diff options
Diffstat (limited to '')
42 files changed, 40960 insertions, 0 deletions
diff --git a/private/ntos/tdi/isn/ipx/action.c b/private/ntos/tdi/isn/ipx/action.c new file mode 100644 index 000000000..0a57bad98 --- /dev/null +++ b/private/ntos/tdi/isn/ipx/action.c @@ -0,0 +1,2921 @@ +/*++ + +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> + +// +// Line ups when indicated up should have this length subtracted from the +// max. send size that ndis indicated to us for the line +// +#define HDR_LEN_802_3 14 +#define ASYNC_MEDIUM_HDR_LEN HDR_LEN_802_3 + +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; + PIPX_QUERY_WAN_INACTIVITY QueryWanInactivity; + PIPXWAN_CONFIG_DONE IpxwanConfigDone; + } 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 + IPX_FIND_ROUTE_REQUEST routeEntry; + +#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; + +#if 0 + case MIPX_SETNIC: + + // + // IPX_NIC_ADDRESS TRUE + // + + IPX_DEBUG (ACTION, ("%lx: MIPX_SETNIC\n", AddressFile)); + AddressFile->NicAddressing = TRUE; + AddressFile->SpecialReceiveProcessing = TRUE; + break; + + case MIPX_NOSETNIC: + + // + // IPX_NIC_ADDRESS (FALSE). + // + + IPX_DEBUG (ACTION, ("%lx: MIPX_NOSETNIC\n", AddressFile)); + AddressFile->NicAddressing = FALSE; + AddressFile->SpecialReceiveProcessing = (BOOLEAN) + (AddressFile->ReceiveFlagsAddressing || + AddressFile->ReceiveIpxHeader || + AddressFile->FilterOnPacketType || AddressFile->IsSapSocket || + AddressFile->NicAddressing); + break; +#endif + + 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 + if (Device->ForwarderBound) { + // + // [FW] Call the Forwarder's FindRoute if installed + // + + // + // BUGBUG: What about the node number here? + // + Status = (*Device->UpperDrivers[IDENTIFIER_RIP].FindRouteHandler) ( + u.IpxNetnumData->netnum, + NULL, // FindRouteRequest->Node, + &routeEntry); + + if (Status != STATUS_SUCCESS) { + IPX_DEBUG (ACTION, (" MIPX_GETNETINFO_NR failed net %lx", + REORDER_ULONG(*(UNALIGNED ULONG *)(u.IpxNetnumData->netnum)))); + Status = STATUS_BAD_NETWORK_PATH; + } else { + // + // Fill in the information + // + IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1); + + if (Binding = NIC_ID_TO_BINDING(Device, routeEntry.LocalTarget.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.LocalTarget.NicId - 1); + } + + // RtlMoveMemory (u.IpxNetnumData->router, routeEntry.LocalTarget.MacAddress, 6); + + *((UNALIGNED ULONG *)u.IpxNetnumData->router) = + *((UNALIGNED ULONG *)routeEntry.LocalTarget.MacAddress); + *((UNALIGNED ULONG *)(u.IpxNetnumData->router+4)) = + *((UNALIGNED ULONG *)(routeEntry.LocalTarget.MacAddress+4)); + } + IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1); + } + + + } else { + 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: + + // + // BUGBUG We dont really support Re-RIP in the case of Forwarder above us + // + + // + // 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 { + +#ifdef _PNP_POWER + + if (Device->ForwarderBound) { + + // + // [FW] Call the Forwarder's FindRoute if installed + // + + // + // BUGBUG: What about the node number here? + // + Status = (*Device->UpperDrivers[IDENTIFIER_RIP].FindRouteHandler) ( + u.IpxNetnumData->netnum, + NULL, // FindRouteRequest->Node, + &routeEntry); + + if (Status != STATUS_SUCCESS) { + IPX_DEBUG (ACTION, (" MIPX_RERIPNETNUM failed net %lx", + REORDER_ULONG(*(UNALIGNED ULONG *)(u.IpxNetnumData->netnum)))); + Status = STATUS_BAD_NETWORK_PATH; + } else { + // + // Fill in the information + // + IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1); + if (Binding = NIC_ID_TO_BINDING(Device, routeEntry.LocalTarget.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.LocalTarget.NicId - 1); + } + + // RtlMoveMemory (u.IpxNetnumData->router, routeEntry.LocalTarget.MacAddress, 6); + + *((UNALIGNED ULONG *)u.IpxNetnumData->router) = + *((UNALIGNED ULONG *)routeEntry.LocalTarget.MacAddress); + *((UNALIGNED ULONG *)(u.IpxNetnumData->router+4)) = + *((UNALIGNED ULONG *)(routeEntry.LocalTarget.MacAddress+4)); + } + IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1); + } + + } else { + Segment = RipGetSegment(u.IpxNetnumData->netnum); + 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 + 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]) && + (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 { + +#ifdef _PNP_POWER + + if (Device->ForwarderBound) { + + // + // [FW] Call the Forwarder's FindRoute if installed + // + + // + // BUGBUG: What about the node number here? + // + Status = (*Device->UpperDrivers[IDENTIFIER_RIP].FindRouteHandler) ( + u.IpxNetnumData->netnum, + NULL, // FindRouteRequest->Node, + &routeEntry); + + if (Status != STATUS_SUCCESS) { + IPX_DEBUG (ACTION, (" MIPX_GETNETINFO failed net %lx", + REORDER_ULONG(*(UNALIGNED ULONG *)(u.IpxNetnumData->netnum)))); + Status = STATUS_BAD_NETWORK_PATH; + } else { + // + // Fill in the information + // + IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1); + + if (Binding = NIC_ID_TO_BINDING(Device, routeEntry.LocalTarget.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.LocalTarget.NicId - 1); + } + + // RtlMoveMemory (u.IpxNetnumData->router, routeEntry.LocalTarget.MacAddress, 6); + + *((UNALIGNED ULONG *)u.IpxNetnumData->router) = + *((UNALIGNED ULONG *)routeEntry.LocalTarget.MacAddress); + *((UNALIGNED ULONG *)(u.IpxNetnumData->router+4)) = + *((UNALIGNED ULONG *)(routeEntry.LocalTarget.MacAddress+4)); + } + + IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1); + } + } else { + Segment = RipGetSegment(u.IpxNetnumData->netnum); + 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 + 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 { + + // + // 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); + + if (Device->ForwarderBound) { + + // + // [FW] Call the Forwarder's FindRoute if installed + // + + // + // BUGBUG: What about the node number here? + // + Status = (*Device->UpperDrivers[IDENTIFIER_RIP].FindRouteHandler) ( + (PUCHAR)&u.GetLocalTarget->IpxAddress.NetworkAddress, + NULL, // FindRouteRequest->Node, + &routeEntry); + + if (Status != STATUS_SUCCESS) { + IPX_DEBUG (ACTION, (" MIPX_LOCALTARGET failed net %lx", + REORDER_ULONG(u.GetLocalTarget->IpxAddress.NetworkAddress))); + Status = STATUS_BAD_NETWORK_PATH; + } else { + // + // Fill in the information + // + + IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1); + // + // BUGBUG What about check for IPX_ROUTER_LOCAL_NET + // + if (Binding = NIC_ID_TO_BINDING(Device, routeEntry.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; + + u.GetLocalTarget->LocalTarget.NicId = Binding->NicId; + + } else { + + u.GetLocalTarget->LocalTarget.NicId = routeEntry.LocalTarget.NicId; + } + + *((UNALIGNED ULONG *)u.GetLocalTarget->LocalTarget.MacAddress) = + *((UNALIGNED ULONG *)routeEntry.LocalTarget.MacAddress); + *((UNALIGNED ULONG *)(u.GetLocalTarget->LocalTarget.MacAddress+4)) = + *((UNALIGNED ULONG *)(routeEntry.LocalTarget.MacAddress+4)); + } + + IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1); + } + } else { + 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 { + + if (Device->ForwarderBound) { + + // + // [FW] Call the Forwarder's FindRoute if installed + // + + // + // BUGBUG: What about the node number here? + // + Status = (*Device->UpperDrivers[IDENTIFIER_RIP].FindRouteHandler) ( + (PUCHAR)&u.GetNetworkInfo->Network, + NULL, // FindRouteRequest->Node, + &routeEntry); + + if (Status != STATUS_SUCCESS) { + IPX_DEBUG (ACTION, (" MIPX_GETNETINFO_NR failed net %lx", + REORDER_ULONG(u.GetNetworkInfo->Network))); + Status = STATUS_BAD_NETWORK_PATH; + } else { + // + // Fill in the information + // + + IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1); + if (Binding = NIC_ID_TO_BINDING(Device, routeEntry.LocalTarget.NicId)) { + // + // 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; + } + IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1); + } + } 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; + + + // + // Return new nic info to the requestor. Currently, no check for + // who retrieved the info earlier. + // + case MIPX_GETNEWNICINFO: + + DbgPrint("GetNewNicInfo case entered\n"); + IPX_DEBUG (ACTION, ("%lx: MIPX_GETNEWNICINFO (%lx)\n", AddressFile, + Request)); + // + // a request for details on new bindings. + // + Status = GetNewNics(Device, Request, TRUE, NwlinkAction, BufferLength, FALSE); + break; + + // + // In case a LineUp occurs with the IpxwanConfigRequired, this is used + // to indicate to IPX that the config is done and that the LineUp + // can be indicated to the other clients. + // + case MIPX_IPXWAN_CONFIG_DONE: + + DbgPrint("IPXWAN_CONFIG_DONE case entered\n"); + IPX_DEBUG (ACTION, ("MIPX_IPXWAN_CONFIG_DONE (%lx)\n", Request)); + + if (DataLength < sizeof(IPXWAN_CONFIG_DONE)) { + return STATUS_BUFFER_TOO_SMALL; + } + + u.IpxwanConfigDone = (PIPXWAN_CONFIG_DONE)(NwlinkAction->Data); + Status = IpxIndicateLineUp( IpxDevice, + u.IpxwanConfigDone->NicId, + u.IpxwanConfigDone->Network, + u.IpxwanConfigDone->LocalNode, + u.IpxwanConfigDone->RemoteNode); + break; + + // + // Used to query the WAN inactivity counter for a given NicId + // + case MIPX_QUERY_WAN_INACTIVITY: { + + USHORT NicId; + + DbgPrint("QUERY_WAN_INACTIVITY case entered\n"); + IPX_DEBUG (ACTION, ("MIPX_QUERY_WAN_INACTIVITY (%lx)\n", Request)); + + if (DataLength < sizeof(IPX_QUERY_WAN_INACTIVITY)) { + return STATUS_BUFFER_TOO_SMALL; + } + + u.QueryWanInactivity = (PIPX_QUERY_WAN_INACTIVITY)(NwlinkAction->Data); + + // + // If this is an invalid Nic, then we need to associate a Nic with the ConnectionId that + // was passed in. + // This should happen only once per line up. + // + if (u.QueryWanInactivity->NicId == INVALID_NICID) { + PBINDING Binding; + { + ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId); + + IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1); + for ( NicId = Device->HighestLanNicId+1;NicId < Index;NicId++ ) { + Binding = NIC_ID_TO_BINDING(Device, NicId); + if (Binding && (Binding->ConnectionId == u.QueryWanInactivity->ConnectionId)) { + CTEAssert(Binding->Adapter->MacInfo.MediumAsync); + if (Binding->LineUp != LINE_CONFIG) { + IPX_DEBUG (WAN, ("Binding is not in config state yet got QUERY_WAN_INACTIVITY %lx %lx", Binding, Request)); + NicId = 0; + } + u.QueryWanInactivity->NicId = NicId; + break; + } + } + IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1); + } + } + + if (NicId) { + u.QueryWanInactivity->WanInactivityCounter = IpxInternalQueryWanInactivity(NicId); + Status = STATUS_SUCCESS; + } else { + 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; + } + } + } + + if (!Found) { + for (p = Device->NicNtfQueue.Flink; + p != &Device->NicNtfQueue; + p = p->Flink) { + + if (LIST_ENTRY_TO_REQUEST(p) == Request) { + + RemoveEntryList (p); + Found = TRUE; + IOCTLType = MIPX_GETNEWNICINFO; + 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 { + if (IOCTLType == MIPX_LINECHANGE) { + IPX_DEBUG(ACTION, ("Cancelled action LINECHANGE %lx\n", Request)); + IpxDereferenceDevice (Device, DREF_LINE_CHANGE); + } 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 */ + + +NTSTATUS +GetNewNics( + PDEVICE Device, + IN PREQUEST Request, + BOOLEAN fCheck, + PNWLINK_ACTION NwlinkAction, + UINT BufferLength, + BOOLEAN OldIrp +) +{ + NTSTATUS Status = STATUS_SUCCESS; + UINT DataLength; + PNDIS_BUFFER NdisBuffer; + CTELockHandle LockHandle; + CTELockHandle LockHandle1; + PBINDING Binding; + ULONG NoOfNullNics = 0; + PIPX_NICS pNics; + PIPX_NIC_INFO pNicInfo; + PIPX_NIC_INFO pLastNicInfo; + UINT LengthOfHeader; + ULONG n, i; + KIRQL OldIrql; + + + LengthOfHeader = (UINT)(FIELD_OFFSET(NWLINK_ACTION, Data[0])); + if (fCheck) + { + if (BufferLength < (LengthOfHeader + FIELD_OFFSET(IPX_NICS, Data[0]) + sizeof(IPX_NIC_INFO))) + { + IPX_DEBUG (ACTION, ("Nwlink action failed, buffer too small for even one NICs info\n")); + return STATUS_BUFFER_TOO_SMALL; + } + } + else + { + NdisQueryBuffer (REQUEST_NDIS_BUFFER(Request), (PVOID *)&NwlinkAction, &BufferLength); + + } + pNics = (PIPX_NICS)(NwlinkAction->Data); + pNicInfo = (PIPX_NIC_INFO)(pNics->Data); + pLastNicInfo = pNicInfo + ((BufferLength - LengthOfHeader - FIELD_OFFSET(IPX_NICS, Data[0]))/sizeof(IPX_NIC_INFO)) - 1; + + DbgPrint("GetNewNicInfo: pNicInfo=(%x), pLastNicInfo=(%x),LengthOfHeader=(%x), BindingCount=(%x)\n", pNicInfo, pLastNicInfo, LengthOfHeader, Device->ValidBindings); + DbgPrint("BufferLength is (%d). Length for storing NICS is (%d)\n", BufferLength, (BufferLength - LengthOfHeader - FIELD_OFFSET(IPX_NICS, Data[0]))); + // + // Optimize since we don't want to go over the array all the time. + // + + CTEGetLock (&Device->Lock, &LockHandle); + + { + ULONG Index = MIN (Device->MaxBindings, Device->ValidBindings); + + IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1); + for (n=0, i=1; i<=Index; i++) + { + Binding = NIC_ID_TO_BINDING(Device, i); + + if (!Binding) + { + NoOfNullNics++; + continue; + } + // + // If we have already indicated info about this NIC, go on to the + // next nic. + // + if ((Binding->fInfoIndicated && !pNics->fAllNicsDesired) + || (pNicInfo > pLastNicInfo)) + { + continue; + } + + // + // If we have a WAN nic, indicate the line up/down status. Also, + // copy the remote address into the app. field + // + if (Binding->Adapter->MacInfo.MediumAsync) + { + RtlCopyMemory(pNicInfo->RemoteNodeAddress, Binding->WanRemoteNode, HARDWARE_ADDRESS_LENGTH); + if (Binding->LineUp) + { + // pNicInfo->Status = NIC_LINE_UP; + + pNicInfo->Status = NIC_CREATED; + } + else + { + // pNicInfo->Status = NIC_LINE_DOWN; + + pNicInfo->Status = NIC_DELETED; + } + + pNicInfo->InterfaceIndex = Binding->InterfaceIndex; + pNicInfo->MaxPacketSize = + Binding->MaxSendPacketSize - ASYNC_MEDIUM_HDR_LEN; + } + else + { + if (Binding->LocalAddress.NetworkAddress == 0) + { + pNicInfo->Status = NIC_CREATED; + } + else + { + pNicInfo->Status = NIC_CONFIGURED; + } + + // + // RealMaxDatagramSize does not include space for ipx + // header. The forwarder needs to have it included since + // we give the entire packet (mimus the mac header) to + // the forwarder + // + pNicInfo->MaxPacketSize = + Binding->RealMaxDatagramSize + sizeof(IPX_HEADER); + } + pNicInfo->NdisMediumType= Binding->Adapter->MacInfo.RealMediumType; + pNicInfo->LinkSpeed = Binding->MediumSpeed; + pNicInfo->PacketType = Binding->FrameType; + pNicInfo->NetworkAddress= Binding->LocalAddress.NetworkAddress; + RtlCopyMemory(pNicInfo->LocalNodeAddress, Binding->LocalAddress.NodeAddress, HARDWARE_ADDRESS_LENGTH); + pNicInfo->NicId = Binding->NicId; + pNicInfo->ConnectionId = Binding->ConnectionId; + pNicInfo->IpxwanConfigRequired = Binding->IpxwanConfigRequired; + + pNicInfo++; //increment to store next nic info + n++; //indicates the # of nics processed so far. + Binding->fInfoIndicated = TRUE; + DbgPrint("Iteration no = (%d) complete\n", n); + } + IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1); + } + CTEFreeLock (&Device->Lock, LockHandle); + + pNics->NoOfNics = n; + pNics->TotalNoOfNics = Device->ValidBindings - NoOfNullNics; + + // + // If no nics. to report, queue the request + // + if (!n) { + + DbgPrint("GetNewNicInfo: Inserting Irp\n"); + CTEGetLock (&Device->Lock, &LockHandle); + + InsertTailList( &Device->NicNtfQueue, REQUEST_LINKAGE(Request) ); + + if (!OldIrp) + { + CTEFreeLock (&Device->Lock, LockHandle); + IoAcquireCancelSpinLock(&OldIrql); + IoSetCancelRoutine (Request, IpxCancelAction); + IoReleaseCancelSpinLock(OldIrql); + CTEGetLock (&Device->Lock, &LockHandle); + } + if (Request->Cancel) { + DbgPrint("GetNewNicInfo:Cancelling Irp\n"); + + (VOID)RemoveTailList (&Device->NicNtfQueue); + CTEFreeLock (&Device->Lock, LockHandle); + IoAcquireCancelSpinLock(&OldIrql); + IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL); + IoReleaseCancelSpinLock(OldIrql); + Status = STATUS_CANCELLED; + } else { + if (!OldIrp) + { + IpxReferenceDevice (Device, DREF_NIC_NOTIFY); + } + Status = STATUS_PENDING; + CTEFreeLock (&Device->Lock, LockHandle); + } + } + else + { + DbgPrint("Reporting (%d) nics\n", n); + } + + return(Status); +} + + +VOID +IpxAbortNtfChanges( + 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->NicNtfQueue.Flink; + + while (p != &Device->NicNtfQueue) { + LARGE_INTEGER ControlChId; + + Request = LIST_ENTRY_TO_REQUEST(p); + + CCID_FROM_REQUEST(ControlChId, Request); + + DbgPrint("IpxAbortNtfChange: There is at least one IRP in the queue\n"); + p = p->Flink; + + if (ControlChId.QuadPart == ((PLARGE_INTEGER)ControlChannelContext)->QuadPart) { + DbgPrint("IpxAbortNtfChanges: Dequeing an Irp\n"); + 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 ); + + DbgPrint("IpxAbortNtfChanges: Cancelling the dequeued Irp\n"); + IpxCompleteRequest (Request); + IpxFreeRequest(Device, Request); + + IpxDereferenceDevice (Device, DREF_NIC_NOTIFY); + + IoAcquireCancelSpinLock( &irql ); + CTEGetLock(&Device->Lock, &LockHandle); + } + + CTEFreeLock(&Device->Lock, LockHandle); + IoReleaseCancelSpinLock( irql ); +} /* IpxAbortNtfChanges */ + +NTSTATUS +IpxIndicateLineUp( + IN PDEVICE Device, + IN USHORT NicId, + IN ULONG Network, + IN UCHAR LocalNode[6], + IN UCHAR RemoteNode[6] + ) +/*++ + +Routine Description: + + This routine indicates a line-up to all the concerned clients once + the line is up. + For now, called only if the MIPX_IPXWAN_CONFIG_DONE IOCTL is received. + + +Arguments: + + Device - The device for the operation. + + NicId - The NicId corresponding to the binding that is up. + + Network, LocalNode, RemoteNode - addresses corresponding to this lineup. + +Return Value: + + NTSTATUS - status of operation. + +--*/ +{ + PBINDING Binding = NIC_ID_TO_BINDING(Device, NicId); + IPX_LINE_INFO LineInfo; + USHORT i; + PLIST_ENTRY p; + PREQUEST Request; + PNDIS_BUFFER NdisBuffer; + PNWLINK_ACTION NwlinkAction; + UINT BufferLength; + PIPX_ADDRESS_DATA IpxAddressData; + IPXCP_CONFIGURATION Configuration; + KIRQL irql, OldIrq; + NTSTATUS Status; + NTSTATUS ntStatus; + KIRQL OldIrql; + + IPX_DEFINE_LOCK_HANDLE (LockHandle) + + if (!(Binding && + Binding->Adapter->MacInfo.MediumAsync && + Binding->LineUp == LINE_CONFIG)) { + IPX_DEBUG(WAN, ("Indicate line up on invalid line: %lu\n", NicId)); + return STATUS_INVALID_PARAMETER; + } + + // [BUGBUG] take bindaccesslock here... + // + + // + // If we are here, then this flag was set on a line up. + // We turn it off now so that the adapter dll above us can decide + // to indicate this lineup to the router module instead of the IpxWan module + // + + CTEAssert(Binding->IpxwanConfigRequired); + + Binding->IpxwanConfigRequired = 0; + + Binding->LineUp = LINE_UP; + + // + // Indicate to the upper drivers. + // + + LineInfo.LinkSpeed = Binding->MediumSpeed; + LineInfo.MaximumPacketSize = Binding->MaxSendPacketSize - 14; + LineInfo.MaximumSendSize = Binding->MaxSendPacketSize - 14; + LineInfo.MacOptions = Binding->Adapter->MacInfo.MacOptions; + + // + // Fill-in the addresses into the bindings + // + Binding->LocalAddress.NetworkAddress = Network; + + *(UNALIGNED ULONG *)Binding->LocalAddress.NodeAddress = *(UNALIGNED ULONG *)LocalNode; + *(UNALIGNED ULONG *)(Binding->LocalAddress.NodeAddress+4) = *(UNALIGNED ULONG *)(LocalNode+4); + + *(UNALIGNED ULONG *)Binding->WanRemoteNode = *(UNALIGNED ULONG *)RemoteNode; + *(UNALIGNED ULONG *)(Binding->WanRemoteNode+4) = *(UNALIGNED ULONG *)(RemoteNode+4); + + // + // Fill in the IPXCP_CONFIGURATION structure from the binding. + // + *(UNALIGNED ULONG *)Configuration.Network = Binding->LocalAddress.NetworkAddress; + + *(UNALIGNED ULONG *)Configuration.LocalNode = *(UNALIGNED ULONG *)Binding->LocalAddress.NodeAddress; + *(UNALIGNED USHORT *)(Configuration.LocalNode+4) = *(UNALIGNED USHORT *)(Binding->LocalAddress.NodeAddress+4); + + *(UNALIGNED ULONG *)Configuration.RemoteNode = *(UNALIGNED ULONG *)RemoteNode; + *(UNALIGNED USHORT *)(Configuration.RemoteNode+4) = *(UNALIGNED USHORT *)(RemoteNode+4); + + Configuration.InterfaceIndex = Binding->InterfaceIndex; + Configuration.ConnectionClient = Binding->DialOutAsync; + +#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) + + Binding->IsnInformed[IDENTIFIER_NB] = TRUE; + + 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. + // + // + // Give line up to RIP as it is not PnP aware. + // + if (Device->UpperDriverBound[IDENTIFIER_RIP]) { + Binding->IsnInformed[IDENTIFIER_RIP] = TRUE; + (*Device->UpperDrivers[IDENTIFIER_RIP].LineUpHandler)( + Binding->NicId, + &LineInfo, + NdisMediumWan, + &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, + &Configuration); + } + } +#endif + + // + // Add router entry for this net since it was not done on LineUp. + // Also, update the addresses' pre-constructed local IPX address. + // + { + ULONG CurrentHash; + PADAPTER Adapter = Binding->Adapter; + PADDRESS Address; + + // + // 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 + Binding->MediumSpeed) / Binding->MediumSpeed)) != 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")); + // [FW] Binding->LineUp = FALSE; + Binding->LineUp = LINE_DOWN; + return STATUS_SUCCESS; + } + } + + // + // 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); + + } + } + + + + // + // [FW] IpxWan config state will not be entered if only the line params are getting + // updated. + // + // if (!UpdateLineUp) { + + // + // Instead of the check for ConnectionClient, use the DialOutAsync flag + // + if ((Device->SingleNetworkActive) && + /*(LineUp->Configuration.ConnectionClient == 1)*/ + Binding->DialOutAsync) { + + // + // 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); + + IoAcquireCancelSpinLock( &irql ); + IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL); + IoReleaseCancelSpinLock( irql ); + + REQUEST_STATUS(Request) = STATUS_SUCCESS; + + // + // BUGBUG:NwRdr assumes that Line-up completions are at DPC + // + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + IpxCompleteRequest (Request); + KeLowerIrql(OldIrql); + + 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; + + IoAcquireCancelSpinLock( &irql ); + IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL); + IoReleaseCancelSpinLock( irql ); + + REQUEST_STATUS(Request) = STATUS_SUCCESS; + IpxCompleteRequest (Request); + IpxFreeRequest (Device, Request); + + IpxDereferenceDevice (Device, DREF_ADDRESS_NOTIFY); + } + + Binding->fInfoIndicated = FALSE; + if ((p = ExInterlockedRemoveHeadList( + &Device->NicNtfQueue, + &Device->Lock)) != NULL) + { + Request = LIST_ENTRY_TO_REQUEST(p); + + DbgPrint("IpxStatus: WAN LINE UP\n"); + Status = GetNewNics(Device, Request, FALSE, NULL, 0, FALSE); + if (Status != STATUS_SUCCESS) + { + DbgPrint("WAN Line up screw up\n"); + } + else + { + IoAcquireCancelSpinLock(&OldIrq); + IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL); + IoReleaseCancelSpinLock(OldIrq); + + REQUEST_STATUS(Request) = Status; + IpxCompleteRequest (Request); + IpxFreeRequest (Device, Request); + IpxDereferenceDevice (Device, DREF_NIC_NOTIFY); + } + } +// } + + return STATUS_SUCCESS; +} diff --git a/private/ntos/tdi/isn/ipx/adapter.c b/private/ntos/tdi/isn/ipx/adapter.c new file mode 100644 index 000000000..4dc3799aa --- /dev/null +++ b/private/ntos/tdi/isn/ipx/adapter.c @@ -0,0 +1,804 @@ +/*++ + +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 + +// +// [FW] So, later we can change this to pnp-compatible value +// + +// +// ULONG +// ADAPTER_INDEX_TO_FWCONTEXT( +// IN ULONG _adapterindex; +// ); +// + +#define ADAPTER_INDEX_TO_FWCONTEXT(_adapterindex) _adapterindex + + +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 + +// +// [FW] +// + +NTSTATUS +IpxOpenAdapter( + IN NIC_HANDLE AdapterIndex1, + IN ULONG FwdAdapterContext, + OUT PNIC_HANDLE IpxAdapterContext + ) + +/*++ + +Routine Description: + + This routine is called by the Kernel Forwarder to open an adapter + +Arguments: + + AdapterIndex - index of the adapter to open (NICid for now - will change to a struct + with a version number, signature and the NicId + FwdAdapterContext - Forwarder's context + IpxAdapterContext - our context (for now we use the NICid - for pnp will change + this to contain a signature and version #) + +Return Value: + + STATUS_INVALID_HANDLE if the AdapterIndex handle was invalid + STATUS_ADAPTER_ALREADY_OPENED if the Adapter is being opened a second time + STATUS_SUCCESS + +--*/ + +{ + PBINDING Binding; + PDEVICE Device = IpxDevice; + USHORT AdapterIndex = AdapterIndex1.NicId; + +#if DBG + DbgPrint ("IPX: Entered IpxOpenAdapter\n"); +#endif + + // + // Return error if the AdapterIndex is out of range. + // We do indicate the slave bindings to NB/SPX (but not to RIP) + // Hence, the index should be less than HighestExternalNicId (not ValidBindings) + // + + if (AdapterIndex > Device->HighestExternalNicId) { + return STATUS_INVALID_HANDLE; + } + + + // + // Fill up our context to be returned to the Forwarder + // + NIC_HANDLE_FROM_NIC((*IpxAdapterContext), AdapterIndex); + + // + // If AdapterIndex is 0, it is for the virtual net + // BUGBUG: Will the forwarder open this at all? + // + + if (AdapterIndex == 0) { + return STATUS_SUCCESS; + } + + // + // Get the binding pointer + // + + Binding = NIC_ID_TO_BINDING(IpxDevice, AdapterIndex); + + // + // Return error if adapter is being opened a second time (or more times) + // + + if (GET_VALUE(Binding->ReferenceCount) >= 2) { + return STATUS_ADAPTER_ALREADY_OPENED; + } + + // + // Store the Forwarder's Adapter Context in the binding + // + + Binding->FwdAdapterContext = FwdAdapterContext; + + // + // Reference the Binding + // + + IpxReferenceBinding(Binding, BREF_FWDOPEN); + + return STATUS_SUCCESS; + +} + +NTSTATUS +IpxCloseAdapter( + IN NIC_HANDLE IpxAdapterContext + ) + +/*++ + +Routine Description: + + This routine is called by the Kernel Forwarder to close an adapter + +Arguments: + + IpxAdapterContext - our context (for now we use the NICid - for pnp will change + this to contain a signature and version#) + +Return Value: + + STATUS_ADAPTER_ALREADY_CLOSED - if the adapter is being closed a second time + STATUS_SUCCESS + +--*/ + +{ + + PBINDING Binding; + +#if DBG + DbgPrint ("IPX: Entered IpxCloseAdapter\n"); +#endif + + Binding = NIC_ID_TO_BINDING(IpxDevice, IpxAdapterContext.NicId); + + // + // Either the adapter is around (count = 2) + // or it went away (count = 1). The latter cannot happen now. + // + + if (GET_VALUE(Binding->ReferenceCount) <= 1) { + return STATUS_ADAPTER_ALREADY_CLOSED; + } + + // + // Dereference the Binding so it can be deleted + // + + IpxDereferenceBinding(Binding, BREF_FWDOPEN); + + + // + // Clear the Forwarder's Adapter Context in the binding + // + + Binding->FwdAdapterContext = 0; + + return STATUS_SUCCESS; +} + diff --git a/private/ntos/tdi/isn/ipx/address.c b/private/ntos/tdi/isn/ipx/address.c new file mode 100644 index 000000000..c7e1e0f38 --- /dev/null +++ b/private/ntos/tdi/isn/ipx/address.c @@ -0,0 +1,1882 @@ +/*++ + +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 + ) + +{ + return(IpxOpenAddressM(Device, Request, 0)); +} + + + +NTSTATUS +IpxOpenAddressM( + IN PDEVICE Device, + IN PREQUEST Request, + IN ULONG Index + ) +/*++ + +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 && (REQUEST_CODE(Request) != MIPX_RT_CREATE)) { + 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")); +#ifdef SNMP + ++IPX_MIB_ENTRY(Device, SysOpenSocketFails); +#endif SNMP + 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; + + if (REQUEST_CODE(Request) == MIPX_RT_CREATE) { + Address->RtAdd = TRUE; + Address->Index = Index; + } else { + Address->RtAdd = FALSE; + } + +#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)); + + // + // We never allow shared access to a RT address. So, check that + // we don't have a "RT address create" request and also that the + // address has not only been taken up by a RT Address request. If + // and only if both the above + // + if ((REQUEST_CODE(Request) != MIPX_RT_CREATE) && (!Address->RtAdd)) + { + // + // 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; + + } + } + } + else + { + DbgPrint("IpxOpenAddress: ACCESS DENIED - duplicate address\n"); + status = STATUS_ACCESS_DENIED; + ExReleaseResource (&Device->AddressResource); + IpxDereferenceAddressFile (AddressFile, AFREF_CREATE); + + } + + // + // 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/isn/ipx/config.c b/private/ntos/tdi/isn/ipx/config.c new file mode 100644 index 000000000..f5d8aefbf --- /dev/null +++ b/private/ntos/tdi/isn/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/isn/ipx/config.h b/private/ntos/tdi/isn/ipx/config.h new file mode 100644 index 000000000..ba6e76d83 --- /dev/null +++ b/private/ntos/tdi/isn/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/isn/ipx/device.c b/private/ntos/tdi/isn/ipx/device.c new file mode 100644 index 000000000..f6cb2d302 --- /dev/null +++ b/private/ntos/tdi/isn/ipx/device.c @@ -0,0 +1,612 @@ +/*++ + +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); + + // + // [FW] Initialize the timer used to update inactivity counters + // on WAN lines. + // + CTEInitTimer (&Device->WanInactivityTimer); + + // + // 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); + +#ifdef SNMP + // + // BUGBUGZZ: what are the values for these? + // + IPX_MIB_ENTRY(Device, SysInstance) = 0; + IPX_MIB_ENTRY(Device, SysExistState) = 0; +#endif SNMP + + *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/isn/ipx/dirs b/private/ntos/tdi/isn/ipx/dirs new file mode 100644 index 000000000..0dab2f056 --- /dev/null +++ b/private/ntos/tdi/isn/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/isn/ipx/driver.c b/private/ntos/tdi/isn/ipx/driver.c new file mode 100644 index 000000000..5db05660a --- /dev/null +++ b/private/ntos/tdi/isn/ipx/driver.c @@ -0,0 +1,4447 @@ +/*++ + +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); + + 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; + + InitializeListHead(&Device->NicNtfQueue); + InitializeListHead(&Device->NicNtfComplQueue); + +#ifdef _PNP_POWER + Device->InitBindings = 5; // BUGBUG: config this? + + // + // RAS max is 240 (?) + 10 max LAN + // + Device->MaxPoolBindings = 250; // BUGBUG: config this? +#endif + +#ifdef SNMP + IPX_MIB_ENTRY(Device, SysConfigSockets) = (Device->SocketEnd - Device->SocketStart) + / ((Device->SocketUniqueness > 1) ? Device->SocketUniqueness : 1); + ; +#endif SNMP + + // + // 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 - EXTRA_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)); + + // + // We keep BindingArray[-1] as a placeholder for demand dial bindings. + // This NicId is returned by the Fwd when a FindRoute is done on a demand + // dial Nic. At the time of the InternalSend, the true Nic is returned. + // We create a placeholder here to avoid special checks in the critical send path. + // + // NOTE: we need to free this demand dial binding as well as ensure that the + // true binding array pointer is freed at Device Destroy time. + // + // + // Increment beyond the first pointer - we will refer to the just incremented + // one as Device->Bindings[-1]. + // + BindingArray += EXTRA_BINDINGS; + + 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); + + } + + } + + // + // Backup the pointer to free the demand dial location. + // + IpxDevice->Bindings -= EXTRA_BINDINGS; + +#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; + ULONG Type; + + 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; + } + + // + // Router + // + if (strncmp(openType->EaName, ROUTER_INTERFACE, + openType->EaNameLength) == 0) + { + found = TRUE; + } + + if (found) { + Status = OpenRtAddress (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 + { + Status = STATUS_NONEXISTENT_EA_ENTRY; + + } + + } 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 (Type = ((ULONG)(REQUEST_OPEN_TYPE(Request)) & IPX_CC_MASK)) { + default: + if ((Type >= ROUTER_ADDRESS_FILE) && + (Type <= (ROUTER_ADDRESS_FILE + IPX_RT_MAX_ADDRESSES))) + { + CloseRtAddress(Device, Request); + } + else + { + Status = STATUS_INVALID_HANDLE; + break; + } + + // fall through + 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; + } + } + + 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 (Type = ((ULONG)(REQUEST_OPEN_TYPE(Request)) & IPX_CC_MASK)) { + default: + + if ((Type >= ROUTER_ADDRESS_FILE) && + (Type <= (ROUTER_ADDRESS_FILE + IPX_RT_MAX_ADDRESSES))) + { + CleanupRtAddress(Device, Request); + } + else + { + Status = STATUS_INVALID_HANDLE; + break; + } + + + // + // fall through + // + 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); + IpxAbortNtfChanges ((PVOID)&ControlChannelId); + + Status = STATUS_SUCCESS; + break; + } + } + + 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; + +#ifdef SNMP + case IOCTL_IPX_MIB_GET: { + + // + // Get the Base MIB entries out of the device. All Host-side + // entries, appearing in the MS and Novell MIBs are returned. + // + PNOVIPXMIB_BASE UserBuffer; + + UserBuffer = (PNOVIPXMIB_BASE)Irp->AssociatedIrp.SystemBuffer; + + Irp->IoStatus.Information = sizeof(NOVIPXMIB_BASE); + + RtlCopyMemory( UserBuffer, + &Device->MibBase, + sizeof(NOVIPXMIB_BASE)); + + Irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest (Irp, IO_NETWORK_INCREMENT); + + Status = STATUS_SUCCESS; + + break; + } +#endif SNMP + + case MIPX_SEND_DATAGRAM: + MARK_REQUEST_PENDING(Irp); + Status = SendIrpFromRt (Device, Irp); + if (Status == STATUS_PENDING) { + return STATUS_PENDING; + } else { + UNMARK_REQUEST_PENDING(Irp); + REQUEST_STATUS(Irp) = Status; + IpxCompleteRequest (Irp); + IpxFreeRequest (Device, Irp); + return Status; + } + + break; + + case MIPX_RCV_DATAGRAM: + MARK_REQUEST_PENDING(Irp); + Status = RcvIrpFromRt (Device, Irp); + if (Status == STATUS_PENDING) { + return STATUS_PENDING; + } else { + UNMARK_REQUEST_PENDING(Irp); + REQUEST_STATUS(Irp) = Status; + IpxCompleteRequest (Irp); + IpxFreeRequest (Device, Irp); + return Status; + } + + 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); + + Binding->fInfoIndicated = FALSE; + + if (Adapter->MacInfo.MediumAsync) { + PBINDING DemandDialBinding; + + // + // 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; + } + + // + // Prime the DemandDial binding too. + // + + // + // First allocate the memory for the binding. + // + status = IpxCreateBinding( + Device, + NULL, + 0, + Adapter->AdapterName, + &DemandDialBinding); + + if (status != STATUS_SUCCESS) { + CTEAssert(FALSE); + } + + // + // Copy over all the values from the first WAN binding created above. + // + RtlCopyMemory(DemandDialBinding, Binding, sizeof(BINDING)); + INSERT_BINDING(Device, (SHORT)DEMAND_DIAL_ADAPTER_CONTEXT, DemandDialBinding); + DemandDialBinding->NicId = (USHORT)DEMAND_DIAL_ADAPTER_CONTEXT; + DemandDialBinding->FwdAdapterContext = INVALID_CONTEXT_VALUE; + IpxReferenceBinding(DemandDialBinding, BREF_FWDOPEN); // so it appears the FWD opened it. + + // + // 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 && + (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 { + + PBINDING WanBinding=NIC_ID_TO_BINDING_NO_ILOCK(Device, Device->HighestLanNicId+1); + + if (WanBinding) { + WanBinding->Adapter->LastWanNicId++; + WanBinding->Adapter->FirstWanNicId++; + } + + // + // 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++; + } + } + + // + // Increment the WAN counters in the adapter. + // + + + // + // 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; + } + + if (!NIC_ID_TO_BINDING(Device, (SHORT)LOOPBACK_NIC_ID)) { + PBINDING LoopbackBinding; + + // + // Prime the Loopback binding too. + // + + // + // First allocate the memory for the binding. + // + status = IpxCreateBinding( + Device, + NULL, + 0, + Adapter->AdapterName, + &LoopbackBinding); + + if (status != STATUS_SUCCESS) { + CTEAssert(FALSE); + } + + // + // Copy over all the values from the first WAN binding created above. + // + RtlCopyMemory(LoopbackBinding, Binding, sizeof(BINDING)); + INSERT_BINDING(Device, (SHORT)LOOPBACK_NIC_ID, LoopbackBinding); + LoopbackBinding->NicId = (USHORT)LOOPBACK_NIC_ID; + LoopbackBinding->FwdAdapterContext = VIRTUAL_NET_FORWARDER_CONTEXT; + IpxReferenceBinding(LoopbackBinding, BREF_FWDOPEN); // so it appears the FWD opened it. + } + } + + } + + // + // 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 close 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; + PBIND_ARRAY_ELEM OldBindingArray; + 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)); + + // + // Backup the pointer to free the demand dial location. + // + OldBindingArray = Device->Bindings - EXTRA_BINDINGS; + + // + // Copy the old array into the new one. + // + RtlCopyMemory (BindingArray, OldBindingArray, (Device->ValidBindings+1+EXTRA_BINDINGS) * sizeof(BIND_ARRAY_ELEM)); + + // + // Free the old one. + // + IpxFreeMemory ( OldBindingArray, + (Device->MaxBindings+EXTRA_BINDINGS) * 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)); + + + // + // We keep BindingArray[-1] as a placeholder for demand dial bindings. + // This NicId is returned by the Fwd when a FindRoute is done on a demand + // dial Nic. At the time of the InternalSend, the true Nic is returned. + // We create a placeholder here to avoid special checks in the critical send path. + // + // NOTE: we need to free this demand dial binding as well as ensure that the + // true binding array pointer is freed at Device Destroy time. + // + // + // Increment beyond the first pointer - we will refer to the just incremented + // one as Device->Bindings[-1]. + // + BindingArray += EXTRA_BINDINGS; + + // + // 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 - EXTRA_BINDINGS; + + return STATUS_SUCCESS; +} +#endif _PNP_POWER + diff --git a/private/ntos/tdi/isn/ipx/event.c b/private/ntos/tdi/isn/ipx/event.c new file mode 100644 index 000000000..a64f85d34 --- /dev/null +++ b/private/ntos/tdi/isn/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/isn/ipx/ind.c b/private/ntos/tdi/isn/ipx/ind.c new file mode 100644 index 000000000..c670c3a59 --- /dev/null +++ b/private/ntos/tdi/isn/ipx/ind.c @@ -0,0 +1,4417 @@ +/*++ + +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 IpxReceiveIndicationCommon + 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) + PIPX_DATAGRAM_OPTIONS2 Options2; + BOOLEAN RtProc = FALSE; + + // + // 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. + // + +#ifdef SNMP + ++IPX_MIB_ENTRY(Device, SysInUnknownSockets); +#endif SNMP + + 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); + + // + // If this is RtAdd, skip the entire body + // + if (!Address->RtAdd) + { + 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. + // + + // + // [FW] no need to check if the FWD is bound + // + if (!Device->ForwarderBound && + (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; + } + + } + } else { + + //IpxPrint0("IpxProcessDatagram: Rt packet\n"); + if (Address->ReceivePacketInUse) { + // + // Need a packet, check the pool. + // + + s = IpxPopReceivePacket (Device); + + if (s == NULL) { + + goto BreakWithLock; + } + + + Reserved = CONTAINING_RECORD (s, IPX_RECEIVE_RESERVED, PoolLinkage); + ReceivePacket = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]); + + } else { + + Address->ReceivePacketInUse = TRUE; + ReceivePacket = PACKET(&Address->ReceivePacket); + Reserved = RECEIVE_RESERVED(&Address->ReceivePacket); + + } + //IpxPrint0("IpxProcessDatagram: Rt packet reserved\n"); + s = IpxPopReceiveBuffer (Adapter); + + if (s == NULL) { + + // + // No buffers, fail the request. + // + // BUGBUG: Should we fail the transfer for the + // first request too? + // + goto BreakWithLock; + } + + ReceiveBuffer = CONTAINING_RECORD(s, IPX_RECEIVE_BUFFER, PoolLinkage); + NdisBuffer = ReceiveBuffer->NdisBuffer; + Reserved->ReceiveBuffer = ReceiveBuffer; + ByteOffset = LookaheadBufferOffset; + BytesToTransfer = PacketSize; + //IpxPrint0("IpxProcessDatagram: Rt packet buffer reserved\n"); + RtProc = TRUE; + Reserved->Index = Address->Index; + + } + +BreakWithLock: + + 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 || RtProc) { + + if (RtProc) { + Reserved->pContext = IpxAllocateMemory(sizeof(IPX_DATAGRAM_OPTIONS2), MEMORY_PACKET, "RT Options"); + if (!Reserved->pContext) { + + ASSERTMSG("Out of resources\n", 1); + goto GetOut; + } else { + //IpxPrint1("IpxProcessDatagram: Nic Id is (%d)\n", DatagramOptions->LocalTarget.NicId); + RtlCopyMemory( + &((PIPX_DATAGRAM_OPTIONS2)(Reserved->pContext))->DgrmOptions, + DatagramOptions, + sizeof(IPX_DATAGRAM_OPTIONS)); + //IpxPrint1("IpxProcessDatagram: Nic Id is (%d)\n", + // ((PIPX_DATAGRAM_OPTIONS2)(Reserved->pContext))->DgrmOptions.LocalTarget.NicId); + } + } else { + Reserved->pContext = NULL; + } + + // + // 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); + } + } +#ifdef SNMP + else { + ++IPX_MIB_ENTRY(Device, SysInUnknownSockets); + } +#endif SNMP + +GetOut: + + 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 IpxReceiveIndicationCommon ( + 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 +IpxReceiveIndicationCommon( + 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 + BOOLEAN fCallProcessDatagram = FALSE; + +#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)) { +#ifdef SNMP + ++IPX_MIB_ENTRY(Device, SysInReceives); + ++IPX_MIB_ENTRY(Device, SysInHdrErrors); +#endif SNMP + 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, LOOPBACK_NIC_ID); +#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. + // + + // + // [FW] If FWD bound, no need to check since the FWD does the checks + // + if (!Device->ForwarderBound && + (!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)); + +#ifdef SNMP + ++IPX_MIB_ENTRY(Device, SysInReceives); + +#endif SNMP + + 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 + +#ifdef SNMP + ++IPX_MIB_ENTRY(Device, SysInReceives); + +#endif SNMP + + 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; + + DestinationNode = IpxHeader->DestinationNode; + + if (DestinationSocket != RIP_SOCKET) { + + DestinationNetwork = *(UNALIGNED ULONG *)IpxHeader->DestinationNetwork; + +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: + + // + // [FW] For internally destined packets, call the Forwarder's internal + // receive handler to filter the packets. + // + // STEFAN: 3/28/96: + // Dont filter IPXWAN config packets since the FWD does not have this adapter opened. + // + + IPX_DEBUG(RECEIVE, ("DestSocket: %lx\n", DestinationSocket)); + +#ifdef SNMP + ++IPX_MIB_ENTRY(Device, SysInDelivers); +#endif SNMP + + if (DestinationSocket != IPXWAN_SOCKET && + Device->ForwarderBound) { + + NDIS_STATUS NdisStatus; + + IPX_DEBUG(RECEIVE, ("Internal packet, sending up to the Forwarder\n")); + + // + // We should pass up the correct Fwd ctx for loopback ptks + // + + // + // Indicate this up only if the adapter the packet came on was opened by the Forwarder + // + if (GET_VALUE(Binding->ReferenceCount) == 2) { + + NdisStatus = (*Device->UpperDrivers[IDENTIFIER_RIP].InternalReceiveHandler) ( + (IsLoopback) ? + VIRTUAL_NET_FORWARDER_CONTEXT : + Binding->FwdAdapterContext, // ForwarderAdapterContext + &DatagramOptions.LocalTarget, // Remote Address + (PUCHAR) IpxHeader, // Lookahead buffer + LookaheadBufferSize - IpxHeaderOffset // Lookahead buffer size + ); + + IPX_DEBUG(RECEIVE, ("Internal packet, Forwarder returned %lx\n", NdisStatus)); + + if (NdisStatus != STATUS_SUCCESS) { + // + // BUGBUG: Log this packet + // + IPX_DEBUG(RECEIVE, ("Internal packet, failed the filter: ipxheader: %lx\n", IpxHeader)); + + // + // The router needs to see Netbios type 20 broadcasts. + // + + if (IsBroadcast && + (IpxHeader->PacketType == 0x14) && + (Binding->ReceiveBroadcast) && + (!fCallProcessDatagram)) { + + goto RipIndication; + } + // else + return NDIS_STATUS_SUCCESS; + } + + } else { + IPX_DEBUG(RECEIVE, ("Internal packet, Forwarder has not opened the adapter yet\n")); + return NDIS_STATUS_SUCCESS; + } + } + + // + // 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. + // + if ((*Device->UpperDrivers[IDENTIFIER_NB].ReceiveHandler)( + (IsLoopback) ? BindingContext : Adapter->NdisBindingHandle, + ReceiveContext, + Binding->FwdAdapterContext, + &DatagramOptions.LocalTarget, + Adapter->MacInfo.MacOptions, + (PUCHAR)IpxHeader, + LookaheadBufferSize - IpxHeaderOffset, + (IsLoopback) ? IpxHeaderOffset+HeaderBufferSize : IpxHeaderOffset, + IpxPacketSize, + pMdl)) { + + CTEAssert(FALSE); + (*pTdiClientCount)++; + } + + Device->ReceiveCompletePending[IDENTIFIER_NB] = TRUE; + } + + // + // The router needs to see Netbios type 20 broadcasts. + // + + if (IsBroadcast && + (IpxHeader->PacketType == 0x14) && + (Binding->ReceiveBroadcast) && + (!fCallProcessDatagram)) { + 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); + } + + if ((*Device->UpperDrivers[IDENTIFIER_SPX].ReceiveHandler)( + (IsLoopback) ? BindingContext : Adapter->NdisBindingHandle, + ReceiveContext, + Binding->FwdAdapterContext, + &DatagramOptions.LocalTarget, + Adapter->MacInfo.MacOptions, + (PUCHAR)IpxHeader, + LookaheadBufferSize - IpxHeaderOffset, + (IsLoopback) ? IpxHeaderOffset+HeaderBufferSize : IpxHeaderOffset, + IpxPacketSize, + pMdl)) { + + CTEAssert(FALSE); + (*pTdiClientCount)++; + } + + 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) && + (!fCallProcessDatagram)) { + 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->ForwarderBound) { + // + // FWD .... + // + + if (DestinationSocket == RIP_SOCKET) { + // + // [FW] Since RIP is now a user app with the same socket #, we inform thru' + // the ProcessDatagram path. And only if the Forwarder is installed. + // + + IsBroadcast = IPX_NODE_BROADCAST(DestinationNode); + fCallProcessDatagram = TRUE; + goto CallProcessDatagram; + } else { + 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 + } + + if (GET_VALUE(Binding->ReferenceCount) == 2) { + if ((*Device->UpperDrivers[IDENTIFIER_RIP].ReceiveHandler)( + (IsLoopback) ? BindingContext : Adapter->NdisBindingHandle, + ReceiveContext, + Binding->FwdAdapterContext, + &DatagramOptions.LocalTarget, + Adapter->MacInfo.MacOptions, + (PUCHAR)IpxHeader, + LookaheadBufferSize - IpxHeaderOffset, + (IsLoopback) ? IpxHeaderOffset+HeaderBufferSize : IpxHeaderOffset, + IpxPacketSize, + pMdl)) { + + (*pTdiClientCount)++; + } + + Device->ReceiveCompletePending[IDENTIFIER_RIP] = TRUE; + } else { + IPX_DEBUG(RECEIVE, ("External packet, Forwarder has not opened the adapter yet\n")); + } + } + } else if (Device->UpperDriverBound[IDENTIFIER_RIP]) { + // + // Old 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 + } + + + if ((*Device->UpperDrivers[IDENTIFIER_RIP].ReceiveHandler)( + (IsLoopback) ? BindingContext : Adapter->NdisBindingHandle, + ReceiveContext, + Binding->FwdAdapterContext, + &DatagramOptions.LocalTarget, + Adapter->MacInfo.MacOptions, + (PUCHAR)IpxHeader, + LookaheadBufferSize - IpxHeaderOffset, + (IsLoopback) ? IpxHeaderOffset+HeaderBufferSize : IpxHeaderOffset, + IpxPacketSize, + pMdl)) { + + CTEAssert(FALSE); + (*pTdiClientCount)++; + } + + 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 SNMP + ++IPX_MIB_ENTRY(Device, SysInReceives); + ++IPX_MIB_ENTRY(Device, SysInHdrErrors); +#endif SNMP + +#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 SNMP + ++IPX_MIB_ENTRY(Device, SysInReceives); + ++IPX_MIB_ENTRY(Device, SysInHdrErrors); +#endif SNMP + +#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 SNMP + ++IPX_MIB_ENTRY(Device, SysInReceives); + ++IPX_MIB_ENTRY(Device, SysInHdrErrors); +#endif SNMP + +#ifdef _PNP_POWER + + IpxDereferenceAdapter(Adapter); + IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1); +#endif +NotValidLoopback: + +#ifdef SNMP + ++IPX_MIB_ENTRY(Device, SysInReceives); + ++IPX_MIB_ENTRY(Device, SysInHdrErrors); +#endif SNMP + +#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; + CTELockHandle OldIrq; + PDEVICE Device = IpxDevice; + PIRP pIrp; + PLIST_ENTRY pLE; + + + // + // 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; + + } + + } + + CTEGetLock(&Device->Lock, &OldIrq); + if (pRtInfo) + { + CTEFreeLock(&Device->Lock, OldIrq); + IpxReferenceRt(pRtInfo, RT_EXTRACT); + while((pLE = ExInterlockedRemoveHeadList(&pRtInfo->CompletedIrps, + &pRtInfo->Lock)) != NULL) + { + pIrp = LIST_ENTRY_TO_REQUEST(pLE); + CTEAssert(pIrp); + IpxPrint0("IpxReceiveComplete: Completing extracted irp\n"); + NTIoComplete(pIrp, (NTSTATUS)-1,(ULONG)-1); + } + IpxDereferenceRt(pRtInfo, RT_EXTRACT); + + } else { + CTEFreeLock(&Device->Lock, OldIrq); + } + + // + // If there are any Ntf completions, do them. These ntf completions + // are only if we discovered the address of one of our adapters. + // + + while((pLE = ExInterlockedRemoveHeadList(&Device->NicNtfComplQueue, &Device ->Lock)) != NULL) + { + pIrp = LIST_ENTRY_TO_REQUEST(pLE); + CTEAssert(pIrp); + IpxPrint0("IpxReceiveComplete: Completing Nic Ntf irp\n"); + NTIoComplete(pIrp, (NTSTATUS)-1, (ULONG)-1); + IpxDereferenceDevice (Device, DREF_NIC_NOTIFY); + } + +} /* 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; + + } + + Binding->fInfoIndicated = FALSE; + if ((p = ExInterlockedRemoveHeadList( + &Device->NicNtfQueue, + &Device->Lock)) != NULL) + { + PREQUEST Request; + + Request = LIST_ENTRY_TO_REQUEST(p); + + DbgPrint("IpxStatus: Got address of binding\n"); + Status = GetNewNics(Device, Request, FALSE, NULL, 0, TRUE); + + // + // If not success, we don't queue back the irp. It has + // already been queued or completed + // + if (Status != STATUS_SUCCESS) + { + DbgPrint("New address Irp screw up. Status = (%lx)\n", + Status); + } + else + { + KIRQL OldIrq; + // + // Status is SUCCESS + // + IoAcquireCancelSpinLock(&OldIrq); + IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL); + IoReleaseCancelSpinLock(OldIrq); + REQUEST_STATUS(Request) = Status; + ExInterlockedInsertTailList(&Device->NicNtfComplQueue,REQUEST_LINKAGE(Request), &Device->Lock); + } + + } + + 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 IpxReceiveIndicationCommon(), + +--*/ +{ + 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 = IpxReceiveIndicationCommon ( + 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; + } + } + +#ifdef SNMP + *(UNALIGNED ULONG *)(IPX_MIB_ENTRY(Device, SysNetNumber)) = Device->SourceAddress.NetworkAddress; + + *(UNALIGNED ULONG *)(IPX_MIB_ENTRY(Device, SysNode)) = + *(UNALIGNED ULONG *)(Device->SourceAddress.NodeAddress); + *(UNALIGNED USHORT *)(IPX_MIB_ENTRY(Device, SysNode)+4) = + *(UNALIGNED USHORT *)(Device->SourceAddress.NodeAddress+4); +#endif + 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; + } + + // + // DeRegister this address with the TDI clients. + // + + // + // 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); + + IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1); + + CTEAssert(Binding->TdiRegistrationHandle); + + if ((ntStatus = TdiDeregisterNetAddress(Binding->TdiRegistrationHandle)) != STATUS_SUCCESS) { + IPX_DEBUG(PNP, ("TdiDeRegisterNetAddress failed: %lx", ntStatus)); + } + + // + // 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); + + IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1); + + // + // 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)); + } + + // + // Free the demand dial binding place holder. + // + IpxUnBindFromAdapter(NIC_ID_TO_BINDING(IpxDevice, DEMAND_DIAL_ADAPTER_CONTEXT)); + + // + // 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; + + // + // Free the loopback binding place holder. + // + IpxUnBindFromAdapter(NIC_ID_TO_BINDING(IpxDevice, LOOPBACK_NIC_ID)); + + // + // 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; + PBINDING WanBinding=NIC_ID_TO_BINDING_NO_ILOCK(Device, Device->HighestLanNicId+1); + + if (WanBinding) { + --WanBinding->Adapter->LastWanNicId; + --WanBinding->Adapter->FirstWanNicId; + } + + // + // 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: + + +--*/ +{ +} /* IpxTranslate */ + +#endif _PNP_POWER + + diff --git a/private/ntos/tdi/isn/ipx/internal.c b/private/ntos/tdi/isn/ipx/internal.c new file mode 100644 index 000000000..a0721679a --- /dev/null +++ b/private/ntos/tdi/isn/ipx/internal.c @@ -0,0 +1,1342 @@ +/*++ + +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 + BOOLEAN fFwdBindAttempt = FALSE; +#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 Forwarder gives us 2 (ISN_VERSION). +// + if (BindInput->Identifier == IDENTIFIER_RIP) { + if (BindInput->Version == ISN_VERSION) { + fFwdBindAttempt = TRUE; + } else { + CTEAssert(!Device->ForwarderBound); + + 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; + + if (!fFwdBindAttempt) { + 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; + + // + // [BUGBUGZZ] remove this... + // + BindRipOutput->IncrementWanInactivityHandler = IpxInternalIncrementWanInactivity; + BindRipOutput->QueryWanInactivityHandler = IpxInternalQueryWanInactivity; + } else { + // + // [FW] New routines provided for the Forwarder + // + BindRipOutput->OpenAdapterHandler = IpxOpenAdapter; + BindRipOutput->CloseAdapterHandler = IpxCloseAdapter; + BindRipOutput->InternalSendCompleteHandler = IpxInternalSendComplete; + } + + 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->ForwarderBound = fFwdBindAttempt; + + 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; + } + + // + // [FW] If RIP is unbinding, restart the long timer + // Also, set the RipResponder flag if virutal net configured + + // + // BUGBUG: Deref all bindings that RIP did not close + // + if (Identifier == IDENTIFIER_RIP && + Device->ForwarderBound) { + UINT i; + + Device->ForwarderBound = FALSE; + + // + // [FW] Walk the binding list, to deref all bindings not closed by + // the forwarder before it unbound from us. + // + { + ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId); + + for (i = 1; i <= Index; i++) { + PBINDING Binding = NIC_ID_TO_BINDING(Device, i); + + if (Binding && (Binding->FwdAdapterContext != 0)) { + IpxDereferenceBinding(Binding, BREF_FWDOPEN); + } + } + } + + if (Device->VirtualNetwork) { + Device->RipResponder = TRUE; + } + + // + // Start the timer which updates the RIP database + // periodically. + // + + IpxReferenceDevice (Device, DREF_LONG_TIMER); + + CTEStartTimer( + &Device->RipLongTimer, + 10000, + RipLongTimeout, + (PVOID)Device); + + } + + 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 + + // + // [FW] Call the Forwarder's FindRoute if installed + // + + if (Device->ForwarderBound) { + // IPX_ROUTE_ENTRY routeEntry; + + Status = (*Device->UpperDrivers[IDENTIFIER_RIP].FindRouteHandler) ( + FindRouteRequest->Network, + FindRouteRequest->Node, + FindRouteRequest); + + if (Status != STATUS_SUCCESS) { + IPX_DEBUG (RIP, ("RouteHandler returned: %lx\n", Status)); + } else { + +#if DBG + // + // If a demand-dial NIC was returned, we should have a WAN adapter. In PnP we can check this + // by making sure that Device->HighestLanNicId < Device->HighestExternalNicId. + // + if (FindRouteRequest->LocalTarget.NicId == DEMAND_DIAL_ADAPTER_CONTEXT) { + CTEAssert(Device->HighestLanNicId < Device->HighestExternalNicId); + } +#endif + + IPX_DEBUG(RIP, ("FindRoute for %02x-%02x-%02x-%02x-%02x-%02x returned %lx", + FindRouteRequest->LocalTarget.MacAddress[0], + FindRouteRequest->LocalTarget.MacAddress[1], + FindRouteRequest->LocalTarget.MacAddress[2], + FindRouteRequest->LocalTarget.MacAddress[3], + FindRouteRequest->LocalTarget.MacAddress[4], + FindRouteRequest->LocalTarget.MacAddress[5], + Status)); + + } + + } else { + // + // 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/isn/ipx/ipx.rc b/private/ntos/tdi/isn/ipx/ipx.rc new file mode 100644 index 000000000..3c403b684 --- /dev/null +++ b/private/ntos/tdi/isn/ipx/ipx.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 "ISN IPX Protocol Driver" +#define VER_INTERNALNAME_STR "isnipx.sys" +#define VER_ORIGINALFILENAME_STR "isnipx.sys" + +#include "common.ver" + diff --git a/private/ntos/tdi/isn/ipx/ipxprocs.h b/private/ntos/tdi/isn/ipx/ipxprocs.h new file mode 100644 index 000000000..0b43029db --- /dev/null +++ b/private/ntos/tdi/isn/ipx/ipxprocs.h @@ -0,0 +1,1675 @@ +/*++ + +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, IpxReceiveIndicationCommon + + 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 STEFAN_DBG +//#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); + +#define IpxReferenceRt(_Rt, _Type) \ + (VOID)IPX_ADD_ULONG ( \ + &(_Rt)->RefTypes[_Type], \ + 1, \ + &IpxGlobalInterlock); \ + IpxRefRt (_Rt) + +#define IpxDereferenceRt(_Rt, _Type) \ + (VOID)IPX_ADD_ULONG ( \ + &(_Rt)->RefTypes[_Type], \ + (ULONG)-1, \ + &IpxGlobalInterlock); \ + IpxDerefRt (_Rt) + +#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) + +#define IpxReferenceRt(_Rt, _Type) \ + InterlockedIncrement(&(_Rt)->ReferenceCount) + +#define IpxDereferenceRt(_Rt, _Type) \ + IpxDerefRt (_Rt) + +#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 + ); + +VOID +IpxAbortNtfChanges( + IN PVOID ControlChannelContext + ); + +NTSTATUS +IpxIndicateLineUp( + IN PDEVICE Device, + IN USHORT NicId, + IN ULONG Network, + IN UCHAR LocalNode[6], + IN UCHAR RemoteNode[6] + ); + +// +// 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 + +// +// [FW] New functions added for Forwarder support +// + +NTSTATUS +IpxOpenAdapter( + IN NIC_HANDLE AdapterIndex, + IN ULONG FwdAdapterContext, + OUT PNIC_HANDLE IpxAdapterContext + ); + +NTSTATUS +IpxCloseAdapter( + IN NIC_HANDLE IpxAdapterContext + ); + +// +// 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 + ); + +NTSTATUS +IpxOpenAddressM( + IN PDEVICE Device, + IN PREQUEST Request, + IN ULONG Index + ); + +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 +IpxReceiveIndicationCommon( + 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 + ); + + +// +// Routines in rt.c +// + + +NTSTATUS +GetNewNics( + PDEVICE, + PREQUEST, + BOOLEAN, + PNWLINK_ACTION, + UINT, + BOOLEAN OldIrp +); + +NTSTATUS +OpenRtAddress( + IN PDEVICE Device, + IN PIRP Request + ); + +NTSTATUS +CloseRtAddress( + IN PDEVICE pDevice, + IN PIRP pIrp + ); + +NTSTATUS +CleanupRtAddress( + IN PDEVICE pDevice, + IN PIRP pIrp + ); + +NTSTATUS +SendIrpFromRt ( + IN PDEVICE pDevice, + IN PIRP pIrp + ); + +NTSTATUS +RcvIrpFromRt ( + IN PDEVICE pDevice, + IN PIRP pIrp + ); +NTSTATUS +PassDgToRt ( + IN PDEVICE pDevice, + IN PIPX_DATAGRAM_OPTIONS2 pContext, + IN ULONG Index, + IN VOID UNALIGNED *pDgrm, + IN ULONG uNumBytes + ); + +NTSTATUS +NTCheckSetCancelRoutine( + IN PIRP pIrp, + IN PVOID CancelRoutine, + IN PDEVICE pDevice + ); + + +VOID +NTIoComplete( + IN PIRP pIrp, + IN NTSTATUS Status, + IN ULONG SentLength); + +VOID +IpxRefRt( + PRT_INFO pRt); + +VOID +IpxDerefRt( + PRT_INFO pRt); + +VOID +IpxDestroyRt( + PRT_INFO pRt); + +#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 + ); + + +// +// [FW] InternalSendCompletion from Forwarder +// + +// [FW] Added length here +VOID +IpxInternalSendComplete( + IN PIPX_LOCAL_TARGET LocalTarget, + IN PNDIS_PACKET Packet, + IN ULONG PacketLength, + IN NTSTATUS Status + ); diff --git a/private/ntos/tdi/isn/ipx/ipxtypes.h b/private/ntos/tdi/isn/ipx/ipxtypes.h new file mode 100644 index 000000000..a353a65b4 --- /dev/null +++ b/private/ntos/tdi/isn/ipx/ipxtypes.h @@ -0,0 +1,2144 @@ +/*++ + +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) + +--*/ + +#ifdef SNMP +#include <hipxmib.h> +#endif SNMP + +// +// 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). +// + +// +// NicId cast to SHORT so DemandDial Nic (0xffff) maps to -1. +// +#define NIC_ID_TO_BINDING(_device, _nicid) \ + ((PBINDING)GET_VALUE( ((PBIND_ARRAY_ELEM) GET_VALUE( (_device)->Bindings) )[(SHORT)_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) + +#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 + PVOID pContext; + ULONG Index; +} 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 + ); + +// +// These are the states a WAN line can be in. +// +typedef enum _WAN_LINE_STATE{ + LINE_DOWN, + LINE_UP, + LINE_CONFIG +} WAN_LINE_STATE, *PWAN_LINE_STATE; + +#define BREF_BOUND 1 +#ifdef _PNP_POWER +#define BREF_DEVICE_ACCESS 2 +#define BREF_ADAPTER_ACCESS 3 +#endif + +// +// [FW] New flag to indicate the KFWD opened an adapter +// +#define BREF_FWDOPEN 4 + +#define BREF_TOTAL 5 + +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; + WAN_LINE_STATE 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; + }; + + ULONG FwdAdapterContext; // [FW] + + ULONG InterfaceIndex; // [FW] + + ULONG ConnectionId; // [FW] used to match TimeSinceLastActivity IOCtls + + ULONG IpxwanConfigRequired; // [FW] used to indicate to the adapter dll whether the line up is for Router or IpxWan. + + BOOLEAN fInfoIndicated; //Info indicated to user app + +#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_NIC_NOTIFY 10 + +#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 + + // + // [FW] To keep track of the number of WAN lines currently UP + // + USHORT UpWanLineCount; + + 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; + + // + // Action requests from forwarder waiting for the NIC change notification + // + LIST_ENTRY NicNtfQueue; + LIST_ENTRY NicNtfComplQueue; + + // + // 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. + + // + // [FW] Kicks in every minute if at least one WAN line is up. Increments + // the WAN incativity counter on all UP WAN bindings. + // + CTETimer WanInactivityTimer; + + // + // 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 ForwarderBound; + + 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 + +#ifdef SNMP + NOVIPXMIB_BASE MibBase; +#endif SNMP + + // + // 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 + +#ifdef SNMP +#define IPX_MIB_ENTRY(Device, Variable) ((Device)->MibBase.Variable) +#endif SNMP + +// +// 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 + + ULONG Index; + BOOLEAN RtAdd; + +} 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); + +//#define USER_BUFFER_OFFSET FIELD_OFFSET(RTRCV_BUFFER, DgrmLength) +#define USER_BUFFER_OFFSET FIELD_OFFSET(RTRCV_BUFFER, Options) +// +// This structure keeps track of the WINS recv Irp and any datagram +// queued to go up to WINS (name service datagrams) +// +#define REFRT_TOTAL 8 + +#define RT_CREATE 0 +#define RT_CLEANUP 1 +#define RT_CLOSE 2 +#define RT_SEND 3 +#define RT_RCV 4 +#define RT_IRPIN 5 +#define RT_BUFF 6 +#define RT_EXTRACT 7 + + +#define RT_EMPTY 0 +#define RT_OPEN 1 +#define RT_CLOSING 2 +#define RT_CLOSED 3 + + +#define RT_IRP_MAX 1000 +#define RT_BUFF_MAX 1000 + +// +// Max. memory allocated for queueing buffers to be received by the RT +// manager +// +#define RT_MAX_BUFF_MEM 65000 //bytes + +// +// Get Index corresponding to the address object opened by RT. BTW We +// can not have more than one Address file (client) for a RT address. +// +#define RT_ADDRESS_INDEX(_pIrp) (((ULONG)REQUEST_OPEN_TYPE(_pIrp)) - ROUTER_ADDRESS_FILE) + +typedef struct _RT_IRP { + PADDRESS_FILE AddressFile; + LIST_ENTRY RcvIrpList; + ULONG NoOfRcvIrps; + LIST_ENTRY RcvList; // linked list of Datagrams Q'd to rcv + ULONG NoOfRcvBuffs; // linked list of Datagrams Q'd to rcv + BOOLEAN State; + } RT_IRP, *PRT_IRP; + +typedef struct +{ +#if DBG + ULONG RefTypes[REFRT_TOTAL]; +#endif + + CSHORT Type; // type of this structure + USHORT Size; // size of this structure + +#if DBG + UCHAR Signature[4]; // contains "IBI1" +#endif + LIST_ENTRY CompletedIrps; // linked list of Datagrams Q'd to rcv + LIST_ENTRY HolderIrpsList; // Holds Irps + CTELock Lock; + ULONG ReferenceCount; + ULONG RcvMemoryAllocated; // bytes buffered so far + ULONG RcvMemoryMax; // max # of bytes to buffer on Rcv + PDEVICE pDevice; // the devicecontext used by wins + UCHAR NoOfAdds; + RT_IRP AddFl[IPX_RT_MAX_ADDRESSES]; +} RT_INFO, *PRT_INFO; + +// +// RT Rcv Buffer structure +// +typedef struct +{ + LIST_ENTRY Linkage; + ULONG TotalAllocSize; + ULONG UserBufferLengthToPass; + IPX_DATAGRAM_OPTIONS2 Options; + +} RTRCV_BUFFER, *PRTRCV_BUFFER; + +#define OFFSET_OPTIONS_IN_RCVBUFF FIELD_OFFSET(RTRCV_BUFFER, Options) +#define OFFSET_PKT_IN_RCVBUFF (FIELD_OFFSET(RTRCV_BUFFER, Options) + FIELD_OFFSET(IPX_DATAGRAM_OPTIONS2, Data)) +#define OFFSET_PKT_IN_OPTIONS FIELD_OFFSET(IPX_DATAGRAM_OPTIONS2, Data) + +extern PRT_INFO pRtInfo; + +// +// We keep the demand-dial binding at the beginning of the binding array; this keeps +// track of the number of extra bindings that we have. +// Currently 1 (for demand-dial), we could also keep other bindings like the loopback +// binding, etc. +// +#define DEMAND_DIAL_NIC_ID DEMAND_DIAL_ADAPTER_CONTEXT +#define LOOPBACK_NIC_ID VIRTUAL_NET_ADAPTER_CONTEXT + +#define EXTRA_BINDINGS 2 diff --git a/private/ntos/tdi/isn/ipx/isnipx.h b/private/ntos/tdi/isn/ipx/isnipx.h new file mode 100644 index 000000000..ae48d1449 --- /dev/null +++ b/private/ntos/tdi/isn/ipx/isnipx.h @@ -0,0 +1,554 @@ +/*++ + +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_RT_SIGNATURE 0x1406 + +#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)) + + +#define OPEN_REQUEST_EA_LENGTH(_Request) \ + (((IoGetCurrentIrpStackLocation(_Request))->Parameters.DeviceIoControl.InputBufferLength)) + +#define OPEN_REQUEST_RCV_LEN(_Request) \ + (((IoGetCurrentIrpStackLocation(_Request))->Parameters.DeviceIoControl.OutputBufferLength)) + +#define REQUEST_SPECIAL_RECV(_Request) \ + (((IoGetCurrentIrpStackLocation(_Request))->Parameters.DeviceIoControl.IoControlCode) == MIPX_RCV_DATAGRAM) + +#define REQUEST_SPECIAL_SEND(_Request) \ + (((IoGetCurrentIrpStackLocation(_Request))->Parameters.DeviceIoControl.IoControlCode) == MIPX_SEND_DATAGRAM) + + +#define REQUEST_CODE(_Request) \ + ((IoGetCurrentIrpStackLocation(_Request))->Parameters.DeviceIoControl.IoControlCode) + +// +// The following value does not clash with TDI_TRANSPORT_ADDRESS_FILE value of +// 0x1 +// +#define ROUTER_ADDRESS_FILE 0x4 + +// +// 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/isn/ipx/loopback.c b/private/ntos/tdi/isn/ipx/loopback.c new file mode 100644 index 000000000..be44bae5b --- /dev/null +++ b/private/ntos/tdi/isn/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/isn/ipx/mac.c b/private/ntos/tdi/isn/ipx/mac.c new file mode 100644 index 000000000..a8f2e3b5d --- /dev/null +++ b/private/ntos/tdi/isn/ipx/mac.c @@ -0,0 +1,3940 @@ +/*++ + +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; + PUCHAR IpxHeader; + UINT TempHeaderBufferLength; + PDEVICE Device = IpxDevice; + PIPX_HEADER TempHeader; + NTSTATUS ret; + BOOLEAN fIterate=FALSE; + + // + // Figure out the IpxHeader - it is always at the top of the second MDL. + // + NdisQueryPacket (Packet, NULL, NULL, &HeaderBuffer, NULL); + NdisQueryBuffer (NDIS_BUFFER_LINKAGE(HeaderBuffer), &IpxHeader, &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 ITERATIVE_NIC_ID, then this could be a send + // over all NICs in the case of NB/SPX. + // + if (NIC_FROM_LOCAL_TARGET(LocalTarget) == (USHORT)ITERATIVE_NIC_ID) { + CTEAssert(Reserved->Identifier == IDENTIFIER_NB || + Reserved->Identifier == IDENTIFIER_SPX); + // + // Start with 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; + fIterate = TRUE; + } + + // + // If the Forwarder is installed, send the packet out for filtering + // + if (Device->ForwarderBound) { + ULONG FwdAdapterContext = INVALID_CONTEXT_VALUE; + PBINDING Binding; + + // + // Figure out the FwdAdapterContext; if the NicId is 0 + // then no NicId is specified (since we never return a + // NicId of 0 in a FindRoute). + // + + // + // We need to fix the following problems with respect to type 20 iterative bcasts : + // 1. IPX will not bcast on a down WAN line (thus the Fwd cannot bring up a demand-dial line). + // 2. IPX bcasts on every Nic (since it is not any wiser about selecting relevant Nics). + // 3. If the first bcast fails, the whole send fails. + // + // All the above (except 3.) occur because the Fwd knows more about the Nics than IPX does; hence + // we let the Fwd decide which lines he wants to send a bcast on. Thus, for Type20 pkts, we pass + // up the invalid Fwd context so the Fwd decides the next Nic to send on. + // + if (!((((PIPX_HEADER)IpxHeader)->PacketType == 0x14) && fIterate) && + Reserved->LocalTarget.NicId && + (Binding = NIC_ID_TO_BINDING(Device, Reserved->LocalTarget.NicId)) && + (GET_VALUE(Binding->ReferenceCount) == 2)) { + // + // If proper NicId specified, and the adapter has been opened by + // the forwarder, set the FwdAdapterContext. + // + FwdAdapterContext = Binding->FwdAdapterContext; + } +#if DBG + else { + if (((PIPX_HEADER)IpxHeader)->PacketType == 0x14) { + IPX_DEBUG(SEND, ("SendComplete: IpxHeader has Type20: %lx\n", IpxHeader)); + } + } +#endif + + // + // Call the InternalSend to filter the packet and get to know + // the correct adapter context + // + ret = (*Device->UpperDrivers[IDENTIFIER_RIP].InternalSendHandler)( + &Reserved->LocalTarget, + FwdAdapterContext, + Packet, + IpxHeader, + IpxHeader+sizeof(IPX_HEADER), // the data starts after the IPX Header. + PacketLength, + fIterate); + + if (ret == STATUS_SUCCESS) { + // + // The adapter could have gone away and we have indicated to the Forwarder + // but the Forwarder has not yet closed the adapter. + // [ZZ] adapters do not go away now. + // + // BUGBUG: what if the binding is NULL here? Can we trust the Forwarder to + // give us a non-NULL binding? + // + + if (GET_VALUE(NIC_ID_TO_BINDING(Device, Reserved->LocalTarget.NicId)->ReferenceCount) == 1) { + IPX_DEBUG(SEND, ("IPX: SendFramePreFwd: FWD returned SUCCESS, Ref count is 1\n")); + return NDIS_STATUS_SUCCESS; + } else { + + // + // Fill up the changed LocalTarget for the client except in the ITERATE case. + // + if (!fIterate) { + *LocalTarget = Reserved->LocalTarget; + } + + IPX_DEBUG(SEND, ("IPX: SendFramePreFwd: FWD returned SUCCESS, sending out on wire\n")); + goto SendPkt; + } + } else if (ret == STATUS_PENDING) { + // + // LocalTarget will get filled up in InternalSendComplete + // + IPX_DEBUG(SEND, ("SendFramePreFwd: FWD returned PENDING\n")); + return NDIS_STATUS_PENDING; + } else if (ret == STATUS_DROP_SILENTLY) { + // + // This was a keepalive which the router is spoofing. Drop it silently. + // + IPX_DEBUG(SEND, ("IPX: SendFramePreFwd: FWD returned STATUS_DROP_SILENTLY - dropping pkt.\n")); + return NDIS_STATUS_SUCCESS; + } + + // + // else DISCARD - this means that either the packet failed the send + // or that the preferred NicId was not good. + // + return STATUS_NETWORK_UNREACHABLE; + + } else { + +SendPkt: + if (NIC_FROM_LOCAL_TARGET(LocalTarget) == (USHORT)LOOPBACK_NIC_ID) { + // + // 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); + + } +} +#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) + +#ifdef SNMP +// +// This should not include the forwarded packets; on host side, it is 0. +// On router, the AdvSysForwPackets are subtracted in the sub-agent code. +// + ++IPX_MIB_ENTRY(Device, SysOutRequests); +#endif SNMP + + // + // 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. + // +#ifdef SNMP + ++IPX_MIB_ENTRY(Device, SysOutMalformedRequests); +#endif SNMP + 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 +#ifdef SNMP + ++IPX_MIB_ENTRY(Device, SysOutMalformedRequests); +#endif SNMP + 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 + } + + } + } + + // + // [STEFANS]: Replace all source addresses with the virtualnet# to allow for sends + // on 0 network number WAN lines (typically between routers). + // + if (Device->VirtualNetwork) { + *(UNALIGNED ULONG *)TempHeader->SourceNetwork = Device->SourceAddress.NetworkAddress; + RtlCopyMemory (TempHeader->SourceNode, Device->SourceAddress.NodeAddress, 6); + } + + } 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: + + // + // [FW] This will allow both LINE_UP and LINE_CONFIG states + // + 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 +#ifdef SNMP + ++IPX_MIB_ENTRY(Device, SysOutDiscards); +#endif SNMP + 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. + // + + // + // [FW] do this only if the forwarder is not bound + // + if (!Device->ForwarderBound && + (!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); + + + // + // In order for loopback to work properly, we need to put the local MAC address for locally destined + // pkts so NdisWAN can loop them back. + // + if (IPX_NODE_EQUAL(LocalTarget->MacAddress, Binding->LocalAddress.NodeAddress)) { + RtlCopyMemory (Header, Binding->LocalMacAddress.Address, 6); + } else { + 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) ); +#if DBG + if ((Reserved->Identifier == IDENTIFIER_RIP) && + (LastBufferLength == 1500)) { + DbgPrint("Packet: %lx\n", Packet); + DbgBreakPoint(); + } +#endif DBG + } + + 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; + + 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 + } + + // + // Create space for the source routing information + // +#if BACK_FILL + BACK_FILL_HEADER(Header, Reserved, 17+SourceRoutingLength, Packet); +#endif BACK_FILL + + 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; + + 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); + } + } + } + + // + // Create space for sourcerouting headers + // +#if BACK_FILL + BACK_FILL_HEADER(Header, Reserved, 22+SourceRoutingLength, Packet); +#endif BACK_FILL + + 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 + + // + // [FW] This will allow both LINE_UP and LINE_CONFIG states + // + 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 + + // + // In order for loopback to work properly, we need to put the local MAC address for locally destined + // pkts so NdisWAN can loop them back. + // + if (IPX_NODE_EQUAL(LocalTarget->MacAddress, Binding->LocalAddress.NodeAddress)) { + RtlCopyMemory (Header, Binding->LocalMacAddress.Address, 6); + } else { + RtlCopyMemory (Header, Binding->RemoteMacAddress.Address, 6); + } + // 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/isn/ipx/mac.h b/private/ntos/tdi/isn/ipx/mac.h new file mode 100644 index 000000000..a88e77ecd --- /dev/null +++ b/private/ntos/tdi/isn/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/isn/ipx/mp/makefile b/private/ntos/tdi/isn/ipx/mp/makefile new file mode 100644 index 000000000..6ee4f43fa --- /dev/null +++ b/private/ntos/tdi/isn/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/isn/ipx/mp/nwlnkipx.prf b/private/ntos/tdi/isn/ipx/mp/nwlnkipx.prf new file mode 100644 index 000000000..0c4359235 --- /dev/null +++ b/private/ntos/tdi/isn/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/isn/ipx/mp/sources b/private/ntos/tdi/isn/ipx/mp/sources new file mode 100644 index 000000000..dc48d81bb --- /dev/null +++ b/private/ntos/tdi/isn/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/isn/ipx/ndis.c b/private/ntos/tdi/isn/ipx/ndis.c new file mode 100644 index 000000000..db1d41e13 --- /dev/null +++ b/private/ntos/tdi/isn/ipx/ndis.c @@ -0,0 +1,2381 @@ +/*++ + +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) + IPX_DEFINE_LOCK_HANDLE (OldIrq) + 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. + // + // [FW] Binding->LineUp = TRUE; + Binding->LineUp = LINE_UP; + + 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); + + // + // [FW] No need to update these if this flag is on since these values will be + // provided with IPX_WAN_CONFIG_DONE ioctl; instead we zero out the fields so that + // IPXWAN packets have proper source addresses. + // + if (Device->ForwarderBound && + Configuration->IpxwanConfigRequired) { + Binding->LocalAddress.NetworkAddress = 0; + RtlZeroMemory (Binding->LocalAddress.NodeAddress, 6); + + } else { + + // + // 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")); + // [FW] Binding->LineUp = FALSE; + Binding->LineUp = LINE_DOWN; + + #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); + + // + // 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); + } + } + + // + // 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); + + // + // Reset this since the line just came up. + // + + Binding->WanInactivityCounter = 0; + + // + // [FW] Update the InterfaceIndex and ConnectionId. + // + Binding->InterfaceIndex = Configuration->InterfaceIndex; + Binding->ConnectionId = Configuration->ConnectionId; + Binding->IpxwanConfigRequired = Configuration->IpxwanConfigRequired; + + // + // [FW] We need to keep track of WAN inactivity counters ourselves. + // Every minute, the wan inactivity counters are incremented for all + // UP WAN lines. + // + IPX_GET_LOCK (&Device->Lock, &LockHandle); + if (Device->UpWanLineCount == 0) { +/* + // + // [BUGBUGZZ] remove this... + // + CTEStartTimer( + &Device->WanInactivityTimer, + 60000, // 1 minute + IpxInternalIncrementWanInactivity, + (PVOID)Device); +*/ + } + + Device->UpWanLineCount++; + IPX_FREE_LOCK (&Device->Lock, LockHandle); + } + + 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); + + // + // [FW] If the IpxwanConfigRequired flag is true, we don't inform + // the upper layers until IPXWAN sends down the ioctl to do so. + // + // Inform IpxWan only if this is not an Update; it will be an update in + // the case of multilink. In fact, do not access the Configuration param in + // case UpdateLineUp is TRUE. + // + if (!UpdateLineUp && + Configuration->IpxwanConfigRequired) { + + IPX_DEBUG(WAN, ("IPXWAN configuration required on LineUp: %lx\n", LineUp)); + CTEAssert(!UpdateLineUp); + Binding->LineUp = LINE_CONFIG; + goto InformIpxWan; + } + +#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) + + Binding->IsnInformed[IDENTIFIER_NB] = TRUE; + + 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. + // Give lineup to FWD only if it opened this adapter first. + // + if (Device->UpperDriverBound[IDENTIFIER_RIP]) { + + // + // Line status, after lineup. + // + if (UpdateLineUp) { + // + // was the lineup given earlier? if not, then dont send this up. + // + if (Binding->IsnInformed[IDENTIFIER_RIP]) { + CTEAssert(Binding->FwdAdapterContext); + + (*Device->UpperDrivers[IDENTIFIER_RIP].LineUpHandler)( + Binding->NicId, + &LineInfo, + NdisMediumWan, + NULL); + } + + } else { + Binding->IsnInformed[IDENTIFIER_RIP] = TRUE; + (*Device->UpperDrivers[IDENTIFIER_RIP].LineUpHandler)( + Binding->NicId, + &LineInfo, + NdisMediumWan, + 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); + } + +InformIpxWan: + Binding->fInfoIndicated = FALSE; + if ((p = ExInterlockedRemoveHeadList( + &Device->NicNtfQueue, + &Device->Lock)) != NULL) + { + Request = LIST_ENTRY_TO_REQUEST(p); + + DbgPrint("IpxStatus: WAN LINE UP\n"); + Status = GetNewNics(Device, Request, FALSE, NULL, 0, FALSE); + if (Status != STATUS_SUCCESS) + { + DbgPrint("WAN Line up screw up\n"); + } + else + { + IoAcquireCancelSpinLock(&OldIrq); + IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL); + IoReleaseCancelSpinLock(OldIrq); + + REQUEST_STATUS(Request) = Status; + IpxCompleteRequest (Request); + IpxFreeRequest (Device, Request); + IpxDereferenceDevice (Device, DREF_NIC_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 + + // [FW] Binding->LineUp = FALSE; + Binding->LineUp = LINE_DOWN; + + // + // 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. + // + + // + // [FW] if this was a line on which IPXWAN config was happening, then we dont do this. + // + if (!Binding->IpxwanConfigRequired && + !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); + + } + + // + // [FW] If this was the last UpWanLine, cancel the inactivity timer. + // + /* + IPX_GET_LOCK (&Device->Lock, &LockHandle); + if (--Device->UpWanLineCount == 0) { + if (!CTEStopTimer (&IpxDevice->WanInactivityTimer)) { + DbgPrint("Could not stop the WanInactivityTimer\n"); + DbgBreakPoint(); + } + } + IPX_FREE_LOCK (&Device->Lock, LockHandle); + */ + + // + // If this was a line on which IPXWAN config was going on, then we need to tell only the + // IPXWAN layer that the line went down since none of the other clients were informed of + // the line up in the first place. + // + if (Binding->IpxwanConfigRequired) { + goto InformIpxWan1; + } + + // + // 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); + } + } + + // + // Indicate to the Fwd only if it opened this adapter first. + // + if (Device->UpperDriverBound[IDENTIFIER_RIP] && + (!Device->ForwarderBound || Binding->FwdAdapterContext)) { + + (*Device->UpperDrivers[IDENTIFIER_RIP].LineDownHandler)( + Binding->NicId, + Binding->FwdAdapterContext); + + CTEAssert(Binding->IsnInformed[IDENTIFIER_RIP]); + + Binding->IsnInformed[IDENTIFIER_RIP] = FALSE; + } +#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); + } + +InformIpxWan1: + Binding->fInfoIndicated = FALSE; + if ((p = ExInterlockedRemoveHeadList( + &Device->NicNtfQueue, + &Device->Lock)) != NULL) + { + + Request = LIST_ENTRY_TO_REQUEST(p); + DbgPrint("IpxStatus: WAN LINE DOWN\n"); + + Status = GetNewNics(Device, Request, FALSE, NULL, 0, FALSE); + if (Status != STATUS_SUCCESS) + { + DbgPrint("WAN Line down screw up\n"); + } + else + { + IoAcquireCancelSpinLock(&OldIrq); + IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL); + IoReleaseCancelSpinLock(OldIrq); + + REQUEST_STATUS(Request) = Status; + IpxCompleteRequest (Request); + IpxFreeRequest (Device, Request); //noop + IpxDereferenceDevice (Device, DREF_NIC_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/isn/ipx/nwlnkipx.ini b/private/ntos/tdi/isn/ipx/nwlnkipx.ini new file mode 100644 index 000000000..416f0c6b7 --- /dev/null +++ b/private/ntos/tdi/isn/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/isn/ipx/nwlnkipx.rc b/private/ntos/tdi/isn/ipx/nwlnkipx.rc new file mode 100644 index 000000000..0f437a15d --- /dev/null +++ b/private/ntos/tdi/isn/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/isn/ipx/packet.c b/private/ntos/tdi/isn/ipx/packet.c new file mode 100644 index 000000000..f70154b03 --- /dev/null +++ b/private/ntos/tdi/isn/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/isn/ipx/precomp.h b/private/ntos/tdi/isn/ipx/precomp.h new file mode 100644 index 000000000..21775002a --- /dev/null +++ b/private/ntos/tdi/isn/ipx/precomp.h @@ -0,0 +1,45 @@ +/*++ + +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 +#define _HIPX_SUBAGNT + +#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/isn/ipx/query.c b/private/ntos/tdi/isn/ipx/query.c new file mode 100644 index 000000000..28b38df5c --- /dev/null +++ b/private/ntos/tdi/isn/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/isn/ipx/receive.c b/private/ntos/tdi/isn/ipx/receive.c new file mode 100644 index 000000000..6bed71e3c --- /dev/null +++ b/private/ntos/tdi/isn/ipx/receive.c @@ -0,0 +1,493 @@ +/*++ + +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->pContext) { + + 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; + + } + + } else { + //IpxPrint0("IpxTransferDataComplete: Calling PassDgToRt\n"); + //ByteOffset = sizeof(IPX_HEADER); + ByteOffset = 0; + PassDgToRt(IpxDevice, Reserved->pContext, Reserved->Index, + &Reserved->ReceiveBuffer->Data[ByteOffset], + BytesTransferred); + + // + // Free the memory allocated for options. + // + IpxFreeMemory(Reserved->pContext, sizeof(IPX_DATAGRAM_OPTIONS2), + MEMORY_PACKET, "RT OPTIONS"); + // + // Now free the receive buffer back. + // + + IPX_PUSH_ENTRY_LIST( + &Adapter->ReceiveBufferList, + &Reserved->ReceiveBuffer->PoolLinkage, + Adapter->DeviceLock); + + 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); + + } + + if (!Reserved->pContext) { + // + // 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/isn/ipx/rip.c b/private/ntos/tdi/isn/ipx/rip.c new file mode 100644 index 000000000..950949ca0 --- /dev/null +++ b/private/ntos/tdi/isn/ipx/rip.c @@ -0,0 +1,2700 @@ +/*++ + + +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, LOOPBACK_NIC_ID); + 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, LOOPBACK_NIC_ID); +#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) + + // + // [FW] TRUE if there are no more entries to age out. + // + BOOLEAN fMoreToAge=FALSE; + + // + // 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]) { + // + // [FW] For the case when the Forwarder appears after our table has + // been primed, we need to age out these entries.... + // + if (Device->ForwarderBound) { + goto ageout; + } + + 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. + // + +ageout: + 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; + } + + // + // [FW] There are more entries to age + // + fMoreToAge = TRUE; + + ++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) && + !Device->ForwarderBound) { + + // + // 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); + + } + + + // + // [FW] If RIP installed, restart the timer only if there was at least + // one entry which could be aged. + // + + if (Device->ForwarderBound) { + + if (fMoreToAge) { + + IPX_DEBUG(RIP, ("More entries to age - restarting long timer\n")); + CTEStartTimer( + &Device->RipLongTimer, + 60000, // one minute timeout + RipLongTimeout, + (PVOID)Device); + + } else { + + // + // Else, dont restart the timer and deref the device + // + + IPX_DEBUG(RIP, ("No more entries to age - derefing the device\n")); + IpxDereferenceDevice (Device, DREF_LONG_TIMER); + } + } else { + // + // 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/isn/ipx/rt.c b/private/ntos/tdi/isn/ipx/rt.c new file mode 100644 index 000000000..8881f03fa --- /dev/null +++ b/private/ntos/tdi/isn/ipx/rt.c @@ -0,0 +1,1311 @@ +/*++ + +Copyright (c) 1989-1994 Microsoft Corporation + +Module Name; + + Rt.c + +Abstract; + + +Author; + + +Revision History; + +TODO: Get rid of ref/Deref since the RTINFO structure will not be destroyed + Use a common alloc/free function (with the rest of ipx) + Allocate tagged memory + Optimize code more +--*/ + +#include "precomp.h" +#pragma hdrstop + +// +// function prototypes +// + +VOID +RtIrpCancel( + IN PDEVICE_OBJECT Device, + IN PIRP pIrp + ); + + +PVOID +RtAllocMem( + IN ULONG Size + ); + +VOID +RtFreeMem( + IN PVOID pBuffer, + IN ULONG Size + ); + +NTSTATUS +NTCheckSetCancelRoutine( + IN PIRP pIrp, + IN PVOID CancelRoutine, + IN PDEVICE pDevice + ); +VOID +NTIoComplete( + IN PIRP pIrp, + IN NTSTATUS Status, + IN ULONG SentLength); + +NTSTATUS +CleanupRtAddress( + IN PDEVICE pDevice, + IN PIRP pIrp); + +NTSTATUS +CloseRtAddress( + IN PDEVICE pDevice, + IN PIRP pIrp); + +NTSTATUS +SendIrpFromRt ( + IN PDEVICE pDevice, + IN PIRP pIrp + ); + +NTSTATUS +RcvIrpFromRt ( + IN PDEVICE pDevice, + IN PIRP pIrp + ); +NTSTATUS +PassDgToRt ( + IN PDEVICE pDevice, + IN PIPX_DATAGRAM_OPTIONS2 pContext, + IN ULONG Index, + IN VOID UNALIGNED *pDgrm, + IN ULONG uNumBytes + ); + +VOID +IpxDerefRt( + PRT_INFO pRt + ); + +VOID +IpxRefRt( + PRT_INFO pRt + ); + +VOID +IpxDestroyRt( + IN PRT_INFO pRt + ); + +#define ALLOC_PRAGMA 1 +#define CTEMakePageable(x, y) alloc_text(x,y) + +#define AllocMem(_BytesToAlloc) IpxAllocateMemory(_BytesToAlloc, MEMORY_PACKET, "RT MEMORY") + +#define FreeMem(_Memory, _BytesAllocated) IpxFreeMemory(_Memory, _BytesAllocated, MEMORY_PACKET, "RT MEMORY") + + +#define IpxVerifyRt(pRt) // \ + // if ((pRt->Type != IPX_RT_SIGNATURE) || (pRt->Size != sizeof(RT_INFO))) { return STATUS_INVALID_ADDRESS; } + + +//******************* Pageable Routine Declarations **************** +#ifdef ALLOC_PRAGMA +#pragma CTEMakePageable(PAGERT, CloseRtAddress) +#pragma CTEMakePageable(PAGERT, CleanupRtAddress) +#pragma CTEMakePageable(PAGERT, RcvIrpFromRt) +#pragma CTEMakePageable(PAGERT, SendIrpFromRt) +#pragma CTEMakePageable(PAGERT, PassDgToRt) +#pragma CTEMakePageable(PAGERT, RtIrpCancel) +#pragma CTEMakePageable(PAGERT, NTCheckSetCancelRoutine) +#pragma CTEMakePageable(PAGERT, NTIoComplete) +#pragma CTEMakePageable(PAGERT, RtFreeMem) +#pragma CTEMakePageable(PAGERT, RtAllocMem) +#pragma CTEMakePageable(PAGERT, IpxRefRt) +#pragma CTEMakePageable(PAGERT, IpxDerefRt) +#pragma CTEMakePageable(PAGERT, IpxDestroyRt) +#endif +//******************* Pageable Routine Declarations **************** + + +HANDLE IpxRtDiscardableCodeHandle={0}; + +PRT_INFO pRtInfo; //contains info about all rt opened end points + + +NTSTATUS +OpenRtAddress( + IN PDEVICE pDevice, + IN PREQUEST pIrp + ) +{ + PRT_INFO pRt; + CTELockHandle OldIrq; + NTSTATUS status; + ULONG SaveReqCode; + + + IpxPrint0("OpenRtAddress - entered\n"); + + // + // if the RTINFO endpoint structure is not allocated, then allocate it + // and initialize it. But first get the device lock. This gurantees that + // we can not have two irps doing the creation at the same time + // + CTEGetLock(&pDevice->Lock, &OldIrq); + if (!pRtInfo) + { + + pRt = AllocMem(sizeof(RT_INFO)); + + // + // Do this after locking the pagable rtns. + // + // pRtInfo = pRt; //store it in pRtInfo. When irps come down from RM, + // we can compare pRt passed in them with pRtInfo + if (pRt) + { + RtlZeroMemory(pRt,sizeof(RT_INFO)); + IpxPrint1("OpenRtAddress: Initializing CompletedIrps for pRt=(%lx)\n", pRt); + pRt->RcvMemoryMax = RT_MAX_BUFF_MEM; // max. memory we can allocate + pRt->Type = IPX_RT_SIGNATURE; + pRt->Size = sizeof(RT_INFO); + pRt->pDevice = pDevice; + IpxPrint1("OpenRtAddress: pRtInfo=(%lx)\n", pRt); + IpxPrint1("Completed Irp list is (%lx)\n", IsListEmpty(&pRt->CompletedIrps)); + +#if DBG + RtlCopyMemory(pRt->Signature, "RTIF", sizeof("RTIF") - 1); +#endif + InitializeListHead(&pRt->CompletedIrps); + InitializeListHead(&pRt->HolderIrpsList); + } + CTEFreeLock(&pDevice->Lock, OldIrq); + } + else + { + pRt = pRtInfo; + CTEFreeLock(&pDevice->Lock, OldIrq); + IpxPrint1("OpenRtAddress: RTINFO found = (%lx)\n", pRtInfo); + } + + if (pRt) + { + + // Page in the Rt Code, if it hasn't already been paged in. + // + if (!IpxRtDiscardableCodeHandle) + { + IpxRtDiscardableCodeHandle = MmLockPagableCodeSection( CloseRtAddress ); + + pRtInfo = pRt; //store it in pRtInfo. When irps come down from RM, + // we can compare pRt passed in them with pRtInfo + } + + // + // it could fail to lock the pages so check for that + // + if (IpxRtDiscardableCodeHandle) + { + + ULONG i; + status = STATUS_SUCCESS; + + IpxReferenceRt(pRtInfo, RT_CREATE); + + // + // Find an empty slot and mark it open + // + CTEGetLock(&pRt->Lock, &OldIrq); + for (i=0; i<IPX_RT_MAX_ADDRESSES; i++) + { + if (pRt->AddFl[i].State == RT_EMPTY) + { + break; + } + } + if (i < IPX_RT_MAX_ADDRESSES) + { + pRt->AddFl[i].State = RT_OPEN; + pRt->NoOfAdds++; + InitializeListHead(&pRt->AddFl[i].RcvList); + InitializeListHead(&pRt->AddFl[i].RcvIrpList); + } + else + { + CTEFreeLock(&pRt->Lock, OldIrq); + IpxPrint1("OpenRtAddress; All %d slots used up\n", IPX_RT_MAX_ADDRESSES); + IpxDereferenceRt(pRtInfo, RT_CREATE); + status = STATUS_INSUFFICIENT_RESOURCES; + goto RET; + } + CTEFreeLock(&pRt->Lock, OldIrq); + + // + // Found an empty slot. Initialize all relevant info. and then + // open an address object. + // + SaveReqCode = REQUEST_CODE(pIrp); + REQUEST_CODE(pIrp) = MIPX_RT_CREATE; + status = IpxOpenAddressM(pDevice, pIrp, i); + REQUEST_CODE(pIrp) = SaveReqCode; + + IpxPrint1("After IpxOpenAddressM: Completed Irp list is (%lx)\n", IsListEmpty(&pRtInfo->CompletedIrps)); + if (status != STATUS_SUCCESS) + { + IpxPrint0("OpenRtAddress; Access Denied due to OpenAddress\n"); + IpxDereferenceRt(pRtInfo, RT_CREATE); + CTEGetLock(&pRt->Lock, &OldIrq); + pRt->AddFl[i].State = RT_EMPTY; + pRt->NoOfAdds--; + CTEFreeLock(&pRt->Lock, OldIrq); + } + else + { + CTEGetLock(&pRt->Lock, &OldIrq); + pRt->AddFl[i].AddressFile = REQUEST_OPEN_CONTEXT(pIrp); + CTEFreeLock(&pRt->Lock, OldIrq); + + // + // No need to put pRt since it is global. We stick with the addressfile here. + // + + // REQUEST_OPEN_CONTEXT(pIrp) = (PVOID)pRt; + REQUEST_OPEN_TYPE(pIrp) = (PVOID)(ROUTER_ADDRESS_FILE + i); + IpxPrint1("OpenRtAdd: Index = (%d)\n", RT_ADDRESS_INDEX(pIrp)); + } + } + else + { + IpxPrint1("OpenRtAddress; All %d slots used up\n", IPX_RT_MAX_ADDRESSES); + + status = STATUS_INSUFFICIENT_RESOURCES; + } + } + else + { + IpxPrint0("OpenRtCreate; Couldn't allocate a RT_INFO structure\n"); + CTEAssert(FALSE); //should never happen unless system is running + //out of non-paged pool + status = STATUS_INSUFFICIENT_RESOURCES; + + } +RET: + IpxPrint1("OpenRtAddress status prior to return= %X\n",status); + return(status); +} + + +NTSTATUS +CleanupRtAddress( + IN PDEVICE pDevice, + IN PIRP pIrp) + +/*++ +Routine Description; + + This Routine handles closing the Rt Object that is used by + by RT to send and receive name service datagrams on port 137. + + +Arguments; + + pIrp - a ptr to an IRP + +Return Value; + + NTSTATUS - status of the request + +--*/ + +{ + NTSTATUS status; + PRT_INFO pRt; + CTELockHandle OldIrq; + PLIST_ENTRY pHead; + ULONG Index; + PLIST_ENTRY pLE; + PIRP pTmpIrp; + + + + IpxPrint0("CleanupRtAddress - entered\n"); + + // + // if the endpoint structure is allocated, then deallocate it + // + // pRt = REQUEST_OPEN_CONTEXT(pIrp); + pRt = pRtInfo; + + Index = RT_ADDRESS_INDEX(pIrp); + IpxPrint1("CleanupRtAdd: Index = (%d)\n", Index); + + IpxVerifyRt(pRt); + CTEAssert(pRt && (pRt == pRtInfo)); + CTEAssert(Index < IPX_RT_MAX_ADDRESSES); + + do + { + PLIST_ENTRY pRcvEntry; + PRTRCV_BUFFER pRcv; + PRT_IRP pRtAddFl = &pRt->AddFl[Index]; + + CTEAssert(pRtAddFl->State == RT_OPEN); + IpxPrint1("CleanupRtAddress: Got AF handle = (%lx)\n", pRtAddFl); + IpxReferenceRt(pRt, RT_CLEANUP); + status = STATUS_SUCCESS; + + CTEGetLock (&pRt->Lock, &OldIrq); + + // + // prevent any more dgram getting queued up + // + pRtAddFl->State = RT_CLOSING; + CTEFreeLock (&pRt->Lock, OldIrq); + + // + // free any rcv buffers that may be queued up + // + pHead = &pRtAddFl->RcvList; + while (pRcvEntry = ExInterlockedRemoveHeadList(pHead, &pRt->Lock)) + { + pRcv = CONTAINING_RECORD(pRcvEntry,RTRCV_BUFFER,Linkage); + + CTEAssert(pRcv); + IpxPrint1("CleanupRtAddress:Freeing buffer = (%lx)\n", pRcv); + RtFreeMem(pRcv,pRcv->TotalAllocSize); + } + + // + // Complete all irps that are queued + // + while (pLE = ExInterlockedRemoveHeadList(&pRtAddFl->RcvIrpList, &pRt->Lock)) { + + // + // The recv irp is here so copy the data to its buffer and + // pass it up to RT + // + pTmpIrp = CONTAINING_RECORD(pLE, IRP, Tail.Overlay.ListEntry); + IpxPrint1("CleanupRtAddress: Completing Rt rcv Irp from AdFl queue pIrp=%X\n" ,pTmpIrp); + pTmpIrp->IoStatus.Information = 0; + pTmpIrp->IoStatus.Status = STATUS_CANCELLED; + + NTIoComplete(pTmpIrp, (NTSTATUS)-1, (ULONG)-1); + + } //end of while + + // + // dequeue and complete any irps on the complete queue. + // + + while (pLE = ExInterlockedRemoveHeadList(&pRt->CompletedIrps, &pRt->Lock)) + { + pTmpIrp = CONTAINING_RECORD(pLE, IRP, Tail.Overlay.ListEntry); + if (RT_ADDRESS_INDEX(pTmpIrp) == Index) + { + IpxPrint1("CleanupRtAddress:Completing Rt rcv Irp from CompleteIrps queue pIrp=%X\n" ,pTmpIrp); + + pTmpIrp->IoStatus.Information = 0; + pTmpIrp->IoStatus.Status = STATUS_CANCELLED; + NTIoComplete(pTmpIrp, (NTSTATUS)-1, (ULONG)-1); + } + else + { + ExInterlockedInsertHeadList(&pRt->HolderIrpsList, pLE, &pRt->Lock); + } + } + CTEGetLock(&pRt->Lock, &OldIrq); + while(!IsListEmpty(&pRt->HolderIrpsList)) + { + pLE = RemoveHeadList(&pRt->HolderIrpsList); + InsertHeadList(&pRt->CompletedIrps, pLE); + } + CTEFreeLock(&pRt->Lock, OldIrq); + + // + // Store AF pointer in Irp since we will now be freeing the address file + // (in driver.c). + // + + // + // We always have addressfile in the Irp + // + + // REQUEST_OPEN_CONTEXT(pIrp) = (PVOID)(pRtAddFl->AddressFile); + + IpxDereferenceRt(pRt, RT_CLEANUP); + } while (FALSE); + + IpxPrint0("CleanupRtAddress: Return\n"); + return(status); +} + +NTSTATUS +CloseRtAddress( + IN PDEVICE pDevice, + IN PIRP pIrp) +{ + + NTSTATUS status; + PRT_INFO pRt; + CTELockHandle OldIrq; + PLIST_ENTRY pHead; + ULONG Index; + + IpxPrint0("CloseRtAddress - entered\n"); + + // pRt = REQUEST_OPEN_CONTEXT(pIrp); + pRt = pRtInfo; + + Index = RT_ADDRESS_INDEX(pIrp); + IpxPrint1("CloseRtAdd: Index = (%d)\n", Index); + + IpxVerifyRt(pRt); + CTEAssert(pRt && (pRt == pRtInfo)); + CTEAssert(Index < IPX_RT_MAX_ADDRESSES); + CTEAssert(pRt->AddFl[Index].State == RT_CLOSING); + + // REQUEST_OPEN_CONTEXT(pIrp) = (PVOID)(pRt->AddFl[Index].AddressFile); + //REQUEST_OPEN_TYPE(pIrp) = (PVOID)TDI_TRANSPORT_ADDRESS_FILE; + + CTEGetLock(&pRt->Lock, &OldIrq); + pRt->AddFl[Index].State = RT_EMPTY; + pRt->NoOfAdds--; + CTEFreeLock(&pRt->Lock, OldIrq); + + // + // THis is a counter to the RT_CREATE + // + IpxDereferenceRt(pRt, RT_CLOSE); + + return(STATUS_SUCCESS); +} + +//---------------------------------------------------------------------------- +NTSTATUS +SendIrpFromRt ( + IN PDEVICE pDevice, + IN PIRP pIrp + ) +{ + CTELockHandle OldIrq; + NTSTATUS Status; + ULONG Index; + PRT_INFO pRt; + + IpxPrint0("SendIrpfromRt - entered\n"); + // pRt = REQUEST_OPEN_CONTEXT(pIrp); + pRt = pRtInfo; + + Index = RT_ADDRESS_INDEX(pIrp); + IpxVerifyRt(pRt); + CTEAssert(pRt && (pRt == pRtInfo)); + do { + // + // Check if the add. file slot indicates that it is OPEN. If it is + // not open, then we should return STATUS_INVALID_HANDLE. The + // reason why it may not be open is if we got a cleanup/close before + // this irp. + // + CTEGetLock(&pRt->Lock, &OldIrq); + if (pRt->AddFl[Index].State != RT_OPEN) + { + + // + // free the lock, set the status and break out + // + CTEFreeLock (&pRt->Lock, OldIrq); + Status = STATUS_INVALID_HANDLE; + break; + } + // + // Let us reference the RtInfo structure so that it does not dissapear + // and also for some accounting + // + IpxReferenceRt(pRt, RT_SEND); + + + IpxPrint1("SendIrpFromRt: Index = (%d)\n", Index); + + // + // Store the AF pointer since IpxTdiSendDatagram will use it. Free + // the device lock since we have nothing more to do with our structures + // here. + // + // REQUEST_OPEN_CONTEXT(pIrp) = (PVOID)(pRtInfo->AddFl[Index].AddressFile); + CTEFreeLock (&pRt->Lock, OldIrq); + + Status = IpxTdiSendDatagram(pDevice->DeviceObject, pIrp); + + // + // All done with this send. Derefernce the RtInfo structure. + // + IpxDereferenceRt(pRtInfo, RT_SEND); + } while(FALSE); + + IpxPrint0("SendIrpfromRt - leaving\n"); + return(Status); +} + +NTSTATUS +RcvIrpFromRt ( + IN PDEVICE pDevice, + IN PIRP pIrp + ) +/*++ + +Routine Description; + + This function takes the rcv irp posted by RT and decides if there are + any datagram queued waiting to go up to RT. If so then the datagram + is copied to the RT buffer and passed back up. Otherwise the irp is + held by Netbt until a datagram does come in. + +Arguments; + + pDevice - not used + pIrp - Rt Rcv Irp + +Return Value; + + STATUS_PENDING if the buffer is to be held on to , the normal case. + +Notes; + + +--*/ + +{ + NTSTATUS status; + PRTRCV_BUFFER pBuffer; + PLIST_ENTRY pEntry; + CTELockHandle OldIrq; + PRT_INFO pRt; + PIPX_DATAGRAM_OPTIONS2 pRtBuffer; + PRT_IRP pRtAF; + ULONG Index; +#if DBG + ULONG NoOfRcvIrp; +#endif + + IpxPrint0("RcvIrpfromRt - Entered\n"); + + // pRt = REQUEST_OPEN_CONTEXT(pIrp); + pRt = pRtInfo; + + Index = RT_ADDRESS_INDEX(pIrp); + + IpxPrint1("RcvIrpFromRt: Index = (%d)\n", Index); + + IpxVerifyRt(pRt); + CTEAssert(pRt && (pRt == pRtInfo)); + CTEAssert(Index < IPX_RT_MAX_ADDRESSES); + + CTEGetLock (&pRt->Lock, &OldIrq); + do + { + pRtAF = &pRt->AddFl[Index]; + if (pRtAF->State != RT_OPEN) + { + status = STATUS_INVALID_HANDLE; + CTEFreeLock (&pRt->Lock, OldIrq); + break; + } + IpxReferenceRt(pRt, RT_IRPIN); + + if (!IsListEmpty(&pRtAF->RcvList)) + { + PMDL pMdl; + ULONG CopyLength; + ULONG UserBufferLengthToPass; + ULONG MdlLength; + + // + // There is at least one datagram waiting to be received + // + pEntry = RemoveHeadList(&pRtAF->RcvList); + + pBuffer = (PRTRCV_BUFFER)CONTAINING_RECORD(pEntry,RTRCV_BUFFER, + Linkage); + + IpxPrint0("RcvIrpFromRt: Buffer dequeued\n"); + // + // Copy the datagram and the source address to RT buffer and + // return to RT + // + pMdl = pIrp->MdlAddress; + IpxPrint2("RcvIrpFromRt: Irp=(%lx); Mdl=(%lx)\n", pIrp, pMdl); + CTEAssert(pMdl); + if (!pMdl) + { + status = STATUS_BUFFER_TOO_SMALL; + CTEFreeLock (&pRt->Lock, OldIrq); + IpxDereferenceRt(pRtInfo, RT_IRPIN); + break; + + } + pRtBuffer = MmGetSystemAddressForMdl(pMdl); + MdlLength = MmGetMdlByteCount(pMdl); + + UserBufferLengthToPass = pBuffer->UserBufferLengthToPass; + + CopyLength = (UserBufferLengthToPass <= MdlLength) ? UserBufferLengthToPass : MdlLength; + IpxPrint0("RcvIrpFromRt: Copying Options\n"); + RtlCopyMemory((PVOID)pRtBuffer, + (PVOID)&pBuffer->Options, + CopyLength); + + // + // subtract from the total amount buffered for RT since we are + // passing a datagram up to RT now. + // + pRtInfo->RcvMemoryAllocated -= pBuffer->TotalAllocSize; + RtFreeMem(pBuffer, pBuffer->TotalAllocSize); + + CTEAssert(pRtBuffer->DgrmOptions.LocalTarget.NicId); + + // + // pass the irp up to RT + // + if (CopyLength < UserBufferLengthToPass) + { + status = STATUS_BUFFER_OVERFLOW; + } + else + { + status = STATUS_SUCCESS; + } +#if DBG + NoOfRcvIrp = pRtAF->NoOfRcvIrps; +#endif + + CTEFreeLock (&pRt->Lock, OldIrq); + + + IpxPrint3("Returning Rt rcv Irp immediately with queued dgram, status=%X,pIrp=%X. NoOfRcvIrp=(%d)\n" ,status,pIrp, NoOfRcvIrp); + + pIrp->IoStatus.Information = CopyLength; + pIrp->IoStatus.Status = status; + } + else + { + + status = NTCheckSetCancelRoutine(pIrp,RtIrpCancel,pDevice); + + if (!NT_SUCCESS(status)) + { + CTEFreeLock (&pRt->Lock, OldIrq); + } + else + { + if (pRtAF->NoOfRcvIrps++ > RT_IRP_MAX) + { + IpxPrint1("RcvIrpFromRt; REACHED LIMIT OF IRPS. NoOfRcvIrp=(%d)\n", pRtAF->NoOfRcvIrps); + status = STATUS_INSUFFICIENT_RESOURCES; + pRtAF->NoOfRcvIrps--; + CTEFreeLock (&pRt->Lock, OldIrq); + + } + else + { + InsertTailList(&pRtAF->RcvIrpList,REQUEST_LINKAGE(pIrp)); + IpxPrint2("IpxRt;Holding onto Rt Rcv Irp, pIrp =%Xstatus=%X\n", status,pIrp); + + status = STATUS_PENDING; + CTEFreeLock(&pRt->Lock,OldIrq); + } + } + + + } + IpxDereferenceRt(pRtInfo, RT_IRPIN); + } while(FALSE); + + IpxPrint0("RcvIrpfromRt - Leaving\n"); + return(status); + +} + +//---------------------------------------------------------------------------- +NTSTATUS +PassDgToRt ( + IN PDEVICE pDevice, + IN PIPX_DATAGRAM_OPTIONS2 pContext, + IN ULONG Index, + IN VOID UNALIGNED *pDgrm, + IN ULONG uNumBytes + ) +/*++ + +Routine Description; + + This function is used to allow NBT to pass name query service Pdu's to + RT. Rt posts a Rcv irp to Netbt. If the Irp is here then simply + copy the data to the irp and return it, otherwise buffer the data up + to a maximum # of bytes. Beyond that limit the datagrams are discarded. + + If Retstatus is not success then the pdu will also be processed by + nbt. This allows nbt to process packets when wins pauses and + its list of queued buffers is exceeded. + +Arguments; + + pDevice - card that the request can in on + pSrcAddress - source address + pDgrm - ptr to the datagram + uNumBytes - length of datagram + +Return Value; + + STATUS_PENDING if the buffer is to be held on to , the normal case. + +Notes; + + +--*/ + +{ + NTSTATUS status; + PIPX_DATAGRAM_OPTIONS2 pRtBuffer; + PIRP pIrp; + CTELockHandle OldIrq; + + + IpxPrint0("PassDgToRt - Entered\n"); + + // + // Get the source port and ip address, since RT needs this information. + // + IpxPrint1("PassDgToRt: Index = (%d)\n", Index); + CTEGetLock(&pRtInfo->Lock,&OldIrq); + + do + { + PRT_IRP pRtAF = &pRtInfo->AddFl[Index]; + if (pRtAF->State != RT_OPEN) + { + CTEFreeLock(&pRtInfo->Lock,OldIrq); + break; + } + IpxReferenceRt(pRtInfo, RT_BUFF); + if (IsListEmpty(&pRtAF->RcvIrpList)) + { + IpxPrint0("PassDgToRt: No Rcv Irp\n"); + if (pRtInfo->RcvMemoryAllocated < pRtInfo->RcvMemoryMax) + { + PRTRCV_BUFFER pBuffer; + + pBuffer = RtAllocMem(uNumBytes + sizeof(RTRCV_BUFFER)); + if (pBuffer) + { + pBuffer->TotalAllocSize = uNumBytes + sizeof(RTRCV_BUFFER); + + // + // Copy the user data + // + RtlCopyMemory( + (PUCHAR)((PUCHAR)pBuffer + OFFSET_PKT_IN_RCVBUFF), + (PVOID)pDgrm,uNumBytes); + + + pBuffer->Options.DgrmOptions.LocalTarget.NicId = + pContext->DgrmOptions.LocalTarget.NicId; + pBuffer->Options.LengthOfExtraOpInfo = 0; + + // + // total amount allocated for user + // + pBuffer->UserBufferLengthToPass = uNumBytes + OFFSET_PKT_IN_OPTIONS; + + CTEAssert(pContext->DgrmOptions.LocalTarget.NicId); + IpxPrint2("PassDgToRt: Nic Id is (%d). BufferLength is (%lx)\n", pContext->DgrmOptions.LocalTarget.NicId, uNumBytes); + + + + // + // Keep track of the total amount buffered so that we don't + // eat up all non-paged pool buffering for RT + // + pRtInfo->RcvMemoryAllocated += pBuffer->TotalAllocSize; + + IpxPrint0("IpxRt;Buffering Rt Rcv - no Irp, status=%X\n"); + InsertTailList(&pRtAF->RcvList,&pBuffer->Linkage); + IpxPrint0("PassDgToRt: Buffer Queued\n"); + status = STATUS_SUCCESS; + } + else + { + IpxPrint0("PassDgToRt; Could not allocate buffer\n"); + status = STATUS_INSUFFICIENT_RESOURCES; + } + } + else + { + // this ret status will allow netbt to process the packet. + // + IpxPrint0("PassDgToRt; Dropping Pkt\n"); + status = STATUS_INSUFFICIENT_RESOURCES; + } + CTEFreeLock(&pRtInfo->Lock,OldIrq); + } + else + { + PMDL pMdl; + ULONG CopyLength; + ULONG DgrmLength; + ULONG MdlBufferLength; + ULONG BytesToCopy; + PLIST_ENTRY pLE; + + // + // The recv irp is here so copy the data to its buffer and + // pass it up to RT + // + pLE = RemoveHeadList(&pRtAF->RcvIrpList); + pIrp = CONTAINING_RECORD(pLE, IRP, Tail.Overlay.ListEntry); + + (*(REQUEST_LINKAGE(pIrp))).Flink = NULL; + (*(REQUEST_LINKAGE(pIrp))).Blink = NULL; + + // + // Copy the datagram and the source address to RT buffer and + // return to RT + // + pMdl = pIrp->MdlAddress; + IpxPrint2("PassDgToRt: Irp=(%lx); Mdl=(%lx)\n", pIrp, pMdl); + CTEAssert(pMdl); + + pRtBuffer = MmGetSystemAddressForMdl(pIrp->MdlAddress); + + MdlBufferLength = MmGetMdlByteCount(pMdl); + DgrmLength = uNumBytes; + BytesToCopy = DgrmLength + OFFSET_PKT_IN_OPTIONS; + + CopyLength = (BytesToCopy <= MdlBufferLength) ? BytesToCopy : MdlBufferLength; + IpxPrint2("PassDgToRt: Copy Length = (%d); Mdl Buffer Length is (%d)\n", CopyLength, MdlBufferLength); + + // + // Copy user datagram into pRtBuffer + // + RtlCopyMemory((PVOID)((PUCHAR)pRtBuffer + OFFSET_PKT_IN_OPTIONS), + (PVOID)pDgrm, + CopyLength-OFFSET_PKT_IN_OPTIONS); + + IpxPrint1("Data copied is (%.12s)\n", (PUCHAR)((PUCHAR)pRtBuffer + OFFSET_PKT_IN_OPTIONS + sizeof(IPX_HEADER))); + + pRtBuffer->DgrmOptions.LocalTarget.NicId = pContext->DgrmOptions.LocalTarget.NicId; + pRtBuffer->LengthOfExtraOpInfo = 0; + + IpxPrint3("PassDgToRt: Copy to RcvIrp;Nic Id is (%d/%d). BufferLength is (%lx)\n", pContext->DgrmOptions.LocalTarget.NicId, pRtBuffer->DgrmOptions.LocalTarget.NicId, uNumBytes); + + + CTEAssert(pContext->DgrmOptions.LocalTarget.NicId); + + // + // pass the irp up to RT + // + if (CopyLength < BytesToCopy) + { + status = STATUS_BUFFER_OVERFLOW; + } + else + { + status = STATUS_SUCCESS; + } + + InsertTailList(&pRtInfo->CompletedIrps, REQUEST_LINKAGE(pIrp)); + pRtAF->NoOfRcvIrps--; + IpxPrint4("PassDgToRt;Returning Rt Rcv Irp - data from net, Length=%X,pIrp=%X; status = (%d). NoOfRcvIrp = (%d)\n" ,uNumBytes,pIrp, status, pRtAF->NoOfRcvIrps); + + pIrp->IoStatus.Status = status; + pIrp->IoStatus.Information = CopyLength; + CTEFreeLock(&pRtInfo->Lock,OldIrq); + + } + IpxDereferenceRt(pRtInfo, RT_BUFF); + } while (FALSE); + + + IpxPrint0("PassDgToRt - Entered\n"); + return(status); + +} + +//---------------------------------------------------------------------------- +VOID +RtIrpCancel( + IN PDEVICE_OBJECT pDeviceObject, + IN PIRP pIrp + ) +/*++ + +Routine Description; + + This routine handles the cancelling a RtRcv Irp. It must release the + cancel spin lock before returning re; IoCancelIrp(). + +Arguments; + + +Return Value; + + The final status from the operation. + +--*/ +{ + KIRQL OldIrq; + PRT_INFO pRt; + PDEVICE pDevice = IpxDevice; + ULONG Index; + PIRP pTmpIrp; + + IpxPrint0("RtIrpCancel;Got a Rt Irp Cancel !!! *****************\n"); + + Index = RT_ADDRESS_INDEX(pIrp); + IpxPrint1("RtIrpCancel: Index = (%d)\n", Index); + // pRt = (PRT_INFO)REQUEST_OPEN_CONTEXT(pIrp); + pRt = pRtInfo; + + IoReleaseCancelSpinLock(pIrp->CancelIrql); + if ((pRt->Type != IPX_RT_SIGNATURE) || (pRt->Size != sizeof(RT_INFO))) { + return; + } + + + // + // Be sure that PassNamePduToRt has not taken the RcvIrp for a + // Rcv just now. + // + CTEGetLock(&pRt->Lock,&OldIrq); + if (pRt && (pRt == pRtInfo) && (*(REQUEST_LINKAGE(pIrp))).Flink != NULL) + { + + PRT_IRP pRtAF = &pRt->AddFl[Index]; + + RemoveEntryList(REQUEST_LINKAGE(pIrp)); + + pIrp->IoStatus.Status = STATUS_CANCELLED; + pRtAF->NoOfRcvIrps--; + CTEFreeLock(&pRt->Lock,OldIrq); + IpxPrint1("RtIrpCancel;Completing Request. NoOfRcvIrp = (%d)\n", pRtAF->NoOfRcvIrps); + IoCompleteRequest(pIrp,IO_NETWORK_INCREMENT); + } else { + CTEFreeLock(&pRt->Lock,OldIrq); + } +} +//---------------------------------------------------------------------------- +PVOID +RtAllocMem( + IN ULONG Size + ) + +/*++ +Routine Description; + + This Routine handles allocating memory and keeping track of how + much has been allocated. + +Arguments; + + Size - number of bytes to allocate + Rcv - boolean that indicates if it is rcv or send buffering + +Return Value; + + ptr to the memory allocated + +--*/ + +{ + if (pRtInfo->RcvMemoryAllocated > pRtInfo->RcvMemoryMax) + { + return NULL; + } + else + { + pRtInfo->RcvMemoryAllocated += Size; + return (AllocMem(Size)); + } +} +//---------------------------------------------------------------------------- +VOID +RtFreeMem( + IN PVOID pBuffer, + IN ULONG Size + ) + +/*++ +Routine Description; + + This Routine handles freeing memory and keeping track of how + much has been allocated. + +Arguments; + + pBuffer - buffer to free + Size - number of bytes to allocate + Rcv - boolean that indicates if it is rcv or send buffering + +Return Value; + + none + +--*/ + +{ + if (pRtInfo) + { + pRtInfo->RcvMemoryAllocated -= Size; + } + + FreeMem(pBuffer, Size); +} + + + +//---------------------------------------------------------------------------- + +VOID +NTIoComplete( + IN PIRP pIrp, + IN NTSTATUS Status, + IN ULONG SentLength) + +/*++ +Routine Description; + + This Routine handles calling the NT I/O system to complete an I/O. + +Arguments; + + status - a completion status for the Irp + +Return Value; + + NTSTATUS - status of the request + +--*/ + +{ + KIRQL OldIrq; + + if (Status != -1) + { + pIrp->IoStatus.Status = Status; + } + // use -1 as a flag to mean do not adjust the sent length since it is + // already set + if (SentLength != -1) + { + pIrp->IoStatus.Information = SentLength; + } + +#if DBG + if (SentLength != -1) + { + if ( (Status != STATUS_SUCCESS) && + (Status != STATUS_PENDING) && + (Status != STATUS_INVALID_DEVICE_REQUEST) && + (Status != STATUS_INVALID_PARAMETER) && + (Status != STATUS_IO_TIMEOUT) && + (Status != STATUS_BUFFER_OVERFLOW) && + (Status != STATUS_BUFFER_TOO_SMALL) && + (Status != STATUS_INVALID_HANDLE) && + (Status != STATUS_INSUFFICIENT_RESOURCES) && + (Status != STATUS_CANCELLED) && + (Status != STATUS_DUPLICATE_NAME) && + (Status != STATUS_TOO_MANY_NAMES) && + (Status != STATUS_TOO_MANY_SESSIONS) && + (Status != STATUS_REMOTE_NOT_LISTENING) && + (Status != STATUS_BAD_NETWORK_PATH) && + (Status != STATUS_HOST_UNREACHABLE) && + (Status != STATUS_CONNECTION_REFUSED) && + (Status != STATUS_WORKING_SET_QUOTA) && + (Status != STATUS_REMOTE_DISCONNECT) && + (Status != STATUS_LOCAL_DISCONNECT) && + (Status != STATUS_LINK_FAILED) && + (Status != STATUS_SHARING_VIOLATION) && + (Status != STATUS_UNSUCCESSFUL) && + (Status != STATUS_ACCESS_VIOLATION) && + (Status != STATUS_NONEXISTENT_EA_ENTRY) ) + { + IpxPrint1("returning unusual status = %X\n",Status); + } + } +#endif + IpxPrint1("Irp Status is %d\n", pIrp->IoStatus.Status); + + // + // set the Irps cancel routine to null or the system may bugcheck + // with a bug code of CANCEL_STATE_IN_COMPLETED_IRP + // + // refer to IoCancelIrp() ..\ntos\io\iosubs.c + // + IoAcquireCancelSpinLock(&OldIrq); + IoSetCancelRoutine(pIrp,NULL); + IoReleaseCancelSpinLock(OldIrq); + + IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT); +} + + +//---------------------------------------------------------------------------- +NTSTATUS +NTCheckSetCancelRoutine( + IN PIRP pIrp, + IN PVOID CancelRoutine, + IN PDEVICE pDevice + ) + +/*++ +Routine Description; + + This Routine sets the cancel routine for an Irp. + +Arguments; + + status - a completion status for the Irp + +Return Value; + + NTSTATUS - status of the request + +--*/ + +{ + NTSTATUS status; + + IpxPrint1("CheckSetCancelRoutine: Entered. Irp = (%lx)\n", pIrp); + // + // Check if the irp was cancelled yet and if not, then set the + // irp cancel routine. + // + IoAcquireCancelSpinLock(&pIrp->CancelIrql); + if (pIrp->Cancel) + { + pIrp->IoStatus.Status = STATUS_CANCELLED; + status = STATUS_CANCELLED; + + } + else + { + // setup the cancel routine + IoMarkIrpPending(pIrp); + IoSetCancelRoutine(pIrp,CancelRoutine); + status = STATUS_SUCCESS; + } + + IoReleaseCancelSpinLock(pIrp->CancelIrql); + return(status); + +} + + + + +VOID +IpxRefRt( + PRT_INFO pRt + ) + +/*++ + +Routine Description; + + This routine increments the reference count on a device context. + +Arguments; + + Binding - Pointer to a transport device context object. + +Return Value; + + none. + +--*/ + +{ + + (VOID)InterlockedIncrement (&pRt->ReferenceCount); +// CTEAssert (pRt->ReferenceCount > 0); // not perfect, but... +// IpxPrint1("RefRt: RefCount is (%d)\n", pRt->ReferenceCount); + +} /* IpxRefRt */ + + +VOID +IpxDerefRt( + PRT_INFO pRt + ) + +/*++ + +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 (&pRt->ReferenceCount); +// IpxPrint1("DerefRt: RefCount is (%d)\n", pRt->ReferenceCount); + +// CTEAssert (result >= 0); + +#if 0 + if (result == 0) { + IpxDestroyRt (pRt); + } +#endif + +} /* IpxDerefRt */ + + + + +VOID +IpxDestroyRt( + IN PRT_INFO pRt + ) + +/*++ + +Routine Description; + + This routine destroys a binding structure. + +Arguments; + + Binding - Pointer to a transport binding structure. + +Return Value; + + None. + +--*/ + +{ + IpxPrint0("Destroying Rt\n"); + FreeMem (pRt, sizeof(RT_INFO)); + pRtInfo = NULL; + return; +} /* IpxDestroyRt */ + diff --git a/private/ntos/tdi/isn/ipx/send.c b/private/ntos/tdi/isn/ipx/send.c new file mode 100644 index 000000000..b4e885c48 --- /dev/null +++ b/private/ntos/tdi/isn/ipx/send.c @@ -0,0 +1,2364 @@ + +/*++ + +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. + // +RealFunctionStart:; + 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->ForwarderBound || + (!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 if the FWD is + // not bound; 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 + + // + // [FW] Call the InternalSendHandler of the Forwarder + // + + if (Device->ForwarderBound) { + + // + // Call the InternalSend to filter the packet and get to know + // the correct adapter context + // + + NTSTATUS ret; + PUCHAR IpxHeader; + PUCHAR Data; + PNDIS_BUFFER HeaderBuffer; + UINT TempHeaderBufferLength; + UINT DataLength; + ULONG FwdAdapterCtx = INVALID_CONTEXT_VALUE; + + if (GET_VALUE(Binding->ReferenceCount) == 2) { + FwdAdapterCtx = Binding->FwdAdapterContext; + } + + // + // Figure out the IpxHeader - it is always at the top of the second MDL. + // + NdisQueryPacket (NdisPacket, NULL, NULL, &HeaderBuffer, NULL); + NdisQueryBuffer (NDIS_BUFFER_LINKAGE(HeaderBuffer), &IpxHeader, &TempHeaderBufferLength); + + // + // Data is always at the top of the third MDL. + // + NdisQueryBuffer (NDIS_BUFFER_LINKAGE(NDIS_BUFFER_LINKAGE(HeaderBuffer)), &Data, &DataLength); + + ret = (*Device->UpperDrivers[IDENTIFIER_RIP].InternalSendHandler)( + &LocalTarget, + FwdAdapterCtx, + NdisPacket, + IpxHeader, + Data, + REQUEST_INFORMATION(Reserved->u.SR_DG.Request) + sizeof(IPX_HEADER), + FALSE); + + // + // The return shd not be a silent drop - we dont broadcast keepalives. + // + CTEAssert(ret != STATUS_DROP_SILENTLY); + + if (ret == STATUS_SUCCESS) { + // + // The adapter could have gone away and we have indicated to the Forwarder + // but the Forwarder has not yet closed the adapter. + // [ZZ] adapters do not go away now. + // + // BUGBUG: what if the binding is NULL here? Can we trust the Forwarder to + // give us a non-NULL binding? + // + Binding = NIC_ID_TO_BINDING(Device, NIC_FROM_LOCAL_TARGET(&LocalTarget)); + + if (GET_VALUE(Binding->ReferenceCount) == 1) { + Adapter = Binding->Adapter; +#ifdef _PNP_POWER + IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS); +#endif _PNP_POWER + goto FunctionStart; + } else { + goto send_packet; + } + + } else if (ret == STATUS_PENDING) { + // + // LocalTarget will get filled up in InternalSendComplete + // + return; + } + // + // else DISCARD + // + Adapter = Binding->Adapter; +#ifdef _PNP_POWER + IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS); +#endif _PNP_POWER + goto FunctionStart; + + } else { +send_packet: + // + // [FW] Use the frametype specific send handler + // + + // if ((NdisStatus = IpxSendFrame( + // &LocalTarget, + // NdisPacket, + // REQUEST_INFORMATION(Reserved->u.SR_DG.Request) + sizeof(IPX_HEADER), + // sizeof(IPX_HEADER))) != NDIS_STATUS_PENDING) { + // + // Adapter = Binding->Adapter; + // goto FunctionStart; + // } + // + // return; + + if ((NdisStatus = (*Binding->SendFrameHandler)( + Binding->Adapter, + &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 RealFunctionStart; + } +#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; + BOOLEAN fFwdDecides=FALSE; + + if (NdisStatus == NDIS_STATUS_SUCCESS) { + Reserved->Net0SendSucceeded = TRUE; + } + + // + // Figure out the IpxHeader - it is always at the top of the second MDL. + // + NdisQueryPacket (NdisPacket, NULL, NULL, &HeaderBuffer, NULL); + NdisQueryBuffer (NDIS_BUFFER_LINKAGE(HeaderBuffer), &IpxHeader, &TempHeaderBufferLength); + + // + // For Type 20 pkts, we let the Fwd decide the next Nic to send on, so we pass + // the old Nic itself and let the Fwd change it for us. + // + if ((Device->ForwarderBound) && + (IpxHeader->PacketType == 0x14)) { + NewId = NIC_FROM_LOCAL_TARGET(&Reserved->LocalTarget); + fFwdDecides=TRUE; + Binding = NIC_ID_TO_BINDING(Device, NewId); + IPX_DEBUG(SEND, ("SendComplete: IpxHeader has Type20: %lx\n", IpxHeader)); + } else { + + 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; + +#ifdef _PNP_POWER + FILL_LOCAL_TARGET(&LocalTarget, NewId); +#else + LocalTarget.NicId = NewId; +#endif + RtlCopyMemory(LocalTarget.MacAddress, IpxHeader->DestinationNode, 6); + + // + // [FW] Call the InternalSendHandler of the Forwarder + // + + if (Device->ForwarderBound) { + + // + // Call the InternalSend to filter the packet and get to know + // the correct adapter context + // + + NTSTATUS ret; + PUCHAR Data; + UINT DataLength; + ULONG FwdAdapterCtx = INVALID_CONTEXT_VALUE; + + if (GET_VALUE(Binding->ReferenceCount) == 2) { + FwdAdapterCtx = Binding->FwdAdapterContext; + } + + ret = (*Device->UpperDrivers[IDENTIFIER_RIP].InternalSendHandler)( + &LocalTarget, + FwdAdapterCtx, + NdisPacket, + (PUCHAR)IpxHeader, + ((PUCHAR)IpxHeader)+sizeof(IPX_HEADER), // the data starts after the IPX Header. + Reserved->PacketLength, + TRUE); // iterate is true + + // + // The return shd not be a silent drop - we dont broadcast keepalives. + // + CTEAssert(ret != STATUS_DROP_SILENTLY); + + if (ret == STATUS_SUCCESS) { + // + // The adapter could have gone away and we have indicated to the Forwarder + // but the Forwarder has not yet closed the adapter. + // [ZZ] adapters do not go away now. + // + // BUGBUG: what if the binding is NULL here? Can we trust the Forwarder to + // give us a non-NULL binding? + // + Binding = NIC_ID_TO_BINDING(Device, NIC_FROM_LOCAL_TARGET(&LocalTarget)); + + if (GET_VALUE(Binding->ReferenceCount) == 1) { + Adapter = Binding->Adapter; + IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS); + goto FunctionStart; + } else { + NewId = NIC_FROM_LOCAL_TARGET(&LocalTarget); + goto send_packet1; + } + + } else if (ret == STATUS_PENDING) { + // + // LocalTarget will get filled up in InternalSendComplete + // + return; + } + // + // else DISCARD + // + Adapter = Binding->Adapter; + IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS); + + // + // If Fwd decides, then this is end of Nic list - complete the send. + // + if (fFwdDecides) { + goto NoMoreSends; + } else { + goto FunctionStart; + } + + } else { +#if DBG + NdisQueryPacket (NdisPacket, NULL, NULL, &HeaderBuffer, NULL); + NdisQueryBuffer(HeaderBuffer, &Header, &TempHeaderBufferLength); + + IpxHeader = (PIPX_HEADER)(&Header[Device->IncludedHeaderOffset]); + + IPX_DEBUG(SEND, ("SendComplete: IpxHeader: %lx\n", IpxHeader)); +#endif + +send_packet1: + + 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); +NoMoreSends: + // + // 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; + IPX_FIND_ROUTE_REQUEST routeEntry; + PIPX_DATAGRAM_OPTIONS2 Options; + +#ifdef _PNP_POWER + IPX_DEFINE_LOCK_HANDLE(LockHandle1) +#endif + +#ifdef SNMP + ++IPX_MIB_ENTRY(Device, SysOutRequests); +#endif SNMP + + // + // 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. + // + + if (!REQUEST_SPECIAL_SEND(Request)) { + 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; +#ifdef SNMP + ++IPX_MIB_ENTRY(Device, SysOutDiscards); +#endif SNMP + goto error_send_no_packet; + } + } else { + ASSERT(OPEN_REQUEST_EA_LENGTH(Request) == sizeof(IPX_DATAGRAM_OPTIONS2)); + Options = ((PIPX_DATAGRAM_OPTIONS2)(OPEN_REQUEST_EA_INFORMATION(Request))); + RemoteAddress = (TDI_ADDRESS_IPX UNALIGNED *)(&Options->RemoteAddress); + IPX_DEBUG(SEND, ("IpxTdiSendDatagram: Options buffer supplied as input buffer\n")); + } + + 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; +#ifdef SNMP + ++IPX_MIB_ENTRY(Device, SysOutDiscards); +#endif SNMP + 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; +#ifdef SNMP + ++IPX_MIB_ENTRY(Device, SysOutDiscards); +#endif SNMP + 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 IrpSp does not have a buffer for the right size for + // datagram options and there is no input buffer + // + if (!REQUEST_SPECIAL_SEND(Request) && + (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; +#ifdef SNMP + ++IPX_MIB_ENTRY(Device, SysOutMalformedRequests); +#endif SNMP + 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 + + // + // [FW] the localtarget shd be in the packet's reserved section + // + LocalTarget = &Reserved->LocalTarget; + Reserved->LocalTarget = TempLocalTarget; + } else { + + // + // [FW] If router installed, call the Forwarder's FindRouteHandler. + // This returns a STATUS_SUCCESS if a route is available + // + if (Device->ForwarderBound) { + + Status = (*Device->UpperDrivers[IDENTIFIER_RIP].FindRouteHandler) ( + (PUCHAR)&RemoteAddress->NetworkAddress, + RemoteAddress->NodeAddress, + &routeEntry); + + if (Status != STATUS_SUCCESS) { + + IPX_DEBUG (SEND, ("RouteHandler failed, network: %lx\n", + REORDER_ULONG(*(UNALIGNED ULONG *)RemoteAddress->NetworkAddress))); + goto error_send_with_packet; + + } else { + + // + // Fill in the LocalTarget from the RouteEntry + // + + LocalTarget = &Reserved->LocalTarget; + + Reserved->LocalTarget = routeEntry.LocalTarget; + + IPX_DEBUG(SEND, ("IPX: SendFramePreFwd: LocalTarget is: %lx\n", Reserved->LocalTarget)); + + if (GET_VALUE(NIC_ID_TO_BINDING(Device, LocalTarget->NicId)->ReferenceCount) == 1) { + IPX_DEBUG(SEND, ("IPX: SendFramePreFwd: FWD returned SUCCESS, Ref count is 1\n")); + Status = NDIS_STATUS_SUCCESS; + goto error_send_with_packet; + } + + if (Parameters->SendLength > + NIC_ID_TO_BINDING(Device, LocalTarget->NicId)->RealMaxDatagramSize) { + + IPX_DEBUG (SEND, ("Send %d bytes too large (%d)\n", + Parameters->SendLength, + NIC_ID_TO_BINDING(Device, LocalTarget->NicId)->RealMaxDatagramSize)); + + REQUEST_INFORMATION(Request) = 0; + Status = STATUS_INVALID_BUFFER_SIZE; + + goto error_send_with_packet; + } + + // + // [FW] we dont need to check this since the FWD does it for us. + // + + /* + if ((Device->DisableDialoutSap) && + (Address->Socket == SAP_SOCKET) && + (NIC_ID_TO_BINDING(Device, LocalTarget->NicId)->DialOutAsync)) { + + REQUEST_INFORMATION(Request) = 0; + Status = STATUS_NETWORK_UNREACHABLE; + goto error_send_with_packet; + } + */ + +#ifdef _PNP_POWER + IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1); + Binding = NIC_ID_TO_BINDING(Device, NIC_FROM_LOCAL_TARGET(LocalTarget)); + IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS); + IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1); +#endif + IPX_DEBUG(SEND, ("FindRoute for %02x-%02x-%02x-%02x-%02x-%02x returned %lx\n", + LocalTarget->MacAddress[0], + LocalTarget->MacAddress[1], + LocalTarget->MacAddress[2], + LocalTarget->MacAddress[3], + LocalTarget->MacAddress[4], + LocalTarget->MacAddress[5], + Status)); + + } + + } 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) == (USHORT)LOOPBACK_NIC_ID) { + 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; +#ifdef SNMP + ++IPX_MIB_ENTRY(Device, SysOutMalformedRequests); +#endif SNMP + goto error_send_with_packet; + } + + if (!Device->ForwarderBound && + (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); +#ifdef SNMP + ++IPX_MIB_ENTRY(Device, SysOutDiscards); +#endif SNMP + 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); +#ifdef SNMP + ++IPX_MIB_ENTRY(Device, SysOutDiscards); +#endif SNMP + goto error_send_with_packet; + + } + + // + // [FW] The localtarget shd be in the reserved section. + // + LocalTarget = &Reserved->LocalTarget; + Reserved->LocalTarget = TempLocalTarget; + } + } + + // + // [FW] moved to the conditions above so we save a copy in the RIP case + // + + // 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 { + + if (!REQUEST_SPECIAL_SEND(Request)) { + PacketType = ((PUCHAR)(Information->Options))[0]; + LocalTarget = &((PIPX_DATAGRAM_OPTIONS)(Information->Options))->LocalTarget; + } else { + ASSERT(OPEN_REQUEST_EA_LENGTH(Request) == sizeof(IPX_DATAGRAM_OPTIONS2)); + if (OPEN_REQUEST_EA_LENGTH(Request) == sizeof(IPX_DATAGRAM_OPTIONS2)) { + //IpxPrint0("IpxTdiSendDatagram: We have an input buffer of the right size\n"); + } else { + //IpxPrint1("IpxTdiSendDatagram: Wrong sized buffer. Buff size is =(%d)\n", OPEN_REQUEST_EA_LENGTH(Request)); + Status = STATUS_INVALID_BUFFER_SIZE; + goto error_send_with_packet; + } + + PacketType = Options->DgrmOptions.PacketType; + LocalTarget = &Options->DgrmOptions.LocalTarget; + if (NIC_ID_TO_BINDING(Device, LocalTarget->NicId) == NULL) { + Status = STATUS_NOT_FOUND; + goto error_send_with_packet; + } + } + + // + // 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) == (USHORT)LOOPBACK_NIC_ID) { + 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; +#ifdef SNMP + ++IPX_MIB_ENTRY(Device, SysOutMalformedRequests); +#endif SNMP + 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 + + // + // In case the packet is being sent to a SAP socket or + // we have multiple cards and a zero virtual net or + // it is a special send (on a nic), we need to use + // the binding's address instead of the virtual address. + // + if (Device->MultiCardZeroVirtual || + (Address->LocalAddress.Socket == SAP_SOCKET) || + (RemoteAddress->Socket == SAP_SOCKET) || + (REQUEST_SPECIAL_SEND(Request))) { + + // + // 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 (Address->RtAdd) + { + REQUEST_OPEN_CONTEXT(Request) = (PVOID)(pRtInfo); + } + */ + + // + // [FW] If Forwarder installed, send the packet out for filtering + // + // STEFAN: 3/28/96: + // Dont filter IPXWAN config packets since the FWD does not have this adapter opened yet. + // + + IPX_DEBUG(SEND, ("LocalAddress.Socket %x, IPXWAN_SOCKET\n", Address->LocalAddress.Socket, IPXWAN_SOCKET)); + if (Address->LocalAddress.Socket != IPXWAN_SOCKET && + Device->ForwarderBound) { + + // + // Call the InternalSend to filter the packet and get to know + // the correct adapter context + // + + NTSTATUS ret; + ULONG FwdAdapterCtx = INVALID_CONTEXT_VALUE; + PUCHAR Data; + UINT DataLength; + + if (GET_VALUE(Binding->ReferenceCount) == 2) { + FwdAdapterCtx = Binding->FwdAdapterContext; + } + + // + // Figure out the location of the data in the packet + // For BackFill packets, the data is in the first (and only) MDL. + // For others, it is in the third MDL. + // +#if BACK_FILL + if (Reserved->BackFill) { + Data = (PUCHAR)(IpxHeader+sizeof(IPX_HEADER)); + } else { + NdisQueryBuffer(NDIS_BUFFER_LINKAGE(NDIS_BUFFER_LINKAGE(Reserved->HeaderBuffer)), &Data, &DataLength); + } +#else + NdisQueryBuffer(NDIS_BUFFER_LINKAGE(NDIS_BUFFER_LINKAGE(Reserved->HeaderBuffer)), &Data, &DataLength); +#endif + + ret = (*Device->UpperDrivers[IDENTIFIER_RIP].InternalSendHandler)( + LocalTarget, + FwdAdapterCtx, + Packet, + (PUCHAR)IpxHeader, + Data, + LengthIncludingHeader, + FALSE); + + if (ret == STATUS_SUCCESS) { + // + // The adapter could have gone away and we have indicated to the Forwarder + // but the Forwarder has not yet closed the adapter. + // + // BUGBUG: what if the binding is NULL here? Can we trust the Forwarder to + // give us a non-NULL binding? + // + + Binding = NIC_ID_TO_BINDING(Device, NIC_FROM_LOCAL_TARGET(LocalTarget)); + + if (GET_VALUE(Binding->ReferenceCount) == 1) { + Status = NDIS_STATUS_SUCCESS; +// #if DBG + CTEAssert (Reserved->SendInProgress); + Reserved->SendInProgress = FALSE; +// #endif + goto error_send_with_packet; + } else { + IsLoopback = (NIC_FROM_LOCAL_TARGET(LocalTarget) == (USHORT)LOOPBACK_NIC_ID); + goto send_packet; + } + } else if (ret == STATUS_PENDING) { + // + // LocalTarget will get filled up in InternalSendComplete + // + + // + // BUGBUG: this is a NULL macro - include this? + // + IPX_END_SYNC (&SyncContext); + + return STATUS_PENDING; + } else if (ret == STATUS_DROP_SILENTLY) { + IPX_DEBUG(SEND, ("IPX: SendFramePreFwd: FWD returned STATUS_DROP_SILENTLY - dropping pkt.\n")); + Status = NDIS_STATUS_SUCCESS; + +// #if DBG + CTEAssert (Reserved->SendInProgress); + Reserved->SendInProgress = FALSE; +// #endif + goto error_send_with_packet; + } + + // + // else DISCARD + // + +// #if DBG + CTEAssert (Reserved->SendInProgress); + Reserved->SendInProgress = FALSE; +// #endif + Status = STATUS_NETWORK_UNREACHABLE; + goto error_send_with_packet; + + } else { + + // + // [FW] Jump here if the Forwarder gave us the go ahead on this send. + // We also come here to send if the Forwarder is not installed. + // + +send_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; +#ifdef SNMP + ++IPX_MIB_ENTRY(Device, SysOutDiscards); +#endif SNMP + goto error_send_no_packet; + + } + + } else { + + // + // The address file didn't look like one. + // + + Status = STATUS_INVALID_HANDLE; +#ifdef SNMP + ++IPX_MIB_ENTRY(Device, SysOutDiscards); +#endif SNMP + 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 + + + +// +// [FW] +// + +VOID +IpxInternalSendComplete( + IN PIPX_LOCAL_TARGET LocalTarget, + IN PNDIS_PACKET Packet, + IN ULONG PacketLength, + IN NTSTATUS Status + ) +/*++ + +Routine Description: + + This routine is called by the Kernel Forwarder to indicate that a pending + internal send to it has completed. + +Arguments: + + LocalTarget - if Status is OK, this has the local target for the send. + + Packet - A pointer to the NDIS_PACKET that we sent. + + PacketLength - length of the packet (including the IPX header) + + BUGBUG: Can IpxSendFrame use the local var. PktLength instead? What about IpxSendFrameXXX (frame specific) + + Status - the completion status of the send - STATUS_SUCCESS or STATUS_NETWORK_UNREACHABLE + +Return Value: + + none. + +--*/ +{ + PDEVICE Device=IpxDevice; + PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved); + PBINDING Binding; + NDIS_STATUS NdisStatus; + PIO_STACK_LOCATION irpSp; + PREQUEST Request; + PADDRESS_FILE AddressFile; + + switch (Reserved->Identifier) + { + case IDENTIFIER_IPX: + + // + // datagrams can be sent to the frame-specific handlers directly + // + // BUGBUG: Make this change in SendComplete too + // + + if ((Status == STATUS_SUCCESS) && + (Binding = NIC_ID_TO_BINDING(Device, NIC_FROM_LOCAL_TARGET(LocalTarget))) && + (GET_VALUE(Binding->ReferenceCount) == 2)) { + + if (NIC_FROM_LOCAL_TARGET(LocalTarget) == (USHORT)LOOPBACK_NIC_ID) { + + // + // Enque this packet to the LoopbackQueue on the binding. + // If the LoopbackRtn is not already scheduled, schedule it. + // + + IPX_DEBUG(LOOPB, ("Packet: %lx \n", Packet)); + + // + // 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, + PacketLength, + sizeof(IPX_HEADER))) != NDIS_STATUS_PENDING) { + // + // Call SendComplete here so it can send broadcasts over other + // Nic's and remove any padding if used. + // + + IpxSendComplete((NDIS_HANDLE)Binding->Adapter, + Packet, + NdisStatus); + } + } + } else { + // + // DISCARD was returned - complete the IRP + // + NdisStatus = STATUS_NETWORK_UNREACHABLE; + + + // + // We need to free the packet and deref the addressfile... + // + + // #if DBG + CTEAssert (Reserved->SendInProgress); + Reserved->SendInProgress = FALSE; + // #endif + + if (Reserved->OwnedByAddress) { + Reserved->Address->SendPacketInUse = FALSE; + } else { + IPX_PUSH_ENTRY_LIST( + &Device->SendPacketList, + &Reserved->PoolLinkage, + &Device->Lock); + } + + AddressFile = Reserved->u.SR_DG.AddressFile; + IpxDereferenceAddressFileSync (AddressFile, AFREF_SEND_DGRAM); + + Request = Reserved->u.SR_DG.Request; + REQUEST_STATUS(Request) = NdisStatus; + irpSp = IoGetCurrentIrpStackLocation( Request ); + + // + // If this is a fast send irp, we bypass the file system and + // call the completion routine directly. + // + + 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); + } + + break; + + default: + // + // for all other packet types + // + + if ((Status == STATUS_SUCCESS) && + (Binding = NIC_ID_TO_BINDING(Device, NIC_FROM_LOCAL_TARGET(LocalTarget))) && + (GET_VALUE(Binding->ReferenceCount) == 2)) { + // + // BUGBUG: IncludedHeaderLength is only used to check for RIP packets (==0) + // so IPX_HEADER size is OK. Should finally remove this parameter. + // + + if (NIC_FROM_LOCAL_TARGET(LocalTarget) == (USHORT)LOOPBACK_NIC_ID) { + + // + // Enque this packet to the LoopbackQueue on the binding. + // If the LoopbackRtn is not already scheduled, schedule it. + // + + IPX_DEBUG(LOOPB, ("Packet: %lx\n", Packet)); + + // + // 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 { + NdisStatus = IpxSendFrame(LocalTarget, Packet, PacketLength, sizeof(IPX_HEADER)); + + if (NdisStatus != NDIS_STATUS_PENDING) { + IPX_DEBUG (SEND, ("IpxSendFrame status %lx on NICid %lx, packet %lx \n", + NdisStatus, LocalTarget->NicId, Packet)); + goto error_complete; + } + } + } else { + // + // DISCARD was returned - call the upper driver's sendcomplete with error + // + + // + // Else return STATUS_NETWORK_UNREACHABLE + // + + NdisStatus = STATUS_NETWORK_UNREACHABLE; + + error_complete: + + IPX_DEBUG (SEND, ("Calling the SendCompleteHandler of tightly bound driver with status: %lx\n", NdisStatus)); + (*Device->UpperDrivers[Reserved->Identifier].SendCompleteHandler)( + Packet, + NdisStatus); + } + } +} + + diff --git a/private/ntos/tdi/isn/ipx/sources.inc b/private/ntos/tdi/isn/ipx/sources.inc new file mode 100644 index 000000000..9e78c5493 --- /dev/null +++ b/private/ntos/tdi/isn/ipx/sources.inc @@ -0,0 +1,75 @@ +!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 \ + ..\rt.c + +PRECOMPILED_INCLUDE=..\precomp.h +PRECOMPILED_PCH=precomp.pch +PRECOMPILED_OBJ=precomp.obj + +SOURCES_USED=..\sources.inc + + diff --git a/private/ntos/tdi/isn/ipx/up/makefile b/private/ntos/tdi/isn/ipx/up/makefile new file mode 100644 index 000000000..6ee4f43fa --- /dev/null +++ b/private/ntos/tdi/isn/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/isn/ipx/up/nwlnkipx.prf b/private/ntos/tdi/isn/ipx/up/nwlnkipx.prf new file mode 100644 index 000000000..0c4359235 --- /dev/null +++ b/private/ntos/tdi/isn/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/isn/ipx/up/sources b/private/ntos/tdi/isn/ipx/up/sources new file mode 100644 index 000000000..85cdb3764 --- /dev/null +++ b/private/ntos/tdi/isn/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 diff --git a/private/ntos/tdi/isn/ipxroute/ipxroute.c b/private/ntos/tdi/isn/ipxroute/ipxroute.c new file mode 100644 index 000000000..d4e327f12 --- /dev/null +++ b/private/ntos/tdi/isn/ipxroute/ipxroute.c @@ -0,0 +1,1822 @@ +/**************************************************************************** +* (c) Copyright 1990, 1993 Micro Computer Systems, Inc. All rights reserved. +***************************************************************************** +* +* Title: IPX/SPX Compatible Source Routing Daemon for Windows NT +* +* Module: ipx/route/ipxroute.c +* +* Version: 1.00.00 +* +* Date: 04-08-93 +* +* Author: Brian Walker +* +***************************************************************************** +* +* Change Log: +* +* Date DevSFC Comment +* -------- ------ ------------------------------------------------------- +* 02-14-95 RamC Added command line options to support displaying +* Router Table, Router Statistics and SAP information. +* Basically a merge of ipxroute and Stefan's rttest. +***************************************************************************** +* +* Functional Description: +* +* +****************************************************************************/ +#include <nt.h> +#include <ntrtl.h> +#include <nturtl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <process.h> +#include <ntstapi.h> +#include <sys/stropts.h> +#include <windows.h> +#include "errno.h" +#include "tdi.h" +#include "isnkrnl.h" +#include "ipxrtmsg.h" +#include "..\rip\driver.h" +#include "utils.h" +#include "nwsap.h" + +typedef struct _IPX_ROUTE_ENTRY { + UCHAR Network[4]; + USHORT NicId; + UCHAR NextRouter[6]; + PVOID NdisBindingContext; + USHORT Flags; + USHORT Timer; + UINT Segment; + USHORT TickCount; + USHORT HopCount; + PVOID AlternateRoute[2]; + PVOID NicLinkage[2]; + struct { + PVOID Linkage[2]; + ULONG Reserved[1]; + } PRIVATE; +} IPX_ROUTE_ENTRY, * PIPX_ROUTE_ENTRY; + + + + +IPX_ROUTE_ENTRY rte; + +/** Global Variables **/ + +int sr_def = 0; +int sr_bcast = 0; +int sr_multi = 0; +int boardnum = 0; +int clear = 0; +int config = 0; +int showtable = 0; +int showservers = 0; +int showstats = 0; +int clearstats = 0; +int servertype; +char nodeaddr[6]; /* Node address to remove */ +HANDLE nwlinkfd; +HANDLE isnipxfd; +HANDLE isnripfd; +char ebuffer[128]; + +char nwlinkname[] = "\\Device\\Streams\\NWLinkIpx"; +wchar_t isnipxname[] = L"\\Device\\NwlnkIpx"; +wchar_t isnripname[] = L"\\Device\\Ipxroute"; +char pgmname[] = "IPXROUTE"; +#define SHOW_ALL_SERVERS 0XFFFF + +/** **/ + +#define INVALID_HANDLE (HANDLE)(-1) + +/** Structure to send REMOVE with **/ + +typedef struct rterem { + int rterem_bnum; /* Board number */ + char rterem_node[6]; /* Node to remove */ +} rterem; + +typedef int (_CRTAPI1 * PQSORT_COMPARE)(const void * p0, const void * p1); + +/** Internal Function Prototypes **/ + +extern void print_table(int); +extern void usage(void); +extern void print_version(void); +extern char *print_type(int); +extern int my_strncmp(char *, char *, int); +extern int get_board_num(char *, int *); +extern int get_node_num(char *, char *); +extern int get_server_type(char *, int *); +extern unsigned char get_hex_byte(char *); +extern int get_driver_parms(void); +extern int set_driver_parms(void); +extern int do_strioctl(HANDLE, int, char *, int, int); +extern void remove_address(char *); +extern void clear_table(void); +extern void print_config(void); +extern unsigned long get_emsg(int); +int do_isnipxioctl(HANDLE fd, int cmd, char *datap, int dlen); +unsigned long put_msg(BOOLEAN error, unsigned long MsgNum, ... ); +char *load_msg( unsigned long MsgNum, ... ); +extern void show_router_table(PHANDLE, PIO_STATUS_BLOCK); +extern void show_stats(HANDLE, PIO_STATUS_BLOCK); +extern void clear_stats(HANDLE, PIO_STATUS_BLOCK); +extern void show_servers(int); +extern int _CRTAPI1 CompareServerNames( void * p0, void * p1); +extern int _CRTAPI1 CompareNetNumber( void * p0, void * p1); + +/*page************************************************************* + m a i n + + This is the main routine that gets executed when a NET START + happens. + + Arguments - None + + Returns - Nothing +********************************************************************/ +void _CRTAPI1 main(int argc, char **argv) +{ + char *p; + int todo; + int remove_flag; + UNICODE_STRING FileString; + OBJECT_ATTRIBUTES ObjectAttributes, RouterObjectAttributes; + IO_STATUS_BLOCK IoStatusBlock, RouterIoStatusBlock; + NTSTATUS Status; + + /** **/ + + print_version(); + + /** Open the nwlink driver **/ + + nwlinkfd = s_open(nwlinkname, 0, 0); + + /** Open the isnipx driver **/ + + RtlInitUnicodeString (&FileString, isnipxname); + + InitializeObjectAttributes( + &ObjectAttributes, + &FileString, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + + Status = NtOpenFile( + &isnipxfd, + SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA, + &ObjectAttributes, + &IoStatusBlock, + FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_SYNCHRONOUS_IO_ALERT); + + if (!NT_SUCCESS(Status)) { + isnipxfd = INVALID_HANDLE; + put_msg (TRUE, MSG_OPEN_FAILED, "\\Device\\NwlnkIpx"); + } + + /** Open the isnrip driver **/ + + RtlInitUnicodeString (&FileString, isnripname); + + InitializeObjectAttributes( + &RouterObjectAttributes, + &FileString, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + + Status = NtOpenFile( + &isnripfd, + SYNCHRONIZE | GENERIC_READ, + &RouterObjectAttributes, + &RouterIoStatusBlock, + FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_SYNCHRONOUS_IO_NONALERT); + + if (!NT_SUCCESS(Status)) { + isnripfd = INVALID_HANDLE; + // don't display any error message, but display the + // message that the IPX router is not started when + // the user actually tries to look at the router. + } + + if ((nwlinkfd == INVALID_HANDLE) && + (isnipxfd == INVALID_HANDLE) && + (isnripfd == INVALID_HANDLE)) + { + exit(1); + } + + + /** Go thru the command line and set it up **/ + + argc--; + argv++; + + /** Parse the command line **/ + + todo = 0; + remove_flag = 0; + while (argc--) { + + /** Uppercase the arg **/ + + p = *argv; + _strupr(p); + + /** Parse the argument **/ + + if (!strcmp(p, "CLEAR")) { + todo = 1; + clear = 1; + } + else if (!strcmp(p, "DEF")) { + todo = 1; + sr_def = 1; + } + else if (!strcmp(p, "GBR")) { + todo = 1; + sr_bcast = 1; + } + else if (!strcmp(p, "MBR")) { + todo = 1; + sr_multi = 1; + } + else if (!strcmp(p, "CONFIG")) { + todo = 1; + config = 1; + } + else if (!my_strncmp(p, "BOARD=", 6)) + get_board_num(p + 6, &boardnum); + else if (!my_strncmp(p, "REMOVE=", 7)) { + remove_flag = 1; + get_node_num(p + 7, nodeaddr); + } + else if (!strcmp(p, "TABLE")) { + todo = 1; + showtable = 1; + } + else if (!strcmp(p, "SERVERS")) { + todo = 1; + showservers = 1; + /** default is to show all server types **/ + servertype = SHOW_ALL_SERVERS; + argv++; + if(argc--) { + p = *argv; + _strupr(p); + if (!my_strncmp(p, "/TYPE=", 6)) { + get_server_type(p + 6, &servertype); + } + else + usage(); + } + /** no more arguments - break out of while lop **/ + else + break; + } + else if (!strcmp(p, "STATS")) { + todo = 1; + /** default is to show the router statistics **/ + showstats = 1; + argv++; + if(argc--) { + p = *argv; + _strupr(p); + if (!strcmp(p, "/CLEAR")) { + clearstats = 1; + showstats = 0; + } + else if (!strcmp(p, "/SHOW")) { + showstats = 1; + } + else + usage; + } + /** no more arguments - break out of while lop **/ + else + break; + } + else + usage(); + + /** Goto the next entry **/ + + argv++; + } + + /** Go update the driver **/ + +#if 0 + printf("todo = %d\n", todo); + printf("remove_flag= %d\n", remove_flag); + printf("Clear flag = %d\n", clear); + printf("Config flag = %d\n", config); + printf("SR_DEF = %d\n", sr_def); + printf("SR_BCAST = %d\n", sr_bcast); + printf("SR_MULTI = %d\n", sr_multi); + printf("Board = %d\n", boardnum); + printf("Node = %02x:%02x:%02x:%02x:%02x:%02x\n", + (unsigned char)nodeaddr[0], + (unsigned char)nodeaddr[1], + (unsigned char)nodeaddr[2], + (unsigned char)nodeaddr[3], + (unsigned char)nodeaddr[4], + (unsigned char)nodeaddr[5]); +#endif + + /** If we have a remove - go remove it and leave **/ + + if (remove_flag) + remove_address(nodeaddr); /* Does not return */ + + /** If clear - go clear the source routing table **/ + + if (clear) + clear_table(); /* Does not return */ + + /** If config - print out config **/ + + if (config) + print_config(); /* Does not return */ + + /** If showtable - print out routing table **/ + + if (showtable) + show_router_table(&isnripfd, &RouterIoStatusBlock); /* Does not return */ + + /** If showservers - print out selected servers list **/ + + if (showservers) + show_servers(servertype); /* Does not return */ + + /** If showstats - print out statistics **/ + + if (showstats) + show_stats(&isnripfd, &RouterIoStatusBlock); /* Does not return */ + + /** If clearstats - go clear statistics **/ + + if (clearstats) + clear_stats(&isnripfd, &RouterIoStatusBlock); /* Does not return */ + + /** If there is nothing to do - just print out everything **/ + + if (!todo) { + + /** Get the driver parms **/ + + if (get_driver_parms()) { + if (isnipxfd != INVALID_HANDLE) NtClose(isnipxfd); + if (nwlinkfd != INVALID_HANDLE) NtClose(nwlinkfd); + if (isnripfd != INVALID_HANDLE) NtClose(isnripfd); + exit(1); + } + + /** Print out the table (Never comes back) **/ + + print_table(1); + } + + /** Go set the parameters **/ + + set_driver_parms(); + + /** Print the table out **/ + + print_table(0); + + /** All Done **/ + + if (isnipxfd != INVALID_HANDLE) NtClose(isnipxfd); + if (nwlinkfd != INVALID_HANDLE) NtClose(nwlinkfd); + if (isnripfd != INVALID_HANDLE) NtClose(isnripfd); + exit(0); +} + +/*page************************************************************* + p r i n t _ t a b l e + + Print out the status of the source routing. + + Arguments - flag = 0 - Do NOT print the table + 1 - Do print the table (Never returns) + + Returns - Nothing +********************************************************************/ +void print_table(int flag) +{ + /** Print the information **/ + + char * ptype; + + printf("\n"); + ptype = print_type(sr_def); + put_msg (FALSE, MSG_DEFAULT_NODE, ptype); + LocalFree (ptype); + printf("\n"); + + ptype = print_type(sr_bcast); + put_msg (FALSE, MSG_BROADCAST, ptype); + LocalFree (ptype); + printf("\n"); + + ptype = print_type(sr_multi); + put_msg (FALSE, MSG_MULTICAST, ptype); + LocalFree (ptype); + printf("\n"); + + if (!flag) + return; + +#if 0 + printf("\n"); + printf(" Node Address Source Route\n"); + printf("\n"); +#endif + + /** All Done **/ + + if (isnipxfd != INVALID_HANDLE) NtClose(isnipxfd); + if (nwlinkfd != INVALID_HANDLE) NtClose(nwlinkfd); + if (isnripfd != INVALID_HANDLE) NtClose(isnripfd); + exit(0); +} + +/*page************************************************************* + u s a g e + + Print the usage message. + + Arguments - None + + Returns - Nothing +********************************************************************/ +void usage(void) +{ + put_msg( FALSE, MSG_USAGE, pgmname ); + + /** All Done **/ + + if (isnipxfd != INVALID_HANDLE) NtClose(isnipxfd); + if (nwlinkfd != INVALID_HANDLE) NtClose(nwlinkfd); + if (isnripfd != INVALID_HANDLE) NtClose(isnripfd); + exit(0); +} + +/*page************************************************************* + p r i n t _ v e r s i o n + + Print the version number + + Arguments - None + + Returns - Nothing +********************************************************************/ +void print_version(void) +{ + printf("\n"); + put_msg (FALSE, MSG_VERSION); + return; +} + +/*page************************************************************* + p r i n t _ t y p e + + Returns the broadcast type given in a string, the caller + must free the string. + + Arguments - 0 = SINGLE ROUTE + Else = ALL ROUTES + + Returns - Nothing +********************************************************************/ +char *print_type(int flag) +{ + if (flag) + return load_msg (MSG_ALL_ROUTE); + else + return load_msg (MSG_SINGLE_ROUTE); + +} + +/*page************************************************************* + m y _ s t r n c m p + + Given a string (p), see if the first len chars are the same + as those of the 2nd string (s). + + Arguments - p = Ptr to first string + s = Ptr to 2nd string + len = Length to check + + Returns - 0 = Matched + Else = Not matched +********************************************************************/ +int my_strncmp(char *p, char *s, int len) +{ + /** **/ + + while (len--) { + if (*p++ != *s++) + return 1; + } + + /** They matched **/ + + return 0; +} + +/*page************************************************************* + g e t _ b o a r d _ n u m + + Get the decimal number from the command line + + Arguments - p = Ptr to the ASCII number + nump = Store the number here + + Returns - 0 = Got the number OK + Else = Bad number +********************************************************************/ +int get_board_num(char *p, int *nump) +{ + *nump = atoi(p); + return 0; +} + +/*page************************************************************* + g e t _ n o d e _ n u m + + Get a node address from the command line + + Arguments - p = Ptr to the ASCII number + nodep = Store the node number here + + Returns - 0 = Got the number OK + Else = Bad number +********************************************************************/ +int get_node_num(char *p, char *nodep) +{ + int i; + unsigned char c1; + unsigned char c2; + + /** **/ + + if (strlen(p) != 12) { + put_msg (TRUE, MSG_INVALID_REMOVE); + exit(1); + } + + /** Get the number **/ + + for (i = 0 ; i < 6 ; i++) { + + /** Get the next 2 digits **/ + + c1 = get_hex_byte(p++); + c2 = get_hex_byte(p++); + + /** If we got a bad number - return error **/ + + if ((c1 == 0xFF) || (c2 == 0xFF)) { + put_msg (TRUE, MSG_INVALID_REMOVE); + exit(1); + } + + /** Set the next byte **/ + + *nodep++ = (c1 << 4) + c2; + } + + /** Return OK **/ + + return 0; +} + +/*page************************************************************* + g e t _ s e r v e r _ t y p e + + Get the decimal number from the command line + + Arguments - p = Ptr to the ASCII number + nump = Store the number here + + Returns - 0 = Got the number OK + Else = Bad number +********************************************************************/ +int get_server_type(char *p, int *nump) +{ + *nump = atoi(p); + return 0; +} + +/*page************************************************************* + g e t _ h e x _ b y t e + + Take 1 ascii hex chars and convert to a hex byte + + Arguments - p = Ptr to the ASCII number + + Returns - The number + (0xFF = Error) +********************************************************************/ +unsigned char get_hex_byte(char *p) +{ + unsigned char c; + + /** Get the char **/ + + c = *(unsigned char *)p; + + /** If 0-9 handle it **/ + + if ((c >= '0') && (c <= '9')) { + c -= '0'; + return c; + } + + /** If A-F handle it **/ + + if ((c >= 'A') && (c <= 'F')) { + c -= ('A' - 10); + return c; + } + + /** This is a bad number **/ + + return 0xFF; +} + + +/*page*************************************************************** + g e t _ d r i v e r _ p a r m s + + Get the parameters from the driver + + Arguments - None + + Returns - 0 = OK + else = Error +********************************************************************/ +int get_driver_parms() +{ + int rc; + int buffer[4]; + + /** Set the board number **/ + + buffer[0] = boardnum; + + /** Get the parms **/ + + if (nwlinkfd != INVALID_HANDLE) { + rc = do_strioctl(nwlinkfd, MIPX_SRGETPARMS, (char *)buffer, 4*sizeof(int), 0); + if (rc) { + + /** Get the error code **/ + + rc = GetLastError(); + put_msg (TRUE, MSG_BAD_PARAMETERS, "nwlink"); + put_msg (TRUE, get_emsg(rc)); + + /** Return the error **/ + + return rc; + } + } + + if (isnipxfd != INVALID_HANDLE) { + rc = do_isnipxioctl(isnipxfd, MIPX_SRGETPARMS, (char *)buffer, 4*sizeof(int)); + if (rc) { + + put_msg (TRUE, MSG_BAD_PARAMETERS, "nwlnkipx"); + put_msg (TRUE, get_emsg(rc)); + + /** Return the error **/ + + return rc; + } + } + + /** Get the variables **/ + + sr_def = buffer[1]; + sr_bcast = buffer[2]; + sr_multi = buffer[3]; + + /** Return OK **/ + + return 0; +} + +/*page*************************************************************** + s e t _ d r i v e r _ p a r m s + + Set the parameters for the driver + + Arguments - None + + Returns - 0 = OK + else = Error +********************************************************************/ +int set_driver_parms() +{ + int rc; + int buffer[2]; + + /** Set the DEFAULT parm **/ + + buffer[0] = boardnum; + buffer[1] = sr_def; + + if (nwlinkfd != INVALID_HANDLE) { + rc = do_strioctl(nwlinkfd, MIPX_SRDEF, (char *)buffer, 2 * sizeof(int), 0); + if (rc) { + rc = GetLastError(); + put_msg (TRUE, MSG_SET_DEFAULT_ERROR, "nwlink"); + put_msg (TRUE, get_emsg(rc)); + return rc; + } + } + if (isnipxfd != INVALID_HANDLE) { + rc = do_isnipxioctl(isnipxfd, MIPX_SRDEF, (char *)buffer, 2 * sizeof(int)); + if (rc) { + put_msg (TRUE, MSG_SET_DEFAULT_ERROR, "nwlnkipx"); + put_msg (TRUE, get_emsg(rc)); + return rc; + } + } + + /** Set the BROADCAST parm **/ + + buffer[0] = boardnum; + buffer[1] = sr_bcast; + + if (nwlinkfd != INVALID_HANDLE) { + rc = do_strioctl(nwlinkfd, MIPX_SRBCAST, (char *)buffer, 2 * sizeof(int), 0); + if (rc) { + rc = GetLastError(); + put_msg (TRUE, MSG_SET_BROADCAST_ERROR, "nwlink"); + put_msg (TRUE, get_emsg(rc)); + return rc; + } + } + if (isnipxfd != INVALID_HANDLE) { + rc = do_isnipxioctl(isnipxfd, MIPX_SRBCAST, (char *)buffer, 2 * sizeof(int)); + if (rc) { + put_msg (TRUE, MSG_SET_BROADCAST_ERROR, "nwlnkipx"); + put_msg (TRUE, get_emsg(rc)); + return rc; + } + } + + /** Set the MULTICAST parm **/ + + buffer[0] = boardnum; + buffer[1] = sr_multi; + + if (nwlinkfd != INVALID_HANDLE) { + rc = do_strioctl(nwlinkfd, MIPX_SRMULTI, (char *)buffer, 2 * sizeof(int), 0); + if (rc) { + rc = GetLastError(); + put_msg (TRUE, MSG_SET_MULTICAST_ERROR, "nwlink"); + put_msg (TRUE, get_emsg(rc)); + return rc; + } + } + if (isnipxfd != INVALID_HANDLE) { + rc = do_isnipxioctl(isnipxfd, MIPX_SRMULTI, (char *)buffer, 2 * sizeof(int)); + if (rc) { + put_msg (TRUE, MSG_SET_MULTICAST_ERROR, "nwlnkipx"); + put_msg (TRUE, get_emsg(rc)); + return rc; + } + } + + /** Return OK **/ + + return 0; +} + +/*page*************************************************************** + d o _ s t r i o c t l + + Do a stream ioctl + + Arguments - fd = Handle to put on + cmd = Command to send + datap = Ptr to ctrl buffer + dlen = Ptr to len of data buffer + timout = Timeout value + + Returns - 0 = OK + else = Error +********************************************************************/ +int do_strioctl(HANDLE fd, int cmd, char *datap, int dlen, int timout) +{ + int rc; + struct strioctl io; + + /** Fill out the structure **/ + + io.ic_cmd = cmd; + io.ic_dp = datap; + io.ic_len = dlen; + io.ic_timout = timout; + + /** Issue the ioctl **/ + + rc = s_ioctl(fd, I_STR, &io); + + /** All Done **/ + + return rc; +} + +/*page*************************************************************** + r e m o v e _ a d d r e s s + + Remove an address from the source routing table. + + Arguments - nodep = Ptr to node address to remove + + Returns - Does not return +********************************************************************/ +void remove_address(char *nodep) +{ + int rc; + int len; + rterem buf; + + /** Build the area to send down to the driver **/ + + buf.rterem_bnum = boardnum; + memcpy(buf.rterem_node, nodep, 6); + len = sizeof(int) + 6; + + /** Send the ioctl to remove the address **/ + + if (nwlinkfd != INVALID_HANDLE) { + rc = do_strioctl(nwlinkfd, MIPX_SRREMOVE, (char *)&buf, len, 0); + if (rc) { + rc = GetLastError(); + put_msg (TRUE, MSG_REMOVE_ADDRESS_ERROR, "nwlink"); + put_msg (TRUE, get_emsg(rc)); + } + } + if (isnipxfd != INVALID_HANDLE) { + rc = do_isnipxioctl(isnipxfd, MIPX_SRREMOVE, (char *)&buf, len); + if (rc) { + put_msg (TRUE, MSG_REMOVE_ADDRESS_ERROR, "nwlnkipx"); + if (rc == EINVAL) { + put_msg (TRUE, MSG_ADDRESS_NOT_FOUND); + } else { + put_msg (TRUE, get_emsg(rc)); + } + } + } + + /** Close up and exit **/ + + if (isnipxfd != INVALID_HANDLE) NtClose(isnipxfd); + if (nwlinkfd != INVALID_HANDLE) NtClose(nwlinkfd); + if (isnripfd != INVALID_HANDLE) NtClose(isnripfd); + exit(0); +} + +/*page*************************************************************** + c l e a r _ t a b l e + + Clear out the routing table + + Arguments - None + + Returns - Does not return +********************************************************************/ +void clear_table(void) +{ + int rc; + + /** Send the ioctl to clear the table **/ + + if (nwlinkfd != INVALID_HANDLE) { + rc = do_strioctl(nwlinkfd, MIPX_SRCLEAR, (char *)&boardnum, sizeof(int), 0); + if (rc) { + rc= GetLastError(); + put_msg (TRUE, MSG_CLEAR_TABLE_ERROR, "nwlink"); + put_msg (TRUE, get_emsg(rc)); + } + } + if (isnipxfd != INVALID_HANDLE) { + rc = do_isnipxioctl(isnipxfd, MIPX_SRCLEAR, (char *)&boardnum, sizeof(int)); + if (rc) { + put_msg (TRUE, MSG_CLEAR_TABLE_ERROR, "nwlnkipx"); + put_msg (TRUE, get_emsg(rc)); + } + } + + /** Close up and exit **/ + + if (isnipxfd != INVALID_HANDLE) NtClose(isnipxfd); + if (nwlinkfd != INVALID_HANDLE) NtClose(nwlinkfd); + if (isnripfd != INVALID_HANDLE) NtClose(isnripfd); + exit(0); +} + +typedef struct _ISN_ACTION_GET_DETAILS { + USHORT NicId; // passed by caller + BOOLEAN BindingSet; // returns TRUE if in 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's MAC address. + WCHAR AdapterName[64]; // terminated with Unicode NULL +} ISN_ACTION_GET_DETAILS, *PISN_ACTION_GET_DETAILS; + +#define REORDER_ULONG(_Ulong) \ + ((((_Ulong) & 0xff000000) >> 24) | \ + (((_Ulong) & 0x00ff0000) >> 8) | \ + (((_Ulong) & 0x0000ff00) << 8) | \ + (((_Ulong) & 0x000000ff) << 24)) + + +/*page*************************************************************** + p r i n t _ c o n f i g + + Prints out the current config + + Arguments - None + + Returns - Does not return +********************************************************************/ +void print_config(void) +{ + int rc; + int nicid, nicidcount; + int showlegend = 0; + char nicidbuf[6]; + char network[9]; + char * frametype; + char node[13]; + char special[2]; + char adaptername[64]; + ISN_ACTION_GET_DETAILS getdetails; + + + if (isnipxfd != INVALID_HANDLE) { + + /** First query nicid 0 **/ + + getdetails.NicId = 0; + + rc = do_isnipxioctl(isnipxfd, MIPX_CONFIG, (char *)&getdetails, sizeof(getdetails)); + if (rc) { + put_msg (TRUE, MSG_QUERY_CONFIG_ERROR, "nwlnkipx"); + put_msg (TRUE, get_emsg(rc)); + goto errorexit; + } + + printf("\n"); + + if (getdetails.NetworkNumber != 0) { + sprintf (network, "%.8x", REORDER_ULONG(getdetails.NetworkNumber)); + put_msg (FALSE, MSG_SHOW_INTERNAL_NET, network); + } + + // + // The NicId 0 query returns the total number. + // + + nicidcount = getdetails.NicId; + + for (nicid = 1; nicid <= nicidcount; nicid++) { + + getdetails.NicId = nicid; + + rc = do_isnipxioctl(isnipxfd, MIPX_CONFIG, (char *)&getdetails, sizeof(getdetails)); + if (rc) { + continue; + } + + sprintf (nicidbuf, "%d", nicid); + sprintf (network, "%.8x", REORDER_ULONG(getdetails.NetworkNumber)); + + switch (getdetails.FrameType) { + case 0: frametype = load_msg (MSG_ETHERNET_II); break; + case 1: frametype = load_msg (MSG_802_3); break; + case 2: frametype = load_msg (MSG_802_2); break; + case 3: frametype = load_msg (MSG_SNAP); break; + case 4: frametype = load_msg (MSG_ARCNET); break; + default: frametype = load_msg (MSG_UNKNOWN); break; + } + sprintf (adaptername, "%ws", getdetails.AdapterName); + + sprintf (node, "%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x", + getdetails.Node[0], + getdetails.Node[1], + getdetails.Node[2], + getdetails.Node[3], + getdetails.Node[4], + getdetails.Node[5]); + + special[1] = '\0'; + if (getdetails.BindingSet) { + special[0] = '*'; + showlegend |= 1; + } else if (getdetails.Type == 2) { + special[0] = '+'; + showlegend |= 2; + } else if (getdetails.Type == 3) { + special[0] = '-'; + showlegend |= 4; + } else { + special[0] = '\0'; + } + + put_msg (FALSE, MSG_SHOW_NET_NUMBER, + nicidbuf, + network, + frametype, + adaptername, + node, + special); + + LocalFree (frametype); + + } + + if (showlegend) { + if (showlegend & 1) { + put_msg (FALSE, MSG_LEGEND_BINDING_SET); + } + if (showlegend & 2) { + put_msg (FALSE, MSG_LEGEND_ACTIVE_WAN); + } + if (showlegend & 4) { + put_msg (FALSE, MSG_LEGEND_DOWN_WAN); + } + printf("\n"); + } + + } + +errorexit: + + /** Close up and exit **/ + + if (isnipxfd != INVALID_HANDLE) NtClose(isnipxfd); + if (nwlinkfd != INVALID_HANDLE) NtClose(nwlinkfd); + if (isnripfd != INVALID_HANDLE) NtClose(isnripfd); + exit(0); +} + +/*page*************************************************************** + g e t _ e m s g + + Get an error message for an error + + Arguments - None + + Returns - Does not return +********************************************************************/ +unsigned long get_emsg(int rc) +{ + /** + We have 3 defined error codes that can come back. + + 1 - EINVAL means that we sent down parameters wrong + (SHOULD NEVER HAPPEN) + + 2 - ERANGE means that the board number is invalid + (CAN HAPPEN IF USER ENTERS BAD BOARD) + + 3 - ENOENT means that on remove - the address given + is not in the source routing table. + **/ + + switch (rc) { + + case EINVAL: + return MSG_INTERNAL_ERROR; + + case ERANGE: + return MSG_INVALID_BOARD; + + case ENOENT: + return MSG_ADDRESS_NOT_FOUND; + + default: + return MSG_UNKNOWN_ERROR; + } + +} + +/*page*************************************************************** + d o _ i s n i p x i o c t l + + Do the equivalent of a stream ioctl to isnipx + + Arguments - fd = Handle to put on + cmd = Command to send + datap = Ptr to ctrl buffer + dlen = Ptr to len of data buffer + + Returns - 0 = OK + else = Error +********************************************************************/ +int do_isnipxioctl(HANDLE fd, int cmd, char *datap, int dlen) +{ + NTSTATUS Status; + UCHAR buffer[sizeof(NWLINK_ACTION) + sizeof(ISN_ACTION_GET_DETAILS) - 1]; + PNWLINK_ACTION action; + IO_STATUS_BLOCK IoStatusBlock; + int rc; + + /** Fill out the structure **/ + + action = (PNWLINK_ACTION)buffer; + + action->Header.TransportId = ISN_ACTION_TRANSPORT_ID; + action->OptionType = NWLINK_OPTION_CONTROL; + action->BufferLength = sizeof(ULONG) + dlen; + action->Option = cmd; + RtlMoveMemory(action->Data, datap, dlen); + + /** Issue the ioctl **/ + + Status = NtDeviceIoControlFile( + fd, + NULL, + NULL, + NULL, + &IoStatusBlock, + IOCTL_TDI_ACTION, + NULL, + 0, + action, + FIELD_OFFSET(NWLINK_ACTION,Data) + dlen); + + if (Status != STATUS_SUCCESS) { + if (Status == STATUS_INVALID_PARAMETER) { + rc = ERANGE; + } else { + rc = EINVAL; + } + } else { + if (dlen > 0) { + RtlMoveMemory (datap, action->Data, dlen); + } + rc = 0; + } + + return rc; + +} + + +//***************************************************************************** +// +// Name: put_msg +// +// Description: Reads a message resource, formats it in the current language +// and displays the message. +// +// NOTE: This routine was stolen from net\sockets\tcpcmd\common2\util.c. +// +// Parameters: error - TRUE if this is an error message. +// unsigned long MsgNum: ID of the message resource. +// +// Returns: unsigned long: number of characters displayed. +// +// History: +// 01/05/93 JayPh Created. +// +//***************************************************************************** + +unsigned long put_msg(BOOLEAN error, unsigned long MsgNum, ... ) +{ + unsigned long msglen; + char *vp; + va_list arglist; + + va_start( arglist, MsgNum ); + msglen = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_HMODULE, + NULL, + MsgNum, + 0L, // Default country ID. + (LPTSTR)&vp, + 0, + &arglist ); + if ( msglen == 0 ) + { + return ( 0 ); + } + + fprintf( error ? stderr : stdout, "%s", vp ); + LocalFree( vp ); + + return ( msglen ); +} + + +//***************************************************************************** +// +// Name: load_msg +// +// Description: Reads and formats a message resource and returns a pointer +// to the buffer containing the formatted message. It is the +// responsibility of the caller to free the buffer. +// +// NOTE: This routine was stolen from net\sockets\tcpcmd\common2\util.c. +// +// Parameters: unsigned long MsgNum: ID of the message resource. +// +// Returns: char *: pointer to the message buffer, NULL if error. +// +// History: +// 01/05/93 JayPh Created. +// +//***************************************************************************** + +char *load_msg( unsigned long MsgNum, ... ) +{ + unsigned long msglen; + char *vp; + va_list arglist; + + va_start( arglist, MsgNum ); + msglen = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_HMODULE, + NULL, + MsgNum, + 0L, // Default country ID. + (LPTSTR)&vp, + 0, + &arglist ); + if ( msglen == 0 ) + { + return(0); + } + + return ( vp ); +} + + +#define MAX_NETWORK_INTERFACES 255 + +typedef struct router_info +{ + ULONG NetNumber; + USHORT TickCount; + USHORT HopCount; + USHORT NicId; + UCHAR InterfaceNumber[10]; +} ROUTER_INFO, *PROUTER_INFO; + +/*page*************************************************************** + s h o w _ r o u t e r _ t a b l e + + Display the IPX routing table + + Arguments - FileHandle = Router File Handle + IoStatusBlock = Device IO Status Block + + Returns - Does not return +********************************************************************/ +VOID +show_router_table( + PHANDLE FileHandle, + PIO_STATUS_BLOCK IoStatusBlock +) +{ + SHOW_NIC_INFO nis[MAX_NETWORK_INTERFACES]; + ULONG NetNumber; + char InterfaceNumber[10]; + NTSTATUS Status; + USHORT index, i, NumEntries, count; + char router_entry[128]; + char buffer[32]; + PROUTER_INFO RouterInfo = NULL; + + if (*FileHandle == INVALID_HANDLE) { + put_msg(TRUE, MSG_IPXROUTER_NOT_STARTED ); + goto exit_show_table; + } + /** First get the Network numbers for all interfaces **/ + + index = 0; + while(TRUE) { + + Status = NtDeviceIoControlFile( + *FileHandle, // HANDLE to File + NULL, // HANDLE to Event + NULL, // ApcRoutine + NULL, // ApcContext + IoStatusBlock, // IO_STATUS_BLOCK + IOCTL_IPXROUTER_SHOWNICINFO, // IoControlCode + &index, // Input Buffer + sizeof(USHORT), // Input Buffer Length + &nis[index], // Output Buffer + sizeof(SHOW_NIC_INFO)); // Output Buffer Length + + if(IoStatusBlock->Status == STATUS_NO_MORE_ENTRIES) { + break; + } + + index ++; + + if(Status != STATUS_SUCCESS) { + sprintf(buffer, "%x", Status); + put_msg(TRUE, MSG_SHOWSTATS_FAILED, buffer); + goto exit_show_table; + } + + if (index >= MAX_NETWORK_INTERFACES) { + // break out of this loop if there are more than 255 network + // interfaces because we only have storage for 255. + + break; + } + + } + + Status = NtDeviceIoControlFile( + *FileHandle, // HANDLE to File + NULL, // HANDLE to Event + NULL, // ApcRoutine + NULL, // ApcContext + IoStatusBlock, // IO_STATUS_BLOCK + IOCTL_IPXROUTER_SNAPROUTES, // IoControlCode + NULL, // Input Buffer + 0, // Input Buffer Length + NULL, // Output Buffer + 0); // Output Buffer Length + + if (IoStatusBlock->Status != STATUS_SUCCESS) { + sprintf(buffer, "%x", Status); + put_msg(TRUE, MSG_SNAPROUTES_FAILED, buffer); + goto exit_show_table; + } + + // first determine the number of router table entries to + // allocate sufficient storage + + NumEntries = 0; + while(TRUE) { + + Status = NtDeviceIoControlFile( + *FileHandle, // HANDLE to File + NULL, // HANDLE to Event + NULL, // ApcRoutine + NULL, // ApcContext + IoStatusBlock, // IO_STATUS_BLOCK + IOCTL_IPXROUTER_GETNEXTROUTE, // IoControlCode + NULL, // Input Buffer + 0, // Input Buffer Length + &rte, // Output Buffer + sizeof(IPX_ROUTE_ENTRY)); // Output Buffer Length + + if(IoStatusBlock->Status == STATUS_NO_MORE_ENTRIES) { + break; + } + + if(Status != STATUS_SUCCESS) { + sprintf(buffer,"%x",Status); + put_msg(TRUE, MSG_GETNEXTROUTE_FAILED, buffer); + goto exit_show_table; + } + + NumEntries ++; + } + + RouterInfo = (PROUTER_INFO) LocalAlloc(LPTR, sizeof(ROUTER_INFO) * NumEntries); + if(!RouterInfo) { + put_msg(FALSE, MSG_INSUFFICIENT_MEMORY); + goto exit_show_table; + } + + Status = NtDeviceIoControlFile( + *FileHandle, // HANDLE to File + NULL, // HANDLE to Event + NULL, // ApcRoutine + NULL, // ApcContext + IoStatusBlock, // IO_STATUS_BLOCK + IOCTL_IPXROUTER_SNAPROUTES, // IoControlCode + NULL, // Input Buffer + 0, // Input Buffer Length + NULL, // Output Buffer + 0); // Output Buffer Length + + if (IoStatusBlock->Status != STATUS_SUCCESS) { + sprintf(buffer, "%x", Status); + put_msg(TRUE, MSG_SNAPROUTES_FAILED, buffer); + goto exit_show_table; + } + + index = 0; + + while(TRUE) { + + Status = NtDeviceIoControlFile( + *FileHandle, // HANDLE to File + NULL, // HANDLE to Event + NULL, // ApcRoutine + NULL, // ApcContext + IoStatusBlock, // IO_STATUS_BLOCK + IOCTL_IPXROUTER_GETNEXTROUTE, // IoControlCode + NULL, // Input Buffer + 0, // Input Buffer Length + &rte, // Output Buffer + sizeof(IPX_ROUTE_ENTRY)); // Output Buffer Length + + if(IoStatusBlock->Status == STATUS_NO_MORE_ENTRIES) { + break; + } + + if(Status != STATUS_SUCCESS) { + sprintf(buffer,"%x",Status); + put_msg(TRUE, MSG_GETNEXTROUTE_FAILED, buffer); + goto exit_show_table; + } + + // make sure we don't exceed the number of entries + if (index > NumEntries) { + break; + } + + // get net nr in "on the wire" order + + GETLONG2ULONG(&(RouterInfo[index].NetNumber), rte.Network); + + // find out the matching Network number based on NIC ID + for(i=0; i < MAX_NETWORK_INTERFACES; i++) { + if(rte.NicId == nis[i].NicId) { + sprintf(RouterInfo[index].InterfaceNumber, "%.2x%.2x%.2x%.2x", + nis[i].Network[0], + nis[i].Network[1], + nis[i].Network[2], + nis[i].Network[3]); + break; + } + } + RouterInfo[index].TickCount = rte.TickCount; + RouterInfo[index].HopCount = rte.HopCount; + RouterInfo[index].NicId = rte.NicId; + + index++; + } + + // Now sort the entries by net number + qsort( (void*) RouterInfo, + NumEntries, + sizeof(ROUTER_INFO), + (PQSORT_COMPARE)CompareNetNumber ); + + put_msg(FALSE, MSG_ROUTER_TABLE_HEADER); + for(index =0, count = 0; index < NumEntries; index++, count++) + { + if (count > 50) { + count = 0; + // display router table header every 25 entries + // to make reading the table easier. + put_msg(FALSE, MSG_ROUTER_TABLE_HEADER); + } + printf("%.8x %6d %2d %-16s %d\n", + RouterInfo[index].NetNumber, + RouterInfo[index].TickCount, + RouterInfo[index].HopCount, + RouterInfo[index].InterfaceNumber, + RouterInfo[index].NicId ); + } + /** Close up and exit **/ +exit_show_table: + if (RouterInfo) LocalFree(RouterInfo); + if (isnipxfd != INVALID_HANDLE) NtClose(isnipxfd); + if (nwlinkfd != INVALID_HANDLE) NtClose(nwlinkfd); + if (isnripfd != INVALID_HANDLE) NtClose(isnripfd); + exit(0); +} + +int _CRTAPI1 CompareNetNumber( void * p0, void * p1) +{ + PROUTER_INFO pLeft = (PROUTER_INFO) p0; + PROUTER_INFO pRight = (PROUTER_INFO) p1; + + if(pLeft->NetNumber == pRight->NetNumber) + return(0); + if(pLeft->NetNumber > pRight->NetNumber) + return(1); + else + return(-1); +} + +PUCHAR DeviceType[2] = { "LAN", "WAN" }; +PUCHAR NicState[4] = { "CLOSED", "CLOSING", "ACTIVE", "PENDING_OPEN" }; + +/*page*************************************************************** + s h o w _ s t a t s + + Displays IPX internal routing statistics + + Arguments - FileHandle = Router File Handle + IoStatusBlock = Device IO Status Block + + Returns - Does not return +********************************************************************/ +VOID +show_stats( + PHANDLE FileHandle, + PIO_STATUS_BLOCK IoStatusBlock +) +{ + SHOW_NIC_INFO nis; + USHORT index, i; + char NicId[4]; + char NetworkNumber[10]; + char RipRcvd[32], RipSent[32]; + char RoutedRcvd[32], RoutedSent[32]; + char Type20Rcvd[32], Type20Sent[32]; + char BadRcvd[32]; + char buffer[32]; + + NTSTATUS Status; + + if (*FileHandle == INVALID_HANDLE) { + put_msg(TRUE, MSG_IPXROUTER_NOT_STARTED ); + goto end_stats; + } + + index = 0; + + while(TRUE) { + + Status = NtDeviceIoControlFile( + *FileHandle, // HANDLE to File + NULL, // HANDLE to Event + NULL, // ApcRoutine + NULL, // ApcContext + IoStatusBlock, // IO_STATUS_BLOCK + IOCTL_IPXROUTER_SHOWNICINFO, // IoControlCode + &index, // Input Buffer + sizeof(USHORT), // Input Buffer Length + &nis, // Output Buffer + sizeof(nis)); // Output Buffer Length + + if(IoStatusBlock->Status == STATUS_NO_MORE_ENTRIES) { + goto end_stats; + } + + index ++; + + if(Status != STATUS_SUCCESS) { + sprintf(buffer, "%x", Status); + put_msg(TRUE, MSG_SHOWSTATS_FAILED, buffer); + goto end_stats; + } + + sprintf(NicId, "%d", nis.NicId); + + sprintf(NetworkNumber, + "%.2x%.2x%.2x%.2x", + nis.Network[0], + nis.Network[1], + nis.Network[2], + nis.Network[3]); + + sprintf(RipRcvd, "%-8d", nis.StatRipReceived); + + sprintf(RipSent, "%-8d", nis.StatRipSent); + + sprintf(RoutedRcvd, "%-8d", nis.StatRoutedReceived); + + sprintf(RoutedSent, "%-8d", nis.StatRoutedSent); + + sprintf(Type20Rcvd, "%-8d", nis.StatType20Received); + + sprintf(Type20Sent, "%-8d", nis.StatType20Sent); + + sprintf(BadRcvd, "%-8d", nis.StatBadReceived); + + put_msg(FALSE, + MSG_SHOW_STATISTICS, + NicId, + NetworkNumber, + RipRcvd, + RipSent, + Type20Rcvd, + Type20Sent, + RoutedRcvd, + RoutedSent, + BadRcvd); + + } + + /** Close up and exit **/ + +end_stats: + if (isnipxfd != INVALID_HANDLE) NtClose(isnipxfd); + if (nwlinkfd != INVALID_HANDLE) NtClose(nwlinkfd); + if (isnripfd != INVALID_HANDLE) NtClose(isnripfd); + exit(0); +} + +/*page*************************************************************** + c l e a r _ s t a t s + + Clears the IPX internal routing statistics + + Arguments - FileHandle = Router File Handle + IoStatusBlock = Device IO Status Block + + Returns - Does not return +********************************************************************/ +VOID +clear_stats( + PHANDLE FileHandle, + PIO_STATUS_BLOCK IoStatusBlock +) +{ + NTSTATUS Status; + char buffer[32]; + + if (*FileHandle == INVALID_HANDLE) { + put_msg(TRUE, MSG_IPXROUTER_NOT_STARTED ); + goto end_clearstats; + } + + Status = NtDeviceIoControlFile( + *FileHandle, // HANDLE to File + NULL, // HANDLE to Event + NULL, // ApcRoutine + NULL, // ApcContext + IoStatusBlock, // IO_STATUS_BLOCK + IOCTL_IPXROUTER_ZERONICSTATISTICS, // IoControlCode + NULL, // Input Buffer + 0, // Input Buffer Length + NULL, // Output Buffer + 0); // Output Buffer Length + + if(Status != STATUS_SUCCESS) { + sprintf(buffer, "%x", Status); + put_msg(TRUE, MSG_CLEAR_STATS_FAILED, buffer); + } + /** Close up and exit **/ +end_clearstats: + if (isnipxfd != INVALID_HANDLE) NtClose(isnipxfd); + if (nwlinkfd != INVALID_HANDLE) NtClose(nwlinkfd); + if (isnripfd != INVALID_HANDLE) NtClose(isnripfd); + exit(0); +} + +typedef struct server_info +{ + USHORT ObjectType; + UCHAR ObjectName[100]; + UCHAR IpxAddress[12]; +} SERVER_INFO, *PSERVER_INFO; + +/*page*************************************************************** + s h o w _ s e r v e r s + + Display the servers from the SAP table + + Arguments - servertype = Type of servers to display + Defaults to show all server types + + Returns - Does not return +********************************************************************/ +VOID +show_servers(int servertype) +{ + INT rc; + ULONG ObjectID = 0xFFFFFFFF; + UCHAR ObjectName[100]; + USHORT ObjectType; + USHORT ScanType = servertype; + UCHAR IpxAddress[12]; + USHORT i; + USHORT index, count, NumServers; + + PSERVER_INFO ServerInfo = NULL; + + if(rc = SapLibInit() != SAPRETURN_SUCCESS) { + put_msg(TRUE, MSG_SAP_NOT_STARTED); + goto show_servers_end; + } + + memset(&ObjectName, 0, 100); + + // find out how many servers are there so that we can allocate + // sufficient storage + NumServers = 0; + + while((rc = SapScanObject(&ObjectID, + ObjectName, + &ObjectType, + ScanType)) == SAPRETURN_SUCCESS) + { + NumServers++; + } + + ServerInfo = (PSERVER_INFO) LocalAlloc(LPTR, sizeof(SERVER_INFO) * NumServers); + if(!ServerInfo) + { + put_msg(FALSE, MSG_INSUFFICIENT_MEMORY); + goto show_servers_end; + } + + index = 0; + ObjectID = 0xFFFFFFFF; + + while((rc = SapScanObject(&ObjectID, + ObjectName, + &ObjectType, + ScanType)) == SAPRETURN_SUCCESS) + { + if (index > NumServers) { + break; + } + + // get object address + SapGetObjectName(ObjectID, + ObjectName, + &ObjectType, + IpxAddress); + + ServerInfo[index].ObjectType = ObjectType; + strcpy(ServerInfo[index].ObjectName, ObjectName); + CopyMemory(ServerInfo[index].IpxAddress, IpxAddress, 12); + + index++; + } + + // Now sort the entries by server name + qsort( (void*) ServerInfo, + NumServers, + sizeof(SERVER_INFO), + (PQSORT_COMPARE)CompareServerNames ); + + if(servertype == SHOW_ALL_SERVERS) + put_msg(FALSE, MSG_SHOW_ALL_SERVERS_HEADER); + else + put_msg(FALSE, MSG_SHOW_SPECIFIC_SERVER_HEADER); + + for(index = 0, count = 0; index < NumServers; index++, count++) + { + if (count > 50) { + // write the table header for every 50 entries + // to make this more readable. + count = 0; + + if(servertype == SHOW_ALL_SERVERS) + put_msg(FALSE, MSG_SHOW_ALL_SERVERS_HEADER); + else + put_msg(FALSE, MSG_SHOW_SPECIFIC_SERVER_HEADER); + } + + for(i=0; i<4; i++) { + printf("%.2x", ServerInfo[index].IpxAddress[i]); + } + printf("."); + for(i=4; i<10; i++) { + printf("%.2x", ServerInfo[index].IpxAddress[i]); + } + + if(servertype == SHOW_ALL_SERVERS) { + printf(" %-6d", ServerInfo[index].ObjectType); + } + + printf(" %s\n", ServerInfo[index].ObjectName); + } + + /** Close up and exit **/ +show_servers_end: + if (ServerInfo) LocalFree(ServerInfo); + if (isnipxfd != INVALID_HANDLE) NtClose(isnipxfd); + if (nwlinkfd != INVALID_HANDLE) NtClose(nwlinkfd); + if (isnripfd != INVALID_HANDLE) NtClose(isnripfd); + exit(0); +} + +int _CRTAPI1 CompareServerNames( void * p0, void * p1) +{ + PSERVER_INFO pLeft = (PSERVER_INFO) p0; + PSERVER_INFO pRight = (PSERVER_INFO) p1; + + return(strcmp(pLeft->ObjectName, pRight->ObjectName)); +} + diff --git a/private/ntos/tdi/isn/ipxroute/ipxroute.rc b/private/ntos/tdi/isn/ipxroute/ipxroute.rc new file mode 100644 index 000000000..e56b3d767 --- /dev/null +++ b/private/ntos/tdi/isn/ipxroute/ipxroute.rc @@ -0,0 +1,13 @@ +#include <windows.h> + +#include <ntverp.h> + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN +#define VER_FILEDESCRIPTION_STR "NWLink Source Routing Application" +#define VER_INTERNALNAME_STR "ipxroute.exe" +#define VER_ORIGINALFILENAME_STR "ipxroute.exe" + +#include "common.ver" + +1 11 MSG00001.BIN diff --git a/private/ntos/tdi/isn/ipxroute/ipxrtmsg.mc b/private/ntos/tdi/isn/ipxroute/ipxrtmsg.mc new file mode 100644 index 000000000..47203d60e --- /dev/null +++ b/private/ntos/tdi/isn/ipxroute/ipxrtmsg.mc @@ -0,0 +1,252 @@ +; //*************************************************************************** +; // +; // Name: ipxroute.mc +; // +; // Description: Message file for ipxroute.exe +; // +; // History: +; // 07/14/94 AdamBa Created. +; // +; //*************************************************************************** +; +; //*************************************************************************** +; // +; // Copyright (c) 1994 by Microsoft Corp. All rights reserved. +; // +; //*************************************************************************** + +MessageId=10000 SymbolicName=MSG_USAGE +Language=English + +Display and modify information about the routing tables +used by IPX. + +IPX Routing Options +------------------- + +%1 servers [/type=xxxx] +%1 stats [/show] [/clear] +%1 table + + servers Displays the SAP table for the specified + server type. Server type is an integer value. + For example use %1 servers /type=4 to display + all file servers. If no type is specified, + servers of all types are shown. The displayed + list is sorted by server name. + + stats Displays or clears IPX router interface statistics. + If no option is specified, statistics are shown. + To clear the statistics specify /clear. + + table Displays the IPX routing table. The displayed + list is sorted by network number. + +Source Routing Options +---------------------- + +%1 board=n clear def gbr mbr remove=xxxxxxxxxxxx +%1 config + + board=n Specify the board number to check. + clear Clear the source routing table. + def Send packets that are destined for an + unknown address to the ALL ROUTES broadcast + (Default is SINGLE ROUTE broadcast). + gbr Send packets that are destined for the + broadcast address (FFFF FFFF FFFF) to the + ALL ROUTES broadcast + (Default is SINGLE ROUTE broadcast). + mbr Send packets that are destined for a + multicast address (C000 xxxx xxxx) to the + ALL ROUTES broadcast + (Default is SINGLE ROUTE broadcast). + remove=xxxx Remove the given mac address from the + source routing table. + + config Displays information on all the bindings + that IPX is configured for. + +All parameters should be separated by spaces. +. +MessageId=10001 SymbolicName=MSG_INTERNAL_ERROR +Language=English +Invalid parameters (internal error). +. +MessageId=10002 SymbolicName=MSG_INVALID_BOARD +Language=English +Invalid board number. +. +MessageId=10003 SymbolicName=MSG_ADDRESS_NOT_FOUND +Language=English +Address not in table. +. +MessageId=10004 SymbolicName=MSG_UNKNOWN_ERROR +Language=English +Unknown error. +. +MessageId=10005 SymbolicName=MSG_OPEN_FAILED +Language=English +Unable to open transport %1. +. +MessageId=10006 SymbolicName=MSG_VERSION +Language=English +NWLink IPX Routing and Source Routing Control Program v2.00 +. +MessageId=10007 SymbolicName=MSG_DEFAULT_NODE +Language=English + DEFault Node (Unknown) Addresses are sent %1 +. +MessageId=10008 SymbolicName=MSG_BROADCAST +Language=English + Broadcast (FFFF FFFF FFFF) Addresses are sent %1 +. +MessageId=10009 SymbolicName=MSG_MULTICAST +Language=English + Multicast (C000 xxxx xxxx) Addresses are sent %1 +. +MessageId=10010 SymbolicName=MSG_ALL_ROUTE +Language=English +ALL ROUTE BROADCAST%0 +. +MessageId=10011 SymbolicName=MSG_SINGLE_ROUTE +Language=English +SINGLE ROUTE BROADCAST%0 +. +MessageId=10012 SymbolicName=MSG_INVALID_REMOVE +Language=English +Invalid value for the remove node number. +. +MessageId=10013 SymbolicName=MSG_BAD_PARAMETERS +Language=English +Error getting parameters from IPX (%1): %0 +. +MessageId=10014 SymbolicName=MSG_SET_DEFAULT_ERROR +Language=English +Error setting DEFAULT flag to IPX (%1): %0 +. +MessageId=10015 SymbolicName=MSG_SET_BROADCAST_ERROR +Language=English +Error setting BROADCAST flag to IPX (%1): %0 +. +MessageId=10016 SymbolicName=MSG_SET_MULTICAST_ERROR +Language=English +Error setting MULTICAST flag to IPX (%1): %0 +. +MessageId=10017 SymbolicName=MSG_REMOVE_ADDRESS_ERROR +Language=English +Error removing address from source routing table (%1): %0 +. +MessageId=10018 SymbolicName=MSG_CLEAR_TABLE_ERROR +Language=English +Error clearing source routing table (%1): %0 +. +MessageId=10019 SymbolicName=MSG_QUERY_CONFIG_ERROR +Language=English +Error querying config (%1): %0 +. +MessageId=10020 SymbolicName=MSG_SHOW_INTERNAL_NET +Language=English +IPX internal network number %1 +. +MessageId=10021 SymbolicName=MSG_SHOW_NET_NUMBER +Language=English +net %1: network number %2, frame type %3, device %4 (%5)%6 +. +MessageId=10022 SymbolicName=MSG_ETHERNET_II +Language=English +ethernet ii%0 +. +MessageId=10023 SymbolicName=MSG_802_3 +Language=English +802.3%0 +. +MessageId=10024 SymbolicName=MSG_802_2 +Language=English +802.2%0 +. +MessageId=10025 SymbolicName=MSG_SNAP +Language=English +snap%0 +. +MessageId=10026 SymbolicName=MSG_ARCNET +Language=English +arcnet%0 +. +MessageId=10027 SymbolicName=MSG_UNKNOWN +Language=English +unknown%0 +. +MessageId=10028 SymbolicName=MSG_LEGEND_BINDING_SET +Language=English +* binding set member %0 +. +MessageId=10029 SymbolicName=MSG_LEGEND_ACTIVE_WAN +Language=English ++ active wan line %0 +. +MessageId=10030 SymbolicName=MSG_LEGEND_DOWN_WAN +Language=English +- down wan line %0 +. +MessageId=10031 SymbolicName=MSG_ROUTER_TABLE_HEADER +Language=English + +Net Number Ticks Hops Interface Net Number Interface ID +------------------------------------------------------------------------- +. +MessageId=10032 SymbolicName=MSG_SNAPROUTES_FAILED +Language=English +Ioctl snap routes to IPX router failed with error %1. +. +MessageId=10033 SymbolicName=MSG_GETNEXTROUTE_FAILED +Language=English +Failed to get the next route from the IPX router with error %1. +. +MessageId=10034 SymbolicName=MSG_SHOWSTATS_FAILED +Language=English +Failed to get the internal router statistics with error %1. +. +MessageId=10035 SymbolicName=MSG_SHOW_STATISTICS +Language=English + +Network Interface ID = %1 +Network Interface Number = %2 +RIP packets: received = %3 sent = %4 +Type 20 packets: received = %5 sent = %6 +Forwarded packets: received = %7 sent = %8 +Discarded packets: received = %9 +. +MessageId=10036 SymbolicName=MSG_CLEAR_STATS_FAILED +Language=English +Ioctl to clear statistics failed with error %1. +. +MessageId=10037 SymbolicName=MSG_SHOW_ALL_SERVERS_HEADER +Language=English + +IPX Address Server Type Server Name +------------------------------------------------------- +. +MessageId=10038 SymbolicName=MSG_SHOW_SPECIFIC_SERVER_HEADER +Language=English + +IPX Address Server Name +---------------------------------------- +. +MessageId=10039 SymbolicName=MSG_IPXROUTER_NOT_STARTED +Language=English + +Unable to set/get information from the IPX router. +Make sure that the IPX router service (NWLNKRIP) is started. +. +MessageId=10040 SymbolicName=MSG_SAP_NOT_STARTED +Language=English + +Unable to get information from the SAP agent. +Make sure that the SAP agent service (NWSAPAGENT) is started. +. +MessageId=10041 SymbolicName=MSG_INSUFFICIENT_MEMORY +Language=English +Cannot allocate sufficient memory. Close other applications and try this operation. +. +
\ No newline at end of file diff --git a/private/ntos/tdi/isn/ipxroute/makefile b/private/ntos/tdi/isn/ipxroute/makefile new file mode 100644 index 000000000..6ee4f43fa --- /dev/null +++ b/private/ntos/tdi/isn/ipxroute/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/isn/ipxroute/makefile.inc b/private/ntos/tdi/isn/ipxroute/makefile.inc new file mode 100644 index 000000000..ce99ed09d --- /dev/null +++ b/private/ntos/tdi/isn/ipxroute/makefile.inc @@ -0,0 +1,13 @@ +IPX_BASENAME = $(TARGETNAME).exe + +NLINKEXENAME = obj\$(TARGET_DIRECTORY)\$(IPX_BASENAME) + +NLINKBINNAME = $(BASEDIR)\public\sdk\lib\$(TARGET_DIRECTORY)\$(IPX_BASENAME) + +$(NLINKBINNAME): $(NLINKEXENAME) + copy $(NLINKEXENAME) $(NLINKBINNAME) + +ipxroute.rc: ipxrtmsg.rc msg00001.bin + +ipxrtmsg.h ipxrtmsg.rc msg00001.bin: ipxrtmsg.mc + mc -v ipxrtmsg.mc diff --git a/private/ntos/tdi/isn/ipxroute/sources b/private/ntos/tdi/isn/ipxroute/sources new file mode 100644 index 000000000..de1fcda6b --- /dev/null +++ b/private/ntos/tdi/isn/ipxroute/sources @@ -0,0 +1,36 @@ +!IF 0 + +Copyright (c) 1993 Micro Computer Systems, Inc. + +!ENDIF + +MAJORCOMP=nwlink +MINORCOMP=ipxroute + +TARGETNAME=ipxroute +TARGETPATH=$(BASEDIR)\public\sdk\lib +TARGETTYPE=UMAPPL_NOLIB + +USE_CRTDLL=1 + +C_DEFINES=$(C_DEFINES) + +!IF 0 +INCLUDES=..\h;..\..\..\..\..\inc;..\..\..\..\inc;..\..\..\inc +!ELSE +INCLUDES=..\h;$(BASEDIR)\private\inc;$(BASEDIR)\private\ntos\inc;$(BASEDIR)\private\ntos\streams\inc;$(BASEDIR)\private\net\inc +!ENDIF + +MSC_WARNING_LEVEL=/W3 /WX + +SOURCES= ipxroute.rc + +UMTYPE=console +UMAPPL=$(TARGETNAME) +UMLIBS=$(BASEDIR)\public\sdk\lib\*\ntdll.lib \ + $(BASEDIR)\public\sdk\lib\*\winstrm.lib \ + $(BASEDIR)\public\sdk\lib\*\nwsaplib.lib + +UMRES=obj\*\ipxroute.res + +NTTARGETFILE0=ipxrtmsg.h ipxrtmsg.mc ipxroute.rc diff --git a/private/ntos/tdi/isn/ipxroute/utils.h b/private/ntos/tdi/isn/ipxroute/utils.h new file mode 100644 index 000000000..afacd2a35 --- /dev/null +++ b/private/ntos/tdi/isn/ipxroute/utils.h @@ -0,0 +1,55 @@ +/*******************************************************************/ +/* Copyright(c) 1993 Microsoft Corporation */ +/*******************************************************************/ + +//*** +// +// Filename: utils.h +// +// Description: Contains miscellaneous utilities +// +// Author: Stefan Solomon (stefans) October 4, 1993. +// +// Revision History: +// +//*** + +#ifndef _UTILS_ +#define _UTILS_ + +/* + * The following macros deal with on-the-wire short and long values + * + * On the wire format is big-endian i.e. a long value of 0x01020304 is + * represented as 01 02 03 04. + * Similarly a short value of 0x0102 is represented as 01 02. + * + * The host format is not assumed since it will vary from processor to + * processor. + */ + +// Get a short from on-the-wire format to a USHORT in the host format +#define GETSHORT2USHORT(DstPtr, SrcPtr) \ + *(PUSHORT)(DstPtr) = ((*((PUCHAR)(SrcPtr)+0) << 8) + \ + (*((PUCHAR)(SrcPtr)+1) )) + +// Get a long from on-the-wire format to a ULONG in the host format +#define GETLONG2ULONG(DstPtr, SrcPtr) \ + *(PULONG)(DstPtr) = ((*((PUCHAR)(SrcPtr)+0) << 24) + \ + (*((PUCHAR)(SrcPtr)+1) << 16) + \ + (*((PUCHAR)(SrcPtr)+2) << 8) + \ + (*((PUCHAR)(SrcPtr)+3) )) + +// Put a USHORT from the host format to a short to on-the-wire format +#define PUTUSHORT2SHORT(DstPtr, Src) \ + *((PUCHAR)(DstPtr)+0) = (UCHAR) ((USHORT)(Src) >> 8), \ + *((PUCHAR)(DstPtr)+1) = (UCHAR)(Src) + +// Put a ULONG from the host format to an array of 4 UCHARs on-the-wire format +#define PUTULONG2LONG(DstPtr, Src) \ + *((PUCHAR)(DstPtr)+0) = (UCHAR) ((ULONG)(Src) >> 24), \ + *((PUCHAR)(DstPtr)+1) = (UCHAR) ((ULONG)(Src) >> 16), \ + *((PUCHAR)(DstPtr)+2) = (UCHAR) ((ULONG)(Src) >> 8), \ + *((PUCHAR)(DstPtr)+3) = (UCHAR) (Src) + +#endif // _UTILS_ |