Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1302 lines
26 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. ipinip\ioctl.c
  5. Abstract:
  6. IOCTL handlers for IP in IP encapsulation driver
  7. Author:
  8. Amritansh Raghav
  9. Revision History:
  10. AmritanR Created
  11. Notes:
  12. --*/
  13. #define __FILE_SIG__ IOCT_SIG
  14. #include "inc.h"
  15. NTSTATUS
  16. AddTunnelInterface(
  17. IN PIRP pIrp,
  18. IN ULONG ulInLength,
  19. IN ULONG ulOutLength
  20. )
  21. /*++
  22. Routine Description
  23. This is the handler for IOCTL_IPINIP_CREATE_TUNNEL. We do the normal
  24. buffer length checks.
  25. Locks
  26. None
  27. Arguments
  28. pIrp IRP
  29. ulInLength The length of the Input Buffer
  30. ulOutLength The length of the Output Buffer
  31. Return Value
  32. STATUS_SUCCESS
  33. STATUS_BUFFER_TOO_SMALL
  34. STATUS_INFO_LENGTH_MISMATCH
  35. STATUS_INVALID_PARAMETER
  36. --*/
  37. {
  38. PVOID pvIoBuffer;
  39. NTSTATUS nStatus;
  40. PTUNNEL pTunnel;
  41. KIRQL irql;
  42. ULONG i, ulMaxLength;
  43. BOOLEAN bTerminated;
  44. DWORD dwNewIndex;
  45. PIPINIP_CREATE_TUNNEL pCreateInfo;
  46. TraceEnter(TUNN, "AddTunnelInterface");
  47. //
  48. // Get the user buffer
  49. //
  50. pvIoBuffer = pIrp->AssociatedIrp.SystemBuffer;
  51. pCreateInfo = (PIPINIP_CREATE_TUNNEL)pvIoBuffer;
  52. //
  53. // Always clean out the information field
  54. //
  55. pIrp->IoStatus.Information = 0;
  56. if(ulInLength < sizeof(IPINIP_CREATE_TUNNEL))
  57. {
  58. Trace(TUNN, ERROR,
  59. ("AddTunnelInterface: In Length %d too small\n",
  60. ulInLength));
  61. TraceLeave(TUNN, "AddTunnelInterface");
  62. return STATUS_BUFFER_TOO_SMALL;
  63. }
  64. if(ulOutLength < sizeof(IPINIP_CREATE_TUNNEL))
  65. {
  66. Trace(TUNN, ERROR,
  67. ("AddTunnelInterface: Out Length %d too small\n",
  68. ulInLength));
  69. TraceLeave(TUNN, "AddTunnelInterface");
  70. return STATUS_BUFFER_TOO_SMALL;
  71. }
  72. nStatus = IpIpCreateAdapter(pCreateInfo,
  73. 0,
  74. &dwNewIndex);
  75. if(nStatus is STATUS_SUCCESS)
  76. {
  77. pIrp->IoStatus.Information = sizeof(IPINIP_CREATE_TUNNEL);
  78. pCreateInfo->dwIfIndex = dwNewIndex;
  79. }
  80. TraceLeave(TUNN, "AddTunnelInterface");
  81. return nStatus;
  82. }
  83. NTSTATUS
  84. DeleteTunnelInterface(
  85. IN PIRP pIrp,
  86. IN ULONG ulInLength,
  87. IN ULONG ulOutLength
  88. )
  89. /*++
  90. Routine Description
  91. This is the handler for IOCTL_IPINIP_DELETE_TUNNEL.
  92. Locks
  93. Takes the tunnel list lock as writer and the tunnel lock
  94. Arguments
  95. pIrp IRP
  96. ulInLength The length of the Input Buffer
  97. ulOutLength The length of the Output Buffer
  98. Return Value
  99. STATUS_SUCCESS
  100. STATUS_BUFFER_TOO_SMALL
  101. STATUS_OBJECT_NAME_NOT_FOUND
  102. --*/
  103. {
  104. PVOID pvIoBuffer;
  105. NTSTATUS nStatus;
  106. PTUNNEL pTunnel;
  107. KIRQL irql;
  108. ULONG i;
  109. LIST_ENTRY leTempList;
  110. PIPINIP_DELETE_TUNNEL pDeleteInfo;
  111. TraceEnter(TUNN, "DeleteTunnelInterface");
  112. //
  113. // Get the user buffer
  114. //
  115. pvIoBuffer = pIrp->AssociatedIrp.SystemBuffer;
  116. pDeleteInfo = (PIPINIP_DELETE_TUNNEL)pvIoBuffer;
  117. //
  118. // Always clean out the information field
  119. //
  120. pIrp->IoStatus.Information = 0;
  121. if(ulInLength < sizeof(IPINIP_DELETE_TUNNEL))
  122. {
  123. Trace(TUNN, ERROR,
  124. ("DeleteTunnelInterface: In Length %d too small\n",
  125. ulInLength));
  126. TraceLeave(TUNN, "DeleteTunnelInterface");
  127. return STATUS_BUFFER_TOO_SMALL;
  128. }
  129. InitializeListHead(&leTempList);
  130. EnterReader(&g_rwlTunnelLock,
  131. &irql);
  132. pTunnel = FindTunnelGivenIndex(pDeleteInfo->dwIfIndex);
  133. if(pTunnel is NULL)
  134. {
  135. ExitReader(&g_rwlTunnelLock,
  136. irql);
  137. //
  138. // Could not find the tunnel for the given index
  139. //
  140. Trace(TUNN, ERROR,
  141. ("DeleteTunnelInterface: Couldnt find tunnel for index %d\n",
  142. pDeleteInfo->dwIfIndex));
  143. TraceLeave(TUNN, "DeleteTunnelInterface");
  144. return STATUS_OBJECT_NAME_NOT_FOUND;
  145. }
  146. if(IsTunnelMapped(pTunnel))
  147. {
  148. //
  149. // Remove it from the address blocks
  150. //
  151. RemoveEntryList(&(pTunnel->leAddressLink));
  152. }
  153. //
  154. // Mark the tunnel as unmapped
  155. //
  156. MarkTunnelUnmapped(pTunnel);
  157. //
  158. // Remove the tunnel from the list
  159. //
  160. RemoveEntryList(&(pTunnel->leTunnelLink));
  161. pTunnel->dwAdminState |= TS_DELETING;
  162. pTunnel->dwOperState = IF_OPER_STATUS_NON_OPERATIONAL;
  163. //
  164. // If there are queued packets, copy out the queue
  165. //
  166. if(!IsListEmpty(&(pTunnel->lePacketQueueHead)))
  167. {
  168. //
  169. // Copy out Flink and Blink
  170. //
  171. leTempList = pTunnel->lePacketQueueHead;
  172. //
  173. // Set Flink's Blink
  174. //
  175. leTempList.Flink->Blink = &leTempList;
  176. //
  177. // Set Blink's Flink
  178. //
  179. leTempList.Blink->Flink = &leTempList;
  180. }
  181. RtReleaseSpinLockFromDpcLevel(&(pTunnel->rlLock));
  182. //
  183. // Deref the tunnel once for deleting it from the list
  184. //
  185. DereferenceTunnel(pTunnel);
  186. //
  187. // Protected by the tunnel lock
  188. //
  189. g_ulNumTunnels--;
  190. //
  191. // Let go of the lock
  192. //
  193. ExitReader(&g_rwlTunnelLock, irql);
  194. //
  195. // Before deleting from IP, free all the packets
  196. //
  197. while(!IsListEmpty(&leTempList))
  198. {
  199. PLIST_ENTRY pleNode;
  200. PQUEUE_NODE pQueueNode;
  201. pleNode = RemoveHeadList(&leTempList);
  202. pQueueNode = CONTAINING_RECORD(pleNode,
  203. QUEUE_NODE,
  204. leQueueItemLink);
  205. for(i = 0; i < pQueueNode->uiNumPackets; i++)
  206. {
  207. PNDIS_PACKET pnpPacket;
  208. pnpPacket = pQueueNode->ppPacketArray[i];
  209. //
  210. // ok to access pvIpContext since we have a reference
  211. // and the tunnel is not going away
  212. //
  213. g_pfnIpSendComplete(pTunnel->pvIpContext,
  214. pnpPacket,
  215. NDIS_STATUS_ADAPTER_NOT_READY);
  216. }
  217. FreeQueueNode(pQueueNode);
  218. }
  219. //
  220. // Now delete the interface
  221. //
  222. g_pfnIpDeleteInterface(pTunnel->pvIpContext,
  223. TRUE);
  224. //
  225. // Dereference the tunnel for deleting it from IP
  226. // and once more because FindTunnel... put a ref on it
  227. //
  228. DereferenceTunnel(pTunnel);
  229. DereferenceTunnel(pTunnel);
  230. TraceLeave(TUNN, "DeleteTunnelInterface");
  231. return STATUS_SUCCESS;
  232. }
  233. NTSTATUS
  234. SetTunnelInfo(
  235. IN PIRP pIrp,
  236. IN ULONG ulInLength,
  237. IN ULONG ulOutLength
  238. )
  239. /*++
  240. Routine Description
  241. This is the handler for IOCTL_IPINIP_SET_TUNNEL. We do the normal
  242. buffer length checks.
  243. Locks
  244. Takes the tunnel list lock as writer and the tunnel lock
  245. Arguments
  246. pIrp IRP
  247. ulInLength The length of the Input Buffer
  248. ulOutLength The length of the Output Buffer
  249. Return Value
  250. STATUS_SUCCESS
  251. STATUS_BUFFER_TOO_SMALL
  252. STATUS_INSUFFICIENT_RESOURCES
  253. STATUS_OBJECT_NAME_NOT_FOUND
  254. STATUS_INVALID_PARAMETER
  255. --*/
  256. {
  257. PVOID pvIoBuffer;
  258. NTSTATUS nsStatus;
  259. PTUNNEL pTunnel;
  260. KIRQL irql;
  261. LIST_ENTRY leTempList;
  262. ULONG i;
  263. PIPINIP_SET_TUNNEL_INFO pSet;
  264. PTDI_ADDRESS_IP pTdiIp;
  265. PADDRESS_BLOCK pAddrBlock;
  266. TraceEnter(TUNN, "SetTunnelInfo");
  267. //
  268. // Get the user buffer
  269. //
  270. pvIoBuffer = pIrp->AssociatedIrp.SystemBuffer;
  271. pSet = (PIPINIP_SET_TUNNEL_INFO)pvIoBuffer;
  272. //
  273. // Always clean out the information field
  274. //
  275. pIrp->IoStatus.Information = 0;
  276. if(ulInLength < sizeof(IPINIP_SET_TUNNEL_INFO))
  277. {
  278. Trace(TUNN, ERROR,
  279. ("SetTunnelInfo: In Length %d too small\n",
  280. ulInLength));
  281. TraceLeave(TUNN, "SetTunnelInfo");
  282. return STATUS_BUFFER_TOO_SMALL;
  283. }
  284. //
  285. // Validate the parameters
  286. //
  287. if((pSet->dwLocalAddress is INVALID_IP_ADDRESS) or
  288. (pSet->dwRemoteAddress is INVALID_IP_ADDRESS) or
  289. ((DWORD)(pSet->dwLocalAddress & 0x000000E0) >= (DWORD)0x000000E0) or
  290. ((DWORD)(pSet->dwRemoteAddress & 0x000000E0) >= (DWORD)0x000000E0) or
  291. (pSet->byTtl is 0))
  292. {
  293. Trace(TUNN, ERROR,
  294. ("SetTunnelInfo: One of %d.%d.%d.%d %d.%d.%d.%d %d is invalid\n",
  295. PRINT_IPADDR(pSet->dwLocalAddress),
  296. PRINT_IPADDR(pSet->dwRemoteAddress),
  297. pSet->byTtl));
  298. TraceLeave(TUNN, "SetTunnelInfo");
  299. return STATUS_INVALID_PARAMETER;
  300. }
  301. InitializeListHead(&leTempList);
  302. EnterWriter(&g_rwlTunnelLock,
  303. &irql);
  304. pTunnel = FindTunnelGivenIndex(pSet->dwIfIndex);
  305. if(pTunnel is NULL)
  306. {
  307. ExitWriter(&g_rwlTunnelLock,
  308. irql);
  309. //
  310. // Could not find the tunnel for the given index
  311. //
  312. Trace(TUNN, ERROR,
  313. ("SetTunnelInfo: Couldnt find tunnel for index %d\n",
  314. pSet->dwIfIndex));
  315. TraceLeave(TUNN, "SetTunnelInfo");
  316. return STATUS_OBJECT_NAME_NOT_FOUND;
  317. }
  318. if(IsTunnelMapped(pTunnel))
  319. {
  320. Trace(TUNN, TRACE,
  321. ("SetTunnelInfo: Tunnel already mapped\n"));
  322. //
  323. // if we are only changing the TTL, alles okay
  324. //
  325. if((pSet->dwRemoteAddress is pTunnel->REMADDR) and
  326. (pSet->dwLocalAddress is pTunnel->LOCALADDR))
  327. {
  328. Trace(TUNN, TRACE,
  329. ("SetTunnelInfo: Only changing TTL on mapped tunnel\n"));
  330. pTunnel->byTtl = pSet->byTtl;
  331. RtReleaseSpinLockFromDpcLevel(&(pTunnel->rlLock));
  332. DereferenceTunnel(pTunnel);
  333. ExitWriter(&g_rwlTunnelLock,
  334. irql);
  335. TraceLeave(TUNN, "SetTunnelInfo");
  336. return STATUS_SUCCESS;
  337. }
  338. //
  339. // So addresses are changing..
  340. //
  341. Trace(TUNN, TRACE,
  342. ("SetTunnelInfo: Changing address on mapped tunnel\n"));
  343. //
  344. // Remove it from the address blocks
  345. //
  346. RemoveEntryList(&(pTunnel->leAddressLink));
  347. //
  348. // This also marks it unmapped
  349. //
  350. pTunnel->dwAdminState = IF_ADMIN_STATUS_DOWN;
  351. pTunnel->dwOperState = IF_OPER_STATUS_NON_OPERATIONAL;
  352. //
  353. // Copy out the queued packets to delete later
  354. //
  355. if(!IsListEmpty(&(pTunnel->lePacketQueueHead)))
  356. {
  357. //
  358. // Copy out Flink and Blink
  359. //
  360. leTempList = pTunnel->lePacketQueueHead;
  361. //
  362. // Set Flink's Blink
  363. //
  364. leTempList.Flink->Blink = &leTempList;
  365. //
  366. // Set Blink's Flink
  367. //
  368. leTempList.Blink->Flink = &leTempList;
  369. }
  370. }
  371. else
  372. {
  373. RtAssert(IsListEmpty(&(pTunnel->lePacketQueueHead)));
  374. }
  375. //
  376. // Set the state down
  377. //
  378. pTunnel->dwOperState = IF_OPER_STATUS_NON_OPERATIONAL;
  379. pTunnel->dwAdminState = IF_ADMIN_STATUS_UP;
  380. //
  381. // See if we have the address block for this
  382. //
  383. pAddrBlock = GetAddressBlock(pSet->dwLocalAddress);
  384. if(pAddrBlock)
  385. {
  386. RtAssert(pAddrBlock->dwAddress is pSet->dwLocalAddress);
  387. if(pAddrBlock->bAddressPresent)
  388. {
  389. pTunnel->dwAdminState |= TS_ADDRESS_PRESENT;
  390. }
  391. }
  392. else
  393. {
  394. //
  395. // Create one
  396. //
  397. pAddrBlock = RtAllocate(NonPagedPool,
  398. sizeof(ADDRESS_BLOCK),
  399. TUNNEL_TAG);
  400. if(pAddrBlock is NULL)
  401. {
  402. RtReleaseSpinLockFromDpcLevel(&(pTunnel->rlLock));
  403. ExitWriter(&g_rwlTunnelLock,
  404. irql);
  405. DereferenceTunnel(pTunnel);
  406. Trace(TDI, ERROR,
  407. ("TdixAddressArrival: Unable to allocate address block\n"));
  408. return STATUS_INSUFFICIENT_RESOURCES;
  409. }
  410. pAddrBlock->dwAddress = pSet->dwLocalAddress;
  411. pAddrBlock->bAddressPresent = FALSE;
  412. InitializeListHead(&(pAddrBlock->leTunnelList));
  413. InsertHeadList(&g_leAddressList,
  414. &(pAddrBlock->leAddressLink));
  415. }
  416. //
  417. // Link this onto the address
  418. //
  419. InsertHeadList(&(pAddrBlock->leTunnelList),
  420. &(pTunnel->leAddressLink));
  421. pTunnel->REMADDR = pSet->dwRemoteAddress;
  422. pTunnel->LOCALADDR = pSet->dwLocalAddress;
  423. pTunnel->byTtl = pSet->byTtl;
  424. MarkTunnelMapped(pTunnel);
  425. //
  426. // Initialize the TDI structure for this
  427. //
  428. pTdiIp = &(pTunnel->tiaIpAddr.Address[0].Address[0]);
  429. pTdiIp->sin_port = 0;
  430. pTdiIp->in_addr = pTunnel->REMADDR;
  431. if(pTunnel->dwAdminState & TS_ADDRESS_PRESENT)
  432. {
  433. UpdateMtuAndReachability(pTunnel);
  434. }
  435. //
  436. // Return the current operational state to the user
  437. //
  438. pSet->dwOperationalState = pTunnel->dwOperState;
  439. RtReleaseSpinLockFromDpcLevel(&(pTunnel->rlLock));
  440. ExitWriter(&g_rwlTunnelLock,
  441. irql);
  442. //
  443. // Before dereferencing
  444. //
  445. while(!IsListEmpty(&leTempList))
  446. {
  447. PLIST_ENTRY pleNode;
  448. PQUEUE_NODE pQueueNode;
  449. pleNode = RemoveHeadList(&leTempList);
  450. pQueueNode = CONTAINING_RECORD(pleNode,
  451. QUEUE_NODE,
  452. leQueueItemLink);
  453. for(i = 0; i < pQueueNode->uiNumPackets; i++)
  454. {
  455. PNDIS_PACKET pnpPacket;
  456. pnpPacket = pQueueNode->ppPacketArray[i];
  457. //
  458. // ok to access pvIpContext since we have a reference
  459. // and the tunnel is not going away
  460. //
  461. g_pfnIpSendComplete(pTunnel->pvIpContext,
  462. pnpPacket,
  463. NDIS_STATUS_ADAPTER_NOT_READY);
  464. }
  465. FreeQueueNode(pQueueNode);
  466. }
  467. DereferenceTunnel(pTunnel);
  468. TraceLeave(TUNN, "SetTunnelInfo");
  469. pIrp->IoStatus.Information = sizeof(IPINIP_SET_TUNNEL_INFO);
  470. return STATUS_SUCCESS;
  471. }
  472. NTSTATUS
  473. GetTunnelTable(
  474. IN PIRP pIrp,
  475. IN ULONG ulInLength,
  476. IN ULONG ulOutLength
  477. )
  478. /*++
  479. Routine Description
  480. This is the handler for IOCTL_IPINIP_GET_TUNNEL. We do the normal
  481. buffer length checks.
  482. Locks
  483. Takes the tunnel list lock as Reader
  484. Arguments
  485. pIrp IRP
  486. ulInLength The length of the Input Buffer
  487. ulOutLength The length of the Output Buffer
  488. Return Value
  489. STATUS_SUCCESS
  490. STATUS_BUFFER_TOO_SMALL
  491. --*/
  492. {
  493. PVOID pvIoBuffer;
  494. ULONG i;
  495. NTSTATUS nsStatus;
  496. KIRQL irql;
  497. PLIST_ENTRY pleNode;
  498. PTUNNEL pTunnel;
  499. PIPINIP_TUNNEL_TABLE pTunnelTable;
  500. TraceEnter(TUNN, "GetTunnels");
  501. //
  502. // Get the user buffer
  503. //
  504. pvIoBuffer = pIrp->AssociatedIrp.SystemBuffer;
  505. pTunnelTable = (PIPINIP_TUNNEL_TABLE)pvIoBuffer;
  506. //
  507. // Always clean out the information field
  508. //
  509. pIrp->IoStatus.Information = 0;
  510. if(ulOutLength < SIZEOF_BASIC_TUNNEL_TABLE)
  511. {
  512. Trace(TUNN, ERROR,
  513. ("GetTunnels: In Length %d too smaller than smallest table %d\n",
  514. ulInLength,
  515. SIZEOF_BASIC_TUNNEL_TABLE));
  516. TraceLeave(TUNN, "GetTunnels");
  517. return STATUS_BUFFER_TOO_SMALL;
  518. }
  519. EnterReader(&g_rwlTunnelLock,
  520. &irql);
  521. if(ulOutLength < SIZEOF_TUNNEL_TABLE(g_ulNumTunnels))
  522. {
  523. ExitReader(&g_rwlTunnelLock,
  524. irql);
  525. Trace(TUNN, ERROR,
  526. ("GetTunnels: Len %d is less than required (%d) for %d i/f\n",
  527. ulOutLength,
  528. SIZEOF_TUNNEL_TABLE(g_ulNumTunnels),
  529. g_ulNumTunnels));
  530. pTunnelTable->ulNumTunnels = g_ulNumTunnels;
  531. pIrp->IoStatus.Information = SIZEOF_BASIC_TUNNEL_TABLE;
  532. TraceLeave(TUNN, "GetTunnels");
  533. return STATUS_SUCCESS;
  534. }
  535. pTunnelTable->ulNumTunnels = g_ulNumTunnels;
  536. //
  537. // So we have enough space to fill the tunnel
  538. //
  539. for(pleNode = g_leTunnelList.Flink, i = 0;
  540. pleNode isnot &g_leTunnelList;
  541. pleNode = pleNode->Flink, i++)
  542. {
  543. pTunnel = CONTAINING_RECORD(pleNode,
  544. TUNNEL,
  545. leTunnelLink);
  546. pTunnelTable->rgTable[i].dwIfIndex = pTunnel->dwIfIndex;
  547. pTunnelTable->rgTable[i].dwRemoteAddress = pTunnel->REMADDR;
  548. pTunnelTable->rgTable[i].dwLocalAddress = pTunnel->LOCALADDR;
  549. pTunnelTable->rgTable[i].fMapped = IsTunnelMapped(pTunnel);
  550. pTunnelTable->rgTable[i].byTtl = pTunnel->byTtl;
  551. }
  552. RtAssert(i is g_ulNumTunnels);
  553. ExitReader(&g_rwlTunnelLock,
  554. irql);
  555. pIrp->IoStatus.Information = SIZEOF_TUNNEL_TABLE(i);
  556. TraceLeave(TUNN, "GetTunnels");
  557. return STATUS_SUCCESS;
  558. }
  559. NTSTATUS
  560. ProcessNotification(
  561. PIRP pIrp,
  562. ULONG ulInLength,
  563. ULONG ulOutLength
  564. )
  565. /*++
  566. Routine Description:
  567. The handler for IOCTL_IPINIP_NOTIFICATION. We see if we have some info
  568. we wish to return to the caller and if we do, we return it. Otherwise,
  569. we pend the IRP and use it later when we need to report an event to
  570. the user mode
  571. Locks:
  572. Acquires the IoCancelSpinLock
  573. Arguments:
  574. pIrp IRP
  575. ulInLength The length of the Input Buffer
  576. ulOutLength The length of the Output Buffer
  577. Return Value:
  578. STATUS_PENDING
  579. STATUS_SUCCESS
  580. STATUS_BUFFER_TOO_SMALL
  581. --*/
  582. {
  583. KIRQL kiIrql;
  584. PLIST_ENTRY pleNode;
  585. PVOID pvIoBuffer;
  586. PPENDING_MESSAGE pMessage;
  587. TraceEnter(GLOBAL, "ProcessNotification");
  588. pvIoBuffer = pIrp->AssociatedIrp.SystemBuffer;
  589. pIrp->IoStatus.Information = 0;
  590. if((ulInLength < sizeof(IPINIP_NOTIFICATION)) or
  591. (ulOutLength < sizeof(IPINIP_NOTIFICATION)))
  592. {
  593. return STATUS_BUFFER_TOO_SMALL;
  594. }
  595. //
  596. // use cancel spin lock to prevent irp being cancelled during this call.
  597. //
  598. IoAcquireCancelSpinLock(&kiIrql);
  599. //
  600. // If we have a pending notification then complete it - else
  601. // queue the notification IRP
  602. //
  603. if(!IsListEmpty(&g_lePendingMessageList))
  604. {
  605. //
  606. // We have some old info
  607. //
  608. Trace(GLOBAL, TRACE,
  609. ("ProcNotification: Pending message being completed\n"));
  610. //
  611. // Remove it off the pending list
  612. //
  613. pleNode = RemoveHeadList(&g_lePendingMessageList);
  614. //
  615. // Get a pointer to the structure
  616. //
  617. pMessage = CONTAINING_RECORD(pleNode,
  618. PENDING_MESSAGE,
  619. leMessageLink);
  620. //
  621. // Copy out the event to the user mode buffer
  622. //
  623. RtlCopyMemory(pIrp->AssociatedIrp.SystemBuffer,
  624. &pMessage->inMsg,
  625. sizeof(IPINIP_NOTIFICATION));
  626. //
  627. // Mark the IRP as non pending (and hence non cancelable)
  628. //
  629. IoSetCancelRoutine(pIrp,
  630. NULL);
  631. //
  632. // Fill the irp info
  633. //
  634. pIrp->IoStatus.Information = sizeof(IPINIP_NOTIFICATION);
  635. IoReleaseCancelSpinLock(kiIrql);
  636. //
  637. // Free the allocated message
  638. //
  639. FreeMessage(pMessage);
  640. return STATUS_SUCCESS;
  641. }
  642. Trace(GLOBAL, TRACE,
  643. ("ProcNotification: Notification being queued\n"));
  644. //
  645. // Queue this IRP to use for later
  646. // First, mark the irp as pending
  647. //
  648. IoMarkIrpPending(pIrp);
  649. //
  650. // Queue up the irp at the end
  651. //
  652. InsertTailList(&g_lePendingIrpList,
  653. &(pIrp->Tail.Overlay.ListEntry));
  654. //
  655. // Set the cancel routine
  656. //
  657. IoSetCancelRoutine(pIrp,
  658. CancelNotificationIrp);
  659. IoReleaseCancelSpinLock(kiIrql);
  660. return STATUS_PENDING;
  661. }
  662. VOID
  663. CancelNotificationIrp(
  664. PDEVICE_OBJECT pDeviceObject,
  665. PIRP pIrp
  666. )
  667. /*++
  668. Routine Description:
  669. Called to cancel a queued irp
  670. Locks:
  671. Called with the IoCancelSpinLock acquired
  672. Arguments:
  673. pDeviceObject
  674. pIrp
  675. Return Value:
  676. None
  677. --*/
  678. {
  679. TraceEnter(GLOBAL, "CancelNotificationIrp");
  680. //
  681. // Mark this Irp as cancelled
  682. //
  683. pIrp->IoStatus.Status = STATUS_CANCELLED;
  684. pIrp->IoStatus.Information = 0;
  685. //
  686. // Take off our own list
  687. //
  688. RemoveEntryList(&pIrp->Tail.Overlay.ListEntry);
  689. //
  690. // Release cancel spin lock which the IO system acquired
  691. //
  692. IoReleaseCancelSpinLock(pIrp->CancelIrql);
  693. IoCompleteRequest(pIrp,
  694. IO_NETWORK_INCREMENT);
  695. }
  696. VOID
  697. CompleteNotificationIrp(
  698. PPENDING_MESSAGE pMessage
  699. )
  700. /*++
  701. Routine Description:
  702. Called to send a message to user mode
  703. Locks:
  704. Acquires the IoCancelSpinLock
  705. Arguments:
  706. pEvent
  707. Return Value:
  708. None
  709. --*/
  710. {
  711. KIRQL kiIrql;
  712. TraceEnter(GLOBAL, "CompleteNotificationIrp");
  713. //
  714. // grab cancel spin lock
  715. //
  716. IoAcquireCancelSpinLock(&kiIrql);
  717. if(!IsListEmpty(&g_lePendingIrpList))
  718. {
  719. PLIST_ENTRY pleNode;
  720. PIRP pIrp;
  721. //
  722. // We have a pending IRP. Use it to return info to router manager
  723. //
  724. pleNode = RemoveHeadList(&g_lePendingIrpList) ;
  725. pIrp = CONTAINING_RECORD(pleNode,
  726. IRP,
  727. Tail.Overlay.ListEntry);
  728. RtlCopyMemory(pIrp->AssociatedIrp.SystemBuffer,
  729. &(pMessage->inMsg),
  730. sizeof(IPINIP_NOTIFICATION));
  731. Trace(GLOBAL, TRACE,
  732. ("CompleteNotificationIrp: Returning Irp with event code of %d\n",
  733. ((PIPINIP_NOTIFICATION)pIrp->AssociatedIrp.SystemBuffer)->ieEvent));
  734. IoSetCancelRoutine(pIrp,
  735. NULL);
  736. pIrp->IoStatus.Status = STATUS_SUCCESS;
  737. pIrp->IoStatus.Information = sizeof(IPINIP_NOTIFICATION);
  738. //
  739. // release lock
  740. //
  741. IoReleaseCancelSpinLock(kiIrql);
  742. IoCompleteRequest(pIrp,
  743. IO_NETWORK_INCREMENT);
  744. //
  745. // Free the allocated Message
  746. //
  747. FreeMessage(pMessage);
  748. }
  749. else
  750. {
  751. Trace(GLOBAL, TRACE,
  752. ("CompleteNotificationIrp: Found no pending Irp so queuing message\n"));
  753. InsertTailList(&g_lePendingMessageList,
  754. &(pMessage->leMessageLink));
  755. //
  756. // release lock
  757. //
  758. IoReleaseCancelSpinLock(kiIrql);
  759. }
  760. }
  761. PADDRESS_BLOCK
  762. GetAddressBlock(
  763. DWORD dwAddress
  764. )
  765. /*++
  766. Routine Description
  767. Looks up the address block for the given address
  768. Locks
  769. Must be called with the g_rwlTunnelLock held
  770. Arguments
  771. dwAddress
  772. Return Value
  773. Pointer to the address block
  774. NULL if not found
  775. --*/
  776. {
  777. PLIST_ENTRY pleNode;
  778. for(pleNode = g_leAddressList.Flink;
  779. pleNode isnot &g_leAddressList;
  780. pleNode = pleNode->Flink)
  781. {
  782. PADDRESS_BLOCK pAddrBlock;
  783. pAddrBlock = CONTAINING_RECORD(pleNode,
  784. ADDRESS_BLOCK,
  785. leAddressLink);
  786. if(pAddrBlock->dwAddress is dwAddress)
  787. {
  788. return pAddrBlock;
  789. }
  790. }
  791. return NULL;
  792. }
  793. VOID
  794. UpdateMtuAndReachability(
  795. PTUNNEL pTunnel
  796. )
  797. /*++
  798. Routine Description
  799. Updates the MTU and reachability info for a tunnel
  800. Locks
  801. Must be called with the Tunnel locked and referenced
  802. Arguments
  803. pTunnel
  804. Return Value
  805. None
  806. --*/
  807. {
  808. DWORD dwLocalNet;
  809. RouteCacheEntry *pDummyRce;
  810. BYTE byType;
  811. USHORT usMtu;
  812. IPOptInfo OptInfo;
  813. BOOLEAN bChange;
  814. ULONG ulNewMtu;
  815. PPENDING_MESSAGE pMessage;
  816. bChange = FALSE;
  817. RtAssert(pTunnel->dwAdminState & TS_ADDRESS_PRESENT);
  818. RtAssert(IsTunnelMapped(pTunnel));
  819. RtlZeroMemory(&OptInfo,
  820. sizeof(OptInfo));
  821. //
  822. // See if the remote address is reachable and what the MTU is.
  823. //
  824. dwLocalNet = g_pfnOpenRce(pTunnel->REMADDR,
  825. pTunnel->LOCALADDR,
  826. &pDummyRce,
  827. &byType,
  828. &usMtu,
  829. &OptInfo);
  830. if(dwLocalNet isnot NULL_IP_ADDR)
  831. {
  832. LLIPMTUChange mtuChangeInfo;
  833. pTunnel->dwAdminState |= TS_ADDRESS_REACHABLE;
  834. //
  835. // Clear out any error bits
  836. //
  837. ClearErrorBits(pTunnel);
  838. //
  839. // Set the MTU if its changed
  840. //
  841. RtAssert(usMtu > MAX_IP_HEADER_LENGTH);
  842. ulNewMtu = usMtu - MAX_IP_HEADER_LENGTH;
  843. if(pTunnel->ulMtu isnot ulNewMtu)
  844. {
  845. bChange = TRUE;
  846. pTunnel->ulMtu = ulNewMtu;
  847. mtuChangeInfo.lmc_mtu = pTunnel->ulMtu;
  848. g_pfnIpStatus(pTunnel->pvIpContext,
  849. LLIP_STATUS_MTU_CHANGE,
  850. &mtuChangeInfo,
  851. sizeof(LLIPMTUChange),
  852. NULL);
  853. }
  854. if(pTunnel->dwOperState isnot IF_OPER_STATUS_OPERATIONAL)
  855. {
  856. bChange = TRUE;
  857. pTunnel->dwOperState = IF_OPER_STATUS_OPERATIONAL;
  858. }
  859. //
  860. // Close the RCE
  861. //
  862. g_pfnCloseRce(pDummyRce);
  863. }
  864. else
  865. {
  866. pTunnel->dwAdminState &= ~TS_ADDRESS_REACHABLE;
  867. if(pTunnel->dwOperState isnot IF_OPER_STATUS_NON_OPERATIONAL)
  868. {
  869. bChange = TRUE;
  870. pTunnel->dwOperState = IF_OPER_STATUS_NON_OPERATIONAL;
  871. }
  872. }
  873. if(bChange)
  874. {
  875. pMessage = AllocateMessage();
  876. if(pMessage isnot NULL)
  877. {
  878. if(pTunnel->dwOperState is IF_OPER_STATUS_OPERATIONAL)
  879. {
  880. pMessage->inMsg.ieEvent = IE_INTERFACE_UP;
  881. }
  882. else
  883. {
  884. pMessage->inMsg.ieEvent = IE_INTERFACE_DOWN;
  885. }
  886. pMessage->inMsg.iseSubEvent = 0xFFFFFFFF;
  887. pMessage->inMsg.dwIfIndex = pTunnel->dwIfIndex;
  888. CompleteNotificationIrp(pMessage);
  889. }
  890. }
  891. KeQueryTickCount((PLARGE_INTEGER)&((pTunnel->ullLastChange)));
  892. }