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