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