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