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
37 * There are three implemened methods for determining the MAC address of an
39 * - a specific IOCTL (Linux)
40 * - looking in the ARP cache (at least Solaris)
41 * - using the sysctl interface (FreeBSD and MacOSX)
42 * Solaris and some others have SIOCGENADDR, but I haven't gotten that to work
43 * on the Solaris boxes at SourceForge's compile farm, whereas SIOCGARP does.
57 #include <sys/types.h>
59 #ifdef HAVE_SYS_SOCKET_H
60 #include <sys/socket.h>
63 #ifdef HAVE_NETINET_IN_H
64 #include <netinet/in.h>
67 #ifdef HAVE_ARPA_INET_H
68 #include <arpa/inet.h>
75 #ifdef HAVE_NET_IF_ARP_H
76 #include <net/if_arp.h>
79 #ifdef HAVE_NET_ROUTE_H
80 #include <net/route.h>
83 #ifdef HAVE_SYS_IOCTL_H
84 #include <sys/ioctl.h>
87 #ifdef HAVE_SYS_SYSCTL_H
88 #include <sys/sysctl.h>
91 #ifdef HAVE_SYS_SOCKIO_H
92 #include <sys/sockio.h>
95 #ifdef HAVE_NET_IF_DL_H
96 #include <net/if_dl.h>
99 #ifdef HAVE_NET_IF_TYPES_H
100 #include <net/if_types.h>
105 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
106 #define ifreq_len(ifr) \
107 max(sizeof(struct ifreq), sizeof((ifr)->ifr_name)+(ifr)->ifr_addr.sa_len)
109 #define ifreq_len(ifr) sizeof(struct ifreq)
117 #define INADDR_NONE (~0U)
120 #define INITIAL_INTERFACES_ASSUMED 4
122 #define INDEX_IS_LOOPBACK 0x00800000
124 /* Type declarations */
126 typedef struct _InterfaceNameMapEntry
{
130 } InterfaceNameMapEntry
;
132 typedef struct _InterfaceNameMap
{
136 InterfaceNameMapEntry table
[1];
139 /* Global variables */
141 static CRITICAL_SECTION mapCS
;
142 static InterfaceNameMap
*gNonLoopbackInterfaceMap
= NULL
;
143 static InterfaceNameMap
*gLoopbackInterfaceMap
= NULL
;
147 void interfaceMapInit(void)
149 InitializeCriticalSection(&mapCS
);
152 void interfaceMapFree(void)
154 DeleteCriticalSection(&mapCS
);
155 HeapFree(GetProcessHeap(), 0, gNonLoopbackInterfaceMap
);
156 HeapFree(GetProcessHeap(), 0, gLoopbackInterfaceMap
);
159 /* Sizes the passed-in map to have enough space for numInterfaces interfaces.
160 * If map is NULL, allocates a new map. If it is not, may reallocate the
161 * existing map and return a map of increased size. Returns the allocated map,
162 * or NULL if it could not allocate a map of the requested size.
164 static InterfaceNameMap
*sizeMap(InterfaceNameMap
*map
, DWORD numInterfaces
)
167 numInterfaces
= max(numInterfaces
, INITIAL_INTERFACES_ASSUMED
);
168 map
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
169 sizeof(InterfaceNameMap
) +
170 (numInterfaces
- 1) * sizeof(InterfaceNameMapEntry
));
172 map
->numAllocated
= numInterfaces
;
175 if (map
->numAllocated
< numInterfaces
) {
176 map
= HeapReAlloc(GetProcessHeap(), 0, map
,
177 sizeof(InterfaceNameMap
) +
178 (numInterfaces
- 1) * sizeof(InterfaceNameMapEntry
));
180 memset(&map
->table
[map
->numAllocated
], 0,
181 (numInterfaces
- map
->numAllocated
) * sizeof(InterfaceNameMapEntry
));
187 static int isLoopbackInterface(int fd
, const char *name
)
194 lstrcpynA(ifr
.ifr_name
, name
, IFNAMSIZ
);
195 if (ioctl(fd
, SIOCGIFFLAGS
, &ifr
) == 0)
196 ret
= ifr
.ifr_flags
& IFF_LOOPBACK
;
201 static void countInterfaces(int fd
, caddr_t buf
, size_t len
)
204 DWORD numNonLoopbackInterfaces
= 0, numLoopbackInterfaces
= 0;
206 while (ifPtr
&& ifPtr
< buf
+ len
) {
207 struct ifreq
*ifr
= (struct ifreq
*)ifPtr
;
209 if (isLoopbackInterface(fd
, ifr
->ifr_name
))
210 numLoopbackInterfaces
++;
212 numNonLoopbackInterfaces
++;
213 ifPtr
+= ifreq_len(ifr
);
215 gNonLoopbackInterfaceMap
= sizeMap(gNonLoopbackInterfaceMap
,
216 numNonLoopbackInterfaces
);
217 gLoopbackInterfaceMap
= sizeMap(gLoopbackInterfaceMap
,
218 numLoopbackInterfaces
);
221 /* Stores the name in the given map, and increments the map's numInterfaces
222 * member if stored successfully. Will store in the same slot as previously if
223 * usedLastPass is set, otherwise will store in a new slot.
224 * Assumes map and name are not NULL, and the usedLastPass flag is set
225 * correctly for each entry in the map, and that map->numInterfaces <
227 * FIXME: this is kind of expensive, doing a linear scan of the map with a
228 * string comparison of each entry to find the old slot.
230 static void storeInterfaceInMap(InterfaceNameMap
*map
, const char *name
)
236 /* look for previous slot, mark in use if so */
237 for (ndx
= 0; !stored
&& ndx
< map
->nextAvailable
; ndx
++) {
238 if (map
->table
[ndx
].usedLastPass
&& !strncmp(map
->table
[ndx
].name
, name
,
239 sizeof(map
->table
[ndx
].name
))) {
240 map
->table
[ndx
].inUse
= TRUE
;
244 /* look for new slot */
245 for (ndx
= 0; !stored
&& ndx
< map
->numAllocated
; ndx
++) {
246 if (!map
->table
[ndx
].inUse
) {
247 lstrcpynA(map
->table
[ndx
].name
, name
, IFNAMSIZ
);
248 map
->table
[ndx
].inUse
= TRUE
;
250 if (ndx
>= map
->nextAvailable
)
251 map
->nextAvailable
= ndx
+ 1;
255 map
->numInterfaces
++;
259 /* Sets all used entries' usedLastPass flag to their inUse flag, clears
260 * their inUse flag, and clears their numInterfaces member.
262 static void markOldInterfaces(InterfaceNameMap
*map
)
267 map
->numInterfaces
= 0;
268 for (ndx
= 0; ndx
< map
->nextAvailable
; ndx
++) {
269 map
->table
[ndx
].usedLastPass
= map
->table
[ndx
].inUse
;
270 map
->table
[ndx
].inUse
= FALSE
;
275 static void classifyInterfaces(int fd
, caddr_t buf
, size_t len
)
279 markOldInterfaces(gNonLoopbackInterfaceMap
);
280 markOldInterfaces(gLoopbackInterfaceMap
);
281 while (ifPtr
&& ifPtr
< buf
+ len
) {
282 struct ifreq
*ifr
= (struct ifreq
*)ifPtr
;
284 if (ifr
->ifr_addr
.sa_family
== AF_INET
) {
285 if (isLoopbackInterface(fd
, ifr
->ifr_name
))
286 storeInterfaceInMap(gLoopbackInterfaceMap
, ifr
->ifr_name
);
288 storeInterfaceInMap(gNonLoopbackInterfaceMap
, ifr
->ifr_name
);
290 ifPtr
+= ifreq_len(ifr
);
294 static void enumerateInterfaces(void)
298 fd
= socket(PF_INET
, SOCK_DGRAM
, 0);
300 int ret
, guessedNumInterfaces
;
303 /* try to avoid silly heap action by starting with the right size buffer */
304 guessedNumInterfaces
= 0;
305 if (gNonLoopbackInterfaceMap
)
306 guessedNumInterfaces
+= gNonLoopbackInterfaceMap
->numInterfaces
;
307 if (gLoopbackInterfaceMap
)
308 guessedNumInterfaces
+= gLoopbackInterfaceMap
->numInterfaces
;
311 memset(&ifc
, 0, sizeof(ifc
));
312 /* there is no way to know the interface count beforehand,
313 so we need to loop again and again upping our max each time
314 until returned < max */
316 if (guessedNumInterfaces
== 0)
317 guessedNumInterfaces
= INITIAL_INTERFACES_ASSUMED
;
319 guessedNumInterfaces
*= 2;
320 HeapFree(GetProcessHeap(), 0, ifc
.ifc_buf
);
321 ifc
.ifc_len
= sizeof(struct ifreq
) * guessedNumInterfaces
;
322 ifc
.ifc_buf
= HeapAlloc(GetProcessHeap(), 0, ifc
.ifc_len
);
323 ret
= ioctl(fd
, SIOCGIFCONF
, &ifc
);
325 ifc
.ifc_len
== (sizeof(struct ifreq
) * guessedNumInterfaces
));
328 EnterCriticalSection(&mapCS
);
329 countInterfaces(fd
, ifc
.ifc_buf
, ifc
.ifc_len
);
330 classifyInterfaces(fd
, ifc
.ifc_buf
, ifc
.ifc_len
);
331 LeaveCriticalSection(&mapCS
);
334 HeapFree(GetProcessHeap(), 0, ifc
.ifc_buf
);
339 DWORD
getNumNonLoopbackInterfaces(void)
341 enumerateInterfaces();
342 return gNonLoopbackInterfaceMap
? gNonLoopbackInterfaceMap
->numInterfaces
: 0;
345 DWORD
getNumInterfaces(void)
347 DWORD ret
= getNumNonLoopbackInterfaces();
349 ret
+= gLoopbackInterfaceMap
? gLoopbackInterfaceMap
->numInterfaces
: 0;
353 const char *getInterfaceNameByIndex(DWORD index
)
356 InterfaceNameMap
*map
;
357 const char *ret
= NULL
;
359 EnterCriticalSection(&mapCS
);
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
;
370 LeaveCriticalSection(&mapCS
);
374 DWORD
getInterfaceIndexByName(const char *name
, PDWORD index
)
380 return ERROR_INVALID_PARAMETER
;
382 return ERROR_INVALID_PARAMETER
;
384 EnterCriticalSection(&mapCS
);
385 for (ndx
= 0; !found
&& gNonLoopbackInterfaceMap
&&
386 ndx
< gNonLoopbackInterfaceMap
->nextAvailable
; ndx
++)
387 if (!strncmp(gNonLoopbackInterfaceMap
->table
[ndx
].name
, name
, IFNAMSIZ
)) {
391 for (ndx
= 0; !found
&& gLoopbackInterfaceMap
&&
392 ndx
< gLoopbackInterfaceMap
->nextAvailable
; ndx
++)
393 if (!strncmp(gLoopbackInterfaceMap
->table
[ndx
].name
, name
, IFNAMSIZ
)) {
395 *index
= ndx
| INDEX_IS_LOOPBACK
;
397 LeaveCriticalSection(&mapCS
);
401 ret
= ERROR_INVALID_DATA
;
405 static void addMapEntriesToIndexTable(InterfaceIndexTable
*table
,
406 const InterfaceNameMap
*map
)
411 for (ndx
= 0; ndx
< map
->nextAvailable
&&
412 table
->numIndexes
< table
->numAllocated
; ndx
++)
413 if (map
->table
[ndx
].inUse
) {
414 DWORD externalNdx
= ndx
;
416 if (map
== gLoopbackInterfaceMap
)
417 externalNdx
|= INDEX_IS_LOOPBACK
;
418 table
->indexes
[table
->numIndexes
++] = externalNdx
;
423 InterfaceIndexTable
*getInterfaceIndexTable(void)
426 InterfaceIndexTable
*ret
;
428 EnterCriticalSection(&mapCS
);
429 numInterfaces
= getNumInterfaces();
430 ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
431 sizeof(InterfaceIndexTable
) + (numInterfaces
- 1) * sizeof(DWORD
));
433 ret
->numAllocated
= numInterfaces
;
434 addMapEntriesToIndexTable(ret
, gNonLoopbackInterfaceMap
);
435 addMapEntriesToIndexTable(ret
, gLoopbackInterfaceMap
);
437 LeaveCriticalSection(&mapCS
);
441 InterfaceIndexTable
*getNonLoopbackInterfaceIndexTable(void)
444 InterfaceIndexTable
*ret
;
446 EnterCriticalSection(&mapCS
);
447 numInterfaces
= getNumNonLoopbackInterfaces();
448 ret
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
449 sizeof(InterfaceIndexTable
) + (numInterfaces
- 1) * sizeof(DWORD
));
451 ret
->numAllocated
= numInterfaces
;
452 addMapEntriesToIndexTable(ret
, gNonLoopbackInterfaceMap
);
454 LeaveCriticalSection(&mapCS
);
458 DWORD
getInterfaceIPAddrByName(const char *name
)
460 DWORD ret
= INADDR_ANY
;
463 int fd
= socket(PF_INET
, SOCK_DGRAM
, 0);
468 lstrcpynA(ifr
.ifr_name
, name
, IFNAMSIZ
);
469 if (ioctl(fd
, SIOCGIFADDR
, &ifr
) == 0)
470 memcpy(&ret
, ifr
.ifr_addr
.sa_data
+ 2, sizeof(DWORD
));
477 DWORD
getInterfaceIPAddrByIndex(DWORD index
)
480 const char *name
= getInterfaceNameByIndex(index
);
483 ret
= getInterfaceIPAddrByName(name
);
489 DWORD
getInterfaceBCastAddrByName(const char *name
)
491 DWORD ret
= INADDR_ANY
;
494 int fd
= socket(PF_INET
, SOCK_DGRAM
, 0);
499 lstrcpynA(ifr
.ifr_name
, name
, IFNAMSIZ
);
500 if (ioctl(fd
, SIOCGIFBRDADDR
, &ifr
) == 0)
501 memcpy(&ret
, ifr
.ifr_addr
.sa_data
+ 2, sizeof(DWORD
));
508 DWORD
getInterfaceBCastAddrByIndex(DWORD index
)
511 const char *name
= getInterfaceNameByIndex(index
);
514 ret
= getInterfaceBCastAddrByName(name
);
520 DWORD
getInterfaceMaskByName(const char *name
)
522 DWORD ret
= INADDR_NONE
;
525 int fd
= socket(PF_INET
, SOCK_DGRAM
, 0);
530 lstrcpynA(ifr
.ifr_name
, name
, IFNAMSIZ
);
531 if (ioctl(fd
, SIOCGIFNETMASK
, &ifr
) == 0)
532 memcpy(&ret
, ifr
.ifr_addr
.sa_data
+ 2, sizeof(DWORD
));
539 DWORD
getInterfaceMaskByIndex(DWORD index
)
542 const char *name
= getInterfaceNameByIndex(index
);
545 ret
= getInterfaceMaskByName(name
);
551 #if defined (SIOCGIFHWADDR)
552 DWORD
getInterfacePhysicalByName(const char *name
, PDWORD len
, PBYTE addr
,
558 if (!name
|| !len
|| !addr
|| !type
)
559 return ERROR_INVALID_PARAMETER
;
561 fd
= socket(PF_INET
, SOCK_DGRAM
, 0);
565 memset(&ifr
, 0, sizeof(struct ifreq
));
566 lstrcpynA(ifr
.ifr_name
, name
, IFNAMSIZ
);
567 if ((ioctl(fd
, SIOCGIFHWADDR
, &ifr
)))
568 ret
= ERROR_INVALID_DATA
;
570 unsigned int addrLen
;
572 switch (ifr
.ifr_hwaddr
.sa_family
)
574 #ifdef ARPHRD_LOOPBACK
575 case ARPHRD_LOOPBACK
:
577 *type
= MIB_IF_TYPE_LOOPBACK
;
583 *type
= MIB_IF_TYPE_ETHERNET
;
589 *type
= MIB_IF_TYPE_FDDI
;
592 #ifdef ARPHRD_IEEE802
593 case ARPHRD_IEEE802
: /* 802.2 Ethernet && Token Ring, guess TR? */
595 *type
= MIB_IF_TYPE_TOKENRING
;
598 #ifdef ARPHRD_IEEE802_TR
599 case ARPHRD_IEEE802_TR
: /* also Token Ring? */
601 *type
= MIB_IF_TYPE_TOKENRING
;
607 *type
= MIB_IF_TYPE_SLIP
;
613 *type
= MIB_IF_TYPE_PPP
;
617 addrLen
= min(MAX_INTERFACE_PHYSADDR
, sizeof(ifr
.ifr_hwaddr
.sa_data
));
618 *type
= MIB_IF_TYPE_OTHER
;
620 if (addrLen
> *len
) {
621 ret
= ERROR_INSUFFICIENT_BUFFER
;
626 memcpy(addr
, ifr
.ifr_hwaddr
.sa_data
, addrLen
);
627 /* zero out remaining bytes for broken implementations */
628 memset(addr
+ addrLen
, 0, *len
- addrLen
);
636 ret
= ERROR_NO_MORE_FILES
;
639 #elif defined (SIOCGARP)
640 DWORD
getInterfacePhysicalByName(const char *name
, PDWORD len
, PBYTE addr
,
646 if (!name
|| !len
|| !addr
|| !type
)
647 return ERROR_INVALID_PARAMETER
;
649 fd
= socket(PF_INET
, SOCK_DGRAM
, 0);
651 if (isLoopbackInterface(fd
, name
)) {
652 *type
= MIB_IF_TYPE_LOOPBACK
;
653 memset(addr
, 0, *len
);
659 struct sockaddr_in
*saddr
;
661 memset(&arp
, 0, sizeof(struct arpreq
));
662 arp
.arp_pa
.sa_family
= AF_INET
;
663 saddr
= (struct sockaddr_in
*)&arp
; /* proto addr is first member */
664 saddr
->sin_family
= AF_INET
;
665 saddr
->sin_addr
.s_addr
= getInterfaceIPAddrByName(name
);
666 if ((ioctl(fd
, SIOCGARP
, &arp
)))
667 ret
= ERROR_INVALID_DATA
;
669 /* FIXME: heh: who said it was ethernet? */
670 int addrLen
= ETH_ALEN
;
672 if (addrLen
> *len
) {
673 ret
= ERROR_INSUFFICIENT_BUFFER
;
678 memcpy(addr
, &arp
.arp_ha
.sa_data
[0], addrLen
);
679 /* zero out remaining bytes for broken implementations */
680 memset(addr
+ addrLen
, 0, *len
- addrLen
);
682 *type
= MIB_IF_TYPE_ETHERNET
;
690 ret
= ERROR_NO_MORE_FILES
;
694 #elif defined (HAVE_SYS_SYSCTL_H) && defined (HAVE_NET_IF_DL_H)
695 DWORD
getInterfacePhysicalByName(const char *name
, PDWORD len
, PBYTE addr
,
699 struct if_msghdr
*ifm
;
700 struct sockaddr_dl
*sdl
;
703 int mib
[] = { CTL_NET
, AF_ROUTE
, 0, AF_LINK
, NET_RT_IFLIST
, 0 };
707 if (!name
|| !len
|| !addr
|| !type
)
708 return ERROR_INVALID_PARAMETER
;
710 if (sysctl(mib
, 6, NULL
, &mibLen
, NULL
, 0) < 0)
711 return ERROR_NO_MORE_FILES
;
713 buf
= HeapAlloc(GetProcessHeap(), 0, mibLen
);
715 return ERROR_NOT_ENOUGH_MEMORY
;
717 if (sysctl(mib
, 6, buf
, &mibLen
, NULL
, 0) < 0) {
718 HeapFree(GetProcessHeap(), 0, buf
);
719 return ERROR_NO_MORE_FILES
;
722 ret
= ERROR_INVALID_DATA
;
723 for (p
= buf
; !found
&& p
< buf
+ mibLen
; p
+= ifm
->ifm_msglen
) {
724 ifm
= (struct if_msghdr
*)p
;
725 sdl
= (struct sockaddr_dl
*)(ifm
+ 1);
727 if (ifm
->ifm_type
!= RTM_IFINFO
|| (ifm
->ifm_addrs
& RTA_IFP
) == 0)
730 if (sdl
->sdl_family
!= AF_LINK
|| sdl
->sdl_nlen
== 0 ||
731 memcmp(sdl
->sdl_data
, name
, max(sdl
->sdl_nlen
, strlen(name
))) != 0)
735 addrLen
= min(MAX_INTERFACE_PHYSADDR
, sdl
->sdl_alen
);
736 if (addrLen
> *len
) {
737 ret
= ERROR_INSUFFICIENT_BUFFER
;
742 memcpy(addr
, LLADDR(sdl
), addrLen
);
743 /* zero out remaining bytes for broken implementations */
744 memset(addr
+ addrLen
, 0, *len
- addrLen
);
746 #if defined(HAVE_NET_IF_TYPES_H)
747 switch (sdl
->sdl_type
)
750 *type
= MIB_IF_TYPE_ETHERNET
;
753 *type
= MIB_IF_TYPE_FDDI
;
755 case IFT_ISO88024
: /* Token Bus */
756 *type
= MIB_IF_TYPE_TOKENRING
;
758 case IFT_ISO88025
: /* Token Ring */
759 *type
= MIB_IF_TYPE_TOKENRING
;
762 *type
= MIB_IF_TYPE_PPP
;
765 *type
= MIB_IF_TYPE_SLIP
;
768 *type
= MIB_IF_TYPE_LOOPBACK
;
771 *type
= MIB_IF_TYPE_OTHER
;
774 /* default if we don't know */
775 *type
= MIB_IF_TYPE_ETHERNET
;
780 HeapFree(GetProcessHeap(), 0, buf
);
785 DWORD
getInterfacePhysicalByIndex(DWORD index
, PDWORD len
, PBYTE addr
,
788 const char *name
= getInterfaceNameByIndex(index
);
791 return getInterfacePhysicalByName(name
, len
, addr
, type
);
793 return ERROR_INVALID_DATA
;
796 DWORD
getInterfaceMtuByName(const char *name
, PDWORD mtu
)
802 return ERROR_INVALID_PARAMETER
;
804 return ERROR_INVALID_PARAMETER
;
806 fd
= socket(PF_INET
, SOCK_DGRAM
, 0);
810 lstrcpynA(ifr
.ifr_name
, name
, IFNAMSIZ
);
811 if ((ioctl(fd
, SIOCGIFMTU
, &ifr
)))
812 ret
= ERROR_INVALID_DATA
;
817 *mtu
= ifr
.ifr_metric
;
824 ret
= ERROR_NO_MORE_FILES
;
828 DWORD
getInterfaceMtuByIndex(DWORD index
, PDWORD mtu
)
830 const char *name
= getInterfaceNameByIndex(index
);
833 return getInterfaceMtuByName(name
, mtu
);
835 return ERROR_INVALID_DATA
;
838 DWORD
getInterfaceStatusByName(const char *name
, PDWORD status
)
844 return ERROR_INVALID_PARAMETER
;
846 return ERROR_INVALID_PARAMETER
;
848 fd
= socket(PF_INET
, SOCK_DGRAM
, 0);
852 lstrcpynA(ifr
.ifr_name
, name
, IFNAMSIZ
);
853 if ((ioctl(fd
, SIOCGIFFLAGS
, &ifr
)))
854 ret
= ERROR_INVALID_DATA
;
856 if (ifr
.ifr_flags
& IFF_UP
)
857 *status
= MIB_IF_OPER_STATUS_OPERATIONAL
;
859 *status
= MIB_IF_OPER_STATUS_NON_OPERATIONAL
;
865 ret
= ERROR_NO_MORE_FILES
;
869 DWORD
getInterfaceStatusByIndex(DWORD index
, PDWORD status
)
871 const char *name
= getInterfaceNameByIndex(index
);
874 return getInterfaceStatusByName(name
, status
);
876 return ERROR_INVALID_DATA
;
879 DWORD
getInterfaceEntryByName(const char *name
, PMIB_IFROW entry
)
881 BYTE addr
[MAX_INTERFACE_PHYSADDR
];
882 DWORD ret
, len
= sizeof(addr
), type
;
885 return ERROR_INVALID_PARAMETER
;
887 return ERROR_INVALID_PARAMETER
;
889 if (getInterfacePhysicalByName(name
, &len
, addr
, &type
) == NO_ERROR
) {
893 memset(entry
, 0, sizeof(MIB_IFROW
));
894 for (assigner
= entry
->wszName
, walker
= name
; *walker
;
895 walker
++, assigner
++)
898 getInterfaceIndexByName(name
, &entry
->dwIndex
);
899 entry
->dwPhysAddrLen
= len
;
900 memcpy(entry
->bPhysAddr
, addr
, len
);
901 memset(entry
->bPhysAddr
+ len
, 0, sizeof(entry
->bPhysAddr
) - len
);
902 entry
->dwType
= type
;
903 /* FIXME: how to calculate real speed? */
904 getInterfaceMtuByName(name
, &entry
->dwMtu
);
905 /* lie, there's no "administratively down" here */
906 entry
->dwAdminStatus
= MIB_IF_ADMIN_STATUS_UP
;
907 getInterfaceStatusByName(name
, &entry
->dwOperStatus
);
908 /* punt on dwLastChange? */
909 entry
->dwDescrLen
= min(strlen(name
), MAX_INTERFACE_DESCRIPTION
- 1);
910 memcpy(entry
->bDescr
, name
, entry
->dwDescrLen
);
911 entry
->bDescr
[entry
->dwDescrLen
] = '\0';
916 ret
= ERROR_INVALID_DATA
;
920 DWORD
getInterfaceEntryByIndex(DWORD index
, PMIB_IFROW entry
)
922 const char *name
= getInterfaceNameByIndex(index
);
925 return getInterfaceEntryByName(name
, entry
);
927 return ERROR_INVALID_DATA
;
930 char *toIPAddressString(unsigned int addr
, char string
[16])
933 struct in_addr iAddr
;
936 /* extra-anal, just to make auditors happy */
937 lstrcpynA(string
, inet_ntoa(iAddr
), 16);