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