Fixed some issues found by winapi_check.
[wine/multimedia.git] / dlls / iphlpapi / ifenum.c
blob8505081bfb67ec28f64ed985f783d51b2fce2486
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 * But here's a problem with doing so:
31 * - Netbios() has a concept of an LAN adapter number (LANA), which is an 8-bit
32 * number in the range 0-254, inclusive. The MSDN pages for Netbios() says
33 * the original Netbios() spec allowed only 0 or 1 to be used, though "new"
34 * applications should enumerate available adapters rather than assuming 0
35 * is the default adapter.
36 * I'm concerned that some old application might depend on being able to get
37 * "the" MAC address of a machine by opening LANA 0 and getting its MAC
38 * address. This also implies LANA 0 should correspond to a non-loopback
39 * interface.
40 * On Linux, the if_nametoindex index is 1-based, and "lo" typically has
41 * index 1.
42 * I could make netapi32 do its own LANA map, independent of my index
43 * assignment, but it seems simpler just to assign 0-based indexes and put
44 * non-loopback adapters first, so the first 255 indexes (!) on a system will
45 * automatically map to LANA numbers without difficulty.
46 * - One more argument for doing it this way, if you don't buy the Netbios()
47 * argument: WsControl() (in wsock32) uses the same index to refer to an IP
48 * address and an interface. If I assigned multiple IP addresses to an
49 * interface, wsock32 would have to maintain a table of IP addresses with its
50 * own indexing scheme. No thanks.
52 * There are three implemened methods for determining the MAC address of an
53 * interface:
54 * - a specific IOCTL (Linux)
55 * - looking in the ARP cache (at least Solaris)
56 * - using the sysctl interface (FreeBSD and MacOSX)
57 * Solaris and some others have SIOCGENADDR, but I haven't gotten that to work
58 * on the Solaris boxes at SourceForge's compile farm, whereas SIOCGARP does.
61 #include "config.h"
63 #include <stdio.h>
64 #include <stdlib.h>
65 #include <string.h>
67 #ifdef HAVE_UNISTD_H
68 #include <unistd.h>
69 #endif
71 #include <sys/types.h>
73 #ifdef HAVE_SYS_SOCKET_H
74 #include <sys/socket.h>
75 #endif
77 #ifdef HAVE_NETINET_IN_H
78 #include <netinet/in.h>
79 #endif
81 #ifdef HAVE_ARPA_INET_H
82 #include <arpa/inet.h>
83 #endif
85 #ifdef HAVE_NET_IF_H
86 #include <net/if.h>
87 #endif
89 #ifdef HAVE_NET_IF_ARP_H
90 #include <net/if_arp.h>
91 #endif
93 #ifdef HAVE_NET_ROUTE_H
94 #include <net/route.h>
95 #endif
97 #ifdef HAVE_SYS_IOCTL_H
98 #include <sys/ioctl.h>
99 #endif
101 #ifdef HAVE_SYS_SYSCTL_H
102 #include <sys/sysctl.h>
103 #endif
105 #ifdef HAVE_SYS_SOCKIO_H
106 #include <sys/sockio.h>
107 #endif
109 #ifdef HAVE_NET_IF_DL_H
110 #include <net/if_dl.h>
111 #endif
113 #ifdef HAVE_NET_IF_TYPES_H
114 #include <net/if_types.h>
115 #endif
117 #include "winbase.h"
118 #include "iprtrmib.h"
119 #include "ifenum.h"
121 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
122 #define ifreq_len(ifr) \
123 max(sizeof(struct ifreq), sizeof((ifr)->ifr_name)+(ifr)->ifr_addr.sa_len)
124 #else
125 #define ifreq_len(ifr) sizeof(struct ifreq)
126 #endif
128 #ifndef ETH_ALEN
129 #define ETH_ALEN 6
130 #endif
132 #ifndef INADDR_NONE
133 #define INADDR_NONE (~0U)
134 #endif
136 #define INITIAL_INTERFACES_ASSUMED 4
138 #define INDEX_IS_LOOPBACK 0x00800000
140 /* Type declarations */
142 typedef struct _InterfaceNameMapEntry {
143 char name[IFNAMSIZ];
144 BOOL inUse;
145 BOOL usedLastPass;
146 } InterfaceNameMapEntry;
148 typedef struct _InterfaceNameMap {
149 DWORD numInterfaces;
150 DWORD nextAvailable;
151 DWORD numAllocated;
152 InterfaceNameMapEntry table[1];
153 } InterfaceNameMap;
155 /* Global variables */
157 static InterfaceNameMap *gNonLoopbackInterfaceMap = NULL;
158 static InterfaceNameMap *gLoopbackInterfaceMap = NULL;
160 /* Functions */
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 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 (isLoopbackInterface(fd, ifr->ifr_name))
288 storeInterfaceInMap(gLoopbackInterfaceMap, ifr->ifr_name);
289 else
290 storeInterfaceInMap(gNonLoopbackInterfaceMap, ifr->ifr_name);
291 ifPtr += ifreq_len(ifr);
295 static void enumerateInterfaces(void)
297 int fd;
299 fd = socket(PF_INET, SOCK_DGRAM, 0);
300 if (fd != -1) {
301 int ret, guessedNumInterfaces;
302 struct ifconf ifc;
304 /* try to avoid silly heap action by starting with the right size buffer */
305 guessedNumInterfaces = 0;
306 if (gNonLoopbackInterfaceMap)
307 guessedNumInterfaces += gNonLoopbackInterfaceMap->numInterfaces;
308 if (gLoopbackInterfaceMap)
309 guessedNumInterfaces += gLoopbackInterfaceMap->numInterfaces;
311 ret = 0;
312 memset(&ifc, 0, sizeof(ifc));
313 /* there is no way to know the interface count beforehand,
314 so we need to loop again and again upping our max each time
315 until returned < max */
316 do {
317 if (guessedNumInterfaces == 0)
318 guessedNumInterfaces = INITIAL_INTERFACES_ASSUMED;
319 else
320 guessedNumInterfaces *= 2;
321 if (ifc.ifc_buf)
322 free(ifc.ifc_buf);
323 ifc.ifc_len = sizeof(struct ifreq) * guessedNumInterfaces;
324 ifc.ifc_buf = (char *)malloc(ifc.ifc_len);
325 ret = ioctl(fd, SIOCGIFCONF, &ifc);
326 } while (ret == 0 &&
327 ifc.ifc_len == (sizeof(struct ifreq) * guessedNumInterfaces));
329 if (ret == 0) {
330 countInterfaces(fd, ifc.ifc_buf, ifc.ifc_len);
331 classifyInterfaces(fd, ifc.ifc_buf, ifc.ifc_len);
334 if (ifc.ifc_buf)
335 free(ifc.ifc_buf);
336 close(fd);
340 DWORD getNumNonLoopbackInterfaces(void)
342 enumerateInterfaces();
343 return gNonLoopbackInterfaceMap ? gNonLoopbackInterfaceMap->numInterfaces : 0;
346 DWORD getNumInterfaces(void)
348 DWORD ret = getNumNonLoopbackInterfaces();
350 ret += gLoopbackInterfaceMap ? gLoopbackInterfaceMap->numInterfaces : 0;
351 return ret;
354 const char *getInterfaceNameByIndex(DWORD index)
356 DWORD realIndex;
357 InterfaceNameMap *map;
358 const char *ret = NULL;
360 if (index & INDEX_IS_LOOPBACK) {
361 realIndex = index ^ INDEX_IS_LOOPBACK;
362 map = gLoopbackInterfaceMap;
364 else {
365 realIndex = index;
366 map = gNonLoopbackInterfaceMap;
368 if (map && realIndex < map->nextAvailable)
369 ret = map->table[realIndex].name;
370 return ret;
373 DWORD getInterfaceIndexByName(const char *name, PDWORD index)
375 DWORD ndx;
376 BOOL found = FALSE;
378 if (!name)
379 return ERROR_INVALID_PARAMETER;
380 if (!index)
381 return ERROR_INVALID_PARAMETER;
383 for (ndx = 0; !found && gNonLoopbackInterfaceMap &&
384 ndx < gNonLoopbackInterfaceMap->nextAvailable; ndx++)
385 if (!strncmp(gNonLoopbackInterfaceMap->table[ndx].name, name, IFNAMSIZ)) {
386 found = TRUE;
387 *index = ndx;
389 for (ndx = 0; !found && gLoopbackInterfaceMap &&
390 ndx < gLoopbackInterfaceMap->nextAvailable; ndx++)
391 if (!strncmp(gLoopbackInterfaceMap->table[ndx].name, name, IFNAMSIZ)) {
392 found = TRUE;
393 *index = ndx | INDEX_IS_LOOPBACK;
395 if (found)
396 return NO_ERROR;
397 else
398 return ERROR_INVALID_DATA;
401 static void addMapEntriesToIndexTable(InterfaceIndexTable *table,
402 const InterfaceNameMap *map)
404 if (table && map) {
405 DWORD ndx;
407 for (ndx = 0; ndx < map->nextAvailable &&
408 table->numIndexes < table->numAllocated; ndx++)
409 if (map->table[ndx].inUse) {
410 DWORD externalNdx = ndx;
412 if (map == gLoopbackInterfaceMap)
413 externalNdx |= INDEX_IS_LOOPBACK;
414 table->indexes[table->numIndexes++] = externalNdx;
419 InterfaceIndexTable *getInterfaceIndexTable(void)
421 DWORD numInterfaces = getNumInterfaces();
422 InterfaceIndexTable *ret = (InterfaceIndexTable *)calloc(1,
423 sizeof(InterfaceIndexTable) + (numInterfaces - 1) * sizeof(DWORD));
425 if (ret) {
426 ret->numAllocated = numInterfaces;
427 addMapEntriesToIndexTable(ret, gNonLoopbackInterfaceMap);
428 addMapEntriesToIndexTable(ret, gLoopbackInterfaceMap);
430 return ret;
433 InterfaceIndexTable *getNonLoopbackInterfaceIndexTable(void)
435 DWORD numInterfaces = getNumNonLoopbackInterfaces();
436 InterfaceIndexTable *ret = (InterfaceIndexTable *)calloc(1,
437 sizeof(InterfaceIndexTable) + (numInterfaces - 1) * sizeof(DWORD));
439 if (ret) {
440 ret->numAllocated = numInterfaces;
441 addMapEntriesToIndexTable(ret, gNonLoopbackInterfaceMap);
443 return ret;
446 DWORD getInterfaceIPAddrByName(const char *name)
448 DWORD ret = INADDR_ANY;
450 if (name) {
451 int fd = socket(PF_INET, SOCK_DGRAM, 0);
453 if (fd != -1) {
454 struct ifreq ifr;
456 strncpy(ifr.ifr_name, name, IFNAMSIZ);
457 ifr.ifr_name[IFNAMSIZ-1] = '\0';
458 if (ioctl(fd, SIOCGIFADDR, &ifr) == 0)
459 memcpy(&ret, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
460 close(fd);
463 return ret;
466 DWORD getInterfaceIPAddrByIndex(DWORD index)
468 DWORD ret;
469 const char *name = getInterfaceNameByIndex(index);
471 if (name)
472 ret = getInterfaceIPAddrByName(name);
473 else
474 ret = INADDR_ANY;
475 return ret;
478 DWORD getInterfaceBCastAddrByName(const char *name)
480 DWORD ret = INADDR_ANY;
482 if (name) {
483 int fd = socket(PF_INET, SOCK_DGRAM, 0);
485 if (fd != -1) {
486 struct ifreq ifr;
488 strncpy(ifr.ifr_name, name, IFNAMSIZ);
489 ifr.ifr_name[IFNAMSIZ-1] = '\0';
490 if (ioctl(fd, SIOCGIFBRDADDR, &ifr) == 0)
491 memcpy(&ret, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
492 close(fd);
495 return ret;
498 DWORD getInterfaceBCastAddrByIndex(DWORD index)
500 DWORD ret;
501 const char *name = getInterfaceNameByIndex(index);
503 if (name)
504 ret = getInterfaceBCastAddrByName(name);
505 else
506 ret = INADDR_ANY;
507 return ret;
510 DWORD getInterfaceMaskByName(const char *name)
512 DWORD ret = INADDR_NONE;
514 if (name) {
515 int fd = socket(PF_INET, SOCK_DGRAM, 0);
517 if (fd != -1) {
518 struct ifreq ifr;
520 strncpy(ifr.ifr_name, name, IFNAMSIZ);
521 ifr.ifr_name[IFNAMSIZ-1] = '\0';
522 if (ioctl(fd, SIOCGIFNETMASK, &ifr) == 0)
523 memcpy(&ret, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
524 close(fd);
527 return ret;
530 DWORD getInterfaceMaskByIndex(DWORD index)
532 DWORD ret;
533 const char *name = getInterfaceNameByIndex(index);
535 if (name)
536 ret = getInterfaceMaskByName(name);
537 else
538 ret = INADDR_NONE;
539 return ret;
542 #if defined (SIOCGIFHWADDR)
543 DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
544 PDWORD type)
546 DWORD ret;
547 int fd;
549 if (!name || !len || !addr || !type)
550 return ERROR_INVALID_PARAMETER;
552 fd = socket(PF_INET, SOCK_DGRAM, 0);
553 if (fd != -1) {
554 struct ifreq ifr;
556 memset(&ifr, 0, sizeof(struct ifreq));
557 strncpy(ifr.ifr_name, name, IFNAMSIZ);
558 ifr.ifr_name[IFNAMSIZ-1] = '\0';
559 if ((ioctl(fd, SIOCGIFHWADDR, &ifr)))
560 ret = ERROR_INVALID_DATA;
561 else {
562 int addrLen;
564 switch (ifr.ifr_hwaddr.sa_family)
566 case ARPHRD_LOOPBACK:
567 addrLen = 0;
568 *type = MIB_IF_TYPE_LOOPBACK;
569 break;
570 case ARPHRD_ETHER:
571 addrLen = ETH_ALEN;
572 *type = MIB_IF_TYPE_ETHERNET;
573 break;
574 case ARPHRD_FDDI:
575 addrLen = ETH_ALEN;
576 *type = MIB_IF_TYPE_FDDI;
577 break;
578 case ARPHRD_IEEE802: /* 802.2 Ethernet && Token Ring, guess TR? */
579 addrLen = ETH_ALEN;
580 *type = MIB_IF_TYPE_TOKENRING;
581 break;
582 case ARPHRD_IEEE802_TR: /* also Token Ring? */
583 addrLen = ETH_ALEN;
584 *type = MIB_IF_TYPE_TOKENRING;
585 break;
586 case ARPHRD_SLIP:
587 addrLen = 0;
588 *type = MIB_IF_TYPE_SLIP;
589 break;
590 case ARPHRD_PPP:
591 addrLen = 0;
592 *type = MIB_IF_TYPE_PPP;
593 break;
594 default:
595 addrLen = min(MAX_INTERFACE_PHYSADDR, sizeof(ifr.ifr_hwaddr.sa_data));
596 *type = MIB_IF_TYPE_OTHER;
598 if (addrLen > *len) {
599 ret = ERROR_INSUFFICIENT_BUFFER;
600 *len = addrLen;
602 else {
603 if (addrLen > 0)
604 memcpy(addr, ifr.ifr_hwaddr.sa_data, addrLen);
605 /* zero out remaining bytes for broken implementations */
606 memset(addr + addrLen, 0, *len - addrLen);
607 *len = addrLen;
608 ret = NO_ERROR;
611 close(fd);
613 else
614 ret = ERROR_NO_MORE_FILES;
615 return ret;
617 #elif defined (SIOCGARP)
618 DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
619 PDWORD type)
621 DWORD ret;
622 int fd;
624 if (!name || !len || !addr || !type)
625 return ERROR_INVALID_PARAMETER;
627 fd = socket(PF_INET, SOCK_DGRAM, 0);
628 if (fd != -1) {
629 if (isLoopbackInterface(fd, name)) {
630 *type = MIB_IF_TYPE_LOOPBACK;
631 memset(addr, 0, *len);
632 *len = 0;
633 ret=NOERROR;
635 else {
636 struct arpreq arp;
637 struct sockaddr_in *saddr;
639 memset(&arp, 0, sizeof(struct arpreq));
640 arp.arp_pa.sa_family = AF_INET;
641 saddr = (struct sockaddr_in *)&arp; /* proto addr is first member */
642 saddr->sin_family = AF_INET;
643 saddr->sin_addr.s_addr = getInterfaceIPAddrByName(name);
644 if ((ioctl(fd, SIOCGARP, &arp)))
645 ret = ERROR_INVALID_DATA;
646 else {
647 /* FIXME: heh: who said it was ethernet? */
648 int addrLen = ETH_ALEN;
650 if (addrLen > *len) {
651 ret = ERROR_INSUFFICIENT_BUFFER;
652 *len = addrLen;
654 else {
655 if (addrLen > 0)
656 memcpy(addr, &arp.arp_ha.sa_data[0], addrLen);
657 /* zero out remaining bytes for broken implementations */
658 memset(addr + addrLen, 0, *len - addrLen);
659 *len = addrLen;
660 *type = MIB_IF_TYPE_ETHERNET;
661 ret = NO_ERROR;
665 close(fd);
667 else
668 ret = ERROR_NO_MORE_FILES;
670 return ret;
672 #elif defined (HAVE_SYS_SYSCTL_H) && defined (HAVE_NET_IF_DL_H)
673 DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
674 PDWORD type)
676 DWORD ret;
677 struct if_msghdr *ifm;
678 struct sockaddr_dl *sdl;
679 u_char *p, *buf;
680 size_t mibLen;
681 int mib[] = { CTL_NET, AF_ROUTE, 0, AF_LINK, NET_RT_IFLIST, 0 };
682 int addrLen;
683 BOOL found = FALSE;
685 if (!name || !len || !addr || !type)
686 return ERROR_INVALID_PARAMETER;
688 if (sysctl(mib, 6, NULL, &mibLen, NULL, 0) < 0)
689 return ERROR_NO_MORE_FILES;
691 buf = (u_char *)malloc(mibLen);
692 if (!buf)
693 return ERROR_NOT_ENOUGH_MEMORY;
695 if (sysctl(mib, 6, buf, &mibLen, NULL, 0) < 0) {
696 free(buf);
697 return ERROR_NO_MORE_FILES;
700 ret = ERROR_INVALID_DATA;
701 for (p = buf; !found && p < buf + mibLen; p += ifm->ifm_msglen) {
702 ifm = (struct if_msghdr *)p;
703 sdl = (struct sockaddr_dl *)(ifm + 1);
705 if (ifm->ifm_type != RTM_IFINFO || (ifm->ifm_addrs & RTA_IFP) == 0)
706 continue;
708 if (sdl->sdl_family != AF_LINK || sdl->sdl_nlen == 0 ||
709 memcmp(sdl->sdl_data, name, max(sdl->sdl_nlen, strlen(name))) != 0)
710 continue;
712 found = TRUE;
713 addrLen = min(MAX_INTERFACE_PHYSADDR, sdl->sdl_alen);
714 if (addrLen > *len) {
715 ret = ERROR_INSUFFICIENT_BUFFER;
716 *len = addrLen;
718 else {
719 if (addrLen > 0)
720 memcpy(addr, LLADDR(sdl), addrLen);
721 /* zero out remaining bytes for broken implementations */
722 memset(addr + addrLen, 0, *len - addrLen);
723 *len = addrLen;
724 #if defined(HAVE_NET_IF_TYPES_H)
725 switch (sdl->sdl_type)
727 case IFT_ETHER:
728 *type = MIB_IF_TYPE_ETHERNET;
729 break;
730 case IFT_FDDI:
731 *type = MIB_IF_TYPE_FDDI;
732 break;
733 case IFT_ISO88024: /* Token Bus */
734 *type = MIB_IF_TYPE_TOKENRING;
735 break;
736 case IFT_ISO88025: /* Token Ring */
737 *type = MIB_IF_TYPE_TOKENRING;
738 break;
739 case IFT_PPP:
740 *type = MIB_IF_TYPE_PPP;
741 break;
742 case IFT_SLIP:
743 *type = MIB_IF_TYPE_SLIP;
744 break;
745 case IFT_LOOP:
746 *type = MIB_IF_TYPE_LOOPBACK;
747 break;
748 default:
749 *type = MIB_IF_TYPE_OTHER;
751 #else
752 /* default if we don't know */
753 *type = MIB_IF_TYPE_ETHERNET;
754 #endif
755 ret = NO_ERROR;
758 free(buf);
759 return ret;
761 #endif
763 DWORD getInterfacePhysicalByIndex(DWORD index, PDWORD len, PBYTE addr,
764 PDWORD type)
766 const char *name = getInterfaceNameByIndex(index);
768 if (name)
769 return getInterfacePhysicalByName(name, len, addr, type);
770 else
771 return ERROR_INVALID_DATA;
774 DWORD getInterfaceMtuByName(const char *name, PDWORD mtu)
776 DWORD ret;
777 int fd;
779 if (!name)
780 return ERROR_INVALID_PARAMETER;
781 if (!mtu)
782 return ERROR_INVALID_PARAMETER;
784 fd = socket(PF_INET, SOCK_DGRAM, 0);
785 if (fd != -1) {
786 struct ifreq ifr;
788 strncpy(ifr.ifr_name, name, IFNAMSIZ);
789 ifr.ifr_name[IFNAMSIZ-1] = '\0';
790 if ((ioctl(fd, SIOCGIFMTU, &ifr)))
791 ret = ERROR_INVALID_DATA;
792 else {
793 *mtu = ifr.ifr_mtu;
794 ret = NO_ERROR;
797 else
798 ret = ERROR_NO_MORE_FILES;
799 return ret;
802 DWORD getInterfaceMtuByIndex(DWORD index, PDWORD mtu)
804 const char *name = getInterfaceNameByIndex(index);
806 if (name)
807 return getInterfaceMtuByName(name, mtu);
808 else
809 return ERROR_INVALID_DATA;
812 DWORD getInterfaceStatusByName(const char *name, PDWORD status)
814 DWORD ret;
815 int fd;
817 if (!name)
818 return ERROR_INVALID_PARAMETER;
819 if (!status)
820 return ERROR_INVALID_PARAMETER;
822 fd = socket(PF_INET, SOCK_DGRAM, 0);
823 if (fd != -1) {
824 struct ifreq ifr;
826 strncpy(ifr.ifr_name, name, IFNAMSIZ);
827 ifr.ifr_name[IFNAMSIZ-1] = '\0';
828 if ((ioctl(fd, SIOCGIFFLAGS, &ifr)))
829 ret = ERROR_INVALID_DATA;
830 else {
831 if (ifr.ifr_flags & IFF_UP)
832 *status = MIB_IF_OPER_STATUS_OPERATIONAL;
833 else
834 *status = MIB_IF_OPER_STATUS_NON_OPERATIONAL;
835 ret = NO_ERROR;
838 else
839 ret = ERROR_NO_MORE_FILES;
840 return ret;
843 DWORD getInterfaceStatusByIndex(DWORD index, PDWORD status)
845 const char *name = getInterfaceNameByIndex(index);
847 if (name)
848 return getInterfaceStatusByName(name, status);
849 else
850 return ERROR_INVALID_DATA;
853 DWORD getInterfaceEntryByName(const char *name, PMIB_IFROW entry)
855 BYTE addr[MAX_INTERFACE_PHYSADDR];
856 DWORD ret, len = sizeof(addr), type;
858 if (!name)
859 return ERROR_INVALID_PARAMETER;
860 if (!entry)
861 return ERROR_INVALID_PARAMETER;
863 if (getInterfacePhysicalByName(name, &len, addr, &type) == NO_ERROR) {
864 WCHAR *assigner;
865 const char *walker;
867 memset(entry, 0, sizeof(MIB_IFROW));
868 for (assigner = entry->wszName, walker = name; *walker;
869 walker++, assigner++)
870 *assigner = *walker;
871 *assigner = 0;
872 getInterfaceIndexByName(name, &entry->dwIndex);
873 entry->dwPhysAddrLen = len;
874 memcpy(entry->bPhysAddr, addr, len);
875 memset(entry->bPhysAddr + len, 0, sizeof(entry->bPhysAddr) - len);
876 entry->dwType = type;
877 /* FIXME: how to calculate real speed? */
878 getInterfaceMtuByName(name, &entry->dwMtu);
879 /* lie, there's no "administratively down" here */
880 entry->dwAdminStatus = MIB_IF_ADMIN_STATUS_UP;
881 getInterfaceStatusByName(name, &entry->dwOperStatus);
882 /* punt on dwLastChange? */
883 entry->dwDescrLen = min(strlen(name), MAX_INTERFACE_DESCRIPTION - 1);
884 memcpy(entry->bDescr, name, entry->dwDescrLen);
885 entry->bDescr[entry->dwDescrLen] = '\0';
886 entry->dwDescrLen++;
887 ret = NO_ERROR;
889 else
890 ret = ERROR_INVALID_DATA;
891 return ret;
894 DWORD getInterfaceEntryByIndex(DWORD index, PMIB_IFROW entry)
896 const char *name = getInterfaceNameByIndex(index);
898 if (name)
899 return getInterfaceEntryByName(name, entry);
900 else
901 return ERROR_INVALID_DATA;
904 char *toIPAddressString(unsigned int addr, char string[16])
906 if (string) {
907 struct in_addr iAddr;
909 iAddr.s_addr = addr;
910 /* extra-anal, just to make auditors happy */
911 strncpy(string, inet_ntoa(iAddr), 16);
912 string[16] = '\0';
914 return string;