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