|
|
1.1 root 1: /*++
2:
3: Copyright (c) 1989-1993 Microsoft Corporation
4:
5: Module Name:
6:
7: send.c
8:
9: Abstract:
10:
11: This module contains code which performs the following TDI services:
12:
13: o TdiSend
14: o TdiSendDatagram
15:
16: Environment:
17:
18: Kernel mode
19:
20: Revision History:
21:
22: --*/
23:
24: #include "st.h"
25:
26:
27: NTSTATUS
28: StTdiSend(
29: IN PIRP Irp
30: )
31:
32: /*++
33:
34: Routine Description:
35:
36: This routine performs the TdiSend request for the transport provider.
37:
38: Arguments:
39:
40: Irp - Pointer to the I/O Request Packet for this request.
41:
42: Return Value:
43:
44: NTSTATUS - status of operation.
45:
46: --*/
47:
48: {
49: KIRQL oldirql, cancelirql;
50: NTSTATUS status;
51: PTP_CONNECTION connection;
52: PMDL SendBuffer;
53: ULONG SendBufferLength;
54: PIO_STACK_LOCATION irpSp;
55: PTDI_REQUEST_KERNEL_SEND parameters;
56: PIRP TempIrp;
57:
58: //
59: // Determine which connection this send belongs on.
60: //
61:
62: irpSp = IoGetCurrentIrpStackLocation (Irp);
63: connection = irpSp->FileObject->FsContext;
64:
65: //
66: // Check that this is really a connection.
67: //
68:
69: if ((connection->Size != sizeof (TP_CONNECTION)) ||
70: (connection->Type != ST_CONNECTION_SIGNATURE)) {
71: return STATUS_INVALID_CONNECTION;
72: }
73:
74: //
75: // Now map the data in to SVA space.
76: //
77:
78: parameters = (PTDI_REQUEST_KERNEL_SEND)(&irpSp->Parameters);
79: SendBuffer = Irp->MdlAddress;
80: SendBufferLength = parameters->SendLength;
81:
82: //
83: // Interpret send options.
84: //
85:
86: //
87: // Now we have a reference on the connection object. Queue up this
88: // send to the connection object.
89: //
90:
91:
92: // This reference is removed by TdiDestroyRequest
93:
94: StReferenceConnection("TdiSend", connection);
95:
96: IRP_CONNECTION(irpSp) = connection;
97: IRP_REFCOUNT(irpSp) = 1;
98:
99: IoAcquireCancelSpinLock(&cancelirql);
100: ACQUIRE_SPIN_LOCK (&connection->SpinLock,&oldirql);
101:
102: if ((connection->Flags & CONNECTION_FLAGS_STOPPING) != 0) {
103: RELEASE_SPIN_LOCK (&connection->SpinLock,oldirql);
104: IoReleaseCancelSpinLock(cancelirql);
105: StCompleteSendIrp(
106: Irp,
107: connection->Status,
108: 0);
109: status = STATUS_PENDING;
110: } else {
111:
112: StReferenceConnection ("Verify Temp Use", connection);
113:
114: //
115: // Insert onto the send queue, and make the IRP
116: // cancellable.
117: //
118:
119: InsertTailList (&connection->SendQueue,&Irp->Tail.Overlay.ListEntry);
120:
121:
122: //
123: // If this IRP has been cancelled, then call the
124: // cancel routine.
125: //
126:
127: if (Irp->Cancel) {
128: RELEASE_SPIN_LOCK (&connection->SpinLock,oldirql);
129: Irp->CancelIrql = cancelirql;
130: StCancelSend((PDEVICE_OBJECT)(connection->Provider), Irp);
131: StDereferenceConnection ("IRP cancelled", connection); // release lookup hold.
132: return STATUS_PENDING;
133: }
134:
135: Irp->CancelRoutine = StCancelSend;
136:
137: //
138: // If this connection is waiting for an EOR to appear because a non-EOR
139: // send failed at some point in the past, fail this send. Clear the
140: // flag that causes this if this request has the EOR set.
141: //
142: // BUGBUG: Should the FailSend status be clearer here?
143: //
144:
145: if ((connection->Flags & CONNECTION_FLAGS_FAILING_TO_EOR) != 0) {
146:
147: RELEASE_SPIN_LOCK (&connection->SpinLock,oldirql);
148: IoReleaseCancelSpinLock(cancelirql);
149:
150: //
151: // BUGBUG: Should we save status from real failure?
152: //
153:
154: FailSend (connection, STATUS_LINK_FAILED, TRUE);
155:
156: if ( (parameters->SendFlags & TDI_SEND_PARTIAL) == 0) {
157: connection->Flags &= ~CONNECTION_FLAGS_FAILING_TO_EOR;
158: }
159:
160: StDereferenceConnection ("Failing to EOR", connection); // release lookup hold.
161: return STATUS_PENDING;
162: }
163:
164:
165: //
166: // If the send state is either IDLE or W_EOR, then we should
167: // begin packetizing this send. Otherwise, some other event
168: // will cause it to be packetized.
169: //
170:
171: //
172: // NOTE: If we call StartPacketizingConnection, we make
173: // sure that it is the last operation we do on this
174: // connection. This allows us to "hand off" the reference
175: // we have to that function, which converts it into
176: // a reference for being on the packetize queue.
177: //
178:
179: switch (connection->SendState) {
180:
181: case CONNECTION_SENDSTATE_IDLE:
182:
183: InitializeSend (connection); // sets state to PACKETIZE
184:
185: //
186: // If we can, packetize right now.
187: //
188:
189: if ((!(connection->Flags & CONNECTION_FLAGS_PACKETIZE)) &&
190: (!(connection->Flags & CONNECTION_FLAGS_STOPPING))) {
191:
192: connection->Flags |= CONNECTION_FLAGS_PACKETIZE;
193:
194: RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
195: IoReleaseCancelSpinLock(cancelirql);
196:
197: PacketizeSend (connection);
198:
199: } else {
200:
201: RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
202: IoReleaseCancelSpinLock(cancelirql);
203:
204: StDereferenceConnection ("Stopping or already packetizing", connection); // release lookup hold.
205:
206: }
207:
208: break;
209:
210: case CONNECTION_SENDSTATE_W_EOR:
211: connection->SendState = CONNECTION_SENDSTATE_PACKETIZE;
212:
213: //
214: // Adjust the send variables on the connection so that
215: // they correctly point to this new send. We can't call
216: // InitializeSend to do that, because we need to keep
217: // track of the other outstanding sends on this connection
218: // which have been sent but are a part of this message.
219: //
220:
221: TempIrp = CONTAINING_RECORD(
222: connection->SendQueue.Flink,
223: IRP,
224: Tail.Overlay.ListEntry);
225:
226: connection->sp.CurrentSendIrp = TempIrp;
227: connection->sp.CurrentSendMdl = TempIrp->MdlAddress;
228: connection->sp.SendByteOffset = 0;
229: connection->CurrentSendLength +=
230: IRP_SEND_LENGTH(IoGetCurrentIrpStackLocation(TempIrp));
231:
232: StartPacketizingConnection (connection, TRUE, oldirql, cancelirql);
233: break;
234:
235: default:
236:
237: //
238: // The connection is in another state (such as
239: // W_ACK or W_LINK), we just need to make sure
240: // to call InitializeSend if the new one is
241: // the first one on the list.
242: //
243:
244: //
245: // BUGBUG: Currently InitializeSend sets SendState,
246: // we should fix this.
247: //
248:
249: if (connection->SendQueue.Flink == &Irp->Tail.Overlay.ListEntry) {
250: ULONG SavedSendState;
251: SavedSendState = connection->SendState;
252: InitializeSend (connection);
253: connection->SendState = SavedSendState;
254: }
255: RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
256: IoReleaseCancelSpinLock(cancelirql);
257:
258: StDereferenceConnection("temp TdiSend", connection);
259:
260: }
261:
262: }
263:
264: status = STATUS_PENDING;
265:
266:
267: return status;
268: } /* TdiSend */
269:
270:
271: NTSTATUS
272: StTdiSendDatagram(
273: IN PIRP Irp
274: )
275:
276: /*++
277:
278: Routine Description:
279:
280: This routine performs the TdiSendDatagram request for the transport
281: provider.
282:
283: Arguments:
284:
285: Irp - Pointer to the I/O Request Packet for this request.
286:
287: Return Value:
288:
289: NTSTATUS - status of operation.
290:
291: --*/
292:
293: {
294: NTSTATUS status;
295: KIRQL oldirql;
296: PTP_REQUEST tpRequest;
297: PTP_ADDRESS_FILE addressFile;
298: PTP_ADDRESS address;
299: PMDL SendBuffer;
300: ULONG SendBufferLength;
301: PIO_STACK_LOCATION irpSp;
302: PTDI_REQUEST_KERNEL_SENDDG parameters;
303: LARGE_INTEGER timeout = {0,0};
304: UINT MaxUserData;
305:
306: irpSp = IoGetCurrentIrpStackLocation (Irp);
307: addressFile = irpSp->FileObject->FsContext;
308:
309: status = StVerifyAddressObject (addressFile);
310: if (!NT_SUCCESS (status)) {
311: return status;
312: }
313:
314: address = addressFile->Address;
315: parameters = (PTDI_REQUEST_KERNEL_SENDDG)(&irpSp->Parameters);
316: SendBuffer = Irp->MdlAddress;
317: SendBufferLength = parameters->SendLength;
318:
319: //
320: // Check that the length is short enough.
321: //
322:
323: MacReturnMaxDataSize(
324: &address->Provider->MacInfo,
325: NULL,
326: 0,
327: address->Provider->MaxSendPacketSize,
328: &MaxUserData);
329:
330: if (SendBufferLength >
331: (MaxUserData - sizeof(ST_HEADER))) {
332:
333: return STATUS_INVALID_PARAMETER;
334:
335: }
336:
337: //
338: // We need a request object to keep track of this TDI request.
339: // Attach this request to the address object.
340: //
341:
342: status = StCreateRequest (
343: Irp, // IRP for this request.
344: address, // context.
345: REQUEST_FLAGS_ADDRESS, // partial flags.
346: SendBuffer, // the data to be sent.
347: SendBufferLength, // length of the data.
348: timeout,
349: &tpRequest);
350:
351: if (!NT_SUCCESS (status)) {
352: StDereferenceAddress ("no send request", address);
353: return status; // if we couldn't queue the request.
354: }
355:
356: StReferenceAddress ("Send datagram", address);
357: tpRequest->Owner = AddressType;
358:
359: ACQUIRE_SPIN_LOCK (&address->SpinLock,&oldirql);
360:
361: if ((address->Flags & ADDRESS_FLAGS_STOPPING) != 0) {
362: RELEASE_SPIN_LOCK (&address->SpinLock,oldirql);
363: StCompleteRequest (tpRequest, STATUS_NETWORK_NAME_DELETED, 0);
364: return STATUS_PENDING;
365: } else {
366: InsertTailList (
367: &address->SendDatagramQueue,
368: &tpRequest->Linkage);
369: RELEASE_SPIN_LOCK (&address->SpinLock,oldirql);
370: }
371:
372: //
373: // The request is queued. Ship the next request at the head of the queue,
374: // provided the completion handler is not active. We serialize this so
375: // that only one MDL and ST datagram header needs to be statically
376: // allocated for reuse by all send datagram requests.
377: //
378:
379: (VOID)StSendDatagramsOnAddress (address);
380:
381: StDereferenceAddress("tmp send datagram", address);
382:
383: return STATUS_PENDING;
384:
385: } /* StTdiSendDatagram */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.