- Merge aicom-network-fixes up to r36740
[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 HANDLE RegHandle = 0;
968
969 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
970
971 Adapter->State = LAN_STATE_OPENING;
972
973 NdisStatus = NDISCall(Adapter,
974 NdisRequestSetInformation,
975 OID_GEN_CURRENT_LOOKAHEAD,
976 &Lookahead,
977 sizeof(ULONG));
978 if (NdisStatus != NDIS_STATUS_SUCCESS) {
979 TI_DbgPrint(DEBUG_DATALINK, ("Could not set lookahead buffer size (0x%X).\n", NdisStatus));
980 return FALSE;
981 }
982
983 /* Bind the adapter to IP layer */
984 BindInfo.Context = Adapter;
985 BindInfo.HeaderSize = Adapter->HeaderSize;
986 BindInfo.MinFrameSize = Adapter->MinFrameSize;
987 BindInfo.MTU = Adapter->MTU;
988 BindInfo.Address = (PUCHAR)&Adapter->HWAddress;
989 BindInfo.AddressLength = Adapter->HWAddressLength;
990 BindInfo.Transmit = LANTransmit;
991
992 IF = IPCreateInterface(&BindInfo);
993
994 if (!IF) {
995 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
996 return FALSE;
997 }
998
999 /*
1000 * Query per-adapter configuration from the registry
1001 * In case anyone is curious: there *is* an Ndis configuration api
1002 * for this sort of thing, but it doesn't really support things like
1003 * REG_MULTI_SZ very well, and there is a note in the DDK that says that
1004 * protocol drivers developed for win2k and above just use the native
1005 * services (ZwOpenKey, etc).
1006 */
1007
1008 GetName( RegistryPath, &IF->Name );
1009
1010 Status = OpenRegistryKey( RegistryPath, &RegHandle );
1011
1012 if(NT_SUCCESS(Status)) {
1013 Status = FindDeviceDescForAdapter( &IF->Name, &IF->Description );
1014 TI_DbgPrint(DEBUG_DATALINK,("Adapter Description: %wZ\n",
1015 &IF->Description));
1016 } else {
1017 IPDestroyInterface( IF );
1018 return FALSE;
1019 }
1020
1021 DefaultMask.Type = IP_ADDRESS_V4;
1022
1023 IF->Unicast = DefaultMask;
1024 IF->Netmask = DefaultMask;
1025
1026 IF->Broadcast.Type = IP_ADDRESS_V4;
1027 IF->Broadcast.Address.IPv4Address =
1028 IF->Unicast.Address.IPv4Address |
1029 ~IF->Netmask.Address.IPv4Address;
1030
1031 TI_DbgPrint(DEBUG_DATALINK,("BCAST(IF) %s\n", A2S(&IF->Broadcast)));
1032
1033 /* Get maximum link speed */
1034 NdisStatus = NDISCall(Adapter,
1035 NdisRequestQueryInformation,
1036 OID_GEN_LINK_SPEED,
1037 &IF->Speed,
1038 sizeof(UINT));
1039
1040 if( !NT_SUCCESS(NdisStatus) )
1041 IF->Speed = IP_DEFAULT_LINK_SPEED;
1042
1043 /* Register interface with IP layer */
1044 IPRegisterInterface(IF);
1045
1046 /* Set packet filter so we can send and receive packets */
1047 NdisStatus = NDISCall(Adapter,
1048 NdisRequestSetInformation,
1049 OID_GEN_CURRENT_PACKET_FILTER,
1050 &Adapter->PacketFilter,
1051 sizeof(UINT));
1052
1053 if (NdisStatus != NDIS_STATUS_SUCCESS) {
1054 TI_DbgPrint(DEBUG_DATALINK, ("Could not set packet filter (0x%X).\n", NdisStatus));
1055 IPDestroyInterface(IF);
1056 return FALSE;
1057 }
1058
1059 Adapter->Context = IF;
1060 Adapter->State = LAN_STATE_STARTED;
1061 return TRUE;
1062 }
1063
1064
1065 VOID UnbindAdapter(
1066 PLAN_ADAPTER Adapter)
1067 /*
1068 * FUNCTION: Unbinds a LAN adapter from IP layer
1069 * ARGUMENTS:
1070 * Adapter = Pointer to LAN_ADAPTER structure
1071 */
1072 {
1073 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
1074
1075 if (Adapter->State == LAN_STATE_STARTED) {
1076 PIP_INTERFACE IF = Adapter->Context;
1077
1078 IPUnregisterInterface(IF);
1079
1080 IPDestroyInterface(IF);
1081 }
1082 }
1083
1084
1085 NDIS_STATUS LANRegisterAdapter(
1086 PNDIS_STRING AdapterName,
1087 PNDIS_STRING RegistryPath)
1088 /*
1089 * FUNCTION: Registers protocol with an NDIS adapter
1090 * ARGUMENTS:
1091 * AdapterName = Pointer to string with name of adapter to register
1092 * Adapter = Address of pointer to a LAN_ADAPTER structure
1093 * RETURNS:
1094 * Status of operation
1095 */
1096 {
1097 PLAN_ADAPTER IF;
1098 NDIS_STATUS NdisStatus;
1099 NDIS_STATUS OpenStatus;
1100 UINT MediaIndex;
1101 NDIS_MEDIUM MediaArray[MAX_MEDIA];
1102 UINT AddressOID;
1103 UINT Speed;
1104
1105 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
1106
1107 IF = exAllocatePool(NonPagedPool, sizeof(LAN_ADAPTER));
1108 if (!IF) {
1109 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
1110 return NDIS_STATUS_RESOURCES;
1111 }
1112
1113 RtlZeroMemory(IF, sizeof(LAN_ADAPTER));
1114
1115 /* Put adapter in stopped state */
1116 IF->State = LAN_STATE_STOPPED;
1117
1118 /* Initialize protecting spin lock */
1119 KeInitializeSpinLock(&IF->Lock);
1120
1121 KeInitializeEvent(&IF->Event, SynchronizationEvent, FALSE);
1122
1123 /* Initialize array with media IDs we support */
1124 MediaArray[MEDIA_ETH] = NdisMedium802_3;
1125
1126 TI_DbgPrint(DEBUG_DATALINK,("opening adapter %wZ\n", AdapterName));
1127 /* Open the adapter. */
1128 NdisOpenAdapter(&NdisStatus,
1129 &OpenStatus,
1130 &IF->NdisHandle,
1131 &MediaIndex,
1132 MediaArray,
1133 MAX_MEDIA,
1134 NdisProtocolHandle,
1135 IF,
1136 AdapterName,
1137 0,
1138 NULL);
1139
1140 /* Wait until the adapter is opened */
1141 if (NdisStatus == NDIS_STATUS_PENDING)
1142 KeWaitForSingleObject(&IF->Event, UserRequest, KernelMode, FALSE, NULL);
1143 else if (NdisStatus != NDIS_STATUS_SUCCESS) {
1144 TI_DbgPrint(DEBUG_DATALINK,("denying adapter %wZ\n", AdapterName));
1145 exFreePool(IF);
1146 return NdisStatus;
1147 }
1148
1149 IF->Media = MediaArray[MediaIndex];
1150
1151 /* Fill LAN_ADAPTER structure with some adapter specific information */
1152 switch (IF->Media) {
1153 case NdisMedium802_3:
1154 IF->HWAddressLength = IEEE_802_ADDR_LENGTH;
1155 IF->BCastMask = BCAST_ETH_MASK;
1156 IF->BCastCheck = BCAST_ETH_CHECK;
1157 IF->BCastOffset = BCAST_ETH_OFFSET;
1158 IF->HeaderSize = sizeof(ETH_HEADER);
1159 IF->MinFrameSize = 60;
1160 AddressOID = OID_802_3_CURRENT_ADDRESS;
1161 IF->PacketFilter =
1162 NDIS_PACKET_TYPE_BROADCAST |
1163 NDIS_PACKET_TYPE_DIRECTED |
1164 NDIS_PACKET_TYPE_MULTICAST;
1165 break;
1166
1167 default:
1168 /* Unsupported media */
1169 TI_DbgPrint(MIN_TRACE, ("Unsupported media.\n"));
1170 exFreePool(IF);
1171 return NDIS_STATUS_NOT_SUPPORTED;
1172 }
1173
1174 /* Get maximum frame size */
1175 NdisStatus = NDISCall(IF,
1176 NdisRequestQueryInformation,
1177 OID_GEN_MAXIMUM_FRAME_SIZE,
1178 &IF->MTU,
1179 sizeof(UINT));
1180 if (NdisStatus != NDIS_STATUS_SUCCESS) {
1181 TI_DbgPrint(DEBUG_DATALINK,("denying adapter %wZ (NDISCall)\n", AdapterName));
1182 exFreePool(IF);
1183 return NdisStatus;
1184 }
1185
1186 /* Get maximum packet size */
1187 NdisStatus = NDISCall(IF,
1188 NdisRequestQueryInformation,
1189 OID_GEN_MAXIMUM_TOTAL_SIZE,
1190 &IF->MaxPacketSize,
1191 sizeof(UINT));
1192 if (NdisStatus != NDIS_STATUS_SUCCESS) {
1193 TI_DbgPrint(MIN_TRACE, ("Query for maximum packet size failed.\n"));
1194 exFreePool(IF);
1195 return NdisStatus;
1196 }
1197
1198 /* Get maximum number of packets we can pass to NdisSend(Packets) at one time */
1199 NdisStatus = NDISCall(IF,
1200 NdisRequestQueryInformation,
1201 OID_GEN_MAXIMUM_SEND_PACKETS,
1202 &IF->MaxSendPackets,
1203 sizeof(UINT));
1204 if (NdisStatus != NDIS_STATUS_SUCCESS)
1205 /* Legacy NIC drivers may not support this query, if it fails we
1206 assume it can send at least one packet per call to NdisSend(Packets) */
1207 IF->MaxSendPackets = 1;
1208
1209 /* Get current hardware address */
1210 NdisStatus = NDISCall(IF,
1211 NdisRequestQueryInformation,
1212 AddressOID,
1213 &IF->HWAddress,
1214 IF->HWAddressLength);
1215 if (NdisStatus != NDIS_STATUS_SUCCESS) {
1216 TI_DbgPrint(MIN_TRACE, ("Query for current hardware address failed.\n"));
1217 exFreePool(IF);
1218 return NdisStatus;
1219 }
1220
1221 /* Get maximum link speed */
1222 NdisStatus = NDISCall(IF,
1223 NdisRequestQueryInformation,
1224 OID_GEN_LINK_SPEED,
1225 &Speed,
1226 sizeof(UINT));
1227 if (NdisStatus != NDIS_STATUS_SUCCESS) {
1228 TI_DbgPrint(MIN_TRACE, ("Query for maximum link speed failed.\n"));
1229 exFreePool(IF);
1230 return NdisStatus;
1231 }
1232
1233 /* Convert returned link speed to bps (it is in 100bps increments) */
1234 IF->Speed = Speed * 100L;
1235
1236 /* Bind adapter to IP layer */
1237 if( !BindAdapter(IF, RegistryPath) ) {
1238 TI_DbgPrint(DEBUG_DATALINK,("denying adapter %wZ (BindAdapter)\n", AdapterName));
1239 exFreePool(IF);
1240 return NDIS_STATUS_NOT_ACCEPTED;
1241 }
1242
1243 /* Add adapter to the adapter list */
1244 ExInterlockedInsertTailList(&AdapterListHead,
1245 &IF->ListEntry,
1246 &AdapterListLock);
1247
1248 TI_DbgPrint(DEBUG_DATALINK, ("Leaving.\n"));
1249
1250 return NDIS_STATUS_SUCCESS;
1251 }
1252
1253
1254 NDIS_STATUS LANUnregisterAdapter(
1255 PLAN_ADAPTER Adapter)
1256 /*
1257 * FUNCTION: Unregisters protocol with NDIS adapter
1258 * ARGUMENTS:
1259 * Adapter = Pointer to a LAN_ADAPTER structure
1260 * RETURNS:
1261 * Status of operation
1262 */
1263 {
1264 KIRQL OldIrql;
1265 NDIS_HANDLE NdisHandle;
1266 NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS;
1267
1268 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
1269
1270 /* Unlink the adapter from the list */
1271 RemoveEntryList(&Adapter->ListEntry);
1272
1273 /* Unbind adapter from IP layer */
1274 UnbindAdapter(Adapter);
1275
1276 TcpipAcquireSpinLock(&Adapter->Lock, &OldIrql);
1277 NdisHandle = Adapter->NdisHandle;
1278 if (NdisHandle) {
1279 Adapter->NdisHandle = NULL;
1280 TcpipReleaseSpinLock(&Adapter->Lock, OldIrql);
1281
1282 NdisCloseAdapter(&NdisStatus, NdisHandle);
1283 if (NdisStatus == NDIS_STATUS_PENDING) {
1284 TcpipWaitForSingleObject(&Adapter->Event,
1285 UserRequest,
1286 KernelMode,
1287 FALSE,
1288 NULL);
1289 NdisStatus = Adapter->NdisStatus;
1290 }
1291 } else
1292 TcpipReleaseSpinLock(&Adapter->Lock, OldIrql);
1293
1294 FreeAdapter(Adapter);
1295
1296 return NdisStatus;
1297 }
1298
1299
1300 NTSTATUS LANRegisterProtocol(
1301 PNDIS_STRING Name)
1302 /*
1303 * FUNCTION: Registers this protocol driver with NDIS
1304 * ARGUMENTS:
1305 * Name = Name of this protocol driver
1306 * RETURNS:
1307 * Status of operation
1308 */
1309 {
1310 NDIS_STATUS NdisStatus;
1311 NDIS_PROTOCOL_CHARACTERISTICS ProtChars;
1312
1313 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
1314
1315 InitializeListHead(&AdapterListHead);
1316 KeInitializeSpinLock(&AdapterListLock);
1317
1318 /* Set up protocol characteristics */
1319 RtlZeroMemory(&ProtChars, sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
1320 ProtChars.MajorNdisVersion = NDIS_VERSION_MAJOR;
1321 ProtChars.MinorNdisVersion = NDIS_VERSION_MINOR;
1322 ProtChars.Name.Length = Name->Length;
1323 ProtChars.Name.Buffer = Name->Buffer;
1324 ProtChars.Name.MaximumLength = Name->MaximumLength;
1325 ProtChars.OpenAdapterCompleteHandler = ProtocolOpenAdapterComplete;
1326 ProtChars.CloseAdapterCompleteHandler = ProtocolCloseAdapterComplete;
1327 ProtChars.ResetCompleteHandler = ProtocolResetComplete;
1328 ProtChars.RequestCompleteHandler = ProtocolRequestComplete;
1329 ProtChars.SendCompleteHandler = ProtocolSendComplete;
1330 ProtChars.TransferDataCompleteHandler = ProtocolTransferDataComplete;
1331 ProtChars.ReceiveHandler = ProtocolReceive;
1332 ProtChars.ReceiveCompleteHandler = ProtocolReceiveComplete;
1333 ProtChars.StatusHandler = ProtocolStatus;
1334 ProtChars.StatusCompleteHandler = ProtocolStatusComplete;
1335 ProtChars.BindAdapterHandler = ProtocolBindAdapter;
1336
1337 /* Try to register protocol */
1338 NdisRegisterProtocol(&NdisStatus,
1339 &NdisProtocolHandle,
1340 &ProtChars,
1341 sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
1342 if (NdisStatus != NDIS_STATUS_SUCCESS)
1343 {
1344 TI_DbgPrint(DEBUG_DATALINK, ("NdisRegisterProtocol failed, status 0x%x\n", NdisStatus));
1345 return (NTSTATUS)NdisStatus;
1346 }
1347
1348 ProtocolRegistered = TRUE;
1349
1350 return STATUS_SUCCESS;
1351 }
1352
1353
1354 VOID LANUnregisterProtocol(
1355 VOID)
1356 /*
1357 * FUNCTION: Unregisters this protocol driver with NDIS
1358 * NOTES: Does not care wether we are already registered
1359 */
1360 {
1361 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
1362
1363 if (ProtocolRegistered) {
1364 NDIS_STATUS NdisStatus;
1365 PLIST_ENTRY CurrentEntry;
1366 PLIST_ENTRY NextEntry;
1367 PLAN_ADAPTER Current;
1368 KIRQL OldIrql;
1369
1370 TcpipAcquireSpinLock(&AdapterListLock, &OldIrql);
1371
1372 /* Search the list and remove every adapter we find */
1373 CurrentEntry = AdapterListHead.Flink;
1374 while (CurrentEntry != &AdapterListHead) {
1375 NextEntry = CurrentEntry->Flink;
1376 Current = CONTAINING_RECORD(CurrentEntry, LAN_ADAPTER, ListEntry);
1377 /* Unregister it */
1378 LANUnregisterAdapter(Current);
1379 CurrentEntry = NextEntry;
1380 }
1381
1382 TcpipReleaseSpinLock(&AdapterListLock, OldIrql);
1383
1384 NdisDeregisterProtocol(&NdisStatus, NdisProtocolHandle);
1385 ProtocolRegistered = FALSE;
1386 }
1387 }
1388
1389 VOID LANStartup() {
1390 InitializeListHead( &LanSendCompleteList );
1391 KeInitializeSpinLock( &LanSendCompleteLock );
1392 }
1393
1394 VOID LANShutdown() {
1395 KIRQL OldIrql;
1396 PLAN_WQ_ITEM WorkItem;
1397 PLIST_ENTRY ListEntry;
1398
1399 KeAcquireSpinLock( &LanSendCompleteLock, &OldIrql );
1400 while( !IsListEmpty( &LanSendCompleteList ) ) {
1401 ListEntry = RemoveHeadList( &LanSendCompleteList );
1402 WorkItem = CONTAINING_RECORD(ListEntry, LAN_WQ_ITEM, ListEntry);
1403 FreeNdisPacket( WorkItem->Packet );
1404 ExFreePool( WorkItem );
1405 }
1406 KeReleaseSpinLock( &LanSendCompleteLock, OldIrql );
1407 }
1408
1409 /* EOF */