Added double complete protection so that we never call an upper-level
[reactos.git] / reactos / drivers / net / tcpip / datalink / lan.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS TCP/IP protocol driver
4 * FILE: datalink/lan.c
5 * PURPOSE: Local Area Network media routines
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 /* Define this to bugcheck on double complete */
14 /* #define BREAK_ON_DOUBLE_COMPLETE */
15
16 UINT TransferDataCalled = 0;
17 UINT TransferDataCompleteCalled = 0;
18 UINT LanReceiveWorkerCalled = 0;
19
20 #define NGFP(_Packet) \
21 { \
22 PVOID _Header; \
23 ULONG _ContigSize, _TotalSize; \
24 PNDIS_BUFFER _NdisBuffer; \
25 \
26 TI_DbgPrint(MID_TRACE,("Checking Packet %x\n", _Packet)); \
27 NdisGetFirstBufferFromPacket(_Packet, \
28 &_NdisBuffer, \
29 &_Header, \
30 &_ContigSize, \
31 &_TotalSize); \
32 TI_DbgPrint(MID_TRACE,("NdisBuffer: %x\n", _NdisBuffer)); \
33 TI_DbgPrint(MID_TRACE,("Header : %x\n", _Header)); \
34 TI_DbgPrint(MID_TRACE,("ContigSize: %x\n", _ContigSize)); \
35 TI_DbgPrint(MID_TRACE,("TotalSize : %x\n", _TotalSize)); \
36 }
37
38 typedef struct _LAN_WQ_ITEM {
39 LIST_ENTRY ListEntry;
40 PNDIS_PACKET Packet;
41 PLAN_ADAPTER Adapter;
42 UINT BytesTransferred;
43 } LAN_WQ_ITEM, *PLAN_WQ_ITEM;
44
45 NDIS_HANDLE NdisProtocolHandle = (NDIS_HANDLE)NULL;
46 BOOLEAN ProtocolRegistered = FALSE;
47 LIST_ENTRY AdapterListHead;
48 KSPIN_LOCK AdapterListLock;
49
50 /* Work around being called back into afd at Dpc level */
51 KSPIN_LOCK LanWorkLock;
52 LIST_ENTRY LanWorkList;
53 WORK_QUEUE_ITEM LanWorkItem;
54
55 /* Double complete protection */
56 KSPIN_LOCK LanSendCompleteLock;
57 LIST_ENTRY LanSendCompleteList;
58
59 VOID LanChainCompletion( PLAN_ADAPTER Adapter, PNDIS_PACKET NdisPacket ) {
60 PLAN_WQ_ITEM PendingCompletion =
61 ExAllocatePool( NonPagedPool, sizeof(LAN_WQ_ITEM) );
62
63 if( !PendingCompletion ) return;
64
65 PendingCompletion->Packet = NdisPacket;
66 PendingCompletion->Adapter = Adapter;
67
68 ExInterlockedInsertTailList( &LanSendCompleteList,
69 &PendingCompletion->ListEntry,
70 &LanSendCompleteLock );
71 }
72
73 BOOLEAN LanShouldComplete( PLAN_ADAPTER Adapter, PNDIS_PACKET NdisPacket ) {
74 PLIST_ENTRY ListEntry;
75 PLAN_WQ_ITEM CompleteEntry;
76 KIRQL OldIrql;
77
78 KeAcquireSpinLock( &LanSendCompleteLock, &OldIrql );
79 for( ListEntry = LanSendCompleteList.Flink;
80 ListEntry != &LanSendCompleteList;
81 ListEntry = ListEntry->Flink ) {
82 CompleteEntry = CONTAINING_RECORD(ListEntry, LAN_WQ_ITEM, ListEntry);
83
84 if( CompleteEntry->Adapter == Adapter &&
85 CompleteEntry->Packet == NdisPacket ) {
86 RemoveEntryList( ListEntry );
87 KeReleaseSpinLock( &LanSendCompleteLock, OldIrql );
88 ExFreePool( CompleteEntry );
89 return TRUE;
90 }
91 }
92 KeReleaseSpinLock( &LanSendCompleteLock, OldIrql );
93
94 TI_DbgPrint(MID_TRACE,("NDIS completed the same send packet twice "
95 "(Adapter %x Packet %x)!!\n", Adapter, NdisPacket));
96 #ifdef BREAK_ON_DOUBLE_COMPLETE
97 KeBugCheck(0);
98 #endif
99
100 return FALSE;
101 }
102
103 NDIS_STATUS NDISCall(
104 PLAN_ADAPTER Adapter,
105 NDIS_REQUEST_TYPE Type,
106 NDIS_OID OID,
107 PVOID Buffer,
108 UINT Length)
109 /*
110 * FUNCTION: Send a request to NDIS
111 * ARGUMENTS:
112 * Adapter = Pointer to a LAN_ADAPTER structure
113 * Type = Type of request (Set or Query)
114 * OID = Value to be set/queried for
115 * Buffer = Pointer to a buffer to use
116 * Length = Number of bytes in Buffer
117 * RETURNS:
118 * Status of operation
119 */
120 {
121 NDIS_REQUEST Request;
122 NDIS_STATUS NdisStatus;
123
124 Request.RequestType = Type;
125 if (Type == NdisRequestSetInformation) {
126 Request.DATA.SET_INFORMATION.Oid = OID;
127 Request.DATA.SET_INFORMATION.InformationBuffer = Buffer;
128 Request.DATA.SET_INFORMATION.InformationBufferLength = Length;
129 } else {
130 Request.DATA.QUERY_INFORMATION.Oid = OID;
131 Request.DATA.QUERY_INFORMATION.InformationBuffer = Buffer;
132 Request.DATA.QUERY_INFORMATION.InformationBufferLength = Length;
133 }
134
135 if (Adapter->State != LAN_STATE_RESETTING) {
136 NdisRequest(&NdisStatus, Adapter->NdisHandle, &Request);
137 } else {
138 NdisStatus = NDIS_STATUS_NOT_ACCEPTED;
139 }
140
141 /* Wait for NDIS to complete the request */
142 if (NdisStatus == NDIS_STATUS_PENDING) {
143 KeWaitForSingleObject(&Adapter->Event,
144 UserRequest,
145 KernelMode,
146 FALSE,
147 NULL);
148 NdisStatus = Adapter->NdisStatus;
149 }
150
151 return NdisStatus;
152 }
153
154
155 VOID FreeAdapter(
156 PLAN_ADAPTER Adapter)
157 /*
158 * FUNCTION: Frees memory for a LAN_ADAPTER structure
159 * ARGUMENTS:
160 * Adapter = Pointer to LAN_ADAPTER structure to free
161 */
162 {
163 exFreePool(Adapter);
164 }
165
166
167 VOID STDCALL ProtocolOpenAdapterComplete(
168 NDIS_HANDLE BindingContext,
169 NDIS_STATUS Status,
170 NDIS_STATUS OpenErrorStatus)
171 /*
172 * FUNCTION: Called by NDIS to complete opening of an adapter
173 * ARGUMENTS:
174 * BindingContext = Pointer to a device context (LAN_ADAPTER)
175 * Status = Status of the operation
176 * OpenErrorStatus = Additional status information
177 */
178 {
179 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
180
181 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
182
183 KeSetEvent(&Adapter->Event, 0, FALSE);
184 }
185
186
187 VOID STDCALL ProtocolCloseAdapterComplete(
188 NDIS_HANDLE BindingContext,
189 NDIS_STATUS Status)
190 /*
191 * FUNCTION: Called by NDIS to complete closing an adapter
192 * ARGUMENTS:
193 * BindingContext = Pointer to a device context (LAN_ADAPTER)
194 * Status = Status of the operation
195 */
196 {
197 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
198
199 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
200
201 Adapter->NdisStatus = Status;
202
203 KeSetEvent(&Adapter->Event, 0, FALSE);
204 }
205
206
207 VOID STDCALL ProtocolResetComplete(
208 NDIS_HANDLE BindingContext,
209 NDIS_STATUS Status)
210 /*
211 * FUNCTION: Called by NDIS to complete resetting an adapter
212 * ARGUMENTS:
213 * BindingContext = Pointer to a device context (LAN_ADAPTER)
214 * Status = Status of the operation
215 */
216 {
217 TI_DbgPrint(MID_TRACE, ("Called.\n"));
218 }
219
220
221 VOID STDCALL ProtocolRequestComplete(
222 NDIS_HANDLE BindingContext,
223 PNDIS_REQUEST NdisRequest,
224 NDIS_STATUS Status)
225 /*
226 * FUNCTION: Called by NDIS to complete a request
227 * ARGUMENTS:
228 * BindingContext = Pointer to a device context (LAN_ADAPTER)
229 * NdisRequest = Pointer to an object describing the request
230 * Status = Status of the operation
231 */
232 {
233 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
234
235 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
236
237 /* Save status of request and signal an event */
238 Adapter->NdisStatus = Status;
239
240 KeSetEvent(&Adapter->Event, 0, FALSE);
241 }
242
243
244 VOID STDCALL ProtocolSendComplete(
245 NDIS_HANDLE BindingContext,
246 PNDIS_PACKET Packet,
247 NDIS_STATUS Status)
248 /*
249 * FUNCTION: Called by NDIS to complete sending process
250 * ARGUMENTS:
251 * BindingContext = Pointer to a device context (LAN_ADAPTER)
252 * Packet = Pointer to a packet descriptor
253 * Status = Status of the operation
254 */
255 {
256 TI_DbgPrint(DEBUG_DATALINK, ("Calling completion routine\n"));
257 if( LanShouldComplete( (PLAN_ADAPTER)BindingContext, Packet ) ) {
258 ASSERT_KM_POINTER(Packet);
259 ASSERT_KM_POINTER(PC(Packet));
260 ASSERT_KM_POINTER(PC(Packet)->DLComplete);
261 (*PC(Packet)->DLComplete)( PC(Packet)->Context, Packet, Status);
262 TI_DbgPrint(DEBUG_DATALINK, ("Finished\n"));
263 }
264 }
265
266 VOID STDCALL LanReceiveWorker( PVOID Context ) {
267 UINT PacketType;
268 PLIST_ENTRY ListEntry;
269 PLAN_WQ_ITEM WorkItem;
270 PNDIS_PACKET Packet;
271 PLAN_ADAPTER Adapter;
272 UINT BytesTransferred;
273 PNDIS_BUFFER NdisBuffer;
274 IP_PACKET IPPacket;
275
276 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
277
278 while( (ListEntry =
279 ExInterlockedRemoveHeadList( &LanWorkList, &LanWorkLock )) ) {
280 WorkItem = CONTAINING_RECORD(ListEntry, LAN_WQ_ITEM, ListEntry);
281
282 LanReceiveWorkerCalled++;
283 ASSERT(LanReceiveWorkerCalled <= TransferDataCompleteCalled);
284
285 Packet = WorkItem->Packet;
286 Adapter = WorkItem->Adapter;
287 BytesTransferred = WorkItem->BytesTransferred;
288
289 ExFreePool( WorkItem );
290
291 IPPacket.NdisPacket = Packet;
292
293 NdisGetFirstBufferFromPacket(Packet,
294 &NdisBuffer,
295 &IPPacket.Header,
296 &IPPacket.ContigSize,
297 &IPPacket.TotalSize);
298
299 IPPacket.ContigSize = IPPacket.TotalSize = BytesTransferred;
300 /* Determine which upper layer protocol that should receive
301 this packet and pass it to the correct receive handler */
302
303 TI_DbgPrint(MID_TRACE,
304 ("ContigSize: %d, TotalSize: %d, BytesTransferred: %d\n",
305 IPPacket.ContigSize, IPPacket.TotalSize,
306 BytesTransferred));
307
308 PacketType = PC(IPPacket.NdisPacket)->PacketType;
309 IPPacket.Position = 0;
310
311 TI_DbgPrint
312 (DEBUG_DATALINK,
313 ("Ether Type = %x ContigSize = %d Total = %d\n",
314 PacketType, IPPacket.ContigSize, IPPacket.TotalSize));
315
316 switch (PacketType) {
317 case ETYPE_IPv4:
318 case ETYPE_IPv6:
319 TI_DbgPrint(MID_TRACE,("Received IP Packet\n"));
320 IPReceive(Adapter->Context, &IPPacket);
321 break;
322 case ETYPE_ARP:
323 TI_DbgPrint(MID_TRACE,("Received ARP Packet\n"));
324 ARPReceive(Adapter->Context, &IPPacket);
325 default:
326 break;
327 }
328
329 FreeNdisPacket( Packet );
330 }
331 }
332
333 VOID STDCALL ProtocolTransferDataComplete(
334 NDIS_HANDLE BindingContext,
335 PNDIS_PACKET Packet,
336 NDIS_STATUS Status,
337 UINT BytesTransferred)
338 /*
339 * FUNCTION: Called by NDIS to complete reception of data
340 * ARGUMENTS:
341 * BindingContext = Pointer to a device context (LAN_ADAPTER)
342 * Packet = Pointer to a packet descriptor
343 * Status = Status of the operation
344 * BytesTransferred = Number of bytes transferred
345 * NOTES:
346 * If the packet was successfully received, determine the protocol
347 * type and pass it to the correct receive handler
348 */
349 {
350 BOOLEAN WorkStart;
351 PLAN_WQ_ITEM WQItem;
352 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
353 KIRQL OldIrql;
354
355 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
356
357 if( Status != NDIS_STATUS_SUCCESS ) return;
358 TcpipAcquireSpinLock( &LanWorkLock, &OldIrql );
359
360 TransferDataCompleteCalled++;
361
362 ASSERT(TransferDataCompleteCalled <= TransferDataCalled);
363
364 WQItem = ExAllocatePool( NonPagedPool, sizeof(LAN_WQ_ITEM) );
365 if( !WQItem ) {
366 TcpipReleaseSpinLock( &LanWorkLock, OldIrql );
367 return;
368 }
369
370 WorkStart = IsListEmpty( &LanWorkList );
371 WQItem->Packet = Packet;
372 WQItem->Adapter = Adapter;
373 WQItem->BytesTransferred = BytesTransferred;
374 InsertTailList( &LanWorkList, &WQItem->ListEntry );
375 if( WorkStart )
376 ExQueueWorkItem( &LanWorkItem, CriticalWorkQueue );
377 TcpipReleaseSpinLock( &LanWorkLock, OldIrql );
378 }
379
380 NDIS_STATUS STDCALL ProtocolReceive(
381 NDIS_HANDLE BindingContext,
382 NDIS_HANDLE MacReceiveContext,
383 PVOID HeaderBuffer,
384 UINT HeaderBufferSize,
385 PVOID LookaheadBuffer,
386 UINT LookaheadBufferSize,
387 UINT PacketSize)
388 /*
389 * FUNCTION: Called by NDIS when a packet has been received on the physical link
390 * ARGUMENTS:
391 * BindingContext = Pointer to a device context (LAN_ADAPTER)
392 * MacReceiveContext = Handle used by underlying NIC driver
393 * HeaderBuffer = Pointer to a buffer containing the packet header
394 * HeaderBufferSize = Number of bytes in HeaderBuffer
395 * LookaheadBuffer = Pointer to a buffer containing buffered packet data
396 * LookaheadBufferSize = Size of LookaheadBuffer. May be less than asked for
397 * PacketSize = Overall size of the packet (not including header)
398 * RETURNS:
399 * Status of operation
400 */
401 {
402 USHORT EType;
403 UINT PacketType, BytesTransferred;
404 UINT temp;
405 IP_PACKET IPPacket;
406 PCHAR BufferData;
407 NDIS_STATUS NdisStatus;
408 PNDIS_PACKET NdisPacket;
409 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
410 PETH_HEADER EHeader = (PETH_HEADER)HeaderBuffer;
411 KIRQL OldIrql;
412
413 TI_DbgPrint(DEBUG_DATALINK, ("Called. (packetsize %d)\n",PacketSize));
414
415 if (Adapter->State != LAN_STATE_STARTED) {
416 TI_DbgPrint(DEBUG_DATALINK, ("Adapter is stopped.\n"));
417 return NDIS_STATUS_NOT_ACCEPTED;
418 }
419
420 if (HeaderBufferSize < Adapter->HeaderSize) {
421 TI_DbgPrint(DEBUG_DATALINK, ("Runt frame received.\n"));
422 return NDIS_STATUS_NOT_ACCEPTED;
423 }
424
425 if (Adapter->Media == NdisMedium802_3) {
426 /* Ethernet and IEEE 802.3 frames can be destinguished by
427 looking at the IEEE 802.3 length field. This field is
428 less than or equal to 1500 for a valid IEEE 802.3 frame
429 and larger than 1500 is it's a valid EtherType value.
430 See RFC 1122, section 2.3.3 for more information */
431 /* FIXME: Test for Ethernet and IEEE 802.3 frame */
432 if (((EType = EHeader->EType) != ETYPE_IPv4) && (EType != ETYPE_ARP)) {
433 TI_DbgPrint(DEBUG_DATALINK, ("Not IP or ARP frame. EtherType (0x%X).\n", EType));
434 return NDIS_STATUS_NOT_ACCEPTED;
435 }
436 /* We use EtherType constants to destinguish packet types */
437 PacketType = EType;
438 } else {
439 TI_DbgPrint(MIN_TRACE, ("Unsupported media.\n"));
440 /* FIXME: Support other medias */
441 return NDIS_STATUS_NOT_ACCEPTED;
442 }
443
444 /* Get a transfer data packet */
445
446 TI_DbgPrint(DEBUG_DATALINK, ("Adapter: %x (MTU %d)\n",
447 Adapter, Adapter->MTU));
448
449 TcpipAcquireSpinLock( &LanWorkLock, &OldIrql );
450
451 NdisStatus = AllocatePacketWithBuffer( &NdisPacket, NULL,
452 PacketSize + HeaderBufferSize );
453 if( NdisStatus != NDIS_STATUS_SUCCESS ) {
454 TcpipReleaseSpinLock( &LanWorkLock, OldIrql );
455 return NDIS_STATUS_NOT_ACCEPTED;
456 }
457
458 PC(NdisPacket)->PacketType = PacketType;
459
460 TI_DbgPrint(DEBUG_DATALINK, ("pretransfer LookaheadBufferSize %d packsize %d\n",LookaheadBufferSize,PacketSize));
461
462 GetDataPtr( NdisPacket, 0, &BufferData, &temp );
463
464 IPPacket.NdisPacket = NdisPacket;
465 IPPacket.Position = 0;
466
467 TransferDataCalled++;
468
469 if (LookaheadBufferSize == PacketSize)
470 {
471 /* Optimized code path for packets that are fully contained in
472 * the lookahead buffer. */
473 NdisCopyLookaheadData(BufferData,
474 LookaheadBuffer,
475 LookaheadBufferSize,
476 Adapter->MacOptions);
477 }
478 else
479 {
480 if (NdisStatus == NDIS_STATUS_SUCCESS)
481 {
482 ASSERT(PacketSize <= Adapter->MTU);
483
484 NdisTransferData(&NdisStatus, Adapter->NdisHandle,
485 MacReceiveContext, 0, PacketSize,
486 NdisPacket, &BytesTransferred);
487 }
488 else
489 {
490 BytesTransferred = 0;
491 }
492 }
493 TcpipReleaseSpinLock( &LanWorkLock, OldIrql );
494 TI_DbgPrint(DEBUG_DATALINK, ("Calling complete\n"));
495
496 if (NdisStatus != NDIS_STATUS_PENDING)
497 ProtocolTransferDataComplete(BindingContext,
498 NdisPacket,
499 NdisStatus,
500 PacketSize);
501
502 TI_DbgPrint(DEBUG_DATALINK, ("leaving\n"));
503
504 return NDIS_STATUS_SUCCESS;
505 }
506
507
508 VOID STDCALL ProtocolReceiveComplete(
509 NDIS_HANDLE BindingContext)
510 /*
511 * FUNCTION: Called by NDIS when we're done receiving data
512 * ARGUMENTS:
513 * BindingContext = Pointer to a device context (LAN_ADAPTER)
514 */
515 {
516 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
517 }
518
519
520 VOID STDCALL ProtocolStatus(
521 NDIS_HANDLE BindingContext,
522 NDIS_STATUS GenerelStatus,
523 PVOID StatusBuffer,
524 UINT StatusBufferSize)
525 /*
526 * FUNCTION: Called by NDIS when the underlying driver has changed state
527 * ARGUMENTS:
528 * BindingContext = Pointer to a device context (LAN_ADAPTER)
529 * GenerelStatus = A generel status code
530 * StatusBuffer = Pointer to a buffer with medium-specific data
531 * StatusBufferSize = Number of bytes in StatusBuffer
532 */
533 {
534 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
535 }
536
537
538 VOID STDCALL ProtocolStatusComplete(
539 NDIS_HANDLE NdisBindingContext)
540 /*
541 * FUNCTION: Called by NDIS when a status-change has occurred
542 * ARGUMENTS:
543 * BindingContext = Pointer to a device context (LAN_ADAPTER)
544 */
545 {
546 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
547 }
548
549 VOID STDCALL ProtocolBindAdapter(
550 OUT PNDIS_STATUS Status,
551 IN NDIS_HANDLE BindContext,
552 IN PNDIS_STRING DeviceName,
553 IN PVOID SystemSpecific1,
554 IN PVOID SystemSpecific2)
555 /*
556 * FUNCTION: Called by NDIS during NdisRegisterProtocol to set up initial
557 * bindings, and periodically thereafer as new adapters come online
558 * ARGUMENTS:
559 * Status: Return value to NDIS
560 * BindContext: Handle provided by NDIS to track pending binding operations
561 * DeviceName: Name of the miniport device to bind to
562 * SystemSpecific1: Pointer to a registry path with protocol-specific configuration information
563 * SystemSpecific2: Unused & must not be touched
564 */
565 {
566 /* XXX confirm that this is still true, or re-word the following comment */
567 /* we get to ignore BindContext because we will never pend an operation with NDIS */
568 TI_DbgPrint(DEBUG_DATALINK, ("Called with registry path %wZ for %wZ\n", SystemSpecific1, DeviceName));
569 *Status = LANRegisterAdapter(DeviceName, SystemSpecific1);
570 }
571
572
573 VOID LANTransmit(
574 PVOID Context,
575 PNDIS_PACKET NdisPacket,
576 UINT Offset,
577 PVOID LinkAddress,
578 USHORT Type)
579 /*
580 * FUNCTION: Transmits a packet
581 * ARGUMENTS:
582 * Context = Pointer to context information (LAN_ADAPTER)
583 * NdisPacket = Pointer to NDIS packet to send
584 * Offset = Offset in packet where data starts
585 * LinkAddress = Pointer to link address of destination (NULL = broadcast)
586 * Type = LAN protocol type (LAN_PROTO_*)
587 */
588 {
589 NDIS_STATUS NdisStatus;
590 PETH_HEADER EHeader;
591 PCHAR Data;
592 UINT Size;
593 KIRQL OldIrql;
594 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)Context;
595
596 TI_DbgPrint(DEBUG_DATALINK,
597 ("Called( NdisPacket %x, Offset %d, Adapter %x )\n",
598 NdisPacket, Offset, Adapter));
599
600 TI_DbgPrint(DEBUG_DATALINK,
601 ("Adapter Address [%02x %02x %02x %02x %02x %02x]\n",
602 Adapter->HWAddress[0] & 0xff,
603 Adapter->HWAddress[1] & 0xff,
604 Adapter->HWAddress[2] & 0xff,
605 Adapter->HWAddress[3] & 0xff,
606 Adapter->HWAddress[4] & 0xff,
607 Adapter->HWAddress[5] & 0xff));
608
609 /* XXX arty -- Handled adjustment in a saner way than before ...
610 * not needed immediately */
611 GetDataPtr( NdisPacket, 0, &Data, &Size );
612
613 if (Adapter->State == LAN_STATE_STARTED) {
614 switch (Adapter->Media) {
615 case NdisMedium802_3:
616 EHeader = (PETH_HEADER)Data;
617
618 if (LinkAddress) {
619 /* Unicast address */
620 RtlCopyMemory(EHeader->DstAddr, LinkAddress, IEEE_802_ADDR_LENGTH);
621 } else {
622 /* Broadcast address */
623 RtlFillMemory(EHeader->DstAddr, IEEE_802_ADDR_LENGTH, 0xFF);
624 }
625
626 RtlCopyMemory(EHeader->SrcAddr, Adapter->HWAddress, IEEE_802_ADDR_LENGTH);
627
628 switch (Type) {
629 case LAN_PROTO_IPv4:
630 EHeader->EType = ETYPE_IPv4;
631 break;
632 case LAN_PROTO_ARP:
633 EHeader->EType = ETYPE_ARP;
634 break;
635 case LAN_PROTO_IPv6:
636 EHeader->EType = ETYPE_IPv6;
637 break;
638 default:
639 #ifdef DBG
640 /* Should not happen */
641 TI_DbgPrint(MIN_TRACE, ("Unknown LAN protocol.\n"));
642
643 ProtocolSendComplete((NDIS_HANDLE)Context,
644 NdisPacket,
645 NDIS_STATUS_FAILURE);
646 #endif
647 return;
648 }
649 break;
650
651 default:
652 /* FIXME: Support other medias */
653 break;
654 }
655
656 TI_DbgPrint( MID_TRACE, ("LinkAddress: %x\n", LinkAddress));
657 if( LinkAddress ) {
658 TI_DbgPrint
659 ( MID_TRACE,
660 ("Link Address [%02x %02x %02x %02x %02x %02x]\n",
661 ((PCHAR)LinkAddress)[0] & 0xff,
662 ((PCHAR)LinkAddress)[1] & 0xff,
663 ((PCHAR)LinkAddress)[2] & 0xff,
664 ((PCHAR)LinkAddress)[3] & 0xff,
665 ((PCHAR)LinkAddress)[4] & 0xff,
666 ((PCHAR)LinkAddress)[5] & 0xff));
667 }
668
669 TcpipAcquireSpinLock( &Adapter->Lock, &OldIrql );
670 TI_DbgPrint(MID_TRACE, ("NdisSend\n"));
671 NdisSend(&NdisStatus, Adapter->NdisHandle, NdisPacket);
672 LanChainCompletion( Adapter, NdisPacket );
673 TI_DbgPrint(MID_TRACE, ("NdisSend Done\n"));
674 TcpipReleaseSpinLock( &Adapter->Lock, OldIrql );
675
676 if (NdisStatus != NDIS_STATUS_PENDING)
677 ProtocolSendComplete((NDIS_HANDLE)Context, NdisPacket, NdisStatus);
678 } else {
679 ProtocolSendComplete((NDIS_HANDLE)Context, NdisPacket, NDIS_STATUS_CLOSED);
680 }
681 }
682
683 static NTSTATUS
684 OpenRegistryKey( PNDIS_STRING RegistryPath, PHANDLE RegHandle ) {
685 OBJECT_ATTRIBUTES Attributes;
686 NTSTATUS Status;
687
688 InitializeObjectAttributes(&Attributes, RegistryPath, OBJ_CASE_INSENSITIVE, 0, 0);
689 Status = ZwOpenKey(RegHandle, GENERIC_READ, &Attributes);
690 return Status;
691 }
692
693 static NTSTATUS ReadIPAddressFromRegistry( HANDLE RegHandle,
694 PWCHAR RegistryValue,
695 PIP_ADDRESS Address ) {
696 UNICODE_STRING ValueName;
697 UNICODE_STRING UnicodeAddress;
698 NTSTATUS Status;
699 ULONG ResultLength;
700 UCHAR buf[1024];
701 PKEY_VALUE_PARTIAL_INFORMATION Information = (PKEY_VALUE_PARTIAL_INFORMATION)buf;
702 ANSI_STRING AnsiAddress;
703 ULONG AnsiLen;
704
705 RtlInitUnicodeString(&ValueName, RegistryValue);
706 Status =
707 ZwQueryValueKey(RegHandle,
708 &ValueName,
709 KeyValuePartialInformation,
710 Information,
711 sizeof(buf),
712 &ResultLength);
713
714 if (!NT_SUCCESS(Status))
715 return Status;
716 /* IP address is stored as a REG_MULTI_SZ - we only pay attention to the first one though */
717 TI_DbgPrint(MIN_TRACE, ("Information DataLength: 0x%x\n", Information->DataLength));
718
719 UnicodeAddress.Buffer = (PWCHAR)&Information->Data;
720 UnicodeAddress.Length = Information->DataLength;
721 UnicodeAddress.MaximumLength = Information->DataLength;
722
723 AnsiLen = RtlUnicodeStringToAnsiSize(&UnicodeAddress);
724 if(!AnsiLen)
725 return STATUS_NO_MEMORY;
726
727 AnsiAddress.Buffer = exAllocatePoolWithTag(PagedPool, AnsiLen, 0x01020304);
728 if(!AnsiAddress.Buffer)
729 return STATUS_NO_MEMORY;
730
731 AnsiAddress.Length = AnsiLen;
732 AnsiAddress.MaximumLength = AnsiLen;
733
734 Status = RtlUnicodeStringToAnsiString(&AnsiAddress, &UnicodeAddress, FALSE);
735 if (!NT_SUCCESS(Status)) {
736 exFreePool(AnsiAddress.Buffer);
737 return STATUS_UNSUCCESSFUL;
738 }
739
740 AnsiAddress.Buffer[AnsiAddress.Length] = 0;
741 AddrInitIPv4(Address, inet_addr(AnsiAddress.Buffer));
742
743 return STATUS_SUCCESS;
744 }
745
746 static NTSTATUS ReadStringFromRegistry( HANDLE RegHandle,
747 PWCHAR RegistryValue,
748 PUNICODE_STRING String ) {
749 UNICODE_STRING ValueName;
750 UNICODE_STRING UnicodeString;
751 NTSTATUS Status;
752 ULONG ResultLength;
753 UCHAR buf[1024];
754 PKEY_VALUE_PARTIAL_INFORMATION Information = (PKEY_VALUE_PARTIAL_INFORMATION)buf;
755
756 RtlInitUnicodeString(&ValueName, RegistryValue);
757 Status =
758 ZwQueryValueKey(RegHandle,
759 &ValueName,
760 KeyValuePartialInformation,
761 Information,
762 sizeof(buf),
763 &ResultLength);
764
765 if (!NT_SUCCESS(Status))
766 return Status;
767 /* IP address is stored as a REG_MULTI_SZ - we only pay attention to the first one though */
768 TI_DbgPrint(MIN_TRACE, ("Information DataLength: 0x%x\n", Information->DataLength));
769
770 UnicodeString.Buffer = (PWCHAR)&Information->Data;
771 UnicodeString.Length = Information->DataLength;
772 UnicodeString.MaximumLength = Information->DataLength;
773
774 String->Buffer =
775 (PWCHAR)exAllocatePool( NonPagedPool,
776 UnicodeString.MaximumLength + sizeof(WCHAR) );
777
778 if( !String->Buffer ) return STATUS_NO_MEMORY;
779
780 String->MaximumLength = UnicodeString.MaximumLength;
781 RtlCopyUnicodeString( String, &UnicodeString );
782
783 return STATUS_SUCCESS;
784 }
785
786 static VOID GetSimpleAdapterNameFromRegistryPath
787 ( PUNICODE_STRING TargetString,
788 PUNICODE_STRING RegistryPath ) {
789 PWCHAR i, LastSlash = NULL;
790 UINT NewStringLength = 0;
791
792 for( i = RegistryPath->Buffer;
793 i < RegistryPath->Buffer +
794 (RegistryPath->Length / sizeof(WCHAR));
795 i++ ) if( *i == '\\' ) LastSlash = i;
796
797 if( LastSlash ) LastSlash++; else LastSlash = RegistryPath->Buffer;
798
799 NewStringLength = RegistryPath->MaximumLength -
800 ((LastSlash - RegistryPath->Buffer) * sizeof(WCHAR));
801
802 TargetString->Buffer =
803 (PWCHAR)exAllocatePool( NonPagedPool, NewStringLength );
804
805 if( !TargetString->Buffer ) {
806 TargetString->Length = TargetString->MaximumLength = 0;
807 return;
808 }
809
810 TargetString->Length = TargetString->MaximumLength = NewStringLength;
811 RtlCopyMemory( TargetString->Buffer, LastSlash, NewStringLength );
812 }
813
814 VOID BindAdapter(
815 PLAN_ADAPTER Adapter,
816 PNDIS_STRING RegistryPath)
817 /*
818 * FUNCTION: Binds a LAN adapter to IP layer
819 * ARGUMENTS:
820 * Adapter = Pointer to LAN_ADAPTER structure
821 * NOTES:
822 * We set the lookahead buffer size, set the packet filter and
823 * bind the adapter to IP layer
824 */
825 {
826 PIP_INTERFACE IF;
827 NDIS_STATUS NdisStatus;
828 LLIP_BIND_INFO BindInfo;
829 IP_ADDRESS DefaultGateway, DefaultMask = { 0 };
830 ULONG Lookahead = LOOKAHEAD_SIZE;
831 NTSTATUS Status;
832 HANDLE RegHandle = 0;
833
834 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
835
836 Adapter->State = LAN_STATE_OPENING;
837
838 NdisStatus = NDISCall(Adapter,
839 NdisRequestSetInformation,
840 OID_GEN_CURRENT_LOOKAHEAD,
841 &Lookahead,
842 sizeof(ULONG));
843 if (NdisStatus != NDIS_STATUS_SUCCESS) {
844 TI_DbgPrint(MID_TRACE, ("Could not set lookahead buffer size (0x%X).\n", NdisStatus));
845 return;
846 }
847
848 /* Bind the adapter to IP layer */
849 BindInfo.Context = Adapter;
850 BindInfo.HeaderSize = Adapter->HeaderSize;
851 BindInfo.MinFrameSize = Adapter->MinFrameSize;
852 BindInfo.MTU = Adapter->MTU;
853 BindInfo.Address = (PUCHAR)&Adapter->HWAddress;
854 BindInfo.AddressLength = Adapter->HWAddressLength;
855 BindInfo.Transmit = LANTransmit;
856
857 IF = IPCreateInterface(&BindInfo);
858
859 if (!IF) {
860 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
861 return;
862 }
863
864 /*
865 * Query per-adapter configuration from the registry
866 * In case anyone is curious: there *is* an Ndis configuration api
867 * for this sort of thing, but it doesn't really support things like
868 * REG_MULTI_SZ very well, and there is a note in the DDK that says that
869 * protocol drivers developed for win2k and above just use the native
870 * services (ZwOpenKey, etc).
871 */
872
873 Status = OpenRegistryKey( RegistryPath, &RegHandle );
874
875 if(NT_SUCCESS(Status))
876 Status = ReadIPAddressFromRegistry( RegHandle, L"DefaultGateway",
877 &DefaultGateway );
878 if(!NT_SUCCESS(Status)) {
879 Status = STATUS_SUCCESS;
880 RtlZeroMemory( &DefaultGateway, sizeof(DefaultGateway) );
881 }
882
883 if(NT_SUCCESS(Status))
884 Status = ReadIPAddressFromRegistry( RegHandle, L"IPAddress",
885 &IF->Unicast );
886 if(NT_SUCCESS(Status))
887 Status = ReadIPAddressFromRegistry( RegHandle, L"SubnetMask",
888 &IF->Netmask );
889 if(NT_SUCCESS(Status)) {
890 Status = ReadStringFromRegistry( RegHandle, L"DeviceDesc",
891 &IF->Name );
892
893 RtlZeroMemory( &IF->Name, sizeof( IF->Name ) );
894
895 /* I think that not getting a devicedesc is not a fatal error */
896 if( !NT_SUCCESS(Status) ) {
897 if( IF->Name.Buffer ) exFreePool( IF->Name.Buffer );
898 GetSimpleAdapterNameFromRegistryPath( &IF->Name, RegistryPath );
899 }
900 Status = STATUS_SUCCESS;
901 }
902
903 if(!NT_SUCCESS(Status))
904 {
905 TI_DbgPrint(MIN_TRACE, ("Unable to open protocol-specific registry key: 0x%x\n", Status));
906
907 /* XXX how do we proceed? No ip address, no parameters... do we guess? */
908 if(RegHandle)
909 ZwClose(RegHandle);
910 IPDestroyInterface(IF);
911 return;
912 }
913
914 TI_DbgPrint
915 (MID_TRACE,
916 ("--> Our IP address on this interface: '%s'\n",
917 A2S(&IF->Unicast)));
918
919 TI_DbgPrint
920 (MID_TRACE,
921 ("--> Our net mask on this interface: '%s'\n",
922 A2S(&IF->Netmask)));
923
924 if( DefaultGateway.Address.IPv4Address ) {
925 TI_DbgPrint
926 (MID_TRACE,
927 ("--> Our gateway is: '%s'\n",
928 A2S(&DefaultGateway)));
929
930 /* Create a default route */
931 RouterCreateRoute( &DefaultMask, /* Zero */
932 &DefaultMask, /* Zero */
933 &DefaultGateway,
934 IF,
935 1 );
936 }
937
938 /* Register interface with IP layer */
939 IPRegisterInterface(IF);
940
941 /* Set packet filter so we can send and receive packets */
942 NdisStatus = NDISCall(Adapter,
943 NdisRequestSetInformation,
944 OID_GEN_CURRENT_PACKET_FILTER,
945 &Adapter->PacketFilter,
946 sizeof(UINT));
947 if (NdisStatus != NDIS_STATUS_SUCCESS) {
948 TI_DbgPrint(MID_TRACE, ("Could not set packet filter (0x%X).\n", NdisStatus));
949 IPDestroyInterface(IF);
950 return;
951 }
952
953 Adapter->Context = IF;
954 Adapter->State = LAN_STATE_STARTED;
955 }
956
957
958 VOID UnbindAdapter(
959 PLAN_ADAPTER Adapter)
960 /*
961 * FUNCTION: Unbinds a LAN adapter from IP layer
962 * ARGUMENTS:
963 * Adapter = Pointer to LAN_ADAPTER structure
964 */
965 {
966 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
967
968 if (Adapter->State == LAN_STATE_STARTED) {
969 PIP_INTERFACE IF = Adapter->Context;
970
971 IPUnregisterInterface(IF);
972
973 IPDestroyInterface(IF);
974 }
975 }
976
977
978 NDIS_STATUS LANRegisterAdapter(
979 PNDIS_STRING AdapterName,
980 PNDIS_STRING RegistryPath)
981 /*
982 * FUNCTION: Registers protocol with an NDIS adapter
983 * ARGUMENTS:
984 * AdapterName = Pointer to string with name of adapter to register
985 * Adapter = Address of pointer to a LAN_ADAPTER structure
986 * RETURNS:
987 * Status of operation
988 */
989 {
990 PLAN_ADAPTER IF;
991 NDIS_STATUS NdisStatus;
992 NDIS_STATUS OpenStatus;
993 UINT MediaIndex;
994 NDIS_MEDIUM MediaArray[MAX_MEDIA];
995 UINT AddressOID;
996 UINT Speed;
997
998 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
999
1000 IF = exAllocatePool(NonPagedPool, sizeof(LAN_ADAPTER));
1001 if (!IF) {
1002 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
1003 return NDIS_STATUS_RESOURCES;
1004 }
1005
1006 RtlZeroMemory(IF, sizeof(LAN_ADAPTER));
1007
1008 /* Put adapter in stopped state */
1009 IF->State = LAN_STATE_STOPPED;
1010
1011 /* Initialize protecting spin lock */
1012 KeInitializeSpinLock(&IF->Lock);
1013
1014 KeInitializeEvent(&IF->Event, SynchronizationEvent, FALSE);
1015
1016 /* Initialize array with media IDs we support */
1017 MediaArray[MEDIA_ETH] = NdisMedium802_3;
1018
1019 TI_DbgPrint(DEBUG_DATALINK,("opening adapter %wZ\n", AdapterName));
1020 /* Open the adapter. */
1021 NdisOpenAdapter(&NdisStatus,
1022 &OpenStatus,
1023 &IF->NdisHandle,
1024 &MediaIndex,
1025 MediaArray,
1026 MAX_MEDIA,
1027 NdisProtocolHandle,
1028 IF,
1029 AdapterName,
1030 0,
1031 NULL);
1032
1033 /* Wait until the adapter is opened */
1034 if (NdisStatus == NDIS_STATUS_PENDING)
1035 KeWaitForSingleObject(&IF->Event, UserRequest, KernelMode, FALSE, NULL);
1036 else if (NdisStatus != NDIS_STATUS_SUCCESS) {
1037 exFreePool(IF);
1038 return NdisStatus;
1039 }
1040
1041 IF->Media = MediaArray[MediaIndex];
1042
1043 /* Fill LAN_ADAPTER structure with some adapter specific information */
1044 switch (IF->Media) {
1045 case NdisMedium802_3:
1046 IF->HWAddressLength = IEEE_802_ADDR_LENGTH;
1047 IF->BCastMask = BCAST_ETH_MASK;
1048 IF->BCastCheck = BCAST_ETH_CHECK;
1049 IF->BCastOffset = BCAST_ETH_OFFSET;
1050 IF->HeaderSize = sizeof(ETH_HEADER);
1051 IF->MinFrameSize = 60;
1052 AddressOID = OID_802_3_CURRENT_ADDRESS;
1053 IF->PacketFilter =
1054 NDIS_PACKET_TYPE_BROADCAST |
1055 NDIS_PACKET_TYPE_DIRECTED |
1056 NDIS_PACKET_TYPE_MULTICAST;
1057 break;
1058
1059 default:
1060 /* Unsupported media */
1061 TI_DbgPrint(MIN_TRACE, ("Unsupported media.\n"));
1062 exFreePool(IF);
1063 return NDIS_STATUS_NOT_SUPPORTED;
1064 }
1065
1066 /* Get maximum frame size */
1067 NdisStatus = NDISCall(IF,
1068 NdisRequestQueryInformation,
1069 OID_GEN_MAXIMUM_FRAME_SIZE,
1070 &IF->MTU,
1071 sizeof(UINT));
1072 if (NdisStatus != NDIS_STATUS_SUCCESS) {
1073 exFreePool(IF);
1074 return NdisStatus;
1075 }
1076
1077 /* Get maximum packet size */
1078 NdisStatus = NDISCall(IF,
1079 NdisRequestQueryInformation,
1080 OID_GEN_MAXIMUM_TOTAL_SIZE,
1081 &IF->MaxPacketSize,
1082 sizeof(UINT));
1083 if (NdisStatus != NDIS_STATUS_SUCCESS) {
1084 TI_DbgPrint(MIN_TRACE, ("Query for maximum packet size failed.\n"));
1085 exFreePool(IF);
1086 return NdisStatus;
1087 }
1088
1089 /* Get maximum number of packets we can pass to NdisSend(Packets) at one time */
1090 NdisStatus = NDISCall(IF,
1091 NdisRequestQueryInformation,
1092 OID_GEN_MAXIMUM_SEND_PACKETS,
1093 &IF->MaxSendPackets,
1094 sizeof(UINT));
1095 if (NdisStatus != NDIS_STATUS_SUCCESS)
1096 /* Legacy NIC drivers may not support this query, if it fails we
1097 assume it can send at least one packet per call to NdisSend(Packets) */
1098 IF->MaxSendPackets = 1;
1099
1100 /* Get current hardware address */
1101 NdisStatus = NDISCall(IF,
1102 NdisRequestQueryInformation,
1103 AddressOID,
1104 &IF->HWAddress,
1105 IF->HWAddressLength);
1106 if (NdisStatus != NDIS_STATUS_SUCCESS) {
1107 TI_DbgPrint(MIN_TRACE, ("Query for current hardware address failed.\n"));
1108 exFreePool(IF);
1109 return NdisStatus;
1110 }
1111
1112 /* Get maximum link speed */
1113 NdisStatus = NDISCall(IF,
1114 NdisRequestQueryInformation,
1115 OID_GEN_LINK_SPEED,
1116 &Speed,
1117 sizeof(UINT));
1118 if (NdisStatus != NDIS_STATUS_SUCCESS) {
1119 TI_DbgPrint(MIN_TRACE, ("Query for maximum link speed failed.\n"));
1120 exFreePool(IF);
1121 return NdisStatus;
1122 }
1123
1124 /* Convert returned link speed to bps (it is in 100bps increments) */
1125 IF->Speed = Speed * 100L;
1126
1127 /* Add adapter to the adapter list */
1128 ExInterlockedInsertTailList(&AdapterListHead,
1129 &IF->ListEntry,
1130 &AdapterListLock);
1131
1132 /* Bind adapter to IP layer */
1133 BindAdapter(IF, RegistryPath);
1134
1135 TI_DbgPrint(DEBUG_DATALINK, ("Leaving.\n"));
1136
1137 return NDIS_STATUS_SUCCESS;
1138 }
1139
1140
1141 NDIS_STATUS LANUnregisterAdapter(
1142 PLAN_ADAPTER Adapter)
1143 /*
1144 * FUNCTION: Unregisters protocol with NDIS adapter
1145 * ARGUMENTS:
1146 * Adapter = Pointer to a LAN_ADAPTER structure
1147 * RETURNS:
1148 * Status of operation
1149 */
1150 {
1151 KIRQL OldIrql;
1152 NDIS_HANDLE NdisHandle;
1153 NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS;
1154
1155 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
1156
1157 /* Unlink the adapter from the list */
1158 RemoveEntryList(&Adapter->ListEntry);
1159
1160 /* Unbind adapter from IP layer */
1161 UnbindAdapter(Adapter);
1162
1163 TcpipAcquireSpinLock(&Adapter->Lock, &OldIrql);
1164 NdisHandle = Adapter->NdisHandle;
1165 if (NdisHandle) {
1166 Adapter->NdisHandle = NULL;
1167 TcpipReleaseSpinLock(&Adapter->Lock, OldIrql);
1168
1169 NdisCloseAdapter(&NdisStatus, NdisHandle);
1170 if (NdisStatus == NDIS_STATUS_PENDING) {
1171 TcpipWaitForSingleObject(&Adapter->Event,
1172 UserRequest,
1173 KernelMode,
1174 FALSE,
1175 NULL);
1176 NdisStatus = Adapter->NdisStatus;
1177 }
1178 } else
1179 TcpipReleaseSpinLock(&Adapter->Lock, OldIrql);
1180
1181 FreeAdapter(Adapter);
1182
1183 return NDIS_STATUS_SUCCESS;
1184 }
1185
1186
1187 NTSTATUS LANRegisterProtocol(
1188 PNDIS_STRING Name)
1189 /*
1190 * FUNCTION: Registers this protocol driver with NDIS
1191 * ARGUMENTS:
1192 * Name = Name of this protocol driver
1193 * RETURNS:
1194 * Status of operation
1195 */
1196 {
1197 NDIS_STATUS NdisStatus;
1198 NDIS_PROTOCOL_CHARACTERISTICS ProtChars;
1199
1200 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
1201
1202 InitializeListHead(&AdapterListHead);
1203 KeInitializeSpinLock(&AdapterListLock);
1204
1205 /* Set up protocol characteristics */
1206 RtlZeroMemory(&ProtChars, sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
1207 ProtChars.MajorNdisVersion = NDIS_VERSION_MAJOR;
1208 ProtChars.MinorNdisVersion = NDIS_VERSION_MINOR;
1209 ProtChars.Name.Length = Name->Length;
1210 ProtChars.Name.Buffer = Name->Buffer;
1211 ProtChars.Name.MaximumLength = Name->MaximumLength;
1212 ProtChars.OpenAdapterCompleteHandler = ProtocolOpenAdapterComplete;
1213 ProtChars.CloseAdapterCompleteHandler = ProtocolCloseAdapterComplete;
1214 ProtChars.ResetCompleteHandler = ProtocolResetComplete;
1215 ProtChars.RequestCompleteHandler = ProtocolRequestComplete;
1216 ProtChars.SendCompleteHandler = ProtocolSendComplete;
1217 ProtChars.TransferDataCompleteHandler = ProtocolTransferDataComplete;
1218 ProtChars.ReceiveHandler = ProtocolReceive;
1219 ProtChars.ReceiveCompleteHandler = ProtocolReceiveComplete;
1220 ProtChars.StatusHandler = ProtocolStatus;
1221 ProtChars.StatusCompleteHandler = ProtocolStatusComplete;
1222 ProtChars.BindAdapterHandler = ProtocolBindAdapter;
1223
1224 /* Try to register protocol */
1225 NdisRegisterProtocol(&NdisStatus,
1226 &NdisProtocolHandle,
1227 &ProtChars,
1228 sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
1229 if (NdisStatus != NDIS_STATUS_SUCCESS)
1230 {
1231 TI_DbgPrint(MID_TRACE, ("NdisRegisterProtocol failed, status 0x%x\n", NdisStatus));
1232 return (NTSTATUS)NdisStatus;
1233 }
1234
1235 ProtocolRegistered = TRUE;
1236
1237 return STATUS_SUCCESS;
1238 }
1239
1240
1241 VOID LANUnregisterProtocol(
1242 VOID)
1243 /*
1244 * FUNCTION: Unregisters this protocol driver with NDIS
1245 * NOTES: Does not care wether we are already registered
1246 */
1247 {
1248 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
1249
1250 if (ProtocolRegistered) {
1251 NDIS_STATUS NdisStatus;
1252 PLIST_ENTRY CurrentEntry;
1253 PLIST_ENTRY NextEntry;
1254 PLAN_ADAPTER Current;
1255 KIRQL OldIrql;
1256
1257 TcpipAcquireSpinLock(&AdapterListLock, &OldIrql);
1258
1259 /* Search the list and remove every adapter we find */
1260 CurrentEntry = AdapterListHead.Flink;
1261 while (CurrentEntry != &AdapterListHead) {
1262 NextEntry = CurrentEntry->Flink;
1263 Current = CONTAINING_RECORD(CurrentEntry, LAN_ADAPTER, ListEntry);
1264 /* Unregister it */
1265 LANUnregisterAdapter(Current);
1266 CurrentEntry = NextEntry;
1267 }
1268
1269 TcpipReleaseSpinLock(&AdapterListLock, OldIrql);
1270
1271 NdisDeregisterProtocol(&NdisStatus, NdisProtocolHandle);
1272 ProtocolRegistered = FALSE;
1273 }
1274 }
1275
1276 VOID LANStartup() {
1277 InitializeListHead( &LanWorkList );
1278 InitializeListHead( &LanSendCompleteList );
1279 KeInitializeSpinLock( &LanSendCompleteLock );
1280 ExInitializeWorkItem( &LanWorkItem, LanReceiveWorker, NULL );
1281 }
1282
1283 VOID LANShutdown() {
1284 KIRQL OldIrql;
1285 PLAN_WQ_ITEM WorkItem;
1286 PLIST_ENTRY ListEntry;
1287
1288 TcpipAcquireSpinLock( &LanWorkLock, &OldIrql );
1289 while( !IsListEmpty( &LanWorkList ) ) {
1290 ListEntry = RemoveHeadList( &LanWorkList );
1291 WorkItem = CONTAINING_RECORD(ListEntry, LAN_WQ_ITEM, ListEntry);
1292 FreeNdisPacket( WorkItem->Packet );
1293 ExFreePool( WorkItem );
1294 }
1295 TcpipReleaseSpinLock( &LanWorkLock, OldIrql );
1296
1297 KeAcquireSpinLock( &LanSendCompleteLock, &OldIrql );
1298 while( !IsListEmpty( &LanSendCompleteList ) ) {
1299 ListEntry = RemoveHeadList( &LanSendCompleteList );
1300 WorkItem = CONTAINING_RECORD(ListEntry, LAN_WQ_ITEM, ListEntry);
1301 FreeNdisPacket( WorkItem->Packet );
1302 ExFreePool( WorkItem );
1303 }
1304 KeReleaseSpinLock( &LanSendCompleteLock, OldIrql );
1305 }
1306
1307 /* EOF */