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