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.

3801 lines
137 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 1998-2002 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: Receive.cpp
  6. * Content: This file contains code which receives indications of incoming data
  7. * from a ServiceProvider, cracks the data, and handles it appropriately.
  8. * History:
  9. * Date By Reason
  10. * ==== == ======
  11. * 11/06/98 ejs Created
  12. * 07/01/2000 masonb Assumed Ownership
  13. *
  14. ****************************************************************************/
  15. #include "dnproti.h"
  16. // local protos
  17. BOOL CancelFrame(PEPD, BYTE, DWORD tNow, PSPRECEIVEDBUFFER* ppRcvBuffToFree);
  18. VOID CompleteSends(PEPD);
  19. VOID DropReceive(PEPD, PRCD, PSPRECEIVEDBUFFER* ppRcvBuffToFree);
  20. HRESULT IndicateReceive(PSPD, PSPIE_DATA);
  21. #ifndef DPNBUILD_NOMULTICAST
  22. HRESULT IndicateReceiveUnknownSender(PSPD, PSPIE_DATA_UNKNOWNSENDER);
  23. #endif // ! DPNBUILD_NOMULTICAST
  24. HRESULT ProcessUnconnectedData(PSPD, PSPIE_DATA_UNCONNECTED);
  25. HRESULT IndicateConnect(PSPD, PSPIE_CONNECT);
  26. HRESULT ProcessEnumQuery( PSPD, PSPIE_QUERY );
  27. HRESULT ProcessQueryResponse( PSPD, PSPIE_QUERYRESPONSE );
  28. VOID ProcessConnectedResponse(PSPD, PEPD, PCFRAME, DWORD);
  29. VOID ProcessConnectedSignedResponse(PSPD, PEPD, CFRAME_CONNECTEDSIGNED * , DWORD);
  30. VOID ProcessConnectRequest(PSPD, PEPD, PCFRAME);
  31. VOID ProcessEndOfStream(PEPD);
  32. VOID ProcessListenStatus(PSPD, PSPIE_LISTENSTATUS);
  33. VOID ProcessConnectAddressInfo(PSPD, PSPIE_CONNECTADDRESSINFO);
  34. VOID ProcessEnumAddressInfo(PSPD, PSPIE_ENUMADDRESSINFO);
  35. VOID ProcessListenAddressInfo(PSPD, PSPIE_LISTENADDRESSINFO);
  36. VOID ProcessSendMask(PEPD, BYTE, ULONG, ULONG, DWORD tNow, PSPRECEIVEDBUFFER* ppRcvBuffToFree);
  37. VOID ProcessSPDisconnect(PSPD, PSPIE_DISCONNECT);
  38. VOID ReceiveInOrderFrame(PEPD, PRCD, PSPRECEIVEDBUFFER* ppRcvBuffToFree);
  39. VOID ReceiveOutOfOrderFrame(PEPD, PRCD, ULONG, PSPRECEIVEDBUFFER* ppRcvBuffToFree);
  40. VOID ProcessHardDisconnect(PEPD);
  41. HRESULT CreateConnectedSignedReply(void * pvReplyBuffer, DWORD * pdwReplySize, DWORD dwSessID, DWORD dwAddressHash,
  42. ULONGLONG ullConnectSecret, DWORD dwSigningFlags, DWORD tNow);
  43. BOOL ValidateIncomingFrameSig(PEPD pEPD, BYTE * pbyFrame, DWORD dwFrameSize, BYTE bSeq, UNALIGNED ULONGLONG * pullFrameSig);
  44. HRESULT CrackCommand(PSPD, PEPD, PSPRECEIVEDBUFFER, DWORD, PSPRECEIVEDBUFFER* ppRcvBuffToFree);
  45. HRESULT CrackDataFrame(PSPD, PEPD, PSPRECEIVEDBUFFER, DWORD, PSPRECEIVEDBUFFER* ppRcvBuffToFree);
  46. /*
  47. ** GetDFrameMaskHeaderSize
  48. **
  49. ** Returns the size in bytes of the send/sack mask header in a dframe, when give
  50. ** the control byte from the dframe header.
  51. **/
  52. #undef DPF_MODNAME
  53. #define DPF_MODNAME "GetDFrameMaskHeaderSize"
  54. inline DWORD GetDFrameMaskHeaderSize(BYTE bControl)
  55. {
  56. DWORD dwLen=0;
  57. if (bControl & PACKET_CONTROL_SACK_MASK1)
  58. {
  59. dwLen += sizeof(DWORD);
  60. }
  61. if (bControl & PACKET_CONTROL_SACK_MASK2)
  62. {
  63. dwLen += sizeof(DWORD);
  64. }
  65. if (bControl & PACKET_CONTROL_SEND_MASK1)
  66. {
  67. dwLen += sizeof(DWORD);
  68. }
  69. if (bControl & PACKET_CONTROL_SEND_MASK2)
  70. {
  71. dwLen += sizeof(DWORD);
  72. }
  73. return dwLen;
  74. }
  75. /*
  76. ** Indicate Receive
  77. **
  78. ** Service Provider calls this entry when data arrives on the network.
  79. ** We will quickly validate the frame and then figure what to do with it...
  80. **
  81. ** Poll/Response activity should be handled before data is indicated to
  82. ** clients. We want to measure the network latency up to delivery, not including
  83. ** delivery.
  84. */
  85. #undef DPF_MODNAME
  86. #define DPF_MODNAME "DNSP_IndicateEvent"
  87. HRESULT WINAPI DNSP_IndicateEvent(IDP8SPCallback *pIDNSP, SP_EVENT_TYPE Opcode, PVOID DataBlock)
  88. {
  89. HRESULT hr;
  90. PSPD pSPD;
  91. hr = DPN_OK;
  92. pSPD = (PSPD)pIDNSP;
  93. ASSERT_SPD(pSPD);
  94. switch(Opcode)
  95. {
  96. case SPEV_DATA:
  97. hr = IndicateReceive(pSPD, (PSPIE_DATA) DataBlock);
  98. break;
  99. case SPEV_CONNECT:
  100. hr = IndicateConnect(pSPD, (PSPIE_CONNECT) DataBlock);
  101. break;
  102. case SPEV_ENUMQUERY:
  103. hr = ProcessEnumQuery( pSPD, (PSPIE_QUERY) DataBlock );
  104. break;
  105. case SPEV_QUERYRESPONSE:
  106. hr = ProcessQueryResponse( pSPD, (PSPIE_QUERYRESPONSE) DataBlock );
  107. break;
  108. case SPEV_DISCONNECT:
  109. ProcessSPDisconnect(pSPD, (PSPIE_DISCONNECT) DataBlock);
  110. break;
  111. case SPEV_LISTENSTATUS:
  112. ProcessListenStatus(pSPD, (PSPIE_LISTENSTATUS) DataBlock);
  113. break;
  114. case SPEV_LISTENADDRESSINFO:
  115. ProcessListenAddressInfo(pSPD, (PSPIE_LISTENADDRESSINFO) DataBlock);
  116. break;
  117. case SPEV_CONNECTADDRESSINFO:
  118. ProcessConnectAddressInfo(pSPD, (PSPIE_CONNECTADDRESSINFO) DataBlock);
  119. break;
  120. case SPEV_ENUMADDRESSINFO:
  121. ProcessEnumAddressInfo(pSPD, (PSPIE_ENUMADDRESSINFO) DataBlock);
  122. break;
  123. case SPEV_DATA_UNCONNECTED:
  124. hr = ProcessUnconnectedData(pSPD, (PSPIE_DATA_UNCONNECTED) DataBlock);
  125. break;
  126. #ifndef DPNBUILD_NOMULTICAST
  127. case SPEV_DATA_UNKNOWNSENDER:
  128. hr = IndicateReceiveUnknownSender(pSPD, (PSPIE_DATA_UNKNOWNSENDER) DataBlock);
  129. break;
  130. #endif // ! DPNBUILD_NOMULTICAST
  131. // SP passed something unexpected
  132. default:
  133. DPFX(DPFPREP,0, "Unknown Event indicated by SP");
  134. ASSERT(0);
  135. break;
  136. }
  137. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blProtocolCritSecsHeld);
  138. return hr;
  139. }
  140. /*
  141. ** Process Unconnected Data
  142. **
  143. ** This event is indicated when the SP receives data from a sender
  144. ** for which we don't have a connected endpoint. We return DPN_OK to
  145. ** allow the SP to connect an endpoint and indicate the data again off the
  146. ** new endpoint. Alternatively we can have the SP reply to the sender
  147. ** without allocating an endpoint, or we can return DPNERR_ABORTED to
  148. ** ignore the data.
  149. */
  150. #undef DPF_MODNAME
  151. #define DPF_MODNAME "ProcessUnconnectedData"
  152. HRESULT ProcessUnconnectedData(PSPD pSPD, PSPIE_DATA_UNCONNECTED pUnconnectedData)
  153. {
  154. PMSD pMSD = (PMSD) pUnconnectedData->pvListenCommandContext;
  155. BYTE byPktCommand=*pUnconnectedData->pReceivedData->BufferDesc.pBufferData;
  156. DWORD dwDataLength = pUnconnectedData->pReceivedData->BufferDesc.dwBufferSize;
  157. ASSERT_MSD(pMSD);
  158. ASSERT(pMSD->pSPD == pSPD);
  159. DPFX(DPFPREP,DPF_CALLIN_LVL, "Parameters: pSPD[%p], pUnconnectedData[%p] - pMSD[%p]", pSPD, pUnconnectedData, pMSD);
  160. //if we've been told to remove the service provider we shouldn't process anything else.
  161. //Tell sp to dump this incoming data
  162. if(pSPD->ulSPFlags & SPFLAGS_TERMINATING)
  163. {
  164. DPFX(DPFPREP, 5, "SP is terminating, returning DPNERR_ABORTED, pSPD[%p]", pSPD);
  165. return DPNERR_ABORTED;
  166. }
  167. //check that we still have a valid listen running to handle this data
  168. Lock(&pMSD->CommandLock);
  169. //make sure this actually is a listen command
  170. //Note sure if its possible for it to be anything else, but we'll code robustly
  171. if(pMSD->CommandID != COMMAND_ID_LISTEN)
  172. {
  173. DPFX(DPFPREP,0, "Received unconnected data and MSD not marked as LISTEN pMSD[%p] "
  174. "pMSD->CommandID[%u]", pMSD, (DWORD ) pMSD->CommandID);
  175. DNASSERTX(FALSE, 0);
  176. Unlock(&pMSD->CommandLock);
  177. return DPNERR_ABORTED;
  178. }
  179. //if the listen has already been cancelled then drop incoming data on the floor
  180. if(pMSD->ulMsgFlags1 & MFLAGS_ONE_CANCELLED)
  181. {
  182. DPFX(DPFPREP, 5, "Received unconnected data on a cancelled listen pSPD[%p] pMSD[%p]", pSPD, pMSD);
  183. Unlock(&pMSD->CommandLock);
  184. return DPNERR_ABORTED;
  185. }
  186. //store the session signing type and the connect secrets
  187. DWORD dwSigningType=0;
  188. ULONGLONG ullLastConnectSecret, ullCurrentConnectSecret;
  189. DWORD tNow=GETTIMESTAMP();
  190. if (pMSD->ulMsgFlags1 & MFLAGS_ONE_SIGNED)
  191. {
  192. if (pMSD->ulMsgFlags1 & MFLAGS_ONE_FAST_SIGNED)
  193. {
  194. dwSigningType=PACKET_SIGNING_FAST;
  195. }
  196. else
  197. {
  198. DNASSERT(pMSD->ulMsgFlags1 & MFLAGS_ONE_FULL_SIGNED);
  199. dwSigningType=PACKET_SIGNING_FULL;
  200. }
  201. //check how much time has elapsed since we last updated the connect secret.
  202. //if its exceed a pre-determined amount then lets pick a new connect secret
  203. if ((tNow-pMSD->dwTimeConnectSecretChanged)>CONNECT_SECRET_CHANGE_INTERVAL)
  204. {
  205. pMSD->ullLastConnectSecret=pMSD->ullCurrentConnectSecret;
  206. DNGetGoodRandomData(&pMSD->ullCurrentConnectSecret, sizeof(pMSD->ullCurrentConnectSecret));
  207. pMSD->dwTimeConnectSecretChanged=tNow;
  208. }
  209. //store the current connect secrets locally.
  210. ullLastConnectSecret=pMSD->ullLastConnectSecret;
  211. ullCurrentConnectSecret=pMSD->ullCurrentConnectSecret;
  212. }
  213. //we're done with the MSD now so can unlock its
  214. Unlock(&pMSD->CommandLock);
  215. //once we get here we've got a valid SP reporting data for a valid listen.
  216. //now need to check if the frame is actually interesting.
  217. //The only things we care about are the cframes CONNECT and CONNECTED_SIGNED and the dframe keep alives
  218. //N.B. We pick up on keep alives because of the possible connect sequence
  219. //Connect recv, ConnectedSigned sent, ConnectSigned should be recv but is dropped
  220. //in this case the connector will think the link is valid but the listener will have no record of them
  221. //we therefore use the keep alive the connector will send at first as a clue to send another ConnectedSigned from the
  222. //listening side
  223. //have we got a dframe?
  224. if( (dwDataLength >= MIN_SEND_DFRAME_HEADER_SIZE) &&
  225. (byPktCommand & PACKET_COMMAND_DATA))
  226. {
  227. PDFRAME pDFrame=(PDFRAME) pUnconnectedData->pReceivedData->BufferDesc.pBufferData;
  228. //if we haven't got a signed session then we don't care what sort of dframe this is. This clearly isn't
  229. //the start of a connection and we don't have to handle the ConnectedSigned dropped case outlined above
  230. if ((dwSigningType & (PACKET_SIGNING_FAST | PACKET_SIGNING_FULL))==0)
  231. {
  232. DPFX(DPFPREP, 5, "Rejecting unconnected dframe received for an unsigned session");
  233. return DPNERR_ABORTED;
  234. }
  235. //only unconnected dframe we care about in a signed session is a new style keep alive.
  236. //i.e. one with a session identity in it, rather than simple zero data
  237. //The control flags for this kind of keep alive are retry=don't care, keepalive=set, coalesce=clear and eos=clear
  238. //it should also have a zero sequence count, since we only care about the keep alive sent on a new connection
  239. if (((pDFrame->bControl & PACKET_CONTROL_KEEPALIVE)==0) ||
  240. (pDFrame->bControl & (PACKET_CONTROL_END_STREAM | PACKET_CONTROL_COALESCE)) ||
  241. pDFrame->bSeq!=0)
  242. {
  243. DPFX(DPFPREP, 5, "Rejecting unconnected dframe that doesn't look like a keep alive");
  244. return DPNERR_ABORTED;
  245. }
  246. //size must be at least big enough to hold data that we require
  247. //i.e. DFRAME header, whatever the mask size is, the signature, and then the DWORD session identity
  248. DWORD dwRequiredSize=sizeof(DFRAME)+GetDFrameMaskHeaderSize(pDFrame->bControl)+sizeof(ULONGLONG)+sizeof(DWORD);
  249. if (dwDataLength<dwRequiredSize)
  250. {
  251. DPFX(DPFPREP, 0, "Rejected unconnected keep alive dframe that's too short");
  252. return DPNERR_ABORTED;
  253. }
  254. //looks like we've got a keep alive that meets all our criteria for sending a CONNECTED_SIGNED response
  255. return CreateConnectedSignedReply(pUnconnectedData->pvReplyBuffer, &pUnconnectedData->dwReplyBufferSize,
  256. *((DWORD * ) ((((BYTE* ) pDFrame)+dwRequiredSize-sizeof(DWORD)))), pUnconnectedData->dwSenderAddressHash,
  257. ullCurrentConnectSecret, dwSigningType, tNow);
  258. }
  259. //have we got a cframe?
  260. if ((dwDataLength >= MIN_SEND_CFRAME_HEADER_SIZE) &&
  261. ((byPktCommand == PACKET_COMMAND_CFRAME) ||
  262. (byPktCommand == (PACKET_COMMAND_CFRAME|PACKET_COMMAND_POLL))))
  263. {
  264. //looks like we've got a command frame.
  265. PCFRAME pCFrame=(PCFRAME ) pUnconnectedData->pReceivedData->BufferDesc.pBufferData;
  266. //if its not a type we're interested in then dump it
  267. //N.B. We ignore FRAME_EXOPCODE_CONNECTED frames. If we haven't got a signed session we fall
  268. //back to the connect data path on receiving a CONNECT. Hence, by the time we get the CONNECTED
  269. //we should always have an associated endpoint
  270. if (pCFrame->bExtOpcode!=FRAME_EXOPCODE_CONNECT &&
  271. pCFrame->bExtOpcode!=FRAME_EXOPCODE_CONNECTED_SIGNED)
  272. {
  273. DPFX(DPFPREP, 5, "Rejecting unconnected cframe that is neither a CONNECT or CONNECTEDSIGNED");
  274. return DPNERR_ABORTED;
  275. }
  276. //If the major version number doesn't match ours we can ignore this
  277. if((pCFrame->dwVersion >> 16) != (DNET_VERSION_NUMBER >> 16))
  278. {
  279. DPFX(DPFPREP,1, "Received unconnected CFrame from incompatible version (theirs %x, ours %x)",
  280. pCFrame->dwVersion, DNET_VERSION_NUMBER);
  281. return DPNERR_ABORTED;
  282. }
  283. //if we've got a bogus session identity we can also throw this frame away
  284. if (VersionSupportsSigning(pCFrame->dwVersion) && pCFrame->dwSessID==0)
  285. {
  286. DPFX(DPFPREP,1, "Received unconnected CFrame with invalid session identity");
  287. return DPNERR_ABORTED;
  288. }
  289. if (pCFrame->bExtOpcode==FRAME_EXOPCODE_CONNECT)
  290. {
  291. //if the session isn't signed then fall back to the old code path of allocating an endpoint up front
  292. //and kicking off the connect sequence
  293. if ((dwSigningType & (PACKET_SIGNING_FAST | PACKET_SIGNING_FULL))==0)
  294. {
  295. DPFX(DPFPREP, 5, "Received CONNECT frame for unsigned session. Instructing SP to indicate an endpoint. "
  296. "pSPD[%p] pMSD[%p]", pSPD, pMSD);
  297. return DPN_OK;
  298. }
  299. //We've got a connect request to a signed session. Better make sure they support signing
  300. if (VersionSupportsSigning(pCFrame->dwVersion)==FALSE)
  301. {
  302. //N.B. This approach means we'll appear unresponsive to far end and it'll time out the connect
  303. //It would be nice to send a reject packet, but unfortunately the protocol has no support for that
  304. DPFX(DPFPREP, 1, "Ignoring incoming CONNECT from protocol version that doesn't support signing. "
  305. "pSPD[%p] Their Minor Version [%u]", pSPD, pCFrame->dwVersion & 0xFFFF);
  306. return DPNERR_ABORTED;
  307. }
  308. //Looks like everything is valid and we should respond to the CONNECT with a CONNECTEDSIGNED cframe
  309. return CreateConnectedSignedReply(pUnconnectedData->pvReplyBuffer, &pUnconnectedData->dwReplyBufferSize,
  310. pCFrame->dwSessID, pUnconnectedData->dwSenderAddressHash,
  311. ullCurrentConnectSecret, dwSigningType, tNow);
  312. }
  313. DNASSERT(pCFrame->bExtOpcode==FRAME_EXOPCODE_CONNECTED_SIGNED);
  314. //make sure size matches minimum we expect
  315. if (dwDataLength<sizeof(CFRAME_CONNECTEDSIGNED))
  316. {
  317. DPFX(DPFPREP, 0, "Rejecting CONNECTED_SIGNED cframe that is too short");
  318. return DPNERR_ABORTED;
  319. }
  320. //make sure the signing type matches what we've got for the session
  321. if ((((CFRAME_CONNECTEDSIGNED * ) pCFrame)->dwSigningOpts & (PACKET_SIGNING_FAST | PACKET_SIGNING_FULL))
  322. !=dwSigningType)
  323. {
  324. DPFX(DPFPREP, 0, "Rejecting CONNECTED_SIGNED cframe with invalid signing options");
  325. return DPNERR_ABORTED;
  326. }
  327. //we need to check the connect signature to ensure that we're seeing is a genuine response
  328. //to an original CONNECTED_SIGNED frame we sent out
  329. ULONGLONG ullConnectSig=GenerateConnectSig(pCFrame->dwSessID,
  330. pUnconnectedData->dwSenderAddressHash, ullCurrentConnectSecret);
  331. if (ullConnectSig!=((CFRAME_CONNECTEDSIGNED * ) pCFrame)->ullConnectSig)
  332. {
  333. //possible we're seeing a connect response that's overlapped with a change in the connect secret
  334. //so lets check the previous connect secret
  335. ullConnectSig=GenerateConnectSig(pCFrame->dwSessID,
  336. pUnconnectedData->dwSenderAddressHash, ullLastConnectSecret);
  337. if (ullConnectSig!=((CFRAME_CONNECTEDSIGNED * ) pCFrame)->ullConnectSig)
  338. {
  339. DPFX(DPFPREP, 0, "Rejecting CONNECTED_SIGNED cframe that has an invalid connection signature");
  340. return DPNERR_ABORTED;
  341. }
  342. }
  343. //looks like we've got a valid CONNECTEDSIGNED response. This tells us that the original connect wasn't from
  344. //a fake IP and we've got a valid remote host to form the connection with. Return OK to tell the SP to allocate
  345. //an endpoint for this connection
  346. return DPN_OK;
  347. }
  348. //looks like we got something weird that was neither a dframe or a cframe
  349. DPFX(DPFPREP, 0, "Rejecting unconnected cframe that is neither a dframe or cframe");
  350. return DPNERR_ABORTED;
  351. }
  352. /*
  353. ** Indicate Connect
  354. **
  355. ** This event is indicated for both calling and listening sides. The
  356. ** calling side will do most of its work when the SP Connect call completes
  357. ** and the listening side will do most of its work when the CONNECT frame
  358. ** gets delivered. All we do here is allocate the EPD and attach it to the
  359. ** MSD (for calling case)
  360. **
  361. ** Since we have a connect protocol, there will always be a CONNECT
  362. ** frame following closely on the heels of this indication. Therefore,
  363. ** there is not a whole lot of stuff that we need to do here. We will
  364. ** allocate the EndPoint and leave it dormant.
  365. **
  366. ** Synchronization Issue: We have decided that if an SP Listen command is cancelled,
  367. ** the cancel call will not complete until all ConnectIndications have returned from the
  368. ** protocol. This means that we are GUARANTEED that the Listen command in the context
  369. ** will be valid throughout this call. This is important because now we can add a reference
  370. ** to the Listen's MSD here and now and we will know that it wont disappear on us before we
  371. ** do it. Truth, however, is that there will be a race until SP fixes itself to follow
  372. ** this behavior.
  373. */
  374. #undef DPF_MODNAME
  375. #define DPF_MODNAME "IndicateConnect"
  376. HRESULT IndicateConnect(PSPD pSPD, PSPIE_CONNECT pConnData)
  377. {
  378. PEPD pEPD;
  379. PMSD pMSD;
  380. pMSD = (PMSD) pConnData->pCommandContext;
  381. ASSERT_MSD(pMSD);
  382. ASSERT(pMSD->pSPD == pSPD);
  383. DPFX(DPFPREP,DPF_CALLIN_LVL, "Parameters: pSPD[%p], pConnData[%p] - pMSD[%p]", pSPD, pConnData, pMSD);
  384. Lock(&pMSD->CommandLock);
  385. LOCK_MSD(pMSD, "EPD Ref"); // Place a reference on the command object. This prevents it from
  386. // going away during the Connect Protocol, an assumption which simplifies
  387. // life extraordinarily. We will want to ASSERT this fact, however, to make
  388. // sure that SP is playing by our rules.
  389. if ((pMSD->CommandID != COMMAND_ID_CONNECT) && (pMSD->CommandID != COMMAND_ID_LISTEN)
  390. #ifndef DPNBUILD_NOMULTICAST
  391. && (pMSD->CommandID != COMMAND_ID_CONNECT_MULTICAST_SEND) && (pMSD->CommandID != COMMAND_ID_CONNECT_MULTICAST_RECEIVE)
  392. #endif // DPNBUILD_NOMULTICAST
  393. )
  394. {
  395. DPFX(DPFPREP,1, "Connect Rejected - CommandID is not Connect or Listen, returning DPNERR_ABORTED, pMSD[%p]", pMSD);
  396. RELEASE_MSD(pMSD, "EPD Ref"); // Releases CommandLock
  397. return DPNERR_ABORTED;
  398. }
  399. if ((pMSD->CommandID == COMMAND_ID_CONNECT
  400. #ifndef DPNBUILD_NOMULTICAST
  401. || (pMSD->CommandID == COMMAND_ID_CONNECT_MULTICAST_SEND)
  402. || (pMSD->CommandID == COMMAND_ID_CONNECT_MULTICAST_RECEIVE)
  403. #endif // DPNBUILD_NOMULTICAST
  404. ) && (pMSD->pEPD != NULL))
  405. {
  406. DPFX(DPFPREP,1, "Connect Rejected - Connect command already has an endpoint, returning DPNERR_ABORTED, pMSD[%p], pEPD[%p]", pMSD, pMSD->pEPD);
  407. RELEASE_MSD(pMSD, "EPD Ref"); // Releases CommandLock
  408. return DPNERR_ABORTED;
  409. }
  410. if(pMSD->ulMsgFlags1 & MFLAGS_ONE_CANCELLED)
  411. {
  412. DPFX(DPFPREP,1, "Connect Rejected - Command is cancelled, returning DPNERR_ABORTED, pMSD[%p]", pMSD);
  413. RELEASE_MSD(pMSD, "EPD Ref"); // Releases CommandLock
  414. return DPNERR_ABORTED;
  415. }
  416. if((pEPD = NewEndPoint(pSPD, pConnData->hEndpoint)) == NULL)
  417. {
  418. DPFX(DPFPREP,0, "Failed to allocate new EPD, returning DPNERR_ABORTED, pMSD[%p]", pMSD);
  419. RELEASE_MSD(pMSD, "EPD Ref"); // Releases CommandLock
  420. return DPNERR_ABORTED; // This error will implicitly DISCONNECT from Endpoint
  421. }
  422. // Associate either the Connect or Listen with this Endpoint, this will be removed when the connection is complete.
  423. // The EPD Ref placed above will be carried around until this is NULL'd.
  424. pEPD->pCommand = pMSD;
  425. if(pMSD->CommandID == COMMAND_ID_CONNECT)
  426. {
  427. DPFX(DPFPREP,5, "INDICATE CONNECT (CALLING) -- EPD = %p, pMSD[%p]", pEPD, pMSD);
  428. pMSD->pEPD = pEPD;
  429. }
  430. #ifndef DPNBUILD_NOMULTICAST
  431. else if (pMSD->CommandID == COMMAND_ID_CONNECT_MULTICAST_SEND)
  432. {
  433. DPFX(DPFPREP,5, "INDICATE MULTICAST SEND CONNECT (CALLING) -- EPD = %p, pMSD[%p]", pEPD, pMSD);
  434. pEPD->ulEPFlags |= EPFLAGS_STATE_CONNECTED | EPFLAGS_STREAM_UNBLOCKED;
  435. pEPD->ulEPFlags2 |= EPFLAGS2_MULTICAST_SEND;
  436. pMSD->pEPD = pEPD;
  437. }
  438. else if (pMSD->CommandID == COMMAND_ID_CONNECT_MULTICAST_RECEIVE)
  439. {
  440. DPFX(DPFPREP,5, "INDICATE MULTICAST RECEIVE CONNECT (CALLING) -- EPD = %p, pMSD[%p]", pEPD, pMSD);
  441. pEPD->ulEPFlags |= EPFLAGS_STATE_CONNECTED | EPFLAGS_STREAM_UNBLOCKED;
  442. pEPD->ulEPFlags2 |= EPFLAGS2_MULTICAST_RECEIVE;
  443. pMSD->pEPD = pEPD;
  444. }
  445. #endif // DPNBUILD_NOMULTICAST
  446. else
  447. {
  448. DPFX(DPFPREP,5, "INDICATE CONNECT (LISTENING) -- EPD = %p, pMSD[%p]", pEPD, pMSD);
  449. ASSERT(pMSD->CommandID == COMMAND_ID_LISTEN);
  450. ASSERT((pEPD->ulEPFlags & EPFLAGS_LINKED_TO_LISTEN)==0);
  451. // For a Listen command, connecting endpoints are held on the blFrameList
  452. pEPD->blSPLinkage.InsertBefore( &pMSD->blFrameList);
  453. pEPD->ulEPFlags |= EPFLAGS_LINKED_TO_LISTEN;
  454. }
  455. pConnData->pEndpointContext = pEPD;
  456. Unlock(&pMSD->CommandLock);
  457. return DPN_OK;
  458. }
  459. /*
  460. ** Indicate Receive
  461. **
  462. ** A frame has been delivered by the service provider. We are Guaranteed to
  463. ** have an active Endpoint in our hash table (or else something is wrong). I have not
  464. ** decided whether I will respond to POLL bits at this high level or else let
  465. ** each handler repond in its own particular... eh... idiom.
  466. **
  467. ** Our return value controls whether SP will recycle the receive buffer, or whether
  468. ** we can keep the buffer around until we are ready to indicate it to higher levels
  469. ** later on. If we return DPN_OK then we are done with the buffer and it will be recycled.
  470. ** If we return DPNERR_PENDING then we may hold on to the buffer until we release them later.
  471. */
  472. #undef DPF_MODNAME
  473. #define DPF_MODNAME "IndicateReceive"
  474. HRESULT IndicateReceive(PSPD pSPD, PSPIE_DATA pDataBlock)
  475. {
  476. PEPD pEPD;
  477. HRESULT hr;
  478. BYTE byPktCommand;
  479. DWORD tNow;
  480. DWORD dwDataLength;
  481. PSPRECEIVEDBUFFER pRcvBuffToFree;
  482. pEPD = (PEPD)pDataBlock->pEndpointContext;
  483. byPktCommand=*pDataBlock->pReceivedData->BufferDesc.pBufferData;
  484. dwDataLength = pDataBlock->pReceivedData->BufferDesc.dwBufferSize;
  485. tNow = GETTIMESTAMP();
  486. pRcvBuffToFree = NULL;
  487. DPFX(DPFPREP,DPF_CALLIN_LVL, "Parameters: pSPD[%p], pDataBlock[%p] - pEPD[%p]", pSPD, pDataBlock, pEPD);
  488. if(pSPD->ulSPFlags & SPFLAGS_TERMINATING)
  489. {
  490. DPFX(DPFPREP,1, "(%p) SP is terminating, returning DPN_OK, pSPD[%p]", pEPD, pSPD);
  491. return DPN_OK;
  492. }
  493. ASSERT_EPD(pEPD);
  494. ASSERT(pEPD->pSPD == pSPD);
  495. ASSERT(pDataBlock->hEndpoint == pEPD->hEndPt);
  496. #ifndef DPNBUILD_NOMULTICAST
  497. if (pEPD->ulEPFlags2 & EPFLAGS2_MULTICAST_RECEIVE)
  498. {
  499. PSPRECEIVEDBUFFER pRcvBuffer;
  500. pRcvBuffer = pDataBlock->pReceivedData;
  501. DNASSERT(pRcvBuffer != NULL);
  502. DNASSERT(pRcvBuffer->pNext == NULL);
  503. DNASSERT(pRcvBuffer->dwProtocolData == 0);
  504. DNASSERT(pRcvBuffer->pServiceProviderDescriptor == NULL);
  505. pRcvBuffer->dwProtocolData = RBT_SERVICE_PROVIDER_BUFFER;
  506. pRcvBuffer->pServiceProviderDescriptor = pSPD;
  507. DEBUG_ONLY(DNInterlockedIncrement(&pSPD->pPData->ThreadsInReceive));
  508. DEBUG_ONLY(DNInterlockedIncrement(&pSPD->pPData->BuffersInReceive));
  509. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blProtocolCritSecsHeld);
  510. DPFX(DPFPREP,DPF_CALLOUT_LVL, "(%p) Calling Core->IndicateReceive(multicast), Core Context[%p]", pEPD, pEPD->Context);
  511. hr = pSPD->pPData->pfVtbl->IndicateReceive( pSPD->pPData->Parent,
  512. pEPD->Context,
  513. pRcvBuffer->BufferDesc.pBufferData,
  514. pRcvBuffer->BufferDesc.dwBufferSize,
  515. pRcvBuffer,
  516. 0);
  517. if(hr == DPN_OK)
  518. {
  519. DEBUG_ONLY(DNInterlockedDecrement(&pSPD->pPData->BuffersInReceive));
  520. }
  521. else
  522. {
  523. ASSERT(hr == DPNERR_PENDING);
  524. }
  525. DEBUG_ONLY(DNInterlockedDecrement(&pSPD->pPData->ThreadsInReceive));
  526. }
  527. else
  528. {
  529. #endif // DPNBUILD_NOMULTICAST
  530. // Hold a reference throughout the operation so we don't have to deal with the EPD going away.
  531. LOCK_EPD(pEPD, "LOCK (IND RECEIVE)");
  532. pEPD->tLastPacket = tNow; // Track last time each guy writes to us
  533. #ifdef DBG
  534. // copy this frame to buffer in EPD so we can look after a break.
  535. DWORD dwLen = _MIN(sizeof(pEPD->LastPacket), pDataBlock->pReceivedData->BufferDesc.dwBufferSize);
  536. memcpy(pEPD->LastPacket, pDataBlock->pReceivedData->BufferDesc.pBufferData, dwLen);
  537. #endif // DBG
  538. //take lock on endpoint
  539. Lock(&pEPD->EPLock);
  540. // A valid data packet is one that meets the length requirements and has the Data flag set.
  541. // All other flags are allowed on a data frame (NOTE: even PACKET_COMMAND_CFRAME is allowed
  542. // as it shares its value with PACKET_COMMAND_USER_2).
  543. if( (dwDataLength >= MIN_SEND_DFRAME_HEADER_SIZE) && // Validate the length first
  544. (byPktCommand & PACKET_COMMAND_DATA)) // Data goes this way
  545. {
  546. //if endpoint is marked as either hard disconnect source or target it won't process further data frames
  547. if (pEPD->ulEPFlags & (EPFLAGS_HARD_DISCONNECT_SOURCE | EPFLAGS_HARD_DISCONNECT_TARGET))
  548. {
  549. Unlock(&pEPD->EPLock);
  550. hr=DPN_OK;
  551. }
  552. else
  553. {
  554. hr = CrackDataFrame(pSPD, pEPD, pDataBlock->pReceivedData, tNow, &pRcvBuffToFree);
  555. //above call will release ep lock
  556. }
  557. }
  558. else if ((dwDataLength >= MIN_SEND_CFRAME_HEADER_SIZE) && // Validate the length first
  559. ((byPktCommand == PACKET_COMMAND_CFRAME) || // Only the CFRAME and POLL flags are allowed on a CFrame
  560. (byPktCommand == (PACKET_COMMAND_CFRAME|PACKET_COMMAND_POLL))))
  561. {
  562. hr = CrackCommand(pSPD, pEPD, pDataBlock->pReceivedData, tNow, &pRcvBuffToFree);
  563. //above call will release ep lock
  564. }
  565. else
  566. {
  567. DPFX(DPFPREP,1, "(%p) Received frame that is neither Command nor Data, rejecting", pEPD);
  568. DNASSERTX(FALSE, 2);
  569. RejectInvalidPacket(pEPD);
  570. //above call will release ep lock
  571. hr = DPN_OK;
  572. }
  573. // Free any buffers created during the receive
  574. if (pRcvBuffToFree != NULL)
  575. {
  576. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blProtocolCritSecsHeld);
  577. DPFX(DPFPREP,DPF_CALLOUT_LVL, "(%p) Calling SP->ReturnReceiveBuffers, pSPD[%p], pRcvBuffToFree[%p]", pEPD, pSPD, pRcvBuffToFree);
  578. IDP8ServiceProvider_ReturnReceiveBuffers(pSPD->IISPIntf, pRcvBuffToFree);
  579. }
  580. Lock(&pEPD->EPLock);
  581. RELEASE_EPD(pEPD, "UNLOCK (IND RCV DONE)"); // Releases EPLock
  582. #ifndef DPNBUILD_NOMULTICAST
  583. }
  584. #endif // DPNBUILD_NOMULTICAST
  585. // This is either DPN_OK or DPNSUCCESS_PENDING. If it is pending we have to return the buffer later.
  586. return hr;
  587. }
  588. #ifndef DPNBUILD_NOMULTICAST
  589. /*
  590. ** Indicate Receive from an Unknown Sender
  591. **
  592. ** A frame has been delivered by the service provider from some multicast sender for which
  593. ** we do not have an endpoint.
  594. **
  595. ** Our return value controls whether SP will recycle the receive buffer, or whether
  596. ** we can keep the buffer around until we are ready to indicate it to higher levels
  597. ** later on. If we return DPN_OK then we are done with the buffer and it will be recycled.
  598. ** If we return DPNERR_PENDING then we may hold on to the buffer until we release them later.
  599. */
  600. #undef DPF_MODNAME
  601. #define DPF_MODNAME "IndicateReceiveUnknownSender"
  602. HRESULT IndicateReceiveUnknownSender(PSPD pSPD, PSPIE_DATA_UNKNOWNSENDER pDataBlock)
  603. {
  604. HRESULT hr;
  605. PMSD pMSD;
  606. PSPRECEIVEDBUFFER pRcvBuffer;
  607. pMSD = (PMSD) pDataBlock->pvListenCommandContext;
  608. DPFX(DPFPREP,DPF_CALLIN_LVL, "Parameters: pSPD[%p], pDataBlock[%p] - pMSD[%p]", pSPD, pDataBlock, pMSD);
  609. ASSERT_MSD(pMSD);
  610. ASSERT(pMSD->pSPD == pSPD);
  611. ASSERT(pMSD->CommandID == COMMAND_ID_LISTEN_MULTICAST);
  612. pRcvBuffer = pDataBlock->pReceivedData;
  613. DNASSERT(pRcvBuffer != NULL);
  614. DNASSERT(pRcvBuffer->pNext == NULL);
  615. DNASSERT(pRcvBuffer->dwProtocolData == 0);
  616. DNASSERT(pRcvBuffer->pServiceProviderDescriptor == NULL);
  617. pRcvBuffer->dwProtocolData = RBT_SERVICE_PROVIDER_BUFFER;
  618. pRcvBuffer->pServiceProviderDescriptor = pSPD;
  619. DEBUG_ONLY(DNInterlockedIncrement(&pSPD->pPData->ThreadsInReceive));
  620. DEBUG_ONLY(DNInterlockedIncrement(&pSPD->pPData->BuffersInReceive));
  621. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blProtocolCritSecsHeld);
  622. DPFX(DPFPREP,DPF_CALLOUT_LVL, "(%p) Calling Core->IndicateReceiveUnknownSender, Core Context[%p]", pMSD, pMSD->Context);
  623. hr = pSPD->pPData->pfVtbl->IndicateReceiveUnknownSender(pSPD->pPData->Parent,
  624. pMSD->Context,
  625. pDataBlock->pSenderAddress,
  626. pRcvBuffer->BufferDesc.pBufferData,
  627. pRcvBuffer->BufferDesc.dwBufferSize,
  628. pRcvBuffer);
  629. if(hr == DPN_OK)
  630. {
  631. DEBUG_ONLY(DNInterlockedDecrement(&pSPD->pPData->BuffersInReceive));
  632. }
  633. else
  634. {
  635. ASSERT(hr == DPNERR_PENDING);
  636. }
  637. DEBUG_ONLY(DNInterlockedDecrement(&pSPD->pPData->ThreadsInReceive));
  638. return hr;
  639. }
  640. #endif // ! DPNBUILD_NOMULTICAST
  641. /*
  642. ** Process Enum Query
  643. **
  644. ** A frame has been delivered by the service provider representing an enumereation
  645. ** query.
  646. */
  647. #undef DPF_MODNAME
  648. #define DPF_MODNAME "ProcessEnumQuery"
  649. HRESULT ProcessEnumQuery( PSPD pSPD, PSPIE_QUERY pQueryBlock )
  650. {
  651. MSD *pMSD;
  652. PROTOCOL_ENUM_DATA EnumData;
  653. pMSD = static_cast<MSD*>( pQueryBlock->pUserContext );
  654. ASSERT_MSD(pMSD);
  655. ASSERT(pMSD->pSPD == pSPD);
  656. DPFX(DPFPREP,DPF_CALLIN_LVL, "Parameters: pSPD[%p], pQueryBlock[%p] - pMSD[%p]", pSPD, pQueryBlock, pMSD);
  657. EnumData.pSenderAddress = pQueryBlock->pAddressSender;
  658. EnumData.pDeviceAddress = pQueryBlock->pAddressDevice;
  659. EnumData.ReceivedData.pBufferData = pQueryBlock->pReceivedData->BufferDesc.pBufferData;
  660. EnumData.ReceivedData.dwBufferSize = pQueryBlock->pReceivedData->BufferDesc.dwBufferSize;
  661. EnumData.hEnumQuery = pQueryBlock;
  662. DBG_CASSERT( sizeof( &EnumData ) == sizeof( PBYTE ) );
  663. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blProtocolCritSecsHeld);
  664. DPFX(DPFPREP,DPF_CALLOUT_LVL, "(%p) Calling Core->IndicateEnumQuery, Core Context[%p]", pMSD, pMSD->Context);
  665. pSPD->pPData->pfVtbl->IndicateEnumQuery( pSPD->pPData->Parent,
  666. pMSD->Context,
  667. pMSD,
  668. reinterpret_cast<PBYTE>( &EnumData ),
  669. sizeof( EnumData ));
  670. return DPN_OK;
  671. }
  672. /*
  673. ** Process Query Response
  674. **
  675. ** A frame has been delivered by the service provider representing a response to an enum.
  676. */
  677. #undef DPF_MODNAME
  678. #define DPF_MODNAME "ProcessQueryResponse"
  679. HRESULT ProcessQueryResponse( PSPD pSPD, PSPIE_QUERYRESPONSE pQueryResponseBlock)
  680. {
  681. MSD *pMSD;
  682. PROTOCOL_ENUM_RESPONSE_DATA EnumResponseData;
  683. pMSD = static_cast<MSD*>( pQueryResponseBlock->pUserContext );
  684. ASSERT_MSD(pMSD);
  685. ASSERT(pMSD->pSPD == pSPD);
  686. DPFX(DPFPREP,DPF_CALLIN_LVL, "Parameters: pSPD[%p], pQueryResponseBlock[%p] - pMSD[%p]", pSPD, pQueryResponseBlock, pMSD);
  687. EnumResponseData.pSenderAddress = pQueryResponseBlock->pAddressSender;
  688. EnumResponseData.pDeviceAddress = pQueryResponseBlock->pAddressDevice;
  689. EnumResponseData.ReceivedData.pBufferData = pQueryResponseBlock->pReceivedData->BufferDesc.pBufferData;
  690. EnumResponseData.ReceivedData.dwBufferSize = pQueryResponseBlock->pReceivedData->BufferDesc.dwBufferSize;
  691. EnumResponseData.dwRoundTripTime = pQueryResponseBlock->dwRoundTripTime;
  692. DBG_CASSERT( sizeof( &EnumResponseData ) == sizeof( PBYTE ) );
  693. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blProtocolCritSecsHeld);
  694. DPFX(DPFPREP,DPF_CALLOUT_LVL, "(%p) Calling Core->IndicateEnumResponse, Core Context[%p]", pMSD, pMSD->Context);
  695. pSPD->pPData->pfVtbl->IndicateEnumResponse( pSPD->pPData->Parent,
  696. pMSD,
  697. pMSD->Context,
  698. reinterpret_cast<PBYTE>( &EnumResponseData ),
  699. sizeof( EnumResponseData ));
  700. return DPN_OK;
  701. }
  702. /*
  703. ** Reject Invalid Packet
  704. **
  705. ** Called with EP Lock held. Returns with lock released
  706. */
  707. #undef DPF_MODNAME
  708. #define DPF_MODNAME "RejectInvalidPacket"
  709. VOID RejectInvalidPacket(PEPD pEPD)
  710. {
  711. PMSD pMSD;
  712. AssertCriticalSectionIsTakenByThisThread(&pEPD->EPLock, TRUE);
  713. if(pEPD->ulEPFlags & EPFLAGS_STATE_DORMANT)
  714. {
  715. // Unlink MSD from EPD, there should always be one if we are in the DORMANT state
  716. pMSD = pEPD->pCommand;
  717. ASSERT_MSD(pMSD);
  718. if (pMSD->CommandID == COMMAND_ID_LISTEN)
  719. {
  720. pEPD->pCommand = NULL;
  721. LOCK_EPD(pEPD, "Temp Ref");
  722. DPFX(DPFPREP,1, "(%p) Received invalid frame on a dormant, listening endpoint, dropping link", pEPD);
  723. DropLink(pEPD); // This will release the EPLock
  724. // The order here is important. We call DropLink first without ever leaving the EPLock because
  725. // we need to ensure no new packets try to come in. After calling DropLink we know we stay in the
  726. // TERMINATING state until returning to the pool, so state is not an issue after that call.
  727. Lock(&pMSD->CommandLock);
  728. Lock(&pEPD->EPLock);
  729. // If a cancel on a listen comes in at the same time as this happens, it is possible that the cancel came
  730. // through and already unlinked this EPD from the Listen while we were outside the lock. If so, removing
  731. // it from the pMSD->blFrameList twice is harmless.
  732. pEPD->ulEPFlags &= ~(EPFLAGS_LINKED_TO_LISTEN);
  733. pEPD->blSPLinkage.RemoveFromList(); // Unlink EPD from Listen Queue
  734. // Release MSD before EPD since final EPD will call out to SP and we don't want any locks held
  735. RELEASE_MSD(pMSD, "EPD Ref"); // Releases CommandLock
  736. RELEASE_EPD(pEPD, "Temp Ref"); // Releases EPLock
  737. }
  738. else
  739. {
  740. DPFX(DPFPREP,1, "(%p) Received invalid frame on a dormant, connecting endpoint, ignoring", pEPD);
  741. Unlock(&pEPD->EPLock);
  742. }
  743. }
  744. else
  745. {
  746. DPFX(DPFPREP,1, "(%p) Received invalid frame on a non-dormant endpoint, ignoring", pEPD);
  747. Unlock(&pEPD->EPLock);
  748. }
  749. }
  750. /*
  751. ** Crack Command
  752. **
  753. ** This frame is a maintainance frame containing no user data
  754. **
  755. ** Called with EP lock held, returns with EP lock released
  756. **
  757. */
  758. #undef DPF_MODNAME
  759. #define DPF_MODNAME "CrackCommand"
  760. HRESULT CrackCommand(PSPD pSPD, PEPD pEPD, PSPRECEIVEDBUFFER pRcvBuffer, DWORD tNow, PSPRECEIVEDBUFFER* ppRcvBuffToFree)
  761. {
  762. DWORD dwDataLength = pRcvBuffer->BufferDesc.dwBufferSize;
  763. UNALIGNED ULONG *array_ptr;
  764. ULONG mask1, mask2;
  765. union
  766. {
  767. BYTE * pbyFrame;
  768. PCFRAME pCFrame;
  769. PSACKFRAME8 pSack;
  770. } pData;
  771. AssertCriticalSectionIsTakenByThisThread(&pEPD->EPLock, TRUE);
  772. pData.pCFrame = (PCFRAME) pRcvBuffer->BufferDesc.pBufferData;
  773. //if ep is marked as a hard disconnect target then it ignore all CFRAMES. Its going to
  774. //drop the link any moment now
  775. if (pEPD->ulEPFlags & EPFLAGS_HARD_DISCONNECT_TARGET)
  776. {
  777. DPFX(DPFPREP, 7, "(%p) Ignoring CFRAME on hard disconnect target ep bExtOpcode[%u]", pEPD,
  778. (DWORD ) pData.pCFrame->bExtOpcode);
  779. Unlock(&pEPD->EPLock);
  780. return DPN_OK;
  781. }
  782. //hard disconnects are handled as a special case, as they're the only CFrame that
  783. //an ep mark as a hard disconnect source is interested in. Hence, we process them
  784. //here before making that check
  785. if (pData.pCFrame->bExtOpcode==FRAME_EXOPCODE_HARD_DISCONNECT)
  786. {
  787. DPFX(DPFPREP,7, "(%p) HARD_DISCONECT Frame Received", pEPD);
  788. //obviously we have to be connected to care about a disconnect event
  789. if(!(pEPD->ulEPFlags & EPFLAGS_STATE_CONNECTED))
  790. {
  791. DPFX(DPFPREP,1, "(%p) Received HARD_DISCONECT on non-connected endpoint, rejecting...", pEPD);
  792. RejectInvalidPacket(pEPD);
  793. //returns with EP lock released
  794. return DPN_OK;
  795. }
  796. //validate size of frame and its signature (if relevant)
  797. if (pEPD->ulEPFlags2 & EPFLAGS2_SIGNED_LINK)
  798. {
  799. if (dwDataLength < (sizeof(CFRAME)+sizeof(ULONGLONG)))
  800. {
  801. DPFX(DPFPREP,1, "(%p) Received short signed HARD DISCONNECT frame, rejecting...", pEPD);
  802. DNASSERTX(FALSE, 2);
  803. RejectInvalidPacket(pEPD);
  804. //returns with EP lock released
  805. return DPN_OK;
  806. }
  807. //for purposes of signing the sender places the next send seq number in the bRespID filed of the hard
  808. //disconnect frame. This is effectively tells us what signature version the hard disconnect was signed with
  809. if (ValidateIncomingFrameSig(pEPD, pData.pbyFrame, dwDataLength, pData.pCFrame->bRspID,
  810. (UNALIGNED ULONGLONG * ) (pData.pbyFrame+sizeof(CFRAME)))==FALSE)
  811. {
  812. DPFX(DPFPREP,1, "(%p) Dropping incorrectly signed hard disconnect frame", pEPD);
  813. DNASSERTX(FALSE, 2);
  814. RejectInvalidPacket(pEPD);
  815. //returns with EP lock released
  816. return DPN_OK;
  817. }
  818. }
  819. else if (dwDataLength < sizeof(CFRAME))
  820. {
  821. DPFX(DPFPREP,1, "(%p) Received short HARD DISCONNECT frame, rejecting...", pEPD);
  822. DNASSERTX(FALSE, 2);
  823. RejectInvalidPacket(pEPD);
  824. //returns with EP lock released
  825. return DPN_OK;
  826. }
  827. //looks like we've got a valid response to a hard disconnect sequence we instigated
  828. ProcessHardDisconnect(pEPD);
  829. //above call release ep lock
  830. return DPN_OK;
  831. }
  832. //as stated above, if ep is marked as a hard disconnect source then it ignores all other CFRAMES.
  833. //Hence, in that case we need proceed no further
  834. if (pEPD->ulEPFlags & EPFLAGS_HARD_DISCONNECT_SOURCE)
  835. {
  836. DPFX(DPFPREP, 7, "(%p) Ignoring CFRAME on hard disconnected source ep bExtOpcode[%u]", pEPD,
  837. (DWORD ) pData.pCFrame->bExtOpcode);
  838. RejectInvalidPacket(pEPD);
  839. //returns with EP lock released
  840. return DPN_OK;
  841. }
  842. switch(pData.pCFrame->bExtOpcode)
  843. {
  844. case FRAME_EXOPCODE_SACK:
  845. DPFX(DPFPREP,7, "(%p) SACK Frame Received", pEPD);
  846. // Check state
  847. if(!(pEPD->ulEPFlags & EPFLAGS_STATE_CONNECTED))
  848. {
  849. DPFX(DPFPREP,1, "(%p) Received SACK on non-connected endpoint, rejecting...", pEPD);
  850. DNASSERTX(FALSE, 4);
  851. RejectInvalidPacket(pEPD);
  852. //returns with EP lock released
  853. break;
  854. }
  855. // Drop short frames (should not happen)
  856. DWORD dwRequiredLength;
  857. dwRequiredLength = sizeof(SACKFRAME8);
  858. array_ptr = (ULONG * ) (pData.pSack+1);
  859. if (pData.pSack->bFlags & SACK_FLAGS_SACK_MASK1)
  860. {
  861. dwRequiredLength += sizeof(DWORD);
  862. }
  863. if (pData.pSack->bFlags & SACK_FLAGS_SACK_MASK2)
  864. {
  865. dwRequiredLength += sizeof(DWORD);
  866. }
  867. if (pData.pSack->bFlags & SACK_FLAGS_SEND_MASK1)
  868. {
  869. dwRequiredLength += sizeof(DWORD);
  870. }
  871. if (pData.pSack->bFlags & SACK_FLAGS_SEND_MASK2)
  872. {
  873. dwRequiredLength += sizeof(DWORD);
  874. }
  875. if (pEPD->ulEPFlags2 & EPFLAGS2_SIGNED_LINK)
  876. {
  877. dwRequiredLength += sizeof(ULONGLONG);
  878. }
  879. if (dwDataLength < dwRequiredLength)
  880. {
  881. DPFX(DPFPREP,1, "(%p) Dropping short ack frame on connected link", pEPD);
  882. DNASSERTX(FALSE, 2);
  883. Unlock(&pEPD->EPLock);
  884. return DPN_OK;
  885. }
  886. //for purposes of signing we use the next send sequence number of the sack frame as an indication
  887. //of what secret it was signed with. i.e. If the sack tells us that the next send is 27 then we treat it
  888. //as being signed the same as data frame 27 will be
  889. if ((pEPD->ulEPFlags2 & EPFLAGS2_SIGNED_LINK) &&
  890. ValidateIncomingFrameSig(pEPD, pData.pbyFrame, dwDataLength, pData.pSack->bNSeq,
  891. (UNALIGNED ULONGLONG * ) (pData.pbyFrame+dwRequiredLength-sizeof(ULONGLONG)))==FALSE)
  892. {
  893. DPFX(DPFPREP,1, "(%p) Dropping incorrectly signed ack frame", pEPD);
  894. DNASSERTX(FALSE, 2);
  895. Unlock(&pEPD->EPLock);
  896. return DPN_OK;
  897. }
  898. if( pData.pSack->bFlags & SACK_FLAGS_RESPONSE )
  899. {
  900. DPFX(DPFPREP,7, "(%p) ACK RESP RCVD: Retry=%d, N(R)=0x%02x", pEPD, pData.pSack->bRetry, pData.pSack->bNRcv);
  901. }
  902. mask1 = pData.pSack->bFlags & SACK_FLAGS_SACK_MASK1 ? *array_ptr++ : 0;
  903. mask2 = pData.pSack->bFlags & SACK_FLAGS_SACK_MASK2 ? *array_ptr++ : 0;
  904. DPFX(DPFPREP,7, "(%p) UpdateXmitState - N(R) 0x%02x Mask 0x%08x 0x%08x", pEPD, (DWORD)pData.pSack->bNRcv, mask2, mask1);
  905. UpdateXmitState(pEPD, pData.pSack->bNRcv, mask1, mask2, tNow);
  906. mask1 = pData.pSack->bFlags & SACK_FLAGS_SEND_MASK1 ? *array_ptr++ : 0;
  907. mask2 = pData.pSack->bFlags & SACK_FLAGS_SEND_MASK2 ? *array_ptr++ : 0;
  908. if(mask1 | mask2)
  909. {
  910. DPFX(DPFPREP,7, "(%p) Processing Send Mask N(S) 0x%02x Mask 0x%08x 0x%08x", pEPD, (DWORD) pData.pSack->bNSeq, mask2, mask1);
  911. ProcessSendMask(pEPD, pData.pSack->bNSeq, mask1, mask2, tNow, ppRcvBuffToFree);
  912. }
  913. if (! pEPD->blCompleteList.IsEmpty())
  914. {
  915. if (! (pEPD->ulEPFlags & EPFLAGS_IN_RECEIVE_COMPLETE))
  916. {
  917. DPFX(DPFPREP,8, "(%p) Completing Receives...", pEPD);
  918. pEPD->ulEPFlags |= EPFLAGS_IN_RECEIVE_COMPLETE; // ReceiveComplete will clear this flag when done
  919. ReceiveComplete(pEPD); // Deliver the goods, returns with EPLock released
  920. }
  921. else
  922. {
  923. DPFX(DPFPREP,7, "(%p) Already in ReceiveComplete, letting other thread handle receives", pEPD);
  924. Unlock(&pEPD->EPLock);
  925. }
  926. }
  927. else
  928. {
  929. Unlock(&pEPD->EPLock);
  930. }
  931. DPFX(DPFPREP,8, "(%p) Completing Sends...", pEPD);
  932. CompleteSends(pEPD);
  933. break;
  934. case FRAME_EXOPCODE_CONNECT:
  935. DPFX(DPFPREP,7, "(%p) CONNECT Frame Received", pEPD);
  936. if (dwDataLength < sizeof(CFRAME))
  937. {
  938. DPFX(DPFPREP,1, "(%p) Received short CONNECT frame, rejecting...", pEPD);
  939. DNASSERTX(FALSE, 2);
  940. RejectInvalidPacket(pEPD);
  941. //returns with EP lock released
  942. return DPN_OK;
  943. }
  944. ProcessConnectRequest(pSPD, pEPD, pData.pCFrame);
  945. //returns with EP lock released
  946. break;
  947. case FRAME_EXOPCODE_CONNECTED:
  948. DPFX(DPFPREP,7, "(%p) CONNECTED Frame Received", pEPD);
  949. if (dwDataLength < sizeof(CFRAME))
  950. {
  951. DPFX(DPFPREP,1, "(%p) Received short CONNECTED frame, rejecting...", pEPD);
  952. DNASSERTX(FALSE, 2);
  953. RejectInvalidPacket(pEPD);
  954. //returns with EP lock released
  955. return DPN_OK;
  956. }
  957. ProcessConnectedResponse(pSPD, pEPD, pData.pCFrame, tNow);
  958. break;
  959. case FRAME_EXOPCODE_HARD_DISCONNECT:
  960. DPFX(DPFPREP,7, "(%p) HARD_DISCONECT Frame Received", pEPD);
  961. if (dwDataLength < sizeof(CFRAME))
  962. {
  963. DPFX(DPFPREP,1, "(%p) Received short HARD_DISCONECT frame, rejecting...", pEPD);
  964. DNASSERTX(FALSE, 2);
  965. RejectInvalidPacket(pEPD);
  966. //returns with EP lock released
  967. return DPN_OK;
  968. }
  969. if(!(pEPD->ulEPFlags & EPFLAGS_STATE_CONNECTED))
  970. {
  971. DPFX(DPFPREP,1, "(%p) Received HARD_DISCONECT on non-connected endpoint, rejecting...", pEPD);
  972. RejectInvalidPacket(pEPD);
  973. //returns with EP lock released
  974. break;
  975. }
  976. ProcessHardDisconnect(pEPD);
  977. //returns with EP lock released
  978. break;
  979. case FRAME_EXOPCODE_CONNECTED_SIGNED:
  980. DPFX(DPFPREP,7, "(%p) CONNECTEDSIGNED Frame Received", pEPD);
  981. if (dwDataLength < sizeof(CFRAME_CONNECTEDSIGNED))
  982. {
  983. DPFX(DPFPREP,1, "(%p) Received short CONNECTEDSIGNED frame, rejecting...", pEPD);
  984. DNASSERTX(FALSE, 2);
  985. RejectInvalidPacket(pEPD);
  986. //returns with EP lock released
  987. return DPN_OK;
  988. }
  989. ProcessConnectedSignedResponse(pSPD, pEPD, (CFRAME_CONNECTEDSIGNED * ) pData.pCFrame, tNow);
  990. break;
  991. default:
  992. DPFX(DPFPREP,1, "(%p) Received invalid CFrame, rejecting...", pEPD);
  993. DNASSERTX(FALSE, 2);
  994. RejectInvalidPacket(pEPD);
  995. //above call will release ep lock
  996. break;
  997. }
  998. return DPN_OK;
  999. }
  1000. /*
  1001. ** Crack Data Frame
  1002. **
  1003. ** In addition to delivering data contained in the frame, we also must
  1004. ** use the included state info to drive the transmission process. We will update
  1005. ** our link state according to this info and see if we need to put this session
  1006. ** back into the sending pipeline.
  1007. **
  1008. ** Of course, data will only be delivered if we have completed an entire message.
  1009. **
  1010. ** This is called with EP lock held and returns with it released.
  1011. ** CRITICAL SECTION NOTE -- It might seem rather lavish the way we hold the EPD->StateLock
  1012. ** thru this entire routine, but anything less would require an obscene level of complexity
  1013. ** to keep ironed out. This is why I defer all ReceiveIndications and buffer mappings until
  1014. ** the end of the routine when the Lock can be released.
  1015. **
  1016. */
  1017. #undef DPF_MODNAME
  1018. #define DPF_MODNAME "CrackDataFrame"
  1019. HRESULT CrackDataFrame(PSPD pSPD, PEPD pEPD, PSPRECEIVEDBUFFER pRcvBuffer, DWORD tNow, PSPRECEIVEDBUFFER* ppRcvBuffToFree)
  1020. {
  1021. DWORD dwDataLength = pRcvBuffer->BufferDesc.dwBufferSize;
  1022. PDFRAME pFrame = (PDFRAME) (pRcvBuffer->BufferDesc.pBufferData);
  1023. DWORD dwNumCoalesceHeaders = 0;
  1024. PRCD pRCD;
  1025. ULONG bit;
  1026. UINT count;
  1027. UNALIGNED ULONG *array_ptr;
  1028. ULONG MaskArray[4];
  1029. ULONG mask;
  1030. //This is the DFrame header+Masks+Signature (if present), it doesn't include the coalesence headers (if present)
  1031. DWORD dwHeaderSize;
  1032. //As we walk the coalesce headers validating the packet we store a pointer to the first reliable
  1033. //coalesced data block we see. This is then used if we're full signing and this frame is a candidate
  1034. //for modifying the remote secret we don't have to walk the packet againt to find the relevant user data
  1035. BYTE * pbyRelData=NULL;
  1036. DWORD dwRelDataSize;
  1037. AssertCriticalSectionIsTakenByThisThread(&pEPD->EPLock, TRUE);
  1038. // Data on an unconnected link
  1039. //
  1040. // There are two possibilities (as I see it today). Either we have dropped our link because partner
  1041. // went silent, but now he has started sending again. OR We have disconnected and are now reconnecting
  1042. // but there are some old data frames bouncing around (less likely).
  1043. //
  1044. // If we have dropped and partner is just figuring it out, we must kill the endpoint or else it will hang
  1045. // around forever after partner stops bothering us. We can help out partner by sending him a DISC frame
  1046. // so he knows that we arent playing anymore, buts its not technically necessary.
  1047. //
  1048. // In the second case, we do not want to close the EP because that will crush the session startup that
  1049. // is supposedly in progress. Therefore, if we are not in a DORMANT state, then we know a session
  1050. // startup is in progress, and we will let the EP remain open.
  1051. if(!(pEPD->ulEPFlags & EPFLAGS_STATE_CONNECTED))
  1052. {
  1053. DPFX(DPFPREP,1, "(%p) Received data on non-connected endpoint, rejecting...", pEPD);
  1054. DNASSERTX(FALSE, 4);
  1055. RejectInvalidPacket(pEPD);
  1056. //above call will release ep lock
  1057. return DPN_OK; // do not accept data before we have connected
  1058. }
  1059. BYTE bSeq = pFrame->bSeq;
  1060. DPFX(DPFPREP,7, "(%p) Data Frame Arrives Seq=%x; N(R)=%x", pEPD, bSeq, pEPD->bNextReceive);
  1061. DWORD dwRequiredLength = sizeof(DFRAME) + GetDFrameMaskHeaderSize(pFrame->bControl);
  1062. if (dwDataLength < dwRequiredLength)
  1063. {
  1064. DPFX(DPFPREP,1, "(%p) Dropping short frame on connected link", pEPD);
  1065. DNASSERTX(FALSE, 2);
  1066. Unlock(&pEPD->EPLock);
  1067. return DPN_OK;
  1068. }
  1069. //if we've got a signed link, then the next thing in the header should be the signature
  1070. if (pEPD->ulEPFlags2 & EPFLAGS2_SIGNED_LINK)
  1071. {
  1072. UNALIGNED ULONGLONG * pullSig=(UNALIGNED ULONGLONG * ) (((BYTE * ) pFrame)+dwRequiredLength);
  1073. dwRequiredLength+=sizeof(ULONGLONG);
  1074. if (dwDataLength<dwRequiredLength)
  1075. {
  1076. DPFX(DPFPREP,1, "(%p) Dropping data frame too short to contain signature on signed link", pEPD);
  1077. DNASSERTX(FALSE, 2);
  1078. Unlock(&pEPD->EPLock);
  1079. return DPN_OK;
  1080. }
  1081. //check if the signature is valid
  1082. if (ValidateIncomingFrameSig(pEPD, (BYTE * ) pFrame, dwDataLength, pFrame->bSeq, pullSig)==FALSE)
  1083. {
  1084. DPFX(DPFPREP,1, "(%p) Dropping data frame with invalid signature on signed link", pEPD);
  1085. DNASSERTX(FALSE, 2);
  1086. Unlock(&pEPD->EPLock);
  1087. return DPN_OK;
  1088. }
  1089. }
  1090. //at this point the dwRequiredLength is equal to the size of DFrame header, plus masks, plus signature (if present)
  1091. dwHeaderSize=dwRequiredLength;
  1092. //If we've got a link that supports signing then we'll expect new style keep alives that contain
  1093. //a DWORD session identity as data. These frames are marked by a KEEPALIVE control bit being flipped
  1094. if ((pEPD->ulEPFlags2 & EPFLAGS2_SUPPORTS_SIGNING) && (pFrame->bControl & PACKET_CONTROL_KEEPALIVE))
  1095. {
  1096. //take pointer to where the session identity should be in the keep alive
  1097. DWORD * pdwKeepAliveSessID=(DWORD * ) (((BYTE * ) pFrame)+dwRequiredLength);
  1098. //ensure that the frame is big enough to hold the required data
  1099. dwRequiredLength+=sizeof(DWORD);
  1100. if (dwDataLength < dwRequiredLength)
  1101. {
  1102. DPFX(DPFPREP,1, "(%p) Dropping short keepalive frame on connected link", pEPD);
  1103. DNASSERTX(FALSE, 2);
  1104. Unlock(&pEPD->EPLock);
  1105. return DPN_OK;
  1106. }
  1107. //We should screen out keep alives whose session identity doesn't match what we expect.
  1108. //This handles the case when one end has stopped and then restarted. Rather than responding
  1109. //to what is now an outdated KeepAlive we'll ignore it, causing the other end to hopefully time out
  1110. if (*pdwKeepAliveSessID!=pEPD->dwSessID)
  1111. {
  1112. DPFX(DPFPREP,1, "(%p) Dropping outdated keepalive frame on connected link KeepAliveSessID[%u] dwSessId[%u]",
  1113. pEPD, *pdwKeepAliveSessID, pEPD->dwSessID);
  1114. Unlock(&pEPD->EPLock);
  1115. return DPN_OK;
  1116. }
  1117. }
  1118. else if (pFrame->bControl & PACKET_CONTROL_COALESCE)
  1119. {
  1120. PCOALESCEHEADER pCoalesceHeaders = (PCOALESCEHEADER)((BYTE*)pFrame + dwRequiredLength);
  1121. DWORD dwCoalesceFrameSize;
  1122. BYTE bCommand;
  1123. DWORD dwTotalCoalesceDataSize=0;
  1124. // Keep looping until we see the last coalesce header.
  1125. do
  1126. {
  1127. // See if we can have a coalesce header
  1128. dwRequiredLength+=sizeof(COALESCEHEADER);
  1129. if (dwDataLength < dwRequiredLength )
  1130. {
  1131. DPFX(DPFPREP,1, "(%p) Dropping short coalesce frame (hdr) on connected link", pEPD);
  1132. DNASSERTX(FALSE, 2);
  1133. Unlock(&pEPD->EPLock);
  1134. return DPN_OK;
  1135. }
  1136. // Now that we know it's valid we can touch the header. Figure out the size.
  1137. dwCoalesceFrameSize = pCoalesceHeaders[dwNumCoalesceHeaders].bSize;
  1138. bCommand = pCoalesceHeaders[dwNumCoalesceHeaders].bCommand;
  1139. dwCoalesceFrameSize |= (DWORD) (bCommand & (PACKET_COMMAND_COALESCE_BIG_1 | PACKET_COMMAND_COALESCE_BIG_2 | PACKET_COMMAND_COALESCE_BIG_3)) << 5;
  1140. if (dwCoalesceFrameSize == 0)
  1141. {
  1142. DPFX(DPFPREP,1, "(%p) Dropping 0 byte coalesce frame on connected link", pEPD);
  1143. DNASSERTX(FALSE, 2);
  1144. Unlock(&pEPD->EPLock);
  1145. return DPN_OK;
  1146. }
  1147. //if we've hit the first reliable coalesced frame then store the offset from
  1148. //the end of the coalesce headers to the start of its data
  1149. if (pbyRelData==NULL && (bCommand & PACKET_COMMAND_RELIABLE))
  1150. {
  1151. pbyRelData=((BYTE * ) pFrame)+dwTotalCoalesceDataSize;
  1152. dwRelDataSize=dwCoalesceFrameSize;
  1153. }
  1154. // Round frame size up to the nearest DWORD alignment unless it's the last subframe.
  1155. if (! (bCommand & PACKET_COMMAND_END_COALESCE))
  1156. {
  1157. dwCoalesceFrameSize = (dwCoalesceFrameSize + 3) & (~3);
  1158. }
  1159. dwTotalCoalesceDataSize+=dwCoalesceFrameSize;
  1160. dwNumCoalesceHeaders++;
  1161. }
  1162. while (! (bCommand & PACKET_COMMAND_END_COALESCE));
  1163. // If we have an odd number of coalesce headers, there needs to be padding for DWORD
  1164. // alignment.
  1165. DBG_CASSERT(sizeof(COALESCEHEADER) == 2);
  1166. if ((dwNumCoalesceHeaders & 1) != 0)
  1167. {
  1168. dwRequiredLength += 2;
  1169. }
  1170. //if we found a reliable coalesce header in there, shift the offset to its data by dwRequiredLength
  1171. //this adjustment is necessary because when we first assign the pointer we ignore the presence of
  1172. //any headers, hence its off by packet header+coalesce header sizes
  1173. if (pbyRelData)
  1174. {
  1175. pbyRelData+=dwRequiredLength;
  1176. }
  1177. //check that the frame holds all the coalesced user data we expect it to
  1178. dwRequiredLength+=dwTotalCoalesceDataSize;
  1179. if (dwDataLength < dwRequiredLength)
  1180. {
  1181. DPFX(DPFPREP,1, "(%p) Dropping short coalesce frame (user data) on connected link", pEPD);
  1182. DNASSERTX(FALSE, 2);
  1183. Unlock(&pEPD->EPLock);
  1184. return DPN_OK;
  1185. }
  1186. }
  1187. // Make sure that new frame is within our receive window
  1188. if((BYTE)(bSeq - pEPD->bNextReceive) >= (BYTE) MAX_FRAME_OFFSET)
  1189. {
  1190. DPFX(DPFPREP,1, "(%p) Rejecting frame that is out of receive window SeqN=%x, N(R)=%x", pEPD, bSeq, pEPD->bNextReceive);
  1191. pEPD->ulEPFlags |= EPFLAGS_DELAY_ACKNOWLEDGE;
  1192. if(pFrame->bCommand & PACKET_COMMAND_POLL)
  1193. {
  1194. // Is he asking for an immediate response
  1195. DPFX(DPFPREP,7, "(%p) Sending Ack Frame", pEPD);
  1196. SendAckFrame(pEPD, 1); // This unlocks the EPLock since param 2 is 1
  1197. }
  1198. else if(pEPD->DelayedAckTimer == 0)
  1199. {
  1200. // If timer is not running better start it now
  1201. LOCK_EPD(pEPD, "LOCK (DelayedAckTimer)"); // Bump RefCnt for new timer
  1202. DPFX(DPFPREP,7, "(%p) Setting Delayed Ack Timer", pEPD);
  1203. ScheduleProtocolTimer(pSPD, SHORT_DELAYED_ACK_TIMEOUT, 0, DelayedAckTimeout,
  1204. (PVOID) pEPD, &pEPD->DelayedAckTimer, &pEPD->DelayedAckTimerUnique);
  1205. Unlock(&pEPD->EPLock);
  1206. }
  1207. else
  1208. {
  1209. Unlock(&pEPD->EPLock);
  1210. }
  1211. return DPN_OK;
  1212. }
  1213. // Determine what's in the variable length header
  1214. mask = (pFrame->bControl & PACKET_CONTROL_VARIABLE_MASKS) / PACKET_CONTROL_SACK_MASK1;
  1215. if(mask)
  1216. {
  1217. array_ptr = (ULONG * ) (pFrame+1);
  1218. for(count = 0; count < 4; count++, mask >>= 1)
  1219. {
  1220. MaskArray[count] = (mask & 1) ? *array_ptr++ : 0;
  1221. }
  1222. // See if this frame Acknowledges any of our outstanding data
  1223. DPFX(DPFPREP,7, "(%p) UpdateXmitState - N(R) 0x%02x Mask 0x%08x 0x%08x", pEPD, (DWORD)pFrame->bNRcv, MaskArray[1], MaskArray[0]);
  1224. UpdateXmitState(pEPD, pFrame->bNRcv, MaskArray[0], MaskArray[1], tNow); // Do this before taking StateLock
  1225. // Determine if there is a SendMask in this frame which identifies dropped frames as unreliable
  1226. if(pFrame->bControl & (PACKET_CONTROL_SEND_MASK1 | PACKET_CONTROL_SEND_MASK2))
  1227. {
  1228. DPFX(DPFPREP,7, "(%p) Processing Send Mask N(S) 0x%02x Mask 0x%08x 0x%08x", pEPD, (DWORD)pFrame->bSeq, MaskArray[3], MaskArray[2]);
  1229. ProcessSendMask(pEPD, pFrame->bSeq, MaskArray[2], MaskArray[3], tNow, ppRcvBuffToFree);
  1230. // NOTE: ProcessSendMask may have advanced N(R)
  1231. // Re-verify that the new frame is within our receive window
  1232. if((BYTE)(bSeq - pEPD->bNextReceive) >= (BYTE) MAX_FRAME_OFFSET)
  1233. {
  1234. DPFX(DPFPREP,1, "(%p) ProcessSendMask advanced N(R) such that the current frame is out of window, rejecting receive, N(R)=0x%02x, Seq=0x%02x", pEPD, (DWORD)pEPD->bNextReceive, (DWORD)pFrame->bSeq);
  1235. Unlock(&pEPD->EPLock);
  1236. return DPN_OK;
  1237. }
  1238. }
  1239. }
  1240. else
  1241. {
  1242. DPFX(DPFPREP,7, "(%p) UpdateXmitState - N(R) 0x%02x No Mask", pEPD, (DWORD)pFrame->bNRcv);
  1243. UpdateXmitState(pEPD, pFrame->bNRcv, 0, 0, tNow); // Do this before taking StateLock
  1244. }
  1245. // We can receive this frame.
  1246. // If we're full signing, its got reliable data in it and its earlier in the sequence space than the current frame we're proposing
  1247. // to modify the remote secret with, then its the new candidate for being the remote secret modifier
  1248. if ((pEPD->ulEPFlags2 & EPFLAGS2_FULL_SIGNED_LINK) && (pFrame->bCommand & PACKET_COMMAND_RELIABLE) &&
  1249. (pFrame->bSeq<pEPD->byRemoteSecretModifierSeqNum) && (pFrame->bControl & PACKET_CONTROL_KEEPALIVE)==0)
  1250. {
  1251. //if it was a coalesced frame then we'll already have an offset to a block of reliable data
  1252. //if it wasn't then we simply pick the entire user data contents
  1253. if (pbyRelData==NULL)
  1254. {
  1255. DNASSERT((pFrame->bControl & PACKET_CONTROL_COALESCE)==0);
  1256. pbyRelData=((PBYTE) pFrame) + dwHeaderSize;
  1257. dwRelDataSize=dwDataLength - dwHeaderSize;
  1258. }
  1259. pEPD->byRemoteSecretModifierSeqNum=pFrame->bSeq;
  1260. pEPD->ullRemoteSecretModifier=GenerateRemoteSecretModifier(pbyRelData, dwRelDataSize);
  1261. }
  1262. //Copy relevant info into Receive descriptor
  1263. if((pRCD = (PRCD)POOLALLOC(MEMID_RCD, &RCDPool)) == NULL)
  1264. {
  1265. DPFX(DPFPREP,0, "(%p) Failed to allocate new RCD", pEPD);
  1266. Unlock(&pEPD->EPLock);
  1267. return DPN_OK;
  1268. }
  1269. pEPD->ulEPFlags |= EPFLAGS_DELAY_ACKNOWLEDGE; // State has changed. Make sure it gets sent.
  1270. DNASSERT(pRcvBuffer->pNext == NULL);
  1271. DNASSERT(pRcvBuffer->dwProtocolData == 0);
  1272. DNASSERT(pRcvBuffer->pServiceProviderDescriptor == 0);
  1273. pRCD->bSeq = bSeq;
  1274. pRCD->bFrameFlags = pFrame->bCommand;
  1275. pRCD->bFrameControl = pFrame->bControl;
  1276. pRCD->pbData = (PBYTE) (((PBYTE) pFrame) + dwHeaderSize);
  1277. pRCD->uiDataSize = dwDataLength - dwHeaderSize;
  1278. pRCD->tTimestamp = tNow;
  1279. pRCD->dwNumCoalesceHeaders = dwNumCoalesceHeaders;
  1280. pRCD->pRcvBuff = pRcvBuffer;
  1281. // Update our receiving state info.
  1282. //
  1283. // RCDs go onto one of two queues. If it is the next numbered (expected) frame then it is
  1284. // placed on the ReceiveList (in EPD). If this frame completes a message it can now be
  1285. // indicated. If this frame fills a hole left by previous frames then a condensation with
  1286. // the second list must occur.
  1287. // If it is not the next numbered frame then it is placed, in order, on the MisOrdered frame
  1288. // list, and the bitmask is updated.
  1289. //
  1290. // Condensation of lists is performed by testing the LSB of the ReceiveMask. Each time LSB is set,
  1291. // the first frame on the list can be moved to the ReceiveList, and the mask is shifted right.
  1292. // As each frame is moved to the ReceiveList, the EOM flag must be checked for and if set, then
  1293. // everything on the ReceiveList should be moved to the CompleteList for indication to the user.
  1294. BOOL fPoll = pFrame->bCommand & PACKET_COMMAND_POLL;
  1295. BOOL fSendInstantAck = pFrame->bControl & PACKET_CONTROL_END_STREAM;
  1296. if(bSeq == pEPD->bNextReceive)
  1297. {
  1298. // Frame is the next expected # in sequence
  1299. DPFX(DPFPREP,8, "(%p) Receiving In-Order Frame, pRCD[%p]", pEPD, pRCD);
  1300. ReceiveInOrderFrame(pEPD, pRCD, ppRcvBuffToFree); // Build frame into message AND move adjacent frames off OddFrameList
  1301. // NOTE: ReceiveInOrderFrame may have caused the frame to be freed via DropReceive
  1302. // so we absolutely must not use pFrame past this point!
  1303. // See if we need to respond right away...
  1304. //
  1305. // Because there are lots of way to generate POLL bits (full window, empty queue, poll count) we sometimes find ourselves
  1306. // generating too much dedicated ack-traffic. Therefore, we will treat the POLL not as Respond-Immediately but instead as
  1307. // Respond-Soon. We will not wait the full Delayed_Ack_Timeout interval but we will wait long enough to allow a quick piggyback
  1308. // response (say 5ms) (we may want this longer on a slow connection...)
  1309. // Is he asking for an instant response?
  1310. if(fSendInstantAck)
  1311. {
  1312. DPFX(DPFPREP,7, "(%p) Sending Ack Frame", pEPD);
  1313. SendAckFrame(pEPD, 0); // Send Ack w/timing info
  1314. }
  1315. // Is he asking for a response soon?
  1316. else if(fPoll)
  1317. {
  1318. if(pEPD->DelayedAckTimer != NULL)
  1319. {
  1320. DPFX(DPFPREP,7, "(%p) Cancelling Delayed Ack Timer", pEPD);
  1321. if(CancelProtocolTimer(pSPD, pEPD->DelayedAckTimer, pEPD->DelayedAckTimerUnique)!= DPN_OK)
  1322. {
  1323. DPFX(DPFPREP,7, "(%p) Cancelling Delayed Ack Timer Failed", pEPD);
  1324. LOCK_EPD(pEPD, "LOCK (re-start delayed ack timer)");
  1325. }
  1326. }
  1327. else
  1328. {
  1329. LOCK_EPD(pEPD, "LOCK (start short delayed ack timer)");
  1330. }
  1331. DPFX(DPFPREP,7, "Delaying POLL RESP");
  1332. pEPD->ulEPFlags |= EPFLAGS_DELAY_ACKNOWLEDGE;
  1333. DPFX(DPFPREP,7, "(%p) Setting Delayed Ack Timer", pEPD);
  1334. ScheduleProtocolTimer(pSPD, 4, 4, DelayedAckTimeout, (PVOID) pEPD,
  1335. &pEPD->DelayedAckTimer, &pEPD->DelayedAckTimerUnique);
  1336. }
  1337. else if(pEPD->DelayedAckTimer == 0)
  1338. {
  1339. // If timer is not running better start it now
  1340. LOCK_EPD(pEPD, "LOCK (DelayedAckTimer)"); // Bump RefCnt for timer
  1341. ScheduleProtocolTimer(pSPD, DELAYED_ACK_TIMEOUT, 0, DelayedAckTimeout, (PVOID) pEPD,
  1342. &pEPD->DelayedAckTimer, &pEPD->DelayedAckTimerUnique);
  1343. }
  1344. } // IF frame is in order
  1345. else
  1346. {
  1347. // Frame arrives out of order
  1348. // bit location in mask for this frame
  1349. bit = (BYTE) ((bSeq - pEPD->bNextReceive) - 1);
  1350. // Make sure this is not a duplicate frame
  1351. if( ((bit < 32) && (pEPD->ulReceiveMask & (1 << bit))) || ((bit > 31) && (pEPD->ulReceiveMask2 & (1 << (bit - 32)))) )
  1352. {
  1353. DPFX(DPFPREP,7, "(%p) REJECT DUPLICATE OUT-OF-ORDER Frame Seq=%x", pEPD, bSeq);
  1354. Unlock(&pEPD->EPLock);
  1355. pRCD->pRcvBuff = NULL;
  1356. RELEASE_RCD(pRCD);
  1357. return DPN_OK;
  1358. }
  1359. DPFX(DPFPREP,8, "(%p) Receiving Out-of-Order Frame, pRCD[%p]", pEPD, pRCD);
  1360. ReceiveOutOfOrderFrame(pEPD, pRCD, bit, ppRcvBuffToFree);
  1361. // NOTE: ReceiveOutOfOrderFrame may have caused the frame to be freed via DropReceive
  1362. // so we absolutely must not use pFrame past this point!
  1363. if(fPoll)
  1364. {
  1365. if(pEPD->DelayedAckTimer != NULL)
  1366. {
  1367. DPFX(DPFPREP,7, "(%p) Cancelling Delayed Ack Timer", pEPD);
  1368. if(CancelProtocolTimer(pSPD, pEPD->DelayedAckTimer, pEPD->DelayedAckTimerUnique)!= DPN_OK)
  1369. {
  1370. DPFX(DPFPREP,7, "(%p) Cancelling Delayed Ack Timer Failed", pEPD);
  1371. LOCK_EPD(pEPD, "LOCK (re-start delayed ack timer)");
  1372. }
  1373. // Start an abreviated delayed ack timer in case NACK gets cancelled
  1374. }
  1375. else
  1376. {
  1377. LOCK_EPD(pEPD, "LOCK (start short delayed ack timer)");
  1378. }
  1379. DPFX(DPFPREP,7, "Delaying POLL RESP");
  1380. pEPD->ulEPFlags |= EPFLAGS_DELAY_ACKNOWLEDGE;
  1381. DPFX(DPFPREP,7, "(%p) Setting Delayed Ack Timer", pEPD);
  1382. ScheduleProtocolTimer(pSPD, 5, 5, DelayedAckTimeout, (PVOID) pEPD,
  1383. &pEPD->DelayedAckTimer, &pEPD->DelayedAckTimerUnique);
  1384. }
  1385. }
  1386. // EPD->StateLock is still HELD
  1387. //
  1388. // We use a FLAG for exclusive access to ReceiveComplete routine. This is safe because the flag is only
  1389. // tested and modified while holding the EPD->StateLock. Lets be sure to keep it that way...
  1390. if (! pEPD->blCompleteList.IsEmpty())
  1391. {
  1392. if (! (pEPD->ulEPFlags & EPFLAGS_IN_RECEIVE_COMPLETE))
  1393. {
  1394. DPFX(DPFPREP,8, "(%p) Completing Receives...", pEPD);
  1395. pEPD->ulEPFlags |= EPFLAGS_IN_RECEIVE_COMPLETE; // ReceiveComplete will clear this flag when done
  1396. ReceiveComplete(pEPD); // Deliver the goods, returns with EPLock released
  1397. }
  1398. else
  1399. {
  1400. DPFX(DPFPREP,7, "(%p) Already in ReceiveComplete, letting other thread handle receives", pEPD);
  1401. Unlock(&pEPD->EPLock);
  1402. }
  1403. }
  1404. else
  1405. {
  1406. Unlock(&pEPD->EPLock);
  1407. }
  1408. DPFX(DPFPREP,8, "(%p) Completing Sends...", pEPD);
  1409. CompleteSends(pEPD);
  1410. return DPNERR_PENDING;
  1411. }
  1412. /*
  1413. ** Receive In Order Frame
  1414. **
  1415. ** The interesting part of this function is moving frames off of the OddFrameList that
  1416. ** the new frame adjoins. This may also be called with a NULL frame which will happen when
  1417. ** a cancelled frame is the next-in-order receive.
  1418. **
  1419. ** One result of having cancelled frames running around is that we may miss the SOM or EOM
  1420. ** flags which delimit messages. Therefore, we must watch as we assemble messages that we do not
  1421. ** see unexpected flags, ie a new message w/o an SOM on first frame which means that part of the
  1422. ** message must have been lost, and the whole thing must be trashed...
  1423. **
  1424. ** ** EPLOCK is HELD through this entire function **
  1425. */
  1426. #undef DPF_MODNAME
  1427. #define DPF_MODNAME "ReceiveInOrderFrame"
  1428. VOID
  1429. ReceiveInOrderFrame(PEPD pEPD, PRCD pRCD, PSPRECEIVEDBUFFER* ppRcvBuffToFree)
  1430. {
  1431. PSPD pSPD = pEPD->pSPD;
  1432. CBilink *pLink;
  1433. UINT flag;
  1434. AssertCriticalSectionIsTakenByThisThread(&pEPD->EPLock, TRUE);
  1435. // Condensing Loop WHILE (Next In-Order Frame has been received)
  1436. do
  1437. {
  1438. ASSERT(pRCD->bSeq == pEPD->bNextReceive);
  1439. pEPD->tLastDataFrame = pRCD->tTimestamp; // Always keep the receive time of (N(R) - 1)
  1440. pEPD->bLastDataRetry = (pRCD->bFrameControl & PACKET_CONTROL_RETRY);
  1441. #ifdef DBG
  1442. pEPD->bLastDataSeq = pRCD->bSeq;
  1443. #endif // DBG
  1444. pRCD->pMsgLink = NULL;
  1445. if(pEPD->pNewMessage == NULL)
  1446. {
  1447. // Add this frame to the in-order rcv list
  1448. // pNewMessage implies we have no current message, head or tail
  1449. ASSERT(pEPD->pNewTail == NULL);
  1450. if(!(pRCD->bFrameFlags & PACKET_COMMAND_NEW_MSG))
  1451. {
  1452. // There is no NEW_MESSAGE flag on the first frame we see. We must
  1453. // have lost the first frame or this is an invalid packet. We can throw
  1454. // this frame away...
  1455. DPFX(DPFPREP,1, "(%p) NEW_MESSAGE flag not set on first frame of message, scrapping frame (%x)", pEPD, pRCD->bSeq);
  1456. pRCD->ulRFlags |= RFLAGS_FRAME_LOST;
  1457. pRCD->bFrameFlags |= PACKET_COMMAND_END_MSG; // Turn this on so we will release buffer right away
  1458. }
  1459. //N.B. We don't bother checking to see if the first frame exceeds the maximum message size
  1460. //we accept. If its a single frame message then we'll handle scanning out oversize messages
  1461. //in the ReceiveComplete function. If its the start of a message spread over multiple frames
  1462. //then we'll drop everything when the second frame arrives
  1463. // Even if we get rid of it, we will need these below
  1464. pEPD->pNewMessage = pRCD;
  1465. pEPD->pNewTail = pRCD;
  1466. pRCD->uiFrameCount = 1;
  1467. pRCD->uiMsgSize = pRCD->uiDataSize;
  1468. DPFX(DPFPREP,8, "(%p) Queuing Frame (NEW MESSAGE) (%x)", pEPD, pRCD->bSeq);
  1469. }
  1470. else
  1471. {
  1472. if (pRCD->bFrameFlags & PACKET_COMMAND_NEW_MSG)
  1473. {
  1474. // We are getting the start of a new message in the start of an existing message, drop it all
  1475. DPFX(DPFPREP,1, "(%p) NEW_MESSAGE flag set in the middle of existing message, scrapping message (%x, %x)", pEPD, pEPD->pNewMessage->bSeq, pRCD->bSeq);
  1476. pRCD->ulRFlags |= RFLAGS_FRAME_LOST;
  1477. pRCD->bFrameFlags |= PACKET_COMMAND_END_MSG; // Turn this on so we will release buffer right away
  1478. }
  1479. ASSERT((pEPD->pNewTail->bSeq) == (BYTE)(pRCD->bSeq - 1)); // Make sure they stay sequential
  1480. pEPD->pNewTail->pMsgLink = pRCD;
  1481. pEPD->pNewMessage->uiFrameCount++;
  1482. pEPD->pNewMessage->uiMsgSize += pRCD->uiDataSize;
  1483. pEPD->pNewMessage->ulRFlags |= (pRCD->ulRFlags & RFLAGS_FRAME_LOST);// UNION FRAME_LOST flag from all frames of a message
  1484. pEPD->pNewTail = pRCD;
  1485. if (pEPD->pNewMessage->uiMsgSize>pSPD->pPData->dwMaxRecvMsgSize)
  1486. {
  1487. DPFX(DPFPREP,1, "(%p) Message size exceeds maximum accepted. Dropping frames in middle of multipart "
  1488. "receive uiMsgSize[%u], MaxRecvMsgSize[%u]", pEPD, pEPD->pNewMessage->uiMsgSize,
  1489. pSPD->pPData->dwMaxRecvMsgSize);
  1490. pRCD->ulRFlags |= RFLAGS_FRAME_LOST;
  1491. pRCD->bFrameFlags |= PACKET_COMMAND_END_MSG; // Turn this on so we will release buffer right away
  1492. }
  1493. DPFX(DPFPREP,8, "(%p) Queuing Frame (ON TAIL) (%x)", pEPD, pRCD->bSeq);
  1494. }
  1495. if(pRCD->bFrameFlags & PACKET_COMMAND_END_MSG)
  1496. {
  1497. // Either this frame completes a message or we decided to drop this one above
  1498. // All frames on the ReceiveList should now be removed and delivered
  1499. // Get either the message we are dropping above, or the beginning of the sequence of messages we are completing
  1500. pRCD = pEPD->pNewMessage;
  1501. pEPD->pNewMessage = NULL;
  1502. if(pRCD->ulRFlags & RFLAGS_FRAME_LOST)
  1503. {
  1504. // We need to throw this away
  1505. DPFX(DPFPREP,7, "(%p) Throwing away message with missing frames (%x, %x)", pEPD, pRCD->bSeq, pEPD->pNewTail->bSeq);
  1506. pEPD->pNewTail = NULL;
  1507. DropReceive(pEPD, pRCD, ppRcvBuffToFree);
  1508. }
  1509. else
  1510. {
  1511. // We need to complete this sequence
  1512. pRCD->blCompleteLinkage.InsertBefore( &pEPD->blCompleteList); // place on end of Completion list
  1513. DPFX(DPFPREP,7, "(%p) Adding msg to complete list FirstSeq=%x, LastSeq=%x QueueSize=%d",
  1514. pEPD, pRCD->bSeq, pEPD->pNewTail->bSeq, pEPD->uiCompleteMsgCount);
  1515. pEPD->pNewTail = NULL;
  1516. pEPD->uiCompleteMsgCount++;
  1517. #ifdef DBG
  1518. // This is guaranteed to at least be 1 since we just incremented it above
  1519. if ((pEPD->uiCompleteMsgCount % 128) == 0)
  1520. {
  1521. DPFX(DPFPREP, 1, "(%p) Receives waiting to be completed count has grown to %d, app is slow processing receives", pEPD, pEPD->uiCompleteMsgCount);
  1522. }
  1523. #endif // DBG
  1524. }
  1525. }
  1526. // Since we are allowing out of order indication of receives it is possible that frames later than
  1527. // the new one have already been indicated. This means that there may be bits set in the ReceiveMask
  1528. // whose correlating frames do not need to be indicated. The most straightforward way to implement this
  1529. // is to leave the early-indicated frames in the list, but mark them as INDICATED_NONSEQ. So inside this
  1530. // master DO loop there will be an inner DO loop which passes over INDICATED frames and just takes them off
  1531. // the list.
  1532. //
  1533. // Now its possible that a NonSeq indicated frame is still sitting on the CompleteList awaiting indication,
  1534. // so I am using a ref count. An extra ref is added when a frame is completed non-seq. When a completed frame
  1535. // is removed below we will release one reference, and the indication code will release one reference when it
  1536. // finishes on that end. Happily, we can release the actual buffers while the RCD turd is still sitting on the
  1537. // OddFrameList.
  1538. BOOL fIndicatedNonSeq = FALSE;
  1539. do
  1540. {
  1541. flag = pEPD->ulReceiveMask & 1; // set flag if next frame in stream is present
  1542. pEPD->bNextReceive += 1; // Update receive window
  1543. RIGHT_SHIFT_64(pEPD->ulReceiveMask2, pEPD->ulReceiveMask);// shift mask because base has changed
  1544. DPFX(DPFPREP,7, "(%p) N(R) incremented to %x, Mask %x %x", pEPD, pEPD->bNextReceive, pEPD->ulReceiveMask2, pEPD->ulReceiveMask);
  1545. //if we're fully signing the link and we just we got 3/4's way through the sequence space then
  1546. //we're now in a position to modify the remote secret. We'll still need to hang onto the
  1547. //existing secret because for the next 1/4 of the sequence space we'll still need to use it
  1548. //to validate incoming data
  1549. if ((pEPD->ulEPFlags2 & EPFLAGS2_FULL_SIGNED_LINK) && (pEPD->bNextReceive==SEQ_WINDOW_3Q))
  1550. {
  1551. pEPD->ullOldRemoteSecret=pEPD->ullCurrentRemoteSecret;
  1552. pEPD->byRemoteSecretModifierSeqNum=SEQ_WINDOW_3Q;
  1553. pEPD->ullCurrentRemoteSecret=GenerateNewSecret(pEPD->ullCurrentRemoteSecret, pEPD->ullRemoteSecretModifier);
  1554. }
  1555. if(flag)
  1556. {
  1557. // The next frame in the sequence has arrived already since low bit of ulReceiveMask was set
  1558. // Several things can happen here:
  1559. // 1) We are in the middle of a message, in which case, its next piece is on the out of order list
  1560. // 2) We have just finished a message, which leaves two subcases:
  1561. // a) We are beginning a new message. In this case our first piece is on the out of order list
  1562. // b) Out-of-order non-sequential messages have completed while we were completing our in-order message
  1563. // In this case there are some already indicated RCDs on the out of order list, and a new partial
  1564. // message may or may not follow.
  1565. pLink = pEPD->blOddFrameList.GetNext();
  1566. ASSERT(pLink != &pEPD->blOddFrameList); // Make sure we didn't run out of RCDs on the list
  1567. pRCD = CONTAINING_OBJECT(pLink, RCD, blOddFrameLinkage);
  1568. ASSERT_RCD(pRCD);
  1569. pLink->RemoveFromList(); // take next frame out of OddFrameList
  1570. // Make sure everything previous got removed from the odd frame list, and it is sorted correctly
  1571. ASSERT(pRCD->bSeq == pEPD->bNextReceive);
  1572. if (pRCD->ulRFlags & RFLAGS_FRAME_INDICATED_NONSEQ)
  1573. {
  1574. if (pEPD->pNewMessage)
  1575. {
  1576. // We need to throw this away
  1577. PRCD pRCDTemp = pEPD->pNewMessage;
  1578. pEPD->pNewMessage = NULL;
  1579. DPFX(DPFPREP,1, "(%p) Throwing away non-ended message (%x, %x)", pEPD, pRCDTemp->bSeq, pEPD->pNewTail->bSeq);
  1580. pEPD->pNewTail = NULL;
  1581. DropReceive(pEPD, pRCDTemp, ppRcvBuffToFree);
  1582. }
  1583. fIndicatedNonSeq = TRUE;
  1584. DPFX(DPFPREP,7, "(%p) Pulling Indicated-NonSequential message off of Out-of-Order List Seq=%x", pEPD, pRCD->bSeq);
  1585. pEPD->tLastDataFrame = pRCD->tTimestamp; // Always keep the receive time of (N(R) - 1)
  1586. pEPD->bLastDataRetry = (pRCD->bFrameControl & PACKET_CONTROL_RETRY);
  1587. DEBUG_ONLY(pEPD->bLastDataSeq = pRCD->bSeq);
  1588. RELEASE_RCD(pRCD);
  1589. }
  1590. else
  1591. {
  1592. // In the case of cancelling one of the messages in the middle of a large message,
  1593. // we will drop all previous, drop that one, and then we will get to a situation where we aren't
  1594. // currently working on a new message (pNewMessage was NULL'ed in the cancelling) and the current
  1595. // message does not have the NEW_MSG flag, in which case we scrap it above.
  1596. ASSERT(!fIndicatedNonSeq || (pRCD->bFrameFlags & PACKET_COMMAND_NEW_MSG) ||
  1597. (!pEPD->pNewMessage && !(pRCD->bFrameFlags & PACKET_COMMAND_NEW_MSG)));
  1598. // go ahead and move this to the receive list
  1599. DPFX(DPFPREP,7, "(%p) Moving OutOfOrder frame to received list Seq=%x", pEPD, pRCD->bSeq);
  1600. ASSERT(pRCD->bSeq == pEPD->bNextReceive);
  1601. break; // Back to the top
  1602. }
  1603. }
  1604. }
  1605. while (flag); // DO WHILE (There are still in order frames that have already arrived with no incomplete messages)
  1606. }
  1607. while (flag); // DO WHILE (There are still in order frames that have already arrived with an incomplete message)
  1608. if((pEPD->ulReceiveMask | pEPD->ulReceiveMask2)==0)
  1609. {
  1610. pEPD->ulEPFlags &= ~(EPFLAGS_DELAYED_NACK);
  1611. if(((pEPD->ulEPFlags & EPFLAGS_DELAYED_SENDMASK)==0)&&(pEPD->DelayedMaskTimer != NULL))
  1612. {
  1613. DPFX(DPFPREP,7, "(%p) Cancelling Delayed Mask Timer", pEPD);
  1614. if(CancelProtocolTimer(pSPD, pEPD->DelayedMaskTimer, pEPD->DelayedMaskTimerUnique) == DPN_OK)
  1615. {
  1616. DECREMENT_EPD(pEPD, "UNLOCK (cancel DelayedMask)"); // SPLock not already held
  1617. pEPD->DelayedMaskTimer = 0;
  1618. }
  1619. else
  1620. {
  1621. DPFX(DPFPREP,7, "(%p) Cancelling Delayed Mask Timer Failed", pEPD);
  1622. }
  1623. }
  1624. }
  1625. }
  1626. /*
  1627. ** Receive Out Of Order Frame
  1628. **
  1629. ** Its like the title says. We must set the appropriate bit in the 64-bit ReceiveMask
  1630. ** and then place it into the OddFrameList in its proper sorted place. After that, we must
  1631. ** scan to see if a complete message has been formed and see if we are able to indicate it
  1632. ** early.
  1633. **
  1634. ** ** EPLOCK is HELD through this entire function **
  1635. */
  1636. #undef DPF_MODNAME
  1637. #define DPF_MODNAME "ReceiveOutOfOrderFrame"
  1638. VOID
  1639. ReceiveOutOfOrderFrame(PEPD pEPD, PRCD pRCD, ULONG bit, PSPRECEIVEDBUFFER* ppRcvBuffToFree)
  1640. {
  1641. PSPD pSPD = pEPD->pSPD;
  1642. PRCD pRCD1;
  1643. PRCD pRCD2;
  1644. CBilink *pLink;
  1645. BYTE NextSeq;
  1646. ULONG highbit;
  1647. ULONG Mask;
  1648. ULONG WorkMaskHigh;
  1649. ULONG WorkMaskLow;
  1650. ULONG MaskHigh;
  1651. ULONG MaskLow;
  1652. BOOL nack = FALSE;
  1653. UINT count;
  1654. BOOL lost = FALSE;
  1655. UINT frame_count = 0;
  1656. UINT msg_length = 0;
  1657. DPFX(DPFPREP,8,"(%p) Received out of order frame, Seq=%x, bit=%x", pEPD, pRCD->bSeq, bit);
  1658. // Bit shouldn't be more than 64 (MAX_RECEIVE_RANGE)
  1659. ASSERT(bit <= MAX_RECEIVE_RANGE);
  1660. AssertCriticalSectionIsTakenByThisThread(&pEPD->EPLock, TRUE);
  1661. // RECEIVE OUT OF ORDER FRAME
  1662. //
  1663. // DO WE SEND IMMEDIATE ACK FOR THIS OUT OF ORDER FRAME?
  1664. //
  1665. // When we receive an OutOfOrder frame it is almost certainly because the missing frame has been lost.
  1666. // So we can accelerate the re-transmission process greatly by telling partner right away that frames
  1667. // are missing. HOWEVER, with a large send window we will get many mis-ordered frames for each drop,
  1668. // but we only want to send a Negative Ack once. SO, we will only initiate a NACK here if we have
  1669. // created a NEW HOLE in our receive mask!
  1670. //
  1671. // First, we will not have created a new hole unless we added to the END of the OddFrameList.
  1672. // Second, we will not have created a new hole unless the FIRST BIT TO THE RIGHT of the new bit
  1673. // is CLEAR.
  1674. //
  1675. // So we will only generate an immediate NACK frame if both of the above cases are true!
  1676. // NOTE - if this is the only OoO frame, then we should always send a NACK
  1677. //
  1678. // ANOTHER NOTE. SP implementation has been changed so that it frequently misorders receives in close
  1679. // proximity. One effect of this is that we must not immediately send a NACK for an out of order frame, but
  1680. // instead should wait a short period (say ~5ms) and see if the missing frame hasn't shown up.
  1681. // Make sure this RCD is within the receive window
  1682. // NOTE: Presume SACK arrives with bNSeq of 84, N(R) is 20, and all bits are set except the one representing 20.
  1683. // In that case, pRCD->bSeq - pEPD->bNextReceive will be equal to 63 (ie MAX_FRAME_OFFSET).
  1684. ASSERT((BYTE)(pRCD->bSeq - pEPD->bNextReceive) <= (BYTE)MAX_FRAME_OFFSET);
  1685. // We will insert frame in OddFrameList maintaining sort by Seq number
  1686. //
  1687. // We can optimize for most likely case, which is new frames are added to END of list. We can
  1688. // check for this first case by investigating whether the new bit is the left-most bit in the mask.
  1689. // If it is LMB, then it trivially gets added to the END of the list.
  1690. //
  1691. // Please note that both this and the following algorithms assume that we have already verified
  1692. // that the new frame is NOT already in the list
  1693. MaskLow = pEPD->ulReceiveMask; // Get scratch copy of Mask
  1694. MaskHigh = pEPD->ulReceiveMask2;
  1695. if(bit < 32)
  1696. {
  1697. // Frame is within 32 of N(Rcv)
  1698. WorkMaskLow = 1 << bit; // Find bit in mask for new frame
  1699. WorkMaskHigh = 0;
  1700. pEPD->ulReceiveMask |= WorkMaskLow; // Set appropriate bit in mask
  1701. // check immediately preceeding bit for NACK determination
  1702. if( (MaskLow & (WorkMaskLow >> 1)) == 0)
  1703. {
  1704. nack = TRUE; // preceeding bit is not set
  1705. }
  1706. }
  1707. else
  1708. {
  1709. highbit = bit - 32;
  1710. WorkMaskHigh = 1 << highbit;
  1711. WorkMaskLow = 0;
  1712. pEPD->ulReceiveMask2 |= WorkMaskHigh; // Set appropriate bit in mask
  1713. if(highbit)
  1714. {
  1715. // check preceeding bit for NACK determination
  1716. if( (MaskHigh & (WorkMaskHigh >> 1)) == 0)
  1717. {
  1718. nack = TRUE; // preceeding bit is not set
  1719. }
  1720. }
  1721. else
  1722. {
  1723. if( (MaskLow & 0x80000000) == 0)
  1724. {
  1725. nack = TRUE;
  1726. }
  1727. }
  1728. }
  1729. // Insert frame in sorted OddFrameList.
  1730. //
  1731. // First test for trivial insert at tail condition. True if new bit is LEFTMOST set bit in
  1732. // both masks.
  1733. if( (WorkMaskHigh > MaskHigh) || ( (MaskHigh == 0) && (WorkMaskLow > MaskLow) ) )
  1734. {
  1735. // TAIL INSERTION
  1736. DPFX(DPFPREP,7, "(%p) Received %x OUT OF ORDER - INSERT AT TAIL NRcv=%x MaskL=%x MaskH=%x",
  1737. pEPD, pRCD->bSeq, pEPD->bNextReceive, pEPD->ulReceiveMask, pEPD->ulReceiveMask2);
  1738. pLink = &pEPD->blOddFrameList;
  1739. // Make sure this is either the only RCD in the list, or it is farther in the window than the last one
  1740. ASSERT(pLink->IsEmpty() || ((BYTE)(CONTAINING_OBJECT(pLink->GetPrev(), RCD, blOddFrameLinkage))->bSeq - pEPD->bNextReceive) < (BYTE)(pRCD->bSeq - pEPD->bNextReceive));
  1741. pRCD->blOddFrameLinkage.InsertBefore( pLink);
  1742. // Check to see if we should NACK (negative acknowledge) any frames. We only want to NACK a given
  1743. // frame once so we will NACK if this is the first frame added to the OOF list, or if the immediately
  1744. // preceeding frame is missing. First condition is trivial to test.
  1745. if( ((MaskLow | MaskHigh) == 0) || (nack == 1) )
  1746. {
  1747. pEPD->ulEPFlags |= EPFLAGS_DELAYED_NACK;
  1748. if(pEPD->DelayedMaskTimer == 0)
  1749. {
  1750. DPFX(DPFPREP,7, "(%p) Setting Delayed Mask Timer", pEPD);
  1751. LOCK_EPD(pEPD, "LOCK (DelayedMaskTimer)"); // Bump RefCnt for timer
  1752. ScheduleProtocolTimer(pSPD, SHORT_DELAYED_ACK_TIMEOUT, 5, DelayedAckTimeout,
  1753. (PVOID) pEPD, &pEPD->DelayedMaskTimer, &pEPD->DelayedMaskTimerUnique);
  1754. pEPD->tReceiveMaskDelta = GETTIMESTAMP();
  1755. }
  1756. else
  1757. {
  1758. DPFX(DPFPREP,7, "(%p) *** DELAYED NACK *** Timer already running", pEPD);
  1759. }
  1760. }
  1761. }
  1762. else
  1763. {
  1764. // NOT TAIL INSERTION
  1765. // This is the non-trivial case, ie new frame goes at beginning or in middle of OddFrameList.
  1766. // So we need to count the ONE bits that are to the RIGHT of the new bit in the ReceiveMask.
  1767. // We will mask off bits higher then the New Bit and then do a quick bit-count...
  1768. DPFX(DPFPREP,7, "(%p) Receive OUT OF ORDER - Walking Frame List (Seq=%x, NRcv=%x) MaskL=%x MaskH=%x", pEPD, pRCD->bSeq, pEPD->bNextReceive, pEPD->ulReceiveMask, pEPD->ulReceiveMask2);
  1769. // If we are inserting into high mask, we must count all one-bits in low mask
  1770. //
  1771. // We will test for the special case of all-bits-set at the outset...
  1772. pLink = pEPD->blOddFrameList.GetNext(); // pLink = First frame in list; we will walk list as we count
  1773. if(WorkMaskHigh)
  1774. {
  1775. // new frame in high mask. only count bits to right of new bit
  1776. WorkMaskHigh -= 1; // Convert to mask preserving all bits to right of new bit
  1777. WorkMaskHigh &= MaskHigh; // WMH now represents all bits to right of new bit
  1778. while(WorkMaskHigh)
  1779. {
  1780. // Make sure this is farther in the window than the one we are skipping
  1781. ASSERT(((BYTE)(CONTAINING_OBJECT(pLink, RCD, blOddFrameLinkage))->bSeq - pEPD->bNextReceive) < (BYTE)(pRCD->bSeq - pEPD->bNextReceive));
  1782. // Count bits in WMH
  1783. Mask = WorkMaskHigh - 1;
  1784. WorkMaskHigh &= Mask;
  1785. pLink = pLink->GetNext();
  1786. }
  1787. if(MaskLow == 0xFFFFFFFF)
  1788. {
  1789. // special case if low mask is full
  1790. for(count = 0; count < 32; count++)
  1791. {
  1792. // Make sure this is farther in the window than the one we are skipping
  1793. ASSERT(((BYTE)(CONTAINING_OBJECT(pLink, RCD, blOddFrameLinkage))->bSeq - pEPD->bNextReceive) < (BYTE)(pRCD->bSeq - pEPD->bNextReceive));
  1794. pLink = pLink->GetNext();
  1795. }
  1796. }
  1797. else
  1798. {
  1799. // else count all bits in lower mask
  1800. while(MaskLow)
  1801. {
  1802. // Make sure this is farther in the window than the one we are skipping
  1803. ASSERT(((BYTE)(CONTAINING_OBJECT(pLink, RCD, blOddFrameLinkage))->bSeq - pEPD->bNextReceive) < (BYTE)(pRCD->bSeq - pEPD->bNextReceive));
  1804. Mask = MaskLow - 1;
  1805. MaskLow &= Mask; // Mask off low 1-bit
  1806. pLink = pLink->GetNext();
  1807. }
  1808. }
  1809. }
  1810. else
  1811. {
  1812. WorkMaskLow -= 1;
  1813. WorkMaskLow &= MaskLow; // WML == bits to the right of new bit
  1814. while(WorkMaskLow)
  1815. {
  1816. // Make sure this is farther in the window than the one we are skipping
  1817. ASSERT(((BYTE)(CONTAINING_OBJECT(pLink, RCD, blOddFrameLinkage))->bSeq - pEPD->bNextReceive) < (BYTE)(pRCD->bSeq - pEPD->bNextReceive));
  1818. Mask = WorkMaskLow - 1;
  1819. WorkMaskLow &= Mask; // Mask off low 1-bit
  1820. pLink = pLink->GetNext();
  1821. }
  1822. }
  1823. // Make sure this is farther in the window than the last one
  1824. ASSERT(((BYTE)(CONTAINING_OBJECT(pLink->GetPrev(), RCD, blOddFrameLinkage))->bSeq - pEPD->bNextReceive) < (BYTE)(pRCD->bSeq - pEPD->bNextReceive));
  1825. pRCD->blOddFrameLinkage.InsertBefore( pLink); // Insert new frame in sorted list
  1826. } // Receive not at tail
  1827. #ifdef DBG
  1828. // Dump the contents of the Out of Order Frame List for verification. There are at most 64 frames.
  1829. {
  1830. BYTE bCurSeq = pEPD->bNextReceive + 1;
  1831. ULONG64 ulMask = ((ULONG64)pEPD->ulReceiveMask2 << 32) | ((ULONG64)pEPD->ulReceiveMask);
  1832. CBilink* pTemp;
  1833. TCHAR szOOFL[256];
  1834. szOOFL[0] = 0;
  1835. pTemp = pEPD->blOddFrameList.GetNext();
  1836. while (pTemp != &pEPD->blOddFrameList)
  1837. {
  1838. while (ulMask != 0 && !(ulMask & 1))
  1839. {
  1840. ulMask >>= 1;
  1841. bCurSeq++;
  1842. }
  1843. ASSERT(ulMask != 0);
  1844. PRCD pRCDTemp = CONTAINING_OBJECT(pTemp, RCD, blOddFrameLinkage);
  1845. ASSERT_RCD(pRCDTemp);
  1846. ASSERT(bCurSeq == pRCDTemp->bSeq);
  1847. wsprintf(szOOFL, _T("%s %02x"), szOOFL, pRCDTemp->bSeq);
  1848. ulMask >>= 1;
  1849. bCurSeq++;
  1850. pTemp = pTemp->GetNext();
  1851. }
  1852. DPFX(DPFPREP, 7, "OOFL contents: %s", szOOFL);
  1853. }
  1854. #endif // DBG
  1855. // ** Non-Sequential Indication
  1856. //
  1857. // This is the Non-Trivial implementation of non-sequential receive indication.
  1858. // We will work from the assumption that we only need to complete messages that are touched by the new frame.
  1859. // So we must back up in the OddFrame list until we see either a gap or a Start of Message marker. Then we must work
  1860. // forward looking for an End of Message...
  1861. //
  1862. // One more complication is the fact that dropped packets might in the list via place-holding dummies. Since we
  1863. // do not know what SOM/EOM flags would have been present on a dropped frame, we can consider them to have BOTH flags.
  1864. // Then we also need to be aware that frames bordering on dropped frames without a delimiter (SOM or EOM) are fragments
  1865. // and therefore count as dropped data too. I think to keep this from getting too complex, we wont probe further for
  1866. // neighbors of lost data frames. We will discover them when we are building a message later.
  1867. //
  1868. // pLink = Item after new element in Out of Order list
  1869. // pRCD = new Item
  1870. // IF this frame is not marked as SEQUENTIAL
  1871. if((pRCD->bFrameFlags & PACKET_COMMAND_SEQUENTIAL)==0)
  1872. {
  1873. DPFX(DPFPREP,7, "(%p) Received Non-Seq %x out of order; flags=%x", pEPD, pRCD->bSeq, pRCD->bFrameFlags);
  1874. NextSeq = pRCD->bSeq;
  1875. // NOTE: The first pLink will be the passed in RCD so we will have included that in the frame_count and msg_length after leaving this while
  1876. while ( (pLink = pLink->GetPrev()) != &pEPD->blOddFrameList )
  1877. {
  1878. pRCD1 = CONTAINING_OBJECT(pLink, RCD, blOddFrameLinkage);
  1879. ASSERT_RCD(pRCD1);
  1880. frame_count++;
  1881. msg_length += pRCD1->uiDataSize;
  1882. if((pRCD1->bFrameFlags & PACKET_COMMAND_NEW_MSG) || (pRCD1->bSeq != NextSeq))
  1883. {
  1884. break; // Stop probing when we find a NEW_MSG flag OR a gap in the frame sequence numbers
  1885. }
  1886. --NextSeq;
  1887. }
  1888. // We have either found a NEW_MSG or a sequence gap. If its a NEW_MSG, then we probe forward for an END_MSG
  1889. if((pRCD1->bFrameFlags & PACKET_COMMAND_NEW_MSG) && (pRCD1->bSeq == NextSeq))
  1890. {
  1891. // So far so good. We have a sequential message start frame
  1892. //
  1893. // pRCD = frame just arrived
  1894. // pRCD1 = Start of message frame
  1895. // pLink = Start of message linkage
  1896. pLink = &pRCD->blOddFrameLinkage;
  1897. NextSeq = pRCD->bSeq;
  1898. // Look for the message end or a sequence gap
  1899. while ( ( (pRCD->bFrameFlags & PACKET_COMMAND_END_MSG)==0 ) && (pRCD->bSeq == NextSeq))
  1900. {
  1901. // Stop if we hit the end of the OddFrameList
  1902. if((pLink = pLink->GetNext()) == &pEPD->blOddFrameList)
  1903. {
  1904. break;
  1905. }
  1906. // NOTE: the first pLink here will be the one after the passed in RCD. If there is a gap that won't
  1907. // matter because we are out of here after the next if. If it is the next message we will continue until
  1908. // we hit the END_MSG and have a proper frame_count and msg_length.
  1909. pRCD = CONTAINING_OBJECT(pLink, RCD, blOddFrameLinkage);
  1910. ASSERT_RCD(pRCD);
  1911. frame_count++;
  1912. msg_length += pRCD->uiDataSize;
  1913. NextSeq++;
  1914. }
  1915. // pLink should not be used after this point due to the way the above while could have left it either valid
  1916. // or at &pEPD->blOddFrameList.
  1917. pLink = NULL;
  1918. if((pRCD->bFrameFlags & PACKET_COMMAND_END_MSG) && (pRCD->bSeq == NextSeq))
  1919. {
  1920. // We have completed a message
  1921. //
  1922. // pRCD1 = First frame in message
  1923. // pRCD = Last frame in message
  1924. DPFX(DPFPREP,7, "(%p) Completed Non-Seq Msg: First=%x, Last=%x", pEPD, pRCD1->bSeq, pRCD->bSeq);
  1925. lost = FALSE;
  1926. pRCD->ulRFlags |= RFLAGS_FRAME_INDICATED_NONSEQ;
  1927. pRCD->pMsgLink = NULL;
  1928. lost |= pRCD->ulRFlags & RFLAGS_FRAME_LOST;
  1929. // Get the pointer to the next to last message so we can remove the last
  1930. pLink = pRCD->blOddFrameLinkage.GetPrev();
  1931. LOCK_RCD(pRCD); // ReceiveInOrderFrame must remove this
  1932. // Walk from the last message to the first message accumulating lost flags, linking messages,
  1933. // setting indicated flag, and pulling off of the odd frame list
  1934. while (pRCD != pRCD1)
  1935. {
  1936. ASSERT(pLink != &pEPD->blOddFrameList); // Make sure we didn't run out of RCDs on the list
  1937. pRCD2 = CONTAINING_OBJECT(pLink, RCD, blOddFrameLinkage);
  1938. ASSERT_RCD(pRCD2);
  1939. pRCD2->pMsgLink = pRCD;
  1940. LOCK_RCD(pRCD2); // ReceiveInOrderFrame must remove this
  1941. pRCD2->ulRFlags |= RFLAGS_FRAME_INDICATED_NONSEQ;
  1942. lost |= pRCD2->ulRFlags & RFLAGS_FRAME_LOST;
  1943. pLink = pRCD2->blOddFrameLinkage.GetPrev();
  1944. pRCD = pRCD2;
  1945. }
  1946. // Both RCD and RCD1 point to the first message now
  1947. // If any were lost, drop the receive, otherwise complete it
  1948. if(!lost)
  1949. {
  1950. pRCD->uiFrameCount = frame_count;
  1951. pRCD->uiMsgSize = msg_length;
  1952. DPFX(DPFPREP,7, "(%p) Adding msg to complete list FirstSeq=%x QueueSize=%d", pEPD, pRCD->bSeq, pEPD->uiCompleteMsgCount);
  1953. pRCD->blCompleteLinkage.InsertBefore( &pEPD->blCompleteList);
  1954. pEPD->uiCompleteMsgCount++;
  1955. }
  1956. else
  1957. {
  1958. DPFX(DPFPREP,7, "(%p) Complete Non-Seq MSG is dropped due to missing frames", pEPD);
  1959. DropReceive(pEPD, pRCD, ppRcvBuffToFree);
  1960. }
  1961. }
  1962. } // else there is nothing to complete at this time...
  1963. } // IF NON SEQUENTIAL
  1964. }
  1965. /*
  1966. ** Drop Receive
  1967. **
  1968. ** One or more frames composing a message have been dropped, so the entire message can be scrapped.
  1969. ** If this was determined during an out of order receive then the RCDs will remain on the OddFrameList
  1970. ** as usual.
  1971. */
  1972. #undef DPF_MODNAME
  1973. #define DPF_MODNAME "DropReceive"
  1974. VOID
  1975. DropReceive(PEPD pEPD, PRCD pRCD, PSPRECEIVEDBUFFER* ppRcvBuffToFree)
  1976. {
  1977. PRCD pNext;
  1978. while(pRCD != NULL)
  1979. {
  1980. ASSERT_RCD(pRCD);
  1981. if (pRCD->bFrameFlags & PACKET_COMMAND_RELIABLE)
  1982. {
  1983. DPFX(DPFPREP,1, "(%p) Dropping G receive frame %x!!!", pEPD, pRCD->bSeq);
  1984. }
  1985. else
  1986. {
  1987. DPFX(DPFPREP,7, "(%p) Dropping NG receive frame %x", pEPD, pRCD->bSeq);
  1988. }
  1989. RELEASE_SP_BUFFER(*ppRcvBuffToFree, pRCD->pRcvBuff);
  1990. pNext = pRCD->pMsgLink;
  1991. RELEASE_RCD(pRCD);
  1992. pRCD = pNext;
  1993. }
  1994. }
  1995. /*
  1996. ** Receive Complete
  1997. **
  1998. ** We have received an entire reliable message, potentially spanning
  1999. ** multiple messages. We are still on the receive thread right now so depending
  2000. ** upon our desired indication behavior we will either indicate it directly or
  2001. ** else queue it to be indicated on a background thread of some sort.
  2002. **
  2003. ** Messages spanning multiple frames (for now) will be copied into a contiguous
  2004. ** buffer for delivery. CODEWORK -- Server implementations should be able to receive
  2005. ** large messages as buffer chains (or arrays of BufDescs).
  2006. **
  2007. ** This is also where we must notice that an End Of Stream flag is set in a message,
  2008. ** indicating that the connection is being closed.
  2009. **
  2010. ** *** CALLED WITH EPD->STATELOCK HELD *** RETURNS WITH STATELOCK RELEASED ***
  2011. */
  2012. #undef DPF_MODNAME
  2013. #define DPF_MODNAME "ReceiveComplete"
  2014. VOID
  2015. ReceiveComplete(PEPD pEPD)
  2016. {
  2017. CBilink *pLink;
  2018. PRCD pRCD;
  2019. PRCD pNext;
  2020. PSPRECEIVEDBUFFER pRcvBuff = NULL;
  2021. PBIGBUF pBuf;
  2022. PBYTE write;
  2023. UINT length;
  2024. UINT frames;
  2025. DWORD flag;
  2026. UINT MsgSize;
  2027. HRESULT hr;
  2028. PProtocolData pPData=pEPD->pSPD->pPData;
  2029. AssertCriticalSectionIsTakenByThisThread(&pEPD->EPLock, TRUE);
  2030. while((pLink = pEPD->blCompleteList.GetNext()) != &pEPD->blCompleteList)
  2031. {
  2032. pLink->RemoveFromList();
  2033. ASSERT(pEPD->uiCompleteMsgCount > 0);
  2034. pEPD->uiCompleteMsgCount--;
  2035. Unlock(&pEPD->EPLock);
  2036. pRCD = CONTAINING_OBJECT(pLink, RCD, blCompleteLinkage);
  2037. ASSERT_RCD(pRCD);
  2038. // Handle easy case first
  2039. if(pRCD->uiFrameCount == 1) // message is only 1 frame
  2040. {
  2041. //if data length is zero we've either got an old style keep alive or an EOS
  2042. //alternatively if link supports signing and the keep alive bit is flicked we've
  2043. //got a new style keep alive
  2044. if (pRCD->uiDataSize==0 ||
  2045. ((pEPD->ulEPFlags2 & EPFLAGS2_SUPPORTS_SIGNING) && (pRCD->bFrameControl & PACKET_CONTROL_KEEPALIVE)))
  2046. {
  2047. DNASSERT(!(pRCD->bFrameControl & PACKET_CONTROL_COALESCE));
  2048. //for EOS or old style keep alive there will be no data
  2049. //for a new style keep alive there should be a DWORD session identity
  2050. DNASSERT(pRCD->uiDataSize==0 || (pRCD->uiDataSize==sizeof(DWORD)));
  2051. //if marked as end of stream handle the closure case
  2052. if(pRCD->bFrameControl & PACKET_CONTROL_END_STREAM)
  2053. {
  2054. // END OF STREAM indicated
  2055. DPFX(DPFPREP,7, "(%p) Processing EndOfStream, pRCD[%p]", pEPD, pRCD);
  2056. ProcessEndOfStream(pEPD);
  2057. }
  2058. RELEASE_SP_BUFFER(pRcvBuff, pRCD->pRcvBuff); // Really only queues it to be released
  2059. }
  2060. //else we've got some user data to indicate up
  2061. else
  2062. {
  2063. DNASSERT(pRCD->pRcvBuff->pNext == NULL);
  2064. pRCD->pRcvBuff->pServiceProviderDescriptor = pEPD->pSPD;
  2065. if (pRCD->bFrameControl & PACKET_CONTROL_COALESCE)
  2066. {
  2067. PCOALESCEHEADER pCoalesceHeaders = (PCOALESCEHEADER) pRCD->pbData;
  2068. DWORD dwSubFrame;
  2069. BYTE* pbData;
  2070. DWORD dwCoalesceDataSize;
  2071. // Find the start of the data. Skip the alignment padding, if there is any.
  2072. pbData = (BYTE*) (pCoalesceHeaders + pRCD->dwNumCoalesceHeaders);
  2073. DBG_CASSERT(sizeof(COALESCEHEADER) == 2);
  2074. if ((pRCD->dwNumCoalesceHeaders & 1) != 0)
  2075. {
  2076. pbData += 2;
  2077. }
  2078. // We will borrow pNext to use as a ref count. We must add one ref at the top of this
  2079. // loop to ensure that the count doesn't go to zero before we indicate all of the
  2080. // pieces to the Core.
  2081. pRCD->pRcvBuff->pNext = (_SPRECEIVEDBUFFER*)1;
  2082. pRCD->pRcvBuff->dwProtocolData = RBT_SERVICE_PROVIDER_BUFFER_COALESCE;
  2083. for(dwSubFrame = 0; dwSubFrame < pRCD->dwNumCoalesceHeaders; dwSubFrame++)
  2084. {
  2085. dwCoalesceDataSize = pCoalesceHeaders[dwSubFrame].bSize;
  2086. dwCoalesceDataSize |= (DWORD) (pCoalesceHeaders[dwSubFrame].bCommand & (PACKET_COMMAND_COALESCE_BIG_1 | PACKET_COMMAND_COALESCE_BIG_2 | PACKET_COMMAND_COALESCE_BIG_3)) << 5;
  2087. ASSERT((UINT) ((UINT_PTR) (pbData + dwCoalesceDataSize - pRCD->pbData)) <= pRCD->uiDataSize);
  2088. //if message size exceeds the maximum size we just skip this subframe
  2089. //otherwise update stats and indicate it up to core
  2090. if (dwCoalesceDataSize>pPData->dwMaxRecvMsgSize)
  2091. {
  2092. DPFX(DPFPREP, 1, "(%p) Message size exceeds maximum accepted. Skipping subframe "
  2093. "MsgSize[%u], MaxRecvMsgSize[%u]", pEPD, dwCoalesceDataSize, pPData->dwMaxRecvMsgSize);
  2094. }
  2095. else
  2096. {
  2097. DNInterlockedIncrement((LONG*)&pRCD->pRcvBuff->pNext);
  2098. pEPD->uiMessagesReceived++;
  2099. if(pCoalesceHeaders[dwSubFrame].bCommand & PACKET_COMMAND_RELIABLE)
  2100. {
  2101. pEPD->uiGuaranteedFramesReceived++;
  2102. pEPD->uiGuaranteedBytesReceived += dwCoalesceDataSize;
  2103. }
  2104. else
  2105. {
  2106. pEPD->uiDatagramFramesReceived++;
  2107. pEPD->uiDatagramBytesReceived += dwCoalesceDataSize;
  2108. }
  2109. flag = (((DWORD) pCoalesceHeaders[dwSubFrame].bCommand) & (PACKET_COMMAND_USER_1 | PACKET_COMMAND_USER_2)) * (DN_SENDFLAGS_SET_USER_FLAG / PACKET_COMMAND_USER_1);
  2110. DEBUG_ONLY(DNInterlockedIncrement(&pEPD->pSPD->pPData->ThreadsInReceive));
  2111. DEBUG_ONLY(DNInterlockedIncrement(&pEPD->pSPD->pPData->BuffersInReceive));
  2112. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blProtocolCritSecsHeld);
  2113. DPFX(DPFPREP,DPF_CALLOUT_LVL, "(%p) Calling Core->IndicateReceive (coalesced), pRCD[%p] (data 0x%p, %u, %u/%u), Core Context[%p]", pEPD, pRCD, pbData, dwCoalesceDataSize, dwSubFrame, pRCD->dwNumCoalesceHeaders, pEPD->Context);
  2114. hr = pEPD->pSPD->pPData->pfVtbl->IndicateReceive(pEPD->pSPD->pPData->Parent, pEPD->Context, pbData, dwCoalesceDataSize, pRCD->pRcvBuff, flag);
  2115. if(hr == DPN_OK)
  2116. {
  2117. ASSERT(*((LONG*)&pRCD->pRcvBuff->pNext) > 1);
  2118. DNInterlockedDecrement((LONG*)&pRCD->pRcvBuff->pNext);
  2119. }
  2120. else
  2121. {
  2122. ASSERT(hr == DPNERR_PENDING);
  2123. }
  2124. DEBUG_ONLY(DNInterlockedDecrement(&pEPD->pSPD->pPData->ThreadsInReceive));
  2125. }
  2126. // If this isn't the last packet, round up to the nearest DWORD alignment.
  2127. if (! (pCoalesceHeaders[dwSubFrame].bCommand & PACKET_COMMAND_END_COALESCE))
  2128. {
  2129. dwCoalesceDataSize = (dwCoalesceDataSize + 3) & (~3);
  2130. }
  2131. pbData += dwCoalesceDataSize;
  2132. ASSERT((UINT) ((UINT_PTR) (pbData - pRCD->pbData)) <= pRCD->uiDataSize);
  2133. }
  2134. DNPReleaseReceiveBuffer(pEPD->pSPD->pPData, pRCD->pRcvBuff);
  2135. // The Core owns it now and is responsible for calling DNPReleaseReceiveBuffer to free it
  2136. pRCD->pRcvBuff = NULL;
  2137. }
  2138. else
  2139. {
  2140. //if message size exceeds the maximum we accept then simply release the SP buffer
  2141. if (pRCD->uiDataSize>pPData->dwMaxRecvMsgSize)
  2142. {
  2143. DPFX(DPFPREP, 1, "(%p) Message size exceeds maximum accepted. Dropping single frame "
  2144. "MsgSize[%u], MaxRecvMsgSize[%u]", pEPD, pRCD->uiDataSize, pPData->dwMaxRecvMsgSize);
  2145. RELEASE_SP_BUFFER(pRcvBuff, pRCD->pRcvBuff);
  2146. }
  2147. else
  2148. {
  2149. pRCD->pRcvBuff->dwProtocolData = RBT_SERVICE_PROVIDER_BUFFER;
  2150. pEPD->uiMessagesReceived++;
  2151. if(pRCD->bFrameFlags & PACKET_COMMAND_RELIABLE)
  2152. {
  2153. pEPD->uiGuaranteedFramesReceived++;
  2154. pEPD->uiGuaranteedBytesReceived += pRCD->uiDataSize;
  2155. }
  2156. else
  2157. {
  2158. pEPD->uiDatagramFramesReceived++;
  2159. pEPD->uiDatagramBytesReceived += pRCD->uiDataSize;
  2160. }
  2161. flag = (((DWORD) pRCD->bFrameFlags) & (PACKET_COMMAND_USER_1 | PACKET_COMMAND_USER_2)) * (DN_SENDFLAGS_SET_USER_FLAG / PACKET_COMMAND_USER_1);
  2162. DEBUG_ONLY(DNInterlockedIncrement(&pEPD->pSPD->pPData->ThreadsInReceive));
  2163. DEBUG_ONLY(DNInterlockedIncrement(&pEPD->pSPD->pPData->BuffersInReceive));
  2164. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blProtocolCritSecsHeld);
  2165. DPFX(DPFPREP,DPF_CALLOUT_LVL, "(%p) Calling Core->IndicateReceive, pRCD[%p], Core Context[%p]", pEPD, pRCD, pEPD->Context);
  2166. hr = pEPD->pSPD->pPData->pfVtbl->IndicateReceive(pEPD->pSPD->pPData->Parent, pEPD->Context, pRCD->pbData, pRCD->uiDataSize, pRCD->pRcvBuff, flag);
  2167. if(hr == DPN_OK)
  2168. {
  2169. RELEASE_SP_BUFFER(pRcvBuff, pRCD->pRcvBuff); // Really only queues it to be released
  2170. DEBUG_ONLY(DNInterlockedDecrement(&pEPD->pSPD->pPData->BuffersInReceive));
  2171. }
  2172. else
  2173. {
  2174. ASSERT(hr == DPNERR_PENDING);
  2175. // The Core owns it now and is responsible for calling DNPReleaseReceiveBuffer to free it
  2176. pRCD->pRcvBuff = NULL;
  2177. }
  2178. DEBUG_ONLY(DNInterlockedDecrement(&pEPD->pSPD->pPData->ThreadsInReceive));
  2179. }
  2180. }
  2181. }
  2182. RELEASE_RCD(pRCD); // Release reference for Complete Processing
  2183. pRCD = NULL;
  2184. }
  2185. else // Message spans multiple frames
  2186. {
  2187. ASSERT(!(pRCD->bFrameControl & PACKET_CONTROL_COALESCE));
  2188. //if the message exceeds the maximum size permitted then don't allocate a buffer
  2189. //otherwise get a single buffer large enough to hold data from multiple buffers
  2190. MsgSize = pRCD->uiMsgSize;
  2191. if (MsgSize>pPData->dwMaxRecvMsgSize)
  2192. {
  2193. DPFX(DPFPREP, 1, "(%p) Message size exceeds maximum accepted. Dropping multiple frames "
  2194. "MsgSize[%u], MaxRecvMsgSize[%u]", pEPD, MsgSize, pPData->dwMaxRecvMsgSize);
  2195. pBuf=NULL;
  2196. }
  2197. else if (MsgSize<= SMALL_BUFFER_SIZE)
  2198. {
  2199. pBuf = (PBIGBUF)POOLALLOC(MEMID_SMALLBUFF, &BufPool);
  2200. }
  2201. else if (MsgSize <= MEDIUM_BUFFER_SIZE)
  2202. {
  2203. pBuf = (PBIGBUF)POOLALLOC(MEMID_MEDBUFF, &MedBufPool);
  2204. }
  2205. else if (MsgSize <= LARGE_BUFFER_SIZE)
  2206. {
  2207. pBuf = (PBIGBUF)POOLALLOC(MEMID_BIGBUFF, &BigBufPool);
  2208. }
  2209. else
  2210. {
  2211. DPFX(DPFPREP,7, "(%p) RECEIVE HUGE MESSAGE", pEPD);
  2212. // Receive is larger then our biggest static receive buffer. This means we have to allocate a dynamic buffer.
  2213. pBuf = (PBIGBUF) MEMALLOC(MEMID_HUGEBUF, MsgSize + sizeof(DYNBUF));
  2214. if(pBuf)
  2215. {
  2216. pBuf->Type = RBT_DYNAMIC_BUFFER;
  2217. }
  2218. }
  2219. if(pBuf == NULL)
  2220. {
  2221. DPFX(DPFPREP,0, "(%p) Either mem alloc failed or message too large. Cannot deliver data", pEPD);
  2222. while(pRCD != NULL)
  2223. {
  2224. ASSERT_RCD(pRCD);
  2225. pNext = pRCD->pMsgLink;
  2226. RELEASE_SP_BUFFER(pRcvBuff, pRCD->pRcvBuff);
  2227. RELEASE_RCD(pRCD);
  2228. pRCD = pNext;
  2229. }
  2230. Lock(&pEPD->EPLock);
  2231. continue; // blow it off!
  2232. }
  2233. write = pBuf->data; // initialize write pointer
  2234. length = 0;
  2235. frames = 0;
  2236. while(pRCD != NULL)
  2237. {
  2238. ASSERT_RCD(pRCD);
  2239. memcpy(write, pRCD->pbData, pRCD->uiDataSize);
  2240. write += pRCD->uiDataSize;
  2241. length += pRCD->uiDataSize;
  2242. frames++;
  2243. pNext = pRCD->pMsgLink;
  2244. flag = (DWORD) pRCD->bFrameFlags;
  2245. RELEASE_SP_BUFFER(pRcvBuff, pRCD->pRcvBuff);
  2246. RELEASE_RCD(pRCD);
  2247. pRCD = pNext;
  2248. }
  2249. pEPD->uiMessagesReceived++;
  2250. if(flag & PACKET_COMMAND_RELIABLE)
  2251. {
  2252. pEPD->uiGuaranteedFramesReceived += frames;
  2253. pEPD->uiGuaranteedBytesReceived += length;
  2254. }
  2255. else
  2256. {
  2257. pEPD->uiDatagramFramesReceived += frames;
  2258. pEPD->uiDatagramBytesReceived += length;
  2259. }
  2260. flag = (flag & (PACKET_COMMAND_USER_1 | PACKET_COMMAND_USER_2)) * (DN_SENDFLAGS_SET_USER_FLAG / PACKET_COMMAND_USER_1);
  2261. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blProtocolCritSecsHeld);
  2262. DPFX(DPFPREP,DPF_CALLOUT_LVL, "(%p) Calling Core->IndicateReceive, Core Context[%p]", pEPD, pEPD->Context);
  2263. hr = pEPD->pSPD->pPData->pfVtbl->IndicateReceive(pEPD->pSPD->pPData->Parent, pEPD->Context, pBuf->data, length, pBuf, flag);
  2264. if(hr == DPN_OK)
  2265. {
  2266. DNPReleaseReceiveBuffer(pEPD->pSPD->pPData, pBuf);
  2267. }
  2268. else
  2269. {
  2270. ASSERT(hr == DPNERR_PENDING);
  2271. }
  2272. }
  2273. Lock(&pEPD->EPLock);
  2274. }
  2275. ASSERT(pEPD->blCompleteList.IsEmpty());
  2276. pEPD->ulEPFlags &= ~(EPFLAGS_IN_RECEIVE_COMPLETE); // Clear this before releasing Lock final time
  2277. Unlock(&pEPD->EPLock);
  2278. if(pRcvBuff != NULL)
  2279. {
  2280. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blProtocolCritSecsHeld);
  2281. DPFX(DPFPREP,DPF_CALLOUT_LVL, "(%p) Calling SP->ReturnReceiveBuffers, pSPD[%p]", pEPD, pEPD->pSPD);
  2282. IDP8ServiceProvider_ReturnReceiveBuffers(pEPD->pSPD->IISPIntf, pRcvBuff);
  2283. }
  2284. }
  2285. /*
  2286. ** Process Send Mask
  2287. **
  2288. ** The send mask is what our partner uses to tell us to stop waiting for particular frames.
  2289. ** This will happen after an Unreliable frame is dropped. Instead of retransmitting the unreliable
  2290. ** frame, the sender will forward the appropriate bit in a send mask. In this routine, we attempt
  2291. ** to update our receive state pursuant to the newly received mask.
  2292. **
  2293. ** THIS IS CALLED WITH STATELOCK HELD AND RETURNS WITH STATELOCK HELD
  2294. **
  2295. ** suffice it to say that we should not release statelock anywhere in the following
  2296. */
  2297. #undef DPF_MODNAME
  2298. #define DPF_MODNAME "ProcessSendMask"
  2299. VOID
  2300. ProcessSendMask(PEPD pEPD, BYTE bSeq, ULONG MaskLow, ULONG MaskHigh, DWORD tNow, PSPRECEIVEDBUFFER* ppRcvBuffToFree)
  2301. {
  2302. PSPD pSPD = pEPD->pSPD;
  2303. INT deltaS;
  2304. ULONG workmaskS;
  2305. BYTE bThisFrame;
  2306. UINT skip;
  2307. ASSERT(MaskLow | MaskHigh);
  2308. DPFX(DPFPREP,7, "(%p) PROCESS SEND MASK N(R)=%x, bSeq=%x, MaskL=%x, MaskH=%x", pEPD, pEPD->bNextReceive, bSeq, MaskLow, MaskHigh);
  2309. // The mask can only refer to frames earlier than the Seq number in this frame. So if this frame
  2310. // is the next In-Order then the mask can have nothing interesting in it.
  2311. //
  2312. // The SendMask is coded with decending frame numbers starting at the Seq in this frame - 1.
  2313. // The ReceiveMask is coded with ascending frame numbers start at N(Rcv) + 1.
  2314. //
  2315. // We will walk forward through the rcvmask and backward through the sendmask looking for the magic combo
  2316. // of a bit clear in the rcvmask and the corresponding bit set in the sendmask. For each of these matches,
  2317. // a dummy cancel frame can be 'received' for that sequence number.
  2318. //
  2319. // This would be fairly straightforward if it wasn't for the fact that both masks are 64 bits so the code has
  2320. // to track which DWORD of each mask we are dealing with at any given time.
  2321. //
  2322. // NOTE: It is perfectly legitimate for a SACK to come in with a bNSeq at MAX_FRAME_OFFSET from pEPD->bNextReceive. Consider
  2323. // the case where pEPD->bNextReceive is 0 and the sender has sent and timed out 0-63. A SACK would arrive with a bNSeq of 64
  2324. // and both masks fully set.
  2325. top:
  2326. if (bSeq != pEPD->bNextReceive)
  2327. {
  2328. deltaS = (INT) (((BYTE)(bSeq - pEPD->bNextReceive)) - 1); // count of frames between first missing frame and sequence base of mask
  2329. bThisFrame = pEPD->bNextReceive;
  2330. if ( deltaS <= MAX_FRAME_OFFSET )
  2331. {
  2332. // If the difference is greater then 32 frames then we need to look at the high mask first and
  2333. // then fall through to the low mask. Otherwise, we can ignore the highmask and start with the low.
  2334. while((deltaS > 31) && (MaskHigh)) // Any work to do in the upper bits?
  2335. {
  2336. workmaskS = 1 << (deltaS - 32); // walks bit positions backward in send mask
  2337. // See if the next frame we are interested in is covered by this mask
  2338. if(workmaskS & MaskHigh)
  2339. {
  2340. CancelFrame(pEPD, bThisFrame, tNow, ppRcvBuffToFree);
  2341. MaskHigh &= ~workmaskS;
  2342. // N(R) may have been bumped up multiple times by CancelFrame, reset to make sure we work with
  2343. // up to date information.
  2344. goto top;
  2345. }
  2346. else
  2347. {
  2348. bThisFrame++;
  2349. deltaS--;
  2350. }
  2351. }
  2352. if(deltaS > 31)
  2353. {
  2354. skip = deltaS - 31; // how many bit positions did we skip
  2355. bThisFrame += (BYTE) skip;
  2356. deltaS -= skip;
  2357. }
  2358. while((deltaS >= 0) && (MaskLow)) // Any work to do in the lower bits?
  2359. {
  2360. workmaskS = 1 << deltaS;
  2361. if(workmaskS & MaskLow)
  2362. {
  2363. CancelFrame(pEPD, bThisFrame, tNow, ppRcvBuffToFree);
  2364. MaskLow &= ~workmaskS;
  2365. // N(R) may have been bumped up multiple times by CancelFrame, reset to make sure we work with
  2366. // up to date information.
  2367. goto top;
  2368. }
  2369. else
  2370. {
  2371. bThisFrame++;
  2372. deltaS--;
  2373. }
  2374. }
  2375. }
  2376. }
  2377. // We need to ACK every time a send mask. Consider the case of one way Non-Guaranteed traffic. If data or an ACK gets lost,
  2378. // this will be the only way we get back in sync with the other side.
  2379. // If timer is not running better start it now
  2380. if(pEPD->DelayedAckTimer == 0)
  2381. {
  2382. LOCK_EPD(pEPD, "LOCK (DelayedAckTimer)"); // Bump RefCnt for timer
  2383. pEPD->ulEPFlags |= EPFLAGS_DELAY_ACKNOWLEDGE;
  2384. DPFX(DPFPREP,7, "(%p) Setting Delayed Ack Timer", pEPD);
  2385. ScheduleProtocolTimer(pSPD, DELAYED_ACK_TIMEOUT, 0, DelayedAckTimeout,
  2386. (PVOID) pEPD, &pEPD->DelayedAckTimer, &pEPD->DelayedAckTimerUnique);
  2387. }
  2388. }
  2389. #undef DPF_MODNAME
  2390. #define DPF_MODNAME "BuildCancelledRCD"
  2391. PRCD
  2392. BuildCancelledRCD(PEPD pEPD, BYTE bSeq, DWORD tNow)
  2393. {
  2394. PRCD pRCD;
  2395. if((pRCD = (PRCD)POOLALLOC(MEMID_CANCEL_RCD, &RCDPool)) == NULL)
  2396. {
  2397. DPFX(DPFPREP,0, "Failed to allocate RCD");
  2398. return NULL;
  2399. }
  2400. pRCD->bSeq = bSeq;
  2401. pRCD->bFrameFlags = PACKET_COMMAND_NEW_MSG | PACKET_COMMAND_END_MSG;
  2402. pRCD->bFrameControl = 0;
  2403. pRCD->pbData = NULL;
  2404. pRCD->uiDataSize = 0;
  2405. pRCD->tTimestamp = tNow;
  2406. pRCD->pRcvBuff = NULL;
  2407. pRCD->ulRFlags = RFLAGS_FRAME_LOST;
  2408. return pRCD;
  2409. }
  2410. /* Cancel Frame
  2411. **
  2412. ** An unreliable frame has been reported as lost by sender. This means we should consider it acknowledged
  2413. ** and remove it from our receive window. This may require us to place a dummy receive descriptor in the OddFrameList
  2414. ** to hold its place until the window moves past it.
  2415. */
  2416. #undef DPF_MODNAME
  2417. #define DPF_MODNAME "CancelFrame"
  2418. BOOL
  2419. CancelFrame(PEPD pEPD, BYTE bSeq, DWORD tNow, PSPRECEIVEDBUFFER* ppRcvBuffToFree)
  2420. {
  2421. PRCD pRCD;
  2422. ULONG bit;
  2423. DPFX(DPFPREP,7, "(%p) CANCEL FRAME: Seq=%x", pEPD, bSeq);
  2424. AssertCriticalSectionIsTakenByThisThread(&pEPD->EPLock, TRUE);
  2425. // Trivial case is when the cancelled frame is at the front of the window. In this case we can complete not only
  2426. // this frame but any contiguous frames following it in the OddFrameList
  2427. if(pEPD->bNextReceive == bSeq)
  2428. {
  2429. if((pRCD = BuildCancelledRCD(pEPD, bSeq, tNow)) == NULL)
  2430. {
  2431. return FALSE;
  2432. }
  2433. ReceiveInOrderFrame(pEPD, pRCD, ppRcvBuffToFree);
  2434. }
  2435. // Here we have to place a dummy node on the OddFrameList to represent this frame.
  2436. else
  2437. {
  2438. // bit location in mask for this frame
  2439. bit = (BYTE) ((bSeq - pEPD->bNextReceive) - 1);
  2440. // Make sure this is not a duplicate frame
  2441. if( ((bit < 32) && (pEPD->ulReceiveMask & (1 << bit))) || ((bit > 31) && (pEPD->ulReceiveMask2 & (1 << (bit - 32)))) )
  2442. {
  2443. DPFX(DPFPREP,7, "(%p) Received CancelMask for frame that's already received Seq=%x", pEPD, bSeq);
  2444. return FALSE;
  2445. }
  2446. if((pRCD = BuildCancelledRCD(pEPD, bSeq, tNow)) == NULL)
  2447. {
  2448. return FALSE;
  2449. }
  2450. ReceiveOutOfOrderFrame(pEPD, pRCD, bit, ppRcvBuffToFree);
  2451. }
  2452. return TRUE;
  2453. }
  2454. /*
  2455. ** Release Receive Buffer
  2456. **
  2457. ** The core calls this function to return buffers previously handed
  2458. ** over in an IndicateUserData call. This call may be made before the
  2459. ** actual indication returns.
  2460. */
  2461. #undef DPF_MODNAME
  2462. #define DPF_MODNAME "DNPReleaseReceiveBuffer"
  2463. HRESULT
  2464. DNPReleaseReceiveBuffer(HANDLE hProtocolData, HANDLE hBuffer)
  2465. {
  2466. ProtocolData* pPData;
  2467. PSPD pSPD;
  2468. HRESULT hr;
  2469. union
  2470. {
  2471. PBIGBUF pBuf;
  2472. PSPRECEIVEDBUFFER pRcvBuff;
  2473. } pBuffer;
  2474. DBG_CASSERT(OFFSETOF(buf, Type) == OFFSETOF(SPRECEIVEDBUFFER, dwProtocolData));
  2475. DBG_CASSERT(sizeof(BUFFER_TYPE) == sizeof(DWORD));
  2476. DPFX(DPFPREP,DPF_CALLIN_LVL, "Parameters: hProtocolData[%p], hBuffer[%p]", hProtocolData, hBuffer);
  2477. hr = DPN_OK;
  2478. pPData = (ProtocolData*)hProtocolData;
  2479. ASSERT_PPD(pPData);
  2480. pBuffer.pBuf = (PBIGBUF) hBuffer;
  2481. // NOTE: This is expecting pRcvBuff->pNext to be NULL and for RBT_SERVICE_PROVIDER_BUFFER to equal zero
  2482. // to work.
  2483. switch(pBuffer.pBuf->Type)
  2484. {
  2485. case RBT_SERVICE_PROVIDER_BUFFER:
  2486. pSPD = (PSPD)pBuffer.pRcvBuff->pServiceProviderDescriptor;
  2487. ASSERT_SPD(pSPD);
  2488. DEBUG_ONLY(DNInterlockedDecrement(&pSPD->pPData->BuffersInReceive));
  2489. pBuffer.pRcvBuff->pNext = NULL;
  2490. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blProtocolCritSecsHeld);
  2491. DPFX(DPFPREP,DPF_CALLOUT_LVL, "Calling SP->ReturnReceiveBuffers, pRcvBuff[%p], pSPD[%p]", pBuffer.pRcvBuff, pSPD);
  2492. IDP8ServiceProvider_ReturnReceiveBuffers(pSPD->IISPIntf, pBuffer.pRcvBuff);
  2493. break;
  2494. case RBT_SERVICE_PROVIDER_BUFFER_COALESCE:
  2495. // For coalesced packets we borrow pNext as a ref count. When the ref count gets to zero,
  2496. // we change the buffer back to a normal SP buffer and free it.
  2497. pSPD = (PSPD)pBuffer.pRcvBuff->pServiceProviderDescriptor;
  2498. ASSERT_SPD(pSPD);
  2499. DEBUG_ONLY(DNInterlockedDecrement(&pSPD->pPData->BuffersInReceive));
  2500. if (DNInterlockedDecrement((LONG*)&pBuffer.pRcvBuff->pNext) == 0)
  2501. {
  2502. pBuffer.pBuf->Type = RBT_SERVICE_PROVIDER_BUFFER;
  2503. hr = DNPReleaseReceiveBuffer(hProtocolData, hBuffer);
  2504. }
  2505. break;
  2506. case RBT_PROTOCOL_NORM_BUFFER:
  2507. BufPool.Release(pBuffer.pBuf);
  2508. break;
  2509. case RBT_PROTOCOL_MED_BUFFER:
  2510. MedBufPool.Release(pBuffer.pBuf);
  2511. break;
  2512. case RBT_PROTOCOL_BIG_BUFFER:
  2513. BigBufPool.Release(pBuffer.pBuf);
  2514. break;
  2515. case RBT_DYNAMIC_BUFFER:
  2516. DNFree(hBuffer);
  2517. break;
  2518. default:
  2519. DPFX(DPFPREP,0, "RELEASE RECEIVE BUFFER CALLED WITH BAD PARAMETER");
  2520. DNASSERT(FALSE);
  2521. hr = DPNERR_INVALIDPARAM;
  2522. break;
  2523. }
  2524. DPFX(DPFPREP,DPF_CALLIN_LVL, "Returning hr[%x]", hr);
  2525. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blProtocolCritSecsHeld);
  2526. return hr;
  2527. }
  2528. /*
  2529. ** Complete Sends
  2530. **
  2531. ** Reliable sends are completed upon acknowlegement. Acknowlegements are discovered inside
  2532. ** the UpdateXmitState routine while walking through the pending window. Since the actual completion
  2533. ** event requires the user to be called, state can change. So the easiest thing to do is defer these
  2534. ** completion callbacks until we are finished walking and can release any state locks. Also, this way
  2535. ** we can defer the callbacks until after we have indicated any data which the acks were piggybacking on,
  2536. ** something which ought to have priority anyway.
  2537. **
  2538. ** So we will place all completed reliable sends onto a complete list and after all other processing
  2539. ** we will come here and callback everything on the list.
  2540. */
  2541. #undef DPF_MODNAME
  2542. #define DPF_MODNAME "CompleteSends"
  2543. VOID CompleteSends(PEPD pEPD)
  2544. {
  2545. PMSD pMSD;
  2546. CBilink *pLink;
  2547. Lock(&pEPD->EPLock);
  2548. pLink = pEPD->blCompleteSendList.GetNext();
  2549. while((pEPD->ulEPFlags & EPFLAGS_COMPLETE_SENDS) &&
  2550. (pLink != &pEPD->blCompleteSendList))
  2551. {
  2552. pMSD = CONTAINING_OBJECT(pLink, MSD, blQLinkage);
  2553. ASSERT_MSD(pMSD);
  2554. if(pMSD->CommandID != COMMAND_ID_SEND_DATAGRAM)
  2555. {
  2556. // Reliables, Keepalives, and Disconnects will come down this path
  2557. if(pMSD->ulMsgFlags2 & (MFLAGS_TWO_SEND_COMPLETE|MFLAGS_TWO_ABORT))
  2558. {
  2559. if (pMSD->uiFrameCount == 0)
  2560. {
  2561. DPFX(DPFPREP, DPF_FRAMECNT_LVL, "Completing, pMSD[%p], framecount[%u]", pMSD, pMSD->uiFrameCount);
  2562. pLink->RemoveFromList();
  2563. Unlock(&pEPD->EPLock);
  2564. Lock(&pMSD->CommandLock);
  2565. CompleteReliableSend(pEPD->pSPD, pMSD, DPN_OK); // This releases the CommandLock
  2566. Lock(&pEPD->EPLock);
  2567. pLink = pEPD->blCompleteSendList.GetNext();
  2568. }
  2569. else
  2570. {
  2571. DPFX(DPFPREP, DPF_FRAMECNT_LVL, "Frames still out, pMSD[%p], framecount[%u]", pMSD, pMSD->uiFrameCount);
  2572. pLink = pLink->GetNext();
  2573. }
  2574. }
  2575. else
  2576. {
  2577. DPFX(DPFPREP, DPF_FRAMECNT_LVL, "Message not yet complete, pMSD[%p], framecount[%u]", pMSD, pMSD->uiFrameCount);
  2578. break; // These will complete in order, so stop checking when we see one that's not Complete.
  2579. }
  2580. }
  2581. else
  2582. {
  2583. // Datagrams will come down this path
  2584. DPFX(DPFPREP, DPF_FRAMECNT_LVL, "Skipping datagram frame on complete list, pMSD[%p], framecount[%u]", pMSD, pMSD->uiFrameCount);
  2585. pLink = pLink->GetNext();
  2586. }
  2587. }
  2588. #ifdef DBG
  2589. // In DBG we want to assert that no one one the list could have been completed if we are leaving here
  2590. pLink = pEPD->blCompleteSendList.GetNext();
  2591. while(pLink != &pEPD->blCompleteSendList)
  2592. {
  2593. pMSD = CONTAINING_OBJECT(pLink, MSD, blQLinkage);
  2594. ASSERT_MSD(pMSD);
  2595. ASSERT(!(pMSD->ulMsgFlags2 & (MFLAGS_TWO_SEND_COMPLETE|MFLAGS_TWO_ABORT)) || pMSD->uiFrameCount != 0);
  2596. pLink = pLink->GetNext();
  2597. }
  2598. #endif // DBG
  2599. pEPD->ulEPFlags &= ~(EPFLAGS_COMPLETE_SENDS);
  2600. Unlock(&pEPD->EPLock);
  2601. }
  2602. /*
  2603. ** Lookup CheckPoint
  2604. **
  2605. ** Walk the EndPoint's list of active CPs looking for one with the provided
  2606. ** response correlator.
  2607. ** We keep the CKPT queue sorted by age so the matches should be at the front
  2608. ** of the queue. So as we pass by entries at the head we will check the age of each
  2609. ** and timeout the ones that are 4(RTT) or greater.
  2610. ** Since DG drops are reported by the partner, we dont need to do any booking about
  2611. ** the orphaned checkpoints.
  2612. **
  2613. ** *!* This link's StateLock must be held on entry
  2614. */
  2615. #ifdef DBG
  2616. #undef DPF_MODNAME
  2617. #define DPF_MODNAME "DumpChkPtList"
  2618. VOID
  2619. DumpChkPtList(PEPD pEPD)
  2620. {
  2621. CBilink *pLink;
  2622. PCHKPT pCP;
  2623. AssertCriticalSectionIsTakenByThisThread(&pEPD->EPLock, TRUE);
  2624. DPFX(DPFPREP,1, "==== DUMPING CHECKPOINT LIST ==== (pEPD = %p)", pEPD);
  2625. pLink = pEPD->blChkPtQueue.GetNext();
  2626. while(pLink != &pEPD->blChkPtQueue)
  2627. {
  2628. pCP = CONTAINING_OBJECT(pLink, CHKPT, blLinkage);
  2629. DPFX(DPFPREP,1, "(%p) MsgID=%x; Timestamp=%x", pEPD, pCP->bMsgID, pCP->tTimestamp);
  2630. pLink = pLink->GetNext();
  2631. }
  2632. }
  2633. #endif // DBG
  2634. #undef DPF_MODNAME
  2635. #define DPF_MODNAME "LookupCheckPoint"
  2636. PCHKPT LookupCheckPoint(PEPD pEPD, BYTE bRspID)
  2637. {
  2638. CBilink *pLink;
  2639. PCHKPT pCP;
  2640. AssertCriticalSectionIsTakenByThisThread(&pEPD->EPLock, TRUE);
  2641. pCP = CONTAINING_OBJECT((pLink = pEPD->blChkPtQueue.GetNext()), CHKPT, blLinkage);
  2642. while(pLink != &pEPD->blChkPtQueue)
  2643. {
  2644. // Look for checkpoint that matches correlator
  2645. if(pCP->bMsgID == bRspID)
  2646. {
  2647. pLink->RemoveFromList();
  2648. return pCP;
  2649. }
  2650. // We have passed the spot for this correlator!
  2651. else if ((bRspID - pCP->bMsgID) & 0x80)
  2652. {
  2653. DPFX(DPFPREP,1, "(%p) CHECKPOINT NOT FOUND - Later Chkpt found in list (%x)", pEPD, bRspID);
  2654. return NULL;
  2655. }
  2656. else
  2657. {
  2658. pLink = pLink->GetNext(); // Remove ChkPts prior to the one received
  2659. pCP->blLinkage.RemoveFromList(); // ..target and remove the stale ones.
  2660. ChkPtPool.Release(pCP); // we expect them to complete in order of queue
  2661. pCP = CONTAINING_OBJECT(pLink, CHKPT, blLinkage);
  2662. }
  2663. }
  2664. DPFX(DPFPREP,1, "(%p) CHECKPOINT NOT FOUND - EXHAUSTED LIST W/O MATCH (%x)", pEPD, bRspID);
  2665. #ifdef DBG
  2666. DumpChkPtList(pEPD);
  2667. #endif // DBG
  2668. return NULL;
  2669. }
  2670. #undef DPF_MODNAME
  2671. #define DPF_MODNAME "FlushCheckPoints"
  2672. VOID FlushCheckPoints(PEPD pEPD)
  2673. {
  2674. PCHKPT pCP;
  2675. AssertCriticalSectionIsTakenByThisThread(&pEPD->EPLock, TRUE);
  2676. while(!pEPD->blChkPtQueue.IsEmpty())
  2677. {
  2678. pCP = CONTAINING_OBJECT(pEPD->blChkPtQueue.GetNext(), CHKPT, blLinkage);
  2679. pCP->blLinkage.RemoveFromList();
  2680. ChkPtPool.Release(pCP);
  2681. }
  2682. }
  2683. /*
  2684. ** Process End Of Stream
  2685. **
  2686. ** Our partner has initiated an orderly link termination. He will not be
  2687. ** sending us any more data. We are allowed to finish sending any data in our
  2688. ** pipeline, but should not allow any new sends to be accepted. When our send
  2689. ** pipeline is emptied, we should send an EOS frame and take down our
  2690. ** link. Easiest way to do this is enqueue the EOS at the end of send queue now.
  2691. */
  2692. #undef DPF_MODNAME
  2693. #define DPF_MODNAME "ProcessEndOfStream"
  2694. VOID ProcessEndOfStream(PEPD pEPD)
  2695. {
  2696. PMSD pMSD;
  2697. Lock(&pEPD->EPLock);
  2698. // Since an EOS comes in as a data packet, and we must be Connected to receive data, we know
  2699. // we can now be in either the Connected or Terminating state. If we are in the Terminating
  2700. // state, someone is already attempting to destroy the link and we will ignore this EOS, and
  2701. // let that termination finish. Otherwise, we expect to be in the Connected state, and this
  2702. // is a normal disconnect.
  2703. if (pEPD->ulEPFlags & EPFLAGS_STATE_TERMINATING)
  2704. {
  2705. DPFX(DPFPREP,7, "(%p) Received EndOfStream on an already terminating link, ignoring", pEPD);
  2706. Unlock(&pEPD->EPLock);
  2707. return;
  2708. }
  2709. ASSERT(pEPD->ulEPFlags & EPFLAGS_STATE_CONNECTED);
  2710. DPFX(DPFPREP,7, "(%p) Process EndOfStream", pEPD);
  2711. //we should never get both an EOS and a hard disconnect, since the remote ep should only
  2712. //ever attempt one type of disconnect, but lets code robustly and guard the case anyway
  2713. if (pEPD->ulEPFlags & EPFLAGS_HARD_DISCONNECT_TARGET)
  2714. {
  2715. DPFX(DPFPREP, 0, "(%p) Received both EOS and hard disconnect", pEPD);
  2716. DNASSERT(0);
  2717. Unlock(&pEPD->EPLock);
  2718. return;
  2719. }
  2720. //Possible that remote end start closing at the same time we started hard disconnect
  2721. //In which case we should ignore this EOS, as the hard disconnect takes priority
  2722. //We can't treat the EOS as the equivelant to a hard disconnect response because the sequence
  2723. // 1. Send Hard Disconnect. 2. Hard Disconnect Dropped. 3. Receive EOS and drop link
  2724. // would leave the far end hung until it timed out. Sending more hard disconnects will resolve this (hopefully!)
  2725. if (pEPD->ulEPFlags & EPFLAGS_HARD_DISCONNECT_SOURCE)
  2726. {
  2727. DPFX(DPFPREP, 7, "(%p) Received EOS with hard disconnect already started. Ignoring EOS", pEPD);
  2728. Unlock(&pEPD->EPLock);
  2729. return;
  2730. }
  2731. //if we've already received a disconnect then the close sequence will already have begun on this side
  2732. //hence nothing to do in this case
  2733. if(pEPD->ulEPFlags & EPFLAGS_RECEIVED_DISCONNECT)
  2734. {
  2735. DPFX(DPFPREP, 7, "(%p) Received another EOS. Ignoring this one", pEPD);
  2736. Unlock(&pEPD->EPLock);
  2737. return;
  2738. }
  2739. // Our side has not started closing yet, so our partner must have initiated a Disconnect.
  2740. // We are allowed to finish sending all data in our pipeline, but we should not accept
  2741. // any new data. We must deliver an indication to the application telling him that
  2742. // Disconnection is now underway.
  2743. //
  2744. // Please note that we do not set the TERMINATING flag until the Disconnecting indication
  2745. // returns. This allows the application to send any final messages (last words) before
  2746. // the gate is slammed shut.
  2747. DPFX(DPFPREP,7, "(%p) Partner Disconnect received (refcnt=%d)", pEPD, pEPD->lRefCnt);
  2748. // Don't let anyone else in here again.
  2749. pEPD->ulEPFlags |= EPFLAGS_RECEIVED_DISCONNECT;
  2750. // Force 3 disconnect ACKs now since we are going away.
  2751. // Setting fFinalAck to TRUE on last ACK so CommandComplete will drop if appropriate
  2752. DPFX(DPFPREP,7, "(%p) ACK'ing Partner's Disconnect", pEPD);
  2753. SendAckFrame(pEPD, 0);
  2754. SendAckFrame(pEPD, 0);
  2755. SendAckFrame(pEPD, 0, TRUE);
  2756. // There is the possibility that this side initiated a disconnect, and is now receiving a
  2757. // disconnect from the other side simultaneously. In this case, we do not want to tell the
  2758. // Core on our side about the disconnect, because the Core on our side is already disconnecting
  2759. // anyway. We also do not need to send an EOS, because we have sent one already, and can
  2760. // just wait for that one to be ACK'd.
  2761. if(!(pEPD->ulEPFlags & EPFLAGS_SENT_DISCONNECT))
  2762. {
  2763. // We know we won't get in here twice because of EPFLAGS_RECEIVED_DISCONNECT above.
  2764. Unlock(&pEPD->EPLock);
  2765. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blProtocolCritSecsHeld);
  2766. DPFX(DPFPREP,DPF_CALLOUT_LVL, "(%p) Calling Core->IndicateDisconnect, Core Context[%p]", pEPD, pEPD->Context);
  2767. pEPD->pSPD->pPData->pfVtbl->IndicateDisconnect(pEPD->pSPD->pPData->Parent, pEPD->Context);
  2768. Lock(&pEPD->EPLock);
  2769. // This will prevent any new sends, so don't set it until after calling IndicateDisconnect.
  2770. pEPD->ulEPFlags |= EPFLAGS_SENT_DISCONNECT;
  2771. if((pMSD = BuildDisconnectFrame(pEPD)) == NULL)
  2772. {
  2773. DropLink(pEPD); // DROPLINK will release EPLock for us
  2774. return;
  2775. }
  2776. pMSD->CommandID = COMMAND_ID_DISC_RESPONSE; // Mark MSD so we know its not a user command
  2777. LOCK_EPD(pEPD, "LOCK (DISC RESP)"); // Add reference for this frame
  2778. pEPD->pCommand = pMSD; // Store the DisconnectResp on the Endpoint until it is complete
  2779. DPFX(DPFPREP,7, "(%p) Responding to Disconnect. pMSD=0x%p", pEPD, pMSD);
  2780. EnqueueMessage(pMSD, pEPD); // Enqueue the DISC frame at end of sendQ
  2781. }
  2782. Unlock(&pEPD->EPLock);
  2783. }
  2784. /*
  2785. ** Process SP Disconnect
  2786. **
  2787. ** Service Provider has told us that an endpoint has gone away. This is probably
  2788. ** because we have Disconnected it ourselves, in which case the IN_USE flag will be
  2789. ** clear. Otherwise, we need to clean this thing up ourselves...
  2790. */
  2791. #undef DPF_MODNAME
  2792. #define DPF_MODNAME "ProcessSPDisconnect"
  2793. VOID
  2794. ProcessSPDisconnect(PSPD pSPD, PSPIE_DISCONNECT pDataBlock)
  2795. {
  2796. PEPD pEPD = static_cast<PEPD>( pDataBlock->pEndpointContext );
  2797. ASSERT_EPD(pEPD);
  2798. ASSERT(pEPD->pSPD == pSPD);
  2799. ASSERT(pDataBlock->hEndpoint == pEPD->hEndPt);
  2800. PMSD pMSD = NULL;
  2801. DPFX(DPFPREP,DPF_CALLIN_LVL, "Parameters: pSPD[%p], pDataBlock[%p] - pEPD[%p]", pSPD, pDataBlock, pEPD);
  2802. Lock(&pEPD->EPLock);
  2803. // Make sure ReleaseEPD knows that this occurred
  2804. pEPD->ulEPFlags |= EPFLAGS_SP_DISCONNECTED;
  2805. if (!(pEPD->ulEPFlags & EPFLAGS_STATE_TERMINATING))
  2806. {
  2807. DECREMENT_EPD(pEPD, "SP reference"); // Remove the SP reference
  2808. // If there is an outstanding connection, clean it up
  2809. if (pEPD->ulEPFlags & (EPFLAGS_STATE_CONNECTING|EPFLAGS_STATE_DORMANT))
  2810. {
  2811. // Even if this is COMMAND_ID_CONNECT this is safe to do
  2812. pEPD->ulEPFlags &= ~(EPFLAGS_LINKED_TO_LISTEN);
  2813. pEPD->blSPLinkage.RemoveFromList(); // Unlink EPD from Listen Queue
  2814. // We know this will only happen once because the person who does it will transition us out
  2815. // of the CONNECTING state, and we can't get here unless we are in that state.
  2816. pMSD = pEPD->pCommand;
  2817. pEPD->pCommand = NULL;
  2818. }
  2819. DropLink(pEPD); // This will release the EPLock
  2820. if (pMSD)
  2821. {
  2822. Lock(&pMSD->CommandLock);
  2823. RELEASE_MSD(pMSD, "EPD Ref");
  2824. }
  2825. }
  2826. else
  2827. {
  2828. #ifndef DPNBUILD_NOMULTICAST
  2829. if (pEPD->ulEPFlags2 & (EPFLAGS2_MULTICAST_SEND|EPFLAGS2_MULTICAST_RECEIVE))
  2830. {
  2831. //
  2832. // We will need to generate a completion to the core
  2833. //
  2834. pMSD = pEPD->pCommand;
  2835. Unlock(&pEPD->EPLock);
  2836. Lock(&pMSD->CommandLock);
  2837. CompleteDisconnect(pMSD,pSPD,pEPD);
  2838. pMSD = NULL;
  2839. }
  2840. else
  2841. #endif // DPNBUILD_NOMULTICAST
  2842. {
  2843. RELEASE_EPD(pEPD, "SP reference"); // releases EPLock
  2844. }
  2845. }
  2846. }
  2847. /*
  2848. ** Process Listen Status
  2849. **
  2850. ** This call tells us that a submitted Listen command has become active. Truth is, we
  2851. ** dont care. We are just interested in seeing the Connect indications as they arrive. What we
  2852. ** do care about, however, is the Endpoint handle associated with this listen in case we are
  2853. ** later asked about the address associated with the listen. So we will pull it out of the
  2854. ** data block and save it in our MSD.
  2855. */
  2856. #undef DPF_MODNAME
  2857. #define DPF_MODNAME "ProcessListenStatus"
  2858. VOID
  2859. ProcessListenStatus(PSPD pSPD, PSPIE_LISTENSTATUS pDataBlock)
  2860. {
  2861. PMSD pMSD;
  2862. DPFX(DPFPREP,DPF_CALLIN_LVL, "Parameters: pSPD[%p], pDataBlock[%p] - hr=%x", pSPD, pDataBlock, pDataBlock->hResult);
  2863. pMSD = (PMSD) pDataBlock->pUserContext;
  2864. ASSERT_MSD(pMSD);
  2865. ASSERT(pMSD->pSPD == pSPD);
  2866. #ifdef DPNBUILD_NOMULTICAST
  2867. ASSERT(pMSD->CommandID == COMMAND_ID_LISTEN);
  2868. #else // ! DPNBUILD_NOMULTICAST
  2869. ASSERT((pMSD->CommandID == COMMAND_ID_LISTEN) || (pMSD->CommandID == COMMAND_ID_LISTEN_MULTICAST));
  2870. #endif // ! DPNBUILD_NOMULTICAST
  2871. ASSERT(pDataBlock->hCommand == pMSD->hCommand || pMSD->hCommand == NULL);
  2872. pMSD->hListenEndpoint = pDataBlock->hEndpoint;
  2873. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blProtocolCritSecsHeld);
  2874. DPFX(DPFPREP,DPF_CALLOUT_LVL, "Calling Core->CompleteListen, pMSD[%p], Core Context[%p], hr[%x]", pMSD, pMSD->Context, pDataBlock->hResult);
  2875. pSPD->pPData->pfVtbl->CompleteListen(pSPD->pPData->Parent, &pMSD->Context, pDataBlock->hResult, pMSD);
  2876. if(pDataBlock->hResult != DPN_OK)
  2877. {
  2878. // Release the final reference on the MSD AFTER indicating to the Core
  2879. Lock(&pMSD->CommandLock);
  2880. RELEASE_MSD(pMSD, "Release On Complete");
  2881. }
  2882. return;
  2883. }
  2884. /*
  2885. ** Process Connect Address Info
  2886. **
  2887. ** This call tells us what addressing information has been used to start a connect.
  2888. */
  2889. #undef DPF_MODNAME
  2890. #define DPF_MODNAME "ProcessConnectAddressInfo"
  2891. VOID
  2892. ProcessConnectAddressInfo(PSPD pSPD, PSPIE_CONNECTADDRESSINFO pDataBlock)
  2893. {
  2894. PMSD pMSD;
  2895. pMSD = (PMSD) pDataBlock->pCommandContext;
  2896. DPFX(DPFPREP,DPF_CALLIN_LVL, "Parameters: pSPD[%p], pDataBlock[%p] - pMSD[%p]", pSPD, pDataBlock, pMSD);
  2897. ASSERT_MSD(pMSD);
  2898. ASSERT(pMSD->pSPD == pSPD);
  2899. #ifdef DPNBUILD_NOMULTICAST
  2900. ASSERT(pMSD->CommandID == COMMAND_ID_CONNECT);
  2901. #else // ! DPNBUILD_NOMULTICAST
  2902. ASSERT((pMSD->CommandID == COMMAND_ID_CONNECT) || (pMSD->CommandID == COMMAND_ID_CONNECT_MULTICAST_SEND) || (pMSD->CommandID == COMMAND_ID_CONNECT_MULTICAST_RECEIVE));
  2903. #endif // ! DPNBUILD_NOMULTICAST
  2904. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blProtocolCritSecsHeld);
  2905. DPFX(DPFPREP,DPF_CALLOUT_LVL, "(%p) Calling Core->AddressInfoConnect, Core Context[%p]", pMSD, pMSD->Context);
  2906. pSPD->pPData->pfVtbl->AddressInfoConnect( pSPD->pPData->Parent,
  2907. pMSD->Context,
  2908. pDataBlock->hCommandStatus,
  2909. pDataBlock->pHostAddress,
  2910. pDataBlock->pDeviceAddress );
  2911. return;
  2912. }
  2913. /*
  2914. ** Process Enum Address Info
  2915. **
  2916. ** This call tells us what addressing information has been used to start an enum.
  2917. */
  2918. #undef DPF_MODNAME
  2919. #define DPF_MODNAME "ProcessEnumAddressInfo"
  2920. VOID
  2921. ProcessEnumAddressInfo(PSPD pSPD, PSPIE_ENUMADDRESSINFO pDataBlock)
  2922. {
  2923. PMSD pMSD;
  2924. pMSD = (PMSD) pDataBlock->pCommandContext;
  2925. DPFX(DPFPREP,DPF_CALLIN_LVL, "Parameters: pSPD[%p], pDataBlock[%p] - pMSD[%p]", pSPD, pDataBlock, pMSD);
  2926. ASSERT_MSD(pMSD);
  2927. ASSERT(pMSD->pSPD == pSPD);
  2928. ASSERT(pMSD->CommandID == COMMAND_ID_ENUM );
  2929. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blProtocolCritSecsHeld);
  2930. DPFX(DPFPREP,DPF_CALLOUT_LVL, "(%p) Calling Core->AddressInfoEnum, Core Context[%p]", pMSD, pMSD->Context);
  2931. pSPD->pPData->pfVtbl->AddressInfoEnum( pSPD->pPData->Parent,
  2932. pMSD->Context,
  2933. pDataBlock->hCommandStatus,
  2934. pDataBlock->pHostAddress,
  2935. pDataBlock->pDeviceAddress );
  2936. return;
  2937. }
  2938. /*
  2939. ** Process Listen Address Info
  2940. **
  2941. ** This call tells us what addressing information has been used to start a listen.
  2942. */
  2943. #undef DPF_MODNAME
  2944. #define DPF_MODNAME "ProcessListenAddressInfo"
  2945. VOID
  2946. ProcessListenAddressInfo(PSPD pSPD, PSPIE_LISTENADDRESSINFO pDataBlock)
  2947. {
  2948. PMSD pMSD;
  2949. pMSD = (PMSD) pDataBlock->pCommandContext;
  2950. DPFX(DPFPREP,DPF_CALLIN_LVL, "Parameters: pSPD[%p], pDataBlock[%p] - pMSD[%p]", pSPD, pDataBlock, pMSD);
  2951. ASSERT_MSD(pMSD);
  2952. ASSERT(pMSD->pSPD == pSPD);
  2953. #ifdef DPNBUILD_NOMULTICAST
  2954. ASSERT(pMSD->CommandID == COMMAND_ID_LISTEN);
  2955. #else // ! DPNBUILD_NOMULTICAST
  2956. ASSERT((pMSD->CommandID == COMMAND_ID_LISTEN) || (pMSD->CommandID == COMMAND_ID_LISTEN_MULTICAST));
  2957. #endif // ! DPNBUILD_NOMULTICAST
  2958. AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blProtocolCritSecsHeld);
  2959. DPFX(DPFPREP,DPF_CALLOUT_LVL, "(%p) Calling Core->AddressInfoListen, Core Context[%p]", pMSD, pMSD->Context);
  2960. pSPD->pPData->pfVtbl->AddressInfoListen( pSPD->pPData->Parent,
  2961. pMSD->Context,
  2962. pDataBlock->hCommandStatus,
  2963. pDataBlock->pDeviceAddress );
  2964. return;
  2965. }
  2966. /*
  2967. ** Process Hard Disconnect
  2968. **
  2969. ** Called when we receive a hard disconnect frame
  2970. ** CALLED WITH EPLOCK HELD; RETURNS WITH EPLOCK RELEASED
  2971. */
  2972. #undef DPF_MODNAME
  2973. #define DPF_MODNAME "ProcessHardDisconnect"
  2974. VOID
  2975. ProcessHardDisconnect(PEPD pEPD)
  2976. {
  2977. AssertCriticalSectionIsTakenByThisThread(&pEPD->EPLock, TRUE);
  2978. //if the ep is in the process of terminating we should do nothing
  2979. if (pEPD->ulEPFlags & EPFLAGS_STATE_TERMINATING)
  2980. {
  2981. DPFX(DPFPREP, 7, "(%p) Ignoring Hard Disconnect on terminating endpoint", pEPD);
  2982. Unlock(&pEPD->EPLock);
  2983. return;
  2984. }
  2985. //if we're the source for this hard disconnect sequence then this is our cue to drop the
  2986. //link and complete the disconnect
  2987. //N.B. Its possible both sides attempted a hard disconnect at the same time. In which case
  2988. //they'll both assume each other hard disconnect frames were actually responses to what
  2989. //they sent, and everything proceeds swimmingly
  2990. if (pEPD->ulEPFlags & EPFLAGS_HARD_DISCONNECT_SOURCE)
  2991. {
  2992. CompleteHardDisconnect(pEPD);
  2993. //above call will release EP lock
  2994. return;
  2995. }
  2996. //if we've already received a hard disconnect frame then we'll already have started
  2997. //the respond/drop link sequence, so can ignore this new request
  2998. if (pEPD->ulEPFlags & EPFLAGS_HARD_DISCONNECT_TARGET)
  2999. {
  3000. DPFX(DPFPREP, 7, "(%p) Ignoring Hard Disconnect. Already marked as hard disconnect target", pEPD);
  3001. Unlock(&pEPD->EPLock);
  3002. return;
  3003. }
  3004. //looks like remote ep wants to kick off a hard disconnect sequence
  3005. pEPD->ulEPFlags|=EPFLAGS_HARD_DISCONNECT_TARGET;
  3006. DNASSERT((pEPD->ulEPFlags2 & EPFLAGS2_HARD_DISCONNECT_COMPLETE)==0);
  3007. //add a reference to the endpoint to make sure it hangs around whilst we complete our response
  3008. //this is dropped in the CompleteHardDisconnect function
  3009. LOCK_EPD(pEPD, "LOCK (HARD DISCONNECT RESPONSE)");
  3010. //now send 3 hard disconnects back to the other side immediately
  3011. //assuming 1 of them gets through this'll tell the originator of the hard disconnect
  3012. //he can stop sending hard disconnect frames to us. If they all drop it doesn't matter too much,
  3013. //as the originator will give up sending at some point pretty soon anyway
  3014. SendCommandFrame(pEPD, FRAME_EXOPCODE_HARD_DISCONNECT, 0, 0, FALSE);
  3015. SendCommandFrame(pEPD, FRAME_EXOPCODE_HARD_DISCONNECT, 0, 0, FALSE);
  3016. //N.B. The final send command frame has the bSendDirect flag set to TRUE
  3017. //this causes the queued send frames to be commited to the SP. It also has the final hard disconnect flag
  3018. //set. This ensures when the SP completes the send of this command frame we know to drop the link
  3019. HRESULT hr=SendCommandFrame(pEPD, FRAME_EXOPCODE_HARD_DISCONNECT,
  3020. 0, FFLAGS_FINAL_HARD_DISCONNECT, TRUE);
  3021. //EP lock is released by above call (since bSendDirect==TRUE)
  3022. //if the final send fails then we can't wait for the send completition from the sp to complete the disconnect
  3023. //hence we have to do it now
  3024. if (FAILED(hr))
  3025. {
  3026. Lock(&pEPD->EPLock);
  3027. DPFX(DPFPREP, 0, "(%p) Failed to send final HARD_DISCONNECT. Completing disconnect immediately hr[0x%x]", pEPD, hr);
  3028. CompleteHardDisconnect(pEPD);
  3029. //above call will release ep lock
  3030. }
  3031. }
  3032. /*
  3033. ** Create Connected Signed Reply
  3034. **
  3035. ** Called when we're listening for connections to a signed session and we either get a CONNECT or a KEEPALIVE that looks
  3036. ** like the first KEEPALIVE in a session. We want to return a CONNECTEDSIGNED response in the supplied reply buffer
  3037. **
  3038. */
  3039. #undef DPF_MODNAME
  3040. #define DPF_MODNAME "CreateConnectedSignedFrame"
  3041. HRESULT CreateConnectedSignedReply(void * pvReplyBuffer, DWORD * pdwReplySize, DWORD dwSessID, DWORD dwAddressHash,
  3042. ULONGLONG ullConnectSecret, DWORD dwSigningOpts, DWORD tNow)
  3043. {
  3044. //if the reply buffer isn't large enough to send our response then tell the SP to do nothing
  3045. if (*pdwReplySize<sizeof(CFRAME_CONNECTEDSIGNED))
  3046. {
  3047. DPFX(DPFPREP, 0, "Unconnected data reply buffer too small to send CONNECTEDSIGNED response");
  3048. DNASSERT(0);
  3049. return DPNERR_ABORTED;
  3050. }
  3051. *pdwReplySize=sizeof(CFRAME_CONNECTEDSIGNED);
  3052. CFRAME_CONNECTEDSIGNED * pCFrame=(CFRAME_CONNECTEDSIGNED * ) pvReplyBuffer;
  3053. //Set members common to all CFrames
  3054. //N.B. We set the poll bit to indicate that this is the reponse from the listening side
  3055. //When the connector sends its CONNECTSIGNED frame it won't set this bit
  3056. pCFrame->bCommand = PACKET_COMMAND_CFRAME | PACKET_COMMAND_POLL;
  3057. pCFrame->bExtOpcode = FRAME_EXOPCODE_CONNECTED_SIGNED;
  3058. pCFrame->dwVersion = DNET_VERSION_NUMBER;
  3059. pCFrame->bRspID = 0;
  3060. pCFrame->dwSessID = dwSessID;
  3061. pCFrame->tTimestamp = tNow;
  3062. pCFrame->bMsgID = 0;
  3063. //set members specific just to CONNECTEDSIGNED frames
  3064. //N.B. We let the connector pick the secrets, so we zero out the ones we send. And the EchoTimestamp is
  3065. //unused because the connecting endpoint will use a checkpoint to track the RTT.
  3066. pCFrame->ullConnectSig=GenerateConnectSig(dwSessID, dwAddressHash, ullConnectSecret);
  3067. pCFrame->ullSenderSecret=0;
  3068. pCFrame->ullReceiverSecret=0;
  3069. pCFrame->dwSigningOpts=dwSigningOpts;
  3070. pCFrame->dwEchoTimestamp=0;
  3071. //tell the sp to send the data we've placed in the reply buffer
  3072. return DPNSUCCESS_PENDING;
  3073. }
  3074. #undef DPF_MODNAME
  3075. #define DPF_MODNAME "ValidateIncomingFrameSig"
  3076. BOOL ValidateIncomingFrameSig(PEPD pEPD, BYTE * pbyFrame, DWORD dwFrameSize, BYTE bSeq, UNALIGNED ULONGLONG * pullFrameSig)
  3077. {
  3078. //fast signing is trivial, simply check for a match on the (not very) secret
  3079. if (pEPD->ulEPFlags2 & EPFLAGS2_FAST_SIGNED_LINK)
  3080. {
  3081. if (*pullFrameSig!=pEPD->ullCurrentRemoteSecret)
  3082. {
  3083. DPFX(DPFPREP,1, "(%p) Invalid signature on fast signed link", pEPD);
  3084. return FALSE;
  3085. }
  3086. return TRUE;
  3087. }
  3088. DNASSERT(pEPD->ulEPFlags2 & EPFLAGS2_FULL_SIGNED_LINK);
  3089. //store the sig from the packet and then zero it out. This ensures the state of the packet
  3090. //matches what it should have been when it was originally signed
  3091. ULONGLONG ullSuppliedSig=*pullFrameSig;
  3092. *pullFrameSig=0;
  3093. //sig to use depends on where we are in the sequence space and where the packet is
  3094. if ((pEPD->bNextReceive>=SEQ_WINDOW_3Q || pEPD->bNextReceive<SEQ_WINDOW_1Q) && (bSeq>=SEQ_WINDOW_3Q))
  3095. {
  3096. if (GenerateIncomingFrameSig(pbyFrame, dwFrameSize, pEPD->ullOldRemoteSecret)!=ullSuppliedSig)
  3097. {
  3098. DPFX(DPFPREP,1, "(%p) Invalid signature on full signed link", pEPD);
  3099. return FALSE;
  3100. }
  3101. }
  3102. else
  3103. {
  3104. if (GenerateIncomingFrameSig(pbyFrame, dwFrameSize, pEPD->ullCurrentRemoteSecret)!=ullSuppliedSig)
  3105. {
  3106. DPFX(DPFPREP,1, "(%p) Invalid signature on full signed link", pEPD);
  3107. return FALSE;
  3108. }
  3109. }
  3110. return TRUE;
  3111. }
  3112. /*************************************
  3113. **
  3114. ** RECEIVE BUFFER MANAGEMENT
  3115. **
  3116. ** When multiple frame messages arrive we *may* have to copy them in to a single contiguous
  3117. ** buffer. We are supporting an OPTIONAL scatter-receive option which would allow sophisticated
  3118. ** clients to receive a BUFFER_DESCRIPTOR array instead of a single cont-buffer, and avoiding
  3119. ** a large datacopy.
  3120. **
  3121. ** For clients which dont support scatter-receive, we need a pooling strategy for large receive
  3122. ** buffers. We will only need buffers LARGER then our frame limit because smaller receives are delivered
  3123. ** in the SPs buffer.
  3124. **
  3125. ** Try placing receives into generally sized buffers. If frame size is usu 1.4K bytes, 2K is a small
  3126. ** buffer, 4K, 16K, 32K, 64K. If frame size is <1K we can have 1K buffers too.
  3127. **
  3128. **
  3129. *************************************/
  3130. /***********************
  3131. ========SPACER==========
  3132. ************************/
  3133. /*
  3134. ** RCD Pool support routines
  3135. **
  3136. ** These are the functions called by Fixed Pool Manager as it handles RCDs.
  3137. */
  3138. #define pELEMENT ((PRCD) pElement)
  3139. #undef DPF_MODNAME
  3140. #define DPF_MODNAME "RCD_Allocate"
  3141. BOOL RCD_Allocate(PVOID pElement, PVOID pvContext)
  3142. {
  3143. DPFX(DPFPREP,7, "(%p) Allocating new RCD", pELEMENT);
  3144. pELEMENT->blOddFrameLinkage.Initialize();
  3145. pELEMENT->blCompleteLinkage.Initialize();
  3146. pELEMENT->Sign = RCD_SIGN;
  3147. return TRUE;
  3148. }
  3149. // Get is called each time an MSD is used
  3150. #undef DPF_MODNAME
  3151. #define DPF_MODNAME "RCD_Get"
  3152. VOID RCD_Get(PVOID pElement, PVOID pvContext)
  3153. {
  3154. DPFX(DPFPREP,DPF_REFCNT_FINAL_LVL, "CREATING RCD %p", pELEMENT);
  3155. // NOTE: First sizeof(PVOID) bytes will have been overwritten by the pool code,
  3156. // we must set them to acceptable values.
  3157. pELEMENT->pRcvBuff = NULL;
  3158. pELEMENT->lRefCnt = 1;
  3159. pELEMENT->ulRFlags = 0;
  3160. ASSERT( pELEMENT->blOddFrameLinkage.IsEmpty());
  3161. ASSERT( pELEMENT->blCompleteLinkage.IsEmpty());
  3162. ASSERT_RCD(pELEMENT);
  3163. }
  3164. // RCD Release -- This release call will release an entire chain of RCDs
  3165. // that are linked together... or then again maybe not.
  3166. #undef DPF_MODNAME
  3167. #define DPF_MODNAME "RCD_Release"
  3168. VOID RCD_Release(PVOID pElement)
  3169. {
  3170. ASSERT_RCD(pELEMENT);
  3171. ASSERT(pELEMENT->lRefCnt == 0);
  3172. ASSERT(pELEMENT->pRcvBuff == NULL);
  3173. ASSERT( pELEMENT->blOddFrameLinkage.IsEmpty());
  3174. ASSERT( pELEMENT->blCompleteLinkage.IsEmpty());
  3175. DPFX(DPFPREP,DPF_REFCNT_FINAL_LVL, "RELEASING RCD %p", pELEMENT);
  3176. }
  3177. #undef DPF_MODNAME
  3178. #define DPF_MODNAME "RCD_Free"
  3179. VOID RCD_Free(PVOID pElement)
  3180. {
  3181. }
  3182. #undef pELEMENT
  3183. /*
  3184. ** Buffer pool support
  3185. **
  3186. **
  3187. */
  3188. #define pELEMENT ((PBUF) pElement)
  3189. #undef DPF_MODNAME
  3190. #define DPF_MODNAME "Buf_Allocate"
  3191. BOOL Buf_Allocate(PVOID pElement, PVOID pvContext)
  3192. {
  3193. DPFX(DPFPREP,7, "(%p) Allocating new Buf", pElement);
  3194. return TRUE;
  3195. }
  3196. #undef DPF_MODNAME
  3197. #define DPF_MODNAME "Buf_Get"
  3198. VOID Buf_Get(PVOID pElement, PVOID pvContext)
  3199. {
  3200. // NOTE: First sizeof(PVOID) bytes will have been overwritten by the pool code,
  3201. // we must set them to acceptable values.
  3202. pELEMENT->Type = RBT_PROTOCOL_NORM_BUFFER;
  3203. }
  3204. #undef DPF_MODNAME
  3205. #define DPF_MODNAME "Buf_GetMed"
  3206. VOID Buf_GetMed(PVOID pElement, PVOID pvContext)
  3207. {
  3208. // NOTE: First sizeof(PVOID) bytes will have been overwritten by the pool code,
  3209. // we must set them to acceptable values.
  3210. pELEMENT->Type = RBT_PROTOCOL_MED_BUFFER;
  3211. }
  3212. #undef DPF_MODNAME
  3213. #define DPF_MODNAME "Buf_GetBig"
  3214. VOID Buf_GetBig(PVOID pElement, PVOID pvContext)
  3215. {
  3216. // NOTE: First sizeof(PVOID) bytes will have been overwritten by the pool code,
  3217. // we must set them to acceptable values.
  3218. pELEMENT->Type = RBT_PROTOCOL_BIG_BUFFER;
  3219. }
  3220. #undef pELEMENT