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