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