2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 /* Functions for accessing NT system configuration information. */
12 #include <afsconfig.h>
13 #include <afs/param.h>
31 static int IsLoopback(char * guid);
32 int syscfg_GetIFInfo_2000(int *count, int *addrs, int *masks, int *mtus, int *flags);
34 DWORD GetMTUForAddress(PIP_ADAPTER_ADDRESSES cAddress)
36 DWORD min_mtu = 0xFFFFFFFF; /* Default */
38 HKEY hk_services = NULL;
40 HKEY hk_adapters = NULL;
42 HKEY hk_adapter = NULL;
44 char * ipconfig = NULL;
46 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services", 0,
47 KEY_READ, &hk_services) != ERROR_SUCCESS)
50 if (RegOpenKeyEx(hk_services, "Tcpip\\Parameters\\Adapters", 0, KEY_READ,
55 if (RegOpenKeyEx(hk_adapters, cAddress->AdapterName, 0, KEY_READ, &hk_adapter)
65 if (RegQueryValueEx(hk_adapter, "IpConfig", 0, NULL, NULL, &cb_ipc)
69 cb_alloc = cb_ipc + sizeof(char) * 2;
70 ipconfig = malloc(cb_alloc);
74 if (RegQueryValueEx(hk_adapter, "IpConfig", 0, &type, ipconfig,
75 &cb_ipc) != ERROR_SUCCESS) {
79 if (cb_ipc < cb_alloc)
80 memset(ipconfig + cb_ipc / sizeof(char), 0,
81 (cb_alloc - cb_ipc) / sizeof(char));
83 for (this_ipc = ipconfig; (this_ipc - ipconfig) < cb_alloc / sizeof(char) &&
84 *this_ipc; this_ipc = this_ipc + (strlen(this_ipc) + 1)) {
86 HKEY hk_interface = NULL;
90 if (RegOpenKeyEx(hk_services, this_ipc, 0, KEY_READ,
91 &hk_interface) != ERROR_SUCCESS)
95 if (RegQueryValueEx(hk_interface, "MTU", NULL, NULL, &mtu,
96 &cb_mtu) == ERROR_SUCCESS) {
97 min_mtu = min(min_mtu, mtu);
100 RegCloseKey(hk_interface);
108 if (hk_services != NULL)
109 RegCloseKey(hk_services);
111 if (hk_adapters != NULL)
112 RegCloseKey(hk_adapters);
114 if (hk_adapter != NULL)
115 RegCloseKey(hk_adapter);
122 * Retrieve IP addresses, subnet masks, MTU sizes, and flags for all
123 * configured interfaces.
127 * count - in is max size of arrays. out is number of elements used.
130 * addrs - array of configured IP addresses, in host order.
131 * masks - array of subnet masks, in host order.
132 * mtus - array of MTU sizes.
133 * flags - array of flags.
136 * Total number of configured interfaces (>= count) or -1 on error.
139 int syscfg_GetIFInfo(int *count, int *addrs, int *masks, int *mtus, int *flags)
141 PMIB_IPADDRTABLE pIpAddrTable = NULL;
142 DWORD validAddrs = 0;
144 int maxCount = *count;
146 PIP_ADAPTER_ADDRESSES pAddresses, cAddress;
147 PMIB_IPADDRTABLE pIpTbl;
154 DWORD (WINAPI *pGetAdaptersAddresses)(ULONG, DWORD, PVOID,
155 PIP_ADAPTER_ADDRESSES, PULONG) = 0;
157 hIpHlp = LoadLibrary("iphlpapi");
158 if (hIpHlp != NULL) {
159 (FARPROC) pGetAdaptersAddresses = GetProcAddress(hIpHlp, "GetAdaptersAddresses");
160 if (pGetAdaptersAddresses == NULL)
164 if (pGetAdaptersAddresses == NULL)
165 return syscfg_GetIFInfo_2000(count, addrs, masks, mtus, flags);
167 /* first pass to get the required size of the IP table */
168 pIpTbl = (PMIB_IPADDRTABLE) malloc(sizeof(MIB_IPADDRTABLE));
169 outBufLen = sizeof(MIB_IPADDRTABLE);
171 dwRetVal = GetIpAddrTable(pIpTbl, &outBufLen, FALSE);
172 if (dwRetVal != ERROR_INSUFFICIENT_BUFFER) {
173 /* this should have failed with an insufficient buffer because we
174 didn't give any space to place the IP addresses */
181 /* second pass to get the actual data */
183 pIpTbl = (PMIB_IPADDRTABLE) malloc(outBufLen);
185 dwRetVal = GetIpAddrTable(pIpTbl, &outBufLen, FALSE);
186 if (dwRetVal != NO_ERROR) {
193 pAddresses = (IP_ADAPTER_ADDRESSES*) malloc(sizeof(IP_ADAPTER_ADDRESSES));
195 /* first call gets required buffer size */
196 if (pGetAdaptersAddresses(AF_INET,
200 &outBufLen) == ERROR_BUFFER_OVERFLOW)
203 pAddresses = (IP_ADAPTER_ADDRESSES*) malloc(outBufLen);
211 /* second call to get the actual data */
212 if ((dwRetVal = pGetAdaptersAddresses(AF_INET,
216 &outBufLen)) == NO_ERROR)
218 /* we have a list of addresses. go through them and figure out
220 for (cAddress = pAddresses; cAddress; cAddress = cAddress->Next) {
222 /* skip software loopback adapters */
223 if (cAddress->IfType == IF_TYPE_SOFTWARE_LOOPBACK)
226 /* also skip interfaces that are not up */
227 if (cAddress->OperStatus != 1)
230 /* starting with the AdapterName, which is actually the adapter
231 instance GUID, check if this is a MS loopback device */
232 if (IsLoopback(cAddress->AdapterName))
235 /* ok. looks good. Now fish out all the addresses from the
236 address table corresponding to the interface, and add them
238 for (i=0;i<pIpTbl->dwNumEntries;i++) {
239 if (pIpTbl->table[i].dwIndex == cAddress->IfIndex)
243 if_mtu = GetMTUForAddress(cAddress);
245 if (if_mtu < cAddress->Mtu) {
247 StringCbPrintf(s, sizeof(s), "MTU from registry is less than MTU from adapter address (%d vs %d)\n", if_mtu, cAddress->Mtu);
248 OutputDebugString(s);
253 addrs[n] = ntohl(pIpTbl->table[i].dwAddr);
254 masks[n] = ntohl(pIpTbl->table[i].dwMask);
255 mtus[n] = min(cAddress->Mtu, if_mtu);
269 /* again. this is bad */
281 static int IsLoopback(char * guid)
283 int isloopback = FALSE;
287 HKEY hkDevConn = NULL;
289 HKEY hkAdapter = NULL;
291 char pnpIns[MAX_PATH];
293 char service[MAX_PATH];
297 /* Open the network adapters key */
298 if (FAILED(RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}", 0, KEY_READ, &hkNet)))
301 /* open the guid key */
302 if (FAILED(RegOpenKeyEx(hkNet, guid, 0, KEY_READ, &hkDev)))
305 /* then the connection */
306 if (FAILED(RegOpenKeyEx(hkDev, "Connection", 0, KEY_READ, &hkDevConn)))
309 /* and find out the plug-n-play instance ID */
311 if (FAILED(RegQueryValueEx(hkDevConn, "PnpInstanceID", NULL, NULL, pnpIns, &size)))
314 /* now look in the device ENUM */
315 if (FAILED(RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Enum", 0, KEY_READ, &hkEnum)))
318 /* for the instance that we found above */
319 if (FAILED(RegOpenKeyEx(hkEnum, pnpIns, 0, KEY_READ, &hkAdapter)))
322 /* and fetch the harware ID */
324 if (FAILED(RegQueryValueEx(hkAdapter, "HardwareID", NULL, NULL, hwId, &size)))
328 if (FAILED(RegQueryValueEx(hkAdapter, "Service", NULL, NULL, service, &size)))
331 /* and see if it is the loopback adapter */
332 if (!stricmp(hwId, "*msloop") || !stricmp(service, "msloop"))
337 RegCloseKey(hkAdapter);
341 RegCloseKey(hkDevConn);
350 static int GetInterfaceList(HKEY skey, char **list);
351 static char *GetNextInterface(char *iflist);
352 static int GetIP(HKEY skey, char *ifname, int *addr, int *mask);
354 int syscfg_GetIFInfo_2000(int *count, int *addrs, int *masks, int *mtus, int *flags)
356 int maxCount = *count;
357 char *IFListBase = NULL;
358 char *IFList, *ifname;
362 if (RegOpenKeyAlt(AFSREG_NULL_KEY, AFSREG_IPSRV_KEY,
363 KEY_READ, 0, &skey, NULL))
366 if ((nConfig = GetInterfaceList(skey, &IFListBase)) < 0) {
367 (void) RegCloseKey(skey);
374 while ((n < maxCount) && (ifname = GetNextInterface(IFList))) {
375 if (!IsLoopback(ifname) && GetIP(skey, ifname, &addrs[n], &masks[n]) == 0 && addrs[n] != 0) {
383 /* And until we get mtu's and flags */
384 for (i = 0; i < n; i++) {
389 (void) RegCloseKey(skey);
399 * Get interface list; list is represented as a multistring.
400 * Returns number of elements in interface list or -1 on error.
402 static int GetInterfaceList(HKEY skey, char **list)
410 if (RegOpenKeyAlt(skey, AFSREG_IPSRV_IFACELIST_SUBKEY,
411 KEY_READ, 0, &key, NULL))
414 status = RegQueryValueAlt(key, AFSREG_IPSRV_IFACELIST_BIND_VALUE,
415 &valType, &str, NULL);
416 (void) RegCloseKey(key);
417 if (status || (valType != REG_MULTI_SZ))
420 /* Count strings in multistring. */
427 if (str[i] == '\0') {
428 /* hit end of string */
431 if (str[i] == '\0') {
432 /* hit end of multistring */
445 * Parse interface list. In first call to GetNextInterface(), iflist is
446 * the list returned by GetInterfaceList(); in successive calls, iflist is
447 * the pointer returned by the previous call to GetNextInterface().
449 * Returns pointer to next adapter name, or NULL if done.
452 static char *GetNextInterface(char *iflist)
456 /* interface substrings are assumed to be of form \Device\<adapter name>
457 * \Tcpip\Parameters\Interfaces\<adapter name>
459 ifname = strrchr(iflist, '\\');
462 /* subsequent (not first) call; advance to next interface substring */
463 iflist += strlen(iflist) + 1;
464 /* iflist now points to next interface or end-of-multistring char */
465 ifname = strrchr(iflist, '\\');
469 /* advance to first character of adapter name */
479 * Get IP address associated with interface (adapter name).
480 * Returns 0 on success and -1 on error.
483 static int GetIP(HKEY skey, char *ifname, int *addr, int *mask)
496 len = (int) strlen(ifname) + 1 + sizeof(AFSREG_IPSRV_ADAPTER_PARAM_SUBKEY);
501 sprintf(s, "%s\\%s", ifname, AFSREG_IPSRV_ADAPTER_PARAM_SUBKEY);
503 status = RegOpenKeyAlt(skey, s, KEY_READ, 0, &key, NULL);
509 dwSize = sizeof(DWORD);
510 status = RegQueryValueEx(key, "EnableDHCP", NULL,
511 &valType, (LPBYTE) &dwDHCP, &dwSize);
512 if (status || (valType != REG_DWORD))
516 status = RegQueryValueAlt(key, AFSREG_IPSRV_ADAPTER_PARAM_ADDR_VALUE,
517 &valType, &ipStr, NULL);
518 if (status || (valType != REG_SZ && valType != REG_MULTI_SZ)) {
519 if (ipStr) free(ipStr);
520 (void) RegCloseKey(key);
524 status = RegQueryValueAlt(key, AFSREG_IPSRV_ADAPTER_PARAM_MASK_VALUE,
525 &valType, &snMask, NULL);
526 if (status || (valType != REG_SZ && valType != REG_MULTI_SZ)) {
527 if (snMask) free(snMask);
531 /* adapter configured via DHCP; address/mask in alternate values */
532 dwSize = sizeof(DWORD);
533 status = RegQueryValueEx(key, "Lease", NULL,
534 &valType, (LPBYTE)&dwLease, &dwSize);
535 if (status || (valType != REG_DWORD) || dwLease == 0) {
536 (void) RegCloseKey(key);
540 status = RegQueryValueAlt(key,
541 AFSREG_IPSRV_ADAPTER_PARAM_DHCPADDR_VALUE,
542 &valType, &ipStr, NULL);
544 if (status || (valType != REG_SZ && valType != REG_MULTI_SZ)) {
545 if (ipStr) free(ipStr);
546 (void) RegCloseKey(key);
550 status = RegQueryValueAlt(key,
551 AFSREG_IPSRV_ADAPTER_PARAM_DHCPMASK_VALUE,
552 &valType, &snMask, NULL);
554 if (status || (valType != REG_SZ && valType != REG_MULTI_SZ)) {
555 if (snMask) free(snMask);
560 /* convert ip and subnet. */
561 *addr = (int)inet_addr(ipStr);
562 *addr = ntohl(*addr);
566 *mask = (int)inet_addr(snMask);
567 *mask = ntohl(*mask);
573 (void) RegCloseKey(key);