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.

1317 lines
36 KiB

  1. /*
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. tcptdi.c
  5. Abstract:
  6. This module contains the interfaces to the TCP/IP stack via TDI
  7. Author:
  8. Shirish Koti
  9. Revision History:
  10. 22 Jan 1998 Initial Version
  11. --*/
  12. #define FILENUM FILE_TCPTDI
  13. #include <afp.h>
  14. /*** DsiOpenTdiAddress
  15. *
  16. * This routine creates a TDI address for the AFP port on the given adapter
  17. *
  18. * Parm IN: pTcpAdptr - adapter object
  19. *
  20. * Parm OUT: pRetFileHandle - file handle to the address object
  21. * ppRetFileObj - pointer to file object pointer
  22. *
  23. * Returns: status of operation
  24. *
  25. */
  26. NTSTATUS
  27. DsiOpenTdiAddress(
  28. IN PTCPADPTR pTcpAdptr,
  29. OUT PHANDLE pRetFileHandle,
  30. OUT PFILE_OBJECT *ppRetFileObj
  31. )
  32. {
  33. OBJECT_ATTRIBUTES AddressAttributes;
  34. IO_STATUS_BLOCK IoStatusBlock;
  35. PFILE_FULL_EA_INFORMATION EaBuffer;
  36. NTSTATUS status;
  37. UNICODE_STRING ucDeviceName;
  38. PTRANSPORT_ADDRESS pTransAddressEa;
  39. PTRANSPORT_ADDRESS pTransAddr;
  40. TDI_ADDRESS_IP TdiIpAddr;
  41. HANDLE FileHandle;
  42. PFILE_OBJECT pFileObject;
  43. PDEVICE_OBJECT pDeviceObject;
  44. PEPROCESS CurrentProcess;
  45. BOOLEAN fAttachAttempted;
  46. ASSERT(KeGetCurrentIrql() != DISPATCH_LEVEL);
  47. ASSERT(pTcpAdptr->adp_Signature == DSI_ADAPTER_SIGNATURE);
  48. *pRetFileHandle = INVALID_HANDLE_VALUE;
  49. // copy device name into the unicode string
  50. ucDeviceName.MaximumLength = (wcslen(AFP_TCP_BINDNAME) + 1)*sizeof(WCHAR);
  51. ucDeviceName.Length = 0;
  52. ucDeviceName.Buffer = (PWSTR)AfpAllocZeroedNonPagedMemory(
  53. ucDeviceName.MaximumLength);
  54. if (ucDeviceName.Buffer == NULL)
  55. {
  56. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  57. ("DsiOpenTdiAddress: malloc for ucDeviceName Failed\n"));
  58. return(STATUS_INSUFFICIENT_RESOURCES);
  59. }
  60. status = RtlAppendUnicodeToString(&ucDeviceName, AFP_TCP_BINDNAME);
  61. if (!NT_SUCCESS(status))
  62. {
  63. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  64. ("DsiOpenTdiAddress: RtlAppend... failed %lx\n",status));
  65. AfpFreeMemory(ucDeviceName.Buffer);
  66. return(status);
  67. }
  68. EaBuffer = (PFILE_FULL_EA_INFORMATION)AfpAllocZeroedNonPagedMemory(
  69. sizeof(FILE_FULL_EA_INFORMATION) - 1 +
  70. TDI_TRANSPORT_ADDRESS_LENGTH + 1 +
  71. sizeof(TRANSPORT_ADDRESS) +
  72. sizeof(TDI_ADDRESS_IP));
  73. if (EaBuffer == NULL)
  74. {
  75. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  76. ("DsiOpenTdiAddress: malloc for Eabuffer failed!\n"));
  77. AfpFreeMemory(ucDeviceName.Buffer);
  78. return(STATUS_INSUFFICIENT_RESOURCES);
  79. }
  80. EaBuffer->NextEntryOffset = 0;
  81. EaBuffer->Flags = 0;
  82. EaBuffer->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
  83. EaBuffer->EaValueLength = sizeof(TRANSPORT_ADDRESS) -1
  84. + sizeof(TDI_ADDRESS_IP);
  85. // put "TransportAddress" into the name
  86. RtlMoveMemory(EaBuffer->EaName,
  87. TdiTransportAddress,
  88. EaBuffer->EaNameLength + 1);
  89. // fill in the IP address and Port number
  90. //
  91. pTransAddressEa = (TRANSPORT_ADDRESS *)&EaBuffer->EaName[EaBuffer->EaNameLength+1];
  92. // allocate Memory for the transport address
  93. //
  94. pTransAddr = (PTRANSPORT_ADDRESS)AfpAllocZeroedNonPagedMemory(
  95. sizeof(TDI_ADDRESS_IP)+sizeof(TRANSPORT_ADDRESS));
  96. if (pTransAddr == NULL)
  97. {
  98. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  99. ("DsiOpenTdiAddress: malloc for pTransAddr failed!\n"));
  100. AfpFreeMemory(ucDeviceName.Buffer);
  101. AfpFreeMemory(EaBuffer);
  102. return(STATUS_INSUFFICIENT_RESOURCES);
  103. }
  104. pTransAddr->TAAddressCount = 1;
  105. pTransAddr->Address[0].AddressLength = sizeof(TDI_ADDRESS_IP);
  106. pTransAddr->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
  107. TdiIpAddr.sin_port = htons(AFP_TCP_PORT); // put in network order
  108. TdiIpAddr.in_addr = 0; // inaddr_any
  109. // zero fill the last component of the IP address
  110. //
  111. RtlFillMemory((PVOID)&TdiIpAddr.sin_zero,
  112. sizeof(TdiIpAddr.sin_zero),
  113. 0);
  114. // copy the ip address to the end of the structure
  115. //
  116. RtlMoveMemory(pTransAddr->Address[0].Address,
  117. (CONST PVOID)&TdiIpAddr,
  118. sizeof(TdiIpAddr));
  119. // copy the ip address to the end of the name in the EA structure
  120. //
  121. RtlMoveMemory((PVOID)pTransAddressEa,
  122. (CONST PVOID)pTransAddr,
  123. sizeof(TDI_ADDRESS_IP) + sizeof(TRANSPORT_ADDRESS)-1);
  124. InitializeObjectAttributes(
  125. &AddressAttributes,
  126. &ucDeviceName,
  127. OBJ_CASE_INSENSITIVE,
  128. NULL,
  129. NULL);
  130. CurrentProcess = IoGetCurrentProcess();
  131. AFPAttachProcess(CurrentProcess);
  132. fAttachAttempted = TRUE;
  133. status = ZwCreateFile(
  134. &FileHandle,
  135. GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
  136. &AddressAttributes,
  137. &IoStatusBlock,
  138. NULL,
  139. FILE_ATTRIBUTE_NORMAL,
  140. FILE_SHARE_READ | FILE_SHARE_WRITE,
  141. FILE_OPEN_IF,
  142. 0,
  143. (PVOID)EaBuffer,
  144. sizeof(FILE_FULL_EA_INFORMATION) - 1 +
  145. EaBuffer->EaNameLength + 1 +
  146. EaBuffer->EaValueLength);
  147. // don't need these no more..
  148. AfpFreeMemory((PVOID)pTransAddr);
  149. AfpFreeMemory((PVOID)EaBuffer);
  150. AfpFreeMemory(ucDeviceName.Buffer);
  151. if (NT_SUCCESS(status))
  152. {
  153. // if the ZwCreate passed set the status to the IoStatus
  154. status = IoStatusBlock.Status;
  155. if (!NT_SUCCESS(status))
  156. {
  157. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  158. ("DsiOpenTdiAddress: ZwCreateFile failed, iostatus=%lx\n",status));
  159. AFPDetachProcess(CurrentProcess);
  160. return(status);
  161. }
  162. // dereference the file object to keep the device ptr around to avoid
  163. // this dereference at run time
  164. //
  165. status = ObReferenceObjectByHandle(
  166. FileHandle,
  167. (ULONG)0,
  168. 0,
  169. KernelMode,
  170. (PVOID *)&pFileObject,
  171. NULL);
  172. if (NT_SUCCESS(status))
  173. {
  174. AFPDetachProcess(CurrentProcess);
  175. fAttachAttempted = FALSE;
  176. pDeviceObject = IoGetRelatedDeviceObject(pFileObject);
  177. status = DsiSetEventHandler(
  178. pDeviceObject,
  179. pFileObject,
  180. TDI_EVENT_ERROR,
  181. (PVOID)DsiTdiErrorHandler,
  182. (PVOID)pTcpAdptr);
  183. if (NT_SUCCESS(status))
  184. {
  185. status = DsiSetEventHandler(
  186. pDeviceObject,
  187. pFileObject,
  188. TDI_EVENT_RECEIVE,
  189. (PVOID)DsiTdiReceiveHandler,
  190. (PVOID)pTcpAdptr);
  191. if (NT_SUCCESS(status))
  192. {
  193. status = DsiSetEventHandler(
  194. pDeviceObject,
  195. pFileObject,
  196. TDI_EVENT_DISCONNECT,
  197. (PVOID)DsiTdiDisconnectHandler,
  198. (PVOID)pTcpAdptr);
  199. if (NT_SUCCESS(status))
  200. {
  201. status = DsiSetEventHandler(
  202. pDeviceObject,
  203. pFileObject,
  204. TDI_EVENT_CONNECT,
  205. (PVOID)DsiTdiConnectHandler,
  206. (PVOID)pTcpAdptr);
  207. if (NT_SUCCESS(status))
  208. {
  209. // all worked well: done here
  210. *pRetFileHandle = FileHandle;
  211. *ppRetFileObj = pFileObject;
  212. return(status);
  213. }
  214. else
  215. {
  216. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  217. ("DsiOpenTdiAddress: Set.. DsiTdiConnectHandler failed %lx\n",
  218. status));
  219. }
  220. }
  221. else
  222. {
  223. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  224. ("DsiOpenTdiAddress: Set.. DsiTdiDisconnectHandler failed %lx\n",
  225. status));
  226. }
  227. }
  228. else
  229. {
  230. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  231. ("DsiOpenTdiAddress: Set.. DsiTdiReciveHandler failed %lx\n",
  232. status));
  233. }
  234. //
  235. // ERROR Case
  236. //
  237. ObDereferenceObject(pFileObject);
  238. ZwClose(FileHandle);
  239. return(status);
  240. }
  241. else
  242. {
  243. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  244. ("DsiOpenTdiAddress: Set.. DsiTdiErrorHandler failed %lx\n",
  245. status));
  246. }
  247. }
  248. else
  249. {
  250. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  251. ("DsiOpenTdiAddress: ObReferenceObjectByHandle failed %lx\n",status));
  252. ZwClose(FileHandle);
  253. }
  254. }
  255. else
  256. {
  257. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  258. ("DsiOpenTdiAddress: ZwCreateFile failed %lx\n",status));
  259. }
  260. if (fAttachAttempted)
  261. {
  262. AFPDetachProcess(CurrentProcess);
  263. }
  264. return(status);
  265. }
  266. /*** DsiOpenTdiConnection
  267. *
  268. * This routine creates a TDI Conection for the given connection object
  269. *
  270. * Parm IN: pTcpConn - connection object
  271. *
  272. * Returns: status of operation
  273. *
  274. */
  275. NTSTATUS
  276. DsiOpenTdiConnection(
  277. IN PTCPCONN pTcpConn
  278. )
  279. {
  280. IO_STATUS_BLOCK IoStatusBlock;
  281. NTSTATUS Status;
  282. OBJECT_ATTRIBUTES ObjectAttributes;
  283. PFILE_FULL_EA_INFORMATION EaBuffer;
  284. UNICODE_STRING RelativeDeviceName = {0,0,NULL};
  285. PMDL pMdl;
  286. PEPROCESS CurrentProcess;
  287. BOOLEAN fAttachAttempted;
  288. ASSERT(KeGetCurrentIrql() != DISPATCH_LEVEL);
  289. ASSERT(VALID_TCPCONN(pTcpConn));
  290. ASSERT(pTcpConn->con_pTcpAdptr->adp_Signature == DSI_ADAPTER_SIGNATURE);
  291. InitializeObjectAttributes (
  292. &ObjectAttributes,
  293. &RelativeDeviceName,
  294. 0,
  295. pTcpConn->con_pTcpAdptr->adp_FileHandle,
  296. NULL);
  297. // Allocate memory for the address info to be passed to the transport
  298. EaBuffer = (PFILE_FULL_EA_INFORMATION)AfpAllocZeroedNonPagedMemory (
  299. sizeof(FILE_FULL_EA_INFORMATION) - 1 +
  300. TDI_CONNECTION_CONTEXT_LENGTH + 1 +
  301. sizeof(CONNECTION_CONTEXT));
  302. if (!EaBuffer)
  303. {
  304. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  305. ("DsiOpenTdiConnection: alloc for EaBuffer failed\n"));
  306. return(STATUS_INSUFFICIENT_RESOURCES);
  307. }
  308. EaBuffer->NextEntryOffset = 0;
  309. EaBuffer->Flags = 0;
  310. EaBuffer->EaNameLength = TDI_CONNECTION_CONTEXT_LENGTH;
  311. EaBuffer->EaValueLength = sizeof (CONNECTION_CONTEXT);
  312. // copy ConnectionContext to EaName
  313. RtlMoveMemory( EaBuffer->EaName, TdiConnectionContext, EaBuffer->EaNameLength + 1 );
  314. // put out context into the EaBuffer
  315. RtlMoveMemory (
  316. (PVOID)&EaBuffer->EaName[EaBuffer->EaNameLength + 1],
  317. (CONST PVOID)&pTcpConn,
  318. sizeof (CONNECTION_CONTEXT));
  319. CurrentProcess = IoGetCurrentProcess();
  320. AFPAttachProcess(CurrentProcess);;
  321. fAttachAttempted = TRUE;
  322. Status = ZwCreateFile (
  323. &pTcpConn->con_FileHandle,
  324. GENERIC_READ | GENERIC_WRITE,
  325. &ObjectAttributes, // object attributes.
  326. &IoStatusBlock, // returned status information.
  327. NULL, // block size (unused).
  328. FILE_ATTRIBUTE_NORMAL, // file attributes.
  329. 0,
  330. FILE_CREATE,
  331. 0, // create options.
  332. (PVOID)EaBuffer, // EA buffer.
  333. sizeof(FILE_FULL_EA_INFORMATION) - 1 +
  334. TDI_CONNECTION_CONTEXT_LENGTH + 1 +
  335. sizeof(CONNECTION_CONTEXT));
  336. AfpFreeMemory((PVOID)EaBuffer);
  337. if (NT_SUCCESS(Status))
  338. {
  339. // if the ZwCreate passed set the status to the IoStatus
  340. //
  341. Status = IoStatusBlock.Status;
  342. if (NT_SUCCESS(Status))
  343. {
  344. // dereference file handle, now that we are at task time
  345. Status = ObReferenceObjectByHandle(
  346. pTcpConn->con_FileHandle,
  347. 0L,
  348. NULL,
  349. KernelMode,
  350. (PVOID *)&pTcpConn->con_pFileObject,
  351. NULL);
  352. if (NT_SUCCESS(Status))
  353. {
  354. AFPDetachProcess(CurrentProcess);
  355. return(Status);
  356. }
  357. else
  358. {
  359. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  360. ("DsiOpenTdiConnection: ObReference.. failed %lx\n",Status));
  361. ZwClose(pTcpConn->con_FileHandle);
  362. }
  363. }
  364. else
  365. {
  366. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  367. ("DsiOpenTdiConnection: ZwCreateFile IoStatus failed %lx\n",Status));
  368. }
  369. }
  370. else
  371. {
  372. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  373. ("DsiOpenTdiConnection: ZwCreateFile failed %lx\n",Status));
  374. }
  375. if (fAttachAttempted)
  376. {
  377. AFPDetachProcess(CurrentProcess);
  378. }
  379. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  380. ("DsiOpenTdiConnection: taking error path, returning %lx\n",Status));
  381. return Status;
  382. }
  383. /*** DsiAssociateTdiConnection
  384. *
  385. * This routine associates a TDI connection with the address object for AFP port
  386. *
  387. * Parm IN: pTcpConn - connection object
  388. *
  389. * Returns: status of operation
  390. *
  391. */
  392. NTSTATUS
  393. DsiAssociateTdiConnection(
  394. IN PTCPCONN pTcpConn
  395. )
  396. {
  397. NTSTATUS status;
  398. PIRP pIrp;
  399. PDEVICE_OBJECT pDeviceObject;
  400. ASSERT(VALID_TCPCONN(pTcpConn));
  401. ASSERT(pTcpConn->con_pTcpAdptr->adp_Signature == DSI_ADAPTER_SIGNATURE);
  402. pDeviceObject = IoGetRelatedDeviceObject(pTcpConn->con_pFileObject);
  403. if ((pIrp = AfpAllocIrp(pDeviceObject->StackSize)) == NULL)
  404. {
  405. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  406. ("DsiAssociateTdiConnection: alloc for pIrp failed\n"));
  407. return(STATUS_INSUFFICIENT_RESOURCES);
  408. }
  409. TdiBuildAssociateAddress(
  410. pIrp,
  411. pDeviceObject,
  412. pTcpConn->con_pFileObject,
  413. DsiTdiCompletionRoutine,
  414. NULL,
  415. pTcpConn->con_pTcpAdptr->adp_FileHandle);
  416. status = DsiTdiSynchronousIrp(pIrp, pDeviceObject);
  417. if (status != STATUS_SUCCESS)
  418. {
  419. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  420. ("DsiAssociateTdiConnection: ..TdiSynch.. failed %lx\n",status));
  421. }
  422. AfpFreeIrp(pIrp);
  423. return(status);
  424. }
  425. /*** DsiSetEventHandler
  426. *
  427. * This routine sends an irp down to the tcp stack to set a specified event handler
  428. *
  429. * Parm IN: pDeviceObject - TCP's device object
  430. * pFileObject - file object corresponding to the address object
  431. * EventType - TDI_EVENT_CONNECT, TDI_EVENT_RECEIVE etc.
  432. * EventHandler - the handler for this event
  433. * Context - our adapter object
  434. *
  435. * Returns: status of operation
  436. *
  437. */
  438. NTSTATUS
  439. DsiSetEventHandler(
  440. IN PDEVICE_OBJECT pDeviceObject,
  441. IN PFILE_OBJECT pFileObject,
  442. IN ULONG EventType,
  443. IN PVOID EventHandler,
  444. IN PVOID Context
  445. )
  446. {
  447. PIRP pIrp;
  448. NTSTATUS status;
  449. if ((pIrp = AfpAllocIrp(pDeviceObject->StackSize)) == NULL)
  450. {
  451. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  452. ("DsiSetEventHandler: alloc for pIrp failed\n"));
  453. return(STATUS_INSUFFICIENT_RESOURCES);
  454. }
  455. TdiBuildSetEventHandler(pIrp,
  456. pDeviceObject,
  457. pFileObject,
  458. NULL,
  459. NULL,
  460. EventType,
  461. EventHandler,
  462. Context);
  463. status = DsiTdiSynchronousIrp(pIrp, pDeviceObject);
  464. if (status != STATUS_SUCCESS)
  465. {
  466. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  467. ("DsiSetEventHandler: ..TdiSynch.. failed %lx\n",status));
  468. }
  469. AfpFreeIrp(pIrp);
  470. return(status);
  471. }
  472. /*** DsiTdiSynchronousIrp
  473. *
  474. * This routine sends an irp down to the tcp stack, and blocks until the irp
  475. * is completed
  476. *
  477. * Parm IN: pIrp - the irp that needs to be sent down
  478. * pDeviceObject - TCP's device object
  479. *
  480. * Returns: status of operation
  481. *
  482. */
  483. NTSTATUS
  484. DsiTdiSynchronousIrp(
  485. IN PIRP pIrp,
  486. PDEVICE_OBJECT pDeviceObject
  487. )
  488. {
  489. NTSTATUS status;
  490. KEVENT Event;
  491. KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
  492. IoSetCompletionRoutine(pIrp,
  493. (PIO_COMPLETION_ROUTINE)DsiTdiCompletionRoutine,
  494. (PVOID)&Event,
  495. TRUE,
  496. TRUE,
  497. TRUE);
  498. status = IoCallDriver(pDeviceObject, pIrp);
  499. if (!NT_SUCCESS(status))
  500. {
  501. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  502. ("DsiTdiSynchronousIrp: IoCallDriver failed %lx\n",status));
  503. }
  504. if (status == STATUS_PENDING)
  505. {
  506. status = KeWaitForSingleObject((PVOID)&Event,
  507. Executive,
  508. KernelMode,
  509. FALSE,
  510. NULL);
  511. if (!NT_SUCCESS(status))
  512. {
  513. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  514. ("DsiTdiSynchronousIrp: KeWaitFor... failed %lx\n",status));
  515. return(status);
  516. }
  517. status = pIrp->IoStatus.Status;
  518. }
  519. return(status);
  520. }
  521. /*** DsiTdiCompletionRoutine
  522. *
  523. * This routine gets called when the irp sent in DsiTdiSynchronousIrp is
  524. * completed
  525. *
  526. * Parm IN: pDeviceObject - TCP's device object
  527. * pIrp - the irp that got completed
  528. * Context - our adapter object
  529. *
  530. * Returns: status of operation
  531. *
  532. */
  533. NTSTATUS
  534. DsiTdiCompletionRoutine(
  535. IN PDEVICE_OBJECT DeviceObject,
  536. IN PIRP Irp,
  537. IN PVOID Context
  538. )
  539. {
  540. KeSetEvent((PKEVENT )Context, 0, FALSE);
  541. return(STATUS_MORE_PROCESSING_REQUIRED);
  542. }
  543. /*** DsiTdiSend
  544. *
  545. * This routine is the send routine for all DSI sends out to TCP
  546. *
  547. * Parm IN: pTcpConn - the connection object
  548. * pMdl - mdl containing the buffer
  549. * DataLen - how many bytes to send
  550. * pCompletionRoutine - whom to call when send completes
  551. * pContext - context for the completion routine
  552. *
  553. * Returns: status of operation
  554. *
  555. */
  556. NTSTATUS
  557. DsiTdiSend(
  558. IN PTCPCONN pTcpConn,
  559. IN PMDL pMdl,
  560. IN DWORD DataLen,
  561. IN PVOID pCompletionRoutine,
  562. IN PVOID pContext
  563. )
  564. {
  565. PDEVICE_OBJECT pDeviceObject;
  566. PIRP pIrp;
  567. NTSTATUS status;
  568. // make sure beginning of the packet looks like the DSI header
  569. #if DBG
  570. PBYTE pPacket;
  571. pPacket = MmGetSystemAddressForMdlSafe(
  572. pMdl,
  573. NormalPagePriority);
  574. if (pPacket != NULL)
  575. ASSERT(*(DWORD *)&pPacket[DSI_OFFSET_DATALEN] == ntohl(DataLen-DSI_HEADER_SIZE));
  576. #endif
  577. pDeviceObject = IoGetRelatedDeviceObject(pTcpConn->con_pFileObject);
  578. if ((pIrp = AfpAllocIrp(pDeviceObject->StackSize)) == NULL)
  579. {
  580. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  581. ("DsiTdiSend: AllocIrp failed\n"));
  582. return(STATUS_INSUFFICIENT_RESOURCES);
  583. }
  584. pIrp->CancelRoutine = NULL;
  585. TdiBuildSend(
  586. pIrp,
  587. pDeviceObject,
  588. pTcpConn->con_pFileObject,
  589. pCompletionRoutine,
  590. pContext,
  591. pMdl,
  592. 0,
  593. DataLen);
  594. status = IoCallDriver(pDeviceObject,pIrp);
  595. if (!NT_SUCCESS(status))
  596. {
  597. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  598. ("DsiTdiSend: IoCallDriver failed %lx\n",status));
  599. }
  600. return(STATUS_PENDING);
  601. }
  602. /*** DsiIpAddressCameIn
  603. *
  604. * This routine gets called when ipaddress becomes available on an adapter
  605. *
  606. * Parm IN: Address - TA_ADDRESS
  607. * Context1 -
  608. * Context2 -
  609. *
  610. * Returns: none
  611. *
  612. */
  613. VOID
  614. DsiIpAddressCameIn(
  615. IN PTA_ADDRESS Address,
  616. IN PUNICODE_STRING DeviceName,
  617. IN PTDI_PNP_CONTEXT Context2
  618. )
  619. {
  620. IPADDRESS IpAddress;
  621. PUNICODE_STRING pBindDeviceName;
  622. NTSTATUS status=STATUS_SUCCESS;
  623. KIRQL OldIrql;
  624. BOOLEAN fCreateAdapter=FALSE;
  625. BOOLEAN fClosing=FALSE;
  626. pBindDeviceName = DeviceName;
  627. // if this is not an ipaddress, we don't care: just return
  628. if (Address->AddressType != TDI_ADDRESS_TYPE_IP)
  629. {
  630. return;
  631. }
  632. IpAddress = ntohl(((PTDI_ADDRESS_IP)&Address->Address[0])->in_addr);
  633. if (IpAddress == 0)
  634. {
  635. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_WARN,
  636. ("AfpTdiIpAddressCameIn: ipaddress is 0 on %ws!\n",
  637. (pBindDeviceName)->Buffer));
  638. return;
  639. }
  640. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_WARN,
  641. ("AfpTdiIpAddressCameIn: %d.%d.%d.%d on %ws\n",
  642. (IpAddress>>24)&0xFF,(IpAddress>>16)&0xFF,(IpAddress>>8)&0xFF,
  643. IpAddress&0xFF,(pBindDeviceName)->Buffer));
  644. if ((AfpServerState == AFP_STATE_STOP_PENDING) ||
  645. (AfpServerState == AFP_STATE_SHUTTINGDOWN) ||
  646. (AfpServerState == AFP_STATE_STOPPED))
  647. {
  648. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  649. ("AfpTdiIpAddressCameIn: server shutting down, returning\n"));
  650. return;
  651. }
  652. //
  653. // do we already have the DSI-tdi interface initialized (i.e. DsiTcpAdapter
  654. // is non-null)? If we already saw an ipaddr come in earlier, this would be
  655. // initialized. if not, we must initialize now
  656. //
  657. ACQUIRE_SPIN_LOCK(&DsiAddressLock, &OldIrql);
  658. if (DsiTcpAdapter == NULL)
  659. {
  660. fCreateAdapter = TRUE;
  661. }
  662. RELEASE_SPIN_LOCK(&DsiAddressLock, OldIrql);
  663. // add this ipaddress to our list
  664. DsiAddIpaddressToList(IpAddress);
  665. if (fCreateAdapter)
  666. {
  667. DsiCreateAdapter();
  668. }
  669. // ipaddress came in: update the status buffer
  670. DsiScheduleWorkerEvent(DsiUpdateAfpStatus, NULL);
  671. }
  672. /*** DsiIpAddressWentAway
  673. *
  674. * This routine gets called when ipaddress goes away on an adapter
  675. *
  676. * Parm IN: Address - TA_ADDRESS
  677. * Context1 -
  678. * Context2 -
  679. *
  680. * Returns: none
  681. *
  682. */
  683. VOID
  684. DsiIpAddressWentAway(
  685. IN PTA_ADDRESS Address,
  686. IN PUNICODE_STRING DeviceName,
  687. IN PTDI_PNP_CONTEXT Context2
  688. )
  689. {
  690. PUNICODE_STRING pBindDeviceName;
  691. IPADDRESS IpAddress;
  692. KIRQL OldIrql;
  693. BOOLEAN fDestroyIt=FALSE;
  694. BOOLEAN fIpAddrRemoved=TRUE;
  695. BOOLEAN fMustDeref=FALSE;
  696. pBindDeviceName = DeviceName;
  697. if (Address->AddressType != TDI_ADDRESS_TYPE_IP)
  698. {
  699. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_WARN,
  700. ("AfpTdiIpAddressWentAway: unknown AddrType %d on %ws, ignoring!\n",
  701. Address->AddressType,(pBindDeviceName)->Buffer));
  702. return;
  703. }
  704. IpAddress = ntohl(((PTDI_ADDRESS_IP)&Address->Address[0])->in_addr);
  705. if (IpAddress == 0)
  706. {
  707. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_WARN,
  708. ("AfpTdiIpAddressWentAway: ipaddress is 0 on %ws!\n",
  709. (pBindDeviceName)->Buffer));
  710. return;
  711. }
  712. DsiRemoveIpaddressFromList(IpAddress);
  713. //
  714. // if the global adapter exists, see if we need to destroy it because the
  715. // last ipaddress went away
  716. //
  717. ACQUIRE_SPIN_LOCK(&DsiAddressLock, &OldIrql);
  718. if (DsiTcpAdapter != NULL)
  719. {
  720. fDestroyIt = IsListEmpty(&DsiIpAddrList)? TRUE : FALSE;
  721. }
  722. RELEASE_SPIN_LOCK(&DsiAddressLock, OldIrql);
  723. // ipaddress went away: update the status buffer
  724. DsiScheduleWorkerEvent(DsiUpdateAfpStatus, NULL);
  725. if (fDestroyIt)
  726. {
  727. DsiDestroyAdapter();
  728. }
  729. }
  730. /*** DsiTdiConnectHandler
  731. *
  732. * This routine
  733. *
  734. * Parm IN: EventContext - pTcpAdptr that we passed when we set tdi handlers
  735. * MacIpAddrLen - length of the address of the Mac (4 bytes!)
  736. * pMacIpAddr - ipaddr of the Mac that's attempting to connect
  737. * DsiDataLength - length of DSI data, if any, in this connect request
  738. * pDsiData - pointer to DSI data, if any
  739. * OptionsLength - unused
  740. * pOptions - unused
  741. *
  742. * Parm OUT: pOurConnContext - connection context, pTcpConn for this connection
  743. * ppOurAcceptIrp - irp, if accpeting this connection
  744. *
  745. * Returns: status of operation
  746. *
  747. */
  748. NTSTATUS
  749. DsiTdiConnectHandler(
  750. IN PVOID EventContext,
  751. IN int MacIpAddrLen,
  752. IN PVOID pSrcAddress,
  753. IN int DsiDataLength,
  754. IN PVOID pDsiData,
  755. IN int OptionsLength,
  756. IN PVOID pOptions,
  757. OUT CONNECTION_CONTEXT *pOurConnContext,
  758. OUT PIRP *ppOurAcceptIrp
  759. )
  760. {
  761. NTSTATUS status=STATUS_SUCCESS;
  762. PTCPADPTR pTcpAdptr;
  763. PTCPCONN pTcpConn;
  764. PDEVICE_OBJECT pDeviceObject;
  765. IPADDRESS MacIpAddr;
  766. PTRANSPORT_ADDRESS pXportAddr;
  767. PIRP pIrp;
  768. pTcpAdptr = (PTCPADPTR)EventContext;
  769. *pOurConnContext = NULL;
  770. *ppOurAcceptIrp = NULL;
  771. ASSERT(pTcpAdptr->adp_Signature == DSI_ADAPTER_SIGNATURE);
  772. pDeviceObject = IoGetRelatedDeviceObject(pTcpAdptr->adp_pFileObject);
  773. if ((pIrp = AfpAllocIrp(pDeviceObject->StackSize)) == NULL)
  774. {
  775. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  776. ("DsiTdiConnectHandler: AllocIrp failed\n"));
  777. return(STATUS_DATA_NOT_ACCEPTED);
  778. }
  779. pXportAddr = (PTRANSPORT_ADDRESS)pSrcAddress;
  780. MacIpAddr = ((PTDI_ADDRESS_IP)&pXportAddr->Address[0].Address[0])->in_addr;
  781. //
  782. // see if DSI wants to accept this connection
  783. //
  784. status = DsiAcceptConnection(pTcpAdptr, ntohl(MacIpAddr), &pTcpConn);
  785. if (!NT_SUCCESS(status))
  786. {
  787. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  788. ("DsiTdiConnectHandler: DsiAccep.. failed %lx\n",status));
  789. AfpFreeIrp(pIrp);
  790. return(status);
  791. }
  792. TdiBuildAccept(pIrp,
  793. IoGetRelatedDeviceObject(pTcpConn->con_pFileObject),
  794. pTcpConn->con_pFileObject,
  795. DsiAcceptConnectionCompletion,
  796. pTcpConn,
  797. NULL,
  798. NULL);
  799. pIrp->MdlAddress = NULL;
  800. *pOurConnContext = (CONNECTION_CONTEXT)pTcpConn;
  801. *ppOurAcceptIrp = pIrp;
  802. // do what IoSubSystem would have done, if we had called IoCallDriver
  803. IoSetNextIrpStackLocation(pIrp);
  804. return(STATUS_MORE_PROCESSING_REQUIRED);
  805. }
  806. /*** DsiTdiReceiveHandler
  807. *
  808. * This routine
  809. *
  810. * Parm IN: EventContext - pTcpAdptr that we passed when we set tdi handlers
  811. * ConnectionContext - our context, pTcpConn for this connection
  812. * RcvFlags - more info about how the data was received
  813. * BytesIndicated - number of bytes tcp is indicating
  814. * BytesAvailable - number of bytes that came in (tcp has with it)
  815. * pDsiData - the data that came in
  816. *
  817. * Parm OUT: pBytesAccepted - how many bytes did we accept
  818. * ppIrp - irp, if for tcp to copy data in (if needed)
  819. *
  820. * Returns: status of operation
  821. *
  822. */
  823. NTSTATUS
  824. DsiTdiReceiveHandler(
  825. IN PVOID EventContext,
  826. IN PVOID ConnectionContext,
  827. IN USHORT RcvFlags,
  828. IN ULONG BytesIndicated,
  829. IN ULONG BytesAvailable,
  830. OUT PULONG pBytesAccepted,
  831. IN PVOID pDsiData,
  832. OUT PIRP *ppIrp
  833. )
  834. {
  835. NTSTATUS status;
  836. PTCPCONN pTcpConn;
  837. PBYTE pBuffer;
  838. PIRP pIrp;
  839. pTcpConn = (PTCPCONN)ConnectionContext;
  840. *ppIrp = NULL;
  841. *pBytesAccepted = 0;
  842. ASSERT(VALID_TCPCONN(pTcpConn));
  843. status = DsiProcessData(pTcpConn,
  844. BytesIndicated,
  845. BytesAvailable,
  846. (PBYTE)pDsiData,
  847. pBytesAccepted,
  848. ppIrp);
  849. return(status);
  850. }
  851. /*** DsiTdiDisconnectHandler
  852. *
  853. * This routine
  854. *
  855. * Parm IN: EventContext - pTcpAdptr that we passed when we set tdi handlers
  856. * ConnectionContext - our context, pTcpConn for this connection
  857. * DisconnectDataLength -
  858. * pDisconnectData -
  859. *
  860. *
  861. *
  862. * Returns: status of operation
  863. *
  864. */
  865. NTSTATUS
  866. DsiTdiDisconnectHandler(
  867. IN PVOID EventContext,
  868. IN PVOID ConnectionContext,
  869. IN ULONG DisconnectDataLength,
  870. IN PVOID pDisconnectData,
  871. IN ULONG DisconnectInformationLength,
  872. IN PVOID pDisconnectInformation,
  873. IN ULONG DisconnectIndicators
  874. )
  875. {
  876. PTCPCONN pTcpConn;
  877. KIRQL OldIrql;
  878. BOOLEAN fMustAbort=FALSE;
  879. BOOLEAN fWeInitiatedAbort=FALSE;
  880. pTcpConn = (PTCPCONN)ConnectionContext;
  881. ASSERT(VALID_TCPCONN(pTcpConn));
  882. //
  883. // if the connection went away non-gracefully (i.e. TCP got a reset), and
  884. // if we have not already given an irp down to tcp to disconnect, then
  885. // complete the disconnect here
  886. //
  887. if ((UCHAR)DisconnectIndicators == TDI_DISCONNECT_ABORT)
  888. {
  889. ACQUIRE_SPIN_LOCK(&pTcpConn->con_SpinLock, &OldIrql);
  890. fWeInitiatedAbort =
  891. (pTcpConn->con_State & TCPCONN_STATE_ABORTIVE_DISCONNECT)? TRUE : FALSE;
  892. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  893. ("ABORT from %s on %lx\n",fWeInitiatedAbort?"Local":"Remote",pTcpConn));
  894. if (pTcpConn->con_State & TCPCONN_STATE_NOTIFY_TCP)
  895. {
  896. fMustAbort = TRUE;
  897. pTcpConn->con_State &= ~TCPCONN_STATE_NOTIFY_TCP;
  898. pTcpConn->con_State |= TCPCONN_STATE_CLOSING;
  899. }
  900. RELEASE_SPIN_LOCK(&pTcpConn->con_SpinLock, OldIrql);
  901. if (fMustAbort)
  902. {
  903. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_WARN,
  904. ("DsiTdiDisconnectHandler: abortive disconnect on %lx\n",pTcpConn));
  905. DsiAbortConnection(pTcpConn);
  906. DsiTcpDisconnectCompletion(NULL, NULL, pTcpConn);
  907. // TCP is telling us it got cient's RST: remove the TCP CLIENT-FIN refcount
  908. DsiDereferenceConnection(pTcpConn);
  909. DBGREFCOUNT(("DsiTdiDisconnectHandler: CLIENT-FIN dec %lx (%d %d,%d)\n",
  910. pTcpConn,pTcpConn->con_RefCount,pTcpConn->con_State,pTcpConn->con_RcvState));
  911. }
  912. //
  913. // if we had initiated a graceful close, remove that TCP CLIENT-FIN refcount:
  914. // (if we had initiated an abortive close, we already took care of it)
  915. //
  916. else if (!fWeInitiatedAbort)
  917. {
  918. DsiDereferenceConnection(pTcpConn);
  919. }
  920. else
  921. {
  922. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  923. ("DsiTdiDisconnectHandler: abortive disc,race condition on %lx\n",
  924. pTcpConn));
  925. }
  926. }
  927. else if ((UCHAR)DisconnectIndicators == TDI_DISCONNECT_RELEASE)
  928. {
  929. //
  930. // since we got a graceful disconnect from the remote client, we had
  931. // better received the DSI Close already. If not, the client is on
  932. // drugs, so just reset the connection!
  933. //
  934. ACQUIRE_SPIN_LOCK(&pTcpConn->con_SpinLock, &OldIrql);
  935. if ((pTcpConn->con_State & TCPCONN_STATE_AFP_ATTACHED) &&
  936. (!(pTcpConn->con_State & TCPCONN_STATE_RCVD_REMOTE_CLOSE)))
  937. {
  938. fMustAbort = TRUE;
  939. }
  940. RELEASE_SPIN_LOCK(&pTcpConn->con_SpinLock, OldIrql);
  941. if (fMustAbort)
  942. {
  943. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_WARN,
  944. ("DsiTdiDisconnectHandler: ungraceful FIN, killing %lx\n",pTcpConn));
  945. DsiAbortConnection(pTcpConn);
  946. }
  947. else
  948. {
  949. //
  950. // by this time, we shouldn't have to do this, but just in case we
  951. // have an ill-behaved client (calling this routine many times is ok)
  952. //
  953. DsiTerminateConnection(pTcpConn);
  954. // TCP is telling us it got cient's FIN: remove the TCP CLIENT-FIN refcount
  955. DsiDereferenceConnection(pTcpConn);
  956. DBGREFCOUNT(("DsiTdiDisconnectHandler: CLIENT-FIN dec %lx (%d %d,%d)\n",
  957. pTcpConn,pTcpConn->con_RefCount,pTcpConn->con_State,pTcpConn->con_RcvState));
  958. }
  959. }
  960. else
  961. {
  962. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  963. ("DsiTdiDisconnectHandler: flag=%d, ignored on %lx\n",
  964. DisconnectIndicators,pTcpConn));
  965. ASSERT(0);
  966. }
  967. return(STATUS_SUCCESS);
  968. }
  969. /*** DsiTdiErrorHandler
  970. *
  971. * This routine
  972. *
  973. * Parm IN: EventContext - pTcpAdptr that we passed when we set tdi handlers
  974. * status - what went wrong?
  975. *
  976. * Returns: status of operation
  977. *
  978. */
  979. NTSTATUS
  980. DsiTdiErrorHandler(
  981. IN PVOID EventContext,
  982. IN NTSTATUS Status
  983. )
  984. {
  985. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  986. ("DsiTdiErrorHandler: entered, with Status=%lx\n",Status));
  987. ASSERT(0);
  988. return(STATUS_DATA_NOT_ACCEPTED);
  989. }
  990. /*** DsiCloseTdiAddress
  991. *
  992. * This routine closes the address object with TCP
  993. *
  994. * Parm IN: pTcpAdptr - our adapter object
  995. *
  996. * Returns: status of operation
  997. *
  998. */
  999. NTSTATUS
  1000. DsiCloseTdiAddress(
  1001. IN PTCPADPTR pTcpAdptr
  1002. )
  1003. {
  1004. PEPROCESS CurrentProcess;
  1005. ASSERT(KeGetCurrentIrql() != DISPATCH_LEVEL);
  1006. ASSERT(pTcpAdptr->adp_Signature == DSI_ADAPTER_SIGNATURE);
  1007. CurrentProcess = IoGetCurrentProcess();
  1008. AFPAttachProcess(CurrentProcess);;
  1009. if (pTcpAdptr->adp_pFileObject)
  1010. {
  1011. ObDereferenceObject((PVOID *)pTcpAdptr->adp_pFileObject);
  1012. pTcpAdptr->adp_pFileObject = NULL;
  1013. }
  1014. if (pTcpAdptr->adp_FileHandle != INVALID_HANDLE_VALUE)
  1015. {
  1016. ZwClose(pTcpAdptr->adp_FileHandle);
  1017. pTcpAdptr->adp_FileHandle = INVALID_HANDLE_VALUE;
  1018. }
  1019. AFPDetachProcess(CurrentProcess);
  1020. return(STATUS_SUCCESS);
  1021. }
  1022. /*** DsiCloseTdiConnection
  1023. *
  1024. * This routine closes the connection object with TCP
  1025. *
  1026. * Parm IN: pTcpConn - our connection context
  1027. *
  1028. * Returns: status of operation
  1029. *
  1030. */
  1031. NTSTATUS
  1032. DsiCloseTdiConnection(
  1033. IN PTCPCONN pTcpConn
  1034. )
  1035. {
  1036. PEPROCESS CurrentProcess;
  1037. ASSERT(KeGetCurrentIrql() != DISPATCH_LEVEL);
  1038. ASSERT(pTcpConn->con_Signature == DSI_CONN_SIGNATURE);
  1039. ASSERT(pTcpConn->con_pTcpAdptr->adp_Signature == DSI_ADAPTER_SIGNATURE);
  1040. CurrentProcess = IoGetCurrentProcess();
  1041. AFPAttachProcess(CurrentProcess);;
  1042. if (pTcpConn->con_pFileObject)
  1043. {
  1044. ObDereferenceObject((PVOID *)pTcpConn->con_pFileObject);
  1045. pTcpConn->con_pFileObject = NULL;
  1046. }
  1047. if (pTcpConn->con_FileHandle != INVALID_HANDLE_VALUE)
  1048. {
  1049. ZwClose(pTcpConn->con_FileHandle);
  1050. pTcpConn->con_FileHandle = INVALID_HANDLE_VALUE;
  1051. }
  1052. AFPDetachProcess(CurrentProcess);
  1053. return(STATUS_SUCCESS);
  1054. }