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