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