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.

7423 lines
208 KiB

  1. // -*- mode: C++; tab-width: 4; indent-tabs-mode: nil -*- (for GNU Emacs)
  2. //
  3. // Copyright (c) 1985-2000 Microsoft Corporation
  4. //
  5. // This file is part of the Microsoft Research IPv6 Network Protocol Stack.
  6. // You should have received a copy of the Microsoft End-User License Agreement
  7. // for this software along with this release; see the file "license.txt".
  8. // If not, please see http://www.research.microsoft.com/msripv6/license.htm,
  9. // or write to Microsoft Research, One Microsoft Way, Redmond, WA 98052-6399.
  10. //
  11. // Abstract:
  12. //
  13. // NT specific routines for dispatching and handling IRPs.
  14. //
  15. #include <oscfg.h>
  16. #include <ndis.h>
  17. #include <ip6imp.h>
  18. #include "ip6def.h"
  19. #include "icmp.h"
  20. #include "ipsec.h"
  21. #include "security.h"
  22. #include "route.h"
  23. #include "select.h"
  24. #include "neighbor.h"
  25. #include <ntddip6.h>
  26. #include "ntreg.h"
  27. #include <string.h>
  28. #include <wchar.h>
  29. #include "fragment.h"
  30. //
  31. // Local structures.
  32. //
  33. typedef struct pending_irp {
  34. LIST_ENTRY Linkage;
  35. PIRP Irp;
  36. PFILE_OBJECT FileObject;
  37. PVOID Context;
  38. } PENDING_IRP, *PPENDING_IRP;
  39. //
  40. // Global variables.
  41. //
  42. LIST_ENTRY PendingEchoList;
  43. //
  44. // Local prototypes.
  45. //
  46. NTSTATUS
  47. IPDispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
  48. NTSTATUS
  49. IPDispatchDeviceControl(IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp);
  50. NTSTATUS
  51. IPCreate(IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp);
  52. NTSTATUS
  53. IPCleanup(IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp);
  54. NTSTATUS
  55. IPClose(IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp);
  56. NTSTATUS
  57. DispatchEchoRequest(IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp);
  58. void
  59. CompleteEchoRequest(void *Context, IP_STATUS Status,
  60. const IPv6Addr *Address, uint ScopeId,
  61. void *Data, uint DataSize);
  62. NTSTATUS
  63. IoctlQueryInterface(IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp);
  64. NTSTATUS
  65. IoctlPersistentQueryInterface(IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp);
  66. NTSTATUS
  67. IoctlQueryAddress(IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp);
  68. NTSTATUS
  69. IoctlPersistentQueryAddress(IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp);
  70. NTSTATUS
  71. IoctlQueryNeighborCache(IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp);
  72. NTSTATUS
  73. IoctlQueryRouteCache(IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp);
  74. NTSTATUS
  75. IoctlCreateSecurityPolicy(IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp);
  76. NTSTATUS
  77. IoctlQuerySecurityPolicyList(IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp);
  78. NTSTATUS
  79. IoctlDeleteSecurityPolicy(IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp);
  80. NTSTATUS
  81. IoctlCreateSecurityAssociation(IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp);
  82. NTSTATUS
  83. IoctlQuerySecurityAssociationList(IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp);
  84. NTSTATUS
  85. IoctlDeleteSecurityAssociation(IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp);
  86. NTSTATUS
  87. IoctlQueryRouteTable(IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp);
  88. NTSTATUS
  89. IoctlPersistentQueryRouteTable(IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp);
  90. NTSTATUS
  91. IoctlUpdateRouteTable(IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp,
  92. IN int Persistent);
  93. NTSTATUS
  94. IoctlUpdateAddress(IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp,
  95. IN int Persistent);
  96. NTSTATUS
  97. IoctlQueryBindingCache(IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp);
  98. NTSTATUS
  99. IoctlCreateInterface(IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp,
  100. IN int Persistent);
  101. NTSTATUS
  102. IoctlUpdateInterface(IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp,
  103. IN int Persistent);
  104. NTSTATUS
  105. IoctlDeleteInterface(IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp,
  106. IN int Persistent);
  107. NTSTATUS
  108. IoctlFlushNeighborCache(IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp);
  109. NTSTATUS
  110. IoctlFlushRouteCache(IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp);
  111. NTSTATUS
  112. IoctlSortDestAddrs(IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp);
  113. NTSTATUS
  114. IoctlQuerySitePrefix(IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp);
  115. NTSTATUS
  116. IoctlUpdateSitePrefix(IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp);
  117. NTSTATUS
  118. IoctlRtChangeNotifyRequest(IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp);
  119. NTSTATUS
  120. IoctlQueryGlobalParameters(IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp,
  121. IN int Persistent);
  122. NTSTATUS
  123. IoctlUpdateGlobalParameters(IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp,
  124. IN int Persistent);
  125. NTSTATUS
  126. IoctlQueryPrefixPolicy(IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp);
  127. NTSTATUS
  128. IoctlPersistentQueryPrefixPolicy(IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp);
  129. NTSTATUS
  130. IoctlUpdatePrefixPolicy(IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp,
  131. IN int Persistent);
  132. NTSTATUS
  133. IoctlDeletePrefixPolicy(IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp,
  134. IN int Persistent);
  135. NTSTATUS
  136. IoctlUpdateRouterLLAddress(IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp);
  137. NTSTATUS
  138. IoctlResetManualConfig(IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp,
  139. IN int Persistent);
  140. NTSTATUS
  141. IoctlRenewInterface(IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp);
  142. //
  143. // All of this code is pageable.
  144. //
  145. #ifdef ALLOC_PRAGMA
  146. #pragma alloc_text(PAGE, IPDispatch)
  147. #pragma alloc_text(PAGE, IPDispatchDeviceControl)
  148. #pragma alloc_text(PAGE, IPCreate)
  149. #pragma alloc_text(PAGE, IPClose)
  150. #pragma alloc_text(PAGE, DispatchEchoRequest)
  151. #endif // ALLOC_PRAGMA
  152. //
  153. // Dispatch function definitions.
  154. //
  155. //* IPDispatch
  156. //
  157. // This is the dispatch routine for IP.
  158. //
  159. NTSTATUS // Returns: whether the request was successfully queued.
  160. IPDispatch(
  161. IN PDEVICE_OBJECT DeviceObject, // Device object for target device.
  162. IN PIRP Irp) // I/O request packet.
  163. {
  164. PIO_STACK_LOCATION irpSp;
  165. NTSTATUS status;
  166. UNREFERENCED_PARAMETER(DeviceObject);
  167. PAGED_CODE();
  168. irpSp = IoGetCurrentIrpStackLocation(Irp);
  169. switch (irpSp->MajorFunction) {
  170. case IRP_MJ_DEVICE_CONTROL:
  171. case IRP_MJ_INTERNAL_DEVICE_CONTROL:
  172. return IPDispatchDeviceControl(Irp, irpSp);
  173. case IRP_MJ_CREATE:
  174. status = IPCreate(Irp, irpSp);
  175. break;
  176. case IRP_MJ_CLEANUP:
  177. status = IPCleanup(Irp, irpSp);
  178. break;
  179. case IRP_MJ_CLOSE:
  180. status = IPClose(Irp, irpSp);
  181. break;
  182. default:
  183. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_USER_ERROR,
  184. "IPDispatch: Invalid major function %d\n",
  185. irpSp->MajorFunction));
  186. status = STATUS_NOT_IMPLEMENTED;
  187. break;
  188. }
  189. Irp->IoStatus.Status = status;
  190. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  191. return(status);
  192. } // IPDispatch
  193. //* IPDispatchDeviceControl
  194. //
  195. NTSTATUS // Returns: whether the request was successfully queued.
  196. IPDispatchDeviceControl(
  197. IN PIRP Irp, // I/O request packet.
  198. IN PIO_STACK_LOCATION IrpSp) // Current stack location in the Irp.
  199. {
  200. NTSTATUS status;
  201. ULONG code;
  202. PAGED_CODE();
  203. code = IrpSp->Parameters.DeviceIoControl.IoControlCode;
  204. switch (code) {
  205. case IOCTL_ICMPV6_ECHO_REQUEST:
  206. return DispatchEchoRequest(Irp, IrpSp);
  207. case IOCTL_IPV6_QUERY_INTERFACE:
  208. return IoctlQueryInterface(Irp, IrpSp);
  209. case IOCTL_IPV6_PERSISTENT_QUERY_INTERFACE:
  210. return IoctlPersistentQueryInterface(Irp, IrpSp);
  211. case IOCTL_IPV6_QUERY_ADDRESS:
  212. return IoctlQueryAddress(Irp, IrpSp);
  213. case IOCTL_IPV6_PERSISTENT_QUERY_ADDRESS:
  214. return IoctlPersistentQueryAddress(Irp, IrpSp);
  215. case IOCTL_IPV6_QUERY_NEIGHBOR_CACHE:
  216. return IoctlQueryNeighborCache(Irp, IrpSp);
  217. case IOCTL_IPV6_QUERY_ROUTE_CACHE:
  218. return IoctlQueryRouteCache(Irp, IrpSp);
  219. case IOCTL_IPV6_CREATE_SECURITY_POLICY:
  220. return IoctlCreateSecurityPolicy(Irp, IrpSp);
  221. case IOCTL_IPV6_QUERY_SECURITY_POLICY_LIST:
  222. return IoctlQuerySecurityPolicyList(Irp, IrpSp);
  223. case IOCTL_IPV6_DELETE_SECURITY_POLICY:
  224. return IoctlDeleteSecurityPolicy(Irp, IrpSp);
  225. case IOCTL_IPV6_CREATE_SECURITY_ASSOCIATION:
  226. return IoctlCreateSecurityAssociation(Irp, IrpSp);
  227. case IOCTL_IPV6_QUERY_SECURITY_ASSOCIATION_LIST:
  228. return IoctlQuerySecurityAssociationList(Irp, IrpSp);
  229. case IOCTL_IPV6_DELETE_SECURITY_ASSOCIATION:
  230. return IoctlDeleteSecurityAssociation(Irp, IrpSp);
  231. case IOCTL_IPV6_QUERY_ROUTE_TABLE:
  232. return IoctlQueryRouteTable(Irp, IrpSp);
  233. case IOCTL_IPV6_PERSISTENT_QUERY_ROUTE_TABLE:
  234. return IoctlPersistentQueryRouteTable(Irp, IrpSp);
  235. case IOCTL_IPV6_UPDATE_ROUTE_TABLE:
  236. return IoctlUpdateRouteTable(Irp, IrpSp, FALSE);
  237. case IOCTL_IPV6_PERSISTENT_UPDATE_ROUTE_TABLE:
  238. return IoctlUpdateRouteTable(Irp, IrpSp, TRUE);
  239. case IOCTL_IPV6_UPDATE_ADDRESS:
  240. return IoctlUpdateAddress(Irp, IrpSp, FALSE);
  241. case IOCTL_IPV6_PERSISTENT_UPDATE_ADDRESS:
  242. return IoctlUpdateAddress(Irp, IrpSp, TRUE);
  243. case IOCTL_IPV6_QUERY_BINDING_CACHE:
  244. return IoctlQueryBindingCache(Irp, IrpSp);
  245. case IOCTL_IPV6_CREATE_INTERFACE:
  246. return IoctlCreateInterface(Irp, IrpSp, FALSE);
  247. case IOCTL_IPV6_PERSISTENT_CREATE_INTERFACE:
  248. return IoctlCreateInterface(Irp, IrpSp, TRUE);
  249. case IOCTL_IPV6_UPDATE_INTERFACE:
  250. return IoctlUpdateInterface(Irp, IrpSp, FALSE);
  251. case IOCTL_IPV6_PERSISTENT_UPDATE_INTERFACE:
  252. return IoctlUpdateInterface(Irp, IrpSp, TRUE);
  253. case IOCTL_IPV6_DELETE_INTERFACE:
  254. return IoctlDeleteInterface(Irp, IrpSp, FALSE);
  255. case IOCTL_IPV6_PERSISTENT_DELETE_INTERFACE:
  256. return IoctlDeleteInterface(Irp, IrpSp, TRUE);
  257. case IOCTL_IPV6_FLUSH_NEIGHBOR_CACHE:
  258. return IoctlFlushNeighborCache(Irp, IrpSp);
  259. case IOCTL_IPV6_FLUSH_ROUTE_CACHE:
  260. return IoctlFlushRouteCache(Irp, IrpSp);
  261. case IOCTL_IPV6_SORT_DEST_ADDRS:
  262. return IoctlSortDestAddrs(Irp, IrpSp);
  263. case IOCTL_IPV6_QUERY_SITE_PREFIX:
  264. return IoctlQuerySitePrefix(Irp, IrpSp);
  265. case IOCTL_IPV6_UPDATE_SITE_PREFIX:
  266. return IoctlUpdateSitePrefix(Irp, IrpSp);
  267. case IOCTL_IPV6_RTCHANGE_NOTIFY_REQUEST:
  268. return IoctlRtChangeNotifyRequest(Irp, IrpSp);
  269. case IOCTL_IPV6_QUERY_GLOBAL_PARAMETERS:
  270. return IoctlQueryGlobalParameters(Irp, IrpSp, FALSE);
  271. case IOCTL_IPV6_PERSISTENT_QUERY_GLOBAL_PARAMETERS:
  272. return IoctlQueryGlobalParameters(Irp, IrpSp, TRUE);
  273. case IOCTL_IPV6_UPDATE_GLOBAL_PARAMETERS:
  274. return IoctlUpdateGlobalParameters(Irp, IrpSp, FALSE);
  275. case IOCTL_IPV6_PERSISTENT_UPDATE_GLOBAL_PARAMETERS:
  276. return IoctlUpdateGlobalParameters(Irp, IrpSp, TRUE);
  277. case IOCTL_IPV6_QUERY_PREFIX_POLICY:
  278. return IoctlQueryPrefixPolicy(Irp, IrpSp);
  279. case IOCTL_IPV6_PERSISTENT_QUERY_PREFIX_POLICY:
  280. return IoctlPersistentQueryPrefixPolicy(Irp, IrpSp);
  281. case IOCTL_IPV6_UPDATE_PREFIX_POLICY:
  282. return IoctlUpdatePrefixPolicy(Irp, IrpSp, FALSE);
  283. case IOCTL_IPV6_PERSISTENT_UPDATE_PREFIX_POLICY:
  284. return IoctlUpdatePrefixPolicy(Irp, IrpSp, TRUE);
  285. case IOCTL_IPV6_DELETE_PREFIX_POLICY:
  286. return IoctlDeletePrefixPolicy(Irp, IrpSp, FALSE);
  287. case IOCTL_IPV6_PERSISTENT_DELETE_PREFIX_POLICY:
  288. return IoctlDeletePrefixPolicy(Irp, IrpSp, TRUE);
  289. case IOCTL_IPV6_UPDATE_ROUTER_LL_ADDRESS:
  290. return IoctlUpdateRouterLLAddress(Irp, IrpSp);
  291. case IOCTL_IPV6_RESET:
  292. return IoctlResetManualConfig(Irp, IrpSp, FALSE);
  293. case IOCTL_IPV6_PERSISTENT_RESET:
  294. return IoctlResetManualConfig(Irp, IrpSp, TRUE);
  295. case IOCTL_IPV6_RENEW_INTERFACE:
  296. return IoctlRenewInterface(Irp, IrpSp);
  297. default:
  298. status = STATUS_NOT_IMPLEMENTED;
  299. break;
  300. }
  301. Irp->IoStatus.Status = status;
  302. Irp->IoStatus.Information = 0;
  303. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  304. return status;
  305. } // IPDispatchDeviceControl
  306. //* IPCreate
  307. //
  308. NTSTATUS // Returns: whether the request was successfully queued.
  309. IPCreate(
  310. IN PIRP Irp, // I/O request packet.
  311. IN PIO_STACK_LOCATION IrpSp) // Current stack location in the Irp.
  312. {
  313. PAGED_CODE();
  314. return(STATUS_SUCCESS);
  315. } // IPCreate
  316. //* IPCleanup
  317. //
  318. NTSTATUS // Returns: whether the request was successfully queued.
  319. IPCleanup(
  320. IN PIRP Irp, // I/O request packet.
  321. IN PIO_STACK_LOCATION IrpSp) // Current stack location in the Irp.
  322. {
  323. PPENDING_IRP pendingIrp;
  324. PLIST_ENTRY entry, nextEntry;
  325. KIRQL oldIrql;
  326. LIST_ENTRY completeList;
  327. PIRP cancelledIrp;
  328. InitializeListHead(&completeList);
  329. //
  330. // Collect all of the pending IRPs on this file object.
  331. //
  332. IoAcquireCancelSpinLock(&oldIrql);
  333. entry = PendingEchoList.Flink;
  334. while ( entry != &PendingEchoList ) {
  335. pendingIrp = CONTAINING_RECORD(entry, PENDING_IRP, Linkage);
  336. if (pendingIrp->FileObject == IrpSp->FileObject) {
  337. nextEntry = entry->Flink;
  338. RemoveEntryList(entry);
  339. IoSetCancelRoutine(pendingIrp->Irp, NULL);
  340. InsertTailList(&completeList, &(pendingIrp->Linkage));
  341. entry = nextEntry;
  342. }
  343. else {
  344. entry = entry->Flink;
  345. }
  346. }
  347. IoReleaseCancelSpinLock(oldIrql);
  348. //
  349. // Complete them.
  350. //
  351. entry = completeList.Flink;
  352. while ( entry != &completeList ) {
  353. pendingIrp = CONTAINING_RECORD(entry, PENDING_IRP, Linkage);
  354. cancelledIrp = pendingIrp->Irp;
  355. entry = entry->Flink;
  356. //
  357. // Free the PENDING_IRP structure. The control block will be freed
  358. // when the request completes.
  359. //
  360. ExFreePool(pendingIrp);
  361. //
  362. // Complete the IRP.
  363. //
  364. cancelledIrp->IoStatus.Information = 0;
  365. cancelledIrp->IoStatus.Status = STATUS_CANCELLED;
  366. IoCompleteRequest(cancelledIrp, IO_NETWORK_INCREMENT);
  367. }
  368. return(STATUS_SUCCESS);
  369. } // IPCleanup
  370. //* IPClose
  371. //
  372. NTSTATUS // Returns: whether the request was successfully queued.
  373. IPClose(
  374. IN PIRP Irp, // I/O request packet.
  375. IN PIO_STACK_LOCATION IrpSp) // Current stack location in the Irp.
  376. {
  377. PAGED_CODE();
  378. return(STATUS_SUCCESS);
  379. } // IPClose
  380. //
  381. // ICMP Echo function definitions
  382. //
  383. //* CancelEchoRequest
  384. //
  385. // This function is called with cancel spinlock held. It must be
  386. // released before the function returns.
  387. //
  388. // The echo control block associated with this request cannot be
  389. // freed until the request completes. The completion routine will
  390. // free it.
  391. //
  392. VOID
  393. CancelEchoRequest(
  394. IN PDEVICE_OBJECT Device, // Device on which the request was issued.
  395. IN PIRP Irp) // I/O request packet to cancel.
  396. {
  397. PPENDING_IRP pendingIrp = NULL;
  398. PPENDING_IRP item;
  399. PLIST_ENTRY entry;
  400. for ( entry = PendingEchoList.Flink;
  401. entry != &PendingEchoList;
  402. entry = entry->Flink
  403. ) {
  404. item = CONTAINING_RECORD(entry, PENDING_IRP, Linkage);
  405. if (item->Irp == Irp) {
  406. pendingIrp = item;
  407. RemoveEntryList(entry);
  408. IoSetCancelRoutine(pendingIrp->Irp, NULL);
  409. break;
  410. }
  411. }
  412. IoReleaseCancelSpinLock(Irp->CancelIrql);
  413. if (pendingIrp != NULL) {
  414. //
  415. // Free the PENDING_IRP structure. The control block will be freed
  416. // when the request completes.
  417. //
  418. ExFreePool(pendingIrp);
  419. //
  420. // Complete the IRP.
  421. //
  422. Irp->IoStatus.Information = 0;
  423. Irp->IoStatus.Status = STATUS_CANCELLED;
  424. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  425. }
  426. return;
  427. } // CancelEchoRequest
  428. //* CompleteEchoRequest
  429. //
  430. // Handles the completion of an ICMP Echo request.
  431. //
  432. void
  433. CompleteEchoRequest(
  434. void *Context, // EchoControl structure for this request.
  435. IP_STATUS Status, // Status of the transmission.
  436. const IPv6Addr *Address, // Source of the echo reply.
  437. uint ScopeId, // Scope of the echo reply source.
  438. void *Data, // Pointer to data returned in the echo reply.
  439. uint DataSize) // Lengh of the returned data.
  440. {
  441. KIRQL oldIrql;
  442. PIRP irp;
  443. EchoControl *controlBlock;
  444. PPENDING_IRP pendingIrp = NULL;
  445. PPENDING_IRP item;
  446. PLIST_ENTRY entry;
  447. ULONG bytesReturned;
  448. controlBlock = (EchoControl *) Context;
  449. //
  450. // Find the echo request IRP on the pending list.
  451. //
  452. IoAcquireCancelSpinLock(&oldIrql);
  453. for ( entry = PendingEchoList.Flink;
  454. entry != &PendingEchoList;
  455. entry = entry->Flink
  456. ) {
  457. item = CONTAINING_RECORD(entry, PENDING_IRP, Linkage);
  458. if (item->Context == controlBlock) {
  459. pendingIrp = item;
  460. irp = pendingIrp->Irp;
  461. IoSetCancelRoutine(irp, NULL);
  462. RemoveEntryList(entry);
  463. break;
  464. }
  465. }
  466. IoReleaseCancelSpinLock(oldIrql);
  467. if (pendingIrp == NULL) {
  468. //
  469. // IRP must have been cancelled. PENDING_IRP struct
  470. // was freed by cancel routine. Free control block.
  471. //
  472. ExFreePool(controlBlock);
  473. return;
  474. }
  475. irp->IoStatus.Status = ICMPv6EchoComplete(
  476. controlBlock,
  477. Status,
  478. Address,
  479. ScopeId,
  480. Data,
  481. DataSize,
  482. &irp->IoStatus.Information
  483. );
  484. ExFreePool(pendingIrp);
  485. ExFreePool(controlBlock);
  486. //
  487. // Complete the IRP.
  488. //
  489. IoCompleteRequest(irp, IO_NETWORK_INCREMENT);
  490. } // CompleteEchoRequest
  491. //* PrepareEchoIrpForCancel
  492. //
  493. // Prepares an Echo IRP for cancellation.
  494. //
  495. BOOLEAN // Returns: TRUE if IRP was already cancelled, FALSE otherwise.
  496. PrepareEchoIrpForCancel(
  497. PIRP Irp, // I/O request packet to init for cancellation.
  498. PPENDING_IRP PendingIrp) // PENDING_IRP structure for this IRP.
  499. {
  500. BOOLEAN cancelled = TRUE;
  501. KIRQL oldIrql;
  502. IoAcquireCancelSpinLock(&oldIrql);
  503. ASSERT(Irp->CancelRoutine == NULL);
  504. if (!Irp->Cancel) {
  505. IoSetCancelRoutine(Irp, CancelEchoRequest);
  506. InsertTailList(&PendingEchoList, &(PendingIrp->Linkage));
  507. cancelled = FALSE;
  508. }
  509. IoReleaseCancelSpinLock(oldIrql);
  510. return(cancelled);
  511. } // PrepareEchoIrpForCancel
  512. //* DispatchEchoRequest
  513. //
  514. // Processes an ICMP request.
  515. //
  516. // Note: Return value indicates whether NT-specific processing of the
  517. // request was successful. The status of the actual request is returned
  518. // in the request buffers.
  519. //
  520. NTSTATUS
  521. DispatchEchoRequest(
  522. IN PIRP Irp, // I/O request packet.
  523. IN PIO_STACK_LOCATION IrpSp) // Current stack location in the Irp.
  524. {
  525. NTSTATUS ntStatus = STATUS_SUCCESS;
  526. IP_STATUS ipStatus;
  527. PPENDING_IRP pendingIrp;
  528. EchoControl *controlBlock;
  529. PICMPV6_ECHO_REPLY replyBuffer;
  530. BOOLEAN cancelled;
  531. PAGED_CODE();
  532. pendingIrp = ExAllocatePool(NonPagedPool, sizeof(PENDING_IRP));
  533. if (pendingIrp == NULL) {
  534. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  535. goto echo_error;
  536. }
  537. controlBlock = ExAllocatePool(NonPagedPool, sizeof(EchoControl));
  538. if (controlBlock == NULL) {
  539. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  540. goto echo_error_free_pending;
  541. }
  542. pendingIrp->Irp = Irp;
  543. pendingIrp->FileObject = IrpSp->FileObject;
  544. pendingIrp->Context = controlBlock;
  545. controlBlock->WhenIssued = KeQueryPerformanceCounter(NULL);
  546. controlBlock->ReplyBuf = Irp->AssociatedIrp.SystemBuffer;
  547. controlBlock->ReplyBufLen =
  548. IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  549. IoMarkIrpPending(Irp);
  550. cancelled = PrepareEchoIrpForCancel(Irp, pendingIrp);
  551. if (!cancelled) {
  552. ICMPv6EchoRequest(
  553. Irp->AssociatedIrp.SystemBuffer, // request buf
  554. IrpSp->Parameters.DeviceIoControl.InputBufferLength, // request len
  555. controlBlock, // echo ctrl
  556. CompleteEchoRequest // cmplt rtn
  557. );
  558. return STATUS_PENDING;
  559. }
  560. //
  561. // Irp has already been cancelled.
  562. //
  563. ntStatus = STATUS_CANCELLED;
  564. ExFreePool(controlBlock);
  565. echo_error_free_pending:
  566. ExFreePool(pendingIrp);
  567. echo_error:
  568. Irp->IoStatus.Information = 0;
  569. Irp->IoStatus.Status = ntStatus;
  570. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  571. return(ntStatus);
  572. } // DispatchEchoRequest
  573. //* FindInterfaceFromQuery
  574. //
  575. // Given an IPV6_QUERY_INTERFACE structure,
  576. // finds the specified interface.
  577. // The interface (if found) is returned with a reference.
  578. //
  579. Interface *
  580. FindInterfaceFromQuery(
  581. IPV6_QUERY_INTERFACE *Query)
  582. {
  583. Interface *IF;
  584. if (Query->Index == 0)
  585. IF = FindInterfaceFromGuid(&Query->Guid);
  586. else
  587. IF = FindInterfaceFromIndex(Query->Index);
  588. return IF;
  589. }
  590. //* ReturnQueryInterface
  591. //
  592. // Initializes a returned IPV6_QUERY_INTERFACE structure
  593. // with query information for the specified interface.
  594. //
  595. void
  596. ReturnQueryInterface(
  597. Interface *IF,
  598. IPV6_QUERY_INTERFACE *Query)
  599. {
  600. if (IF == NULL) {
  601. Query->Index = (uint)-1;
  602. RtlZeroMemory(&Query->Guid, sizeof Query->Guid);
  603. }
  604. else {
  605. Query->Index = IF->Index;
  606. Query->Guid = IF->Guid;
  607. }
  608. }
  609. //* ReturnQueryInterfaceNext
  610. //
  611. // Initializes a returned IPV6_QUERY_INTERFACE structure
  612. // with query information for the next interface
  613. // after the specified interface. (Or the first interface,
  614. // if the specified interface is NULL.)
  615. //
  616. void
  617. ReturnQueryInterfaceNext(
  618. Interface *IF,
  619. IPV6_QUERY_INTERFACE *Query)
  620. {
  621. IF = FindNextInterface(IF);
  622. ReturnQueryInterface(IF, Query);
  623. if (IF != NULL)
  624. ReleaseIF(IF);
  625. }
  626. //* IoctlQueryInterface
  627. //
  628. // Processes an IOCTL_IPV6_QUERY_INTERFACE request.
  629. //
  630. // Note: Return value indicates whether NT-specific processing of the
  631. // request was successful. The status of the actual request is returned
  632. // in the request buffers.
  633. //
  634. NTSTATUS
  635. IoctlQueryInterface(
  636. IN PIRP Irp, // I/O request packet.
  637. IN PIO_STACK_LOCATION IrpSp) // Current stack location in the Irp.
  638. {
  639. IPV6_QUERY_INTERFACE *Query;
  640. IPV6_INFO_INTERFACE *Info;
  641. Interface *IF;
  642. NTSTATUS Status;
  643. uint LinkLayerAddressesLength;
  644. uchar *LinkLayerAddress;
  645. PAGED_CODE();
  646. Irp->IoStatus.Information = 0;
  647. if ((IrpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof *Query) ||
  648. (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof *Info)) {
  649. Status = STATUS_INVALID_PARAMETER;
  650. goto Return;
  651. }
  652. Query = (IPV6_QUERY_INTERFACE *) Irp->AssociatedIrp.SystemBuffer;
  653. Info = (IPV6_INFO_INTERFACE *) Irp->AssociatedIrp.SystemBuffer;
  654. if (Query->Index == (uint)-1) {
  655. //
  656. // Return query information for the first interface.
  657. //
  658. ReturnQueryInterfaceNext(NULL, &Info->Next);
  659. Irp->IoStatus.Information = sizeof Info->Next;
  660. } else {
  661. //
  662. // Return information about the specified interface.
  663. //
  664. IF = FindInterfaceFromQuery(Query);
  665. if (IF == NULL) {
  666. Status = STATUS_INVALID_PARAMETER_1;
  667. goto Return;
  668. }
  669. Irp->IoStatus.Information = sizeof *Info;
  670. Info->Length = sizeof *Info;
  671. //
  672. // Return query information for the next interface.
  673. //
  674. ReturnQueryInterfaceNext(IF, &Info->Next);
  675. //
  676. // Return miscellaneous information about the interface.
  677. //
  678. ReturnQueryInterface(IF, &Info->This);
  679. RtlCopyMemory(Info->ZoneIndices, IF->ZoneIndices,
  680. sizeof Info->ZoneIndices);
  681. Info->TrueLinkMTU = IF->TrueLinkMTU;
  682. Info->LinkMTU = IF->LinkMTU;
  683. Info->CurHopLimit = IF->CurHopLimit;
  684. Info->BaseReachableTime = IF->BaseReachableTime;
  685. Info->ReachableTime = ConvertTicksToMillis(IF->ReachableTime);
  686. Info->RetransTimer = ConvertTicksToMillis(IF->RetransTimer);
  687. Info->DupAddrDetectTransmits = IF->DupAddrDetectTransmits;
  688. Info->Type = IF->Type;
  689. Info->RouterDiscovers = !!(IF->Flags & IF_FLAG_ROUTER_DISCOVERS);
  690. Info->NeighborDiscovers = !!(IF->Flags & IF_FLAG_NEIGHBOR_DISCOVERS);
  691. Info->PeriodicMLD = !!(IF->Flags & IF_FLAG_PERIODICMLD);
  692. Info->Advertises = !!(IF->Flags & IF_FLAG_ADVERTISES);
  693. Info->Forwards = !!(IF->Flags & IF_FLAG_FORWARDS);
  694. Info->OtherStatefulConfig = !!(IF->Flags & IF_FLAG_OTHER_STATEFUL_CONFIG);
  695. if (IF->Flags & IF_FLAG_MEDIA_DISCONNECTED)
  696. Info->MediaStatus = IPV6_IF_MEDIA_STATUS_DISCONNECTED;
  697. else if (IF->Flags & IF_FLAG_MEDIA_RECONNECTED)
  698. Info->MediaStatus = IPV6_IF_MEDIA_STATUS_RECONNECTED;
  699. else
  700. Info->MediaStatus = IPV6_IF_MEDIA_STATUS_CONNECTED;
  701. Info->Preference = IF->Preference;
  702. //
  703. // Return the interface's link-layer addresses,
  704. // if there is room in the user's buffer.
  705. //
  706. Info->LinkLayerAddressLength = IF->LinkAddressLength;
  707. Info->LocalLinkLayerAddress = 0;
  708. Info->RemoteLinkLayerAddress = 0;
  709. if (IF->Type == IF_TYPE_TUNNEL_AUTO) {
  710. LinkLayerAddressesLength = 2 * IF->LinkAddressLength;
  711. }
  712. else {
  713. LinkLayerAddressesLength = 0;
  714. if (!(IF->Flags & IF_FLAG_PSEUDO))
  715. LinkLayerAddressesLength += IF->LinkAddressLength;
  716. if (IF->Flags & IF_FLAG_P2P)
  717. LinkLayerAddressesLength += IF->LinkAddressLength;
  718. }
  719. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
  720. sizeof *Info + LinkLayerAddressesLength) {
  721. //
  722. // Return the fixed-size portion of the structure.
  723. //
  724. Status = STATUS_BUFFER_OVERFLOW;
  725. ReleaseIF(IF);
  726. goto Return;
  727. }
  728. LinkLayerAddress = (uchar *)(Info + 1);
  729. if (IF->Type == IF_TYPE_TUNNEL_AUTO) {
  730. //
  731. // For ISATAP (automatic tunnels), TokenAddr corresponds to
  732. // LocalLinkLayerAddress and DstAddr to RemoteLinkLayerAddress.
  733. //
  734. RtlCopyMemory(LinkLayerAddress,
  735. IF->LinkAddress + IF->LinkAddressLength,
  736. 2 * IF->LinkAddressLength);
  737. Info->RemoteLinkLayerAddress = (uint)
  738. (LinkLayerAddress - (uchar *)Info);
  739. Info->LocalLinkLayerAddress = Info->RemoteLinkLayerAddress +
  740. IF->LinkAddressLength;
  741. }
  742. else {
  743. if (!(IF->Flags & IF_FLAG_PSEUDO)) {
  744. RtlCopyMemory(LinkLayerAddress, IF->LinkAddress,
  745. IF->LinkAddressLength);
  746. Info->LocalLinkLayerAddress = (uint)
  747. (LinkLayerAddress - (uchar *)Info);
  748. LinkLayerAddress += IF->LinkAddressLength;
  749. }
  750. if (IF->Flags & IF_FLAG_P2P) {
  751. RtlCopyMemory(LinkLayerAddress,
  752. IF->LinkAddress + IF->LinkAddressLength,
  753. IF->LinkAddressLength);
  754. Info->RemoteLinkLayerAddress = (uint)
  755. (LinkLayerAddress - (uchar *)Info);
  756. LinkLayerAddress += IF->LinkAddressLength;
  757. }
  758. }
  759. Irp->IoStatus.Information += LinkLayerAddressesLength;
  760. ReleaseIF(IF);
  761. }
  762. Status = STATUS_SUCCESS;
  763. Return:
  764. Irp->IoStatus.Status = Status;
  765. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  766. return Status;
  767. } // IoctlQueryInterface
  768. //* OpenInterfaceRegKey
  769. //
  770. // Given an interface guid, opens the registry key that holds
  771. // persistent configuration information for the interface.
  772. //
  773. // Callable from thread context, not DPC context.
  774. //
  775. NTSTATUS
  776. OpenInterfaceRegKey(
  777. const GUID *Guid,
  778. HANDLE *RegKey,
  779. OpenRegKeyAction Action)
  780. {
  781. UNICODE_STRING GuidName;
  782. HANDLE InterfacesKey;
  783. NTSTATUS Status;
  784. PAGED_CODE();
  785. Status = OpenTopLevelRegKey(L"Interfaces", &InterfacesKey,
  786. ((Action == OpenRegKeyCreate) ?
  787. OpenRegKeyCreate : OpenRegKeyRead));
  788. if (! NT_SUCCESS(Status))
  789. return Status;
  790. //
  791. // Convert the guid to string form.
  792. // It will be null-terminated.
  793. //
  794. Status = RtlStringFromGUID(Guid, &GuidName);
  795. if (! NT_SUCCESS(Status))
  796. goto ReturnCloseKey;
  797. ASSERT(GuidName.MaximumLength == GuidName.Length + sizeof(WCHAR));
  798. ASSERT(((WCHAR *)GuidName.Buffer)[GuidName.Length/sizeof(WCHAR)] == UNICODE_NULL);
  799. Status = OpenRegKey(RegKey, InterfacesKey,
  800. (WCHAR *)GuidName.Buffer, Action);
  801. RtlFreeUnicodeString(&GuidName);
  802. ReturnCloseKey:
  803. ZwClose(InterfacesKey);
  804. return Status;
  805. }
  806. //* ReadPersistentInterface
  807. //
  808. // Reads interface attributes from the registry key.
  809. // Initializes all the fields except This and Next.
  810. //
  811. // On input, the Length field should contain the remaining space
  812. // for link-layer addresses. On output, it contains the amount
  813. // of space for link-layer addresses that was actually used.
  814. //
  815. // Returns:
  816. // STATUS_INVALID_PARAMETER Could not read the interface.
  817. // STATUS_BUFFER_OVERFLOW No room for link-layer addresses.
  818. // STATUS_SUCCESS
  819. //
  820. NTSTATUS
  821. ReadPersistentInterface(
  822. HANDLE IFKey,
  823. IPV6_INFO_INTERFACE *Info)
  824. {
  825. uint LinkLayerAddressSpace;
  826. NTSTATUS Status;
  827. InitRegDWORDParameter(IFKey, L"Type",
  828. (ULONG *)&Info->Type, (uint)-1);
  829. InitRegDWORDParameter(IFKey, L"RouterDiscovers",
  830. &Info->RouterDiscovers, (uint)-1);
  831. InitRegDWORDParameter(IFKey, L"NeighborDiscovers",
  832. &Info->NeighborDiscovers, (uint)-1);
  833. InitRegDWORDParameter(IFKey, L"PeriodicMLD",
  834. &Info->PeriodicMLD, (uint)-1);
  835. InitRegDWORDParameter(IFKey, L"Advertises",
  836. &Info->Advertises, (uint)-1);
  837. InitRegDWORDParameter(IFKey, L"Forwards",
  838. &Info->Forwards, (uint)-1);
  839. Info->MediaStatus = (uint)-1;
  840. memset(Info->ZoneIndices, 0, sizeof Info->ZoneIndices);
  841. Info->TrueLinkMTU = 0;
  842. InitRegDWORDParameter(IFKey, L"LinkMTU",
  843. &Info->LinkMTU, 0);
  844. InitRegDWORDParameter(IFKey, L"CurHopLimit",
  845. &Info->CurHopLimit, (uint)-1);
  846. InitRegDWORDParameter(IFKey, L"BaseReachableTime",
  847. &Info->BaseReachableTime, 0);
  848. Info->ReachableTime = 0;
  849. InitRegDWORDParameter(IFKey, L"RetransTimer",
  850. &Info->RetransTimer, 0);
  851. InitRegDWORDParameter(IFKey, L"DupAddrDetectTransmits",
  852. &Info->DupAddrDetectTransmits, (uint)-1);
  853. InitRegDWORDParameter(IFKey, L"Preference",
  854. &Info->Preference, (uint)-1);
  855. //
  856. // Start by assuming we will not return link-layer addresses.
  857. //
  858. Info->LocalLinkLayerAddress = 0;
  859. Info->RemoteLinkLayerAddress = 0;
  860. //
  861. // But depending on the interface type they may be in the registry.
  862. //
  863. switch (Info->Type) {
  864. case IF_TYPE_TUNNEL_6OVER4: {
  865. IPAddr *SrcAddr;
  866. Info->LinkLayerAddressLength = sizeof(IPAddr);
  867. LinkLayerAddressSpace = Info->LinkLayerAddressLength;
  868. if (Info->Length < LinkLayerAddressSpace)
  869. return STATUS_BUFFER_OVERFLOW;
  870. Info->Length = LinkLayerAddressSpace;
  871. //
  872. // Read the source address.
  873. //
  874. SrcAddr = (IPAddr *)(Info + 1);
  875. Status = GetRegIPAddrValue(IFKey, L"SrcAddr", SrcAddr);
  876. if (! NT_SUCCESS(Status))
  877. return STATUS_NO_MORE_ENTRIES;
  878. Info->LocalLinkLayerAddress = (uint)
  879. ((uchar *)SrcAddr - (uchar *)Info);
  880. break;
  881. }
  882. case IF_TYPE_TUNNEL_V6V4: {
  883. IPAddr *SrcAddr, *DstAddr;
  884. Info->LinkLayerAddressLength = sizeof(IPAddr);
  885. LinkLayerAddressSpace = 2 * Info->LinkLayerAddressLength;
  886. if (Info->Length < LinkLayerAddressSpace)
  887. return STATUS_BUFFER_OVERFLOW;
  888. Info->Length = LinkLayerAddressSpace;
  889. //
  890. // Read the source address.
  891. //
  892. SrcAddr = (IPAddr *)(Info + 1);
  893. Status = GetRegIPAddrValue(IFKey, L"SrcAddr", SrcAddr);
  894. if (! NT_SUCCESS(Status))
  895. return STATUS_INVALID_PARAMETER;
  896. Info->LocalLinkLayerAddress = (uint)
  897. ((uchar *)SrcAddr - (uchar *)Info);
  898. //
  899. // Read the destination address.
  900. //
  901. DstAddr = SrcAddr + 1;
  902. Status = GetRegIPAddrValue(IFKey, L"DstAddr", DstAddr);
  903. if (! NT_SUCCESS(Status))
  904. return STATUS_INVALID_PARAMETER;
  905. Info->RemoteLinkLayerAddress = (uint)
  906. ((uchar *)DstAddr - (uchar *)Info);
  907. break;
  908. }
  909. default:
  910. Info->LinkLayerAddressLength = (uint) -1;
  911. Info->Length = 0;
  912. break;
  913. }
  914. return STATUS_SUCCESS;
  915. }
  916. //* OpenPersistentInterface
  917. //
  918. // Parses an interface key name into a guid
  919. // and opens the interface key.
  920. //
  921. NTSTATUS
  922. OpenPersistentInterface(
  923. HANDLE ParentKey,
  924. WCHAR *SubKeyName,
  925. GUID *Guid,
  926. HANDLE *IFKey,
  927. OpenRegKeyAction Action)
  928. {
  929. UNICODE_STRING UGuid;
  930. NTSTATUS Status;
  931. PAGED_CODE();
  932. //
  933. // First, parse the interface guid.
  934. //
  935. RtlInitUnicodeString(&UGuid, SubKeyName);
  936. Status = RtlGUIDFromString(&UGuid, Guid);
  937. if (! NT_SUCCESS(Status)) {
  938. //
  939. // Not a valid guid.
  940. //
  941. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_USER_ERROR,
  942. "OpenPersistentInterface: bad syntax %ls\n",
  943. SubKeyName));
  944. return STATUS_NO_MORE_ENTRIES;
  945. }
  946. //
  947. // Open the interface key.
  948. //
  949. Status = OpenRegKey(IFKey, ParentKey, SubKeyName, Action);
  950. if (! NT_SUCCESS(Status)) {
  951. //
  952. // Could not open the interface key.
  953. //
  954. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_USER_ERROR,
  955. "OpenPersistentInterface: bad key %ls\n",
  956. SubKeyName));
  957. return STATUS_NO_MORE_ENTRIES;
  958. }
  959. return STATUS_SUCCESS;
  960. }
  961. //* EnumPersistentInterface
  962. //
  963. // Helper function for FindPersistentInterfaceFromQuery,
  964. // wrapping OpenPersistentInterface for EnumRegKeyIndex.
  965. //
  966. NTSTATUS
  967. EnumPersistentInterface(
  968. void *Context,
  969. HANDLE ParentKey,
  970. WCHAR *SubKeyName)
  971. {
  972. struct {
  973. GUID *Guid;
  974. HANDLE *IFKey;
  975. OpenRegKeyAction Action;
  976. } *Args = Context;
  977. PAGED_CODE();
  978. return OpenPersistentInterface(ParentKey, SubKeyName,
  979. Args->Guid,
  980. Args->IFKey,
  981. Args->Action);
  982. }
  983. //* FindPersistentInterfaceFromQuery
  984. //
  985. // Given an IPV6_PERSISTENT_QUERY_INTERFACE structure,
  986. // finds the specified interface key in the registry.
  987. // If the interface key is found, then Query->Guid is returned.
  988. //
  989. NTSTATUS
  990. FindPersistentInterfaceFromQuery(
  991. IPV6_PERSISTENT_QUERY_INTERFACE *Query,
  992. HANDLE *IFKey)
  993. {
  994. NTSTATUS Status;
  995. if (Query->RegistryIndex == (uint)-1) {
  996. //
  997. // Persistent query via guid.
  998. //
  999. return OpenInterfaceRegKey(&Query->Guid, IFKey, OpenRegKeyRead);
  1000. }
  1001. else {
  1002. HANDLE InterfacesKey;
  1003. struct {
  1004. GUID *Guid;
  1005. HANDLE *IFKey;
  1006. OpenRegKeyAction Action;
  1007. } Args;
  1008. //
  1009. // Persistent query via registry index.
  1010. //
  1011. Status = OpenTopLevelRegKey(L"Interfaces", &InterfacesKey,
  1012. OpenRegKeyRead);
  1013. if (! NT_SUCCESS(Status)) {
  1014. //
  1015. // If the Interfaces subkey is not present,
  1016. // then the index is not present.
  1017. //
  1018. if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
  1019. Status = STATUS_NO_MORE_ENTRIES;
  1020. return Status;
  1021. }
  1022. Args.Guid = &Query->Guid;
  1023. Args.IFKey = IFKey;
  1024. Args.Action = OpenRegKeyRead;
  1025. Status = EnumRegKeyIndex(InterfacesKey,
  1026. Query->RegistryIndex,
  1027. EnumPersistentInterface,
  1028. &Args);
  1029. ZwClose(InterfacesKey);
  1030. return Status;
  1031. }
  1032. }
  1033. //* IoctlPersistentQueryInterface
  1034. //
  1035. // Processes an IOCTL_IPV6_PERSISTENT_QUERY_INTERFACE request.
  1036. //
  1037. // Note: Return value indicates whether NT-specific processing of the
  1038. // request was successful. The status of the actual request is returned
  1039. // in the request buffers.
  1040. //
  1041. NTSTATUS
  1042. IoctlPersistentQueryInterface(
  1043. IN PIRP Irp, // I/O request packet.
  1044. IN PIO_STACK_LOCATION IrpSp) // Current stack location in the Irp.
  1045. {
  1046. IPV6_PERSISTENT_QUERY_INTERFACE *Query;
  1047. IPV6_INFO_INTERFACE *Info;
  1048. HANDLE IFKey;
  1049. NTSTATUS Status;
  1050. PAGED_CODE();
  1051. Irp->IoStatus.Information = 0;
  1052. if ((IrpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof *Query) ||
  1053. (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof *Info)) {
  1054. Status = STATUS_INVALID_PARAMETER;
  1055. goto Return;
  1056. }
  1057. Query = (IPV6_PERSISTENT_QUERY_INTERFACE *)
  1058. Irp->AssociatedIrp.SystemBuffer;
  1059. Info = (IPV6_INFO_INTERFACE *)
  1060. Irp->AssociatedIrp.SystemBuffer;
  1061. Status = FindPersistentInterfaceFromQuery(Query, &IFKey);
  1062. if (! NT_SUCCESS(Status))
  1063. goto Return;
  1064. //
  1065. // Let ReadPersistentInterface know how much space is available
  1066. // for link-layer addresses. It will use this field to return
  1067. // how much space it actually used.
  1068. //
  1069. Info->Length = (IrpSp->Parameters.DeviceIoControl.OutputBufferLength -
  1070. sizeof *Info);
  1071. //
  1072. // The interface index is not returned for persistent queries.
  1073. //
  1074. Info->This.Index = 0;
  1075. Info->This.Guid = Query->Guid;
  1076. Status = ReadPersistentInterface(IFKey, Info);
  1077. ZwClose(IFKey);
  1078. if (NT_SUCCESS(Status)) {
  1079. //
  1080. // Return link-layer addresses too.
  1081. //
  1082. Irp->IoStatus.Information = sizeof *Info + Info->Length;
  1083. Status = STATUS_SUCCESS;
  1084. }
  1085. else if (Status == STATUS_BUFFER_OVERFLOW) {
  1086. //
  1087. // Return the fixed-size structure.
  1088. //
  1089. Irp->IoStatus.Information = sizeof *Info;
  1090. }
  1091. else
  1092. goto Return;
  1093. //
  1094. // Do not return query information for the next interface,
  1095. // since persistent iteration uses RegistryIndex.
  1096. //
  1097. ReturnQueryInterface(NULL, &Info->Next);
  1098. Info->Length = sizeof *Info;
  1099. Return:
  1100. Irp->IoStatus.Status = Status;
  1101. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1102. return Status;
  1103. } // IoctlPersistentQueryInterface
  1104. //* ReturnQueryAddress
  1105. //
  1106. // Initializes a returned IPV6_QUERY_ADDRESS structure
  1107. // with query information for the specified address.
  1108. // Does NOT initialize Query->IF.
  1109. //
  1110. void
  1111. ReturnQueryAddress(
  1112. AddressEntry *ADE,
  1113. IPV6_QUERY_ADDRESS *Query)
  1114. {
  1115. if (ADE == NULL)
  1116. Query->Address = UnspecifiedAddr;
  1117. else
  1118. Query->Address = ADE->Address;
  1119. }
  1120. //* IoctlQueryAddress
  1121. //
  1122. // Processes an IOCTL_IPV6_QUERY_ADDRESS request.
  1123. //
  1124. // Note: Return value indicates whether NT-specific processing of the
  1125. // request was successful. The status of the actual request is returned
  1126. // in the request buffers.
  1127. //
  1128. NTSTATUS
  1129. IoctlQueryAddress(
  1130. IN PIRP Irp, // I/O request packet.
  1131. IN PIO_STACK_LOCATION IrpSp) // Current stack location in the Irp.
  1132. {
  1133. IPV6_QUERY_ADDRESS *Query;
  1134. IPV6_INFO_ADDRESS *Info;
  1135. Interface *IF = NULL;
  1136. AddressEntry *ADE;
  1137. KIRQL OldIrql;
  1138. NTSTATUS Status;
  1139. Irp->IoStatus.Information = 0;
  1140. if ((IrpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof *Query) ||
  1141. (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof *Info)) {
  1142. Status = STATUS_INVALID_PARAMETER;
  1143. goto Return;
  1144. }
  1145. //
  1146. // Note that the Query and Info->Next structures overlap!
  1147. //
  1148. Query = (IPV6_QUERY_ADDRESS *) Irp->AssociatedIrp.SystemBuffer;
  1149. Info = (IPV6_INFO_ADDRESS *) Irp->AssociatedIrp.SystemBuffer;
  1150. //
  1151. // Return information about the specified interface.
  1152. //
  1153. IF = FindInterfaceFromQuery(&Query->IF);
  1154. if (IF == NULL) {
  1155. Status = STATUS_INVALID_PARAMETER_1;
  1156. goto Return;
  1157. }
  1158. if (IsUnspecified(&Query->Address)) {
  1159. //
  1160. // Return the address of the first ADE.
  1161. //
  1162. KeAcquireSpinLock(&IF->Lock, &OldIrql);
  1163. ReturnQueryAddress(IF->ADE, &Info->Next);
  1164. KeReleaseSpinLock(&IF->Lock, OldIrql);
  1165. Irp->IoStatus.Information = sizeof Info->Next;
  1166. } else {
  1167. //
  1168. // Find the specified ADE.
  1169. //
  1170. KeAcquireSpinLock(&IF->Lock, &OldIrql);
  1171. for (ADE = IF->ADE; ; ADE = ADE->Next) {
  1172. if (ADE == NULL) {
  1173. KeReleaseSpinLock(&IF->Lock, OldIrql);
  1174. Status = STATUS_INVALID_PARAMETER_2;
  1175. goto ReturnReleaseIF;
  1176. }
  1177. if (IP6_ADDR_EQUAL(&Query->Address, &ADE->Address))
  1178. break;
  1179. }
  1180. //
  1181. // Return misc. information about the ADE.
  1182. //
  1183. Info->This = *Query;
  1184. Info->Type = ADE->Type;
  1185. Info->Scope = ADE->Scope;
  1186. Info->ScopeId = DetermineScopeId(&ADE->Address, IF);
  1187. switch (ADE->Type) {
  1188. case ADE_UNICAST: {
  1189. NetTableEntry *NTE = (NetTableEntry *)ADE;
  1190. struct AddrConfEntry AddrConf;
  1191. Info->DADState = NTE->DADState;
  1192. AddrConf.Value = NTE->AddrConf;
  1193. Info->PrefixConf = AddrConf.PrefixConf;
  1194. Info->InterfaceIdConf = AddrConf.InterfaceIdConf;
  1195. Info->ValidLifetime = ConvertTicksToSeconds(NTE->ValidLifetime);
  1196. Info->PreferredLifetime = ConvertTicksToSeconds(NTE->PreferredLifetime);
  1197. break;
  1198. }
  1199. case ADE_MULTICAST: {
  1200. MulticastAddressEntry *MAE = (MulticastAddressEntry *)ADE;
  1201. Info->MCastRefCount = MAE->MCastRefCount;
  1202. Info->MCastFlags = MAE->MCastFlags;
  1203. Info->MCastTimer = ConvertTicksToSeconds(MAE->MCastTimer);
  1204. break;
  1205. }
  1206. }
  1207. //
  1208. // Return address of the next ADE.
  1209. //
  1210. ReturnQueryAddress(ADE->Next, &Info->Next);
  1211. KeReleaseSpinLock(&IF->Lock, OldIrql);
  1212. Irp->IoStatus.Information = sizeof *Info;
  1213. }
  1214. ReturnQueryInterface(IF, &Info->Next.IF);
  1215. Status = STATUS_SUCCESS;
  1216. ReturnReleaseIF:
  1217. ReleaseIF(IF);
  1218. Return:
  1219. Irp->IoStatus.Status = Status;
  1220. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1221. return Status;
  1222. } // IoctlQueryAddress
  1223. //* OpenAddressRegKey
  1224. //
  1225. // Given an interface's registry key and an IPv6 address,
  1226. // opens the registry key with configuration info for the address.
  1227. //
  1228. // Callable from thread context, not DPC context.
  1229. //
  1230. NTSTATUS
  1231. OpenAddressRegKey(HANDLE IFKey, const IPv6Addr *Addr,
  1232. OUT HANDLE *RegKey, OpenRegKeyAction Action)
  1233. {
  1234. WCHAR AddressName[64];
  1235. HANDLE AddressesKey;
  1236. NTSTATUS Status;
  1237. PAGED_CODE();
  1238. Status = OpenRegKey(&AddressesKey, IFKey, L"Addresses",
  1239. ((Action == OpenRegKeyCreate) ?
  1240. OpenRegKeyCreate : OpenRegKeyRead));
  1241. if (! NT_SUCCESS(Status))
  1242. return Status;
  1243. //
  1244. // The output of RtlIpv6AddressToString may change
  1245. // over time with improvements/changes in the pretty-printing,
  1246. // and we need a consistent mapping.
  1247. // It doesn't need to be pretty.
  1248. //
  1249. swprintf(AddressName,
  1250. L"%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
  1251. net_short(Addr->s6_words[0]), net_short(Addr->s6_words[1]),
  1252. net_short(Addr->s6_words[2]), net_short(Addr->s6_words[3]),
  1253. net_short(Addr->s6_words[4]), net_short(Addr->s6_words[5]),
  1254. net_short(Addr->s6_words[6]), net_short(Addr->s6_words[7]));
  1255. Status = OpenRegKey(RegKey, AddressesKey, AddressName, Action);
  1256. ZwClose(AddressesKey);
  1257. return Status;
  1258. }
  1259. //* OpenPersistentAddress
  1260. //
  1261. // Parses an address key name into an address
  1262. // and opens the address key.
  1263. //
  1264. NTSTATUS
  1265. OpenPersistentAddress(
  1266. HANDLE ParentKey,
  1267. WCHAR *SubKeyName,
  1268. IPv6Addr *Address,
  1269. HANDLE *AddrKey,
  1270. OpenRegKeyAction Action)
  1271. {
  1272. WCHAR *Terminator;
  1273. NTSTATUS Status;
  1274. PAGED_CODE();
  1275. //
  1276. // First, parse the address.
  1277. //
  1278. if (! ParseV6Address(SubKeyName, &Terminator, Address) ||
  1279. (*Terminator != UNICODE_NULL)) {
  1280. //
  1281. // Not a valid address.
  1282. //
  1283. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_USER_ERROR,
  1284. "OpenPersistentAddress: bad syntax %ls\n",
  1285. SubKeyName));
  1286. return STATUS_NO_MORE_ENTRIES;
  1287. }
  1288. //
  1289. // Open the address key.
  1290. //
  1291. Status = OpenRegKey(AddrKey, ParentKey, SubKeyName, Action);
  1292. if (! NT_SUCCESS(Status)) {
  1293. //
  1294. // Could not open the address key.
  1295. //
  1296. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_USER_ERROR,
  1297. "OpenPersistentAddress: bad key %ls\n",
  1298. SubKeyName));
  1299. return STATUS_NO_MORE_ENTRIES;
  1300. }
  1301. return STATUS_SUCCESS;
  1302. }
  1303. //* EnumPersistentAddress
  1304. //
  1305. // Helper function for FindPersistentAddressFromQuery,
  1306. // wrapping OpenPersistentAddress for EnumRegKeyIndex.
  1307. //
  1308. NTSTATUS
  1309. EnumPersistentAddress(
  1310. void *Context,
  1311. HANDLE ParentKey,
  1312. WCHAR *SubKeyName)
  1313. {
  1314. struct {
  1315. IPv6Addr *Address;
  1316. HANDLE *AddrKey;
  1317. OpenRegKeyAction Action;
  1318. } *Args = Context;
  1319. PAGED_CODE();
  1320. return OpenPersistentAddress(ParentKey, SubKeyName,
  1321. Args->Address,
  1322. Args->AddrKey,
  1323. Args->Action);
  1324. }
  1325. //* FindPersistentAddressFromQuery
  1326. //
  1327. // Given an IPV6_PERSISTENT_QUERY_ADDRESS structure,
  1328. // finds the specified address key in the registry.
  1329. // If the address key is found, then Query->IF.Guid and
  1330. // Query->Address are returned.
  1331. //
  1332. NTSTATUS
  1333. FindPersistentAddressFromQuery(
  1334. IPV6_PERSISTENT_QUERY_ADDRESS *Query,
  1335. HANDLE *AddrKey)
  1336. {
  1337. HANDLE IFKey;
  1338. NTSTATUS Status;
  1339. PAGED_CODE();
  1340. //
  1341. // First get the interface key.
  1342. //
  1343. Status = FindPersistentInterfaceFromQuery(&Query->IF, &IFKey);
  1344. if (! NT_SUCCESS(Status))
  1345. return STATUS_INVALID_PARAMETER_1;
  1346. if (Query->RegistryIndex == (uint)-1) {
  1347. //
  1348. // Persistent query via address.
  1349. //
  1350. Status = OpenAddressRegKey(IFKey, &Query->Address,
  1351. AddrKey, OpenRegKeyRead);
  1352. }
  1353. else {
  1354. HANDLE AddressesKey;
  1355. //
  1356. // Open the Addresses subkey.
  1357. //
  1358. Status = OpenRegKey(&AddressesKey, IFKey,
  1359. L"Addresses", OpenRegKeyRead);
  1360. if (NT_SUCCESS(Status)) {
  1361. struct {
  1362. IPv6Addr *Address;
  1363. HANDLE *AddrKey;
  1364. OpenRegKeyAction Action;
  1365. } Args;
  1366. //
  1367. // Persistent query via registry index.
  1368. //
  1369. Args.Address = &Query->Address;
  1370. Args.AddrKey = AddrKey;
  1371. Args.Action = OpenRegKeyRead;
  1372. Status = EnumRegKeyIndex(AddressesKey,
  1373. Query->RegistryIndex,
  1374. EnumPersistentAddress,
  1375. &Args);
  1376. ZwClose(AddressesKey);
  1377. }
  1378. else {
  1379. //
  1380. // If the Addresses subkey is not present,
  1381. // then the index is not present.
  1382. //
  1383. if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
  1384. Status = STATUS_NO_MORE_ENTRIES;
  1385. }
  1386. }
  1387. ZwClose(IFKey);
  1388. return Status;
  1389. }
  1390. //* GetPersistentLifetimes
  1391. //
  1392. // Read valid and preferred lifetimes from the registry key.
  1393. //
  1394. void
  1395. GetPersistentLifetimes(
  1396. HANDLE RegKey,
  1397. int Immortal,
  1398. uint *ValidLifetime,
  1399. uint *PreferredLifetime)
  1400. {
  1401. LARGE_INTEGER ValidLifetime64;
  1402. LARGE_INTEGER PreferredLifetime64;
  1403. //
  1404. // Read the 64-bit lifetimes.
  1405. //
  1406. ValidLifetime64.QuadPart = (LONGLONG) (LONG)INFINITE_LIFETIME;
  1407. InitRegQUADParameter(RegKey, L"ValidLifetime", &ValidLifetime64);
  1408. PreferredLifetime64.QuadPart = (LONGLONG) (LONG)INFINITE_LIFETIME;
  1409. InitRegQUADParameter(RegKey, L"PreferredLifetime", &PreferredLifetime64);
  1410. //
  1411. // Convert the lifetimes from 64-bit times to seconds.
  1412. // If the lifetimes are Immortal, then the persisted values
  1413. // are relative lifetimes. Otherwise they are absolute lifetimes.
  1414. //
  1415. if (Immortal) {
  1416. if (ValidLifetime64.QuadPart == (LONGLONG) (LONG)INFINITE_LIFETIME)
  1417. *ValidLifetime = INFINITE_LIFETIME;
  1418. else
  1419. *ValidLifetime = (uint)
  1420. (ValidLifetime64.QuadPart / (10*1000*1000));
  1421. if (PreferredLifetime64.QuadPart == (LONGLONG) (LONG)INFINITE_LIFETIME)
  1422. *PreferredLifetime = INFINITE_LIFETIME;
  1423. else
  1424. *PreferredLifetime = (uint)
  1425. (PreferredLifetime64.QuadPart / (10*1000*1000));
  1426. }
  1427. else {
  1428. LARGE_INTEGER Now64;
  1429. KeQuerySystemTime(&Now64);
  1430. if (ValidLifetime64.QuadPart == (LONGLONG) (LONG)INFINITE_LIFETIME)
  1431. *ValidLifetime = INFINITE_LIFETIME;
  1432. else if (ValidLifetime64.QuadPart < Now64.QuadPart)
  1433. *ValidLifetime = 0;
  1434. else
  1435. *ValidLifetime = (uint)
  1436. ((ValidLifetime64.QuadPart - Now64.QuadPart) / (10*1000*1000));
  1437. if (PreferredLifetime64.QuadPart == (LONGLONG) (LONG)INFINITE_LIFETIME)
  1438. *PreferredLifetime = INFINITE_LIFETIME;
  1439. else if (PreferredLifetime64.QuadPart < Now64.QuadPart)
  1440. *PreferredLifetime = 0;
  1441. else
  1442. *PreferredLifetime = (uint)
  1443. ((PreferredLifetime64.QuadPart - Now64.QuadPart) / (10*1000*1000));
  1444. }
  1445. }
  1446. //* SetPersistentLifetimes
  1447. //
  1448. // Write valid and preferred lifetimes to the registry key.
  1449. //
  1450. NTSTATUS
  1451. SetPersistentLifetimes(
  1452. HANDLE RegKey,
  1453. int Immortal,
  1454. uint ValidLifetime,
  1455. uint PreferredLifetime)
  1456. {
  1457. LARGE_INTEGER ValidLifetime64;
  1458. LARGE_INTEGER PreferredLifetime64;
  1459. NTSTATUS Status;
  1460. //
  1461. // Persist the lifetimes as 64-bit times.
  1462. // If the lifetimes are Immortal, then we persist
  1463. // relative lifetimes. Otherwise we persist
  1464. // absolute lifetimes.
  1465. //
  1466. if (Immortal) {
  1467. if (ValidLifetime == INFINITE_LIFETIME)
  1468. ValidLifetime64.QuadPart = (LONGLONG) (LONG)INFINITE_LIFETIME;
  1469. else
  1470. ValidLifetime64.QuadPart = (10*1000*1000) *
  1471. (LONGLONG) ValidLifetime;
  1472. if (PreferredLifetime == INFINITE_LIFETIME)
  1473. PreferredLifetime64.QuadPart = (LONGLONG) (LONG)INFINITE_LIFETIME;
  1474. else
  1475. PreferredLifetime64.QuadPart = (10*1000*1000) *
  1476. (LONGLONG) PreferredLifetime;
  1477. }
  1478. else {
  1479. LARGE_INTEGER Now64;
  1480. KeQuerySystemTime(&Now64);
  1481. if (ValidLifetime == INFINITE_LIFETIME)
  1482. ValidLifetime64.QuadPart = (LONGLONG) (LONG)INFINITE_LIFETIME;
  1483. else
  1484. ValidLifetime64.QuadPart = Now64.QuadPart + (10*1000*1000) *
  1485. (LONGLONG) ValidLifetime;
  1486. if (PreferredLifetime == INFINITE_LIFETIME)
  1487. PreferredLifetime64.QuadPart = (LONGLONG) (LONG)INFINITE_LIFETIME;
  1488. else
  1489. PreferredLifetime64.QuadPart = Now64.QuadPart + (10*1000*1000) *
  1490. (LONGLONG) PreferredLifetime;
  1491. }
  1492. //
  1493. // Persist the valid lifetime.
  1494. //
  1495. Status = SetRegQUADValue(RegKey, L"ValidLifetime",
  1496. &ValidLifetime64);
  1497. if (! NT_SUCCESS(Status))
  1498. return Status;
  1499. //
  1500. // Persist the preferred lifetime.
  1501. //
  1502. Status = SetRegQUADValue(RegKey, L"PreferredLifetime",
  1503. &PreferredLifetime64);
  1504. return Status;
  1505. }
  1506. //* ReadPersistentAddress
  1507. //
  1508. // Reads address attributes from the registry key.
  1509. // Initializes all the fields except This.
  1510. //
  1511. void
  1512. ReadPersistentAddress(
  1513. HANDLE AddrKey,
  1514. IPV6_UPDATE_ADDRESS *Info)
  1515. {
  1516. InitRegDWORDParameter(AddrKey, L"Type",
  1517. (ULONG *)&Info->Type, ADE_UNICAST);
  1518. Info->PrefixConf = PREFIX_CONF_MANUAL;
  1519. Info->InterfaceIdConf = IID_CONF_MANUAL;
  1520. GetPersistentLifetimes(AddrKey, FALSE,
  1521. &Info->ValidLifetime,
  1522. &Info->PreferredLifetime);
  1523. }
  1524. //* IoctlPersistentQueryAddress
  1525. //
  1526. // Processes an IOCTL_IPV6_PERSISTENT_QUERY_ADDRESS request.
  1527. //
  1528. // Note: Return value indicates whether NT-specific processing of the
  1529. // request was successful. The status of the actual request is returned
  1530. // in the request buffers.
  1531. //
  1532. NTSTATUS
  1533. IoctlPersistentQueryAddress(
  1534. IN PIRP Irp, // I/O request packet.
  1535. IN PIO_STACK_LOCATION IrpSp) // Current stack location in the Irp.
  1536. {
  1537. IPV6_PERSISTENT_QUERY_ADDRESS *Query;
  1538. IPV6_UPDATE_ADDRESS *Info;
  1539. IPV6_QUERY_ADDRESS This;
  1540. HANDLE AddrKey;
  1541. NTSTATUS Status;
  1542. Irp->IoStatus.Information = 0;
  1543. if ((IrpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof *Query) ||
  1544. (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof *Info)) {
  1545. Status = STATUS_INVALID_PARAMETER;
  1546. goto Return;
  1547. }
  1548. //
  1549. // Note that the Query and Info->This structures overlap!
  1550. //
  1551. Query = (IPV6_PERSISTENT_QUERY_ADDRESS *) Irp->AssociatedIrp.SystemBuffer;
  1552. Info = (IPV6_UPDATE_ADDRESS *) Irp->AssociatedIrp.SystemBuffer;
  1553. //
  1554. // Get the registry key for the specified address.
  1555. //
  1556. Status = FindPersistentAddressFromQuery(Query, &AddrKey);
  1557. if (! NT_SUCCESS(Status))
  1558. goto Return;
  1559. //
  1560. // The interface index is not returned for persistent queries.
  1561. //
  1562. This.IF.Index = 0;
  1563. This.IF.Guid = Query->IF.Guid;
  1564. This.Address = Query->Address;
  1565. Info->This = This;
  1566. //
  1567. // Read address information from the registry key.
  1568. //
  1569. ReadPersistentAddress(AddrKey, Info);
  1570. ZwClose(AddrKey);
  1571. Status = STATUS_SUCCESS;
  1572. Irp->IoStatus.Information = sizeof *Info;
  1573. Return:
  1574. Irp->IoStatus.Status = Status;
  1575. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1576. return Status;
  1577. } // IoctlPersistentQueryAddress
  1578. //* IoctlQueryNeighborCache
  1579. //
  1580. // Processes an IOCTL_IPV6_QUERY_NEIGHBOR_CACHE request.
  1581. //
  1582. // Note: Return value indicates whether NT-specific processing of the
  1583. // request was successful. The status of the actual request is returned
  1584. // in the request buffers.
  1585. //
  1586. NTSTATUS
  1587. IoctlQueryNeighborCache(
  1588. IN PIRP Irp, // I/O request packet.
  1589. IN PIO_STACK_LOCATION IrpSp) // Current stack location in the Irp.
  1590. {
  1591. IPV6_QUERY_NEIGHBOR_CACHE *Query;
  1592. IPV6_INFO_NEIGHBOR_CACHE *Info;
  1593. Interface *IF = NULL;
  1594. NeighborCacheEntry *NCE;
  1595. KIRQL OldIrql;
  1596. NTSTATUS Status;
  1597. PAGED_CODE();
  1598. Irp->IoStatus.Information = 0;
  1599. if ((IrpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof *Query) ||
  1600. (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof *Info)) {
  1601. Status = STATUS_INVALID_PARAMETER;
  1602. goto Return;
  1603. }
  1604. //
  1605. // Note that the Query and Info->Query structures overlap!
  1606. //
  1607. Query = (IPV6_QUERY_NEIGHBOR_CACHE *) Irp->AssociatedIrp.SystemBuffer;
  1608. Info = (IPV6_INFO_NEIGHBOR_CACHE *) Irp->AssociatedIrp.SystemBuffer;
  1609. //
  1610. // Return information about the specified interface.
  1611. //
  1612. IF = FindInterfaceFromQuery(&Query->IF);
  1613. if (IF == NULL) {
  1614. Status = STATUS_INVALID_PARAMETER_1;
  1615. goto Return;
  1616. }
  1617. if (IsUnspecified(&Query->Address)) {
  1618. //
  1619. // Return the address of the first NCE.
  1620. //
  1621. KeAcquireSpinLock(&IF->LockNC, &OldIrql);
  1622. if (IF->FirstNCE != SentinelNCE(IF))
  1623. Info->Query.Address = IF->FirstNCE->NeighborAddress;
  1624. KeReleaseSpinLock(&IF->LockNC, OldIrql);
  1625. Irp->IoStatus.Information = sizeof Info->Query;
  1626. } else {
  1627. uint Now = IPv6TickCount;
  1628. //
  1629. // Find the specified NCE.
  1630. //
  1631. KeAcquireSpinLock(&IF->LockNC, &OldIrql);
  1632. for (NCE = IF->FirstNCE; ; NCE = NCE->Next) {
  1633. if (NCE == SentinelNCE(IF)) {
  1634. KeReleaseSpinLock(&IF->LockNC, OldIrql);
  1635. Status = STATUS_INVALID_PARAMETER_2;
  1636. goto Return;
  1637. }
  1638. if (IP6_ADDR_EQUAL(&Query->Address, &NCE->NeighborAddress))
  1639. break;
  1640. }
  1641. Irp->IoStatus.Information = sizeof *Info;
  1642. //
  1643. // Return the neighbor's link-layer address,
  1644. // if there is room in the user's buffer.
  1645. //
  1646. Info->LinkLayerAddressLength = IF->LinkAddressLength;
  1647. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength >=
  1648. sizeof *Info + IF->LinkAddressLength) {
  1649. RtlCopyMemory(Info + 1, NCE->LinkAddress, IF->LinkAddressLength);
  1650. Irp->IoStatus.Information += IF->LinkAddressLength;
  1651. }
  1652. //
  1653. // Return miscellaneous information about the NCE.
  1654. //
  1655. Info->IsRouter = NCE->IsRouter;
  1656. Info->IsUnreachable = NCE->IsUnreachable;
  1657. if ((NCE->NDState == ND_STATE_REACHABLE) &&
  1658. ((uint)(Now - NCE->LastReachability) > IF->ReachableTime))
  1659. Info->NDState = ND_STATE_STALE;
  1660. else if ((NCE->NDState == ND_STATE_PROBE) &&
  1661. (NCE->NSCount == 0))
  1662. Info->NDState = ND_STATE_DELAY;
  1663. else
  1664. Info->NDState = NCE->NDState;
  1665. Info->ReachableTimer = ConvertTicksToMillis(IF->ReachableTime -
  1666. (Now - NCE->LastReachability));
  1667. //
  1668. // Return address of the next NCE (or zero).
  1669. //
  1670. if (NCE->Next == SentinelNCE(IF))
  1671. Info->Query.Address = UnspecifiedAddr;
  1672. else
  1673. Info->Query.Address = NCE->Next->NeighborAddress;
  1674. KeReleaseSpinLock(&IF->LockNC, OldIrql);
  1675. }
  1676. Status = STATUS_SUCCESS;
  1677. Return:
  1678. if (IF != NULL)
  1679. ReleaseIF(IF);
  1680. Irp->IoStatus.Status = Status;
  1681. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1682. return Status;
  1683. } // IoctlQueryNeighborCache
  1684. //* IoctlQueryRouteCache
  1685. //
  1686. // Processes an IOCTL_IPV6_QUERY_ROUTE_CACHE request.
  1687. //
  1688. // Note: Return value indicates whether NT-specific processing of the
  1689. // request was successful. The status of the actual request is returned
  1690. // in the request buffers.
  1691. //
  1692. NTSTATUS
  1693. IoctlQueryRouteCache(
  1694. IN PIRP Irp, // I/O request packet.
  1695. IN PIO_STACK_LOCATION IrpSp) // Current stack location in the Irp.
  1696. {
  1697. IPV6_QUERY_ROUTE_CACHE *Query;
  1698. IPV6_INFO_ROUTE_CACHE *Info;
  1699. RouteCacheEntry *RCE;
  1700. BindingCacheEntry *BCE;
  1701. KIRQL OldIrql;
  1702. NTSTATUS Status;
  1703. PAGED_CODE();
  1704. Irp->IoStatus.Information = 0;
  1705. if ((IrpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof *Query) ||
  1706. (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof *Info)) {
  1707. Status = STATUS_INVALID_PARAMETER;
  1708. goto Return;
  1709. }
  1710. //
  1711. // Note that the Query and Info->Query structures overlap!
  1712. //
  1713. Query = (IPV6_QUERY_ROUTE_CACHE *) Irp->AssociatedIrp.SystemBuffer;
  1714. Info = (IPV6_INFO_ROUTE_CACHE *) Irp->AssociatedIrp.SystemBuffer;
  1715. if (Query->IF.Index == 0) {
  1716. //
  1717. // Return the index and address of the first RCE.
  1718. //
  1719. KeAcquireSpinLock(&RouteCacheLock, &OldIrql);
  1720. if (RouteCache.First != SentinelRCE) {
  1721. Info->Query.IF.Index = RouteCache.First->NTE->IF->Index;
  1722. Info->Query.Address = RouteCache.First->Destination;
  1723. }
  1724. KeReleaseSpinLock(&RouteCacheLock, OldIrql);
  1725. Irp->IoStatus.Information = sizeof Info->Query;
  1726. } else {
  1727. uint Now = IPv6TickCount;
  1728. //
  1729. // Find the specified RCE.
  1730. //
  1731. KeAcquireSpinLock(&RouteCacheLock, &OldIrql);
  1732. for (RCE = RouteCache.First; ; RCE = RCE->Next) {
  1733. if (RCE == SentinelRCE) {
  1734. KeReleaseSpinLock(&RouteCacheLock, OldIrql);
  1735. Status = STATUS_INVALID_PARAMETER_2;
  1736. goto Return;
  1737. }
  1738. if (IP6_ADDR_EQUAL(&Query->Address, &RCE->Destination) &&
  1739. (Query->IF.Index == RCE->NTE->IF->Index))
  1740. break;
  1741. }
  1742. //
  1743. // Return misc. information about the RCE.
  1744. //
  1745. Info->Type = RCE->Type;
  1746. Info->Flags = RCE->Flags;
  1747. Info->Valid = (RCE->Valid == RouteCacheValidationCounter);
  1748. Info->SourceAddress = RCE->NTE->Address;
  1749. Info->NextHopAddress = RCE->NCE->NeighborAddress;
  1750. Info->NextHopInterface = RCE->NCE->IF->Index;
  1751. Info->PathMTU = RCE->PathMTU;
  1752. if (RCE->PMTULastSet != 0) {
  1753. uint SinceLastSet = Now - RCE->PMTULastSet;
  1754. ASSERT((int)SinceLastSet >= 0);
  1755. if (SinceLastSet < PATH_MTU_RETRY_TIME)
  1756. Info->PMTUProbeTimer =
  1757. ConvertTicksToMillis(PATH_MTU_RETRY_TIME - SinceLastSet);
  1758. else
  1759. Info->PMTUProbeTimer = 0; // Fires on next packet.
  1760. } else
  1761. Info->PMTUProbeTimer = INFINITE_LIFETIME; // Not set.
  1762. if (RCE->LastError != 0)
  1763. Info->ICMPLastError = ConvertTicksToMillis(Now - RCE->LastError);
  1764. else
  1765. Info->ICMPLastError = 0;
  1766. if (RCE->BCE != NULL) {
  1767. Info->CareOfAddress = RCE->BCE->CareOfRCE->Destination;
  1768. Info->BindingSeqNumber = RCE->BCE->BindingSeqNumber;
  1769. Info->BindingLifetime = ConvertTicksToSeconds(RCE->BCE->BindingLifetime);
  1770. } else {
  1771. Info->CareOfAddress = UnspecifiedAddr;
  1772. Info->BindingSeqNumber = 0;
  1773. Info->BindingLifetime = 0;
  1774. }
  1775. //
  1776. // Return index and address of the next RCE (or zero).
  1777. //
  1778. if (RCE->Next == SentinelRCE) {
  1779. Info->Query.IF.Index = 0;
  1780. } else {
  1781. Info->Query.IF.Index = RCE->Next->NTE->IF->Index;
  1782. Info->Query.Address = RCE->Next->Destination;
  1783. }
  1784. KeReleaseSpinLock(&RouteCacheLock, OldIrql);
  1785. Irp->IoStatus.Information = sizeof *Info;
  1786. }
  1787. Status = STATUS_SUCCESS;
  1788. Return:
  1789. Irp->IoStatus.Status = Status;
  1790. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1791. return Status;
  1792. } // IoctlQueryRouteCache
  1793. //* IoctlCreateSecurityPolicy
  1794. //
  1795. NTSTATUS
  1796. IoctlCreateSecurityPolicy(
  1797. IN PIRP Irp, // I/O request packet.
  1798. IN PIO_STACK_LOCATION IrpSp) // Current stack location in the Irp.
  1799. {
  1800. IPV6_CREATE_SECURITY_POLICY *CreateSP;
  1801. SecurityPolicy *SP, *BundledSP;
  1802. NTSTATUS Status;
  1803. KIRQL OldIrql;
  1804. PAGED_CODE();
  1805. if ((IrpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof *CreateSP) ||
  1806. (IrpSp->Parameters.DeviceIoControl.OutputBufferLength != 0)) {
  1807. Status = STATUS_INVALID_PARAMETER;
  1808. goto Return;
  1809. }
  1810. CreateSP = (IPV6_CREATE_SECURITY_POLICY *)Irp->AssociatedIrp.SystemBuffer;
  1811. //
  1812. // Sanity check the user-supplied input values.
  1813. //
  1814. if ((CreateSP->RemoteAddrField != WILDCARD_VALUE) &&
  1815. (CreateSP->RemoteAddrField != SINGLE_VALUE) &&
  1816. (CreateSP->RemoteAddrField != RANGE_VALUE)) {
  1817. Status = STATUS_INVALID_PARAMETER_1;
  1818. goto Return;
  1819. }
  1820. if ((CreateSP->LocalAddrField != WILDCARD_VALUE) &&
  1821. (CreateSP->LocalAddrField != SINGLE_VALUE) &&
  1822. (CreateSP->LocalAddrField != RANGE_VALUE)) {
  1823. Status = STATUS_INVALID_PARAMETER_2;
  1824. goto Return;
  1825. }
  1826. // TransportProto can be anything.
  1827. // Port values can be anything.
  1828. //
  1829. // We do not support IPSEC_APPCHOICE.
  1830. //
  1831. if ((CreateSP->IPSecAction != IPSEC_DISCARD) &&
  1832. (CreateSP->IPSecAction != IPSEC_APPLY) &&
  1833. (CreateSP->IPSecAction != IPSEC_BYPASS)) {
  1834. Status = STATUS_INVALID_PARAMETER_3;
  1835. goto Return;
  1836. }
  1837. if ((CreateSP->IPSecProtocol != IP_PROTOCOL_AH) &&
  1838. (CreateSP->IPSecProtocol != IP_PROTOCOL_ESP) &&
  1839. (CreateSP->IPSecProtocol != NONE)) {
  1840. Status = STATUS_INVALID_PARAMETER_4;
  1841. goto Return;
  1842. }
  1843. if ((CreateSP->IPSecMode != TRANSPORT) &&
  1844. (CreateSP->IPSecMode != TUNNEL) &&
  1845. (CreateSP->IPSecMode != NONE)) {
  1846. Status = STATUS_INVALID_PARAMETER_5;
  1847. goto Return;
  1848. }
  1849. if (CreateSP->IPSecAction == IPSEC_APPLY) {
  1850. if ((CreateSP->IPSecProtocol == NONE) ||
  1851. (CreateSP->IPSecMode == NONE)) {
  1852. Status = STATUS_INVALID_PARAMETER_MIX;
  1853. goto Return;
  1854. }
  1855. }
  1856. if ((CreateSP->Direction != INBOUND) &&
  1857. (CreateSP->Direction != OUTBOUND) &&
  1858. (CreateSP->Direction != BIDIRECTIONAL)) {
  1859. Status = STATUS_INVALID_PARAMETER_6;
  1860. goto Return;
  1861. }
  1862. if (((CreateSP->RemoteAddrSelector != PACKET_SELECTOR) &&
  1863. (CreateSP->RemoteAddrSelector != POLICY_SELECTOR)) ||
  1864. ((CreateSP->LocalAddrSelector != PACKET_SELECTOR) &&
  1865. (CreateSP->LocalAddrSelector != POLICY_SELECTOR)) ||
  1866. ((CreateSP->RemotePortSelector != PACKET_SELECTOR) &&
  1867. (CreateSP->RemotePortSelector != POLICY_SELECTOR)) ||
  1868. ((CreateSP->LocalPortSelector != PACKET_SELECTOR) &&
  1869. (CreateSP->LocalPortSelector != POLICY_SELECTOR)) ||
  1870. ((CreateSP->TransportProtoSelector != PACKET_SELECTOR) &&
  1871. (CreateSP->TransportProtoSelector != POLICY_SELECTOR))) {
  1872. Status = STATUS_INVALID_PARAMETER_7;
  1873. goto Return;
  1874. }
  1875. // Get Security Lock.
  1876. KeAcquireSpinLock(&IPSecLock, &OldIrql);
  1877. //
  1878. // REVIEW: This considers a non-existent interface an error. Should it?
  1879. //
  1880. if (CreateSP->SPInterface != 0) {
  1881. Interface *IF;
  1882. IF = FindInterfaceFromIndex(CreateSP->SPInterface);
  1883. if (IF == NULL) {
  1884. //
  1885. // Unknown interface.
  1886. //
  1887. Status = STATUS_NOT_FOUND;
  1888. goto ReturnUnlock;
  1889. }
  1890. ReleaseIF(IF);
  1891. }
  1892. //
  1893. // Allocate memory for Security Policy.
  1894. //
  1895. SP = ExAllocatePool(NonPagedPool, sizeof *SP);
  1896. if (SP == NULL) {
  1897. Status = STATUS_INSUFFICIENT_RESOURCES;
  1898. goto ReturnUnlock;
  1899. }
  1900. //
  1901. // Copy CreateSP to SP.
  1902. //
  1903. SP->Index = CreateSP->SPIndex;
  1904. SP->RemoteAddr = CreateSP->RemoteAddr;
  1905. SP->RemoteAddrData = CreateSP->RemoteAddrData;
  1906. SP->RemoteAddrSelector = CreateSP->RemoteAddrSelector;
  1907. SP->RemoteAddrField = CreateSP->RemoteAddrField;
  1908. SP->LocalAddr = CreateSP->LocalAddr;
  1909. SP->LocalAddrData = CreateSP->LocalAddrData;
  1910. SP->LocalAddrSelector = CreateSP->LocalAddrSelector;
  1911. SP->LocalAddrField = CreateSP->LocalAddrField;
  1912. SP->TransportProto = CreateSP->TransportProto;
  1913. SP->TransportProtoSelector = CreateSP->TransportProtoSelector;
  1914. SP->RemotePort = CreateSP->RemotePort;
  1915. SP->RemotePortData = CreateSP->RemotePortData;
  1916. SP->RemotePortSelector = CreateSP->RemotePortSelector;
  1917. SP->RemotePortField = CreateSP->RemotePortField;
  1918. SP->LocalPort = CreateSP->LocalPort;
  1919. SP->LocalPortData = CreateSP->LocalPortData;
  1920. SP->LocalPortSelector = CreateSP->LocalPortSelector;
  1921. SP->LocalPortField = CreateSP->LocalPortField;
  1922. SP->SecPolicyFlag = CreateSP->IPSecAction;
  1923. SP->IPSecSpec.Protocol = CreateSP->IPSecProtocol;
  1924. SP->IPSecSpec.Mode = CreateSP->IPSecMode;
  1925. SP->IPSecSpec.RemoteSecGWIPAddr = CreateSP->RemoteSecurityGWAddr;
  1926. SP->DirectionFlag = CreateSP->Direction;
  1927. SP->OutboundSA = NULL;
  1928. SP->InboundSA = NULL;
  1929. SP->PrevSABundle = NULL;
  1930. SP->RefCnt = 0;
  1931. SP->NestCount = 1;
  1932. SP->IFIndex = CreateSP->SPInterface;
  1933. //
  1934. // Insert SP into the global list.
  1935. //
  1936. if (!InsertSecurityPolicy(SP)) {
  1937. //
  1938. // Couldn't insert, free up failed SP memory.
  1939. //
  1940. ExFreePool(SP);
  1941. Status = STATUS_OBJECT_NAME_COLLISION;
  1942. goto ReturnUnlock;
  1943. }
  1944. //
  1945. // Convert SABundleIndex to the SABundle pointer.
  1946. //
  1947. if (CreateSP->SABundleIndex == 0) {
  1948. SP->SABundle = NULL;
  1949. } else {
  1950. // Search the SP List starting at the first SP.
  1951. BundledSP = FindSecurityPolicyMatch(SecurityPolicyList, 0,
  1952. CreateSP->SABundleIndex);
  1953. if (BundledSP == NULL) {
  1954. //
  1955. // Policy with which this new one was supposed to bundle
  1956. // does not exist. Abort creation of this new policy.
  1957. //
  1958. RemoveSecurityPolicy(SP);
  1959. ExFreePool(SP);
  1960. Status = STATUS_INVALID_PARAMETER;
  1961. goto ReturnUnlock;
  1962. } else {
  1963. SP->SABundle = BundledSP;
  1964. BundledSP->RefCnt++;
  1965. SP->NestCount = BundledSP->NestCount + 1;
  1966. //
  1967. // The bundle entry list is doubly linked to facilitate
  1968. // ease of entry deletion.
  1969. //
  1970. BundledSP->PrevSABundle = SP;
  1971. SP->RefCnt++;
  1972. }
  1973. }
  1974. Status = STATUS_SUCCESS;
  1975. ReturnUnlock:
  1976. // Release lock.
  1977. KeReleaseSpinLock(&IPSecLock, OldIrql);
  1978. Return:
  1979. Irp->IoStatus.Status = Status;
  1980. Irp->IoStatus.Information = 0;
  1981. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1982. return Status;
  1983. } // IoctlCreateSecurityPolicy
  1984. //* IoctlCreateSecurityAssociation
  1985. //
  1986. NTSTATUS
  1987. IoctlCreateSecurityAssociation(
  1988. IN PIRP Irp, // I/O request packet.
  1989. IN PIO_STACK_LOCATION IrpSp) // Current stack location in the Irp.
  1990. {
  1991. IPV6_CREATE_SECURITY_ASSOCIATION *CreateSA;
  1992. SecurityAssociation *SA;
  1993. SecurityPolicy *SP;
  1994. uint KeySize;
  1995. uchar *RawKey;
  1996. NTSTATUS Status;
  1997. KIRQL OldIrql;
  1998. PAGED_CODE();
  1999. if ((IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof *CreateSA) ||
  2000. (IrpSp->Parameters.DeviceIoControl.OutputBufferLength != 0)) {
  2001. Status = STATUS_INVALID_PARAMETER;
  2002. goto Return;
  2003. }
  2004. CreateSA = (IPV6_CREATE_SECURITY_ASSOCIATION *)Irp->AssociatedIrp.SystemBuffer;
  2005. //
  2006. // Sanity check the user-supplied input values.
  2007. //
  2008. if ((CreateSA->Direction != INBOUND) &&
  2009. (CreateSA->Direction != OUTBOUND)) {
  2010. Status = STATUS_INVALID_PARAMETER_1;
  2011. goto Return;
  2012. }
  2013. if (CreateSA->AlgorithmId >= NUM_ALGORITHMS) {
  2014. Status = STATUS_INVALID_PARAMETER_2;
  2015. goto Return;
  2016. }
  2017. KeySize = AlgorithmTable[CreateSA->AlgorithmId].KeySize;
  2018. if (CreateSA->RawKeySize > MAX_KEY_SIZE) {
  2019. //
  2020. // We cap the RawKeySize at something rational.
  2021. //
  2022. Status = STATUS_INVALID_PARAMETER_3;
  2023. goto Return;
  2024. }
  2025. //
  2026. // RawKey should be passed in the Ioctl immediately after CreateSA.
  2027. //
  2028. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength !=
  2029. (sizeof(*CreateSA) + CreateSA->RawKeySize)) {
  2030. Status = STATUS_INVALID_PARAMETER;
  2031. goto Return;
  2032. }
  2033. RawKey = (uchar *)(CreateSA + 1);
  2034. //
  2035. // Allocate memory for Security Association and the Key.
  2036. // The Key will immediately follow the SA in memory.
  2037. //
  2038. #ifdef IPSEC_DEBUG
  2039. SA = ExAllocatePool(NonPagedPool,
  2040. sizeof(*SA) + KeySize + CreateSA->RawKeySize);
  2041. #else
  2042. SA = ExAllocatePool(NonPagedPool, sizeof(*SA) + KeySize);
  2043. #endif
  2044. if (SA == NULL) {
  2045. Status = STATUS_INSUFFICIENT_RESOURCES;
  2046. goto Return;
  2047. }
  2048. SA->Key = (uchar *)(SA + 1);
  2049. //
  2050. // Copy CreateSA to SA.
  2051. //
  2052. SA->Index = CreateSA->SAIndex;
  2053. SA->SPI = CreateSA->SPI;
  2054. SA->SequenceNum = 0;
  2055. SA->SADestAddr = CreateSA->SADestAddr;
  2056. SA->DestAddr = CreateSA->DestAddr;
  2057. SA->SrcAddr = CreateSA->SrcAddr;
  2058. SA->TransportProto = CreateSA->TransportProto;
  2059. SA->DestPort = CreateSA->DestPort;
  2060. SA->SrcPort = CreateSA->SrcPort;
  2061. SA->DirectionFlag = CreateSA->Direction;
  2062. SA->RefCnt = 0;
  2063. SA->AlgorithmId = CreateSA->AlgorithmId;
  2064. SA->KeyLength = KeySize;
  2065. #ifdef IPSEC_DEBUG
  2066. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_IPSEC,
  2067. "SA %d prepped KeySize is %d\n",
  2068. CreateSA->SAIndex, KeySize));
  2069. SA->RawKey = (uchar *)(SA->Key + KeySize);
  2070. SA->RawKeyLength = CreateSA->RawKeySize;
  2071. //
  2072. // Copy raw key to SA.
  2073. //
  2074. memcpy(SA->RawKey, RawKey, SA->RawKeyLength);
  2075. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_IPSEC,
  2076. "SA %d RawKey (%d bytes): ",
  2077. CreateSA->SAIndex, SA->RawKeyLength));
  2078. DumpKey(SA->RawKey, SA->RawKeyLength);
  2079. #endif
  2080. //
  2081. // Prepare the manual key.
  2082. //
  2083. (*AlgorithmTable[SA->AlgorithmId].PrepareKey)
  2084. (RawKey, CreateSA->RawKeySize, SA->Key);
  2085. //
  2086. // Get Security Lock.
  2087. //
  2088. KeAcquireSpinLock(&IPSecLock, &OldIrql);
  2089. //
  2090. // Find policy which this association instantiates.
  2091. //
  2092. SP = FindSecurityPolicyMatch(SecurityPolicyList, 0,
  2093. CreateSA->SecPolicyIndex);
  2094. if (SP == NULL) {
  2095. //
  2096. // No matching policy exists.
  2097. //
  2098. Status = STATUS_INVALID_PARAMETER_4;
  2099. ExFreePool(SA);
  2100. goto ReturnUnlock;
  2101. }
  2102. // Set the SA's IPSecProto to match that of the SP.
  2103. SA->IPSecProto = SP->IPSecSpec.Protocol;
  2104. //
  2105. // Check that direction of SA is legitimate for this SP.
  2106. //
  2107. if ((SA->DirectionFlag & SP->DirectionFlag) == 0) {
  2108. //
  2109. // Direction of SA is incompatible with SP's.
  2110. // Abort creation of this new association.
  2111. //
  2112. Status = STATUS_INVALID_PARAMETER_MIX;
  2113. ExFreePool(SA);
  2114. goto ReturnUnlock;
  2115. }
  2116. //
  2117. // Add this association to the global list.
  2118. //
  2119. if (!InsertSecurityAssociation(SA)) {
  2120. //
  2121. // Couldn't insert, free up failed SP memory.
  2122. //
  2123. Status = STATUS_OBJECT_NAME_COLLISION;
  2124. ExFreePool(SA);
  2125. goto ReturnUnlock;
  2126. }
  2127. //
  2128. // Add this association to policy's instantiated associations list.
  2129. //
  2130. if (SA->DirectionFlag == INBOUND) {
  2131. // Add the SA to the policy's inbound list.
  2132. SA->ChainedSecAssoc = SP->InboundSA;
  2133. SP->InboundSA = SA;
  2134. AddRefSA(SA);
  2135. // The SA keeps a pointer to the SP it instantiates.
  2136. SA->SecPolicy = SP;
  2137. SA->SecPolicy->RefCnt++;
  2138. } else {
  2139. // Add the SA to the policy's outbound list.
  2140. SA->ChainedSecAssoc = SP->OutboundSA;
  2141. SP->OutboundSA = SA;
  2142. AddRefSA(SA);
  2143. // Add the SP to the SA SecPolicy pointer.
  2144. SA->SecPolicy = SP;
  2145. SA->SecPolicy->RefCnt++;
  2146. }
  2147. SA->Valid = SA_VALID;
  2148. Status = STATUS_SUCCESS;
  2149. ReturnUnlock:
  2150. // Release lock.
  2151. KeReleaseSpinLock(&IPSecLock, OldIrql);
  2152. Return:
  2153. Irp->IoStatus.Status = Status;
  2154. Irp->IoStatus.Information = 0;
  2155. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  2156. return Status;
  2157. } // IoctlCreateSecurityAssociation
  2158. //* IoctlQuerySecurityPolicyList
  2159. //
  2160. NTSTATUS
  2161. IoctlQuerySecurityPolicyList(
  2162. IN PIRP Irp, // I/O request packet.
  2163. IN PIO_STACK_LOCATION IrpSp) // Current stack location in the Irp.
  2164. {
  2165. IPV6_QUERY_SECURITY_POLICY_LIST *Query;
  2166. IPV6_INFO_SECURITY_POLICY_LIST *Info;
  2167. SecurityPolicy *SP, *NextSP;
  2168. KIRQL OldIrql;
  2169. NTSTATUS Status;
  2170. PAGED_CODE();
  2171. Irp->IoStatus.Information = 0;
  2172. if ((IrpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof *Query) ||
  2173. (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof *Info)) {
  2174. Status = STATUS_INVALID_PARAMETER;
  2175. goto Return;
  2176. }
  2177. Query = (IPV6_QUERY_SECURITY_POLICY_LIST *)Irp->AssociatedIrp.SystemBuffer;
  2178. Info = (IPV6_INFO_SECURITY_POLICY_LIST *)Irp->AssociatedIrp.SystemBuffer;
  2179. //
  2180. // REVIEW: This considers a non-existent interface an error. Should it?
  2181. //
  2182. if (Query->SPInterface != 0) {
  2183. Interface *IF;
  2184. IF = FindInterfaceFromIndex(Query->SPInterface);
  2185. if (IF == NULL) {
  2186. //
  2187. // Unknown interface.
  2188. //
  2189. Status = STATUS_NOT_FOUND;
  2190. goto Return;
  2191. }
  2192. ReleaseIF(IF);
  2193. }
  2194. //
  2195. // Get Security Lock.
  2196. //
  2197. KeAcquireSpinLock(&IPSecLock, &OldIrql);
  2198. //
  2199. // Find matching policy.
  2200. //
  2201. SP = FindSecurityPolicyMatch(SecurityPolicyList, Query->SPInterface,
  2202. Query->Index);
  2203. if (SP == NULL) {
  2204. //
  2205. // No matching policy exists.
  2206. //
  2207. Status = STATUS_NO_MATCH;
  2208. goto ReturnUnlock;
  2209. }
  2210. //
  2211. // Get the next index to query.
  2212. //
  2213. NextSP = FindSecurityPolicyMatch(SP->Next, Query->SPInterface, 0);
  2214. if (NextSP == NULL) {
  2215. Info->NextSPIndex = 0;
  2216. } else {
  2217. Info->NextSPIndex = NextSP->Index;
  2218. }
  2219. //
  2220. // Copy SP to Info.
  2221. //
  2222. Info->SPIndex = SP->Index;
  2223. Info->RemoteAddr = SP->RemoteAddr;
  2224. Info->RemoteAddrData = SP->RemoteAddrData;
  2225. Info->RemoteAddrSelector = SP->RemoteAddrSelector;
  2226. Info->RemoteAddrField = SP->RemoteAddrField;
  2227. Info->LocalAddr = SP->LocalAddr;
  2228. Info->LocalAddrData = SP->LocalAddrData;
  2229. Info->LocalAddrSelector = SP->LocalAddrSelector;
  2230. Info->LocalAddrField = SP->LocalAddrField;
  2231. Info->TransportProto = SP->TransportProto;
  2232. Info->TransportProtoSelector = SP->TransportProtoSelector;
  2233. Info->RemotePort = SP->RemotePort;
  2234. Info->RemotePortData = SP->RemotePortData;
  2235. Info->RemotePortSelector = SP->RemotePortSelector;
  2236. Info->RemotePortField = SP->RemotePortField;
  2237. Info->LocalPort = SP->LocalPort;
  2238. Info->LocalPortData = SP->LocalPortData;
  2239. Info->LocalPortSelector = SP->LocalPortSelector;
  2240. Info->LocalPortField = SP->LocalPortField;
  2241. Info->IPSecProtocol = SP->IPSecSpec.Protocol;
  2242. Info->IPSecMode = SP->IPSecSpec.Mode;
  2243. Info->RemoteSecurityGWAddr = SP->IPSecSpec.RemoteSecGWIPAddr;
  2244. Info->Direction = SP->DirectionFlag;
  2245. Info->IPSecAction = SP->SecPolicyFlag;
  2246. Info->SABundleIndex = GetSecurityPolicyIndex(SP->SABundle);
  2247. Info->SPInterface = SP->IFIndex;
  2248. Status = STATUS_SUCCESS;
  2249. Irp->IoStatus.Information = sizeof *Info;
  2250. ReturnUnlock:
  2251. KeReleaseSpinLock(&IPSecLock, OldIrql);
  2252. Return:
  2253. Irp->IoStatus.Status = Status;
  2254. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  2255. return Status;
  2256. } // IoctlQuerySecurityPolicyList
  2257. //* IoctlDeleteSecurityPolicy
  2258. //
  2259. NTSTATUS
  2260. IoctlDeleteSecurityPolicy(
  2261. IN PIRP Irp, // I/O request packet.
  2262. IN PIO_STACK_LOCATION IrpSp) // Current stack location in the Irp.
  2263. {
  2264. IPV6_QUERY_SECURITY_POLICY_LIST *Query;
  2265. SecurityPolicy *SP;
  2266. KIRQL OldIrql;
  2267. NTSTATUS Status;
  2268. PAGED_CODE();
  2269. if ((IrpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof *Query) ||
  2270. (IrpSp->Parameters.DeviceIoControl.OutputBufferLength != 0)) {
  2271. Status = STATUS_INVALID_PARAMETER;
  2272. goto Return;
  2273. }
  2274. Query = (IPV6_QUERY_SECURITY_POLICY_LIST *)Irp->AssociatedIrp.SystemBuffer;
  2275. //
  2276. // Get Security Lock.
  2277. //
  2278. KeAcquireSpinLock(&IPSecLock, &OldIrql);
  2279. //
  2280. // Find the policy in question.
  2281. //
  2282. SP = FindSecurityPolicyMatch(SecurityPolicyList, 0, Query->Index);
  2283. if (SP == NULL) {
  2284. //
  2285. // The policy does not exist.
  2286. //
  2287. Status = STATUS_NO_MATCH;
  2288. goto ReturnUnlock;
  2289. }
  2290. //
  2291. // Remove the SP.
  2292. //
  2293. if (DeleteSP(SP)) {
  2294. Status = STATUS_SUCCESS;
  2295. } else {
  2296. Status = STATUS_UNSUCCESSFUL;
  2297. }
  2298. ReturnUnlock:
  2299. KeReleaseSpinLock(&IPSecLock, OldIrql);
  2300. Return:
  2301. Irp->IoStatus.Status = Status;
  2302. Irp->IoStatus.Information = 0;
  2303. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  2304. return Status;
  2305. }
  2306. //* IoctlQuerySecurityAssociationList
  2307. //
  2308. NTSTATUS
  2309. IoctlQuerySecurityAssociationList(
  2310. IN PIRP Irp, // I/O request packet.
  2311. IN PIO_STACK_LOCATION IrpSp) // Current stack location in the Irp.
  2312. {
  2313. IPV6_QUERY_SECURITY_ASSOCIATION_LIST *Query;
  2314. IPV6_INFO_SECURITY_ASSOCIATION_LIST *Info;
  2315. SecurityAssociation *SA;
  2316. KIRQL OldIrql;
  2317. NTSTATUS Status;
  2318. PAGED_CODE();
  2319. Irp->IoStatus.Information = 0;
  2320. if ((IrpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof *Query) ||
  2321. (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof *Info)) {
  2322. Status = STATUS_INVALID_PARAMETER;
  2323. goto Return;
  2324. }
  2325. Query = (IPV6_QUERY_SECURITY_ASSOCIATION_LIST *)Irp->AssociatedIrp.SystemBuffer;
  2326. Info = (IPV6_INFO_SECURITY_ASSOCIATION_LIST *)Irp->AssociatedIrp.SystemBuffer;
  2327. //
  2328. // Get Security Lock.
  2329. //
  2330. KeAcquireSpinLock(&IPSecLock, &OldIrql);
  2331. //
  2332. // Find matching association.
  2333. //
  2334. SA = FindSecurityAssociationMatch(Query->Index);
  2335. if (SA == NULL) {
  2336. //
  2337. // No matching association exists.
  2338. //
  2339. Status = STATUS_NO_MATCH;
  2340. goto ReturnUnlock;
  2341. }
  2342. //
  2343. // Get the next index to query.
  2344. //
  2345. if (SA->Next == NULL) {
  2346. // No more SAs after this one.
  2347. Info->NextSAIndex = 0;
  2348. } else {
  2349. // Return the next SA.
  2350. Info->NextSAIndex = SA->Next->Index;
  2351. }
  2352. //
  2353. // Copy SA to Info.
  2354. //
  2355. Info->SAIndex = SA->Index;
  2356. Info->SPI = SA->SPI;
  2357. Info->SADestAddr = SA->SADestAddr;
  2358. Info->DestAddr = SA->DestAddr;
  2359. Info->SrcAddr = SA->SrcAddr;
  2360. Info->TransportProto = SA->TransportProto;
  2361. Info->DestPort = SA->DestPort;
  2362. Info->SrcPort = SA->SrcPort;
  2363. Info->Direction = SA->DirectionFlag;
  2364. Info->SecPolicyIndex = GetSecurityPolicyIndex(SA->SecPolicy);
  2365. Info->AlgorithmId = SA->AlgorithmId;
  2366. Status = STATUS_SUCCESS;
  2367. Irp->IoStatus.Information = sizeof *Info;
  2368. ReturnUnlock:
  2369. KeReleaseSpinLock(&IPSecLock, OldIrql);
  2370. Return:
  2371. Irp->IoStatus.Status = Status;
  2372. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  2373. return Status;
  2374. } // IoctlQuerySecurityAssociationList
  2375. //* IoctlDeleteSecurityAssociation
  2376. //
  2377. NTSTATUS
  2378. IoctlDeleteSecurityAssociation(
  2379. IN PIRP Irp, // I/O request packet.
  2380. IN PIO_STACK_LOCATION IrpSp) // Current stack location in the Irp.
  2381. {
  2382. IPV6_QUERY_SECURITY_ASSOCIATION_LIST *Query;
  2383. SecurityAssociation *SA;
  2384. KIRQL OldIrql;
  2385. NTSTATUS Status;
  2386. PAGED_CODE();
  2387. if ((IrpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof *Query) ||
  2388. (IrpSp->Parameters.DeviceIoControl.OutputBufferLength != 0)) {
  2389. Status = STATUS_INVALID_PARAMETER;
  2390. goto Return;
  2391. }
  2392. Query = (IPV6_QUERY_SECURITY_ASSOCIATION_LIST *)Irp->AssociatedIrp.SystemBuffer;
  2393. //
  2394. // Get Security Lock.
  2395. //
  2396. KeAcquireSpinLock(&IPSecLock, &OldIrql);
  2397. //
  2398. // Find the association in question.
  2399. //
  2400. SA = FindSecurityAssociationMatch(Query->Index);
  2401. if (SA == NULL) {
  2402. //
  2403. // The association does not exist.
  2404. //
  2405. Status = STATUS_NO_MATCH;
  2406. goto ReturnUnlock;
  2407. }
  2408. //
  2409. // Remove the SA.
  2410. //
  2411. if (DeleteSA(SA)) {
  2412. Status = STATUS_SUCCESS;
  2413. } else {
  2414. Status = STATUS_UNSUCCESSFUL;
  2415. }
  2416. ReturnUnlock:
  2417. KeReleaseSpinLock(&IPSecLock, OldIrql);
  2418. Return:
  2419. Irp->IoStatus.Status = Status;
  2420. Irp->IoStatus.Information = 0;
  2421. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  2422. return Status;
  2423. }
  2424. //* RouteTableInfo
  2425. //
  2426. // Return information about a route.
  2427. //
  2428. // We allow Info->This to be filled in from a different RTE
  2429. // than the other fields.
  2430. //
  2431. void
  2432. RouteTableInfo(RouteTableEntry *ThisRTE, RouteTableEntry *InfoRTE,
  2433. IPV6_INFO_ROUTE_TABLE *Info)
  2434. {
  2435. if (ThisRTE == NULL) {
  2436. Info->This.Neighbor.IF.Index = 0;
  2437. } else {
  2438. Info->This.Prefix = ThisRTE->Prefix;
  2439. Info->This.PrefixLength = ThisRTE->PrefixLength;
  2440. Info->This.Neighbor.IF.Index = ThisRTE->IF->Index;
  2441. if (!IsOnLinkRTE(ThisRTE))
  2442. Info->This.Neighbor.Address = ThisRTE->NCE->NeighborAddress;
  2443. else
  2444. Info->This.Neighbor.Address = UnspecifiedAddr;
  2445. }
  2446. if (InfoRTE != NULL) {
  2447. Info->SitePrefixLength = InfoRTE->SitePrefixLength;;
  2448. Info->ValidLifetime =
  2449. ConvertTicksToSeconds(InfoRTE->ValidLifetime);
  2450. Info->PreferredLifetime =
  2451. ConvertTicksToSeconds(InfoRTE->PreferredLifetime);
  2452. Info->Preference = InfoRTE->Preference;
  2453. Info->Publish = !!(InfoRTE->Flags & RTE_FLAG_PUBLISH);
  2454. Info->Immortal = !!(InfoRTE->Flags & RTE_FLAG_IMMORTAL);
  2455. Info->Type = InfoRTE->Type;
  2456. }
  2457. }
  2458. //* IoctlQueryRouteTable
  2459. //
  2460. // Processes an IOCTL_IPV6_QUERY_ROUTE_TABLE request.
  2461. //
  2462. // Note: Return value indicates whether NT-specific processing of the
  2463. // request was successful. The status of the actual request is returned
  2464. // in the request buffers.
  2465. //
  2466. NTSTATUS
  2467. IoctlQueryRouteTable(
  2468. IN PIRP Irp, // I/O request packet.
  2469. IN PIO_STACK_LOCATION IrpSp) // Current stack location in the Irp.
  2470. {
  2471. IPV6_QUERY_ROUTE_TABLE *Query;
  2472. IPV6_INFO_ROUTE_TABLE *Info;
  2473. RouteTableEntry *RTE;
  2474. KIRQL OldIrql;
  2475. NTSTATUS Status;
  2476. Irp->IoStatus.Information = 0;
  2477. if ((IrpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof *Query) ||
  2478. (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof *Info)) {
  2479. Status = STATUS_INVALID_PARAMETER;
  2480. goto Return;
  2481. }
  2482. //
  2483. // Note that the Query and Info->This structures overlap!
  2484. //
  2485. Query = (IPV6_QUERY_ROUTE_TABLE *) Irp->AssociatedIrp.SystemBuffer;
  2486. Info = (IPV6_INFO_ROUTE_TABLE *) Irp->AssociatedIrp.SystemBuffer;
  2487. if (Query->Neighbor.IF.Index == 0) {
  2488. //
  2489. // Return the prefix and neighbor of the first RTE.
  2490. //
  2491. KeAcquireSpinLock(&RouteTableLock, &OldIrql);
  2492. RouteTableInfo(RouteTable.First, NULL, Info);
  2493. KeReleaseSpinLock(&RouteTableLock, OldIrql);
  2494. Irp->IoStatus.Information = sizeof Info->This;
  2495. } else {
  2496. //
  2497. // Find the specified RTE.
  2498. //
  2499. KeAcquireSpinLock(&RouteTableLock, &OldIrql);
  2500. for (RTE = RouteTable.First; ; RTE = RTE->Next) {
  2501. if (RTE == NULL) {
  2502. KeReleaseSpinLock(&RouteTableLock, OldIrql);
  2503. Status = STATUS_INVALID_PARAMETER_2;
  2504. goto Return;
  2505. }
  2506. if (IP6_ADDR_EQUAL(&Query->Prefix, &RTE->Prefix) &&
  2507. (Query->PrefixLength == RTE->PrefixLength) &&
  2508. (Query->Neighbor.IF.Index == RTE->IF->Index) &&
  2509. IP6_ADDR_EQUAL(&Query->Neighbor.Address,
  2510. (IsOnLinkRTE(RTE) ?
  2511. &UnspecifiedAddr :
  2512. &RTE->NCE->NeighborAddress)))
  2513. break;
  2514. }
  2515. //
  2516. // Return misc. information about the RTE.
  2517. //
  2518. RouteTableInfo(RTE->Next, RTE, Info);
  2519. KeReleaseSpinLock(&RouteTableLock, OldIrql);
  2520. Irp->IoStatus.Information = sizeof *Info;
  2521. }
  2522. Status = STATUS_SUCCESS;
  2523. Return:
  2524. Irp->IoStatus.Status = Status;
  2525. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  2526. return Status;
  2527. } // IoctlQueryRouteTable
  2528. //* OpenRouteRegKey
  2529. //
  2530. // Given an interface's registry key and route information
  2531. // opens the registry key with configuration info for the route.
  2532. //
  2533. // Callable from thread context, not DPC context.
  2534. //
  2535. NTSTATUS
  2536. OpenRouteRegKey(
  2537. HANDLE IFKey,
  2538. const IPv6Addr *Prefix,
  2539. uint PrefixLength,
  2540. const IPv6Addr *Neighbor,
  2541. OUT HANDLE *RegKey,
  2542. OpenRegKeyAction Action)
  2543. {
  2544. WCHAR RouteName[128];
  2545. HANDLE RoutesKey;
  2546. NTSTATUS Status;
  2547. PAGED_CODE();
  2548. Status = OpenRegKey(&RoutesKey, IFKey, L"Routes",
  2549. ((Action == OpenRegKeyCreate) ?
  2550. OpenRegKeyCreate : OpenRegKeyRead));
  2551. if (! NT_SUCCESS(Status))
  2552. return Status;
  2553. //
  2554. // The output of RtlIpv6AddressToString may change
  2555. // over time with improvements/changes in the pretty-printing,
  2556. // and we need a consistent mapping.
  2557. // It doesn't need to be pretty.
  2558. //
  2559. swprintf(RouteName,
  2560. L"%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x/%u->"
  2561. L"%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
  2562. net_short(Prefix->s6_words[0]), net_short(Prefix->s6_words[1]),
  2563. net_short(Prefix->s6_words[2]), net_short(Prefix->s6_words[3]),
  2564. net_short(Prefix->s6_words[4]), net_short(Prefix->s6_words[5]),
  2565. net_short(Prefix->s6_words[6]), net_short(Prefix->s6_words[7]),
  2566. PrefixLength,
  2567. net_short(Neighbor->s6_words[0]), net_short(Neighbor->s6_words[1]),
  2568. net_short(Neighbor->s6_words[2]), net_short(Neighbor->s6_words[3]),
  2569. net_short(Neighbor->s6_words[4]), net_short(Neighbor->s6_words[5]),
  2570. net_short(Neighbor->s6_words[6]), net_short(Neighbor->s6_words[7]));
  2571. Status = OpenRegKey(RegKey, RoutesKey, RouteName, Action);
  2572. ZwClose(RoutesKey);
  2573. return Status;
  2574. }
  2575. //* OpenPersistentRoute
  2576. //
  2577. // Parses a route key name into a prefix and prefix length plus
  2578. // a next-hop neighbor address and opens the route key.
  2579. //
  2580. NTSTATUS
  2581. OpenPersistentRoute(
  2582. HANDLE ParentKey,
  2583. WCHAR *SubKeyName,
  2584. IPv6Addr *Prefix,
  2585. uint *PrefixLength,
  2586. IPv6Addr *Neighbor,
  2587. HANDLE *RouteKey,
  2588. OpenRegKeyAction Action)
  2589. {
  2590. WCHAR *Terminator;
  2591. NTSTATUS Status;
  2592. PAGED_CODE();
  2593. //
  2594. // First, parse the prefix.
  2595. //
  2596. if (! ParseV6Address(SubKeyName, &Terminator, Prefix) ||
  2597. (*Terminator != L'/')) {
  2598. //
  2599. // Not a valid prefix.
  2600. //
  2601. SyntaxError:
  2602. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_USER_ERROR,
  2603. "OpenPersistentRoute: bad syntax %ls\n",
  2604. SubKeyName));
  2605. return STATUS_NO_MORE_ENTRIES;
  2606. }
  2607. //
  2608. // Next, parse the prefix length.
  2609. //
  2610. Terminator++; // Move past the L'/'.
  2611. *PrefixLength = 0;
  2612. for (;;) {
  2613. WCHAR Char = *Terminator++;
  2614. if (Char == L'-') {
  2615. Char = *Terminator++;
  2616. if (Char == L'>')
  2617. break;
  2618. else
  2619. goto SyntaxError;
  2620. }
  2621. else if ((L'0' <= Char) && (Char <= L'9')) {
  2622. *PrefixLength *= 10;
  2623. *PrefixLength += Char - L'0';
  2624. if (*PrefixLength > IPV6_ADDRESS_LENGTH)
  2625. goto SyntaxError;
  2626. }
  2627. else
  2628. goto SyntaxError;
  2629. }
  2630. //
  2631. // Finally, parse the neighbor address.
  2632. //
  2633. if (! ParseV6Address(Terminator, &Terminator, Neighbor) ||
  2634. (*Terminator != UNICODE_NULL))
  2635. goto SyntaxError;
  2636. //
  2637. // Open the route key.
  2638. //
  2639. Status = OpenRegKey(RouteKey, ParentKey, SubKeyName, Action);
  2640. if (! NT_SUCCESS(Status)) {
  2641. //
  2642. // Could not open the route key.
  2643. //
  2644. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_USER_ERROR,
  2645. "OpenPersistentRoute: bad key %ls\n",
  2646. SubKeyName));
  2647. return STATUS_NO_MORE_ENTRIES;
  2648. }
  2649. return STATUS_SUCCESS;
  2650. }
  2651. //* EnumPersistentRoute
  2652. //
  2653. // Helper function for FindPersistentRouteFromQuery,
  2654. // wrapping OpenPersistentRoute for EnumRegKeyIndex.
  2655. //
  2656. NTSTATUS
  2657. EnumPersistentRoute(
  2658. void *Context,
  2659. HANDLE ParentKey,
  2660. WCHAR *SubKeyName)
  2661. {
  2662. struct {
  2663. IPv6Addr *Prefix;
  2664. uint *PrefixLength;
  2665. IPv6Addr *Neighbor;
  2666. HANDLE *RouteKey;
  2667. OpenRegKeyAction Action;
  2668. } *Args = Context;
  2669. PAGED_CODE();
  2670. return OpenPersistentRoute(ParentKey, SubKeyName,
  2671. Args->Prefix,
  2672. Args->PrefixLength,
  2673. Args->Neighbor,
  2674. Args->RouteKey,
  2675. Args->Action);
  2676. }
  2677. //* FindPersistentRouteFromQuery
  2678. //
  2679. // Given an IPV6_PERSISTENT_QUERY_ROUTE_TABLE structure,
  2680. // finds the specified route key in the registry.
  2681. // If the route key is found, then Query->IF.Guid and
  2682. // Query->Address are returned.
  2683. //
  2684. NTSTATUS
  2685. FindPersistentRouteFromQuery(
  2686. IPV6_PERSISTENT_QUERY_ROUTE_TABLE *Query,
  2687. HANDLE *RouteKey)
  2688. {
  2689. HANDLE IFKey;
  2690. NTSTATUS Status;
  2691. PAGED_CODE();
  2692. //
  2693. // First get the interface key.
  2694. //
  2695. Status = FindPersistentInterfaceFromQuery(&Query->IF, &IFKey);
  2696. if (! NT_SUCCESS(Status))
  2697. return STATUS_INVALID_PARAMETER_1;
  2698. if (Query->RegistryIndex == (uint)-1) {
  2699. //
  2700. // Persistent query via prefix & next-hop.
  2701. //
  2702. Status = OpenRouteRegKey(IFKey,
  2703. &Query->Prefix, Query->PrefixLength,
  2704. &Query->Neighbor,
  2705. RouteKey, OpenRegKeyRead);
  2706. }
  2707. else {
  2708. HANDLE RoutesKey;
  2709. //
  2710. // Open the Routes subkey.
  2711. //
  2712. Status = OpenRegKey(&RoutesKey, IFKey,
  2713. L"Routes", OpenRegKeyRead);
  2714. if (NT_SUCCESS(Status)) {
  2715. struct {
  2716. IPv6Addr *Prefix;
  2717. uint *PrefixLength;
  2718. IPv6Addr *Neighbor;
  2719. HANDLE *RouteKey;
  2720. OpenRegKeyAction Action;
  2721. } Args;
  2722. //
  2723. // Persistent query via registry index.
  2724. //
  2725. Args.Prefix = &Query->Prefix;
  2726. Args.PrefixLength = &Query->PrefixLength;
  2727. Args.Neighbor = &Query->Neighbor;
  2728. Args.RouteKey = RouteKey;
  2729. Args.Action = OpenRegKeyRead;
  2730. Status = EnumRegKeyIndex(RoutesKey,
  2731. Query->RegistryIndex,
  2732. EnumPersistentRoute,
  2733. &Args);
  2734. ZwClose(RoutesKey);
  2735. }
  2736. else {
  2737. //
  2738. // If the Routes subkey is not present,
  2739. // then the index is not present.
  2740. //
  2741. if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
  2742. Status = STATUS_NO_MORE_ENTRIES;
  2743. }
  2744. }
  2745. ZwClose(IFKey);
  2746. return Status;
  2747. }
  2748. //* ReadPersistentRoute
  2749. //
  2750. // Reads route attributes from the registry key.
  2751. // Initializes all the fields except This.
  2752. //
  2753. void
  2754. ReadPersistentRoute(
  2755. HANDLE RouteKey,
  2756. IPV6_INFO_ROUTE_TABLE *Info)
  2757. {
  2758. //
  2759. // Read the route preference.
  2760. //
  2761. InitRegDWORDParameter(RouteKey, L"Preference",
  2762. &Info->Preference, ROUTE_PREF_HIGHEST);
  2763. //
  2764. // Read the site prefix length.
  2765. //
  2766. InitRegDWORDParameter(RouteKey, L"SitePrefixLength",
  2767. &Info->SitePrefixLength, 0);
  2768. //
  2769. // Read the Publish flag.
  2770. //
  2771. InitRegDWORDParameter(RouteKey, L"Publish",
  2772. &Info->Publish, FALSE);
  2773. //
  2774. // Read the Immortal flag.
  2775. //
  2776. InitRegDWORDParameter(RouteKey, L"Immortal",
  2777. &Info->Immortal, FALSE);
  2778. //
  2779. // Read the lifetimes.
  2780. //
  2781. GetPersistentLifetimes(RouteKey, Info->Immortal,
  2782. &Info->ValidLifetime, &Info->PreferredLifetime);
  2783. //
  2784. // The route type is not persisted.
  2785. //
  2786. Info->Type = RTE_TYPE_MANUAL;
  2787. }
  2788. //* IoctlPersistentQueryRouteTable
  2789. //
  2790. // Processes an IOCTL_IPV6_PERSISTENT_QUERY_ROUTE_TABLE request.
  2791. //
  2792. // Note: Return value indicates whether NT-specific processing of the
  2793. // request was successful. The status of the actual request is returned
  2794. // in the request buffers.
  2795. //
  2796. NTSTATUS
  2797. IoctlPersistentQueryRouteTable(
  2798. IN PIRP Irp, // I/O request packet.
  2799. IN PIO_STACK_LOCATION IrpSp) // Current stack location in the Irp.
  2800. {
  2801. IPV6_PERSISTENT_QUERY_ROUTE_TABLE *Query;
  2802. IPV6_INFO_ROUTE_TABLE *Info;
  2803. IPV6_QUERY_ROUTE_TABLE This;
  2804. HANDLE RouteKey;
  2805. NTSTATUS Status;
  2806. PAGED_CODE();
  2807. Irp->IoStatus.Information = 0;
  2808. if ((IrpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof *Query) ||
  2809. (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof *Info)) {
  2810. Status = STATUS_INVALID_PARAMETER;
  2811. goto Return;
  2812. }
  2813. //
  2814. // Note that the Query and Info->This structures overlap!
  2815. //
  2816. Query = (IPV6_PERSISTENT_QUERY_ROUTE_TABLE *)
  2817. Irp->AssociatedIrp.SystemBuffer;
  2818. Info = (IPV6_INFO_ROUTE_TABLE *)
  2819. Irp->AssociatedIrp.SystemBuffer;
  2820. //
  2821. // Get the registry key for the specified route.
  2822. //
  2823. Status = FindPersistentRouteFromQuery(Query, &RouteKey);
  2824. if (! NT_SUCCESS(Status))
  2825. goto Return;
  2826. //
  2827. // The interface index is not returned for persistent queries.
  2828. //
  2829. This.Neighbor.IF.Index = 0;
  2830. This.Neighbor.IF.Guid = Query->IF.Guid;
  2831. This.Neighbor.Address = Query->Neighbor;
  2832. This.Prefix = Query->Prefix;
  2833. This.PrefixLength = Query->PrefixLength;
  2834. Info->This = This;
  2835. //
  2836. // Read route information from the registry key.
  2837. //
  2838. ReadPersistentRoute(RouteKey, Info);
  2839. ZwClose(RouteKey);
  2840. Status = STATUS_SUCCESS;
  2841. Irp->IoStatus.Information = sizeof *Info;
  2842. Return:
  2843. Irp->IoStatus.Status = Status;
  2844. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  2845. return Status;
  2846. } // IoctlPersistentQueryRouteTable
  2847. //* InternalUpdateRouteTable
  2848. //
  2849. // Common helper function for IoctlUpdateRouteTable
  2850. // and CreatePersistentRoute, consolidating
  2851. // parameter validation in one place.
  2852. //
  2853. // The IF argument supercedes Info->This.IF.
  2854. //
  2855. // Callable from thread context, not DPC context.
  2856. //
  2857. // Return codes:
  2858. // STATUS_INVALID_PARAMETER_1 Bad Interface.
  2859. // STATUS_INVALID_PARAMETER_2 Bad Neighbor.
  2860. // STATUS_INVALID_PARAMETER_3 Bad PrefixLength.
  2861. // STATUS_INVALID_PARAMETER_4 Bad PreferredLifetime.
  2862. // STATUS_INVALID_PARAMETER_5 Bad Preference.
  2863. // STATUS_INVALID_PARAMETER_6 Bad Type.
  2864. // STATUS_INVALID_PARAMETER_7 Bad Prefix.
  2865. // STATUS_INSUFFICIENT_RESOURCES No pool.
  2866. // STATUS_ACCESS_DENIED Invalid system route update.
  2867. //
  2868. NTSTATUS
  2869. InternalUpdateRouteTable(
  2870. FILE_OBJECT *FileObject,
  2871. Interface *IF,
  2872. IPV6_INFO_ROUTE_TABLE *Info)
  2873. {
  2874. NeighborCacheEntry *NCE;
  2875. uint ValidLifetime;
  2876. uint PreferredLifetime;
  2877. NTSTATUS Status;
  2878. PAGED_CODE();
  2879. //
  2880. // Convert the lifetime from seconds to ticks.
  2881. //
  2882. ValidLifetime = ConvertSecondsToTicks(Info->ValidLifetime);
  2883. PreferredLifetime = ConvertSecondsToTicks(Info->PreferredLifetime);
  2884. //
  2885. // Sanity check the arguments.
  2886. //
  2887. if ((Info->This.PrefixLength > IPV6_ADDRESS_LENGTH) ||
  2888. (Info->SitePrefixLength > Info->This.PrefixLength))
  2889. return STATUS_INVALID_PARAMETER_3;
  2890. if (PreferredLifetime > ValidLifetime)
  2891. return STATUS_INVALID_PARAMETER_4;
  2892. if (! IsValidPreference(Info->Preference))
  2893. return STATUS_INVALID_PARAMETER_5;
  2894. if (! IsValidRouteTableType(Info->Type))
  2895. return STATUS_INVALID_PARAMETER_6;
  2896. if ((IsLinkLocal(&Info->This.Prefix) && Info->Publish) ||
  2897. (IsMulticast(&Info->This.Prefix) && Info->Publish) ||
  2898. (IsSiteLocal(&Info->This.Prefix) && (Info->SitePrefixLength != 0)))
  2899. return STATUS_INVALID_PARAMETER_7;
  2900. if (IsUnspecified(&Info->This.Neighbor.Address)) {
  2901. //
  2902. // The prefix is on-link.
  2903. //
  2904. NCE = NULL;
  2905. }
  2906. else {
  2907. //
  2908. // REVIEW - Sanity check that the specified neighbor address
  2909. // is reasonably on-link to the specified interface?
  2910. // Perhaps only allow link-local next-hop addresses,
  2911. // and other next-hops would imply recursive routing lookups?
  2912. //
  2913. if (IsInvalidSourceAddress(&Info->This.Neighbor.Address) ||
  2914. IsLoopback(&Info->This.Neighbor.Address)) {
  2915. return STATUS_INVALID_PARAMETER_2;
  2916. }
  2917. //
  2918. // Find or create the specified neighbor.
  2919. //
  2920. NCE = FindOrCreateNeighbor(IF, &Info->This.Neighbor.Address);
  2921. if (NCE == NULL)
  2922. return STATUS_INSUFFICIENT_RESOURCES;
  2923. }
  2924. //
  2925. // Create/update the specified route.
  2926. //
  2927. Status = RouteTableUpdate(FileObject,
  2928. IF, NCE,
  2929. &Info->This.Prefix,
  2930. Info->This.PrefixLength,
  2931. Info->SitePrefixLength,
  2932. ValidLifetime, PreferredLifetime,
  2933. Info->Preference,
  2934. Info->Type,
  2935. Info->Publish, Info->Immortal);
  2936. if (NCE != NULL)
  2937. ReleaseNCE(NCE);
  2938. return Status;
  2939. }
  2940. //* CreatePersistentRoute
  2941. //
  2942. // Creates a persistent route on an interface.
  2943. //
  2944. // SubKeyName has the following syntax:
  2945. // prefix/length->neighbor
  2946. // where prefix and neighbor are literal IPv6 addresses.
  2947. //
  2948. // Callable from thread context, not DPC context.
  2949. //
  2950. NTSTATUS
  2951. CreatePersistentRoute(
  2952. void *Context,
  2953. HANDLE ParentKey,
  2954. WCHAR *SubKeyName)
  2955. {
  2956. Interface *IF = (Interface *) Context;
  2957. IPV6_INFO_ROUTE_TABLE Info;
  2958. HANDLE RouteKey;
  2959. NTSTATUS Status;
  2960. PAGED_CODE();
  2961. //
  2962. // Open the route key. We might want to delete it.
  2963. //
  2964. Status = OpenPersistentRoute(ParentKey, SubKeyName,
  2965. &Info.This.Prefix,
  2966. &Info.This.PrefixLength,
  2967. &Info.This.Neighbor.Address,
  2968. &RouteKey,
  2969. OpenRegKeyDeleting);
  2970. if (! NT_SUCCESS(Status)) {
  2971. //
  2972. // Could not open the route key.
  2973. // But we return success so the enumeration continues.
  2974. //
  2975. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_USER_ERROR,
  2976. "CreatePersistentRoute(IF %u/%p %ls): bad key %ls\n",
  2977. IF->Index, IF, IF->DeviceName.Buffer, SubKeyName));
  2978. return STATUS_SUCCESS;
  2979. }
  2980. //
  2981. // Read route attributes.
  2982. //
  2983. ReadPersistentRoute(RouteKey, &Info);
  2984. //
  2985. // Create the route.
  2986. //
  2987. Status = InternalUpdateRouteTable(NULL, IF, &Info);
  2988. if (! NT_SUCCESS(Status)) {
  2989. if ((STATUS_INVALID_PARAMETER_1 <= Status) &&
  2990. (Status <= STATUS_INVALID_PARAMETER_12)) {
  2991. //
  2992. // Invalid parameter.
  2993. // But we return success so the enumeration continues.
  2994. //
  2995. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_USER_ERROR,
  2996. "CreatePersistentRoute(IF %u/%p %ls): bad param %ls\n",
  2997. IF->Index, IF, IF->DeviceName.Buffer, SubKeyName));
  2998. Status = STATUS_SUCCESS;
  2999. }
  3000. else {
  3001. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INTERNAL_ERROR,
  3002. "CreatePersistentRoute(IF %u/%p %ls): error %ls\n",
  3003. IF->Index, IF, IF->DeviceName.Buffer, SubKeyName));
  3004. }
  3005. }
  3006. else {
  3007. //
  3008. // If the route lifetime in the registry has expired,
  3009. // so that the persistent route is now stale,
  3010. // remove it from the registry.
  3011. //
  3012. if ((Info.ValidLifetime == 0) && !Info.Publish)
  3013. (void) ZwDeleteKey(RouteKey);
  3014. }
  3015. ZwClose(RouteKey);
  3016. return Status;
  3017. }
  3018. //* PersistUpdateRouteTable
  3019. //
  3020. // Helper function for persisting route information in the registry.
  3021. // The IF argument supercedes Info->This.IF.
  3022. //
  3023. // Callable from thread context, not DPC context.
  3024. //
  3025. NTSTATUS
  3026. PersistUpdateRouteTable(
  3027. Interface *IF,
  3028. IPV6_INFO_ROUTE_TABLE *Info)
  3029. {
  3030. HANDLE IFKey;
  3031. HANDLE RouteKey;
  3032. NTSTATUS Status;
  3033. PAGED_CODE();
  3034. //
  3035. // For persistent routes, we have some extra restrictions.
  3036. //
  3037. if (Info->Type != RTE_TYPE_MANUAL)
  3038. return STATUS_CANNOT_MAKE;
  3039. //
  3040. // Open/create the interface key.
  3041. //
  3042. Status = OpenInterfaceRegKey(&IF->Guid, &IFKey,
  3043. OpenRegKeyCreate);
  3044. if (! NT_SUCCESS(Status))
  3045. return Status;
  3046. //
  3047. // Open/create the route key.
  3048. //
  3049. Status = OpenRouteRegKey(IFKey,
  3050. &Info->This.Prefix,
  3051. Info->This.PrefixLength,
  3052. &Info->This.Neighbor.Address,
  3053. &RouteKey, OpenRegKeyCreate);
  3054. ZwClose(IFKey);
  3055. if (! NT_SUCCESS(Status))
  3056. return Status;
  3057. //
  3058. // Persist the route preference.
  3059. //
  3060. Status = SetRegDWORDValue(RouteKey, L"Preference",
  3061. Info->Preference);
  3062. if (! NT_SUCCESS(Status))
  3063. goto ReturnReleaseRouteKey;
  3064. //
  3065. // Persist the site prefix length.
  3066. //
  3067. Status = SetRegDWORDValue(RouteKey, L"SitePrefixLength",
  3068. Info->SitePrefixLength);
  3069. if (! NT_SUCCESS(Status))
  3070. goto ReturnReleaseRouteKey;
  3071. //
  3072. // Persist the Publish flag.
  3073. //
  3074. Status = SetRegDWORDValue(RouteKey, L"Publish", Info->Publish);
  3075. if (! NT_SUCCESS(Status))
  3076. goto ReturnReleaseRouteKey;
  3077. //
  3078. // Persist the Immortal flag.
  3079. //
  3080. Status = SetRegDWORDValue(RouteKey, L"Immortal", Info->Immortal);
  3081. if (! NT_SUCCESS(Status))
  3082. goto ReturnReleaseRouteKey;
  3083. //
  3084. // Persist the lifetimes.
  3085. //
  3086. Status = SetPersistentLifetimes(RouteKey, Info->Immortal,
  3087. Info->ValidLifetime,
  3088. Info->PreferredLifetime);
  3089. if (! NT_SUCCESS(Status))
  3090. goto ReturnReleaseRouteKey;
  3091. Status = STATUS_SUCCESS;
  3092. ReturnReleaseRouteKey:
  3093. ZwClose(RouteKey);
  3094. return Status;
  3095. }
  3096. //* PersistDeleteRouteTable
  3097. //
  3098. // Helper function for deleting route information from the registry.
  3099. // The IF argument supercedes Info->This.IF.
  3100. //
  3101. // Callable from thread context, not DPC context.
  3102. //
  3103. NTSTATUS
  3104. PersistDeleteRouteTable(
  3105. Interface *IF,
  3106. IPV6_INFO_ROUTE_TABLE *Info)
  3107. {
  3108. HANDLE IFKey;
  3109. HANDLE RouteKey;
  3110. NTSTATUS Status;
  3111. PAGED_CODE();
  3112. //
  3113. // Open the interface key. It's OK if it doesn't exist.
  3114. //
  3115. Status = OpenInterfaceRegKey(&IF->Guid, &IFKey,
  3116. OpenRegKeyRead);
  3117. if (! NT_SUCCESS(Status)) {
  3118. if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
  3119. return STATUS_SUCCESS;
  3120. else
  3121. return Status;
  3122. }
  3123. //
  3124. // Open the route key. It's OK if it doesn't exist.
  3125. //
  3126. Status = OpenRouteRegKey(IFKey,
  3127. &Info->This.Prefix,
  3128. Info->This.PrefixLength,
  3129. &Info->This.Neighbor.Address,
  3130. &RouteKey, OpenRegKeyDeleting);
  3131. ZwClose(IFKey);
  3132. if (! NT_SUCCESS(Status)) {
  3133. if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
  3134. return STATUS_SUCCESS;
  3135. else
  3136. return Status;
  3137. }
  3138. //
  3139. // Delete the route key.
  3140. //
  3141. Status = ZwDeleteKey(RouteKey);
  3142. ZwClose(RouteKey);
  3143. return Status;
  3144. }
  3145. //* IoctlUpdateRouteTable
  3146. //
  3147. // Processes an IOCTL_IPV6_UPDATE_ROUTE_TABLE request.
  3148. //
  3149. // Note: Return value indicates whether NT-specific processing of the
  3150. // request was successful. The status of the actual request is returned
  3151. // in the request buffers.
  3152. //
  3153. NTSTATUS
  3154. IoctlUpdateRouteTable(
  3155. IN PIRP Irp, // I/O request packet.
  3156. IN PIO_STACK_LOCATION IrpSp, // Current stack location in the Irp.
  3157. IN int Persistent)
  3158. {
  3159. IPV6_INFO_ROUTE_TABLE *Info;
  3160. Interface *IF = NULL;
  3161. NeighborCacheEntry *NCE;
  3162. uint ValidLifetime;
  3163. uint PreferredLifetime;
  3164. KIRQL OldIrql;
  3165. NTSTATUS Status;
  3166. PAGED_CODE();
  3167. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof *Info) {
  3168. Status = STATUS_INVALID_PARAMETER;
  3169. goto Return;
  3170. }
  3171. Info = (IPV6_INFO_ROUTE_TABLE *) Irp->AssociatedIrp.SystemBuffer;
  3172. //
  3173. // Find the specified interface.
  3174. //
  3175. IF = FindInterfaceFromQuery(&Info->This.Neighbor.IF);
  3176. if (IF == NULL) {
  3177. Status = STATUS_INVALID_PARAMETER_1;
  3178. goto Return;
  3179. }
  3180. //
  3181. // Update the routing table.
  3182. //
  3183. Status = InternalUpdateRouteTable(IrpSp->FileObject, IF, Info);
  3184. if (! NT_SUCCESS(Status))
  3185. goto ReturnReleaseIF;
  3186. //
  3187. // Make the change persistent?
  3188. // This needs to happen after updating the running data structures,
  3189. // to ensure that the change is correct before persisting it.
  3190. //
  3191. if (Persistent) {
  3192. //
  3193. // If the lifetime is zero and the route is not published,
  3194. // then the route should be deleted. Otherwise we create the key.
  3195. //
  3196. if ((Info->ValidLifetime == 0) && !Info->Publish)
  3197. Status = PersistDeleteRouteTable(IF, Info);
  3198. else
  3199. Status = PersistUpdateRouteTable(IF, Info);
  3200. if (! NT_SUCCESS(Status))
  3201. goto ReturnReleaseIF;
  3202. }
  3203. Status = STATUS_SUCCESS;
  3204. ReturnReleaseIF:
  3205. ReleaseIF(IF);
  3206. Return:
  3207. Irp->IoStatus.Status = Status;
  3208. Irp->IoStatus.Information = 0;
  3209. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  3210. return Status;
  3211. } // IoctlUpdateRouteTable
  3212. //* InternalUpdateAddress
  3213. //
  3214. // Common helper function for IoctlUpdateAddress
  3215. // and CreatePersistentAddr, consolidating
  3216. // parameter validation in one place.
  3217. //
  3218. // The IF argument supercedes Info->This.IF.
  3219. //
  3220. // Callable from thread context, not DPC context.
  3221. //
  3222. // Return codes:
  3223. // STATUS_INVALID_PARAMETER_2 Bad lifetime.
  3224. // STATUS_INVALID_PARAMETER_3 Bad address.
  3225. // STATUS_INVALID_PARAMETER_4 Bad type.
  3226. // STATUS_INVALID_PARAMETER_5 Bad prefix origin.
  3227. // STATUS_INVALID_PARAMETER_6 Bad interface id origin.
  3228. // STATUS_UNSUCCESSFUL Failure.
  3229. //
  3230. NTSTATUS
  3231. InternalUpdateAddress(
  3232. Interface *IF,
  3233. IPV6_UPDATE_ADDRESS *Info)
  3234. {
  3235. uint ValidLifetime;
  3236. uint PreferredLifetime;
  3237. struct AddrConfEntry AddrConf;
  3238. int rc;
  3239. //
  3240. // Convert the lifetime from seconds to ticks.
  3241. //
  3242. ValidLifetime = ConvertSecondsToTicks(Info->ValidLifetime);
  3243. PreferredLifetime = ConvertSecondsToTicks(Info->PreferredLifetime);
  3244. if (PreferredLifetime > ValidLifetime)
  3245. return STATUS_INVALID_PARAMETER_2;
  3246. //
  3247. // Sanity check the address.
  3248. //
  3249. if (IsNotManualAddress(&Info->This.Address))
  3250. return STATUS_INVALID_PARAMETER_3;
  3251. AddrConf.PrefixConf = (uchar)Info->PrefixConf;
  3252. AddrConf.InterfaceIdConf = (uchar)Info->InterfaceIdConf;
  3253. //
  3254. // We only support unicast and anycast addresses here.
  3255. // Use the socket apis to join a multicast address.
  3256. //
  3257. if (Info->Type == ADE_UNICAST) {
  3258. if (IsKnownAnycast(&Info->This.Address))
  3259. return STATUS_INVALID_PARAMETER_3;
  3260. if (! IsValidPrefixConfValue(Info->PrefixConf))
  3261. return STATUS_INVALID_PARAMETER_5;
  3262. if (! IsValidInterfaceIdConfValue(Info->InterfaceIdConf))
  3263. return STATUS_INVALID_PARAMETER_6;
  3264. if (AddrConf.Value == ADDR_CONF_ANONYMOUS)
  3265. return STATUS_INVALID_PARAMETER_6;
  3266. }
  3267. else if (Info->Type == ADE_ANYCAST) {
  3268. if ((ValidLifetime != PreferredLifetime) ||
  3269. ((ValidLifetime != 0) &&
  3270. (ValidLifetime != INFINITE_LIFETIME)))
  3271. return STATUS_INVALID_PARAMETER_2;
  3272. if (Info->PrefixConf != PREFIX_CONF_MANUAL)
  3273. return STATUS_INVALID_PARAMETER_5;
  3274. if (Info->InterfaceIdConf != IID_CONF_MANUAL)
  3275. return STATUS_INVALID_PARAMETER_6;
  3276. }
  3277. else {
  3278. return STATUS_INVALID_PARAMETER_4;
  3279. }
  3280. //
  3281. // Create/update/delete the address.
  3282. //
  3283. if (Info->Type == ADE_ANYCAST) {
  3284. if (Info->ValidLifetime == 0)
  3285. rc = FindAndDeleteAAE(IF, &Info->This.Address);
  3286. else
  3287. rc = FindOrCreateAAE(IF, &Info->This.Address, NULL);
  3288. }
  3289. else {
  3290. rc = FindOrCreateNTE(IF, &Info->This.Address, AddrConf.Value,
  3291. ValidLifetime, PreferredLifetime);
  3292. }
  3293. if (rc)
  3294. return STATUS_SUCCESS;
  3295. else
  3296. return STATUS_UNSUCCESSFUL;
  3297. }
  3298. //* CreatePersistentAddr
  3299. //
  3300. // Given the name of a persistent address,
  3301. // creates the address on an interface.
  3302. //
  3303. // SubKeyName is a literal IPv6 address.
  3304. //
  3305. // Callable from thread context, not DPC context.
  3306. //
  3307. NTSTATUS
  3308. CreatePersistentAddr(
  3309. void *Context,
  3310. HANDLE ParentKey,
  3311. WCHAR *SubKeyName)
  3312. {
  3313. Interface *IF = (Interface *) Context;
  3314. IPV6_UPDATE_ADDRESS Info;
  3315. int Preferred;
  3316. HANDLE AddrKey;
  3317. NTSTATUS Status;
  3318. PAGED_CODE();
  3319. //
  3320. // Open the address key. We might want to delete it.
  3321. //
  3322. Status = OpenPersistentAddress(ParentKey, SubKeyName,
  3323. &Info.This.Address,
  3324. &AddrKey,
  3325. OpenRegKeyDeleting);
  3326. if (! NT_SUCCESS(Status)) {
  3327. //
  3328. // Could not open the address key.
  3329. // But we return success so the enumeration continues.
  3330. //
  3331. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_USER_ERROR,
  3332. "CreatePersistentAddr(IF %u/%p %ls): bad key %ls\n",
  3333. IF->Index, IF, IF->DeviceName.Buffer, SubKeyName));
  3334. return STATUS_SUCCESS;
  3335. }
  3336. //
  3337. // Read address attributes.
  3338. //
  3339. ReadPersistentAddress(AddrKey, &Info);
  3340. //
  3341. // Create the address.
  3342. //
  3343. Status = InternalUpdateAddress(IF, &Info);
  3344. if (! NT_SUCCESS(Status)) {
  3345. if ((STATUS_INVALID_PARAMETER_1 <= Status) &&
  3346. (Status <= STATUS_INVALID_PARAMETER_12)) {
  3347. //
  3348. // Invalid parameter.
  3349. // But we return success so the enumeration continues.
  3350. //
  3351. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_USER_ERROR,
  3352. "CreatePersistentAddr(IF %u/%p %ls): bad param %ls\n",
  3353. IF->Index, IF, IF->DeviceName.Buffer, SubKeyName));
  3354. Status = STATUS_SUCCESS;
  3355. }
  3356. else {
  3357. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INTERNAL_ERROR,
  3358. "CreatePersistentAddr(IF %u/%p %ls): error %ls\n",
  3359. IF->Index, IF, IF->DeviceName.Buffer, SubKeyName));
  3360. }
  3361. }
  3362. else {
  3363. //
  3364. // If the address lifetime in the registry has expired,
  3365. // so that the persistent address is now stale,
  3366. // remove it from the registry.
  3367. //
  3368. if (Info.ValidLifetime == 0)
  3369. (void) ZwDeleteKey(AddrKey);
  3370. }
  3371. ZwClose(AddrKey);
  3372. return Status;
  3373. }
  3374. //* PersistUpdateAddress
  3375. //
  3376. // Helper function for persisting an address in the registry.
  3377. // The IF argument supercedes Info->This.IF.
  3378. //
  3379. // Callable from thread context, not DPC context.
  3380. //
  3381. NTSTATUS
  3382. PersistUpdateAddress(
  3383. Interface *IF,
  3384. IPV6_UPDATE_ADDRESS *Info)
  3385. {
  3386. HANDLE IFKey;
  3387. HANDLE AddrKey;
  3388. NTSTATUS Status;
  3389. PAGED_CODE();
  3390. //
  3391. // For persistent addresses, we have extra restrictions.
  3392. //
  3393. if ((Info->PrefixConf != PREFIX_CONF_MANUAL) ||
  3394. (Info->InterfaceIdConf != IID_CONF_MANUAL))
  3395. return STATUS_CANNOT_MAKE;
  3396. //
  3397. // Open/create the interface key.
  3398. //
  3399. Status = OpenInterfaceRegKey(&IF->Guid, &IFKey,
  3400. OpenRegKeyCreate);
  3401. if (! NT_SUCCESS(Status))
  3402. return Status;
  3403. //
  3404. // Open/create the address key.
  3405. //
  3406. Status = OpenAddressRegKey(IFKey, &Info->This.Address,
  3407. &AddrKey, OpenRegKeyCreate);
  3408. ZwClose(IFKey);
  3409. if (! NT_SUCCESS(Status))
  3410. return Status;
  3411. //
  3412. // Persist the address type.
  3413. //
  3414. Status = SetRegDWORDValue(AddrKey, L"Type", Info->Type);
  3415. if (! NT_SUCCESS(Status))
  3416. goto ReturnReleaseAddrKey;
  3417. //
  3418. // Persist the address lifetimes.
  3419. //
  3420. Status = SetPersistentLifetimes(AddrKey, FALSE,
  3421. Info->ValidLifetime,
  3422. Info->PreferredLifetime);
  3423. if (! NT_SUCCESS(Status))
  3424. goto ReturnReleaseAddrKey;
  3425. Status = STATUS_SUCCESS;
  3426. ReturnReleaseAddrKey:
  3427. ZwClose(AddrKey);
  3428. return Status;
  3429. }
  3430. //* PersistDeleteAddress
  3431. //
  3432. // Helper function for deleting an address from the registry.
  3433. // The IF argument supercedes Info->This.IF.
  3434. //
  3435. // Callable from thread context, not DPC context.
  3436. //
  3437. NTSTATUS
  3438. PersistDeleteAddress(
  3439. Interface *IF,
  3440. IPV6_UPDATE_ADDRESS *Info)
  3441. {
  3442. HANDLE IFKey;
  3443. HANDLE AddrKey;
  3444. NTSTATUS Status;
  3445. PAGED_CODE();
  3446. //
  3447. // Open the interface key. It's OK if it doesn't exist.
  3448. //
  3449. Status = OpenInterfaceRegKey(&IF->Guid, &IFKey,
  3450. OpenRegKeyRead);
  3451. if (! NT_SUCCESS(Status)) {
  3452. if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
  3453. return STATUS_SUCCESS;
  3454. else
  3455. return Status;
  3456. }
  3457. //
  3458. // Open the address key. It's OK if it doesn't exist.
  3459. //
  3460. Status = OpenAddressRegKey(IFKey, &Info->This.Address,
  3461. &AddrKey, OpenRegKeyDeleting);
  3462. ZwClose(IFKey);
  3463. if (! NT_SUCCESS(Status)) {
  3464. if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
  3465. return STATUS_SUCCESS;
  3466. else
  3467. return Status;
  3468. }
  3469. //
  3470. // Delete the address key.
  3471. //
  3472. Status = ZwDeleteKey(AddrKey);
  3473. ZwClose(AddrKey);
  3474. return Status;
  3475. }
  3476. //* IoctlUpdateAddress
  3477. //
  3478. // Processes an IOCTL_IPV6_UPDATE_ADDRESS request.
  3479. //
  3480. // Note: Return value indicates whether NT-specific processing of the
  3481. // request was successful. The status of the actual request is returned
  3482. // in the request buffers.
  3483. //
  3484. NTSTATUS
  3485. IoctlUpdateAddress(
  3486. IN PIRP Irp, // I/O request packet.
  3487. IN PIO_STACK_LOCATION IrpSp, // Current stack location in the Irp.
  3488. IN int Persistent)
  3489. {
  3490. IPV6_UPDATE_ADDRESS *Info;
  3491. Interface *IF;
  3492. NTSTATUS Status;
  3493. PAGED_CODE();
  3494. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof *Info) {
  3495. Status = STATUS_INVALID_PARAMETER;
  3496. goto Return;
  3497. }
  3498. Info = (IPV6_UPDATE_ADDRESS *) Irp->AssociatedIrp.SystemBuffer;
  3499. //
  3500. // Find the specified interface.
  3501. //
  3502. IF = FindInterfaceFromQuery(&Info->This.IF);
  3503. if (IF == NULL) {
  3504. Status = STATUS_INVALID_PARAMETER_1;
  3505. goto Return;
  3506. }
  3507. //
  3508. // Update the address on the interface.
  3509. //
  3510. Status = InternalUpdateAddress(IF, Info);
  3511. if (! NT_SUCCESS(Status))
  3512. goto ReturnReleaseIF;
  3513. //
  3514. // Make the change persistent?
  3515. // This needs to happen after updating the running data structures,
  3516. // to ensure that the change is correct before persisting it.
  3517. //
  3518. if (Persistent) {
  3519. //
  3520. // If the lifetime is zero, we delete the address's key.
  3521. // Otherwise the lifetime is infinite and we create the key.
  3522. //
  3523. if (Info->ValidLifetime == 0)
  3524. Status = PersistDeleteAddress(IF, Info);
  3525. else
  3526. Status = PersistUpdateAddress(IF, Info);
  3527. if (! NT_SUCCESS(Status))
  3528. goto ReturnReleaseIF;
  3529. }
  3530. Status = STATUS_SUCCESS;
  3531. ReturnReleaseIF:
  3532. ReleaseIF(IF);
  3533. Return:
  3534. Irp->IoStatus.Status = Status;
  3535. Irp->IoStatus.Information = 0;
  3536. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  3537. return Status;
  3538. } // IoctlUpdateAddress
  3539. //* IoctlQueryBindingCache
  3540. //
  3541. // Processes an IOCTL_IPV6_QUERY_BINDING_CACHE request.
  3542. //
  3543. // Note: Return value indicates whether NT-specific processing of the
  3544. // request was successful. The status of the actual request is returned
  3545. // in the request buffers.
  3546. //
  3547. NTSTATUS
  3548. IoctlQueryBindingCache(
  3549. IN PIRP Irp, // I/O request packet.
  3550. IN PIO_STACK_LOCATION IrpSp) // Current stack location in the Irp.
  3551. {
  3552. IPV6_QUERY_BINDING_CACHE *Query;
  3553. IPV6_INFO_BINDING_CACHE *Info;
  3554. BindingCacheEntry *BCE;
  3555. KIRQL OldIrql;
  3556. NTSTATUS Status;
  3557. PAGED_CODE();
  3558. Irp->IoStatus.Information = 0;
  3559. if ((IrpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof *Query) ||
  3560. (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof *Info)) {
  3561. Status = STATUS_INVALID_PARAMETER;
  3562. goto Return;
  3563. }
  3564. //
  3565. // Note that the Query and Info->Query structures overlap!
  3566. //
  3567. Query = (IPV6_QUERY_BINDING_CACHE *) Irp->AssociatedIrp.SystemBuffer;
  3568. Info = (IPV6_INFO_BINDING_CACHE *) Irp->AssociatedIrp.SystemBuffer;
  3569. if (IsUnspecified(&Query->HomeAddress)) {
  3570. //
  3571. // Return the home address of the first BCE.
  3572. //
  3573. KeAcquireSpinLock(&RouteCacheLock, &OldIrql);
  3574. if (BindingCache.First != SentinelBCE) {
  3575. Info->Query.HomeAddress = BindingCache.First->HomeAddr;
  3576. }
  3577. KeReleaseSpinLock(&RouteCacheLock, OldIrql);
  3578. Irp->IoStatus.Information = sizeof Info->Query;
  3579. } else {
  3580. //
  3581. // Find the specified BCE.
  3582. //
  3583. KeAcquireSpinLock(&RouteCacheLock, &OldIrql);
  3584. for (BCE = BindingCache.First; ; BCE = BCE->Next) {
  3585. if (BCE == SentinelBCE) {
  3586. KeReleaseSpinLock(&RouteCacheLock, OldIrql);
  3587. Status = STATUS_INVALID_PARAMETER_2;
  3588. goto Return;
  3589. }
  3590. if (IP6_ADDR_EQUAL(&Query->HomeAddress, &BCE->HomeAddr))
  3591. break;
  3592. }
  3593. //
  3594. // Return misc. information about the BCE.
  3595. //
  3596. Info->HomeAddress = BCE->HomeAddr;
  3597. Info->CareOfAddress = BCE->CareOfRCE->Destination;
  3598. Info->BindingSeqNumber = BCE->BindingSeqNumber;
  3599. Info->BindingLifetime = ConvertTicksToSeconds(BCE->BindingLifetime);
  3600. //
  3601. // Return home address of the next BCE (or Unspecified).
  3602. //
  3603. if (BCE->Next == SentinelBCE) {
  3604. Info->Query.HomeAddress = UnspecifiedAddr;
  3605. } else {
  3606. Info->Query.HomeAddress = BCE->Next->HomeAddr;
  3607. }
  3608. KeReleaseSpinLock(&RouteCacheLock, OldIrql);
  3609. Irp->IoStatus.Information = sizeof *Info;
  3610. }
  3611. Status = STATUS_SUCCESS;
  3612. Return:
  3613. Irp->IoStatus.Status = Status;
  3614. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  3615. return Status;
  3616. } // IoctlQueryBindingCache
  3617. //* InternalCreateInterface
  3618. //
  3619. // Common helper function for IoctlCreateInterface
  3620. // and CreatePersistentInterface, consolidating
  3621. // parameter validation in one place.
  3622. //
  3623. // Callable from thread context, not DPC context.
  3624. //
  3625. // Return codes:
  3626. // STATUS_INVALID_PARAMETER_1 Bad Type.
  3627. // STATUS_INVALID_PARAMETER_2 Bad Flags.
  3628. // STATUS_INVALID_PARAMETER_3 Bad SrcAddr.
  3629. // STATUS_INVALID_PARAMETER_4 Bad DstAddr.
  3630. // STATUS_ADDRESS_ALREADY_EXISTS The interface already exists.
  3631. // STATUS_INSUFFICIENT_RESOURCES
  3632. // STATUS_UNSUCCESSFUL
  3633. // STATUS_SUCCESS
  3634. //
  3635. NTSTATUS
  3636. InternalCreateInterface(
  3637. IPV6_INFO_INTERFACE *Info,
  3638. Interface **ReturnIF)
  3639. {
  3640. IPAddr SrcAddr, DstAddr;
  3641. int RouterDiscovers = Info->RouterDiscovers;
  3642. int NeighborDiscovers = Info->NeighborDiscovers;
  3643. int PeriodicMLD = Info->PeriodicMLD;
  3644. uint Flags;
  3645. if (Info->LinkLayerAddressLength != sizeof(IPAddr))
  3646. return STATUS_INVALID_PARAMETER_1;
  3647. switch (Info->Type) {
  3648. case IF_TYPE_TUNNEL_V6V4:
  3649. //
  3650. // Set default values.
  3651. //
  3652. if (RouterDiscovers == -1)
  3653. RouterDiscovers = FALSE;
  3654. if (NeighborDiscovers == -1)
  3655. NeighborDiscovers = FALSE;
  3656. if (PeriodicMLD == -1)
  3657. PeriodicMLD = FALSE;
  3658. //
  3659. // For now, require the ND and RD flags to be set the same.
  3660. // Setting them differently should work, but it's not an important
  3661. // scenario at the moment, and it would be more work to test.
  3662. // This check can be removed in the future if desired.
  3663. //
  3664. if (NeighborDiscovers != RouterDiscovers)
  3665. return STATUS_INVALID_PARAMETER_2;
  3666. if (Info->LocalLinkLayerAddress == 0)
  3667. return STATUS_INVALID_PARAMETER_3;
  3668. if (Info->RemoteLinkLayerAddress == 0)
  3669. return STATUS_INVALID_PARAMETER_4;
  3670. SrcAddr = * (IPAddr UNALIGNED *)
  3671. ((char *)Info + Info->LocalLinkLayerAddress);
  3672. DstAddr = * (IPAddr UNALIGNED *)
  3673. ((char *)Info + Info->RemoteLinkLayerAddress);
  3674. break;
  3675. case IF_TYPE_TUNNEL_6OVER4:
  3676. //
  3677. // Set default values.
  3678. //
  3679. if (RouterDiscovers == -1)
  3680. RouterDiscovers = TRUE;
  3681. if (NeighborDiscovers == -1)
  3682. NeighborDiscovers = TRUE;
  3683. if (PeriodicMLD == -1)
  3684. PeriodicMLD = FALSE;
  3685. //
  3686. // For now, require the RD flag to be set in addition to ND.
  3687. // PeriodicMLD is not allowed.
  3688. //
  3689. if (!RouterDiscovers || !NeighborDiscovers || PeriodicMLD)
  3690. return STATUS_INVALID_PARAMETER_2;
  3691. if (Info->LocalLinkLayerAddress == 0)
  3692. return STATUS_INVALID_PARAMETER_3;
  3693. if (Info->RemoteLinkLayerAddress != 0)
  3694. return STATUS_INVALID_PARAMETER_4;
  3695. SrcAddr = * (IPAddr UNALIGNED *)
  3696. ((char *)Info + Info->LocalLinkLayerAddress);
  3697. DstAddr = 0;
  3698. break;
  3699. default:
  3700. return STATUS_INVALID_PARAMETER_1;
  3701. }
  3702. Flags = ((RouterDiscovers ? IF_FLAG_ROUTER_DISCOVERS : 0) |
  3703. (NeighborDiscovers ? IF_FLAG_NEIGHBOR_DISCOVERS : 0) |
  3704. (PeriodicMLD ? IF_FLAG_PERIODICMLD : 0));
  3705. return TunnelCreateTunnel(SrcAddr, DstAddr, Flags, ReturnIF);
  3706. }
  3707. //* CreatePersistentInterface
  3708. //
  3709. // Creates a persistent interface.
  3710. //
  3711. // Callable from thread context, not DPC context.
  3712. //
  3713. NTSTATUS
  3714. CreatePersistentInterface(
  3715. void *Context,
  3716. HANDLE ParentKey,
  3717. WCHAR *SubKeyName)
  3718. {
  3719. struct {
  3720. IPV6_INFO_INTERFACE Info;
  3721. IPAddr SrcAddr;
  3722. IPAddr DstAddr;
  3723. } Create;
  3724. HANDLE IFKey;
  3725. Interface *IF;
  3726. WCHAR *InterfaceName;
  3727. NTSTATUS Status;
  3728. UNREFERENCED_PARAMETER(Context);
  3729. PAGED_CODE();
  3730. //
  3731. // Open the interface key.
  3732. //
  3733. Status = OpenPersistentInterface(ParentKey, SubKeyName,
  3734. &Create.Info.This.Guid,
  3735. &IFKey, OpenRegKeyRead);
  3736. if (! NT_SUCCESS(Status)) {
  3737. //
  3738. // Could not open the interface key.
  3739. // But we return success so the enumeration continues.
  3740. //
  3741. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_USER_ERROR,
  3742. "CreatePersistentInterface: bad key %ls\n",
  3743. SubKeyName));
  3744. return STATUS_SUCCESS;
  3745. }
  3746. //
  3747. // Let ReadPersistentInterface know how much space is available
  3748. // for link-layer addresses.
  3749. //
  3750. Create.Info.Length = sizeof Create - sizeof Create.Info;
  3751. //
  3752. // Read interface attributes.
  3753. //
  3754. Status = ReadPersistentInterface(IFKey, &Create.Info);
  3755. ZwClose(IFKey);
  3756. if (! NT_SUCCESS(Status)) {
  3757. //
  3758. // Could not read the interface key.
  3759. // But we return success so the enumeration continues.
  3760. //
  3761. goto InvalidParameter;
  3762. }
  3763. //
  3764. // Should we create an interface?
  3765. //
  3766. if (Create.Info.Type == (uint)-1)
  3767. return STATUS_SUCCESS;
  3768. //
  3769. // Create the persistent interface.
  3770. //
  3771. Status = InternalCreateInterface(&Create.Info, &IF);
  3772. if (! NT_SUCCESS(Status)) {
  3773. if (((STATUS_INVALID_PARAMETER_1 <= Status) &&
  3774. (Status <= STATUS_INVALID_PARAMETER_12)) ||
  3775. (Status == STATUS_ADDRESS_ALREADY_EXISTS)) {
  3776. //
  3777. // Invalid parameter.
  3778. // But we return success so the enumeration continues.
  3779. //
  3780. InvalidParameter:
  3781. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_USER_ERROR,
  3782. "CreatePersistentInterface: bad param %ls\n",
  3783. SubKeyName));
  3784. return STATUS_SUCCESS;
  3785. }
  3786. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INTERNAL_ERROR,
  3787. "CreatePersistentInterface: error %ls\n",
  3788. SubKeyName));
  3789. return Status;
  3790. }
  3791. //
  3792. // Consistency check. This is not an assertion because
  3793. // someone editing the registry can make this fail.
  3794. //
  3795. InterfaceName = (WCHAR *)IF->DeviceName.Buffer +
  3796. (sizeof IPV6_EXPORT_STRING_PREFIX / sizeof(WCHAR)) - 1;
  3797. if (wcscmp(SubKeyName, InterfaceName) != 0) {
  3798. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_USER_ERROR,
  3799. "CreatePersistentInterface: inconsistency %ls IF %u/%p\n",
  3800. SubKeyName, IF->Index, IF));
  3801. }
  3802. ReleaseIF(IF);
  3803. return STATUS_SUCCESS;
  3804. }
  3805. //* ConfigurePersistentInterfaces
  3806. //
  3807. // Configures persistent interfaces from the registry.
  3808. //
  3809. // Callable from thread context, not DPC context.
  3810. //
  3811. void
  3812. ConfigurePersistentInterfaces(void)
  3813. {
  3814. HANDLE RegKey;
  3815. NTSTATUS Status;
  3816. //
  3817. // Create persistent interfaces.
  3818. //
  3819. Status = OpenTopLevelRegKey(L"Interfaces", &RegKey, OpenRegKeyRead);
  3820. if (NT_SUCCESS(Status)) {
  3821. (void) EnumRegKeys(RegKey, CreatePersistentInterface, NULL);
  3822. ZwClose(RegKey);
  3823. }
  3824. }
  3825. //* PersistCreateInterface
  3826. //
  3827. // Helper function for persisting an interface in the registry.
  3828. // The IF argument supercedes Info->This.IF.
  3829. //
  3830. // Callable from thread context, not DPC context.
  3831. //
  3832. NTSTATUS
  3833. PersistCreateInterface(
  3834. Interface *IF,
  3835. IPV6_INFO_INTERFACE *Info)
  3836. {
  3837. HANDLE IFKey;
  3838. NTSTATUS Status;
  3839. PAGED_CODE();
  3840. //
  3841. // Open/create the interface key.
  3842. //
  3843. Status = OpenInterfaceRegKey(&IF->Guid, &IFKey,
  3844. OpenRegKeyCreate);
  3845. if (! NT_SUCCESS(Status))
  3846. return Status;
  3847. //
  3848. // Persist the interface type.
  3849. //
  3850. Status = SetRegDWORDValue(IFKey, L"Type", Info->Type);
  3851. if (! NT_SUCCESS(Status))
  3852. goto ReturnReleaseKey;
  3853. //
  3854. // Persist the interface flags.
  3855. //
  3856. if (Info->RouterDiscovers != -1) {
  3857. Status = SetRegDWORDValue(IFKey, L"RouterDiscovers",
  3858. Info->RouterDiscovers);
  3859. if (! NT_SUCCESS(Status))
  3860. goto ReturnReleaseKey;
  3861. }
  3862. if (Info->NeighborDiscovers != -1) {
  3863. Status = SetRegDWORDValue(IFKey, L"NeighborDiscovers",
  3864. Info->NeighborDiscovers);
  3865. if (! NT_SUCCESS(Status))
  3866. goto ReturnReleaseKey;
  3867. }
  3868. if (Info->PeriodicMLD != -1) {
  3869. Status = SetRegDWORDValue(IFKey, L"PeriodicMLD",
  3870. Info->PeriodicMLD);
  3871. if (! NT_SUCCESS(Status))
  3872. goto ReturnReleaseKey;
  3873. }
  3874. switch (Info->Type) {
  3875. case IF_TYPE_TUNNEL_6OVER4: {
  3876. IPAddr SrcAddr = * (IPAddr UNALIGNED *)
  3877. ((char *)Info + Info->LocalLinkLayerAddress);
  3878. //
  3879. // Persist the source address.
  3880. //
  3881. Status = SetRegIPAddrValue(IFKey, L"SrcAddr", SrcAddr);
  3882. if (! NT_SUCCESS(Status))
  3883. goto ReturnReleaseKey;
  3884. break;
  3885. }
  3886. case IF_TYPE_TUNNEL_V6V4: {
  3887. IPAddr SrcAddr = * (IPAddr UNALIGNED *)
  3888. ((char *)Info + Info->LocalLinkLayerAddress);
  3889. IPAddr DstAddr = * (IPAddr UNALIGNED *)
  3890. ((char *)Info + Info->RemoteLinkLayerAddress);
  3891. //
  3892. // Persist the source address.
  3893. //
  3894. Status = SetRegIPAddrValue(IFKey, L"SrcAddr", SrcAddr);
  3895. if (! NT_SUCCESS(Status))
  3896. goto ReturnReleaseKey;
  3897. //
  3898. // Persist the destination address.
  3899. //
  3900. Status = SetRegIPAddrValue(IFKey, L"DstAddr", DstAddr);
  3901. if (! NT_SUCCESS(Status))
  3902. goto ReturnReleaseKey;
  3903. break;
  3904. }
  3905. }
  3906. Status = STATUS_SUCCESS;
  3907. ReturnReleaseKey:
  3908. ZwClose(IFKey);
  3909. return Status;
  3910. }
  3911. //* IoctlCreateInterface
  3912. //
  3913. // Processes an IOCTL_IPV6_CREATE_INTERFACE request.
  3914. //
  3915. // Note: Return value indicates whether NT-specific processing of the
  3916. // request was successful. The status of the actual request is returned
  3917. // in the request buffers.
  3918. //
  3919. NTSTATUS
  3920. IoctlCreateInterface(
  3921. IN PIRP Irp, // I/O request packet.
  3922. IN PIO_STACK_LOCATION IrpSp, // Current stack location in the Irp.
  3923. IN int Persistent)
  3924. {
  3925. IPV6_INFO_INTERFACE *Info;
  3926. IPV6_QUERY_INTERFACE *Result;
  3927. Interface *IF;
  3928. NTSTATUS Status;
  3929. PAGED_CODE();
  3930. //
  3931. // Initialize now for error paths.
  3932. //
  3933. Irp->IoStatus.Information = 0;
  3934. if ((IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof *Info) ||
  3935. (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof *Result)) {
  3936. Status = STATUS_INVALID_PARAMETER;
  3937. goto Return;
  3938. }
  3939. Info = (IPV6_INFO_INTERFACE *) Irp->AssociatedIrp.SystemBuffer;
  3940. Result = (IPV6_QUERY_INTERFACE *) Irp->AssociatedIrp.SystemBuffer;
  3941. //
  3942. // Check that the structure and link-layer addresses, if supplied,
  3943. // fit in the buffer. Watch out for addition overflow.
  3944. //
  3945. if ((Info->Length < sizeof *Info) ||
  3946. (Info->Length > IrpSp->Parameters.DeviceIoControl.InputBufferLength) ||
  3947. ((Info->LocalLinkLayerAddress != 0) &&
  3948. (((Info->LocalLinkLayerAddress + Info->LinkLayerAddressLength) >
  3949. IrpSp->Parameters.DeviceIoControl.InputBufferLength) ||
  3950. ((Info->LocalLinkLayerAddress + Info->LinkLayerAddressLength) <
  3951. Info->LocalLinkLayerAddress))) ||
  3952. ((Info->RemoteLinkLayerAddress != 0) &&
  3953. (((Info->RemoteLinkLayerAddress + Info->LinkLayerAddressLength) >
  3954. IrpSp->Parameters.DeviceIoControl.InputBufferLength) ||
  3955. ((Info->RemoteLinkLayerAddress + Info->LinkLayerAddressLength) <
  3956. Info->RemoteLinkLayerAddress)))) {
  3957. Status = STATUS_INVALID_PARAMETER;
  3958. goto Return;
  3959. }
  3960. //
  3961. // Create the interface.
  3962. //
  3963. Status = InternalCreateInterface(Info, &IF);
  3964. if (! NT_SUCCESS(Status))
  3965. goto Return;
  3966. //
  3967. // Make the change persistent?
  3968. // This needs to happen after updating the running data structures,
  3969. // to ensure that the change is correct before persisting it.
  3970. //
  3971. if (Persistent) {
  3972. Status = PersistCreateInterface(IF, Info);
  3973. if (! NT_SUCCESS(Status))
  3974. goto ReturnReleaseIF;
  3975. }
  3976. //
  3977. // Return query information for the new interface.
  3978. //
  3979. ReturnQueryInterface(IF, Result);
  3980. Irp->IoStatus.Information = sizeof *Result;
  3981. Status = STATUS_SUCCESS;
  3982. ReturnReleaseIF:
  3983. ReleaseIF(IF);
  3984. Return:
  3985. Irp->IoStatus.Status = Status;
  3986. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  3987. return Status;
  3988. } // IoctlCreateInterface
  3989. //* AreIndicesSpecified
  3990. //
  3991. // Are there any non-zero zone indices in the array?
  3992. //
  3993. int
  3994. AreIndicesSpecified(uint ZoneIndices[ADE_NUM_SCOPES])
  3995. {
  3996. ushort Scope;
  3997. for (Scope = ADE_SMALLEST_SCOPE; Scope <= ADE_LARGEST_SCOPE; Scope++)
  3998. if (ZoneIndices[Scope] != 0)
  3999. return TRUE;
  4000. return FALSE;
  4001. }
  4002. //* CheckZoneIndices
  4003. //
  4004. // Checks consistency of a zone update,
  4005. // and fills in unspecified values.
  4006. // Returns FALSE if there is an inconsistency.
  4007. //
  4008. // The logic for filling in unspecified values makes it
  4009. // more convenient for a user to change zone indices.
  4010. // For example, an user can change an interface's site index
  4011. // and the subnet & admin indices will be automatically changed.
  4012. //
  4013. // Called with the global ZoneUpdateLock held.
  4014. //
  4015. int
  4016. CheckZoneIndices(Interface *IF, uint ZoneIndices[ADE_NUM_SCOPES])
  4017. {
  4018. Interface *OtherIF;
  4019. uint Scope, i;
  4020. //
  4021. // Zone indices 0 (ADE_SMALLEST_SCOPE) and 1 (ADE_INTERFACE_LOCAL)
  4022. // are special and must have the value IF->Index.
  4023. //
  4024. if (ZoneIndices[ADE_SMALLEST_SCOPE] == 0)
  4025. ZoneIndices[ADE_SMALLEST_SCOPE] = IF->Index;
  4026. else if (ZoneIndices[ADE_SMALLEST_SCOPE] != IF->Index)
  4027. return FALSE;
  4028. if (ZoneIndices[ADE_INTERFACE_LOCAL] == 0)
  4029. ZoneIndices[ADE_INTERFACE_LOCAL] = IF->Index;
  4030. else if (ZoneIndices[ADE_INTERFACE_LOCAL] != IF->Index)
  4031. return FALSE;
  4032. //
  4033. // Zone indices 14 (ADE_GLOBAL) and 15 (ADE_LARGEST_SCOPE) are special
  4034. // and must have the value one.
  4035. //
  4036. if (ZoneIndices[ADE_GLOBAL] == 0)
  4037. ZoneIndices[ADE_GLOBAL] = 1;
  4038. else if (ZoneIndices[ADE_GLOBAL] != 1)
  4039. return FALSE;
  4040. if (ZoneIndices[ADE_LARGEST_SCOPE] == 0)
  4041. ZoneIndices[ADE_LARGEST_SCOPE] = 1;
  4042. else if (ZoneIndices[ADE_LARGEST_SCOPE] != 1)
  4043. return FALSE;
  4044. for (Scope = ADE_LINK_LOCAL; Scope < ADE_GLOBAL; Scope++) {
  4045. if (ZoneIndices[Scope] == 0) {
  4046. //
  4047. // The user did not specify the zone index for this scope.
  4048. // If leaving the current zone index unchanged works,
  4049. // then we prefer to do that. However, the user may be changing
  4050. // the zone index for a larger scope. If necessary
  4051. // for consistency, then we use a new zone index at this scope.
  4052. //
  4053. for (i = Scope+1; i < ADE_GLOBAL; i++) {
  4054. if (ZoneIndices[i] != 0) {
  4055. //
  4056. // If we use the current value at level Scope,
  4057. // would it cause an inconsistency at level i?
  4058. //
  4059. OtherIF = FindInterfaceFromZone(IF,
  4060. Scope, IF->ZoneIndices[Scope]);
  4061. if (OtherIF != NULL) {
  4062. if (OtherIF->ZoneIndices[i] != ZoneIndices[i]) {
  4063. Interface *ExistingIF;
  4064. //
  4065. // Yes. We need a different zone index.
  4066. // Is there an existing one that we can reuse?
  4067. //
  4068. ExistingIF = FindInterfaceFromZone(IF,
  4069. i, ZoneIndices[i]);
  4070. if (ExistingIF != NULL) {
  4071. //
  4072. // Yes, reuse the existing zone index.
  4073. //
  4074. ZoneIndices[Scope] = ExistingIF->ZoneIndices[Scope];
  4075. ReleaseIF(ExistingIF);
  4076. }
  4077. else {
  4078. //
  4079. // No, we need a new zone index.
  4080. //
  4081. ZoneIndices[Scope] = FindNewZoneIndex(Scope);
  4082. }
  4083. }
  4084. ReleaseIF(OtherIF);
  4085. }
  4086. break;
  4087. }
  4088. }
  4089. if (ZoneIndices[Scope] == 0) {
  4090. //
  4091. // Use the current value from the interface.
  4092. //
  4093. ZoneIndices[Scope] = IF->ZoneIndices[Scope];
  4094. }
  4095. }
  4096. OtherIF = FindInterfaceFromZone(IF, Scope, ZoneIndices[Scope]);
  4097. if (OtherIF != NULL) {
  4098. //
  4099. // Enforce the zone containment invariant.
  4100. //
  4101. while (++Scope < ADE_GLOBAL) {
  4102. if (ZoneIndices[Scope] == 0)
  4103. ZoneIndices[Scope] = OtherIF->ZoneIndices[Scope];
  4104. else if (ZoneIndices[Scope] != OtherIF->ZoneIndices[Scope]) {
  4105. ReleaseIF(OtherIF);
  4106. return FALSE;
  4107. }
  4108. }
  4109. ReleaseIF(OtherIF);
  4110. return TRUE;
  4111. }
  4112. }
  4113. return TRUE;
  4114. }
  4115. //* InternalUpdateInterface
  4116. //
  4117. // Common helper function for IoctlUpdateInterface
  4118. // and ConfigureInterface, consolidating
  4119. // parameter validation in one place.
  4120. //
  4121. // The IF argument supercedes Info->This.IF.
  4122. // Does not implement Info->Renew.
  4123. //
  4124. // Callable from thread context, not DPC context.
  4125. //
  4126. // Return codes:
  4127. // STATUS_INVALID_PARAMETER_1 Bad Interface.
  4128. // STATUS_INVALID_PARAMETER_2 Bad Preference.
  4129. // STATUS_INVALID_PARAMETER_3 Bad LinkMTU.
  4130. // STATUS_INVALID_PARAMETER_4 Bad BaseReachableTime.
  4131. // STATUS_INVALID_PARAMETER_5 Bad CurHopLimit.
  4132. // STATUS_INSUFFICIENT_RESOURCES
  4133. // STATUS_SUCCESS
  4134. //
  4135. NTSTATUS
  4136. InternalUpdateInterface(
  4137. Interface *IF,
  4138. IPV6_INFO_INTERFACE *Info)
  4139. {
  4140. KIRQL OldIrql;
  4141. NTSTATUS Status;
  4142. if ((Info->Preference != (uint)-1) &&
  4143. ! IsValidPreference(Info->Preference))
  4144. return STATUS_INVALID_PARAMETER_2;
  4145. if ((Info->LinkMTU != 0) &&
  4146. ! ((IPv6_MINIMUM_MTU <= Info->LinkMTU) &&
  4147. (Info->LinkMTU <= IF->TrueLinkMTU)))
  4148. return STATUS_INVALID_PARAMETER_3;
  4149. if ((Info->BaseReachableTime != 0) &&
  4150. (Info->BaseReachableTime > MAX_REACHABLE_TIME))
  4151. return STATUS_INVALID_PARAMETER_4;
  4152. if ((Info->CurHopLimit != (uint)-1) &&
  4153. (Info->CurHopLimit >= 256))
  4154. return STATUS_INVALID_PARAMETER_5;
  4155. if (AreIndicesSpecified(Info->ZoneIndices)) {
  4156. //
  4157. // Fill in unspecified values in the ZoneIndices array
  4158. // and check for illegal values.
  4159. // The global lock ensures consistency across interfaces.
  4160. //
  4161. KeAcquireSpinLock(&ZoneUpdateLock, &OldIrql);
  4162. if (! CheckZoneIndices(IF, Info->ZoneIndices)) {
  4163. KeReleaseSpinLock(&ZoneUpdateLock, OldIrql);
  4164. return STATUS_INVALID_PARAMETER_3;
  4165. }
  4166. //
  4167. // Update the ZoneIndices.
  4168. //
  4169. RtlCopyMemory(IF->ZoneIndices, Info->ZoneIndices,
  4170. sizeof IF->ZoneIndices);
  4171. InvalidateRouteCache();
  4172. KeReleaseSpinLock(&ZoneUpdateLock, OldIrql);
  4173. }
  4174. //
  4175. // Update the forwarding and advertising attributes.
  4176. // We must update the advertising attribute before
  4177. // any auto-configured attributes, because
  4178. // InterfaceResetAutoConfig will reset them.
  4179. //
  4180. Status = UpdateInterface(IF, Info->Advertises, Info->Forwards);
  4181. if (! NT_SUCCESS(Status))
  4182. return Status;
  4183. //
  4184. // Update the link MTU.
  4185. //
  4186. if (Info->LinkMTU != 0)
  4187. UpdateLinkMTU(IF, Info->LinkMTU);
  4188. //
  4189. // Update the interface's routing preference.
  4190. //
  4191. if (Info->Preference != (uint)-1) {
  4192. //
  4193. // No lock needed.
  4194. //
  4195. IF->Preference = Info->Preference;
  4196. InvalidateRouteCache();
  4197. }
  4198. //
  4199. // Update the base reachable time.
  4200. //
  4201. if (Info->BaseReachableTime != 0) {
  4202. KeAcquireSpinLock(&IF->Lock, &OldIrql);
  4203. IF->BaseReachableTime = Info->BaseReachableTime;
  4204. IF->ReachableTime = CalcReachableTime(Info->BaseReachableTime);
  4205. KeReleaseSpinLock(&IF->Lock, OldIrql);
  4206. }
  4207. //
  4208. // Update the ND retransmission timer.
  4209. //
  4210. if (Info->RetransTimer != 0) {
  4211. //
  4212. // No lock needed.
  4213. //
  4214. IF->RetransTimer = ConvertMillisToTicks(Info->RetransTimer);
  4215. }
  4216. //
  4217. // Update the number of DAD transmissions.
  4218. //
  4219. if (Info->DupAddrDetectTransmits != (uint)-1) {
  4220. //
  4221. // No lock needed.
  4222. //
  4223. IF->DupAddrDetectTransmits = Info->DupAddrDetectTransmits;
  4224. }
  4225. //
  4226. // Update the default hop limit.
  4227. //
  4228. if (Info->CurHopLimit != (uint)-1) {
  4229. //
  4230. // No lock needed.
  4231. //
  4232. IF->CurHopLimit = Info->CurHopLimit;
  4233. }
  4234. return STATUS_SUCCESS;
  4235. }
  4236. //* ConfigureInterface
  4237. //
  4238. // Configures a newly-created interface from the registry.
  4239. // The interface has not yet been added to the global list,
  4240. // but it is otherwise fully initialized.
  4241. //
  4242. // Callable from thread context, not DPC context.
  4243. //
  4244. void
  4245. ConfigureInterface(Interface *IF)
  4246. {
  4247. IPV6_INFO_INTERFACE Info;
  4248. HANDLE IFKey;
  4249. HANDLE RegKey;
  4250. NTSTATUS Status;
  4251. PAGED_CODE();
  4252. //
  4253. // Open the interface key.
  4254. //
  4255. Status = OpenInterfaceRegKey(&IF->Guid, &IFKey, OpenRegKeyRead);
  4256. if (! NT_SUCCESS(Status))
  4257. return;
  4258. //
  4259. // Read interface attributes.
  4260. //
  4261. Info.Length = 0;
  4262. Status = ReadPersistentInterface(IFKey, &Info);
  4263. ASSERT(NT_SUCCESS(Status) || (Status == STATUS_BUFFER_OVERFLOW));
  4264. //
  4265. // Update the interface.
  4266. //
  4267. Status = InternalUpdateInterface(IF, &Info);
  4268. if (! NT_SUCCESS(Status)) {
  4269. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_USER_ERROR,
  4270. "ConfigureInterface: bad params %x\n", Status));
  4271. }
  4272. //
  4273. // Create persistent addresses.
  4274. //
  4275. Status = OpenRegKey(&RegKey, IFKey, L"Addresses", OpenRegKeyRead);
  4276. if (NT_SUCCESS(Status)) {
  4277. (void) EnumRegKeys(RegKey, CreatePersistentAddr, IF);
  4278. ZwClose(RegKey);
  4279. }
  4280. //
  4281. // Create persistent routes.
  4282. //
  4283. Status = OpenRegKey(&RegKey, IFKey, L"Routes", OpenRegKeyRead);
  4284. if (NT_SUCCESS(Status)) {
  4285. (void) EnumRegKeys(RegKey, CreatePersistentRoute, IF);
  4286. ZwClose(RegKey);
  4287. }
  4288. InitRegDWORDParameter(IFKey, L"TcpInitialRTT",
  4289. &IF->TcpInitialRTT, 0);
  4290. ZwClose(IFKey);
  4291. }
  4292. //* PersistUpdateInterface
  4293. //
  4294. // Helper function for persisting interface attributes in the registry.
  4295. // The IF argument supercedes Info->This.IF.
  4296. //
  4297. // Callable from thread context, not DPC context.
  4298. //
  4299. NTSTATUS
  4300. PersistUpdateInterface(
  4301. Interface *IF,
  4302. IPV6_INFO_INTERFACE *Info)
  4303. {
  4304. HANDLE RegKey;
  4305. NTSTATUS Status;
  4306. PAGED_CODE();
  4307. Status = OpenInterfaceRegKey(&IF->Guid, &RegKey,
  4308. OpenRegKeyCreate);
  4309. if (! NT_SUCCESS(Status))
  4310. return Status;
  4311. if (Info->Advertises != (uint)-1) {
  4312. Status = SetRegDWORDValue(RegKey, L"Advertises",
  4313. Info->Advertises);
  4314. if (! NT_SUCCESS(Status))
  4315. goto ReturnReleaseKey;
  4316. }
  4317. if (Info->Forwards != (uint)-1) {
  4318. Status = SetRegDWORDValue(RegKey, L"Forwards",
  4319. Info->Forwards);
  4320. if (! NT_SUCCESS(Status))
  4321. goto ReturnReleaseKey;
  4322. }
  4323. if (Info->LinkMTU != 0) {
  4324. Status = SetRegDWORDValue(RegKey, L"LinkMTU",
  4325. Info->LinkMTU);
  4326. if (! NT_SUCCESS(Status))
  4327. goto ReturnReleaseKey;
  4328. }
  4329. if (Info->Preference != (uint)-1) {
  4330. Status = SetRegDWORDValue(RegKey, L"Preference",
  4331. Info->Preference);
  4332. if (! NT_SUCCESS(Status))
  4333. goto ReturnReleaseKey;
  4334. }
  4335. if (Info->BaseReachableTime != 0) {
  4336. Status = SetRegDWORDValue(RegKey, L"BaseReachableTime",
  4337. Info->BaseReachableTime);
  4338. if (! NT_SUCCESS(Status))
  4339. goto ReturnReleaseKey;
  4340. }
  4341. if (Info->RetransTimer != 0) {
  4342. Status = SetRegDWORDValue(RegKey, L"RetransTimer",
  4343. Info->RetransTimer);
  4344. if (! NT_SUCCESS(Status))
  4345. goto ReturnReleaseKey;
  4346. }
  4347. if (Info->DupAddrDetectTransmits != (uint)-1) {
  4348. Status = SetRegDWORDValue(RegKey, L"DupAddrDetectTransmits",
  4349. Info->DupAddrDetectTransmits);
  4350. if (! NT_SUCCESS(Status))
  4351. goto ReturnReleaseKey;
  4352. }
  4353. if (Info->CurHopLimit != (uint)-1) {
  4354. Status = SetRegDWORDValue(RegKey, L"CurHopLimit",
  4355. Info->CurHopLimit);
  4356. if (! NT_SUCCESS(Status))
  4357. goto ReturnReleaseKey;
  4358. }
  4359. Status = STATUS_SUCCESS;
  4360. ReturnReleaseKey:
  4361. ZwClose(RegKey);
  4362. return Status;
  4363. }
  4364. //* IoctlUpdateInterface
  4365. //
  4366. // Processes an IOCTL_IPV6_UPDATE_INTERFACE request.
  4367. //
  4368. // Note: Return value indicates whether NT-specific processing of the
  4369. // request was successful. The status of the actual request is returned
  4370. // in the request buffers.
  4371. //
  4372. NTSTATUS
  4373. IoctlUpdateInterface(
  4374. IN PIRP Irp, // I/O request packet.
  4375. IN PIO_STACK_LOCATION IrpSp, // Current stack location in the Irp.
  4376. IN int Persistent)
  4377. {
  4378. IPV6_INFO_INTERFACE *Info;
  4379. Interface *IF;
  4380. KIRQL OldIrql;
  4381. NTSTATUS Status;
  4382. PAGED_CODE();
  4383. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof *Info) {
  4384. Status = STATUS_INVALID_PARAMETER;
  4385. goto ErrorReturn;
  4386. }
  4387. Info = (IPV6_INFO_INTERFACE *) Irp->AssociatedIrp.SystemBuffer;
  4388. //
  4389. // Find the specified interface.
  4390. //
  4391. IF = FindInterfaceFromQuery(&Info->This);
  4392. if (IF == NULL) {
  4393. Status = STATUS_INVALID_PARAMETER_1;
  4394. goto ErrorReturn;
  4395. }
  4396. //
  4397. // Validate parameters and update the interface.
  4398. //
  4399. Status = InternalUpdateInterface(IF, Info);
  4400. if (! NT_SUCCESS(Status))
  4401. goto ErrorReturnReleaseIF;
  4402. //
  4403. // Make the changes persistent?
  4404. //
  4405. if (Persistent) {
  4406. Status = PersistUpdateInterface(IF, Info);
  4407. if (! NT_SUCCESS(Status))
  4408. goto ErrorReturnReleaseIF;
  4409. }
  4410. Status = STATUS_SUCCESS;
  4411. ErrorReturnReleaseIF:
  4412. ReleaseIF(IF);
  4413. ErrorReturn:
  4414. Irp->IoStatus.Status = Status;
  4415. Irp->IoStatus.Information = 0;
  4416. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  4417. return Status;
  4418. } // IoctlUpdateInterface
  4419. //* PersistDeleteInterface
  4420. //
  4421. // Helper function for deleting an interface in the registry.
  4422. // We do not delete the interface key.
  4423. // Instead we just delete the Type value.
  4424. // This way persistent interface attributes (if any) remain.
  4425. //
  4426. // Callable from thread context, not DPC context.
  4427. //
  4428. NTSTATUS
  4429. PersistDeleteInterface(
  4430. Interface *IF)
  4431. {
  4432. HANDLE IFKey;
  4433. NTSTATUS Status;
  4434. PAGED_CODE();
  4435. //
  4436. // Open the interface key.
  4437. //
  4438. Status = OpenInterfaceRegKey(&IF->Guid, &IFKey, OpenRegKeyRead);
  4439. if (! NT_SUCCESS(Status)) {
  4440. if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
  4441. return STATUS_SUCCESS;
  4442. else
  4443. return Status;
  4444. }
  4445. //
  4446. // Delete the Type value.
  4447. //
  4448. Status = RegDeleteValue(IFKey, L"Type");
  4449. ZwClose(IFKey);
  4450. return Status;
  4451. }
  4452. //* IoctlDeleteInterface
  4453. //
  4454. // Processes an IOCTL_IPV6_DELETE_INTERFACE request.
  4455. //
  4456. // Note: Return value indicates whether NT-specific processing of the
  4457. // request was successful. The status of the actual request is returned
  4458. // in the request buffers.
  4459. //
  4460. NTSTATUS
  4461. IoctlDeleteInterface(
  4462. IN PIRP Irp, // I/O request packet.
  4463. IN PIO_STACK_LOCATION IrpSp, // Current stack location in the Irp.
  4464. IN int Persistent)
  4465. {
  4466. IPV6_QUERY_INTERFACE *Info;
  4467. Interface *IF;
  4468. NTSTATUS Status;
  4469. PAGED_CODE();
  4470. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof *Info) {
  4471. Status = STATUS_INVALID_PARAMETER;
  4472. goto Return;
  4473. }
  4474. Info = (IPV6_QUERY_INTERFACE *) Irp->AssociatedIrp.SystemBuffer;
  4475. //
  4476. // Can not delete some predefined interfaces.
  4477. // 6to4svc and other user-level things depend
  4478. // on these standard interfaces.
  4479. //
  4480. if (Info->Index <= 3) {
  4481. Status = STATUS_INVALID_PARAMETER_1;
  4482. goto Return;
  4483. }
  4484. //
  4485. // Find the specified interface.
  4486. //
  4487. IF = FindInterfaceFromQuery(Info);
  4488. if (IF == NULL) {
  4489. Status = STATUS_INVALID_PARAMETER_1;
  4490. goto Return;
  4491. }
  4492. //
  4493. // This will disable the interface, so it will effectively
  4494. // disappear. When the last ref is gone it will be freed.
  4495. //
  4496. DestroyIF(IF);
  4497. //
  4498. // Make the changes persistent?
  4499. //
  4500. if (Persistent) {
  4501. Status = PersistDeleteInterface(IF);
  4502. if (! NT_SUCCESS(Status))
  4503. goto ReturnReleaseIF;
  4504. }
  4505. Status = STATUS_SUCCESS;
  4506. ReturnReleaseIF:
  4507. ReleaseIF(IF);
  4508. Return:
  4509. Irp->IoStatus.Status = Status;
  4510. Irp->IoStatus.Information = 0;
  4511. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  4512. return Status;
  4513. } // IoctlDeleteInterface
  4514. //* IoctlRenewInterface
  4515. //
  4516. // Processes an IOCTL_IPV6_RENEW_INTERFACE request.
  4517. //
  4518. // Note: Return value indicates whether NT-specific processing of the
  4519. // request was successful. The status of the actual request is returned
  4520. // in the request buffers.
  4521. //
  4522. NTSTATUS
  4523. IoctlRenewInterface(
  4524. IN PIRP Irp, // I/O request packet.
  4525. IN PIO_STACK_LOCATION IrpSp) // Current stack location in the Irp.
  4526. {
  4527. IPV6_QUERY_INTERFACE *Query;
  4528. Interface *IF;
  4529. KIRQL OldIrql;
  4530. NTSTATUS Status;
  4531. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof *Query) {
  4532. Status = STATUS_INVALID_PARAMETER;
  4533. goto Return;
  4534. }
  4535. Query = (IPV6_QUERY_INTERFACE *) Irp->AssociatedIrp.SystemBuffer;
  4536. //
  4537. // Find the specified interface.
  4538. //
  4539. IF = FindInterfaceFromQuery(Query);
  4540. if (IF == NULL) {
  4541. Status = STATUS_INVALID_PARAMETER_1;
  4542. goto Return;
  4543. }
  4544. //
  4545. // Pretend as if the interface received a media reconnect
  4546. // event, but only if the interface is already connected.
  4547. //
  4548. // This IOCTL is used by 802.1x to indicate successful data link
  4549. // authentication of this interface. Any data packets already sent
  4550. // on this interface would have been dropped by the authenticator,
  4551. // and hence IPv6 needs to restart its protocol mechanisms, i.e.
  4552. // resend Router Solicitation|Advertisement, Multicast Listener
  4553. // Discovery, and Duplicate Address Detection messages.
  4554. //
  4555. KeAcquireSpinLock(&IF->Lock, &OldIrql);
  4556. if (!IsDisabledIF(IF) && !(IF->Flags & IF_FLAG_MEDIA_DISCONNECTED))
  4557. ReconnectInterface(IF);
  4558. KeReleaseSpinLock(&IF->Lock, OldIrql);
  4559. Status = STATUS_SUCCESS;
  4560. ReleaseIF(IF);
  4561. Return:
  4562. Irp->IoStatus.Status = Status;
  4563. Irp->IoStatus.Information = 0;
  4564. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  4565. return Status;
  4566. } // IoctlRenewInterface
  4567. //* IoctlFlushNeighborCache
  4568. //
  4569. // Processes an IOCTL_IPV6_FLUSH_NEIGHBOR_CACHE request.
  4570. //
  4571. // Note: Return value indicates whether NT-specific processing of the
  4572. // request was successful. The status of the actual request is returned
  4573. // in the request buffers.
  4574. //
  4575. NTSTATUS
  4576. IoctlFlushNeighborCache(
  4577. IN PIRP Irp, // I/O request packet.
  4578. IN PIO_STACK_LOCATION IrpSp) // Current stack location in the Irp.
  4579. {
  4580. IPV6_QUERY_NEIGHBOR_CACHE *Query;
  4581. Interface *IF;
  4582. const IPv6Addr *Address;
  4583. NTSTATUS Status;
  4584. PAGED_CODE();
  4585. Irp->IoStatus.Information = 0;
  4586. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof *Query) {
  4587. Status = STATUS_INVALID_PARAMETER;
  4588. goto Return;
  4589. }
  4590. Query = (IPV6_QUERY_NEIGHBOR_CACHE *) Irp->AssociatedIrp.SystemBuffer;
  4591. //
  4592. // Find the specified interface.
  4593. //
  4594. IF = FindInterfaceFromQuery(&Query->IF);
  4595. if (IF == NULL) {
  4596. Status = STATUS_INVALID_PARAMETER_1;
  4597. goto Return;
  4598. }
  4599. if (IsUnspecified(&Query->Address))
  4600. Address = NULL;
  4601. else
  4602. Address = &Query->Address;
  4603. NeighborCacheFlush(IF, Address);
  4604. ReleaseIF(IF);
  4605. Status = STATUS_SUCCESS;
  4606. Return:
  4607. Irp->IoStatus.Status = Status;
  4608. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  4609. return Status;
  4610. } // IoctlFlushNeighborCache
  4611. //* IoctlFlushRouteCache
  4612. //
  4613. // Processes an IOCTL_IPV6_FLUSH_ROUTE_CACHE request.
  4614. //
  4615. // Note: Return value indicates whether NT-specific processing of the
  4616. // request was successful. The status of the actual request is returned
  4617. // in the request buffers.
  4618. //
  4619. NTSTATUS
  4620. IoctlFlushRouteCache(
  4621. IN PIRP Irp, // I/O request packet.
  4622. IN PIO_STACK_LOCATION IrpSp) // Current stack location in the Irp.
  4623. {
  4624. IPV6_QUERY_ROUTE_CACHE *Query;
  4625. Interface *IF;
  4626. const IPv6Addr *Address;
  4627. NTSTATUS Status;
  4628. PAGED_CODE();
  4629. Irp->IoStatus.Information = 0;
  4630. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof *Query) {
  4631. Status = STATUS_INVALID_PARAMETER;
  4632. goto Return;
  4633. }
  4634. Query = (IPV6_QUERY_ROUTE_CACHE *) Irp->AssociatedIrp.SystemBuffer;
  4635. if (Query->IF.Index == (uint)-1) {
  4636. IF = NULL;
  4637. }
  4638. else {
  4639. //
  4640. // Find the specified interface.
  4641. //
  4642. IF = FindInterfaceFromQuery(&Query->IF);
  4643. if (IF == NULL) {
  4644. Status = STATUS_INVALID_PARAMETER_1;
  4645. goto Return;
  4646. }
  4647. }
  4648. if (IsUnspecified(&Query->Address))
  4649. Address = NULL;
  4650. else
  4651. Address = &Query->Address;
  4652. FlushRouteCache(IF, Address);
  4653. if (IF != NULL)
  4654. ReleaseIF(IF);
  4655. Status = STATUS_SUCCESS;
  4656. Return:
  4657. Irp->IoStatus.Status = Status;
  4658. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  4659. return Status;
  4660. } // IoctlFlushRouteCache
  4661. //* IoctlSortDestAddrs
  4662. //
  4663. // Processes an IOCTL_IPV6_SORT_DEST_ADDRS request.
  4664. //
  4665. // Note: Return value indicates whether NT-specific processing of the
  4666. // request was successful. The status of the actual request is returned
  4667. // in the request buffers.
  4668. //
  4669. NTSTATUS
  4670. IoctlSortDestAddrs(
  4671. IN PIRP Irp, // I/O request packet.
  4672. IN PIO_STACK_LOCATION IrpSp) // Current stack location in the Irp.
  4673. {
  4674. TDI_ADDRESS_IP6 *Addrs;
  4675. uint *Key;
  4676. uint NumAddrsIn, NumAddrsOut;
  4677. uint i;
  4678. NTSTATUS Status;
  4679. PAGED_CODE();
  4680. NumAddrsIn = IrpSp->Parameters.DeviceIoControl.InputBufferLength /
  4681. sizeof(TDI_ADDRESS_IP6);
  4682. NumAddrsOut = NumAddrsIn;
  4683. if ((IrpSp->Parameters.DeviceIoControl.InputBufferLength !=
  4684. NumAddrsIn * sizeof(TDI_ADDRESS_IP6)) ||
  4685. (IrpSp->Parameters.DeviceIoControl.OutputBufferLength !=
  4686. ALIGN_UP(NumAddrsIn * sizeof(TDI_ADDRESS_IP6), uint) +
  4687. NumAddrsOut * sizeof(uint))) {
  4688. Irp->IoStatus.Information = 0;
  4689. Status = STATUS_INVALID_PARAMETER;
  4690. goto Return;
  4691. }
  4692. Addrs = Irp->AssociatedIrp.SystemBuffer;
  4693. Key = (uint *)ALIGN_UP_POINTER(Addrs + NumAddrsIn, uint);
  4694. //
  4695. // Initialize key array.
  4696. //
  4697. for (i = 0; i < NumAddrsIn; i++)
  4698. Key[i] = i;
  4699. if (NumAddrsOut > 1) {
  4700. //
  4701. // Remove inappropriate site-local addresses
  4702. // and set the scope-id of site-local addresses.
  4703. //
  4704. ProcessSiteLocalAddresses(Addrs, Key, &NumAddrsOut);
  4705. //
  4706. // Sort the remaining addresses.
  4707. //
  4708. if (NumAddrsOut > 1)
  4709. SortDestAddresses(Addrs, Key, NumAddrsOut);
  4710. }
  4711. Irp->IoStatus.Information = ALIGN_UP(NumAddrsIn * sizeof(TDI_ADDRESS_IP6), uint)
  4712. + (NumAddrsOut * sizeof(uint));
  4713. Status = STATUS_SUCCESS;
  4714. Return:
  4715. Irp->IoStatus.Status = Status;
  4716. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  4717. return Status;
  4718. } // IoctlSortDestAddrs.
  4719. //* IoctlQuerySitePrefix
  4720. //
  4721. // Processes an IOCTL_IPV6_QUERY_SITE_PREFIX request.
  4722. //
  4723. // Note: Return value indicates whether NT-specific processing of the
  4724. // request was successful. The status of the actual request is returned
  4725. // in the request buffers.
  4726. //
  4727. NTSTATUS
  4728. IoctlQuerySitePrefix(
  4729. IN PIRP Irp, // I/O request packet.
  4730. IN PIO_STACK_LOCATION IrpSp) // Current stack location in the Irp.
  4731. {
  4732. IPV6_QUERY_SITE_PREFIX *Query;
  4733. IPV6_INFO_SITE_PREFIX *Info;
  4734. SitePrefixEntry *SPE;
  4735. KIRQL OldIrql;
  4736. NTSTATUS Status;
  4737. PAGED_CODE();
  4738. Irp->IoStatus.Information = 0;
  4739. if ((IrpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof *Query) ||
  4740. (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof *Info)) {
  4741. Status = STATUS_INVALID_PARAMETER;
  4742. goto Return;
  4743. }
  4744. //
  4745. // Note that the Query and Info->Query structures overlap!
  4746. //
  4747. Query = (IPV6_QUERY_SITE_PREFIX *) Irp->AssociatedIrp.SystemBuffer;
  4748. Info = (IPV6_INFO_SITE_PREFIX *) Irp->AssociatedIrp.SystemBuffer;
  4749. if (Query->IF.Index == 0) {
  4750. //
  4751. // Return query parameters of the first SPE.
  4752. //
  4753. KeAcquireSpinLock(&RouteTableLock, &OldIrql);
  4754. if ((SPE = SitePrefixTable) != NULL) {
  4755. Info->Query.Prefix = SPE->Prefix;
  4756. Info->Query.PrefixLength = SPE->SitePrefixLength;
  4757. Info->Query.IF.Index = SPE->IF->Index;
  4758. }
  4759. KeReleaseSpinLock(&RouteTableLock, OldIrql);
  4760. Irp->IoStatus.Information = sizeof Info->Query;
  4761. } else {
  4762. //
  4763. // Find the specified SPE.
  4764. //
  4765. KeAcquireSpinLock(&RouteTableLock, &OldIrql);
  4766. for (SPE = SitePrefixTable; ; SPE = SPE->Next) {
  4767. if (SPE == NULL) {
  4768. KeReleaseSpinLock(&RouteTableLock, OldIrql);
  4769. Status = STATUS_INVALID_PARAMETER_2;
  4770. goto Return;
  4771. }
  4772. if (IP6_ADDR_EQUAL(&Query->Prefix, &SPE->Prefix) &&
  4773. (Query->PrefixLength == SPE->SitePrefixLength) &&
  4774. (Query->IF.Index == SPE->IF->Index))
  4775. break;
  4776. }
  4777. //
  4778. // Return misc. information about the SPE.
  4779. //
  4780. Info->ValidLifetime = ConvertTicksToSeconds(SPE->ValidLifetime);
  4781. //
  4782. // Return query parameters of the next SPE (or zero).
  4783. //
  4784. if ((SPE = SPE->Next) == NULL) {
  4785. Info->Query.IF.Index = 0;
  4786. } else {
  4787. Info->Query.Prefix = SPE->Prefix;
  4788. Info->Query.PrefixLength = SPE->SitePrefixLength;
  4789. Info->Query.IF.Index = SPE->IF->Index;
  4790. }
  4791. KeReleaseSpinLock(&RouteTableLock, OldIrql);
  4792. Irp->IoStatus.Information = sizeof *Info;
  4793. }
  4794. Status = STATUS_SUCCESS;
  4795. Return:
  4796. Irp->IoStatus.Status = Status;
  4797. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  4798. return Status;
  4799. } // IoctlQuerySitePrefix
  4800. //* IoctlUpdateSitePrefix
  4801. //
  4802. // Processes an IOCTL_IPV6_UPDATE_SITE_PREFIX request.
  4803. //
  4804. // Note: Return value indicates whether NT-specific processing of the
  4805. // request was successful. The status of the actual request is returned
  4806. // in the request buffers.
  4807. //
  4808. NTSTATUS
  4809. IoctlUpdateSitePrefix(
  4810. IN PIRP Irp, // I/O request packet.
  4811. IN PIO_STACK_LOCATION IrpSp) // Current stack location in the Irp.
  4812. {
  4813. IPV6_INFO_SITE_PREFIX *Info;
  4814. Interface *IF = NULL;
  4815. SitePrefixEntry *SPE;
  4816. uint ValidLifetime;
  4817. KIRQL OldIrql;
  4818. NTSTATUS Status;
  4819. PAGED_CODE();
  4820. Irp->IoStatus.Information = 0;
  4821. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof *Info) {
  4822. Status = STATUS_INVALID_PARAMETER;
  4823. goto Return;
  4824. }
  4825. Info = (IPV6_INFO_SITE_PREFIX *) Irp->AssociatedIrp.SystemBuffer;
  4826. //
  4827. // Sanity check the arguments.
  4828. //
  4829. if (Info->Query.PrefixLength > IPV6_ADDRESS_LENGTH) {
  4830. Status = STATUS_INVALID_PARAMETER_3;
  4831. goto Return;
  4832. }
  4833. //
  4834. // Find the specified interface.
  4835. //
  4836. IF = FindInterfaceFromQuery(&Info->Query.IF);
  4837. if (IF == NULL) {
  4838. Status = STATUS_INVALID_PARAMETER_1;
  4839. goto Return;
  4840. }
  4841. //
  4842. // Convert the lifetime from seconds to ticks.
  4843. //
  4844. ValidLifetime = ConvertSecondsToTicks(Info->ValidLifetime);
  4845. //
  4846. // Create/update the specified site prefix.
  4847. //
  4848. SitePrefixUpdate(IF,
  4849. &Info->Query.Prefix,
  4850. Info->Query.PrefixLength,
  4851. ValidLifetime);
  4852. Irp->IoStatus.Information = 0;
  4853. Status = STATUS_SUCCESS;
  4854. Return:
  4855. if (IF != NULL)
  4856. ReleaseIF(IF);
  4857. Irp->IoStatus.Status = Status;
  4858. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  4859. return Status;
  4860. } // IoctlUpdateSitePrefix
  4861. //* CancelRtChangeNotifyRequest
  4862. //
  4863. // The IO manager calls this function when a route change
  4864. // notification request is cancelled.
  4865. //
  4866. // Called with the cancel spinlock held.
  4867. //
  4868. void
  4869. CancelRtChangeNotifyRequest(
  4870. IN PDEVICE_OBJECT DeviceObject,
  4871. IN PIRP Irp)
  4872. {
  4873. int ShouldComplete;
  4874. ASSERT(Irp->Cancel);
  4875. ASSERT(Irp->CancelRoutine == NULL);
  4876. //
  4877. // The route lock protects the queue.
  4878. //
  4879. KeAcquireSpinLockAtDpcLevel(&RouteTableLock);
  4880. ShouldComplete = (Irp->Tail.Overlay.ListEntry.Flink != NULL);
  4881. if (ShouldComplete) {
  4882. //
  4883. // CheckRtChangeNotifyRequests has not removed
  4884. // this request from the queue. So we remove the request
  4885. // and complete it below.
  4886. //
  4887. RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
  4888. }
  4889. else {
  4890. //
  4891. // CheckRtChangeNotifyRequests has removed
  4892. // this request from the queue. We must not
  4893. // touch the Irp after unlocking because
  4894. // CompleteRtChangeNotifyRequests could complete it.
  4895. //
  4896. }
  4897. KeReleaseSpinLockFromDpcLevel(&RouteTableLock);
  4898. IoReleaseCancelSpinLock(Irp->CancelIrql);
  4899. if (ShouldComplete) {
  4900. Irp->IoStatus.Information = 0;
  4901. Irp->IoStatus.Status = STATUS_CANCELLED;
  4902. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  4903. }
  4904. }
  4905. //* CheckFileObjectInIrpList
  4906. //
  4907. // Looks to see if an Irp in the list has the given file object.
  4908. //
  4909. int
  4910. CheckFileObjectInIrpList(PFILE_OBJECT FileObject, PIRP Irp)
  4911. {
  4912. PIO_STACK_LOCATION IrpSp;
  4913. while (Irp != NULL) {
  4914. IrpSp = IoGetCurrentIrpStackLocation(Irp);
  4915. if (IrpSp->FileObject == FileObject)
  4916. return TRUE;
  4917. Irp = (PIRP) Irp->Tail.Overlay.ListEntry.Blink;
  4918. }
  4919. return FALSE;
  4920. }
  4921. //* CheckRtChangeNotifyRequests
  4922. //
  4923. // Searches the queue of route change notification requests.
  4924. // Moves any matching requests (that should be completed)
  4925. // to a temporary list kept in the context structure.
  4926. //
  4927. // Called with the route lock held.
  4928. //
  4929. void
  4930. CheckRtChangeNotifyRequests(
  4931. CheckRtChangeContext *Context,
  4932. PFILE_OBJECT FileObject,
  4933. RouteTableEntry *RTE)
  4934. {
  4935. LIST_ENTRY *ListEntry;
  4936. LIST_ENTRY *NextListEntry;
  4937. PIRP Irp;
  4938. PIO_STACK_LOCATION IrpSp;
  4939. IPV6_RTCHANGE_NOTIFY_REQUEST *Request;
  4940. PIRP *ThisChangeList;
  4941. //
  4942. // *ThisChangeList is the tail of Context->RequestList
  4943. // that was added as a result of this change.
  4944. //
  4945. ThisChangeList = Context->LastRequest;
  4946. for (ListEntry = RouteNotifyQueue.Flink;
  4947. ListEntry != &RouteNotifyQueue;
  4948. ListEntry = NextListEntry) {
  4949. NextListEntry = ListEntry->Flink;
  4950. Irp = CONTAINING_RECORD(ListEntry, IRP, Tail.Overlay.ListEntry);
  4951. IrpSp = IoGetCurrentIrpStackLocation(Irp);
  4952. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength >=
  4953. sizeof *Request)
  4954. Request = (IPV6_RTCHANGE_NOTIFY_REQUEST *)
  4955. Irp->AssociatedIrp.SystemBuffer;
  4956. else
  4957. Request = NULL;
  4958. if ((Request == NULL) ||
  4959. (IntersectPrefix(&RTE->Prefix, RTE->PrefixLength,
  4960. &Request->Prefix, Request->PrefixLength) &&
  4961. ((Request->ScopeId == 0) ||
  4962. (Request->ScopeId == DetermineScopeId(&Request->Prefix,
  4963. RTE->IF))))) {
  4964. //
  4965. // This request matches the route change.
  4966. // But we might still suppress notification.
  4967. //
  4968. if ((Request != NULL) &&
  4969. (((Request->Flags &
  4970. IPV6_RTCHANGE_NOTIFY_REQUEST_FLAG_SUPPRESS_MINE) &&
  4971. (IrpSp->FileObject == FileObject)) ||
  4972. ((Request->Flags &
  4973. IPV6_RTCHANGE_NOTIFY_REQUEST_FLAG_SYNCHRONIZE) &&
  4974. CheckFileObjectInIrpList(IrpSp->FileObject,
  4975. *ThisChangeList)))) {
  4976. //
  4977. // The request matches, but suppress notification.
  4978. //
  4979. }
  4980. else {
  4981. //
  4982. // Before we remove the Irp from RouteNotifyQueue,
  4983. // may need to allocate a work item & work context.
  4984. // If the allocation fails, we can bail without doing anything.
  4985. //
  4986. if ((Context->OldIrql >= DISPATCH_LEVEL) &&
  4987. (Context->Context == NULL)) {
  4988. CompleteRtChangeContext *MyContext;
  4989. MyContext = ExAllocatePool(NonPagedPool,
  4990. sizeof *MyContext);
  4991. if (MyContext == NULL)
  4992. return;
  4993. MyContext->WorkItem = IoAllocateWorkItem(IPDeviceObject);
  4994. if (MyContext->WorkItem == NULL) {
  4995. ExFreePool(MyContext);
  4996. return;
  4997. }
  4998. Context->Context = MyContext;
  4999. }
  5000. //
  5001. // We will complete this pending notification,
  5002. // so remove it from RouteNotifyQueue and
  5003. // put it on our private list.
  5004. //
  5005. RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
  5006. Irp->Tail.Overlay.ListEntry.Flink = NULL;
  5007. Irp->Tail.Overlay.ListEntry.Blink = NULL;
  5008. *Context->LastRequest = Irp;
  5009. Context->LastRequest = (PIRP *)
  5010. &Irp->Tail.Overlay.ListEntry.Blink;
  5011. //
  5012. // Return output information, if requested.
  5013. //
  5014. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength >=
  5015. sizeof(IPV6_INFO_ROUTE_TABLE)) {
  5016. IPV6_INFO_ROUTE_TABLE *Info = (IPV6_INFO_ROUTE_TABLE *)
  5017. Irp->AssociatedIrp.SystemBuffer;
  5018. //
  5019. // Return misc. information about the RTE.
  5020. //
  5021. RouteTableInfo(RTE, RTE, Info);
  5022. Irp->IoStatus.Information = sizeof *Info;
  5023. }
  5024. else
  5025. Irp->IoStatus.Information = 0;
  5026. }
  5027. }
  5028. }
  5029. }
  5030. //* CompleteRtChangeNotifyRequestsHelper
  5031. //
  5032. // Completes a list of route change notification requests.
  5033. //
  5034. // Callable from thread context, not DPC context.
  5035. // May NOT be called with the route lock held.
  5036. //
  5037. void
  5038. CompleteRtChangeNotifyRequestsHelper(PIRP RequestList)
  5039. {
  5040. PIRP Irp;
  5041. KIRQL OldIrql;
  5042. ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
  5043. //
  5044. // RequestList is singly-linked through the Blink field.
  5045. // The Flink field is NULL; CancelRtChangeNotifyRequest
  5046. // looks at this.
  5047. //
  5048. while ((Irp = RequestList) != NULL) {
  5049. ASSERT(Irp->Tail.Overlay.ListEntry.Flink == NULL);
  5050. RequestList = (PIRP) Irp->Tail.Overlay.ListEntry.Blink;
  5051. IoAcquireCancelSpinLock(&OldIrql);
  5052. if (Irp->Cancel) {
  5053. //
  5054. // The Irp is being cancelled.
  5055. //
  5056. ASSERT(Irp->CancelRoutine == NULL);
  5057. Irp->IoStatus.Information = 0;
  5058. Irp->IoStatus.Status = STATUS_CANCELLED;
  5059. }
  5060. else {
  5061. //
  5062. // The Irp is not yet cancelled.
  5063. // We must prevent CancelRtChangeNotifyRequest
  5064. // from being called after we release the cancel lock.
  5065. //
  5066. ASSERT(Irp->CancelRoutine == CancelRtChangeNotifyRequest);
  5067. IoSetCancelRoutine(Irp, NULL);
  5068. //
  5069. // Irp->IoStatus.Information and the output structure
  5070. // are already initialized.
  5071. //
  5072. Irp->IoStatus.Status = STATUS_SUCCESS;
  5073. }
  5074. IoReleaseCancelSpinLock(OldIrql);
  5075. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  5076. }
  5077. }
  5078. //* CompleteRtChangeNotifyRequestsWorker
  5079. //
  5080. // Worker thread function - cleans up the work item
  5081. // and calls CompleteRtChangeNotifyRequestsHelper.
  5082. //
  5083. void
  5084. CompleteRtChangeNotifyRequestsWorker(
  5085. PDEVICE_OBJECT DeviceObject,
  5086. PVOID Context)
  5087. {
  5088. CompleteRtChangeContext *MyContext = Context;
  5089. CompleteRtChangeNotifyRequestsHelper(MyContext->RequestList);
  5090. IoFreeWorkItem(MyContext->WorkItem);
  5091. ExFreePool(MyContext);
  5092. }
  5093. //* CompleteRtChangeNotifyRequests
  5094. //
  5095. // Completes a list of route change notification requests.
  5096. //
  5097. // Callable from a thread or DPC context.
  5098. // May NOT be called with the route lock held.
  5099. //
  5100. void
  5101. CompleteRtChangeNotifyRequests(CheckRtChangeContext *Context)
  5102. {
  5103. ASSERT(Context->OldIrql == KeGetCurrentIrql());
  5104. if (Context->OldIrql >= DISPATCH_LEVEL) {
  5105. CompleteRtChangeContext *MyContext = Context->Context;
  5106. //
  5107. // We can't complete Irps at dispatch level,
  5108. // so punt to a worker thread.
  5109. // The work item was already allocated.
  5110. //
  5111. MyContext->RequestList = Context->RequestList;
  5112. IoQueueWorkItem(MyContext->WorkItem,
  5113. CompleteRtChangeNotifyRequestsWorker,
  5114. CriticalWorkQueue,
  5115. MyContext);
  5116. }
  5117. else {
  5118. //
  5119. // We can complete the Irps directly.
  5120. //
  5121. ASSERT(Context->Context == NULL);
  5122. CompleteRtChangeNotifyRequestsHelper(Context->RequestList);
  5123. }
  5124. }
  5125. //* IoctlRtChangeNotifyRequest
  5126. //
  5127. // Processes an IOCTL_IPV6_RTCHANGE_NOTIFY_REQUEST request.
  5128. //
  5129. // Note: Return value indicates whether NT-specific processing of the
  5130. // request was successful. The status of the actual request is returned
  5131. // in the request buffers.
  5132. //
  5133. NTSTATUS
  5134. IoctlRtChangeNotifyRequest(
  5135. IN PIRP Irp, // I/O request packet.
  5136. IN PIO_STACK_LOCATION IrpSp) // Current stack location in the Irp.
  5137. {
  5138. NTSTATUS Status;
  5139. KIRQL OldIrql;
  5140. PAGED_CODE();
  5141. if (((IrpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof(IPV6_RTCHANGE_NOTIFY_REQUEST)) &&
  5142. (IrpSp->Parameters.DeviceIoControl.InputBufferLength != 0)) ||
  5143. ((IrpSp->Parameters.DeviceIoControl.OutputBufferLength != sizeof(IPV6_INFO_ROUTE_TABLE)) &&
  5144. (IrpSp->Parameters.DeviceIoControl.OutputBufferLength != 0))) {
  5145. Status = STATUS_INVALID_PARAMETER;
  5146. goto ErrorReturn;
  5147. }
  5148. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength == sizeof(IPV6_RTCHANGE_NOTIFY_REQUEST)) {
  5149. IPV6_RTCHANGE_NOTIFY_REQUEST *Request;
  5150. Request = (IPV6_RTCHANGE_NOTIFY_REQUEST *)
  5151. Irp->AssociatedIrp.SystemBuffer;
  5152. //
  5153. // Sanity check the arguments.
  5154. //
  5155. if (Request->PrefixLength > IPV6_ADDRESS_LENGTH) {
  5156. Status = STATUS_INVALID_PARAMETER_1;
  5157. goto ErrorReturn;
  5158. }
  5159. if (Request->ScopeId != 0) {
  5160. //
  5161. // If a ScopeId is specified, it must be
  5162. // unambiguously a link-local or site-local prefix.
  5163. //
  5164. if ((Request->PrefixLength < 10) ||
  5165. !(IsLinkLocal(&Request->Prefix) ||
  5166. IsSiteLocal(&Request->Prefix))) {
  5167. Status = STATUS_INVALID_PARAMETER_2;
  5168. goto ErrorReturn;
  5169. }
  5170. }
  5171. }
  5172. IoAcquireCancelSpinLock(&OldIrql);
  5173. ASSERT(Irp->CancelRoutine == NULL);
  5174. if (Irp->Cancel) {
  5175. IoReleaseCancelSpinLock(OldIrql);
  5176. Status = STATUS_CANCELLED;
  5177. goto ErrorReturn;
  5178. }
  5179. //
  5180. // Add this Irp to the queue of notification requests.
  5181. // Acquire route lock, which protects the queue.
  5182. //
  5183. KeAcquireSpinLockAtDpcLevel(&RouteTableLock);
  5184. InsertTailList(&RouteNotifyQueue, &Irp->Tail.Overlay.ListEntry);
  5185. KeReleaseSpinLockFromDpcLevel(&RouteTableLock);
  5186. //
  5187. // We return pending to indicate that we've queued the Irp
  5188. // and it will be completed later.
  5189. // Must mark the Irp before unlocking, because once unlocked
  5190. // the Irp might be completed and deallocated.
  5191. //
  5192. IoMarkIrpPending(Irp);
  5193. IoSetCancelRoutine(Irp, CancelRtChangeNotifyRequest);
  5194. IoReleaseCancelSpinLock(OldIrql);
  5195. return STATUS_PENDING;
  5196. ErrorReturn:
  5197. Irp->IoStatus.Information = 0;
  5198. Irp->IoStatus.Status = Status;
  5199. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  5200. return Status;
  5201. } // IoctlRtChangeNotifyRequest
  5202. //* ReadPersistentGlobalParameters
  5203. //
  5204. // Reads global parameters from the registry.
  5205. //
  5206. void
  5207. ReadPersistentGlobalParameters(IPV6_GLOBAL_PARAMETERS *Params)
  5208. {
  5209. HANDLE RegKey = NULL;
  5210. NTSTATUS Status;
  5211. Status = OpenTopLevelRegKey(L"GlobalParams", &RegKey, OpenRegKeyRead);
  5212. ASSERT(NT_SUCCESS(Status) || (RegKey == NULL));
  5213. //
  5214. // Read global parameters from the registry.
  5215. //
  5216. InitRegDWORDParameter(RegKey,
  5217. L"DefaultCurHopLimit",
  5218. &Params->DefaultCurHopLimit,
  5219. (uint)-1);
  5220. InitRegDWORDParameter(RegKey,
  5221. L"UseAnonymousAddresses",
  5222. &Params->UseAnonymousAddresses,
  5223. (uint)-1);
  5224. InitRegDWORDParameter(RegKey,
  5225. L"MaxAnonDADAttempts",
  5226. &Params->MaxAnonDADAttempts,
  5227. (uint)-1);
  5228. InitRegDWORDParameter(RegKey,
  5229. L"MaxAnonValidLifetime",
  5230. &Params->MaxAnonValidLifetime,
  5231. (uint)-1);
  5232. InitRegDWORDParameter(RegKey,
  5233. L"MaxAnonPreferredLifetime",
  5234. &Params->MaxAnonPreferredLifetime,
  5235. (uint)-1);
  5236. InitRegDWORDParameter(RegKey,
  5237. L"AnonRegenerateTime",
  5238. &Params->AnonRegenerateTime,
  5239. (uint)-1);
  5240. InitRegDWORDParameter(RegKey,
  5241. L"MaxAnonRandomTime",
  5242. &Params->MaxAnonRandomTime,
  5243. (uint)-1);
  5244. Params->AnonRandomTime = 0;
  5245. InitRegDWORDParameter(RegKey,
  5246. L"NeighborCacheLimit",
  5247. &Params->NeighborCacheLimit,
  5248. (uint)-1);
  5249. InitRegDWORDParameter(RegKey,
  5250. L"RouteCacheLimit",
  5251. &Params->RouteCacheLimit,
  5252. (uint)-1);
  5253. InitRegDWORDParameter(RegKey,
  5254. L"BindingCacheLimit",
  5255. &Params->BindingCacheLimit,
  5256. (uint)-1);
  5257. InitRegDWORDParameter(RegKey,
  5258. L"ReassemblyLimit",
  5259. &Params->ReassemblyLimit,
  5260. (uint)-1);
  5261. InitRegDWORDParameter(RegKey,
  5262. L"MobilitySecurity",
  5263. (ULONG *)&Params->MobilitySecurity,
  5264. (uint)-1);
  5265. if (RegKey != NULL)
  5266. ZwClose(RegKey);
  5267. }
  5268. //* IoctlQueryGlobalParameters
  5269. //
  5270. // Processes an IOCTL_IPV6_QUERY_GLOBAL_PARAMETERS request.
  5271. //
  5272. // Note: Return value indicates whether NT-specific processing of the
  5273. // request was successful. The status of the actual request is returned
  5274. // in the request buffers.
  5275. //
  5276. NTSTATUS
  5277. IoctlQueryGlobalParameters(
  5278. IN PIRP Irp, // I/O request packet.
  5279. IN PIO_STACK_LOCATION IrpSp, // Current stack location in the Irp.
  5280. IN int Persistent)
  5281. {
  5282. IPV6_GLOBAL_PARAMETERS *Params;
  5283. NTSTATUS Status;
  5284. PAGED_CODE();
  5285. Irp->IoStatus.Information = 0;
  5286. if ((IrpSp->Parameters.DeviceIoControl.InputBufferLength != 0) ||
  5287. (IrpSp->Parameters.DeviceIoControl.OutputBufferLength != sizeof *Params)) {
  5288. Status = STATUS_INVALID_PARAMETER;
  5289. goto Return;
  5290. }
  5291. Params = (IPV6_GLOBAL_PARAMETERS *)Irp->AssociatedIrp.SystemBuffer;
  5292. if (Persistent) {
  5293. //
  5294. // Read global parameters from the registry.
  5295. //
  5296. ReadPersistentGlobalParameters(Params);
  5297. }
  5298. else {
  5299. //
  5300. // Return the current values of the parameters.
  5301. //
  5302. Params->DefaultCurHopLimit = DefaultCurHopLimit;
  5303. Params->UseAnonymousAddresses = UseAnonymousAddresses;
  5304. Params->MaxAnonDADAttempts = MaxAnonDADAttempts;
  5305. Params->MaxAnonValidLifetime = ConvertTicksToSeconds(MaxAnonValidLifetime);
  5306. Params->MaxAnonPreferredLifetime = ConvertTicksToSeconds(MaxAnonPreferredLifetime);
  5307. Params->AnonRegenerateTime = ConvertTicksToSeconds(AnonRegenerateTime);
  5308. Params->MaxAnonRandomTime = ConvertTicksToSeconds(MaxAnonRandomTime);
  5309. Params->AnonRandomTime = ConvertTicksToSeconds(AnonRandomTime);
  5310. Params->NeighborCacheLimit = NeighborCacheLimit;
  5311. Params->RouteCacheLimit = RouteCache.Limit;
  5312. Params->BindingCacheLimit = BindingCache.Limit;
  5313. Params->ReassemblyLimit = ReassemblyList.Limit;
  5314. Params->MobilitySecurity = MobilitySecurity;
  5315. }
  5316. Irp->IoStatus.Information = sizeof *Params;
  5317. Status = STATUS_SUCCESS;
  5318. Return:
  5319. Irp->IoStatus.Status = Status;
  5320. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  5321. return Status;
  5322. } // IoctlQueryGlobalParameters.
  5323. //* InternalUpdateGlobalParameters
  5324. //
  5325. // Common helper function for IoctlUpdateGlobalParameters
  5326. // and ConfigureGlobalParameters, consolidating
  5327. // parameter validation in one place.
  5328. //
  5329. // Callable from thread context, not DPC context.
  5330. //
  5331. // Return codes:
  5332. // STATUS_INVALID_PARAMETER_1 Bad DefaultCurHopLimit.
  5333. // STATUS_INVALID_PARAMETER_2 Bad UseAnonymousAddresses.
  5334. // STATUS_INVALID_PARAMETER_3 Bad anonymous times.
  5335. // STATUS_SUCCESS
  5336. //
  5337. NTSTATUS
  5338. InternalUpdateGlobalParameters(IPV6_GLOBAL_PARAMETERS *Params)
  5339. {
  5340. uint NewMaxAnonValidLifetime;
  5341. uint NewMaxAnonPreferredLifetime;
  5342. uint NewAnonRegenerateTime;
  5343. uint NewMaxAnonRandomTime;
  5344. uint NewAnonRandomTime;
  5345. PAGED_CODE();
  5346. //
  5347. // Sanity check the new parameters.
  5348. //
  5349. if (Params->DefaultCurHopLimit != (uint)-1) {
  5350. if ((Params->DefaultCurHopLimit == 0) ||
  5351. (Params->DefaultCurHopLimit > 0xff))
  5352. return STATUS_INVALID_PARAMETER_1;
  5353. }
  5354. if (Params->UseAnonymousAddresses != (uint)-1) {
  5355. if (Params->UseAnonymousAddresses > USE_ANON_COUNTER)
  5356. return STATUS_INVALID_PARAMETER_2;
  5357. }
  5358. if (Params->MaxAnonValidLifetime != (uint)-1)
  5359. NewMaxAnonValidLifetime =
  5360. ConvertSecondsToTicks(Params->MaxAnonValidLifetime);
  5361. else
  5362. NewMaxAnonValidLifetime = MaxAnonValidLifetime;
  5363. if (Params->MaxAnonPreferredLifetime != (uint)-1)
  5364. NewMaxAnonPreferredLifetime =
  5365. ConvertSecondsToTicks(Params->MaxAnonPreferredLifetime);
  5366. else
  5367. NewMaxAnonPreferredLifetime = MaxAnonPreferredLifetime;
  5368. if (Params->AnonRegenerateTime != (uint)-1)
  5369. NewAnonRegenerateTime =
  5370. ConvertSecondsToTicks(Params->AnonRegenerateTime);
  5371. else
  5372. NewAnonRegenerateTime = AnonRegenerateTime;
  5373. if (Params->MaxAnonRandomTime != (uint)-1)
  5374. NewMaxAnonRandomTime =
  5375. ConvertSecondsToTicks(Params->MaxAnonRandomTime);
  5376. else
  5377. NewMaxAnonRandomTime = MaxAnonRandomTime;
  5378. if (Params->AnonRandomTime == 0)
  5379. NewAnonRandomTime = RandomNumber(0, NewMaxAnonRandomTime);
  5380. else if (Params->AnonRandomTime == (uint)-1)
  5381. NewAnonRandomTime = AnonRandomTime;
  5382. else
  5383. NewAnonRandomTime = ConvertSecondsToTicks(Params->AnonRandomTime);
  5384. if (!(NewAnonRandomTime <= NewMaxAnonRandomTime) ||
  5385. !(NewAnonRegenerateTime + NewMaxAnonRandomTime <
  5386. NewMaxAnonPreferredLifetime) ||
  5387. !(NewMaxAnonPreferredLifetime <= NewMaxAnonValidLifetime))
  5388. return STATUS_INVALID_PARAMETER_3;
  5389. //
  5390. // Set the new values.
  5391. //
  5392. if (Params->DefaultCurHopLimit != (uint)-1)
  5393. DefaultCurHopLimit = Params->DefaultCurHopLimit;
  5394. if (Params->UseAnonymousAddresses != (uint)-1)
  5395. UseAnonymousAddresses = Params->UseAnonymousAddresses;
  5396. if (Params->MaxAnonDADAttempts != (uint)-1)
  5397. MaxAnonDADAttempts = Params->MaxAnonDADAttempts;
  5398. MaxAnonValidLifetime = NewMaxAnonValidLifetime;
  5399. MaxAnonPreferredLifetime = NewMaxAnonPreferredLifetime;
  5400. AnonRegenerateTime = NewAnonRegenerateTime;
  5401. MaxAnonRandomTime = NewMaxAnonRandomTime;
  5402. AnonRandomTime = NewAnonRandomTime;
  5403. if (Params->NeighborCacheLimit != (uint)-1)
  5404. NeighborCacheLimit = Params->NeighborCacheLimit;
  5405. if (Params->RouteCacheLimit != (uint)-1)
  5406. RouteCache.Limit = Params->RouteCacheLimit;
  5407. if (Params->BindingCacheLimit != (uint)-1)
  5408. BindingCache.Limit = Params->BindingCacheLimit;
  5409. if (Params->ReassemblyLimit != (uint)-1)
  5410. ReassemblyList.Limit = Params->ReassemblyLimit;
  5411. if (Params->MobilitySecurity != -1)
  5412. MobilitySecurity = Params->MobilitySecurity;
  5413. return STATUS_SUCCESS;
  5414. }
  5415. //* DefaultReassemblyLimit
  5416. //
  5417. // Computes the default memory limit for reassembly buffers, based
  5418. // on the amount of physical memory in the system.
  5419. //
  5420. uint
  5421. DefaultReassemblyLimit(void)
  5422. {
  5423. SYSTEM_BASIC_INFORMATION Info;
  5424. ULONG MemSize;
  5425. NTSTATUS Status;
  5426. Status = ZwQuerySystemInformation(SystemBasicInformation,
  5427. &Info,
  5428. sizeof(Info),
  5429. NULL);
  5430. if (!NT_SUCCESS(Status)) {
  5431. //
  5432. // If this failed, then we're probably really resource constrained,
  5433. // so use only 256K.
  5434. //
  5435. return (256 * 1024);
  5436. }
  5437. //
  5438. // By default, limit the reassembly buffers to a maximum size equal
  5439. // to 1/128th of the physical memory. On a machine with only 128M of
  5440. // memory, this is 1M of memory maximum (enough to reassemble
  5441. // 16 64K packets, or 128 8K packets, for example). In contrast,
  5442. // the IPv4 stack currently allows reassembling a fixed maximum of
  5443. // 100 packets, regardless of packet size or available memory.
  5444. //
  5445. return (uint)(Info.NumberOfPhysicalPages * (Info.PageSize / 128));
  5446. }
  5447. //* GlobalParametersReset
  5448. //
  5449. // Resets global parameters to their default values.
  5450. // Also used to initialize them at boot.
  5451. //
  5452. void
  5453. GlobalParametersReset(void)
  5454. {
  5455. IPV6_GLOBAL_PARAMETERS Params;
  5456. NTSTATUS Status;
  5457. Params.DefaultCurHopLimit = DEFAULT_CUR_HOP_LIMIT;
  5458. Params.UseAnonymousAddresses = USE_ANON_YES;
  5459. Params.MaxAnonDADAttempts = MAX_ANON_DAD_ATTEMPTS;
  5460. Params.MaxAnonValidLifetime = MAX_ANON_VALID_LIFETIME;
  5461. Params.MaxAnonPreferredLifetime = MAX_ANON_PREFERRED_LIFETIME;
  5462. Params.AnonRegenerateTime = ANON_REGENERATE_TIME;
  5463. Params.MaxAnonRandomTime = MAX_ANON_RANDOM_TIME;
  5464. Params.AnonRandomTime = 0;
  5465. Params.NeighborCacheLimit = NEIGHBOR_CACHE_LIMIT;
  5466. Params.RouteCacheLimit = ROUTE_CACHE_LIMIT;
  5467. Params.BindingCacheLimit = BINDING_CACHE_LIMIT;
  5468. Params.ReassemblyLimit = DefaultReassemblyLimit();
  5469. Params.MobilitySecurity = TRUE;
  5470. Status = InternalUpdateGlobalParameters(&Params);
  5471. ASSERT(NT_SUCCESS(Status));
  5472. }
  5473. //* ConfigureGlobalParameters
  5474. //
  5475. // Configures global parameters from the registry.
  5476. //
  5477. // Callable from thread context, not DPC context.
  5478. //
  5479. void
  5480. ConfigureGlobalParameters(void)
  5481. {
  5482. IPV6_GLOBAL_PARAMETERS Params;
  5483. NTSTATUS Status;
  5484. //
  5485. // First initialize global parameters to default values.
  5486. //
  5487. GlobalParametersReset();
  5488. //
  5489. // Read global parameters from the registry.
  5490. //
  5491. ReadPersistentGlobalParameters(&Params);
  5492. Status = InternalUpdateGlobalParameters(&Params);
  5493. if (! NT_SUCCESS(Status)) {
  5494. //
  5495. // This should only happen if someone played with the registry.
  5496. //
  5497. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_USER_ERROR,
  5498. "ConfigureGlobalParameters: bad params %x\n", Status));
  5499. }
  5500. }
  5501. //* PersistUpdateGlobalParameters
  5502. //
  5503. // Helper function for persisting global parameters in the registry.
  5504. //
  5505. // Callable from thread context, not DPC context.
  5506. //
  5507. NTSTATUS
  5508. PersistUpdateGlobalParameters(IPV6_GLOBAL_PARAMETERS *Params)
  5509. {
  5510. HANDLE RegKey;
  5511. NTSTATUS Status;
  5512. Status = OpenTopLevelRegKey(L"GlobalParams", &RegKey, OpenRegKeyCreate);
  5513. if (! NT_SUCCESS(Status))
  5514. return Status;
  5515. if (Params->DefaultCurHopLimit != (uint)-1) {
  5516. Status = SetRegDWORDValue(RegKey, L"DefaultCurHopLimit",
  5517. Params->DefaultCurHopLimit);
  5518. if (! NT_SUCCESS(Status))
  5519. goto ReturnReleaseKey;
  5520. }
  5521. if (Params->UseAnonymousAddresses != (uint)-1) {
  5522. Status = SetRegDWORDValue(RegKey, L"UseAnonymousAddresses",
  5523. Params->UseAnonymousAddresses);
  5524. if (! NT_SUCCESS(Status))
  5525. goto ReturnReleaseKey;
  5526. }
  5527. if (Params->MaxAnonDADAttempts != (uint)-1) {
  5528. Status = SetRegDWORDValue(RegKey, L"MaxAnonDADAttempts",
  5529. Params->MaxAnonDADAttempts);
  5530. if (! NT_SUCCESS(Status))
  5531. goto ReturnReleaseKey;
  5532. }
  5533. if (Params->MaxAnonValidLifetime != (uint)-1) {
  5534. Status = SetRegDWORDValue(RegKey, L"MaxAnonValidLifetime",
  5535. Params->MaxAnonValidLifetime);
  5536. if (! NT_SUCCESS(Status))
  5537. goto ReturnReleaseKey;
  5538. }
  5539. if (Params->MaxAnonPreferredLifetime != (uint)-1) {
  5540. Status = SetRegDWORDValue(RegKey, L"MaxAnonPreferredLifetime",
  5541. Params->MaxAnonPreferredLifetime);
  5542. if (! NT_SUCCESS(Status))
  5543. goto ReturnReleaseKey;
  5544. }
  5545. if (Params->AnonRegenerateTime != (uint)-1) {
  5546. Status = SetRegDWORDValue(RegKey, L"AnonRegenerateTime",
  5547. Params->AnonRegenerateTime);
  5548. if (! NT_SUCCESS(Status))
  5549. goto ReturnReleaseKey;
  5550. }
  5551. if (Params->MaxAnonRandomTime != (uint)-1) {
  5552. Status = SetRegDWORDValue(RegKey, L"MaxAnonRandomTime",
  5553. Params->MaxAnonRandomTime);
  5554. if (! NT_SUCCESS(Status))
  5555. goto ReturnReleaseKey;
  5556. }
  5557. if (Params->NeighborCacheLimit != (uint)-1) {
  5558. Status = SetRegDWORDValue(RegKey, L"NeighborCacheLimit",
  5559. Params->NeighborCacheLimit);
  5560. if (! NT_SUCCESS(Status))
  5561. goto ReturnReleaseKey;
  5562. }
  5563. if (Params->RouteCacheLimit != (uint)-1) {
  5564. Status = SetRegDWORDValue(RegKey, L"RouteCacheLimit",
  5565. Params->RouteCacheLimit);
  5566. if (! NT_SUCCESS(Status))
  5567. goto ReturnReleaseKey;
  5568. }
  5569. if (Params->BindingCacheLimit != (uint)-1) {
  5570. Status = SetRegDWORDValue(RegKey, L"BindingCacheLimit",
  5571. Params->BindingCacheLimit);
  5572. if (! NT_SUCCESS(Status))
  5573. goto ReturnReleaseKey;
  5574. }
  5575. if (Params->ReassemblyLimit != (uint)-1) {
  5576. Status = SetRegDWORDValue(RegKey, L"ReassemblyLimit",
  5577. Params->ReassemblyLimit);
  5578. if (! NT_SUCCESS(Status))
  5579. goto ReturnReleaseKey;
  5580. }
  5581. if (Params->MobilitySecurity != -1) {
  5582. Status = SetRegDWORDValue(RegKey, L"MobilitySecurity",
  5583. Params->MobilitySecurity);
  5584. if (! NT_SUCCESS(Status))
  5585. goto ReturnReleaseKey;
  5586. }
  5587. Status = STATUS_SUCCESS;
  5588. ReturnReleaseKey:
  5589. ZwClose(RegKey);
  5590. return Status;
  5591. }
  5592. //* IoctlUpdateGlobalParameters
  5593. //
  5594. // Processes an IOCTL_IPV6_UPDATE_GLOBAL_PARAMETERS request.
  5595. //
  5596. // Note: Return value indicates whether NT-specific processing of the
  5597. // request was successful. The status of the actual request is returned
  5598. // in the request buffers.
  5599. //
  5600. NTSTATUS
  5601. IoctlUpdateGlobalParameters(
  5602. IN PIRP Irp, // I/O request packet.
  5603. IN PIO_STACK_LOCATION IrpSp, // Current stack location in the Irp.
  5604. IN int Persistent)
  5605. {
  5606. IPV6_GLOBAL_PARAMETERS *Params;
  5607. NTSTATUS Status;
  5608. PAGED_CODE();
  5609. if ((IrpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof *Params) ||
  5610. (IrpSp->Parameters.DeviceIoControl.OutputBufferLength != 0)) {
  5611. Status = STATUS_INVALID_PARAMETER;
  5612. goto Return;
  5613. }
  5614. Params = (IPV6_GLOBAL_PARAMETERS *)Irp->AssociatedIrp.SystemBuffer;
  5615. Status = InternalUpdateGlobalParameters(Params);
  5616. if (! NT_SUCCESS(Status))
  5617. goto Return;
  5618. if (Persistent) {
  5619. Status = PersistUpdateGlobalParameters(Params);
  5620. if (! NT_SUCCESS(Status))
  5621. goto Return;
  5622. }
  5623. Status = STATUS_SUCCESS;
  5624. Return:
  5625. Irp->IoStatus.Status = Status;
  5626. Irp->IoStatus.Information = 0;
  5627. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  5628. return Status;
  5629. } // IoctlUpdateGlobalParameters.
  5630. //* ReturnQueryPrefixPolicy
  5631. //
  5632. // Initializes a returned IPV6_QUERY_PREFIX_POLICY structure
  5633. // with query information for the specified prefix policy.
  5634. //
  5635. void
  5636. ReturnQueryPrefixPolicy(
  5637. PrefixPolicyEntry *PPE,
  5638. IPV6_QUERY_PREFIX_POLICY *Query)
  5639. {
  5640. if (PPE == NULL) {
  5641. Query->Prefix = UnspecifiedAddr;
  5642. Query->PrefixLength = (uint)-1;
  5643. }
  5644. else {
  5645. Query->Prefix = PPE->Prefix;
  5646. Query->PrefixLength = PPE->PrefixLength;
  5647. }
  5648. }
  5649. //* IoctlQueryPrefixPolicy
  5650. //
  5651. // Processes an IOCTL_IPV6_QUERY_PREFIX_POLICY request.
  5652. //
  5653. // Note: Return value indicates whether NT-specific processing of the
  5654. // request was successful. The status of the actual request is returned
  5655. // in the request buffers.
  5656. //
  5657. NTSTATUS
  5658. IoctlQueryPrefixPolicy(
  5659. IN PIRP Irp, // I/O request packet.
  5660. IN PIO_STACK_LOCATION IrpSp) // Current stack location in the Irp.
  5661. {
  5662. IPV6_QUERY_PREFIX_POLICY *Query;
  5663. IPV6_INFO_PREFIX_POLICY *Info;
  5664. PrefixPolicyEntry *PPE;
  5665. KIRQL OldIrql;
  5666. NTSTATUS Status;
  5667. Irp->IoStatus.Information = 0;
  5668. if ((IrpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof *Query) ||
  5669. (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof *Info)) {
  5670. Status = STATUS_INVALID_PARAMETER;
  5671. goto Return;
  5672. }
  5673. //
  5674. // Note that the Query and Info->Next structures overlap!
  5675. //
  5676. Query = (IPV6_QUERY_PREFIX_POLICY *)Irp->AssociatedIrp.SystemBuffer;
  5677. Info = (IPV6_INFO_PREFIX_POLICY *)Irp->AssociatedIrp.SystemBuffer;
  5678. if (Query->PrefixLength == (uint)-1) {
  5679. //
  5680. // Return query information for the first PPE.
  5681. //
  5682. KeAcquireSpinLock(&SelectLock, &OldIrql);
  5683. ReturnQueryPrefixPolicy(PrefixPolicyTable, &Info->Next);
  5684. KeReleaseSpinLock(&SelectLock, OldIrql);
  5685. Irp->IoStatus.Information = sizeof Info->Next;
  5686. } else {
  5687. //
  5688. // Find the specified PPE.
  5689. //
  5690. KeAcquireSpinLock(&SelectLock, &OldIrql);
  5691. for (PPE = PrefixPolicyTable; ; PPE = PPE->Next) {
  5692. if (PPE == NULL) {
  5693. KeReleaseSpinLock(&SelectLock, OldIrql);
  5694. Status = STATUS_INVALID_PARAMETER_2;
  5695. goto Return;
  5696. }
  5697. if (IP6_ADDR_EQUAL(&Query->Prefix, &PPE->Prefix) &&
  5698. (Query->PrefixLength == PPE->PrefixLength))
  5699. break;
  5700. }
  5701. //
  5702. // Return misc. information about the PPE.
  5703. //
  5704. Info->This = *Query;
  5705. Info->Precedence = PPE->Precedence;
  5706. Info->SrcLabel = PPE->SrcLabel;
  5707. Info->DstLabel = PPE->DstLabel;
  5708. //
  5709. // Return query information for the next PPE.
  5710. //
  5711. ReturnQueryPrefixPolicy(PPE->Next, &Info->Next);
  5712. KeReleaseSpinLock(&SelectLock, OldIrql);
  5713. Irp->IoStatus.Information = sizeof *Info;
  5714. }
  5715. Status = STATUS_SUCCESS;
  5716. Return:
  5717. Irp->IoStatus.Status = Status;
  5718. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  5719. return Status;
  5720. } // IoctlQueryPrefixPolicy
  5721. //* ReadPersistentPrefixPolicy
  5722. //
  5723. // Reads a prefix policy from the registry.
  5724. //
  5725. // Returns:
  5726. // STATUS_NO_MORE_ENTRIES Could not read the prefix policy.
  5727. // STATUS_SUCCESS
  5728. //
  5729. NTSTATUS
  5730. ReadPersistentPrefixPolicy(
  5731. void *Context,
  5732. HANDLE ParentKey,
  5733. WCHAR *SubKeyName)
  5734. {
  5735. IPV6_INFO_PREFIX_POLICY *Info = (IPV6_INFO_PREFIX_POLICY *) Context;
  5736. WCHAR *Terminator;
  5737. HANDLE PolicyKey;
  5738. NTSTATUS Status;
  5739. PAGED_CODE();
  5740. //
  5741. // First, parse the prefix.
  5742. //
  5743. if (! ParseV6Address(SubKeyName, &Terminator, &Info->This.Prefix) ||
  5744. (*Terminator != L'/')) {
  5745. //
  5746. // Not a valid prefix.
  5747. //
  5748. SyntaxError:
  5749. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_USER_ERROR,
  5750. "ReadPersistentPrefixPolicy: bad syntax %ls\n",
  5751. SubKeyName));
  5752. return STATUS_NO_MORE_ENTRIES;
  5753. }
  5754. //
  5755. // Next, parse the prefix length.
  5756. //
  5757. Terminator++; // Move past the L'/'.
  5758. Info->This.PrefixLength = 0;
  5759. for (;;) {
  5760. WCHAR Char = *Terminator++;
  5761. if (Char == UNICODE_NULL)
  5762. break;
  5763. else if ((L'0' <= Char) && (Char <= L'9')) {
  5764. Info->This.PrefixLength *= 10;
  5765. Info->This.PrefixLength += Char - L'0';
  5766. if (Info->This.PrefixLength > IPV6_ADDRESS_LENGTH)
  5767. goto SyntaxError;
  5768. }
  5769. else
  5770. goto SyntaxError;
  5771. }
  5772. //
  5773. // Open the policy key.
  5774. //
  5775. Status = OpenRegKey(&PolicyKey, ParentKey, SubKeyName, OpenRegKeyRead);
  5776. if (! NT_SUCCESS(Status)) {
  5777. //
  5778. // Could not open the policy key.
  5779. //
  5780. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_USER_ERROR,
  5781. "ReadPersistentPrefixPolicy: bad key %ls\n",
  5782. SubKeyName));
  5783. return STATUS_NO_MORE_ENTRIES;
  5784. }
  5785. //
  5786. // Read prefix policy attributes.
  5787. //
  5788. InitRegDWORDParameter(PolicyKey, L"Precedence",
  5789. (ULONG *)&Info->Precedence, 0);
  5790. InitRegDWORDParameter(PolicyKey, L"SrcLabel",
  5791. (ULONG *)&Info->SrcLabel, 0);
  5792. InitRegDWORDParameter(PolicyKey, L"DstLabel",
  5793. (ULONG *)&Info->DstLabel, 0);
  5794. //
  5795. // Done reading the policy attributes.
  5796. //
  5797. ZwClose(PolicyKey);
  5798. return STATUS_SUCCESS;
  5799. }
  5800. //* IoctlPersistentQueryPrefixPolicy
  5801. //
  5802. // Processes an IOCTL_IPV6_PERSISTENT_QUERY_PREFIX_POLICY request.
  5803. //
  5804. // Note: Return value indicates whether NT-specific processing of the
  5805. // request was successful. The status of the actual request is returned
  5806. // in the request buffers.
  5807. //
  5808. NTSTATUS
  5809. IoctlPersistentQueryPrefixPolicy(
  5810. IN PIRP Irp, // I/O request packet.
  5811. IN PIO_STACK_LOCATION IrpSp) // Current stack location in the Irp.
  5812. {
  5813. IPV6_PERSISTENT_QUERY_PREFIX_POLICY *Query;
  5814. IPV6_INFO_PREFIX_POLICY *Info;
  5815. HANDLE RegKey;
  5816. NTSTATUS Status;
  5817. PAGED_CODE();
  5818. Irp->IoStatus.Information = 0;
  5819. if ((IrpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof *Query) ||
  5820. (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof *Info)) {
  5821. Status = STATUS_INVALID_PARAMETER;
  5822. goto Return;
  5823. }
  5824. //
  5825. // Note that the Query and Info->Next structures overlap!
  5826. //
  5827. Query = (IPV6_PERSISTENT_QUERY_PREFIX_POLICY *)
  5828. Irp->AssociatedIrp.SystemBuffer;
  5829. Info = (IPV6_INFO_PREFIX_POLICY *)
  5830. Irp->AssociatedIrp.SystemBuffer;
  5831. Status = OpenTopLevelRegKey(L"PrefixPolicies", &RegKey, OpenRegKeyRead);
  5832. if (! NT_SUCCESS(Status)) {
  5833. if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
  5834. Status = STATUS_NO_MORE_ENTRIES;
  5835. goto Return;
  5836. }
  5837. Status = EnumRegKeyIndex(RegKey, Query->RegistryIndex,
  5838. ReadPersistentPrefixPolicy, Info);
  5839. ZwClose(RegKey);
  5840. if (! NT_SUCCESS(Status))
  5841. goto Return;
  5842. //
  5843. // Do not return query information for a next policy,
  5844. // since an iteration uses RegistryIndex.
  5845. //
  5846. ReturnQueryPrefixPolicy(NULL, &Info->Next);
  5847. Status = STATUS_SUCCESS;
  5848. Irp->IoStatus.Information = sizeof *Info;
  5849. Return:
  5850. Irp->IoStatus.Status = Status;
  5851. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  5852. return Status;
  5853. } // IoctlPersistentQueryPrefixPolicy
  5854. struct PrefixPolicyDefault {
  5855. IPv6Addr *Prefix;
  5856. uint PrefixLength;
  5857. uint Precedence;
  5858. uint SrcLabel;
  5859. uint DstLabel;
  5860. } PrefixPolicyDefault[] = {
  5861. { &LoopbackAddr, 128, 50, 0, 0 }, // ::1/128 (loopback)
  5862. { &UnspecifiedAddr, 0, 40, 1, 1 }, // ::/0
  5863. { &SixToFourPrefix, 16, 30, 2, 2 }, // 2002::/16 (6to4)
  5864. { &UnspecifiedAddr, 96, 20, 3, 3 }, // ::/96 (v4-compatible)
  5865. { &V4MappedPrefix, 96, 10, 4, 4 }, // ::ffff:0.0.0.0/96 (v4-mapped)
  5866. };
  5867. int UsingDefaultPrefixPolicies;
  5868. #define NUM_DEFAULT_PREFIX_POLICIES \
  5869. (sizeof PrefixPolicyDefault / sizeof PrefixPolicyDefault[0])
  5870. //* ConfigureDefaultPrefixPolicies
  5871. //
  5872. // Installs the default prefix policies.
  5873. //
  5874. void
  5875. ConfigureDefaultPrefixPolicies(void)
  5876. {
  5877. uint i;
  5878. for (i = 0; i < NUM_DEFAULT_PREFIX_POLICIES; i++) {
  5879. struct PrefixPolicyDefault *Policy = &PrefixPolicyDefault[i];
  5880. PrefixPolicyUpdate(Policy->Prefix,
  5881. Policy->PrefixLength,
  5882. Policy->Precedence,
  5883. Policy->SrcLabel,
  5884. Policy->DstLabel);
  5885. }
  5886. UsingDefaultPrefixPolicies = TRUE;
  5887. }
  5888. //* InternalUpdatePrefixPolicy
  5889. //
  5890. // Common helper function for IoctlUpdatePrefixPolicy
  5891. // and CreatePersistentPrefixPolicy, consolidating
  5892. // parameter validation in one place.
  5893. //
  5894. // Callable from thread context, not DPC context.
  5895. //
  5896. // Return codes:
  5897. // STATUS_INVALID_PARAMETER_1 Bad PrefixLength.
  5898. // STATUS_INVALID_PARAMETER_2 Bad Precedence.
  5899. // STATUS_INVALID_PARAMETER_3 Bad SrcLabel.
  5900. // STATUS_INVALID_PARAMETER_4 Bad DstLabel.
  5901. //
  5902. NTSTATUS
  5903. InternalUpdatePrefixPolicy(IPV6_INFO_PREFIX_POLICY *Info)
  5904. {
  5905. if (Info->This.PrefixLength > IPV6_ADDRESS_LENGTH)
  5906. return STATUS_INVALID_PARAMETER_1;
  5907. //
  5908. // Disallow the value -1. It's used internally.
  5909. //
  5910. if (Info->Precedence == (uint)-1)
  5911. return STATUS_INVALID_PARAMETER_2;
  5912. if (Info->SrcLabel == (uint)-1)
  5913. return STATUS_INVALID_PARAMETER_3;
  5914. if (Info->DstLabel == (uint)-1)
  5915. return STATUS_INVALID_PARAMETER_4;
  5916. if (UsingDefaultPrefixPolicies) {
  5917. //
  5918. // The user is changing the default policies for the first time.
  5919. // Remove the default policies.
  5920. //
  5921. UsingDefaultPrefixPolicies = FALSE;
  5922. PrefixPolicyReset();
  5923. }
  5924. //
  5925. // Create/update the specified prefix policy.
  5926. //
  5927. PrefixPolicyUpdate(&Info->This.Prefix,
  5928. Info->This.PrefixLength,
  5929. Info->Precedence,
  5930. Info->SrcLabel,
  5931. Info->DstLabel);
  5932. return STATUS_SUCCESS;
  5933. }
  5934. //* CreatePersistentPrefixPolicy
  5935. //
  5936. // Creates a persistent prefix policy.
  5937. //
  5938. // SubKeyName has the following syntax:
  5939. // prefix/length
  5940. // where prefix is a literal IPv6 address.
  5941. //
  5942. // Callable from thread context, not DPC context.
  5943. //
  5944. NTSTATUS
  5945. CreatePersistentPrefixPolicy(
  5946. void *Context,
  5947. HANDLE ParentKey,
  5948. WCHAR *SubKeyName)
  5949. {
  5950. IPV6_INFO_PREFIX_POLICY Info;
  5951. NTSTATUS Status;
  5952. UNREFERENCED_PARAMETER(Context);
  5953. PAGED_CODE();
  5954. //
  5955. // Read the prefix policy from the registry.
  5956. //
  5957. Status = ReadPersistentPrefixPolicy(&Info, ParentKey, SubKeyName);
  5958. if (! NT_SUCCESS(Status)) {
  5959. //
  5960. // If there was an error reading this policy,
  5961. // continue the enumeration.
  5962. //
  5963. if (Status == STATUS_NO_MORE_ENTRIES)
  5964. Status = STATUS_SUCCESS;
  5965. return Status;
  5966. }
  5967. //
  5968. // Create the prefix policy.
  5969. //
  5970. Status = InternalUpdatePrefixPolicy(&Info);
  5971. if (! NT_SUCCESS(Status)) {
  5972. if ((STATUS_INVALID_PARAMETER_1 <= Status) &&
  5973. (Status <= STATUS_INVALID_PARAMETER_12)) {
  5974. //
  5975. // Invalid parameter.
  5976. // But we return success so the enumeration continues.
  5977. //
  5978. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_USER_ERROR,
  5979. "CreatePersistentPrefixPolicy: bad param %ls\n",
  5980. SubKeyName));
  5981. return STATUS_SUCCESS;
  5982. }
  5983. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INTERNAL_ERROR,
  5984. "CreatePersistentPrefixPolicy: error %ls\n",
  5985. SubKeyName));
  5986. }
  5987. return Status;
  5988. }
  5989. //* ConfigurePrefixPolicies
  5990. //
  5991. // Configures prefix policies from the registry.
  5992. //
  5993. // Callable from thread context, not DPC context.
  5994. //
  5995. void
  5996. ConfigurePrefixPolicies(void)
  5997. {
  5998. HANDLE RegKey;
  5999. NTSTATUS Status;
  6000. Status = OpenTopLevelRegKey(L"PrefixPolicies", &RegKey, OpenRegKeyRead);
  6001. if (NT_SUCCESS(Status)) {
  6002. //
  6003. // Create persistent policies.
  6004. //
  6005. (void) EnumRegKeys(RegKey, CreatePersistentPrefixPolicy, NULL);
  6006. ZwClose(RegKey);
  6007. }
  6008. else {
  6009. //
  6010. // There are no persistent policies,
  6011. // so install the default policies.
  6012. //
  6013. ConfigureDefaultPrefixPolicies();
  6014. }
  6015. }
  6016. //* OpenPrefixPolicyRegKey
  6017. //
  6018. // Given a prefix with prefix length,
  6019. // opens the registry key with configuration info
  6020. // for the prefix policy.
  6021. //
  6022. // Callable from thread context, not DPC context.
  6023. //
  6024. NTSTATUS
  6025. OpenPrefixPolicyRegKey(const IPv6Addr *Prefix, uint PrefixLength,
  6026. OUT HANDLE *RegKey, OpenRegKeyAction Action)
  6027. {
  6028. WCHAR PrefixPolicyName[64];
  6029. HANDLE PrefixPoliciesKey;
  6030. NTSTATUS Status;
  6031. PAGED_CODE();
  6032. //
  6033. // Note that if we are deleting a prefix policy,
  6034. // then we must create the top-level key if it
  6035. // doesn't exist yet. This is for ConfigurePrefixPolicies.
  6036. //
  6037. Status = OpenTopLevelRegKey(L"PrefixPolicies", &PrefixPoliciesKey,
  6038. ((Action != OpenRegKeyRead) ?
  6039. OpenRegKeyCreate : OpenRegKeyRead));
  6040. if (! NT_SUCCESS(Status))
  6041. return Status;
  6042. //
  6043. // The output of RtlIpv6AddressToString may change
  6044. // over time with improvements/changes in the pretty-printing,
  6045. // and we need a consistent mapping.
  6046. // It doesn't need to be pretty.
  6047. //
  6048. swprintf(PrefixPolicyName,
  6049. L"%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x/%u",
  6050. net_short(Prefix->s6_words[0]), net_short(Prefix->s6_words[1]),
  6051. net_short(Prefix->s6_words[2]), net_short(Prefix->s6_words[3]),
  6052. net_short(Prefix->s6_words[4]), net_short(Prefix->s6_words[5]),
  6053. net_short(Prefix->s6_words[6]), net_short(Prefix->s6_words[7]),
  6054. PrefixLength);
  6055. Status = OpenRegKey(RegKey, PrefixPoliciesKey, PrefixPolicyName, Action);
  6056. ZwClose(PrefixPoliciesKey);
  6057. return Status;
  6058. }
  6059. //* PersistUpdatePrefixPolicy
  6060. //
  6061. // Helper function for persisting a prefix policy in the registry.
  6062. //
  6063. // Callable from thread context, not DPC context.
  6064. //
  6065. NTSTATUS
  6066. PersistUpdatePrefixPolicy(IPV6_INFO_PREFIX_POLICY *Info)
  6067. {
  6068. HANDLE PolicyKey;
  6069. NTSTATUS Status;
  6070. PAGED_CODE();
  6071. //
  6072. // Open/create the policy key.
  6073. //
  6074. Status = OpenPrefixPolicyRegKey(&Info->This.Prefix,
  6075. Info->This.PrefixLength,
  6076. &PolicyKey, OpenRegKeyCreate);
  6077. if (! NT_SUCCESS(Status))
  6078. return Status;
  6079. //
  6080. // Persist the prefix policy precedence.
  6081. //
  6082. Status = SetRegDWORDValue(PolicyKey, L"Precedence", Info->Precedence);
  6083. if (! NT_SUCCESS(Status))
  6084. goto ReturnReleasePolicyKey;
  6085. //
  6086. // Persist the prefix policy source label.
  6087. //
  6088. Status = SetRegDWORDValue(PolicyKey, L"SrcLabel", Info->SrcLabel);
  6089. if (! NT_SUCCESS(Status))
  6090. goto ReturnReleasePolicyKey;
  6091. //
  6092. // Persist the prefix policy destination label.
  6093. //
  6094. Status = SetRegDWORDValue(PolicyKey, L"DstLabel", Info->DstLabel);
  6095. if (! NT_SUCCESS(Status))
  6096. goto ReturnReleasePolicyKey;
  6097. Status = STATUS_SUCCESS;
  6098. ReturnReleasePolicyKey:
  6099. ZwClose(PolicyKey);
  6100. return Status;
  6101. }
  6102. //* IoctlUpdatePrefixPolicy
  6103. //
  6104. // Processes an IOCTL_IPV6_UPDATE_PREFIX_POLICY request.
  6105. //
  6106. // Note: Return value indicates whether NT-specific processing of the
  6107. // request was successful. The status of the actual request is returned
  6108. // in the request buffers.
  6109. //
  6110. NTSTATUS
  6111. IoctlUpdatePrefixPolicy(
  6112. IN PIRP Irp, // I/O request packet.
  6113. IN PIO_STACK_LOCATION IrpSp, // Current stack location in the Irp.
  6114. IN int Persistent)
  6115. {
  6116. IPV6_INFO_PREFIX_POLICY *Info;
  6117. NTSTATUS Status;
  6118. PAGED_CODE();
  6119. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof *Info) {
  6120. Status = STATUS_INVALID_PARAMETER;
  6121. goto Return;
  6122. }
  6123. Info = (IPV6_INFO_PREFIX_POLICY *) Irp->AssociatedIrp.SystemBuffer;
  6124. //
  6125. // Update the prefix policy.
  6126. //
  6127. Status = InternalUpdatePrefixPolicy(Info);
  6128. if (! NT_SUCCESS(Status))
  6129. goto Return;
  6130. //
  6131. // Make the change persistent?
  6132. //
  6133. if (Persistent) {
  6134. Status = PersistUpdatePrefixPolicy(Info);
  6135. if (! NT_SUCCESS(Status))
  6136. goto Return;
  6137. }
  6138. Status = STATUS_SUCCESS;
  6139. Return:
  6140. Irp->IoStatus.Status = Status;
  6141. Irp->IoStatus.Information = 0;
  6142. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  6143. return Status;
  6144. } // IoctlUpdatePrefixPolicy
  6145. //* PersistDeletePrefixPolicy
  6146. //
  6147. // Helper function for deleting a prefix policy from the registry.
  6148. //
  6149. // Callable from thread context, not DPC context.
  6150. //
  6151. NTSTATUS
  6152. PersistDeletePrefixPolicy(IPV6_QUERY_PREFIX_POLICY *Query)
  6153. {
  6154. HANDLE PolicyKey;
  6155. NTSTATUS Status;
  6156. PAGED_CODE();
  6157. //
  6158. // Open the policy key. It's OK if it doesn't exist.
  6159. //
  6160. Status = OpenPrefixPolicyRegKey(&Query->Prefix, Query->PrefixLength,
  6161. &PolicyKey, OpenRegKeyDeleting);
  6162. if (! NT_SUCCESS(Status)) {
  6163. if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
  6164. return STATUS_SUCCESS;
  6165. else
  6166. return Status;
  6167. }
  6168. //
  6169. // Delete the policy key.
  6170. //
  6171. Status = ZwDeleteKey(PolicyKey);
  6172. ZwClose(PolicyKey);
  6173. return Status;
  6174. }
  6175. //* IoctlDeletePrefixPolicy
  6176. //
  6177. // Processes an IOCTL_IPV6_DELETE_PREFIX_POLICY request.
  6178. //
  6179. // Note: Return value indicates whether NT-specific processing of the
  6180. // request was successful. The status of the actual request is returned
  6181. // in the request buffers.
  6182. //
  6183. NTSTATUS
  6184. IoctlDeletePrefixPolicy(
  6185. IN PIRP Irp, // I/O request packet.
  6186. IN PIO_STACK_LOCATION IrpSp, // Current stack location in the Irp.
  6187. IN int Persistent)
  6188. {
  6189. IPV6_QUERY_PREFIX_POLICY *Query;
  6190. NTSTATUS Status;
  6191. PAGED_CODE();
  6192. Irp->IoStatus.Information = 0;
  6193. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof *Query) {
  6194. Status = STATUS_INVALID_PARAMETER;
  6195. goto Return;
  6196. }
  6197. Query = (IPV6_QUERY_PREFIX_POLICY *) Irp->AssociatedIrp.SystemBuffer;
  6198. if (UsingDefaultPrefixPolicies) {
  6199. //
  6200. // The user is changing the default policies for the first time.
  6201. // Remove the default policies.
  6202. //
  6203. UsingDefaultPrefixPolicies = FALSE;
  6204. PrefixPolicyReset();
  6205. }
  6206. //
  6207. // Delete the specified prefix policy.
  6208. //
  6209. PrefixPolicyDelete(&Query->Prefix, Query->PrefixLength);
  6210. //
  6211. // Make the change persistent?
  6212. //
  6213. if (Persistent) {
  6214. Status = PersistDeletePrefixPolicy(Query);
  6215. if (! NT_SUCCESS(Status))
  6216. goto Return;
  6217. }
  6218. Status = STATUS_SUCCESS;
  6219. Return:
  6220. Irp->IoStatus.Status = Status;
  6221. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  6222. return Status;
  6223. } // IoctlDeletePrefixPolicy
  6224. //* IoctlUpdateRouterLLAddress
  6225. //
  6226. // Processes an IOCTL_IPV6_UPDATE_ROUTER_LL_ADDRESS request.
  6227. //
  6228. // Note: Return value indicates whether NT-specific processing of the
  6229. // request was successful. The status of the actual request is returned
  6230. // in the request buffers.
  6231. //
  6232. NTSTATUS
  6233. IoctlUpdateRouterLLAddress(
  6234. IN PIRP Irp, // I/O request packet.
  6235. IN PIO_STACK_LOCATION IrpSp) // Current stack location in the Irp.
  6236. {
  6237. IPV6_UPDATE_ROUTER_LL_ADDRESS *Info;
  6238. NTSTATUS Status;
  6239. Interface *IF;
  6240. char *LinkAddress;
  6241. KIRQL OldIrql;
  6242. PAGED_CODE();
  6243. if ((IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof *Info) ||
  6244. (IrpSp->Parameters.DeviceIoControl.OutputBufferLength != 0)) {
  6245. Status = STATUS_INVALID_PARAMETER;
  6246. goto Return;
  6247. }
  6248. Info = (IPV6_UPDATE_ROUTER_LL_ADDRESS *) Irp->AssociatedIrp.SystemBuffer;
  6249. IF = FindInterfaceFromQuery(&Info->IF);
  6250. if (IF == NULL) {
  6251. Status = STATUS_INVALID_PARAMETER_1;
  6252. goto Return;
  6253. }
  6254. //
  6255. // Verify that this ioctl is legal on the interface.
  6256. //
  6257. if (IF->SetRouterLLAddress == NULL) {
  6258. Status = STATUS_INVALID_PARAMETER_1;
  6259. goto Cleanup;
  6260. }
  6261. //
  6262. // Verify link-layer address length matches interface's.
  6263. //
  6264. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength !=
  6265. sizeof *Info + 2 * IF->LinkAddressLength) {
  6266. Status = STATUS_INVALID_PARAMETER;
  6267. goto Cleanup;
  6268. }
  6269. LinkAddress = (char *)(Info + 1);
  6270. Status = (*IF->SetRouterLLAddress)(IF->LinkContext, LinkAddress,
  6271. LinkAddress + IF->LinkAddressLength);
  6272. Cleanup:
  6273. ReleaseIF(IF);
  6274. Return:
  6275. Irp->IoStatus.Status = Status;
  6276. Irp->IoStatus.Information = 0;
  6277. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  6278. return Status;
  6279. } // IoctlUpdateRouterLLAddress
  6280. //* IoctlResetManualConfig
  6281. //
  6282. // Processes an IOCTL_IPV6_RESET request.
  6283. //
  6284. // Note: Return value indicates whether NT-specific processing of the
  6285. // request was successful. The status of the actual request is returned
  6286. // in the request buffers.
  6287. //
  6288. NTSTATUS
  6289. IoctlResetManualConfig(
  6290. IN PIRP Irp, // I/O request packet.
  6291. IN PIO_STACK_LOCATION IrpSp, // Current stack location in the Irp.
  6292. IN int Persistent)
  6293. {
  6294. HANDLE RegKey;
  6295. NTSTATUS Status;
  6296. PAGED_CODE();
  6297. if ((IrpSp->Parameters.DeviceIoControl.InputBufferLength != 0) ||
  6298. (IrpSp->Parameters.DeviceIoControl.OutputBufferLength != 0)) {
  6299. Status = STATUS_INVALID_PARAMETER;
  6300. goto Return;
  6301. }
  6302. //
  6303. // Reset the running data structures.
  6304. //
  6305. GlobalParametersReset();
  6306. InterfaceReset();
  6307. RouteTableReset();
  6308. PrefixPolicyReset();
  6309. ConfigureDefaultPrefixPolicies();
  6310. if (Persistent) {
  6311. //
  6312. // Delete all persistent configuration information.
  6313. //
  6314. Status = DeleteTopLevelRegKey(L"GlobalParams");
  6315. if (! NT_SUCCESS(Status))
  6316. goto Return;
  6317. Status = DeleteTopLevelRegKey(L"Interfaces");
  6318. if (! NT_SUCCESS(Status))
  6319. goto Return;
  6320. Status = DeleteTopLevelRegKey(L"PrefixPolicies");
  6321. if (! NT_SUCCESS(Status))
  6322. goto Return;
  6323. }
  6324. Status = STATUS_SUCCESS;
  6325. Return:
  6326. Irp->IoStatus.Status = Status;
  6327. Irp->IoStatus.Information = 0;
  6328. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  6329. return Status;
  6330. } // IoctlPersistentReset