summaryrefslogtreecommitdiffstats
path: root/private/ntos/tdi/isnp/nb/action.c
blob: 9ff843a76bf8cdab1b4419a6af1ed9be5555540d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
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 */