|
|
1.1 root 1: /*++
2:
3: Copyright (c) 1989-1993 Microsoft Corporation
4:
5: Module Name:
6:
7: rcveng.c
8:
9: Abstract:
10:
11: This module contains code that implements the receive engine for the
12: Sample transport provider.
13:
14: Environment:
15:
16: Kernel mode
17:
18: Revision History:
19:
20: --*/
21:
22: #include "st.h"
23:
24:
25: VOID
26: ActivateReceive(
27: PTP_CONNECTION Connection
28: )
29:
30: /*++
31:
32: Routine Description:
33:
34: This routine activates the next TdiReceive request on the specified
35: connection object if there is no active request on that connection
36: already. This allows the request to accept data on the connection.
37:
38: Arguments:
39:
40: Connection - Pointer to a TP_CONNECTION object.
41:
42: Return Value:
43:
44: none.
45:
46: --*/
47:
48: {
49: KIRQL oldirql;
50: PTP_REQUEST Request;
51:
52: //
53: // The ACTIVE_RECEIVE bitflag will be set on the connection if
54: // the receive-fields in the CONNECTION object are valid. If
55: // this flag is cleared, then we try to make the next TdiReceive
56: // request in the ReceiveQueue the active request.
57: //
58:
59: ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
60: if (!(Connection->Flags & CONNECTION_FLAGS_ACTIVE_RECEIVE)) {
61: if (!IsListEmpty (&Connection->ReceiveQueue)) {
62:
63: //
64: // Found a receive, so make it the active one.
65: //
66:
67: Connection->Flags |= CONNECTION_FLAGS_ACTIVE_RECEIVE;
68:
69: Request = CONTAINING_RECORD (
70: Connection->ReceiveQueue.Flink,
71: TP_REQUEST,
72: Linkage);
73: Connection->MessageBytesReceived = 0;
74: Connection->MessageBytesAcked = 0;
75: Connection->CurrentReceiveRequest = Request;
76: Connection->CurrentReceiveMdl = Request->Buffer2;
77: Connection->ReceiveLength = Request->Buffer2Length;
78: Connection->ReceiveByteOffset = 0;
79: }
80: }
81:
82: RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
83:
84: } /* ActivateReceive */
85:
86:
87: VOID
88: AwakenReceive(
89: PTP_CONNECTION Connection
90: )
91:
92: /*++
93:
94: Routine Description:
95:
96: This routine is called to reactivate a sleeping connection with the
97: RECEIVE_WAKEUP bitflag set because data arrived for which no receive
98: was available. The caller has made a receive available at the connection,
99: so here we activate the next receive, and send the appropriate protocol
100: to restart the message at the first byte offset past the one received
101: by the last receive.
102:
103: Arguments:
104:
105: Connection - Pointer to a TP_CONNECTION object.
106:
107: Return Value:
108:
109: none.
110:
111: --*/
112:
113: {
114: KIRQL oldirql;
115:
116: //
117: // If the RECEIVE_WAKEUP bitflag is set, then awaken the connection.
118: //
119:
120: ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
121: if (Connection->Flags & CONNECTION_FLAGS_RECEIVE_WAKEUP) {
122: if (Connection->ReceiveQueue.Flink != &Connection->ReceiveQueue) {
123: Connection->Flags &= ~CONNECTION_FLAGS_RECEIVE_WAKEUP;
124:
125: //
126: // Found a receive, so turn off the wakeup flag, and activate
127: // the next receive.
128: //
129:
130: RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
131: ActivateReceive (Connection);
132:
133: return;
134: }
135: }
136: RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
137: } /* AwakenReceive */
138:
139:
140: VOID
141: CompleteReceive(
142: PTP_CONNECTION Connection,
143: BOOLEAN EndOfRecord,
144: KIRQL ConnectionIrql,
145: KIRQL CancelIrql
146: )
147:
148: /*++
149:
150: Routine Description:
151:
152: This routine is called by ProcessIncomingData when the current receive
153: must be completed. Depending on whether the current frame being
154: processed is a DATA_FIRST_MIDDLE or DATA_ONLY_LAST, and also whether
155: all of the data was processed, the EndOfRecord flag will be set accordingly
156: by the caller to indicate that a message boundary was received.
157:
158: NOTE: This function is called with the connection and cancel
159: IRQLs held, and returns with them released.
160:
161: Arguments:
162:
163: Connection - Pointer to a TP_CONNECTION object.
164:
165: EndOfRecord - BOOLEAN set to true if TDI_END_OF_RECORD should be reported.
166:
167: ConnectionIrql - The IRQL at which the connection spinlock was acquired.
168:
169: CancelIrql - The IRQL at which the cancel spinlock was acquired.
170:
171: Return Value:
172:
173: none.
174:
175: --*/
176:
177: {
178: PLIST_ENTRY p;
179: PTP_REQUEST Request;
180: KIRQL oldirql = ConnectionIrql;
181: KIRQL cancelirql = CancelIrql;
182: ULONG BytesReceived;
183:
184:
185: if (IsListEmpty (&Connection->ReceiveQueue)) {
186:
187: ASSERT ((Connection->Flags & CONNECTION_FLAGS_STOPPING) != 0);
188:
189: RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
190: IoReleaseCancelSpinLock(cancelirql);
191: return;
192: }
193:
194: Connection->Flags &= ~CONNECTION_FLAGS_ACTIVE_RECEIVE;
195: BytesReceived = Connection->MessageBytesReceived;
196:
197:
198: //
199: // Complete the TdiReceive request at the head of the
200: // connection's ReceiveQueue.
201: //
202:
203: p = RemoveHeadList (&Connection->ReceiveQueue);
204: Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
205:
206: Request->IoRequestPacket->CancelRoutine = (PDRIVER_CANCEL)NULL;
207:
208: RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
209: IoReleaseCancelSpinLock(cancelirql);
210:
211:
212: Request->Flags |= REQUEST_FLAGS_DELAY;
213:
214: StCompleteRequest(
215: Request,
216: EndOfRecord ? STATUS_SUCCESS : STATUS_BUFFER_OVERFLOW,
217: BytesReceived);
218:
219: } /* CompleteReceive */
220:
221:
222: VOID
223: StCancelReceive(
224: IN PDEVICE_OBJECT DeviceObject,
225: IN PIRP Irp
226: )
227:
228: /*++
229:
230: Routine Description:
231:
232: This routine is called by the I/O system to cancel a receive.
233: The receive is found on the connection's receive queue; if it
234: is the current request it is cancelled and the connection
235: goes into "cancelled receive" mode, otherwise it is cancelled
236: silently.
237:
238: In "cancelled receive" mode the connection makes it appear to
239: the remote the data is being received, but in fact it is not
240: indicated to the transport or buffered on our end
241:
242: NOTE: This routine is called with the CancelSpinLock held and
243: is responsible for releasing it.
244:
245: Arguments:
246:
247: DeviceObject - Pointer to the device object for this driver.
248:
249: Irp - Pointer to the request packet representing the I/O request.
250:
251: Return Value:
252:
253: none.
254:
255: --*/
256:
257: {
258: KIRQL oldirql;
259: PIO_STACK_LOCATION IrpSp;
260: PTP_CONNECTION Connection;
261: PTP_REQUEST Request;
262: PLIST_ENTRY p;
263: ULONG BytesReceived;
264: BOOLEAN Found;
265:
266: UNREFERENCED_PARAMETER (DeviceObject);
267:
268: //
269: // Get a pointer to the current stack location in the IRP. This is where
270: // the function codes and parameters are stored.
271: //
272:
273: IrpSp = IoGetCurrentIrpStackLocation (Irp);
274:
275: ASSERT ((IrpSp->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
276: (IrpSp->MinorFunction == TDI_RECEIVE));
277:
278: Connection = IrpSp->FileObject->FsContext;
279:
280: //
281: // Since this IRP is still in the cancellable state, we know
282: // that the connection is still around (although it may be in
283: // the process of being torn down).
284: //
285:
286: //
287: // See if this is the IRP for the current receive request.
288: //
289:
290: ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
291:
292: BytesReceived = Connection->MessageBytesReceived;
293:
294: p = Connection->ReceiveQueue.Flink;
295:
296: //
297: // If there is a receive active, then see if this is it.
298: //
299:
300: if ((Connection->Flags & CONNECTION_FLAGS_ACTIVE_RECEIVE) != 0) {
301:
302: Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
303:
304: if (Request->IoRequestPacket == Irp) {
305:
306: //
307: // yes, it is the active receive. Turn on the RCV_CANCELLED
308: // bit instructing the connection to drop the rest of the
309: // data received (until the DOL comes in).
310: //
311:
312: Connection->Flags2 |= CONNECTION_FLAGS2_RCV_CANCELLED;
313: Connection->Flags &= ~CONNECTION_FLAGS_ACTIVE_RECEIVE;
314:
315: (VOID)RemoveHeadList (&Connection->ReceiveQueue);
316:
317: RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
318: IoReleaseCancelSpinLock (Irp->CancelIrql);
319:
320: //
321: // The following dereference will complete the I/O, provided removes
322: // the last reference on the request object. The I/O will complete
323: // with the status and information stored in the Irp. Therefore,
324: // we set those values here before the dereference.
325: //
326:
327: StCompleteRequest (Request, STATUS_CANCELLED, 0);
328: return;
329:
330: }
331:
332: }
333:
334:
335: //
336: // If we fall through to here, the IRP was not the active receive.
337: // Scan through the list, looking for this IRP.
338: //
339:
340: Found = FALSE;
341:
342: while (p != &Connection->ReceiveQueue) {
343:
344: Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
345: if (Request->IoRequestPacket == Irp) {
346:
347: //
348: // Found it, remove it from the list here.
349: //
350:
351: RemoveEntryList (p);
352: Found = TRUE;
353:
354: RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
355: IoReleaseCancelSpinLock (Irp->CancelIrql);
356:
357: //
358: // The following dereference will complete the I/O, provided removes
359: // the last reference on the request object. The I/O will complete
360: // with the status and information stored in the Irp. Therefore,
361: // we set those values here before the dereference.
362: //
363:
364: StCompleteRequest (Request, STATUS_CANCELLED, 0);
365: break;
366:
367: }
368:
369: p = p->Flink;
370:
371: }
372:
373: if (!Found) {
374:
375: //
376: // We didn't find it!
377: //
378:
379: RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
380: IoReleaseCancelSpinLock (Irp->CancelIrql);
381: }
382:
383: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.