Added networking code from Casper Hornstrup
[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 #include <tcpip.h>
11 #include <lan.h>
12 #include <address.h>
13 #include <routines.h>
14 #include <transmit.h>
15 #include <receive.h>
16 #include <arp.h>
17
18
19 NDIS_HANDLE NdisProtocolHandle = (NDIS_HANDLE)NULL;
20 BOOLEAN ProtocolRegistered = FALSE;
21 PLAN_ADAPTER Adapters = NULL;
22
23
24 NDIS_STATUS NDISCall(
25 PLAN_ADAPTER Adapter,
26 NDIS_REQUEST_TYPE Type,
27 NDIS_OID OID,
28 PVOID Buffer,
29 UINT Length)
30 /*
31 * FUNCTION: Send a request to NDIS
32 * ARGUMENTS:
33 * Adapter = Pointer to a LAN_ADAPTER structure
34 * Type = Type of request (Set or Query)
35 * OID = Value to be set/queried for
36 * Buffer = Pointer to a buffer to use
37 * Length = Number of bytes in Buffer
38 * RETURNS:
39 * Status of operation
40 */
41 {
42 NDIS_REQUEST Request;
43 NDIS_STATUS NdisStatus;
44
45 Request.RequestType = Type;
46 if (Type == NdisRequestSetInformation) {
47 Request.DATA.SET_INFORMATION.Oid = OID;
48 Request.DATA.SET_INFORMATION.InformationBuffer = Buffer;
49 Request.DATA.SET_INFORMATION.InformationBufferLength = Length;
50 } else {
51 Request.DATA.QUERY_INFORMATION.Oid = OID;
52 Request.DATA.QUERY_INFORMATION.InformationBuffer = Buffer;
53 Request.DATA.QUERY_INFORMATION.InformationBufferLength = Length;
54 }
55
56 if (Adapter->State != LAN_STATE_RESETTING) {
57 NdisRequest(&NdisStatus, Adapter->NdisHandle, &Request);
58 } else
59 NdisStatus = NDIS_STATUS_NOT_ACCEPTED;
60
61 /* Wait for NDIS to complete the request */
62 if (NdisStatus == NDIS_STATUS_PENDING) {
63 KeWaitForSingleObject(&Adapter->Event, UserRequest, KernelMode, FALSE, NULL);
64 NdisStatus = Adapter->NdisStatus;
65 }
66
67 return NdisStatus;
68 }
69
70
71 PNDIS_PACKET AllocateTDPacket(
72 PLAN_ADAPTER Adapter)
73 /*
74 * FUNCTION: Allocates an NDIS packet for NdisTransferData
75 * ARGUMENTS:
76 * Adapter = Pointer to LAN_ADAPTER structure
77 * RETURNS:
78 * Pointer to NDIS packet or NULL if there was not enough free
79 * non-paged memory
80 */
81 {
82 NDIS_STATUS NdisStatus;
83 PNDIS_PACKET NdisPacket;
84 PNDIS_BUFFER Buffer;
85 PVOID Data;
86
87 NdisAllocatePacket(&NdisStatus, &NdisPacket, GlobalPacketPool);
88 if (NdisStatus != NDIS_STATUS_SUCCESS)
89 return NULL;
90
91 Data = ExAllocatePool(NonPagedPool, Adapter->MTU);
92 if (!Data) {
93 NdisFreePacket(NdisPacket);
94 return NULL;
95 }
96
97 NdisAllocateBuffer(&NdisStatus, &Buffer, GlobalBufferPool, Data, Adapter->MTU);
98 if (NdisStatus != NDIS_STATUS_SUCCESS) {
99 NdisFreePacket(NdisPacket);
100 ExFreePool(Data);
101 return NULL;
102 }
103
104 NdisChainBufferAtFront(NdisPacket, Buffer);
105
106 PC(NdisPacket)->Context = NULL; /* End of list */
107
108 return NdisPacket;
109 }
110
111
112 VOID FreeTDPackets(
113 PLAN_ADAPTER Adapter)
114 /*
115 * FUNCTION: Frees transfer data packets
116 * ARGUMENTS:
117 * Adapter = Pointer to LAN_ADAPTER structure
118 */
119 {
120 PNDIS_PACKET NdisPacket, Next;
121
122 /* Release transfer data packets */
123 NdisPacket = Adapter->TDPackets;
124 while (NdisPacket) {
125 Next = PC(NdisPacket)->Context;
126 FreeNdisPacket(NdisPacket);
127 NdisPacket = Next;
128 }
129 Adapter->TDPackets = NULL;
130 }
131
132
133 VOID FreeAdapter(
134 PLAN_ADAPTER Adapter)
135 /*
136 * FUNCTION: Frees memory for a LAN_ADAPTER structure
137 * ARGUMENTS:
138 * Adapter = Pointer to LAN_ADAPTER structure to free
139 */
140 {
141 FreeTDPackets(Adapter);
142 ExFreePool(Adapter);
143 }
144
145
146 VOID ProtocolOpenAdapterComplete(
147 NDIS_HANDLE BindingContext,
148 NDIS_STATUS Status,
149 NDIS_STATUS OpenErrorStatus)
150 /*
151 * FUNCTION: Called by NDIS to complete opening of an adapter
152 * ARGUMENTS:
153 * BindingContext = Pointer to a device context (LAN_ADAPTER)
154 * Status = Status of the operation
155 * OpenErrorStatus = Additional status information
156 */
157 {
158 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
159
160 TI_DbgPrint(MID_TRACE, ("Called.\n"));
161
162 KeSetEvent(&Adapter->Event, 0, FALSE);
163 }
164
165
166 VOID ProtocolCloseAdapterComplete(
167 NDIS_HANDLE BindingContext,
168 NDIS_STATUS Status)
169 /*
170 * FUNCTION: Called by NDIS to complete closing an adapter
171 * ARGUMENTS:
172 * BindingContext = Pointer to a device context (LAN_ADAPTER)
173 * Status = Status of the operation
174 */
175 {
176 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
177
178 TI_DbgPrint(MID_TRACE, ("Called.\n"));
179
180 Adapter->NdisStatus = Status;
181
182 KeSetEvent(&Adapter->Event, 0, FALSE);
183 }
184
185
186 VOID ProtocolResetComplete(
187 NDIS_HANDLE BindingContext,
188 NDIS_STATUS Status)
189 /*
190 * FUNCTION: Called by NDIS to complete resetting an adapter
191 * ARGUMENTS:
192 * BindingContext = Pointer to a device context (LAN_ADAPTER)
193 * Status = Status of the operation
194 */
195 {
196 TI_DbgPrint(MID_TRACE, ("Called.\n"));
197 }
198
199
200 VOID ProtocolRequestComplete(
201 NDIS_HANDLE BindingContext,
202 PNDIS_REQUEST NdisRequest,
203 NDIS_STATUS Status)
204 /*
205 * FUNCTION: Called by NDIS to complete a request
206 * ARGUMENTS:
207 * BindingContext = Pointer to a device context (LAN_ADAPTER)
208 * NdisRequest = Pointer to an object describing the request
209 * Status = Status of the operation
210 */
211 {
212 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
213
214 /* Save status of request and signal an event */
215 Adapter->NdisStatus = Status;
216
217 KeSetEvent(&Adapter->Event, 0, FALSE);
218 }
219
220
221 VOID ProtocolSendComplete(
222 NDIS_HANDLE BindingContext,
223 PNDIS_PACKET Packet,
224 NDIS_STATUS Status)
225 /*
226 * FUNCTION: Called by NDIS to complete sending process
227 * ARGUMENTS:
228 * BindingContext = Pointer to a device context (LAN_ADAPTER)
229 * Packet = Pointer to a packet descriptor
230 * Status = Status of the operation
231 */
232 {
233 PLAN_ADAPTER Adapter = BindingContext;
234
235 TI_DbgPrint(MAX_TRACE, ("Called.\n"));
236
237 AdjustPacket(Packet, Adapter->HeaderSize, PC(Packet)->DLOffset);
238
239 (*PC(Packet)->DLComplete)(Adapter->Context, Packet, Status);
240 }
241
242
243 VOID ProtocolTransferDataComplete(
244 NDIS_HANDLE BindingContext,
245 PNDIS_PACKET Packet,
246 NDIS_STATUS Status,
247 UINT BytesTransferred)
248 /*
249 * FUNCTION: Called by NDIS to complete reception of data
250 * ARGUMENTS:
251 * BindingContext = Pointer to a device context (LAN_ADAPTER)
252 * Packet = Pointer to a packet descriptor
253 * Status = Status of the operation
254 * BytesTransferred = Number of bytes transferred
255 * NOTES:
256 * If the packet was successfully received, determine the protocol
257 * type and pass it to the correct receive handler
258 */
259 {
260 UINT PacketType;
261 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
262
263 if (Status == NDIS_STATUS_SUCCESS) {
264 PNDIS_BUFFER NdisBuffer;
265 IP_PACKET IPPacket;
266
267 NdisGetFirstBufferFromPacket(
268 Packet, &NdisBuffer, &IPPacket.Header,
269 &IPPacket.ContigSize, &IPPacket.TotalSize);
270
271 /* Determine which upper layer protocol that should receive
272 this packet and pass it to the correct receive handler */
273 PacketType = ((PETH_HEADER)IPPacket.Header)->EType;
274 switch (PacketType) {
275 case ETYPE_IPv4:
276 case ETYPE_IPv6:
277 IPReceive(Adapter->Context, &IPPacket);
278 break;
279 case ETYPE_ARP:
280 ARPReceive(Adapter->Context, &IPPacket);
281 default:
282 break;
283 }
284 }
285
286 /* Release the packet descriptor */
287 KeAcquireSpinLockAtDpcLevel(&Adapter->Lock);
288
289 PC(Packet)->Context = Adapter->TDPackets;
290 Adapter->TDPackets = Packet;
291
292 KeReleaseSpinLockFromDpcLevel(&Adapter->Lock);
293 }
294
295
296 NDIS_STATUS ProtocolReceive(
297 NDIS_HANDLE BindingContext,
298 NDIS_HANDLE MacReceiveContext,
299 PVOID HeaderBuffer,
300 UINT HeaderBufferSize,
301 PVOID LookaheadBuffer,
302 UINT LookaheadBufferSize,
303 UINT PacketSize)
304 /*
305 * FUNCTION: Called by NDIS when a packet has been received on the physical link
306 * ARGUMENTS:
307 * BindingContext = Pointer to a device context (LAN_ADAPTER)
308 * MacReceiveContext = Handle used by underlying NIC driver
309 * HeaderBuffer = Pointer to a buffer containing the packet header
310 * HeaderBufferSize = Number of bytes in HeaderBuffer
311 * LookaheadBuffer = Pointer to a buffer containing buffered packet data
312 * LookaheadBufferSize = Size of LookaheadBuffer. May be less than asked for
313 * PacketSize = Overall size of the packet (not including header)
314 * RETURNS:
315 * Status of operation
316 */
317 {
318 USHORT EType;
319 UINT PacketType;
320 IP_PACKET IPPacket;
321 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
322 PETH_HEADER EHeader = (PETH_HEADER)HeaderBuffer;
323
324 TI_DbgPrint(MAX_TRACE, ("Called.\n"));
325
326 if ((Adapter->State != LAN_STATE_STARTED) ||
327 HeaderBufferSize < Adapter->HeaderSize)
328 /* Adapter is not started or the header was too small */
329 return NDIS_STATUS_NOT_ACCEPTED;
330
331 if (Adapter->Media == NdisMedium802_3) {
332 /* Ethernet and IEEE 802.3 frames can be destinguished by
333 looking at the IEEE 802.3 length field. This field is
334 less than or equal to 1500 for a valid IEEE 802.3 frame
335 and larger than 1500 is it's a valid Ether-Type value.
336 See RFC 1122, section 2.3.3 for more information */
337 if (((EType = EHeader->EType) != ETYPE_IPv4) && (EType != ETYPE_ARP))
338 return NDIS_STATUS_NOT_ACCEPTED;
339 /* We use Ether-Type constants to destinguish packets */
340 PacketType = EType;
341 } else
342 /* FIXME: Support other medias */
343 return NDIS_STATUS_NOT_ACCEPTED;
344
345 if (LookaheadBufferSize < PacketSize) {
346 NDIS_STATUS NdisStatus;
347 PNDIS_PACKET NdisPacket;
348 UINT BytesTransferred;
349
350 /* Get transfer data packet */
351
352 KeAcquireSpinLockAtDpcLevel(&Adapter->Lock);
353
354 NdisPacket = Adapter->TDPackets;
355 if (NdisPacket == (PNDIS_PACKET)NULL) {
356 /* We don't have a free packet descriptor. Drop the packet */
357 KeReleaseSpinLockFromDpcLevel(&Adapter->Lock);
358 return NDIS_STATUS_SUCCESS;
359 }
360 Adapter->TDPackets = PC(NdisPacket)->Context;
361
362 KeReleaseSpinLockFromDpcLevel(&Adapter->Lock);
363
364 /* Get the data */
365 NdisTransferData(&NdisStatus, Adapter->NdisHandle,
366 MacReceiveContext, 0, PacketSize,
367 NdisPacket, &BytesTransferred);
368 if (NdisStatus != NDIS_STATUS_PENDING)
369 ProtocolTransferDataComplete(BindingContext,
370 NdisPacket, NdisStatus, BytesTransferred);
371
372 return NDIS_STATUS_SUCCESS;
373 }
374
375 /* We got all the data in the lookahead buffer */
376 RtlZeroMemory(&IPPacket, sizeof(IPPacket));
377 IPPacket.Header = LookaheadBuffer;
378 IPPacket.TotalSize = PacketSize;
379
380 switch (PacketType) {
381 case ETYPE_IPv4:
382 case ETYPE_IPv6:
383 IPReceive(Adapter->Context, &IPPacket);
384 break;
385 case ETYPE_ARP:
386 ARPReceive(Adapter->Context, &IPPacket);
387 break;
388 default:
389 break;
390 }
391
392 return NDIS_STATUS_SUCCESS;
393 }
394
395
396 VOID ProtocolReceiveComplete(
397 NDIS_HANDLE BindingContext)
398 /*
399 * FUNCTION: Called by NDIS when we're done receiving data
400 * ARGUMENTS:
401 * BindingContext = Pointer to a device context (LAN_ADAPTER)
402 */
403 {
404 TI_DbgPrint(MID_TRACE, ("Called.\n"));
405 }
406
407
408 VOID ProtocolStatus(
409 NDIS_HANDLE BindingContext,
410 NDIS_STATUS GenerelStatus,
411 PVOID StatusBuffer,
412 UINT StatusBufferSize)
413 /*
414 * FUNCTION: Called by NDIS when the underlying driver has changed state
415 * ARGUMENTS:
416 * BindingContext = Pointer to a device context (LAN_ADAPTER)
417 * GenerelStatus = A generel status code
418 * StatusBuffer = Pointer to a buffer with medium-specific data
419 * StatusBufferSize = Number of bytes in StatusBuffer
420 */
421 {
422 TI_DbgPrint(MID_TRACE, ("Called.\n"));
423 }
424
425
426 VOID ProtocolStatusComplete(
427 NDIS_HANDLE NdisBindingContext)
428 /*
429 * FUNCTION: Called by NDIS when a status-change has occurred
430 * ARGUMENTS:
431 * BindingContext = Pointer to a device context (LAN_ADAPTER)
432 */
433 {
434 TI_DbgPrint(MID_TRACE, ("Called.\n"));
435 }
436
437
438 VOID LANTransmit(
439 PVOID Context,
440 PNDIS_PACKET NdisPacket,
441 UINT Offset,
442 PVOID LinkAddress,
443 USHORT Type)
444 /*
445 * FUNCTION: Transmits a packet
446 * ARGUMENTS:
447 * Context = Pointer to context information (LAN_ADAPTER)
448 * NdisPacket = Pointer to NDIS packet to send
449 * Offset = Offset in packet where data starts
450 * LinkAddress = Pointer to link address of destination (NULL = broadcast)
451 * Type = LAN protocol type (LAN_PROTO_*)
452 */
453 {
454 NDIS_STATUS NdisStatus;
455 PETH_HEADER EHeader;
456 PVOID Data;
457 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)Context;
458
459 TI_DbgPrint(MAX_TRACE, ("Called.\n"));
460
461 /* NDIS send routines don't have an offset argument so we
462 must offset the data in upper layers and adjust the
463 packet here. We save the offset in the packet context
464 area so it can be undone before we release the packet */
465 Data = AdjustPacket(NdisPacket, Offset, Adapter->HeaderSize);
466 PC(NdisPacket)->DLOffset = Offset;
467
468 if (Adapter->State == LAN_STATE_STARTED) {
469 switch (Adapter->Media) {
470 case NdisMedium802_3:
471 EHeader = (PETH_HEADER)Data;
472
473 if (LinkAddress)
474 /* Unicast address */
475 RtlCopyMemory(EHeader->DstAddr, LinkAddress, IEEE_802_ADDR_LENGTH);
476 else
477 /* Broadcast address */
478 RtlFillMemory(EHeader->DstAddr, IEEE_802_ADDR_LENGTH, 0xFF);
479
480 RtlCopyMemory(EHeader->SrcAddr, Adapter->HWAddress, IEEE_802_ADDR_LENGTH);
481
482 switch (Type) {
483 case LAN_PROTO_IPv4:
484 EHeader->EType = ETYPE_IPv4;
485 break;
486 case LAN_PROTO_ARP:
487 EHeader->EType = ETYPE_ARP;
488 break;
489 case LAN_PROTO_IPv6:
490 EHeader->EType = ETYPE_IPv6;
491 break;
492 default:
493 #if DBG
494 /* Should not happen */
495 TI_DbgPrint(MIN_TRACE, ("Unknown LAN protocol.\n"));
496
497 ProtocolSendComplete((NDIS_HANDLE)Context, NdisPacket, NDIS_STATUS_FAILURE);
498 #endif
499 return;
500 }
501 break;
502
503 default:
504 /* FIXME: Support other medias */
505 break;
506 }
507
508 NdisSend(&NdisStatus, Adapter->NdisHandle, NdisPacket);
509 if (NdisStatus != NDIS_STATUS_PENDING)
510 ProtocolSendComplete((NDIS_HANDLE)Context, NdisPacket, NdisStatus);
511 } else
512 ProtocolSendComplete((NDIS_HANDLE)Context, NdisPacket, NDIS_STATUS_CLOSED);
513 }
514
515
516 VOID BindAdapter(
517 PLAN_ADAPTER Adapter)
518 /*
519 * FUNCTION: Binds a LAN adapter to IP layer
520 * ARGUMENTS:
521 * Adapter = Pointer to LAN_ADAPTER structure
522 * NOTES:
523 * We set the lookahead buffer size, set the packet filter and
524 * bind the adapter to IP layer
525 */
526 {
527 INT i;
528 PIP_INTERFACE IF;
529 PIP_ADDRESS Address;
530 PNDIS_PACKET Packet;
531 NDIS_STATUS NdisStatus;
532 LLIP_BIND_INFO BindInfo;
533 ULONG Lookahead = LOOKAHEAD_SIZE;
534
535 TI_DbgPrint(MID_TRACE, ("Called.\n"));
536
537 Adapter->State = LAN_STATE_OPENING;
538
539 NdisStatus = NDISCall(Adapter, NdisRequestSetInformation,
540 OID_GEN_CURRENT_LOOKAHEAD, &Lookahead, sizeof(ULONG));
541 if (NdisStatus != NDIS_STATUS_SUCCESS) {
542 TI_DbgPrint(MID_TRACE, ("Could not set lookahead buffer size (0x%X).\n", NdisStatus));
543 return;
544 }
545
546 /* Allocate packets for NdisTransferData */
547 /* FIXME: How many should we allocate? */
548 Adapter->TDPackets = NULL;
549 for (i = 0; i < 2; i++) {
550 Packet = AllocateTDPacket(Adapter);
551 PC(Packet)->Context = Adapter->TDPackets;
552 Adapter->TDPackets = Packet;
553 if (!Packet) {
554 TI_DbgPrint(MID_TRACE, ("Could not allocate transfer data packet (out of resources).\n"));
555 FreeTDPackets(Adapter);
556 return;
557 }
558 }
559
560 /* Bind the adapter to IP layer */
561 BindInfo.Context = Adapter;
562 BindInfo.HeaderSize = Adapter->HeaderSize;
563 BindInfo.MinFrameSize = Adapter->MinFrameSize;
564 BindInfo.MTU = Adapter->MTU;
565 BindInfo.Address = (PUCHAR)&Adapter->HWAddress;
566 BindInfo.AddressLength = Adapter->HWAddressLength;
567 BindInfo.Transmit = LANTransmit;
568
569 IF = IPCreateInterface(&BindInfo);
570 if (!IF) {
571 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
572 FreeTDPackets(Adapter);
573 return;
574 }
575
576 /* FIXME: Get address from registry.
577 For now just use a private address, eg. 10.0.0.10 */
578 Address = AddrBuildIPv4(0x0A00000A);
579 if (!Address) {
580 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
581 FreeTDPackets(Adapter);
582 IPDestroyInterface(Adapter->Context);
583 return;
584 }
585 /* Create a net table entry for this interface */
586 if (!IPCreateNTE(IF, Address, 8)) {
587 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
588 FreeTDPackets(Adapter);
589 IPDestroyInterface(IF);
590 return;
591 }
592
593 /* Reference the interface for the NTE. The reference for
594 the address is just passed on to the NTE */
595 ReferenceObject(IF);
596
597 /* Register interface with IP layer */
598 IPRegisterInterface(IF);
599
600 /* Set packet filter so we can send and receive packets */
601 NdisStatus = NDISCall(Adapter, NdisRequestSetInformation,
602 OID_GEN_CURRENT_PACKET_FILTER, &Adapter->PacketFilter, sizeof(UINT));
603 if (NdisStatus != NDIS_STATUS_SUCCESS) {
604 TI_DbgPrint(MID_TRACE, ("Could not set packet filter (0x%X).\n", NdisStatus));
605 FreeTDPackets(Adapter);
606 IPDestroyInterface(IF);
607 return;
608 }
609
610 Adapter->Context = IF;
611
612 Adapter->State = LAN_STATE_STARTED;
613 }
614
615
616 VOID UnbindAdapter(
617 PLAN_ADAPTER Adapter)
618 /*
619 * FUNCTION: Unbinds a LAN adapter from IP layer
620 * ARGUMENTS:
621 * Adapter = Pointer to LAN_ADAPTER structure
622 */
623 {
624 TI_DbgPrint(MID_TRACE, ("Called.\n"));
625
626 if (Adapter->State == LAN_STATE_STARTED) {
627 PIP_INTERFACE IF = Adapter->Context;
628
629 IPUnregisterInterface(IF);
630
631 IPDestroyInterface(IF);
632
633 /* Free transfer data packets */
634 FreeTDPackets(Adapter);
635 }
636 }
637
638
639 NDIS_STATUS LANRegisterAdapter(
640 PNDIS_STRING AdapterName,
641 PLAN_ADAPTER *Adapter)
642 /*
643 * FUNCTION: Registers protocol with an NDIS adapter
644 * ARGUMENTS:
645 * AdapterName = Pointer to string with name of adapter to register
646 * Adapter = Address of pointer to a LAN_ADAPTER structure
647 * RETURNS:
648 * Status of operation
649 */
650 {
651 PLAN_ADAPTER IF;
652 NDIS_STATUS NdisStatus;
653 NDIS_STATUS OpenStatus;
654 UINT MediaIndex;
655 NDIS_MEDIUM MediaArray[MAX_MEDIA];
656 UINT AddressOID;
657 UINT Speed;
658
659 TI_DbgPrint(MAX_TRACE, ("Called.\n"));
660
661 IF = ExAllocatePool(NonPagedPool, sizeof(LAN_ADAPTER));
662 if (!IF)
663 return NDIS_STATUS_RESOURCES;
664
665 RtlZeroMemory(IF, sizeof(LAN_ADAPTER));
666
667 /* Put adapter in stopped state */
668 IF->State = LAN_STATE_STOPPED;
669
670 /* Initialize protecting spin lock */
671 KeInitializeSpinLock(&IF->Lock);
672
673 KeInitializeEvent(&IF->Event, SynchronizationEvent, FALSE);
674
675 /* Initialize array with media IDs we support */
676 MediaArray[MEDIA_ETH] = NdisMedium802_3;
677
678 /* Open the adapter. */
679 NdisOpenAdapter(&NdisStatus, &OpenStatus, &IF->NdisHandle, &MediaIndex,
680 MediaArray, MAX_MEDIA, NdisProtocolHandle, IF, AdapterName, 0, NULL);
681
682 /* Wait until the adapter is opened */
683 if (NdisStatus == NDIS_STATUS_PENDING)
684 KeWaitForSingleObject(&IF->Event, UserRequest, KernelMode, FALSE, NULL);
685 else if (NdisStatus != NDIS_STATUS_SUCCESS) {
686 ExFreePool(IF);
687 return NdisStatus;
688 }
689
690 IF->Media = MediaArray[MediaIndex];
691
692 /* Fill LAN_ADAPTER structure with some adapter specific information */
693 switch (IF->Media) {
694 case NdisMedium802_3:
695 IF->HWAddressLength = IEEE_802_ADDR_LENGTH;
696 IF->BCastMask = BCAST_ETH_MASK;
697 IF->BCastCheck = BCAST_ETH_CHECK;
698 IF->BCastOffset = BCAST_ETH_OFFSET;
699 IF->HeaderSize = sizeof(ETH_HEADER);
700 IF->MinFrameSize = 60;
701 AddressOID = OID_802_3_CURRENT_ADDRESS;
702 IF->PacketFilter =
703 NDIS_PACKET_TYPE_BROADCAST |
704 NDIS_PACKET_TYPE_DIRECTED |
705 NDIS_PACKET_TYPE_MULTICAST;
706 break;
707
708 default:
709 /* Unsupported media */
710 TI_DbgPrint(MIN_TRACE, ("Unsupported media.\n"));
711 ExFreePool(IF);
712 return NDIS_STATUS_NOT_SUPPORTED;
713 }
714
715 /* Get maximum frame size */
716 NdisStatus = NDISCall(IF, NdisRequestQueryInformation,
717 OID_GEN_MAXIMUM_FRAME_SIZE, &IF->MTU, sizeof(UINT));
718 if (NdisStatus != NDIS_STATUS_SUCCESS) {
719 ExFreePool(IF);
720 return NdisStatus;
721 }
722
723 /* Get maximum packet size */
724 NdisStatus = NDISCall(IF, NdisRequestQueryInformation,
725 OID_GEN_MAXIMUM_TOTAL_SIZE, &IF->MaxPacketSize, sizeof(UINT));
726 if (NdisStatus != NDIS_STATUS_SUCCESS) {
727 TI_DbgPrint(MIN_TRACE, ("Query for maximum packet size failed.\n"));
728 ExFreePool(IF);
729 return NdisStatus;
730 }
731
732 /* Get maximum number of packets we can pass to NdisSend(Packets) at one time */
733 NdisStatus = NDISCall(IF, NdisRequestQueryInformation,
734 OID_GEN_MAXIMUM_SEND_PACKETS, &IF->MaxSendPackets, sizeof(UINT));
735 if (NdisStatus != NDIS_STATUS_SUCCESS)
736 /* Legacy NIC drivers may not support this query, if it fails we
737 assume it can send at least one packet per call to NdisSend(Packets) */
738 IF->MaxSendPackets = 1;
739
740 /* Get current hardware address */
741 NdisStatus = NDISCall(IF, NdisRequestQueryInformation, AddressOID,
742 IF->HWAddress, IF->HWAddressLength);
743 if (NdisStatus != NDIS_STATUS_SUCCESS) {
744 TI_DbgPrint(MIN_TRACE, ("Query for current hardware address failed.\n"));
745 ExFreePool(IF);
746 return NdisStatus;
747 }
748
749 /* Get maximum link speed */
750 NdisStatus = NDISCall(IF, NdisRequestQueryInformation,
751 OID_GEN_LINK_SPEED, &Speed, sizeof(UINT));
752 if (NdisStatus != NDIS_STATUS_SUCCESS) {
753 TI_DbgPrint(MIN_TRACE, ("Query for maximum link speed failed.\n"));
754 ExFreePool(IF);
755 return NdisStatus;
756 }
757
758 /* Convert returned link speed to bps (it is in 100bps increments) */
759 IF->Speed = Speed * 100L;
760
761 *Adapter = IF;
762
763 /* Add adapter to the adapter list */
764 IF->Next = Adapters;
765 Adapters = IF;
766
767 /* Bind adapter to IP layer */
768 BindAdapter(IF);
769
770 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
771
772 return NDIS_STATUS_SUCCESS;
773 }
774
775
776 NDIS_STATUS LANUnregisterAdapter(
777 PLAN_ADAPTER Adapter)
778 /*
779 * FUNCTION: Unregisters protocol with NDIS adapter
780 * ARGUMENTS:
781 * Adapter = Pointer to a LAN_ADAPTER structure
782 * RETURNS:
783 * Status of operation
784 */
785 {
786 KIRQL OldIrql;
787 NDIS_HANDLE NdisHandle;
788 PLAN_ADAPTER IF, PrevIF;
789 BOOLEAN Found = FALSE;
790 NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS;
791
792 TI_DbgPrint(MAX_TRACE, ("Called.\n"));
793
794 /* Search the adapter list for the specified adapter and remove it */
795 IF = Adapters;
796 if (IF) {
797 if (Adapter != Adapters) {
798 PrevIF = IF;
799 while ((IF) && (!Found)) {
800 if (IF == Adapter) {
801 /* We've found the adapter, now remove it from the list */
802 PrevIF->Next = IF->Next;
803 Found = TRUE;
804 }
805 PrevIF = IF;
806 IF = IF->Next;
807 }
808 } else {
809 Adapters = NULL;
810 Found = TRUE;
811 }
812 }
813 if (!Found) {
814 TI_DbgPrint(MIN_TRACE, ("Leaving (adapter was not in list).\n"));
815 return NDIS_STATUS_ADAPTER_NOT_FOUND;
816 }
817
818 /* Unbind adapter from IP layer */
819 UnbindAdapter(Adapter);
820
821 KeAcquireSpinLock(&Adapter->Lock, &OldIrql);
822 NdisHandle = Adapter->NdisHandle;
823 if (NdisHandle) {
824 Adapter->NdisHandle = NULL;
825 KeReleaseSpinLock(&Adapter->Lock, OldIrql);
826
827 NdisCloseAdapter(&NdisStatus, NdisHandle);
828 if (NdisStatus == NDIS_STATUS_PENDING) {
829 KeWaitForSingleObject(&Adapter->Event,
830 UserRequest, KernelMode, FALSE, NULL);
831 NdisStatus = Adapter->NdisStatus;
832 }
833 } else
834 KeReleaseSpinLock(&Adapter->Lock, OldIrql);
835
836 FreeAdapter(Adapter);
837
838 return NDIS_STATUS_SUCCESS;
839 }
840
841
842 NTSTATUS LANRegisterProtocol(
843 PSTRING Name)
844 /*
845 * FUNCTION: Registers this protocol driver with NDIS
846 * ARGUMENTS:
847 * Name = Name of this protocol driver
848 * RETURNS:
849 * Status of operation
850 */
851 {
852 NDIS_STATUS NdisStatus;
853 NDIS_PROTOCOL_CHARACTERISTICS ProtChars;
854
855 /* Set up protocol characteristics */
856 RtlZeroMemory(&ProtChars, sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
857 ProtChars.MajorNdisVersion = NDIS_VERSION_MAJOR;
858 ProtChars.MinorNdisVersion = NDIS_VERSION_MINOR;
859 ProtChars.Name.Length = Name->Length;
860 ProtChars.Name.Buffer = (PVOID)Name->Buffer;
861 ProtChars.OpenAdapterCompleteHandler = ProtocolOpenAdapterComplete;
862 ProtChars.CloseAdapterCompleteHandler = ProtocolCloseAdapterComplete;
863 ProtChars.ResetCompleteHandler = ProtocolResetComplete;
864 ProtChars.RequestCompleteHandler = ProtocolRequestComplete;
865 ProtChars.SendCompleteHandler = ProtocolSendComplete;
866 ProtChars.TransferDataCompleteHandler = ProtocolTransferDataComplete;
867 ProtChars.ReceiveHandler = ProtocolReceive;
868 ProtChars.ReceiveCompleteHandler = ProtocolReceiveComplete;
869 ProtChars.StatusHandler = ProtocolStatus;
870 ProtChars.StatusCompleteHandler = ProtocolStatusComplete;
871
872 /* Try to register protocol */
873 NdisRegisterProtocol(
874 &NdisStatus, &NdisProtocolHandle, &ProtChars,
875 sizeof(NDIS_PROTOCOL_CHARACTERISTICS) + Name->Length);
876 if (NdisStatus != NDIS_STATUS_SUCCESS)
877 return (NTSTATUS)NdisStatus;
878
879 ProtocolRegistered = TRUE;
880
881 return STATUS_SUCCESS;
882 }
883
884
885 VOID LANUnregisterProtocol(
886 VOID)
887 /*
888 * FUNCTION: Unregisters this protocol driver with NDIS
889 * NOTES: Does not care wether we are already registered
890 */
891 {
892 if (ProtocolRegistered) {
893 NDIS_STATUS NdisStatus;
894
895 while (Adapters)
896 NdisStatus = LANUnregisterAdapter(Adapters);
897
898 NdisDeregisterProtocol(&NdisStatus, NdisProtocolHandle);
899 ProtocolRegistered = FALSE;
900 }
901 }
902
903 /* EOF */