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
);