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.

2839 lines
128 KiB

  1. /*++
  2. Copyright (c) 1989-1993 Microsoft Corporation
  3. Module Name:
  4. spxrecv.c
  5. Abstract:
  6. Author:
  7. Nikhil Kamkolkar (nikhilk) 11-November-1993
  8. Environment:
  9. Kernel mode
  10. Revision History:
  11. Sanjay Anand (SanjayAn) 5-July-1995
  12. Bug fixes - tagged [SA]
  13. --*/
  14. #include "precomp.h"
  15. #pragma hdrstop
  16. // Define module number for event logging entries
  17. #define FILENUM SPXRECV
  18. BOOLEAN
  19. SpxReceive(
  20. IN NDIS_HANDLE MacBindingHandle,
  21. IN NDIS_HANDLE MacReceiveContext,
  22. IN ULONG_PTR FwdAdapterCtx,
  23. IN PIPX_LOCAL_TARGET RemoteAddress,
  24. IN ULONG MacOptions,
  25. IN PUCHAR LookaheadBuffer,
  26. IN UINT LookaheadBufferSize,
  27. IN UINT LookaheadBufferOffset,
  28. IN UINT PacketSize,
  29. IN PMDL pMdl
  30. )
  31. {
  32. PIPXSPX_HDR pHdr;
  33. // We have a separate routine to process SYS packets. DATA packets are
  34. // processed within this routine.
  35. if (LookaheadBufferSize < MIN_IPXSPX_HDRSIZE)
  36. {
  37. DBGPRINT(RECEIVE, ERR,
  38. ("SpxReceive: Invalid length %lx\n", LookaheadBufferSize));
  39. return FALSE;
  40. }
  41. ++SpxDevice->dev_Stat.PacketsReceived;
  42. pHdr = (PIPXSPX_HDR)LookaheadBuffer;
  43. if ((pHdr->hdr_ConnCtrl & SPX_CC_SYS) == 0)
  44. {
  45. // Check for data packets
  46. if ((pHdr->hdr_DataType != SPX2_DT_ORDREL) &&
  47. (pHdr->hdr_DataType != SPX2_DT_IDISC) &&
  48. (pHdr->hdr_DataType != SPX2_DT_IDISC_ACK))
  49. {
  50. // HANDLE DATA PACKET
  51. SpxRecvDataPacket(
  52. MacBindingHandle,
  53. MacReceiveContext,
  54. RemoteAddress,
  55. MacOptions,
  56. LookaheadBuffer,
  57. LookaheadBufferSize,
  58. LookaheadBufferOffset,
  59. PacketSize);
  60. }
  61. else
  62. {
  63. // The whole packet better be in the lookahead, else we ignore.
  64. if (LookaheadBufferSize == PacketSize)
  65. {
  66. SpxRecvDiscPacket(
  67. LookaheadBuffer,
  68. RemoteAddress,
  69. LookaheadBufferSize);
  70. }
  71. }
  72. }
  73. else
  74. {
  75. SpxRecvSysPacket(
  76. MacBindingHandle,
  77. MacReceiveContext,
  78. RemoteAddress,
  79. MacOptions,
  80. LookaheadBuffer,
  81. LookaheadBufferSize,
  82. LookaheadBufferOffset,
  83. PacketSize);
  84. }
  85. return FALSE;
  86. }
  87. VOID
  88. SpxTransferDataComplete(
  89. IN PNDIS_PACKET pNdisPkt,
  90. IN NDIS_STATUS NdisStatus,
  91. IN UINT BytesTransferred
  92. )
  93. /*++
  94. Routine Description:
  95. Arguments:
  96. Return Value:
  97. --*/
  98. {
  99. PSPX_CONN_FILE pSpxConnFile;
  100. PREQUEST pRequest;
  101. PSPX_RECV_RESD pRecvResd;
  102. CTELockHandle lockHandle;
  103. NTSTATUS status;
  104. BOOLEAN fAck, fEom, fBuffered, fImmedAck, fLockHeld;
  105. PNDIS_BUFFER pNdisBuffer;
  106. DBGPRINT(RECEIVE, DBG,
  107. ("SpxTransferData: For %lx with status %lx\n", pNdisPkt, NdisStatus));
  108. pRecvResd = RECV_RESD(pNdisPkt);
  109. pSpxConnFile = pRecvResd->rr_ConnFile;
  110. CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
  111. fLockHeld = TRUE;
  112. fEom = ((pRecvResd->rr_State & SPX_RECVPKT_EOM) != 0);
  113. fImmedAck = ((pRecvResd->rr_State & SPX_RECVPKT_IMMEDACK) != 0);
  114. fBuffered = ((pRecvResd->rr_State & SPX_RECVPKT_BUFFERING) != 0);
  115. fAck = ((pRecvResd->rr_State & SPX_RECVPKT_SENDACK) != 0);
  116. // Check if receive is done. If we remove the reference for this
  117. // packet and it goes to zero, that means the receive was aborted.
  118. // Move to the completion queue.
  119. // If receive is filled up, then remove the creation reference
  120. // i.e. just complete the receive at this point.
  121. // There can be only one packet per receive, we dont support
  122. // out of order reception.
  123. if (!fBuffered)
  124. {
  125. // Get pointer to the buffer descriptor and its memory.
  126. NdisUnchainBufferAtFront(pNdisPkt, &pNdisBuffer);
  127. CTEAssert((pNdisBuffer != NULL) || (BytesTransferred == 0));
  128. // BUG #11772
  129. // On MP-machines scf_CurRecvReq could be set to NULL. Get the req
  130. // from the recv packet.
  131. // pRequest = pSpxConnFile->scf_CurRecvReq;
  132. // CTEAssert(pRequest == pRecvResd->rr_Request);
  133. pRequest = pRecvResd->rr_Request;
  134. // Remove reference for this packet.
  135. --(REQUEST_INFORMATION(pRequest));
  136. if (NdisStatus == NDIS_STATUS_SUCCESS)
  137. {
  138. pSpxConnFile->scf_CurRecvOffset += BytesTransferred;
  139. pSpxConnFile->scf_CurRecvSize -= BytesTransferred;
  140. #if DBG
  141. if ((pRecvResd->rr_State & SPX_RECVPKT_INDICATED) != 0)
  142. {
  143. if (BytesTransferred != 0)
  144. {
  145. CTEAssert (pSpxConnFile->scf_IndBytes != 0);
  146. pSpxConnFile->scf_IndBytes -= BytesTransferred;
  147. }
  148. }
  149. #endif
  150. if (REQUEST_INFORMATION(pRequest) == 0)
  151. {
  152. DBGPRINT(RECEIVE, DBG,
  153. ("SpxTransferDataComplete: Request %lx ref %lx Cur %lx.%lx\n",
  154. pRequest, REQUEST_INFORMATION(pRequest),
  155. REQUEST_STATUS(pRequest),
  156. pSpxConnFile->scf_CurRecvSize));
  157. if (SPX_CONN_STREAM(pSpxConnFile) ||
  158. (pSpxConnFile->scf_CurRecvSize == 0) ||
  159. fEom ||
  160. ((REQUEST_STATUS(pRequest) != STATUS_SUCCESS) &&
  161. (REQUEST_STATUS(pRequest) != STATUS_RECEIVE_PARTIAL)))
  162. {
  163. CTELockHandle lockHandleInter;
  164. // We are done with this receive.
  165. REQUEST_INFORMATION(pRequest) = pSpxConnFile->scf_CurRecvOffset;
  166. status = STATUS_SUCCESS;
  167. if (!SPX_CONN_STREAM(pSpxConnFile) &&
  168. (pSpxConnFile->scf_CurRecvSize == 0) &&
  169. !fEom)
  170. {
  171. status = STATUS_RECEIVE_PARTIAL;
  172. }
  173. if ((REQUEST_STATUS(pRequest) != STATUS_SUCCESS) &&
  174. (REQUEST_STATUS(pRequest) != STATUS_RECEIVE_PARTIAL))
  175. {
  176. status = REQUEST_STATUS(pRequest);
  177. }
  178. REQUEST_STATUS(pRequest) = status;
  179. DBGPRINT(RECEIVE, DBG,
  180. ("SpxTransferDataComplete: Request %lx ref %lx Cur %lx.%lx\n",
  181. pRequest, REQUEST_INFORMATION(pRequest),
  182. REQUEST_STATUS(pRequest),
  183. pSpxConnFile->scf_CurRecvSize));
  184. // Dequeue this request, Set next recv if one exists.
  185. SPX_CONN_SETNEXT_CUR_RECV(pSpxConnFile, pRequest);
  186. CTEGetLock(&SpxGlobalQInterlock, &lockHandleInter);
  187. InsertTailList(
  188. &pSpxConnFile->scf_RecvDoneLinkage,
  189. REQUEST_LINKAGE(pRequest));
  190. SPX_QUEUE_FOR_RECV_COMPLETION(pSpxConnFile);
  191. CTEFreeLock(&SpxGlobalQInterlock, lockHandleInter);
  192. }
  193. }
  194. }
  195. if (pNdisBuffer != NULL)
  196. {
  197. NdisFreeBuffer(pNdisBuffer);
  198. }
  199. }
  200. else
  201. {
  202. // Buffered receive, queue it in if successful.
  203. // BUG #18363
  204. // IF WE DISCONNECTED in the meantime, we need to just dump this
  205. // packet.
  206. if (SPX_CONN_ACTIVE(pSpxConnFile) &&
  207. (NdisStatus == NDIS_STATUS_SUCCESS))
  208. {
  209. // Queue packet in connection. Reference connection for this.
  210. SpxConnQueueRecvPktTail(pSpxConnFile, pNdisPkt);
  211. SpxConnFileLockReference(pSpxConnFile, CFREF_VERIFY);
  212. DBGPRINT(RECEIVE, DBG,
  213. ("SpxTransferData: Buffering: %lx Pkt %lx Size %lx F %lx\n",
  214. pSpxConnFile, pNdisPkt, BytesTransferred, pRecvResd->rr_State));
  215. // There could either be queued receives. (This could happen in
  216. // a partial receive case. Or if a receive got queued in while we
  217. // were processing this packet (Possible on MP)), or a packet was
  218. // buffered while we were completing some receives
  219. CTEAssert(pSpxConnFile->scf_RecvListHead);
  220. if ((pSpxConnFile->scf_CurRecvReq != NULL) ||
  221. ((pSpxConnFile->scf_RecvListHead->rr_State &
  222. SPX_RECVPKT_INDICATED) == 0))
  223. {
  224. CTELockHandle interLockHandle;
  225. // Push this connection into a ProcessRecv queue which will be
  226. // dealt with in receive completion.
  227. DBGPRINT(RECEIVE, DBG,
  228. ("spxRecvTransferData: Queueing for recvp %lx.%lx\n",
  229. pSpxConnFile, pSpxConnFile->scf_Flags));
  230. // Get the global q lock, push into recv list.
  231. CTEGetLock(&SpxGlobalQInterlock, &interLockHandle);
  232. SPX_QUEUE_FOR_RECV_COMPLETION(pSpxConnFile);
  233. CTEFreeLock(&SpxGlobalQInterlock, interLockHandle);
  234. }
  235. }
  236. else
  237. {
  238. PBYTE pData;
  239. ULONG dataLen;
  240. // Get pointer to the buffer descriptor and its memory.
  241. NdisUnchainBufferAtFront(pNdisPkt, &pNdisBuffer);
  242. if (pNdisBuffer != NULL)
  243. {
  244. NdisQueryBuffer(pNdisBuffer, &pData, &dataLen);
  245. CTEAssert(pData != NULL);
  246. CTEAssert((LONG)dataLen >= 0);
  247. // Free the data, ndis buffer.
  248. if (pNdisBuffer != NULL)
  249. {
  250. NdisFreeBuffer(pNdisBuffer);
  251. }
  252. SpxFreeMemory(pData);
  253. }
  254. // Dont send ack, set status to be failure so we free packet/buffer.
  255. fAck = FALSE;
  256. NdisStatus = NDIS_STATUS_FAILURE;
  257. }
  258. }
  259. END_PROCESS_PACKET(
  260. pSpxConnFile, fBuffered, (NdisStatus == NDIS_STATUS_SUCCESS));
  261. if (fAck)
  262. {
  263. // Rem ack addr should have been copied in receive.
  264. // #17564
  265. if (fImmedAck ||
  266. SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_NOACKWAIT) ||
  267. SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_IMMED_ACK))
  268. {
  269. SpxConnSendAck(pSpxConnFile, lockHandle);
  270. fLockHeld = FALSE;
  271. }
  272. else
  273. {
  274. SpxConnQWaitAck(pSpxConnFile);
  275. }
  276. }
  277. if (fLockHeld)
  278. {
  279. CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
  280. }
  281. if (!fBuffered || (NdisStatus != STATUS_SUCCESS))
  282. {
  283. // Free the ndis packet/buffer
  284. SpxPktRecvRelease(pNdisPkt);
  285. }
  286. return;
  287. }
  288. VOID
  289. SpxReceiveComplete(
  290. IN USHORT NicId
  291. )
  292. {
  293. CTELockHandle lockHandleInter, lockHandle;
  294. PREQUEST pRequest;
  295. BOOLEAN fConnLockHeld, fInterlockHeld;
  296. PSPX_CONN_FILE pSpxConnFile;
  297. int numDerefs = 0;
  298. // See if any connections need recv processing. This will also take
  299. // care of any acks opening up window so our sends go to the max.
  300. CTEGetLock(&SpxGlobalQInterlock, &lockHandleInter);
  301. fInterlockHeld = TRUE;
  302. while ((pSpxConnFile = SpxRecvConnList.pcl_Head) != NULL)
  303. {
  304. // Reset for each connection
  305. numDerefs = 0;
  306. if ((SpxRecvConnList.pcl_Head = pSpxConnFile->scf_ProcessRecvNext) == NULL)
  307. SpxRecvConnList.pcl_Tail = NULL;
  308. // Reset next field to NULL
  309. pSpxConnFile->scf_ProcessRecvNext = NULL;
  310. DBGPRINT(SEND, DBG,
  311. ("SpxConnRemoveFromRecv: %lx\n", pSpxConnFile));
  312. CTEFreeLock(&SpxGlobalQInterlock, lockHandleInter);
  313. CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
  314. do
  315. {
  316. // Complete pending requests.
  317. while (!IsListEmpty(&pSpxConnFile->scf_ReqDoneLinkage))
  318. {
  319. pRequest =
  320. LIST_ENTRY_TO_REQUEST(pSpxConnFile->scf_ReqDoneLinkage.Flink);
  321. RemoveEntryList(REQUEST_LINKAGE(pRequest));
  322. CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
  323. DBGPRINT(TDI, DBG,
  324. ("SpxReceiveComplete: Completing %lx with %lx.%lx\n",
  325. pRequest, REQUEST_STATUS(pRequest),
  326. REQUEST_INFORMATION(pRequest)));
  327. CTEAssert (REQUEST_MINOR_FUNCTION(pRequest) != TDI_RECEIVE);
  328. SpxCompleteRequest(pRequest);
  329. numDerefs++;
  330. CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
  331. }
  332. // Call process pkts if we have any packets or if any receives to
  333. // complete. Note this will call even when there are no receives
  334. // queued and the first packet has already been indicated.
  335. if ((SPX_RECV_STATE(pSpxConnFile) != SPX_RECV_PROCESS_PKTS) &&
  336. (!IsListEmpty(&pSpxConnFile->scf_RecvDoneLinkage) ||
  337. (pSpxConnFile->scf_RecvListHead != NULL)))
  338. {
  339. // We have the flag reference on the connection.
  340. SpxRecvProcessPkts(pSpxConnFile, lockHandle);
  341. CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
  342. }
  343. #if DBG
  344. if (!IsListEmpty(&pSpxConnFile->scf_RecvDoneLinkage))
  345. {
  346. DBGPRINT(TDI, DBG,
  347. ("SpxReceiveComplete: RecvDone left %lx\n",
  348. pSpxConnFile));
  349. }
  350. #endif
  351. // Hmm. This check is rather expensive, and essentially we are doing
  352. // it twice. Should look to see if this can be modified safely.
  353. } while ((!IsListEmpty(&pSpxConnFile->scf_ReqDoneLinkage)) ||
  354. ((SPX_RECV_STATE(pSpxConnFile) != SPX_RECV_PROCESS_PKTS) &&
  355. ((!IsListEmpty(&pSpxConnFile->scf_RecvDoneLinkage)) ||
  356. ((pSpxConnFile->scf_RecvListHead != NULL) &&
  357. ((pSpxConnFile->scf_RecvListHead->rr_State &
  358. (SPX_RECVPKT_BUFFERING | SPX_RECVPKT_INDICATED)) ==
  359. SPX_RECVPKT_BUFFERING)))));
  360. SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_RECVQ);
  361. SpxConnFileTransferReference(
  362. pSpxConnFile,
  363. CFREF_RECV,
  364. CFREF_VERIFY);
  365. numDerefs++;
  366. CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
  367. while (numDerefs-- > 0)
  368. {
  369. SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
  370. }
  371. CTEGetLock(&SpxGlobalQInterlock, &lockHandleInter);
  372. }
  373. // First see if we need to packetize.
  374. while ((pSpxConnFile = SpxPktConnList.pcl_Head) != NULL)
  375. {
  376. if ((SpxPktConnList.pcl_Head = pSpxConnFile->scf_PktNext) == NULL)
  377. SpxPktConnList.pcl_Tail = NULL;
  378. // Reset next field to NULL
  379. pSpxConnFile->scf_PktNext = NULL;
  380. CTEFreeLock(&SpxGlobalQInterlock, lockHandleInter);
  381. DBGPRINT(SEND, DBG,
  382. ("SpxConnRemoveFromPkt: %lx\n", pSpxConnFile));
  383. CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
  384. fConnLockHeld = TRUE;
  385. DBGPRINT(RECEIVE, DBG,
  386. ("SpxReceiveComplete: Packetizing %lx\n", pSpxConnFile));
  387. SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_PKTQ);
  388. if (SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_IDLE)
  389. {
  390. SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_PACKETIZE);
  391. // 262691 SpxConnPacketize always frees the lock.
  392. SpxConnPacketize(
  393. pSpxConnFile,
  394. TRUE,
  395. lockHandle);
  396. fConnLockHeld = FALSE;
  397. }
  398. if (fConnLockHeld)
  399. {
  400. CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
  401. }
  402. SpxConnFileDereference(pSpxConnFile, CFREF_PKTIZE);
  403. CTEGetLock(&SpxGlobalQInterlock, &lockHandleInter);
  404. }
  405. if (fInterlockHeld)
  406. {
  407. CTEFreeLock(&SpxGlobalQInterlock, lockHandleInter);
  408. }
  409. return;
  410. }
  411. //
  412. // PACKET HANDLING ROUTINES
  413. //
  414. VOID
  415. SpxRecvSysPacket(
  416. IN NDIS_HANDLE MacBindingHandle,
  417. IN NDIS_HANDLE MacReceiveContext,
  418. IN PIPX_LOCAL_TARGET pRemoteAddr,
  419. IN ULONG MacOptions,
  420. IN PUCHAR LookaheadBuffer,
  421. IN UINT LookaheadBufferSize,
  422. IN UINT LookaheadBufferOffset,
  423. IN UINT PacketSize
  424. )
  425. /*++
  426. Routine Description:
  427. This is called to indicate an incoming system packet.
  428. Arguments:
  429. Return Value:
  430. --*/
  431. {
  432. NTSTATUS status;
  433. PIPXSPX_HDR pHdr;
  434. USHORT srcConnId, destConnId,
  435. pktLen, ackNum, allocNum;
  436. PSPX_CONN_FILE pSpxConnFile;
  437. CTELockHandle lockHandle;
  438. BOOLEAN lockHeld = FALSE;
  439. pHdr = (PIPXSPX_HDR)LookaheadBuffer;
  440. // check minimum length
  441. if (PacketSize < MIN_IPXSPX_HDRSIZE)
  442. {
  443. return;
  444. }
  445. // Convert hdr to host format as needed.
  446. GETSHORT2SHORT(&pktLen, &pHdr->hdr_PktLen);
  447. GETSHORT2SHORT(&destConnId, &pHdr->hdr_DestConnId);
  448. if ((pktLen < MIN_IPXSPX_HDRSIZE) ||
  449. (pktLen > PacketSize) ||
  450. (pHdr->hdr_PktType != SPX_PKT_TYPE))
  451. {
  452. DBGPRINT(RECEIVE, ERR,
  453. ("SpxRecvSysPacket: Packet Size %lx.%lx\n",
  454. pktLen, PacketSize));
  455. return;
  456. }
  457. if ((pktLen == SPX_CR_PKTLEN) &&
  458. (destConnId == 0xFFFF) &&
  459. (pHdr->hdr_ConnCtrl & SPX_CC_CR))
  460. {
  461. spxConnHandleConnReq(
  462. pHdr,
  463. pRemoteAddr);
  464. return;
  465. }
  466. //
  467. // [SA] Bug #14917
  468. // Some SPX SYS packets (no extended ack field) may come in with the SPX2 bit set.
  469. // Make sure we don't discard these packets.
  470. //
  471. // if ((pHdr->hdr_ConnCtrl & SPX_CC_SPX2) && (pktLen < MIN_IPXSPX2_HDRSIZE))
  472. // {
  473. // return;
  474. // }
  475. GETSHORT2SHORT(&ackNum, &pHdr->hdr_AckNum);
  476. GETSHORT2SHORT(&allocNum, &pHdr->hdr_AllocNum);
  477. // We keep and use the remote id in the net format. This maintains the
  478. // 0x0 and 0xFFFF to be as in the host format.
  479. srcConnId = *(USHORT UNALIGNED *)&pHdr->hdr_SrcConnId;
  480. if ((srcConnId == 0) || (srcConnId == 0xFFFF) || (destConnId == 0))
  481. {
  482. DBGPRINT(RECEIVE, ERR,
  483. ("SpxConnSysPacket: Incorrect conn id %lx.%lx\n",
  484. srcConnId, destConnId));
  485. return;
  486. }
  487. DBGPRINT(CONNECT, DBG,
  488. ("SpxConnSysPacket: packet received dest %lx src %lx\n",
  489. pHdr->hdr_DestSkt, pHdr->hdr_SrcSkt));
  490. // Find the connection this is destined for and reference it.
  491. SpxConnFileReferenceById(destConnId, &pSpxConnFile, &status);
  492. if (!NT_SUCCESS(status))
  493. {
  494. DBGPRINT(RECEIVE, WARN,
  495. ("SpxConnSysPacket: Id %lx NOT FOUND\n", destConnId));
  496. return;
  497. }
  498. do
  499. {
  500. DBGPRINT(RECEIVE, INFO,
  501. ("SpxConnSysPacket: Id %lx Conn %lx\n",
  502. destConnId, pSpxConnFile));
  503. // This could be one of many packets. Connection ack/Session negotiate/
  504. // Session setup, Data Ack, Probe/Ack, Renegotiate/Ack. We shunt
  505. // off all the packets to different routines but process the data
  506. // ack packets here.
  507. CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
  508. //
  509. // We have the connection. We should update the dest. sock # in
  510. // it in case it changed. Unix machines do do that sometimes.
  511. // SCO bug 7676
  512. //
  513. SpxCopyIpxAddr(pHdr, pSpxConnFile->scf_RemAddr);
  514. lockHeld = TRUE;
  515. // Restart watchdog timer if started.
  516. if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER))
  517. {
  518. // This will either successfully restart or not affect the timer
  519. // if it is currently running.
  520. SpxTimerCancelEvent(
  521. pSpxConnFile->scf_WTimerId,
  522. TRUE);
  523. pSpxConnFile->scf_WRetryCount = PARAM(CONFIG_KEEPALIVE_COUNT);
  524. }
  525. switch (SPX_MAIN_STATE(pSpxConnFile))
  526. {
  527. case SPX_CONNFILE_CONNECTING:
  528. CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
  529. lockHeld = FALSE;
  530. spxConnHandleSessPktFromSrv(
  531. pHdr,
  532. pRemoteAddr,
  533. pSpxConnFile);
  534. break;
  535. case SPX_CONNFILE_LISTENING:
  536. CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
  537. lockHeld = FALSE;
  538. spxConnHandleSessPktFromClient(
  539. pHdr,
  540. pRemoteAddr,
  541. pSpxConnFile);
  542. break;
  543. case SPX_CONNFILE_ACTIVE:
  544. case SPX_CONNFILE_DISCONN:
  545. // NOTE: Our ack to a session setup might get dropped.
  546. // But the SS Ack is similar to a normal SPX2 ack.
  547. // We dont have to do anything special.
  548. // Received ack/nack/reneg/reneg ack/disc associated packet.
  549. // Disc packets except ordrel ack have non-zero datastream type.
  550. if ((pHdr->hdr_ConnCtrl &
  551. (SPX_CC_SYS | SPX_CC_ACK | SPX_CC_NEG | SPX_CC_SPX2)) ==
  552. (SPX_CC_SYS | SPX_CC_ACK | SPX_CC_NEG | SPX_CC_SPX2))
  553. {
  554. // We received a renegotiate packet. Ignore all ack values
  555. // in a reneg req.
  556. SpxConnProcessRenegReq(pSpxConnFile, pHdr, pRemoteAddr, lockHandle);
  557. lockHeld = FALSE;
  558. break;
  559. }
  560. // Set ack numbers for connection.
  561. SPX_SET_ACKNUM(
  562. pSpxConnFile, ackNum, allocNum);
  563. // Check if we are an ack/nack packet in which case call process
  564. // ack. Note that the spx2 orderly release ack is a normal spx2 ack.
  565. if (((pHdr->hdr_ConnCtrl & SPX_CC_ACK) == 0) &&
  566. (pHdr->hdr_DataType == 0))
  567. {
  568. SpxConnProcessAck(pSpxConnFile, pHdr, lockHandle);
  569. lockHeld = FALSE;
  570. }
  571. else
  572. {
  573. // Just process the numbers we got.
  574. SpxConnProcessAck(pSpxConnFile, NULL, lockHandle);
  575. lockHeld = FALSE;
  576. }
  577. // If the remote wants us to send an ack, do it.
  578. if (pHdr->hdr_ConnCtrl & SPX_CC_ACK)
  579. {
  580. // First copy the remote address in connection.
  581. SpxCopyIpxAddr(pHdr, pSpxConnFile->scf_RemAckAddr);
  582. pSpxConnFile->scf_AckLocalTarget = *pRemoteAddr;
  583. if (!lockHeld)
  584. {
  585. CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
  586. lockHeld = TRUE;
  587. }
  588. SpxConnSendAck(pSpxConnFile, lockHandle);
  589. lockHeld = FALSE;
  590. break;
  591. }
  592. break;
  593. default:
  594. // Ignore this packet.
  595. DBGPRINT(RECEIVE, WARN,
  596. ("SpxConnSysPacket: Ignoring packet, state is not active\n"));
  597. break;
  598. }
  599. } while (FALSE);
  600. if (lockHeld)
  601. {
  602. CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
  603. }
  604. // Remove reference added on connection
  605. SpxConnFileDereference(pSpxConnFile, CFREF_BYID);
  606. return;
  607. }
  608. VOID
  609. SpxRecvDiscPacket(
  610. IN PUCHAR LookaheadBuffer,
  611. IN PIPX_LOCAL_TARGET pRemoteAddr,
  612. IN UINT LookaheadSize
  613. )
  614. /*++
  615. Routine Description:
  616. This is called to indicate an incoming connection.
  617. Arguments:
  618. Return Value:
  619. --*/
  620. {
  621. NTSTATUS status;
  622. PIPXSPX_HDR pHdr;
  623. USHORT srcConnId, destConnId,
  624. pktLen, seqNum, ackNum, allocNum;
  625. PSPX_CONN_FILE pSpxConnFile;
  626. CTELockHandle lockHandle;
  627. BOOLEAN lockHeld;
  628. pHdr = (PIPXSPX_HDR)LookaheadBuffer;
  629. // check minimum length
  630. if (LookaheadSize < MIN_IPXSPX_HDRSIZE)
  631. {
  632. return;
  633. }
  634. // Convert hdr to host format as needed.
  635. GETSHORT2SHORT(&pktLen, &pHdr->hdr_PktLen);
  636. GETSHORT2SHORT(&destConnId, &pHdr->hdr_DestConnId);
  637. GETSHORT2SHORT(&seqNum, &pHdr->hdr_SeqNum);
  638. GETSHORT2SHORT(&ackNum, &pHdr->hdr_AckNum);
  639. GETSHORT2SHORT(&allocNum, &pHdr->hdr_AllocNum);
  640. if ((pktLen < MIN_IPXSPX_HDRSIZE) ||
  641. (pHdr->hdr_PktType != SPX_PKT_TYPE))
  642. {
  643. DBGPRINT(RECEIVE, ERR,
  644. ("SpxRecvDiscPacket: Packet Size %lx\n",
  645. pktLen));
  646. return;
  647. }
  648. // We keep and use the remote id in the net format. This maintains the
  649. // 0x0 and 0xFFFF to be as in the host format.
  650. srcConnId = *(USHORT UNALIGNED *)&pHdr->hdr_SrcConnId;
  651. if ((srcConnId == 0) || (srcConnId == 0xFFFF) || (destConnId == 0))
  652. {
  653. DBGPRINT(RECEIVE, ERR,
  654. ("SpxConnDiscPacket: Incorrect conn id %lx.%lx\n",
  655. srcConnId, destConnId));
  656. return;
  657. }
  658. DBGPRINT(CONNECT, DBG,
  659. ("SpxConnDiscPacket: packet received dest %lx src %lx\n",
  660. pHdr->hdr_DestSkt, pHdr->hdr_SrcSkt));
  661. // Find the connection this is destined for and reference it.
  662. SpxConnFileReferenceById(destConnId, &pSpxConnFile, &status);
  663. if (!NT_SUCCESS(status))
  664. {
  665. DBGPRINT(RECEIVE, WARN,
  666. ("SpxConnDiscPacket: Id %lx NOT FOUND", destConnId));
  667. return;
  668. }
  669. do
  670. {
  671. DBGPRINT(RECEIVE, INFO,
  672. ("SpxConnDiscPacket: Id %lx Conn %lx DiscType %lx\n",
  673. destConnId, pSpxConnFile, pHdr->hdr_DataType));
  674. CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
  675. lockHeld = TRUE;
  676. // Unless we are in the active/disconnecting, but send state = idle
  677. // and recv state = idle/recv posted, we ignore all disconnect packets.
  678. if (((SPX_MAIN_STATE(pSpxConnFile) != SPX_CONNFILE_ACTIVE) &&
  679. (SPX_MAIN_STATE(pSpxConnFile) != SPX_CONNFILE_DISCONN)) ||
  680. ((SPX_SEND_STATE(pSpxConnFile) != SPX_SEND_IDLE) &&
  681. (SPX_SEND_STATE(pSpxConnFile) != SPX_SEND_PACKETIZE)) ||
  682. ((SPX_RECV_STATE(pSpxConnFile) != SPX_RECV_IDLE) &&
  683. (SPX_RECV_STATE(pSpxConnFile) != SPX_RECV_POSTED)) ||
  684. !(IsListEmpty(&pSpxConnFile->scf_RecvDoneLinkage)) ||
  685. (SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_PKT)))
  686. {
  687. DBGPRINT(RECEIVE, DBG,
  688. ("SpxConnDiscPacket: %lx, %lx, %lx.%lx, %d.%d\n",
  689. pSpxConnFile,
  690. SPX_MAIN_STATE(pSpxConnFile),
  691. SPX_SEND_STATE(pSpxConnFile), SPX_RECV_STATE(pSpxConnFile),
  692. (IsListEmpty(&pSpxConnFile->scf_RecvDoneLinkage)),
  693. (SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_PKT))));
  694. break;
  695. }
  696. // If we have received a disconnect, process received ack to complete any
  697. // pending sends before we allow the disconnect. This ack number will be
  698. // the last word on this session.
  699. SPX_SET_ACKNUM(
  700. pSpxConnFile, ackNum, allocNum);
  701. SpxConnProcessAck(pSpxConnFile, NULL, lockHandle);
  702. CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
  703. switch (pHdr->hdr_DataType)
  704. {
  705. case SPX2_DT_ORDREL:
  706. DBGPRINT(RECEIVE, DBG,
  707. ("SpxConnDiscPacket: Recd ORDREl!\n"));
  708. // Need to deal with all sthe states.
  709. // Restart watchdog timer if started.
  710. if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER))
  711. {
  712. // This will either successfully restart or not affect the timer
  713. // if it is currently running.
  714. SpxTimerCancelEvent(
  715. pSpxConnFile->scf_WTimerId,
  716. TRUE);
  717. pSpxConnFile->scf_WRetryCount = PARAM(CONFIG_KEEPALIVE_COUNT);
  718. }
  719. // On receive, we do check the seq num for the orderly release, just
  720. // like for a data packet.
  721. // If this was not already indicated, indicate it now. That is all
  722. // we do for an orderly release. When our client does a orderly rel
  723. // and we receive the ack for that, call abortive with success.
  724. // Verify ord rel packet, this checks if seq nums match also.
  725. if ((pktLen != MIN_IPXSPX2_HDRSIZE) ||
  726. ((pHdr->hdr_ConnCtrl &
  727. (SPX_CC_ACK | SPX_CC_EOM | SPX_CC_SPX2)) !=
  728. (SPX_CC_ACK | SPX_CC_EOM | SPX_CC_SPX2)) ||
  729. (pHdr->hdr_DataType != SPX2_DT_ORDREL) ||
  730. (srcConnId == 0) ||
  731. (srcConnId == 0xFFFF) ||
  732. (srcConnId != pSpxConnFile->scf_RemConnId) ||
  733. (destConnId == 0) ||
  734. (destConnId == 0xFFFF) ||
  735. (destConnId != pSpxConnFile->scf_LocalConnId))
  736. {
  737. DBGPRINT(CONNECT, DBG1,
  738. ("SpxConnDiscPacket: OR Failed/Ignored %lx, %lx.%lx.%lx\n",
  739. pSpxConnFile, seqNum, pSpxConnFile->scf_RecvSeqNum,
  740. pSpxConnFile->scf_RecvListTail));
  741. break;
  742. }
  743. // If it passed above test, but seq number is incorrect, schedule
  744. // to send an ack.
  745. if (seqNum != pSpxConnFile->scf_RecvSeqNum)
  746. {
  747. USHORT NumToResend;
  748. DBGPRINT(CONNECT, DBG,
  749. ("SpxConnDiscPacket: Unexpected seq on %lx, %lx.%lx\n",
  750. pSpxConnFile, seqNum, pSpxConnFile->scf_RecvSeqNum));
  751. // Calculate number to be resent. If we expect sequence 1 and receive
  752. // 2 for eg., we need to send a nack, else we send an ack.
  753. if (SPX2_CONN(pSpxConnFile) &&
  754. UNSIGNED_GREATER_WITH_WRAP(
  755. seqNum,
  756. pSpxConnFile->scf_RecvSeqNum) &&
  757. !UNSIGNED_GREATER_WITH_WRAP(
  758. seqNum,
  759. pSpxConnFile->scf_SentAllocNum))
  760. {
  761. NumToResend = (USHORT)(seqNum - pSpxConnFile->scf_RecvSeqNum + 1);
  762. SpxConnSendNack(pSpxConnFile, NumToResend, lockHandle);
  763. lockHeld = FALSE;
  764. }
  765. break;
  766. }
  767. // Copy address for when ack is to be sent.
  768. SpxCopyIpxAddr(pHdr, pSpxConnFile->scf_RemAckAddr);
  769. pSpxConnFile->scf_AckLocalTarget = *pRemoteAddr;
  770. if (pSpxConnFile->scf_RecvListHead == NULL)
  771. {
  772. // No received data, go ahead and process now.
  773. DBGPRINT(CONNECT, INFO,
  774. ("SpxConnDiscPacket: NO DATA ORDREL %lx.%lx.%lx\n",
  775. pSpxConnFile,
  776. pSpxConnFile->scf_RecvListHead,
  777. pSpxConnFile->scf_SendSeqListHead));
  778. SpxConnProcessOrdRel(pSpxConnFile, lockHandle);
  779. lockHeld = FALSE;
  780. }
  781. else
  782. {
  783. // No received data, go ahead and process now.
  784. DBGPRINT(CONNECT, DBG1,
  785. ("SpxConnDiscPacket: DATA ORDREL %lx.%lx.%lx\n",
  786. pSpxConnFile,
  787. pSpxConnFile->scf_RecvListHead,
  788. pSpxConnFile->scf_SendSeqListHead));
  789. // Set flag in last recd buffer
  790. pSpxConnFile->scf_RecvListTail->rr_State |= SPX_RECVPKT_ORD_DISC;
  791. }
  792. break;
  793. case SPX2_DT_IDISC:
  794. DBGPRINT(RECEIVE, DBG,
  795. ("SpxConnDiscPacket: %lx Recd IDISC %lx!\n",
  796. pSpxConnFile, pSpxConnFile->scf_RefCount));
  797. DBGPRINT(RECEIVE, INFO,
  798. ("SpxConnDiscPacket: SEND %d. RECV %d.%lx!\n",
  799. IsListEmpty(&pSpxConnFile->scf_ReqLinkage),
  800. IsListEmpty(&pSpxConnFile->scf_RecvLinkage),
  801. pSpxConnFile->scf_RecvDoneLinkage));
  802. if (!((pktLen == MIN_IPXSPX_HDRSIZE) ||
  803. ((pHdr->hdr_ConnCtrl & SPX_CC_SPX2) &&
  804. (pktLen == MIN_IPXSPX2_HDRSIZE))) ||
  805. !(pHdr->hdr_ConnCtrl & SPX_CC_ACK) ||
  806. (pHdr->hdr_DataType != SPX2_DT_IDISC) ||
  807. (srcConnId == 0) ||
  808. (srcConnId == 0xFFFF) ||
  809. (srcConnId != pSpxConnFile->scf_RemConnId) ||
  810. (destConnId == 0) ||
  811. (destConnId == 0xFFFF) ||
  812. (destConnId != pSpxConnFile->scf_LocalConnId))
  813. {
  814. DBGPRINT(CONNECT, ERR,
  815. ("SpxConnDiscPacket:IDISC Ignored %lx.%lx.%lx.%lx\n",
  816. pSpxConnFile, seqNum,
  817. pSpxConnFile->scf_RecvSeqNum,
  818. pSpxConnFile->scf_RecvListTail));
  819. break;
  820. }
  821. // Copy address for when ack is to be sent.
  822. SpxCopyIpxAddr(pHdr, pSpxConnFile->scf_RemAckAddr);
  823. pSpxConnFile->scf_AckLocalTarget = *pRemoteAddr;
  824. if (pSpxConnFile->scf_RecvListHead == NULL)
  825. {
  826. // No received data, go ahead and process now.
  827. DBGPRINT(CONNECT, INFO,
  828. ("SpxConnDiscPacket: NO RECV DATA IDISC %lx.%lx.%lx\n",
  829. pSpxConnFile,
  830. pSpxConnFile->scf_RecvListHead,
  831. pSpxConnFile->scf_SendSeqListHead));
  832. SpxConnProcessIDisc(pSpxConnFile, lockHandle);
  833. lockHeld = FALSE;
  834. }
  835. else
  836. {
  837. // Set flag in last recd buffer
  838. pSpxConnFile->scf_RecvListTail->rr_State |= SPX_RECVPKT_IDISC;
  839. }
  840. break;
  841. case SPX2_DT_IDISC_ACK:
  842. // Done with informed disconnect. Call abort connection with
  843. // status success. That completes the pending disconnect request
  844. // with status_success.
  845. DBGPRINT(RECEIVE, DBG,
  846. ("SpxConnDiscPacket: %lx Recd IDISC ack!\n", pSpxConnFile));
  847. if (!((pktLen == MIN_IPXSPX_HDRSIZE) ||
  848. ((pHdr->hdr_ConnCtrl & SPX_CC_SPX2) &&
  849. (pktLen == MIN_IPXSPX2_HDRSIZE))) ||
  850. (pHdr->hdr_DataType != SPX2_DT_IDISC_ACK) ||
  851. (srcConnId == 0) ||
  852. (srcConnId == 0xFFFF) ||
  853. (srcConnId != pSpxConnFile->scf_RemConnId) ||
  854. (destConnId == 0) ||
  855. (destConnId == 0xFFFF) ||
  856. (destConnId != pSpxConnFile->scf_LocalConnId))
  857. {
  858. DBGPRINT(CONNECT, ERR,
  859. ("SpxConnDiscPacket:Ver idisc ack Failed %lx, %lx.%lx\n",
  860. pSpxConnFile, seqNum, pSpxConnFile->scf_RecvSeqNum));
  861. break;
  862. }
  863. // We should be in the right state to accept this.
  864. if ((SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_DISCONN) &&
  865. (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_SENT_IDISC))
  866. {
  867. spxConnAbortiveDisc(
  868. pSpxConnFile,
  869. STATUS_SUCCESS,
  870. SPX_CALL_RECVLEVEL,
  871. lockHandle,
  872. FALSE); // [SA] bug #15249
  873. lockHeld = FALSE;
  874. }
  875. break;
  876. default:
  877. KeBugCheck(0);
  878. }
  879. } while (FALSE);
  880. if (lockHeld)
  881. {
  882. CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
  883. }
  884. // Remove reference added on connection
  885. SpxConnFileDereference(pSpxConnFile, CFREF_BYID);
  886. return;
  887. }
  888. VOID
  889. SpxRecvBufferPkt(
  890. IN PSPX_CONN_FILE pSpxConnFile,
  891. IN NDIS_HANDLE MacBindingHandle,
  892. IN NDIS_HANDLE MacReceiveContext,
  893. IN UINT LookaheadOffset,
  894. IN PIPXSPX_HDR pIpxSpxHdr,
  895. IN UINT PacketSize,
  896. IN PIPX_LOCAL_TARGET pRemoteAddr,
  897. IN CTELockHandle LockHandleConn
  898. )
  899. /*++
  900. Routine Description:
  901. This is called to indicate an incoming connection.
  902. Arguments:
  903. Return Value:
  904. --*/
  905. {
  906. PNDIS_PACKET pNdisPkt;
  907. PSPX_RECV_RESD pRecvResd;
  908. ULONG bytesCopied;
  909. BOOLEAN fEom;
  910. NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS;
  911. PBYTE pData = NULL;
  912. PNDIS_BUFFER pNdisBuffer = NULL;
  913. if (PacketSize > 0)
  914. {
  915. // Allocate memory for this data.
  916. if (pData = (PBYTE)SpxAllocateMemory(PacketSize))
  917. {
  918. // Describe memory with a ndis buffer descriptor.
  919. NdisAllocateBuffer(
  920. &ndisStatus,
  921. &pNdisBuffer,
  922. SpxDevice->dev_NdisBufferPoolHandle,
  923. pData,
  924. PacketSize);
  925. }
  926. else
  927. {
  928. ndisStatus = NDIS_STATUS_RESOURCES;
  929. }
  930. }
  931. if (ndisStatus == NDIS_STATUS_SUCCESS)
  932. {
  933. // Allocate a ndis receive packet.
  934. SpxAllocRecvPacket(SpxDevice, &pNdisPkt, &ndisStatus);
  935. if (ndisStatus == NDIS_STATUS_SUCCESS)
  936. {
  937. // Queue the buffer into the packet if there is one.
  938. if (pNdisBuffer)
  939. {
  940. NdisChainBufferAtBack(
  941. pNdisPkt,
  942. pNdisBuffer);
  943. }
  944. fEom = ((SPX_CONN_MSG(pSpxConnFile) &&
  945. (pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_EOM)) ||
  946. SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_IPXHDR));
  947. pRecvResd = RECV_RESD(pNdisPkt);
  948. pRecvResd->rr_DataOffset= 0;
  949. #if DBG
  950. // Store seq number
  951. GETSHORT2SHORT(&pRecvResd->rr_SeqNum , &pIpxSpxHdr->hdr_SeqNum);
  952. #endif
  953. pRecvResd->rr_State =
  954. (SPX_RECVPKT_BUFFERING |
  955. (SPX_CONN_FLAG2(
  956. pSpxConnFile, SPX_CONNFILE2_PKT_NOIND) ? SPX_RECVPKT_INDICATED : 0) |
  957. (fEom ? SPX_RECVPKT_EOM : 0) |
  958. ((pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_ACK) ? SPX_RECVPKT_SENDACK : 0));
  959. if (pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_ACK)
  960. {
  961. // copy the remote address in connection.
  962. SpxCopyIpxAddr(pIpxSpxHdr, pSpxConnFile->scf_RemAckAddr);
  963. pSpxConnFile->scf_AckLocalTarget = *pRemoteAddr;
  964. }
  965. pRecvResd->rr_Request = NULL;
  966. pRecvResd->rr_ConnFile = pSpxConnFile;
  967. DBGPRINT(RECEIVE, DBG,
  968. ("SpxRecvBufferPkt: %lx Len %lx DataPts %lx F %lx\n",
  969. pSpxConnFile, PacketSize, pData, pRecvResd->rr_State));
  970. CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
  971. // Call ndis transfer data. Copy ENTIRE packet. copySize has
  972. // been modified so use original values.
  973. ndisStatus = NDIS_STATUS_SUCCESS;
  974. bytesCopied = 0;
  975. if (PacketSize > 0)
  976. {
  977. (*IpxTransferData)(
  978. &ndisStatus,
  979. MacBindingHandle,
  980. MacReceiveContext,
  981. LookaheadOffset,
  982. PacketSize,
  983. pNdisPkt,
  984. &bytesCopied);
  985. }
  986. if (ndisStatus != STATUS_PENDING)
  987. {
  988. SpxTransferDataComplete(
  989. pNdisPkt,
  990. ndisStatus,
  991. bytesCopied);
  992. }
  993. // BUG: FDDI returns pending which messes us up here.
  994. ndisStatus = NDIS_STATUS_SUCCESS;
  995. }
  996. }
  997. // ASSERT: Lock will be freed in the success case.
  998. if (ndisStatus != NDIS_STATUS_SUCCESS)
  999. {
  1000. DBGPRINT(RECEIVE, ERR,
  1001. ("SpxRecvBufferPkt: FAILED!\n"));
  1002. END_PROCESS_PACKET(pSpxConnFile, FALSE, FALSE);
  1003. CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
  1004. if (pData != NULL)
  1005. {
  1006. SpxFreeMemory(pData);
  1007. }
  1008. if (pNdisBuffer != NULL)
  1009. {
  1010. NdisFreeBuffer(pNdisBuffer);
  1011. }
  1012. }
  1013. return;
  1014. }
  1015. VOID
  1016. SpxRecvDataPacket(
  1017. IN NDIS_HANDLE MacBindingHandle,
  1018. IN NDIS_HANDLE MacReceiveContext,
  1019. IN PIPX_LOCAL_TARGET RemoteAddress,
  1020. IN ULONG MacOptions,
  1021. IN PUCHAR LookaheadBuffer,
  1022. IN UINT LookaheadSize,
  1023. IN UINT LookaheadOffset,
  1024. IN UINT PacketSize
  1025. )
  1026. /*++
  1027. Routine Description:
  1028. This is called to indicate an incoming connection.
  1029. Arguments:
  1030. Return Value:
  1031. --*/
  1032. {
  1033. NTSTATUS status;
  1034. PIPXSPX_HDR pIpxSpxHdr;
  1035. USHORT srcConnId, destConnId,
  1036. pktLen, seqNum, ackNum, allocNum;
  1037. ULONG receiveFlags;
  1038. PSPX_CONN_FILE pSpxConnFile;
  1039. PTDI_IND_RECEIVE pRecvHandler;
  1040. PVOID pRecvCtx;
  1041. PIRP pRecvIrp;
  1042. ULONG bytesTaken, iOffset, copySize, bytesCopied;
  1043. CTELockHandle lockHandle;
  1044. PNDIS_PACKET pNdisPkt;
  1045. PNDIS_BUFFER pNdisBuffer;
  1046. PSPX_RECV_RESD pRecvResd;
  1047. NDIS_STATUS ndisStatus;
  1048. PREQUEST pRequest = NULL;
  1049. BOOLEAN fEom,
  1050. fImmedAck = FALSE, fLockHeld = FALSE, fPktDone = FALSE;
  1051. pIpxSpxHdr = (PIPXSPX_HDR)LookaheadBuffer;
  1052. // check minimum length
  1053. if (PacketSize < MIN_IPXSPX_HDRSIZE)
  1054. {
  1055. return;
  1056. }
  1057. // Convert hdr to host format as needed.
  1058. GETSHORT2SHORT(&pktLen, &pIpxSpxHdr->hdr_PktLen);
  1059. GETSHORT2SHORT(&destConnId, &pIpxSpxHdr->hdr_DestConnId);
  1060. GETSHORT2SHORT(&seqNum, &pIpxSpxHdr->hdr_SeqNum);
  1061. GETSHORT2SHORT(&allocNum, &pIpxSpxHdr->hdr_AllocNum);
  1062. GETSHORT2SHORT(&ackNum, &pIpxSpxHdr->hdr_AckNum);
  1063. if ((pktLen < MIN_IPXSPX_HDRSIZE) ||
  1064. (pktLen > PacketSize) ||
  1065. (pIpxSpxHdr->hdr_PktType != SPX_PKT_TYPE))
  1066. {
  1067. DBGPRINT(RECEIVE, ERR,
  1068. ("SpxConnDataPacket: Packet Size %lx.%lx\n",
  1069. pktLen, PacketSize));
  1070. return;
  1071. }
  1072. // We keep and use the remote id in the net format.
  1073. srcConnId = *(USHORT UNALIGNED *)&pIpxSpxHdr->hdr_SrcConnId;
  1074. if ((srcConnId == 0) || (srcConnId == 0xFFFF) || (destConnId == 0))
  1075. {
  1076. DBGPRINT(RECEIVE, ERR,
  1077. ("SpxConnDataPacket: Incorrect conn id %lx.%lx\n",
  1078. srcConnId, destConnId));
  1079. return;
  1080. }
  1081. DBGPRINT(CONNECT, DBG,
  1082. ("SpxConnDataPacket: packet received dest %lx src %lx seq %lx\n",
  1083. pIpxSpxHdr->hdr_DestSkt, pIpxSpxHdr->hdr_SrcSkt, seqNum));
  1084. if ((pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_SPX2) &&
  1085. (pktLen < MIN_IPXSPX2_HDRSIZE))
  1086. {
  1087. return;
  1088. }
  1089. // Find the connection this is destined for and reference it.
  1090. SpxConnFileReferenceById(destConnId, &pSpxConnFile, &status);
  1091. if (!NT_SUCCESS(status))
  1092. {
  1093. DBGPRINT(RECEIVE, WARN,
  1094. ("SpxConnDataPacket: Id %lx NOT FOUND", destConnId));
  1095. return;
  1096. }
  1097. CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
  1098. #if 0
  1099. //
  1100. // We have the connection. We should update the dest. sock # in
  1101. // it in case it changed. Unix machines do do that sometimes.
  1102. // SCO bug 7676
  1103. //
  1104. SpxCopyIpxAddr(pIpxSpxHdr, pSpxConnFile->scf_RemAddr);
  1105. #endif
  1106. fLockHeld = TRUE;
  1107. do
  1108. {
  1109. DBGPRINT(RECEIVE, INFO,
  1110. ("SpxConnDataPacket: Id %lx Conn %lx\n",
  1111. destConnId, pSpxConnFile));
  1112. // Restart watchdog timer if started.
  1113. if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER))
  1114. {
  1115. // This will either successfully restart or not affect the timer
  1116. // if it is currently running.
  1117. SpxTimerCancelEvent(
  1118. pSpxConnFile->scf_WTimerId,
  1119. TRUE);
  1120. pSpxConnFile->scf_WRetryCount = PARAM(CONFIG_KEEPALIVE_COUNT);
  1121. }
  1122. if (SPX_CONN_ACTIVE(pSpxConnFile))
  1123. {
  1124. // Verify data packet, this checks if seq nums match also.
  1125. if ((pIpxSpxHdr->hdr_SrcConnId != pSpxConnFile->scf_RemConnId) ||
  1126. (destConnId != pSpxConnFile->scf_LocalConnId) ||
  1127. !((pktLen >= MIN_IPXSPX_HDRSIZE) ||
  1128. ((pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_SPX2) &&
  1129. (pktLen >= MIN_IPXSPX2_HDRSIZE))))
  1130. {
  1131. DBGPRINT(CONNECT, DBG,
  1132. ("SpxConnDataPacket: Failed %lx, %lx.%lx\n",
  1133. pSpxConnFile, seqNum, pSpxConnFile->scf_RecvSeqNum));
  1134. break;
  1135. }
  1136. // If it passed above test, but seq number is incorrect, schedule
  1137. // to send an ack.
  1138. if (seqNum != pSpxConnFile->scf_RecvSeqNum)
  1139. {
  1140. USHORT NumToResend;
  1141. DBGPRINT(CONNECT, DBG,
  1142. ("SpxConnDataPacket: Unexpected seq on %lx, %lx.%lx\n",
  1143. pSpxConnFile, seqNum, pSpxConnFile->scf_RecvSeqNum));
  1144. ++SpxDevice->dev_Stat.DataFramesRejected;
  1145. ExInterlockedAddLargeStatistic(
  1146. &SpxDevice->dev_Stat.DataFrameBytesRejected,
  1147. pktLen - (SPX2_CONN(pSpxConnFile) ?
  1148. MIN_IPXSPX2_HDRSIZE : MIN_IPXSPX_HDRSIZE));
  1149. //
  1150. // Bug #16975: Set the remote ack addr for use in SpxConnSendAck()
  1151. //
  1152. SpxCopyIpxAddr(pIpxSpxHdr, pSpxConnFile->scf_RemAckAddr);
  1153. pSpxConnFile->scf_AckLocalTarget = *RemoteAddress;
  1154. // Calculate number to be resent. If we expect sequence 1 and receive
  1155. // 2 for eg., we need to send a nack, else we send an ack.
  1156. if (SPX2_CONN(pSpxConnFile) &&
  1157. UNSIGNED_GREATER_WITH_WRAP(
  1158. seqNum,
  1159. pSpxConnFile->scf_RecvSeqNum) &&
  1160. !UNSIGNED_GREATER_WITH_WRAP(
  1161. seqNum,
  1162. pSpxConnFile->scf_SentAllocNum))
  1163. {
  1164. NumToResend = (USHORT)(seqNum - pSpxConnFile->scf_RecvSeqNum + 1);
  1165. SpxConnSendNack(pSpxConnFile, NumToResend, lockHandle);
  1166. fLockHeld = FALSE;
  1167. }
  1168. else
  1169. {
  1170. SpxConnSendAck(pSpxConnFile, lockHandle);
  1171. fLockHeld = FALSE;
  1172. }
  1173. break;
  1174. }
  1175. // If we have received an orderly release, we accept no more data
  1176. // packets.
  1177. if (SPX_CONN_FLAG(
  1178. pSpxConnFile,
  1179. (SPX_CONNFILE_IND_IDISC |
  1180. SPX_CONNFILE_IND_ODISC))
  1181. ||
  1182. ((pSpxConnFile->scf_RecvListTail != NULL) &&
  1183. ((pSpxConnFile->scf_RecvListTail->rr_State &
  1184. SPX_RECVPKT_DISCMASK) != 0)))
  1185. {
  1186. DBGPRINT(CONNECT, ERR,
  1187. ("SpxConnDataPacket: After ord rel %lx, %lx.%lx\n",
  1188. pSpxConnFile, seqNum, pSpxConnFile->scf_RecvSeqNum));
  1189. break;
  1190. }
  1191. // We are processing a packet OR a receive is about to complete.
  1192. if (!SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_PKT))
  1193. {
  1194. BEGIN_PROCESS_PACKET(pSpxConnFile, seqNum);
  1195. }
  1196. else
  1197. {
  1198. // Already processing a packet. Or a receive is waiting to
  1199. // complete. Get out.
  1200. break;
  1201. }
  1202. // Set ack numbers for connection.
  1203. SPX_SET_ACKNUM(
  1204. pSpxConnFile, ackNum, allocNum);
  1205. SpxConnProcessAck(pSpxConnFile, NULL, lockHandle);
  1206. CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
  1207. iOffset = MIN_IPXSPX2_HDRSIZE;
  1208. if (!SPX2_CONN(pSpxConnFile))
  1209. {
  1210. iOffset = 0;
  1211. if (!SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_IPXHDR))
  1212. {
  1213. iOffset = MIN_IPXSPX_HDRSIZE;
  1214. }
  1215. }
  1216. copySize = pktLen - iOffset;
  1217. fEom = ((SPX_CONN_MSG(pSpxConnFile) &&
  1218. (pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_EOM)) ||
  1219. SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_IPXHDR));
  1220. // Do we attempt to piggyback? If not, fImmedAck is true.
  1221. // For SPX1 we dont piggyback.
  1222. // Bug #18253
  1223. fImmedAck = (!SPX2_CONN(pSpxConnFile) ||
  1224. ((pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_EOM) == 0));
  1225. // If we do not have EOM to indicate AND we are a zero-sized packet
  1226. // then just consume this packet.
  1227. if (!fEom && (copySize == 0))
  1228. {
  1229. DBGPRINT(RECEIVE, ERR,
  1230. ("SpxConnDataPacket: ZERO LENGTH PACKET NO EOM %lx.%lx\n",
  1231. pSpxConnFile, seqNum));
  1232. fPktDone = TRUE;
  1233. break;
  1234. }
  1235. receiveFlags = TDI_RECEIVE_NORMAL;
  1236. receiveFlags |= ((fEom ? TDI_RECEIVE_ENTIRE_MESSAGE : 0) |
  1237. (((MacOptions &
  1238. NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA) != 0) ?
  1239. TDI_RECEIVE_COPY_LOOKAHEAD : 0));
  1240. ++SpxDevice->dev_Stat.DataFramesReceived;
  1241. ExInterlockedAddLargeStatistic(
  1242. &SpxDevice->dev_Stat.DataFrameBytesReceived,
  1243. copySize);
  1244. // Ok, we accept this packet. Depending on our state.
  1245. switch (SPX_RECV_STATE(pSpxConnFile))
  1246. {
  1247. case SPX_RECV_PROCESS_PKTS:
  1248. DBGPRINT(RECEIVE, DBG,
  1249. ("SpxConnDataPacket: recv completions on %lx\n",
  1250. pSpxConnFile));
  1251. goto BufferPacket;
  1252. case SPX_RECV_IDLE:
  1253. // If recv q is non-empty we are buffering data.
  1254. // Also, if no receive handler goto buffer data. Also, if receives
  1255. // are being completed, buffer this packet.
  1256. if ((pSpxConnFile->scf_RecvListHead != NULL) ||
  1257. !(IsListEmpty(&pSpxConnFile->scf_RecvDoneLinkage)) ||
  1258. !(pRecvHandler = pSpxConnFile->scf_AddrFile->saf_RecvHandler))
  1259. {
  1260. DBGPRINT(RECEIVE, DBG,
  1261. ("SpxConnDataPacket: RecvListHead non-null %lx\n",
  1262. pSpxConnFile));
  1263. goto BufferPacket;
  1264. }
  1265. if (!SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_PKT_NOIND))
  1266. {
  1267. pRecvCtx = pSpxConnFile->scf_AddrFile->saf_RecvHandlerCtx;
  1268. // Don't indicate this packet again.
  1269. SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_PKT_NOIND);
  1270. #if DBG
  1271. CTEAssert(pSpxConnFile->scf_CurRecvReq == NULL);
  1272. // Debug code to ensure we dont reindicate data/indicate
  1273. // when previously indicated data waiting with afd.
  1274. //
  1275. // Comment this out for Buf # 10394. we'r hitting this assert
  1276. // even when there was no data loss.
  1277. //
  1278. // CTEAssert(pSpxConnFile->scf_IndBytes == 0);
  1279. CTEAssert(pSpxConnFile->scf_PktSeqNum != seqNum);
  1280. pSpxConnFile->scf_PktSeqNum = seqNum;
  1281. pSpxConnFile->scf_PktFlags = pSpxConnFile->scf_Flags;
  1282. pSpxConnFile->scf_PktFlags2 = pSpxConnFile->scf_Flags2;
  1283. pSpxConnFile->scf_IndBytes = copySize;
  1284. pSpxConnFile->scf_IndLine = __LINE__;
  1285. #endif
  1286. CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
  1287. bytesTaken = 0;
  1288. status = (*pRecvHandler)(
  1289. pRecvCtx,
  1290. pSpxConnFile->scf_ConnCtx,
  1291. receiveFlags,
  1292. LookaheadSize - iOffset,
  1293. copySize,
  1294. &bytesTaken,
  1295. LookaheadBuffer + iOffset,
  1296. &pRecvIrp);
  1297. DBGPRINT(RECEIVE, DBG,
  1298. ("SpxConnDataPacket: IND Flags %lx.%lx ConnID %lx,\
  1299. %lx Ctx %lx SEQ %lx Size %lx . %lx .%lx IND Status %lx\n",
  1300. pIpxSpxHdr->hdr_ConnCtrl,
  1301. receiveFlags,
  1302. destConnId,
  1303. pSpxConnFile,
  1304. pSpxConnFile->scf_ConnCtx,
  1305. seqNum,
  1306. LookaheadSize - iOffset,
  1307. copySize,
  1308. bytesTaken,
  1309. status));
  1310. DBGPRINT(RECEIVE, INFO,
  1311. ("SpxConnDataPacket: %x %x %x %x %x %x %x %x %x %x %x %x\n",
  1312. *(LookaheadBuffer+iOffset),
  1313. *(LookaheadBuffer+iOffset+1),
  1314. *(LookaheadBuffer+iOffset+2),
  1315. *(LookaheadBuffer+iOffset+3),
  1316. *(LookaheadBuffer+iOffset+4),
  1317. *(LookaheadBuffer+iOffset+5),
  1318. *(LookaheadBuffer+iOffset+6),
  1319. *(LookaheadBuffer+iOffset+7),
  1320. *(LookaheadBuffer+iOffset+8),
  1321. *(LookaheadBuffer+iOffset+9),
  1322. *(LookaheadBuffer+iOffset+10),
  1323. *(LookaheadBuffer+iOffset+11)));
  1324. CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
  1325. if (status == STATUS_SUCCESS)
  1326. {
  1327. // Assume all data accepted.
  1328. CTEAssert((bytesTaken != 0) || fEom);
  1329. fPktDone = TRUE;
  1330. #if DBG
  1331. // Set this to 0, since we just indicated, there could
  1332. // not have been other data.
  1333. pSpxConnFile->scf_IndBytes = 0;
  1334. #endif
  1335. break;
  1336. }
  1337. if (status == STATUS_MORE_PROCESSING_REQUIRED)
  1338. {
  1339. // Queue irp into connection, change state to receive
  1340. // posted and fall thru.
  1341. pRequest = SpxAllocateRequest(
  1342. SpxDevice,
  1343. pRecvIrp);
  1344. IF_NOT_ALLOCATED(pRequest)
  1345. {
  1346. pRecvIrp->IoStatus.Status =
  1347. STATUS_INSUFFICIENT_RESOURCES;
  1348. IoCompleteRequest (pRecvIrp, IO_NETWORK_INCREMENT);
  1349. break;
  1350. }
  1351. // If there was indicated but not received data waiting
  1352. // (which in this path there will never be, the request
  1353. // could be completed given the data filled it up, and
  1354. // the lock released.
  1355. SpxConnQueueRecv(
  1356. pSpxConnFile,
  1357. pRequest);
  1358. CTEAssert(pRequest == pSpxConnFile->scf_CurRecvReq);
  1359. }
  1360. else if (IsListEmpty(&pSpxConnFile->scf_RecvLinkage))
  1361. {
  1362. // Data was not accepted. Need to buffer data and
  1363. // reduce window.
  1364. goto BufferPacket;
  1365. }
  1366. // Fall through to recv_posted.
  1367. }
  1368. else
  1369. {
  1370. DBGPRINT(RECEIVE, WARN,
  1371. ("SpxConnDataPacket: !!!Ignoring %lx Seq %lx\n",
  1372. pSpxConnFile,
  1373. seqNum));
  1374. break;
  1375. }
  1376. case SPX_RECV_POSTED:
  1377. if (pSpxConnFile->scf_RecvListHead != NULL)
  1378. {
  1379. // This can happen also. Buffer packet if it does.
  1380. goto BufferPacket;
  1381. }
  1382. // If a receive irp is posted, then process the receive irp. If
  1383. // we fell thru we MAY already will have an irp.
  1384. if (pRequest == NULL)
  1385. {
  1386. CTEAssert(!IsListEmpty(&pSpxConnFile->scf_RecvLinkage));
  1387. CTEAssert(pSpxConnFile->scf_CurRecvReq != NULL);
  1388. pRequest = pSpxConnFile->scf_CurRecvReq;
  1389. }
  1390. // Process receive. Here we do not need to worry about
  1391. // indicated yet not received data. We just deal with
  1392. // servicing the current packet.
  1393. CTEAssert(pRequest == pSpxConnFile->scf_CurRecvReq);
  1394. if ((LookaheadSize == PacketSize) &&
  1395. (pSpxConnFile->scf_CurRecvSize >= copySize))
  1396. {
  1397. bytesCopied = 0;
  1398. status = STATUS_SUCCESS;
  1399. if (copySize > 0)
  1400. {
  1401. status = TdiCopyBufferToMdl(
  1402. LookaheadBuffer,
  1403. iOffset,
  1404. copySize,
  1405. REQUEST_TDI_BUFFER(pRequest),
  1406. pSpxConnFile->scf_CurRecvOffset,
  1407. &bytesCopied);
  1408. CTEAssert(NT_SUCCESS(status));
  1409. if (!NT_SUCCESS(status))
  1410. {
  1411. // Abort request with this status. Reset request
  1412. // queue to next request if one is available.
  1413. }
  1414. DBGPRINT(RECEIVE, DBG,
  1415. ("BytesCopied %lx CopySize %lx, Recv Size %lx.%lx\n",
  1416. bytesCopied, copySize,
  1417. pSpxConnFile->scf_CurRecvSize,
  1418. pSpxConnFile->scf_CurRecvOffset));
  1419. }
  1420. // Update current request values and see if this request
  1421. // is to be completed. Either zero or fEom.
  1422. pSpxConnFile->scf_CurRecvOffset += bytesCopied;
  1423. pSpxConnFile->scf_CurRecvSize -= bytesCopied;
  1424. #if DBG
  1425. // Decrement indicated data count
  1426. if (SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_PKT_NOIND))
  1427. {
  1428. if (bytesCopied != 0)
  1429. {
  1430. CTEAssert (pSpxConnFile->scf_IndBytes != 0);
  1431. pSpxConnFile->scf_IndBytes -= bytesCopied;
  1432. }
  1433. }
  1434. #endif
  1435. if (SPX_CONN_STREAM(pSpxConnFile) ||
  1436. (pSpxConnFile->scf_CurRecvSize == 0) ||
  1437. fEom)
  1438. {
  1439. CTELockHandle lockHandleInter;
  1440. // Set status
  1441. REQUEST_STATUS(pRequest) = STATUS_SUCCESS;
  1442. REQUEST_INFORMATION(pRequest)=
  1443. pSpxConnFile->scf_CurRecvOffset;
  1444. if (!SPX_CONN_STREAM(pSpxConnFile) &&
  1445. (pSpxConnFile->scf_CurRecvSize == 0) &&
  1446. !fEom)
  1447. {
  1448. REQUEST_STATUS(pRequest) = STATUS_RECEIVE_PARTIAL;
  1449. }
  1450. DBGPRINT(RECEIVE, DBG,
  1451. ("spxConnData: Completing recv %lx with %lx.%lx\n",
  1452. pRequest, REQUEST_STATUS(pRequest),
  1453. REQUEST_INFORMATION(pRequest)));
  1454. // Dequeue this request, Set next recv if one exists.
  1455. SPX_CONN_SETNEXT_CUR_RECV(pSpxConnFile, pRequest);
  1456. // Request is done. Move to completion list.
  1457. CTEGetLock(&SpxGlobalQInterlock, &lockHandleInter);
  1458. InsertTailList(
  1459. &pSpxConnFile->scf_RecvDoneLinkage,
  1460. REQUEST_LINKAGE(pRequest));
  1461. SPX_QUEUE_FOR_RECV_COMPLETION(pSpxConnFile);
  1462. CTEFreeLock(&SpxGlobalQInterlock, lockHandleInter);
  1463. }
  1464. fPktDone = TRUE;
  1465. }
  1466. else
  1467. {
  1468. // Need to allocate a ndis receive packet for transfer
  1469. // data.
  1470. DBGPRINT(RECEIVE, DBG,
  1471. ("SpxConnDataPacket: %lx.%lx Tranfer data needed!\n",
  1472. copySize, pSpxConnFile->scf_CurRecvSize));
  1473. if (copySize > pSpxConnFile->scf_CurRecvSize)
  1474. {
  1475. // Partial receive. Buffer and then deal with it.
  1476. goto BufferPacket;
  1477. }
  1478. // Allocate a ndis receive packet.
  1479. SpxAllocRecvPacket(SpxDevice, &pNdisPkt, &ndisStatus);
  1480. if (ndisStatus != NDIS_STATUS_SUCCESS)
  1481. {
  1482. break;
  1483. }
  1484. // Describe the receive irp's data with a ndis buffer
  1485. // descriptor.
  1486. if (copySize > 0)
  1487. {
  1488. SpxCopyBufferChain(
  1489. &ndisStatus,
  1490. &pNdisBuffer,
  1491. SpxDevice->dev_NdisBufferPoolHandle,
  1492. REQUEST_TDI_BUFFER(pRequest),
  1493. pSpxConnFile->scf_CurRecvOffset,
  1494. copySize);
  1495. if (ndisStatus != NDIS_STATUS_SUCCESS)
  1496. {
  1497. // Free the recv packet
  1498. SpxPktRecvRelease(pNdisPkt);
  1499. break;
  1500. }
  1501. // Queue the buffer into the packet
  1502. // Link the buffer descriptor into the packet descriptor
  1503. NdisChainBufferAtBack(
  1504. pNdisPkt,
  1505. pNdisBuffer);
  1506. }
  1507. // Don't care about whether this is indicated or not here
  1508. // as it is not a buffering packet.
  1509. pRecvResd = RECV_RESD(pNdisPkt);
  1510. pRecvResd->rr_Id = IDENTIFIER_SPX;
  1511. pRecvResd->rr_State =
  1512. ((fEom ? SPX_RECVPKT_EOM : 0) |
  1513. (SPX_CONN_FLAG2(
  1514. pSpxConnFile, SPX_CONNFILE2_PKT_NOIND) ? SPX_RECVPKT_INDICATED : 0) |
  1515. (fImmedAck ? SPX_RECVPKT_IMMEDACK : 0) |
  1516. ((pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_ACK) ?
  1517. SPX_RECVPKT_SENDACK : 0));
  1518. if (pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_ACK)
  1519. {
  1520. // copy the remote address in connection.
  1521. SpxCopyIpxAddr(pIpxSpxHdr, pSpxConnFile->scf_RemAckAddr);
  1522. pSpxConnFile->scf_AckLocalTarget = *RemoteAddress;
  1523. }
  1524. pRecvResd->rr_Request = pRequest;
  1525. pRecvResd->rr_ConnFile = pSpxConnFile;
  1526. // reference receive request
  1527. REQUEST_INFORMATION(pRequest)++;
  1528. CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
  1529. fLockHeld = FALSE;
  1530. // Call ndis transfer data.
  1531. ndisStatus = NDIS_STATUS_SUCCESS;
  1532. bytesCopied = 0;
  1533. if (copySize > 0)
  1534. {
  1535. (*IpxTransferData)(
  1536. &ndisStatus,
  1537. MacBindingHandle,
  1538. MacReceiveContext,
  1539. iOffset + LookaheadOffset,
  1540. copySize,
  1541. pNdisPkt,
  1542. &bytesCopied);
  1543. }
  1544. if (ndisStatus != STATUS_PENDING)
  1545. {
  1546. SpxTransferDataComplete(
  1547. pNdisPkt,
  1548. ndisStatus,
  1549. bytesCopied);
  1550. }
  1551. }
  1552. break;
  1553. default:
  1554. KeBugCheck(0);
  1555. break;
  1556. }
  1557. break;
  1558. BufferPacket:
  1559. SpxRecvBufferPkt(
  1560. pSpxConnFile,
  1561. MacBindingHandle,
  1562. MacReceiveContext,
  1563. iOffset + LookaheadOffset,
  1564. pIpxSpxHdr,
  1565. copySize,
  1566. RemoteAddress,
  1567. lockHandle);
  1568. fLockHeld = FALSE;
  1569. }
  1570. } while (FALSE);
  1571. // Here we process a received ack.
  1572. if (!fLockHeld)
  1573. {
  1574. CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
  1575. fLockHeld = TRUE;
  1576. }
  1577. // Send an ack if one was asked for. And we are done with this packet.
  1578. if (fPktDone)
  1579. {
  1580. END_PROCESS_PACKET(pSpxConnFile, FALSE, TRUE);
  1581. }
  1582. if ((pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_ACK) && fPktDone)
  1583. {
  1584. if (!fLockHeld)
  1585. {
  1586. CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
  1587. fLockHeld = TRUE;
  1588. }
  1589. // First copy the remote address in connection.
  1590. SpxCopyIpxAddr(pIpxSpxHdr, pSpxConnFile->scf_RemAckAddr);
  1591. pSpxConnFile->scf_AckLocalTarget = *RemoteAddress;
  1592. // #17564
  1593. if (fImmedAck ||
  1594. SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_NOACKWAIT) ||
  1595. SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_IMMED_ACK))
  1596. {
  1597. SpxConnSendAck(pSpxConnFile, lockHandle);
  1598. fLockHeld = FALSE;
  1599. }
  1600. else
  1601. {
  1602. SpxConnQWaitAck(pSpxConnFile);
  1603. }
  1604. }
  1605. if (fLockHeld)
  1606. {
  1607. CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
  1608. }
  1609. // Deref the connection
  1610. SpxConnFileDereference(pSpxConnFile, CFREF_BYID);
  1611. return;
  1612. }
  1613. VOID
  1614. SpxRecvFlushBytes(
  1615. IN PSPX_CONN_FILE pSpxConnFile,
  1616. IN ULONG BytesToFlush,
  1617. IN CTELockHandle LockHandleConn
  1618. )
  1619. /*++
  1620. Routine Description:
  1621. Arguments:
  1622. pSpxConnFile - Pointer to a transport address file object.
  1623. Return Value:
  1624. --*/
  1625. {
  1626. PNDIS_PACKET pNdisPkt;
  1627. PNDIS_BUFFER pNdisBuffer;
  1628. PSPX_RECV_RESD pRecvResd;
  1629. PBYTE pData;
  1630. ULONG dataLen, copyLen;
  1631. BOOLEAN fLockHeld = TRUE, fWdwOpen = FALSE;
  1632. USHORT discState = 0;
  1633. int numPkts = 0, numDerefs = 0;
  1634. DBGPRINT(RECEIVE, DBG,
  1635. ("SpxRecvFlushBytes: %lx Flush %lx\n",
  1636. pSpxConnFile, BytesToFlush));
  1637. while (((pRecvResd = pSpxConnFile->scf_RecvListHead) != NULL) &&
  1638. ((BytesToFlush > 0) ||
  1639. ((pRecvResd->rr_State & SPX_RECVPKT_INDICATED) != 0)))
  1640. {
  1641. // A buffering recv packet will have ATMOST one ndis buffer descriptor
  1642. // queued in, which will describe a segment of memory we have
  1643. // allocated. An offset will also be present indicating the data
  1644. // to start reading from (or to indicate from to AFD).
  1645. CTEAssert((pRecvResd->rr_State & SPX_RECVPKT_BUFFERING) != 0);
  1646. pNdisPkt = (PNDIS_PACKET)CONTAINING_RECORD(
  1647. pRecvResd, NDIS_PACKET, ProtocolReserved);
  1648. NdisQueryPacket(pNdisPkt, NULL, NULL, &pNdisBuffer, NULL);
  1649. // Initialize pData
  1650. pData = NULL;
  1651. dataLen = 0;
  1652. if (pNdisBuffer != NULL)
  1653. {
  1654. NdisQueryBuffer(pNdisBuffer, &pData, &dataLen);
  1655. CTEAssert(pData != NULL);
  1656. CTEAssert((LONG)dataLen >= 0);
  1657. }
  1658. if ((BytesToFlush == 0) && (dataLen != 0))
  1659. {
  1660. // Don't flush this packet.
  1661. break;
  1662. }
  1663. // Allow for zero data, eom only packets.
  1664. copyLen = MIN((dataLen - pRecvResd->rr_DataOffset), BytesToFlush);
  1665. DBGPRINT(RECEIVE, DBG,
  1666. ("SpxRecvFlushBytes: %lx Pkt %lx DataLen %lx Copy %lx Flush %lx\n",
  1667. pSpxConnFile, pNdisPkt, dataLen, copyLen, BytesToFlush));
  1668. // Adjust various values to see whats done whats not
  1669. pRecvResd->rr_DataOffset += (USHORT)copyLen;
  1670. BytesToFlush -= (ULONG)copyLen;
  1671. #if DBG
  1672. if (copyLen != 0)
  1673. {
  1674. CTEAssert (pSpxConnFile->scf_IndBytes != 0);
  1675. pSpxConnFile->scf_IndBytes -= copyLen;
  1676. }
  1677. #endif
  1678. if (pRecvResd->rr_DataOffset == dataLen)
  1679. {
  1680. // Packet consumed. Free it up. Check if disc happened.
  1681. discState = (pRecvResd->rr_State & SPX_RECVPKT_DISCMASK);
  1682. CTEAssert((discState == 0) ||
  1683. (pRecvResd == pSpxConnFile->scf_RecvListTail));
  1684. numDerefs++;
  1685. SpxConnDequeueRecvPktLock(pSpxConnFile, pNdisPkt);
  1686. if (pNdisBuffer != NULL)
  1687. {
  1688. NdisUnchainBufferAtFront(pNdisPkt, &pNdisBuffer);
  1689. CTEAssert(pNdisBuffer != NULL);
  1690. NdisFreeBuffer(pNdisBuffer);
  1691. SpxFreeMemory(pData);
  1692. }
  1693. SpxPktRecvRelease(pNdisPkt);
  1694. DBGPRINT(RECEIVE, DBG,
  1695. ("SpxRecvFlushBytes: !!!ALL INDICATED on %lx.%lx.%lx.%lx\n",
  1696. pSpxConnFile, pNdisPkt, pNdisBuffer, pData));
  1697. INCREMENT_WINDOW(pSpxConnFile);
  1698. fWdwOpen = TRUE;
  1699. }
  1700. else
  1701. {
  1702. // Took only part of this packet. Get out.
  1703. break;
  1704. }
  1705. }
  1706. if (fWdwOpen && (pSpxConnFile->scf_RecvListHead == NULL))
  1707. {
  1708. // Send an ack as our windows probably opened up. Dont wait to
  1709. // piggyback here...
  1710. DBGPRINT(RECEIVE, DBG,
  1711. ("spxRecvFlushBytes: Send ACK %lx\n",
  1712. pSpxConnFile));
  1713. #if DBG_WDW_CLOSE
  1714. // If packets been indicated we have started buffering. Also
  1715. // check if window is now zero.
  1716. {
  1717. LARGE_INTEGER li, ntTime;
  1718. int value;
  1719. li = pSpxConnFile->scf_WdwCloseTime;
  1720. if (li.LowPart && li.HighPart)
  1721. {
  1722. KeQuerySystemTime(&ntTime);
  1723. // Get the difference
  1724. ntTime.QuadPart = ntTime.QuadPart - li.QuadPart;
  1725. // Convert to milliseconds. If the highpart is 0, we
  1726. // take a shortcut.
  1727. if (ntTime.HighPart == 0)
  1728. {
  1729. value = ntTime.LowPart/10000;
  1730. }
  1731. else
  1732. {
  1733. ntTime = SPX_CONVERT100NSTOCENTISEC(ntTime);
  1734. value = ntTime.LowPart << 4;
  1735. }
  1736. // Set new average close time
  1737. pSpxConnFile->scf_WdwCloseAve += value;
  1738. pSpxConnFile->scf_WdwCloseAve /= 2;
  1739. DBGPRINT(RECEIVE, DBG,
  1740. ("V %ld AVE %ld\n",
  1741. value, pSpxConnFile->scf_WdwCloseAve));
  1742. }
  1743. }
  1744. #endif
  1745. SpxConnSendAck(pSpxConnFile, LockHandleConn);
  1746. CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
  1747. }
  1748. // Check if disconnect happened
  1749. switch (discState)
  1750. {
  1751. case SPX_RECVPKT_IDISC:
  1752. CTEAssert(pSpxConnFile->scf_RecvListHead == NULL);
  1753. DBGPRINT(RECEIVE, ERR,
  1754. ("spxRecvFlushBytes: Buffered IDISC %lx\n",
  1755. pSpxConnFile));
  1756. SpxConnProcessIDisc(pSpxConnFile, LockHandleConn);
  1757. fLockHeld = FALSE;
  1758. break;
  1759. case SPX_RECVPKT_ORD_DISC:
  1760. CTEAssert(pSpxConnFile->scf_RecvListHead == NULL);
  1761. DBGPRINT(RECEIVE, ERR,
  1762. ("spxRecvFlushBytes: Buffered ORDREL %lx\n",
  1763. pSpxConnFile));
  1764. SpxConnProcessOrdRel(pSpxConnFile, LockHandleConn);
  1765. fLockHeld = FALSE;
  1766. break;
  1767. case (SPX_RECVPKT_IDISC | SPX_RECVPKT_ORD_DISC):
  1768. // IDISC has more priority.
  1769. CTEAssert(pSpxConnFile->scf_RecvListHead == NULL);
  1770. DBGPRINT(RECEIVE, ERR,
  1771. ("spxRecvFlushBytes: Buffered IDISC *AND* ORDREL %lx\n",
  1772. pSpxConnFile));
  1773. SpxConnProcessIDisc(pSpxConnFile, LockHandleConn);
  1774. fLockHeld = FALSE;
  1775. break;
  1776. default:
  1777. break;
  1778. }
  1779. if (fLockHeld)
  1780. {
  1781. CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
  1782. }
  1783. while (numDerefs-- > 0)
  1784. {
  1785. SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
  1786. }
  1787. return;
  1788. }
  1789. BOOLEAN
  1790. SpxRecvIndicatePendingData(
  1791. IN PSPX_CONN_FILE pSpxConnFile,
  1792. IN CTELockHandle LockHandleConn
  1793. )
  1794. /*++
  1795. Routine Description:
  1796. Arguments:
  1797. pSpxConnFile - Pointer to a transport address file object.
  1798. Return Value:
  1799. BOOLEAN - Receive was queued => TRUE
  1800. --*/
  1801. {
  1802. ULONG indicateFlags;
  1803. PNDIS_PACKET pNdisPkt;
  1804. PNDIS_BUFFER pNdisBuffer;
  1805. PREQUEST pRequest;
  1806. PIRP pRecvIrp;
  1807. ULONG bytesTaken, totalSize, bufSize;
  1808. PTDI_IND_RECEIVE pRecvHandler;
  1809. PVOID pRecvCtx;
  1810. PSPX_RECV_RESD pRecvResd;
  1811. NTSTATUS status;
  1812. PBYTE lookaheadData;
  1813. ULONG lookaheadSize;
  1814. BOOLEAN fLockHeld = TRUE, fRecvQueued = FALSE;
  1815. while ((pRecvHandler = pSpxConnFile->scf_AddrFile->saf_RecvHandler) &&
  1816. ((pRecvResd = pSpxConnFile->scf_RecvListHead) != NULL) &&
  1817. (IsListEmpty(&pSpxConnFile->scf_RecvDoneLinkage)) &&
  1818. ((pRecvResd->rr_State & SPX_RECVPKT_BUFFERING) != 0) &&
  1819. ((pRecvResd->rr_State & SPX_RECVPKT_INDICATED) == 0))
  1820. {
  1821. // Once a receive is queued we better get out.
  1822. CTEAssert(!fRecvQueued);
  1823. // Initialize lookahead values
  1824. lookaheadData = NULL;
  1825. lookaheadSize = 0;
  1826. // We have no indicated but pending data, and there is some data to
  1827. // indicate. Figure out how much. Indicate upto end of message or as
  1828. // much as we have.
  1829. // A buffering recv packet will have ATMOST one ndis buffer descriptor
  1830. // queued in, which will describe a segment of memory we have
  1831. // allocated. An offset will also be present indicating the data
  1832. // to start reading from (or to indicate from to AFD).
  1833. CTEAssert((pRecvResd->rr_State & SPX_RECVPKT_BUFFERING) != 0);
  1834. pNdisPkt = (PNDIS_PACKET)CONTAINING_RECORD(
  1835. pRecvResd, NDIS_PACKET, ProtocolReserved);
  1836. NdisQueryPacket(pNdisPkt, NULL, NULL, &pNdisBuffer, NULL);
  1837. if (pNdisBuffer != NULL)
  1838. {
  1839. NdisQueryBuffer(pNdisBuffer, &lookaheadData, &lookaheadSize);
  1840. CTEAssert(lookaheadData != NULL);
  1841. CTEAssert((LONG)lookaheadSize >= 0);
  1842. }
  1843. // Allow for zero data, eom only packets.
  1844. lookaheadSize -= pRecvResd->rr_DataOffset;
  1845. totalSize = lookaheadSize;
  1846. lookaheadData += pRecvResd->rr_DataOffset;
  1847. // If this packet contained data then eom must also have been
  1848. // indicated at the time all the data was consumed.
  1849. CTEAssert((lookaheadSize > 0) ||
  1850. ((pRecvResd->rr_DataOffset == 0) &&
  1851. ((pRecvResd->rr_State & SPX_RECVPKT_EOM) != 0)));
  1852. #if DBG
  1853. CTEAssert (pSpxConnFile->scf_CurRecvReq == NULL);
  1854. // Debug code to ensure we dont reindicate data/indicate
  1855. // when previously indicated data waiting with afd.
  1856. CTEAssert(pSpxConnFile->scf_IndBytes == 0);
  1857. CTEAssert(pSpxConnFile->scf_PktSeqNum != pRecvResd->rr_SeqNum);
  1858. pSpxConnFile->scf_PktSeqNum = pRecvResd->rr_SeqNum;
  1859. pSpxConnFile->scf_PktFlags = pSpxConnFile->scf_Flags;
  1860. pSpxConnFile->scf_PktFlags2 = pSpxConnFile->scf_Flags2;
  1861. #endif
  1862. pRecvResd->rr_State |= SPX_RECVPKT_INDICATED;
  1863. // Go ahead and walk the list of waiting packets. Get total size.
  1864. while ((pRecvResd->rr_Next != NULL) &&
  1865. ((pRecvResd->rr_State & SPX_RECVPKT_EOM) == 0))
  1866. {
  1867. // Check next packet.
  1868. pRecvResd = pRecvResd->rr_Next;
  1869. #if DBG
  1870. CTEAssert(pSpxConnFile->scf_PktSeqNum != pRecvResd->rr_SeqNum);
  1871. pSpxConnFile->scf_PktSeqNum = pRecvResd->rr_SeqNum;
  1872. pSpxConnFile->scf_PktFlags = pSpxConnFile->scf_Flags;
  1873. pSpxConnFile->scf_PktFlags2 = pSpxConnFile->scf_Flags2;
  1874. #endif
  1875. pRecvResd->rr_State |= SPX_RECVPKT_INDICATED;
  1876. pNdisPkt = (PNDIS_PACKET)CONTAINING_RECORD(
  1877. pRecvResd, NDIS_PACKET, ProtocolReserved);
  1878. NdisQueryPacket(pNdisPkt, NULL, NULL, NULL, &bufSize);
  1879. CTEAssert((LONG)bufSize >= 0);
  1880. // Allow for zero data, eom only packets.
  1881. totalSize += bufSize;
  1882. }
  1883. #if DBG
  1884. pSpxConnFile->scf_IndBytes = totalSize;
  1885. pSpxConnFile->scf_IndLine = __LINE__;
  1886. // There better not be any pending receives. If so, we have data
  1887. // corruption about to happen.
  1888. if (!IsListEmpty(&pSpxConnFile->scf_RecvDoneLinkage))
  1889. {
  1890. DBGBRK(FATAL);
  1891. KeBugCheck(0);
  1892. }
  1893. #endif
  1894. indicateFlags = TDI_RECEIVE_NORMAL | TDI_RECEIVE_COPY_LOOKAHEAD;
  1895. if ((pRecvResd->rr_State & SPX_RECVPKT_EOM) != 0)
  1896. {
  1897. indicateFlags |= TDI_RECEIVE_ENTIRE_MESSAGE;
  1898. }
  1899. pRecvCtx = pSpxConnFile->scf_AddrFile->saf_RecvHandlerCtx;
  1900. CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
  1901. bytesTaken = 0;
  1902. status = (*pRecvHandler)(
  1903. pRecvCtx,
  1904. pSpxConnFile->scf_ConnCtx,
  1905. indicateFlags,
  1906. lookaheadSize,
  1907. totalSize,
  1908. &bytesTaken,
  1909. lookaheadData,
  1910. &pRecvIrp);
  1911. DBGPRINT(RECEIVE, DBG,
  1912. ("SpxConnIndicatePendingData: IND Flags %lx Size %lx .%lx IND Status %lx\n",
  1913. indicateFlags,
  1914. totalSize,
  1915. bytesTaken,
  1916. status));
  1917. CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
  1918. if (status == STATUS_SUCCESS)
  1919. {
  1920. // Assume all data accepted. Free bytesTaken worth of data packets.
  1921. // Sometimes AFD returns STATUS_SUCCESS to just flush the data, so
  1922. // we can't assume it took only one packet (since lookahead only
  1923. // had that information).
  1924. CTEAssert(bytesTaken == totalSize);
  1925. SpxRecvFlushBytes(pSpxConnFile, totalSize, LockHandleConn);
  1926. CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
  1927. continue;
  1928. }
  1929. else if (status == STATUS_MORE_PROCESSING_REQUIRED)
  1930. {
  1931. // Queue irp into connection, change state to receive
  1932. // posted and fall thru.
  1933. pRequest = SpxAllocateRequest(
  1934. SpxDevice,
  1935. pRecvIrp);
  1936. IF_NOT_ALLOCATED(pRequest)
  1937. {
  1938. pRecvIrp->IoStatus.Status =
  1939. STATUS_INSUFFICIENT_RESOURCES;
  1940. IoCompleteRequest (pRecvIrp, IO_NETWORK_INCREMENT);
  1941. return (FALSE);
  1942. }
  1943. SpxConnQueueRecv(
  1944. pSpxConnFile,
  1945. pRequest);
  1946. fRecvQueued = TRUE;
  1947. }
  1948. break;
  1949. }
  1950. if (fLockHeld)
  1951. {
  1952. CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
  1953. }
  1954. return fRecvQueued;
  1955. }
  1956. VOID
  1957. SpxRecvProcessPkts(
  1958. IN PSPX_CONN_FILE pSpxConnFile,
  1959. IN CTELockHandle LockHandleConn
  1960. )
  1961. /*++
  1962. Routine Description:
  1963. Handle buffered data, complete irp if necessary. Set state to idle
  1964. if list becomes empty.
  1965. Arguments:
  1966. pSpxConnFile - Pointer to a transport address file object.
  1967. Return Value:
  1968. BOOLEAN: More data left to indicate => TRUE
  1969. --*/
  1970. {
  1971. ULONG remainingDataLen, copyLen, bytesCopied;
  1972. PREQUEST pRequest;
  1973. NTSTATUS status;
  1974. BOOLEAN fEom;
  1975. PNDIS_PACKET pNdisPkt;
  1976. PNDIS_BUFFER pNdisBuffer;
  1977. PSPX_RECV_RESD pRecvResd;
  1978. ULONG dataLen;
  1979. PBYTE pData;
  1980. LIST_ENTRY *p;
  1981. BOOLEAN fLockHeld = TRUE, fMoreData = TRUE, fWdwOpen = FALSE;
  1982. USHORT discState = 0;
  1983. int numDerefs = 0;
  1984. if (SPX_RECV_STATE(pSpxConnFile) != SPX_RECV_PROCESS_PKTS)
  1985. {
  1986. SPX_RECV_SETSTATE(pSpxConnFile, SPX_RECV_PROCESS_PKTS);
  1987. ProcessReceives:
  1988. while ((pSpxConnFile->scf_CurRecvReq != NULL) &&
  1989. ((pRecvResd = pSpxConnFile->scf_RecvListHead) != NULL))
  1990. {
  1991. // A buffering recv packet will have one ndis buffer descriptor
  1992. // queued in, which will describe a segment of memory we have
  1993. // allocated. An offset will also be present indicating the data
  1994. // to start reading from (or to indicate from to AFD).
  1995. CTEAssert((pRecvResd->rr_State & SPX_RECVPKT_BUFFERING) != 0);
  1996. pNdisPkt = (PNDIS_PACKET)CONTAINING_RECORD(
  1997. pRecvResd, NDIS_PACKET, ProtocolReserved);
  1998. NdisQueryPacket(pNdisPkt, NULL, NULL, &pNdisBuffer, NULL);
  1999. // Initialize pData
  2000. pData = NULL;
  2001. dataLen = 0;
  2002. if (pNdisBuffer != NULL)
  2003. {
  2004. NdisQueryBuffer(pNdisBuffer, &pData, &dataLen);
  2005. CTEAssert(pData != NULL);
  2006. CTEAssert((LONG)dataLen >= 0);
  2007. }
  2008. // Allow for zero data, eom only packets.
  2009. remainingDataLen = dataLen - pRecvResd->rr_DataOffset;
  2010. // If this packet contained data then eom must also have been
  2011. // indicated at the time all the data was consumed.
  2012. CTEAssert((remainingDataLen > 0) ||
  2013. ((pRecvResd->rr_DataOffset == 0) &&
  2014. ((pRecvResd->rr_State & SPX_RECVPKT_EOM) != 0)));
  2015. status = STATUS_SUCCESS;
  2016. copyLen = 0;
  2017. if (remainingDataLen > 0)
  2018. {
  2019. copyLen = MIN(remainingDataLen, pSpxConnFile->scf_CurRecvSize);
  2020. status = TdiCopyBufferToMdl(
  2021. pData,
  2022. pRecvResd->rr_DataOffset,
  2023. copyLen,
  2024. REQUEST_TDI_BUFFER(pSpxConnFile->scf_CurRecvReq),
  2025. pSpxConnFile->scf_CurRecvOffset,
  2026. &bytesCopied);
  2027. CTEAssert(NT_SUCCESS(status));
  2028. if (!NT_SUCCESS(status))
  2029. {
  2030. // Abort request with this status. Reset request
  2031. // queue to next request if one is available.
  2032. copyLen = pSpxConnFile->scf_CurRecvSize;
  2033. }
  2034. }
  2035. DBGPRINT(RECEIVE, DBG,
  2036. ("spxConnProcessRecdPkts: %lx Pkt %lx Data %lx Size %lx F %lx\n",
  2037. pSpxConnFile, pNdisPkt, pData, copyLen, pRecvResd->rr_State));
  2038. // Adjust various values to see whats done whats not
  2039. pRecvResd->rr_DataOffset += (USHORT)copyLen;
  2040. pSpxConnFile->scf_CurRecvSize -= (USHORT)copyLen;
  2041. pSpxConnFile->scf_CurRecvOffset += (USHORT)copyLen;
  2042. #if DBG
  2043. // If this packet was part of indicated data count, decrement.
  2044. if ((pRecvResd->rr_State & SPX_RECVPKT_INDICATED) != 0)
  2045. {
  2046. if (copyLen != 0)
  2047. {
  2048. CTEAssert (pSpxConnFile->scf_IndBytes != 0);
  2049. pSpxConnFile->scf_IndBytes -= copyLen;
  2050. }
  2051. }
  2052. #endif
  2053. // Set fEom/discState (init to 0) only if all of packet was consumed.
  2054. fEom = FALSE;
  2055. if (pRecvResd->rr_DataOffset == dataLen)
  2056. {
  2057. fEom = (BOOLEAN)((pRecvResd->rr_State & SPX_RECVPKT_EOM) != 0);
  2058. // Remember if disconnect needed to happen. If set, this better be
  2059. // last packet received. Again, only if entire pkt was consumed.
  2060. discState = (pRecvResd->rr_State & SPX_RECVPKT_DISCMASK);
  2061. CTEAssert((discState == 0) ||
  2062. (pRecvResd == pSpxConnFile->scf_RecvListTail));
  2063. // Packet consumed. Free it up.
  2064. numDerefs++;
  2065. SpxConnDequeueRecvPktLock(pSpxConnFile, pNdisPkt);
  2066. INCREMENT_WINDOW(pSpxConnFile);
  2067. fWdwOpen = TRUE;
  2068. DBGPRINT(RECEIVE, DBG,
  2069. ("spxConnProcessRecdPkts: %lx Pkt %lx Data %lx DEQUEUED\n",
  2070. pSpxConnFile, pNdisPkt, pData));
  2071. if (pNdisBuffer != NULL)
  2072. {
  2073. NdisUnchainBufferAtFront(pNdisPkt, &pNdisBuffer);
  2074. NdisFreeBuffer(pNdisBuffer);
  2075. SpxFreeMemory(pData);
  2076. }
  2077. SpxPktRecvRelease(pNdisPkt);
  2078. }
  2079. else
  2080. {
  2081. DBGPRINT(RECEIVE, DBG,
  2082. ("spxConnProcessRecdPkts: %lx Pkt %lx PARTIAL USE %lx.%lx\n",
  2083. pSpxConnFile, pNdisPkt, pRecvResd->rr_DataOffset, dataLen));
  2084. }
  2085. // Don't complete until we are out of all packets and stream mode or...
  2086. if (((pSpxConnFile->scf_RecvListHead == NULL) &&
  2087. SPX_CONN_STREAM(pSpxConnFile)) ||
  2088. (pSpxConnFile->scf_CurRecvSize == 0) ||
  2089. fEom)
  2090. {
  2091. // Done with receive, move to completion or complete depending on
  2092. // call level.
  2093. pRequest = pSpxConnFile->scf_CurRecvReq;
  2094. // Set status. Complete with error from TdiCopy if so.
  2095. REQUEST_INFORMATION(pRequest) = pSpxConnFile->scf_CurRecvOffset;
  2096. REQUEST_STATUS(pRequest) = status;
  2097. // Ensure we dont overwrite an error status.
  2098. if (!SPX_CONN_STREAM(pSpxConnFile) &&
  2099. (pSpxConnFile->scf_CurRecvSize == 0) &&
  2100. !fEom &&
  2101. NT_SUCCESS(status))
  2102. {
  2103. REQUEST_STATUS(pRequest) = STATUS_RECEIVE_PARTIAL;
  2104. }
  2105. // Dequeue this request, set next recv if one exists.
  2106. SPX_CONN_SETNEXT_CUR_RECV(pSpxConnFile, pRequest);
  2107. DBGPRINT(RECEIVE, DBG,
  2108. ("spxConnProcessRecdPkts: %lx Recv %lx with %lx.%lx\n",
  2109. pSpxConnFile, pRequest, REQUEST_STATUS(pRequest),
  2110. REQUEST_INFORMATION(pRequest)));
  2111. #if DBG
  2112. if ((REQUEST_STATUS(pRequest) == STATUS_SUCCESS) &&
  2113. (REQUEST_INFORMATION(pRequest) == 0))
  2114. {
  2115. DBGPRINT(TDI, DBG,
  2116. ("SpxReceiveComplete: Completing %lx with %lx.%lx\n",
  2117. pRequest, REQUEST_STATUS(pRequest),
  2118. REQUEST_INFORMATION(pRequest)));
  2119. }
  2120. #endif
  2121. // Request is done. Move to receive completion list. There
  2122. // could already be previously queued requests in here.
  2123. InsertTailList(
  2124. &pSpxConnFile->scf_RecvDoneLinkage,
  2125. REQUEST_LINKAGE(pRequest));
  2126. }
  2127. CTEAssert((discState == 0) ||
  2128. (pSpxConnFile->scf_RecvListHead == NULL));
  2129. }
  2130. // Complete any completed receives
  2131. while ((p = pSpxConnFile->scf_RecvDoneLinkage.Flink) !=
  2132. &pSpxConnFile->scf_RecvDoneLinkage)
  2133. {
  2134. pRequest = LIST_ENTRY_TO_REQUEST(p);
  2135. RemoveEntryList(REQUEST_LINKAGE(pRequest));
  2136. CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
  2137. DBGPRINT(TDI, DBG,
  2138. ("SpxConnDiscPkt: PENDING REQ COMP %lx with %lx.%lx\n",
  2139. pRequest, REQUEST_STATUS(pRequest),
  2140. REQUEST_INFORMATION(pRequest)));
  2141. #if DBG
  2142. if ((REQUEST_STATUS(pRequest) == STATUS_SUCCESS) &&
  2143. (REQUEST_INFORMATION(pRequest) == 0))
  2144. {
  2145. DBGPRINT(TDI, DBG,
  2146. ("SpxReceiveComplete: Completing %lx with %lx.%lx\n",
  2147. pRequest, REQUEST_STATUS(pRequest),
  2148. REQUEST_INFORMATION(pRequest)));
  2149. }
  2150. #endif
  2151. SpxCompleteRequest(pRequest);
  2152. numDerefs++;
  2153. CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
  2154. }
  2155. fMoreData = ((pSpxConnFile->scf_RecvListHead != NULL) &&
  2156. ((pSpxConnFile->scf_RecvListHead ->rr_State &
  2157. SPX_RECVPKT_BUFFERING) != 0) &&
  2158. ((pSpxConnFile->scf_RecvListHead->rr_State &
  2159. SPX_RECVPKT_INDICATED) == 0));
  2160. while (fMoreData)
  2161. {
  2162. // Bug #21036
  2163. // If there is a receive waiting to be processed, we better not
  2164. // indicate data before we finish it.
  2165. if (pSpxConnFile->scf_CurRecvReq != NULL)
  2166. goto ProcessReceives;
  2167. // If a receive was queued the goto beginning again.
  2168. if (SpxRecvIndicatePendingData(pSpxConnFile, LockHandleConn))
  2169. {
  2170. CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
  2171. goto ProcessReceives;
  2172. }
  2173. CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
  2174. fMoreData = ((pSpxConnFile->scf_RecvListHead != NULL) &&
  2175. ((pSpxConnFile->scf_RecvListHead ->rr_State &
  2176. SPX_RECVPKT_BUFFERING) != 0) &&
  2177. ((pSpxConnFile->scf_RecvListHead->rr_State &
  2178. SPX_RECVPKT_INDICATED) == 0));
  2179. }
  2180. // Set state
  2181. SPX_RECV_SETSTATE(
  2182. pSpxConnFile,
  2183. (pSpxConnFile->scf_CurRecvReq == NULL) ?
  2184. SPX_RECV_IDLE : SPX_RECV_POSTED);
  2185. }
  2186. #if DBG
  2187. else
  2188. {
  2189. DBGPRINT(RECEIVE, ERR,
  2190. ("spxConnProcessRecdPkts: Already processing pkts %lx\n",
  2191. pSpxConnFile));
  2192. }
  2193. #endif
  2194. if (fWdwOpen && (pSpxConnFile->scf_RecvListHead == NULL))
  2195. {
  2196. // Send an ack as our windows probably opened up. Dont wait to
  2197. // piggyback here...
  2198. DBGPRINT(RECEIVE, DBG,
  2199. ("spxConnProcessRecdPkts: Send ACK %lx\n",
  2200. pSpxConnFile));
  2201. #if DBG_WDW_CLOSE
  2202. // If packets been indicated we have started buffering. Also
  2203. // check if window is now zero.
  2204. {
  2205. LARGE_INTEGER li, ntTime;
  2206. int value;
  2207. li = pSpxConnFile->scf_WdwCloseTime;
  2208. if (li.LowPart && li.HighPart)
  2209. {
  2210. KeQuerySystemTime(&ntTime);
  2211. // Get the difference
  2212. ntTime.QuadPart = ntTime.QuadPart - li.QuadPart;
  2213. // Convert to milliseconds. If the highpart is 0, we
  2214. // take a shortcut.
  2215. if (ntTime.HighPart == 0)
  2216. {
  2217. value = ntTime.LowPart/10000;
  2218. }
  2219. else
  2220. {
  2221. ntTime = SPX_CONVERT100NSTOCENTISEC(ntTime);
  2222. value = ntTime.LowPart << 4;
  2223. }
  2224. // Set new average close time
  2225. pSpxConnFile->scf_WdwCloseAve += value;
  2226. pSpxConnFile->scf_WdwCloseAve /= 2;
  2227. DBGPRINT(RECEIVE, DBG,
  2228. ("V %ld AVE %ld\n",
  2229. value, pSpxConnFile->scf_WdwCloseAve));
  2230. }
  2231. }
  2232. #endif
  2233. SpxConnSendAck(pSpxConnFile, LockHandleConn);
  2234. fLockHeld = FALSE;
  2235. }
  2236. // Check if disconnect happened
  2237. switch (discState)
  2238. {
  2239. case SPX_RECVPKT_IDISC:
  2240. CTEAssert(!fMoreData);
  2241. CTEAssert(pSpxConnFile->scf_RecvListHead == NULL);
  2242. if (!fLockHeld)
  2243. {
  2244. CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
  2245. }
  2246. DBGPRINT(RECEIVE, DBG,
  2247. ("spxConnProcessRecdPkts: Buffered IDISC %lx\n",
  2248. pSpxConnFile, fMoreData));
  2249. SpxConnProcessIDisc(pSpxConnFile, LockHandleConn);
  2250. fLockHeld = FALSE;
  2251. break;
  2252. case SPX_RECVPKT_ORD_DISC:
  2253. CTEAssert(!fMoreData);
  2254. CTEAssert(pSpxConnFile->scf_RecvListHead == NULL);
  2255. if (!fLockHeld)
  2256. {
  2257. CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
  2258. }
  2259. DBGPRINT(RECEIVE, DBG,
  2260. ("spxConnProcessRecdPkts: Buffered ORDREL %lx\n",
  2261. pSpxConnFile, fMoreData));
  2262. SpxConnProcessOrdRel(pSpxConnFile, LockHandleConn);
  2263. fLockHeld = FALSE;
  2264. break;
  2265. case (SPX_RECVPKT_IDISC | SPX_RECVPKT_ORD_DISC):
  2266. // IDISC has more priority.
  2267. CTEAssert(!fMoreData);
  2268. CTEAssert(pSpxConnFile->scf_RecvListHead == NULL);
  2269. if (!fLockHeld)
  2270. {
  2271. CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
  2272. }
  2273. DBGPRINT(RECEIVE, ERR,
  2274. ("spxConnProcessRecdPkts: Buffered IDISC *AND* ORDREL %lx\n",
  2275. pSpxConnFile, fMoreData));
  2276. SpxConnProcessIDisc(pSpxConnFile, LockHandleConn);
  2277. fLockHeld = FALSE;
  2278. break;
  2279. default:
  2280. break;
  2281. }
  2282. if (fLockHeld)
  2283. {
  2284. CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
  2285. }
  2286. while (numDerefs-- > 0)
  2287. {
  2288. SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
  2289. }
  2290. return;
  2291. }