summaryrefslogtreecommitdiffstats
path: root/private/ntos/tdi/acd/timer.c
blob: cf4f3ab633588d23835b2609a3e16af6fe44ef08 (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
/*++

Copyright (c) 1995 Microsoft Corporation

Module Name:

    timer.c

Abstract:

    Timer thread to monitor connection progress in the
    automatic connection driver (acd.sys).

Author:

    Anthony Discolo (adiscolo)  25-Apr-1995

Environment:

    Kernel Mode

Revision History:

--*/

#include <ndis.h>
#include <cxport.h>
#include <tdi.h>
#include <tdikrnl.h>
#include <tdistat.h>
#include <tdiinfo.h>
#include <acd.h>

#include "acdapi.h"
#include "table.h"
#include "acddefs.h"
#include "debug.h"

//
// Imported routines.
//
VOID
AcdSignalCompletionCommon(
    IN PACD_CONNECTION pConnection,
    IN BOOLEAN fSuccess
    );

//
// Keep track how long the user-space
// process has been attempting a connection.
//
#define ACD_MAX_TIMER_CALLS    3*60     // 3 minutes

//
// We give the user-space process
// some slack on missed pings.
//
#define ACD_MAX_MISSED_PINGS   40       // 20 seconds



VOID
AcdConnectionTimer(
    IN PDEVICE_OBJECT pDeviceObject,
    IN PVOID          pContext
    )
{
    PLIST_ENTRY pEntry;
    PACD_CONNECTION pConnection;
    BOOLEAN bCancel = FALSE;

    //
    // Acquire the spin lock.
    // We're guaranteed to be at DPC
    // since this is a timer routine.
    //
    KeAcquireSpinLockAtDpcLevel(&AcdSpinLockG);
    //
    // If the user-space process responsible
    // for creating the connection hasn't
    // pinged us in a while, or if it hasn't
    // created a connection in 3 minutes,
    // cancel all the pending requests.
    //
    for (pEntry = AcdConnectionQueueG.Flink;
         pEntry != &AcdConnectionQueueG;
         pEntry = pEntry->Flink)
    {
        pConnection = CONTAINING_RECORD(pEntry, ACD_CONNECTION, ListEntry);

        IF_ACDDBG(ACD_DEBUG_TIMER) {
            PACD_COMPLETION pCompletion;

            AcdPrint((
              "AcdConnectionTimer: pConnection=0x%x, fNotif=%d, szAddr=",
              pConnection,
              pConnection->fNotif));
            pCompletion = CONTAINING_RECORD(pConnection->CompletionList.Flink, ACD_COMPLETION, ListEntry);
            AcdPrintAddress(&pCompletion->notif.addr);
            AcdPrint((", nTimerCalls=%d, nMissedPings=%d\n",
              pConnection->ulTimerCalls,
              pConnection->ulMissedPings));
        }
        //
        // If we haven't reported the connection to
        // user space yet, or it is in the process of
        // being completed, then don't time it out.
        //
        if (!pConnection->fNotif || pConnection->fCompleting)
            continue;

        pConnection->ulTimerCalls++;
        if (pConnection->fProgressPing)
            pConnection->ulMissedPings = 0;
        else
            pConnection->ulMissedPings++;
        if (pConnection->ulTimerCalls >= ACD_MAX_TIMER_CALLS ||
            pConnection->ulMissedPings >= ACD_MAX_MISSED_PINGS)
        {
            IF_ACDDBG(ACD_DEBUG_TIMER) {
                AcdPrint((
                  "AcdConnectionTimer: canceling pConnection=0x%x\n",
                  pConnection));
            }
            //
            // Set the completion-in-progress flag so
            // this request cannot be completed after
            // we release the spin lock.
            //
            pConnection->fCompleting = TRUE;
            bCancel = TRUE;
            break;
        }
    }
    //
    // Release the spin lock.
    //
    KeReleaseSpinLockFromDpcLevel(&AcdSpinLockG);
    //
    // We now process all the canceled requests.
    //
    if (bCancel)
        AcdSignalCompletionCommon(pConnection, FALSE);
} // AcdConnectionTimer