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)
8 * CSH 01/08-2000 Created
19 WORK_QUEUE_ITEM LoopWorkItem
;
20 PIP_INTERFACE Loopback
= NULL
;
21 /* Indicates wether the loopback interface is currently transmitting */
22 BOOLEAN LoopBusy
= FALSE
;
23 /* Loopback transmit queue */
24 PNDIS_PACKET LoopQueueHead
= (PNDIS_PACKET
)NULL
;
25 PNDIS_PACKET LoopQueueTail
= (PNDIS_PACKET
)NULL
;
26 /* Spin lock for protecting loopback transmit queue */
27 KSPIN_LOCK LoopQueueLock
;
33 * FUNCTION: Transmits one or more packet(s) in loopback queue to ourselves
35 * Context = Pointer to context information (loopback interface)
38 PNDIS_PACKET NdisPacket
;
39 PNDIS_BUFFER NdisBuffer
;
43 TI_DbgPrint(MAX_TRACE
, ("Called.\n"));
45 KeRaiseIrql(DISPATCH_LEVEL
, &OldIrql
);
46 KeAcquireSpinLockAtDpcLevel(&LoopQueueLock
);
50 /* Get the next packet from the queue (if any) */
51 NdisPacket
= LoopQueueHead
;
55 TI_DbgPrint(MAX_TRACE
, ("NdisPacket (0x%X)\n", NdisPacket
));
57 LoopQueueHead
= *(PNDIS_PACKET
*)NdisPacket
->u
.s3
.MacReserved
;
58 KeReleaseSpinLockFromDpcLevel(&LoopQueueLock
);
59 IPPacket
.NdisPacket
= NdisPacket
;
61 NdisGetFirstBufferFromPacket(NdisPacket
,
66 IPReceive(Context
, &IPPacket
);
67 AdjustPacket(NdisPacket
, 0, PC(NdisPacket
)->DLOffset
);
68 PC(NdisPacket
)->DLComplete(Context
, NdisPacket
, NDIS_STATUS_SUCCESS
);
69 /* Lower IRQL for a moment to prevent starvation */
71 KeRaiseIrql(DISPATCH_LEVEL
, &OldIrql
);
72 KeAcquireSpinLockAtDpcLevel(&LoopQueueLock
);
76 KeReleaseSpinLockFromDpcLevel(&LoopQueueLock
);
82 PNDIS_PACKET NdisPacket
,
87 * FUNCTION: Transmits a packet
89 * Context = Pointer to context information (NULL)
90 * NdisPacket = Pointer to NDIS packet to send
91 * Offset = Offset in packet where packet data starts
92 * LinkAddress = Pointer to link address
93 * Type = LAN protocol type (unused)
96 PNDIS_PACKET
*pNdisPacket
;
99 TI_DbgPrint(MAX_TRACE
, ("Called.\n"));
101 /* NDIS send routines don't have an offset argument so we
102 must offset the data in upper layers and adjust the
103 packet here. We save the offset in the packet context
104 area so it can be undone before we release the packet */
105 AdjustPacket(NdisPacket
, Offset
, 0);
106 PC(NdisPacket
)->DLOffset
= Offset
;
108 pNdisPacket
= (PNDIS_PACKET
*)NdisPacket
->u
.s3
.MacReserved
;
111 KeAcquireSpinLock(&LoopQueueLock
, &OldIrql
);
113 /* Add packet to transmit queue */
114 if (LoopQueueHead
!= NULL
)
116 /* Transmit queue is not empty */
117 pNdisPacket
= (PNDIS_PACKET
*)LoopQueueTail
->u
.s3
.MacReserved
;
118 *pNdisPacket
= NdisPacket
;
122 /* Transmit queue is empty */
123 LoopQueueHead
= NdisPacket
;
126 LoopQueueTail
= NdisPacket
;
128 /* If RealTransmit is not running (or scheduled to run) then schedule it to run now */
131 LoopBusy
= TRUE
; /* The loopback interface is now busy */
132 ExQueueWorkItem(&LoopWorkItem
, CriticalWorkQueue
);
135 KeReleaseSpinLock(&LoopQueueLock
, OldIrql
);
138 NDIS_STATUS
LoopRegisterAdapter(
139 PNDIS_STRING AdapterName
,
140 PLAN_ADAPTER
*Adapter
)
142 * FUNCTION: Registers loopback adapter with the network layer
144 * AdapterName = Unused
147 * Status of operation
153 Status
= NDIS_STATUS_SUCCESS
;
155 TI_DbgPrint(MID_TRACE
, ("Called.\n"));
157 Address
= AddrBuildIPv4(LOOPBACK_ADDRESS_IPv4
);
160 LLIP_BIND_INFO BindInfo
;
162 /* Bind the adapter to network (IP) layer */
163 BindInfo
.Context
= NULL
;
164 BindInfo
.HeaderSize
= 0;
165 BindInfo
.MinFrameSize
= 0;
166 BindInfo
.MTU
= 16384;
167 BindInfo
.Address
= NULL
;
168 BindInfo
.AddressLength
= 0;
169 BindInfo
.Transmit
= LoopTransmit
;
171 Loopback
= IPCreateInterface(&BindInfo
);
172 if ((Loopback
!= NULL
) && (IPCreateNTE(Loopback
, Address
, 8)))
174 /* Reference the interface for the NTE. The reference for
175 the address is just passed on to the NTE */
176 ReferenceObject(Loopback
);
178 IPRegisterInterface(Loopback
);
180 ExInitializeWorkItem(&LoopWorkItem
, RealTransmit
, Loopback
);
182 KeInitializeSpinLock(&LoopQueueLock
);
187 Status
= NDIS_STATUS_RESOURCES
;
192 Status
= NDIS_STATUS_RESOURCES
;
195 if (!NT_SUCCESS(Status
))
197 LoopUnregisterAdapter(NULL
);
200 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
206 NDIS_STATUS
LoopUnregisterAdapter(
207 PLAN_ADAPTER Adapter
)
209 * FUNCTION: Unregisters loopback adapter with the network layer
213 * Status of operation
215 * Does not care wether we have registered loopback adapter
218 TI_DbgPrint(MID_TRACE
, ("Called.\n"));
220 if (Loopback
!= NULL
)
222 IPUnregisterInterface(Loopback
);
223 IPDestroyInterface(Loopback
);
227 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
229 return NDIS_STATUS_SUCCESS
;