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