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