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.
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
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.
58 #include <sys/types.h>
60 #ifdef HAVE_SYS_SOCKET_H
61 #include <sys/socket.h>
64 #ifdef HAVE_NETINET_IN_H
65 #include <netinet/in.h>
68 #ifdef HAVE_ARPA_INET_H
69 #include <arpa/inet.h>
76 #ifdef HAVE_NET_IF_ARP_H
77 #include <net/if_arp.h>
80 #ifdef HAVE_NET_ROUTE_H
81 #include <net/route.h>
84 #ifdef HAVE_SYS_IOCTL_H
85 #include <sys/ioctl.h>
88 #ifdef HAVE_SYS_SYSCTL_H
89 #include <sys/sysctl.h>
92 #ifdef HAVE_SYS_SOCKIO_H
93 #include <sys/sockio.h>
96 #ifdef HAVE_NET_IF_DL_H
97 #include <net/if_dl.h>
100 #ifdef HAVE_NET_IF_TYPES_H
101 #include <net/if_types.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)
110 #define ifreq_len(ifr) sizeof(struct ifreq)
118 #define INADDR_NONE (~0U)
121 #define INITIAL_INTERFACES_ASSUMED 4
123 #define INDEX_IS_LOOPBACK 0x00800000
125 /* Type declarations */
127 typedef struct _InterfaceNameMapEntry
{
131 } InterfaceNameMapEntry
;
133 typedef struct _InterfaceNameMap
{
137 InterfaceNameMapEntry table
[1];
140 /* Global variables */
142 static CRITICAL_SECTION mapCS
;
143 static InterfaceNameMap
*gNonLoopbackInterfaceMap
= NULL
;
144 static InterfaceNameMap
*gLoopbackInterfaceMap
= NULL
;
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
)
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 (ifr
->ifr_addr
.sa_family
== AF_INET
) {
288 if (isLoopbackInterface(fd
, ifr
->ifr_name
))
289 storeInterfaceInMap(gLoopbackInterfaceMap
, ifr
->ifr_name
);
291 storeInterfaceInMap(gNonLoopbackInterfaceMap
, ifr
->ifr_name
);
293 ifPtr
+= ifreq_len(ifr
);
297 static void enumerateInterfaces(void)
301 fd
= socket(PF_INET
, SOCK_DGRAM
, 0);
303 int ret
, guessedNumInterfaces
;
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
;
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 */
319 if (guessedNumInterfaces
== 0)
320 guessedNumInterfaces
= INITIAL_INTERFACES_ASSUMED
;
322 guessedNumInterfaces
*= 2;
325 ifc
.ifc_len
= sizeof(struct ifreq
) * guessedNumInterfaces
;
326 ifc
.ifc_buf
= (char *)malloc(ifc
.ifc_len
);
327 ret
= ioctl(fd
, SIOCGIFCONF
, &ifc
);
329 ifc
.ifc_len
== (sizeof(struct ifreq
) * guessedNumInterfaces
));
332 EnterCriticalSection(&mapCS
);
333 countInterfaces(fd
, ifc
.ifc_buf
, ifc
.ifc_len
);
334 classifyInterfaces(fd
, ifc
.ifc_buf
, ifc
.ifc_len
);
335 LeaveCriticalSection(&mapCS
);
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;
358 const char *getInterfaceNameByIndex(DWORD index
)
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
;
371 map
= gNonLoopbackInterfaceMap
;
373 if (map
&& realIndex
< map
->nextAvailable
)
374 ret
= map
->table
[realIndex
].name
;
375 LeaveCriticalSection(&mapCS
);
379 DWORD
getInterfaceIndexByName(const char *name
, PDWORD index
)
385 return ERROR_INVALID_PARAMETER
;
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
)) {
396 for (ndx
= 0; !found
&& gLoopbackInterfaceMap
&&
397 ndx
< gLoopbackInterfaceMap
->nextAvailable
; ndx
++)
398 if (!strncmp(gLoopbackInterfaceMap
->table
[ndx
].name
, name
, IFNAMSIZ
)) {
400 *index
= ndx
| INDEX_IS_LOOPBACK
;
402 LeaveCriticalSection(&mapCS
);
406 ret
= ERROR_INVALID_DATA
;
410 static void addMapEntriesToIndexTable(InterfaceIndexTable
*table
,
411 const InterfaceNameMap
*map
)
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)
431 InterfaceIndexTable
*ret
;
433 EnterCriticalSection(&mapCS
);
434 numInterfaces
= getNumInterfaces();
435 ret
= (InterfaceIndexTable
*)calloc(1,
436 sizeof(InterfaceIndexTable
) + (numInterfaces
- 1) * sizeof(DWORD
));
438 ret
->numAllocated
= numInterfaces
;
439 addMapEntriesToIndexTable(ret
, gNonLoopbackInterfaceMap
);
440 addMapEntriesToIndexTable(ret
, gLoopbackInterfaceMap
);
442 LeaveCriticalSection(&mapCS
);
446 InterfaceIndexTable
*getNonLoopbackInterfaceIndexTable(void)
449 InterfaceIndexTable
*ret
;
451 EnterCriticalSection(&mapCS
);
452 numInterfaces
= getNumNonLoopbackInterfaces();
453 ret
= (InterfaceIndexTable
*)calloc(1,
454 sizeof(InterfaceIndexTable
) + (numInterfaces
- 1) * sizeof(DWORD
));
456 ret
->numAllocated
= numInterfaces
;
457 addMapEntriesToIndexTable(ret
, gNonLoopbackInterfaceMap
);
459 LeaveCriticalSection(&mapCS
);
463 DWORD
getInterfaceIPAddrByName(const char *name
)
465 DWORD ret
= INADDR_ANY
;
468 int fd
= socket(PF_INET
, SOCK_DGRAM
, 0);
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
));
483 DWORD
getInterfaceIPAddrByIndex(DWORD index
)
486 const char *name
= getInterfaceNameByIndex(index
);
489 ret
= getInterfaceIPAddrByName(name
);
495 DWORD
getInterfaceBCastAddrByName(const char *name
)
497 DWORD ret
= INADDR_ANY
;
500 int fd
= socket(PF_INET
, SOCK_DGRAM
, 0);
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
));
515 DWORD
getInterfaceBCastAddrByIndex(DWORD index
)
518 const char *name
= getInterfaceNameByIndex(index
);
521 ret
= getInterfaceBCastAddrByName(name
);
527 DWORD
getInterfaceMaskByName(const char *name
)
529 DWORD ret
= INADDR_NONE
;
532 int fd
= socket(PF_INET
, SOCK_DGRAM
, 0);
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
));
547 DWORD
getInterfaceMaskByIndex(DWORD index
)
550 const char *name
= getInterfaceNameByIndex(index
);
553 ret
= getInterfaceMaskByName(name
);
559 #if defined (SIOCGIFHWADDR)
560 DWORD
getInterfacePhysicalByName(const char *name
, PDWORD len
, PBYTE addr
,
566 if (!name
|| !len
|| !addr
|| !type
)
567 return ERROR_INVALID_PARAMETER
;
569 fd
= socket(PF_INET
, SOCK_DGRAM
, 0);
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
;
581 switch (ifr
.ifr_hwaddr
.sa_family
)
583 #ifdef ARPHRD_LOOPBACK
584 case ARPHRD_LOOPBACK
:
586 *type
= MIB_IF_TYPE_LOOPBACK
;
592 *type
= MIB_IF_TYPE_ETHERNET
;
598 *type
= MIB_IF_TYPE_FDDI
;
601 #ifdef ARPHRD_IEEE802
602 case ARPHRD_IEEE802
: /* 802.2 Ethernet && Token Ring, guess TR? */
604 *type
= MIB_IF_TYPE_TOKENRING
;
607 #ifdef ARPHRD_IEEE802_TR
608 case ARPHRD_IEEE802_TR
: /* also Token Ring? */
610 *type
= MIB_IF_TYPE_TOKENRING
;
616 *type
= MIB_IF_TYPE_SLIP
;
622 *type
= MIB_IF_TYPE_PPP
;
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
;
635 memcpy(addr
, ifr
.ifr_hwaddr
.sa_data
, addrLen
);
636 /* zero out remaining bytes for broken implementations */
637 memset(addr
+ addrLen
, 0, *len
- addrLen
);
645 ret
= ERROR_NO_MORE_FILES
;
648 #elif defined (SIOCGARP)
649 DWORD
getInterfacePhysicalByName(const char *name
, PDWORD len
, PBYTE addr
,
655 if (!name
|| !len
|| !addr
|| !type
)
656 return ERROR_INVALID_PARAMETER
;
658 fd
= socket(PF_INET
, SOCK_DGRAM
, 0);
660 if (isLoopbackInterface(fd
, name
)) {
661 *type
= MIB_IF_TYPE_LOOPBACK
;
662 memset(addr
, 0, *len
);
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
;
678 /* FIXME: heh: who said it was ethernet? */
679 int addrLen
= ETH_ALEN
;
681 if (addrLen
> *len
) {
682 ret
= ERROR_INSUFFICIENT_BUFFER
;
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
);
691 *type
= MIB_IF_TYPE_ETHERNET
;
699 ret
= ERROR_NO_MORE_FILES
;
703 #elif defined (HAVE_SYS_SYSCTL_H) && defined (HAVE_NET_IF_DL_H)
704 DWORD
getInterfacePhysicalByName(const char *name
, PDWORD len
, PBYTE addr
,
708 struct if_msghdr
*ifm
;
709 struct sockaddr_dl
*sdl
;
712 int mib
[] = { CTL_NET
, AF_ROUTE
, 0, AF_LINK
, NET_RT_IFLIST
, 0 };
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
);
724 return ERROR_NOT_ENOUGH_MEMORY
;
726 if (sysctl(mib
, 6, buf
, &mibLen
, NULL
, 0) < 0) {
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)
739 if (sdl
->sdl_family
!= AF_LINK
|| sdl
->sdl_nlen
== 0 ||
740 memcmp(sdl
->sdl_data
, name
, max(sdl
->sdl_nlen
, strlen(name
))) != 0)
744 addrLen
= min(MAX_INTERFACE_PHYSADDR
, sdl
->sdl_alen
);
745 if (addrLen
> *len
) {
746 ret
= ERROR_INSUFFICIENT_BUFFER
;
751 memcpy(addr
, LLADDR(sdl
), addrLen
);
752 /* zero out remaining bytes for broken implementations */
753 memset(addr
+ addrLen
, 0, *len
- addrLen
);
755 #if defined(HAVE_NET_IF_TYPES_H)
756 switch (sdl
->sdl_type
)
759 *type
= MIB_IF_TYPE_ETHERNET
;
762 *type
= MIB_IF_TYPE_FDDI
;
764 case IFT_ISO88024
: /* Token Bus */
765 *type
= MIB_IF_TYPE_TOKENRING
;
767 case IFT_ISO88025
: /* Token Ring */
768 *type
= MIB_IF_TYPE_TOKENRING
;
771 *type
= MIB_IF_TYPE_PPP
;
774 *type
= MIB_IF_TYPE_SLIP
;
777 *type
= MIB_IF_TYPE_LOOPBACK
;
780 *type
= MIB_IF_TYPE_OTHER
;
783 /* default if we don't know */
784 *type
= MIB_IF_TYPE_ETHERNET
;
794 DWORD
getInterfacePhysicalByIndex(DWORD index
, PDWORD len
, PBYTE addr
,
797 const char *name
= getInterfaceNameByIndex(index
);
800 return getInterfacePhysicalByName(name
, len
, addr
, type
);
802 return ERROR_INVALID_DATA
;
805 DWORD
getInterfaceMtuByName(const char *name
, PDWORD mtu
)
811 return ERROR_INVALID_PARAMETER
;
813 return ERROR_INVALID_PARAMETER
;
815 fd
= socket(PF_INET
, SOCK_DGRAM
, 0);
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
;
827 *mtu
= ifr
.ifr_metric
;
833 ret
= ERROR_NO_MORE_FILES
;
837 DWORD
getInterfaceMtuByIndex(DWORD index
, PDWORD mtu
)
839 const char *name
= getInterfaceNameByIndex(index
);
842 return getInterfaceMtuByName(name
, mtu
);
844 return ERROR_INVALID_DATA
;
847 DWORD
getInterfaceStatusByName(const char *name
, PDWORD status
)
853 return ERROR_INVALID_PARAMETER
;
855 return ERROR_INVALID_PARAMETER
;
857 fd
= socket(PF_INET
, SOCK_DGRAM
, 0);
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
;
866 if (ifr
.ifr_flags
& IFF_UP
)
867 *status
= MIB_IF_OPER_STATUS_OPERATIONAL
;
869 *status
= MIB_IF_OPER_STATUS_NON_OPERATIONAL
;
874 ret
= ERROR_NO_MORE_FILES
;
878 DWORD
getInterfaceStatusByIndex(DWORD index
, PDWORD status
)
880 const char *name
= getInterfaceNameByIndex(index
);
883 return getInterfaceStatusByName(name
, status
);
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
;
894 return ERROR_INVALID_PARAMETER
;
896 return ERROR_INVALID_PARAMETER
;
898 if (getInterfacePhysicalByName(name
, &len
, addr
, &type
) == NO_ERROR
) {
902 memset(entry
, 0, sizeof(MIB_IFROW
));
903 for (assigner
= entry
->wszName
, walker
= name
; *walker
;
904 walker
++, assigner
++)
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';
925 ret
= ERROR_INVALID_DATA
;
929 DWORD
getInterfaceEntryByIndex(DWORD index
, PMIB_IFROW entry
)
931 const char *name
= getInterfaceNameByIndex(index
);
934 return getInterfaceEntryByName(name
, entry
);
936 return ERROR_INVALID_DATA
;
939 char *toIPAddressString(unsigned int addr
, char string
[16])
942 struct in_addr iAddr
;
945 /* extra-anal, just to make auditors happy */
946 strncpy(string
, inet_ntoa(iAddr
), 16);