You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2836 lines
96 KiB
2836 lines
96 KiB
/*++
|
|
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>
|
|
|
|
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; // 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;
|
|
|
|
IPX_DEFINE_LOCK_HANDLE(LockHandle1)
|
|
|
|
//
|
|
// 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;
|
|
}
|
|
|
|
NdisQueryBufferSafe (REQUEST_NDIS_BUFFER(Request), (PVOID *)&NwlinkAction, &BufferLength, NormalPagePriority);
|
|
|
|
if (NwlinkAction == NULL) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// 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;
|
|
}
|
|
|
|
if ((!RtlEqualMemory ((PVOID) (UNALIGNED ULONG *) (&NwlinkAction->Header.TransportId), "MISN", 4)) &&
|
|
(!RtlEqualMemory ((PVOID) (UNALIGNED ULONG *) (&NwlinkAction->Header.TransportId), "MIPX", 4)) &&
|
|
(!RtlEqualMemory ((PVOID) (UNALIGNED ULONG *) (&NwlinkAction->Header.TransportId), "XPIM", 4)) &&
|
|
(!RtlEqualMemory ((PVOID) (UNALIGNED ULONG *) (&NwlinkAction->Header.TransportId), BogusId, 4))) {
|
|
|
|
return STATUS_NOT_SUPPORTED;
|
|
}
|
|
|
|
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) {
|
|
|
|
IPX_DEBUG (ACTION, ("NwlinkAction->Option is (%x)\n", 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));
|
|
|
|
//
|
|
// It's enabled by default now
|
|
//
|
|
/*
|
|
|
|
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));
|
|
//
|
|
// It's enabled by default now
|
|
//
|
|
/*
|
|
|
|
CTEGetLock (&Device->Lock, &LockHandle);
|
|
|
|
if (AddressFile->EnableBroadcast) {
|
|
|
|
AddressFile->EnableBroadcast = FALSE;
|
|
IpxRemoveBroadcast (Device);
|
|
}
|
|
|
|
CTEFreeLock (&Device->Lock, LockHandle);
|
|
*/
|
|
break;
|
|
|
|
case MIPX_GETPKTSIZE:
|
|
|
|
//
|
|
// IPX_MAXSIZE.
|
|
//
|
|
// 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)))) {
|
|
|
|
// Get lock
|
|
IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
|
|
|
|
Binding = NIC_ID_TO_BINDING(Device, AdapterNum);
|
|
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;
|
|
Binding = NIC_ID_TO_BINDING(Device, i);
|
|
} while (Binding == NULL);
|
|
|
|
//CTEAssert (Binding->Adapter->MacInfo.MediumAsync);
|
|
//CTEAssert (i >= Binding->Adapter->FirstWanNicId);
|
|
//CTEAssert (AdapterNum <= Binding->Adapter->LastWanNicId);
|
|
// take out assertion because srv might have gotten the number
|
|
// of adapters before we finished bindadapters.
|
|
|
|
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 {
|
|
#ifdef SUNDOWN
|
|
u.IpxAddressData->status = (unsigned char) Binding->LineUp;
|
|
#else
|
|
u.IpxAddressData->status = Binding->LineUp;
|
|
#endif
|
|
|
|
|
|
*(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;
|
|
IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
|
|
} 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)) {
|
|
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 {
|
|
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 IO Manager calls the cancel routine, then it will
|
|
// set the cancel routine to be NULL.
|
|
// IoSetCancelRoutine returns the previous cancel
|
|
// routine, if the return value is null, then IO Manager
|
|
// has called the cancel routine. If not null, then
|
|
// the cancel routine has not been called and the irp
|
|
// was canceled before we set the cancel routine.
|
|
|
|
if (Request->Cancel &&
|
|
IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL) != NULL) {
|
|
|
|
(VOID)RemoveTailList (&Device->AddressNotifyQueue);
|
|
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 &&
|
|
IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL) != NULL) {
|
|
|
|
(VOID)RemoveTailList (&Device->LineChangeQueue);
|
|
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 {
|
|
|
|
|
|
if (Device->ForwarderBound) {
|
|
//
|
|
// [FW] Call the Forwarder's FindRoute if installed
|
|
//
|
|
|
|
//
|
|
// 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);
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case MIPX_RERIPNETNUM:
|
|
|
|
//
|
|
// 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);
|
|
|
|
//
|
|
// 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 {
|
|
|
|
|
|
if (Device->ForwarderBound) {
|
|
|
|
//
|
|
// [FW] Call the Forwarder's FindRoute if installed
|
|
//
|
|
|
|
//
|
|
// 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.
|
|
//
|
|
#ifdef SUNDOWN
|
|
REQUEST_INFORMATION(Request) = (ULONG_PTR)u.IpxNetnumData;
|
|
#else
|
|
REQUEST_INFORMATION(Request) = (ULONG)u.IpxNetnumData;
|
|
#endif
|
|
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
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);
|
|
|
|
//
|
|
// 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 {
|
|
|
|
|
|
if (Device->ForwarderBound) {
|
|
|
|
//
|
|
// [FW] Call the Forwarder's FindRoute if installed
|
|
//
|
|
|
|
//
|
|
// 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.
|
|
//
|
|
#ifdef SUNDOWN
|
|
REQUEST_INFORMATION(Request) = (ULONG_PTR)u.IpxNetnumData;
|
|
#else
|
|
REQUEST_INFORMATION(Request) = (ULONG)u.IpxNetnumData;
|
|
#endif
|
|
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case MIPX_SENDPTYPE:
|
|
case MIPX_NOSENDPTYPE:
|
|
|
|
//
|
|
// For the moment just use OptionsLength >= 1 to indicate
|
|
// that the send options include the packet type.
|
|
//
|
|
// 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.
|
|
//
|
|
// 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);
|
|
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 {
|
|
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);
|
|
IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
|
|
|
|
if (Binding = NIC_ID_TO_BINDING(Device, u.SetSrParameter->BoardNumber+1)) {
|
|
if (NwlinkAction->Option == MIPX_SRDEF) {
|
|
|
|
//
|
|
// 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 {
|
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
break;
|
|
|
|
case MIPX_SRREMOVE:
|
|
|
|
if (DataLength >= sizeof(SR_SET_REMOVE)) {
|
|
u.SetSrRemove = (PSR_SET_REMOVE)(NwlinkAction->Data);
|
|
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 {
|
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
break;
|
|
|
|
case MIPX_SRCLEAR:
|
|
|
|
if (DataLength >= sizeof(SR_SET_CLEAR)) {
|
|
u.SetSrClear = (PSR_SET_CLEAR)(NwlinkAction->Data);
|
|
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 {
|
|
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
|
|
//
|
|
|
|
//
|
|
// 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);
|
|
//
|
|
// 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.
|
|
//
|
|
FILL_LOCAL_TARGET(&u.GetLocalTarget->LocalTarget, 1);
|
|
CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
|
|
|
|
} else {
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
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.
|
|
//
|
|
#ifdef SUNDOWN
|
|
REQUEST_INFORMATION(Request) = (ULONG_PTR)u.GetLocalTarget;
|
|
#else
|
|
REQUEST_INFORMATION(Request) = (ULONG)u.GetLocalTarget;
|
|
#endif
|
|
|
|
|
|
InsertTailList(
|
|
&Device->Segments[Segment].WaitingLocalTarget,
|
|
REQUEST_LINKAGE(Request));
|
|
|
|
}
|
|
|
|
CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
|
|
}
|
|
|
|
}
|
|
|
|
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
|
|
//
|
|
|
|
//
|
|
// 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);
|
|
|
|
IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
|
|
CTEGetLock (&Device->SegmentLocks[Segment], &LockHandle);
|
|
|
|
//
|
|
// See which net card this is routed on.
|
|
//
|
|
|
|
RouteEntry = RipGetRoute (Segment, (PUCHAR)&u.GetNetworkInfo->Network);
|
|
|
|
if ((RouteEntry != NULL) &&
|
|
(Binding = NIC_ID_TO_BINDING(Device, RouteEntry->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;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Fail the call, we don't have a route yet.
|
|
// 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);
|
|
IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case MIPX_CONFIG:
|
|
|
|
//
|
|
// A request for details on every binding.
|
|
//
|
|
|
|
if (DataLength < sizeof(ISN_ACTION_GET_DETAILS)) {
|
|
IPX_DEBUG(ACTION, ("Not enought buffer %d < %d\n", 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 {
|
|
IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
|
|
Binding = NIC_ID_TO_BINDING(Device, u.GetDetails->NicId);
|
|
|
|
if ((Binding != NULL) &&
|
|
(u.GetDetails->NicId <= MIN (Device->MaxBindings, Device->ValidBindings))) {
|
|
|
|
ULONG StringLoc;
|
|
IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
|
|
IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
|
|
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)));
|
|
|
|
IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
|
|
} else {
|
|
IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
|
|
IPX_DEBUG(ACTION, ("Bad nic id %d\n",u.GetDetails->NicId));
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
//
|
|
// Return new nic info to the requestor. Currently, no check for
|
|
// who retrieved the info earlier.
|
|
//
|
|
case MIPX_GETNEWNICINFO:
|
|
|
|
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:
|
|
|
|
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;
|
|
|
|
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_NIC_NOTIFY);
|
|
}
|
|
}
|
|
|
|
}
|
|
#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 */
|
|
|
|
#define ROUTER_INFORMED_OF_NIC_CREATION 2
|
|
|
|
|
|
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;
|
|
BOOLEAN fIncDec = FALSE;
|
|
ULONG StringLoc = 0;
|
|
|
|
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
|
|
{
|
|
NdisQueryBufferSafe (REQUEST_NDIS_BUFFER(Request), (PVOID *)&NwlinkAction, &BufferLength, NormalPagePriority);
|
|
if (NwlinkAction == NULL) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
}
|
|
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;
|
|
|
|
IPX_DEBUG(BIND, ("GetNewNicInfo: pNicInfo=(%x), pLastNicInfo=(%x),LengthOfHeader=(%x), BindingCount=(%x)\n", pNicInfo, pLastNicInfo, LengthOfHeader, Device->ValidBindings));
|
|
IPX_DEBUG(BIND, ("BufferLength is (%d). Length for storing NICS is (%d)\n", BufferLength, (BufferLength - LengthOfHeader - FIELD_OFFSET(IPX_NICS, Data[0]))));
|
|
|
|
|
|
if (pNics->fAllNicsDesired) {
|
|
IPX_DEBUG(BIND, ("Yes, All NICs desired\n"));
|
|
} else {
|
|
IPX_DEBUG(BIND, ("No, All NICs NOT desired\n"));
|
|
|
|
}
|
|
|
|
//
|
|
// 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);
|
|
|
|
|
|
//
|
|
// If all nics are desired, then mark them ALL as dirty,
|
|
// for the subsequent IRPs that do not have this flag.
|
|
//
|
|
|
|
if (pNics->fAllNicsDesired) {
|
|
|
|
IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
|
|
|
|
for (n=0, i=LOOPBACK_NIC_ID; i<=Index; i++) {
|
|
|
|
Binding = NIC_ID_TO_BINDING(Device, i);
|
|
|
|
if (Binding) {
|
|
|
|
Binding->fInfoIndicated = FALSE;
|
|
|
|
}
|
|
}
|
|
|
|
IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
|
|
|
|
}
|
|
|
|
IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
|
|
for (n=0, i=LOOPBACK_NIC_ID; i<=Index; i++)
|
|
{
|
|
Binding = NIC_ID_TO_BINDING(Device, i);
|
|
|
|
if (!Binding)
|
|
{
|
|
NoOfNullNics++;
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// If the binding is of type autodetect *and* we haven't gotten a response on the adapter,
|
|
// that means IPX is still Autodetecting for this card. Do NOT tell FWD about it [shreem]
|
|
//
|
|
if (!Binding->PastAutoDetection) {
|
|
|
|
IPX_DEBUG(BIND, ("Binding[%d] Dont Tell FWD!\n", i));
|
|
NoOfNullNics++;
|
|
continue;
|
|
|
|
} else {
|
|
|
|
IPX_DEBUG(BIND, ("Binding[%d] Tell FWD about it (past auto detect)!\n", i));
|
|
|
|
}
|
|
|
|
//
|
|
// If we have already indicated info about this NIC, go on to the
|
|
// next nic.
|
|
//
|
|
if ((Binding->fInfoIndicated && !pNics->fAllNicsDesired)
|
|
|| (pNicInfo > pLastNicInfo))
|
|
{
|
|
if (Binding->fInfoIndicated) {
|
|
IPX_DEBUG(BIND, ("-------------------------> %d already indicated\n", i));
|
|
} else {
|
|
IPX_DEBUG(BIND, ("*********** Continue for another reason! (%d) \n", i));
|
|
}
|
|
|
|
if (pNicInfo > pLastNicInfo) {
|
|
IPX_DEBUG(BIND, ("pNicInfo: %x pLastNicInfo %x\n", 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;
|
|
//fIncDec = NIC_OPCODE_INCREMENT_NICIDS;
|
|
}
|
|
else
|
|
{
|
|
// pNicInfo->Status = NIC_LINE_DOWN;
|
|
|
|
pNicInfo->Status = NIC_DELETED;
|
|
//fIncDec = NIC_OPCODE_DECREMENT_NICIDS;
|
|
}
|
|
|
|
pNicInfo->InterfaceIndex = Binding->InterfaceIndex;
|
|
pNicInfo->MaxPacketSize =
|
|
Binding->MaxSendPacketSize - ASYNC_MEDIUM_HDR_LEN;
|
|
}
|
|
else
|
|
{
|
|
if (Binding->LocalAddress.NetworkAddress == 0)
|
|
{
|
|
|
|
pNicInfo->Status = NIC_CREATED;
|
|
|
|
if (ROUTER_INFORMED_OF_NIC_CREATION != Binding->PastAutoDetection) {
|
|
IPX_DEBUG(BIND, ("!!!!!!!---- Increment on Binding %x, index (%d)\n", Binding,i));
|
|
fIncDec = NIC_OPCODE_INCREMENT_NICIDS;
|
|
|
|
} else {
|
|
IPX_DEBUG(BIND, ("Already informed. No increment on Binding %x, index (%d)\n", Binding,i));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pNicInfo->Status = NIC_CONFIGURED;
|
|
|
|
//
|
|
// IPX might have already informed the Router of the
|
|
// creation of this NicId, in which case, we dont ask
|
|
// it to increment the NicIds [ShreeM]
|
|
//
|
|
if (ROUTER_INFORMED_OF_NIC_CREATION != Binding->PastAutoDetection) {
|
|
IPX_DEBUG(BIND, ("!!!!!!!!! --------Increment on Binding %x, index (%d)\n", Binding,i));
|
|
fIncDec = NIC_OPCODE_INCREMENT_NICIDS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Router pnp changes [ShreeM]
|
|
//
|
|
if (FALSE == Binding->LineUp) {
|
|
|
|
pNicInfo->Status = NIC_DELETED;
|
|
fIncDec = NIC_OPCODE_DECREMENT_NICIDS;
|
|
|
|
}
|
|
|
|
//
|
|
// Loopback Adapter
|
|
//
|
|
if (LOOPBACK_NIC_ID == Binding->NicId) {
|
|
|
|
pNicInfo->Status = NIC_CONFIGURED;
|
|
fIncDec = NIC_OPCODE_INCREMENT_NICIDS;
|
|
|
|
}
|
|
|
|
//
|
|
// 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;
|
|
|
|
//
|
|
// Zero the stuff out and then set fields that make sense.
|
|
//
|
|
RtlZeroMemory(&pNicInfo->Details, sizeof(ISN_ACTION_GET_DETAILS));
|
|
|
|
pNicInfo->Details.NetworkNumber = Binding->LocalAddress.NetworkAddress;
|
|
RtlCopyMemory(pNicInfo->Details.Node, Binding->LocalAddress.NodeAddress, HARDWARE_ADDRESS_LENGTH);
|
|
pNicInfo->Details.NicId = Binding->NicId;
|
|
pNicInfo->Details.BindingSet = Binding->BindingSetMember;
|
|
pNicInfo->Details.FrameType = Binding->FrameType;
|
|
|
|
if (Binding->Adapter->MacInfo.MediumAsync) {
|
|
if (Binding->LineUp) {
|
|
pNicInfo->Details.Type = 2;
|
|
} else {
|
|
pNicInfo->Details.Type = 3;
|
|
}
|
|
} else {
|
|
pNicInfo->Details.Type = 1;
|
|
}
|
|
|
|
//
|
|
// Copy the adapter name, including the final NULL.
|
|
//
|
|
|
|
StringLoc = (Binding->Adapter->AdapterNameLength / sizeof(WCHAR)) - 2;
|
|
while (Binding->Adapter->AdapterName[StringLoc] != L'\\') {
|
|
--StringLoc;
|
|
}
|
|
|
|
RtlCopyMemory(
|
|
pNicInfo->Details.AdapterName,
|
|
&Binding->Adapter->AdapterName[StringLoc+1],
|
|
Binding->Adapter->AdapterNameLength - ((StringLoc+1) * sizeof(WCHAR)));
|
|
|
|
//
|
|
// Tell the forwarder that the rest of the NICIDs are to be moved up/down
|
|
// only if it is not asking for ALL of them
|
|
//
|
|
if (!pNics->fAllNicsDesired) {
|
|
pNicInfo->Status |= fIncDec;
|
|
}
|
|
|
|
pNicInfo->ConnectionId = Binding->ConnectionId;
|
|
pNicInfo->IpxwanConfigRequired = Binding->IpxwanConfigRequired;
|
|
|
|
#if DBG
|
|
//
|
|
// Dump the IPX_NIC_INFO Structure.
|
|
//
|
|
|
|
IPX_DEBUG(BIND, ("%d.\nNICID= %d, Interface Index = %d\n", i, pNicInfo->Details.NicId, pNicInfo->InterfaceIndex));
|
|
|
|
IPX_DEBUG(BIND, ("Interface Index = %d\n", pNicInfo->InterfaceIndex));
|
|
IPX_DEBUG(BIND, ("LinkSpeed = %d\n", pNicInfo->LinkSpeed));
|
|
IPX_DEBUG(BIND, ("PacketType = %d\n", pNicInfo->PacketType));
|
|
IPX_DEBUG(BIND, ("MaxPacketSize = %d\n", pNicInfo->MaxPacketSize));
|
|
IPX_DEBUG(BIND, ("NdisMediumType = %d\n", pNicInfo->NdisMediumType));
|
|
IPX_DEBUG(BIND, ("NdisMediumSubtype = %d\n", pNicInfo->NdisMediumSubtype));
|
|
IPX_DEBUG(BIND, ("Status = %d\n", (ULONG) pNicInfo->Status));
|
|
IPX_DEBUG(BIND, ("ConnectionID = %d\n", pNicInfo->ConnectionId));
|
|
IPX_DEBUG(BIND, ("IpxwanConfigRequired = %d\n", pNicInfo->IpxwanConfigRequired));
|
|
|
|
IPX_DEBUG(BIND, ("FrameType = %d\n", pNicInfo->Details.FrameType));
|
|
IPX_DEBUG(BIND, ("Type = %d\n", pNicInfo->Details.Type));
|
|
IPX_DEBUG(BIND, ("NetworkNumber = %d\n", pNicInfo->Details.NetworkNumber));
|
|
IPX_DEBUG(BIND, ("BindingSet = %d\n", pNicInfo->Details.BindingSet));
|
|
IPX_DEBUG(BIND, ("LocalNode = %x-%x-%x-%x-%x-%x\n", pNicInfo->Details.Node[0],
|
|
pNicInfo->Details.Node[1],
|
|
pNicInfo->Details.Node[2],
|
|
pNicInfo->Details.Node[3],
|
|
pNicInfo->Details.Node[4],
|
|
pNicInfo->Details.Node[5]));
|
|
|
|
IPX_DEBUG(BIND, ("RemoteNode = %x-%x-%x-%x-%x-%x\n", pNicInfo->RemoteNodeAddress[0],
|
|
pNicInfo->RemoteNodeAddress[1],
|
|
pNicInfo->RemoteNodeAddress[2],
|
|
pNicInfo->RemoteNodeAddress[3],
|
|
pNicInfo->RemoteNodeAddress[4],
|
|
pNicInfo->RemoteNodeAddress[5]));
|
|
|
|
//IPX_DEBUG(BIND, ("AdadpterName = %ws\n", pNicInfo->Details.AdapterName));
|
|
|
|
#endif
|
|
|
|
pNicInfo++; //increment to store next nic info
|
|
n++; //indicates the # of nics processed so far.
|
|
Binding->fInfoIndicated = TRUE;
|
|
Binding->PastAutoDetection = ROUTER_INFORMED_OF_NIC_CREATION;
|
|
IPX_DEBUG(BIND, ("Iteration no = (%d) complete : reporting NicId:(%lx)\n", n, Binding->NicId));
|
|
|
|
|
|
}
|
|
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) {
|
|
|
|
IPX_DEBUG(BIND, ("GetNewNicInfo: Inserting Irp\n"));
|
|
CTEGetLock (&Device->Lock, &LockHandle);
|
|
|
|
InsertTailList( &Device->NicNtfQueue, REQUEST_LINKAGE(Request) );
|
|
|
|
if (!OldIrp)
|
|
{
|
|
IoSetCancelRoutine (Request, IpxCancelAction);
|
|
}
|
|
if (Request->Cancel &&
|
|
IoSetCancelRoutine(Request, (PDRIVER_CANCEL)NULL)) {
|
|
|
|
IPX_DEBUG(BIND, ("GetNewNicInfo:Cancelling Irp\n"));
|
|
(VOID)RemoveTailList (&Device->NicNtfQueue);
|
|
CTEFreeLock (&Device->Lock, LockHandle);
|
|
Status = STATUS_CANCELLED;
|
|
|
|
} else {
|
|
if (!OldIrp)
|
|
{
|
|
IpxReferenceDevice (Device, DREF_NIC_NOTIFY);
|
|
}
|
|
Status = STATUS_PENDING;
|
|
CTEFreeLock (&Device->Lock, LockHandle);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
IPX_DEBUG(BIND, ("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);
|
|
|
|
IPX_DEBUG(BIND, ("IpxAbortNtfChange: There is at least one IRP in the queue\n"));
|
|
p = p->Flink;
|
|
|
|
if (ControlChId.QuadPart == ((PLARGE_INTEGER)ControlChannelContext)->QuadPart) {
|
|
IPX_DEBUG(BIND, ("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 );
|
|
|
|
IPX_DEBUG(BIND, ("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;
|
|
}
|
|
|
|
// 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;
|
|
|
|
|
|
//
|
|
// 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,
|
|
#if defined(_PNP_POWER_)
|
|
&IpxDeviceName,
|
|
NULL,
|
|
#endif _PNP_POWER_
|
|
&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);
|
|
}
|
|
|
|
//
|
|
// 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.
|
|
//
|
|
// 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;
|
|
|
|
//
|
|
// 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.
|
|
//
|
|
// Use RipSendResponse, and do it even
|
|
// if SingleNetworkActive is FALSE??
|
|
//
|
|
|
|
if (Device->RipResponder && Binding->DialOutAsync) {
|
|
(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);
|
|
NdisQueryBufferSafe (REQUEST_NDIS_BUFFER(Request), (PVOID *)&NwlinkAction, &BufferLength, HighPagePriority);
|
|
|
|
if (NwlinkAction == NULL) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
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; // 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);
|
|
|
|
IPX_DEBUG(BIND, ("IpxStatus: WAN LINE UP\n"));
|
|
Status = GetNewNics(Device, Request, FALSE, NULL, 0, TRUE);
|
|
if (Status == STATUS_PENDING)
|
|
{
|
|
IPX_DEBUG(BIND, ("WANLineUp may not be responding properly\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;
|
|
}
|