Main Page | Modules | Class List | Directories | File List | Class Members | File Members | Related Pages

intf-win32.c

Go to the documentation of this file.
00001 /*
00002  * intf-win32.c
00003  *
00004  * Copyright (c) 2002 Dug Song <dugsong@monkey.org>
00005  *
00006  * $Id: intf-win32.c,v 1.25 2005/09/26 02:47:08 dugsong Exp $
00007  */
00008 
00009 #include "config.h"
00010 
00011 #include <iphlpapi.h>
00012 
00013 #include <ctype.h>
00014 #include <errno.h>
00015 #include <stdio.h>
00016 #include <stdlib.h>
00017 #include <string.h>
00018 
00019 #include "dnet.h"
00020 
00021 struct ifcombo {
00022         DWORD           *idx;
00023         int              cnt;
00024         int              max;
00025 };
00026 
00027 #define MIB_IF_TYPE_MAX  32     /* XXX - ipifcons.h */
00028 
00029 struct intf_handle {
00030         struct ifcombo   ifcombo[MIB_IF_TYPE_MAX];
00031         MIB_IFTABLE     *iftable;
00032         MIB_IPADDRTABLE *iptable;
00033 };
00034 
00035 static char *
00036 _ifcombo_name(int type)
00037 {
00038         char *name = "net";     /* XXX */
00039         
00040         if (type == MIB_IF_TYPE_ETHERNET) {
00041                 name = "eth";
00042         } else if (type == MIB_IF_TYPE_TOKENRING) {
00043                 name = "tr";
00044         } else if (type == MIB_IF_TYPE_FDDI) {
00045                 name = "fddi";
00046         } else if (type == MIB_IF_TYPE_PPP) {
00047                 name = "ppp";
00048         } else if (type == MIB_IF_TYPE_LOOPBACK) {
00049                 name = "lo";
00050         } else if (type == MIB_IF_TYPE_SLIP) {
00051                 name = "sl";
00052         }
00053         return (name);
00054 }
00055 
00056 static int
00057 _ifcombo_type(const char *device)
00058 {
00059         int type = INTF_TYPE_OTHER;
00060         
00061         if (strncmp(device, "eth", 3) == 0) {
00062                 type = INTF_TYPE_ETH;
00063         } else if (strncmp(device, "tr", 2) == 0) {
00064                 type = INTF_TYPE_TOKENRING;
00065         } else if (strncmp(device, "fd", 2) == 0) {
00066                 type = INTF_TYPE_FDDI;
00067         } else if (strncmp(device, "ppp", 3) == 0) {
00068                 type = INTF_TYPE_PPP;
00069         } else if (strncmp(device, "lo", 2) == 0) {
00070                 type = INTF_TYPE_LOOPBACK;
00071         } else if (strncmp(device, "sl", 2) == 0) {
00072                 type = INTF_TYPE_SLIP;
00073         }
00074         return (type);
00075 }
00076 
00077 static void
00078 _ifcombo_add(struct ifcombo *ifc, DWORD idx)
00079 {
00080         if (ifc->cnt == ifc->max) {
00081                 if (ifc->idx) {
00082                         ifc->max *= 2;
00083                         ifc->idx = realloc(ifc->idx,
00084                             sizeof(ifc->idx[0] * ifc->max));
00085                 } else {
00086                         ifc->max = 8;
00087                         ifc->idx = malloc(sizeof(ifc->idx[0] * ifc->max));
00088                 }
00089         }
00090         ifc->idx[ifc->cnt++] = idx;
00091 }
00092 
00093 static void
00094 _ifrow_to_entry(intf_t *intf, MIB_IFROW *ifrow, struct intf_entry *entry)
00095 {
00096         struct addr *ap, *lap;
00097         int i;
00098         
00099         memset(entry, 0, sizeof(*entry));
00100 
00101         for (i = 0; i < intf->ifcombo[ifrow->dwType].cnt; i++) {
00102                 if (intf->ifcombo[ifrow->dwType].idx[i] == ifrow->dwIndex)
00103                         break;
00104         }
00105         /* XXX - dwType matches MIB-II ifType. */
00106         snprintf(entry->intf_name, sizeof(entry->intf_name), "%s%lu",
00107             _ifcombo_name(ifrow->dwType), i);
00108         entry->intf_type = (uint16_t)ifrow->dwType;
00109         
00110         /* Get interface flags. */
00111         entry->intf_flags = 0;
00112         if (ifrow->dwAdminStatus == MIB_IF_ADMIN_STATUS_UP)
00113                 entry->intf_flags |= INTF_FLAG_UP;
00114         if (ifrow->dwType == MIB_IF_TYPE_LOOPBACK)
00115                 entry->intf_flags |= INTF_FLAG_LOOPBACK;
00116         else
00117                 entry->intf_flags |= INTF_FLAG_MULTICAST;
00118         
00119         /* Get interface MTU. */
00120         entry->intf_mtu = ifrow->dwMtu;
00121         
00122         /* Get hardware address. */
00123         if (ifrow->dwPhysAddrLen == ETH_ADDR_LEN) {
00124                 entry->intf_link_addr.addr_type = ADDR_TYPE_ETH;
00125                 entry->intf_link_addr.addr_bits = ETH_ADDR_BITS;
00126                 memcpy(&entry->intf_link_addr.addr_eth, ifrow->bPhysAddr,
00127                     ETH_ADDR_LEN);
00128         }
00129         /* Get addresses. */
00130         ap = entry->intf_alias_addrs;
00131         lap = ap + ((entry->intf_len - sizeof(*entry)) /
00132             sizeof(entry->intf_alias_addrs[0]));
00133         for (i = 0; i < (int)intf->iptable->dwNumEntries; i++) {
00134                 if (intf->iptable->table[i].dwIndex == ifrow->dwIndex &&
00135                     intf->iptable->table[i].dwAddr != 0) {
00136                         if (entry->intf_addr.addr_type == ADDR_TYPE_NONE) {
00137                                 /* Set primary address if unset. */
00138                                 entry->intf_addr.addr_type = ADDR_TYPE_IP;
00139                                 entry->intf_addr.addr_ip =
00140                                     intf->iptable->table[i].dwAddr;
00141                                 addr_mtob(&intf->iptable->table[i].dwMask,
00142                                     IP_ADDR_LEN, &entry->intf_addr.addr_bits);
00143                         } else if (ap < lap) {
00144                                 /* Set aliases. */
00145                                 ap->addr_type = ADDR_TYPE_IP;
00146                                 ap->addr_ip = intf->iptable->table[i].dwAddr;
00147                                 addr_mtob(&intf->iptable->table[i].dwMask,
00148                                     IP_ADDR_LEN, &ap->addr_bits);
00149                                 ap++, entry->intf_alias_num++;
00150                         }
00151                 }
00152         }
00153         entry->intf_len = (u_char *)ap - (u_char *)entry;
00154 }
00155 
00156 static int
00157 _refresh_tables(intf_t *intf)
00158 {
00159         MIB_IFROW *ifrow;
00160         ULONG len;
00161         u_int i, ret;
00162 
00163         /* Get interface table. */
00164         for (len = sizeof(intf->iftable[0]); ; ) {
00165                 if (intf->iftable)
00166                         free(intf->iftable);
00167                 intf->iftable = malloc(len);
00168                 ret = GetIfTable(intf->iftable, &len, FALSE);
00169                 if (ret == NO_ERROR)
00170                         break;
00171                 else if (ret != ERROR_INSUFFICIENT_BUFFER)
00172                         return (-1);
00173         }
00174         /* Get IP address table. */
00175         for (len = sizeof(intf->iptable[0]); ; ) {
00176                 if (intf->iptable)
00177                         free(intf->iptable);
00178                 intf->iptable = malloc(len);
00179                 ret = GetIpAddrTable(intf->iptable, &len, FALSE);
00180                 if (ret == NO_ERROR)
00181                         break;
00182                 else if (ret != ERROR_INSUFFICIENT_BUFFER)
00183                         return (-1);
00184         }
00185         /*
00186          * Map "unfriendly" win32 interface indices to ours.
00187          * XXX - like IP_ADAPTER_INFO ComboIndex
00188          */
00189         for (i = 0; i < intf->iftable->dwNumEntries; i++) {
00190                 ifrow = &intf->iftable->table[i];
00191                 if (ifrow->dwType < MIB_IF_TYPE_MAX) {
00192                         _ifcombo_add(&intf->ifcombo[ifrow->dwType],
00193                             ifrow->dwIndex);
00194                 } else
00195                         return (-1);
00196         }
00197         return (0);
00198 }
00199 
00200 static int
00201 _find_ifindex(intf_t *intf, const char *device)
00202 {
00203         char *p = (char *)device;
00204         int n, type = _ifcombo_type(device);
00205         
00206         while (isalpha(*p)) p++;
00207         n = atoi(p);
00208 
00209         return (intf->ifcombo[type].idx[n]);
00210 }
00211 
00212 intf_t *
00213 intf_open(void)
00214 {
00215         return (calloc(1, sizeof(intf_t)));
00216 }
00217 
00218 int
00219 intf_get(intf_t *intf, struct intf_entry *entry)
00220 {
00221         MIB_IFROW ifrow;
00222         
00223         if (_refresh_tables(intf) < 0)
00224                 return (-1);
00225         
00226         ifrow.dwIndex = _find_ifindex(intf, entry->intf_name);
00227         
00228         if (GetIfEntry(&ifrow) != NO_ERROR)
00229                 return (-1);
00230 
00231         _ifrow_to_entry(intf, &ifrow, entry);
00232         
00233         return (0);
00234 }
00235 
00236 int
00237 intf_get_src(intf_t *intf, struct intf_entry *entry, struct addr *src)
00238 {
00239         MIB_IFROW ifrow;
00240         MIB_IPADDRROW *iprow;
00241         int i;
00242 
00243         if (src->addr_type != ADDR_TYPE_IP) {
00244                 errno = EINVAL;
00245                 return (-1);
00246         }
00247         if (_refresh_tables(intf) < 0)
00248                 return (-1);
00249         
00250         for (i = 0; i < (int)intf->iptable->dwNumEntries; i++) {
00251                 iprow = &intf->iptable->table[i];
00252                 if (iprow->dwAddr == src->addr_ip) {
00253                         ifrow.dwIndex = iprow->dwIndex;
00254                         if (GetIfEntry(&ifrow) != NO_ERROR)
00255                                 return (-1);
00256                         _ifrow_to_entry(intf, &ifrow, entry);
00257                         return (0);
00258                 }
00259         }
00260         errno = ENXIO;
00261         return (-1);
00262 }
00263 
00264 int
00265 intf_get_dst(intf_t *intf, struct intf_entry *entry, struct addr *dst)
00266 {
00267         MIB_IFROW ifrow;
00268         
00269         if (dst->addr_type != ADDR_TYPE_IP) {
00270                 errno = EINVAL;
00271                 return (-1);
00272         }
00273         if (GetBestInterface(dst->addr_ip, &ifrow.dwIndex) != NO_ERROR)
00274                 return (-1);
00275 
00276         if (GetIfEntry(&ifrow) != NO_ERROR)
00277                 return (-1);
00278         
00279         if (_refresh_tables(intf) < 0)
00280                 return (-1);
00281         
00282         _ifrow_to_entry(intf, &ifrow, entry);
00283         
00284         return (0);
00285 }
00286 
00287 int
00288 intf_set(intf_t *intf, const struct intf_entry *entry)
00289 {
00290         /*
00291          * XXX - could set interface up/down via SetIfEntry(),
00292          * but what about the rest of the configuration? :-(
00293          * {Add,Delete}IPAddress for 2000/XP only
00294          */
00295 #if 0
00296         /* Set interface address. XXX - 2000/XP only? */
00297         if (entry->intf_addr.addr_type == ADDR_TYPE_IP) {
00298                 ULONG ctx = 0, inst = 0;
00299                 UINT ip, mask;
00300 
00301                 memcpy(&ip, &entry->intf_addr.addr_ip, IP_ADDR_LEN);
00302                 addr_btom(entry->intf_addr.addr_bits, &mask, IP_ADDR_LEN);
00303                 
00304                 if (AddIPAddress(ip, mask,
00305                         _find_ifindex(intf, entry->intf_name),
00306                         &ctx, &inst) != NO_ERROR) {
00307                         return (-1);
00308                 }
00309                 return (0);
00310         }
00311 #endif
00312         errno = ENOSYS;
00313         SetLastError(ERROR_NOT_SUPPORTED);
00314         return (-1);
00315 }
00316 
00317 int
00318 intf_loop(intf_t *intf, intf_handler callback, void *arg)
00319 {
00320         struct intf_entry *entry;
00321         u_char ebuf[1024];
00322         int i, ret = 0;
00323 
00324         if (_refresh_tables(intf) < 0)
00325                 return (-1);
00326         
00327         entry = (struct intf_entry *)ebuf;
00328         
00329         for (i = 0; i < (int)intf->iftable->dwNumEntries; i++) {
00330                 entry->intf_len = sizeof(ebuf);
00331                 _ifrow_to_entry(intf, &intf->iftable->table[i], entry);
00332                 if ((ret = (*callback)(entry, arg)) != 0)
00333                         break;
00334         }
00335         return (ret);
00336 }
00337 
00338 intf_t *
00339 intf_close(intf_t *intf)
00340 {
00341         int i;
00342 
00343         if (intf != NULL) {
00344                 for (i = 0; i < MIB_IF_TYPE_MAX; i++) {
00345                         if (intf->ifcombo[i].idx)
00346                                 free(intf->ifcombo[i].idx);
00347                 }
00348                 if (intf->iftable)
00349                         free(intf->iftable);
00350                 if (intf->iptable)
00351                         free(intf->iptable);
00352                 free(intf);
00353         }
00354         return (NULL);
00355 }

Generated on Sun May 14 14:51:11 2006 by  doxygen 1.4.2