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
40 * On Linux, the if_nametoindex index is 1-based, and "lo" typically has
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
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.
71 #include <sys/types.h>
74 #include <sys/socket.h>
78 #include <netinet/in.h>
82 #include <arpa/inet.h>
90 #include <net/if_arp.h>
94 #include <net/route.h>
98 #include <sys/ioctl.h>
101 #if HAVE_SYS_SYSCTL_H
102 #include <sys/sysctl.h>
105 #if HAVE_SYS_SOCKIO_H
106 #include <sys/sockio.h>
110 #include <net/if_dl.h>
113 #if HAVE_NET_IF_TYPES_H
114 #include <net/if_types.h>
118 #include "iprtrmib.h"
121 #if HAVE_STRUCT_SOCKADDR_SA_LEN
122 #define ifreq_len(ifr) \
123 max(sizeof(struct ifreq), sizeof((ifr)->ifr_name)+(ifr)->ifr_addr.sa_len)
125 #define ifreq_len(ifr) sizeof(struct ifreq)
133 #define INADDR_NONE (~0U)
136 #define INITIAL_INTERFACES_ASSUMED 4
138 #define INDEX_IS_LOOPBACK 0x00800000
140 /* Type declarations */
142 typedef struct _InterfaceNameMapEntry
{
146 } InterfaceNameMapEntry
;
148 typedef struct _InterfaceNameMap
{
152 InterfaceNameMapEntry table
[1];
155 /* Global variables */
157 static InterfaceNameMap
*gNonLoopbackInterfaceMap
= NULL
;
158 static InterfaceNameMap
*gLoopbackInterfaceMap
= NULL
;
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
)
170 numInterfaces
= max(numInterfaces
, INITIAL_INTERFACES_ASSUMED
);
171 map
= (InterfaceNameMap
*)calloc(1, sizeof(InterfaceNameMap
) +
172 (numInterfaces
- 1) * sizeof(InterfaceNameMapEntry
));
174 map
->numAllocated
= numInterfaces
;
177 if (map
->numAllocated
< numInterfaces
) {
178 map
= (InterfaceNameMap
*)realloc(map
, sizeof(InterfaceNameMap
) +
179 (numInterfaces
- 1) * sizeof(InterfaceNameMapEntry
));
181 memset(&map
->table
[map
->numAllocated
], 0,
182 (numInterfaces
- map
->numAllocated
) * sizeof(InterfaceNameMapEntry
));
188 static int isLoopbackInterface(int fd
, const char *name
)
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
;
203 static void countInterfaces(int fd
, caddr_t buf
, size_t len
)
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
++;
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 <
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
)
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
;
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
;
253 if (ndx
>= map
->nextAvailable
)
254 map
->nextAvailable
= ndx
+ 1;
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
)
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
)
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
);
290 storeInterfaceInMap(gNonLoopbackInterfaceMap
, ifr
->ifr_name
);
291 ifPtr
+= ifreq_len(ifr
);
295 static void enumerateInterfaces(void)
299 fd
= socket(PF_INET
, SOCK_DGRAM
, 0);
301 int ret
, guessedNumInterfaces
;
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
;
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 */
317 if (guessedNumInterfaces
== 0)
318 guessedNumInterfaces
= INITIAL_INTERFACES_ASSUMED
;
320 guessedNumInterfaces
*= 2;
323 ifc
.ifc_len
= sizeof(struct ifreq
) * guessedNumInterfaces
;
324 ifc
.ifc_buf
= (char *)malloc(ifc
.ifc_len
);
325 ret
= ioctl(fd
, SIOCGIFCONF
, &ifc
);
327 ifc
.ifc_len
== (sizeof(struct ifreq
) * guessedNumInterfaces
));
330 countInterfaces(fd
, ifc
.ifc_buf
, ifc
.ifc_len
);
331 classifyInterfaces(fd
, ifc
.ifc_buf
, ifc
.ifc_len
);
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;
354 const char *getInterfaceNameByIndex(DWORD index
)
357 InterfaceNameMap
*map
;
358 const char *ret
= NULL
;
360 if (index
& INDEX_IS_LOOPBACK
) {
361 realIndex
= index
^ INDEX_IS_LOOPBACK
;
362 map
= gLoopbackInterfaceMap
;
366 map
= gNonLoopbackInterfaceMap
;
368 if (map
&& realIndex
< map
->nextAvailable
)
369 ret
= map
->table
[realIndex
].name
;
373 DWORD
getInterfaceIndexByName(const char *name
, PDWORD index
)
379 return ERROR_INVALID_PARAMETER
;
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
)) {
389 for (ndx
= 0; !found
&& gLoopbackInterfaceMap
&&
390 ndx
< gLoopbackInterfaceMap
->nextAvailable
; ndx
++)
391 if (!strncmp(gLoopbackInterfaceMap
->table
[ndx
].name
, name
, IFNAMSIZ
)) {
393 *index
= ndx
| INDEX_IS_LOOPBACK
;
398 return ERROR_INVALID_DATA
;
401 static void addMapEntriesToIndexTable(InterfaceIndexTable
*table
,
402 const InterfaceNameMap
*map
)
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
));
426 ret
->numAllocated
= numInterfaces
;
427 addMapEntriesToIndexTable(ret
, gNonLoopbackInterfaceMap
);
428 addMapEntriesToIndexTable(ret
, gLoopbackInterfaceMap
);
433 InterfaceIndexTable
*getNonLoopbackInterfaceIndexTable(void)
435 DWORD numInterfaces
= getNumNonLoopbackInterfaces();
436 InterfaceIndexTable
*ret
= (InterfaceIndexTable
*)calloc(1,
437 sizeof(InterfaceIndexTable
) + (numInterfaces
- 1) * sizeof(DWORD
));
440 ret
->numAllocated
= numInterfaces
;
441 addMapEntriesToIndexTable(ret
, gNonLoopbackInterfaceMap
);
446 DWORD
getInterfaceIPAddrByName(const char *name
)
448 DWORD ret
= INADDR_ANY
;
451 int fd
= socket(PF_INET
, SOCK_DGRAM
, 0);
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
));
466 DWORD
getInterfaceIPAddrByIndex(DWORD index
)
469 const char *name
= getInterfaceNameByIndex(index
);
472 ret
= getInterfaceIPAddrByName(name
);
478 DWORD
getInterfaceBCastAddrByName(const char *name
)
480 DWORD ret
= INADDR_ANY
;
483 int fd
= socket(PF_INET
, SOCK_DGRAM
, 0);
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
));
498 DWORD
getInterfaceBCastAddrByIndex(DWORD index
)
501 const char *name
= getInterfaceNameByIndex(index
);
504 ret
= getInterfaceBCastAddrByName(name
);
510 DWORD
getInterfaceMaskByName(const char *name
)
512 DWORD ret
= INADDR_NONE
;
515 int fd
= socket(PF_INET
, SOCK_DGRAM
, 0);
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
));
530 DWORD
getInterfaceMaskByIndex(DWORD index
)
533 const char *name
= getInterfaceNameByIndex(index
);
536 ret
= getInterfaceMaskByName(name
);
542 #if defined (SIOCGIFHWADDR)
543 DWORD
getInterfacePhysicalByName(const char *name
, PDWORD len
, PBYTE addr
,
549 if (!name
|| !len
|| !addr
|| !type
)
550 return ERROR_INVALID_PARAMETER
;
552 fd
= socket(PF_INET
, SOCK_DGRAM
, 0);
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
;
564 switch (ifr
.ifr_hwaddr
.sa_family
)
566 case ARPHRD_LOOPBACK
:
568 *type
= MIB_IF_TYPE_LOOPBACK
;
572 *type
= MIB_IF_TYPE_ETHERNET
;
576 *type
= MIB_IF_TYPE_FDDI
;
578 case ARPHRD_IEEE802
: /* 802.2 Ethernet && Token Ring, guess TR? */
580 *type
= MIB_IF_TYPE_TOKENRING
;
582 case ARPHRD_IEEE802_TR
: /* also Token Ring? */
584 *type
= MIB_IF_TYPE_TOKENRING
;
588 *type
= MIB_IF_TYPE_SLIP
;
592 *type
= MIB_IF_TYPE_PPP
;
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
;
604 memcpy(addr
, ifr
.ifr_hwaddr
.sa_data
, addrLen
);
605 /* zero out remaining bytes for broken implementations */
606 memset(addr
+ addrLen
, 0, *len
- addrLen
);
614 ret
= ERROR_NO_MORE_FILES
;
617 #elif defined (SIOCGARP)
618 DWORD
getInterfacePhysicalByName(const char *name
, PDWORD len
, PBYTE addr
,
624 if (!name
|| !len
|| !addr
|| !type
)
625 return ERROR_INVALID_PARAMETER
;
627 fd
= socket(PF_INET
, SOCK_DGRAM
, 0);
629 if (isLoopbackInterface(fd
, name
)) {
630 *type
= MIB_IF_TYPE_LOOPBACK
;
631 memset(addr
, 0, *len
);
636 struct sockaddr_in
*saddr
;
638 memset(&arp
, 0, sizeof(struct arpreq
));
639 arp
.arp_pa
.sa_family
= AF_INET
;
640 saddr
= (struct sockaddr_in
*)&arp
; /* proto addr is first member */
641 saddr
->sin_family
= AF_INET
;
642 saddr
->sin_addr
.s_addr
= getInterfaceAddrByName(name
);
643 if ((ioctl(fd
, SIOCGARP
, &arp
)))
644 ret
= ERROR_INVALID_DATA
;
646 /* FIXME: heh: who said it was ethernet? */
647 int addrLen
= ETH_ALEN
;
649 if (addrLen
> *len
) {
650 ret
= ERROR_INSUFFICIENT_BUFFER
;
655 memcpy(addr
, &arp
.arp_ha
.sa_data
[0], addrLen
);
656 /* zero out remaining bytes for broken implementations */
657 memset(addr
+ addrLen
, 0, *len
- addrLen
);
659 *type
= MIB_IF_TYPE_ETHERNET
;
665 ret
= ERROR_NO_MORE_FILES
;
669 #elif defined (HAVE_SYS_SYSCTL_H) && defined (HAVE_NET_IF_DL_H)
670 DWORD
getInterfacePhysicalByName(const char *name
, PDWORD len
, PBYTE addr
,
674 struct if_msghdr
*ifm
;
675 struct sockaddr_dl
*sdl
;
678 int mib
[] = { CTL_NET
, AF_ROUTE
, 0, AF_LINK
, NET_RT_IFLIST
, 0 };
682 if (!name
|| !len
|| !addr
|| !type
)
683 return ERROR_INVALID_PARAMETER
;
685 if (sysctl(mib
, 6, NULL
, &mibLen
, NULL
, 0) < 0)
686 return ERROR_NO_MORE_FILES
;
688 buf
= (u_char
*)malloc(mibLen
);
690 return ERROR_NOT_ENOUGH_MEMORY
;
692 if (sysctl(mib
, 6, buf
, &mibLen
, NULL
, 0) < 0) {
694 return ERROR_NO_MORE_FILES
;
697 ret
= ERROR_INVALID_DATA
;
698 for (p
= buf
; !found
&& p
< buf
+ mibLen
; p
+= ifm
->ifm_msglen
) {
699 ifm
= (struct if_msghdr
*)p
;
700 sdl
= (struct sockaddr_dl
*)(ifm
+ 1);
702 if (ifm
->ifm_type
!= RTM_IFINFO
|| (ifm
->ifm_addrs
& RTA_IFP
) == 0)
705 if (sdl
->sdl_family
!= AF_LINK
|| sdl
->sdl_nlen
== 0 ||
706 memcmp(sdl
->sdl_data
, name
, max(sdl
->sdl_nlen
, strlen(name
))) != 0)
710 addrLen
= min(MAX_INTERFACE_PHYSADDR
, sdl
->sdl_alen
);
711 if (addrLen
> *len
) {
712 ret
= ERROR_INSUFFICIENT_BUFFER
;
717 memcpy(addr
, LLADDR(sdl
), addrLen
);
718 /* zero out remaining bytes for broken implementations */
719 memset(addr
+ addrLen
, 0, *len
- addrLen
);
721 #if defined(HAVE_NET_IF_TYPES_H)
722 switch (sdl
->sdl_type
)
725 *type
= MIB_IF_TYPE_ETHERNET
;
728 *type
= MIB_IF_TYPE_FDDI
;
730 case IFT_ISO88024
: /* Token Bus */
731 *type
= MIB_IF_TYPE_TOKENRING
;
733 case IFT_ISO88025
: /* Token Ring */
734 *type
= MIB_IF_TYPE_TOKENRING
;
737 *type
= MIB_IF_TYPE_PPP
;
740 *type
= MIB_IF_TYPE_SLIP
;
743 *type
= MIB_IF_TYPE_LOOPBACK
;
746 *type
= MIB_IF_TYPE_OTHER
;
749 /* default if we don't know */
750 *type
= MIB_IF_TYPE_ETHERNET
;
760 DWORD
getInterfacePhysicalByIndex(DWORD index
, PDWORD len
, PBYTE addr
,
763 const char *name
= getInterfaceNameByIndex(index
);
766 return getInterfacePhysicalByName(name
, len
, addr
, type
);
768 return ERROR_INVALID_DATA
;
771 DWORD
getInterfaceMtuByName(const char *name
, PDWORD mtu
)
777 return ERROR_INVALID_PARAMETER
;
779 return ERROR_INVALID_PARAMETER
;
781 fd
= socket(PF_INET
, SOCK_DGRAM
, 0);
785 strncpy(ifr
.ifr_name
, name
, IFNAMSIZ
);
786 ifr
.ifr_name
[IFNAMSIZ
-1] = '\0';
787 if ((ioctl(fd
, SIOCGIFMTU
, &ifr
)))
788 ret
= ERROR_INVALID_DATA
;
795 ret
= ERROR_NO_MORE_FILES
;
799 DWORD
getInterfaceMtuByIndex(DWORD index
, PDWORD mtu
)
801 const char *name
= getInterfaceNameByIndex(index
);
804 return getInterfaceMtuByName(name
, mtu
);
806 return ERROR_INVALID_DATA
;
809 DWORD
getInterfaceStatusByName(const char *name
, PDWORD status
)
815 return ERROR_INVALID_PARAMETER
;
817 return ERROR_INVALID_PARAMETER
;
819 fd
= socket(PF_INET
, SOCK_DGRAM
, 0);
823 strncpy(ifr
.ifr_name
, name
, IFNAMSIZ
);
824 ifr
.ifr_name
[IFNAMSIZ
-1] = '\0';
825 if ((ioctl(fd
, SIOCGIFFLAGS
, &ifr
)))
826 ret
= ERROR_INVALID_DATA
;
828 if (ifr
.ifr_flags
& IFF_UP
)
829 *status
= MIB_IF_OPER_STATUS_OPERATIONAL
;
831 *status
= MIB_IF_OPER_STATUS_NON_OPERATIONAL
;
836 ret
= ERROR_NO_MORE_FILES
;
840 DWORD
getInterfaceStatusByIndex(DWORD index
, PDWORD status
)
842 const char *name
= getInterfaceNameByIndex(index
);
845 return getInterfaceStatusByName(name
, status
);
847 return ERROR_INVALID_DATA
;
850 DWORD
getInterfaceEntryByName(const char *name
, PMIB_IFROW entry
)
852 BYTE addr
[MAX_INTERFACE_PHYSADDR
];
853 DWORD ret
, len
= sizeof(addr
), type
;
856 return ERROR_INVALID_PARAMETER
;
858 return ERROR_INVALID_PARAMETER
;
860 if (getInterfacePhysicalByName(name
, &len
, addr
, &type
) == NO_ERROR
) {
864 memset(entry
, 0, sizeof(MIB_IFROW
));
865 for (assigner
= entry
->wszName
, walker
= name
; *walker
;
866 walker
++, assigner
++)
869 getInterfaceIndexByName(name
, &entry
->dwIndex
);
870 entry
->dwPhysAddrLen
= len
;
871 memcpy(entry
->bPhysAddr
, addr
, len
);
872 memset(entry
->bPhysAddr
+ len
, 0, sizeof(entry
->bPhysAddr
) - len
);
873 entry
->dwType
= type
;
874 /* FIXME: how to calculate real speed? */
875 getInterfaceMtuByName(name
, &entry
->dwMtu
);
876 /* lie, there's no "administratively down" here */
877 entry
->dwAdminStatus
= MIB_IF_ADMIN_STATUS_UP
;
878 getInterfaceStatusByName(name
, &entry
->dwOperStatus
);
879 /* punt on dwLastChange? */
880 entry
->dwDescrLen
= min(strlen(name
), MAX_INTERFACE_DESCRIPTION
- 1);
881 memcpy(entry
->bDescr
, name
, entry
->dwDescrLen
);
882 entry
->bDescr
[entry
->dwDescrLen
] = '\0';
887 ret
= ERROR_INVALID_DATA
;
891 DWORD
getInterfaceEntryByIndex(DWORD index
, PMIB_IFROW entry
)
893 const char *name
= getInterfaceNameByIndex(index
);
896 return getInterfaceEntryByName(name
, entry
);
898 return ERROR_INVALID_DATA
;
901 char *toIPAddressString(unsigned int addr
, char string
[16])
904 struct in_addr iAddr
;
907 /* extra-anal, just to make auditors happy */
908 strncpy(string
, inet_ntoa(iAddr
), 16);