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.

2297 lines
57 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. routing\ip\ipinip\tdix.c
  5. Abstract:
  6. Interface to TDI
  7. Revision History:
  8. Derived from Steve Cobb's ndis\l2tp code
  9. About ALLOCATEIRPS:
  10. This driver is lower level code than typical TDI drivers. It has locked
  11. MDL-mapped input buffers readily available and does not need to provide any
  12. mapping to user mode client requests on completion. This allows a
  13. performance gain from allocating and deallocating IRPs directly, thus
  14. avoiding unnecessary setup in TdiBuildInternalDeviceControlIrp and
  15. unnecessary APC queuing in IoCompleteRequest. Define ALLOCATEIRPs=1 to
  16. make this optimization, or define it 0 to use the strictly TDI-compliant
  17. TdiBuildInternalDeviceControlIrp method.
  18. About NDISBUFFERISMDL:
  19. Calls to TdiBuildSendDatagram assume the NDIS_BUFFER can be passed in place
  20. of an MDL which avoids a pointless copy. If this is not the case, an
  21. explicit MDL buffer would need to be allocated and caller's buffer copied
  22. to the MDL buffer before sending. Same issue for TdiBuildReceiveDatagram,
  23. except of course that the copy would be from the MDL buffer to caller's
  24. buffer after receiving.
  25. --*/
  26. #define __FILE_SIG__ TDIX_SIG
  27. #include "inc.h"
  28. #if NDISBUFFERISMDL
  29. #else
  30. #error Additional code to copy NDIS_BUFFER to/from MDL NYI.
  31. #endif
  32. //
  33. // The Handle for the IP in IP (proto 4) transport address
  34. //
  35. HANDLE g_hIpIpHandle;
  36. //
  37. // The pointer to the file object for the above handle
  38. //
  39. PFILE_OBJECT g_pIpIpFileObj;
  40. //
  41. // The Handle for the ICMP (proto 1) transport address
  42. //
  43. HANDLE g_hIcmpHandle;
  44. //
  45. // The pointer to the file object for the above handle
  46. //
  47. PFILE_OBJECT g_pIcmpFileObj;
  48. //
  49. // Handle for address changes
  50. //
  51. HANDLE g_hAddressChange;
  52. NPAGED_LOOKASIDE_LIST g_llSendCtxtBlocks;
  53. NPAGED_LOOKASIDE_LIST g_llTransferCtxtBlocks;
  54. NPAGED_LOOKASIDE_LIST g_llQueueNodeBlocks;
  55. #pragma alloc_text(PAGE, TdixInitialize)
  56. VOID
  57. TdixInitialize(
  58. PVOID pvContext
  59. )
  60. /*++
  61. Routine Description
  62. Initialize the TDI related globals.
  63. Open the TDI transport address for Raw IP, protocol number 4.
  64. Sets the address object for HEADER_INCLUDE
  65. Also opens Raw IP for ICMP (used to manager TUNNEL MTU)
  66. Register to receive datagrams at the selected handler
  67. Locks
  68. This call must be made at PASSIVE IRQL.
  69. Arguments
  70. None
  71. Return Value
  72. STATUS_SUCCESS if successful
  73. STATUS_UNSUCCESSFUL otherwise
  74. --*/
  75. {
  76. PIRP pIrp;
  77. IO_STATUS_BLOCK iosb;
  78. NTSTATUS nStatus;
  79. TDIObjectID *pTdiObjId;
  80. KEVENT keWait;
  81. POPEN_CONTEXT pOpenCtxt;
  82. PIO_STACK_LOCATION pIrpSp;
  83. TCP_REQUEST_SET_INFORMATION_EX tcpSetInfo;
  84. TDI_CLIENT_INTERFACE_INFO tdiInterface;
  85. TraceEnter(TDI, "TdixInitialize");
  86. PAGED_CODE();
  87. pOpenCtxt = (POPEN_CONTEXT)pvContext;
  88. //
  89. // Init the Handle and pointer to file object for RAW IP
  90. //
  91. g_hIpIpHandle = NULL;
  92. g_pIpIpFileObj = NULL;
  93. g_hIcmpHandle = NULL;
  94. g_pIcmpFileObj = NULL;
  95. //
  96. // Initialize lookaside lists for our send and receive contexts
  97. //
  98. ExInitializeNPagedLookasideList(&g_llSendCtxtBlocks,
  99. NULL,
  100. NULL,
  101. 0,
  102. sizeof(SEND_CONTEXT),
  103. SEND_CONTEXT_TAG,
  104. SEND_CONTEXT_LOOKASIDE_DEPTH);
  105. ExInitializeNPagedLookasideList(&g_llTransferCtxtBlocks,
  106. NULL,
  107. NULL,
  108. 0,
  109. sizeof(TRANSFER_CONTEXT),
  110. TRANSFER_CONTEXT_TAG,
  111. TRANSFER_CONTEXT_LOOKASIDE_DEPTH);
  112. ExInitializeNPagedLookasideList(&g_llQueueNodeBlocks,
  113. NULL,
  114. NULL,
  115. 0,
  116. sizeof(QUEUE_NODE),
  117. QUEUE_NODE_TAG,
  118. QUEUE_NODE_LOOKASIDE_DEPTH);
  119. InitializeListHead(&g_leAddressList);
  120. //
  121. // Open file and handle objects for both IP in IP and ICMP
  122. //
  123. nStatus = TdixOpenRawIp(PROTO_IPINIP,
  124. &g_hIpIpHandle,
  125. &g_pIpIpFileObj);
  126. if(nStatus isnot STATUS_SUCCESS)
  127. {
  128. Trace(TDI, ERROR,
  129. ("TdixInitialize: Couldnt open raw IP for IP in IP\n"));
  130. TdixDeinitialize(g_pIpIpDevice,
  131. NULL);
  132. TraceLeave(TDI, "TdixInitialize");
  133. pOpenCtxt->nStatus = nStatus;
  134. KeSetEvent(pOpenCtxt->pkeEvent,
  135. 0,
  136. FALSE);
  137. return;
  138. }
  139. nStatus = TdixOpenRawIp(PROTO_ICMP,
  140. &g_hIcmpHandle,
  141. &g_pIcmpFileObj);
  142. if(nStatus isnot STATUS_SUCCESS)
  143. {
  144. Trace(TDI, ERROR,
  145. ("TdixInitialize: Couldnt open raw IP for ICMP\n"));
  146. TdixDeinitialize(g_pIpIpDevice,
  147. NULL);
  148. TraceLeave(TDI, "TdixInitialize");
  149. pOpenCtxt->nStatus = nStatus;
  150. KeSetEvent(pOpenCtxt->pkeEvent,
  151. 0,
  152. FALSE);
  153. return;
  154. }
  155. //
  156. // Set HeaderInclude option on this AddressObject
  157. //
  158. tcpSetInfo.BufferSize = 1;
  159. tcpSetInfo.Buffer[0] = TRUE;
  160. pTdiObjId = &tcpSetInfo.ID;
  161. pTdiObjId->toi_entity.tei_entity = CL_TL_ENTITY;
  162. pTdiObjId->toi_entity.tei_instance = 0;
  163. pTdiObjId->toi_class = INFO_CLASS_PROTOCOL;
  164. pTdiObjId->toi_type = INFO_TYPE_ADDRESS_OBJECT;
  165. pTdiObjId->toi_id = AO_OPTION_IP_HDRINCL;
  166. //
  167. // Init the event needed to wait on the IRP
  168. //
  169. KeInitializeEvent(&keWait,
  170. SynchronizationEvent,
  171. FALSE);
  172. pIrp = IoBuildDeviceIoControlRequest(IOCTL_TCP_SET_INFORMATION_EX,
  173. g_pIpIpFileObj->DeviceObject,
  174. (PVOID)&tcpSetInfo,
  175. sizeof(TCP_REQUEST_SET_INFORMATION_EX),
  176. NULL,
  177. 0,
  178. FALSE,
  179. &keWait,
  180. &iosb);
  181. if (pIrp is NULL)
  182. {
  183. Trace(TDI, ERROR,
  184. ("TdixInitialize: Couldnt build Irp for IP\n"));
  185. nStatus = STATUS_UNSUCCESSFUL;
  186. }
  187. else
  188. {
  189. //
  190. // Io subsystem doesnt do anything for us in kernel mode
  191. // so we need to set up the IRP ourselves
  192. //
  193. pIrpSp = IoGetNextIrpStackLocation(pIrp);
  194. pIrpSp->FileObject = g_pIpIpFileObj;
  195. //
  196. // Submit the request to the forwarder
  197. //
  198. nStatus = IoCallDriver(g_pIpIpFileObj->DeviceObject,
  199. pIrp);
  200. if(nStatus isnot STATUS_SUCCESS)
  201. {
  202. if(nStatus is STATUS_PENDING)
  203. {
  204. Trace(TDI, INFO,
  205. ("TdixInitialize: IP returned pending when setting HDRINCL option\n"));
  206. KeWaitForSingleObject(&keWait,
  207. Executive,
  208. KernelMode,
  209. FALSE,
  210. 0);
  211. nStatus = STATUS_SUCCESS;
  212. }
  213. }
  214. }
  215. if(nStatus isnot STATUS_SUCCESS)
  216. {
  217. Trace(TDI, ERROR,
  218. ("TdixInitialize: IOCTL to IP Forwarder for HDRINCL failed %x\n",
  219. nStatus));
  220. TdixDeinitialize(g_pIpIpDevice,
  221. NULL);
  222. TraceLeave(TDI, "TdixInitialize");
  223. pOpenCtxt->nStatus = nStatus;
  224. KeSetEvent(pOpenCtxt->pkeEvent,
  225. 0,
  226. FALSE);
  227. return;
  228. }
  229. //
  230. // Install our receive datagram handler. Caller's 'pReceiveHandler' will
  231. // be called by our handler when a datagram arrives and TDI business is
  232. // out of the way.
  233. //
  234. nStatus = TdixInstallEventHandler(g_pIpIpFileObj,
  235. TDI_EVENT_RECEIVE_DATAGRAM,
  236. TdixReceiveIpIpDatagram,
  237. NULL);
  238. if(nStatus isnot STATUS_SUCCESS)
  239. {
  240. Trace(TDI, ERROR,
  241. ("TdixOpen: Status %x installing IpIpReceiveDatagram Event\n",
  242. nStatus));
  243. TdixDeinitialize(g_pIpIpDevice,
  244. NULL);
  245. TraceLeave(TDI, "TdixInitialize");
  246. pOpenCtxt->nStatus = nStatus;
  247. KeSetEvent(pOpenCtxt->pkeEvent,
  248. 0,
  249. FALSE);
  250. return;
  251. }
  252. nStatus = TdixInstallEventHandler(g_pIcmpFileObj,
  253. TDI_EVENT_RECEIVE_DATAGRAM,
  254. TdixReceiveIcmpDatagram,
  255. NULL);
  256. if(nStatus isnot STATUS_SUCCESS)
  257. {
  258. Trace(TDI, ERROR,
  259. ("TdixOpen: Status %x installing IcmpReceiveDatagram Event\n",
  260. nStatus));
  261. TdixDeinitialize(g_pIpIpDevice,
  262. NULL);
  263. TraceLeave(TDI, "TdixInitialize");
  264. pOpenCtxt->nStatus = nStatus;
  265. KeSetEvent(pOpenCtxt->pkeEvent,
  266. 0,
  267. FALSE);
  268. return;
  269. }
  270. RtlZeroMemory(&tdiInterface,
  271. sizeof(TDI_CLIENT_INTERFACE_INFO));
  272. tdiInterface.MajorTdiVersion = TDI_CURRENT_MAJOR_VERSION;
  273. tdiInterface.MinorTdiVersion = TDI_CURRENT_MINOR_VERSION;
  274. tdiInterface.AddAddressHandlerV2 = TdixAddressArrival;
  275. tdiInterface.DelAddressHandlerV2 = TdixAddressDeletion;
  276. TdiRegisterPnPHandlers(&tdiInterface,
  277. sizeof(TDI_CLIENT_INTERFACE_INFO),
  278. &g_hAddressChange);
  279. pOpenCtxt->nStatus = STATUS_SUCCESS;
  280. KeSetEvent(pOpenCtxt->pkeEvent,
  281. 0,
  282. FALSE);
  283. TraceLeave(TDI, "TdixInitialize");
  284. return;
  285. }
  286. #pragma alloc_text(PAGE, TdixOpenRawIp)
  287. NTSTATUS
  288. TdixOpenRawIp(
  289. IN DWORD dwProtoId,
  290. OUT HANDLE *phAddrHandle,
  291. OUT FILE_OBJECT **ppAddrFileObj
  292. )
  293. /*++
  294. Routine Description
  295. This routine opens a Raw IP transport address for a given protocol
  296. Locks
  297. None
  298. Arguments
  299. dwProtoId Protocol to be opened
  300. phAddrHandle Pointer to transport Address Handle opened
  301. ppAddrFileObject Pointer to pointer to file object for transport address
  302. handle
  303. Return Value
  304. STATUS_SUCCESS
  305. --*/
  306. {
  307. ULONG ulEaLength;
  308. BYTE rgbyEa[100];
  309. WCHAR rgwcRawIpDevice[sizeof(DD_RAW_IP_DEVICE_NAME) + 10];
  310. WCHAR rgwcProtocolNumber[10];
  311. NTSTATUS nStatus;
  312. OBJECT_ATTRIBUTES oa;
  313. IO_STATUS_BLOCK iosb;
  314. PTA_IP_ADDRESS pTaIp;
  315. PTDI_ADDRESS_IP pTdiIp;
  316. UNICODE_STRING usDevice;
  317. UNICODE_STRING usProtocolNumber;
  318. HANDLE hTransportAddrHandle;
  319. PFILE_OBJECT pTransportAddrFileObj;
  320. PFILE_FULL_EA_INFORMATION pEa;
  321. PAGED_CODE();
  322. TraceEnter(TDI, "TdixOpenRawIp");
  323. *phAddrHandle = NULL;
  324. *ppAddrFileObj = NULL;
  325. //
  326. // FILE_FULL_EA_INFORMATION wants null terminated buffers now
  327. //
  328. RtlZeroMemory(rgbyEa,
  329. sizeof(rgbyEa));
  330. RtlZeroMemory(rgwcRawIpDevice,
  331. sizeof(rgwcRawIpDevice));
  332. RtlZeroMemory(rgwcProtocolNumber,
  333. sizeof(rgwcProtocolNumber));
  334. //
  335. // Set up parameters needed to open the transport address. First, the
  336. // object attributes.
  337. //
  338. //
  339. // Build the raw IP device name as a counted string. The device name
  340. // is followed by a path separator then the protocol number of
  341. // interest.
  342. //
  343. usDevice.Buffer = rgwcRawIpDevice;
  344. usDevice.Length = 0;
  345. usDevice.MaximumLength = sizeof(rgwcRawIpDevice);
  346. RtlAppendUnicodeToString(&usDevice,
  347. DD_RAW_IP_DEVICE_NAME);
  348. usDevice.Buffer[usDevice.Length/sizeof(WCHAR)] = OBJ_NAME_PATH_SEPARATOR;
  349. usDevice.Length += sizeof(WCHAR);
  350. usProtocolNumber.Buffer = rgwcProtocolNumber;
  351. usProtocolNumber.MaximumLength = sizeof(rgwcProtocolNumber);
  352. RtlIntegerToUnicodeString((ULONG)dwProtoId,
  353. 10,
  354. &usProtocolNumber);
  355. RtlAppendUnicodeStringToString(&usDevice,
  356. &usProtocolNumber);
  357. RtAssert(usDevice.Length < sizeof(rgwcRawIpDevice));
  358. InitializeObjectAttributes(&oa,
  359. &usDevice,
  360. OBJ_CASE_INSENSITIVE,
  361. NULL,
  362. NULL);
  363. //
  364. // Set up the extended attribute that tells the IP stack the IP
  365. // address/port on which we want to receive.
  366. // We "bind" to INADDR_ANY
  367. //
  368. RtAssert((sizeof(FILE_FULL_EA_INFORMATION) +
  369. TDI_TRANSPORT_ADDRESS_LENGTH +
  370. sizeof(TA_IP_ADDRESS))
  371. <= 100);
  372. pEa = (PFILE_FULL_EA_INFORMATION)rgbyEa;
  373. pEa->NextEntryOffset = 0;
  374. pEa->Flags = 0;
  375. pEa->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
  376. pEa->EaValueLength = sizeof(TA_IP_ADDRESS);
  377. NdisMoveMemory(pEa->EaName,
  378. TdiTransportAddress,
  379. TDI_TRANSPORT_ADDRESS_LENGTH);
  380. //
  381. // Note: The unused byte represented by the "+ 1" below is to match up
  382. // with what the IP stack expects, though it doesn't appear in the
  383. // current docs.
  384. //
  385. pTaIp = (PTA_IP_ADDRESS)(pEa->EaName + TDI_TRANSPORT_ADDRESS_LENGTH + 1);
  386. pTaIp->TAAddressCount = 1;
  387. pTaIp->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
  388. pTaIp->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
  389. pTdiIp = &(pTaIp->Address[0].Address[0]);
  390. pTdiIp->sin_port = 0;
  391. pTdiIp->in_addr = 0;
  392. NdisZeroMemory(pTdiIp->sin_zero,
  393. sizeof(pTdiIp->sin_zero));
  394. ulEaLength = (ULONG) ((UINT_PTR)(pTaIp + 1) - (UINT_PTR)pEa);
  395. //
  396. // Open the transport address.
  397. // Settin FILE_SHARE_READ|FILE_SHARE_WRITE is equivalent to the
  398. // SO_REUSEADDR option
  399. //
  400. nStatus = ZwCreateFile(&hTransportAddrHandle,
  401. FILE_READ_DATA | FILE_WRITE_DATA,
  402. &oa,
  403. &iosb,
  404. NULL,
  405. FILE_ATTRIBUTE_NORMAL,
  406. 0,
  407. FILE_OPEN,
  408. 0,
  409. pEa,
  410. ulEaLength);
  411. if(nStatus isnot STATUS_SUCCESS)
  412. {
  413. Trace(TDI, ERROR,
  414. ("TdixOpenRawIp: Unable to open %S. Status %x\n",
  415. usDevice.Buffer,
  416. nStatus));
  417. TraceLeave(TDI, "TdixOpenRawIp");
  418. return STATUS_UNSUCCESSFUL;
  419. }
  420. //
  421. // Get the object address from the handle. This also checks our
  422. // permissions on the object.
  423. //
  424. nStatus = ObReferenceObjectByHandle(hTransportAddrHandle,
  425. 0,
  426. NULL,
  427. KernelMode,
  428. &pTransportAddrFileObj,
  429. NULL);
  430. if(nStatus isnot STATUS_SUCCESS)
  431. {
  432. Trace(TDI, ERROR,
  433. ("TdixOpenRawIp: Unable to open object for handle %x. Status %x\n",
  434. hTransportAddrHandle,
  435. nStatus));
  436. TraceLeave(TDI, "TdixOpenRawIp");
  437. return STATUS_UNSUCCESSFUL;
  438. }
  439. *phAddrHandle = hTransportAddrHandle;
  440. *ppAddrFileObj = pTransportAddrFileObj;
  441. TraceLeave(TDI, "TdixOpenRawIp");
  442. return STATUS_SUCCESS;
  443. }
  444. #pragma alloc_text(PAGE, TdixDeinitialize)
  445. VOID
  446. TdixDeinitialize(
  447. IN PDEVICE_OBJECT pDeviceObject,
  448. IN PVOID pvContext
  449. )
  450. /*++
  451. Routine Description
  452. Undo TdixInitialize actions
  453. Locks
  454. This call must be made at PASSIVE IRQL in the context of the system process
  455. Arguments
  456. pvContext
  457. Return Value
  458. None
  459. --*/
  460. {
  461. POPEN_CONTEXT pOpenCtxt;
  462. PAGED_CODE();
  463. TraceEnter(TDI, "TdixDeinitialize");
  464. UNREFERENCED_PARAMETER(pDeviceObject);
  465. pOpenCtxt = (POPEN_CONTEXT)pvContext;
  466. if(g_hAddressChange isnot NULL)
  467. {
  468. TdiDeregisterPnPHandlers(g_hAddressChange);
  469. }
  470. ExDeleteNPagedLookasideList(&g_llSendCtxtBlocks);
  471. ExDeleteNPagedLookasideList(&g_llTransferCtxtBlocks);
  472. ExDeleteNPagedLookasideList(&g_llQueueNodeBlocks);
  473. if(g_pIpIpFileObj)
  474. {
  475. //
  476. // Install a NULL handler, effectively uninstalling.
  477. //
  478. TdixInstallEventHandler(g_pIpIpFileObj,
  479. TDI_EVENT_RECEIVE_DATAGRAM,
  480. NULL,
  481. NULL);
  482. ObDereferenceObject(g_pIpIpFileObj);
  483. g_pIpIpFileObj = NULL;
  484. }
  485. if(g_hIpIpHandle)
  486. {
  487. ZwClose(g_hIpIpHandle);
  488. g_hIpIpHandle = NULL;
  489. }
  490. if(g_pIcmpFileObj)
  491. {
  492. TdixInstallEventHandler(g_pIcmpFileObj,
  493. TDI_EVENT_RECEIVE_DATAGRAM,
  494. NULL,
  495. NULL);
  496. ObDereferenceObject(g_pIcmpFileObj);
  497. g_pIcmpFileObj = NULL;
  498. }
  499. if(g_hIcmpHandle)
  500. {
  501. ZwClose(g_hIcmpHandle);
  502. g_hIcmpHandle = NULL;
  503. }
  504. if(pOpenCtxt)
  505. {
  506. KeSetEvent(pOpenCtxt->pkeEvent,
  507. 0,
  508. FALSE);
  509. }
  510. TraceLeave(TDI, "TdixDeinitialize");
  511. }
  512. #pragma alloc_text(PAGE, TdixInstallEventHandler)
  513. NTSTATUS
  514. TdixInstallEventHandler(
  515. IN PFILE_OBJECT pAddrFileObj,
  516. IN INT iEventType,
  517. IN PVOID pfnEventHandler,
  518. IN PVOID pvEventContext
  519. )
  520. /*++
  521. Routine Description
  522. Install a TDI event handler routine
  523. Locks
  524. The call must be made at PASSIVE
  525. Arguments
  526. iEventType The event for which the handler is to be set
  527. pfnEventHandler The event handler
  528. pvEventContext The context passed to the event handler
  529. Return Value
  530. STATUS_INSUFFICIENT_RESOURCES
  531. STATUS_SUCCESS
  532. --*/
  533. {
  534. NTSTATUS nStatus;
  535. PIRP pIrp;
  536. PAGED_CODE();
  537. TraceEnter(TDI, "TdixInstallEventHandler");
  538. //
  539. // Allocate a "set event" IRP with base initialization.
  540. //
  541. pIrp = TdiBuildInternalDeviceControlIrp(
  542. TDI_SET_EVENT_HANDLER,
  543. pAddrFileObj->DeviceObject,
  544. pAddrFileObj,
  545. NULL,
  546. NULL);
  547. if(pIrp is NULL)
  548. {
  549. Trace(TDI, ERROR,
  550. ("TdixInstallEventHandler: Could not allocate IRP\n"));
  551. return STATUS_INSUFFICIENT_RESOURCES;
  552. }
  553. //
  554. // Complete the "set event" IRP initialization.
  555. //
  556. TdiBuildSetEventHandler(pIrp,
  557. pAddrFileObj->DeviceObject,
  558. pAddrFileObj,
  559. NULL,
  560. NULL,
  561. iEventType,
  562. pfnEventHandler,
  563. pvEventContext);
  564. /*
  565. Trace(GLOBAL, ERROR,
  566. ("**FileObj 0x%x Irp 0x%x fscontext to callee 0x%x\n",
  567. pAddrFileObj,
  568. pIrp,
  569. IoGetNextIrpStackLocation(pIrp)->FileObject));
  570. */
  571. //
  572. // Tell the I/O manager to pass our IRP to the transport for processing.
  573. //
  574. nStatus = IoCallDriver(pAddrFileObj->DeviceObject,
  575. pIrp);
  576. if(nStatus isnot STATUS_SUCCESS)
  577. {
  578. Trace(TDI, ERROR,
  579. ("TdixInstallEventHandler: Error %X sending IRP\n",
  580. nStatus));
  581. }
  582. TraceLeave(TDI, "TdixInstallEventHandler");
  583. return nStatus;
  584. }
  585. VOID
  586. TdixAddressArrival(
  587. PTA_ADDRESS pAddr,
  588. PUNICODE_STRING pusDeviceName,
  589. PTDI_PNP_CONTEXT pContext
  590. )
  591. /*++
  592. Routine Description
  593. Our handler called by TDI whenever a new address is added to the
  594. system
  595. We see if this is an IP Address and if we have any tunnels that
  596. use this address as an endpoint. If any do, then we mark all those
  597. tunnels as up
  598. Locks
  599. Acquires the g_rwlTunnelLock as WRITER.
  600. Also locks each of the tunnels
  601. Arguments
  602. pAddr
  603. pusDeviceName
  604. pContext
  605. Return Value
  606. --*/
  607. {
  608. KIRQL kiIrql;
  609. PADDRESS_BLOCK pAddrBlock;
  610. PTDI_ADDRESS_IP pTdiIpAddr;
  611. PLIST_ENTRY pleNode;
  612. TraceEnter(TDI, "TdixAddressArrival");
  613. if(pAddr->AddressType isnot TDI_ADDRESS_TYPE_IP)
  614. {
  615. TraceLeave(TDI, "TdixAddressArrival");
  616. return;
  617. }
  618. RtAssert(pAddr->AddressLength >= sizeof(TDI_ADDRESS_IP));
  619. pTdiIpAddr = (PTDI_ADDRESS_IP)pAddr->Address;
  620. Trace(TDI, TRACE,
  621. ("TdixAddressArrival: New address %d.%d.%d.%d\n",
  622. PRINT_IPADDR(pTdiIpAddr->in_addr)));
  623. EnterWriter(&g_rwlTunnelLock,
  624. &kiIrql);
  625. pAddrBlock = GetAddressBlock(pTdiIpAddr->in_addr);
  626. if(pAddrBlock isnot NULL)
  627. {
  628. RtAssert(pAddrBlock->dwAddress is pTdiIpAddr->in_addr);
  629. if(pAddrBlock->bAddressPresent is TRUE)
  630. {
  631. Trace(TDI, ERROR,
  632. ("TdixAddressArrival: Multiple notification on %d.%d.%d.%d\n",
  633. PRINT_IPADDR(pTdiIpAddr->in_addr)));
  634. ExitWriter(&g_rwlTunnelLock,
  635. kiIrql);
  636. TraceLeave(TDI, "TdixAddressArrival");
  637. return;
  638. }
  639. pAddrBlock->bAddressPresent = TRUE;
  640. }
  641. else
  642. {
  643. pAddrBlock = RtAllocate(NonPagedPool,
  644. sizeof(ADDRESS_BLOCK),
  645. TUNNEL_TAG);
  646. if(pAddrBlock is NULL)
  647. {
  648. Trace(TDI, ERROR,
  649. ("TdixAddressArrival: Unable to allocate address block\n"));
  650. ExitWriter(&g_rwlTunnelLock,
  651. kiIrql);
  652. TraceLeave(TDI, "TdixAddressArrival");
  653. return;
  654. }
  655. pAddrBlock->dwAddress = pTdiIpAddr->in_addr;
  656. pAddrBlock->bAddressPresent = TRUE;
  657. InitializeListHead(&(pAddrBlock->leTunnelList));
  658. InsertHeadList(&g_leAddressList,
  659. &(pAddrBlock->leAddressLink));
  660. }
  661. //
  662. // Walk the list of tunnels on this address and
  663. // set them up
  664. //
  665. for(pleNode = pAddrBlock->leTunnelList.Flink;
  666. pleNode isnot &(pAddrBlock->leTunnelList);
  667. pleNode = pleNode->Flink)
  668. {
  669. PTUNNEL pTunnel;
  670. DWORD dwLocalNet;
  671. RouteCacheEntry *pDummyRce;
  672. BYTE byType;
  673. USHORT usMtu;
  674. IPOptInfo OptInfo;
  675. pTunnel = CONTAINING_RECORD(pleNode,
  676. TUNNEL,
  677. leAddressLink);
  678. RtAcquireSpinLockAtDpcLevel(&(pTunnel->rlLock));
  679. RtAssert(pTunnel->LOCALADDR is pTdiIpAddr->in_addr);
  680. RtAssert(pTunnel->dwOperState is IF_OPER_STATUS_NON_OPERATIONAL);
  681. pTunnel->dwAdminState |= TS_ADDRESS_PRESENT;
  682. if(GetAdminState(pTunnel) is IF_ADMIN_STATUS_UP)
  683. {
  684. pTunnel->dwOperState = IF_OPER_STATUS_OPERATIONAL;
  685. //
  686. // See if the remote address is reachable and what the MTU is.
  687. //
  688. UpdateMtuAndReachability(pTunnel);
  689. }
  690. RtReleaseSpinLockFromDpcLevel(&(pTunnel->rlLock));
  691. }
  692. ExitWriter(&g_rwlTunnelLock,
  693. kiIrql);
  694. TraceLeave(TDI, "TdixAddressArrival");
  695. return;
  696. }
  697. VOID
  698. TdixAddressDeletion(
  699. PTA_ADDRESS pAddr,
  700. PUNICODE_STRING pusDeviceName,
  701. PTDI_PNP_CONTEXT pContext
  702. )
  703. /*++
  704. Routine Description
  705. Our handler called by TDI whenever an address is removed from to the
  706. system
  707. We see if this is an IP Address and if we have any tunnels that
  708. use this address as an endpoint. If any do, then we mark all those
  709. tunnels as down
  710. Locks
  711. Acquires the g_rwlTunnelLock as WRITER.
  712. Also locks each of the tunnels
  713. Arguments
  714. pAddr
  715. pusDeviceName
  716. pContext
  717. Return Value
  718. --*/
  719. {
  720. KIRQL kiIrql;
  721. PADDRESS_BLOCK pAddrBlock;
  722. PTDI_ADDRESS_IP pTdiIpAddr;
  723. PLIST_ENTRY pleNode;
  724. TraceEnter(TDI, "TdixAddressDeletion");
  725. if(pAddr->AddressType isnot TDI_ADDRESS_TYPE_IP)
  726. {
  727. TraceLeave(TDI, "TdixAddressDeletion");
  728. return;
  729. }
  730. RtAssert(pAddr->AddressLength >= sizeof(TDI_ADDRESS_IP));
  731. pTdiIpAddr = (PTDI_ADDRESS_IP)pAddr->Address;
  732. Trace(TDI, TRACE,
  733. ("TdixAddressDeletion: Address %d.%d.%d.%d\n",
  734. PRINT_IPADDR(pTdiIpAddr->in_addr)));
  735. EnterWriter(&g_rwlTunnelLock,
  736. &kiIrql);
  737. pAddrBlock = GetAddressBlock(pTdiIpAddr->in_addr);
  738. if(pAddrBlock is NULL)
  739. {
  740. ExitWriter(&g_rwlTunnelLock,
  741. kiIrql);
  742. TraceLeave(TDI, "TdixAddressDeletion");
  743. return;
  744. }
  745. RtAssert(pAddrBlock->dwAddress is pTdiIpAddr->in_addr);
  746. RtAssert(pAddrBlock->bAddressPresent);
  747. //
  748. // Walk the list of tunnels on this address and
  749. // set them down
  750. //
  751. for(pleNode = pAddrBlock->leTunnelList.Flink;
  752. pleNode isnot &(pAddrBlock->leTunnelList);
  753. pleNode = pleNode->Flink)
  754. {
  755. PTUNNEL pTunnel;
  756. pTunnel = CONTAINING_RECORD(pleNode,
  757. TUNNEL,
  758. leAddressLink);
  759. RtAcquireSpinLockAtDpcLevel(&(pTunnel->rlLock));
  760. RtAssert(pTunnel->LOCALADDR is pTdiIpAddr->in_addr);
  761. RtAssert(pTunnel->dwAdminState & TS_ADDRESS_PRESENT);
  762. RtAssert(IsTunnelMapped(pTunnel));
  763. pTunnel->dwOperState = IF_OPER_STATUS_NON_OPERATIONAL;
  764. //
  765. // Reset the admin state to UP/DOWN|MAPPED (It has to be mapped)
  766. //
  767. pTunnel->dwAdminState = GetAdminState(pTunnel);
  768. MarkTunnelMapped(pTunnel);
  769. RtReleaseSpinLockFromDpcLevel(&(pTunnel->rlLock));
  770. }
  771. ExitWriter(&g_rwlTunnelLock,
  772. kiIrql);
  773. TraceLeave(TDI, "TdixAddressDeletion");
  774. return;
  775. }
  776. NTSTATUS
  777. TdixReceiveIpIpDatagram(
  778. IN PVOID pvTdiEventContext,
  779. IN LONG lSourceAddressLen,
  780. IN PVOID pvSourceAddress,
  781. IN LONG plOptionsLen,
  782. IN PVOID pvOptions,
  783. IN ULONG ulReceiveDatagramFlags,
  784. IN ULONG ulBytesIndicated,
  785. IN ULONG ulBytesAvailable,
  786. OUT PULONG pulBytesTaken,
  787. IN PVOID pvTsdu,
  788. OUT IRP **ppIoRequestPacket
  789. )
  790. /*++
  791. Routine Description
  792. ClientEventReceiveDatagram indication handler. We figure out the
  793. tunnel with which to associate the lookahead data. We increment some
  794. stats and then indicate the data to IP (taking care to skip over the
  795. outer IP header) along with a receive context.
  796. If all the data is there, IP copies the data out and returns.
  797. Otherwise IP requests a TransferData.
  798. In our TransferData function, we set a flag in the receive context (the
  799. same one is being passed around) to indicate the IP requested a
  800. TransferData, and return PENDING.
  801. The control then returns back to this function. We look at the pXferCtxt
  802. to see if IP requested a transfer, and if so, we call
  803. TdiBuildReceiveDatagram() to create the IRP to pass back to complete
  804. the receive.
  805. There is some funky stuff that needs to be done with offsets into the
  806. lookahead as well as destination buffers and care should be taken to
  807. understand those before change is made to the code.
  808. Locks
  809. Runs at DISPATCH IRQL.
  810. Arguments
  811. Return Value
  812. NO_ERROR
  813. --*/
  814. {
  815. PTRANSFER_CONTEXT pXferCtxt;
  816. PNDIS_BUFFER pnbFirstBuffer;
  817. PVOID pvData;
  818. PIRP pIrp;
  819. PIP_HEADER pOutHeader, pInHeader;
  820. ULARGE_INTEGER uliTunnelId;
  821. PTA_IP_ADDRESS ptiaAddress;
  822. PTUNNEL pTunnel;
  823. ULONG ulOutHdrLen, ulDataLen;
  824. BOOLEAN bNonUnicast;
  825. TraceEnter(RCV, "TdixReceiveIpIp");
  826. //
  827. // The TSDU is the data and NOT the MDL
  828. //
  829. pvData = (PVOID)pvTsdu;
  830. //
  831. // Figure out the tunnel for this receive
  832. // Since the transport indicates atleast 128 bytes, we can safely read out
  833. // the IP Header
  834. //
  835. RtAssert(ulBytesIndicated > sizeof(IP_HEADER));
  836. pOutHeader = (PIP_HEADER)pvData;
  837. RtAssert(pOutHeader->byProtocol is PROTO_IPINIP);
  838. RtAssert((pOutHeader->byVerLen >> 4) is IP_VERSION_4);
  839. //
  840. // These defines depend upon a variable being named "uliTunnelId"
  841. //
  842. REMADDR = pOutHeader->dwSrc;
  843. LOCALADDR = pOutHeader->dwDest;
  844. //
  845. // Make sure that the source address given and the IP Header are in
  846. // synch
  847. //
  848. ptiaAddress = (PTA_IP_ADDRESS)pvSourceAddress;
  849. //
  850. // Bunch of checks to make sure the packet and the handler
  851. // are telling us the same thing
  852. //
  853. RtAssert(lSourceAddressLen is sizeof(TA_IP_ADDRESS));
  854. RtAssert(ptiaAddress->TAAddressCount is 1);
  855. RtAssert(ptiaAddress->Address[0].AddressType is TDI_ADDRESS_TYPE_IP);
  856. RtAssert(ptiaAddress->Address[0].AddressLength is TDI_ADDRESS_LENGTH_IP);
  857. RtAssert(ptiaAddress->Address[0].Address[0].in_addr is pOutHeader->dwSrc);
  858. //
  859. // Get a pointer to the inside header. By TDI spec we should get
  860. // enough data to get at the inner header
  861. //
  862. ulDataLen = RtlUshortByteSwap(pOutHeader->wLength);
  863. ulOutHdrLen = LengthOfIPHeader(pOutHeader);
  864. if(ulDataLen < ulOutHdrLen + MIN_IP_HEADER_LENGTH)
  865. {
  866. //
  867. // Malformed packet. Doesnt have a inner header
  868. //
  869. Trace(RCV, ERROR,
  870. ("TdixReceiveIpIp: Packet %d.%d.%d.%d -> %d.%d.%d.%d had size %d\n",
  871. PRINT_IPADDR(pOutHeader->dwSrc),
  872. PRINT_IPADDR(pOutHeader->dwDest),
  873. ulDataLen));
  874. TraceLeave(RCV, "TdixReceiveIpIp");
  875. return STATUS_DATA_NOT_ACCEPTED;
  876. }
  877. //
  878. // This cant be more than 128 (60 + 20)
  879. //
  880. RtAssert(ulBytesIndicated > ulOutHdrLen + MIN_IP_HEADER_LENGTH);
  881. pInHeader = (PIP_HEADER)((PBYTE)pOutHeader + ulOutHdrLen);
  882. //
  883. // If the inside header is also IP in IP and is for one of our tunnels,
  884. // drop the packet. If we dont, someone could build a series of
  885. // encapsulated headers which would cause this function to be called
  886. // recursively making us overflow our stack. Ofcourse, a better fix
  887. // would be to switch processing to another thread at this point
  888. // for multiply encapsulated packets, but that is too much work; so
  889. // currently we just dont allow an IP in IP tunnel within an IP in IP
  890. // tunnel
  891. //
  892. if(pInHeader->byProtocol is PROTO_IPINIP)
  893. {
  894. ULARGE_INTEGER uliInsideId;
  895. PTUNNEL pInTunnel;
  896. //
  897. // See if this is for us
  898. //
  899. uliInsideId.LowPart = pInHeader->dwSrc;
  900. uliInsideId.HighPart = pInHeader->dwDest;
  901. //
  902. // Find the TUNNEL. We need to acquire the tunnel lock
  903. //
  904. EnterReaderAtDpcLevel(&g_rwlTunnelLock);
  905. pInTunnel = FindTunnel(&uliInsideId);
  906. ExitReaderFromDpcLevel(&g_rwlTunnelLock);
  907. if(pInTunnel isnot NULL)
  908. {
  909. RtReleaseSpinLockFromDpcLevel(&(pInTunnel->rlLock));
  910. DereferenceTunnel(pInTunnel);
  911. Trace(RCV, WARN,
  912. ("TdixReceiveIpIp: Packet on tunnel for %d.%d.%d.%d/%d.%d.%d.%d contained another IPinIP packet for tunnel %d.%d.%d.%d/%d.%d.%d.%d\n",
  913. PRINT_IPADDR(REMADDR),
  914. PRINT_IPADDR(LOCALADDR),
  915. PRINT_IPADDR(uliInsideId.LowPart),
  916. PRINT_IPADDR(uliInsideId.HighPart)));
  917. TraceLeave(RCV, "TdixReceiveIpIp");
  918. return STATUS_DATA_NOT_ACCEPTED;
  919. }
  920. }
  921. #if DBG
  922. //
  923. // The size of the inner data must be total bytes - outer header
  924. //
  925. ulDataLen = RtlUshortByteSwap(pInHeader->wLength);
  926. RtAssert((ulDataLen + ulOutHdrLen) is ulBytesAvailable);
  927. //
  928. // The outer header should also give a good length
  929. //
  930. ulDataLen = RtlUshortByteSwap(pOutHeader->wLength);
  931. //
  932. // Data length and bytes available must match
  933. //
  934. RtAssert(ulDataLen is ulBytesAvailable);
  935. #endif
  936. //
  937. // Find the TUNNEL. We need to acquire the tunnel lock
  938. //
  939. EnterReaderAtDpcLevel(&g_rwlTunnelLock);
  940. pTunnel = FindTunnel(&uliTunnelId);
  941. ExitReaderFromDpcLevel(&g_rwlTunnelLock);
  942. if(pTunnel is NULL)
  943. {
  944. Trace(RCV, WARN,
  945. ("TdixReceiveIpIp: Couldnt find tunnel for %d.%d.%d.%d/%d.%d.%d.%d\n",
  946. PRINT_IPADDR(REMADDR),
  947. PRINT_IPADDR(LOCALADDR)));
  948. //
  949. // Could not find a matching tunnel
  950. //
  951. TraceLeave(RCV, "TdixReceiveIpIp");
  952. return STATUS_DATA_NOT_ACCEPTED;
  953. }
  954. //
  955. // Ok, so we have the tunnel and it is ref counted and locked
  956. //
  957. //
  958. // The number of octets received
  959. //
  960. pTunnel->ulInOctets += ulBytesAvailable;
  961. //
  962. // Check the actual (inside) destination
  963. //
  964. if(IsUnicastAddr(pInHeader->dwDest))
  965. {
  966. //
  967. // TODO: should we check to see that the address is not 0.0.0.0?
  968. //
  969. pTunnel->ulInUniPkts++;
  970. bNonUnicast = FALSE;
  971. }
  972. else
  973. {
  974. pTunnel->ulInNonUniPkts++;
  975. if(IsClassEAddr(pInHeader->dwDest))
  976. {
  977. //
  978. // Bad address - throw it away
  979. //
  980. pTunnel->ulInErrors++;
  981. //
  982. // Releaselock, free buffer chain
  983. //
  984. }
  985. bNonUnicast = TRUE;
  986. }
  987. if(pTunnel->dwOperState isnot IF_OPER_STATUS_OPERATIONAL)
  988. {
  989. Trace(RCV, WARN,
  990. ("TdixReceiveIpIp: Tunnel %x is not up\n",
  991. pTunnel));
  992. pTunnel->ulInDiscards++;
  993. RtReleaseSpinLockFromDpcLevel(&(pTunnel->rlLock));
  994. DereferenceTunnel(pTunnel);
  995. TraceLeave(RCV, "TdixReceiveIpIp");
  996. return STATUS_DATA_NOT_ACCEPTED;
  997. }
  998. //
  999. // Allocate a receive context
  1000. //
  1001. pXferCtxt = AllocateTransferContext();
  1002. if(pXferCtxt is NULL)
  1003. {
  1004. Trace(RCV, ERROR,
  1005. ("TdixReceiveIpIp: Couldnt allocate transfer context\n"));
  1006. //
  1007. // Could not allocate context, free the data, unlock and deref
  1008. // the tunnel
  1009. //
  1010. pTunnel->ulInDiscards++;
  1011. RtReleaseSpinLockFromDpcLevel(&(pTunnel->rlLock));
  1012. DereferenceTunnel(pTunnel);
  1013. TraceLeave(RCV, "TdixReceiveIpIp");
  1014. return STATUS_DATA_NOT_ACCEPTED;
  1015. }
  1016. //
  1017. // Fill in the read-datagram context with the information that won't
  1018. // otherwise be available in the completion routine.
  1019. //
  1020. pXferCtxt->pTunnel = pTunnel;
  1021. //
  1022. // Ok, all statistics are done.
  1023. // Release the lock on the tunnel and indicate the data (or part
  1024. // thereof) to IP
  1025. //
  1026. RtReleaseSpinLockFromDpcLevel(&(pTunnel->rlLock));
  1027. //
  1028. // The data starts at pInHeader
  1029. // We indicate (ulBytesIndicated - outer header length) up to IP
  1030. // The total data is the (ulBytesAvailable - outer header)
  1031. // We associate a TRANSFER_CONTEXT with this indication,
  1032. // The Protocol Offset is just our outer header
  1033. //
  1034. pXferCtxt->bRequestTransfer = FALSE;
  1035. #if PROFILE
  1036. KeQueryTickCount((PLARGE_INTEGER)&(pXferCtxt->llRcvTime));
  1037. #endif
  1038. g_pfnIpRcv(pTunnel->pvIpContext,
  1039. pInHeader,
  1040. ulBytesIndicated - ulOutHdrLen,
  1041. ulBytesAvailable - ulOutHdrLen,
  1042. pXferCtxt,
  1043. ulOutHdrLen,
  1044. bNonUnicast,
  1045. NULL);
  1046. //
  1047. // IP calls our TransferData synchronously, and since we also handle
  1048. // that call synchronously. If IP requests a data transfer, we set
  1049. // bRequestTransfer to true in the pXferCtxt
  1050. //
  1051. if(pXferCtxt->bRequestTransfer is FALSE)
  1052. {
  1053. #if PROFILE
  1054. LONGLONG llTime;
  1055. KeQueryTickCount((PLARGE_INTEGER)&llTime);
  1056. llTime -= pXferCtxt->llRcvTime;
  1057. llTime *= KeQueryTimeIncrement();
  1058. Trace(RCV, ERROR,
  1059. ("Profile: Rcv took %d.%d units\n",
  1060. ((PLARGE_INTEGER)&llTime)->HighPart,
  1061. ((PLARGE_INTEGER)&llTime)->LowPart));
  1062. #endif
  1063. Trace(RCV, TRACE,
  1064. ("TdixReceiveIpIp: IP did not request transfer\n"));
  1065. //
  1066. // For some reason or another IP did not want this packet
  1067. // We are done with it
  1068. //
  1069. FreeTransferContext(pXferCtxt);
  1070. DereferenceTunnel(pTunnel);
  1071. TraceLeave(RCV, "TdixReceiveIpIp");
  1072. return STATUS_SUCCESS;
  1073. }
  1074. //
  1075. // Make sure that the things looks the same before and after the call
  1076. //
  1077. RtAssert(pXferCtxt->pvContext is pTunnel);
  1078. RtAssert(pXferCtxt->uiProtoOffset is ulOutHdrLen);
  1079. //
  1080. // Should not be asking to transfer more than was indicated
  1081. //
  1082. RtAssert(pXferCtxt->uiTransferLength <= ulBytesAvailable);
  1083. //
  1084. // So IP did want it transferred
  1085. //
  1086. #if ALLOCATEIRPS
  1087. //
  1088. // Allocate the IRP directly.
  1089. //
  1090. pIrp = IoAllocateIrp(g_pIpIpFileObj->DeviceObject->StackSize,
  1091. FALSE);
  1092. #else
  1093. //
  1094. // Allocate a "receive datagram" IRP with base initialization.
  1095. //
  1096. pIrp = TdiBuildInternalDeviceControlIrp(TDI_RECEIVE_DATAGRAM,
  1097. g_pIpIpFileObj->DeviceObject,
  1098. g_pIpIpFileObj,
  1099. NULL,
  1100. NULL);
  1101. #endif
  1102. if(!pIrp)
  1103. {
  1104. Trace(RCV, ERROR,
  1105. ("TdixReceiveIpIp: Unable to build IRP for receive\n"));
  1106. pTunnel->ulInDiscards++;
  1107. FreeTransferContext(pXferCtxt);
  1108. //
  1109. // Call IP's TDComplete to signal the failure of this
  1110. // transfer
  1111. //
  1112. DereferenceTunnel(pTunnel);
  1113. TraceLeave(RCV, "TdixReceiveIpIp");
  1114. return STATUS_DATA_NOT_ACCEPTED;
  1115. }
  1116. //
  1117. // IP gives us an NDIS_PACKET to which to transfer data
  1118. // TDI wants just an MDL chain
  1119. //
  1120. #if NDISBUFFERISMDL
  1121. NdisQueryPacket(pXferCtxt->pnpTransferPacket,
  1122. NULL,
  1123. NULL,
  1124. &pnbFirstBuffer,
  1125. NULL);
  1126. #else
  1127. #error "Fix This"
  1128. #endif
  1129. //
  1130. // Complete the "receive datagram" IRP initialization.
  1131. //
  1132. TdiBuildReceiveDatagram(pIrp,
  1133. g_pIpIpFileObj->DeviceObject,
  1134. g_pIpIpFileObj,
  1135. TdixReceiveIpIpDatagramComplete,
  1136. pXferCtxt,
  1137. pnbFirstBuffer,
  1138. pXferCtxt->uiTransferLength,
  1139. NULL,
  1140. NULL,
  1141. 0);
  1142. //
  1143. // Adjust the IRP's stack location to make the transport's stack current.
  1144. // Normally IoCallDriver handles this, but this IRP doesn't go thru
  1145. // IoCallDriver. Seems like it would be the transport's job to make this
  1146. // adjustment, but IP for one doesn't seem to do it. There is a similar
  1147. // adjustment in both the redirector and PPTP.
  1148. //
  1149. IoSetNextIrpStackLocation(pIrp);
  1150. *ppIoRequestPacket = pIrp;
  1151. *pulBytesTaken = pXferCtxt->uiTransferOffset + ulOutHdrLen;
  1152. //
  1153. // we DONT dereference the TUNNEL here
  1154. // That is done in the completion routine
  1155. //
  1156. TraceLeave(RCV, "TdixReceiveIpIp");
  1157. return STATUS_MORE_PROCESSING_REQUIRED;
  1158. }
  1159. NTSTATUS
  1160. TdixReceiveIpIpDatagramComplete(
  1161. IN PDEVICE_OBJECT DeviceObject,
  1162. IN PIRP Irp,
  1163. IN PVOID Context
  1164. )
  1165. /*++
  1166. Routine Description
  1167. Standard I/O completion routine.
  1168. Called to signal the completion of a receive. The context is the
  1169. TRANSFER_CONTEXT setup with TdiBuildReceiveDatagram.
  1170. Locks
  1171. Takes the TUNNEL's lock.
  1172. Arguments
  1173. Return Value
  1174. STATUS_SUCCESS
  1175. --*/
  1176. {
  1177. PTRANSFER_CONTEXT pXferCtxt;
  1178. PTUNNEL pTunnel;
  1179. LONGLONG llTime;
  1180. TraceEnter(RCV, "TdixReceiveIpIpDatagramComplete");
  1181. pXferCtxt = (PTRANSFER_CONTEXT) Context;
  1182. //
  1183. // The tunnel has been referenced but not locked
  1184. //
  1185. pTunnel = pXferCtxt->pTunnel;
  1186. RtAssert(pXferCtxt->uiTransferLength is Irp->IoStatus.Information);
  1187. g_pfnIpTDComplete(pTunnel->pvIpContext,
  1188. pXferCtxt->pnpTransferPacket,
  1189. Irp->IoStatus.Status,
  1190. (ULONG)(Irp->IoStatus.Information));
  1191. #if PROFILE
  1192. KeQueryTickCount((PLARGE_INTEGER)&llTime);
  1193. Trace(RCV, ERROR,
  1194. ("Profile: %d.%d %d.%d\n",
  1195. ((PLARGE_INTEGER)&llTime)->HighPart,
  1196. ((PLARGE_INTEGER)&llTime)->LowPart,
  1197. ((PLARGE_INTEGER)&pXferCtxt->llRcvTime)->HighPart,
  1198. ((PLARGE_INTEGER)&pXferCtxt->llRcvTime)->LowPart));
  1199. llTime -= pXferCtxt->llRcvTime;
  1200. llTime *= KeQueryTimeIncrement();
  1201. Trace(RCV, ERROR,
  1202. ("Profile: Rcv took %d.%d units\n",
  1203. ((PLARGE_INTEGER)&llTime)->HighPart,
  1204. ((PLARGE_INTEGER)&llTime)->LowPart));
  1205. #endif
  1206. FreeTransferContext(pXferCtxt);
  1207. //
  1208. // Deref the tunnel (finally)
  1209. //
  1210. DereferenceTunnel(pTunnel);
  1211. #if ALLOCATEIRPS
  1212. //
  1213. // Releae the IRP resources and tell the I/O manager to forget it existed
  1214. // in the standard way.
  1215. //
  1216. IoFreeIrp(Irp);
  1217. TraceLeave(RCV, "TdixReceiveIpIpDatagramComplete");
  1218. return STATUS_MORE_PROCESSING_REQUIRED;
  1219. #else
  1220. //
  1221. // Let the I/O manager release the IRP resources.
  1222. //
  1223. TraceLeave(RCV, "TdixReceiveIpIpDatagramComplete");
  1224. return STATUS_SUCCESS;
  1225. #endif
  1226. }
  1227. #pragma alloc_text(PAGE, TdixSendDatagram)
  1228. #if PROFILE
  1229. NTSTATUS
  1230. TdixSendDatagram(
  1231. IN PTUNNEL pTunnel,
  1232. IN PNDIS_PACKET pnpPacket,
  1233. IN PNDIS_BUFFER pnbFirstBuffer,
  1234. IN ULONG ulBufferLength,
  1235. IN LONGLONG llSendTime,
  1236. IN LONGLONG llCallTime,
  1237. IN LONGLONG llTransmitTime
  1238. )
  1239. #else
  1240. NTSTATUS
  1241. TdixSendDatagram(
  1242. IN PTUNNEL pTunnel,
  1243. IN PNDIS_PACKET pnpPacket,
  1244. IN PNDIS_BUFFER pnbFirstBuffer,
  1245. IN ULONG ulBufferLength
  1246. )
  1247. #endif
  1248. /*++
  1249. Routine Description
  1250. Sends a datagram over a tunnel. The remote endpoint is that of the tunnel
  1251. and the send complete handler is TdixSendCompleteHandler
  1252. A SendContext is associated with the send
  1253. Locks
  1254. This call needs to be at PASSIVE level
  1255. The TUNNEL needs to be ref counted but not locked
  1256. Arguments
  1257. pTunnel TUNNEL over which the datagram is to be sent
  1258. pnpPacket Packet descriptor allocate from PACKET_POOL of the tunnel
  1259. pnbFirstBuffer The first buffer in the chain (the outer IP header)
  1260. ulBufferLength The lenght of the complete packet (including outer header)
  1261. Return Value
  1262. --*/
  1263. {
  1264. NTSTATUS nStatus;
  1265. PSEND_CONTEXT pSendCtxt;
  1266. PIRP pIrp;
  1267. TraceEnter(SEND, "TdixSendDatagram");
  1268. do
  1269. {
  1270. //
  1271. // Allocate a context for this send-datagram from our lookaside list.
  1272. //
  1273. pSendCtxt = AllocateSendContext();
  1274. if(pSendCtxt is NULL)
  1275. {
  1276. Trace(SEND, ERROR,
  1277. ("TdixSendDatagram: Unable to allocate send context\n"));
  1278. nStatus = STATUS_INSUFFICIENT_RESOURCES;
  1279. break;
  1280. }
  1281. #if ALLOCATEIRPS
  1282. //
  1283. // Allocate the IRP directly.
  1284. //
  1285. pIrp = IoAllocateIrp(g_pIpIpFileObj->DeviceObject->StackSize,
  1286. FALSE);
  1287. // Trace(GLOBAL, ERROR,
  1288. // ("TdixSendDatagram: irp = 0x%x\n",pIrp));
  1289. #else
  1290. //
  1291. // Allocate a "send datagram" IRP with base initialization.
  1292. //
  1293. pIrp = TdiBuildInternalDeviceControlIrp(TDI_SEND_DATAGRAM,
  1294. g_pIpIpFileObj->DeviceObject,
  1295. g_pIpIpFileObj,
  1296. NULL,
  1297. NULL);
  1298. #endif
  1299. if(!pIrp)
  1300. {
  1301. Trace(SEND, ERROR,
  1302. ("TdixSendDatagram: Unable to build IRP\n"));
  1303. nStatus = STATUS_INSUFFICIENT_RESOURCES;
  1304. break;
  1305. }
  1306. //
  1307. // Fill in the send-datagram context.
  1308. //
  1309. pSendCtxt->pTunnel = pTunnel;
  1310. pSendCtxt->pnpPacket = pnpPacket;
  1311. pSendCtxt->ulOutOctets = ulBufferLength;
  1312. #if PROFILE
  1313. pSendCtxt->llSendTime = llSendTime;
  1314. pSendCtxt->llCallTime = llCallTime;
  1315. pSendCtxt->llTransmitTime = llTransmitTime;
  1316. #endif
  1317. //
  1318. // Complete the "send datagram" IRP initialization.
  1319. //
  1320. TdiBuildSendDatagram(pIrp,
  1321. g_pIpIpFileObj->DeviceObject,
  1322. g_pIpIpFileObj,
  1323. TdixSendDatagramComplete,
  1324. pSendCtxt,
  1325. pnbFirstBuffer,
  1326. ulBufferLength,
  1327. &(pTunnel->tciConnInfo));
  1328. //
  1329. // Tell the I/O manager to pass our IRP to the transport for
  1330. // processing.
  1331. //
  1332. #if PROFILE
  1333. KeQueryTickCount((PLARGE_INTEGER)&pSendCtxt->llCall2Time);
  1334. #endif
  1335. nStatus = IoCallDriver(g_pIpIpFileObj->DeviceObject,
  1336. pIrp);
  1337. RtAssert(nStatus is STATUS_PENDING);
  1338. nStatus = STATUS_SUCCESS;
  1339. }while (FALSE);
  1340. if(nStatus isnot STATUS_SUCCESS)
  1341. {
  1342. Trace(SEND, ERROR,
  1343. ("TdixSendDatagram: Status %X sending\n",
  1344. nStatus));
  1345. //
  1346. // Pull a half Jameel, i.e. convert a synchronous failure to an
  1347. // asynchronous failure from client's perspective. However, clean up
  1348. // context here.
  1349. //
  1350. if(pSendCtxt)
  1351. {
  1352. FreeSendContext(pSendCtxt);
  1353. }
  1354. IpIpSendComplete(nStatus,
  1355. pTunnel,
  1356. pnpPacket,
  1357. ulBufferLength);
  1358. }
  1359. TraceLeave(SEND, "TdixSendDatagram");
  1360. return STATUS_PENDING;
  1361. }
  1362. NTSTATUS
  1363. TdixSendDatagramComplete(
  1364. IN PDEVICE_OBJECT DeviceObject,
  1365. IN PIRP Irp,
  1366. IN PVOID Context
  1367. )
  1368. {
  1369. PSEND_CONTEXT pSendCtxt;
  1370. PTUNNEL pTunnel;
  1371. PNDIS_PACKET pnpPacket;
  1372. PNDIS_BUFFER pnbFirstBuffer;
  1373. ULONG ulBufferLength;
  1374. KIRQL irql;
  1375. LONGLONG llTime, llSendTime, llQTime, llTxTime, llCallTime;
  1376. ULONG ulInc;
  1377. TraceEnter(SEND, "TdixSendDatagramComplete");
  1378. pSendCtxt = (PSEND_CONTEXT) Context;
  1379. #if PROFILE
  1380. KeQueryTickCount((PLARGE_INTEGER)&llTime);
  1381. ulInc = KeQueryTimeIncrement();
  1382. llSendTime = pSendCtxt->llCallTime - pSendCtxt->llSendTime;
  1383. llSendTime *= ulInc;
  1384. llQTime = pSendCtxt->llTransmitTime - pSendCtxt->llCallTime;
  1385. llQTime *= ulInc;
  1386. llTxTime = pSendCtxt->llCall2Time - pSendCtxt->llTransmitTime;
  1387. llTxTime *= ulInc;
  1388. llCallTime = llTime - pSendCtxt->llCall2Time;
  1389. llCallTime *= ulInc;
  1390. llTime = llTime - pSendCtxt->llSendTime;
  1391. llTime *= ulInc;
  1392. DbgPrint("SendProfile: Send %d.%d Q %d.%d Tx %d.%d Call %d.%d \nTotal %d.%d\n",
  1393. ((PLARGE_INTEGER)&llSendTime)->HighPart,
  1394. ((PLARGE_INTEGER)&llSendTime)->LowPart,
  1395. ((PLARGE_INTEGER)&llQTime)->HighPart,
  1396. ((PLARGE_INTEGER)&llQTime)->LowPart,
  1397. ((PLARGE_INTEGER)&llTxTime)->HighPart,
  1398. ((PLARGE_INTEGER)&llTxTime)->LowPart,
  1399. ((PLARGE_INTEGER)&llCallTime)->HighPart,
  1400. ((PLARGE_INTEGER)&llCallTime)->LowPart,
  1401. ((PLARGE_INTEGER)&llTime)->HighPart,
  1402. ((PLARGE_INTEGER)&llTime)->LowPart);
  1403. #endif
  1404. //
  1405. // Just call our SendComplete function with the right args
  1406. //
  1407. pTunnel = pSendCtxt->pTunnel;
  1408. pnpPacket = pSendCtxt->pnpPacket;
  1409. ulBufferLength = pSendCtxt->ulOutOctets;
  1410. //
  1411. // Free the send-complete context.
  1412. //
  1413. FreeSendContext(pSendCtxt);
  1414. IpIpSendComplete(Irp->IoStatus.Status,
  1415. pTunnel,
  1416. pnpPacket,
  1417. ulBufferLength);
  1418. #if ALLOCATEIRPS
  1419. //
  1420. // Release the IRP resources and tell the I/O manager to forget it existed
  1421. // in the standard way.
  1422. //
  1423. IoFreeIrp(Irp);
  1424. TraceLeave(SEND, "TdixSendDatagramComplete");
  1425. return STATUS_MORE_PROCESSING_REQUIRED;
  1426. #else
  1427. //
  1428. // Let the I/O manager release the IRP resources.
  1429. //
  1430. TraceLeave(SEND, "TdixSendDatagramComplete");
  1431. return STATUS_SUCCESS;
  1432. #endif
  1433. }
  1434. NTSTATUS
  1435. TdixReceiveIcmpDatagram(
  1436. IN PVOID pvTdiEventContext,
  1437. IN LONG lSourceAddressLen,
  1438. IN PVOID pvSourceAddress,
  1439. IN LONG plOptionsLeng,
  1440. IN PVOID pvOptions,
  1441. IN ULONG ulReceiveDatagramFlags,
  1442. IN ULONG ulBytesIndicated,
  1443. IN ULONG ulBytesAvailable,
  1444. OUT PULONG pulBytesTaken,
  1445. IN PVOID pvTsdu,
  1446. OUT IRP **ppIoRequestPacket
  1447. )
  1448. /*++
  1449. Routine Description
  1450. ClientEventReceiveDatagram indication handler for ICMP messages.
  1451. ICMP messages are used to monitor the state of the tunnel
  1452. We currently only look for Type 3 Code 4 messages (fragmentation
  1453. needed, but don't fragment bit is set). This is done to support
  1454. PATH MTU over tunnels.
  1455. We look at the IP header inside the ICMP packet. We see if it was an
  1456. IP in IP packet that caused this ICMP message, and if so we try and match
  1457. it to one of our TUNNELS.
  1458. Locks
  1459. Runs at DISPATCH IRQL.
  1460. Arguments
  1461. Return Value
  1462. NO_ERROR
  1463. --*/
  1464. {
  1465. PVOID pvData;
  1466. PIRP pIrp;
  1467. PIP_HEADER pOutHeader, pInHeader;
  1468. PICMP_HEADER pIcmpHdr;
  1469. ULARGE_INTEGER uliTunnelId;
  1470. PTA_IP_ADDRESS ptiaAddress;
  1471. PTUNNEL pTunnel;
  1472. ULONG ulOutHdrLen, ulDataLen, ulIcmpLen;
  1473. BOOLEAN bNonUnicast;
  1474. PICMP_HANDLER pfnHandler;
  1475. NTSTATUS nStatus;
  1476. pfnHandler = NULL;
  1477. //
  1478. // The TSDU is the data and NOT the MDL
  1479. //
  1480. pvData = (PVOID)pvTsdu;
  1481. //
  1482. // Figure out the tunnel for this receive
  1483. // Since the transport indicates atleast 128 bytes, we can safely read out
  1484. // the IP Header
  1485. //
  1486. RtAssert(ulBytesIndicated > sizeof(IP_HEADER));
  1487. pOutHeader = (PIP_HEADER)pvData;
  1488. RtAssert(pOutHeader->byProtocol is PROTO_ICMP);
  1489. RtAssert(pOutHeader->byVerLen >> 4 is IP_VERSION_4);
  1490. //
  1491. // Since the ICMP packet is small, we expect all the data to be
  1492. // give to us, instead of having to do a transfer data
  1493. //
  1494. ulDataLen = RtlUshortByteSwap(pOutHeader->wLength);
  1495. ulOutHdrLen = LengthOfIPHeader(pOutHeader);
  1496. if(ulDataLen < ulOutHdrLen + sizeof(ICMP_HEADER))
  1497. {
  1498. //
  1499. // Malformed packet. Doesnt have a inner header
  1500. //
  1501. Trace(RCV, ERROR,
  1502. ("TdixReceiveIcmp: Packet %d.%d.%d.%d -> %d.%d.%d.%d had size %d\n",
  1503. PRINT_IPADDR(pOutHeader->dwSrc),
  1504. PRINT_IPADDR(pOutHeader->dwDest),
  1505. ulDataLen));
  1506. return STATUS_DATA_NOT_ACCEPTED;
  1507. }
  1508. //
  1509. // This cant be more than 128 (60 + 4)
  1510. //
  1511. RtAssert(ulBytesIndicated > ulOutHdrLen + sizeof(ICMP_HEADER));
  1512. pIcmpHdr = (PICMP_HEADER)((PBYTE)pOutHeader + ulOutHdrLen);
  1513. ulIcmpLen = ulDataLen - ulOutHdrLen;
  1514. //
  1515. // See if this is one of the types we are interested in
  1516. //
  1517. switch(pIcmpHdr->byType)
  1518. {
  1519. case ICMP_TYPE_DEST_UNREACHABLE:
  1520. {
  1521. //
  1522. // Only interested in codes 0 - 4
  1523. //
  1524. if(pIcmpHdr->byCode > ICMP_CODE_DGRAM_TOO_BIG)
  1525. {
  1526. return STATUS_DATA_NOT_ACCEPTED;
  1527. }
  1528. if(ulIcmpLen < (DEST_UNREACH_LENGTH + MIN_IP_HEADER_LENGTH))
  1529. {
  1530. //
  1531. // Not enough data to get at the tunnel
  1532. //
  1533. return STATUS_DATA_NOT_ACCEPTED;
  1534. }
  1535. pInHeader = (PIP_HEADER)((ULONG_PTR)pIcmpHdr + DEST_UNREACH_LENGTH);
  1536. pfnHandler = HandleDestUnreachable;
  1537. break;
  1538. }
  1539. case ICMP_TYPE_TIME_EXCEEDED:
  1540. {
  1541. if(ulIcmpLen < (TIME_EXCEED_LENGTH + MIN_IP_HEADER_LENGTH))
  1542. {
  1543. //
  1544. // Not enough data to get at the tunnel
  1545. //
  1546. return STATUS_DATA_NOT_ACCEPTED;
  1547. }
  1548. pInHeader = (PIP_HEADER)((PBYTE)pIcmpHdr + TIME_EXCEED_LENGTH);
  1549. pfnHandler = HandleTimeExceeded;
  1550. break;
  1551. }
  1552. case ICMP_TYPE_PARAM_PROBLEM:
  1553. default:
  1554. {
  1555. //
  1556. // Not interested in this
  1557. //
  1558. return STATUS_DATA_NOT_ACCEPTED;
  1559. }
  1560. }
  1561. //
  1562. // See if the packet that caused the ICMP was an IP in IP packet
  1563. //
  1564. if(pInHeader->byProtocol isnot PROTO_IPINIP)
  1565. {
  1566. //
  1567. // Someother packet caused this
  1568. //
  1569. return STATUS_DATA_NOT_ACCEPTED;
  1570. }
  1571. //
  1572. // See if we can find a tunnel associated with the original packet
  1573. // These defines depend upon a variable being named "uliTunnelId"
  1574. //
  1575. REMADDR = pInHeader->dwDest;
  1576. LOCALADDR = pInHeader->dwSrc;
  1577. //
  1578. // Make sure that the source address given and the IP Header are in
  1579. // synch
  1580. //
  1581. ptiaAddress = (PTA_IP_ADDRESS)pvSourceAddress;
  1582. //
  1583. // Bunch of checks to make sure the packet and the handler
  1584. // are telling us the same thing
  1585. //
  1586. RtAssert(lSourceAddressLen is sizeof(TA_IP_ADDRESS));
  1587. RtAssert(ptiaAddress->TAAddressCount is 1);
  1588. RtAssert(ptiaAddress->Address[0].AddressType is TDI_ADDRESS_TYPE_IP);
  1589. RtAssert(ptiaAddress->Address[0].AddressLength is TDI_ADDRESS_LENGTH_IP);
  1590. RtAssert(ptiaAddress->Address[0].Address[0].in_addr is pOutHeader->dwSrc);
  1591. //
  1592. // Find the TUNNEL. We need to acquire the tunnel lock
  1593. //
  1594. EnterReaderAtDpcLevel(&g_rwlTunnelLock);
  1595. pTunnel = FindTunnel(&uliTunnelId);
  1596. ExitReaderFromDpcLevel(&g_rwlTunnelLock);
  1597. if(pTunnel is NULL)
  1598. {
  1599. //
  1600. // Could not find a matching tunnel
  1601. //
  1602. return STATUS_DATA_NOT_ACCEPTED;
  1603. }
  1604. //
  1605. // Ok, so we have the tunnel and it is ref counted and locked
  1606. //
  1607. nStatus = pfnHandler(pTunnel,
  1608. pIcmpHdr,
  1609. pInHeader);
  1610. RtReleaseSpinLockFromDpcLevel(&(pTunnel->rlLock));
  1611. DereferenceTunnel(pTunnel);
  1612. return STATUS_SUCCESS;
  1613. }