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.

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