diff options
Diffstat (limited to '')
-rw-r--r-- | private/ntos/tdi/isnp/nb/action.c | 221 |
1 files changed, 221 insertions, 0 deletions
diff --git a/private/ntos/tdi/isnp/nb/action.c b/private/ntos/tdi/isnp/nb/action.c new file mode 100644 index 000000000..9ff843a76 --- /dev/null +++ b/private/ntos/tdi/isnp/nb/action.c @@ -0,0 +1,221 @@ +/*++ + +Copyright (c) 1989-1993 Microsoft Corporation + +Module Name: + + action.c + +Abstract: + + This module contains code which implements the TDI action + dispatch routines. + +Environment: + + Kernel mode + +Revision History: + +--*/ + +#include "precomp.h" +#pragma hdrstop + + +typedef struct _NB_ACTION_GET_COUNTS { + USHORT MaximumNicId; // returns maximum NIC ID + USHORT NicIdCounts[32]; // session counts for first 32 NIC IDs +} NB_ACTION_GET_COUNTS, *PNB_ACTION_GET_COUNTS; + + +NTSTATUS +NbiTdiAction( + IN PDEVICE Device, + IN PREQUEST Request + ) + +/*++ + +Routine Description: + + This routine handles action requests. + +Arguments: + + Device - The netbios device. + + Request - The request describing the action. + +Return Value: + + NTSTATUS - status of operation. + +--*/ + +{ + + NTSTATUS Status; + PADDRESS_FILE AddressFile; + PCONNECTION Connection; + UINT BufferLength; + UINT DataLength; + PNDIS_BUFFER NdisBuffer; + CTELockHandle LockHandle; + union { + PNB_ACTION_GET_COUNTS GetCounts; + } u; // BUGBUG: Make these unaligned?? + PNWLINK_ACTION NwlinkAction; + UINT i; + static UCHAR BogusId[4] = { 0x01, 0x00, 0x00, 0x00 }; // old nwrdr uses this + + + // + // 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]))) { + NB_DEBUG (QUERY, ("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) { + NB_DEBUG (QUERY, ("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 != NB_ADDRESSFILE_SIGNATURE)) { + + NB_DEBUG (QUERY, ("Nwlink action failed, bad address file\n")); + return STATUS_INVALID_HANDLE; + } + + } else if (NwlinkAction->OptionType != NWLINK_OPTION_CONTROL) { + + NB_DEBUG (QUERY, ("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) { + + case (I_MIPX | 351): + + // + // A request for details on every binding. + // + + if (DataLength < sizeof(NB_ACTION_GET_COUNTS)) { + return STATUS_BUFFER_TOO_SMALL; + } + + u.GetCounts = (PNB_ACTION_GET_COUNTS)(NwlinkAction->Data); + + u.GetCounts->MaximumNicId = NbiDevice->MaximumNicId; + + for (i = 0; i < 32 ; i++) { + u.GetCounts->NicIdCounts[i] = 0; + } + + for (i = 0; i < CONNECTION_HASH_COUNT; i++) { + + NB_GET_LOCK (&Device->Lock, &LockHandle); + + Connection = Device->ConnectionHash[i].Connections; + + while (Connection != NULL) { +#if defined(_PNP_POWER) + if ((Connection->State == CONNECTION_STATE_ACTIVE) && + (Connection->LocalTarget.NicHandle.NicId < 32)) { + + ++u.GetCounts->NicIdCounts[Connection->LocalTarget.NicHandle.NicId]; + } +#else + if ((Connection->State == CONNECTION_STATE_ACTIVE) && + (Connection->LocalTarget.NicId < 32)) { + + ++u.GetCounts->NicIdCounts[Connection->LocalTarget.NicId]; + } +#endif _PNP_POWER + Connection = Connection->NextConnection; + } + + NB_FREE_LOCK (&Device->Lock, LockHandle); + + } + + 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)) { + NB_DEBUG (QUERY, ("Nwlink action %lx failed, status %lx\n", NwlinkAction->Option, Status)); + } +#endif + + return Status; + +} /* NbiTdiAction */ + |