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.

887 lines
19 KiB

  1. /*++
  2. Copyright (c) 2001-2002 Microsoft Corporation
  3. Module Name:
  4. common.c
  5. Abstract:
  6. This module contains the teredo interface to the IPv6 Helper Service.
  7. Author:
  8. Mohit Talwar (mohitt) Wed Nov 07 11:27:01 2001
  9. Environment:
  10. User mode only.
  11. --*/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. CONST IN6_ADDR TeredoIpv6ServicePrefix = TEREDO_SERVICE_PREFIX;
  15. CONST IN6_ADDR TeredoIpv6MulticastPrefix = TEREDO_MULTICAST_PREFIX;
  16. LPGUID TeredoWmiEvent[] = {
  17. (LPGUID) &GUID_NDIS_NOTIFY_ADAPTER_ARRIVAL,
  18. (LPGUID) &GUID_NDIS_NOTIFY_ADAPTER_REMOVAL,
  19. (LPGUID) &GUID_NDIS_NOTIFY_DEVICE_POWER_ON,
  20. (LPGUID) &GUID_NDIS_NOTIFY_DEVICE_POWER_OFF,
  21. };
  22. HANDLE TeredoTimer; // Periodic timer started for the service.
  23. HANDLE TeredoTimerEvent; // Event signalled upon Timer deletion.
  24. HANDLE TeredoTimerEventWait; // Wait registered for TimerEvent.
  25. ULONG TeredoResolveInterval = TEREDO_RESOLVE_INTERVAL;
  26. ULONG TeredoClientRefreshInterval = TEREDO_REFRESH_INTERVAL;
  27. TEREDO_TYPE TeredoType = TEREDO_DEFAULT_TYPE;
  28. WCHAR TeredoServerName[NI_MAXHOST] = TEREDO_SERVER_NAME;
  29. BOOL TeredoClientEnabled = (TEREDO_DEFAULT_TYPE == TEREDO_CLIENT);
  30. BOOL TeredoServerEnabled = (TEREDO_DEFAULT_TYPE == TEREDO_SERVER);
  31. BOOL TeredoRequired = TRUE;
  32. BOOL TeredoInitialized = FALSE;
  33. ICMPv6Header *
  34. TeredoParseIpv6Headers (
  35. IN PUCHAR Buffer,
  36. IN ULONG Bytes
  37. )
  38. {
  39. UCHAR NextHeader = IP_PROTOCOL_V6;
  40. ULONG Length;
  41. //
  42. // Parse up until the ICMPv6 header.
  43. //
  44. for (;;) {
  45. switch (NextHeader) {
  46. case IP_PROTOCOL_V6:
  47. if (Bytes < sizeof(IP6_HDR)) {
  48. return NULL;
  49. }
  50. NextHeader = ((PIP6_HDR) Buffer)->ip6_nxt;
  51. Length = sizeof(IP6_HDR);
  52. break;
  53. case IP_PROTOCOL_HOP_BY_HOP:
  54. case IP_PROTOCOL_DEST_OPTS:
  55. case IP_PROTOCOL_ROUTING:
  56. if (Bytes < sizeof(ExtensionHeader)) {
  57. return NULL;
  58. }
  59. NextHeader = ((ExtensionHeader *) Buffer)->NextHeader;
  60. Length = ((ExtensionHeader *) Buffer)->HeaderExtLength * 8 + 8;
  61. break;
  62. case IP_PROTOCOL_FRAGMENT:
  63. if (Bytes < sizeof(FragmentHeader)) {
  64. return NULL;
  65. }
  66. NextHeader = ((FragmentHeader *) Buffer)->NextHeader;
  67. Length = sizeof(FragmentHeader);
  68. break;
  69. case IP_PROTOCOL_AH:
  70. if (Bytes < sizeof(AHHeader)) {
  71. return NULL;
  72. }
  73. NextHeader = ((AHHeader *) Buffer)->NextHeader;
  74. Length = sizeof(AHHeader) +
  75. ((AHHeader *) Buffer)->PayloadLen * 4 + 8;
  76. break;
  77. case IP_PROTOCOL_ICMPv6:
  78. if (Bytes < sizeof(ICMPv6Header)) {
  79. return NULL;
  80. }
  81. return (ICMPv6Header *) Buffer;
  82. default:
  83. return NULL;
  84. }
  85. if (Bytes < Length) {
  86. return NULL;
  87. }
  88. Buffer += Length;
  89. Bytes -= Length;
  90. }
  91. }
  92. BOOL
  93. TeredoInterface(
  94. IN PWCHAR Guid
  95. )
  96. /*++
  97. Routine Description:
  98. Determine whether an interface is the Teredo Tunnel.
  99. Arguments:
  100. Guid - Supplies the interface GUID.
  101. Return Value:
  102. True if Teredo Tunnel, False o/w.
  103. Caller LOCK: API.
  104. --*/
  105. {
  106. PTEREDO_IO Io = NULL;
  107. if (TeredoClient.State != TEREDO_STATE_OFFLINE) {
  108. Io = &(TeredoClient.Io);
  109. }
  110. if (TeredoServer.State != TEREDO_STATE_OFFLINE) {
  111. Io = &(TeredoServer.Io);
  112. }
  113. if ((Io != NULL) && (_wcsicmp(Io->TunnelInterface, Guid) == 0)) {
  114. return TRUE;
  115. }
  116. return FALSE;
  117. }
  118. __inline
  119. VOID
  120. TeredoStart(
  121. VOID
  122. )
  123. {
  124. //
  125. // Both client and server should not be enabled on the same node.
  126. //
  127. ASSERT(!TeredoClientEnabled || !TeredoServerEnabled);
  128. if (TeredoClientEnabled) {
  129. //
  130. // The service might already be running, but that's alright.
  131. //
  132. TeredoStartClient();
  133. }
  134. if (TeredoServerEnabled) {
  135. //
  136. // The service might already be running, but that's alright.
  137. //
  138. TeredoStartServer();
  139. }
  140. }
  141. __inline
  142. VOID
  143. TeredoStop(
  144. VOID
  145. )
  146. {
  147. //
  148. // Both client and server should not be enabled on the same node.
  149. //
  150. ASSERT(!TeredoClientEnabled || !TeredoServerEnabled);
  151. if (TeredoClientEnabled) {
  152. //
  153. // The service might not be running, but that's all right.
  154. //
  155. TeredoStopClient();
  156. }
  157. if (TeredoServerEnabled) {
  158. //
  159. // The service might not be running, but that's all right.
  160. //
  161. TeredoStopServer();
  162. }
  163. }
  164. DWORD
  165. __inline
  166. TeredoEnableWmiEvent(
  167. IN LPGUID EventGuid,
  168. IN BOOLEAN Enable
  169. )
  170. {
  171. return WmiNotificationRegistrationW(
  172. EventGuid, // Event Type.
  173. Enable, // Enable or Disable.
  174. TeredoWmiEventNotification, // Callback.
  175. 0, // Context.
  176. NOTIFICATION_CALLBACK_DIRECT); // Notification Flags.
  177. }
  178. VOID
  179. __inline
  180. TeredoDeregisterWmiEventNotification(
  181. VOID
  182. )
  183. {
  184. int i;
  185. for (i = 0; i < (sizeof(TeredoWmiEvent) / sizeof(LPGUID)); i++) {
  186. (VOID) TeredoEnableWmiEvent(TeredoWmiEvent[i], FALSE);
  187. }
  188. }
  189. DWORD
  190. __inline
  191. TeredoRegisterWmiEventNotification(
  192. VOID
  193. )
  194. {
  195. DWORD Error;
  196. int i;
  197. for (i = 0; i < (sizeof(TeredoWmiEvent) / sizeof(LPGUID)); i++) {
  198. Error = TeredoEnableWmiEvent(TeredoWmiEvent[i], TRUE);
  199. if (Error != NO_ERROR) {
  200. Trace2(ANY, L"TeredoEnableWmiEvent(%u): Error(%x)", i, Error);
  201. goto Bail;
  202. }
  203. }
  204. return NO_ERROR;
  205. Bail:
  206. TeredoDeregisterWmiEventNotification();
  207. return Error;
  208. }
  209. VOID
  210. CALLBACK
  211. TeredoTimerCallback(
  212. IN PVOID Parameter,
  213. IN BOOLEAN TimerOrWaitFired
  214. )
  215. /*++
  216. Routine Description:
  217. Callback routine for TeredoTimer expiration.
  218. The timer is always active.
  219. Arguments:
  220. Parameter, TimerOrWaitFired - Ignored.
  221. Return Value:
  222. None.
  223. --*/
  224. {
  225. ENTER_API();
  226. TeredoStart();
  227. LEAVE_API();
  228. }
  229. VOID
  230. CALLBACK
  231. TeredoTimerCleanup(
  232. IN PVOID Parameter,
  233. IN BOOLEAN TimerOrWaitFired
  234. )
  235. /*++
  236. Routine Description:
  237. Callback routine for TeredoTimer deletion.
  238. Deletion is performed asynchronously since we acquire a lock in
  239. the callback function that we hold when deleting the timer.
  240. Arguments:
  241. Parameter, TimerOrWaitFired - Ignored.
  242. Return Value:
  243. None.
  244. --*/
  245. {
  246. UnregisterWait(TeredoTimerEventWait);
  247. CloseHandle(TeredoTimerEvent);
  248. DecEventCount("TeredoCleanupTimer");
  249. }
  250. DWORD
  251. TeredoInitializeTimer(
  252. VOID
  253. )
  254. /*++
  255. Routine Description:
  256. Initializes the timer.
  257. Arguments:
  258. None.
  259. Return Value:
  260. NO_ERROR or failure code.
  261. --*/
  262. {
  263. DWORD Error;
  264. ULONG ResolveInterval;
  265. TeredoTimerEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  266. if (TeredoTimerEvent == NULL) {
  267. Error = GetLastError();
  268. return Error;
  269. }
  270. if (!RegisterWaitForSingleObject(
  271. &(TeredoTimerEventWait),
  272. TeredoTimerEvent,
  273. TeredoTimerCleanup,
  274. NULL,
  275. INFINITE,
  276. 0)) {
  277. Error = GetLastError();
  278. CloseHandle(TeredoTimerEvent);
  279. return Error;
  280. }
  281. //
  282. // If the service is enabled, we attempt to start it every
  283. // TeredoResolveInterval seconds. Else we disable its timer.
  284. //
  285. ResolveInterval = (TeredoClientEnabled || TeredoServerEnabled)
  286. ? (TeredoResolveInterval * 1000)
  287. : INFINITE_INTERVAL;
  288. if (!CreateTimerQueueTimer(
  289. &(TeredoTimer),
  290. NULL,
  291. TeredoTimerCallback,
  292. NULL,
  293. ResolveInterval,
  294. ResolveInterval,
  295. 0)) {
  296. Error = GetLastError();
  297. UnregisterWait(TeredoTimerEventWait);
  298. CloseHandle(TeredoTimerEvent);
  299. return Error;
  300. }
  301. IncEventCount("TeredoInitializeTimer");
  302. return NO_ERROR;
  303. }
  304. VOID
  305. TeredoUninitializeTimer(
  306. VOID
  307. )
  308. /*++
  309. Routine Description:
  310. Uninitializes the timer. Typically invoked upon service stop.
  311. Arguments:
  312. None.
  313. Return Value:
  314. None.
  315. --*/
  316. {
  317. DeleteTimerQueueTimer(NULL, TeredoTimer, TeredoTimerEvent);
  318. TeredoTimer = NULL;
  319. }
  320. DWORD
  321. TeredoInitializeGlobals(
  322. VOID
  323. )
  324. /*++
  325. Routine Description:
  326. Initializes the teredo client and server and attempts to start them.
  327. Arguments:
  328. None.
  329. Return Value:
  330. NO_ERROR or failure code.
  331. --*/
  332. {
  333. DWORD Error;
  334. BOOL ClientInitialized = FALSE;
  335. BOOL ServerInitialized = FALSE;
  336. BOOL TimerInitialized = FALSE;
  337. Error = TeredoInitializeClient();
  338. if (Error != NO_ERROR) {
  339. goto Bail;
  340. }
  341. ClientInitialized = TRUE;
  342. Error = TeredoInitializeServer();
  343. if (Error != NO_ERROR) {
  344. goto Bail;
  345. }
  346. ServerInitialized = TRUE;
  347. Error = TeredoInitializeTimer();
  348. if (Error != NO_ERROR) {
  349. goto Bail;
  350. }
  351. TimerInitialized = TRUE;
  352. Error = TeredoRegisterWmiEventNotification();
  353. if (Error != NO_ERROR) {
  354. goto Bail;
  355. }
  356. TeredoStart();
  357. TeredoInitialized = TRUE;
  358. return NO_ERROR;
  359. Bail:
  360. //
  361. // This can always be safely invoked!
  362. //
  363. TeredoDeregisterWmiEventNotification();
  364. if (TimerInitialized) {
  365. TeredoUninitializeTimer();
  366. }
  367. if (ServerInitialized) {
  368. TeredoUninitializeServer();
  369. }
  370. if (ClientInitialized) {
  371. TeredoUninitializeClient();
  372. }
  373. return Error;
  374. }
  375. VOID
  376. TeredoUninitializeGlobals(
  377. VOID
  378. )
  379. /*++
  380. Routine Description:
  381. Uninitializes the teredo client and server.
  382. Arguments:
  383. None.
  384. Return Value:
  385. None.
  386. --*/
  387. {
  388. if (!TeredoInitialized) {
  389. return;
  390. }
  391. TeredoDeregisterWmiEventNotification();
  392. TeredoUninitializeTimer();
  393. TeredoUninitializeServer();
  394. TeredoUninitializeClient();
  395. TeredoInitialized = FALSE;
  396. }
  397. VOID
  398. TeredoAddressChangeNotification(
  399. IN BOOL Delete,
  400. IN IN_ADDR Address
  401. )
  402. /*++
  403. Routine Description:
  404. Process an address deletion or addition request.
  405. Arguments:
  406. Delete - Supplies a boolean. TRUE if the address was deleted, FALSE o/w.
  407. Address - Supplies the IPv4 address that was deleted or added.
  408. Return Value:
  409. None.
  410. Caller LOCK: API.
  411. --*/
  412. {
  413. if (Delete) {
  414. //
  415. // Both client and server should not be running on the same node.
  416. //
  417. ASSERT((TeredoClient.State == TEREDO_STATE_OFFLINE) ||
  418. (TeredoServer.State == TEREDO_STATE_OFFLINE));
  419. if (TeredoClient.State != TEREDO_STATE_OFFLINE) {
  420. TeredoClientAddressDeletionNotification(Address);
  421. }
  422. if (TeredoServer.State != TEREDO_STATE_OFFLINE) {
  423. TeredoServerAddressDeletionNotification(Address);
  424. }
  425. return;
  426. }
  427. //
  428. // Address addition.
  429. // Attempt to start the service (if it is not already running).
  430. //
  431. TeredoStart();
  432. }
  433. VOID
  434. TeredoRouteChangeNotification(
  435. VOID
  436. )
  437. /*++
  438. Routine Description:
  439. Process a route change notification.
  440. Arguments:
  441. None.
  442. Return Value:
  443. None.
  444. Caller LOCK: API.
  445. --*/
  446. {
  447. //
  448. // Both client and server should not be enabled on the same node.
  449. //
  450. ASSERT(!TeredoClientEnabled || !TeredoServerEnabled);
  451. if (TeredoClientEnabled) {
  452. if (TeredoClient.State != TEREDO_STATE_OFFLINE) {
  453. //
  454. // Refresh I/O state.
  455. //
  456. TeredoRefreshClient();
  457. } else {
  458. TeredoStartClient();
  459. }
  460. }
  461. if (TeredoServerEnabled) {
  462. if (TeredoServer.State != TEREDO_STATE_OFFLINE) {
  463. //
  464. // Refresh I/O state.
  465. //
  466. TeredoRefreshServer();
  467. } else {
  468. TeredoStartServer();
  469. }
  470. }
  471. }
  472. VOID
  473. TeredoConfigurationChangeNotification(
  474. VOID
  475. )
  476. /*++
  477. Routine Description:
  478. Process an configuration change request.
  479. Arguments:
  480. None.
  481. Return Value:
  482. None.
  483. Caller LOCK: API.
  484. --*/
  485. {
  486. HKEY Key = INVALID_HANDLE_VALUE;
  487. BOOL EnableClient, EnableServer;
  488. ULONG RefreshInterval, ResolveInterval;
  489. WCHAR OldServerName[NI_MAXHOST];
  490. BOOL IoStateChange = FALSE;
  491. (VOID) RegOpenKeyExW(
  492. HKEY_LOCAL_MACHINE, KEY_TEREDO, 0, KEY_QUERY_VALUE, &Key);
  493. //
  494. // Continue despite errors, reverting to default values.
  495. //
  496. //
  497. // Get the new configuration parameters.
  498. //
  499. RefreshInterval = GetInteger(
  500. Key, KEY_TEREDO_REFRESH_INTERVAL, TEREDO_REFRESH_INTERVAL);
  501. if (RefreshInterval == 0) {
  502. //
  503. // Invalid value. Revert to default.
  504. //
  505. RefreshInterval = TEREDO_REFRESH_INTERVAL;
  506. }
  507. TeredoClientRefreshInterval = RefreshInterval;
  508. TeredoClientRefreshIntervalChangeNotification();
  509. TeredoType = GetInteger(Key, KEY_TEREDO_TYPE, TEREDO_DEFAULT_TYPE);
  510. if ((TeredoType == TEREDO_DEFAULT) || (TeredoType >= TEREDO_MAXIMUM)) {
  511. //
  512. // Invalid value. Revert to default.
  513. //
  514. TeredoType = TEREDO_DEFAULT_TYPE;
  515. }
  516. EnableClient = ((TeredoType == TEREDO_CLIENT) ||
  517. ((TeredoType == TEREDO_AUTOMATIC) && TeredoRequired));
  518. EnableServer = (TeredoType == TEREDO_SERVER);
  519. wcscpy(OldServerName, TeredoServerName);
  520. GetString(
  521. Key,
  522. KEY_TEREDO_SERVER_NAME,
  523. TeredoServerName,
  524. NI_MAXHOST,
  525. TEREDO_SERVER_NAME);
  526. if (_wcsicmp(TeredoServerName, OldServerName) != 0) {
  527. IoStateChange = TRUE;
  528. }
  529. if (Key != INVALID_HANDLE_VALUE) {
  530. RegCloseKey(Key);
  531. }
  532. //
  533. // Both client and server should not be enabled on the same node.
  534. //
  535. ASSERT(!TeredoClientEnabled || !TeredoServerEnabled);
  536. //
  537. // Stop / Start / Reconfigure.
  538. //
  539. if (!EnableClient && TeredoClientEnabled) {
  540. TeredoClientEnabled = FALSE;
  541. TeredoStopClient();
  542. }
  543. if (!EnableServer && TeredoServerEnabled) {
  544. TeredoServerEnabled = FALSE;
  545. TeredoStopServer();
  546. }
  547. if (EnableClient) {
  548. if (TeredoClient.State != TEREDO_STATE_OFFLINE) {
  549. if (IoStateChange) {
  550. //
  551. // Refresh I/O state.
  552. //
  553. TeredoRefreshClient();
  554. }
  555. } else {
  556. TeredoClientEnabled = TRUE;
  557. TeredoStartClient();
  558. }
  559. }
  560. if (EnableServer) {
  561. if (TeredoServer.State != TEREDO_STATE_OFFLINE) {
  562. if (IoStateChange) {
  563. //
  564. // Refresh I/O state.
  565. //
  566. TeredoRefreshServer();
  567. }
  568. } else {
  569. TeredoServerEnabled = TRUE;
  570. TeredoStartServer();
  571. }
  572. }
  573. //
  574. // If the service is enabled, we attempt to start it every
  575. // TeredoResolveInterval seconds. Else we disable its timer.
  576. //
  577. ResolveInterval = (TeredoClientEnabled || TeredoServerEnabled)
  578. ? (TeredoResolveInterval * 1000)
  579. : INFINITE_INTERVAL;
  580. (VOID) ChangeTimerQueueTimer(
  581. NULL, TeredoTimer, ResolveInterval, ResolveInterval);
  582. }
  583. VOID
  584. WINAPI
  585. TeredoWmiEventNotification(
  586. IN PWNODE_HEADER Event,
  587. IN UINT_PTR Context
  588. )
  589. /*++
  590. Routine Description:
  591. Process a WMI event (specifically adapter arrival or removal).
  592. Arguments:
  593. Event - Supplies event specific information.
  594. Context - Supplies the context registered.
  595. Return Value:
  596. None.
  597. --*/
  598. {
  599. PWNODE_SINGLE_INSTANCE Instance = (PWNODE_SINGLE_INSTANCE) Event;
  600. USHORT AdapterNameLength;
  601. WCHAR AdapterName[MAX_ADAPTER_NAME_LENGTH], *AdapterGuid;
  602. if (Instance == NULL) {
  603. return;
  604. }
  605. ENTER_API();
  606. TraceEnter("TeredoWmiEventNotification");
  607. //
  608. // WNODE_SINGLE_INSTANCE is organized thus...
  609. // +-----------------------------------------------------------+
  610. // |<--- DataBlockOffset --->| AdapterNameLength | AdapterName |
  611. // +-----------------------------------------------------------+
  612. //
  613. // AdapterName is defined as "\DEVICE\"AdapterGuid
  614. //
  615. AdapterNameLength =
  616. *((PUSHORT) (((PUCHAR) Instance) + Instance->DataBlockOffset));
  617. if (AdapterNameLength > ((MAX_ADAPTER_NAME_LENGTH - 1) * sizeof(WCHAR))) {
  618. AdapterNameLength = (MAX_ADAPTER_NAME_LENGTH - 1) * sizeof(WCHAR);
  619. }
  620. RtlCopyMemory(
  621. AdapterName,
  622. ((PUCHAR) Instance) + Instance->DataBlockOffset + sizeof(USHORT),
  623. AdapterNameLength);
  624. AdapterName[AdapterNameLength / sizeof(WCHAR)] = L'\0';
  625. AdapterGuid = AdapterName + wcslen(DEVICE_PREFIX);
  626. Trace1(ANY, L"TeredoAdapter: %s", AdapterGuid);
  627. if ((memcmp(
  628. &(Event->Guid),
  629. &GUID_NDIS_NOTIFY_ADAPTER_ARRIVAL,
  630. sizeof(GUID)) == 0) ||
  631. (memcmp(
  632. &(Event->Guid),
  633. &GUID_NDIS_NOTIFY_DEVICE_POWER_ON,
  634. sizeof(GUID)) == 0)) {
  635. //
  636. // Adapter arrival (perhaps TUN).
  637. // Attempt to start the service (if it is not already running).
  638. //
  639. Trace0(ANY, L"Adapter Arrival");
  640. TeredoStart();
  641. }
  642. if ((memcmp(
  643. &(Event->Guid),
  644. &GUID_NDIS_NOTIFY_ADAPTER_REMOVAL,
  645. sizeof(GUID)) == 0) ||
  646. (memcmp(
  647. &(Event->Guid),
  648. &GUID_NDIS_NOTIFY_DEVICE_POWER_OFF,
  649. sizeof(GUID)) == 0)) {
  650. if (TeredoInterface(AdapterGuid)) {
  651. //
  652. // TUN adapter removal.
  653. // Stop the service if it is running.
  654. //
  655. Trace0(ANY, L"Adapter Removal");
  656. TeredoStop();
  657. }
  658. }
  659. LEAVE_API();
  660. }
  661. VOID
  662. TeredoRequirementChangeNotification(
  663. IN BOOL Required
  664. )
  665. /*++
  666. Routine Description:
  667. Process a possible requirement change notification.
  668. Arguments:
  669. Required - Whether the Teredo service is required for global connectivity.
  670. Return Value:
  671. None.
  672. Caller LOCK: API.
  673. --*/
  674. {
  675. if (TeredoRequired != Required) {
  676. TeredoRequired = Required;
  677. TeredoConfigurationChangeNotification();
  678. }
  679. }