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