summaryrefslogblamecommitdiffstats
path: root/private/ntos/ndis/elnkii/pend.c
blob: b2d343852e9aaf2b328932361dce46591fe4c1f4 (plain) (tree)
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
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440























































































































































































































































































































































































































































                                                                                         
/*++

Copyright (c) 1990  Microsoft Corporation

Module Name:

    pend.c

Abstract:

    Multicast and filter functions for the NDIS 3.0 Etherlink II driver.

Author:

    Adam Barr (adamba) 30-Jul-1990
    Aaron Ogus (aarono) 27-Sep-1991

Environment:

    Kernel mode, FSD

Revision History:


 Aaron Ogus (aarono) 27-Sep-1991
   Changes to NdisRequest() format required changes to pending operations
 Sean Selitrennikoff (seanse) Dec-1991
   Changes to meet standard model for NDIS drivers.

--*/

#include <ndis.h>
#include <efilter.h>
#include "elnkhrd.h"
#include "elnksft.h"


VOID
HandlePendingOperations(
    IN PVOID SystemSpecific1,
    IN PVOID DeferredContext,       // will be a pointer to the adapter block
    IN PVOID SystemSpecific2,
    IN PVOID SystemSpecific3
    )

/*++

Routine Description:

    Called by pending functions to process elements on the
    pending queue.

Arguments:

    DeferredContext - will be a pointer to the adapter block

Return Value:

    None.

--*/

{
    PELNKII_ADAPTER AdaptP = ((PELNKII_ADAPTER)DeferredContext);
    PELNKII_PEND_DATA PendOp;
    PELNKII_OPEN TmpOpen;
    NDIS_STATUS Status;

    UNREFERENCED_PARAMETER(SystemSpecific1);
    UNREFERENCED_PARAMETER(SystemSpecific2);
    UNREFERENCED_PARAMETER(SystemSpecific3);

    NdisAcquireSpinLock(&AdaptP->Lock);

    AdaptP->References++;

    //
    // If an operation is being dispatched or a reset is running, exit.
    //

    if ((!AdaptP->ResetInProgress) && (AdaptP->PendOp == NULL)) {

        for (;;) {

            //
            // We hold SpinLock here.
            //

            if (AdaptP->PendQueue != NULL) {

                //
                // Take the request off the queue and dispatch it.
                //

                PendOp = AdaptP->PendQueue;

                AdaptP->PendQueue = PendOp->Next;

                if (PendOp == AdaptP->PendQTail) {

                    AdaptP->PendQTail = NULL;

                }

                AdaptP->PendOp = PendOp;

                NdisReleaseSpinLock(&AdaptP->Lock);

                Status = ((PendOp->RequestType == NdisRequestClose) ||
                          (PendOp->RequestType == NdisRequestGeneric3)) ?
                              DispatchSetMulticastAddressList(AdaptP)  :
                              DispatchSetPacketFilter(AdaptP);

                TmpOpen = PendOp->Open;

                if ((PendOp->RequestType != NdisRequestGeneric1) &&
                    (PendOp->RequestType != NdisRequestClose)) {  // Close Adapter


                    //
                    // Complete it since it previously pended.
                    //

                    NdisCompleteRequest(PendOp->Open->NdisBindingContext,
                        PNDIS_REQUEST_FROM_PELNKII_PEND_DATA(PendOp),
                        Status);

                }

                //
                // This will call CompleteClose if necessary.
                //

                NdisAcquireSpinLock(&AdaptP->Lock);

                TmpOpen->ReferenceCount--;

                if (AdaptP->ResetInProgress) {

                    //
                    // We have to stop processing requests.
                    //

                    break;     // jump to BREAK_LOCATION
                }

            } else {

                break;     // jump to BREAK_LOCATION

            }
        }

        //
        // BREAK_LOCATION
        //
        // Hold Lock here.
        //

        AdaptP->PendOp = NULL;

        if (AdaptP->ResetInProgress) {

            //
            // Exited due to a reset, indicate that the DPC
            // handler is done for now.
            //

            AdaptP->References--;

            NdisReleaseSpinLock(&AdaptP->Lock);

            ElnkiiResetStageDone(AdaptP, MULTICAST_RESET);

            return;
        }

    }

    if (AdaptP->CloseQueue != NULL) {

        PELNKII_OPEN OpenP;
        PELNKII_OPEN TmpOpenP;
        PELNKII_OPEN PrevOpenP;

        //
        // Check for an open that may have closed
        //

        OpenP = AdaptP->CloseQueue;
        PrevOpenP = NULL;

        while (OpenP != NULL) {

            if (OpenP->ReferenceCount > 0) {

                OpenP = OpenP->NextOpen;
                PrevOpenP = OpenP;

                continue;

            }

#if DBG

            if (!OpenP->Closing) {

                DbgPrint("BAD CLOSE: %d\n", OpenP->ReferenceCount);

                DbgBreakPoint();

                OpenP = OpenP->NextOpen;
                PrevOpenP = OpenP;

                continue;

            }

#endif


            //
            // The last reference is completed; a previous call to ElnkiiCloseAdapter
            // will have returned NDIS_STATUS_PENDING, so things must be finished
            // off now.
            //

            //
            // Check if MaxLookAhead needs adjusting.
            //

            if (OpenP->LookAhead == AdaptP->MaxLookAhead) {

                ElnkiiAdjustMaxLookAhead(AdaptP);

            }

            NdisReleaseSpinLock(&AdaptP->Lock);

            NdisCompleteCloseAdapter (OpenP->NdisBindingContext, NDIS_STATUS_SUCCESS);

            NdisAcquireSpinLock(&AdaptP->Lock);

            //
            // Remove from close list
            //

            if (PrevOpenP != NULL) {

                PrevOpenP->NextOpen = OpenP->NextOpen;

            } else {

                AdaptP->CloseQueue = OpenP->NextOpen;
            }

            //
            // Go to next one
            //

            TmpOpenP = OpenP;
            OpenP = OpenP->NextOpen;

            NdisFreeMemory(TmpOpenP, sizeof(ELNKII_OPEN), 0);

        }

        if ((AdaptP->CloseQueue == NULL) && (AdaptP->OpenQueue == NULL)) {

            //
            // We can stop the card.
            //

            CardStop(AdaptP);

        }

    }

    ELNKII_DO_DEFERRED(AdaptP);

}

