Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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