Merge aicom-network-fixes up to 35155
[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 if (NdisStatus == NDIS_STATUS_SUCCESS)
489 {
490 NdisTransferData(&NdisStatus, Adapter->NdisHandle,
491 MacReceiveContext, 0, PacketSize,
492 NdisPacket, &BytesTransferred);
493 }
494 else
495 {
496 BytesTransferred = 0;
497 }
498 }
499 TI_DbgPrint(DEBUG_DATALINK, ("Calling complete\n"));
500
501 if (NdisStatus != NDIS_STATUS_PENDING)
502 ProtocolTransferDataComplete(BindingContext,
503 NdisPacket,
504 NdisStatus,
505 PacketSize);
506
507 TI_DbgPrint(DEBUG_DATALINK, ("leaving\n"));
508
509 return NDIS_STATUS_SUCCESS;
510 }
511
512
513 VOID STDCALL ProtocolReceiveComplete(
514 NDIS_HANDLE BindingContext)
515 /*
516 * FUNCTION: Called by NDIS when we're done receiving data
517 * ARGUMENTS:
518 * BindingContext = Pointer to a device context (LAN_ADAPTER)
519 */
520 {
521 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
522 }
523
524
525 VOID STDCALL ProtocolStatus(
526 NDIS_HANDLE BindingContext,
527 NDIS_STATUS GenerelStatus,
528 PVOID StatusBuffer,
529 UINT StatusBufferSize)
530 /*
531 * FUNCTION: Called by NDIS when the underlying driver has changed state
532 * ARGUMENTS:
533 * BindingContext = Pointer to a device context (LAN_ADAPTER)
534 * GenerelStatus = A generel status code
535 * StatusBuffer = Pointer to a buffer with medium-specific data
536 * StatusBufferSize = Number of bytes in StatusBuffer
537 */
538 {
539 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
540 }
541
542
543 VOID STDCALL ProtocolStatusComplete(
544 NDIS_HANDLE NdisBindingContext)
545 /*
546 * FUNCTION: Called by NDIS when a status-change has occurred
547 * ARGUMENTS:
548 * BindingContext = Pointer to a device context (LAN_ADAPTER)
549 */
550 {
551 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
552 }
553
554 VOID STDCALL ProtocolBindAdapter(
555 OUT PNDIS_STATUS Status,
556 IN NDIS_HANDLE BindContext,
557 IN PNDIS_STRING DeviceName,
558 IN PVOID SystemSpecific1,
559 IN PVOID SystemSpecific2)
560 /*
561 * FUNCTION: Called by NDIS during NdisRegisterProtocol to set up initial
562 * bindings, and periodically thereafer as new adapters come online
563 * ARGUMENTS:
564 * Status: Return value to NDIS
565 * BindContext: Handle provided by NDIS to track pending binding operations
566 * DeviceName: Name of the miniport device to bind to
567 * SystemSpecific1: Pointer to a registry path with protocol-specific configuration information
568 * SystemSpecific2: Unused & must not be touched
569 */
570 {
571 /* XXX confirm that this is still true, or re-word the following comment */
572 /* we get to ignore BindContext because we will never pend an operation with NDIS */
573 TI_DbgPrint(DEBUG_DATALINK, ("Called with registry path %wZ for %wZ\n", SystemSpecific1, DeviceName));
574 *Status = LANRegisterAdapter(DeviceName, SystemSpecific1);
575 }
576
577
578 VOID LANTransmit(
579 PVOID Context,
580 PNDIS_PACKET NdisPacket,
581 UINT Offset,
582 PVOID LinkAddress,
583 USHORT Type)
584 /*
585 * FUNCTION: Transmits a packet
586 * ARGUMENTS:
587 * Context = Pointer to context information (LAN_ADAPTER)
588 * NdisPacket = Pointer to NDIS packet to send
589 * Offset = Offset in packet where data starts
590 * LinkAddress = Pointer to link address of destination (NULL = broadcast)
591 * Type = LAN protocol type (LAN_PROTO_*)
592 */
593 {
594 NDIS_STATUS NdisStatus;
595 PETH_HEADER EHeader;
596 PCHAR Data;
597 UINT Size;
598 KIRQL OldIrql;
599 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)Context;
600
601 TI_DbgPrint(DEBUG_DATALINK,
602 ("Called( NdisPacket %x, Offset %d, Adapter %x )\n",
603 NdisPacket, Offset, Adapter));
604
605 TI_DbgPrint(DEBUG_DATALINK,
606 ("Adapter Address [%02x %02x %02x %02x %02x %02x]\n",
607 Adapter->HWAddress[0] & 0xff,
608 Adapter->HWAddress[1] & 0xff,
609 Adapter->HWAddress[2] & 0xff,
610 Adapter->HWAddress[3] & 0xff,
611 Adapter->HWAddress[4] & 0xff,
612 Adapter->HWAddress[5] & 0xff));
613
614 /* XXX arty -- Handled adjustment in a saner way than before ...
615 * not needed immediately */
616 GetDataPtr( NdisPacket, 0, &Data, &Size );
617
618 LanChainCompletion( Adapter, NdisPacket );
619
620 if (Adapter->State == LAN_STATE_STARTED) {
621 switch (Adapter->Media) {
622 case NdisMedium802_3:
623 EHeader = (PETH_HEADER)Data;
624
625 if (LinkAddress) {
626 /* Unicast address */
627 RtlCopyMemory(EHeader->DstAddr, LinkAddress, IEEE_802_ADDR_LENGTH);
628 } else {
629 /* Broadcast address */
630 RtlFillMemory(EHeader->DstAddr, IEEE_802_ADDR_LENGTH, 0xFF);
631 }
632
633 RtlCopyMemory(EHeader->SrcAddr, Adapter->HWAddress, IEEE_802_ADDR_LENGTH);
634
635 switch (Type) {
636 case LAN_PROTO_IPv4:
637 EHeader->EType = ETYPE_IPv4;
638 break;
639 case LAN_PROTO_ARP:
640 EHeader->EType = ETYPE_ARP;
641 break;
642 case LAN_PROTO_IPv6:
643 EHeader->EType = ETYPE_IPv6;
644 break;
645 default:
646 #ifdef DBG
647 /* Should not happen */
648 TI_DbgPrint(MIN_TRACE, ("Unknown LAN protocol.\n"));
649
650 ProtocolSendComplete((NDIS_HANDLE)Context,
651 NdisPacket,
652 NDIS_STATUS_FAILURE);
653 #endif
654 return;
655 }
656 break;
657
658 default:
659 /* FIXME: Support other medias */
660 break;
661 }
662
663 TI_DbgPrint( MID_TRACE, ("LinkAddress: %x\n", LinkAddress));
664 if( LinkAddress ) {
665 TI_DbgPrint
666 ( MID_TRACE,
667 ("Link Address [%02x %02x %02x %02x %02x %02x]\n",
668 ((PCHAR)LinkAddress)[0] & 0xff,
669 ((PCHAR)LinkAddress)[1] & 0xff,
670 ((PCHAR)LinkAddress)[2] & 0xff,
671 ((PCHAR)LinkAddress)[3] & 0xff,
672 ((PCHAR)LinkAddress)[4] & 0xff,
673 ((PCHAR)LinkAddress)[5] & 0xff));
674 }
675
676 TcpipAcquireSpinLock( &Adapter->Lock, &OldIrql );
677 TI_DbgPrint(MID_TRACE, ("NdisSend\n"));
678 NdisSend(&NdisStatus, Adapter->NdisHandle, NdisPacket);
679 TI_DbgPrint(MID_TRACE, ("NdisSend %s\n",
680 NdisStatus == NDIS_STATUS_PENDING ?
681 "Pending" : "Complete"));
682 TcpipReleaseSpinLock( &Adapter->Lock, OldIrql );
683
684 /* I had a talk with vizzini: these really ought to be here.
685 * we're supposed to see these completed by ndis *only* when
686 * status_pending is returned. Note that this is different from
687 * the situation with IRPs. */
688 if (NdisStatus != NDIS_STATUS_PENDING)
689 ProtocolSendComplete((NDIS_HANDLE)Context, NdisPacket, NdisStatus);
690 } else {
691 ProtocolSendComplete((NDIS_HANDLE)Context, NdisPacket, NDIS_STATUS_CLOSED);
692 }
693 }
694
695 static NTSTATUS
696 OpenRegistryKey( PNDIS_STRING RegistryPath, PHANDLE RegHandle ) {
697 OBJECT_ATTRIBUTES Attributes;
698 NTSTATUS Status;
699
700 InitializeObjectAttributes(&Attributes, RegistryPath, OBJ_CASE_INSENSITIVE, 0, 0);
701 Status = ZwOpenKey(RegHandle, KEY_ALL_ACCESS, &Attributes);
702 return Status;
703 }
704
705 static NTSTATUS ReadStringFromRegistry( HANDLE RegHandle,
706 PWCHAR RegistryValue,
707 PUNICODE_STRING String ) {
708 UNICODE_STRING ValueName;
709 UNICODE_STRING UnicodeString;
710 NTSTATUS Status;
711 ULONG ResultLength;
712 UCHAR buf[1024];
713 PKEY_VALUE_PARTIAL_INFORMATION Information = (PKEY_VALUE_PARTIAL_INFORMATION)buf;
714
715 RtlInitUnicodeString(&ValueName, RegistryValue);
716 Status =
717 ZwQueryValueKey(RegHandle,
718 &ValueName,
719 KeyValuePartialInformation,
720 Information,
721 sizeof(buf),
722 &ResultLength);
723
724 if (!NT_SUCCESS(Status))
725 return Status;
726 /* IP address is stored as a REG_MULTI_SZ - we only pay attention to the first one though */
727 TI_DbgPrint(MIN_TRACE, ("Information DataLength: 0x%x\n", Information->DataLength));
728
729 UnicodeString.Buffer = (PWCHAR)&Information->Data;
730 UnicodeString.Length = Information->DataLength - sizeof(WCHAR);
731 UnicodeString.MaximumLength = Information->DataLength;
732
733 String->Buffer =
734 (PWCHAR)exAllocatePool( NonPagedPool,
735 UnicodeString.MaximumLength + sizeof(WCHAR) );
736
737 if( !String->Buffer ) return STATUS_NO_MEMORY;
738
739 String->MaximumLength = UnicodeString.MaximumLength;
740 RtlCopyUnicodeString( String, &UnicodeString );
741
742 return STATUS_SUCCESS;
743 }
744
745 /*
746 * Utility to copy and append two unicode strings.
747 *
748 * IN OUT PUNICODE_STRING ResultFirst -> First string and result
749 * IN PUNICODE_STRING Second -> Second string to append
750 * IN BOOL Deallocate -> TRUE: Deallocate First string before
751 * overwriting.
752 *
753 * Returns NTSTATUS.
754 */
755
756 NTSTATUS NTAPI AppendUnicodeString(PUNICODE_STRING ResultFirst,
757 PUNICODE_STRING Second,
758 BOOL Deallocate) {
759 NTSTATUS Status;
760 UNICODE_STRING Ustr = *ResultFirst;
761 PWSTR new_string = ExAllocatePoolWithTag
762 (PagedPool,
763 (ResultFirst->Length + Second->Length + sizeof(WCHAR)), TAG_STRING);
764 if( !new_string ) {
765 return STATUS_NO_MEMORY;
766 }
767 memcpy( new_string, ResultFirst->Buffer, ResultFirst->Length );
768 memcpy( new_string + ResultFirst->Length / sizeof(WCHAR),
769 Second->Buffer, Second->Length );
770 if( Deallocate ) RtlFreeUnicodeString(ResultFirst);
771 ResultFirst->Length = Ustr.Length + Second->Length;
772 ResultFirst->MaximumLength = ResultFirst->Length;
773 new_string[ResultFirst->Length / sizeof(WCHAR)] = 0;
774 Status = RtlCreateUnicodeString(ResultFirst,new_string) ?
775 STATUS_SUCCESS : STATUS_NO_MEMORY;
776 ExFreePool(new_string);
777 return Status;
778 }
779
780 static NTSTATUS CheckForDeviceDesc( PUNICODE_STRING EnumKeyName,
781 PUNICODE_STRING TargetKeyName,
782 PUNICODE_STRING Name,
783 PUNICODE_STRING DeviceDesc ) {
784 UNICODE_STRING RootDevice = { 0 }, LinkageKeyName = { 0 };
785 UNICODE_STRING DescKeyName = { 0 }, Linkage = { 0 };
786 UNICODE_STRING BackSlash = { 0 };
787 HANDLE DescKey = NULL, LinkageKey = NULL;
788 NTSTATUS Status;
789
790 TI_DbgPrint(DEBUG_DATALINK,("EnumKeyName %wZ\n", EnumKeyName));
791
792 RtlInitUnicodeString(&BackSlash, L"\\");
793 RtlInitUnicodeString(&Linkage, L"\\Linkage");
794
795 RtlInitUnicodeString(&DescKeyName, L"");
796 AppendUnicodeString( &DescKeyName, EnumKeyName, FALSE );
797 AppendUnicodeString( &DescKeyName, &BackSlash, TRUE );
798 AppendUnicodeString( &DescKeyName, TargetKeyName, TRUE );
799
800 RtlInitUnicodeString(&LinkageKeyName, L"");
801 AppendUnicodeString( &LinkageKeyName, &DescKeyName, FALSE );
802 AppendUnicodeString( &LinkageKeyName, &Linkage, TRUE );
803
804 Status = OpenRegistryKey( &LinkageKeyName, &LinkageKey );
805 if( !NT_SUCCESS(Status) ) goto cleanup;
806
807 Status = ReadStringFromRegistry( LinkageKey, L"RootDevice", &RootDevice );
808 if( !NT_SUCCESS(Status) ) goto cleanup;
809
810 if( RtlCompareUnicodeString( &RootDevice, Name, TRUE ) == 0 ) {
811 Status = OpenRegistryKey( &DescKeyName, &DescKey );
812 if( !NT_SUCCESS(Status) ) goto cleanup;
813
814 Status = ReadStringFromRegistry( DescKey, L"DriverDesc", DeviceDesc );
815 if( !NT_SUCCESS(Status) ) goto cleanup;
816
817 TI_DbgPrint(DEBUG_DATALINK,("ADAPTER DESC: %wZ\n", DeviceDesc));
818 } else Status = STATUS_UNSUCCESSFUL;
819
820 cleanup:
821 RtlFreeUnicodeString( &RootDevice );
822 RtlFreeUnicodeString( &LinkageKeyName );
823 RtlFreeUnicodeString( &DescKeyName );
824 if( LinkageKey ) NtClose( LinkageKey );
825 if( DescKey ) NtClose( DescKey );
826
827 TI_DbgPrint(DEBUG_DATALINK,("Returning %x\n", Status));
828
829 return Status;
830 }
831
832 static NTSTATUS FindDeviceDescForAdapter( PUNICODE_STRING Name,
833 PUNICODE_STRING DeviceDesc ) {
834 UNICODE_STRING EnumKeyName, TargetKeyName;
835 HANDLE EnumKey;
836 NTSTATUS Status;
837 ULONG i;
838 KEY_BASIC_INFORMATION *Kbio =
839 ExAllocatePool(NonPagedPool, sizeof(KEY_BASIC_INFORMATION));
840 ULONG KbioLength = sizeof(KEY_BASIC_INFORMATION), ResultLength;
841
842 if( !Kbio ) return STATUS_INSUFFICIENT_RESOURCES;
843
844 RtlInitUnicodeString
845 (&EnumKeyName, CCS_ROOT L"\\Control\\Class\\" TCPIP_GUID);
846
847 Status = OpenRegistryKey( &EnumKeyName, &EnumKey );
848
849 if( !NT_SUCCESS(Status) ) {
850 TI_DbgPrint(DEBUG_DATALINK,("Couldn't open Enum key %wZ: %x\n",
851 &EnumKeyName, Status));
852 ExFreePool( Kbio );
853 return Status;
854 }
855
856 for( i = 0; NT_SUCCESS(Status); i++ ) {
857 Status = ZwEnumerateKey( EnumKey, i, KeyBasicInformation,
858 Kbio, KbioLength, &ResultLength );
859
860 if( Status == STATUS_BUFFER_TOO_SMALL || Status == STATUS_BUFFER_OVERFLOW ) {
861 ExFreePool( Kbio );
862 KbioLength = ResultLength;
863 Kbio = ExAllocatePool( NonPagedPool, KbioLength );
864
865 Status = ZwEnumerateKey( EnumKey, i, KeyBasicInformation,
866 Kbio, KbioLength, &ResultLength );
867
868 if( !NT_SUCCESS(Status) ) {
869 TI_DbgPrint(DEBUG_DATALINK,("Couldn't enum key child %d\n", i));
870 NtClose( EnumKey );
871 ExFreePool( Kbio );
872 return Status;
873 }
874 }
875
876 if( NT_SUCCESS(Status) ) {
877 TargetKeyName.Length = TargetKeyName.MaximumLength =
878 Kbio->NameLength;
879 TargetKeyName.Buffer = Kbio->Name;
880
881 Status = CheckForDeviceDesc
882 ( &EnumKeyName, &TargetKeyName, Name, DeviceDesc );
883 if( NT_SUCCESS(Status) ) {
884 NtClose( EnumKey );
885 ExFreePool( Kbio );
886 return Status;
887 } else Status = STATUS_SUCCESS;
888 }
889 }
890
891 RtlInitUnicodeString( DeviceDesc, L"" );
892 AppendUnicodeString( DeviceDesc, &TargetKeyName, FALSE );
893 NtClose( EnumKey );
894 ExFreePool( Kbio );
895 return STATUS_UNSUCCESSFUL;
896 }
897
898 VOID GetName( PUNICODE_STRING RegistryKey,
899 PUNICODE_STRING OutName ) {
900 PWCHAR Ptr;
901 UNICODE_STRING PartialRegistryKey;
902
903 PartialRegistryKey.Buffer =
904 RegistryKey->Buffer + wcslen(CCS_ROOT L"\\Services\\");
905 Ptr = PartialRegistryKey.Buffer;
906
907 while( *Ptr != L'\\' &&
908 ((PCHAR)Ptr) < ((PCHAR)RegistryKey->Buffer) + RegistryKey->Length )
909 Ptr++;
910
911 PartialRegistryKey.Length = PartialRegistryKey.MaximumLength =
912 (Ptr - PartialRegistryKey.Buffer) * sizeof(WCHAR);
913
914 RtlInitUnicodeString( OutName, L"" );
915 AppendUnicodeString( OutName, &PartialRegistryKey, FALSE );
916 }
917
918 BOOLEAN BindAdapter(
919 PLAN_ADAPTER Adapter,
920 PNDIS_STRING RegistryPath)
921 /*
922 * FUNCTION: Binds a LAN adapter to IP layer
923 * ARGUMENTS:
924 * Adapter = Pointer to LAN_ADAPTER structure
925 * NOTES:
926 * We set the lookahead buffer size, set the packet filter and
927 * bind the adapter to IP layer
928 */
929 {
930 PIP_INTERFACE IF;
931 NDIS_STATUS NdisStatus;
932 LLIP_BIND_INFO BindInfo;
933 IP_ADDRESS DefaultMask = { 0 };
934 ULONG Lookahead = LOOKAHEAD_SIZE;
935 NTSTATUS Status;
936 HANDLE RegHandle = 0;
937
938 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
939
940 Adapter->State = LAN_STATE_OPENING;
941
942 NdisStatus = NDISCall(Adapter,
943 NdisRequestSetInformation,
944 OID_GEN_CURRENT_LOOKAHEAD,
945 &Lookahead,
946 sizeof(ULONG));
947 if (NdisStatus != NDIS_STATUS_SUCCESS) {
948 TI_DbgPrint(DEBUG_DATALINK, ("Could not set lookahead buffer size (0x%X).\n", NdisStatus));
949 return FALSE;
950 }
951
952 /* Bind the adapter to IP layer */
953 BindInfo.Context = Adapter;
954 BindInfo.HeaderSize = Adapter->HeaderSize;
955 BindInfo.MinFrameSize = Adapter->MinFrameSize;
956 BindInfo.MTU = Adapter->MTU;
957 BindInfo.Address = (PUCHAR)&Adapter->HWAddress;
958 BindInfo.AddressLength = Adapter->HWAddressLength;
959 BindInfo.Transmit = LANTransmit;
960
961 IF = IPCreateInterface(&BindInfo);
962
963 if (!IF) {
964 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
965 return FALSE;
966 }
967
968 /*
969 * Query per-adapter configuration from the registry
970 * In case anyone is curious: there *is* an Ndis configuration api
971 * for this sort of thing, but it doesn't really support things like
972 * REG_MULTI_SZ very well, and there is a note in the DDK that says that
973 * protocol drivers developed for win2k and above just use the native
974 * services (ZwOpenKey, etc).
975 */
976
977 GetName( RegistryPath, &IF->Name );
978
979 Status = OpenRegistryKey( RegistryPath, &RegHandle );
980
981 if(NT_SUCCESS(Status)) {
982 Status = FindDeviceDescForAdapter( &IF->Name, &IF->Description );
983 TI_DbgPrint(DEBUG_DATALINK,("Adapter Description: %wZ\n",
984 &IF->Description));
985 } else {
986 IPDestroyInterface( IF );
987 return FALSE;
988 }
989
990 DefaultMask.Type = IP_ADDRESS_V4;
991
992 IF->Unicast = DefaultMask;
993 IF->Netmask = DefaultMask;
994
995 IF->Broadcast.Type = IP_ADDRESS_V4;
996 IF->Broadcast.Address.IPv4Address =
997 IF->Unicast.Address.IPv4Address |
998 ~IF->Netmask.Address.IPv4Address;
999
1000 TI_DbgPrint(DEBUG_DATALINK,("BCAST(IF) %s\n", A2S(&IF->Broadcast)));
1001
1002 /* Get maximum link speed */
1003 NdisStatus = NDISCall(Adapter,
1004 NdisRequestQueryInformation,
1005 OID_GEN_LINK_SPEED,
1006 &IF->Speed,
1007 sizeof(UINT));
1008
1009 if( !NT_SUCCESS(NdisStatus) )
1010 IF->Speed = IP_DEFAULT_LINK_SPEED;
1011
1012 /* Register interface with IP layer */
1013 IPRegisterInterface(IF);
1014
1015 /* Set packet filter so we can send and receive packets */
1016 NdisStatus = NDISCall(Adapter,
1017 NdisRequestSetInformation,
1018 OID_GEN_CURRENT_PACKET_FILTER,
1019 &Adapter->PacketFilter,
1020 sizeof(UINT));
1021
1022 if (NdisStatus != NDIS_STATUS_SUCCESS) {
1023 TI_DbgPrint(DEBUG_DATALINK, ("Could not set packet filter (0x%X).\n", NdisStatus));
1024 IPDestroyInterface(IF);
1025 return FALSE;
1026 }
1027
1028 Adapter->Context = IF;
1029 Adapter->State = LAN_STATE_STARTED;
1030 return TRUE;
1031 }
1032
1033
1034 VOID UnbindAdapter(
1035 PLAN_ADAPTER Adapter)
1036 /*
1037 * FUNCTION: Unbinds a LAN adapter from IP layer
1038 * ARGUMENTS:
1039 * Adapter = Pointer to LAN_ADAPTER structure
1040 */
1041 {
1042 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
1043
1044 if (Adapter->State == LAN_STATE_STARTED) {
1045 PIP_INTERFACE IF = Adapter->Context;
1046
1047 IPUnregisterInterface(IF);
1048
1049 IPDestroyInterface(IF);
1050 }
1051 }
1052
1053
1054 NDIS_STATUS LANRegisterAdapter(
1055 PNDIS_STRING AdapterName,
1056 PNDIS_STRING RegistryPath)
1057 /*
1058 * FUNCTION: Registers protocol with an NDIS adapter
1059 * ARGUMENTS:
1060 * AdapterName = Pointer to string with name of adapter to register
1061 * Adapter = Address of pointer to a LAN_ADAPTER structure
1062 * RETURNS:
1063 * Status of operation
1064 */
1065 {
1066 PLAN_ADAPTER IF;
1067 NDIS_STATUS NdisStatus;
1068 NDIS_STATUS OpenStatus;
1069 UINT MediaIndex;
1070 NDIS_MEDIUM MediaArray[MAX_MEDIA];
1071 UINT AddressOID;
1072 UINT Speed;
1073
1074 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
1075
1076 IF = exAllocatePool(NonPagedPool, sizeof(LAN_ADAPTER));
1077 if (!IF) {
1078 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
1079 return NDIS_STATUS_RESOURCES;
1080 }
1081
1082 RtlZeroMemory(IF, sizeof(LAN_ADAPTER));
1083
1084 /* Put adapter in stopped state */
1085 IF->State = LAN_STATE_STOPPED;
1086
1087 /* Initialize protecting spin lock */
1088 KeInitializeSpinLock(&IF->Lock);
1089
1090 KeInitializeEvent(&IF->Event, SynchronizationEvent, FALSE);
1091
1092 /* Initialize array with media IDs we support */
1093 MediaArray[MEDIA_ETH] = NdisMedium802_3;
1094
1095 TI_DbgPrint(DEBUG_DATALINK,("opening adapter %wZ\n", AdapterName));
1096 /* Open the adapter. */
1097 NdisOpenAdapter(&NdisStatus,
1098 &OpenStatus,
1099 &IF->NdisHandle,
1100 &MediaIndex,
1101 MediaArray,
1102 MAX_MEDIA,
1103 NdisProtocolHandle,
1104 IF,
1105 AdapterName,
1106 0,
1107 NULL);
1108
1109 /* Wait until the adapter is opened */
1110 if (NdisStatus == NDIS_STATUS_PENDING)
1111 KeWaitForSingleObject(&IF->Event, UserRequest, KernelMode, FALSE, NULL);
1112 else if (NdisStatus != NDIS_STATUS_SUCCESS) {
1113 TI_DbgPrint(DEBUG_DATALINK,("denying adapter %wZ\n", AdapterName));
1114 exFreePool(IF);
1115 return NdisStatus;
1116 }
1117
1118 IF->Media = MediaArray[MediaIndex];
1119
1120 /* Fill LAN_ADAPTER structure with some adapter specific information */
1121 switch (IF->Media) {
1122 case NdisMedium802_3:
1123 IF->HWAddressLength = IEEE_802_ADDR_LENGTH;
1124 IF->BCastMask = BCAST_ETH_MASK;
1125 IF->BCastCheck = BCAST_ETH_CHECK;
1126 IF->BCastOffset = BCAST_ETH_OFFSET;
1127 IF->HeaderSize = sizeof(ETH_HEADER);
1128 IF->MinFrameSize = 60;
1129 AddressOID = OID_802_3_CURRENT_ADDRESS;
1130 IF->PacketFilter =
1131 NDIS_PACKET_TYPE_BROADCAST |
1132 NDIS_PACKET_TYPE_DIRECTED |
1133 NDIS_PACKET_TYPE_MULTICAST;
1134 break;
1135
1136 default:
1137 /* Unsupported media */
1138 TI_DbgPrint(MIN_TRACE, ("Unsupported media.\n"));
1139 exFreePool(IF);
1140 return NDIS_STATUS_NOT_SUPPORTED;
1141 }
1142
1143 /* Get maximum frame size */
1144 NdisStatus = NDISCall(IF,
1145 NdisRequestQueryInformation,
1146 OID_GEN_MAXIMUM_FRAME_SIZE,
1147 &IF->MTU,
1148 sizeof(UINT));
1149 if (NdisStatus != NDIS_STATUS_SUCCESS) {
1150 TI_DbgPrint(DEBUG_DATALINK,("denying adapter %wZ (NDISCall)\n", AdapterName));
1151 exFreePool(IF);
1152 return NdisStatus;
1153 }
1154
1155 /* Get maximum packet size */
1156 NdisStatus = NDISCall(IF,
1157 NdisRequestQueryInformation,
1158 OID_GEN_MAXIMUM_TOTAL_SIZE,
1159 &IF->MaxPacketSize,
1160 sizeof(UINT));
1161 if (NdisStatus != NDIS_STATUS_SUCCESS) {
1162 TI_DbgPrint(MIN_TRACE, ("Query for maximum packet size failed.\n"));
1163 exFreePool(IF);
1164 return NdisStatus;
1165 }
1166
1167 /* Get maximum number of packets we can pass to NdisSend(Packets) at one time */
1168 NdisStatus = NDISCall(IF,
1169 NdisRequestQueryInformation,
1170 OID_GEN_MAXIMUM_SEND_PACKETS,
1171 &IF->MaxSendPackets,
1172 sizeof(UINT));
1173 if (NdisStatus != NDIS_STATUS_SUCCESS)
1174 /* Legacy NIC drivers may not support this query, if it fails we
1175 assume it can send at least one packet per call to NdisSend(Packets) */
1176 IF->MaxSendPackets = 1;
1177
1178 /* Get current hardware address */
1179 NdisStatus = NDISCall(IF,
1180 NdisRequestQueryInformation,
1181 AddressOID,
1182 &IF->HWAddress,
1183 IF->HWAddressLength);
1184 if (NdisStatus != NDIS_STATUS_SUCCESS) {
1185 TI_DbgPrint(MIN_TRACE, ("Query for current hardware address failed.\n"));
1186 exFreePool(IF);
1187 return NdisStatus;
1188 }
1189
1190 /* Get maximum link speed */
1191 NdisStatus = NDISCall(IF,
1192 NdisRequestQueryInformation,
1193 OID_GEN_LINK_SPEED,
1194 &Speed,
1195 sizeof(UINT));
1196 if (NdisStatus != NDIS_STATUS_SUCCESS) {
1197 TI_DbgPrint(MIN_TRACE, ("Query for maximum link speed failed.\n"));
1198 exFreePool(IF);
1199 return NdisStatus;
1200 }
1201
1202 /* Convert returned link speed to bps (it is in 100bps increments) */
1203 IF->Speed = Speed * 100L;
1204
1205 /* Add adapter to the adapter list */
1206 ExInterlockedInsertTailList(&AdapterListHead,
1207 &IF->ListEntry,
1208 &AdapterListLock);
1209
1210 /* Bind adapter to IP layer */
1211 if( !BindAdapter(IF, RegistryPath) ) {
1212 TI_DbgPrint(DEBUG_DATALINK,("denying adapter %wZ (BindAdapter)\n", AdapterName));
1213 exFreePool(IF);
1214 return NDIS_STATUS_NOT_ACCEPTED;
1215 }
1216
1217 TI_DbgPrint(DEBUG_DATALINK, ("Leaving.\n"));
1218
1219 return NDIS_STATUS_SUCCESS;
1220 }
1221
1222
1223 NDIS_STATUS LANUnregisterAdapter(
1224 PLAN_ADAPTER Adapter)
1225 /*
1226 * FUNCTION: Unregisters protocol with NDIS adapter
1227 * ARGUMENTS:
1228 * Adapter = Pointer to a LAN_ADAPTER structure
1229 * RETURNS:
1230 * Status of operation
1231 */
1232 {
1233 KIRQL OldIrql;
1234 NDIS_HANDLE NdisHandle;
1235 NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS;
1236
1237 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
1238
1239 /* Unlink the adapter from the list */
1240 RemoveEntryList(&Adapter->ListEntry);
1241
1242 /* Unbind adapter from IP layer */
1243 UnbindAdapter(Adapter);
1244
1245 TcpipAcquireSpinLock(&Adapter->Lock, &OldIrql);
1246 NdisHandle = Adapter->NdisHandle;
1247 if (NdisHandle) {
1248 Adapter->NdisHandle = NULL;
1249 TcpipReleaseSpinLock(&Adapter->Lock, OldIrql);
1250
1251 NdisCloseAdapter(&NdisStatus, NdisHandle);
1252 if (NdisStatus == NDIS_STATUS_PENDING) {
1253 TcpipWaitForSingleObject(&Adapter->Event,
1254 UserRequest,
1255 KernelMode,
1256 FALSE,
1257 NULL);
1258 NdisStatus = Adapter->NdisStatus;
1259 }
1260 } else
1261 TcpipReleaseSpinLock(&Adapter->Lock, OldIrql);
1262
1263 FreeAdapter(Adapter);
1264
1265 return NDIS_STATUS_SUCCESS;
1266 }
1267
1268
1269 NTSTATUS LANRegisterProtocol(
1270 PNDIS_STRING Name)
1271 /*
1272 * FUNCTION: Registers this protocol driver with NDIS
1273 * ARGUMENTS:
1274 * Name = Name of this protocol driver
1275 * RETURNS:
1276 * Status of operation
1277 */
1278 {
1279 NDIS_STATUS NdisStatus;
1280 NDIS_PROTOCOL_CHARACTERISTICS ProtChars;
1281
1282 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
1283
1284 InitializeListHead(&AdapterListHead);
1285 KeInitializeSpinLock(&AdapterListLock);
1286
1287 /* Set up protocol characteristics */
1288 RtlZeroMemory(&ProtChars, sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
1289 ProtChars.MajorNdisVersion = NDIS_VERSION_MAJOR;
1290 ProtChars.MinorNdisVersion = NDIS_VERSION_MINOR;
1291 ProtChars.Name.Length = Name->Length;
1292 ProtChars.Name.Buffer = Name->Buffer;
1293 ProtChars.Name.MaximumLength = Name->MaximumLength;
1294 ProtChars.OpenAdapterCompleteHandler = ProtocolOpenAdapterComplete;
1295 ProtChars.CloseAdapterCompleteHandler = ProtocolCloseAdapterComplete;
1296 ProtChars.ResetCompleteHandler = ProtocolResetComplete;
1297 ProtChars.RequestCompleteHandler = ProtocolRequestComplete;
1298 ProtChars.SendCompleteHandler = ProtocolSendComplete;
1299 ProtChars.TransferDataCompleteHandler = ProtocolTransferDataComplete;
1300 ProtChars.ReceiveHandler = ProtocolReceive;
1301 ProtChars.ReceiveCompleteHandler = ProtocolReceiveComplete;
1302 ProtChars.StatusHandler = ProtocolStatus;
1303 ProtChars.StatusCompleteHandler = ProtocolStatusComplete;
1304 ProtChars.BindAdapterHandler = ProtocolBindAdapter;
1305
1306 /* Try to register protocol */
1307 NdisRegisterProtocol(&NdisStatus,
1308 &NdisProtocolHandle,
1309 &ProtChars,
1310 sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
1311 if (NdisStatus != NDIS_STATUS_SUCCESS)
1312 {
1313 TI_DbgPrint(DEBUG_DATALINK, ("NdisRegisterProtocol failed, status 0x%x\n", NdisStatus));
1314 return (NTSTATUS)NdisStatus;
1315 }
1316
1317 ProtocolRegistered = TRUE;
1318
1319 return STATUS_SUCCESS;
1320 }
1321
1322
1323 VOID LANUnregisterProtocol(
1324 VOID)
1325 /*
1326 * FUNCTION: Unregisters this protocol driver with NDIS
1327 * NOTES: Does not care wether we are already registered
1328 */
1329 {
1330 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
1331
1332 if (ProtocolRegistered) {
1333 NDIS_STATUS NdisStatus;
1334 PLIST_ENTRY CurrentEntry;
1335 PLIST_ENTRY NextEntry;
1336 PLAN_ADAPTER Current;
1337 KIRQL OldIrql;
1338
1339 TcpipAcquireSpinLock(&AdapterListLock, &OldIrql);
1340
1341 /* Search the list and remove every adapter we find */
1342 CurrentEntry = AdapterListHead.Flink;
1343 while (CurrentEntry != &AdapterListHead) {
1344 NextEntry = CurrentEntry->Flink;
1345 Current = CONTAINING_RECORD(CurrentEntry, LAN_ADAPTER, ListEntry);
1346 /* Unregister it */
1347 LANUnregisterAdapter(Current);
1348 CurrentEntry = NextEntry;
1349 }
1350
1351 TcpipReleaseSpinLock(&AdapterListLock, OldIrql);
1352
1353 NdisDeregisterProtocol(&NdisStatus, NdisProtocolHandle);
1354 ProtocolRegistered = FALSE;
1355 }
1356 }
1357
1358 VOID LANStartup() {
1359 InitializeListHead( &LanSendCompleteList );
1360 KeInitializeSpinLock( &LanSendCompleteLock );
1361 }
1362
1363 VOID LANShutdown() {
1364 KIRQL OldIrql;
1365 PLAN_WQ_ITEM WorkItem;
1366 PLIST_ENTRY ListEntry;
1367
1368 KeAcquireSpinLock( &LanSendCompleteLock, &OldIrql );
1369 while( !IsListEmpty( &LanSendCompleteList ) ) {
1370 ListEntry = RemoveHeadList( &LanSendCompleteList );
1371 WorkItem = CONTAINING_RECORD(ListEntry, LAN_WQ_ITEM, ListEntry);
1372 FreeNdisPacket( WorkItem->Packet );
1373 ExFreePool( WorkItem );
1374 }
1375 KeReleaseSpinLock( &LanSendCompleteLock, OldIrql );
1376 }
1377
1378 /* EOF */