NDIS_STATUS
DispatchSetPacketFilter(
    IN PELNKII_ADAPTER AdaptP
    )

/*++

Routine Description:

    Sets the appropriate bits in the adapter filters
    and modifies the card Receive Configuration Register if needed.

Arguments:

    AdaptP - Pointer to the adapter block

Return Value:

    The final status (always NDIS_STATUS_SUCCESS).

Notes:

  - Note that to receive all multicast packets the multicast
    registers on the card must be filled with 1's. To be
    promiscuous that must be done as well as setting the
    promiscuous physical flag in the RCR. This must be done
    as long as ANY protocol bound to this adapter has their
    filter set accordingly.

--*/


{
    UINT PacketFilter;

    PacketFilter = ETH_QUERY_FILTER_CLASSES(AdaptP->FilterDB);

    //
    // See what has to be put on the card.
    //

    if (PacketFilter & (NDIS_PACKET_TYPE_ALL_MULTICAST | NDIS_PACKET_TYPE_PROMISCUOUS)) {

        //
        // need "all multicast" now.
        //

        CardSetAllMulticast(AdaptP);    // fills it with 1's

    } else {

        //
        // No longer need "all multicast".
        //

        DispatchSetMulticastAddressList(AdaptP);

    }


    //
    // The multicast bit in the RCR should be on if ANY protocol wants
    // multicast/all multicast packets (or is promiscuous).
    //

    if (PacketFilter & (NDIS_PACKET_TYPE_ALL_MULTICAST |
                        NDIS_PACKET_TYPE_MULTICAST |
                        NDIS_PACKET_TYPE_PROMISCUOUS)) {

        AdaptP->NicReceiveConfig |= RCR_MULTICAST;

    } else {

        AdaptP->NicReceiveConfig &= ~RCR_MULTICAST;

    }


    //
    // The promiscuous physical bit in the RCR should be on if ANY
    // protocol wants to be promiscuous.
    //

    if (PacketFilter & NDIS_PACKET_TYPE_PROMISCUOUS) {

        AdaptP->NicReceiveConfig |= RCR_ALL_PHYS;

    } else {

        AdaptP->NicReceiveConfig &= ~RCR_ALL_PHYS;

    }


    //
    // The broadcast bit in the RCR should be on if ANY protocol wants
    // broadcast packets (or is promiscuous).
    //

    if (PacketFilter & (NDIS_PACKET_TYPE_BROADCAST | NDIS_PACKET_TYPE_PROMISCUOUS)) {

        AdaptP->NicReceiveConfig |= RCR_BROADCAST;

    } else {

        AdaptP->NicReceiveConfig &= ~RCR_BROADCAST;

    }


    CardSetReceiveConfig(AdaptP);

    return NDIS_STATUS_SUCCESS;
}



NDIS_STATUS
DispatchSetMulticastAddressList(
    IN PELNKII_ADAPTER AdaptP
    )

/*++

Routine Description:

    Sets the multicast list for this open

Arguments:

    AdaptP - Pointer to the adapter block

Return Value:

Implementation Note:

    When invoked, we are to make it so that the multicast list in the filter
    package becomes the multicast list for the adapter. To do this, we
    determine the required contents of the NIC multicast registers and
    update them.


--*/
{

    //
    // Update the local copy of the NIC multicast regs and copy them to the NIC
    //

    CardFillMulticastRegs(AdaptP);

    CardCopyMulticastRegs(AdaptP);

    return NDIS_STATUS_SUCCESS;
}