/*++
Copyright (c) 1989-1993 Microsoft Corporation
Module Name:
action.c
Abstract:
This module contains code which performs the following TDI services:
o TdiAction
Environment:
Kernel mode
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
#include <packon.h>
typedef struct _GET_PKT_SIZE {
ULONG Unknown;
ULONG MaxDatagramSize;
} GET_PKT_SIZE, *PGET_PKT_SIZE;
//
// These structures are used to set and query information
// about our source routing table.
//
typedef struct _SR_GET_PARAMETERS {
ULONG BoardNumber; // 0-based
ULONG SrDefault; // 0 = single route, 1 = all routes
ULONG SrBroadcast;
ULONG SrMulticast;
} SR_GET_PARAMETERS, *PSR_GET_PARAMETERS;
typedef struct _SR_SET_PARAMETER {
ULONG BoardNumber; // 0-based
ULONG Parameter; // 0 = single route, 1 = all routes
} SR_SET_PARAMETER, *PSR_SET_PARAMETER;
typedef struct _SR_SET_REMOVE {
ULONG BoardNumber; // 0-based
UCHAR MacAddress[6]; // remote to drop routing for
} SR_SET_REMOVE, *PSR_SET_REMOVE;
typedef struct _SR_SET_CLEAR {
ULONG BoardNumber; // 0-based
} SR_SET_CLEAR, *PSR_SET_CLEAR;
#include <packoff.h>
typedef struct _ISN_ACTION_GET_DETAILS {
USHORT NicId; // passed by caller, returns count if it is 0
BOOLEAN BindingSet; // returns TRUE if in a set
UCHAR Type; // 1 = lan, 2 = up wan, 3 = down wan
ULONG FrameType; // returns 0 through 3
ULONG NetworkNumber; // returns virtual net if NicId is 0
UCHAR Node[6]; // adapter MAC address
WCHAR AdapterName[64]; // terminated with Unicode NULL
} ISN_ACTION_GET_DETAILS, *PISN_ACTION_GET_DETAILS;
NTSTATUS
IpxTdiAction(
IN PDEVICE Device,
IN PREQUEST Request
)
/*++
Routine Description:
This routine performs the TdiAction request for the transport
provider.
Arguments:
Device - The device for the operation.
Request - Describes the action request.
Return Value:
NTSTATUS - status of operation.
--*/
{
NTSTATUS Status;
PADDRESS_FILE AddressFile;
UINT BufferLength;
UINT DataLength;
PNDIS_BUFFER NdisBuffer;
CTELockHandle LockHandle;
PBINDING Binding, MasterBinding;
PADAPTER Adapter;
union {
PISN_ACTION_GET_LOCAL_TARGET GetLocalTarget;
PISN_ACTION_GET_NETWORK_INFO GetNetworkInfo;
PISN_ACTION_GET_DETAILS GetDetails;
PSR_GET_PARAMETERS GetSrParameters;
PSR_SET_PARAMETER SetSrParameter;
PSR_SET_REMOVE SetSrRemove;
PSR_SET_CLEAR SetSrClear;
PIPX_ADDRESS_DATA IpxAddressData;
PGET_PKT_SIZE GetPktSize;
PIPX_NETNUM_DATA IpxNetnumData;
} u; // BUGBUG: Make these unaligned??
PIPX_ROUTE_ENTRY RouteEntry;
PNWLINK_ACTION NwlinkAction;
ULONG Segment;
ULONG AdapterNum;
static UCHAR BogusId[4] = { 0x01, 0x00, 0x00, 0x00 }; // old nwrdr uses this
#ifdef _PNP_POWER
IPX_DEFINE_LOCK_HANDLE(LockHandle1)
#endif
//
// To maintain some compatibility with the NWLINK streams-
// based transport, we use the streams header format for
// our actions. The old transport expected the action header
// to be in InputBuffer and the output to go in OutputBuffer.
// We follow the TDI spec, which states that OutputBuffer
// is used for both input and output. Since IOCTL_TDI_ACTION
// is method out direct, this means that the output buffer
// is mapped by the MDL chain; for action the chain will
// only have one piece so we use it for input and output.
//
NdisBuffer = REQUEST_NDIS_BUFFER(Request);
if (NdisBuffer == NULL) {
return STATUS_INVALID_PARAMETER;
}
NdisQueryBuffer (REQUEST_NDIS_BUFFER(Request), (PVOID *)&NwlinkAction, &BufferLength);
if ((!RtlEqualMemory ((PVOID)(&NwlinkAction->Header.TransportId), "MISN", 4)) &&
(!RtlEqualMemory ((PVOID)(&NwlinkAction->Header.TransportId), "MIPX", 4)) &&
(!RtlEqualMemory ((PVOID)(&NwlinkAction->Header.TransportId), "XPIM", 4)) &&
(!RtlEqualMemory ((PVOID)(&NwlinkAction->Header.TransportId), BogusId, 4))) {
return STATUS_NOT_SUPPORTED;
}
//
// Make sure we have enough room for just the header not
// including the data.
//
if (BufferLength < (UINT)(FIELD_OFFSET(NWLINK_ACTION, Data[0]))) {
IPX_DEBUG (ACTION, ("Nwlink action failed, buffer too small\n"));
return STATUS_BUFFER_TOO_SMALL;
}
DataLength = BufferLength - FIELD_OFFSET(NWLINK_ACTION, Data[0]);
//
// Make sure that the correct file object is being used.
//
if (NwlinkAction->OptionType == NWLINK_OPTION_ADDRESS) {
if (REQUEST_OPEN_TYPE(Request) != (PVOID)TDI_TRANSPORT_ADDRESS_FILE) {
IPX_DEBUG (ACTION, ("Nwlink action failed, not address file\n"));
return STATUS_INVALID_HANDLE;
}
AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
if ((AddressFile->Size != sizeof (ADDRESS_FILE)) ||
(AddressFile->Type != IPX_ADDRESSFILE_SIGNATURE)) {
IPX_DEBUG (ACTION, ("Nwlink action failed, bad address file\n"));
return STATUS_INVALID_HANDLE;
}
} else if (NwlinkAction->OptionType != NWLINK_OPTION_CONTROL) {
IPX_DEBUG (ACTION, ("Nwlink action failed, option type %d\n", NwlinkAction->OptionType));
return STATUS_NOT_SUPPORTED;
}
//
// Handle the requests based on the action code. For these
// requests ActionHeader->ActionCode is 0, we use the
// Option field in the streams header instead.
//
Status = STATUS_SUCCESS;
switch (NwlinkAction->Option) {
//DbgPrint("NwlinkAction->Option is (%x)\n", NwlinkAction->Option);
//
// This first group support the winsock helper dll.
// In most cases the corresponding sockopt is shown in
// the comment, as well as the contents of the Data
// part of the action buffer.
//
case MIPX_SETSENDPTYPE:
//
// IPX_PTYPE: Data is a single byte packet type.
//
if (DataLength >= 1) {
IPX_DEBUG (ACTION, ("%lx: MIPX_SETSENDPTYPE %x\n", AddressFile, NwlinkAction->Data[0]));
AddressFile->DefaultPacketType = NwlinkAction->Data[0];
} else {
Status = STATUS_BUFFER_TOO_SMALL;
}
break;
case MIPX_FILTERPTYPE:
//
// IPX_FILTERPTYPE: Data is a single byte to filter on.
//
if (DataLength >= 1) {
IPX_DEBUG (ACTION, ("%lx: MIPX_FILTERPTYPE %x\n", AddressFile, NwlinkAction->Data[0]));
AddressFile->FilteredType = NwlinkAction->Data[0];
AddressFile->FilterOnPacketType = TRUE;
AddressFile->SpecialReceiveProcessing = TRUE;
} else {
Status = STATUS_BUFFER_TOO_SMALL;
}
break;
case MIPX_NOFILTERPTYPE:
//
// IPX_STOPFILTERPTYPE.
//
IPX_DEBUG (ACTION, ("%lx: MIPX_NOFILTERPTYPE\n", AddressFile));
AddressFile->FilterOnPacketType = FALSE;
AddressFile->SpecialReceiveProcessing = (BOOLEAN)
(AddressFile->ExtendedAddressing || AddressFile->ReceiveFlagsAddressing ||
AddressFile->ReceiveIpxHeader || AddressFile->IsSapSocket);
break;
case MIPX_SENDADDROPT:
//
// IPX_EXTENDED_ADDRESS (TRUE).
//
IPX_DEBUG (ACTION, ("%lx: MIPX_SENDADDROPT\n", AddressFile));
AddressFile->ExtendedAddressing = TRUE;
AddressFile->SpecialReceiveProcessing = TRUE;
break;
case MIPX_NOSENDADDROPT:
//
// IPX_EXTENDED_ADDRESS (FALSE).
//
IPX_DEBUG (ACTION, ("%lx: MIPX_NOSENDADDROPT\n", AddressFile));
AddressFile->ExtendedAddressing = FALSE;
AddressFile->SpecialReceiveProcessing = (BOOLEAN)
(AddressFile->ReceiveFlagsAddressing || AddressFile->ReceiveIpxHeader ||
AddressFile->FilterOnPacketType || AddressFile->IsSapSocket);
break;
case MIPX_SETRCVFLAGS:
//
// No sockopt yet.
//
IPX_DEBUG (ACTION, ("%lx: MIPX_SETRCVFLAGS\n", AddressFile));
AddressFile->ReceiveFlagsAddressing = TRUE;
AddressFile->SpecialReceiveProcessing = TRUE;
break;
case MIPX_NORCVFLAGS:
//
// No sockopt yet.
//
IPX_DEBUG (ACTION, ("%lx: MIPX_NORCVFLAGS\n", AddressFile));
AddressFile->ReceiveFlagsAddressing = FALSE;
AddressFile->SpecialReceiveProcessing = (BOOLEAN)
(AddressFile->ExtendedAddressing || AddressFile->ReceiveIpxHeader ||
AddressFile->FilterOnPacketType || AddressFile->IsSapSocket);
break;
case MIPX_SENDHEADER:
//
// IPX_RECVHDR (TRUE);
//
IPX_DEBUG (ACTION, ("%lx: MIPX_SENDHEADER\n", AddressFile));
AddressFile->ReceiveIpxHeader = TRUE;
AddressFile->SpecialReceiveProcessing = TRUE;
break;
case MIPX_NOSENDHEADER:
//
// IPX_RECVHDR (FALSE);
//
IPX_DEBUG (ACTION, ("%lx: MIPX_NOSENDHEADER\n", AddressFile));
AddressFile->ReceiveIpxHeader = FALSE;
AddressFile->SpecialReceiveProcessing = (BOOLEAN)
(AddressFile->ExtendedAddressing || AddressFile->ReceiveFlagsAddressing ||
AddressFile->FilterOnPacketType || AddressFile->IsSapSocket);
break;
case MIPX_RCVBCAST:
//
// Broadcast reception enabled.
//
IPX_DEBUG (ACTION, ("%lx: MIPX_RCVBCAST\n", AddressFile));
CTEGetLock (&Device->Lock, &LockHandle);
if (!AddressFile->EnableBroadcast) {
AddressFile->EnableBroadcast = TRUE;
IpxAddBroadcast (Device);
}
CTEFreeLock (&Device->Lock, LockHandle);
break;
case MIPX_NORCVBCAST:
//
// Broadcast reception disabled.
//
IPX_DEBUG (ACTION, ("%lx: MIPX_NORCVBCAST\n", AddressFile));
CTEGetLock (&Device->Lock, &LockHandle);
if (AddressFile->EnableBroadcast) {
AddressFile->EnableBroadcast = FALSE;
IpxRemoveBroadcast (Device);
}
CTEFreeLock (&Device->Lock, LockHandle);
break;
case MIPX_GETPKTSIZE:
//
// IPX_MAXSIZE.
//
// BUGBUG: Figure out what the first length is for.
//
IPX_DEBUG (ACTION, ("%lx: MIPX_GETPKTSIZE\n", AddressFile));
if (DataLength >= sizeof(GET_PKT_SIZE)) {
u.GetPktSize = (PGET_PKT_SIZE)(NwlinkAction->Data);
u.GetPktSize->Unknown = 0;
u.GetPktSize->MaxDatagramSize = Device->Information.MaxDatagramSize;
} else {
Status = STATUS_BUFFER_TOO_SMALL;
}
break;
case MIPX_ADAPTERNUM:
//
// IPX_MAX_ADAPTER_NUM.
//
IPX_DEBUG (ACTION, ("%lx: MIPX_ADAPTERNUM\n", AddressFile));
if (DataLength >= sizeof(ULONG)) {
*(UNALIGNED ULONG *)(NwlinkAction->Data) = Device->SapNicCount;
} else {
Status = STATUS_BUFFER_TOO_SMALL;
}
break;
case MIPX_ADAPTERNUM2:
//
// IPX_MAX_ADAPTER_NUM.
//
IPX_DEBUG (ACTION, ("%lx: MIPX_ADAPTERNUM2\n", AddressFile));
if (DataLength >= sizeof(ULONG)) {
*(UNALIGNED ULONG *)(NwlinkAction->Data) = MIN (Device->MaxBindings, Device->ValidBindings);
} else {
Status = STATUS_BUFFER_TOO_SMALL;
}
break;
case MIPX_GETCARDINFO:
case MIPX_GETCARDINFO2:
//
// GETCARDINFO is IPX_ADDRESS.
//
IPX_DEBUG (ACTION, ("%lx: MIPX_GETCARDINFO (%d)\n",
AddressFile, *(UNALIGNED UINT *)NwlinkAction->Data));
if (DataLength >= sizeof(IPX_ADDRESS_DATA)) {
u.IpxAddressData = (PIPX_ADDRESS_DATA)(NwlinkAction->Data);
AdapterNum = u.IpxAddressData->adapternum+1;
if (((AdapterNum >= 1) && (AdapterNum <= Device->SapNicCount)) ||
((NwlinkAction->Option == MIPX_GETCARDINFO2) && (AdapterNum <= (ULONG) MIN (Device->MaxBindings, Device->ValidBindings)))) {
#ifdef _PNP_POWER
// Get lock
IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
Binding = NIC_ID_TO_BINDING(Device, AdapterNum);
#else
Binding = Device->Bindings[AdapterNum];
#endif
if (Binding == NULL) {
//
// This should be a binding in the WAN range
// of an adapter which is currently not
// allocated. We scan back to the previous
// non-NULL binding, which should be on the
// same adapter, and return a down line with
// the same characteristics as that binding.
//
UINT i = AdapterNum;
do {
--i;
#ifdef _PNP_POWER
Binding = NIC_ID_TO_BINDING(Device, i);
#else
Binding = Device->Bindings[i];
#endif
} while (Binding == NULL);
CTEAssert (Binding->Adapter->MacInfo.MediumAsync);
CTEAssert (i >= Binding->Adapter->FirstWanNicId);
CTEAssert (AdapterNum <= Binding->Adapter->LastWanNicId);
u.IpxAddressData->status = FALSE;
*(UNALIGNED ULONG *)u.IpxAddressData->netnum = Binding->LocalAddress.NetworkAddress;
} else {
if ((Binding->Adapter->MacInfo.MediumAsync) &&
(Device->WanGlobalNetworkNumber)) {
//
// In this case we make it look like one big wan
// net, so the line is "up" or "down" depending
// on whether we have given him the first indication
// or not.
//
u.IpxAddressData->status = Device->GlobalNetworkIndicated;
*(UNALIGNED ULONG *)u.IpxAddressData->netnum = Device->GlobalWanNetwork;
} else {
u.IpxAddressData->status = Binding->LineUp;
*(UNALIGNED ULONG *)u.IpxAddressData->netnum = Binding->LocalAddress.NetworkAddress;
}
}
RtlCopyMemory(u.IpxAddressData->nodenum, Binding->LocalAddress.NodeAddress, 6);
Adapter = Binding->Adapter;
u.IpxAddressData->wan = Adapter->MacInfo.MediumAsync;
u.IpxAddressData->maxpkt =
(NwlinkAction->Option == MIPX_GETCARDINFO) ?
Binding->AnnouncedMaxDatagramSize :
Binding->RealMaxDatagramSize;
u.IpxAddressData->linkspeed = Binding->MediumSpeed;
#ifdef _PNP_POWER
IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
#endif
} else {
Status = STATUS_INVALID_PARAMETER;
}
} else {
#if 1
//
// Support the old format query for now.
//
typedef struct _IPX_OLD_ADDRESS_DATA {
UINT adapternum;
UCHAR netnum[4];
UCHAR nodenum[6];
} IPX_OLD_ADDRESS_DATA, *PIPX_OLD_ADDRESS_DATA;
if (DataLength >= sizeof(IPX_OLD_ADDRESS_DATA)) {
u.IpxAddressData = (PIPX_ADDRESS_DATA)(NwlinkAction->Data);
AdapterNum = u.IpxAddressData->adapternum+1;
if ((AdapterNum >= 1) && (AdapterNum <= Device->SapNicCount)) {
#ifdef _PNP_POWER
IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
if (Binding = NIC_ID_TO_BINDING(Device, AdapterNum)) {
*(UNALIGNED ULONG *)u.IpxAddressData->netnum = Binding->LocalAddress.NetworkAddress;
RtlCopyMemory(u.IpxAddressData->nodenum, Binding->LocalAddress.NodeAddress, 6);
} else {
Status = STATUS_INVALID_PARAMETER;
}
IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
#else
if (Binding = Device->Bindings[AdapterNum]) {
*(UNALIGNED ULONG *)u.IpxAddressData->netnum = Binding->LocalAddress.NetworkAddress;
RtlCopyMemory(u.IpxAddressData->nodenum, Binding->LocalAddress.NodeAddress, 6);
} else {
Status = STATUS_INVALID_PARAMETER;
}
#endif
} else {
Status = STATUS_INVALID_PARAMETER;
}
} else {
Status = STATUS_BUFFER_TOO_SMALL;
}
#else
Status = STATUS_BUFFER_TOO_SMALL;
#endif
}
break;
case MIPX_NOTIFYCARDINFO:
//
// IPX_ADDRESS_NOTIFY.
//
IPX_DEBUG (ACTION, ("%lx: MIPX_NOTIFYCARDINFO (%lx)\n", AddressFile, Request));
CTEGetLock (&Device->Lock, &LockHandle);
//
// If the device is open and there is room in the
// buffer for the data, insert it in our queue.
// It will be completed when a change happens or
// the driver is unloaded.
//
if (Device->State == DEVICE_STATE_OPEN) {
if (DataLength >= sizeof(IPX_ADDRESS_DATA)) {
InsertTailList(
&Device->AddressNotifyQueue,
REQUEST_LINKAGE(Request)
);
IoSetCancelRoutine (Request, IpxCancelAction);
if (Request->Cancel) {
(VOID)RemoveTailList (&Device->AddressNotifyQueue);
IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
Status = STATUS_CANCELLED;
} else {
IpxReferenceDevice (Device, DREF_ADDRESS_NOTIFY);
Status = STATUS_PENDING;
}
} else {
Status = STATUS_BUFFER_TOO_SMALL;
}
} else {
Status = STATUS_DEVICE_NOT_READY;
}
CTEFreeLock (&Device->Lock, LockHandle);
break;
case MIPX_LINECHANGE:
//
// IPX_ADDRESS_NOTIFY.
//
IPX_DEBUG (ACTION, ("MIPX_LINECHANGE (%lx)\n", Request));
CTEGetLock (&Device->Lock, &LockHandle);
//
// If the device is open and there is room in the
// buffer for the data, insert it in our queue.
// It will be completed when a change happens or
// the driver is unloaded.
//
if (Device->State == DEVICE_STATE_OPEN) {
InsertTailList(
&Device->LineChangeQueue,
REQUEST_LINKAGE(Request)
);
IoSetCancelRoutine (Request, IpxCancelAction);
if (Request->Cancel) {
(VOID)RemoveTailList (&Device->LineChangeQueue);
IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
Status = STATUS_CANCELLED;
} else {
IpxReferenceDevice (Device, DREF_LINE_CHANGE);
Status = STATUS_PENDING;
}
} else {
Status = STATUS_DEVICE_NOT_READY;
}
CTEFreeLock (&Device->Lock, LockHandle);
break;
case MIPX_GETNETINFO_NR:
//
// A request for network information about the immediate
// route to a network (this is called by sockets apps).
//
if (DataLength < sizeof(IPX_NETNUM_DATA)) {
return STATUS_BUFFER_TOO_SMALL;
}
u.IpxNetnumData = (PIPX_NETNUM_DATA)(NwlinkAction->Data);
//
// A query on network 0 means that the caller wants
// information about our directly attached net.
//
if (*(UNALIGNED ULONG *)u.IpxNetnumData->netnum == 0) {
//
// The tick count is the number of 1/18.21 second ticks
// it takes to deliver a 576-byte packet. Our link speed
// is in 100 bit-per-second units. We calculate it as
// follows (LS is the LinkSpeed):
//
// 576 bytes 8 bits 1 second 1821 ticks
// * ------ * ------------- * ----------
// 1 byte LS * 100 bits 100 seconds
//
// which becomes 839 / LinkSpeed -- we add LinkSpeed
// to the top to round up.
//
if (Device->LinkSpeed == 0) {
u.IpxNetnumData->netdelay = 16;
} else {
u.IpxNetnumData->netdelay = (USHORT)((839 + Device->LinkSpeed) /
(Device->LinkSpeed));
}
u.IpxNetnumData->hopcount = 0;
u.IpxNetnumData->cardnum = 0;
RtlMoveMemory (u.IpxNetnumData->router, Device->SourceAddress.NodeAddress, 6);
} else {
#ifdef _PNP_POWER
Segment = RipGetSegment(u.IpxNetnumData->netnum);
//
// To maintain the lock order: BindAccessLock > RIP table
//
IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
CTEGetLock (&Device->SegmentLocks[Segment], &LockHandle);
//
// See which net card this is routed on.
//
RouteEntry = RipGetRoute (Segment, u.IpxNetnumData->netnum);
if ((RouteEntry != NULL) &&
(Binding = NIC_ID_TO_BINDING(Device, RouteEntry->NicId))) {
u.IpxNetnumData->hopcount = RouteEntry->HopCount;
u.IpxNetnumData->netdelay = RouteEntry->TickCount;
if (Binding->BindingSetMember) {
u.IpxNetnumData->cardnum = (INT)(MIN (Device->MaxBindings, Binding->MasterBinding->NicId) - 1);
} else {
u.IpxNetnumData->cardnum = (INT)(RouteEntry->NicId - 1);
}
RtlMoveMemory (u.IpxNetnumData->router, RouteEntry->NextRouter, 6);
} else {
//
// Fail the call, we don't have a route yet.
//
IPX_DEBUG (ACTION, ("MIPX_GETNETINFO_NR failed net %lx\n",
REORDER_ULONG(*(UNALIGNED ULONG *)(u.IpxNetnumData->netnum))));
Status = STATUS_BAD_NETWORK_PATH;
}
CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
#else
Segment = RipGetSegment(u.IpxNetnumData->netnum);
CTEGetLock (&Device->SegmentLocks[Segment], &LockHandle);
//
// See which net card this is routed on.
//
RouteEntry = RipGetRoute (Segment, u.IpxNetnumData->netnum);
if ((RouteEntry != NULL) &&
(Binding = Device->Bindings[RouteEntry->NicId])) {
u.IpxNetnumData->hopcount = RouteEntry->HopCount;
u.IpxNetnumData->netdelay = RouteEntry->TickCount;
if (Binding->BindingSetMember) {
u.IpxNetnumData->cardnum = (INT)(Binding->MasterBinding->NicId - 1);
} else {
u.IpxNetnumData->cardnum = (INT)(RouteEntry->NicId - 1);
}
RtlMoveMemory (u.IpxNetnumData->router, RouteEntry->NextRouter, 6);
} else {
//
// Fail the call, we don't have a route yet.
//
IPX_DEBUG (ACTION, ("MIPX_GETNETINFO_NR failed net %lx\n",
REORDER_ULONG(*(UNALIGNED ULONG *)(u.IpxNetnumData->netnum))));
Status = STATUS_BAD_NETWORK_PATH;
}
CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
#endif
}
break;
case MIPX_RERIPNETNUM:
//
// A request for network information about the immediate
// route to a network (this is called by sockets apps).
//
if (DataLength < sizeof(IPX_NETNUM_DATA)) {
return STATUS_BUFFER_TOO_SMALL;
}
u.IpxNetnumData = (PIPX_NETNUM_DATA)(NwlinkAction->Data);
//
// BUGBUG: Allow net 0 queries??
//
if (*(UNALIGNED ULONG *)u.IpxNetnumData->netnum == 0) {
if (Device->LinkSpeed == 0) {
u.IpxNetnumData->netdelay = 16;
} else {
u.IpxNetnumData->netdelay = (USHORT)((839 + Device->LinkSpeed) /
(Device->LinkSpeed));
}
u.IpxNetnumData->hopcount = 0;
u.IpxNetnumData->cardnum = 0;
RtlMoveMemory (u.IpxNetnumData->router, Device->SourceAddress.NodeAddress, 6);
} else {
Segment = RipGetSegment(u.IpxNetnumData->netnum);
#ifdef _PNP_POWER
IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
CTEGetLock (&Device->SegmentLocks[Segment], &LockHandle);
//
// See which net card this is routed on.
//
RouteEntry = RipGetRoute (Segment, u.IpxNetnumData->netnum);
if ((RouteEntry != NULL) &&
(Binding = NIC_ID_TO_BINDING(Device, RouteEntry->NicId)) &&
(RouteEntry->Flags & IPX_ROUTER_PERMANENT_ENTRY)) {
u.IpxNetnumData->hopcount = RouteEntry->HopCount;
u.IpxNetnumData->netdelay = RouteEntry->TickCount;
if (Binding->BindingSetMember) {
u.IpxNetnumData->cardnum = (INT)(MIN (Device->MaxBindings, Binding->MasterBinding->NicId) - 1);
} else {
u.IpxNetnumData->cardnum = (INT)(RouteEntry->NicId - 1);
}
RtlMoveMemory (u.IpxNetnumData->router, RouteEntry->NextRouter, 6);
} else {
//
// This call will return STATUS_PENDING if we successfully
// queue a RIP request for the packet.
//
Status = RipQueueRequest (*(UNALIGNED ULONG *)u.IpxNetnumData->netnum, RIP_REQUEST);
CTEAssert (Status != STATUS_SUCCESS);
if (Status == STATUS_PENDING) {
//
// A RIP request went out on the network; we queue
// this request for completion when the RIP response
// arrives. We save the network in the information
// field for easier retrieval later.
//
REQUEST_INFORMATION(Request) = (ULONG)u.IpxNetnumData;
InsertTailList(
&Device->Segments[Segment].WaitingReripNetnum,
REQUEST_LINKAGE(Request));
IPX_DEBUG (ACTION, ("MIPX_RERIPNETNUM queued net %lx\n",
REORDER_ULONG(*(UNALIGNED ULONG *)(u.IpxNetnumData->netnum))));
}
}
CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
#else
CTEGetLock (&Device->SegmentLocks[Segment], &LockHandle);
//
// See which net card this is routed on.
//
RouteEntry = RipGetRoute (Segment, u.IpxNetnumData->netnum);
if ((RouteEntry != NULL) &&
(Binding = Device->Bindings[RouteEntry->NicId]) &&
(RouteEntry->Flags & IPX_ROUTER_PERMANENT_ENTRY)) {
u.IpxNetnumData->hopcount = RouteEntry->HopCount;
u.IpxNetnumData->netdelay = RouteEntry->TickCount;
if (Binding->BindingSetMember) {
u.IpxNetnumData->cardnum = (INT)(Binding->MasterBinding->NicId - 1);
} else {
u.IpxNetnumData->cardnum = (INT)(RouteEntry->NicId - 1);
}
RtlMoveMemory (u.IpxNetnumData->router, RouteEntry->NextRouter, 6);
} else {
//
// This call will return STATUS_PENDING if we successfully
// queue a RIP request for the packet.
//
Status = RipQueueRequest (*(UNALIGNED ULONG *)u.IpxNetnumData->netnum, RIP_REQUEST);
CTEAssert (Status != STATUS_SUCCESS);
if (Status == STATUS_PENDING) {
//
// A RIP request went out on the network; we queue
// this request for completion when the RIP response
// arrives. We save the network in the information
// field for easier retrieval later.
//
REQUEST_INFORMATION(Request) = (ULONG)u.IpxNetnumData;
InsertTailList(
&Device->Segments[Segment].WaitingReripNetnum,
REQUEST_LINKAGE(Request));
IPX_DEBUG (ACTION, ("MIPX_RERIPNETNUM queued net %lx\n",
REORDER_ULONG(*(UNALIGNED ULONG *)(u.IpxNetnumData->netnum))));
}
}
CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
#endif
}
break;
case MIPX_GETNETINFO:
//
// A request for network information about the immediate
// route to a network (this is called by sockets apps).
//
if (DataLength < sizeof(IPX_NETNUM_DATA)) {
return STATUS_BUFFER_TOO_SMALL;
}
u.IpxNetnumData = (PIPX_NETNUM_DATA)(NwlinkAction->Data);
//
// BUGBUG: Allow net 0 queries??
//
if (*(UNALIGNED ULONG *)u.IpxNetnumData->netnum == 0) {
if (Device->LinkSpeed == 0) {
u.IpxNetnumData->netdelay = 16;
} else {
u.IpxNetnumData->netdelay = (USHORT)((839 + Device->LinkSpeed) /
(Device->LinkSpeed));
}
u.IpxNetnumData->hopcount = 0;
u.IpxNetnumData->cardnum = 0;
RtlMoveMemory (u.IpxNetnumData->router, Device->SourceAddress.NodeAddress, 6);
} else {
Segment = RipGetSegment(u.IpxNetnumData->netnum);
#ifdef _PNP_POWER
IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
CTEGetLock (&Device->SegmentLocks[Segment], &LockHandle);
//
// See which net card this is routed on.
//
RouteEntry = RipGetRoute (Segment, u.IpxNetnumData->netnum);
if ((RouteEntry != NULL) &&
(Binding = NIC_ID_TO_BINDING(Device, RouteEntry->NicId))) {
u.IpxNetnumData->hopcount = RouteEntry->HopCount;
u.IpxNetnumData->netdelay = RouteEntry->TickCount;
if (Binding->BindingSetMember) {
u.IpxNetnumData->cardnum = (INT)(MIN (Device->MaxBindings, Binding->MasterBinding->NicId) - 1);
} else {
u.IpxNetnumData->cardnum = (INT)(RouteEntry->NicId - 1);
}
RtlMoveMemory (u.IpxNetnumData->router, RouteEntry->NextRouter, 6);
} else {
//
// This call will return STATUS_PENDING if we successfully
// queue a RIP request for the packet.
//
Status = RipQueueRequest (*(UNALIGNED ULONG *)u.IpxNetnumData->netnum, RIP_REQUEST);
CTEAssert (Status != STATUS_SUCCESS);
if (Status == STATUS_PENDING) {
//
// A RIP request went out on the network; we queue
// this request for completion when the RIP response
// arrives. We save the network in the information
// field for easier retrieval later.
//
REQUEST_INFORMATION(Request) = (ULONG)u.IpxNetnumData;
InsertTailList(
&Device->Segments[Segment].WaitingReripNetnum,
REQUEST_LINKAGE(Request));
IPX_DEBUG (ACTION, ("MIPX_GETNETINFO queued net %lx\n",
REORDER_ULONG(*(UNALIGNED ULONG *)(u.IpxNetnumData->netnum))));
}
}
CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
#else
CTEGetLock (&Device->SegmentLocks[Segment], &LockHandle);
//
// See which net card this is routed on.
//
RouteEntry = RipGetRoute (Segment, u.IpxNetnumData->netnum);
if ((RouteEntry != NULL) &&
(Binding = Device->Bindings[RouteEntry->NicId])) {
u.IpxNetnumData->hopcount = RouteEntry->HopCount;
u.IpxNetnumData->netdelay = RouteEntry->TickCount;
if (Binding->BindingSetMember) {
u.IpxNetnumData->cardnum = (INT)(Binding->MasterBinding->NicId - 1);
} else {
u.IpxNetnumData->cardnum = (INT)(RouteEntry->NicId - 1);
}
RtlMoveMemory (u.IpxNetnumData->router, RouteEntry->NextRouter, 6);
} else {
//
// This call will return STATUS_PENDING if we successfully
// queue a RIP request for the packet.
//
Status = RipQueueRequest (*(UNALIGNED ULONG *)u.IpxNetnumData->netnum, RIP_REQUEST);
CTEAssert (Status != STATUS_SUCCESS);
if (Status == STATUS_PENDING) {
//
// A RIP request went out on the network; we queue
// this request for completion when the RIP response
// arrives. We save the network in the information
// field for easier retrieval later.
//
REQUEST_INFORMATION(Request) = (ULONG)u.IpxNetnumData;
InsertTailList(
&Device->Segments[Segment].WaitingReripNetnum,
REQUEST_LINKAGE(Request));
IPX_DEBUG (ACTION, ("MIPX_GETNETINFO queued net %lx\n",
REORDER_ULONG(*(UNALIGNED ULONG *)(u.IpxNetnumData->netnum))));
}
}
CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
#endif
}
break;
case MIPX_SENDPTYPE:
case MIPX_NOSENDPTYPE:
//
// For the moment just use OptionsLength >= 1 to indicate
// that the send options include the packet type.
//
// BUGBUG: Do we need to worry about card num being there?
//
#if 0
IPX_DEBUG (ACTION, ("%lx: MIPS_%sSENDPTYPE\n", AddressFile,
NwlinkAction->Option == MIPX_SENDPTYPE ? "" : "NO"));
#endif
break;
case MIPX_ZEROSOCKET:
//
// Sends from this address should be from socket 0;
// This is done the simple way by just putting the
// information in the address itself, instead of
// making it per address file (this is OK since
// this call is not exposed through winsock).
//
IPX_DEBUG (ACTION, ("%lx: MIPX_ZEROSOCKET\n", AddressFile));
AddressFile->Address->SendSourceSocket = 0;
AddressFile->Address->LocalAddress.Socket = 0;
break;
//
// This next batch are the source routing options. They
// are submitted by the IPXROUTE program.
//
// BUGBUG: Do we expose all binding set members to this?
case MIPX_SRGETPARMS:
if (DataLength >= sizeof(SR_GET_PARAMETERS)) {
u.GetSrParameters = (PSR_GET_PARAMETERS)(NwlinkAction->Data);
#ifdef _PNP_POWER
IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
if (Binding = NIC_ID_TO_BINDING(Device, u.GetSrParameters->BoardNumber+1)) {
IPX_DEBUG (ACTION, ("MIPX_SRGETPARMS (%d)\n", u.GetSrParameters->BoardNumber+1));
u.GetSrParameters->SrDefault = (Binding->AllRouteDirected) ? 1 : 0;
u.GetSrParameters->SrBroadcast = (Binding->AllRouteBroadcast) ? 1 : 0;
u.GetSrParameters->SrMulticast = (Binding->AllRouteMulticast) ? 1 : 0;
} else {
Status = STATUS_INVALID_PARAMETER;
}
IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
#else
if (Binding = Device->Bindings[u.GetSrParameters->BoardNumber+1]) {
IPX_DEBUG (ACTION, ("MIPX_SRGETPARMS (%d)\n", u.GetSrParameters->BoardNumber+1));
u.GetSrParameters->SrDefault = (Binding->AllRouteDirected) ? 1 : 0;
u.GetSrParameters->SrBroadcast = (Binding->AllRouteBroadcast) ? 1 : 0;
u.GetSrParameters->SrMulticast = (Binding->AllRouteMulticast) ? 1 : 0;
} else {
Status = STATUS_INVALID_PARAMETER;
}
#endif
} else {
Status = STATUS_BUFFER_TOO_SMALL;
}
break;
case MIPX_SRDEF:
case MIPX_SRBCAST:
case MIPX_SRMULTI:
if (DataLength >= sizeof(SR_SET_PARAMETER)) {
u.SetSrParameter = (PSR_SET_PARAMETER)(NwlinkAction->Data);
#ifdef _PNP_POWER
IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
if (Binding = NIC_ID_TO_BINDING(Device, u.SetSrParameter->BoardNumber+1)) {
if (NwlinkAction->Option == MIPX_SRDEF) {
//
// BUGBUG: The compiler generates strange
// code which always makes this path be
// taken????
//
IPX_DEBUG (ACTION, ("MIPX_SRDEF %d (%d)\n",
u.SetSrParameter->Parameter, u.SetSrParameter->BoardNumber+1));
Binding->AllRouteDirected = (BOOLEAN)u.SetSrParameter->Parameter;
} else if (NwlinkAction->Option == MIPX_SRBCAST) {
IPX_DEBUG (ACTION, ("MIPX_SRBCAST %d (%d)\n",
u.SetSrParameter->Parameter, u.SetSrParameter->BoardNumber+1));
Binding->AllRouteBroadcast = (BOOLEAN)u.SetSrParameter->Parameter;
} else {
IPX_DEBUG (ACTION, ("MIPX_SRMCAST %d (%d)\n",
u.SetSrParameter->Parameter, u.SetSrParameter->BoardNumber+1));
Binding->AllRouteMulticast = (BOOLEAN)u.SetSrParameter->Parameter;
}
} else {
Status = STATUS_INVALID_PARAMETER;
}
IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
#else
if (Binding = Device->Bindings[u.SetSrParameter->BoardNumber+1]) {
if (NwlinkAction->Option == MIPX_SRDEF) {
//
// BUGBUG: The compiler generates strange
// code which always makes this path be
// taken????
//
IPX_DEBUG (ACTION, ("MIPX_SRDEF %d (%d)\n",
u.SetSrParameter->Parameter, u.SetSrParameter->BoardNumber+1));
Binding->AllRouteDirected = (BOOLEAN)u.SetSrParameter->Parameter;
} else if (NwlinkAction->Option == MIPX_SRBCAST) {
IPX_DEBUG (ACTION, ("MIPX_SRBCAST %d (%d)\n",
u.SetSrParameter->Parameter, u.SetSrParameter->BoardNumber+1));
Binding->AllRouteBroadcast = (BOOLEAN)u.SetSrParameter->Parameter;
} else {
IPX_DEBUG (ACTION, ("MIPX_SRMCAST %d (%d)\n",
u.SetSrParameter->Parameter, u.SetSrParameter->BoardNumber+1));
Binding->AllRouteMulticast = (BOOLEAN)u.SetSrParameter->Parameter;
}
} else {
Status = STATUS_INVALID_PARAMETER;
}
#endif
} else {
Status = STATUS_BUFFER_TOO_SMALL;
}
break;
case MIPX_SRREMOVE:
if (DataLength >= sizeof(SR_SET_REMOVE)) {
u.SetSrRemove = (PSR_SET_REMOVE)(NwlinkAction->Data);
#ifdef _PNP_POWER
IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
if (Binding = NIC_ID_TO_BINDING(Device, u.SetSrRemove->BoardNumber+1)) {
IPX_DEBUG (ACTION, ("MIPX_SRREMOVE %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x (%d)\n",
u.SetSrRemove->MacAddress[0],
u.SetSrRemove->MacAddress[1],
u.SetSrRemove->MacAddress[2],
u.SetSrRemove->MacAddress[3],
u.SetSrRemove->MacAddress[4],
u.SetSrRemove->MacAddress[5],
u.SetSrRemove->BoardNumber+1));
MacSourceRoutingRemove (Binding, u.SetSrRemove->MacAddress);
} else {
Status = STATUS_INVALID_PARAMETER;
}
IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
#else
if (Binding = Device->Bindings[u.SetSrRemove->BoardNumber+1]) {
IPX_DEBUG (ACTION, ("MIPX_SRREMOVE %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x (%d)\n",
u.SetSrRemove->MacAddress[0],
u.SetSrRemove->MacAddress[1],
u.SetSrRemove->MacAddress[2],
u.SetSrRemove->MacAddress[3],
u.SetSrRemove->MacAddress[4],
u.SetSrRemove->MacAddress[5],
u.SetSrRemove->BoardNumber+1));
MacSourceRoutingRemove (Binding, u.SetSrRemove->MacAddress);
} else {
Status = STATUS_INVALID_PARAMETER;
}
#endif
} else {
Status = STATUS_BUFFER_TOO_SMALL;
}
break;
case MIPX_SRCLEAR:
if (DataLength >= sizeof(SR_SET_CLEAR)) {
u.SetSrClear = (PSR_SET_CLEAR)(NwlinkAction->Data);
#ifdef _PNP_POWER
IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
if (Binding = NIC_ID_TO_BINDING(Device, u.SetSrClear->BoardNumber+1)) {
IPX_DEBUG (ACTION, ("MIPX_SRCLEAR (%d)\n", u.SetSrClear->BoardNumber+1));
MacSourceRoutingClear (Binding);
} else {
Status = STATUS_INVALID_PARAMETER;
}
IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
#else
if (Binding = Device->Bindings[u.SetSrClear->BoardNumber+1]) {
IPX_DEBUG (ACTION, ("MIPX_SRCLEAR (%d)\n", u.SetSrClear->BoardNumber+1));
MacSourceRoutingClear (Binding);
} else {
Status = STATUS_INVALID_PARAMETER;
}
#endif
} else {
Status = STATUS_BUFFER_TOO_SMALL;
}
break;
//
// These are new for ISN (not supported in NWLINK).
//
case MIPX_LOCALTARGET:
//
// A request for the local target for an IPX address.
//
if (DataLength < sizeof(ISN_ACTION_GET_LOCAL_TARGET)) {
return STATUS_BUFFER_TOO_SMALL;
}
u.GetLocalTarget = (PISN_ACTION_GET_LOCAL_TARGET)(NwlinkAction->Data);
Segment = RipGetSegment((PUCHAR)&u.GetLocalTarget->IpxAddress.NetworkAddress);
CTEGetLock (&Device->SegmentLocks[Segment], &LockHandle);
//
// See if this route is local.
//
RouteEntry = RipGetRoute (Segment, (PUCHAR)&u.GetLocalTarget->IpxAddress.NetworkAddress);
if ((RouteEntry != NULL) &&
(RouteEntry->Flags & IPX_ROUTER_PERMANENT_ENTRY)) {
//
// This is a local net, to send to it you just use
// the appropriate NIC ID and the real MAC address.
//
if ((RouteEntry->Flags & IPX_ROUTER_LOCAL_NET) == 0) {
//
// It's the virtual net, send via the first card.
//
#ifdef _PNP_POWER
FILL_LOCAL_TARGET(&u.GetLocalTarget->LocalTarget, 1);
#else
u.GetLocalTarget->LocalTarget.NicId = 1;
#endif
} else {
#ifdef _PNP_POWER
CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
Binding = NIC_ID_TO_BINDING(Device, RouteEntry->NicId);
if (Binding->BindingSetMember) {
//
// It's a binding set member, we round-robin the
// responses across all the cards to distribute
// the traffic.
//
MasterBinding = Binding->MasterBinding;
Binding = MasterBinding->CurrentSendBinding;
MasterBinding->CurrentSendBinding = Binding->NextBinding;
FILL_LOCAL_TARGET(&u.GetLocalTarget->LocalTarget, MIN( Device->MaxBindings, Binding->NicId));
} else {
FILL_LOCAL_TARGET(&u.GetLocalTarget->LocalTarget, RouteEntry->NicId);
}
IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
#else
Binding = Device->Bindings[RouteEntry->NicId];
if (Binding->BindingSetMember) {
//
// It's a binding set member, we round-robin the
// responses across all the cards to distribute
// the traffic.
//
MasterBinding = Binding->MasterBinding;
Binding = MasterBinding->CurrentSendBinding;
MasterBinding->CurrentSendBinding = Binding->NextBinding;
u.GetLocalTarget->LocalTarget.NicId = Binding->NicId;
} else {
u.GetLocalTarget->LocalTarget.NicId = RouteEntry->NicId;
}
#endif
}
RtlCopyMemory(
u.GetLocalTarget->LocalTarget.MacAddress,
u.GetLocalTarget->IpxAddress.NodeAddress,
6);
} else {
//
// This call will return STATUS_PENDING if we successfully
// queue a RIP request for the packet.
//
Status = RipQueueRequest (u.GetLocalTarget->IpxAddress.NetworkAddress, RIP_REQUEST);
CTEAssert (Status != STATUS_SUCCESS);
if (Status == STATUS_PENDING) {
//
// A RIP request went out on the network; we queue
// this request for completion when the RIP response
// arrives. We save the network in the information
// field for easier retrieval later.
//
REQUEST_INFORMATION(Request) = (ULONG)u.GetLocalTarget;
InsertTailList(
&Device->Segments[Segment].WaitingLocalTarget,
REQUEST_LINKAGE(Request));
}
#ifdef _PNP_POWER
CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
#endif
}
#ifndef _PNP_POWER
CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
#endif
break;
case MIPX_NETWORKINFO:
//
// A request for network information about the immediate
// route to a network.
//
if (DataLength < sizeof(ISN_ACTION_GET_NETWORK_INFO)) {
return STATUS_BUFFER_TOO_SMALL;
}
u.GetNetworkInfo = (PISN_ACTION_GET_NETWORK_INFO)(NwlinkAction->Data);
if (u.GetNetworkInfo->Network == 0) {
//
// This is information about the local card.
//
u.GetNetworkInfo->LinkSpeed = Device->LinkSpeed * 12;
u.GetNetworkInfo->MaximumPacketSize = Device->Information.MaxDatagramSize;
} else {
Segment = RipGetSegment((PUCHAR)&u.GetNetworkInfo->Network);
#ifdef _PNP_POWER
IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
#endif
CTEGetLock (&Device->SegmentLocks[Segment], &LockHandle);
//
// See which net card this is routed on.
//
RouteEntry = RipGetRoute (Segment, (PUCHAR)&u.GetNetworkInfo->Network);
if ((RouteEntry != NULL) &&
#ifdef _PNP_POWER
(Binding = NIC_ID_TO_BINDING(Device, RouteEntry->NicId))) {
#else
(Binding = Device->Bindings[RouteEntry->NicId])) {
#endif
//
// Our medium speed is stored in 100 bps, we
// convert to bytes/sec by multiplying by 12
// (should really be 100/8 = 12.5).
//
u.GetNetworkInfo->LinkSpeed = Binding->MediumSpeed * 12;
u.GetNetworkInfo->MaximumPacketSize = Binding->AnnouncedMaxDatagramSize;
} else {
//
// Fail the call, we don't have a route yet.
// BUGBUG: This requires that a packet has been
// sent to this net already; nwrdr says this is
// OK, they will send their connect request
// before they query. On the server it should
// have RIP running so all nets should be in
// the database.
//
Status = STATUS_BAD_NETWORK_PATH;
}
CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
#ifdef _PNP_POWER
IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
#endif
}
break;
case MIPX_CONFIG:
//
// A request for details on every binding.
//
if (DataLength < sizeof(ISN_ACTION_GET_DETAILS)) {
return STATUS_BUFFER_TOO_SMALL;
}
u.GetDetails = (PISN_ACTION_GET_DETAILS)(NwlinkAction->Data);
if (u.GetDetails->NicId == 0) {
//
// This is information about the local card. We also
// tell him the total number of bindings in NicId.
//
u.GetDetails->NetworkNumber = Device->VirtualNetworkNumber;
u.GetDetails->NicId = (USHORT)MIN (Device->MaxBindings, Device->ValidBindings);
} else {
#ifdef _PNP_POWER
IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
Binding = NIC_ID_TO_BINDING(Device, u.GetDetails->NicId);
#else
Binding = Device->Bindings[u.GetDetails->NicId];
#endif
if ((Binding != NULL) &&
(u.GetDetails->NicId <= MIN (Device->MaxBindings, Device->ValidBindings))) {
ULONG StringLoc;
#ifdef _PNP_POWER
IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
#endif
u.GetDetails->NetworkNumber = Binding->LocalAddress.NetworkAddress;
if (Binding->Adapter->MacInfo.MediumType == NdisMediumArcnet878_2) {
u.GetDetails->FrameType = ISN_FRAME_TYPE_ARCNET;
} else {
u.GetDetails->FrameType = Binding->FrameType;
}
u.GetDetails->BindingSet = Binding->BindingSetMember;
if (Binding->Adapter->MacInfo.MediumAsync) {
if (Binding->LineUp) {
u.GetDetails->Type = 2;
} else {
u.GetDetails->Type = 3;
}
} else {
u.GetDetails->Type = 1;
}
RtlCopyMemory (u.GetDetails->Node, Binding->LocalMacAddress.Address, 6);
//
// Copy the adapter name, including the final NULL.
//
StringLoc = (Binding->Adapter->AdapterNameLength / sizeof(WCHAR)) - 2;
while (Binding->Adapter->AdapterName[StringLoc] != L'\\') {
--StringLoc;
}
RtlCopyMemory(
u.GetDetails->AdapterName,
&Binding->Adapter->AdapterName[StringLoc+1],
Binding->Adapter->AdapterNameLength - ((StringLoc+1) * sizeof(WCHAR)));
#ifdef _PNP_POWER
IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
#endif
} else {
#ifdef _PNP_POWER
IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
#endif
Status = STATUS_INVALID_PARAMETER;
}
}
break;
//
// The Option was not supported, so fail.
//
default:
Status = STATUS_NOT_SUPPORTED;
break;
} // end of the long switch on NwlinkAction->Option
#if DBG
if (!NT_SUCCESS(Status)) {
IPX_DEBUG (ACTION, ("Nwlink action %lx failed, status %lx\n", NwlinkAction->Option, Status));
}
#endif
return Status;
} /* IpxTdiAction */
VOID
IpxCancelAction(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This routine is called by the I/O system to cancel an Action.
What is done to cancel it is specific to each action.
NOTE: This routine is called with the CancelSpinLock held and
is responsible for releasing it.
Arguments:
DeviceObject - Pointer to the device object for this driver.
Irp - Pointer to the request packet representing the I/O request.
Return Value:
none.
--*/
{
PDEVICE Device = IpxDevice;
PREQUEST Request = (PREQUEST)Irp;
CTELockHandle LockHandle;
PLIST_ENTRY p;
BOOLEAN Found;
UINT IOCTLType;
ASSERT( DeviceObject->DeviceExtension == IpxDevice );
//
// Find the request on the address notify queue.
//
Found = FALSE;
CTEGetLock (&Device->Lock, &LockHandle);
for (p = Device->AddressNotifyQueue.Flink;
p != &Device->AddressNotifyQueue;
p = p->Flink) {
if (LIST_ENTRY_TO_REQUEST(p) == Request) {
RemoveEntryList (p);
Found = TRUE;
IOCTLType = MIPX_NOTIFYCARDINFO;
break;
}
}
if (!Found) {
for (p = Device->LineChangeQueue.Flink;
p != &Device->LineChangeQueue;
p = p->Flink) {
if (LIST_ENTRY_TO_REQUEST(p) == Request) {
RemoveEntryList (p);
Found = TRUE;
IOCTLType = MIPX_LINECHANGE;
break;
}
}
}
CTEFreeLock (&Device->Lock, LockHandle);
IoReleaseCancelSpinLock (Irp->CancelIrql);
if (Found) {
REQUEST_INFORMATION(Request) = 0;
REQUEST_STATUS(Request) = STATUS_CANCELLED;
IpxCompleteRequest (Request);
IpxFreeRequest(Device, Request);
if (IOCTLType == MIPX_NOTIFYCARDINFO) {
IPX_DEBUG(ACTION, ("Cancelled action NOTIFYCARDINFO %lx\n", Request));
IpxDereferenceDevice (Device, DREF_ADDRESS_NOTIFY);
} else {
IPX_DEBUG(ACTION, ("Cancelled action LINECHANGE %lx\n", Request));
IpxDereferenceDevice (Device, DREF_LINE_CHANGE);
}
}
#if DBG
else {
IPX_DEBUG(ACTION, ("Cancelled action orphan %lx\n", Request));
}
#endif
} /* IpxCancelAction */
VOID
IpxAbortLineChanges(
IN PVOID ControlChannelContext
)
/*++
Routine Description:
This routine aborts any line change IRPs posted by the
control channel with the specified open context. It is
called when a control channel is being shut down.
Arguments:
ControlChannelContext - The context assigned to the control
channel when it was opened.
Return Value:
none.
--*/
{
PDEVICE Device = IpxDevice;
CTELockHandle LockHandle;
LIST_ENTRY AbortList;
PLIST_ENTRY p;
PREQUEST Request;
KIRQL irql;
InitializeListHead (&AbortList);
IoAcquireCancelSpinLock( &irql );
CTEGetLock (&Device->Lock, &LockHandle);
p = Device->LineChangeQueue.Flink;
while (p != &Device->LineChangeQueue) {
LARGE_INTEGER ControlChId;
Request = LIST_ENTRY_TO_REQUEST(p);
CCID_FROM_REQUEST(ControlChId, Request);
p = p->Flink;
if (ControlChId.QuadPart == ((PLARGE_INTEGER)ControlChannelContext)->QuadPart) {
RemoveEntryList (REQUEST_LINKAGE(Request));
InsertTailList (&AbortList, REQUEST_LINKAGE(Request));
}
}
while (!IsListEmpty (&AbortList)) {
p = RemoveHeadList (&AbortList);
Request = LIST_ENTRY_TO_REQUEST(p);
IPX_DEBUG(ACTION, ("Aborting line change %lx\n", Request));
IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
REQUEST_INFORMATION(Request) = 0;
REQUEST_STATUS(Request) = STATUS_CANCELLED;
CTEFreeLock(&Device->Lock, LockHandle);
IoReleaseCancelSpinLock( irql );
IpxCompleteRequest (Request);
IpxFreeRequest(Device, Request);
IpxDereferenceDevice (Device, DREF_LINE_CHANGE);
IoAcquireCancelSpinLock( &irql );
CTEGetLock(&Device->Lock, &LockHandle);
}
CTEFreeLock(&Device->Lock, LockHandle);
IoReleaseCancelSpinLock( irql );
} /* IpxAbortLineChanges */