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.

3101 lines
90 KiB

  1. // Copyright (c) 1997, Microsoft Corporation, all rights reserved
  2. //
  3. // tdix.c
  4. // RAS L2TP WAN mini-port/call-manager driver
  5. // TDI extensions interface
  6. //
  7. // 01/07/97 Steve Cobb
  8. //
  9. // These routines encapsulate L2TP's usage of TDI, with the intent of
  10. // minimalizing the change required to support other TDI transports in the
  11. // future, e.g. Frame Relay.
  12. //
  13. //
  14. // About ALLOCATEIRPS:
  15. //
  16. // This driver is lower level code than typical TDI client drivers. It has
  17. // locked MDL-mapped input buffers readily available and does not need to
  18. // provide any mapping to user mode client requests on completion. This
  19. // allows a performance gain from allocating and deallocating IRPs directly,
  20. // thus avoiding unnecessary setup in TdiBuildInternalDeviceControlIrp and
  21. // unnecessary APC queuing in IoCompleteRequest. Define ALLOCATEIRPs 1 (in
  22. // sources file) to make this optimization, or define it 0 to use the strictly
  23. // TDI-compliant TdiBuildInternalDeviceControlIrp method.
  24. //
  25. //
  26. // About NDISBUFFERISMDL:
  27. //
  28. // Calls to TdiBuildSendDatagram assume the NDIS_BUFFER can be passed in place
  29. // of an MDL which avoids a pointless copy. If this is not the case, an
  30. // explicit MDL buffer would need to be allocated and caller's buffer copied
  31. // to the MDL buffer before sending. Same issue for TdiBuildReceiveDatagram,
  32. // except of course that the copy would be from the MDL buffer to caller's
  33. // buffer after receiving.
  34. //
  35. //
  36. // About ROUTEWITHREF:
  37. //
  38. // Calls the IP_SET_ROUTEWITHREF IOCTLs rather than the TCP_SET_INFORMATION_EX
  39. // IOCTLs to set up the host route. The referenced route IOCTLs prevent PPTP
  40. // and L2TP from walking on each others routes. This setting provided only as
  41. // a hedge against failure of the ROUTEWITHREF IOCTL. Assuming it works it
  42. // should always be preferable.
  43. //
  44. #include "l2tpp.h"
  45. #define IP_PKTINFO 19 // receive packet information
  46. typedef struct in_pktinfo {
  47. ULONG ipi_addr; // destination IPv4 address
  48. UINT ipi_ifindex; // received interface index
  49. } IN_PKTINFO;
  50. // Debug count of errors that should not be happening.
  51. //
  52. ULONG g_ulTdixOpenFailures = 0;
  53. ULONG g_ulTdixSendDatagramFailures = 0;
  54. ULONG g_ulTdixAddHostRouteFailures = 0;
  55. ULONG g_ulTdixDeleteHostRouteFailures = 0;
  56. ULONG g_ulTdixOpenCtrlAddrFailures = 0;
  57. ULONG g_ulTdixOpenPayloadAddrFailures = 0;
  58. ULONG g_ulTdixSetInterfaceFailures = 0;
  59. ULONG g_ulTdixConnectAddrFailures = 0;
  60. ULONG g_ulTdixAddHostRouteSuccesses = 0;
  61. ULONG g_ulTdixDeleteHostRouteSuccesses = 0;
  62. ULONG g_ulTdixOpenCtrlAddrSuccesses = 0;
  63. ULONG g_ulTdixOpenPayloadAddrSuccesses = 0;
  64. ULONG g_ulTdixSetInterfaceSuccesses = 0;
  65. ULONG g_ulTdixConnectAddrSuccesses = 0;
  66. ULONG g_ulNoBestRoute = 0;
  67. NTSTATUS g_statusLastAhrSetRouteFailure = 0;
  68. NTSTATUS g_statusLastAhrTcpQueryInfoExFailure = 0;
  69. NTSTATUS g_statusLastDhrSetRouteFailure = 0;
  70. NTSTATUS g_statusLastDhrTcpQueryInfoExFailure = 0;
  71. #if NDISBUFFERISMDL
  72. #else
  73. #error Additional code to copy NDIS_BUFFER to/from MDL NYI.
  74. #endif
  75. //-----------------------------------------------------------------------------
  76. // Local datatypes
  77. //-----------------------------------------------------------------------------
  78. //-----------------------------------------------------------------------------
  79. // Local prototypes (alphabetically)
  80. //-----------------------------------------------------------------------------
  81. NTSTATUS
  82. TdixConnectAddrInterface(
  83. FILE_OBJECT* pFileObj,
  84. HANDLE hFileHandle,
  85. TDIXROUTE* pTdixRoute
  86. );
  87. VOID
  88. TdixDisableUdpChecksums(
  89. IN FILE_OBJECT* pAddress);
  90. VOID
  91. TdixDoClose(
  92. TDIXCONTEXT* pTdix);
  93. VOID
  94. TdixEnableIpPktInfo(
  95. IN FILE_OBJECT* pAddress);
  96. VOID
  97. TdixExtractAddress(
  98. IN TDIXCONTEXT* pTdix,
  99. OUT TDIXRDGINFO* pRdg,
  100. IN VOID* pTransportAddress,
  101. IN LONG lTransportAddressLen,
  102. IN VOID* Options,
  103. IN LONG OptionsLength);
  104. NTSTATUS
  105. TdixInstallEventHandler(
  106. IN FILE_OBJECT* pAddress,
  107. IN INT nEventType,
  108. IN VOID* pfuncEventHandler,
  109. IN VOID* pEventContext );
  110. NTSTATUS
  111. TdixOpenIpAddress(
  112. IN UNICODE_STRING* puniDevice,
  113. IN TDIXIPADDRESS* pTdixAddr,
  114. OUT HANDLE* phAddress,
  115. OUT FILE_OBJECT** ppFileObject );
  116. NTSTATUS
  117. TdixReceiveDatagramComplete(
  118. IN PDEVICE_OBJECT DeviceObject,
  119. IN PIRP Irp,
  120. IN PVOID Context );
  121. NTSTATUS
  122. TdixReceiveDatagramHandler(
  123. IN PVOID TdiEventContext,
  124. IN LONG SourceAddressLength,
  125. IN PVOID SourceAddress,
  126. IN LONG OptionsLength,
  127. IN PVOID Options,
  128. IN ULONG ReceiveDatagramFlags,
  129. IN ULONG BytesIndicated,
  130. IN ULONG BytesAvailable,
  131. OUT ULONG* BytesTaken,
  132. IN PVOID Tsdu,
  133. OUT PIRP* IoRequestPacket );
  134. TDIXROUTE*
  135. TdixRouteFromIpAddress(
  136. IN TDIXCONTEXT* pTdix,
  137. IN ULONG ulIpAddress);
  138. NTSTATUS
  139. TdixSendComplete(
  140. IN PDEVICE_OBJECT DeviceObject,
  141. IN PIRP Irp,
  142. IN PVOID Context );
  143. NTSTATUS
  144. TdixSendDatagramComplete(
  145. IN PDEVICE_OBJECT DeviceObject,
  146. IN PIRP Irp,
  147. IN PVOID Context );
  148. //-----------------------------------------------------------------------------
  149. // Interface routines
  150. //-----------------------------------------------------------------------------
  151. VOID
  152. TdixInitialize(
  153. IN TDIXMEDIATYPE mediatype,
  154. IN HOSTROUTEEXISTS hre,
  155. IN ULONG ulFlags,
  156. IN PTDIXRECEIVE pReceiveHandler,
  157. IN BUFFERPOOL* pPoolNdisBuffers,
  158. IN OUT TDIXCONTEXT* pTdix )
  159. // Initialize caller's 'pTdix' buffer for future sessions using media type
  160. // 'mediatype', the 'hre' existing host route strategy, and TDIXF_*
  161. // options 'ulFlags'. Caller's receive datagram callback
  162. // 'pReceiveHandler' is called with a buffer allocated from caller's
  163. // buffer pool 'pPoolNdisBuffers'.
  164. //
  165. {
  166. TRACE( TL_N, TM_Tdi, ( "TdixInit" ) );
  167. pTdix->lRef = 0;
  168. pTdix->hAddress = NULL;
  169. pTdix->pAddress = NULL;
  170. pTdix->mediatype = mediatype;
  171. pTdix->hre = hre;
  172. pTdix->ulFlags |= ulFlags;
  173. pTdix->ulFlags = 0;
  174. InitializeListHead( &pTdix->listRoutes );
  175. NdisAllocateSpinLock( &pTdix->lock );
  176. pTdix->pPoolNdisBuffers = pPoolNdisBuffers;
  177. pTdix->pReceiveHandler = pReceiveHandler;
  178. // The 'llistRdg' and 'llistSdg' lookaside lists are initialized at
  179. // TdixOpen.
  180. }
  181. NDIS_STATUS
  182. TdixOpen(
  183. OUT TDIXCONTEXT* pTdix )
  184. // Open the TDI transport address matching the selected media and register
  185. // to receive datagrams at the selected handler. 'PTdix' is the
  186. // previously intialized context.
  187. //
  188. // This call must be made at PASSIVE IRQL.
  189. //
  190. // Returns NDIS_STATUS_SUCCESS if successful, or NDIS_STATUS_FAILURE.
  191. //
  192. {
  193. NTSTATUS status;
  194. OBJECT_ATTRIBUTES oa;
  195. IO_STATUS_BLOCK iosb;
  196. FILE_FULL_EA_INFORMATION* pEa;
  197. ULONG ulEaLength;
  198. TA_IP_ADDRESS* pTaIp;
  199. TDI_ADDRESS_IP* pTdiIp;
  200. CHAR achEa[ 100 ];
  201. UNICODE_STRING uniDevice;
  202. UNICODE_STRING uniProtocolNumber;
  203. WCHAR achRawIpDevice[ sizeof(DD_RAW_IP_DEVICE_NAME) + 10 ];
  204. WCHAR achProtocolNumber[ 10 ];
  205. SHORT sPort;
  206. LONG lRef;
  207. // Open the TDI extensions or notice that it's already been requested
  208. // and/or completed.
  209. //
  210. for (;;)
  211. {
  212. BOOLEAN fPending;
  213. BOOLEAN fDoOpen;
  214. fPending = FALSE;
  215. fDoOpen = FALSE;
  216. NdisAcquireSpinLock( &pTdix->lock );
  217. {
  218. if (ReadFlags( &pTdix->ulFlags) & TDIXF_Pending)
  219. {
  220. fPending = TRUE;
  221. }
  222. else
  223. {
  224. lRef = ++pTdix->lRef;
  225. TRACE( TL_N, TM_Tdi, ( "TdixOpen, refs=%d", lRef ) );
  226. if (lRef == 1)
  227. {
  228. SetFlags( &pTdix->ulFlags, TDIXF_Pending );
  229. fDoOpen = TRUE;
  230. }
  231. }
  232. }
  233. NdisReleaseSpinLock( &pTdix->lock );
  234. if (fDoOpen)
  235. {
  236. // Go on and open the transport address.
  237. //
  238. break;
  239. }
  240. if (!fPending)
  241. {
  242. // It's already open, so report success.
  243. //
  244. return NDIS_STATUS_SUCCESS;
  245. }
  246. // An operation is already in progress. Give it some time to finish
  247. // then check again.
  248. //
  249. TRACE( TL_I, TM_Tdi, ( "NdisMSleep(open)" ) );
  250. NdisMSleep( 100000 );
  251. TRACE( TL_I, TM_Tdi, ( "NdisMSleep(open) done" ) );
  252. }
  253. do
  254. {
  255. // Set up parameters needed to open the transport address. First, the
  256. // object attributes.
  257. //
  258. if (pTdix->mediatype == TMT_Udp)
  259. {
  260. TDIXIPADDRESS TdixIpAddress;
  261. TRACE( TL_V, TM_Tdi, ( "UDP" ) );
  262. // Build the UDP device name as a counted string.
  263. //
  264. uniDevice.Buffer = DD_UDP_DEVICE_NAME;
  265. uniDevice.Length = sizeof(DD_UDP_DEVICE_NAME) - sizeof(WCHAR);
  266. NdisZeroMemory(&TdixIpAddress, sizeof(TdixIpAddress));
  267. TdixIpAddress.sUdpPort = (SHORT)( htons( L2TP_UdpPort ));
  268. status = TdixOpenIpAddress(
  269. &uniDevice,
  270. &TdixIpAddress,
  271. &pTdix->hAddress,
  272. &pTdix->pAddress );
  273. if (status != STATUS_SUCCESS)
  274. {
  275. break;
  276. }
  277. TdixEnableIpPktInfo(pTdix->pAddress);
  278. }
  279. else
  280. {
  281. TDIXIPADDRESS TdixIpAddress;
  282. ASSERT( pTdix->mediatype == TMT_RawIp );
  283. TRACE( TL_A, TM_Tdi, ( "Raw IP" ) );
  284. // Build the raw IP device name as a counted string. The device
  285. // name is followed by a path separator then the protocol number
  286. // of interest.
  287. //
  288. uniDevice.Buffer = achRawIpDevice;
  289. uniDevice.Length = 0;
  290. uniDevice.MaximumLength = sizeof(achRawIpDevice);
  291. RtlAppendUnicodeToString( &uniDevice, DD_RAW_IP_DEVICE_NAME );
  292. uniDevice.Buffer[ uniDevice.Length / sizeof(WCHAR) ]
  293. = OBJ_NAME_PATH_SEPARATOR;
  294. uniDevice.Length += sizeof(WCHAR);
  295. uniProtocolNumber.Buffer = achProtocolNumber;
  296. uniProtocolNumber.MaximumLength = sizeof(achProtocolNumber);
  297. RtlIntegerToUnicodeString(
  298. (ULONG )L2TP_IpProtocol, 10, &uniProtocolNumber );
  299. RtlAppendUnicodeStringToString( &uniDevice, &uniProtocolNumber );
  300. ASSERT( uniDevice.Length < sizeof(achRawIpDevice) );
  301. NdisZeroMemory(&TdixIpAddress, sizeof(TdixIpAddress));
  302. status = TdixOpenIpAddress(
  303. &uniDevice,
  304. &TdixIpAddress,
  305. &pTdix->hAddress,
  306. &pTdix->pAddress );
  307. if (status != STATUS_SUCCESS)
  308. {
  309. break;
  310. }
  311. }
  312. // Initialize the lookaside lists of read/send-datagram contexts.
  313. //
  314. NdisInitializeNPagedLookasideList(
  315. &pTdix->llistRdg,
  316. NULL,
  317. NULL,
  318. 0,
  319. sizeof(TDIXRDGINFO),
  320. MTAG_TDIXRDG,
  321. 10 );
  322. NdisInitializeNPagedLookasideList(
  323. &pTdix->llistSdg,
  324. NULL,
  325. NULL,
  326. 0,
  327. sizeof(TDIXSDGINFO),
  328. MTAG_TDIXSDG,
  329. 10 );
  330. // Install our receive datagram handler. Caller's 'pReceiveHandler' will
  331. // be called by our handler when a datagram arrives and TDI business is
  332. // out of the way.
  333. //
  334. status =
  335. TdixInstallEventHandler(
  336. pTdix->pAddress,
  337. TDI_EVENT_RECEIVE_DATAGRAM,
  338. TdixReceiveDatagramHandler,
  339. pTdix );
  340. #if ROUTEWITHREF
  341. {
  342. TDIXIPADDRESS TdixIpAddress;
  343. // Open the IP stack address which is needed in both UDP and raw IP
  344. // mode for referenced route management.
  345. //
  346. NdisZeroMemory(&TdixIpAddress, sizeof(TdixIpAddress));
  347. uniDevice.Buffer = DD_IP_DEVICE_NAME;
  348. uniDevice.Length = sizeof(DD_IP_DEVICE_NAME) - sizeof(WCHAR);
  349. status = TdixOpenIpAddress(
  350. &uniDevice,
  351. &TdixIpAddress,
  352. &pTdix->hIpStackAddress,
  353. &pTdix->pIpStackAddress );
  354. if (status != STATUS_SUCCESS)
  355. {
  356. break;
  357. }
  358. }
  359. #endif
  360. }
  361. while (FALSE);
  362. // Report results after marking the operation complete.
  363. //
  364. {
  365. BOOLEAN fDoClose;
  366. fDoClose = FALSE;
  367. NdisAcquireSpinLock( &pTdix->lock );
  368. {
  369. if (status == STATUS_SUCCESS)
  370. {
  371. ClearFlags( &pTdix->ulFlags, TDIXF_Pending );
  372. }
  373. else
  374. {
  375. ++g_ulTdixOpenFailures;
  376. ASSERT( pTdix->lRef == 1)
  377. pTdix->lRef = 0;
  378. fDoClose = TRUE;
  379. }
  380. }
  381. NdisReleaseSpinLock( &pTdix->lock );
  382. if (status != STATUS_SUCCESS)
  383. {
  384. TdixDoClose( pTdix );
  385. }
  386. }
  387. TRACE( TL_N, TM_Tdi, ( "TdixOpen=$%08x", status ) );
  388. return
  389. (status == STATUS_SUCCESS)
  390. ? NDIS_STATUS_SUCCESS
  391. : NDIS_STATUS_FAILURE;
  392. }
  393. VOID
  394. TdixReference(
  395. IN TDIXCONTEXT* pTdix )
  396. // Increments the TDI extension reference count, like TdixOpen, except
  397. // this routine may be called at DISPATCH IRQL.
  398. //
  399. // This call must only be made if it is known that the TDI context is
  400. // already fully open.
  401. //
  402. {
  403. NdisAcquireSpinLock( &pTdix->lock );
  404. {
  405. ASSERT( pTdix->lRef > 0 );
  406. ++pTdix->lRef;
  407. }
  408. NdisReleaseSpinLock( &pTdix->lock );
  409. }
  410. VOID
  411. TdixClose(
  412. IN TDIXCONTEXT* pTdix )
  413. // Undo TdixOpen actions for transport context 'pTdix'.
  414. //
  415. // This call must be made at PASSIVE IRQL.
  416. //
  417. {
  418. for (;;)
  419. {
  420. LONG lRef;
  421. BOOLEAN fPending;
  422. BOOLEAN fDoClose;
  423. fPending = FALSE;
  424. fDoClose = FALSE;
  425. NdisAcquireSpinLock( &pTdix->lock );
  426. {
  427. if (ReadFlags( &pTdix->ulFlags ) & TDIXF_Pending)
  428. {
  429. fPending = TRUE;
  430. }
  431. else
  432. {
  433. lRef = --pTdix->lRef;
  434. ASSERT( lRef >= 0 );
  435. TRACE( TL_N, TM_Tdi, ( "TdixClose, refs=%d", lRef ) );
  436. if (lRef == 0)
  437. {
  438. SetFlags( &pTdix->ulFlags, TDIXF_Pending );
  439. fDoClose = TRUE;
  440. }
  441. }
  442. }
  443. NdisReleaseSpinLock( &pTdix->lock );
  444. if (fDoClose)
  445. {
  446. // Go on and close the transport address.
  447. //
  448. break;
  449. }
  450. if (!fPending)
  451. {
  452. // It's still got references, so just return;
  453. //
  454. return;
  455. }
  456. // An operation is already in progress. Give it some time to finish
  457. // then check again.
  458. //
  459. TRACE( TL_I, TM_Tdi, ( "NdisMSleep(close)" ) );
  460. NdisMSleep( 100000 );
  461. TRACE( TL_I, TM_Tdi, ( "NdisMSleep(close) done" ) );
  462. }
  463. ASSERT( IsListEmpty( &pTdix->listRoutes ) );
  464. TdixDoClose( pTdix );
  465. }
  466. NDIS_STATUS
  467. TdixSend(
  468. IN TDIXCONTEXT* pTdix,
  469. IN FILE_OBJECT* pFileObj,
  470. IN PTDIXSENDCOMPLETE pSendCompleteHandler,
  471. IN VOID* pContext1,
  472. IN VOID* pContext2,
  473. IN VOID* pAddress,
  474. IN CHAR* pBuffer,
  475. IN ULONG ulBufferLength,
  476. OUT IRP** ppIrp )
  477. // Send a datagram buffer 'pBuffer', 'ulBufferLength' bytes long, to
  478. // remote address 'pAddress'. The buffer must be from a BUFFERPOOL of
  479. // NDIS_BUFFERs. 'PTdix' is the transport context.
  480. // 'PSendDatagramCompleteHander' is caller's completion handler which is
  481. // passed 'pContext1' and 'pContext2'. If 'ppIrp' is non-NULL '*ppIrp' is
  482. // set to the address of the posted IRP, this for debugging purposes.
  483. //
  484. // This call must be made at PASSIVE IRQL.
  485. //
  486. // Returns NDIS_STATUS_SUCCESS if successful, or NDIS_STATUS_FAILURE.
  487. //
  488. {
  489. NDIS_STATUS status;
  490. NTSTATUS iostatus;
  491. TDIXSDGINFO* pSdg;
  492. SHORT sPort;
  493. PIRP pIrp;
  494. TDI_ADDRESS_IP* pTdiIp;
  495. DEVICE_OBJECT* DeviceObj;
  496. TRACE( TL_N, TM_Tdi, ( "TdixSend(dst=%d.%d.%d.%d/%d,len=%d)",
  497. IPADDRTRACE( ((TDIXIPADDRESS* )pAddress)->ulIpAddress ),
  498. (ULONG )(ntohs( ((TDIXIPADDRESS* )pAddress)->sUdpPort )),
  499. ulBufferLength ) );
  500. ASSERT(pFileObj != NULL);
  501. do
  502. {
  503. // Allocate a context for this send-datagram from our lookaside list.
  504. //
  505. pSdg = ALLOC_TDIXSDGINFO( pTdix );
  506. if (pSdg)
  507. {
  508. // Fill in the send-datagram context.
  509. //
  510. pSdg->pTdix = pTdix;
  511. pSdg->pSendCompleteHandler = pSendCompleteHandler;
  512. pSdg->pContext1 = pContext1;
  513. pSdg->pContext2 = pContext2;
  514. pSdg->pBuffer = pBuffer;
  515. }
  516. else
  517. {
  518. ASSERT( !"Alloc SDG?" );
  519. status = NDIS_STATUS_RESOURCES;
  520. break;
  521. }
  522. #if 0
  523. // Put the destination IP address in the "connection" structure as TDI
  524. // expects. The "connection" is part of our context as it must be
  525. // available to TDI until the request completes.
  526. //
  527. pSdg->taip.TAAddressCount = 1;
  528. pSdg->taip.Address[ 0 ].AddressLength = TDI_ADDRESS_LENGTH_IP;
  529. pSdg->taip.Address[ 0 ].AddressType = TDI_ADDRESS_TYPE_IP;
  530. pTdiIp = &pSdg->taip.Address[ 0 ].Address[ 0 ];
  531. sPort = ((TDIXIPADDRESS* )pAddress)->sUdpPort;
  532. if (sPort == 0 && pTdix->mediatype == TMT_Udp)
  533. {
  534. sPort = (SHORT )(htons( L2TP_UdpPort ));
  535. }
  536. pTdiIp->sin_port = sPort;
  537. pTdiIp->in_addr = ((TDIXIPADDRESS* )pAddress)->ulIpAddress;
  538. NdisZeroMemory( pTdiIp->sin_zero, sizeof(pTdiIp->sin_zero) );
  539. pSdg->tdiconninfo.UserDataLength = 0;
  540. pSdg->tdiconninfo.UserData = NULL;
  541. pSdg->tdiconninfo.OptionsLength = 0;
  542. pSdg->tdiconninfo.Options = NULL;
  543. pSdg->tdiconninfo.RemoteAddressLength = sizeof(pSdg->taip);
  544. pSdg->tdiconninfo.RemoteAddress = &pSdg->taip;
  545. #endif
  546. DeviceObj = pFileObj->DeviceObject;
  547. #if ALLOCATEIRPS
  548. // Allocate the IRP directly.
  549. //
  550. pIrp = IoAllocateIrp(DeviceObj->StackSize, FALSE );
  551. #else
  552. // Allocate a "send datagram" IRP with base initialization.
  553. //
  554. pIrp =
  555. TdiBuildInternalDeviceControlIrp(
  556. TDI_SEND,
  557. DeviceObj,
  558. FileObj,
  559. NULL,
  560. NULL );
  561. #endif
  562. if (!pIrp)
  563. {
  564. TRACE( TL_A, TM_Tdi, ( "Alloc IRP?" ) );
  565. status = NDIS_STATUS_RESOURCES;
  566. break;
  567. }
  568. // Complete the "send datagram" IRP initialization.
  569. //
  570. TdiBuildSend(
  571. pIrp,
  572. DeviceObj,
  573. pFileObj,
  574. TdixSendComplete,
  575. pSdg,
  576. NdisBufferFromBuffer( pBuffer ),
  577. 0,
  578. ulBufferLength);
  579. if (ppIrp)
  580. {
  581. *ppIrp = pIrp;
  582. }
  583. // Tell the I/O manager to pass our IRP to the transport for
  584. // processing.
  585. //
  586. iostatus = IoCallDriver( DeviceObj, pIrp );
  587. ASSERT( iostatus == STATUS_PENDING );
  588. status = NDIS_STATUS_SUCCESS;
  589. }
  590. while (FALSE);
  591. if (status != NDIS_STATUS_SUCCESS)
  592. {
  593. // Pull a half Jameel, i.e. convert a synchronous failure to an
  594. // asynchronous failure from client's perspective. However, clean up
  595. // context here.
  596. //
  597. ++g_ulTdixSendDatagramFailures;
  598. if (pSdg)
  599. {
  600. FREE_TDIXSDGINFO( pTdix, pSdg );
  601. }
  602. pSendCompleteHandler( pTdix, pContext1, pContext2, pBuffer );
  603. }
  604. return NDIS_STATUS_PENDING;
  605. }
  606. NDIS_STATUS
  607. TdixSendDatagram(
  608. IN TDIXCONTEXT* pTdix,
  609. IN FILE_OBJECT* FileObj,
  610. IN PTDIXSENDCOMPLETE pSendCompleteHandler,
  611. IN VOID* pContext1,
  612. IN VOID* pContext2,
  613. IN VOID* pAddress,
  614. IN CHAR* pBuffer,
  615. IN ULONG ulBufferLength,
  616. OUT IRP** ppIrp )
  617. // Send a datagram buffer 'pBuffer', 'ulBufferLength' bytes long, to
  618. // remote address 'pAddress'. The buffer must be from a BUFFERPOOL of
  619. // NDIS_BUFFERs. 'PTdix' is the transport context.
  620. // 'PSendDatagramCompleteHander' is caller's completion handler which is
  621. // passed 'pContext1' and 'pContext2'. If 'ppIrp' is non-NULL '*ppIrp' is
  622. // set to the address of the posted IRP, this for debugging purposes.
  623. //
  624. // This call must be made at PASSIVE IRQL.
  625. //
  626. // Returns NDIS_STATUS_SUCCESS if successful, or NDIS_STATUS_FAILURE.
  627. //
  628. {
  629. NDIS_STATUS status;
  630. NTSTATUS iostatus;
  631. TDIXSDGINFO* pSdg;
  632. SHORT sPort;
  633. PIRP pIrp;
  634. TDI_ADDRESS_IP* pTdiIp;
  635. TRACE( TL_N, TM_Tdi, ( "TdixSendDg(dst=%d.%d.%d.%d/%d,len=%d)",
  636. IPADDRTRACE( ((TDIXIPADDRESS* )pAddress)->ulIpAddress ),
  637. (ULONG )(ntohs( ((TDIXIPADDRESS* )pAddress)->sUdpPort )),
  638. ulBufferLength ) );
  639. // Not used in this function!
  640. //
  641. FileObj;
  642. do
  643. {
  644. // Allocate a context for this send-datagram from our lookaside list.
  645. //
  646. pSdg = ALLOC_TDIXSDGINFO( pTdix );
  647. if (pSdg)
  648. {
  649. // Fill in the send-datagram context.
  650. //
  651. pSdg->pTdix = pTdix;
  652. pSdg->pSendCompleteHandler = pSendCompleteHandler;
  653. pSdg->pContext1 = pContext1;
  654. pSdg->pContext2 = pContext2;
  655. pSdg->pBuffer = pBuffer;
  656. }
  657. else
  658. {
  659. ASSERT( !"Alloc SDG?" );
  660. status = NDIS_STATUS_RESOURCES;
  661. break;
  662. }
  663. // Put the destination IP address in the "connection" structure as TDI
  664. // expects. The "connection" is part of our context as it must be
  665. // available to TDI until the request completes.
  666. //
  667. pSdg->taip.TAAddressCount = 1;
  668. pSdg->taip.Address[ 0 ].AddressLength = TDI_ADDRESS_LENGTH_IP;
  669. pSdg->taip.Address[ 0 ].AddressType = TDI_ADDRESS_TYPE_IP;
  670. pTdiIp = &pSdg->taip.Address[ 0 ].Address[ 0 ];
  671. sPort = ((TDIXIPADDRESS* )pAddress)->sUdpPort;
  672. if (sPort == 0 && pTdix->mediatype == TMT_Udp)
  673. {
  674. sPort = (SHORT )(htons( L2TP_UdpPort ));
  675. }
  676. pTdiIp->sin_port = sPort;
  677. pTdiIp->in_addr = ((TDIXIPADDRESS* )pAddress)->ulIpAddress;
  678. NdisZeroMemory( pTdiIp->sin_zero, sizeof(pTdiIp->sin_zero) );
  679. pSdg->tdiconninfo.UserDataLength = 0;
  680. pSdg->tdiconninfo.UserData = NULL;
  681. pSdg->tdiconninfo.OptionsLength = 0;
  682. pSdg->tdiconninfo.Options = NULL;
  683. pSdg->tdiconninfo.RemoteAddressLength = sizeof(pSdg->taip);
  684. pSdg->tdiconninfo.RemoteAddress = &pSdg->taip;
  685. #if ALLOCATEIRPS
  686. // Allocate the IRP directly.
  687. //
  688. pIrp = IoAllocateIrp(
  689. pTdix->pAddress->DeviceObject->StackSize, FALSE );
  690. #else
  691. // Allocate a "send datagram" IRP with base initialization.
  692. //
  693. pIrp =
  694. TdiBuildInternalDeviceControlIrp(
  695. TDI_SEND_DATAGRAM,
  696. pTdix->pAddress->DeviceObject,
  697. pTdix->pAddress,
  698. NULL,
  699. NULL );
  700. #endif
  701. if (!pIrp)
  702. {
  703. TRACE( TL_A, TM_Tdi, ( "Alloc IRP?" ) );
  704. status = NDIS_STATUS_RESOURCES;
  705. break;
  706. }
  707. // Complete the "send datagram" IRP initialization.
  708. //
  709. TdiBuildSendDatagram(
  710. pIrp,
  711. pTdix->pAddress->DeviceObject,
  712. pTdix->pAddress,
  713. TdixSendDatagramComplete,
  714. pSdg,
  715. NdisBufferFromBuffer( pBuffer ),
  716. ulBufferLength,
  717. &pSdg->tdiconninfo );
  718. if (ppIrp)
  719. {
  720. *ppIrp = pIrp;
  721. }
  722. // Tell the I/O manager to pass our IRP to the transport for
  723. // processing.
  724. //
  725. iostatus = IoCallDriver( pTdix->pAddress->DeviceObject, pIrp );
  726. ASSERT( iostatus == STATUS_PENDING );
  727. status = NDIS_STATUS_SUCCESS;
  728. }
  729. while (FALSE);
  730. if (status != NDIS_STATUS_SUCCESS)
  731. {
  732. // Pull a half Jameel, i.e. convert a synchronous failure to an
  733. // asynchronous failure from client's perspective. However, clean up
  734. // context here.
  735. //
  736. ++g_ulTdixSendDatagramFailures;
  737. if (pSdg)
  738. {
  739. FREE_TDIXSDGINFO( pTdix, pSdg );
  740. }
  741. pSendCompleteHandler( pTdix, pContext1, pContext2, pBuffer );
  742. }
  743. return NDIS_STATUS_PENDING;
  744. }
  745. VOID
  746. TdixDestroyConnection(
  747. TDIXUDPCONNECTCONTEXT *pUdpContext)
  748. {
  749. if (pUdpContext->fUsePayloadAddr) {
  750. ASSERT(pUdpContext->hPayloadAddr != NULL);
  751. ObDereferenceObject( pUdpContext->pPayloadAddr );
  752. // Close the payload address object
  753. //
  754. ZwClose(pUdpContext->hPayloadAddr);
  755. pUdpContext->hPayloadAddr = NULL;
  756. pUdpContext->fUsePayloadAddr = FALSE;
  757. }
  758. if (pUdpContext->hCtrlAddr != NULL) {
  759. // Close the Ctrl address object
  760. //
  761. ObDereferenceObject( pUdpContext->pCtrlAddr );
  762. ZwClose (pUdpContext->hCtrlAddr);
  763. pUdpContext->hCtrlAddr = NULL;
  764. }
  765. }
  766. NDIS_STATUS
  767. TdixSetupConnection(
  768. IN TDIXCONTEXT* pTdix,
  769. IN ULONG ulIpAddress,
  770. IN SHORT sPort,
  771. IN TDIXROUTE *pTdixRoute,
  772. IN TDIXUDPCONNECTCONTEXT* pUdpContext)
  773. {
  774. NDIS_STATUS status = STATUS_SUCCESS;
  775. ASSERT(pUdpContext != NULL);
  776. if (pTdix->mediatype == TMT_Udp)
  777. {
  778. do {
  779. UNICODE_STRING uniDevice;
  780. UNICODE_STRING uniProtocolNumber;
  781. TDIXIPADDRESS TdixIpAddress;
  782. // Create an address object that we can send across. If we have udp xsums
  783. // disabled we will need to create two address objects, one for control
  784. // and one for payload. This allows payload specific features to be
  785. // implemented.
  786. //
  787. uniDevice.Buffer = DD_UDP_DEVICE_NAME;
  788. uniDevice.Length = sizeof(DD_UDP_DEVICE_NAME) - sizeof(WCHAR);
  789. NdisZeroMemory(&TdixIpAddress, sizeof(TdixIpAddress));
  790. if(sPort != 0)
  791. {
  792. pTdixRoute->sPort = sPort;
  793. }
  794. else
  795. {
  796. pTdixRoute->sPort = (SHORT)(htons(L2TP_UdpPort));
  797. }
  798. TdixIpAddress.sUdpPort = (SHORT)(htons(L2TP_UdpPort));
  799. TRACE( TL_A, TM_Tdi, ( "sPort for $%08x set to %d",
  800. ulIpAddress, (UINT) ntohs(pTdixRoute->sPort ) ));
  801. // Build the UDP device name as a counted string.
  802. //
  803. status = TdixOpenIpAddress(&uniDevice,
  804. &TdixIpAddress,
  805. &pUdpContext->hCtrlAddr,
  806. &pUdpContext->pCtrlAddr );
  807. if (status != STATUS_SUCCESS)
  808. {
  809. TRACE( TL_A, TM_Tdi, ( "AHR OpenCtrlAddr=%x?", status ) );
  810. break;
  811. }
  812. //
  813. // Associate a particular "send" IP interface index with the address
  814. // object, so that if that interface disappears traffic will not be
  815. // "re-routed" often back into the tunnel producing disastrous
  816. // looping.
  817. //
  818. status = TdixConnectAddrInterface(pUdpContext->pCtrlAddr,
  819. pUdpContext->hCtrlAddr,
  820. pTdixRoute);
  821. if (status != STATUS_SUCCESS)
  822. {
  823. TRACE( TL_A, TM_Tdi, ( "AHR ConnectCtrlAddr=%x?", status ) );
  824. break;
  825. }
  826. // If udp xsums are disabled we need to create another address object.
  827. // We will set this object to disable udp xsums and then use it to
  828. // send payload data.
  829. //
  830. // If udp xsums are enabled we can use the same address object for
  831. // payloads that we use for contrl frames.
  832. //
  833. if (pTdix->ulFlags & TDIXF_DisableUdpXsums)
  834. {
  835. TDIXIPADDRESS TdixIpAddress;
  836. NdisZeroMemory(&TdixIpAddress, sizeof(TdixIpAddress));
  837. TdixIpAddress.sUdpPort = (SHORT)(htons(L2TP_UdpPort));
  838. // Open the address object
  839. //
  840. status = TdixOpenIpAddress(&uniDevice,
  841. &TdixIpAddress,
  842. &pUdpContext->hPayloadAddr,
  843. &pUdpContext->pPayloadAddr );
  844. if (status != STATUS_SUCCESS)
  845. {
  846. TRACE( TL_A, TM_Tdi, ( "AHR OpenPayloadAddr=%x?", status ) );
  847. pUdpContext->hPayloadAddr = NULL;
  848. break;
  849. }
  850. pUdpContext->fUsePayloadAddr = TRUE;
  851. TdixDisableUdpChecksums( pUdpContext->pPayloadAddr );
  852. // Associate a particular "send" IP interface index with the address
  853. // object, so that if that interface disappears traffic will not be
  854. // "re-routed" often back into the tunnel producing disastrous
  855. // looping.
  856. //
  857. status = TdixConnectAddrInterface(pUdpContext->pPayloadAddr,
  858. pUdpContext->hPayloadAddr,
  859. pTdixRoute );
  860. if (status != STATUS_SUCCESS)
  861. {
  862. TRACE( TL_A, TM_Tdi, ( "AHR ConnectPayloadAddr=%x?", status ) );
  863. break;
  864. }
  865. }
  866. else
  867. {
  868. pUdpContext->hPayloadAddr = pUdpContext->hCtrlAddr;
  869. pUdpContext->pPayloadAddr = pUdpContext->pCtrlAddr;
  870. TRACE( TL_I, TM_Tdi, ( "AHR Ctrl==Payload") );
  871. }
  872. } while ( FALSE );
  873. }
  874. return status;
  875. }
  876. VOID*
  877. TdixAddHostRoute(
  878. IN TDIXCONTEXT* pTdix,
  879. IN ULONG ulIpAddress,
  880. IN SHORT sPort)
  881. // Adds a host route for the remote peer's network byte-ordered IP address
  882. // 'ulIpAddress', i.e. routes packets directed to the L2TP peer to the LAN
  883. // card rather than back into the tunnel where it would loop infinitely.
  884. // 'PTdix' is the is caller's TDI extension context.
  885. //
  886. // Returns true if the route was added, false otherwise.
  887. //
  888. // Note: This routine borrows heavily from PPTP.
  889. //
  890. {
  891. TCP_REQUEST_QUERY_INFORMATION_EX QueryBuf;
  892. TCP_REQUEST_SET_INFORMATION_EX* pSetBuf;
  893. VOID* pBuffer2;
  894. PIO_STACK_LOCATION pIrpSp;
  895. PDEVICE_OBJECT pDeviceObject;
  896. PDEVICE_OBJECT pIpDeviceObject;
  897. NTSTATUS status = STATUS_SUCCESS;
  898. PIRP pIrp;
  899. IO_STATUS_BLOCK iosb;
  900. IPRouteEntry* pBuffer;
  901. IPRouteEntry* pRouteEntry;
  902. IPRouteEntry* pNewRouteEntry;
  903. IPRouteEntry* pBestRoute;
  904. ULONG ulRouteCount;
  905. ULONG ulSize;
  906. ULONG i;
  907. ULONG ulBestMask;
  908. ULONG ulBestMetric;
  909. TDIXROUTE* pTdixRoute;
  910. BOOLEAN fNewRoute;
  911. BOOLEAN fPending;
  912. BOOLEAN fOpenPending;
  913. BOOLEAN fUsedNonL2tpRoute;
  914. LONG lRef;
  915. KEVENT event;
  916. if (ulIpAddress == 0)
  917. {
  918. TRACE( TL_A, TM_Tdi, ( "IP == 0?" ) );
  919. return ((VOID*)NULL);
  920. }
  921. TRACE( TL_N, TM_Tdi,
  922. ( "TdixAddHostRoute(ip=%d.%d.%d.%d)", IPADDRTRACE( ulIpAddress ) ) );
  923. // Host routes are referenced since more than one tunnel to the same peer
  924. // (allowed by L2TP) shares the same system route. See if this is just a
  925. // reference or the actual add of the system host route.
  926. //
  927. for (;;)
  928. {
  929. fPending = FALSE;
  930. fOpenPending = FALSE;
  931. pTdixRoute = NULL;
  932. fNewRoute = FALSE;
  933. NdisAcquireSpinLock( &pTdix->lock );
  934. do
  935. {
  936. if (pTdix->lRef <= 0)
  937. {
  938. // TDIX is closed or closing, so the add route fails.
  939. //
  940. break;
  941. }
  942. if (ReadFlags( &pTdix->ulFlags ) & TDIXF_Pending)
  943. {
  944. // A TdixOpen is pending. Wait for it to finish before
  945. // adding the route.
  946. //
  947. fOpenPending = TRUE;
  948. break;
  949. }
  950. pTdixRoute = TdixRouteFromIpAddress( pTdix, ulIpAddress );
  951. if (pTdixRoute)
  952. {
  953. // Found an existing route context.
  954. //
  955. fPending = pTdixRoute->fPending;
  956. if (!fPending)
  957. {
  958. // No other operation is pending on the route context.
  959. // Take a reference.
  960. //
  961. ++pTdixRoute->lRef;
  962. }
  963. break;
  964. }
  965. // No existing route context. Create and link a new one.
  966. //
  967. pTdixRoute = ALLOC_TDIXROUTE( pTdix );
  968. if (pTdixRoute)
  969. {
  970. NdisZeroMemory(pTdixRoute, sizeof(TDIXROUTE));
  971. pTdixRoute->ulIpAddress = ulIpAddress;
  972. pTdixRoute->lRef = 1;
  973. pTdixRoute->fPending = TRUE;
  974. pTdixRoute->fUsedNonL2tpRoute = FALSE;
  975. InsertTailList(
  976. &pTdix->listRoutes, &pTdixRoute->linkRoutes );
  977. lRef = ++pTdix->lRef;
  978. TRACE( TL_N, TM_Tdi, ( "TdixAHR, refs=%d", lRef ) );
  979. fPending = pTdixRoute->fPending;
  980. fNewRoute = TRUE;
  981. }
  982. }
  983. while (FALSE);
  984. NdisReleaseSpinLock( &pTdix->lock );
  985. if (!fOpenPending)
  986. {
  987. if (!pTdixRoute)
  988. {
  989. // TDIX is closed or we couldn't find an existing route
  990. // context or create a new one. Report failure.
  991. //
  992. return ((VOID*)NULL);
  993. }
  994. if (fNewRoute)
  995. {
  996. // Created a new route context so go on to make the IOCTL
  997. // calls to add the associated system host route.
  998. //
  999. break;
  1000. }
  1001. if (!fPending)
  1002. {
  1003. // Took a reference on an existing route context. Report
  1004. // success.
  1005. //
  1006. return (pTdixRoute);
  1007. }
  1008. }
  1009. // An operation is already pending. Give it some time to finish then
  1010. // check again.
  1011. //
  1012. TRACE( TL_I, TM_Tdi, ( "NdisMSleep(add)" ) );
  1013. NdisMSleep( 100000 );
  1014. TRACE( TL_I, TM_Tdi, ( "NdisMSleep(add) done" ) );
  1015. }
  1016. // Do the IOCTLs to add the host route.
  1017. //
  1018. pBuffer = NULL;
  1019. pBuffer2 = NULL;
  1020. fUsedNonL2tpRoute = FALSE;
  1021. do
  1022. {
  1023. // Get the routing table from the IP stack. This make take a few
  1024. // iterations since the size of the buffer required is not known. Set
  1025. // up the static request information first.
  1026. //
  1027. QueryBuf.ID.toi_entity.tei_entity = CL_NL_ENTITY;
  1028. QueryBuf.ID.toi_entity.tei_instance = 0;
  1029. QueryBuf.ID.toi_class = INFO_CLASS_PROTOCOL;
  1030. QueryBuf.ID.toi_type = INFO_TYPE_PROVIDER;
  1031. pDeviceObject = IoGetRelatedDeviceObject( pTdix->pAddress );
  1032. status = !STATUS_SUCCESS;
  1033. ulRouteCount = 20;
  1034. for (;;)
  1035. {
  1036. // Allocate a buffer big enough for 'ulRouteCount' routes.
  1037. //
  1038. ulSize = sizeof(IPRouteEntry) * ulRouteCount;
  1039. QueryBuf.ID.toi_id = IP_MIB_RTTABLE_ENTRY_ID;
  1040. NdisZeroMemory( &QueryBuf.Context, CONTEXT_SIZE );
  1041. pBuffer = (IPRouteEntry* )ALLOC_NONPAGED( ulSize, MTAG_ROUTEQUERY );
  1042. if (!pBuffer)
  1043. {
  1044. TRACE( TL_A, TM_Tdi, ( "Alloc RQ?" ) );
  1045. break;
  1046. }
  1047. // Set up a request to the IP stack to fill the buffer with the
  1048. // routing table and send it to the stack.
  1049. //
  1050. KeInitializeEvent(&event, SynchronizationEvent, FALSE);
  1051. pIrp =
  1052. IoBuildDeviceIoControlRequest(
  1053. IOCTL_TCP_QUERY_INFORMATION_EX,
  1054. pDeviceObject,
  1055. (PVOID )&QueryBuf,
  1056. sizeof(QueryBuf),
  1057. pBuffer,
  1058. ulSize,
  1059. FALSE,
  1060. &event,
  1061. &iosb);
  1062. if (!pIrp)
  1063. {
  1064. TRACE( TL_A, TM_Tdi, ( "Build Q Irp?" ) );
  1065. break;
  1066. }
  1067. pIrpSp = IoGetNextIrpStackLocation( pIrp );
  1068. pIrpSp->FileObject = pTdix->pAddress;
  1069. status = IoCallDriver( pDeviceObject, pIrp );
  1070. if (status == STATUS_PENDING) {
  1071. KeWaitForSingleObject(&event,
  1072. Executive,
  1073. KernelMode,
  1074. FALSE,
  1075. NULL);
  1076. status = iosb.Status;
  1077. }
  1078. if (status != STATUS_BUFFER_OVERFLOW)
  1079. {
  1080. if (status != STATUS_SUCCESS)
  1081. {
  1082. g_statusLastAhrTcpQueryInfoExFailure = status;
  1083. }
  1084. break;
  1085. }
  1086. // The buffer didn't hold the routing table. Undo in preparation
  1087. // for another try with twice as big a buffer.
  1088. //
  1089. ulRouteCount <<= 1;
  1090. FREE_NONPAGED( pBuffer );
  1091. }
  1092. if (status != STATUS_SUCCESS)
  1093. {
  1094. TRACE( TL_A, TM_Tdi, ( "AHR Q_INFO_EX=%d?", status ) );
  1095. break;
  1096. }
  1097. status = !STATUS_SUCCESS;
  1098. // Calculate how many routes were loaded into our buffer.
  1099. //
  1100. ulRouteCount = (ULONG )(iosb.Information / sizeof(IPRouteEntry));
  1101. // Walk the route table looking for the "best route" that will be used
  1102. // to route packets to the peer, i.e. the one with the highest
  1103. // priority metric, and within that, the highest class address mask.
  1104. //
  1105. pBestRoute = NULL;
  1106. ulBestMask = 0;
  1107. ulBestMetric = (ULONG )-1;
  1108. for (i = 0, pRouteEntry = pBuffer;
  1109. i < ulRouteCount;
  1110. ++i, ++pRouteEntry)
  1111. {
  1112. if (pRouteEntry->ire_dest == (ulIpAddress & pRouteEntry->ire_mask))
  1113. {
  1114. // Found a route that applies to peer's IP address.
  1115. //
  1116. if (!pBestRoute
  1117. || (ulBestMask == pRouteEntry->ire_mask)
  1118. && (pRouteEntry->ire_metric1 < ulBestMetric))
  1119. {
  1120. // The route has a lower (higher priority) metric than
  1121. // anything found so far.
  1122. //
  1123. pBestRoute = pRouteEntry;
  1124. ulBestMask = pRouteEntry->ire_mask;
  1125. ulBestMetric = pRouteEntry->ire_metric1;
  1126. continue;
  1127. }
  1128. if (ntohl( pRouteEntry->ire_mask ) > ntohl( ulBestMask ))
  1129. {
  1130. // The route has a higher address class mask than anything
  1131. // found so far.
  1132. //
  1133. pBestRoute = pRouteEntry;
  1134. ulBestMask = pRouteEntry->ire_mask;
  1135. ulBestMetric = pRouteEntry->ire_metric1;
  1136. }
  1137. }
  1138. }
  1139. if (pBestRoute)
  1140. {
  1141. // Found the route that will be used to route peer's address.
  1142. //
  1143. if (pBestRoute->ire_dest == ulIpAddress
  1144. && pBestRoute->ire_mask == 0xFFFFFFFF)
  1145. {
  1146. // The host route already exists.
  1147. //
  1148. if (pTdix->hre == HRE_Use)
  1149. {
  1150. TRACE( TL_I, TM_Tdi, ( "Route exists (use as is)" ) );
  1151. status = STATUS_SUCCESS;
  1152. fUsedNonL2tpRoute = TRUE;
  1153. break;
  1154. }
  1155. else if (pTdix->hre == HRE_Fail)
  1156. {
  1157. TRACE( TL_I, TM_Tdi, ( "Route exists (fail)" ) );
  1158. break;
  1159. }
  1160. // If we reach here then we are in HRE_Reference mode, so drop
  1161. // thru and re-add the route so it's reference in the IP stack
  1162. // will be incremented.
  1163. }
  1164. pTdixRoute->InterfaceIndex = pBestRoute->ire_index;
  1165. #if ROUTEWITHREF
  1166. // Allocate a buffer to hold our request to add a new route.
  1167. //
  1168. ulSize = sizeof(IPRouteEntry);
  1169. pBuffer2 = ALLOC_NONPAGED( ulSize, MTAG_ROUTESET );
  1170. if (!pBuffer2)
  1171. {
  1172. TRACE( TL_A, TM_Tdi, ( "Alloc SI?" ) );
  1173. break;
  1174. }
  1175. // Fill in the request buffer with the information about the new
  1176. // specific route. The best route is used as a template.
  1177. //
  1178. pNewRouteEntry = (IPRouteEntry* )pBuffer2;
  1179. NdisMoveMemory( pNewRouteEntry, pBestRoute, sizeof(IPRouteEntry) );
  1180. pNewRouteEntry->ire_dest = ulIpAddress;
  1181. pNewRouteEntry->ire_mask = 0xFFFFFFFF;
  1182. // Check DIRECT/INDIRECT only if this is not a host route
  1183. if(pBestRoute->ire_mask != 0xFFFFFFFF)
  1184. {
  1185. if ((pBestRoute->ire_nexthop & pBestRoute->ire_mask)
  1186. == (ulIpAddress & pBestRoute->ire_mask))
  1187. {
  1188. pNewRouteEntry->ire_type = IRE_TYPE_DIRECT;
  1189. }
  1190. else
  1191. {
  1192. pNewRouteEntry->ire_type = IRE_TYPE_INDIRECT;
  1193. }
  1194. }
  1195. pNewRouteEntry->ire_proto = IRE_PROTO_NETMGMT;
  1196. pIpDeviceObject =
  1197. IoGetRelatedDeviceObject( pTdix->pIpStackAddress );
  1198. KeInitializeEvent(&event, SynchronizationEvent, FALSE);
  1199. pIrp =
  1200. IoBuildDeviceIoControlRequest(
  1201. IOCTL_IP_SET_ROUTEWITHREF,
  1202. pIpDeviceObject,
  1203. pNewRouteEntry,
  1204. ulSize,
  1205. NULL,
  1206. 0,
  1207. FALSE,
  1208. &event,
  1209. &iosb);
  1210. if (!pIrp)
  1211. {
  1212. TRACE( TL_A, TM_Tdi, ( "Build S Irp?" ) );
  1213. break;
  1214. }
  1215. pIrpSp = IoGetNextIrpStackLocation( pIrp );
  1216. pIrpSp->FileObject = pTdix->pIpStackAddress;
  1217. // Send the request to the IP stack.
  1218. //
  1219. status = IoCallDriver( pIpDeviceObject, pIrp );
  1220. #else
  1221. // Allocate a buffer to hold our request to add a new route.
  1222. //
  1223. ulSize =
  1224. sizeof(TCP_REQUEST_SET_INFORMATION_EX) + sizeof(IPRouteEntry);
  1225. pBuffer2 = ALLOC_NONPAGED( ulSize, MTAG_ROUTESET );
  1226. if (!pBuffer2)
  1227. {
  1228. TRACE( TL_A, TM_Tdi, ( "Alloc SI?" ) );
  1229. break;
  1230. }
  1231. // Fill in the request buffer with the information about the new
  1232. // specific route. The best route is used as a template.
  1233. //
  1234. pSetBuf = (TCP_REQUEST_SET_INFORMATION_EX* )pBuffer2;
  1235. NdisZeroMemory( pSetBuf, ulSize );
  1236. pSetBuf->ID.toi_entity.tei_entity = CL_NL_ENTITY;
  1237. pSetBuf->ID.toi_entity.tei_instance = 0;
  1238. pSetBuf->ID.toi_class = INFO_CLASS_PROTOCOL;
  1239. pSetBuf->ID.toi_type = INFO_TYPE_PROVIDER;
  1240. pSetBuf->ID.toi_id = IP_MIB_RTTABLE_ENTRY_ID;
  1241. pSetBuf->BufferSize = sizeof(IPRouteEntry);
  1242. pNewRouteEntry = (IPRouteEntry* )&pSetBuf->Buffer[ 0 ];
  1243. NdisMoveMemory( pNewRouteEntry, pBestRoute, sizeof(IPRouteEntry) );
  1244. pNewRouteEntry->ire_dest = ulIpAddress;
  1245. pNewRouteEntry->ire_mask = 0xFFFFFFFF;
  1246. // Check DIRECT/INDIRECT only if this is not a host route
  1247. if(pBestRoute->ire_mask != 0xFFFFFFFF)
  1248. {
  1249. if ((pBestRoute->ire_nexthop & pBestRoute->ire_mask)
  1250. == (ulIpAddress & pBestRoute->ire_mask))
  1251. {
  1252. pNewRouteEntry->ire_type = IRE_TYPE_DIRECT;
  1253. }
  1254. else
  1255. {
  1256. pNewRouteEntry->ire_type = IRE_TYPE_INDIRECT;
  1257. }
  1258. }
  1259. pNewRouteEntry->ire_proto = IRE_PROTO_NETMGMT;
  1260. KeInitializeEvent(&event, SynchronizationEvent, FALSE);
  1261. pIrp =
  1262. IoBuildDeviceIoControlRequest(
  1263. IOCTL_TCP_SET_INFORMATION_EX,
  1264. pDeviceObject,
  1265. pSetBuf,
  1266. ulSize,
  1267. NULL,
  1268. 0,
  1269. FALSE,
  1270. &event,
  1271. &iosb);
  1272. if (!pIrp)
  1273. {
  1274. TRACE( TL_A, TM_Tdi, ( "Build S Irp?" ) );
  1275. break;
  1276. }
  1277. pIrpSp = IoGetNextIrpStackLocation( pIrp );
  1278. pIrpSp->FileObject = pTdix->pAddress;
  1279. // Send the request to the IP stack.
  1280. //
  1281. status = IoCallDriver( pDeviceObject, pIrp );
  1282. #endif
  1283. if (status == STATUS_PENDING) {
  1284. KeWaitForSingleObject(&event,
  1285. Executive,
  1286. KernelMode,
  1287. FALSE,
  1288. NULL);
  1289. status = iosb.Status;
  1290. }
  1291. if (status != STATUS_SUCCESS)
  1292. {
  1293. TRACE( TL_A, TM_Tdi, ( "AHR SET_ROUTE=$%08x?", status ) );
  1294. g_statusLastAhrSetRouteFailure = status;
  1295. break;
  1296. }
  1297. TRACE( TL_N, TM_Tdi,
  1298. ( "Add host route %d.%d.%d.%d type %d nexthop %d.%d.%d.%d index %d",
  1299. IPADDRTRACE( pNewRouteEntry->ire_dest ),
  1300. pNewRouteEntry->ire_type,
  1301. IPADDRTRACE( pNewRouteEntry->ire_nexthop ),
  1302. pNewRouteEntry->ire_index ) );
  1303. }
  1304. else
  1305. {
  1306. ++g_ulNoBestRoute;
  1307. TRACE( TL_A, TM_Tdi, ( "No best route for $%08x?", ulIpAddress ) );
  1308. break;
  1309. }
  1310. }
  1311. while (FALSE);
  1312. if (pBuffer)
  1313. {
  1314. FREE_NONPAGED( pBuffer );
  1315. }
  1316. if (pBuffer2)
  1317. {
  1318. FREE_NONPAGED( pBuffer2 );
  1319. }
  1320. // Update the route context.
  1321. //
  1322. {
  1323. BOOLEAN fDoClose;
  1324. LONG lRef;
  1325. fDoClose = FALSE;
  1326. NdisAcquireSpinLock( &pTdix->lock );
  1327. {
  1328. pTdixRoute->fUsedNonL2tpRoute = fUsedNonL2tpRoute;
  1329. if (status == STATUS_SUCCESS)
  1330. {
  1331. ++g_ulTdixAddHostRouteSuccesses;
  1332. pTdixRoute->fPending = FALSE;
  1333. }
  1334. else
  1335. {
  1336. ++g_ulTdixAddHostRouteFailures;
  1337. RemoveEntryList( &pTdixRoute->linkRoutes );
  1338. lRef = --pTdix->lRef;
  1339. TRACE( TL_A, TM_Tdi, ( "TdixAHR fail, refs=%d", lRef ) );
  1340. if (lRef <= 0)
  1341. {
  1342. fDoClose = TRUE;
  1343. }
  1344. FREE_TDIXROUTE( pTdxi, pTdixRoute );
  1345. pTdixRoute = NULL;
  1346. }
  1347. }
  1348. NdisReleaseSpinLock( &pTdix->lock );
  1349. if (fDoClose)
  1350. {
  1351. TdixDoClose( pTdix );
  1352. }
  1353. }
  1354. #if 0
  1355. if ((status == STATUS_SUCCESS) &&
  1356. (pTdix->mediatype == TMT_Udp)) {
  1357. do {
  1358. UNICODE_STRING uniDevice;
  1359. UNICODE_STRING uniProtocolNumber;
  1360. TDIXIPADDRESS TdixIpAddress;
  1361. // Create an address object that we can send across. If we have udp xsums
  1362. // disabled we will need to create two address objects, one for control
  1363. // and one for payload. This allows payload specific features to be
  1364. // implemented.
  1365. //
  1366. uniDevice.Buffer = DD_UDP_DEVICE_NAME;
  1367. uniDevice.Length = sizeof(DD_UDP_DEVICE_NAME) - sizeof(WCHAR);
  1368. NdisZeroMemory(&TdixIpAddress, sizeof(TdixIpAddress));
  1369. if(sPort != 0)
  1370. {
  1371. pTdixRoute->sPort = sPort;
  1372. }
  1373. else
  1374. {
  1375. pTdixRoute->sPort = (SHORT)(htons(L2TP_UdpPort));
  1376. }
  1377. TdixIpAddress.sUdpPort = (SHORT)(htons(L2TP_UdpPort));
  1378. TRACE( TL_A, TM_Tdi, ( "sPort for $%08x set to %d",
  1379. ulIpAddress, (UINT) ntohs(pTdixRoute->sPort ) ));
  1380. // Build the UDP device name as a counted string.
  1381. //
  1382. status = TdixOpenIpAddress(&uniDevice,
  1383. &TdixIpAddress,
  1384. &pTdixRoute->hCtrlAddr,
  1385. &pTdixRoute->pCtrlAddr );
  1386. if (status != STATUS_SUCCESS)
  1387. {
  1388. TRACE( TL_A, TM_Tdi, ( "AHR OpenCtrlAddr=%x?", status ) );
  1389. break;
  1390. }
  1391. //
  1392. // Associate a particular "send" IP interface index with the address
  1393. // object, so that if that interface disappears traffic will not be
  1394. // "re-routed" often back into the tunnel producing disastrous
  1395. // looping.
  1396. //
  1397. status = TdixConnectAddrInterface(pTdixRoute->pCtrlAddr,
  1398. pTdixRoute->hCtrlAddr,
  1399. pTdixRoute);
  1400. if (status != STATUS_SUCCESS)
  1401. {
  1402. TRACE( TL_A, TM_Tdi, ( "AHR ConnectCtrlAddr=%x?", status ) );
  1403. break;
  1404. }
  1405. // If udp xsums are disabled we need to create another address object.
  1406. // We will set this object to disable udp xsums and then use it to
  1407. // send payload data.
  1408. //
  1409. // If udp xsums are enabled we can use the same address object for
  1410. // payloads that we use for contrl frames.
  1411. //
  1412. if (pTdix->ulFlags & TDIXF_DisableUdpXsums)
  1413. {
  1414. TDIXIPADDRESS TdixIpAddress;
  1415. NdisZeroMemory(&TdixIpAddress, sizeof(TdixIpAddress));
  1416. TdixIpAddress.sUdpPort = (SHORT)(htons(L2TP_UdpPort));
  1417. // Open the address object
  1418. //
  1419. status = TdixOpenIpAddress(&uniDevice,
  1420. &TdixIpAddress,
  1421. &pTdixRoute->hPayloadAddr,
  1422. &pTdixRoute->pPayloadAddr );
  1423. if (status != STATUS_SUCCESS)
  1424. {
  1425. TRACE( TL_A, TM_Tdi, ( "AHR OpenPayloadAddr=%x?", status ) );
  1426. pTdixRoute->hPayloadAddr = NULL;
  1427. break;
  1428. }
  1429. pTdixRoute->fUsePayloadAddr = TRUE;
  1430. TdixDisableUdpChecksums( pTdixRoute->pPayloadAddr );
  1431. // Associate a particular "send" IP interface index with the address
  1432. // object, so that if that interface disappears traffic will not be
  1433. // "re-routed" often back into the tunnel producing disastrous
  1434. // looping.
  1435. //
  1436. status = TdixConnectAddrInterface(pTdixRoute->pPayloadAddr,
  1437. pTdixRoute->hPayloadAddr,
  1438. pTdixRoute );
  1439. if (status != STATUS_SUCCESS)
  1440. {
  1441. TRACE( TL_A, TM_Tdi, ( "AHR ConnectPayloadAddr=%x?", status ) );
  1442. break;
  1443. }
  1444. }
  1445. else
  1446. {
  1447. pTdixRoute->hPayloadAddr = pTdixRoute->hCtrlAddr;
  1448. pTdixRoute->pPayloadAddr = pTdixRoute->pCtrlAddr;
  1449. TRACE( TL_I, TM_Tdi, ( "AHR Ctrl==Payload") );
  1450. }
  1451. } while ( FALSE );
  1452. if (status != STATUS_SUCCESS) {
  1453. TdixDeleteHostRoute(pTdix, ulIpAddress);
  1454. pTdixRoute = NULL;
  1455. }
  1456. }
  1457. #endif
  1458. return (pTdixRoute);
  1459. }
  1460. VOID
  1461. TdixDeleteHostRoute(
  1462. IN TDIXCONTEXT* pTdix,
  1463. IN ULONG ulIpAddress)
  1464. // Deletes the host route added for network byte-ordered IP address
  1465. // 'ulIpAddress'. 'PTdix' is caller's TDI extension context.
  1466. //
  1467. // Note: This routine borrows heavily from PPTP.
  1468. //
  1469. {
  1470. TCP_REQUEST_QUERY_INFORMATION_EX QueryBuf;
  1471. TCP_REQUEST_SET_INFORMATION_EX *pSetBuf;
  1472. VOID* pBuffer2;
  1473. PIO_STACK_LOCATION pIrpSp;
  1474. PDEVICE_OBJECT pDeviceObject;
  1475. PDEVICE_OBJECT pIpDeviceObject;
  1476. UCHAR context[ CONTEXT_SIZE ];
  1477. NTSTATUS status;
  1478. PIRP pIrp;
  1479. IO_STATUS_BLOCK iosb;
  1480. IPRouteEntry* pBuffer;
  1481. IPRouteEntry* pRouteEntry;
  1482. IPRouteEntry* pNewRouteEntry;
  1483. ULONG ulRouteCount;
  1484. ULONG ulSize;
  1485. ULONG i;
  1486. TDIXROUTE* pTdixRoute;
  1487. BOOLEAN fPending;
  1488. BOOLEAN fDoDelete;
  1489. KEVENT event;
  1490. TRACE( TL_N, TM_Tdi, ( "TdixDeleteHostRoute(%d.%d.%d.%d)",
  1491. IPADDRTRACE( ulIpAddress ) ) );
  1492. if (!ulIpAddress)
  1493. {
  1494. TRACE( TL_A, TM_Tdi, ( "!IP?" ) );
  1495. return;
  1496. }
  1497. // Host routes are referenced since more than one tunnel to the same peer
  1498. // (allowed by L2TP) shares the same system route. First, see if this is
  1499. // just a dereference or the final deletion of the system host route.
  1500. //
  1501. for (;;)
  1502. {
  1503. fDoDelete = FALSE;
  1504. fPending = FALSE;
  1505. NdisAcquireSpinLock( &pTdix->lock );
  1506. do
  1507. {
  1508. // These asserts hold because we never delete routes we didn't
  1509. // add, and since the route we added holds a TDIX reference, TDIX
  1510. // cannot be opening or closing.
  1511. //
  1512. ASSERT( pTdix->lRef > 0 );
  1513. ASSERT( !(ReadFlags( &pTdix->ulFlags) & TDIXF_Pending) );
  1514. pTdixRoute = TdixRouteFromIpAddress( pTdix, ulIpAddress );
  1515. if (pTdixRoute)
  1516. {
  1517. // Route exists. Remove a reference.
  1518. //
  1519. fPending = pTdixRoute->fPending;
  1520. if (!fPending)
  1521. {
  1522. if (--pTdixRoute->lRef <= 0)
  1523. {
  1524. // Last "add" reference has been removed so call the
  1525. // IOCTLs to delete the system route.
  1526. //
  1527. pTdixRoute->fPending = TRUE;
  1528. fDoDelete = TRUE;
  1529. }
  1530. }
  1531. }
  1532. DBG_else
  1533. {
  1534. ASSERT( FALSE );
  1535. }
  1536. }
  1537. while (FALSE);
  1538. NdisReleaseSpinLock( &pTdix->lock );
  1539. if (fDoDelete)
  1540. {
  1541. // This is the last reference, so go on and issue the IOCTLs to
  1542. // delete the system host route.
  1543. //
  1544. break;
  1545. }
  1546. if (!fPending)
  1547. {
  1548. // Just remove a reference.
  1549. //
  1550. return;
  1551. }
  1552. // An operation is already pending. Give it some time to finish then
  1553. // check again.
  1554. //
  1555. TRACE( TL_I, TM_Tdi, ( "NdisMSleep(del)" ) );
  1556. NdisMSleep( 100000 );
  1557. TRACE( TL_I, TM_Tdi, ( "NdisMSleep(del)" ) );
  1558. }
  1559. pBuffer = NULL;
  1560. do
  1561. {
  1562. if (pTdixRoute->fUsedNonL2tpRoute)
  1563. {
  1564. // Used a route we didn't add so don't delete it either.
  1565. //
  1566. status = STATUS_SUCCESS;
  1567. break;
  1568. }
  1569. // Get the routing table from the IP stack. This make take a few
  1570. // iterations since the size of the buffer required is not known. Set
  1571. // up the static request information first.
  1572. //
  1573. QueryBuf.ID.toi_entity.tei_entity = CL_NL_ENTITY;
  1574. QueryBuf.ID.toi_entity.tei_instance = 0;
  1575. QueryBuf.ID.toi_class = INFO_CLASS_PROTOCOL;
  1576. QueryBuf.ID.toi_type = INFO_TYPE_PROVIDER;
  1577. pDeviceObject = IoGetRelatedDeviceObject( pTdix->pAddress );
  1578. status = !STATUS_SUCCESS;
  1579. ulRouteCount = 20;
  1580. for (;;)
  1581. {
  1582. // Allocate a buffer big enough for 'ulRouteCount' routes.
  1583. //
  1584. ulSize = sizeof(IPRouteEntry) * ulRouteCount;
  1585. QueryBuf.ID.toi_id = IP_MIB_RTTABLE_ENTRY_ID;
  1586. NdisZeroMemory( &QueryBuf.Context, CONTEXT_SIZE );
  1587. pBuffer = (IPRouteEntry* )ALLOC_NONPAGED( ulSize, MTAG_ROUTEQUERY );
  1588. if (!pBuffer)
  1589. {
  1590. TRACE( TL_A, TM_Tdi, ( "Alloc RQ?" ) );
  1591. break;
  1592. }
  1593. // Set up a request to the IP stack to fill the buffer with the
  1594. // routing table and send it to the stack.
  1595. //
  1596. KeInitializeEvent(&event, SynchronizationEvent, FALSE);
  1597. pIrp = IoBuildDeviceIoControlRequest(
  1598. IOCTL_TCP_QUERY_INFORMATION_EX,
  1599. pDeviceObject,
  1600. (PVOID )&QueryBuf,
  1601. sizeof(QueryBuf),
  1602. pBuffer,
  1603. ulSize,
  1604. FALSE,
  1605. &event,
  1606. &iosb );
  1607. if (!pIrp)
  1608. {
  1609. TRACE( TL_A, TM_Tdi, ( "TCP_QI Irp?" ) );
  1610. break;
  1611. }
  1612. pIrpSp = IoGetNextIrpStackLocation( pIrp );
  1613. pIrpSp->FileObject = pTdix->pAddress;
  1614. status = IoCallDriver( pDeviceObject, pIrp );
  1615. if (status == STATUS_PENDING) {
  1616. KeWaitForSingleObject(&event,
  1617. Executive,
  1618. KernelMode,
  1619. FALSE,
  1620. NULL);
  1621. status = iosb.Status;
  1622. }
  1623. if (status != STATUS_BUFFER_OVERFLOW)
  1624. {
  1625. if (status != STATUS_SUCCESS)
  1626. {
  1627. TRACE( TL_A, TM_Tdi, ( "DHR Q_INFO_EX=%d?", status ) );
  1628. g_statusLastDhrTcpQueryInfoExFailure = status;
  1629. }
  1630. break;
  1631. }
  1632. // The buffer didn't hold the routing table. Undo in preparation for
  1633. // another try with twice as big a buffer.
  1634. //
  1635. ulRouteCount <<= 1;
  1636. FREE_NONPAGED( pBuffer );
  1637. }
  1638. if (status != STATUS_SUCCESS)
  1639. {
  1640. break;
  1641. }
  1642. // Calculate how many routes were loaded into our buffer.
  1643. //
  1644. ulRouteCount = (ULONG )(iosb.Information / sizeof(IPRouteEntry));
  1645. // Walk the route table looking for the route we added in
  1646. // TdixAddHostRoute.
  1647. //
  1648. status = !STATUS_SUCCESS;
  1649. pBuffer2 = NULL;
  1650. for (i = 0, pRouteEntry = pBuffer;
  1651. i < ulRouteCount;
  1652. ++i, ++pRouteEntry)
  1653. {
  1654. if (pRouteEntry->ire_dest == ulIpAddress
  1655. && pRouteEntry->ire_proto == IRE_PROTO_NETMGMT)
  1656. {
  1657. #if ROUTEWITHREF
  1658. // Found the added route. Allocate a buffer to hold our
  1659. // request to delete the route.
  1660. //
  1661. ulSize = sizeof(IPRouteEntry);
  1662. pBuffer2 = ALLOC_NONPAGED( ulSize, MTAG_ROUTESET );
  1663. if (!pBuffer2)
  1664. {
  1665. TRACE( TL_A, TM_Tdi, ( "!pBuffer2" ) );
  1666. break;
  1667. }
  1668. // Use the found route as a template for the route entry
  1669. // marked for deletion.
  1670. //
  1671. pNewRouteEntry = (IPRouteEntry* )pBuffer2;
  1672. NdisMoveMemory(
  1673. pNewRouteEntry, pRouteEntry, sizeof(IPRouteEntry) );
  1674. pNewRouteEntry->ire_type = IRE_TYPE_INVALID;
  1675. pIpDeviceObject =
  1676. IoGetRelatedDeviceObject( pTdix->pIpStackAddress );
  1677. KeInitializeEvent(&event, SynchronizationEvent, FALSE);
  1678. pIrp = IoBuildDeviceIoControlRequest(
  1679. IOCTL_IP_SET_ROUTEWITHREF,
  1680. pIpDeviceObject,
  1681. pNewRouteEntry,
  1682. ulSize,
  1683. NULL,
  1684. 0,
  1685. FALSE,
  1686. &event,
  1687. &iosb);
  1688. if (!pIrp)
  1689. {
  1690. TRACE( TL_A, TM_Tdi, ( "TCP_SI Irp?" ) );
  1691. break;
  1692. }
  1693. pIrpSp = IoGetNextIrpStackLocation( pIrp );
  1694. pIrpSp->FileObject = pTdix->pIpStackAddress;
  1695. // Send the request to the IP stack.
  1696. //
  1697. status = IoCallDriver( pIpDeviceObject, pIrp );
  1698. #else
  1699. // Found the added route. Allocate a buffer to hold our
  1700. // request to delete the route.
  1701. //
  1702. ulSize = sizeof(TCP_REQUEST_SET_INFORMATION_EX)
  1703. + sizeof(IPRouteEntry);
  1704. pBuffer2 = ALLOC_NONPAGED( ulSize, MTAG_ROUTESET );
  1705. if (!pBuffer2)
  1706. {
  1707. TRACE( TL_A, TM_Tdi, ( "!pSetBuf" ) );
  1708. break;
  1709. }
  1710. // Fill in the request buffer with static information about
  1711. // changing routes.
  1712. //
  1713. pSetBuf = (TCP_REQUEST_SET_INFORMATION_EX *)pBuffer2;
  1714. NdisZeroMemory( pSetBuf, ulSize );
  1715. pSetBuf->ID.toi_entity.tei_entity = CL_NL_ENTITY;
  1716. pSetBuf->ID.toi_entity.tei_instance = 0;
  1717. pSetBuf->ID.toi_class = INFO_CLASS_PROTOCOL;
  1718. pSetBuf->ID.toi_type = INFO_TYPE_PROVIDER;
  1719. pSetBuf->ID.toi_id = IP_MIB_RTTABLE_ENTRY_ID;
  1720. pSetBuf->BufferSize = sizeof(IPRouteEntry);
  1721. // Use the found route as a template for the route entry marked
  1722. // for deletion.
  1723. //
  1724. pNewRouteEntry = (IPRouteEntry* )&pSetBuf->Buffer[ 0 ];
  1725. NdisMoveMemory(
  1726. pNewRouteEntry, pRouteEntry, sizeof(IPRouteEntry) );
  1727. pNewRouteEntry->ire_type = IRE_TYPE_INVALID;
  1728. KeInitializeEvent(&event, SynchronizationEvent, FALSE);
  1729. pIrp = IoBuildDeviceIoControlRequest(
  1730. IOCTL_TCP_SET_INFORMATION_EX,
  1731. pDeviceObject,
  1732. pSetBuf,
  1733. ulSize,
  1734. NULL,
  1735. 0,
  1736. FALSE,
  1737. &event,
  1738. &iosb);
  1739. if (!pIrp)
  1740. {
  1741. TRACE( TL_A, TM_Tdi, ( "TCP_SI Irp?" ) );
  1742. break;
  1743. }
  1744. pIrpSp = IoGetNextIrpStackLocation( pIrp );
  1745. pIrpSp->FileObject = pTdix->pAddress;
  1746. // Send the request to the IP stack.
  1747. //
  1748. status = IoCallDriver( pDeviceObject, pIrp );
  1749. #endif
  1750. if (status == STATUS_PENDING) {
  1751. KeWaitForSingleObject(&event,
  1752. Executive,
  1753. KernelMode,
  1754. FALSE,
  1755. NULL);
  1756. status = iosb.Status;
  1757. }
  1758. if (status != STATUS_SUCCESS)
  1759. {
  1760. TRACE( TL_A, TM_Tdi, ( "DHR SET_ROUTE=%d?", status ) );
  1761. g_statusLastDhrSetRouteFailure = status;
  1762. break;
  1763. }
  1764. break;
  1765. }
  1766. }
  1767. if (pBuffer2)
  1768. {
  1769. FREE_NONPAGED( pBuffer2 );
  1770. }
  1771. TRACE( TL_V, TM_Tdi, ( "TdixDeleteHostRoute done" ) );
  1772. }
  1773. while (FALSE);
  1774. if (pBuffer)
  1775. {
  1776. FREE_NONPAGED( pBuffer );
  1777. }
  1778. if (pTdixRoute->fUsePayloadAddr) {
  1779. ASSERT(pTdixRoute->hPayloadAddr != NULL);
  1780. ObDereferenceObject( pTdixRoute->pPayloadAddr );
  1781. // Close the payload address object
  1782. //
  1783. ZwClose(pTdixRoute->hPayloadAddr);
  1784. pTdixRoute->hPayloadAddr = NULL;
  1785. pTdixRoute->fUsePayloadAddr = FALSE;
  1786. }
  1787. if (pTdixRoute->hCtrlAddr != NULL) {
  1788. // Close the Ctrl address object
  1789. //
  1790. ObDereferenceObject( pTdixRoute->pCtrlAddr );
  1791. ZwClose (pTdixRoute->hCtrlAddr);
  1792. pTdixRoute->hCtrlAddr = NULL;
  1793. }
  1794. // Remove the route context effectively unpending the operation.
  1795. //
  1796. {
  1797. BOOLEAN fDoClose;
  1798. LONG lRef;
  1799. fDoClose = FALSE;
  1800. NdisAcquireSpinLock( &pTdix->lock );
  1801. {
  1802. if (status == STATUS_SUCCESS)
  1803. {
  1804. ++g_ulTdixDeleteHostRouteSuccesses;
  1805. }
  1806. else
  1807. {
  1808. ++g_ulTdixDeleteHostRouteFailures;
  1809. }
  1810. ASSERT( pTdixRoute->lRef == 0 );
  1811. RemoveEntryList( &pTdixRoute->linkRoutes );
  1812. lRef = --pTdix->lRef;
  1813. TRACE( TL_N, TM_Tdi, ( "TdixDHR, refs=%d", lRef ) );
  1814. if (lRef == 0)
  1815. {
  1816. fDoClose = TRUE;
  1817. }
  1818. FREE_TDIXROUTE( pTdix, pTdixRoute );
  1819. }
  1820. NdisReleaseSpinLock( &pTdix->lock );
  1821. if (fDoClose)
  1822. {
  1823. TdixDoClose( pTdix );
  1824. }
  1825. }
  1826. }
  1827. NTSTATUS
  1828. TdixGetInterfaceInfo(
  1829. IN TDIXCONTEXT* pTdix,
  1830. IN ULONG ulIpAddress,
  1831. OUT PULONG pulSpeed)
  1832. {
  1833. TCP_REQUEST_QUERY_INFORMATION_EX QueryBuf;
  1834. PDEVICE_OBJECT pDeviceObject;
  1835. NTSTATUS status;
  1836. PIRP pIrp;
  1837. PIO_STACK_LOCATION pIrpSp;
  1838. IO_STATUS_BLOCK iosb;
  1839. UCHAR pBuffer[256];
  1840. KEVENT event;
  1841. IPInterfaceInfo* pInterfaceInfo;
  1842. // Get the routing table from the IP stack. This make take a few
  1843. // iterations since the size of the buffer required is not known. Set
  1844. // up the static request information first.
  1845. //
  1846. QueryBuf.ID.toi_entity.tei_entity = CL_NL_ENTITY;
  1847. QueryBuf.ID.toi_entity.tei_instance = 0;
  1848. QueryBuf.ID.toi_class = INFO_CLASS_PROTOCOL;
  1849. QueryBuf.ID.toi_type = INFO_TYPE_PROVIDER;
  1850. QueryBuf.ID.toi_id = IP_INTFC_INFO_ID;
  1851. *(ULONG *)QueryBuf.Context = ulIpAddress;
  1852. pDeviceObject = IoGetRelatedDeviceObject( pTdix->pAddress );
  1853. // Set up a request to the IP stack to fill the buffer with the
  1854. // routing table and send it to the stack.
  1855. KeInitializeEvent(&event, SynchronizationEvent, FALSE);
  1856. pIrp =
  1857. IoBuildDeviceIoControlRequest(
  1858. IOCTL_TCP_QUERY_INFORMATION_EX,
  1859. pDeviceObject,
  1860. (PVOID )&QueryBuf,
  1861. sizeof(QueryBuf),
  1862. pBuffer,
  1863. sizeof(pBuffer),
  1864. FALSE,
  1865. &event,
  1866. &iosb);
  1867. if (!pIrp)
  1868. {
  1869. TRACE( TL_A, TM_Tdi, ( "Build Q Irp?" ) );
  1870. return NDIS_STATUS_RESOURCES;
  1871. }
  1872. pIrpSp = IoGetNextIrpStackLocation( pIrp );
  1873. pIrpSp->FileObject = pTdix->pAddress;
  1874. status = IoCallDriver( pDeviceObject, pIrp );
  1875. if (status == STATUS_PENDING) {
  1876. KeWaitForSingleObject(&event,
  1877. Executive,
  1878. KernelMode,
  1879. FALSE,
  1880. NULL);
  1881. status = iosb.Status;
  1882. }
  1883. if (status == STATUS_SUCCESS)
  1884. {
  1885. *pulSpeed = ((IPInterfaceInfo *)pBuffer)->iii_speed;
  1886. }
  1887. return status;
  1888. }
  1889. //-----------------------------------------------------------------------------
  1890. // Local utility routines (alphabetically)
  1891. //-----------------------------------------------------------------------------
  1892. NTSTATUS
  1893. TdixSetTdiAOOption(
  1894. IN FILE_OBJECT* pAddress,
  1895. IN ULONG ulOption,
  1896. IN ULONG ulValue)
  1897. // Turn off UDP checksums on open UDP address object 'pAddress'.
  1898. //
  1899. {
  1900. NTSTATUS status;
  1901. PDEVICE_OBJECT pDeviceObject;
  1902. PIO_STACK_LOCATION pIrpSp;
  1903. IO_STATUS_BLOCK iosb;
  1904. PIRP pIrp;
  1905. TCP_REQUEST_SET_INFORMATION_EX* pInfo;
  1906. CHAR achBuf[ sizeof(*pInfo) + sizeof(ULONG) ];
  1907. pInfo = (TCP_REQUEST_SET_INFORMATION_EX* )achBuf;
  1908. pInfo->ID.toi_entity.tei_entity = CL_TL_ENTITY;
  1909. pInfo->ID.toi_entity.tei_instance = 0;
  1910. pInfo->ID.toi_class = INFO_CLASS_PROTOCOL;
  1911. pInfo->ID.toi_type = INFO_TYPE_ADDRESS_OBJECT;
  1912. pInfo->ID.toi_id = ulOption;
  1913. NdisMoveMemory( pInfo->Buffer, &ulValue, sizeof(ulValue) );
  1914. pInfo->BufferSize = sizeof(ulValue);
  1915. pDeviceObject = IoGetRelatedDeviceObject( pAddress );
  1916. pIrp = IoBuildDeviceIoControlRequest(
  1917. IOCTL_TCP_WSH_SET_INFORMATION_EX,
  1918. pDeviceObject,
  1919. (PVOID )pInfo,
  1920. sizeof(*pInfo) + sizeof(ulValue),
  1921. NULL,
  1922. 0,
  1923. FALSE,
  1924. NULL,
  1925. &iosb );
  1926. if (!pIrp)
  1927. {
  1928. TRACE( TL_A, TM_Tdi, ( "TdixSetTdiAOOption Irp?" ) );
  1929. return NDIS_STATUS_RESOURCES;
  1930. }
  1931. pIrpSp = IoGetNextIrpStackLocation( pIrp );
  1932. pIrpSp->FileObject = pAddress;
  1933. status = IoCallDriver( pDeviceObject, pIrp );
  1934. if(NT_SUCCESS(status))
  1935. {
  1936. status = iosb.Status;
  1937. }
  1938. return status;
  1939. }
  1940. VOID
  1941. TdixDisableUdpChecksums(
  1942. IN FILE_OBJECT* pAddress )
  1943. // Turn off UDP checksums on open UDP address object 'pAddress'.
  1944. //
  1945. {
  1946. NTSTATUS status;
  1947. status = TdixSetTdiAOOption(pAddress, AO_OPTION_XSUM, FALSE);
  1948. TRACE( TL_I, TM_Tdi, ( "Disable XSUMs($%p)=$%08x",
  1949. pAddress, status ) );
  1950. }
  1951. VOID
  1952. TdixEnableIpPktInfo(
  1953. IN FILE_OBJECT* pAddress )
  1954. // Turn on IP_PKTINFO on open UDP address object 'pAddress'.
  1955. //
  1956. {
  1957. NTSTATUS status;
  1958. status = TdixSetTdiAOOption(pAddress, AO_OPTION_IP_PKTINFO, TRUE);
  1959. TRACE( TL_I, TM_Tdi, ( "Enable IP_PKTINFO ($%p)=$%08x",
  1960. pAddress, status ) );
  1961. }
  1962. VOID
  1963. TdixDoClose(
  1964. TDIXCONTEXT* pTdix )
  1965. // Called when 'pTdix->lRef' reaches 0 to close down the TDI session.
  1966. // 'PTdix' is the transport context for the session.
  1967. //
  1968. {
  1969. TRACE( TL_N, TM_Tdi, ( "TdixDoClose" ) );
  1970. if (pTdix->pAddress)
  1971. {
  1972. // Install a NULL handler, effectively uninstalling.
  1973. //
  1974. TdixInstallEventHandler( pTdix->pAddress,
  1975. TDI_EVENT_RECEIVE_DATAGRAM, NULL, pTdix );
  1976. ObDereferenceObject( pTdix->pAddress );
  1977. pTdix->pAddress = NULL;
  1978. // If have a valid transport address, the lookaside lists were also
  1979. // initialized.
  1980. //
  1981. NdisDeleteNPagedLookasideList( &pTdix->llistRdg );
  1982. NdisDeleteNPagedLookasideList( &pTdix->llistSdg );
  1983. }
  1984. if (pTdix->hAddress)
  1985. {
  1986. ZwClose( pTdix->hAddress );
  1987. pTdix->hAddress = NULL;
  1988. }
  1989. #if ROUTEWITHREF
  1990. if (pTdix->hIpStackAddress)
  1991. {
  1992. ZwClose( pTdix->hIpStackAddress );
  1993. pTdix->hIpStackAddress = NULL;
  1994. }
  1995. #endif
  1996. if (pTdix->pIpStackAddress)
  1997. {
  1998. ObDereferenceObject( pTdix->pIpStackAddress );
  1999. pTdix->pIpStackAddress = NULL;
  2000. }
  2001. // Mark the operation complete.
  2002. //
  2003. NdisAcquireSpinLock( &pTdix->lock );
  2004. {
  2005. ASSERT( pTdix->lRef == 0 );
  2006. ClearFlags( &pTdix->ulFlags, TDIXF_Pending );
  2007. }
  2008. NdisReleaseSpinLock( &pTdix->lock );
  2009. }
  2010. VOID
  2011. TdixExtractAddress(
  2012. IN TDIXCONTEXT* pTdix,
  2013. OUT TDIXRDGINFO* pRdg,
  2014. IN VOID* pTransportAddress,
  2015. IN LONG lTransportAddressLen,
  2016. IN VOID* Options,
  2017. IN LONG OptionsLength)
  2018. // Fills callers '*pAddress' with the useful part of the transport address
  2019. // 'pTransportAddress' of length 'lTransportAddressLen'. 'PTdix' is our
  2020. // context.
  2021. //
  2022. {
  2023. TDIXIPADDRESS* pAddress = &pRdg->source;
  2024. TA_IP_ADDRESS* pTAddress = (TA_IP_ADDRESS* )pTransportAddress;
  2025. ASSERT( lTransportAddressLen == sizeof(TA_IP_ADDRESS) );
  2026. ASSERT( pTAddress->TAAddressCount == 1 );
  2027. ASSERT( pTAddress->Address[ 0 ].AddressType == TDI_ADDRESS_TYPE_IP );
  2028. ASSERT( pTAddress->Address[ 0 ].AddressLength == TDI_ADDRESS_LENGTH_IP );
  2029. // source address
  2030. pAddress->ulIpAddress = pTAddress->Address[ 0 ].Address[ 0 ].in_addr;
  2031. pAddress->sUdpPort = pTAddress->Address[ 0 ].Address[ 0 ].sin_port;
  2032. // dest address
  2033. if(Options)
  2034. {
  2035. IN_PKTINFO* pktinfo = (IN_PKTINFO*)TDI_CMSG_DATA(Options);
  2036. ASSERT(((PTDI_CMSGHDR)Options)->cmsg_type == IP_PKTINFO);
  2037. // Fill in the ancillary data object header information.
  2038. pRdg->dest.ulIpAddress = pktinfo->ipi_addr;
  2039. // Get the index of the local interface on which the packet arrived.
  2040. pRdg->dest.ifindex = pktinfo->ipi_ifindex;
  2041. }
  2042. }
  2043. NTSTATUS
  2044. TdixInstallEventHandler(
  2045. IN FILE_OBJECT* pAddress,
  2046. IN INT nEventType,
  2047. IN VOID* pfuncEventHandler,
  2048. IN VOID* pEventContext )
  2049. // Install a TDI event handler routine 'pfuncEventHandler' to be called
  2050. // when events of type 'nEventType' occur. 'PEventContext' is passed to
  2051. // the handler. 'PAddress' is the transport address object.
  2052. //
  2053. // This call must be made at PASSIVE IRQL.
  2054. //
  2055. // Returns 0 if successful or an error code.
  2056. //
  2057. {
  2058. NTSTATUS status;
  2059. PIRP pIrp;
  2060. TRACE( TL_N, TM_Tdi, ( "TdixInstallEventHandler" ) );
  2061. // Allocate a "set event" IRP with base initialization.
  2062. //
  2063. pIrp =
  2064. TdiBuildInternalDeviceControlIrp(
  2065. TDI_SET_EVENT_HANDLER,
  2066. pAddress->DeviceObject,
  2067. pAddress,
  2068. NULL,
  2069. NULL );
  2070. if (!pIrp)
  2071. {
  2072. TRACE( TL_A, TM_Tdi, ( "TdiBuildIDCIrp?" ) );
  2073. return NDIS_STATUS_RESOURCES;
  2074. }
  2075. // Complete the "set event" IRP initialization.
  2076. //
  2077. TdiBuildSetEventHandler(
  2078. pIrp,
  2079. pAddress->DeviceObject,
  2080. pAddress,
  2081. NULL,
  2082. NULL,
  2083. nEventType,
  2084. pfuncEventHandler,
  2085. pEventContext );
  2086. // Tell the I/O manager to pass our IRP to the transport for processing.
  2087. //
  2088. status = IoCallDriver( pAddress->DeviceObject, pIrp );
  2089. if (status != STATUS_SUCCESS)
  2090. {
  2091. TRACE( TL_A, TM_Tdi, ( "IoCallDriver=$%08x?", status ) );
  2092. return status;
  2093. }
  2094. TRACE( TL_V, TM_Tdi, ( "TdixInstallEventHandler=0" ) );
  2095. return STATUS_SUCCESS;
  2096. }
  2097. NTSTATUS
  2098. TdixOpenIpAddress(
  2099. IN UNICODE_STRING* puniDevice,
  2100. IN TDIXIPADDRESS* pTdixAddr,
  2101. OUT HANDLE* phAddress,
  2102. OUT FILE_OBJECT** ppFileObject )
  2103. // Open a transport address for the IP-based protocol with name
  2104. // '*puniDevice' and port 'sPort'. 'SPort' may be 0 indicating "any"
  2105. // port. "Any" address is assumed. Loads the open address object handle
  2106. // into '*phAddress' and the referenced file object into '*ppFileObject'.
  2107. //
  2108. // Returns STATUS_SUCCESS or an error code.
  2109. //
  2110. {
  2111. NTSTATUS status;
  2112. OBJECT_ATTRIBUTES oa;
  2113. IO_STATUS_BLOCK iosb;
  2114. FILE_FULL_EA_INFORMATION *pEa;
  2115. ULONG ulEaLength;
  2116. TA_IP_ADDRESS UNALIGNED *pTaIp;
  2117. TDI_ADDRESS_IP UNALIGNED *pTdiIp;
  2118. CHAR achEa[ 100 ];
  2119. HANDLE hAddress;
  2120. FILE_OBJECT* pFileObject;
  2121. hAddress = NULL;
  2122. pFileObject = NULL;
  2123. // Initialize object attributes, a parameter needed to open the device.
  2124. //
  2125. InitializeObjectAttributes(
  2126. &oa, puniDevice, OBJ_CASE_INSENSITIVE, NULL, NULL );
  2127. // Set up the extended attribute that tells the IP stack the IP
  2128. // address/port from which we want to receive. For raw IP we say "any
  2129. // address and port" and for UDP we say "any address on the L2TP
  2130. // port". Is this an ugly structure or what?
  2131. //
  2132. ASSERT( sizeof(FILE_FULL_EA_INFORMATION)
  2133. + TDI_TRANSPORT_ADDRESS_LENGTH + sizeof(TA_IP_ADDRESS) <= 100);
  2134. pEa = (FILE_FULL_EA_INFORMATION* )achEa;
  2135. pEa->NextEntryOffset = 0;
  2136. pEa->Flags = 0;
  2137. pEa->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
  2138. pEa->EaValueLength = sizeof(TA_IP_ADDRESS);
  2139. NdisMoveMemory(
  2140. pEa->EaName, TdiTransportAddress, TDI_TRANSPORT_ADDRESS_LENGTH );
  2141. // Note: The ZwCreateFile wants the sized name to have a null
  2142. // terminator character (go figure), so add it and account for
  2143. // it with the "+ 1" below.
  2144. //
  2145. pEa->EaName[ TDI_TRANSPORT_ADDRESS_LENGTH ] = '\0';
  2146. pTaIp = (TA_IP_ADDRESS UNALIGNED* )
  2147. (pEa->EaName + TDI_TRANSPORT_ADDRESS_LENGTH + 1);
  2148. pTaIp->TAAddressCount = 1;
  2149. pTaIp->Address[ 0 ].AddressLength = TDI_ADDRESS_LENGTH_IP;
  2150. pTaIp->Address[ 0 ].AddressType = TDI_ADDRESS_TYPE_IP;
  2151. pTdiIp = &pTaIp->Address[ 0 ].Address[ 0 ];
  2152. pTdiIp->sin_port = pTdixAddr->sUdpPort;
  2153. pTdiIp->in_addr = pTdixAddr->ulIpAddress;
  2154. NdisZeroMemory( pTdiIp->sin_zero, sizeof(pTdiIp->sin_zero) );
  2155. ulEaLength = (ULONG )((CHAR* )(pTaIp + 1) - (CHAR* )pEa);
  2156. // Open the transport address.
  2157. //
  2158. status =
  2159. ZwCreateFile(
  2160. &hAddress,
  2161. FILE_READ_DATA | FILE_WRITE_DATA,
  2162. &oa,
  2163. &iosb,
  2164. NULL,
  2165. FILE_ATTRIBUTE_NORMAL,
  2166. FILE_SHARE_WRITE,
  2167. FILE_OPEN,
  2168. 0,
  2169. pEa,
  2170. ulEaLength );
  2171. if (status != STATUS_SUCCESS)
  2172. {
  2173. TRACE( TL_A, TM_Tdi, ( "ZwCreateFile(%S)=$%08x,ios=$%08x?",
  2174. puniDevice->Buffer, status, iosb.Information ) );
  2175. return status;
  2176. }
  2177. // Get the object address from the handle. This also checks our
  2178. // permissions on the object.
  2179. //
  2180. status =
  2181. ObReferenceObjectByHandle(
  2182. hAddress,
  2183. 0,
  2184. NULL,
  2185. KernelMode,
  2186. &pFileObject,
  2187. NULL );
  2188. if (status != STATUS_SUCCESS)
  2189. {
  2190. TRACE( TL_A, TM_Tdi,
  2191. ( "ObRefObjByHandle(%S)=$%08x?", puniDevice->Buffer, status ) );
  2192. ZwClose( hAddress );
  2193. return status;
  2194. }
  2195. *phAddress = hAddress;
  2196. *ppFileObject = pFileObject;
  2197. return STATUS_SUCCESS;
  2198. }
  2199. NTSTATUS
  2200. TdixReceiveDatagramHandler(
  2201. IN PVOID TdiEventContext,
  2202. IN LONG SourceAddressLength,
  2203. IN PVOID SourceAddress,
  2204. IN LONG OptionsLength,
  2205. IN PVOID Options,
  2206. IN ULONG ReceiveDatagramFlags,
  2207. IN ULONG BytesIndicated,
  2208. IN ULONG BytesAvailable,
  2209. OUT ULONG* BytesTaken,
  2210. IN PVOID Tsdu,
  2211. OUT PIRP* IoRequestPacket )
  2212. // Standard TDI ClientEventReceiveDatagram indication handler. See TDI
  2213. // doc. Runs at DISPATCH IRQL.
  2214. //
  2215. {
  2216. TDIXCONTEXT* pTdix;
  2217. TDIXRDGINFO* pRdg;
  2218. CHAR* pBuffer;
  2219. NDIS_BUFFER* pNdisBuffer;
  2220. PIRP pIrp;
  2221. TRACE( TL_N, TM_Tdi, ( "TdixRecvDg, f=$%08x bi=%d, ba=%d",
  2222. ReceiveDatagramFlags, BytesIndicated, BytesAvailable ) );
  2223. if (BytesAvailable > L2TP_FrameBufferSize) {
  2224. // We received a larger datagram then expected or can handle,
  2225. // so we just ignore the datagram.
  2226. //
  2227. ASSERT( !"BytesAvailable > L2TP_FrameBufferSize?" );
  2228. *IoRequestPacket = NULL;
  2229. *BytesTaken = 0;
  2230. return STATUS_SUCCESS;
  2231. }
  2232. pTdix = (TDIXCONTEXT* )TdiEventContext;
  2233. // Allocate a receive pBuffer from TDIX client's pool.
  2234. //
  2235. pBuffer = GetBufferFromPool( pTdix->pPoolNdisBuffers );
  2236. if (!pBuffer)
  2237. {
  2238. // Not a whole lot we can do with this unlikely error from inside this
  2239. // handler, so we just ignore the datagram.
  2240. //
  2241. ASSERT( !"GetBfromP?" );
  2242. return STATUS_SUCCESS;
  2243. }
  2244. // Allocate a context for this read-datagram from our lookaside list.
  2245. //
  2246. pRdg = ALLOC_TDIXRDGINFO( pTdix );
  2247. if (pRdg)
  2248. {
  2249. // Fill in the read-datagram context with the information that won't
  2250. // otherwise be available in the completion routine.
  2251. //
  2252. pRdg->pTdix = pTdix;
  2253. pRdg->pBuffer = pBuffer;
  2254. pRdg->ulBufferLen = BytesAvailable;
  2255. // Extract the useful IP address from the more general transport
  2256. // address information.
  2257. //
  2258. TdixExtractAddress(
  2259. pTdix, pRdg, SourceAddress, SourceAddressLength, Options, OptionsLength);
  2260. }
  2261. else
  2262. {
  2263. // Not a whole lot we can do with this unlikely error from inside this
  2264. // handler, so we just ignore the datagram.
  2265. //
  2266. FreeBufferToPool( pTdix->pPoolNdisBuffers, pBuffer, TRUE );
  2267. ASSERT( !"AllocRdg?" );
  2268. return STATUS_SUCCESS;
  2269. }
  2270. if (BytesIndicated < BytesAvailable)
  2271. {
  2272. // The less common case where all the information is not immediately
  2273. // available. Allocate an IRP to request the data.
  2274. //
  2275. #if ALLOCATEIRPS
  2276. // Allocate the IRP directly.
  2277. //
  2278. pIrp = IoAllocateIrp(
  2279. pTdix->pAddress->DeviceObject->StackSize, FALSE );
  2280. #else
  2281. // Allocate a "receive datagram" IRP with base initialization.
  2282. //
  2283. pIrp =
  2284. TdiBuildInternalDeviceControlIrp(
  2285. TDI_RECEIVE_DATAGRAM,
  2286. pTdix->pAddress->DeviceObject,
  2287. pTdix->pAddress,
  2288. NULL,
  2289. NULL );
  2290. #endif
  2291. if (!pIrp)
  2292. {
  2293. // Not a whole lot we can do with this unlikely error from inside
  2294. // this handler, so we just ignore the datagram.
  2295. //
  2296. FreeBufferToPool( pTdix->pPoolNdisBuffers, pBuffer, TRUE );
  2297. FREE_TDIXRDGINFO( pTdix, pRdg );
  2298. ASSERT( !"Alloc IRP?" );
  2299. return STATUS_SUCCESS;
  2300. }
  2301. pNdisBuffer = NdisBufferFromBuffer( pBuffer );
  2302. // Complete the "receive datagram" IRP initialization.
  2303. //
  2304. TdiBuildReceiveDatagram(
  2305. pIrp,
  2306. pTdix->pAddress->DeviceObject,
  2307. pTdix->pAddress,
  2308. TdixReceiveDatagramComplete,
  2309. pRdg,
  2310. pNdisBuffer,
  2311. 0,
  2312. NULL,
  2313. NULL,
  2314. 0 );
  2315. // Adjust the IRP's stack location to make the transport's stack
  2316. // current. Normally IoCallDriver handles this, but this IRP doesn't
  2317. // go thru IoCallDriver. Seems like it would be the transport's job
  2318. // to make this adjustment, but IP for one doesn't seem to do it.
  2319. // There is a similar adjustment in both the redirector and PPTP.
  2320. //
  2321. IoSetNextIrpStackLocation( pIrp );
  2322. *IoRequestPacket = pIrp;
  2323. *BytesTaken = 0;
  2324. return STATUS_MORE_PROCESSING_REQUIRED;
  2325. }
  2326. else
  2327. {
  2328. // The common case where all the information is immediately available.
  2329. // Copy it to from the transport buffer and call client's completion
  2330. // handler directly. See bug 329371.
  2331. //
  2332. NdisMoveMemory( pBuffer, (CHAR* )Tsdu, BytesIndicated );
  2333. TdixReceiveDatagramComplete( NULL, NULL, pRdg );
  2334. *IoRequestPacket = NULL;
  2335. *BytesTaken = BytesIndicated;
  2336. return STATUS_SUCCESS;
  2337. }
  2338. // Not reached.
  2339. }
  2340. NTSTATUS
  2341. TdixReceiveDatagramComplete(
  2342. IN PDEVICE_OBJECT DeviceObject,
  2343. IN PIRP Irp,
  2344. IN PVOID Context )
  2345. // Standard NT I/O completion routine. See DDK doc. Called with a NULL
  2346. // 'DeviceObject' and 'Irp' to complete the fast-past Irp-less receives.
  2347. //
  2348. {
  2349. TDIXRDGINFO* pRdg;
  2350. BOOLEAN fBad;
  2351. ULONG ulOffset;
  2352. pRdg = (TDIXRDGINFO* )Context;
  2353. TRACE( TL_N, TM_Tdi, ( "TdixRecvDgComp" ) );
  2354. fBad = FALSE;
  2355. ulOffset = 0;
  2356. if (pRdg->pTdix->mediatype == TMT_RawIp)
  2357. {
  2358. UCHAR uchVersion;
  2359. // The raw IP stack doesn't strip the IP header from the received
  2360. // datagram for some reason, so calculate the offset to the "real"
  2361. // data at the end of the IP header.
  2362. //
  2363. uchVersion = *((UCHAR* )pRdg->pBuffer) >> 4;
  2364. if (uchVersion == 4)
  2365. {
  2366. // Good, it's IP version 4. Find the length of the IP header,
  2367. // which can vary depending on the presence of option fields.
  2368. //
  2369. ulOffset = (*((UCHAR* )pRdg->pBuffer) & 0x0F) * sizeof(ULONG);
  2370. }
  2371. else
  2372. {
  2373. // It's not IP version 4, the only version we handle.
  2374. //
  2375. TRACE( TL_A, TM_Tdi, ( "Not IPv4? v=%d?", (ULONG )uchVersion ) );
  2376. fBad = TRUE;
  2377. }
  2378. }
  2379. if (!fBad && (!Irp || Irp->IoStatus.Status == STATUS_SUCCESS))
  2380. {
  2381. // Pass the result to the TDIX client's handler.
  2382. //
  2383. pRdg->pTdix->pReceiveHandler(
  2384. pRdg->pTdix,
  2385. pRdg,
  2386. pRdg->pBuffer,
  2387. ulOffset,
  2388. pRdg->ulBufferLen );
  2389. }
  2390. // Free the read-datagram context.
  2391. //
  2392. FREE_TDIXRDGINFO( pRdg->pTdix, pRdg );
  2393. #if ALLOCATEIRPS
  2394. // Release the IRP resources, if any, and tell the I/O manager to forget
  2395. // it existed in the standard way.
  2396. //
  2397. if (Irp)
  2398. {
  2399. IoFreeIrp( Irp );
  2400. return STATUS_MORE_PROCESSING_REQUIRED;
  2401. }
  2402. #endif
  2403. // Let the I/O manager release the IRP resources, if any.
  2404. //
  2405. return STATUS_SUCCESS;
  2406. }
  2407. TDIXROUTE*
  2408. TdixRouteFromIpAddress(
  2409. IN TDIXCONTEXT* pTdix,
  2410. IN ULONG ulIpAddress)
  2411. // Returns the host route context associated with IP address 'ulIpAddress'
  2412. // from the TDIX context 'pTdix's list of host routes, or NULL if none.
  2413. // 'UlIpAddress' is in network byte order.
  2414. //
  2415. // IMPORTANT: The caller must hold 'pTdix->lock'.
  2416. //
  2417. {
  2418. LIST_ENTRY* pLink;
  2419. for (pLink = pTdix->listRoutes.Flink;
  2420. pLink != &pTdix->listRoutes;
  2421. pLink = pLink->Flink)
  2422. {
  2423. TDIXROUTE* pRoute;
  2424. pRoute = CONTAINING_RECORD( pLink, TDIXROUTE, linkRoutes );
  2425. if (pRoute->ulIpAddress == ulIpAddress)
  2426. {
  2427. return pRoute;
  2428. }
  2429. }
  2430. return NULL;
  2431. }
  2432. NTSTATUS
  2433. TdixSendComplete(
  2434. IN PDEVICE_OBJECT DeviceObject,
  2435. IN PIRP Irp,
  2436. IN PVOID Context )
  2437. // Standard NT I/O completion routine. See DDK doc.
  2438. //
  2439. {
  2440. TDIXSDGINFO* pSdg;
  2441. DBG_if (Irp->IoStatus.Status != STATUS_SUCCESS)
  2442. {
  2443. TRACE( TL_A, TM_Tdi, ( "TdixSendComp, s=$%08x?",
  2444. Irp->IoStatus.Status ) );
  2445. }
  2446. pSdg = (TDIXSDGINFO* )Context;
  2447. // Pass the result to the TDIX client's handler.
  2448. //
  2449. pSdg->pSendCompleteHandler(
  2450. pSdg->pTdix, pSdg->pContext1, pSdg->pContext2, pSdg->pBuffer );
  2451. // Free the send-complete context.
  2452. //
  2453. FREE_TDIXSDGINFO( pSdg->pTdix, pSdg );
  2454. #if ALLOCATEIRPS
  2455. // Release the IRP resources and tell the I/O manager to forget it existed
  2456. // in the standard way.
  2457. //
  2458. IoFreeIrp( Irp );
  2459. return STATUS_MORE_PROCESSING_REQUIRED;
  2460. #else
  2461. // Let the I/O manager release the IRP resources.
  2462. //
  2463. return STATUS_SUCCESS;
  2464. #endif
  2465. }
  2466. NTSTATUS
  2467. TdixSendDatagramComplete(
  2468. IN PDEVICE_OBJECT DeviceObject,
  2469. IN PIRP Irp,
  2470. IN PVOID Context )
  2471. // Standard NT I/O completion routine. See DDK doc.
  2472. //
  2473. {
  2474. TDIXSDGINFO* pSdg;
  2475. DBG_if (Irp->IoStatus.Status != STATUS_SUCCESS)
  2476. {
  2477. TRACE( TL_A, TM_Tdi, ( "TdixSendDgComp, s=$%08x?",
  2478. Irp->IoStatus.Status ) );
  2479. }
  2480. pSdg = (TDIXSDGINFO* )Context;
  2481. // Pass the result to the TDIX client's handler.
  2482. //
  2483. pSdg->pSendCompleteHandler(
  2484. pSdg->pTdix, pSdg->pContext1, pSdg->pContext2, pSdg->pBuffer );
  2485. // Free the send-complete context.
  2486. //
  2487. FREE_TDIXSDGINFO( pSdg->pTdix, pSdg );
  2488. #if ALLOCATEIRPS
  2489. // Release the IRP resources and tell the I/O manager to forget it existed
  2490. // in the standard way.
  2491. //
  2492. IoFreeIrp( Irp );
  2493. return STATUS_MORE_PROCESSING_REQUIRED;
  2494. #else
  2495. // Let the I/O manager release the IRP resources.
  2496. //
  2497. return STATUS_SUCCESS;
  2498. #endif
  2499. }
  2500. NTSTATUS
  2501. TdixConnectAddrInterface(
  2502. FILE_OBJECT* pFileObj,
  2503. HANDLE hFileHandle,
  2504. TDIXROUTE* pTdixRoute
  2505. )
  2506. {
  2507. NTSTATUS status;
  2508. PDEVICE_OBJECT pDeviceObj;
  2509. PIO_STACK_LOCATION pIrpSp;
  2510. IO_STATUS_BLOCK iosb;
  2511. PIRP pIrp;
  2512. TCP_REQUEST_SET_INFORMATION_EX* pInfo;
  2513. CHAR achBuf[ sizeof(*pInfo) + sizeof(ULONG) ];
  2514. ULONG ulValue;
  2515. TDI_CONNECTION_INFORMATION RequestConnInfo;
  2516. KEVENT Event;
  2517. TA_IP_ADDRESS taip;
  2518. TDI_ADDRESS_IP* pTdiIp;
  2519. KEVENT event;
  2520. pDeviceObj = IoGetRelatedDeviceObject( pFileObj );
  2521. #if 0
  2522. KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
  2523. pIrp = TdiBuildInternalDeviceControlIrp(TDI_ASSOCIATE_ADDRESS,
  2524. pDeviceObj,
  2525. pFileObj,
  2526. &Event,
  2527. &iosb);
  2528. if (!pIrp) {
  2529. TRACE( TL_A, TM_Tdi, ( "SetIfcIndex Associate Irp?" ) );
  2530. return !STATUS_SUCCESS;
  2531. }
  2532. TdiBuildAssociateAddress(pIrp,
  2533. pDeviceObj,
  2534. pFileObj,
  2535. NULL,
  2536. NULL,
  2537. hFileHandle);
  2538. status = IoCallDriver( pDeviceObj, pIrp );
  2539. if (status == STATUS_PENDING) {
  2540. KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, 0);
  2541. }
  2542. if (iosb.Status != STATUS_SUCCESS)
  2543. {
  2544. TRACE( TL_A, TM_Tdi, ( "SetIfcIndex Associate=%x?", status ) );
  2545. return (iosb.Status);
  2546. }
  2547. #endif
  2548. pInfo = (TCP_REQUEST_SET_INFORMATION_EX* )achBuf;
  2549. pInfo->ID.toi_entity.tei_entity = CL_TL_ENTITY;
  2550. pInfo->ID.toi_entity.tei_instance = 0;
  2551. pInfo->ID.toi_class = INFO_CLASS_PROTOCOL;
  2552. pInfo->ID.toi_type = INFO_TYPE_ADDRESS_OBJECT;
  2553. pInfo->ID.toi_id = AO_OPTION_IP_UCASTIF;
  2554. ulValue = pTdixRoute->InterfaceIndex;
  2555. NdisMoveMemory( pInfo->Buffer, &ulValue, sizeof(ulValue) );
  2556. pInfo->BufferSize = sizeof(ulValue);
  2557. KeInitializeEvent(&event, SynchronizationEvent, FALSE);
  2558. pIrp = IoBuildDeviceIoControlRequest(
  2559. IOCTL_TCP_WSH_SET_INFORMATION_EX,
  2560. pDeviceObj,
  2561. (PVOID )pInfo,
  2562. sizeof(*pInfo) + sizeof(ulValue),
  2563. NULL,
  2564. 0,
  2565. FALSE,
  2566. &event,
  2567. &iosb );
  2568. if (!pIrp)
  2569. {
  2570. TRACE( TL_A, TM_Tdi, ( "SetIfcIndex Irp?" ) );
  2571. return !STATUS_SUCCESS;
  2572. }
  2573. pIrpSp = IoGetNextIrpStackLocation( pIrp );
  2574. pIrpSp->FileObject = pFileObj;
  2575. status = IoCallDriver( pDeviceObj, pIrp );
  2576. if (status == STATUS_PENDING) {
  2577. KeWaitForSingleObject(&event,
  2578. Executive,
  2579. KernelMode,
  2580. FALSE,
  2581. NULL);
  2582. status = iosb.Status;
  2583. }
  2584. if (status != STATUS_SUCCESS)
  2585. {
  2586. TRACE( TL_A, TM_Tdi, ( "SetIfcIndex=%x?", status ) );
  2587. return status;
  2588. }
  2589. KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
  2590. pIrp = TdiBuildInternalDeviceControlIrp(TDI_CONNECT,
  2591. pDeviceObj,
  2592. pFileObj,
  2593. &Event,
  2594. &iosb);
  2595. if (!pIrp) {
  2596. TRACE( TL_A, TM_Tdi, ( "SetIfcIndex ConnectIrp?" ) );
  2597. return !STATUS_SUCCESS;
  2598. }
  2599. // Put the destination IP address in the "connection" structure as TDI
  2600. // expects.
  2601. //
  2602. taip.TAAddressCount = 1;
  2603. taip.Address[ 0 ].AddressLength = TDI_ADDRESS_LENGTH_IP;
  2604. taip.Address[ 0 ].AddressType = TDI_ADDRESS_TYPE_IP;
  2605. pTdiIp = &taip.Address[ 0 ].Address[ 0 ];
  2606. pTdiIp->sin_port = pTdixRoute->sPort;
  2607. pTdiIp->in_addr = pTdixRoute->ulIpAddress;
  2608. NdisZeroMemory( pTdiIp->sin_zero, sizeof(pTdiIp->sin_zero) );
  2609. RequestConnInfo.Options = NULL;
  2610. RequestConnInfo.OptionsLength = 0;
  2611. RequestConnInfo.RemoteAddress = &taip;
  2612. RequestConnInfo.RemoteAddressLength = sizeof(taip);
  2613. RequestConnInfo.UserData = NULL;
  2614. RequestConnInfo.UserDataLength = 0;
  2615. TdiBuildConnect(pIrp,
  2616. pDeviceObj,
  2617. pFileObj,
  2618. NULL,
  2619. NULL,
  2620. 0,
  2621. &RequestConnInfo,
  2622. NULL);
  2623. status = IoCallDriver( pDeviceObj, pIrp );
  2624. if (status == STATUS_PENDING) {
  2625. KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, 0);
  2626. }
  2627. if (iosb.Status != STATUS_SUCCESS)
  2628. {
  2629. TRACE( TL_A, TM_Tdi, ( "SetIfcIndex Connect=%x?", status ) );
  2630. return (iosb.Status);
  2631. }
  2632. return (STATUS_SUCCESS);
  2633. }