Don't use NdisTransferData if the whole packet is contained in the header+lookup...
[reactos.git] / reactos / drivers / net / 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 typedef struct _LAN_WQ_ITEM {
14 LIST_ENTRY ListEntry;
15 PNDIS_PACKET Packet;
16 PLAN_ADAPTER Adapter;
17 UINT BytesTransferred;
18 } LAN_WQ_ITEM, *PLAN_WQ_ITEM;
19
20 NDIS_HANDLE NdisProtocolHandle = (NDIS_HANDLE)NULL;
21 BOOLEAN ProtocolRegistered = FALSE;
22 LIST_ENTRY AdapterListHead;
23 KSPIN_LOCK AdapterListLock;
24
25 /* Work around being called back into afd at Dpc level */
26 KSPIN_LOCK LanWorkLock;
27 LIST_ENTRY LanWorkList;
28 WORK_QUEUE_ITEM LanWorkItem;
29
30 NDIS_STATUS NDISCall(
31 PLAN_ADAPTER Adapter,
32 NDIS_REQUEST_TYPE Type,
33 NDIS_OID OID,
34 PVOID Buffer,
35 UINT Length)
36 /*
37 * FUNCTION: Send a request to NDIS
38 * ARGUMENTS:
39 * Adapter = Pointer to a LAN_ADAPTER structure
40 * Type = Type of request (Set or Query)
41 * OID = Value to be set/queried for
42 * Buffer = Pointer to a buffer to use
43 * Length = Number of bytes in Buffer
44 * RETURNS:
45 * Status of operation
46 */
47 {
48 NDIS_REQUEST Request;
49 NDIS_STATUS NdisStatus;
50
51 Request.RequestType = Type;
52 if (Type == NdisRequestSetInformation) {
53 Request.DATA.SET_INFORMATION.Oid = OID;
54 Request.DATA.SET_INFORMATION.InformationBuffer = Buffer;
55 Request.DATA.SET_INFORMATION.InformationBufferLength = Length;
56 } else {
57 Request.DATA.QUERY_INFORMATION.Oid = OID;
58 Request.DATA.QUERY_INFORMATION.InformationBuffer = Buffer;
59 Request.DATA.QUERY_INFORMATION.InformationBufferLength = Length;
60 }
61
62 if (Adapter->State != LAN_STATE_RESETTING) {
63 NdisRequest(&NdisStatus, Adapter->NdisHandle, &Request);
64 } else {
65 NdisStatus = NDIS_STATUS_NOT_ACCEPTED;
66 }
67
68 /* Wait for NDIS to complete the request */
69 if (NdisStatus == NDIS_STATUS_PENDING) {
70 KeWaitForSingleObject(&Adapter->Event,
71 UserRequest,
72 KernelMode,
73 FALSE,
74 NULL);
75 NdisStatus = Adapter->NdisStatus;
76 }
77
78 return NdisStatus;
79 }
80
81
82 VOID FreeAdapter(
83 PLAN_ADAPTER Adapter)
84 /*
85 * FUNCTION: Frees memory for a LAN_ADAPTER structure
86 * ARGUMENTS:
87 * Adapter = Pointer to LAN_ADAPTER structure to free
88 */
89 {
90 exFreePool(Adapter);
91 }
92
93
94 VOID STDCALL ProtocolOpenAdapterComplete(
95 NDIS_HANDLE BindingContext,
96 NDIS_STATUS Status,
97 NDIS_STATUS OpenErrorStatus)
98 /*
99 * FUNCTION: Called by NDIS to complete opening of an adapter
100 * ARGUMENTS:
101 * BindingContext = Pointer to a device context (LAN_ADAPTER)
102 * Status = Status of the operation
103 * OpenErrorStatus = Additional status information
104 */
105 {
106 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
107
108 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
109
110 KeSetEvent(&Adapter->Event, 0, FALSE);
111 }
112
113
114 VOID STDCALL ProtocolCloseAdapterComplete(
115 NDIS_HANDLE BindingContext,
116 NDIS_STATUS Status)
117 /*
118 * FUNCTION: Called by NDIS to complete closing an adapter
119 * ARGUMENTS:
120 * BindingContext = Pointer to a device context (LAN_ADAPTER)
121 * Status = Status of the operation
122 */
123 {
124 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
125
126 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
127
128 Adapter->NdisStatus = Status;
129
130 KeSetEvent(&Adapter->Event, 0, FALSE);
131 }
132
133
134 VOID STDCALL ProtocolResetComplete(
135 NDIS_HANDLE BindingContext,
136 NDIS_STATUS Status)
137 /*
138 * FUNCTION: Called by NDIS to complete resetting an adapter
139 * ARGUMENTS:
140 * BindingContext = Pointer to a device context (LAN_ADAPTER)
141 * Status = Status of the operation
142 */
143 {
144 TI_DbgPrint(MID_TRACE, ("Called.\n"));
145 }
146
147
148 VOID STDCALL ProtocolRequestComplete(
149 NDIS_HANDLE BindingContext,
150 PNDIS_REQUEST NdisRequest,
151 NDIS_STATUS Status)
152 /*
153 * FUNCTION: Called by NDIS to complete a request
154 * ARGUMENTS:
155 * BindingContext = Pointer to a device context (LAN_ADAPTER)
156 * NdisRequest = Pointer to an object describing the request
157 * Status = Status of the operation
158 */
159 {
160 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
161
162 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
163
164 /* Save status of request and signal an event */
165 Adapter->NdisStatus = Status;
166
167 KeSetEvent(&Adapter->Event, 0, FALSE);
168 }
169
170
171 VOID STDCALL ProtocolSendComplete(
172 NDIS_HANDLE BindingContext,
173 PNDIS_PACKET Packet,
174 NDIS_STATUS Status)
175 /*
176 * FUNCTION: Called by NDIS to complete sending process
177 * ARGUMENTS:
178 * BindingContext = Pointer to a device context (LAN_ADAPTER)
179 * Packet = Pointer to a packet descriptor
180 * Status = Status of the operation
181 */
182 {
183 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
184
185 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
186
187 AdjustPacket(Packet, Adapter->HeaderSize, PC(Packet)->DLOffset);
188 TI_DbgPrint(DEBUG_DATALINK, ("Calling completion routine\n"));
189 (*PC(Packet)->DLComplete)(Adapter->Context, Packet, Status);
190 TI_DbgPrint(DEBUG_DATALINK, ("Finished\n"));
191 }
192
193 VOID STDCALL LanReceiveWorker( PVOID Context ) {
194 UINT PacketType;
195 PLIST_ENTRY ListEntry;
196 PLAN_WQ_ITEM WorkItem;
197 PNDIS_PACKET Packet;
198 PLAN_ADAPTER Adapter;
199 UINT BytesTransferred;
200 PNDIS_BUFFER NdisBuffer;
201 IP_PACKET IPPacket;
202
203
204 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
205
206 while( (ListEntry =
207 ExInterlockedRemoveHeadList( &LanWorkList, &LanWorkLock )) ) {
208 WorkItem = CONTAINING_RECORD(ListEntry, LAN_WQ_ITEM, ListEntry);
209
210 Packet = WorkItem->Packet;
211 Adapter = WorkItem->Adapter;
212 BytesTransferred = WorkItem->BytesTransferred;
213
214 ExFreePool( WorkItem );
215
216 IPPacket.NdisPacket = Packet;
217
218 NdisGetFirstBufferFromPacket(Packet,
219 &NdisBuffer,
220 &IPPacket.Header,
221 &IPPacket.ContigSize,
222 &IPPacket.TotalSize);
223
224 IPPacket.ContigSize = IPPacket.TotalSize = BytesTransferred;
225 /* Determine which upper layer protocol that should receive
226 this packet and pass it to the correct receive handler */
227
228 OskitDumpBuffer( IPPacket.Header, BytesTransferred );
229
230 PacketType = ((PETH_HEADER)IPPacket.Header)->EType;
231 IPPacket.Header = ((PCHAR)IPPacket.Header) + sizeof(ETH_HEADER);
232 IPPacket.Position = sizeof(ETH_HEADER);
233 IPPacket.TotalSize -= sizeof(ETH_HEADER);
234
235 TI_DbgPrint
236 (DEBUG_DATALINK,
237 ("Ether Type = %x ContigSize = %d Total = %d\n",
238 PacketType, IPPacket.ContigSize, IPPacket.TotalSize));
239
240 switch (PacketType) {
241 case ETYPE_IPv4:
242 case ETYPE_IPv6:
243 TI_DbgPrint(MID_TRACE,("Received IP Packet\n"));
244 IPReceive(Adapter->Context, &IPPacket);
245 break;
246 case ETYPE_ARP:
247 TI_DbgPrint(MID_TRACE,("Received ARP Packet\n"));
248 ARPReceive(Adapter->Context, &IPPacket);
249 default:
250 break;
251 }
252
253 FreeNdisPacket( Packet );
254 }
255 }
256
257 VOID STDCALL ProtocolTransferDataComplete(
258 NDIS_HANDLE BindingContext,
259 PNDIS_PACKET Packet,
260 NDIS_STATUS Status,
261 UINT BytesTransferred)
262 /*
263 * FUNCTION: Called by NDIS to complete reception of data
264 * ARGUMENTS:
265 * BindingContext = Pointer to a device context (LAN_ADAPTER)
266 * Packet = Pointer to a packet descriptor
267 * Status = Status of the operation
268 * BytesTransferred = Number of bytes transferred
269 * NOTES:
270 * If the packet was successfully received, determine the protocol
271 * type and pass it to the correct receive handler
272 */
273 {
274 BOOLEAN WorkStart;
275 PLAN_WQ_ITEM WQItem;
276 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
277
278 if( Status != NDIS_STATUS_SUCCESS ) return;
279 WQItem = ExAllocatePool( NonPagedPool, sizeof(LAN_WQ_ITEM) );
280 if( !WQItem ) return;
281
282 KeAcquireSpinLockAtDpcLevel( &LanWorkLock );
283 WorkStart = IsListEmpty( &LanWorkList );
284 WQItem->Packet = Packet;
285 WQItem->Adapter = Adapter;
286 WQItem->BytesTransferred = BytesTransferred;
287 InsertTailList( &LanWorkList, &WQItem->ListEntry );
288 if( WorkStart )
289 ExQueueWorkItem( &LanWorkItem, CriticalWorkQueue );
290 KeReleaseSpinLockFromDpcLevel( &LanWorkLock );
291 }
292
293 NDIS_STATUS STDCALL ProtocolReceive(
294 NDIS_HANDLE BindingContext,
295 NDIS_HANDLE MacReceiveContext,
296 PVOID HeaderBuffer,
297 UINT HeaderBufferSize,
298 PVOID LookaheadBuffer,
299 UINT LookaheadBufferSize,
300 UINT PacketSize)
301 /*
302 * FUNCTION: Called by NDIS when a packet has been received on the physical link
303 * ARGUMENTS:
304 * BindingContext = Pointer to a device context (LAN_ADAPTER)
305 * MacReceiveContext = Handle used by underlying NIC driver
306 * HeaderBuffer = Pointer to a buffer containing the packet header
307 * HeaderBufferSize = Number of bytes in HeaderBuffer
308 * LookaheadBuffer = Pointer to a buffer containing buffered packet data
309 * LookaheadBufferSize = Size of LookaheadBuffer. May be less than asked for
310 * PacketSize = Overall size of the packet (not including header)
311 * RETURNS:
312 * Status of operation
313 */
314 {
315 USHORT EType;
316 UINT PacketType, BytesTransferred;
317 IP_PACKET IPPacket;
318 PCHAR BufferData;
319 NDIS_STATUS NdisStatus;
320 PNDIS_PACKET NdisPacket;
321 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
322 PETH_HEADER EHeader = (PETH_HEADER)HeaderBuffer;
323
324 TI_DbgPrint(DEBUG_DATALINK, ("Called. (packetsize %d)\n",PacketSize));
325
326 if (Adapter->State != LAN_STATE_STARTED) {
327 TI_DbgPrint(DEBUG_DATALINK, ("Adapter is stopped.\n"));
328 return NDIS_STATUS_NOT_ACCEPTED;
329 }
330
331 if (HeaderBufferSize < Adapter->HeaderSize) {
332 TI_DbgPrint(DEBUG_DATALINK, ("Runt frame received.\n"));
333 return NDIS_STATUS_NOT_ACCEPTED;
334 }
335
336 if (Adapter->Media == NdisMedium802_3) {
337 /* Ethernet and IEEE 802.3 frames can be destinguished by
338 looking at the IEEE 802.3 length field. This field is
339 less than or equal to 1500 for a valid IEEE 802.3 frame
340 and larger than 1500 is it's a valid EtherType value.
341 See RFC 1122, section 2.3.3 for more information */
342 /* FIXME: Test for Ethernet and IEEE 802.3 frame */
343 if (((EType = EHeader->EType) != ETYPE_IPv4) && (EType != ETYPE_ARP)) {
344 TI_DbgPrint(DEBUG_DATALINK, ("Not IP or ARP frame. EtherType (0x%X).\n", EType));
345 return NDIS_STATUS_NOT_ACCEPTED;
346 }
347 /* We use EtherType constants to destinguish packet types */
348 PacketType = EType;
349 } else {
350 TI_DbgPrint(MIN_TRACE, ("Unsupported media.\n"));
351 /* FIXME: Support other medias */
352 return NDIS_STATUS_NOT_ACCEPTED;
353 }
354
355 /* Get a transfer data packet */
356
357 KeAcquireSpinLockAtDpcLevel(&Adapter->Lock);
358 NdisStatus = AllocatePacketWithBuffer( &NdisPacket, NULL, Adapter->MTU );
359 if( NdisStatus != NDIS_STATUS_SUCCESS ) {
360 KeReleaseSpinLockFromDpcLevel(&Adapter->Lock);
361 return NDIS_STATUS_NOT_ACCEPTED;
362 }
363
364 TI_DbgPrint(DEBUG_DATALINK, ("pretransfer LookaheadBufferSize %d packsize %d\n",LookaheadBufferSize,PacketSize));
365 {
366 UINT temp;
367 temp = PacketSize;
368 GetDataPtr( NdisPacket, 0, &BufferData, &temp );
369 }
370
371 IPPacket.NdisPacket = NdisPacket;
372 IPPacket.Position = 0;
373
374 if ((LookaheadBufferSize + HeaderBufferSize) < PacketSize)
375 {
376 TI_DbgPrint(DEBUG_DATALINK, ("pretransfer LookaheadBufferSize %d packsize %d\n",LookaheadBufferSize,PacketSize));
377 /* Get the data */
378 NdisTransferData(&NdisStatus,
379 Adapter->NdisHandle,
380 MacReceiveContext,
381 0,
382 PacketSize + HeaderBufferSize,
383 NdisPacket,
384 &BytesTransferred);
385 } else {
386 TI_DbgPrint(DEBUG_DATALINK, ("copy\n"));
387 NdisStatus = NDIS_STATUS_SUCCESS;
388 BytesTransferred = PacketSize;
389 RtlCopyMemory(BufferData,
390 HeaderBuffer,
391 HeaderBufferSize);
392 RtlCopyMemory(BufferData + HeaderBufferSize,
393 LookaheadBuffer, LookaheadBufferSize);
394 }
395 TI_DbgPrint(DEBUG_DATALINK, ("Calling complete\n"));
396
397 /* Release the packet descriptor */
398 KeReleaseSpinLockFromDpcLevel(&Adapter->Lock);
399
400 if (NdisStatus != NDIS_STATUS_PENDING)
401 ProtocolTransferDataComplete(BindingContext,
402 NdisPacket,
403 NdisStatus,
404 PacketSize + HeaderBufferSize);
405
406 TI_DbgPrint(DEBUG_DATALINK, ("leaving\n"));
407
408 return NDIS_STATUS_SUCCESS;
409 }
410
411
412 VOID STDCALL ProtocolReceiveComplete(
413 NDIS_HANDLE BindingContext)
414 /*
415 * FUNCTION: Called by NDIS when we're done receiving data
416 * ARGUMENTS:
417 * BindingContext = Pointer to a device context (LAN_ADAPTER)
418 */
419 {
420 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
421 }
422
423
424 VOID STDCALL ProtocolStatus(
425 NDIS_HANDLE BindingContext,
426 NDIS_STATUS GenerelStatus,
427 PVOID StatusBuffer,
428 UINT StatusBufferSize)
429 /*
430 * FUNCTION: Called by NDIS when the underlying driver has changed state
431 * ARGUMENTS:
432 * BindingContext = Pointer to a device context (LAN_ADAPTER)
433 * GenerelStatus = A generel status code
434 * StatusBuffer = Pointer to a buffer with medium-specific data
435 * StatusBufferSize = Number of bytes in StatusBuffer
436 */
437 {
438 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
439 }
440
441
442 VOID STDCALL ProtocolStatusComplete(
443 NDIS_HANDLE NdisBindingContext)
444 /*
445 * FUNCTION: Called by NDIS when a status-change has occurred
446 * ARGUMENTS:
447 * BindingContext = Pointer to a device context (LAN_ADAPTER)
448 */
449 {
450 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
451 }
452
453 VOID STDCALL ProtocolBindAdapter(
454 OUT PNDIS_STATUS Status,
455 IN NDIS_HANDLE BindContext,
456 IN PNDIS_STRING DeviceName,
457 IN PVOID SystemSpecific1,
458 IN PVOID SystemSpecific2)
459 /*
460 * FUNCTION: Called by NDIS during NdisRegisterProtocol to set up initial
461 * bindings, and periodically thereafer as new adapters come online
462 * ARGUMENTS:
463 * Status: Return value to NDIS
464 * BindContext: Handle provided by NDIS to track pending binding operations
465 * DeviceName: Name of the miniport device to bind to
466 * SystemSpecific1: Pointer to a registry path with protocol-specific configuration information
467 * SystemSpecific2: Unused & must not be touched
468 */
469 {
470 /* XXX confirm that this is still true, or re-word the following comment */
471 /* we get to ignore BindContext because we will never pend an operation with NDIS */
472 TI_DbgPrint(DEBUG_DATALINK, ("Called with registry path %wZ\n", SystemSpecific1));
473 *Status = LANRegisterAdapter(DeviceName, SystemSpecific1);
474 }
475
476
477 VOID LANTransmit(
478 PVOID Context,
479 PNDIS_PACKET NdisPacket,
480 UINT Offset,
481 PVOID LinkAddress,
482 USHORT Type)
483 /*
484 * FUNCTION: Transmits a packet
485 * ARGUMENTS:
486 * Context = Pointer to context information (LAN_ADAPTER)
487 * NdisPacket = Pointer to NDIS packet to send
488 * Offset = Offset in packet where data starts
489 * LinkAddress = Pointer to link address of destination (NULL = broadcast)
490 * Type = LAN protocol type (LAN_PROTO_*)
491 */
492 {
493 NDIS_STATUS NdisStatus;
494 PETH_HEADER EHeader;
495 PVOID Data;
496 KIRQL OldIrql;
497 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)Context;
498
499 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
500
501 /* NDIS send routines don't have an offset argument so we
502 must offset the data in upper layers and adjust the
503 packet here. We save the offset in the packet context
504 area so it can be undone before we release the packet */
505 Data = AdjustPacket(NdisPacket, Offset, Adapter->HeaderSize);
506 PC(NdisPacket)->DLOffset = Offset;
507
508 if (Adapter->State == LAN_STATE_STARTED) {
509 switch (Adapter->Media) {
510 case NdisMedium802_3:
511 EHeader = (PETH_HEADER)Data;
512
513 if (LinkAddress) {
514 /* Unicast address */
515 RtlCopyMemory(EHeader->DstAddr, LinkAddress, IEEE_802_ADDR_LENGTH);
516 } else {
517 /* Broadcast address */
518 RtlFillMemory(EHeader->DstAddr, IEEE_802_ADDR_LENGTH, 0xFF);
519 }
520
521 RtlCopyMemory(EHeader->SrcAddr, Adapter->HWAddress, IEEE_802_ADDR_LENGTH);
522
523 switch (Type) {
524 case LAN_PROTO_IPv4:
525 EHeader->EType = ETYPE_IPv4;
526 break;
527 case LAN_PROTO_ARP:
528 EHeader->EType = ETYPE_ARP;
529 break;
530 case LAN_PROTO_IPv6:
531 EHeader->EType = ETYPE_IPv6;
532 break;
533 default:
534 #ifdef DBG
535 /* Should not happen */
536 TI_DbgPrint(MIN_TRACE, ("Unknown LAN protocol.\n"));
537
538 ProtocolSendComplete((NDIS_HANDLE)Context,
539 NdisPacket,
540 NDIS_STATUS_FAILURE);
541 #endif
542 return;
543 }
544 break;
545
546 default:
547 /* FIXME: Support other medias */
548 break;
549 }
550
551 KeAcquireSpinLock( &Adapter->Lock, &OldIrql );
552 NdisSend(&NdisStatus, Adapter->NdisHandle, NdisPacket);
553 KeReleaseSpinLock( &Adapter->Lock, OldIrql );
554
555 if (NdisStatus != NDIS_STATUS_PENDING)
556 ProtocolSendComplete((NDIS_HANDLE)Context, NdisPacket, NdisStatus);
557 } else {
558 ProtocolSendComplete((NDIS_HANDLE)Context, NdisPacket, NDIS_STATUS_CLOSED);
559 }
560 }
561
562 static NTSTATUS
563 OpenRegistryKey( PNDIS_STRING RegistryPath, PHANDLE RegHandle ) {
564 OBJECT_ATTRIBUTES Attributes;
565 NTSTATUS Status;
566
567 InitializeObjectAttributes(&Attributes, RegistryPath, OBJ_CASE_INSENSITIVE, 0, 0);
568 Status = ZwOpenKey(RegHandle, GENERIC_READ, &Attributes);
569 return Status;
570 }
571
572 static NTSTATUS ReadIPAddressFromRegistry( HANDLE RegHandle,
573 PWCHAR RegistryValue,
574 PIP_ADDRESS *Address ) {
575 UNICODE_STRING ValueName;
576 UNICODE_STRING UnicodeAddress;
577 NTSTATUS Status;
578 ULONG ResultLength;
579 UCHAR buf[1024];
580 PKEY_VALUE_PARTIAL_INFORMATION Information = (PKEY_VALUE_PARTIAL_INFORMATION)buf;
581 ANSI_STRING AnsiAddress;
582 ULONG AnsiLen;
583
584 RtlInitUnicodeString(&ValueName, RegistryValue);
585 Status =
586 ZwQueryValueKey(RegHandle,
587 &ValueName,
588 KeyValuePartialInformation,
589 Information,
590 sizeof(buf),
591 &ResultLength);
592
593 if (!NT_SUCCESS(Status))
594 return Status;
595 /* IP address is stored as a REG_MULTI_SZ - we only pay attention to the first one though */
596 TI_DbgPrint(MIN_TRACE, ("Information DataLength: 0x%x\n", Information->DataLength));
597
598 UnicodeAddress.Buffer = (PWCHAR)&Information->Data;
599 UnicodeAddress.Length = Information->DataLength;
600 UnicodeAddress.MaximumLength = Information->DataLength;
601
602 AnsiLen = RtlUnicodeStringToAnsiSize(&UnicodeAddress);
603 if(!AnsiLen)
604 return STATUS_NO_MEMORY;
605
606 AnsiAddress.Buffer = exAllocatePoolWithTag(PagedPool, AnsiLen, 0x01020304);
607 if(!AnsiAddress.Buffer)
608 return STATUS_NO_MEMORY;
609
610 AnsiAddress.Length = AnsiLen;
611 AnsiAddress.MaximumLength = AnsiLen;
612
613 Status = RtlUnicodeStringToAnsiString(&AnsiAddress, &UnicodeAddress, FALSE);
614 if (!NT_SUCCESS(Status)) {
615 exFreePool(AnsiAddress.Buffer);
616 return STATUS_UNSUCCESSFUL;
617 }
618
619 AnsiAddress.Buffer[AnsiAddress.Length] = 0;
620 *Address = AddrBuildIPv4(inet_addr(AnsiAddress.Buffer));
621 if (!Address) {
622 exFreePool(AnsiAddress.Buffer);
623 return STATUS_UNSUCCESSFUL;
624 }
625
626 return *Address ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
627 }
628
629 VOID BindAdapter(
630 PLAN_ADAPTER Adapter,
631 PNDIS_STRING RegistryPath)
632 /*
633 * FUNCTION: Binds a LAN adapter to IP layer
634 * ARGUMENTS:
635 * Adapter = Pointer to LAN_ADAPTER structure
636 * NOTES:
637 * We set the lookahead buffer size, set the packet filter and
638 * bind the adapter to IP layer
639 */
640 {
641 PIP_INTERFACE IF;
642 PIP_ADDRESS Address = 0;
643 PIP_ADDRESS Netmask = 0;
644 NDIS_STATUS NdisStatus;
645 LLIP_BIND_INFO BindInfo;
646 ULONG Lookahead = LOOKAHEAD_SIZE;
647 NTSTATUS Status;
648 HANDLE RegHandle = 0;
649
650 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
651
652 Adapter->State = LAN_STATE_OPENING;
653
654 NdisStatus = NDISCall(Adapter,
655 NdisRequestSetInformation,
656 OID_GEN_CURRENT_LOOKAHEAD,
657 &Lookahead,
658 sizeof(ULONG));
659 if (NdisStatus != NDIS_STATUS_SUCCESS) {
660 TI_DbgPrint(MID_TRACE, ("Could not set lookahead buffer size (0x%X).\n", NdisStatus));
661 return;
662 }
663
664 /* Bind the adapter to IP layer */
665 BindInfo.Context = Adapter;
666 BindInfo.HeaderSize = Adapter->HeaderSize;
667 BindInfo.MinFrameSize = Adapter->MinFrameSize;
668 BindInfo.MTU = Adapter->MTU;
669 BindInfo.Address = (PUCHAR)&Adapter->HWAddress;
670 BindInfo.AddressLength = Adapter->HWAddressLength;
671 BindInfo.Transmit = LANTransmit;
672
673 IF = IPCreateInterface(&BindInfo);
674
675 if (!IF) {
676 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
677 return;
678 }
679
680 /*
681 * Query per-adapter configuration from the registry
682 * In case anyone is curious: there *is* an Ndis configuration api
683 * for this sort of thing, but it doesn't really support things like
684 * REG_MULTI_SZ very well, and there is a note in the DDK that says that
685 * protocol drivers developed for win2k and above just use the native
686 * services (ZwOpenKey, etc).
687 */
688
689 Status = OpenRegistryKey( RegistryPath, &RegHandle );
690
691 if(NT_SUCCESS(Status))
692 Status = ReadIPAddressFromRegistry( RegHandle, L"IPAddress",
693 &Address );
694 if(NT_SUCCESS(Status))
695 Status = ReadIPAddressFromRegistry( RegHandle, L"SubnetMask",
696 &Netmask );
697
698 if(!NT_SUCCESS(Status) || !Address || !Netmask)
699 {
700 TI_DbgPrint(MIN_TRACE, ("Unable to open protocol-specific registry key: 0x%x\n", Status));
701
702 /* XXX how do we proceed? No ip address, no parameters... do we guess? */
703 if(RegHandle)
704 ZwClose(RegHandle);
705 if(Address) Address->Free(Address);
706 if(Netmask) Netmask->Free(Netmask);
707 IPDestroyInterface(IF);
708 return;
709 }
710
711 TI_DbgPrint
712 (MID_TRACE,
713 ("--> Our IP address on this interface: '%s'\n",
714 A2S(Address)));
715
716 TI_DbgPrint
717 (MID_TRACE,
718 ("--> Our net mask on this interface: '%s'\n",
719 A2S(Netmask)));
720
721 /* Create a net table entry for this interface */
722 if (!IPCreateNTE(IF, Address, AddrCountPrefixBits(Netmask))) {
723 Netmask->Free(Netmask);
724 TI_DbgPrint(MIN_TRACE, ("IPCreateNTE() failed.\n"));
725 IPDestroyInterface(IF);
726 return;
727 }
728
729 Netmask->Free(Netmask);
730
731 /* Reference the interface for the NTE. The reference
732 for the address is just passed on to the NTE */
733 ReferenceObject(IF);
734
735 /* Register interface with IP layer */
736 IPRegisterInterface(IF);
737
738 /* Set packet filter so we can send and receive packets */
739 NdisStatus = NDISCall(Adapter,
740 NdisRequestSetInformation,
741 OID_GEN_CURRENT_PACKET_FILTER,
742 &Adapter->PacketFilter,
743 sizeof(UINT));
744 if (NdisStatus != NDIS_STATUS_SUCCESS) {
745 TI_DbgPrint(MID_TRACE, ("Could not set packet filter (0x%X).\n", NdisStatus));
746 IPDestroyInterface(IF);
747 return;
748 }
749
750 Adapter->Context = IF;
751 Adapter->State = LAN_STATE_STARTED;
752 }
753
754
755 VOID UnbindAdapter(
756 PLAN_ADAPTER Adapter)
757 /*
758 * FUNCTION: Unbinds a LAN adapter from IP layer
759 * ARGUMENTS:
760 * Adapter = Pointer to LAN_ADAPTER structure
761 */
762 {
763 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
764
765 if (Adapter->State == LAN_STATE_STARTED) {
766 PIP_INTERFACE IF = Adapter->Context;
767
768 IPUnregisterInterface(IF);
769
770 IPDestroyInterface(IF);
771 }
772 }
773
774
775 NDIS_STATUS LANRegisterAdapter(
776 PNDIS_STRING AdapterName,
777 PNDIS_STRING RegistryPath)
778 /*
779 * FUNCTION: Registers protocol with an NDIS adapter
780 * ARGUMENTS:
781 * AdapterName = Pointer to string with name of adapter to register
782 * Adapter = Address of pointer to a LAN_ADAPTER structure
783 * RETURNS:
784 * Status of operation
785 */
786 {
787 PLAN_ADAPTER IF;
788 NDIS_STATUS NdisStatus;
789 NDIS_STATUS OpenStatus;
790 UINT MediaIndex;
791 NDIS_MEDIUM MediaArray[MAX_MEDIA];
792 UINT AddressOID;
793 UINT Speed;
794
795 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
796
797 IF = exAllocatePool(NonPagedPool, sizeof(LAN_ADAPTER));
798 if (!IF) {
799 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
800 return NDIS_STATUS_RESOURCES;
801 }
802
803 RtlZeroMemory(IF, sizeof(LAN_ADAPTER));
804
805 /* Put adapter in stopped state */
806 IF->State = LAN_STATE_STOPPED;
807
808 /* Initialize protecting spin lock */
809 KeInitializeSpinLock(&IF->Lock);
810
811 KeInitializeEvent(&IF->Event, SynchronizationEvent, FALSE);
812
813 /* Initialize array with media IDs we support */
814 MediaArray[MEDIA_ETH] = NdisMedium802_3;
815
816 TI_DbgPrint(DEBUG_DATALINK,("opening adapter %wZ\n", AdapterName));
817 /* Open the adapter. */
818 NdisOpenAdapter(&NdisStatus,
819 &OpenStatus,
820 &IF->NdisHandle,
821 &MediaIndex,
822 MediaArray,
823 MAX_MEDIA,
824 NdisProtocolHandle,
825 IF,
826 AdapterName,
827 0,
828 NULL);
829
830 /* Wait until the adapter is opened */
831 if (NdisStatus == NDIS_STATUS_PENDING)
832 KeWaitForSingleObject(&IF->Event, UserRequest, KernelMode, FALSE, NULL);
833 else if (NdisStatus != NDIS_STATUS_SUCCESS) {
834 exFreePool(IF);
835 return NdisStatus;
836 }
837
838 IF->Media = MediaArray[MediaIndex];
839
840 /* Fill LAN_ADAPTER structure with some adapter specific information */
841 switch (IF->Media) {
842 case NdisMedium802_3:
843 IF->HWAddressLength = IEEE_802_ADDR_LENGTH;
844 IF->BCastMask = BCAST_ETH_MASK;
845 IF->BCastCheck = BCAST_ETH_CHECK;
846 IF->BCastOffset = BCAST_ETH_OFFSET;
847 IF->HeaderSize = sizeof(ETH_HEADER);
848 IF->MinFrameSize = 60;
849 AddressOID = OID_802_3_CURRENT_ADDRESS;
850 IF->PacketFilter =
851 NDIS_PACKET_TYPE_BROADCAST |
852 NDIS_PACKET_TYPE_DIRECTED |
853 NDIS_PACKET_TYPE_MULTICAST;
854 break;
855
856 default:
857 /* Unsupported media */
858 TI_DbgPrint(MIN_TRACE, ("Unsupported media.\n"));
859 exFreePool(IF);
860 return NDIS_STATUS_NOT_SUPPORTED;
861 }
862
863 /* Get maximum frame size */
864 NdisStatus = NDISCall(IF,
865 NdisRequestQueryInformation,
866 OID_GEN_MAXIMUM_FRAME_SIZE,
867 &IF->MTU,
868 sizeof(UINT));
869 if (NdisStatus != NDIS_STATUS_SUCCESS) {
870 exFreePool(IF);
871 return NdisStatus;
872 }
873
874 /* Get maximum packet size */
875 NdisStatus = NDISCall(IF,
876 NdisRequestQueryInformation,
877 OID_GEN_MAXIMUM_TOTAL_SIZE,
878 &IF->MaxPacketSize,
879 sizeof(UINT));
880 if (NdisStatus != NDIS_STATUS_SUCCESS) {
881 TI_DbgPrint(MIN_TRACE, ("Query for maximum packet size failed.\n"));
882 exFreePool(IF);
883 return NdisStatus;
884 }
885
886 /* Get maximum number of packets we can pass to NdisSend(Packets) at one time */
887 NdisStatus = NDISCall(IF,
888 NdisRequestQueryInformation,
889 OID_GEN_MAXIMUM_SEND_PACKETS,
890 &IF->MaxSendPackets,
891 sizeof(UINT));
892 if (NdisStatus != NDIS_STATUS_SUCCESS)
893 /* Legacy NIC drivers may not support this query, if it fails we
894 assume it can send at least one packet per call to NdisSend(Packets) */
895 IF->MaxSendPackets = 1;
896
897 /* Get current hardware address */
898 NdisStatus = NDISCall(IF,
899 NdisRequestQueryInformation,
900 AddressOID,
901 &IF->HWAddress,
902 IF->HWAddressLength);
903 if (NdisStatus != NDIS_STATUS_SUCCESS) {
904 TI_DbgPrint(MIN_TRACE, ("Query for current hardware address failed.\n"));
905 exFreePool(IF);
906 return NdisStatus;
907 }
908
909 /* Get maximum link speed */
910 NdisStatus = NDISCall(IF,
911 NdisRequestQueryInformation,
912 OID_GEN_LINK_SPEED,
913 &Speed,
914 sizeof(UINT));
915 if (NdisStatus != NDIS_STATUS_SUCCESS) {
916 TI_DbgPrint(MIN_TRACE, ("Query for maximum link speed failed.\n"));
917 exFreePool(IF);
918 return NdisStatus;
919 }
920
921 /* Convert returned link speed to bps (it is in 100bps increments) */
922 IF->Speed = Speed * 100L;
923
924 /* Add adapter to the adapter list */
925 ExInterlockedInsertTailList(&AdapterListHead,
926 &IF->ListEntry,
927 &AdapterListLock);
928
929 /* Bind adapter to IP layer */
930 BindAdapter(IF, RegistryPath);
931
932 TI_DbgPrint(DEBUG_DATALINK, ("Leaving.\n"));
933
934 return NDIS_STATUS_SUCCESS;
935 }
936
937
938 NDIS_STATUS LANUnregisterAdapter(
939 PLAN_ADAPTER Adapter)
940 /*
941 * FUNCTION: Unregisters protocol with NDIS adapter
942 * ARGUMENTS:
943 * Adapter = Pointer to a LAN_ADAPTER structure
944 * RETURNS:
945 * Status of operation
946 */
947 {
948 KIRQL OldIrql;
949 NDIS_HANDLE NdisHandle;
950 NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS;
951
952 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
953
954 /* Unlink the adapter from the list */
955 RemoveEntryList(&Adapter->ListEntry);
956
957 /* Unbind adapter from IP layer */
958 UnbindAdapter(Adapter);
959
960 KeAcquireSpinLock(&Adapter->Lock, &OldIrql);
961 NdisHandle = Adapter->NdisHandle;
962 if (NdisHandle) {
963 Adapter->NdisHandle = NULL;
964 KeReleaseSpinLock(&Adapter->Lock, OldIrql);
965
966 NdisCloseAdapter(&NdisStatus, NdisHandle);
967 if (NdisStatus == NDIS_STATUS_PENDING) {
968 KeWaitForSingleObject(&Adapter->Event,
969 UserRequest,
970 KernelMode,
971 FALSE,
972 NULL);
973 NdisStatus = Adapter->NdisStatus;
974 }
975 } else
976 KeReleaseSpinLock(&Adapter->Lock, OldIrql);
977
978 FreeAdapter(Adapter);
979
980 return NDIS_STATUS_SUCCESS;
981 }
982
983
984 NTSTATUS LANRegisterProtocol(
985 PNDIS_STRING Name)
986 /*
987 * FUNCTION: Registers this protocol driver with NDIS
988 * ARGUMENTS:
989 * Name = Name of this protocol driver
990 * RETURNS:
991 * Status of operation
992 */
993 {
994 NDIS_STATUS NdisStatus;
995 NDIS_PROTOCOL_CHARACTERISTICS ProtChars;
996
997 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
998
999 InitializeListHead(&AdapterListHead);
1000 KeInitializeSpinLock(&AdapterListLock);
1001
1002 /* Set up protocol characteristics */
1003 RtlZeroMemory(&ProtChars, sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
1004 ProtChars.MajorNdisVersion = NDIS_VERSION_MAJOR;
1005 ProtChars.MinorNdisVersion = NDIS_VERSION_MINOR;
1006 ProtChars.Name.Length = Name->Length;
1007 ProtChars.Name.Buffer = Name->Buffer;
1008 ProtChars.Name.MaximumLength = Name->MaximumLength;
1009 ProtChars.OpenAdapterCompleteHandler = ProtocolOpenAdapterComplete;
1010 ProtChars.CloseAdapterCompleteHandler = ProtocolCloseAdapterComplete;
1011 ProtChars.ResetCompleteHandler = ProtocolResetComplete;
1012 ProtChars.RequestCompleteHandler = ProtocolRequestComplete;
1013 ProtChars.SendCompleteHandler = ProtocolSendComplete;
1014 ProtChars.TransferDataCompleteHandler = ProtocolTransferDataComplete;
1015 ProtChars.ReceiveHandler = ProtocolReceive;
1016 ProtChars.ReceiveCompleteHandler = ProtocolReceiveComplete;
1017 ProtChars.StatusHandler = ProtocolStatus;
1018 ProtChars.StatusCompleteHandler = ProtocolStatusComplete;
1019 ProtChars.BindAdapterHandler = ProtocolBindAdapter;
1020
1021 /* Try to register protocol */
1022 NdisRegisterProtocol(&NdisStatus,
1023 &NdisProtocolHandle,
1024 &ProtChars,
1025 sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
1026 if (NdisStatus != NDIS_STATUS_SUCCESS)
1027 {
1028 TI_DbgPrint(MID_TRACE, ("NdisRegisterProtocol failed, status 0x%x\n", NdisStatus));
1029 return (NTSTATUS)NdisStatus;
1030 }
1031
1032 ProtocolRegistered = TRUE;
1033
1034 return STATUS_SUCCESS;
1035 }
1036
1037
1038 VOID LANUnregisterProtocol(
1039 VOID)
1040 /*
1041 * FUNCTION: Unregisters this protocol driver with NDIS
1042 * NOTES: Does not care wether we are already registered
1043 */
1044 {
1045 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
1046
1047 if (ProtocolRegistered) {
1048 NDIS_STATUS NdisStatus;
1049 PLIST_ENTRY CurrentEntry;
1050 PLIST_ENTRY NextEntry;
1051 PLAN_ADAPTER Current;
1052 KIRQL OldIrql;
1053
1054 KeAcquireSpinLock(&AdapterListLock, &OldIrql);
1055
1056 /* Search the list and remove every adapter we find */
1057 CurrentEntry = AdapterListHead.Flink;
1058 while (CurrentEntry != &AdapterListHead) {
1059 NextEntry = CurrentEntry->Flink;
1060 Current = CONTAINING_RECORD(CurrentEntry, LAN_ADAPTER, ListEntry);
1061 /* Unregister it */
1062 LANUnregisterAdapter(Current);
1063 CurrentEntry = NextEntry;
1064 }
1065
1066 KeReleaseSpinLock(&AdapterListLock, OldIrql);
1067
1068 NdisDeregisterProtocol(&NdisStatus, NdisProtocolHandle);
1069 ProtocolRegistered = FALSE;
1070 }
1071 }
1072
1073 VOID LANStartup() {
1074 InitializeListHead( &LanWorkList );
1075 ExInitializeWorkItem( &LanWorkItem, LanReceiveWorker, NULL );
1076 }
1077
1078 VOID LANShutdown() {
1079 KIRQL OldIrql;
1080 PLAN_WQ_ITEM WorkItem;
1081 PLIST_ENTRY ListEntry;
1082
1083 KeAcquireSpinLock( &LanWorkLock, &OldIrql );
1084 while( !IsListEmpty( &LanWorkList ) ) {
1085 ListEntry = RemoveHeadList( &LanWorkList );
1086 WorkItem = CONTAINING_RECORD(ListEntry, LAN_WQ_ITEM, ListEntry);
1087 FreeNdisPacket( WorkItem->Packet );
1088 ExFreePool( WorkItem );
1089 }
1090 KeReleaseSpinLock( &LanWorkLock, OldIrql );
1091 }
1092
1093 /* EOF */