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.

408 lines
11 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. // Helper functions for dealing with the IPv6 protocol stack.
  14. // Really these should be in a library of some kind.
  15. //
  16. #include "precomp.h"
  17. #pragma hdrstop
  18. HANDLE Handle;
  19. //
  20. // Initialize this module.
  21. // Returns FALSE for failure.
  22. //
  23. int
  24. InitIPv6Library(void)
  25. {
  26. //
  27. // Get a handle to the IPv6 device.
  28. // We will use this for ioctl operations.
  29. //
  30. Handle = CreateFileW(WIN_IPV6_DEVICE_NAME,
  31. GENERIC_WRITE, // access mode
  32. FILE_SHARE_READ | FILE_SHARE_WRITE,
  33. NULL, // security attributes
  34. OPEN_EXISTING,
  35. 0, // flags & attributes
  36. NULL); // template file
  37. return Handle != INVALID_HANDLE_VALUE;
  38. }
  39. void
  40. UninitIPv6Library(void)
  41. {
  42. CloseHandle(Handle);
  43. Handle = INVALID_HANDLE_VALUE;
  44. }
  45. void
  46. ForEachInterface(void (*func)(IPV6_INFO_INTERFACE *, void *), void *Context)
  47. {
  48. IPV6_QUERY_INTERFACE Query;
  49. IPV6_INFO_INTERFACE *IF;
  50. u_int InfoSize, BytesReturned;
  51. InfoSize = sizeof *IF + 2 * MAX_LINK_LAYER_ADDRESS_LENGTH;
  52. IF = (IPV6_INFO_INTERFACE *) MALLOC(InfoSize);
  53. if (IF == NULL)
  54. return;
  55. Query.Index = (u_int) -1;
  56. for (;;) {
  57. if (!DeviceIoControl(Handle, IOCTL_IPV6_QUERY_INTERFACE,
  58. &Query, sizeof Query,
  59. IF, InfoSize, &BytesReturned,
  60. NULL)) {
  61. // fprintf(stderr, "bad index %u\n", Query.Index);
  62. break;
  63. }
  64. if (Query.Index != (u_int) -1) {
  65. if ((BytesReturned < sizeof *IF) ||
  66. (IF->Length < sizeof *IF) ||
  67. (BytesReturned != IF->Length +
  68. ((IF->LocalLinkLayerAddress != 0) ?
  69. IF->LinkLayerAddressLength : 0) +
  70. ((IF->RemoteLinkLayerAddress != 0) ?
  71. IF->LinkLayerAddressLength : 0))) {
  72. // printf("inconsistent interface info length\n");
  73. break;
  74. }
  75. (*func)(IF, Context);
  76. }
  77. else {
  78. if (BytesReturned != sizeof IF->Next) {
  79. // printf("inconsistent interface info length\n");
  80. break;
  81. }
  82. }
  83. if (IF->Next.Index == (u_int) -1)
  84. break;
  85. Query = IF->Next;
  86. }
  87. FREE(IF);
  88. }
  89. BOOL ReconnectInterface(
  90. IN PWCHAR AdapterName
  91. )
  92. {
  93. UNICODE_STRING GuidString;
  94. IPV6_QUERY_INTERFACE Query;
  95. UINT BytesReturned;
  96. TraceEnter("ReconnectInterface");
  97. RtlInitUnicodeString(&GuidString, AdapterName);
  98. if (RtlGUIDFromString(&GuidString, &Query.Guid) != NO_ERROR) {
  99. return FALSE;
  100. }
  101. //
  102. // Pretend as though the interface was reconnected.
  103. // This causes the IPv6 stack to resend router solicitation messages.
  104. //
  105. Query.Index = 0;
  106. if (!DeviceIoControl(Handle,
  107. IOCTL_IPV6_RENEW_INTERFACE, &Query, sizeof(Query),
  108. NULL, 0, &BytesReturned, NULL)) {
  109. return FALSE;
  110. }
  111. return TRUE;
  112. }
  113. int
  114. UpdateInterface(IPV6_INFO_INTERFACE *Update)
  115. {
  116. u_int BytesReturned;
  117. TraceEnter("UpdateInterface");
  118. return DeviceIoControl(Handle, IOCTL_IPV6_UPDATE_INTERFACE,
  119. Update, sizeof *Update,
  120. NULL, 0, &BytesReturned, NULL);
  121. }
  122. int
  123. UpdateRouteTable(IPV6_INFO_ROUTE_TABLE *Route)
  124. {
  125. u_int BytesReturned;
  126. TraceEnter("UpdateRouteTable");
  127. return DeviceIoControl(Handle, IOCTL_IPV6_UPDATE_ROUTE_TABLE,
  128. Route, sizeof *Route,
  129. NULL, 0, &BytesReturned, NULL);
  130. }
  131. int
  132. UpdateAddress(IPV6_UPDATE_ADDRESS *Address)
  133. {
  134. u_int BytesReturned;
  135. TraceEnter("UpdateAddress");
  136. return DeviceIoControl(Handle, IOCTL_IPV6_UPDATE_ADDRESS,
  137. Address, sizeof *Address,
  138. NULL, 0, &BytesReturned, NULL);
  139. }
  140. //* ConfirmIPv6Reachability
  141. //
  142. // Pings the specifies IPv6 destination address using
  143. // the specified timeout in milliseconds.
  144. //
  145. // The return value is the round-trip latency in milliseconds.
  146. // (Forced to be at least one.)
  147. //
  148. // If there is a timeout or failure, returns zero.
  149. //
  150. u_int
  151. ConfirmIPv6Reachability(SOCKADDR_IN6 *Dest, u_int Timeout)
  152. {
  153. ICMPV6_ECHO_REQUEST request;
  154. ICMPV6_ECHO_REPLY reply;
  155. u_long BytesReturned;
  156. DWORD TickCount;
  157. char hostname[NI_MAXHOST];
  158. //
  159. // REVIEW: Ad hoc testing showed that cisco's relay had problems
  160. // without this delay. Need to investigate why. In the meantime,
  161. // add a workaround to unblock people.
  162. //
  163. Sleep(500);
  164. getnameinfo((LPSOCKADDR)Dest, sizeof(SOCKADDR_IN6),
  165. hostname, sizeof(hostname),
  166. NULL, 0, NI_NUMERICHOST);
  167. Trace1(FSM, L"ConfirmIPv6Reachability: %hs", hostname);
  168. CopyTDIFromSA6(&request.DstAddress, Dest);
  169. memset(&request.SrcAddress, 0, sizeof request.SrcAddress);
  170. request.Timeout = Timeout;
  171. request.TTL = 1;
  172. request.Flags = 0;
  173. //
  174. // Start measuring elapsed time.
  175. //
  176. TickCount = GetTickCount();
  177. if (! DeviceIoControl(Handle,
  178. IOCTL_ICMPV6_ECHO_REQUEST,
  179. &request, sizeof request,
  180. &reply, sizeof reply,
  181. &BytesReturned,
  182. NULL)) {
  183. // fprintf(stderr, "DeviceIoControl: %u\n", GetLastError());
  184. return 0;
  185. }
  186. if (reply.Status == IP_HOP_LIMIT_EXCEEDED) {
  187. //
  188. // We guessed wrong about the relay's IPv6 address, but we have
  189. // IPv6 reachability via the IPv6 address in the reply.
  190. //
  191. CopySAFromTDI6(Dest, &reply.Address);
  192. getnameinfo((LPSOCKADDR)Dest, sizeof(SOCKADDR_IN6),
  193. hostname, sizeof(hostname),
  194. NULL, 0, NI_NUMERICHOST);
  195. Trace1(FSM, L"Got actual IPv6 address: %hs", hostname);
  196. } else if (reply.Status != IP_SUCCESS) {
  197. Trace1(ERR,L"Got error %u", reply.Status);
  198. return 0;
  199. }
  200. //
  201. // Stop the elapsed time measurement.
  202. //
  203. TickCount = GetTickCount() - TickCount;
  204. if (TickCount == 0)
  205. TickCount = 1;
  206. return TickCount;
  207. }
  208. IPV6_INFO_INTERFACE *
  209. GetInterfaceStackInfo(WCHAR *strAdapterName)
  210. {
  211. UNICODE_STRING UGuidStr;
  212. IPV6_QUERY_INTERFACE Query;
  213. IPV6_INFO_INTERFACE *IF;
  214. u_int InfoSize, BytesReturned;
  215. NTSTATUS Status;
  216. TraceEnter("GetInterfaceStackInfo");
  217. InfoSize = sizeof *IF + 2 * MAX_LINK_LAYER_ADDRESS_LENGTH;
  218. IF = (IPV6_INFO_INTERFACE *) MALLOC(InfoSize);
  219. if (IF == NULL)
  220. return NULL;
  221. RtlInitUnicodeString(&UGuidStr, strAdapterName);
  222. Status = RtlGUIDFromString(&UGuidStr, &Query.Guid);
  223. if (! NT_SUCCESS(Status))
  224. goto Error;
  225. Query.Index = 0; // query by guid.
  226. if (!DeviceIoControl(Handle, IOCTL_IPV6_QUERY_INTERFACE,
  227. &Query, sizeof Query,
  228. IF, InfoSize, &BytesReturned,
  229. NULL))
  230. goto Error;
  231. if ((BytesReturned < sizeof *IF) ||
  232. (IF->Length < sizeof *IF) ||
  233. (BytesReturned != IF->Length +
  234. ((IF->LocalLinkLayerAddress != 0) ?
  235. IF->LinkLayerAddressLength : 0) +
  236. ((IF->RemoteLinkLayerAddress != 0) ?
  237. IF->LinkLayerAddressLength : 0)))
  238. goto Error;
  239. return IF;
  240. Error:
  241. FREE(IF);
  242. return NULL;
  243. }
  244. u_int
  245. Create6over4Interface(IN_ADDR SrcAddr)
  246. {
  247. struct {
  248. IPV6_INFO_INTERFACE Info;
  249. IN_ADDR SrcAddr;
  250. } Create;
  251. IPV6_QUERY_INTERFACE Result;
  252. u_int BytesReturned;
  253. IPV6_INIT_INFO_INTERFACE(&Create.Info);
  254. Create.Info.Type = IPV6_IF_TYPE_TUNNEL_6OVER4;
  255. Create.Info.NeighborDiscovers = TRUE;
  256. Create.Info.RouterDiscovers = TRUE;
  257. Create.Info.LinkLayerAddressLength = sizeof(IN_ADDR);
  258. Create.Info.LocalLinkLayerAddress = (u_int)
  259. ((char *)&Create.SrcAddr - (char *)&Create.Info);
  260. Create.SrcAddr = SrcAddr;
  261. if (!DeviceIoControl(Handle, IOCTL_IPV6_CREATE_INTERFACE,
  262. &Create, sizeof Create,
  263. &Result, sizeof Result, &BytesReturned, NULL) ||
  264. (BytesReturned != sizeof Result)) {
  265. return 0;
  266. }
  267. Trace1(ERR, _T("Created 6over4 interface %d"), Result.Index);
  268. return Result.Index;
  269. }
  270. u_int
  271. CreateV6V4Interface(IN_ADDR SrcAddr, IN_ADDR DstAddr)
  272. {
  273. struct {
  274. IPV6_INFO_INTERFACE Info;
  275. IN_ADDR SrcAddr;
  276. IN_ADDR DstAddr;
  277. } Create;
  278. IPV6_QUERY_INTERFACE Result;
  279. u_int BytesReturned;
  280. IPV6_INIT_INFO_INTERFACE(&Create.Info);
  281. Create.Info.Type = IPV6_IF_TYPE_TUNNEL_V6V4;
  282. Create.Info.PeriodicMLD = TRUE;
  283. Create.Info.LinkLayerAddressLength = sizeof(IN_ADDR);
  284. Create.Info.LocalLinkLayerAddress = (u_int)
  285. ((char *)&Create.SrcAddr - (char *)&Create.Info);
  286. Create.Info.RemoteLinkLayerAddress = (u_int)
  287. ((char *)&Create.DstAddr - (char *)&Create.Info);
  288. Create.SrcAddr = SrcAddr;
  289. Create.DstAddr = DstAddr;
  290. if (!DeviceIoControl(Handle, IOCTL_IPV6_CREATE_INTERFACE,
  291. &Create, sizeof Create,
  292. &Result, sizeof Result, &BytesReturned, NULL) ||
  293. (BytesReturned != sizeof Result)) {
  294. return 0;
  295. }
  296. Trace1(ERR, _T("Created v6v4 interface %d"), Result.Index);
  297. return Result.Index;
  298. }
  299. BOOL
  300. DeleteInterface(u_int IfIndex)
  301. {
  302. IPV6_QUERY_INTERFACE Query;
  303. u_int BytesReturned;
  304. Trace1(ERR, _T("Deleting interface %d"), IfIndex);
  305. Query.Index = IfIndex;
  306. if (!DeviceIoControl(Handle, IOCTL_IPV6_DELETE_INTERFACE,
  307. &Query, sizeof Query,
  308. NULL, 0, &BytesReturned, NULL)) {
  309. return FALSE;
  310. }
  311. return TRUE;
  312. }
  313. BOOL
  314. UpdateRouterLinkAddress(u_int IfIndex, IN_ADDR SrcAddr, IN_ADDR DstAddr)
  315. {
  316. char Buffer[sizeof(IPV6_UPDATE_ROUTER_LL_ADDRESS) + 2 * sizeof(IPAddr)];
  317. IPV6_UPDATE_ROUTER_LL_ADDRESS *Update =
  318. (IPV6_UPDATE_ROUTER_LL_ADDRESS *) Buffer;
  319. IN_ADDR *Addr = (IN_ADDR*) (Update + 1);
  320. u_int BytesReturned;
  321. Trace2(FSM, _T("Setting router link address on if %d to %d.%d.%d.%d"),
  322. IfIndex, PRINT_IPADDR(DstAddr.s_addr));
  323. Update->IF.Index = IfIndex;
  324. Addr[0] = SrcAddr;
  325. Addr[1] = DstAddr;
  326. if (!DeviceIoControl(Handle, IOCTL_IPV6_UPDATE_ROUTER_LL_ADDRESS,
  327. Buffer, sizeof(Buffer),
  328. NULL, 0, &BytesReturned, NULL)) {
  329. Trace1(ERR, _T("DeviceIoControl error %d"), GetLastError());
  330. return FALSE;
  331. }
  332. return TRUE;
  333. }