/*++ 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 */