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. */
27 static int IsLoopback(char * guid);
28 int syscfg_GetIFInfo_2000(int *count, int *addrs, int *masks, int *mtus, int *flags);
30 DWORD GetMTUForAddress(PIP_ADAPTER_ADDRESSES cAddress)
32 DWORD min_mtu = 0xFFFFFFFF; /* Default */
34 HKEY hk_services = NULL;
36 HKEY hk_adapters = NULL;
38 HKEY hk_adapter = NULL;
40 char * ipconfig = NULL;
42 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services", 0,
43 KEY_READ, &hk_services) != ERROR_SUCCESS)
46 if (RegOpenKeyEx(hk_services, "Tcpip\\Parameters\\Adapters", 0, KEY_READ,
51 if (RegOpenKeyEx(hk_adapters, cAddress->AdapterName, 0, KEY_READ, &hk_adapter)
61 if (RegQueryValueEx(hk_adapter, "IpConfig", 0, NULL, NULL, &cb_ipc)
65 cb_alloc = cb_ipc + sizeof(char) * 2;
66 ipconfig = malloc(cb_alloc);
70 if (RegQueryValueEx(hk_adapter, "IpConfig", 0, &type, ipconfig,
71 &cb_ipc) != ERROR_SUCCESS) {
75 if (cb_ipc < cb_alloc)
76 memset(ipconfig + cb_ipc / sizeof(char), 0,
77 (cb_alloc - cb_ipc) / sizeof(char));
79 for (this_ipc = ipconfig; (this_ipc - ipconfig) < cb_alloc / sizeof(char) &&
80 *this_ipc; this_ipc = this_ipc + (strlen(this_ipc) + 1)) {
82 HKEY hk_interface = NULL;
86 if (RegOpenKeyEx(hk_services, this_ipc, 0, KEY_READ,
87 &hk_interface) != ERROR_SUCCESS)
91 if (RegQueryValueEx(hk_interface, "MTU", NULL, NULL, &mtu,
92 &cb_mtu) == ERROR_SUCCESS) {
93 min_mtu = min(min_mtu, mtu);
96 RegCloseKey(hk_interface);
104 if (hk_services != NULL)
105 RegCloseKey(hk_services);
107 if (hk_adapters != NULL)
108 RegCloseKey(hk_adapters);
110 if (hk_adapter != NULL)
111 RegCloseKey(hk_adapter);
118 * Retrieve IP addresses, subnet masks, MTU sizes, and flags for all
119 * configured interfaces.
123 * count - in is max size of arrays. out is number of elements used.
126 * addrs - array of configured IP addresses, in host order.
127 * masks - array of subnet masks, in host order.
128 * mtus - array of MTU sizes.
129 * flags - array of flags.
132 * Total number of configured interfaces (>= count) or -1 on error.
135 int syscfg_GetIFInfo(int *count, int *addrs, int *masks, int *mtus, int *flags)
137 PMIB_IPADDRTABLE pIpAddrTable = NULL;
138 DWORD validAddrs = 0;
140 int maxCount = *count;
142 PIP_ADAPTER_ADDRESSES pAddresses, cAddress;
143 PMIB_IPADDRTABLE pIpTbl;
150 DWORD (WINAPI *pGetAdaptersAddresses)(ULONG, DWORD, PVOID,
151 PIP_ADAPTER_ADDRESSES, PULONG) = 0;
153 hIpHlp = LoadLibrary("iphlpapi");
154 if (hIpHlp != NULL) {
155 (FARPROC) pGetAdaptersAddresses = GetProcAddress(hIpHlp, "GetAdaptersAddresses");
156 if (pGetAdaptersAddresses == NULL)
160 if (pGetAdaptersAddresses == NULL)
161 return syscfg_GetIFInfo_2000(count, addrs, masks, mtus, flags);
163 /* first pass to get the required size of the IP table */
164 pIpTbl = (PMIB_IPADDRTABLE) malloc(sizeof(MIB_IPADDRTABLE));
165 outBufLen = sizeof(MIB_IPADDRTABLE);
167 dwRetVal = GetIpAddrTable(pIpTbl, &outBufLen, FALSE);
168 if (dwRetVal != ERROR_INSUFFICIENT_BUFFER) {
169 /* this should have failed with an insufficient buffer because we
170 didn't give any space to place the IP addresses */
177 /* second pass to get the actual data */
179 pIpTbl = (PMIB_IPADDRTABLE) malloc(outBufLen);
181 dwRetVal = GetIpAddrTable(pIpTbl, &outBufLen, FALSE);
182 if (dwRetVal != NO_ERROR) {
189 pAddresses = (IP_ADAPTER_ADDRESSES*) malloc(sizeof(IP_ADAPTER_ADDRESSES));
191 /* first call gets required buffer size */
192 if (pGetAdaptersAddresses(AF_INET,
196 &outBufLen) == ERROR_BUFFER_OVERFLOW)
199 pAddresses = (IP_ADAPTER_ADDRESSES*) malloc(outBufLen);
207 /* second call to get the actual data */
208 if ((dwRetVal = pGetAdaptersAddresses(AF_INET,
212 &outBufLen)) == NO_ERROR)
214 /* we have a list of addresses. go through them and figure out
216 for (cAddress = pAddresses; cAddress; cAddress = cAddress->Next) {
218 /* skip software loopback adapters */
219 if (cAddress->IfType == IF_TYPE_SOFTWARE_LOOPBACK)
222 /* also skip interfaces that are not up */
223 if (cAddress->OperStatus != 1)
226 /* starting with the AdapterName, which is actually the adapter
227 instance GUID, check if this is a MS loopback device */
228 if (IsLoopback(cAddress->AdapterName))
231 /* ok. looks good. Now fish out all the addresses from the
232 address table corresponding to the interface, and add them
234 for (i=0;i<pIpTbl->dwNumEntries;i++) {
235 if (pIpTbl->table[i].dwIndex == cAddress->IfIndex)
239 if_mtu = GetMTUForAddress(cAddress);
241 if (if_mtu < cAddress->Mtu) {
243 StringCbPrintf(s, sizeof(s), "MTU from registry is less than MTU from adapter address (%d vs %d)\n", if_mtu, cAddress->Mtu);
244 OutputDebugString(s);
249 addrs[n] = ntohl(pIpTbl->table[i].dwAddr);
250 masks[n] = ntohl(pIpTbl->table[i].dwMask);
251 mtus[n] = min(cAddress->Mtu, if_mtu);
265 /* again. this is bad */
277 static int IsLoopback(char * guid)
279 int isloopback = FALSE;
283 HKEY hkDevConn = NULL;
285 HKEY hkAdapter = NULL;
287 char pnpIns[MAX_PATH];
289 char service[MAX_PATH];
293 /* Open the network adapters key */
294 if (FAILED(RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}", 0, KEY_READ, &hkNet)))
297 /* open the guid key */
298 if (FAILED(RegOpenKeyEx(hkNet, guid, 0, KEY_READ, &hkDev)))
301 /* then the connection */
302 if (FAILED(RegOpenKeyEx(hkDev, "Connection", 0, KEY_READ, &hkDevConn)))
305 /* and find out the plug-n-play instance ID */
307 if (FAILED(RegQueryValueEx(hkDevConn, "PnpInstanceID", NULL, NULL, pnpIns, &size)))
310 /* now look in the device ENUM */
311 if (FAILED(RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Enum", 0, KEY_READ, &hkEnum)))
314 /* for the instance that we found above */
315 if (FAILED(RegOpenKeyEx(hkEnum, pnpIns, 0, KEY_READ, &hkAdapter)))
318 /* and fetch the harware ID */
320 if (FAILED(RegQueryValueEx(hkAdapter, "HardwareID", NULL, NULL, hwId, &size)))
324 if (FAILED(RegQueryValueEx(hkAdapter, "Service", NULL, NULL, service, &size)))
327 /* and see if it is the loopback adapter */
328 if (!stricmp(hwId, "*msloop") || !stricmp(service, "msloop"))
333 RegCloseKey(hkAdapter);
337 RegCloseKey(hkDevConn);
346 static int GetInterfaceList(HKEY skey, char **list);
347 static char *GetNextInterface(char *iflist);
348 static int GetIP(HKEY skey, char *ifname, int *addr, int *mask);
350 int syscfg_GetIFInfo_2000(int *count, int *addrs, int *masks, int *mtus, int *flags)
352 int maxCount = *count;
353 char *IFListBase = NULL;
354 char *IFList, *ifname;
358 if (RegOpenKeyAlt(AFSREG_NULL_KEY, AFSREG_IPSRV_KEY,
359 KEY_READ, 0, &skey, NULL))
362 if ((nConfig = GetInterfaceList(skey, &IFListBase)) < 0) {
363 (void) RegCloseKey(skey);
370 while ((n < maxCount) && (ifname = GetNextInterface(IFList))) {
371 if (!IsLoopback(ifname) && GetIP(skey, ifname, &addrs[n], &masks[n]) == 0 && addrs[n] != 0) {
379 /* And until we get mtu's and flags */
380 for (i = 0; i < n; i++) {
385 (void) RegCloseKey(skey);
395 * Get interface list; list is represented as a multistring.
396 * Returns number of elements in interface list or -1 on error.
398 static int GetInterfaceList(HKEY skey, char **list)
406 if (RegOpenKeyAlt(skey, AFSREG_IPSRV_IFACELIST_SUBKEY,
407 KEY_READ, 0, &key, NULL))
410 status = RegQueryValueAlt(key, AFSREG_IPSRV_IFACELIST_BIND_VALUE,
411 &valType, &str, NULL);
412 (void) RegCloseKey(key);
413 if (status || (valType != REG_MULTI_SZ))
416 /* Count strings in multistring. */
423 if (str[i] == '\0') {
424 /* hit end of string */
427 if (str[i] == '\0') {
428 /* hit end of multistring */
441 * Parse interface list. In first call to GetNextInterface(), iflist is
442 * the list returned by GetInterfaceList(); in successive calls, iflist is
443 * the pointer returned by the previous call to GetNextInterface().
445 * Returns pointer to next adapter name, or NULL if done.
448 static char *GetNextInterface(char *iflist)
452 /* interface substrings are assumed to be of form \Device\<adapter name>
453 * \Tcpip\Parameters\Interfaces\<adapter name>
455 ifname = strrchr(iflist, '\\');
458 /* subsequent (not first) call; advance to next interface substring */
459 iflist += strlen(iflist) + 1;
460 /* iflist now points to next interface or end-of-multistring char */
461 ifname = strrchr(iflist, '\\');
465 /* advance to first character of adapter name */
475 * Get IP address associated with interface (adapter name).
476 * Returns 0 on success and -1 on error.
479 static int GetIP(HKEY skey, char *ifname, int *addr, int *mask)
492 len = (int) strlen(ifname) + 1 + sizeof(AFSREG_IPSRV_ADAPTER_PARAM_SUBKEY);
497 sprintf(s, "%s\\%s", ifname, AFSREG_IPSRV_ADAPTER_PARAM_SUBKEY);
499 status = RegOpenKeyAlt(skey, s, KEY_READ, 0, &key, NULL);
505 dwSize = sizeof(DWORD);
506 status = RegQueryValueEx(key, "EnableDHCP", NULL,
507 &valType, (LPBYTE) &dwDHCP, &dwSize);
508 if (status || (valType != REG_DWORD))
512 status = RegQueryValueAlt(key, AFSREG_IPSRV_ADAPTER_PARAM_ADDR_VALUE,
513 &valType, &ipStr, NULL);
514 if (status || (valType != REG_SZ && valType != REG_MULTI_SZ)) {
515 if (ipStr) free(ipStr);
516 (void) RegCloseKey(key);
520 status = RegQueryValueAlt(key, AFSREG_IPSRV_ADAPTER_PARAM_MASK_VALUE,
521 &valType, &snMask, NULL);
522 if (status || (valType != REG_SZ && valType != REG_MULTI_SZ)) {
523 if (snMask) free(snMask);
527 /* adapter configured via DHCP; address/mask in alternate values */
528 dwSize = sizeof(DWORD);
529 status = RegQueryValueEx(key, "Lease", NULL,
530 &valType, (LPBYTE)&dwLease, &dwSize);
531 if (status || (valType != REG_DWORD) || dwLease == 0) {
532 (void) RegCloseKey(key);
536 status = RegQueryValueAlt(key,
537 AFSREG_IPSRV_ADAPTER_PARAM_DHCPADDR_VALUE,
538 &valType, &ipStr, NULL);
540 if (status || (valType != REG_SZ && valType != REG_MULTI_SZ)) {
541 if (ipStr) free(ipStr);
542 (void) RegCloseKey(key);
546 status = RegQueryValueAlt(key,
547 AFSREG_IPSRV_ADAPTER_PARAM_DHCPMASK_VALUE,
548 &valType, &snMask, NULL);
550 if (status || (valType != REG_SZ && valType != REG_MULTI_SZ)) {
551 if (snMask) free(snMask);
556 /* convert ip and subnet. */
557 *addr = (int)inet_addr(ipStr);
558 *addr = ntohl(*addr);
562 *mask = (int)inet_addr(snMask);
563 *mask = ntohl(*mask);
569 (void) RegCloseKey(key);