Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

508 lines
15 KiB

  1. /*++
  2. Copyright (c) 1989, 1990, 1991 Microsoft Corporation
  3. Module Name:
  4. send.c
  5. Abstract:
  6. This module contains code which performs the following TDI services:
  7. o TdiSend
  8. o TdiSendDatagram
  9. Author:
  10. David Beaver (dbeaver) 1-July-1991
  11. Environment:
  12. Kernel mode
  13. Revision History:
  14. --*/
  15. #include "precomp.h"
  16. #pragma hdrstop
  17. NTSTATUS
  18. NbfTdiSend(
  19. IN PIRP Irp
  20. )
  21. /*++
  22. Routine Description:
  23. This routine performs the TdiSend request for the transport provider.
  24. NOTE: THIS FUNCTION MUST BE CALLED AT DPC LEVEL.
  25. Arguments:
  26. Irp - Pointer to the I/O Request Packet for this request.
  27. Return Value:
  28. NTSTATUS - status of operation.
  29. --*/
  30. {
  31. KIRQL oldirql, cancelIrql;
  32. PTP_CONNECTION connection;
  33. PIO_STACK_LOCATION irpSp;
  34. PTDI_REQUEST_KERNEL_SEND parameters;
  35. PIRP TempIrp;
  36. //
  37. // Determine which connection this send belongs on.
  38. //
  39. irpSp = IoGetCurrentIrpStackLocation (Irp);
  40. connection = irpSp->FileObject->FsContext;
  41. //
  42. // Check that this is really a connection.
  43. //
  44. if ((irpSp->FileObject->FsContext2 == UlongToPtr(NBF_FILE_TYPE_CONTROL)) ||
  45. (connection->Size != sizeof (TP_CONNECTION)) ||
  46. (connection->Type != NBF_CONNECTION_SIGNATURE)) {
  47. #if DBG
  48. NbfPrint2 ("TdiSend: Invalid Connection %lx Irp %lx\n", connection, Irp);
  49. #endif
  50. return STATUS_INVALID_CONNECTION;
  51. }
  52. #if DBG
  53. Irp->IoStatus.Information = 0; // initialize it.
  54. Irp->IoStatus.Status = 0x01010101; // initialize it.
  55. #endif
  56. //
  57. // Interpret send options.
  58. //
  59. #if DBG
  60. parameters = (PTDI_REQUEST_KERNEL_SEND)(&irpSp->Parameters);
  61. if ((parameters->SendFlags & TDI_SEND_PARTIAL) != 0) {
  62. IF_NBFDBG (NBF_DEBUG_SENDENG) {
  63. NbfPrint0 ("NbfTdiSend: TDI_END_OF_RECORD not found.\n");
  64. }
  65. }
  66. #endif
  67. //
  68. // Now we have a reference on the connection object. Queue up this
  69. // send to the connection object.
  70. //
  71. //
  72. // We would normally add a connection reference of type
  73. // CREF_SEND_IRP, however we delay doing this until we
  74. // know we are not going to call PacketizeSend with the
  75. // second parameter TRUE. If we do call that it assumes
  76. // we have not added the reference.
  77. //
  78. IRP_SEND_IRP(irpSp) = Irp;
  79. IRP_SEND_REFCOUNT(irpSp) = 1;
  80. KeRaiseIrql (DISPATCH_LEVEL, &oldirql);
  81. ACQUIRE_DPC_C_SPIN_LOCK (&connection->SpinLock);
  82. if ((connection->Flags & CONNECTION_FLAGS_READY) == 0) {
  83. RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
  84. Irp->IoStatus.Status = connection->Status;
  85. Irp->IoStatus.Information = 0;
  86. NbfDereferenceSendIrp ("Complete", irpSp, RREF_CREATION); // remove creation reference.
  87. } else {
  88. //
  89. // Once the reference is in, LinkSpinLock will stay valid.
  90. //
  91. NbfReferenceConnection ("Verify Temp Use", connection, CREF_BY_ID);
  92. RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
  93. IoAcquireCancelSpinLock(&cancelIrql);
  94. ACQUIRE_DPC_SPIN_LOCK (connection->LinkSpinLock);
  95. #if DBG
  96. NbfSends[NbfSendsNext].Irp = Irp;
  97. NbfSends[NbfSendsNext].Request = NULL;
  98. NbfSends[NbfSendsNext].Connection = (PVOID)connection;
  99. {
  100. ULONG i,j;
  101. PUCHAR va;
  102. PMDL mdl;
  103. mdl = Irp->MdlAddress;
  104. if (parameters->SendLength > TRACK_TDI_CAPTURE) {
  105. NbfSends[NbfSendsNext].Contents[0] = 0xFF;
  106. } else {
  107. NbfSends[NbfSendsNext].Contents[0] = (UCHAR)parameters->SendLength;
  108. }
  109. i = 1;
  110. while (i < TRACK_TDI_CAPTURE) {
  111. if (mdl == NULL) break;
  112. for ( va = MmGetSystemAddressForMdl (mdl),
  113. j = MmGetMdlByteCount (mdl);
  114. (i < TRACK_TDI_CAPTURE) && (j > 0);
  115. i++, j-- ) {
  116. NbfSends[NbfSendsNext].Contents[i] = *va++;
  117. }
  118. mdl = mdl->Next;
  119. }
  120. }
  121. NbfSendsNext++;
  122. if (NbfSendsNext >= TRACK_TDI_LIMIT) NbfSendsNext = 0;
  123. #endif
  124. //
  125. // If this IRP has been cancelled already, complete it now.
  126. //
  127. if (Irp->Cancel) {
  128. #if DBG
  129. NbfCompletedSends[NbfCompletedSendsNext].Irp = Irp;
  130. NbfCompletedSends[NbfCompletedSendsNext].Status = STATUS_CANCELLED;
  131. NbfCompletedSendsNext = (NbfCompletedSendsNext++) % TRACK_TDI_LIMIT;
  132. #endif
  133. NbfReferenceConnection("TdiSend cancelled", connection, CREF_SEND_IRP);
  134. RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
  135. IoReleaseCancelSpinLock(cancelIrql);
  136. NbfCompleteSendIrp (Irp, STATUS_CANCELLED, 0);
  137. KeLowerIrql (oldirql);
  138. NbfDereferenceConnection ("IRP cancelled", connection, CREF_BY_ID); // release lookup hold.
  139. return STATUS_PENDING;
  140. }
  141. //
  142. // Insert onto the send queue, and make the IRP
  143. // cancellable.
  144. //
  145. InsertTailList (&connection->SendQueue,&Irp->Tail.Overlay.ListEntry);
  146. IoSetCancelRoutine(Irp, NbfCancelSend);
  147. //
  148. // Release the cancel spinlock out of order. We were at DPC level
  149. // when we acquired both the cancel and link spinlocks, so the irqls
  150. // don't need to be swapped.
  151. //
  152. ASSERT(cancelIrql == DISPATCH_LEVEL);
  153. IoReleaseCancelSpinLock(cancelIrql);
  154. //
  155. // If this connection is waiting for an EOR to appear because a non-EOR
  156. // send failed at some point in the past, fail this send. Clear the
  157. // flag that causes this if this request has the EOR set.
  158. //
  159. // Should the FailSend status be clearer here?
  160. //
  161. if ((connection->Flags & CONNECTION_FLAGS_FAILING_TO_EOR) != 0) {
  162. NbfReferenceConnection("TdiSend failing to EOR", connection, CREF_SEND_IRP);
  163. RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
  164. //
  165. // Should we save status from real failure?
  166. //
  167. FailSend (connection, STATUS_LINK_FAILED, TRUE);
  168. parameters = (PTDI_REQUEST_KERNEL_SEND)(&irpSp->Parameters);
  169. if ( (parameters->SendFlags & TDI_SEND_PARTIAL) == 0) {
  170. connection->Flags &= ~CONNECTION_FLAGS_FAILING_TO_EOR;
  171. }
  172. KeLowerIrql (oldirql);
  173. NbfDereferenceConnection ("Failing to EOR", connection, CREF_BY_ID); // release lookup hold.
  174. return STATUS_PENDING;
  175. }
  176. //
  177. // If the send state is either IDLE or W_EOR, then we should
  178. // begin packetizing this send. Otherwise, some other event
  179. // will cause it to be packetized.
  180. //
  181. //
  182. // NOTE: If we call StartPacketizingConnection, we make
  183. // sure that it is the last operation we do on this
  184. // connection. This allows us to "hand off" the reference
  185. // we have to that function, which converts it into
  186. // a reference for being on the packetize queue.
  187. //
  188. // NbfPrint2 ("TdiSend: Sending, connection %lx send state %lx\n",
  189. // connection, connection->SendState);
  190. switch (connection->SendState) {
  191. case CONNECTION_SENDSTATE_IDLE:
  192. InitializeSend (connection); // sets state to PACKETIZE
  193. //
  194. // If we can, packetize right now.
  195. //
  196. if (!(connection->Flags & CONNECTION_FLAGS_PACKETIZE)) {
  197. ASSERT (!(connection->Flags2 & CONNECTION_FLAGS2_STOPPING));
  198. connection->Flags |= CONNECTION_FLAGS_PACKETIZE;
  199. #if DBG
  200. NbfReferenceConnection ("Packetize", connection, CREF_PACKETIZE_QUEUE);
  201. NbfDereferenceConnection("temp TdiSend", connection, CREF_BY_ID);
  202. #endif
  203. //
  204. // This releases the spinlock. Note that PacketizeSend
  205. // assumes that the current SendIrp has a reference
  206. // of type RREF_PACKET;
  207. //
  208. #if DBG
  209. NbfReferenceSendIrp ("Packetize", irpSp, RREF_PACKET);
  210. #else
  211. ++IRP_SEND_REFCOUNT(irpSp); // OK since it was just queued.
  212. #endif
  213. PacketizeSend (connection, TRUE);
  214. } else {
  215. #if DBG
  216. NbfReferenceConnection("TdiSend packetizing", connection, CREF_SEND_IRP);
  217. NbfDereferenceConnection ("Stopping or already packetizing", connection, CREF_BY_ID); // release lookup hold.
  218. #endif
  219. RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
  220. }
  221. break;
  222. case CONNECTION_SENDSTATE_W_EOR:
  223. connection->SendState = CONNECTION_SENDSTATE_PACKETIZE;
  224. //
  225. // Adjust the send variables on the connection so that
  226. // they correctly point to this new send. We can't call
  227. // InitializeSend to do that, because we need to keep
  228. // track of the other outstanding sends on this connection
  229. // which have been sent but are a part of this message.
  230. //
  231. TempIrp = CONTAINING_RECORD(
  232. connection->SendQueue.Flink,
  233. IRP,
  234. Tail.Overlay.ListEntry);
  235. connection->sp.CurrentSendIrp = TempIrp;
  236. connection->sp.CurrentSendMdl = TempIrp->MdlAddress;
  237. connection->sp.SendByteOffset = 0;
  238. connection->CurrentSendLength +=
  239. IRP_SEND_LENGTH(IoGetCurrentIrpStackLocation(TempIrp));
  240. //
  241. // StartPacketizingConnection removes the CREF_BY_ID
  242. // reference.
  243. //
  244. NbfReferenceConnection("TdiSend W_EOR", connection, CREF_SEND_IRP);
  245. StartPacketizingConnection (connection, TRUE);
  246. break;
  247. default:
  248. // NbfPrint2 ("TdiSend: Sending, unknown state! connection %lx send state %lx\n",
  249. // connection, connection->SendState);
  250. //
  251. // The connection is in another state (such as
  252. // W_ACK or W_LINK), we just need to make sure
  253. // to call InitializeSend if the new one is
  254. // the first one on the list.
  255. //
  256. //
  257. // Currently InitializeSend sets SendState, we should fix this.
  258. //
  259. if (connection->SendQueue.Flink == &Irp->Tail.Overlay.ListEntry) {
  260. ULONG SavedSendState;
  261. SavedSendState = connection->SendState;
  262. InitializeSend (connection);
  263. connection->SendState = SavedSendState;
  264. }
  265. #if DBG
  266. NbfReferenceConnection("TdiSend other", connection, CREF_SEND_IRP);
  267. NbfDereferenceConnection("temp TdiSend", connection, CREF_BY_ID);
  268. #endif
  269. RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
  270. }
  271. }
  272. KeLowerIrql (oldirql);
  273. return STATUS_PENDING;
  274. } /* TdiSend */
  275. NTSTATUS
  276. NbfTdiSendDatagram(
  277. IN PIRP Irp
  278. )
  279. /*++
  280. Routine Description:
  281. This routine performs the TdiSendDatagram request for the transport
  282. provider.
  283. Arguments:
  284. Irp - Pointer to the I/O Request Packet for this request.
  285. Return Value:
  286. NTSTATUS - status of operation.
  287. --*/
  288. {
  289. NTSTATUS status;
  290. KIRQL oldirql;
  291. PTP_ADDRESS_FILE addressFile;
  292. PTP_ADDRESS address;
  293. PIO_STACK_LOCATION irpSp;
  294. PTDI_REQUEST_KERNEL_SENDDG parameters;
  295. UINT MaxUserData;
  296. irpSp = IoGetCurrentIrpStackLocation (Irp);
  297. if (irpSp->FileObject->FsContext2 != (PVOID) TDI_TRANSPORT_ADDRESS_FILE) {
  298. return STATUS_INVALID_ADDRESS;
  299. }
  300. addressFile = irpSp->FileObject->FsContext;
  301. status = NbfVerifyAddressObject (addressFile);
  302. if (!NT_SUCCESS (status)) {
  303. IF_NBFDBG (NBF_DEBUG_SENDENG) {
  304. NbfPrint2 ("TdiSendDG: Invalid address %lx Irp %lx\n",
  305. addressFile, Irp);
  306. }
  307. return status;
  308. }
  309. address = addressFile->Address;
  310. parameters = (PTDI_REQUEST_KERNEL_SENDDG)(&irpSp->Parameters);
  311. //
  312. // Check that the length is short enough.
  313. //
  314. MacReturnMaxDataSize(
  315. &address->Provider->MacInfo,
  316. NULL,
  317. 0,
  318. address->Provider->MaxSendPacketSize,
  319. FALSE,
  320. &MaxUserData);
  321. if (parameters->SendLength >
  322. (MaxUserData - sizeof(DLC_FRAME) - sizeof(NBF_HDR_CONNECTIONLESS))) {
  323. NbfDereferenceAddress("tmp send datagram", address, AREF_VERIFY);
  324. return STATUS_INVALID_PARAMETER;
  325. }
  326. //
  327. // If we are on a disconnected RAS link, then fail the datagram
  328. // immediately.
  329. //
  330. if ((address->Provider->MacInfo.MediumAsync) &&
  331. (!address->Provider->MediumSpeedAccurate)) {
  332. NbfDereferenceAddress("tmp send datagram", address, AREF_VERIFY);
  333. return STATUS_DEVICE_NOT_READY;
  334. }
  335. //
  336. // Check that the target address includes a Netbios component.
  337. //
  338. if (!(NbfValidateTdiAddress(
  339. parameters->SendDatagramInformation->RemoteAddress,
  340. parameters->SendDatagramInformation->RemoteAddressLength)) ||
  341. (NbfParseTdiAddress(parameters->SendDatagramInformation->RemoteAddress, TRUE) == NULL)) {
  342. NbfDereferenceAddress("tmp send datagram", address, AREF_VERIFY);
  343. return STATUS_BAD_NETWORK_PATH;
  344. }
  345. ACQUIRE_SPIN_LOCK (&address->SpinLock,&oldirql);
  346. if ((address->Flags & (ADDRESS_FLAGS_STOPPING | ADDRESS_FLAGS_CONFLICT)) != 0) {
  347. RELEASE_SPIN_LOCK (&address->SpinLock,oldirql);
  348. Irp->IoStatus.Information = 0;
  349. Irp->IoStatus.Status = (address->Flags & ADDRESS_FLAGS_STOPPING) ?
  350. STATUS_NETWORK_NAME_DELETED : STATUS_DUPLICATE_NAME;
  351. IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
  352. } else {
  353. NbfReferenceAddress ("Send datagram", address, AREF_REQUEST);
  354. Irp->IoStatus.Information = parameters->SendLength;
  355. InsertTailList (
  356. &address->SendDatagramQueue,
  357. &Irp->Tail.Overlay.ListEntry);
  358. RELEASE_SPIN_LOCK (&address->SpinLock,oldirql);
  359. //
  360. // The request is queued. Ship the next request at the head of the queue,
  361. // provided the completion handler is not active. We serialize this so
  362. // that only one MDL and NBF datagram header needs to be statically
  363. // allocated for reuse by all send datagram requests.
  364. //
  365. (VOID)NbfSendDatagramsOnAddress (address);
  366. }
  367. NbfDereferenceAddress("tmp send datagram", address, AREF_VERIFY);
  368. return STATUS_PENDING;
  369. } /* NbfTdiSendDatagram */