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