busybox/networking/libiproute/ll_map.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*
   3 * ll_map.c
   4 *
   5 *              This program is free software; you can redistribute it and/or
   6 *              modify it under the terms of the GNU General Public License
   7 *              as published by the Free Software Foundation; either version
   8 *              2 of the License, or (at your option) any later version.
   9 *
  10 * Authors:     Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
  11 *
  12 */
  13
  14#include <net/if.h>     /* struct ifreq and co. */
  15
  16#include "libbb.h"
  17#include "libnetlink.h"
  18#include "ll_map.h"
  19
  20struct idxmap {
  21        struct idxmap *next;
  22        int            index;
  23        int            type;
  24        int            alen;
  25        unsigned       flags;
  26        unsigned char  addr[8];
  27        char           name[16];
  28};
  29
  30static struct idxmap **idxmap; /* treat as *idxmap[16] */
  31
  32static struct idxmap *find_by_index(int idx)
  33{
  34        struct idxmap *im;
  35
  36        if (idxmap)
  37                for (im = idxmap[idx & 0xF]; im; im = im->next)
  38                        if (im->index == idx)
  39                                return im;
  40        return NULL;
  41}
  42
  43int FAST_FUNC ll_remember_index(const struct sockaddr_nl *who UNUSED_PARAM,
  44                struct nlmsghdr *n,
  45                void *arg UNUSED_PARAM)
  46{
  47        int h;
  48        struct ifinfomsg *ifi = NLMSG_DATA(n);
  49        struct idxmap *im, **imp;
  50        struct rtattr *tb[IFLA_MAX+1];
  51
  52        if (n->nlmsg_type != RTM_NEWLINK)
  53                return 0;
  54
  55        if (n->nlmsg_len < NLMSG_LENGTH(sizeof(ifi)))
  56                return -1;
  57
  58        memset(tb, 0, sizeof(tb));
  59        parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), IFLA_PAYLOAD(n));
  60        if (tb[IFLA_IFNAME] == NULL)
  61                return 0;
  62
  63        if (!idxmap)
  64                idxmap = xzalloc(sizeof(idxmap[0]) * 16);
  65
  66        h = ifi->ifi_index & 0xF;
  67        for (imp = &idxmap[h]; (im = *imp) != NULL; imp = &im->next)
  68                if (im->index == ifi->ifi_index)
  69                        goto found;
  70
  71        im = xmalloc(sizeof(*im));
  72        im->next = *imp;
  73        im->index = ifi->ifi_index;
  74        *imp = im;
  75 found:
  76        im->type = ifi->ifi_type;
  77        im->flags = ifi->ifi_flags;
  78        if (tb[IFLA_ADDRESS]) {
  79                int alen;
  80                im->alen = alen = RTA_PAYLOAD(tb[IFLA_ADDRESS]);
  81                if (alen > (int)sizeof(im->addr))
  82                        alen = sizeof(im->addr);
  83                memcpy(im->addr, RTA_DATA(tb[IFLA_ADDRESS]), alen);
  84        } else {
  85                im->alen = 0;
  86                memset(im->addr, 0, sizeof(im->addr));
  87        }
  88        strcpy(im->name, RTA_DATA(tb[IFLA_IFNAME]));
  89        return 0;
  90}
  91
  92const char FAST_FUNC *ll_idx_n2a(int idx, char *buf)
  93{
  94        struct idxmap *im;
  95
  96        if (idx == 0)
  97                return "*";
  98        im = find_by_index(idx);
  99        if (im)
 100                return im->name;
 101        snprintf(buf, 16, "if%d", idx);
 102        return buf;
 103}
 104
 105
 106const char FAST_FUNC *ll_index_to_name(int idx)
 107{
 108        static char nbuf[16];
 109
 110        return ll_idx_n2a(idx, nbuf);
 111}
 112
 113#ifdef UNUSED
 114int ll_index_to_type(int idx)
 115{
 116        struct idxmap *im;
 117
 118        if (idx == 0)
 119                return -1;
 120        im = find_by_index(idx);
 121        if (im)
 122                return im->type;
 123        return -1;
 124}
 125#endif
 126
 127unsigned FAST_FUNC ll_index_to_flags(int idx)
 128{
 129        struct idxmap *im;
 130
 131        if (idx == 0)
 132                return 0;
 133        im = find_by_index(idx);
 134        if (im)
 135                return im->flags;
 136        return 0;
 137}
 138
 139int FAST_FUNC xll_name_to_index(const char *name)
 140{
 141        int ret = 0;
 142        int sock_fd;
 143
 144/* caching is not warranted - no users which repeatedly call it */
 145#ifdef UNUSED
 146        static char ncache[16];
 147        static int icache;
 148
 149        struct idxmap *im;
 150        int i;
 151
 152        if (name == NULL)
 153                goto out;
 154        if (icache && strcmp(name, ncache) == 0) {
 155                ret = icache;
 156                goto out;
 157        }
 158        if (idxmap) {
 159                for (i = 0; i < 16; i++) {
 160                        for (im = idxmap[i]; im; im = im->next) {
 161                                if (strcmp(im->name, name) == 0) {
 162                                        icache = im->index;
 163                                        strcpy(ncache, name);
 164                                        ret = im->index;
 165                                        goto out;
 166                                }
 167                        }
 168                }
 169        }
 170        /* We have not found the interface in our cache, but the kernel
 171         * may still know about it. One reason is that we may be using
 172         * module on-demand loading, which means that the kernel will
 173         * load the module and make the interface exist only when
 174         * we explicitely request it (check for dev_load() in net/core/dev.c).
 175         * I can think of other similar scenario, but they are less common...
 176         * Jean II */
 177#endif
 178
 179        sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
 180        if (sock_fd >= 0) {
 181                struct ifreq ifr;
 182                int tmp;
 183
 184                strncpy_IFNAMSIZ(ifr.ifr_name, name);
 185                ifr.ifr_ifindex = -1;
 186                tmp = ioctl(sock_fd, SIOCGIFINDEX, &ifr);
 187                close(sock_fd);
 188                if (tmp >= 0)
 189                        /* In theory, we should redump the interface list
 190                         * to update our cache, this is left as an exercise
 191                         * to the reader... Jean II */
 192                        ret = ifr.ifr_ifindex;
 193        }
 194/* out:*/
 195        if (ret <= 0)
 196                bb_error_msg_and_die("can't find device '%s'", name);
 197        return ret;
 198}
 199
 200int FAST_FUNC ll_init_map(struct rtnl_handle *rth)
 201{
 202        xrtnl_wilddump_request(rth, AF_UNSPEC, RTM_GETLINK);
 203        xrtnl_dump_filter(rth, ll_remember_index, NULL);
 204        return 0;
 205}
 206