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.

691 lines
16 KiB

  1. /*++
  2. Copyright (c) 2001-2002 Microsoft Corporation
  3. Module Name:
  4. common.c
  5. Abstract:
  6. This module contains the shipworm 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. ULONG ShipwormClientRefreshInterval = SHIPWORM_REFRESH_INTERVAL;
  15. BOOL ShipwormClientEnabled = (SHIPWORM_DEFAULT_TYPE == SHIPWORM_CLIENT);
  16. BOOL ShipwormServerEnabled = (SHIPWORM_DEFAULT_TYPE == SHIPWORM_SERVER);
  17. WCHAR ShipwormServerName[NI_MAXHOST] = SHIPWORM_SERVER_NAME;
  18. WCHAR ShipwormServiceName[NI_MAXSERV] = SHIPWORM_SERVICE_NAME;
  19. CONST IN6_ADDR ShipwormIpv6ServicePrefix = SHIPWORM_SERVICE_PREFIX;
  20. #define DEVICE_PREFIX L"\\Device\\"
  21. LPGUID ShipwormWmiEvent[] = {
  22. (LPGUID) &GUID_NDIS_NOTIFY_ADAPTER_ARRIVAL,
  23. (LPGUID) &GUID_NDIS_NOTIFY_ADAPTER_REMOVAL,
  24. };
  25. VOID
  26. WINAPI
  27. ShipwormWmiEventNotification(
  28. IN PWNODE_HEADER Event,
  29. IN UINT_PTR Context
  30. )
  31. /*++
  32. Routine Description:
  33. Process a WMI event (Adapter arrival or removal).
  34. Arguments:
  35. Event - Supplies the event specific information.
  36. Context - Supplies the context
  37. Return Value:
  38. None.
  39. Caller LOCK: API.
  40. --*/
  41. {
  42. PWNODE_SINGLE_INSTANCE Instance = (PWNODE_SINGLE_INSTANCE) Event;
  43. USHORT AdapterNameLength;
  44. WCHAR AdapterName[MAX_ADAPTER_NAME_LENGTH], *AdapterGuid;
  45. PSHIPWORM_IO Io = NULL;
  46. if (Instance == NULL) {
  47. return;
  48. }
  49. ENTER_API();
  50. TraceEnter("ShipwormWmiEventNotification");
  51. //
  52. // WNODE_SINGLE_INSTANCE is organized thus...
  53. // +-----------------------------------------------------------+
  54. // |<--- DataBlockOffset --->| AdapterNameLength | AdapterName |
  55. // +-----------------------------------------------------------+
  56. //
  57. // AdapterName is defined as "\DEVICE\"AdapterGuid
  58. //
  59. AdapterNameLength =
  60. *((PUSHORT) (((PUCHAR) Instance) + Instance->DataBlockOffset));
  61. RtlCopyMemory(
  62. AdapterName,
  63. ((PUCHAR) Instance) + Instance->DataBlockOffset + sizeof(USHORT),
  64. AdapterNameLength);
  65. AdapterName[AdapterNameLength] = L'\0';
  66. AdapterGuid = AdapterName + wcslen(DEVICE_PREFIX);
  67. Trace1(ANY, L"ShipwormAdapter: %s", AdapterGuid);
  68. if (memcmp(
  69. &(Event->Guid), &GUID_NDIS_NOTIFY_ADAPTER_ARRIVAL, sizeof(GUID)) == 0) {
  70. Trace0(ANY, L"GUID_NDIS_NOTIFY_ADAPTER_ARRIVAL");
  71. //
  72. // Adapter arrival (perhaps TUN).
  73. // Attempt to start the service (if it is not already running).
  74. //
  75. ShipwormStart();
  76. return;
  77. }
  78. if (memcmp(
  79. &(Event->Guid), &GUID_NDIS_NOTIFY_ADAPTER_REMOVAL, sizeof(GUID)) == 0)
  80. {
  81. Trace0(ANY, L"GUID_NDIS_NOTIFY_ADAPTER_REMOVAL");
  82. if (ShipwormClient.State != SHIPWORM_STATE_OFFLINE) {
  83. Io = &(ShipwormClient.Io);
  84. }
  85. if (ShipwormServer.State != SHIPWORM_STATE_OFFLINE) {
  86. Io = &(ShipwormServer.Io);
  87. }
  88. if ((Io != NULL) &&
  89. (_wcsicmp(Io->TunnelInterface, AdapterGuid) == 0)) {
  90. //
  91. // TUN adapter removal.
  92. // Stop the service if it is running.
  93. //
  94. ShipwormStop();
  95. }
  96. }
  97. LEAVE_API();
  98. }
  99. DWORD
  100. __inline
  101. ShipwormEnableWmiEvent(
  102. IN LPGUID EventGuid,
  103. IN BOOLEAN Enable
  104. )
  105. {
  106. return WmiNotificationRegistrationW(
  107. EventGuid, // Event Type.
  108. Enable, // Enable or Disable.
  109. ShipwormWmiEventNotification, // Callback.
  110. 0, // Context.
  111. NOTIFICATION_CALLBACK_DIRECT); // Notification Flags.
  112. }
  113. VOID
  114. __inline
  115. ShipwormDeregisterWmiEventNotification(
  116. VOID
  117. )
  118. {
  119. int i;
  120. for (i = 0; i < (sizeof(ShipwormWmiEvent) / sizeof(LPGUID)); i++) {
  121. (VOID) ShipwormEnableWmiEvent(ShipwormWmiEvent[i], FALSE);
  122. }
  123. }
  124. DWORD
  125. __inline
  126. ShipwormRegisterWmiEventNotification(
  127. VOID
  128. )
  129. {
  130. DWORD Error;
  131. int i;
  132. for (i = 0; i < (sizeof(ShipwormWmiEvent) / sizeof(LPGUID)); i++) {
  133. Error = ShipwormEnableWmiEvent(ShipwormWmiEvent[i], TRUE);
  134. if (Error != NO_ERROR) {
  135. goto Bail;
  136. }
  137. }
  138. return NO_ERROR;
  139. Bail:
  140. ShipwormDeregisterWmiEventNotification();
  141. return Error;
  142. }
  143. ICMPv6Header *
  144. ShipwormParseIpv6Headers (
  145. IN PUCHAR Buffer,
  146. IN ULONG Bytes
  147. )
  148. {
  149. UCHAR NextHeader = IP_PROTOCOL_V6;
  150. ULONG Length;
  151. //
  152. // Parse up until the ICMPv6 header.
  153. //
  154. while (TRUE) {
  155. switch (NextHeader) {
  156. case IP_PROTOCOL_V6:
  157. if (Bytes < sizeof(IP6_HDR)) {
  158. return NULL;
  159. }
  160. NextHeader = ((PIP6_HDR) Buffer)->ip6_nxt;
  161. Length = sizeof(IP6_HDR);
  162. break;
  163. case IP_PROTOCOL_HOP_BY_HOP:
  164. case IP_PROTOCOL_DEST_OPTS:
  165. case IP_PROTOCOL_ROUTING:
  166. if (Bytes < sizeof(ExtensionHeader)) {
  167. return NULL;
  168. }
  169. NextHeader = ((ExtensionHeader *) Buffer)->NextHeader;
  170. Length = ((ExtensionHeader *) Buffer)->HeaderExtLength * 8 + 8;
  171. break;
  172. case IP_PROTOCOL_FRAGMENT:
  173. if (Bytes < sizeof(FragmentHeader)) {
  174. return NULL;
  175. }
  176. NextHeader = ((FragmentHeader *) Buffer)->NextHeader;
  177. Length = sizeof(FragmentHeader);
  178. break;
  179. case IP_PROTOCOL_AH:
  180. if (Bytes < sizeof(AHHeader)) {
  181. return NULL;
  182. }
  183. NextHeader = ((AHHeader *) Buffer)->NextHeader;
  184. Length = sizeof(AHHeader) +
  185. ((AHHeader *) Buffer)->PayloadLen * 4 + 8;
  186. break;
  187. case IP_PROTOCOL_ICMPv6:
  188. if (Bytes < sizeof(ICMPv6Header)) {
  189. return NULL;
  190. }
  191. return (ICMPv6Header *) Buffer;
  192. default:
  193. return NULL;
  194. }
  195. if (Bytes < Length) {
  196. return NULL;
  197. }
  198. Buffer += Length;
  199. Bytes -= Length;
  200. }
  201. ASSERT(FALSE);
  202. }
  203. __inline
  204. VOID
  205. ShipwormStart(
  206. VOID
  207. )
  208. {
  209. //
  210. // Both client and server should not be enabled on the same node.
  211. //
  212. ASSERT(!ShipwormClientEnabled || !ShipwormServerEnabled);
  213. if (ShipwormClientEnabled) {
  214. //
  215. // The service might already be running, but that's alright.
  216. //
  217. ShipwormStartClient();
  218. }
  219. if (ShipwormServerEnabled) {
  220. //
  221. // The service might already be running, but that's alright.
  222. //
  223. ShipwormStartServer();
  224. }
  225. }
  226. __inline
  227. VOID
  228. ShipwormStop(
  229. VOID
  230. )
  231. {
  232. //
  233. // Both client and server should not be enabled on the same node.
  234. //
  235. ASSERT(!ShipwormClientEnabled || !ShipwormServerEnabled);
  236. if (ShipwormClientEnabled) {
  237. //
  238. // The service might not be running, but that's alright.
  239. //
  240. ShipwormStopClient();
  241. }
  242. if (ShipwormServerEnabled) {
  243. //
  244. // The service might not be running, but that's alright.
  245. //
  246. ShipwormStopServer();
  247. }
  248. }
  249. DWORD
  250. ShipwormInitialize(
  251. VOID
  252. )
  253. /*++
  254. Routine Description:
  255. Initializes the shipworm client and server and attempts to start them.
  256. Arguments:
  257. None.
  258. Return Value:
  259. NO_ERROR or failure code.
  260. --*/
  261. {
  262. DWORD Error;
  263. BOOL ClientInitialized = FALSE, ServerInitialized = FALSE;
  264. Error = ShipwormRegisterWmiEventNotification();
  265. if (Error != NO_ERROR) {
  266. return Error;
  267. }
  268. Error = ShipwormInitializeClient();
  269. if (Error != NO_ERROR) {
  270. goto Bail;
  271. }
  272. ClientInitialized = TRUE;
  273. Error = ShipwormInitializeServer();
  274. if (Error != NO_ERROR) {
  275. goto Bail;
  276. }
  277. ServerInitialized = TRUE;
  278. ShipwormStart();
  279. return NO_ERROR;
  280. Bail:
  281. ShipwormDeregisterWmiEventNotification();
  282. if (ClientInitialized) {
  283. ShipwormUninitializeClient();
  284. }
  285. if (ServerInitialized) {
  286. ShipwormUninitializeServer();
  287. }
  288. return Error;
  289. }
  290. VOID
  291. ShipwormUninitialize(
  292. VOID
  293. )
  294. /*++
  295. Routine Description:
  296. Uninitializes the shipworm client and server.
  297. Arguments:
  298. None.
  299. Return Value:
  300. None.
  301. --*/
  302. {
  303. ShipwormUninitializeClient();
  304. ShipwormUninitializeServer();
  305. ShipwormDeregisterWmiEventNotification();
  306. }
  307. VOID
  308. ShipwormAddressChangeNotification(
  309. IN BOOL Delete,
  310. IN IN_ADDR Address
  311. )
  312. /*++
  313. Routine Description:
  314. Process an address deletion or addition request.
  315. Arguments:
  316. Delete - Supplies a boolean. TRUE if the address was deleted, FALSE o/w.
  317. Address - Supplies the IPv4 address that was deleted or added.
  318. Return Value:
  319. None.
  320. Caller LOCK: API.
  321. --*/
  322. {
  323. if (Delete) {
  324. //
  325. // Both client and server should not be running on the same node.
  326. //
  327. ASSERT((ShipwormClient.State == SHIPWORM_STATE_OFFLINE) ||
  328. (ShipwormServer.State == SHIPWORM_STATE_OFFLINE));
  329. if (ShipwormClient.State != SHIPWORM_STATE_OFFLINE) {
  330. ShipwormClientAddressDeletionNotification(Address);
  331. }
  332. if (ShipwormServer.State != SHIPWORM_STATE_OFFLINE) {
  333. ShipwormServerAddressDeletionNotification(Address);
  334. }
  335. return;
  336. }
  337. //
  338. // Address addition.
  339. // Attempt to start the service (if it is not already running).
  340. //
  341. ShipwormStart();
  342. }
  343. VOID
  344. ShipwormConfigurationChangeNotification(
  345. VOID
  346. )
  347. /*++
  348. Routine Description:
  349. Process an configuration change request.
  350. Arguments:
  351. None.
  352. Return Value:
  353. None.
  354. Caller LOCK: API.
  355. --*/
  356. {
  357. HKEY Key = INVALID_HANDLE_VALUE;
  358. SHIPWORM_TYPE Type;
  359. BOOL EnableClient, EnableServer;
  360. ULONG RefreshInterval;
  361. WCHAR OldServerName[NI_MAXHOST];
  362. WCHAR OldServiceName[NI_MAXSERV];
  363. BOOL IoStateChange = FALSE;
  364. (VOID) RegOpenKeyExW(
  365. HKEY_LOCAL_MACHINE, KEY_SHIPWORM, 0, KEY_QUERY_VALUE, &Key);
  366. //
  367. // Continue despite errors, reverting to default values.
  368. //
  369. //
  370. // Get the new configuration parameters.
  371. //
  372. RefreshInterval = GetInteger(
  373. Key, KEY_SHIPWORM_REFRESH_INTERVAL, SHIPWORM_REFRESH_INTERVAL);
  374. if (RefreshInterval == 0) {
  375. //
  376. // Invalid value. Revert to default.
  377. //
  378. RefreshInterval = SHIPWORM_REFRESH_INTERVAL;
  379. }
  380. ShipwormClientRefreshInterval = RefreshInterval;
  381. Type = GetInteger(Key, KEY_SHIPWORM_TYPE, SHIPWORM_DEFAULT_TYPE);
  382. if ((Type == SHIPWORM_DEFAULT) || (Type >= SHIPWORM_MAXIMUM)) {
  383. //
  384. // Invalid value. Revert to default.
  385. //
  386. Type = SHIPWORM_DEFAULT_TYPE;
  387. }
  388. EnableClient = (Type == SHIPWORM_CLIENT);
  389. EnableServer = (Type == SHIPWORM_SERVER);
  390. wcscpy(OldServerName, ShipwormServerName);
  391. GetString(
  392. Key,
  393. KEY_SHIPWORM_SERVER_NAME,
  394. ShipwormServerName,
  395. NI_MAXHOST,
  396. SHIPWORM_SERVER_NAME);
  397. if (_wcsicmp(ShipwormServerName, OldServerName) != 0) {
  398. IoStateChange = TRUE;
  399. }
  400. wcscpy(OldServiceName, ShipwormServiceName);
  401. GetString(
  402. Key,
  403. KEY_SHIPWORM_SERVICE_NAME,
  404. ShipwormServiceName,
  405. NI_MAXSERV,
  406. SHIPWORM_SERVICE_NAME);
  407. if (_wcsicmp(ShipwormServiceName, OldServiceName) != 0) {
  408. IoStateChange = TRUE;
  409. }
  410. RegCloseKey(Key);
  411. //
  412. // Both client and server should not be enabled on the same node.
  413. //
  414. ASSERT(!ShipwormClientEnabled || !ShipwormServerEnabled);
  415. //
  416. // Stop / Start / Reconfigure.
  417. //
  418. if (!EnableClient && ShipwormClientEnabled) {
  419. ShipwormClientEnabled = FALSE;
  420. ShipwormStopClient();
  421. }
  422. if (!EnableServer && ShipwormServerEnabled) {
  423. ShipwormServerEnabled = FALSE;
  424. ShipwormStopServer();
  425. }
  426. if (EnableClient) {
  427. if (ShipwormClient.State != SHIPWORM_STATE_OFFLINE) {
  428. if (IoStateChange) {
  429. //
  430. // Refresh I/O state.
  431. //
  432. ShipwormClientAddressDeletionNotification(
  433. ShipwormClient.Io.SourceAddress.sin_addr);
  434. }
  435. } else {
  436. ShipwormClientEnabled = TRUE;
  437. ShipwormStartClient();
  438. }
  439. }
  440. if (EnableServer) {
  441. if (ShipwormServer.State != SHIPWORM_STATE_OFFLINE) {
  442. if (IoStateChange) {
  443. //
  444. // Refresh I/O state.
  445. //
  446. ShipwormServerAddressDeletionNotification(
  447. ShipwormServer.Io.SourceAddress.sin_addr);
  448. }
  449. } else {
  450. ShipwormServerEnabled = TRUE;
  451. ShipwormStartServer();
  452. }
  453. }
  454. }
  455. VOID
  456. ShipwormDeviceChangeNotification(
  457. IN DWORD Type,
  458. IN PVOID Data
  459. )
  460. /*++
  461. Routine Description:
  462. Process an adapter arrival or removal request.
  463. Arguments:
  464. Type - Supplies the event type.
  465. Data - Supplies the data associated with the event.
  466. Return Value:
  467. None.
  468. Caller LOCK: API.
  469. --*/
  470. {
  471. DEV_BROADCAST_DEVICEINTERFACE *Adapter =
  472. (DEV_BROADCAST_DEVICEINTERFACE *) Data;
  473. PSHIPWORM_IO Io = NULL;
  474. PWCHAR AdapterGuid;
  475. TraceEnter("ShipwormDeviceChangeNotification");
  476. switch(Type) {
  477. case DBT_DEVICEARRIVAL:
  478. Trace0(ANY, L"DeviceArrival");
  479. break;
  480. case DBT_DEVICEREMOVECOMPLETE:
  481. Trace0(ANY, L"DeviceRemoveComplete");
  482. break;
  483. case DBT_DEVICEQUERYREMOVE:
  484. Trace0(ANY, L"DeviceQueryRemove");
  485. break;
  486. case DBT_DEVICEQUERYREMOVEFAILED:
  487. Trace0(ANY, L"DeviceQueryRemoveFailed");
  488. break;
  489. case DBT_DEVICEREMOVEPENDING:
  490. Trace0(ANY, L"DeviceQueryRemovePending");
  491. break;
  492. case DBT_CUSTOMEVENT:
  493. Trace0(ANY, L"DeviceCustomEvent");
  494. break;
  495. default:
  496. Trace2(ANY, L"Device Type %u, %u", Type, Adapter->dbcc_devicetype);
  497. break;
  498. }
  499. //
  500. // Scan for the last occurance of the '{' character.
  501. // The string beginning at that position is the adapter GUID.
  502. //
  503. if ((Adapter == NULL) ||
  504. (Adapter->dbcc_devicetype != DBT_DEVTYP_DEVICEINTERFACE) ||
  505. ((AdapterGuid = wcsrchr(Adapter->dbcc_name, L'{')) == NULL)) {
  506. return;
  507. }
  508. switch(Type) {
  509. case DBT_DEVICEARRIVAL:
  510. //
  511. // Adapter arrival (perhaps TUN).
  512. // Attempt to start the service (if it is not already running).
  513. //
  514. ShipwormStart();
  515. return;
  516. case DBT_DEVICEREMOVECOMPLETE:
  517. if (ShipwormClient.State != SHIPWORM_STATE_OFFLINE) {
  518. Io = &(ShipwormClient.Io);
  519. }
  520. if (ShipwormServer.State != SHIPWORM_STATE_OFFLINE) {
  521. Io = &(ShipwormServer.Io);
  522. }
  523. if ((Io != NULL) &&
  524. (_wcsicmp(Io->TunnelInterface, AdapterGuid) == 0)) {
  525. //
  526. // TUN adapter removal.
  527. // Stop the service if it is running.
  528. //
  529. ShipwormStop();
  530. }
  531. return;
  532. }
  533. }