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