wininet: Handle NULL lpBuffersIn in HttpSendRequestExW.
[wine/multimedia.git] / dlls / iphlpapi / ifenum.c
blob63a66aff17beacbe1b4c2b7381127e5f60ed9333
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
37 * There are three implemened methods for determining the MAC address of an
38 * interface:
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.
46 #include "config.h"
48 #include <stdarg.h>
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
53 #ifdef HAVE_UNISTD_H
54 #include <unistd.h>
55 #endif
57 #include <sys/types.h>
59 #ifdef HAVE_SYS_SOCKET_H
60 #include <sys/socket.h>
61 #endif
63 #ifdef HAVE_NETINET_IN_H
64 #include <netinet/in.h>
65 #endif
67 #ifdef HAVE_ARPA_INET_H
68 #include <arpa/inet.h>
69 #endif
71 #ifdef HAVE_NET_IF_H
72 #include <net/if.h>
73 #endif
75 #ifdef HAVE_NET_IF_ARP_H
76 #include <net/if_arp.h>
77 #endif
79 #ifdef HAVE_NET_ROUTE_H
80 #include <net/route.h>
81 #endif
83 #ifdef HAVE_SYS_IOCTL_H
84 #include <sys/ioctl.h>
85 #endif
87 #ifdef HAVE_SYS_SYSCTL_H
88 #include <sys/sysctl.h>
89 #endif
91 #ifdef HAVE_SYS_SOCKIO_H
92 #include <sys/sockio.h>
93 #endif
95 #ifdef HAVE_NET_IF_DL_H
96 #include <net/if_dl.h>
97 #endif
99 #ifdef HAVE_NET_IF_TYPES_H
100 #include <net/if_types.h>
101 #endif
103 #include "ifenum.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)
108 #else
109 #define ifreq_len(ifr) sizeof(struct ifreq)
110 #endif
112 #ifndef ETH_ALEN
113 #define ETH_ALEN 6
114 #endif
116 #ifndef INADDR_NONE
117 #define INADDR_NONE (~0U)
118 #endif
120 #define INITIAL_INTERFACES_ASSUMED 4
122 #define INDEX_IS_LOOPBACK 0x00800000
124 /* Type declarations */
126 typedef struct _InterfaceNameMapEntry {
127 char name[IFNAMSIZ];
128 BOOL inUse;
129 BOOL usedLastPass;
130 } InterfaceNameMapEntry;
132 typedef struct _InterfaceNameMap {
133 DWORD numInterfaces;
134 DWORD nextAvailable;
135 DWORD numAllocated;
136 InterfaceNameMapEntry table[1];
137 } InterfaceNameMap;
139 /* Global variables */
141 static CRITICAL_SECTION mapCS;
142 static InterfaceNameMap *gNonLoopbackInterfaceMap = NULL;
143 static InterfaceNameMap *gLoopbackInterfaceMap = NULL;
145 /* Functions */
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)
166 if (!map) {
167 numInterfaces = max(numInterfaces, INITIAL_INTERFACES_ASSUMED);
168 map = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
169 sizeof(InterfaceNameMap) +
170 (numInterfaces - 1) * sizeof(InterfaceNameMapEntry));
171 if (map)
172 map->numAllocated = numInterfaces;
174 else {
175 if (map->numAllocated < numInterfaces) {
176 map = HeapReAlloc(GetProcessHeap(), 0, map,
177 sizeof(InterfaceNameMap) +
178 (numInterfaces - 1) * sizeof(InterfaceNameMapEntry));
179 if (map)
180 memset(&map->table[map->numAllocated], 0,
181 (numInterfaces - map->numAllocated) * sizeof(InterfaceNameMapEntry));
184 return map;
187 static int isLoopbackInterface(int fd, const char *name)
189 int ret = 0;
191 if (name) {
192 struct ifreq ifr;
194 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
195 if (ioctl(fd, SIOCGIFFLAGS, &ifr) == 0)
196 ret = ifr.ifr_flags & IFF_LOOPBACK;
198 return ret;
201 static void countInterfaces(int fd, caddr_t buf, size_t len)
203 caddr_t ifPtr = buf;
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++;
211 else
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 <
226 * map->numAllocated.
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)
232 if (map && name) {
233 DWORD ndx;
234 BOOL stored = FALSE;
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;
241 stored = 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;
249 stored = TRUE;
250 if (ndx >= map->nextAvailable)
251 map->nextAvailable = ndx + 1;
254 if (stored)
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)
264 if (map) {
265 DWORD ndx;
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)
277 caddr_t ifPtr = buf;
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);
287 else
288 storeInterfaceInMap(gNonLoopbackInterfaceMap, ifr->ifr_name);
290 ifPtr += ifreq_len(ifr);
294 static void enumerateInterfaces(void)
296 int fd;
298 fd = socket(PF_INET, SOCK_DGRAM, 0);
299 if (fd != -1) {
300 int ret, guessedNumInterfaces;
301 struct ifconf ifc;
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;
310 ret = 0;
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 */
315 do {
316 if (guessedNumInterfaces == 0)
317 guessedNumInterfaces = INITIAL_INTERFACES_ASSUMED;
318 else
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);
324 } while (ret == 0 &&
325 ifc.ifc_len == (sizeof(struct ifreq) * guessedNumInterfaces));
327 if (ret == 0) {
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);
335 close(fd);
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;
350 return ret;
353 const char *getInterfaceNameByIndex(DWORD index)
355 DWORD realIndex;
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;
364 else {
365 realIndex = index;
366 map = gNonLoopbackInterfaceMap;
368 if (map && realIndex < map->nextAvailable)
369 ret = map->table[realIndex].name;
370 LeaveCriticalSection(&mapCS);
371 return ret;
374 DWORD getInterfaceIndexByName(const char *name, PDWORD index)
376 DWORD ndx, ret;
377 BOOL found = FALSE;
379 if (!name)
380 return ERROR_INVALID_PARAMETER;
381 if (!index)
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)) {
388 found = TRUE;
389 *index = ndx;
391 for (ndx = 0; !found && gLoopbackInterfaceMap &&
392 ndx < gLoopbackInterfaceMap->nextAvailable; ndx++)
393 if (!strncmp(gLoopbackInterfaceMap->table[ndx].name, name, IFNAMSIZ)) {
394 found = TRUE;
395 *index = ndx | INDEX_IS_LOOPBACK;
397 LeaveCriticalSection(&mapCS);
398 if (found)
399 ret = NO_ERROR;
400 else
401 ret = ERROR_INVALID_DATA;
402 return ret;
405 static void addMapEntriesToIndexTable(InterfaceIndexTable *table,
406 const InterfaceNameMap *map)
408 if (table && map) {
409 DWORD ndx;
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)
425 DWORD numInterfaces;
426 InterfaceIndexTable *ret;
428 EnterCriticalSection(&mapCS);
429 numInterfaces = getNumInterfaces();
430 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
431 sizeof(InterfaceIndexTable) + (numInterfaces - 1) * sizeof(DWORD));
432 if (ret) {
433 ret->numAllocated = numInterfaces;
434 addMapEntriesToIndexTable(ret, gNonLoopbackInterfaceMap);
435 addMapEntriesToIndexTable(ret, gLoopbackInterfaceMap);
437 LeaveCriticalSection(&mapCS);
438 return ret;
441 InterfaceIndexTable *getNonLoopbackInterfaceIndexTable(void)
443 DWORD numInterfaces;
444 InterfaceIndexTable *ret;
446 EnterCriticalSection(&mapCS);
447 numInterfaces = getNumNonLoopbackInterfaces();
448 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
449 sizeof(InterfaceIndexTable) + (numInterfaces - 1) * sizeof(DWORD));
450 if (ret) {
451 ret->numAllocated = numInterfaces;
452 addMapEntriesToIndexTable(ret, gNonLoopbackInterfaceMap);
454 LeaveCriticalSection(&mapCS);
455 return ret;
458 DWORD getInterfaceIPAddrByName(const char *name)
460 DWORD ret = INADDR_ANY;
462 if (name) {
463 int fd = socket(PF_INET, SOCK_DGRAM, 0);
465 if (fd != -1) {
466 struct ifreq ifr;
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));
471 close(fd);
474 return ret;
477 DWORD getInterfaceIPAddrByIndex(DWORD index)
479 DWORD ret;
480 const char *name = getInterfaceNameByIndex(index);
482 if (name)
483 ret = getInterfaceIPAddrByName(name);
484 else
485 ret = INADDR_ANY;
486 return ret;
489 DWORD getInterfaceBCastAddrByName(const char *name)
491 DWORD ret = INADDR_ANY;
493 if (name) {
494 int fd = socket(PF_INET, SOCK_DGRAM, 0);
496 if (fd != -1) {
497 struct ifreq ifr;
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));
502 close(fd);
505 return ret;
508 DWORD getInterfaceBCastAddrByIndex(DWORD index)
510 DWORD ret;
511 const char *name = getInterfaceNameByIndex(index);
513 if (name)
514 ret = getInterfaceBCastAddrByName(name);
515 else
516 ret = INADDR_ANY;
517 return ret;
520 DWORD getInterfaceMaskByName(const char *name)
522 DWORD ret = INADDR_NONE;
524 if (name) {
525 int fd = socket(PF_INET, SOCK_DGRAM, 0);
527 if (fd != -1) {
528 struct ifreq ifr;
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));
533 close(fd);
536 return ret;
539 DWORD getInterfaceMaskByIndex(DWORD index)
541 DWORD ret;
542 const char *name = getInterfaceNameByIndex(index);
544 if (name)
545 ret = getInterfaceMaskByName(name);
546 else
547 ret = INADDR_NONE;
548 return ret;
551 #if defined (SIOCGIFHWADDR)
552 DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
553 PDWORD type)
555 DWORD ret;
556 int fd;
558 if (!name || !len || !addr || !type)
559 return ERROR_INVALID_PARAMETER;
561 fd = socket(PF_INET, SOCK_DGRAM, 0);
562 if (fd != -1) {
563 struct ifreq ifr;
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;
569 else {
570 unsigned int addrLen;
572 switch (ifr.ifr_hwaddr.sa_family)
574 #ifdef ARPHRD_LOOPBACK
575 case ARPHRD_LOOPBACK:
576 addrLen = 0;
577 *type = MIB_IF_TYPE_LOOPBACK;
578 break;
579 #endif
580 #ifdef ARPHRD_ETHER
581 case ARPHRD_ETHER:
582 addrLen = ETH_ALEN;
583 *type = MIB_IF_TYPE_ETHERNET;
584 break;
585 #endif
586 #ifdef ARPHRD_FDDI
587 case ARPHRD_FDDI:
588 addrLen = ETH_ALEN;
589 *type = MIB_IF_TYPE_FDDI;
590 break;
591 #endif
592 #ifdef ARPHRD_IEEE802
593 case ARPHRD_IEEE802: /* 802.2 Ethernet && Token Ring, guess TR? */
594 addrLen = ETH_ALEN;
595 *type = MIB_IF_TYPE_TOKENRING;
596 break;
597 #endif
598 #ifdef ARPHRD_IEEE802_TR
599 case ARPHRD_IEEE802_TR: /* also Token Ring? */
600 addrLen = ETH_ALEN;
601 *type = MIB_IF_TYPE_TOKENRING;
602 break;
603 #endif
604 #ifdef ARPHRD_SLIP
605 case ARPHRD_SLIP:
606 addrLen = 0;
607 *type = MIB_IF_TYPE_SLIP;
608 break;
609 #endif
610 #ifdef ARPHRD_PPP
611 case ARPHRD_PPP:
612 addrLen = 0;
613 *type = MIB_IF_TYPE_PPP;
614 break;
615 #endif
616 default:
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;
622 *len = addrLen;
624 else {
625 if (addrLen > 0)
626 memcpy(addr, ifr.ifr_hwaddr.sa_data, addrLen);
627 /* zero out remaining bytes for broken implementations */
628 memset(addr + addrLen, 0, *len - addrLen);
629 *len = addrLen;
630 ret = NO_ERROR;
633 close(fd);
635 else
636 ret = ERROR_NO_MORE_FILES;
637 return ret;
639 #elif defined (SIOCGARP)
640 DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
641 PDWORD type)
643 DWORD ret;
644 int fd;
646 if (!name || !len || !addr || !type)
647 return ERROR_INVALID_PARAMETER;
649 fd = socket(PF_INET, SOCK_DGRAM, 0);
650 if (fd != -1) {
651 if (isLoopbackInterface(fd, name)) {
652 *type = MIB_IF_TYPE_LOOPBACK;
653 memset(addr, 0, *len);
654 *len = 0;
655 ret=NOERROR;
657 else {
658 struct arpreq arp;
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;
668 else {
669 /* FIXME: heh: who said it was ethernet? */
670 int addrLen = ETH_ALEN;
672 if (addrLen > *len) {
673 ret = ERROR_INSUFFICIENT_BUFFER;
674 *len = addrLen;
676 else {
677 if (addrLen > 0)
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);
681 *len = addrLen;
682 *type = MIB_IF_TYPE_ETHERNET;
683 ret = NO_ERROR;
687 close(fd);
689 else
690 ret = ERROR_NO_MORE_FILES;
692 return ret;
694 #elif defined (HAVE_SYS_SYSCTL_H) && defined (HAVE_NET_IF_DL_H)
695 DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
696 PDWORD type)
698 DWORD ret;
699 struct if_msghdr *ifm;
700 struct sockaddr_dl *sdl;
701 u_char *p, *buf;
702 size_t mibLen;
703 int mib[] = { CTL_NET, AF_ROUTE, 0, AF_LINK, NET_RT_IFLIST, 0 };
704 int addrLen;
705 BOOL found = FALSE;
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);
714 if (!buf)
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)
728 continue;
730 if (sdl->sdl_family != AF_LINK || sdl->sdl_nlen == 0 ||
731 memcmp(sdl->sdl_data, name, max(sdl->sdl_nlen, strlen(name))) != 0)
732 continue;
734 found = TRUE;
735 addrLen = min(MAX_INTERFACE_PHYSADDR, sdl->sdl_alen);
736 if (addrLen > *len) {
737 ret = ERROR_INSUFFICIENT_BUFFER;
738 *len = addrLen;
740 else {
741 if (addrLen > 0)
742 memcpy(addr, LLADDR(sdl), addrLen);
743 /* zero out remaining bytes for broken implementations */
744 memset(addr + addrLen, 0, *len - addrLen);
745 *len = addrLen;
746 #if defined(HAVE_NET_IF_TYPES_H)
747 switch (sdl->sdl_type)
749 case IFT_ETHER:
750 *type = MIB_IF_TYPE_ETHERNET;
751 break;
752 case IFT_FDDI:
753 *type = MIB_IF_TYPE_FDDI;
754 break;
755 case IFT_ISO88024: /* Token Bus */
756 *type = MIB_IF_TYPE_TOKENRING;
757 break;
758 case IFT_ISO88025: /* Token Ring */
759 *type = MIB_IF_TYPE_TOKENRING;
760 break;
761 case IFT_PPP:
762 *type = MIB_IF_TYPE_PPP;
763 break;
764 case IFT_SLIP:
765 *type = MIB_IF_TYPE_SLIP;
766 break;
767 case IFT_LOOP:
768 *type = MIB_IF_TYPE_LOOPBACK;
769 break;
770 default:
771 *type = MIB_IF_TYPE_OTHER;
773 #else
774 /* default if we don't know */
775 *type = MIB_IF_TYPE_ETHERNET;
776 #endif
777 ret = NO_ERROR;
780 HeapFree(GetProcessHeap(), 0, buf);
781 return ret;
783 #endif
785 DWORD getInterfacePhysicalByIndex(DWORD index, PDWORD len, PBYTE addr,
786 PDWORD type)
788 const char *name = getInterfaceNameByIndex(index);
790 if (name)
791 return getInterfacePhysicalByName(name, len, addr, type);
792 else
793 return ERROR_INVALID_DATA;
796 DWORD getInterfaceMtuByName(const char *name, PDWORD mtu)
798 DWORD ret;
799 int fd;
801 if (!name)
802 return ERROR_INVALID_PARAMETER;
803 if (!mtu)
804 return ERROR_INVALID_PARAMETER;
806 fd = socket(PF_INET, SOCK_DGRAM, 0);
807 if (fd != -1) {
808 struct ifreq ifr;
810 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
811 if ((ioctl(fd, SIOCGIFMTU, &ifr)))
812 ret = ERROR_INVALID_DATA;
813 else {
814 #ifndef __sun
815 *mtu = ifr.ifr_mtu;
816 #else
817 *mtu = ifr.ifr_metric;
818 #endif
819 ret = NO_ERROR;
821 close(fd);
823 else
824 ret = ERROR_NO_MORE_FILES;
825 return ret;
828 DWORD getInterfaceMtuByIndex(DWORD index, PDWORD mtu)
830 const char *name = getInterfaceNameByIndex(index);
832 if (name)
833 return getInterfaceMtuByName(name, mtu);
834 else
835 return ERROR_INVALID_DATA;
838 DWORD getInterfaceStatusByName(const char *name, PDWORD status)
840 DWORD ret;
841 int fd;
843 if (!name)
844 return ERROR_INVALID_PARAMETER;
845 if (!status)
846 return ERROR_INVALID_PARAMETER;
848 fd = socket(PF_INET, SOCK_DGRAM, 0);
849 if (fd != -1) {
850 struct ifreq ifr;
852 lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
853 if ((ioctl(fd, SIOCGIFFLAGS, &ifr)))
854 ret = ERROR_INVALID_DATA;
855 else {
856 if (ifr.ifr_flags & IFF_UP)
857 *status = MIB_IF_OPER_STATUS_OPERATIONAL;
858 else
859 *status = MIB_IF_OPER_STATUS_NON_OPERATIONAL;
860 ret = NO_ERROR;
862 close(fd);
864 else
865 ret = ERROR_NO_MORE_FILES;
866 return ret;
869 DWORD getInterfaceStatusByIndex(DWORD index, PDWORD status)
871 const char *name = getInterfaceNameByIndex(index);
873 if (name)
874 return getInterfaceStatusByName(name, status);
875 else
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;
884 if (!name)
885 return ERROR_INVALID_PARAMETER;
886 if (!entry)
887 return ERROR_INVALID_PARAMETER;
889 if (getInterfacePhysicalByName(name, &len, addr, &type) == NO_ERROR) {
890 WCHAR *assigner;
891 const char *walker;
893 memset(entry, 0, sizeof(MIB_IFROW));
894 for (assigner = entry->wszName, walker = name; *walker;
895 walker++, assigner++)
896 *assigner = *walker;
897 *assigner = 0;
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';
912 entry->dwDescrLen++;
913 ret = NO_ERROR;
915 else
916 ret = ERROR_INVALID_DATA;
917 return ret;
920 DWORD getInterfaceEntryByIndex(DWORD index, PMIB_IFROW entry)
922 const char *name = getInterfaceNameByIndex(index);
924 if (name)
925 return getInterfaceEntryByName(name, entry);
926 else
927 return ERROR_INVALID_DATA;
930 char *toIPAddressString(unsigned int addr, char string[16])
932 if (string) {
933 struct in_addr iAddr;
935 iAddr.s_addr = addr;
936 /* extra-anal, just to make auditors happy */
937 lstrcpynA(string, inet_ntoa(iAddr), 16);
939 return string;