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