* Sync up to trunk head (r64716).
[reactos.git] / 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 #include <ntifs.h>
14 #include <receive.h>
15 #include <wait.h>
16
17 UINT TransferDataCalled = 0;
18 UINT TransferDataCompleteCalled = 0;
19
20 #define CCS_ROOT L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet"
21 #define TCPIP_GUID L"{4D36E972-E325-11CE-BFC1-08002BE10318}"
22
23 typedef struct _LAN_WQ_ITEM {
24 LIST_ENTRY ListEntry;
25 PNDIS_PACKET Packet;
26 PLAN_ADAPTER Adapter;
27 UINT BytesTransferred;
28 BOOLEAN LegacyReceive;
29 } LAN_WQ_ITEM, *PLAN_WQ_ITEM;
30
31 typedef struct _RECONFIGURE_CONTEXT {
32 ULONG State;
33 PLAN_ADAPTER Adapter;
34 } RECONFIGURE_CONTEXT, *PRECONFIGURE_CONTEXT;
35
36 NDIS_HANDLE NdisProtocolHandle = (NDIS_HANDLE)NULL;
37 BOOLEAN ProtocolRegistered = FALSE;
38 LIST_ENTRY AdapterListHead;
39 KSPIN_LOCK AdapterListLock;
40
41 NDIS_STATUS NDISCall(
42 PLAN_ADAPTER Adapter,
43 NDIS_REQUEST_TYPE Type,
44 NDIS_OID OID,
45 PVOID Buffer,
46 UINT Length)
47 /*
48 * FUNCTION: Send a request to NDIS
49 * ARGUMENTS:
50 * Adapter = Pointer to a LAN_ADAPTER structure
51 * Type = Type of request (Set or Query)
52 * OID = Value to be set/queried for
53 * Buffer = Pointer to a buffer to use
54 * Length = Number of bytes in Buffer
55 * RETURNS:
56 * Status of operation
57 */
58 {
59 NDIS_REQUEST Request;
60 NDIS_STATUS NdisStatus;
61
62 Request.RequestType = Type;
63 if (Type == NdisRequestSetInformation) {
64 Request.DATA.SET_INFORMATION.Oid = OID;
65 Request.DATA.SET_INFORMATION.InformationBuffer = Buffer;
66 Request.DATA.SET_INFORMATION.InformationBufferLength = Length;
67 } else {
68 Request.DATA.QUERY_INFORMATION.Oid = OID;
69 Request.DATA.QUERY_INFORMATION.InformationBuffer = Buffer;
70 Request.DATA.QUERY_INFORMATION.InformationBufferLength = Length;
71 }
72
73 if (Adapter->State != LAN_STATE_RESETTING) {
74 NdisRequest(&NdisStatus, Adapter->NdisHandle, &Request);
75 } else {
76 NdisStatus = NDIS_STATUS_NOT_ACCEPTED;
77 }
78
79 /* Wait for NDIS to complete the request */
80 if (NdisStatus == NDIS_STATUS_PENDING) {
81 KeWaitForSingleObject(&Adapter->Event,
82 UserRequest,
83 KernelMode,
84 FALSE,
85 NULL);
86 NdisStatus = Adapter->NdisStatus;
87 }
88
89 return NdisStatus;
90 }
91
92 /* Used by legacy ProtocolReceive for packet type */
93 NDIS_STATUS
94 GetPacketTypeFromHeaderBuffer(PLAN_ADAPTER Adapter,
95 PVOID HeaderBuffer,
96 ULONG HeaderBufferSize,
97 PULONG PacketType)
98 {
99 PETH_HEADER EthHeader = HeaderBuffer;
100
101 if (HeaderBufferSize < Adapter->HeaderSize)
102 {
103 TI_DbgPrint(DEBUG_DATALINK, ("Runt frame (size %d).\n", HeaderBufferSize));
104 return NDIS_STATUS_NOT_ACCEPTED;
105 }
106
107 switch (Adapter->Media)
108 {
109 case NdisMedium802_3:
110 /* Ethernet and IEEE 802.3 frames can be destinguished by
111 looking at the IEEE 802.3 length field. This field is
112 less than or equal to 1500 for a valid IEEE 802.3 frame
113 and larger than 1500 is it's a valid EtherType value.
114 See RFC 1122, section 2.3.3 for more information */
115
116 *PacketType = EthHeader->EType;
117 break;
118
119 default:
120 TI_DbgPrint(MIN_TRACE, ("Unsupported media.\n"));
121
122 /* FIXME: Support other medias */
123 return NDIS_STATUS_NOT_ACCEPTED;
124 }
125
126 TI_DbgPrint(DEBUG_DATALINK, ("EtherType (0x%X).\n", *PacketType));
127
128 return NDIS_STATUS_SUCCESS;
129 }
130
131 /* Used by ProtocolReceivePacket for packet type */
132 NDIS_STATUS
133 GetPacketTypeFromNdisPacket(PLAN_ADAPTER Adapter,
134 PNDIS_PACKET NdisPacket,
135 PULONG PacketType)
136 {
137 PVOID HeaderBuffer;
138 ULONG BytesCopied;
139 NDIS_STATUS Status;
140
141 HeaderBuffer = ExAllocatePool(NonPagedPool,
142 Adapter->HeaderSize);
143 if (!HeaderBuffer)
144 return NDIS_STATUS_RESOURCES;
145
146 /* Copy the media header */
147 BytesCopied = CopyPacketToBuffer(HeaderBuffer,
148 NdisPacket,
149 0,
150 Adapter->HeaderSize);
151 if (BytesCopied != Adapter->HeaderSize)
152 {
153 /* Runt frame */
154 ExFreePool(HeaderBuffer);
155 TI_DbgPrint(DEBUG_DATALINK, ("Runt frame (size %d).\n", BytesCopied));
156 return NDIS_STATUS_NOT_ACCEPTED;
157 }
158
159 Status = GetPacketTypeFromHeaderBuffer(Adapter,
160 HeaderBuffer,
161 BytesCopied,
162 PacketType);
163
164 ExFreePool(HeaderBuffer);
165
166 return Status;
167 }
168
169
170 VOID FreeAdapter(
171 PLAN_ADAPTER Adapter)
172 /*
173 * FUNCTION: Frees memory for a LAN_ADAPTER structure
174 * ARGUMENTS:
175 * Adapter = Pointer to LAN_ADAPTER structure to free
176 */
177 {
178 ExFreePoolWithTag(Adapter, LAN_ADAPTER_TAG);
179 }
180
181
182 NTSTATUS TcpipLanGetDwordOid
183 ( PIP_INTERFACE Interface,
184 NDIS_OID Oid,
185 PULONG Result ) {
186 /* Get maximum frame size */
187 if( Interface->Context ) {
188 return NDISCall((PLAN_ADAPTER)Interface->Context,
189 NdisRequestQueryInformation,
190 Oid,
191 Result,
192 sizeof(ULONG));
193 } else switch( Oid ) { /* Loopback Case */
194 case OID_GEN_HARDWARE_STATUS:
195 *Result = NdisHardwareStatusReady;
196 return STATUS_SUCCESS;
197 case OID_GEN_MEDIA_CONNECT_STATUS:
198 *Result = NdisMediaStateConnected;
199 return STATUS_SUCCESS;
200 default:
201 return STATUS_INVALID_PARAMETER;
202 }
203 }
204
205
206 VOID NTAPI ProtocolOpenAdapterComplete(
207 NDIS_HANDLE BindingContext,
208 NDIS_STATUS Status,
209 NDIS_STATUS OpenErrorStatus)
210 /*
211 * FUNCTION: Called by NDIS to complete opening of an adapter
212 * ARGUMENTS:
213 * BindingContext = Pointer to a device context (LAN_ADAPTER)
214 * Status = Status of the operation
215 * OpenErrorStatus = Additional status information
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 NTAPI ProtocolCloseAdapterComplete(
229 NDIS_HANDLE BindingContext,
230 NDIS_STATUS Status)
231 /*
232 * FUNCTION: Called by NDIS to complete closing an adapter
233 * ARGUMENTS:
234 * BindingContext = Pointer to a device context (LAN_ADAPTER)
235 * Status = Status of the operation
236 */
237 {
238 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
239
240 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
241
242 Adapter->NdisStatus = Status;
243
244 KeSetEvent(&Adapter->Event, 0, FALSE);
245 }
246
247
248 VOID NTAPI ProtocolResetComplete(
249 NDIS_HANDLE BindingContext,
250 NDIS_STATUS Status)
251 /*
252 * FUNCTION: Called by NDIS to complete resetting an adapter
253 * ARGUMENTS:
254 * BindingContext = Pointer to a device context (LAN_ADAPTER)
255 * Status = Status of the operation
256 */
257 {
258 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
259
260 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
261
262 Adapter->NdisStatus = Status;
263
264 KeSetEvent(&Adapter->Event, 0, FALSE);
265 }
266
267
268 VOID NTAPI ProtocolRequestComplete(
269 NDIS_HANDLE BindingContext,
270 PNDIS_REQUEST NdisRequest,
271 NDIS_STATUS Status)
272 /*
273 * FUNCTION: Called by NDIS to complete a request
274 * ARGUMENTS:
275 * BindingContext = Pointer to a device context (LAN_ADAPTER)
276 * NdisRequest = Pointer to an object describing the request
277 * Status = Status of the operation
278 */
279 {
280 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
281
282 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
283
284 /* Save status of request and signal an event */
285 Adapter->NdisStatus = Status;
286
287 KeSetEvent(&Adapter->Event, 0, FALSE);
288 }
289
290
291 VOID NTAPI ProtocolSendComplete(
292 NDIS_HANDLE BindingContext,
293 PNDIS_PACKET Packet,
294 NDIS_STATUS Status)
295 /*
296 * FUNCTION: Called by NDIS to complete sending process
297 * ARGUMENTS:
298 * BindingContext = Pointer to a device context (LAN_ADAPTER)
299 * Packet = Pointer to a packet descriptor
300 * Status = Status of the operation
301 */
302 {
303 FreeNdisPacket(Packet);
304 }
305
306 VOID LanReceiveWorker( PVOID Context ) {
307 ULONG PacketType;
308 PLAN_WQ_ITEM WorkItem = (PLAN_WQ_ITEM)Context;
309 PNDIS_PACKET Packet;
310 PLAN_ADAPTER Adapter;
311 UINT BytesTransferred;
312 IP_PACKET IPPacket;
313 BOOLEAN LegacyReceive;
314 PIP_INTERFACE Interface;
315
316 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
317
318 Packet = WorkItem->Packet;
319 Adapter = WorkItem->Adapter;
320 BytesTransferred = WorkItem->BytesTransferred;
321 LegacyReceive = WorkItem->LegacyReceive;
322
323 ExFreePoolWithTag(WorkItem, WQ_CONTEXT_TAG);
324
325 Interface = Adapter->Context;
326
327 IPInitializePacket(&IPPacket, 0);
328
329 IPPacket.NdisPacket = Packet;
330 IPPacket.ReturnPacket = !LegacyReceive;
331
332 if (LegacyReceive)
333 {
334 /* Packet type is precomputed */
335 PacketType = PC(IPPacket.NdisPacket)->PacketType;
336
337 /* Data is at position 0 */
338 IPPacket.Position = 0;
339
340 /* Packet size is determined by bytes transferred */
341 IPPacket.TotalSize = BytesTransferred;
342 }
343 else
344 {
345 /* Determine packet type from media header */
346 if (GetPacketTypeFromNdisPacket(Adapter,
347 IPPacket.NdisPacket,
348 &PacketType) != NDIS_STATUS_SUCCESS)
349 {
350 /* Bad packet */
351 IPPacket.Free(&IPPacket);
352 return;
353 }
354
355 /* Data is at the end of the media header */
356 IPPacket.Position = Adapter->HeaderSize;
357
358 /* Calculate packet size (excluding media header) */
359 NdisQueryPacketLength(IPPacket.NdisPacket, &IPPacket.TotalSize);
360 }
361
362 TI_DbgPrint
363 (DEBUG_DATALINK,
364 ("Ether Type = %x Total = %d\n",
365 PacketType, IPPacket.TotalSize));
366
367 /* Update interface stats */
368 Interface->Stats.InBytes += IPPacket.TotalSize + Adapter->HeaderSize;
369
370 /* NDIS packet is freed in all of these cases */
371 switch (PacketType) {
372 case ETYPE_IPv4:
373 case ETYPE_IPv6:
374 TI_DbgPrint(MID_TRACE,("Received IP Packet\n"));
375 IPReceive(Adapter->Context, &IPPacket);
376 break;
377 case ETYPE_ARP:
378 TI_DbgPrint(MID_TRACE,("Received ARP Packet\n"));
379 ARPReceive(Adapter->Context, &IPPacket);
380 break;
381 default:
382 IPPacket.Free(&IPPacket);
383 break;
384 }
385 }
386
387 VOID LanSubmitReceiveWork(
388 NDIS_HANDLE BindingContext,
389 PNDIS_PACKET Packet,
390 UINT BytesTransferred,
391 BOOLEAN LegacyReceive) {
392 PLAN_WQ_ITEM WQItem = ExAllocatePoolWithTag(NonPagedPool, sizeof(LAN_WQ_ITEM),
393 WQ_CONTEXT_TAG);
394 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
395
396 TI_DbgPrint(DEBUG_DATALINK,("called\n"));
397
398 if (!WQItem) return;
399
400 WQItem->Packet = Packet;
401 WQItem->Adapter = Adapter;
402 WQItem->BytesTransferred = BytesTransferred;
403 WQItem->LegacyReceive = LegacyReceive;
404
405 if (!ChewCreate( LanReceiveWorker, WQItem ))
406 ExFreePoolWithTag(WQItem, WQ_CONTEXT_TAG);
407 }
408
409 VOID NTAPI ProtocolTransferDataComplete(
410 NDIS_HANDLE BindingContext,
411 PNDIS_PACKET Packet,
412 NDIS_STATUS Status,
413 UINT BytesTransferred)
414 /*
415 * FUNCTION: Called by NDIS to complete reception of data
416 * ARGUMENTS:
417 * BindingContext = Pointer to a device context (LAN_ADAPTER)
418 * Packet = Pointer to a packet descriptor
419 * Status = Status of the operation
420 * BytesTransferred = Number of bytes transferred
421 * NOTES:
422 * If the packet was successfully received, determine the protocol
423 * type and pass it to the correct receive handler
424 */
425 {
426 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
427
428 TI_DbgPrint(DEBUG_DATALINK,("called\n"));
429
430 TransferDataCompleteCalled++;
431 ASSERT(TransferDataCompleteCalled <= TransferDataCalled);
432
433 if( Status != NDIS_STATUS_SUCCESS ) return;
434
435 LanSubmitReceiveWork(BindingContext,
436 Packet,
437 BytesTransferred,
438 TRUE);
439 }
440
441 INT NTAPI ProtocolReceivePacket(
442 NDIS_HANDLE BindingContext,
443 PNDIS_PACKET NdisPacket)
444 {
445 PLAN_ADAPTER Adapter = BindingContext;
446
447 if (Adapter->State != LAN_STATE_STARTED) {
448 TI_DbgPrint(DEBUG_DATALINK, ("Adapter is stopped.\n"));
449 return 0;
450 }
451
452 LanSubmitReceiveWork(BindingContext,
453 NdisPacket,
454 0, /* Unused */
455 FALSE);
456
457 /* Hold 1 reference on this packet */
458 return 1;
459 }
460
461 NDIS_STATUS NTAPI ProtocolReceive(
462 NDIS_HANDLE BindingContext,
463 NDIS_HANDLE MacReceiveContext,
464 PVOID HeaderBuffer,
465 UINT HeaderBufferSize,
466 PVOID LookaheadBuffer,
467 UINT LookaheadBufferSize,
468 UINT PacketSize)
469 /*
470 * FUNCTION: Called by NDIS when a packet has been received on the physical link
471 * ARGUMENTS:
472 * BindingContext = Pointer to a device context (LAN_ADAPTER)
473 * MacReceiveContext = Handle used by underlying NIC driver
474 * HeaderBuffer = Pointer to a buffer containing the packet header
475 * HeaderBufferSize = Number of bytes in HeaderBuffer
476 * LookaheadBuffer = Pointer to a buffer containing buffered packet data
477 * LookaheadBufferSize = Size of LookaheadBuffer. May be less than asked for
478 * PacketSize = Overall size of the packet (not including header)
479 * RETURNS:
480 * Status of operation
481 */
482 {
483 ULONG PacketType;
484 UINT BytesTransferred;
485 PCHAR BufferData;
486 NDIS_STATUS NdisStatus;
487 PNDIS_PACKET NdisPacket;
488 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
489
490 TI_DbgPrint(DEBUG_DATALINK, ("Called. (packetsize %d)\n",PacketSize));
491
492 if (Adapter->State != LAN_STATE_STARTED) {
493 TI_DbgPrint(DEBUG_DATALINK, ("Adapter is stopped.\n"));
494 return NDIS_STATUS_NOT_ACCEPTED;
495 }
496
497 if (HeaderBufferSize < Adapter->HeaderSize) {
498 TI_DbgPrint(DEBUG_DATALINK, ("Runt frame received.\n"));
499 return NDIS_STATUS_NOT_ACCEPTED;
500 }
501
502 NdisStatus = GetPacketTypeFromHeaderBuffer(Adapter,
503 HeaderBuffer,
504 HeaderBufferSize,
505 &PacketType);
506 if (NdisStatus != NDIS_STATUS_SUCCESS)
507 return NDIS_STATUS_NOT_ACCEPTED;
508
509 TI_DbgPrint(DEBUG_DATALINK, ("Adapter: %x (MTU %d)\n",
510 Adapter, Adapter->MTU));
511
512 /* Get a transfer data packet */
513 NdisStatus = AllocatePacketWithBuffer( &NdisPacket, NULL,
514 PacketSize );
515 if( NdisStatus != NDIS_STATUS_SUCCESS ) {
516 return NDIS_STATUS_NOT_ACCEPTED;
517 }
518
519 PC(NdisPacket)->PacketType = PacketType;
520
521 TI_DbgPrint(DEBUG_DATALINK, ("pretransfer LookaheadBufferSize %d packsize %d\n",LookaheadBufferSize,PacketSize));
522
523 GetDataPtr( NdisPacket, 0, &BufferData, &PacketSize );
524
525 TransferDataCalled++;
526
527 if (LookaheadBufferSize == PacketSize)
528 {
529 /* Optimized code path for packets that are fully contained in
530 * the lookahead buffer. */
531 NdisCopyLookaheadData(BufferData,
532 LookaheadBuffer,
533 LookaheadBufferSize,
534 Adapter->MacOptions);
535 }
536 else
537 {
538 NdisTransferData(&NdisStatus, Adapter->NdisHandle,
539 MacReceiveContext, 0, PacketSize,
540 NdisPacket, &BytesTransferred);
541 }
542 TI_DbgPrint(DEBUG_DATALINK, ("Calling complete\n"));
543
544 if (NdisStatus != NDIS_STATUS_PENDING)
545 ProtocolTransferDataComplete(BindingContext,
546 NdisPacket,
547 NdisStatus,
548 PacketSize);
549
550 TI_DbgPrint(DEBUG_DATALINK, ("leaving\n"));
551
552 return NDIS_STATUS_SUCCESS;
553 }
554
555
556 VOID NTAPI ProtocolReceiveComplete(
557 NDIS_HANDLE BindingContext)
558 /*
559 * FUNCTION: Called by NDIS when we're done receiving data
560 * ARGUMENTS:
561 * BindingContext = Pointer to a device context (LAN_ADAPTER)
562 */
563 {
564 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
565 }
566
567 BOOLEAN ReadIpConfiguration(PIP_INTERFACE Interface)
568 {
569 OBJECT_ATTRIBUTES ObjectAttributes;
570 HANDLE ParameterHandle;
571 PKEY_VALUE_PARTIAL_INFORMATION KeyValueInfo;
572 WCHAR Buffer[150];
573 UNICODE_STRING IPAddress = RTL_CONSTANT_STRING(L"IPAddress");
574 UNICODE_STRING Netmask = RTL_CONSTANT_STRING(L"SubnetMask");
575 UNICODE_STRING Gateway = RTL_CONSTANT_STRING(L"DefaultGateway");
576 UNICODE_STRING EnableDhcp = RTL_CONSTANT_STRING(L"EnableDHCP");
577 UNICODE_STRING Prefix = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\");
578 UNICODE_STRING TcpipRegistryPath;
579 UNICODE_STRING RegistryDataU;
580 ANSI_STRING RegistryDataA;
581 ULONG Unused;
582 NTSTATUS Status;
583 IP_ADDRESS DefaultMask, Router;
584
585 AddrInitIPv4(&DefaultMask, 0);
586
587 TcpipRegistryPath.MaximumLength = sizeof(WCHAR) * 150;
588 TcpipRegistryPath.Length = 0;
589 TcpipRegistryPath.Buffer = Buffer;
590
591 /* Build the registry path */
592 RtlAppendUnicodeStringToString(&TcpipRegistryPath, &Prefix);
593 RtlAppendUnicodeStringToString(&TcpipRegistryPath, &Interface->Name);
594
595 InitializeObjectAttributes(&ObjectAttributes,
596 &TcpipRegistryPath,
597 OBJ_CASE_INSENSITIVE,
598 0,
599 NULL);
600
601 /* Open a handle to the adapter parameters */
602 Status = ZwOpenKey(&ParameterHandle, KEY_READ, &ObjectAttributes);
603
604 if (!NT_SUCCESS(Status))
605 {
606 return FALSE;
607 }
608 else
609 {
610 KeyValueInfo = ExAllocatePool(PagedPool, sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 16 * sizeof(WCHAR));
611 if (!KeyValueInfo)
612 {
613 ZwClose(ParameterHandle);
614 return FALSE;
615 }
616
617 /* Read the EnableDHCP entry */
618 Status = ZwQueryValueKey(ParameterHandle,
619 &EnableDhcp,
620 KeyValuePartialInformation,
621 KeyValueInfo,
622 sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG),
623 &Unused);
624 if (NT_SUCCESS(Status) && KeyValueInfo->DataLength == sizeof(ULONG) && (*(PULONG)KeyValueInfo->Data) == 0)
625 {
626 RegistryDataU.MaximumLength = 16 + sizeof(WCHAR);
627 RegistryDataU.Buffer = (PWCHAR)KeyValueInfo->Data;
628
629 /* Read the IP address */
630 Status = ZwQueryValueKey(ParameterHandle,
631 &IPAddress,
632 KeyValuePartialInformation,
633 KeyValueInfo,
634 sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 16 * sizeof(WCHAR),
635 &Unused);
636 if (NT_SUCCESS(Status))
637 {
638 RegistryDataU.Length = KeyValueInfo->DataLength;
639
640 RtlUnicodeStringToAnsiString(&RegistryDataA,
641 &RegistryDataU,
642 TRUE);
643
644 AddrInitIPv4(&Interface->Unicast, inet_addr(RegistryDataA.Buffer));
645
646 RtlFreeAnsiString(&RegistryDataA);
647 }
648
649 Status = ZwQueryValueKey(ParameterHandle,
650 &Netmask,
651 KeyValuePartialInformation,
652 KeyValueInfo,
653 sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 16 * sizeof(WCHAR),
654 &Unused);
655 if (NT_SUCCESS(Status))
656 {
657 RegistryDataU.Length = KeyValueInfo->DataLength;
658
659 RtlUnicodeStringToAnsiString(&RegistryDataA,
660 &RegistryDataU,
661 TRUE);
662
663 AddrInitIPv4(&Interface->Netmask, inet_addr(RegistryDataA.Buffer));
664
665 RtlFreeAnsiString(&RegistryDataA);
666 }
667
668 /* We have to wait until both IP address and subnet mask
669 * are read to add the interface route, but we must do it
670 * before we add the default gateway */
671 if (!AddrIsUnspecified(&Interface->Unicast) &&
672 !AddrIsUnspecified(&Interface->Netmask))
673 IPAddInterfaceRoute(Interface);
674
675 /* Read default gateway info */
676 Status = ZwQueryValueKey(ParameterHandle,
677 &Gateway,
678 KeyValuePartialInformation,
679 KeyValueInfo,
680 sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 16 * sizeof(WCHAR),
681 &Unused);
682 if (NT_SUCCESS(Status))
683 {
684 RegistryDataU.Length = KeyValueInfo->DataLength;
685
686 RtlUnicodeStringToAnsiString(&RegistryDataA,
687 &RegistryDataU,
688 TRUE);
689
690 AddrInitIPv4(&Router, inet_addr(RegistryDataA.Buffer));
691
692 if (!AddrIsUnspecified(&Router))
693 RouterCreateRoute(&DefaultMask, &DefaultMask, &Router, Interface, 1);
694
695 RtlFreeAnsiString(&RegistryDataA);
696 }
697 }
698
699 ZwClose(ParameterHandle);
700 }
701
702 return TRUE;
703 }
704
705 BOOLEAN ReconfigureAdapter(PRECONFIGURE_CONTEXT Context)
706 {
707 PLAN_ADAPTER Adapter = Context->Adapter;
708 PIP_INTERFACE Interface = Adapter->Context;
709 //NDIS_STATUS NdisStatus;
710 IP_ADDRESS DefaultMask;
711
712 /* Initialize the default unspecified address (0.0.0.0) */
713 AddrInitIPv4(&DefaultMask, 0);
714 if (Context->State == LAN_STATE_STARTED &&
715 !Context->Adapter->CompletingReset)
716 {
717 /* Read the IP configuration */
718 ReadIpConfiguration(Interface);
719
720 /* Compute the broadcast address */
721 Interface->Broadcast.Type = IP_ADDRESS_V4;
722 Interface->Broadcast.Address.IPv4Address = Interface->Unicast.Address.IPv4Address |
723 ~Interface->Netmask.Address.IPv4Address;
724 }
725 else if (!Context->Adapter->CompletingReset)
726 {
727 /* Clear IP configuration */
728 Interface->Unicast = DefaultMask;
729 Interface->Netmask = DefaultMask;
730 Interface->Broadcast = DefaultMask;
731
732 /* Remove all interface routes */
733 RouterRemoveRoutesForInterface(Interface);
734
735 /* Destroy all cached neighbors */
736 NBDestroyNeighborsForInterface(Interface);
737 }
738
739 Context->Adapter->CompletingReset = FALSE;
740
741 /* Update the IP and link status information cached in TCP */
742 TCPUpdateInterfaceIPInformation(Interface);
743 TCPUpdateInterfaceLinkStatus(Interface);
744
745 /* We're done here if the adapter isn't connected */
746 if (Context->State != LAN_STATE_STARTED)
747 {
748 Adapter->State = Context->State;
749 return TRUE;
750 }
751
752 /* NDIS Bug! */
753 #if 0
754 /* Get maximum link speed */
755 NdisStatus = NDISCall(Adapter,
756 NdisRequestQueryInformation,
757 OID_GEN_LINK_SPEED,
758 &Interface->Speed,
759 sizeof(UINT));
760
761 if (!NT_SUCCESS(NdisStatus))
762 Interface->Speed = IP_DEFAULT_LINK_SPEED;
763
764 Adapter->Speed = Interface->Speed * 100L;
765
766 /* Get maximum frame size */
767 NdisStatus = NDISCall(Adapter,
768 NdisRequestQueryInformation,
769 OID_GEN_MAXIMUM_FRAME_SIZE,
770 &Adapter->MTU,
771 sizeof(UINT));
772 if (NdisStatus != NDIS_STATUS_SUCCESS)
773 return FALSE;
774
775 Interface->MTU = Adapter->MTU;
776
777 /* Get maximum packet size */
778 NdisStatus = NDISCall(Adapter,
779 NdisRequestQueryInformation,
780 OID_GEN_MAXIMUM_TOTAL_SIZE,
781 &Adapter->MaxPacketSize,
782 sizeof(UINT));
783 if (NdisStatus != NDIS_STATUS_SUCCESS)
784 return FALSE;
785 #endif
786
787 Adapter->State = Context->State;
788
789 return TRUE;
790 }
791
792 VOID ReconfigureAdapterWorker(PVOID Context)
793 {
794 PRECONFIGURE_CONTEXT ReconfigureContext = Context;
795
796 /* Complete the reconfiguration asynchronously */
797 ReconfigureAdapter(ReconfigureContext);
798
799 /* Free the context */
800 ExFreePool(ReconfigureContext);
801 }
802
803 VOID NTAPI ProtocolStatus(
804 NDIS_HANDLE BindingContext,
805 NDIS_STATUS GeneralStatus,
806 PVOID StatusBuffer,
807 UINT StatusBufferSize)
808 /*
809 * FUNCTION: Called by NDIS when the underlying driver has changed state
810 * ARGUMENTS:
811 * BindingContext = Pointer to a device context (LAN_ADAPTER)
812 * GeneralStatus = A general status code
813 * StatusBuffer = Pointer to a buffer with medium-specific data
814 * StatusBufferSize = Number of bytes in StatusBuffer
815 */
816 {
817 PLAN_ADAPTER Adapter = BindingContext;
818 PRECONFIGURE_CONTEXT Context;
819
820 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
821
822 /* Ignore the status indication if we have no context yet. We'll get another later */
823 if (!Adapter->Context)
824 return;
825
826 Context = ExAllocatePool(NonPagedPool, sizeof(RECONFIGURE_CONTEXT));
827 if (!Context)
828 return;
829
830 Context->Adapter = Adapter;
831
832 switch(GeneralStatus)
833 {
834 case NDIS_STATUS_MEDIA_CONNECT:
835 DbgPrint("NDIS_STATUS_MEDIA_CONNECT\n");
836
837 if (Adapter->State == LAN_STATE_STARTED)
838 {
839 ExFreePool(Context);
840 return;
841 }
842
843 Context->State = LAN_STATE_STARTED;
844 break;
845
846 case NDIS_STATUS_MEDIA_DISCONNECT:
847 DbgPrint("NDIS_STATUS_MEDIA_DISCONNECT\n");
848
849 if (Adapter->State == LAN_STATE_STOPPED)
850 {
851 ExFreePool(Context);
852 return;
853 }
854
855 Context->State = LAN_STATE_STOPPED;
856 break;
857
858 case NDIS_STATUS_RESET_START:
859 Adapter->OldState = Adapter->State;
860 Adapter->State = LAN_STATE_RESETTING;
861 /* Nothing else to do here */
862 ExFreePool(Context);
863 return;
864
865 case NDIS_STATUS_RESET_END:
866 Adapter->CompletingReset = TRUE;
867 Context->State = Adapter->OldState;
868 break;
869
870 default:
871 DbgPrint("Unhandled status: %x", GeneralStatus);
872 ExFreePool(Context);
873 return;
874 }
875
876 /* Queue the work item */
877 if (!ChewCreate(ReconfigureAdapterWorker, Context))
878 ExFreePool(Context);
879 }
880
881 VOID NTAPI ProtocolStatusComplete(NDIS_HANDLE NdisBindingContext)
882 /*
883 * FUNCTION: Called by NDIS when a status-change has occurred
884 * ARGUMENTS:
885 * BindingContext = Pointer to a device context (LAN_ADAPTER)
886 */
887 {
888 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
889 }
890
891 NDIS_STATUS NTAPI
892 ProtocolPnPEvent(
893 NDIS_HANDLE NdisBindingContext,
894 PNET_PNP_EVENT PnPEvent)
895 {
896 switch(PnPEvent->NetEvent)
897 {
898 case NetEventSetPower:
899 DbgPrint("Device transitioned to power state %ld\n", PnPEvent->Buffer);
900 return NDIS_STATUS_SUCCESS;
901
902 case NetEventQueryPower:
903 DbgPrint("Device wants to go into power state %ld\n", PnPEvent->Buffer);
904 return NDIS_STATUS_SUCCESS;
905
906 case NetEventQueryRemoveDevice:
907 DbgPrint("Device is about to be removed\n");
908 return NDIS_STATUS_SUCCESS;
909
910 case NetEventCancelRemoveDevice:
911 DbgPrint("Device removal cancelled\n");
912 return NDIS_STATUS_SUCCESS;
913
914 default:
915 DbgPrint("Unhandled event type: %ld\n", PnPEvent->NetEvent);
916 return NDIS_STATUS_SUCCESS;
917 }
918 }
919
920 VOID NTAPI ProtocolBindAdapter(
921 OUT PNDIS_STATUS Status,
922 IN NDIS_HANDLE BindContext,
923 IN PNDIS_STRING DeviceName,
924 IN PVOID SystemSpecific1,
925 IN PVOID SystemSpecific2)
926 /*
927 * FUNCTION: Called by NDIS during NdisRegisterProtocol to set up initial
928 * bindings, and periodically thereafer as new adapters come online
929 * ARGUMENTS:
930 * Status: Return value to NDIS
931 * BindContext: Handle provided by NDIS to track pending binding operations
932 * DeviceName: Name of the miniport device to bind to
933 * SystemSpecific1: Pointer to a registry path with protocol-specific configuration information
934 * SystemSpecific2: Unused & must not be touched
935 */
936 {
937 TI_DbgPrint(DEBUG_DATALINK, ("Called with registry path %wZ for %wZ\n", SystemSpecific1, DeviceName));
938 *Status = LANRegisterAdapter(DeviceName, SystemSpecific1);
939 }
940
941
942 VOID LANTransmit(
943 PVOID Context,
944 PNDIS_PACKET NdisPacket,
945 UINT Offset,
946 PVOID LinkAddress,
947 USHORT Type)
948 /*
949 * FUNCTION: Transmits a packet
950 * ARGUMENTS:
951 * Context = Pointer to context information (LAN_ADAPTER)
952 * NdisPacket = Pointer to NDIS packet to send
953 * Offset = Offset in packet where data starts
954 * LinkAddress = Pointer to link address of destination (NULL = broadcast)
955 * Type = LAN protocol type (LAN_PROTO_*)
956 */
957 {
958 NDIS_STATUS NdisStatus;
959 PETH_HEADER EHeader;
960 PCHAR Data, OldData;
961 UINT Size, OldSize;
962 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)Context;
963 KIRQL OldIrql;
964 PNDIS_PACKET XmitPacket;
965 PIP_INTERFACE Interface = Adapter->Context;
966
967 TI_DbgPrint(DEBUG_DATALINK,
968 ("Called( NdisPacket %x, Offset %d, Adapter %x )\n",
969 NdisPacket, Offset, Adapter));
970
971 if (Adapter->State != LAN_STATE_STARTED) {
972 (*PC(NdisPacket)->DLComplete)(PC(NdisPacket)->Context, NdisPacket, NDIS_STATUS_NOT_ACCEPTED);
973 return;
974 }
975
976 TI_DbgPrint(DEBUG_DATALINK,
977 ("Adapter Address [%02x %02x %02x %02x %02x %02x]\n",
978 Adapter->HWAddress[0] & 0xff,
979 Adapter->HWAddress[1] & 0xff,
980 Adapter->HWAddress[2] & 0xff,
981 Adapter->HWAddress[3] & 0xff,
982 Adapter->HWAddress[4] & 0xff,
983 Adapter->HWAddress[5] & 0xff));
984
985 GetDataPtr( NdisPacket, 0, &OldData, &OldSize );
986
987 NdisStatus = AllocatePacketWithBuffer(&XmitPacket, NULL, OldSize + Adapter->HeaderSize);
988 if (NdisStatus != NDIS_STATUS_SUCCESS) {
989 (*PC(NdisPacket)->DLComplete)(PC(NdisPacket)->Context, NdisPacket, NDIS_STATUS_RESOURCES);
990 return;
991 }
992
993 GetDataPtr(XmitPacket, 0, &Data, &Size);
994
995 RtlCopyMemory(Data + Adapter->HeaderSize, OldData, OldSize);
996
997 (*PC(NdisPacket)->DLComplete)(PC(NdisPacket)->Context, NdisPacket, NDIS_STATUS_SUCCESS);
998
999 switch (Adapter->Media) {
1000 case NdisMedium802_3:
1001 EHeader = (PETH_HEADER)Data;
1002
1003 if (LinkAddress) {
1004 /* Unicast address */
1005 RtlCopyMemory(EHeader->DstAddr, LinkAddress, IEEE_802_ADDR_LENGTH);
1006 } else {
1007 /* Broadcast address */
1008 RtlFillMemory(EHeader->DstAddr, IEEE_802_ADDR_LENGTH, 0xFF);
1009 }
1010
1011 RtlCopyMemory(EHeader->SrcAddr, Adapter->HWAddress, IEEE_802_ADDR_LENGTH);
1012
1013 switch (Type) {
1014 case LAN_PROTO_IPv4:
1015 EHeader->EType = ETYPE_IPv4;
1016 break;
1017 case LAN_PROTO_ARP:
1018 EHeader->EType = ETYPE_ARP;
1019 break;
1020 case LAN_PROTO_IPv6:
1021 EHeader->EType = ETYPE_IPv6;
1022 break;
1023 default:
1024 ASSERT(FALSE);
1025 return;
1026 }
1027 break;
1028
1029 default:
1030 /* FIXME: Support other medias */
1031 break;
1032 }
1033
1034 TI_DbgPrint( MID_TRACE, ("LinkAddress: %x\n", LinkAddress));
1035 if( LinkAddress ) {
1036 TI_DbgPrint
1037 ( MID_TRACE,
1038 ("Link Address [%02x %02x %02x %02x %02x %02x]\n",
1039 ((PCHAR)LinkAddress)[0] & 0xff,
1040 ((PCHAR)LinkAddress)[1] & 0xff,
1041 ((PCHAR)LinkAddress)[2] & 0xff,
1042 ((PCHAR)LinkAddress)[3] & 0xff,
1043 ((PCHAR)LinkAddress)[4] & 0xff,
1044 ((PCHAR)LinkAddress)[5] & 0xff));
1045 }
1046
1047 if (Adapter->MTU < Size) {
1048 /* This is NOT a pointer. MSDN explicitly says so. */
1049 NDIS_PER_PACKET_INFO_FROM_PACKET(NdisPacket,
1050 TcpLargeSendPacketInfo) = (PVOID)((ULONG_PTR)Adapter->MTU);
1051 }
1052
1053 /* Update interface stats */
1054 Interface->Stats.OutBytes += Size;
1055
1056 TcpipAcquireSpinLock( &Adapter->Lock, &OldIrql );
1057 TI_DbgPrint(MID_TRACE, ("NdisSend\n"));
1058 NdisSend(&NdisStatus, Adapter->NdisHandle, XmitPacket);
1059 TI_DbgPrint(MID_TRACE, ("NdisSend %s\n",
1060 NdisStatus == NDIS_STATUS_PENDING ?
1061 "Pending" : "Complete"));
1062 TcpipReleaseSpinLock( &Adapter->Lock, OldIrql );
1063
1064 /* I had a talk with vizzini: these really ought to be here.
1065 * we're supposed to see these completed by ndis *only* when
1066 * status_pending is returned. Note that this is different from
1067 * the situation with IRPs. */
1068 if (NdisStatus != NDIS_STATUS_PENDING)
1069 ProtocolSendComplete((NDIS_HANDLE)Context, XmitPacket, NdisStatus);
1070 }
1071
1072 static NTSTATUS
1073 OpenRegistryKey( PNDIS_STRING RegistryPath, PHANDLE RegHandle ) {
1074 OBJECT_ATTRIBUTES Attributes;
1075 NTSTATUS Status;
1076
1077 InitializeObjectAttributes(&Attributes, RegistryPath, OBJ_CASE_INSENSITIVE, 0, 0);
1078 Status = ZwOpenKey(RegHandle, KEY_ALL_ACCESS, &Attributes);
1079 return Status;
1080 }
1081
1082 static NTSTATUS ReadStringFromRegistry( HANDLE RegHandle,
1083 PWCHAR RegistryValue,
1084 PUNICODE_STRING String ) {
1085 UNICODE_STRING ValueName;
1086 UNICODE_STRING UnicodeString;
1087 NTSTATUS Status;
1088 ULONG ResultLength;
1089 UCHAR buf[1024];
1090 PKEY_VALUE_PARTIAL_INFORMATION Information = (PKEY_VALUE_PARTIAL_INFORMATION)buf;
1091
1092 RtlInitUnicodeString(&ValueName, RegistryValue);
1093 Status =
1094 ZwQueryValueKey(RegHandle,
1095 &ValueName,
1096 KeyValuePartialInformation,
1097 Information,
1098 sizeof(buf),
1099 &ResultLength);
1100
1101 if (!NT_SUCCESS(Status))
1102 return Status;
1103 /* IP address is stored as a REG_MULTI_SZ - we only pay attention to the first one though */
1104 TI_DbgPrint(MIN_TRACE, ("Information DataLength: 0x%x\n", Information->DataLength));
1105
1106 UnicodeString.Buffer = (PWCHAR)&Information->Data;
1107 UnicodeString.Length = Information->DataLength - sizeof(WCHAR);
1108 UnicodeString.MaximumLength = Information->DataLength;
1109
1110 String->Buffer =
1111 (PWCHAR)ExAllocatePool( NonPagedPool,
1112 UnicodeString.MaximumLength + sizeof(WCHAR) );
1113
1114 if( !String->Buffer ) return STATUS_NO_MEMORY;
1115
1116 String->MaximumLength = UnicodeString.MaximumLength;
1117 RtlCopyUnicodeString( String, &UnicodeString );
1118
1119 return STATUS_SUCCESS;
1120 }
1121
1122 /*
1123 * Utility to copy and append two unicode strings.
1124 *
1125 * IN OUT PUNICODE_STRING ResultFirst -> First string and result
1126 * IN PUNICODE_STRING Second -> Second string to append
1127 * IN BOOL Deallocate -> TRUE: Deallocate First string before
1128 * overwriting.
1129 *
1130 * Returns NTSTATUS.
1131 */
1132
1133 NTSTATUS NTAPI AppendUnicodeString(PUNICODE_STRING ResultFirst,
1134 PUNICODE_STRING Second,
1135 BOOLEAN Deallocate) {
1136 NTSTATUS Status;
1137 UNICODE_STRING Ustr = *ResultFirst;
1138 PWSTR new_string = ExAllocatePool
1139 (PagedPool,
1140 (ResultFirst->Length + Second->Length + sizeof(WCHAR)));
1141 if( !new_string ) {
1142 return STATUS_NO_MEMORY;
1143 }
1144 memcpy( new_string, ResultFirst->Buffer, ResultFirst->Length );
1145 memcpy( new_string + ResultFirst->Length / sizeof(WCHAR),
1146 Second->Buffer, Second->Length );
1147 if( Deallocate ) RtlFreeUnicodeString(ResultFirst);
1148 ResultFirst->Length = Ustr.Length + Second->Length;
1149 ResultFirst->MaximumLength = ResultFirst->Length;
1150 new_string[ResultFirst->Length / sizeof(WCHAR)] = 0;
1151 Status = RtlCreateUnicodeString(ResultFirst,new_string) ?
1152 STATUS_SUCCESS : STATUS_NO_MEMORY;
1153 ExFreePool(new_string);
1154 return Status;
1155 }
1156
1157 static NTSTATUS CheckForDeviceDesc( PUNICODE_STRING EnumKeyName,
1158 PUNICODE_STRING TargetKeyName,
1159 PUNICODE_STRING Name,
1160 PUNICODE_STRING DeviceDesc ) {
1161 UNICODE_STRING RootDevice = { 0, 0, NULL }, LinkageKeyName = { 0, 0, NULL };
1162 UNICODE_STRING DescKeyName = { 0, 0, NULL }, Linkage = { 0, 0, NULL };
1163 UNICODE_STRING BackSlash = { 0, 0, NULL };
1164 HANDLE DescKey = NULL, LinkageKey = NULL;
1165 NTSTATUS Status;
1166
1167 TI_DbgPrint(DEBUG_DATALINK,("EnumKeyName %wZ\n", EnumKeyName));
1168
1169 RtlInitUnicodeString(&BackSlash, L"\\");
1170 RtlInitUnicodeString(&Linkage, L"\\Linkage");
1171
1172 RtlInitUnicodeString(&DescKeyName, L"");
1173 AppendUnicodeString( &DescKeyName, EnumKeyName, FALSE );
1174 AppendUnicodeString( &DescKeyName, &BackSlash, TRUE );
1175 AppendUnicodeString( &DescKeyName, TargetKeyName, TRUE );
1176
1177 RtlInitUnicodeString(&LinkageKeyName, L"");
1178 AppendUnicodeString( &LinkageKeyName, &DescKeyName, FALSE );
1179 AppendUnicodeString( &LinkageKeyName, &Linkage, TRUE );
1180
1181 Status = OpenRegistryKey( &LinkageKeyName, &LinkageKey );
1182 if( !NT_SUCCESS(Status) ) goto cleanup;
1183
1184 Status = ReadStringFromRegistry( LinkageKey, L"RootDevice", &RootDevice );
1185 if( !NT_SUCCESS(Status) ) goto cleanup;
1186
1187 if( RtlCompareUnicodeString( &RootDevice, Name, TRUE ) == 0 ) {
1188 Status = OpenRegistryKey( &DescKeyName, &DescKey );
1189 if( !NT_SUCCESS(Status) ) goto cleanup;
1190
1191 Status = ReadStringFromRegistry( DescKey, L"DriverDesc", DeviceDesc );
1192 if( !NT_SUCCESS(Status) ) goto cleanup;
1193
1194 TI_DbgPrint(DEBUG_DATALINK,("ADAPTER DESC: %wZ\n", DeviceDesc));
1195 } else Status = STATUS_UNSUCCESSFUL;
1196
1197 cleanup:
1198 RtlFreeUnicodeString( &RootDevice );
1199 RtlFreeUnicodeString( &LinkageKeyName );
1200 RtlFreeUnicodeString( &DescKeyName );
1201 if( LinkageKey ) NtClose( LinkageKey );
1202 if( DescKey ) NtClose( DescKey );
1203
1204 TI_DbgPrint(DEBUG_DATALINK,("Returning %x\n", Status));
1205
1206 return Status;
1207 }
1208
1209 static NTSTATUS FindDeviceDescForAdapter( PUNICODE_STRING Name,
1210 PUNICODE_STRING DeviceDesc ) {
1211 UNICODE_STRING EnumKeyName, TargetKeyName;
1212 HANDLE EnumKey;
1213 NTSTATUS Status;
1214 ULONG i;
1215 KEY_BASIC_INFORMATION *Kbio =
1216 ExAllocatePool(NonPagedPool, sizeof(KEY_BASIC_INFORMATION));
1217 ULONG KbioLength = sizeof(KEY_BASIC_INFORMATION), ResultLength;
1218
1219 RtlInitUnicodeString( DeviceDesc, NULL );
1220
1221 if( !Kbio ) return STATUS_INSUFFICIENT_RESOURCES;
1222
1223 RtlInitUnicodeString
1224 (&EnumKeyName, CCS_ROOT L"\\Control\\Class\\" TCPIP_GUID);
1225
1226 Status = OpenRegistryKey( &EnumKeyName, &EnumKey );
1227
1228 if( !NT_SUCCESS(Status) ) {
1229 TI_DbgPrint(DEBUG_DATALINK,("Couldn't open Enum key %wZ: %x\n",
1230 &EnumKeyName, Status));
1231 ExFreePool( Kbio );
1232 return Status;
1233 }
1234
1235 for( i = 0; NT_SUCCESS(Status); i++ ) {
1236 Status = ZwEnumerateKey( EnumKey, i, KeyBasicInformation,
1237 Kbio, KbioLength, &ResultLength );
1238
1239 if( Status == STATUS_BUFFER_TOO_SMALL || Status == STATUS_BUFFER_OVERFLOW ) {
1240 ExFreePool( Kbio );
1241 KbioLength = ResultLength;
1242 Kbio = ExAllocatePool( NonPagedPool, KbioLength );
1243 if( !Kbio ) {
1244 TI_DbgPrint(DEBUG_DATALINK,("Failed to allocate memory\n"));
1245 NtClose( EnumKey );
1246 return STATUS_NO_MEMORY;
1247 }
1248
1249 Status = ZwEnumerateKey( EnumKey, i, KeyBasicInformation,
1250 Kbio, KbioLength, &ResultLength );
1251
1252 if( !NT_SUCCESS(Status) ) {
1253 TI_DbgPrint(DEBUG_DATALINK,("Couldn't enum key child %d\n", i));
1254 NtClose( EnumKey );
1255 ExFreePool( Kbio );
1256 return Status;
1257 }
1258 }
1259
1260 if( NT_SUCCESS(Status) ) {
1261 TargetKeyName.Length = TargetKeyName.MaximumLength =
1262 Kbio->NameLength;
1263 TargetKeyName.Buffer = Kbio->Name;
1264
1265 Status = CheckForDeviceDesc
1266 ( &EnumKeyName, &TargetKeyName, Name, DeviceDesc );
1267 if( NT_SUCCESS(Status) ) {
1268 NtClose( EnumKey );
1269 ExFreePool( Kbio );
1270 return Status;
1271 } else Status = STATUS_SUCCESS;
1272 }
1273 }
1274
1275 NtClose( EnumKey );
1276 ExFreePool( Kbio );
1277 return STATUS_UNSUCCESSFUL;
1278 }
1279
1280 VOID GetName( PUNICODE_STRING RegistryKey,
1281 PUNICODE_STRING OutName ) {
1282 PWCHAR Ptr;
1283 UNICODE_STRING PartialRegistryKey;
1284
1285 PartialRegistryKey.Buffer =
1286 RegistryKey->Buffer + wcslen(CCS_ROOT L"\\Services\\");
1287 Ptr = PartialRegistryKey.Buffer;
1288
1289 while( *Ptr != L'\\' &&
1290 ((PCHAR)Ptr) < ((PCHAR)RegistryKey->Buffer) + RegistryKey->Length )
1291 Ptr++;
1292
1293 PartialRegistryKey.Length = PartialRegistryKey.MaximumLength =
1294 (Ptr - PartialRegistryKey.Buffer) * sizeof(WCHAR);
1295
1296 RtlInitUnicodeString( OutName, L"" );
1297 AppendUnicodeString( OutName, &PartialRegistryKey, FALSE );
1298 }
1299
1300 BOOLEAN BindAdapter(
1301 PLAN_ADAPTER Adapter,
1302 PNDIS_STRING RegistryPath)
1303 /*
1304 * FUNCTION: Binds a LAN adapter to IP layer
1305 * ARGUMENTS:
1306 * Adapter = Pointer to LAN_ADAPTER structure
1307 * NOTES:
1308 * We set the lookahead buffer size, set the packet filter and
1309 * bind the adapter to IP layer
1310 */
1311 {
1312 PIP_INTERFACE IF;
1313 NDIS_STATUS NdisStatus;
1314 LLIP_BIND_INFO BindInfo;
1315 ULONG Lookahead = LOOKAHEAD_SIZE;
1316 NTSTATUS Status;
1317 NDIS_MEDIA_STATE MediaState;
1318
1319 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
1320
1321 Adapter->State = LAN_STATE_OPENING;
1322
1323 NdisStatus = NDISCall(Adapter,
1324 NdisRequestSetInformation,
1325 OID_GEN_CURRENT_LOOKAHEAD,
1326 &Lookahead,
1327 sizeof(ULONG));
1328 if (NdisStatus != NDIS_STATUS_SUCCESS) {
1329 TI_DbgPrint(DEBUG_DATALINK, ("Could not set lookahead buffer size (0x%X).\n", NdisStatus));
1330 return FALSE;
1331 }
1332
1333 /* Bind the adapter to IP layer */
1334 BindInfo.Context = Adapter;
1335 BindInfo.HeaderSize = Adapter->HeaderSize;
1336 BindInfo.MinFrameSize = Adapter->MinFrameSize;
1337 BindInfo.Address = (PUCHAR)&Adapter->HWAddress;
1338 BindInfo.AddressLength = Adapter->HWAddressLength;
1339 BindInfo.Transmit = LANTransmit;
1340
1341 IF = IPCreateInterface(&BindInfo);
1342
1343 if (!IF) {
1344 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
1345 return FALSE;
1346 }
1347
1348 /*
1349 * Query per-adapter configuration from the registry
1350 * In case anyone is curious: there *is* an Ndis configuration api
1351 * for this sort of thing, but it doesn't really support things like
1352 * REG_MULTI_SZ very well, and there is a note in the DDK that says that
1353 * protocol drivers developed for win2k and above just use the native
1354 * services (ZwOpenKey, etc).
1355 */
1356
1357 GetName( RegistryPath, &IF->Name );
1358
1359 Status = FindDeviceDescForAdapter( &IF->Name, &IF->Description );
1360 if (!NT_SUCCESS(Status)) {
1361 TI_DbgPrint(MIN_TRACE, ("Failed to get device description.\n"));
1362 IPDestroyInterface(IF);
1363 return FALSE;
1364 }
1365
1366 TI_DbgPrint(DEBUG_DATALINK,("Adapter Description: %wZ\n",
1367 &IF->Description));
1368
1369 /* Get maximum link speed */
1370 NdisStatus = NDISCall(Adapter,
1371 NdisRequestQueryInformation,
1372 OID_GEN_LINK_SPEED,
1373 &IF->Speed,
1374 sizeof(UINT));
1375
1376 if (!NT_SUCCESS(NdisStatus))
1377 IF->Speed = IP_DEFAULT_LINK_SPEED;
1378
1379 Adapter->Speed = IF->Speed * 100L;
1380
1381 /* Get maximum frame size */
1382 NdisStatus = NDISCall(Adapter,
1383 NdisRequestQueryInformation,
1384 OID_GEN_MAXIMUM_FRAME_SIZE,
1385 &Adapter->MTU,
1386 sizeof(UINT));
1387 if (NdisStatus != NDIS_STATUS_SUCCESS)
1388 return FALSE;
1389
1390 IF->MTU = Adapter->MTU;
1391
1392 /* Get maximum packet size */
1393 NdisStatus = NDISCall(Adapter,
1394 NdisRequestQueryInformation,
1395 OID_GEN_MAXIMUM_TOTAL_SIZE,
1396 &Adapter->MaxPacketSize,
1397 sizeof(UINT));
1398 if (NdisStatus != NDIS_STATUS_SUCCESS)
1399 return FALSE;
1400
1401 /* Register interface with IP layer */
1402 IPRegisterInterface(IF);
1403
1404 /* Store adapter context */
1405 Adapter->Context = IF;
1406
1407 /* Get the media state */
1408 NdisStatus = NDISCall(Adapter,
1409 NdisRequestQueryInformation,
1410 OID_GEN_MEDIA_CONNECT_STATUS,
1411 &MediaState,
1412 sizeof(MediaState));
1413 if (NdisStatus != NDIS_STATUS_SUCCESS) {
1414 TI_DbgPrint(DEBUG_DATALINK, ("Could not query media status (0x%X).\n", NdisStatus));
1415 IPUnregisterInterface(IF);
1416 IPDestroyInterface(IF);
1417 return FALSE;
1418 }
1419
1420 /* Indicate the current media state */
1421 ProtocolStatus(Adapter,
1422 (MediaState == NdisMediaStateConnected) ? NDIS_STATUS_MEDIA_CONNECT : NDIS_STATUS_MEDIA_DISCONNECT,
1423 NULL, 0);
1424
1425 /* Set packet filter so we can send and receive packets */
1426 NdisStatus = NDISCall(Adapter,
1427 NdisRequestSetInformation,
1428 OID_GEN_CURRENT_PACKET_FILTER,
1429 &Adapter->PacketFilter,
1430 sizeof(UINT));
1431
1432 if (NdisStatus != NDIS_STATUS_SUCCESS) {
1433 TI_DbgPrint(DEBUG_DATALINK, ("Could not set packet filter (0x%X).\n", NdisStatus));
1434 IPUnregisterInterface(IF);
1435 IPDestroyInterface(IF);
1436 return FALSE;
1437 }
1438
1439 return TRUE;
1440 }
1441
1442
1443 VOID UnbindAdapter(
1444 PLAN_ADAPTER Adapter)
1445 /*
1446 * FUNCTION: Unbinds a LAN adapter from IP layer
1447 * ARGUMENTS:
1448 * Adapter = Pointer to LAN_ADAPTER structure
1449 */
1450 {
1451 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
1452
1453 if (Adapter->State == LAN_STATE_STARTED) {
1454 PIP_INTERFACE IF = Adapter->Context;
1455
1456 IPUnregisterInterface(IF);
1457
1458 IPDestroyInterface(IF);
1459 }
1460 }
1461
1462
1463 NDIS_STATUS LANRegisterAdapter(
1464 PNDIS_STRING AdapterName,
1465 PNDIS_STRING RegistryPath)
1466 /*
1467 * FUNCTION: Registers protocol with an NDIS adapter
1468 * ARGUMENTS:
1469 * AdapterName = Pointer to string with name of adapter to register
1470 * Adapter = Address of pointer to a LAN_ADAPTER structure
1471 * RETURNS:
1472 * Status of operation
1473 */
1474 {
1475 PLAN_ADAPTER IF;
1476 NDIS_STATUS NdisStatus;
1477 NDIS_STATUS OpenStatus;
1478 UINT MediaIndex;
1479 NDIS_MEDIUM MediaArray[MAX_MEDIA];
1480 UINT AddressOID;
1481
1482 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
1483
1484 IF = ExAllocatePoolWithTag(NonPagedPool, sizeof(LAN_ADAPTER), LAN_ADAPTER_TAG);
1485 if (!IF) {
1486 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
1487 return NDIS_STATUS_RESOURCES;
1488 }
1489
1490 RtlZeroMemory(IF, sizeof(LAN_ADAPTER));
1491
1492 /* Put adapter in stopped state */
1493 IF->State = LAN_STATE_STOPPED;
1494
1495 /* Initialize protecting spin lock */
1496 KeInitializeSpinLock(&IF->Lock);
1497
1498 KeInitializeEvent(&IF->Event, SynchronizationEvent, FALSE);
1499
1500 /* Initialize array with media IDs we support */
1501 MediaArray[MEDIA_ETH] = NdisMedium802_3;
1502
1503 TI_DbgPrint(DEBUG_DATALINK,("opening adapter %wZ\n", AdapterName));
1504 /* Open the adapter. */
1505 NdisOpenAdapter(&NdisStatus,
1506 &OpenStatus,
1507 &IF->NdisHandle,
1508 &MediaIndex,
1509 MediaArray,
1510 MAX_MEDIA,
1511 NdisProtocolHandle,
1512 IF,
1513 AdapterName,
1514 0,
1515 NULL);
1516
1517 /* Wait until the adapter is opened */
1518 if (NdisStatus == NDIS_STATUS_PENDING)
1519 KeWaitForSingleObject(&IF->Event, UserRequest, KernelMode, FALSE, NULL);
1520 else if (NdisStatus != NDIS_STATUS_SUCCESS) {
1521 TI_DbgPrint(DEBUG_DATALINK,("denying adapter %wZ\n", AdapterName));
1522 ExFreePoolWithTag(IF, LAN_ADAPTER_TAG);
1523 return NdisStatus;
1524 }
1525
1526 IF->Media = MediaArray[MediaIndex];
1527
1528 /* Fill LAN_ADAPTER structure with some adapter specific information */
1529 switch (IF->Media) {
1530 case NdisMedium802_3:
1531 IF->HWAddressLength = IEEE_802_ADDR_LENGTH;
1532 IF->BCastMask = BCAST_ETH_MASK;
1533 IF->BCastCheck = BCAST_ETH_CHECK;
1534 IF->BCastOffset = BCAST_ETH_OFFSET;
1535 IF->HeaderSize = sizeof(ETH_HEADER);
1536 IF->MinFrameSize = 60;
1537 AddressOID = OID_802_3_CURRENT_ADDRESS;
1538 IF->PacketFilter =
1539 NDIS_PACKET_TYPE_BROADCAST |
1540 NDIS_PACKET_TYPE_DIRECTED |
1541 NDIS_PACKET_TYPE_MULTICAST;
1542 break;
1543
1544 default:
1545 /* Unsupported media */
1546 TI_DbgPrint(MIN_TRACE, ("Unsupported media.\n"));
1547 ExFreePoolWithTag(IF, LAN_ADAPTER_TAG);
1548 return NDIS_STATUS_NOT_SUPPORTED;
1549 }
1550
1551 /* Get maximum number of packets we can pass to NdisSend(Packets) at one time */
1552 NdisStatus = NDISCall(IF,
1553 NdisRequestQueryInformation,
1554 OID_GEN_MAXIMUM_SEND_PACKETS,
1555 &IF->MaxSendPackets,
1556 sizeof(UINT));
1557 if (NdisStatus != NDIS_STATUS_SUCCESS)
1558 /* Legacy NIC drivers may not support this query, if it fails we
1559 assume it can send at least one packet per call to NdisSend(Packets) */
1560 IF->MaxSendPackets = 1;
1561
1562 /* Get current hardware address */
1563 NdisStatus = NDISCall(IF,
1564 NdisRequestQueryInformation,
1565 AddressOID,
1566 &IF->HWAddress,
1567 IF->HWAddressLength);
1568 if (NdisStatus != NDIS_STATUS_SUCCESS) {
1569 TI_DbgPrint(MIN_TRACE, ("Query for current hardware address failed.\n"));
1570 ExFreePoolWithTag(IF, LAN_ADAPTER_TAG);
1571 return NdisStatus;
1572 }
1573
1574 /* Bind adapter to IP layer */
1575 if( !BindAdapter(IF, RegistryPath) ) {
1576 TI_DbgPrint(DEBUG_DATALINK,("denying adapter %wZ (BindAdapter)\n", AdapterName));
1577 ExFreePoolWithTag(IF, LAN_ADAPTER_TAG);
1578 return NDIS_STATUS_NOT_ACCEPTED;
1579 }
1580
1581 /* Add adapter to the adapter list */
1582 ExInterlockedInsertTailList(&AdapterListHead,
1583 &IF->ListEntry,
1584 &AdapterListLock);
1585
1586 TI_DbgPrint(DEBUG_DATALINK, ("Leaving.\n"));
1587
1588 return NDIS_STATUS_SUCCESS;
1589 }
1590
1591
1592 NDIS_STATUS LANUnregisterAdapter(
1593 PLAN_ADAPTER Adapter)
1594 /*
1595 * FUNCTION: Unregisters protocol with NDIS adapter
1596 * ARGUMENTS:
1597 * Adapter = Pointer to a LAN_ADAPTER structure
1598 * RETURNS:
1599 * Status of operation
1600 */
1601 {
1602 KIRQL OldIrql;
1603 NDIS_HANDLE NdisHandle;
1604 NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS;
1605
1606 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
1607
1608 /* Unlink the adapter from the list */
1609 RemoveEntryList(&Adapter->ListEntry);
1610
1611 /* Unbind adapter from IP layer */
1612 UnbindAdapter(Adapter);
1613
1614 TcpipAcquireSpinLock(&Adapter->Lock, &OldIrql);
1615 NdisHandle = Adapter->NdisHandle;
1616 if (NdisHandle) {
1617 Adapter->NdisHandle = NULL;
1618 TcpipReleaseSpinLock(&Adapter->Lock, OldIrql);
1619
1620 NdisCloseAdapter(&NdisStatus, NdisHandle);
1621 if (NdisStatus == NDIS_STATUS_PENDING) {
1622 TcpipWaitForSingleObject(&Adapter->Event,
1623 UserRequest,
1624 KernelMode,
1625 FALSE,
1626 NULL);
1627 NdisStatus = Adapter->NdisStatus;
1628 }
1629 } else
1630 TcpipReleaseSpinLock(&Adapter->Lock, OldIrql);
1631
1632 FreeAdapter(Adapter);
1633
1634 return NdisStatus;
1635 }
1636
1637 VOID
1638 NTAPI
1639 LANUnregisterProtocol(VOID)
1640 /*
1641 * FUNCTION: Unregisters this protocol driver with NDIS
1642 * NOTES: Does not care wether we are already registered
1643 */
1644 {
1645 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
1646
1647 if (ProtocolRegistered) {
1648 NDIS_STATUS NdisStatus;
1649 PLIST_ENTRY CurrentEntry;
1650 PLIST_ENTRY NextEntry;
1651 PLAN_ADAPTER Current;
1652 KIRQL OldIrql;
1653
1654 TcpipAcquireSpinLock(&AdapterListLock, &OldIrql);
1655
1656 /* Search the list and remove every adapter we find */
1657 CurrentEntry = AdapterListHead.Flink;
1658 while (CurrentEntry != &AdapterListHead) {
1659 NextEntry = CurrentEntry->Flink;
1660 Current = CONTAINING_RECORD(CurrentEntry, LAN_ADAPTER, ListEntry);
1661 /* Unregister it */
1662 LANUnregisterAdapter(Current);
1663 CurrentEntry = NextEntry;
1664 }
1665
1666 TcpipReleaseSpinLock(&AdapterListLock, OldIrql);
1667
1668 NdisDeregisterProtocol(&NdisStatus, NdisProtocolHandle);
1669 ProtocolRegistered = FALSE;
1670 }
1671 }
1672
1673 VOID
1674 NTAPI
1675 ProtocolUnbindAdapter(
1676 PNDIS_STATUS Status,
1677 NDIS_HANDLE ProtocolBindingContext,
1678 NDIS_HANDLE UnbindContext)
1679 {
1680 /* We don't pend any unbinding so we can just ignore UnbindContext */
1681 *Status = LANUnregisterAdapter((PLAN_ADAPTER)ProtocolBindingContext);
1682 }
1683
1684 NTSTATUS LANRegisterProtocol(
1685 PNDIS_STRING Name)
1686 /*
1687 * FUNCTION: Registers this protocol driver with NDIS
1688 * ARGUMENTS:
1689 * Name = Name of this protocol driver
1690 * RETURNS:
1691 * Status of operation
1692 */
1693 {
1694 NDIS_STATUS NdisStatus;
1695 NDIS_PROTOCOL_CHARACTERISTICS ProtChars;
1696
1697 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
1698
1699 InitializeListHead(&AdapterListHead);
1700 KeInitializeSpinLock(&AdapterListLock);
1701
1702 /* Set up protocol characteristics */
1703 RtlZeroMemory(&ProtChars, sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
1704 ProtChars.MajorNdisVersion = NDIS_VERSION_MAJOR;
1705 ProtChars.MinorNdisVersion = NDIS_VERSION_MINOR;
1706 ProtChars.Name.Length = Name->Length;
1707 ProtChars.Name.Buffer = Name->Buffer;
1708 ProtChars.Name.MaximumLength = Name->MaximumLength;
1709 ProtChars.OpenAdapterCompleteHandler = ProtocolOpenAdapterComplete;
1710 ProtChars.CloseAdapterCompleteHandler = ProtocolCloseAdapterComplete;
1711 ProtChars.ResetCompleteHandler = ProtocolResetComplete;
1712 ProtChars.RequestCompleteHandler = ProtocolRequestComplete;
1713 ProtChars.SendCompleteHandler = ProtocolSendComplete;
1714 ProtChars.TransferDataCompleteHandler = ProtocolTransferDataComplete;
1715 ProtChars.ReceivePacketHandler = ProtocolReceivePacket;
1716 ProtChars.ReceiveHandler = ProtocolReceive;
1717 ProtChars.ReceiveCompleteHandler = ProtocolReceiveComplete;
1718 ProtChars.StatusHandler = ProtocolStatus;
1719 ProtChars.StatusCompleteHandler = ProtocolStatusComplete;
1720 ProtChars.BindAdapterHandler = ProtocolBindAdapter;
1721 ProtChars.PnPEventHandler = ProtocolPnPEvent;
1722 ProtChars.UnbindAdapterHandler = ProtocolUnbindAdapter;
1723 ProtChars.UnloadHandler = LANUnregisterProtocol;
1724
1725 /* Try to register protocol */
1726 NdisRegisterProtocol(&NdisStatus,
1727 &NdisProtocolHandle,
1728 &ProtChars,
1729 sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
1730 if (NdisStatus != NDIS_STATUS_SUCCESS)
1731 {
1732 TI_DbgPrint(DEBUG_DATALINK, ("NdisRegisterProtocol failed, status 0x%x\n", NdisStatus));
1733 return (NTSTATUS)NdisStatus;
1734 }
1735
1736 ProtocolRegistered = TRUE;
1737
1738 return STATUS_SUCCESS;
1739 }
1740
1741 /* EOF */