|
|
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.