Draw +/- correctly for large icon sizes.
[wine/hacks.git] / dlls / iphlpapi / ifenum.c
blobaeaebdf78d281482725e670fac5554047c4d6a16
1 /* Copyright (C) 2003 Juan Lang
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2.1 of the License, or (at your option) any later version.
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 * Implementation notes
18 * Interface index fun:
19 * - Windows may rely on an index being cleared in the topmost 8 bits in some
20 * APIs; see GetFriendlyIfIndex and the mention of "backward compatible"
21 * indexes. It isn't clear which APIs might fail with non-backward-compatible
22 * indexes, but I'll keep them bits clear just in case.
23 * - Even though if_nametoindex and if_indextoname seem to be pretty portable,
24 * Linux, at any rate, uses the same interface index for all virtual
25 * interfaces of a real interface as well as for the real interface itself.
26 * If I used the Linux index as my index, this would break my statement that
27 * an index is a key, and that an interface has 0 or 1 IP addresses.
28 * If that behavior were consistent across UNIXen (I don't know), it could
29 * help me implement multiple IP addresses more in the Windows way.
30 * I used to assert I could not use UNIX interface indexes as my iphlpapi
31 * indexes due to restrictions in netapi32 and wsock32, but I have removed
32 * those restrictions, so using if_nametoindex and if_indextoname rather
33 * than my current mess would probably be better.
34 * FIXME:
35 * - I don't support IPv6 addresses here, since SIOCGIFCONF can't return them
36 * - the memory interface uses malloc/free; it should be using HeapAlloc instead
38 * There are three implemened methods for determining the MAC address of an
39 * interface:
40 * - a specific IOCTL (Linux)
41 * - looking in the ARP cache (at least Solaris)
42 * - using the sysctl interface (FreeBSD and MacOSX)
43 * Solaris and some others have SIOCGENADDR, but I haven't gotten that to work
44 * on the Solaris boxes at SourceForge's compile farm, whereas SIOCGARP does.
47 #include "config.h"
49 #include <stdarg.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
54 #ifdef HAVE_UNISTD_H
55 #include <unistd.h>
56 #endif
58 #include <sys/types.h>
60 #ifdef HAVE_SYS_SOCKET_H
61 #include <sys/socket.h>
62 #endif
64 #ifdef HAVE_NETINET_IN_H
65 #include <netinet/in.h>
66 #endif
68 #ifdef HAVE_ARPA_INET_H
69 #include <arpa/inet.h>
70 #endif
72 #ifdef HAVE_NET_IF_H
73 #include <net/if.h>
74 #endif
76 #ifdef HAVE_NET_IF_ARP_H
77 #include <net/if_arp.h>
78 #endif
80 #ifdef HAVE_NET_ROUTE_H
81 #include <net/route.h>
82 #endif
84 #ifdef HAVE_SYS_IOCTL_H
85 #include <sys/ioctl.h>
86 #endif
88 #ifdef HAVE_SYS_SYSCTL_H
89 #include <sys/sysctl.h>
90 #endif
92 #ifdef HAVE_SYS_SOCKIO_H
93 #include <sys/sockio.h>
94 #endif
96 #ifdef HAVE_NET_IF_DL_H
97 #include <net/if_dl.h>
98 #endif
100 #ifdef HAVE_NET_IF_TYPES_H
101 #include <net/if_types.h>
102 #endif
104 #include "ifenum.h"
106 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
107 #define ifreq_len(ifr) \
108 max(sizeof(struct ifreq), sizeof((ifr)->ifr_name)+(ifr)->ifr_addr.sa_len)
109 #else
110 #define ifreq_len(ifr) sizeof(struct ifreq)
111 #endif
113 #ifndef ETH_ALEN
114 #define ETH_ALEN 6
115 #endif
117 #ifndef INADDR_NONE
118 #define INADDR_NONE (~0U)
119 #endif
121 #define INITIAL_INTERFACES_ASSUMED 4
123 #define INDEX_IS_LOOPBACK 0x00800000
125 /* Type declarations */
127 typedef struct _InterfaceNameMapEntry {
128 char name[IFNAMSIZ];
129 BOOL inUse;
130 BOOL usedLastPass;
131 } InterfaceNameMapEntry;
133 typedef struct _InterfaceNameMap {
134 DWORD numInterfaces;
135 DWORD nextAvailable;
136 DWORD numAllocated;
137 InterfaceNameMapEntry table[1];
138 } InterfaceNameMap;
140 /* Global variables */
142 static CRITICAL_SECTION mapCS;
143 static InterfaceNameMap *gNonLoopbackInterfaceMap = NULL;
144 static InterfaceNameMap *gLoopbackInterfaceMap = NULL;
146 /* Functions */
148 void interfaceMapInit(void)
150 InitializeCriticalSection(&mapCS);
153 void interfaceMapFree(void)
155 DeleteCriticalSection(&mapCS);
156 if (gNonLoopbackInterfaceMap)
157 free(gNonLoopbackInterfaceMap);
158 if (gLoopbackInterfaceMap)
159 free(gLoopbackInterfaceMap);
162 /* Sizes the passed-in map to have enough space for numInterfaces interfaces.
163 * If map is NULL, allocates a new map. If it is not, may reallocate the
164 * existing map and return a map of increased size. Returns the allocated map,
165 * or NULL if it could not allocate a map of the requested size.
167 static InterfaceNameMap *sizeMap(InterfaceNameMap *map, DWORD numInterfaces)
169 if (!map) {
170 numInterfaces = max(numInterfaces, INITIAL_INTERFACES_ASSUMED);
171 map = (InterfaceNameMap *)calloc(1, sizeof(InterfaceNameMap) +
172 (numInterfaces - 1) * sizeof(InterfaceNameMapEntry));
173 if (map)
174 map->numAllocated = numInterfaces;
176 else {
177 if (map->numAllocated < numInterfaces) {
178 map = (InterfaceNameMap *)realloc(map, sizeof(InterfaceNameMap) +
179 (numInterfaces - 1) * sizeof(InterfaceNameMapEntry));
180 if (map)
181 memset(&map->table[map->numAllocated], 0,
182 (numInterfaces - map->numAllocated) * sizeof(InterfaceNameMapEntry));
185 return map;
188 static int isLoopbackInterface(int fd, const char *name)
190 int ret = 0;
192 if (name) {
193 struct ifreq ifr;
195 strncpy(ifr.ifr_name, name, IFNAMSIZ);
196 ifr.ifr_name[IFNAMSIZ-1] = '\0';
197 if (ioctl(fd, SIOCGIFFLAGS, &ifr) == 0)
198 ret = ifr.ifr_flags & IFF_LOOPBACK;
200 return ret;
203 static void countInterfaces(int fd, caddr_t buf, size_t len)
205 caddr_t ifPtr = buf;
206 DWORD numNonLoopbackInterfaces = 0, numLoopbackInterfaces = 0;
208 while (ifPtr && ifPtr < buf + len) {
209 struct ifreq *ifr = (struct ifreq *)ifPtr;
211 if (isLoopbackInterface(fd, ifr->ifr_name))
212 numLoopbackInterfaces++;
213 else
214 numNonLoopbackInterfaces++;
215 ifPtr += ifreq_len(ifr);
217 gNonLoopbackInterfaceMap = sizeMap(gNonLoopbackInterfaceMap,
218 numNonLoopbackInterfaces);
219 gLoopbackInterfaceMap = sizeMap(gLoopbackInterfaceMap,
220 numLoopbackInterfaces);
223 /* Stores the name in the given map, and increments the map's numInterfaces
224 * member if stored successfully. Will store in the same slot as previously if
225 * usedLastPass is set, otherwise will store in a new slot.
226 * Assumes map and name are not NULL, and the usedLastPass flag is set
227 * correctly for each entry in the map, and that map->numInterfaces <
228 * map->numAllocated.
229 * FIXME: this is kind of expensive, doing a linear scan of the map with a
230 * string comparison of each entry to find the old slot.
232 static void storeInterfaceInMap(InterfaceNameMap *map, const char *name)
234 if (map && name) {
235 DWORD ndx;
236 BOOL stored = FALSE;
238 /* look for previous slot, mark in use if so */
239 for (ndx = 0; !stored && ndx < map->nextAvailable; ndx++) {
240 if (map->table[ndx].usedLastPass && !strncmp(map->table[ndx].name, name,
241 sizeof(map->table[ndx].name))) {
242 map->table[ndx].inUse = TRUE;
243 stored = TRUE;
246 /* look for new slot */
247 for (ndx = 0; !stored && ndx < map->numAllocated; ndx++) {
248 if (!map->table[ndx].inUse) {
249 strncpy(map->table[ndx].name, name, IFNAMSIZ);
250 map->table[ndx].name[IFNAMSIZ-1] = '\0';
251 map->table[ndx].inUse = TRUE;
252 stored = TRUE;
253 if (ndx >= map->nextAvailable)
254 map->nextAvailable = ndx + 1;
257 if (stored)
258 map->numInterfaces++;
262 /* Sets all used entries' usedLastPass flag to their inUse flag, clears
263 * their inUse flag, and clears their numInterfaces member.
265 static void markOldInterfaces(InterfaceNameMap *map)
267 if (map) {
268 DWORD ndx;
270 map->numInterfaces = 0;
271 for (ndx = 0; ndx < map->nextAvailable; ndx++) {
272 map->table[ndx].usedLastPass = map->table[ndx].inUse;
273 map->table[ndx].inUse = FALSE;
278 static void classifyInterfaces(int fd, caddr_t buf, size_t len)
280 caddr_t ifPtr = buf;
282 markOldInterfaces(gNonLoopbackInterfaceMap);
283 markOldInterfaces(gLoopbackInterfaceMap);
284 while (ifPtr && ifPtr < buf + len) {
285 struct ifreq *ifr = (struct ifreq *)ifPtr;
287 if (ifr->ifr_addr.sa_family == AF_INET) {
288 if (isLoopbackInterface(fd, ifr->ifr_name))
289 storeInterfaceInMap(gLoopbackInterfaceMap, ifr->ifr_name);
290 else
291 storeInterfaceInMap(gNonLoopbackInterfaceMap, ifr->ifr_name);
293 ifPtr += ifreq_len(ifr);
297 static void enumerateInterfaces(void)
299 int fd;
301 fd = socket(PF_INET, SOCK_DGRAM, 0);
302 if (fd != -1) {
303 int ret, guessedNumInterfaces;
304 struct ifconf ifc;
306 /* try to avoid silly heap action by starting with the right size buffer */
307 guessedNumInterfaces = 0;
308 if (gNonLoopbackInterfaceMap)
309 guessedNumInterfaces += gNonLoopbackInterfaceMap->numInterfaces;
310 if (gLoopbackInterfaceMap)
311 guessedNumInterfaces += gLoopbackInterfaceMap->numInterfaces;
313 ret = 0;
314 memset(&ifc, 0, sizeof(ifc));
315 /* there is no way to know the interface count beforehand,
316 so we need to loop again and again upping our max each time
317 until returned < max */
318 do {
319 if (guessedNumInterfaces == 0)
320 guessedNumInterfaces = INITIAL_INTERFACES_ASSUMED;
321 else
322 guessedNumInterfaces *= 2;
323 if (ifc.ifc_buf)
324 free(ifc.ifc_buf);
325 ifc.ifc_len = sizeof(struct ifreq) * guessedNumInterfaces;
326 ifc.ifc_buf = (char *)malloc(ifc.ifc_len);
327 ret = ioctl(fd, SIOCGIFCONF, &ifc);
328 } while (ret == 0 &&
329 ifc.ifc_len == (sizeof(struct ifreq) * guessedNumInterfaces));
331 if (ret == 0) {
332 EnterCriticalSection(&mapCS);
333 countInterfaces(fd, ifc.ifc_buf, ifc.ifc_len);
334 classifyInterfaces(fd, ifc.ifc_buf, ifc.ifc_len);
335 LeaveCriticalSection(&mapCS);
338 if (ifc.ifc_buf)
339 free(ifc.ifc_buf);
340 close(fd);
344 DWORD getNumNonLoopbackInterfaces(void)
346 enumerateInterfaces();
347 return gNonLoopbackInterfaceMap ? gNonLoopbackInterfaceMap->numInterfaces : 0;
350 DWORD getNumInterfaces(void)
352 DWORD ret = getNumNonLoopbackInterfaces();
354 ret += gLoopbackInterfaceMap ? gLoopbackInterfaceMap->numInterfaces : 0;
355 return ret;
358 const char *getInterfaceNameByIndex(DWORD index)
360 DWORD realIndex;
361 InterfaceNameMap *map;
362 const char *ret = NULL;
364 EnterCriticalSection(&mapCS);
365 if (index & INDEX_IS_LOOPBACK) {
366 realIndex = index ^ INDEX_IS_LOOPBACK;
367 map = gLoopbackInterfaceMap;
369 else {
370 realIndex = index;
371 map = gNonLoopbackInterfaceMap;
373 if (map && realIndex < map->nextAvailable)
374 ret = map->table[realIndex].name;
375 LeaveCriticalSection(&mapCS);
376 return ret;
379 DWORD getInterfaceIndexByName(const char *name, PDWORD index)
381 DWORD ndx, ret;
382 BOOL found = FALSE;
384 if (!name)
385 return ERROR_INVALID_PARAMETER;
386 if (!index)
387 return ERROR_INVALID_PARAMETER;
389 EnterCriticalSection(&mapCS);
390 for (ndx = 0; !found && gNonLoopbackInterfaceMap &&
391 ndx < gNonLoopbackInterfaceMap->nextAvailable; ndx++)
392 if (!strncmp(gNonLoopbackInterfaceMap->table[ndx].name, name, IFNAMSIZ)) {
393 found = TRUE;
394 *index = ndx;
396 for (ndx = 0; !found && gLoopbackInterfaceMap &&
397 ndx < gLoopbackInterfaceMap->nextAvailable; ndx++)
398 if (!strncmp(gLoopbackInterfaceMap->table[ndx].name, name, IFNAMSIZ)) {
399 found = TRUE;
400 *index = ndx | INDEX_IS_LOOPBACK;
402 LeaveCriticalSection(&mapCS);
403 if (found)
404 ret = NO_ERROR;
405 else
406 ret = ERROR_INVALID_DATA;
407 return ret;
410 static void addMapEntriesToIndexTable(InterfaceIndexTable *table,
411 const InterfaceNameMap *map)
413 if (table && map) {
414 DWORD ndx;
416 for (ndx = 0; ndx < map->nextAvailable &&
417 table->numIndexes < table->numAllocated; ndx++)
418 if (map->table[ndx].inUse) {
419 DWORD externalNdx = ndx;
421 if (map == gLoopbackInterfaceMap)
422 externalNdx |= INDEX_IS_LOOPBACK;
423 table->indexes[table->numIndexes++] = externalNdx;
428 InterfaceIndexTable *getInterfaceIndexTable(void)
430 DWORD numInterfaces;
431 InterfaceIndexTable *ret;
433 EnterCriticalSection(&mapCS);
434 numInterfaces = getNumInterfaces();
435 ret = (InterfaceIndexTable *)calloc(1,
436 sizeof(InterfaceIndexTable) + (numInterfaces - 1) * sizeof(DWORD));
437 if (ret) {
438 ret->numAllocated = numInterfaces;
439 addMapEntriesToIndexTable(ret, gNonLoopbackInterfaceMap);
440 addMapEntriesToIndexTable(ret, gLoopbackInterfaceMap);
442 LeaveCriticalSection(&mapCS);
443 return ret;
446 InterfaceIndexTable *getNonLoopbackInterfaceIndexTable(void)
448 DWORD numInterfaces;
449 InterfaceIndexTable *ret;
451 EnterCriticalSection(&mapCS);
452 numInterfaces = getNumNonLoopbackInterfaces();
453 ret = (InterfaceIndexTable *)calloc(1,
454 sizeof(InterfaceIndexTable) + (numInterfaces - 1) * sizeof(DWORD));
455 if (ret) {
456 ret->numAllocated = numInterfaces;
457 addMapEntriesToIndexTable(ret, gNonLoopbackInterfaceMap);
459 LeaveCriticalSection(&mapCS);
460 return ret;
463 DWORD getInterfaceIPAddrByName(const char *name)
465 DWORD ret = INADDR_ANY;
467 if (name) {
468 int fd = socket(PF_INET, SOCK_DGRAM, 0);
470 if (fd != -1) {
471 struct ifreq ifr;
473 strncpy(ifr.ifr_name, name, IFNAMSIZ);
474 ifr.ifr_name[IFNAMSIZ-1] = '\0';
475 if (ioctl(fd, SIOCGIFADDR, &ifr) == 0)
476 memcpy(&ret, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
477 close(fd);
480 return ret;
483 DWORD getInterfaceIPAddrByIndex(DWORD index)
485 DWORD ret;
486 const char *name = getInterfaceNameByIndex(index);
488 if (name)
489 ret = getInterfaceIPAddrByName(name);
490 else
491 ret = INADDR_ANY;
492 return ret;
495 DWORD getInterfaceBCastAddrByName(const char *name)
497 DWORD ret = INADDR_ANY;
499 if (name) {
500 int fd = socket(PF_INET, SOCK_DGRAM, 0);
502 if (fd != -1) {
503 struct ifreq ifr;
505 strncpy(ifr.ifr_name, name, IFNAMSIZ);
506 ifr.ifr_name[IFNAMSIZ-1] = '\0';
507 if (ioctl(fd, SIOCGIFBRDADDR, &ifr) == 0)
508 memcpy(&ret, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
509 close(fd);
512 return ret;
515 DWORD getInterfaceBCastAddrByIndex(DWORD index)
517 DWORD ret;
518 const char *name = getInterfaceNameByIndex(index);
520 if (name)
521 ret = getInterfaceBCastAddrByName(name);
522 else
523 ret = INADDR_ANY;
524 return ret;
527 DWORD getInterfaceMaskByName(const char *name)
529 DWORD ret = INADDR_NONE;
531 if (name) {
532 int fd = socket(PF_INET, SOCK_DGRAM, 0);
534 if (fd != -1) {
535 struct ifreq ifr;
537 strncpy(ifr.ifr_name, name, IFNAMSIZ);
538 ifr.ifr_name[IFNAMSIZ-1] = '\0';
539 if (ioctl(fd, SIOCGIFNETMASK, &ifr) == 0)
540 memcpy(&ret, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
541 close(fd);
544 return ret;
547 DWORD getInterfaceMaskByIndex(DWORD index)
549 DWORD ret;
550 const char *name = getInterfaceNameByIndex(index);
552 if (name)
553 ret = getInterfaceMaskByName(name);
554 else
555 ret = INADDR_NONE;
556 return ret;
559 #if defined (SIOCGIFHWADDR)
560 DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
561 PDWORD type)
563 DWORD ret;
564 int fd;
566 if (!name || !len || !addr || !type)
567 return ERROR_INVALID_PARAMETER;
569 fd = socket(PF_INET, SOCK_DGRAM, 0);
570 if (fd != -1) {
571 struct ifreq ifr;
573 memset(&ifr, 0, sizeof(struct ifreq));
574 strncpy(ifr.ifr_name, name, IFNAMSIZ);
575 ifr.ifr_name[IFNAMSIZ-1] = '\0';
576 if ((ioctl(fd, SIOCGIFHWADDR, &ifr)))
577 ret = ERROR_INVALID_DATA;
578 else {
579 unsigned int addrLen;
581 switch (ifr.ifr_hwaddr.sa_family)
583 #ifdef ARPHRD_LOOPBACK
584 case ARPHRD_LOOPBACK:
585 addrLen = 0;
586 *type = MIB_IF_TYPE_LOOPBACK;
587 break;
588 #endif
589 #ifdef ARPHRD_ETHER
590 case ARPHRD_ETHER:
591 addrLen = ETH_ALEN;
592 *type = MIB_IF_TYPE_ETHERNET;
593 break;
594 #endif
595 #ifdef ARPHRD_FDDI
596 case ARPHRD_FDDI:
597 addrLen = ETH_ALEN;
598 *type = MIB_IF_TYPE_FDDI;
599 break;
600 #endif
601 #ifdef ARPHRD_IEEE802
602 case ARPHRD_IEEE802: /* 802.2 Ethernet && Token Ring, guess TR? */
603 addrLen = ETH_ALEN;
604 *type = MIB_IF_TYPE_TOKENRING;
605 break;
606 #endif
607 #ifdef ARPHRD_IEEE802_TR
608 case ARPHRD_IEEE802_TR: /* also Token Ring? */
609 addrLen = ETH_ALEN;
610 *type = MIB_IF_TYPE_TOKENRING;
611 break;
612 #endif
613 #ifdef ARPHRD_SLIP
614 case ARPHRD_SLIP:
615 addrLen = 0;
616 *type = MIB_IF_TYPE_SLIP;
617 break;
618 #endif
619 #ifdef ARPHRD_PPP
620 case ARPHRD_PPP:
621 addrLen = 0;
622 *type = MIB_IF_TYPE_PPP;
623 break;
624 #endif
625 default:
626 addrLen = min(MAX_INTERFACE_PHYSADDR, sizeof(ifr.ifr_hwaddr.sa_data));
627 *type = MIB_IF_TYPE_OTHER;
629 if (addrLen > *len) {
630 ret = ERROR_INSUFFICIENT_BUFFER;
631 *len = addrLen;
633 else {
634 if (addrLen > 0)
635 memcpy(addr, ifr.ifr_hwaddr.sa_data, addrLen);
636 /* zero out remaining bytes for broken implementations */
637 memset(addr + addrLen, 0, *len - addrLen);
638 *len = addrLen;
639 ret = NO_ERROR;
642 close(fd);
644 else
645 ret = ERROR_NO_MORE_FILES;
646 return ret;
648 #elif defined (SIOCGARP)
649 DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
650 PDWORD type)
652 DWORD ret;
653 int fd;
655 if (!name || !len || !addr || !type)
656 return ERROR_INVALID_PARAMETER;
658 fd = socket(PF_INET, SOCK_DGRAM, 0);
659 if (fd != -1) {
660 if (isLoopbackInterface(fd, name)) {
661 *type = MIB_IF_TYPE_LOOPBACK;
662 memset(addr, 0, *len);
663 *len = 0;
664 ret=NOERROR;
666 else {
667 struct arpreq arp;
668 struct sockaddr_in *saddr;
670 memset(&arp, 0, sizeof(struct arpreq));
671 arp.arp_pa.sa_family = AF_INET;
672 saddr = (struct sockaddr_in *)&arp; /* proto addr is first member */
673 saddr->sin_family = AF_INET;
674 saddr->sin_addr.s_addr = getInterfaceIPAddrByName(name);
675 if ((ioctl(fd, SIOCGARP, &arp)))
676 ret = ERROR_INVALID_DATA;
677 else {
678 /* FIXME: heh: who said it was ethernet? */
679 int addrLen = ETH_ALEN;
681 if (addrLen > *len) {
682 ret = ERROR_INSUFFICIENT_BUFFER;
683 *len = addrLen;
685 else {
686 if (addrLen > 0)
687 memcpy(addr, &arp.arp_ha.sa_data[0], addrLen);
688 /* zero out remaining bytes for broken implementations */
689 memset(addr + addrLen, 0, *len - addrLen);
690 *len = addrLen;
691 *type = MIB_IF_TYPE_ETHERNET;
692 ret = NO_ERROR;
696 close(fd);
698 else
699 ret = ERROR_NO_MORE_FILES;
701 return ret;
703 #elif defined (HAVE_SYS_SYSCTL_H) && defined (HAVE_NET_IF_DL_H)
704 DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
705 PDWORD type)
707 DWORD ret;
708 struct if_msghdr *ifm;
709 struct sockaddr_dl *sdl;
710 u_char *p, *buf;
711 size_t mibLen;
712 int mib[] = { CTL_NET, AF_ROUTE, 0, AF_LINK, NET_RT_IFLIST, 0 };
713 int addrLen;
714 BOOL found = FALSE;
716 if (!name || !len || !addr || !type)
717 return ERROR_INVALID_PARAMETER;
719 if (sysctl(mib, 6, NULL, &mibLen, NULL, 0) < 0)
720 return ERROR_NO_MORE_FILES;
722 buf = (u_char *)malloc(mibLen);
723 if (!buf)
724 return ERROR_NOT_ENOUGH_MEMORY;
726 if (sysctl(mib, 6, buf, &mibLen, NULL, 0) < 0) {
727 free(buf);
728 return ERROR_NO_MORE_FILES;
731 ret = ERROR_INVALID_DATA;
732 for (p = buf; !found && p < buf + mibLen; p += ifm->ifm_msglen) {
733 ifm = (struct if_msghdr *)p;
734 sdl = (struct sockaddr_dl *)(ifm + 1);
736 if (ifm->ifm_type != RTM_IFINFO || (ifm->ifm_addrs & RTA_IFP) == 0)
737 continue;
739 if (sdl->sdl_family != AF_LINK || sdl->sdl_nlen == 0 ||
740 memcmp(sdl->sdl_data, name, max(sdl->sdl_nlen, strlen(name))) != 0)
741 continue;
743 found = TRUE;
744 addrLen = min(MAX_INTERFACE_PHYSADDR, sdl->sdl_alen);
745 if (addrLen > *len) {
746 ret = ERROR_INSUFFICIENT_BUFFER;
747 *len = addrLen;
749 else {
750 if (addrLen > 0)
751 memcpy(addr, LLADDR(sdl), addrLen);
752 /* zero out remaining bytes for broken implementations */
753 memset(addr + addrLen, 0, *len - addrLen);
754 *len = addrLen;
755 #if defined(HAVE_NET_IF_TYPES_H)
756 switch (sdl->sdl_type)
758 case IFT_ETHER:
759 *type = MIB_IF_TYPE_ETHERNET;
760 break;
761 case IFT_FDDI:
762 *type = MIB_IF_TYPE_FDDI;
763 break;
764 case IFT_ISO88024: /* Token Bus */
765 *type = MIB_IF_TYPE_TOKENRING;
766 break;
767 case IFT_ISO88025: /* Token Ring */
768 *type = MIB_IF_TYPE_TOKENRING;
769 break;
770 case IFT_PPP:
771 *type = MIB_IF_TYPE_PPP;
772 break;
773 case IFT_SLIP:
774 *type = MIB_IF_TYPE_SLIP;
775 break;
776 case IFT_LOOP:
777 *type = MIB_IF_TYPE_LOOPBACK;
778 break;
779 default:
780 *type = MIB_IF_TYPE_OTHER;
782 #else
783 /* default if we don't know */
784 *type = MIB_IF_TYPE_ETHERNET;
785 #endif
786 ret = NO_ERROR;
789 free(buf);
790 return ret;
792 #endif
794 DWORD getInterfacePhysicalByIndex(DWORD index, PDWORD len, PBYTE addr,
795 PDWORD type)
797 const char *name = getInterfaceNameByIndex(index);
799 if (name)
800 return getInterfacePhysicalByName(name, len, addr, type);
801 else
802 return ERROR_INVALID_DATA;
805 DWORD getInterfaceMtuByName(const char *name, PDWORD mtu)
807 DWORD ret;
808 int fd;
810 if (!name)
811 return ERROR_INVALID_PARAMETER;
812 if (!mtu)
813 return ERROR_INVALID_PARAMETER;
815 fd = socket(PF_INET, SOCK_DGRAM, 0);
816 if (fd != -1) {
817 struct ifreq ifr;
819 strncpy(ifr.ifr_name, name, IFNAMSIZ);
820 ifr.ifr_name[IFNAMSIZ-1] = '\0';
821 if ((ioctl(fd, SIOCGIFMTU, &ifr)))
822 ret = ERROR_INVALID_DATA;
823 else {
824 #ifndef __sun
825 *mtu = ifr.ifr_mtu;
826 #else
827 *mtu = ifr.ifr_metric;
828 #endif
829 ret = NO_ERROR;
832 else
833 ret = ERROR_NO_MORE_FILES;
834 return ret;
837 DWORD getInterfaceMtuByIndex(DWORD index, PDWORD mtu)
839 const char *name = getInterfaceNameByIndex(index);
841 if (name)
842 return getInterfaceMtuByName(name, mtu);
843 else
844 return ERROR_INVALID_DATA;
847 DWORD getInterfaceStatusByName(const char *name, PDWORD status)
849 DWORD ret;
850 int fd;
852 if (!name)
853 return ERROR_INVALID_PARAMETER;
854 if (!status)
855 return ERROR_INVALID_PARAMETER;
857 fd = socket(PF_INET, SOCK_DGRAM, 0);
858 if (fd != -1) {
859 struct ifreq ifr;
861 strncpy(ifr.ifr_name, name, IFNAMSIZ);
862 ifr.ifr_name[IFNAMSIZ-1] = '\0';
863 if ((ioctl(fd, SIOCGIFFLAGS, &ifr)))
864 ret = ERROR_INVALID_DATA;
865 else {
866 if (ifr.ifr_flags & IFF_UP)
867 *status = MIB_IF_OPER_STATUS_OPERATIONAL;
868 else
869 *status = MIB_IF_OPER_STATUS_NON_OPERATIONAL;
870 ret = NO_ERROR;
873 else
874 ret = ERROR_NO_MORE_FILES;
875 return ret;
878 DWORD getInterfaceStatusByIndex(DWORD index, PDWORD status)
880 const char *name = getInterfaceNameByIndex(index);
882 if (name)
883 return getInterfaceStatusByName(name, status);
884 else
885 return ERROR_INVALID_DATA;
888 DWORD getInterfaceEntryByName(const char *name, PMIB_IFROW entry)
890 BYTE addr[MAX_INTERFACE_PHYSADDR];
891 DWORD ret, len = sizeof(addr), type;
893 if (!name)
894 return ERROR_INVALID_PARAMETER;
895 if (!entry)
896 return ERROR_INVALID_PARAMETER;
898 if (getInterfacePhysicalByName(name, &len, addr, &type) == NO_ERROR) {
899 WCHAR *assigner;
900 const char *walker;
902 memset(entry, 0, sizeof(MIB_IFROW));
903 for (assigner = entry->wszName, walker = name; *walker;
904 walker++, assigner++)
905 *assigner = *walker;
906 *assigner = 0;
907 getInterfaceIndexByName(name, &entry->dwIndex);
908 entry->dwPhysAddrLen = len;
909 memcpy(entry->bPhysAddr, addr, len);
910 memset(entry->bPhysAddr + len, 0, sizeof(entry->bPhysAddr) - len);
911 entry->dwType = type;
912 /* FIXME: how to calculate real speed? */
913 getInterfaceMtuByName(name, &entry->dwMtu);
914 /* lie, there's no "administratively down" here */
915 entry->dwAdminStatus = MIB_IF_ADMIN_STATUS_UP;
916 getInterfaceStatusByName(name, &entry->dwOperStatus);
917 /* punt on dwLastChange? */
918 entry->dwDescrLen = min(strlen(name), MAX_INTERFACE_DESCRIPTION - 1);
919 memcpy(entry->bDescr, name, entry->dwDescrLen);
920 entry->bDescr[entry->dwDescrLen] = '\0';
921 entry->dwDescrLen++;
922 ret = NO_ERROR;
924 else
925 ret = ERROR_INVALID_DATA;
926 return ret;
929 DWORD getInterfaceEntryByIndex(DWORD index, PMIB_IFROW entry)
931 const char *name = getInterfaceNameByIndex(index);
933 if (name)
934 return getInterfaceEntryByName(name, entry);
935 else
936 return ERROR_INVALID_DATA;
939 char *toIPAddressString(unsigned int addr, char string[16])
941 if (string) {
942 struct in_addr iAddr;
944 iAddr.s_addr = addr;
945 /* extra-anal, just to make auditors happy */
946 strncpy(string, inet_ntoa(iAddr), 16);
947 string[16] = '\0';
949 return string;