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.

614 lines
11 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. D:\nt\private\ntos\tdi\rawwan\core\send.c
  5. Abstract:
  6. Routines for sending data, including TDI entry points and
  7. NDIS completions.
  8. Revision History:
  9. Who When What
  10. -------- -------- ----------------------------------------------
  11. arvindm 05-16-97 Created
  12. Notes:
  13. --*/
  14. #include <precomp.h>
  15. #define _FILENUMBER 'DNES'
  16. #if STATS
  17. ULONG SendPktsOk = 0;
  18. ULONG SendBytesOk = 0;
  19. ULONG SendPktsFail = 0;
  20. ULONG SendBytesFail = 0;
  21. #endif // STATS
  22. RWAN_STATUS
  23. RWanInitSend(
  24. VOID
  25. )
  26. /*++
  27. Routine Description:
  28. Initialize our send side structures. All we need to do is to allocate
  29. an NDIS packet pool.
  30. Arguments:
  31. None
  32. Return Value:
  33. RWAN_STATUS_SUCCESS if we initialized successfully, RWAN_STATUS_RESOURCES
  34. if we couldn't allocate what we need.
  35. --*/
  36. {
  37. NDIS_STATUS Status;
  38. NdisAllocatePacketPoolEx(
  39. &Status,
  40. &RWanSendPacketPool,
  41. RWAN_INITIAL_SEND_PACKET_COUNT,
  42. RWAN_OVERFLOW_SEND_PACKET_COUNT,
  43. 0
  44. );
  45. return ((Status == NDIS_STATUS_SUCCESS)? RWAN_STATUS_SUCCESS: RWAN_STATUS_RESOURCES);
  46. }
  47. VOID
  48. RWanShutdownSend(
  49. VOID
  50. )
  51. /*++
  52. Routine Description:
  53. Free up our send resources.
  54. Arguments:
  55. None
  56. Return Value:
  57. None
  58. --*/
  59. {
  60. if (RWanSendPacketPool != NULL)
  61. {
  62. NdisFreePacketPool(RWanSendPacketPool);
  63. RWanSendPacketPool = NULL;
  64. }
  65. return;
  66. }
  67. TDI_STATUS
  68. RWanTdiSendData(
  69. IN PTDI_REQUEST pTdiRequest,
  70. IN USHORT SendFlags,
  71. IN UINT SendLength,
  72. IN PNDIS_BUFFER pSendBuffer
  73. )
  74. /*++
  75. Routine Description:
  76. This is the TDI Entry point for sending connection-oriented data.
  77. The Connection Object is identified by its context buried in the
  78. TDI Request.
  79. If all is well with the specified Connection, we prepend an NDIS
  80. packet to the buffer chain, and submit it to the miniport.
  81. Arguments:
  82. pTdiRequest - Pointer to the TDI Request containing the Send
  83. SendFlags - Options associated with this Send
  84. SendLength - Total data bytes in this Send
  85. pSendBuffer - Pointer to buffer chain
  86. Return Value:
  87. TDI_STATUS - this is TDI_PENDING if we successfully submitted
  88. a send request via NDIS, TDI_NO_RESOURCES if we failed to allocate
  89. resources for the send, TDI_INVALID_CONNECTION if the specified
  90. --*/
  91. {
  92. RWAN_CONN_ID ConnId;
  93. PRWAN_TDI_CONNECTION pConnObject;
  94. TDI_STATUS TdiStatus;
  95. PRWAN_NDIS_VC pVc;
  96. NDIS_HANDLE NdisVcHandle;
  97. PNDIS_PACKET pNdisPacket;
  98. PRWAN_SEND_REQUEST pSendReq;
  99. NDIS_STATUS NdisStatus;
  100. pNdisPacket = NULL;
  101. do
  102. {
  103. //
  104. // XXX: Should we check the length?
  105. //
  106. //
  107. // Discard zero-length sends.
  108. //
  109. if (SendLength == 0)
  110. {
  111. TdiStatus = TDI_SUCCESS;
  112. break;
  113. }
  114. //
  115. // Fail expedited data.
  116. // TBD - base this on the media-specific module.
  117. //
  118. if (SendFlags & TDI_SEND_EXPEDITED)
  119. {
  120. TdiStatus = STATUS_NOT_SUPPORTED; // No matching TDI status!
  121. break;
  122. }
  123. pNdisPacket = RWanAllocateSendPacket();
  124. if (pNdisPacket == NULL)
  125. {
  126. TdiStatus = TDI_NO_RESOURCES;
  127. break;
  128. }
  129. ConnId = (RWAN_CONN_ID) PtrToUlong(pTdiRequest->Handle.ConnectionContext);
  130. RWAN_ACQUIRE_CONN_TABLE_LOCK();
  131. pConnObject = RWanGetConnFromId(ConnId);
  132. RWAN_RELEASE_CONN_TABLE_LOCK();
  133. if (pConnObject == NULL_PRWAN_TDI_CONNECTION)
  134. {
  135. TdiStatus = TDI_INVALID_CONNECTION;
  136. break;
  137. }
  138. RWAN_ACQUIRE_CONN_LOCK(pConnObject);
  139. if ((pConnObject->State != RWANS_CO_CONNECTED) ||
  140. (RWAN_IS_BIT_SET(pConnObject->Flags, RWANF_CO_CLOSING)) ||
  141. (RWAN_IS_BIT_SET(pConnObject->Flags, RWANF_CO_CLOSE_SCHEDULED)))
  142. {
  143. //
  144. // Fix up the return status to get proper Winsock error
  145. // codes back to the app.
  146. //
  147. RWANDEBUGP(DL_INFO, DC_DATA_TX,
  148. ("Send: bad state %d, pConnObject %x\n", pConnObject->State, pConnObject));
  149. if ((pConnObject->State == RWANS_CO_DISCON_INDICATED) ||
  150. (pConnObject->State == RWANS_CO_ASSOCIATED) ||
  151. (pConnObject->State == RWANS_CO_DISCON_REQUESTED))
  152. {
  153. //
  154. // AFD would like to see us send an Abort at this time.
  155. //
  156. PDisconnectEvent pDisconInd;
  157. PVOID IndContext;
  158. PVOID ConnectionHandle;
  159. RWAN_ASSERT(pConnObject->pAddrObject != NULL);
  160. pDisconInd = pConnObject->pAddrObject->pDisconInd;
  161. IndContext = pConnObject->pAddrObject->DisconIndContext;
  162. ConnectionHandle = pConnObject->ConnectionHandle;
  163. RWAN_RELEASE_CONN_LOCK(pConnObject);
  164. (*pDisconInd)(
  165. IndContext,
  166. ConnectionHandle,
  167. 0, // Disconnect Data Length
  168. NULL, // Disconnect Data
  169. 0, // Disconnect Info Length
  170. NULL, // Disconnect Info
  171. TDI_DISCONNECT_ABORT
  172. );
  173. TdiStatus = TDI_CONNECTION_RESET;
  174. }
  175. else
  176. {
  177. RWAN_RELEASE_CONN_LOCK(pConnObject);
  178. TdiStatus = TDI_INVALID_STATE;
  179. }
  180. break;
  181. }
  182. if (RWAN_IS_BIT_SET(pConnObject->Flags, RWANF_CO_LEAF))
  183. {
  184. //
  185. // Allow sends only on the Root Connection object.
  186. //
  187. RWAN_RELEASE_CONN_LOCK(pConnObject);
  188. TdiStatus = TDI_INVALID_CONNECTION;
  189. break;
  190. }
  191. pVc = pConnObject->NdisConnection.pNdisVc;
  192. RWAN_ASSERT(pVc != NULL_PRWAN_NDIS_VC);
  193. RWAN_STRUCT_ASSERT(pVc, nvc);
  194. NdisVcHandle = pVc->NdisVcHandle;
  195. //
  196. // Save context about this send.
  197. //
  198. pSendReq = RWAN_SEND_REQUEST_FROM_PACKET(pNdisPacket);
  199. pSendReq->Request.pReqComplete = pTdiRequest->RequestNotifyObject;
  200. pSendReq->Request.ReqContext = pTdiRequest->RequestContext;
  201. //
  202. // XXX: we save the send flags also - may not be needed?
  203. //
  204. if ((pVc->MaxSendSize != 0) &&
  205. (SendLength > pVc->MaxSendSize))
  206. {
  207. RWANDEBUGP(DL_WARN, DC_DATA_TX,
  208. ("TdiSendData: Sending %d, which is more than %d\n",
  209. SendLength, pVc->MaxSendSize));
  210. #if HACK_SEND_SIZE
  211. pSendReq->SendLength = pVc->MaxSendSize;
  212. }
  213. else
  214. {
  215. pSendReq->SendLength = SendLength;
  216. #else
  217. RWAN_RELEASE_CONN_LOCK(pConnObject);
  218. TdiStatus = TDI_NO_RESOURCES;
  219. break;
  220. }
  221. pSendReq->SendLength = SendLength;
  222. #endif // HACK_SEND_SIZE
  223. pVc->PendingPacketCount++;
  224. RWAN_RELEASE_CONN_LOCK(pConnObject);
  225. pSendReq->SendFlags = SendFlags;
  226. RWANDEBUGP(DL_INFO, DC_DATA_TX,
  227. ("Send: VC %x [%d], %d bytes\n", pVc, pVc->MaxSendSize, SendLength));
  228. //
  229. // Attach the buffer chain to the Packet.
  230. //
  231. NdisChainBufferAtFront(pNdisPacket, pSendBuffer);
  232. #if HACK_SEND_SIZE
  233. if (pSendReq->SendLength != SendLength)
  234. {
  235. UINT TotalPacketLength;
  236. //
  237. // HACK: Recalculate total bytes and fix it.
  238. //
  239. NdisQueryPacket(
  240. pNdisPacket,
  241. NULL,
  242. NULL,
  243. NULL,
  244. &TotalPacketLength
  245. );
  246. pNdisPacket->Private.TotalLength = pSendReq->SendLength;
  247. DbgPrint("RWan: send: real length %d, sending length %d\n",
  248. TotalPacketLength, pSendReq->SendLength);
  249. }
  250. #endif // HACK_SEND_SIZE
  251. RWAND_LOG_PACKET(pVc, RWAND_DLOG_TX_START, pNdisPacket, pTdiRequest->RequestContext);
  252. //
  253. // And send it off.
  254. //
  255. NdisCoSendPackets(NdisVcHandle, &pNdisPacket, 1);
  256. //
  257. // Our CoSendComplete handler will be called to signify completion.
  258. // So we return PENDING now.
  259. //
  260. TdiStatus = TDI_PENDING;
  261. break;
  262. }
  263. while (FALSE);
  264. if (TdiStatus != TDI_PENDING)
  265. {
  266. #if STATS
  267. if (TdiStatus == TDI_SUCCESS)
  268. {
  269. INCR_STAT(&SendPktsOk);
  270. ADD_STAT(&SendBytesOk, SendLength);
  271. }
  272. else
  273. {
  274. INCR_STAT(&SendPktsFail);
  275. ADD_STAT(&SendBytesFail, SendLength);
  276. }
  277. #endif // STATS
  278. //
  279. // Clean up.
  280. //
  281. if (pNdisPacket != NULL)
  282. {
  283. RWanFreeSendPacket(pNdisPacket);
  284. }
  285. #if DBG
  286. if (TdiStatus != TDI_SUCCESS)
  287. {
  288. RWANDEBUGP(DL_INFO, DC_DATA_TX,
  289. ("Send: Length %x, failing with status %x\n", SendLength, TdiStatus));
  290. }
  291. #endif
  292. }
  293. return (TdiStatus);
  294. }
  295. VOID
  296. RWanNdisCoSendComplete(
  297. IN NDIS_STATUS NdisStatus,
  298. IN NDIS_HANDLE ProtocolVcContext,
  299. IN PNDIS_PACKET pNdisPacket
  300. )
  301. /*++
  302. Routine Description:
  303. This is the NDIS Entry point indicating completion of a
  304. packet send. We complete the TDI Send Request.
  305. Arguments:
  306. NdisStatus - Status of the NDIS Send.
  307. ProtocolVcContext - Actually a pointer to our NDIS VC structure
  308. pNdisPacket - Packet that has been sent.
  309. Return Value:
  310. None
  311. --*/
  312. {
  313. PRWAN_NDIS_VC pVc;
  314. PRWAN_SEND_REQUEST pSendReq;
  315. PRWAN_TDI_CONNECTION pConnObject;
  316. TDI_STATUS TdiStatus;
  317. pVc = (PRWAN_NDIS_VC)ProtocolVcContext;
  318. RWAN_STRUCT_ASSERT(pVc, nvc);
  319. #if STATS
  320. {
  321. PNDIS_BUFFER pNdisBuffer;
  322. PVOID FirstBufferVa;
  323. UINT FirstBufferLength;
  324. UINT TotalLength;
  325. NdisGetFirstBufferFromPacket(
  326. pNdisPacket,
  327. &pNdisBuffer,
  328. &FirstBufferVa,
  329. &FirstBufferLength,
  330. &TotalLength
  331. );
  332. if (NdisStatus == NDIS_STATUS_SUCCESS)
  333. {
  334. INCR_STAT(&SendPktsOk);
  335. ADD_STAT(&SendBytesOk, TotalLength);
  336. }
  337. else
  338. {
  339. INCR_STAT(&SendPktsFail);
  340. ADD_STAT(&SendBytesFail, TotalLength);
  341. }
  342. }
  343. #endif // STATS
  344. if (NdisStatus == NDIS_STATUS_SUCCESS)
  345. {
  346. TdiStatus = TDI_SUCCESS;
  347. }
  348. else
  349. {
  350. TdiStatus = RWanNdisToTdiStatus(NdisStatus);
  351. RWANDEBUGP(DL_INFO, DC_DATA_TX,
  352. ("CoSendComp: Failing Pkt %x, NDIS Status %x, TDI Status %x\n",
  353. pNdisPacket, NdisStatus, TdiStatus));
  354. }
  355. pSendReq = RWAN_SEND_REQUEST_FROM_PACKET(pNdisPacket);
  356. RWAND_LOG_PACKET(pVc, RWAND_DLOG_TX_END, pNdisPacket, pSendReq->Request.ReqContext);
  357. //
  358. // Complete the TDI Send.
  359. //
  360. (*pSendReq->Request.pReqComplete)(
  361. pSendReq->Request.ReqContext,
  362. TdiStatus,
  363. ((TdiStatus == TDI_SUCCESS) ? pSendReq->SendLength: 0)
  364. );
  365. //
  366. // Free the NDIS Packet structure.
  367. //
  368. RWanFreeSendPacket(pNdisPacket);
  369. //
  370. // Update the Connection object.
  371. //
  372. pConnObject = pVc->pConnObject;
  373. if (pConnObject != NULL)
  374. {
  375. RWAN_ASSERT(pConnObject->NdisConnection.pNdisVc == pVc);
  376. RWAN_ACQUIRE_CONN_LOCK(pConnObject);
  377. pVc->PendingPacketCount--; // Send complete
  378. if ((pVc->PendingPacketCount == 0) &&
  379. (RWAN_IS_BIT_SET(pVc->Flags, RWANF_VC_NEEDS_CLOSE)))
  380. {
  381. RWanStartCloseCall(pConnObject, pVc);
  382. }
  383. else
  384. {
  385. RWAN_RELEASE_CONN_LOCK(pConnObject);
  386. }
  387. }
  388. //
  389. // else we are aborting this connection.
  390. //
  391. #if DBG
  392. else
  393. {
  394. RWANDEBUGP(DL_WARN, DC_DATA_TX,
  395. ("SendComp: VC %x, ConnObj is NULL\n", pVc));
  396. }
  397. #endif // DBG
  398. return;
  399. }
  400. PNDIS_PACKET
  401. RWanAllocateSendPacket(
  402. VOID
  403. )
  404. /*++
  405. Routine Description:
  406. Allocate and return an NDIS packet to prepare a send.
  407. Arguments:
  408. None
  409. Return Value:
  410. Pointer to allocate packet if successful, else NULL.
  411. --*/
  412. {
  413. PNDIS_PACKET pSendPacket;
  414. NDIS_STATUS Status;
  415. NdisAllocatePacket(
  416. &Status,
  417. &pSendPacket,
  418. RWanSendPacketPool
  419. );
  420. if (Status != NDIS_STATUS_SUCCESS)
  421. {
  422. pSendPacket = NULL;
  423. }
  424. return (pSendPacket);
  425. }
  426. VOID
  427. RWanFreeSendPacket(
  428. IN PNDIS_PACKET pSendPacket
  429. )
  430. /*++
  431. Routine Description:
  432. Free an NDIS_PACKET used for a send.
  433. Arguments:
  434. pSendPacket - Points to packet to be freed.
  435. Return Value:
  436. None
  437. --*/
  438. {
  439. RWAN_ASSERT(pSendPacket != NULL);
  440. NdisFreePacket(pSendPacket);
  441. }
  442. VOID
  443. RWanNdisSendComplete(
  444. IN NDIS_HANDLE ProtocolBindingContext,
  445. IN PNDIS_PACKET pNdisPacket,
  446. IN NDIS_STATUS Status
  447. )
  448. /*++
  449. Routine Description:
  450. Dummy handler for connection-less send completes.
  451. Arguments:
  452. Return Value:
  453. None
  454. --*/
  455. {
  456. //
  457. // We don't do connection-less sends yet.
  458. //
  459. RWAN_ASSERT(FALSE);
  460. return;
  461. }