Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1615 lines
39 KiB

  1. /*
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. tcputil.c
  5. Abstract:
  6. This module contains utility routines that used to implement the AFP/TCP interface
  7. Author:
  8. Shirish Koti
  9. Revision History:
  10. 22 Jan 1998 Initial Version
  11. --*/
  12. #define FILENUM FILE_TCPUTIL
  13. #include <afp.h>
  14. #include <scavengr.h>
  15. /*** DsiInit
  16. *
  17. * This routine initialization of DSI related globals
  18. *
  19. * Returns: nothing
  20. *
  21. */
  22. VOID
  23. DsiInit(
  24. IN VOID
  25. )
  26. {
  27. DsiTcpAdapter = NULL;
  28. INITIALIZE_SPIN_LOCK(&DsiAddressLock);
  29. INITIALIZE_SPIN_LOCK(&DsiResourceLock);
  30. InitializeListHead(&DsiFreeRequestList);
  31. InitializeListHead(&DsiIpAddrList);
  32. KeInitializeEvent(&DsiShutdownEvent, NotificationEvent, False);
  33. //
  34. // initialize the function table of entry points into DSI
  35. //
  36. AfpDsiEntries.asp_AtalkAddr.Address = 0;
  37. AfpDsiEntries.asp_AspCtxt = NULL;
  38. AfpDsiEntries.asp_SetStatus = DsiAfpSetStatus;
  39. AfpDsiEntries.asp_CloseConn = DsiAfpCloseConn;
  40. AfpDsiEntries.asp_FreeConn = DsiAfpFreeConn;
  41. AfpDsiEntries.asp_ListenControl = DsiAfpListenControl;
  42. AfpDsiEntries.asp_WriteContinue = DsiAfpWriteContinue;
  43. AfpDsiEntries.asp_Reply = DsiAfpReply;
  44. AfpDsiEntries.asp_SendAttention = DsiAfpSendAttention;
  45. }
  46. /*** DsiCreateAdapter
  47. *
  48. * This routine creates an adapter object. It's called whenever TDI tells us that
  49. * a tcpip interface became available
  50. *
  51. * Returns: status of operation
  52. *
  53. */
  54. NTSTATUS FASTCALL
  55. DsiCreateAdapter(
  56. IN VOID
  57. )
  58. {
  59. NTSTATUS status;
  60. PTCPADPTR pTcpAdptr;
  61. PTCPADPTR pCurrTcpAdptr;
  62. KIRQL OldIrql;
  63. HANDLE FileHandle;
  64. PFILE_OBJECT pFileObject;
  65. DWORD i;
  66. KeClearEvent(&DsiShutdownEvent);
  67. pTcpAdptr = (PTCPADPTR)AfpAllocZeroedNonPagedMemory(sizeof(TCPADPTR));
  68. if (pTcpAdptr == NULL)
  69. {
  70. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  71. ("DsiCreateInterface: alloc for PTCPADPTR failed\n"));
  72. status = STATUS_INSUFFICIENT_RESOURCES;
  73. goto DsiCreateAdapter_ErrExit;
  74. }
  75. pTcpAdptr->adp_Signature = DSI_ADAPTER_SIGNATURE;
  76. pTcpAdptr->adp_RefCount = 1; // creation refcount
  77. pTcpAdptr->adp_State = TCPADPTR_STATE_INIT;
  78. InitializeListHead(&pTcpAdptr->adp_ActiveConnHead);
  79. InitializeListHead(&pTcpAdptr->adp_FreeConnHead);
  80. INITIALIZE_SPIN_LOCK(&pTcpAdptr->adp_SpinLock);
  81. pTcpAdptr->adp_FileHandle = INVALID_HANDLE_VALUE;
  82. pTcpAdptr->adp_pFileObject = NULL;
  83. //
  84. // ok, save this adapter as our global adapter (there can only be one
  85. // "adapter" active at any time.
  86. //
  87. ACQUIRE_SPIN_LOCK(&DsiAddressLock, &OldIrql);
  88. ASSERT(DsiTcpAdapter == NULL);
  89. if (DsiTcpAdapter == NULL)
  90. {
  91. DsiTcpAdapter = pTcpAdptr;
  92. status = STATUS_SUCCESS;
  93. RELEASE_SPIN_LOCK(&DsiAddressLock, OldIrql);
  94. }
  95. else
  96. {
  97. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  98. ("DsiCreateAdapter: DsiTcpAdapter is not NULL!\n"));
  99. ASSERT(0);
  100. status = STATUS_ADDRESS_ALREADY_EXISTS;
  101. RELEASE_SPIN_LOCK(&DsiAddressLock, OldIrql);
  102. goto DsiCreateAdapter_ErrExit;
  103. }
  104. //
  105. // create TDI address for the AFP port
  106. //
  107. status = DsiOpenTdiAddress(pTcpAdptr,
  108. &FileHandle,
  109. &pFileObject);
  110. if (!NT_SUCCESS(status))
  111. {
  112. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  113. ("DsiCreateAdapter: ...TdiAddr.. failed %lx on %lx!\n",
  114. status,pTcpAdptr));
  115. goto DsiCreateAdapter_ErrExit;
  116. }
  117. ACQUIRE_SPIN_LOCK(&pTcpAdptr->adp_SpinLock, &OldIrql);
  118. pTcpAdptr->adp_FileHandle = FileHandle;
  119. pTcpAdptr->adp_pFileObject = pFileObject;
  120. // mark that we now have opened the tdi address object
  121. pTcpAdptr->adp_State |= TCPADPTR_STATE_BOUND;
  122. // we are going to create DSI_INIT_FREECONNLIST_SIZE connections to put
  123. // on the free list. Idea is at any time, so many (currently 2) connections
  124. // should be on the free list.
  125. pTcpAdptr->adp_RefCount += DSI_INIT_FREECONNLIST_SIZE;
  126. RELEASE_SPIN_LOCK(&pTcpAdptr->adp_SpinLock, OldIrql);
  127. //
  128. // now, schedule an event to create those connections for the free list
  129. //
  130. for (i=0; i<DSI_INIT_FREECONNLIST_SIZE; i++)
  131. {
  132. DsiScheduleWorkerEvent(DsiCreateTcpConn, pTcpAdptr);
  133. }
  134. ACQUIRE_SPIN_LOCK(&DsiAddressLock, &OldIrql);
  135. AfpServerBoundToTcp = TRUE;
  136. RELEASE_SPIN_LOCK(&DsiAddressLock, OldIrql);
  137. // start off tickle timer (monitor all connections to see who needs a tickle)
  138. AfpScavengerScheduleEvent(DsiSendTickles, NULL, DSI_TICKLE_TIMER, False);
  139. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,("AFP/TCP bound and ready\n"));
  140. //
  141. // if we came this far, all went well: return success
  142. //
  143. return(STATUS_SUCCESS);
  144. //
  145. // Error path
  146. //
  147. DsiCreateAdapter_ErrExit:
  148. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  149. ("DsiCreateAdapter: couldn't create global adapter (%lx)\n",status));
  150. ASSERT(0);
  151. if (status != STATUS_ADDRESS_ALREADY_EXISTS)
  152. {
  153. ACQUIRE_SPIN_LOCK(&DsiAddressLock, &OldIrql);
  154. DsiTcpAdapter = NULL;
  155. RELEASE_SPIN_LOCK(&DsiAddressLock, OldIrql);
  156. }
  157. if (pTcpAdptr)
  158. {
  159. AfpFreeMemory(pTcpAdptr);
  160. }
  161. return(status);
  162. }
  163. /*** DsiCreateTcpConn
  164. *
  165. * This routine creates a connection object, creates a tdi connection for it
  166. * and associates it with the tdi address object for the AFP port, and finally
  167. * puts it on the free connections list of the adapter in question.
  168. *
  169. * Parm IN: pTcpAdptr - adapter context
  170. *
  171. * Returns: status of operation
  172. *
  173. */
  174. NTSTATUS FASTCALL
  175. DsiCreateTcpConn(
  176. IN PTCPADPTR pTcpAdptr
  177. )
  178. {
  179. PTCPCONN pTcpConn;
  180. NTSTATUS status;
  181. KIRQL OldIrql;
  182. ASSERT(pTcpAdptr->adp_Signature == DSI_ADAPTER_SIGNATURE);
  183. pTcpConn = (PTCPCONN)AfpAllocZeroedNonPagedMemory(sizeof(TCPCONN));
  184. if (pTcpConn == NULL)
  185. {
  186. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  187. ("DsiCreateTcpConn: alloc for TCPCONN failed\n"));
  188. // remove the CONN refcount (we put before calling this routine)
  189. DsiDereferenceAdapter(pTcpAdptr);
  190. return(STATUS_INSUFFICIENT_RESOURCES);
  191. }
  192. pTcpConn->con_pTcpAdptr = pTcpAdptr;
  193. pTcpConn->con_Signature = DSI_CONN_SIGNATURE;
  194. pTcpConn->con_State = TCPCONN_STATE_INIT;
  195. pTcpConn->con_RcvState = DSI_NEW_REQUEST;
  196. pTcpConn->con_DestIpAddr = 0;
  197. pTcpConn->con_RefCount = 1;
  198. pTcpConn->con_pDsiReq = NULL;
  199. pTcpConn->con_FileHandle = INVALID_HANDLE_VALUE;
  200. pTcpConn->con_pFileObject = NULL;
  201. DBGREFCOUNT(("DsiCreateTcpConn: CREATION inc %lx (%d %d,%d)\n",
  202. pTcpConn,pTcpConn->con_RefCount,pTcpConn->con_State,pTcpConn->con_RcvState));
  203. InitializeListHead(&pTcpConn->con_PendingReqs);
  204. //
  205. // initialize the TDI stuff for this connection and open handles
  206. //
  207. status = DsiOpenTdiConnection(pTcpConn);
  208. if (!NT_SUCCESS(status))
  209. {
  210. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  211. ("DsiCreateTcpConn: ..TdiConn.. failed %lx\n",status));
  212. // remove the CONN refcount (we put before calling this routine)
  213. DsiDereferenceAdapter(pTcpAdptr);
  214. AfpFreeMemory(pTcpConn);
  215. return(status);
  216. }
  217. //
  218. // associate this connection with the addr object
  219. //
  220. status = DsiAssociateTdiConnection(pTcpConn);
  221. if (!NT_SUCCESS(status))
  222. {
  223. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  224. ("DsiCreateTcpConn: ..AssociateTdiConn.. failed %lx\n",status));
  225. DsiCloseTdiConnection(pTcpConn);
  226. AfpFreeMemory(pTcpConn);
  227. // remove the CONN refcount (we put before calling this routine)
  228. DsiDereferenceAdapter(pTcpAdptr);
  229. return(status);
  230. }
  231. //
  232. // the connection is ready to be queued to the Free list. Make sure the
  233. // addr object isn't closing before putting this puppy on the list
  234. //
  235. ACQUIRE_SPIN_LOCK(&pTcpAdptr->adp_SpinLock, &OldIrql);
  236. if (!(pTcpAdptr->adp_State & TCPADPTR_STATE_CLOSING))
  237. {
  238. InsertTailList(&pTcpAdptr->adp_FreeConnHead,&pTcpConn->con_Linkage);
  239. pTcpAdptr->adp_NumFreeConnections++;
  240. status = STATUS_SUCCESS;
  241. }
  242. else
  243. {
  244. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  245. ("DsiCreateTcpConn: Failed #2, pTcpAdptr %lx is closing\n",pTcpAdptr));
  246. status = STATUS_INVALID_ADDRESS;
  247. }
  248. RELEASE_SPIN_LOCK(&pTcpAdptr->adp_SpinLock, OldIrql);
  249. //
  250. // if something went wrong, undo everything
  251. //
  252. if (!NT_SUCCESS(status))
  253. {
  254. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  255. ("DsiCreateTcpConn: something went wrong status=%lx, conn not created\n",status));
  256. // close the TDI handles
  257. DsiCloseTdiConnection(pTcpConn);
  258. AfpFreeMemory(pTcpConn);
  259. // remove the CONN refcount (we put before calling this routine)
  260. DsiDereferenceAdapter(pTcpAdptr);
  261. }
  262. else
  263. {
  264. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_INFO,
  265. ("DsiCreateTcpConn: put new connection %lx on free list\n",pTcpConn));
  266. }
  267. return(status);
  268. }
  269. /*** DsiAddIpaddressToList
  270. *
  271. * This routine saves an "active" ipaddress in our list of ipaddresses
  272. *
  273. * Parm IN: IpAddress - the ipaddress to save
  274. *
  275. * Returns: result of the operation
  276. *
  277. */
  278. NTSTATUS
  279. DsiAddIpaddressToList(
  280. IN IPADDRESS IpAddress
  281. )
  282. {
  283. KIRQL OldIrql;
  284. PLIST_ENTRY pList;
  285. PIPADDRENTITY pIpaddrEntity;
  286. PIPADDRENTITY pTmpIpaddrEntity;
  287. BOOLEAN fAlreadyPresent=FALSE;
  288. pIpaddrEntity =
  289. (PIPADDRENTITY)AfpAllocZeroedNonPagedMemory(sizeof(IPADDRENTITY));
  290. if (pIpaddrEntity == NULL)
  291. {
  292. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  293. ("DsiAddIpaddressToList: malloc failed! (%lx)\n",IpAddress));
  294. return(STATUS_INSUFFICIENT_RESOURCES);
  295. }
  296. pIpaddrEntity->IpAddress = IpAddress;
  297. ACQUIRE_SPIN_LOCK(&DsiAddressLock, &OldIrql);
  298. pList = DsiIpAddrList.Flink;
  299. while (pList != &DsiIpAddrList)
  300. {
  301. pTmpIpaddrEntity = CONTAINING_RECORD(pList, IPADDRENTITY, Linkage);
  302. if (pTmpIpaddrEntity->IpAddress == IpAddress)
  303. {
  304. fAlreadyPresent = TRUE;
  305. break;
  306. }
  307. pList = pList->Flink;
  308. }
  309. if (fAlreadyPresent)
  310. {
  311. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  312. ("DsiAddIpaddressToList: %d.%d.%d.%d already present!\n",
  313. (IpAddress>>24)&0xFF,(IpAddress>>16)&0xFF,(IpAddress>>8)&0xFF,IpAddress&0xFF));
  314. ASSERT(0);
  315. RELEASE_SPIN_LOCK(&DsiAddressLock, OldIrql);
  316. return(STATUS_ADDRESS_ALREADY_EXISTS);
  317. }
  318. InsertTailList(&DsiIpAddrList, &pIpaddrEntity->Linkage);
  319. RELEASE_SPIN_LOCK(&DsiAddressLock, OldIrql);
  320. return(STATUS_SUCCESS);
  321. }
  322. /*** DsiRemoveIpaddressFromList
  323. *
  324. * This routine remove ipaddress from our list of ipaddresses
  325. *
  326. * Parm IN: IpAddress - the ipaddress to remove
  327. *
  328. * Returns: TRUE if we removed the ipaddress, FALSE if we didn't
  329. *
  330. */
  331. BOOLEAN
  332. DsiRemoveIpaddressFromList(
  333. IN IPADDRESS IpAddress
  334. )
  335. {
  336. KIRQL OldIrql;
  337. PLIST_ENTRY pList;
  338. PIPADDRENTITY pIpaddrEntity;
  339. BOOLEAN fFoundInList=FALSE;
  340. ACQUIRE_SPIN_LOCK(&DsiAddressLock, &OldIrql);
  341. pList = DsiIpAddrList.Flink;
  342. while (pList != &DsiIpAddrList)
  343. {
  344. pIpaddrEntity = CONTAINING_RECORD(pList, IPADDRENTITY, Linkage);
  345. if (pIpaddrEntity->IpAddress == IpAddress)
  346. {
  347. fFoundInList = TRUE;
  348. break;
  349. }
  350. pList = pList->Flink;
  351. }
  352. if (!fFoundInList)
  353. {
  354. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  355. ("DsiRemoveIpaddressFromList: %d.%d.%d.%d not in the list!\n",
  356. (IpAddress>>24)&0xFF,(IpAddress>>16)&0xFF,(IpAddress>>8)&0xFF,IpAddress&0xFF));
  357. ASSERT(0);
  358. RELEASE_SPIN_LOCK(&DsiAddressLock, OldIrql);
  359. return(FALSE);
  360. }
  361. RemoveEntryList(&pIpaddrEntity->Linkage);
  362. RELEASE_SPIN_LOCK(&DsiAddressLock, OldIrql);
  363. AfpFreeMemory(pIpaddrEntity);
  364. return(TRUE);
  365. }
  366. /*** DsiGetRequest
  367. *
  368. * This routine allocates a DSI Request structure and returns. For performance
  369. * reasons, we don't alloc new memory each time, but save a list of these
  370. *
  371. * Parm IN: nothin'
  372. *
  373. * Returns: pointer to a DSIREQ strucutre (NULL on failure)
  374. *
  375. */
  376. PDSIREQ
  377. DsiGetRequest(
  378. IN VOID
  379. )
  380. {
  381. PDSIREQ pDsiReq=NULL;
  382. PLIST_ENTRY pList;
  383. KIRQL OldIrql;
  384. ACQUIRE_SPIN_LOCK(&DsiResourceLock, &OldIrql);
  385. if (!IsListEmpty(&DsiFreeRequestList))
  386. {
  387. pList = RemoveHeadList(&DsiFreeRequestList);
  388. pDsiReq = CONTAINING_RECORD(pList, DSIREQ, dsi_Linkage);
  389. ASSERT(DsiFreeRequestListSize > 0);
  390. DsiFreeRequestListSize--;
  391. RtlZeroMemory(pDsiReq, sizeof(DSIREQ));
  392. }
  393. RELEASE_SPIN_LOCK(&DsiResourceLock, OldIrql);
  394. if (pDsiReq == NULL)
  395. {
  396. pDsiReq = (PDSIREQ)AfpAllocZeroedNonPagedMemory(sizeof(DSIREQ));
  397. }
  398. if (pDsiReq != NULL)
  399. {
  400. pDsiReq->dsi_Signature = DSI_REQUEST_SIGNATURE;
  401. InitializeListHead(&pDsiReq->dsi_Linkage);
  402. }
  403. else
  404. {
  405. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  406. ("DsiGetRequest: malloc failed!\n"));
  407. }
  408. return(pDsiReq);
  409. }
  410. /*** DsiGetReqBuffer
  411. *
  412. * This routine allocates a buffer to hold either a header or a command
  413. * The likelihood of this function getting called is pretty slim (basically
  414. * if a packet is fragmented by TCP). So we simply make a call to alloc
  415. *
  416. * Parm IN: BufLen - length of the buffer requested
  417. *
  418. * Returns: pointer to a buffer (NULL on failure)
  419. *
  420. */
  421. PBYTE
  422. DsiGetReqBuffer(
  423. IN DWORD BufLen
  424. )
  425. {
  426. PBYTE pBuffer=NULL;
  427. pBuffer = AfpAllocNonPagedMemory(BufLen);
  428. #if DBG
  429. if (pBuffer == NULL)
  430. {
  431. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  432. ("DsiGetReqBuffer: malloc failed!\n"));
  433. }
  434. #endif
  435. return(pBuffer);
  436. }
  437. /*** DsiFreeRequest
  438. *
  439. * This routine frees up a previously allocated DSI Request structure. Again,
  440. * for performance reasons, we don't free up the memory but put this in a list
  441. *
  442. * Parm IN: pDsiReq - the request to be freed
  443. *
  444. * Returns: nothing
  445. *
  446. */
  447. VOID
  448. DsiFreeRequest(
  449. PDSIREQ pDsiReq
  450. )
  451. {
  452. KIRQL OldIrql;
  453. BOOLEAN fQueueTooBig = TRUE;
  454. if ((pDsiReq->dsi_PartialBuf != NULL) &&
  455. (pDsiReq->dsi_PartialBuf != &pDsiReq->dsi_RespHeader[0]))
  456. {
  457. ASSERT(pDsiReq->dsi_PartialBufSize > 0);
  458. DsiFreeReqBuffer(pDsiReq->dsi_PartialBuf);
  459. pDsiReq->dsi_PartialBuf = NULL;
  460. pDsiReq->dsi_PartialBufSize = 0;
  461. }
  462. // if there was an Mdl we got via cache mgr, it had better be returned to system
  463. ASSERT(pDsiReq->dsi_AfpRequest.rq_CacheMgrContext == NULL);
  464. //
  465. // if we came here via abnormal disconnect, this could be non-null
  466. //
  467. if (pDsiReq->dsi_pDsiAllocedMdl)
  468. {
  469. AfpFreeMdl(pDsiReq->dsi_pDsiAllocedMdl);
  470. }
  471. #if DBG
  472. RtlFillMemory(pDsiReq, sizeof(DSIREQ), 'f');
  473. #endif
  474. ACQUIRE_SPIN_LOCK(&DsiResourceLock, &OldIrql);
  475. if (DsiFreeRequestListSize < DsiNumTcpConnections)
  476. {
  477. InsertTailList(&DsiFreeRequestList, &pDsiReq->dsi_Linkage);
  478. DsiFreeRequestListSize++;
  479. fQueueTooBig = FALSE;
  480. }
  481. RELEASE_SPIN_LOCK(&DsiResourceLock, OldIrql);
  482. if (fQueueTooBig)
  483. {
  484. AfpFreeMemory(pDsiReq);
  485. }
  486. return;
  487. }
  488. /*** DsiFreeReqBuffer
  489. *
  490. * This routine allocates a buffer to hold either a header or a command
  491. * The likelihood of this function getting called is pretty slim (basically
  492. * if a packet is fragmented by TCP). So we simply make a call to alloc
  493. *
  494. * Parm IN: BufLen - length of the buffer requested
  495. *
  496. * Returns: pointer to a buffer (NULL on failure)
  497. *
  498. */
  499. VOID
  500. DsiFreeReqBuffer(
  501. IN PBYTE pBuffer
  502. )
  503. {
  504. ASSERT(pBuffer != NULL);
  505. AfpFreeMemory(pBuffer);
  506. return;
  507. }
  508. /*** DsiDereferenceAdapter
  509. *
  510. * This routine dereferences the adapter object. When refcount goes to 0, it
  511. * removes it from the global list of adapters. If at task time, it calls a
  512. * routine to close tcp handles and free the memory. If at dpc, it schedules
  513. * an event to do the same.
  514. *
  515. * Parm IN: pTcpAdptr - adapter context
  516. *
  517. * Returns: nothin'
  518. *
  519. */
  520. VOID
  521. DsiDereferenceAdapter(
  522. IN PTCPADPTR pTcpAdptr
  523. )
  524. {
  525. KIRQL OldIrql;
  526. BOOLEAN fDone=FALSE;
  527. ASSERT(pTcpAdptr->adp_Signature == DSI_ADAPTER_SIGNATURE);
  528. ACQUIRE_SPIN_LOCK(&pTcpAdptr->adp_SpinLock, &OldIrql);
  529. pTcpAdptr->adp_RefCount--;
  530. if (pTcpAdptr->adp_RefCount == 0)
  531. {
  532. fDone = TRUE;
  533. ASSERT(pTcpAdptr->adp_State & TCPADPTR_STATE_CLOSING);
  534. }
  535. RELEASE_SPIN_LOCK(&pTcpAdptr->adp_SpinLock, OldIrql);
  536. if (!fDone)
  537. {
  538. return;
  539. }
  540. //
  541. // this dude's life is over: do the needful to bid goodbye
  542. //
  543. // if we are at DPC, we need to do all the cleanup (file handle closing etc.)
  544. // at task time: queue an event
  545. if (KeGetCurrentIrql() == DISPATCH_LEVEL)
  546. {
  547. // queue an event, since we are at dpc
  548. DsiScheduleWorkerEvent(DsiFreeAdapter, pTcpAdptr);
  549. }
  550. else
  551. {
  552. DsiFreeAdapter(pTcpAdptr);
  553. }
  554. return;
  555. }
  556. /*** DsiDereferenceConnection
  557. *
  558. * This routine dereferences the connection object. When refcount goes to 0, it
  559. * removes it from the list of connections. If at task time, it calls a
  560. * routine to close tcp handles and free the memory. If at dpc, it schedules
  561. * an event to do the same.
  562. *
  563. * Parm IN: pTcpConn - connection context
  564. *
  565. * Returns: nothin'
  566. *
  567. */
  568. VOID
  569. DsiDereferenceConnection(
  570. IN PTCPCONN pTcpConn
  571. )
  572. {
  573. KIRQL OldIrql;
  574. BOOLEAN fDone=FALSE;
  575. ASSERT(VALID_TCPCONN(pTcpConn));
  576. ACQUIRE_SPIN_LOCK(&pTcpConn->con_SpinLock, &OldIrql);
  577. pTcpConn->con_RefCount--;
  578. if (pTcpConn->con_RefCount == 0)
  579. {
  580. fDone = TRUE;
  581. ASSERT(pTcpConn->con_State & TCPCONN_STATE_CLOSING);
  582. }
  583. RELEASE_SPIN_LOCK(&pTcpConn->con_SpinLock, OldIrql);
  584. if (!fDone)
  585. {
  586. return;
  587. }
  588. //
  589. // this dude's life is over: do the needful to bid goodbye
  590. //
  591. #if 0
  592. // if we are at DPC, we need to do all the cleanup (file handle closing etc.)
  593. // at task time: queue an event
  594. if (KeGetCurrentIrql() == DISPATCH_LEVEL)
  595. {
  596. // queue an event, since we are at dpc
  597. DsiScheduleWorkerEvent(DsiFreeConnection, pTcpConn);
  598. }
  599. else
  600. {
  601. DsiFreeConnection(pTcpConn);
  602. }
  603. #endif
  604. // schedule a worker event to free this connection
  605. DsiScheduleWorkerEvent(DsiFreeConnection, pTcpConn);
  606. return;
  607. }
  608. /*** DsiDestroyAdapter
  609. *
  610. * This routine destroys the global adapter object.
  611. *
  612. * Returns: status of operation
  613. *
  614. */
  615. NTSTATUS
  616. DsiDestroyAdapter(
  617. IN VOID
  618. )
  619. {
  620. KIRQL OldIrql;
  621. PLIST_ENTRY pFreeList;
  622. PLIST_ENTRY pActiveList;
  623. PTCPCONN pTcpConn;
  624. BOOLEAN fAlreadyCleanedUp=FALSE;
  625. if (DsiTcpAdapter == NULL)
  626. {
  627. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  628. ("DsiDestroyAdapter: adapter gone! How did this happen!!\n"));
  629. // unblock the event!
  630. KeSetEvent(&DsiShutdownEvent, IO_NETWORK_INCREMENT, False);
  631. return(STATUS_SUCCESS);
  632. }
  633. // stop the tickle timer
  634. if (!AfpScavengerKillEvent(DsiSendTickles, NULL))
  635. {
  636. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  637. ("DsiDestroyAdapter: TickleTimer not running or hit timing window!!\n"));
  638. }
  639. ACQUIRE_SPIN_LOCK(&DsiTcpAdapter->adp_SpinLock, &OldIrql);
  640. if (DsiTcpAdapter->adp_State & TCPADPTR_STATE_CLEANED_UP)
  641. {
  642. fAlreadyCleanedUp = TRUE;
  643. }
  644. DsiTcpAdapter->adp_State |= TCPADPTR_STATE_CLOSING;
  645. DsiTcpAdapter->adp_State |= TCPADPTR_STATE_CLEANED_UP;
  646. if (fAlreadyCleanedUp)
  647. {
  648. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  649. ("DsiDestroyAdapter: already destroyed!\n"));
  650. ASSERT(IsListEmpty(&DsiTcpAdapter->adp_FreeConnHead));
  651. ASSERT(IsListEmpty(&DsiTcpAdapter->adp_ActiveConnHead));
  652. ASSERT(DsiTcpAdapter->adp_NumFreeConnections == 0);
  653. RELEASE_SPIN_LOCK(&DsiTcpAdapter->adp_SpinLock, OldIrql);
  654. return(STATUS_SUCCESS);
  655. }
  656. //
  657. // free up all the connections from the Free list
  658. //
  659. while (!IsListEmpty(&DsiTcpAdapter->adp_FreeConnHead))
  660. {
  661. pFreeList = DsiTcpAdapter->adp_FreeConnHead.Flink;
  662. pTcpConn = CONTAINING_RECORD(pFreeList, TCPCONN, con_Linkage);
  663. RemoveEntryList(&pTcpConn->con_Linkage);
  664. ASSERT(DsiTcpAdapter->adp_NumFreeConnections > 0);
  665. DsiTcpAdapter->adp_NumFreeConnections--;
  666. InitializeListHead(&pTcpConn->con_Linkage);
  667. RELEASE_SPIN_LOCK(&DsiTcpAdapter->adp_SpinLock, OldIrql);
  668. pTcpConn->con_State |= TCPCONN_STATE_CLOSING;
  669. DsiDereferenceConnection(pTcpConn);
  670. DBGREFCOUNT(("DsiDestroyAdapter: Creation dec %lx (%d %d,%d)\n",
  671. pTcpConn,pTcpConn->con_RefCount,pTcpConn->con_State,pTcpConn->con_RcvState));
  672. ACQUIRE_SPIN_LOCK(&DsiTcpAdapter->adp_SpinLock, &OldIrql);
  673. }
  674. //
  675. // kill all the connections from the Active list
  676. //
  677. pActiveList = DsiTcpAdapter->adp_ActiveConnHead.Flink;
  678. while (pActiveList != &DsiTcpAdapter->adp_ActiveConnHead)
  679. {
  680. pTcpConn = CONTAINING_RECORD(pActiveList, TCPCONN, con_Linkage);
  681. pActiveList = pActiveList->Flink;
  682. ACQUIRE_SPIN_LOCK_AT_DPC(&pTcpConn->con_SpinLock);
  683. // if this connection is already closing, skip it
  684. if (pTcpConn->con_State & TCPCONN_STATE_CLOSING)
  685. {
  686. RELEASE_SPIN_LOCK_FROM_DPC(&pTcpConn->con_SpinLock);
  687. continue;
  688. }
  689. // put ABORT refcount for now
  690. pTcpConn->con_RefCount++;
  691. DBGREFCOUNT(("DsiDestroyAdapter: ABORT inc %lx (%d %d,%d)\n",
  692. pTcpConn,pTcpConn->con_RefCount,pTcpConn->con_State,pTcpConn->con_RcvState));
  693. RemoveEntryList(&pTcpConn->con_Linkage);
  694. InitializeListHead(&pTcpConn->con_Linkage);
  695. RELEASE_SPIN_LOCK_FROM_DPC(&pTcpConn->con_SpinLock);
  696. RELEASE_SPIN_LOCK(&DsiTcpAdapter->adp_SpinLock, OldIrql);
  697. DsiAbortConnection(pTcpConn);
  698. // remove that ABORT refcount
  699. DsiDereferenceConnection(pTcpConn);
  700. DBGREFCOUNT(("DsiDestroyAdapter: ABORT dec %lx (%d %d,%d)\n",
  701. pTcpConn,pTcpConn->con_RefCount,pTcpConn->con_State,pTcpConn->con_RcvState));
  702. ACQUIRE_SPIN_LOCK(&DsiTcpAdapter->adp_SpinLock, &OldIrql);
  703. // since we released the lock, things could have changed: start over
  704. pActiveList = DsiTcpAdapter->adp_ActiveConnHead.Flink;
  705. }
  706. RELEASE_SPIN_LOCK(&DsiTcpAdapter->adp_SpinLock, OldIrql);
  707. // remove the creation refcount
  708. DsiDereferenceAdapter(DsiTcpAdapter);
  709. return(STATUS_SUCCESS);
  710. }
  711. /*** DsiKillConnection
  712. *
  713. * This routine kills an active connection.
  714. *
  715. * Parm IN: pTcpConn - the connection to kill
  716. *
  717. * Returns: TRUE if we killed it, FALSE if we couldn't
  718. *
  719. */
  720. BOOLEAN
  721. DsiKillConnection(
  722. IN PTCPCONN pTcpConn,
  723. IN DWORD DiscFlag
  724. )
  725. {
  726. KIRQL OldIrql;
  727. NTSTATUS status;
  728. PDSIREQ pPartialDsiReq=NULL;
  729. BOOLEAN fFirstVisit=TRUE;
  730. ACQUIRE_SPIN_LOCK(&pTcpConn->con_SpinLock, &OldIrql);
  731. if (pTcpConn->con_State & TCPCONN_STATE_CLEANED_UP)
  732. {
  733. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_WARN,
  734. ("DsiKillConnection: connection %lx already cleaned up\n",pTcpConn));
  735. fFirstVisit = FALSE;
  736. }
  737. pTcpConn->con_State &= ~TCPCONN_STATE_CONNECTED;
  738. pTcpConn->con_State |= (TCPCONN_STATE_CLOSING | TCPCONN_STATE_CLEANED_UP);
  739. //
  740. // if a request is waiting for an mdl to become available, don't touch it here.
  741. // When afp returns with mdl (or null mdl), we'll clean up this request
  742. //
  743. if (pTcpConn->con_RcvState != DSI_AWAITING_WRITE_MDL)
  744. {
  745. pPartialDsiReq = pTcpConn->con_pDsiReq;
  746. pTcpConn->con_pDsiReq = NULL;
  747. }
  748. RELEASE_SPIN_LOCK(&pTcpConn->con_SpinLock, OldIrql);
  749. if (pPartialDsiReq)
  750. {
  751. // if we had allocated an mdl, let afp know so afp can free it
  752. if ((pPartialDsiReq->dsi_Command == DSI_COMMAND_WRITE) &&
  753. (pPartialDsiReq->dsi_AfpRequest.rq_WriteMdl != NULL))
  754. {
  755. AfpCB_RequestNotify(STATUS_REMOTE_DISCONNECT,
  756. pTcpConn->con_pSda,
  757. &pPartialDsiReq->dsi_AfpRequest);
  758. }
  759. DsiFreeRequest(pPartialDsiReq);
  760. // remove the REQUEST refcount
  761. DsiDereferenceConnection(pTcpConn);
  762. DBGREFCOUNT(("DsiKillConnection: REQUEST dec %lx (%d %d,%d)\n",
  763. pTcpConn,pTcpConn->con_RefCount,pTcpConn->con_State,pTcpConn->con_RcvState));
  764. }
  765. status = (DiscFlag == TDI_DISCONNECT_ABORT)?
  766. STATUS_LOCAL_DISCONNECT: STATUS_REMOTE_DISCONNECT;
  767. // give AFP the bad news
  768. DsiDisconnectWithAfp(pTcpConn, status);
  769. // give TCP the bad news
  770. DsiDisconnectWithTcp(pTcpConn, DiscFlag);
  771. // remove the Creation refcount if this is the first time we're visiting
  772. // this routine
  773. if (fFirstVisit)
  774. {
  775. DsiDereferenceConnection(pTcpConn);
  776. DBGREFCOUNT(("DsiKillConnection: Creation dec %lx (%d %d,%d)\n",
  777. pTcpConn,pTcpConn->con_RefCount,pTcpConn->con_State,pTcpConn->con_RcvState));
  778. }
  779. return(TRUE);
  780. }
  781. /*** DsiFreeAdapter
  782. *
  783. * This routine frees the adapter object after closing the tcp handles
  784. *
  785. * Parm IN: pTcpAdptr - adapter object
  786. *
  787. * Returns: result of the operation
  788. *
  789. */
  790. NTSTATUS FASTCALL
  791. DsiFreeAdapter(
  792. IN PTCPADPTR pTcpAdptr
  793. )
  794. {
  795. BOOLEAN fRecreateAdapter=FALSE;
  796. KIRQL OldIrql;
  797. ASSERT(KeGetCurrentIrql() != DISPATCH_LEVEL);
  798. ASSERT(pTcpAdptr->adp_Signature == DSI_ADAPTER_SIGNATURE);
  799. ASSERT(pTcpAdptr->adp_State & TCPADPTR_STATE_CLOSING);
  800. ASSERT(pTcpAdptr->adp_RefCount == 0);
  801. // close file handles
  802. DsiCloseTdiAddress(pTcpAdptr);
  803. ACQUIRE_SPIN_LOCK(&DsiAddressLock, &OldIrql);
  804. DsiTcpAdapter = NULL;
  805. AfpServerBoundToTcp = FALSE;
  806. //
  807. // it's possible that by the time we did all the cleanup and everything,
  808. // an ipaddress(es) became available. If that has happened, go ahead and
  809. // create the global adapter again!
  810. //
  811. if (!IsListEmpty(&DsiIpAddrList))
  812. {
  813. fRecreateAdapter = TRUE;
  814. }
  815. // if we are shutting down, don't create the adapter again!
  816. if ((AfpServerState == AFP_STATE_STOP_PENDING) ||
  817. (AfpServerState == AFP_STATE_SHUTTINGDOWN) ||
  818. (AfpServerState == AFP_STATE_STOPPED))
  819. {
  820. fRecreateAdapter = FALSE;
  821. }
  822. RELEASE_SPIN_LOCK(&DsiAddressLock, OldIrql);
  823. ASSERT(pTcpAdptr->adp_pFileObject == NULL);
  824. ASSERT(pTcpAdptr->adp_FileHandle == INVALID_HANDLE_VALUE);
  825. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  826. ("DsiFreeAdapter: freeing adapter %lx\n",pTcpAdptr));
  827. AfpFreeMemory(pTcpAdptr);
  828. // wake up that blocked thread!
  829. KeSetEvent(&DsiShutdownEvent, IO_NETWORK_INCREMENT, False);
  830. if (fRecreateAdapter)
  831. {
  832. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  833. ("DsiFreeAdapter: ipaddress came in, so recreating global adapter\n"));
  834. DsiCreateAdapter();
  835. }
  836. return(STATUS_SUCCESS);
  837. }
  838. /*** DsiFreeConnection
  839. *
  840. * This routine frees the connection object after closing the tcp handles
  841. *
  842. * Parm IN: pTcpConn - connection object
  843. *
  844. * Returns: result of the operation
  845. *
  846. */
  847. NTSTATUS FASTCALL
  848. DsiFreeConnection(
  849. IN PTCPCONN pTcpConn
  850. )
  851. {
  852. KIRQL OldIrql;
  853. PTCPADPTR pTcpAdptr;
  854. IPADDRESS IpAddress;
  855. ASSERT(KeGetCurrentIrql() != DISPATCH_LEVEL);
  856. ASSERT(pTcpConn->con_Signature == DSI_CONN_SIGNATURE);
  857. ASSERT(pTcpConn->con_State & TCPCONN_STATE_CLOSING);
  858. ASSERT(pTcpConn->con_RefCount == 0);
  859. pTcpAdptr = pTcpConn->con_pTcpAdptr;
  860. ASSERT(pTcpAdptr->adp_Signature == DSI_ADAPTER_SIGNATURE);
  861. // close file handles
  862. DsiCloseTdiConnection(pTcpConn);
  863. // remove this puppy from the list
  864. ACQUIRE_SPIN_LOCK(&pTcpAdptr->adp_SpinLock, &OldIrql);
  865. RemoveEntryList(&pTcpConn->con_Linkage);
  866. RELEASE_SPIN_LOCK(&pTcpAdptr->adp_SpinLock, OldIrql);
  867. // remove the CONN refcount for this connection
  868. DsiDereferenceAdapter(pTcpConn->con_pTcpAdptr);
  869. ASSERT(pTcpConn->con_pFileObject == NULL);
  870. ASSERT(pTcpConn->con_FileHandle == INVALID_HANDLE_VALUE);
  871. #if DBG
  872. IpAddress = pTcpConn->con_DestIpAddr;
  873. if (IpAddress)
  874. {
  875. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_WARN,
  876. ("DsiFreeConnection: freeing connection on %d.%d.%d.%d (%lx)\n",
  877. (IpAddress>>24)&0xFF,(IpAddress>>16)&0xFF,(IpAddress>>8)&0xFF,
  878. IpAddress&0xFF,pTcpConn));
  879. }
  880. pTcpConn->con_Signature = 0xDEADBEEF;
  881. #endif
  882. AfpFreeMemory(pTcpConn);
  883. return(STATUS_SUCCESS);
  884. }
  885. /*** DsiGetIpAddrBlob
  886. *
  887. * This routine generates a 'blob' that gets plugged into the ServerInfo buffer.
  888. * Here we walk the ipaddr list and generate a blob with all the available
  889. * ipaddresses (6-byte-per-ipaddress_
  890. *
  891. * Parm OUT: pIpAddrCount - how many ipaddresses there are in the system
  892. * ppIpAddrBlob - pointer to a pointer to a buffer
  893. *
  894. * Returns: status of operation
  895. *
  896. */
  897. NTSTATUS
  898. DsiGetIpAddrBlob(
  899. OUT DWORD *pIpAddrCount,
  900. OUT PBYTE *ppIpAddrBlob
  901. )
  902. {
  903. KIRQL OldIrql;
  904. PLIST_ENTRY pList;
  905. DWORD AddrCount=0;
  906. DWORD TmpCount=0;
  907. PBYTE AddrBlob;
  908. PBYTE pCurrentBlob;
  909. PIPADDRENTITY pIpaddrEntity;
  910. *pIpAddrCount = 0;
  911. *ppIpAddrBlob = NULL;
  912. ACQUIRE_SPIN_LOCK(&DsiAddressLock, &OldIrql);
  913. if (!DsiTcpEnabled)
  914. {
  915. RELEASE_SPIN_LOCK(&DsiAddressLock, OldIrql);
  916. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  917. ("DsiGetIpAddrBlob: Server is disabled\n"));
  918. return(STATUS_SUCCESS);
  919. }
  920. //
  921. // find out how many ipaddresses are there on the list
  922. //
  923. AddrCount = 0;
  924. pList = DsiIpAddrList.Flink;
  925. while (pList != &DsiIpAddrList)
  926. {
  927. AddrCount++;
  928. pList = pList->Flink;
  929. }
  930. if (AddrCount == 0)
  931. {
  932. RELEASE_SPIN_LOCK(&DsiAddressLock, OldIrql);
  933. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  934. ("DsiGetIpAddrBlob: calling AfpSetServerStatus with 0 addrs\n"));
  935. return(STATUS_SUCCESS);
  936. }
  937. if (AddrCount > DSI_MAX_IPADDR_COUNT)
  938. {
  939. AddrCount = DSI_MAX_IPADDR_COUNT;
  940. }
  941. AddrBlob = AfpAllocZeroedNonPagedMemory(AddrCount * DSI_NETWORK_ADDR_LEN);
  942. if (AddrBlob == NULL)
  943. {
  944. RELEASE_SPIN_LOCK(&DsiAddressLock, OldIrql);
  945. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  946. ("DsiGetIpAddrBlob: malloc failed\n"));
  947. return(STATUS_INSUFFICIENT_RESOURCES);
  948. }
  949. //
  950. // create a "blob" that AfpSetServerStatus can directly copy
  951. //
  952. TmpCount = 0;
  953. pCurrentBlob = AddrBlob;
  954. pList = DsiIpAddrList.Flink;
  955. while (pList != &DsiIpAddrList)
  956. {
  957. pIpaddrEntity = CONTAINING_RECORD(pList, IPADDRENTITY, Linkage);
  958. pCurrentBlob[0] = DSI_NETWORK_ADDR_LEN;
  959. pCurrentBlob[1] = DSI_NETWORK_ADDR_IPTAG;
  960. PUTDWORD2DWORD(&pCurrentBlob[2], pIpaddrEntity->IpAddress);
  961. pCurrentBlob += DSI_NETWORK_ADDR_LEN;
  962. pList = pList->Flink;
  963. TmpCount++;
  964. if (TmpCount == AddrCount)
  965. {
  966. break;
  967. }
  968. }
  969. RELEASE_SPIN_LOCK(&DsiAddressLock, OldIrql);
  970. *pIpAddrCount = AddrCount;
  971. *ppIpAddrBlob = AddrBlob;
  972. return(STATUS_SUCCESS);
  973. }
  974. /*** DsiGetIrpForTcp
  975. *
  976. * This routine is called when we need to pass an irp back to TCP to get the
  977. * remainint data (when it has more data than it has indicated to us).
  978. * Here we allocate an mdl if there isn't one already, and allocate and
  979. * initialize an irp ready to be sent to TCP
  980. *
  981. * Parm IN: pTcpConn - the connection object
  982. * pBuffer - buffer that TCP will copy data in
  983. * pInputMdl - if non-null, then we don't allocate a new mdl
  984. * ReadSize - how many bytes do we need
  985. *
  986. * Returns: pIrp if successful, NULL otherwise
  987. *
  988. * NOTE: pTcpConn spinlock is held on entry
  989. *
  990. */
  991. PIRP
  992. DsiGetIrpForTcp(
  993. IN PTCPCONN pTcpConn,
  994. IN PBYTE pBuffer,
  995. IN PMDL pInputMdl,
  996. IN DWORD ReadSize
  997. )
  998. {
  999. PDEVICE_OBJECT pDeviceObject;
  1000. PIRP pIrp=NULL;
  1001. PTDI_REQUEST_KERNEL_RECEIVE pRequest;
  1002. PMDL pMdl;
  1003. pDeviceObject = IoGetRelatedDeviceObject(pTcpConn->con_pFileObject);
  1004. pIrp = AfpAllocIrp(pDeviceObject->StackSize);
  1005. if (pIrp == NULL)
  1006. {
  1007. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  1008. ("DsiGetIrpForTcp: alloc irp failed!\n"));
  1009. return(NULL);
  1010. }
  1011. if (pInputMdl)
  1012. {
  1013. pMdl = pInputMdl;
  1014. }
  1015. else
  1016. {
  1017. pMdl = AfpAllocMdl(pBuffer, ReadSize, NULL);
  1018. if (pMdl == NULL)
  1019. {
  1020. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  1021. ("DsiGetIrpForTcp: alloc mdl failed!\n"));
  1022. AfpFreeIrp(pIrp);
  1023. return(NULL);
  1024. }
  1025. }
  1026. pTcpConn->con_pRcvIrp = pIrp;
  1027. pTcpConn->con_State |= TCPCONN_STATE_TCP_HAS_IRP;
  1028. // put TcpIRP refcount, removed when the irp completes
  1029. pTcpConn->con_RefCount++;
  1030. DBGREFCOUNT(("DsiGetIrpForTcp: TcpIRP inc %lx (%d %d,%d)\n",
  1031. pTcpConn,pTcpConn->con_RefCount,pTcpConn->con_State,pTcpConn->con_RcvState));
  1032. TdiBuildReceive(pIrp,
  1033. pDeviceObject,
  1034. pTcpConn->con_pFileObject,
  1035. DsiTcpRcvIrpCompletion,
  1036. (PVOID)pTcpConn,
  1037. pMdl,
  1038. TDI_RECEIVE_NORMAL,
  1039. ReadSize);
  1040. //
  1041. // this irp will be returned to TCP, so do what IoSubSystem
  1042. // would have done if we had called IoCallDriver
  1043. //
  1044. IoSetNextIrpStackLocation(pIrp);
  1045. return(pIrp);
  1046. }
  1047. /*** DsiMakePartialMdl
  1048. *
  1049. * This routine is called when we need to reissue an Mdl (via irp) back to TCP
  1050. * because TCP prematurely completed the previous irp (i.e. all the requested
  1051. * bytes haven't come in yet, but say Push bit was set or something). In such
  1052. * a case, we need to give a new mdl which accounts for the bytes we have got
  1053. * so far (i.e. the offset has changed)
  1054. *
  1055. * Parm IN: pOrgMdl - the original Mdl we gave to TCp
  1056. * dwOffset - what offset we want the new partial Mdl to describe
  1057. *
  1058. * Returns: the new partial Mdl if successful, NULL otherwise
  1059. *
  1060. */
  1061. PMDL
  1062. DsiMakePartialMdl(
  1063. IN PMDL pOrgMdl,
  1064. IN DWORD dwOffset
  1065. )
  1066. {
  1067. PMDL pSubMdl;
  1068. PMDL pPartialMdl=NULL;
  1069. DWORD dwNewMdlLen;
  1070. PVOID vAddr;
  1071. ASSERT(pOrgMdl != NULL);
  1072. ASSERT(dwOffset > 0);
  1073. ASSERT(dwOffset < AfpMdlChainSize(pOrgMdl));
  1074. pSubMdl = pOrgMdl;
  1075. //
  1076. // get to the Mdl that is going to have this offset
  1077. //
  1078. while (dwOffset >= MmGetMdlByteCount(pSubMdl))
  1079. {
  1080. dwOffset -= MmGetMdlByteCount(pSubMdl);
  1081. pSubMdl = pSubMdl->Next;
  1082. ASSERT(pSubMdl != NULL);
  1083. }
  1084. ASSERT(MmGetMdlByteCount(pSubMdl) > dwOffset);
  1085. vAddr = (PVOID)((PUCHAR)MmGetMdlVirtualAddress( pSubMdl ) + dwOffset);
  1086. dwNewMdlLen = MmGetMdlByteCount(pSubMdl) - dwOffset;
  1087. pPartialMdl = IoAllocateMdl(vAddr, dwNewMdlLen, FALSE, FALSE, NULL);
  1088. if (pPartialMdl == NULL)
  1089. {
  1090. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  1091. ("DsiMakePartialMdl: IoAllocateMdl failed\n"));
  1092. return(NULL);
  1093. }
  1094. AFP_DBG_INC_COUNT(AfpDbgMdlsAlloced);
  1095. IoBuildPartialMdl(pSubMdl, pPartialMdl, vAddr, dwNewMdlLen);
  1096. // if there are further Mdl's down the original, link them on
  1097. pPartialMdl->Next = pSubMdl->Next;
  1098. return(pPartialMdl);
  1099. }
  1100. /*** DsiUpdateAfpStatus
  1101. *
  1102. * This routine is just a wrapper function so that we can schedule an event to
  1103. * call the real function AfpSetServerStatus
  1104. *
  1105. * Returns: status of operation
  1106. *
  1107. */
  1108. NTSTATUS FASTCALL
  1109. DsiUpdateAfpStatus(
  1110. IN PVOID Unused
  1111. )
  1112. {
  1113. NTSTATUS status;
  1114. status = AfpSetServerStatus();
  1115. return(status);
  1116. }
  1117. /*** DsiScheduleWorkerEvent
  1118. *
  1119. * This routine schedules an event for a later time. This routine is called
  1120. * typically when we are at dpc but something (e.g. file handle operations)
  1121. * needs to be done at passive level. This routine puts the request on the
  1122. * worker queue.
  1123. *
  1124. * Parm IN: WorkerRoutine - the routine to be exececuted by the worker thread
  1125. * Context - parameter for that routine
  1126. *
  1127. * Returns: result of the operation
  1128. *
  1129. */
  1130. NTSTATUS
  1131. DsiScheduleWorkerEvent(
  1132. IN DSI_WORKER WorkerRoutine,
  1133. IN PVOID Context
  1134. )
  1135. {
  1136. PTCPWORKITEM pTWItem;
  1137. pTWItem = (PTCPWORKITEM)AfpAllocZeroedNonPagedMemory(sizeof(TCPWORKITEM));
  1138. if (pTWItem == NULL)
  1139. {
  1140. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  1141. ("DsiScheduleWorkerEvent: alloc failed!\n"));
  1142. return(STATUS_INSUFFICIENT_RESOURCES);
  1143. }
  1144. AfpInitializeWorkItem(&pTWItem->tcp_WorkItem, DsiWorker, pTWItem);
  1145. pTWItem->tcp_Worker = WorkerRoutine;
  1146. pTWItem->tcp_Context = Context;
  1147. AfpQueueWorkItem(&pTWItem->tcp_WorkItem);
  1148. return(STATUS_SUCCESS);
  1149. }
  1150. /*** DsiScheduleWorkerEvent
  1151. *
  1152. * This routine gets called by the worker thread when DsiScheduleWorkerEvent
  1153. * schedules an event. This routine then calls the actual routine that was
  1154. * scheduled for later time.
  1155. *
  1156. * Parm IN: Context - the work item
  1157. *
  1158. * Returns: result of the operation
  1159. *
  1160. */
  1161. VOID FASTCALL
  1162. DsiWorker(
  1163. IN PVOID Context
  1164. )
  1165. {
  1166. PTCPWORKITEM pTWItem;
  1167. NTSTATUS status;
  1168. pTWItem = (PTCPWORKITEM)Context;
  1169. ASSERT (KeGetCurrentIrql() < DISPATCH_LEVEL);
  1170. (*pTWItem->tcp_Worker)(pTWItem->tcp_Context);
  1171. AfpFreeMemory(pTWItem);
  1172. }
  1173. /*** DsiShutdown
  1174. *
  1175. * This routine is called when sfm is shutting down. We basically make sure
  1176. * that all the resources are freed up, file handles closed etc.
  1177. *
  1178. * Returns: Nothing
  1179. *
  1180. */
  1181. VOID
  1182. DsiShutdown(
  1183. IN VOID
  1184. )
  1185. {
  1186. KIRQL OldIrql;
  1187. PLIST_ENTRY pList;
  1188. PIPADDRENTITY pIpaddrEntity;
  1189. PDSIREQ pDsiReq=NULL;
  1190. ACQUIRE_SPIN_LOCK(&DsiAddressLock, &OldIrql);
  1191. while (!IsListEmpty(&DsiIpAddrList))
  1192. {
  1193. pList = RemoveHeadList(&DsiIpAddrList);
  1194. pIpaddrEntity = CONTAINING_RECORD(pList, IPADDRENTITY, Linkage);
  1195. AfpFreeMemory(pIpaddrEntity);
  1196. }
  1197. if (DsiStatusBuffer != NULL)
  1198. {
  1199. AfpFreeMemory(DsiStatusBuffer);
  1200. DsiStatusBuffer = NULL;
  1201. }
  1202. RELEASE_SPIN_LOCK(&DsiAddressLock, OldIrql);
  1203. // kill the global adapter if it's around
  1204. if (DsiTcpAdapter)
  1205. {
  1206. KeClearEvent(&DsiShutdownEvent);
  1207. DsiDestroyAdapter();
  1208. // if the "adapter" is still hanging around, wait till it's gone
  1209. if (DsiTcpAdapter)
  1210. {
  1211. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  1212. ("DsiShutdown: waiting for the TCP interface to go away...\n"));
  1213. AfpIoWait(&DsiShutdownEvent, NULL);
  1214. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  1215. ("DsiShutdown: ... and the wait is over!\n"));
  1216. }
  1217. }
  1218. ACQUIRE_SPIN_LOCK(&DsiResourceLock, &OldIrql);
  1219. while (!IsListEmpty(&DsiFreeRequestList))
  1220. {
  1221. pList = RemoveHeadList(&DsiFreeRequestList);
  1222. pDsiReq = CONTAINING_RECORD(pList, DSIREQ, dsi_Linkage);
  1223. AfpFreeMemory(pDsiReq);
  1224. DsiFreeRequestListSize--;
  1225. }
  1226. RELEASE_SPIN_LOCK(&DsiResourceLock, OldIrql);
  1227. ASSERT(DsiFreeRequestListSize == 0);
  1228. }
  1229.