summaryrefslogtreecommitdiffstats
path: root/private/ntos/tdi/isnp/ipx
diff options
context:
space:
mode:
Diffstat (limited to 'private/ntos/tdi/isnp/ipx')
-rw-r--r--private/ntos/tdi/isnp/ipx/action.c1802
-rw-r--r--private/ntos/tdi/isnp/ipx/adapter.c636
-rw-r--r--private/ntos/tdi/isnp/ipx/address.c1843
-rw-r--r--private/ntos/tdi/isnp/ipx/config.c1715
-rw-r--r--private/ntos/tdi/isnp/ipx/config.h132
-rw-r--r--private/ntos/tdi/isnp/ipx/device.c599
-rw-r--r--private/ntos/tdi/isnp/ipx/dirs22
-rw-r--r--private/ntos/tdi/isnp/ipx/driver.c4219
-rw-r--r--private/ntos/tdi/isnp/ipx/event.c143
-rw-r--r--private/ntos/tdi/isnp/ipx/ind.c4047
-rw-r--r--private/ntos/tdi/isnp/ipx/internal.c1233
-rw-r--r--private/ntos/tdi/isnp/ipx/ipxprocs.h1525
-rw-r--r--private/ntos/tdi/isnp/ipx/ipxtypes.h1999
-rw-r--r--private/ntos/tdi/isnp/ipx/isnipx.h531
-rw-r--r--private/ntos/tdi/isnp/ipx/loopback.c280
-rw-r--r--private/ntos/tdi/isnp/ipx/mac.c3793
-rw-r--r--private/ntos/tdi/isnp/ipx/mac.h44
-rw-r--r--private/ntos/tdi/isnp/ipx/mp/makefile6
-rw-r--r--private/ntos/tdi/isnp/ipx/mp/nwlnkipx.prf89
-rw-r--r--private/ntos/tdi/isnp/ipx/mp/sources29
-rw-r--r--private/ntos/tdi/isnp/ipx/ndis.c2204
-rw-r--r--private/ntos/tdi/isnp/ipx/nwlnkipx.ini191
-rw-r--r--private/ntos/tdi/isnp/ipx/nwlnkipx.rc12
-rw-r--r--private/ntos/tdi/isnp/ipx/packet.c1560
-rw-r--r--private/ntos/tdi/isnp/ipx/precomp.h44
-rw-r--r--private/ntos/tdi/isnp/ipx/query.c297
-rw-r--r--private/ntos/tdi/isnp/ipx/receive.c466
-rw-r--r--private/ntos/tdi/isnp/ipx/rip.c2655
-rw-r--r--private/ntos/tdi/isnp/ipx/send.c1651
-rw-r--r--private/ntos/tdi/isnp/ipx/sources.inc74
-rw-r--r--private/ntos/tdi/isnp/ipx/up/makefile6
-rw-r--r--private/ntos/tdi/isnp/ipx/up/nwlnkipx.prf89
-rw-r--r--private/ntos/tdi/isnp/ipx/up/sources29
33 files changed, 33965 insertions, 0 deletions
diff --git a/private/ntos/tdi/isnp/ipx/action.c b/private/ntos/tdi/isnp/ipx/action.c
new file mode 100644
index 000000000..807391cae
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/action.c
@@ -0,0 +1,1802 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ action.c
+
+Abstract:
+
+ This module contains code which performs the following TDI services:
+
+ o TdiAction
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+#include <packon.h>
+
+typedef struct _GET_PKT_SIZE {
+ ULONG Unknown;
+ ULONG MaxDatagramSize;
+} GET_PKT_SIZE, *PGET_PKT_SIZE;
+
+
+//
+// These structures are used to set and query information
+// about our source routing table.
+//
+
+typedef struct _SR_GET_PARAMETERS {
+ ULONG BoardNumber; // 0-based
+ ULONG SrDefault; // 0 = single route, 1 = all routes
+ ULONG SrBroadcast;
+ ULONG SrMulticast;
+} SR_GET_PARAMETERS, *PSR_GET_PARAMETERS;
+
+typedef struct _SR_SET_PARAMETER {
+ ULONG BoardNumber; // 0-based
+ ULONG Parameter; // 0 = single route, 1 = all routes
+} SR_SET_PARAMETER, *PSR_SET_PARAMETER;
+
+typedef struct _SR_SET_REMOVE {
+ ULONG BoardNumber; // 0-based
+ UCHAR MacAddress[6]; // remote to drop routing for
+} SR_SET_REMOVE, *PSR_SET_REMOVE;
+
+typedef struct _SR_SET_CLEAR {
+ ULONG BoardNumber; // 0-based
+} SR_SET_CLEAR, *PSR_SET_CLEAR;
+
+#include <packoff.h>
+
+typedef struct _ISN_ACTION_GET_DETAILS {
+ USHORT NicId; // passed by caller, returns count if it is 0
+ BOOLEAN BindingSet; // returns TRUE if in a set
+ UCHAR Type; // 1 = lan, 2 = up wan, 3 = down wan
+ ULONG FrameType; // returns 0 through 3
+ ULONG NetworkNumber; // returns virtual net if NicId is 0
+ UCHAR Node[6]; // adapter MAC address
+ WCHAR AdapterName[64]; // terminated with Unicode NULL
+} ISN_ACTION_GET_DETAILS, *PISN_ACTION_GET_DETAILS;
+
+
+
+NTSTATUS
+IpxTdiAction(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiAction request for the transport
+ provider.
+
+Arguments:
+
+ Device - The device for the operation.
+
+ Request - Describes the action request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PADDRESS_FILE AddressFile;
+ UINT BufferLength;
+ UINT DataLength;
+ PNDIS_BUFFER NdisBuffer;
+ CTELockHandle LockHandle;
+ PBINDING Binding, MasterBinding;
+ PADAPTER Adapter;
+ union {
+ PISN_ACTION_GET_LOCAL_TARGET GetLocalTarget;
+ PISN_ACTION_GET_NETWORK_INFO GetNetworkInfo;
+ PISN_ACTION_GET_DETAILS GetDetails;
+ PSR_GET_PARAMETERS GetSrParameters;
+ PSR_SET_PARAMETER SetSrParameter;
+ PSR_SET_REMOVE SetSrRemove;
+ PSR_SET_CLEAR SetSrClear;
+ PIPX_ADDRESS_DATA IpxAddressData;
+ PGET_PKT_SIZE GetPktSize;
+ PIPX_NETNUM_DATA IpxNetnumData;
+ } u; // BUGBUG: Make these unaligned??
+ PIPX_ROUTE_ENTRY RouteEntry;
+ PNWLINK_ACTION NwlinkAction;
+ ULONG Segment;
+ ULONG AdapterNum;
+ static UCHAR BogusId[4] = { 0x01, 0x00, 0x00, 0x00 }; // old nwrdr uses this
+
+#ifdef _PNP_POWER
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+#endif
+
+ //
+ // To maintain some compatibility with the NWLINK streams-
+ // based transport, we use the streams header format for
+ // our actions. The old transport expected the action header
+ // to be in InputBuffer and the output to go in OutputBuffer.
+ // We follow the TDI spec, which states that OutputBuffer
+ // is used for both input and output. Since IOCTL_TDI_ACTION
+ // is method out direct, this means that the output buffer
+ // is mapped by the MDL chain; for action the chain will
+ // only have one piece so we use it for input and output.
+ //
+
+ NdisBuffer = REQUEST_NDIS_BUFFER(Request);
+ if (NdisBuffer == NULL) {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ NdisQueryBuffer (REQUEST_NDIS_BUFFER(Request), (PVOID *)&NwlinkAction, &BufferLength);
+
+ if ((!RtlEqualMemory ((PVOID)(&NwlinkAction->Header.TransportId), "MISN", 4)) &&
+ (!RtlEqualMemory ((PVOID)(&NwlinkAction->Header.TransportId), "MIPX", 4)) &&
+ (!RtlEqualMemory ((PVOID)(&NwlinkAction->Header.TransportId), "XPIM", 4)) &&
+ (!RtlEqualMemory ((PVOID)(&NwlinkAction->Header.TransportId), BogusId, 4))) {
+
+ return STATUS_NOT_SUPPORTED;
+ }
+
+
+ //
+ // Make sure we have enough room for just the header not
+ // including the data.
+ //
+
+ if (BufferLength < (UINT)(FIELD_OFFSET(NWLINK_ACTION, Data[0]))) {
+ IPX_DEBUG (ACTION, ("Nwlink action failed, buffer too small\n"));
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ DataLength = BufferLength - FIELD_OFFSET(NWLINK_ACTION, Data[0]);
+
+
+ //
+ // Make sure that the correct file object is being used.
+ //
+
+ if (NwlinkAction->OptionType == NWLINK_OPTION_ADDRESS) {
+
+ if (REQUEST_OPEN_TYPE(Request) != (PVOID)TDI_TRANSPORT_ADDRESS_FILE) {
+ IPX_DEBUG (ACTION, ("Nwlink action failed, not address file\n"));
+ return STATUS_INVALID_HANDLE;
+ }
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+
+ if ((AddressFile->Size != sizeof (ADDRESS_FILE)) ||
+ (AddressFile->Type != IPX_ADDRESSFILE_SIGNATURE)) {
+
+ IPX_DEBUG (ACTION, ("Nwlink action failed, bad address file\n"));
+ return STATUS_INVALID_HANDLE;
+ }
+
+ } else if (NwlinkAction->OptionType != NWLINK_OPTION_CONTROL) {
+
+ IPX_DEBUG (ACTION, ("Nwlink action failed, option type %d\n", NwlinkAction->OptionType));
+ return STATUS_NOT_SUPPORTED;
+ }
+
+
+ //
+ // Handle the requests based on the action code. For these
+ // requests ActionHeader->ActionCode is 0, we use the
+ // Option field in the streams header instead.
+ //
+
+
+ Status = STATUS_SUCCESS;
+
+ switch (NwlinkAction->Option) {
+
+ //DbgPrint("NwlinkAction->Option is (%x)\n", NwlinkAction->Option);
+ //
+ // This first group support the winsock helper dll.
+ // In most cases the corresponding sockopt is shown in
+ // the comment, as well as the contents of the Data
+ // part of the action buffer.
+ //
+
+ case MIPX_SETSENDPTYPE:
+
+ //
+ // IPX_PTYPE: Data is a single byte packet type.
+ //
+
+ if (DataLength >= 1) {
+ IPX_DEBUG (ACTION, ("%lx: MIPX_SETSENDPTYPE %x\n", AddressFile, NwlinkAction->Data[0]));
+ AddressFile->DefaultPacketType = NwlinkAction->Data[0];
+ } else {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ break;
+
+ case MIPX_FILTERPTYPE:
+
+ //
+ // IPX_FILTERPTYPE: Data is a single byte to filter on.
+ //
+
+ if (DataLength >= 1) {
+ IPX_DEBUG (ACTION, ("%lx: MIPX_FILTERPTYPE %x\n", AddressFile, NwlinkAction->Data[0]));
+ AddressFile->FilteredType = NwlinkAction->Data[0];
+ AddressFile->FilterOnPacketType = TRUE;
+ AddressFile->SpecialReceiveProcessing = TRUE;
+ } else {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ break;
+
+ case MIPX_NOFILTERPTYPE:
+
+ //
+ // IPX_STOPFILTERPTYPE.
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_NOFILTERPTYPE\n", AddressFile));
+ AddressFile->FilterOnPacketType = FALSE;
+ AddressFile->SpecialReceiveProcessing = (BOOLEAN)
+ (AddressFile->ExtendedAddressing || AddressFile->ReceiveFlagsAddressing ||
+ AddressFile->ReceiveIpxHeader || AddressFile->IsSapSocket);
+ break;
+
+ case MIPX_SENDADDROPT:
+
+ //
+ // IPX_EXTENDED_ADDRESS (TRUE).
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_SENDADDROPT\n", AddressFile));
+ AddressFile->ExtendedAddressing = TRUE;
+ AddressFile->SpecialReceiveProcessing = TRUE;
+ break;
+
+ case MIPX_NOSENDADDROPT:
+
+ //
+ // IPX_EXTENDED_ADDRESS (FALSE).
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_NOSENDADDROPT\n", AddressFile));
+ AddressFile->ExtendedAddressing = FALSE;
+ AddressFile->SpecialReceiveProcessing = (BOOLEAN)
+ (AddressFile->ReceiveFlagsAddressing || AddressFile->ReceiveIpxHeader ||
+ AddressFile->FilterOnPacketType || AddressFile->IsSapSocket);
+ break;
+
+ case MIPX_SETRCVFLAGS:
+
+ //
+ // No sockopt yet.
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_SETRCVFLAGS\n", AddressFile));
+ AddressFile->ReceiveFlagsAddressing = TRUE;
+ AddressFile->SpecialReceiveProcessing = TRUE;
+ break;
+
+ case MIPX_NORCVFLAGS:
+
+ //
+ // No sockopt yet.
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_NORCVFLAGS\n", AddressFile));
+ AddressFile->ReceiveFlagsAddressing = FALSE;
+ AddressFile->SpecialReceiveProcessing = (BOOLEAN)
+ (AddressFile->ExtendedAddressing || AddressFile->ReceiveIpxHeader ||
+ AddressFile->FilterOnPacketType || AddressFile->IsSapSocket);
+ break;
+
+ case MIPX_SENDHEADER:
+
+ //
+ // IPX_RECVHDR (TRUE);
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_SENDHEADER\n", AddressFile));
+ AddressFile->ReceiveIpxHeader = TRUE;
+ AddressFile->SpecialReceiveProcessing = TRUE;
+ break;
+
+ case MIPX_NOSENDHEADER:
+
+ //
+ // IPX_RECVHDR (FALSE);
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_NOSENDHEADER\n", AddressFile));
+ AddressFile->ReceiveIpxHeader = FALSE;
+ AddressFile->SpecialReceiveProcessing = (BOOLEAN)
+ (AddressFile->ExtendedAddressing || AddressFile->ReceiveFlagsAddressing ||
+ AddressFile->FilterOnPacketType || AddressFile->IsSapSocket);
+ break;
+
+ case MIPX_RCVBCAST:
+
+ //
+ // Broadcast reception enabled.
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_RCVBCAST\n", AddressFile));
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ if (!AddressFile->EnableBroadcast) {
+
+ AddressFile->EnableBroadcast = TRUE;
+ IpxAddBroadcast (Device);
+ }
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ break;
+
+ case MIPX_NORCVBCAST:
+
+ //
+ // Broadcast reception disabled.
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_NORCVBCAST\n", AddressFile));
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ if (AddressFile->EnableBroadcast) {
+
+ AddressFile->EnableBroadcast = FALSE;
+ IpxRemoveBroadcast (Device);
+ }
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ break;
+
+ case MIPX_GETPKTSIZE:
+
+ //
+ // IPX_MAXSIZE.
+ //
+ // BUGBUG: Figure out what the first length is for.
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_GETPKTSIZE\n", AddressFile));
+ if (DataLength >= sizeof(GET_PKT_SIZE)) {
+ u.GetPktSize = (PGET_PKT_SIZE)(NwlinkAction->Data);
+ u.GetPktSize->Unknown = 0;
+ u.GetPktSize->MaxDatagramSize = Device->Information.MaxDatagramSize;
+ } else {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ break;
+
+ case MIPX_ADAPTERNUM:
+
+ //
+ // IPX_MAX_ADAPTER_NUM.
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_ADAPTERNUM\n", AddressFile));
+ if (DataLength >= sizeof(ULONG)) {
+ *(UNALIGNED ULONG *)(NwlinkAction->Data) = Device->SapNicCount;
+ } else {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ break;
+
+ case MIPX_ADAPTERNUM2:
+
+ //
+ // IPX_MAX_ADAPTER_NUM.
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_ADAPTERNUM2\n", AddressFile));
+ if (DataLength >= sizeof(ULONG)) {
+ *(UNALIGNED ULONG *)(NwlinkAction->Data) = MIN (Device->MaxBindings, Device->ValidBindings);
+ } else {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ break;
+
+ case MIPX_GETCARDINFO:
+ case MIPX_GETCARDINFO2:
+
+ //
+ // GETCARDINFO is IPX_ADDRESS.
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_GETCARDINFO (%d)\n",
+ AddressFile, *(UNALIGNED UINT *)NwlinkAction->Data));
+ if (DataLength >= sizeof(IPX_ADDRESS_DATA)) {
+ u.IpxAddressData = (PIPX_ADDRESS_DATA)(NwlinkAction->Data);
+ AdapterNum = u.IpxAddressData->adapternum+1;
+
+ if (((AdapterNum >= 1) && (AdapterNum <= Device->SapNicCount)) ||
+ ((NwlinkAction->Option == MIPX_GETCARDINFO2) && (AdapterNum <= (ULONG) MIN (Device->MaxBindings, Device->ValidBindings)))) {
+
+#ifdef _PNP_POWER
+// Get lock
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ Binding = NIC_ID_TO_BINDING(Device, AdapterNum);
+#else
+ Binding = Device->Bindings[AdapterNum];
+#endif
+ if (Binding == NULL) {
+
+ //
+ // This should be a binding in the WAN range
+ // of an adapter which is currently not
+ // allocated. We scan back to the previous
+ // non-NULL binding, which should be on the
+ // same adapter, and return a down line with
+ // the same characteristics as that binding.
+ //
+
+ UINT i = AdapterNum;
+
+ do {
+ --i;
+#ifdef _PNP_POWER
+ Binding = NIC_ID_TO_BINDING(Device, i);
+#else
+ Binding = Device->Bindings[i];
+#endif
+ } while (Binding == NULL);
+
+ CTEAssert (Binding->Adapter->MacInfo.MediumAsync);
+ CTEAssert (i >= Binding->Adapter->FirstWanNicId);
+ CTEAssert (AdapterNum <= Binding->Adapter->LastWanNicId);
+
+ u.IpxAddressData->status = FALSE;
+ *(UNALIGNED ULONG *)u.IpxAddressData->netnum = Binding->LocalAddress.NetworkAddress;
+
+ } else {
+
+ if ((Binding->Adapter->MacInfo.MediumAsync) &&
+ (Device->WanGlobalNetworkNumber)) {
+
+ //
+ // In this case we make it look like one big wan
+ // net, so the line is "up" or "down" depending
+ // on whether we have given him the first indication
+ // or not.
+ //
+
+ u.IpxAddressData->status = Device->GlobalNetworkIndicated;
+ *(UNALIGNED ULONG *)u.IpxAddressData->netnum = Device->GlobalWanNetwork;
+
+ } else {
+
+ u.IpxAddressData->status = Binding->LineUp;
+ *(UNALIGNED ULONG *)u.IpxAddressData->netnum = Binding->LocalAddress.NetworkAddress;
+ }
+
+ }
+
+ RtlCopyMemory(u.IpxAddressData->nodenum, Binding->LocalAddress.NodeAddress, 6);
+
+ Adapter = Binding->Adapter;
+ u.IpxAddressData->wan = Adapter->MacInfo.MediumAsync;
+ u.IpxAddressData->maxpkt =
+ (NwlinkAction->Option == MIPX_GETCARDINFO) ?
+ Binding->AnnouncedMaxDatagramSize :
+ Binding->RealMaxDatagramSize;
+ u.IpxAddressData->linkspeed = Binding->MediumSpeed;
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+ } else {
+
+ Status = STATUS_INVALID_PARAMETER;
+ }
+
+ } else {
+#if 1
+ //
+ // Support the old format query for now.
+ //
+
+ typedef struct _IPX_OLD_ADDRESS_DATA {
+ UINT adapternum;
+ UCHAR netnum[4];
+ UCHAR nodenum[6];
+ } IPX_OLD_ADDRESS_DATA, *PIPX_OLD_ADDRESS_DATA;
+
+ if (DataLength >= sizeof(IPX_OLD_ADDRESS_DATA)) {
+ u.IpxAddressData = (PIPX_ADDRESS_DATA)(NwlinkAction->Data);
+ AdapterNum = u.IpxAddressData->adapternum+1;
+
+ if ((AdapterNum >= 1) && (AdapterNum <= Device->SapNicCount)) {
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ if (Binding = NIC_ID_TO_BINDING(Device, AdapterNum)) {
+ *(UNALIGNED ULONG *)u.IpxAddressData->netnum = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory(u.IpxAddressData->nodenum, Binding->LocalAddress.NodeAddress, 6);
+ } else {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+ if (Binding = Device->Bindings[AdapterNum]) {
+ *(UNALIGNED ULONG *)u.IpxAddressData->netnum = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory(u.IpxAddressData->nodenum, Binding->LocalAddress.NodeAddress, 6);
+ } else {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+#endif
+ } else {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+ } else {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+#else
+ Status = STATUS_BUFFER_TOO_SMALL;
+#endif
+ }
+ break;
+
+ case MIPX_NOTIFYCARDINFO:
+
+ //
+ // IPX_ADDRESS_NOTIFY.
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_NOTIFYCARDINFO (%lx)\n", AddressFile, Request));
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ //
+ // If the device is open and there is room in the
+ // buffer for the data, insert it in our queue.
+ // It will be completed when a change happens or
+ // the driver is unloaded.
+ //
+
+ if (Device->State == DEVICE_STATE_OPEN) {
+ if (DataLength >= sizeof(IPX_ADDRESS_DATA)) {
+ InsertTailList(
+ &Device->AddressNotifyQueue,
+ REQUEST_LINKAGE(Request)
+ );
+ IoSetCancelRoutine (Request, IpxCancelAction);
+ if (Request->Cancel) {
+ (VOID)RemoveTailList (&Device->AddressNotifyQueue);
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ Status = STATUS_CANCELLED;
+ } else {
+ IpxReferenceDevice (Device, DREF_ADDRESS_NOTIFY);
+ Status = STATUS_PENDING;
+ }
+ } else {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ } else {
+ Status = STATUS_DEVICE_NOT_READY;
+ }
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ break;
+
+ case MIPX_LINECHANGE:
+
+ //
+ // IPX_ADDRESS_NOTIFY.
+ //
+
+ IPX_DEBUG (ACTION, ("MIPX_LINECHANGE (%lx)\n", Request));
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ //
+ // If the device is open and there is room in the
+ // buffer for the data, insert it in our queue.
+ // It will be completed when a change happens or
+ // the driver is unloaded.
+ //
+
+ if (Device->State == DEVICE_STATE_OPEN) {
+
+ InsertTailList(
+ &Device->LineChangeQueue,
+ REQUEST_LINKAGE(Request)
+ );
+
+ IoSetCancelRoutine (Request, IpxCancelAction);
+ if (Request->Cancel) {
+ (VOID)RemoveTailList (&Device->LineChangeQueue);
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ Status = STATUS_CANCELLED;
+ } else {
+ IpxReferenceDevice (Device, DREF_LINE_CHANGE);
+ Status = STATUS_PENDING;
+ }
+ } else {
+ Status = STATUS_DEVICE_NOT_READY;
+ }
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ break;
+
+ case MIPX_GETNETINFO_NR:
+
+ //
+ // A request for network information about the immediate
+ // route to a network (this is called by sockets apps).
+ //
+
+ if (DataLength < sizeof(IPX_NETNUM_DATA)) {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ u.IpxNetnumData = (PIPX_NETNUM_DATA)(NwlinkAction->Data);
+
+ //
+ // A query on network 0 means that the caller wants
+ // information about our directly attached net.
+ //
+
+ if (*(UNALIGNED ULONG *)u.IpxNetnumData->netnum == 0) {
+
+ //
+ // The tick count is the number of 1/18.21 second ticks
+ // it takes to deliver a 576-byte packet. Our link speed
+ // is in 100 bit-per-second units. We calculate it as
+ // follows (LS is the LinkSpeed):
+ //
+ // 576 bytes 8 bits 1 second 1821 ticks
+ // * ------ * ------------- * ----------
+ // 1 byte LS * 100 bits 100 seconds
+ //
+ // which becomes 839 / LinkSpeed -- we add LinkSpeed
+ // to the top to round up.
+ //
+
+ if (Device->LinkSpeed == 0) {
+ u.IpxNetnumData->netdelay = 16;
+ } else {
+ u.IpxNetnumData->netdelay = (USHORT)((839 + Device->LinkSpeed) /
+ (Device->LinkSpeed));
+ }
+ u.IpxNetnumData->hopcount = 0;
+ u.IpxNetnumData->cardnum = 0;
+ RtlMoveMemory (u.IpxNetnumData->router, Device->SourceAddress.NodeAddress, 6);
+
+ } else {
+
+
+#ifdef _PNP_POWER
+ Segment = RipGetSegment(u.IpxNetnumData->netnum);
+
+ //
+ // To maintain the lock order: BindAccessLock > RIP table
+ //
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ CTEGetLock (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // See which net card this is routed on.
+ //
+
+ RouteEntry = RipGetRoute (Segment, u.IpxNetnumData->netnum);
+ if ((RouteEntry != NULL) &&
+ (Binding = NIC_ID_TO_BINDING(Device, RouteEntry->NicId))) {
+
+ u.IpxNetnumData->hopcount = RouteEntry->HopCount;
+ u.IpxNetnumData->netdelay = RouteEntry->TickCount;
+ if (Binding->BindingSetMember) {
+ u.IpxNetnumData->cardnum = (INT)(MIN (Device->MaxBindings, Binding->MasterBinding->NicId) - 1);
+ } else {
+ u.IpxNetnumData->cardnum = (INT)(RouteEntry->NicId - 1);
+ }
+ RtlMoveMemory (u.IpxNetnumData->router, RouteEntry->NextRouter, 6);
+
+ } else {
+
+ //
+ // Fail the call, we don't have a route yet.
+ //
+
+ IPX_DEBUG (ACTION, ("MIPX_GETNETINFO_NR failed net %lx\n",
+ REORDER_ULONG(*(UNALIGNED ULONG *)(u.IpxNetnumData->netnum))));
+ Status = STATUS_BAD_NETWORK_PATH;
+
+ }
+ CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+#else
+ Segment = RipGetSegment(u.IpxNetnumData->netnum);
+
+ CTEGetLock (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // See which net card this is routed on.
+ //
+
+ RouteEntry = RipGetRoute (Segment, u.IpxNetnumData->netnum);
+ if ((RouteEntry != NULL) &&
+ (Binding = Device->Bindings[RouteEntry->NicId])) {
+
+ u.IpxNetnumData->hopcount = RouteEntry->HopCount;
+ u.IpxNetnumData->netdelay = RouteEntry->TickCount;
+ if (Binding->BindingSetMember) {
+ u.IpxNetnumData->cardnum = (INT)(Binding->MasterBinding->NicId - 1);
+ } else {
+ u.IpxNetnumData->cardnum = (INT)(RouteEntry->NicId - 1);
+ }
+ RtlMoveMemory (u.IpxNetnumData->router, RouteEntry->NextRouter, 6);
+
+ } else {
+
+ //
+ // Fail the call, we don't have a route yet.
+ //
+
+ IPX_DEBUG (ACTION, ("MIPX_GETNETINFO_NR failed net %lx\n",
+ REORDER_ULONG(*(UNALIGNED ULONG *)(u.IpxNetnumData->netnum))));
+ Status = STATUS_BAD_NETWORK_PATH;
+
+ }
+ CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
+#endif
+
+ }
+
+ break;
+
+ case MIPX_RERIPNETNUM:
+
+ //
+ // A request for network information about the immediate
+ // route to a network (this is called by sockets apps).
+ //
+
+ if (DataLength < sizeof(IPX_NETNUM_DATA)) {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ u.IpxNetnumData = (PIPX_NETNUM_DATA)(NwlinkAction->Data);
+
+ //
+ // BUGBUG: Allow net 0 queries??
+ //
+
+ if (*(UNALIGNED ULONG *)u.IpxNetnumData->netnum == 0) {
+
+ if (Device->LinkSpeed == 0) {
+ u.IpxNetnumData->netdelay = 16;
+ } else {
+ u.IpxNetnumData->netdelay = (USHORT)((839 + Device->LinkSpeed) /
+ (Device->LinkSpeed));
+ }
+ u.IpxNetnumData->hopcount = 0;
+ u.IpxNetnumData->cardnum = 0;
+ RtlMoveMemory (u.IpxNetnumData->router, Device->SourceAddress.NodeAddress, 6);
+
+ } else {
+
+ Segment = RipGetSegment(u.IpxNetnumData->netnum);
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ CTEGetLock (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // See which net card this is routed on.
+ //
+
+ RouteEntry = RipGetRoute (Segment, u.IpxNetnumData->netnum);
+
+ if ((RouteEntry != NULL) &&
+ (Binding = NIC_ID_TO_BINDING(Device, RouteEntry->NicId)) &&
+ (RouteEntry->Flags & IPX_ROUTER_PERMANENT_ENTRY)) {
+
+ u.IpxNetnumData->hopcount = RouteEntry->HopCount;
+ u.IpxNetnumData->netdelay = RouteEntry->TickCount;
+
+ if (Binding->BindingSetMember) {
+ u.IpxNetnumData->cardnum = (INT)(MIN (Device->MaxBindings, Binding->MasterBinding->NicId) - 1);
+ } else {
+ u.IpxNetnumData->cardnum = (INT)(RouteEntry->NicId - 1);
+ }
+ RtlMoveMemory (u.IpxNetnumData->router, RouteEntry->NextRouter, 6);
+
+ } else {
+
+ //
+ // This call will return STATUS_PENDING if we successfully
+ // queue a RIP request for the packet.
+ //
+
+ Status = RipQueueRequest (*(UNALIGNED ULONG *)u.IpxNetnumData->netnum, RIP_REQUEST);
+ CTEAssert (Status != STATUS_SUCCESS);
+
+ if (Status == STATUS_PENDING) {
+
+ //
+ // A RIP request went out on the network; we queue
+ // this request for completion when the RIP response
+ // arrives. We save the network in the information
+ // field for easier retrieval later.
+ //
+
+ REQUEST_INFORMATION(Request) = (ULONG)u.IpxNetnumData;
+ InsertTailList(
+ &Device->Segments[Segment].WaitingReripNetnum,
+ REQUEST_LINKAGE(Request));
+
+ IPX_DEBUG (ACTION, ("MIPX_RERIPNETNUM queued net %lx\n",
+ REORDER_ULONG(*(UNALIGNED ULONG *)(u.IpxNetnumData->netnum))));
+
+ }
+
+ }
+
+ CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+ CTEGetLock (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // See which net card this is routed on.
+ //
+
+ RouteEntry = RipGetRoute (Segment, u.IpxNetnumData->netnum);
+
+ if ((RouteEntry != NULL) &&
+ (Binding = Device->Bindings[RouteEntry->NicId]) &&
+ (RouteEntry->Flags & IPX_ROUTER_PERMANENT_ENTRY)) {
+
+ u.IpxNetnumData->hopcount = RouteEntry->HopCount;
+ u.IpxNetnumData->netdelay = RouteEntry->TickCount;
+
+ if (Binding->BindingSetMember) {
+ u.IpxNetnumData->cardnum = (INT)(Binding->MasterBinding->NicId - 1);
+ } else {
+ u.IpxNetnumData->cardnum = (INT)(RouteEntry->NicId - 1);
+ }
+ RtlMoveMemory (u.IpxNetnumData->router, RouteEntry->NextRouter, 6);
+
+ } else {
+
+ //
+ // This call will return STATUS_PENDING if we successfully
+ // queue a RIP request for the packet.
+ //
+
+ Status = RipQueueRequest (*(UNALIGNED ULONG *)u.IpxNetnumData->netnum, RIP_REQUEST);
+ CTEAssert (Status != STATUS_SUCCESS);
+
+ if (Status == STATUS_PENDING) {
+
+ //
+ // A RIP request went out on the network; we queue
+ // this request for completion when the RIP response
+ // arrives. We save the network in the information
+ // field for easier retrieval later.
+ //
+
+ REQUEST_INFORMATION(Request) = (ULONG)u.IpxNetnumData;
+ InsertTailList(
+ &Device->Segments[Segment].WaitingReripNetnum,
+ REQUEST_LINKAGE(Request));
+
+ IPX_DEBUG (ACTION, ("MIPX_RERIPNETNUM queued net %lx\n",
+ REORDER_ULONG(*(UNALIGNED ULONG *)(u.IpxNetnumData->netnum))));
+
+ }
+
+ }
+
+ CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
+#endif
+ }
+
+ break;
+
+ case MIPX_GETNETINFO:
+
+ //
+ // A request for network information about the immediate
+ // route to a network (this is called by sockets apps).
+ //
+
+ if (DataLength < sizeof(IPX_NETNUM_DATA)) {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ u.IpxNetnumData = (PIPX_NETNUM_DATA)(NwlinkAction->Data);
+
+ //
+ // BUGBUG: Allow net 0 queries??
+ //
+
+ if (*(UNALIGNED ULONG *)u.IpxNetnumData->netnum == 0) {
+
+ if (Device->LinkSpeed == 0) {
+ u.IpxNetnumData->netdelay = 16;
+ } else {
+ u.IpxNetnumData->netdelay = (USHORT)((839 + Device->LinkSpeed) /
+ (Device->LinkSpeed));
+ }
+ u.IpxNetnumData->hopcount = 0;
+ u.IpxNetnumData->cardnum = 0;
+ RtlMoveMemory (u.IpxNetnumData->router, Device->SourceAddress.NodeAddress, 6);
+
+ } else {
+
+ Segment = RipGetSegment(u.IpxNetnumData->netnum);
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ CTEGetLock (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // See which net card this is routed on.
+ //
+
+ RouteEntry = RipGetRoute (Segment, u.IpxNetnumData->netnum);
+
+ if ((RouteEntry != NULL) &&
+ (Binding = NIC_ID_TO_BINDING(Device, RouteEntry->NicId))) {
+
+ u.IpxNetnumData->hopcount = RouteEntry->HopCount;
+ u.IpxNetnumData->netdelay = RouteEntry->TickCount;
+
+ if (Binding->BindingSetMember) {
+ u.IpxNetnumData->cardnum = (INT)(MIN (Device->MaxBindings, Binding->MasterBinding->NicId) - 1);
+ } else {
+ u.IpxNetnumData->cardnum = (INT)(RouteEntry->NicId - 1);
+ }
+ RtlMoveMemory (u.IpxNetnumData->router, RouteEntry->NextRouter, 6);
+
+ } else {
+
+ //
+ // This call will return STATUS_PENDING if we successfully
+ // queue a RIP request for the packet.
+ //
+
+ Status = RipQueueRequest (*(UNALIGNED ULONG *)u.IpxNetnumData->netnum, RIP_REQUEST);
+ CTEAssert (Status != STATUS_SUCCESS);
+
+ if (Status == STATUS_PENDING) {
+
+ //
+ // A RIP request went out on the network; we queue
+ // this request for completion when the RIP response
+ // arrives. We save the network in the information
+ // field for easier retrieval later.
+ //
+
+ REQUEST_INFORMATION(Request) = (ULONG)u.IpxNetnumData;
+ InsertTailList(
+ &Device->Segments[Segment].WaitingReripNetnum,
+ REQUEST_LINKAGE(Request));
+
+ IPX_DEBUG (ACTION, ("MIPX_GETNETINFO queued net %lx\n",
+ REORDER_ULONG(*(UNALIGNED ULONG *)(u.IpxNetnumData->netnum))));
+
+ }
+
+ }
+
+ CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+ CTEGetLock (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // See which net card this is routed on.
+ //
+
+ RouteEntry = RipGetRoute (Segment, u.IpxNetnumData->netnum);
+
+ if ((RouteEntry != NULL) &&
+ (Binding = Device->Bindings[RouteEntry->NicId])) {
+
+ u.IpxNetnumData->hopcount = RouteEntry->HopCount;
+ u.IpxNetnumData->netdelay = RouteEntry->TickCount;
+
+ if (Binding->BindingSetMember) {
+ u.IpxNetnumData->cardnum = (INT)(Binding->MasterBinding->NicId - 1);
+ } else {
+ u.IpxNetnumData->cardnum = (INT)(RouteEntry->NicId - 1);
+ }
+ RtlMoveMemory (u.IpxNetnumData->router, RouteEntry->NextRouter, 6);
+
+ } else {
+
+ //
+ // This call will return STATUS_PENDING if we successfully
+ // queue a RIP request for the packet.
+ //
+
+ Status = RipQueueRequest (*(UNALIGNED ULONG *)u.IpxNetnumData->netnum, RIP_REQUEST);
+ CTEAssert (Status != STATUS_SUCCESS);
+
+ if (Status == STATUS_PENDING) {
+
+ //
+ // A RIP request went out on the network; we queue
+ // this request for completion when the RIP response
+ // arrives. We save the network in the information
+ // field for easier retrieval later.
+ //
+
+ REQUEST_INFORMATION(Request) = (ULONG)u.IpxNetnumData;
+ InsertTailList(
+ &Device->Segments[Segment].WaitingReripNetnum,
+ REQUEST_LINKAGE(Request));
+
+ IPX_DEBUG (ACTION, ("MIPX_GETNETINFO queued net %lx\n",
+ REORDER_ULONG(*(UNALIGNED ULONG *)(u.IpxNetnumData->netnum))));
+
+ }
+
+ }
+
+ CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
+#endif
+ }
+
+ break;
+
+ case MIPX_SENDPTYPE:
+ case MIPX_NOSENDPTYPE:
+
+ //
+ // For the moment just use OptionsLength >= 1 to indicate
+ // that the send options include the packet type.
+ //
+ // BUGBUG: Do we need to worry about card num being there?
+ //
+
+#if 0
+ IPX_DEBUG (ACTION, ("%lx: MIPS_%sSENDPTYPE\n", AddressFile,
+ NwlinkAction->Option == MIPX_SENDPTYPE ? "" : "NO"));
+#endif
+ break;
+
+ case MIPX_ZEROSOCKET:
+
+ //
+ // Sends from this address should be from socket 0;
+ // This is done the simple way by just putting the
+ // information in the address itself, instead of
+ // making it per address file (this is OK since
+ // this call is not exposed through winsock).
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_ZEROSOCKET\n", AddressFile));
+ AddressFile->Address->SendSourceSocket = 0;
+ AddressFile->Address->LocalAddress.Socket = 0;
+ break;
+
+
+ //
+ // This next batch are the source routing options. They
+ // are submitted by the IPXROUTE program.
+ //
+ // BUGBUG: Do we expose all binding set members to this?
+
+ case MIPX_SRGETPARMS:
+
+ if (DataLength >= sizeof(SR_GET_PARAMETERS)) {
+ u.GetSrParameters = (PSR_GET_PARAMETERS)(NwlinkAction->Data);
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ if (Binding = NIC_ID_TO_BINDING(Device, u.GetSrParameters->BoardNumber+1)) {
+
+ IPX_DEBUG (ACTION, ("MIPX_SRGETPARMS (%d)\n", u.GetSrParameters->BoardNumber+1));
+ u.GetSrParameters->SrDefault = (Binding->AllRouteDirected) ? 1 : 0;
+ u.GetSrParameters->SrBroadcast = (Binding->AllRouteBroadcast) ? 1 : 0;
+ u.GetSrParameters->SrMulticast = (Binding->AllRouteMulticast) ? 1 : 0;
+
+ } else {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+ if (Binding = Device->Bindings[u.GetSrParameters->BoardNumber+1]) {
+
+ IPX_DEBUG (ACTION, ("MIPX_SRGETPARMS (%d)\n", u.GetSrParameters->BoardNumber+1));
+ u.GetSrParameters->SrDefault = (Binding->AllRouteDirected) ? 1 : 0;
+ u.GetSrParameters->SrBroadcast = (Binding->AllRouteBroadcast) ? 1 : 0;
+ u.GetSrParameters->SrMulticast = (Binding->AllRouteMulticast) ? 1 : 0;
+
+ } else {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+#endif
+ } else {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+
+ break;
+
+ case MIPX_SRDEF:
+ case MIPX_SRBCAST:
+ case MIPX_SRMULTI:
+
+ if (DataLength >= sizeof(SR_SET_PARAMETER)) {
+ u.SetSrParameter = (PSR_SET_PARAMETER)(NwlinkAction->Data);
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ if (Binding = NIC_ID_TO_BINDING(Device, u.SetSrParameter->BoardNumber+1)) {
+ if (NwlinkAction->Option == MIPX_SRDEF) {
+
+ //
+ // BUGBUG: The compiler generates strange
+ // code which always makes this path be
+ // taken????
+ //
+
+ IPX_DEBUG (ACTION, ("MIPX_SRDEF %d (%d)\n",
+ u.SetSrParameter->Parameter, u.SetSrParameter->BoardNumber+1));
+ Binding->AllRouteDirected = (BOOLEAN)u.SetSrParameter->Parameter;
+
+ } else if (NwlinkAction->Option == MIPX_SRBCAST) {
+
+ IPX_DEBUG (ACTION, ("MIPX_SRBCAST %d (%d)\n",
+ u.SetSrParameter->Parameter, u.SetSrParameter->BoardNumber+1));
+ Binding->AllRouteBroadcast = (BOOLEAN)u.SetSrParameter->Parameter;
+
+ } else {
+
+ IPX_DEBUG (ACTION, ("MIPX_SRMCAST %d (%d)\n",
+ u.SetSrParameter->Parameter, u.SetSrParameter->BoardNumber+1));
+ Binding->AllRouteMulticast = (BOOLEAN)u.SetSrParameter->Parameter;
+
+ }
+
+ } else {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+ if (Binding = Device->Bindings[u.SetSrParameter->BoardNumber+1]) {
+ if (NwlinkAction->Option == MIPX_SRDEF) {
+
+ //
+ // BUGBUG: The compiler generates strange
+ // code which always makes this path be
+ // taken????
+ //
+
+ IPX_DEBUG (ACTION, ("MIPX_SRDEF %d (%d)\n",
+ u.SetSrParameter->Parameter, u.SetSrParameter->BoardNumber+1));
+ Binding->AllRouteDirected = (BOOLEAN)u.SetSrParameter->Parameter;
+
+ } else if (NwlinkAction->Option == MIPX_SRBCAST) {
+
+ IPX_DEBUG (ACTION, ("MIPX_SRBCAST %d (%d)\n",
+ u.SetSrParameter->Parameter, u.SetSrParameter->BoardNumber+1));
+ Binding->AllRouteBroadcast = (BOOLEAN)u.SetSrParameter->Parameter;
+
+ } else {
+
+ IPX_DEBUG (ACTION, ("MIPX_SRMCAST %d (%d)\n",
+ u.SetSrParameter->Parameter, u.SetSrParameter->BoardNumber+1));
+ Binding->AllRouteMulticast = (BOOLEAN)u.SetSrParameter->Parameter;
+
+ }
+
+ } else {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+#endif
+ } else {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+
+ break;
+
+ case MIPX_SRREMOVE:
+
+ if (DataLength >= sizeof(SR_SET_REMOVE)) {
+ u.SetSrRemove = (PSR_SET_REMOVE)(NwlinkAction->Data);
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ if (Binding = NIC_ID_TO_BINDING(Device, u.SetSrRemove->BoardNumber+1)) {
+
+ IPX_DEBUG (ACTION, ("MIPX_SRREMOVE %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x (%d)\n",
+ u.SetSrRemove->MacAddress[0],
+ u.SetSrRemove->MacAddress[1],
+ u.SetSrRemove->MacAddress[2],
+ u.SetSrRemove->MacAddress[3],
+ u.SetSrRemove->MacAddress[4],
+ u.SetSrRemove->MacAddress[5],
+ u.SetSrRemove->BoardNumber+1));
+ MacSourceRoutingRemove (Binding, u.SetSrRemove->MacAddress);
+
+ } else {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+ if (Binding = Device->Bindings[u.SetSrRemove->BoardNumber+1]) {
+
+ IPX_DEBUG (ACTION, ("MIPX_SRREMOVE %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x (%d)\n",
+ u.SetSrRemove->MacAddress[0],
+ u.SetSrRemove->MacAddress[1],
+ u.SetSrRemove->MacAddress[2],
+ u.SetSrRemove->MacAddress[3],
+ u.SetSrRemove->MacAddress[4],
+ u.SetSrRemove->MacAddress[5],
+ u.SetSrRemove->BoardNumber+1));
+ MacSourceRoutingRemove (Binding, u.SetSrRemove->MacAddress);
+
+ } else {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+#endif
+ } else {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+
+ break;
+
+ case MIPX_SRCLEAR:
+
+ if (DataLength >= sizeof(SR_SET_CLEAR)) {
+ u.SetSrClear = (PSR_SET_CLEAR)(NwlinkAction->Data);
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ if (Binding = NIC_ID_TO_BINDING(Device, u.SetSrClear->BoardNumber+1)) {
+
+ IPX_DEBUG (ACTION, ("MIPX_SRCLEAR (%d)\n", u.SetSrClear->BoardNumber+1));
+ MacSourceRoutingClear (Binding);
+
+ } else {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+ if (Binding = Device->Bindings[u.SetSrClear->BoardNumber+1]) {
+
+ IPX_DEBUG (ACTION, ("MIPX_SRCLEAR (%d)\n", u.SetSrClear->BoardNumber+1));
+ MacSourceRoutingClear (Binding);
+
+ } else {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+#endif
+ } else {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+
+ break;
+
+
+ //
+ // These are new for ISN (not supported in NWLINK).
+ //
+
+ case MIPX_LOCALTARGET:
+
+ //
+ // A request for the local target for an IPX address.
+ //
+
+ if (DataLength < sizeof(ISN_ACTION_GET_LOCAL_TARGET)) {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ u.GetLocalTarget = (PISN_ACTION_GET_LOCAL_TARGET)(NwlinkAction->Data);
+ Segment = RipGetSegment((PUCHAR)&u.GetLocalTarget->IpxAddress.NetworkAddress);
+
+ CTEGetLock (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // See if this route is local.
+ //
+
+ RouteEntry = RipGetRoute (Segment, (PUCHAR)&u.GetLocalTarget->IpxAddress.NetworkAddress);
+
+ if ((RouteEntry != NULL) &&
+ (RouteEntry->Flags & IPX_ROUTER_PERMANENT_ENTRY)) {
+
+ //
+ // This is a local net, to send to it you just use
+ // the appropriate NIC ID and the real MAC address.
+ //
+
+ if ((RouteEntry->Flags & IPX_ROUTER_LOCAL_NET) == 0) {
+
+ //
+ // It's the virtual net, send via the first card.
+ //
+#ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(&u.GetLocalTarget->LocalTarget, 1);
+#else
+ u.GetLocalTarget->LocalTarget.NicId = 1;
+#endif
+
+ } else {
+
+#ifdef _PNP_POWER
+
+ CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ Binding = NIC_ID_TO_BINDING(Device, RouteEntry->NicId);
+
+ if (Binding->BindingSetMember) {
+
+ //
+ // It's a binding set member, we round-robin the
+ // responses across all the cards to distribute
+ // the traffic.
+ //
+
+ MasterBinding = Binding->MasterBinding;
+ Binding = MasterBinding->CurrentSendBinding;
+ MasterBinding->CurrentSendBinding = Binding->NextBinding;
+
+ FILL_LOCAL_TARGET(&u.GetLocalTarget->LocalTarget, MIN( Device->MaxBindings, Binding->NicId));
+
+ } else {
+
+ FILL_LOCAL_TARGET(&u.GetLocalTarget->LocalTarget, RouteEntry->NicId);
+
+ }
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+ Binding = Device->Bindings[RouteEntry->NicId];
+ if (Binding->BindingSetMember) {
+
+ //
+ // It's a binding set member, we round-robin the
+ // responses across all the cards to distribute
+ // the traffic.
+ //
+ MasterBinding = Binding->MasterBinding;
+ Binding = MasterBinding->CurrentSendBinding;
+ MasterBinding->CurrentSendBinding = Binding->NextBinding;
+
+ u.GetLocalTarget->LocalTarget.NicId = Binding->NicId;
+ } else {
+
+ u.GetLocalTarget->LocalTarget.NicId = RouteEntry->NicId;
+
+ }
+#endif
+
+ }
+
+ RtlCopyMemory(
+ u.GetLocalTarget->LocalTarget.MacAddress,
+ u.GetLocalTarget->IpxAddress.NodeAddress,
+ 6);
+
+ } else {
+
+ //
+ // This call will return STATUS_PENDING if we successfully
+ // queue a RIP request for the packet.
+ //
+
+ Status = RipQueueRequest (u.GetLocalTarget->IpxAddress.NetworkAddress, RIP_REQUEST);
+ CTEAssert (Status != STATUS_SUCCESS);
+
+ if (Status == STATUS_PENDING) {
+
+ //
+ // A RIP request went out on the network; we queue
+ // this request for completion when the RIP response
+ // arrives. We save the network in the information
+ // field for easier retrieval later.
+ //
+
+ REQUEST_INFORMATION(Request) = (ULONG)u.GetLocalTarget;
+ InsertTailList(
+ &Device->Segments[Segment].WaitingLocalTarget,
+ REQUEST_LINKAGE(Request));
+
+ }
+
+#ifdef _PNP_POWER
+ CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
+#endif
+ }
+#ifndef _PNP_POWER
+ CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
+#endif
+
+
+ break;
+
+ case MIPX_NETWORKINFO:
+
+ //
+ // A request for network information about the immediate
+ // route to a network.
+ //
+
+ if (DataLength < sizeof(ISN_ACTION_GET_NETWORK_INFO)) {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ u.GetNetworkInfo = (PISN_ACTION_GET_NETWORK_INFO)(NwlinkAction->Data);
+
+ if (u.GetNetworkInfo->Network == 0) {
+
+ //
+ // This is information about the local card.
+ //
+
+ u.GetNetworkInfo->LinkSpeed = Device->LinkSpeed * 12;
+ u.GetNetworkInfo->MaximumPacketSize = Device->Information.MaxDatagramSize;
+
+ } else {
+
+ Segment = RipGetSegment((PUCHAR)&u.GetNetworkInfo->Network);
+
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+#endif
+ CTEGetLock (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // See which net card this is routed on.
+ //
+
+ RouteEntry = RipGetRoute (Segment, (PUCHAR)&u.GetNetworkInfo->Network);
+
+ if ((RouteEntry != NULL) &&
+#ifdef _PNP_POWER
+ (Binding = NIC_ID_TO_BINDING(Device, RouteEntry->NicId))) {
+#else
+ (Binding = Device->Bindings[RouteEntry->NicId])) {
+#endif
+
+ //
+ // Our medium speed is stored in 100 bps, we
+ // convert to bytes/sec by multiplying by 12
+ // (should really be 100/8 = 12.5).
+ //
+
+ u.GetNetworkInfo->LinkSpeed = Binding->MediumSpeed * 12;
+ u.GetNetworkInfo->MaximumPacketSize = Binding->AnnouncedMaxDatagramSize;
+
+ } else {
+
+ //
+ // Fail the call, we don't have a route yet.
+ // BUGBUG: This requires that a packet has been
+ // sent to this net already; nwrdr says this is
+ // OK, they will send their connect request
+ // before they query. On the server it should
+ // have RIP running so all nets should be in
+ // the database.
+ //
+
+ Status = STATUS_BAD_NETWORK_PATH;
+
+ }
+
+ CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+ }
+
+ break;
+
+ case MIPX_CONFIG:
+
+ //
+ // A request for details on every binding.
+ //
+
+ if (DataLength < sizeof(ISN_ACTION_GET_DETAILS)) {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ u.GetDetails = (PISN_ACTION_GET_DETAILS)(NwlinkAction->Data);
+
+ if (u.GetDetails->NicId == 0) {
+
+ //
+ // This is information about the local card. We also
+ // tell him the total number of bindings in NicId.
+ //
+
+ u.GetDetails->NetworkNumber = Device->VirtualNetworkNumber;
+ u.GetDetails->NicId = (USHORT)MIN (Device->MaxBindings, Device->ValidBindings);
+
+ } else {
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ Binding = NIC_ID_TO_BINDING(Device, u.GetDetails->NicId);
+#else
+ Binding = Device->Bindings[u.GetDetails->NicId];
+#endif
+
+ if ((Binding != NULL) &&
+ (u.GetDetails->NicId <= MIN (Device->MaxBindings, Device->ValidBindings))) {
+
+ ULONG StringLoc;
+#ifdef _PNP_POWER
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+ u.GetDetails->NetworkNumber = Binding->LocalAddress.NetworkAddress;
+ if (Binding->Adapter->MacInfo.MediumType == NdisMediumArcnet878_2) {
+ u.GetDetails->FrameType = ISN_FRAME_TYPE_ARCNET;
+ } else {
+ u.GetDetails->FrameType = Binding->FrameType;
+ }
+ u.GetDetails->BindingSet = Binding->BindingSetMember;
+ if (Binding->Adapter->MacInfo.MediumAsync) {
+ if (Binding->LineUp) {
+ u.GetDetails->Type = 2;
+ } else {
+ u.GetDetails->Type = 3;
+ }
+ } else {
+ u.GetDetails->Type = 1;
+ }
+
+ RtlCopyMemory (u.GetDetails->Node, Binding->LocalMacAddress.Address, 6);
+
+ //
+ // Copy the adapter name, including the final NULL.
+ //
+
+ StringLoc = (Binding->Adapter->AdapterNameLength / sizeof(WCHAR)) - 2;
+ while (Binding->Adapter->AdapterName[StringLoc] != L'\\') {
+ --StringLoc;
+ }
+ RtlCopyMemory(
+ u.GetDetails->AdapterName,
+ &Binding->Adapter->AdapterName[StringLoc+1],
+ Binding->Adapter->AdapterNameLength - ((StringLoc+1) * sizeof(WCHAR)));
+
+#ifdef _PNP_POWER
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif
+ } else {
+
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+
+ Status = STATUS_INVALID_PARAMETER;
+
+ }
+ }
+
+ break;
+
+
+ //
+ // The Option was not supported, so fail.
+ //
+
+ default:
+
+ Status = STATUS_NOT_SUPPORTED;
+ break;
+
+
+ } // end of the long switch on NwlinkAction->Option
+
+
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ IPX_DEBUG (ACTION, ("Nwlink action %lx failed, status %lx\n", NwlinkAction->Option, Status));
+ }
+#endif
+
+ return Status;
+
+} /* IpxTdiAction */
+
+
+VOID
+IpxCancelAction(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to cancel an Action.
+ What is done to cancel it is specific to each action.
+
+ NOTE: This routine is called with the CancelSpinLock held and
+ is responsible for releasing it.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PDEVICE Device = IpxDevice;
+ PREQUEST Request = (PREQUEST)Irp;
+ CTELockHandle LockHandle;
+ PLIST_ENTRY p;
+ BOOLEAN Found;
+ UINT IOCTLType;
+
+ ASSERT( DeviceObject->DeviceExtension == IpxDevice );
+
+ //
+ // Find the request on the address notify queue.
+ //
+
+ Found = FALSE;
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ for (p = Device->AddressNotifyQueue.Flink;
+ p != &Device->AddressNotifyQueue;
+ p = p->Flink) {
+
+ if (LIST_ENTRY_TO_REQUEST(p) == Request) {
+
+ RemoveEntryList (p);
+ Found = TRUE;
+ IOCTLType = MIPX_NOTIFYCARDINFO;
+ break;
+ }
+ }
+
+ if (!Found) {
+ for (p = Device->LineChangeQueue.Flink;
+ p != &Device->LineChangeQueue;
+ p = p->Flink) {
+
+ if (LIST_ENTRY_TO_REQUEST(p) == Request) {
+
+ RemoveEntryList (p);
+ Found = TRUE;
+ IOCTLType = MIPX_LINECHANGE;
+ break;
+ }
+ }
+ }
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+ if (Found) {
+
+
+ REQUEST_INFORMATION(Request) = 0;
+ REQUEST_STATUS(Request) = STATUS_CANCELLED;
+
+ IpxCompleteRequest (Request);
+ IpxFreeRequest(Device, Request);
+ if (IOCTLType == MIPX_NOTIFYCARDINFO) {
+ IPX_DEBUG(ACTION, ("Cancelled action NOTIFYCARDINFO %lx\n", Request));
+ IpxDereferenceDevice (Device, DREF_ADDRESS_NOTIFY);
+ } else {
+ IPX_DEBUG(ACTION, ("Cancelled action LINECHANGE %lx\n", Request));
+ IpxDereferenceDevice (Device, DREF_LINE_CHANGE);
+ }
+
+ }
+#if DBG
+ else {
+ IPX_DEBUG(ACTION, ("Cancelled action orphan %lx\n", Request));
+ }
+#endif
+
+} /* IpxCancelAction */
+
+
+VOID
+IpxAbortLineChanges(
+ IN PVOID ControlChannelContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine aborts any line change IRPs posted by the
+ control channel with the specified open context. It is
+ called when a control channel is being shut down.
+
+Arguments:
+
+ ControlChannelContext - The context assigned to the control
+ channel when it was opened.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PDEVICE Device = IpxDevice;
+ CTELockHandle LockHandle;
+ LIST_ENTRY AbortList;
+ PLIST_ENTRY p;
+ PREQUEST Request;
+ KIRQL irql;
+
+
+ InitializeListHead (&AbortList);
+
+ IoAcquireCancelSpinLock( &irql );
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ p = Device->LineChangeQueue.Flink;
+
+ while (p != &Device->LineChangeQueue) {
+ LARGE_INTEGER ControlChId;
+
+ Request = LIST_ENTRY_TO_REQUEST(p);
+
+ CCID_FROM_REQUEST(ControlChId, Request);
+
+ p = p->Flink;
+
+ if (ControlChId.QuadPart == ((PLARGE_INTEGER)ControlChannelContext)->QuadPart) {
+ RemoveEntryList (REQUEST_LINKAGE(Request));
+ InsertTailList (&AbortList, REQUEST_LINKAGE(Request));
+ }
+ }
+
+ while (!IsListEmpty (&AbortList)) {
+
+ p = RemoveHeadList (&AbortList);
+ Request = LIST_ENTRY_TO_REQUEST(p);
+
+ IPX_DEBUG(ACTION, ("Aborting line change %lx\n", Request));
+
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+
+ REQUEST_INFORMATION(Request) = 0;
+ REQUEST_STATUS(Request) = STATUS_CANCELLED;
+
+ CTEFreeLock(&Device->Lock, LockHandle);
+ IoReleaseCancelSpinLock( irql );
+
+ IpxCompleteRequest (Request);
+ IpxFreeRequest(Device, Request);
+
+ IpxDereferenceDevice (Device, DREF_LINE_CHANGE);
+
+ IoAcquireCancelSpinLock( &irql );
+ CTEGetLock(&Device->Lock, &LockHandle);
+ }
+
+ CTEFreeLock(&Device->Lock, LockHandle);
+ IoReleaseCancelSpinLock( irql );
+} /* IpxAbortLineChanges */
+
diff --git a/private/ntos/tdi/isnp/ipx/adapter.c b/private/ntos/tdi/isnp/ipx/adapter.c
new file mode 100644
index 000000000..479570e48
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/adapter.c
@@ -0,0 +1,636 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ adapter.c
+
+Abstract:
+
+ This module contains code which implements the ADAPTER object.
+ Routines are provided to reference, and dereference transport
+ adapter objects.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+//
+// These are init only until binding is really dynamic.
+//
+#ifndef _PNP_POWER
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,IpxCreateAdapter)
+#endif
+#endif _PNP_POWER
+
+
+
+VOID
+IpxRefBinding(
+ IN PBINDING Binding
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a device context.
+
+Arguments:
+
+ Binding - Pointer to a transport device context object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ CTEAssert (Binding->ReferenceCount > 0); // not perfect, but...
+
+ (VOID)InterlockedIncrement (&Binding->ReferenceCount);
+
+} /* IpxRefBinding */
+
+
+VOID
+IpxDerefBinding(
+ IN PBINDING Binding
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences a device context by decrementing the
+ reference count contained in the structure. Currently, we don't
+ do anything special when the reference count drops to zero, but
+ we could dynamically unload stuff then.
+
+Arguments:
+
+ Binding - Pointer to a transport device context object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ LONG result;
+
+ result = InterlockedDecrement (&Binding->ReferenceCount);
+
+ CTEAssert (result >= 0);
+
+ if (result == 0) {
+ IpxDestroyBinding (Binding);
+ }
+
+} /* IpxDerefBinding */
+
+
+NTSTATUS
+IpxCreateAdapter(
+ IN PDEVICE Device,
+ IN PUNICODE_STRING AdapterName,
+ IN OUT PADAPTER *AdapterPtr
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates and initializes a device context structure.
+
+Arguments:
+
+
+ DriverObject - pointer to the IO subsystem supplied driver object.
+
+ Adapter - Pointer to a pointer to a transport device context object.
+
+ AdapterName - pointer to the name of the device this device object points to.
+
+Return Value:
+
+ STATUS_SUCCESS if all is well; STATUS_INSUFFICIENT_RESOURCES otherwise.
+
+--*/
+
+{
+ PADAPTER Adapter;
+#if 0
+ UINT i, j;
+#endif
+
+ Adapter = (PADAPTER)IpxAllocateMemory (sizeof(ADAPTER) + AdapterName->Length + sizeof(WCHAR), MEMORY_ADAPTER, "Adapter");
+
+#ifdef _PNP_POWER
+ if (Adapter == NULL) {
+ if (KeGetCurrentIrql() == 0) {
+ IPX_DEBUG (ADAPTER, ("Create adapter %ws failed\n", AdapterName));
+ } else {
+ IPX_DEBUG (ADAPTER, ("Create adapter %lx failed\n", AdapterName));
+ }
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ IPX_DEBUG (ADAPTER, ("Create adapter %lx %lx succeeded\n", Adapter, AdapterName));
+#else
+ if (Adapter == NULL) {
+ IPX_DEBUG (ADAPTER, ("Create adapter %ws failed\n", AdapterName->Buffer));
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ IPX_DEBUG (ADAPTER, ("Create adapter %ws succeeded\n", AdapterName->Buffer));
+#endif
+
+ RtlZeroMemory(Adapter, sizeof(ADAPTER));
+
+ //
+ // Copy over the adapter name.
+ //
+
+ Adapter->AdapterNameLength = AdapterName->Length + sizeof(WCHAR);
+ Adapter->AdapterName = (PWCHAR)(Adapter+1);
+ RtlCopyMemory(
+ Adapter->AdapterName,
+ AdapterName->Buffer,
+ AdapterName->Length);
+ Adapter->AdapterName[AdapterName->Length/sizeof(WCHAR)] = UNICODE_NULL;
+
+
+#if DBG
+ RtlCopyMemory(Adapter->Signature1, "IAD1", 4);
+#endif
+
+ Adapter->Type = IPX_ADAPTER_SIGNATURE;
+ Adapter->Size = sizeof(ADAPTER);
+
+ CTEInitLock (&Adapter->Lock);
+
+ InitializeListHead (&Adapter->RequestCompletionQueue);
+
+ InitializeListHead (&Adapter->ReceiveBufferPoolList);
+
+ ExInitializeSListHead (&Adapter->ReceiveBufferList);
+
+ Adapter->Device = Device;
+ Adapter->DeviceLock = &Device->Lock;
+ IpxReferenceDevice (Device, DREF_ADAPTER);
+
+#if 0
+ Adapter->ReceiveBufferPool.Next = NULL;
+ for (i = 0; i < ISN_FRAME_TYPE_MAX; i++) {
+ Adapter->Bindings[i] = NULL;
+ }
+ Adapter->BindingCount = 0;
+
+ for (i = 0; i < IDENTIFIER_TOTAL; i++) {
+ for (j = 0; j < SOURCE_ROUTE_HASH_SIZE; j++) {
+ Adapter->SourceRoutingHeads[i][j] = (PSOURCE_ROUTE)NULL;
+ }
+ }
+#endif
+
+ //
+ // BUGBUG: For the moment, we have to do the source
+ // routing operation on any type where broadcast
+ // may not be used for discovery -- improve this
+ // hopefully.
+ //
+
+ Adapter->SourceRoutingEmpty[IDENTIFIER_RIP] = FALSE;
+ Adapter->SourceRoutingEmpty[IDENTIFIER_IPX] = FALSE;
+ Adapter->SourceRoutingEmpty[IDENTIFIER_SPX] = FALSE;
+ Adapter->SourceRoutingEmpty[IDENTIFIER_NB] = TRUE;
+
+#ifdef _PNP_POWER
+ //
+ // Lock here? [BUGBUGZZ]
+ //
+ Adapter->ReferenceCount = 1;
+#endif
+
+ *AdapterPtr = Adapter;
+
+ return STATUS_SUCCESS;
+
+} /* IpxCreateAdapter */
+
+
+VOID
+IpxDestroyAdapter(
+ IN PADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys a device context structure.
+
+Arguments:
+
+ Adapter - Pointer to a pointer to a transport device context object.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG Database, Hash;
+ PSOURCE_ROUTE Current;
+ ULONG ReceiveBufferPoolSize;
+ PIPX_RECEIVE_BUFFER ReceiveBuffer;
+ PIPX_RECEIVE_BUFFER_POOL ReceiveBufferPool;
+ PDEVICE Device = Adapter->Device;
+ PLIST_ENTRY p;
+ UINT i;
+
+ IPX_DEBUG (ADAPTER, ("Destroy adapter %lx\n", Adapter));
+
+ //
+ // Free any receive buffer pools this adapter has.
+ //
+
+ ReceiveBufferPoolSize = FIELD_OFFSET (IPX_RECEIVE_BUFFER_POOL, Buffers[0]) +
+ (sizeof(IPX_RECEIVE_BUFFER) * Device->InitReceiveBuffers) +
+ (Adapter->MaxReceivePacketSize * Device->InitReceiveBuffers);
+
+ while (!IsListEmpty (&Adapter->ReceiveBufferPoolList)) {
+
+ p = RemoveHeadList (&Adapter->ReceiveBufferPoolList);
+ ReceiveBufferPool = CONTAINING_RECORD (p, IPX_RECEIVE_BUFFER_POOL, Linkage);
+
+ for (i = 0; i < ReceiveBufferPool->BufferCount; i++) {
+
+ ReceiveBuffer = &ReceiveBufferPool->Buffers[i];
+ IpxDeinitializeReceiveBuffer (Adapter, ReceiveBuffer, Adapter->MaxReceivePacketSize);
+
+ }
+
+ IPX_DEBUG (PACKET, ("Free buffer pool %lx\n", ReceiveBufferPool));
+ IpxFreeMemory (ReceiveBufferPool, ReceiveBufferPoolSize, MEMORY_PACKET, "ReceiveBufferPool");
+ }
+
+ //
+ // Free all the source routing information for this adapter.
+ //
+
+ for (Database = 0; Database < IDENTIFIER_TOTAL; Database++) {
+
+ for (Hash = 0; Hash < SOURCE_ROUTE_HASH_SIZE; Hash++) {
+
+ while (Adapter->SourceRoutingHeads[Database][Hash]) {
+
+ Current = Adapter->SourceRoutingHeads[Database][Hash];
+ Adapter->SourceRoutingHeads[Database][Hash] = Current->Next;
+
+ IpxFreeMemory (Current, SOURCE_ROUTE_SIZE (Current->SourceRoutingLength), MEMORY_SOURCE_ROUTE, "SourceRouting");
+ }
+ }
+ }
+
+ IpxDereferenceDevice (Adapter->Device, DREF_ADAPTER);
+ IpxFreeMemory (Adapter, sizeof(ADAPTER) + Adapter->AdapterNameLength, MEMORY_ADAPTER, "Adapter");
+
+} /* IpxDestroyAdapter */
+
+
+NTSTATUS
+IpxCreateBinding(
+ IN PDEVICE Device,
+ IN PBINDING_CONFIG ConfigBinding OPTIONAL,
+ IN ULONG NetworkNumberIndex,
+ IN PWCHAR AdapterName,
+ IN OUT PBINDING *BindingPtr
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates and initializes a binding structure.
+
+Arguments:
+
+ Device - The device.
+
+ ConfigBinding - Information about this binding. If this is
+ NULL then this is a WAN binding and all the relevant
+ information will be filled in by the caller.
+
+ NetworkNumberIndex - The index in the frame type array for
+ ConfigBinding indicating which frame type this binding is for.
+ Not used if ConfigBinding is not provided.
+
+ AdapterName - Used for error logging.
+
+ BindingPtr - Returns the allocated binding structure.
+
+Return Value:
+
+ STATUS_SUCCESS if all is well; STATUS_INSUFFICIENT_RESOURCES otherwise.
+
+--*/
+
+{
+ PBINDING Binding;
+#ifdef _PNP_POWER
+ PSINGLE_LIST_ENTRY s;
+
+ s = IPX_POP_ENTRY_LIST(
+ &Device->BindingList,
+ &Device->SListsLock);
+
+ if (s != NULL) {
+ goto GotBinding;
+ }
+
+ //
+ // This function tries to allocate another packet pool.
+ //
+
+ s = IpxPopBinding(Device);
+
+ //
+ // Possibly we should queue the packet up to wait
+ // for one to become free.
+ //
+
+ if (s == NULL) {
+
+#if DBG
+ if (KeGetCurrentIrql() == 0) {
+ IPX_DEBUG (ADAPTER, ("Create binding %ws failed\n", AdapterName));
+ } else {
+ IPX_DEBUG (ADAPTER, ("Create binding WAN failed\n"));
+ }
+#endif
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+GotBinding:
+
+ Binding = CONTAINING_RECORD (s, BINDING, PoolLinkage);
+
+#else
+ Binding = (PBINDING)IpxAllocateMemory (sizeof(BINDING), MEMORY_ADAPTER, "Binding");
+
+ //
+ // We can't vsprintf a %ws at DPC level, so we check for
+ // that. Only WAN bindings will be created then.
+ //
+
+ if (Binding == NULL) {
+#if DBG
+ if (KeGetCurrentIrql() == 0) {
+ IPX_DEBUG (ADAPTER, ("Create binding %ws failed\n", AdapterName));
+ } else {
+ IPX_DEBUG (ADAPTER, ("Create binding WAN failed\n"));
+ }
+#endif
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+#endif
+
+#if DBG
+ if (KeGetCurrentIrql() == 0) {
+ IPX_DEBUG (ADAPTER, ("Create binding %ws succeeded, %lx\n", AdapterName, Binding));
+ } else {
+ IPX_DEBUG (ADAPTER, ("Create binding WAN succeeded\n"));
+ }
+#endif
+
+ RtlZeroMemory(Binding, sizeof(BINDING));
+
+ //
+ // Initialize the reference count.
+ //
+
+ Binding->ReferenceCount = 1;
+#if DBG
+ Binding->RefTypes[BREF_BOUND] = 1;
+#endif
+
+#if DBG
+ RtlCopyMemory(Binding->Signature1, "IBI1", 4);
+#endif
+
+ Binding->Type = IPX_BINDING_SIGNATURE;
+ Binding->Size = sizeof(BINDING);
+
+ Binding->Device = Device;
+ Binding->DeviceLock = &Device->Lock;
+
+ if (ConfigBinding != NULL) {
+
+ ULONG Temp = ConfigBinding->NetworkNumber[NetworkNumberIndex];
+ Binding->ConfiguredNetworkNumber = REORDER_ULONG (Temp);
+
+ Binding->AutoDetect = ConfigBinding->AutoDetect[NetworkNumberIndex];
+ Binding->DefaultAutoDetect = ConfigBinding->DefaultAutoDetect[NetworkNumberIndex];
+
+ Binding->AllRouteDirected = (BOOLEAN)ConfigBinding->Parameters[BINDING_ALL_ROUTE_DEF];
+ Binding->AllRouteBroadcast = (BOOLEAN)ConfigBinding->Parameters[BINDING_ALL_ROUTE_BC];
+ Binding->AllRouteMulticast = (BOOLEAN)ConfigBinding->Parameters[BINDING_ALL_ROUTE_MC];
+
+ }
+
+ Binding->ReceiveBroadcast = TRUE;
+#if 0
+ Binding->BindingSetMember = FALSE;
+ Binding->NextBinding = (PBINDING)NULL;
+ Binding->DialOutAsync = FALSE;
+#endif
+
+ //
+ // We set Binding->FrameType later, after we can map it based on the
+ // media type of the adapter we bind to.
+ //
+
+ *BindingPtr = Binding;
+
+ return STATUS_SUCCESS;
+
+} /* IpxCreateBinding */
+
+
+VOID
+IpxDestroyBinding(
+ IN PBINDING Binding
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys a binding structure.
+
+Arguments:
+
+ Binding - Pointer to a transport binding structure.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ IPX_DEBUG (ADAPTER, ("Destroy binding %lx\n", Binding));
+
+#ifdef _PNP_POWER
+
+ IPX_PUSH_ENTRY_LIST(
+ &IpxDevice->BindingList,
+ &Binding->PoolLinkage,
+ &IpxDevice->SListsLock);
+#else
+ IpxFreeMemory (Binding, sizeof(BINDING), MEMORY_ADAPTER, "Binding");
+#endif
+
+} /* IpxDestroyBinding */
+
+
+#ifdef _PNP_POWER
+VOID
+IpxAllocateBindingPool(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds 10 bindings to the pool for this device.
+
+Arguments:
+
+ Device - The device.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_BINDING_POOL BindingPool;
+ UINT BindingPoolSize;
+ UINT BindingNum;
+ PBINDING Binding;
+ CTELockHandle LockHandle;
+
+ BindingPoolSize = FIELD_OFFSET (IPX_BINDING_POOL, Bindings[0]) +
+ (sizeof(BINDING) * Device->InitBindings);
+
+ BindingPool = (PIPX_BINDING_POOL)IpxAllocateMemory (BindingPoolSize, MEMORY_PACKET, "BindingPool");
+
+ if (BindingPool == NULL) {
+ IPX_DEBUG (PNP, ("Could not allocate binding pool memory\n"));
+ return;
+ }
+
+
+ IPX_DEBUG (PNP, ("Initializing Binding pool %lx, %d bindings\n",
+ BindingPool, Device->InitBindings));
+
+ BindingPool->BindingCount = Device->InitBindings;
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ for (BindingNum = 0; BindingNum < BindingPool->BindingCount; BindingNum++) {
+
+ Binding = &BindingPool->Bindings[BindingNum];
+ IPX_PUSH_ENTRY_LIST (&Device->BindingList, &Binding->PoolLinkage, &Device->SListsLock);
+
+#ifdef IPX_TRACK_POOL
+ Binding->Pool = BindingPool;
+#endif
+ }
+
+ InsertTailList (&Device->BindingPoolList, &BindingPool->Linkage);
+
+ Device->AllocatedBindings += BindingPool->BindingCount;
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+} /* IpxAllocateBindingPool */
+
+
+PSINGLE_LIST_ENTRY
+IpxPopBinding(
+ PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates a binding from the device context's pool.
+ If there are no bindings in the pool, it allocates one up to
+ the configured limit.
+
+Arguments:
+
+ Device - Pointer to our device to charge the packet to.
+
+Return Value:
+
+ The pointer to the Linkage field in the allocated binding.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+
+ s = IPX_POP_ENTRY_LIST(
+ &Device->BindingList,
+ &Device->SListsLock);
+
+ if (s != NULL) {
+ return s;
+ }
+
+ //
+ // No packets in the pool, see if we can allocate more.
+ //
+
+ if (Device->AllocatedBindings < Device->MaxPoolBindings) {
+
+ //
+ // Allocate a pool and try again.
+ //
+
+ IpxAllocateBindingPool (Device);
+ s = IPX_POP_ENTRY_LIST(
+ &Device->BindingList,
+ &Device->SListsLock);
+
+ return s;
+
+ } else {
+
+ return NULL;
+
+ }
+
+} /* IpxPopBinding */
+#endif
diff --git a/private/ntos/tdi/isnp/ipx/address.c b/private/ntos/tdi/isnp/ipx/address.c
new file mode 100644
index 000000000..1049bc8de
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/address.c
@@ -0,0 +1,1843 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ address.c
+
+Abstract:
+
+ This module contains code which implements the ADDRESS object.
+ Routines are provided to create, destroy, reference, and dereference,
+ transport address objects.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) - 22-Sept-1995
+ BackFill optimization changes added under #if BACK_FILL
+
+ Sanjay Anand (SanjayAn) 3-Oct-1995
+ Changes to support transfer of buffer ownership to transports - tagged [CH]
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+//
+// Map all generic accesses to the same one.
+//
+
+static GENERIC_MAPPING AddressGenericMapping =
+ { READ_CONTROL, READ_CONTROL, READ_CONTROL, READ_CONTROL };
+
+
+
+TDI_ADDRESS_IPX UNALIGNED *
+IpxParseTdiAddress(
+ IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans a TRANSPORT_ADDRESS, looking for an address
+ of type TDI_ADDRESS_TYPE_IPX.
+
+Arguments:
+
+ Transport - The generic TDI address.
+
+Return Value:
+
+ A pointer to the IPX address, or NULL if none is found.
+
+--*/
+
+{
+ TA_ADDRESS UNALIGNED * addressName;
+ INT i;
+
+ addressName = &TransportAddress->Address[0];
+
+ //
+ // The name can be passed with multiple entries; we'll take and use only
+ // the IPX one.
+ //
+
+ for (i=0;i<TransportAddress->TAAddressCount;i++) {
+ if (addressName->AddressType == TDI_ADDRESS_TYPE_IPX) {
+ if (addressName->AddressLength >= sizeof(TDI_ADDRESS_IPX)) {
+ return ((TDI_ADDRESS_IPX UNALIGNED *)(addressName->Address));
+ }
+ }
+ addressName = (TA_ADDRESS UNALIGNED *)(addressName->Address +
+ addressName->AddressLength);
+ }
+ return NULL;
+
+} /* IpxParseTdiAddress */
+
+
+BOOLEAN
+IpxValidateTdiAddress(
+ IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress,
+ IN ULONG TransportAddressLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans a TRANSPORT_ADDRESS, verifying that the
+ components of the address do not extend past the specified
+ length.
+
+Arguments:
+
+ TransportAddress - The generic TDI address.
+
+ TransportAddressLength - The specific length of TransportAddress.
+
+Return Value:
+
+ TRUE if the address is valid, FALSE otherwise.
+
+--*/
+
+{
+ PUCHAR AddressEnd = ((PUCHAR)TransportAddress) + TransportAddressLength;
+ TA_ADDRESS UNALIGNED * addressName;
+ INT i;
+
+ if (TransportAddressLength < sizeof(TransportAddress->TAAddressCount)) {
+ IpxPrint0 ("IpxValidateTdiAddress: runt address\n");
+ return FALSE;
+ }
+
+ addressName = &TransportAddress->Address[0];
+
+ for (i=0;i<TransportAddress->TAAddressCount;i++) {
+ if (addressName->Address > AddressEnd) {
+ IpxPrint0 ("IpxValidateTdiAddress: address too short\n");
+ return FALSE;
+ }
+ addressName = (TA_ADDRESS UNALIGNED *)(addressName->Address +
+ addressName->AddressLength);
+ }
+
+ if ((PUCHAR)addressName > AddressEnd) {
+ IpxPrint0 ("IpxValidateTdiAddress: address too short\n");
+ return FALSE;
+ }
+ return TRUE;
+
+} /* IpxValidateTdiAddress */
+
+#if DBG
+
+VOID
+IpxBuildTdiAddress(
+ IN PVOID AddressBuffer,
+ IN ULONG Network,
+ IN UCHAR Node[6],
+ IN USHORT Socket
+ )
+
+/*++
+
+Routine Description:
+
+ This routine fills in a TRANSPORT_ADDRESS in the specified
+ buffer, given the socket, network and node.
+
+Arguments:
+
+ AddressBuffer - The buffer that will hold the address.
+
+ Network - The network number.
+
+ Node - The node address.
+
+ Socket - The socket.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ TA_IPX_ADDRESS UNALIGNED * IpxAddress;
+
+ IpxAddress = (TA_IPX_ADDRESS UNALIGNED *)AddressBuffer;
+
+ IpxAddress->TAAddressCount = 1;
+ IpxAddress->Address[0].AddressLength = sizeof(TDI_ADDRESS_IPX);
+ IpxAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_IPX;
+ IpxAddress->Address[0].Address[0].NetworkAddress = Network;
+ IpxAddress->Address[0].Address[0].Socket = Socket;
+ RtlCopyMemory(IpxAddress->Address[0].Address[0].NodeAddress, Node, 6);
+
+} /* IpxBuildTdiAddress */
+#endif
+
+
+NTSTATUS
+IpxOpenAddress(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine opens a file that points to an existing address object, or, if
+ the object doesn't exist, creates it (note that creation of the address
+ object includes registering the address, and may take many seconds to
+ complete, depending upon system configuration).
+
+ If the address already exists, and it has an ACL associated with it, the
+ ACL is checked for access rights before allowing creation of the address.
+
+Arguments:
+
+ Device - pointer to the device describing the IPX transport.
+
+ Request - a pointer to the request used for the creation of the address.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ PADDRESS Address;
+ PADDRESS_FILE AddressFile;
+ PFILE_FULL_EA_INFORMATION ea;
+ TRANSPORT_ADDRESS UNALIGNED *name;
+ TA_ADDRESS UNALIGNED *AddressName;
+ USHORT Socket;
+ ULONG DesiredShareAccess;
+ CTELockHandle LockHandle;
+ PACCESS_STATE AccessState;
+ ACCESS_MASK GrantedAccess;
+ BOOLEAN AccessAllowed;
+ int i;
+ BOOLEAN found = FALSE;
+#ifdef ISN_NT
+ PIRP Irp = (PIRP)Request;
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
+#endif
+
+
+ //
+ // If we are a dedicated router, we cannot let addresses
+ // be opened.
+ //
+
+ if (Device->DedicatedRouter) {
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ //
+ // The network name is in the EA, passed in the request.
+ //
+
+ ea = OPEN_REQUEST_EA_INFORMATION(Request);
+ if (ea == NULL) {
+ IpxPrint1("OpenAddress: REQUEST %lx has no EA\n", Request);
+ return STATUS_NONEXISTENT_EA_ENTRY;
+ }
+
+ //
+ // this may be a valid name; parse the name from the EA and use it if OK.
+ //
+
+ name = (PTRANSPORT_ADDRESS)&ea->EaName[ea->EaNameLength+1];
+ AddressName = (PTA_ADDRESS)&name->Address[0];
+
+ //
+ // The name can be passed with multiple entries; we'll take and use only
+ // the first one of type IPX.
+ //
+
+ for (i=0;i<name->TAAddressCount;i++) {
+ if (AddressName->AddressType == TDI_ADDRESS_TYPE_IPX) {
+ if (AddressName->AddressLength >= sizeof(TDI_ADDRESS_IPX)) {
+ Socket = ((TDI_ADDRESS_IPX UNALIGNED *)&AddressName->Address[0])->Socket;
+ found = TRUE;
+ }
+ break;
+
+ } else {
+
+ AddressName = (PTA_ADDRESS)(AddressName->Address +
+ AddressName->AddressLength);
+
+ }
+
+ }
+
+ if (!found) {
+ IPX_DEBUG (ADDRESS, ("OpenAddress, request %lx has no IPX Address\n", Request));
+ return STATUS_NONEXISTENT_EA_ENTRY;
+ }
+
+ if (Socket == 0) {
+
+ Socket = IpxAssignSocket (Device);
+
+ if (Socket == 0) {
+ IPX_DEBUG (ADDRESS, ("OpenAddress, no unique socket found\n"));
+ return STATUS_INSUFFICIENT_RESOURCES;
+ } else {
+ IPX_DEBUG (ADDRESS, ("OpenAddress, assigned socket %lx\n", REORDER_USHORT(Socket)));
+ }
+
+ } else {
+
+ IPX_DEBUG (ADDRESS, ("OpenAddress, socket %lx\n", REORDER_USHORT(Socket)));
+
+ }
+
+ //
+ // get an address file structure to represent this address.
+ //
+
+ AddressFile = IpxCreateAddressFile (Device);
+
+ if (AddressFile == (PADDRESS_FILE)NULL) {
+ return status;
+ }
+
+ //
+ // We mark this socket specially.
+ //
+
+ if (Socket == SAP_SOCKET) {
+ AddressFile->IsSapSocket = TRUE;
+ AddressFile->SpecialReceiveProcessing = TRUE;
+ }
+
+ //
+ // See if this address is already established. This call automatically
+ // increments the reference count on the address so that it won't disappear
+ // from underneath us after this call but before we have a chance to use it.
+ //
+ // To ensure that we don't create two address objects for the
+ // same address, we hold the device context addressResource until
+ // we have found the address or created a new one.
+ //
+
+ ExAcquireResourceExclusive (&Device->AddressResource, TRUE);
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ Address = IpxLookupAddress (Device, Socket);
+
+ if (Address == NULL) {
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ //
+ // This address doesn't exist. Create it.
+ // registering it.
+ //
+
+ Address = IpxCreateAddress (
+ Device,
+ Socket);
+
+ if (Address != (PADDRESS)NULL) {
+
+ //
+ // Set this now in case we have to deref.
+ //
+
+ AddressFile->AddressLock = &Address->Lock;
+
+#ifdef ISN_NT
+
+ //
+ // Initialize the shared access now. We use read access
+ // to control all access.
+ //
+
+ DesiredShareAccess = (ULONG)
+ (((IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_READ) ||
+ (IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_WRITE)) ?
+ FILE_SHARE_READ : 0);
+
+ IoSetShareAccess(
+ FILE_READ_DATA,
+ DesiredShareAccess,
+ IrpSp->FileObject,
+ &Address->u.ShareAccess);
+
+
+ //
+ // Assign the security descriptor (need to do this with
+ // the spinlock released because the descriptor is not
+ // mapped).
+ //
+
+ AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState;
+
+ status = SeAssignSecurity(
+ NULL, // parent descriptor
+ AccessState->SecurityDescriptor,
+ &Address->SecurityDescriptor,
+ FALSE, // is directory
+ &AccessState->SubjectSecurityContext,
+ &AddressGenericMapping,
+ NonPagedPool);
+
+ if (!NT_SUCCESS(status)) {
+
+ //
+ // Error, return status.
+ //
+
+ IoRemoveShareAccess (IrpSp->FileObject, &Address->u.ShareAccess);
+ ExReleaseResource (&Device->AddressResource);
+ IpxDereferenceAddress (Address, AREF_ADDRESS_FILE);
+ IpxDereferenceAddressFile (AddressFile, AFREF_CREATE);
+ return status;
+
+ }
+
+#endif
+
+ ExReleaseResource (&Device->AddressResource);
+
+ //
+ // if the adapter isn't ready, we can't do any of this; get out
+ //
+
+ if (Device->State == DEVICE_STATE_STOPPING) {
+ IpxDereferenceAddress (Address, AREF_ADDRESS_FILE);
+ IpxDereferenceAddressFile (AddressFile, AFREF_CREATE);
+ status = STATUS_DEVICE_NOT_READY;
+
+ } else {
+
+ REQUEST_OPEN_CONTEXT(Request) = (PVOID)AddressFile;
+ REQUEST_OPEN_TYPE(Request) = (PVOID)TDI_TRANSPORT_ADDRESS_FILE;
+#ifdef ISN_NT
+ AddressFile->FileObject = IrpSp->FileObject;
+#endif
+ AddressFile->Request = Request;
+ AddressFile->Address = Address;
+
+ CTEGetLock (&Address->Lock, &LockHandle);
+ InsertTailList (&Address->AddressFileDatabase, &AddressFile->Linkage);
+ CTEFreeLock (&Address->Lock, LockHandle);
+
+ AddressFile->Request = NULL;
+ AddressFile->State = ADDRESSFILE_STATE_OPEN;
+ status = STATUS_SUCCESS;
+
+ }
+
+ } else {
+
+ ExReleaseResource (&Device->AddressResource);
+
+ //
+ // If the address could not be created, and is not in the
+ // process of being created, then we can't open up an address.
+ // Since we can't use the AddressLock to deref, we just destroy
+ // the address file.
+ //
+
+ IpxDestroyAddressFile (AddressFile);
+
+ }
+
+ } else {
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ IPX_DEBUG (ADDRESS, ("Add to address %lx\n", Address));
+
+ //
+ // Set this now in case we have to deref.
+ //
+
+ AddressFile->AddressLock = &Address->Lock;
+
+ //
+ // The address already exists. Check the ACL and see if we
+ // can access it. If so, simply use this address as our address.
+ //
+
+#ifdef ISN_NT
+
+ AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState;
+
+ AccessAllowed = SeAccessCheck(
+ Address->SecurityDescriptor,
+ &AccessState->SubjectSecurityContext,
+ FALSE, // tokens locked
+ IrpSp->Parameters.Create.SecurityContext->DesiredAccess,
+ (ACCESS_MASK)0, // previously granted
+ NULL, // privileges
+ &AddressGenericMapping,
+ Irp->RequestorMode,
+ &GrantedAccess,
+ &status);
+
+#else // ISN_NT
+
+ AccessAllowed = TRUE;
+
+#endif // ISN_NT
+
+ if (!AccessAllowed) {
+
+ ExReleaseResource (&Device->AddressResource);
+
+ IpxDereferenceAddressFile (AddressFile, AFREF_CREATE);
+
+ } else {
+
+#ifdef ISN_NT
+
+ //
+ // Now check that we can obtain the desired share
+ // access. We use read access to control all access.
+ //
+
+ DesiredShareAccess = (ULONG)
+ (((IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_READ) ||
+ (IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_WRITE)) ?
+ FILE_SHARE_READ : 0);
+
+ status = IoCheckShareAccess(
+ FILE_READ_DATA,
+ DesiredShareAccess,
+ IrpSp->FileObject,
+ &Address->u.ShareAccess,
+ TRUE);
+
+#else // ISN_NT
+
+ status = STATUS_SUCCESS;
+
+#endif // ISN_NT
+
+ if (!NT_SUCCESS (status)) {
+
+ ExReleaseResource (&Device->AddressResource);
+
+ IpxDereferenceAddressFile (AddressFile, AFREF_CREATE);
+
+ } else {
+
+ ExReleaseResource (&Device->AddressResource);
+
+ CTEGetLock (&Address->Lock, &LockHandle);
+
+ InsertTailList (
+ &Address->AddressFileDatabase,
+ &AddressFile->Linkage);
+
+ AddressFile->Request = NULL;
+ AddressFile->Address = Address;
+#ifdef ISN_NT
+ AddressFile->FileObject = IrpSp->FileObject;
+#endif
+ AddressFile->State = ADDRESSFILE_STATE_OPEN;
+
+ IpxReferenceAddress (Address, AREF_ADDRESS_FILE);
+
+ REQUEST_OPEN_CONTEXT(Request) = (PVOID)AddressFile;
+ REQUEST_OPEN_TYPE(Request) = (PVOID)TDI_TRANSPORT_ADDRESS_FILE;
+
+ CTEFreeLock (&Address->Lock, LockHandle);
+
+ status = STATUS_SUCCESS;
+
+ }
+ }
+
+ //
+ // Remove the reference from IpxLookupAddress.
+ //
+
+ IpxDereferenceAddress (Address, AREF_LOOKUP);
+ }
+
+ return status;
+
+} /* IpxOpenAddress */
+
+
+USHORT
+IpxAssignSocket(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine assigns a socket that is unique within a range
+ of SocketUniqueness.
+
+Arguments:
+
+ Device - Pointer to the device context.
+
+Return Value:
+
+ The assigned socket number, or 0 if a unique one cannot
+ be found.
+
+--*/
+
+{
+ USHORT InitialSocket, CurrentSocket, AddressSocket;
+ ULONG CurrentHash;
+ BOOLEAN Conflict;
+ PLIST_ENTRY p;
+ PADDRESS Address;
+ CTELockHandle LockHandle;
+
+ //
+ // Loop through all possible sockets, starting at
+ // Device->CurrentSocket, looking for a suitable one.
+ // Device->CurrentSocket rotates through the possible
+ // sockets to improve the chances of finding one
+ // quickly.
+ //
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ InitialSocket = Device->CurrentSocket;
+ Device->CurrentSocket = (USHORT)(Device->CurrentSocket + Device->SocketUniqueness);
+ if ((USHORT)(Device->CurrentSocket+Device->SocketUniqueness) > Device->SocketEnd) {
+ Device->CurrentSocket = Device->SocketStart;
+ }
+
+ CurrentSocket = InitialSocket;
+
+ do {
+
+ //
+ // Scan all addresses; if we find one with a socket
+ // that conflicts with this one, we can't use it.
+ //
+ // NOTE: Device->Lock is acquired here.
+ //
+
+ Conflict = FALSE;
+
+ for (CurrentHash = 0; CurrentHash < IPX_ADDRESS_HASH_COUNT; CurrentHash++) {
+
+ for (p = Device->AddressDatabases[CurrentHash].Flink;
+ p != &Device->AddressDatabases[CurrentHash];
+ p = p->Flink) {
+
+ Address = CONTAINING_RECORD (p, ADDRESS, Linkage);
+ AddressSocket = REORDER_USHORT(Address->Socket);
+
+ if ((AddressSocket + Device->SocketUniqueness > CurrentSocket) &&
+ (AddressSocket < CurrentSocket + Device->SocketUniqueness)) {
+ Conflict = TRUE;
+ break;
+ }
+ }
+
+ //
+ // If we've found a conflict, no need to check the other
+ // queues.
+ //
+
+ if (Conflict) {
+ break;
+ }
+ }
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ //
+ // We intentionally free the lock here so that we
+ // never spend too much time with it held.
+ //
+
+ if (!Conflict) {
+
+ //
+ // We went through the address list without
+ // finding a conflict; use this socket.
+ //
+
+ return REORDER_USHORT(CurrentSocket);
+ }
+
+ CurrentSocket = (USHORT)(CurrentSocket + Device->SocketUniqueness);
+ if ((USHORT)(CurrentSocket+Device->SocketUniqueness) > Device->SocketEnd) {
+ CurrentSocket = Device->SocketStart;
+ }
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ } while (CurrentSocket != InitialSocket);
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ //
+ // Could not find one to assign.
+ //
+
+ return (USHORT)0;
+
+} /* IpxAssignSocket */
+
+
+PADDRESS
+IpxCreateAddress(
+ IN PDEVICE Device,
+ IN USHORT Socket
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates a transport address and associates it with
+ the specified transport device context. The reference count in the
+ address is automatically set to 1, and the reference count of the
+ device context is incremented.
+
+ NOTE: This routine must be called with the Device
+ spinlock held.
+
+Arguments:
+
+ Device - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ address.
+
+ Socket - The socket to assign to this address.
+
+Return Value:
+
+ The newly created address, or NULL if none can be allocated.
+
+--*/
+
+{
+ PADDRESS Address;
+ PIPX_SEND_RESERVED SendReserved;
+ PIPX_RECEIVE_RESERVED ReceiveReserved;
+ NDIS_STATUS Status;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+
+ Address = (PADDRESS)IpxAllocateMemory (sizeof(ADDRESS), MEMORY_ADDRESS, "Address");
+ if (Address == NULL) {
+ IPX_DEBUG (ADDRESS, ("Create address %lx failed\n", REORDER_USHORT(Socket)));
+ return NULL;
+ }
+
+ IPX_DEBUG (ADDRESS, ("Create address %lx (%lx)\n", Address, REORDER_USHORT(Socket)));
+ RtlZeroMemory (Address, sizeof(ADDRESS));
+
+#ifndef IPX_OWN_PACKETS
+ IpxAllocateSingleSendPacket(Device, &Address->SendPacket, &Status);
+ if (Status != NDIS_STATUS_SUCCESS) {
+ goto Fail1;
+ }
+#endif
+
+ if (IpxInitializeSendPacket (Device, &Address->SendPacket, Address->SendPacketHeader) != STATUS_SUCCESS) {
+#ifndef IPX_OWN_PACKETS
+Fail1:
+#endif
+ Address->SendPacketInUse = TRUE;
+ } else {
+ SendReserved = SEND_RESERVED(&Address->SendPacket);
+ SendReserved->Address = Address;
+ SendReserved->OwnedByAddress = TRUE;
+ Address->SendPacketInUse = FALSE;
+#ifdef IPX_TRACK_POOL
+ SendReserved->Pool = NULL;
+#endif
+ }
+
+
+#if BACK_FILL
+ {
+ PIPX_SEND_RESERVED BackFillReserved;
+
+#ifndef IPX_OWN_PACKETS
+ IpxAllocateSingleSendPacket(Device, &Address->BackFillPacket, &Status);
+ if (Status != NDIS_STATUS_SUCCESS) {
+ goto Fail2;
+ }
+#endif
+ if (IpxInitializeBackFillPacket (Device, &Address->BackFillPacket, NULL) != STATUS_SUCCESS) {
+#ifndef IPX_OWN_PACKETS
+Fail2:
+#endif
+ Address->BackFillPacketInUse = TRUE;
+ } else {
+ BackFillReserved = SEND_RESERVED(&Address->BackFillPacket);
+ BackFillReserved->Address = Address;
+ Address->BackFillPacketInUse = FALSE;
+ BackFillReserved->OwnedByAddress = TRUE;
+#ifdef IPX_TRACK_POOL
+ BackFillReserved->Pool = NULL;
+#endif
+ }
+ }
+#endif
+
+#ifndef IPX_OWN_PACKETS
+ IpxAllocateSingleReceivePacket(Device, &Address->ReceivePacket, &Status);
+ if (Status != NDIS_STATUS_SUCCESS) {
+ goto Fail3;
+ }
+#endif
+ if (IpxInitializeReceivePacket (Device, &Address->ReceivePacket) != STATUS_SUCCESS) {
+#ifndef IPX_OWN_PACKETS
+Fail3:
+#endif
+ Address->ReceivePacketInUse = TRUE;
+ } else {
+ ReceiveReserved = RECEIVE_RESERVED(&Address->ReceivePacket);
+ ReceiveReserved->Address = Address;
+ ReceiveReserved->OwnedByAddress = TRUE;
+ Address->ReceivePacketInUse = FALSE;
+#ifdef IPX_TRACK_POOL
+ ReceiveReserved->Pool = NULL;
+#endif
+ }
+
+ Address->Type = IPX_ADDRESS_SIGNATURE;
+ Address->Size = sizeof (ADDRESS);
+
+ Address->Device = Device;
+ Address->DeviceLock = &Device->Lock;
+ CTEInitLock (&Address->Lock);
+
+ InitializeListHead (&Address->AddressFileDatabase);
+
+ Address->ReferenceCount = 1;
+#if DBG
+ Address->RefTypes[AREF_ADDRESS_FILE] = 1;
+#endif
+ Address->Socket = Socket;
+ Address->SendSourceSocket = Socket;
+
+ //
+ // Save our local address for building datagrams quickly.
+ //
+
+ RtlCopyMemory (&Address->LocalAddress, &Device->SourceAddress, FIELD_OFFSET(TDI_ADDRESS_IPX,Socket));
+ Address->LocalAddress.Socket = Socket;
+
+ //
+ // Now link this address into the specified device context's
+ // address database. To do this, we need to acquire the spin lock
+ // on the device context.
+ //
+
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+ InsertTailList (&Device->AddressDatabases[IPX_HASH_SOCKET(Socket)], &Address->Linkage);
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+
+ IpxReferenceDevice (Device, DREF_ADDRESS);
+
+ return Address;
+
+} /* IpxCreateAddress */
+
+
+NTSTATUS
+IpxVerifyAddressFile(
+ IN PADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to verify that the pointer given us in a file
+ object is in fact a valid address file object. We also verify that the
+ address object pointed to by it is a valid address object, and reference
+ it to keep it from disappearing while we use it.
+
+Arguments:
+
+ AddressFile - potential pointer to a ADDRESS_FILE object
+
+Return Value:
+
+ STATUS_SUCCESS if all is well; STATUS_INVALID_ADDRESS otherwise
+
+--*/
+
+{
+ CTELockHandle LockHandle;
+ NTSTATUS status = STATUS_SUCCESS;
+ PADDRESS Address;
+
+ //
+ // try to verify the address file signature. If the signature is valid,
+ // verify the address pointed to by it and get the address spinlock.
+ // check the address's state, and increment the reference count if it's
+ // ok to use it. Note that the only time we return an error for state is
+ // if the address is closing.
+ //
+
+ try {
+
+ if ((AddressFile->Size == sizeof (ADDRESS_FILE)) &&
+ (AddressFile->Type == IPX_ADDRESSFILE_SIGNATURE) ) {
+// (AddressFile->State != ADDRESSFILE_STATE_CLOSING) ) {
+
+ Address = AddressFile->Address;
+
+ if ((Address->Size == sizeof (ADDRESS)) &&
+ (Address->Type == IPX_ADDRESS_SIGNATURE) ) {
+
+ CTEGetLock (&Address->Lock, &LockHandle);
+
+ if (!Address->Stopping) {
+
+ IpxReferenceAddressFileLock (AddressFile, AFREF_VERIFY);
+
+ } else {
+
+ IpxPrint1("IpxVerifyAddressFile: A %lx closing\n", Address);
+ status = STATUS_INVALID_ADDRESS;
+ }
+
+ CTEFreeLock (&Address->Lock, LockHandle);
+
+ } else {
+
+ IpxPrint1("IpxVerifyAddressFile: A %lx bad signature\n", Address);
+ status = STATUS_INVALID_ADDRESS;
+ }
+
+ } else {
+
+ IpxPrint1("IpxVerifyAddressFile: AF %lx bad signature\n", AddressFile);
+ status = STATUS_INVALID_ADDRESS;
+ }
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ IpxPrint1("IpxVerifyAddressFile: AF %lx exception\n", Address);
+ return GetExceptionCode();
+ }
+
+ return status;
+
+} /* IpxVerifyAddressFile */
+
+
+VOID
+IpxDestroyAddress(
+ IN PVOID Parameter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys a transport address and removes all references
+ made by it to other objects in the transport. The address structure
+ is returned to nonpaged system pool. It is assumed
+ that the caller has already removed all addressfile structures associated
+ with this address.
+
+ It is called from a worker thread queue by IpxDerefAddress when
+ the reference count goes to 0.
+
+ This thread is only queued by IpxDerefAddress. The reason for
+ this is that there may be multiple streams of execution which are
+ simultaneously referencing the same address object, and it should
+ not be deleted out from under an interested stream of execution.
+
+Arguments:
+
+ Address - Pointer to a transport address structure to be destroyed.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PADDRESS Address = (PADDRESS)Parameter;
+ PDEVICE Device = Address->Device;
+ CTELockHandle LockHandle;
+
+ IPX_DEBUG (ADDRESS, ("Destroy address %lx (%lx)\n", Address, REORDER_USHORT(Address->Socket)));
+
+ SeDeassignSecurity (&Address->SecurityDescriptor);
+
+ //
+ // Delink this address from its associated device context's address
+ // database. To do this we must spin lock on the device context object,
+ // not on the address.
+ //
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+ RemoveEntryList (&Address->Linkage);
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ if (!Address->SendPacketInUse) {
+ IpxDeinitializeSendPacket (Device, &Address->SendPacket);
+#ifndef IPX_OWN_PACKETS
+ IpxFreeSingleSendPacket (Device, Address->SendPacket);
+#endif
+ }
+
+ if (!Address->ReceivePacketInUse) {
+ IpxDeinitializeReceivePacket (Device, &Address->ReceivePacket);
+#ifndef IPX_OWN_PACKETS
+ IpxFreeSingleReceivePacket (Device, Address->ReceivePacket);
+#endif
+ }
+
+#if BACK_FILL
+ if (!Address->BackFillPacketInUse) {
+ IpxDeinitializeBackFillPacket (Device, &Address->BackFillPacket);
+#ifndef IPX_OWN_PACKETS
+ IpxFreeSingleSendPacket (Device, Address->BackFillPacket);
+#endif
+ }
+#endif
+ IpxFreeMemory (Address, sizeof(ADDRESS), MEMORY_ADDRESS, "Address");
+
+ IpxDereferenceDevice (Device, DREF_ADDRESS);
+
+} /* IpxDestroyAddress */
+
+
+#if DBG
+VOID
+IpxRefAddress(
+ IN PADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a transport address.
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ CTEAssert (Address->ReferenceCount > 0); // not perfect, but...
+
+ (VOID)InterlockedIncrement(&Address->ReferenceCount);
+
+} /* IpxRefAddress */
+
+
+VOID
+IpxRefAddressLock(
+ IN PADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a transport address
+ when the device lock is already held.
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ CTEAssert (Address->ReferenceCount > 0); // not perfect, but...
+
+ // ++Address->ReferenceCount;
+ (VOID)InterlockedIncrement(&Address->ReferenceCount);
+
+} /* IpxRefAddressLock */
+#endif
+
+
+VOID
+IpxDerefAddress(
+ IN PADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences a transport address by decrementing the
+ reference count contained in the structure. If, after being
+ decremented, the reference count is zero, then this routine calls
+ IpxDestroyAddress to remove it from the system.
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ ULONG oldvalue;
+
+ oldvalue = IPX_ADD_ULONG (
+ &Address->ReferenceCount,
+ (ULONG)-1,
+ Address->DeviceLock);
+
+ //
+ // If we have deleted all references to this address, then we can
+ // destroy the object. It is okay to have already released the spin
+ // lock at this point because there is no possible way that another
+ // stream of execution has access to the address any longer.
+ //
+
+ CTEAssert (oldvalue != 0);
+
+ if (oldvalue == 1) {
+
+#if ISN_NT
+ ExInitializeWorkItem(
+ &Address->u.DestroyAddressQueueItem,
+ IpxDestroyAddress,
+ (PVOID)Address);
+ ExQueueWorkItem(&Address->u.DestroyAddressQueueItem, DelayedWorkQueue);
+#else
+ IpxDestroyAddress(Address);
+#endif
+
+ }
+
+} /* IpxDerefAddress */
+
+
+VOID
+IpxDerefAddressSync(
+ IN PADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences a transport address by decrementing the
+ reference count contained in the structure. If, after being
+ decremented, the reference count is zero, then this routine calls
+ IpxDestroyAddress to remove it from the system. This routine can
+ only be called when we are synchronized (inside an IPX_SYNC_START/
+ IPX_SYNC_END pair, with a lock held, or in an indication).
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ ULONG oldvalue;
+
+ oldvalue = IPX_ADD_ULONG (
+ &Address->ReferenceCount,
+ (ULONG)-1,
+ Address->DeviceLock);
+
+ //
+ // If we have deleted all references to this address, then we can
+ // destroy the object. It is okay to have already released the spin
+ // lock at this point because there is no possible way that another
+ // stream of execution has access to the address any longer.
+ //
+
+ CTEAssert (oldvalue != 0);
+
+ if (oldvalue == 1) {
+
+#if ISN_NT
+ ExInitializeWorkItem(
+ &Address->u.DestroyAddressQueueItem,
+ IpxDestroyAddress,
+ (PVOID)Address);
+ ExQueueWorkItem(&Address->u.DestroyAddressQueueItem, DelayedWorkQueue);
+#else
+ IpxDestroyAddress(Address);
+#endif
+
+ }
+
+} /* IpxDerefAddressSync */
+
+
+PADDRESS_FILE
+IpxCreateAddressFile(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates an address file from the pool of ther
+ specified device context. The reference count in the
+ address is automatically set to 1.
+
+Arguments:
+
+ Device - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ address.
+
+Return Value:
+
+ The allocate address file or NULL.
+
+--*/
+
+{
+ CTELockHandle LockHandle;
+ PADDRESS_FILE AddressFile;
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ AddressFile = (PADDRESS_FILE)IpxAllocateMemory (sizeof(ADDRESS_FILE), MEMORY_ADDRESS, "AddressFile");
+ if (AddressFile == NULL) {
+ IPX_DEBUG (ADDRESS, ("Create address file failed\n"));
+ CTEFreeLock (&Device->Lock, LockHandle);
+ return NULL;
+ }
+
+ IPX_DEBUG (ADDRESS, ("Create address file %lx\n", AddressFile));
+
+ RtlZeroMemory (AddressFile, sizeof(ADDRESS_FILE));
+
+ AddressFile->Type = IPX_ADDRESSFILE_SIGNATURE;
+ AddressFile->Size = sizeof (ADDRESS_FILE);
+
+ InitializeListHead (&AddressFile->ReceiveDatagramQueue);
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+#if 0
+ AddressFile->SpecialReceiveProcessing = FALSE;
+ AddressFile->ExtendedAddressing = FALSE;
+ AddressFile->ReceiveIpxHeader = FALSE;
+ AddressFile->FilterOnPacketType = FALSE;
+ AddressFile->DefaultPacketType = 0;
+ AddressFile->Address = NULL;
+#ifdef ISN_NT
+ AddressFile->FileObject = NULL;
+#endif
+#endif
+
+ AddressFile->Device = Device;
+ AddressFile->State = ADDRESSFILE_STATE_OPENING;
+ AddressFile->ReferenceCount = 1;
+#if DBG
+ AddressFile->RefTypes[AFREF_CREATE] = 1;
+#endif
+ AddressFile->CloseRequest = (PREQUEST)NULL;
+
+ //
+ // Initialize the request handlers.
+ //
+
+ AddressFile->RegisteredReceiveDatagramHandler = FALSE;
+ AddressFile->ReceiveDatagramHandler = TdiDefaultRcvDatagramHandler;
+ AddressFile->ReceiveDatagramHandlerContext = NULL;
+
+ //
+ // [CH] Added these handlers for chained buffer receives
+ //
+ AddressFile->RegisteredChainedReceiveDatagramHandler = FALSE;
+ AddressFile->ChainedReceiveDatagramHandler = TdiDefaultChainedRcvDatagramHandler;
+ AddressFile->ChainedReceiveDatagramHandlerContext = NULL;
+
+ AddressFile->RegisteredErrorHandler = FALSE;
+ AddressFile->ErrorHandler = TdiDefaultErrorHandler;
+ AddressFile->ErrorHandlerContext = NULL;
+
+ return AddressFile;
+
+} /* IpxCreateAddressFile */
+
+
+NTSTATUS
+IpxDestroyAddressFile(
+ IN PADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys an address file and removes all references
+ made by it to other objects in the transport.
+
+ This routine is only called by IpxDereferenceAddressFile. The reason
+ for this is that there may be multiple streams of execution which are
+ simultaneously referencing the same address file object, and it should
+ not be deleted out from under an interested stream of execution.
+
+Arguments:
+
+ AddressFile Pointer to a transport address file structure to be destroyed.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ CTELockHandle LockHandle, LockHandle1;
+ PADDRESS Address;
+ PDEVICE Device;
+ PREQUEST CloseRequest;
+
+ IPX_DEBUG (ADDRESS, ("Destroy address file %lx\n", AddressFile));
+
+ Address = AddressFile->Address;
+ Device = AddressFile->Device;
+
+ if (Address) {
+
+ //
+ // This addressfile was associated with an address.
+ //
+
+ CTEGetLock (&Address->Lock, &LockHandle);
+
+ //
+ // remove this addressfile from the address list and disassociate it from
+ // the file handle.
+ //
+
+ RemoveEntryList (&AddressFile->Linkage);
+ InitializeListHead (&AddressFile->Linkage);
+
+ if (Address->AddressFileDatabase.Flink == &Address->AddressFileDatabase) {
+
+ //
+ // This is the last open of this address, it will close
+ // due to normal dereferencing but we have to set the
+ // CLOSING flag too to stop further references.
+ //
+
+ CTEGetLock (&Device->Lock, &LockHandle1);
+ Address->Stopping = TRUE;
+ if (Device->LastAddress == Address) {
+ Device->LastAddress = NULL;
+ }
+ CTEFreeLock (&Device->Lock, LockHandle1);
+
+ }
+
+ AddressFile->Address = NULL;
+
+#ifdef ISN_NT
+ AddressFile->FileObject->FsContext = NULL;
+ AddressFile->FileObject->FsContext2 = NULL;
+#endif
+
+ CTEFreeLock (&Address->Lock, LockHandle);
+
+ //
+ // We will already have been removed from the ShareAccess
+ // of the owning address.
+ //
+
+ //
+ // Now dereference the owning address.
+ //
+
+ IpxDereferenceAddress (Address, AREF_ADDRESS_FILE);
+
+ }
+
+ //
+ // Save this for later completion.
+ //
+
+ CloseRequest = AddressFile->CloseRequest;
+
+ //
+ // return the addressFile to the pool of address files
+ //
+
+ IpxFreeMemory (AddressFile, sizeof(ADDRESS_FILE), MEMORY_ADDRESS, "AddressFile");
+
+ if (CloseRequest != (PREQUEST)NULL) {
+ REQUEST_INFORMATION(CloseRequest) = 0;
+ REQUEST_STATUS(CloseRequest) = STATUS_SUCCESS;
+ IpxCompleteRequest (CloseRequest);
+ IpxFreeRequest (Device, CloseRequest);
+ }
+
+ return STATUS_SUCCESS;
+
+} /* IpxDestroyAddressFile */
+
+
+#if DBG
+VOID
+IpxRefAddressFile(
+ IN PADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on an address file.
+
+Arguments:
+
+ AddressFile - Pointer to a transport address file object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ CTEAssert (AddressFile->ReferenceCount > 0); // not perfect, but...
+
+ (VOID)IPX_ADD_ULONG (
+ &AddressFile->ReferenceCount,
+ 1,
+ AddressFile->AddressLock);
+
+} /* IpxRefAddressFile */
+
+
+VOID
+IpxRefAddressFileLock(
+ IN PADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on an address file.
+ IT IS CALLED WITH THE ADDRESS LOCK HELD.
+
+Arguments:
+
+ AddressFile - Pointer to a transport address file object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ CTEAssert (AddressFile->ReferenceCount > 0); // not perfect, but...
+
+ //++AddressFile->ReferenceCount;
+ (VOID)InterlockedIncrement(&AddressFile->ReferenceCount);
+
+} /* IpxRefAddressFileLock */
+
+
+VOID
+IpxRefAddressFileSync(
+ IN PADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on an address file.
+
+Arguments:
+
+ AddressFile - Pointer to a transport address file object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ CTEAssert (AddressFile->ReferenceCount > 0); // not perfect, but...
+
+ (VOID)IPX_ADD_ULONG (
+ &AddressFile->ReferenceCount,
+ 1,
+ AddressFile->AddressLock);
+
+} /* IpxRefAddressFileSync */
+
+
+VOID
+IpxDerefAddressFile(
+ IN PADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences an address file by decrementing the
+ reference count contained in the structure. If, after being
+ decremented, the reference count is zero, then this routine calls
+ IpxDestroyAddressFile to remove it from the system.
+
+Arguments:
+
+ AddressFile - Pointer to a transport address file object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ ULONG oldvalue;
+
+ oldvalue = IPX_ADD_ULONG (
+ &AddressFile->ReferenceCount,
+ (ULONG)-1,
+ AddressFile->AddressLock);
+
+ //
+ // If we have deleted all references to this address file, then we can
+ // destroy the object. It is okay to have already released the spin
+ // lock at this point because there is no possible way that another
+ // stream of execution has access to the address any longer.
+ //
+
+ CTEAssert (oldvalue > 0);
+
+ if (oldvalue == 1) {
+ IpxDestroyAddressFile (AddressFile);
+ }
+
+} /* IpxDerefAddressFile */
+
+
+VOID
+IpxDerefAddressFileSync(
+ IN PADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences an address file by decrementing the
+ reference count contained in the structure. If, after being
+ decremented, the reference count is zero, then this routine calls
+ IpxDestroyAddressFile to remove it from the system. This routine
+ can only be called when we are synchronized (inside an IPX_SYNC_START/
+ IPX_SYNC_END pair, with a lock held, or in an indication).
+
+Arguments:
+
+ AddressFile - Pointer to a transport address file object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ ULONG oldvalue;
+
+ oldvalue = IPX_ADD_ULONG (
+ &AddressFile->ReferenceCount,
+ (ULONG)-1,
+ AddressFile->AddressLock);
+
+ //
+ // If we have deleted all references to this address file, then we can
+ // destroy the object. It is okay to have already released the spin
+ // lock at this point because there is no possible way that another
+ // stream of execution has access to the address any longer.
+ //
+
+ CTEAssert (oldvalue > 0);
+
+ if (oldvalue == 1) {
+ IpxDestroyAddressFile (AddressFile);
+ }
+
+} /* IpxDerefAddressFileSync */
+#endif
+
+
+PADDRESS
+IpxLookupAddress(
+ IN PDEVICE Device,
+ IN USHORT Socket
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans the transport addresses defined for the given
+ device context and compares them with the specified NETWORK
+ NAME values. If an exact match is found, then a pointer to the
+ ADDRESS object is returned, and as a side effect, the reference
+ count to the address object is incremented. If the address is not
+ found, then NULL is returned.
+
+ NOTE: This routine must be called with the Device
+ spinlock held.
+
+Arguments:
+
+ Device - Pointer to the device object and its extension.
+
+ Socket - The socket to look up.
+
+Return Value:
+
+ Pointer to the ADDRESS object found, or NULL if not found.
+
+--*/
+
+{
+ PADDRESS Address;
+ PLIST_ENTRY p;
+ ULONG Hash = IPX_HASH_SOCKET (Socket);
+
+ p = Device->AddressDatabases[Hash].Flink;
+
+ for (p = Device->AddressDatabases[Hash].Flink;
+ p != &Device->AddressDatabases[Hash];
+ p = p->Flink) {
+
+ Address = CONTAINING_RECORD (p, ADDRESS, Linkage);
+
+ if (Address->Stopping) {
+ continue;
+ }
+
+ if (Address->Socket == Socket) {
+
+ //
+ // We found the match. Bump the reference count on the address, and
+ // return a pointer to the address object for the caller to use.
+ //
+
+ IpxReferenceAddressLock (Address, AREF_LOOKUP);
+ return Address;
+
+ }
+
+ }
+
+ //
+ // The specified address was not found.
+ //
+
+ return NULL;
+
+} /* IpxLookupAddress */
+
+
+NTSTATUS
+IpxStopAddressFile(
+ IN PADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to terminate all activity on an AddressFile and
+ destroy the object. We remove every connection and datagram associated
+ with this addressfile from the address database and terminate their
+ activity. Then, if there are no other outstanding addressfiles open on
+ this address, the address will go away.
+
+Arguments:
+
+ AddressFile - pointer to the addressFile to be stopped
+
+Return Value:
+
+ STATUS_SUCCESS if all is well, STATUS_INVALID_HANDLE if the request
+ is not for a real address.
+
+--*/
+
+{
+ CTELockHandle LockHandle;
+ PREQUEST Request;
+ PADDRESS Address = AddressFile->Address;
+ PLIST_ENTRY p;
+ KIRQL irql;
+
+
+ IoAcquireCancelSpinLock( &irql );
+ CTEGetLock (&Address->Lock, &LockHandle);
+
+ if (AddressFile->State == ADDRESSFILE_STATE_CLOSING) {
+ CTEFreeLock (&Address->Lock, LockHandle);
+ IoReleaseCancelSpinLock( irql );
+ return STATUS_SUCCESS;
+ }
+
+
+ AddressFile->State = ADDRESSFILE_STATE_CLOSING;
+
+ while (!(IsListEmpty(&AddressFile->ReceiveDatagramQueue))) {
+
+ p = RemoveHeadList (&AddressFile->ReceiveDatagramQueue);
+ Request = LIST_ENTRY_TO_REQUEST (p);
+
+ REQUEST_INFORMATION(Request) = 0;
+ REQUEST_STATUS(Request) = STATUS_NETWORK_NAME_DELETED;
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+
+ CTEFreeLock(&Address->Lock, LockHandle);
+ IoReleaseCancelSpinLock( irql );
+
+ IpxCompleteRequest (Request);
+ IpxFreeRequest (Device, Request);
+
+ IpxDereferenceAddressFile (AddressFile, AFREF_RCV_DGRAM);
+
+ IoAcquireCancelSpinLock( &irql );
+ CTEGetLock(&Address->Lock, &LockHandle);
+
+ }
+
+ CTEFreeLock(&Address->Lock, LockHandle);
+ IoReleaseCancelSpinLock( irql );
+
+} /* IpxStopAddressFile */
+
+
+NTSTATUS
+IpxCloseAddressFile(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to close the addressfile pointed to by a file
+ object. If there is any activity to be run down, we will run it down
+ before we terminate the addressfile. We remove every connection and
+ datagram associated with this addressfile from the address database
+ and terminate their activity. Then, if there are no other outstanding
+ addressfiles open on this address, the address will go away.
+
+Arguments:
+
+ Request - the close request.
+
+Return Value:
+
+ STATUS_SUCCESS if all is well, STATUS_INVALID_HANDLE if the
+ request does not point to a real address.
+
+--*/
+
+{
+ PADDRESS Address;
+ PADDRESS_FILE AddressFile;
+ CTELockHandle LockHandle;
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+ AddressFile->CloseRequest = Request;
+
+ //
+ // We assume that addressFile has already been verified
+ // at this point.
+ //
+
+ Address = AddressFile->Address;
+ CTEAssert (Address);
+
+ //
+ // Remove us from the access info for this address.
+ //
+
+ ExAcquireResourceExclusive (&Device->AddressResource, TRUE);
+#ifdef ISN_NT
+ IoRemoveShareAccess (AddressFile->FileObject, &Address->u.ShareAccess);
+#endif
+ ExReleaseResource (&Device->AddressResource);
+
+ //
+ // If this address file had broadcasts enabled, turn it off.
+ //
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+ if (AddressFile->EnableBroadcast) {
+ AddressFile->EnableBroadcast = FALSE;
+ IpxRemoveBroadcast (Device);
+ }
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ IpxStopAddressFile (AddressFile);
+ IpxDereferenceAddressFile (AddressFile, AFREF_CREATE);
+
+ return STATUS_PENDING;
+
+} /* IpxCloseAddressFile */
+
+
diff --git a/private/ntos/tdi/isnp/ipx/config.c b/private/ntos/tdi/isnp/ipx/config.c
new file mode 100644
index 000000000..f5d8aefbf
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/config.c
@@ -0,0 +1,1715 @@
+/*++
+
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ config.c
+
+Abstract:
+
+ This contains all routines necessary for the support of the dynamic
+ configuration of the ISN IPX module.
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) 19-Sept-1995
+ Changes to support Plug and Play (in _PNP_POWER)
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+//
+// Local functions used to access the registry.
+//
+
+NTSTATUS
+IpxGetConfigValue(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+NTSTATUS
+IpxGetBindingValue(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+NTSTATUS
+IpxGetFrameType(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+NTSTATUS
+IpxAddBind(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+NTSTATUS
+IpxAddExport(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+NTSTATUS
+IpxReadLinkageInformation(
+ IN PCONFIG Config
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,IpxGetConfiguration)
+#pragma alloc_text(INIT,IpxFreeConfiguration)
+
+#ifndef _PNP_POWER
+#pragma alloc_text(INIT,IpxGetConfigValue)
+#pragma alloc_text(INIT,IpxGetBindingValue)
+#pragma alloc_text(INIT,IpxGetFrameType)
+#pragma alloc_text(INIT,IpxWriteDefaultAutoDetectType)
+#endif
+
+#pragma alloc_text(INIT,IpxAddBind)
+#pragma alloc_text(INIT,IpxAddExport)
+#pragma alloc_text(INIT,IpxReadLinkageInformation)
+#endif
+
+
+
+NTSTATUS
+IpxGetConfiguration (
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath,
+ OUT PCONFIG * ConfigPtr
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by IPX to get information from the configuration
+ management routines. We read the registry, starting at RegistryPath,
+ to get the parameters. If they don't exist, we use the defaults
+ set in ipxcnfg.h file. A list of adapters to bind to is chained
+ on to the config information.
+
+Arguments:
+
+ DriverObject - Used for logging errors.
+
+ RegistryPath - The name of IPX's node in the registry.
+
+ ConfigPtr - Returns the configuration information.
+
+Return Value:
+
+ Status - STATUS_SUCCESS if everything OK, STATUS_INSUFFICIENT_RESOURCES
+ otherwise.
+
+--*/
+
+{
+ PWSTR RegistryPathBuffer;
+ PCONFIG Config;
+ RTL_QUERY_REGISTRY_TABLE QueryTable[CONFIG_PARAMETERS+2];
+ NTSTATUS Status;
+ ULONG Zero = 0;
+ ULONG One = 1;
+ ULONG Five = 5;
+ ULONG Eight = 8;
+ ULONG Ten = 10;
+ ULONG Fifteen = 15;
+ ULONG Fifty = 50;
+ ULONG DefaultSocketStart = 0x4000;
+ ULONG DefaultSocketEnd = 0x8000;
+ ULONG RipSegments = RIP_SEGMENTS;
+ PWSTR Parameters = L"Parameters";
+ struct {
+ PWSTR KeyName;
+ PULONG DefaultValue;
+ } ParameterValues[CONFIG_PARAMETERS] = {
+ { L"DedicatedRouter", &Zero } ,
+ { L"InitDatagrams", &Ten } ,
+ { L"MaxDatagrams", &Fifty } ,
+ { L"RipAgeTime", &Five } , // minutes
+ { L"RipCount", &Five } ,
+ { L"RipTimeout", &One } , // half-second
+ { L"RipUsageTime", &Fifteen } , // minutes
+ { L"SourceRouteUsageTime", &Ten } , // minutes
+ { L"SocketUniqueness", &Eight } ,
+ { L"SocketStart", &DefaultSocketStart } ,
+ { L"SocketEnd", &DefaultSocketEnd } ,
+ { L"VirtualNetworkNumber", &Zero } ,
+ { L"MaxMemoryUsage", &Zero } ,
+ { L"RipTableSize", &RipSegments } ,
+ { L"VirtualNetworkOptional", &One } ,
+ { L"EthernetPadToEven", &One } ,
+ { L"EthernetExtraPadding", &Zero } ,
+ { L"SingleNetworkActive", &Zero } ,
+ { L"DisableDialoutSap", &Zero } ,
+ { L"DisableDialinNetbios", &One } ,
+ { L"VerifySourceAddress", &One } };
+ UINT i;
+
+
+ //
+ // Allocate memory for the main config structure.
+ //
+
+ Config = IpxAllocateMemory (sizeof(CONFIG), MEMORY_CONFIG, "Config");
+ if (Config == NULL) {
+ IpxWriteResourceErrorLog(
+ (PVOID)DriverObject,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ sizeof(CONFIG),
+ MEMORY_CONFIG);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ Config->DeviceName.Buffer = NULL;
+ InitializeListHead (&Config->BindingList);
+ Config->DriverObject = DriverObject;
+
+ //
+ // Read in the NDIS binding information.
+ //
+ // IpxReadLinkageInformation expects a null-terminated path,
+ // so we have to create one from the UNICODE_STRING.
+ //
+
+ RegistryPathBuffer = (PWSTR)IpxAllocateMemory(RegistryPath->Length + sizeof(WCHAR),
+ MEMORY_CONFIG, "RegistryPathBuffer");
+ if (RegistryPathBuffer == NULL) {
+ IpxFreeConfiguration(Config);
+ IpxWriteResourceErrorLog(
+ (PVOID)DriverObject,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ RegistryPath->Length + sizeof(WCHAR),
+ MEMORY_CONFIG);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ RtlCopyMemory (RegistryPathBuffer, RegistryPath->Buffer, RegistryPath->Length);
+ *(PWCHAR)(((PUCHAR)RegistryPathBuffer)+RegistryPath->Length) = (WCHAR)'\0';
+
+ Config->RegistryPathBuffer = RegistryPathBuffer;
+
+ //
+ // Determine what name to export and who to bind to.
+ //
+
+ Status = IpxReadLinkageInformation (Config);
+ if (Status != STATUS_SUCCESS) {
+
+ //
+ // It logged an error if it failed.
+ //
+
+ IpxFreeConfiguration(Config);
+ return Status;
+ }
+
+ //
+ // Read the per-transport (as opposed to per-binding)
+ // parameters.
+ //
+
+ //
+ // Set up QueryTable to do the following:
+ //
+
+ //
+ // 1) Switch to the Parameters key below IPX
+ //
+
+ QueryTable[0].QueryRoutine = NULL;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
+ QueryTable[0].Name = Parameters;
+
+ //
+ // 2-14) Call IpxGetConfigValue for each of the keys we
+ // care about.
+ //
+
+ for (i = 0; i < CONFIG_PARAMETERS; i++) {
+
+ QueryTable[i+1].QueryRoutine = IpxGetConfigValue;
+ QueryTable[i+1].Flags = 0;
+ QueryTable[i+1].Name = ParameterValues[i].KeyName;
+ QueryTable[i+1].EntryContext = (PVOID)i;
+ QueryTable[i+1].DefaultType = REG_DWORD;
+ QueryTable[i+1].DefaultData = (PVOID)(ParameterValues[i].DefaultValue);
+ QueryTable[i+1].DefaultLength = sizeof(ULONG);
+
+ }
+
+ //
+ // 15) Stop
+ //
+
+ QueryTable[CONFIG_PARAMETERS+1].QueryRoutine = NULL;
+ QueryTable[CONFIG_PARAMETERS+1].Flags = 0;
+ QueryTable[CONFIG_PARAMETERS+1].Name = NULL;
+
+
+ Status = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE,
+ Config->RegistryPathBuffer,
+ QueryTable,
+ (PVOID)Config,
+ NULL);
+
+ if (Status != STATUS_SUCCESS) {
+
+ IpxFreeConfiguration(Config);
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)DriverObject,
+ EVENT_IPX_ILLEGAL_CONFIG,
+ 905,
+ Status,
+ Parameters,
+ 0,
+ NULL);
+ return STATUS_DEVICE_CONFIGURATION_ERROR;
+ }
+
+ //
+ // For PnP, we need to keep this path around
+ //
+#ifndef _PNP_POWER
+ IpxFreeMemory (RegistryPathBuffer, RegistryPath->Length + sizeof(WCHAR), MEMORY_CONFIG, "RegistryPathBuffer");
+#endif _PNP_POWER
+
+ *ConfigPtr = Config;
+
+ return STATUS_SUCCESS;
+
+} /* IpxGetConfiguration */
+
+
+VOID
+IpxFreeConfiguration (
+ IN PCONFIG Config
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by IPX to get free any storage that was allocated
+ by IpxGetConfiguration in producing the specified CONFIG structure.
+
+Arguments:
+
+ Config - A pointer to the configuration information structure.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PLIST_ENTRY p;
+ PBINDING_CONFIG Binding;
+
+ while (!IsListEmpty (&Config->BindingList)) {
+ p = RemoveHeadList (&Config->BindingList);
+ Binding = CONTAINING_RECORD (p, BINDING_CONFIG, Linkage);
+ IpxFreeMemory (Binding->AdapterName.Buffer, Binding->AdapterName.MaximumLength, MEMORY_CONFIG, "NameBuffer");
+ IpxFreeMemory (Binding, sizeof(BINDING_CONFIG), MEMORY_CONFIG, "Binding");
+ }
+
+ if (Config->DeviceName.Buffer) {
+ IpxFreeMemory (Config->DeviceName.Buffer, Config->DeviceName.MaximumLength, MEMORY_CONFIG, "DeviceName");
+ }
+
+ IpxFreeMemory (Config, sizeof(CONFIG), MEMORY_CONFIG, "Config");
+
+} /* IpxFreeConfiguration */
+
+
+NTSTATUS
+IpxGetConfigValue(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a callback routine for RtlQueryRegistryValues
+ It is called for each entry in the Parameters
+ node to set the config values. The table is set up
+ so that this function will be called with correct default
+ values for keys that are not present.
+
+Arguments:
+
+ ValueName - The name of the value (ignored).
+
+ ValueType - The type of the value (REG_DWORD -- ignored).
+
+ ValueData - The data for the value.
+
+ ValueLength - The length of ValueData (ignored).
+
+ Context - A pointer to the CONFIG structure.
+
+ EntryContext - The index in Config->Parameters to save the value.
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ PCONFIG Config = (PCONFIG)Context;
+
+ UNREFERENCED_PARAMETER(ValueName);
+ UNREFERENCED_PARAMETER(ValueType);
+ UNREFERENCED_PARAMETER(ValueLength);
+
+ if ((ValueType != REG_DWORD) || (ValueLength != sizeof(ULONG))) {
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)Config->DriverObject,
+ EVENT_IPX_ILLEGAL_CONFIG,
+ 904,
+ STATUS_INVALID_PARAMETER,
+ ValueName,
+ 0,
+ NULL);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ IPX_DEBUG (CONFIG, ("Config parameter %d, value %lx\n",
+ (ULONG)EntryContext, *(UNALIGNED ULONG *)ValueData));
+ Config->Parameters[(ULONG)EntryContext] = *(UNALIGNED ULONG *)ValueData;
+
+ return STATUS_SUCCESS;
+
+} /* IpxGetConfigValue */
+
+
+NTSTATUS
+IpxGetBindingValue(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a callback routine for RtlQueryRegistryValues
+ It is called for each entry in the NetConfig\DriverNN
+ node to set the per-binding values. The table is set up
+ so that this function will be called with correct default
+ values for keys that are not present.
+
+Arguments:
+
+ ValueName - The name of the value (ignored).
+
+ ValueType - The type of the value (REG_DWORD -- ignored).
+
+ ValueData - The data for the value.
+
+ ValueLength - The length of ValueData (ignored).
+
+ Context - A pointer to the BINDING_CONFIG structure.
+
+ EntryContext - The index in Binding->Parameters to save the value.
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ PBINDING_CONFIG Binding = (PBINDING_CONFIG)Context;
+
+ UNREFERENCED_PARAMETER(ValueName);
+ UNREFERENCED_PARAMETER(ValueType);
+ UNREFERENCED_PARAMETER(ValueLength);
+
+ if ((ValueType != REG_DWORD) || (ValueLength != sizeof(ULONG))) {
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)Binding->DriverObject,
+ EVENT_IPX_ILLEGAL_CONFIG,
+ 903,
+ STATUS_INVALID_PARAMETER,
+ ValueName,
+ 0,
+ NULL);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ IPX_DEBUG (CONFIG, ("Binding parameter %d, value %lx\n",
+ (ULONG)EntryContext, *(UNALIGNED ULONG *)ValueData));
+ Binding->Parameters[(ULONG)EntryContext] = *(UNALIGNED ULONG *)ValueData;
+
+ return STATUS_SUCCESS;
+
+} /* IpxGetBindingValue */
+
+
+NTSTATUS
+IpxGetFrameType(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a callback routine for RtlQueryRegistryValues.
+ It is called for each of the entry in the "PktType" and
+ "NetworkNumber" multi-strings for a given binding.
+
+Arguments:
+
+ ValueName - The name of the value ("PktType" or "NetworkNumber" -- ignored).
+
+ ValueType - The type of the value (REG_MULTI_SZ -- ignored).
+
+ ValueData - The null-terminated data for the value.
+
+ ValueLength - The length of ValueData.
+
+ Context - A pointer to the BINDING_CONFIG structure.
+
+ EntryContext - A pointer to a count of multi-string entries.
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ PBINDING_CONFIG Binding = (PBINDING_CONFIG)Context;
+ ULONG IntegerValue;
+ PWCHAR Cur;
+ PULONG Count = (PULONG)EntryContext;
+
+ if ((ValueType != REG_SZ) ||
+ (*Count >= 4)) {
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)Binding->DriverObject,
+ EVENT_IPX_ILLEGAL_CONFIG,
+ 903,
+ STATUS_INVALID_PARAMETER,
+ ValueName,
+ 0,
+ NULL);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ IntegerValue = 0;
+ for (Cur = (PWCHAR)(ValueData); ; Cur++) {
+ if (*Cur >= L'0' && *Cur <= L'9') {
+ IntegerValue = (IntegerValue * 16) + (*Cur - L'0');
+ } else if (*Cur >= L'A' && *Cur <= L'F') {
+ IntegerValue = (IntegerValue * 16) + (*Cur - L'A' + 10);
+ } else if (*Cur >= L'a' && *Cur <= L'f') {
+ IntegerValue = (IntegerValue * 16) + (*Cur - L'a' + 10);
+ } else {
+ break;
+ }
+ }
+
+ if (((PWCHAR)ValueName)[0] == L'P') {
+
+ //
+ // PktType. We map arcnet to 802_3 so the code around
+ // here can assume there are only four packets type --
+ // the frame type is ignored later for arcnet.
+ //
+
+ if ((IntegerValue > ISN_FRAME_TYPE_ARCNET) &&
+ (IntegerValue != ISN_FRAME_TYPE_AUTO)) {
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)Binding->DriverObject,
+ EVENT_IPX_ILLEGAL_CONFIG,
+ 903,
+ STATUS_INVALID_PARAMETER,
+ ValueName,
+ 0,
+ NULL);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ IPX_DEBUG (CONFIG, ("PktType(%d) is %lx\n", *Count, IntegerValue));
+ if (IntegerValue == ISN_FRAME_TYPE_ARCNET) {
+ Binding->FrameType[*Count] = ISN_FRAME_TYPE_802_3;
+ } else {
+ Binding->FrameType[*Count] = IntegerValue;
+ }
+
+ } else {
+
+ //
+ // NetworkNumber
+ //
+
+ IPX_DEBUG (CONFIG, ("NetworkNumber(%d) is %d\n", *Count, IntegerValue));
+ Binding->NetworkNumber[*Count] = IntegerValue;
+
+ }
+
+ ++(*Count);
+
+ return STATUS_SUCCESS;
+
+} /* IpxGetFrameType */
+
+
+NTSTATUS
+IpxAddBind(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a callback routine for RtlQueryRegistryValues
+ It is called for each piece of the "Bind" multi-string and
+ saves the information in a Config structure. It
+ also queries the per-binding information and stores it.
+
+Arguments:
+
+ ValueName - The name of the value ("Bind" -- ignored).
+
+ ValueType - The type of the value (REG_SZ -- ignored).
+
+ ValueData - The null-terminated data for the value.
+
+ ValueLength - The length of ValueData.
+
+ Context - A pointer to the Config structure.
+
+ EntryContext - A pointer to a count of binds that is incremented.
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ PCONFIG Config = (PCONFIG)Context;
+ PBINDING_CONFIG Binding;
+ PULONG CurBindNum = ((PULONG)EntryContext);
+ RTL_QUERY_REGISTRY_TABLE QueryTable[BINDING_PARAMETERS+4];
+ ULONG FrameTypeCount, NetworkNumberCount;
+ ULONG StringLoc;
+ BOOLEAN AutoDetect;
+ ULONG AutoDetectLoc;
+ ULONG SlideCount;
+ PWCHAR NameBuffer;
+ NTSTATUS Status;
+ BOOLEAN FrameTypeUsed[ISN_FRAME_TYPE_MAX];
+ ULONG Zero = 0;
+ ULONG One = 1;
+ ULONG DefaultBindSap = 0x8137;
+ ULONG DefaultAutoDetectType = ISN_FRAME_TYPE_802_2;
+ PWSTR Subkey = L"NetConfig\\12345678901234567890"; // BUGBUG: hack
+ PWSTR ValueDataWstr = (PWSTR)ValueData;
+ struct {
+ PWSTR KeyName;
+ PULONG DefaultValue;
+ } ParameterValues[BINDING_PARAMETERS] = {
+ { L"MaxPktSize", &Zero } ,
+ { L"BindSap", &DefaultBindSap } ,
+ { L"DefaultAutoDetectType", &DefaultAutoDetectType } ,
+ { L"SourceRouting", &One } ,
+ { L"SourceRouteDef", &Zero } ,
+ { L"SourceRouteBcast", &Zero } ,
+ { L"SourceRouteMcast", &Zero } ,
+ { L"EnableFuncaddr", &One } ,
+ { L"EnableWanRouter", &One } };
+ ULONG BindingPreference[ISN_FRAME_TYPE_MAX] = {
+ ISN_FRAME_TYPE_802_2,
+ ISN_FRAME_TYPE_802_3,
+ ISN_FRAME_TYPE_ETHERNET_II,
+ ISN_FRAME_TYPE_SNAP };
+
+ UINT i, j, k;
+
+ UNREFERENCED_PARAMETER(ValueName);
+ UNREFERENCED_PARAMETER(ValueType);
+
+
+ Binding = (PBINDING_CONFIG)IpxAllocateMemory (sizeof(BINDING_CONFIG), MEMORY_CONFIG, "Binding");
+ if (Binding == NULL) {
+ IpxWriteResourceErrorLog(
+ (PVOID)Config->DriverObject,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ sizeof(BINDING_CONFIG),
+ MEMORY_CONFIG);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ NameBuffer = (PWCHAR)IpxAllocateMemory (ValueLength, MEMORY_CONFIG, "NameBuffer");
+ if (NameBuffer == NULL) {
+ IpxFreeMemory (Binding, sizeof(BINDING_CONFIG), MEMORY_CONFIG, "Binding");
+ IpxWriteResourceErrorLog(
+ (PVOID)Config->DriverObject,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ ValueLength,
+ MEMORY_CONFIG);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlCopyMemory (NameBuffer, ValueData, ValueLength);
+ Binding->AdapterName.Buffer = NameBuffer;
+ Binding->AdapterName.Length = (USHORT)(ValueLength - sizeof(WCHAR));
+ Binding->AdapterName.MaximumLength = (USHORT)ValueLength;
+
+ Binding->DriverObject = Config->DriverObject;
+
+ FrameTypeCount = 0;
+ NetworkNumberCount = 0;
+
+ //
+ // The structure is allocated OK, insert it into the list.
+ //
+
+ InsertTailList (&Config->BindingList, &Binding->Linkage);
+ ++(*CurBindNum);
+
+
+ //
+ // Set up QueryTable to do the following:
+ //
+
+ //
+ // 1) Switch to the NetConfig\XXXX key below IPX
+ // (we construct the right name in Subkey,
+ // first scan back to find the \, then copy
+ // the rest over, including the final '\0').
+ //
+
+ StringLoc = (ValueLength / sizeof(WCHAR)) - 2;
+ while (ValueDataWstr[StringLoc] != L'\\') {
+ --StringLoc;
+ }
+ RtlCopyMemory(&Subkey[10], &ValueDataWstr[StringLoc+1], ValueLength - ((StringLoc+1) * sizeof(WCHAR)));
+
+ QueryTable[0].QueryRoutine = NULL;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
+ QueryTable[0].Name = Subkey;
+
+ //
+ // 2) Call IpxGetFrameType for each part of the
+ // "PktType" multi-string.
+ //
+
+ QueryTable[1].QueryRoutine = IpxGetFrameType;
+ QueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED;
+ QueryTable[1].Name = L"PktType";
+ QueryTable[1].EntryContext = &FrameTypeCount;
+ QueryTable[1].DefaultType = REG_NONE;
+
+ //
+ // 3) Call IpxGetFrameType for each part of the
+ // "NetworkNumber" multi-string.
+ //
+
+ QueryTable[2].QueryRoutine = IpxGetFrameType;
+ QueryTable[2].Flags = RTL_QUERY_REGISTRY_REQUIRED;
+ QueryTable[2].Name = L"NetworkNumber";
+ QueryTable[2].EntryContext = &NetworkNumberCount;
+ QueryTable[2].DefaultType = REG_NONE;
+
+ //
+ // 4-11) Call IpxGetBindingValue for each of the keys we
+ // care about.
+ //
+
+ for (i = 0; i < BINDING_PARAMETERS; i++) {
+
+ QueryTable[i+3].QueryRoutine = IpxGetBindingValue;
+ QueryTable[i+3].Flags = 0;
+ QueryTable[i+3].Name = ParameterValues[i].KeyName;
+ QueryTable[i+3].EntryContext = (PVOID)i;
+ QueryTable[i+3].DefaultType = REG_DWORD;
+ QueryTable[i+3].DefaultData = (PVOID)(ParameterValues[i].DefaultValue);
+ QueryTable[i+3].DefaultLength = sizeof(ULONG);
+
+ }
+
+ //
+ // 12) Stop
+ //
+
+ QueryTable[BINDING_PARAMETERS+3].QueryRoutine = NULL;
+ QueryTable[BINDING_PARAMETERS+3].Flags = 0;
+ QueryTable[BINDING_PARAMETERS+3].Name = NULL;
+
+
+ IPX_DEBUG (CONFIG, ("Read bind key for %ws (%ws)\n", ValueData, Subkey));
+
+ Status = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE,
+ Config->RegistryPathBuffer,
+ QueryTable,
+ (PVOID)Binding,
+ NULL);
+
+ if (Status != STATUS_SUCCESS) {
+
+ //
+ // The binding will get freed during cleanup.
+ //
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)Config->DriverObject,
+ EVENT_IPX_ILLEGAL_CONFIG,
+ 906,
+ Status,
+ Subkey,
+ 0,
+ NULL);
+ return STATUS_DEVICE_CONFIGURATION_ERROR;
+ }
+
+ if (FrameTypeCount == 0) {
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)Config->DriverObject,
+ EVENT_IPX_NO_FRAME_TYPES,
+ 907,
+ Status,
+ Subkey + 10,
+ 0,
+ NULL);
+ }
+
+ if (FrameTypeCount > NetworkNumberCount) {
+ for (i = NetworkNumberCount; i <FrameTypeCount; i++) {
+ Binding->NetworkNumber[i] = 0;
+ }
+ }
+ Binding->FrameTypeCount = FrameTypeCount;
+
+ //
+ // Go through and eliminate duplicates from the frame
+ // type array.
+ //
+
+ for (i = 0; i < Binding->FrameTypeCount; i++) {
+
+ for (j = i+1; j < Binding->FrameTypeCount; j++) {
+
+ if (Binding->FrameType[j] == Binding->FrameType[i]) {
+
+ IPX_DEBUG (CONFIG, ("Frame types %d and %d identical\n", i, j));
+
+ //
+ // A duplicate, slide everything else down.
+ //
+
+ for (k = j+1; k < Binding->FrameTypeCount; k++) {
+ Binding->FrameType[k-1] = Binding->FrameType[k];
+ Binding->NetworkNumber[k-1] = Binding->NetworkNumber[k];
+ }
+ --Binding->FrameTypeCount;
+
+ --j; // so we check whoever just moved into this spot.
+ }
+ }
+ }
+
+
+ //
+ // Mark all the explicitly configured frame types, and
+ // see if we have to auto-detect.
+ //
+
+ for (i = 0; i < 4; i++) {
+ FrameTypeUsed[i] = FALSE;
+ }
+
+ AutoDetect = FALSE;
+ for (i = 0; i < Binding->FrameTypeCount; i++) {
+ if (Binding->FrameType[i] == ISN_FRAME_TYPE_AUTO) {
+ AutoDetectLoc = i;
+ AutoDetect = TRUE;
+ } else {
+ Binding->AutoDetect[i] = FALSE;
+ Binding->DefaultAutoDetect[i] = FALSE;
+ FrameTypeUsed[Binding->FrameType[i]] = TRUE;
+ }
+ }
+
+ if (!AutoDetect) {
+ IPX_DEBUG (AUTO_DETECT, ("No bindings auto-detected\n"));
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // Slide everything that is past the auto-detect point up
+ // to the end.
+ //
+
+ SlideCount = Binding->FrameTypeCount - AutoDetectLoc - 1;
+ for (j = 3; j > 3 - SlideCount; j--) {
+ Binding->FrameType[j] = Binding->FrameType[j-(3-Binding->FrameTypeCount)];
+ Binding->NetworkNumber[j] = Binding->NetworkNumber[j-(3-Binding->FrameTypeCount)];
+ Binding->AutoDetect[j] = Binding->AutoDetect[j-(3-Binding->FrameTypeCount)];
+ Binding->DefaultAutoDetect[j] = Binding->DefaultAutoDetect[j-(3-Binding->FrameTypeCount)];
+ }
+
+ //
+ // Now fill in any frame types that are not hard-coded,
+ // this will start at AutoDetectLoc and exactly fill up
+ // the gap created when we slid things up above. We
+ // first put the default auto-detect at the first spot.
+ //
+
+ if (!FrameTypeUsed[Binding->Parameters[BINDING_DEFAULT_AUTO_DETECT]]) {
+ Binding->FrameType[AutoDetectLoc] = Binding->Parameters[BINDING_DEFAULT_AUTO_DETECT];
+ Binding->NetworkNumber[AutoDetectLoc] = 0;
+ Binding->AutoDetect[AutoDetectLoc] = TRUE;
+ Binding->DefaultAutoDetect[AutoDetectLoc] = TRUE;
+ ++AutoDetectLoc;
+ FrameTypeUsed[Binding->Parameters[BINDING_DEFAULT_AUTO_DETECT]] = TRUE;
+ }
+
+ //
+ // Now fill in the array, using the preference order in
+ // the BindingPreference array (this comes into effect
+ // because the first frame type in our list that we
+ // find is used).
+ //
+
+ for (i = 0; i < ISN_FRAME_TYPE_MAX; i++) {
+
+ if (!FrameTypeUsed[BindingPreference[i]]) {
+ Binding->FrameType[AutoDetectLoc] = BindingPreference[i];
+ Binding->NetworkNumber[AutoDetectLoc] = 0;
+ Binding->AutoDetect[AutoDetectLoc] = TRUE;
+ Binding->DefaultAutoDetect[AutoDetectLoc] = FALSE;
+ ++AutoDetectLoc;
+ }
+ }
+
+ Binding->FrameTypeCount = ISN_FRAME_TYPE_MAX;
+
+#if DBG
+ for (i = 0; i < ISN_FRAME_TYPE_MAX; i++) {
+ IPX_DEBUG (AUTO_DETECT, ("%d: type %d, net %d, auto %d\n",
+ i, Binding->FrameType[i], Binding->NetworkNumber[i], Binding->AutoDetect[i]));
+ }
+#endif
+
+ return STATUS_SUCCESS;
+
+} /* IpxAddBind */
+
+
+NTSTATUS
+IpxAddExport(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a callback routine for RtlQueryRegistryValues
+ It is called for each piece of the "Export" multi-string. It
+ saves the first callback string in the Config structure.
+
+Arguments:
+
+ ValueName - The name of the value ("Export" -- ignored).
+
+ ValueType - The type of the value (REG_SZ -- ignored).
+
+ ValueData - The null-terminated data for the value.
+
+ ValueLength - The length of ValueData.
+
+ Context - A pointer to the Config structure.
+
+ EntryContext - A pointer to a ULONG that goes to 1 after the
+ first call to this routine (so we know to ignore other ones).
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ PCONFIG Config = (PCONFIG)Context;
+ PULONG ValueReadOk = ((PULONG)EntryContext);
+ PWCHAR NameBuffer;
+
+ UNREFERENCED_PARAMETER(ValueName);
+ UNREFERENCED_PARAMETER(ValueType);
+
+ if (*ValueReadOk == 0) {
+
+ IPX_DEBUG (CONFIG, ("Read export value %ws\n", ValueData));
+
+ NameBuffer = (PWCHAR)IpxAllocateMemory (ValueLength, MEMORY_CONFIG, "DeviceName");
+ if (NameBuffer == NULL) {
+ IpxWriteResourceErrorLog(
+ (PVOID)Config->DriverObject,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ ValueLength,
+ MEMORY_CONFIG);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlCopyMemory (NameBuffer, ValueData, ValueLength);
+ Config->DeviceName.Buffer = NameBuffer;
+ Config->DeviceName.Length = (USHORT)(ValueLength - sizeof(WCHAR));
+ Config->DeviceName.MaximumLength = (USHORT)ValueLength;
+
+ //
+ // Set this to ignore any other callbacks and let the
+ // caller know we read something.
+ //
+
+ *ValueReadOk = 1;
+
+ }
+
+ return STATUS_SUCCESS;
+
+} /* IpxAddExport */
+
+
+NTSTATUS
+IpxReadLinkageInformation(
+ IN PCONFIG Config
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by IPX to read its linkage information
+ from the registry.
+
+Arguments:
+
+ Config - The config structure which will have per-binding information
+ linked on to it.
+
+Return Value:
+
+ The status of the operation.
+
+--*/
+
+{
+
+ NTSTATUS Status;
+ RTL_QUERY_REGISTRY_TABLE QueryTable[3];
+ PWSTR Subkey = L"Linkage";
+ PWSTR Bind = L"Bind";
+ PWSTR Export = L"Export";
+ ULONG ValueReadOk;
+
+ //
+ // Set up QueryTable to do the following:
+ //
+
+ //
+ // 1) Switch to the Linkage key below IPX
+ //
+
+ QueryTable[0].QueryRoutine = NULL;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
+ QueryTable[0].Name = Subkey;
+
+ //
+ // 1) Call IpxAddExport for each string in "Export"
+ //
+
+ QueryTable[1].QueryRoutine = IpxAddExport;
+ QueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED;
+ QueryTable[1].Name = Export;
+ QueryTable[1].EntryContext = (PVOID)&ValueReadOk;
+ QueryTable[1].DefaultType = REG_NONE;
+
+ //
+ // 2) Stop
+ //
+
+ QueryTable[2].QueryRoutine = NULL;
+ QueryTable[2].Flags = 0;
+ QueryTable[2].Name = NULL;
+
+
+ ValueReadOk = 0;
+
+ Status = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE,
+ Config->RegistryPathBuffer,
+ QueryTable,
+ (PVOID)Config,
+ NULL);
+
+ if ((Status != STATUS_SUCCESS) || (ValueReadOk == 0)) {
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)Config->DriverObject,
+ EVENT_IPX_ILLEGAL_CONFIG,
+ 901,
+ Status,
+ Export,
+ 0,
+ NULL);
+ return STATUS_DEVICE_CONFIGURATION_ERROR;
+ }
+
+#ifndef _PNP_POWER
+//
+// This will be done as and when adapters appear.
+//
+ //
+ // 1) Change to call IpxAddBind for each string in "Bind"
+ //
+
+ QueryTable[1].QueryRoutine = IpxAddBind;
+ QueryTable[1].Flags = 0; // not required
+ QueryTable[1].Name = Bind;
+ QueryTable[1].EntryContext = (PVOID)&Config->BindCount;
+ QueryTable[1].DefaultType = REG_NONE;
+
+ Config->BindCount = 0;
+
+ Status = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE,
+ Config->RegistryPathBuffer,
+ QueryTable,
+ (PVOID)Config,
+ NULL);
+
+ //
+ // For the moment fail if we find no bindings -- eventually when
+ // we support dynamic binding we should stick around in this case.
+ //
+
+ if ((Status != STATUS_SUCCESS) || (Config->BindCount == 0)) {
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)Config->DriverObject,
+ EVENT_IPX_ILLEGAL_CONFIG,
+ 902,
+ Status,
+ Bind,
+ 0,
+ NULL);
+ return STATUS_DEVICE_CONFIGURATION_ERROR;
+ }
+#endif
+ return STATUS_SUCCESS;
+
+} /* IpxReadLinkageInformation */
+
+
+VOID
+IpxWriteDefaultAutoDetectType(
+ IN PUNICODE_STRING RegistryPath,
+ IN struct _ADAPTER * Adapter,
+ IN ULONG FrameType
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when we were unable to detect the default
+ auto-detect type and instead found a different one. We update
+ the "DefaultAutoDetectType" in the registry.
+
+Arguments:
+
+ RegistryPath - The name of IPX's node in the registry.
+
+ Adapter - The adapter which we auto-detected on.
+
+ FrameType - The new auto-detected value.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PWSTR FullRegistryPath;
+ PUCHAR CurRegistryPath;
+ ULONG FullRegistryPathLength;
+ ULONG AdapterNameLength;
+ WCHAR NetConfigName[] = L"\\NetConfig";
+ static PWCHAR FrameTypeNames[4] = { L"Ethernet II", L"802.3", L"802.2", L"SNAP" };
+ PWCHAR CurAdapterName;
+ NTSTATUS Status;
+
+
+ //
+ // We need to allocate a buffer which contains the registry path,
+ // followed by "NetConfig", followed by the adapter name, and
+ // then NULL-terminated.
+ //
+
+ CurAdapterName = &Adapter->AdapterName[(Adapter->AdapterNameLength/sizeof(WCHAR))-2];
+ while (*CurAdapterName != L'\\') {
+ --CurAdapterName;
+ }
+ CurAdapterName;
+ AdapterNameLength = Adapter->AdapterNameLength - ((CurAdapterName - Adapter->AdapterName) * sizeof(WCHAR)) - sizeof(WCHAR);
+
+ FullRegistryPathLength = RegistryPath->Length + sizeof(NetConfigName) + AdapterNameLength;
+
+ FullRegistryPath = (PWSTR)IpxAllocateMemory (FullRegistryPathLength, MEMORY_CONFIG, "FullRegistryPath");
+ if (FullRegistryPath == NULL) {
+ IpxWriteResourceErrorLog(
+ IpxDevice->DeviceObject,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ FullRegistryPathLength,
+ MEMORY_CONFIG);
+ return;
+ }
+
+ CurRegistryPath = (PUCHAR)FullRegistryPath;
+ RtlCopyMemory (CurRegistryPath, RegistryPath->Buffer, RegistryPath->Length);
+ CurRegistryPath += RegistryPath->Length;
+ RtlCopyMemory (CurRegistryPath, NetConfigName, sizeof(NetConfigName) - sizeof(WCHAR));
+ CurRegistryPath += (sizeof(NetConfigName) - sizeof(WCHAR));
+ RtlCopyMemory (CurRegistryPath, CurAdapterName, AdapterNameLength);
+ CurRegistryPath += AdapterNameLength;
+ *(PWCHAR)CurRegistryPath = L'\0';
+
+ Status = RtlWriteRegistryValue(
+ RTL_REGISTRY_ABSOLUTE,
+ FullRegistryPath,
+ L"DefaultAutoDetectType",
+ REG_DWORD,
+ &FrameType,
+ sizeof(ULONG));
+
+ IpxFreeMemory (FullRegistryPath, FullRegistryPathLength, MEMORY_CONFIG, "FullRegistryPath");
+
+ IpxWriteGeneralErrorLog(
+ IpxDevice->DeviceObject,
+ EVENT_IPX_NEW_DEFAULT_TYPE,
+ 888,
+ STATUS_SUCCESS,
+ FrameTypeNames[FrameType],
+ 0,
+ NULL);
+
+} /* IpxWriteDefaultAutoDetectType */
+
+
+#ifdef _PNP_POWER
+//
+// Vnet# and VnetOptional
+//
+#define VIRTUAL_NETWORK_PARAMETERS 2
+
+NTSTATUS
+IpxPnPGetVirtualNetworkNumber (
+ IN PCONFIG Config
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by IPX to read the virtual network number
+ from the registry. This is called on appearance/disappearance of an
+ adapter from the system. We read the registry, starting at RegistryPath,
+ to get the value of the VirtualNetworkNumber parameter. If it doesn't
+ exist, we use the default set in ipxcnfg.h file.
+ Adapted from IpxGetConfiguration().
+
+Arguments:
+
+ Config - Contians the configuration information.
+
+Return Value:
+
+ Status - STATUS_SUCCESS if everything OK, STATUS_DEVICE_CONFIGURATION_ERROR
+ otherwise.
+
+--*/
+
+{
+ RTL_QUERY_REGISTRY_TABLE QueryTable[VIRTUAL_NETWORK_PARAMETERS+2];
+ NTSTATUS Status;
+ ULONG Zero = 0;
+ ULONG One = 1;
+ PWSTR Parameters = L"Parameters";
+ struct {
+ PWSTR KeyName;
+ PULONG DefaultValue;
+ } ParameterValues[VIRTUAL_NETWORK_PARAMETERS] = {
+ { L"VirtualNetworkNumber", &Zero } ,
+ { L"VirtualNetworkOptional", &One } };
+ UINT i;
+
+ //
+ // Read the virtual net number from the parameters.
+ //
+
+ //
+ // Set up QueryTable to do the following:
+ //
+
+ //
+ // 1) Switch to the Parameters key below IPX
+ //
+
+ QueryTable[0].QueryRoutine = NULL;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
+ QueryTable[0].Name = Parameters;
+
+ //
+ // 2) Call IpxGetConfigValue for the virtual net number key
+ //
+
+ QueryTable[1].QueryRoutine = IpxGetConfigValue;
+ QueryTable[1].Flags = 0;
+ QueryTable[1].Name = ParameterValues[0].KeyName;
+ QueryTable[1].EntryContext = (PVOID)CONFIG_VIRTUAL_NETWORK;
+ QueryTable[1].DefaultType = REG_DWORD;
+ QueryTable[1].DefaultData = (PVOID)(ParameterValues[0].DefaultValue);
+ QueryTable[1].DefaultLength = sizeof(ULONG);
+
+ //
+ // 2) Call IpxGetConfigValue for the virtual net optional key
+ //
+
+ QueryTable[2].QueryRoutine = IpxGetConfigValue;
+ QueryTable[2].Flags = 0;
+ QueryTable[2].Name = ParameterValues[1].KeyName;
+ QueryTable[2].EntryContext = (PVOID)CONFIG_VIRTUAL_OPTIONAL;
+ QueryTable[2].DefaultType = REG_DWORD;
+ QueryTable[2].DefaultData = (PVOID)(ParameterValues[1].DefaultValue);
+ QueryTable[2].DefaultLength = sizeof(ULONG);
+
+ //
+ // 15) Stop
+ //
+
+ QueryTable[3].QueryRoutine = NULL;
+ QueryTable[3].Flags = 0;
+ QueryTable[3].Name = NULL;
+
+
+ Status = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE,
+ Config->RegistryPathBuffer,
+ QueryTable,
+ (PVOID)Config,
+ NULL);
+
+ if (Status != STATUS_SUCCESS) {
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)Config->DriverObject,
+ EVENT_IPX_ILLEGAL_CONFIG,
+ 905,
+ Status,
+ Parameters,
+ 0,
+ NULL);
+ return STATUS_DEVICE_CONFIGURATION_ERROR;
+ }
+
+ return STATUS_SUCCESS;
+
+} /* IpxPnPGetNetworkNumber */
+
+
+NTSTATUS
+IpxPnPGetAdapterParameters(
+ IN PCONFIG Config,
+ IN PNDIS_STRING DeviceName,
+ IN OUT PBINDING_CONFIG Binding
+ )
+/*++
+
+Routine Description:
+
+ This routine is called by IPX to read the adapter-specific parameters
+ from the registry on PnP appearance of an adapter in the system.
+ We read the registry, starting at RegistryPath\NetConfig\DeviceName.
+
+ Adapted from IpxAddBind().
+
+Arguments:
+
+ Config - Config structure - supplies the DeviceObject and RegistryPathBuffer.
+
+ DeviceName - name of the adapter that was added.
+
+ Binding - Returns the configuration information per adapter.
+
+Return Value:
+
+ Status - STATUS_SUCCESS if everything OK, STATUS_DEVICE_CONFIGURATION_ERROR
+ otherwise.
+
+--*/
+{
+ RTL_QUERY_REGISTRY_TABLE QueryTable[BINDING_PARAMETERS+4];
+ ULONG FrameTypeCount, NetworkNumberCount;
+ ULONG StringLoc;
+ BOOLEAN AutoDetect;
+ ULONG AutoDetectLoc;
+ ULONG SlideCount;
+ PWCHAR NameBuffer;
+ NTSTATUS Status;
+ BOOLEAN FrameTypeUsed[ISN_FRAME_TYPE_MAX];
+ ULONG Zero = 0;
+ ULONG One = 1;
+ ULONG DefaultBindSap = 0x8137;
+ ULONG DefaultAutoDetectType = ISN_FRAME_TYPE_802_2;
+ PWSTR Subkey = L"NetConfig\\12345678901234567890"; // BUGBUG: hack
+ struct {
+ PWSTR KeyName;
+ PULONG DefaultValue;
+ } ParameterValues[BINDING_PARAMETERS] = {
+ { L"MaxPktSize", &Zero } ,
+ { L"BindSap", &DefaultBindSap } ,
+ { L"DefaultAutoDetectType", &DefaultAutoDetectType } ,
+ { L"SourceRouting", &One } ,
+ { L"SourceRouteDef", &Zero } ,
+ { L"SourceRouteBcast", &Zero } ,
+ { L"SourceRouteMcast", &Zero } ,
+ { L"EnableFuncaddr", &One } ,
+ { L"EnableWanRouter", &One } };
+ ULONG BindingPreference[ISN_FRAME_TYPE_MAX] = {
+ ISN_FRAME_TYPE_802_2,
+ ISN_FRAME_TYPE_802_3,
+ ISN_FRAME_TYPE_ETHERNET_II,
+ ISN_FRAME_TYPE_SNAP };
+
+ UINT i, j, k;
+
+ FrameTypeCount = 0;
+ NetworkNumberCount = 0;
+
+ //
+ // The structure is allocated OK, insert it into the list.
+ //
+
+// InsertTailList (&Config->BindingList, &Binding->Linkage);
+// ++(*CurBindNum);
+
+
+ //
+ // Set up QueryTable to do the following:
+ //
+
+ //
+ // 1) Switch to the NetConfig\XXXX key below IPX
+ // (we construct the right name in Subkey,
+ // first scan back to find the \, then copy
+ // the rest over, including the final '\0').
+ //
+ StringLoc = (DeviceName->MaximumLength / sizeof(WCHAR)) - 2;
+ while (DeviceName->Buffer[StringLoc] != L'\\') {
+ --StringLoc;
+ }
+ RtlCopyMemory(&Subkey[10], &DeviceName->Buffer[StringLoc+1], DeviceName->MaximumLength - ((StringLoc+1) * sizeof(WCHAR)));
+
+ QueryTable[0].QueryRoutine = NULL;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
+ QueryTable[0].Name = Subkey;
+
+ //
+ // 2) Call IpxGetFrameType for each part of the
+ // "PktType" multi-string.
+ //
+
+ QueryTable[1].QueryRoutine = IpxGetFrameType;
+ QueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED;
+ QueryTable[1].Name = L"PktType";
+ QueryTable[1].EntryContext = &FrameTypeCount;
+ QueryTable[1].DefaultType = REG_NONE;
+
+ //
+ // 3) Call IpxGetFrameType for each part of the
+ // "NetworkNumber" multi-string.
+ //
+
+ QueryTable[2].QueryRoutine = IpxGetFrameType;
+ QueryTable[2].Flags = RTL_QUERY_REGISTRY_REQUIRED;
+ QueryTable[2].Name = L"NetworkNumber";
+ QueryTable[2].EntryContext = &NetworkNumberCount;
+ QueryTable[2].DefaultType = REG_NONE;
+
+ //
+ // 4-11) Call IpxGetBindingValue for each of the keys we
+ // care about.
+ //
+
+ for (i = 0; i < BINDING_PARAMETERS; i++) {
+
+ QueryTable[i+3].QueryRoutine = IpxGetBindingValue;
+ QueryTable[i+3].Flags = 0;
+ QueryTable[i+3].Name = ParameterValues[i].KeyName;
+ QueryTable[i+3].EntryContext = (PVOID)i;
+ QueryTable[i+3].DefaultType = REG_DWORD;
+ QueryTable[i+3].DefaultData = (PVOID)(ParameterValues[i].DefaultValue);
+ QueryTable[i+3].DefaultLength = sizeof(ULONG);
+
+ }
+
+ //
+ // 12) Stop
+ //
+
+ QueryTable[BINDING_PARAMETERS+3].QueryRoutine = NULL;
+ QueryTable[BINDING_PARAMETERS+3].Flags = 0;
+ QueryTable[BINDING_PARAMETERS+3].Name = NULL;
+
+
+ IPX_DEBUG (CONFIG, ("Read bind key for %ws (%ws)\n", DeviceName->Buffer, Subkey));
+
+ Status = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE,
+ Config->RegistryPathBuffer,
+ QueryTable,
+ (PVOID)Binding,
+ NULL);
+
+ if (Status != STATUS_SUCCESS) {
+
+ //
+ // The binding will get freed during cleanup.
+ //
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)Config->DriverObject,
+ EVENT_IPX_ILLEGAL_CONFIG,
+ 906,
+ Status,
+ Subkey,
+ 0,
+ NULL);
+ return STATUS_DEVICE_CONFIGURATION_ERROR;
+ }
+
+ if (FrameTypeCount == 0) {
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)Config->DriverObject,
+ EVENT_IPX_NO_FRAME_TYPES,
+ 907,
+ Status,
+ Subkey + 10,
+ 0,
+ NULL);
+ }
+
+ if (FrameTypeCount > NetworkNumberCount) {
+ for (i = NetworkNumberCount; i <FrameTypeCount; i++) {
+ Binding->NetworkNumber[i] = 0;
+ }
+ }
+ Binding->FrameTypeCount = FrameTypeCount;
+
+ //
+ // Go through and eliminate duplicates from the frame
+ // type array.
+ //
+
+ for (i = 0; i < Binding->FrameTypeCount; i++) {
+
+ for (j = i+1; j < Binding->FrameTypeCount; j++) {
+
+ if (Binding->FrameType[j] == Binding->FrameType[i]) {
+
+ IPX_DEBUG (CONFIG, ("Frame types %d and %d identical\n", i, j));
+
+ //
+ // A duplicate, slide everything else down.
+ //
+
+ for (k = j+1; k < Binding->FrameTypeCount; k++) {
+ Binding->FrameType[k-1] = Binding->FrameType[k];
+ Binding->NetworkNumber[k-1] = Binding->NetworkNumber[k];
+ }
+ --Binding->FrameTypeCount;
+
+ --j; // so we check whoever just moved into this spot.
+ }
+ }
+ }
+
+
+ //
+ // Mark all the explicitly configured frame types, and
+ // see if we have to auto-detect.
+ //
+
+ for (i = 0; i < 4; i++) {
+ FrameTypeUsed[i] = FALSE;
+ }
+
+ AutoDetect = FALSE;
+ for (i = 0; i < Binding->FrameTypeCount; i++) {
+ if ((Binding->FrameType[i] == ISN_FRAME_TYPE_AUTO)) {
+ AutoDetectLoc = i;
+ AutoDetect = TRUE;
+ } else {
+ Binding->AutoDetect[i] = FALSE;
+ Binding->DefaultAutoDetect[i] = FALSE;
+ FrameTypeUsed[Binding->FrameType[i]] = TRUE;
+ }
+ }
+
+ if (!AutoDetect) {
+ IPX_DEBUG (AUTO_DETECT, ("No bindings auto-detected\n"));
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // Slide everything that is past the auto-detect point up
+ // to the end.
+ //
+
+ //
+ // Fixed this loop which can spill over if the FrameTypeCount is 4 and the SlideCount > 0.
+ // Here, the FrameTypeCount is 1-based, whereas the indices are 0-based, we need to make
+ // the index 1-based for this to work. So, instead of (3-Binding->FrameTypeCount), we use
+ // (4-Binding->FrameTypeCount). This loop copies all the non-auto-detect frametypes down to
+ // the bottom of the array to make space after the last auto-detect frame-type for filling
+ // in the frametypes in the preference order.
+ //
+#if 0
+ SlideCount = Binding->FrameTypeCount - AutoDetectLoc - 1;
+ for (j = 3; j > 3 - SlideCount; j--) {
+ Binding->FrameType[j] = Binding->FrameType[j-(3-Binding->FrameTypeCount)];
+ Binding->NetworkNumber[j] = Binding->NetworkNumber[j-(3-Binding->FrameTypeCount)];
+ Binding->AutoDetect[j] = Binding->AutoDetect[j-(3-Binding->FrameTypeCount)];
+ Binding->DefaultAutoDetect[j] = Binding->DefaultAutoDetect[j-(3-Binding->FrameTypeCount)];
+ }
+#else
+ SlideCount = Binding->FrameTypeCount - AutoDetectLoc - 1;
+ for (j = 3; j > 3 - SlideCount; j--) {
+ Binding->FrameType[j] = Binding->FrameType[j-(4-Binding->FrameTypeCount)];
+ Binding->NetworkNumber[j] = Binding->NetworkNumber[j-(4-Binding->FrameTypeCount)];
+ Binding->AutoDetect[j] = Binding->AutoDetect[j-(4-Binding->FrameTypeCount)];
+ Binding->DefaultAutoDetect[j] = Binding->DefaultAutoDetect[j-(4-Binding->FrameTypeCount)];
+ }
+#endif
+
+ //
+ // Now fill in any frame types that are not hard-coded,
+ // this will start at AutoDetectLoc and exactly fill up
+ // the gap created when we slid things up above. We
+ // first put the default auto-detect at the first spot.
+ //
+
+ if (!FrameTypeUsed[Binding->Parameters[BINDING_DEFAULT_AUTO_DETECT]]) {
+ Binding->FrameType[AutoDetectLoc] = Binding->Parameters[BINDING_DEFAULT_AUTO_DETECT];
+ Binding->NetworkNumber[AutoDetectLoc] = 0;
+ Binding->AutoDetect[AutoDetectLoc] = TRUE;
+ Binding->DefaultAutoDetect[AutoDetectLoc] = TRUE;
+ ++AutoDetectLoc;
+ FrameTypeUsed[Binding->Parameters[BINDING_DEFAULT_AUTO_DETECT]] = TRUE;
+ }
+
+ //
+ // Now fill in the array, using the preference order in
+ // the BindingPreference array (this comes into effect
+ // because the first frame type in our list that we
+ // find is used).
+ //
+
+ for (i = 0; i < ISN_FRAME_TYPE_MAX; i++) {
+
+ if (!FrameTypeUsed[BindingPreference[i]]) {
+ Binding->FrameType[AutoDetectLoc] = BindingPreference[i];
+ Binding->NetworkNumber[AutoDetectLoc] = 0;
+ Binding->AutoDetect[AutoDetectLoc] = TRUE;
+ Binding->DefaultAutoDetect[AutoDetectLoc] = FALSE;
+ ++AutoDetectLoc;
+ }
+ }
+
+ Binding->FrameTypeCount = ISN_FRAME_TYPE_MAX;
+
+#if DBG
+ for (i = 0; i < ISN_FRAME_TYPE_MAX; i++) {
+ IPX_DEBUG (AUTO_DETECT, ("%d: type %d, net %d, auto %d\n",
+ i, Binding->FrameType[i], Binding->NetworkNumber[i], Binding->AutoDetect[i]));
+ }
+#endif
+
+ return STATUS_SUCCESS;
+} /* IpxPnPGetAdapterParameters */
+
+#endif _PNP_POWER
+
diff --git a/private/ntos/tdi/isnp/ipx/config.h b/private/ntos/tdi/isnp/ipx/config.h
new file mode 100644
index 000000000..ba6e76d83
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/config.h
@@ -0,0 +1,132 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ config.h
+
+Abstract:
+
+ Private include file for the ISN IPX module.
+ file defines all constants and structures necessary for support of
+ the dynamic configuration of ST.
+
+Revision History:
+
+--*/
+
+
+//
+// These are used to index into the Parameters array in CONFIG.
+//
+
+#define CONFIG_DEDICATED_ROUTER 0
+#define CONFIG_INIT_DATAGRAMS 1
+#define CONFIG_MAX_DATAGRAMS 2
+#define CONFIG_RIP_AGE_TIME 3
+#define CONFIG_RIP_COUNT 4
+#define CONFIG_RIP_TIMEOUT 5
+#define CONFIG_RIP_USAGE_TIME 6
+#define CONFIG_ROUTE_USAGE_TIME 7
+#define CONFIG_SOCKET_UNIQUENESS 8
+#define CONFIG_SOCKET_START 9
+#define CONFIG_SOCKET_END 10
+#define CONFIG_VIRTUAL_NETWORK 11
+#define CONFIG_MAX_MEMORY_USAGE 12
+#define CONFIG_RIP_TABLE_SIZE 13
+#define CONFIG_VIRTUAL_OPTIONAL 14
+#define CONFIG_ETHERNET_PAD 15
+#define CONFIG_ETHERNET_LENGTH 16
+#define CONFIG_SINGLE_NETWORK 17
+#define CONFIG_DISABLE_DIALOUT_SAP 18
+#define CONFIG_DISABLE_DIALIN_NB 19
+#define CONFIG_VERIFY_SOURCE_ADDRESS 20
+
+#define CONFIG_PARAMETERS 21
+
+//
+// Main configuration structure.
+//
+
+typedef struct _CONFIG {
+
+ ULONG Parameters[CONFIG_PARAMETERS]; // index defined above
+ NDIS_STRING DeviceName; // device name exported
+ PWSTR RegistryPathBuffer; // path to config info
+ ULONG BindCount; // entries in BindingList
+ LIST_ENTRY BindingList; // one per binding
+ PDRIVER_OBJECT DriverObject; // used for logging errors
+
+} CONFIG, * PCONFIG;
+
+
+//
+// These are used to index into the Parameters array in BINDING_CONFIG.
+//
+
+#define BINDING_MAX_PKT_SIZE 0
+#define BINDING_BIND_SAP 1
+#define BINDING_DEFAULT_AUTO_DETECT 2
+#define BINDING_SOURCE_ROUTE 3
+#define BINDING_ALL_ROUTE_DEF 4
+#define BINDING_ALL_ROUTE_BC 5
+#define BINDING_ALL_ROUTE_MC 6
+#define BINDING_ENABLE_FUNC_ADDR 7
+#define BINDING_ENABLE_WAN 8
+
+#define BINDING_PARAMETERS 9
+
+
+//
+// One of these is allocated per adapter we are to bind to.
+//
+
+typedef struct _BINDING_CONFIG {
+
+ LIST_ENTRY Linkage; // for chaining on BindingList
+ NDIS_STRING AdapterName; // NDIS adapter to bind to
+ ULONG FrameTypeCount; // number of frame types defined (max. 4)
+ // == number of valid entries in arrays:
+ ULONG FrameType[ISN_FRAME_TYPE_MAX]; // ISN_FRAME_TYPE_XXX
+ ULONG NetworkNumber[ISN_FRAME_TYPE_MAX]; // may be 0
+ BOOLEAN AutoDetect[ISN_FRAME_TYPE_MAX]; // remove if net number can't be found
+ BOOLEAN DefaultAutoDetect[ISN_FRAME_TYPE_MAX]; // use this if multiple or none found
+ ULONG Parameters[BINDING_PARAMETERS]; // index defined above
+ PDRIVER_OBJECT DriverObject; // used for logging errors
+
+} BINDING_CONFIG, * PBINDING_CONFIG;
+
+
+NTSTATUS
+IpxGetConfiguration (
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath,
+ OUT PCONFIG * ConfigPtr
+ );
+
+VOID
+IpxFreeConfiguration (
+ IN PCONFIG Config
+ );
+
+VOID
+IpxWriteDefaultAutoDetectType(
+ IN PUNICODE_STRING RegistryPath,
+ IN struct _ADAPTER * Adapter,
+ IN ULONG FrameType
+ );
+
+#ifdef _PNP_POWER
+NTSTATUS
+IpxPnPGetVirtualNetworkNumber (
+ IN PCONFIG Config
+ );
+
+NTSTATUS
+IpxPnPGetAdapterParameters(
+ IN PCONFIG Config,
+ IN PNDIS_STRING DeviceName,
+ IN OUT PBINDING_CONFIG Binding
+ );
+#endif _PNP_POWER
diff --git a/private/ntos/tdi/isnp/ipx/device.c b/private/ntos/tdi/isnp/ipx/device.c
new file mode 100644
index 000000000..f2d9d19f4
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/device.c
@@ -0,0 +1,599 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ device.c
+
+Abstract:
+
+ This module contains code which implements the DEVICE_CONTEXT object.
+ Routines are provided to reference, and dereference transport device
+ context objects.
+
+ The transport device context object is a structure which contains a
+ system-defined DEVICE_OBJECT followed by information which is maintained
+ by the transport provider, called the context.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) - 22-Sept-1995
+ BackFill optimization changes added under #if BACK_FILL
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,IpxCreateDevice)
+#endif
+
+
+
+VOID
+IpxRefDevice(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a device context.
+
+Arguments:
+
+ Device - Pointer to a transport device context object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ CTEAssert (Device->ReferenceCount > 0); // not perfect, but...
+
+ (VOID)InterlockedIncrement(&Device->ReferenceCount);
+
+} /* IpxRefDevice */
+
+
+VOID
+IpxDerefDevice(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences a device context by decrementing the
+ reference count contained in the structure. Currently, we don't
+ do anything special when the reference count drops to zero, but
+ we could dynamically unload stuff then.
+
+Arguments:
+
+ Device - Pointer to a transport device context object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ LONG result;
+
+ result = InterlockedDecrement (&Device->ReferenceCount);
+
+ CTEAssert (result >= 0);
+
+ if (result == 0) {
+ IpxDestroyDevice (Device);
+ }
+
+} /* IpxDerefDevice */
+
+
+NTSTATUS
+IpxCreateDevice(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING DeviceName,
+ IN ULONG SegmentCount,
+ IN OUT PDEVICE *DevicePtr
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates and initializes a device context structure.
+
+Arguments:
+
+
+ DriverObject - pointer to the IO subsystem supplied driver object.
+
+ Device - Pointer to a pointer to a transport device context object.
+
+ SegmentCount - The number of segments in the RIP router table.
+
+ DeviceName - pointer to the name of the device this device object points to.
+
+Return Value:
+
+ STATUS_SUCCESS if all is well; STATUS_INSUFFICIENT_RESOURCES otherwise.
+
+--*/
+
+{
+ NTSTATUS status;
+ PDEVICE_OBJECT deviceObject;
+ PDEVICE Device;
+ ULONG DeviceSize;
+ ULONG LocksOffset;
+ ULONG SegmentsOffset;
+ ULONG DeviceNameOffset;
+ UINT i;
+
+
+ //
+ // Create the device object for the sample transport, allowing
+ // room at the end for the device name to be stored (for use
+ // in logging errors) and the RIP fields.
+ //
+
+ DeviceSize = sizeof(DEVICE) +
+ (sizeof(CTELock) * SegmentCount) +
+ (sizeof(ROUTER_SEGMENT) * SegmentCount) +
+ DeviceName->Length + sizeof(UNICODE_NULL);
+
+ status = IoCreateDevice(
+ DriverObject,
+ DeviceSize,
+ DeviceName,
+ FILE_DEVICE_TRANSPORT,
+ 0,
+ FALSE,
+ &deviceObject);
+
+ if (!NT_SUCCESS(status)) {
+ IPX_DEBUG(DEVICE, ("Create device %ws failed %lx\n", DeviceName->Buffer, status));
+ return status;
+ }
+
+ deviceObject->Flags |= DO_DIRECT_IO;
+
+ Device = (PDEVICE)deviceObject->DeviceExtension;
+
+ IPX_DEBUG(DEVICE, ("Create device %ws succeeded %lx\n", DeviceName->Buffer));
+
+ //
+ // Initialize our part of the device context.
+ //
+
+ RtlZeroMemory(
+ ((PUCHAR)Device) + sizeof(DEVICE_OBJECT),
+ sizeof(DEVICE) - sizeof(DEVICE_OBJECT));
+
+ Device->DeviceObject = deviceObject;
+
+ LocksOffset = sizeof(DEVICE);
+ SegmentsOffset = LocksOffset + (sizeof(CTELock) * SegmentCount);
+ DeviceNameOffset = SegmentsOffset + (sizeof(ROUTER_SEGMENT) * SegmentCount);
+
+ //
+ // Set some internal pointers.
+ //
+
+ Device->SegmentLocks = (CTELock *)(((PUCHAR)Device) + LocksOffset);
+ Device->Segments = (PROUTER_SEGMENT)(((PUCHAR)Device) + SegmentsOffset);
+ Device->SegmentCount = SegmentCount;
+
+ for (i = 0; i < SegmentCount; i++) {
+
+ CTEInitLock (&Device->SegmentLocks[i]);
+ InitializeListHead (&Device->Segments[i].WaitingForRoute);
+ InitializeListHead (&Device->Segments[i].FindWaitingForRoute);
+ InitializeListHead (&Device->Segments[i].WaitingLocalTarget);
+ InitializeListHead (&Device->Segments[i].WaitingReripNetnum);
+ InitializeListHead (&Device->Segments[i].Entries);
+ Device->Segments[i].EnumerateLocation = &Device->Segments[i].Entries;
+
+ }
+
+ //
+ // Copy over the device name.
+ //
+
+ Device->DeviceNameLength = DeviceName->Length + sizeof(WCHAR);
+ Device->DeviceName = (PWCHAR)(((PUCHAR)Device) + DeviceNameOffset);
+ RtlCopyMemory(
+ Device->DeviceName,
+ DeviceName->Buffer,
+ DeviceName->Length);
+ Device->DeviceName[DeviceName->Length/sizeof(WCHAR)] = UNICODE_NULL;
+
+ //
+ // Initialize the reference count.
+ //
+
+ Device->ReferenceCount = 1;
+#if DBG
+ Device->RefTypes[DREF_CREATE] = 1;
+#endif
+
+#if DBG
+ RtlCopyMemory(Device->Signature1, "IDC1", 4);
+ RtlCopyMemory(Device->Signature2, "IDC2", 4);
+#endif
+
+ Device->Information.Version = 0x0100;
+ Device->Information.MaxSendSize = 0; // no sends allowed
+ Device->Information.MaxConnectionUserData = 0;
+ Device->Information.ServiceFlags =
+ TDI_SERVICE_CONNECTIONLESS_MODE | TDI_SERVICE_BROADCAST_SUPPORTED |
+ TDI_SERVICE_ROUTE_DIRECTED;
+ Device->Information.MinimumLookaheadData = 128;
+ Device->Information.NumberOfResources = IPX_TDI_RESOURCES;
+ KeQuerySystemTime (&Device->Information.StartTime);
+
+ Device->Statistics.Version = 0x0100;
+
+#if 0
+ //
+ // These will be filled in after all the binding is done.
+ //
+
+ Device->Information.MaxDatagramSize = 0;
+ Device->Information.MaximumLookaheadData = 0;
+
+
+ Device->SourceRoutingUsed = FALSE;
+ Device->SourceRoutingTime = 0;
+ Device->RipPacketCount = 0;
+
+ Device->RipShortTimerActive = FALSE;
+ Device->RipSendTime = 0;
+#endif
+
+
+ //
+ // Initialize the resource that guards address ACLs.
+ //
+
+ ExInitializeResource (&Device->AddressResource);
+
+#ifdef _PNP_POWER
+ //
+ // Init the resource that guards the binding array/indices
+ //
+ CTEInitLock (&Device->BindAccessLock);
+#endif _PNP_POWER
+
+ InitializeListHead (&Device->WaitingRipPackets);
+ CTEInitTimer (&Device->RipShortTimer);
+ CTEInitTimer (&Device->RipLongTimer);
+
+ CTEInitTimer (&Device->SourceRoutingTimer);
+
+ //
+ // initialize the various fields in the device context
+ //
+
+ CTEInitLock (&Device->Interlock);
+ CTEInitLock (&Device->Lock);
+ CTEInitLock (&Device->SListsLock);
+
+ Device->ControlChannelIdentifier.QuadPart = 1;
+
+ InitializeListHead (&Device->GlobalSendPacketList);
+ InitializeListHead (&Device->GlobalReceivePacketList);
+ InitializeListHead (&Device->GlobalReceiveBufferList);
+#if BACK_FILL
+ InitializeListHead (&Device->GlobalBackFillPacketList);
+#endif
+
+ InitializeListHead (&Device->AddressNotifyQueue);
+ InitializeListHead (&Device->LineChangeQueue);
+
+ for (i = 0; i < IPX_ADDRESS_HASH_COUNT; i++) {
+ InitializeListHead (&Device->AddressDatabases[i]);
+ }
+
+#if BACK_FILL
+ InitializeListHead (&Device->BackFillPoolList);
+#endif
+ InitializeListHead (&Device->SendPoolList);
+ InitializeListHead (&Device->ReceivePoolList);
+
+#ifdef _PNP_POWER
+ InitializeListHead (&Device->BindingPoolList);
+#endif
+
+ ExInitializeSListHead (&Device->SendPacketList);
+ ExInitializeSListHead (&Device->ReceivePacketList);
+#if BACK_FILL
+ ExInitializeSListHead (&Device->BackFillPacketList);
+#endif
+
+#ifdef _PNP_POWER
+ ExInitializeSListHead (&Device->BindingList);
+#endif
+
+#if 0
+ Device->MemoryUsage = 0;
+ Device->SendPacketList.Next = NULL;
+ Device->ReceivePacketList.Next = NULL;
+ Device->Bindings = NULL;
+ Device->BindingCount = 0;
+#endif
+
+ KeQuerySystemTime (&Device->IpxStartTime);
+
+ Device->State = DEVICE_STATE_CLOSED;
+ Device->AutoDetectState = AUTO_DETECT_STATE_INIT;
+
+ Device->Type = IPX_DEVICE_SIGNATURE;
+ Device->Size = sizeof (DEVICE);
+
+
+ *DevicePtr = Device;
+ return STATUS_SUCCESS;
+
+} /* IpxCreateDevice */
+
+
+VOID
+IpxDestroyDevice(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys a device context structure.
+
+Arguments:
+
+ Device - Pointer to a pointer to a transport device context object.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PLIST_ENTRY p;
+ PSINGLE_LIST_ENTRY s;
+ PIPX_SEND_POOL SendPool;
+ PIPX_SEND_PACKET SendPacket;
+ PIPX_RECEIVE_POOL ReceivePool;
+ PIPX_RECEIVE_PACKET ReceivePacket;
+ PIPX_ROUTE_ENTRY RouteEntry;
+ UINT SendPoolSize;
+ UINT ReceivePoolSize;
+ UINT i;
+#if BACK_FILL
+ PIPX_SEND_POOL BackFillPool;
+ UINT BackFillPoolSize;
+ PIPX_SEND_PACKET BackFillPacket;
+#endif
+
+#ifdef _PNP_POWER
+ PIPX_BINDING_POOL BindingPool;
+ UINT BindingPoolSize;
+ PBINDING Binding;
+#endif
+
+ IPX_DEBUG (DEVICE, ("Destroy device %lx\n", Device));
+
+ //
+ // Take all the packets out of its pools.
+ //
+
+#if _PNP_POWER
+ BindingPoolSize = FIELD_OFFSET (IPX_BINDING_POOL, Bindings[0]) +
+ (sizeof(BINDING) * Device->InitBindings);
+
+ while (!IsListEmpty (&Device->BindingPoolList)) {
+
+ p = RemoveHeadList (&Device->BindingPoolList);
+ BindingPool = CONTAINING_RECORD (p, IPX_BINDING_POOL, Linkage);
+ IPX_DEBUG (PACKET, ("Free binding pool %lx\n", BindingPool));
+ IpxFreeMemory (BindingPool, BindingPoolSize, MEMORY_PACKET, "BindingPool");
+
+ }
+#endif
+
+#ifdef IPX_OWN_PACKETS
+
+#if BACK_FILL
+ BackFillPoolSize = FIELD_OFFSET (IPX_SEND_POOL, Packets[0]) +
+ (sizeof(IPX_SEND_PACKET) * Device->InitDatagrams);
+ while (!IsListEmpty (&Device->BackFillPoolList)) {
+
+ p = RemoveHeadList (&Device->BackFillPoolList);
+ BackFillPool = CONTAINING_RECORD (p, IPX_SEND_POOL, Linkage);
+
+ for (i = 0; i < BackFillPool->PacketCount; i++) {
+ BackFillPacket = &BackFillPool->Packets[i];
+ IpxDeinitializeBackFillPacket (Device, BackFillPacket);
+ }
+
+ IPX_DEBUG (PACKET, ("Free packet pool %lx\n", BackFillPool));
+ IpxFreeMemory (BackFillPool, BackFillPoolSize, MEMORY_PACKET, "BackPool");
+ }
+#endif
+
+ SendPoolSize = FIELD_OFFSET (IPX_SEND_POOL, Packets[0]) +
+ (sizeof(IPX_SEND_PACKET) * Device->InitDatagrams) +
+ (((IPX_MAXIMUM_MAC + sizeof(IPX_HEADER) + 3) & ~3) * Device->InitDatagrams);
+
+ while (!IsListEmpty (&Device->SendPoolList)) {
+
+ p = RemoveHeadList (&Device->SendPoolList);
+ SendPool = CONTAINING_RECORD (p, IPX_SEND_POOL, Linkage);
+
+ for (i = 0; i < SendPool->PacketCount; i++) {
+
+ SendPacket = &SendPool->Packets[i];
+ IpxDeinitializeSendPacket (Device, SendPacket);
+
+ }
+
+ IPX_DEBUG (PACKET, ("Free packet pool %lx\n", SendPool));
+ IpxFreeMemory (SendPool, SendPoolSize, MEMORY_PACKET, "SendPool");
+ }
+
+ ReceivePoolSize = FIELD_OFFSET (IPX_RECEIVE_POOL, Packets[0]) +
+ (sizeof(IPX_RECEIVE_PACKET) * Device->InitReceivePackets);
+
+ while (!IsListEmpty (&Device->ReceivePoolList)) {
+
+ p = RemoveHeadList (&Device->ReceivePoolList);
+ ReceivePool = CONTAINING_RECORD (p, IPX_RECEIVE_POOL, Linkage);
+
+ for (i = 0; i < ReceivePool->PacketCount; i++) {
+
+ ReceivePacket = &ReceivePool->Packets[i];
+ IpxDeinitializeReceivePacket (Device, ReceivePacket);
+
+ }
+
+ IPX_DEBUG (PACKET, ("Free receive packet pool %lx\n", ReceivePool));
+ IpxFreeMemory (ReceivePool, ReceivePoolSize, MEMORY_PACKET, "ReceivePool");
+ }
+#else
+
+#if BACK_FILL
+
+ while (s = IPX_POP_ENTRY_LIST(&Device->BackFillPacketList, &Device->Lock)) {
+ PIPX_SEND_RESERVED Reserved = CONTAINING_RECORD (s, IPX_SEND_RESERVED, PoolLinkage);
+ IPX_SEND_PACKET BackFillPacket;
+
+ BackFillPacket.Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ IpxDeinitializeBackFillPacket (Device, &BackFillPacket);
+ Device->MemoryUsage -= (FIELD_OFFSET(NDIS_PACKET,ProtocolReserved[0]) + sizeof(IPX_SEND_RESERVED));
+ }
+
+ while (!IsListEmpty (&Device->BackFillPoolList)) {
+
+ p = RemoveHeadList (&Device->BackFillPoolList);
+ BackFillPool = CONTAINING_RECORD (p, IPX_SEND_POOL, Linkage);
+
+ IPX_DEBUG (PACKET, ("Free packet pool %lx\n", BackFillPool));
+ NdisFreePacketPool (BackFillPool->PoolHandle);
+ Device->MemoryUsage -= FIELD_OFFSET(NDIS_PACKET_POOL,Buffer[0]);
+
+ IpxFreeMemory (BackFillPool, sizeof(IPX_SEND_POOL), MEMORY_PACKET, "BafiPool");
+ }
+#endif
+
+ while (s = IPX_POP_ENTRY_LIST(&Device->SendPacketList, &Device->Lock)){
+ PIPX_SEND_RESERVED Reserved = CONTAINING_RECORD (s, IPX_SEND_RESERVED, PoolLinkage);
+ IPX_SEND_PACKET SendPacket;
+ PUCHAR Header = Reserved->Header;
+
+ SendPacket.Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ IpxDeinitializeSendPacket (Device, &SendPacket);
+ Device->MemoryUsage -= (FIELD_OFFSET(NDIS_PACKET,ProtocolReserved[0]) + sizeof(IPX_SEND_RESERVED));
+ }
+
+ while (!IsListEmpty (&Device->SendPoolList)) {
+
+ p = RemoveHeadList (&Device->SendPoolList);
+ SendPool = CONTAINING_RECORD (p, IPX_SEND_POOL, Linkage);
+
+ IPX_DEBUG (PACKET, ("Free packet pool %lx\n", SendPool));
+ NdisFreePacketPool (SendPool->PoolHandle);
+ Device->MemoryUsage -= FIELD_OFFSET(NDIS_PACKET_POOL,Buffer[0]);
+
+ IpxFreeMemory (SendPool->Header, PACKET_HEADER_SIZE * Device->InitDatagrams, MEMORY_PACKET, "SendPool");
+
+ IpxFreeMemory (SendPool, sizeof(IPX_SEND_POOL), MEMORY_PACKET, "SendPool");
+ }
+
+ while (s = IPX_POP_ENTRY_LIST(&Device->ReceivePacketList, &Device->Lock)){
+ PIPX_RECEIVE_RESERVED Reserved = CONTAINING_RECORD (s, IPX_RECEIVE_RESERVED, PoolLinkage);
+ IPX_RECEIVE_PACKET ReceivePacket;
+
+ ReceivePacket.Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ IpxDeinitializeReceivePacket (Device, &ReceivePacket);
+ Device->MemoryUsage -= (FIELD_OFFSET(NDIS_PACKET,ProtocolReserved[0]) + sizeof(IPX_RECEIVE_RESERVED));
+ }
+
+ while (!IsListEmpty (&Device->ReceivePoolList)) {
+
+ p = RemoveHeadList (&Device->ReceivePoolList);
+ ReceivePool = CONTAINING_RECORD (p, IPX_RECEIVE_POOL, Linkage);
+
+ IPX_DEBUG (PACKET, ("Free packet pool %lx\n", ReceivePool));
+ NdisFreePacketPool (ReceivePool->PoolHandle);
+ Device->MemoryUsage -= FIELD_OFFSET(NDIS_PACKET_POOL,Buffer[0]);
+
+ IpxFreeMemory (ReceivePool, sizeof(IPX_RECEIVE_POOL), MEMORY_PACKET, "ReceivePool");
+ }
+
+#endif IPX_OWN_PACKETS
+ //
+ // Destroy all rip table entries.
+ //
+
+ for (i = 0; i < Device->SegmentCount; i++) {
+
+ RouteEntry = RipGetFirstRoute(i);
+ while (RouteEntry != NULL) {
+
+ (VOID)RipDeleteRoute(i, RouteEntry);
+ IpxFreeMemory(RouteEntry, sizeof(IPX_ROUTE_ENTRY), MEMORY_RIP, "RouteEntry");
+ RouteEntry = RipGetNextRoute(i);
+
+ }
+
+ }
+
+ IPX_DEBUG (DEVICE, ("Final memory use is %d\n", Device->MemoryUsage));
+#if DBG
+ for (i = 0; i < MEMORY_MAX; i++) {
+ if (IpxMemoryTag[i].BytesAllocated != 0) {
+ IPX_DEBUG (DEVICE, ("Tag %d: %d bytes left\n", i, IpxMemoryTag[i].BytesAllocated));
+ }
+ }
+#endif
+
+ //
+ // If we are being unloaded then someone is waiting for this
+ // event to finish the cleanup, since we may be at DISPATCH_LEVEL;
+ // otherwise it is during load and we can just kill ourselves here.
+ //
+
+ if (Device->UnloadWaiting) {
+
+ KeSetEvent(
+ &Device->UnloadEvent,
+ 0L,
+ FALSE);
+
+ } else {
+
+ CTEAssert (KeGetCurrentIrql() < DISPATCH_LEVEL);
+ ExDeleteResource (&Device->AddressResource);
+ IoDeleteDevice (Device->DeviceObject);
+ }
+
+} /* IpxDestroyDevice */
+
diff --git a/private/ntos/tdi/isnp/ipx/dirs b/private/ntos/tdi/isnp/ipx/dirs
new file mode 100644
index 000000000..0dab2f056
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/dirs
@@ -0,0 +1,22 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+
+Author:
+
+
+NOTE: Commented description of this file is in \nt\bak\bin\dirs.tpl
+
+!ENDIF
+
+DIRS=up mp
diff --git a/private/ntos/tdi/isnp/ipx/driver.c b/private/ntos/tdi/isnp/ipx/driver.c
new file mode 100644
index 000000000..7c32cd0e3
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/driver.c
@@ -0,0 +1,4219 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ driver.c
+
+Abstract:
+
+ This module contains the DriverEntry and other initialization
+ code for the IPX module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 2-September-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) - 22-Sept-1995
+ BackFill optimization changes added under #if BACK_FILL
+
+ Sanjay Anand (SanjayAn) 18-Sept-1995
+ Changes to support Plug and Play (in _PNP_POWER)
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+PDEVICE IpxDevice = NULL;
+PIPX_PADDING_BUFFER IpxPaddingBuffer = NULL;
+
+#if DBG
+
+UCHAR IpxTempDebugBuffer[150];
+ULONG IpxDebug = 0x0;
+ULONG IpxMemoryDebug = 0xffffffd3;
+UCHAR IpxDebugMemory[IPX_MEMORY_LOG_SIZE][64];
+PUCHAR IpxDebugMemoryLoc = IpxDebugMemory[0];
+PUCHAR IpxDebugMemoryEnd = IpxDebugMemory[IPX_MEMORY_LOG_SIZE];
+
+VOID
+IpxDebugMemoryLog(
+ IN PUCHAR FormatString,
+ ...
+)
+
+{
+ INT ArgLen;
+ va_list ArgumentPointer;
+
+ va_start(ArgumentPointer, FormatString);
+
+ //
+ // To avoid any overflows, copy this in a temp buffer first.
+ RtlZeroMemory (IpxTempDebugBuffer, 150);
+ ArgLen = vsprintf(IpxTempDebugBuffer, FormatString, ArgumentPointer);
+ va_end(ArgumentPointer);
+
+ if ( ArgLen > 64 ) {
+ CTEAssert( FALSE );
+ } else {
+ RtlZeroMemory (IpxDebugMemoryLoc, 64);
+ RtlCopyMemory( IpxDebugMemoryLoc, IpxTempDebugBuffer, ArgLen );
+
+ IpxDebugMemoryLoc += 64;
+ if (IpxDebugMemoryLoc >= IpxDebugMemoryEnd) {
+ IpxDebugMemoryLoc = IpxDebugMemory[0];
+ }
+ }
+}
+
+
+DEFINE_LOCK_STRUCTURE(IpxMemoryInterlock);
+MEMORY_TAG IpxMemoryTag[MEMORY_MAX];
+
+DEFINE_LOCK_STRUCTURE(IpxGlobalInterlock);
+
+#endif
+
+#if DBG
+
+//
+// Use for debug printouts
+//
+
+PUCHAR FrameTypeNames[5] = { "Ethernet II", "802.3", "802.2", "SNAP", "Arcnet" };
+#define OutputFrameType(_Binding) \
+ (((_Binding)->Adapter->MacInfo.MediumType == NdisMediumArcnet878_2) ? \
+ FrameTypeNames[4] : \
+ FrameTypeNames[(_Binding)->FrameType])
+#endif
+
+
+#ifdef IPX_PACKET_LOG
+
+ULONG IpxPacketLogDebug = IPX_PACKET_LOG_RCV_OTHER | IPX_PACKET_LOG_SEND_OTHER;
+USHORT IpxPacketLogSocket = 0;
+DEFINE_LOCK_STRUCTURE(IpxPacketLogLock);
+IPX_PACKET_LOG_ENTRY IpxPacketLog[IPX_PACKET_LOG_LENGTH];
+PIPX_PACKET_LOG_ENTRY IpxPacketLogLoc = IpxPacketLog;
+PIPX_PACKET_LOG_ENTRY IpxPacketLogEnd = &IpxPacketLog[IPX_PACKET_LOG_LENGTH];
+
+VOID
+IpxLogPacket(
+ IN BOOLEAN Send,
+ IN PUCHAR DestMac,
+ IN PUCHAR SrcMac,
+ IN USHORT Length,
+ IN PVOID IpxHeader,
+ IN PVOID Data
+ )
+
+{
+
+ CTELockHandle LockHandle;
+ PIPX_PACKET_LOG_ENTRY PacketLog;
+ LARGE_INTEGER TickCount;
+ ULONG DataLength;
+
+ CTEGetLock (&IpxPacketLogLock, &LockHandle);
+
+ PacketLog = IpxPacketLogLoc;
+
+ ++IpxPacketLogLoc;
+ if (IpxPacketLogLoc >= IpxPacketLogEnd) {
+ IpxPacketLogLoc = IpxPacketLog;
+ }
+ *(UNALIGNED ULONG *)IpxPacketLogLoc->TimeStamp = 0x3e3d3d3d; // "===>"
+
+ CTEFreeLock (&IpxPacketLogLock, LockHandle);
+
+ RtlZeroMemory (PacketLog, sizeof(IPX_PACKET_LOG_ENTRY));
+
+ PacketLog->SendReceive = Send ? '>' : '<';
+
+ KeQueryTickCount(&TickCount);
+ _itoa (TickCount.LowPart % 100000, PacketLog->TimeStamp, 10);
+
+ RtlCopyMemory(PacketLog->DestMac, DestMac, 6);
+ RtlCopyMemory(PacketLog->SrcMac, SrcMac, 6);
+ PacketLog->Length[0] = Length / 256;
+ PacketLog->Length[1] = Length % 256;
+
+ if (Length < sizeof(IPX_HEADER)) {
+ RtlCopyMemory(&PacketLog->IpxHeader, IpxHeader, Length);
+ } else {
+ RtlCopyMemory(&PacketLog->IpxHeader, IpxHeader, sizeof(IPX_HEADER));
+ }
+
+ DataLength = Length - sizeof(IPX_HEADER);
+ if (DataLength < 14) {
+ RtlCopyMemory(PacketLog->Data, Data, DataLength);
+ } else {
+ RtlCopyMemory(PacketLog->Data, Data, 14);
+ }
+
+} /* IpxLogPacket */
+
+#endif // IPX_PACKET_LOG
+
+
+//
+// Forward declaration of various routines used in this module.
+//
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ );
+
+//
+// This is now shared with other modules
+//
+#ifndef _PNP_POWER
+ULONG
+IpxResolveAutoDetect(
+ IN PDEVICE Device,
+ IN ULONG ValidBindings,
+ IN PUNICODE_STRING RegistryPath
+ );
+
+VOID
+IpxResolveBindingSets(
+ IN PDEVICE Device,
+ IN ULONG ValidBindings
+ );
+
+NTSTATUS
+IpxBindToAdapter(
+ IN PDEVICE Device,
+ IN PBINDING_CONFIG ConfigAdapter,
+ IN ULONG FrameTypeIndex
+ );
+
+NTSTATUS
+IpxUnBindFromAdapter(
+ IN PBINDING Binding
+ );
+#endif _PNP_POWER
+
+VOID
+IpxUnload(
+ IN PDRIVER_OBJECT DriverObject
+ );
+
+NTSTATUS
+IpxDispatchDeviceControl(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+IpxDispatchOpenClose(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+IpxDispatchInternal (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,DriverEntry)
+
+//
+// These routines can be called at any time in case of PnP.
+//
+#ifndef _PNP_POWER
+#pragma alloc_text(INIT,IpxResolveAutoDetect)
+#pragma alloc_text(INIT,IpxResolveBindingSets)
+#pragma alloc_text(INIT,IpxBindToAdapter)
+#endif
+
+#endif
+
+UCHAR VirtualNode[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 };
+
+//
+// This prevents us from having a bss section.
+//
+
+ULONG _setjmpexused = 0;
+
+ULONG IpxFailLoad = FALSE;
+
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs initialization of the IPX ISN module.
+ It creates the device objects for the transport
+ provider and performs other driver initialization.
+
+Arguments:
+
+ DriverObject - Pointer to driver object created by the system.
+
+ RegistryPath - The name of IPX's node in the registry.
+
+Return Value:
+
+ The function value is the final status from the initialization operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ UINT SuccessfulOpens, ValidBindings;
+#ifdef _PNP_POWER
+ static const NDIS_STRING ProtocolName = NDIS_STRING_CONST("NWLNKIPX");
+#else
+ static const NDIS_STRING ProtocolName = NDIS_STRING_CONST("IPX Transport");
+#endif
+ PDEVICE Device;
+ PBINDING Binding;
+ PADAPTER Adapter;
+ ULONG BindingCount, BindingIndex;
+ PBINDING * BindingArray;
+ PLIST_ENTRY p;
+ ULONG AnnouncedMaxDatagram, RealMaxDatagram, MaxLookahead;
+ ULONG LinkSpeed, MacOptions;
+ ULONG Temp;
+ UINT i;
+ BOOLEAN CountedWan;
+
+ PCONFIG Config = NULL;
+ PBINDING_CONFIG ConfigBinding;
+
+#if 0
+ DbgPrint ("IPX: FailLoad at %lx\n", &IpxFailLoad);
+ DbgBreakPoint();
+
+ if (IpxFailLoad) {
+ return STATUS_UNSUCCESSFUL;
+ }
+#endif
+
+
+ //
+ // This ordering matters because we use it to quickly
+ // determine if packets are internally generated or not.
+ //
+
+ CTEAssert (IDENTIFIER_NB < IDENTIFIER_IPX);
+ CTEAssert (IDENTIFIER_SPX < IDENTIFIER_IPX);
+ CTEAssert (IDENTIFIER_RIP < IDENTIFIER_IPX);
+ CTEAssert (IDENTIFIER_RIP_INTERNAL > IDENTIFIER_IPX);
+
+ //
+ // We assume that this structure is not packet in between
+ // the fields.
+ //
+
+ CTEAssert (FIELD_OFFSET (TDI_ADDRESS_IPX, Socket) + sizeof(USHORT) == 12);
+
+
+ //
+ // Initialize the Common Transport Environment.
+ //
+
+ if (CTEInitialize() == 0) {
+
+ IPX_DEBUG (DEVICE, ("CTEInitialize() failed\n"));
+ IpxWriteGeneralErrorLog(
+ (PVOID)DriverObject,
+ EVENT_TRANSPORT_REGISTER_FAILED,
+ 101,
+ STATUS_UNSUCCESSFUL,
+ NULL,
+ 0,
+ NULL);
+ return STATUS_UNSUCCESSFUL;
+ }
+
+#if DBG
+ CTEInitLock (&IpxGlobalInterlock);
+ CTEInitLock (&IpxMemoryInterlock);
+ for (i = 0; i < MEMORY_MAX; i++) {
+ IpxMemoryTag[i].Tag = i;
+ IpxMemoryTag[i].BytesAllocated = 0;
+ }
+#endif
+#ifdef IPX_PACKET_LOG
+ CTEInitLock (&IpxPacketLogLock);
+#endif
+
+#ifdef IPX_OWN_PACKETS
+ CTEAssert (NDIS_PACKET_SIZE == FIELD_OFFSET(NDIS_PACKET, ProtocolReserved[0]));
+#endif
+
+ IPX_DEBUG (DEVICE, ("IPX loaded\n"));
+
+ //
+ // This allocates the CONFIG structure and returns
+ // it in Config.
+ //
+
+ status = IpxGetConfiguration(DriverObject, RegistryPath, &Config);
+
+ if (!NT_SUCCESS (status)) {
+
+ //
+ // If it failed, it logged an error.
+ //
+
+ PANIC (" Failed to initialize transport, IPX initialization failed.\n");
+ return status;
+
+ }
+
+#ifdef _PNP_POWER
+ //
+ // Initialize the TDI layer.
+ //
+ TdiInitialize();
+#endif
+
+ //
+ // make ourselves known to the NDIS wrapper.
+ //
+
+ status = IpxRegisterProtocol ((PNDIS_STRING)&ProtocolName);
+
+ if (!NT_SUCCESS (status)) {
+
+ IpxFreeConfiguration(Config);
+ PANIC ("IpxInitialize: RegisterProtocol failed!\n");
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)DriverObject,
+ EVENT_TRANSPORT_REGISTER_FAILED,
+ 607,
+ status,
+ NULL,
+ 0,
+ NULL);
+
+ return status;
+
+ }
+
+
+ //
+ // Initialize the driver object with this driver's entry points.
+ //
+
+ DriverObject->MajorFunction [IRP_MJ_CREATE] = IpxDispatchOpenClose;
+ DriverObject->MajorFunction [IRP_MJ_CLOSE] = IpxDispatchOpenClose;
+ DriverObject->MajorFunction [IRP_MJ_CLEANUP] = IpxDispatchOpenClose;
+ DriverObject->MajorFunction [IRP_MJ_INTERNAL_DEVICE_CONTROL] = IpxDispatchInternal;
+ DriverObject->MajorFunction [IRP_MJ_DEVICE_CONTROL] = IpxDispatchDeviceControl;
+
+ DriverObject->DriverUnload = IpxUnload;
+
+ SuccessfulOpens = 0;
+
+ status = IpxCreateDevice(
+ DriverObject,
+ &Config->DeviceName,
+ Config->Parameters[CONFIG_RIP_TABLE_SIZE],
+ &Device);
+
+ if (!NT_SUCCESS (status)) {
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)DriverObject,
+ EVENT_IPX_CREATE_DEVICE,
+ 801,
+ status,
+ NULL,
+ 0,
+ NULL);
+
+ IpxFreeConfiguration(Config);
+ IpxDeregisterProtocol();
+ return status;
+ }
+
+ IpxDevice = Device;
+
+
+ //
+ // Save the relevant configuration parameters.
+ //
+
+ Device->DedicatedRouter = (BOOLEAN)(Config->Parameters[CONFIG_DEDICATED_ROUTER] != 0);
+ Device->InitDatagrams = Config->Parameters[CONFIG_INIT_DATAGRAMS];
+ Device->MaxDatagrams = Config->Parameters[CONFIG_MAX_DATAGRAMS];
+ Device->RipAgeTime = Config->Parameters[CONFIG_RIP_AGE_TIME];
+ Device->RipCount = Config->Parameters[CONFIG_RIP_COUNT];
+ Device->RipTimeout =
+ ((Config->Parameters[CONFIG_RIP_TIMEOUT] * 500) + (RIP_GRANULARITY/2)) /
+ RIP_GRANULARITY;
+ Device->RipUsageTime = Config->Parameters[CONFIG_RIP_USAGE_TIME];
+ Device->SourceRouteUsageTime = Config->Parameters[CONFIG_ROUTE_USAGE_TIME];
+ Device->SocketUniqueness = Config->Parameters[CONFIG_SOCKET_UNIQUENESS];
+ Device->SocketStart = (USHORT)Config->Parameters[CONFIG_SOCKET_START];
+ Device->SocketEnd = (USHORT)Config->Parameters[CONFIG_SOCKET_END];
+ Device->MemoryLimit = Config->Parameters[CONFIG_MAX_MEMORY_USAGE];
+ Device->VerifySourceAddress = (BOOLEAN)(Config->Parameters[CONFIG_VERIFY_SOURCE_ADDRESS] != 0);
+
+ Device->InitReceivePackets = (Device->InitDatagrams + 1) / 2;
+ Device->InitReceiveBuffers = (Device->InitDatagrams + 1) / 2;
+
+ Device->MaxReceivePackets = 10; // BUGBUG: config this?
+ Device->MaxReceiveBuffers = 10;
+
+#ifdef _PNP_POWER
+ Device->InitBindings = 5; // BUGBUG: config this?
+
+ //
+ // RAS max is 240 (?) + 10 max LAN
+ //
+ Device->MaxPoolBindings = 250; // BUGBUG: config this?
+#endif
+
+ //
+ // Have to reverse this.
+ //
+#ifndef _PNP_POWER
+//
+// Look at this only when the first adapter appears.
+//
+ Temp = Config->Parameters[CONFIG_VIRTUAL_NETWORK];
+ Device->VirtualNetworkNumber = REORDER_ULONG (Temp);
+#endif
+
+ Device->VirtualNetworkOptional = (BOOLEAN)(Config->Parameters[CONFIG_VIRTUAL_OPTIONAL] != 0);
+
+ Device->CurrentSocket = Device->SocketStart;
+
+ Device->EthernetPadToEven = (BOOLEAN)(Config->Parameters[CONFIG_ETHERNET_PAD] != 0);
+ Device->EthernetExtraPadding = (Config->Parameters[CONFIG_ETHERNET_LENGTH] & 0xfffffffe) + 1;
+
+ Device->SingleNetworkActive = (BOOLEAN)(Config->Parameters[CONFIG_SINGLE_NETWORK] != 0);
+ Device->DisableDialoutSap = (BOOLEAN)(Config->Parameters[CONFIG_DISABLE_DIALOUT_SAP] != 0);
+ Device->DisableDialinNetbios = (UCHAR)(Config->Parameters[CONFIG_DISABLE_DIALIN_NB]);
+
+#ifdef _PNP_POWER
+//
+// Used later to access the registry.
+//
+ Device->RegistryPathBuffer = Config->RegistryPathBuffer;
+ Device->RegistryPath.Length = RegistryPath->Length;
+ Device->RegistryPath.MaximumLength = RegistryPath->MaximumLength;
+ Device->RegistryPath.Buffer = Device->RegistryPathBuffer;
+#endif _PNP_POWER
+
+ //
+ // ActiveNetworkWan will start as FALSE, which is correct.
+ //
+
+ //
+ // Allocate our initial packet pool. We do not allocate
+ // receive and receive buffer pools until we need them,
+ // because in many cases we never do.
+ //
+
+#if BACK_FILL
+ IpxAllocateBackFillPool (Device);
+#endif
+
+ IpxAllocateSendPool (Device);
+
+#ifdef _PNP_POWER
+ IpxAllocateBindingPool (Device);
+#endif
+
+ //
+ // Allocate one 1-byte buffer for odd length packets.
+ //
+
+ IpxPaddingBuffer = IpxAllocatePaddingBuffer(Device);
+
+ if ( IpxPaddingBuffer == (PIPX_PADDING_BUFFER)NULL ) {
+ IpxWriteGeneralErrorLog(
+ (PVOID)DriverObject,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ 801,
+ STATUS_INSUFFICIENT_RESOURCES,
+ NULL,
+ 0,
+ NULL);
+
+ IpxFreeConfiguration(Config);
+ IpxDeregisterProtocol();
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // Initialize the loopback structures
+ //
+ IpxInitLoopback();
+
+//
+// All this will be done on appearance of adapters.
+//
+
+#ifndef _PNP_POWER
+
+ //
+ // Bind to all the configured adapters.
+ //
+
+ InitializeListHead (&Device->InitialBindingList);
+
+ p = Config->BindingList.Flink;
+
+ while (p != &Config->BindingList) {
+
+ ConfigBinding = CONTAINING_RECORD (p, BINDING_CONFIG, Linkage);
+ p = p->Flink;
+
+ for (i = 0; i < ConfigBinding->FrameTypeCount; i++) {
+
+ //
+ // If successful, this queues them on Device->InitialBindingList.
+ //
+
+ status = IpxBindToAdapter (Device, ConfigBinding, i);
+
+ //
+ // If this failed because the adapter could not be bound
+ // to, then don't try any more frame types on this adapter.
+ // For other failures we do try the other frame types.
+ //
+
+ if (status == STATUS_DEVICE_DOES_NOT_EXIST) {
+ break;
+ }
+
+ if (status != STATUS_SUCCESS) {
+ continue;
+ }
+
+ if (ConfigBinding->AutoDetect[i]) {
+ Device->AutoDetect = TRUE;
+ }
+
+ ++SuccessfulOpens;
+
+ }
+
+ }
+
+
+ IpxFreeConfiguration(Config);
+
+ if (SuccessfulOpens == 0) {
+
+ IpxDereferenceDevice (Device, DREF_CREATE);
+
+ } else {
+
+ IPX_DEFINE_SYNC_CONTEXT (SyncContext);
+
+ //
+ // Allocate the device binding array and transfer those
+ // on the list to it. First count up the bindings.
+ //
+
+ BindingCount = 0;
+
+ for (p = Device->InitialBindingList.Flink;
+ p != &Device->InitialBindingList;
+ p = p->Flink) {
+
+ Binding = CONTAINING_RECORD (p, BINDING, InitialLinkage);
+ Adapter = Binding->Adapter;
+
+ if (Adapter->MacInfo.MediumAsync) {
+ Adapter->FirstWanNicId = (USHORT)(BindingCount+1);
+ Adapter->LastWanNicId = (USHORT)(BindingCount + Adapter->WanNicIdCount);
+ BindingCount += Adapter->WanNicIdCount;
+ } else {
+ ++BindingCount;
+ }
+ }
+
+ BindingArray = (PBINDING *)IpxAllocateMemory ((BindingCount+1) * sizeof(BINDING), MEMORY_BINDING, "Binding array");
+
+ if (BindingArray == NULL) {
+
+ while (!IsListEmpty (&Device->InitialBindingList)) {
+ p = RemoveHeadList (&Device->InitialBindingList);
+ Binding = CONTAINING_RECORD (p, BINDING, InitialLinkage);
+ IpxDestroyBinding (Binding);
+ }
+
+ IpxDereferenceDevice (Device, DREF_CREATE);
+ SuccessfulOpens = 0;
+ goto InitFailed;
+ }
+
+ RtlZeroMemory (BindingArray, (BindingCount+1) * sizeof(BINDING));
+
+ //
+ // Now walk the list transferring bindings to the array.
+ //
+
+ BindingIndex = 1;
+
+ for (p = Device->InitialBindingList.Flink;
+ p != &Device->InitialBindingList;
+ ) {
+
+ Binding = CONTAINING_RECORD (p, BINDING, InitialLinkage);
+
+ p = p->Flink; // we overwrite the linkage in here, so save it.
+
+ BindingArray[BindingIndex] = Binding;
+ Binding->NicId = (USHORT)BindingIndex;
+
+ if (Binding->ConfiguredNetworkNumber != 0) {
+
+ //
+ // If the configured network number is non-zero, then
+ // use it, unless we are unable to insert a rip table
+ // entry for it (duplicates are OK because they will
+ // become binding set members -- BUGBUG: What if the
+ // duplicate is a different media or frame type, then
+ // it won't get noted as a binding set).
+ //
+
+ status = RipInsertLocalNetwork(
+ Binding->ConfiguredNetworkNumber,
+ Binding->NicId,
+ Binding->Adapter->NdisBindingHandle,
+ (USHORT)((839 + Binding->Adapter->MediumSpeed) / Binding->Adapter->MediumSpeed));
+
+ if ((status == STATUS_SUCCESS) ||
+ (status == STATUS_DUPLICATE_NAME)) {
+
+ Binding->LocalAddress.NetworkAddress = Binding->ConfiguredNetworkNumber;
+ }
+ }
+
+ //
+ // These are a union with the InitialLinkage fields.
+ //
+
+ Binding->NextBinding = NULL;
+ Binding->CurrentSendBinding = NULL;
+
+ Adapter = Binding->Adapter;
+
+ if (Adapter->MacInfo.MediumAsync) {
+ CTEAssert (Adapter->FirstWanNicId == BindingIndex);
+ BindingIndex += Adapter->WanNicIdCount;
+ } else {
+ ++BindingIndex;
+ }
+ }
+
+ CTEAssert (BindingIndex == BindingCount+1);
+
+ Device->Bindings = BindingArray;
+ Device->BindingCount = BindingCount;
+
+
+ //
+ // Queue a request to discover our locally attached
+ // adapter addresses. This must succeed because we
+ // just allocated our send packet pool. We need
+ // to wait for this, either because we are
+ // auto-detecting or because we need to determine
+ // if there are multiple cards on the same network.
+ //
+
+ KeInitializeEvent(
+ &Device->AutoDetectEvent,
+ NotificationEvent,
+ FALSE
+ );
+
+ Device->AutoDetectState = AUTO_DETECT_STATE_RUNNING;
+
+ //
+ // Make this 0; after we are done waiting, which means
+ // the packet has been completed, we set it to the
+ // correct value.
+ //
+
+ Device->IncludedHeaderOffset = 0;
+
+ IPX_BEGIN_SYNC (&SyncContext);
+ status = RipQueueRequest (0xffffffff, RIP_REQUEST);
+ IPX_END_SYNC (&SyncContext);
+
+ CTEAssert (status == STATUS_PENDING);
+
+ //
+ // This is set when this rip send completes.
+ //
+
+ IPX_DEBUG (AUTO_DETECT, ("Waiting for AutoDetectEvent\n"));
+
+ KeWaitForSingleObject(
+ &Device->AutoDetectEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+
+ Device->AutoDetectState = AUTO_DETECT_STATE_PROCESSING;
+
+ //
+ // Now that we are done receiving responses, insert the
+ // current network number for every auto-detect binding
+ // to the rip database.
+ //
+
+ for (i = 1; i <= Device->BindingCount; i++) {
+
+ Binding = Device->Bindings[i];
+
+ //
+ // Skip empty WAN slots or bindings that were configured
+ // for a certain network number, we inserted those above.
+ // If no network number was detected, also skip it.
+ //
+
+ if ((!Binding) ||
+ (Binding->ConfiguredNetworkNumber != 0) ||
+ (Binding->TentativeNetworkAddress == 0)) {
+
+ continue;
+ }
+
+ IPX_DEBUG (AUTO_DETECT, ("Final score for %lx on %lx is %d - %d\n",
+ REORDER_ULONG(Binding->TentativeNetworkAddress),
+ Binding,
+ Binding->MatchingResponses,
+ Binding->NonMatchingResponses));
+
+ //
+ // We don't care about the status.
+ //
+
+ status = RipInsertLocalNetwork(
+ Binding->TentativeNetworkAddress,
+ Binding->NicId,
+ Binding->Adapter->NdisBindingHandle,
+ (USHORT)((839 + Binding->MediumSpeed) / Binding->MediumSpeed));
+
+ if ((status != STATUS_SUCCESS) &&
+ (status != STATUS_DUPLICATE_NAME)) {
+
+ //
+ // We failed to insert, keep it at zero, hopefully
+ // we will be able to update later.
+ //
+
+#if DBG
+ DbgPrint ("IPX: Could not insert net %lx for binding %lx\n",
+ REORDER_ULONG(Binding->LocalAddress.NetworkAddress),
+ Binding);
+#endif
+ CTEAssert (Binding->LocalAddress.NetworkAddress == 0);
+
+ } else {
+
+ Binding->LocalAddress.NetworkAddress = Binding->TentativeNetworkAddress;
+ }
+
+ }
+
+ ValidBindings = Device->BindingCount;
+
+ if (Device->AutoDetect) {
+
+ ValidBindings = IpxResolveAutoDetect (Device, ValidBindings, RegistryPath);
+
+ }
+
+ Device->ValidBindings = ValidBindings;
+
+ //
+ // Now see if any bindings are actually on the same
+ // network. This sets Device->HighestExternalNicId
+ // and Device->HighestType20NicId.
+ //
+
+ IpxResolveBindingSets (Device, ValidBindings);
+
+
+ //
+ // For multiple adapters, use the offset of the first...why not.
+ //
+
+#if 0
+ Device->IncludedHeaderOffset = Device->Bindings[1]->DefHeaderSize;
+#endif
+
+ Device->IncludedHeaderOffset = MAC_HEADER_SIZE;
+
+ //
+ // Success; see if there is a virtual network configured.
+ //
+
+ if (Device->VirtualNetworkNumber != 0) {
+
+ status = RipInsertLocalNetwork(
+ Device->VirtualNetworkNumber,
+ 0, // NIC ID
+ Device->Bindings[1]->Adapter->NdisBindingHandle,
+ 1);
+
+ if (status != STATUS_SUCCESS) {
+
+ //
+ // Log the appropriate error, then ignore the
+ // virtual network. If the error was
+ // INSUFFICIENT_RESOURCES, the RIP module
+ // will have already logged an error.
+ //
+
+ if (status == STATUS_DUPLICATE_NAME) {
+
+ IPX_DEBUG (AUTO_DETECT, ("Ignoring virtual network %lx, conflict\n", REORDER_ULONG (Device->VirtualNetworkNumber)));
+
+ IpxWriteResourceErrorLog(
+ Device->DeviceObject,
+ EVENT_IPX_INTERNAL_NET_INVALID,
+ 0,
+ REORDER_ULONG (Device->VirtualNetworkNumber));
+ }
+
+ Device->VirtualNetworkNumber = 0;
+ goto NoVirtualNetwork;
+
+ }
+
+ Device->VirtualNetwork = TRUE;
+ Device->MultiCardZeroVirtual = FALSE;
+ RtlCopyMemory(Device->SourceAddress.NodeAddress, VirtualNode, 6);
+ Device->SourceAddress.NetworkAddress = Device->VirtualNetworkNumber;
+
+ //
+ // This will get set to FALSE if RIP binds.
+ //
+
+ Device->RipResponder = TRUE;
+
+ } else {
+
+NoVirtualNetwork:
+
+ Device->VirtualNetwork = FALSE;
+
+ //
+ // See if we need to be set up for the fake
+ // virtual network.
+ //
+
+ if (ValidBindings > 1) {
+
+ CTEAssert (Device->VirtualNetworkOptional);
+
+ //
+ // In this case we return as our local node the
+ // address of the first card. We will also only
+ // direct SAP sends to that card.
+ //
+
+ Device->MultiCardZeroVirtual = TRUE;
+
+ } else {
+
+ Device->MultiCardZeroVirtual = FALSE;
+ }
+
+ RtlCopyMemory(&Device->SourceAddress, &Device->Bindings[1]->LocalAddress, FIELD_OFFSET(TDI_ADDRESS_IPX,Socket));
+
+ }
+
+
+ //
+ // Now get SapNicCount -- regular adapters are counted
+ // as one, but all the WAN lines together only count for one.
+ // We also calculate FirstLanNicId and FirstWanNicId here.
+ //
+
+ CountedWan = FALSE;
+ Device->SapNicCount = 0;
+
+ Device->FirstLanNicId = (USHORT)-1;
+ Device->FirstWanNicId = (USHORT)-1;
+
+ {
+ ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
+
+ for (i = 1; i <= Index; i++) {
+
+ if (Device->Bindings[i]) {
+
+ if (Device->Bindings[i]->Adapter->MacInfo.MediumAsync) {
+
+ if (Device->FirstWanNicId == (USHORT)-1) {
+ Device->FirstWanNicId = i;
+ }
+
+ if (CountedWan) {
+ continue;
+ } else {
+ CountedWan = TRUE;
+ }
+
+ } else {
+
+ if (Device->FirstLanNicId == (USHORT)-1) {
+ Device->FirstLanNicId = i;
+ }
+
+ }
+
+ } else {
+
+ //
+ // NULL bindings are WANs and are not the first one,
+ // so don't count them.
+ //
+
+ CTEAssert (Device->FirstWanNicId != -1);
+ CTEAssert (CountedWan);
+ continue;
+ }
+
+ ++Device->SapNicCount;
+
+ }
+ }
+
+ if (Device->FirstLanNicId == (USHORT)-1) {
+ Device->FirstLanNicId = 1;
+ }
+ if (Device->FirstWanNicId == (USHORT)-1) {
+ Device->FirstWanNicId = 1;
+ }
+
+
+ //
+ // Calculate some values based on all the bindings.
+ //
+
+ MaxLookahead = Device->Bindings[1]->MaxLookaheadData; // largest binding value
+ AnnouncedMaxDatagram = Device->Bindings[1]->AnnouncedMaxDatagramSize; // smallest binding value
+ RealMaxDatagram = Device->Bindings[1]->RealMaxDatagramSize; // smallest binding value
+
+ if (Device->Bindings[1]->LineUp) {
+ LinkSpeed = Device->Bindings[1]->MediumSpeed; // smallest binding value
+ } else {
+ LinkSpeed = 0xffffffff;
+ }
+ MacOptions = Device->Bindings[1]->Adapter->MacInfo.MacOptions; // AND of binding values
+
+ for (i = 2; i <= ValidBindings; i++) {
+
+ Binding = Device->Bindings[i];
+
+ if (!Binding) {
+ continue;
+ }
+
+ if (Binding->MaxLookaheadData > MaxLookahead) {
+ MaxLookahead = Binding->MaxLookaheadData;
+ }
+ if (Binding->AnnouncedMaxDatagramSize < AnnouncedMaxDatagram) {
+ AnnouncedMaxDatagram = Binding->AnnouncedMaxDatagramSize;
+ }
+ if (Binding->RealMaxDatagramSize < RealMaxDatagram) {
+ RealMaxDatagram = Binding->RealMaxDatagramSize;
+ }
+
+ if (Binding->LineUp && (Binding->MediumSpeed < LinkSpeed)) {
+ LinkSpeed = Binding->MediumSpeed;
+ }
+ MacOptions &= Binding->Adapter->MacInfo.MacOptions;
+
+ }
+
+ Device->Information.MaxDatagramSize = AnnouncedMaxDatagram;
+ Device->RealMaxDatagramSize = RealMaxDatagram;
+ Device->Information.MaximumLookaheadData = MaxLookahead;
+
+ //
+ // If we couldn't find anything better, use the speed from
+ // the first binding.
+ //
+
+ if (LinkSpeed == 0xffffffff) {
+ Device->LinkSpeed = Device->Bindings[1]->MediumSpeed;
+ } else {
+ Device->LinkSpeed = LinkSpeed;
+ }
+ Device->MacOptions = MacOptions;
+
+ Device->State = DEVICE_STATE_OPEN;
+ Device->AutoDetectState = AUTO_DETECT_STATE_DONE;
+
+ IPX_DEBUG (DEVICE, ("Node is %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x, ",
+ Device->SourceAddress.NodeAddress[0], Device->SourceAddress.NodeAddress[1],
+ Device->SourceAddress.NodeAddress[2], Device->SourceAddress.NodeAddress[3],
+ Device->SourceAddress.NodeAddress[4], Device->SourceAddress.NodeAddress[5]));
+ IPX_DEBUG (DEVICE, ("Network is %lx\n",
+ REORDER_ULONG (Device->SourceAddress.NetworkAddress)));
+
+
+ //
+ // Start the timer which updates the RIP database
+ // periodically. For the first one we do a ten
+ // second timeout (hopefully this is enough time
+ // for RIP to start if it is going to).
+ //
+
+ IpxReferenceDevice (Device, DREF_LONG_TIMER);
+
+ CTEStartTimer(
+ &Device->RipLongTimer,
+ 10000,
+ RipLongTimeout,
+ (PVOID)Device);
+
+ //
+ // We use this event when unloading to signal that we
+ // can proceed...initialize it here so we know it is
+ // ready to go when unload is called.
+ //
+
+ KeInitializeEvent(
+ &IpxDevice->UnloadEvent,
+ NotificationEvent,
+ FALSE
+ );
+
+ }
+
+InitFailed:
+
+ if (SuccessfulOpens == 0) {
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)DriverObject,
+ EVENT_IPX_NO_ADAPTERS,
+ 802,
+ STATUS_DEVICE_DOES_NOT_EXIST,
+ NULL,
+ 0,
+ NULL);
+ return STATUS_DEVICE_DOES_NOT_EXIST;
+
+ } else {
+
+ return STATUS_SUCCESS;
+ }
+
+#else // _PNP_POWER
+{
+ PBIND_ARRAY_ELEM BindingArray;
+ PTA_ADDRESS TdiRegistrationAddress;
+
+ //
+ // Pre-allocate the binding array
+ // Later, we will allocate the LAN/WAN and SLAVE bindings separately
+ // [BUGBUGZZ] Read the array size from registry?
+ //
+ BindingArray = (PBIND_ARRAY_ELEM)IpxAllocateMemory (
+ MAX_BINDINGS * sizeof(BIND_ARRAY_ELEM),
+ MEMORY_BINDING,
+ "Binding array");
+
+ if (BindingArray == NULL) {
+ IpxWriteGeneralErrorLog(
+ (PVOID)DriverObject,
+ EVENT_IPX_NO_ADAPTERS,
+ 802,
+ STATUS_DEVICE_DOES_NOT_EXIST,
+ NULL,
+ 0,
+ NULL);
+ IpxDereferenceDevice (Device, DREF_CREATE);
+ return STATUS_DEVICE_DOES_NOT_EXIST;
+ }
+
+ Device->MaxBindings = MAX_BINDINGS;
+
+ //
+ // Allocate the TA_ADDRESS structure - this will be used in all TdiRegisterNetAddress
+ // notifications.
+ //
+ TdiRegistrationAddress = (PTA_ADDRESS)IpxAllocateMemory (
+ (2 * sizeof(USHORT) + sizeof(TDI_ADDRESS_IPX)),
+ MEMORY_ADDRESS,
+ "Tdi Address");
+
+ if (TdiRegistrationAddress == NULL) {
+ IpxWriteGeneralErrorLog(
+ (PVOID)DriverObject,
+ EVENT_IPX_NO_ADAPTERS,
+ 802,
+ STATUS_DEVICE_DOES_NOT_EXIST,
+ NULL,
+ 0,
+ NULL);
+ IpxFreeMemory(BindingArray, sizeof(BindingArray), MEMORY_BINDING, "Binding Array");
+ IpxDereferenceDevice (Device, DREF_CREATE);
+ return STATUS_DEVICE_DOES_NOT_EXIST;
+ }
+
+ RtlZeroMemory (BindingArray, MAX_BINDINGS * sizeof(BIND_ARRAY_ELEM));
+ RtlZeroMemory (TdiRegistrationAddress, 2 * sizeof(USHORT) + sizeof(TDI_ADDRESS_IPX));
+
+ Device->Bindings = BindingArray;
+
+ TdiRegistrationAddress->AddressLength = sizeof(TDI_ADDRESS_IPX);
+ TdiRegistrationAddress->AddressType = TDI_ADDRESS_TYPE_IPX;
+
+ //
+ // Store the pointer in the Device.
+ //
+ Device->TdiRegistrationAddress = TdiRegistrationAddress;
+
+ //
+ // Device state is loaded, but not opened. It is opened when at least
+ // one adapter has appeared.
+ //
+ Device->State = DEVICE_STATE_LOADED;
+
+ Device->FirstLanNicId = Device->FirstWanNicId = (USHORT)1; // will be changed later
+
+ IpxFreeConfiguration(Config);
+
+ //
+ // We use this event when unloading to signal that we
+ // can proceed...initialize it here so we know it is
+ // ready to go when unload is called.
+ //
+
+ KeInitializeEvent(
+ &IpxDevice->UnloadEvent,
+ NotificationEvent,
+ FALSE
+ );
+
+ return STATUS_SUCCESS;
+}
+#endif // _PNP_POWER
+} /* DriverEntry */
+
+
+ULONG
+IpxResolveAutoDetect(
+ IN PDEVICE Device,
+ IN ULONG ValidBindings,
+#ifdef _PNP_POWER
+ IN CTELockHandle *LockHandle1,
+#endif
+ IN PUNICODE_STRING RegistryPath
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called for auto-detect bindings to
+ remove any bindings that were not successfully found.
+ It also updates "DefaultAutoDetectType" in the registry
+ if needed.
+
+Arguments:
+
+ Device - The IPX device object.
+
+ ValidBindings - The total number of bindings present.
+
+ RegistryPath - The path to the ipx registry, used if we have
+ to write a value back.
+
+Return Value:
+
+ The updated number of bindings.
+
+--*/
+
+{
+ PBINDING Binding, TmpBinding;
+ UINT i, j;
+
+ //
+ // Get rid of any auto-detect devices which we
+ // could not find nets for. We also remove any
+ // devices which are not the first ones
+ // auto-detected on a particular adapter.
+ //
+
+ for (i = 1; i <= ValidBindings; i++) {
+#ifdef _PNP_POWER
+ Binding = NIC_ID_TO_BINDING(Device, i);
+#else
+ Binding = Device->Bindings[i];
+#endif
+
+ if (!Binding) {
+ continue;
+ }
+
+ //
+ // If this was auto-detected and was not the default,
+ // or it was the default, but nothing was detected for
+ // it *and* something else *was* detected (which means
+ // we will use that frame type when we get to it),
+ // we may need to remove this binding.
+ //
+
+ if (Binding->AutoDetect &&
+ (!Binding->DefaultAutoDetect ||
+ (Binding->DefaultAutoDetect &&
+ (Binding->LocalAddress.NetworkAddress == 0) &&
+ Binding->Adapter->AutoDetectResponse))) {
+
+ if ((Binding->LocalAddress.NetworkAddress == 0) ||
+ (Binding->Adapter->AutoDetectFound)) {
+
+ //
+ // Remove this binding.
+ //
+
+ if (Binding->LocalAddress.NetworkAddress == 0) {
+ IPX_DEBUG (AUTO_DETECT, ("Binding %d (%d) no net found\n",
+ i, Binding->FrameType));
+ } else {
+ IPX_DEBUG (AUTO_DETECT, ("Binding %d (%d) adapter already auto-detected\n",
+ i, Binding->FrameType));
+ }
+
+ CTEAssert (Binding->NicId == i);
+ CTEAssert (!Binding->Adapter->MacInfo.MediumAsync);
+
+ //
+ // Remove any routes through this NIC, and
+ // adjust any NIC ID's above this one in the
+ // database down by one.
+ //
+
+ RipAdjustForBindingChange (Binding->NicId, 0, IpxBindingDeleted);
+
+ Binding->Adapter->Bindings[Binding->FrameType] = NULL;
+ for (j = i+1; j <= ValidBindings; j++) {
+#ifndef _PNP_POWER
+ TmpBinding = Device->Bindings[j];
+ Device->Bindings[j-1] = TmpBinding;
+#else
+ TmpBinding = NIC_ID_TO_BINDING(Device, j);
+ INSERT_BINDING(Device, j-1, TmpBinding);
+#endif _PNP_POWER
+ if (TmpBinding) {
+ if ((TmpBinding->Adapter->MacInfo.MediumAsync) &&
+ (TmpBinding->Adapter->FirstWanNicId == TmpBinding->NicId)) {
+ --TmpBinding->Adapter->FirstWanNicId;
+ --TmpBinding->Adapter->LastWanNicId;
+ }
+ --TmpBinding->NicId;
+ }
+ }
+#ifdef _PNP_POWER
+ INSERT_BINDING(Device, ValidBindings, NULL);
+#else
+ Device->Bindings[ValidBindings] = NULL;
+#endif
+ --Binding->Adapter->BindingCount;
+ --ValidBindings;
+
+ --i; // so we check the binding that was just moved.
+
+ //
+ // Wait 100 ms before freeing the binding,
+ // in case an indication is using it.
+ //
+
+ KeStallExecutionProcessor(100000);
+
+ IpxDestroyBinding (Binding);
+
+ } else {
+
+ IPX_DEBUG (AUTO_DETECT, ("Binding %d (%d) auto-detected OK\n",
+ i, Binding->FrameType));
+
+#if DBG
+ DbgPrint ("IPX: Auto-detected non-default frame type %s, net %lx\n",
+ OutputFrameType(Binding),
+ REORDER_ULONG (Binding->LocalAddress.NetworkAddress));
+#endif
+
+ //
+ // Save it in the registry for the next boot.
+ //
+#ifdef _PNP_POWER
+//
+// This cannot be done at DPC, so, drop the IRQL
+//
+ IPX_FREE_LOCK1(&Device->BindAccessLock, *LockHandle1);
+ IpxWriteDefaultAutoDetectType(
+ RegistryPath,
+ Binding->Adapter,
+ Binding->FrameType);
+ IPX_GET_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+ IpxWriteDefaultAutoDetectType(
+ RegistryPath,
+ Binding->Adapter,
+ Binding->FrameType);
+#endif
+
+ Binding->Adapter->AutoDetectFound = TRUE;
+ }
+
+ } else {
+
+ if (Binding->AutoDetect) {
+
+ IPX_DEBUG (AUTO_DETECT, ("Binding %d (%d) auto-detect default\n",
+ i, Binding->FrameType));
+
+#if DBG
+ if (Binding->LocalAddress.NetworkAddress != 0) {
+ DbgPrint ("IPX: Auto-detected default frame type %s, net %lx\n",
+ OutputFrameType(Binding),
+ REORDER_ULONG (Binding->LocalAddress.NetworkAddress));
+ } else {
+ DbgPrint ("IPX: Using default auto-detect frame type %s\n",
+ OutputFrameType(Binding));
+ }
+#endif
+
+ Binding->Adapter->AutoDetectFound = TRUE;
+
+ } else {
+
+ IPX_DEBUG (AUTO_DETECT, ("Binding %d (%d) not auto-detected\n",
+ i, Binding->FrameType));
+ }
+
+ }
+
+ }
+
+
+ for (i = 1; i <= ValidBindings; i++) {
+#ifdef _PNP_POWER
+ if (Binding = NIC_ID_TO_BINDING(Device, i)) {
+#else
+ if (Binding = Device->Bindings[i]) {
+#endif
+ CTEAssert (Binding->NicId == i);
+ IPX_DEBUG (AUTO_DETECT, ("Binding %lx, type %d, auto %d\n",
+ Binding, Binding->FrameType, Binding->AutoDetect));
+ }
+
+ }
+
+ return ValidBindings;
+
+} /* IpxResolveAutoDetect */
+
+
+VOID
+IpxResolveBindingSets(
+ IN PDEVICE Device,
+ IN ULONG ValidBindings
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to determine if we have any
+ binding sets and rearrange the bindings the way we
+ like. The order is as follows:
+
+ - First comes the first binding to each LAN network
+ - Following that are all WAN bindings
+ - Following that are any duplicate bindings to LAN networks
+ (the others in the "binding set").
+
+ If "global wan net" is true we will advertise up to
+ and including the first wan binding as the highest nic
+ id; otherwise we advertise up to and including the last
+ wan binding. In all cases the duplicate bindings are
+ hidden.
+
+Arguments:
+
+ Device - The IPX device object.
+
+ ValidBindings - The total number of bindings present.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PBINDING Binding, MasterBinding, TmpBinding;
+ UINT i, j;
+ ULONG WanCount, DuplicateCount;
+
+ //
+ // First loop through and push all the wan bindings
+ // to the end.
+ //
+#ifdef _PNP_POWER
+
+ WanCount = Device->HighestExternalNicId - Device->HighestLanNicId;
+
+#else
+
+ WanCount = 0;
+
+ //
+ // For PnP, we dont do this as the bindings are in order
+ // at the time of insertion
+ //
+ for (i = 1; i <= (ValidBindings-WanCount); ) {
+
+ Binding = Device->Bindings[i];
+
+ if ((Binding == NULL) || Binding->Adapter->MacInfo.MediumAsync) {
+
+ //
+ // Put this binding at the end, and slide all the
+ // others down. If it is a NULL WAN binding then we
+ // don't have to do some of this.
+ //
+
+#if DBG
+ //
+ // Any non-NULL bindings should be correct in this
+ // respect at any point.
+ //
+
+ if (Binding != NULL) {
+ CTEAssert (Binding->NicId == i);
+ }
+#endif
+
+ //
+ // If the Binding is NULL we won't have anything in the
+ // database at this binding, but we still need to adjust
+ // any NIC ID's in the database which are above this.
+ //
+
+ RipAdjustForBindingChange ((USHORT)i, (USHORT)ValidBindings, IpxBindingMoved);
+
+ //
+ // Slide the bindings above this down.
+ //
+
+ for (j = i+1; j <= ValidBindings; j++) {
+ TmpBinding = Device->Bindings[j];
+ Device->Bindings[j-1] = TmpBinding;
+ if (TmpBinding) {
+ if ((TmpBinding->Adapter->MacInfo.MediumAsync) &&
+ (TmpBinding->Adapter->FirstWanNicId == TmpBinding->NicId)) {
+ --TmpBinding->Adapter->FirstWanNicId;
+ --TmpBinding->Adapter->LastWanNicId;
+ }
+ --TmpBinding->NicId;
+ }
+ }
+
+ //
+ // Put this binding at the end.
+ //
+
+ Device->Bindings[ValidBindings] = Binding;
+ if (Binding != NULL) {
+ if ((Binding->Adapter->MacInfo.MediumAsync) &&
+ (Binding->Adapter->FirstWanNicId == Binding->NicId)) {
+ Binding->Adapter->FirstWanNicId = (USHORT)ValidBindings;
+ Binding->Adapter->LastWanNicId += (USHORT)(ValidBindings - Binding->NicId);
+ }
+ Binding->NicId = (USHORT)ValidBindings;
+ }
+ ++WanCount;
+
+ //
+ // Keep i the same, to check the new binding at
+ // this position.
+ //
+
+ } else {
+
+ i++;
+
+ }
+
+ }
+#endif _PNP_POWER
+ //
+ // Now go through and find the LAN duplicates and
+ // create binding sets from them.
+ //
+
+ DuplicateCount = 0;
+
+ for (i = 1; i <= (ValidBindings-(WanCount+DuplicateCount)); ) {
+
+#ifdef _PNP_POWER
+ Binding = NIC_ID_TO_BINDING(Device, i);
+#else
+ Binding = Device->Bindings[i];
+#endif
+ CTEAssert (Binding != NULL); // because we are only looking at LAN bindings
+
+ CTEAssert (!Binding->Adapter->MacInfo.MediumAsync);
+
+ if (Binding->LocalAddress.NetworkAddress == 0) {
+ i++;
+ continue;
+ }
+
+ //
+ // See if any previous bindings match the
+ // frame type, medium type, and number of
+ // this network (for the moment we match on
+ // frame type and medium type too so that we
+ // don't have to worry about different frame
+ // formats and header offsets within a set).
+ //
+
+ for (j = 1; j < i; j++) {
+#ifdef _PNP_POWER
+ MasterBinding = NIC_ID_TO_BINDING(Device, j);
+#else
+ MasterBinding = Device->Bindings[j];
+#endif
+ if ((MasterBinding->LocalAddress.NetworkAddress == Binding->LocalAddress.NetworkAddress) &&
+ (MasterBinding->FrameType == Binding->FrameType) &&
+ (MasterBinding->Adapter->MacInfo.MediumType == Binding->Adapter->MacInfo.MediumType)) {
+ break;
+ }
+
+ }
+
+ if (j == i) {
+ i++;
+ continue;
+ }
+
+ //
+ // We have a duplicate. First slide it down to the
+ // end. Note that we change any router entries that
+ // use our real NicId to use the real NicId of the
+ // master (there should be no entries in the rip
+ // database that have the NicId of a binding slave).
+ //
+
+ RipAdjustForBindingChange (Binding->NicId, MasterBinding->NicId, IpxBindingMoved);
+
+ for (j = i+1; j <= ValidBindings; j++) {
+#ifdef _PNP_POWER
+ TmpBinding = NIC_ID_TO_BINDING(Device, j);
+ INSERT_BINDING(Device, j-1, TmpBinding);
+#else
+ TmpBinding = Device->Bindings[j];
+ Device->Bindings[j-1] = TmpBinding;
+#endif
+ if (TmpBinding) {
+ if ((TmpBinding->Adapter->MacInfo.MediumAsync) &&
+ (TmpBinding->Adapter->FirstWanNicId == TmpBinding->NicId)) {
+ --TmpBinding->Adapter->FirstWanNicId;
+ --TmpBinding->Adapter->LastWanNicId;
+ }
+ --TmpBinding->NicId;
+ }
+ }
+#ifdef _PNP_POWER
+ INSERT_BINDING(Device, ValidBindings, Binding);
+#else
+ Device->Bindings[ValidBindings] = Binding;
+#endif
+
+ Binding->NicId = (USHORT)ValidBindings;
+ ++DuplicateCount;
+
+ //
+ // Now make MasterBinding the head of a binding set.
+ //
+
+ if (MasterBinding->BindingSetMember) {
+
+ //
+ // Just insert ourselves in the chain.
+ //
+
+#if DBG
+ DbgPrint ("IPX: %lx is also on network %lx\n",
+ Binding->Adapter->AdapterName,
+ REORDER_ULONG (Binding->LocalAddress.NetworkAddress));
+#endif
+ IPX_DEBUG (AUTO_DETECT, ("Add %lx to binding set of %lx\n", Binding, MasterBinding));
+
+ CTEAssert (MasterBinding->CurrentSendBinding);
+ Binding->NextBinding = MasterBinding->NextBinding;
+
+ } else {
+
+ //
+ // Start the chain with the two bindings in it.
+ //
+
+#if DBG
+ DbgPrint ("IPX: %lx and %lx are on the same network %lx, will load balance\n",
+ MasterBinding->Adapter->AdapterName, Binding->Adapter->AdapterName,
+ REORDER_ULONG (Binding->LocalAddress.NetworkAddress));
+#endif
+ IPX_DEBUG (AUTO_DETECT, ("Create new %lx in binding set of %lx\n", Binding, MasterBinding));
+
+ MasterBinding->BindingSetMember = TRUE;
+ MasterBinding->CurrentSendBinding = MasterBinding;
+ MasterBinding->MasterBinding = MasterBinding;
+ Binding->NextBinding = MasterBinding;
+
+ }
+
+ MasterBinding->NextBinding = Binding;
+ Binding->BindingSetMember = TRUE;
+ Binding->ReceiveBroadcast = FALSE;
+ Binding->CurrentSendBinding = NULL;
+ Binding->MasterBinding = MasterBinding;
+
+ //
+ // Since the master binding looks like all members of
+ // the binding set to people querying from above, we have
+ // to make it the worst-case of all the elements. Generally
+ // these will be equal since the frame type and media is
+ // the same.
+ //
+
+ if (Binding->MaxLookaheadData > MasterBinding->MaxLookaheadData) {
+ MasterBinding->MaxLookaheadData = Binding->MaxLookaheadData;
+ }
+ if (Binding->AnnouncedMaxDatagramSize < MasterBinding->AnnouncedMaxDatagramSize) {
+ MasterBinding->AnnouncedMaxDatagramSize = Binding->AnnouncedMaxDatagramSize;
+ }
+ if (Binding->RealMaxDatagramSize < MasterBinding->RealMaxDatagramSize) {
+ MasterBinding->RealMaxDatagramSize = Binding->RealMaxDatagramSize;
+ }
+ if (Binding->MediumSpeed < MasterBinding->MediumSpeed) {
+ MasterBinding->MediumSpeed = Binding->MediumSpeed;
+ }
+
+ //
+ // Keep i the same, to check the new binding at
+ // this position.
+ //
+
+ }
+#ifndef _PNP_POWER
+ Device->HighestExternalNicId = (USHORT)(ValidBindings - DuplicateCount);
+ Device->HighestType20NicId = (USHORT)(ValidBindings-(WanCount+DuplicateCount));
+#else
+ Device->HighestLanNicId -= (USHORT)DuplicateCount;
+
+ if (Device->HighestLanNicId == 0) {
+ CTEAssert(FALSE);
+ }
+
+ Device->HighestExternalNicId -= (USHORT)DuplicateCount;
+ Device->HighestType20NicId -= (USHORT)DuplicateCount;
+ Device->SapNicCount -= (USHORT)DuplicateCount;
+#endif _PNP_POWER
+} /* IpxResolveBindingSets */
+
+
+NTSTATUS
+IpxBindToAdapter(
+ IN PDEVICE Device,
+ IN PBINDING_CONFIG ConfigBinding,
+#ifdef _PNP_POWER
+ IN PADAPTER *AdapterPtr,
+#endif
+ IN ULONG FrameTypeIndex
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles binding the transport to a new
+ adapter. It can be called at any point during the life
+ of the transport.
+
+Arguments:
+
+ Device - The IPX device object.
+
+ ConfigBinding - The configuration info for this binding.
+
+ AdapterPtr - pointer to the adapter to bind to in case of PnP.
+
+ FrameTypeIndex - The index into ConfigBinding's array of frame
+ types for this adapter. The routine is called once for
+ every valid frame type.
+
+Return Value:
+
+ The function value is the final status from the initialization operation.
+
+--*/
+
+{
+ NTSTATUS status;
+
+#ifndef _PNP_POWER
+ //
+ // Adapter came in as a parameter
+ //
+ PADAPTER Adapter = NULL;
+#else
+ PADAPTER Adapter = *AdapterPtr;
+#endif
+
+ PBINDING Binding, OldBinding;
+ ULONG FrameType, MappedFrameType;
+ PLIST_ENTRY p;
+
+ //
+ // We can't bind more than one adapter unless we have a
+ // virtual network configured or we are allowed to run
+ // with a virtual network of 0.
+ //
+
+ if (Device->BindingCount == 1) {
+ if ((Device->VirtualNetworkNumber == 0) &&
+ (!Device->VirtualNetworkOptional)) {
+
+ IPX_DEBUG (ADAPTER, ("Cannot bind to more than one adapter\n"));
+ DbgPrint ("IPX: Disallowing multiple bind ==> VirtualNetwork is 0\n");
+ IpxWriteGeneralErrorLog(
+ Device->DeviceObject,
+ EVENT_TRANSPORT_BINDING_FAILED,
+ 666,
+ STATUS_NOT_SUPPORTED,
+ ConfigBinding->AdapterName.Buffer,
+ 0,
+ NULL);
+
+ return STATUS_NOT_SUPPORTED;
+ }
+ }
+
+
+ //
+ // First allocate the memory for the binding.
+ //
+
+ status = IpxCreateBinding(
+ Device,
+ ConfigBinding,
+ FrameTypeIndex,
+ ConfigBinding->AdapterName.Buffer,
+ &Binding);
+
+ if (status != STATUS_SUCCESS) {
+ return status;
+ }
+
+ FrameType = ConfigBinding->FrameType[FrameTypeIndex];
+
+//
+// In PnP case, we dont need to check for existing adapters since
+// we supply a NULL adapter in the parameters if it needs to be created
+//
+#ifndef _PNP_POWER
+
+ //
+ // Check if there is already an NDIS binding to this adapter,
+ // and if so, that there is not already a binding with this
+ // frame type.
+ //
+
+
+ for (p = Device->InitialBindingList.Flink;
+ p != &Device->InitialBindingList;
+ p = p->Flink) {
+
+ OldBinding = CONTAINING_RECORD (p, BINDING, InitialLinkage);
+
+ if (RtlEqualMemory(
+ OldBinding->Adapter->AdapterName,
+ ConfigBinding->AdapterName.Buffer,
+ OldBinding->Adapter->AdapterNameLength)) {
+
+ Adapter = OldBinding->Adapter;
+
+ MacMapFrameType(
+ Adapter->MacInfo.RealMediumType,
+ FrameType,
+ &MappedFrameType);
+
+ if (Adapter->Bindings[MappedFrameType] != NULL) {
+
+ IPX_DEBUG (ADAPTER, ("Bind to adapter %ws, type %d exists\n",
+ Adapter->AdapterName,
+ MappedFrameType));
+
+ //
+ // If this was the auto-detect default for this
+ // adapter and it failed, we need to make the
+ // previous one the default, so that at least
+ // one binding will stick around.
+ //
+
+ if (ConfigBinding->DefaultAutoDetect[FrameTypeIndex]) {
+ IPX_DEBUG (ADAPTER, ("Default auto-detect changed from %d to %d\n",
+ FrameType, MappedFrameType));
+ Adapter->Bindings[MappedFrameType]->DefaultAutoDetect = TRUE;
+ }
+
+ IpxDestroyBinding (Binding);
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ IPX_DEBUG (ADAPTER, ("Using existing bind to adapter %ws, type %d\n",
+ Adapter->AdapterName,
+ MappedFrameType));
+ break;
+
+ }
+ }
+#endif _PNP_POWER
+
+ if (Adapter == NULL) {
+
+ //
+ // No binding to this adapter exists, so create a
+ // new one.
+ //
+
+ status = IpxCreateAdapter(
+ Device,
+ &ConfigBinding->AdapterName,
+ &Adapter);
+
+ if (status != STATUS_SUCCESS) {
+ IpxDestroyBinding(Binding);
+ return status;
+ }
+
+ //
+ // Save these now (they will be the same for all bindings
+ // on this adapter).
+ //
+
+ Adapter->ConfigMaxPacketSize = ConfigBinding->Parameters[BINDING_MAX_PKT_SIZE];
+ Adapter->SourceRouting = (BOOLEAN)ConfigBinding->Parameters[BINDING_SOURCE_ROUTE];
+ Adapter->EnableFunctionalAddress = (BOOLEAN)ConfigBinding->Parameters[BINDING_ENABLE_FUNC_ADDR];
+ Adapter->EnableWanRouter = (BOOLEAN)ConfigBinding->Parameters[BINDING_ENABLE_WAN];
+
+ Adapter->BindSap = (USHORT)ConfigBinding->Parameters[BINDING_BIND_SAP];
+ Adapter->BindSapNetworkOrder = REORDER_USHORT(Adapter->BindSap);
+ CTEAssert (Adapter->BindSap == 0x8137);
+ CTEAssert (Adapter->BindSapNetworkOrder == 0x3781);
+
+ //
+ // Now fire up NDIS so this adapter talks
+ //
+
+ status = IpxInitializeNdis(
+ Adapter,
+ ConfigBinding);
+
+ if (!NT_SUCCESS (status)) {
+
+ //
+ // Log an error.
+ //
+
+ IpxWriteGeneralErrorLog(
+ Device->DeviceObject,
+ EVENT_TRANSPORT_BINDING_FAILED,
+ 601,
+ status,
+ ConfigBinding->AdapterName.Buffer,
+ 0,
+ NULL);
+
+ IpxDestroyAdapter (Adapter);
+ IpxDestroyBinding (Binding);
+
+ //
+ // Returning this status informs the caller to not
+ // try any more frame types on this adapter.
+ //
+
+ return STATUS_DEVICE_DOES_NOT_EXIST;
+
+ }
+
+ //
+ // For 802.5 bindings we need to start the source routing
+ // timer to time out old entries.
+ //
+
+ if ((Adapter->MacInfo.MediumType == NdisMedium802_5) &&
+ (Adapter->SourceRouting)) {
+
+ if (!Device->SourceRoutingUsed) {
+
+ Device->SourceRoutingUsed = TRUE;
+ IpxReferenceDevice (Device, DREF_SR_TIMER);
+
+ CTEStartTimer(
+ &Device->SourceRoutingTimer,
+ 60000, // one minute timeout
+ MacSourceRoutingTimeout,
+ (PVOID)Device);
+ }
+ }
+
+ MacMapFrameType(
+ Adapter->MacInfo.RealMediumType,
+ FrameType,
+ &MappedFrameType);
+
+ IPX_DEBUG (ADAPTER, ("Create new bind to adapter %ws, type %d\n",
+ ConfigBinding->AdapterName.Buffer,
+ MappedFrameType));
+
+ IpxAllocateReceiveBufferPool (Adapter);
+
+#ifdef _PNP_POWER
+ *AdapterPtr = Adapter;
+#endif
+ }
+#ifdef _PNP_POWER
+ else {
+ //
+ // get the mapped frame type
+ //
+ MacMapFrameType(
+ Adapter->MacInfo.RealMediumType,
+ FrameType,
+ &MappedFrameType);
+
+ if (Adapter->Bindings[MappedFrameType] != NULL) {
+
+ IPX_DEBUG (ADAPTER, ("Bind to adapter %ws, type %d exists\n",
+ Adapter->AdapterName,
+ MappedFrameType));
+
+ //
+ // If this was the auto-detect default for this
+ // adapter and it failed, we need to make the
+ // previous one the default, so that at least
+ // one binding will stick around.
+ //
+
+ if (ConfigBinding->DefaultAutoDetect[FrameTypeIndex]) {
+ IPX_DEBUG (ADAPTER, ("Default auto-detect changed from %d to %d\n",
+ FrameType, MappedFrameType));
+ Adapter->Bindings[MappedFrameType]->DefaultAutoDetect = TRUE;
+ }
+
+ IpxDestroyBinding (Binding);
+
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ IPX_DEBUG (ADAPTER, ("Using existing bind to adapter %ws, type %d\n",
+ Adapter->AdapterName,
+ MappedFrameType));
+ }
+#endif _PNP_POWER
+
+ //
+ // The local node address starts out the same as the
+ // MAC address of the adapter (on WAN this will change).
+ // The local MAC address can also change for WAN.
+ //
+
+ RtlCopyMemory (Binding->LocalAddress.NodeAddress, Adapter->LocalMacAddress.Address, 6);
+ RtlCopyMemory (Binding->LocalMacAddress.Address, Adapter->LocalMacAddress.Address, 6);
+
+
+ //
+ // Save the send handler.
+ //
+
+ Binding->SendFrameHandler = NULL;
+ Binding->FrameType = MappedFrameType;
+
+ //
+ // BUGBUG: Put this in InitializeBindingInfo.
+ //
+
+ switch (Adapter->MacInfo.RealMediumType) {
+ case NdisMedium802_3:
+ switch (MappedFrameType) {
+ case ISN_FRAME_TYPE_802_3: Binding->SendFrameHandler = IpxSendFrame802_3802_3; break;
+ case ISN_FRAME_TYPE_802_2: Binding->SendFrameHandler = IpxSendFrame802_3802_2; break;
+ case ISN_FRAME_TYPE_ETHERNET_II: Binding->SendFrameHandler = IpxSendFrame802_3EthernetII; break;
+ case ISN_FRAME_TYPE_SNAP: Binding->SendFrameHandler = IpxSendFrame802_3Snap; break;
+ }
+ break;
+ case NdisMedium802_5:
+ switch (MappedFrameType) {
+ case ISN_FRAME_TYPE_802_2: Binding->SendFrameHandler = IpxSendFrame802_5802_2; break;
+ case ISN_FRAME_TYPE_SNAP: Binding->SendFrameHandler = IpxSendFrame802_5Snap; break;
+ }
+ break;
+ case NdisMediumFddi:
+ switch (MappedFrameType) {
+ case ISN_FRAME_TYPE_802_3: Binding->SendFrameHandler = IpxSendFrameFddi802_3; break;
+ case ISN_FRAME_TYPE_802_2: Binding->SendFrameHandler = IpxSendFrameFddi802_2; break;
+ case ISN_FRAME_TYPE_SNAP: Binding->SendFrameHandler = IpxSendFrameFddiSnap; break;
+ }
+ break;
+ case NdisMediumArcnet878_2:
+ switch (MappedFrameType) {
+ case ISN_FRAME_TYPE_802_3: Binding->SendFrameHandler = IpxSendFrameArcnet878_2; break;
+ }
+ break;
+ case NdisMediumWan:
+ switch (MappedFrameType) {
+ case ISN_FRAME_TYPE_ETHERNET_II: Binding->SendFrameHandler = IpxSendFrameWanEthernetII; break;
+ }
+ break;
+ }
+
+ if (Binding->SendFrameHandler == NULL) {
+ DbgPrint ("BUGBUG!: SendFrameHandler is NULL\n");
+ }
+
+ Adapter->Bindings[MappedFrameType] = Binding;
+ ++Adapter->BindingCount;
+
+ Binding->Adapter = Adapter;
+
+#ifndef _PNP_POWER
+ InsertTailList (&Device->InitialBindingList, &Binding->InitialLinkage);
+#endif _PNP_POWER
+
+ //
+ // NicId and ExternalNicId will be filled in later when the binding
+ // is assigned a spot in the Device->Bindings array.
+ //
+
+ //
+ // Initialize the per-binding MAC information
+ //
+
+ if ((Adapter->ConfigMaxPacketSize == 0) ||
+ (Adapter->MaxSendPacketSize < Adapter->ConfigMaxPacketSize)) {
+ Binding->MaxSendPacketSize = Adapter->MaxSendPacketSize;
+ } else {
+ Binding->MaxSendPacketSize = Adapter->ConfigMaxPacketSize;
+ }
+ Binding->MediumSpeed = Adapter->MediumSpeed;
+ if (Adapter->MacInfo.MediumAsync) {
+ Binding->LineUp = FALSE;
+ } else {
+ Binding->LineUp = TRUE;
+ }
+
+ MacInitializeBindingInfo(
+ Binding,
+ Adapter);
+
+ return STATUS_SUCCESS;
+
+} /* IpxBindToAdapter */
+
+
+BOOLEAN
+IpxIsAddressLocal(
+ IN TDI_ADDRESS_IPX UNALIGNED * SourceAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns TRUE if the specified SourceAddress indicates
+ the packet was sent by us, and FALSE otherwise.
+
+Arguments:
+
+ SourceAddress - The source IPX address.
+
+Return Value:
+
+ TRUE if the address is local.
+
+--*/
+
+{
+ PBINDING Binding;
+ UINT i;
+
+ //
+ // First see if it is a virtual network address or not.
+ //
+
+ if (RtlEqualMemory (VirtualNode, SourceAddress->NodeAddress, 6)) {
+
+ //
+ // This is us if we have a virtual network configured.
+ // If we don't have a virtual node, we fall through to the
+ // other check -- an arcnet card configured as node 1 will
+ // have what we think of as the "virtual node" as its
+ // real node address.
+ //
+
+ if ((IpxDevice->VirtualNetwork) &&
+ (IpxDevice->VirtualNetworkNumber == SourceAddress->NetworkAddress)) {
+ return TRUE;
+ }
+
+ }
+
+ //
+ // Check through our list of adapters to see if one of
+ // them is the source node.
+ //
+ {
+ ULONG Index = MIN (IpxDevice->MaxBindings, IpxDevice->ValidBindings);
+
+ for (i = 1; i <= Index; i++) {
+#ifdef _PNP_POWER
+ if (((Binding = NIC_ID_TO_BINDING(IpxDevice, i)) != NULL) &&
+#else
+ if (((Binding = IpxDevice->Bindings[i]) != NULL) &&
+#endif _PNP_POWER
+ (RtlEqualMemory (Binding->LocalAddress.NodeAddress, SourceAddress->NodeAddress, 6))) {
+ return TRUE;
+ }
+ }
+ }
+
+ return FALSE;
+
+} /* IpxIsAddressLocal */
+
+
+NTSTATUS
+IpxUnBindFromAdapter(
+ IN PBINDING Binding
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles unbinding the transport from an
+ adapter. It can be called at any point during the life
+ of the transport.
+
+Arguments:
+
+ Binding - The adapter to unbind.
+
+Return Value:
+
+ The function value is the final status from the initialization operation.
+
+--*/
+
+{
+ PADAPTER Adapter = Binding->Adapter;
+
+ Adapter->Bindings[Binding->FrameType] = NULL;
+ --Adapter->BindingCount;
+
+ IpxDereferenceBinding (Binding, BREF_BOUND);
+
+ if (Adapter->BindingCount == 0) {
+
+ //
+ // DereferenceAdapter is a NULL macro for load-only.
+ //
+ // BUGBUG: Revisit Post 4.0
+ //
+#ifdef _PNP_LATER
+ //
+ // Take away the creation reference. When the in-use ref is taken off,
+ // we destroy this adapter.
+ //
+ IpxDereferenceAdapter(Adapter);
+#else
+ //
+ // Free the packet pools, etc. and close the
+ // adapter.
+ //
+
+ IpxCloseNdis (Adapter);
+
+ IpxDestroyAdapter (Adapter);
+#endif
+ }
+
+ return STATUS_SUCCESS;
+
+} /* IpxUnBindFromAdapter */
+
+
+VOID
+IpxUnload(
+ IN PDRIVER_OBJECT DriverObject
+ )
+
+/*++
+
+Routine Description:
+
+ This routine unloads the sample transport driver.
+ It unbinds from any NDIS drivers that are open and frees all resources
+ associated with the transport. The I/O system will not call us until
+ nobody above has IPX open.
+
+Arguments:
+
+ DriverObject - Pointer to driver object created by the system.
+
+Return Value:
+
+ None. When the function returns, the driver is unloaded.
+
+--*/
+
+{
+
+ PBINDING Binding;
+ PREQUEST Request;
+ PLIST_ENTRY p;
+ UINT i;
+
+
+ UNREFERENCED_PARAMETER (DriverObject);
+
+ IpxDevice->State = DEVICE_STATE_STOPPING;
+
+
+ //
+ // Complete any pending address notify requests.
+ //
+
+ while ((p = ExInterlockedRemoveHeadList(
+ &IpxDevice->AddressNotifyQueue,
+ &IpxDevice->Lock)) != NULL) {
+
+ Request = LIST_ENTRY_TO_REQUEST(p);
+ REQUEST_STATUS(Request) = STATUS_DEVICE_NOT_READY;
+ IpxCompleteRequest (Request);
+ IpxFreeRequest (IpxDevice, Request);
+
+ IpxDereferenceDevice (IpxDevice, DREF_ADDRESS_NOTIFY);
+ }
+
+
+ //
+ // Cancel the source routing timer if used.
+ //
+
+ if (IpxDevice->SourceRoutingUsed) {
+
+ IpxDevice->SourceRoutingUsed = FALSE;
+ if (CTEStopTimer (&IpxDevice->SourceRoutingTimer)) {
+ IpxDereferenceDevice (IpxDevice, DREF_SR_TIMER);
+ }
+ }
+
+
+ //
+ // Cancel the RIP long timer, and if we do that then
+ // send a RIP DOWN message if needed.
+ //
+
+ if (CTEStopTimer (&IpxDevice->RipLongTimer)) {
+
+ if (IpxDevice->RipResponder) {
+
+ if (RipQueueRequest (IpxDevice->VirtualNetworkNumber, RIP_DOWN) == STATUS_PENDING) {
+
+ //
+ // If we queue a request, it will stop the timer.
+ //
+
+ KeWaitForSingleObject(
+ &IpxDevice->UnloadEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+ }
+ }
+
+ IpxDereferenceDevice (IpxDevice, DREF_LONG_TIMER);
+
+ } else {
+
+ //
+ // We couldn't stop the timer, which means it is running,
+ // so we need to wait for the event that is kicked when
+ // the RIP DOWN messages are done.
+ //
+
+ if (IpxDevice->RipResponder) {
+
+ KeWaitForSingleObject(
+ &IpxDevice->UnloadEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+ }
+ }
+
+
+ //
+ // Walk the list of device contexts.
+ //
+
+ for (i = 1; i <= IpxDevice->BindingCount; i++) {
+#ifdef _PNP_POWER
+ if ((Binding = NIC_ID_TO_BINDING(IpxDevice, i)) != NULL) {
+ INSERT_BINDING(IpxDevice, i, NULL);
+#else
+ if (IpxDevice->Bindings[i] != NULL) {
+ Binding = IpxDevice->Bindings[i];
+ IpxDevice->Bindings[i] = NULL;
+#endif _PNP_POWER
+
+ IpxUnBindFromAdapter (Binding);
+
+ }
+
+ }
+
+#ifdef _PNP_POWER
+
+ IpxFreeMemory ( IpxDevice->Bindings,
+ IpxDevice->MaxBindings * sizeof(BIND_ARRAY_ELEM),
+ MEMORY_BINDING,
+ "Binding array");
+
+ //
+ // Deallocate the TdiRegistrationAddress and RegistryPathBuffer.
+ //
+ IpxFreeMemory ( IpxDevice->TdiRegistrationAddress,
+ (2 * sizeof(USHORT) + sizeof(TDI_ADDRESS_IPX)),
+ MEMORY_ADDRESS,
+ "Tdi Address");
+
+ IpxFreeMemory ( IpxDevice->RegistryPathBuffer,
+ IpxDevice->RegistryPath.Length + sizeof(WCHAR),
+ MEMORY_CONFIG,
+ "RegistryPathBuffer");
+
+#endif
+
+ KeResetEvent(
+ &IpxDevice->UnloadEvent
+ );
+ IpxDevice->UnloadWaiting = TRUE;
+
+ //
+ // Remove the reference for us being loaded.
+ //
+
+ IpxDereferenceDevice (IpxDevice, DREF_CREATE);
+
+ //
+ // Wait for our count to drop to zero.
+ //
+
+ KeWaitForSingleObject(
+ &IpxDevice->UnloadEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+
+ //
+ // Now free the padding buffer.
+ //
+
+ IpxFreePaddingBuffer (IpxDevice);
+
+ //
+ // Now do the cleanup that has to happen at IRQL 0.
+ //
+
+ ExDeleteResource (&IpxDevice->AddressResource);
+ IoDeleteDevice (IpxDevice->DeviceObject);
+
+ //
+ // Finally, remove ourselves as an NDIS protocol.
+ //
+
+ IpxDeregisterProtocol();
+
+} /* IpxUnload */
+
+
+NTSTATUS
+IpxDispatchOpenClose(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the main dispatch routine for the IPX device driver.
+ It accepts an I/O Request Packet, performs the request, and then
+ returns with the appropriate status.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ CTELockHandle LockHandle;
+ PDEVICE Device = IpxDevice;
+ NTSTATUS Status;
+ PFILE_FULL_EA_INFORMATION openType;
+ BOOLEAN found;
+ PADDRESS_FILE AddressFile;
+ PREQUEST Request;
+ UINT i;
+
+ ASSERT( DeviceObject->DeviceExtension == IpxDevice );
+
+#ifdef _PNP_POWER
+ if ((Device->State == DEVICE_STATE_CLOSED) ||
+ (Device->State == DEVICE_STATE_STOPPING)) {
+ Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+#else
+ if (Device->State != DEVICE_STATE_OPEN) {
+ Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+#endif
+ //
+ // Allocate a request to track this IRP.
+ //
+
+ Request = IpxAllocateRequest (Device, Irp);
+ IF_NOT_ALLOCATED(Request) {
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // Make sure status information is consistent every time.
+ //
+
+ MARK_REQUEST_PENDING(Request);
+ REQUEST_STATUS(Request) = STATUS_PENDING;
+ REQUEST_INFORMATION(Request) = 0;
+
+ //
+ // Case on the function that is being performed by the requestor. If the
+ // operation is a valid one for this device, then make it look like it was
+ // successfully completed, where possible.
+ //
+
+
+ switch (REQUEST_MAJOR_FUNCTION(Request)) {
+
+ //
+ // The Create function opens a transport object (either address or
+ // connection). Access checking is performed on the specified
+ // address to ensure security of transport-layer addresses.
+ //
+
+ case IRP_MJ_CREATE:
+
+ openType = OPEN_REQUEST_EA_INFORMATION(Request);
+
+ if (openType != NULL) {
+
+ found = TRUE;
+
+ for (i=0;i<openType->EaNameLength;i++) {
+ if (openType->EaName[i] == TdiTransportAddress[i]) {
+ continue;
+ } else {
+ found = FALSE;
+ break;
+ }
+ }
+
+ if (found) {
+ Status = IpxOpenAddress (Device, Request);
+ break;
+ }
+
+ //
+ // Connection?
+ //
+
+ found = TRUE;
+
+ for (i=0;i<openType->EaNameLength;i++) {
+ if (openType->EaName[i] == TdiConnectionContext[i]) {
+ continue;
+ } else {
+ found = FALSE;
+ break;
+ }
+ }
+
+ if (found) {
+ Status = STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ } else {
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ //
+ // LowPart is in the OPEN_CONTEXT directly.
+ // HighPart goes into the upper 2 bytes of the OPEN_TYPE.
+ //
+ REQUEST_OPEN_CONTEXT(Request) = (PVOID)(Device->ControlChannelIdentifier.LowPart);
+
+ (ULONG)(REQUEST_OPEN_TYPE(Request)) = (Device->ControlChannelIdentifier.HighPart << 16);
+ (ULONG)(REQUEST_OPEN_TYPE(Request)) |= IPX_FILE_TYPE_CONTROL;
+
+ ++(Device->ControlChannelIdentifier.QuadPart);
+
+ if (Device->ControlChannelIdentifier.QuadPart > MAX_CCID) {
+ Device->ControlChannelIdentifier.QuadPart = 1;
+ }
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ Status = STATUS_SUCCESS;
+ }
+
+ break;
+
+ case IRP_MJ_CLOSE:
+
+ //
+ // The Close function closes a transport endpoint, terminates
+ // all outstanding transport activity on the endpoint, and unbinds
+ // the endpoint from its transport address, if any. If this
+ // is the last transport endpoint bound to the address, then
+ // the address is removed from the provider.
+ //
+
+ switch ((ULONG)(REQUEST_OPEN_TYPE(Request)) & IPX_CC_MASK) {
+ case TDI_TRANSPORT_ADDRESS_FILE:
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+
+ //
+ // This creates a reference to AddressFile->Address
+ // which is removed by IpxCloseAddressFile.
+ //
+
+ Status = IpxVerifyAddressFile(AddressFile);
+
+ if (!NT_SUCCESS (Status)) {
+ Status = STATUS_INVALID_HANDLE;
+ } else {
+ Status = IpxCloseAddressFile (Device, Request);
+ IpxDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+
+ }
+
+ break;
+
+ case IPX_FILE_TYPE_CONTROL:
+ {
+ LARGE_INTEGER ControlChannelId;
+
+ CCID_FROM_REQUEST(ControlChannelId, Request);
+
+ //
+ // See if it is one of the upper driver's control channels.
+ //
+
+ Status = STATUS_SUCCESS;
+
+ IPX_DEBUG (DEVICE, ("CCID: (%d, %d)\n", ControlChannelId.HighPart, ControlChannelId.LowPart));
+
+ for (i = 0; i < UPPER_DRIVER_COUNT; i++) {
+ if (Device->UpperDriverControlChannel[i].QuadPart ==
+ ControlChannelId.QuadPart) {
+ Status = IpxInternalUnbind (Device, i);
+ break;
+ }
+ }
+
+ break;
+ }
+ default:
+ Status = STATUS_INVALID_HANDLE;
+ }
+
+ break;
+
+ case IRP_MJ_CLEANUP:
+
+ //
+ // Handle the two stage IRP for a file close operation. When the first
+ // stage hits, run down all activity on the object of interest. This
+ // do everything to it but remove the creation hold. Then, when the
+ // CLOSE irp hits, actually close the object.
+ //
+
+ switch ((ULONG)(REQUEST_OPEN_TYPE(Request)) & IPX_CC_MASK) {
+ case TDI_TRANSPORT_ADDRESS_FILE:
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+ Status = IpxVerifyAddressFile(AddressFile);
+ if (!NT_SUCCESS (Status)) {
+
+ Status = STATUS_INVALID_HANDLE;
+
+ } else {
+
+ IpxStopAddressFile (AddressFile);
+ IpxDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+ Status = STATUS_SUCCESS;
+ }
+
+ break;
+
+ case IPX_FILE_TYPE_CONTROL:
+ {
+ LARGE_INTEGER ControlChannelId;
+
+ CCID_FROM_REQUEST(ControlChannelId, Request);
+
+ //
+ // Check for any line change IRPs submitted by this
+ // address.
+ //
+
+ IpxAbortLineChanges ((PVOID)&ControlChannelId);
+
+ Status = STATUS_SUCCESS;
+ break;
+ }
+ default:
+ Status = STATUS_INVALID_HANDLE;
+ }
+
+ break;
+
+ default:
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+
+ } /* major function switch */
+
+ if (Status != STATUS_PENDING) {
+ UNMARK_REQUEST_PENDING(Request);
+ REQUEST_STATUS(Request) = Status;
+ IpxCompleteRequest (Request);
+ IpxFreeRequest (Device, Request);
+ }
+
+ //
+ // Return the immediate status code to the caller.
+ //
+
+ return Status;
+
+} /* IpxDispatchOpenClose */
+
+#define IOCTL_IPX_LOAD_SPX _IPX_CONTROL_CODE( 0x5678, METHOD_BUFFERED )
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+ZwLoadDriver(
+ IN PUNICODE_STRING DriverServiceName
+ );
+
+
+NTSTATUS
+IpxDispatchDeviceControl(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dispatches TDI request types to different handlers based
+ on the minor IOCTL function code in the IRP's current stack location.
+ In addition to cracking the minor function code, this routine also
+ reaches into the IRP and passes the packetized parameters stored there
+ as parameters to the various TDI request handlers so that they are
+ not IRP-dependent.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PDEVICE Device = IpxDevice;
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation (Irp);
+ static NDIS_STRING SpxServiceName = NDIS_STRING_CONST ("\\Registry\\Machine\\System\\CurrentControlSet\\Services\\NwlnkSpx");
+
+ ASSERT( DeviceObject->DeviceExtension == IpxDevice );
+
+ //
+ // Branch to the appropriate request handler. Preliminary checking of
+ // the size of the request block is performed here so that it is known
+ // in the handlers that the minimum input parameters are readable. It
+ // is *not* determined here whether variable length input fields are
+ // passed correctly; this is a check which must be made within each routine.
+ //
+
+ switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
+
+ case IOCTL_TDI_QUERY_DIRECT_SENDDG_HANDLER: {
+
+ PULONG EntryPoint;
+
+ //
+ // This is the LanmanServer trying to get the send
+ // entry point.
+ //
+
+ IPX_DEBUG (BIND, ("Direct send entry point being returned\n"));
+
+ EntryPoint = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
+ *EntryPoint = (ULONG)IpxTdiSendDatagram;
+
+ Status = STATUS_SUCCESS;
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ break;
+ }
+
+ case IOCTL_IPX_INTERNAL_BIND:
+
+ //
+ // This is a client trying to bind.
+ //
+
+ CTEAssert ((IOCTL_IPX_INTERNAL_BIND & 0x3) == METHOD_BUFFERED);
+ CTEAssert (IrpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL);
+
+#ifdef _PNP_POWER
+
+ if ((Device->State == DEVICE_STATE_CLOSED) ||
+ (Device->State == DEVICE_STATE_STOPPING)) {
+#else
+ if (Device->State != DEVICE_STATE_OPEN) {
+#endif
+ Status = STATUS_INVALID_DEVICE_STATE;
+
+ } else {
+
+ Status = IpxInternalBind (Device, Irp);
+
+ }
+
+ CTEAssert (Status != STATUS_PENDING);
+
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+
+ break;
+
+ case IOCTL_IPX_LOAD_SPX:
+
+ //
+ // The SPX helper dll is asking us to load SPX.
+ //
+
+ Status = ZwLoadDriver (&SpxServiceName);
+
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+
+ break;
+
+ default:
+
+ //
+ // Convert the user call to the proper internal device call.
+ //
+
+ Status = TdiMapUserRequest (DeviceObject, Irp, IrpSp);
+
+ if (Status == STATUS_SUCCESS) {
+
+ //
+ // If TdiMapUserRequest returns SUCCESS then the IRP
+ // has been converted into an IRP_MJ_INTERNAL_DEVICE_CONTROL
+ // IRP, so we dispatch it as usual. The IRP will
+ // be completed by this call.
+ //
+
+ Status = IpxDispatchInternal (DeviceObject, Irp);
+
+ } else {
+
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+
+ }
+
+ break;
+ }
+ return Status;
+
+} /* IpxDispatchDeviceControl */
+
+
+NTSTATUS
+IpxDispatchInternal (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dispatches TDI request types to different handlers based
+ on the minor IOCTL function code in the IRP's current stack location.
+ In addition to cracking the minor function code, this routine also
+ reaches into the IRP and passes the packetized parameters stored there
+ as parameters to the various TDI request handlers so that they are
+ not IRP-dependent.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PDEVICE Device = IpxDevice;
+ PREQUEST Request;
+
+ ASSERT( DeviceObject->DeviceExtension == IpxDevice );
+
+ if (Device->State == DEVICE_STATE_OPEN) {
+
+ //
+ // Allocate a request to track this IRP.
+ //
+
+ Request = IpxAllocateRequest (Device, Irp);
+
+ IF_NOT_ALLOCATED(Request) {
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // Make sure status information is consistent every time.
+ //
+
+ MARK_REQUEST_PENDING(Request);
+#if DBG
+ REQUEST_STATUS(Request) = STATUS_PENDING;
+ REQUEST_INFORMATION(Request) = 0;
+#endif
+
+ //
+ // Branch to the appropriate request handler. Preliminary checking of
+ // the size of the request block is performed here so that it is known
+ // in the handlers that the minimum input parameters are readable. It
+ // is *not* determined here whether variable length input fields are
+ // passed correctly; this is a check which must be made within each routine.
+ //
+
+ switch (REQUEST_MINOR_FUNCTION(Request)) {
+
+ case TDI_SEND_DATAGRAM:
+ Status = IpxTdiSendDatagram (DeviceObject, Request);
+ break;
+
+ case TDI_ACTION:
+ Status = IpxTdiAction (Device, Request);
+ break;
+
+ case TDI_QUERY_INFORMATION:
+ Status = IpxTdiQueryInformation (Device, Request);
+ break;
+
+ case TDI_RECEIVE_DATAGRAM:
+ Status = IpxTdiReceiveDatagram (Request);
+ break;
+
+ case TDI_SET_EVENT_HANDLER:
+ Status = IpxTdiSetEventHandler (Request);
+ break;
+
+ case TDI_SET_INFORMATION:
+ Status = IpxTdiSetInformation (Device, Request);
+ break;
+
+
+ //
+ // Something we don't know about was submitted.
+ //
+
+ default:
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+ }
+
+ //
+ // Return the immediate status code to the caller.
+ //
+
+ if (Status == STATUS_PENDING) {
+
+ return STATUS_PENDING;
+
+ } else {
+
+ UNMARK_REQUEST_PENDING(Request);
+ REQUEST_STATUS(Request) = Status;
+ IpxCompleteRequest (Request);
+ IpxFreeRequest (Device, Request);
+ return Status;
+ }
+
+ } else {
+
+ //
+ // The device was not open.
+ //
+
+ Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+} /* IpxDispatchInternal */
+
+
+PVOID
+IpxpAllocateMemory(
+ IN ULONG BytesNeeded,
+ IN ULONG Tag,
+ IN BOOLEAN ChargeDevice
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates memory, making sure it is within
+ the limit allowed by the device.
+
+Arguments:
+
+ BytesNeeded - The number of bytes to allocated.
+
+ ChargeDevice - TRUE if the device should be charged.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PVOID Memory;
+ PDEVICE Device = IpxDevice;
+
+ if (ChargeDevice) {
+ if ((Device->MemoryLimit != 0) &&
+ (((LONG)(Device->MemoryUsage + BytesNeeded) >
+ Device->MemoryLimit))) {
+
+ IpxPrint1 ("IPX: Could not allocate %d: limit\n", BytesNeeded);
+ IpxWriteResourceErrorLog(
+ Device->DeviceObject,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ BytesNeeded,
+ Tag);
+
+ return NULL;
+ }
+ }
+
+#if ISN_NT
+ Memory = ExAllocatePoolWithTag (NonPagedPool, BytesNeeded, ' XPI');
+#else
+ Memory = CTEAllocMem (BytesNeeded);
+#endif
+
+ if (Memory == NULL) {
+
+ IpxPrint1("IPX: Could not allocate %d: no pool\n", BytesNeeded);
+ if (ChargeDevice) {
+ IpxWriteResourceErrorLog(
+ Device->DeviceObject,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ BytesNeeded,
+ Tag);
+ }
+
+ return NULL;
+ }
+
+ if (ChargeDevice) {
+ Device->MemoryUsage += BytesNeeded;
+ }
+
+ return Memory;
+} /* IpxpAllocateMemory */
+
+
+VOID
+IpxpFreeMemory(
+ IN PVOID Memory,
+ IN ULONG BytesAllocated,
+ IN BOOLEAN ChargeDevice
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees memory allocated with IpxpAllocateMemory.
+
+Arguments:
+
+ Memory - The memory allocated.
+
+ BytesAllocated - The number of bytes to freed.
+
+ ChargeDevice - TRUE if the device should be charged.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = IpxDevice;
+
+#if ISN_NT
+ ExFreePool (Memory);
+#else
+ CTEFreeMem (Memory);
+#endif
+ if (ChargeDevice) {
+ Device->MemoryUsage -= BytesAllocated;
+ }
+
+} /* IpxpFreeMemory */
+
+#if DBG
+
+
+PVOID
+IpxpAllocateTaggedMemory(
+ IN ULONG BytesNeeded,
+ IN ULONG Tag,
+ IN PUCHAR Description
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates memory, charging it to the device.
+ If it cannot allocate memory it uses the Tag and Descriptor
+ to log an error.
+
+Arguments:
+
+ BytesNeeded - The number of bytes to allocated.
+
+ Tag - A unique ID used in the error log.
+
+ Description - A text description of the allocation.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PVOID Memory;
+
+ UNREFERENCED_PARAMETER(Description);
+
+ Memory = IpxpAllocateMemory(BytesNeeded, Tag, (BOOLEAN)(Tag != MEMORY_CONFIG));
+
+ if (Memory) {
+ (VOID)IPX_ADD_ULONG(
+ &IpxMemoryTag[Tag].BytesAllocated,
+ BytesNeeded,
+ &IpxMemoryInterlock);
+ }
+
+ return Memory;
+
+} /* IpxpAllocateTaggedMemory */
+
+
+VOID
+IpxpFreeTaggedMemory(
+ IN PVOID Memory,
+ IN ULONG BytesAllocated,
+ IN ULONG Tag,
+ IN PUCHAR Description
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees memory allocated with IpxpAllocateTaggedMemory.
+
+Arguments:
+
+ Memory - The memory allocated.
+
+ BytesAllocated - The number of bytes to freed.
+
+ Tag - A unique ID used in the error log.
+
+ Description - A text description of the allocation.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ UNREFERENCED_PARAMETER(Description);
+
+ (VOID)IPX_ADD_ULONG(
+ &IpxMemoryTag[Tag].BytesAllocated,
+ (ULONG)(-(LONG)BytesAllocated),
+ &IpxMemoryInterlock);
+
+ IpxpFreeMemory (Memory, BytesAllocated, (BOOLEAN)(Tag != MEMORY_CONFIG));
+
+} /* IpxpFreeTaggedMemory */
+
+#endif
+
+
+VOID
+IpxWriteResourceErrorLog(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN NTSTATUS ErrorCode,
+ IN ULONG BytesNeeded,
+ IN ULONG UniqueErrorValue
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and writes an error log entry which has
+ a %3 value that needs to be converted to a string. It is currently
+ used for EVENT_TRANSPORT_RESOURCE_POOL and EVENT_IPX_INTERNAL_NET_
+ INVALID.
+
+Arguments:
+
+ DeviceObject - Pointer to the system device object.
+
+ ErrorCode - The transport event code.
+
+ BytesNeeded - If applicable, the number of bytes that could not
+ be allocated -- will be put in the dump data.
+
+ UniqueErrorValue - Used as the UniqueErrorValue in the error log
+ packet and converted for use as the %3 string.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ UCHAR EntrySize;
+ PUCHAR StringLoc;
+ ULONG TempUniqueError;
+ PDEVICE Device = IpxDevice;
+ static WCHAR UniqueErrorBuffer[9] = L"00000000";
+ UINT CurrentDigit;
+ INT i;
+
+
+ //
+ // Convert the error value into a buffer.
+ //
+
+ TempUniqueError = UniqueErrorValue;
+ i = 8;
+ do {
+ CurrentDigit = TempUniqueError & 0xf;
+ TempUniqueError >>= 4;
+ i--;
+ if (CurrentDigit >= 0xa) {
+ UniqueErrorBuffer[i] = (WCHAR)(CurrentDigit - 0xa + L'A');
+ } else {
+ UniqueErrorBuffer[i] = (WCHAR)(CurrentDigit + L'0');
+ }
+ } while (TempUniqueError);
+
+
+ EntrySize = sizeof(IO_ERROR_LOG_PACKET) +
+ Device->DeviceNameLength +
+ sizeof(UniqueErrorBuffer) - (i * sizeof(WCHAR));
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ DeviceObject,
+ EntrySize
+ );
+
+ if (errorLogEntry != NULL) {
+
+ errorLogEntry->MajorFunctionCode = (UCHAR)-1;
+ errorLogEntry->RetryCount = (UCHAR)-1;
+ errorLogEntry->DumpDataSize = sizeof(ULONG);
+ errorLogEntry->NumberOfStrings = 2;
+ errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET);
+ errorLogEntry->EventCategory = 0;
+ errorLogEntry->ErrorCode = ErrorCode;
+ errorLogEntry->UniqueErrorValue = UniqueErrorValue;
+ errorLogEntry->FinalStatus = STATUS_INSUFFICIENT_RESOURCES;
+ errorLogEntry->SequenceNumber = (ULONG)-1;
+ errorLogEntry->IoControlCode = 0;
+ errorLogEntry->DumpData[0] = BytesNeeded;
+
+ StringLoc = ((PUCHAR)errorLogEntry) + errorLogEntry->StringOffset;
+ RtlCopyMemory (StringLoc, Device->DeviceName, Device->DeviceNameLength);
+
+ StringLoc += Device->DeviceNameLength;
+ RtlCopyMemory (StringLoc, UniqueErrorBuffer + i, sizeof(UniqueErrorBuffer) - (i * sizeof(WCHAR)));
+
+ IoWriteErrorLogEntry(errorLogEntry);
+
+ }
+
+} /* IpxWriteResourceErrorLog */
+
+
+VOID
+IpxWriteGeneralErrorLog(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN NTSTATUS ErrorCode,
+ IN ULONG UniqueErrorValue,
+ IN NTSTATUS FinalStatus,
+ IN PWSTR SecondString,
+ IN ULONG DumpDataCount,
+ IN ULONG DumpData[]
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and writes an error log entry indicating
+ a general problem as indicated by the parameters. It handles
+ event codes REGISTER_FAILED, BINDING_FAILED, ADAPTER_NOT_FOUND,
+ TRANSFER_DATA, TOO_MANY_LINKS, and BAD_PROTOCOL. All these
+ events have messages with one or two strings in them.
+
+Arguments:
+
+ DeviceObject - Pointer to the system device object, or this may be
+ a driver object instead.
+
+ ErrorCode - The transport event code.
+
+ UniqueErrorValue - Used as the UniqueErrorValue in the error log
+ packet.
+
+ FinalStatus - Used as the FinalStatus in the error log packet.
+
+ SecondString - If not NULL, the string to use as the %3
+ value in the error log packet.
+
+ DumpDataCount - The number of ULONGs of dump data.
+
+ DumpData - Dump data for the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ UCHAR EntrySize;
+ ULONG SecondStringSize;
+ PUCHAR StringLoc;
+ PDEVICE Device = IpxDevice;
+ static WCHAR DriverName[9] = L"NwlnkIpx";
+
+ EntrySize = sizeof(IO_ERROR_LOG_PACKET) +
+ (DumpDataCount * sizeof(ULONG));
+
+ if (DeviceObject->Type == IO_TYPE_DEVICE) {
+ EntrySize += (UCHAR)Device->DeviceNameLength;
+ } else {
+ EntrySize += sizeof(DriverName);
+ }
+
+ if (SecondString) {
+ SecondStringSize = (wcslen(SecondString)*sizeof(WCHAR)) + sizeof(UNICODE_NULL);
+ EntrySize += (UCHAR)SecondStringSize;
+ }
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ DeviceObject,
+ EntrySize
+ );
+
+ if (errorLogEntry != NULL) {
+
+ errorLogEntry->MajorFunctionCode = (UCHAR)-1;
+ errorLogEntry->RetryCount = (UCHAR)-1;
+ errorLogEntry->DumpDataSize = (USHORT)(DumpDataCount * sizeof(ULONG));
+ errorLogEntry->NumberOfStrings = (SecondString == NULL) ? 1 : 2;
+ errorLogEntry->StringOffset =
+ sizeof(IO_ERROR_LOG_PACKET) + ((DumpDataCount-1) * sizeof(ULONG));
+ errorLogEntry->EventCategory = 0;
+ errorLogEntry->ErrorCode = ErrorCode;
+ errorLogEntry->UniqueErrorValue = UniqueErrorValue;
+ errorLogEntry->FinalStatus = FinalStatus;
+ errorLogEntry->SequenceNumber = (ULONG)-1;
+ errorLogEntry->IoControlCode = 0;
+
+ if (DumpDataCount) {
+ RtlCopyMemory(errorLogEntry->DumpData, DumpData, DumpDataCount * sizeof(ULONG));
+ }
+
+ StringLoc = ((PUCHAR)errorLogEntry) + errorLogEntry->StringOffset;
+ if (DeviceObject->Type == IO_TYPE_DEVICE) {
+ RtlCopyMemory (StringLoc, Device->DeviceName, Device->DeviceNameLength);
+ StringLoc += Device->DeviceNameLength;
+ } else {
+ RtlCopyMemory (StringLoc, DriverName, sizeof(DriverName));
+ StringLoc += sizeof(DriverName);
+ }
+ if (SecondString) {
+ RtlCopyMemory (StringLoc, SecondString, SecondStringSize);
+ }
+
+ IoWriteErrorLogEntry(errorLogEntry);
+
+ }
+
+} /* IpxWriteGeneralErrorLog */
+
+
+VOID
+IpxWriteOidErrorLog(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN NTSTATUS ErrorCode,
+ IN NTSTATUS FinalStatus,
+ IN PWSTR AdapterString,
+ IN ULONG OidValue
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and writes an error log entry indicating
+ a problem querying or setting an OID on an adapter. It handles
+ event codes SET_OID_FAILED and QUERY_OID_FAILED.
+
+Arguments:
+
+ DeviceObject - Pointer to the system device object.
+
+ ErrorCode - Used as the ErrorCode in the error log packet.
+
+ FinalStatus - Used as the FinalStatus in the error log packet.
+
+ AdapterString - The name of the adapter we were bound to.
+
+ OidValue - The OID which could not be set or queried.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ UCHAR EntrySize;
+ ULONG AdapterStringSize;
+ PUCHAR StringLoc;
+ PDEVICE Device = IpxDevice;
+ static WCHAR OidBuffer[9] = L"00000000";
+ INT i;
+ UINT CurrentDigit;
+
+ AdapterStringSize = (wcslen(AdapterString)*sizeof(WCHAR)) + sizeof(UNICODE_NULL);
+ EntrySize = sizeof(IO_ERROR_LOG_PACKET) -
+ sizeof(ULONG) +
+ Device->DeviceNameLength +
+ AdapterStringSize +
+ sizeof(OidBuffer);
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ DeviceObject,
+ EntrySize
+ );
+
+ //
+ // Convert the OID into a buffer.
+ //
+
+ for (i=7; i>=0; i--) {
+ CurrentDigit = OidValue & 0xf;
+ OidValue >>= 4;
+ if (CurrentDigit >= 0xa) {
+ OidBuffer[i] = (WCHAR)(CurrentDigit - 0xa + L'A');
+ } else {
+ OidBuffer[i] = (WCHAR)(CurrentDigit + L'0');
+ }
+ }
+
+ if (errorLogEntry != NULL) {
+
+ errorLogEntry->MajorFunctionCode = (UCHAR)-1;
+ errorLogEntry->RetryCount = (UCHAR)-1;
+ errorLogEntry->DumpDataSize = 0;
+ errorLogEntry->NumberOfStrings = 3;
+ errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET) - sizeof(ULONG);
+ errorLogEntry->EventCategory = 0;
+ errorLogEntry->ErrorCode = ErrorCode;
+ errorLogEntry->UniqueErrorValue = 0;
+ errorLogEntry->FinalStatus = FinalStatus;
+ errorLogEntry->SequenceNumber = (ULONG)-1;
+ errorLogEntry->IoControlCode = 0;
+
+ StringLoc = ((PUCHAR)errorLogEntry) + errorLogEntry->StringOffset;
+ RtlCopyMemory (StringLoc, Device->DeviceName, Device->DeviceNameLength);
+ StringLoc += Device->DeviceNameLength;
+
+ RtlCopyMemory (StringLoc, OidBuffer, sizeof(OidBuffer));
+ StringLoc += sizeof(OidBuffer);
+
+ RtlCopyMemory (StringLoc, AdapterString, AdapterStringSize);
+
+ IoWriteErrorLogEntry(errorLogEntry);
+
+ }
+
+} /* IpxWriteOidErrorLog */
+
+
+#ifdef _PNP_POWER
+VOID
+IpxPnPUpdateDevice(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ Updates datagram sizes, lookahead sizes, etc. in the Device as a result
+ of a new binding coming in.
+
+Arguments:
+
+ Device - The IPX device object.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ULONG AnnouncedMaxDatagram, RealMaxDatagram, MaxLookahead;
+ ULONG LinkSpeed, MacOptions;
+ ULONG i;
+ PBINDING Binding;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+
+ IPX_GET_LOCK(&Device->BindAccessLock, &LockHandle);
+
+ //
+ // Calculate some values based on all the bindings.
+ //
+
+ MaxLookahead = NIC_ID_TO_BINDING_NO_ILOCK(Device, 1)->MaxLookaheadData; // largest binding value
+ AnnouncedMaxDatagram = NIC_ID_TO_BINDING_NO_ILOCK(Device, 1)->AnnouncedMaxDatagramSize; // smallest binding value
+ RealMaxDatagram = NIC_ID_TO_BINDING_NO_ILOCK(Device, 1)->RealMaxDatagramSize; // smallest binding value
+
+ if (NIC_ID_TO_BINDING_NO_ILOCK(Device, 1)->LineUp) {
+ LinkSpeed = NIC_ID_TO_BINDING_NO_ILOCK(Device, 1)->MediumSpeed; // smallest binding value
+ } else {
+ LinkSpeed = 0xffffffff;
+ }
+ MacOptions = NIC_ID_TO_BINDING_NO_ILOCK(Device, 1)->Adapter->MacInfo.MacOptions; // AND of binding values
+
+ for (i = 2; i <= Device->ValidBindings; i++) {
+
+ Binding = NIC_ID_TO_BINDING_NO_ILOCK(Device, i);
+
+ if (!Binding) {
+ continue;
+ }
+
+ if (Binding->MaxLookaheadData > MaxLookahead) {
+ MaxLookahead = Binding->MaxLookaheadData;
+ }
+ if (Binding->AnnouncedMaxDatagramSize < AnnouncedMaxDatagram) {
+ AnnouncedMaxDatagram = Binding->AnnouncedMaxDatagramSize;
+ }
+ if (Binding->RealMaxDatagramSize < RealMaxDatagram) {
+ RealMaxDatagram = Binding->RealMaxDatagramSize;
+ }
+
+ if (Binding->LineUp && (Binding->MediumSpeed < LinkSpeed)) {
+ LinkSpeed = Binding->MediumSpeed;
+ }
+ MacOptions &= Binding->Adapter->MacInfo.MacOptions;
+
+ }
+
+ Device->Information.MaxDatagramSize = AnnouncedMaxDatagram;
+ Device->RealMaxDatagramSize = RealMaxDatagram;
+ Device->Information.MaximumLookaheadData = MaxLookahead;
+
+ //
+ // If we couldn't find anything better, use the speed from
+ // the first binding.
+ //
+
+ if (LinkSpeed == 0xffffffff) {
+ Device->LinkSpeed = NIC_ID_TO_BINDING_NO_ILOCK(Device, 1)->MediumSpeed;
+ } else {
+ Device->LinkSpeed = LinkSpeed;
+ }
+ Device->MacOptions = MacOptions;
+
+ IPX_FREE_LOCK(&Device->BindAccessLock, LockHandle);
+}
+
+VOID
+IpxPnPUpdateBindingArray(
+ IN PDEVICE Device,
+ IN PADAPTER Adapter,
+ IN PBINDING_CONFIG ConfigBinding
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to update the binding array to
+ add the new bindings that appeared in this PnP event.
+ The order of bindings in the array is as follows:
+
+ - First comes the first binding to each LAN network
+ - Following that are all WAN bindings
+ - Following that are any duplicate bindings to LAN networks
+ (the others in the "binding set").
+
+ This routine inserts the bindings while maintaining this
+ order by resolving binding sets.
+
+ The bindings are also inserted into the RIP database.
+
+ If "global wan net" is true we will advertise up to
+ and including the first wan binding as the highest nic
+ id; otherwise we advertise up to and including the last
+ wan binding. In all cases the duplicate bindings are
+ hidden.
+
+ Updates the SapNicCount, Device->FirstLanNicId and Device->FirstWanNicId
+
+Arguments:
+
+ Device - The IPX device object.
+
+ Adapter - The adapter added in this PnP event
+
+ ValidBindings - the number of bindings valid for this adapter (if LAN)
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ULONG i, j;
+ PBINDING Binding, MasterBinding;
+ NTSTATUS status;
+
+ //
+ // Insert in proper place; if WAN, after all the WAN bindings
+ // If LAN, check for binding sets and insert in proper place
+ // Also, insert into the Rip Tables.
+ //
+
+ //
+ // Go thru' the bindings for this adapter, inserting into the
+ // binding array in place
+ //
+ for (i = 0; i < ConfigBinding->FrameTypeCount; i++) {
+ ULONG MappedFrameType;
+
+ //
+ // Store in the preference order.
+ // Map the frame types since we could have a case where the user selects a FrameType (say, EthernetII on FDDI)
+ // which maps to a different FrameType (802.2). Then we would fail to find the binding in the adapter array;
+ // we could potentialy add a binding twice (if two frame types map to the same Frame, then we would go to the
+ // mapped one twice). This is taken care of by purging dups from the ConfigBinding->FrameType array when we
+ // create the bindings off of the Adapter (see call to IpxBindToAdapter).
+ //
+
+ MacMapFrameType(
+ Adapter->MacInfo.RealMediumType,
+ ConfigBinding->FrameType[i],
+ &MappedFrameType);
+
+ Binding = Adapter->Bindings[MappedFrameType];
+
+ if (!Binding){
+ continue;
+ }
+
+ CTEAssert(Binding->FrameType == MappedFrameType);
+
+ if (Adapter->MacInfo.MediumAsync) {
+ //
+ // WAN: Place after the HighestExternalNicId, with space for WanLine # of bindings.
+ // Update the First/LastWanNicId.
+ //
+ Adapter->FirstWanNicId = (USHORT)Device->HighestExternalNicId+1;
+ Adapter->LastWanNicId = (USHORT)(Device->HighestExternalNicId + Adapter->WanNicIdCount);
+
+ //
+ // Make sure we dont overflow the array
+ // Re-alloc the array to fit the new bindings
+ //
+ if (Device->ValidBindings+Adapter->WanNicIdCount >= Device->MaxBindings) {
+ status = IpxPnPReallocateBindingArray(Device, Adapter->WanNicIdCount);
+ CTEAssert(status == STATUS_SUCCESS);
+ }
+
+ //
+ // Move Slaves down by WanNicIdCount# of entries
+ //
+ for (j = Device->ValidBindings; j > Device->HighestExternalNicId; j--) {
+ INSERT_BINDING(Device, j+Adapter->WanNicIdCount, NIC_ID_TO_BINDING_NO_ILOCK(Device, j));
+ if (NIC_ID_TO_BINDING_NO_ILOCK(Device, j+Adapter->WanNicIdCount)) {
+ NIC_ID_TO_BINDING_NO_ILOCK(Device, j+Adapter->WanNicIdCount)->NicId += (USHORT)Adapter->WanNicIdCount;
+ }
+ }
+
+ //
+ // Insert the WAN binding in the place just allocated
+ //
+ INSERT_BINDING(Device, Device->HighestExternalNicId+1, Binding);
+ SET_VERSION(Device, Device->HighestExternalNicId+1);
+
+ Binding->NicId = (USHORT)Device->HighestExternalNicId+1;
+
+ //
+ // Update the indices
+ //
+ Device->HighestExternalNicId += (USHORT)Adapter->WanNicIdCount;
+ Device->ValidBindings += (USHORT)Adapter->WanNicIdCount;
+ Device->BindingCount += (USHORT)Adapter->WanNicIdCount;
+ Device->SapNicCount++;
+
+ //
+ // Since we initialize FirstWanNicId to 1, we need to compare against that.
+ // In case of no LAN bindings, we are fine since we have only one WAN binding initally
+ // (all the other WAN lines have place holders).
+ //
+ if (Device->FirstWanNicId == (USHORT)1) {
+ Device->FirstWanNicId = Binding->NicId;
+ }
+
+ //
+ // BUGBUGZZ Make this inline later
+ //
+ // This should be done after all the auto-detect bindings have been thrown away.
+ //
+ // IpxPnPUpdateDevice(Device, Binding);
+
+ //
+ // Since WAN can have only one frame type, break
+ //
+ break;
+
+ } else {
+
+ Device->BindingCount++;
+
+ //
+ // Make sure we dont overflow the array
+ // Re-alloc the array to fit the new bindings
+ //
+ if (Device->ValidBindings+1 >= Device->MaxBindings) {
+ status = IpxPnPReallocateBindingArray(Device, 1);
+ CTEAssert(status == STATUS_SUCCESS);
+ }
+
+ //
+ // LAN: Figure out if it is a slave binding only for non-auto-detect bindings.
+ //
+ {
+ ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
+
+ for (j = 1; j < Index; j++) {
+ MasterBinding = NIC_ID_TO_BINDING_NO_ILOCK(Device, j);
+ if ((MasterBinding->ConfiguredNetworkNumber) &&
+ (MasterBinding->ConfiguredNetworkNumber == Binding->ConfiguredNetworkNumber) &&
+ (MasterBinding->FrameType == Binding->FrameType) &&
+ (MasterBinding->Adapter->MacInfo.MediumType == Binding->Adapter->MacInfo.MediumType)) {
+
+ CTEAssert(Binding->ConfiguredNetworkNumber);
+ break;
+ }
+ }
+ }
+
+ if (j < Device->HighestExternalNicId) {
+ //
+ // Slave binding
+ //
+
+ //
+ // Now make MasterBinding the head of a binding set.
+ //
+
+ if (MasterBinding->BindingSetMember) {
+
+ //
+ // Just insert ourselves in the chain.
+ //
+
+#if DBG
+ DbgPrint ("IPX: %ws is also on network %lx\n",
+ Binding->Adapter->AdapterName,
+ REORDER_ULONG (Binding->LocalAddress.NetworkAddress));
+#endif
+ IPX_DEBUG (AUTO_DETECT, ("Add %lx to binding set of %lx\n", Binding, MasterBinding));
+
+ CTEAssert (MasterBinding->CurrentSendBinding);
+ Binding->NextBinding = MasterBinding->NextBinding;
+
+ } else {
+
+ //
+ // Start the chain with the two bindings in it.
+ //
+
+#if DBG
+ DbgPrint ("IPX: %lx and %lx are on the same network %lx, will load balance\n",
+ MasterBinding->Adapter->AdapterName, Binding->Adapter->AdapterName,
+ REORDER_ULONG (Binding->LocalAddress.NetworkAddress));
+#endif
+ IPX_DEBUG (AUTO_DETECT, ("Create new %lx in binding set of %lx\n", Binding, MasterBinding));
+
+ MasterBinding->BindingSetMember = TRUE;
+ MasterBinding->CurrentSendBinding = MasterBinding;
+ MasterBinding->MasterBinding = MasterBinding;
+ Binding->NextBinding = MasterBinding;
+
+ }
+
+ MasterBinding->NextBinding = Binding;
+ Binding->BindingSetMember = TRUE;
+ Binding->ReceiveBroadcast = FALSE;
+ Binding->CurrentSendBinding = NULL;
+ Binding->MasterBinding = MasterBinding;
+
+ //
+ // Since the master binding looks like all members of
+ // the binding set to people querying from above, we have
+ // to make it the worst-case of all the elements. Generally
+ // these will be equal since the frame type and media is
+ // the same.
+ //
+
+ if (Binding->MaxLookaheadData > MasterBinding->MaxLookaheadData) {
+ MasterBinding->MaxLookaheadData = Binding->MaxLookaheadData;
+ }
+ if (Binding->AnnouncedMaxDatagramSize < MasterBinding->AnnouncedMaxDatagramSize) {
+ MasterBinding->AnnouncedMaxDatagramSize = Binding->AnnouncedMaxDatagramSize;
+ }
+ if (Binding->RealMaxDatagramSize < MasterBinding->RealMaxDatagramSize) {
+ MasterBinding->RealMaxDatagramSize = Binding->RealMaxDatagramSize;
+ }
+ if (Binding->MediumSpeed < MasterBinding->MediumSpeed) {
+ MasterBinding->MediumSpeed = Binding->MediumSpeed;
+ }
+
+ //
+ // Place the binding after the last slave binding
+ //
+ INSERT_BINDING(Device, Device->ValidBindings+1, Binding);
+ SET_VERSION(Device, Device->ValidBindings+1);
+
+ Binding->NicId = (USHORT)Device->ValidBindings+1;
+
+ //
+ // Update the indices
+ //
+ Device->ValidBindings++;
+
+ } else {
+
+ //
+ // Not a binding set slave binding - just add it after the last LAN binding
+ //
+
+ //
+ // Move WAN and Slaves down by 1 entry
+ //
+ for (j = Device->ValidBindings; j > Device->HighestLanNicId; j--) {
+ INSERT_BINDING(Device, j+1, NIC_ID_TO_BINDING_NO_ILOCK(Device, j));
+ if (NIC_ID_TO_BINDING_NO_ILOCK(Device, j+1)) {
+ NIC_ID_TO_BINDING_NO_ILOCK(Device, j+1)->NicId++;
+ }
+ }
+
+ //
+ // Insert the LAN binding in the place just allocated
+ //
+ INSERT_BINDING(Device, Device->HighestLanNicId+1, Binding);
+ SET_VERSION(Device, Device->HighestLanNicId+1);
+ Binding->NicId = (USHORT)Device->HighestLanNicId+1;
+
+ //
+ // Update the indices
+ //
+ Device->HighestLanNicId++;
+ Device->HighestExternalNicId++;
+ Device->ValidBindings++;
+ Device->HighestType20NicId++;
+ Device->SapNicCount++;
+
+ if (Device->FirstLanNicId == (USHORT)-1) {
+ Device->FirstLanNicId = Binding->NicId;
+ }
+
+ }
+
+ }
+
+ //
+ // Insert this binding in the RIP Tables
+ //
+ if (Binding->ConfiguredNetworkNumber != 0) {
+ status = RipInsertLocalNetwork(
+ Binding->ConfiguredNetworkNumber,
+ Binding->NicId,
+ Binding->Adapter->NdisBindingHandle,
+ (USHORT)((839 + Binding->Adapter->MediumSpeed) / Binding->Adapter->MediumSpeed));
+
+ if ((status == STATUS_SUCCESS) ||
+ (status == STATUS_DUPLICATE_NAME)) {
+
+ Binding->LocalAddress.NetworkAddress = Binding->ConfiguredNetworkNumber;
+ }
+ }
+
+ //
+ // BUGBUGZZ Make this inline later
+ //
+ // This should be done after all the auto-detect bindings have been thrown away.
+ //
+ // IpxPnPUpdateDevice(Device, Binding);
+ }
+} /* IpxPnPUpdateBindingArray */
+
+
+VOID
+IpxPnPToLoad()
+/*++
+
+Routine Description:
+
+ This routine takes the driver to LOADED state (from OPEN) when all
+ PnP adapters have been removed from the machine.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None. When the function returns, the driver is in LOADED state.
+
+--*/
+
+{
+ PBINDING Binding;
+ PREQUEST Request;
+ PLIST_ENTRY p;
+ UINT i;
+ NTSTATUS ntStatus;
+
+ IPX_DEBUG(PNP, ("Going back to loaded state\n"));
+
+ //
+ // Inform TDI clients about the open of our device object.
+ //
+ if ((ntStatus = TdiDeregisterDeviceObject(IpxDevice->TdiRegistrationHandle)) != STATUS_SUCCESS) {
+ IPX_DEBUG(PNP, ("TdiDeRegisterDeviceObject failed: %lx", ntStatus));
+ }
+
+ //
+ // Complete any pending address notify requests.
+ //
+
+ while ((p = ExInterlockedRemoveHeadList(
+ &IpxDevice->AddressNotifyQueue,
+ &IpxDevice->Lock)) != NULL) {
+
+ Request = LIST_ENTRY_TO_REQUEST(p);
+ REQUEST_STATUS(Request) = STATUS_DEVICE_NOT_READY;
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ IpxCompleteRequest (Request);
+ IpxFreeRequest (IpxDevice, Request);
+
+ IpxDereferenceDevice (IpxDevice, DREF_ADDRESS_NOTIFY);
+ }
+
+ //
+ // Cancel the source routing timer if used.
+ //
+
+ if (IpxDevice->SourceRoutingUsed) {
+
+ IpxDevice->SourceRoutingUsed = FALSE;
+ if (CTEStopTimer (&IpxDevice->SourceRoutingTimer)) {
+ IpxDereferenceDevice (IpxDevice, DREF_SR_TIMER);
+ }
+ }
+
+
+ //
+ // Cancel the RIP long timer, and if we do that then
+ // send a RIP DOWN message if needed.
+ //
+
+ if (CTEStopTimer (&IpxDevice->RipLongTimer)) {
+
+ if (IpxDevice->RipResponder) {
+
+ if (RipQueueRequest (IpxDevice->VirtualNetworkNumber, RIP_DOWN) == STATUS_PENDING) {
+
+ //
+ // If we queue a request, it will stop the timer.
+ //
+
+ KeWaitForSingleObject(
+ &IpxDevice->UnloadEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+ }
+ }
+
+ IpxDereferenceDevice (IpxDevice, DREF_LONG_TIMER);
+
+ } else {
+
+ //
+ // We couldn't stop the timer, which means it is running,
+ // so we need to wait for the event that is kicked when
+ // the RIP DOWN messages are done.
+ //
+
+ if (IpxDevice->RipResponder) {
+
+ KeWaitForSingleObject(
+ &IpxDevice->UnloadEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+ }
+ }
+} /* IpxPnPToLoad */
+
+
+NTSTATUS
+IpxPnPReallocateBindingArray(
+ IN PDEVICE Device,
+ IN ULONG Size
+ )
+/*++
+
+Routine Description:
+
+ This routine reallocates the binding array when the number of bindings go above
+ Device->MaxBindings.
+
+Arguments:
+
+ Device - pointer to the device.
+ Size - the number of new entries required.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PBIND_ARRAY_ELEM BindingArray;
+ ULONG Pad=2; // extra bindings we keep around
+ ULONG NewSize = Size + Pad + Device->MaxBindings;
+
+ //
+ // The absolute max WAN bindings.
+ //
+ CTEAssert(Size < 2048);
+
+ //
+ // Re-allocate the new array
+ //
+ BindingArray = (PBIND_ARRAY_ELEM)IpxAllocateMemory (
+ NewSize * sizeof(BIND_ARRAY_ELEM),
+ MEMORY_BINDING,
+ "Binding array");
+
+ if (BindingArray == NULL) {
+ IpxWriteGeneralErrorLog(
+ (PVOID)Device->DeviceObject,
+ EVENT_IPX_NO_ADAPTERS,
+ 802,
+ STATUS_DEVICE_DOES_NOT_EXIST,
+ NULL,
+ 0,
+ NULL);
+ IpxDereferenceDevice (Device, DREF_CREATE);
+
+ DbgPrint ("Failed to allocate memory in binding array expansion\n");
+
+ //
+ // Unload the driver here? In case of WAN, we can tolerate this failure. What about LAN? [BUGBUGZZ]
+ //
+
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlZeroMemory (BindingArray, NewSize * sizeof(BIND_ARRAY_ELEM));
+
+ //
+ // Copy the old array into the new one.
+ //
+ RtlCopyMemory (BindingArray, Device->Bindings, (Device->ValidBindings+1) * sizeof(BIND_ARRAY_ELEM));
+
+ //
+ // Free the old one.
+ //
+ IpxFreeMemory ( Device->Bindings,
+ Device->MaxBindings * sizeof(BIND_ARRAY_ELEM),
+ MEMORY_BINDING,
+ "Binding array");
+
+ IPX_DEBUG(PNP, ("Expand bindarr old: %lx, new: %lx, oldsize: %lx\n",
+ Device->Bindings, BindingArray, Device->MaxBindings));
+
+ //
+ // Use interlocked exchange to assign this since we dont take the BindAccessLock anymore.
+ //
+ // Device->Bindings = BindingArray;
+ SET_VALUE(Device->Bindings, BindingArray);
+
+ Device->MaxBindings = (USHORT)NewSize;
+
+ return STATUS_SUCCESS;
+}
+#endif _PNP_POWER
+
diff --git a/private/ntos/tdi/isnp/ipx/event.c b/private/ntos/tdi/isnp/ipx/event.c
new file mode 100644
index 000000000..a64f85d34
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/event.c
@@ -0,0 +1,143 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ event.c
+
+Abstract:
+
+ This module contains code which performs the following TDI services:
+
+ o TdiSetEventHandler
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) 3-Oct-1995
+ Changes to support transfer of buffer ownership to transports
+
+ 1. Added a new event type - TDI_EVENT_CHAINED_RECEIVE_DATAGRAM
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+NTSTATUS
+IpxTdiSetEventHandler(
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiSetEventHandler request for the
+ transport provider. The caller (request dispatcher) verifies
+ that this routine will not be executed on behalf of a user-mode
+ client, as this request enables direct callouts at DISPATCH_LEVEL.
+
+Arguments:
+
+ Request - Pointer to the request
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ CTELockHandle LockHandle;
+ PTDI_REQUEST_KERNEL_SET_EVENT Parameters;
+ PADDRESS_FILE AddressFile;
+
+ //
+ // Get the Address this is associated with; if there is none, get out.
+ //
+
+ AddressFile = REQUEST_OPEN_CONTEXT(Request);
+ Status = IpxVerifyAddressFile (AddressFile);
+
+ if (!NT_SUCCESS (Status)) {
+ return Status;
+ }
+
+ CTEGetLock (&AddressFile->Address->Lock, &LockHandle);
+
+ Parameters = (PTDI_REQUEST_KERNEL_SET_EVENT)REQUEST_PARAMETERS(Request);
+
+ switch (Parameters->EventType) {
+
+ case TDI_EVENT_RECEIVE_DATAGRAM:
+
+ if (Parameters->EventHandler == NULL) {
+ AddressFile->ReceiveDatagramHandler =
+ (PTDI_IND_RECEIVE_DATAGRAM)TdiDefaultRcvDatagramHandler;
+ AddressFile->ReceiveDatagramHandlerContext = NULL;
+ AddressFile->RegisteredReceiveDatagramHandler = FALSE;
+ } else {
+ AddressFile->ReceiveDatagramHandler =
+ (PTDI_IND_RECEIVE_DATAGRAM)Parameters->EventHandler;
+ AddressFile->ReceiveDatagramHandlerContext = Parameters->EventContext;
+ AddressFile->RegisteredReceiveDatagramHandler = TRUE;
+ }
+
+ break;
+ //
+ // [SA] New event handler to receive chained buffers
+ //
+ case TDI_EVENT_CHAINED_RECEIVE_DATAGRAM:
+
+ if (Parameters->EventHandler == NULL) {
+ AddressFile->ChainedReceiveDatagramHandler =
+ (PTDI_IND_CHAINED_RECEIVE_DATAGRAM)TdiDefaultChainedRcvDatagramHandler;
+ AddressFile->ChainedReceiveDatagramHandlerContext = NULL;
+ AddressFile->RegisteredChainedReceiveDatagramHandler = FALSE;
+ } else {
+ AddressFile->ChainedReceiveDatagramHandler =
+ (PTDI_IND_CHAINED_RECEIVE_DATAGRAM)Parameters->EventHandler;
+ AddressFile->ChainedReceiveDatagramHandlerContext = Parameters->EventContext;
+ AddressFile->RegisteredChainedReceiveDatagramHandler = TRUE;
+ }
+
+ break;
+
+ case TDI_EVENT_ERROR:
+
+ if (Parameters->EventHandler == NULL) {
+ AddressFile->ErrorHandler =
+ (PTDI_IND_ERROR)TdiDefaultErrorHandler;
+ AddressFile->ErrorHandlerContext = NULL;
+ AddressFile->RegisteredErrorHandler = FALSE;
+ } else {
+ AddressFile->ErrorHandler =
+ (PTDI_IND_ERROR)Parameters->EventHandler;
+ AddressFile->ErrorHandlerContext = Parameters->EventContext;
+ AddressFile->RegisteredErrorHandler = TRUE;
+ }
+
+ break;
+
+ default:
+
+ Status = STATUS_INVALID_PARAMETER;
+
+ } /* switch */
+
+ CTEFreeLock (&AddressFile->Address->Lock, LockHandle);
+
+ IpxDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+
+ REQUEST_INFORMATION(Request) = 0;
+
+ return Status;
+
+} /* IpxTdiSetEventHandler */
+
diff --git a/private/ntos/tdi/isnp/ipx/ind.c b/private/ntos/tdi/isnp/ipx/ind.c
new file mode 100644
index 000000000..f43a524bc
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/ind.c
@@ -0,0 +1,4047 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ ind.c
+
+Abstract:
+
+ This module contains code which implements the indication handler
+ for the IPX transport provider.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) 3-Oct-1995
+ Changes to support transfer of buffer ownership to transports
+
+ 1. Added IpxReceivePacket which receives buffers that can be owned
+ 2. Changed IpxReceiveIndication to call a new function IpxReceiveIndicationNew
+ which takes an extra parameter to indicate whether this is a chained receive or
+ not.
+ 3. Changed IpxProcessDatagram to take the MDL ptr to indicate chained receive,
+ a client count and the headerbuffersize as params.
+
+ Sanjay Anand (SanjayAn) 27-Oct-1995
+ Changes to support Plug and Play (in _PNP_POWER)
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+//
+// This is declared here so it will be in the same function
+// as IpxReceiveIndication and we can inline it.
+//
+
+
+#if defined(_M_IX86)
+_inline
+#endif
+VOID
+IpxProcessDatagram(
+ IN PDEVICE Device,
+ IN PADAPTER Adapter,
+ IN PBINDING Binding,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PIPX_DATAGRAM_OPTIONS DatagramOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT LookaheadBufferOffset,
+ IN UINT PacketSize,
+ IN BOOLEAN Broadcast,
+ IN PINT pTdiClientCount,
+ IN UINT HeaderBufferSize,
+ IN PMDL pMdl,
+ IN NDIS_HANDLE BindingContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routing handles incoming IPX datagrams.
+
+Arguments:
+
+ Device - The IPX device.
+
+ Adapter - The adapter the frame was received on.
+
+ Binding - The binding of the adapter it was received on.
+
+ MacReceiveContext - The context to use when calling
+ NdisTransferData.
+
+ DatagramOptions - Contains the datagram options, which
+ consists of room for the packet type, padding, and
+ the local target of the remote the frame was received from.
+
+ LookaheadBuffer - The lookahead data.
+
+ LookaheadBufferSize - The length of the lookahead data.
+
+ LookaheadBufferOffset - The offset to add when calling
+ NdisTransferData.
+
+ PacketSize - The length of the packet, starting at the IPX
+ header.
+
+ Broadcast - TRUE if the packet was broadcast.
+
+ pTdiClientCount - to return count of the number of TDI clients above us
+ so NDIS can obtain that many ref counts on the buffer.
+
+ HeaderBufferSize - the size of the MAC header buffer - used to determine
+ the offsets into the TSDU.
+
+ pMdl - Mdl chain pointer - non-NULL if chained receive
+
+ BindingContext - In case of loopback, this contains IPX_LOOPBACK_COOKIE
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+
+ PIPX_HEADER IpxHeader = (PIPX_HEADER)LookaheadBuffer;
+ PADDRESS Address;
+ PADDRESS_FILE AddressFile;
+ PADDRESS_FILE ReferencedAddressFile;
+ PREQUEST Request;
+ PIPX_RECEIVE_BUFFER ReceiveBuffer;
+ PTDI_CONNECTION_INFORMATION DatagramInformation;
+ TDI_ADDRESS_IPX UNALIGNED * DatagramAddress;
+ ULONG IndicateBytesCopied;
+ IPX_ADDRESS_EXTENDED_FLAGS SourceAddress;
+ ULONG SourceAddressLength;
+ ULONG RequestCount;
+ PNDIS_BUFFER NdisBuffer;
+ NDIS_STATUS NdisStatus;
+ NTSTATUS Status;
+ PIRP Irp;
+ UINT ByteOffset, BytesToTransfer;
+ ULONG BytesTransferred;
+ BOOLEAN LastAddressFile;
+ ULONG IndicateOffset;
+ PNDIS_PACKET ReceivePacket;
+ PIPX_RECEIVE_RESERVED Reserved;
+ PLIST_ENTRY p, q;
+ PSINGLE_LIST_ENTRY s;
+ USHORT DestinationSocket;
+ USHORT SourceSocket;
+ ULONG Hash;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+
+ //
+ // First scan the device's address database, looking for
+ // the destination socket of this frame.
+ //
+
+ DestinationSocket = *(USHORT UNALIGNED *)&IpxHeader->DestinationSocket;
+
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+
+ if ((Address = Device->LastAddress) &&
+ (Address->Socket == DestinationSocket)) {
+
+ //
+ // Device->LastAddress cannot be stopping, so
+ // we use it.
+ //
+
+ IpxReferenceAddressLock (Address, AREF_RECEIVE);
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ goto FoundAddress;
+ }
+
+ Hash = IPX_DEST_SOCKET_HASH (IpxHeader);
+
+ for (p = Device->AddressDatabases[Hash].Flink;
+ p != &Device->AddressDatabases[Hash];
+ p = p->Flink) {
+
+ Address = CONTAINING_RECORD (p, ADDRESS, Linkage);
+
+ if ((Address->Socket == DestinationSocket) &&
+ (!Address->Stopping)) {
+ IpxReferenceAddressLock (Address, AREF_RECEIVE);
+ Device->LastAddress = Address;
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ goto FoundAddress;
+ }
+ }
+
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+
+ //
+ // If we had found an address we would have jumped
+ // past here.
+ //
+
+ return;
+
+FoundAddress:
+
+ SourceSocket = *(USHORT UNALIGNED *)&IpxHeader->SourceSocket;
+ IpxBuildTdiAddress(
+ &SourceAddress.IpxAddress,
+ (*(ULONG UNALIGNED *)(IpxHeader->SourceNetwork) == 0) ?
+ Binding->LocalAddress.NetworkAddress :
+ *(UNALIGNED ULONG *)(IpxHeader->SourceNetwork),
+ IpxHeader->SourceNode,
+ SourceSocket);
+
+ DatagramOptions->PacketType = IpxHeader->PacketType;
+
+
+ //
+ // Now that we have found the address, scan its list of
+ // address files for clients that want this datagram.
+ //
+ // If we have to release the address lock to indicate to
+ // a client, we reference the current address file. If
+ // we get an IRP we transfer the reference to that;
+ // otherwise we store the address file in ReferencedAddressFile
+ // and deref it the next time we release the lock.
+ //
+
+ ReferencedAddressFile = NULL;
+ RequestCount = 0;
+
+ ++Device->TempDatagramsReceived;
+ Device->TempDatagramBytesReceived += (PacketSize - sizeof(IPX_HEADER));
+
+ //
+ // If LastAddressFile is TRUE, it means we did an indication
+ // to the client on the last address file in the address'
+ // list, and we did not reacquire the lock when we were
+ // done.
+ //
+
+ LastAddressFile = FALSE;
+
+ IPX_GET_LOCK (&Address->Lock, &LockHandle);
+
+ for (p = Address->AddressFileDatabase.Flink;
+ p != &Address->AddressFileDatabase;
+ p = p->Flink) {
+
+ AddressFile = CONTAINING_RECORD (p, ADDRESS_FILE, Linkage);
+
+ if (AddressFile->State != ADDRESSFILE_STATE_OPEN) {
+ continue; // next address file
+ }
+
+ //
+ // Set these to the common values, then change them.
+ //
+
+ SourceAddressLength = sizeof(TA_IPX_ADDRESS);
+ IndicateOffset = sizeof(IPX_HEADER);
+
+ if (AddressFile->SpecialReceiveProcessing) {
+
+ //
+ // On dial out lines, we don't indicate packets to
+ // the SAP socket if DisableDialoutSap is set.
+ //
+
+ if ((AddressFile->IsSapSocket) &&
+ (Binding->DialOutAsync) &&
+ (Device->DisableDialoutSap || Device->SingleNetworkActive)) {
+
+ //
+ // Go to the next address file (although it will
+ // likely fail this test too).
+ //
+
+ continue;
+
+ }
+
+ //
+ // Set this, since generally we want it.
+ //
+
+ SourceAddress.PacketType = IpxHeader->PacketType;
+
+ //
+ // See if we fail a packet type filter.
+ //
+
+ if (AddressFile->FilterOnPacketType) {
+ if (AddressFile->FilteredType != IpxHeader->PacketType) {
+ continue;
+ }
+ }
+
+ //
+ // Calculate how long the addresses expected are.
+ //
+
+ if (AddressFile->ReceiveFlagsAddressing ||
+ AddressFile->ExtendedAddressing) {
+
+ SourceAddress.Flags = 0;
+ if (Broadcast) {
+ SourceAddress.Flags = IPX_EXTENDED_FLAG_BROADCAST;
+ }
+ if (IpxIsAddressLocal((TDI_ADDRESS_IPX UNALIGNED *)
+ &SourceAddress.IpxAddress.Address[0].Address[0])) {
+ SourceAddress.Flags |= IPX_EXTENDED_FLAG_LOCAL;
+ }
+ SourceAddressLength = sizeof(IPX_ADDRESS_EXTENDED_FLAGS);
+ SourceAddress.IpxAddress.Address[0].AddressLength +=
+ (sizeof(IPX_ADDRESS_EXTENDED_FLAGS) - sizeof(TA_IPX_ADDRESS));
+
+ }
+
+ //
+ // Determine how much of the packet the client wants.
+ //
+
+ if (AddressFile->ReceiveIpxHeader) {
+ IndicateOffset = 0;
+ }
+ }
+
+ //
+ // First scan the address' receive datagram queue
+ // for datagrams that match. We do a quick check
+ // to see if the list is empty.
+ //
+
+ q = AddressFile->ReceiveDatagramQueue.Flink;
+ if (q != &AddressFile->ReceiveDatagramQueue) {
+
+ do {
+
+ Request = LIST_ENTRY_TO_REQUEST(q);
+
+ DatagramInformation =
+ ((PTDI_REQUEST_KERNEL_RECEIVEDG)(REQUEST_PARAMETERS(Request)))->
+ ReceiveDatagramInformation;
+
+ if ((DatagramInformation != NULL) &&
+ (DatagramInformation->RemoteAddress != NULL) &&
+ (DatagramAddress = IpxParseTdiAddress(DatagramInformation->RemoteAddress)) &&
+ (DatagramAddress->Socket != SourceSocket)) {
+
+ //
+ // The address that this datagram is looking for is
+ // not satisfied by this frame.
+ //
+ // BUGBUG: Speed this up; worry about node and network?
+ //
+
+ q = q->Flink;
+ continue; // next receive datagram on this address file
+
+ } else {
+
+ //
+ // We found a datagram on the queue.
+ //
+
+ IPX_DEBUG (RECEIVE, ("Found RDG on %lx\n", AddressFile));
+ RemoveEntryList (q);
+ REQUEST_INFORMATION(Request) = 0;
+
+ goto HandleDatagram;
+
+ }
+
+ } while (q != &AddressFile->ReceiveDatagramQueue);
+
+ }
+
+ //
+ // If we found a datagram we would have jumped past here,
+ // so looking for a datagram failed; see if the
+ // client has a receive datagram handler registered.
+ //
+
+ //
+ // Look for the chained receive handler if the MDL is not NULL
+ //
+ if (pMdl && AddressFile->RegisteredChainedReceiveDatagramHandler) {
+
+ //
+ // Chained receive both above and below => we indicate the entire MDL up.
+ // Offset the LookaheadBuffer by the size of the MAC header.
+ //
+ LookaheadBufferOffset += HeaderBufferSize;
+
+ IpxReferenceAddressFileLock (AddressFile, AFREF_INDICATION);
+
+ //
+ // Set this so we can exit without reacquiring
+ // the lock.
+ //
+
+ if (p == &Address->AddressFileDatabase) {
+ LastAddressFile = TRUE;
+ }
+
+ IndicateBytesCopied = 0;
+
+ IPX_FREE_LOCK (&Address->Lock, LockHandle);
+
+ if (ReferencedAddressFile) {
+ IpxDereferenceAddressFileSync (ReferencedAddressFile, AFREF_INDICATION);
+ ReferencedAddressFile = NULL;
+ }
+
+ IPX_DEBUG(RECEIVE, ("ChainedIndicate RecvLen: %d, StartOffset: %d, Tsdu: %lx\n",
+ PacketSize - IndicateOffset, IndicateOffset, pMdl));
+
+ //
+ // Will return SUCCESS if the client did not take ownership of the Tsdu
+ // PENDING if the client took ownership and will free it later (using TdiFreeReceiveChain).
+ // DATA_NOT_ACCEPTED if the client did not take ownership and did not copy the data.
+ //
+
+ //
+ // Since NDIS needs an array of PNDIS_PACKETs when the TDI client returns this packet,
+ // we pass the Packet as the ReceiveContext here. The TDI client will pass in the address
+ // of this context on a ReturnPacket.
+ // Also, NDIS needs the PacketArray (not to be confused with the array of packetptrs. mentioned
+ // above) on an NdisTransferData call. These clients dont do this, but other clients like
+ // NB, SPX, RIP or TDI clients that do not have this new interface, can call NdisTransferData
+ // so we pass in the PacketArray as a parameter to them.
+ //
+ Status = (*AddressFile->ChainedReceiveDatagramHandler)(
+ AddressFile->ChainedReceiveDatagramHandlerContext,
+ SourceAddressLength,
+ &SourceAddress,
+ sizeof(IPX_DATAGRAM_OPTIONS),
+ DatagramOptions,
+ Adapter->MacInfo.CopyLookahead, // TdiRcvFlags|Adapter->MacInfo.CopyLookahead, Receive datagram flags
+ PacketSize - IndicateOffset, // ReceiveLength
+ IndicateOffset+LookaheadBufferOffset, // StartingOffset
+ pMdl, // Tsdu - MDL chain
+ (PNDIS_PACKET)MacReceiveContext); // TransportContext - pointer to the packet
+
+ if (Status != STATUS_DATA_NOT_ACCEPTED) {
+
+ if (Status == STATUS_PENDING) {
+ //
+ // We assume here that the client referenced the packet which will
+ // be removed when the packet is freed.
+ // Increment the Tdi client count
+ //
+ (*pTdiClientCount)++;
+ }
+
+ //
+ // The handler accepted the data or did not
+ // return an IRP; in either case there is
+ // nothing else to do, so go to the next
+ // address file.
+ //
+
+ ReferencedAddressFile = AddressFile;
+ if (!LastAddressFile) {
+
+ IPX_GET_LOCK (&Address->Lock, &LockHandle);
+ continue;
+
+ } else {
+
+ //
+ // In this case we have no cleanup, so just leave
+ // if there are no datagrams pending.
+ //
+ // RequestCount should always be 0 here.
+ //
+
+
+ //if (RequestCount == 0) {
+ // return;
+ //}
+ goto BreakWithoutLock;
+ }
+
+ } else {
+ //
+ // Since no IRP can be returned here, we continue to the next addressfile
+ //
+
+ ReferencedAddressFile = AddressFile;
+ if (!LastAddressFile) {
+
+ IPX_GET_LOCK (&Address->Lock, &LockHandle);
+ continue;
+
+ } else {
+
+ //
+ // In this case we have no cleanup, so just leave
+ // if there are no datagrams pending.
+ //
+
+ //if (RequestCount == 0) {
+ // return;
+ //}
+ goto BreakWithoutLock;
+ }
+ }
+
+ } else if (AddressFile->RegisteredReceiveDatagramHandler) {
+
+ IpxReferenceAddressFileLock (AddressFile, AFREF_INDICATION);
+
+ //
+ // Set this so we can exit without reacquiring
+ // the lock.
+ //
+
+ if (p == &Address->AddressFileDatabase) {
+ LastAddressFile = TRUE;
+ }
+
+ IPX_FREE_LOCK (&Address->Lock, LockHandle);
+
+ if (ReferencedAddressFile) {
+ IpxDereferenceAddressFileSync (ReferencedAddressFile, AFREF_INDICATION);
+ ReferencedAddressFile = NULL;
+ }
+
+ IndicateBytesCopied = 0;
+
+ if (PacketSize > LookaheadBufferSize) {
+ IPX_DEBUG(RECEIVE, ("Indicate %d/%d to %lx on %lx\n",
+ LookaheadBufferSize, PacketSize,
+ AddressFile->ReceiveDatagramHandler, AddressFile));
+ }
+
+ Status = (*AddressFile->ReceiveDatagramHandler)(
+ AddressFile->ReceiveDatagramHandlerContext,
+ SourceAddressLength,
+ &SourceAddress,
+ sizeof(IPX_DATAGRAM_OPTIONS),
+ DatagramOptions,
+ Adapter->MacInfo.CopyLookahead,
+ LookaheadBufferSize - IndicateOffset, // indicated
+ PacketSize - IndicateOffset, // available
+ &IndicateBytesCopied, // taken
+ LookaheadBuffer + IndicateOffset, // data
+ &Irp);
+
+
+ if (Status != STATUS_MORE_PROCESSING_REQUIRED) {
+
+ //
+ // The handler accepted the data or did not
+ // return an IRP; in either case there is
+ // nothing else to do, so go to the next
+ // address file.
+ //
+
+ ReferencedAddressFile = AddressFile;
+ if (!LastAddressFile) {
+
+ IPX_GET_LOCK (&Address->Lock, &LockHandle);
+ continue;
+
+ } else {
+
+ //
+ // In this case we have no cleanup, so just leave
+ // if there are no datagrams pending.
+ //
+
+ if (RequestCount == 0) {
+ return;
+ }
+ goto BreakWithoutLock;
+ }
+
+ } else {
+
+ //
+ // The client returned an IRP.
+ //
+
+ IPX_DEBUG (RECEIVE, ("Indicate IRP %lx, taken %d\n", Irp, IndicateBytesCopied));
+
+ Request = IpxAllocateRequest (Device, Irp);
+
+ IF_NOT_ALLOCATED(Request) {
+ Irp->IoStatus.Information = 0;
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ ReferencedAddressFile = AddressFile;
+ IPX_GET_LOCK (&Address->Lock, &LockHandle);
+ continue;
+ }
+
+ if (!LastAddressFile) {
+ IPX_GET_LOCK (&Address->Lock, &LockHandle);
+ }
+
+#if DBG
+ //
+ // Make sure the IRP file object is right.
+ //
+
+ if (IoGetCurrentIrpStackLocation(Irp)->FileObject->FsContext != AddressFile) {
+ DbgPrint ("IRP %lx does not match AF %lx, H %lx C %lx\n",
+ Irp, AddressFile,
+ AddressFile->ReceiveDatagramHandler,
+ AddressFile->ReceiveDatagramHandlerContext);
+ DbgBreakPoint();
+ }
+#endif
+ //
+ // Set up the information field so we know
+ // how much to skip in it.
+ //
+
+ IpxTransferReferenceAddressFile (AddressFile, AFREF_INDICATION, AFREF_RCV_DGRAM);
+ REQUEST_INFORMATION(Request) = IndicateBytesCopied;
+
+ //
+ // Fall out of the if and continue via
+ // HandleDatagram...
+ //
+
+ }
+
+ } else {
+
+ //
+ // No posted datagram, no handler; go to the next
+ // address file.
+ //
+
+ continue; // next address file
+
+ }
+
+HandleDatagram:
+
+ //
+ // At this point, Request is set to the request
+ // that will hold for this address file, and
+ // REQUEST_INFORMATION() is the offset to start
+ // the transfer at.
+ //
+
+ //
+ // First copy over the source address while it is handy.
+ //
+
+ DatagramInformation =
+ ((PTDI_REQUEST_KERNEL_RECEIVEDG)(REQUEST_PARAMETERS(Request)))->
+ ReturnDatagramInformation;
+
+ if (DatagramInformation != NULL) {
+
+ RtlCopyMemory(
+ DatagramInformation->RemoteAddress,
+ &SourceAddress,
+ (ULONG)DatagramInformation->RemoteAddressLength < SourceAddressLength ?
+ DatagramInformation->RemoteAddressLength : SourceAddressLength);
+ RtlCopyMemory(
+ DatagramInformation->Options,
+ &DatagramOptions,
+ (ULONG)DatagramInformation->OptionsLength < sizeof(IPX_DATAGRAM_OPTIONS) ?
+ DatagramInformation->OptionsLength : sizeof(IPX_DATAGRAM_OPTIONS));
+
+ }
+
+ //
+ // Now check if this is the first request that will
+ // take the data, otherwise queue it up.
+ //
+
+ if (RequestCount == 0) {
+
+ //
+ // First one; we need to allocate a packet for the transfer.
+ //
+
+ //if (Address->ReceivePacketInUse) {
+ if (InterlockedExchangeAdd(&Address->ReceivePacketInUse, 0) != 0) {
+ //
+ // Need a packet, check the pool.
+ //
+
+ s = IpxPopReceivePacket (Device);
+
+ if (s == NULL) {
+
+ //
+ // None in pool, fail the request.
+ //
+
+ REQUEST_INFORMATION(Request) = 0;
+ REQUEST_STATUS(Request) = STATUS_INSUFFICIENT_RESOURCES;
+ IPX_INSERT_TAIL_LIST(
+ &Adapter->RequestCompletionQueue,
+ REQUEST_LINKAGE(Request),
+ Adapter->DeviceLock);
+
+ if (!LastAddressFile) {
+ continue;
+ } else {
+ goto BreakWithoutLock;
+ }
+
+ }
+
+ Reserved = CONTAINING_RECORD (s, IPX_RECEIVE_RESERVED, PoolLinkage);
+ ReceivePacket = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ } else {
+
+ // Address->ReceivePacketInUse = TRUE;
+ InterlockedIncrement(&Address->ReceivePacketInUse);
+
+ ReceivePacket = PACKET(&Address->ReceivePacket);
+ Reserved = RECEIVE_RESERVED(&Address->ReceivePacket);
+
+ }
+
+ CTEAssert (IsListEmpty(&Reserved->Requests));
+
+ Reserved->SingleRequest = Request;
+ NdisBuffer = REQUEST_NDIS_BUFFER(Request);
+
+ ByteOffset = REQUEST_INFORMATION(Request) + LookaheadBufferOffset + IndicateOffset;
+ BytesToTransfer =
+ ((PTDI_REQUEST_KERNEL_RECEIVEDG)(REQUEST_PARAMETERS(Request)))->ReceiveLength;
+
+ if (BytesToTransfer > (PacketSize - IndicateOffset)) {
+ BytesToTransfer = PacketSize - IndicateOffset;
+ }
+
+ } else {
+
+ if (RequestCount == 1) {
+
+ //
+ // There is already one request. We need to
+ // allocate a buffer.
+ //
+
+ s = IpxPopReceiveBuffer (Adapter);
+
+ if (s == NULL) {
+
+ //
+ // No buffers, fail the request.
+ //
+ // BUGBUG: Should we fail the transfer for the
+ // first request too?
+ //
+
+ REQUEST_INFORMATION(Request) = 0;
+ REQUEST_STATUS(Request) = STATUS_INSUFFICIENT_RESOURCES;
+ IPX_INSERT_TAIL_LIST(
+ &Adapter->RequestCompletionQueue,
+ REQUEST_LINKAGE(Request),
+ Adapter->DeviceLock);
+
+ if (!LastAddressFile) {
+ continue;
+ } else {
+ goto BreakWithoutLock;
+ }
+ }
+
+ ReceiveBuffer = CONTAINING_RECORD(s, IPX_RECEIVE_BUFFER, PoolLinkage);
+ NdisBuffer = ReceiveBuffer->NdisBuffer;
+
+ //
+ // Convert this to a queued multiple piece request.
+ //
+
+ InsertTailList(&Reserved->Requests, REQUEST_LINKAGE(Reserved->SingleRequest));
+ Reserved->SingleRequest = NULL;
+ Reserved->ReceiveBuffer = ReceiveBuffer;
+
+ ByteOffset = LookaheadBufferOffset;
+ BytesToTransfer = PacketSize;
+
+ }
+
+ InsertTailList(&Reserved->Requests, REQUEST_LINKAGE(Request));
+
+ }
+
+ //
+ // We are done setting up this address file's transfer,
+ // proceed to the next one.
+ //
+
+ ++RequestCount;
+
+ if (LastAddressFile) {
+ goto BreakWithoutLock;
+ }
+
+ }
+
+ IPX_FREE_LOCK (&Address->Lock, LockHandle);
+
+BreakWithoutLock:
+
+ if (ReferencedAddressFile) {
+ IpxDereferenceAddressFileSync (ReferencedAddressFile, AFREF_INDICATION);
+ ReferencedAddressFile = NULL;
+ }
+
+
+ //
+ // We can be transferring directly into a request's buffer,
+ // transferring into an intermediate buffer, or not
+ // receiving the packet at all.
+ //
+
+ if (RequestCount > 0) {
+
+ //
+ // If this is true, then ReceivePacket, Reserved,
+ // and NdisBuffer are all set up correctly.
+ //
+
+ CTEAssert (ReceivePacket);
+ CTEAssert (Reserved == (PIPX_RECEIVE_RESERVED)(ReceivePacket->ProtocolReserved));
+
+
+ NdisChainBufferAtFront(ReceivePacket, NdisBuffer);
+
+ IPX_DEBUG (RECEIVE, ("Transfer into %lx, offset %d bytes %d\n",
+ NdisBuffer, ByteOffset, BytesToTransfer));
+
+ if (BindingContext == (PVOID)IPX_LOOPBACK_COOKIE) {
+
+ IPX_DEBUG (LOOPB, ("Loopback Copy from packet: %lx to packet: %lx\n", ReceivePacket, MacReceiveContext));
+
+ NdisCopyFromPacketToPacket(
+ ReceivePacket, // Destination
+ 0, // DestinationOffset
+ BytesToTransfer, // BytesToCopy
+ (PNDIS_PACKET)MacReceiveContext, // Source
+ ByteOffset, // SourceOffset - loopback packet
+ &BytesTransferred); // BytesCopied
+
+ NdisStatus = NDIS_STATUS_SUCCESS;
+
+ } else {
+ NdisTransferData(
+ &NdisStatus,
+ Adapter->NdisBindingHandle,
+ MacReceiveContext,
+ ByteOffset,
+ BytesToTransfer,
+ ReceivePacket,
+ &BytesTransferred);
+ }
+
+ if (NdisStatus != NDIS_STATUS_PENDING) {
+
+ IpxTransferDataComplete(
+ (NDIS_HANDLE)Adapter,
+ ReceivePacket,
+ NdisStatus,
+ BytesTransferred);
+ }
+ }
+
+
+ IpxDereferenceAddressSync (Address, AREF_RECEIVE);
+
+} /* IpxProcessDatagram */
+
+
+
+NDIS_STATUS
+IpxReceiveIndication(
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_HANDLE ReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine receives control from the physical provider as an
+ indication that a frame has been received on the physical link.
+ This routine is time critical, so we only allocate a
+ buffer and copy the packet into it. We also perform minimal
+ validation on this packet. It gets queued to the device context
+ to allow for processing later.
+
+Arguments:
+
+ BindingContext - The Adapter Binding specified at initialization time.
+
+ ReceiveContext - A magic cookie for the MAC.
+
+ HeaderBuffer - pointer to a buffer containing the packet header.
+
+ HeaderBufferSize - the size of the header.
+
+ LookaheadBuffer - pointer to a buffer containing the negotiated minimum
+ amount of buffer I get to look at (not including header).
+
+ LookaheadBufferSize - the size of the above. May be less than asked
+ for, if that's all there is.
+
+ PacketSize - Overall size of the packet (not including header).
+
+Return Value:
+
+ NDIS_STATUS - status of operation, one of:
+
+ NDIS_STATUS_SUCCESS if packet accepted,
+ NDIS_STATUS_NOT_RECOGNIZED if not recognized by protocol,
+ NDIS_any_other_thing if I understand, but can't handle.
+
+--*/
+{
+ //
+ // Call the actual receive indication handler and indicate that this is not a
+ // chained receive
+ //
+
+ return IpxReceiveIndicationNew (
+ BindingContext,
+ ReceiveContext, // ReceiveContext
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize, // PacketSize
+ NULL, // pMdl - non-NULL => chained receive.
+ NULL // pTdiClientCount - used in chained recv case to keep count of TDI clients
+ );
+
+}
+
+
+NDIS_STATUS
+IpxReceiveIndicationNew(
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_HANDLE ReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize,
+ IN PMDL pMdl,
+ IN PINT pTdiClientCount
+ )
+
+/*++
+
+Routine Description:
+
+ This routine receives control from the physical provider as an
+ indication that a frame has been received on the physical link.
+ This routine is time critical, so we only allocate a
+ buffer and copy the packet into it. We also perform minimal
+ validation on this packet. It gets queued to the device context
+ to allow for processing later.
+
+Arguments:
+
+ BindingContext - The Adapter Binding specified at initialization time.
+
+ ReceiveContext - A magic cookie for the MAC.
+
+ HeaderBuffer - pointer to a buffer containing the packet header.
+
+ HeaderBufferSize - the size of the header.
+
+ LookaheadBuffer - pointer to a buffer containing the negotiated minimum
+ amount of buffer I get to look at (not including header).
+
+ LookaheadBufferSize - the size of the above. May be less than asked
+ for, if that's all there is.
+
+ PacketSize - Overall size of the packet (not including header).
+
+ pMdl - pointer to MDL chain if chained, NULL if this came from indication.
+
+Return Value:
+
+ NDIS_STATUS - status of operation, one of:
+
+ NDIS_STATUS_SUCCESS if packet accepted,
+ NDIS_STATUS_NOT_RECOGNIZED if not recognized by protocol,
+ NDIS_any_other_thing if I understand, but can't handle.
+
+--*/
+{
+
+ IPX_DATAGRAM_OPTIONS DatagramOptions;
+ PADAPTER Adapter = (PADAPTER)BindingContext;
+ PBINDING Binding;
+ PDEVICE Device = IpxDevice;
+ PUCHAR Header = (PUCHAR)HeaderBuffer;
+ PUCHAR Lookahead = (PUCHAR)LookaheadBuffer;
+ ULONG PacketLength;
+ UINT IpxPacketSize;
+ ULONG Length802_3;
+ USHORT Saps;
+ ULONG DestinationNetwork;
+ ULONG SourceNetwork;
+ PUCHAR DestinationNode;
+ USHORT DestinationSocket;
+ ULONG IpxHeaderOffset;
+ PIPX_HEADER IpxHeader;
+ UINT i;
+ BOOLEAN IsBroadcast;
+ BOOLEAN IsLoopback = FALSE;
+#if DBG
+ PUCHAR DestMacAddress;
+ ULONG ReceiveFlag;
+#endif
+
+#ifdef _PNP_POWER
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+#endif _PNP_POWER
+
+ //
+ // Reject packets that are too short to hold even the
+ // basic IPX header (this ignores any extra 802.2 etc.
+ // headers but is good enough because a runt will fail
+ // the IPX header packet length check).
+ //
+
+ if (PacketSize < sizeof(IPX_HEADER)) {
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // If this is a loopback packet, no need to do figure out the
+ // MAC header.
+ //
+ if (BindingContext == (PVOID)IPX_LOOPBACK_COOKIE) {
+
+#ifdef _PNP_POWER
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ Binding = NIC_ID_TO_BINDING(IpxDevice, 1);
+
+ if (!Binding) {
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ goto NotValidLoopback;
+ }
+
+ Adapter = Binding->Adapter;
+
+ //
+ // Bump up the ref count so the adapter doesn't disappear from under
+ // us.
+ //
+ IpxReferenceAdapter(Adapter);
+
+ IpxReferenceBinding1(Binding, BREF_ADAPTER_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ FILL_LOCAL_TARGET(&DatagramOptions.LocalTarget, 0);
+#else
+ if ((Binding = IpxDevice->Bindings[1]) == NULL) {
+ goto NotValidLoopback;
+ }
+
+ Adapter = Binding->Adapter;
+
+ DatagramOptions.LocalTarget.NicId = 0;
+#endif
+
+ //
+ // Do this copy later, from the IpxHeader.
+ //
+ // RtlCopyMemory (DatagramOptions.LocalTarget.MacAddress, Binding->LocalAddress.NodeAddress, 6);
+
+ if (Binding->Adapter->MacInfo.MediumType == NdisMedium802_5) {
+ DatagramOptions.LocalTarget.MacAddress[0] &= 0x7f;
+ }
+
+ //
+ // Ipx header starts at the top of the LookAheadBuffer
+ //
+ IpxHeaderOffset = 0;
+
+ IPX_DEBUG (LOOPB, ("Loopback packet received: %lx\n", ReceiveContext));
+
+#if DBG
+ DestMacAddress = DatagramOptions.LocalTarget.MacAddress;
+#endif
+
+ IsLoopback = TRUE;
+ goto Loopback;
+ }
+
+#ifdef _PNP_POWER
+ //
+ // Bump up the ref count so the adapter doesn't disappear from under
+ // us.
+ //
+ IpxReferenceAdapter(Adapter);
+#endif
+
+ //
+ // The first step is to construct the 8-byte local
+ // target from the packet. We store it in the 9-byte
+ // datagram options, leaving one byte at the front
+ // for use by IpxProcessDatagram when indicating to
+ // its TDI clients.
+ //
+
+#if DBG
+ Binding = NULL;
+#endif
+
+ if (Adapter->MacInfo.MediumType == NdisMedium802_3) {
+
+ //
+ // Try to figure out what the packet type is.
+ //
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+#endif
+
+ if (Header[12] < 0x06) {
+
+ //
+ // An 802.3 header; check the next bytes. They may
+ // be E0/E0 (802.2), FFFF (raw 802.3) or A0/A0 (SNAP).
+ //
+
+ Saps = *(UNALIGNED USHORT *)(Lookahead);
+
+ if (Saps == 0xffff) {
+ if ((Binding = Adapter->Bindings[ISN_FRAME_TYPE_802_3]) == NULL) {
+ goto NotValid802_3;
+ }
+ IpxHeaderOffset = 0;
+ Length802_3 = ((Header[12] << 8) | Header[13]);
+ goto Valid802_3;
+
+ } else if (Saps == 0xe0e0) {
+ if (Lookahead[2] == 0x03) {
+ if ((Binding = Adapter->Bindings[ISN_FRAME_TYPE_802_2]) == NULL) {
+ goto NotValid802_3;
+ }
+ IpxHeaderOffset = 3;
+ Length802_3 = ((Header[12] << 8) | Header[13]);
+ goto Valid802_3;
+ }
+
+ } else if (Saps == 0xaaaa) {
+
+ if ((Lookahead[2] == 0x03) &&
+ (*(UNALIGNED USHORT *)(Lookahead+6) == Adapter->BindSapNetworkOrder)) {
+ if ((Binding = Adapter->Bindings[ISN_FRAME_TYPE_SNAP]) == NULL) {
+ goto NotValid802_3;
+ }
+ IpxHeaderOffset = 8;
+ Length802_3 = ((Header[12] << 8) | Header[13]);
+ goto Valid802_3;
+ }
+ }
+
+ goto NotValid802_3;
+
+ } else {
+
+ //
+ // It has an ethertype, see if it is ours.
+ //
+
+ if (*(UNALIGNED USHORT *)(Header+12) == Adapter->BindSapNetworkOrder) {
+
+ if (Adapter->MacInfo.MediumAsync) {
+
+ *((ULONG UNALIGNED *)(&Binding)) = *((ULONG UNALIGNED *)(&Header[2]));
+
+ CTEAssert(Binding != NULL);
+
+ if ((Binding != NULL) &&
+ (Binding->LineUp)) {
+
+ IpxHeaderOffset = 0;
+ Length802_3 = PacketSize; // set this so the check succeeds
+
+ //
+ // Check if this is a type 20 packet and
+ // we are disabling them on dialin lines -- we do
+ // this check here to avoid impacting the main
+ // indication path for LANs.
+ //
+ // The 0x02 bit of DisableDialinNetbios controls
+ // WAN->LAN packets, which we handle here.
+ //
+
+ if ((!Binding->DialOutAsync) &&
+ ((Device->DisableDialinNetbios & 0x02) != 0)) {
+
+ IpxHeader = (PIPX_HEADER)Lookahead; // IpxHeaderOffset is 0
+ if (IpxHeader->PacketType == 0x14) {
+#ifdef _PNP_POWER
+ IpxDereferenceAdapter(Adapter);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+ return STATUS_SUCCESS;
+ }
+ }
+
+ goto Valid802_3;
+ }
+ goto NotValid802_3;
+
+ } else if ((Binding = Adapter->Bindings[ISN_FRAME_TYPE_ETHERNET_II]) == NULL) {
+ goto NotValid802_3;
+ }
+
+ IpxHeaderOffset = 0;
+ Length802_3 = PacketSize; // set this so the check succeeds
+ goto Valid802_3;
+
+ }
+ }
+
+ goto NotValid802_3;
+
+Valid802_3:
+
+ if (Length802_3 > PacketSize) {
+ goto NotValid802_3;
+ } else if (Length802_3 < PacketSize) {
+ PacketSize = Length802_3;
+ if (LookaheadBufferSize > Length802_3) {
+ LookaheadBufferSize = Length802_3;
+ }
+ }
+
+#ifdef _PNP_POWER
+ IpxReferenceBinding1(Binding, BREF_ADAPTER_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+ RtlCopyMemory (DatagramOptions.LocalTarget.MacAddress, Header+6, 6);
+#if DBG
+ DestMacAddress = Header;
+#endif
+
+ } else if (Adapter->MacInfo.MediumType == NdisMedium802_5) {
+
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+#endif
+ Saps = *(USHORT UNALIGNED *)(Lookahead);
+
+ if (Saps == 0xe0e0) {
+
+ if (Lookahead[2] == 0x03) {
+ if ((Binding = Adapter->Bindings[ISN_FRAME_TYPE_802_2]) == NULL) {
+ goto NotValid802_5;
+ }
+
+ IpxHeaderOffset = 3;
+ goto Valid802_5;
+ }
+
+ } else if (Saps == 0xaaaa) {
+
+ if ((Lookahead[2] == 0x03) &&
+ (*(UNALIGNED USHORT *)(Lookahead+6) == Adapter->BindSapNetworkOrder)) {
+ if ((Binding = Adapter->Bindings[ISN_FRAME_TYPE_SNAP]) == NULL) {
+ goto NotValid802_5;
+ }
+ IpxHeaderOffset = 8;
+ goto Valid802_5;
+ }
+ }
+
+ goto NotValid802_5;
+
+Valid802_5:
+#ifdef _PNP_POWER
+ IpxReferenceBinding1(Binding, BREF_ADAPTER_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+
+ RtlCopyMemory (DatagramOptions.LocalTarget.MacAddress, Header+8, 6);
+ DatagramOptions.LocalTarget.MacAddress[0] &= 0x7f;
+
+#if DBG
+ DestMacAddress = Header+2;
+#endif
+
+ } else if (Adapter->MacInfo.MediumType == NdisMediumFddi) {
+
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+#endif
+ Saps = *(USHORT UNALIGNED *)(Lookahead);
+
+ if (Saps == 0xe0e0) {
+
+ if (Lookahead[2] == 0x03) {
+ if ((Binding = Adapter->Bindings[ISN_FRAME_TYPE_802_2]) == NULL) {
+ goto NotValidFddi;
+ }
+ IpxHeaderOffset = 3;
+ goto ValidFddi;
+ }
+
+ } else if (Saps == 0xffff) {
+
+ if ((Binding = Adapter->Bindings[ISN_FRAME_TYPE_802_3]) == NULL) {
+ goto NotValidFddi;
+ }
+ IpxHeaderOffset = 0;
+ goto ValidFddi;
+
+ } else if (Saps == 0xaaaa) {
+
+ if ((Lookahead[2] == 0x03) &&
+ (*(UNALIGNED USHORT *)(Lookahead+6) == Adapter->BindSapNetworkOrder)) {
+
+ if ((Binding = Adapter->Bindings[ISN_FRAME_TYPE_SNAP]) == NULL) {
+ goto NotValidFddi;
+ }
+ IpxHeaderOffset = 8;
+ goto ValidFddi;
+ }
+ }
+
+ goto NotValidFddi;
+
+ValidFddi:
+
+#ifdef _PNP_POWER
+ IpxReferenceBinding1(Binding, BREF_ADAPTER_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+
+ RtlCopyMemory (DatagramOptions.LocalTarget.MacAddress, Header+7, 6);
+
+#if DBG
+ DestMacAddress = Header+1;
+#endif
+
+
+ } else {
+
+ //
+ // NdisMediumArcnet878_2
+ //
+
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+#endif
+ if ((Header[2] == ARCNET_PROTOCOL_ID) &&
+ ((Binding = Adapter->Bindings[ISN_FRAME_TYPE_802_3]) != NULL)) {
+
+ IpxHeaderOffset = 0;
+ RtlZeroMemory (DatagramOptions.LocalTarget.MacAddress, 5);
+ DatagramOptions.LocalTarget.MacAddress[5] = Header[0];
+
+ } else {
+
+#ifdef _PNP_POWER
+ IpxDereferenceAdapter(Adapter);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+
+#ifdef IPX_PACKET_LOG
+ if (PACKET_LOG(IPX_PACKET_LOG_RCV_ALL)) {
+ IpxLogPacket(FALSE, Header+2, Header+1, (USHORT)PacketSize, LookaheadBuffer, (PUCHAR)LookaheadBuffer + sizeof(IPX_HEADER));
+ }
+#endif
+ return NDIS_STATUS_SUCCESS;
+ }
+
+#if DBG
+ DestMacAddress = Header+2; // BUGBUG Need to log less than six bytes
+#endif
+
+#ifdef _PNP_POWER
+ IpxReferenceBinding1(Binding, BREF_ADAPTER_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+ }
+
+ //
+ // Make sure this didn't slip through.
+ //
+
+ CTEAssert (Binding != NULL);
+#ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(&DatagramOptions.LocalTarget, MIN( Device->MaxBindings, Binding->NicId));
+#else
+ DatagramOptions.LocalTarget.NicId = Binding->NicId;
+#endif
+
+Loopback:
+
+ //
+ // Now that we have validated the header and constructed
+ // the local target, indicate the packet to the correct
+ // client.
+ //
+
+ IpxHeader = (PIPX_HEADER)(Lookahead + IpxHeaderOffset);
+
+ PacketLength = (IpxHeader->PacketLength[0] << 8) | IpxHeader->PacketLength[1];
+
+ IpxPacketSize = PacketSize - IpxHeaderOffset;
+
+ if (PacketLength > IpxPacketSize) {
+
+#ifdef _PNP_POWER
+ IpxDereferenceAdapter(Adapter);
+ IpxDereferenceBinding1(Binding, BREF_ADAPTER_ACCESS);
+#endif
+
+#ifdef IPX_PACKET_LOG
+ if (PACKET_LOG(IPX_PACKET_LOG_RCV_ALL)) {
+ IpxLogPacket(FALSE, DestMacAddress, DatagramOptions.LocalTarget.MacAddress, (USHORT)PacketSize, IpxHeader, IpxHeader+1);
+ }
+#endif
+ IPX_DEBUG (BAD_PACKET, ("Packet len %d, IPX len %d\n",
+ PacketLength, IpxPacketSize));
+
+ return NDIS_STATUS_SUCCESS;
+
+ } else if (PacketLength < IpxPacketSize) {
+
+ IpxPacketSize = PacketLength;
+ if (LookaheadBufferSize > (PacketLength + IpxHeaderOffset)) {
+ LookaheadBufferSize = PacketLength + IpxHeaderOffset;
+ }
+
+ }
+
+ //
+ // Bug #33595 - (hotfixed in 3.51, checked into 4.0 beta2)
+ // Customer problem where NT allowed RIP/SAP to reply to an 802.5 functional address in the IPX source node. The source
+ // MAC address was proper in this case. We need to check for the case where if the packet's source network is the same
+ // as that of the binding it came on (=> did not come thru a router), then the SourceNodeAddress in the IPX header
+ // should be equal to the SourceAddress in the MAC header.
+ //
+ // This check is controlled through a registry value - VerifySourceAddress.
+ // In case of Arcnet, this check will not succeed.
+ // Also, for WAN, the node addresses will not match, so avoid check for those.
+
+ //
+ // If the source network is 0, we drop it. Auto-detect frames should have matching node (MAC) addresses.
+ // Loopback packets dont have a valid header, so skip this test for them.
+ //
+ // BUGBUG: For loopback pkts, do all the processing above, so we can avoid all these checks for IsLoopback here.
+ // Also, to prevent the RtlCopyMemory into the localtarget above, try to use the MAC header to indicate the
+ // correct binding to us so we dont use the first one always.
+ //
+ // CAVEAT:: when using the MAC header as a binding pointer, ensure that we use the adapter corresp, to that binding
+ // to enque all the receive requests. currently we enqueue them onto the first bindings adapter.
+ //
+ if (((*(UNALIGNED ULONG *)IpxHeader->SourceNetwork == Binding->LocalAddress.NetworkAddress) ||
+ (*(UNALIGNED ULONG *)IpxHeader->SourceNetwork == 0)) &&
+ (!IPX_NODE_EQUAL (IpxHeader->SourceNode, DatagramOptions.LocalTarget.MacAddress)) &&
+ Device->VerifySourceAddress &&
+ !IsLoopback &&
+ !Adapter->MacInfo.MediumAsync &&
+ (Adapter->MacInfo.MediumType != NdisMediumArcnet878_2)) {
+
+ IPX_DEBUG(BAD_PACKET, ("Local packet: Src MAC %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x ",
+ DatagramOptions.LocalTarget.MacAddress[0],
+ DatagramOptions.LocalTarget.MacAddress[1],
+ DatagramOptions.LocalTarget.MacAddress[2],
+ DatagramOptions.LocalTarget.MacAddress[3],
+ DatagramOptions.LocalTarget.MacAddress[4],
+ DatagramOptions.LocalTarget.MacAddress[5]));
+
+ IPX_DEBUG(BAD_PACKET, ("IPX Src Node %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x\n",
+ IpxHeader->SourceNode[0],
+ IpxHeader->SourceNode[1],
+ IpxHeader->SourceNode[2],
+ IpxHeader->SourceNode[3],
+ IpxHeader->SourceNode[4],
+ IpxHeader->SourceNode[5]));
+
+#ifdef IPX_PACKET_LOG
+ ReceiveFlag = IPX_PACKET_LOG_RCV_ALL;
+ if (PACKET_LOG(ReceiveFlag)) {
+ IpxLogPacket(
+ FALSE,
+ DestMacAddress,
+ DatagramOptions.LocalTarget.MacAddress,
+ (USHORT)IpxPacketSize,
+ IpxHeader,
+ IpxHeader+1);
+ }
+#endif
+
+#ifdef _PNP_POWER
+ IpxDereferenceAdapter(Adapter);
+ IpxDereferenceBinding1(Binding, BREF_ADAPTER_ACCESS);
+#endif
+
+ return NDIS_STATUS_SUCCESS;
+ }
+
+ DestinationSocket = *(USHORT UNALIGNED *)&IpxHeader->DestinationSocket;
+
+ //
+ // In order to have consistent local targets, copy over the target from the IpxHeader.
+ //
+ if (IsLoopback) {
+ IPX_DEBUG (LOOPB, ("Loopback packet copied the localtarget: %lx\n", IpxHeader->DestinationNode));
+ // RtlCopyMemory (DatagramOptions.LocalTarget.MacAddress, IpxHeader->DestinationNode, 6);
+
+ *((UNALIGNED ULONG *)DatagramOptions.LocalTarget.MacAddress) =
+ *((UNALIGNED ULONG *)IpxHeader->DestinationNode);
+
+ *((UNALIGNED USHORT *)(DatagramOptions.LocalTarget.MacAddress+4)) =
+ *((UNALIGNED USHORT *)(IpxHeader->DestinationNode+4));
+ }
+
+ ++Device->Statistics.PacketsReceived;
+
+ if (DestinationSocket != RIP_SOCKET) {
+
+ DestinationNetwork = *(UNALIGNED ULONG *)IpxHeader->DestinationNetwork;
+ DestinationNode = IpxHeader->DestinationNode;
+
+RecheckPacket:
+
+ if (Device->MultiCardZeroVirtual) {
+
+ if ((DestinationNetwork == Binding->LocalAddress.NetworkAddress) ||
+ (DestinationNetwork == 0)) {
+
+ if (IPX_NODE_EQUAL (DestinationNode, Binding->LocalAddress.NodeAddress)) {
+ IsBroadcast = FALSE;
+ goto DestinationOk;
+ } else {
+ if ((IsBroadcast = IPX_NODE_BROADCAST(DestinationNode)) &&
+ (Binding->ReceiveBroadcast)) {
+ goto DestinationOk;
+ }
+ }
+
+ //
+ // If this is a binding set slave, check for the master's
+ // address.
+ //
+
+ if ((Binding->BindingSetMember) &&
+ (IPX_NODE_EQUAL (DestinationNode, Binding->MasterBinding->LocalAddress.NodeAddress))) {
+ goto DestinationOk;
+ }
+
+ } else {
+ IsBroadcast = IPX_NODE_BROADCAST(DestinationNode);
+ }
+
+ } else {
+
+ if ((DestinationNetwork == Device->SourceAddress.NetworkAddress) ||
+ (DestinationNetwork == 0)) {
+
+ if (IPX_NODE_EQUAL (DestinationNode, Device->SourceAddress.NodeAddress)) {
+ IsBroadcast = FALSE;
+ goto DestinationOk;
+ } else {
+ if ((IsBroadcast = IPX_NODE_BROADCAST(DestinationNode)) &&
+ (Binding->ReceiveBroadcast)) {
+ goto DestinationOk;
+ }
+ }
+ } else {
+ IsBroadcast = IPX_NODE_BROADCAST(DestinationNode);
+ }
+
+ //
+ // We need to check for frames that are sent to the
+ // binding node and net, because if we have a virtual
+ // net we won't catch them in the check above. This
+ // will include any Netbios frames, since they don't
+ // use the virtual net. Doing the check like this will slow
+ // down netbios indications just a bit on a machine with
+ // a virtual network, but it saves a jump for other traffic
+ // vs. adding the check up there (the assumption is if we
+ // have a virtual net most traffic is NCP).
+ //
+ // Note that IsBroadcast is already set, so we don't have
+ // to do that.
+ //
+
+ if ((Device->VirtualNetwork) &&
+ ((DestinationNetwork == Binding->LocalAddress.NetworkAddress) ||
+ (DestinationNetwork == 0))) {
+
+ if (IPX_NODE_EQUAL (DestinationNode, Binding->LocalAddress.NodeAddress)) {
+ goto DestinationOk;
+ } else {
+ if (IsBroadcast && (Binding->ReceiveBroadcast)) {
+ goto DestinationOk;
+ }
+
+ }
+
+ //
+ // If this is a binding set slave, check for the master's
+ // address.
+ //
+
+ if ((Binding->BindingSetMember) &&
+ (IPX_NODE_EQUAL (DestinationNode, Binding->MasterBinding->LocalAddress.NodeAddress))) {
+ goto DestinationOk;
+ }
+ }
+ }
+
+ //
+ // If this was a loopback packet that was sent on the second binding (but showed back up on the first one),
+ // then the networknumbers will not match. Allow the receive on the first binding itself.
+ //
+ if (IsLoopback) {
+ IPX_DEBUG (LOOPB, ("Loopback packet forced on first binding: %lx\n", ReceiveContext));
+ goto DestinationOk;
+ }
+
+ //
+ // If we did not receive this packet, it might be because
+ // our network is still 0 and this packet was actually
+ // sent to the real network number. If so we try to
+ // update our local address, and if successful we
+ // re-check the packet. We don't insert if we are
+ // not done with auto detection, to avoid colliding
+ // with that.
+ //
+ // To avoid problems if we are a router, we only update
+ // on packets that are broadcast or sent to us.
+ //
+
+ if ((Binding->LocalAddress.NetworkAddress == 0) &&
+ (Device->AutoDetectState == AUTO_DETECT_STATE_DONE) &&
+ (DestinationNetwork != 0) &&
+ (IsBroadcast ||
+ IPX_NODE_EQUAL (DestinationNode, Binding->LocalAddress.NodeAddress))) {
+
+ CTEAssert (Binding->NicId != 0);
+
+ if (IpxUpdateBindingNetwork(
+ Device,
+ Binding,
+ DestinationNetwork) == STATUS_SUCCESS) {
+
+ IPX_DEBUG (RIP, ("Binding %d reconfigured to network %lx\n",
+ Binding->NicId,
+ REORDER_ULONG(Binding->LocalAddress.NetworkAddress)));
+
+ //
+ // Jump back and re-process the packet; we know
+ // we won't loop through here again because the
+ // binding's network is now non-zero.
+ //
+
+ goto RecheckPacket;
+
+ }
+ }
+
+
+ //
+ // The only frames that will not already have jumped to
+ // DestinationOk are those to or from the SAP socket,
+ // so we check for those.
+ //
+
+ if ((*(USHORT UNALIGNED *)&IpxHeader->SourceSocket == SAP_SOCKET) ||
+ (DestinationSocket == SAP_SOCKET)) {
+
+DestinationOk:
+
+ //
+ // An IPX packet sent to us, or a SAP packet (which
+ // are not sent to the virtual address but still need
+ // to be indicated and not forwarded to RIP).
+ //
+
+ if (DestinationSocket == NB_SOCKET) {
+#if DBG
+ ReceiveFlag = IPX_PACKET_LOG_RCV_NB | IPX_PACKET_LOG_RCV_ALL;
+#endif
+ if (((!IsBroadcast) || (Device->UpperDrivers[IDENTIFIER_NB].BroadcastEnable)) &&
+ (Device->UpperDriverBound[IDENTIFIER_NB])) {
+
+ if (!IsLoopback && Adapter->MacInfo.MediumType == NdisMedium802_5) {
+ MacUpdateSourceRouting (IDENTIFIER_NB, Adapter, Header, HeaderBufferSize);
+ }
+
+ //
+ // We add HeaderBufferSize to the IpxHeaderOffset field since we do an NdisCopyFromPacketToPacket
+ // in IpxTransferData, which needs offset from the beginning of the packet.
+ // NdisTransferData adds the offset passed in to the beginning of the IPX packet.
+ //
+ (*Device->UpperDrivers[IDENTIFIER_NB].ReceiveHandler)(
+ (IsLoopback) ? BindingContext : Adapter->NdisBindingHandle,
+ ReceiveContext,
+ &DatagramOptions.LocalTarget,
+ Adapter->MacInfo.MacOptions,
+ (PUCHAR)IpxHeader,
+ LookaheadBufferSize - IpxHeaderOffset,
+ (IsLoopback) ? IpxHeaderOffset+HeaderBufferSize : IpxHeaderOffset,
+ IpxPacketSize);
+
+ Device->ReceiveCompletePending[IDENTIFIER_NB] = TRUE;
+ }
+
+ //
+ // The router needs to see Netbios type 20 broadcasts.
+ //
+
+ if (IsBroadcast &&
+ (IpxHeader->PacketType == 0x14) &&
+ (Binding->ReceiveBroadcast)) {
+ goto RipIndication;
+ }
+
+ } else if (IpxHeader->PacketType == SPX_PACKET_TYPE) {
+
+#if DBG
+ ReceiveFlag = IPX_PACKET_LOG_RCV_SPX | IPX_PACKET_LOG_RCV_ALL;
+#endif
+
+ if (((!IsBroadcast) || (Device->UpperDrivers[IDENTIFIER_SPX].BroadcastEnable)) &&
+ (Device->UpperDriverBound[IDENTIFIER_SPX])) {
+
+ if (!IsLoopback && Adapter->MacInfo.MediumType == NdisMedium802_5) {
+ MacUpdateSourceRouting (IDENTIFIER_SPX, Adapter, Header, HeaderBufferSize);
+ }
+
+ (*Device->UpperDrivers[IDENTIFIER_SPX].ReceiveHandler)(
+ (IsLoopback) ? BindingContext : Adapter->NdisBindingHandle,
+ ReceiveContext,
+ &DatagramOptions.LocalTarget,
+ Adapter->MacInfo.MacOptions,
+ (PUCHAR)IpxHeader,
+ LookaheadBufferSize - IpxHeaderOffset,
+ (IsLoopback) ? IpxHeaderOffset+HeaderBufferSize : IpxHeaderOffset,
+ IpxPacketSize);
+
+ Device->ReceiveCompletePending[IDENTIFIER_SPX] = TRUE;
+ }
+
+ } else {
+
+ IPX_DEBUG (RECEIVE, ("Received packet type %d, length %d\n",
+ Binding->FrameType,
+ IpxPacketSize));
+ IPX_DEBUG (RECEIVE, ("Source %lx %2.2x-%2.2x-%2.2x-%2.2x %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x\n",
+ *(USHORT UNALIGNED *)&IpxHeader->SourceSocket,
+ IpxHeader->SourceNetwork[0],
+ IpxHeader->SourceNetwork[1],
+ IpxHeader->SourceNetwork[2],
+ IpxHeader->SourceNetwork[3],
+ IpxHeader->SourceNode[0],
+ IpxHeader->SourceNode[1],
+ IpxHeader->SourceNode[2],
+ IpxHeader->SourceNode[3],
+ IpxHeader->SourceNode[4],
+ IpxHeader->SourceNode[5]));
+ IPX_DEBUG (RECEIVE, ("Destination %d %2.2x-%2.2x-%2.2x-%2.2x %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x\n",
+ DestinationSocket,
+ IpxHeader->DestinationNetwork[0],
+ IpxHeader->DestinationNetwork[1],
+ IpxHeader->DestinationNetwork[2],
+ IpxHeader->DestinationNetwork[3],
+ IpxHeader->DestinationNode[0],
+ IpxHeader->DestinationNode[1],
+ IpxHeader->DestinationNode[2],
+ IpxHeader->DestinationNode[3],
+ IpxHeader->DestinationNode[4],
+ IpxHeader->DestinationNode[5]));
+
+#if DBG
+ if (IpxHeader->DestinationSocket == IpxPacketLogSocket) {
+ ReceiveFlag = IPX_PACKET_LOG_RCV_SOCKET | IPX_PACKET_LOG_RCV_OTHER | IPX_PACKET_LOG_RCV_ALL;
+ } else {
+ ReceiveFlag = IPX_PACKET_LOG_RCV_OTHER | IPX_PACKET_LOG_RCV_ALL;
+ }
+#endif
+
+ //
+ // Fiddle with this if so in the general case
+ // the jump is not made (BUGBUG the compiler
+ // still rearranges it).
+ //
+
+ if (Adapter->MacInfo.MediumType != NdisMedium802_5) {
+
+CallProcessDatagram:
+ //
+ // [SA] Returns a status now which needs to be returned to NDIS
+ // Also, MDL is passed in.
+ // We need to pass in the HeaderBufferSize too....
+ //
+ IpxProcessDatagram(
+ Device,
+ Adapter,
+ Binding,
+ ReceiveContext,
+ &DatagramOptions,
+ (PUCHAR)IpxHeader,
+ LookaheadBufferSize - IpxHeaderOffset,
+ (IsLoopback) ? IpxHeaderOffset+HeaderBufferSize : IpxHeaderOffset, // lookaheadbufferoffset
+ IpxPacketSize,
+ IsBroadcast,
+ pTdiClientCount,
+ HeaderBufferSize,
+ pMdl,
+ BindingContext);
+
+ } else {
+ if (!IsLoopback) {
+ MacUpdateSourceRouting (IDENTIFIER_IPX, Adapter, Header, HeaderBufferSize);
+ }
+ goto CallProcessDatagram;
+ }
+
+ //
+ // The router needs to see type 20 broadcasts.
+ //
+
+ if (IsBroadcast &&
+ (IpxHeader->PacketType == 0x14) &&
+ (Binding->ReceiveBroadcast)) {
+ goto RipIndication;
+ }
+ }
+
+ } else {
+
+#if DBG
+ ReceiveFlag = IPX_PACKET_LOG_RCV_ALL;
+#endif
+
+ //
+ // We need to let non-type 20 broadcast frames go to RIP to allow for lan-specific
+ // broadcasts. For logon over IPX, this allows the logon request to get thru the WAN
+ // line.
+ //
+ // if ( !IsBroadcast ) {
+
+RipIndication:;
+
+ if (Device->UpperDriverBound[IDENTIFIER_RIP]) {
+
+ if (!IsLoopback && Adapter->MacInfo.MediumType == NdisMedium802_5) {
+ MacUpdateSourceRouting (IDENTIFIER_RIP, Adapter, Header, HeaderBufferSize);
+ }
+
+ //
+ // We hide binding sets from the router, to avoid
+ // misordering packets which it routes.
+ //
+
+ if (!IsLoopback && Binding->BindingSetMember) {
+#ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(&DatagramOptions.LocalTarget, MIN (Device->MaxBindings, Binding->MasterBinding->NicId));
+#else
+ DatagramOptions.LocalTarget.NicId = Binding->MasterBinding->NicId;
+#endif
+ }
+
+ (*Device->UpperDrivers[IDENTIFIER_RIP].ReceiveHandler)(
+ (IsLoopback) ? BindingContext : Adapter->NdisBindingHandle,
+ ReceiveContext,
+ &DatagramOptions.LocalTarget,
+ Adapter->MacInfo.MacOptions,
+ (PUCHAR)IpxHeader,
+ LookaheadBufferSize - IpxHeaderOffset,
+ (IsLoopback) ? IpxHeaderOffset+HeaderBufferSize : IpxHeaderOffset,
+ IpxPacketSize);
+
+ Device->ReceiveCompletePending[IDENTIFIER_RIP] = TRUE;
+ }
+ // }
+ }
+
+ } else {
+
+ if ((Binding->ReceiveBroadcast) ||
+ (!IPX_NODE_BROADCAST(IpxHeader->DestinationNode))) {
+
+ SourceNetwork = *(UNALIGNED LONG *)IpxHeader->SourceNetwork;
+
+ //
+ // Sent to the RIP socket; check if this binding needs a
+ // network number.
+ //
+
+ if ((Binding->LocalAddress.NetworkAddress == 0) &&
+ ((SourceNetwork = *(UNALIGNED LONG *)IpxHeader->SourceNetwork) != 0)) {
+
+ switch (Device->AutoDetectState) {
+
+ case AUTO_DETECT_STATE_DONE:
+
+ //
+ // We are done with auto-detect and running.
+ // Make sure this packet is useful. If the source
+ // MAC address and source IPX node are the same then
+ // it was not routed, and we also check that it is not
+ // an IPX broadcast (otherwise a misconfigured client
+ // might confuse us).
+ //
+
+ if ((RtlEqualMemory(
+ IpxHeader->SourceNode,
+ DatagramOptions.LocalTarget.MacAddress,
+ 6)) &&
+ (*(UNALIGNED ULONG *)(IpxHeader->DestinationNode) != 0xffffffff) &&
+ (*(UNALIGNED USHORT *)(IpxHeader->DestinationNode+4) != 0xffff)) {
+
+ CTEAssert (Binding->NicId != 0);
+
+ if (IpxUpdateBindingNetwork(
+ Device,
+ Binding,
+ *(UNALIGNED LONG *)IpxHeader->SourceNetwork) == STATUS_SUCCESS) {
+
+ IPX_DEBUG (RIP, ("Binding %d is network %lx\n",
+ Binding->NicId,
+ REORDER_ULONG(Binding->LocalAddress.NetworkAddress)));
+
+ }
+ }
+
+ break;
+
+ case AUTO_DETECT_STATE_RUNNING:
+
+ //
+ // We are waiting for rip responses to figure out our
+ // network number. We count the responses that match
+ // and do not match our current value; when the non-
+ // matching number exceeds it we switch (to whatever
+ // this frame happens to have). Note that on the first
+ // non-zero response this will be the case and we will
+ // switch to that network.
+ //
+ // After auto-detect is done we call RipInsertLocalNetwork
+ // for whatever the current network is on each binding.
+ //
+
+ if (SourceNetwork == Binding->TentativeNetworkAddress) {
+
+ ++Binding->MatchingResponses;
+
+ } else {
+
+ ++Binding->NonMatchingResponses;
+
+ if (Binding->NonMatchingResponses > Binding->MatchingResponses) {
+
+ IPX_DEBUG (AUTO_DETECT, ("Switching to net %lx on %lx (%d - %d)\n",
+ REORDER_ULONG(SourceNetwork),
+ Binding,
+ Binding->NonMatchingResponses,
+ Binding->MatchingResponses));
+
+ Binding->TentativeNetworkAddress = SourceNetwork;
+ Binding->MatchingResponses = 1;
+ Binding->NonMatchingResponses = 0;
+ }
+
+ }
+
+ //
+ // If we are auto-detecting and we have just found
+ // a default, set this so that RIP stops trying
+ // to auto-detect on other nets. BUGBUG: Unless we
+ // are on a server doing multiple detects.
+ //
+
+ if (Binding->DefaultAutoDetect) {
+ Adapter->DefaultAutoDetected = TRUE;
+ }
+ Adapter->AutoDetectResponse = TRUE;
+
+ break;
+
+ default:
+
+ //
+ // We are still initializing, or are processing auto-detect
+ // responses, not the right time to start updating stuff.
+ //
+
+ break;
+
+ }
+
+ }
+
+
+ //
+ // See if any packets are waiting for a RIP response.
+ //
+
+ if (Device->RipPacketCount > 0) {
+
+ RIP_PACKET UNALIGNED * RipPacket = (RIP_PACKET UNALIGNED *)(IpxHeader+1);
+
+ if ((IpxPacketSize >= sizeof(IPX_HEADER) + sizeof(RIP_PACKET)) &&
+ (RipPacket->Operation == RIP_RESPONSE) &&
+ (RipPacket->NetworkEntry.NetworkNumber != 0xffffffff)) {
+
+ RipProcessResponse(
+ Device,
+ &DatagramOptions.LocalTarget,
+ RipPacket);
+ }
+ }
+
+
+ //
+ // See if this is a RIP response for our virtual network
+ // and we are the only person who could respond to it.
+ // We also respond to general queries on WAN lines since
+ // we are the only machine on it.
+ //
+
+ if (Device->RipResponder) {
+
+ PRIP_PACKET RipPacket =
+ (PRIP_PACKET)(IpxHeader+1);
+
+ if ((IpxPacketSize >= sizeof(IPX_HEADER) + sizeof(RIP_PACKET)) &&
+ (RipPacket->Operation == RIP_REQUEST) &&
+ ((RipPacket->NetworkEntry.NetworkNumber == Device->VirtualNetworkNumber) ||
+ (Adapter->MacInfo.MediumAsync && (RipPacket->NetworkEntry.NetworkNumber == 0xffffffff)))) {
+
+ //
+ // Update this so our response goes out correctly.
+ //
+
+ if (!IsLoopback && Adapter->MacInfo.MediumType == NdisMedium802_5) {
+ MacUpdateSourceRouting (IDENTIFIER_IPX, Adapter, Header, HeaderBufferSize);
+ }
+
+ RipSendResponse(
+ Binding,
+ (TDI_ADDRESS_IPX UNALIGNED *)(IpxHeader->SourceNetwork),
+ &DatagramOptions.LocalTarget);
+ }
+ }
+
+#if DBG
+ ReceiveFlag = IPX_PACKET_LOG_RCV_RIP | IPX_PACKET_LOG_RCV_ALL;
+#endif
+
+ //
+ // See if the RIP upper driver wants it too.
+ //
+
+ goto RipIndication;
+ }
+
+ }
+
+
+#ifdef _PNP_POWER
+ IpxDereferenceAdapter(Adapter);
+ IpxDereferenceBinding1(Binding, BREF_ADAPTER_ACCESS);
+#endif
+
+#ifdef IPX_PACKET_LOG
+ if (PACKET_LOG(ReceiveFlag)) {
+ IpxLogPacket(
+ FALSE,
+ DestMacAddress,
+ DatagramOptions.LocalTarget.MacAddress,
+ (USHORT)IpxPacketSize,
+ IpxHeader,
+ IpxHeader+1);
+ }
+#endif
+ return NDIS_STATUS_SUCCESS;
+
+ //
+ // These are the failure routines for the various media types.
+ // They only differ in the debug logging.
+ //
+
+NotValid802_3:
+
+#ifdef _PNP_POWER
+
+ IpxDereferenceAdapter(Adapter);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+
+#ifdef IPX_PACKET_LOG
+ if (PACKET_LOG(IPX_PACKET_LOG_RCV_ALL)) {
+ IpxLogPacket(FALSE, Header, Header+6, (USHORT)PacketSize, LookaheadBuffer, (PUCHAR)LookaheadBuffer + sizeof(IPX_HEADER));
+ }
+#endif
+ return NDIS_STATUS_SUCCESS;
+
+NotValid802_5:
+
+#ifdef _PNP_POWER
+
+ IpxDereferenceAdapter(Adapter);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+#ifdef IPX_PACKET_LOG
+ if (PACKET_LOG(IPX_PACKET_LOG_RCV_ALL)) {
+ IpxLogPacket(FALSE, Header+2, Header+8, (USHORT)PacketSize, LookaheadBuffer, (PUCHAR)LookaheadBuffer + sizeof(IPX_HEADER));
+ }
+#endif
+ return NDIS_STATUS_SUCCESS;
+
+NotValidFddi:
+
+#ifdef _PNP_POWER
+
+ IpxDereferenceAdapter(Adapter);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+NotValidLoopback:
+
+#ifdef IPX_PACKET_LOG
+ if (PACKET_LOG(IPX_PACKET_LOG_RCV_ALL)) {
+ IpxLogPacket(FALSE, Header+1, Header+7, (USHORT)PacketSize, LookaheadBuffer, (PUCHAR)LookaheadBuffer + sizeof(IPX_HEADER));
+ }
+#endif
+
+ return NDIS_STATUS_SUCCESS;
+
+} /* IpxReceiveIndication */
+
+
+VOID
+IpxReceiveComplete(
+ IN NDIS_HANDLE BindingContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine receives control from the physical provider as an
+ indication that a connection(less) frame has been received on the
+ physical link. We dispatch to the correct packet handler here.
+
+Arguments:
+
+ BindingContext - The Adapter Binding specified at initialization time.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ PADAPTER Adapter = (PADAPTER)BindingContext;
+ PREQUEST Request;
+ PADDRESS_FILE AddressFile;
+ PLIST_ENTRY linkage;
+
+
+ //
+ // Complete all pending receives. Do a quick check
+ // without the lock.
+ //
+
+ while (!IsListEmpty (&Adapter->RequestCompletionQueue)) {
+
+ linkage = IPX_REMOVE_HEAD_LIST(
+ &Adapter->RequestCompletionQueue,
+ Adapter->DeviceLock);
+
+ if (!IPX_LIST_WAS_EMPTY (&Adapter->RequestCompletionQueue, linkage)) {
+
+ Request = LIST_ENTRY_TO_REQUEST(linkage);
+ AddressFile = REQUEST_OPEN_CONTEXT(Request);
+
+ IPX_DEBUG (RECEIVE, ("Completing RDG on %lx\n", AddressFile));
+
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ IpxCompleteRequest(Request);
+ IpxFreeRequest(Adapter->Device, Request);
+
+ IpxDereferenceAddressFileSync (AddressFile, AFREF_RCV_DGRAM);
+
+ } else {
+
+ //
+ // IPX_REMOVE_HEAD_LIST returned nothing, so don't
+ // bother looping back.
+ //
+
+ break;
+
+ }
+
+ }
+
+ //
+ // Unwind this loop for speed.
+ //
+
+ if (IpxDevice->AnyUpperDriverBound) {
+
+ PDEVICE Device = IpxDevice;
+
+ if ((Device->UpperDriverBound[0]) &&
+ (Device->ReceiveCompletePending[0])) {
+
+ (*Device->UpperDrivers[0].ReceiveCompleteHandler)(
+ (USHORT)1); // BUGBUG: Fix NIC ID or remove.
+ Device->ReceiveCompletePending[0] = FALSE;
+
+ }
+
+ if ((Device->UpperDriverBound[1]) &&
+ (Device->ReceiveCompletePending[1])) {
+
+ (*Device->UpperDrivers[1].ReceiveCompleteHandler)(
+ (USHORT)1); // BUGBUG: Fix NIC ID or remove.
+ Device->ReceiveCompletePending[1] = FALSE;
+
+ }
+
+ if ((Device->UpperDriverBound[2]) &&
+ (Device->ReceiveCompletePending[2])) {
+
+ (*Device->UpperDrivers[2].ReceiveCompleteHandler)(
+ (USHORT)1); // BUGBUG: Fix NIC ID or remove.
+ Device->ReceiveCompletePending[2] = FALSE;
+
+ }
+
+ }
+
+} /* IpxReceiveComplete */
+
+
+NTSTATUS
+IpxUpdateBindingNetwork(
+ IN PDEVICE Device,
+ IN PBINDING Binding,
+ IN ULONG Network
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when we have decided that we now know
+ the network number for a binding which we previously thought
+ was zero.
+
+Arguments:
+
+ Device - The IPX device.
+
+ Binding - The binding being updated.
+
+ Network - The new network number.
+
+Return Value:
+
+ The status of the operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PADDRESS Address;
+ ULONG CurrentHash;
+ PLIST_ENTRY p;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+
+ //
+ // Only binding set members should have these different,
+ // and they will not have a network of 0.
+ //
+
+ Status = RipInsertLocalNetwork(
+ Network,
+ Binding->NicId,
+ Binding->Adapter->NdisBindingHandle,
+ (USHORT)((839 + Binding->MediumSpeed) / Binding->MediumSpeed));
+
+ if (Status == STATUS_SUCCESS) {
+
+ Binding->LocalAddress.NetworkAddress = Network;
+
+ //
+ // Update the device address if we have no virtual net
+ // and there is one binding (!Device->MultiCardZeroVirtual)
+ // or this is the first binding, which is the one we
+ // appear to be if a) we have no virtual net defined and
+ // b) we are bound to multiple cards.
+ //
+#ifdef _PNP_POWER
+
+ if ((!Device->MultiCardZeroVirtual) || (Binding->NicId == 1)) {
+
+ if (!Device->VirtualNetwork) {
+
+ Device->SourceAddress.NetworkAddress = Network;
+
+ //
+ // Scan through all the addresses that exist and modify
+ // their pre-constructed local IPX address to reflect
+ // the new local net and node.
+ //
+
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+
+ for (CurrentHash = 0; CurrentHash < IPX_ADDRESS_HASH_COUNT; CurrentHash++) {
+
+ for (p = Device->AddressDatabases[CurrentHash].Flink;
+ p != &Device->AddressDatabases[CurrentHash];
+ p = p->Flink) {
+
+ Address = CONTAINING_RECORD (p, ADDRESS, Linkage);
+
+ Address->LocalAddress.NetworkAddress = Network;
+ }
+ }
+
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+
+ //
+ // Let SPX know because it fills in its own headers.
+ //
+ if (Device->UpperDriverBound[IDENTIFIER_SPX]) {
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+ IPX_PNP_INFO IpxPnPInfo;
+
+ IpxPnPInfo.NewReservedAddress = TRUE;
+ IpxPnPInfo.NetworkAddress = Network;
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, Binding->LocalAddress.NodeAddress, 6);
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, Binding->NicId);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ //
+ // give the PnP indication
+ //
+ (*Device->UpperDrivers[IDENTIFIER_SPX].PnPHandler) (
+ IPX_PNP_ADDRESS_CHANGE,
+ &IpxPnPInfo);
+
+ IPX_DEBUG(AUTO_DETECT, ("IPX_PNP_ADDRESS_CHANGED to SPX: net addr: %lx\n", Network));
+ }
+
+ }
+ }
+#else
+ if ((!Device->VirtualNetwork) &&
+ ((!Device->MultiCardZeroVirtual) || (Binding->NicId == 1))) {
+
+ Device->SourceAddress.NetworkAddress = Network;
+
+ //
+ // Scan through all the addresses that exist and modify
+ // their pre-constructed local IPX address to reflect
+ // the new local net and node.
+ //
+
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+
+ for (CurrentHash = 0; CurrentHash < IPX_ADDRESS_HASH_COUNT; CurrentHash++) {
+
+ for (p = Device->AddressDatabases[CurrentHash].Flink;
+ p != &Device->AddressDatabases[CurrentHash];
+ p = p->Flink) {
+
+ Address = CONTAINING_RECORD (p, ADDRESS, Linkage);
+
+ Address->LocalAddress.NetworkAddress = Network;
+ }
+ }
+
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+
+ //
+ // Let SPX know because it fills in its own
+ // headers. When we indicate a line up on NIC ID
+ // 0 it knows to requery the local address.
+ //
+ // BUGBUG: Line up indication to RIP/NB??
+ //
+
+ if (Device->UpperDriverBound[IDENTIFIER_SPX]) {
+
+ IPX_LINE_INFO LineInfo;
+ LineInfo.LinkSpeed = Device->LinkSpeed;
+ LineInfo.MaximumPacketSize =
+ Device->Information.MaximumLookaheadData + sizeof(IPX_HEADER);
+ LineInfo.MaximumSendSize =
+ Device->Information.MaxDatagramSize + sizeof(IPX_HEADER);
+ LineInfo.MacOptions = Device->MacOptions;
+
+ (*Device->UpperDrivers[IDENTIFIER_SPX].LineUpHandler)(
+ 0,
+ &LineInfo,
+ Binding->Adapter->MacInfo.RealMediumType,
+ NULL);
+
+ }
+ }
+#endif
+ } else if (Status == STATUS_DUPLICATE_NAME) {
+
+ //
+ // If it was a duplicate we still set the binding's local
+ // address to the value so we can detect binding sets.
+ //
+
+ Binding->LocalAddress.NetworkAddress = Network;
+
+ }
+
+ return Status;
+
+} /* IpxUpdateBindingNetwork */
+
+
+INT
+IpxReceivePacket (
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_PACKET Packet
+ )
+/*++
+
+Routine Description:
+
+ This routine receives control from the physical provider as an
+ indication that a frame has been received on the physical link.
+ The packet passed up from NDIS can be held on to by the TDI clients
+ that request TDI_EVENT_RECEIVE_EX_DATAGRAM events with us.
+
+Arguments:
+
+ ProtocolBindingContext - The Adapter Binding specified at initialization time.
+
+ Packet - contains the packet received as well as some mediaspecific info.
+
+Return Value:
+
+ return of IpxReceiveIndicationNew(),
+
+--*/
+{
+ UINT HeaderBufferSize = NDIS_GET_PACKET_HEADER_SIZE(Packet);
+ UINT firstbufferLength, bufferLength;
+ PNDIS_BUFFER pFirstBuffer;
+ PUCHAR headerBuffer;
+ NTSTATUS ntStatus;
+ INT tdiClientCount = 0;
+
+ //
+ // Query the number of buffers, the first MDL's descriptor and the packet length
+ //
+ NdisGetFirstBufferFromPacket(Packet, // packet
+ &pFirstBuffer, // first buffer descriptor
+ &headerBuffer, // ptr to the start of packet
+ &firstbufferLength,// length of the header+lookahead
+ &bufferLength); // length of the bytes in the buffers
+
+ //
+ // ReceiveContext is the packet itself
+ //
+
+ ntStatus = IpxReceiveIndicationNew (
+ ProtocolBindingContext,
+ Packet, // ReceiveContext
+ headerBuffer,
+ HeaderBufferSize,
+ headerBuffer + HeaderBufferSize, // LookaheadBuffer
+ bufferLength - HeaderBufferSize, // LookaheadBufferSize
+ bufferLength - HeaderBufferSize, // PacketSize - since the whole packet is indicated
+ pFirstBuffer, // pMdl
+ &tdiClientCount // tdi client count
+ );
+
+ IPX_DEBUG(RECEIVE, ("IpxReceivePacket: Tdi Client Count is: %lx\n", tdiClientCount));
+
+ return tdiClientCount;
+} /* IpxReceivePacket */
+
+
+#ifdef _PNP_POWER
+
+#if defined(_M_IX86)
+_inline
+#endif
+BOOLEAN
+IpxNewVirtualNetwork(
+ IN PDEVICE Device,
+ IN BOOLEAN NewVirtualNetwork
+ )
+/*++
+
+Routine Description:
+
+ If the virtualnetwork number changed, this function records this fact
+ in the device.
+
+ Called with the BINDACCESSLOCK held.
+Arguments:
+
+ Device - Pointer to the Device.
+
+ NewVirtualNetwork - boolean to indicate if the virtual net# changed.
+
+Return Value:
+
+ BOOLEAN - to indicate whether SPX's reserved address was changed.
+
+--*/
+{
+ NTSTATUS ntStatus;
+ UCHAR VirtualNode[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 };
+ BOOLEAN ReservedAddrChanged = FALSE;
+
+ if (Device->VirtualNetworkNumber) {
+
+ if (NewVirtualNetwork) {
+ //
+ // If a new one appeared.
+ //
+
+ ntStatus = RipInsertLocalNetwork(
+ Device->VirtualNetworkNumber,
+ 0, // NIC ID
+ NIC_ID_TO_BINDING(Device, 1)->Adapter->NdisBindingHandle,
+ 1);
+
+ if (ntStatus != STATUS_SUCCESS) {
+
+ //
+ // Log the appropriate error, then ignore the
+ // virtual network. If the error was
+ // INSUFFICIENT_RESOURCES, the RIP module
+ // will have already logged an error.
+ //
+
+ if (ntStatus == STATUS_DUPLICATE_NAME) {
+
+ IPX_DEBUG (AUTO_DETECT, ("Ignoring virtual network %lx, conflict\n", REORDER_ULONG (Device->VirtualNetworkNumber)));
+
+ IpxWriteResourceErrorLog(
+ Device->DeviceObject,
+ EVENT_IPX_INTERNAL_NET_INVALID,
+ 0,
+ REORDER_ULONG (Device->VirtualNetworkNumber));
+ }
+
+ Device->VirtualNetworkNumber = 0;
+ goto NoVirtualNetwork;
+
+ }
+
+ //
+ // If the number is non-zero now, a new one appeared
+ //
+ Device->VirtualNetwork = TRUE;
+ Device->MultiCardZeroVirtual = FALSE;
+ RtlCopyMemory(Device->SourceAddress.NodeAddress, VirtualNode, 6);
+ Device->SourceAddress.NetworkAddress = Device->VirtualNetworkNumber;
+ ReservedAddrChanged = TRUE;
+
+ //
+ // If RIP is not bound, then this node is a RipResponder
+ //
+ if (!Device->UpperDriverBound[IDENTIFIER_RIP]) {
+ Device->RipResponder = TRUE;
+ }
+ }
+
+ } else {
+NoVirtualNetwork:
+ Device->VirtualNetwork = FALSE;
+
+ //
+ // See if we need to be set up for the fake
+ // virtual network.
+ //
+
+ if (Device->ValidBindings > 1) {
+
+ CTEAssert (Device->VirtualNetworkOptional);
+
+ //
+ // In this case we return as our local node the
+ // address of the first card. We will also only
+ // direct SAP sends to that card.
+ //
+
+ Device->MultiCardZeroVirtual = TRUE;
+
+ } else {
+
+ Device->MultiCardZeroVirtual = FALSE;
+ }
+
+ if (NewVirtualNetwork) {
+ //
+ // The virtual network number disappeared this time
+ //
+
+ //
+ // Remove the prev. net # from the RIP tables here
+ //
+ RipAdjustForBindingChange (0, 0, IpxBindingDeleted);
+
+ //
+ // If we were a RipResponder, we are not anymore
+ //
+ if (Device->RipResponder) {
+ Device->RipResponder = FALSE;
+ }
+ }
+
+ //
+ // Since there is not virtual network number, SPX's reserved address is
+ // the address of the first binding. This could have changed because of
+ // several reasons: if there was a WAN binding only earlier and this time
+ // a LAN binding appeared, or if the first LAN binding disappeared. Instead
+ // of checking for all these conditions, check if the Device's sourceaddress
+ // and that of the first mis-match.
+ // NB uses the address of the first device always and hence does not need
+ // this mechanism to determine if this is a reserved address change.
+ //
+ if (!RtlEqualMemory( &Device->SourceAddress,
+ &NIC_ID_TO_BINDING(Device, 1)->LocalAddress,
+ FIELD_OFFSET(TDI_ADDRESS_IPX,Socket))) {
+
+ RtlCopyMemory( &Device->SourceAddress,
+ &NIC_ID_TO_BINDING(Device, 1)->LocalAddress,
+ FIELD_OFFSET(TDI_ADDRESS_IPX,Socket));
+
+ ReservedAddrChanged = TRUE;
+ }
+ }
+
+ return ReservedAddrChanged;
+}
+
+
+VOID
+IpxBindAdapter(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE BindContext,
+ IN PNDIS_STRING DeviceName,
+ IN PVOID SystemSpecific1,
+ IN PVOID SystemSpecific2
+ )
+
+/*++
+
+Routine Description:
+
+ This routine receives a Plug and Play notification about a new
+ adapter in the machine. We are called here only if this adapter
+ is to be bound to us, so we don't make any checks for this.
+
+Arguments:
+
+ Status - NDIS_STATUS_SUCCESS, NDIS_STATUS_PENDING
+
+ BindContext - context to represent this bind indication
+
+ DeviceName - Name of the adapter that appeared (e.g. \Device\Lance1)
+
+ SystemSpecific1/2 - Not used here
+
+Return Value:
+
+ Status - NDIS_STATUS_SUCCESS
+
+--*/
+{
+ NTSTATUS ntStatus;
+ PDEVICE Device = IpxDevice;
+ PADAPTER Adapter = NULL;
+ CONFIG Config;
+ UINT i;
+ ULONG Temp, SuccessfulOpens=0;
+ PBINDING Binding;
+ BINDING_CONFIG ConfigBinding;
+ ULONG ValidBindings;
+ USHORT AutoDetectReject;
+ BOOLEAN NewVirtualNetwork = FALSE;
+ BOOLEAN FirstDevice = FALSE;
+ BOOLEAN ReservedAddrChanged = FALSE;
+ IPX_PNP_INFO IpxPnPInfo;
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+ IPX_DEFINE_LOCK_HANDLE(LockHandle)
+
+ //
+ // Used for error logging
+ //
+ Config.DriverObject = (PDRIVER_OBJECT)Device->DeviceObject;
+
+ Config.RegistryPathBuffer = Device->RegistryPathBuffer;
+ ConfigBinding.AdapterName = *DeviceName;
+
+ //
+ // Read the registry to see if a virtual network number appeared/disappeared
+ //
+ ntStatus = IpxPnPGetVirtualNetworkNumber(&Config);
+
+ if (ntStatus != STATUS_SUCCESS) {
+ IPX_DEBUG(PNP, ("Could not read the vnet#: registrypathbuffer: %lx\n", Device->RegistryPathBuffer));
+ *Status = NDIS_STATUS_SUCCESS;
+ return;
+ }
+
+ Temp = REORDER_ULONG (Config.Parameters[CONFIG_VIRTUAL_NETWORK]);
+
+ //
+ // If the virtual network number changed, record this fact.
+ //
+ if (Device->VirtualNetworkNumber != Temp) {
+ NewVirtualNetwork = TRUE;
+ Device->VirtualNetworkNumber = Temp;
+ }
+
+ Device->VirtualNetworkOptional = (BOOLEAN)(Config.Parameters[CONFIG_VIRTUAL_OPTIONAL] != 0);
+
+ IPX_DEBUG(PNP, ("Virtual net # is: %lx\n", Temp));
+
+ //
+ // For each FrameType and Network Number configured, initialize the
+ // FrameType array in the CONFIG_BINDING
+ //
+ ntStatus = IpxPnPGetAdapterParameters(
+ &Config,
+ DeviceName,
+ &ConfigBinding);
+
+ if (ntStatus != STATUS_SUCCESS) {
+ IPX_DEBUG(PNP, ("Could not read the adapter params: DeviceName: %lx\n", DeviceName->Buffer));
+ *Status = NDIS_STATUS_SUCCESS;
+ return;
+ }
+
+ IPX_DEBUG(PNP, ("ConfigBinding.FrameTypeCount: %lx\n", ConfigBinding.FrameTypeCount));
+
+ //
+ // Reset the auto-detect state to init so that if a receive occurs on this binding
+ // before we can place this binding in the device's binding array, we know of it.
+ //
+ Device->AutoDetectState = AUTO_DETECT_STATE_INIT;
+
+ //
+ // Register adapter with NDIS; query the various parameters; get the WAN line count
+ // if this is a WAN adapter.
+ // Allocate the bindings corresponding to this adapter
+ //
+ for (i = 0; i < ConfigBinding.FrameTypeCount; i++) {
+
+ //
+ // If successful, this queues them on Device->InitialBindingList. [BUGBUGZZ] not right now
+ // Adapter is NULL first time and is allocated then. In subsequent calls,
+ // it is not NULL and the bindings are hooked to this adapter.
+
+ ntStatus = IpxBindToAdapter (Device, &ConfigBinding, &Adapter, i);
+
+ //
+ // If this failed because the adapter could not be bound
+ // to, then don't try any more frame types on this adapter.
+ // For other failures we do try the other frame types.
+ //
+
+ if (ntStatus == STATUS_DEVICE_DOES_NOT_EXIST) {
+ break;
+ }
+
+ //
+ // If the status is STATUS_NOT_SUPPORTED, then this frametype mapped to a previously
+ // initialized one. In this case, remove this index fron the FrameType array so that
+ // when we try to update the binding array, we dont have duplicates.
+ //
+ if (ntStatus == STATUS_NOT_SUPPORTED) {
+ ULONG j;
+
+ //
+ // Remove this frametype from the FrameType array.
+ //
+ for (j = i+1; j < ConfigBinding.FrameTypeCount; j++) {
+ ConfigBinding.FrameType[j-1] = ConfigBinding.FrameType[j];
+ }
+
+ --ConfigBinding.FrameTypeCount;
+
+ //
+ // Decrement so we see the one just moved up.
+ //
+ --i;
+
+#if DBG
+ for (j = 0; j < ISN_FRAME_TYPE_MAX; j++) {
+ IPX_DEBUG (AUTO_DETECT, ("%d: type %d, net %d, auto %d\n",
+ j, ConfigBinding.FrameType[j], ConfigBinding.NetworkNumber[j], ConfigBinding.AutoDetect[j]));
+ }
+#endif
+ continue;
+ }
+
+ if (ntStatus != STATUS_SUCCESS) {
+ continue;
+ }
+
+ if (ConfigBinding.AutoDetect[i]) {
+ Device->AutoDetect = TRUE;
+ }
+
+ CTEAssert(Adapter);
+
+ ++SuccessfulOpens;
+
+ //
+ // Even for WAN adapters, the FrameTypeCount is set to 4. We only need to
+ // allocate one binding for WAN; the others come later.
+ //
+ if (Adapter->MacInfo.MediumAsync) {
+ break;
+ }
+ }
+
+ if (SuccessfulOpens == 0) {
+ goto InitFailed;
+ }
+
+ //
+ // Place all the bindings corresponding to this adapter in the binding array
+ // Also resolve binding sets for non-autodetect bindings.
+ //
+
+ //
+ // Obtain lock to the Binding related stuff.
+ //
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ IpxPnPUpdateBindingArray (Device, Adapter, &ConfigBinding);
+
+ //
+ // Release access to the Binding related stuff.
+ //
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ //
+ // If at least one card appeared here, set our state
+ // to open
+ //
+ // [BUGBUGZZ]: what if all these bindings are eliminated - then
+ // the state is not open...
+ //
+ if (Device->ValidBindings > 0) {
+ if (Device->State == DEVICE_STATE_LOADED) {
+ FirstDevice = TRUE;
+ Device->State = DEVICE_STATE_OPEN;
+ }
+ }
+
+ //
+ // We don't do auto-detect/bindingsets for WAN lines: skip over.
+ //
+ if (Adapter->MacInfo.MediumAsync) {
+ goto jump_wan;
+ }
+
+ //
+ // Auto-detect the network number. Update the results for only the
+ // bindings corresponding to this adapter
+ //
+
+ //
+ // Queue a request to discover our locally attached
+ // adapter addresses. This must succeed because we
+ // just allocated our send packet pool. We need
+ // to wait for this, either because we are
+ // auto-detecting or because we need to determine
+ // if there are multiple cards on the same network.
+ //
+
+ KeInitializeEvent(
+ &Device->AutoDetectEvent,
+ NotificationEvent,
+ FALSE
+ );
+
+ Device->AutoDetectState = AUTO_DETECT_STATE_RUNNING;
+
+ //
+ // Make this 0; after we are done waiting, which means
+ // the packet has been completed, we set it to the
+ // correct value.
+ //
+
+ // Device->IncludedHeaderOffset = 0;
+
+ IPX_BEGIN_SYNC (&SyncContext);
+ ntStatus = RipQueueRequest (0xffffffff, RIP_REQUEST);
+ IPX_END_SYNC (&SyncContext);
+
+ CTEAssert (ntStatus == STATUS_PENDING);
+
+ //
+ // This is set when this rip send completes.
+ //
+
+ IPX_DEBUG (AUTO_DETECT, ("Waiting for AutoDetectEvent\n"));
+
+ KeWaitForSingleObject(
+ &Device->AutoDetectEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+
+ Device->AutoDetectState = AUTO_DETECT_STATE_PROCESSING;
+
+ //
+ // Now that we are done receiving responses, insert the
+ // current network number for every auto-detect binding
+ // to the rip database.
+ //
+
+ //
+ // Obtain exclusive access to the Binding related stuff.
+ //
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ //
+ // Note, here we go thru' only the bindings corresponding to this adapter
+ //
+ for (i = 0; i < ISN_FRAME_TYPE_MAX; i++) {
+
+ Binding = Adapter->Bindings[i];
+
+ //
+ // Skip empty binding slots or bindings that were configured
+ // for a certain network number, we inserted those above.
+ // If no network number was detected, also skip it.
+ //
+
+ if ((!Binding) ||
+ (Binding->ConfiguredNetworkNumber != 0) ||
+ (Binding->TentativeNetworkAddress == 0)) {
+
+ continue;
+ }
+
+ IPX_DEBUG (AUTO_DETECT, ("Final score for %lx on %lx is %d - %d\n",
+ REORDER_ULONG(Binding->TentativeNetworkAddress),
+ Binding,
+ Binding->MatchingResponses,
+ Binding->NonMatchingResponses));
+
+ //
+ // We don't care about the status.
+ //
+
+ ntStatus = RipInsertLocalNetwork(
+ Binding->TentativeNetworkAddress,
+ Binding->NicId,
+ Binding->Adapter->NdisBindingHandle,
+ (USHORT)((839 + Binding->MediumSpeed) / Binding->MediumSpeed));
+
+ if ((ntStatus != STATUS_SUCCESS) &&
+ (ntStatus != STATUS_DUPLICATE_NAME)) {
+
+ //
+ // We failed to insert, keep it at zero, hopefully
+ // we will be able to update later.
+ //
+
+#if DBG
+ DbgPrint ("IPX: Could not insert net %lx for binding %lx\n",
+ REORDER_ULONG(Binding->LocalAddress.NetworkAddress),
+ Binding);
+#endif
+ CTEAssert (Binding->LocalAddress.NetworkAddress == 0);
+
+ } else {
+
+ Binding->LocalAddress.NetworkAddress = Binding->TentativeNetworkAddress;
+ }
+
+ Binding->LocalAddress.NetworkAddress = Binding->TentativeNetworkAddress;
+ }
+
+ // ValidBindings = Device->BindingCount;
+
+ ValidBindings = Device->ValidBindings;
+
+ // [BUGBUGZZ] if (Device->AutoDetect) {
+
+ ValidBindings = IpxResolveAutoDetect (Device, ValidBindings, &LockHandle1, &Device->RegistryPath);
+
+ //}
+
+ //
+ // Adjust all the indices by the number of AutoDetect bindings thrown away
+ //
+ // AutoDetectReject = (USHORT)(Device->BindingCount - ValidBindings);
+
+ AutoDetectReject = (USHORT)(Device->ValidBindings - ValidBindings);
+
+ Device->HighestLanNicId -= AutoDetectReject;
+ Device->HighestExternalNicId -= AutoDetectReject;
+ Device->HighestType20NicId -= AutoDetectReject;
+ Device->SapNicCount -= AutoDetectReject;
+
+ Device->ValidBindings = (USHORT)ValidBindings;
+
+ //
+ // Now see if any bindings are actually on the same
+ // network. This updates the Device->HighestExternalNicId
+ // and Device->HighestType20NicId, SapNicCount, HighestLanNicId
+ //
+
+ //
+ // Do this only for the auto-detect bindings
+ // [BUGBUGZZ] check this
+ //
+
+ //if (Device->AutoDetect) {
+ IpxResolveBindingSets (Device, Device->HighestExternalNicId);
+ //}
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+jump_wan:
+
+ IPX_DEBUG(PNP, ("BindingCount: %lu\n", Device->BindingCount));
+ IPX_DEBUG(PNP, ("ValidBindings: %lu\n", Device->ValidBindings));
+ IPX_DEBUG(PNP, ("HighestLanNicId: %lu\n", Device->HighestLanNicId));
+ IPX_DEBUG(PNP, ("HighestExternalNicId: %lu\n", Device->HighestExternalNicId));
+ IPX_DEBUG(PNP, ("HighestType20NicId: %lu\n", Device->HighestType20NicId));
+ IPX_DEBUG(PNP, ("SapNicCount: %lu\n", Device->SapNicCount));
+ IPX_DEBUG(PNP, ("BindingArray: %lx\n", Device->Bindings));
+
+ //
+ // Enable this regardless of whether any of our clients enabled b'cast.
+ // NB always enables it, so we are fine.
+ //
+ // Since we dont increment the Broadcast count in the device, we will disable b'casts
+ // correctly if the count drops to 0.
+ //
+ // If the ISN clients appear before the adapters, they increment the BCount, but
+ // since the ValidBindings is 0, all works. Then, when the adapters appear, we enable
+ // the broadcasts here.
+ //
+ // If the adapters appear before the ISN clients, then the broadcast is enabled on
+ // the adapters here and the adapter's flag is set to indicate this, which will prevent
+ // any further calls to NDIS when the ISN clients force an IpxAddBroadcast.
+ //
+ Device->EnableBroadcastPending = TRUE;
+ IpxBroadcastOperation((PVOID)TRUE);
+
+ //
+ // For multiple adapters, use the offset of the first...why not.
+ //
+
+#if 0
+ Device->IncludedHeaderOffset = Device->Bindings[1]->DefHeaderSize;
+#endif
+
+ Device->IncludedHeaderOffset = MAC_HEADER_SIZE;
+
+ //
+ // This function updates flags like RipResponder, MultiCardZeroVirtual, etc.
+ // If the VirtualNetwork number changed (NewVirtualNetwork is TRUE), it updates
+ // the Device structure and the RIP tables accordingly.
+ // It returns a boolean to indicate if SPX's reserved address changed.
+ //
+ ReservedAddrChanged = IpxNewVirtualNetwork(Device, NewVirtualNetwork);
+
+ //
+ // Update the values once the auto-detect bindings have been thrown away...
+ //
+ IpxPnPUpdateDevice(Device);
+
+ Device->AutoDetectState = AUTO_DETECT_STATE_DONE;
+
+ IPX_DEBUG (DEVICE, ("Node is %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x, ",
+ Device->SourceAddress.NodeAddress[0], Device->SourceAddress.NodeAddress[1],
+ Device->SourceAddress.NodeAddress[2], Device->SourceAddress.NodeAddress[3],
+ Device->SourceAddress.NodeAddress[4], Device->SourceAddress.NodeAddress[5]));
+ IPX_DEBUG (DEVICE, ("Network is %lx\n",
+ REORDER_ULONG (Device->SourceAddress.NetworkAddress)));
+
+ //
+ // Start the timer which updates the RIP database
+ // periodically. For the first one we do a ten
+ // second timeout (hopefully this is enough time
+ // for RIP to start if it is going to).
+ //
+ if (FirstDevice) {
+ UNICODE_STRING devicename;
+
+ //
+ // Inform TDI clients about the open of our device object.
+ //
+ devicename.MaximumLength = (USHORT)Device->DeviceNameLength;
+ devicename.Length = (USHORT)Device->DeviceNameLength - sizeof(WCHAR);
+ devicename.Buffer = Device->DeviceName;
+
+ if ((ntStatus = TdiRegisterDeviceObject(
+ &devicename,
+ &Device->TdiRegistrationHandle)) != STATUS_SUCCESS) {
+
+ IPX_DEBUG(PNP, ("TdiRegisterDeviceObject failed: %lx", ntStatus));
+ }
+
+ IpxReferenceDevice (Device, DREF_LONG_TIMER);
+
+ CTEStartTimer(
+ &Device->RipLongTimer,
+ 10000,
+ RipLongTimeout,
+ (PVOID)Device);
+
+ }
+
+ //
+ // Set up the LineInfo struct.
+ //
+ IpxPnPInfo.LineInfo.LinkSpeed = Device->LinkSpeed;
+ IpxPnPInfo.LineInfo.MaximumPacketSize =
+ Device->Information.MaximumLookaheadData + sizeof(IPX_HEADER);
+ IpxPnPInfo.LineInfo.MaximumSendSize =
+ Device->Information.MaxDatagramSize + sizeof(IPX_HEADER);
+ IpxPnPInfo.LineInfo.MacOptions = Device->MacOptions;
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ //
+ // Inform NB and TDI of all the bindings corresponding to this adapter
+ //
+ for (i = 0; i < ISN_FRAME_TYPE_MAX; i++) {
+ Binding = Adapter->Bindings[i];
+
+ //
+ // If a NULL binding or a binding set slave, dont inform NB about it.
+ //
+ if (!Binding || (Binding->NicId > Device->HighestExternalNicId)) {
+#if DBG
+ if (Binding) {
+ IPX_DEBUG(PNP, ("Binding: %lx, Binding set slave\n", Binding));
+ }
+#endif
+ continue;
+ }
+
+ //
+ // Register this address with the TDI clients.
+ //
+ RtlCopyMemory (Device->TdiRegistrationAddress->Address, &Binding->LocalAddress, sizeof(TDI_ADDRESS_IPX));
+
+ if ((ntStatus = TdiRegisterNetAddress(
+ Device->TdiRegistrationAddress,
+ &Binding->TdiRegistrationHandle)) != STATUS_SUCCESS) {
+
+ IPX_DEBUG(PNP, ("TdiRegisterNetAddress failed: %lx", ntStatus));
+ }
+
+ //
+ // Lock taken to check the UpperDriverBound flag.
+ // We already have the BindAccessLock at this point.
+ //
+ IPX_GET_LOCK(&Device->Lock, &LockHandle);
+
+ if (Device->UpperDriverBound[IDENTIFIER_NB]) {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+
+ //
+ // We could have informed the upper driver from IpxPnPIsnIndicate
+ // Ensure that we dont do it twice.
+ //
+ if (!Binding->IsnInformed[IDENTIFIER_NB]) {
+
+ //
+ // Also, to ensure that the indications are done in the right order,
+ // check if the first card has been indicated yet.
+ //
+ if ((Binding->NicId != 1) &&
+ !NIC_ID_TO_BINDING_NO_ILOCK(Device, 1)->IsnInformed[IDENTIFIER_NB]) {
+
+ break;
+ }
+
+ Binding->IsnInformed[IDENTIFIER_NB] = TRUE;
+
+ if (Binding->NicId == 1) {
+ IpxPnPInfo.NewReservedAddress = TRUE;
+
+ if (FirstDevice) {
+ IpxPnPInfo.FirstORLastDevice = TRUE;
+ } else {
+ IpxPnPInfo.FirstORLastDevice = FALSE;
+ }
+ } else {
+ IpxPnPInfo.FirstORLastDevice = FALSE;
+ IpxPnPInfo.NewReservedAddress = FALSE;
+ }
+
+ IpxPnPInfo.NetworkAddress = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, Binding->LocalAddress.NodeAddress, 6);
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, Binding->NicId);
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ //
+ // give the PnP indication
+ //
+ (*Device->UpperDrivers[IDENTIFIER_NB].PnPHandler) (
+ IPX_PNP_ADD_DEVICE,
+ &IpxPnPInfo);
+
+ IPX_DEBUG(PNP, ("PnP to NB add: %lx\n", Binding));
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ }
+ } else {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+ }
+ }
+
+ IPX_GET_LOCK(&Device->Lock, &LockHandle);
+
+ if (Device->UpperDriverBound[IDENTIFIER_SPX]) {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+
+ //
+ // Always true for SPX
+ //
+ IpxPnPInfo.NewReservedAddress = TRUE;
+
+ if (FirstDevice) {
+
+ IpxPnPInfo.FirstORLastDevice = TRUE;
+
+ //
+ // We could have informed the upper driver from IpxPnPIsnIndicate
+ //
+ if (!NIC_ID_TO_BINDING_NO_ILOCK(Device, 1)->IsnInformed[IDENTIFIER_SPX]) {
+
+ NIC_ID_TO_BINDING_NO_ILOCK(Device, 1)->IsnInformed[IDENTIFIER_SPX] = TRUE;
+ //
+ // Inform SPX - the network/node address is the Virtual one if it exists
+ // else the address of the first binding
+ //
+ IpxPnPInfo.NetworkAddress = Device->SourceAddress.NetworkAddress;
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, Device->SourceAddress.NodeAddress, 6);
+
+ if (Device->VirtualNetwork) {
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, 0);
+ } else {
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, 1);
+ }
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ (*Device->UpperDrivers[IDENTIFIER_SPX].PnPHandler) (
+ IPX_PNP_ADD_DEVICE,
+ &IpxPnPInfo);
+
+ IPX_DEBUG(PNP, ("PnP to SPX add: %lx\n", Binding));
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ }
+ } else {
+
+ //
+ // Not the first device - inform if the reserved address changed.
+ //
+ if (ReservedAddrChanged) {
+ if (!NIC_ID_TO_BINDING_NO_ILOCK(Device, 1)->IsnInformed[IDENTIFIER_SPX]) {
+ NIC_ID_TO_BINDING_NO_ILOCK(Device, 1)->IsnInformed[IDENTIFIER_SPX] = TRUE;
+ IPX_DEBUG(PNP, ("Reserved addr changed; SPX not told of first one yet\n"));
+ }
+
+ IpxPnPInfo.NetworkAddress = Device->SourceAddress.NetworkAddress;
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, Device->SourceAddress.NodeAddress, 6);
+
+ if (Device->VirtualNetwork) {
+ //
+ // new one appeared
+ //
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, 0);
+ } else {
+ //
+ // Old one disappeared
+ //
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, 1);
+ }
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ IPX_DEBUG(PNP, ("PnP to SPX add (res. addr change): %lx\n", Binding));
+ (*Device->UpperDrivers[IDENTIFIER_SPX].PnPHandler) (
+ IPX_PNP_ADD_DEVICE,
+ &IpxPnPInfo);
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ }
+ }
+ } else {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+ }
+
+ //
+ // Release access to the Binding related stuff.
+ //
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+InitFailed:
+ *Status = NDIS_STATUS_SUCCESS;
+ return;
+
+} /* IpxBindAdapter */
+
+
+VOID
+IpxUnbindAdapter(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_HANDLE UnbindContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine receives a Plug and Play notification about the removal
+ of an existing adapter from the machine. We are called here only if
+ this adapter is to be bound to us, so we don't make any checks for this.
+
+Arguments:
+
+ Status - NDIS_STATUS_SUCCESS, NDIS_STATUS_PENDING.
+
+ ProtocolBindingContext - the adapter that got removed.
+
+ UnbindContext - context to represent this bind indication.
+
+Return Value:
+
+ Void - return thru' Status above.
+
+--*/
+{
+ NTSTATUS ntStatus;
+ PADAPTER Adapter=(PADAPTER)ProtocolBindingContext;
+ CONFIG Config;
+ PBINDING Binding;
+ PDEVICE Device=IpxDevice;
+ ULONG i, Temp;
+ BOOLEAN NewVirtualNetwork = FALSE;
+ BOOLEAN NBReservedAddrChanged = FALSE;
+ BOOLEAN SPXInformed = FALSE;
+ IPX_PNP_INFO IpxPnPInfo;
+ PBINDING newMasterBinding;
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+ IPX_DEFINE_LOCK_HANDLE(LockHandle)
+
+ //
+ // Used for error logging
+ //
+ Config.DriverObject = (PDRIVER_OBJECT)Device->DeviceObject;
+
+ Config.RegistryPathBuffer = Device->RegistryPathBuffer;
+
+ //
+ // Read the registry to see if a virtual network number appeared/disappeared
+ //
+ ntStatus = IpxPnPGetVirtualNetworkNumber(&Config);
+
+ if (ntStatus != STATUS_SUCCESS) {
+ IPX_DEBUG(PNP, ("Could not read the vnet#: registrypathbuffer: %lx\n", Device->RegistryPathBuffer));
+ *Status = NDIS_STATUS_SUCCESS;
+ return;
+ }
+
+ Temp = REORDER_ULONG (Config.Parameters[CONFIG_VIRTUAL_NETWORK]);
+
+ //
+ // If the VirtualNetwork number changed, record it.
+ //
+ if (Device->VirtualNetworkNumber != Temp) {
+ NewVirtualNetwork = TRUE;
+ }
+
+ Device->VirtualNetworkOptional = (BOOLEAN)(Config.Parameters[CONFIG_VIRTUAL_OPTIONAL] != 0);
+
+ IPX_DEBUG(PNP, ("Virtual net # is: %lx\n", Temp));
+
+ //
+ // If the WAN adapter disappeared, we can simply remove all the WAN bindings since
+ // all of them correspond to this single WAN adapter. Since we tell NB only about
+ // the first one of these, we need to indicate removal of only one binding to NB.
+ //
+ if (Adapter->MacInfo.MediumAsync) {
+ USHORT wanLineCount = (USHORT)Adapter->WanNicIdCount;
+
+ CTEAssert(wanLineCount == (Device->HighestExternalNicId - Device->HighestLanNicId));
+
+ //
+ // If no more bindings remain, tell upper driver of the same.
+ // We go back to the loaded state.
+ //
+
+ if ((Device->ValidBindings - wanLineCount) == 0) {
+ IpxPnPInfo.FirstORLastDevice = TRUE;
+ Device->State = DEVICE_STATE_LOADED;
+
+ //
+ // Shut down RIP timers, complete address notify requests, etc.
+ //
+ IpxPnPToLoad();
+ } else {
+ CTEAssert(Device->State == DEVICE_STATE_OPEN);
+ IpxPnPInfo.FirstORLastDevice = FALSE;
+ }
+
+ //
+ // Set up the LineInfo struct.
+ //
+ IpxPnPInfo.LineInfo.LinkSpeed = Device->LinkSpeed;
+ IpxPnPInfo.LineInfo.MaximumPacketSize =
+ Device->Information.MaximumLookaheadData + sizeof(IPX_HEADER);
+ IpxPnPInfo.LineInfo.MaximumSendSize =
+ Device->Information.MaxDatagramSize + sizeof(IPX_HEADER);
+ IpxPnPInfo.LineInfo.MacOptions = Device->MacOptions;
+
+ IPX_GET_LOCK(&Device->Lock, &LockHandle);
+ if (Device->UpperDriverBound[IDENTIFIER_NB]) {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+
+ //
+ // Get to the first WAN binding - this is always the one after the last LAN binding.
+ //
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ Binding = NIC_ID_TO_BINDING_NO_ILOCK(Device, Device->HighestLanNicId+1);
+
+ //
+ // DeRegister this address with the TDI clients.
+ //
+
+ CTEAssert(Binding->TdiRegistrationHandle);
+
+ if ((ntStatus = TdiDeregisterNetAddress(Binding->TdiRegistrationHandle)) != STATUS_SUCCESS) {
+ IPX_DEBUG(PNP, ("TdiDeRegisterNetAddress failed: %lx", ntStatus));
+ }
+
+ //
+ // Give the PnP indication to indicate the deletion only if it was
+ // added before.
+ //
+ if (Binding->IsnInformed[IDENTIFIER_NB]) {
+
+ IpxPnPInfo.NetworkAddress = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, Binding->LocalAddress.NodeAddress, 6);
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, Binding->NicId);
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ IPX_DEBUG(PNP, ("Inform NB: delete WAN device\n"));
+
+ (*Device->UpperDrivers[IDENTIFIER_NB].PnPHandler) (
+ IPX_PNP_DELETE_DEVICE,
+ &IpxPnPInfo);
+
+ IPX_DEBUG(PNP, ("PnP to NB delete: %lx\n", Binding));
+ }
+#if DBG
+ else {
+ DbgPrint("WAN adapter id: %lx not indicated to NB\n", Binding->NicId);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ }
+#endif
+ } else {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+ }
+
+ //
+ // Inform SPX only if this is the last device.
+ //
+
+ IPX_GET_LOCK(&Device->Lock, &LockHandle);
+
+ if (Device->UpperDriverBound[IDENTIFIER_SPX]) {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+
+ if (IpxPnPInfo.FirstORLastDevice && Binding->IsnInformed[IDENTIFIER_SPX]) {
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ CTEAssert(Device->HighestLanNicId == 0);
+
+ //
+ // Get to the first WAN binding - this is always the one after the last LAN binding.
+ //
+ Binding = NIC_ID_TO_BINDING_NO_ILOCK(Device, Device->HighestLanNicId+1);
+ IpxPnPInfo.NetworkAddress = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, Binding->LocalAddress.NodeAddress, 6);
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, Binding->NicId);
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ IPX_DEBUG(PNP, ("Inform SPX: delete WAN device\n"));
+
+ (*Device->UpperDrivers[IDENTIFIER_SPX].PnPHandler) (
+ IPX_PNP_DELETE_DEVICE,
+ &IpxPnPInfo);
+ }
+
+ } else {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+ }
+
+ //
+ // Now remove these WAN bindings from the array. Move all the Slave bindings
+ // up to where the WAN bindings were.
+ //
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ for (i = Device->HighestLanNicId+1; i <= Device->HighestExternalNicId; i++) {
+ //
+ // Unbind from the adapter - if it is not referenced by any other thread, it will
+ // be deleted at this point.
+ //
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ IpxUnBindFromAdapter(NIC_ID_TO_BINDING_NO_ILOCK(Device, i));
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ //
+ // Move the slave binding here.
+ //
+ INSERT_BINDING(Device, i, NIC_ID_TO_BINDING_NO_ILOCK(Device, i+wanLineCount));
+ }
+
+ /*
+ RtlCopyMemory( Device->Bindings[Device->HighestLanNicId+1],
+ Device->Bindings[Device->HighestExternalNicId+1],
+ (Device->ValidBindings - Device->HighestExternalNicId) * sizeof(PBIND_ARRAY_ELEM));
+ */
+
+ //
+ // Update the indices
+ //
+ Device->HighestExternalNicId -= wanLineCount;
+ Device->ValidBindings -= wanLineCount;
+ Device->BindingCount -= wanLineCount;
+ Device->SapNicCount = Device->HighestType20NicId = Device->HighestLanNicId;
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ CTEAssert(Device->HighestLanNicId == Device->HighestExternalNicId);
+
+ } else {
+ //
+ // LAN adapter disappeared.
+ //
+
+ //
+ // Set up the LineInfo struct.
+ //
+ IpxPnPInfo.LineInfo.LinkSpeed = Device->LinkSpeed;
+ IpxPnPInfo.LineInfo.MaximumPacketSize =
+ Device->Information.MaximumLookaheadData + sizeof(IPX_HEADER);
+ IpxPnPInfo.LineInfo.MaximumSendSize =
+ Device->Information.MaxDatagramSize + sizeof(IPX_HEADER);
+ IpxPnPInfo.LineInfo.MacOptions = Device->MacOptions;
+
+ //
+ // For each binding corresponding to this adapter, inform NB only
+ // if the binding addition was indicated.
+ //
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ for (i = 0; i < ISN_FRAME_TYPE_MAX; i++) {
+ Binding = Adapter->Bindings[i];
+
+ if (!Binding) {
+ continue;
+ }
+
+ //
+ // We cannot receive on this binding anymore
+ //
+ Adapter->Bindings[i] = NULL;
+
+ //
+ // If this was a slave binding, dont inform of the deletion.
+ // Just remove the binding from the binding array and the bindingset list.
+ //
+
+ if (Binding->NicId > Device->HighestExternalNicId) {
+ PBINDING MasterBinding, tempBinding;
+
+ CTEAssert(Binding->BindingSetMember);
+ CTEAssert(Binding->CurrentSendBinding == NULL);
+
+ //
+ // Traverse the bindingset list and remove this binding from there.
+ //
+ tempBinding = MasterBinding = Binding->MasterBinding;
+
+ while (tempBinding->NextBinding != MasterBinding) {
+ if (tempBinding->NextBinding == Binding) {
+ tempBinding->NextBinding = tempBinding->NextBinding->NextBinding;
+ break;
+ }
+ tempBinding = tempBinding->NextBinding;
+ }
+
+ //
+ // If no more slaves, this is no longer a bindingset.
+ //
+ if (MasterBinding->NextBinding == MasterBinding) {
+ MasterBinding->BindingSetMember = FALSE;
+ MasterBinding->CurrentSendBinding = NULL;
+ MasterBinding->ReceiveBroadcast = TRUE;
+
+ IPX_DEBUG(PNP, ("Slave binding: %lx removed, no master: %lx\n", Binding, MasterBinding));
+ }
+
+ //
+ // Change the slave binding entries to have the master's NicId
+ //
+ RipAdjustForBindingChange (Binding->NicId, MasterBinding->NicId, IpxBindingMoved);
+ IPX_DEBUG(PNP, ("RipAdjustForBindingChange (%d, %d, IpxBindingMoved)\n", Binding->NicId, MasterBinding->NicId));
+
+ //
+ // Null out the Slave binding.
+ //
+ INSERT_BINDING(Device, Binding->NicId, NULL);
+
+ --Device->ValidBindings;
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ IpxUnBindFromAdapter(Binding);
+
+ continue;
+ }
+
+ //
+ // If this was the last binding, go back to loaded state and shut down the RIP timers.
+ //
+ if (Device->ValidBindings == 1) {
+ CTEAssert(Device->HighestExternalNicId == 1);
+ CTEAssert(Device->HighestLanNicId == 1);
+ CTEAssert(Device->SapNicCount == 1);
+ CTEAssert(Device->HighestType20NicId == 1);
+
+ Device->State = DEVICE_STATE_LOADED;
+ IpxPnPInfo.FirstORLastDevice = TRUE;
+
+ //
+ // Shut down RIP timers, complete address notify requests, etc.
+ //
+ IpxPnPToLoad();
+
+ } else {
+ CTEAssert(Device->State == DEVICE_STATE_OPEN);
+ IpxPnPInfo.FirstORLastDevice = FALSE;
+ }
+
+ //
+ // If this was a master binding, promote a slave binding to master.
+ //
+ if (Binding->BindingSetMember) {
+
+ CTEAssert(Binding->CurrentSendBinding);
+ CTEAssert(Binding->MasterBinding == Binding);
+
+ //
+ // Promote the next slave to Master.
+ //
+ newMasterBinding = Binding->NextBinding;
+ INSERT_BINDING(Device, Binding->NicId, newMasterBinding);
+ newMasterBinding->CurrentSendBinding = newMasterBinding;
+ newMasterBinding->MasterBinding = newMasterBinding;
+
+ //
+ // If this is the only binding remaining out of its set,
+ // it is no longer part of a set.
+ //
+ if (newMasterBinding->NextBinding == Binding) {
+ newMasterBinding->NextBinding = newMasterBinding->CurrentSendBinding = NULL;
+ newMasterBinding->BindingSetMember = FALSE;
+ newMasterBinding->ReceiveBroadcast = TRUE;
+
+ IPX_DEBUG(PNP, ("Master binding: %lx removed, no master: %lx\n", Binding, newMasterBinding));
+ }
+
+ //
+ // Change the slave binding entries to have the master's NicId
+ //
+ RipAdjustForBindingChange (newMasterBinding->NicId, Binding->NicId, IpxBindingMoved);
+ IPX_DEBUG(PNP, ("RipAdjustForBindingChange (%d, %d, IpxBindingMoved)\n", newMasterBinding->NicId, Binding->NicId));
+
+ //
+ // Register slave's address with the TDI clients.
+ //
+ CTEAssert(!newMasterBinding->TdiRegistrationHandle);
+
+ RtlCopyMemory ( Device->TdiRegistrationAddress->Address,
+ &newMasterBinding->LocalAddress,
+ sizeof(TDI_ADDRESS_IPX));
+
+ if ((ntStatus = TdiRegisterNetAddress(
+ Device->TdiRegistrationAddress,
+ &newMasterBinding->TdiRegistrationHandle)) != STATUS_SUCCESS) {
+
+ IPX_DEBUG(PNP, ("TdiRegisterNetAddress failed: %lx", ntStatus));
+ }
+
+ //
+ // Null out the slave binding
+ //
+ INSERT_BINDING(Device, newMasterBinding->NicId, NULL);
+
+ newMasterBinding->NicId = Binding->NicId;
+
+ IPX_DEBUG(PNP, ("Promoted a master binding: %lx, old master: %lx\n", newMasterBinding, Binding));
+ } else {
+
+ ULONG j;
+
+ //
+ // Remove the binding from the array
+ //
+ RipAdjustForBindingChange (Binding->NicId, 0, IpxBindingDeleted);
+
+ for (j = Binding->NicId+1; j <= Device->HighestExternalNicId; j++) {
+ INSERT_BINDING(Device, j-1, NIC_ID_TO_BINDING_NO_ILOCK(Device, j));
+ --NIC_ID_TO_BINDING_NO_ILOCK(Device, j)->NicId;
+ }
+
+ INSERT_BINDING(Device, Device->HighestExternalNicId, NULL);
+
+ --Device->HighestExternalNicId;
+ --Device->HighestLanNicId;
+ --Device->HighestType20NicId;
+ --Device->SapNicCount;
+ }
+
+ --Device->ValidBindings;
+
+ IPX_GET_LOCK(&Device->Lock, &LockHandle);
+
+ //
+ // If this is the first binding, NB's reserved will change.
+ // When we inform SPX of an address change later, we dont have
+ // this binding to know if this binding was indicated to SPX earlier.
+ // So, set SPXInformed, which is used later to determine if an address
+ // change is to be indicated to SPX later.
+ //
+ // Since NB is informed of all adapters, we inform of the reserved address
+ // change to NB if the new Binding (now at NicId 1) was indicated earlier.
+ //
+ if (Binding->NicId == 1) {
+ NBReservedAddrChanged = TRUE;
+ if (Binding->IsnInformed[IDENTIFIER_SPX]) {
+ SPXInformed = TRUE;
+ }
+ }
+
+ CTEAssert(Binding->TdiRegistrationHandle);
+
+ //
+ // DeRegister this address with the TDI clients.
+ //
+ if ((ntStatus = TdiDeregisterNetAddress(Binding->TdiRegistrationHandle)) != STATUS_SUCCESS) {
+ IPX_DEBUG(PNP, ("TdiDeRegisterNetAddress failed: %lx", ntStatus));
+ }
+
+ if (Device->UpperDriverBound[IDENTIFIER_NB]) {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+ //
+ // If this binding's addition was indicated earlier, indicate its deletion to NB.
+ //
+ if (Binding->IsnInformed[IDENTIFIER_NB]) {
+ IpxPnPInfo.NetworkAddress = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, Binding->LocalAddress.NodeAddress, 6);
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, Binding->NicId);
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ IPX_DEBUG(PNP, ("Inform NB: delete LAN device: %lx\n", Binding));
+
+ (*Device->UpperDrivers[IDENTIFIER_NB].PnPHandler) (
+ IPX_PNP_DELETE_DEVICE,
+ &IpxPnPInfo);
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ //
+ // If this was a Master, indicate the addition of the (promoted) slave
+ //
+ if (Binding->BindingSetMember) {
+ IpxPnPInfo.NetworkAddress = newMasterBinding->LocalAddress.NetworkAddress;
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, newMasterBinding->LocalAddress.NodeAddress, 6);
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, newMasterBinding->NicId);
+
+ //
+ // In this case, we set the ReservedAddrChanged bit here itself so dont need
+ // to indicate a separate address changed.
+ //
+ IpxPnPInfo.NewReservedAddress = (NBReservedAddrChanged) ? TRUE : FALSE;
+ NBReservedAddrChanged = FALSE;
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ IPX_DEBUG(PNP, ("Inform NB: add slave device: NicId: %lx\n", Binding->NicId));
+
+ (*Device->UpperDrivers[IDENTIFIER_NB].PnPHandler) (
+ IPX_PNP_ADD_DEVICE,
+ &IpxPnPInfo);
+
+ newMasterBinding->IsnInformed[IDENTIFIER_NB] = TRUE;
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ }
+ }
+ } else {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+ }
+
+ //
+ // Last device - inform SPX if it is bound and this device was added earlier.
+ //
+ if (IpxPnPInfo.FirstORLastDevice) {
+ IPX_DEBUG(PNP, ("Last device - inform SPX\n"));
+
+ IPX_GET_LOCK(&Device->Lock, &LockHandle);
+ if (Device->UpperDriverBound[IDENTIFIER_SPX]) {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+
+ if (Binding->IsnInformed[IDENTIFIER_SPX]) {
+
+ IpxPnPInfo.NetworkAddress = Device->SourceAddress.NetworkAddress;
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, Device->SourceAddress.NodeAddress, 6);
+
+ if (Device->VirtualNetwork) {
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, 0);
+ } else {
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, 1);
+ }
+
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, Binding->NicId);
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ IPX_DEBUG(PNP, ("Inform SPX: last LAN device\n"));
+
+ (*Device->UpperDrivers[IDENTIFIER_SPX].PnPHandler) (
+ IPX_PNP_DELETE_DEVICE,
+ &IpxPnPInfo);
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ }
+ } else {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+ }
+ }
+
+ //
+ // Unbind from the adapter so it can be deleted
+ //
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ IpxUnBindFromAdapter(Binding);
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ }
+
+ //
+ // Update the Device and RIP tables if this is not the last device.
+ // If the reserved address changed, inform NB and SPX of this change.
+ //
+ if (!IpxPnPInfo.FirstORLastDevice) {
+
+ Binding = NIC_ID_TO_BINDING_NO_ILOCK(Device, 1);
+
+ if (IpxNewVirtualNetwork(Device, NewVirtualNetwork)) {
+
+ IPX_DEBUG(PNP, ("SPX's reserved address changed\n"));
+
+ //
+ // SPX's reserved address changed
+ //
+ IpxPnPInfo.NewReservedAddress = TRUE;
+
+ IPX_GET_LOCK(&Device->Lock, &LockHandle);
+ if (Device->UpperDriverBound[IDENTIFIER_SPX]) {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+
+ //
+ // If this binding's addition was indicated earlier, indicate change of address.
+ //
+ if (SPXInformed) {
+ Binding->IsnInformed[IDENTIFIER_SPX] = TRUE;
+
+ IPX_DEBUG(PNP, ("Inform SPX: reserved address changed\n"));
+ IpxPnPInfo.NetworkAddress = Device->SourceAddress.NetworkAddress;
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, Device->SourceAddress.NodeAddress, 6);
+
+ if (Device->VirtualNetwork) {
+ //
+ // new one appeared
+ //
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, 0);
+ } else {
+ //
+ // Old one disappeared
+ //
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, 1);
+ }
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ (*Device->UpperDrivers[IDENTIFIER_SPX].PnPHandler) (
+ IPX_PNP_ADD_DEVICE,
+ &IpxPnPInfo);
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ }
+ } else {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+ }
+ } else {
+
+ //
+ // Set the first binding's flag so that when this binding goes away, we remember
+ // to inform SPX of this device's removal.
+ //
+
+ IPX_DEBUG(PNP, ("Transfer SPX informed flag to NicId: %lx\n", Binding->NicId));
+ Binding->IsnInformed[IDENTIFIER_SPX] = TRUE;
+ }
+
+ if (NBReservedAddrChanged) {
+ //
+ // NB's reserved address changed.
+ //
+ IpxPnPInfo.NewReservedAddress = TRUE;
+
+ IPX_GET_LOCK(&Device->Lock, &LockHandle);
+ if (Device->UpperDriverBound[IDENTIFIER_NB]) {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+ //
+ // If this binding's addition was indicated earlier, indicate the change of reserved address.
+ //
+ if (Binding->IsnInformed[IDENTIFIER_NB]) {
+ IpxPnPInfo.NetworkAddress = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, Binding->LocalAddress.NodeAddress, 6);
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, Binding->NicId);
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ IPX_DEBUG(PNP, ("Inform NB: reserved address changed\n"));
+
+ (*Device->UpperDrivers[IDENTIFIER_NB].PnPHandler) (
+ IPX_PNP_ADDRESS_CHANGE,
+ &IpxPnPInfo);
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ }
+ } else {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+ }
+ }
+ }
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ }
+
+ //
+ // Re-calculate the values of datagram sizes in the Device.
+ //
+ IpxPnPUpdateDevice(Device);
+
+ IPX_DEBUG(PNP, ("BindingCount: %lu\n", Device->BindingCount));
+ IPX_DEBUG(PNP, ("ValidBindings: %lu\n", Device->ValidBindings));
+ IPX_DEBUG(PNP, ("HighestLanNicId: %lu\n", Device->HighestLanNicId));
+ IPX_DEBUG(PNP, ("HighestExternalNicId: %lu\n", Device->HighestExternalNicId));
+ IPX_DEBUG(PNP, ("HighestType20NicId: %lu\n", Device->HighestType20NicId));
+ IPX_DEBUG(PNP, ("SapNicCount: %lu\n", Device->SapNicCount));
+ IPX_DEBUG(PNP, ("BindingArray: %lx\n", Device->Bindings));
+} /* IpxUnbindAdapter */
+
+
+VOID
+IpxTranslate(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE ProtocolBindingContext,
+ OUT PNET_PNP_ID IdList,
+ IN ULONG IdListLength,
+ OUT PULONG BytesReturned
+ )
+/*++
+
+Routine Description:
+
+ This routine receives control from the physical provider as an
+ indication that a frame has been received on the physical link.
+ The packet passed up from NDIS can be held on to by the TDI clients
+ that request TDI_EVENT_RECEIVE_EX_DATAGRAM events with us.
+
+Arguments:
+
+ ProtocolBindingContext - The Adapter Binding specified at initialization time.
+
+ ReceivedPacket - The packet received
+
+ MediaSpecificInformation - Used for media such as Irda, wireless, etc. Not used here.
+
+ HeaderBufferSize - Size of the MAC header
+
+Return Value:
+
+ return of IpxReceiveIndicationNew(),
+
+--*/
+{
+} /* IpxTranslate */
+
+#endif _PNP_POWER
+
+
diff --git a/private/ntos/tdi/isnp/ipx/internal.c b/private/ntos/tdi/isnp/ipx/internal.c
new file mode 100644
index 000000000..f11790158
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/internal.c
@@ -0,0 +1,1233 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ internal.c
+
+Abstract:
+
+ This module contains the code to handle the internal
+ binding of the upper drivers to IPX.
+
+Author:
+
+ Adam Barr (adamba) 2-September-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) 25-August-1995
+ Bug Fixes - tagged [SA]
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+
+NTSTATUS
+IpxInternalBind(
+ IN PDEVICE Device,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used when one of the upper drivers submits
+ a request to bind to IPX.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation (Irp);
+ PIPX_INTERNAL_BIND_INPUT BindInput;
+ PIPX_INTERNAL_BIND_OUTPUT BindOutput;
+ PIPX_INTERNAL_BIND_RIP_OUTPUT BindRipOutput;
+ CTELockHandle LockHandle;
+ PIPX_NIC_DATA NicData;
+ PBINDING Binding, LastRealBinding;
+ PADAPTER Adapter;
+ ULONG Identifier;
+ ULONG BindOutputSize;
+ BOOLEAN BroadcastEnable;
+ UINT i;
+#if DBG
+ PUCHAR IdStrings[] = { "NB", "SPX", "RIP" };
+#endif
+
+#ifdef _PNP_POWER
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+#endif
+
+ if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
+ (sizeof(IPX_INTERNAL_BIND_INPUT) - sizeof(ULONG))) {
+
+ IPX_DEBUG (BIND, ("Bind received, bad input length %d/%d\n",
+ IrpSp->Parameters.DeviceIoControl.InputBufferLength,
+ sizeof (IPX_INTERNAL_BIND_INPUT)));
+ return STATUS_INVALID_PARAMETER;
+
+ }
+
+ BindInput = (PIPX_INTERNAL_BIND_INPUT)(Irp->AssociatedIrp.SystemBuffer);
+
+ if (BindInput->Identifier >= UPPER_DRIVER_COUNT) {
+ IPX_DEBUG (BIND, ("Bind received, bad id %d\n", BindInput->Identifier));
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ IPX_DEBUG (BIND, ("Bind received from id %d (%s)\n",
+ BindInput->Identifier,
+ IdStrings[BindInput->Identifier]));
+
+#ifdef _PNP_POWER
+// RIP gives us version == 1 whereas the others give us 2 (ISN_VERSION).
+// [BUGBUGZZ] - have RIP change?
+//
+ if (BindInput->Identifier == IDENTIFIER_RIP) {
+ if (BindInput->Version != 1) {
+ IPX_DEBUG (BIND, ("Bind: bad version %d/%d\n",
+ BindInput->Version, 1));
+ return STATUS_INVALID_PARAMETER;
+ }
+ } else {
+ if (BindInput->Version != ISN_VERSION) {
+ IPX_DEBUG (BIND, ("Bind: bad version %d/%d\n",
+ BindInput->Version, 1));
+ return STATUS_INVALID_PARAMETER;
+ }
+ }
+
+#else
+ if (BindInput->Version != 1) {
+ IPX_DEBUG (BIND, ("Bind: bad version %d/%d\n",
+ BindInput->Version, 1));
+ return STATUS_INVALID_PARAMETER;
+ }
+#endif
+
+ if (BindInput->Identifier != IDENTIFIER_RIP) {
+ BindOutputSize = sizeof(IPX_INTERNAL_BIND_OUTPUT);
+ } else {
+ BindOutputSize = FIELD_OFFSET (IPX_INTERNAL_BIND_RIP_OUTPUT, NicInfoBuffer.NicData[0]) +
+ (MIN (Device->MaxBindings, Device->HighestExternalNicId) * sizeof(IPX_NIC_DATA));
+ }
+
+ Irp->IoStatus.Information = BindOutputSize;
+
+ if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
+ BindOutputSize) {
+
+ IPX_DEBUG (BIND, ("Bind: bad output length %d/%d\n",
+ IrpSp->Parameters.DeviceIoControl.OutputBufferLength,
+ BindOutputSize));
+
+ //
+ // Fail this request with BUFFER_TOO_SMALL. Since the
+ // I/O system may not copy the status block back to
+ // the user's status block, do that here so that
+ // he gets IoStatus.Information.
+ //
+
+ try {
+ *Irp->UserIosb = Irp->IoStatus;
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+ NOTHING;
+ }
+
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ //
+ // We have verified the length, make sure we are not
+ // already bound.
+ //
+
+ Identifier = BindInput->Identifier;
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ if (Device->UpperDriverBound[Identifier]) {
+ IPX_DEBUG (BIND, ("Bind: already bound\n"));
+ CTEFreeLock (&Device->Lock, LockHandle);
+ return STATUS_REQUEST_NOT_ACCEPTED;
+ }
+
+ {
+ LARGE_INTEGER ControlChId;
+
+ CCID_FROM_REQUEST(ControlChId, Irp);
+
+ IPX_DEBUG (BIND, ("Control ChId: (%d, %d) for Id: %d\n", ControlChId.HighPart, ControlChId.LowPart, Identifier));
+ Device->UpperDriverControlChannel[Identifier].QuadPart = ControlChId.QuadPart;
+ }
+
+ RtlCopyMemory(
+ &Device->UpperDrivers[Identifier],
+ BindInput,
+ sizeof (IPX_INTERNAL_BIND_INPUT)
+ );
+
+ BroadcastEnable = BindInput->BroadcastEnable;
+
+ //
+ // Now construct the output buffer.
+ //
+
+ if (Identifier != IDENTIFIER_RIP) {
+
+ BindOutput = (PIPX_INTERNAL_BIND_OUTPUT)Irp->AssociatedIrp.SystemBuffer;
+
+ BindOutput->Version = 1;
+
+ //
+ // Tell netbios our first binding's net/node instead of the
+ // virtual one.
+ //
+#ifdef _PNP_POWER
+//
+// Fill the fields in only if the adapters have already appeared
+// Else, set NodeNumber to 0 so NB/SPX know of it.
+//
+ if ((*(UNALIGNED USHORT *)(Device->SourceAddress.NodeAddress+4) != 0) ||
+ (*(UNALIGNED ULONG *)Device->SourceAddress.NodeAddress != 0)) {
+
+ IPX_DEBUG(BIND, ("Device already opened\n"));
+ CTEAssert(Device->ValidBindings);
+
+ if (Identifier == IDENTIFIER_SPX) {
+
+ //
+ // For SPX, inform directly.
+ //
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ if (!NIC_ID_TO_BINDING(Device, 1)->IsnInformed[Identifier]) {
+ NIC_ID_TO_BINDING(Device, 1)->IsnInformed[Identifier] = TRUE;
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ IpxPnPIsnIndicate((PVOID)Identifier);
+
+ } else {
+ CTEAssert(FALSE);
+
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ }
+
+ IPX_GET_LOCK(&Device->Lock, &LockHandle);
+ } else {
+ //
+ // For NB, queue a work item which will go thru' the adapters list and
+ // inform the upper drivers about each of them.
+ //
+ ExInitializeWorkItem(
+ &Device->PnPIndicationsQueueItem,
+ IpxPnPIsnIndicate,
+ (PVOID)Identifier);
+ ExQueueWorkItem(&Device->PnPIndicationsQueueItem, DelayedWorkQueue);
+ }
+
+ } else {
+ IPX_DEBUG(BIND, ("Device not open\n"));
+ *((UNALIGNED ULONG *)BindOutput->Node) = 0;
+ *((UNALIGNED USHORT *)(BindOutput->Node+4)) = 0;
+ RtlZeroMemory(&BindOutput->LineInfo, sizeof(BindOutput->LineInfo));
+ }
+
+ BindOutput->MacHeaderNeeded = MAC_HEADER_SIZE; //40;
+ BindOutput->IncludedHeaderOffset = MAC_HEADER_SIZE; // (USHORT)Device->IncludedHeaderOffset;
+
+ BindOutput->SendHandler = IpxSendFramePreFwd;
+ BindOutput->FindRouteHandler = IpxInternalFindRoute;
+ BindOutput->QueryHandler = IpxInternalQuery;
+
+#else
+ if ((Identifier == IDENTIFIER_NB) &&
+ (Device->VirtualNetwork)) {
+ RtlCopyMemory(BindOutput->Node, Device->Bindings[1]->LocalAddress.NodeAddress, 6);
+ *(UNALIGNED ULONG *)(BindOutput->Network) = Device->Bindings[1]->LocalAddress.NetworkAddress;
+ } else {
+
+ RtlCopyMemory(BindOutput->Node, Device->SourceAddress.NodeAddress, 6);
+ *(UNALIGNED ULONG *)(BindOutput->Network) = Device->SourceAddress.NetworkAddress;
+ }
+
+ BindOutput->MacHeaderNeeded = MAC_HEADER_SIZE; //40;
+
+ BindOutput->IncludedHeaderOffset = (USHORT)Device->IncludedHeaderOffset;
+
+ BindOutput->LineInfo.LinkSpeed = Device->LinkSpeed;
+ BindOutput->LineInfo.MaximumPacketSize =
+ Device->Information.MaximumLookaheadData + sizeof(IPX_HEADER);
+ BindOutput->LineInfo.MaximumSendSize =
+ Device->Information.MaxDatagramSize + sizeof(IPX_HEADER);
+ BindOutput->LineInfo.MacOptions = Device->MacOptions;
+
+ BindOutput->SendHandler = IpxSendFrame;
+ BindOutput->FindRouteHandler = IpxInternalFindRoute;
+ BindOutput->QueryHandler = IpxInternalQuery;
+#endif
+ BindOutput->TransferDataHandler = IpxTransferData;
+ } else {
+ //
+ // Set this so we stop RIPping for our virtual network (if
+ // we have one).
+ //
+
+ Device->RipResponder = FALSE;
+
+ //
+ // See if he wants a single wan network number.
+ //
+
+ if ((IrpSp->Parameters.DeviceIoControl.InputBufferLength <
+ sizeof(IPX_INTERNAL_BIND_INPUT)) ||
+ ((BindInput->RipParameters & IPX_RIP_PARAM_GLOBAL_NETWORK) == 0)) {
+
+ Device->WanGlobalNetworkNumber = FALSE;
+ Device->SapNicCount = Device->HighestExternalNicId;
+
+ } else {
+
+ Device->WanGlobalNetworkNumber = TRUE;
+
+ }
+
+ BindRipOutput = (PIPX_INTERNAL_BIND_RIP_OUTPUT)Irp->AssociatedIrp.SystemBuffer;
+
+ BindRipOutput->Version = 1;
+ BindRipOutput->MaximumNicCount = MIN (Device->MaxBindings, Device->HighestExternalNicId) + 1;
+
+ BindRipOutput->MacHeaderNeeded = MAC_HEADER_SIZE; //40;
+ BindRipOutput->IncludedHeaderOffset = (USHORT)Device->IncludedHeaderOffset;
+
+ BindRipOutput->SendHandler = IpxSendFrame;
+
+ BindRipOutput->SegmentCount = Device->SegmentCount;
+ BindRipOutput->SegmentLocks = Device->SegmentLocks;
+
+ BindRipOutput->GetSegmentHandler = RipGetSegment;
+ BindRipOutput->GetRouteHandler = RipGetRoute;
+ BindRipOutput->AddRouteHandler = RipAddRoute;
+ BindRipOutput->DeleteRouteHandler = RipDeleteRoute;
+ BindRipOutput->GetFirstRouteHandler = RipGetFirstRoute;
+ BindRipOutput->GetNextRouteHandler = RipGetNextRoute;
+
+ BindRipOutput->IncrementWanInactivityHandler = IpxInternalIncrementWanInactivity;
+ BindRipOutput->QueryWanInactivityHandler = IpxInternalQueryWanInactivity;
+
+ BindRipOutput->TransferDataHandler = IpxTransferData;
+
+ BindRipOutput->NicInfoBuffer.NicCount = (USHORT)MIN (Device->MaxBindings, Device->HighestExternalNicId);
+ BindRipOutput->NicInfoBuffer.VirtualNicId = 0;
+ if (Device->VirtualNetwork || Device->MultiCardZeroVirtual) {
+ *(UNALIGNED ULONG *)(BindRipOutput->NicInfoBuffer.VirtualNetwork) = Device->SourceAddress.NetworkAddress;
+ } else if (Device->DedicatedRouter) {
+ *(UNALIGNED ULONG *)(BindRipOutput->NicInfoBuffer.VirtualNetwork) = 0x0;
+ }
+
+ NicData = &BindRipOutput->NicInfoBuffer.NicData[0];
+
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+#endif
+ {
+ ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
+
+ for (i = 1; i <= Index; i++) {
+
+#ifdef _PNP_POWER
+ Binding = NIC_ID_TO_BINDING(Device, i);
+#else
+ Binding = Device->Bindings[i];
+#endif
+
+ //
+ // NULL bindings are WAN bindings, so we return the
+ // information from the last non-NULL binding found,
+ // which will be the first one on this adapter.
+ // Otherwise we save this as the last non-NULL one.
+ //
+
+ if (Binding == NULL) {
+ Binding = LastRealBinding;
+ } else {
+ LastRealBinding = Binding;
+ }
+
+ Adapter = Binding->Adapter;
+ NicData->NicId = i;
+ RtlCopyMemory (NicData->Node, Binding->LocalAddress.NodeAddress, 6);
+ *(UNALIGNED ULONG *)NicData->Network = Binding->LocalAddress.NetworkAddress;
+ NicData->LineInfo.LinkSpeed = Binding->MediumSpeed;
+ NicData->LineInfo.MaximumPacketSize =
+ Binding->MaxLookaheadData + sizeof(IPX_HEADER);
+ NicData->LineInfo.MaximumSendSize =
+ Binding->AnnouncedMaxDatagramSize + sizeof(IPX_HEADER);
+ NicData->LineInfo.MacOptions = Adapter->MacInfo.MacOptions;
+ NicData->DeviceType = Adapter->MacInfo.RealMediumType;
+ NicData->EnableWanRouter = Adapter->EnableWanRouter;
+
+ ++NicData;
+ }
+ }
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+ }
+ if (BroadcastEnable) {
+ IpxAddBroadcast (Device);
+ }
+
+ Device->UpperDriverBound[Identifier] = TRUE;
+ Device->AnyUpperDriverBound = TRUE;
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ return STATUS_SUCCESS;
+
+} /* IpxInternalBind */
+
+
+NTSTATUS
+IpxInternalUnbind(
+ IN PDEVICE Device,
+ IN UINT Identifier
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used when one of the upper drivers submits
+ a request to unbind from IPX. It does this by closing the
+ control channel on which the bind ioctl was submitted.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ CTELockHandle LockHandle;
+#if DBG
+ PUCHAR IdStrings[] = { "NB", "SPX", "RIP" };
+#endif
+
+ IPX_DEBUG (BIND, ("Unbind received from id %d (%s)\n",
+ Identifier,
+ IdStrings[Identifier]));
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ if (!Device->UpperDriverBound[Identifier]) {
+ CTEFreeLock (&Device->Lock, LockHandle);
+ IPX_DEBUG (BIND, ("No existing binding\n"));
+ return STATUS_SUCCESS;
+ }
+
+ Device->UpperDriverBound[Identifier] = FALSE;
+ Device->AnyUpperDriverBound = (BOOLEAN)
+ (Device->UpperDriverBound[IDENTIFIER_RIP] ||
+ Device->UpperDriverBound[IDENTIFIER_SPX] ||
+ Device->UpperDriverBound[IDENTIFIER_NB]);
+
+ if (Device->UpperDrivers[Identifier].BroadcastEnable) {
+ IpxRemoveBroadcast (Device);
+ }
+
+#ifdef _PNP_POWER
+ if (Device->ValidBindings > 0) {
+ //
+ // If SPX went away, reset the IsnIndicate flag in the first binding
+ //
+ if (Identifier == IDENTIFIER_SPX) {
+ CTEAssert(NIC_ID_TO_BINDING(Device, 1));
+
+ if (NIC_ID_TO_BINDING(Device, 1)->IsnInformed[Identifier]) {
+ NIC_ID_TO_BINDING(Device, 1)->IsnInformed[Identifier] = FALSE;
+ IPX_DEBUG(PNP, ("SPX unbound: IsnInformed turned off\n"));
+ }
+ }
+
+ //
+ // If NB went away, reset all the Binding's flags
+ //
+ if (Identifier == IDENTIFIER_SPX) {
+ PBINDING Binding;
+ UINT i;
+ ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
+
+ for (i = 1; i < Index; i++) {
+ Binding = NIC_ID_TO_BINDING(Device, i);
+ if (Binding && Binding->IsnInformed[Identifier]) {
+ Binding->IsnInformed[Identifier] = FALSE;
+ IPX_DEBUG(PNP, ("NB unbound: IsnInformed off for NicId: %lx\n", i));
+ }
+ }
+ }
+ }
+#endif
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ //
+ // BUGBUG: Ensure that no calls are made to bogus
+ // handlers.
+ //
+
+ return STATUS_SUCCESS;
+
+} /* IpxInternalUnbind */
+
+
+VOID
+IpxInternalFindRoute (
+ IN PIPX_FIND_ROUTE_REQUEST FindRouteRequest
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the entry point for upper drivers to submit
+ requests to find a remote network, which is contained in
+ FindRouteRequest->Network. FindRouteRequest->Identifier must
+ contain the identifier of the upper driver.
+
+ This request is always asynchronous and is completed by
+ a call to the FindRouteComplete handler of the upper driver.
+
+ NOTE: As a currently unspecified extension to this call,
+ we returns the tick and hop counts as two USHORTs in the
+ PVOID Reserved2 structure of the request.
+
+Arguments:
+
+ FindRouteRequest - Describes the request and contains
+ storage for IPX to use while processing it.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = IpxDevice;
+ ULONG Segment;
+ TDI_ADDRESS_IPX TempAddress;
+ PBINDING Binding, MasterBinding;
+ NTSTATUS Status;
+ IPX_DEFINE_SYNC_CONTEXT (SyncContext)
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+#ifdef _PNP_POWER
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+#endif
+
+ //
+ // First see if we have a route to this network in our
+ // table.
+ //
+
+ TempAddress.NetworkAddress = *(UNALIGNED ULONG *)(FindRouteRequest->Network);
+ //
+ // [SA] Bug #15094 Copy over the Node address so it can be used in WAN cases
+ //
+
+ // RtlZeroMemory (TempAddress.NodeAddress, 6);
+
+ *((UNALIGNED ULONG *)TempAddress.NodeAddress) = *((UNALIGNED ULONG *)FindRouteRequest->Node);
+ *((UNALIGNED USHORT *)(TempAddress.NodeAddress+4)) = *((UNALIGNED USHORT *)(FindRouteRequest->Node+4));
+
+ Segment = RipGetSegment(FindRouteRequest->Network);
+#ifdef _PNP_POWER
+ //
+ // Since we maintain the order of locks as Bind > Device > RIP table
+ // Get the lock up-front.
+ //
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+#endif
+ IPX_BEGIN_SYNC (&SyncContext);
+ IPX_GET_LOCK (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // This call will return STATUS_PENDING if we need to
+ // RIP for the packet.
+ //
+
+ CTEAssert ((sizeof(USHORT)*2) <= sizeof(PVOID));
+
+ Status = RipGetLocalTarget(
+ Segment,
+ &TempAddress,
+ FindRouteRequest->Type,
+ &FindRouteRequest->LocalTarget,
+ (PUSHORT)&FindRouteRequest->Reserved2);
+
+ if (Status == STATUS_PENDING) {
+
+ //
+ // A RIP request went out on the network; we queue
+ // this find route request for completion when the
+ // RIP response arrives.
+ //
+
+ CTEAssert (FindRouteRequest->Type != IPX_FIND_ROUTE_NO_RIP); // should never pend
+
+ InsertTailList(
+ &Device->Segments[Segment].FindWaitingForRoute,
+ &FindRouteRequest->Linkage);
+
+ }
+
+ IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
+ IPX_END_SYNC (&SyncContext);
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+ if (Status != STATUS_PENDING) {
+
+ if (Status == STATUS_SUCCESS && FindRouteRequest->LocalTarget.NicId) {
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ Binding = NIC_HANDLE_TO_BINDING(Device, &FindRouteRequest->LocalTarget.NicHandle);
+
+ if (Binding->BindingSetMember) {
+
+ //
+ // It's a binding set member, we round-robin the
+ // responses across all the cards to distribute
+ // the traffic.
+ //
+
+ MasterBinding = Binding->MasterBinding;
+ Binding = MasterBinding->CurrentSendBinding;
+ MasterBinding->CurrentSendBinding = Binding->NextBinding;
+
+ FILL_LOCAL_TARGET(&FindRouteRequest->LocalTarget, Binding->NicId);
+
+ }
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+ Binding = Device->Bindings[FindRouteRequest->LocalTarget.NicId];
+
+ if (Binding->BindingSetMember) {
+
+ //
+ // It's a binding set member, we round-robin the
+ // responses across all the cards to distribute
+ // the traffic.
+ //
+
+ MasterBinding = Binding->MasterBinding;
+ Binding = MasterBinding->CurrentSendBinding;
+ MasterBinding->CurrentSendBinding = Binding->NextBinding;
+
+ FindRouteRequest->LocalTarget.NicId = Binding->NicId;
+
+ }
+#endif
+ }
+
+ (*Device->UpperDrivers[FindRouteRequest->Identifier].FindRouteCompleteHandler)(
+ FindRouteRequest,
+ (BOOLEAN)((Status == STATUS_SUCCESS) ? TRUE : FALSE));
+
+ }
+
+} /* IpxInternalFindRoute */
+
+
+NTSTATUS
+IpxInternalQuery(
+ IN ULONG InternalQueryType,
+#ifdef _PNP_POWER
+ IN PNIC_HANDLE NicHandle OPTIONAL,
+#else
+ IN USHORT NicId OPTIONAL,
+#endif
+ IN OUT PVOID Buffer,
+ IN ULONG BufferLength,
+ OUT PULONG BufferLengthNeeded OPTIONAL
+)
+
+/*++
+
+Routine Description:
+
+ This routine is the entry point for upper drivers to query
+ information from us.
+
+Arguments:
+
+ InternalQueryType - Identifies the type of the query.
+
+ NicId - The ID to query, if needed
+
+ Buffer - Input or output buffer for the query.
+
+ BufferLength - The length of the buffer.
+
+ BufferLengthNeeded - If the buffer is too short, this returns
+ the length needed.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PBINDING Binding;
+ BOOLEAN BindingNeeded;
+ ULONG LengthNeeded;
+ PIPX_LINE_INFO LineInfo;
+ PUSHORT MaximumNicId;
+ PULONG ReceiveBufferSpace;
+ TDI_ADDRESS_IPX UNALIGNED * IpxAddress;
+ IPX_SOURCE_ROUTING_INFO UNALIGNED * SourceRoutingInfo;
+ ULONG SourceRoutingLength;
+ UINT MaxUserData;
+ PDEVICE Device = IpxDevice;
+#ifdef _PNP_POWER
+ USHORT NicId = NicHandle->NicId;
+
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+#endif
+
+ //
+ // First verify the parameters.
+ //
+
+ switch (InternalQueryType) {
+
+ case IPX_QUERY_LINE_INFO:
+
+ BindingNeeded = TRUE;
+ LengthNeeded = sizeof(IPX_LINE_INFO);
+ break;
+
+ case IPX_QUERY_MAXIMUM_NIC_ID:
+ case IPX_QUERY_MAX_TYPE_20_NIC_ID:
+
+ BindingNeeded = FALSE;
+ LengthNeeded = sizeof(USHORT);
+ break;
+
+ case IPX_QUERY_IS_ADDRESS_LOCAL:
+
+ BindingNeeded = FALSE; // for now we don't need it
+ LengthNeeded = sizeof(TDI_ADDRESS_IPX);
+ break;
+
+ case IPX_QUERY_RECEIVE_BUFFER_SPACE:
+
+ BindingNeeded = TRUE;
+ LengthNeeded = sizeof(ULONG);
+ break;
+
+ case IPX_QUERY_IPX_ADDRESS:
+
+ if ((NicId == 0) &&
+ (BufferLength >= sizeof(TDI_ADDRESS_IPX))) {
+
+ RtlCopyMemory (Buffer, &Device->SourceAddress, sizeof(TDI_ADDRESS_IPX));
+ return STATUS_SUCCESS;
+
+ }
+
+ BindingNeeded = TRUE;
+ LengthNeeded = sizeof(TDI_ADDRESS_IPX);
+ break;
+
+ case IPX_QUERY_SOURCE_ROUTING:
+
+ BindingNeeded = TRUE;
+ LengthNeeded = sizeof(IPX_SOURCE_ROUTING_INFO);
+ break;
+
+#ifdef _PNP_POWER
+ //
+ // These are moved down from NB/SPX to IPX. LengthNeeded is set to 0
+ // so we dont return BUFFER_TOO_SMALL here; we assume here that
+ // Bufferlength is also 0.
+ // Buffer is actually the IRP here.
+ //
+ case IPX_QUERY_DATA_LINK_ADDRESS:
+ case IPX_QUERY_NETWORK_ADDRESS:
+
+ BindingNeeded = FALSE;
+ LengthNeeded = 0;
+ break;
+#endif
+ default:
+
+ return STATUS_NOT_SUPPORTED;
+
+ }
+
+
+ if (LengthNeeded > BufferLength) {
+ if (BufferLengthNeeded != NULL) {
+ *BufferLengthNeeded = LengthNeeded;
+ }
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ if (BindingNeeded) {
+
+ if (NicId == 0) {
+ NicId = 1;
+ }
+
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ Binding = NIC_ID_TO_BINDING(IpxDevice, NicId);
+ if ((Binding == NULL) ||
+ (!Binding->LineUp)) {
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+ Binding = IpxDevice->Bindings[NicId];
+ if ((Binding == NULL) ||
+ (!Binding->LineUp)) {
+ return STATUS_INVALID_PARAMETER;
+ }
+#endif
+ }
+
+
+ //
+ // Now return the data.
+ //
+
+ switch (InternalQueryType) {
+
+ case IPX_QUERY_LINE_INFO:
+
+ LineInfo = (PIPX_LINE_INFO)Buffer;
+ LineInfo->LinkSpeed = Binding->MediumSpeed;
+ LineInfo->MaximumPacketSize = Binding->MaxLookaheadData + sizeof(IPX_HEADER);
+ LineInfo->MaximumSendSize = Binding->AnnouncedMaxDatagramSize + sizeof(IPX_HEADER);
+ LineInfo->MacOptions = Binding->Adapter->MacInfo.MacOptions;
+ break;
+
+ case IPX_QUERY_MAXIMUM_NIC_ID:
+
+ MaximumNicId = (PUSHORT)Buffer;
+ *MaximumNicId = MIN (Device->MaxBindings, IpxDevice->HighestExternalNicId);
+ break;
+
+ case IPX_QUERY_IS_ADDRESS_LOCAL:
+
+ IpxAddress = (TDI_ADDRESS_IPX UNALIGNED *)Buffer;
+ if (!IpxIsAddressLocal(IpxAddress)) {
+ return STATUS_NO_SUCH_DEVICE;
+ }
+ break;
+
+ case IPX_QUERY_RECEIVE_BUFFER_SPACE:
+
+ ReceiveBufferSpace = (PULONG)Buffer;
+ *ReceiveBufferSpace = Binding->Adapter->ReceiveBufferSpace;
+ break;
+
+ case IPX_QUERY_IPX_ADDRESS:
+
+ RtlCopyMemory (Buffer, &Binding->LocalAddress, sizeof(TDI_ADDRESS_IPX));
+ break;
+
+ case IPX_QUERY_SOURCE_ROUTING:
+
+ SourceRoutingInfo = (IPX_SOURCE_ROUTING_INFO UNALIGNED *)Buffer;
+
+ MacLookupSourceRouting(
+ SourceRoutingInfo->Identifier,
+ Binding,
+ SourceRoutingInfo->RemoteAddress,
+ SourceRoutingInfo->SourceRouting,
+ &SourceRoutingLength);
+
+ //
+ // Reverse the direction of the source routing since it
+ // is returned in the outgoing order.
+ //
+
+ if (SourceRoutingLength > 0) {
+ SourceRoutingInfo->SourceRouting[0] &= 0x7f;
+ }
+ SourceRoutingInfo->SourceRoutingLength = (USHORT)SourceRoutingLength;
+
+ MacReturnMaxDataSize(
+ &Binding->Adapter->MacInfo,
+ SourceRoutingInfo->SourceRouting,
+ SourceRoutingLength,
+ Binding->MaxSendPacketSize,
+ &MaxUserData);
+
+ //
+ // MaxUserData does not include the MAC header but does include
+ // any extra 802.2 etc. headers, so we adjust for that to get the
+ // size starting at the IPX header.
+ //
+
+ SourceRoutingInfo->MaximumSendSize =
+ MaxUserData -
+ (Binding->DefHeaderSize - Binding->Adapter->MacInfo.MinHeaderLength);
+
+ break;
+
+ case IPX_QUERY_MAX_TYPE_20_NIC_ID:
+
+ MaximumNicId = (PUSHORT)Buffer;
+ *MaximumNicId = MIN (Device->MaxBindings, IpxDevice->HighestType20NicId);
+ break;
+
+#ifdef _PNP_POWER
+ case IPX_QUERY_DATA_LINK_ADDRESS:
+ case IPX_QUERY_NETWORK_ADDRESS:
+ //
+ // Call the TDI query equivalent here.
+ //
+ return IpxTdiQueryInformation(Device, (PREQUEST)Buffer);
+
+#endif
+ }
+
+#ifdef _PNP_POWER
+ //
+ // If Binding was needed earlier, it was referenced, deref it now.
+ //
+ if (BindingNeeded) {
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ }
+#endif
+
+ //
+ // If we haven't returned failure by now, succeed.
+ //
+
+ return STATUS_SUCCESS;
+
+} /* IpxInternalQuery */
+
+
+VOID
+IpxInternalIncrementWanInactivity(
+#ifdef _PNP_LATER
+// RIP not converted yet...
+//
+ IN NIC_HANDLE NicHandle
+#else
+ IN USHORT NicId
+#endif
+)
+
+/*++
+
+Routine Description:
+
+ This routine is the entry point where rip calls us to increment
+ the inactivity counter on a wan binding. This is done every
+ minute.
+
+Arguments:
+
+ NicId - The NIC ID of the wan binding.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+#ifdef _PNP_POWER
+ PBINDING Binding;
+
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+
+ IPX_GET_LOCK1(&IpxDevice->BindAccessLock, &LockHandle1);
+ //
+ // [BUGBUGZZ] Change to NIC_HANDLE_TO_BINDING later. Not done yet since RIP not changed to
+ // use NICHANDLE instead of NicId
+ //
+ Binding = NIC_ID_TO_BINDING(IpxDevice, NicId);
+
+ if ((Binding != NULL) &&
+ (Binding->Adapter->MacInfo.MediumAsync)) {
+
+ ++Binding->WanInactivityCounter;
+
+ } else {
+
+ CTEAssert (FALSE);
+
+ }
+ IPX_FREE_LOCK1(&IpxDevice->BindAccessLock, LockHandle1);
+#else
+ PBINDING Binding = IpxDevice->Bindings[NicId];
+
+ if ((Binding != NULL) &&
+ (Binding->Adapter->MacInfo.MediumAsync)) {
+
+ ++Binding->WanInactivityCounter;
+
+ } else {
+
+ CTEAssert (FALSE);
+
+ }
+#endif
+
+} /* IpxInternalIncrementWanInactivity */
+
+
+ULONG
+IpxInternalQueryWanInactivity(
+#ifdef _PNP_LATER
+ IN NIC_HANDLE NicHandle
+#else
+ IN USHORT NicId
+#endif
+)
+
+/*++
+
+Routine Description:
+
+ This routine is the entry point where rip calls us to query
+ the inactivity counter on a wan binding.
+
+Arguments:
+
+ NicId - The NIC ID of the wan binding.
+
+Return Value:
+
+ The inactivity counter for this binding.
+
+--*/
+
+{
+#ifdef _PNP_POWER
+ PBINDING Binding;
+
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+
+ IPX_GET_LOCK1(&IpxDevice->BindAccessLock, &LockHandle1);
+ // Binding = NIC_HANDLE_TO_BINDING(IpxDevice, &NicHandle);
+
+ Binding = NIC_ID_TO_BINDING(IpxDevice, NicId);
+ if ((Binding != NULL) &&
+ (Binding->Adapter->MacInfo.MediumAsync)) {
+ IPX_FREE_LOCK1(&IpxDevice->BindAccessLock, LockHandle1);
+ return Binding->WanInactivityCounter;
+
+ } else {
+ IPX_FREE_LOCK1(&IpxDevice->BindAccessLock, LockHandle1);
+ CTEAssert (FALSE);
+ return 0;
+
+ }
+
+#else
+ PBINDING Binding = IpxDevice->Bindings[NicId];
+
+ if ((Binding != NULL) &&
+ (Binding->Adapter->MacInfo.MediumAsync)) {
+
+ return Binding->WanInactivityCounter;
+
+ } else {
+
+ CTEAssert (FALSE);
+ return 0;
+
+ }
+#endif
+
+} /* IpxInternalQueryWanInactivity */
+
+#ifdef _PNP_POWER
+
+VOID
+IpxPnPIsnIndicate(
+ IN PVOID Param
+)
+
+/*++
+
+Routine Description:
+
+ This routine goes through the list of adapters and informs (thru' PnP indications)
+ the ISN drivers bound to IPX about any new adapters that have appeared before the
+ bind took place.
+
+ This is queued as a work item in the InternalBind routine.
+
+Arguments:
+
+ Param - the upper driver identifier.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ULONG Identifier = (ULONG)Param;
+ PDEVICE Device=IpxDevice;
+ ULONG i;
+ PBINDING Binding;
+ IPX_PNP_INFO IpxPnPInfo;
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+
+ //
+ // Set up the LineInfo struct.
+ //
+
+ //
+ // BUGBUG: Do we give Binding-specific information here?
+ //
+ IpxPnPInfo.LineInfo.LinkSpeed = Device->LinkSpeed;
+ IpxPnPInfo.LineInfo.MaximumPacketSize =
+ Device->Information.MaximumLookaheadData + sizeof(IPX_HEADER);
+ IpxPnPInfo.LineInfo.MaximumSendSize =
+ Device->Information.MaxDatagramSize + sizeof(IPX_HEADER);
+ IpxPnPInfo.LineInfo.MacOptions = Device->MacOptions;
+
+ switch(Identifier) {
+ case IDENTIFIER_NB:
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ //
+ // Inform about all the adapters
+ //
+ {
+ ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
+
+ for (i = 1; i <= Index; i++) {
+ Binding = NIC_ID_TO_BINDING(Device, i);
+
+ if (!Binding) {
+ continue;
+ }
+
+ //
+ // We could have informed the upper driver from IpxBindAdapter
+ //
+ if (!Binding->IsnInformed[Identifier]) {
+ Binding->IsnInformed[Identifier] = TRUE;
+
+ //
+ // Inform NB - the reserved network/node address is always that of the first
+ // binding
+ //
+ if (i==1) {
+ IpxPnPInfo.FirstORLastDevice = TRUE;
+ IpxPnPInfo.NewReservedAddress = TRUE;
+ } else {
+ IpxPnPInfo.FirstORLastDevice = FALSE;
+ IpxPnPInfo.NewReservedAddress = FALSE;
+ }
+
+ IpxPnPInfo.NetworkAddress = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, Binding->LocalAddress.NodeAddress, 6);
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, (USHORT)i);
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ //
+ // give the PnP indication
+ //
+ (*Device->UpperDrivers[Identifier].PnPHandler) (
+ IPX_PNP_ADD_DEVICE,
+ &IpxPnPInfo);
+
+ IPX_DEBUG(PNP, ("IpxPnPIsnIndicate: PnP to NB add: %lx\n", Binding));
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ }
+ }
+ }
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ break;
+
+ case IDENTIFIER_SPX:
+ //
+ // For SPX this is called directly, with the IsnInformed flag appropriately set.
+ // This is done so that the IsnInformed flag cannot be changed under
+ // us by the BindAdapter routine.
+ //
+#if 0
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ if (!NIC_ID_TO_BINDING(Device, 1)->IsnInformed[Identifier]) {
+ NIC_ID_TO_BINDING(Device, 1)->IsnInformed[Identifier] = TRUE;
+#endif
+ IpxPnPInfo.FirstORLastDevice = TRUE;
+ //
+ // Inform of the reserved address only
+ //
+ if (Device->VirtualNetwork) {
+ IpxPnPInfo.NetworkAddress = Device->SourceAddress.NetworkAddress;
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, Device->SourceAddress.NodeAddress, 6);
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, 0);
+ } else {
+ IpxPnPInfo.NetworkAddress = NIC_ID_TO_BINDING(Device, 1)->LocalAddress.NetworkAddress;
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, NIC_ID_TO_BINDING(Device, 1)->LocalAddress.NodeAddress, 6);
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, 1);
+ }
+
+ IpxPnPInfo.NewReservedAddress = TRUE;
+
+ // IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ (*Device->UpperDrivers[Identifier].PnPHandler) (
+ IPX_PNP_ADD_DEVICE,
+ &IpxPnPInfo);
+
+ IPX_DEBUG(PNP, ("IpxPnPIsnIndicate: PnP to SPX add: %lx\n", NIC_ID_TO_BINDING(Device, 1)));
+#if 0
+ } else {
+ CTEAssert(FALSE);
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ }
+#endif
+
+ }
+}
+#endif
diff --git a/private/ntos/tdi/isnp/ipx/ipxprocs.h b/private/ntos/tdi/isnp/ipx/ipxprocs.h
new file mode 100644
index 000000000..abfcf6ec3
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/ipxprocs.h
@@ -0,0 +1,1525 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ ipxprocs.h
+
+Abstract:
+
+ This module contains definitions specific to the
+ IPX module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 2-September-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) 3-Oct-1995
+ Changes to support transfer of buffer ownership to transports - tagged [CH]
+ 1. Added new functions - IpxReceivePacket, IpxReceiveIndicationNew
+
+ Sanjay Anand (SanjayAn) 27-Oct-1995
+ Changes to support Plug and Play (in _PNP_POWER)
+
+--*/
+
+
+//
+// MACROS.
+//
+//
+// Debugging aids
+//
+
+//
+// VOID
+// PANIC(
+// IN PSZ Message
+// );
+//
+
+#if DBG
+#define PANIC(Msg) \
+ CTEPrint ((Msg))
+#else
+#define PANIC(Msg)
+#endif
+
+
+//
+// These are define to allow CTEPrints that disappear when
+// DBG is 0.
+//
+
+#if DBG
+#define IpxPrint0(fmt) DbgPrint(fmt)
+#define IpxPrint1(fmt,v0) DbgPrint(fmt,v0)
+#define IpxPrint2(fmt,v0,v1) DbgPrint(fmt,v0,v1)
+#define IpxPrint3(fmt,v0,v1,v2) DbgPrint(fmt,v0,v1,v2)
+#define IpxPrint4(fmt,v0,v1,v2,v3) DbgPrint(fmt,v0,v1,v2,v3)
+#define IpxPrint5(fmt,v0,v1,v2,v3,v4) DbgPrint(fmt,v0,v1,v2,v3,v4)
+#define IpxPrint6(fmt,v0,v1,v2,v3,v4,v5) DbgPrint(fmt,v0,v1,v2,v3,v4,v5)
+#else
+#define IpxPrint0(fmt)
+#define IpxPrint1(fmt,v0)
+#define IpxPrint2(fmt,v0,v1)
+#define IpxPrint3(fmt,v0,v1,v2)
+#define IpxPrint4(fmt,v0,v1,v2,v3)
+#define IpxPrint5(fmt,v0,v1,v2,v3,v4)
+#define IpxPrint6(fmt,v0,v1,v2,v3,v4,v5)
+#endif
+
+
+//
+// Routines to log packets to a buffer.
+//
+
+#if DBG
+#define IPX_PACKET_LOG 1
+#endif
+
+#ifdef IPX_PACKET_LOG
+
+//
+// The size of this is 64 bytes for easy display.
+//
+
+typedef struct _IPX_PACKET_LOG_ENTRY {
+ UCHAR SendReceive;
+ UCHAR TimeStamp[5]; // low 5 digits of tick count.
+ UCHAR DestMac[6];
+ UCHAR SrcMac[6];
+ UCHAR Length[2];
+ IPX_HEADER IpxHeader;
+ UCHAR Data[14];
+} IPX_PACKET_LOG_ENTRY, *PIPX_PACKET_LOG_ENTRY;
+
+#define IPX_PACKET_LOG_LENGTH 128
+extern ULONG IpxPacketLogDebug;
+extern USHORT IpxPacketLogSocket;
+EXTERNAL_LOCK(IpxPacketLogLock);
+extern IPX_PACKET_LOG_ENTRY IpxPacketLog[IPX_PACKET_LOG_LENGTH];
+extern PIPX_PACKET_LOG_ENTRY IpxPacketLogLoc;
+extern PIPX_PACKET_LOG_ENTRY IpxPacketLogEnd;
+
+//
+// Bit fields in IpxPacketLogDebug
+//
+
+#define IPX_PACKET_LOG_RCV_RIP 0x0001 // All RIP packets
+#define IPX_PACKET_LOG_RCV_SPX 0x0002 // All SPX packets
+#define IPX_PACKET_LOG_RCV_NB 0x0004 // All Netbios packets
+#define IPX_PACKET_LOG_RCV_OTHER 0x0008 // All TDI client packets
+#define IPX_PACKET_LOG_RCV_SOCKET 0x0010 // All packets to IpxPacketLogSocket
+#define IPX_PACKET_LOG_RCV_ALL 0x0020 // All packets (even non-IPX)
+
+#define IPX_PACKET_LOG_SEND_RIP 0x0001 // All RIP packets
+#define IPX_PACKET_LOG_SEND_SPX 0x0002 // All SPX packets
+#define IPX_PACKET_LOG_SEND_NB 0x0004 // All Netbios packets
+#define IPX_PACKET_LOG_SEND_OTHER 0x0008 // All TDI client packets
+#define IPX_PACKET_LOG_SEND_SOCKET 0x0010 // All packets from IpxPacketLogSocket
+
+VOID
+IpxLogPacket(
+ IN BOOLEAN Send,
+ IN PUCHAR DestMac,
+ IN PUCHAR SrcMac,
+ IN USHORT Length,
+ IN PVOID IpxHeader,
+ IN PVOID Data
+ );
+
+#define PACKET_LOG(_Bit) (IpxPacketLogDebug & (_Bit))
+
+#else // IPX_PACKET_LOG
+
+#define IpxLogPacket(_MacHeader,_Length,_IpxHeader,_Data)
+#define PACKET_LOG(_Bit) 0
+
+#endif // IPX_PACKET_LOG
+
+#ifdef _PNP_POWER
+//
+// In load-only PnP, references are not needed on adapters. This should be changed
+// to actually take the reference post 4.0.
+//
+// BUGBUG: Revisit Post 4.0 - Keep the actual instructions around for ease of activation later.
+//
+#define IpxReferenceAdapter(_adapter)
+ // InterlockedIncrement(&(_adapter)->ReferenceCount)
+
+#define IpxDereferenceAdapter(_adapter)
+/*
+ if (InterlockedDecrement(&(_adapter)->ReferenceCount) == 0) {\
+ IpxCloseNdis(_adapter); \
+ IpxDestroyAdapter(_adapter);\
+ }\
+*/
+#endif
+
+//
+// In load-only PnP case, we dont need the references on bindings. All such references
+// have been changed to this macro.
+//
+#define IpxReferenceBinding1(_Binding, _Type)
+
+#define IpxDereferenceBinding1(_Binding, _Type)
+
+#if DBG
+
+#define IpxReferenceBinding(_Binding, _Type) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_Binding)->RefTypes[_Type], \
+ 1, \
+ &IpxGlobalInterlock); \
+ IpxRefBinding (_Binding)
+
+#define IpxDereferenceBinding(_Binding, _Type) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_Binding)->RefTypes[_Type], \
+ (ULONG)-1, \
+ &IpxGlobalInterlock); \
+ IpxDerefBinding (_Binding)
+
+#define IpxReferenceDevice(_Device, _Type) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_Device)->RefTypes[_Type], \
+ 1, \
+ &IpxGlobalInterlock); \
+ IpxRefDevice (_Device)
+
+#define IpxDereferenceDevice(_Device, _Type) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_Device)->RefTypes[_Type], \
+ (ULONG)-1, \
+ &IpxGlobalInterlock); \
+ IpxDerefDevice (_Device)
+
+
+#define IpxReferenceAddress(_Address, _Type) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_Address)->RefTypes[_Type], \
+ 1, \
+ &IpxGlobalInterlock); \
+ IpxRefAddress (_Address)
+
+#define IpxReferenceAddressLock(_Address, _Type) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_Address)->RefTypes[_Type], \
+ 1, \
+ &IpxGlobalInterlock); \
+ IpxRefAddressLock (_Address)
+
+#define IpxDereferenceAddress(_Address, _Type) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_Address)->RefTypes[_Type], \
+ (ULONG)-1, \
+ &IpxGlobalInterlock); \
+ IpxDerefAddress (_Address)
+
+#define IpxDereferenceAddressSync(_Address, _Type) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_Address)->RefTypes[_Type], \
+ (ULONG)-1, \
+ &IpxGlobalInterlock); \
+ IpxDerefAddressSync (_Address)
+
+
+#define IpxReferenceAddressFile(_AddressFile, _Type) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_AddressFile)->RefTypes[_Type], \
+ 1, \
+ &IpxGlobalInterlock); \
+ IpxRefAddressFile (_AddressFile)
+
+#define IpxReferenceAddressFileLock(_AddressFile, _Type) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_AddressFile)->RefTypes[_Type], \
+ 1, \
+ &IpxGlobalInterlock); \
+ IpxRefAddressFileLock (_AddressFile)
+
+#define IpxReferenceAddressFileSync(_AddressFile, _Type) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_AddressFile)->RefTypes[_Type], \
+ 1, \
+ &IpxGlobalInterlock); \
+ IpxRefAddressFileSync (_AddressFile)
+
+#define IpxDereferenceAddressFile(_AddressFile, _Type) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_AddressFile)->RefTypes[_Type], \
+ (ULONG)-1, \
+ &IpxGlobalInterlock); \
+ IpxDerefAddressFile (_AddressFile)
+
+#define IpxDereferenceAddressFileSync(_AddressFile, _Type) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_AddressFile)->RefTypes[_Type], \
+ (ULONG)-1, \
+ &IpxGlobalInterlock); \
+ IpxDerefAddressFileSync (_AddressFile)
+
+#define IpxTransferReferenceAddressFile(_AddressFile, _OldType, _NewType) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_AddressFile)->RefTypes[_NewType], \
+ 1, \
+ &IpxGlobalInterlock); \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_AddressFile)->RefTypes[_OldType], \
+ (ULONG)-1, \
+ &IpxGlobalInterlock);
+
+#else // DBG
+
+#define IpxReferenceBinding(_Binding, _Type) \
+ InterlockedIncrement(&(_Binding)->ReferenceCount)
+
+#define IpxDereferenceBinding(_Binding, _Type) \
+ IpxDerefBinding (_Binding)
+
+#define IpxReferenceDevice(_Device, _Type) \
+ InterlockedIncrement(&(_Device)->ReferenceCount)
+
+#define IpxDereferenceDevice(_Device, _Type) \
+ IpxDerefDevice (_Device)
+
+#define IpxReferenceAddress(_Address, _Type) \
+ InterlockedIncrement(&(_Address)->ReferenceCount)
+
+#define IpxReferenceAddressLock(_Address, _Type) \
+ InterlockedIncrement(&(_Address)->ReferenceCount)
+
+#define IpxDereferenceAddress(_Address, _Type) \
+ IpxDerefAddress (_Address)
+
+#define IpxDereferenceAddressSync(_Address, _Type) \
+ IpxDerefAddressSync (_Address)
+
+#define IpxReferenceAddressFile(_AddressFile, _Type) \
+ InterlockedIncrement(&(_AddressFile)->ReferenceCount)
+
+#define IpxReferenceAddressFileLock(_AddressFile, _Type) \
+ InterlockedIncrement(&(_AddressFile)->ReferenceCount)
+
+#define IpxReferenceAddressFileSync(_AddressFile, _Type) \
+ (VOID)IPX_ADD_ULONG( \
+ &(_AddressFile)->ReferenceCount, \
+ 1, \
+ (_AddressFile)->AddressLock)
+
+#define IpxDereferenceAddressFile(_AddressFile, _Type) \
+ if (InterlockedDecrement(&(_AddressFile)->ReferenceCount) == 0) { \
+ IpxDestroyAddressFile (_AddressFile); \
+ }
+
+#define IpxDereferenceAddressFileSync(_AddressFile, _Type) \
+ if (InterlockedDecrement(&(_AddressFile)->ReferenceCount) == 0) { \
+ IpxDestroyAddressFile (_AddressFile); \
+ }
+
+#define IpxTransferReferenceAddressFile(_AddressFile, _OldType, _NewType)
+
+#endif // DBG
+
+
+
+#if DBG
+
+#define IpxAllocateMemory(_BytesNeeded,_Tag,_Description) \
+ IpxpAllocateTaggedMemory(_BytesNeeded,_Tag,_Description)
+
+#define IpxFreeMemory(_Memory,_BytesAllocated,_Tag,_Description) \
+ IpxpFreeTaggedMemory(_Memory,_BytesAllocated,_Tag,_Description)
+
+#else // DBG
+
+#define IpxAllocateMemory(_BytesNeeded,_Tag,_Description) \
+ IpxpAllocateMemory(_BytesNeeded,_Tag,(BOOLEAN)((_Tag) != MEMORY_CONFIG))
+
+#define IpxFreeMemory(_Memory,_BytesAllocated,_Tag,_Description) \
+ IpxpFreeMemory(_Memory,_BytesAllocated,(BOOLEAN)((_Tag) != MEMORY_CONFIG))
+
+
+#endif // DBG
+
+
+//
+// This routine compares two node addresses.
+//
+
+#define IPX_NODE_EQUAL(_A,_B) \
+ ((*(UNALIGNED ULONG *)((PUCHAR)(_A)) == *(UNALIGNED ULONG *)((PUCHAR)(_B))) && \
+ (*(UNALIGNED USHORT *)(((PUCHAR)(_A))+4) == *(UNALIGNED USHORT *)(((PUCHAR)(_B))+4)))
+
+//
+// This routine checks if an address is the broadcast address.
+//
+
+#define IPX_NODE_BROADCAST(_A) \
+ ((*(UNALIGNED ULONG *)((PUCHAR)(_A)) == 0xffffffff) && \
+ (*(UNALIGNED USHORT *)(((PUCHAR)(_A))+4) == 0xffff))
+
+//
+// This routine does an ordered compare of two node addresses. It
+// can handle the first address having the source-routing bit on.
+//
+
+#define IPX_NODE_COMPARE(_A,_B,_R) \
+ if ((*(_R) = (*(UNALIGNED SHORT *)(((PUCHAR)(_A))+4) - *(UNALIGNED SHORT *)(((PUCHAR)(_B))+4))) == 0) { \
+ *(_R) = ((*(UNALIGNED LONG *)((PUCHAR)(_A)) & 0xffffff7f) - *(UNALIGNED LONG *)((PUCHAR)(_B))); \
+ }
+
+
+
+//
+// Routines in action.c
+//
+
+NTSTATUS
+IpxTdiAction(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+VOID
+IpxCancelAction(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+VOID
+IpxAbortLineChanges(
+ IN PVOID ControlChannelContext
+ );
+
+
+//
+// Routines in adapter.c
+//
+
+VOID
+IpxRefBinding(
+ IN PBINDING Binding
+ );
+
+VOID
+IpxDerefBinding(
+ IN PBINDING Binding
+ );
+
+NTSTATUS
+IpxCreateAdapter(
+ IN PDEVICE Device,
+ IN PUNICODE_STRING AdapterName,
+ IN OUT PADAPTER *AdapterPtr
+ );
+
+VOID
+IpxDestroyAdapter(
+ IN PADAPTER Adapter
+ );
+
+NTSTATUS
+IpxCreateBinding(
+ IN PDEVICE Device,
+ IN PBINDING_CONFIG ConfigBinding OPTIONAL,
+ IN ULONG NetworkNumberIndex,
+ IN PWCHAR AdapterName,
+ IN OUT PBINDING *BindingPtr
+ );
+
+VOID
+IpxDestroyBinding(
+ IN PBINDING Binding
+ );
+
+#ifdef _PNP_POWER
+VOID
+IpxAllocateBindingPool(
+ IN PDEVICE Device
+ );
+
+PSINGLE_LIST_ENTRY
+IpxPopBinding(
+ PDEVICE Device
+ );
+#endif
+
+//
+// Routines in address.c
+//
+
+TDI_ADDRESS_IPX UNALIGNED *
+IpxParseTdiAddress(
+ IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress
+ );
+
+BOOLEAN
+IpxValidateTdiAddress(
+ IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress,
+ IN ULONG TransportAddressLength
+ );
+
+#if DBG
+
+VOID
+IpxBuildTdiAddress(
+ IN PVOID AddressBuffer,
+ IN ULONG Network,
+ IN UCHAR Node[6],
+ IN USHORT Socket
+ );
+
+#else
+
+#define IpxBuildTdiAddress(_AddressBuffer,_Network,_Node,_Socket) { \
+ TA_IPX_ADDRESS UNALIGNED * _IpxAddress = (TA_IPX_ADDRESS UNALIGNED *)(_AddressBuffer); \
+ _IpxAddress->TAAddressCount = 1; \
+ _IpxAddress->Address[0].AddressLength = sizeof(TDI_ADDRESS_IPX); \
+ _IpxAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_IPX; \
+ _IpxAddress->Address[0].Address[0].NetworkAddress = (_Network); \
+ _IpxAddress->Address[0].Address[0].Socket = (_Socket); \
+ RtlCopyMemory(_IpxAddress->Address[0].Address[0].NodeAddress, (_Node), 6); \
+}
+
+#endif
+
+NTSTATUS
+IpxOpenAddress(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+USHORT
+IpxAssignSocket(
+ IN PDEVICE Device
+ );
+
+PADDRESS
+IpxCreateAddress(
+ IN PDEVICE Device,
+ IN USHORT Socket
+ );
+
+NTSTATUS
+IpxVerifyAddressFile(
+ IN PADDRESS_FILE AddressFile
+ );
+
+VOID
+IpxDestroyAddress(
+ IN PVOID Parameter
+ );
+
+#if DBG
+
+VOID
+IpxRefAddress(
+ IN PADDRESS Address
+ );
+
+VOID
+IpxRefAddressLock(
+ IN PADDRESS Address
+ );
+
+#endif
+
+VOID
+IpxDerefAddress(
+ IN PADDRESS Address
+ );
+
+VOID
+IpxDerefAddressSync(
+ IN PADDRESS Address
+ );
+
+PADDRESS_FILE
+IpxCreateAddressFile(
+ IN PDEVICE Device
+ );
+
+NTSTATUS
+IpxDestroyAddressFile(
+ IN PADDRESS_FILE AddressFile
+ );
+
+#if DBG
+
+VOID
+IpxRefAddressFile(
+ IN PADDRESS_FILE AddressFile
+ );
+
+VOID
+IpxRefAddressFileLock(
+ IN PADDRESS_FILE AddressFile
+ );
+
+VOID
+IpxRefAddressFileSync(
+ IN PADDRESS_FILE AddressFile
+ );
+
+VOID
+IpxDerefAddressFile(
+ IN PADDRESS_FILE AddressFile
+ );
+
+VOID
+IpxDerefAddressFileSync(
+ IN PADDRESS_FILE AddressFile
+ );
+
+#endif
+
+PADDRESS
+IpxLookupAddress(
+ IN PDEVICE Device,
+ IN USHORT Socket
+ );
+
+NTSTATUS
+IpxStopAddressFile(
+ IN PADDRESS_FILE AddressFile
+ );
+
+NTSTATUS
+IpxCloseAddressFile(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+
+//
+// Routines in device.c
+//
+
+VOID
+IpxRefDevice(
+ IN PDEVICE Device
+ );
+
+VOID
+IpxDerefDevice(
+ IN PDEVICE Device
+ );
+
+NTSTATUS
+IpxCreateDevice(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING DeviceName,
+ IN ULONG SegmentCount,
+ IN OUT PDEVICE *DevicePtr
+ );
+
+VOID
+IpxDestroyDevice(
+ IN PDEVICE Device
+ );
+
+
+//
+// Routines in driver.c
+//
+#ifdef _PNP_POWER
+VOID
+IpxPnPUpdateDevice(
+ IN PDEVICE Device
+ );
+#endif
+
+BOOLEAN
+IpxIsAddressLocal(
+ IN TDI_ADDRESS_IPX UNALIGNED * SourceAddress
+ );
+
+PVOID
+IpxpAllocateMemory(
+ IN ULONG BytesNeeded,
+ IN ULONG Tag,
+ IN BOOLEAN ChargeDevice
+ );
+
+VOID
+IpxpFreeMemory(
+ IN PVOID Memory,
+ IN ULONG BytesAllocated,
+ IN BOOLEAN ChargeDevice
+ );
+
+#if DBG
+
+PVOID
+IpxpAllocateTaggedMemory(
+ IN ULONG BytesNeeded,
+ IN ULONG Tag,
+ IN PUCHAR Description
+ );
+
+VOID
+IpxpFreeTaggedMemory(
+ IN PVOID Memory,
+ IN ULONG BytesAllocated,
+ IN ULONG Tag,
+ IN PUCHAR Description
+ );
+
+#endif
+
+VOID
+IpxWriteResourceErrorLog(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN NTSTATUS ErrorCode,
+ IN ULONG BytesNeeded,
+ IN ULONG UniqueErrorValue
+ );
+
+VOID
+IpxWriteGeneralErrorLog(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN NTSTATUS ErrorCode,
+ IN ULONG UniqueErrorValue,
+ IN NTSTATUS FinalStatus,
+ IN PWSTR SecondString,
+ IN ULONG DumpDataCount,
+ IN ULONG DumpData[]
+ );
+
+VOID
+IpxWriteOidErrorLog(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN NTSTATUS ErrorCode,
+ IN NTSTATUS FinalStatus,
+ IN PWSTR AdapterString,
+ IN ULONG OidValue
+ );
+
+#ifdef _PNP_POWER
+ULONG
+IpxResolveAutoDetect(
+ IN PDEVICE Device,
+ IN ULONG ValidBindings,
+ IN CTELockHandle *LockHandle1,
+ IN PUNICODE_STRING RegistryPath
+ );
+
+VOID
+IpxResolveBindingSets(
+ IN PDEVICE Device,
+ IN ULONG ValidBindings
+ );
+
+NTSTATUS
+IpxBindToAdapter(
+ IN PDEVICE Device,
+ IN PBINDING_CONFIG ConfigAdapter,
+ IN PADAPTER *AdapterPtr,
+ IN ULONG FrameTypeIndex
+ );
+
+NTSTATUS
+IpxUnBindFromAdapter(
+ IN PBINDING Binding
+ );
+
+VOID
+IpxPnPUpdateBindingArray(
+ IN PDEVICE Device,
+ IN PADAPTER Adapter,
+ IN PBINDING_CONFIG ConfigBinding
+ );
+
+VOID
+IpxPnPToLoad();
+
+NTSTATUS
+IpxPnPReallocateBindingArray(
+ IN PDEVICE Device,
+ IN ULONG Size
+ );
+
+#endif _PNP_POWER
+
+//
+// Routines in event.c
+//
+
+NTSTATUS
+IpxTdiSetEventHandler(
+ IN PREQUEST Request
+ );
+
+
+//
+// Routines in ind.c
+//
+
+//
+// [CH] Added these two functions
+//
+INT
+IpxReceivePacket (
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_PACKET Packet
+ );
+
+NDIS_STATUS
+IpxReceiveIndicationNew(
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_HANDLE ReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize,
+ IN PMDL pMdl,
+ IN PINT pTdiClientCount
+ );
+
+NDIS_STATUS
+IpxReceiveIndication(
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_HANDLE ReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ );
+
+VOID
+IpxReceiveComplete(
+ IN NDIS_HANDLE BindingContext
+ );
+
+NTSTATUS
+IpxUpdateBindingNetwork(
+ IN PDEVICE Device,
+ IN PBINDING Binding,
+ IN ULONG Network
+ );
+
+
+//
+// Routines in internal.c
+//
+
+NTSTATUS
+IpxInternalBind(
+ IN PDEVICE Device,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+IpxInternalUnbind(
+ IN PDEVICE Device,
+ IN UINT Identifier
+ );
+
+VOID
+IpxInternalFindRoute(
+ IN PIPX_FIND_ROUTE_REQUEST FindRouteRequest
+ );
+
+NTSTATUS
+IpxInternalQuery(
+ IN ULONG InternalQueryType,
+#ifdef _PNP_POWER
+ IN PNIC_HANDLE NicHandle OPTIONAL,
+#else
+ IN USHORT NicId OPTIONAL,
+#endif
+ IN OUT PVOID Buffer,
+ IN ULONG BufferLength,
+ OUT PULONG BufferLengthNeeded OPTIONAL
+);
+
+VOID
+IpxInternalIncrementWanInactivity(
+#ifdef _PNP_LATER
+ IN NIC_HANDLE NicHandle
+#else
+ IN USHORT NicId
+#endif
+);
+
+ULONG
+IpxInternalQueryWanInactivity(
+#ifdef _PNP_LATER
+ IN NIC_HANDLE NicHandle
+#else
+ IN USHORT NicId
+#endif
+);
+
+#ifdef _PNP_POWER
+VOID
+IpxPnPIsnIndicate(
+ IN PVOID Param
+);
+#endif
+
+//
+// Routines in ndis.c
+//
+
+NTSTATUS
+IpxRegisterProtocol(
+ IN PNDIS_STRING NameString
+ );
+
+VOID
+IpxDeregisterProtocol(
+ VOID
+ );
+
+NTSTATUS
+IpxInitializeNdis(
+ IN PADAPTER Adapter,
+ IN PBINDING_CONFIG ConfigBinding
+ );
+
+VOID
+IpxAddBroadcast(
+ IN PDEVICE Device
+ );
+
+VOID
+IpxRemoveBroadcast(
+ IN PDEVICE Device
+ );
+
+VOID
+IpxBroadcastOperation(
+ IN PVOID Parameter
+ );
+
+BOOLEAN
+IpxIsAddressLocal(
+ IN TDI_ADDRESS_IPX UNALIGNED * SourceAddress
+ );
+
+VOID
+IpxCloseNdis(
+ IN PADAPTER Adapter
+ );
+
+VOID
+IpxOpenAdapterComplete(
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_STATUS NdisStatus,
+ IN NDIS_STATUS OpenErrorStatus
+ );
+
+VOID
+IpxCloseAdapterComplete(
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_STATUS NdisStatus
+ );
+
+VOID
+IpxResetComplete(
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_STATUS NdisStatus
+ );
+
+VOID
+IpxRequestComplete(
+ IN NDIS_HANDLE BindingContext,
+ IN PNDIS_REQUEST NdisRequest,
+ IN NDIS_STATUS NdisStatus
+ );
+
+VOID
+IpxStatus(
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_STATUS NdisStatus,
+ IN PVOID StatusBuffer,
+ IN UINT StatusBufferSize
+ );
+
+VOID
+IpxStatusComplete(
+ IN NDIS_HANDLE NdisBindingContext
+ );
+
+
+#ifdef _PNP_POWER
+VOID
+IpxBindAdapter(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE BindContext,
+ IN PNDIS_STRING DeviceName,
+ IN PVOID SystemSpecific1,
+ IN PVOID SystemSpecific2
+ );
+
+VOID
+IpxUnbindAdapter(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_HANDLE UnbindContext
+ );
+
+VOID
+IpxTranslate(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE ProtocolBindingContext,
+ OUT PNET_PNP_ID IdList,
+ IN ULONG IdListLength,
+ OUT PULONG BytesReturned
+ );
+#endif // _PNP_POWER
+
+//
+// Routines in mac.c
+//
+
+VOID
+MacInitializeBindingInfo(
+ IN struct _BINDING * Binding,
+ IN struct _ADAPTER * Adapter
+ );
+
+VOID
+MacInitializeMacInfo(
+ IN NDIS_MEDIUM MacType,
+ OUT PNDIS_INFORMATION MacInfo
+ );
+
+VOID
+MacMapFrameType(
+ IN NDIS_MEDIUM MacType,
+ IN ULONG FrameType,
+ OUT ULONG * MappedFrameType
+ );
+
+VOID
+MacReturnMaxDataSize(
+ IN PNDIS_INFORMATION MacInfo,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength,
+ IN UINT DeviceMaxFrameSize,
+ OUT PUINT MaxFrameSize
+ );
+
+#ifdef _PNP_POWER
+NDIS_STATUS
+IpxSendFramePreFwd(
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ );
+#endif
+
+NDIS_STATUS
+IpxSendFrame(
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ );
+
+NDIS_STATUS
+IpxSendFrame802_3802_3(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ );
+
+NDIS_STATUS
+IpxSendFrame802_3802_2(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ );
+
+NDIS_STATUS
+IpxSendFrame802_3EthernetII(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ );
+
+NDIS_STATUS
+IpxSendFrame802_3Snap(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ );
+
+NDIS_STATUS
+IpxSendFrame802_5802_2(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ );
+
+NDIS_STATUS
+IpxSendFrame802_5Snap(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ );
+
+NDIS_STATUS
+IpxSendFrameFddi802_3(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ );
+
+NDIS_STATUS
+IpxSendFrameFddi802_2(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ );
+
+NDIS_STATUS
+IpxSendFrameFddiSnap(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ );
+
+NDIS_STATUS
+IpxSendFrameArcnet878_2(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ );
+
+NDIS_STATUS
+IpxSendFrameWanEthernetII(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ );
+
+VOID
+MacUpdateSourceRouting(
+ IN ULONG Database,
+ IN PADAPTER Adapter,
+ IN PUCHAR MacHeader,
+ IN ULONG MacHeaderLength
+ );
+
+VOID
+MacLookupSourceRouting(
+ IN ULONG Database,
+ IN PBINDING Binding,
+ IN UCHAR NextRouter[6],
+ IN OUT UCHAR SourceRouting[18],
+ OUT PULONG SourceRoutingLength
+ );
+
+VOID
+MacSourceRoutingTimeout(
+ CTEEvent * Event,
+ PVOID Context
+ );
+
+VOID
+MacSourceRoutingRemove(
+ IN PBINDING Binding,
+ IN UCHAR MacAddress[6]
+ );
+
+VOID
+MacSourceRoutingClear(
+ IN PBINDING Binding
+ );
+
+
+//
+// Routines in packet.c
+//
+
+NTSTATUS
+IpxInitializeSendPacket(
+ IN PDEVICE Device,
+ IN PIPX_SEND_PACKET Packet,
+ IN PUCHAR Header
+ );
+
+#if BACK_FILL
+NTSTATUS
+IpxInitializeBackFillPacket(
+ IN PDEVICE Device,
+ IN PIPX_SEND_PACKET Packet,
+ IN PUCHAR Header
+ );
+#endif
+
+NTSTATUS
+IpxInitializeReceivePacket(
+ IN PDEVICE Device,
+ IN PIPX_RECEIVE_PACKET Packet
+ );
+
+NTSTATUS
+NbiInitializeReceiveBuffer(
+ IN PADAPTER Adapter,
+ IN PIPX_RECEIVE_BUFFER ReceiveBuffer,
+ IN PUCHAR DataBuffer,
+ IN ULONG DataBufferLength
+ );
+
+NTSTATUS
+IpxInitializePaddingBuffer(
+ IN PDEVICE Device,
+ IN PIPX_PADDING_BUFFER PaddingBuffer,
+ IN ULONG DataBufferLength
+ );
+
+VOID
+IpxDeinitializeSendPacket(
+ IN PDEVICE Device,
+ IN PIPX_SEND_PACKET Packet
+ );
+
+#if BACK_FILL
+VOID
+IpxDeinitializeBackFillPacket(
+ IN PDEVICE Device,
+ IN PIPX_SEND_PACKET Packet
+ );
+#endif
+
+VOID
+IpxDeinitializeReceivePacket(
+ IN PDEVICE Device,
+ IN PIPX_RECEIVE_PACKET Packet
+ );
+
+VOID
+IpxDeinitializeReceiveBuffer(
+ IN PADAPTER Adapter,
+ IN PIPX_RECEIVE_BUFFER ReceiveBuffer,
+ IN ULONG DataBufferLength
+ );
+
+VOID
+IpxDeinitializePaddingBuffer(
+ IN PDEVICE Device,
+ IN PIPX_PADDING_BUFFER PaddingBuffer,
+ IN ULONG DataBufferLength
+ );
+
+VOID
+IpxAllocateSendPool(
+ IN PDEVICE Device
+ );
+
+#if BACK_FILL
+VOID
+IpxAllocateBackFillPool(
+ IN PDEVICE Device
+ );
+#endif
+
+VOID
+IpxAllocateReceivePool(
+ IN PDEVICE Device
+ );
+
+VOID
+IpxAllocateReceiveBufferPool(
+ IN PADAPTER Adapter
+ );
+
+PSINGLE_LIST_ENTRY
+IpxPopSendPacket(
+ IN PDEVICE Device
+ );
+
+#if BACK_FILL
+PSINGLE_LIST_ENTRY
+IpxPopBackFillPacket(
+ IN PDEVICE Device
+ );
+#endif
+
+PSINGLE_LIST_ENTRY
+IpxPopReceivePacket(
+ IN PDEVICE Device
+ );
+
+PSINGLE_LIST_ENTRY
+IpxPopReceiveBuffer(
+ IN PADAPTER Adapter
+ );
+
+PIPX_PADDING_BUFFER
+IpxAllocatePaddingBuffer(
+ IN PDEVICE Device
+ );
+
+VOID
+IpxFreePaddingBuffer(
+ IN PDEVICE Device
+ );
+
+
+
+//
+// Routines in query.c
+//
+
+NTSTATUS
+IpxTdiQueryInformation(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+NTSTATUS
+IpxTdiSetInformation(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+
+//
+// Routines in receive.c
+//
+
+VOID
+IpxTransferDataComplete(
+ IN NDIS_HANDLE BindingContext,
+ IN PNDIS_PACKET NdisPacket,
+ IN NDIS_STATUS NdisStatus,
+ IN UINT BytesTransferred
+ );
+
+
+VOID
+IpxTransferData(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ IN OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ );
+
+NTSTATUS
+IpxTdiReceiveDatagram(
+ IN PREQUEST Request
+ );
+
+VOID
+IpxCancelReceiveDatagram(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+
+//
+// Routines in rip.c
+//
+
+NTSTATUS
+RipGetLocalTarget(
+ IN ULONG Segment,
+ IN TDI_ADDRESS_IPX UNALIGNED * RemoteAddress,
+ IN UCHAR Type,
+ OUT PIPX_LOCAL_TARGET LocalTarget,
+ OUT USHORT Counts[2] OPTIONAL
+ );
+
+NTSTATUS
+RipQueueRequest(
+ IN ULONG Network,
+ IN USHORT Operation
+ );
+
+VOID
+RipSendResponse(
+ IN PBINDING Binding,
+ IN TDI_ADDRESS_IPX UNALIGNED * RemoteAddress,
+ IN PIPX_LOCAL_TARGET LocalTarget
+ );
+
+VOID
+RipShortTimeout(
+ CTEEvent * Event,
+ PVOID Context
+ );
+
+VOID
+RipLongTimeout(
+ CTEEvent * Event,
+ PVOID Context
+ );
+
+VOID
+RipCleanupPacket(
+ IN PDEVICE Device,
+ IN PIPX_SEND_RESERVED RipReserved
+ );
+
+VOID
+RipProcessResponse(
+ IN PDEVICE Device,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN RIP_PACKET UNALIGNED * RipPacket
+ );
+
+VOID
+RipHandleRoutePending(
+ IN PDEVICE Device,
+ IN UCHAR Network[4],
+ IN CTELockHandle LockHandle,
+ IN BOOLEAN Success,
+ IN OPTIONAL PIPX_LOCAL_TARGET LocalTarget,
+ IN OPTIONAL USHORT HopCount,
+ IN OPTIONAL USHORT TickCount
+ );
+
+NTSTATUS
+RipInsertLocalNetwork(
+ IN ULONG Network,
+ IN USHORT NicId,
+ IN NDIS_HANDLE NdisBindingContext,
+ IN USHORT Count
+ );
+
+VOID
+RipAdjustForBindingChange(
+ IN USHORT NicId,
+ IN USHORT NewNicId,
+ IN IPX_BINDING_CHANGE_TYPE ChangeType
+ );
+
+UINT
+RipGetSegment(
+ IN UCHAR Network[4]
+ );
+
+PIPX_ROUTE_ENTRY
+RipGetRoute(
+ IN UINT Segment,
+ IN UCHAR Network[4]
+ );
+
+BOOLEAN
+RipAddRoute(
+ IN UINT Segment,
+ IN PIPX_ROUTE_ENTRY RouteEntry
+ );
+
+BOOLEAN
+RipDeleteRoute(
+ IN UINT Segment,
+ IN PIPX_ROUTE_ENTRY RouteEntry
+ );
+
+PIPX_ROUTE_ENTRY
+RipGetFirstRoute(
+ IN UINT Segment
+ );
+
+PIPX_ROUTE_ENTRY
+RipGetNextRoute(
+ IN UINT Segment
+ );
+
+VOID
+RipDropRemoteEntries(
+ VOID
+ );
+
+
+//
+// Routines in send.c
+//
+
+VOID
+IpxSendComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_PACKET NdisPacket,
+ IN NDIS_STATUS NdisStatus
+ );
+
+NTSTATUS
+IpxTdiSendDatagram(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PREQUEST Request
+ );
+
+#if DBG
+VOID
+IpxConstructHeader(
+ IN PUCHAR Header,
+ IN USHORT PacketLength,
+ IN UCHAR PacketType,
+ IN TDI_ADDRESS_IPX UNALIGNED * RemoteAddress,
+ IN PTDI_ADDRESS_IPX LocalAddress
+ );
+#else
+#define IpxConstructHeader(_Header,_PacketLength,_PacketType,_RemoteAddress,_LocalAddress) { \
+ PIPX_HEADER _IpxHeader = (PIPX_HEADER)(_Header); \
+ _IpxHeader->CheckSum = 0xffff; \
+ _IpxHeader->PacketLength[0] = (UCHAR)((_PacketLength) / 256); \
+ _IpxHeader->PacketLength[1] = (UCHAR)((_PacketLength) % 256); \
+ _IpxHeader->TransportControl = 0; \
+ _IpxHeader->PacketType = (_PacketType); \
+ RtlCopyMemory(_IpxHeader->DestinationNetwork, (PVOID)(_RemoteAddress), 12); \
+ RtlCopyMemory(_IpxHeader->SourceNetwork, (_LocalAddress), 12); \
+}
+#endif
+
+//
+// Routines in loopback.c
+//
+
+VOID
+IpxDoLoopback(
+ IN CTEEvent *Event,
+ IN PVOID Context
+ );
+
+VOID
+IpxInitLoopback();
+
+VOID
+IpxLoopbackEnque(
+ IN PNDIS_PACKET Packet,
+ IN PVOID Context
+ );
+
diff --git a/private/ntos/tdi/isnp/ipx/ipxtypes.h b/private/ntos/tdi/isnp/ipx/ipxtypes.h
new file mode 100644
index 000000000..0cc788a8f
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/ipxtypes.h
@@ -0,0 +1,1999 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ ipxtypes.h
+
+Abstract:
+
+ This module contains definitions specific to the
+ IPX module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 2-September-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) 3-Oct-1995
+ Changes to support transfer of buffer ownership to transports - tagged [CH]
+
+ Sanjay Anand (SanjayAn) 27-Oct-1995
+ Changes to support Plug and Play (in _PNP_POWER)
+
+--*/
+
+
+//
+// Definition of the protocol reserved field of a send packet.
+//
+
+typedef struct _IPX_SEND_RESERVED {
+ UCHAR Identifier; // 0 for IPX packets
+ BOOLEAN SendInProgress; // used in an NdisSend
+ BOOLEAN OwnedByAddress; // packet is owned by an address
+ UCHAR DestinationType; // one of DEF, BCAST, MCAST
+ struct _IPX_PADDING_BUFFER * PaddingBuffer; // if one was allocated
+ PNDIS_BUFFER PreviousTail; // if padding buffer was appended
+#ifdef _PNP_POWER
+ IPX_LOCAL_TARGET LocalTarget;
+ USHORT CurrentNicId; // current binding being tried for net 0 sends
+ ULONG PacketLength; // length that comes into IpxSendFrame initially
+ BOOLEAN Net0SendSucceeded; // at least one NdisSend succeeded for net 0 sends
+#endif
+ SINGLE_LIST_ENTRY PoolLinkage; // when on free queue
+ LIST_ENTRY GlobalLinkage; // all packets are on this
+ LIST_ENTRY WaitLinkage; // when on WaitingForRoute/WaitingRipPackets
+#ifdef IPX_TRACK_POOL
+ PVOID Pool; // send pool it was allocated from
+#endif
+ struct _ADDRESS * Address; // that owns this packet, if ones does
+
+ //
+ // The next fields are used differently depending on whether
+ // the packet is being used for a datagram send or a rip request.
+ //
+
+ union {
+ struct {
+ PREQUEST Request; // send datagram request
+ struct _ADDRESS_FILE * AddressFile; // that this send is on
+ USHORT CurrentNicId; // current binding being tried for net 0 sends
+ BOOLEAN Net0SendSucceeded; // at least one NdisSend succeeded for net 0 sends
+ BOOLEAN OutgoingSap; // packet is sent from the SAP socket
+ } SR_DG;
+ struct {
+ ULONG Network; // net we are looking for
+ USHORT CurrentNicId; // current binding being tried
+ UCHAR RetryCount; // number of times sent; 0xfe = response, 0xff = down
+ BOOLEAN RouteFound; // network has been found
+ USHORT SendTime; // timer expirations when sent.
+ BOOLEAN NoIdAdvance; // don't advance CurrentNicId this time.
+ } SR_RIP;
+ } u;
+
+ PUCHAR Header; // points to the MAC/IPX header
+ PNDIS_BUFFER HeaderBuffer; // the NDIS_BUFFER describing Header;
+#if BACK_FILL
+ BOOLEAN BackFill; // 1 if we are using SMB's extended header
+ PNDIS_BUFFER IpxHeader; // Place holder for our IpxHeader
+ PNDIS_BUFFER MacHeader; // Place holder for our mac header
+ PVOID MappedSystemVa;
+ PVOID ByteOffset;
+ LONG UserLength;
+#endif
+} IPX_SEND_RESERVED, *PIPX_SEND_RESERVED;
+
+//
+// Values for the DestinationType field.
+//
+
+#define DESTINATION_DEF 1
+#define DESTINATION_BCAST 2
+#define DESTINATION_MCAST 3
+
+//
+// Used to indicate to IpxReceiveIndication that this is a loopback packet
+// Assumption: Ndis cannot return this as the NdisBindingHandle value since
+// that is a pointer (our pointers shd in kernel space, if not in Nonpaged pool).
+//
+#define IPX_LOOPBACK_COOKIE 0x00460007
+
+//
+// MIN/MAX macros
+//
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+
+#ifdef _PNP_POWER
+
+//
+// In order to avoid a lock to read a value, this is used.
+// As long as the final value has made it to _b by the time
+// the check is made, this works fine.
+//
+
+#define ASSIGN_LOOP(_a, _b) \
+ do { \
+ _a = _b; \
+ } while ( _a != _b );
+
+//
+// Gets the value of a Ulong (possibly a pointer) by adding 0 in an interlocked manner.
+// This relies on the fact that the return of the ExchangeAdd will be the value prior to
+// addition. Since the value added is 0, the final value stays the same.
+//
+#define GET_VALUE(x) \
+ InterlockedExchangeAdd((PULONG)&(x), 0)
+
+#define SET_VALUE(x,y) \
+ InterlockedExchange((PLONG)&(x), (LONG)(y))
+
+/*
+PBINDING
+NIC_ID_TO_BINDING (
+ IN PDEVICE _device,
+ IN USHORT _nicid
+ );
+*/
+//
+// We need to ensure that the binding array pointer is valid hence use the interlocked operation.
+// Also, the binding pointer read out of the array should be valid. Since the bindings are never
+// freed (IPX maintains a pool of bindings), the pointer thus retrieved will always point to
+// memory that belongs to us, which in the worst case could point to a re-claimed binding block.
+//
+// BUGBUGZZ: we can eliminate the second interlock if we always ensure that the bindings in an array
+// dont change i.e. when we move around bindings, do them in a copy and make that the master (thru'
+// a single ulong exchange).
+//
+// A problem that still remains here is that even if we get a valid (IPX owned non-paged) ptr out of
+// the array, we still cannot atomically get a ref on the binding
+// We might need those locks after all.... (revisit post SUR when the delete is enabled).
+//
+#define NIC_ID_TO_BINDING(_device, _nicid) \
+ ((PBINDING)GET_VALUE( ((PBIND_ARRAY_ELEM) GET_VALUE( (_device)->Bindings) )[_nicid].Binding ))
+
+/*
+PBINDING
+NIC_ID_TO_BINDING_NO_ILOCK (
+ IN PDEVICE _device,
+ IN USHORT _nicid
+ );
+*/
+//
+// No interlocked operations are used here to get to the binding. This is used in the PnP add/delete
+// adapter paths on the assumption that NDIS will serialize the addition/deletion of cards. [JammelH: 5/15/96]
+//
+#define NIC_ID_TO_BINDING_NO_ILOCK(_device, _nicid) \
+ ((_device)->Bindings[_nicid].Binding)
+
+/*
+VOID
+INSERT_BINDING(
+ IN PDEVICE _device,
+ IN USHORT _nicid,
+ IN PBINDING _binding
+ )
+*/
+//
+// We dont do a get_value for the first arg of the macro since we are the writer and
+// this value cannot change from under us here (NDIS will not give us two PnP Add adapter
+// indications simultaneously).
+//
+#define INSERT_BINDING(_device, _nicid, _binding) \
+ SET_VALUE((_device)->Bindings[_nicid].Binding, (_binding));
+
+/*
+VOID
+SET_VERSION(
+ IN PDEVICE _device,
+ IN USHORT _nicid
+ )
+*/
+#define SET_VERSION(_device, _nicid) \
+ SET_VALUE((_device)->Bindings[_nicid].Version, ++(_device)->BindingVersionNumber);
+
+/*
+PBINDING
+NIC_HANDLE_TO_BINDING (
+ IN PDEVICE _device,
+ IN PNIC_HANDLE _nichandle,
+ );
+*/
+#ifdef _PNP_LATER
+#define NIC_HANDLE_TO_BINDING(_device, _nichandle) \
+ (((_nichandle)->Signature == IPX_BINDING_SIGNATURE) && \
+ ((_nichandle)->Version == (_device)->Bindings[(_nichandle)->NicId].Version)) ? \
+ (_device)->Bindings[(_nichandle)->NicId].Binding : NULL;
+#else
+
+#define NIC_HANDLE_TO_BINDING(_device, _nichandle) \
+ NIC_ID_TO_BINDING(_device, (_nichandle)->NicId);
+#endif
+
+/*
+VOID
+FILL_LOCAL_TARGET(
+ IN PLOCAL_TARGET _localtarget,
+ IN USHORT _nicid
+ )
+*/
+
+#define FILL_LOCAL_TARGET(_localtarget, _nicid) \
+ NIC_HANDLE_FROM_NIC((_localtarget)->NicHandle, _nicid)
+
+#ifdef _PNP_LATER
+#define NIC_HANDLE_FROM_NIC(_nichandle, _nic) \
+ _nichandle.NicId = _nic; \
+ _nichandle.Signature = IPX_BINDING_SIGNATURE; \
+ if (_nic == 0) { \
+ _nichandle.Version = 0; \
+ } else { \
+ _nichandle.Version = IpxDevice->Bindings[_nic].Version; \
+ }
+
+#else
+
+#define NIC_HANDLE_FROM_NIC(_nichandle, _nic) \
+ _nichandle.NicId = _nic;
+
+#endif
+
+#define NIC_FROM_LOCAL_TARGET(_localtarget) \
+ (_localtarget)->NicHandle.NicId
+
+#endif _PNP_POWER
+
+//
+// Definition of the protocol reserved field of a receive packet.
+//
+
+typedef struct _IPX_RECEIVE_RESERVED {
+ UCHAR Identifier; // 0 for IPX packets
+ BOOLEAN TransferInProgress; // used in an NdisTransferData
+ BOOLEAN OwnedByAddress; // packet is owned by an address
+#ifdef IPX_TRACK_POOL
+ PVOID Pool; // send pool it was allocated from
+#endif
+ struct _ADDRESS * Address; // that owns this packet, if ones does
+ PREQUEST SingleRequest; // if transfer is for one only
+ struct _IPX_RECEIVE_BUFFER * ReceiveBuffer; // if transfer is for multiple requests
+ SINGLE_LIST_ENTRY PoolLinkage; // when on free queue
+ LIST_ENTRY GlobalLinkage; // all packets are on this
+ LIST_ENTRY Requests; // waiting on this transfer
+} IPX_RECEIVE_RESERVED, *PIPX_RECEIVE_RESERVED;
+
+//
+// The amount of data we need in our standard header, rounded up
+// to the next longword bounday.
+//
+// [BUGBUGZZ] Make this declaration in one place
+//
+#define PACKET_HEADER_SIZE (MAC_HEADER_SIZE + IPX_HEADER_SIZE + RIP_PACKET_SIZE)
+
+//
+// Types to abstract NDIS packets. This is to allow us to
+// switch from using our own memory for packets to using
+// authentically allocated NDIS packets.
+//
+
+// #define IPX_OWN_PACKETS 1
+
+#define IpxAllocateSendPacket(_Device,_SendPacket,_Status) { \
+ NdisReinitializePacket((PNDIS_PACKET)(PACKET(_SendPacket))); \
+ *(_Status) = STATUS_SUCCESS; \
+}
+
+#define IpxAllocateReceivePacket(_Device,_ReceivePacket,_Status) { \
+ NdisReinitializePacket((PNDIS_PACKET)(PACKET(_ReceivePacket))); \
+ *(_Status) = STATUS_SUCCESS; \
+}
+
+#ifdef IPX_OWN_PACKETS
+
+#define NDIS_PACKET_SIZE 48
+// #define NDIS_PACKET_SIZE FIELD_OFFSET(NDIS_PACKET,ProtocolReserved[0])
+
+typedef struct _IPX_SEND_PACKET {
+ UCHAR Data[NDIS_PACKET_SIZE+sizeof(IPX_SEND_RESERVED)];
+} IPX_SEND_PACKET, *PIPX_SEND_PACKET;
+
+typedef struct _IPX_RECEIVE_PACKET {
+ UCHAR Data[NDIS_PACKET_SIZE+sizeof(IPX_RECEIVE_RESERVED)];
+} IPX_RECEIVE_PACKET, *PIPX_RECEIVE_PACKET;
+
+#define PACKET(_Packet) ((PNDIS_PACKET)((_Packet)->Data))
+
+#define IpxFreeSendPacket(_Device,_Packet)
+
+#define IpxFreeReceivePacket(_Device,_Packet)
+
+#else // IPX_OWN_PACKETS
+
+typedef struct _IPX_SEND_PACKET {
+ PNDIS_PACKET Packet;
+ NDIS_HANDLE PoolHandle;
+} IPX_SEND_PACKET, *PIPX_SEND_PACKET;
+
+typedef struct _IPX_RECEIVE_PACKET {
+ PNDIS_PACKET Packet;
+ NDIS_HANDLE PoolHandle;
+} IPX_RECEIVE_PACKET, *PIPX_RECEIVE_PACKET;
+
+#define PACKET(_Packet) ((_Packet)->Packet)
+
+#define IpxAllocateSingleSendPacket(_Device,_SendPacket,_Status) { \
+ NdisAllocatePacketPool(_Status, &(_SendPacket)->PoolHandle,1,sizeof(IPX_SEND_RESERVED)); \
+ if (*(_Status) == NDIS_STATUS_SUCCESS) { \
+ NdisAllocatePacket(_Status, &(_SendPacket)->Packet, (_SendPacket)->PoolHandle); \
+ if (*(_Status) == NDIS_STATUS_SUCCESS) { \
+ (_Device)->MemoryUsage += \
+ (FIELD_OFFSET(NDIS_PACKET_POOL,Buffer[0])+ \
+ FIELD_OFFSET(NDIS_PACKET,ProtocolReserved[0])+ \
+ sizeof(IPX_SEND_RESERVED)); \
+ } else {\
+ IPX_DEBUG (PACKET, ("Could not allocate Ndis packet memory\n"));\
+ }\
+ } else {\
+ IPX_DEBUG (PACKET, ("Could not allocate Ndis pool memory\n"));\
+ }\
+}
+
+#define IpxAllocateSingleReceivePacket(_Device,_ReceivePacket,_Status) { \
+ NdisAllocatePacketPool(_Status, &(_ReceivePacket)->PoolHandle,1,sizeof(IPX_RECEIVE_RESERVED)); \
+ if (*(_Status) == NDIS_STATUS_SUCCESS) { \
+ NdisAllocatePacket(_Status, &(_ReceivePacket)->Packet, (_ReceivePacket)->PoolHandle); \
+ if (*(_Status) == NDIS_STATUS_SUCCESS) { \
+ (_Device)->MemoryUsage += \
+ (FIELD_OFFSET(NDIS_PACKET_POOL,Buffer[0])+ \
+ FIELD_OFFSET(NDIS_PACKET,ProtocolReserved[0])+ \
+ sizeof(IPX_RECEIVE_RESERVED)); \
+ } else {\
+ IPX_DEBUG (PACKET, ("Could not allocate Ndis packet memory\n"));\
+ }\
+ } else {\
+ IPX_DEBUG (PACKET, ("Could not allocate Ndis pool memory\n"));\
+ }\
+}
+
+#define IpxFreeSingleSendPacket(_Device,_Packet) { \
+ NdisFreePacket((_Packet).Packet); \
+ NdisFreePacketPool((_Packet).PoolHandle); \
+ (_Device)->MemoryUsage -= \
+ (FIELD_OFFSET(NDIS_PACKET_POOL,Buffer[0])+ \
+ FIELD_OFFSET(NDIS_PACKET,ProtocolReserved[0])+ \
+ sizeof(IPX_SEND_RESERVED)); \
+}
+#define IpxFreeSingleReceivePacket(_Device,_Packet) { \
+ NdisFreePacket((_Packet).Packet); \
+ NdisFreePacketPool((_Packet).PoolHandle); \
+ (_Device)->MemoryUsage -= \
+ (FIELD_OFFSET(NDIS_PACKET_POOL,Buffer[0])+ \
+ FIELD_OFFSET(NDIS_PACKET,ProtocolReserved[0])+ \
+ sizeof(IPX_RECEIVE_RESERVED)); \
+}
+
+#define IpxFreeSendPacket(_Device,_Packet) NdisFreePacket(PACKET(_Packet))
+
+#define IpxFreeReceivePacket(_Device,_Packet) NdisFreePacket(PACKET(_Packet))
+
+#endif // IPX_OWN_PACKETS
+
+#define SEND_RESERVED(_Packet) ((PIPX_SEND_RESERVED)((PACKET(_Packet))->ProtocolReserved))
+#define RECEIVE_RESERVED(_Packet) ((PIPX_RECEIVE_RESERVED)((PACKET(_Packet))->ProtocolReserved))
+
+
+//
+// This is the structure that contains a receive buffer for
+// datagrams that are going to multiple recipients.
+//
+
+typedef struct _IPX_RECEIVE_BUFFER {
+ LIST_ENTRY GlobalLinkage; // all buffers are on this
+#ifdef IPX_TRACK_POOL
+ PVOID Pool; // receive buffer pool was allocated from
+#endif
+ SINGLE_LIST_ENTRY PoolLinkage; // when on free list
+ PNDIS_BUFFER NdisBuffer; // length of the NDIS buffer
+ ULONG DataLength; // length of the data
+ PUCHAR Data; // the actual data
+} IPX_RECEIVE_BUFFER, *PIPX_RECEIVE_BUFFER;
+
+
+//
+// This is the structure that contains a padding buffer for
+// padding ethernet frames out to an even number of bytes.
+//
+
+typedef struct _IPX_PADDING_BUFFER {
+ LIST_ENTRY GlobalLinkage; // all buffers are on this
+ SINGLE_LIST_ENTRY PoolLinkage; // when on free list
+ PNDIS_BUFFER NdisBuffer; // length of the NDIS buffer
+ ULONG DataLength; // length of the data
+ UCHAR Data[1]; // the actual pad data
+} IPX_PADDING_BUFFER, *PIPX_PADDING_BUFFER;
+
+#ifdef IPX_OWN_PACKETS
+
+typedef struct _IPX_SEND_POOL {
+ LIST_ENTRY Linkage;
+ UINT PacketCount;
+ UINT PacketFree;
+ IPX_SEND_PACKET Packets[1];
+} IPX_SEND_POOL, *PIPX_SEND_POOL;
+
+typedef struct _IPX_RECEIVE_POOL {
+ LIST_ENTRY Linkage;
+ UINT PacketCount;
+ UINT PacketFree;
+ IPX_RECEIVE_PACKET Packets[1];
+} IPX_RECEIVE_POOL, *PIPX_RECEIVE_POOL;
+#else
+
+typedef struct _IPX_PACKET_POOL {
+ LIST_ENTRY Linkage;
+ PUCHAR Header;
+ NDIS_HANDLE PoolHandle;
+} IPX_PACKET_POOL, *PIPX_PACKET_POOL;
+
+typedef IPX_PACKET_POOL IPX_RECEIVE_POOL, *PIPX_RECEIVE_POOL;
+typedef IPX_PACKET_POOL IPX_SEND_POOL, *PIPX_SEND_POOL;
+
+#endif // IPX_OWN_PACKETS
+
+typedef struct _IPX_RECEIVE_BUFFER_POOL {
+ LIST_ENTRY Linkage;
+ UINT BufferCount;
+ UINT BufferFree;
+ IPX_RECEIVE_BUFFER Buffers[1];
+ // after the packets the data buffers are allocated also.
+} IPX_RECEIVE_BUFFER_POOL, *PIPX_RECEIVE_BUFFER_POOL;
+
+//
+// Number of upper drivers we support.
+//
+
+#define UPPER_DRIVER_COUNT 3
+
+
+
+//
+// Tags for memory allocation.
+//
+
+#define MEMORY_CONFIG 0
+#define MEMORY_ADAPTER 1
+#define MEMORY_ADDRESS 2
+#define MEMORY_PACKET 3
+#define MEMORY_RIP 4
+#define MEMORY_SOURCE_ROUTE 5
+#define MEMORY_BINDING 6
+#define MEMORY_QUERY 7
+
+#define MEMORY_MAX 8
+
+#if DBG
+
+//
+// Holds the allocations for a specific memory type.
+//
+
+typedef struct _MEMORY_TAG {
+ ULONG Tag;
+ ULONG BytesAllocated;
+} MEMORY_TAG, *PMEMORY_TAG;
+
+EXTERNAL_LOCK(IpxMemoryInterlock);
+extern MEMORY_TAG IpxMemoryTag[MEMORY_MAX];
+
+#endif
+
+
+//
+// This defines the reasons we delete rip entries for a binding.
+//
+
+typedef enum _IPX_BINDING_CHANGE_TYPE {
+ IpxBindingDeleted,
+ IpxBindingMoved,
+ IpxBindingDown
+} IPX_BINDING_CHANGE_TYPE, *PIPX_BINDING_CHANGE_TYPE;
+
+
+//
+// This structure contains information about a single
+// source routing entry.
+//
+
+typedef struct _SOURCE_ROUTE {
+
+ struct _SOURCE_ROUTE * Next; // next in hash list
+
+ UCHAR MacAddress[6]; // remote MAC address
+ UCHAR TimeSinceUsed; // timer expirations since last used
+ UCHAR SourceRoutingLength; // length of the data
+
+ UCHAR SourceRouting[1]; // source routing data, stored as received in
+
+} SOURCE_ROUTE, *PSOURCE_ROUTE;
+
+#define SOURCE_ROUTE_SIZE(_SourceRoutingLength) \
+ (FIELD_OFFSET(SOURCE_ROUTE, SourceRouting[0]) + (_SourceRoutingLength))
+
+#define SOURCE_ROUTE_HASH_SIZE 16
+
+//
+// ULONG
+// MacSourceRoutingHash(
+// IN PUCHAR MacAddress
+// )
+//
+// /*++
+//
+// Routine Description:
+//
+// This routine returns a hash value based on the MAC address
+// that is pointed to. It will be between 0 and SOURCE_ROUTE_HASH_SIZE.
+//
+// Arguments:
+//
+// MacAddress - The MAC address. NOTE: The source-routing bit may
+// or may not be on in the first byte, this routine will handle
+// that.
+//
+// Return Value:
+//
+// The hash value.
+//
+// --*/
+//
+
+#define MacSourceRoutingHash(_MacAddress) \
+ ((ULONG)((_MacAddress)[5] % SOURCE_ROUTE_HASH_SIZE))
+
+
+
+//
+// this structure describes a single NDIS adapter that IPX is
+// bound to.
+//
+
+struct _DEVICE;
+
+typedef struct _ADAPTER {
+
+ CSHORT Type; // type of this structure
+ USHORT Size; // size of this structure
+
+#if DBG
+ UCHAR Signature1[4]; // contains "IAD1"
+#endif
+
+#ifdef _PNP_POWER
+ ULONG ReferenceCount;
+#endif
+
+ ULONG BindingCount; // number bound to this adapter
+
+ //
+ // Handle returned by the NDIS wrapper after we bind to it.
+ //
+
+ NDIS_HANDLE NdisBindingHandle;
+
+ //
+ // The queue of (currently receive only) requests waiting to complete.
+ //
+
+ LIST_ENTRY RequestCompletionQueue;
+
+ //
+ // IPX header normal offsets for directed and
+ // broadcast/multicast frames.
+ //
+
+ ULONG DefHeaderSizes[ISN_FRAME_TYPE_MAX];
+ ULONG BcMcHeaderSizes[ISN_FRAME_TYPE_MAX];
+
+ //
+ // List of buffers to be used for transfers.
+ //
+
+ ULONG AllocatedReceiveBuffers;
+ LIST_ENTRY ReceiveBufferPoolList;
+ SLIST_HEADER ReceiveBufferList;
+
+ //
+ // List of ethernet padding buffers.
+ //
+
+ ULONG AllocatedPaddingBuffers;
+ SINGLE_LIST_ENTRY PaddingBufferList;
+
+ struct _BINDING * Bindings[ISN_FRAME_TYPE_MAX]; // the binding for each frame type.
+
+ //
+ // TRUE if broadcast reception is enabled on this adapter.
+ //
+
+ BOOLEAN BroadcastEnabled;
+
+ //
+ // TRUE if we have enabled an auto-detected frame type
+ // on this adapter -- used to prevent multiple ones.
+ //
+
+ BOOLEAN AutoDetectFound;
+
+ //
+ // TRUE if we got a response to at least one of our
+ // auto-detect frames.
+ //
+
+ BOOLEAN AutoDetectResponse;
+
+ //
+ // This is TRUE if we are auto-detecting and we have
+ // found the default auto-detect type on the net.
+ //
+
+ BOOLEAN DefaultAutoDetected;
+
+ //
+ // For WAN adapters, we support multiple bindings per
+ // adapter, all with the same frame type. For them we
+ // demultiplex using the local mac address. This stores
+ // the range of device NIC IDs associated with this
+ // particular address.
+ //
+
+ USHORT FirstWanNicId;
+ USHORT LastWanNicId;
+ ULONG WanNicIdCount;
+
+ //
+ // This is based on the configuration.
+ //
+
+ USHORT BindSap; // usually 0x8137
+ USHORT BindSapNetworkOrder; // usually 0x3781
+ BOOLEAN SourceRouting;
+ BOOLEAN EnableFunctionalAddress;
+ BOOLEAN EnableWanRouter;
+ ULONG ConfigMaxPacketSize;
+
+ //
+ // TRUE if the tree is empty, so we can check quickly.
+ //
+
+ BOOLEAN SourceRoutingEmpty[IDENTIFIER_TOTAL];
+
+ //
+ // These are kept around for error logging, and stored right
+ // after this structure.
+ //
+
+ PWCHAR AdapterName;
+ ULONG AdapterNameLength;
+
+ struct _DEVICE * Device;
+
+ CTELock Lock;
+ CTELock * DeviceLock;
+
+ //
+ // some MAC addresses we use in the transport
+ //
+
+ HARDWARE_ADDRESS LocalMacAddress; // our local hardware address.
+
+ //
+ // The value of Device->SourceRoutingTime the last time
+ // we checked the list for timeouts (this is so we can
+ // tell in the timeout code when two bindings point to the
+ // same adapter).
+ //
+
+ CHAR LastSourceRoutingTime;
+
+ //
+ // These are used while initializing the MAC driver.
+ //
+
+ KEVENT NdisRequestEvent; // used for pended requests.
+ NDIS_STATUS NdisRequestStatus; // records request status.
+ NDIS_STATUS OpenErrorStatus; // if Status is NDIS_STATUS_OPEN_FAILED.
+
+ //
+ // This is the Mac type we must build the packet header for and know the
+ // offsets for.
+ //
+
+ NDIS_INFORMATION MacInfo;
+
+ ULONG MaxReceivePacketSize; // does not include the MAC header
+ ULONG MaxSendPacketSize; // includes the MAC header
+ ULONG ReceiveBufferSpace; // as queried from the card
+
+ //
+ // This information is used to keep track of the speed of
+ // the underlying medium.
+ //
+
+ ULONG MediumSpeed; // in units of 100 bytes/sec
+
+ //
+ // The source routing tree for each of the identifiers
+ //
+
+ PSOURCE_ROUTE SourceRoutingHeads[IDENTIFIER_TOTAL][SOURCE_ROUTE_HASH_SIZE];
+
+} ADAPTER, * PADAPTER;
+
+#define ASSERT_ADAPTER(_Adapter) \
+ CTEAssert (((_Adapter)->Type == IPX_ADAPTER_SIGNATURE) && ((_Adapter)->Size == sizeof(ADAPTER)))
+
+
+//
+// These are the media and frame type specific MAC header
+// constructors that we call in the main TDI send path.
+//
+
+typedef NDIS_STATUS
+(*IPX_SEND_FRAME_HANDLER) (
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ );
+
+
+#define BREF_BOUND 1
+#ifdef _PNP_POWER
+#define BREF_DEVICE_ACCESS 2
+#define BREF_ADAPTER_ACCESS 3
+#endif
+#define BREF_TOTAL 4
+
+typedef struct _BINDING {
+
+#if DBG
+ ULONG RefTypes[BREF_TOTAL];
+#endif
+
+ CSHORT Type; // type of this structure
+ USHORT Size; // size of this structure
+
+#if DBG
+ UCHAR Signature1[4]; // contains "IBI1"
+#endif
+
+ ULONG ReferenceCount;
+
+#ifdef _PNP_POWER
+ SINGLE_LIST_ENTRY PoolLinkage; // when on free queue
+#endif
+
+ //
+ // Adapter this binding is on.
+ //
+
+ PADAPTER Adapter;
+
+ //
+ // ID identifying us to the system (will be the index
+ // in Device->Bindings[]).
+ //
+
+ USHORT NicId;
+
+ //
+ // For LANs these will be the same as the adapter's, for WANs
+ // they change on line up indications.
+ //
+
+ ULONG MaxSendPacketSize;
+ ULONG MediumSpeed; // in units of 100 bytes/sec
+ HARDWARE_ADDRESS LocalMacAddress; // our local hardware address.
+
+ //
+ // This is used for WAN lines, all sends go to this address
+ // which is given on line up.
+ //
+
+ HARDWARE_ADDRESS RemoteMacAddress;
+
+ //
+ // For WAN lines, holds the remote address indicated to us
+ // in the IPXCP_CONFIGURATION structure -- this is used to
+ // select a binding to send to when WanGlobalNetworkNumber
+ // is TRUE.
+ //
+
+ UCHAR WanRemoteNode[6];
+
+ //
+ // TRUE if this binding was set up to allow auto-detection,
+ // instead of being configured explicitly in the registry.
+ //
+
+ BOOLEAN AutoDetect;
+
+ //
+ // TRUE if this binding was set up for auto-detection AND
+ // was the default in the registry.
+ //
+
+ BOOLEAN DefaultAutoDetect;
+
+ //
+ // During auto-detect when we are processing responses from
+ // various networks, these keep track of how many responses
+ // we have received that match the current guess at the
+ // network number, and how many don't (the current guess
+ // is stored in TentativeNetworkAddress).
+ //
+
+ USHORT MatchingResponses;
+ USHORT NonMatchingResponses;
+
+ //
+ // During auto-detect, stores the current guess at the
+ // network number.
+ //
+
+ ULONG TentativeNetworkAddress;
+
+ //
+ // TRUE if this binding is part of a binding set.
+ //
+
+ BOOLEAN BindingSetMember;
+
+ //
+ // TRUE if this binding should receive broadcasts (this
+ // rotates through the members of a binding set).
+ //
+
+ BOOLEAN ReceiveBroadcast;
+
+ //
+ // TRUE for WAN lines if we are up.
+ //
+
+ BOOLEAN LineUp;
+
+ //
+ // TRUE if this is a WAN line and is dialout.
+ //
+
+ BOOLEAN DialOutAsync;
+
+ union {
+
+ //
+ // Used when a binding is active, if it is a member
+ // of a binding set.
+ //
+
+ struct {
+
+ //
+ // Used to link members of a binding set in a circular list.
+ // NULL for non-set members.
+ //
+
+ struct _BINDING * NextBinding;
+
+ //
+ // If this binding is a master of a binding set, this points
+ // to the binding to use for the next send. For other members
+ // of a binding set it is NULL. We use this to determine
+ // if a binding is a master or not.
+ //
+
+ struct _BINDING * CurrentSendBinding;
+
+ //
+ // For binding set members, points to the master binding
+ // (if this is the master it points to itself).
+ //
+
+ struct _BINDING * MasterBinding;
+
+ };
+
+ //
+ // This is used when we are first binding to adapters,
+ // and the device's Bindings array is not yet allocated.
+ //
+
+ LIST_ENTRY InitialLinkage;
+
+ };
+
+ //
+ // Used by rip to keep track of unused wan lines.
+ //
+
+ ULONG WanInactivityCounter;
+
+ //
+ // Our local address, we don't use the socket but we keep
+ // it here so we can do quick copies. It contains the
+ // real network that we are bound to and our node
+ // address on that net (typically the adapter's MAC
+ // address but it will change for WANs).
+ //
+
+ TDI_ADDRESS_IPX LocalAddress;
+
+ IPX_SEND_FRAME_HANDLER SendFrameHandler;
+
+ struct _DEVICE * Device;
+
+ CTELock * DeviceLock;
+
+ ULONG DefHeaderSize; // IPX header offset for directed frames
+ ULONG BcMcHeaderSize; // IPX header offset for broadcast/multicast
+
+ ULONG AnnouncedMaxDatagramSize; // what we advertise -- assumes worst-case SR
+ ULONG RealMaxDatagramSize; // what will really break the card
+ ULONG MaxLookaheadData;
+
+ //
+ // Configuration parameters. We overlay all of them except
+ // FrameType over the worker thread item we use to delay
+ // deletion -- all the others are not needed once the
+ // binding is up. Some of the config parameters are stored
+ // in the adapter, these are the ones that are modified
+ // per-binding.
+ //
+
+ ULONG FrameType;
+ union {
+ struct {
+ ULONG ConfiguredNetworkNumber;
+ BOOLEAN AllRouteDirected;
+ BOOLEAN AllRouteBroadcast;
+ BOOLEAN AllRouteMulticast;
+ };
+ WORK_QUEUE_ITEM WanDelayedQueueItem;
+ };
+
+#ifdef _PNP_POWER
+ //
+ // Indicates whether this binding was indicated to the ISN driver
+ //
+ BOOLEAN IsnInformed[UPPER_DRIVER_COUNT];
+
+ //
+ // Keeps the NetAddressRegistrationHandle.
+ //
+ HANDLE TdiRegistrationHandle;
+#endif
+} BINDING, * PBINDING;
+
+
+#ifdef _PNP_POWER
+typedef struct _IPX_BINDING_POOL {
+ LIST_ENTRY Linkage;
+ UINT BindingCount;
+ BINDING Bindings[1];
+} IPX_BINDING_POOL, *PIPX_BINDING_POOL;
+#endif
+
+//
+// This structure defines the control structure for a single
+// router table segment.
+//
+
+typedef struct _ROUTER_SEGMENT {
+ LIST_ENTRY WaitingForRoute; // packets waiting for a route in this segment
+ LIST_ENTRY FindWaitingForRoute; // find route requests waiting for a route in this segment
+ LIST_ENTRY WaitingLocalTarget; // QUERY_IPX_LOCAL_TARGETs waiting for a route in this segment
+ LIST_ENTRY WaitingReripNetnum; // MIPX_RERIPNETNUMs waiting for a route in this segment
+ LIST_ENTRY Entries;
+ PLIST_ENTRY EnumerateLocation;
+} ROUTER_SEGMENT, *PROUTER_SEGMENT;
+
+
+//
+// Number of buckets in the address hash table. This is
+// a multiple of 2 so hashing is quick.
+//
+
+#define IPX_ADDRESS_HASH_COUNT 16
+
+//
+// Routine to convert a socket to a hash index. We use the
+// high bits because it is stored reversed.
+//
+
+#define IPX_HASH_SOCKET(_S) ((((_S) & 0xff00) >> 8) % IPX_ADDRESS_HASH_COUNT)
+
+//
+// This macro gets the socket hash right out of the IPX header.
+//
+
+#define IPX_DEST_SOCKET_HASH(_IpxHeader) (((PUCHAR)&(_IpxHeader)->DestinationSocket)[1] % IPX_ADDRESS_HASH_COUNT)
+
+
+//
+// This structure defines the per-device structure for IPX
+// (one of these is allocated globally).
+//
+
+#define DREF_CREATE 0
+#define DREF_LOADED 1
+#define DREF_ADAPTER 2
+#define DREF_ADDRESS 3
+#define DREF_SR_TIMER 4
+#define DREF_RIP_TIMER 5
+#define DREF_LONG_TIMER 6
+#define DREF_RIP_PACKET 7
+#define DREF_ADDRESS_NOTIFY 8
+#define DREF_LINE_CHANGE 9
+
+#define DREF_TOTAL 12
+
+#ifdef _PNP_POWER
+//
+// Pre-allocated binding array size
+//
+#define MAX_BINDINGS 50
+#endif _PNP_POWER
+
+#ifdef _PNP_POWER
+//
+// Our new binding array is composed of the following binding
+// array element
+//
+typedef struct _BIND_ARRAY_ELEM {
+ PBINDING Binding;
+ ULONG Version;
+} BIND_ARRAY_ELEM, *PBIND_ARRAY_ELEM;
+
+#endif _PNP_POWER
+
+typedef struct _DEVICE {
+
+#if DBG
+ ULONG RefTypes[DREF_TOTAL];
+#endif
+
+ CSHORT Type; // type of this structure
+ USHORT Size; // size of this structure
+
+#if DBG
+ UCHAR Signature1[4]; // contains "IDC1"
+#endif
+
+ CTELock Interlock; // GLOBAL lock for reference count.
+ // (used in ExInterlockedXxx calls)
+
+ //
+ // These are temporary versions of these counters, during
+ // timer expiration we update the real ones.
+ //
+
+ ULONG TempDatagramBytesSent;
+ ULONG TempDatagramsSent;
+ ULONG TempDatagramBytesReceived;
+ ULONG TempDatagramsReceived;
+
+ //
+ // Configuration parameters.
+ //
+
+ BOOLEAN EthernetPadToEven;
+ BOOLEAN SingleNetworkActive;
+ BOOLEAN DisableDialoutSap;
+
+ //
+ // TRUE if we have multiple cards but a virtual network of 0.
+ //
+
+ BOOLEAN MultiCardZeroVirtual;
+
+ CTELock Lock;
+
+ //
+ // Lock to access the sequenced lists in the device.
+ //
+ CTELock SListsLock;
+
+ LONG ReferenceCount; // activity count/this provider.
+
+#ifdef _PNP_POWER
+
+ //
+ // Lock used to control the access to a binding (either from the
+ // binding array in the device or from the binding array in the
+ // adapter.
+ //
+ CTELock BindAccessLock;
+
+ //
+ // Registry Path for use when PnP adapters appear.
+ //
+ PWSTR RegistryPathBuffer;
+
+ UNICODE_STRING RegistryPath;
+
+ //
+ // Binding array has the Version number too
+ //
+ PBIND_ARRAY_ELEM Bindings; // allocated when number is determined.
+ ULONG BindingCount; // total allocated in Bindings.
+
+ //
+ // Monotonically increasing version number kept in bindings.
+ // Hopefully this will not wrap around...
+ //
+ ULONG BindingVersionNumber;
+#else
+ //
+ // During init we hold all bindings in a queue, but after we
+ // know the approximate number we allocate an array.
+ //
+
+ union {
+ LIST_ENTRY InitialBindingList; // only used during init.
+ struct {
+ PBINDING * Bindings; // allocated when number is determined.
+ ULONG BindingCount; // total allocated in Bindings.
+ };
+ };
+#endif _PNP_POWER
+
+
+ //
+ // ValidBindings is the number of bindings in the array which may
+ // be valid (they are lan bindings or down wan binding placeholders).
+ // It will be less than BindingCount by the number of auto-detect
+ // bindings that are thrown away. HighestExternalNicId is ValidBindings
+ // minus any binding set slaves which are moved to the end of the
+ // array. SapNicCount is like HighestExternalNicId except that
+ // if WanGlobalNetworkNumber is TRUE it will count all WAN bindings
+ // as one. HighestExternalType20NicId is like HighestExternalNicId
+ // except it stops when all the remaining bindings are down wan
+ // lines, or dialin wan lines if DisableDialinNetbios bit 1 is on.
+ //
+
+ USHORT ValidBindings;
+ USHORT HighestExternalNicId;
+ USHORT SapNicCount;
+ USHORT HighestType20NicId;
+#ifdef _PNP_POWER
+ //
+ // Keeps track of the last LAN binding's position in the binding array
+ //
+ USHORT HighestLanNicId;
+
+ //
+ // This keeps track of the current size of the binding array
+ //
+ USHORT MaxBindings;
+#endif _PNP_POWER
+
+ LIST_ENTRY GlobalSendPacketList;
+ LIST_ENTRY GlobalReceivePacketList;
+ LIST_ENTRY GlobalReceiveBufferList;
+
+#if BACK_FILL
+ LIST_ENTRY GlobalBackFillPacketList;
+#endif
+
+ //
+ // Action requests from SAP waiting for an adapter status to change.
+ //
+
+ LIST_ENTRY AddressNotifyQueue;
+
+ //
+ // Action requests from nwrdr waiting for the WAN line
+ // to go up/down.
+ //
+
+ LIST_ENTRY LineChangeQueue;
+
+ //
+ // All packet pools are chained on these lists.
+ //
+
+ LIST_ENTRY SendPoolList;
+ LIST_ENTRY ReceivePoolList;
+
+
+#if BACK_FILL
+ LIST_ENTRY BackFillPoolList;
+ SLIST_HEADER BackFillPacketList;
+#endif
+
+#ifdef _PNP_POWER
+ LIST_ENTRY BindingPoolList;
+ SLIST_HEADER BindingList;
+#endif
+
+ SLIST_HEADER SendPacketList;
+ SLIST_HEADER ReceivePacketList;
+ PIPX_PADDING_BUFFER PaddingBuffer;
+
+ UCHAR State;
+
+ UCHAR FrameTypeDefault;
+
+ //
+ // This holds state if SingleNetworkActive is TRUE. If
+ // it is TRUE then WAN nets are active; if it is FALSE
+ // then LAN nets are active.
+ //
+
+ BOOLEAN ActiveNetworkWan;
+
+ //
+ // TRUE if we have a virtual network.
+ //
+
+ BOOLEAN VirtualNetwork;
+
+ //
+ // If we are set up for SingleNetworkActive, we may have
+ // to start our broadcast of net 0 frames somewhere other
+ // than NIC ID 1, so that we don't send to the wrong type.
+ //
+
+ USHORT FirstLanNicId;
+ USHORT FirstWanNicId;
+
+ //
+ // This holds the total memory allocated for the above structures.
+ //
+
+ LONG MemoryUsage;
+ LONG MemoryLimit;
+
+ //
+ // How many of various resources have been allocated.
+ //
+
+ ULONG AllocatedDatagrams;
+ ULONG AllocatedReceivePackets;
+ ULONG AllocatedPaddingBuffers;
+
+ //
+ // Other configuration parameters.
+ //
+
+ ULONG InitDatagrams;
+ ULONG MaxDatagrams;
+ ULONG RipAgeTime;
+ ULONG RipCount;
+ ULONG RipTimeout;
+ ULONG RipUsageTime;
+ ULONG SourceRouteUsageTime;
+ USHORT SocketStart;
+ USHORT SocketEnd;
+ ULONG SocketUniqueness;
+ ULONG VirtualNetworkNumber;
+ ULONG EthernetExtraPadding;
+ BOOLEAN DedicatedRouter;
+ BOOLEAN VirtualNetworkOptional;
+ UCHAR DisableDialinNetbios;
+
+ //
+ // These are currently not read from the registry.
+ //
+
+ ULONG InitReceivePackets;
+ ULONG InitReceiveBuffers;
+ ULONG MaxReceivePackets;
+ ULONG MaxReceiveBuffers;
+
+#ifdef _PNP_POWER
+ ULONG MaxPoolBindings;
+ ULONG AllocatedBindings;
+ ULONG InitBindings;
+#endif
+
+ //
+ // This contains the next unique indentified to use as
+ // the FsContext in the file object associated with an
+ // open of the control channel.
+ //
+
+ LARGE_INTEGER ControlChannelIdentifier;
+
+ //
+ // This registry parameter controls whether IPX checks (and discards)
+ // packets with mismatched Source addresses in the receive path.
+ //
+ BOOLEAN VerifySourceAddress;
+
+ //
+ // Where the current socket allocation is.
+ //
+ USHORT CurrentSocket;
+
+ //
+ // Number of segments in the RIP database.
+ //
+
+ ULONG SegmentCount;
+
+ //
+ // Points to an array of locks for the RIP database (these
+ // are stored outside of the ROUTER_SEGMENT so the array
+ // can be exposed to the RIP upper driver as one piece).
+ //
+
+ CTELock *SegmentLocks;
+
+ //
+ // Points to an array of ROUTER_SEGMENT fields for
+ // various RIP control fields.
+ //
+
+ ROUTER_SEGMENT *Segments;
+
+ //
+ // Queue of RIP packets waiting to be sent.
+ //
+
+ LIST_ENTRY WaitingRipPackets;
+ ULONG RipPacketCount;
+
+ //
+ // Timer that keeps RIP requests RIP_GRANULARITY ms apart.
+ //
+
+ BOOLEAN RipShortTimerActive;
+ USHORT RipSendTime;
+ CTETimer RipShortTimer;
+
+ //
+ // Timer that runs to age out unused rip entries (if the
+ // router is not bound) and re-rip every so often for
+ // active entries.
+ //
+
+ CTETimer RipLongTimer;
+
+ //
+ // This controls the source routing timeout code.
+ //
+
+ BOOLEAN SourceRoutingUsed; // TRUE if any 802.5 bindings exist.
+ CHAR SourceRoutingTime; // incremented each time timer fires.
+ CTETimer SourceRoutingTimer; // runs every minute.
+
+ //
+ // These are the merging of the binding values.
+ //
+
+ ULONG LinkSpeed;
+ ULONG MacOptions;
+
+ //
+ // Where we tell upper drivers to put their headers.
+ //
+
+ ULONG IncludedHeaderOffset;
+
+ //
+ // A pre-allocated header containing our node and network,
+ // plus an unused socket (so the structure is a known size
+ // for easy copying).
+ //
+
+ TDI_ADDRESS_IPX SourceAddress;
+
+ //
+ // The following field is an array of list heads of ADDRESS objects that
+ // are defined for this transport provider. To edit the list, you must
+ // hold the spinlock of the device context object.
+ //
+
+ LIST_ENTRY AddressDatabases[IPX_ADDRESS_HASH_COUNT]; // list of defined transport addresses.
+
+ //
+ // Holds the last address we looked up.
+ //
+
+ PVOID LastAddress;
+
+ NDIS_HANDLE NdisBufferPoolHandle;
+
+ //
+ // The following structure contains statistics counters for use
+ // by TdiQueryInformation and TdiSetInformation. They should not
+ // be used for maintenance of internal data structures.
+ //
+
+ TDI_PROVIDER_INFO Information; // information about this provider.
+
+ //
+ // Information.MaxDatagramSize is the minimum size we can
+ // send to all bindings assuming worst-case source routing;
+ // this is the value that won't break any network drivers.
+ //
+
+ ULONG RealMaxDatagramSize;
+
+#if DBG
+ UCHAR Signature2[4]; // contains "IDC2"
+#endif
+
+ //
+ // Indicates whether each upper driver is bound
+ // (Netbios = 0, SPX = 1, RIP = 2).
+ //
+
+ BOOLEAN UpperDriverBound[UPPER_DRIVER_COUNT];
+
+ //
+ // TRUE if any driver is bound.
+ //
+
+ BOOLEAN AnyUpperDriverBound;
+
+ //
+ // Whether a receive complete should be indicated to
+ // this upper driver.
+ //
+
+ BOOLEAN ReceiveCompletePending[UPPER_DRIVER_COUNT];
+
+ //
+ // Control channel identifier for each of the upper
+ // drivers' bindings.
+ //
+
+ LARGE_INTEGER UpperDriverControlChannel[UPPER_DRIVER_COUNT];
+
+ //
+ // Entry points and other information for each of the
+ // upper drivers.
+ //
+
+ IPX_INTERNAL_BIND_INPUT UpperDrivers[UPPER_DRIVER_COUNT];
+
+ //
+ // How many upper drivers want broadcast enabled.
+ //
+
+ ULONG EnableBroadcastCount;
+
+ //
+ // Indicates if an enable broadcast operation is in
+ // progress.
+ //
+
+ BOOLEAN EnableBroadcastPending;
+
+ //
+ // Indicates if a disable broadcast operation is in
+ // progress.
+ //
+
+ BOOLEAN DisableBroadcastPending;
+
+ //
+ // Indicates if the current operation should be
+ // reversed when it is finished.
+ //
+
+ BOOLEAN ReverseBroadcastOperation;
+
+ //
+ // TRUE if RIP wants a single network number for all WANs
+ //
+
+ BOOLEAN WanGlobalNetworkNumber;
+
+ //
+ // If WanGlobalNetworkNumber is TRUE, then this holds the
+ // actual value of the network number, once we know it.
+ //
+
+ ULONG GlobalWanNetwork;
+
+ //
+ // Set to TRUE if WanGlobalNetworkNumber is TRUE and we
+ // have already completed a queued notify from SAP. In
+ // this case GlobalWanNetwork will be set correctly.
+ //
+
+ BOOLEAN GlobalNetworkIndicated;
+
+ //
+ // TRUE if we need to act as a RIP announcer/responder
+ // for our virtual net.
+ //
+
+ BOOLEAN RipResponder;
+
+ //
+ // TRUE if we have already logged an error because someone
+ // sent a SAP response but we have multiple cards with no
+ // virtual network.
+ //
+
+ BOOLEAN SapWarningLogged;
+
+ //
+ // Used to queue up a worker thread to perform
+ // broadcast operations.
+ //
+
+ WORK_QUEUE_ITEM BroadcastOperationQueueItem;
+
+#ifdef _PNP_POWER
+ //
+ // Used to queue up a worker thread to perform
+ // PnP indications to upper drivers.
+ //
+
+ WORK_QUEUE_ITEM PnPIndicationsQueueItem;
+#endif
+
+ //
+ // This event is used when unloading to signal that
+ // the reference count is now 0.
+ //
+
+ KEVENT UnloadEvent;
+ BOOLEAN UnloadWaiting;
+
+ //
+ // Counters for most of the statistics that IPX maintains;
+ // some of these are kept elsewhere. Including the structure
+ // itself wastes a little space but ensures that the alignment
+ // inside the structure is correct.
+ //
+
+ TDI_PROVIDER_STATISTICS Statistics;
+
+
+ //
+ // This is TRUE if we have any adapters where we are
+ // auto-detecting the frame type.
+ //
+
+ BOOLEAN AutoDetect;
+
+ //
+ // This is TRUE if we are auto-detecting and we have
+ // found the default auto-detect type on the net.
+ //
+
+ BOOLEAN DefaultAutoDetected;
+
+ //
+ // Our state during auto-detect. After we are done this
+ // will stay at AutoDetectDone;
+ //
+
+ UCHAR AutoDetectState;
+
+ //
+ // If we are auto-detecting, this event is used to stall
+ // our initialization code while we do auto-detection --
+ // this is so we have a constant view of the world once
+ // we return from DriverEntry.
+ //
+
+ KEVENT AutoDetectEvent;
+
+ //
+ // Counters for "active" time.
+ //
+
+ LARGE_INTEGER IpxStartTime;
+
+ //
+ // This resource guards access to the ShareAccess
+ // and SecurityDescriptor fields in addresses.
+ //
+
+ ERESOURCE AddressResource;
+
+ //
+ // Points back to the system device object.
+ //
+
+ PDEVICE_OBJECT DeviceObject;
+
+#ifdef _PNP_POWER
+ //
+ // Used to store the Tdi registration handle for deviceobject notifications.
+ //
+ HANDLE TdiRegistrationHandle;
+
+ //
+ // Used to store the TA_ADDRESS which is indicated up to Tdi clients as adapters appear.
+ //
+ PTA_ADDRESS TdiRegistrationAddress;
+#endif
+
+ //
+ // These are kept around for error logging, and stored right
+ // after this structure.
+ //
+
+ PWCHAR DeviceName;
+ ULONG DeviceNameLength;
+
+} DEVICE, * PDEVICE;
+
+
+extern PDEVICE IpxDevice;
+extern PIPX_PADDING_BUFFER IpxPaddingBuffer;
+#if DBG
+EXTERNAL_LOCK(IpxGlobalInterlock);
+#endif
+
+
+//
+// device state definitions
+//
+
+#define DEVICE_STATE_CLOSED 0x00
+#define DEVICE_STATE_OPEN 0x01
+#define DEVICE_STATE_STOPPING 0x02
+
+#ifdef _PNP_POWER
+
+//
+// New state which comes between CLOSED and OPEN. At this state,
+// there are no adapters in the system and so no network activity
+// is possible.
+//
+#define DEVICE_STATE_LOADED 0x03
+#endif _PNP_POWER
+
+//
+// This is the state of our auto-detect if we do it.
+//
+
+#define AUTO_DETECT_STATE_INIT 0x00 // still initializing the device
+#define AUTO_DETECT_STATE_RUNNING 0x01 // sent ffffffff query, waiting for responses
+#define AUTO_DETECT_STATE_PROCESSING 0x02 // processing the responses
+#define AUTO_DETECT_STATE_DONE 0x03 // detection is done, IPX is active
+
+
+
+#define IPX_TDI_RESOURCES 9
+
+
+//
+// This structure is pointed to by the FsContext field in the FILE_OBJECT
+// for this Address. This structure is the base for all activities on
+// the open file object within the transport provider. All active connections
+// on the address point to this structure, although no queues exist here to do
+// work from. This structure also maintains a reference to an ADDRESS
+// structure, which describes the address that it is bound to.
+//
+
+#define AFREF_CREATE 0
+#define AFREF_RCV_DGRAM 1
+#define AFREF_SEND_DGRAM 2
+#define AFREF_VERIFY 3
+#define AFREF_INDICATION 4
+
+#define AFREF_TOTAL 8
+
+typedef struct _ADDRESS_FILE {
+
+#if DBG
+ ULONG RefTypes[AFREF_TOTAL];
+#endif
+
+ CSHORT Type;
+ CSHORT Size;
+
+ LIST_ENTRY Linkage; // next address file on this address.
+ // also used for linkage in the
+ // look-aside list
+
+ ULONG ReferenceCount; // number of references to this object.
+
+ //
+ // the current state of the address file structure; this is either open or
+ // closing
+ //
+
+ UCHAR State;
+
+ CTELock * AddressLock;
+
+ //
+ // The following fields are kept for housekeeping purposes.
+ //
+
+ PREQUEST Request; // the request used for open or close
+ struct _ADDRESS *Address; // address to which we are bound.
+#ifdef ISN_NT
+ PFILE_OBJECT FileObject; // easy backlink to file object.
+#endif
+ struct _DEVICE *Device; // device to which we are attached.
+
+ //
+ //
+ // TRUE if ExtendedAddressing, ReceiveIpxHeader,
+ // FilterOnPacketType, or ReceiveFlagAddressing is TRUE.
+ //
+
+ BOOLEAN SpecialReceiveProcessing;
+
+ //
+ // The remote address of a send datagram includes the
+ // packet type. and on a receive datagram includes
+ // the packet type AND a flags byte indicating information
+ // about the frame (was it broadcast, was it sent from
+ // this machine).
+ //
+
+ BOOLEAN ExtendedAddressing;
+
+ //
+ // TRUE if the address on a receive datagram includes
+ // the packet type and a flags byte (like ExtendedAddressing),
+ // but on send the address is normal (no packet type).
+ //
+
+ BOOLEAN ReceiveFlagsAddressing;
+
+ //
+ // Is the IPX header received with the data.
+ //
+
+ BOOLEAN ReceiveIpxHeader;
+
+ //
+ // The packet type to use if it is unspecified in the send.
+ //
+
+ UCHAR DefaultPacketType;
+
+ //
+ // TRUE if packet type filtering is enabled.
+ //
+
+ BOOLEAN FilterOnPacketType;
+
+ //
+ // The packet type to filter on.
+ //
+
+ UCHAR FilteredType;
+
+ //
+ // Does this address file want broadcast packets.
+ //
+
+ BOOLEAN EnableBroadcast;
+
+ //
+ // This is set to TRUE if this is the SAP socket -- we
+ // put this under SpecialReceiveProcessing to avoid
+ // hitting the main path.
+ //
+
+ BOOLEAN IsSapSocket;
+
+ //
+ // The following queue is used to queue receive datagram requests
+ // on this address file. Send datagram requests are queued on the
+ // address itself. These queues are managed by the EXECUTIVE interlocked
+ // list management routines. The actual objects which get queued to this
+ // structure are request control blocks (RCBs).
+ //
+
+ LIST_ENTRY ReceiveDatagramQueue; // FIFO of outstanding TdiReceiveDatagrams.
+
+ //
+ // This holds the request used to close this address file,
+ // for pended completion.
+ //
+
+ PREQUEST CloseRequest;
+
+ //
+ // handler for kernel event actions. First we have a set of booleans that
+ // indicate whether or not this address has an event handler of the given
+ // type registered.
+ //
+
+ //
+ // [CH] Added the chained receive handlers.
+ //
+
+ BOOLEAN RegisteredReceiveDatagramHandler;
+ BOOLEAN RegisteredChainedReceiveDatagramHandler;
+ BOOLEAN RegisteredErrorHandler;
+
+ //
+ // The following function pointer always points to a TDI_IND_RECEIVE_DATAGRAM
+ // event handler for the address. If the NULL handler is specified in a
+ // TdiSetEventHandler, this this points to an internal routine which does
+ // not accept the incoming data.
+ //
+
+ PTDI_IND_RECEIVE_DATAGRAM ReceiveDatagramHandler;
+ PVOID ReceiveDatagramHandlerContext;
+ PTDI_IND_CHAINED_RECEIVE_DATAGRAM ChainedReceiveDatagramHandler;
+ PVOID ChainedReceiveDatagramHandlerContext;
+
+ //
+ // The following function pointer always points to a TDI_IND_ERROR
+ // handler for the address. If the NULL handler is specified in a
+ // TdiSetEventHandler, this this points to an internal routine which
+ // simply returns successfully.
+ //
+
+ PTDI_IND_ERROR ErrorHandler;
+ PVOID ErrorHandlerContext;
+
+} ADDRESS_FILE, *PADDRESS_FILE;
+
+#define ADDRESSFILE_STATE_OPENING 0x00 // not yet open for business
+#define ADDRESSFILE_STATE_OPEN 0x01 // open for business
+#define ADDRESSFILE_STATE_CLOSING 0x02 // closing
+
+
+//
+// This structure defines an ADDRESS, or active transport address,
+// maintained by the transport provider. It contains all the visible
+// components of the address (such as the TSAP and network name components),
+// and it also contains other maintenance parts, such as a reference count,
+// ACL, and so on. All outstanding connection-oriented and connectionless
+// data transfer requests are queued here.
+//
+
+#define AREF_ADDRESS_FILE 0
+#define AREF_LOOKUP 1
+#define AREF_RECEIVE 2
+
+#define AREF_TOTAL 4
+
+typedef struct _ADDRESS {
+
+#if DBG
+ ULONG RefTypes[AREF_TOTAL];
+#endif
+
+ USHORT Size;
+ CSHORT Type;
+
+/* ULONGs to allow for Interlocked operations.
+
+ BOOLEAN SendPacketInUse; // put these after so header is aligned.
+
+ BOOLEAN ReceivePacketInUse;
+#if BACK_FILL
+ BOOLEAN BackFillPacketInUse;
+#endif
+*/
+
+ ULONG SendPacketInUse; // put these after so header is aligned.
+
+ ULONG ReceivePacketInUse;
+#if BACK_FILL
+ ULONG BackFillPacketInUse;
+#endif
+
+ LIST_ENTRY Linkage; // next address/this device object.
+ ULONG ReferenceCount; // number of references to this object.
+
+ CTELock Lock;
+
+ //
+ // The following fields comprise the actual address itself.
+ //
+
+ PREQUEST Request; // pointer to address creation request.
+
+ USHORT Socket; // the socket this address corresponds to.
+ USHORT SendSourceSocket; // used for sends; may be == Socket or 0
+
+ //
+ // The following fields are used to maintain state about this address.
+ //
+
+ BOOLEAN Stopping;
+ ULONG Flags; // attributes of the address.
+ struct _DEVICE *Device; // device context to which we are attached.
+ CTELock * DeviceLock;
+
+ //
+ // The following queues is used to hold send datagrams for this
+ // address. Receive datagrams are queued to the address file. Requests are
+ // processed in a first-in, first-out manner, so that the very next request
+ // to be serviced is always at the head of its respective queue. These
+ // queues are managed by the EXECUTIVE interlocked list management routines.
+ // The actual objects which get queued to this structure are request control
+ // blocks (RCBs).
+ //
+
+ LIST_ENTRY AddressFileDatabase; // list of defined address file objects
+
+ //
+ // Holds our source address, used for construcing datagrams
+ // quickly.
+ //
+
+ TDI_ADDRESS_IPX LocalAddress;
+
+ IPX_SEND_PACKET SendPacket;
+ IPX_RECEIVE_PACKET ReceivePacket;
+
+#if BACK_FILL
+ IPX_SEND_PACKET BackFillPacket;
+#endif
+
+
+ UCHAR SendPacketHeader[IPX_MAXIMUM_MAC + sizeof(IPX_HEADER)];
+
+#ifdef ISN_NT
+
+ //
+ // These two can be a union because they are not used
+ // concurrently.
+ //
+
+ union {
+
+ //
+ // This structure is used for checking share access.
+ //
+
+ SHARE_ACCESS ShareAccess;
+
+ //
+ // Used for delaying IpxDestroyAddress to a thread so
+ // we can access the security descriptor.
+ //
+
+ WORK_QUEUE_ITEM DestroyAddressQueueItem;
+
+ } u;
+
+ //
+ // This structure is used to hold ACLs on the address.
+
+ PSECURITY_DESCRIPTOR SecurityDescriptor;
+
+#endif
+
+} ADDRESS, *PADDRESS;
+
+#define ADDRESS_FLAGS_STOPPING 0x00000001
+
+//
+// In order to increase the range of ControlChannelIds, we have a large integer to represent
+// monotonically increasing ControlChannelIdentifiers. This large integer is packed into the
+// 6 Bytes as follows:
+//
+// REQUEST_OPEN_CONTEXT(_Request) - 4 bytes
+// Upper 2 bytes of REQUEST_OPEN_TYPE(_Request) - 2 bytes
+//
+// IPX_CC_MASK is used to mask out the upper 2 bytes of the OPEN_TYPE.
+// MAX_CCID is 2^48.
+//
+#define IPX_CC_MASK 0x0000ffff
+
+#define MAX_CCID 0xffffffffffff
+
+#define CCID_FROM_REQUEST(_ccid, _Request) \
+ (_ccid).LowPart = (ULONG)(REQUEST_OPEN_CONTEXT(_Request)); \
+ (_ccid).HighPart = ((ULONG)(REQUEST_OPEN_TYPE(_Request)) >> 16);
+
diff --git a/private/ntos/tdi/isnp/ipx/isnipx.h b/private/ntos/tdi/isnp/ipx/isnipx.h
new file mode 100644
index 000000000..df947d439
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/isnipx.h
@@ -0,0 +1,531 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ isnipx.h
+
+Abstract:
+
+ This module contains definitions specific to the
+ IPX module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 2-September-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#ifndef _ISNIPX_
+#define _ISNIPX_
+
+#define MAC_HEADER_SIZE ((IPX_MAXIMUM_MAC + 3) & ~3)
+#define RIP_PACKET_SIZE ((sizeof(RIP_PACKET) + 3) & ~3)
+#define IPX_HEADER_SIZE ((sizeof(IPX_HEADER) + 3) & ~3)
+
+//
+// Frame type definitions
+//
+
+#define ISN_FRAME_TYPE_ETHERNET_II 0
+#define ISN_FRAME_TYPE_802_3 1
+#define ISN_FRAME_TYPE_802_2 2
+#define ISN_FRAME_TYPE_SNAP 3
+#define ISN_FRAME_TYPE_ARCNET 4 // we ignore this
+#define ISN_FRAME_TYPE_MAX 4 // of the four standard ones
+
+#define ISN_FRAME_TYPE_AUTO 0xff
+
+
+//
+// This defines the size of the maximum MAC header required
+// (token-ring: MAC 14 bytes, RI 18 bytes, LLC 3 bytes, SNAP 5 bytes).
+//
+
+#define IPX_MAXIMUM_MAC 40
+
+//
+// This is an internal identifier used for RIP query packets.
+//
+
+#define IDENTIFIER_RIP_INTERNAL 4
+
+//
+// This is an internal identifier used for RIP response packets.
+//
+
+#define IDENTIFIER_RIP_RESPONSE 5
+
+
+//
+// This is the total number of "real" identifiers.
+//
+
+#define IDENTIFIER_TOTAL 4
+
+
+//
+// Some definitions (in the correct on-the-wire order).
+//
+
+#define RIP_PACKET_TYPE 0x01
+#define RIP_SOCKET 0x5304
+#define RIP_REQUEST 0x0100
+#define RIP_RESPONSE 0x0200
+#define RIP_DOWN 0x8200 // use high bit to indicate it
+
+#define SAP_PACKET_TYPE 0x04
+#define SAP_SOCKET 0x5204
+
+#define SPX_PACKET_TYPE 0x05
+
+#define NB_SOCKET 0x5504
+
+
+#include <packon.h>
+
+//
+// Definition of the IPX header.
+//
+
+typedef struct _IPX_HEADER {
+ USHORT CheckSum;
+ UCHAR PacketLength[2];
+ UCHAR TransportControl;
+ UCHAR PacketType;
+ UCHAR DestinationNetwork[4];
+ UCHAR DestinationNode[6];
+ USHORT DestinationSocket;
+ UCHAR SourceNetwork[4];
+ UCHAR SourceNode[6];
+ USHORT SourceSocket;
+} IPX_HEADER, *PIPX_HEADER;
+
+
+//
+// Definition of a RIP network entry.
+//
+
+typedef struct _RIP_NETWORK_ENTRY {
+ ULONG NetworkNumber;
+ USHORT HopCount;
+ USHORT TickCount;
+} RIP_NETWORK_ENTRY, *PRIP_NETWORK_ENTRY;
+
+//
+// Definition of a single entry rip packet.
+//
+
+typedef struct _RIP_PACKET {
+ USHORT Operation;
+ RIP_NETWORK_ENTRY NetworkEntry;
+} RIP_PACKET, *PRIP_PACKET;
+
+#include <packoff.h>
+
+
+#define IPX_DEVICE_SIGNATURE 0x1401
+#define IPX_ADAPTER_SIGNATURE 0x1402
+#define IPX_BINDING_SIGNATURE 0x1403
+#define IPX_ADDRESS_SIGNATURE 0x1404
+#define IPX_ADDRESSFILE_SIGNATURE 0x1405
+
+#define IPX_FILE_TYPE_CONTROL (ULONG)0x4701 // file is type control
+
+
+//
+// Defined granularity of RIP timeouts in milliseconds
+//
+
+#define RIP_GRANULARITY 55
+
+
+//
+// The default number of segments in the RIP table.
+//
+
+#define RIP_SEGMENTS 7
+
+
+
+//
+// Convert a ushort netware order <-> machine order
+//
+
+#define REORDER_USHORT(_Ushort) ((((_Ushort) & 0xff00) >> 8) | (((_Ushort) & 0x00ff) << 8))
+
+//
+// Convert a ulong netware order <-> machine order
+//
+
+#define REORDER_ULONG(_Ulong) \
+ ((((_Ulong) & 0xff000000) >> 24) | \
+ (((_Ulong) & 0x00ff0000) >> 8) | \
+ (((_Ulong) & 0x0000ff00) << 8) | \
+ (((_Ulong) & 0x000000ff) << 24))
+
+
+
+#if DBG
+
+extern ULONG IpxDebug;
+extern ULONG IpxMemoryDebug;
+
+#define IPX_MEMORY_LOG_SIZE 128
+extern UCHAR IpxDebugMemory[IPX_MEMORY_LOG_SIZE][64];
+extern PUCHAR IpxDebugMemoryLoc;
+extern PUCHAR IpxDebugMemoryEnd;
+
+VOID
+IpxDebugMemoryLog(
+ IN PUCHAR FormatString,
+ ...
+);
+
+#define IPX_DEBUG(_Flag, _Print) { \
+ if (IpxDebug & (IPX_DEBUG_ ## _Flag)) { \
+ DbgPrint ("IPX: "); \
+ DbgPrint _Print; \
+ } \
+ if (IpxMemoryDebug & (IPX_DEBUG_ ## _Flag)) { \
+ IpxDebugMemoryLog _Print; \
+ } \
+}
+
+#else
+
+#define IPX_DEBUG(_Flag, _Print)
+
+#endif
+
+
+//
+// These definitions are for abstracting IRPs from the
+// transport for portability.
+//
+
+#if ISN_NT
+
+typedef IRP REQUEST, *PREQUEST;
+
+
+//
+// PREQUEST
+// IpxAllocateRequest(
+// IN PDEVICE Device,
+// IN PIRP Irp
+// );
+//
+// Allocates a request for the system-specific request structure.
+//
+
+#define IpxAllocateRequest(_Device,_Irp) \
+ (_Irp)
+
+
+//
+// BOOLEAN
+// IF_NOT_ALLOCATED(
+// IN PREQUEST Request
+// );
+//
+// Checks if a request was not successfully allocated.
+//
+
+#define IF_NOT_ALLOCATED(_Request) \
+ if (0)
+
+
+//
+// VOID
+// IpxFreeRequest(
+// IN PDEVICE Device,
+// IN PREQUEST Request
+// );
+//
+// Frees a previously allocated request.
+//
+
+#define IpxFreeRequest(_Device,_Request) \
+ ;
+
+
+//
+// VOID
+// MARK_REQUEST_PENDING(
+// IN PREQUEST Request
+// );
+//
+// Marks that a request will pend.
+//
+
+#define MARK_REQUEST_PENDING(_Request) \
+ IoMarkIrpPending(_Request)
+
+
+//
+// VOID
+// UNMARK_REQUEST_PENDING(
+// IN PREQUEST Request
+// );
+//
+// Marks that a request will not pend.
+//
+
+#define UNMARK_REQUEST_PENDING(_Request) \
+ (((IoGetCurrentIrpStackLocation(_Request))->Control) &= ~SL_PENDING_RETURNED)
+
+
+//
+// UCHAR
+// REQUEST_MAJOR_FUNCTION
+// IN PREQUEST Request
+// );
+//
+// Returns the major function code of a request.
+//
+
+#define REQUEST_MAJOR_FUNCTION(_Request) \
+ ((IoGetCurrentIrpStackLocation(_Request))->MajorFunction)
+
+
+//
+// UCHAR
+// REQUEST_MINOR_FUNCTION
+// IN PREQUEST Request
+// );
+//
+// Returns the minor function code of a request.
+//
+
+#define REQUEST_MINOR_FUNCTION(_Request) \
+ ((IoGetCurrentIrpStackLocation(_Request))->MinorFunction)
+
+
+//
+// PNDIS_BUFFER
+// REQUEST_NDIS_BUFFER
+// IN PREQUEST Request
+// );
+//
+// Returns the NDIS buffer chain associated with a request.
+//
+
+#define REQUEST_NDIS_BUFFER(_Request) \
+ ((PNDIS_BUFFER)((_Request)->MdlAddress))
+
+
+//
+// PVOID
+// REQUEST_OPEN_CONTEXT(
+// IN PREQUEST Request
+// );
+//
+// Gets the context associated with an opened address/connection/control channel.
+//
+
+#define REQUEST_OPEN_CONTEXT(_Request) \
+ (((IoGetCurrentIrpStackLocation(_Request))->FileObject)->FsContext)
+
+
+//
+// PVOID
+// REQUEST_OPEN_TYPE(
+// IN PREQUEST Request
+// );
+//
+// Gets the type associated with an opened address/connection/control channel.
+//
+
+#define REQUEST_OPEN_TYPE(_Request) \
+ (((IoGetCurrentIrpStackLocation(_Request))->FileObject)->FsContext2)
+
+
+//
+// PFILE_FULL_EA_INFORMATION
+// OPEN_REQUEST_EA_INFORMATION(
+// IN PREQUEST Request
+// );
+//
+// Returns the EA information associated with an open/close request.
+//
+
+#define OPEN_REQUEST_EA_INFORMATION(_Request) \
+ ((PFILE_FULL_EA_INFORMATION)((_Request)->AssociatedIrp.SystemBuffer))
+
+
+//
+// PTDI_REQUEST_KERNEL
+// REQUEST_PARAMETERS(
+// IN PREQUEST Request
+// );
+//
+// Obtains a pointer to the parameters of a request.
+//
+
+#define REQUEST_PARAMETERS(_Request) \
+ (&((IoGetCurrentIrpStackLocation(_Request))->Parameters))
+
+
+//
+// VOID
+// REQUEST_OPEN_CONTEXT_AND_PARAMS(
+// IN PREQUEST Request
+// OUT PVOID * OpenContext,
+// OUT PTDI_REQUEST_KERNEL * Parameters
+// );
+//
+// Simultaneously returns the open context and the parameters
+// for a request (this is an optimization since the send
+// datagram code needs them both).
+//
+
+#define REQUEST_OPEN_CONTEXT_AND_PARAMS(_Request,_OpenContext,_Parameters) { \
+ PIO_STACK_LOCATION _IrpSp = IoGetCurrentIrpStackLocation(_Request); \
+ *(_OpenContext) = _IrpSp->FileObject->FsContext; \
+ *(_Parameters) = (PTDI_REQUEST_KERNEL)(&_IrpSp->Parameters); \
+}
+
+
+//
+// PLIST_ENTRY
+// REQUEST_LINKAGE(
+// IN PREQUEST Request
+// );
+//
+// Returns a pointer to a linkage field in the request.
+//
+
+#define REQUEST_LINKAGE(_Request) \
+ (&((_Request)->Tail.Overlay.ListEntry))
+
+
+//
+// PREQUEST
+// LIST_ENTRY_TO_REQUEST(
+// IN PLIST_ENTRY ListEntry
+// );
+//
+// Returns a request given a linkage field in it.
+//
+
+#define LIST_ENTRY_TO_REQUEST(_ListEntry) \
+ ((PREQUEST)(CONTAINING_RECORD(_ListEntry, REQUEST, Tail.Overlay.ListEntry)))
+
+
+//
+// NTSTATUS
+// REQUEST_STATUS(
+// IN PREQUEST Request
+// );
+//
+// Used to access the status field of a request.
+//
+
+#define REQUEST_STATUS(_Request) \
+ (_Request)->IoStatus.Status
+
+
+//
+// ULONG
+// REQUEST_INFORMATION(
+// IN PREQUEST Request)
+// );
+//
+// Used to access the information field of a request.
+//
+
+#define REQUEST_INFORMATION(_Request) \
+ (_Request)->IoStatus.Information
+
+
+//
+// VOID
+// IpxCompleteRequest(
+// IN PREQUEST Request
+// );
+//
+// Completes a request whose status and information fields have
+// been filled in.
+//
+
+#define IpxCompleteRequest(_Request) \
+ IoCompleteRequest (_Request, IO_NETWORK_INCREMENT)
+
+#else
+
+//
+// These routines must be defined for portability to a VxD.
+//
+
+#endif
+
+
+#define IPX_INCREMENT(_Long, _Lock) InterlockedIncrement(_Long)
+#define IPX_DECREMENT(_Long, _Lock) InterlockedDecrement(_Long)
+
+#define IPX_ADD_ULONG(_Pulong, _Ulong, _Lock) InterlockedExchangeAdd(_Pulong, _Ulong)
+
+#define IPX_DEFINE_SYNC_CONTEXT(_SyncContext)
+#define IPX_BEGIN_SYNC(_SyncContext)
+#define IPX_END_SYNC(_SyncContext)
+
+#define IPX_DEFINE_LOCK_HANDLE(_LockHandle) CTELockHandle _LockHandle;
+#define IPX_DEFINE_LOCK_HANDLE_PARAM(_LockHandle) CTELockHandle _LockHandle;
+
+#define IPX_GET_LOCK(_Lock, _LockHandle) \
+ CTEGetLock(_Lock, _LockHandle)
+
+#define IPX_FREE_LOCK(_Lock, _LockHandle) \
+ CTEFreeLock(_Lock, _LockHandle)
+
+#define IPX_GET_LOCK1(_Lock, _LockHandle)
+
+#define IPX_FREE_LOCK1(_Lock, _LockHandle)
+
+#define IPX_REMOVE_HEAD_LIST(_Queue, _Lock) ExInterlockedRemoveHeadList(_Queue, _Lock)
+#define IPX_LIST_WAS_EMPTY(_Queue, _OldHead) ((_OldHead) == NULL)
+#define IPX_INSERT_HEAD_LIST(_Queue, _Entry, _Lock) ExInterlockedInsertHeadList(_Queue, _Entry, _Lock)
+#define IPX_INSERT_TAIL_LIST(_Queue, _Entry, _Lock) ExInterlockedInsertTailList(_Queue, _Entry, _Lock)
+
+#define IPX_POP_ENTRY_LIST(_Queue, _Lock) ExInterlockedPopEntrySList(_Queue, _Lock)
+#define IPX_PUSH_ENTRY_LIST(_Queue, _Entry, _Lock) ExInterlockedPushEntrySList(_Queue, _Entry, _Lock)
+
+//
+// This macro adds a ULONG to a LARGE_INTEGER.
+//
+
+#define ADD_TO_LARGE_INTEGER(_LargeInteger,_Ulong) \
+ ExInterlockedAddLargeStatistic((_LargeInteger),(ULONG)(_Ulong))
+
+#define IPX_DEBUG_DEVICE 0x00000001
+#define IPX_DEBUG_ADAPTER 0x00000002
+#define IPX_DEBUG_ADDRESS 0x00000004
+#define IPX_DEBUG_SEND 0x00000008
+#define IPX_DEBUG_NDIS 0x00000010
+#define IPX_DEBUG_RECEIVE 0x00000020
+#define IPX_DEBUG_CONFIG 0x00000040
+#define IPX_DEBUG_PACKET 0x00000080
+#define IPX_DEBUG_RIP 0x00000100
+#define IPX_DEBUG_BIND 0x00000200
+#define IPX_DEBUG_ACTION 0x00000400
+#define IPX_DEBUG_BAD_PACKET 0x00000800
+#define IPX_DEBUG_SOURCE_ROUTE 0x00001000
+#define IPX_DEBUG_WAN 0x00002000
+#define IPX_DEBUG_AUTO_DETECT 0x00004000
+
+#ifdef _PNP_POWER
+#define IPX_DEBUG_PNP 0x00008000
+#endif
+
+#define IPX_DEBUG_LOOPB 0x00010000
+
+#endif
diff --git a/private/ntos/tdi/isnp/ipx/loopback.c b/private/ntos/tdi/isnp/ipx/loopback.c
new file mode 100644
index 000000000..be44bae5b
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/loopback.c
@@ -0,0 +1,280 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ loopback.c
+
+Abstract:
+
+ This module contains the routines to implement loopback
+
+Author:
+
+ Sanjay Anand (SanjayAn) 2/6/96
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+//
+// Global lock to control access to the Loopback queue
+//
+DEFINE_LOCK_STRUCTURE(LoopLock)
+
+//
+// Head and tail of the Loopback queue
+//
+PNDIS_PACKET LoopXmitHead = (PNDIS_PACKET)NULL;
+PNDIS_PACKET LoopXmitTail = (PNDIS_PACKET)NULL;
+
+CTEEvent LoopXmitEvent;
+BOOLEAN LoopXmitRtnRunning = 0;
+
+//
+// MaximumPacket sized buffer to hold the lookahead data.
+//
+// ZZBUGBUG: In PnP this value can change
+//
+// PUCHAR LookaheadBuffer=NULL;
+#define LOOP_LOOKAHEAD_SIZE 128 + sizeof(IPX_HEADER) + 8 + 34
+
+
+VOID
+IpxDoLoopback(
+ IN CTEEvent *Event,
+ IN PVOID Context
+ )
+/*++
+
+Routine Description:
+
+ Does the actual loopback.
+
+Arguments:
+
+ Event - Pointer to event structure.
+
+ Context - Pointer to ZZ
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_PACKET Packet; // Pointer to packet being transmitted
+ PNDIS_BUFFER Buffer; // Current NDIS buffer being processed.
+ ULONG TotalLength; // Total length of send.
+ ULONG LookaheadLength; // Bytes in lookahead.
+ ULONG Copied; // Bytes copied so far.
+ PUCHAR CopyPtr; // Pointer to buffer being copied into.
+ PUCHAR SrcPtr; // Pointer to buffer being copied from.
+ ULONG SrcLength; // Length of src buffer.
+ BOOLEAN Rcvd = FALSE;
+ PIPX_SEND_RESERVED Reserved;
+ ULONG MacSize;
+ PNDIS_PACKET *PacketPtr;
+ UCHAR LookaheadBuffer[LOOP_LOOKAHEAD_SIZE];
+
+ IPX_DEFINE_LOCK_HANDLE(Handle)
+
+ KIRQL OldIrql;
+
+ CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
+
+ //
+ // Raise IRQL so we can acquire locks at DPC level in the receive code.
+ // Also to be able to ReceiveIndicate at DPC
+ //
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ IPX_GET_LOCK(&LoopLock, &Handle);
+
+ if (LoopXmitRtnRunning) {
+ IPX_FREE_LOCK(&LoopLock, Handle);
+ KeLowerIrql(OldIrql);
+ return;
+ }
+
+ LoopXmitRtnRunning = 1;
+
+ for (;;) {
+
+ //
+ // Get the next packet from the list.
+ //
+ Packet = LoopXmitHead;
+
+ if (Packet != (PNDIS_PACKET)NULL) {
+ Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ LoopXmitHead = (PNDIS_PACKET)(Reserved->PaddingBuffer);
+ IPX_FREE_LOCK(&LoopLock, Handle);
+ } else { // Nothing left to do.
+ LoopXmitRtnRunning = 0;
+ IPX_FREE_LOCK(&LoopLock, Handle);
+ break;
+ }
+
+ //
+ // We use the PaddingBuffer section as the next ptr.
+ //
+ Reserved->PaddingBuffer = NULL;
+
+ IPX_DEBUG(LOOPB, ("Packet: %lx\n", Packet));
+
+ NdisQueryPacket(Packet, NULL, NULL, &Buffer, &TotalLength);
+
+ NdisQueryBuffer(Buffer, NULL, &MacSize);
+
+ IPX_DEBUG(LOOPB, ("Buffer: %lx Totalpktlen: %lx MacSize: %lx\n", Buffer, TotalLength, MacSize));
+
+ LookaheadLength = MIN(LOOP_LOOKAHEAD_SIZE, TotalLength);
+ Copied = 0;
+ CopyPtr = LookaheadBuffer;
+ while (Copied < LookaheadLength) {
+ ULONG ThisCopy; // Bytes to copy this time.
+
+#ifdef DBG
+ if (!Buffer) {
+ DbgBreakPoint();
+ IPX_GET_LOCK(&LoopLock, &Handle);
+ LoopXmitRtnRunning = 0;
+ IPX_FREE_LOCK(&LoopLock, Handle);
+ KeLowerIrql(OldIrql);
+ return;
+ }
+#endif
+
+ NdisQueryBuffer(Buffer, &SrcPtr, &SrcLength);
+ ThisCopy = MIN(SrcLength, LookaheadLength - Copied);
+ CTEMemCopy(CopyPtr, SrcPtr, ThisCopy);
+ Copied += ThisCopy;
+ CopyPtr += ThisCopy;
+ NdisGetNextBuffer(Buffer, &Buffer);
+ }
+
+ Rcvd = TRUE;
+
+#ifdef BACK_FILL
+ //
+ // For Backfill packets, the MAC header is not yet set up; for others, it is the size
+ // of the first MDL (17).
+ //
+ if ((Reserved->Identifier == IDENTIFIER_IPX) &&
+ (Reserved->BackFill)) {
+ MacSize = 0;
+ }
+#endif
+ IpxReceiveIndication( (NDIS_HANDLE)IPX_LOOPBACK_COOKIE, // BindingContext
+ Packet, // ReceiveContext
+ (MacSize) ? LookaheadBuffer : NULL, // HeaderBuffer
+ MacSize, // HeaderBufferSize
+ LookaheadBuffer+MacSize, // LookAheadBuffer
+ LookaheadLength-MacSize, // LookAheadBufferSize
+ TotalLength-MacSize); // PacketSize
+
+ IpxSendComplete(Context, Packet, NDIS_STATUS_SUCCESS);
+
+ //
+ // Give other threads a chance to run.
+ //
+ KeLowerIrql(OldIrql);
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+ IPX_GET_LOCK(&LoopLock, &Handle);
+ }
+
+ if (Rcvd) {
+ IpxReceiveComplete(Context);
+ }
+
+ KeLowerIrql(OldIrql);
+}
+
+
+VOID
+IpxInitLoopback()
+/*++
+
+Routine Description:
+
+ Initializes various loopback structures.
+
+Arguments:
+
+Return Value:
+
+ None.
+
+--*/
+{
+ CTEInitLock(&LoopLock);
+ CTEInitEvent(&LoopXmitEvent, IpxDoLoopback);
+ return;
+}
+
+
+VOID
+IpxLoopbackEnque(
+ IN PNDIS_PACKET Packet,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ Enqueues a packet to the loopbackQ
+
+Arguments:
+
+ Packet - The packet to be enqueued.
+
+ Context - Pointer to the adapter corresp to the first binding.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ IPX_DEFINE_LOCK_HANDLE(LockHandle)
+
+ //
+ // We use the PaddingBuffer as the next ptr.
+ //
+ Reserved->PaddingBuffer = NULL;
+
+ IPX_GET_LOCK(&LoopLock, &LockHandle);
+
+ //
+ // LoopbackQ is empty
+ //
+ if (LoopXmitHead == (PNDIS_PACKET)NULL) {
+ LoopXmitHead = Packet;
+ } else {
+ Reserved = (PIPX_SEND_RESERVED)(LoopXmitTail->ProtocolReserved);
+ (PNDIS_PACKET)(Reserved->PaddingBuffer) = Packet;
+ }
+ LoopXmitTail = Packet;
+
+ IPX_DEBUG(LOOPB, ("Enqued packet: %lx, Reserved: %lx\n", Packet, Reserved));
+
+ //
+ // If this routine is not already running, schedule it as a work item.
+ //
+ if (!LoopXmitRtnRunning) {
+ CTEScheduleEvent(&LoopXmitEvent, Context);
+ }
+
+ IPX_FREE_LOCK(&LoopLock, LockHandle);
+}
diff --git a/private/ntos/tdi/isnp/ipx/mac.c b/private/ntos/tdi/isnp/ipx/mac.c
new file mode 100644
index 000000000..93f9e8a89
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/mac.c
@@ -0,0 +1,3793 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ mac.c
+
+Abstract:
+
+ This module contains code which implements Mac type dependent code for
+ the IPX transport.
+
+Environment:
+
+ Kernel mode (Actually, unimportant)
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) - 22-Sept-1995
+ BackFill optimization changes added under #if BACK_FILL
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#define TR_LENGTH_MASK 0x1F // low 5 bits in byte
+#define TR_DIRECTION_MASK 0x80 // returns direction bit
+#define TR_DEFAULT_LENGTH 0x70 // default for outgoing
+#define TR_MAX_SIZE_MASK 0x70
+
+#define TR_PREAMBLE_AC 0x10
+#define TR_PREAMBLE_FC 0x40
+
+#define FDDI_HEADER_BYTE 0x57
+
+
+static UCHAR AllRouteSourceRouting[2] = { 0x82, TR_DEFAULT_LENGTH };
+static UCHAR SingleRouteSourceRouting[2] = { 0xc2, TR_DEFAULT_LENGTH };
+
+#define ROUTE_EQUAL(_A,_B) { \
+ (*(UNALIGNED USHORT *)(_A) == *(UNALIGNED USHORT *)(_B)) \
+}
+
+//
+// For back-fillable packets, chains the back-fill space as a MAC header
+// to the packet and sets the header pointer.
+//
+
+//
+// BUGBUG: We dont need to test for IDENTIFIER_IPX since it will always be
+// true for the mediumframe specific send handlers.
+//
+#define BACK_FILL_HEADER(_header, _reserved, _headerlength, _packet) \
+ if ((_reserved)->Identifier == IDENTIFIER_IPX) { \
+ if((_reserved)->BackFill) { \
+ CTEAssert ((_reserved)->HeaderBuffer); \
+ CTEAssert ((_reserved)->HeaderBuffer->MdlFlags & MDL_NETWORK_HEADER); \
+ _header = (PCHAR)(_reserved)->HeaderBuffer->MappedSystemVa - _headerlength; \
+ (_reserved)->HeaderBuffer->MappedSystemVa = (PCHAR)(_reserved)->HeaderBuffer->MappedSystemVa - _headerlength; \
+ (_reserved)->HeaderBuffer->ByteOffset -= _headerlength; \
+ NdisChainBufferAtFront(_packet,(PNDIS_BUFFER)(_reserved)->HeaderBuffer); \
+ } \
+ }
+
+//
+// In case of back-fillable packets, the adjusted length should include
+// the prev. bytecount of the headerbuffer.
+//
+#define BACK_FILL_ADJUST_BUFFER_LENGTH(_reserved, _headerlength) \
+ if((_reserved)->BackFill){ \
+ NdisAdjustBufferLength ((_reserved)->HeaderBuffer, _headerlength+(_reserved)->HeaderBuffer->ByteCount); \
+ IPX_DEBUG(SEND,("mac user mdl %x\n", (_reserved)->HeaderBuffer)); \
+ } else { \
+ NdisAdjustBufferLength ((_reserved)->HeaderBuffer, _headerlength); \
+ }
+
+//
+// This is the interpretation of the length bits in
+// the 802.5 source-routing information.
+//
+
+ULONG SR802_5Lengths[8] = { 516, 1500, 2052, 4472,
+ 8144, 11407, 17800, 17800 };
+
+#ifndef _PNP_POWER
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,MacInitializeMacInfo)
+#endif
+
+#endif
+
+
+VOID
+MacInitializeBindingInfo(
+ IN struct _BINDING * Binding,
+ IN struct _ADAPTER * Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ Fills in the binding info based on the adapter's MacInfo
+ and the frame type of the binding.
+
+Arguments:
+
+ Binding - The newly created binding.
+
+ Adapter - The adapter.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG MaxUserData;
+
+ Binding->DefHeaderSize = Adapter->DefHeaderSizes[Binding->FrameType];
+ Binding->BcMcHeaderSize = Adapter->BcMcHeaderSizes[Binding->FrameType];
+
+ MacReturnMaxDataSize(
+ &Adapter->MacInfo,
+ NULL,
+ 0,
+ Binding->MaxSendPacketSize,
+ &MaxUserData);
+
+ Binding->MaxLookaheadData =
+ Adapter->MaxReceivePacketSize -
+ sizeof(IPX_HEADER) -
+ (Binding->DefHeaderSize - Adapter->MacInfo.MinHeaderLength);
+
+ Binding->AnnouncedMaxDatagramSize =
+ MaxUserData -
+ sizeof(IPX_HEADER) -
+ (Binding->DefHeaderSize - Adapter->MacInfo.MinHeaderLength);
+
+ Binding->RealMaxDatagramSize =
+ Binding->MaxSendPacketSize -
+ Adapter->MacInfo.MaxHeaderLength -
+ sizeof(IPX_HEADER) -
+ (Binding->DefHeaderSize - Adapter->MacInfo.MinHeaderLength);
+
+} /* MacInitializeBindingInfo */
+
+
+VOID
+MacInitializeMacInfo(
+ IN NDIS_MEDIUM MacType,
+ OUT PNDIS_INFORMATION MacInfo
+ )
+
+/*++
+
+Routine Description:
+
+ Fills in the MacInfo table based on MacType.
+
+Arguments:
+
+ MacType - The MAC type we wish to decode.
+
+ MacInfo - The MacInfo structure to fill in.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ switch (MacType) {
+ case NdisMedium802_3:
+ MacInfo->SourceRouting = FALSE;
+ MacInfo->MediumAsync = FALSE;
+ MacInfo->BroadcastMask = 0x01;
+ MacInfo->MaxHeaderLength = 14;
+ MacInfo->MinHeaderLength = 14;
+ MacInfo->MediumType = NdisMedium802_3;
+ break;
+ case NdisMedium802_5:
+ MacInfo->SourceRouting = TRUE;
+ MacInfo->MediumAsync = FALSE;
+ MacInfo->BroadcastMask = 0x80;
+ MacInfo->MaxHeaderLength = 32;
+ MacInfo->MinHeaderLength = 14;
+ MacInfo->MediumType = NdisMedium802_5;
+ break;
+ case NdisMediumFddi:
+ MacInfo->SourceRouting = FALSE;
+ MacInfo->MediumAsync = FALSE;
+ MacInfo->BroadcastMask = 0x01;
+ MacInfo->MaxHeaderLength = 13;
+ MacInfo->MinHeaderLength = 13;
+ MacInfo->MediumType = NdisMediumFddi;
+ break;
+ case NdisMediumArcnet878_2:
+ MacInfo->SourceRouting = FALSE;
+ MacInfo->MediumAsync = FALSE;
+ MacInfo->BroadcastMask = 0x00;
+ MacInfo->MaxHeaderLength = 3;
+ MacInfo->MinHeaderLength = 3;
+ MacInfo->MediumType = NdisMediumArcnet878_2;
+ break;
+ case NdisMediumWan:
+ MacInfo->SourceRouting = FALSE;
+ MacInfo->MediumAsync = TRUE;
+ MacInfo->BroadcastMask = 0x01;
+ MacInfo->MaxHeaderLength = 14;
+ MacInfo->MinHeaderLength = 14;
+ MacInfo->MediumType = NdisMedium802_3;
+ break;
+ default:
+ CTEAssert(FALSE);
+ }
+ MacInfo->RealMediumType = MacType;
+
+} /* MacInitializeMacInfo */
+
+
+VOID
+MacMapFrameType(
+ IN NDIS_MEDIUM MacType,
+ IN ULONG FrameType,
+ OUT ULONG * MappedFrameType
+ )
+
+/*++
+
+Routine Description:
+
+ Maps the specified frame type to a value which is
+ valid for the medium.
+
+Arguments:
+
+ MacType - The MAC type we wish to map for.
+
+ FrameType - The frame type in question.
+
+ MappedFrameType - Returns the mapped frame type.
+
+Return Value:
+
+--*/
+
+{
+ switch (MacType) {
+
+ //
+ // Ethernet accepts all values, the default is 802.2.
+ //
+
+ case NdisMedium802_3:
+ if (FrameType >= ISN_FRAME_TYPE_MAX) {
+ *MappedFrameType = ISN_FRAME_TYPE_802_2;
+ } else {
+ *MappedFrameType = FrameType;
+ }
+ break;
+
+ //
+ // Token-ring supports SNAP and 802.2 only.
+ //
+
+ case NdisMedium802_5:
+ if (FrameType == ISN_FRAME_TYPE_SNAP) {
+ *MappedFrameType = ISN_FRAME_TYPE_SNAP;
+ } else {
+ *MappedFrameType = ISN_FRAME_TYPE_802_2;
+ }
+ break;
+
+ //
+ // FDDI supports SNAP, 802.2, and 802.3 only.
+ //
+
+ case NdisMediumFddi:
+ if ((FrameType == ISN_FRAME_TYPE_SNAP) || (FrameType == ISN_FRAME_TYPE_802_3)) {
+ *MappedFrameType = FrameType;
+ } else {
+ *MappedFrameType = ISN_FRAME_TYPE_802_2;
+ }
+ break;
+
+ //
+ // On arcnet there is only one frame type, use 802.3
+ // (it doesn't matter what we use).
+ //
+
+ case NdisMediumArcnet878_2:
+ *MappedFrameType = ISN_FRAME_TYPE_802_3;
+ break;
+
+ //
+ // WAN uses ethernet II because it includes the ethertype.
+ //
+
+ case NdisMediumWan:
+ *MappedFrameType = ISN_FRAME_TYPE_ETHERNET_II;
+ break;
+
+ default:
+ CTEAssert(FALSE);
+ }
+
+} /* MacMapFrameType */
+
+//
+// BUGBUG -- use symbols instead of hardcoded values for mac header lengths
+// --pradeepb
+//
+
+VOID
+MacReturnMaxDataSize(
+ IN PNDIS_INFORMATION MacInfo,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength,
+ IN UINT DeviceMaxFrameSize,
+ OUT PUINT MaxFrameSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the space available for user data in a MAC packet.
+ This will be the available space after the MAC header; all headers
+ headers will be included in this space.
+
+Arguments:
+
+ MacInfo - Describes the MAC we wish to decode.
+
+ SourceRouting - If we are concerned about a reply to a specific
+ frame, then this information is used.
+
+ SourceRouting - The length of SourceRouting.
+
+ MaxFrameSize - The maximum frame size as returned by the adapter.
+
+ MaxDataSize - The maximum data size computed.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ switch (MacInfo->MediumType) {
+
+ case NdisMedium802_3:
+
+ //
+ // For 802.3, we always have a 14-byte MAC header.
+ //
+
+ *MaxFrameSize = DeviceMaxFrameSize - 14;
+ break;
+
+ case NdisMedium802_5:
+
+ //
+ // For 802.5, if we have source routing information then
+ // use that, otherwise assume the worst.
+ //
+
+ if (SourceRouting && SourceRoutingLength >= 2) {
+
+ UINT SRLength;
+
+ SRLength = SR802_5Lengths[(SourceRouting[1] & TR_MAX_SIZE_MASK) >> 4];
+ DeviceMaxFrameSize -= (SourceRoutingLength + 14);
+
+ if (DeviceMaxFrameSize < SRLength) {
+ *MaxFrameSize = DeviceMaxFrameSize;
+ } else {
+ *MaxFrameSize = SRLength;
+ }
+
+ } else {
+
+#if 0
+ if (DeviceMaxFrameSize < 608) {
+ *MaxFrameSize = DeviceMaxFrameSize - 32;
+ } else {
+ *MaxFrameSize = 576;
+ }
+#endif
+ //
+ // bug # 6192. There is no point in assuming the worst. It only
+ // leads to lower throughput. Packets can get dropped by an
+ // an intermediate router for both cases (this one and the one
+ // above where 576 is chosen). In the above case, they will
+ // get dropped if two ethernet machines are communicating via
+ // a token ring. In this case, they will if two token ring
+ // machines with a frame size > max ethernet frame size are
+ // going over an ethernet. To fix the packet drop case, one
+ // should adjust the MaxPktSize Parameter of the card.
+ //
+ *MaxFrameSize = DeviceMaxFrameSize - 32;
+ }
+
+ break;
+
+ case NdisMediumFddi:
+
+ //
+ // For FDDI, we always have a 13-byte MAC header.
+ //
+
+ *MaxFrameSize = DeviceMaxFrameSize - 13;
+ break;
+
+ case NdisMediumArcnet878_2:
+
+ //
+ // For Arcnet, we always have a 3-byte MAC header.
+ //
+
+ *MaxFrameSize = DeviceMaxFrameSize - 3;
+ break;
+
+ }
+
+} /* MacReturnMaxDataSize */
+
+#if 0
+
+VOID
+IpxUpdateWanInactivityCounter(
+ IN PBINDING Binding,
+ IN IPX_HEADER UNALIGNED * IpxHeader,
+ IN ULONG IncludedHeaderLength,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when a frame is being sent on a WAN
+ line. It updates the inactivity counter for this binding
+ unless:
+
+ - The frame is from the RIP socket
+ - The frame is from the SAP socket
+ - The frame is a netbios keep alive
+ - The frame is an NCP keep alive
+
+ BUGBUG: Take the identifier as a parameter to optimize.
+
+Arguments:
+
+ Binding - The binding the frame is sent on.
+
+ IpxHeader - May contain the first bytes of the packet.
+
+ IncludedHeaderLength - The number of packet bytes at IpxHeader.
+
+ Packet - The full NDIS packet.
+
+ PacketLength - The length of the packet.
+
+Return Value:
+
+ None, but in some cases we return without resetting the
+ inactivity counter.
+
+Comments: THIS FUNCTION IS REAL HACKY AND NEEDS TO BE WORKED AT. WE CAN
+ Improve the instruction count here - pradeepb
+
+--*/
+
+{
+ PNDIS_BUFFER SecondBuffer = NULL;
+ PUCHAR SecondBufferData;
+ UINT SecondBufferLength;
+ USHORT SourceSocket;
+ PNDIS_BUFFER ThirdBuffer = NULL;
+ PUCHAR ThirdBufferData;
+ UINT ThirdBufferLength;
+
+ UNREFERENCED_PARAMETER (PacketLength);
+
+ //
+ // First get the source socket.
+ //
+
+#if 0
+ //
+ // Only time IncludedHeaderLength is less than the offset of
+ // SourceSocket in IPX header is when it 0 (from rip)
+ //
+ if (IncludedHeaderLength <= FIELD_OFFSET (IPX_HEADER, SourceSocket)) {
+#endif
+
+ //
+ // Get the second buffer in the packet (the ipx header is always in
+ // the second buffer - pradeepb.
+ //
+ // In this case
+ // there must be a second buffer or the packet is too
+ // short, so we don't check for NULL.
+ //
+
+ NdisQueryPacket(Packet, NULL, NULL, &SecondBuffer, NULL);
+ SecondBuffer = NDIS_BUFFER_LINKAGE(SecondBuffer);
+ NdisQueryBuffer (SecondBuffer, (PVOID *)&SecondBufferData, &SecondBufferLength);
+
+ SourceSocket = *(UNALIGNED USHORT *)
+ (&SecondBufferData[FIELD_OFFSET(IPX_HEADER, SourceSocket) - IncludedHeaderLength]);
+
+#if 0
+ }
+else {
+
+ SourceSocket = IpxHeader->SourceSocket;
+ }
+#endif
+ if ((SourceSocket == RIP_SOCKET) ||
+ (SourceSocket == SAP_SOCKET)) {
+
+ return;
+
+ }
+
+ if (SourceSocket == NB_SOCKET) {
+
+ UCHAR ConnectionControlFlag;
+ UCHAR DataStreamType;
+ USHORT TotalDataLength;
+
+#if 0
+ //
+ // We assume the connection control flag and data stream type
+ // are in the same buffer.
+ //
+
+ if (IncludedHeaderLength < sizeof(IPX_HEADER) + 2) {
+
+ if (SecondBuffer == NULL) {
+
+ //
+ // Get the second buffer in the packet.
+ //
+
+ NdisQueryPacket(Packet, NULL, NULL, &SecondBuffer, NULL);
+ SecondBuffer = NDIS_BUFFER_LINKAGE(SecondBuffer);
+ NdisQueryBuffer (ThirdBuffer, (PVOID *)&SecondBufferData, &SecondBufferLength);
+
+ }
+#endif
+
+ ConnectionControlFlag = *(SecondBufferData + (sizeof(IPX_HEADER) - IncludedHeaderLength));
+ DataStreamType = *(SecondBufferData + (sizeof(IPX_HEADER) + 1 - IncludedHeaderLength));
+
+
+#if 0
+ } else {
+
+ ConnectionControlFlag = ((PUCHAR)(IpxHeader+1))[0];
+ DataStreamType = ((PUCHAR)(IpxHeader+1))[1];
+ }
+
+#endif
+
+ //
+ // If this is a SYS packet with or without a request for ACK and
+ // has session data in it.
+ //
+ if (((ConnectionControlFlag == 0x80) || (ConnectionControlFlag == 0xc0)) &&
+ (DataStreamType == 0x06)) {
+
+ //
+ // This would be from the rip driver, if IncludedHeaderLength is
+ // 0. -- pradeepb
+ //
+ // At this point, we assume that total data length is in
+ // the same buffer as the others.
+ //
+ //
+ // real hacky way of doing things. One should be using
+ // FIELD_OFFSET(NB_SESSION, TotalDataLength) instead of 8.
+ // -- pradeepb
+ //
+
+ if (IncludedHeaderLength < sizeof(IPX_HEADER) + 2) {
+ TotalDataLength = *(USHORT UNALIGNED *)(SecondBufferData + (sizeof(IPX_HEADER) + 8 - IncludedHeaderLength));
+ } else {
+ TotalDataLength = ((USHORT UNALIGNED *)(IpxHeader+1))[4];
+ }
+
+ if (TotalDataLength == 0) {
+ return;
+ }
+ }
+
+ } else {
+
+ UCHAR KeepAliveSignature;
+
+
+ //
+ // Now see if it is an NCP keep alive.
+ //
+
+ if (PacketLength == sizeof(IPX_HEADER) + 2) {
+
+ //
+ // if from rip
+ //
+ if (IncludedHeaderLength <= sizeof(IPX_HEADER) + 1) {
+
+
+ //
+ // Get the second buffer
+ //
+#if 0
+ if (SecondBuffer == NULL) {
+
+ //
+ // Get the second buffer in the packet.
+ //
+
+ NdisQueryPacket(Packet, NULL, NULL, &SecondBuffer, NULL);
+ ThirdBuffer = NDIS_BUFFER_LINKAGE(SecondBuffer);
+ NdisQueryBuffer (ThirdBuffer, (PVOID *)&ThirdBufferData, &ThirdBufferLength);
+
+ }
+#endif
+ KeepAliveSignature = SecondBufferData[sizeof(IPX_HEADER) + 1 - IncludedHeaderLength];
+
+ } else {
+
+ //
+ // will we ever come here - pradeepb?
+ //
+ KeepAliveSignature = SecondBufferData[sizeof(IPX_HEADER) + 1 - IncludedHeaderLength];
+#if 0
+ KeepAliveSignature = ((PUCHAR)(IpxHeader+1))[1];
+#endif
+
+ }
+
+ if ((KeepAliveSignature == '?') ||
+ (KeepAliveSignature == 'Y')) {
+ return;
+ }
+
+ }
+
+ }
+
+ //
+ // This was a normal packet, so reset this.
+ //
+
+ Binding->WanInactivityCounter = 0;
+
+} /* IpxUpdateWanInactivityCounter */
+#endif
+
+
+VOID
+IpxUpdateWanInactivityCounter(
+ IN PBINDING Binding,
+ IN IPX_HEADER UNALIGNED * IpxHeader,
+ IN ULONG IncludedHeaderLength,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when a frame is being sent on a WAN
+ line. It updates the inactivity counter for this binding
+ unless:
+
+ - The frame is from the RIP socket
+ - The frame is from the SAP socket
+ - The frame is a netbios keep alive
+ - The frame is an NCP keep alive
+
+ BUGBUG: Take the identifier as a parameter to optimize.
+
+Arguments:
+
+ Binding - The binding the frame is sent on.
+
+ IpxHeader - May contain the first bytes of the packet.
+
+ IncludedHeaderLength - The number of packet bytes at IpxHeader.
+
+ Packet - The full NDIS packet.
+
+ PacketLength - The length of the packet.
+
+Return Value:
+
+ None, but in some cases we return without resetting the
+ inactivity counter.
+
+Comments: Improve the instruction count here - pradeepb
+
+--*/
+
+{
+ USHORT SourceSocket;
+ PNDIS_BUFFER DataBuffer = NULL;
+ PUCHAR DataBufferData;
+ UINT DataBufferLength;
+
+
+ //
+ // First get the source socket.
+ //
+ SourceSocket = IpxHeader->SourceSocket;
+ if ((SourceSocket == RIP_SOCKET) ||
+ (SourceSocket == SAP_SOCKET)) {
+
+ return;
+
+ }
+
+ if (SourceSocket == NB_SOCKET) {
+
+ UCHAR ConnectionControlFlag;
+ UCHAR DataStreamType;
+ USHORT TotalDataLength;
+
+ //
+ // ConnectionControlFlag and DataStreamType will always follow
+ // IpxHeader
+ //
+ ConnectionControlFlag = ((PUCHAR)(IpxHeader+1))[0];
+ DataStreamType = ((PUCHAR)(IpxHeader+1))[1];
+
+ //
+ // If this is a SYS packet with or without a request for ACK and
+ // has session data in it.
+ //
+ if (((ConnectionControlFlag == 0x80) || (ConnectionControlFlag == 0xc0)) &&
+ (DataStreamType == 0x06)) {
+
+ //
+ // TotalDataLength is in the same buffer.
+ //
+ TotalDataLength = ((USHORT UNALIGNED *)(IpxHeader+1))[4];
+
+ //
+ // No need to update the WAN activity counter
+ //
+ if (TotalDataLength == 0) {
+ return;
+ }
+ }
+
+ } else {
+
+ UCHAR KeepAliveSignature;
+
+
+ //
+ // Now see if it is an NCP keep alive. It can be from rip or from
+ // NCP on this machine
+ //
+ // NOTE: We cannot come here for an SMB packet - [IsaacHe - 12/15].
+ //
+ if (PacketLength == sizeof(IPX_HEADER) + 2) {
+
+ //
+ // Get the client data buffer
+ //
+ NdisQueryPacket(Packet, NULL, NULL, &DataBuffer, NULL);
+
+ //
+ // If the included header length is 0, it is from rip
+ //
+ if (IncludedHeaderLength == 0) {
+
+ //
+ // Get the second buffer in the packet. The second buffer
+ // contains the IPX header + other stuff
+ //
+ DataBuffer = NDIS_BUFFER_LINKAGE(DataBuffer);
+ } else {
+ //
+ // Get the third buffer in the packet.
+ //
+ DataBuffer = NDIS_BUFFER_LINKAGE(NDIS_BUFFER_LINKAGE(DataBuffer));
+ }
+
+ NdisQueryBuffer (DataBuffer, (PVOID *)&DataBufferData, &DataBufferLength);
+ CTEAssert(DataBufferData);
+
+ if (IncludedHeaderLength == 0) {
+ KeepAliveSignature = DataBufferData[sizeof(IPX_HEADER) + 1];
+ } else {
+ KeepAliveSignature = DataBufferData[1];
+ }
+
+ if ((KeepAliveSignature == '?') ||
+ (KeepAliveSignature == 'Y')) {
+ return;
+ }
+ }
+ }
+
+
+ //
+ // This was a normal packet, so reset this.
+ //
+
+ Binding->WanInactivityCounter = 0;
+
+} /* IpxUpdateWanInactivityCounter */
+
+#if DBG
+ULONG IpxPadCount = 0;
+#endif
+
+#ifdef _PNP_POWER
+
+NDIS_STATUS
+IpxSendFramePreFwd(
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by NB/SPX to send a frame.
+
+Arguments:
+
+ LocalTarget - The local target of the send - NB will have the LocalTarget in the Send_Reserved part
+ of the packet; SPX will not now, but will later.
+
+ Packet - The NDIS packet.
+
+ PacketLength - The length of the packet, starting at the IPX header.
+
+ IncludedHeaderLength - The length of the header included in the
+ first buffer that needs to be moved if it does not wind up
+ MacHeaderOffset bytes into the packet.
+
+Return Value:
+
+ Return of IpxSendFrame
+
+
+--*/
+
+{
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ PUCHAR Header;
+ PNDIS_BUFFER HeaderBuffer;
+ UINT TempHeaderBufferLength;
+ PDEVICE Device = IpxDevice;
+ PIPX_HEADER TempHeader;
+
+ NdisQueryPacket (Packet, NULL, NULL, &HeaderBuffer, NULL);
+ NdisQueryBuffer(HeaderBuffer, &Header, &TempHeaderBufferLength);
+
+ //
+ // Set this now, will change later
+ //
+ Reserved->CurrentNicId = 0;
+
+ //
+ // Copy the LocalTarget into the send reserved area of the packet.
+ //
+ Reserved->LocalTarget = *LocalTarget;
+
+ //
+ // If the NicId in the handle is 0, then this could be a send
+ // over all NICs in the case of NB/SPX.
+ //
+ if (NIC_FROM_LOCAL_TARGET(LocalTarget) == 0) {
+ CTEAssert(Reserved->Identifier == IDENTIFIER_NB ||
+ Reserved->Identifier == IDENTIFIER_SPX);
+
+ //
+ // Check the destination network in the IPX header. If this is 0,
+ // then we need to iterate the send over all NICs.
+ //
+ TempHeader = (PIPX_HEADER)(&Header[Device->IncludedHeaderOffset]);
+
+ if ((*(UNALIGNED ULONG *)(TempHeader->DestinationNetwork) == 0) &&
+ ((IPX_NODE_BROADCAST(TempHeader->DestinationNode)) ||
+ (Reserved->Identifier == IDENTIFIER_SPX))) {
+
+ //
+ // Start with the first NIC
+ // BUGBUG: Search for the first NIC
+ //
+
+ IPX_DEBUG(SEND, ("Iteration over NICs started, reserved: %lx\n", Reserved));
+ Reserved->CurrentNicId = 1;
+ Reserved->Net0SendSucceeded = FALSE;
+
+ FILL_LOCAL_TARGET(&Reserved->LocalTarget, 1);
+ Reserved->PacketLength = PacketLength;
+ } else {
+ //
+ // If this is on the loopback adapter (Nic 0), queue it on the LoopbackQueue;
+ // if the LoopbackRtn is not started, start it now.
+ //
+
+ //
+ // Enque this packet to the LoopbackQueue on the binding.
+ // If the LoopbackRtn is not already scheduled, schedule it.
+ //
+
+ IPX_DEBUG(LOOPB, ("Mac.c: Packet: %x\n", Packet));
+
+ //
+ // Recalculate packet counts here.
+ //
+
+ //
+ // Assume an 802_3802_2 header and use that length.
+ //
+
+ //
+ // Adjust the MAC header's length to the right value
+ //
+ NdisAdjustBufferLength (HeaderBuffer, 17);
+ NdisRecalculatePacketCounts (Packet);
+ IpxLoopbackEnque(Packet, NIC_ID_TO_BINDING(Device, 1)->Adapter);
+
+ //
+ // The upper driver waits for the SendComplete.
+ //
+ return STATUS_PENDING;
+ }
+
+ return IpxSendFrame (
+ &Reserved->LocalTarget,
+ Packet,
+ PacketLength,
+ IncludedHeaderLength);
+
+ } else {
+ return IpxSendFrame (
+ LocalTarget,
+ Packet,
+ PacketLength,
+ IncludedHeaderLength);
+ }
+}
+#endif
+
+
+NDIS_STATUS
+IpxSendFrame(
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs a MAC header in a packet and submits
+ it to the appropriate NDIS driver.
+
+ It is assumed that the first buffer in the packet contains
+ an IPX header at an offset based on the media type. This
+ IPX header is moved around if needed.
+
+ BUGBUG: Check that Binding is not NULL.
+
+Arguments:
+
+ LocalTarget - The local target of the send.
+
+ Packet - The NDIS packet.
+
+ PacketLength - The length of the packet, starting at the IPX header.
+
+ IncludedHeaderLength - The length of the header included in the
+ first buffer that needs to be moved if it does not wind up
+ MacHeaderOffset bytes into the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ PDEVICE Device = IpxDevice;
+ PUCHAR Header;
+ PBINDING Binding, MasterBinding;
+ PADAPTER Adapter;
+ ULONG TwoBytes;
+ PNDIS_BUFFER HeaderBuffer;
+ UINT TempHeaderBufferLength;
+ ULONG HeaderLength=0;
+ UCHAR SourceRoutingBuffer[18];
+ PUCHAR SourceRouting;
+ ULONG SourceRoutingLength;
+ NDIS_STATUS Status;
+ ULONG BufferLength;
+ UCHAR DestinationType;
+ UCHAR SourceRoutingIdentifier;
+ ULONG HeaderSizeRequired;
+ PIPX_HEADER TempHeader;
+ USHORT PktLength;
+
+#ifdef _PNP_POWER
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+
+ //
+ // Get the lock on the binding array
+ //
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ Binding = NIC_HANDLE_TO_BINDING(Device, &LocalTarget->NicHandle);
+
+ if (Binding == NULL) {
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ IPX_DEBUG(PNP, ("Invalid NIC handle: %lx\n", LocalTarget->NicHandle));
+ //
+ // [BUGBUGZZ] Return a unique error that NB/SPX see and re-query the NicId.
+ //
+ return STATUS_DEVICE_DOES_NOT_EXIST;
+ }
+
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+
+ Adapter = Binding->Adapter;
+
+ IpxReferenceAdapter(Adapter);
+
+ //
+ // Release the lock
+ //
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+
+ //
+ // If this is on the loopback adapter (Nic 0), queue it on the LoopbackQueue;
+ // if the LoopbackRtn is not started, start it now.
+ //
+ if (LocalTarget->NicId == 0) {
+
+ //
+ // Enque this packet to the LoopbackQueue on the binding.
+ // If the LoopbackRtn is not already scheduled, schedule it.
+ //
+
+ IPX_DEBUG(LOOPB, ("Mac.c: Packet: %x\n", Packet));
+
+ //
+ // Assume an 802_3802_2 header and use that length.
+ //
+
+ //
+ // Adjust the MAC header's length to the right value
+ //
+ // NdisAdjustBufferLength (HeaderBuffer, 17);
+
+ NdisRecalculatePacketCounts (Packet);
+
+ IpxLoopbackEnque(Packet, Device->Bindings[1]->Adapter);
+
+ //
+ // The upper driver waits for the SendComplete.
+ //
+ return STATUS_PENDING;
+ }
+
+ Binding = Device->Bindings[LocalTarget->NicId];
+
+ if (Binding == NULL) {
+ return STATUS_DEVICE_DOES_NOT_EXIST; // BUGBUG: Make this a separate switch that generally falls through?
+ }
+ Adapter = Binding->Adapter;
+#endif _PNP_POWER
+
+ //
+ // For IPX and other protocols that are guaranteed to have allocated
+ // the header from non-paged pool, use the buffer directly. For others,
+ // query the packet for the pointer to the MDL.
+ //
+ if (Reserved->Identifier >= IDENTIFIER_IPX) {
+ HeaderBuffer = Reserved->HeaderBuffer;
+ Header = Reserved->Header;
+
+ } else {
+ NdisQueryPacket (Packet, NULL, NULL, &HeaderBuffer, NULL);
+ NdisQueryBuffer(HeaderBuffer, &Header, &TempHeaderBufferLength);
+ }
+
+ CTEAssert (Reserved->PaddingBuffer == NULL);
+
+ //
+ // First move the packet around if needed.
+ //
+
+ if (Reserved->Identifier < IDENTIFIER_IPX) {
+
+ //
+ // Only RIP will have IncludedHeaderLength as 0. I don't know
+ // why we have the comment about RIP inside this if statement.
+ //
+ if (IncludedHeaderLength > 0) {
+
+ //
+ // Spx can handle a virtual net as long as it is
+ // not 0. Netbios always needs to use the real address.
+ // We need to hack the ipx source address for packets
+ // which are sent by spx if we have a fake virtual
+ // net, and packets sent by netbios unless we are
+ // bound to only one card.
+ //
+
+ //
+ // We handle binding sets as follows, based on who
+ // sent the frame to us:
+ //
+ // RIP: Since we only tell RIP about the masters at
+ // bind time, and hide slaves on indications, it should
+ // never be sending on a slave binding. Since RIP knows
+ // the real net and node of every binding we don't
+ // need to modify the packet at all.
+ //
+ // NB: For broadcasts we want to put the first card's
+ // address in the IPX source but round-robin the
+ // actual sends over all cards (broadcasts shouldn't
+ // be passed in with a slave's NIC ID). For directed
+ // packets, which may come in on a slave, we should
+ // put the slave's address in the IPX source.
+ //
+ // SPX: SPX does not send broadcasts. For directed
+ // frames we want to use the slave's net and node
+ // in the IPX source.
+ //
+
+ if (Reserved->Identifier == IDENTIFIER_NB) {
+
+ CTEAssert (IncludedHeaderLength >= sizeof(IPX_HEADER));
+
+ //
+ // Get the packet length from the ipx header. Compare with
+ // the max. allowed datagram size.
+ //
+ TempHeader = (PIPX_HEADER)(&Header[Device->IncludedHeaderOffset]);
+ PktLength = ((TempHeader->PacketLength[0] << 8) |
+ (TempHeader->PacketLength[1]));
+
+//
+// BUGBUG - Not the most efficient way to do this. NWLNKNB should do this.
+// Doing it in ipx means doing it for all packets (even those sent on
+// connections). Will remove this later when nwlnknb change has been
+// tested.
+//
+
+
+ if (PktLength > (Binding->AnnouncedMaxDatagramSize + sizeof(IPX_HEADER))) {
+ IPX_DEBUG (SEND, ("Send %d bytes too large (%d)\n",
+ PktLength,
+ Binding->AnnouncedMaxDatagramSize + sizeof(IPX_HEADER)));
+
+#ifdef _PNP_POWER
+ //
+ // Dereference the binding and adapter
+ //
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IpxDereferenceAdapter(Adapter);
+#endif _PNP_POWER
+ return STATUS_INVALID_BUFFER_SIZE;
+ }
+
+ if (Device->ValidBindings > 1) {
+
+
+ //
+ // Store this now, since even if we round-robin the
+ // actual send we want the binding set master's net
+ // and node in the IPX source address.
+ //
+
+ *(UNALIGNED ULONG *)TempHeader->SourceNetwork = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory (TempHeader->SourceNode, Binding->LocalAddress.NodeAddress, 6);
+
+ if (Binding->BindingSetMember) {
+
+ if (IPX_NODE_BROADCAST(LocalTarget->MacAddress)) {
+
+ //
+ // This is a broadcast, so we round-robin the
+ // sends through the binding set.
+ //
+#ifdef _PNP_POWER
+ //
+ // [BUGBUGZZ]: We dont have a lock here - the masterbinding could be bogus
+ //
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IpxDereferenceAdapter(Adapter);
+#endif
+ MasterBinding = Binding->MasterBinding;
+ Binding = MasterBinding->CurrentSendBinding;
+ MasterBinding->CurrentSendBinding = Binding->NextBinding;
+ Adapter = Binding->Adapter;
+
+#ifdef _PNP_POWER
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IpxReferenceAdapter(Adapter);
+#endif
+ }
+
+ }
+ }
+
+ } else if (Reserved->Identifier == IDENTIFIER_SPX) {
+
+ //
+ // Need to update this if we have multiple cards but
+ // a zero virtual net.
+ //
+
+ if (Device->MultiCardZeroVirtual) {
+
+ CTEAssert (IncludedHeaderLength >= sizeof(IPX_HEADER));
+
+ TempHeader = (PIPX_HEADER)(&Header[Device->IncludedHeaderOffset]);
+
+ *(UNALIGNED ULONG *)TempHeader->SourceNetwork = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory (TempHeader->SourceNode, Binding->LocalAddress.NodeAddress, 6);
+
+ }
+
+ } else {
+
+ //
+ // For a rip packet it should not be in a binding set,
+ // or if it is it should be the master.
+ //
+#if DBG
+ CTEAssert ((!Binding->BindingSetMember) ||
+ (Binding->CurrentSendBinding));
+#endif
+ }
+
+
+#if 0
+ //
+ // There is a header included, we need to adjust it.
+ // The header will be at Device->IncludedHeaderOffset.
+ //
+
+ if (LocalTarget->MacAddress[0] & Adapter->MacInfo.BroadcastMask) {
+ HeaderSizeRequired = Adapter->BcMcHeaderSizes[Binding->FrameType];
+ } else {
+ HeaderSizeRequired = Adapter->DefHeaderSizes[Binding->FrameType];
+ }
+
+ if (HeaderSizeRequired != Device->IncludedHeaderOffset) {
+
+ RtlMoveMemory(
+ &Header[HeaderSizeRequired],
+ &Header[Device->IncludedHeaderOffset],
+ IncludedHeaderLength);
+ }
+#endif
+ }
+ }
+
+
+
+ switch (Adapter->MacInfo.MediumType) {
+
+ case NdisMedium802_3:
+
+ if (!Binding->LineUp) {
+ //
+ // Bug #17273 return proper error message
+ //
+ // return STATUS_DEVICE_DOES_NOT_EXIST; // BUGBUG: Make this a separate switch that generally falls through?
+#ifdef _PNP_POWER
+ //
+ // Derefernce the binding and adapter
+ //
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IpxDereferenceAdapter(Adapter);
+#endif _PNP_POWER
+ return STATUS_NETWORK_UNREACHABLE;
+ }
+
+ if (Adapter->MacInfo.MediumAsync) {
+
+ IPX_HEADER UNALIGNED * IpxHeader;
+ PNDIS_BUFFER IpxNdisBuff;
+ UINT IpxHeaderLen;
+
+#if 0
+ //
+ // The header should have been moved here.
+ //
+
+ CTEAssert(Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_ETHERNET_II] ==
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_ETHERNET_II]);
+
+
+ IpxHeader = (IPX_HEADER UNALIGNED *)
+ (&Header[Adapter->DefHeaderSizes[ISN_FRAME_TYPE_ETHERNET_II]]);
+#endif
+ //
+ // The Ipx header is always the second ndis buffer in the mdl
+ // chain. Get it and then query the va of the same.
+ //
+ IpxNdisBuff = NDIS_BUFFER_LINKAGE(HeaderBuffer);
+ NdisQueryBuffer (IpxNdisBuff, (PVOID *)&IpxHeader, &IpxHeaderLen);
+// IpxHeader = (IPX_HEADER UNALIGNED *) (&Header[MAC_HEADER_SIZE]);
+
+ //
+ // If this is a type 20 name frame from Netbios and we are
+ // on a dialin WAN line, drop it if configured to.
+ //
+ // The 0x01 bit of DisableDialinNetbios controls
+ // internal->WAN packets, which we handle here.
+ //
+ //
+
+ //
+ // SS# 33592: In case of iterative sends, the IncludedHeaderLength is not set properly
+ // since we dont keep track of the length that came in the first time (we track the PacketLength
+ // however). The included length field is used here for checking for NB_NAME_FRAMES, but elsewhere
+ // used only to distinguish between whether RIP or NB/SPX sent the packet (IncludedHeaderLen ==0 for RIP)
+ // The ideal solution here is to do way with this field altogether, but for the beta we will just use the
+ // PacketLength field for comparison here since we are assured that this will be equal to the InclHeaderLen
+ // for any type 0x14 packet that comes down from NB.
+ //
+ // BUGBUGZZ: Remove the IncludedHeaderLength field.
+ //
+ if ((!Binding->DialOutAsync) &&
+ (Reserved->Identifier == IDENTIFIER_NB) &&
+ // (IncludedHeaderLength == sizeof(IPX_HEADER) + 50) && // 50 == sizeof(NB_NAME_FRAME)
+ (PacketLength == sizeof(IPX_HEADER) + 50) && // 50 == sizeof(NB_NAME_FRAME)
+ ((Device->DisableDialinNetbios & 0x01) != 0) &&
+ (IpxHeader->PacketType == 0x14)) {
+#ifdef _PNP_POWER
+ //
+ // Derefernce the binding and adapter
+ //
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IpxDereferenceAdapter(Adapter);
+#endif _PNP_POWER
+ return STATUS_SUCCESS;
+ }
+
+
+ //
+ // We do checks to see if we should reset the inactivity
+ // counter. We normally need to check for netbios
+ // session alives, packets from rip, packets from
+ // sap, and ncp keep alives. In fact sap and ncp
+ // packets don't come through here.
+ //
+
+ IpxUpdateWanInactivityCounter(
+ Binding,
+ IpxHeader,
+ IncludedHeaderLength,
+ Packet,
+ PacketLength);
+
+ RtlCopyMemory (Header, Binding->RemoteMacAddress.Address, 6);
+
+ } else {
+
+ RtlCopyMemory (Header, LocalTarget->MacAddress, 6);
+ }
+
+ RtlCopyMemory (Header+6, Binding->LocalMacAddress.Address, 6);
+
+ switch (Binding->FrameType) {
+
+ case ISN_FRAME_TYPE_802_2:
+ TwoBytes = PacketLength + 3;
+ Header[14] = 0xe0;
+ Header[15] = 0xe0;
+ Header[16] = 0x03;
+ HeaderLength = 17;
+ break;
+ case ISN_FRAME_TYPE_802_3:
+ TwoBytes = PacketLength;
+ HeaderLength = 14;
+ break;
+ case ISN_FRAME_TYPE_ETHERNET_II:
+ TwoBytes = Adapter->BindSap;
+ HeaderLength = 14;
+ break;
+ case ISN_FRAME_TYPE_SNAP:
+ TwoBytes = PacketLength + 8;
+ Header[14] = 0xaa;
+ Header[15] = 0xaa;
+ Header[16] = 0x03;
+ Header[17] = 0x00;
+ Header[18] = 0x00;
+ Header[19] = 0x00;
+ *(UNALIGNED USHORT *)(&Header[20]) = Adapter->BindSapNetworkOrder;
+ HeaderLength = 22;
+ break;
+ }
+
+ Header[12] = (UCHAR)(TwoBytes / 256);
+ Header[13] = (UCHAR)(TwoBytes % 256);
+
+ //BufferLength = IncludedHeaderLength + HeaderLength;
+ BufferLength = HeaderLength;
+
+ //
+ // Pad odd-length packets if needed.
+ //
+
+ if ((((PacketLength + HeaderLength) & 1) != 0) &&
+ (Device->EthernetPadToEven) &&
+ (!Adapter->MacInfo.MediumAsync)) {
+
+ PNDIS_BUFFER CurBuffer;
+ PIPX_PADDING_BUFFER PaddingBuffer = IpxPaddingBuffer;
+ UINT Offset;
+ UINT LastBufferLength;
+
+ //
+ // Find the tail of the current packet.
+ //
+
+ CurBuffer = HeaderBuffer;
+ while (NDIS_BUFFER_LINKAGE(CurBuffer) != NULL) {
+ CurBuffer = NDIS_BUFFER_LINKAGE(CurBuffer);
+ }
+
+ //
+ // If the last byte of the last NDIS_BUFFER is not at the end of
+ // the page, then we can simply increase the NDIS_BUFFER ByteCount
+ // by one.
+ // Otherwise, we must use the global padding buffer.
+ //
+
+ NdisQueryBufferOffset( CurBuffer, &Offset, &LastBufferLength );
+
+ if ( ((Offset + LastBufferLength) & (PAGE_SIZE - 1)) != 0) {
+ if ( CurBuffer == HeaderBuffer ) {
+ BufferLength++; // Just bump this length
+ } else {
+ NdisAdjustBufferLength( CurBuffer, (LastBufferLength + 1) );
+
+ Reserved->PreviousTail = NULL;
+ Reserved->PaddingBuffer = (PIPX_PADDING_BUFFER)CurBuffer;
+ }
+
+ } else {
+
+ CTEAssert (NDIS_BUFFER_LINKAGE(PaddingBuffer->NdisBuffer) == NULL);
+
+ Reserved->PreviousTail = CurBuffer;
+ NDIS_BUFFER_LINKAGE (CurBuffer) = PaddingBuffer->NdisBuffer;
+ Reserved->PaddingBuffer = PaddingBuffer;
+
+ }
+
+ if (TwoBytes != Adapter->BindSap) {
+ CTEAssert(TwoBytes & 1);
+ TwoBytes += 1;
+ Header[12] = (UCHAR)(TwoBytes / 256);
+ Header[13] = (UCHAR)(TwoBytes % 256);
+ }
+
+#if DBG
+ ++IpxPadCount;
+#endif
+ }
+
+ break;
+
+ case NdisMedium802_5:
+
+ if (Reserved->Identifier >= IDENTIFIER_IPX) {
+
+ DestinationType = Reserved->DestinationType;
+ SourceRoutingIdentifier = IDENTIFIER_IPX;
+
+ } else {
+
+ if (LocalTarget->MacAddress[0] & 0x80) {
+ if (*(UNALIGNED ULONG *)(&LocalTarget->MacAddress[2]) != 0xffffffff) {
+ DestinationType = DESTINATION_MCAST;
+ } else {
+ DestinationType = DESTINATION_BCAST;
+ }
+ } else {
+ DestinationType = DESTINATION_DEF;
+ }
+ SourceRoutingIdentifier = Reserved->Identifier;
+
+ }
+
+ if (DestinationType == DESTINATION_DEF) {
+
+ MacLookupSourceRouting(
+ SourceRoutingIdentifier,
+ Binding,
+ LocalTarget->MacAddress,
+ SourceRoutingBuffer,
+ &SourceRoutingLength);
+
+ if (SourceRoutingLength != 0) {
+
+// PUCHAR IpxHeader = Header + Binding->DefHeaderSize;
+ PUCHAR IpxHeader = Header + MAC_HEADER_SIZE;
+
+ //
+ // Need to slide the header down to accomodate the SR.
+ //
+
+ SourceRouting = SourceRoutingBuffer;
+// RtlMoveMemory (IpxHeader+SourceRoutingLength, IpxHeader, IncludedHeaderLength);
+ }
+
+ } else {
+
+ //
+ // For these packets we assume that the header is in the
+ // right place.
+ //
+
+ if (!Adapter->SourceRouting) {
+
+ SourceRoutingLength = 0;
+
+ } else {
+
+ if (DestinationType == DESTINATION_BCAST) {
+
+ if (Binding->AllRouteBroadcast) {
+ SourceRouting = AllRouteSourceRouting;
+ } else {
+ SourceRouting = SingleRouteSourceRouting;
+ }
+ SourceRoutingLength = 2;
+
+ } else {
+
+ CTEAssert (DestinationType == DESTINATION_MCAST);
+
+ if (Binding->AllRouteMulticast) {
+ SourceRouting = AllRouteSourceRouting;
+ } else {
+ SourceRouting = SingleRouteSourceRouting;
+ }
+ SourceRoutingLength = 2;
+
+ }
+ }
+
+#if 0
+ if (SourceRoutingLength != 0) {
+
+ // PUCHAR IpxHeader = Header + Binding->BcMcHeaderSize;
+ PUCHAR IpxHeader = Header + MAC_HEADER_SIZE;
+
+ //
+ // Need to slide the header down to accomodate the SR.
+ //
+
+ RtlMoveMemory (IpxHeader+SourceRoutingLength, IpxHeader, IncludedHeaderLength);
+ }
+#endif
+
+ }
+
+ Header[0] = TR_PREAMBLE_AC;
+ Header[1] = TR_PREAMBLE_FC;
+ RtlCopyMemory (Header+2, LocalTarget->MacAddress, 6);
+ RtlCopyMemory (Header+8, Binding->LocalMacAddress.Address, 6);
+
+ if (SourceRoutingLength != 0) {
+ Header[8] |= TR_SOURCE_ROUTE_FLAG;
+ RtlCopyMemory (Header+14, SourceRouting, SourceRoutingLength);
+ }
+
+ Header += (14 + SourceRoutingLength);
+
+ switch (Binding->FrameType) {
+ case ISN_FRAME_TYPE_802_2:
+ case ISN_FRAME_TYPE_802_3:
+ case ISN_FRAME_TYPE_ETHERNET_II:
+ Header[0] = 0xe0;
+ Header[1] = 0xe0;
+ Header[2] = 0x03;
+ HeaderLength = 17;
+ break;
+ case ISN_FRAME_TYPE_SNAP:
+ Header[0] = 0xaa;
+ Header[1] = 0xaa;
+ Header[2] = 0x03;
+ Header[3] = 0x00;
+ Header[4] = 0x00;
+ Header[5] = 0x00;
+ *(UNALIGNED USHORT *)(&Header[6]) = Adapter->BindSapNetworkOrder;
+ HeaderLength = 22;
+ break;
+ }
+
+// BufferLength = IncludedHeaderLength + HeaderLength + SourceRoutingLength;
+ BufferLength = HeaderLength + SourceRoutingLength;
+
+ break;
+
+ case NdisMediumFddi:
+
+ Header[0] = FDDI_HEADER_BYTE;
+ RtlCopyMemory (Header+1, LocalTarget->MacAddress, 6);
+ RtlCopyMemory (Header+7, Binding->LocalMacAddress.Address, 6);
+
+ switch (Binding->FrameType) {
+ case ISN_FRAME_TYPE_802_3:
+ HeaderLength = 13;
+ break;
+ case ISN_FRAME_TYPE_802_2:
+ case ISN_FRAME_TYPE_ETHERNET_II:
+ Header[13] = 0xe0;
+ Header[14] = 0xe0;
+ Header[15] = 0x03;
+ HeaderLength = 16;
+ break;
+ case ISN_FRAME_TYPE_SNAP:
+ Header[13] = 0xaa;
+ Header[14] = 0xaa;
+ Header[15] = 0x03;
+ Header[16] = 0x00;
+ Header[17] = 0x00;
+ Header[18] = 0x00;
+ *(UNALIGNED USHORT *)(&Header[19]) = Adapter->BindSapNetworkOrder;
+ HeaderLength = 21;
+ break;
+ }
+
+// BufferLength = IncludedHeaderLength + HeaderLength;
+ BufferLength = HeaderLength;
+
+ break;
+
+ case NdisMediumArcnet878_2:
+
+ //
+ // Convert broadcast address to 0 (the arcnet broadcast).
+ //
+
+ Header[0] = Binding->LocalMacAddress.Address[5];
+ if (LocalTarget->MacAddress[5] == 0xff) {
+ Header[1] = 0x00;
+ } else {
+ Header[1] = LocalTarget->MacAddress[5];
+ }
+ Header[2] = ARCNET_PROTOCOL_ID;
+
+ //
+ // Binding->FrameType is not used.
+ //
+
+ HeaderLength = 3;
+// BufferLength = IncludedHeaderLength + HeaderLength;
+ BufferLength = HeaderLength;
+
+ break;
+
+ }
+
+ //
+ // Adjust the MAC header's length to the right value
+ //
+ NdisAdjustBufferLength (HeaderBuffer, BufferLength);
+ NdisRecalculatePacketCounts (Packet);
+
+#if 0
+ {
+ PMDL mdl;
+ mdl = (PMDL)NDIS_BUFFER_LINKAGE(HeaderBuffer);
+ if (mdl) {
+
+ KdPrint(("**Bytecount %x %x\n",mdl->ByteCount, mdl));
+ if ((LONG)mdl->ByteCount < 0) {
+ DbgBreakPoint();
+ }
+ }
+ }
+#endif
+
+#if DBG
+ {
+ ULONG SendFlag;
+ ULONG Temp;
+ PNDIS_BUFFER FirstPacketBuffer;
+ PNDIS_BUFFER SecondPacketBuffer;
+ IPX_HEADER DumpHeader;
+ UCHAR DumpData[14];
+
+ NdisQueryPacket (Packet, NULL, NULL, &FirstPacketBuffer, NULL);
+ SecondPacketBuffer = NDIS_BUFFER_LINKAGE(FirstPacketBuffer);
+ TdiCopyMdlToBuffer(SecondPacketBuffer, 0, &DumpHeader, 0, sizeof(IPX_HEADER), &Temp);
+ if (Reserved->Identifier == IDENTIFIER_NB) {
+ SendFlag = IPX_PACKET_LOG_SEND_NB;
+ } else if (Reserved->Identifier == IDENTIFIER_SPX) {
+ SendFlag = IPX_PACKET_LOG_SEND_SPX;
+ } else if (Reserved->Identifier == IDENTIFIER_RIP) {
+ SendFlag = IPX_PACKET_LOG_SEND_RIP;
+ } else {
+ if (DumpHeader.SourceSocket == IpxPacketLogSocket) {
+ SendFlag = IPX_PACKET_LOG_SEND_SOCKET | IPX_PACKET_LOG_SEND_OTHER;
+ } else {
+ SendFlag = IPX_PACKET_LOG_SEND_OTHER;
+ }
+ }
+
+#if 0
+ if (PACKET_LOG(SendFlag)) {
+
+ TdiCopyMdlToBuffer(SecondPacketBuffer, sizeof(IPX_HEADER), &DumpData, 0, 14, &Temp);
+
+ IpxLogPacket(
+ TRUE,
+ LocalTarget->MacAddress,
+ Binding->LocalMacAddress.Address,
+ (USHORT)PacketLength,
+ &DumpHeader,
+ DumpData);
+
+ }
+#endif
+ }
+#endif
+
+ ++Device->Statistics.PacketsSent;
+
+
+ NdisSend(
+ &Status,
+ Adapter->NdisBindingHandle,
+ Packet);
+
+#ifdef _PNP_POWER
+ if (Status != STATUS_PENDING) {
+
+ if (Reserved->PaddingBuffer) {
+
+ //
+ // Remove padding if it was done.
+ //
+
+ if ( Reserved->PreviousTail ) {
+ NDIS_BUFFER_LINKAGE (Reserved->PreviousTail) = (PNDIS_BUFFER)NULL;
+ } else {
+ PNDIS_BUFFER LastBuffer = (PNDIS_BUFFER)Reserved->PaddingBuffer;
+ UINT LastBufferLength;
+
+ NdisQueryBuffer( LastBuffer, NULL, &LastBufferLength );
+ NdisAdjustBufferLength( LastBuffer, (LastBufferLength - 1) );
+ }
+
+ Reserved->PaddingBuffer = NULL;
+
+ if (Reserved->Identifier < IDENTIFIER_IPX) {
+ NdisRecalculatePacketCounts (Packet);
+ }
+ }
+
+ //
+ // If this was an NB/SPX packet, and there was an
+ // iterative send going on, then call the SendComplete
+ // handler.
+ //
+ if ((Reserved->Identifier == IDENTIFIER_NB ||
+ Reserved->Identifier == IDENTIFIER_SPX) &&
+ (Reserved->CurrentNicId)) {
+
+ IpxSendComplete(
+ (NDIS_HANDLE)Binding->Adapter,
+ Packet,
+ Status);
+
+ Status = STATUS_PENDING;
+ }
+ }
+#else
+ if ((Status != STATUS_PENDING) &&
+ (Reserved->PaddingBuffer)) {
+
+ //
+ // Remove padding if it was done.
+ //
+
+ if ( Reserved->PreviousTail ) {
+ NDIS_BUFFER_LINKAGE (Reserved->PreviousTail) = (PNDIS_BUFFER)NULL;
+ } else {
+ PNDIS_BUFFER LastBuffer = (PNDIS_BUFFER)Reserved->PaddingBuffer;
+ UINT LastBufferLength;
+
+ NdisQueryBuffer( LastBuffer, NULL, &LastBufferLength );
+ NdisAdjustBufferLength( LastBuffer, (LastBufferLength - 1) );
+ }
+
+ Reserved->PaddingBuffer = NULL;
+
+ if (Reserved->Identifier < IDENTIFIER_IPX) {
+ NdisRecalculatePacketCounts (Packet);
+ }
+ }
+#endif
+
+#ifdef _PNP_POWER
+ //
+ // Derefernce the binding and adapter
+ //
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IpxDereferenceAdapter(Adapter);
+#endif _PNP_POWER
+
+ return Status;
+
+} /* IpxSendFrame */
+
+
+NDIS_STATUS
+IpxSendFrame802_3802_3(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs a MAC header in a packet and submits
+ it to the appropriate NDIS driver.
+
+ It is assumed that the first buffer in the packet contains
+ an IPX header at an offset based on the media type. This
+ IPX header is moved around if needed.
+
+ THIS FUNCTION ONLY CONSTRUCT NDISMEDIUM802_3 FRAMES IN
+ THE ISN_FRAME_TYPE_802_3 FORMAT.
+
+Arguments:
+
+ Adapter - The adapter on which we are sending.
+
+ LocalTarget - The local target of the send.
+
+ Packet - The NDIS packet.
+
+ PacketLength - The length of the packet, starting at the IPX header.
+
+ IncludedHeaderLength - The length of the header included in the
+ first buffer that needs to be moved if it does not wind up
+ MacHeaderOffset bytes into the packet.
+
+ //
+ // BUGBUG: Remove the IncludedHeaderLength parameter from here
+ //
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ PUCHAR Header;
+ NDIS_STATUS Status;
+ LONG HeaderLength;
+
+ Header = Reserved->Header;
+
+#if BACK_FILL
+ BACK_FILL_HEADER(Header, Reserved, 14, Packet);
+ IPX_DEBUG(SEND,("Backfill request 802_3802_3!! %x %x %x\n", Packet, Reserved, Reserved->HeaderBuffer));
+#endif
+
+ RtlCopyMemory (Header, LocalTarget->MacAddress, 6);
+ RtlCopyMemory (Header+6, Adapter->LocalMacAddress.Address, 6);
+
+ //
+ // Pad odd-length packets if needed.
+ //
+
+ if (((PacketLength & 1) != 0) &&
+ (IpxDevice->EthernetPadToEven)) {
+
+ PNDIS_BUFFER CurBuffer;
+ PIPX_PADDING_BUFFER PaddingBuffer = IpxPaddingBuffer;
+ UINT Offset;
+ UINT LastBufferLength;
+
+ //
+ // Find the tail of the current packet.
+ //
+
+ CurBuffer = Reserved->HeaderBuffer;
+ while (NDIS_BUFFER_LINKAGE(CurBuffer) != NULL) {
+ CurBuffer = NDIS_BUFFER_LINKAGE(CurBuffer);
+ }
+
+ //
+ // If the last byte of the last NDIS_BUFFER is not at the end of
+ // the page, then we can simply increase the NDIS_BUFFER ByteCount
+ // by one.
+ // Otherwise, we must use the global padding buffer.
+ //
+
+ NdisQueryBufferOffset( CurBuffer, &Offset, &LastBufferLength );
+
+ if ( ((Offset + LastBufferLength) & (PAGE_SIZE - 1)) != 0) {
+#if BACK_FILL
+ if (0) {
+
+#else
+ if ( CurBuffer == Reserved->HeaderBuffer ) {
+ IncludedHeaderLength++; // Just bump this length
+#endif
+ } else {
+ NdisAdjustBufferLength( CurBuffer, (LastBufferLength + 1) );
+
+ Reserved->PreviousTail = NULL;
+ Reserved->PaddingBuffer = (PIPX_PADDING_BUFFER)CurBuffer;
+ }
+
+ } else {
+
+ CTEAssert (NDIS_BUFFER_LINKAGE(PaddingBuffer->NdisBuffer) == NULL);
+
+ Reserved->PreviousTail = CurBuffer;
+ NDIS_BUFFER_LINKAGE (CurBuffer) = PaddingBuffer->NdisBuffer;
+ Reserved->PaddingBuffer = PaddingBuffer;
+
+ }
+
+ ++PacketLength;
+#if DBG
+ ++IpxPadCount;
+#endif
+
+ }
+
+ Header[12] = (UCHAR)(PacketLength / 256);
+ Header[13] = (UCHAR)(PacketLength % 256);
+
+ //NdisAdjustBufferLength (Reserved->HeaderBuffer, IncludedHeaderLength + 14);
+#if BACK_FILL
+ BACK_FILL_ADJUST_BUFFER_LENGTH(Reserved, 14);
+#else
+ NdisAdjustBufferLength (Reserved->HeaderBuffer, 14);
+#endif
+
+ NdisRecalculatePacketCounts (Packet);
+
+ NdisSend(
+ &Status,
+ Adapter->NdisBindingHandle,
+ Packet);
+
+ return Status;
+
+} /* IpxSendFrame802_3802_3 */
+
+
+NDIS_STATUS
+IpxSendFrame802_3802_2(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs a MAC header in a packet and submits
+ it to the appropriate NDIS driver.
+
+ It is assumed that the first buffer in the packet contains
+ an IPX header at an offset based on the media type. This
+ IPX header is moved around if needed.
+
+ THIS FUNCTION ONLY CONSTRUCT NDISMEDIUM802_3 FRAMES IN
+ THE ISN_FRAME_TYPE_802_2 FORMAT.
+
+Arguments:
+
+ Adapter - The adapter on which we are sending.
+
+ LocalTarget - The local target of the send.
+
+ Packet - The NDIS packet.
+
+ PacketLength - The length of the packet, starting at the IPX header.
+
+ IncludedHeaderLength - The length of the header included in the
+ first buffer that needs to be moved if it does not wind up
+ MacHeaderOffset bytes into the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ PUCHAR Header;
+ ULONG TwoBytes;
+ NDIS_STATUS Status;
+
+ Header = Reserved->Header;
+
+#if BACK_FILL
+ BACK_FILL_HEADER(Header, Reserved, 17, Packet);
+ IPX_DEBUG(SEND, ("Backfill request 802_3802_3!! %x %x %x\n", Packet, Reserved, Reserved->HeaderBuffer));
+ IPX_DEBUG(SEND, ("packet=%x, usermdl %x\n",Packet,Reserved->HeaderBuffer));
+#endif
+
+ RtlCopyMemory (Header, LocalTarget->MacAddress, 6);
+ RtlCopyMemory (Header+6, Adapter->LocalMacAddress.Address, 6);
+
+ TwoBytes = PacketLength + 3;
+ Header[14] = 0xe0;
+ Header[15] = 0xe0;
+ Header[16] = 0x03;
+
+ //
+ // Pad odd-length packets if needed.
+ //
+
+ if (((PacketLength & 1) == 0) &&
+ (IpxDevice->EthernetPadToEven)) {
+
+ PNDIS_BUFFER CurBuffer;
+ PIPX_PADDING_BUFFER PaddingBuffer = IpxPaddingBuffer;
+ UINT Offset;
+ UINT LastBufferLength;
+
+ //
+ // Find the tail of the current packet.
+ //
+
+ CurBuffer = Reserved->HeaderBuffer;
+ while (NDIS_BUFFER_LINKAGE(CurBuffer) != NULL) {
+ CurBuffer = NDIS_BUFFER_LINKAGE(CurBuffer);
+ }
+
+ //
+ // If the last byte of the last NDIS_BUFFER is not at the end of
+ // the page, then we can simply increase the NDIS_BUFFER ByteCount
+ // by one.
+ // Otherwise, we must use the global padding buffer.
+ //
+
+ NdisQueryBufferOffset( CurBuffer, &Offset, &LastBufferLength );
+
+ if ( ((Offset + LastBufferLength) & (PAGE_SIZE - 1)) != 0 ) {
+#if BACK_FILL
+ if (0) {
+#else
+ if ( CurBuffer == Reserved->HeaderBuffer ) {
+
+ IncludedHeaderLength++; // Just bump this length
+#endif
+ } else {
+ NdisAdjustBufferLength( CurBuffer, (LastBufferLength + 1) );
+
+ Reserved->PreviousTail = NULL;
+ Reserved->PaddingBuffer = (PIPX_PADDING_BUFFER)CurBuffer;
+ }
+
+ } else {
+
+ CTEAssert (NDIS_BUFFER_LINKAGE(PaddingBuffer->NdisBuffer) == NULL);
+
+ Reserved->PreviousTail = CurBuffer;
+ NDIS_BUFFER_LINKAGE (CurBuffer) = PaddingBuffer->NdisBuffer;
+ Reserved->PaddingBuffer = PaddingBuffer;
+
+ }
+
+ ++TwoBytes;
+#if DBG
+ ++IpxPadCount;
+#endif
+
+ }
+
+ Header[12] = (UCHAR)(TwoBytes / 256);
+ Header[13] = (UCHAR)(TwoBytes % 256);
+
+// NdisAdjustBufferLength (Reserved->HeaderBuffer, IncludedHeaderLength + 17);
+
+#if BACK_FILL
+ BACK_FILL_ADJUST_BUFFER_LENGTH(Reserved, 17);
+#else
+ NdisAdjustBufferLength (Reserved->HeaderBuffer, 17);
+#endif
+
+ NdisRecalculatePacketCounts (Packet);
+
+ NdisSend(
+ &Status,
+ Adapter->NdisBindingHandle,
+ Packet);
+
+ return Status;
+
+} /* IpxSendFrame802_3802_2 */
+
+
+NDIS_STATUS
+IpxSendFrame802_3EthernetII(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs a MAC header in a packet and submits
+ it to the appropriate NDIS driver.
+
+ It is assumed that the first buffer in the packet contains
+ an IPX header at an offset based on the media type. This
+ IPX header is moved around if needed.
+
+ THIS FUNCTION ONLY CONSTRUCT NDISMEDIUM802_3 FRAMES IN
+ THE ISN_FRAME_TYPE_ETHERNET_II FORMAT.
+
+Arguments:
+
+ Adapter - The adapter on which we are sending.
+
+ LocalTarget - The local target of the send.
+
+ Packet - The NDIS packet.
+
+ PacketLength - The length of the packet, starting at the IPX header.
+
+ IncludedHeaderLength - The length of the header included in the
+ first buffer that needs to be moved if it does not wind up
+ MacHeaderOffset bytes into the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ PUCHAR Header;
+ NDIS_STATUS Status;
+
+ Header = Reserved->Header;
+
+#if BACK_FILL
+ BACK_FILL_HEADER(Header, Reserved, 14, Packet);
+#endif BACK_FILL
+
+ RtlCopyMemory (Header, LocalTarget->MacAddress, 6);
+ RtlCopyMemory (Header+6, Adapter->LocalMacAddress.Address, 6);
+
+ *(UNALIGNED USHORT *)(&Header[12]) = Adapter->BindSapNetworkOrder;
+
+ //
+ // Pad odd-length packets if needed.
+ //
+
+ if (((PacketLength & 1) != 0) &&
+ (IpxDevice->EthernetPadToEven)) {
+
+ PNDIS_BUFFER CurBuffer;
+ PIPX_PADDING_BUFFER PaddingBuffer = IpxPaddingBuffer;
+ UINT Offset;
+ UINT LastBufferLength;
+
+ //
+ // Find the tail of the current packet.
+ //
+
+ CurBuffer = Reserved->HeaderBuffer;
+ while (NDIS_BUFFER_LINKAGE(CurBuffer) != NULL) {
+ CurBuffer = NDIS_BUFFER_LINKAGE(CurBuffer);
+ }
+
+ //
+ // If the last byte of the last NDIS_BUFFER is not at the end of
+ // the page, then we can simply increase the NDIS_BUFFER ByteCount
+ // by one.
+ // Otherwise, we must use the global padding buffer.
+ //
+
+ NdisQueryBufferOffset( CurBuffer, &Offset, &LastBufferLength );
+
+ if ( ((Offset + LastBufferLength) & (PAGE_SIZE - 1)) != 0) {
+
+#if BACK_FILL
+ if (0) {
+
+#else
+ if ( CurBuffer == Reserved->HeaderBuffer ) {
+ IncludedHeaderLength++; // Just bump this length
+#endif
+ } else {
+ NdisAdjustBufferLength( CurBuffer, (LastBufferLength + 1) );
+
+ Reserved->PreviousTail = NULL;
+ Reserved->PaddingBuffer = (PIPX_PADDING_BUFFER)CurBuffer;
+ }
+
+ } else {
+
+ CTEAssert (NDIS_BUFFER_LINKAGE(PaddingBuffer->NdisBuffer) == NULL);
+
+ Reserved->PreviousTail = CurBuffer;
+ NDIS_BUFFER_LINKAGE (CurBuffer) = PaddingBuffer->NdisBuffer;
+ Reserved->PaddingBuffer = PaddingBuffer;
+
+ }
+
+#if DBG
+ ++IpxPadCount;
+#endif
+
+ }
+
+ // NdisAdjustBufferLength (Reserved->HeaderBuffer, IncludedHeaderLength + 14);
+
+#if BACK_FILL
+ BACK_FILL_ADJUST_BUFFER_LENGTH(Reserved, 14);
+#else
+ NdisAdjustBufferLength (Reserved->HeaderBuffer, 14);
+#endif
+ NdisRecalculatePacketCounts (Packet);
+
+ NdisSend(
+ &Status,
+ Adapter->NdisBindingHandle,
+ Packet);
+
+ return Status;
+
+} /* IpxSendFrame802_3EthernetII */
+
+
+NDIS_STATUS
+IpxSendFrame802_3Snap(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs a MAC header in a packet and submits
+ it to the appropriate NDIS driver.
+
+ It is assumed that the first buffer in the packet contains
+ an IPX header at an offset based on the media type. This
+ IPX header is moved around if needed.
+
+ THIS FUNCTION ONLY CONSTRUCT NDISMEDIUM802_3 FRAMES IN
+ THE ISN_FRAME_TYPE_SNAP FORMAT.
+
+Arguments:
+
+ Adapter - The adapter on which we are sending.
+
+ LocalTarget - The local target of the send.
+
+ Packet - The NDIS packet.
+
+ PacketLength - The length of the packet, starting at the IPX header.
+
+ IncludedHeaderLength - The length of the header included in the
+ first buffer that needs to be moved if it does not wind up
+ MacHeaderOffset bytes into the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ PUCHAR Header;
+ ULONG TwoBytes;
+ NDIS_STATUS Status;
+
+ Header = Reserved->Header;
+
+#if BACK_FILL
+ BACK_FILL_HEADER(Header, Reserved, 22, Packet);
+#endif BACK_FILL
+
+ RtlCopyMemory (Header, LocalTarget->MacAddress, 6);
+ RtlCopyMemory (Header+6, Adapter->LocalMacAddress.Address, 6);
+
+ TwoBytes = PacketLength + 8;
+ Header[14] = 0xaa;
+ Header[15] = 0xaa;
+ Header[16] = 0x03;
+ Header[17] = 0x00;
+ Header[18] = 0x00;
+ Header[19] = 0x00;
+ *(UNALIGNED USHORT *)(&Header[20]) = Adapter->BindSapNetworkOrder;
+
+ //
+ // Pad odd-length packets if needed.
+ //
+
+ if (((PacketLength & 1) == 0) &&
+ (IpxDevice->EthernetPadToEven)) {
+
+ PNDIS_BUFFER CurBuffer;
+ PIPX_PADDING_BUFFER PaddingBuffer = IpxPaddingBuffer;
+ UINT Offset;
+ UINT LastBufferLength;
+
+ //
+ // Find the tail of the current packet.
+ //
+
+ CurBuffer = Reserved->HeaderBuffer;
+ while (NDIS_BUFFER_LINKAGE(CurBuffer) != NULL) {
+ CurBuffer = NDIS_BUFFER_LINKAGE(CurBuffer);
+ }
+
+ //
+ // If the last byte of the last NDIS_BUFFER is not at the end of
+ // the page, then we can simply increase the NDIS_BUFFER ByteCount
+ // by one.
+ // Otherwise, we must use the global padding buffer.
+ //
+
+ NdisQueryBufferOffset( CurBuffer, &Offset, &LastBufferLength );
+
+ if ( ((Offset + LastBufferLength) & (PAGE_SIZE - 1)) != 0) {
+
+#if BACK_FILL
+ if (0) {
+
+#else
+ if ( CurBuffer == Reserved->HeaderBuffer ) {
+ IncludedHeaderLength++; // Just bump this length
+#endif
+ } else {
+ NdisAdjustBufferLength( CurBuffer, (LastBufferLength + 1) );
+
+ Reserved->PreviousTail = NULL;
+ Reserved->PaddingBuffer = (PIPX_PADDING_BUFFER)CurBuffer;
+ }
+
+ } else {
+
+ CTEAssert (NDIS_BUFFER_LINKAGE(PaddingBuffer->NdisBuffer) == NULL);
+
+ Reserved->PreviousTail = CurBuffer;
+ NDIS_BUFFER_LINKAGE (CurBuffer) = PaddingBuffer->NdisBuffer;
+ Reserved->PaddingBuffer = PaddingBuffer;
+
+ }
+
+ ++TwoBytes;
+#if DBG
+ ++IpxPadCount;
+#endif
+
+ }
+
+ Header[12] = (UCHAR)(TwoBytes / 256);
+ Header[13] = (UCHAR)(TwoBytes % 256);
+
+ // NdisAdjustBufferLength (Reserved->HeaderBuffer, IncludedHeaderLength + 22);
+#if BACK_FILL
+ BACK_FILL_ADJUST_BUFFER_LENGTH(Reserved, 22);
+#else
+ NdisAdjustBufferLength (Reserved->HeaderBuffer, 22);
+#endif
+
+ NdisRecalculatePacketCounts (Packet);
+
+ NdisSend(
+ &Status,
+ Adapter->NdisBindingHandle,
+ Packet);
+
+ return Status;
+
+} /* IpxSendFrame802_3Snap */
+
+
+NDIS_STATUS
+IpxSendFrame802_5802_2(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs a MAC header in a packet and submits
+ it to the appropriate NDIS driver.
+
+ It is assumed that the first buffer in the packet contains
+ an IPX header at an offset based on the media type. This
+ IPX header is moved around if needed.
+
+ THIS FUNCTION ONLY CONSTRUCT NDISMEDIUM802_5 FRAMES IN
+ THE ISN_FRAME_TYPE_802_2 FORMAT.
+
+Arguments:
+
+ Adapter - The adapter on which we are sending.
+
+ LocalTarget - The local target of the send.
+
+ Packet - The NDIS packet.
+
+ PacketLength - The length of the packet, starting at the IPX header.
+
+ IncludedHeaderLength - The length of the header included in the
+ first buffer that needs to be moved if it does not wind up
+ MacHeaderOffset bytes into the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ PBINDING Binding = Adapter->Bindings[ISN_FRAME_TYPE_802_2];
+ PUCHAR Header;
+ ULONG HeaderLength;
+ UCHAR SourceRoutingBuffer[18];
+ PUCHAR SourceRouting;
+ ULONG SourceRoutingLength;
+ NDIS_STATUS Status;
+ ULONG BufferLength;
+ UCHAR DestinationType;
+
+ Header = Reserved->Header;
+
+#if BACK_FILL
+ BACK_FILL_HEADER(Header, Reserved, 17, Packet);
+#endif BACK_FILL
+
+ DestinationType = Reserved->DestinationType;
+
+ if (DestinationType == DESTINATION_DEF) {
+
+ MacLookupSourceRouting(
+ Reserved->Identifier,
+ Binding,
+ LocalTarget->MacAddress,
+ SourceRoutingBuffer,
+ &SourceRoutingLength);
+
+ if (SourceRoutingLength != 0) {
+
+ //PUCHAR IpxHeader = Header + Binding->DefHeaderSize;
+ PUCHAR IpxHeader = Header + MAC_HEADER_SIZE;
+
+ //
+ // Need to slide the header down to accomodate the SR.
+ //
+
+ SourceRouting = SourceRoutingBuffer;
+// RtlMoveMemory (IpxHeader+SourceRoutingLength, IpxHeader, IncludedHeaderLength);
+ }
+
+ } else {
+
+ //
+ // For these packets we assume that the header is in the
+ // right place.
+ //
+
+ if (!Adapter->SourceRouting) {
+
+ SourceRoutingLength = 0;
+
+ } else {
+
+ if (DestinationType == DESTINATION_BCAST) {
+
+ if (Binding->AllRouteBroadcast) {
+ SourceRouting = AllRouteSourceRouting;
+ } else {
+ SourceRouting = SingleRouteSourceRouting;
+ }
+ SourceRoutingLength = 2;
+
+ } else {
+
+ CTEAssert (DestinationType == DESTINATION_MCAST);
+
+ if (Binding->AllRouteMulticast) {
+ SourceRouting = AllRouteSourceRouting;
+ } else {
+ SourceRouting = SingleRouteSourceRouting;
+ }
+ SourceRoutingLength = 2;
+
+ }
+ }
+
+#if 0
+ if (SourceRoutingLength != 0) {
+
+ PUCHAR IpxHeader = Header + Binding->BcMcHeaderSize;
+
+ //
+ // Need to slide the header down to accomodate the SR.
+ //
+
+ RtlMoveMemory (IpxHeader+SourceRoutingLength, IpxHeader, IncludedHeaderLength);
+ }
+#endif
+ }
+
+ Header[0] = TR_PREAMBLE_AC;
+ Header[1] = TR_PREAMBLE_FC;
+ RtlCopyMemory (Header+2, LocalTarget->MacAddress, 6);
+ RtlCopyMemory (Header+8, Adapter->LocalMacAddress.Address, 6);
+
+ if (SourceRoutingLength != 0) {
+ Header[8] |= TR_SOURCE_ROUTE_FLAG;
+ RtlCopyMemory (Header+14, SourceRouting, SourceRoutingLength);
+ }
+
+ Header += (14 + SourceRoutingLength);
+
+ Header[0] = 0xe0;
+ Header[1] = 0xe0;
+ Header[2] = 0x03;
+ HeaderLength = 17;
+
+ //BufferLength = IncludedHeaderLength + HeaderLength + SourceRoutingLength;
+ BufferLength = HeaderLength + SourceRoutingLength;
+
+#if BACK_FILL
+ BACK_FILL_ADJUST_BUFFER_LENGTH(Reserved, BufferLength);
+#else
+ NdisAdjustBufferLength (Reserved->HeaderBuffer, BufferLength);
+#endif
+
+ NdisRecalculatePacketCounts (Packet);
+
+ NdisSend(
+ &Status,
+ Adapter->NdisBindingHandle,
+ Packet);
+
+ return Status;
+
+} /* IpxSendFrame802_5802_2 */
+
+
+NDIS_STATUS
+IpxSendFrame802_5Snap(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs a MAC header in a packet and submits
+ it to the appropriate NDIS driver.
+
+ It is assumed that the first buffer in the packet contains
+ an IPX header at an offset based on the media type. This
+ IPX header is moved around if needed.
+
+ THIS FUNCTION ONLY CONSTRUCT NDISMEDIUM802_5 FRAMES IN
+ THE ISN_FRAME_TYPE_SNAP FORMAT.
+
+Arguments:
+
+ Adapter - The adapter on which we are sending.
+
+ LocalTarget - The local target of the send.
+
+ Packet - The NDIS packet.
+
+ PacketLength - The length of the packet, starting at the IPX header.
+
+ IncludedHeaderLength - The length of the header included in the
+ first buffer that needs to be moved if it does not wind up
+ MacHeaderOffset bytes into the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ PBINDING Binding = Adapter->Bindings[ISN_FRAME_TYPE_SNAP];
+ PUCHAR Header;
+ ULONG HeaderLength;
+ UCHAR SourceRoutingBuffer[18];
+ PUCHAR SourceRouting;
+ ULONG SourceRoutingLength;
+ NDIS_STATUS Status;
+ ULONG BufferLength;
+ UCHAR DestinationType;
+
+ Header = Reserved->Header;
+
+#if BACK_FILL
+ BACK_FILL_HEADER(Header, Reserved, 22, Packet);
+#endif BACK_FILL
+
+ DestinationType = Reserved->DestinationType;
+
+ if (DestinationType == DESTINATION_DEF) {
+
+ MacLookupSourceRouting(
+ Reserved->Identifier,
+ Binding,
+ LocalTarget->MacAddress,
+ SourceRoutingBuffer,
+ &SourceRoutingLength);
+
+ if (SourceRoutingLength != 0) {
+
+// PUCHAR IpxHeader = Header + Binding->DefHeaderSize;
+
+ //
+ // Need to slide the header down to accomodate the SR.
+ //
+
+ SourceRouting = SourceRoutingBuffer;
+ // RtlMoveMemory (IpxHeader+SourceRoutingLength, IpxHeader, IncludedHeaderLength);
+ }
+
+ } else {
+
+ //
+ // For these packets we assume that the header is in the
+ // right place.
+ //
+
+ if (!Adapter->SourceRouting) {
+
+ SourceRoutingLength = 0;
+
+ } else {
+
+ if (DestinationType == DESTINATION_BCAST) {
+
+ if (Binding->AllRouteBroadcast) {
+ SourceRouting = AllRouteSourceRouting;
+ } else {
+ SourceRouting = SingleRouteSourceRouting;
+ }
+ SourceRoutingLength = 2;
+
+ } else {
+
+ CTEAssert (DestinationType == DESTINATION_MCAST);
+
+ if (Binding->AllRouteMulticast) {
+ SourceRouting = AllRouteSourceRouting;
+ } else {
+ SourceRouting = SingleRouteSourceRouting;
+ }
+ SourceRoutingLength = 2;
+
+ }
+
+ if (SourceRoutingLength != 0) {
+
+ // PUCHAR IpxHeader = Header + Binding->BcMcHeaderSize;
+
+ //
+ // Need to slide the header down to accomodate the SR.
+ //
+
+ // RtlMoveMemory (IpxHeader+SourceRoutingLength, IpxHeader, IncludedHeaderLength);
+ }
+ }
+ }
+
+ Header[0] = TR_PREAMBLE_AC;
+ Header[1] = TR_PREAMBLE_FC;
+ RtlCopyMemory (Header+2, LocalTarget->MacAddress, 6);
+ RtlCopyMemory (Header+8, Adapter->LocalMacAddress.Address, 6);
+
+ if (SourceRoutingLength != 0) {
+ Header[8] |= TR_SOURCE_ROUTE_FLAG;
+ RtlCopyMemory (Header+14, SourceRouting, SourceRoutingLength);
+ }
+
+ Header += (14 + SourceRoutingLength);
+
+ Header[0] = 0xaa;
+ Header[1] = 0xaa;
+ Header[2] = 0x03;
+ Header[3] = 0x00;
+ Header[4] = 0x00;
+ Header[5] = 0x00;
+ *(UNALIGNED USHORT *)(&Header[6]) = Adapter->BindSapNetworkOrder;
+ HeaderLength = 22;
+
+ //BufferLength = IncludedHeaderLength + HeaderLength + SourceRoutingLength;
+ BufferLength = HeaderLength + SourceRoutingLength;
+
+#if BACK_FILL
+ BACK_FILL_ADJUST_BUFFER_LENGTH(Reserved, BufferLength);
+#else
+ NdisAdjustBufferLength (Reserved->HeaderBuffer, BufferLength);
+#endif
+ NdisRecalculatePacketCounts (Packet);
+
+ NdisSend(
+ &Status,
+ Adapter->NdisBindingHandle,
+ Packet);
+
+ return Status;
+
+} /* IpxSendFrame802_5Snap */
+
+
+NDIS_STATUS
+IpxSendFrameFddi802_3(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs a MAC header in a packet and submits
+ it to the appropriate NDIS driver.
+
+ It is assumed that the first buffer in the packet contains
+ an IPX header at an offset based on the media type. This
+ IPX header is moved around if needed.
+
+ THIS FUNCTION ONLY CONSTRUCT NDISMEDIUMFDDI FRAMES IN
+ THE ISN_FRAME_TYPE_802_3 FORMAT.
+
+Arguments:
+
+ Adapter - The adapter on which we are sending.
+
+ LocalTarget - The local target of the send.
+
+ Packet - The NDIS packet.
+
+ PacketLength - The length of the packet, starting at the IPX header.
+
+ IncludedHeaderLength - The length of the header included in the
+ first buffer that needs to be moved if it does not wind up
+ MacHeaderOffset bytes into the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ PUCHAR Header;
+ NDIS_STATUS Status;
+
+ Header = Reserved->Header;
+
+#if BACK_FILL
+ BACK_FILL_HEADER(Header, Reserved, 13, Packet);
+#endif BACK_FILL
+
+ Header[0] = FDDI_HEADER_BYTE;
+ RtlCopyMemory (Header+1, LocalTarget->MacAddress, 6);
+ RtlCopyMemory (Header+7, Adapter->LocalMacAddress.Address, 6);
+
+// NdisAdjustBufferLength (Reserved->HeaderBuffer, IncludedHeaderLength + 13);
+
+#if BACK_FILL
+ BACK_FILL_ADJUST_BUFFER_LENGTH(Reserved, 13);
+#else
+ NdisAdjustBufferLength (Reserved->HeaderBuffer, 13);
+#endif
+
+ NdisRecalculatePacketCounts (Packet);
+
+ NdisSend(
+ &Status,
+ Adapter->NdisBindingHandle,
+ Packet);
+
+ return Status;
+
+} /* IpxSendFrameFddi802_3 */
+
+
+NDIS_STATUS
+IpxSendFrameFddi802_2(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs a MAC header in a packet and submits
+ it to the appropriate NDIS driver.
+
+ It is assumed that the first buffer in the packet contains
+ an IPX header at an offset based on the media type. This
+ IPX header is moved around if needed.
+
+ THIS FUNCTION ONLY CONSTRUCT NDISMEDIUMFDDI FRAMES IN
+ THE ISN_FRAME_TYPE_802_2 FORMAT.
+
+Arguments:
+
+ Adapter - The adapter on which we are sending.
+
+ LocalTarget - The local target of the send.
+
+ Packet - The NDIS packet.
+
+ PacketLength - The length of the packet, starting at the IPX header.
+
+ IncludedHeaderLength - The length of the header included in the
+ first buffer that needs to be moved if it does not wind up
+ MacHeaderOffset bytes into the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ PUCHAR Header;
+ NDIS_STATUS Status;
+
+ Header = Reserved->Header;
+
+#if BACK_FILL
+ BACK_FILL_HEADER(Header, Reserved, 16, Packet);
+#endif BACK_FILL
+
+ Header[0] = FDDI_HEADER_BYTE;
+ RtlCopyMemory (Header+1, LocalTarget->MacAddress, 6);
+ RtlCopyMemory (Header+7, Adapter->LocalMacAddress.Address, 6);
+
+ Header[13] = 0xe0;
+ Header[14] = 0xe0;
+ Header[15] = 0x03;
+
+// NdisAdjustBufferLength (Reserved->HeaderBuffer, IncludedHeaderLength + 16);
+
+#if BACK_FILL
+ BACK_FILL_ADJUST_BUFFER_LENGTH(Reserved, 16);
+#else
+ NdisAdjustBufferLength (Reserved->HeaderBuffer, 16);
+#endif
+
+ NdisRecalculatePacketCounts (Packet);
+
+ NdisSend(
+ &Status,
+ Adapter->NdisBindingHandle,
+ Packet);
+
+ return Status;
+
+} /* IpxSendFrameFddi802_2 */
+
+
+NDIS_STATUS
+IpxSendFrameFddiSnap(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs a MAC header in a packet and submits
+ it to the appropriate NDIS driver.
+
+ It is assumed that the first buffer in the packet contains
+ an IPX header at an offset based on the media type. This
+ IPX header is moved around if needed.
+
+ THIS FUNCTION ONLY CONSTRUCT NDISMEDIUMFDDI FRAMES IN
+ THE ISN_FRAME_TYPE_SNAP FORMAT.
+
+Arguments:
+
+ Adapter - The adapter on which we are sending.
+
+ LocalTarget - The local target of the send.
+
+ Packet - The NDIS packet.
+
+ PacketLength - The length of the packet, starting at the IPX header.
+
+ IncludedHeaderLength - The length of the header included in the
+ first buffer that needs to be moved if it does not wind up
+ MacHeaderOffset bytes into the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ PUCHAR Header;
+ NDIS_STATUS Status;
+
+ Header = Reserved->Header;
+
+#if BACK_FILL
+ BACK_FILL_HEADER(Header, Reserved, 21, Packet);
+#endif BACK_FILL
+
+ Header[0] = FDDI_HEADER_BYTE;
+ RtlCopyMemory (Header+1, LocalTarget->MacAddress, 6);
+ RtlCopyMemory (Header+7, Adapter->LocalMacAddress.Address, 6);
+
+ Header[13] = 0xaa;
+ Header[14] = 0xaa;
+ Header[15] = 0x03;
+ Header[16] = 0x00;
+ Header[17] = 0x00;
+ Header[18] = 0x00;
+ *(UNALIGNED USHORT *)(&Header[19]) = Adapter->BindSapNetworkOrder;
+
+// NdisAdjustBufferLength (Reserved->HeaderBuffer, IncludedHeaderLength + 21);
+
+#if BACK_FILL
+ BACK_FILL_ADJUST_BUFFER_LENGTH(Reserved, 21);
+#else
+ NdisAdjustBufferLength (Reserved->HeaderBuffer, 21);
+#endif
+
+ NdisRecalculatePacketCounts (Packet);
+
+ NdisSend(
+ &Status,
+ Adapter->NdisBindingHandle,
+ Packet);
+
+ return Status;
+
+} /* IpxSendFrameFddiSnap */
+
+
+NDIS_STATUS
+IpxSendFrameArcnet878_2(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs a MAC header in a packet and submits
+ it to the appropriate NDIS driver.
+
+ It is assumed that the first buffer in the packet contains
+ an IPX header at an offset based on the media type. This
+ IPX header is moved around if needed.
+
+ THIS FUNCTION ONLY CONSTRUCT NDISMEDIUMARCNET878_2 FRAMES IN
+ THE ISN_FRAME_TYPE_802_2 FORMAT.
+
+Arguments:
+
+ Adapter - The adapter on which we are sending.
+
+ LocalTarget - The local target of the send.
+
+ Packet - The NDIS packet.
+
+ PacketLength - The length of the packet, starting at the IPX header.
+
+ IncludedHeaderLength - The length of the header included in the
+ first buffer that needs to be moved if it does not wind up
+ MacHeaderOffset bytes into the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ PUCHAR Header;
+ NDIS_STATUS Status;
+
+ Header = Reserved->Header;
+
+#if BACK_FILL
+ BACK_FILL_HEADER(Header, Reserved, 3, Packet);
+#endif BACK_FILL
+ //
+ // Convert broadcast address to 0 (the arcnet broadcast).
+ //
+
+ Header[0] = Adapter->LocalMacAddress.Address[5];
+ if (LocalTarget->MacAddress[5] == 0xff) {
+ Header[1] = 0x00;
+ } else {
+ Header[1] = LocalTarget->MacAddress[5];
+ }
+ Header[2] = ARCNET_PROTOCOL_ID;
+
+// NdisAdjustBufferLength (Reserved->HeaderBuffer, IncludedHeaderLength + 3);
+
+#if BACK_FILL
+ BACK_FILL_ADJUST_BUFFER_LENGTH(Reserved, 3);
+#else
+ NdisAdjustBufferLength (Reserved->HeaderBuffer, 3);
+#endif
+
+ NdisRecalculatePacketCounts (Packet);
+
+ NdisSend(
+ &Status,
+ Adapter->NdisBindingHandle,
+ Packet);
+
+ return Status;
+
+} /* IpxSendFrameFddiArcnet878_2 */
+
+
+NDIS_STATUS
+IpxSendFrameWanEthernetII(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs a MAC header in a packet and submits
+ it to the appropriate NDIS driver.
+
+ It is assumed that the first buffer in the packet contains
+ an IPX header at an offset based on the media type. This
+ IPX header is moved around if needed.
+
+ THIS FUNCTION ONLY CONSTRUCT NDISMEDIUMWAN FRAMES IN
+ THE ISN_FRAME_TYPE_ETHERNET_II FORMAT.
+
+Arguments:
+
+ Adapter - The adapter on which we are sending.
+
+ LocalTarget - The local target of the send.
+
+ Packet - The NDIS packet.
+
+ PacketLength - The length of the packet, starting at the IPX header.
+
+ IncludedHeaderLength - The length of the header included in the
+ first buffer that needs to be moved if it does not wind up
+ MacHeaderOffset bytes into the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ PUCHAR Header;
+ NDIS_STATUS Status;
+
+#ifdef _PNP_POWER
+ PBINDING Binding;
+
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+ IPX_GET_LOCK1(&IpxDevice->BindAccessLock, &LockHandle1);
+ Binding = NIC_ID_TO_BINDING(IpxDevice, NIC_FROM_LOCAL_TARGET(LocalTarget));
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+
+ IPX_FREE_LOCK1(&IpxDevice->BindAccessLock, LockHandle1);
+
+#else
+ PBINDING Binding = IpxDevice->Bindings[LocalTarget->NicId];
+#endif _PNP_POWER
+
+ if (Binding->LineUp) {
+
+ Header = Reserved->Header;
+
+#if BACK_FILL
+ BACK_FILL_HEADER(Header, Reserved, 14, Packet);
+
+ //
+ // Call UpdateWanInactivity only if this is not a backfill packet, since
+ // SMB server does not do KeepAlives. In case, of backfilled packets, reset
+ // the counter regardless.
+ //
+ if (!Reserved->BackFill) {
+ IpxUpdateWanInactivityCounter(
+ Binding,
+ (IPX_HEADER UNALIGNED *)(Header + IpxDevice->IncludedHeaderOffset),
+ IncludedHeaderLength,
+ Packet,
+ PacketLength);
+ } else {
+ Binding->WanInactivityCounter = 0;
+ }
+
+#else
+ //
+ // We do checks to see if we should reset the inactivity
+ // counter. We normally need to check for netbios
+ // session alives, packets from rip, packets from
+ // sap, and ncp keep alives. In fact netbios packets
+ // and rip packets don't come through here.
+ //
+
+ IpxUpdateWanInactivityCounter(
+ Binding,
+ (IPX_HEADER UNALIGNED *)(Header + IpxDevice->IncludedHeaderOffset),
+ IncludedHeaderLength,
+ Packet,
+ PacketLength);
+#endif BACK_FILL
+
+ RtlCopyMemory (Header, Binding->RemoteMacAddress.Address, 6);
+ RtlCopyMemory (Header+6, Binding->LocalMacAddress.Address, 6);
+
+ *(UNALIGNED USHORT *)(&Header[12]) = Adapter->BindSapNetworkOrder;
+
+// NdisAdjustBufferLength (Reserved->HeaderBuffer, IncludedHeaderLength + 14);
+
+#if BACK_FILL
+ BACK_FILL_ADJUST_BUFFER_LENGTH(Reserved, 14);
+#else
+ NdisAdjustBufferLength (Reserved->HeaderBuffer, 14);
+#endif
+ NdisRecalculatePacketCounts (Packet);
+
+ NdisSend(
+ &Status,
+ Adapter->NdisBindingHandle,
+ Packet);
+#ifdef _PNP_POWER
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif
+ return Status;
+
+ } else {
+
+ //
+ // Bug #17273 return proper error message
+ //
+
+ // return STATUS_DEVICE_DOES_NOT_EXIST;
+
+#ifdef _PNP_POWER
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif
+ return STATUS_NETWORK_UNREACHABLE;
+ }
+
+} /* IpxSendFrameWanEthernetII */
+
+
+VOID
+MacUpdateSourceRouting(
+ IN ULONG Database,
+ IN PADAPTER Adapter,
+ IN PUCHAR MacHeader,
+ IN ULONG MacHeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when a valid IPX frame is received from
+ a remote. It gives the source routing database a change to
+ update itself to include information about this remote.
+
+Arguments:
+
+ Database - The "database" to use (IPX, SPX, NB, RIP).
+
+ Adapter - The adapter the frame was received on.
+
+ MacHeader - The MAC header of the received frame.
+
+ MacHeaderLength - The length of the MAC header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSOURCE_ROUTE Current;
+ ULONG Hash;
+ LONG Result;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+
+ CTEAssert ((Database >= 0) && (Database <= 3));
+
+ //
+ // If this adapter is configured for no source routing, don't
+ // need to do anything.
+ //
+
+ if (!Adapter->SourceRouting) {
+ return;
+ }
+
+ //
+ // See if this source routing is relevant. We don't
+ // care about two-byte source routing since that
+ // indicates it did not cross a router. If there
+ // is nothing in the database, then don't add
+ // this if it is minimal (if it is not, we need
+ // to add it so we will find it on sending).
+ //
+
+ if ((Adapter->SourceRoutingEmpty[Database]) &&
+ (MacHeaderLength <= 16)) {
+ return;
+ }
+
+ IPX_GET_LOCK (&Adapter->Lock, &LockHandle);
+
+ //
+ // Try to find this address in the database.
+ //
+
+ Hash = MacSourceRoutingHash (MacHeader+8);
+ Current = Adapter->SourceRoutingHeads[Database][Hash];
+
+ while (Current != (PSOURCE_ROUTE)NULL) {
+
+ IPX_NODE_COMPARE (MacHeader+8, Current->MacAddress, &Result);
+
+ if (Result == 0) {
+
+ //
+ // We found routing for this node. If the data is the
+ // same as what we have, update the time since used to
+ // prevent aging.
+ //
+
+ if ((Current->SourceRoutingLength == MacHeaderLength-14) &&
+ (RtlEqualMemory (Current->SourceRouting, MacHeader+14, MacHeaderLength-14))) {
+
+ Current->TimeSinceUsed = 0;
+ }
+ IPX_FREE_LOCK (&Adapter->Lock, LockHandle);
+ return;
+
+ } else {
+
+ Current = Current->Next;
+ }
+
+ }
+
+ //
+ // Not found, insert a new node at the front of the list.
+ //
+
+ Current = (PSOURCE_ROUTE)IpxAllocateMemory (SOURCE_ROUTE_SIZE(MacHeaderLength-14), MEMORY_SOURCE_ROUTE, "SourceRouting");
+
+ if (Current == (PSOURCE_ROUTE)NULL) {
+ IPX_FREE_LOCK (&Adapter->Lock, LockHandle);
+ return;
+ }
+
+ Current->Next = Adapter->SourceRoutingHeads[Database][Hash];
+ Adapter->SourceRoutingHeads[Database][Hash] = Current;
+
+ Adapter->SourceRoutingEmpty[Database] = FALSE;
+
+ RtlCopyMemory (Current->MacAddress, MacHeader+8, 6);
+ Current->MacAddress[0] &= 0x7f;
+ Current->SourceRoutingLength = (UCHAR)(MacHeaderLength - 14);
+ RtlCopyMemory (Current->SourceRouting, MacHeader+14, MacHeaderLength - 14);
+
+ Current->TimeSinceUsed = 0;
+
+ IPX_DEBUG (SOURCE_ROUTE, ("Adding source route %lx for %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x\n",
+ Current, Current->MacAddress[0], Current->MacAddress[1],
+ Current->MacAddress[2], Current->MacAddress[3],
+ Current->MacAddress[4], Current->MacAddress[5]));
+
+ IPX_FREE_LOCK (&Adapter->Lock, LockHandle);
+
+} /* MacUpdateSourceRouting */
+
+
+VOID
+MacLookupSourceRouting(
+ IN ULONG Database,
+ IN PBINDING Binding,
+ IN UCHAR MacAddress[6],
+ IN OUT UCHAR SourceRouting[18],
+ OUT PULONG SourceRoutingLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine looks up a target address in the adapter's
+ source routing database to see if source routing information
+ needs to be added to the frame.
+
+Arguments:
+
+ Database - The "database" to use (IPX, SPX, NB, RIP).
+
+ Binding - The binding the frame is being sent on.
+
+ MacAddress - The destination address.
+
+ SourceRouting - Buffer to hold the returned source routing info.
+
+ SourceRoutingLength - The returned source routing length.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSOURCE_ROUTE Current;
+ PADAPTER Adapter = Binding->Adapter;
+ ULONG Hash;
+ LONG Result;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+
+
+ //
+ // If this adapter is configured for no source routing, don't
+ // insert any.
+ //
+
+ if (!Adapter->SourceRouting) {
+ *SourceRoutingLength = 0;
+ return;
+ }
+
+ //
+ // See if source routing has not been important so far.
+ //
+ // BUGBUG: This is wrong because we may be sending a directed
+ // packet to somebody on the other side of a router, without
+ // ever having received a routed packet. We fix this for the
+ // moment by only setting SourceRoutingEmpty for netbios
+ // which uses broadcasts for discovery.
+ //
+
+ if (Adapter->SourceRoutingEmpty[Database]) {
+ *SourceRoutingLength = 0;
+ return;
+ }
+
+ Hash = MacSourceRoutingHash (MacAddress);
+
+ IPX_GET_LOCK (&Adapter->Lock, &LockHandle);
+ Current = Adapter->SourceRoutingHeads[Database][Hash];
+
+ while (Current != (PSOURCE_ROUTE)NULL) {
+
+ IPX_NODE_COMPARE (MacAddress, Current->MacAddress, &Result);
+
+ if (Result == 0) {
+
+ //
+ // We found routing for this node.
+ //
+
+ if (Current->SourceRoutingLength <= 2) {
+ *SourceRoutingLength = 0;
+ } else {
+ RtlCopyMemory (SourceRouting, Current->SourceRouting, Current->SourceRoutingLength);
+ SourceRouting[0] = (SourceRouting[0] & TR_LENGTH_MASK);
+ SourceRouting[1] = (SourceRouting[1] ^ TR_DIRECTION_MASK);
+ *SourceRoutingLength = Current->SourceRoutingLength;
+ }
+ IPX_FREE_LOCK (&Adapter->Lock, LockHandle);
+ return;
+
+ } else {
+
+ Current = Current->Next;
+
+ }
+
+ }
+
+ IPX_FREE_LOCK (&Adapter->Lock, LockHandle);
+
+ //
+ // We did not find this node, use the default.
+ //
+
+ if (Binding->AllRouteDirected) {
+ RtlCopyMemory (SourceRouting, AllRouteSourceRouting, 2);
+ } else {
+ RtlCopyMemory (SourceRouting, SingleRouteSourceRouting, 2);
+ }
+ *SourceRoutingLength = 2;
+
+} /* MacLookupSourceRouting */
+
+
+VOID
+MacSourceRoutingTimeout(
+ CTEEvent * Event,
+ PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when the source routing timer expires.
+ It is called every minute.
+
+Arguments:
+
+ Event - The event used to queue the timer.
+
+ Context - The context, which is the device pointer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = (PDEVICE)Context;
+ PADAPTER Adapter;
+ PBINDING Binding;
+ PSOURCE_ROUTE Current, OldCurrent, Previous;
+ UINT i, j, k;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+
+
+#ifdef _PNP_POWER
+
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+ //
+ // Get a lock on the access path.
+ //
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ ++Device->SourceRoutingTime;
+ {
+ ULONG Index = MIN (Device->MaxBindings, Device->ValidBindings);
+
+ for (i = 1; i <= Index; i++) {
+
+ if (Binding = NIC_ID_TO_BINDING(Device, i)) {
+#else
+ ++Device->SourceRoutingTime;
+
+ for (i = 1; i <= Device->ValidBindings; i++) {
+
+ if (Binding = Device->Bindings[i]) {
+#endif _PNP_POWER
+
+ Adapter = Binding->Adapter;
+
+ if (Adapter->LastSourceRoutingTime != Device->SourceRoutingTime) {
+
+ //
+ // We need to scan this adapter's source routing
+ // tree for stale routes. To simplify the scan we
+ // only delete entries that have at least one
+ // child that is NULL.
+ //
+
+ Adapter->LastSourceRoutingTime = Device->SourceRoutingTime;
+
+ for (j = 0; j < IDENTIFIER_TOTAL; j++) {
+
+ for (k = 0; k < SOURCE_ROUTE_HASH_SIZE; k++) {
+
+ if (Adapter->SourceRoutingHeads[j][k] == (PSOURCE_ROUTE)NULL) {
+ continue;
+ }
+
+ IPX_GET_LOCK (&Adapter->Lock, &LockHandle);
+
+ Current = Adapter->SourceRoutingHeads[j][k];
+ Previous = (PSOURCE_ROUTE)NULL;
+
+ while (Current != (PSOURCE_ROUTE)NULL) {
+
+ ++Current->TimeSinceUsed;
+
+ if (Current->TimeSinceUsed >= Device->SourceRouteUsageTime) {
+
+ //
+ // A stale entry needs to be aged.
+ //
+
+ if (Previous) {
+ Previous->Next = Current->Next;
+ } else {
+ Adapter->SourceRoutingHeads[j][k] = Current->Next;
+ }
+
+ OldCurrent = Current;
+ Current = Current->Next;
+
+ IPX_DEBUG (SOURCE_ROUTE, ("Aging out source-route entry %lx\n", OldCurrent));
+ IpxFreeMemory (OldCurrent, SOURCE_ROUTE_SIZE (OldCurrent->SourceRoutingLength), MEMORY_SOURCE_ROUTE, "SourceRouting");
+
+ } else {
+
+ Previous = Current;
+ Current = Current->Next;
+ }
+
+ }
+
+ IPX_FREE_LOCK (&Adapter->Lock, LockHandle);
+
+ } // for loop through the database's hash list
+
+ } // for loop through the adapter's four databases
+
+ } // if adapter's database needs to be checked
+
+ } // if binding exists
+
+ } // for loop through every binding
+ }
+
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif _PNP_POWER
+
+ //
+ // Now restart the timer unless we should not (which means
+ // we are being unloaded).
+ //
+
+ if (Device->SourceRoutingUsed) {
+
+ CTEStartTimer(
+ &Device->SourceRoutingTimer,
+ 60000, // one minute timeout
+ MacSourceRoutingTimeout,
+ (PVOID)Device);
+
+ } else {
+
+ IpxDereferenceDevice (Device, DREF_SR_TIMER);
+ }
+
+} /* MacSourceRoutingTimeout */
+
+
+VOID
+MacSourceRoutingRemove(
+ IN PBINDING Binding,
+ IN UCHAR MacAddress[6]
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the IPX action handler when an
+ IPXROUTE use has specified that source routing for a given
+ MAC address should be removed.
+
+Arguments:
+
+ Binding - The binding to modify.
+
+ MacAddress - The MAC address to remove.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PSOURCE_ROUTE Current, Previous;
+ PADAPTER Adapter = Binding->Adapter;
+ ULONG Hash;
+ ULONG Database;
+ LONG Result;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+
+ //
+ // Scan through to find the matching entry in each database.
+ //
+
+ Hash = MacSourceRoutingHash (MacAddress);
+
+ IPX_GET_LOCK (&Adapter->Lock, &LockHandle);
+
+ for (Database = 0; Database < IDENTIFIER_TOTAL; Database++) {
+
+ Current = Adapter->SourceRoutingHeads[Database][Hash];
+ Previous = NULL;
+
+ while (Current != (PSOURCE_ROUTE)NULL) {
+
+ IPX_NODE_COMPARE (MacAddress, Current->MacAddress, &Result);
+
+ if (Result == 0) {
+
+ if (Previous) {
+ Previous->Next = Current->Next;
+ } else {
+ Adapter->SourceRoutingHeads[Database][Hash] = Current->Next;
+ }
+
+ IPX_DEBUG (SOURCE_ROUTE, ("IPXROUTE freeing source-route entry %lx\n", Current));
+ IpxFreeMemory (Current, SOURCE_ROUTE_SIZE (Current->SourceRoutingLength), MEMORY_SOURCE_ROUTE, "SourceRouting");
+
+ break;
+
+ } else {
+
+ Previous = Current;
+ Current = Current->Next;
+
+ }
+
+ }
+
+ }
+
+ IPX_FREE_LOCK (&Adapter->Lock, LockHandle);
+
+} /* MacSourceRoutingRemove */
+
+
+VOID
+MacSourceRoutingClear(
+ IN PBINDING Binding
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the IPX action handler when an
+ IPXROUTE use has specified that source routing for a given
+ binding should be cleared entirely.
+
+Arguments:
+
+ Binding - The binding to be cleared.
+
+ MacAddress - The MAC address to remove.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSOURCE_ROUTE Current;
+ PADAPTER Adapter = Binding->Adapter;
+ ULONG Database, Hash;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+
+ //
+ // Scan through and remove every entry in the database.
+ //
+
+ IPX_GET_LOCK (&Adapter->Lock, &LockHandle);
+
+ for (Database = 0; Database < IDENTIFIER_TOTAL; Database++) {
+
+ for (Hash = 0; Hash < SOURCE_ROUTE_HASH_SIZE; Hash++) {
+
+ while (Adapter->SourceRoutingHeads[Database][Hash]) {
+
+ Current = Adapter->SourceRoutingHeads[Database][Hash];
+ Adapter->SourceRoutingHeads[Database][Hash] = Current->Next;
+
+ IpxFreeMemory (Current, SOURCE_ROUTE_SIZE (Current->SourceRoutingLength), MEMORY_SOURCE_ROUTE, "SourceRouting");
+
+ }
+ }
+ }
+
+ IPX_FREE_LOCK (&Adapter->Lock, LockHandle);
+
+} /* MacSourceRoutingClear */
+
+
+
diff --git a/private/ntos/tdi/isnp/ipx/mac.h b/private/ntos/tdi/isnp/ipx/mac.h
new file mode 100644
index 000000000..a88e77ecd
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/mac.h
@@ -0,0 +1,44 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ mac.h
+
+Abstract:
+
+ This header file defines manifest constants and necessary macros for use
+ by transports dealing with multiple MAC cards through the NDIS interface.
+
+Revision History:
+
+--*/
+
+
+//
+// We need this to define information about the MAC. Note that
+// it is a strange structure in that the first four elements
+// are for use internally by the mac.c routines, while the
+// DeviceContext knows about and uses the last two.
+//
+
+typedef struct _NDIS_INFORMATION {
+
+ NDIS_MEDIUM MediumType;
+ NDIS_MEDIUM RealMediumType;
+ BOOLEAN SourceRouting;
+ BOOLEAN MediumAsync;
+ UCHAR BroadcastMask;
+ ULONG CopyLookahead;
+ ULONG MacOptions;
+ ULONG MinHeaderLength;
+ ULONG MaxHeaderLength;
+
+} NDIS_INFORMATION, * PNDIS_INFORMATION;
+
+
+#define TR_SOURCE_ROUTE_FLAG 0x80
+
+#define ARCNET_PROTOCOL_ID 0xFA
+
diff --git a/private/ntos/tdi/isnp/ipx/mp/makefile b/private/ntos/tdi/isnp/ipx/mp/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/mp/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/tdi/isnp/ipx/mp/nwlnkipx.prf b/private/ntos/tdi/isnp/ipx/mp/nwlnkipx.prf
new file mode 100644
index 000000000..0c4359235
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/mp/nwlnkipx.prf
@@ -0,0 +1,89 @@
+IpxTdiSendDatagram@8
+IpxReceiveIndicationNew@36
+IpxSendFrame@16
+IpxReceiveComplete@4
+IpxSendFrame802_3802_2@20
+IpxReceivePacket@8
+IpxDerefAddressSync@4
+IpxSendComplete@12
+IpxSendFramePreFwd@16
+IpxReceiveIndication@28
+IpxInitializeBackFillPacket@12
+IpxpAllocateMemory@12
+IpxPopBackFillPacket@4
+IpxAllocateBackFillPool@4
+RipLongTimeout@8
+CTEStartTimer@16
+TdiCopyBufferToMdl@24
+IpxTdiQueryInformation@8
+IpxVerifyAddressFile@4
+IpxDispatchInternal@8
+IpxTransferData@28
+IpxInitLoopback@0
+RipGetFirstRoute@4
+IpxCreateAddress@8
+MacReturnMaxDataSize@20
+IpxLookupAddress@8
+IpxAbortLineChanges@4
+MacMapFrameType@12
+IpxInitializeReceiveBuffer@16
+IpxDispatchOpenClose@8
+IpxTdiSetEventHandler@4
+IpxCreateAddressFile@4
+IpxInternalBind@8
+IpxInitializeReceivePacket@8
+IpxIsAddressLocal@4
+IpxOpenAddress@8
+IpxAllocateReceiveBufferPool@4
+IpxSubmitNdisRequest@12
+IpxAddBroadcast@4
+IpxDestroyBinding@4
+RipAdjustForBindingChange@12
+IpxDispatchDeviceControl@8
+IpxAllocatePaddingBuffer@4
+TdiMapUserRequest@12
+CTEInitialize@0
+IpxInitializeSendPacket@12
+IpxpFreeMemory@12
+IpxInitializePaddingBuffer@12
+IpxAllocateSendPool@4
+RipCleanupPacket@8
+TdiRegisterDeviceObject@8
+TdiRegisterNetAddress@8
+IpxTdiAction@8
+IpxCreateBinding@20
+IpxDerefDevice@4
+MacInitializeBindingInfo@8
+IpxRegisterProtocol@4
+IpxInitializeNdis@8
+IpxGetConfigValue@24
+IpxCreateAdapter@12
+IpxResolveBindingSets@8
+IpxGetFrameType@24
+MacInitializeMacInfo@8
+IpxGetBindingValue@24
+RipQueueRequest@8
+RipShortTimeout@8
+IpxPopSendPacket@4
+IpxAllocateBindingPool@4
+IpxInternalQuery@20
+CTEInitTimer@4
+IpxRequestComplete@12
+IpxBroadcastOperation@4
+CTEInitEvent@8
+IpxPnPGetVirtualNetworkNumber@4
+IpxPnPGetAdapterParameters@12
+IpxOpenAdapterComplete@12
+IpxResolveAutoDetect@16
+IpxBindToAdapter@16
+TdiInitialize@0
+IpxPnPIsnIndicate@4
+IpxPnPUpdateBindingArray@12
+IpxBindAdapter@20
+IpxPnPUpdateDevice@4
+IpxGetConfiguration@12
+IpxAddExport@24
+IpxCreateDevice@16
+DriverEntry@8
+IpxReadLinkageInformation@4
+IpxFreeConfiguration@4
diff --git a/private/ntos/tdi/isnp/ipx/mp/sources b/private/ntos/tdi/isnp/ipx/mp/sources
new file mode 100644
index 000000000..dc48d81bb
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/mp/sources
@@ -0,0 +1,29 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+NT_UP=0
+
+TARGETPATH=\nt\public\sdk\lib
+
+!include ..\sources.inc
diff --git a/private/ntos/tdi/isnp/ipx/ndis.c b/private/ntos/tdi/isnp/ipx/ndis.c
new file mode 100644
index 000000000..14066a786
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/ndis.c
@@ -0,0 +1,2204 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ ndis.c
+
+Abstract:
+
+ This module contains code which implements the routines used to
+ initialize the IPX <-> NDIS interface, as well as most of the
+ interface routines.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) 3-Oct-1995
+ Changes to support transfer of buffer ownership to transports
+ 1. Added the ReceivePacketHandler to the ProtChars.
+
+ Sanjay Anand (SanjayAn) 27-Oct-1995
+ Changes to support Plug and Play (in _PNP_POWER)
+
+ Tony Bell (TonyBe) 10-Dec-1995
+ Changes to support new NdisWan Lineup.
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+//
+// This is a one-per-driver variable used in binding
+// to the NDIS interface.
+//
+
+NDIS_HANDLE IpxNdisProtocolHandle = (NDIS_HANDLE)NULL;
+
+NDIS_STATUS
+IpxSubmitNdisRequest(
+ IN PADAPTER Adapter,
+ IN PNDIS_REQUEST NdisRequest,
+ IN PNDIS_STRING AdapterString
+ );
+
+#ifndef _PNP_POWER
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,IpxRegisterProtocol)
+#pragma alloc_text(INIT,IpxInitializeNdis)
+#endif
+#endif
+
+
+NTSTATUS
+IpxRegisterProtocol(
+ IN PNDIS_STRING NameString
+ )
+
+/*++
+
+Routine Description:
+
+ This routine introduces this transport to the NDIS interface.
+
+Arguments:
+
+ NameString - The name of the transport.
+
+Return Value:
+
+ The function value is the status of the operation.
+ STATUS_SUCCESS if all goes well,
+ Failure status if we tried to register and couldn't,
+ STATUS_INSUFFICIENT_RESOURCES if we couldn't even try to register.
+
+--*/
+
+{
+ NDIS_STATUS ndisStatus;
+
+ NDIS_PROTOCOL_CHARACTERISTICS ProtChars; // Used temporarily to register
+
+
+ //
+ // Set up the characteristics of this protocol
+ //
+#if NDIS40
+ ProtChars.MajorNdisVersion = 4;
+
+ ProtChars.ReceivePacketHandler = IpxReceivePacket;
+#else
+ ProtChars.MajorNdisVersion = 3;
+#endif
+ ProtChars.MinorNdisVersion = 0;
+
+ ProtChars.Name = *NameString;
+
+ ProtChars.OpenAdapterCompleteHandler = IpxOpenAdapterComplete;
+ ProtChars.CloseAdapterCompleteHandler = IpxCloseAdapterComplete;
+ ProtChars.ResetCompleteHandler = IpxResetComplete;
+ ProtChars.RequestCompleteHandler = IpxRequestComplete;
+
+ ProtChars.SendCompleteHandler = IpxSendComplete;
+ ProtChars.TransferDataCompleteHandler = IpxTransferDataComplete;
+
+ ProtChars.ReceiveHandler = IpxReceiveIndication;
+ ProtChars.ReceiveCompleteHandler = IpxReceiveComplete;
+ ProtChars.StatusHandler = IpxStatus;
+ ProtChars.StatusCompleteHandler = IpxStatusComplete;
+
+#ifdef _PNP_POWER
+ ProtChars.BindAdapterHandler = IpxBindAdapter;
+ ProtChars.UnbindAdapterHandler = IpxUnbindAdapter;
+ ProtChars.TranslateHandler = IpxTranslate;
+#endif // _PNP_POWER
+
+ NdisRegisterProtocol (
+ &ndisStatus,
+ &IpxNdisProtocolHandle,
+ &ProtChars,
+ (UINT)sizeof(NDIS_PROTOCOL_CHARACTERISTICS) + NameString->Length);
+
+ if (ndisStatus != NDIS_STATUS_SUCCESS) {
+ return (NTSTATUS)ndisStatus;
+ }
+
+ return STATUS_SUCCESS;
+
+} /* IpxRegisterProtocol */
+
+
+VOID
+IpxDeregisterProtocol (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine removes this transport to the NDIS interface.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NDIS_STATUS ndisStatus;
+
+ if (IpxNdisProtocolHandle != (NDIS_HANDLE)NULL) {
+ NdisDeregisterProtocol (
+ &ndisStatus,
+ IpxNdisProtocolHandle);
+ IpxNdisProtocolHandle = (NDIS_HANDLE)NULL;
+ }
+
+} /* IpxDeregisterProtocol */
+
+
+NDIS_STATUS
+IpxSubmitNdisRequest(
+ IN PADAPTER Adapter,
+ IN PNDIS_REQUEST NdisRequest,
+ IN PNDIS_STRING AdapterString
+ )
+
+/*++
+
+Routine Description:
+
+ This routine passed an NDIS_REQUEST to the MAC and waits
+ until it has completed before returning the final status.
+
+Arguments:
+
+ Adapter - Pointer to the device context for this driver.
+
+ NdisRequest - Pointer to the NDIS_REQUEST to submit.
+
+ AdapterString - The name of the adapter, in case an error needs
+ to be logged.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+ NDIS_STATUS NdisStatus;
+
+ NdisRequest(
+ &NdisStatus,
+ Adapter->NdisBindingHandle,
+ NdisRequest);
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ KeWaitForSingleObject(
+ &Adapter->NdisRequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+
+ NdisStatus = Adapter->NdisRequestStatus;
+
+ KeResetEvent(
+ &Adapter->NdisRequestEvent
+ );
+
+ }
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ IPX_DEBUG (NDIS, ("%s on OID %8.8lx failed %lx\n",
+ NdisRequest->RequestType == NdisRequestSetInformation ? "Set" : "Query",
+ NdisRequest->DATA.QUERY_INFORMATION.Oid,
+ NdisStatus));
+
+ IpxWriteOidErrorLog(
+ Adapter->Device->DeviceObject,
+ NdisRequest->RequestType == NdisRequestSetInformation ?
+ EVENT_TRANSPORT_SET_OID_FAILED : EVENT_TRANSPORT_QUERY_OID_FAILED,
+ NdisStatus,
+ AdapterString->Buffer,
+ NdisRequest->DATA.QUERY_INFORMATION.Oid);
+
+ } else {
+
+ IPX_DEBUG (NDIS, ("%s on OID %8.8lx succeeded\n",
+ NdisRequest->RequestType == NdisRequestSetInformation ? "Set" : "Query",
+ NdisRequest->DATA.QUERY_INFORMATION.Oid));
+ }
+
+ return NdisStatus;
+
+} /* IpxSubmitNdisRequest */
+
+
+NTSTATUS
+IpxInitializeNdis(
+ IN PADAPTER Adapter,
+ IN PBINDING_CONFIG ConfigBinding
+ )
+
+/*++
+
+Routine Description:
+
+ This routine introduces this transport to the NDIS interface and sets up
+ any necessary NDIS data structures (Buffer pools and such). It will be
+ called for each adapter opened by this transport.
+
+Arguments:
+
+ Adapter - Structure describing this binding.
+
+ ConfigAdapter - Configuration information for this binding.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ NDIS_STATUS NdisStatus;
+ NDIS_STATUS OpenErrorStatus;
+ NDIS_MEDIUM IpxSupportedMedia[] = { NdisMedium802_3, NdisMedium802_5, NdisMediumFddi, NdisMediumArcnet878_2, NdisMediumWan };
+ UINT SelectedMedium;
+ NDIS_REQUEST IpxRequest;
+ ULONG MinimumLookahead;
+ UCHAR WanProtocolId[6] = { 0x80, 0x00, 0x00, 0x00, 0x81, 0x37 };
+ UCHAR FunctionalAddress[4] = { 0x00, 0x80, 0x00, 0x00 };
+ ULONG WanHeaderFormat = NdisWanHeaderEthernet;
+ NDIS_OID IpxOid;
+ ULONG MacOptions;
+ ULONG PacketFilter;
+ PNDIS_STRING AdapterString = &ConfigBinding->AdapterName;
+
+ //
+ // Initialize this adapter for IPX use through NDIS
+ //
+
+ //
+ // This event is used in case any of the NDIS requests
+ // pend; we wait until it is set by the completion
+ // routine, which also sets NdisRequestStatus.
+ //
+
+ KeInitializeEvent(
+ &Adapter->NdisRequestEvent,
+ NotificationEvent,
+ FALSE
+ );
+
+ Adapter->NdisBindingHandle = NULL;
+
+ OpenErrorStatus = 0;
+
+ NdisOpenAdapter (
+ &NdisStatus,
+ &OpenErrorStatus,
+ &Adapter->NdisBindingHandle,
+ &SelectedMedium,
+ IpxSupportedMedia,
+ sizeof (IpxSupportedMedia) / sizeof(NDIS_MEDIUM),
+ IpxNdisProtocolHandle,
+ (NDIS_HANDLE)Adapter,
+ &ConfigBinding->AdapterName,
+ 0,
+ NULL);
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ KeWaitForSingleObject(
+ &Adapter->NdisRequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+
+ NdisStatus = Adapter->NdisRequestStatus;
+ OpenErrorStatus = Adapter->OpenErrorStatus;
+
+ KeResetEvent(
+ &Adapter->NdisRequestEvent
+ );
+
+ }
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ IPX_DEBUG (NDIS, ("Open %ws failed %lx\n", ConfigBinding->AdapterName.Buffer, NdisStatus));
+
+ IpxWriteGeneralErrorLog(
+ Adapter->Device->DeviceObject,
+ EVENT_TRANSPORT_ADAPTER_NOT_FOUND,
+ 807,
+ NdisStatus,
+ AdapterString->Buffer,
+ 1,
+ &OpenErrorStatus);
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ } else {
+
+ IPX_DEBUG (NDIS, ("Open %ws succeeded\n", ConfigBinding->AdapterName.Buffer));
+ }
+
+
+ //
+ // Get the information we need about the adapter, based on
+ // the media type.
+ //
+
+ MacInitializeMacInfo(
+ IpxSupportedMedia[SelectedMedium],
+ &Adapter->MacInfo);
+
+
+ switch (Adapter->MacInfo.RealMediumType) {
+
+ case NdisMedium802_3:
+
+ IpxOid = OID_802_3_CURRENT_ADDRESS;
+ break;
+
+ case NdisMedium802_5:
+
+ IpxOid = OID_802_5_CURRENT_ADDRESS;
+ break;
+
+ case NdisMediumFddi:
+
+ IpxOid = OID_FDDI_LONG_CURRENT_ADDR;
+ break;
+
+ case NdisMediumArcnet878_2:
+
+ IpxOid = OID_ARCNET_CURRENT_ADDRESS;
+ break;
+
+ case NdisMediumWan:
+
+ IpxOid = OID_WAN_CURRENT_ADDRESS;
+ break;
+
+ default:
+
+ NdisStatus = NDIS_STATUS_FAILURE;
+ break;
+
+ }
+
+ IpxRequest.RequestType = NdisRequestQueryInformation;
+ IpxRequest.DATA.QUERY_INFORMATION.Oid = IpxOid;
+
+ if (IpxOid != OID_ARCNET_CURRENT_ADDRESS) {
+
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = Adapter->LocalMacAddress.Address;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 6;
+
+ } else {
+
+ //
+ // We take the arcnet single-byte address and right-justify
+ // it in a field of zeros.
+ //
+
+ RtlZeroMemory (Adapter->LocalMacAddress.Address, 5);
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = &Adapter->LocalMacAddress.Address[5];
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 1;
+
+ }
+
+ NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ IpxCloseNdis (Adapter);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // Now query the maximum packet sizes.
+ //
+
+ IpxRequest.RequestType = NdisRequestQueryInformation;
+ IpxRequest.DATA.QUERY_INFORMATION.Oid = OID_GEN_MAXIMUM_FRAME_SIZE;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = &(Adapter->MaxReceivePacketSize);
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ IpxCloseNdis (Adapter);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ IpxRequest.RequestType = NdisRequestQueryInformation;
+ IpxRequest.DATA.QUERY_INFORMATION.Oid = OID_GEN_MAXIMUM_TOTAL_SIZE;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = &(Adapter->MaxSendPacketSize);
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ IpxCloseNdis (Adapter);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // Query the receive buffer space.
+ //
+
+ IpxRequest.RequestType = NdisRequestQueryInformation;
+ IpxRequest.DATA.QUERY_INFORMATION.Oid = OID_GEN_RECEIVE_BUFFER_SPACE;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = &(Adapter->ReceiveBufferSpace);
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ IpxCloseNdis (Adapter);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // Now set the minimum lookahead size. The value we choose
+ // here is the 128 needed for TDI indications, plus the size
+ // of the IPX header, plus the largest extra header possible
+ // (a SNAP header, 8 bytes), plus the largest higher-level
+ // header (I think it is a Netbios datagram, 34 bytes).
+ //
+ // BETABUGBUG: Adapt this based on higher-level bindings and
+ // configured frame types.
+ //
+
+ MinimumLookahead = 128 + sizeof(IPX_HEADER) + 8 + 34;
+ IpxRequest.RequestType = NdisRequestSetInformation;
+ IpxRequest.DATA.QUERY_INFORMATION.Oid = OID_GEN_CURRENT_LOOKAHEAD;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = &MinimumLookahead;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ IpxCloseNdis (Adapter);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // Now query the link speed
+ //
+
+ IpxRequest.RequestType = NdisRequestQueryInformation;
+ IpxRequest.DATA.QUERY_INFORMATION.Oid = OID_GEN_LINK_SPEED;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = &(Adapter->MediumSpeed);
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ IpxCloseNdis (Adapter);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // For wan, specify our protocol ID and header format.
+ // We don't query the medium subtype because we don't
+ // case (since we require ethernet emulation).
+ //
+
+ if (Adapter->MacInfo.MediumAsync) {
+
+ if (Adapter->BindSap != 0x8137) {
+ *(UNALIGNED USHORT *)(&WanProtocolId[4]) = Adapter->BindSapNetworkOrder;
+ }
+ IpxRequest.RequestType = NdisRequestSetInformation;
+ IpxRequest.DATA.QUERY_INFORMATION.Oid = OID_WAN_PROTOCOL_TYPE;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = WanProtocolId;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 6;
+
+ NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ IpxCloseNdis (Adapter);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ IpxRequest.RequestType = NdisRequestSetInformation;
+ IpxRequest.DATA.QUERY_INFORMATION.Oid = OID_WAN_HEADER_FORMAT;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = &WanHeaderFormat;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ IpxCloseNdis (Adapter);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // Now query the line count.
+ //
+
+ IpxRequest.RequestType = NdisRequestQueryInformation;
+ IpxRequest.DATA.QUERY_INFORMATION.Oid = OID_WAN_LINE_COUNT;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = &Adapter->WanNicIdCount;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ Adapter->WanNicIdCount = 1;
+ }
+
+ if (Adapter->WanNicIdCount == 0) {
+
+ IPX_DEBUG (NDIS, ("OID_WAN_LINE_COUNT returned 0 lines\n"));
+
+ IpxWriteOidErrorLog(
+ Adapter->Device->DeviceObject,
+ EVENT_TRANSPORT_QUERY_OID_FAILED,
+ NDIS_STATUS_INVALID_DATA,
+ AdapterString->Buffer,
+ OID_WAN_LINE_COUNT);
+
+ IpxCloseNdis (Adapter);
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ }
+ }
+
+
+ //
+ // For 802.5 adapter's configured that way, we enable the
+ // functional address (C0-00-00-80-00-00).
+ //
+
+ if ((Adapter->MacInfo.MediumType == NdisMedium802_5) &&
+ (Adapter->EnableFunctionalAddress)) {
+
+ //
+ // For token-ring, we pass the last four bytes of the
+ // Netbios functional address.
+ //
+
+ IpxRequest.RequestType = NdisRequestSetInformation;
+ IpxRequest.DATA.QUERY_INFORMATION.Oid = OID_802_5_CURRENT_FUNCTIONAL;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = FunctionalAddress;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ IpxCloseNdis (Adapter);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+
+
+ //
+ // Now query the MAC's optional characteristics.
+ //
+
+ IpxRequest.RequestType = NdisRequestQueryInformation;
+ IpxRequest.DATA.QUERY_INFORMATION.Oid = OID_GEN_MAC_OPTIONS;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = &MacOptions;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ IpxCloseNdis (Adapter);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ Adapter->MacInfo.CopyLookahead =
+ ((MacOptions & NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA) != 0) ?
+ TDI_RECEIVE_COPY_LOOKAHEAD : 0;
+ Adapter->MacInfo.MacOptions = MacOptions;
+
+
+ switch (Adapter->MacInfo.MediumType) {
+
+ case NdisMedium802_3:
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_802_2] = 17;
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_802_3] = 14;
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_ETHERNET_II] = 14;
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_SNAP] = 22;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_802_2] = 17;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_802_3] = 14;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_ETHERNET_II] = 14;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_SNAP] = 22;
+ break;
+
+ case NdisMedium802_5:
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_802_2] = 17;
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_802_3] = 17;
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_ETHERNET_II] = 17;
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_SNAP] = 22;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_802_2] = 17;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_802_3] = 17;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_ETHERNET_II] = 17;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_SNAP] = 22;
+ break;
+
+ case NdisMediumFddi:
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_802_2] = 16;
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_802_3] = 13;
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_ETHERNET_II] = 16;
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_SNAP] = 21;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_802_2] = 16;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_802_3] = 13;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_ETHERNET_II] = 16;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_SNAP] = 21;
+ break;
+
+ case NdisMediumArcnet878_2:
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_802_2] = 3;
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_802_3] = 3;
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_ETHERNET_II] = 3;
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_SNAP] = 3;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_802_2] = 3;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_802_3] = 3;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_ETHERNET_II] = 3;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_SNAP] = 3;
+ break;
+
+ }
+
+ //
+ // BUGBUG: If functional filtering is set, set the address
+ // for the appropriate binding.
+ //
+
+ //
+ // Now that everything is set up, we enable the filter
+ // for packet reception.
+ //
+
+ switch (Adapter->MacInfo.MediumType) {
+
+ case NdisMedium802_3:
+ case NdisMediumFddi:
+ case NdisMedium802_5:
+ case NdisMediumArcnet878_2:
+
+ //
+ // If we have a virtual network number we need to receive
+ // broadcasts (either the router will be bound in which
+ // case we want them, or we need to respond to rip requests
+ // ourselves).
+ //
+
+ PacketFilter = NDIS_PACKET_TYPE_DIRECTED;
+
+ if (Adapter->Device->VirtualNetworkNumber != 0) {
+
+ Adapter->BroadcastEnabled = TRUE;
+ Adapter->Device->EnableBroadcastCount = 1;
+ PacketFilter |= NDIS_PACKET_TYPE_BROADCAST;
+
+ if ((Adapter->MacInfo.MediumType == NdisMedium802_5) && (Adapter->EnableFunctionalAddress)) {
+ PacketFilter |= NDIS_PACKET_TYPE_FUNCTIONAL;
+ }
+
+ } else {
+
+ Adapter->BroadcastEnabled = FALSE;
+ Adapter->Device->EnableBroadcastCount = 0;
+
+ }
+
+ break;
+
+ default:
+
+ CTEAssert (FALSE);
+ break;
+
+ }
+
+ //
+ // Now fill in the NDIS_REQUEST.
+ //
+
+ IpxRequest.RequestType = NdisRequestSetInformation;
+ IpxRequest.DATA.SET_INFORMATION.Oid = OID_GEN_CURRENT_PACKET_FILTER;
+ IpxRequest.DATA.SET_INFORMATION.InformationBuffer = &PacketFilter;
+ IpxRequest.DATA.SET_INFORMATION.InformationBufferLength = sizeof(ULONG);
+
+ NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ IpxCloseNdis (Adapter);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ return STATUS_SUCCESS;
+
+} /* IpxInitializeNdis */
+
+
+VOID
+IpxAddBroadcast(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when another reason for enabling
+ broadcast reception is added. If it is the first, then
+ reception on the card is enabled by queueing a call to
+ IpxBroadcastOperation.
+
+ THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD.
+
+Arguments:
+
+ Device - The IPX device.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ++Device->EnableBroadcastCount;
+
+ if (Device->EnableBroadcastCount == 1) {
+
+ //
+ // Broadcasts should be enabled.
+ //
+
+ if (!Device->EnableBroadcastPending) {
+
+ if (Device->DisableBroadcastPending) {
+ Device->ReverseBroadcastOperation = TRUE;
+ } else {
+ Device->EnableBroadcastPending = TRUE;
+ ExInitializeWorkItem(
+ &Device->BroadcastOperationQueueItem,
+ IpxBroadcastOperation,
+ (PVOID)TRUE);
+ ExQueueWorkItem(&Device->BroadcastOperationQueueItem, DelayedWorkQueue);
+ }
+ }
+ }
+
+} /* IpxAddBroadcast */
+
+
+VOID
+IpxRemoveBroadcast(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when a reason for enabling
+ broadcast reception is removed. If it is the last, then
+ reception on the card is disabled by queueing a call to
+ IpxBroadcastOperation.
+
+ THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD.
+
+Arguments:
+
+ Device - The IPX device.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ --Device->EnableBroadcastCount;
+
+ if (Device->EnableBroadcastCount == 0) {
+
+ //
+ // Broadcasts should be disabled.
+ //
+
+ if (!Device->DisableBroadcastPending) {
+
+ if (Device->EnableBroadcastPending) {
+ Device->ReverseBroadcastOperation = TRUE;
+ } else {
+ Device->DisableBroadcastPending = TRUE;
+ ExInitializeWorkItem(
+ &Device->BroadcastOperationQueueItem,
+ IpxBroadcastOperation,
+ (PVOID)FALSE);
+ ExQueueWorkItem(&Device->BroadcastOperationQueueItem, DelayedWorkQueue);
+ }
+ }
+ }
+
+} /* IpxRemoveBroadcast */
+
+
+VOID
+IpxBroadcastOperation(
+ IN PVOID Parameter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to change whether broadcast reception
+ is enabled or disabled. It performs the requested operation
+ on every adapter bound to by IPX.
+
+ This routine is called by a worker thread queued when a
+ bind/unbind operation changes the broadcast state.
+
+Arguments:
+
+ Parameter - TRUE if broadcasts should be enabled, FALSE
+ if they should be disabled.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = IpxDevice;
+ BOOLEAN Enable = (BOOLEAN)Parameter;
+ UINT i;
+ PBINDING Binding;
+ PADAPTER Adapter;
+ ULONG PacketFilter;
+ NDIS_REQUEST IpxRequest;
+ NDIS_STRING AdapterName;
+ CTELockHandle LockHandle;
+
+#ifdef _PNP_POWER
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ IPX_DEBUG (NDIS, ("%s operation started\n", Enable ? "Enable" : "Disable"));
+
+ {
+ ULONG Index = MIN (Device->MaxBindings, Device->ValidBindings);
+
+ for (i = 1; i <= Index; i++) {
+
+ Binding = NIC_ID_TO_BINDING(Device, i);
+#else
+ IPX_DEBUG (NDIS, ("%s operation started\n", Enable ? "Enable" : "Disable"));
+
+ for (i = 1; i <= Device->ValidBindings; i++) {
+
+ Binding = Device->Bindings[i];
+#endif
+ if (Binding == NULL) {
+ continue;
+ }
+
+ Adapter = Binding->Adapter;
+ if (Adapter->BroadcastEnabled == Enable) {
+ continue;
+ }
+
+ if (Enable) {
+ if ((Adapter->MacInfo.MediumType == NdisMedium802_5) && (Adapter->EnableFunctionalAddress)) {
+ PacketFilter = (NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_BROADCAST | NDIS_PACKET_TYPE_FUNCTIONAL);
+ } else {
+ PacketFilter = (NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_BROADCAST);
+ }
+ } else {
+ PacketFilter = NDIS_PACKET_TYPE_DIRECTED;
+ }
+
+ //
+ // Now fill in the NDIS_REQUEST.
+ //
+
+ IpxRequest.RequestType = NdisRequestSetInformation;
+ IpxRequest.DATA.SET_INFORMATION.Oid = OID_GEN_CURRENT_PACKET_FILTER;
+ IpxRequest.DATA.SET_INFORMATION.InformationBuffer = &PacketFilter;
+ IpxRequest.DATA.SET_INFORMATION.InformationBufferLength = sizeof(ULONG);
+
+ AdapterName.Buffer = Adapter->AdapterName;
+ AdapterName.Length = (USHORT)Adapter->AdapterNameLength;
+ AdapterName.MaximumLength = (USHORT)(Adapter->AdapterNameLength + sizeof(WCHAR));
+
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+
+ (VOID)IpxSubmitNdisRequest (Adapter, &IpxRequest, &AdapterName);
+
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+#endif
+
+ Adapter->BroadcastEnabled = Enable;
+
+ }
+ }
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ if (Enable) {
+
+ CTEAssert (Device->EnableBroadcastPending);
+ Device->EnableBroadcastPending = FALSE;
+
+ if (Device->ReverseBroadcastOperation) {
+ Device->ReverseBroadcastOperation = FALSE;
+ Device->DisableBroadcastPending = TRUE;
+ ExInitializeWorkItem(
+ &Device->BroadcastOperationQueueItem,
+ IpxBroadcastOperation,
+ (PVOID)FALSE);
+ ExQueueWorkItem(&Device->BroadcastOperationQueueItem, DelayedWorkQueue);
+ }
+
+ } else {
+
+ CTEAssert (Device->DisableBroadcastPending);
+ Device->DisableBroadcastPending = FALSE;
+
+ if (Device->ReverseBroadcastOperation) {
+ Device->ReverseBroadcastOperation = FALSE;
+ Device->EnableBroadcastPending = TRUE;
+ ExInitializeWorkItem(
+ &Device->BroadcastOperationQueueItem,
+ IpxBroadcastOperation,
+ (PVOID)TRUE);
+ ExQueueWorkItem(&Device->BroadcastOperationQueueItem, DelayedWorkQueue);
+ }
+
+ }
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+}/* IpxBroadcastOperation */
+
+
+VOID
+IpxCloseNdis(
+ IN PADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine unbinds the transport from the NDIS interface and does
+ any other work required to undo what was done in IpxInitializeNdis.
+ It is written so that it can be called from within IpxInitializeNdis
+ if it fails partway through.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ NDIS_STATUS ndisStatus;
+
+ //
+ // Close the NDIS binding.
+ //
+
+ if (Adapter->NdisBindingHandle != (NDIS_HANDLE)NULL) {
+
+ //
+ // This event is used in case any of the NDIS requests
+ // pend; we wait until it is set by the completion
+ // routine, which also sets NdisRequestStatus.
+ //
+
+ KeInitializeEvent(
+ &Adapter->NdisRequestEvent,
+ NotificationEvent,
+ FALSE
+ );
+
+ NdisCloseAdapter(
+ &ndisStatus,
+ Adapter->NdisBindingHandle);
+
+ if (ndisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ KeWaitForSingleObject(
+ &Adapter->NdisRequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+
+ ndisStatus = Adapter->NdisRequestStatus;
+
+ KeResetEvent(
+ &Adapter->NdisRequestEvent
+ );
+
+ }
+
+ //
+ // We ignore ndisStatus.
+ //
+
+ }
+
+#if 0
+ if (Adapter->SendPacketPoolHandle != NULL) {
+ NdisFreePacketPool (Adapter->SendPacketPoolHandle);
+ }
+
+ if (Adapter->ReceivePacketPoolHandle != NULL) {
+ NdisFreePacketPool (Adapter->ReceivePacketPoolHandle);
+ }
+
+ if (Adapter->NdisBufferPoolHandle != NULL) {
+ NdisFreeBufferPool (Adapter->NdisBufferPoolHandle);
+ }
+#endif
+
+} /* IpxCloseNdis */
+
+
+VOID
+IpxOpenAdapterComplete(
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_STATUS NdisStatus,
+ IN NDIS_STATUS OpenErrorStatus
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by NDIS to indicate that an open adapter
+ is complete. Since we only ever have one outstanding, and then only
+ during initialization, all we do is record the status and set
+ the event to signalled to unblock the initialization thread.
+
+Arguments:
+
+ BindingContext - Pointer to the device object for this driver.
+
+ NdisStatus - The request completion code.
+
+ OpenErrorStatus - More status information.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PADAPTER Adapter = (PADAPTER)BindingContext;
+
+ Adapter->NdisRequestStatus = NdisStatus;
+ Adapter->OpenErrorStatus = OpenErrorStatus;
+
+ KeSetEvent(
+ &Adapter->NdisRequestEvent,
+ 0L,
+ FALSE);
+
+} /* IpxOpenAdapterComplete */
+
+VOID
+IpxCloseAdapterComplete(
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_STATUS NdisStatus
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by NDIS to indicate that a close adapter
+ is complete. Currently we don't close adapters, so this is not
+ a problem.
+
+Arguments:
+
+ BindingContext - Pointer to the device object for this driver.
+
+ NdisStatus - The request completion code.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PADAPTER Adapter = (PADAPTER)BindingContext;
+
+ Adapter->NdisRequestStatus = NdisStatus;
+
+ KeSetEvent(
+ &Adapter->NdisRequestEvent,
+ 0L,
+ FALSE);
+
+} /* IpxCloseAdapterComplete */
+
+
+VOID
+IpxResetComplete(
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_STATUS NdisStatus
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by NDIS to indicate that a reset adapter
+ is complete. Currently we don't reset adapters, so this is not
+ a problem.
+
+Arguments:
+
+ BindingContext - Pointer to the device object for this driver.
+
+ NdisStatus - The request completion code.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER(BindingContext);
+ UNREFERENCED_PARAMETER(NdisStatus);
+
+} /* IpxResetComplete */
+
+
+VOID
+IpxRequestComplete(
+ IN NDIS_HANDLE BindingContext,
+ IN PNDIS_REQUEST NdisRequest,
+ IN NDIS_STATUS NdisStatus
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by NDIS to indicate that a request is complete.
+ Since we only ever have one request outstanding, and then only
+ during initialization, all we do is record the status and set
+ the event to signalled to unblock the initialization thread.
+
+Arguments:
+
+ BindingContext - Pointer to the device object for this driver.
+
+ NdisRequest - The object describing the request.
+
+ NdisStatus - The request completion code.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PADAPTER Adapter = (PADAPTER)BindingContext;
+
+ Adapter->NdisRequestStatus = NdisStatus;
+
+ KeSetEvent(
+ &Adapter->NdisRequestEvent,
+ 0L,
+ FALSE);
+
+} /* IpxRequestComplete */
+
+
+VOID
+IpxStatus(
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_STATUS NdisStatus,
+ IN PVOID StatusBuffer,
+ IN UINT StatusBufferSize
+ )
+
+{
+ PADAPTER Adapter, TmpAdapter;
+
+ PNDIS_WAN_LINE_UP LineUp;
+ PNDIS_WAN_LINE_DOWN LineDown;
+ PIPXCP_CONFIGURATION Configuration; // contains ipx net and node
+
+ BOOLEAN UpdateLineUp;
+ PBINDING Binding, TmpBinding;
+ PDEVICE Device;
+ PADDRESS Address;
+ ULONG CurrentHash;
+ PIPX_ROUTE_ENTRY RouteEntry;
+ PNDIS_BUFFER NdisBuffer;
+ PNWLINK_ACTION NwlinkAction;
+ PIPX_ADDRESS_DATA IpxAddressData;
+ PREQUEST Request;
+ UINT BufferLength;
+ IPX_LINE_INFO LineInfo;
+ ULONG Segment;
+ ULONG LinkSpeed;
+ PLIST_ENTRY p;
+ NTSTATUS Status;
+ UINT i, j;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+ NTSTATUS ntStatus;
+
+#ifdef _PNP_POWER
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+ Adapter = (PADAPTER)NdisBindingContext;
+
+ IpxReferenceAdapter(Adapter);
+#else
+ Adapter = (PADAPTER)NdisBindingContext;
+#endif
+
+ Device = Adapter->Device;
+
+ switch (NdisStatus) {
+
+ case NDIS_STATUS_WAN_LINE_UP:
+
+
+ //
+ // If the line is already up, then we are just getting
+ // a change in line conditions, and the IPXCP_CONFIGURATION
+ // information is not included. If it turns out we need
+ // all the info, we check the size again later.
+ //
+
+ if (StatusBufferSize < sizeof(NDIS_WAN_LINE_UP)) {
+ IPX_DEBUG (WAN, ("Line up, status buffer size wrong %d/%d\n", StatusBufferSize, sizeof(NDIS_WAN_LINE_UP)));
+#ifdef _PNP_POWER
+ goto error_no_lock;
+#else
+ return;
+#endif
+ }
+
+ LineUp = (PNDIS_WAN_LINE_UP)StatusBuffer;
+
+ //
+ // We scan through the adapter's NIC ID range looking
+ // for an active binding with the same remote address.
+ //
+
+ UpdateLineUp = FALSE;
+
+ //
+ // See if this is a new lineup or not
+ //
+ *((ULONG UNALIGNED *)(&Binding)) =
+ *((ULONG UNALIGNED *)(&LineUp->LocalAddress[2]));
+
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+#endif
+
+ if (Binding != NULL) {
+ UpdateLineUp = TRUE;
+ }
+
+ if (LineUp->ProtocolType != Adapter->BindSap) {
+ IPX_DEBUG (WAN, ("Line up, wrong protocol type %lx\n", LineUp->ProtocolType));
+
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ goto error_no_lock;
+#else
+ return;
+#endif
+ }
+
+ Configuration = (PIPXCP_CONFIGURATION)LineUp->ProtocolBuffer;
+
+ //
+ // PNP_POWER - We hold the exclusive lock to the binding array (thru both the device and adapter)
+ // and the reference to the adapter at this point.
+ //
+
+ //
+ // If this line was previously down, create a new binding
+ // if needed.
+ //
+
+ if (!UpdateLineUp) {
+
+ //
+ // We look for a binding that is allocated but down, if
+ // we can't find that then we look for any empty spot in
+ // the adapter's NIC ID range and allocate a binding in it.
+ // Since we always allocate this way, the allocated
+ // bindings are all clumped at the beginning and once
+ // we find a NULL spot we know there are no more
+ // allocated ones.
+ //
+ // We keep track of the first binding on this adapter
+ // in TmpBinding in case we need config info from it.
+ //
+
+ TmpBinding = NULL;
+
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+
+ for (i = Adapter->FirstWanNicId;
+ i <= Adapter->LastWanNicId;
+ i++) {
+#ifdef _PNP_POWER
+ Binding = NIC_ID_TO_BINDING(Device, i);
+#else
+ Binding = Device->Bindings[i];
+#endif
+ if (TmpBinding == NULL) {
+ TmpBinding = Binding;
+ }
+
+ if ((Binding == NULL) ||
+ (!Binding->LineUp)) {
+ break;
+ }
+ }
+
+ if (i > Adapter->LastWanNicId) {
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ IPX_DEBUG (WAN, ("Line up, no WAN binding available\n"));
+ return;
+ }
+
+ if (Binding == NULL) {
+
+ //
+ // We need to allocate one.
+ //
+
+ CTEAssert (TmpBinding != NULL);
+
+#ifdef _PNP_POWER
+ //
+ // CreateBinding does an InterLockedPop with the DeviceLock.
+ // So, release the lock here.
+ //
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+#endif
+ Status = IpxCreateBinding(
+ Device,
+ NULL,
+ 0,
+ Adapter->AdapterName,
+ &Binding);
+
+ if (Status != STATUS_SUCCESS) {
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ IPX_DEBUG (WAN, ("Line up, could not create WAN binding\n"));
+ goto error_no_lock;
+#else
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ IPX_DEBUG (WAN, ("Line up, could not create WAN binding\n"));
+ return;
+#endif
+ }
+
+#ifdef _PNP_POWER
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+#endif
+ //
+ // Binding->AllRouteXXX doesn't matter for WAN.
+ //
+
+ Binding->FrameType = ISN_FRAME_TYPE_ETHERNET_II;
+ Binding->SendFrameHandler = IpxSendFrameWanEthernetII;
+ ++Adapter->BindingCount;
+ Binding->Adapter = Adapter;
+
+ Binding->NicId = i;
+#ifdef _PNP_POWER
+ INSERT_BINDING(Device, i, Binding);
+#else
+ Device->Bindings[i] = Binding;
+#endif
+
+ //
+ // Other fields are filled in below.
+ //
+
+ }
+
+ //
+ // This is not an update, so note that the line is active.
+ //
+
+ Binding->LineUp = TRUE;
+
+ if (Configuration->ConnectionClient == 1) {
+ Binding->DialOutAsync = TRUE;
+ } else {
+ Binding->DialOutAsync = FALSE;
+ }
+
+ //
+ // Keep track of the highest NIC ID that we should
+ // send type 20s out on.
+ //
+
+ if (i > (UINT)MIN (Device->MaxBindings, Device->HighestType20NicId)) {
+
+ if ((Binding->DialOutAsync) ||
+ ((Device->DisableDialinNetbios & 0x01) == 0)) {
+
+ Device->HighestType20NicId = i;
+ }
+ }
+
+ //
+ // We could error out below, trying to insert this network number. In RipShortTimeout
+ // we dont check for LineUp when calculating the tick counts; set this before the insert
+ // attempt.
+ //
+ Binding->MediumSpeed = LineUp->LinkSpeed;
+
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+
+
+ //
+ // Add a router entry for this net if there is no router.
+ // We want the number of ticks for a 576-byte frame,
+ // given the link speed in 100 bps units, so we calculate
+ // as:
+ //
+ // seconds 18.21 ticks 4608 bits
+ // --------------------- * ----------- * ---------
+ // link_speed * 100 bits second frame
+ //
+ // to get the formula
+ //
+ // ticks/frame = 839 / link_speed.
+ //
+ // We add link_speed to the numerator also to ensure
+ // that the value is at least 1.
+ //
+
+ if ((!Device->UpperDriverBound[IDENTIFIER_RIP]) &&
+ (*(UNALIGNED ULONG *)Configuration->Network != 0)) {
+ if (RipInsertLocalNetwork(
+ *(UNALIGNED ULONG *)Configuration->Network,
+ Binding->NicId,
+ Adapter->NdisBindingHandle,
+ (USHORT)((839 + LineUp->LinkSpeed) / LineUp->LinkSpeed)) != STATUS_SUCCESS) {
+ //
+ // This means we couldn't allocate memory, or
+ // the entry already existed. If it already
+ // exists we can ignore it for the moment.
+ //
+ // BUGBUG: Now it will succeed if the network
+ // exists.
+ //
+
+ IPX_DEBUG (WAN, ("Line up, could not insert local network\n"));
+ Binding->LineUp = FALSE;
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ goto error_no_lock;
+#else
+ return;
+#endif
+ }
+ }
+
+
+ //
+ // Update our addresses.
+ //
+ Binding->LocalAddress.NetworkAddress = *(UNALIGNED ULONG *)Configuration->Network;
+ RtlCopyMemory (Binding->LocalAddress.NodeAddress, Configuration->LocalNode, 6);
+ RtlCopyMemory (Binding->WanRemoteNode, Configuration->RemoteNode, 6);
+
+ //
+ // Return the binding context for this puppy!
+ //
+ *((ULONG UNALIGNED *)(&LineUp->LocalAddress[2])) =
+ *((ULONG UNALIGNED *)(&Binding));
+
+ RtlCopyMemory (Binding->LocalMacAddress.Address, LineUp->LocalAddress, 6);
+ RtlCopyMemory (Binding->RemoteMacAddress.Address, LineUp->RemoteAddress, 6);
+
+ //
+ // Update the device node and all the address
+ // nodes if we have only one bound, or this is
+ // binding one.
+ //
+
+ if (!Device->VirtualNetwork) {
+
+ if ((!Device->MultiCardZeroVirtual) || (Binding->NicId == 1)) {
+ Device->SourceAddress.NetworkAddress = *(UNALIGNED ULONG *)(Configuration->Network);
+ RtlCopyMemory (Device->SourceAddress.NodeAddress, Configuration->LocalNode, 6);
+ }
+
+ //
+ // Scan through all the addresses that exist and modify
+ // their pre-constructed local IPX address to reflect
+ // the new local net and node.
+ //
+
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+
+ for (CurrentHash = 0; CurrentHash < IPX_ADDRESS_HASH_COUNT; CurrentHash++) {
+
+ for (p = Device->AddressDatabases[CurrentHash].Flink;
+ p != &Device->AddressDatabases[CurrentHash];
+ p = p->Flink) {
+
+ Address = CONTAINING_RECORD (p, ADDRESS, Linkage);
+
+ Address->LocalAddress.NetworkAddress = *(UNALIGNED ULONG *)Configuration->Network;
+ RtlCopyMemory (Address->LocalAddress.NodeAddress, Configuration->LocalNode, 6);
+ }
+ }
+
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+
+ }
+
+ //
+ // Reset this since the line just came up.
+ //
+
+ Binding->WanInactivityCounter = 0;
+
+ }
+
+ LinkSpeed = LineUp->LinkSpeed;
+
+ //
+ // Scan through bindings to update Device->LinkSpeed.
+ // If SingleNetworkActive is set, we only count WAN
+ // bindings when doing this (although it is unlikely
+ // a LAN binding would be the winner).
+ //
+ // BUGBUG: Update other device information?
+ //
+
+ for (i = 1; i <= Device->ValidBindings; i++) {
+#ifdef _PNP_POWER
+ if (TmpBinding = NIC_ID_TO_BINDING(Device, i)) {
+#else
+ if (TmpBinding = Device->Bindings[i]) {
+#endif
+ TmpAdapter = TmpBinding->Adapter;
+ if (TmpBinding->LineUp &&
+ (!Device->SingleNetworkActive || TmpAdapter->MacInfo.MediumAsync) &&
+ (TmpBinding->MediumSpeed < LinkSpeed)) {
+ LinkSpeed = TmpBinding->MediumSpeed;
+ }
+ }
+ }
+
+#ifdef _PNP_POWER
+ //
+ // Release the lock after incrementing the reference count
+ //
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+
+ Device->LinkSpeed = LinkSpeed;
+
+ if ((Adapter->ConfigMaxPacketSize == 0) ||
+ (LineUp->MaximumTotalSize < Adapter->ConfigMaxPacketSize)) {
+ Binding->MaxSendPacketSize = LineUp->MaximumTotalSize;
+ } else {
+ Binding->MaxSendPacketSize = Adapter->ConfigMaxPacketSize;
+ }
+ MacInitializeBindingInfo (Binding, Adapter);
+
+#ifdef _PNP_POWER
+
+ //
+ // We dont give lineups; instead indicate only if the PnP reserved address
+ // changed to SPX. NB gets all PnP indications with the reserved address case
+ // marked out.
+ //
+ {
+ IPX_PNP_INFO NBPnPInfo;
+
+ if ((!Device->MultiCardZeroVirtual) || (Binding->NicId == 1)) {
+
+ //
+ // NB's reserved address changed.
+ //
+ NBPnPInfo.NewReservedAddress = TRUE;
+
+ if (!Device->VirtualNetwork) {
+ //
+ // Let SPX know because it fills in its own headers.
+ //
+ if (Device->UpperDriverBound[IDENTIFIER_SPX]) {
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+ IPX_PNP_INFO IpxPnPInfo;
+
+ IpxPnPInfo.NewReservedAddress = TRUE;
+ IpxPnPInfo.NetworkAddress = Binding->LocalAddress.NetworkAddress;
+ IpxPnPInfo.FirstORLastDevice = FALSE;
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, Binding->LocalAddress.NodeAddress, 6);
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, Binding->NicId);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ //
+ // give the PnP indication
+ //
+ (*Device->UpperDrivers[IDENTIFIER_SPX].PnPHandler) (
+ IPX_PNP_ADDRESS_CHANGE,
+ &IpxPnPInfo);
+
+ IPX_DEBUG(AUTO_DETECT, ("IPX_PNP_ADDRESS_CHANGED to SPX: net addr: %lx\n", Binding->LocalAddress.NetworkAddress));
+ }
+ }
+ } else {
+ NBPnPInfo.NewReservedAddress = FALSE;
+ }
+
+ if (Device->UpperDriverBound[IDENTIFIER_NB]) {
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+
+ NBPnPInfo.LineInfo.LinkSpeed = Device->LinkSpeed;
+ NBPnPInfo.LineInfo.MaximumPacketSize =
+ Device->Information.MaximumLookaheadData + sizeof(IPX_HEADER);
+ NBPnPInfo.LineInfo.MaximumSendSize =
+ Device->Information.MaxDatagramSize + sizeof(IPX_HEADER);
+ NBPnPInfo.LineInfo.MacOptions = Device->MacOptions;
+
+ NBPnPInfo.NetworkAddress = Binding->LocalAddress.NetworkAddress;
+ NBPnPInfo.FirstORLastDevice = FALSE;
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ RtlCopyMemory(NBPnPInfo.NodeAddress, Binding->LocalAddress.NodeAddress, 6);
+ NIC_HANDLE_FROM_NIC(NBPnPInfo.NicHandle, Binding->NicId);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ //
+ // give the PnP indication
+ //
+ (*Device->UpperDrivers[IDENTIFIER_NB].PnPHandler) (
+ IPX_PNP_ADD_DEVICE,
+ &NBPnPInfo);
+
+ IPX_DEBUG(AUTO_DETECT, ("IPX_PNP_ADD_DEVICE (lineup) to NB: net addr: %lx\n", Binding->LocalAddress.NetworkAddress));
+ }
+
+ //
+ // Register this address with the TDI clients.
+ //
+ RtlCopyMemory (Device->TdiRegistrationAddress->Address, &Binding->LocalAddress, sizeof(TDI_ADDRESS_IPX));
+
+ if ((ntStatus = TdiRegisterNetAddress(
+ Device->TdiRegistrationAddress,
+ &Binding->TdiRegistrationHandle)) != STATUS_SUCCESS) {
+
+ IPX_DEBUG(PNP, ("TdiRegisterNetAddress failed: %lx", ntStatus));
+ }
+ }
+
+ //
+ // Indicate to the upper drivers.
+ //
+ LineInfo.LinkSpeed = LineUp->LinkSpeed;
+ LineInfo.MaximumPacketSize = LineUp->MaximumTotalSize - 14;
+ LineInfo.MaximumSendSize = LineUp->MaximumTotalSize - 14;
+ LineInfo.MacOptions = Adapter->MacInfo.MacOptions;
+
+ //
+ // Give line up to RIP as it is not PnP aware.
+ //
+ if (Device->UpperDriverBound[IDENTIFIER_RIP]) {
+ (*Device->UpperDrivers[IDENTIFIER_RIP].LineUpHandler)(
+ Binding->NicId,
+ &LineInfo,
+ NdisMediumWan,
+ UpdateLineUp ? NULL : Configuration);
+ }
+#else
+ //
+ // Indicate to the upper drivers.
+ //
+ LineInfo.LinkSpeed = LineUp->LinkSpeed;
+ LineInfo.MaximumPacketSize = LineUp->MaximumTotalSize - 14;
+ LineInfo.MaximumSendSize = LineUp->MaximumTotalSize - 14;
+ LineInfo.MacOptions = Adapter->MacInfo.MacOptions;
+ for (i = 0; i < UPPER_DRIVER_COUNT; i++) {
+
+ if (Device->UpperDriverBound[i]) {
+ (*Device->UpperDrivers[i].LineUpHandler)(
+ Binding->NicId,
+ &LineInfo,
+ NdisMediumWan,
+ UpdateLineUp ? NULL : Configuration);
+ }
+ }
+#endif
+ if (!UpdateLineUp) {
+
+ if ((Device->SingleNetworkActive) &&
+ (Configuration->ConnectionClient == 1)) {
+ //
+ // Drop all entries in the database if rip is not bound.
+ //
+
+ if (!Device->UpperDriverBound[IDENTIFIER_RIP]) {
+ RipDropRemoteEntries();
+ }
+
+ Device->ActiveNetworkWan = TRUE;
+
+ //
+ // Find a queued line change and complete it.
+ //
+
+ if ((p = ExInterlockedRemoveHeadList(
+ &Device->LineChangeQueue,
+ &Device->Lock)) != NULL) {
+
+ Request = LIST_ENTRY_TO_REQUEST(p);
+
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ REQUEST_STATUS(Request) = STATUS_SUCCESS;
+ IpxCompleteRequest (Request);
+ IpxFreeRequest (Device, Request);
+
+ IpxDereferenceDevice (Device, DREF_LINE_CHANGE);
+
+ }
+
+ //
+ // If we have a virtual net, do a broadcast now so
+ // the router on the other end will know about us.
+ //
+ // BUGBUG: Use RipSendResponse, and do it even
+ // if SingleNetworkActive is FALSE??
+ //
+
+ if (Device->RipResponder) {
+ (VOID)RipQueueRequest (Device->VirtualNetworkNumber, RIP_RESPONSE);
+ }
+
+ }
+
+ //
+ // Find a queued address notify and complete it.
+ // If WanGlobalNetworkNumber is TRUE, we only do
+ // this when the first dialin line comes up.
+ //
+
+ if ((!Device->WanGlobalNetworkNumber ||
+ (!Device->GlobalNetworkIndicated && !Binding->DialOutAsync))
+ &&
+ ((p = ExInterlockedRemoveHeadList(
+ &Device->AddressNotifyQueue,
+ &Device->Lock)) != NULL)) {
+
+ if (Device->WanGlobalNetworkNumber) {
+ Device->GlobalWanNetwork = Binding->LocalAddress.NetworkAddress;
+ Device->GlobalNetworkIndicated = TRUE;
+ }
+
+ Request = LIST_ENTRY_TO_REQUEST(p);
+ NdisBuffer = REQUEST_NDIS_BUFFER(Request);
+ NdisQueryBuffer (REQUEST_NDIS_BUFFER(Request), (PVOID *)&NwlinkAction, &BufferLength);
+
+ IpxAddressData = (PIPX_ADDRESS_DATA)(NwlinkAction->Data);
+
+ if (Device->WanGlobalNetworkNumber) {
+ IpxAddressData->adapternum = Device->SapNicCount - 1;
+ } else {
+ IpxAddressData->adapternum = Binding->NicId - 1;
+ }
+ *(UNALIGNED ULONG *)IpxAddressData->netnum = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory(IpxAddressData->nodenum, Binding->LocalAddress.NodeAddress, 6);
+ IpxAddressData->wan = TRUE;
+ IpxAddressData->status = TRUE;
+ IpxAddressData->maxpkt = Binding->AnnouncedMaxDatagramSize; // BUGBUG: Use real?
+ IpxAddressData->linkspeed = Binding->MediumSpeed;
+
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ REQUEST_STATUS(Request) = STATUS_SUCCESS;
+ IpxCompleteRequest (Request);
+ IpxFreeRequest (Device, Request);
+
+ IpxDereferenceDevice (Device, DREF_ADDRESS_NOTIFY);
+ }
+ }
+#ifdef _PNP_POWER
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif
+ break;
+
+ case NDIS_STATUS_WAN_LINE_DOWN:
+
+ if (StatusBufferSize < sizeof(NDIS_WAN_LINE_DOWN)) {
+ IPX_DEBUG (WAN, ("Line down, status buffer size wrong %d/%d\n", StatusBufferSize, sizeof(NDIS_WAN_LINE_DOWN)));
+ return;
+ }
+
+ LineDown = (PNDIS_WAN_LINE_DOWN)StatusBuffer;
+
+ *((ULONG UNALIGNED*)(&Binding)) = *((ULONG UNALIGNED*)(&LineDown->LocalAddress[2]));
+
+ CTEAssert(Binding != NULL);
+
+ //
+ // Note that the WAN line is down.
+ //
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+#endif
+
+ Binding->LineUp = FALSE;
+
+ //
+ // PNP_POWER - we hold the exclusive lock to the binding
+ // and reference to the adapter at this point.
+ //
+
+ //
+ // Keep track of the highest NIC ID that we should
+ // send type 20s out on.
+ //
+
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+
+ if (Binding->NicId == MIN (Device->MaxBindings, Device->HighestType20NicId)) {
+
+ //
+ // This was the old limit, so we have to scan
+ // backwards to update it -- we stop when we hit
+ // a non-WAN binding, or a wan binding that is up and
+ // dialout, or any wan binding if bit 1 in
+ // DisableDialinNetbios is off.
+ //
+
+ for (i = Binding->NicId-1; i >= 1; i--) {
+#ifdef _PNP_POWER
+ TmpBinding = NIC_ID_TO_BINDING(Device, i);
+#else
+ TmpBinding = Device->Bindings[i];
+#endif
+
+ if ((TmpBinding != NULL) &&
+ ((!TmpBinding->Adapter->MacInfo.MediumAsync) ||
+ (TmpBinding->LineUp &&
+ ((Binding->DialOutAsync) ||
+ ((Device->DisableDialinNetbios & 0x01) == 0))))) {
+
+ break;
+ }
+ }
+
+ Device->HighestType20NicId = i;
+
+ }
+
+
+ //
+ // Scan through bindings to update Device->LinkSpeed.
+ // If SingleNetworkActive is set, we only count LAN
+ // bindings when doing this.
+ //
+ // BUGBUG: Update other device information?
+ //
+
+ LinkSpeed = 0xffffffff;
+ for (i = 1; i <= Device->ValidBindings; i++) {
+#ifdef _PNP_POWER
+ if (TmpBinding = NIC_ID_TO_BINDING(Device, i)) {
+#else
+ if (TmpBinding = Device->Bindings[i]) {
+#endif
+ TmpAdapter = TmpBinding->Adapter;
+ if (TmpBinding->LineUp &&
+ (!Device->SingleNetworkActive || !TmpAdapter->MacInfo.MediumAsync) &&
+ (TmpBinding->MediumSpeed < LinkSpeed)) {
+ LinkSpeed = TmpBinding->MediumSpeed;
+ }
+ }
+ }
+
+ if (LinkSpeed != 0xffffffff) {
+ Device->LinkSpeed = LinkSpeed;
+ }
+
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+
+#ifdef _PNP_POWER
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+
+ //
+ // Remove our router entry for this net.
+ //
+
+ if (!Device->UpperDriverBound[IDENTIFIER_RIP]) {
+
+ Segment = RipGetSegment ((PUCHAR)&Binding->LocalAddress.NetworkAddress);
+ IPX_GET_LOCK (&Device->SegmentLocks[Segment], &LockHandle);
+
+ RouteEntry = RipGetRoute (Segment, (PUCHAR)&Binding->LocalAddress.NetworkAddress);
+
+ if (RouteEntry != (PIPX_ROUTE_ENTRY)NULL) {
+
+ RipDeleteRoute (Segment, RouteEntry);
+ IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
+ IpxFreeMemory (RouteEntry, sizeof(IPX_ROUTE_ENTRY), MEMORY_RIP, "RouteEntry");
+
+ } else {
+
+ IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
+ }
+
+ RipAdjustForBindingChange (Binding->NicId, 0, IpxBindingDown);
+
+ }
+
+ //
+ // Indicate to the upper drivers.
+ //
+#ifdef _PNP_POWER
+
+ //
+ // DeRegister this address with the TDI clients.
+ //
+ {
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ CTEAssert(Binding->TdiRegistrationHandle);
+
+ if ((ntStatus = TdiDeregisterNetAddress(Binding->TdiRegistrationHandle)) != STATUS_SUCCESS) {
+ IPX_DEBUG(PNP, ("TdiDeRegisterNetAddress failed: %lx", ntStatus));
+ }
+
+ if (Device->UpperDriverBound[IDENTIFIER_NB]) {
+ IPX_PNP_INFO NBPnPInfo;
+
+ CTEAssert(Binding->IsnInformed[IDENTIFIER_NB]);
+
+ NBPnPInfo.LineInfo.LinkSpeed = Device->LinkSpeed;
+ NBPnPInfo.LineInfo.MaximumPacketSize =
+ Device->Information.MaximumLookaheadData + sizeof(IPX_HEADER);
+ NBPnPInfo.LineInfo.MaximumSendSize =
+ Device->Information.MaxDatagramSize + sizeof(IPX_HEADER);
+ NBPnPInfo.LineInfo.MacOptions = Device->MacOptions;
+
+ NBPnPInfo.NewReservedAddress = FALSE;
+ NBPnPInfo.FirstORLastDevice = FALSE;
+
+ NBPnPInfo.NetworkAddress = Binding->LocalAddress.NetworkAddress;
+
+ RtlCopyMemory(NBPnPInfo.NodeAddress, Binding->LocalAddress.NodeAddress, 6);
+ NIC_HANDLE_FROM_NIC(NBPnPInfo.NicHandle, Binding->NicId);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ //
+ // give the PnP indication
+ //
+ (*Device->UpperDrivers[IDENTIFIER_NB].PnPHandler) (
+ IPX_PNP_DELETE_DEVICE,
+ &NBPnPInfo);
+
+ IPX_DEBUG(AUTO_DETECT, ("IPX_PNP_DELETE_DEVICE (linedown) to NB: addr: %lx\n", Binding->LocalAddress.NetworkAddress));
+ } else {
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ }
+ }
+
+ if (Device->UpperDriverBound[IDENTIFIER_RIP]) {
+ (*Device->UpperDrivers[IDENTIFIER_RIP].LineDownHandler)(
+ Binding->NicId);
+ }
+#else
+ for (i = 0; i < UPPER_DRIVER_COUNT; i++) {
+
+ if (Device->UpperDriverBound[i]) {
+ (*Device->UpperDrivers[i].LineDownHandler)(
+ Binding->NicId);
+ }
+ }
+#endif
+
+ if ((Device->SingleNetworkActive) &&
+ (Binding->DialOutAsync)) {
+
+ //
+ // Drop all entries in the database if rip is not bound.
+ //
+
+ if (!Device->UpperDriverBound[IDENTIFIER_RIP]) {
+ RipDropRemoteEntries();
+ }
+
+ Device->ActiveNetworkWan = FALSE;
+
+ //
+ // Find a queued line change and complete it.
+ //
+
+ if ((p = ExInterlockedRemoveHeadList(
+ &Device->LineChangeQueue,
+ &Device->Lock)) != NULL) {
+
+ Request = LIST_ENTRY_TO_REQUEST(p);
+
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ REQUEST_STATUS(Request) = STATUS_SUCCESS;
+ IpxCompleteRequest (Request);
+ IpxFreeRequest (Device, Request);
+
+ IpxDereferenceDevice (Device, DREF_LINE_CHANGE);
+
+ }
+
+ }
+
+ //
+ // Find a queued address notify and complete it.
+ //
+
+ if ((!Device->WanGlobalNetworkNumber) &&
+ ((p = ExInterlockedRemoveHeadList(
+ &Device->AddressNotifyQueue,
+ &Device->Lock)) != NULL)) {
+
+ Request = LIST_ENTRY_TO_REQUEST(p);
+ NdisBuffer = REQUEST_NDIS_BUFFER(Request);
+ NdisQueryBuffer (REQUEST_NDIS_BUFFER(Request), (PVOID *)&NwlinkAction, &BufferLength);
+
+ IpxAddressData = (PIPX_ADDRESS_DATA)(NwlinkAction->Data);
+
+ IpxAddressData->adapternum = Binding->NicId - 1;
+ *(UNALIGNED ULONG *)IpxAddressData->netnum = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory(IpxAddressData->nodenum, Binding->LocalAddress.NodeAddress, 6);
+ IpxAddressData->wan = TRUE;
+ IpxAddressData->status = FALSE;
+ IpxAddressData->maxpkt = Binding->AnnouncedMaxDatagramSize; // BUGBUG: Use real?
+ IpxAddressData->linkspeed = Binding->MediumSpeed;
+
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ REQUEST_STATUS(Request) = STATUS_SUCCESS;
+ IpxCompleteRequest (Request);
+ IpxFreeRequest (Device, Request);
+
+ IpxDereferenceDevice (Device, DREF_ADDRESS_NOTIFY);
+ }
+
+#ifdef _PNP_POWER
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif
+ break;
+
+ case NDIS_STATUS_WAN_FRAGMENT:
+
+ //
+ // No response needed, IPX is a datagram service.
+ //
+ // BUGBUG: What about telling Netbios/SPX?
+ //
+
+ break;
+
+ default:
+
+ break;
+
+ }
+
+#ifdef _PNP_POWER
+error_no_lock:
+ IpxDereferenceAdapter(Adapter);
+#endif
+
+} /* IpxStatus */
+
+
+VOID
+IpxStatusComplete(
+ IN NDIS_HANDLE NdisBindingContext
+ )
+{
+ UNREFERENCED_PARAMETER (NdisBindingContext);
+
+} /* IpxStatusComplete */
+
+
+
diff --git a/private/ntos/tdi/isnp/ipx/nwlnkipx.ini b/private/ntos/tdi/isnp/ipx/nwlnkipx.ini
new file mode 100644
index 000000000..416f0c6b7
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/nwlnkipx.ini
@@ -0,0 +1,191 @@
+\Registry\Machine\System\CurrentControlSet\Services\NwlnkIpx
+ Type = REG_DWORD 0x00000001
+ Start = REG_DWORD 0x00000003
+ ErrorControl = REG_DWORD 0x00000001
+ ImagePath = REG_EXPAND_SZ \SystemRoot\System32\drivers\nwlnkipx.sys
+ DisplayName = NWLINK2 IPX Protocol
+ Group = TDI
+ DependOnService = REG_MULTI_SZ
+ DependOnGroup = REG_MULTI_SZ "NDIS"
+ Linkage
+ Bind = REG_MULTI_SZ "\Device\Elnkii1"
+ Export = REG_MULTI_SZ "\Device\NwlnkIpx"
+ Route = REG_MULTI_SZ ""Elnkii" "Elnkii1""
+ Disabled
+ Bind = REG_MULTI_SZ
+ Export = REG_MULTI_SZ
+ Route = REG_MULTI_SZ
+ NetConfig
+ Elnkii1
+ NetworkNumber = REG_MULTI_SZ "0"
+ PktType = REG_MULTI_SZ "1"
+ BindSap = REG_DWORD 0x00008137
+ SourceRouting = REG_DWORD 0x00000001
+ SourceRouteDef = REG_DWORD 0x00000000
+ SourceRouteBcast = REG_DWORD 0x00000000
+ SourceRouteMcast = REG_DWORD 0x00000000
+ EnableFuncaddr = REG_DWORD 0x00000001
+ MaxPktSize = REG_DWORD 0x00000000
+ Netcard2
+ NetworkNumber = REG_MULTI_SZ "0"
+ PktType = REG_MULTI_SZ "1"
+ BindSap = REG_DWORD 0x00008137
+ SourceRouting = REG_DWORD 0x00000001
+ SourceRouteDef = REG_DWORD 0x00000000
+ SourceRouteBcast = REG_DWORD 0x00000000
+ SourceRouteMcast = REG_DWORD 0x00000000
+ EnableFuncaddr = REG_DWORD 0x00000001
+ MaxPktSize = REG_DWORD 0x00000000
+ Netcard3
+ NetworkNumber = REG_MULTI_SZ "0"
+ PktType = REG_MULTI_SZ "1"
+ BindSap = REG_DWORD 0x00008137
+ SourceRouting = REG_DWORD 0x00000001
+ SourceRouteDef = REG_DWORD 0x00000000
+ SourceRouteBcast = REG_DWORD 0x00000000
+ SourceRouteMcast = REG_DWORD 0x00000000
+ EnableFuncaddr = REG_DWORD 0x00000001
+ MaxPktSize = REG_DWORD 0x00000000
+ Netcard4
+ NetworkNumber = REG_MULTI_SZ "0"
+ PktType = REG_MULTI_SZ "1"
+ BindSap = REG_DWORD 0x00008137
+ SourceRouting = REG_DWORD 0x00000001
+ SourceRouteDef = REG_DWORD 0x00000000
+ SourceRouteBcast = REG_DWORD 0x00000000
+ SourceRouteMcast = REG_DWORD 0x00000000
+ EnableFuncaddr = REG_DWORD 0x00000001
+ MaxPktSize = REG_DWORD 0x00000000
+ Netcard5
+ NetworkNumber = REG_MULTI_SZ "0"
+ PktType = REG_MULTI_SZ "1"
+ BindSap = REG_DWORD 0x00008137
+ SourceRouting = REG_DWORD 0x00000001
+ SourceRouteDef = REG_DWORD 0x00000000
+ SourceRouteBcast = REG_DWORD 0x00000000
+ SourceRouteMcast = REG_DWORD 0x00000000
+ EnableFuncaddr = REG_DWORD 0x00000001
+ MaxPktSize = REG_DWORD 0x00000000
+ Parameters
+ DedicatedRouter = REG_DWORD 0x00000000
+ InitDatagrams = REG_DWORD 0x0000000a
+ MaxDatagrams = REG_DWORD 0x00000032
+ RipAgeTime = REG_DWORD 0x00000005
+ RipCount = REG_DWORD 0x00000005
+ RipTimeout = REG_DWORD 0x00000001
+ RipUsageTime = REG_DWORD 0x0000000f
+ SourceRouteUsageTime = REG_DWORD 0x0000000a
+ SocketUniqueness = REG_DWORD 0x00000008
+ VirtualNetworkNumber = REG_DWORD 0x00000000
+ VirtualNetworkOptional = REG_DWORD 0x00000001
+ Winsock
+ Mapping = REG_BINARY 0x00000c08
+ 0x00000100 0x00000003 0x00000006 0x00000002 0x000003e8 0x00000006 0x00000002 0x000003e9
+ 0x00000006 0x00000002 0x000003ea 0x00000006 0x00000002 0x000003eb 0x00000006 0x00000002
+ 0x000003ec 0x00000006 0x00000002 0x000003ed 0x00000006 0x00000002 0x000003ee 0x00000006
+ 0x00000002 0x000003ef 0x00000006 0x00000002 0x000003f0 0x00000006 0x00000002 0x000003f1
+ 0x00000006 0x00000002 0x000003f2 0x00000006 0x00000002 0x000003f3 0x00000006 0x00000002
+ 0x000003f4 0x00000006 0x00000002 0x000003f5 0x00000006 0x00000002 0x000003f6 0x00000006
+ 0x00000002 0x000003f7 0x00000006 0x00000002 0x000003f8 0x00000006 0x00000002 0x000003f9
+ 0x00000006 0x00000002 0x000003fa 0x00000006 0x00000002 0x000003fb 0x00000006 0x00000002
+ 0x000003fc 0x00000006 0x00000002 0x000003fd 0x00000006 0x00000002 0x000003fe 0x00000006
+ 0x00000002 0x000003ff 0x00000006 0x00000002 0x00000400 0x00000006 0x00000002 0x00000401
+ 0x00000006 0x00000002 0x00000402 0x00000006 0x00000002 0x00000403 0x00000006 0x00000002
+ 0x00000404 0x00000006 0x00000002 0x00000405 0x00000006 0x00000002 0x00000406 0x00000006
+ 0x00000002 0x00000407 0x00000006 0x00000002 0x00000408 0x00000006 0x00000002 0x00000409
+ 0x00000006 0x00000002 0x0000040a 0x00000006 0x00000002 0x0000040b 0x00000006 0x00000002
+ 0x0000040c 0x00000006 0x00000002 0x0000040d 0x00000006 0x00000002 0x0000040e 0x00000006
+ 0x00000002 0x0000040f 0x00000006 0x00000002 0x00000410 0x00000006 0x00000002 0x00000411
+ 0x00000006 0x00000002 0x00000412 0x00000006 0x00000002 0x00000413 0x00000006 0x00000002
+ 0x00000414 0x00000006 0x00000002 0x00000415 0x00000006 0x00000002 0x00000416 0x00000006
+ 0x00000002 0x00000417 0x00000006 0x00000002 0x00000418 0x00000006 0x00000002 0x00000419
+ 0x00000006 0x00000002 0x0000041a 0x00000006 0x00000002 0x0000041b 0x00000006 0x00000002
+ 0x0000041c 0x00000006 0x00000002 0x0000041d 0x00000006 0x00000002 0x0000041e 0x00000006
+ 0x00000002 0x0000041f 0x00000006 0x00000002 0x00000420 0x00000006 0x00000002 0x00000421
+ 0x00000006 0x00000002 0x00000422 0x00000006 0x00000002 0x00000423 0x00000006 0x00000002
+ 0x00000424 0x00000006 0x00000002 0x00000425 0x00000006 0x00000002 0x00000426 0x00000006
+ 0x00000002 0x00000427 0x00000006 0x00000002 0x00000428 0x00000006 0x00000002 0x00000429
+ 0x00000006 0x00000002 0x0000042a 0x00000006 0x00000002 0x0000042b 0x00000006 0x00000002
+ 0x0000042c 0x00000006 0x00000002 0x0000042d 0x00000006 0x00000002 0x0000042e 0x00000006
+ 0x00000002 0x0000042f 0x00000006 0x00000002 0x00000430 0x00000006 0x00000002 0x00000431
+ 0x00000006 0x00000002 0x00000432 0x00000006 0x00000002 0x00000433 0x00000006 0x00000002
+ 0x00000434 0x00000006 0x00000002 0x00000435 0x00000006 0x00000002 0x00000436 0x00000006
+ 0x00000002 0x00000437 0x00000006 0x00000002 0x00000438 0x00000006 0x00000002 0x00000439
+ 0x00000006 0x00000002 0x0000043a 0x00000006 0x00000002 0x0000043b 0x00000006 0x00000002
+ 0x0000043c 0x00000006 0x00000002 0x0000043d 0x00000006 0x00000002 0x0000043e 0x00000006
+ 0x00000002 0x0000043f 0x00000006 0x00000002 0x00000440 0x00000006 0x00000002 0x00000441
+ 0x00000006 0x00000002 0x00000442 0x00000006 0x00000002 0x00000443 0x00000006 0x00000002
+ 0x00000444 0x00000006 0x00000002 0x00000445 0x00000006 0x00000002 0x00000446 0x00000006
+ 0x00000002 0x00000447 0x00000006 0x00000002 0x00000448 0x00000006 0x00000002 0x00000449
+ 0x00000006 0x00000002 0x0000044a 0x00000006 0x00000002 0x0000044b 0x00000006 0x00000002
+ 0x0000044c 0x00000006 0x00000002 0x0000044d 0x00000006 0x00000002 0x0000044e 0x00000006
+ 0x00000002 0x0000044f 0x00000006 0x00000002 0x00000450 0x00000006 0x00000002 0x00000451
+ 0x00000006 0x00000002 0x00000452 0x00000006 0x00000002 0x00000453 0x00000006 0x00000002
+ 0x00000454 0x00000006 0x00000002 0x00000455 0x00000006 0x00000002 0x00000456 0x00000006
+ 0x00000002 0x00000457 0x00000006 0x00000002 0x00000458 0x00000006 0x00000002 0x00000459
+ 0x00000006 0x00000002 0x0000045a 0x00000006 0x00000002 0x0000045b 0x00000006 0x00000002
+ 0x0000045c 0x00000006 0x00000002 0x0000045d 0x00000006 0x00000002 0x0000045e 0x00000006
+ 0x00000002 0x0000045f 0x00000006 0x00000002 0x00000460 0x00000006 0x00000002 0x00000461
+ 0x00000006 0x00000002 0x00000462 0x00000006 0x00000002 0x00000463 0x00000006 0x00000002
+ 0x00000464 0x00000006 0x00000002 0x00000465 0x00000006 0x00000002 0x00000466 0x00000006
+ 0x00000002 0x00000467 0x00000006 0x00000002 0x00000468 0x00000006 0x00000002 0x00000469
+ 0x00000006 0x00000002 0x0000046a 0x00000006 0x00000002 0x0000046b 0x00000006 0x00000002
+ 0x0000046c 0x00000006 0x00000002 0x0000046d 0x00000006 0x00000002 0x0000046e 0x00000006
+ 0x00000002 0x0000046f 0x00000006 0x00000002 0x00000470 0x00000006 0x00000002 0x00000471
+ 0x00000006 0x00000002 0x00000472 0x00000006 0x00000002 0x00000473 0x00000006 0x00000002
+ 0x00000474 0x00000006 0x00000002 0x00000475 0x00000006 0x00000002 0x00000476 0x00000006
+ 0x00000002 0x00000477 0x00000006 0x00000002 0x00000478 0x00000006 0x00000002 0x00000479
+ 0x00000006 0x00000002 0x0000047a 0x00000006 0x00000002 0x0000047b 0x00000006 0x00000002
+ 0x0000047c 0x00000006 0x00000002 0x0000047d 0x00000006 0x00000002 0x0000047e 0x00000006
+ 0x00000002 0x0000047f 0x00000006 0x00000002 0x00000480 0x00000006 0x00000002 0x00000481
+ 0x00000006 0x00000002 0x00000482 0x00000006 0x00000002 0x00000483 0x00000006 0x00000002
+ 0x00000484 0x00000006 0x00000002 0x00000485 0x00000006 0x00000002 0x00000486 0x00000006
+ 0x00000002 0x00000487 0x00000006 0x00000002 0x00000488 0x00000006 0x00000002 0x00000489
+ 0x00000006 0x00000002 0x0000048a 0x00000006 0x00000002 0x0000048b 0x00000006 0x00000002
+ 0x0000048c 0x00000006 0x00000002 0x0000048d 0x00000006 0x00000002 0x0000048e 0x00000006
+ 0x00000002 0x0000048f 0x00000006 0x00000002 0x00000490 0x00000006 0x00000002 0x00000491
+ 0x00000006 0x00000002 0x00000492 0x00000006 0x00000002 0x00000493 0x00000006 0x00000002
+ 0x00000494 0x00000006 0x00000002 0x00000495 0x00000006 0x00000002 0x00000496 0x00000006
+ 0x00000002 0x00000497 0x00000006 0x00000002 0x00000498 0x00000006 0x00000002 0x00000499
+ 0x00000006 0x00000002 0x0000049a 0x00000006 0x00000002 0x0000049b 0x00000006 0x00000002
+ 0x0000049c 0x00000006 0x00000002 0x0000049d 0x00000006 0x00000002 0x0000049e 0x00000006
+ 0x00000002 0x0000049f 0x00000006 0x00000002 0x000004a0 0x00000006 0x00000002 0x000004a1
+ 0x00000006 0x00000002 0x000004a2 0x00000006 0x00000002 0x000004a3 0x00000006 0x00000002
+ 0x000004a4 0x00000006 0x00000002 0x000004a5 0x00000006 0x00000002 0x000004a6 0x00000006
+ 0x00000002 0x000004a7 0x00000006 0x00000002 0x000004a8 0x00000006 0x00000002 0x000004a9
+ 0x00000006 0x00000002 0x000004aa 0x00000006 0x00000002 0x000004ab 0x00000006 0x00000002
+ 0x000004ac 0x00000006 0x00000002 0x000004ad 0x00000006 0x00000002 0x000004ae 0x00000006
+ 0x00000002 0x000004af 0x00000006 0x00000002 0x000004b0 0x00000006 0x00000002 0x000004b1
+ 0x00000006 0x00000002 0x000004b2 0x00000006 0x00000002 0x000004b3 0x00000006 0x00000002
+ 0x000004b4 0x00000006 0x00000002 0x000004b5 0x00000006 0x00000002 0x000004b6 0x00000006
+ 0x00000002 0x000004b7 0x00000006 0x00000002 0x000004b8 0x00000006 0x00000002 0x000004b9
+ 0x00000006 0x00000002 0x000004ba 0x00000006 0x00000002 0x000004bb 0x00000006 0x00000002
+ 0x000004bc 0x00000006 0x00000002 0x000004bd 0x00000006 0x00000002 0x000004be 0x00000006
+ 0x00000002 0x000004bf 0x00000006 0x00000002 0x000004c0 0x00000006 0x00000002 0x000004c1
+ 0x00000006 0x00000002 0x000004c2 0x00000006 0x00000002 0x000004c3 0x00000006 0x00000002
+ 0x000004c4 0x00000006 0x00000002 0x000004c5 0x00000006 0x00000002 0x000004c6 0x00000006
+ 0x00000002 0x000004c7 0x00000006 0x00000002 0x000004c8 0x00000006 0x00000002 0x000004c9
+ 0x00000006 0x00000002 0x000004ca 0x00000006 0x00000002 0x000004cb 0x00000006 0x00000002
+ 0x000004cc 0x00000006 0x00000002 0x000004cd 0x00000006 0x00000002 0x000004ce 0x00000006
+ 0x00000002 0x000004cf 0x00000006 0x00000002 0x000004d0 0x00000006 0x00000002 0x000004d1
+ 0x00000006 0x00000002 0x000004d2 0x00000006 0x00000002 0x000004d3 0x00000006 0x00000002
+ 0x000004d4 0x00000006 0x00000002 0x000004d5 0x00000006 0x00000002 0x000004d6 0x00000006
+ 0x00000002 0x000004d7 0x00000006 0x00000002 0x000004d8 0x00000006 0x00000002 0x000004d9
+ 0x00000006 0x00000002 0x000004da 0x00000006 0x00000002 0x000004db 0x00000006 0x00000002
+ 0x000004dc 0x00000006 0x00000002 0x000004dd 0x00000006 0x00000002 0x000004de 0x00000006
+ 0x00000002 0x000004df 0x00000006 0x00000002 0x000004e0 0x00000006 0x00000002 0x000004e1
+ 0x00000006 0x00000002 0x000004e2 0x00000006 0x00000002 0x000004e3 0x00000006 0x00000002
+ 0x000004e4 0x00000006 0x00000002 0x000004e5 0x00000006 0x00000002 0x000004e6 0x00000006
+ 0x00000002 0x000004e7
+
+ HelperDllName = REG_EXPAND_SZ %SystemRoot%\system32\wshisn.dll
+ MinSockaddrLength = REG_DWORD 0x0000000e
+ MaxSockaddrLength = REG_DWORD 0x00000010
+ Performance
+ Library = Perfctrs.dll
+ Open = OpenNbfPerformanceData
+ Collect = CollectNbfPerformanceData
+ Close = CloseNbfPerformanceData
+\Registry\Machine\System\CurrentControlSet\Services\EventLog\System\NwlnkIpx
+ EventMessageFile = REG_EXPAND_SZ %SystemRoot%\System32\netevent.dll
+ TypesSupported = REG_DWORD 0x00000007
diff --git a/private/ntos/tdi/isnp/ipx/nwlnkipx.rc b/private/ntos/tdi/isnp/ipx/nwlnkipx.rc
new file mode 100644
index 000000000..0f437a15d
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/nwlnkipx.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+#define VER_FILEDESCRIPTION_STR "NWLINK2 IPX Protocol Driver"
+#define VER_INTERNALNAME_STR "nwlnkipx.sys"
+#define VER_ORIGINALFILENAME_STR "nwlnkipx.sys"
+
+#include "common.ver"
+
diff --git a/private/ntos/tdi/isnp/ipx/packet.c b/private/ntos/tdi/isnp/ipx/packet.c
new file mode 100644
index 000000000..f70154b03
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/packet.c
@@ -0,0 +1,1560 @@
+/*++
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ packet.c
+
+Abstract:
+
+ This module contains code that implements the SEND_PACKET and
+ RECEIVE_PACKET objects, which describe NDIS packets used
+ by the transport.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) - 22-Sept-1995
+ BackFill optimization changes added under #if BACK_FILL
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+NTSTATUS
+IpxInitializeSendPacket(
+ IN PDEVICE Device,
+ IN PIPX_SEND_PACKET Packet,
+ IN PUCHAR Header
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes a send packet by chaining the
+ buffer for the header on it.
+
+Arguments:
+
+ Device - The device.
+
+ Packet - The packet to initialize.
+
+ Header - Points to storage for the header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ NDIS_STATUS NdisStatus;
+ NTSTATUS Status;
+ PNDIS_BUFFER NdisMacBuffer;
+ PNDIS_BUFFER NdisIpxBuffer;
+ PIPX_SEND_RESERVED Reserved;
+
+ IpxAllocateSendPacket (Device, Packet, &Status);
+
+ if (Status != STATUS_SUCCESS) {
+ // ERROR LOG
+ return Status;
+ }
+
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &NdisMacBuffer,
+ Device->NdisBufferPoolHandle,
+ Header,
+ MAC_HEADER_SIZE);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ IpxFreeSendPacket (Device, Packet);
+ // ERROR LOG
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &NdisIpxBuffer,
+ Device->NdisBufferPoolHandle,
+ Header + MAC_HEADER_SIZE,
+ IPX_HEADER_SIZE + RIP_PACKET_SIZE);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ IpxFreeSendPacket (Device, Packet);
+ // ERROR LOG
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ NdisChainBufferAtFront (PACKET(Packet), NdisMacBuffer);
+ NdisChainBufferAtBack (PACKET(Packet), NdisIpxBuffer);
+
+ //
+ // This flag optimizes the virtual to physical address X-ln
+ // in the MAC drivers on x86
+ //
+ NdisMacBuffer->MdlFlags|=MDL_NETWORK_HEADER;
+ NdisIpxBuffer->MdlFlags|=MDL_NETWORK_HEADER;
+
+ Reserved = SEND_RESERVED(Packet);
+ Reserved->Identifier = IDENTIFIER_IPX;
+ Reserved->SendInProgress = FALSE;
+ Reserved->Header = Header;
+ Reserved->HeaderBuffer = NdisMacBuffer;
+ Reserved->PaddingBuffer = NULL;
+#if BACK_FILL
+ Reserved->BackFill = FALSE;
+#endif
+
+ ExInterlockedInsertHeadList(
+ &Device->GlobalSendPacketList,
+ &Reserved->GlobalLinkage,
+ &Device->Lock);
+
+ return STATUS_SUCCESS;
+
+} /* IpxInitializeSendPacket */
+
+#if BACK_FILL
+NTSTATUS
+IpxInitializeBackFillPacket(
+ IN PDEVICE Device,
+ IN PIPX_SEND_PACKET Packet,
+ IN PUCHAR Header
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes a send packet by chaining the
+ buffer for the header on it.
+
+Arguments:
+
+ Device - The device.
+
+ Packet - The packet to initialize.
+
+ Header - Points to storage for the header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ NDIS_STATUS NdisStatus;
+ NTSTATUS Status;
+ PNDIS_BUFFER NdisMacBuffer;
+ PNDIS_BUFFER NdisIpxBuffer;
+ PIPX_SEND_RESERVED Reserved;
+
+
+ IPX_DEBUG (PACKET, ("Initializing backfill packet\n"));
+ IpxAllocateSendPacket (Device, Packet, &Status);
+
+ if (Status != STATUS_SUCCESS) {
+ // ERROR LOG
+ return Status;
+ }
+
+
+ Reserved = SEND_RESERVED(Packet);
+ Reserved->Identifier = IDENTIFIER_IPX;
+ Reserved->SendInProgress = FALSE;
+ Reserved->Header = NULL;
+ Reserved->HeaderBuffer = NULL;
+ Reserved->PaddingBuffer = NULL;
+ Reserved->BackFill = TRUE;
+
+ ExInterlockedInsertHeadList(
+ &Device->GlobalBackFillPacketList,
+ &Reserved->GlobalLinkage,
+ &Device->Lock);
+
+ IPX_DEBUG (PACKET, ("Initializing backfill packet Done\n"));
+ return STATUS_SUCCESS;
+
+} /* IpxInitializeBackFillPacket */
+#endif
+
+
+NTSTATUS
+IpxInitializeReceivePacket(
+ IN PDEVICE Device,
+ IN PIPX_RECEIVE_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes a receive packet.
+
+Arguments:
+
+ Device - The device.
+
+ Packet - The packet to initialize.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ NTSTATUS Status;
+ PIPX_RECEIVE_RESERVED Reserved;
+
+ IpxAllocateReceivePacket (Device, Packet, &Status);
+
+ if (Status != STATUS_SUCCESS) {
+ // ERROR LOG
+ return Status;
+ }
+
+ Reserved = RECEIVE_RESERVED(Packet);
+ Reserved->Identifier = IDENTIFIER_IPX;
+ Reserved->TransferInProgress = FALSE;
+ Reserved->SingleRequest = NULL;
+ Reserved->ReceiveBuffer = NULL;
+ InitializeListHead (&Reserved->Requests);
+
+ ExInterlockedInsertHeadList(
+ &Device->GlobalReceivePacketList,
+ &Reserved->GlobalLinkage,
+ &Device->Lock);
+
+ return STATUS_SUCCESS;
+
+} /* IpxInitializeReceivePacket */
+
+
+NTSTATUS
+IpxInitializeReceiveBuffer(
+ IN PADAPTER Adapter,
+ IN PIPX_RECEIVE_BUFFER ReceiveBuffer,
+ IN PUCHAR DataBuffer,
+ IN ULONG DataBufferLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes a receive buffer by allocating
+ an NDIS_BUFFER to describe the data buffer.
+
+Arguments:
+
+ Adapter - The adapter.
+
+ ReceiveBuffer - The receive buffer to initialize.
+
+ DataBuffer - The data buffer.
+
+ DataBufferLength - The length of the data buffer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ NDIS_STATUS NdisStatus;
+ PNDIS_BUFFER NdisBuffer;
+ PDEVICE Device = Adapter->Device;
+
+
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &NdisBuffer,
+ Device->NdisBufferPoolHandle,
+ DataBuffer,
+ DataBufferLength);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ // ERROR LOG
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ ReceiveBuffer->NdisBuffer = NdisBuffer;
+ ReceiveBuffer->Data = DataBuffer;
+ ReceiveBuffer->DataLength = 0;
+
+ ExInterlockedInsertHeadList(
+ &Device->GlobalReceiveBufferList,
+ &ReceiveBuffer->GlobalLinkage,
+ &Device->Lock);
+
+ return STATUS_SUCCESS;
+
+} /* IpxInitializeReceiveBuffer */
+
+
+NTSTATUS
+IpxInitializePaddingBuffer(
+ IN PDEVICE Device,
+ IN PIPX_PADDING_BUFFER PaddingBuffer,
+ IN ULONG DataBufferLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes a padding buffer by allocating
+ an NDIS_BUFFER to describe the data buffer.
+
+Arguments:
+
+ Adapter - The adapter.
+
+ PaddingBuffer - The receive buffer to initialize.
+
+ DataBufferLength - The length of the data buffer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ NDIS_STATUS NdisStatus;
+ PNDIS_BUFFER NdisBuffer;
+
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &NdisBuffer,
+ Device->NdisBufferPoolHandle,
+ PaddingBuffer->Data,
+ DataBufferLength);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ // ERROR LOG
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ NDIS_BUFFER_LINKAGE(NdisBuffer) = (PNDIS_BUFFER)NULL;
+ PaddingBuffer->NdisBuffer = NdisBuffer;
+ PaddingBuffer->DataLength = DataBufferLength;
+ RtlZeroMemory (PaddingBuffer->Data, DataBufferLength);
+
+ return STATUS_SUCCESS;
+
+} /* IpxInitializePaddingBuffer */
+
+
+VOID
+IpxDeinitializeSendPacket(
+ IN PDEVICE Device,
+ IN PIPX_SEND_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deinitializes a send packet.
+
+Arguments:
+
+ Device - The device.
+
+ Packet - The packet to deinitialize.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PNDIS_BUFFER NdisBuffer;
+ PNDIS_BUFFER NdisIpxBuffer;
+ PIPX_SEND_RESERVED Reserved;
+ CTELockHandle LockHandle;
+
+
+ Reserved = SEND_RESERVED(Packet);
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+ RemoveEntryList (&Reserved->GlobalLinkage);
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ //
+ // Free the packet in a slightly unconventional way; this
+ // allows us to not have to NULL out HeaderBuffer's linkage
+ // field during normal operations when we put it back in
+ // the free pool.
+ //
+
+ NdisBuffer = Reserved->HeaderBuffer;
+ NdisIpxBuffer = NDIS_BUFFER_LINKAGE(NdisBuffer);
+ NDIS_BUFFER_LINKAGE (NdisBuffer) = NULL;
+ NDIS_BUFFER_LINKAGE (NdisIpxBuffer) = NULL;
+
+#if 0
+ NdisAdjustBufferLength (NdisBuffer, PACKET_HEADER_SIZE);
+#endif
+ NdisAdjustBufferLength (NdisBuffer, MAC_HEADER_SIZE);
+ NdisAdjustBufferLength (NdisIpxBuffer, IPX_HEADER_SIZE + RIP_PACKET_SIZE);
+
+ NdisFreeBuffer (NdisBuffer);
+ NdisFreeBuffer (NdisIpxBuffer);
+
+ NdisReinitializePacket (PACKET(Packet));
+ IpxFreeSendPacket (Device, Packet);
+
+} /* IpxDeinitializeSendPacket */
+
+#if BACK_FILL
+VOID
+IpxDeinitializeBackFillPacket(
+ IN PDEVICE Device,
+ IN PIPX_SEND_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deinitializes a back fill packet.
+
+Arguments:
+
+ Device - The device.
+
+ Packet - The packet to deinitialize.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PNDIS_BUFFER NdisBuffer;
+ PNDIS_BUFFER NdisIpxBuffer;
+ PIPX_SEND_RESERVED Reserved;
+ CTELockHandle LockHandle;
+
+ IPX_DEBUG (PACKET, ("DeInitializing backfill packet\n"));
+
+ Reserved = SEND_RESERVED(Packet);
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+ RemoveEntryList (&Reserved->GlobalLinkage);
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+
+
+ NdisReinitializePacket (PACKET(Packet));
+ IpxFreeSendPacket (Device, Packet);
+ IPX_DEBUG (PACKET, ("DeInitializing backfill packet Done\n"));
+
+
+} /* IpxDeinitializeBackFillPacket */
+#endif
+
+
+VOID
+IpxDeinitializeReceivePacket(
+ IN PDEVICE Device,
+ IN PIPX_RECEIVE_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes a receive packet.
+
+Arguments:
+
+ Device - The device.
+
+ Packet - The packet to initialize.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PIPX_RECEIVE_RESERVED Reserved;
+ CTELockHandle LockHandle;
+
+ Reserved = RECEIVE_RESERVED(Packet);
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+ RemoveEntryList (&Reserved->GlobalLinkage);
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ IpxFreeReceivePacket (Device, Packet);
+
+} /* IpxDeinitializeReceivePacket */
+
+
+VOID
+IpxDeinitializeReceiveBuffer(
+ IN PADAPTER Adapter,
+ IN PIPX_RECEIVE_BUFFER ReceiveBuffer,
+ IN ULONG DataBufferLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deinitializes a receive buffer.
+
+Arguments:
+
+ Device - The device.
+
+ ReceiveBuffer - The receive buffer.
+
+ DataBufferLength - The allocated length of the receive buffer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ CTELockHandle LockHandle;
+ PDEVICE Device = Adapter->Device;
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+ RemoveEntryList (&ReceiveBuffer->GlobalLinkage);
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ NdisAdjustBufferLength (ReceiveBuffer->NdisBuffer, DataBufferLength);
+ NdisFreeBuffer (ReceiveBuffer->NdisBuffer);
+
+} /* IpxDeinitializeReceiveBuffer */
+
+
+VOID
+IpxDeinitializePaddingBuffer(
+ IN PDEVICE Device,
+ IN PIPX_PADDING_BUFFER PaddingBuffer,
+ IN ULONG DataBufferLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deinitializes a padding buffer.
+
+Arguments:
+
+ Device - The device.
+
+ PaddingBuffer - The padding buffer.
+
+ DataBufferLength - The allocated length of the padding buffer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ NdisAdjustBufferLength (PaddingBuffer->NdisBuffer, DataBufferLength);
+ NdisFreeBuffer (PaddingBuffer->NdisBuffer);
+
+} /* IpxDeinitializePaddingBuffer */
+
+
+
+#ifdef IPX_OWN_PACKETS
+VOID
+IpxAllocateSendPool(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds 10 packets to the pool for this device.
+
+Arguments:
+
+ Device - The device.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_POOL SendPool;
+ UINT SendPoolSize;
+ UINT PacketNum;
+ PIPX_SEND_PACKET Packet;
+ PIPX_SEND_RESERVED Reserved;
+ PUCHAR Header;
+ CTELockHandle LockHandle;
+
+
+ SendPoolSize = FIELD_OFFSET (IPX_SEND_POOL, Packets[0]) +
+ (sizeof(IPX_SEND_PACKET) * Device->InitDatagrams) +
+ (PACKET_HEADER_SIZE * Device->InitDatagrams);
+
+
+ SendPool = (PIPX_SEND_POOL)IpxAllocateMemory (SendPoolSize, MEMORY_PACKET, "SendPool");
+ if (SendPool == NULL) {
+ IPX_DEBUG (PACKET, ("Could not allocate send pool memory\n"));
+ return;
+ }
+
+
+ IPX_DEBUG (PACKET, ("Initializing send pool %lx, %d packets\n",
+ SendPool, Device->InitDatagrams));
+
+ Header = (PUCHAR)(&SendPool->Packets[Device->InitDatagrams]);
+
+ for (PacketNum = 0; PacketNum < Device->InitDatagrams; PacketNum++) {
+
+ Packet = &SendPool->Packets[PacketNum];
+
+ if (IpxInitializeSendPacket (Device, Packet, Header) != STATUS_SUCCESS) {
+ IPX_DEBUG (PACKET, ("Could not initialize packet %lx\n", Packet));
+ break;
+ }
+
+ Reserved = SEND_RESERVED(Packet);
+ Reserved->Address = NULL;
+ Reserved->OwnedByAddress = FALSE;
+#ifdef IPX_TRACK_POOL
+ Reserved->Pool = SendPool;
+#endif
+
+ Header += PACKET_HEADER_SIZE;
+
+ }
+
+ SendPool->PacketCount = PacketNum;
+ SendPool->PacketFree = PacketNum;
+
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ for (PacketNum = 0; PacketNum < SendPool->PacketCount; PacketNum++) {
+
+ Packet = &SendPool->Packets[PacketNum];
+ Reserved = SEND_RESERVED(Packet);
+ IPX_PUSH_ENTRY_LIST (&Device->SendPacketList, &Reserved->PoolLinkage, &Device->SListsLock);
+
+ }
+
+ InsertTailList (&Device->SendPoolList, &SendPool->Linkage);
+
+ Device->AllocatedDatagrams += SendPool->PacketCount;
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+} /* IpxAllocateSendPool */
+
+#if BACK_FILL
+
+VOID
+IpxAllocateBackFillPool(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds 10 packets to the pool for this device.
+
+Arguments:
+
+ Device - The device.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_POOL SendPool;
+ UINT SendPoolSize;
+ UINT PacketNum;
+ PIPX_SEND_PACKET Packet;
+ PIPX_SEND_RESERVED Reserved;
+ PUCHAR Header;
+ CTELockHandle LockHandle;
+
+ PIPX_SEND_POOL BackFillPool;
+ UINT BackFillPoolSize;
+
+ IPX_DEBUG (PACKET, ("Allocating backfill pool\n"));
+
+
+ BackFillPoolSize = FIELD_OFFSET (IPX_SEND_POOL, Packets[0]) +
+ (sizeof(IPX_SEND_PACKET) * Device->InitDatagrams);
+
+
+ // Allocate pool for back fillable packets
+
+ BackFillPool = (PIPX_SEND_POOL)IpxAllocateMemory (BackFillPoolSize, MEMORY_PACKET, "BafiPool");
+
+ if (BackFillPool == NULL) {
+ IPX_DEBUG (PACKET, ("Could not allocate BackFill pool memory\n"));
+ return;
+ }
+
+
+
+
+
+ for (PacketNum = 0; PacketNum < Device->InitDatagrams; PacketNum++) {
+
+ Packet = &BackFillPool->Packets[PacketNum];
+
+ if (IpxInitializeBackFillPacket (Device, Packet, NULL) != STATUS_SUCCESS) {
+ IPX_DEBUG (PACKET, ("Could not initialize packet %lx\n", Packet));
+ break;
+ }
+
+ Reserved = SEND_RESERVED(Packet);
+ Reserved->Address = NULL;
+ Reserved->OwnedByAddress = FALSE;
+#ifdef IPX_TRACK_POOL
+ Reserved->Pool = BackFillPool;
+#endif
+
+
+ }
+
+ BackFillPool->PacketCount = PacketNum;
+ BackFillPool->PacketFree = PacketNum;
+
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ for (PacketNum = 0; PacketNum < BackFillPool->PacketCount; PacketNum++) {
+
+ Packet = &BackFillPool->Packets[PacketNum];
+ Reserved = SEND_RESERVED(Packet);
+ IPX_PUSH_ENTRY_LIST (&Device->BackFillPacketList, &Reserved->PoolLinkage, &Device->SListsLock);
+
+ }
+
+ InsertTailList (&Device->BackFillPoolList, &BackFillPool->Linkage);
+
+
+ IPX_DEBUG (PACKET, ("Allocation of backfill pool done\n"));
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+} /* IpxAllocateBackFillPool */
+
+#endif
+
+
+VOID
+IpxAllocateReceivePool(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds receive packets to the pool for this device.
+
+Arguments:
+
+ Device - The device.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_RECEIVE_POOL ReceivePool;
+ UINT ReceivePoolSize;
+ UINT PacketNum;
+ PIPX_RECEIVE_PACKET Packet;
+ PIPX_RECEIVE_RESERVED Reserved;
+ CTELockHandle LockHandle;
+
+ ReceivePoolSize = FIELD_OFFSET (IPX_RECEIVE_POOL, Packets[0]) +
+ (sizeof(IPX_RECEIVE_PACKET) * Device->InitReceivePackets);
+
+ ReceivePool = (PIPX_RECEIVE_POOL)IpxAllocateMemory (ReceivePoolSize, MEMORY_PACKET, "ReceivePool");
+ if (ReceivePool == NULL) {
+ IPX_DEBUG (PACKET, ("Could not allocate receive pool memory\n"));
+ return;
+ }
+
+ IPX_DEBUG (PACKET, ("Initializing receive pool %lx, %d packets\n",
+ ReceivePool, Device->InitReceivePackets));
+
+ for (PacketNum = 0; PacketNum < Device->InitReceivePackets; PacketNum++) {
+
+ Packet = &ReceivePool->Packets[PacketNum];
+
+ if (IpxInitializeReceivePacket (Device, Packet) != STATUS_SUCCESS) {
+ IPX_DEBUG (PACKET, ("Could not initialize packet %lx\n", Packet));
+ break;
+ }
+
+ Reserved = RECEIVE_RESERVED(Packet);
+ Reserved->Address = NULL;
+ Reserved->OwnedByAddress = FALSE;
+#ifdef IPX_TRACK_POOL
+ Reserved->Pool = ReceivePool;
+#endif
+
+ }
+
+ ReceivePool->PacketCount = PacketNum;
+ ReceivePool->PacketFree = PacketNum;
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ for (PacketNum = 0; PacketNum < ReceivePool->PacketCount; PacketNum++) {
+
+ Packet = &ReceivePool->Packets[PacketNum];
+ Reserved = RECEIVE_RESERVED(Packet);
+ IPX_PUSH_ENTRY_LIST (&Device->ReceivePacketList, &Reserved->PoolLinkage, &Device->SListsLock);
+
+ }
+
+ InsertTailList (&Device->ReceivePoolList, &ReceivePool->Linkage);
+
+ Device->AllocatedReceivePackets += ReceivePool->PacketCount;
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+} /* IpxAllocateReceivePool */
+
+
+#else // IPX_OWN_PACKETS
+VOID
+IpxAllocateSendPool(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds 10 packets to the pool for this device.
+
+Arguments:
+
+ Device - The device.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_POOL SendPool;
+ UINT HeaderSize;
+ UINT PacketNum;
+ IPX_SEND_PACKET Packet;
+ PIPX_SEND_RESERVED Reserved;
+ PUCHAR Header;
+ NDIS_STATUS Status;
+
+ CTELockHandle LockHandle;
+
+ SendPool = (PIPX_SEND_POOL)IpxAllocateMemory (sizeof(IPX_SEND_POOL), MEMORY_PACKET, "SendPool");
+
+ if (SendPool == NULL) {
+ IPX_DEBUG (PACKET, ("Could not allocate send pool memory\n"));
+ return;
+ }
+
+ HeaderSize = PACKET_HEADER_SIZE * Device->InitDatagrams;
+
+ Header = (PUCHAR)IpxAllocateMemory (HeaderSize, MEMORY_PACKET, "SendPool");
+
+ if (Header == NULL) {
+ IPX_DEBUG (PACKET, ("Could not allocate header memory\n"));
+ return;
+ }
+
+ NdisAllocatePacketPool(&Status, &SendPool->PoolHandle, Device->InitDatagrams, sizeof(IPX_SEND_RESERVED));
+
+ if (Status == NDIS_STATUS_RESOURCES) {
+ IPX_DEBUG (PACKET, ("Could not allocate Ndis pool memory\n"));
+ return;
+ }
+
+ Device->MemoryUsage += (FIELD_OFFSET(NDIS_PACKET_POOL,Buffer[0]) +
+ Device->InitDatagrams * (FIELD_OFFSET(NDIS_PACKET,ProtocolReserved[0]) + sizeof(IPX_SEND_RESERVED)));
+
+ IPX_DEBUG (PACKET, ("Initializing send pool %lx, %d packets\n",
+ SendPool, Device->InitDatagrams));
+
+ SendPool->Header = Header;
+
+ for (PacketNum = 0; PacketNum < Device->InitDatagrams; PacketNum++) {
+
+ NdisAllocatePacket(&Status, &PACKET(&Packet), SendPool->PoolHandle);
+
+ if (IpxInitializeSendPacket (Device, &Packet, Header) != STATUS_SUCCESS) {
+ IPX_DEBUG (PACKET, ("Could not initialize packet %lx\n", Packet));
+ break;
+ }
+
+ Reserved = SEND_RESERVED(&Packet);
+ Reserved->Address = NULL;
+ Reserved->OwnedByAddress = FALSE;
+#ifdef IPX_TRACK_POOL
+ Reserved->Pool = SendPool;
+#endif
+
+ IPX_PUSH_ENTRY_LIST (&Device->SendPacketList, &Reserved->PoolLinkage, &Device->SListsLock);
+
+ Header += PACKET_HEADER_SIZE;
+
+ }
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ Device->AllocatedDatagrams += PacketNum;
+ InsertTailList (&Device->SendPoolList, &SendPool->Linkage);
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+} /* IpxAllocateSendPool */
+
+
+#if BACK_FILL
+
+VOID
+IpxAllocateBackFillPool(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds 10 packets to the pool for this device.
+
+Arguments:
+
+ Device - The device.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UINT PacketNum;
+ IPX_SEND_PACKET Packet;
+ PIPX_SEND_RESERVED Reserved;
+ CTELockHandle LockHandle;
+ PIPX_SEND_POOL BackFillPool;
+ NDIS_STATUS Status;
+
+ IPX_DEBUG (PACKET, ("Allocating backfill pool\n"));
+
+ // Allocate pool for back fillable packets
+
+ BackFillPool = (PIPX_SEND_POOL)IpxAllocateMemory (sizeof(IPX_SEND_POOL), MEMORY_PACKET, "BafiPool");
+
+ if (BackFillPool == NULL) {
+ IPX_DEBUG (PACKET, ("Could not allocate backfill pool memory\n"));
+ return;
+ }
+
+ NdisAllocatePacketPool(&Status, &BackFillPool->PoolHandle, Device->InitDatagrams, sizeof(IPX_SEND_RESERVED));
+
+ if (Status == NDIS_STATUS_RESOURCES) {
+ IPX_DEBUG (PACKET, ("Could not allocate Ndis pool memory\n"));
+ return;
+ }
+
+ Device->MemoryUsage += (FIELD_OFFSET(NDIS_PACKET_POOL,Buffer[0]) +
+ Device->InitDatagrams * (FIELD_OFFSET(NDIS_PACKET,ProtocolReserved[0]) + sizeof(IPX_SEND_RESERVED)));
+
+ for (PacketNum = 0; PacketNum < Device->InitDatagrams; PacketNum++) {
+
+ NdisAllocatePacket(&Status, &PACKET(&Packet), BackFillPool->PoolHandle);
+
+ if (IpxInitializeBackFillPacket (Device, &Packet, NULL) != STATUS_SUCCESS) {
+ IPX_DEBUG (PACKET, ("Could not initialize packet %lx\n", Packet));
+ break;
+ }
+
+ Reserved = SEND_RESERVED(&Packet);
+ Reserved->Address = NULL;
+ Reserved->OwnedByAddress = FALSE;
+#ifdef IPX_TRACK_POOL
+ Reserved->Pool = BackFillPool;
+#endif
+
+ IPX_PUSH_ENTRY_LIST (&Device->BackFillPacketList, &Reserved->PoolLinkage, &Device->SListsLock);
+ }
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ InsertTailList (&Device->BackFillPoolList, &BackFillPool->Linkage);
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+} /* IpxAllocateBackFillPool */
+
+#endif
+
+
+VOID
+IpxAllocateReceivePool(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds receive packets to the pool for this device.
+
+Arguments:
+
+ Device - The device.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_RECEIVE_POOL ReceivePool;
+ UINT PacketNum;
+ IPX_RECEIVE_PACKET Packet;
+ PIPX_RECEIVE_RESERVED Reserved;
+ CTELockHandle LockHandle;
+ NDIS_STATUS Status;
+
+ ReceivePool = (PIPX_SEND_POOL)IpxAllocateMemory (sizeof(IPX_RECEIVE_POOL), MEMORY_PACKET, "ReceivePool");
+
+ if (ReceivePool == NULL) {
+ IPX_DEBUG (PACKET, ("Could not allocate receive pool memory\n"));
+ return;
+ }
+
+ NdisAllocatePacketPool(&Status, &ReceivePool->PoolHandle, Device->InitDatagrams, sizeof(IPX_SEND_RESERVED));
+
+ if (Status == NDIS_STATUS_RESOURCES) {
+ IPX_DEBUG (PACKET, ("Could not allocate receive pool memory\n"));
+ return;
+ }
+
+ IPX_DEBUG (PACKET, ("Initializing receive pool %lx, %d packets\n",
+ ReceivePool, Device->InitReceivePackets));
+
+ Device->MemoryUsage += (FIELD_OFFSET(NDIS_PACKET_POOL,Buffer[0]) +
+ Device->InitReceivePackets * (FIELD_OFFSET(NDIS_PACKET,ProtocolReserved[0]) + sizeof(IPX_RECEIVE_RESERVED)));
+
+ for (PacketNum = 0; PacketNum < Device->InitReceivePackets; PacketNum++) {
+
+ NdisAllocatePacket(&Status, &PACKET(&Packet), ReceivePool->PoolHandle);
+
+ if (IpxInitializeReceivePacket (Device, &Packet) != STATUS_SUCCESS) {
+ IPX_DEBUG (PACKET, ("Could not initialize packet %lx\n", Packet));
+ break;
+ }
+
+ Reserved = RECEIVE_RESERVED(&Packet);
+ Reserved->Address = NULL;
+ Reserved->OwnedByAddress = FALSE;
+#ifdef IPX_TRACK_POOL
+ Reserved->Pool = ReceivePool;
+#endif
+
+ IPX_PUSH_ENTRY_LIST (&Device->ReceivePacketList, &Reserved->PoolLinkage, &Device->SListsLock);
+
+ }
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ Device->AllocatedReceivePackets += PacketNum;
+
+ InsertTailList (&Device->ReceivePoolList, &ReceivePool->Linkage);
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+} /* IpxAllocateReceivePool */
+#endif // IPX_OWN_PACKETS
+
+VOID
+IpxAllocateReceiveBufferPool(
+ IN PADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds receive buffers to the pool for this adapter.
+
+Arguments:
+
+ Adapter - The adapter.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_RECEIVE_BUFFER ReceiveBuffer;
+ UINT ReceiveBufferPoolSize;
+ UINT BufferNum;
+ PIPX_RECEIVE_BUFFER_POOL ReceiveBufferPool;
+ PDEVICE Device = Adapter->Device;
+ UINT DataLength;
+ PUCHAR Data;
+ CTELockHandle LockHandle;
+
+ DataLength = Adapter->MaxReceivePacketSize;
+
+ ReceiveBufferPoolSize = FIELD_OFFSET (IPX_RECEIVE_BUFFER_POOL, Buffers[0]) +
+ (sizeof(IPX_RECEIVE_BUFFER) * Device->InitReceiveBuffers) +
+ (DataLength * Device->InitReceiveBuffers);
+
+ ReceiveBufferPool = (PIPX_RECEIVE_BUFFER_POOL)IpxAllocateMemory (ReceiveBufferPoolSize, MEMORY_PACKET, "ReceiveBufferPool");
+ if (ReceiveBufferPool == NULL) {
+ IPX_DEBUG (PACKET, ("Could not allocate receive buffer pool memory\n"));
+ return;
+ }
+
+ IPX_DEBUG (PACKET, ("Init recv buffer pool %lx, %d buffers, data %d\n",
+ ReceiveBufferPool, Device->InitReceiveBuffers, DataLength));
+
+ Data = (PUCHAR)(&ReceiveBufferPool->Buffers[Device->InitReceiveBuffers]);
+
+
+ for (BufferNum = 0; BufferNum < Device->InitReceiveBuffers; BufferNum++) {
+
+ ReceiveBuffer = &ReceiveBufferPool->Buffers[BufferNum];
+
+ if (IpxInitializeReceiveBuffer (Adapter, ReceiveBuffer, Data, DataLength) != STATUS_SUCCESS) {
+ IPX_DEBUG (PACKET, ("Could not initialize buffer %lx\n", ReceiveBuffer));
+ break;
+ }
+
+#ifdef IPX_TRACK_POOL
+ ReceiveBuffer->Pool = ReceiveBufferPool;
+#endif
+
+ Data += DataLength;
+
+ }
+
+ ReceiveBufferPool->BufferCount = BufferNum;
+ ReceiveBufferPool->BufferFree = BufferNum;
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ for (BufferNum = 0; BufferNum < ReceiveBufferPool->BufferCount; BufferNum++) {
+
+ ReceiveBuffer = &ReceiveBufferPool->Buffers[BufferNum];
+ IPX_PUSH_ENTRY_LIST (&Adapter->ReceiveBufferList, &ReceiveBuffer->PoolLinkage, &Device->SListsLock);
+
+ }
+
+ InsertTailList (&Adapter->ReceiveBufferPoolList, &ReceiveBufferPool->Linkage);
+
+ Adapter->AllocatedReceiveBuffers += ReceiveBufferPool->BufferCount;
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+} /* IpxAllocateReceiveBufferPool */
+
+
+PSINGLE_LIST_ENTRY
+IpxPopSendPacket(
+ PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates a packet from the device context's pool.
+ If there are no packets in the pool, it allocates one up to
+ the configured limit.
+
+Arguments:
+
+ Device - Pointer to our device to charge the packet to.
+
+Return Value:
+
+ The pointer to the Linkage field in the allocated packet.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+
+ s = IPX_POP_ENTRY_LIST(
+ &Device->SendPacketList,
+ &Device->SListsLock);
+
+ if (s != NULL) {
+ return s;
+ }
+
+ //
+ // No packets in the pool, see if we can allocate more.
+ //
+
+ if (Device->AllocatedDatagrams < Device->MaxDatagrams) {
+
+ //
+ // Allocate a pool and try again.
+ //
+
+ IpxAllocateSendPool (Device);
+ s = IPX_POP_ENTRY_LIST(
+ &Device->SendPacketList,
+ &Device->SListsLock);
+
+ return s;
+
+ } else {
+
+ return NULL;
+
+ }
+
+} /* IpxPopSendPacket */
+
+#if BACK_FILL
+
+PSINGLE_LIST_ENTRY
+IpxPopBackFillPacket(
+ PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates a packet from the device context's pool.
+ If there are no packets in the pool, it allocates one up to
+ the configured limit.
+
+Arguments:
+
+ Device - Pointer to our device to charge the packet to.
+
+Return Value:
+
+ The pointer to the Linkage field in the allocated packet.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+
+ IPX_DEBUG (PACKET, ("Popping backfill packet\n"));
+
+
+ s = IPX_POP_ENTRY_LIST(
+ &Device->BackFillPacketList,
+ &Device->SListsLock);
+
+ if (s != NULL) {
+ return s;
+ }
+
+ //
+ // No packets in the pool, see if we can allocate more.
+ //
+
+ if (Device->AllocatedDatagrams < Device->MaxDatagrams) {
+
+ //
+ // Allocate a pool and try again.
+ //
+
+ IpxAllocateBackFillPool (Device);
+ s = IPX_POP_ENTRY_LIST(
+ &Device->BackFillPacketList,
+ &Device->SListsLock);
+
+
+ IPX_DEBUG (PACKET, ("Popping backfill packet done\n"));
+ return s;
+
+ } else {
+
+ return NULL;
+
+ }
+
+} /* IpxPopBackFillPacket */
+#endif //BackFill
+
+
+PSINGLE_LIST_ENTRY
+IpxPopReceivePacket(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates a packet from the device context's pool.
+ If there are no packets in the pool, it allocates one up to
+ the configured limit.
+
+Arguments:
+
+ Device - Pointer to our device to charge the packet to.
+
+Return Value:
+
+ The pointer to the Linkage field in the allocated packet.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+
+ s = IPX_POP_ENTRY_LIST(
+ &Device->ReceivePacketList,
+ &Device->SListsLock);
+
+ if (s != NULL) {
+ return s;
+ }
+
+ //
+ // No packets in the pool, see if we can allocate more.
+ //
+
+ if (Device->AllocatedReceivePackets < Device->MaxReceivePackets) {
+
+ //
+ // Allocate a pool and try again.
+ //
+
+ IpxAllocateReceivePool (Device);
+ s = IPX_POP_ENTRY_LIST(
+ &Device->ReceivePacketList,
+ &Device->SListsLock);
+
+ return s;
+
+ } else {
+
+ return NULL;
+
+ }
+
+} /* IpxPopReceivePacket */
+
+
+PSINGLE_LIST_ENTRY
+IpxPopReceiveBuffer(
+ IN PADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates a receive buffer from the adapter's pool.
+ If there are no buffers in the pool, it allocates one up to
+ the configured limit.
+
+Arguments:
+
+ Adapter - Pointer to our adapter to charge the buffer to.
+
+Return Value:
+
+ The pointer to the Linkage field in the allocated receive buffer.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+ PDEVICE Device = Adapter->Device;
+
+ s = IPX_POP_ENTRY_LIST(
+ &Adapter->ReceiveBufferList,
+ &Device->SListsLock);
+
+ if (s != NULL) {
+ return s;
+ }
+
+ //
+ // No buffer in the pool, see if we can allocate more.
+ //
+
+ if (Adapter->AllocatedReceiveBuffers < Device->MaxReceiveBuffers) {
+
+ //
+ // Allocate a pool and try again.
+ //
+
+ IpxAllocateReceiveBufferPool (Adapter);
+ s = IPX_POP_ENTRY_LIST(
+ &Adapter->ReceiveBufferList,
+ &Device->SListsLock);
+
+ return s;
+
+ } else {
+
+ return NULL;
+
+ }
+
+} /* IpxPopReceiveBuffer */
+
+
+PIPX_PADDING_BUFFER
+IpxAllocatePaddingBuffer(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates a padding buffer for use by all devices.
+
+Arguments:
+
+ Device - Pointer to our device to charge the packet to.
+
+Return Value:
+
+ The pointer to the allocated padding buffer.
+
+--*/
+
+{
+ PIPX_PADDING_BUFFER PaddingBuffer;
+ ULONG PaddingBufferSize;
+
+ //
+ // We are assuming that we can use 1 global padding buffer for ALL
+ // transmits! We must therefore test to make sure that EthernetExtraPadding
+ // is not greater than 1. Otherwise, we must assume that the extra padding
+ // is being used for something and we therefore cannot share across all
+ // transmit requests.
+ //
+
+ //
+ // We cannot support more than 1 byte padding space, since we allocate only
+ // one buffer for all transmit requests.
+ //
+
+ if ( Device->EthernetExtraPadding > 1 ) {
+ IPX_DEBUG (PACKET, ("Padding buffer cannot be more than 1 byte\n"));
+ DbgBreakPoint();
+ }
+
+ //
+ // Allocate a padding buffer if possible.
+ //
+
+ PaddingBufferSize = FIELD_OFFSET (IPX_PADDING_BUFFER, Data[0]) + Device->EthernetExtraPadding;
+
+ PaddingBuffer = IpxAllocateMemory (PaddingBufferSize, MEMORY_PACKET, "PaddingBuffer");
+
+ if (PaddingBuffer != NULL) {
+
+ if (IpxInitializePaddingBuffer (Device, PaddingBuffer, Device->EthernetExtraPadding) !=
+ STATUS_SUCCESS) {
+ IpxFreeMemory (PaddingBuffer, PaddingBufferSize, MEMORY_PACKET, "Padding Buffer");
+ } else {
+ IPX_DEBUG (PACKET, ("Allocate padding buffer %lx\n", PaddingBuffer));
+ return PaddingBuffer;
+ }
+ }
+
+ return NULL;
+
+} /* IpxAllocatePaddingBuffer */
+
+
+VOID
+IpxFreePaddingBuffer(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deallocates the padding buffer.
+
+Arguments:
+
+ Device - Pointer to our device to charge the packet to.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ ULONG PaddingBufferSize;
+
+ if ( IpxPaddingBuffer == (PIPX_PADDING_BUFFER)NULL ) {
+ return;
+ }
+
+ PaddingBufferSize = FIELD_OFFSET (IPX_PADDING_BUFFER, Data[0]) + Device->EthernetExtraPadding;
+ IpxFreeMemory( IpxPaddingBuffer, PaddingBufferSize, MEMORY_PACKET, "Padding Buffer" );
+ IpxPaddingBuffer = (PIPX_PADDING_BUFFER)NULL;
+
+} /* IpxFreePaddingBuffer */
+
diff --git a/private/ntos/tdi/isnp/ipx/precomp.h b/private/ntos/tdi/isnp/ipx/precomp.h
new file mode 100644
index 000000000..818629e5e
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/precomp.h
@@ -0,0 +1,44 @@
+/*++
+
+Copyright (c) 1993-1995 Microsoft Corporation
+
+Module Name:
+
+ precomp.h
+
+Abstract:
+
+ Precompilation header file.
+
+Author:
+
+ Adam Barr (adamba) 08-Sep-1993
+
+Revision History:
+
+--*/
+
+
+#define ISN_NT 1
+
+//
+// These are needed for CTE
+//
+
+#if DBG
+#define DEBUG 1
+#endif
+
+#define NT 1
+
+#include <ntos.h>
+#include <tdikrnl.h>
+#include <ndis.h>
+#include <cxport.h>
+#include <bind.h>
+#include "isnipx.h"
+#include "config.h"
+#include "mac.h"
+#include "ipxtypes.h"
+#include "ipxprocs.h"
+#include <wsnwlink.h>
diff --git a/private/ntos/tdi/isnp/ipx/query.c b/private/ntos/tdi/isnp/ipx/query.c
new file mode 100644
index 000000000..28b38df5c
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/query.c
@@ -0,0 +1,297 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ query.c
+
+Abstract:
+
+ This module contains code which performs the following TDI services:
+
+ o TdiQueryInformation
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+//
+// Useful macro to obtain the total length of an MDL chain.
+//
+
+#define IpxGetMdlChainLength(Mdl, Length) { \
+ PMDL _Mdl = (Mdl); \
+ *(Length) = 0; \
+ while (_Mdl) { \
+ *(Length) += MmGetMdlByteCount(_Mdl); \
+ _Mdl = _Mdl->Next; \
+ } \
+}
+
+
+
+NTSTATUS
+IpxTdiQueryInformation(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiQueryInformation request for the transport
+ provider.
+
+Arguments:
+
+ Request - the request for the operation.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ PTDI_REQUEST_KERNEL_QUERY_INFORMATION query;
+ PADDRESS_FILE AddressFile;
+ ULONG ElementSize, TransportAddressSize;
+ PTRANSPORT_ADDRESS TransportAddress;
+ TA_ADDRESS UNALIGNED * CurAddress;
+ PBINDING Binding;
+ union {
+ struct {
+ ULONG ActivityCount;
+ TA_IPX_ADDRESS IpxAddress;
+ } AddressInfo;
+ TDI_DATAGRAM_INFO DatagramInfo;
+ TDI_ADDRESS_IPX IpxAddress;
+ } TempBuffer;
+ UINT i;
+
+#ifdef _PNP_POWER
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+#endif
+
+ //
+ // what type of status do we want?
+ //
+
+ query = (PTDI_REQUEST_KERNEL_QUERY_INFORMATION)REQUEST_PARAMETERS(Request);
+
+ switch (query->QueryType) {
+
+ case TDI_QUERY_ADDRESS_INFO:
+
+ //
+ // The caller wants the exact address value.
+ //
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+
+ status = IpxVerifyAddressFile (AddressFile);
+
+ if (status == STATUS_SUCCESS) {
+
+ TempBuffer.AddressInfo.ActivityCount = 0;
+
+ IpxBuildTdiAddress(
+ &TempBuffer.AddressInfo.IpxAddress,
+ Device->SourceAddress.NetworkAddress,
+ Device->SourceAddress.NodeAddress,
+ AddressFile->Address->Socket);
+
+ status = TdiCopyBufferToMdl(
+ &TempBuffer.AddressInfo,
+ 0,
+ sizeof(TempBuffer.AddressInfo),
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+
+ IpxDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+
+ }
+
+ break;
+
+ case TDI_QUERY_PROVIDER_INFO:
+
+ status = TdiCopyBufferToMdl (
+ &(Device->Information),
+ 0,
+ sizeof (TDI_PROVIDER_INFO),
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+ break;
+
+ case TDI_QUERY_PROVIDER_STATISTICS:
+
+ status = TdiCopyBufferToMdl (
+ &Device->Statistics,
+ 0,
+ FIELD_OFFSET (TDI_PROVIDER_STATISTICS, ResourceStats[0]),
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+ break;
+
+ case TDI_QUERY_DATAGRAM_INFO:
+
+ TempBuffer.DatagramInfo.MaximumDatagramBytes = 0;
+ TempBuffer.DatagramInfo.MaximumDatagramCount = 0;
+
+ status = TdiCopyBufferToMdl (
+ &TempBuffer.DatagramInfo,
+ 0,
+ sizeof(TempBuffer.DatagramInfo),
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+ break;
+
+ case TDI_QUERY_DATA_LINK_ADDRESS:
+ case TDI_QUERY_NETWORK_ADDRESS:
+
+ if (query->QueryType == TDI_QUERY_DATA_LINK_ADDRESS) {
+ ElementSize = (2 * sizeof(USHORT)) + 6;
+ } else {
+ ElementSize = (2 * sizeof(USHORT)) + sizeof(TDI_ADDRESS_IPX);
+ }
+
+ TransportAddress = IpxAllocateMemory(sizeof(int) + (ElementSize * MIN (Device->MaxBindings, Device->ValidBindings)), MEMORY_QUERY, "NetworkAddress");
+
+ if (TransportAddress == NULL) {
+
+ status = STATUS_INSUFFICIENT_RESOURCES;
+
+ } else {
+
+ TransportAddress->TAAddressCount = 0;
+ TransportAddressSize = sizeof(int);
+ CurAddress = (TA_ADDRESS UNALIGNED *)TransportAddress->Address;
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ {
+ ULONG Index = MIN (Device->MaxBindings, Device->ValidBindings);
+
+ for (i = 1; i <= Index; i++) {
+
+ Binding = NIC_ID_TO_BINDING(Device, i);
+ if ((Binding == NULL) ||
+ (!Binding->LineUp)) {
+ continue;
+ }
+
+ if (query->QueryType == TDI_QUERY_DATA_LINK_ADDRESS) {
+ CurAddress->AddressLength = 6;
+ CurAddress->AddressType = Binding->Adapter->MacInfo.RealMediumType;
+ RtlCopyMemory (CurAddress->Address, Binding->LocalAddress.NodeAddress, 6);
+ } else {
+ CurAddress->AddressLength = sizeof(TDI_ADDRESS_IPX);
+ CurAddress->AddressType = TDI_ADDRESS_TYPE_IPX;
+ RtlCopyMemory (CurAddress->Address, &Binding->LocalAddress, sizeof(TDI_ADDRESS_IPX));
+ }
+ ++TransportAddress->TAAddressCount;
+ TransportAddressSize += ElementSize;
+ CurAddress = (TA_ADDRESS UNALIGNED *)(((PUCHAR)CurAddress) + ElementSize);
+
+ }
+ }
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+ for (i = 1; i <= Device->ValidBindings; i++) {
+
+ Binding = Device->Bindings[i];
+ if ((Binding == NULL) ||
+ (!Binding->LineUp)) {
+ continue;
+ }
+
+ if (query->QueryType == TDI_QUERY_DATA_LINK_ADDRESS) {
+ CurAddress->AddressLength = 6;
+ CurAddress->AddressType = Binding->Adapter->MacInfo.RealMediumType;
+ RtlCopyMemory (CurAddress->Address, Binding->LocalAddress.NodeAddress, 6);
+ } else {
+ CurAddress->AddressLength = sizeof(TDI_ADDRESS_IPX);
+ CurAddress->AddressType = TDI_ADDRESS_TYPE_IPX;
+ RtlCopyMemory (CurAddress->Address, &Binding->LocalAddress, sizeof(TDI_ADDRESS_IPX));
+ }
+ ++TransportAddress->TAAddressCount;
+ TransportAddressSize += ElementSize;
+ CurAddress = (TA_ADDRESS UNALIGNED *)(((PUCHAR)CurAddress) + ElementSize);
+
+ }
+#endif
+ status = TdiCopyBufferToMdl (
+ TransportAddress,
+ 0,
+ TransportAddressSize,
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+
+ CTEFreeMem (TransportAddress);
+
+ }
+
+ break;
+
+ default:
+
+ status = STATUS_INVALID_DEVICE_REQUEST;
+ break;
+ }
+
+ return status;
+
+} /* IpxTdiQueryInformation */
+
+
+NTSTATUS
+IpxTdiSetInformation(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiSetInformation request for the transport
+ provider.
+
+Arguments:
+
+ Device - the device.
+
+ Request - the request for the operation.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER (Device);
+ UNREFERENCED_PARAMETER (Request);
+
+ return STATUS_NOT_IMPLEMENTED;
+
+} /* IpxTdiSetInformation */
+
+
diff --git a/private/ntos/tdi/isnp/ipx/receive.c b/private/ntos/tdi/isnp/ipx/receive.c
new file mode 100644
index 000000000..ff9c68fbd
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/receive.c
@@ -0,0 +1,466 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ receive.c
+
+Abstract:
+
+ This module contains code which performs the following TDI services:
+
+ o TdiReceiveDatagram
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+
+VOID
+IpxTransferDataComplete(
+ IN NDIS_HANDLE BindingContext,
+ IN PNDIS_PACKET NdisPacket,
+ IN NDIS_STATUS NdisStatus,
+ IN UINT BytesTransferred
+ )
+
+/*++
+
+Routine Description:
+
+ This routine receives control from the physical provider as an
+ indication that an NdisTransferData has completed. We use this indication
+ to complete any pended requests to our clients.
+
+Arguments:
+
+ BindingContext - The Adapter Binding specified at initialization time.
+
+ NdisPacket/RequestHandle - An identifier for the request that completed.
+
+ NdisStatus - The completion status for the request.
+
+ BytesTransferred - Number of bytes actually transferred.
+
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PADAPTER Adapter = (PADAPTER)BindingContext;
+ PIPX_RECEIVE_RESERVED Reserved = (PIPX_RECEIVE_RESERVED)(NdisPacket->ProtocolReserved);
+ PREQUEST Request, LastRequest;
+ PADDRESS_FILE AddressFile;
+ ULONG ByteOffset;
+ PLIST_ENTRY p;
+ PDEVICE Device;
+
+
+ switch (Reserved->Identifier) {
+
+ case IDENTIFIER_IPX:
+
+ if (Reserved->SingleRequest) {
+
+ //
+ // The transfer was directly into the client buffer,
+ // so simply complete the request.
+ //
+
+ Request = Reserved->SingleRequest;
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS) {
+
+ IPX_DEBUG (RECEIVE, ("Transferred %d bytes\n", BytesTransferred));
+ REQUEST_INFORMATION(Request) = BytesTransferred;
+ REQUEST_STATUS(Request) = STATUS_SUCCESS;
+
+ } else {
+
+ IPX_DEBUG (RECEIVE, ("Transfer failed\n"));
+ REQUEST_INFORMATION(Request) = 0;
+ REQUEST_STATUS(Request) = STATUS_ADAPTER_HARDWARE_ERROR;
+
+ }
+
+ LastRequest = Request;
+ Reserved->SingleRequest = NULL;
+
+ } else {
+
+ //
+ // Multiple clients requested this datagram. Save
+ // the last one to delay queueing it for completion.
+ //
+
+ LastRequest = LIST_ENTRY_TO_REQUEST (Reserved->Requests.Blink);
+
+ while (TRUE) {
+
+ p = RemoveHeadList (&Reserved->Requests);
+ if (p == &Reserved->Requests) {
+ break;
+ }
+
+ Request = LIST_ENTRY_TO_REQUEST(p);
+ AddressFile = REQUEST_OPEN_CONTEXT(Request);
+
+ if (AddressFile->ReceiveIpxHeader) {
+ ByteOffset = 0;
+ } else {
+ ByteOffset = sizeof(IPX_HEADER);
+ }
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS) {
+
+ REQUEST_STATUS(Request) =
+ TdiCopyBufferToMdl(
+ Reserved->ReceiveBuffer->Data,
+ ByteOffset + REQUEST_INFORMATION(Request),
+ ((PTDI_REQUEST_KERNEL_RECEIVEDG)(REQUEST_PARAMETERS(Request)))->ReceiveLength,
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+
+ } else {
+
+ REQUEST_INFORMATION(Request) = 0;
+ REQUEST_STATUS(Request) = STATUS_ADAPTER_HARDWARE_ERROR;
+
+ }
+
+ if (Request != LastRequest) {
+
+ IPX_INSERT_TAIL_LIST(
+ &Adapter->RequestCompletionQueue,
+ REQUEST_LINKAGE(Request),
+ Adapter->DeviceLock);
+
+ }
+
+ }
+
+ //
+ // Now free the receive buffer back.
+ //
+
+ IPX_PUSH_ENTRY_LIST(
+ &Adapter->ReceiveBufferList,
+ &Reserved->ReceiveBuffer->PoolLinkage,
+ &Adapter->Device->SListsLock);
+
+ Reserved->ReceiveBuffer = NULL;
+
+ }
+
+
+ //
+ // Now free the packet.
+ //
+
+ NdisReinitializePacket (NdisPacket);
+
+ if (Reserved->OwnedByAddress) {
+
+ // Reserved->Address->ReceivePacketInUse = FALSE;
+ InterlockedDecrement(&Reserved->Address->ReceivePacketInUse);
+
+ } else {
+
+ Device = Adapter->Device;
+
+ IPX_PUSH_ENTRY_LIST(
+ &Device->ReceivePacketList,
+ &Reserved->PoolLinkage,
+ &Device->SListsLock);
+
+ }
+
+
+ //
+ // We Delay inserting the last request (or the only one)
+ // until after we have put the packet back, to keep the
+ // address around if needed (the address won't go away
+ // until the last address file does, and the address file
+ // won't go away until the datagram is completed).
+ //
+
+ IPX_INSERT_TAIL_LIST(
+ &Adapter->RequestCompletionQueue,
+ REQUEST_LINKAGE(LastRequest),
+ Adapter->DeviceLock);
+
+ IpxReceiveComplete ((NDIS_HANDLE)Adapter);
+
+ break;
+
+ default:
+
+ Device = Adapter->Device;
+
+ (*Device->UpperDrivers[Reserved->Identifier].TransferDataCompleteHandler)(
+ NdisPacket,
+ NdisStatus,
+ BytesTransferred);
+
+ break;
+
+ }
+
+} /* IpxTransferDataComplete */
+
+
+VOID
+IpxTransferData(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ IN OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by all tightly bound clients instead of NdisTransferData.
+ If this is a loopback packet, the transfer is done directly here, else NdisTransferData
+ is called.
+
+Arguments:
+
+ Status - status of operation
+ NdisBindingHandle - Loopback cookie or Ndis context
+ MacReceiveContext - Loopback packet or Mac context
+ ByteOffset - Source offset
+ BytesToTransfer - length of the transfer desired
+ Packet - dest packet
+ BytesTransferred - length of successful transfer
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ //
+ // If this is a loopback packet, copy the data directly
+ //
+ if (NdisBindingHandle == (PVOID)IPX_LOOPBACK_COOKIE) {
+
+ IPX_DEBUG (LOOPB, ("LoopbXfer: src: %lx, dest: %lx, bytestoxfer: %lx\n",
+ MacReceiveContext, Packet, BytesToTransfer));
+
+ NdisCopyFromPacketToPacket(
+ Packet, // Destination
+ 0, // DestinationOffset
+ BytesToTransfer, // BytesToCopy
+ (PNDIS_PACKET)MacReceiveContext, // Source
+ ByteOffset, // SourceOffset
+ BytesTransferred); // BytesCopied
+
+ *Status = NDIS_STATUS_SUCCESS;
+ } else {
+ NdisTransferData(
+ Status,
+ NdisBindingHandle,
+ MacReceiveContext,
+ ByteOffset,
+ BytesToTransfer,
+ Packet,
+ BytesTransferred);
+ }
+}
+
+
+
+NTSTATUS
+IpxTdiReceiveDatagram(
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiReceiveDatagram request for the transport
+ provider. Receive datagrams just get queued up to an address, and are
+ completed when a DATAGRAM or DATAGRAM_BROADCAST frame is received at
+ the address.
+
+Arguments:
+
+ Irp - I/O Request Packet for this request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+
+ PADDRESS Address;
+ PADDRESS_FILE AddressFile;
+ IPX_DEFINE_SYNC_CONTEXT (SyncContext)
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+
+
+ //
+ // Do a quick check of the validity of the address.
+ //
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+
+ if ((AddressFile->Size != sizeof (ADDRESS_FILE)) ||
+ (AddressFile->Type != IPX_ADDRESSFILE_SIGNATURE)) {
+
+ return STATUS_INVALID_HANDLE;
+ }
+
+ Address = AddressFile->Address;
+
+ if ((Address == NULL) ||
+ (Address->Size != sizeof (ADDRESS)) ||
+ (Address->Type != IPX_ADDRESS_SIGNATURE)) {
+
+ return STATUS_INVALID_HANDLE;
+ }
+
+ IPX_BEGIN_SYNC (&SyncContext);
+
+ IPX_GET_LOCK (&Address->Lock, &LockHandle);
+
+ if (AddressFile->State != ADDRESSFILE_STATE_OPEN) {
+
+ IPX_FREE_LOCK (&Address->Lock, LockHandle);
+ IPX_END_SYNC (&SyncContext);
+ return STATUS_INVALID_HANDLE;
+ }
+
+
+ InsertTailList (&AddressFile->ReceiveDatagramQueue, REQUEST_LINKAGE(Request));
+
+ IoSetCancelRoutine (Request, IpxCancelReceiveDatagram);
+
+ if (Request->Cancel) {
+
+ (VOID)RemoveTailList (&AddressFile->ReceiveDatagramQueue);
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ IPX_FREE_LOCK (&Address->Lock, LockHandle);
+ IPX_END_SYNC (&SyncContext);
+ return STATUS_CANCELLED;
+ }
+
+ IPX_DEBUG (RECEIVE, ("RDG posted on %lx\n", AddressFile));
+
+ IpxReferenceAddressFileLock (AddressFile, AFREF_RCV_DGRAM);
+
+ IPX_FREE_LOCK (&Address->Lock, LockHandle);
+
+ IPX_END_SYNC (&SyncContext);
+
+ return STATUS_PENDING;
+
+} /* IpxTdiReceiveDatagram */
+
+
+VOID
+IpxCancelReceiveDatagram(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to cancel a receive
+ datagram. The datagram is found on the address file's receive
+ datagram queue.
+
+ NOTE: This routine is called with the CancelSpinLock held and
+ is responsible for releasing it.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ PLIST_ENTRY p;
+ PADDRESS_FILE AddressFile;
+ PADDRESS Address;
+ PREQUEST Request = (PREQUEST)Irp;
+ BOOLEAN Found;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+
+
+ CTEAssert ((REQUEST_MAJOR_FUNCTION(Request) == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
+ (REQUEST_MINOR_FUNCTION(Request) == TDI_RECEIVE_DATAGRAM));
+
+ CTEAssert (REQUEST_OPEN_TYPE(Request) == (PVOID)TDI_TRANSPORT_ADDRESS_FILE);
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+ Address = AddressFile->Address;
+
+ Found = FALSE;
+
+ IPX_GET_LOCK (&Address->Lock, &LockHandle);
+
+ for (p = AddressFile->ReceiveDatagramQueue.Flink;
+ p != &AddressFile->ReceiveDatagramQueue;
+ p = p->Flink) {
+
+ if (LIST_ENTRY_TO_REQUEST(p) == Request) {
+
+ RemoveEntryList (p);
+ Found = TRUE;
+ break;
+ }
+ }
+
+ IPX_FREE_LOCK (&Address->Lock, LockHandle);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+ if (Found) {
+
+ IPX_DEBUG(RECEIVE, ("Cancelled datagram on %lx\n", AddressFile));
+
+ REQUEST_INFORMATION(Request) = 0;
+ REQUEST_STATUS(Request) = STATUS_CANCELLED;
+
+ IpxCompleteRequest (Request);
+ ASSERT( DeviceObject->DeviceExtension == IpxDevice );
+ IpxFreeRequest(IpxDevice, Request);
+
+ IpxDereferenceAddressFile (AddressFile, AFREF_RCV_DGRAM);
+
+ }
+
+} /* IpxCancelReceiveDatagram */
+
+
diff --git a/private/ntos/tdi/isnp/ipx/rip.c b/private/ntos/tdi/isnp/ipx/rip.c
new file mode 100644
index 000000000..d30770223
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/rip.c
@@ -0,0 +1,2655 @@
+/*++
+
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ rip.c
+
+Abstract:
+
+ This module contains code that implements the client-side
+ RIP support and simple router table support.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+UCHAR BroadcastAddress[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+
+NTSTATUS
+RipGetLocalTarget(
+ IN ULONG Segment,
+ IN TDI_ADDRESS_IPX UNALIGNED * RemoteAddress,
+ IN UCHAR Type,
+ OUT PIPX_LOCAL_TARGET LocalTarget,
+ OUT USHORT Counts[2] OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This routine looks up the proper route for the specified remote
+ address. If a RIP request needs to be generated it does so.
+
+ NOTE: THIS REQUEST IS CALLED WITH THE SEGMENT LOCK HELD.
+ NOTE: IN THE CASE OF PnP, THIS COMES WITH THE BIND LOCK SHARED.
+
+Arguments:
+
+ Segment - The segment associate with the remote address.
+
+ RemoteAddress - The IPX address of the remote.
+
+ Type - One of IPX_FIND_ROUTE_NO_RIP, IPX_FIND_ROUTE_RIP_IF_NEEDED,
+ or IPX_FIND_ROUTE_FORCE_RIP.
+
+ LocalTarget - Returns the next router information.
+
+ Counts - If specified, used to return the tick and hop count.
+
+Return Value:
+
+ STATUS_SUCCESS if a route is found, STATUS_PENDING if a
+ RIP request needs to be generated, failure status if a
+ RIP request packet cannot be allocated.
+
+--*/
+
+{
+ PDEVICE Device = IpxDevice;
+ PIPX_ROUTE_ENTRY RouteEntry;
+ PBINDING Binding;
+ UINT i;
+
+
+ //
+ // Packets sent to network 0 go on the first adapter also.
+ //
+
+ if (RemoteAddress->NetworkAddress == 0) {
+#ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(LocalTarget, 1);
+
+ RtlCopyMemory (LocalTarget->MacAddress, RemoteAddress->NodeAddress, 6);
+ if (ARGUMENT_PRESENT(Counts)) {
+ Counts[0] = (USHORT)((839 + NIC_ID_TO_BINDING(Device, 1)->MediumSpeed) /
+ NIC_ID_TO_BINDING(Device, 1)->MediumSpeed); // tick count
+ Counts[1] = 1; // hop count
+ }
+#else
+ LocalTarget->NicId = 1;
+
+ RtlCopyMemory (LocalTarget->MacAddress, RemoteAddress->NodeAddress, 6);
+ if (ARGUMENT_PRESENT(Counts)) {
+ Counts[0] = (USHORT)((839 + Device->Bindings[1]->MediumSpeed) /
+ Device->Bindings[1]->MediumSpeed); // tick count
+ Counts[1] = 1; // hop count
+ }
+#endif
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // See if this is a packet sent to our virtual network.
+ //
+
+ if (Device->VirtualNetwork &&
+ (RemoteAddress->NetworkAddress == Device->SourceAddress.NetworkAddress)) {
+
+ //
+ // Send it through adapter 1.
+ // BUGBUG: Do real loopback.
+ //
+#ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(LocalTarget, 0);
+ RtlCopyMemory (LocalTarget->MacAddress, NIC_ID_TO_BINDING(Device, 1)->LocalMacAddress.Address, 6);
+#else
+ //
+ // Loopback this packet
+ //
+ LocalTarget->NicId = 0;
+ RtlCopyMemory (LocalTarget->MacAddress, Device->Bindings[1]->LocalMacAddress.Address, 6);
+#endif
+
+ IPX_DEBUG (LOOPB, ("Loopback Nic returned for net: %lx\n", RemoteAddress->NetworkAddress));
+ if (ARGUMENT_PRESENT(Counts)) {
+ Counts[0] = 1; // tick count
+ Counts[1] = 1; // hop count
+ }
+ return STATUS_SUCCESS;
+
+ }
+
+ //
+ // Look up the route in the table. If the net is one
+ // of the ones we are directly attached to, this will
+ // return an entry with the correct flag set.
+ //
+
+ RouteEntry = RipGetRoute(Segment, (PUCHAR)&(RemoteAddress->NetworkAddress));
+
+ if (RouteEntry != NULL) {
+
+ RouteEntry->Timer = 0;
+#ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(LocalTarget, RouteEntry->NicId);
+#else
+ LocalTarget->NicId = RouteEntry->NicId;
+#endif
+ if (RouteEntry->Flags & IPX_ROUTER_LOCAL_NET) {
+
+ //
+ // The machine is on the same net, so send it directly.
+ //
+
+ RtlCopyMemory (LocalTarget->MacAddress, RemoteAddress->NodeAddress, 6);
+
+ if (RouteEntry->Flags & IPX_ROUTER_GLOBAL_WAN_NET) {
+
+ //
+ // The NicId here is bogus, we have to scan through
+ // our bindings until we find one whose indicated
+ // IPX remote node matches the destination node of
+ // this frame. We don't scan into the duplicate
+ // binding set members since they won't be WANs.
+ //
+ {
+ ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
+
+ for (i = 1; i <= Index; i++) {
+#ifdef _PNP_POWER
+ Binding = NIC_ID_TO_BINDING(Device, i);
+#else
+ Binding = Device->Bindings[i];
+#endif
+ if ((Binding != (PBINDING)NULL) &&
+ (Binding->Adapter->MacInfo.MediumAsync) &&
+ (RtlEqualMemory(
+ Binding->WanRemoteNode,
+ RemoteAddress->NodeAddress,
+ 6))) {
+#ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(LocalTarget, MIN( Device->MaxBindings, Binding->NicId));
+#else
+ LocalTarget->NicId = Binding->NicId;
+#endif
+ break;
+
+ }
+ }
+ }
+
+ if (i > (UINT)MIN (Device->MaxBindings, Device->HighestExternalNicId)) {
+ //
+ // Bug #17273 return proper error message
+ //
+
+ // return STATUS_DEVICE_DOES_NOT_EXIST;
+ return STATUS_NETWORK_UNREACHABLE;
+ }
+
+ } else {
+ //
+ // Find out if this is a loopback packet. If so, return NicId 0
+ //
+ {
+ ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
+
+ for (i = 1; i <= Index; i++) {
+#ifdef _PNP_POWER
+ Binding = NIC_ID_TO_BINDING(Device, i);
+#else
+ Binding = Device->Bindings[i];
+#endif
+ //
+ // Self-directed - loopback
+ //
+ if ((Binding != (PBINDING)NULL) &&
+ (RtlEqualMemory(
+ Binding->LocalAddress.NodeAddress,
+ RemoteAddress->NodeAddress,
+ 6))) {
+#ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(LocalTarget, 0);
+#else
+ LocalTarget->NicId = 0;
+#endif
+
+ IPX_DEBUG (LOOPB, ("2.Loopback Nic returned for net: %lx\n", RemoteAddress->NetworkAddress));
+ break;
+
+ }
+ }
+ }
+ }
+
+ } else {
+
+ CTEAssert ((RouteEntry->Flags & IPX_ROUTER_PERMANENT_ENTRY) == 0);
+
+ //
+ // This is not a locally attached net, so if the caller
+ // is forcing a re-RIP then do that.
+ //
+
+ if (Type == IPX_FIND_ROUTE_FORCE_RIP) {
+ goto QueueUpRequest;
+ }
+
+ //
+ // Fill in the address of the next router in the route.
+ //
+
+ RtlCopyMemory (LocalTarget->MacAddress, RouteEntry->NextRouter, 6);
+
+ }
+
+ if (ARGUMENT_PRESENT(Counts)) {
+ Counts[0] = RouteEntry->TickCount;
+ Counts[1] = RouteEntry->HopCount;
+ }
+
+ return STATUS_SUCCESS;
+
+ }
+
+QueueUpRequest:
+
+ if (Type == IPX_FIND_ROUTE_NO_RIP) {
+
+ //
+ // Bug #17273 return proper error message
+ //
+
+ // return STATUS_DEVICE_DOES_NOT_EXIST;
+ return STATUS_NETWORK_UNREACHABLE;
+
+ } else {
+
+ return RipQueueRequest (RemoteAddress->NetworkAddress, RIP_REQUEST);
+
+ }
+
+} /* RipGetLocalTarget */
+
+
+NTSTATUS
+RipQueueRequest(
+ IN ULONG Network,
+ IN USHORT Operation
+ )
+
+/*++
+
+Routine Description:
+
+ This routine queues up a request for a RIP route. It can be
+ used to find a specific route or to discover the locally
+ attached network (if Network is 0). It can also be used
+ to do a periodic announcement of the virtual net, which
+ we do once a minute if the router is not bound.
+
+ NOTE: THIS REQUEST IS CALLED WITH THE SEGMENT LOCK HELD
+ IF IT IS A REQUEST AND THE NETWORK IS NOT 0xffffffff.
+
+Arguments:
+
+ Network - The network to discover.
+
+ Operation - One of RIP_REQUEST, RIP_RESPONSE, or RIP_DOWN.
+
+Return Value:
+
+ STATUS_PENDING if the request is queued, failure status
+ if it could not be.
+
+--*/
+
+{
+ PDEVICE Device = IpxDevice;
+ PIPX_SEND_RESERVED Reserved;
+ PSINGLE_LIST_ENTRY s;
+ PLIST_ENTRY p;
+ PRIP_PACKET RipPacket;
+ TDI_ADDRESS_IPX RemoteAddress;
+ TDI_ADDRESS_IPX LocalAddress;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+ PNDIS_BUFFER pNdisIpxBuff;
+
+
+ //
+ // Make sure we only queue a request for net 0xffffffff if we
+ // are auto-detecting, because we assume that in other places.
+ //
+
+ if ((Network == 0xffffffff) &&
+ (Device->AutoDetectState != AUTO_DETECT_STATE_RUNNING)) {
+
+ return STATUS_BAD_NETWORK_PATH;
+
+ }
+
+ //
+ // Try to get a packet to use for the RIP request. We
+ // allocate this now, but check if it succeeded later,
+ // to make the locking work better (we need to keep
+ // the lock between when we check for an existing
+ // request on this network and when we queue this
+ // request).
+ //
+
+ s = IpxPopSendPacket (Device);
+
+ //
+ // There was no router table entry for this network, first see
+ // if there is already a pending request for this route.
+ //
+
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+
+ if (Operation == RIP_REQUEST) {
+
+ for (p = Device->WaitingRipPackets.Flink;
+ p != &Device->WaitingRipPackets;
+ p = p->Flink) {
+
+ Reserved = CONTAINING_RECORD (p, IPX_SEND_RESERVED, WaitLinkage);
+
+ //
+ // Skip responses.
+ //
+
+ if (Reserved->u.SR_RIP.RetryCount >= 0xfe) {
+ continue;
+ }
+
+ if (Reserved->u.SR_RIP.Network == Network &&
+ !Reserved->u.SR_RIP.RouteFound) {
+
+ //
+ // There is already one pending, put back the packet if
+ // we got one (we hold the lock already).
+ //
+
+ if (s != NULL) {
+ IPX_PUSH_ENTRY_LIST (&Device->SendPacketList, s, &Device->SListsLock);
+ }
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ return STATUS_PENDING;
+ }
+ }
+
+ }
+
+
+ if (s == NULL) {
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ Reserved = CONTAINING_RECORD (s, IPX_SEND_RESERVED, PoolLinkage);
+
+ //
+ // We have the packet, fill it in for this request.
+ //
+
+ Reserved->Identifier = IDENTIFIER_RIP_INTERNAL;
+ Reserved->SendInProgress = FALSE;
+ Reserved->DestinationType = DESTINATION_BCAST;
+ Reserved->u.SR_RIP.CurrentNicId = 0;
+ Reserved->u.SR_RIP.NoIdAdvance = FALSE;
+ switch (Operation) {
+ case RIP_REQUEST: Reserved->u.SR_RIP.RetryCount = 0; break;
+ case RIP_RESPONSE: Reserved->u.SR_RIP.RetryCount = 0xfe; break;
+ case RIP_DOWN: Reserved->u.SR_RIP.RetryCount = 0xff; break;
+ }
+ Reserved->u.SR_RIP.RouteFound = FALSE;
+ Reserved->u.SR_RIP.Network = Network;
+ Reserved->u.SR_RIP.SendTime = Device->RipSendTime;
+
+ //
+ // We aren't guaranteed that this is the case for packets
+ // on the free list.
+ //
+
+ pNdisIpxBuff = NDIS_BUFFER_LINKAGE (Reserved->HeaderBuffer);
+ NDIS_BUFFER_LINKAGE (pNdisIpxBuff) = NULL;
+
+ //
+ // Fill in the IPX header at the standard offset (for sending
+ // to actual bindings it will be moved around if needed). We
+ // have to construct the local and remote addresses so they
+ // are in the format that IpxConstructHeader expects.
+ //
+
+ RemoteAddress.NetworkAddress = Network;
+ RtlCopyMemory (RemoteAddress.NodeAddress, BroadcastAddress, 6);
+ RemoteAddress.Socket = RIP_SOCKET;
+
+ RtlCopyMemory (&LocalAddress, &Device->SourceAddress, FIELD_OFFSET(TDI_ADDRESS_IPX,Socket));
+ LocalAddress.Socket = RIP_SOCKET;
+
+ IpxConstructHeader(
+// &Reserved->Header[Device->IncludedHeaderOffset],
+ &Reserved->Header[MAC_HEADER_SIZE],
+ sizeof(IPX_HEADER) + sizeof (RIP_PACKET),
+ RIP_PACKET_TYPE,
+ &RemoteAddress,
+ &LocalAddress);
+
+ //
+ // Fill in the RIP request also.
+ //
+
+#if 0
+ RipPacket = (PRIP_PACKET)(&Reserved->Header[Device->IncludedHeaderOffset + sizeof(IPX_HEADER)]);
+#endif
+ RipPacket = (PRIP_PACKET)(&Reserved->Header[MAC_HEADER_SIZE + sizeof(IPX_HEADER)]);
+ RipPacket->Operation = Operation & 0x7fff;
+ RipPacket->NetworkEntry.NetworkNumber = Network;
+
+ if (Operation == RIP_REQUEST) {
+ RipPacket->NetworkEntry.HopCount = REORDER_USHORT(0xffff);
+ RipPacket->NetworkEntry.TickCount = REORDER_USHORT(0xffff);
+ } else if (Operation == RIP_RESPONSE) {
+ RipPacket->NetworkEntry.HopCount = REORDER_USHORT(1);
+ RipPacket->NetworkEntry.TickCount = REORDER_USHORT(2); // will be modified when sent
+ } else {
+ RipPacket->NetworkEntry.HopCount = REORDER_USHORT(16);
+ RipPacket->NetworkEntry.TickCount = REORDER_USHORT(16);
+ }
+
+ NdisAdjustBufferLength(pNdisIpxBuff, sizeof(IPX_HEADER) + sizeof(RIP_PACKET));
+ //
+ // Now insert this packet in the queue of pending RIP
+ // requests and start the timer if needed (this is done
+ // to ensure the RIP_GRANULARITY milliseconds inter-RIP-packet
+ // delay).
+ //
+
+ IPX_DEBUG (RIP, ("RIP %s for network %lx\n",
+ (Operation == RIP_REQUEST) ? "request" : ((Operation == RIP_RESPONSE) ? "announce" : "down"),
+ REORDER_ULONG(Network)));
+
+ InsertHeadList(
+ &Device->WaitingRipPackets,
+ &Reserved->WaitLinkage);
+
+ ++Device->RipPacketCount;
+
+ if (!Device->RipShortTimerActive) {
+
+ Device->RipShortTimerActive = TRUE;
+ IpxReferenceDevice (Device, DREF_RIP_TIMER);
+
+ CTEStartTimer(
+ &Device->RipShortTimer,
+ 1, // 1 ms, i.e. expire immediately
+ RipShortTimeout,
+ (PVOID)Device);
+ }
+
+ IpxReferenceDevice (Device, DREF_RIP_PACKET);
+
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ return STATUS_PENDING;
+
+} /* RipQueueRequest */
+
+
+VOID
+RipSendResponse(
+ IN PBINDING Binding,
+ IN TDI_ADDRESS_IPX UNALIGNED * RemoteAddress,
+ IN PIPX_LOCAL_TARGET LocalTarget
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a respond to a RIP request from a client --
+ this is only used if we have a virtual network and the router
+ is not bound, and somebody queries on the virtual network.
+
+Arguments:
+
+ Binding - The binding on which the request was received.
+
+ RemoteAddress - The IPX source address of the request.
+
+ LocalTarget - The local target of the received packet.
+
+Return Value:
+
+ STATUS_PENDING if the request is queued, failure status
+ if it could not be.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+ PIPX_SEND_RESERVED Reserved;
+ TDI_ADDRESS_IPX LocalAddress;
+ PNDIS_PACKET Packet;
+ PIPX_HEADER IpxHeader;
+ PRIP_PACKET RipPacket;
+ PDEVICE Device = IpxDevice;
+ PBINDING MasterBinding;
+ NDIS_STATUS NdisStatus;
+ USHORT TickCount;
+ PNDIS_BUFFER pNdisIpxBuff;
+
+ //
+ // Get a packet to use for the RIP response.
+ //
+
+ s = IpxPopSendPacket (Device);
+
+ if (s == NULL) {
+ return;
+ }
+
+ IpxReferenceDevice (Device, DREF_RIP_PACKET);
+
+ Reserved = CONTAINING_RECORD (s, IPX_SEND_RESERVED, PoolLinkage);
+
+ //
+ // We have the packet, fill it in for this request.
+ //
+
+ Reserved->Identifier = IDENTIFIER_RIP_RESPONSE;
+ Reserved->DestinationType = DESTINATION_DEF;
+ CTEAssert (!Reserved->SendInProgress);
+ Reserved->SendInProgress = TRUE;
+
+ //
+ // We aren't guaranteed that this is the case for packets
+ // on the free list.
+ //
+
+ pNdisIpxBuff = NDIS_BUFFER_LINKAGE (Reserved->HeaderBuffer);
+ NDIS_BUFFER_LINKAGE (pNdisIpxBuff) = NULL;
+
+ //
+ // If this binding is a binding set member, round-robin through
+ // the various bindings when responding. We will get some natural
+ // round-robinning because broadcast requests are received on
+ // binding set members in turn, but they are only rotated once
+ // a second.
+ //
+
+ if (Binding->BindingSetMember) {
+
+ //
+ // It's a binding set member, we round-robin the
+ // responses across all the cards to distribute
+ // the traffic.
+ //
+
+ MasterBinding = Binding->MasterBinding;
+ Binding = MasterBinding->CurrentSendBinding;
+ MasterBinding->CurrentSendBinding = Binding->NextBinding;
+
+#ifdef _PNP_POWER
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif
+ }
+
+ //
+ // Fill in the IPX header at the correct offset.
+ //
+
+ LocalAddress.NetworkAddress = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory (LocalAddress.NodeAddress, Binding->LocalAddress.NodeAddress, 6);
+ LocalAddress.Socket = RIP_SOCKET;
+#if 0
+ IpxHeader = (PIPX_HEADER)(&Reserved->Header[Binding->DefHeaderSize]);
+#endif
+ IpxHeader = (PIPX_HEADER)(&Reserved->Header[MAC_HEADER_SIZE]);
+
+ IpxConstructHeader(
+ (PUCHAR)IpxHeader,
+ sizeof(IPX_HEADER) + sizeof (RIP_PACKET),
+ RIP_PACKET_TYPE,
+ RemoteAddress,
+ &LocalAddress);
+
+ //
+ // In case the request comes from net 0, fill that in too.
+ //
+
+ *(UNALIGNED ULONG *)IpxHeader->DestinationNetwork = Binding->LocalAddress.NetworkAddress;
+
+
+ //
+ // Fill in the RIP request.
+ //
+
+ RipPacket = (PRIP_PACKET)(IpxHeader+1);
+
+ RipPacket->Operation = RIP_RESPONSE;
+ RipPacket->NetworkEntry.NetworkNumber = Device->VirtualNetworkNumber;
+
+ RipPacket->NetworkEntry.HopCount = REORDER_USHORT(1);
+ TickCount = (USHORT)(((839 + Binding->MediumSpeed) / Binding->MediumSpeed) + 1);
+ RipPacket->NetworkEntry.TickCount = REORDER_USHORT(TickCount);
+
+ IPX_DEBUG (RIP, ("RIP response for virtual network %lx\n",
+ REORDER_ULONG(Device->VirtualNetworkNumber)));
+
+ NdisAdjustBufferLength(pNdisIpxBuff, sizeof(IPX_HEADER) + sizeof(RIP_PACKET));
+ //
+ // Now submit the packet to NDIS.
+ //
+
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ if ((NdisStatus = IpxSendFrame(
+ LocalTarget,
+ Packet,
+ sizeof(RIP_PACKET) + sizeof(IPX_HEADER),
+ sizeof(RIP_PACKET) + sizeof(IPX_HEADER))) != NDIS_STATUS_PENDING) {
+
+ IpxSendComplete(
+ (NDIS_HANDLE)Binding->Adapter,
+ Packet,
+ NdisStatus);
+ }
+
+#ifdef _PNP_POWER
+ if (Binding->BindingSetMember) {
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ }
+#endif
+ return;
+
+} /* RipSendResponse */
+
+
+VOID
+RipShortTimeout(
+ CTEEvent * Event,
+ PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when the RIP short timer expires.
+ It is called every RIP_GRANULARITY milliseconds unless there
+ is nothing to do.
+
+Arguments:
+
+ Event - The event used to queue the timer.
+
+ Context - The context, which is the device pointer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = (PDEVICE)Context;
+ PLIST_ENTRY p;
+ PIPX_SEND_RESERVED Reserved;
+ PNDIS_PACKET Packet;
+ USHORT OldNicId, NewNicId;
+ ULONG OldOffset, NewOffset;
+ PIPX_HEADER IpxHeader;
+ PBINDING Binding, MasterBinding;
+ NDIS_STATUS NdisStatus;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+
+#ifdef _PNP_LATER
+ static IPX_LOCAL_TARGET BroadcastTarget = { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, {0, 0, 0} };
+#else
+ static IPX_LOCAL_TARGET BroadcastTarget = { 0, { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } };
+#endif
+
+ static ULONG ZeroNetwork = 0;
+#ifdef _PNP_POWER
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+#endif
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+
+ ++Device->RipSendTime;
+
+ if (Device->RipPacketCount == 0) {
+
+ Device->RipShortTimerActive = FALSE;
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ IpxDereferenceDevice (Device, DREF_RIP_TIMER);
+
+ return;
+ }
+
+ //
+ // Check what is on the queue; this is set up as a
+ // loop but in fact it rarely does (under no
+ // circumstances can we send more than one packet
+ // each time this function executes).
+ //
+
+ while (TRUE) {
+
+ p = Device->WaitingRipPackets.Flink;
+ if (p == &Device->WaitingRipPackets) {
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ break;
+ }
+
+ Reserved = CONTAINING_RECORD (p, IPX_SEND_RESERVED, WaitLinkage);
+
+ if ((Reserved->u.SR_RIP.RouteFound) && (!Reserved->SendInProgress)) {
+
+ (VOID)RemoveHeadList (&Device->WaitingRipPackets);
+ Reserved->Identifier = IDENTIFIER_IPX;
+ IPX_PUSH_ENTRY_LIST (&Device->SendPacketList, &Reserved->PoolLinkage, &Device->SListsLock);
+ --Device->RipPacketCount;
+
+ //
+ // It is OK to do this with the lock held because
+ // it won't be the last one (we have the RIP_TIMER ref).
+ //
+
+ IpxDereferenceDevice (Device, DREF_RIP_PACKET);
+ continue;
+ }
+
+ if ((((SHORT)(Device->RipSendTime - Reserved->u.SR_RIP.SendTime)) < 0) ||
+ Reserved->SendInProgress) {
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ break;
+ }
+
+ (VOID)RemoveHeadList (&Device->WaitingRipPackets);
+
+ //
+ // Find the right binding to send to. If NoIdAdvance
+ // is set, then the binding doesn't need to be changed
+ // this time (this means we wrapped last time).
+ //
+
+ OldNicId = Reserved->u.SR_RIP.CurrentNicId;
+
+ if (!Reserved->u.SR_RIP.NoIdAdvance) {
+
+ BOOLEAN FoundNext = FALSE;
+
+#ifdef _PNP_POWER
+//
+// To maintain the lock order, release Device lock here and re-acquire later
+//
+ USHORT StartId;
+
+ if (Device->ValidBindings == 0) {
+ IPX_DEBUG(PNP, ("ValidBindings 0 in RipShortTimeOut\n"));
+
+ Device->RipShortTimerActive = FALSE;
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ IpxDereferenceDevice (Device, DREF_RIP_TIMER);
+ return;
+ }
+
+ StartId = (USHORT)((OldNicId % MIN (Device->MaxBindings, Device->ValidBindings)) + 1);
+
+ NewNicId = StartId;
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+#else
+
+ USHORT StartId = (USHORT)((OldNicId % Device->BindingCount) + 1);
+
+ NewNicId = StartId;
+#endif
+ do {
+
+#ifdef _PNP_POWER
+ Binding = NIC_ID_TO_BINDING(Device, NewNicId);
+#else
+ Binding = Device->Bindings[NewNicId];
+#endif
+ if (Reserved->u.SR_RIP.Network != 0xffffffff) {
+
+ //
+ // We are looking for a real net; check that
+ // the next binding is valid. If it is a WAN
+ // binding, we don't send queries if the router
+ // is bound. If it is a LAN binding, we don't
+ // send queries if we are configured for
+ // SingleNetworkActive and the WAN is up.
+ // We also don't send queries on binding set
+ // members which aren't masters.
+ //
+
+ if ((Binding != NULL)
+ &&
+ ((!Binding->Adapter->MacInfo.MediumAsync) ||
+ (!Device->UpperDriverBound[IDENTIFIER_RIP]))
+ &&
+ ((Binding->Adapter->MacInfo.MediumAsync) ||
+ (!Device->SingleNetworkActive) ||
+ (!Device->ActiveNetworkWan))
+ &&
+ ((!Binding->BindingSetMember) ||
+ (Binding->CurrentSendBinding))) {
+
+ FoundNext = TRUE;
+ break;
+ }
+
+ } else {
+
+ //
+ // We are sending out the initial request to net
+ // 0xffffffff, to generate traffic so we can figure
+ // out our real network number. We don't do this
+ // to nets that already have a number and we don't
+ // do it on WAN links. We also don't do it on
+ // auto-detect nets if we have found the default.
+ //
+
+
+ if ((Binding != NULL) &&
+ (Binding->TentativeNetworkAddress == 0) &&
+ (!Binding->Adapter->MacInfo.MediumAsync) &&
+ (!Binding->AutoDetect || !Binding->Adapter->DefaultAutoDetected)) {
+ FoundNext = TRUE;
+ break;
+ }
+ }
+#ifdef _PNP_POWER
+ //
+ // [BUGBUGZZ] Why cycle thru the entire list?
+ //
+ NewNicId = (USHORT)((NewNicId % MIN (Device->MaxBindings, Device->ValidBindings)) + 1);
+#else
+ NewNicId = (USHORT)((NewNicId % Device->BindingCount) + 1);
+#endif
+ } while (NewNicId != StartId);
+
+ if (!FoundNext) {
+
+ //
+ // Nothing more needs to be done with this packet,
+ // leave it off the queue and since we didn't send
+ // a packet we can check for more.
+ //
+#ifndef _PNP_POWER
+ //
+ // This was released above (before the BindAccessLock was taken
+ //
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+#endif
+ RipCleanupPacket(Device, Reserved);
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+
+ IPX_PUSH_ENTRY_LIST (&Device->SendPacketList, &Reserved->PoolLinkage, &Device->SListsLock);
+ --Device->RipPacketCount;
+ IpxDereferenceDevice (Device, DREF_RIP_PACKET);
+ continue;
+
+ }
+
+#ifdef _PNP_POWER
+
+ IPX_DEBUG(RIP, ("RIP: FoundNext: %lx, StartId: %lx, OldNicId: %lx, NewNicId: %lx\n", FoundNext, StartId, OldNicId, NewNicId));
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ //
+ // Re-acquire the Device lock
+ //
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+#endif
+
+ Reserved->u.SR_RIP.CurrentNicId = NewNicId;
+
+ //
+ // Move the data around if needed.
+ //
+
+#if 0
+ if (OldNicId != NewNicId) {
+
+ if (OldNicId == 0) {
+ OldOffset = Device->IncludedHeaderOffset;
+ } else {
+ OldOffset = Device->Bindings[OldNicId]->BcMcHeaderSize;
+ }
+
+ NewOffset = Binding->BcMcHeaderSize;
+
+ if (OldOffset != NewOffset) {
+
+ RtlMoveMemory(
+ &Reserved->Header[NewOffset],
+ &Reserved->Header[OldOffset],
+ sizeof(IPX_HEADER) + sizeof(RIP_PACKET));
+
+ }
+
+ }
+#endif
+
+ if (NewNicId <= OldNicId) {
+
+ //
+ // We found a new binding but we wrapped, so increment
+ // the counter. If we have done all the resends, or
+ // this is a response (indicated by retry count of 0xff;
+ // they are only sent once) then clean up.
+ //
+
+ if ((Reserved->u.SR_RIP.RetryCount >= 0xfe) ||
+ ((++Reserved->u.SR_RIP.RetryCount) == Device->RipCount)) {
+
+ //
+ // This packet is stale, clean it up and continue.
+ //
+
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+#ifdef _PNP_POWER
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif
+ RipCleanupPacket(Device, Reserved);
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+
+ IPX_PUSH_ENTRY_LIST (&Device->SendPacketList, &Reserved->PoolLinkage, &Device->SListsLock);
+ --Device->RipPacketCount;
+ IpxDereferenceDevice (Device, DREF_RIP_PACKET);
+
+ } else {
+
+ //
+ // We wrapped, so put ourselves back in the queue
+ // at the end.
+ //
+
+ Reserved->u.SR_RIP.SendTime = (USHORT)(Device->RipSendTime + Device->RipTimeout - 1);
+ Reserved->u.SR_RIP.NoIdAdvance = TRUE;
+ InsertTailList (&Device->WaitingRipPackets, &Reserved->WaitLinkage);
+
+#ifdef _PNP_POWER
+ //
+ // Free the Device lock before deref'ing the Binding so we maintain
+ // the lock order: BindingAccess > GlobalInterLock > Device
+ //
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+#endif
+ }
+
+ continue;
+
+ }
+#ifdef _PNP_POWER
+//
+// To prevent the re-acquire of the device lock, this is moved up...
+//
+ //
+ // Send it again as soon as possible (it we just wrapped, then
+ // we will have put ourselves at the tail and won't get here).
+ //
+
+ InsertHeadList (&Device->WaitingRipPackets, &Reserved->WaitLinkage);
+
+ CTEAssert (Reserved->Identifier == IDENTIFIER_RIP_INTERNAL);
+ CTEAssert (!Reserved->SendInProgress);
+ Reserved->SendInProgress = TRUE;
+
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+#endif
+ } else {
+
+ //
+ // Next time we need to advance the binding.
+ //
+
+ Reserved->u.SR_RIP.NoIdAdvance = FALSE;
+ NewNicId = OldNicId;
+#ifdef _PNP_POWER
+ //
+ // Send it again as soon as possible (it we just wrapped, then
+ // we will have put ourselves at the tail and won't get here).
+ //
+
+ InsertHeadList (&Device->WaitingRipPackets, &Reserved->WaitLinkage);
+
+ CTEAssert (Reserved->Identifier == IDENTIFIER_RIP_INTERNAL);
+ CTEAssert (!Reserved->SendInProgress);
+ Reserved->SendInProgress = TRUE;
+
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ Binding = NIC_ID_TO_BINDING(Device, NewNicId);
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+ Binding = Device->Bindings[NewNicId];
+#endif
+
+ }
+#ifndef _PNP_POWER
+ //
+ // Send it again as soon as possible (it we just wrapped, then
+ // we will have put ourselves at the tail and won't get here).
+ //
+
+ InsertHeadList (&Device->WaitingRipPackets, &Reserved->WaitLinkage);
+
+ CTEAssert (Reserved->Identifier == IDENTIFIER_RIP_INTERNAL);
+ CTEAssert (!Reserved->SendInProgress);
+ Reserved->SendInProgress = TRUE;
+
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+#endif
+ //
+ // This packet should be sent on binding NewNicId; first
+ // move the data to the right location for the current
+ // binding.
+ //
+#ifdef _PNP_POWER
+ CTEAssert (Binding == NIC_ID_TO_BINDING(Device, NewNicId)); // temp, just to make sure
+#else
+ CTEAssert (Binding == Device->Bindings[NewNicId]); // temp, just to make sure
+#endif
+// NewOffset = Binding->BcMcHeaderSize;
+
+ //
+ // Now submit the packet to NDIS.
+ //
+
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+#ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(&BroadcastTarget, NewNicId);
+#else
+ BroadcastTarget.NicId = NewNicId;
+#endif
+
+ //
+ // Modify the header so the packet comes from this
+ // specific adapter, not the virtual network.
+ //
+
+ // IpxHeader = (PIPX_HEADER)(&Reserved->Header[NewOffset]);
+ IpxHeader = (PIPX_HEADER)(&Reserved->Header[MAC_HEADER_SIZE]);
+
+ if (Reserved->u.SR_RIP.Network == 0xffffffff) {
+ *(UNALIGNED ULONG *)IpxHeader->SourceNetwork = 0;
+ } else {
+ *(UNALIGNED ULONG *)IpxHeader->SourceNetwork = Binding->LocalAddress.NetworkAddress;
+ }
+
+ if (Reserved->u.SR_RIP.RetryCount < 0xfe) {
+
+ //
+ // This is an outgoing query. We round-robin these through
+ // binding sets.
+ //
+
+ if (Binding->BindingSetMember) {
+
+ //
+ // Shouldn't have any binding sets during initial
+ // discovery.
+ //
+
+ CTEAssert (Reserved->u.SR_RIP.Network != 0xffffffff);
+
+ //
+ // If we are in a binding set, then use the current binding
+ // in the set for this send, and advance the current binding.
+ // The places we have used Binding before here will be fine
+ // since the binding set members all have the same media
+ // and frame type.
+ //
+
+ CTEAssert (Binding->CurrentSendBinding); // should be a master.
+ MasterBinding = Binding;
+ Binding = MasterBinding->CurrentSendBinding;
+ MasterBinding->CurrentSendBinding = Binding->NextBinding;
+#ifdef _PNP_POWER
+ //
+ // [BUGBUGZZ]: We dont have a lock here - the masterbinding could be bogus
+ //
+ IpxDereferenceBinding1(MasterBinding, BREF_DEVICE_ACCESS);
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif
+ }
+ }
+
+
+ RtlCopyMemory (IpxHeader->SourceNode, Binding->LocalAddress.NodeAddress, 6);
+
+ //
+ // Bug# 6485
+ // Rip request, general or specific, is putting the network of the
+ // node to which the route has to be found in the ipx header remote
+ // network field. Some novell routers don't like that. This network
+ // field should be 0.
+ //
+ {
+ PRIP_PACKET RipPacket = (PRIP_PACKET)(&Reserved->Header[MAC_HEADER_SIZE + sizeof(IPX_HEADER)]);
+
+ if (RipPacket->Operation != RIP_REQUEST) {
+ *(UNALIGNED ULONG *)IpxHeader->DestinationNetwork = Binding->LocalAddress.NetworkAddress;
+ } else {
+ *(UNALIGNED ULONG *)IpxHeader->DestinationNetwork = 0;
+ }
+ }
+
+ //
+ // If this is a RIP_RESPONSE, set the tick count for this
+ // binding.
+ //
+
+ if (Reserved->u.SR_RIP.RetryCount == 0xfe) {
+
+ PRIP_PACKET RipPacket = (PRIP_PACKET)(IpxHeader+1);
+ USHORT TickCount = (USHORT)
+ (((839 + Binding->MediumSpeed) / Binding->MediumSpeed) + 1);
+
+ RipPacket->NetworkEntry.TickCount = REORDER_USHORT(TickCount);
+
+ }
+
+ if ((NdisStatus = IpxSendFrame(
+ &BroadcastTarget,
+ Packet,
+ sizeof(RIP_PACKET) + sizeof(IPX_HEADER),
+ sizeof(RIP_PACKET) + sizeof(IPX_HEADER))) != NDIS_STATUS_PENDING) {
+
+ IpxSendComplete(
+ (NDIS_HANDLE)Binding->Adapter,
+ Packet,
+ NdisStatus);
+ }
+#ifdef _PNP_POWER
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif
+
+ break;
+
+ }
+
+ CTEStartTimer(
+ &Device->RipShortTimer,
+ RIP_GRANULARITY,
+ RipShortTimeout,
+ (PVOID)Device);
+
+} /* RipShortTimeout */
+
+
+VOID
+RipLongTimeout(
+ CTEEvent * Event,
+ PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when the RIP long timer expires.
+ It is called every minute and handles periodic re-RIPping
+ to ensure that entries are accurate, as well as aging out
+ of entries if the rip router is not bound.
+
+Arguments:
+
+ Event - The event used to queue the timer.
+
+ Context - The context, which is the device pointer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = (PDEVICE)Context;
+ PROUTER_SEGMENT RouterSegment;
+ PIPX_ROUTE_ENTRY RouteEntry;
+ UINT Segment;
+ UINT i;
+ PBINDING Binding;
+ IPX_DEFINE_LOCK_HANDLE(LockHandle)
+
+
+ //
+ // Rotate the broadcast receiver on all binding sets.
+ // We can loop up to HighestExternal only since we
+ // are only interested in finding binding set masters.
+ //
+#ifdef _PNP_POWER
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+#endif
+ {
+ ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
+
+ for (i = 1; i <= Index; i++) {
+
+#ifdef _PNP_POWER
+ Binding = NIC_ID_TO_BINDING(Device, i);
+#else
+ Binding = Device->Bindings[i];
+#endif
+ if ((Binding != NULL) &&
+ (Binding->CurrentSendBinding)) {
+
+ //
+ // It is a master, so find the current broadcast
+ // receiver, then advance it.
+ //
+
+ while (TRUE) {
+ if (Binding->ReceiveBroadcast) {
+ Binding->ReceiveBroadcast = FALSE;
+ Binding->NextBinding->ReceiveBroadcast = TRUE;
+ break;
+ } else {
+ Binding = Binding->NextBinding;
+ }
+ }
+ }
+ }
+ }
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+
+
+ //
+ // If RIP is bound, we don't do any of this, and
+ // we stop the timer from running.
+ //
+
+ if (Device->UpperDriverBound[IDENTIFIER_RIP]) {
+ IpxDereferenceDevice (Device, DREF_LONG_TIMER);
+ return;
+ }
+
+
+ //
+ // If we have a virtual net, do our periodic broadcast.
+ //
+
+ if (Device->RipResponder) {
+ (VOID)RipQueueRequest (Device->VirtualNetworkNumber, RIP_RESPONSE);
+ }
+
+
+ //
+ // Update the real counters from the temp ones.
+ //
+
+ ADD_TO_LARGE_INTEGER(
+ &Device->Statistics.DatagramBytesSent,
+ Device->TempDatagramBytesSent);
+ Device->Statistics.DatagramsSent += Device->TempDatagramsSent;
+
+ Device->TempDatagramBytesSent = 0;
+ Device->TempDatagramsSent = 0;
+
+ ADD_TO_LARGE_INTEGER(
+ &Device->Statistics.DatagramBytesReceived,
+ Device->TempDatagramBytesReceived);
+ Device->Statistics.DatagramsReceived += Device->TempDatagramsReceived;
+
+ Device->TempDatagramBytesReceived = 0;
+ Device->TempDatagramsReceived = 0;
+
+
+ //
+ // We need to scan each hash bucket to see if there
+ // are any active entries which need to be re-RIPped
+ // for. We also scan for entries that should be timed
+ // out.
+ //
+
+ for (Segment = 0; Segment < Device->SegmentCount; Segment++) {
+
+ RouterSegment = &IpxDevice->Segments[Segment];
+
+ //
+ // Don't take the lock if the bucket is empty.
+ //
+
+ if (RouterSegment->Entries.Flink == &RouterSegment->Entries) {
+ continue;
+ }
+
+ IPX_GET_LOCK (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // Scan through each entry looking for ones to age.
+ //
+
+ for (RouteEntry = RipGetFirstRoute (Segment);
+ RouteEntry != (PIPX_ROUTE_ENTRY)NULL;
+ RouteEntry = RipGetNextRoute (Segment)) {
+
+ if (RouteEntry->Flags & IPX_ROUTER_PERMANENT_ENTRY) {
+ continue;
+ }
+
+ ++RouteEntry->Timer;
+ if (RouteEntry->Timer >= Device->RipUsageTime) {
+
+ RipDeleteRoute (Segment, RouteEntry);
+ IpxFreeMemory(RouteEntry, sizeof(IPX_ROUTE_ENTRY), MEMORY_RIP, "RouteEntry");
+ continue;
+
+ }
+
+ //
+ // See if we should re-RIP for this segment. It has
+ // to have been around for RipAgeTime, and we also
+ // make sure that the Timer is not too high to
+ // prevent us from re-RIPping on unused routes.
+ //
+
+ ++RouteEntry->PRIVATE.Reserved[0];
+
+ if ((RouteEntry->PRIVATE.Reserved[0] >= Device->RipAgeTime) &&
+ (RouteEntry->Timer <= Device->RipAgeTime)) {
+
+ //
+ // If we successfully queue a request, then reset
+ // Reserved[0] so we don't re-RIP for a while.
+ //
+
+ if (RipQueueRequest (*(UNALIGNED ULONG *)RouteEntry->Network, RIP_REQUEST) == STATUS_PENDING) {
+ RouteEntry->PRIVATE.Reserved[0] = 0;
+ }
+ }
+ }
+
+ IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
+
+ }
+
+
+ //
+ // Now restart the timer for the next timeout.
+ //
+
+ if (Device->State == DEVICE_STATE_OPEN) {
+
+ CTEStartTimer(
+ &Device->RipLongTimer,
+ 60000, // one minute timeout
+ RipLongTimeout,
+ (PVOID)Device);
+
+ } else {
+
+ //
+ // Send a DOWN packet if needed, then stop ourselves.
+ //
+
+ if (Device->RipResponder) {
+
+ if (RipQueueRequest (Device->VirtualNetworkNumber, RIP_DOWN) != STATUS_PENDING) {
+
+ //
+ // We need to kick this event because the packet completion
+ // won't.
+ //
+
+ KeSetEvent(
+ &Device->UnloadEvent,
+ 0L,
+ FALSE);
+ }
+ }
+
+ IpxDereferenceDevice (Device, DREF_LONG_TIMER);
+
+ }
+
+} /* RipLongTimeout */
+
+
+VOID
+RipCleanupPacket(
+ IN PDEVICE Device,
+ IN PIPX_SEND_RESERVED RipReserved
+ )
+
+/*++
+
+Routine Description:
+
+ This routine cleans up when a RIP packet times out.
+
+Arguments:
+
+ Device - The device.
+
+ RipReserved - The ProtocolReserved section of the RIP packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG Segment;
+ IPX_DEFINE_LOCK_HANDLE_PARAM (LockHandle)
+
+ if (RipReserved->u.SR_RIP.RetryCount < 0xfe) {
+
+ if (RipReserved->u.SR_RIP.Network != 0xffffffff) {
+
+ IPX_DEBUG (RIP, ("Timing out RIP for network %lx\n",
+ REORDER_ULONG(RipReserved->u.SR_RIP.Network)));
+
+ Segment = RipGetSegment ((PUCHAR)&RipReserved->u.SR_RIP.Network);
+ IPX_GET_LOCK (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // Fail all datagrams, etc. that were waiting for
+ // this route. This call releases the lock.
+ //
+
+ RipHandleRoutePending(
+ Device,
+ (PUCHAR)&(RipReserved->u.SR_RIP.Network),
+ LockHandle,
+ FALSE,
+ NULL,
+ 0,
+ 0);
+
+ } else {
+
+ //
+ // This was the initial query looking for networks --
+ // signal the init thread which is waiting.
+ //
+
+ IPX_DEBUG (AUTO_DETECT, ("Signalling auto-detect event\n"));
+ KeSetEvent(
+ &Device->AutoDetectEvent,
+ 0L,
+ FALSE);
+
+ }
+
+ } else if (RipReserved->u.SR_RIP.RetryCount == 0xff) {
+
+ //
+ // This is a DOWN message, set the device event that
+ // is waiting for it to complete.
+ //
+
+ KeSetEvent(
+ &Device->UnloadEvent,
+ 0L,
+ FALSE);
+ }
+
+ //
+ // Put the RIP packet back in the pool.
+ //
+
+ RipReserved->Identifier = IDENTIFIER_IPX;
+
+} /* RipCleanupPacket */
+
+
+VOID
+RipProcessResponse(
+ IN PDEVICE Device,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN RIP_PACKET UNALIGNED * RipPacket
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes a RIP response from the specified
+ local target, indicating a route to the network in the RIP
+ header.
+
+Arguments:
+
+ Device - The device.
+
+ LocalTarget - The router that the frame was received from.
+
+ RipPacket - The RIP response header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_RESERVED RipReserved; // ProtocolReserved of RIP packet
+ ULONG Segment;
+ PIPX_ROUTE_ENTRY RouteEntry, OldRouteEntry;
+ PLIST_ENTRY p;
+ IPX_DEFINE_LOCK_HANDLE_PARAM (LockHandle)
+
+ //
+ // Since we have received a RIP response for this network.
+ // kill the waiting RIP packets for it if it exists.
+ //
+
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+
+ for (p = Device->WaitingRipPackets.Flink;
+ p != &Device->WaitingRipPackets;
+ p = p->Flink) {
+
+ RipReserved = CONTAINING_RECORD (p, IPX_SEND_RESERVED, WaitLinkage);
+
+ if (RipReserved->u.SR_RIP.RetryCount >= 0xfe) {
+ continue;
+ }
+
+ if (RipReserved->u.SR_RIP.Network ==
+ RipPacket->NetworkEntry.NetworkNumber) {
+ break;
+ }
+
+ }
+
+ if (p == &Device->WaitingRipPackets) {
+
+ //
+ // No packets pending on this, return.
+ //
+
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ return;
+ }
+
+
+ //
+ // Put the RIP packet back in the pool.
+ //
+
+ IPX_DEBUG (RIP, ("Got RIP response for network %lx\n",
+ REORDER_ULONG(RipPacket->NetworkEntry.NetworkNumber)));
+
+ RipReserved->u.SR_RIP.RouteFound = TRUE;
+ if (!RipReserved->SendInProgress) {
+
+ //
+ // If the send is done destroy it now, otherwise
+ // when it pops up in RipShortTimeout it will get
+ // destroyed because RouteFound is TRUE.
+ //
+
+ RemoveEntryList (p);
+ RipReserved->Identifier = IDENTIFIER_IPX;
+ IPX_PUSH_ENTRY_LIST (&Device->SendPacketList, &RipReserved->PoolLinkage, &Device->SListsLock);
+ --Device->RipPacketCount;
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+
+ IpxDereferenceDevice (Device, DREF_RIP_PACKET);
+
+ } else {
+
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ }
+
+
+ //
+ // Try to allocate and add a router segment unless the
+ // RIP router is active...if we don't that is fine, we'll
+ // just re-RIP later.
+ //
+
+ Segment = RipGetSegment ((PUCHAR)&RipPacket->NetworkEntry.NetworkNumber);
+
+ if (!Device->UpperDriverBound[IDENTIFIER_RIP]) {
+
+ RouteEntry = IpxAllocateMemory(sizeof(IPX_ROUTE_ENTRY), MEMORY_RIP, "RouteEntry");
+ if (RouteEntry != (PIPX_ROUTE_ENTRY)NULL) {
+
+ *(UNALIGNED LONG *)RouteEntry->Network = RipPacket->NetworkEntry.NetworkNumber;
+#ifdef _PNP_POWER
+ RouteEntry->NicId = NIC_FROM_LOCAL_TARGET(LocalTarget);
+ RouteEntry->NdisBindingContext = NIC_ID_TO_BINDING(Device, RouteEntry->NicId)->Adapter->NdisBindingHandle;
+ // BUGBUG: What if this is NULL??
+#else
+ RouteEntry->NicId = LocalTarget->NicId;
+ RouteEntry->NdisBindingContext = Device->Bindings[LocalTarget->NicId]->Adapter->NdisBindingHandle; // BUGBUG: What if this is NULL??
+#endif
+ RouteEntry->Flags = 0;
+ RouteEntry->Timer = 0;
+ RouteEntry->PRIVATE.Reserved[0] = 0;
+ RouteEntry->Segment = Segment;
+ RouteEntry->HopCount = REORDER_USHORT(RipPacket->NetworkEntry.HopCount);
+ RouteEntry->TickCount = REORDER_USHORT(RipPacket->NetworkEntry.TickCount);
+ InitializeListHead (&RouteEntry->AlternateRoute);
+ InitializeListHead (&RouteEntry->NicLinkage);
+ RtlCopyMemory (RouteEntry->NextRouter, LocalTarget->MacAddress, 6);
+
+ IPX_GET_LOCK (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // Replace any existing routes. This is OK because once
+ // we get the first response to a RIP packet on a given
+ // route, we will take the packet out of the queue and
+ // ignore further responses. We will only get a bad route
+ // if we do two requests really quickly and there
+ // are two routes, and the second response to the first
+ // request is picked up as the first response to the second
+ // request.
+ //
+
+ if ((OldRouteEntry = RipGetRoute (Segment, (PUCHAR)&(RipPacket->NetworkEntry.NetworkNumber))) != NULL) {
+
+ //
+ // These are saved so timeouts etc. happen right.
+ //
+
+ RouteEntry->Flags = OldRouteEntry->Flags;
+ RouteEntry->Timer = OldRouteEntry->Timer;
+
+ RipDeleteRoute (Segment, OldRouteEntry);
+ IpxFreeMemory(OldRouteEntry, sizeof(IPX_ROUTE_ENTRY), MEMORY_RIP, "RouteEntry");
+
+ }
+
+ RipAddRoute (Segment, RouteEntry);
+
+ } else {
+
+ IPX_GET_LOCK (&Device->SegmentLocks[Segment], &LockHandle);
+ }
+
+ } else {
+
+ IPX_GET_LOCK (&Device->SegmentLocks[Segment], &LockHandle);
+ }
+
+ //
+ // Complete all datagrams etc. that were waiting
+ // for this route. This call releases the lock.
+ //
+
+ RipHandleRoutePending(
+ Device,
+ (PUCHAR)&(RipPacket->NetworkEntry.NetworkNumber),
+ LockHandle,
+ TRUE,
+ LocalTarget,
+ (USHORT)(REORDER_USHORT(RipPacket->NetworkEntry.HopCount)),
+ (USHORT)(REORDER_USHORT(RipPacket->NetworkEntry.TickCount))
+ );
+
+} /* RipProcessResponse */
+
+VOID
+RipHandleRoutePending(
+ IN PDEVICE Device,
+ IN UCHAR Network[4],
+ IN CTELockHandle LockHandle,
+ IN BOOLEAN Success,
+ IN OPTIONAL PIPX_LOCAL_TARGET LocalTarget,
+ IN OPTIONAL USHORT HopCount,
+ IN OPTIONAL USHORT TickCount
+ )
+
+/*++
+
+Routine Description:
+
+ This routine cleans up pending datagrams, find route
+ requests, and GET_LOCAL_TARGET ioctls that were
+ waiting for a route to be found.
+
+ THIS ROUTINE IS CALLED WITH THE SEGMENT LOCK HELD AND
+ RETURNS WITH IT RELEASED.
+
+Arguments:
+
+ Device - The device.
+
+ Network - The network in question.
+
+ LockHandle - The handle used to acquire the lock.
+
+ Success - TRUE if the route was successfully found.
+
+ LocalTarget - If Success is TRUE, the local target for the route.
+
+ HopCount - If Success is TRUE, the hop count for the route,
+ in machine order.
+
+ TickCount - If Success is TRUE, the tick count for the route,
+ in machine order.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ LIST_ENTRY DatagramList;
+ LIST_ENTRY FindRouteList;
+ LIST_ENTRY GetLocalTargetList;
+ LIST_ENTRY ReripNetnumList;
+ PIPX_SEND_RESERVED WaitReserved; // ProtocolReserved of waiting packet
+ PIPX_FIND_ROUTE_REQUEST FindRouteRequest;
+ PREQUEST GetLocalTargetRequest;
+ PREQUEST ReripNetnumRequest;
+ PISN_ACTION_GET_LOCAL_TARGET GetLocalTarget;
+ PIPX_NETNUM_DATA NetnumData;
+ ULONG Segment;
+ PBINDING Binding, SendBinding;
+ PLIST_ENTRY p;
+ PNDIS_PACKET Packet;
+ PIPX_HEADER IpxHeader;
+ ULONG HeaderSize;
+ NDIS_STATUS NdisStatus;
+ ULONG NetworkUlong = *(UNALIGNED ULONG *)Network;
+
+
+ InitializeListHead (&DatagramList);
+ InitializeListHead (&FindRouteList);
+ InitializeListHead (&GetLocalTargetList);
+ InitializeListHead (&ReripNetnumList);
+
+
+ //
+ // Put all packets that were waiting for a route to
+ // this network on DatagramList. They will be sent
+ // or failed later in the routine.
+ //
+
+ Segment = RipGetSegment (Network);
+
+ p = Device->Segments[Segment].WaitingForRoute.Flink;
+
+ while (p != &Device->Segments[Segment].WaitingForRoute) {
+
+ WaitReserved = CONTAINING_RECORD (p, IPX_SEND_RESERVED, WaitLinkage);
+ p = p->Flink;
+#if 0
+ if (*(UNALIGNED ULONG *)(((PIPX_HEADER)(&WaitReserved->Header[Device->IncludedHeaderOffset]))->DestinationNetwork) ==
+ NetworkUlong) {
+#endif
+ if (*(UNALIGNED ULONG *)(((PIPX_HEADER)(&WaitReserved->Header[MAC_HEADER_SIZE]))->DestinationNetwork) ==
+ NetworkUlong) {
+
+ RemoveEntryList (&WaitReserved->WaitLinkage);
+ InsertTailList (&DatagramList, &WaitReserved->WaitLinkage);
+ }
+
+ }
+
+ //
+ // Put all find route requests for this network on
+ // FindRouteList. They will be completed later in the
+ // routine.
+ //
+
+ p = Device->Segments[Segment].FindWaitingForRoute.Flink;
+
+ while (p != &Device->Segments[Segment].FindWaitingForRoute) {
+
+ FindRouteRequest = CONTAINING_RECORD (p, IPX_FIND_ROUTE_REQUEST, Linkage);
+ p = p->Flink;
+ if (*(UNALIGNED ULONG *)(FindRouteRequest->Network) ==
+ NetworkUlong) {
+
+ RemoveEntryList (&FindRouteRequest->Linkage);
+ InsertTailList (&FindRouteList, &FindRouteRequest->Linkage);
+ }
+
+ }
+
+ //
+ // Put all get local target action requests for this
+ // network on GetLocalTargetList. They will be completed
+ // later in the routine.
+ //
+
+ p = Device->Segments[Segment].WaitingLocalTarget.Flink;
+
+ while (p != &Device->Segments[Segment].WaitingLocalTarget) {
+
+ GetLocalTargetRequest = LIST_ENTRY_TO_REQUEST(p);
+ p = p->Flink;
+ GetLocalTarget = (PISN_ACTION_GET_LOCAL_TARGET)REQUEST_INFORMATION(GetLocalTargetRequest);
+ if (GetLocalTarget->IpxAddress.NetworkAddress == NetworkUlong) {
+
+ RemoveEntryList (REQUEST_LINKAGE(GetLocalTargetRequest));
+ InsertTailList (&GetLocalTargetList, REQUEST_LINKAGE(GetLocalTargetRequest));
+ }
+
+ }
+
+ //
+ // Put all MIPX_RERIPNETNUM action requests for this
+ // network on ReripNetnumList. They will be completed
+ // later in the routine.
+ //
+
+ p = Device->Segments[Segment].WaitingReripNetnum.Flink;
+
+ while (p != &Device->Segments[Segment].WaitingReripNetnum) {
+
+ ReripNetnumRequest = LIST_ENTRY_TO_REQUEST(p);
+ p = p->Flink;
+ NetnumData = (PIPX_NETNUM_DATA)REQUEST_INFORMATION(ReripNetnumRequest);
+ if (*(UNALIGNED ULONG *)NetnumData->netnum == NetworkUlong) {
+
+ RemoveEntryList (REQUEST_LINKAGE(ReripNetnumRequest));
+ InsertTailList (&ReripNetnumList, REQUEST_LINKAGE(ReripNetnumRequest));
+ }
+
+ }
+
+
+ IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
+
+ //
+ // For sends we will use the master binding of a binding
+ // set, but we'll return the real NicId for people who
+ // want that.
+ //
+
+ if (Success) {
+#ifdef _PNP_POWER
+ Binding = NIC_ID_TO_BINDING(Device, NIC_FROM_LOCAL_TARGET(LocalTarget));
+
+ if (Binding->BindingSetMember) {
+ SendBinding = Binding->MasterBinding;
+ FILL_LOCAL_TARGET(LocalTarget, MIN( Device->MaxBindings, SendBinding->NicId));
+ } else {
+ SendBinding = Binding;
+ }
+#else
+ Binding = Device->Bindings[LocalTarget->NicId];
+
+ if (Binding->BindingSetMember) {
+ SendBinding = Binding->MasterBinding;
+ LocalTarget->NicId = SendBinding->NicId;
+ } else {
+ SendBinding = Binding;
+ }
+#endif
+ }
+
+
+ //
+ // Now that the lock is free, process all packets on
+ // DatagramList.
+ //
+ // NOTE: May misorder packets if they come in right now...
+ //
+
+ for (p = DatagramList.Flink; p != &DatagramList ; ) {
+
+ WaitReserved = CONTAINING_RECORD (p, IPX_SEND_RESERVED, WaitLinkage);
+ p = p->Flink;
+ Packet = CONTAINING_RECORD (WaitReserved, NDIS_PACKET, ProtocolReserved[0]);
+
+#if DBG
+ CTEAssert (!WaitReserved->SendInProgress);
+ WaitReserved->SendInProgress = TRUE;
+#endif
+
+ if (Success) {
+
+ IPX_DEBUG (RIP, ("Found queued packet %lx\n", WaitReserved));
+
+ if (REQUEST_INFORMATION(WaitReserved->u.SR_DG.Request) >
+ SendBinding->RealMaxDatagramSize) {
+
+ IPX_DEBUG (SEND, ("Queued send %d bytes too large (%d)\n",
+ REQUEST_INFORMATION(WaitReserved->u.SR_DG.Request),
+ SendBinding->RealMaxDatagramSize));
+
+ IpxSendComplete(
+ (NDIS_HANDLE)NULL,
+ Packet,
+ STATUS_INVALID_BUFFER_SIZE);
+
+ } else {
+
+#if 0
+ if (WaitReserved->DestinationType == DESTINATION_DEF) {
+ HeaderSize = SendBinding->DefHeaderSize;
+ } else {
+ HeaderSize = SendBinding->BcMcHeaderSize;
+ }
+
+ IpxHeader = (PIPX_HEADER)
+ (&WaitReserved->Header[HeaderSize]);
+#endif
+ IpxHeader = (PIPX_HEADER)
+ (&WaitReserved->Header[MAC_HEADER_SIZE]);
+
+ //
+ // Move the header to the correct location now that
+ // we know the NIC ID to send to.
+ //
+#if 0
+ if (HeaderSize != Device->IncludedHeaderOffset) {
+
+ RtlMoveMemory(
+ IpxHeader,
+ &WaitReserved->Header[Device->IncludedHeaderOffset],
+ sizeof(IPX_HEADER));
+
+ }
+#endif
+
+ if (Device->MultiCardZeroVirtual ||
+ (IpxHeader->DestinationSocket == SAP_SOCKET)) {
+
+ //
+ // These frames need to look like they come from the
+ // local network, not the virtual one.
+ //
+
+ *(UNALIGNED ULONG *)IpxHeader->SourceNetwork = SendBinding->LocalAddress.NetworkAddress;
+ RtlCopyMemory (IpxHeader->SourceNode, SendBinding->LocalAddress.NodeAddress, 6);
+ }
+
+ //
+ // Fill in the MAC header and submit the frame to NDIS.
+ //
+
+ if ((NdisStatus = IpxSendFrame(
+ LocalTarget,
+ Packet,
+ REQUEST_INFORMATION(WaitReserved->u.SR_DG.Request) + sizeof(IPX_HEADER),
+ sizeof(IPX_HEADER))) != NDIS_STATUS_PENDING) {
+
+ IpxSendComplete(
+ (NDIS_HANDLE)SendBinding->Adapter,
+ Packet,
+ NdisStatus);
+ }
+
+ }
+
+ } else {
+
+ IPX_DEBUG (RIP, ("Timing out packet %lx\n", WaitReserved));
+
+ IpxSendComplete(
+ (NDIS_HANDLE)NULL,
+ Packet,
+ STATUS_BAD_NETWORK_PATH);
+
+ }
+
+ }
+
+
+ //
+ // Since we round-robin outgoing rip packets, we just use the
+ // real NicId here for find route and get local target requests.
+ // We changed LocalTarget->NicId to be the master above.
+ //
+
+ if (Success) {
+#ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(LocalTarget, MIN( Device->MaxBindings, Binding->NicId));
+#else
+ LocalTarget->NicId = Binding->NicId;
+#endif
+ }
+
+ for (p = FindRouteList.Flink; p != &FindRouteList ; ) {
+
+ FindRouteRequest = CONTAINING_RECORD (p, IPX_FIND_ROUTE_REQUEST, Linkage);
+ p = p->Flink;
+
+ if (Success) {
+
+ PUSHORT Counts;
+
+ IPX_DEBUG (RIP, ("Found queued find route %lx\n", FindRouteRequest));
+ FindRouteRequest->LocalTarget = *LocalTarget;
+
+ Counts = (PUSHORT)&FindRouteRequest->Reserved2;
+ Counts[0] = TickCount;
+ Counts[1] = HopCount;
+
+ } else {
+
+ IPX_DEBUG (RIP, ("Timing out find route %lx\n", FindRouteRequest));
+
+ }
+
+ (*Device->UpperDrivers[FindRouteRequest->Identifier].FindRouteCompleteHandler)(
+ FindRouteRequest,
+ Success);
+
+ }
+
+ for (p = GetLocalTargetList.Flink; p != &GetLocalTargetList ; ) {
+
+ GetLocalTargetRequest = LIST_ENTRY_TO_REQUEST(p);
+ p = p->Flink;
+ GetLocalTarget = (PISN_ACTION_GET_LOCAL_TARGET)REQUEST_INFORMATION(GetLocalTargetRequest);
+
+ if (Success) {
+
+ IPX_DEBUG (RIP, ("Found queued LOCAL_TARGET action %lx\n", GetLocalTargetRequest));
+ GetLocalTarget->LocalTarget = *LocalTarget;
+ REQUEST_INFORMATION(GetLocalTargetRequest) = sizeof(ISN_ACTION_GET_LOCAL_TARGET);
+ REQUEST_STATUS(GetLocalTargetRequest) = STATUS_SUCCESS;
+
+ } else {
+
+ IPX_DEBUG (RIP, ("Timing out LOCAL_TARGET action %lx\n", GetLocalTargetRequest));
+ REQUEST_INFORMATION(GetLocalTargetRequest) = 0;
+ REQUEST_STATUS(GetLocalTargetRequest) = STATUS_BAD_NETWORK_PATH;
+ }
+
+ IpxCompleteRequest(GetLocalTargetRequest);
+ IpxFreeRequest(Device, GetLocalTargetRequest);
+
+ }
+
+ //
+ // NOTE: LocalTarget->NicId now points to the real binding
+ // not the master, so we use SendBinding->NicId below.
+ //
+
+ for (p = ReripNetnumList.Flink; p != &ReripNetnumList ; ) {
+
+ ReripNetnumRequest = LIST_ENTRY_TO_REQUEST(p);
+ p = p->Flink;
+ NetnumData = (PIPX_NETNUM_DATA)REQUEST_INFORMATION(ReripNetnumRequest);
+
+ if (Success) {
+
+ IPX_DEBUG (RIP, ("Found queued MIPX_RERIPNETNUM action %lx\n", ReripNetnumRequest));
+ NetnumData->hopcount = HopCount;
+ NetnumData->netdelay = TickCount;
+ NetnumData->cardnum = (INT)(MIN( Device->MaxBindings, SendBinding->NicId) - 1);
+ RtlMoveMemory (NetnumData->router, LocalTarget->MacAddress, 6);
+
+ REQUEST_INFORMATION(ReripNetnumRequest) =
+ FIELD_OFFSET(NWLINK_ACTION, Data[0]) + sizeof(IPX_NETNUM_DATA);
+ REQUEST_STATUS(ReripNetnumRequest) = STATUS_SUCCESS;
+
+ } else {
+
+ IPX_DEBUG (RIP, ("Timing out MIPX_RERIPNETNUM action %lx\n", ReripNetnumRequest));
+ REQUEST_INFORMATION(ReripNetnumRequest) = 0;
+ REQUEST_STATUS(ReripNetnumRequest) = STATUS_BAD_NETWORK_PATH;
+ }
+
+ IpxCompleteRequest(ReripNetnumRequest);
+ IpxFreeRequest(Device, ReripNetnumRequest);
+
+ }
+
+} /* RipHandleRoutePending */
+
+
+NTSTATUS
+RipInsertLocalNetwork(
+ IN ULONG Network,
+ IN USHORT NicId,
+ IN NDIS_HANDLE NdisBindingContext,
+ IN USHORT Count
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates a router entry for a local network
+ and inserts it in the table.
+
+Arguments:
+
+ Network - The network.
+
+ NicId - The NIC ID used to route packets
+
+ NdisBindingHandle - The binding handle used for NdisSend
+
+ Count - The tick and hop count for this network (will be
+ 0 for the virtual net and 1 for attached nets)
+
+Return Value:
+
+ The status of the operation.
+
+--*/
+
+{
+ PIPX_ROUTE_ENTRY RouteEntry;
+ PDEVICE Device = IpxDevice;
+ ULONG Segment;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+
+ //
+ // BUGBUG: We should allocate the memory in the binding/device
+ // structure itself.
+ //
+
+ RouteEntry = IpxAllocateMemory(sizeof(IPX_ROUTE_ENTRY), MEMORY_RIP, "RouteEntry");
+ if (RouteEntry == (PIPX_ROUTE_ENTRY)NULL) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ Segment = RipGetSegment ((PUCHAR)&Network);
+
+ *(UNALIGNED LONG *)RouteEntry->Network = Network;
+ RouteEntry->NicId = NicId;
+ RouteEntry->NdisBindingContext = NdisBindingContext;
+
+ if (NicId == 0) {
+ RouteEntry->Flags = IPX_ROUTER_PERMANENT_ENTRY;
+ } else {
+ RouteEntry->Flags = IPX_ROUTER_PERMANENT_ENTRY | IPX_ROUTER_LOCAL_NET;
+ }
+ RouteEntry->Segment = Segment;
+ RouteEntry->TickCount = Count;
+ RouteEntry->HopCount = 1;
+ InitializeListHead (&RouteEntry->AlternateRoute);
+ InitializeListHead (&RouteEntry->NicLinkage);
+
+ //
+ // RouteEntry->NextRouter is not used for the virtual net or
+ // when LOCAL_NET is set (i.e. every net that we will add here).
+ //
+
+ RtlZeroMemory (RouteEntry->NextRouter, 6);
+
+ IPX_GET_LOCK (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // Make sure one doesn't exist.
+ //
+
+ if (RipGetRoute(Segment, (PUCHAR)&Network) != NULL) {
+ IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
+ IpxFreeMemory (RouteEntry, sizeof(IPX_ROUTE_ENTRY), MEMORY_RIP, "RouteEntry");
+ return STATUS_DUPLICATE_NAME;
+ }
+
+ //
+ // Add this new entry.
+ //
+
+ if (RipAddRoute (Segment, RouteEntry)) {
+
+ IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
+ return STATUS_SUCCESS;
+
+ } else {
+
+ IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
+ IpxFreeMemory (RouteEntry, sizeof(IPX_ROUTE_ENTRY), MEMORY_RIP, "RouteEntry");
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ }
+
+} /* RipInsertLocalNetwork */
+
+
+VOID
+RipAdjustForBindingChange(
+ IN USHORT NicId,
+ IN USHORT NewNicId,
+ IN IPX_BINDING_CHANGE_TYPE ChangeType
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when an auto-detect binding is
+ deleted or moved, or a WAN line goes down.
+
+ It scans the RIP database for routes equal to this NIC ID
+ and modifies them appropriately. If ChangeType is
+ IpxBindingDeleted it will subract one from any NIC IDs
+ in the database that are higher than NicId. It is assumed
+ that other code is readjusting the Device->Bindings
+ array.
+
+Arguments:
+
+ NicId - The NIC ID of the deleted binding.
+
+ NewNicId - The new NIC ID, for IpxBindingMoved changes.
+
+ ChangeType - Either IpxBindingDeleted, IpxBindingMoved,
+ or IpxBindingDown.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = IpxDevice;
+ PIPX_ROUTE_ENTRY RouteEntry;
+ UINT Segment;
+ CTELockHandle LockHandle;
+
+ for (Segment = 0; Segment < Device->SegmentCount; Segment++) {
+
+ CTEGetLock (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // Scan through each entry comparing the NIC ID.
+ //
+
+ for (RouteEntry = RipGetFirstRoute (Segment);
+ RouteEntry != (PIPX_ROUTE_ENTRY)NULL;
+ RouteEntry = RipGetNextRoute (Segment)) {
+
+ if (RouteEntry->NicId == NicId) {
+
+ if (ChangeType != IpxBindingMoved) {
+
+ IPX_DEBUG (AUTO_DETECT, ("Deleting route entry %lx, binding deleted\n", RouteEntry));
+ RipDeleteRoute (Segment, RouteEntry);
+
+ } else {
+
+ IPX_DEBUG (AUTO_DETECT, ("Changing NIC ID for route entry %lx\n", RouteEntry));
+ RouteEntry->NicId = NewNicId;
+
+ }
+#ifdef _PNP_POWER
+ //
+ // If the NicId is 0, we dont adjust the other entries' NicId's - this is to support the removal
+ // of the Virtual Net # which resides at NicId=0.
+ //
+ } else if (NicId && (ChangeType != IpxBindingDown) && (RouteEntry->NicId > NicId)) {
+#else
+ } else if ((ChangeType != IpxBindingDown) && (RouteEntry->NicId > NicId)) {
+#endif
+ IPX_DEBUG (AUTO_DETECT, ("Decrementing NIC ID for route entry %lx\n", RouteEntry));
+ --RouteEntry->NicId;
+
+ }
+ }
+
+ CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
+
+ }
+
+} /* RipAdjustForBindingChange */
+
+
+UINT
+RipGetSegment(
+ IN UCHAR Network[4]
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the correct segment for the specified
+ network.
+
+Arguments:
+
+ Network - The network.
+
+Return Value:
+
+ The segment.
+
+--*/
+
+{
+
+ ULONG Total;
+
+ Total = Network[0] ^ Network[1] ^ Network[2] ^ Network[3];
+ return (Total % IpxDevice->SegmentCount);
+
+} /* RipGetSegment */
+
+
+PIPX_ROUTE_ENTRY
+RipGetRoute(
+ IN UINT Segment,
+ IN UCHAR Network[4]
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the router table entry for the given
+ network, which is in the specified segment of the table.
+ THE SEGMENT LOCK MUST BE HELD. The returned data is valid
+ until the segment lock is released or other operations
+ (add/delete) are performed on the segment.
+
+Arguments:
+
+ Segment - The segment corresponding to the network.
+
+ Network - The network.
+
+Return Value:
+
+ The router table entry, or NULL if none exists for this network.
+
+--*/
+
+{
+ PLIST_ENTRY p;
+ PROUTER_SEGMENT RouterSegment;
+ PIPX_ROUTE_ENTRY RouteEntry;
+
+ RouterSegment = &IpxDevice->Segments[Segment];
+
+ for (p = RouterSegment->Entries.Flink;
+ p != &RouterSegment->Entries;
+ p = p->Flink) {
+
+ RouteEntry = CONTAINING_RECORD(
+ p,
+ IPX_ROUTE_ENTRY,
+ PRIVATE.Linkage);
+
+ if ((*(UNALIGNED LONG *)RouteEntry->Network) ==
+ (*(UNALIGNED LONG *)Network)) {
+ return RouteEntry;
+ }
+ }
+
+ return NULL;
+
+} /* RipGetRoute */
+
+
+BOOLEAN
+RipAddRoute(
+ IN UINT Segment,
+ IN PIPX_ROUTE_ENTRY RouteEntry
+ )
+
+/*++
+
+Routine Description:
+
+ This routine stores a router table entry in the
+ table, which must belong in the specified segment.
+ THE SEGMENT LOCK MUST BE HELD. Storage for the entry
+ is allocated and filled in by the caller.
+
+Arguments:
+
+ Segment - The segment corresponding to the network.
+
+ RouteEntry - The router table entry.
+
+Return Value:
+
+ TRUE if the entry was successfully inserted.
+
+--*/
+
+{
+
+ IPX_DEBUG (RIP, ("Adding route for network %lx (%d)\n",
+ REORDER_ULONG(*(UNALIGNED ULONG *)RouteEntry->Network), Segment));
+ InsertTailList(
+ &IpxDevice->Segments[Segment].Entries,
+ &RouteEntry->PRIVATE.Linkage);
+
+ return TRUE;
+
+} /* RipAddRoute */
+
+
+BOOLEAN
+RipDeleteRoute(
+ IN UINT Segment,
+ IN PIPX_ROUTE_ENTRY RouteEntry
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deletes a router table entry in the
+ table, which must belong in the specified segment.
+ THE SEGMENT LOCK MUST BE HELD. Storage for the entry
+ is freed by the caller.
+
+Arguments:
+
+ Segment - The segment corresponding to the network.
+
+ RouteEntry - The router table entry.
+
+Return Value:
+
+ TRUE if the entry was successfully deleted.
+
+--*/
+
+{
+
+ PROUTER_SEGMENT RouterSegment = &IpxDevice->Segments[Segment];
+
+ IPX_DEBUG (RIP, ("Deleting route for network %lx (%d)\n",
+ REORDER_ULONG(*(UNALIGNED ULONG *)RouteEntry->Network), Segment));
+
+ //
+ // If the current enumeration point for this segment is here,
+ // adjust the pointer before deleting the entry. We make it
+ // point to the previous entry so GetNextRoute will work.
+ //
+
+ if (RouterSegment->EnumerateLocation == &RouteEntry->PRIVATE.Linkage) {
+ RouterSegment->EnumerateLocation = RouterSegment->EnumerateLocation->Blink;
+ }
+
+ RemoveEntryList (&RouteEntry->PRIVATE.Linkage);
+
+ return TRUE;
+
+} /* RipDeleteRoute */
+
+
+PIPX_ROUTE_ENTRY
+RipGetFirstRoute(
+ IN UINT Segment
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the first router table entry in the
+ segment. THE SEGMENT LOCK MUST BE HELD. It is used in
+ conjunction with RipGetNextRoute to enumerate all the
+ entries in a segment.
+
+Arguments:
+
+ Segment - The segment being enumerated.
+
+Return Value:
+
+ The first router table entry, or NULL if the segment is empty.
+
+--*/
+
+{
+ PIPX_ROUTE_ENTRY FirstEntry;
+ PROUTER_SEGMENT RouterSegment = &IpxDevice->Segments[Segment];
+
+ RouterSegment->EnumerateLocation = RouterSegment->Entries.Flink;
+
+ if (RouterSegment->EnumerateLocation == &RouterSegment->Entries) {
+
+ return NULL;
+
+ } else {
+
+ FirstEntry = CONTAINING_RECORD(
+ RouterSegment->EnumerateLocation,
+ IPX_ROUTE_ENTRY,
+ PRIVATE.Linkage);
+
+ return FirstEntry;
+
+ }
+
+} /* RipGetFirstRoute */
+
+
+PIPX_ROUTE_ENTRY
+RipGetNextRoute(
+ IN UINT Segment
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the next router table entry in the
+ segment. THE SEGMENT LOCK MUST BE HELD. It is used in
+ conjunction with RipGetFirstRoute to enumerate all the
+ entries in a segment.
+
+ It is illegal to call RipGetNextRoute on a segment
+ without first calling RipGetFirstRoute. The segment
+ lock must be held for the duration of the enumeration
+ of a single segment. It is legal to stop enumerating
+ the segment in the middle.
+
+Arguments:
+
+ Segment - The segment being enumerated.
+
+Return Value:
+
+ The next router table entry, or NULL if the end of the
+ segment is reached.
+
+--*/
+
+{
+ PIPX_ROUTE_ENTRY NextEntry;
+ PROUTER_SEGMENT RouterSegment = &IpxDevice->Segments[Segment];
+
+ RouterSegment->EnumerateLocation = RouterSegment->EnumerateLocation->Flink;
+
+ if (RouterSegment->EnumerateLocation == &RouterSegment->Entries) {
+
+ return NULL;
+
+ } else {
+
+ NextEntry = CONTAINING_RECORD(
+ RouterSegment->EnumerateLocation,
+ IPX_ROUTE_ENTRY,
+ PRIVATE.Linkage);
+
+ return NextEntry;
+
+ }
+
+} /* RipGetNextRoute */
+
+
+VOID
+RipDropRemoteEntries(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deletes all non-local entries from the
+ RIP database. It is called when the WAN line goes up
+ or down and we want to remove all existing entries.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = IpxDevice;
+ PIPX_ROUTE_ENTRY RouteEntry;
+ UINT Segment;
+ CTELockHandle LockHandle;
+
+ for (Segment = 0; Segment < Device->SegmentCount; Segment++) {
+
+ CTEGetLock (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // Scan through, deleting everything but local entries.
+ //
+
+ for (RouteEntry = RipGetFirstRoute (Segment);
+ RouteEntry != (PIPX_ROUTE_ENTRY)NULL;
+ RouteEntry = RipGetNextRoute (Segment)) {
+
+ if ((RouteEntry->Flags & IPX_ROUTER_PERMANENT_ENTRY) == 0) {
+
+ IPX_DEBUG (AUTO_DETECT, ("Deleting route entry %lx, dropping remote entries\n", RouteEntry));
+ RipDeleteRoute (Segment, RouteEntry);
+
+ }
+ }
+
+ CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
+
+ }
+
+} /* RipDropRemoteEntries */
+
diff --git a/private/ntos/tdi/isnp/ipx/send.c b/private/ntos/tdi/isnp/ipx/send.c
new file mode 100644
index 000000000..fd9a62a7d
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/send.c
@@ -0,0 +1,1651 @@
+
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ send.c
+
+Abstract:
+
+ This module contains code that implements the send engine for the
+ IPX transport provider.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) - August-25-1995
+ Bug Fixes - tagged [SA]
+ Sanjay Anand (SanjayAn) - 22-Sept-1995
+ BackFill optimization changes added under #if BACK_FILL
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+//
+// BUGBUG Using the macro for performance reasons. Should be taken out
+// when NdisQueryPacket is optimized. In the near future (after PPC release)
+// move this to a header file and use it at other places.
+//
+#define IPX_PACKET_HEAD(Pkt) (Pkt)->Private.Head
+
+#if 0
+#define IpxGetMdlChainLength(Mdl, Length) { \
+ PMDL _Mdl = (Mdl); \
+ *(Length) = 0; \
+ while (_Mdl) { \
+ *(Length) += MmGetMdlByteCount(_Mdl); \
+ _Mdl = _Mdl->Next; \
+ } \
+}
+#endif
+
+VOID
+IpxSendComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_PACKET NdisPacket,
+ IN NDIS_STATUS NdisStatus
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to indicate that a connection-
+ oriented packet has been shipped and is no longer needed by the Physical
+ Provider.
+
+Arguments:
+
+ ProtocolBindingContext - The ADAPTER structure for this binding.
+
+ NdisPacket/RequestHandle - A pointer to the NDIS_PACKET that we sent.
+
+ NdisStatus - the completion status of the send.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(NdisPacket->ProtocolReserved);
+ PADAPTER Adapter = (PADAPTER)ProtocolBindingContext;
+ PREQUEST Request;
+ PADDRESS_FILE AddressFile;
+ PDEVICE Device = IpxDevice;
+ PBINDING Binding;
+ USHORT NewId, OldId;
+ ULONG NewOffset, OldOffset;
+ PIPX_HEADER IpxHeader;
+ IPX_LOCAL_TARGET LocalTarget;
+ PIO_STACK_LOCATION irpSp;
+
+#ifdef _PNP_POWER
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+#endif
+
+#if DBG
+ if (Adapter != NULL) {
+ ASSERT_ADAPTER(Adapter);
+ }
+#endif
+
+ //
+ // See if this send was padded.
+ //
+
+ if (Reserved->PaddingBuffer) {
+
+ UINT Offset;
+ //
+ // Check if we simply need to re-adjust the buffer length. This will
+ // happen if we incremented the buffer length in MAC.C.
+ //
+
+ if (Reserved->PreviousTail) {
+ CTEAssert (NDIS_BUFFER_LINKAGE(Reserved->PaddingBuffer->NdisBuffer) == NULL);
+ NDIS_BUFFER_LINKAGE (Reserved->PreviousTail) = (PNDIS_BUFFER)NULL;
+ } else {
+ PNDIS_BUFFER LastBuffer = (PNDIS_BUFFER)Reserved->PaddingBuffer;
+ UINT BufferLength;
+
+ NdisQueryBufferOffset( LastBuffer, &Offset, &BufferLength );
+ NdisAdjustBufferLength( LastBuffer, (BufferLength - 1) );
+ }
+
+ Reserved->PaddingBuffer = NULL;
+
+ if (Reserved->Identifier < IDENTIFIER_IPX) {
+ NdisRecalculatePacketCounts (NdisPacket);
+ }
+ }
+
+FunctionStart:;
+
+ switch (Reserved->Identifier) {
+
+ case IDENTIFIER_IPX:
+
+// #if DBG
+ CTEAssert (Reserved->SendInProgress);
+ Reserved->SendInProgress = FALSE;
+// #endif
+
+ //
+ // Check if this packet should be sent to all
+ // networks.
+ //
+
+ if (Reserved->u.SR_DG.CurrentNicId) {
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS) {
+ Reserved->u.SR_DG.Net0SendSucceeded = TRUE;
+ }
+
+ OldId = Reserved->u.SR_DG.CurrentNicId;
+
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ {
+ ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
+
+ for (NewId = OldId+1; NewId <= Index; NewId++) {
+ if ((Binding = NIC_ID_TO_BINDING(Device, NewId))
+#else
+ for (NewId = OldId+1; NewId <= Device->HighestExternalNicId; NewId++) {
+ if ((Binding = Device->Bindings[NewId])
+#endif _PNP_POWER
+ &&
+ ((!Device->SingleNetworkActive) ||
+ (Device->ActiveNetworkWan == Binding->Adapter->MacInfo.MediumAsync))
+ &&
+ ((!Device->DisableDialoutSap) ||
+ (!Binding->DialOutAsync) ||
+ (!Reserved->u.SR_DG.OutgoingSap))) {
+
+ //
+ // The binding exists, and we either are not configured
+ // for "SingleNetworkActive", or we are and this binding
+ // is the right type (i.e. the active network is wan and
+ // this is a wan binding, or the active network is not
+ // wan and this is not a wan binding), and this is not
+ // an outgoing sap that we are trying to send with
+ // "DisableDialoutSap" set.
+ //
+
+ break;
+ }
+ }
+ }
+
+ if (NewId <= MIN (Device->MaxBindings, Device->HighestExternalNicId)) {
+#ifdef _PNP_POWER
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif _PNP_POWER
+
+ //
+ // Yes, we found another net to send it on, so
+ // move the header around if needed and do so.
+ //
+
+ Reserved->u.SR_DG.CurrentNicId = NewId;
+ CTEAssert ((Reserved->DestinationType == DESTINATION_BCAST) ||
+ (Reserved->DestinationType == DESTINATION_MCAST));
+
+#if 0
+ NewOffset = Binding->BcMcHeaderSize;
+ OldOffset = Device->Bindings[OldId]->BcMcHeaderSize;
+
+ if (OldOffset != NewOffset) {
+
+ RtlMoveMemory(
+ &Reserved->Header[NewOffset],
+ &Reserved->Header[OldOffset],
+ sizeof(IPX_HEADER));
+
+ }
+
+ IpxHeader = (PIPX_HEADER)(&Reserved->Header[NewOffset]);
+#endif
+
+
+
+#if BACK_FILL
+ // This should be a normal packet. Backfill packet is never used for
+ // reserved other than IPX type
+
+ CTEAssert(!Reserved->BackFill);
+#endif
+
+ IpxHeader = (PIPX_HEADER)(&Reserved->Header[MAC_HEADER_SIZE]);
+
+#ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(&LocalTarget, NewId);
+#else
+ LocalTarget.NicId = NewId;
+#endif
+ RtlCopyMemory(LocalTarget.MacAddress, IpxHeader->DestinationNode, 6);
+
+ if (Device->MultiCardZeroVirtual ||
+ (IpxHeader->DestinationSocket == SAP_SOCKET)) {
+
+ //
+ // SAP frames need to look like they come from the
+ // local network, not the virtual one. The same is
+ // true if we are running multiple nets without
+ // a virtual net.
+ //
+
+ *(UNALIGNED ULONG *)IpxHeader->SourceNetwork = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory (IpxHeader->SourceNode, Binding->LocalAddress.NodeAddress, 6);
+ }
+
+ //
+ // Fill in the MAC header and submit the frame to NDIS.
+ //
+
+// #if DBG
+ CTEAssert (!Reserved->SendInProgress);
+ Reserved->SendInProgress = TRUE;
+// #endif
+
+ if ((NdisStatus = IpxSendFrame(
+ &LocalTarget,
+ NdisPacket,
+ REQUEST_INFORMATION(Reserved->u.SR_DG.Request) + sizeof(IPX_HEADER),
+ sizeof(IPX_HEADER))) != NDIS_STATUS_PENDING) {
+
+ Adapter = Binding->Adapter;
+#ifdef _PNP_POWER
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif _PNP_POWER
+ goto FunctionStart;
+ }
+#ifdef _PNP_POWER
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif _PNP_POWER
+
+ return;
+
+ } else {
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif _PNP_POWER
+ //
+ // If any of the sends succeeded then return
+ // success on the datagram send, otherwise
+ // use the most recent failure status.
+ //
+
+ if (Reserved->u.SR_DG.Net0SendSucceeded) {
+ NdisStatus = NDIS_STATUS_SUCCESS;
+ }
+
+ }
+
+ }
+
+
+#if 0
+ //
+ // NOTE: We don't NULL out the linkage field of the
+ // HeaderBuffer, which will leave the old buffer chain
+ // hanging off it; but that is OK because if we reuse
+ // this packet we will replace that chain with the new
+ // one, and before we free it we NULL it out.
+ //
+ // I.e. we don't do this:
+ //
+
+ NDIS_BUFFER_LINKAGE (Reserved->HeaderBuffer) = NULL;
+ NdisRecalculatePacketCounts (NdisPacket);
+#endif
+
+#if 0
+ {
+ ULONG ActualLength;
+ IpxGetMdlChainLength(NDIS_BUFFER_LINKAGE(Reserved->HeaderBuffer), &ActualLength);
+ if (ActualLength != REQUEST_INFORMATION(Reserved->u.SR_DG.Request)) {
+ DbgPrint ("IPX: At completion, IRP %lx has parameter length %d, buffer chain length %d\n",
+ Reserved->u.SR_DG.Request, REQUEST_INFORMATION(Reserved->u.SR_DG.Request), ActualLength);
+ DbgBreakPoint();
+ }
+ }
+#endif
+
+ //
+ // Save these so we can free the packet.
+ //
+
+ Request = Reserved->u.SR_DG.Request;
+ AddressFile = Reserved->u.SR_DG.AddressFile;
+
+
+#if BACK_FILL
+ // Check if this is backfilled. If so restore users Mdl back to its original shape
+ // Also, push the packet on to backfillpacket queue if the packet is not owned by the address
+
+ if (Reserved->BackFill) {
+
+ Reserved->HeaderBuffer->MappedSystemVa = Reserved->MappedSystemVa;
+ Reserved->HeaderBuffer->ByteCount = Reserved->UserLength;
+ Reserved->HeaderBuffer->StartVa = (PCHAR)((ULONG)Reserved->HeaderBuffer->MappedSystemVa & ~(PAGE_SIZE-1));
+ Reserved->HeaderBuffer->ByteOffset = (ULONG)Reserved->HeaderBuffer->MappedSystemVa & (PAGE_SIZE-1);
+
+ IPX_DEBUG(SEND, ("completeing back filled userMdl %x\n",Reserved->HeaderBuffer));
+
+ NdisPacket->Private.ValidCounts = FALSE;
+
+ NdisPacket->Private.Head = NULL;
+ NdisPacket->Private.Tail = NULL;
+
+ Reserved->HeaderBuffer = NULL;
+
+ if (Reserved->OwnedByAddress) {
+
+ // Reserved->Address->BackFillPacketInUse = FALSE;
+ InterlockedDecrement(&Reserved->Address->BackFillPacketInUse);
+
+ IPX_DEBUG(SEND, ("Freeing owned backfill %x\n", Reserved));
+
+ } else {
+
+ IPX_PUSH_ENTRY_LIST(
+ &Device->BackFillPacketList,
+ &Reserved->PoolLinkage,
+ &Device->SListsLock);
+ }
+ }
+ // not a back fill packet. Push it on sendpacket pool
+ else {
+
+ if (Reserved->OwnedByAddress) {
+
+ // Reserved->Address->SendPacketInUse = FALSE;
+ InterlockedDecrement(&Reserved->Address->SendPacketInUse);
+
+ } else {
+
+ IPX_PUSH_ENTRY_LIST(
+ &Device->SendPacketList,
+ &Reserved->PoolLinkage,
+ &Device->SListsLock);
+
+ }
+
+
+ }
+
+#else
+
+ if (Reserved->OwnedByAddress) {
+
+
+ Reserved->Address->SendPacketInUse = FALSE;
+
+ } else {
+
+ IPX_PUSH_ENTRY_LIST(
+ &Device->SendPacketList,
+ &Reserved->PoolLinkage,
+ &Device->SListsLock);
+
+ }
+#endif
+
+ ++Device->Statistics.PacketsSent;
+
+ //
+ // If this is a fast send irp, we bypass the file system and
+ // call the completion routine directly.
+ //
+
+ REQUEST_STATUS(Request) = NdisStatus;
+ irpSp = IoGetCurrentIrpStackLocation( Request );
+
+ if ( irpSp->MinorFunction == TDI_DIRECT_SEND_DATAGRAM ) {
+
+ Request->CurrentLocation++,
+ Request->Tail.Overlay.CurrentStackLocation++;
+
+ (VOID) irpSp->CompletionRoutine(
+ NULL,
+ Request,
+ irpSp->Context
+ );
+
+ } else {
+ IpxCompleteRequest (Request);
+ }
+
+ IpxFreeRequest(Device, Request);
+
+ IpxDereferenceAddressFileSync (AddressFile, AFREF_SEND_DGRAM);
+
+ break;
+
+ case IDENTIFIER_RIP_INTERNAL:
+
+ CTEAssert (Reserved->SendInProgress);
+ Reserved->SendInProgress = FALSE;
+ break;
+
+ case IDENTIFIER_RIP_RESPONSE:
+
+ CTEAssert (Reserved->SendInProgress);
+ Reserved->SendInProgress = FALSE;
+
+ Reserved->Identifier = IDENTIFIER_IPX;
+ IPX_PUSH_ENTRY_LIST(
+ &Device->SendPacketList,
+ &Reserved->PoolLinkage,
+ &Device->SListsLock);
+
+ IpxDereferenceDevice (Device, DREF_RIP_PACKET);
+ break;
+
+#ifdef _PNP_POWER
+ case IDENTIFIER_NB:
+ case IDENTIFIER_SPX:
+
+ //
+ // See if this is an iterative send
+ //
+ if (OldId = Reserved->CurrentNicId) {
+
+ PNDIS_BUFFER HeaderBuffer;
+ UINT TempHeaderBufferLength;
+ PUCHAR Header;
+ PIPX_HEADER IpxHeader;
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS) {
+ Reserved->Net0SendSucceeded = TRUE;
+ }
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ {
+ ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
+
+ for (NewId = OldId+1; NewId <= Index; NewId++) {
+ if (Binding = NIC_ID_TO_BINDING(Device, NewId)) {
+ //
+ // Found next NIC to send on
+ //
+ break;
+ }
+ }
+ }
+
+ if (NewId <= MIN (Device->MaxBindings, Device->HighestExternalNicId)) {
+
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ //
+ // Yes, we found another net to send it on, so
+ // move the header around if needed and do so.
+ //
+ IPX_DEBUG(SEND, ("ISN iteration: OldId: %lx, NewId: %lx\n", OldId, NewId));
+ Reserved->CurrentNicId = NewId;
+#if 0
+ NewOffset = Binding->BcMcHeaderSize;
+ OldOffset = Device->Bindings[OldId]->BcMcHeaderSize;
+
+ if (OldOffset != NewOffset) {
+
+ RtlMoveMemory(
+ &Reserved->Header[NewOffset],
+ &Reserved->Header[OldOffset],
+ sizeof(IPX_HEADER));
+
+ }
+
+ IpxHeader = (PIPX_HEADER)(&Reserved->Header[NewOffset]);
+
+
+#if BACK_FILL
+ // This should be a normal packet. Backfill packet is never used for
+ // reserved other than IPX type
+
+ CTEAssert(!Reserved->BackFill);
+#endif
+#endif
+
+ NdisQueryPacket (NdisPacket, NULL, NULL, &HeaderBuffer, NULL);
+ NdisQueryBuffer(HeaderBuffer, &Header, &TempHeaderBufferLength);
+
+ IpxHeader = (PIPX_HEADER)(&Header[Device->IncludedHeaderOffset]);
+
+ IPX_DEBUG(SEND, ("SendComplete: IpxHeader: %lx\n", IpxHeader));
+ FILL_LOCAL_TARGET(&Reserved->LocalTarget, NewId);
+
+ //
+ // We don't need to so this since the macaddress is replaced in
+ // IpxSendFrame anyway. The LocalTarget is the same as the one on
+ // the original send - this is passed down for further sends.
+ //
+ // RtlCopyMemory(LocalTarget.MacAddress, IpxHeader->DestinationNode, 6);
+
+ //
+ // Fill in the MAC header and submit the frame to NDIS.
+ //
+
+ if ((NdisStatus = IpxSendFrame(
+ &Reserved->LocalTarget,
+ NdisPacket,
+ Reserved->PacketLength,
+ sizeof(IPX_HEADER))) != NDIS_STATUS_PENDING) {
+
+ Adapter = Binding->Adapter;
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ goto FunctionStart;
+ }
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+
+ return;
+
+ } else {
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ //
+ // If any of the sends succeeded then return
+ // success on the datagram send, otherwise
+ // use the most recent failure status.
+ //
+ if (Reserved->Net0SendSucceeded) {
+ NdisStatus = NDIS_STATUS_SUCCESS;
+ }
+
+ }
+ }
+
+ //
+ // fall thru'
+ //
+#endif
+ default:
+
+ (*Device->UpperDrivers[Reserved->Identifier].SendCompleteHandler)(
+ NdisPacket,
+ NdisStatus);
+ break;
+ }
+
+} /* IpxSendComplete */
+
+
+NTSTATUS
+IpxTdiSendDatagram(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiSendDatagram request for the transport
+ provider.
+
+Arguments:
+
+ Request - Pointer to the request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+
+ PADDRESS_FILE AddressFile;
+ PADDRESS Address;
+ PNDIS_PACKET Packet;
+ PIPX_SEND_RESERVED Reserved;
+ PSINGLE_LIST_ENTRY s;
+ TDI_ADDRESS_IPX UNALIGNED * RemoteAddress;
+ TDI_ADDRESS_IPX TempAddress;
+ TA_ADDRESS UNALIGNED * AddressName;
+ PTDI_CONNECTION_INFORMATION Information;
+ PTDI_REQUEST_KERNEL_SENDDG Parameters;
+ PBINDING Binding;
+ IPX_LOCAL_TARGET TempLocalTarget;
+ PIPX_LOCAL_TARGET LocalTarget;
+ PDEVICE Device = IpxDevice;
+ UCHAR PacketType;
+ NTSTATUS Status;
+ PIPX_HEADER IpxHeader;
+ NDIS_STATUS NdisStatus;
+ USHORT LengthIncludingHeader;
+ IPX_DEFINE_SYNC_CONTEXT (SyncContext)
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+ PIO_STACK_LOCATION irpSp; \
+ BOOLEAN IsLoopback = FALSE;
+
+#ifdef _PNP_POWER
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+#endif
+
+ //
+ // Do a quick check of the validity of the address.
+ //
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+
+ IPX_BEGIN_SYNC (&SyncContext);
+
+ if ((AddressFile->Size == sizeof (ADDRESS_FILE)) &&
+ (AddressFile->Type == IPX_ADDRESSFILE_SIGNATURE) &&
+ ((Address = AddressFile->Address) != NULL)) {
+
+ IPX_GET_LOCK (&Address->Lock, &LockHandle);
+
+ if (AddressFile->State != ADDRESSFILE_STATE_CLOSING) {
+
+ Parameters = (PTDI_REQUEST_KERNEL_SENDDG)REQUEST_PARAMETERS(Request);
+ Information = Parameters->SendDatagramInformation;
+
+ //
+ // Do a quick check if this address has only one entry.
+ //
+
+ AddressName = &((TRANSPORT_ADDRESS UNALIGNED *)(Information->RemoteAddress))->Address[0];
+
+ if ((AddressName->AddressType == TDI_ADDRESS_TYPE_IPX) &&
+ (AddressName->AddressLength >= sizeof(TDI_ADDRESS_IPX))) {
+
+ RemoteAddress = (TDI_ADDRESS_IPX UNALIGNED *)(AddressName->Address);
+
+ } else if ((RemoteAddress = IpxParseTdiAddress (Information->RemoteAddress)) == NULL) {
+
+ IPX_FREE_LOCK (&Address->Lock, LockHandle);
+ Status = STATUS_INVALID_ADDRESS;
+ goto error_send_no_packet;
+ }
+
+ IPX_DEBUG (SEND, ("Send on %lx, network %lx socket %lx\n",
+ Address, RemoteAddress->NetworkAddress, RemoteAddress->Socket));
+
+#if 0
+ if (Parameters->SendLength > IpxDevice->RealMaxDatagramSize) {
+
+ IPX_DEBUG (SEND, ("Send %d bytes too large (%d)\n",
+ Parameters->SendLength,
+ IpxDevice->RealMaxDatagramSize));
+
+ REQUEST_INFORMATION(Request) = 0;
+ IPX_FREE_LOCK (&Address->Lock, LockHandle);
+ Status = STATUS_INVALID_BUFFER_SIZE;
+ goto error_send_no_packet;
+ }
+#endif
+ //
+ // Every address has one packet committed to it, use that
+ // if possible, otherwise take one out of the pool.
+ //
+
+
+#if BACK_FILL
+
+ // If the request is coming from the server, which resrves transport header space
+ // build the header in its space. Allocate a special packet to which does not contain
+ // mac and ipx headers in its reserved space.
+
+ if ((PMDL)REQUEST_NDIS_BUFFER(Request) &&
+ (((PMDL)REQUEST_NDIS_BUFFER(Request))->MdlFlags & MDL_NETWORK_HEADER) &&
+ (!(Information->OptionsLength < sizeof(IPX_DATAGRAM_OPTIONS))) &&
+ (RemoteAddress->NodeAddress[0] != 0xff)) {
+
+ //if (!Address->BackFillPacketInUse) {
+ if (InterlockedExchangeAdd(&Address->BackFillPacketInUse, 0) == 0) {
+ //Address->BackFillPacketInUse = TRUE;
+ InterlockedIncrement(&Address->BackFillPacketInUse);
+
+ Packet = PACKET(&Address->BackFillPacket);
+ Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ IPX_DEBUG(SEND, ("Getting owned backfill %x %x \n", Packet,Reserved));
+
+ }else {
+
+ s = IPX_POP_ENTRY_LIST(
+ &Device->BackFillPacketList,
+ &Device->SListsLock);
+
+ if (s != NULL) {
+ goto GotBackFillPacket;
+ }
+
+ //
+ // This function tries to allocate another packet pool.
+ //
+
+ s = IpxPopBackFillPacket(Device);
+
+ //
+ // Possibly we should queue the packet up to wait
+ // for one to become free.
+ //
+
+ if (s == NULL) {
+ IPX_FREE_LOCK (&Address->Lock, LockHandle);
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto error_send_no_packet;
+ }
+
+GotBackFillPacket:
+
+ Reserved = CONTAINING_RECORD (s, IPX_SEND_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+ IPX_DEBUG(SEND, ("getting backfill packet %x %x %x\n", s, Reserved, RemoteAddress->NodeAddress));
+ if(!Reserved->BackFill)DbgBreakPoint();
+
+ }
+
+ }else {
+
+ // if (!Address->SendPacketInUse) {
+ if (InterlockedExchangeAdd(&Address->SendPacketInUse, 0) == 0) {
+ // Address->SendPacketInUse = TRUE;
+ InterlockedIncrement(&Address->SendPacketInUse);
+
+ Packet = PACKET(&Address->SendPacket);
+ Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+
+ } else {
+
+ s = IPX_POP_ENTRY_LIST(
+ &Device->SendPacketList,
+ &Device->SListsLock);
+
+ if (s != NULL) {
+ goto GotPacket;
+ }
+
+ //
+ // This function tries to allocate another packet pool.
+ //
+
+ s = IpxPopSendPacket(Device);
+
+ //
+ // Possibly we should queue the packet up to wait
+ // for one to become free.
+ //
+
+ if (s == NULL) {
+ IPX_FREE_LOCK (&Address->Lock, LockHandle);
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto error_send_no_packet;
+ }
+
+GotPacket:
+
+ Reserved = CONTAINING_RECORD (s, IPX_SEND_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+ Reserved->BackFill = FALSE;
+
+ }
+
+ }
+
+
+#else
+
+ if (!Address->SendPacketInUse) {
+
+ Address->SendPacketInUse = TRUE;
+ Packet = PACKET(&Address->SendPacket);
+ Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+
+ } else {
+
+ s = IPX_POP_ENTRY_LIST(
+ &Device->SendPacketList,
+ &Device->SListsLock);
+
+ if (s != NULL) {
+ goto GotPacket;
+ }
+
+ //
+ // This function tries to allocate another packet pool.
+ //
+
+ s = IpxPopSendPacket(Device);
+
+ //
+ // Possibly we should queue the packet up to wait
+ // for one to become free.
+ //
+
+ if (s == NULL) {
+ IPX_FREE_LOCK (&Address->Lock, LockHandle);
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto error_send_no_packet;
+ }
+
+GotPacket:
+
+ Reserved = CONTAINING_RECORD (s, IPX_SEND_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ }
+
+
+#endif
+
+ IpxReferenceAddressFileLock (AddressFile, AFREF_SEND_DGRAM);
+
+ IPX_FREE_LOCK (&Address->Lock, LockHandle);
+
+ //
+ // Save this now while we have Parameters available.
+ //
+
+ REQUEST_INFORMATION(Request) = Parameters->SendLength;
+ LengthIncludingHeader = (USHORT)(Parameters->SendLength + sizeof(IPX_HEADER));
+
+#if 0
+ {
+ ULONG ActualLength;
+ IpxGetMdlChainLength(REQUEST_NDIS_BUFFER(Request), &ActualLength);
+ if (ActualLength != Parameters->SendLength) {
+ DbgPrint ("IPX: IRP %lx has parameter length %d, buffer chain length %d\n",
+ Request, Parameters->SendLength, ActualLength);
+ DbgBreakPoint();
+ }
+ }
+#endif
+
+ Reserved->u.SR_DG.AddressFile = AddressFile;
+ Reserved->u.SR_DG.Request = Request;
+ CTEAssert (Reserved->Identifier == IDENTIFIER_IPX);
+
+
+ //
+ // Set this to 0; this means the packet is not one that
+ // should be broadcast on all nets. We will change it
+ // later if it turns out this is the case.
+ //
+
+ Reserved->u.SR_DG.CurrentNicId = 0;
+
+ //
+ // We need this to track these packets specially.
+ //
+
+ Reserved->u.SR_DG.OutgoingSap = AddressFile->IsSapSocket;
+
+ //
+ // Add the MDL chain after the pre-allocated header buffer.
+ // NOTE: THIS WILL ONLY WORK IF WE EVENTUALLY CALL
+ // NDISRECALCULATEPACKETCOUNTS (which we do in IpxSendFrame).
+ //
+ //
+#if BACK_FILL
+
+ if (Reserved->BackFill) {
+ Reserved->HeaderBuffer = REQUEST_NDIS_BUFFER(Request);
+
+ //remove the ipx mdl from the packet.
+ Reserved->UserLength = Reserved->HeaderBuffer->ByteCount;
+
+ IPX_DEBUG(SEND, ("back filling userMdl Reserved %x %x\n", Reserved->HeaderBuffer, Reserved));
+ } else {
+ NDIS_BUFFER_LINKAGE (NDIS_BUFFER_LINKAGE(Reserved->HeaderBuffer)) = REQUEST_NDIS_BUFFER(Request);
+ }
+#else
+ NDIS_BUFFER_LINKAGE (NDIS_BUFFER_LINKAGE(Reserved->HeaderBuffer)) = REQUEST_NDIS_BUFFER(Request);
+#endif
+
+
+ if (Information->OptionsLength < sizeof(IPX_DATAGRAM_OPTIONS)) {
+
+ //
+ // The caller did not supply the local target for this
+ // send, so we look it up ourselves.
+ //
+
+ UINT Segment;
+
+ //
+ // We calculate this now since we need to know
+ // if it is directed below.
+ //
+
+ if (RemoteAddress->NodeAddress[0] == 0xff) {
+ // BUGBUG: What about multicast?
+ if ((*(UNALIGNED ULONG *)(RemoteAddress->NodeAddress) != 0xffffffff) ||
+ (*(UNALIGNED USHORT *)(RemoteAddress->NodeAddress+4) != 0xffff)) {
+ Reserved->DestinationType = DESTINATION_MCAST;
+ } else {
+ Reserved->DestinationType = DESTINATION_BCAST;
+ }
+ } else {
+ Reserved->DestinationType = DESTINATION_DEF; // directed send
+ }
+
+ //
+ // If there are no options, then check if the
+ // caller is passing the packet type as a final byte
+ // in the remote address; if not use the default.
+ //
+
+ if (Information->OptionsLength == 0) {
+ if (AddressFile->ExtendedAddressing) {
+ PacketType = ((PUCHAR)(RemoteAddress+1))[0];
+ } else {
+ PacketType = AddressFile->DefaultPacketType;
+ }
+ } else {
+ PacketType = ((PUCHAR)(Information->Options))[0];
+ }
+
+ if ((Reserved->DestinationType != DESTINATION_DEF) &&
+ ((RemoteAddress->NetworkAddress == 0) ||
+ (Device->VirtualNetwork &&
+ (RemoteAddress->NetworkAddress == Device->SourceAddress.NetworkAddress)))) {
+
+ //
+ // This packet needs to be broadcast to all networks.
+ // Make sure it is not too big for any of them.
+ //
+
+ if (Parameters->SendLength > Device->RealMaxDatagramSize) {
+ IPX_DEBUG (SEND, ("Send %d bytes too large (%d)\n",
+ Parameters->SendLength, Device->RealMaxDatagramSize));
+ Status = STATUS_INVALID_BUFFER_SIZE;
+ goto error_send_with_packet;
+ }
+
+ //
+ // If this is a broadcast to the virtual net, we
+ // need to construct a fake remote address which
+ // has network 0 in there instead.
+ //
+
+ if (Device->VirtualNetwork &&
+ (RemoteAddress->NetworkAddress == Device->SourceAddress.NetworkAddress)) {
+
+ RtlCopyMemory (&TempAddress, (PVOID)RemoteAddress, sizeof(TDI_ADDRESS_IPX));
+ TempAddress.NetworkAddress = 0;
+ RemoteAddress = (TDI_ADDRESS_IPX UNALIGNED *)&TempAddress;
+ }
+
+ //
+ // If someone is sending to the SAP socket and
+ // we are running with multiple cards without a
+ // virtual network, AND this packet is a SAP response,
+ // then we log an error to warn them that the
+ // system may not work as they like (since there
+ // is no virtual network to advertise, we use
+ // the first card's net/node as our local address).
+ // We only do this once per boot, using the
+ // SapWarningLogged variable to control that.
+ //
+
+ if ((RemoteAddress->Socket == SAP_SOCKET) &&
+ (!Device->SapWarningLogged) &&
+ (Device->MultiCardZeroVirtual)) {
+
+ PNDIS_BUFFER FirstBuffer;
+ UINT FirstBufferLength;
+ USHORT UNALIGNED * FirstBufferData;
+
+ if ((FirstBuffer = REQUEST_NDIS_BUFFER(Request)) != NULL) {
+
+ NdisQueryBuffer(
+ FirstBuffer,
+ (PVOID *)&FirstBufferData,
+ &FirstBufferLength);
+
+ //
+ // The first two bytes of a SAP packet are the
+ // operation, 0x2 (in network order) is response.
+ //
+
+ if ((FirstBufferLength >= sizeof(USHORT)) &&
+ (*FirstBufferData == 0x0200)) {
+
+ Device->SapWarningLogged = TRUE;
+
+ IpxWriteGeneralErrorLog(
+ Device->DeviceObject,
+ EVENT_IPX_SAP_ANNOUNCE,
+ 777,
+ STATUS_NOT_SUPPORTED,
+ NULL,
+ 0,
+ NULL);
+ }
+ }
+ }
+
+
+ //
+ // In this case we do not RIP but instead set the
+ // packet up so it is sent to each network in turn.
+ //
+ // Special case: If this packet is from the SAP
+ // socket and we are running with multiple cards
+ // without a virtual network, we only send this
+ // on the card with NIC ID 1, so we leave
+ // CurrentNicId set to 0.
+ //
+
+ //
+ // BUGBUG: What if NicId 1 is invalid? Should scan
+ // for first valid one, fail send if none.
+ //
+
+ if ((Address->Socket != SAP_SOCKET) ||
+ (!Device->MultiCardZeroVirtual)) {
+
+ if (Device->SingleNetworkActive) {
+
+ if (Device->ActiveNetworkWan) {
+ Reserved->u.SR_DG.CurrentNicId = Device->FirstWanNicId;
+ } else {
+ Reserved->u.SR_DG.CurrentNicId = Device->FirstLanNicId;
+ }
+
+ } else {
+
+ Reserved->u.SR_DG.CurrentNicId = 1;
+
+ }
+
+ Reserved->u.SR_DG.Net0SendSucceeded = FALSE;
+
+ //
+ // In this case, we need to scan for the first
+ // non-dialout wan socket.
+ //
+
+ if ((Device->DisableDialoutSap) &&
+ (Address->Socket == SAP_SOCKET)) {
+
+ PBINDING TempBinding;
+
+ CTEAssert (Reserved->u.SR_DG.CurrentNicId <= Device->ValidBindings);
+ while (Reserved->u.SR_DG.CurrentNicId <= MIN (Device->MaxBindings, Device->ValidBindings)) {
+#ifdef _PNP_POWER
+// No need to lock the access path since he just looks at it
+//
+ TempBinding = NIC_ID_TO_BINDING(Device, Reserved->u.SR_DG.CurrentNicId);
+#else
+ TempBinding = Device->Bindings[Reserved->u.SR_DG.CurrentNicId];
+#endif _PNP_POWER
+ if ((TempBinding != NULL) &&
+ (!TempBinding->DialOutAsync)) {
+ break;
+ }
+ ++Reserved->u.SR_DG.CurrentNicId;
+ }
+ if (Reserved->u.SR_DG.CurrentNicId > MIN (Device->MaxBindings, Device->ValidBindings)) {
+ //
+ // [SA] Bug #17273 return proper error mesg.
+ //
+
+ // Status = STATUS_DEVICE_DOES_NOT_EXIST;
+ Status = STATUS_NETWORK_UNREACHABLE;
+
+ goto error_send_with_packet;
+ }
+ }
+#ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(&TempLocalTarget, Reserved->u.SR_DG.CurrentNicId);
+#else
+ TempLocalTarget.NicId = Reserved->u.SR_DG.CurrentNicId;
+#endif
+
+ } else {
+#ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(&TempLocalTarget, 1);
+#else
+ TempLocalTarget.NicId = 1;
+#endif
+ }
+
+ RtlCopyMemory(TempLocalTarget.MacAddress, RemoteAddress->NodeAddress, 6);
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ Binding = NIC_ID_TO_BINDING(Device, NIC_FROM_LOCAL_TARGET(&TempLocalTarget));
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+
+ } else {
+
+ Segment = RipGetSegment((PUCHAR)&RemoteAddress->NetworkAddress);
+
+
+ IPX_GET_LOCK (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // This call will return STATUS_PENDING if we need to
+ // RIP for the packet.
+ //
+
+ Status = RipGetLocalTarget(
+ Segment,
+ RemoteAddress,
+ IPX_FIND_ROUTE_RIP_IF_NEEDED,
+ &TempLocalTarget,
+ NULL);
+
+ if (Status == STATUS_SUCCESS) {
+
+ //
+ // We found the route, TempLocalTarget is filled in.
+ //
+
+ IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ if (NIC_FROM_LOCAL_TARGET(&TempLocalTarget) == 0) {
+ IPX_DEBUG(LOOPB, ("Loopback TDI packet: remoteaddr: %lx\n", RemoteAddress));
+ IsLoopback = TRUE;
+ FILL_LOCAL_TARGET(&TempLocalTarget, 1);
+ }
+ Binding = NIC_ID_TO_BINDING(Device, NIC_FROM_LOCAL_TARGET(&TempLocalTarget));
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ if (Parameters->SendLength >
+ Binding->RealMaxDatagramSize) {
+ IPX_DEBUG (SEND, ("Send %d bytes too large (%d)\n",
+ Parameters->SendLength,
+ Binding->RealMaxDatagramSize));
+
+ REQUEST_INFORMATION(Request) = 0;
+ Status = STATUS_INVALID_BUFFER_SIZE;
+ goto error_send_with_packet;
+ }
+
+ if ((Device->DisableDialoutSap) &&
+ (Address->Socket == SAP_SOCKET) &&
+ (Binding->DialOutAsync)) {
+
+ REQUEST_INFORMATION(Request) = 0;
+ //
+ // [SA] Bug #17273 return proper error mesg.
+ //
+
+ // Status = STATUS_DEVICE_DOES_NOT_EXIST;
+ Status = STATUS_NETWORK_UNREACHABLE;
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+
+ goto error_send_with_packet;
+ }
+#else
+ if (TempLocalTarget.NicId == 0) {
+ IPX_DEBUG(LOOPB, ("Loopback TDI packet: remoteaddr: %lx\n", RemoteAddress));
+ IsLoopback = TRUE;
+ TempLocalTarget.NicId = 1;
+ }
+
+ if (Parameters->SendLength >
+ Device->Bindings[TempLocalTarget.NicId]->RealMaxDatagramSize) {
+ IPX_DEBUG (SEND, ("Send %d bytes too large (%d)\n",
+ Parameters->SendLength,
+ Device->Bindings[TempLocalTarget.NicId]->RealMaxDatagramSize));
+
+ REQUEST_INFORMATION(Request) = 0;
+ Status = STATUS_INVALID_BUFFER_SIZE;
+ goto error_send_with_packet;
+ }
+
+ if ((Device->DisableDialoutSap) &&
+ (Address->Socket == SAP_SOCKET) &&
+ (Device->Bindings[TempLocalTarget.NicId]->DialOutAsync)) {
+
+ REQUEST_INFORMATION(Request) = 0;
+ //
+ // [SA] Bug #17273 return proper error mesg.
+ //
+
+ // Status = STATUS_DEVICE_DOES_NOT_EXIST;
+ Status = STATUS_NETWORK_UNREACHABLE;
+ goto error_send_with_packet;
+ }
+#endif _PNP_POWER
+
+ } else if (Status == STATUS_PENDING) {
+
+ //
+ // A RIP request went out on the network; we queue
+ // this packet for transmission when the RIP
+ // response arrives. First we fill in the IPX
+ // header; the only thing we don't know is where
+ // exactly to fill it in, so we choose
+ // the most common location.
+ //
+
+ IpxConstructHeader(
+ &Reserved->Header[Device->IncludedHeaderOffset],
+ LengthIncludingHeader,
+ PacketType,
+ RemoteAddress,
+ &Address->LocalAddress);
+
+ //
+ // Adjust the 2nd mdl's size
+ //
+ NdisAdjustBufferLength(NDIS_BUFFER_LINKAGE(IPX_PACKET_HEAD(Packet)), sizeof(IPX_HEADER));
+
+ IPX_DEBUG (RIP, ("Queueing packet %lx\n", Reserved));
+
+ InsertTailList(
+ &Device->Segments[Segment].WaitingForRoute,
+ &Reserved->WaitLinkage);
+
+ IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
+ IPX_END_SYNC (&SyncContext);
+
+ return STATUS_PENDING;
+
+ } else {
+
+ IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
+ goto error_send_with_packet;
+
+ }
+ }
+
+ LocalTarget = &TempLocalTarget;
+
+ //
+ // Now we know the local target, we can figure out
+ // the offset for the IPX header.
+ //
+#ifdef _PNP_POWER
+// Remember that we have got the binding with ref above....
+
+#else
+ Binding = Device->Bindings[LocalTarget->NicId];
+#endif
+ IpxHeader = (PIPX_HEADER)&Reserved->Header[MAC_HEADER_SIZE];
+#if 0
+ if (Reserved->DestinationType == DESTINATION_DEF) {
+ IpxHeader = (PIPX_HEADER)&Reserved->Header[Binding->DefHeaderSize];
+ } else {
+ IpxHeader = (PIPX_HEADER)&Reserved->Header[Binding->BcMcHeaderSize];
+ }
+#endif
+
+ } else {
+
+ PacketType = ((PUCHAR)(Information->Options))[0];
+ LocalTarget = &((PIPX_DATAGRAM_OPTIONS)(Information->Options))->LocalTarget;
+
+ //
+ // Calculate the binding and the correct location
+ // for the IPX header. We can do this at the same
+ // time as we calculate the DestinationType which
+ // saves an if like the one 15 lines up.
+ //
+
+#ifdef _PNP_POWER
+// Get lock to ref.
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ //
+ // If a loopback packet, use the first binding as place holder
+ //
+ if (NIC_FROM_LOCAL_TARGET(LocalTarget) == 0) {
+ Binding = NIC_ID_TO_BINDING(Device, 1);
+ IsLoopback = TRUE;
+ } else {
+ Binding = NIC_ID_TO_BINDING(Device, NIC_FROM_LOCAL_TARGET(LocalTarget));
+ }
+
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+ if (LocalTarget->NicId == 0) {
+ Binding = Device->Bindings[1];
+ IsLoopback = TRUE;
+ } else {
+ Binding = Device->Bindings[LocalTarget->NicId];
+ }
+#endif _PNP_POWER
+ if (Parameters->SendLength > Binding->RealMaxDatagramSize) {
+
+ IPX_DEBUG (SEND, ("Send %d bytes too large (%d)\n",
+ Parameters->SendLength,
+ Binding->RealMaxDatagramSize));
+
+ REQUEST_INFORMATION(Request) = 0;
+ Status = STATUS_INVALID_BUFFER_SIZE;
+ goto error_send_with_packet;
+ }
+
+#if 0
+ //
+ // This shouldn't be needed because even WAN bindings
+ // don't go away once they are added.
+ //
+
+ if (Binding == NULL) {
+ Status = STATUS_DEVICE_DOES_NOT_EXIST;
+ goto error_send_with_packet;
+ }
+#endif
+
+ if (RemoteAddress->NodeAddress[0] == 0xff) {
+ // BUGBUG: What about multicast?
+ if ((*(UNALIGNED ULONG *)(RemoteAddress->NodeAddress) != 0xffffffff) ||
+ (*(UNALIGNED USHORT *)(RemoteAddress->NodeAddress+4) != 0xffff)) {
+ Reserved->DestinationType = DESTINATION_MCAST;
+ } else {
+ Reserved->DestinationType = DESTINATION_BCAST;
+ }
+// IpxHeader = (PIPX_HEADER)&Reserved->Header[Binding->BcMcHeaderSize];
+ } else {
+ Reserved->DestinationType = DESTINATION_DEF; // directed send
+// IpxHeader = (PIPX_HEADER)&Reserved->Header[Binding->DefHeaderSize];
+ }
+ IpxHeader = (PIPX_HEADER)&Reserved->Header[MAC_HEADER_SIZE];
+
+ }
+
+
+ ++Device->TempDatagramsSent;
+ Device->TempDatagramBytesSent += Parameters->SendLength;
+
+
+#if BACK_FILL
+
+ if (Reserved->BackFill) {
+ Reserved->MappedSystemVa = Reserved->HeaderBuffer->MappedSystemVa;
+ IpxHeader = (PIPX_HEADER)((PCHAR)Reserved->HeaderBuffer->MappedSystemVa - sizeof(IPX_HEADER));
+ Reserved->HeaderBuffer->ByteOffset -= sizeof(IPX_HEADER);
+ (ULONG)Reserved->HeaderBuffer->MappedSystemVa-= sizeof(IPX_HEADER);
+ IPX_DEBUG(SEND, ("Adjusting backfill userMdl Ipxheader %x %x \n",Reserved->HeaderBuffer,IpxHeader));
+ }
+#endif
+
+ if (Device->MultiCardZeroVirtual ||
+ (Address->LocalAddress.Socket == SAP_SOCKET) ||
+ (RemoteAddress->Socket == SAP_SOCKET)) {
+
+ //
+ // SAP frames need to look like they come from the
+ // local network, not the virtual one. The same is
+ // true if we are running multiple nets without
+ // a virtual network number.
+ //
+ // If this is a binding set member and a local target
+ // was provided we will send using the real node of
+ // the binding, even if it was a slave. This is
+ // intentional. If no local target was provided then
+ // this will not be a binding slave.
+ //
+
+ IpxConstructHeader(
+ (PUCHAR)IpxHeader,
+ LengthIncludingHeader,
+ PacketType,
+ RemoteAddress,
+ &Binding->LocalAddress);
+
+ IpxHeader->SourceSocket = Address->SendSourceSocket;
+
+ } else {
+
+ IpxConstructHeader(
+ (PUCHAR)IpxHeader,
+ LengthIncludingHeader,
+ PacketType,
+ RemoteAddress,
+ &Address->LocalAddress);
+
+ }
+
+
+ //
+ // Fill in the MAC header and submit the frame to NDIS.
+ //
+
+// #if DBG
+ CTEAssert (!Reserved->SendInProgress);
+ Reserved->SendInProgress = TRUE;
+// #endif
+ //
+ // Adjust the 2nd mdl's size
+ //
+#if BACK_FILL
+ if (Reserved->BackFill) {
+ NdisAdjustBufferLength(Reserved->HeaderBuffer, (Reserved->HeaderBuffer->ByteCount+sizeof(IPX_HEADER)));
+ } else {
+ NdisAdjustBufferLength(NDIS_BUFFER_LINKAGE(IPX_PACKET_HEAD(Packet)), sizeof(IPX_HEADER));
+ }
+#else
+ NdisAdjustBufferLength(NDIS_BUFFER_LINKAGE(IPX_PACKET_HEAD(Packet)), sizeof(IPX_HEADER));
+#endif
+
+ IPX_DEBUG(SEND, ("Packet Head %x\n",IPX_PACKET_HEAD(Packet)));
+
+ if (IsLoopback) {
+ //
+ // Enque this packet to the LoopbackQueue on the binding.
+ // If the LoopbackRtn is not already scheduled, schedule it.
+ //
+
+ IPX_DEBUG(LOOPB, ("Packet: %lx, Addr: %lx, Addr->SendPacket: %lx\n", Packet, Address, Address->SendPacket));
+
+ //
+ // Recalculate packet counts here.
+ //
+ // NdisAdjustBufferLength (Reserved->HeaderBuffer, 17);
+#if BACK_FILL
+
+ if (Reserved->BackFill) {
+ //
+ // Set the Header pointer and chain the first MDL
+ //
+ Reserved->Header = (PCHAR)Reserved->HeaderBuffer->MappedSystemVa;
+ NdisChainBufferAtFront(Packet,(PNDIS_BUFFER)Reserved->HeaderBuffer);
+ }
+#endif
+ NdisRecalculatePacketCounts (Packet);
+#ifdef _PNP_POWER
+ IpxLoopbackEnque(Packet, NIC_ID_TO_BINDING(Device, 1)->Adapter);
+#else
+ IpxLoopbackEnque(Packet, Device->Bindings[1]->Adapter);
+#endif
+
+ } else {
+ if ((NdisStatus = (*Binding->SendFrameHandler)(
+ Binding->Adapter,
+ LocalTarget,
+ Packet,
+ Parameters->SendLength + sizeof(IPX_HEADER),
+ sizeof(IPX_HEADER))) != NDIS_STATUS_PENDING) {
+
+ IpxSendComplete(
+ (NDIS_HANDLE)Binding->Adapter,
+ Packet,
+ NdisStatus);
+ }
+ }
+
+ IPX_END_SYNC (&SyncContext);
+#ifdef _PNP_POWER
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif
+ return STATUS_PENDING;
+
+ } else {
+
+ //
+ // The address file state was closing.
+ //
+
+ IPX_FREE_LOCK (&Address->Lock, LockHandle);
+ Status = STATUS_INVALID_HANDLE;
+ goto error_send_no_packet;
+
+ }
+
+ } else {
+
+ //
+ // The address file didn't look like one.
+ //
+
+ Status = STATUS_INVALID_HANDLE;
+ goto error_send_no_packet;
+ }
+
+ //
+ // Jump here if we want to fail the send and we have already
+ // allocated the packet and ref'ed the address file.
+ //
+
+error_send_with_packet:
+
+#if BACK_FILL
+ //
+ // Check if this is backfilled. If so, set the headerbuffer to NULL. Note that we dont need
+ // restore to restore the user's MDL since it was never touched when this error occurred.
+ // Also, push the packet on to backfillpacket queue if the packet is not owned by the address
+ //
+ if (Reserved->BackFill) {
+
+ Reserved->HeaderBuffer = NULL;
+
+ if (Reserved->OwnedByAddress) {
+ // Reserved->Address->BackFillPacketInUse = FALSE;
+ InterlockedDecrement(&Reserved->Address->BackFillPacketInUse);
+
+ IPX_DEBUG(SEND, ("Freeing owned backfill %x\n", Reserved));
+ } else {
+ IPX_PUSH_ENTRY_LIST(
+ &Device->BackFillPacketList,
+ &Reserved->PoolLinkage,
+ &Device->SListsLock);
+ }
+ } else {
+ // not a back fill packet. Push it on sendpacket pool
+ if (Reserved->OwnedByAddress) {
+ // Reserved->Address->SendPacketInUse = FALSE;
+ InterlockedDecrement(&Reserved->Address->SendPacketInUse);
+
+ } else {
+ IPX_PUSH_ENTRY_LIST(
+ &Device->SendPacketList,
+ &Reserved->PoolLinkage,
+ &Device->SListsLock);
+
+ }
+ }
+#else
+ if (Reserved->OwnedByAddress) {
+ Reserved->Address->SendPacketInUse = FALSE;
+ } else {
+ IPX_PUSH_ENTRY_LIST(
+ &Device->SendPacketList,
+ &Reserved->PoolLinkage,
+ &Device->SListsLock);
+ }
+#endif
+
+ IpxDereferenceAddressFileSync (AddressFile, AFREF_SEND_DGRAM);
+
+error_send_no_packet:
+
+ //
+ // Jump here if we fail before doing any of that.
+ //
+
+ IPX_END_SYNC (&SyncContext);
+
+ irpSp = IoGetCurrentIrpStackLocation( Request );
+ if ( irpSp->MinorFunction == TDI_DIRECT_SEND_DATAGRAM ) {
+
+ REQUEST_STATUS(Request) = Status;
+ Request->CurrentLocation++,
+ Request->Tail.Overlay.CurrentStackLocation++;
+
+ (VOID) irpSp->CompletionRoutine(
+ NULL,
+ Request,
+ irpSp->Context
+ );
+
+ IpxFreeRequest (DeviceObject, Request);
+ }
+
+ return Status;
+
+} /* IpxTdiSendDatagram */
+
+
+#if DBG
+VOID
+IpxConstructHeader(
+ IN PUCHAR Header,
+ IN USHORT PacketLength,
+ IN UCHAR PacketType,
+ IN TDI_ADDRESS_IPX UNALIGNED * RemoteAddress,
+ IN PTDI_ADDRESS_IPX LocalAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs an IPX header in a packet.
+
+Arguments:
+
+ Header - The location at which the header should be built.
+
+ PacketLength - The length of the packet, including the IPX header.
+
+ PacketType - The packet type of the frame.
+
+ RemoteAddress - The remote IPX address.
+
+ LocalAddress - The local IPX address.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PIPX_HEADER IpxHeader = (PIPX_HEADER)Header;
+
+ IpxHeader->CheckSum = 0xffff;
+ IpxHeader->PacketLength[0] = (UCHAR)(PacketLength / 256);
+ IpxHeader->PacketLength[1] = (UCHAR)(PacketLength % 256);
+ IpxHeader->TransportControl = 0;
+ IpxHeader->PacketType = PacketType;
+
+ //
+ // These copies depend on the fact that the destination
+ // network is the first field in the 12-byte address.
+ //
+
+ RtlCopyMemory(IpxHeader->DestinationNetwork, (PVOID)RemoteAddress, 12);
+ RtlCopyMemory(IpxHeader->SourceNetwork, LocalAddress, 12);
+
+} /* IpxConstructHeader */
+#endif
+
+
diff --git a/private/ntos/tdi/isnp/ipx/sources.inc b/private/ntos/tdi/isnp/ipx/sources.inc
new file mode 100644
index 000000000..449026087
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/sources.inc
@@ -0,0 +1,74 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=nwlnkipx
+
+TARGETNAME=nwlnkipx
+TARGETTYPE=DRIVER
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\tdi.lib \
+ $(BASEDIR)\public\sdk\lib\*\ndis.lib
+
+INCLUDES=..;..\..\inc;..\..\..\..\inc;..\..\..\..\..\inc
+
+NTPROFILEINPUT=yes
+
+
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+C_DEFINES=$(C_DEFINES) -D_NTDRIVER_ -DBACK_FILL=1 -DNDIS40=1 -D_PNP_POWER=1
+
+!IFDEF BUILD_FOR_3_51
+C_DEFINES=$(C_DEFINES) -D_NTIFS_
+!ENDIF
+
+SOURCES= \
+ ..\action.c \
+ ..\adapter.c \
+ ..\address.c \
+ ..\config.c \
+ ..\device.c \
+ ..\driver.c \
+ ..\event.c \
+ ..\ind.c \
+ ..\internal.c \
+ ..\nwlnkipx.rc \
+ ..\mac.c \
+ ..\ndis.c \
+ ..\packet.c \
+ ..\query.c \
+ ..\receive.c \
+ ..\rip.c \
+ ..\send.c \
+ ..\loopback.c
+
+PRECOMPILED_INCLUDE=..\precomp.h
+PRECOMPILED_PCH=precomp.pch
+PRECOMPILED_OBJ=precomp.obj
+
+SOURCES_USED=..\sources.inc
+
+
diff --git a/private/ntos/tdi/isnp/ipx/up/makefile b/private/ntos/tdi/isnp/ipx/up/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/up/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/tdi/isnp/ipx/up/nwlnkipx.prf b/private/ntos/tdi/isnp/ipx/up/nwlnkipx.prf
new file mode 100644
index 000000000..0c4359235
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/up/nwlnkipx.prf
@@ -0,0 +1,89 @@
+IpxTdiSendDatagram@8
+IpxReceiveIndicationNew@36
+IpxSendFrame@16
+IpxReceiveComplete@4
+IpxSendFrame802_3802_2@20
+IpxReceivePacket@8
+IpxDerefAddressSync@4
+IpxSendComplete@12
+IpxSendFramePreFwd@16
+IpxReceiveIndication@28
+IpxInitializeBackFillPacket@12
+IpxpAllocateMemory@12
+IpxPopBackFillPacket@4
+IpxAllocateBackFillPool@4
+RipLongTimeout@8
+CTEStartTimer@16
+TdiCopyBufferToMdl@24
+IpxTdiQueryInformation@8
+IpxVerifyAddressFile@4
+IpxDispatchInternal@8
+IpxTransferData@28
+IpxInitLoopback@0
+RipGetFirstRoute@4
+IpxCreateAddress@8
+MacReturnMaxDataSize@20
+IpxLookupAddress@8
+IpxAbortLineChanges@4
+MacMapFrameType@12
+IpxInitializeReceiveBuffer@16
+IpxDispatchOpenClose@8
+IpxTdiSetEventHandler@4
+IpxCreateAddressFile@4
+IpxInternalBind@8
+IpxInitializeReceivePacket@8
+IpxIsAddressLocal@4
+IpxOpenAddress@8
+IpxAllocateReceiveBufferPool@4
+IpxSubmitNdisRequest@12
+IpxAddBroadcast@4
+IpxDestroyBinding@4
+RipAdjustForBindingChange@12
+IpxDispatchDeviceControl@8
+IpxAllocatePaddingBuffer@4
+TdiMapUserRequest@12
+CTEInitialize@0
+IpxInitializeSendPacket@12
+IpxpFreeMemory@12
+IpxInitializePaddingBuffer@12
+IpxAllocateSendPool@4
+RipCleanupPacket@8
+TdiRegisterDeviceObject@8
+TdiRegisterNetAddress@8
+IpxTdiAction@8
+IpxCreateBinding@20
+IpxDerefDevice@4
+MacInitializeBindingInfo@8
+IpxRegisterProtocol@4
+IpxInitializeNdis@8
+IpxGetConfigValue@24
+IpxCreateAdapter@12
+IpxResolveBindingSets@8
+IpxGetFrameType@24
+MacInitializeMacInfo@8
+IpxGetBindingValue@24
+RipQueueRequest@8
+RipShortTimeout@8
+IpxPopSendPacket@4
+IpxAllocateBindingPool@4
+IpxInternalQuery@20
+CTEInitTimer@4
+IpxRequestComplete@12
+IpxBroadcastOperation@4
+CTEInitEvent@8
+IpxPnPGetVirtualNetworkNumber@4
+IpxPnPGetAdapterParameters@12
+IpxOpenAdapterComplete@12
+IpxResolveAutoDetect@16
+IpxBindToAdapter@16
+TdiInitialize@0
+IpxPnPIsnIndicate@4
+IpxPnPUpdateBindingArray@12
+IpxBindAdapter@20
+IpxPnPUpdateDevice@4
+IpxGetConfiguration@12
+IpxAddExport@24
+IpxCreateDevice@16
+DriverEntry@8
+IpxReadLinkageInformation@4
+IpxFreeConfiguration@4
diff --git a/private/ntos/tdi/isnp/ipx/up/sources b/private/ntos/tdi/isnp/ipx/up/sources
new file mode 100644
index 000000000..85cdb3764
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/up/sources
@@ -0,0 +1,29 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+UP_DRIVER=yes
+
+TARGETPATH=obj
+
+!include ..\sources.inc