- Implement EnumServicesStatusW.
[reactos.git] / reactos / drivers / lib / ip / network / loopback.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS TCP/IP protocol driver
4 * FILE: datalink/loopback.c
5 * PURPOSE: Loopback adapter
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * REVISIONS:
8 * CSH 01/08-2000 Created
9 */
10
11 #include "precomp.h"
12
13 PIP_INTERFACE Loopback = NULL;
14 typedef struct _LAN_WQ_ITEM {
15 LIST_ENTRY ListEntry;
16 PNDIS_PACKET Packet;
17 PLAN_ADAPTER Adapter;
18 UINT BytesTransferred;
19 } LAN_WQ_ITEM, *PLAN_WQ_ITEM;
20
21 /* Work around being called back into afd at Dpc level */
22 KSPIN_LOCK LoopWorkLock;
23 LIST_ENTRY LoopWorkList;
24 WORK_QUEUE_ITEM LoopWorkItem;
25 BOOLEAN LoopReceiveWorkerBusy = FALSE;
26
27 VOID STDCALL LoopReceiveWorker( PVOID Context ) {
28 PLIST_ENTRY ListEntry;
29 PLAN_WQ_ITEM WorkItem;
30 PNDIS_PACKET Packet;
31 PLAN_ADAPTER Adapter;
32 UINT BytesTransferred;
33 PNDIS_BUFFER NdisBuffer;
34 IP_PACKET IPPacket;
35
36 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
37
38 while( (ListEntry =
39 ExInterlockedRemoveHeadList( &LoopWorkList, &LoopWorkLock )) ) {
40 WorkItem = CONTAINING_RECORD(ListEntry, LAN_WQ_ITEM, ListEntry);
41
42 TI_DbgPrint(DEBUG_DATALINK, ("WorkItem: %x\n", WorkItem));
43
44 Packet = WorkItem->Packet;
45 Adapter = WorkItem->Adapter;
46 BytesTransferred = WorkItem->BytesTransferred;
47
48 ExFreePool( WorkItem );
49
50 IPPacket.NdisPacket = Packet;
51
52 TI_DbgPrint(DEBUG_DATALINK, ("Packet %x Adapter %x Trans %x\n",
53 Packet, Adapter, BytesTransferred));
54
55 NdisGetFirstBufferFromPacket(Packet,
56 &NdisBuffer,
57 &IPPacket.Header,
58 &IPPacket.ContigSize,
59 &IPPacket.TotalSize);
60
61 IPPacket.ContigSize = IPPacket.TotalSize = BytesTransferred;
62 /* Determine which upper layer protocol that should receive
63 this packet and pass it to the correct receive handler */
64
65 TI_DbgPrint(MID_TRACE,
66 ("ContigSize: %d, TotalSize: %d, BytesTransferred: %d\n",
67 IPPacket.ContigSize, IPPacket.TotalSize,
68 BytesTransferred));
69
70 IPPacket.Position = 0;
71
72 IPReceive(Loopback, &IPPacket);
73
74 FreeNdisPacket( Packet );
75 }
76 TI_DbgPrint(DEBUG_DATALINK, ("Leaving\n"));
77 LoopReceiveWorkerBusy = FALSE;
78 }
79
80 VOID LoopSubmitReceiveWork(
81 NDIS_HANDLE BindingContext,
82 PNDIS_PACKET Packet,
83 NDIS_STATUS Status,
84 UINT BytesTransferred) {
85 PLAN_WQ_ITEM WQItem;
86 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
87 KIRQL OldIrql;
88
89 TcpipAcquireSpinLock( &LoopWorkLock, &OldIrql );
90
91 WQItem = ExAllocatePool( NonPagedPool, sizeof(LAN_WQ_ITEM) );
92 if( !WQItem ) {
93 TcpipReleaseSpinLock( &LoopWorkLock, OldIrql );
94 return;
95 }
96
97 WQItem->Packet = Packet;
98 WQItem->Adapter = Adapter;
99 WQItem->BytesTransferred = BytesTransferred;
100 InsertTailList( &LoopWorkList, &WQItem->ListEntry );
101
102 TI_DbgPrint(DEBUG_DATALINK, ("Packet %x Adapter %x BytesTrans %x\n",
103 Packet, Adapter, BytesTransferred));
104
105 if( !LoopReceiveWorkerBusy ) {
106 LoopReceiveWorkerBusy = TRUE;
107 ExQueueWorkItem( &LoopWorkItem, CriticalWorkQueue );
108 TI_DbgPrint(DEBUG_DATALINK,
109 ("Work item inserted %x %x\n", &LoopWorkItem, WQItem));
110 } else {
111 TI_DbgPrint(DEBUG_DATALINK,
112 ("LOOP WORKER BUSY %x %x\n", &LoopWorkItem, WQItem));
113 }
114 TcpipReleaseSpinLock( &LoopWorkLock, OldIrql );
115 }
116
117 VOID LoopTransmit(
118 PVOID Context,
119 PNDIS_PACKET NdisPacket,
120 UINT Offset,
121 PVOID LinkAddress,
122 USHORT Type)
123 /*
124 * FUNCTION: Transmits a packet
125 * ARGUMENTS:
126 * Context = Pointer to context information (NULL)
127 * NdisPacket = Pointer to NDIS packet to send
128 * Offset = Offset in packet where packet data starts
129 * LinkAddress = Pointer to link address
130 * Type = LAN protocol type (unused)
131 */
132 {
133 PCHAR PacketBuffer;
134 UINT PacketLength;
135 PNDIS_PACKET XmitPacket;
136 NDIS_STATUS NdisStatus;
137
138 ASSERT_KM_POINTER(NdisPacket);
139 ASSERT_KM_POINTER(PC(NdisPacket));
140 ASSERT_KM_POINTER(PC(NdisPacket)->DLComplete);
141
142 TI_DbgPrint(MAX_TRACE, ("Called (NdisPacket = %x)\n", NdisPacket));
143
144 GetDataPtr( NdisPacket, MaxLLHeaderSize, &PacketBuffer, &PacketLength );
145
146 NdisStatus = AllocatePacketWithBuffer
147 ( &XmitPacket, PacketBuffer, PacketLength );
148
149 if( NT_SUCCESS(NdisStatus) ) {
150 LoopSubmitReceiveWork
151 ( NULL, XmitPacket, STATUS_SUCCESS, PacketLength );
152 }
153
154 (PC(NdisPacket)->DLComplete)
155 ( PC(NdisPacket)->Context, NdisPacket, STATUS_SUCCESS );
156
157 TI_DbgPrint(MAX_TRACE, ("Done\n"));
158 }
159
160 NDIS_STATUS LoopRegisterAdapter(
161 PNDIS_STRING AdapterName,
162 PLAN_ADAPTER *Adapter)
163 /*
164 * FUNCTION: Registers loopback adapter with the network layer
165 * ARGUMENTS:
166 * AdapterName = Unused
167 * Adapter = Unused
168 * RETURNS:
169 * Status of operation
170 */
171 {
172 NDIS_STATUS Status;
173 LLIP_BIND_INFO BindInfo;
174
175 Status = NDIS_STATUS_SUCCESS;
176
177 TI_DbgPrint(MID_TRACE, ("Called.\n"));
178
179 InitializeListHead( &LoopWorkList );
180 ExInitializeWorkItem( &LoopWorkItem, LoopReceiveWorker, NULL );
181
182 /* Bind the adapter to network (IP) layer */
183 BindInfo.Context = NULL;
184 BindInfo.HeaderSize = 0;
185 BindInfo.MinFrameSize = 0;
186 BindInfo.MTU = 16384;
187 BindInfo.Address = NULL;
188 BindInfo.AddressLength = 0;
189 BindInfo.Transmit = LoopTransmit;
190
191 Loopback = IPCreateInterface(&BindInfo);
192
193 Loopback->Name.Buffer = L"Loopback";
194 Loopback->Name.MaximumLength = Loopback->Name.Length =
195 wcslen(Loopback->Name.Buffer) * sizeof(WCHAR);
196
197 AddrInitIPv4(&Loopback->Unicast, LOOPBACK_ADDRESS_IPv4);
198 AddrInitIPv4(&Loopback->Netmask, LOOPBACK_ADDRMASK_IPv4);
199
200 IPRegisterInterface(Loopback);
201
202 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
203
204 return Status;
205 }
206
207
208 NDIS_STATUS LoopUnregisterAdapter(
209 PLAN_ADAPTER Adapter)
210 /*
211 * FUNCTION: Unregisters loopback adapter with the network layer
212 * ARGUMENTS:
213 * Adapter = Unused
214 * RETURNS:
215 * Status of operation
216 * NOTES:
217 * Does not care wether we have registered loopback adapter
218 */
219 {
220 TI_DbgPrint(MID_TRACE, ("Called.\n"));
221
222 if (Loopback != NULL)
223 {
224 IPUnregisterInterface(Loopback);
225 IPDestroyInterface(Loopback);
226 Loopback = NULL;
227 }
228
229 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
230
231 return NDIS_STATUS_SUCCESS;
232 }