ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

lan.c
Go to the documentation of this file.
00001 /*
00002  * COPYRIGHT:   See COPYING in the top level directory
00003  * PROJECT:     ReactOS TCP/IP protocol driver
00004  * FILE:        datalink/lan.c
00005  * PURPOSE:     Local Area Network media routines
00006  * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
00007  * REVISIONS:
00008  *   CSH 01/08-2000 Created
00009  */
00010 
00011 #include "precomp.h"
00012 
00013 UINT TransferDataCalled = 0;
00014 UINT TransferDataCompleteCalled = 0;
00015 
00016 #define CCS_ROOT L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet"
00017 #define TCPIP_GUID L"{4D36E972-E325-11CE-BFC1-08002BE10318}"
00018 
00019 typedef struct _LAN_WQ_ITEM {
00020     LIST_ENTRY ListEntry;
00021     PNDIS_PACKET Packet;
00022     PLAN_ADAPTER Adapter;
00023     UINT BytesTransferred;
00024     BOOLEAN LegacyReceive;
00025 } LAN_WQ_ITEM, *PLAN_WQ_ITEM;
00026 
00027 typedef struct _RECONFIGURE_CONTEXT {
00028     ULONG State;
00029     PLAN_ADAPTER Adapter;
00030 } RECONFIGURE_CONTEXT, *PRECONFIGURE_CONTEXT;
00031 
00032 NDIS_HANDLE NdisProtocolHandle = (NDIS_HANDLE)NULL;
00033 BOOLEAN ProtocolRegistered     = FALSE;
00034 LIST_ENTRY AdapterListHead;
00035 KSPIN_LOCK AdapterListLock;
00036 
00037 NDIS_STATUS NDISCall(
00038     PLAN_ADAPTER Adapter,
00039     NDIS_REQUEST_TYPE Type,
00040     NDIS_OID OID,
00041     PVOID Buffer,
00042     UINT Length)
00043 /*
00044  * FUNCTION: Send a request to NDIS
00045  * ARGUMENTS:
00046  *     Adapter     = Pointer to a LAN_ADAPTER structure
00047  *     Type        = Type of request (Set or Query)
00048  *     OID         = Value to be set/queried for
00049  *     Buffer      = Pointer to a buffer to use
00050  *     Length      = Number of bytes in Buffer
00051  * RETURNS:
00052  *     Status of operation
00053  */
00054 {
00055     NDIS_REQUEST Request;
00056     NDIS_STATUS NdisStatus;
00057 
00058     Request.RequestType = Type;
00059     if (Type == NdisRequestSetInformation) {
00060         Request.DATA.SET_INFORMATION.Oid                     = OID;
00061         Request.DATA.SET_INFORMATION.InformationBuffer       = Buffer;
00062         Request.DATA.SET_INFORMATION.InformationBufferLength = Length;
00063     } else {
00064         Request.DATA.QUERY_INFORMATION.Oid                     = OID;
00065         Request.DATA.QUERY_INFORMATION.InformationBuffer       = Buffer;
00066         Request.DATA.QUERY_INFORMATION.InformationBufferLength = Length;
00067     }
00068 
00069     if (Adapter->State != LAN_STATE_RESETTING) {
00070         NdisRequest(&NdisStatus, Adapter->NdisHandle, &Request);
00071     } else {
00072         NdisStatus = NDIS_STATUS_NOT_ACCEPTED;
00073     }
00074 
00075     /* Wait for NDIS to complete the request */
00076     if (NdisStatus == NDIS_STATUS_PENDING) {
00077         KeWaitForSingleObject(&Adapter->Event,
00078                               UserRequest,
00079                               KernelMode,
00080                               FALSE,
00081                               NULL);
00082         NdisStatus = Adapter->NdisStatus;
00083     }
00084 
00085     return NdisStatus;
00086 }
00087 
00088 /* Used by legacy ProtocolReceive for packet type */
00089 NDIS_STATUS
00090 GetPacketTypeFromHeaderBuffer(PLAN_ADAPTER Adapter,
00091                               PVOID HeaderBuffer,
00092                               ULONG HeaderBufferSize,
00093                               PULONG PacketType)
00094 {
00095     PETH_HEADER EthHeader = HeaderBuffer;
00096 
00097     if (HeaderBufferSize < Adapter->HeaderSize)
00098     {
00099         TI_DbgPrint(DEBUG_DATALINK, ("Runt frame (size %d).\n", HeaderBufferSize));
00100         return NDIS_STATUS_NOT_ACCEPTED;
00101     }
00102 
00103     switch (Adapter->Media)
00104     {
00105         case NdisMedium802_3:
00106             /* Ethernet and IEEE 802.3 frames can be destinguished by
00107                looking at the IEEE 802.3 length field. This field is
00108                less than or equal to 1500 for a valid IEEE 802.3 frame
00109                and larger than 1500 is it's a valid EtherType value.
00110                See RFC 1122, section 2.3.3 for more information */
00111 
00112             *PacketType = EthHeader->EType;
00113             break;
00114 
00115         default:
00116             TI_DbgPrint(MIN_TRACE, ("Unsupported media.\n"));
00117 
00118             /* FIXME: Support other medias */
00119             return NDIS_STATUS_NOT_ACCEPTED;
00120     }
00121     
00122     TI_DbgPrint(DEBUG_DATALINK, ("EtherType (0x%X).\n", *PacketType));
00123     
00124     return NDIS_STATUS_SUCCESS;
00125 }
00126 
00127 /* Used by ProtocolReceivePacket for packet type */
00128 NDIS_STATUS
00129 GetPacketTypeFromNdisPacket(PLAN_ADAPTER Adapter,
00130                             PNDIS_PACKET NdisPacket,
00131                             PULONG PacketType)
00132 {
00133     PVOID HeaderBuffer;
00134     ULONG BytesCopied;
00135     NDIS_STATUS Status;
00136     
00137     HeaderBuffer = ExAllocatePool(NonPagedPool,
00138                                   Adapter->HeaderSize);
00139     if (!HeaderBuffer)
00140         return NDIS_STATUS_RESOURCES;
00141     
00142     /* Copy the media header */
00143     BytesCopied = CopyPacketToBuffer(HeaderBuffer,
00144                                      NdisPacket,
00145                                      0,
00146                                      Adapter->HeaderSize);
00147     if (BytesCopied != Adapter->HeaderSize)
00148     {
00149         /* Runt frame */
00150         ExFreePool(HeaderBuffer);
00151         TI_DbgPrint(DEBUG_DATALINK, ("Runt frame (size %d).\n", BytesCopied));
00152         return NDIS_STATUS_NOT_ACCEPTED;
00153     }
00154 
00155     Status = GetPacketTypeFromHeaderBuffer(Adapter,
00156                                            HeaderBuffer,
00157                                            BytesCopied,
00158                                            PacketType);
00159     
00160     ExFreePool(HeaderBuffer);
00161     
00162     return Status;
00163 }
00164 
00165 
00166 VOID FreeAdapter(
00167     PLAN_ADAPTER Adapter)
00168 /*
00169  * FUNCTION: Frees memory for a LAN_ADAPTER structure
00170  * ARGUMENTS:
00171  *     Adapter = Pointer to LAN_ADAPTER structure to free
00172  */
00173 {
00174     ExFreePoolWithTag(Adapter, LAN_ADAPTER_TAG);
00175 }
00176 
00177 
00178 NTSTATUS TcpipLanGetDwordOid
00179 ( PIP_INTERFACE Interface,
00180   NDIS_OID Oid,
00181   PULONG Result ) {
00182     /* Get maximum frame size */
00183     if( Interface->Context ) {
00184         return NDISCall((PLAN_ADAPTER)Interface->Context,
00185                         NdisRequestQueryInformation,
00186                         Oid,
00187                         Result,
00188                         sizeof(ULONG));
00189     } else switch( Oid ) { /* Loopback Case */
00190     case OID_GEN_HARDWARE_STATUS:
00191         *Result = NdisHardwareStatusReady;
00192         return STATUS_SUCCESS;
00193     case OID_GEN_MEDIA_CONNECT_STATUS:
00194         *Result = NdisMediaStateConnected;
00195         return STATUS_SUCCESS;
00196     default:
00197         return STATUS_INVALID_PARAMETER;
00198     }
00199 }
00200 
00201 
00202 VOID NTAPI ProtocolOpenAdapterComplete(
00203     NDIS_HANDLE BindingContext,
00204     NDIS_STATUS Status,
00205     NDIS_STATUS OpenErrorStatus)
00206 /*
00207  * FUNCTION: Called by NDIS to complete opening of an adapter
00208  * ARGUMENTS:
00209  *     BindingContext  = Pointer to a device context (LAN_ADAPTER)
00210  *     Status          = Status of the operation
00211  *     OpenErrorStatus = Additional status information
00212  */
00213 {
00214     PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
00215 
00216     TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
00217 
00218     Adapter->NdisStatus = Status;
00219 
00220     KeSetEvent(&Adapter->Event, 0, FALSE);
00221 }
00222 
00223 
00224 VOID NTAPI ProtocolCloseAdapterComplete(
00225     NDIS_HANDLE BindingContext,
00226     NDIS_STATUS Status)
00227 /*
00228  * FUNCTION: Called by NDIS to complete closing an adapter
00229  * ARGUMENTS:
00230  *     BindingContext = Pointer to a device context (LAN_ADAPTER)
00231  *     Status         = Status of the operation
00232  */
00233 {
00234     PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
00235 
00236     TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
00237 
00238     Adapter->NdisStatus = Status;
00239 
00240     KeSetEvent(&Adapter->Event, 0, FALSE);
00241 }
00242 
00243 
00244 VOID NTAPI ProtocolResetComplete(
00245     NDIS_HANDLE BindingContext,
00246     NDIS_STATUS Status)
00247 /*
00248  * FUNCTION: Called by NDIS to complete resetting an adapter
00249  * ARGUMENTS:
00250  *     BindingContext = Pointer to a device context (LAN_ADAPTER)
00251  *     Status         = Status of the operation
00252  */
00253 {
00254     PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
00255 
00256     TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
00257 
00258     Adapter->NdisStatus = Status;
00259 
00260     KeSetEvent(&Adapter->Event, 0, FALSE);
00261 }
00262 
00263 
00264 VOID NTAPI ProtocolRequestComplete(
00265     NDIS_HANDLE BindingContext,
00266     PNDIS_REQUEST NdisRequest,
00267     NDIS_STATUS Status)
00268 /*
00269  * FUNCTION: Called by NDIS to complete a request
00270  * ARGUMENTS:
00271  *     BindingContext = Pointer to a device context (LAN_ADAPTER)
00272  *     NdisRequest    = Pointer to an object describing the request
00273  *     Status         = Status of the operation
00274  */
00275 {
00276     PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
00277 
00278     TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
00279 
00280     /* Save status of request and signal an event */
00281     Adapter->NdisStatus = Status;
00282 
00283     KeSetEvent(&Adapter->Event, 0, FALSE);
00284 }
00285 
00286 
00287 VOID NTAPI ProtocolSendComplete(
00288     NDIS_HANDLE BindingContext,
00289     PNDIS_PACKET Packet,
00290     NDIS_STATUS Status)
00291 /*
00292  * FUNCTION: Called by NDIS to complete sending process
00293  * ARGUMENTS:
00294  *     BindingContext = Pointer to a device context (LAN_ADAPTER)
00295  *     Packet         = Pointer to a packet descriptor
00296  *     Status         = Status of the operation
00297  */
00298 {
00299     FreeNdisPacket(Packet);
00300 }
00301 
00302 VOID LanReceiveWorker( PVOID Context ) {
00303     ULONG PacketType;
00304     PLAN_WQ_ITEM WorkItem = (PLAN_WQ_ITEM)Context;
00305     PNDIS_PACKET Packet;
00306     PLAN_ADAPTER Adapter;
00307     UINT BytesTransferred;
00308     IP_PACKET IPPacket;
00309     BOOLEAN LegacyReceive;
00310     PIP_INTERFACE Interface;
00311 
00312     TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
00313 
00314     Packet = WorkItem->Packet;
00315     Adapter = WorkItem->Adapter;
00316     BytesTransferred = WorkItem->BytesTransferred;
00317     LegacyReceive = WorkItem->LegacyReceive;
00318 
00319     ExFreePoolWithTag(WorkItem, WQ_CONTEXT_TAG);
00320 
00321     Interface = Adapter->Context;
00322 
00323     IPInitializePacket(&IPPacket, 0);
00324 
00325     IPPacket.NdisPacket = Packet;
00326     IPPacket.ReturnPacket = !LegacyReceive;
00327 
00328     if (LegacyReceive)
00329     {
00330         /* Packet type is precomputed */
00331         PacketType = PC(IPPacket.NdisPacket)->PacketType;
00332 
00333         /* Data is at position 0 */
00334         IPPacket.Position = 0;
00335 
00336         /* Packet size is determined by bytes transferred */
00337         IPPacket.TotalSize = BytesTransferred;
00338     }
00339     else
00340     {
00341         /* Determine packet type from media header */
00342         if (GetPacketTypeFromNdisPacket(Adapter,
00343                                         IPPacket.NdisPacket,
00344                                         &PacketType) != NDIS_STATUS_SUCCESS)
00345         {
00346             /* Bad packet */
00347             IPPacket.Free(&IPPacket);
00348             return;
00349         }
00350 
00351         /* Data is at the end of the media header */
00352         IPPacket.Position = Adapter->HeaderSize;
00353 
00354         /* Calculate packet size (excluding media header) */
00355         NdisQueryPacketLength(IPPacket.NdisPacket, &IPPacket.TotalSize);
00356     }
00357 
00358     TI_DbgPrint
00359     (DEBUG_DATALINK,
00360      ("Ether Type = %x Total = %d\n",
00361       PacketType, IPPacket.TotalSize));
00362 
00363     /* Update interface stats */
00364     Interface->Stats.InBytes += IPPacket.TotalSize + Adapter->HeaderSize;
00365 
00366     /* NDIS packet is freed in all of these cases */
00367     switch (PacketType) {
00368         case ETYPE_IPv4:
00369         case ETYPE_IPv6:
00370             TI_DbgPrint(MID_TRACE,("Received IP Packet\n"));
00371             IPReceive(Adapter->Context, &IPPacket);
00372             break;
00373         case ETYPE_ARP:
00374             TI_DbgPrint(MID_TRACE,("Received ARP Packet\n"));
00375             ARPReceive(Adapter->Context, &IPPacket);
00376             break;
00377         default:
00378             IPPacket.Free(&IPPacket);
00379             break;
00380     }
00381 }
00382 
00383 VOID LanSubmitReceiveWork(
00384     NDIS_HANDLE BindingContext,
00385     PNDIS_PACKET Packet,
00386     UINT BytesTransferred,
00387     BOOLEAN LegacyReceive) {
00388     PLAN_WQ_ITEM WQItem = ExAllocatePoolWithTag(NonPagedPool, sizeof(LAN_WQ_ITEM),
00389                                                 WQ_CONTEXT_TAG);
00390     PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
00391 
00392     TI_DbgPrint(DEBUG_DATALINK,("called\n"));
00393 
00394     if (!WQItem) return;
00395 
00396     WQItem->Packet = Packet;
00397     WQItem->Adapter = Adapter;
00398     WQItem->BytesTransferred = BytesTransferred;
00399     WQItem->LegacyReceive = LegacyReceive;
00400 
00401     if (!ChewCreate( LanReceiveWorker, WQItem ))
00402         ExFreePoolWithTag(WQItem, WQ_CONTEXT_TAG);
00403 }
00404 
00405 VOID NTAPI ProtocolTransferDataComplete(
00406     NDIS_HANDLE BindingContext,
00407     PNDIS_PACKET Packet,
00408     NDIS_STATUS Status,
00409     UINT BytesTransferred)
00410 /*
00411  * FUNCTION: Called by NDIS to complete reception of data
00412  * ARGUMENTS:
00413  *     BindingContext   = Pointer to a device context (LAN_ADAPTER)
00414  *     Packet           = Pointer to a packet descriptor
00415  *     Status           = Status of the operation
00416  *     BytesTransferred = Number of bytes transferred
00417  * NOTES:
00418  *     If the packet was successfully received, determine the protocol
00419  *     type and pass it to the correct receive handler
00420  */
00421 {
00422     ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
00423 
00424     TI_DbgPrint(DEBUG_DATALINK,("called\n"));
00425 
00426     TransferDataCompleteCalled++;
00427     ASSERT(TransferDataCompleteCalled <= TransferDataCalled);
00428 
00429     if( Status != NDIS_STATUS_SUCCESS ) return;
00430 
00431     LanSubmitReceiveWork(BindingContext,
00432                          Packet,
00433                          BytesTransferred,
00434                          TRUE);
00435 }
00436 
00437 INT NTAPI ProtocolReceivePacket(
00438     NDIS_HANDLE BindingContext,
00439     PNDIS_PACKET NdisPacket)
00440 {
00441     PLAN_ADAPTER Adapter = BindingContext;
00442 
00443     if (Adapter->State != LAN_STATE_STARTED) {
00444         TI_DbgPrint(DEBUG_DATALINK, ("Adapter is stopped.\n"));
00445         return 0;
00446     }
00447 
00448     LanSubmitReceiveWork(BindingContext,
00449                          NdisPacket,
00450                          0, /* Unused */
00451                          FALSE);
00452 
00453     /* Hold 1 reference on this packet */
00454     return 1;
00455 }
00456 
00457 NDIS_STATUS NTAPI ProtocolReceive(
00458     NDIS_HANDLE BindingContext,
00459     NDIS_HANDLE MacReceiveContext,
00460     PVOID HeaderBuffer,
00461     UINT HeaderBufferSize,
00462     PVOID LookaheadBuffer,
00463     UINT LookaheadBufferSize,
00464     UINT PacketSize)
00465 /*
00466  * FUNCTION: Called by NDIS when a packet has been received on the physical link
00467  * ARGUMENTS:
00468  *     BindingContext      = Pointer to a device context (LAN_ADAPTER)
00469  *     MacReceiveContext   = Handle used by underlying NIC driver
00470  *     HeaderBuffer        = Pointer to a buffer containing the packet header
00471  *     HeaderBufferSize    = Number of bytes in HeaderBuffer
00472  *     LookaheadBuffer     = Pointer to a buffer containing buffered packet data
00473  *     LookaheadBufferSize = Size of LookaheadBuffer. May be less than asked for
00474  *     PacketSize          = Overall size of the packet (not including header)
00475  * RETURNS:
00476  *     Status of operation
00477  */
00478 {
00479     ULONG PacketType;
00480     UINT BytesTransferred;
00481     PCHAR BufferData;
00482     NDIS_STATUS NdisStatus;
00483     PNDIS_PACKET NdisPacket;
00484     PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
00485 
00486     TI_DbgPrint(DEBUG_DATALINK, ("Called. (packetsize %d)\n",PacketSize));
00487 
00488     if (Adapter->State != LAN_STATE_STARTED) {
00489         TI_DbgPrint(DEBUG_DATALINK, ("Adapter is stopped.\n"));
00490         return NDIS_STATUS_NOT_ACCEPTED;
00491     }
00492 
00493     if (HeaderBufferSize < Adapter->HeaderSize) {
00494         TI_DbgPrint(DEBUG_DATALINK, ("Runt frame received.\n"));
00495         return NDIS_STATUS_NOT_ACCEPTED;
00496     }
00497 
00498     NdisStatus = GetPacketTypeFromHeaderBuffer(Adapter,
00499                                                HeaderBuffer,
00500                                                HeaderBufferSize,
00501                                                &PacketType);
00502     if (NdisStatus != NDIS_STATUS_SUCCESS)
00503         return NDIS_STATUS_NOT_ACCEPTED;
00504 
00505     TI_DbgPrint(DEBUG_DATALINK, ("Adapter: %x (MTU %d)\n",
00506                  Adapter, Adapter->MTU));
00507 
00508     /* Get a transfer data packet */
00509     NdisStatus = AllocatePacketWithBuffer( &NdisPacket, NULL,
00510                                            PacketSize );
00511     if( NdisStatus != NDIS_STATUS_SUCCESS ) {
00512     return NDIS_STATUS_NOT_ACCEPTED;
00513     }
00514 
00515     PC(NdisPacket)->PacketType = PacketType;
00516 
00517     TI_DbgPrint(DEBUG_DATALINK, ("pretransfer LookaheadBufferSize %d packsize %d\n",LookaheadBufferSize,PacketSize));
00518 
00519     GetDataPtr( NdisPacket, 0, &BufferData, &PacketSize );
00520 
00521     TransferDataCalled++;
00522 
00523     if (LookaheadBufferSize == PacketSize)
00524     {
00525         /* Optimized code path for packets that are fully contained in
00526          * the lookahead buffer. */
00527         NdisCopyLookaheadData(BufferData,
00528                               LookaheadBuffer,
00529                               LookaheadBufferSize,
00530                               Adapter->MacOptions);
00531     }
00532     else
00533     {
00534         NdisTransferData(&NdisStatus, Adapter->NdisHandle,
00535                          MacReceiveContext, 0, PacketSize,
00536              NdisPacket, &BytesTransferred);
00537     }
00538     TI_DbgPrint(DEBUG_DATALINK, ("Calling complete\n"));
00539 
00540     if (NdisStatus != NDIS_STATUS_PENDING)
00541     ProtocolTransferDataComplete(BindingContext,
00542                      NdisPacket,
00543                      NdisStatus,
00544                      PacketSize);
00545 
00546     TI_DbgPrint(DEBUG_DATALINK, ("leaving\n"));
00547 
00548     return NDIS_STATUS_SUCCESS;
00549 }
00550 
00551 
00552 VOID NTAPI ProtocolReceiveComplete(
00553     NDIS_HANDLE BindingContext)
00554 /*
00555  * FUNCTION: Called by NDIS when we're done receiving data
00556  * ARGUMENTS:
00557  *     BindingContext = Pointer to a device context (LAN_ADAPTER)
00558  */
00559 {
00560     TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
00561 }
00562 
00563 BOOLEAN ReadIpConfiguration(PIP_INTERFACE Interface)
00564 {
00565     OBJECT_ATTRIBUTES ObjectAttributes;
00566     HANDLE ParameterHandle;
00567     PKEY_VALUE_PARTIAL_INFORMATION KeyValueInfo;
00568     WCHAR Buffer[150];
00569     UNICODE_STRING IPAddress = RTL_CONSTANT_STRING(L"IPAddress");
00570     UNICODE_STRING Netmask = RTL_CONSTANT_STRING(L"SubnetMask");
00571     UNICODE_STRING Gateway = RTL_CONSTANT_STRING(L"DefaultGateway");
00572     UNICODE_STRING EnableDhcp = RTL_CONSTANT_STRING(L"EnableDHCP");
00573     UNICODE_STRING Prefix = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\");
00574     UNICODE_STRING TcpipRegistryPath;
00575     UNICODE_STRING RegistryDataU;
00576     ANSI_STRING RegistryDataA;
00577     ULONG Unused;
00578     NTSTATUS Status;
00579     IP_ADDRESS DefaultMask, Router;
00580     
00581     AddrInitIPv4(&DefaultMask, 0);
00582 
00583     TcpipRegistryPath.MaximumLength = sizeof(WCHAR) * 150;
00584     TcpipRegistryPath.Length = 0;
00585     TcpipRegistryPath.Buffer = Buffer;
00586     
00587     /* Build the registry path */
00588     RtlAppendUnicodeStringToString(&TcpipRegistryPath, &Prefix);
00589     RtlAppendUnicodeStringToString(&TcpipRegistryPath, &Interface->Name);
00590     
00591     InitializeObjectAttributes(&ObjectAttributes,
00592                                &TcpipRegistryPath,
00593                                OBJ_CASE_INSENSITIVE,
00594                                0,
00595                                NULL);
00596     
00597     /* Open a handle to the adapter parameters */
00598     Status = ZwOpenKey(&ParameterHandle, KEY_READ, &ObjectAttributes);
00599     
00600     if (!NT_SUCCESS(Status))
00601     {
00602         return FALSE;
00603     }
00604     else
00605     {
00606         KeyValueInfo = ExAllocatePool(PagedPool, sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 16 * sizeof(WCHAR));
00607         if (!KeyValueInfo)
00608         {
00609             ZwClose(ParameterHandle);
00610             return FALSE;
00611         }
00612         
00613         /* Read the EnableDHCP entry */
00614         Status = ZwQueryValueKey(ParameterHandle,
00615                                  &EnableDhcp,
00616                                  KeyValuePartialInformation,
00617                                  KeyValueInfo,
00618                                  sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG),
00619                                  &Unused);
00620         if (NT_SUCCESS(Status) && KeyValueInfo->DataLength == sizeof(ULONG) && (*(PULONG)KeyValueInfo->Data) == 0)
00621         {
00622             RegistryDataU.MaximumLength = 16 + sizeof(WCHAR);
00623             RegistryDataU.Buffer = (PWCHAR)KeyValueInfo->Data;
00624             
00625             /* Read the IP address */
00626             Status = ZwQueryValueKey(ParameterHandle,
00627                                      &IPAddress,
00628                                      KeyValuePartialInformation,
00629                                      KeyValueInfo,
00630                                      sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 16 * sizeof(WCHAR),
00631                                      &Unused);
00632             if (NT_SUCCESS(Status))
00633             {
00634                 RegistryDataU.Length = KeyValueInfo->DataLength;
00635                 
00636                 RtlUnicodeStringToAnsiString(&RegistryDataA,
00637                                              &RegistryDataU,
00638                                              TRUE);
00639                 
00640                 AddrInitIPv4(&Interface->Unicast, inet_addr(RegistryDataA.Buffer));
00641                 
00642                 RtlFreeAnsiString(&RegistryDataA);
00643             }
00644 
00645             Status = ZwQueryValueKey(ParameterHandle,
00646                                      &Netmask,
00647                                      KeyValuePartialInformation,
00648                                      KeyValueInfo,
00649                                      sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 16 * sizeof(WCHAR),
00650                                      &Unused);
00651             if (NT_SUCCESS(Status))
00652             {
00653                 RegistryDataU.Length = KeyValueInfo->DataLength;
00654                 
00655                 RtlUnicodeStringToAnsiString(&RegistryDataA,
00656                                              &RegistryDataU,
00657                                              TRUE);
00658                 
00659                 AddrInitIPv4(&Interface->Netmask, inet_addr(RegistryDataA.Buffer));
00660                 
00661                 RtlFreeAnsiString(&RegistryDataA);
00662             }
00663             
00664             /* We have to wait until both IP address and subnet mask
00665              * are read to add the interface route, but we must do it
00666              * before we add the default gateway */
00667             if (!AddrIsUnspecified(&Interface->Unicast) &&
00668                 !AddrIsUnspecified(&Interface->Netmask))
00669                 IPAddInterfaceRoute(Interface);
00670             
00671             /* Read default gateway info */
00672             Status = ZwQueryValueKey(ParameterHandle,
00673                                      &Gateway,
00674                                      KeyValuePartialInformation,
00675                                      KeyValueInfo,
00676                                      sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 16 * sizeof(WCHAR),
00677                                      &Unused);
00678             if (NT_SUCCESS(Status))
00679             {
00680                 RegistryDataU.Length = KeyValueInfo->DataLength;
00681                 
00682                 RtlUnicodeStringToAnsiString(&RegistryDataA,
00683                                              &RegistryDataU,
00684                                              TRUE);
00685                 
00686                 AddrInitIPv4(&Router, inet_addr(RegistryDataA.Buffer));
00687                 
00688                 if (!AddrIsUnspecified(&Router))
00689                     RouterCreateRoute(&DefaultMask, &DefaultMask, &Router, Interface, 1);
00690                 
00691                 RtlFreeAnsiString(&RegistryDataA);
00692             }
00693         }
00694         
00695         ZwClose(ParameterHandle);
00696     }
00697     
00698     return TRUE;
00699 }
00700 
00701 BOOLEAN ReconfigureAdapter(PRECONFIGURE_CONTEXT Context)
00702 {
00703     PLAN_ADAPTER Adapter = Context->Adapter;
00704     PIP_INTERFACE Interface = Adapter->Context;
00705     //NDIS_STATUS NdisStatus;
00706     IP_ADDRESS DefaultMask;
00707 
00708     /* Initalize the default unspecified address (0.0.0.0) */
00709     AddrInitIPv4(&DefaultMask, 0);
00710     if (Context->State == LAN_STATE_STARTED &&
00711         !Context->Adapter->CompletingReset)
00712     {
00713         /* Read the IP configuration */
00714         ReadIpConfiguration(Interface);
00715 
00716         /* Compute the broadcast address */
00717         Interface->Broadcast.Type = IP_ADDRESS_V4;
00718         Interface->Broadcast.Address.IPv4Address = Interface->Unicast.Address.IPv4Address |
00719                                                   ~Interface->Netmask.Address.IPv4Address;
00720     }
00721     else if (!Context->Adapter->CompletingReset)
00722     {
00723         /* Clear IP configuration */
00724         Interface->Unicast = DefaultMask;
00725         Interface->Netmask = DefaultMask;
00726         Interface->Broadcast = DefaultMask;
00727         
00728         /* Remove all interface routes */
00729         RouterRemoveRoutesForInterface(Interface);
00730         
00731         /* Destroy all cached neighbors */
00732         NBDestroyNeighborsForInterface(Interface);
00733     }
00734     
00735     Context->Adapter->CompletingReset = FALSE;
00736 
00737     /* Update the IP and link status information cached in TCP */
00738     TCPUpdateInterfaceIPInformation(Interface);
00739     TCPUpdateInterfaceLinkStatus(Interface);
00740 
00741     /* We're done here if the adapter isn't connected */
00742     if (Context->State != LAN_STATE_STARTED)
00743     {
00744         Adapter->State = Context->State;
00745         return TRUE;
00746     }
00747     
00748     /* NDIS Bug! */
00749 #if 0
00750     /* Get maximum link speed */
00751     NdisStatus = NDISCall(Adapter,
00752                           NdisRequestQueryInformation,
00753                           OID_GEN_LINK_SPEED,
00754                           &Interface->Speed,
00755                           sizeof(UINT));
00756     
00757     if (!NT_SUCCESS(NdisStatus))
00758         Interface->Speed = IP_DEFAULT_LINK_SPEED;
00759 
00760     Adapter->Speed = Interface->Speed * 100L;
00761     
00762     /* Get maximum frame size */
00763     NdisStatus = NDISCall(Adapter,
00764                           NdisRequestQueryInformation,
00765                           OID_GEN_MAXIMUM_FRAME_SIZE,
00766                           &Adapter->MTU,
00767                           sizeof(UINT));
00768     if (NdisStatus != NDIS_STATUS_SUCCESS)
00769         return FALSE;
00770     
00771     Interface->MTU = Adapter->MTU;
00772     
00773     /* Get maximum packet size */
00774     NdisStatus = NDISCall(Adapter,
00775                           NdisRequestQueryInformation,
00776                           OID_GEN_MAXIMUM_TOTAL_SIZE,
00777                           &Adapter->MaxPacketSize,
00778                           sizeof(UINT));
00779     if (NdisStatus != NDIS_STATUS_SUCCESS)
00780         return FALSE;
00781 #endif
00782 
00783     Adapter->State = Context->State;
00784     
00785     return TRUE;
00786 }
00787 
00788 VOID ReconfigureAdapterWorker(PVOID Context)
00789 {
00790     PRECONFIGURE_CONTEXT ReconfigureContext = Context;
00791     
00792     /* Complete the reconfiguration asynchronously */
00793     ReconfigureAdapter(ReconfigureContext);
00794     
00795     /* Free the context */
00796     ExFreePool(ReconfigureContext);
00797 }
00798 
00799 VOID NTAPI ProtocolStatus(
00800     NDIS_HANDLE BindingContext,
00801     NDIS_STATUS GeneralStatus,
00802     PVOID StatusBuffer,
00803     UINT StatusBufferSize)
00804 /*
00805  * FUNCTION: Called by NDIS when the underlying driver has changed state
00806  * ARGUMENTS:
00807  *     BindingContext   = Pointer to a device context (LAN_ADAPTER)
00808  *     GeneralStatus    = A general status code
00809  *     StatusBuffer     = Pointer to a buffer with medium-specific data
00810  *     StatusBufferSize = Number of bytes in StatusBuffer
00811  */
00812 {
00813     PLAN_ADAPTER Adapter = BindingContext;
00814     PRECONFIGURE_CONTEXT Context;
00815 
00816     TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
00817 
00818     /* Ignore the status indication if we have no context yet. We'll get another later */
00819     if (!Adapter->Context)
00820         return;
00821     
00822     Context = ExAllocatePool(NonPagedPool, sizeof(RECONFIGURE_CONTEXT));
00823     if (!Context)
00824         return;
00825     
00826     Context->Adapter = Adapter;
00827 
00828     switch(GeneralStatus)
00829     {
00830         case NDIS_STATUS_MEDIA_CONNECT:
00831             DbgPrint("NDIS_STATUS_MEDIA_CONNECT\n");
00832 
00833             if (Adapter->State == LAN_STATE_STARTED)
00834             {
00835                 ExFreePool(Context);
00836                 return;
00837             }
00838 
00839             Context->State = LAN_STATE_STARTED;
00840             break;
00841             
00842         case NDIS_STATUS_MEDIA_DISCONNECT:
00843             DbgPrint("NDIS_STATUS_MEDIA_DISCONNECT\n");
00844             
00845             if (Adapter->State == LAN_STATE_STOPPED)
00846             {
00847                 ExFreePool(Context);
00848                 return;
00849             }
00850             
00851             Context->State = LAN_STATE_STOPPED;
00852             break;
00853 
00854         case NDIS_STATUS_RESET_START:
00855             Adapter->OldState = Adapter->State;
00856             Adapter->State = LAN_STATE_RESETTING;
00857             /* Nothing else to do here */
00858             ExFreePool(Context);
00859             return;
00860 
00861         case NDIS_STATUS_RESET_END:
00862             Adapter->CompletingReset = TRUE;
00863             Context->State = Adapter->OldState;
00864             break;
00865 
00866         default:
00867             DbgPrint("Unhandled status: %x", GeneralStatus);
00868             ExFreePool(Context);
00869             return;
00870     }
00871 
00872     /* Queue the work item */
00873     if (!ChewCreate(ReconfigureAdapterWorker, Context))
00874         ExFreePool(Context);
00875 }
00876 
00877 VOID NTAPI ProtocolStatusComplete(NDIS_HANDLE NdisBindingContext)
00878 /*
00879  * FUNCTION: Called by NDIS when a status-change has occurred
00880  * ARGUMENTS:
00881  *     BindingContext = Pointer to a device context (LAN_ADAPTER)
00882  */
00883 {
00884     TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
00885 }
00886 
00887 NDIS_STATUS NTAPI
00888 ProtocolPnPEvent(
00889     NDIS_HANDLE NdisBindingContext,
00890     PNET_PNP_EVENT PnPEvent)
00891 {
00892     switch(PnPEvent->NetEvent)
00893     {
00894       case NetEventSetPower:
00895          DbgPrint("Device transitioned to power state %ld\n", PnPEvent->Buffer);
00896          return NDIS_STATUS_SUCCESS;
00897 
00898       case NetEventQueryPower:
00899          DbgPrint("Device wants to go into power state %ld\n", PnPEvent->Buffer);
00900          return NDIS_STATUS_SUCCESS;
00901 
00902       case NetEventQueryRemoveDevice:
00903          DbgPrint("Device is about to be removed\n");
00904          return NDIS_STATUS_SUCCESS;
00905 
00906       case NetEventCancelRemoveDevice:
00907          DbgPrint("Device removal cancelled\n");
00908          return NDIS_STATUS_SUCCESS;
00909 
00910       default:
00911          DbgPrint("Unhandled event type: %ld\n", PnPEvent->NetEvent);
00912          return NDIS_STATUS_SUCCESS;
00913     }
00914 }
00915 
00916 VOID NTAPI ProtocolBindAdapter(
00917     OUT PNDIS_STATUS   Status,
00918     IN  NDIS_HANDLE    BindContext,
00919     IN  PNDIS_STRING   DeviceName,
00920     IN  PVOID          SystemSpecific1,
00921     IN  PVOID          SystemSpecific2)
00922 /*
00923  * FUNCTION: Called by NDIS during NdisRegisterProtocol to set up initial
00924  *           bindings, and periodically thereafer as new adapters come online
00925  * ARGUMENTS:
00926  *     Status: Return value to NDIS
00927  *     BindContext: Handle provided by NDIS to track pending binding operations
00928  *     DeviceName: Name of the miniport device to bind to
00929  *     SystemSpecific1: Pointer to a registry path with protocol-specific configuration information
00930  *     SystemSpecific2: Unused & must not be touched
00931  */
00932 {    
00933     TI_DbgPrint(DEBUG_DATALINK, ("Called with registry path %wZ for %wZ\n", SystemSpecific1, DeviceName));
00934     *Status = LANRegisterAdapter(DeviceName, SystemSpecific1);
00935 }
00936 
00937 
00938 VOID LANTransmit(
00939     PVOID Context,
00940     PNDIS_PACKET NdisPacket,
00941     UINT Offset,
00942     PVOID LinkAddress,
00943     USHORT Type)
00944 /*
00945  * FUNCTION: Transmits a packet
00946  * ARGUMENTS:
00947  *     Context     = Pointer to context information (LAN_ADAPTER)
00948  *     NdisPacket  = Pointer to NDIS packet to send
00949  *     Offset      = Offset in packet where data starts
00950  *     LinkAddress = Pointer to link address of destination (NULL = broadcast)
00951  *     Type        = LAN protocol type (LAN_PROTO_*)
00952  */
00953 {
00954     NDIS_STATUS NdisStatus;
00955     PETH_HEADER EHeader;
00956     PCHAR Data, OldData;
00957     UINT Size, OldSize;
00958     PLAN_ADAPTER Adapter = (PLAN_ADAPTER)Context;
00959     KIRQL OldIrql;
00960     PNDIS_PACKET XmitPacket;
00961     PIP_INTERFACE Interface = Adapter->Context;
00962 
00963     TI_DbgPrint(DEBUG_DATALINK,
00964         ("Called( NdisPacket %x, Offset %d, Adapter %x )\n",
00965          NdisPacket, Offset, Adapter));
00966 
00967     if (Adapter->State != LAN_STATE_STARTED) {
00968         (*PC(NdisPacket)->DLComplete)(PC(NdisPacket)->Context, NdisPacket, NDIS_STATUS_NOT_ACCEPTED);
00969         return;
00970     }
00971 
00972     TI_DbgPrint(DEBUG_DATALINK,
00973         ("Adapter Address [%02x %02x %02x %02x %02x %02x]\n",
00974          Adapter->HWAddress[0] & 0xff,
00975          Adapter->HWAddress[1] & 0xff,
00976          Adapter->HWAddress[2] & 0xff,
00977          Adapter->HWAddress[3] & 0xff,
00978          Adapter->HWAddress[4] & 0xff,
00979          Adapter->HWAddress[5] & 0xff));
00980 
00981     GetDataPtr( NdisPacket, 0, &OldData, &OldSize );
00982 
00983     NdisStatus = AllocatePacketWithBuffer(&XmitPacket, NULL, OldSize + Adapter->HeaderSize);
00984     if (NdisStatus != NDIS_STATUS_SUCCESS) {
00985         (*PC(NdisPacket)->DLComplete)(PC(NdisPacket)->Context, NdisPacket, NDIS_STATUS_RESOURCES);
00986         return;
00987     }
00988 
00989     GetDataPtr(XmitPacket, 0, &Data, &Size);
00990 
00991     RtlCopyMemory(Data + Adapter->HeaderSize, OldData, OldSize);
00992 
00993     (*PC(NdisPacket)->DLComplete)(PC(NdisPacket)->Context, NdisPacket, NDIS_STATUS_SUCCESS);
00994 
00995     switch (Adapter->Media) {
00996         case NdisMedium802_3:
00997             EHeader = (PETH_HEADER)Data;
00998 
00999             if (LinkAddress) {
01000                 /* Unicast address */
01001                 RtlCopyMemory(EHeader->DstAddr, LinkAddress, IEEE_802_ADDR_LENGTH);
01002             } else {
01003                 /* Broadcast address */
01004                 RtlFillMemory(EHeader->DstAddr, IEEE_802_ADDR_LENGTH, 0xFF);
01005             }
01006 
01007             RtlCopyMemory(EHeader->SrcAddr, Adapter->HWAddress, IEEE_802_ADDR_LENGTH);
01008 
01009             switch (Type) {
01010                 case LAN_PROTO_IPv4:
01011                     EHeader->EType = ETYPE_IPv4;
01012                     break;
01013                 case LAN_PROTO_ARP:
01014                     EHeader->EType = ETYPE_ARP;
01015                     break;
01016                 case LAN_PROTO_IPv6:
01017                     EHeader->EType = ETYPE_IPv6;
01018                     break;
01019                 default:
01020                     ASSERT(FALSE);
01021                     return;
01022             }
01023             break;
01024 
01025         default:
01026             /* FIXME: Support other medias */
01027             break;
01028     }
01029 
01030     TI_DbgPrint( MID_TRACE, ("LinkAddress: %x\n", LinkAddress));
01031     if( LinkAddress ) {
01032         TI_DbgPrint
01033         ( MID_TRACE,
01034           ("Link Address [%02x %02x %02x %02x %02x %02x]\n",
01035            ((PCHAR)LinkAddress)[0] & 0xff,
01036            ((PCHAR)LinkAddress)[1] & 0xff,
01037            ((PCHAR)LinkAddress)[2] & 0xff,
01038            ((PCHAR)LinkAddress)[3] & 0xff,
01039            ((PCHAR)LinkAddress)[4] & 0xff,
01040            ((PCHAR)LinkAddress)[5] & 0xff));
01041     }
01042 
01043     if (Adapter->MTU < Size) {
01044         /* This is NOT a pointer. MSDN explicitly says so. */
01045         NDIS_PER_PACKET_INFO_FROM_PACKET(NdisPacket,
01046                                          TcpLargeSendPacketInfo) = (PVOID)((ULONG_PTR)Adapter->MTU);
01047     }
01048 
01049     /* Update interface stats */
01050     Interface->Stats.OutBytes += Size;
01051 
01052     TcpipAcquireSpinLock( &Adapter->Lock, &OldIrql );
01053     TI_DbgPrint(MID_TRACE, ("NdisSend\n"));
01054     NdisSend(&NdisStatus, Adapter->NdisHandle, XmitPacket);
01055     TI_DbgPrint(MID_TRACE, ("NdisSend %s\n",
01056                 NdisStatus == NDIS_STATUS_PENDING ?
01057                 "Pending" : "Complete"));
01058     TcpipReleaseSpinLock( &Adapter->Lock, OldIrql );
01059 
01060     /* I had a talk with vizzini: these really ought to be here.
01061      * we're supposed to see these completed by ndis *only* when
01062      * status_pending is returned.  Note that this is different from
01063      * the situation with IRPs. */
01064         if (NdisStatus != NDIS_STATUS_PENDING)
01065             ProtocolSendComplete((NDIS_HANDLE)Context, XmitPacket, NdisStatus);
01066 }
01067 
01068 static NTSTATUS
01069 OpenRegistryKey( PNDIS_STRING RegistryPath, PHANDLE RegHandle ) {
01070     OBJECT_ATTRIBUTES Attributes;
01071     NTSTATUS Status;
01072 
01073     InitializeObjectAttributes(&Attributes, RegistryPath, OBJ_CASE_INSENSITIVE, 0, 0);
01074     Status = ZwOpenKey(RegHandle, KEY_ALL_ACCESS, &Attributes);
01075     return Status;
01076 }
01077 
01078 static NTSTATUS ReadStringFromRegistry( HANDLE RegHandle,
01079                     PWCHAR RegistryValue,
01080                     PUNICODE_STRING String ) {
01081     UNICODE_STRING ValueName;
01082     UNICODE_STRING UnicodeString;
01083     NTSTATUS Status;
01084     ULONG ResultLength;
01085     UCHAR buf[1024];
01086     PKEY_VALUE_PARTIAL_INFORMATION Information = (PKEY_VALUE_PARTIAL_INFORMATION)buf;
01087 
01088     RtlInitUnicodeString(&ValueName, RegistryValue);
01089     Status =
01090     ZwQueryValueKey(RegHandle,
01091             &ValueName,
01092             KeyValuePartialInformation,
01093             Information,
01094             sizeof(buf),
01095             &ResultLength);
01096 
01097     if (!NT_SUCCESS(Status))
01098     return Status;
01099     /* IP address is stored as a REG_MULTI_SZ - we only pay attention to the first one though */
01100     TI_DbgPrint(MIN_TRACE, ("Information DataLength: 0x%x\n", Information->DataLength));
01101 
01102     UnicodeString.Buffer = (PWCHAR)&Information->Data;
01103     UnicodeString.Length = Information->DataLength - sizeof(WCHAR);
01104     UnicodeString.MaximumLength = Information->DataLength;
01105 
01106     String->Buffer =
01107     (PWCHAR)ExAllocatePool( NonPagedPool,
01108                 UnicodeString.MaximumLength + sizeof(WCHAR) );
01109 
01110     if( !String->Buffer ) return STATUS_NO_MEMORY;
01111 
01112     String->MaximumLength = UnicodeString.MaximumLength;
01113     RtlCopyUnicodeString( String, &UnicodeString );
01114 
01115     return STATUS_SUCCESS;
01116 }
01117 
01118 /*
01119  * Utility to copy and append two unicode strings.
01120  *
01121  * IN OUT PUNICODE_STRING ResultFirst -> First string and result
01122  * IN     PUNICODE_STRING Second      -> Second string to append
01123  * IN     BOOL            Deallocate  -> TRUE: Deallocate First string before
01124  *                                       overwriting.
01125  *
01126  * Returns NTSTATUS.
01127  */
01128 
01129 NTSTATUS NTAPI AppendUnicodeString(PUNICODE_STRING ResultFirst,
01130                    PUNICODE_STRING Second,
01131                    BOOLEAN Deallocate) {
01132     NTSTATUS Status;
01133     UNICODE_STRING Ustr = *ResultFirst;
01134     PWSTR new_string = ExAllocatePool
01135         (PagedPool,
01136          (ResultFirst->Length + Second->Length + sizeof(WCHAR)));
01137     if( !new_string ) {
01138     return STATUS_NO_MEMORY;
01139     }
01140     memcpy( new_string, ResultFirst->Buffer, ResultFirst->Length );
01141     memcpy( new_string + ResultFirst->Length / sizeof(WCHAR),
01142         Second->Buffer, Second->Length );
01143     if( Deallocate ) RtlFreeUnicodeString(ResultFirst);
01144     ResultFirst->Length = Ustr.Length + Second->Length;
01145     ResultFirst->MaximumLength = ResultFirst->Length;
01146     new_string[ResultFirst->Length / sizeof(WCHAR)] = 0;
01147     Status = RtlCreateUnicodeString(ResultFirst,new_string) ?
01148     STATUS_SUCCESS : STATUS_NO_MEMORY;
01149     ExFreePool(new_string);
01150     return Status;
01151 }
01152 
01153 static NTSTATUS CheckForDeviceDesc( PUNICODE_STRING EnumKeyName,
01154                                     PUNICODE_STRING TargetKeyName,
01155                                     PUNICODE_STRING Name,
01156                                     PUNICODE_STRING DeviceDesc ) {
01157     UNICODE_STRING RootDevice = { 0, 0, NULL }, LinkageKeyName = { 0, 0, NULL };
01158     UNICODE_STRING DescKeyName = { 0, 0, NULL }, Linkage = { 0, 0, NULL };
01159     UNICODE_STRING BackSlash = { 0, 0, NULL };
01160     HANDLE DescKey = NULL, LinkageKey = NULL;
01161     NTSTATUS Status;
01162 
01163     TI_DbgPrint(DEBUG_DATALINK,("EnumKeyName %wZ\n", EnumKeyName));
01164 
01165     RtlInitUnicodeString(&BackSlash, L"\\");
01166     RtlInitUnicodeString(&Linkage, L"\\Linkage");
01167 
01168     RtlInitUnicodeString(&DescKeyName, L"");
01169     AppendUnicodeString( &DescKeyName, EnumKeyName, FALSE );
01170     AppendUnicodeString( &DescKeyName, &BackSlash, TRUE );
01171     AppendUnicodeString( &DescKeyName, TargetKeyName, TRUE );
01172 
01173     RtlInitUnicodeString(&LinkageKeyName, L"");
01174     AppendUnicodeString( &LinkageKeyName, &DescKeyName, FALSE );
01175     AppendUnicodeString( &LinkageKeyName, &Linkage, TRUE );
01176 
01177     Status = OpenRegistryKey( &LinkageKeyName, &LinkageKey );
01178     if( !NT_SUCCESS(Status) ) goto cleanup;
01179 
01180     Status = ReadStringFromRegistry( LinkageKey, L"RootDevice", &RootDevice );
01181     if( !NT_SUCCESS(Status) ) goto cleanup;
01182 
01183     if( RtlCompareUnicodeString( &RootDevice, Name, TRUE ) == 0 ) {
01184         Status = OpenRegistryKey( &DescKeyName, &DescKey );
01185         if( !NT_SUCCESS(Status) ) goto cleanup;
01186 
01187         Status = ReadStringFromRegistry( DescKey, L"DriverDesc", DeviceDesc );
01188         if( !NT_SUCCESS(Status) ) goto cleanup;
01189 
01190         TI_DbgPrint(DEBUG_DATALINK,("ADAPTER DESC: %wZ\n", DeviceDesc));
01191     } else Status = STATUS_UNSUCCESSFUL;
01192 
01193 cleanup:
01194     RtlFreeUnicodeString( &RootDevice );
01195     RtlFreeUnicodeString( &LinkageKeyName );
01196     RtlFreeUnicodeString( &DescKeyName );
01197     if( LinkageKey ) NtClose( LinkageKey );
01198     if( DescKey ) NtClose( DescKey );
01199 
01200     TI_DbgPrint(DEBUG_DATALINK,("Returning %x\n", Status));
01201 
01202     return Status;
01203 }
01204 
01205 static NTSTATUS FindDeviceDescForAdapter( PUNICODE_STRING Name,
01206                                           PUNICODE_STRING DeviceDesc ) {
01207     UNICODE_STRING EnumKeyName, TargetKeyName;
01208     HANDLE EnumKey;
01209     NTSTATUS Status;
01210     ULONG i;
01211     KEY_BASIC_INFORMATION *Kbio =
01212         ExAllocatePool(NonPagedPool, sizeof(KEY_BASIC_INFORMATION));
01213     ULONG KbioLength = sizeof(KEY_BASIC_INFORMATION), ResultLength;
01214 
01215     RtlInitUnicodeString( DeviceDesc, NULL );
01216 
01217     if( !Kbio ) return STATUS_INSUFFICIENT_RESOURCES;
01218 
01219     RtlInitUnicodeString
01220         (&EnumKeyName, CCS_ROOT L"\\Control\\Class\\" TCPIP_GUID);
01221 
01222     Status = OpenRegistryKey( &EnumKeyName, &EnumKey );
01223 
01224     if( !NT_SUCCESS(Status) ) {
01225         TI_DbgPrint(DEBUG_DATALINK,("Couldn't open Enum key %wZ: %x\n",
01226                                     &EnumKeyName, Status));
01227         ExFreePool( Kbio );
01228         return Status;
01229     }
01230 
01231     for( i = 0; NT_SUCCESS(Status); i++ ) {
01232         Status = ZwEnumerateKey( EnumKey, i, KeyBasicInformation,
01233                                  Kbio, KbioLength, &ResultLength );
01234 
01235         if( Status == STATUS_BUFFER_TOO_SMALL || Status == STATUS_BUFFER_OVERFLOW ) {
01236             ExFreePool( Kbio );
01237             KbioLength = ResultLength;
01238             Kbio = ExAllocatePool( NonPagedPool, KbioLength );
01239             if( !Kbio ) {
01240                 TI_DbgPrint(DEBUG_DATALINK,("Failed to allocate memory\n"));
01241                 NtClose( EnumKey );
01242                 return STATUS_NO_MEMORY;
01243             }
01244 
01245             Status = ZwEnumerateKey( EnumKey, i, KeyBasicInformation,
01246                                      Kbio, KbioLength, &ResultLength );
01247 
01248             if( !NT_SUCCESS(Status) ) {
01249                 TI_DbgPrint(DEBUG_DATALINK,("Couldn't enum key child %d\n", i));
01250                 NtClose( EnumKey );
01251                 ExFreePool( Kbio );
01252                 return Status;
01253             }
01254         }
01255 
01256         if( NT_SUCCESS(Status) ) {
01257             TargetKeyName.Length = TargetKeyName.MaximumLength =
01258                 Kbio->NameLength;
01259             TargetKeyName.Buffer = Kbio->Name;
01260 
01261             Status = CheckForDeviceDesc
01262                 ( &EnumKeyName, &TargetKeyName, Name, DeviceDesc );
01263             if( NT_SUCCESS(Status) ) {
01264                 NtClose( EnumKey );
01265                 ExFreePool( Kbio );
01266                 return Status;
01267             } else Status = STATUS_SUCCESS;
01268         }
01269     }
01270 
01271     NtClose( EnumKey );
01272     ExFreePool( Kbio );
01273     return STATUS_UNSUCCESSFUL;
01274 }
01275 
01276 VOID GetName( PUNICODE_STRING RegistryKey,
01277               PUNICODE_STRING OutName ) {
01278     PWCHAR Ptr;
01279     UNICODE_STRING PartialRegistryKey;
01280 
01281     PartialRegistryKey.Buffer =
01282         RegistryKey->Buffer + wcslen(CCS_ROOT L"\\Services\\");
01283     Ptr = PartialRegistryKey.Buffer;
01284 
01285     while( *Ptr != L'\\' &&
01286            ((PCHAR)Ptr) < ((PCHAR)RegistryKey->Buffer) + RegistryKey->Length )
01287         Ptr++;
01288 
01289     PartialRegistryKey.Length = PartialRegistryKey.MaximumLength =
01290         (Ptr - PartialRegistryKey.Buffer) * sizeof(WCHAR);
01291 
01292     RtlInitUnicodeString( OutName, L"" );
01293     AppendUnicodeString( OutName, &PartialRegistryKey, FALSE );
01294 }
01295 
01296 BOOLEAN BindAdapter(
01297     PLAN_ADAPTER Adapter,
01298     PNDIS_STRING RegistryPath)
01299 /*
01300  * FUNCTION: Binds a LAN adapter to IP layer
01301  * ARGUMENTS:
01302  *     Adapter = Pointer to LAN_ADAPTER structure
01303  * NOTES:
01304  *    We set the lookahead buffer size, set the packet filter and
01305  *    bind the adapter to IP layer
01306  */
01307 {
01308     PIP_INTERFACE IF;
01309     NDIS_STATUS NdisStatus;
01310     LLIP_BIND_INFO BindInfo;
01311     ULONG Lookahead = LOOKAHEAD_SIZE;
01312     NTSTATUS Status;
01313     NDIS_MEDIA_STATE MediaState;
01314 
01315     TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
01316 
01317     Adapter->State = LAN_STATE_OPENING;
01318 
01319     NdisStatus = NDISCall(Adapter,
01320                           NdisRequestSetInformation,
01321                           OID_GEN_CURRENT_LOOKAHEAD,
01322                           &Lookahead,
01323                           sizeof(ULONG));
01324     if (NdisStatus != NDIS_STATUS_SUCCESS) {
01325         TI_DbgPrint(DEBUG_DATALINK, ("Could not set lookahead buffer size (0x%X).\n", NdisStatus));
01326         return FALSE;
01327     }
01328 
01329     /* Bind the adapter to IP layer */
01330     BindInfo.Context       = Adapter;
01331     BindInfo.HeaderSize    = Adapter->HeaderSize;
01332     BindInfo.MinFrameSize  = Adapter->MinFrameSize;
01333     BindInfo.Address       = (PUCHAR)&Adapter->HWAddress;
01334     BindInfo.AddressLength = Adapter->HWAddressLength;
01335     BindInfo.Transmit      = LANTransmit;
01336 
01337     IF = IPCreateInterface(&BindInfo);
01338 
01339     if (!IF) {
01340         TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
01341         return FALSE;
01342     }
01343 
01344     /*
01345      * Query per-adapter configuration from the registry
01346      * In case anyone is curious:  there *is* an Ndis configuration api
01347      * for this sort of thing, but it doesn't really support things like
01348      * REG_MULTI_SZ very well, and there is a note in the DDK that says that
01349      * protocol drivers developed for win2k and above just use the native
01350      * services (ZwOpenKey, etc).
01351      */
01352 
01353     GetName( RegistryPath, &IF->Name );
01354 
01355     Status = FindDeviceDescForAdapter( &IF->Name, &IF->Description );
01356     if (!NT_SUCCESS(Status)) {
01357         TI_DbgPrint(MIN_TRACE, ("Failed to get device description.\n"));
01358         IPDestroyInterface(IF);
01359         return FALSE;
01360     }
01361 
01362     TI_DbgPrint(DEBUG_DATALINK,("Adapter Description: %wZ\n",
01363                 &IF->Description));
01364     
01365     /* Get maximum link speed */
01366     NdisStatus = NDISCall(Adapter,
01367                           NdisRequestQueryInformation,
01368                           OID_GEN_LINK_SPEED,
01369                           &IF->Speed,
01370                           sizeof(UINT));
01371     
01372     if (!NT_SUCCESS(NdisStatus))
01373         IF->Speed = IP_DEFAULT_LINK_SPEED;
01374     
01375     Adapter->Speed = IF->Speed * 100L;
01376     
01377     /* Get maximum frame size */
01378     NdisStatus = NDISCall(Adapter,
01379                           NdisRequestQueryInformation,
01380                           OID_GEN_MAXIMUM_FRAME_SIZE,
01381                           &Adapter->MTU,
01382                           sizeof(UINT));
01383     if (NdisStatus != NDIS_STATUS_SUCCESS)
01384         return FALSE;
01385     
01386     IF->MTU = Adapter->MTU;
01387     
01388     /* Get maximum packet size */
01389     NdisStatus = NDISCall(Adapter,
01390                           NdisRequestQueryInformation,
01391                           OID_GEN_MAXIMUM_TOTAL_SIZE,
01392                           &Adapter->MaxPacketSize,
01393                           sizeof(UINT));
01394     if (NdisStatus != NDIS_STATUS_SUCCESS)
01395         return FALSE;
01396 
01397     /* Register interface with IP layer */
01398     IPRegisterInterface(IF);
01399 
01400     /* Store adapter context */
01401     Adapter->Context = IF;
01402 
01403     /* Get the media state */
01404     NdisStatus = NDISCall(Adapter,
01405                           NdisRequestQueryInformation,
01406                           OID_GEN_MEDIA_CONNECT_STATUS,
01407                           &MediaState,
01408                           sizeof(MediaState));
01409     if (NdisStatus != NDIS_STATUS_SUCCESS) {
01410         TI_DbgPrint(DEBUG_DATALINK, ("Could not query media status (0x%X).\n", NdisStatus));
01411         IPUnregisterInterface(IF);
01412         IPDestroyInterface(IF);
01413         return FALSE;
01414     }
01415 
01416     /* Indicate the current media state */
01417     ProtocolStatus(Adapter,
01418                    (MediaState == NdisMediaStateConnected) ? NDIS_STATUS_MEDIA_CONNECT : NDIS_STATUS_MEDIA_DISCONNECT,
01419                    NULL, 0);
01420 
01421     /* Set packet filter so we can send and receive packets */
01422     NdisStatus = NDISCall(Adapter,
01423                           NdisRequestSetInformation,
01424                           OID_GEN_CURRENT_PACKET_FILTER,
01425                           &Adapter->PacketFilter,
01426                           sizeof(UINT));
01427 
01428     if (NdisStatus != NDIS_STATUS_SUCCESS) {
01429         TI_DbgPrint(DEBUG_DATALINK, ("Could not set packet filter (0x%X).\n", NdisStatus));
01430         IPUnregisterInterface(IF);
01431         IPDestroyInterface(IF);
01432         return FALSE;
01433     }
01434 
01435     return TRUE;
01436 }
01437 
01438 
01439 VOID UnbindAdapter(
01440     PLAN_ADAPTER Adapter)
01441 /*
01442  * FUNCTION: Unbinds a LAN adapter from IP layer
01443  * ARGUMENTS:
01444  *     Adapter = Pointer to LAN_ADAPTER structure
01445  */
01446 {
01447     TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
01448 
01449     if (Adapter->State == LAN_STATE_STARTED) {
01450         PIP_INTERFACE IF = Adapter->Context;
01451 
01452         IPUnregisterInterface(IF);
01453 
01454         IPDestroyInterface(IF);
01455     }
01456 }
01457 
01458 
01459 NDIS_STATUS LANRegisterAdapter(
01460     PNDIS_STRING AdapterName,
01461     PNDIS_STRING RegistryPath)
01462 /*
01463  * FUNCTION: Registers protocol with an NDIS adapter
01464  * ARGUMENTS:
01465  *     AdapterName = Pointer to string with name of adapter to register
01466  *     Adapter     = Address of pointer to a LAN_ADAPTER structure
01467  * RETURNS:
01468  *     Status of operation
01469  */
01470 {
01471     PLAN_ADAPTER IF;
01472     NDIS_STATUS NdisStatus;
01473     NDIS_STATUS OpenStatus;
01474     UINT MediaIndex;
01475     NDIS_MEDIUM MediaArray[MAX_MEDIA];
01476     UINT AddressOID;
01477 
01478     TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
01479 
01480     IF = ExAllocatePoolWithTag(NonPagedPool, sizeof(LAN_ADAPTER), LAN_ADAPTER_TAG);
01481     if (!IF) {
01482         TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
01483         return NDIS_STATUS_RESOURCES;
01484     }
01485 
01486     RtlZeroMemory(IF, sizeof(LAN_ADAPTER));
01487 
01488     /* Put adapter in stopped state */
01489     IF->State = LAN_STATE_STOPPED;
01490 
01491     /* Initialize protecting spin lock */
01492     KeInitializeSpinLock(&IF->Lock);
01493 
01494     KeInitializeEvent(&IF->Event, SynchronizationEvent, FALSE);
01495 
01496     /* Initialize array with media IDs we support */
01497     MediaArray[MEDIA_ETH] = NdisMedium802_3;
01498 
01499     TI_DbgPrint(DEBUG_DATALINK,("opening adapter %wZ\n", AdapterName));
01500     /* Open the adapter. */
01501     NdisOpenAdapter(&NdisStatus,
01502                     &OpenStatus,
01503                     &IF->NdisHandle,
01504                     &MediaIndex,
01505                     MediaArray,
01506                     MAX_MEDIA,
01507                     NdisProtocolHandle,
01508                     IF,
01509                     AdapterName,
01510                     0,
01511                     NULL);
01512 
01513     /* Wait until the adapter is opened */
01514     if (NdisStatus == NDIS_STATUS_PENDING)
01515         KeWaitForSingleObject(&IF->Event, UserRequest, KernelMode, FALSE, NULL);
01516     else if (NdisStatus != NDIS_STATUS_SUCCESS) {
01517     TI_DbgPrint(DEBUG_DATALINK,("denying adapter %wZ\n", AdapterName));
01518     ExFreePoolWithTag(IF, LAN_ADAPTER_TAG);
01519         return NdisStatus;
01520     }
01521 
01522     IF->Media = MediaArray[MediaIndex];
01523 
01524     /* Fill LAN_ADAPTER structure with some adapter specific information */
01525     switch (IF->Media) {
01526     case NdisMedium802_3:
01527         IF->HWAddressLength = IEEE_802_ADDR_LENGTH;
01528         IF->BCastMask       = BCAST_ETH_MASK;
01529         IF->BCastCheck      = BCAST_ETH_CHECK;
01530         IF->BCastOffset     = BCAST_ETH_OFFSET;
01531         IF->HeaderSize      = sizeof(ETH_HEADER);
01532         IF->MinFrameSize    = 60;
01533         AddressOID          = OID_802_3_CURRENT_ADDRESS;
01534         IF->PacketFilter    =
01535             NDIS_PACKET_TYPE_BROADCAST |
01536             NDIS_PACKET_TYPE_DIRECTED  |
01537             NDIS_PACKET_TYPE_MULTICAST;
01538         break;
01539 
01540     default:
01541         /* Unsupported media */
01542         TI_DbgPrint(MIN_TRACE, ("Unsupported media.\n"));
01543         ExFreePoolWithTag(IF, LAN_ADAPTER_TAG);
01544         return NDIS_STATUS_NOT_SUPPORTED;
01545     }
01546 
01547     /* Get maximum number of packets we can pass to NdisSend(Packets) at one time */
01548     NdisStatus = NDISCall(IF,
01549                           NdisRequestQueryInformation,
01550                           OID_GEN_MAXIMUM_SEND_PACKETS,
01551                           &IF->MaxSendPackets,
01552                           sizeof(UINT));
01553     if (NdisStatus != NDIS_STATUS_SUCCESS)
01554         /* Legacy NIC drivers may not support this query, if it fails we
01555            assume it can send at least one packet per call to NdisSend(Packets) */
01556         IF->MaxSendPackets = 1;
01557 
01558     /* Get current hardware address */
01559     NdisStatus = NDISCall(IF,
01560                           NdisRequestQueryInformation,
01561                           AddressOID,
01562                           &IF->HWAddress,
01563                           IF->HWAddressLength);
01564     if (NdisStatus != NDIS_STATUS_SUCCESS) {
01565         TI_DbgPrint(MIN_TRACE, ("Query for current hardware address failed.\n"));
01566         ExFreePoolWithTag(IF, LAN_ADAPTER_TAG);
01567         return NdisStatus;
01568     }
01569 
01570     /* Bind adapter to IP layer */
01571     if( !BindAdapter(IF, RegistryPath) ) {
01572     TI_DbgPrint(DEBUG_DATALINK,("denying adapter %wZ (BindAdapter)\n", AdapterName));
01573     ExFreePoolWithTag(IF, LAN_ADAPTER_TAG);
01574     return NDIS_STATUS_NOT_ACCEPTED;
01575     }
01576 
01577     /* Add adapter to the adapter list */
01578     ExInterlockedInsertTailList(&AdapterListHead,
01579                                 &IF->ListEntry,
01580                                 &AdapterListLock);
01581 
01582     TI_DbgPrint(DEBUG_DATALINK, ("Leaving.\n"));
01583 
01584     return NDIS_STATUS_SUCCESS;
01585 }
01586 
01587 
01588 NDIS_STATUS LANUnregisterAdapter(
01589     PLAN_ADAPTER Adapter)
01590 /*
01591  * FUNCTION: Unregisters protocol with NDIS adapter
01592  * ARGUMENTS:
01593  *     Adapter = Pointer to a LAN_ADAPTER structure
01594  * RETURNS:
01595  *     Status of operation
01596  */
01597 {
01598     KIRQL OldIrql;
01599     NDIS_HANDLE NdisHandle;
01600     NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS;
01601 
01602     TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
01603 
01604     /* Unlink the adapter from the list */
01605     RemoveEntryList(&Adapter->ListEntry);
01606 
01607     /* Unbind adapter from IP layer */
01608     UnbindAdapter(Adapter);
01609 
01610     TcpipAcquireSpinLock(&Adapter->Lock, &OldIrql);
01611     NdisHandle = Adapter->NdisHandle;
01612     if (NdisHandle) {
01613         Adapter->NdisHandle = NULL;
01614         TcpipReleaseSpinLock(&Adapter->Lock, OldIrql);
01615 
01616         NdisCloseAdapter(&NdisStatus, NdisHandle);
01617         if (NdisStatus == NDIS_STATUS_PENDING) {
01618             TcpipWaitForSingleObject(&Adapter->Event,
01619                                      UserRequest,
01620                                      KernelMode,
01621                                      FALSE,
01622                                      NULL);
01623             NdisStatus = Adapter->NdisStatus;
01624         }
01625     } else
01626         TcpipReleaseSpinLock(&Adapter->Lock, OldIrql);
01627 
01628     FreeAdapter(Adapter);
01629 
01630     return NdisStatus;
01631 }
01632 
01633 VOID 
01634 NTAPI
01635 LANUnregisterProtocol(VOID)
01636 /*
01637  * FUNCTION: Unregisters this protocol driver with NDIS
01638  * NOTES: Does not care wether we are already registered
01639  */
01640 {
01641     TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
01642 
01643     if (ProtocolRegistered) {
01644         NDIS_STATUS NdisStatus;
01645         PLIST_ENTRY CurrentEntry;
01646         PLIST_ENTRY NextEntry;
01647         PLAN_ADAPTER Current;
01648         KIRQL OldIrql;
01649 
01650         TcpipAcquireSpinLock(&AdapterListLock, &OldIrql);
01651 
01652         /* Search the list and remove every adapter we find */
01653         CurrentEntry = AdapterListHead.Flink;
01654         while (CurrentEntry != &AdapterListHead) {
01655             NextEntry = CurrentEntry->Flink;
01656             Current = CONTAINING_RECORD(CurrentEntry, LAN_ADAPTER, ListEntry);
01657             /* Unregister it */
01658             LANUnregisterAdapter(Current);
01659             CurrentEntry = NextEntry;
01660         }
01661 
01662         TcpipReleaseSpinLock(&AdapterListLock, OldIrql);
01663 
01664         NdisDeregisterProtocol(&NdisStatus, NdisProtocolHandle);
01665         ProtocolRegistered = FALSE;
01666     }
01667 }
01668 
01669 VOID
01670 NTAPI
01671 ProtocolUnbindAdapter(
01672     PNDIS_STATUS Status,
01673     NDIS_HANDLE ProtocolBindingContext,
01674     NDIS_HANDLE UnbindContext)
01675 {
01676     /* We don't pend any unbinding so we can just ignore UnbindContext */
01677     *Status = LANUnregisterAdapter((PLAN_ADAPTER)ProtocolBindingContext);
01678 }
01679 
01680 NTSTATUS LANRegisterProtocol(
01681     PNDIS_STRING Name)
01682 /*
01683  * FUNCTION: Registers this protocol driver with NDIS
01684  * ARGUMENTS:
01685  *     Name = Name of this protocol driver
01686  * RETURNS:
01687  *     Status of operation
01688  */
01689 {
01690     NDIS_STATUS NdisStatus;
01691     NDIS_PROTOCOL_CHARACTERISTICS ProtChars;
01692 
01693     TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
01694 
01695     InitializeListHead(&AdapterListHead);
01696     KeInitializeSpinLock(&AdapterListLock);
01697 
01698     /* Set up protocol characteristics */
01699     RtlZeroMemory(&ProtChars, sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
01700     ProtChars.MajorNdisVersion               = NDIS_VERSION_MAJOR;
01701     ProtChars.MinorNdisVersion               = NDIS_VERSION_MINOR;
01702     ProtChars.Name.Length                    = Name->Length;
01703     ProtChars.Name.Buffer                    = Name->Buffer;
01704     ProtChars.Name.MaximumLength             = Name->MaximumLength;
01705     ProtChars.OpenAdapterCompleteHandler     = ProtocolOpenAdapterComplete;
01706     ProtChars.CloseAdapterCompleteHandler    = ProtocolCloseAdapterComplete;
01707     ProtChars.ResetCompleteHandler           = ProtocolResetComplete;
01708     ProtChars.RequestCompleteHandler         = ProtocolRequestComplete;
01709     ProtChars.SendCompleteHandler            = ProtocolSendComplete;
01710     ProtChars.TransferDataCompleteHandler    = ProtocolTransferDataComplete;
01711     ProtChars.ReceivePacketHandler           = ProtocolReceivePacket;
01712     ProtChars.ReceiveHandler                 = ProtocolReceive;
01713     ProtChars.ReceiveCompleteHandler         = ProtocolReceiveComplete;
01714     ProtChars.StatusHandler                  = ProtocolStatus;
01715     ProtChars.StatusCompleteHandler          = ProtocolStatusComplete;
01716     ProtChars.BindAdapterHandler             = ProtocolBindAdapter;
01717     ProtChars.PnPEventHandler                = ProtocolPnPEvent;
01718     ProtChars.UnbindAdapterHandler           = ProtocolUnbindAdapter;
01719     ProtChars.UnloadHandler                  = LANUnregisterProtocol;
01720 
01721     /* Try to register protocol */
01722     NdisRegisterProtocol(&NdisStatus,
01723                          &NdisProtocolHandle,
01724                          &ProtChars,
01725                          sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
01726     if (NdisStatus != NDIS_STATUS_SUCCESS)
01727     {
01728         TI_DbgPrint(DEBUG_DATALINK, ("NdisRegisterProtocol failed, status 0x%x\n", NdisStatus));
01729         return (NTSTATUS)NdisStatus;
01730     }
01731 
01732     ProtocolRegistered = TRUE;
01733 
01734     return STATUS_SUCCESS;
01735 }
01736 
01737 /* EOF */

Generated on Sun May 27 2012 04:28:04 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.