Source code of Windows XP (NT5)
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.

1050 lines
28 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. cnpsend.c
  5. Abstract:
  6. Cluster Network Protocol send processing code.
  7. Author:
  8. Mike Massa (mikemas) January 24, 1997
  9. Revision History:
  10. Who When What
  11. -------- -------- ----------------------------------------------
  12. mikemas 01-24-97 created
  13. Notes:
  14. --*/
  15. #include "precomp.h"
  16. #pragma hdrstop
  17. #include "cnpsend.tmh"
  18. #ifdef ALLOC_PRAGMA
  19. #pragma alloc_text(PAGE, CnpCreateSendRequestPool)
  20. #endif // ALLOC_PRAGMA
  21. //
  22. // Private Utility Functions
  23. //
  24. PCN_RESOURCE
  25. CnpCreateSendRequest(
  26. IN PVOID Context
  27. )
  28. {
  29. PCNP_SEND_REQUEST_POOL_CONTEXT context = Context;
  30. PCNP_SEND_REQUEST request;
  31. PCNP_HEADER cnpHeader;
  32. ULONG cnpHeaderSize;
  33. //
  34. // The CNP header size includes signature data for version 2.
  35. //
  36. cnpHeaderSize = sizeof(CNP_HEADER);
  37. if (context->CnpVersionNumber == 2) {
  38. cnpHeaderSize += CNP_SIG_LENGTH(CX_SIGNATURE_LENGTH);
  39. }
  40. //
  41. // Allocate a new send request. Include space for the upper protocol
  42. // and CNP headers.
  43. //
  44. request = CnAllocatePool(
  45. sizeof(CNP_SEND_REQUEST) + cnpHeaderSize +
  46. ((ULONG) context->UpperProtocolHeaderLength) +
  47. context->UpperProtocolContextSize
  48. );
  49. if (request != NULL) {
  50. //
  51. // Allocate an MDL to describe the CNP and upper transport headers.
  52. //
  53. // On I64 Context has to be 64 bit aligned,
  54. // let's put it before CnpHeader
  55. if (context->UpperProtocolContextSize > 0) {
  56. request->UpperProtocolContext = request + 1;
  57. request->CnpHeader = ( ((PCHAR) request->UpperProtocolContext) +
  58. context->UpperProtocolContextSize );
  59. } else {
  60. request->UpperProtocolContext = NULL;
  61. request->CnpHeader = request + 1;
  62. }
  63. request->HeaderMdl = IoAllocateMdl(
  64. request->CnpHeader,
  65. (ULONG) (context->UpperProtocolHeaderLength +
  66. cnpHeaderSize),
  67. FALSE,
  68. FALSE,
  69. NULL
  70. );
  71. if (request->HeaderMdl != NULL) {
  72. MmBuildMdlForNonPagedPool(request->HeaderMdl);
  73. //
  74. // Finish initializing the request.
  75. //
  76. request->UpperProtocolHeader = ( ((PCHAR) request->CnpHeader) +
  77. cnpHeaderSize );
  78. request->UpperProtocolHeaderLength =
  79. context->UpperProtocolHeaderLength;
  80. RtlZeroMemory(
  81. &(request->TdiSendDatagramInfo),
  82. sizeof(request->TdiSendDatagramInfo)
  83. );
  84. request->McastGroup = NULL;
  85. //
  86. // Fill in the constant CNP header values.
  87. //
  88. cnpHeader = request->CnpHeader;
  89. cnpHeader->Version = context->CnpVersionNumber;
  90. cnpHeader->NextHeader = context->UpperProtocolNumber;
  91. return((PCN_RESOURCE) request);
  92. }
  93. CnFreePool(request);
  94. }
  95. return(NULL);
  96. } // CnpCreateSendRequest
  97. VOID
  98. CnpDeleteSendRequest(
  99. PCN_RESOURCE Resource
  100. )
  101. {
  102. PCNP_SEND_REQUEST request = (PCNP_SEND_REQUEST) Resource;
  103. IoFreeMdl(request->HeaderMdl);
  104. CnFreePool(request);
  105. return;
  106. } // CnpDeleteSendRequest
  107. //
  108. // Routines Exported within the Cluster Transport
  109. //
  110. PCN_RESOURCE_POOL
  111. CnpCreateSendRequestPool(
  112. IN UCHAR CnpVersionNumber,
  113. IN UCHAR UpperProtocolNumber,
  114. IN USHORT UpperProtocolHeaderSize,
  115. IN USHORT UpperProtocolContextSize,
  116. IN USHORT PoolDepth
  117. )
  118. {
  119. PCN_RESOURCE_POOL pool;
  120. PCNP_SEND_REQUEST_POOL_CONTEXT context;
  121. PAGED_CODE();
  122. CnAssert((0xFFFF - sizeof(CNP_HEADER)) >= UpperProtocolHeaderSize);
  123. pool = CnAllocatePool(
  124. sizeof(CN_RESOURCE_POOL) +
  125. sizeof(CNP_SEND_REQUEST_POOL_CONTEXT)
  126. );
  127. if (pool != NULL) {
  128. context = (PCNP_SEND_REQUEST_POOL_CONTEXT) (pool + 1);
  129. context->UpperProtocolNumber = UpperProtocolNumber;
  130. context->UpperProtocolHeaderLength = UpperProtocolHeaderSize;
  131. context->UpperProtocolContextSize = UpperProtocolContextSize;
  132. context->CnpVersionNumber = CnpVersionNumber;
  133. CnInitializeResourcePool(
  134. pool,
  135. PoolDepth,
  136. CnpCreateSendRequest,
  137. context,
  138. CnpDeleteSendRequest
  139. );
  140. }
  141. return(pool);
  142. } // CnpCreateSendRequestPool
  143. VOID
  144. CnpCompleteSendPacketCommon(
  145. IN PIRP Irp,
  146. IN PCNP_SEND_REQUEST Request,
  147. IN PMDL DataMdl
  148. )
  149. {
  150. PCNP_NETWORK network = Request->Network;
  151. ULONG bytesSent = (ULONG)Irp->IoStatus.Information;
  152. NTSTATUS status = Irp->IoStatus.Status;
  153. PCNP_HEADER cnpHeader = Request->CnpHeader;
  154. CnVerifyCpuLockMask(
  155. 0, // Required
  156. 0xFFFFFFFF, // Forbidden
  157. 0 // Maximum
  158. );
  159. if (NT_SUCCESS(status)) {
  160. //
  161. // Subtract the CNP header from the count of bytes sent.
  162. //
  163. if (bytesSent >= sizeof(CNP_HEADER)) {
  164. bytesSent -= sizeof(CNP_HEADER);
  165. }
  166. else {
  167. CnAssert(FALSE);
  168. bytesSent = 0;
  169. }
  170. //
  171. // If CNP signed the message, subtract the signature
  172. // data from the count of bytes sent.
  173. //
  174. if (cnpHeader->Version == CNP_VERSION_MULTICAST) {
  175. CNP_SIGNATURE UNALIGNED * cnpSig;
  176. cnpSig = (CNP_SIGNATURE UNALIGNED *)(cnpHeader + 1);
  177. if (bytesSent >= (ULONG)CNP_SIGHDR_LENGTH &&
  178. bytesSent >= cnpSig->PayloadOffset) {
  179. bytesSent -= cnpSig->PayloadOffset;
  180. } else {
  181. CnAssert(FALSE);
  182. bytesSent = 0;
  183. }
  184. }
  185. CnTrace(CNP_SEND_DETAIL, CnpTraceSendComplete,
  186. "[CNP] Send of packet to node %u on net %u complete, "
  187. "bytes sent %u.",
  188. cnpHeader->DestinationAddress, // LOGULONG
  189. network->Id, // LOGULONG
  190. bytesSent // LOGULONG
  191. );
  192. }
  193. else {
  194. //
  195. // It is possible to reach this path with
  196. // status = c0000240 (STATUS_REQUEST_ABORTED) and
  197. // bytesSent > 0.
  198. //
  199. bytesSent = 0;
  200. CnTrace(CNP_SEND_ERROR, CnpTraceSendFailedBelow,
  201. "[CNP] Tcpip failed to send packet to node %u on net %u, "
  202. "data len %u, status %!status!",
  203. cnpHeader->DestinationAddress, // LOGULONG
  204. network->Id, // LOGULONG
  205. cnpHeader->PayloadLength, // LOGUSHORT
  206. status // LOGSTATUS
  207. );
  208. }
  209. //
  210. // Remove the active reference we put on the network.
  211. //
  212. CnAcquireLock(&(network->Lock), &(network->Irql));
  213. CnpActiveDereferenceNetwork(network);
  214. //
  215. // Free the TDI address buffer
  216. //
  217. CnFreePool(Request->TdiSendDatagramInfo.RemoteAddress);
  218. //
  219. // Call the upper protocol's completion routine
  220. //
  221. if (Request->CompletionRoutine) {
  222. (*(Request->CompletionRoutine))(
  223. status,
  224. &bytesSent,
  225. Request,
  226. DataMdl
  227. );
  228. }
  229. //
  230. // Update the Information field of the completed IRP to
  231. // reflect the actual bytes sent (adjusted for the CNP
  232. // and upper protocol headers).
  233. //
  234. Irp->IoStatus.Information = bytesSent;
  235. CnVerifyCpuLockMask(
  236. 0, // Required
  237. 0xFFFFFFFF, // Forbidden
  238. 0 // Maximum
  239. );
  240. return;
  241. } // CnpCompleteSendPacketCommon
  242. NTSTATUS
  243. CnpCompleteSendPacketNewIrp(
  244. IN PDEVICE_OBJECT DeviceObject,
  245. IN PIRP Irp,
  246. IN PVOID Context
  247. )
  248. {
  249. PCNP_SEND_REQUEST request = Context;
  250. PIRP upperIrp = request->UpperProtocolIrp;
  251. PMDL dataMdl;
  252. CnVerifyCpuLockMask(
  253. 0, // Required
  254. 0xFFFFFFFF, // Forbidden
  255. 0 // Maximum
  256. );
  257. //
  258. // Unlink the data MDL chain from the header MDL.
  259. //
  260. CnAssert(Irp->MdlAddress == request->HeaderMdl);
  261. dataMdl = request->HeaderMdl->Next;
  262. request->HeaderMdl->Next = NULL;
  263. Irp->MdlAddress = NULL;
  264. CnpCompleteSendPacketCommon(Irp, request, dataMdl);
  265. //
  266. // Complete the upper-level IRP, if there is one
  267. //
  268. if (upperIrp != NULL) {
  269. IF_CNDBG( CN_DEBUG_CNPSEND )
  270. CNPRINT(("[CNP] CnpCompleteSendPacketNewIrp calling "
  271. "CnCompleteRequest for IRP %p with status "
  272. "%08x\n",
  273. upperIrp, Irp->IoStatus.Status));
  274. CnAcquireCancelSpinLock(&(upperIrp->CancelIrql));
  275. CnCompletePendingRequest(
  276. upperIrp,
  277. Irp->IoStatus.Status, // status
  278. (ULONG)Irp->IoStatus.Information // bytes returned
  279. );
  280. //
  281. // The IoCancelSpinLock was released by the completion routine.
  282. //
  283. }
  284. //
  285. // Free the new IRP
  286. //
  287. IoFreeIrp(Irp);
  288. CnVerifyCpuLockMask(
  289. 0, // Required
  290. 0xFFFFFFFF, // Forbidden
  291. 0 // Maximum
  292. );
  293. return(STATUS_MORE_PROCESSING_REQUIRED);
  294. } // CnpCompleteSendPacketNewIrp
  295. NTSTATUS
  296. CnpCompleteSendPacketReuseIrp(
  297. IN PDEVICE_OBJECT DeviceObject,
  298. IN PIRP Irp,
  299. IN PVOID Context
  300. )
  301. {
  302. PCNP_SEND_REQUEST request = Context;
  303. PMDL dataMdl;
  304. CnVerifyCpuLockMask(
  305. 0, // Required
  306. 0xFFFFFFFF, // Forbidden
  307. 0 // Maximum
  308. );
  309. //
  310. // Unlink the data MDL chain from the header MDL.
  311. //
  312. CnAssert(Irp->MdlAddress == request->HeaderMdl);
  313. dataMdl = request->HeaderMdl->Next;
  314. request->HeaderMdl->Next = NULL;
  315. //
  316. // Restore the requestor mode of the upper protocol IRP.
  317. //
  318. Irp->RequestorMode = request->UpperProtocolIrpMode;
  319. //
  320. // Restore the MDL of the upper protocol IRP.
  321. //
  322. Irp->MdlAddress = request->UpperProtocolMdl;
  323. CnpCompleteSendPacketCommon(Irp, request, dataMdl);
  324. if (Irp->PendingReturned) {
  325. IoMarkIrpPending(Irp);
  326. }
  327. IF_CNDBG( CN_DEBUG_CNPSEND )
  328. CNPRINT(("[CNP] CnpCompleteSendPacketReuseIrp returning "
  329. "IRP %p to I/O Manager\n",
  330. Irp));
  331. CnVerifyCpuLockMask(
  332. 0, // Required
  333. 0xFFFFFFFF, // Forbidden
  334. 0 // Maximum
  335. );
  336. return(STATUS_SUCCESS);
  337. } // CnpCompleteSendPacketReuseIrp
  338. NTSTATUS
  339. CnpSendPacket(
  340. IN PCNP_SEND_REQUEST SendRequest,
  341. IN CL_NODE_ID DestNodeId,
  342. IN PMDL DataMdl,
  343. IN USHORT DataLength,
  344. IN BOOLEAN CheckDestState,
  345. IN CL_NETWORK_ID NetworkId OPTIONAL
  346. )
  347. /*++
  348. Routine Description:
  349. Main send routine for CNP. Handles unicast and multicast
  350. sends.
  351. --*/
  352. {
  353. NTSTATUS status = STATUS_SUCCESS;
  354. PCNP_HEADER cnpHeader = SendRequest->CnpHeader;
  355. PIRP upperIrp = SendRequest->UpperProtocolIrp;
  356. CN_IRQL tableIrql;
  357. BOOLEAN multicast = FALSE;
  358. CL_NETWORK_ID networkId = NetworkId;
  359. CN_IRQL cancelIrql;
  360. BOOLEAN cnComplete = FALSE;
  361. BOOLEAN destNodeLocked = FALSE;
  362. PCNP_NODE destNode;
  363. ULONG sigDataLen;
  364. PCNP_INTERFACE interface;
  365. PCNP_NETWORK network;
  366. BOOLEAN networkReferenced = FALSE;
  367. PIRP irp;
  368. PVOID addressBuffer = NULL;
  369. PIO_COMPLETION_ROUTINE compRoutine;
  370. PDEVICE_OBJECT targetDeviceObject;
  371. PFILE_OBJECT targetFileObject;
  372. BOOLEAN mcastGroupReferenced = FALSE;
  373. CnVerifyCpuLockMask(
  374. 0, // Required
  375. CNP_LOCK_RANGE, // Forbidden
  376. CNP_PRECEEDING_LOCK_RANGE // Maximum
  377. );
  378. IF_CNDBG( CN_DEBUG_CNPSEND )
  379. CNPRINT(("[CNP] CnpSendPacket called with upper IRP %p\n",
  380. upperIrp));
  381. //
  382. // Make all the tests to see if we can send the packet.
  383. //
  384. //
  385. // Acquire the node table lock to match the destination node id
  386. // to a node object.
  387. //
  388. CnAcquireLock(&CnpNodeTableLock, &tableIrql);
  389. if (CnpNodeTable == NULL) {
  390. CnReleaseLock(&CnpNodeTableLock, tableIrql);
  391. status = STATUS_NETWORK_UNREACHABLE;
  392. goto error_exit;
  393. }
  394. //
  395. // Fill in the local node ID while we still hold the node table lock.
  396. //
  397. CnAssert(CnLocalNodeId != ClusterInvalidNodeId);
  398. cnpHeader->SourceAddress = CnLocalNodeId;
  399. //
  400. // Check first if the destination node id indicates that this is
  401. // a multicast.
  402. //
  403. if (DestNodeId == ClusterAnyNodeId) {
  404. //
  405. // This is a multicast. For multicasts, we use the local
  406. // node in place of the dest node to validate the network
  407. // and interface.
  408. //
  409. multicast = TRUE;
  410. destNode = CnpLockedFindNode(CnLocalNodeId, tableIrql);
  411. }
  412. //
  413. // Not a multicast. The destination node id must be valid.
  414. //
  415. else if (!CnIsValidNodeId(DestNodeId)) {
  416. CnReleaseLock(&CnpNodeTableLock, tableIrql);
  417. status = STATUS_INVALID_ADDRESS_COMPONENT;
  418. goto error_exit;
  419. }
  420. //
  421. // Find the destination node object in the node table.
  422. //
  423. else {
  424. destNode = CnpLockedFindNode(DestNodeId, tableIrql);
  425. }
  426. //
  427. // The NodeTableLock was released. Verify that we know about
  428. // the destination node.
  429. //
  430. if (destNode == NULL) {
  431. status = STATUS_HOST_UNREACHABLE;
  432. goto error_exit;
  433. }
  434. destNodeLocked = TRUE;
  435. //
  436. // CNP multicast messages must be signed.
  437. //
  438. if (multicast) {
  439. CnAssert(((CNP_HEADER UNALIGNED *)(SendRequest->CnpHeader))
  440. ->Version = CNP_VERSION_MULTICAST);
  441. //
  442. // Sign the data, starting with the upper protocol header
  443. // and finishing with the data payload.
  444. //
  445. // If we are requesting the current best multicast network,
  446. // we need to make sure that the mcast group data structure
  447. // is dereferenced.
  448. //
  449. mcastGroupReferenced = (BOOLEAN)(networkId == ClusterAnyNetworkId);
  450. status = CnpSignMulticastMessage(
  451. SendRequest,
  452. DataMdl,
  453. &networkId,
  454. &sigDataLen
  455. );
  456. if (status != STATUS_SUCCESS) {
  457. mcastGroupReferenced = FALSE;
  458. goto error_exit;
  459. }
  460. } else {
  461. sigDataLen = 0;
  462. }
  463. //
  464. // Choose the destination interface.
  465. //
  466. if (networkId != ClusterAnyNetworkId) {
  467. //
  468. // we really want to send this packet over the indicated
  469. // network. walk the node's interface list matching the
  470. // supplied network id to the interface's network ID and
  471. // send the packet on that interface
  472. //
  473. PLIST_ENTRY entry;
  474. for (entry = destNode->InterfaceList.Flink;
  475. entry != &(destNode->InterfaceList);
  476. entry = entry->Flink
  477. )
  478. {
  479. interface = CONTAINING_RECORD(
  480. entry,
  481. CNP_INTERFACE,
  482. NodeLinkage
  483. );
  484. if ( interface->Network->Id == networkId ) {
  485. break;
  486. }
  487. }
  488. if ( entry == &destNode->InterfaceList ) {
  489. //
  490. // no network object with the specified ID. if
  491. // this is the network the sender designated,
  492. // fail the send.
  493. //
  494. status = STATUS_NETWORK_UNREACHABLE;
  495. goto error_exit;
  496. }
  497. } else {
  498. interface = destNode->CurrentInterface;
  499. }
  500. //
  501. // Verify that we know about the destination interface.
  502. //
  503. if (interface == NULL) {
  504. // No interface for node. Must be down. Note that the
  505. // HOST_DOWN error code should cause the caller to give
  506. // up immediately.
  507. status = STATUS_HOST_DOWN;
  508. // status = STATUS_HOST_UNREACHABLE;
  509. goto error_exit;
  510. }
  511. //
  512. // Verify that everything is online. If all looks okay,
  513. // take an active reference on the network.
  514. //
  515. // For unicasts, verify the state of destination interface,
  516. // node, and intervening network.
  517. //
  518. // For multicasts, verify the state of the network and
  519. // its multicast capability.
  520. //
  521. network = interface->Network;
  522. if ( (!multicast)
  523. &&
  524. ( (interface->State > ClusnetInterfaceStateOfflinePending)
  525. &&
  526. (destNode->CommState == ClusnetNodeCommStateOnline)
  527. )
  528. )
  529. {
  530. //
  531. // Everything checks out. Reference the network so
  532. // it can't go offline while we are using it.
  533. //
  534. CnAcquireLockAtDpc(&(network->Lock));
  535. CnAssert(network->State >= ClusnetNetworkStateOfflinePending);
  536. CnpActiveReferenceNetwork(network);
  537. CnReleaseLockFromDpc(&(network->Lock));
  538. networkReferenced = TRUE;
  539. } else {
  540. //
  541. // Either the node is not online or this is a
  542. // multicast (in which case we don't bother checking
  543. // the status of all the nodes). Figure out what to do.
  544. //
  545. if (!multicast && CheckDestState) {
  546. //
  547. // Caller doesn't want to send to a down node.
  548. // Bail out. Note that the HOST_DOWN error code
  549. // should cause the caller to give up immediately.
  550. //
  551. status = STATUS_HOST_DOWN;
  552. // status = STATUS_HOST_UNREACHABLE;
  553. goto error_exit;
  554. }
  555. CnAcquireLockAtDpc(&(network->Lock));
  556. if (network->State <= ClusnetNetworkStateOfflinePending) {
  557. //
  558. // The chosen network is not online.
  559. // Bail out.
  560. //
  561. CnReleaseLockFromDpc(&(network->Lock));
  562. status = STATUS_HOST_UNREACHABLE;
  563. goto error_exit;
  564. }
  565. //
  566. // Multicast checks.
  567. //
  568. if (multicast) {
  569. //
  570. // Verify that the chosen network has been
  571. // enabled for multicast.
  572. //
  573. if (!CnpIsNetworkMulticastCapable(network)) {
  574. CnReleaseLockFromDpc(&(network->Lock));
  575. status = STATUS_HOST_UNREACHABLE;
  576. goto error_exit;
  577. }
  578. }
  579. //
  580. // The network is online, even if the host isn't.
  581. // The caller doesn't care. Go for it.
  582. //
  583. CnpActiveReferenceNetwork(network);
  584. CnReleaseLockFromDpc(&(network->Lock));
  585. networkReferenced = TRUE;
  586. }
  587. //
  588. // Allocate a buffer for the destination address.
  589. //
  590. addressBuffer = CnAllocatePool(interface->TdiAddressLength);
  591. if (addressBuffer == NULL) {
  592. status = STATUS_INSUFFICIENT_RESOURCES;
  593. goto error_exit;
  594. }
  595. //
  596. // Fill in the address buffer, and save it in the send
  597. // request data structure.
  598. //
  599. if (multicast) {
  600. PCNP_MULTICAST_GROUP mcastGroup = SendRequest->McastGroup;
  601. CnAssert(mcastGroup != NULL);
  602. CnAssert(
  603. CnpIsIPv4McastTransportAddress(mcastGroup->McastTdiAddress)
  604. );
  605. CnAssert(
  606. mcastGroup->McastTdiAddressLength == interface->TdiAddressLength
  607. );
  608. RtlMoveMemory(
  609. addressBuffer,
  610. mcastGroup->McastTdiAddress,
  611. mcastGroup->McastTdiAddressLength
  612. );
  613. SendRequest->TdiSendDatagramInfo.RemoteAddressLength =
  614. mcastGroup->McastTdiAddressLength;
  615. if (mcastGroupReferenced) {
  616. CnpDereferenceMulticastGroup(mcastGroup);
  617. mcastGroupReferenced = FALSE;
  618. SendRequest->McastGroup = NULL;
  619. }
  620. targetFileObject = network->DatagramFileObject;
  621. targetDeviceObject = network->DatagramDeviceObject;
  622. } else {
  623. CnAssert(mcastGroupReferenced == FALSE);
  624. RtlMoveMemory(
  625. addressBuffer,
  626. &(interface->TdiAddress),
  627. interface->TdiAddressLength
  628. );
  629. SendRequest->TdiSendDatagramInfo.RemoteAddressLength =
  630. interface->TdiAddressLength;
  631. targetFileObject = network->DatagramFileObject;
  632. targetDeviceObject = network->DatagramDeviceObject;
  633. }
  634. SendRequest->TdiSendDatagramInfo.RemoteAddress =
  635. addressBuffer;
  636. //
  637. // Release the node lock.
  638. //
  639. CnReleaseLock(&(destNode->Lock), destNode->Irql);
  640. destNodeLocked = FALSE;
  641. //
  642. // If there is an upper protocol IRP, see
  643. // if it has enough stack locations.
  644. //
  645. if ( (upperIrp != NULL)
  646. &&
  647. (CnpIsIrpStackSufficient(upperIrp, targetDeviceObject))
  648. ) {
  649. //
  650. // We can use the upper protocol IRP.
  651. //
  652. irp = upperIrp;
  653. compRoutine = CnpCompleteSendPacketReuseIrp;
  654. //
  655. // Ensure that IRP is marked as a kernel request,
  656. // but first save the current requestor mode so
  657. // that it can be restored later.
  658. //
  659. SendRequest->UpperProtocolIrpMode = irp->RequestorMode;
  660. irp->RequestorMode = KernelMode;
  661. //
  662. // Save the upper protocol IRP MDL to restore
  663. // later. This is probably the same as DataMdl,
  664. // but we don't want to make any assumptions.
  665. //
  666. SendRequest->UpperProtocolMdl = irp->MdlAddress;
  667. } else {
  668. //
  669. // We cannot use the upper protocol IRP.
  670. //
  671. // If there is an upper protocol IRP, it needs
  672. // to be marked pending.
  673. //
  674. if (upperIrp != NULL) {
  675. CnAcquireCancelSpinLock(&cancelIrql);
  676. status = CnMarkRequestPending(
  677. upperIrp,
  678. IoGetCurrentIrpStackLocation(upperIrp),
  679. NULL
  680. );
  681. CnReleaseCancelSpinLock(cancelIrql);
  682. if (status == STATUS_CANCELLED) {
  683. //
  684. // Bail out
  685. //
  686. status = STATUS_INSUFFICIENT_RESOURCES;
  687. goto error_exit;
  688. } else {
  689. //
  690. // If IoAllocateIrp fails, we need
  691. // to call CnCompletePendingRequest
  692. // now that we've called
  693. // CnMarkRequestPending.
  694. //
  695. cnComplete = TRUE;
  696. }
  697. }
  698. //
  699. // Allocate a new IRP
  700. //
  701. irp = IoAllocateIrp(
  702. targetDeviceObject->StackSize,
  703. FALSE
  704. );
  705. if (irp == NULL) {
  706. status = STATUS_INSUFFICIENT_RESOURCES;
  707. goto error_exit;
  708. }
  709. //
  710. // Use the completion routine for having
  711. // allocated a new IRP
  712. //
  713. compRoutine = CnpCompleteSendPacketNewIrp;
  714. //
  715. // Fill in IRP fields that are not specific
  716. // to any one stack location.
  717. //
  718. irp->Flags = 0;
  719. irp->RequestorMode = KernelMode;
  720. irp->PendingReturned = FALSE;
  721. irp->UserIosb = NULL;
  722. irp->UserEvent = NULL;
  723. irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
  724. irp->AssociatedIrp.SystemBuffer = NULL;
  725. irp->UserBuffer = NULL;
  726. irp->Tail.Overlay.Thread = PsGetCurrentThread();
  727. irp->Tail.Overlay.AuxiliaryBuffer = NULL;
  728. }
  729. //
  730. // Ok, we can finally send the packet.
  731. //
  732. SendRequest->Network = network;
  733. //
  734. // Link the data MDL chain after the header MDL.
  735. //
  736. SendRequest->HeaderMdl->Next = DataMdl;
  737. //
  738. // Finish building the CNP header.
  739. //
  740. cnpHeader->DestinationAddress = DestNodeId;
  741. cnpHeader->PayloadLength =
  742. SendRequest->UpperProtocolHeaderLength + DataLength;
  743. //
  744. // Build the next irp stack location.
  745. //
  746. TdiBuildSendDatagram(
  747. irp,
  748. targetDeviceObject,
  749. targetFileObject,
  750. compRoutine,
  751. SendRequest,
  752. SendRequest->HeaderMdl,
  753. cnpHeader->PayloadLength + sizeof(CNP_HEADER) + sigDataLen,
  754. &(SendRequest->TdiSendDatagramInfo)
  755. );
  756. CnTrace(CNP_SEND_DETAIL, CnpTraceSend,
  757. "[CNP] Sending packet to node %u on net %u, "
  758. "data len %u",
  759. cnpHeader->DestinationAddress, // LOGULONG
  760. network->Id, // LOGULONG
  761. cnpHeader->PayloadLength // LOGUSHORT
  762. );
  763. //
  764. // Now send the packet.
  765. //
  766. status = IoCallDriver(
  767. targetDeviceObject,
  768. irp
  769. );
  770. CnVerifyCpuLockMask(
  771. 0, // Required
  772. CNP_LOCK_RANGE, // Forbidden
  773. CNP_PRECEEDING_LOCK_RANGE // Maximum
  774. );
  775. return(status);
  776. //
  777. // The following code is only executed in an error condition,
  778. // No send IRP has been submitted to a lower-level driver.
  779. //
  780. error_exit:
  781. CnTrace(CNP_SEND_ERROR, CnpTraceSendFailedInternal,
  782. "[CNP] Failed to send packet to node %u on net %u, "
  783. "data len %u, status %!status!",
  784. cnpHeader->DestinationAddress, // LOGULONG
  785. NetworkId, // LOGULONG
  786. cnpHeader->PayloadLength, // LOGUSHORT
  787. status // LOGSTATUS
  788. );
  789. if (destNodeLocked) {
  790. CnReleaseLock(&(destNode->Lock), destNode->Irql);
  791. destNodeLocked = FALSE;
  792. }
  793. if (networkReferenced) {
  794. //
  795. // Remove the active reference we put on the network.
  796. //
  797. CnAcquireLock(&(network->Lock), &(network->Irql));
  798. CnpActiveDereferenceNetwork(network);
  799. networkReferenced = FALSE;
  800. }
  801. if (mcastGroupReferenced) {
  802. CnAssert(SendRequest->McastGroup != NULL);
  803. CnpDereferenceMulticastGroup(SendRequest->McastGroup);
  804. SendRequest->McastGroup = NULL;
  805. mcastGroupReferenced = FALSE;
  806. }
  807. if (addressBuffer != NULL) {
  808. CnFreePool(addressBuffer);
  809. }
  810. //
  811. // Call the upper protocol completion routine
  812. //
  813. if (SendRequest->CompletionRoutine) {
  814. ULONG bytesSent = 0;
  815. (*SendRequest->CompletionRoutine)(
  816. status,
  817. &bytesSent,
  818. SendRequest,
  819. DataMdl
  820. );
  821. }
  822. //
  823. // Complete the upper protocol IRP, if there is one
  824. //
  825. if (upperIrp) {
  826. if (cnComplete) {
  827. //
  828. // CnMarkRequestPending was called for upperIrp.
  829. //
  830. IF_CNDBG( CN_DEBUG_CNPSEND )
  831. CNPRINT(("[CNP] Calling CnCompletePendingRequest "
  832. "for IRP %p with status %08x\n",
  833. upperIrp, status));
  834. CnCompletePendingRequest(upperIrp, status, 0);
  835. } else {
  836. IF_CNDBG( CN_DEBUG_CNPSEND )
  837. CNPRINT(("[CNP] Completing IRP %p with status %08x\n",
  838. upperIrp, status));
  839. upperIrp->IoStatus.Status = status;
  840. upperIrp->IoStatus.Information = 0;
  841. IoCompleteRequest(upperIrp, IO_NO_INCREMENT);
  842. }
  843. }
  844. CnVerifyCpuLockMask(
  845. 0, // Required
  846. CNP_LOCK_RANGE, // Forbidden
  847. CNP_PRECEEDING_LOCK_RANGE // Maximum
  848. );
  849. return(status);
  850. } // CnpSendPacket