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

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