merge 37282 from amd64-branch:
[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 exFreePool(Adapter);
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 TI_DbgPrint(DEBUG_DATALINK, ("Calling completion routine\n"));
235 ASSERT_KM_POINTER(Packet);
236 ASSERT_KM_POINTER(PC(Packet));
237 ASSERT_KM_POINTER(PC(Packet)->DLComplete);
238 (*PC(Packet)->DLComplete)( PC(Packet)->Context, Packet, Status);
239 TI_DbgPrint(DEBUG_DATALINK, ("Finished\n"));
240 }
241
242 VOID LanReceiveWorker( PVOID Context ) {
243 UINT PacketType;
244 PLAN_WQ_ITEM WorkItem = (PLAN_WQ_ITEM)Context;
245 PNDIS_PACKET Packet;
246 PLAN_ADAPTER Adapter;
247 UINT BytesTransferred;
248 PNDIS_BUFFER NdisBuffer;
249 IP_PACKET IPPacket;
250
251 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
252
253 Packet = WorkItem->Packet;
254 Adapter = WorkItem->Adapter;
255 BytesTransferred = WorkItem->BytesTransferred;
256
257 IPInitializePacket(&IPPacket, 0);
258
259 IPPacket.NdisPacket = Packet;
260
261 NdisGetFirstBufferFromPacket(Packet,
262 &NdisBuffer,
263 &IPPacket.Header,
264 &IPPacket.ContigSize,
265 &IPPacket.TotalSize);
266
267 IPPacket.ContigSize = IPPacket.TotalSize = BytesTransferred;
268 /* Determine which upper layer protocol that should receive
269 this packet and pass it to the correct receive handler */
270
271 TI_DbgPrint(MID_TRACE,
272 ("ContigSize: %d, TotalSize: %d, BytesTransferred: %d\n",
273 IPPacket.ContigSize, IPPacket.TotalSize,
274 BytesTransferred));
275
276 PacketType = PC(IPPacket.NdisPacket)->PacketType;
277 IPPacket.Position = 0;
278
279 TI_DbgPrint
280 (DEBUG_DATALINK,
281 ("Ether Type = %x ContigSize = %d Total = %d\n",
282 PacketType, IPPacket.ContigSize, IPPacket.TotalSize));
283
284 switch (PacketType) {
285 case ETYPE_IPv4:
286 case ETYPE_IPv6:
287 TI_DbgPrint(MID_TRACE,("Received IP Packet\n"));
288 IPReceive(Adapter->Context, &IPPacket);
289 break;
290 case ETYPE_ARP:
291 TI_DbgPrint(MID_TRACE,("Received ARP Packet\n"));
292 ARPReceive(Adapter->Context, &IPPacket);
293 default:
294 IPPacket.Free(&IPPacket);
295 break;
296 }
297
298 FreeNdisPacket( Packet );
299 }
300
301 VOID LanSubmitReceiveWork(
302 NDIS_HANDLE BindingContext,
303 PNDIS_PACKET Packet,
304 NDIS_STATUS Status,
305 UINT BytesTransferred) {
306 LAN_WQ_ITEM WQItem;
307 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
308
309 TI_DbgPrint(DEBUG_DATALINK,("called\n"));
310
311 WQItem.Packet = Packet;
312 WQItem.Adapter = Adapter;
313 WQItem.BytesTransferred = BytesTransferred;
314
315 if( !ChewCreate
316 ( NULL, sizeof(LAN_WQ_ITEM), LanReceiveWorker, &WQItem ) )
317 ASSERT(0);
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 + HeaderBufferSize );
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
518 VOID NTAPI ProtocolStatusComplete(
519 NDIS_HANDLE NdisBindingContext)
520 /*
521 * FUNCTION: Called by NDIS when a status-change has occurred
522 * ARGUMENTS:
523 * BindingContext = Pointer to a device context (LAN_ADAPTER)
524 */
525 {
526 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
527 }
528
529 VOID NTAPI ProtocolBindAdapter(
530 OUT PNDIS_STATUS Status,
531 IN NDIS_HANDLE BindContext,
532 IN PNDIS_STRING DeviceName,
533 IN PVOID SystemSpecific1,
534 IN PVOID SystemSpecific2)
535 /*
536 * FUNCTION: Called by NDIS during NdisRegisterProtocol to set up initial
537 * bindings, and periodically thereafer as new adapters come online
538 * ARGUMENTS:
539 * Status: Return value to NDIS
540 * BindContext: Handle provided by NDIS to track pending binding operations
541 * DeviceName: Name of the miniport device to bind to
542 * SystemSpecific1: Pointer to a registry path with protocol-specific configuration information
543 * SystemSpecific2: Unused & must not be touched
544 */
545 {
546 /* XXX confirm that this is still true, or re-word the following comment */
547 /* we get to ignore BindContext because we will never pend an operation with NDIS */
548 TI_DbgPrint(DEBUG_DATALINK, ("Called with registry path %wZ for %wZ\n", SystemSpecific1, DeviceName));
549 *Status = LANRegisterAdapter(DeviceName, SystemSpecific1);
550 }
551
552
553 VOID LANTransmit(
554 PVOID Context,
555 PNDIS_PACKET NdisPacket,
556 UINT Offset,
557 PVOID LinkAddress,
558 USHORT Type)
559 /*
560 * FUNCTION: Transmits a packet
561 * ARGUMENTS:
562 * Context = Pointer to context information (LAN_ADAPTER)
563 * NdisPacket = Pointer to NDIS packet to send
564 * Offset = Offset in packet where data starts
565 * LinkAddress = Pointer to link address of destination (NULL = broadcast)
566 * Type = LAN protocol type (LAN_PROTO_*)
567 */
568 {
569 NDIS_STATUS NdisStatus;
570 PETH_HEADER EHeader;
571 PCHAR Data;
572 UINT Size;
573 PLAN_ADAPTER Adapter = (PLAN_ADAPTER)Context;
574 KIRQL OldIrql;
575
576 TI_DbgPrint(DEBUG_DATALINK,
577 ("Called( NdisPacket %x, Offset %d, Adapter %x )\n",
578 NdisPacket, Offset, Adapter));
579
580 if (Adapter->State != LAN_STATE_STARTED) {
581 ProtocolSendComplete(Context, NdisPacket, NDIS_STATUS_NOT_ACCEPTED);
582 return;
583 }
584
585 TI_DbgPrint(DEBUG_DATALINK,
586 ("Adapter Address [%02x %02x %02x %02x %02x %02x]\n",
587 Adapter->HWAddress[0] & 0xff,
588 Adapter->HWAddress[1] & 0xff,
589 Adapter->HWAddress[2] & 0xff,
590 Adapter->HWAddress[3] & 0xff,
591 Adapter->HWAddress[4] & 0xff,
592 Adapter->HWAddress[5] & 0xff));
593
594 /* XXX arty -- Handled adjustment in a saner way than before ...
595 * not needed immediately */
596 GetDataPtr( NdisPacket, 0, &Data, &Size );
597
598 switch (Adapter->Media) {
599 case NdisMedium802_3:
600 EHeader = (PETH_HEADER)Data;
601
602 if (LinkAddress) {
603 /* Unicast address */
604 RtlCopyMemory(EHeader->DstAddr, LinkAddress, IEEE_802_ADDR_LENGTH);
605 } else {
606 /* Broadcast address */
607 RtlFillMemory(EHeader->DstAddr, IEEE_802_ADDR_LENGTH, 0xFF);
608 }
609
610 RtlCopyMemory(EHeader->SrcAddr, Adapter->HWAddress, IEEE_802_ADDR_LENGTH);
611
612 switch (Type) {
613 case LAN_PROTO_IPv4:
614 EHeader->EType = ETYPE_IPv4;
615 break;
616 case LAN_PROTO_ARP:
617 EHeader->EType = ETYPE_ARP;
618 break;
619 case LAN_PROTO_IPv6:
620 EHeader->EType = ETYPE_IPv6;
621 break;
622 default:
623 #ifdef DBG
624 /* Should not happen */
625 TI_DbgPrint(MIN_TRACE, ("Unknown LAN protocol.\n"));
626
627 ProtocolSendComplete((NDIS_HANDLE)Context,
628 NdisPacket,
629 NDIS_STATUS_FAILURE);
630 #endif
631 return;
632 }
633 break;
634
635 default:
636 /* FIXME: Support other medias */
637 break;
638 }
639
640 TI_DbgPrint( MID_TRACE, ("LinkAddress: %x\n", LinkAddress));
641 if( LinkAddress ) {
642 TI_DbgPrint
643 ( MID_TRACE,
644 ("Link Address [%02x %02x %02x %02x %02x %02x]\n",
645 ((PCHAR)LinkAddress)[0] & 0xff,
646 ((PCHAR)LinkAddress)[1] & 0xff,
647 ((PCHAR)LinkAddress)[2] & 0xff,
648 ((PCHAR)LinkAddress)[3] & 0xff,
649 ((PCHAR)LinkAddress)[4] & 0xff,
650 ((PCHAR)LinkAddress)[5] & 0xff));
651 }
652
653 TcpipAcquireSpinLock( &Adapter->Lock, &OldIrql );
654 TI_DbgPrint(MID_TRACE, ("NdisSend\n"));
655 NdisSend(&NdisStatus, Adapter->NdisHandle, NdisPacket);
656 TI_DbgPrint(MID_TRACE, ("NdisSend %s\n",
657 NdisStatus == NDIS_STATUS_PENDING ?
658 "Pending" : "Complete"));
659 TcpipReleaseSpinLock( &Adapter->Lock, OldIrql );
660
661 /* I had a talk with vizzini: these really ought to be here.
662 * we're supposed to see these completed by ndis *only* when
663 * status_pending is returned. Note that this is different from
664 * the situation with IRPs. */
665 if (NdisStatus != NDIS_STATUS_PENDING)
666 ProtocolSendComplete((NDIS_HANDLE)Context, NdisPacket, NdisStatus);
667 }
668
669 static NTSTATUS
670 OpenRegistryKey( PNDIS_STRING RegistryPath, PHANDLE RegHandle ) {
671 OBJECT_ATTRIBUTES Attributes;
672 NTSTATUS Status;
673
674 InitializeObjectAttributes(&Attributes, RegistryPath, OBJ_CASE_INSENSITIVE, 0, 0);
675 Status = ZwOpenKey(RegHandle, KEY_ALL_ACCESS, &Attributes);
676 return Status;
677 }
678
679 static NTSTATUS ReadStringFromRegistry( HANDLE RegHandle,
680 PWCHAR RegistryValue,
681 PUNICODE_STRING String ) {
682 UNICODE_STRING ValueName;
683 UNICODE_STRING UnicodeString;
684 NTSTATUS Status;
685 ULONG ResultLength;
686 UCHAR buf[1024];
687 PKEY_VALUE_PARTIAL_INFORMATION Information = (PKEY_VALUE_PARTIAL_INFORMATION)buf;
688
689 RtlInitUnicodeString(&ValueName, RegistryValue);
690 Status =
691 ZwQueryValueKey(RegHandle,
692 &ValueName,
693 KeyValuePartialInformation,
694 Information,
695 sizeof(buf),
696 &ResultLength);
697
698 if (!NT_SUCCESS(Status))
699 return Status;
700 /* IP address is stored as a REG_MULTI_SZ - we only pay attention to the first one though */
701 TI_DbgPrint(MIN_TRACE, ("Information DataLength: 0x%x\n", Information->DataLength));
702
703 UnicodeString.Buffer = (PWCHAR)&Information->Data;
704 UnicodeString.Length = Information->DataLength - sizeof(WCHAR);
705 UnicodeString.MaximumLength = Information->DataLength;
706
707 String->Buffer =
708 (PWCHAR)ExAllocatePool( NonPagedPool,
709 UnicodeString.MaximumLength + sizeof(WCHAR) );
710
711 if( !String->Buffer ) return STATUS_NO_MEMORY;
712
713 String->MaximumLength = UnicodeString.MaximumLength;
714 RtlCopyUnicodeString( String, &UnicodeString );
715
716 return STATUS_SUCCESS;
717 }
718
719 /*
720 * Utility to copy and append two unicode strings.
721 *
722 * IN OUT PUNICODE_STRING ResultFirst -> First string and result
723 * IN PUNICODE_STRING Second -> Second string to append
724 * IN BOOL Deallocate -> TRUE: Deallocate First string before
725 * overwriting.
726 *
727 * Returns NTSTATUS.
728 */
729
730 NTSTATUS NTAPI AppendUnicodeString(PUNICODE_STRING ResultFirst,
731 PUNICODE_STRING Second,
732 BOOLEAN Deallocate) {
733 NTSTATUS Status;
734 UNICODE_STRING Ustr = *ResultFirst;
735 PWSTR new_string = ExAllocatePoolWithTag
736 (PagedPool,
737 (ResultFirst->Length + Second->Length + sizeof(WCHAR)), TAG_STRING);
738 if( !new_string ) {
739 return STATUS_NO_MEMORY;
740 }
741 memcpy( new_string, ResultFirst->Buffer, ResultFirst->Length );
742 memcpy( new_string + ResultFirst->Length / sizeof(WCHAR),
743 Second->Buffer, Second->Length );
744 if( Deallocate ) RtlFreeUnicodeString(ResultFirst);
745 ResultFirst->Length = Ustr.Length + Second->Length;
746 ResultFirst->MaximumLength = ResultFirst->Length;
747 new_string[ResultFirst->Length / sizeof(WCHAR)] = 0;
748 Status = RtlCreateUnicodeString(ResultFirst,new_string) ?
749 STATUS_SUCCESS : STATUS_NO_MEMORY;
750 ExFreePool(new_string);
751 return Status;
752 }
753
754 static NTSTATUS CheckForDeviceDesc( PUNICODE_STRING EnumKeyName,
755 PUNICODE_STRING TargetKeyName,
756 PUNICODE_STRING Name,
757 PUNICODE_STRING DeviceDesc ) {
758 UNICODE_STRING RootDevice = { 0, 0, NULL }, LinkageKeyName = { 0, 0, NULL };
759 UNICODE_STRING DescKeyName = { 0, 0, NULL }, Linkage = { 0, 0, NULL };
760 UNICODE_STRING BackSlash = { 0, 0, NULL };
761 HANDLE DescKey = NULL, LinkageKey = NULL;
762 NTSTATUS Status;
763
764 TI_DbgPrint(DEBUG_DATALINK,("EnumKeyName %wZ\n", EnumKeyName));
765
766 RtlInitUnicodeString(&BackSlash, L"\\");
767 RtlInitUnicodeString(&Linkage, L"\\Linkage");
768
769 RtlInitUnicodeString(&DescKeyName, L"");
770 AppendUnicodeString( &DescKeyName, EnumKeyName, FALSE );
771 AppendUnicodeString( &DescKeyName, &BackSlash, TRUE );
772 AppendUnicodeString( &DescKeyName, TargetKeyName, TRUE );
773
774 RtlInitUnicodeString(&LinkageKeyName, L"");
775 AppendUnicodeString( &LinkageKeyName, &DescKeyName, FALSE );
776 AppendUnicodeString( &LinkageKeyName, &Linkage, TRUE );
777
778 Status = OpenRegistryKey( &LinkageKeyName, &LinkageKey );
779 if( !NT_SUCCESS(Status) ) goto cleanup;
780
781 Status = ReadStringFromRegistry( LinkageKey, L"RootDevice", &RootDevice );
782 if( !NT_SUCCESS(Status) ) goto cleanup;
783
784 if( RtlCompareUnicodeString( &RootDevice, Name, TRUE ) == 0 ) {
785 Status = OpenRegistryKey( &DescKeyName, &DescKey );
786 if( !NT_SUCCESS(Status) ) goto cleanup;
787
788 Status = ReadStringFromRegistry( DescKey, L"DriverDesc", DeviceDesc );
789 if( !NT_SUCCESS(Status) ) goto cleanup;
790
791 TI_DbgPrint(DEBUG_DATALINK,("ADAPTER DESC: %wZ\n", DeviceDesc));
792 } else Status = STATUS_UNSUCCESSFUL;
793
794 cleanup:
795 RtlFreeUnicodeString( &RootDevice );
796 RtlFreeUnicodeString( &LinkageKeyName );
797 RtlFreeUnicodeString( &DescKeyName );
798 if( LinkageKey ) NtClose( LinkageKey );
799 if( DescKey ) NtClose( DescKey );
800
801 TI_DbgPrint(DEBUG_DATALINK,("Returning %x\n", Status));
802
803 return Status;
804 }
805
806 static NTSTATUS FindDeviceDescForAdapter( PUNICODE_STRING Name,
807 PUNICODE_STRING DeviceDesc ) {
808 UNICODE_STRING EnumKeyName, TargetKeyName;
809 HANDLE EnumKey;
810 NTSTATUS Status;
811 ULONG i;
812 KEY_BASIC_INFORMATION *Kbio =
813 ExAllocatePool(NonPagedPool, sizeof(KEY_BASIC_INFORMATION));
814 ULONG KbioLength = sizeof(KEY_BASIC_INFORMATION), ResultLength;
815
816 if( !Kbio ) return STATUS_INSUFFICIENT_RESOURCES;
817
818 RtlInitUnicodeString
819 (&EnumKeyName, CCS_ROOT L"\\Control\\Class\\" TCPIP_GUID);
820
821 Status = OpenRegistryKey( &EnumKeyName, &EnumKey );
822
823 if( !NT_SUCCESS(Status) ) {
824 TI_DbgPrint(DEBUG_DATALINK,("Couldn't open Enum key %wZ: %x\n",
825 &EnumKeyName, Status));
826 ExFreePool( Kbio );
827 return Status;
828 }
829
830 for( i = 0; NT_SUCCESS(Status); i++ ) {
831 Status = ZwEnumerateKey( EnumKey, i, KeyBasicInformation,
832 Kbio, KbioLength, &ResultLength );
833
834 if( Status == STATUS_BUFFER_TOO_SMALL || Status == STATUS_BUFFER_OVERFLOW ) {
835 ExFreePool( Kbio );
836 KbioLength = ResultLength;
837 Kbio = ExAllocatePool( NonPagedPool, KbioLength );
838 if( !Kbio ) {
839 TI_DbgPrint(DEBUG_DATALINK,("Failed to allocate memory\n"));
840 NtClose( EnumKey );
841 return STATUS_NO_MEMORY;
842 }
843
844 Status = ZwEnumerateKey( EnumKey, i, KeyBasicInformation,
845 Kbio, KbioLength, &ResultLength );
846
847 if( !NT_SUCCESS(Status) ) {
848 TI_DbgPrint(DEBUG_DATALINK,("Couldn't enum key child %d\n", i));
849 NtClose( EnumKey );
850 ExFreePool( Kbio );
851 return Status;
852 }
853 }
854
855 if( NT_SUCCESS(Status) ) {
856 TargetKeyName.Length = TargetKeyName.MaximumLength =
857 Kbio->NameLength;
858 TargetKeyName.Buffer = Kbio->Name;
859
860 Status = CheckForDeviceDesc
861 ( &EnumKeyName, &TargetKeyName, Name, DeviceDesc );
862 if( NT_SUCCESS(Status) ) {
863 NtClose( EnumKey );
864 ExFreePool( Kbio );
865 return Status;
866 } else Status = STATUS_SUCCESS;
867 }
868 }
869
870 RtlInitUnicodeString( DeviceDesc, L"" );
871 AppendUnicodeString( DeviceDesc, &TargetKeyName, FALSE );
872 NtClose( EnumKey );
873 ExFreePool( Kbio );
874 return STATUS_UNSUCCESSFUL;
875 }
876
877 VOID GetName( PUNICODE_STRING RegistryKey,
878 PUNICODE_STRING OutName ) {
879 PWCHAR Ptr;
880 UNICODE_STRING PartialRegistryKey;
881
882 PartialRegistryKey.Buffer =
883 RegistryKey->Buffer + wcslen(CCS_ROOT L"\\Services\\");
884 Ptr = PartialRegistryKey.Buffer;
885
886 while( *Ptr != L'\\' &&
887 ((PCHAR)Ptr) < ((PCHAR)RegistryKey->Buffer) + RegistryKey->Length )
888 Ptr++;
889
890 PartialRegistryKey.Length = PartialRegistryKey.MaximumLength =
891 (Ptr - PartialRegistryKey.Buffer) * sizeof(WCHAR);
892
893 RtlInitUnicodeString( OutName, L"" );
894 AppendUnicodeString( OutName, &PartialRegistryKey, FALSE );
895 }
896
897 BOOLEAN BindAdapter(
898 PLAN_ADAPTER Adapter,
899 PNDIS_STRING RegistryPath)
900 /*
901 * FUNCTION: Binds a LAN adapter to IP layer
902 * ARGUMENTS:
903 * Adapter = Pointer to LAN_ADAPTER structure
904 * NOTES:
905 * We set the lookahead buffer size, set the packet filter and
906 * bind the adapter to IP layer
907 */
908 {
909 PIP_INTERFACE IF;
910 NDIS_STATUS NdisStatus;
911 LLIP_BIND_INFO BindInfo;
912 IP_ADDRESS DefaultMask;
913 ULONG Lookahead = LOOKAHEAD_SIZE;
914 NTSTATUS Status;
915
916 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
917
918 Adapter->State = LAN_STATE_OPENING;
919
920 NdisStatus = NDISCall(Adapter,
921 NdisRequestSetInformation,
922 OID_GEN_CURRENT_LOOKAHEAD,
923 &Lookahead,
924 sizeof(ULONG));
925 if (NdisStatus != NDIS_STATUS_SUCCESS) {
926 TI_DbgPrint(DEBUG_DATALINK, ("Could not set lookahead buffer size (0x%X).\n", NdisStatus));
927 return FALSE;
928 }
929
930 /* Bind the adapter to IP layer */
931 BindInfo.Context = Adapter;
932 BindInfo.HeaderSize = Adapter->HeaderSize;
933 BindInfo.MinFrameSize = Adapter->MinFrameSize;
934 BindInfo.MTU = Adapter->MTU;
935 BindInfo.Address = (PUCHAR)&Adapter->HWAddress;
936 BindInfo.AddressLength = Adapter->HWAddressLength;
937 BindInfo.Transmit = LANTransmit;
938
939 IF = IPCreateInterface(&BindInfo);
940
941 if (!IF) {
942 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
943 return FALSE;
944 }
945
946 /*
947 * Query per-adapter configuration from the registry
948 * In case anyone is curious: there *is* an Ndis configuration api
949 * for this sort of thing, but it doesn't really support things like
950 * REG_MULTI_SZ very well, and there is a note in the DDK that says that
951 * protocol drivers developed for win2k and above just use the native
952 * services (ZwOpenKey, etc).
953 */
954
955 GetName( RegistryPath, &IF->Name );
956
957 Status = FindDeviceDescForAdapter( &IF->Name, &IF->Description );
958
959 TI_DbgPrint(DEBUG_DATALINK,("Adapter Description: %wZ\n",
960 &IF->Description));
961
962 AddrInitIPv4(&DefaultMask, 0);
963
964 IF->Unicast = DefaultMask;
965 IF->Netmask = DefaultMask;
966
967 IF->Broadcast.Type = IP_ADDRESS_V4;
968 IF->Broadcast.Address.IPv4Address =
969 IF->Unicast.Address.IPv4Address |
970 ~IF->Netmask.Address.IPv4Address;
971
972 TI_DbgPrint(DEBUG_DATALINK,("BCAST(IF) %s\n", A2S(&IF->Broadcast)));
973
974 /* Get maximum link speed */
975 NdisStatus = NDISCall(Adapter,
976 NdisRequestQueryInformation,
977 OID_GEN_LINK_SPEED,
978 &IF->Speed,
979 sizeof(UINT));
980
981 if( !NT_SUCCESS(NdisStatus) )
982 IF->Speed = IP_DEFAULT_LINK_SPEED;
983
984 /* Register interface with IP layer */
985 IPRegisterInterface(IF);
986
987 /* Set packet filter so we can send and receive packets */
988 NdisStatus = NDISCall(Adapter,
989 NdisRequestSetInformation,
990 OID_GEN_CURRENT_PACKET_FILTER,
991 &Adapter->PacketFilter,
992 sizeof(UINT));
993
994 if (NdisStatus != NDIS_STATUS_SUCCESS) {
995 TI_DbgPrint(DEBUG_DATALINK, ("Could not set packet filter (0x%X).\n", NdisStatus));
996 IPUnregisterInterface(IF);
997 IPDestroyInterface(IF);
998 return FALSE;
999 }
1000
1001 Adapter->Context = IF;
1002 Adapter->State = LAN_STATE_STARTED;
1003 return TRUE;
1004 }
1005
1006
1007 VOID UnbindAdapter(
1008 PLAN_ADAPTER Adapter)
1009 /*
1010 * FUNCTION: Unbinds a LAN adapter from IP layer
1011 * ARGUMENTS:
1012 * Adapter = Pointer to LAN_ADAPTER structure
1013 */
1014 {
1015 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
1016
1017 if (Adapter->State == LAN_STATE_STARTED) {
1018 PIP_INTERFACE IF = Adapter->Context;
1019
1020 IPUnregisterInterface(IF);
1021
1022 IPDestroyInterface(IF);
1023 }
1024 }
1025
1026
1027 NDIS_STATUS LANRegisterAdapter(
1028 PNDIS_STRING AdapterName,
1029 PNDIS_STRING RegistryPath)
1030 /*
1031 * FUNCTION: Registers protocol with an NDIS adapter
1032 * ARGUMENTS:
1033 * AdapterName = Pointer to string with name of adapter to register
1034 * Adapter = Address of pointer to a LAN_ADAPTER structure
1035 * RETURNS:
1036 * Status of operation
1037 */
1038 {
1039 PLAN_ADAPTER IF;
1040 NDIS_STATUS NdisStatus;
1041 NDIS_STATUS OpenStatus;
1042 UINT MediaIndex;
1043 NDIS_MEDIUM MediaArray[MAX_MEDIA];
1044 UINT AddressOID;
1045 UINT Speed;
1046
1047 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
1048
1049 IF = exAllocatePool(NonPagedPool, sizeof(LAN_ADAPTER));
1050 if (!IF) {
1051 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
1052 return NDIS_STATUS_RESOURCES;
1053 }
1054
1055 RtlZeroMemory(IF, sizeof(LAN_ADAPTER));
1056
1057 /* Put adapter in stopped state */
1058 IF->State = LAN_STATE_STOPPED;
1059
1060 /* Initialize protecting spin lock */
1061 KeInitializeSpinLock(&IF->Lock);
1062
1063 KeInitializeEvent(&IF->Event, SynchronizationEvent, FALSE);
1064
1065 /* Initialize array with media IDs we support */
1066 MediaArray[MEDIA_ETH] = NdisMedium802_3;
1067
1068 TI_DbgPrint(DEBUG_DATALINK,("opening adapter %wZ\n", AdapterName));
1069 /* Open the adapter. */
1070 NdisOpenAdapter(&NdisStatus,
1071 &OpenStatus,
1072 &IF->NdisHandle,
1073 &MediaIndex,
1074 MediaArray,
1075 MAX_MEDIA,
1076 NdisProtocolHandle,
1077 IF,
1078 AdapterName,
1079 0,
1080 NULL);
1081
1082 /* Wait until the adapter is opened */
1083 if (NdisStatus == NDIS_STATUS_PENDING)
1084 KeWaitForSingleObject(&IF->Event, UserRequest, KernelMode, FALSE, NULL);
1085 else if (NdisStatus != NDIS_STATUS_SUCCESS) {
1086 TI_DbgPrint(DEBUG_DATALINK,("denying adapter %wZ\n", AdapterName));
1087 exFreePool(IF);
1088 return NdisStatus;
1089 }
1090
1091 IF->Media = MediaArray[MediaIndex];
1092
1093 /* Fill LAN_ADAPTER structure with some adapter specific information */
1094 switch (IF->Media) {
1095 case NdisMedium802_3:
1096 IF->HWAddressLength = IEEE_802_ADDR_LENGTH;
1097 IF->BCastMask = BCAST_ETH_MASK;
1098 IF->BCastCheck = BCAST_ETH_CHECK;
1099 IF->BCastOffset = BCAST_ETH_OFFSET;
1100 IF->HeaderSize = sizeof(ETH_HEADER);
1101 IF->MinFrameSize = 60;
1102 AddressOID = OID_802_3_CURRENT_ADDRESS;
1103 IF->PacketFilter =
1104 NDIS_PACKET_TYPE_BROADCAST |
1105 NDIS_PACKET_TYPE_DIRECTED |
1106 NDIS_PACKET_TYPE_MULTICAST;
1107 break;
1108
1109 default:
1110 /* Unsupported media */
1111 TI_DbgPrint(MIN_TRACE, ("Unsupported media.\n"));
1112 exFreePool(IF);
1113 return NDIS_STATUS_NOT_SUPPORTED;
1114 }
1115
1116 /* Get maximum frame size */
1117 NdisStatus = NDISCall(IF,
1118 NdisRequestQueryInformation,
1119 OID_GEN_MAXIMUM_FRAME_SIZE,
1120 &IF->MTU,
1121 sizeof(UINT));
1122 if (NdisStatus != NDIS_STATUS_SUCCESS) {
1123 TI_DbgPrint(DEBUG_DATALINK,("denying adapter %wZ (NDISCall)\n", AdapterName));
1124 exFreePool(IF);
1125 return NdisStatus;
1126 }
1127
1128 /* Get maximum packet size */
1129 NdisStatus = NDISCall(IF,
1130 NdisRequestQueryInformation,
1131 OID_GEN_MAXIMUM_TOTAL_SIZE,
1132 &IF->MaxPacketSize,
1133 sizeof(UINT));
1134 if (NdisStatus != NDIS_STATUS_SUCCESS) {
1135 TI_DbgPrint(MIN_TRACE, ("Query for maximum packet size failed.\n"));
1136 exFreePool(IF);
1137 return NdisStatus;
1138 }
1139
1140 /* Get maximum number of packets we can pass to NdisSend(Packets) at one time */
1141 NdisStatus = NDISCall(IF,
1142 NdisRequestQueryInformation,
1143 OID_GEN_MAXIMUM_SEND_PACKETS,
1144 &IF->MaxSendPackets,
1145 sizeof(UINT));
1146 if (NdisStatus != NDIS_STATUS_SUCCESS)
1147 /* Legacy NIC drivers may not support this query, if it fails we
1148 assume it can send at least one packet per call to NdisSend(Packets) */
1149 IF->MaxSendPackets = 1;
1150
1151 /* Get current hardware address */
1152 NdisStatus = NDISCall(IF,
1153 NdisRequestQueryInformation,
1154 AddressOID,
1155 &IF->HWAddress,
1156 IF->HWAddressLength);
1157 if (NdisStatus != NDIS_STATUS_SUCCESS) {
1158 TI_DbgPrint(MIN_TRACE, ("Query for current hardware address failed.\n"));
1159 exFreePool(IF);
1160 return NdisStatus;
1161 }
1162
1163 /* Get maximum link speed */
1164 NdisStatus = NDISCall(IF,
1165 NdisRequestQueryInformation,
1166 OID_GEN_LINK_SPEED,
1167 &Speed,
1168 sizeof(UINT));
1169 if (NdisStatus != NDIS_STATUS_SUCCESS) {
1170 TI_DbgPrint(MIN_TRACE, ("Query for maximum link speed failed.\n"));
1171 exFreePool(IF);
1172 return NdisStatus;
1173 }
1174
1175 /* Convert returned link speed to bps (it is in 100bps increments) */
1176 IF->Speed = Speed * 100L;
1177
1178 /* Bind adapter to IP layer */
1179 if( !BindAdapter(IF, RegistryPath) ) {
1180 TI_DbgPrint(DEBUG_DATALINK,("denying adapter %wZ (BindAdapter)\n", AdapterName));
1181 exFreePool(IF);
1182 return NDIS_STATUS_NOT_ACCEPTED;
1183 }
1184
1185 /* Add adapter to the adapter list */
1186 ExInterlockedInsertTailList(&AdapterListHead,
1187 &IF->ListEntry,
1188 &AdapterListLock);
1189
1190 TI_DbgPrint(DEBUG_DATALINK, ("Leaving.\n"));
1191
1192 return NDIS_STATUS_SUCCESS;
1193 }
1194
1195
1196 NDIS_STATUS LANUnregisterAdapter(
1197 PLAN_ADAPTER Adapter)
1198 /*
1199 * FUNCTION: Unregisters protocol with NDIS adapter
1200 * ARGUMENTS:
1201 * Adapter = Pointer to a LAN_ADAPTER structure
1202 * RETURNS:
1203 * Status of operation
1204 */
1205 {
1206 KIRQL OldIrql;
1207 NDIS_HANDLE NdisHandle;
1208 NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS;
1209
1210 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
1211
1212 /* Unlink the adapter from the list */
1213 RemoveEntryList(&Adapter->ListEntry);
1214
1215 /* Unbind adapter from IP layer */
1216 UnbindAdapter(Adapter);
1217
1218 TcpipAcquireSpinLock(&Adapter->Lock, &OldIrql);
1219 NdisHandle = Adapter->NdisHandle;
1220 if (NdisHandle) {
1221 Adapter->NdisHandle = NULL;
1222 TcpipReleaseSpinLock(&Adapter->Lock, OldIrql);
1223
1224 NdisCloseAdapter(&NdisStatus, NdisHandle);
1225 if (NdisStatus == NDIS_STATUS_PENDING) {
1226 TcpipWaitForSingleObject(&Adapter->Event,
1227 UserRequest,
1228 KernelMode,
1229 FALSE,
1230 NULL);
1231 NdisStatus = Adapter->NdisStatus;
1232 }
1233 } else
1234 TcpipReleaseSpinLock(&Adapter->Lock, OldIrql);
1235
1236 FreeAdapter(Adapter);
1237
1238 return NdisStatus;
1239 }
1240
1241
1242 NTSTATUS LANRegisterProtocol(
1243 PNDIS_STRING Name)
1244 /*
1245 * FUNCTION: Registers this protocol driver with NDIS
1246 * ARGUMENTS:
1247 * Name = Name of this protocol driver
1248 * RETURNS:
1249 * Status of operation
1250 */
1251 {
1252 NDIS_STATUS NdisStatus;
1253 NDIS_PROTOCOL_CHARACTERISTICS ProtChars;
1254
1255 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
1256
1257 InitializeListHead(&AdapterListHead);
1258 KeInitializeSpinLock(&AdapterListLock);
1259
1260 /* Set up protocol characteristics */
1261 RtlZeroMemory(&ProtChars, sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
1262 ProtChars.MajorNdisVersion = NDIS_VERSION_MAJOR;
1263 ProtChars.MinorNdisVersion = NDIS_VERSION_MINOR;
1264 ProtChars.Name.Length = Name->Length;
1265 ProtChars.Name.Buffer = Name->Buffer;
1266 ProtChars.Name.MaximumLength = Name->MaximumLength;
1267 ProtChars.OpenAdapterCompleteHandler = ProtocolOpenAdapterComplete;
1268 ProtChars.CloseAdapterCompleteHandler = ProtocolCloseAdapterComplete;
1269 ProtChars.ResetCompleteHandler = ProtocolResetComplete;
1270 ProtChars.RequestCompleteHandler = ProtocolRequestComplete;
1271 ProtChars.SendCompleteHandler = ProtocolSendComplete;
1272 ProtChars.TransferDataCompleteHandler = ProtocolTransferDataComplete;
1273 ProtChars.ReceiveHandler = ProtocolReceive;
1274 ProtChars.ReceiveCompleteHandler = ProtocolReceiveComplete;
1275 ProtChars.StatusHandler = ProtocolStatus;
1276 ProtChars.StatusCompleteHandler = ProtocolStatusComplete;
1277 ProtChars.BindAdapterHandler = ProtocolBindAdapter;
1278
1279 /* Try to register protocol */
1280 NdisRegisterProtocol(&NdisStatus,
1281 &NdisProtocolHandle,
1282 &ProtChars,
1283 sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
1284 if (NdisStatus != NDIS_STATUS_SUCCESS)
1285 {
1286 TI_DbgPrint(DEBUG_DATALINK, ("NdisRegisterProtocol failed, status 0x%x\n", NdisStatus));
1287 return (NTSTATUS)NdisStatus;
1288 }
1289
1290 ProtocolRegistered = TRUE;
1291
1292 return STATUS_SUCCESS;
1293 }
1294
1295
1296 VOID LANUnregisterProtocol(
1297 VOID)
1298 /*
1299 * FUNCTION: Unregisters this protocol driver with NDIS
1300 * NOTES: Does not care wether we are already registered
1301 */
1302 {
1303 TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
1304
1305 if (ProtocolRegistered) {
1306 NDIS_STATUS NdisStatus;
1307 PLIST_ENTRY CurrentEntry;
1308 PLIST_ENTRY NextEntry;
1309 PLAN_ADAPTER Current;
1310 KIRQL OldIrql;
1311
1312 TcpipAcquireSpinLock(&AdapterListLock, &OldIrql);
1313
1314 /* Search the list and remove every adapter we find */
1315 CurrentEntry = AdapterListHead.Flink;
1316 while (CurrentEntry != &AdapterListHead) {
1317 NextEntry = CurrentEntry->Flink;
1318 Current = CONTAINING_RECORD(CurrentEntry, LAN_ADAPTER, ListEntry);
1319 /* Unregister it */
1320 LANUnregisterAdapter(Current);
1321 CurrentEntry = NextEntry;
1322 }
1323
1324 TcpipReleaseSpinLock(&AdapterListLock, OldIrql);
1325
1326 NdisDeregisterProtocol(&NdisStatus, NdisProtocolHandle);
1327 ProtocolRegistered = FALSE;
1328 }
1329 }
1330
1331 /* EOF */