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.

2005 lines
46 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. link.c
  5. Abstract:
  6. This module contains the code that is very specific to initialization
  7. and unload operations in the irenum driver
  8. Author:
  9. Brian Lieuallen, 7-13-2000
  10. Environment:
  11. Kernel mode
  12. Revision History :
  13. --*/
  14. //#include "internal.h"
  15. #define UNICODE 1
  16. #include <ntosp.h>
  17. #include <zwapi.h>
  18. #include <tdikrnl.h>
  19. #define UINT ULONG //tmp
  20. #include <irioctl.h>
  21. #include <ircommtdi.h>
  22. #include <ircomm.h>
  23. #include <ircommdbg.h>
  24. #include "buffer.h"
  25. #include <ntddser.h>
  26. #include "link.h"
  27. typedef enum {
  28. LINK_IDLE,
  29. LINK_PRE_CONNECT,
  30. LINK_ACCEPTED,
  31. LINK_ACCEPT_FAILED,
  32. LINK_CONNECTED,
  33. LINK_DISCONNECTING,
  34. LINK_CLOSING
  35. } LINK_STATE ;
  36. typedef struct {
  37. LONG ReferenceCount;
  38. LINK_STATE State;
  39. BUFFER_POOL_HANDLE SendBufferPool;
  40. BUFFER_POOL_HANDLE ControlBufferPool;
  41. BUFFER_POOL_HANDLE ReceiveBufferPool;
  42. } CONNECTION_OBJECT, *PCONNECTION_OBJECT;
  43. typedef struct _TDI_OBJECTS {
  44. #if DBG
  45. PEPROCESS OpenProcess;
  46. #endif
  47. LONG ReferenceCount;
  48. KEVENT CloseEvent;
  49. HANDLE AddressFileHandle;
  50. PFILE_OBJECT AddressFileObject;
  51. HANDLE ConnectionFileHandle;
  52. PFILE_OBJECT ConnectionFileObject;
  53. } TDI_OBJECTS, *PTDI_OBJECTS;
  54. typedef struct _LINK_OBJECT {
  55. KSPIN_LOCK Lock;
  56. LONG ReferenceCount;
  57. KEVENT CloseEvent;
  58. BOOLEAN Closing;
  59. PTDI_OBJECTS TdiObjects;
  60. PVOID Context;
  61. PLINK_RECEIVE LinkReceiveHandler;
  62. PLINK_STATE LinkStateHandler;
  63. WORK_QUEUE_ITEM WorkItem;
  64. ULONG SendBuffers;
  65. ULONG ControlBuffers;
  66. ULONG ReceiveBuffers;
  67. CONNECTION_OBJECT Connection;
  68. } LINK_OBJECT, *PLINK_OBJECT;
  69. PTDI_OBJECTS
  70. TdiObjectFromHandle(
  71. TDI_OBJECT_HANDLE Handle
  72. );
  73. VOID
  74. RemoveRefTdiObjects(
  75. TDI_OBJECT_HANDLE Handle
  76. );
  77. VOID
  78. RemoveReferenceFromConnection(
  79. PLINK_OBJECT LinkObject
  80. );
  81. NTSTATUS
  82. GetMaxSendPdu(
  83. PFILE_OBJECT FileObject,
  84. PULONG MaxPdu
  85. );
  86. NTSTATUS
  87. ClientEventReceive (
  88. IN PVOID TdiEventContext,
  89. IN CONNECTION_CONTEXT ConnectionContext,
  90. IN ULONG ReceiveFlags,
  91. IN ULONG BytesIndicated,
  92. IN ULONG BytesAvailable,
  93. OUT ULONG *BytesTaken,
  94. IN PVOID Tsdu,
  95. OUT PIRP *IoRequestPacket
  96. );
  97. NTSTATUS
  98. LinkEventDisconnect(
  99. IN PVOID TdiEventContext,
  100. IN CONNECTION_CONTEXT ConnectionContext,
  101. IN int DisconnectDataLength,
  102. IN PVOID DisconnectData,
  103. IN int DisconnectInformationLength,
  104. IN PVOID DisconnectInformation,
  105. IN ULONG DisconnectFlags
  106. );
  107. NTSTATUS
  108. LinkEventConnect(
  109. IN PVOID TdiEventContext,
  110. IN int RemoteAddressLength,
  111. IN PVOID RemoteAddress,
  112. IN int UserDataLength,
  113. IN PVOID UserData,
  114. IN int OptionsLength,
  115. IN PVOID Options,
  116. OUT CONNECTION_CONTEXT *ConnectionContext,
  117. OUT PIRP *AcceptIrp
  118. );
  119. NTSTATUS
  120. IrdaCompleteAcceptIrp(
  121. PDEVICE_OBJECT DeviceObject,
  122. PIRP Irp,
  123. PVOID Context
  124. );
  125. NTSTATUS
  126. IrdaSetEventHandler (
  127. IN PFILE_OBJECT FileObject,
  128. IN ULONG EventType,
  129. IN PVOID EventHandler,
  130. IN PVOID EventContext
  131. );
  132. VOID
  133. ConnectionPassiveWorkRoutine(
  134. PVOID Context
  135. );
  136. NTSTATUS
  137. IrdaCreateAddress(
  138. IN PTDI_ADDRESS_IRDA pRequestedIrdaAddr,
  139. OUT PHANDLE pAddrHandle
  140. )
  141. {
  142. NTSTATUS Status;
  143. UNICODE_STRING DeviceName;
  144. OBJECT_ATTRIBUTES ObjectAttributes;
  145. IO_STATUS_BLOCK Iosb;
  146. UCHAR EaBuf[sizeof(FILE_FULL_EA_INFORMATION)-1 +
  147. TDI_TRANSPORT_ADDRESS_LENGTH+1 +
  148. sizeof(TRANSPORT_ADDRESS) +
  149. sizeof(TDI_ADDRESS_IRDA)];
  150. PFILE_FULL_EA_INFORMATION pEa = (PFILE_FULL_EA_INFORMATION) EaBuf;
  151. ULONG EaBufLen = sizeof(EaBuf);
  152. TRANSPORT_ADDRESS UNALIGNED * pTranAddr = (PTRANSPORT_ADDRESS)
  153. &(pEa->EaName[TDI_TRANSPORT_ADDRESS_LENGTH + 1]);
  154. TDI_ADDRESS_IRDA UNALIGNED * pIrdaAddr = (PTDI_ADDRESS_IRDA)
  155. pTranAddr->Address[0].Address;
  156. pEa->NextEntryOffset = 0;
  157. pEa->Flags = 0;
  158. pEa->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
  159. RtlCopyMemory(pEa->EaName,
  160. TdiTransportAddress,
  161. pEa->EaNameLength + 1);
  162. pEa->EaValueLength = sizeof(TRANSPORT_ADDRESS) + sizeof(TDI_ADDRESS_IRDA);
  163. pTranAddr->TAAddressCount = 1;
  164. pTranAddr->Address[0].AddressLength = sizeof(TDI_ADDRESS_IRDA);
  165. pTranAddr->Address[0].AddressType = TDI_ADDRESS_TYPE_IRDA;
  166. RtlCopyMemory(pIrdaAddr,
  167. pRequestedIrdaAddr,
  168. sizeof(TDI_ADDRESS_IRDA));
  169. RtlInitUnicodeString(&DeviceName, IRDA_DEVICE_NAME);
  170. InitializeObjectAttributes(&ObjectAttributes, &DeviceName,
  171. OBJ_CASE_INSENSITIVE, NULL, NULL);
  172. Status = ZwCreateFile(
  173. pAddrHandle,
  174. GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
  175. &ObjectAttributes,
  176. &Iosb, // returned status information.
  177. 0, // block size (unused).
  178. 0, // file attributes.
  179. FILE_SHARE_READ | FILE_SHARE_WRITE,
  180. FILE_CREATE, // create disposition.
  181. 0, // create options.
  182. pEa,
  183. EaBufLen);
  184. return Status;
  185. }
  186. NTSTATUS
  187. IrdaCreateConnection(
  188. OUT PHANDLE pConnHandle,
  189. IN PVOID ClientContext)
  190. {
  191. NTSTATUS Status;
  192. UNICODE_STRING DeviceName;
  193. OBJECT_ATTRIBUTES ObjectAttributes;
  194. IO_STATUS_BLOCK Iosb;
  195. UCHAR EaBuf[sizeof(FILE_FULL_EA_INFORMATION)-1 +
  196. TDI_CONNECTION_CONTEXT_LENGTH + 1 +
  197. sizeof(CONNECTION_CONTEXT)];
  198. PFILE_FULL_EA_INFORMATION pEa = (PFILE_FULL_EA_INFORMATION) EaBuf;
  199. ULONG EaBufLen = sizeof(EaBuf);
  200. CONNECTION_CONTEXT UNALIGNED *ctx;
  201. pEa->NextEntryOffset = 0;
  202. pEa->Flags = 0;
  203. pEa->EaNameLength = TDI_CONNECTION_CONTEXT_LENGTH;
  204. pEa->EaValueLength = sizeof(CONNECTION_CONTEXT);
  205. RtlCopyMemory(pEa->EaName, TdiConnectionContext, pEa->EaNameLength + 1);
  206. ctx = (CONNECTION_CONTEXT UNALIGNED *)&pEa->EaName[pEa->EaNameLength + 1];
  207. *ctx = (CONNECTION_CONTEXT) ClientContext;
  208. RtlInitUnicodeString(&DeviceName, IRDA_DEVICE_NAME);
  209. InitializeObjectAttributes(&ObjectAttributes, &DeviceName,
  210. OBJ_CASE_INSENSITIVE, NULL, NULL);
  211. Status = ZwCreateFile(pConnHandle,
  212. GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
  213. &ObjectAttributes,
  214. &Iosb, // returned status information.
  215. 0, // block size (unused).
  216. 0, // file attributes.
  217. FILE_SHARE_READ | FILE_SHARE_WRITE,
  218. FILE_CREATE, // create disposition.
  219. 0, // create options.
  220. pEa,
  221. EaBufLen);
  222. return Status;
  223. }
  224. NTSTATUS
  225. IrdaDisconnect(
  226. PFILE_OBJECT ConnectionFileObject
  227. )
  228. {
  229. PIRP pIrp;
  230. KEVENT Event;
  231. IO_STATUS_BLOCK Iosb;
  232. NTSTATUS Status;
  233. KeInitializeEvent( &Event, SynchronizationEvent, FALSE );
  234. pIrp = TdiBuildInternalDeviceControlIrp(
  235. TDI_DISCONNECT,
  236. IoGetRelatedDeviceObject(ConnectionFileObject),
  237. ConnectionFileObject,
  238. &Event,
  239. &Iosb
  240. );
  241. if (pIrp == NULL) {
  242. return STATUS_INSUFFICIENT_RESOURCES;
  243. }
  244. TdiBuildDisconnect(
  245. pIrp,
  246. IoGetRelatedDeviceObject(ConnectionFileObject),
  247. ConnectionFileObject,
  248. NULL,
  249. NULL,
  250. NULL,
  251. TDI_DISCONNECT_ABORT,
  252. NULL,
  253. NULL
  254. );
  255. IoCallDriver(IoGetRelatedDeviceObject(ConnectionFileObject), pIrp);
  256. KeWaitForSingleObject((PVOID) &Event, Executive, KernelMode, FALSE, NULL);
  257. Status = Iosb.Status;
  258. return Status;
  259. }
  260. NTSTATUS
  261. IrdaAssociateAddress(
  262. PFILE_OBJECT ConnectionFileObject,
  263. HANDLE AddressHandle
  264. )
  265. {
  266. PIRP pIrp;
  267. KEVENT Event;
  268. IO_STATUS_BLOCK Iosb;
  269. NTSTATUS Status;
  270. KeInitializeEvent( &Event, SynchronizationEvent, FALSE );
  271. pIrp = TdiBuildInternalDeviceControlIrp(
  272. TDI_ASSOCIATE_ADDRESS,
  273. IoGetRelatedDeviceObject(ConnectionFileObject),
  274. ConnectionFileObject,
  275. &Event,
  276. &Iosb);
  277. if (pIrp == NULL)
  278. return STATUS_INSUFFICIENT_RESOURCES;
  279. TdiBuildAssociateAddress(
  280. pIrp,
  281. IoGetRelatedDeviceObject(ConnectionFileObject),
  282. ConnectionFileObject,
  283. NULL,
  284. NULL,
  285. AddressHandle);
  286. Status = IoCallDriver(IoGetRelatedDeviceObject(ConnectionFileObject), pIrp);
  287. if (Status == STATUS_PENDING) {
  288. KeWaitForSingleObject((PVOID) &Event, Executive, KernelMode, FALSE, NULL);
  289. }
  290. else
  291. {
  292. ASSERT(NT_ERROR(Status) || KeReadStateEvent(&Event));
  293. }
  294. if (NT_SUCCESS(Status))
  295. {
  296. Status = Iosb.Status;
  297. }
  298. return Status;
  299. }
  300. NTSTATUS
  301. IrdaCreateConnectionForAddress(
  302. HANDLE AddressFileHandle,
  303. PVOID Context,
  304. PFILE_OBJECT *ConnectionFileObject,
  305. HANDLE *ConnectionFileHandle
  306. )
  307. {
  308. NTSTATUS Status;
  309. *ConnectionFileHandle=NULL;
  310. *ConnectionFileObject=NULL;
  311. Status = IrdaCreateConnection(ConnectionFileHandle, Context);
  312. if (!NT_SUCCESS(Status)) {
  313. goto done;
  314. }
  315. Status = ObReferenceObjectByHandle(
  316. *ConnectionFileHandle,
  317. 0L, // DesiredAccess
  318. NULL,
  319. KernelMode,
  320. ConnectionFileObject,
  321. NULL
  322. );
  323. if (!NT_SUCCESS(Status)) {
  324. ZwClose(*ConnectionFileHandle);
  325. *ConnectionFileHandle=NULL;
  326. *ConnectionFileObject=NULL;
  327. goto done;
  328. }
  329. Status = IrdaAssociateAddress(*ConnectionFileObject, AddressFileHandle);
  330. if (!NT_SUCCESS(Status)) {
  331. ZwClose(*ConnectionFileHandle);
  332. *ConnectionFileHandle=NULL;
  333. ObDereferenceObject(*ConnectionFileObject);
  334. *ConnectionFileObject=NULL;
  335. }
  336. done:
  337. return Status;
  338. }
  339. NTSTATUS
  340. InitiateConnection(
  341. PFILE_OBJECT ConnectionFileObject,
  342. ULONG DeviceAddress,
  343. PSTR ServiceName
  344. )
  345. {
  346. UCHAR AddrBuf[sizeof(TRANSPORT_ADDRESS) + sizeof(TDI_ADDRESS_IRDA)];
  347. PTRANSPORT_ADDRESS pTranAddr = (PTRANSPORT_ADDRESS) AddrBuf;
  348. PTDI_ADDRESS_IRDA pIrdaAddr = (PTDI_ADDRESS_IRDA) pTranAddr->Address[0].Address;
  349. TDI_CONNECTION_INFORMATION ConnInfo;
  350. PIRP Irp;
  351. NTSTATUS Status;
  352. KEVENT Event;
  353. IO_STATUS_BLOCK Iosb;
  354. KeInitializeEvent(
  355. &Event,
  356. NotificationEvent,
  357. FALSE
  358. );
  359. Irp = TdiBuildInternalDeviceControlIrp(
  360. TDI_CONNECT,
  361. IoGetRelatedDeviceObject(ConnectionFileObject),
  362. ConnectionFileObject,
  363. &Event,
  364. &Iosb
  365. );
  366. if (Irp == NULL) {
  367. D_ERROR(DbgPrint("IRCOMM: TdiBuildInternalDeviceControlIrp Failed\n");)
  368. Status=STATUS_INSUFFICIENT_RESOURCES;
  369. goto CleanUp;
  370. }
  371. RtlZeroMemory(pIrdaAddr,sizeof(*pIrdaAddr));
  372. RtlCopyMemory(pIrdaAddr->irdaDeviceID, &DeviceAddress, 4);
  373. strcpy(pIrdaAddr->irdaServiceName,ServiceName);
  374. pTranAddr->TAAddressCount = 1;
  375. ConnInfo.UserDataLength = 0;
  376. ConnInfo.UserData = NULL;
  377. ConnInfo.OptionsLength = 0;
  378. ConnInfo.Options = NULL;
  379. ConnInfo.RemoteAddressLength = sizeof(AddrBuf);
  380. ConnInfo.RemoteAddress = pTranAddr;
  381. TdiBuildConnect(
  382. Irp,
  383. IoGetRelatedDeviceObject(ConnectionFileObject),
  384. ConnectionFileObject,
  385. NULL, // CompRoutine
  386. NULL, // Context
  387. NULL, // Timeout
  388. &ConnInfo,
  389. NULL); // ReturnConnectionInfo
  390. Status = IoCallDriver(IoGetRelatedDeviceObject(ConnectionFileObject), Irp);
  391. //
  392. // If necessary, wait for the I/O to complete.
  393. //
  394. D_ERROR(DbgPrint("IRCOMM: status %08lx, %08lx\n",Status,Iosb.Status);)
  395. KeWaitForSingleObject(
  396. &Event,
  397. Executive,
  398. KernelMode,
  399. FALSE,
  400. NULL
  401. );
  402. Status = Iosb.Status;
  403. CleanUp:
  404. return Status;
  405. }
  406. VOID
  407. RemoveReferenceOnLink(
  408. PLINK_OBJECT LinkObject
  409. )
  410. {
  411. LONG Count=InterlockedDecrement(&LinkObject->ReferenceCount);
  412. if (Count == 0) {
  413. ASSERT(LinkObject->Closing);
  414. KeSetEvent(
  415. &LinkObject->CloseEvent,
  416. IO_NO_INCREMENT,
  417. FALSE
  418. );
  419. }
  420. return;
  421. }
  422. NTSTATUS
  423. CreateTdiLink(
  424. TDI_OBJECT_HANDLE TdiObjectHandle,
  425. ULONG DeviceAddress,
  426. CHAR *ServiceName,
  427. BOOLEAN OutGoingConnection,
  428. LINK_HANDLE *LinkHandle,
  429. PVOID Context,
  430. PLINK_RECEIVE LinkReceiveHandler,
  431. PLINK_STATE LinkStateHandler,
  432. ULONG SendBuffers,
  433. ULONG ControlBuffers,
  434. ULONG ReceiveBuffers
  435. )
  436. {
  437. NTSTATUS Status;
  438. PLINK_OBJECT LinkObject;
  439. UCHAR AddrBuf[sizeof(TRANSPORT_ADDRESS) + sizeof(TDI_ADDRESS_IRDA)];
  440. PTRANSPORT_ADDRESS TranAddr = (PTRANSPORT_ADDRESS) AddrBuf;
  441. PTDI_ADDRESS_IRDA IrdaAddr = (PTDI_ADDRESS_IRDA) TranAddr->Address[0].Address;
  442. *LinkHandle=NULL;
  443. LinkObject=ALLOCATE_NONPAGED_POOL(sizeof(*LinkObject));
  444. if (LinkObject == NULL) {
  445. return STATUS_INSUFFICIENT_RESOURCES;
  446. }
  447. RtlZeroMemory(LinkObject,sizeof(*LinkObject));
  448. KeInitializeSpinLock(&LinkObject->Lock);
  449. ExInitializeWorkItem(
  450. &LinkObject->WorkItem,
  451. ConnectionPassiveWorkRoutine,
  452. LinkObject
  453. );
  454. LinkObject->ReferenceCount=1;
  455. KeInitializeEvent(
  456. &LinkObject->CloseEvent,
  457. NotificationEvent,
  458. FALSE
  459. );
  460. LinkObject->Connection.State=LINK_IDLE;
  461. LinkObject->LinkReceiveHandler=LinkReceiveHandler;
  462. LinkObject->LinkStateHandler=LinkStateHandler;
  463. LinkObject->Context=Context;
  464. LinkObject->SendBuffers=SendBuffers;
  465. LinkObject->ControlBuffers=ControlBuffers;
  466. LinkObject->ReceiveBuffers=ReceiveBuffers;
  467. //
  468. // a pointer to the tdi objects from the handle, this will add a refcount
  469. // to the object that will need to release when we done with it
  470. //
  471. LinkObject->TdiObjects=TdiObjectFromHandle(TdiObjectHandle);
  472. Status = IrdaSetEventHandler(
  473. LinkObject->TdiObjects->AddressFileObject,
  474. TDI_EVENT_RECEIVE,
  475. ClientEventReceive,
  476. LinkObject
  477. );
  478. if (!NT_SUCCESS(Status)) {
  479. D_ERROR(DbgPrint("IRCOMM: IrdaSetEventHandler failed for TDI_EVENT_RECEIVE : "
  480. "%08lx\n",Status);)
  481. goto CleanUp;
  482. }
  483. Status = IrdaSetEventHandler(
  484. LinkObject->TdiObjects->AddressFileObject,
  485. TDI_EVENT_DISCONNECT,
  486. LinkEventDisconnect,
  487. LinkObject
  488. );
  489. if (!NT_SUCCESS(Status)) {
  490. D_ERROR(DbgPrint("IRCOMM: IrdaSetEventHandler failed for TDI_EVENT_DISCONNECT : "
  491. "%08lx\n",Status);)
  492. goto CleanUp;
  493. }
  494. //
  495. // save this now, since we may get a callbacks for a connection already
  496. //
  497. *LinkHandle=LinkObject;
  498. if (!OutGoingConnection) {
  499. //
  500. // we are going to be waiting for an incoming connection
  501. //
  502. UCHAR IasData[]={0x00, 0x01, 0x4, // service type 9 wire
  503. 0x01, 0x01, 0x01}; // port type serial
  504. Status = IrdaIASOctetSet(
  505. LinkObject->TdiObjects->AddressFileObject,
  506. "IrDA:IrCOMM",
  507. "Parameters",
  508. (PUCHAR)&IasData[0],
  509. sizeof(IasData)
  510. );
  511. if (!NT_SUCCESS(Status)) {
  512. D_ERROR(DbgPrint("IRCOMM: IrdaIASOctetSet failed : %08lx\n",Status);)
  513. goto CleanUp;
  514. }
  515. Status = IrdaSetEventHandler(
  516. LinkObject->TdiObjects->AddressFileObject,
  517. TDI_EVENT_CONNECT,
  518. LinkEventConnect,
  519. LinkObject
  520. );
  521. if (!NT_SUCCESS(Status)) {
  522. D_ERROR(DbgPrint("IRCOMM: IrdaSetEventHandler failed for TDI_EVENT_CONNECT : "
  523. "%08lx\n",Status);)
  524. goto CleanUp;
  525. }
  526. Status=STATUS_SUCCESS;
  527. } else {
  528. //
  529. // we are creating an outgoing connection
  530. //
  531. Status=InitiateConnection(
  532. LinkObject->TdiObjects->ConnectionFileObject,
  533. DeviceAddress,
  534. ServiceName
  535. );
  536. if (NT_SUCCESS(Status)) {
  537. KIRQL OldIrql;
  538. KeAcquireSpinLock(&LinkObject->Lock,&OldIrql);
  539. //
  540. // we a connection begining now
  541. //
  542. InterlockedIncrement(&LinkObject->Connection.ReferenceCount);
  543. //
  544. // the connection counts against the link
  545. //
  546. InterlockedIncrement(&LinkObject->ReferenceCount);
  547. LinkObject->Connection.State=LINK_PRE_CONNECT;
  548. KeReleaseSpinLock(&LinkObject->Lock,OldIrql);
  549. ExQueueWorkItem(
  550. &LinkObject->WorkItem,
  551. CriticalWorkQueue
  552. );
  553. } else {
  554. //
  555. // could not create the connection
  556. //
  557. *LinkHandle=NULL;
  558. goto CleanUp;
  559. }
  560. }
  561. return Status;
  562. CleanUp:
  563. if (LinkObject->TdiObjects != NULL) {
  564. RemoveRefTdiObjects(LinkObject->TdiObjects);
  565. LinkObject->TdiObjects=NULL;
  566. }
  567. FREE_POOL(LinkObject);
  568. return Status;
  569. }
  570. VOID
  571. CloseTdiLink(
  572. LINK_HANDLE LinkHandle
  573. )
  574. {
  575. PLINK_OBJECT LinkObject=LinkHandle;
  576. KIRQL OldIrql;
  577. BOOLEAN Release=FALSE;
  578. NTSTATUS Status = STATUS_SUCCESS;
  579. LinkObject->Closing=TRUE;
  580. Status = IrdaSetEventHandler(
  581. LinkObject->TdiObjects->AddressFileObject,
  582. TDI_EVENT_RECEIVE,
  583. NULL,
  584. NULL
  585. );
  586. if (!NT_SUCCESS(Status))
  587. {
  588. D_ERROR(DbgPrint("IRCOMM: IrdaSetEventHandler in CloseTdiLink failed for "
  589. "TDI_EVENT_RECEIVE : %08lx\n",Status);)
  590. }
  591. Status = IrdaSetEventHandler(
  592. LinkObject->TdiObjects->AddressFileObject,
  593. TDI_EVENT_DISCONNECT,
  594. NULL,
  595. NULL
  596. );
  597. if (!NT_SUCCESS(Status))
  598. {
  599. D_ERROR(DbgPrint("IRCOMM: IrdaSetEventHandler in CloseTdiLink failed for "
  600. "TDI_EVENT_DISCONNECT : %08lx\n",Status);)
  601. }
  602. Status = IrdaSetEventHandler(
  603. LinkObject->TdiObjects->AddressFileObject,
  604. TDI_EVENT_CONNECT,
  605. NULL,
  606. NULL
  607. );
  608. if (!NT_SUCCESS(Status))
  609. {
  610. D_ERROR(DbgPrint("IRCOMM: IrdaSetEventHandler in CloseTdiLink failed for "
  611. "TDI_EVENT_CONNECT : %08lx\n",Status);)
  612. }
  613. KeAcquireSpinLock(&LinkObject->Lock,&OldIrql);
  614. switch (LinkObject->Connection.State) {
  615. case LINK_IDLE:
  616. case LINK_DISCONNECTING:
  617. case LINK_ACCEPT_FAILED:
  618. break;
  619. case LINK_CONNECTED:
  620. //
  621. // it is in the connected state, we need to get it cleaned up
  622. //
  623. LinkObject->Connection.State=LINK_DISCONNECTING;
  624. Release=TRUE;
  625. break;
  626. case LINK_PRE_CONNECT:
  627. ASSERT(0);
  628. break;
  629. default:
  630. ASSERT(0);
  631. break;
  632. }
  633. KeReleaseSpinLock(&LinkObject->Lock,OldIrql);
  634. if (Release) {
  635. RemoveReferenceFromConnection(LinkObject);
  636. }
  637. RemoveReferenceOnLink(LinkObject);
  638. KeWaitForSingleObject(
  639. &LinkObject->CloseEvent,
  640. Executive,
  641. KernelMode,
  642. FALSE,
  643. NULL
  644. );
  645. //
  646. // the link should now be inactive
  647. //
  648. LinkObject->Connection.State=LINK_CLOSING;
  649. //
  650. // done with the TdiObjects
  651. //
  652. RemoveRefTdiObjects(LinkObject->TdiObjects);
  653. LinkObject->TdiObjects=NULL;
  654. FREE_POOL(LinkObject);
  655. return;
  656. }
  657. CONNECTION_HANDLE
  658. GetCurrentConnection(
  659. LINK_HANDLE LinkHandle
  660. )
  661. {
  662. PLINK_OBJECT LinkObject=LinkHandle;
  663. CONNECTION_HANDLE ConnectionHandle=NULL;
  664. KIRQL OldIrql;
  665. KeAcquireSpinLock(&LinkObject->Lock,&OldIrql);
  666. if (LinkObject->Connection.State == LINK_CONNECTED) {
  667. InterlockedIncrement(&LinkObject->Connection.ReferenceCount);
  668. ConnectionHandle=LinkHandle;
  669. }
  670. KeReleaseSpinLock(&LinkObject->Lock,OldIrql);
  671. return ConnectionHandle;
  672. }
  673. VOID
  674. ReleaseConnection(
  675. CONNECTION_HANDLE ConnectionHandle
  676. )
  677. {
  678. PLINK_OBJECT LinkObject=ConnectionHandle;
  679. RemoveReferenceFromConnection(LinkObject);
  680. return;
  681. }
  682. PFILE_OBJECT
  683. ConnectionGetFileObject(
  684. CONNECTION_HANDLE ConnectionHandle
  685. )
  686. {
  687. PLINK_OBJECT LinkObject=ConnectionHandle;
  688. PFILE_OBJECT FileObject;
  689. FileObject=LinkObject->TdiObjects->ConnectionFileObject;
  690. ObReferenceObject(FileObject);
  691. return FileObject;
  692. }
  693. VOID
  694. ConnectionReleaseFileObject(
  695. CONNECTION_HANDLE ConnectionHandle,
  696. PFILE_OBJECT FileObject
  697. )
  698. {
  699. PLINK_OBJECT LinkObject=ConnectionHandle;
  700. ObDereferenceObject(FileObject);
  701. return;
  702. }
  703. PIRCOMM_BUFFER
  704. ConnectionGetBuffer(
  705. CONNECTION_HANDLE ConnectionHandle,
  706. BUFFER_TYPE BufferType
  707. )
  708. {
  709. PLINK_OBJECT LinkObject=ConnectionHandle;
  710. switch (BufferType) {
  711. case BUFFER_TYPE_SEND:
  712. return GetBuffer(LinkObject->Connection.SendBufferPool);
  713. case BUFFER_TYPE_CONTROL:
  714. return GetBuffer(LinkObject->Connection.ControlBufferPool);
  715. case BUFFER_TYPE_RECEIVE:
  716. return GetBuffer(LinkObject->Connection.ReceiveBufferPool);
  717. default:
  718. return NULL;
  719. }
  720. return NULL;
  721. }
  722. NTSTATUS
  723. IrdaRestartDeviceControl (
  724. IN PDEVICE_OBJECT DeviceObject,
  725. IN PIRP Irp,
  726. IN PVOID Context
  727. )
  728. {
  729. //
  730. // N.B. This routine can never be demand paged because it can be
  731. // called before any endpoints have been placed on the global
  732. // list--see IrdaAllocateEndpoint() and it's call to
  733. // IrdaGetTransportInfo().
  734. //
  735. //
  736. // If there was an MDL in the IRP, free it and reset the pointer to
  737. // NULL. The IO system can't handle a nonpaged pool MDL being freed
  738. // in an IRP, which is why we do it here.
  739. //
  740. if ( Irp->MdlAddress != NULL ) {
  741. IoFreeMdl( Irp->MdlAddress );
  742. Irp->MdlAddress = NULL;
  743. }
  744. return STATUS_SUCCESS;
  745. } // IrdaRestartDeviceControl
  746. NTSTATUS
  747. IrdaIssueDeviceControl (
  748. IN HANDLE FileHandle OPTIONAL,
  749. IN PFILE_OBJECT FileObject OPTIONAL,
  750. IN PVOID IrpParameters,
  751. IN ULONG IrpParametersLength,
  752. IN PVOID MdlBuffer,
  753. IN ULONG MdlBufferLength,
  754. IN UCHAR MinorFunction
  755. )
  756. /*++
  757. Routine Description:
  758. Issues a device control returst to a TDI provider and waits for the
  759. request to complete.
  760. Note that while FileHandle and FileObject are both marked as optional,
  761. in reality exactly one of these must be specified.
  762. Arguments:
  763. FileHandle - a TDI handle.
  764. FileObject - a pointer to the file object corresponding to a TDI
  765. handle
  766. IrpParameters - information to write to the parameters section of the
  767. stack location of the IRP.
  768. IrpParametersLength - length of the parameter information. Cannot be
  769. greater than 16.
  770. MdlBuffer - if non-NULL, a buffer of nonpaged pool to be mapped
  771. into an MDL and placed in the MdlAddress field of the IRP.
  772. MdlBufferLength - the size of the buffer pointed to by MdlBuffer.
  773. MinorFunction - the minor function code for the request.
  774. Return Value:
  775. NTSTATUS -- Indicates the status of the request.
  776. --*/
  777. {
  778. NTSTATUS status;
  779. PFILE_OBJECT fileObject;
  780. PIRP irp;
  781. PIO_STACK_LOCATION irpSp;
  782. KEVENT event;
  783. IO_STATUS_BLOCK ioStatusBlock;
  784. PDEVICE_OBJECT deviceObject;
  785. PMDL mdl;
  786. PAGED_CODE( );
  787. //
  788. // Initialize the kernel event that will signal I/O completion.
  789. //
  790. KeInitializeEvent( &event, SynchronizationEvent, FALSE );
  791. if( FileHandle != NULL ) {
  792. ASSERT( FileObject == NULL );
  793. //
  794. // Get the file object corresponding to the directory's handle.
  795. // Referencing the file object every time is necessary because the
  796. // IO completion routine dereferences it.
  797. //
  798. status = ObReferenceObjectByHandle(
  799. FileHandle,
  800. 0L, // DesiredAccess
  801. NULL, // ObjectType
  802. KernelMode,
  803. (PVOID *)&fileObject,
  804. NULL
  805. );
  806. if ( !NT_SUCCESS(status) ) {
  807. return status;
  808. }
  809. } else {
  810. ASSERT( FileObject != NULL );
  811. //
  812. // Reference the passed in file object. This is necessary because
  813. // the IO completion routine dereferences it.
  814. //
  815. ObReferenceObject( FileObject );
  816. fileObject = FileObject;
  817. }
  818. //
  819. // Set the file object event to a non-signaled state.
  820. //
  821. (VOID) KeResetEvent( &fileObject->Event );
  822. //
  823. // Attempt to allocate and initialize the I/O Request Packet (IRP)
  824. // for this operation.
  825. //
  826. deviceObject = IoGetRelatedDeviceObject ( fileObject );
  827. irp = IoAllocateIrp( (deviceObject)->StackSize, TRUE );
  828. if ( irp == NULL ) {
  829. ObDereferenceObject( fileObject );
  830. return STATUS_INSUFFICIENT_RESOURCES;
  831. }
  832. //
  833. // Fill in the service independent parameters in the IRP.
  834. //
  835. irp->Flags = (LONG)IRP_SYNCHRONOUS_API;
  836. irp->RequestorMode = KernelMode;
  837. irp->PendingReturned = FALSE;
  838. irp->UserIosb = &ioStatusBlock;
  839. irp->UserEvent = &event;
  840. irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
  841. irp->AssociatedIrp.SystemBuffer = NULL;
  842. irp->UserBuffer = NULL;
  843. irp->Tail.Overlay.Thread = PsGetCurrentThread();
  844. irp->Tail.Overlay.OriginalFileObject = fileObject;
  845. irp->Tail.Overlay.AuxiliaryBuffer = NULL;
  846. /*
  847. DEBUG ioStatusBlock.Status = STATUS_UNSUCCESSFUL;
  848. DEBUG ioStatusBlock.Information = (ULONG)-1;
  849. */
  850. //
  851. // If an MDL buffer was specified, get an MDL, map the buffer,
  852. // and place the MDL pointer in the IRP.
  853. //
  854. if ( MdlBuffer != NULL ) {
  855. mdl = IoAllocateMdl(
  856. MdlBuffer,
  857. MdlBufferLength,
  858. FALSE,
  859. FALSE,
  860. irp
  861. );
  862. if ( mdl == NULL ) {
  863. IoFreeIrp( irp );
  864. ObDereferenceObject( fileObject );
  865. return STATUS_INSUFFICIENT_RESOURCES;
  866. }
  867. MmBuildMdlForNonPagedPool( mdl );
  868. } else {
  869. irp->MdlAddress = NULL;
  870. }
  871. //
  872. // Put the file object pointer in the stack location.
  873. //
  874. irpSp = IoGetNextIrpStackLocation( irp );
  875. irpSp->FileObject = fileObject;
  876. irpSp->DeviceObject = deviceObject;
  877. //
  878. // Fill in the service-dependent parameters for the request.
  879. //
  880. ASSERT( IrpParametersLength <= sizeof(irpSp->Parameters) );
  881. RtlCopyMemory( &irpSp->Parameters, IrpParameters, IrpParametersLength );
  882. irpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  883. irpSp->MinorFunction = MinorFunction;
  884. //
  885. // Set up a completion routine which we'll use to free the MDL
  886. // allocated previously.
  887. //
  888. IoSetCompletionRoutine( irp, IrdaRestartDeviceControl, NULL, TRUE, TRUE, TRUE );
  889. //
  890. // Queue the IRP to the thread and pass it to the driver.
  891. //
  892. IoEnqueueIrp( irp );
  893. status = IoCallDriver( deviceObject, irp );
  894. //
  895. // If necessary, wait for the I/O to complete.
  896. //
  897. if ( status == STATUS_PENDING ) {
  898. KeWaitForSingleObject( (PVOID)&event, UserRequest, KernelMode, FALSE, NULL );
  899. }
  900. //
  901. // If the request was successfully queued, get the final I/O status.
  902. //
  903. if ( NT_SUCCESS(status) ) {
  904. status = ioStatusBlock.Status;
  905. }
  906. return status;
  907. } // IrdaIssueDeviceControl
  908. NTSTATUS
  909. IrdaSetEventHandler (
  910. IN PFILE_OBJECT FileObject,
  911. IN ULONG EventType,
  912. IN PVOID EventHandler,
  913. IN PVOID EventContext
  914. )
  915. /*++
  916. Routine Description:
  917. Sets up a TDI indication handler on a connection or address object
  918. (depending on the file handle). This is done synchronously, which
  919. shouldn't usually be an issue since TDI providers can usually complete
  920. indication handler setups immediately.
  921. Arguments:
  922. FileObject - a pointer to the file object for an open connection or
  923. address object.
  924. EventType - the event for which the indication handler should be
  925. called.
  926. EventHandler - the routine to call when tghe specified event occurs.
  927. EventContext - context which is passed to the indication routine.
  928. Return Value:
  929. NTSTATUS -- Indicates the status of the request.
  930. --*/
  931. {
  932. TDI_REQUEST_KERNEL_SET_EVENT parameters;
  933. PAGED_CODE( );
  934. parameters.EventType = EventType;
  935. parameters.EventHandler = EventHandler;
  936. parameters.EventContext = EventContext;
  937. return IrdaIssueDeviceControl(
  938. NULL,
  939. FileObject,
  940. &parameters,
  941. sizeof(parameters),
  942. NULL,
  943. 0,
  944. TDI_SET_EVENT_HANDLER
  945. );
  946. } // IrdaSetEventHandler
  947. NTSTATUS
  948. ClientEventReceive (
  949. IN PVOID TdiEventContext,
  950. IN CONNECTION_CONTEXT ConnectionContext,
  951. IN ULONG ReceiveFlags,
  952. IN ULONG BytesIndicated,
  953. IN ULONG BytesAvailable,
  954. OUT ULONG *BytesTaken,
  955. IN PVOID Tsdu,
  956. OUT PIRP *IoRequestPacket
  957. )
  958. {
  959. PLINK_OBJECT LinkObject=(PLINK_OBJECT)TdiEventContext;
  960. NTSTATUS Status;
  961. if (!LinkObject->Closing) {
  962. InterlockedIncrement(&LinkObject->ReferenceCount);
  963. Status= (LinkObject->LinkReceiveHandler)(
  964. LinkObject->Context,
  965. ReceiveFlags,
  966. BytesIndicated,
  967. BytesAvailable,
  968. BytesTaken,
  969. Tsdu,
  970. IoRequestPacket
  971. );
  972. RemoveReferenceOnLink(LinkObject);
  973. } else {
  974. Status=STATUS_SUCCESS;
  975. *BytesTaken=BytesAvailable;
  976. }
  977. return Status;
  978. }
  979. NTSTATUS
  980. LinkEventDisconnect(
  981. IN PVOID TdiEventContext,
  982. IN CONNECTION_CONTEXT ConnectionContext,
  983. IN int DisconnectDataLength,
  984. IN PVOID DisconnectData,
  985. IN int DisconnectInformationLength,
  986. IN PVOID DisconnectInformation,
  987. IN ULONG DisconnectFlags
  988. )
  989. {
  990. PLINK_OBJECT LinkObject=(PLINK_OBJECT)TdiEventContext;
  991. KIRQL OldIrql;
  992. BOOLEAN Release=FALSE;
  993. if (!LinkObject->Closing) {
  994. KeAcquireSpinLock(&LinkObject->Lock,&OldIrql);
  995. if (LinkObject->Connection.State == LINK_CONNECTED) {
  996. LinkObject->Connection.State=LINK_DISCONNECTING;
  997. Release=TRUE;
  998. }
  999. KeReleaseSpinLock(&LinkObject->Lock,OldIrql);
  1000. if (Release) {
  1001. RemoveReferenceFromConnection(LinkObject);
  1002. }
  1003. }
  1004. return STATUS_SUCCESS;
  1005. }
  1006. NTSTATUS
  1007. LinkEventConnect(
  1008. IN PVOID TdiEventContext,
  1009. IN int RemoteAddressLength,
  1010. IN PVOID RemoteAddress,
  1011. IN int UserDataLength,
  1012. IN PVOID UserData,
  1013. IN int OptionsLength,
  1014. IN PVOID Options,
  1015. OUT CONNECTION_CONTEXT *ConnectionContext,
  1016. OUT PIRP *AcceptIrp
  1017. )
  1018. {
  1019. PLINK_OBJECT LinkObject=(PLINK_OBJECT)TdiEventContext;
  1020. PIRP Irp;
  1021. PDEVICE_OBJECT DeviceObject=IoGetRelatedDeviceObject ( LinkObject->TdiObjects->ConnectionFileObject);
  1022. KIRQL OldIrql;
  1023. Irp = IoAllocateIrp((CCHAR)(DeviceObject->StackSize), FALSE);
  1024. if ( Irp == NULL ) {
  1025. return STATUS_INSUFFICIENT_RESOURCES;
  1026. }
  1027. KeAcquireSpinLock(&LinkObject->Lock,&OldIrql);
  1028. if ((LinkObject->Connection.State != LINK_IDLE) || LinkObject->Closing) {
  1029. KeReleaseSpinLock(&LinkObject->Lock,OldIrql);
  1030. IoFreeIrp(Irp);
  1031. return STATUS_CONNECTION_REFUSED;
  1032. }
  1033. LinkObject->Connection.State=LINK_ACCEPTED;
  1034. //
  1035. // we now have a connection starting, in the refcount
  1036. //
  1037. InterlockedIncrement(&LinkObject->Connection.ReferenceCount);
  1038. //
  1039. // the connection counts agains the link
  1040. //
  1041. InterlockedIncrement(&LinkObject->ReferenceCount);
  1042. KeReleaseSpinLock(&LinkObject->Lock,OldIrql);
  1043. TdiBuildAccept(
  1044. Irp,
  1045. DeviceObject,
  1046. LinkObject->TdiObjects->ConnectionFileObject,
  1047. IrdaCompleteAcceptIrp,
  1048. LinkObject,
  1049. NULL, // request connection information
  1050. NULL // return connection information
  1051. );
  1052. IoSetNextIrpStackLocation(Irp);
  1053. //
  1054. // Set the return IRP so the transport processes this accept IRP.
  1055. //
  1056. *AcceptIrp = Irp;
  1057. //
  1058. // Set up the connection context as a pointer to the connection block
  1059. // we're going to use for this connect request. This allows the
  1060. // TDI provider to which connection object to use.
  1061. //
  1062. *ConnectionContext = (CONNECTION_CONTEXT) LinkObject;
  1063. return STATUS_MORE_PROCESSING_REQUIRED;
  1064. }
  1065. NTSTATUS
  1066. IrdaCompleteAcceptIrp(
  1067. PDEVICE_OBJECT DeviceObject,
  1068. PIRP Irp,
  1069. PVOID Context
  1070. )
  1071. {
  1072. PLINK_OBJECT LinkObject=(PLINK_OBJECT)Context;
  1073. KIRQL OldIrql;
  1074. KeAcquireSpinLock(&LinkObject->Lock,&OldIrql);
  1075. if (NT_SUCCESS(Irp->IoStatus.Status)) {
  1076. LinkObject->Connection.State=LINK_PRE_CONNECT;
  1077. ExQueueWorkItem(
  1078. &LinkObject->WorkItem,
  1079. CriticalWorkQueue
  1080. );
  1081. } else {
  1082. LinkObject->Connection.State=LINK_ACCEPT_FAILED;
  1083. }
  1084. KeReleaseSpinLock(&LinkObject->Lock,OldIrql);
  1085. if (!NT_SUCCESS(Irp->IoStatus.Status)) {
  1086. //
  1087. // no connection anymore
  1088. //
  1089. RemoveReferenceFromConnection(LinkObject);
  1090. }
  1091. IoFreeIrp(Irp);
  1092. return STATUS_MORE_PROCESSING_REQUIRED;
  1093. }
  1094. NTSTATUS
  1095. GetMaxSendPdu(
  1096. PFILE_OBJECT FileObject,
  1097. PULONG MaxPdu
  1098. )
  1099. {
  1100. PIRP Irp;
  1101. IO_STATUS_BLOCK IoStatus;
  1102. KEVENT Event;
  1103. *MaxPdu=50;
  1104. KeInitializeEvent(
  1105. &Event,
  1106. NotificationEvent,
  1107. FALSE
  1108. );
  1109. Irp=IoBuildDeviceIoControlRequest(
  1110. IOCTL_IRDA_GET_SEND_PDU_LEN,
  1111. IoGetRelatedDeviceObject(FileObject),
  1112. NULL,
  1113. 0,
  1114. MaxPdu,
  1115. sizeof(*MaxPdu),
  1116. FALSE,
  1117. &Event,
  1118. &IoStatus
  1119. );
  1120. if (Irp != NULL) {
  1121. PIO_STACK_LOCATION IrpSp=IoGetNextIrpStackLocation(Irp);
  1122. IrpSp->FileObject=FileObject;
  1123. IoCallDriver(
  1124. IoGetRelatedDeviceObject(FileObject),
  1125. Irp
  1126. );
  1127. KeWaitForSingleObject(
  1128. &Event,
  1129. Executive,
  1130. KernelMode,
  1131. FALSE,
  1132. NULL
  1133. );
  1134. DbgPrint("IRCOMM: maxsendpdu=%d\n",*MaxPdu);
  1135. return IoStatus.Status;
  1136. }
  1137. return STATUS_INSUFFICIENT_RESOURCES;
  1138. }
  1139. VOID
  1140. ConnectionPassiveWorkRoutine(
  1141. PVOID Context
  1142. )
  1143. {
  1144. PLINK_OBJECT LinkObject=Context;
  1145. KIRQL OldIrql;
  1146. ULONG MaxSendPdu=50;
  1147. BOOLEAN Connected;
  1148. KeAcquireSpinLock(&LinkObject->Lock,&OldIrql);
  1149. switch (LinkObject->Connection.State) {
  1150. case LINK_PRE_CONNECT:
  1151. KeReleaseSpinLock(&LinkObject->Lock,OldIrql);
  1152. GetMaxSendPdu(LinkObject->TdiObjects->ConnectionFileObject,&MaxSendPdu);
  1153. LinkObject->Connection.SendBufferPool=CreateBufferPool(
  1154. IoGetRelatedDeviceObject(LinkObject->TdiObjects->ConnectionFileObject)->StackSize,
  1155. MaxSendPdu,
  1156. LinkObject->SendBuffers
  1157. );
  1158. LinkObject->Connection.ControlBufferPool=CreateBufferPool(
  1159. IoGetRelatedDeviceObject(LinkObject->TdiObjects->ConnectionFileObject)->StackSize,
  1160. MaxSendPdu,
  1161. LinkObject->ControlBuffers
  1162. );
  1163. LinkObject->Connection.ReceiveBufferPool=CreateBufferPool(
  1164. IoGetRelatedDeviceObject(LinkObject->TdiObjects->ConnectionFileObject)->StackSize,
  1165. 1,
  1166. LinkObject->ReceiveBuffers
  1167. );
  1168. LinkObject->Connection.State=LINK_CONNECTED;
  1169. Connected=TRUE;
  1170. break;
  1171. case LINK_DISCONNECTING:
  1172. Connected=FALSE;
  1173. KeReleaseSpinLock(&LinkObject->Lock,OldIrql);
  1174. IrdaDisconnect(LinkObject->TdiObjects->ConnectionFileObject);
  1175. if (LinkObject->Connection.SendBufferPool != NULL) {
  1176. FreeBufferPool(LinkObject->Connection.SendBufferPool);
  1177. LinkObject->Connection.SendBufferPool=NULL;
  1178. }
  1179. if (LinkObject->Connection.ControlBufferPool != NULL) {
  1180. FreeBufferPool(LinkObject->Connection.ControlBufferPool);
  1181. LinkObject->Connection.ControlBufferPool=NULL;
  1182. }
  1183. if (LinkObject->Connection.ReceiveBufferPool != NULL) {
  1184. FreeBufferPool(LinkObject->Connection.ReceiveBufferPool);
  1185. LinkObject->Connection.ReceiveBufferPool=NULL;
  1186. }
  1187. LinkObject->Connection.State=LINK_IDLE;
  1188. break;
  1189. case LINK_ACCEPT_FAILED:
  1190. Connected=FALSE;
  1191. LinkObject->Connection.State=LINK_IDLE;
  1192. KeReleaseSpinLock(&LinkObject->Lock,OldIrql);
  1193. break;
  1194. default:
  1195. ASSERT(0);
  1196. Connected=FALSE;
  1197. KeReleaseSpinLock(&LinkObject->Lock,OldIrql);
  1198. break;
  1199. }
  1200. if (!LinkObject->Closing) {
  1201. //
  1202. // tell the client about the state change
  1203. //
  1204. InterlockedIncrement(&LinkObject->ReferenceCount);
  1205. (LinkObject->LinkStateHandler)(
  1206. LinkObject->Context,
  1207. Connected,
  1208. MaxSendPdu
  1209. );
  1210. RemoveReferenceOnLink(LinkObject);
  1211. }
  1212. if (!Connected) {
  1213. //
  1214. // we have completed the disconnection, remove the reference the connection
  1215. // has to the link
  1216. //
  1217. RemoveReferenceOnLink(LinkObject);
  1218. }
  1219. return;
  1220. }
  1221. VOID
  1222. RemoveReferenceFromConnection(
  1223. PLINK_OBJECT LinkObject
  1224. )
  1225. {
  1226. KIRQL OldIrql;
  1227. LONG Count;
  1228. KeAcquireSpinLock(&LinkObject->Lock,&OldIrql);
  1229. Count=InterlockedDecrement(&LinkObject->Connection.ReferenceCount);
  1230. if (Count == 0) {
  1231. ExQueueWorkItem(
  1232. &LinkObject->WorkItem,
  1233. CriticalWorkQueue
  1234. );
  1235. }
  1236. KeReleaseSpinLock(&LinkObject->Lock,OldIrql);
  1237. return;
  1238. }
  1239. TDI_OBJECT_HANDLE
  1240. OpenTdiObjects(
  1241. const CHAR *ServiceName,
  1242. BOOLEAN OutGoingConnection
  1243. )
  1244. {
  1245. PTDI_OBJECTS TdiObject;
  1246. NTSTATUS Status;
  1247. UCHAR AddrBuf[sizeof(TRANSPORT_ADDRESS) + sizeof(TDI_ADDRESS_IRDA)];
  1248. PTRANSPORT_ADDRESS TranAddr = (PTRANSPORT_ADDRESS) AddrBuf;
  1249. PTDI_ADDRESS_IRDA IrdaAddr = (PTDI_ADDRESS_IRDA) TranAddr->Address[0].Address;
  1250. TdiObject=ALLOCATE_NONPAGED_POOL(sizeof(*TdiObject));
  1251. if (TdiObject == NULL) {
  1252. return NULL;
  1253. }
  1254. RtlZeroMemory(TdiObject,sizeof(*TdiObject));
  1255. //
  1256. // start the ref count at one
  1257. //
  1258. TdiObject->ReferenceCount=1;
  1259. #if DBG
  1260. TdiObject->OpenProcess=IoGetCurrentProcess();
  1261. #endif
  1262. KeInitializeEvent(
  1263. &TdiObject->CloseEvent,
  1264. NotificationEvent,
  1265. FALSE
  1266. );
  1267. if (OutGoingConnection) {
  1268. IrdaAddr->irdaServiceName[0] = 0; // tells irda.sys addrObj is a client
  1269. } else {
  1270. strcpy(IrdaAddr->irdaServiceName,ServiceName);
  1271. }
  1272. //
  1273. // open the tdi address and get a handle
  1274. //
  1275. Status=IrdaCreateAddress(
  1276. IrdaAddr,
  1277. &TdiObject->AddressFileHandle
  1278. );
  1279. if (!NT_SUCCESS(Status)) {
  1280. goto CleanUp;
  1281. }
  1282. //
  1283. // get the file object the handle refers to
  1284. //
  1285. Status = ObReferenceObjectByHandle(
  1286. TdiObject->AddressFileHandle,
  1287. 0L, // DesiredAccess
  1288. NULL,
  1289. KernelMode,
  1290. (PVOID *)&TdiObject->AddressFileObject,
  1291. NULL
  1292. );
  1293. if (Status != STATUS_SUCCESS) {
  1294. D_ERROR(DbgPrint("IRCOMM: ObReferenceObjectByHandle Failed %08lx\n",Status);)
  1295. goto CleanUp;
  1296. }
  1297. //
  1298. // create a connection object and associate it with the address
  1299. //
  1300. Status=IrdaCreateConnectionForAddress(
  1301. TdiObject->AddressFileHandle,
  1302. NULL,
  1303. &TdiObject->ConnectionFileObject,
  1304. &TdiObject->ConnectionFileHandle
  1305. );
  1306. if (!NT_SUCCESS(Status)) {
  1307. D_ERROR(DbgPrint("IRCOMM: IrdaCreateConnectionForAddress Failed %08lx\n",Status);)
  1308. goto CleanUp;
  1309. }
  1310. return TdiObject;
  1311. CleanUp:
  1312. CloseTdiObjects(TdiObject);
  1313. return NULL;
  1314. }
  1315. VOID
  1316. AddRefTdiObjects(
  1317. TDI_OBJECT_HANDLE Handle
  1318. )
  1319. {
  1320. PTDI_OBJECTS TdiObject=(PTDI_OBJECTS)Handle;
  1321. ASSERT(TdiObject->ReferenceCount > 0);
  1322. InterlockedIncrement(&TdiObject->ReferenceCount);
  1323. return;
  1324. }
  1325. VOID
  1326. RemoveRefTdiObjects(
  1327. TDI_OBJECT_HANDLE Handle
  1328. )
  1329. {
  1330. PTDI_OBJECTS TdiObject=(PTDI_OBJECTS)Handle;
  1331. LONG NewRefCount;
  1332. NewRefCount=InterlockedDecrement(&TdiObject->ReferenceCount);
  1333. ASSERT(NewRefCount >= 0);
  1334. if (NewRefCount == 0) {
  1335. KeSetEvent(&TdiObject->CloseEvent,IO_NO_INCREMENT,FALSE);
  1336. }
  1337. return;
  1338. }
  1339. PTDI_OBJECTS
  1340. TdiObjectFromHandle(
  1341. TDI_OBJECT_HANDLE Handle
  1342. )
  1343. {
  1344. PTDI_OBJECTS TdiObject=(PTDI_OBJECTS)Handle;
  1345. AddRefTdiObjects(TdiObject);
  1346. return TdiObject;
  1347. }
  1348. VOID
  1349. CloseTdiObjects(
  1350. TDI_OBJECT_HANDLE Handle
  1351. )
  1352. {
  1353. PTDI_OBJECTS TdiObject=(PTDI_OBJECTS)Handle;
  1354. #if DBG
  1355. ASSERT(TdiObject->OpenProcess == IoGetCurrentProcess());
  1356. #endif
  1357. RemoveRefTdiObjects(Handle);
  1358. //
  1359. // when the ref count goes to zero the event will be signaled
  1360. //
  1361. KeWaitForSingleObject(
  1362. &TdiObject->CloseEvent,
  1363. Executive,
  1364. KernelMode,
  1365. FALSE,
  1366. NULL
  1367. );
  1368. if (TdiObject->AddressFileHandle != NULL) {
  1369. ZwClose(TdiObject->AddressFileHandle);
  1370. TdiObject->AddressFileHandle=NULL;
  1371. }
  1372. if (TdiObject->AddressFileObject != NULL) {
  1373. ObDereferenceObject(TdiObject->AddressFileObject);
  1374. TdiObject->AddressFileObject=NULL;
  1375. }
  1376. if (TdiObject->ConnectionFileHandle != NULL) {
  1377. ZwClose(TdiObject->ConnectionFileHandle);
  1378. TdiObject->ConnectionFileHandle=NULL;
  1379. }
  1380. if (TdiObject->ConnectionFileObject != NULL) {
  1381. ObDereferenceObject(TdiObject->ConnectionFileObject);
  1382. TdiObject->ConnectionFileObject=NULL;
  1383. }
  1384. RtlZeroMemory(TdiObject,sizeof(*TdiObject));
  1385. FREE_POOL(TdiObject);
  1386. return;
  1387. }