123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202 |
- /* vi: set sw=4 ts=4: */
- /*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
- * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
- */
- #include <net/if.h> /* struct ifreq and co. */
- #include "libbb.h"
- #include "libnetlink.h"
- #include "ll_map.h"
- struct idxmap {
- struct idxmap *next;
- int index;
- int type;
- int alen;
- unsigned flags;
- unsigned char addr[8];
- char name[16];
- };
- static struct idxmap **idxmap; /* treat as *idxmap[16] */
- static struct idxmap *find_by_index(int idx)
- {
- struct idxmap *im;
- if (idxmap)
- for (im = idxmap[idx & 0xF]; im; im = im->next)
- if (im->index == idx)
- return im;
- return NULL;
- }
- int FAST_FUNC ll_remember_index(const struct sockaddr_nl *who UNUSED_PARAM,
- struct nlmsghdr *n,
- void *arg UNUSED_PARAM)
- {
- int h;
- struct ifinfomsg *ifi = NLMSG_DATA(n);
- struct idxmap *im, **imp;
- struct rtattr *tb[IFLA_MAX+1];
- if (n->nlmsg_type != RTM_NEWLINK)
- return 0;
- if (n->nlmsg_len < NLMSG_LENGTH(sizeof(ifi)))
- return -1;
- memset(tb, 0, sizeof(tb));
- parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), IFLA_PAYLOAD(n));
- if (tb[IFLA_IFNAME] == NULL)
- return 0;
- if (!idxmap)
- idxmap = xzalloc(sizeof(idxmap[0]) * 16);
- h = ifi->ifi_index & 0xF;
- for (imp = &idxmap[h]; (im = *imp) != NULL; imp = &im->next)
- if (im->index == ifi->ifi_index)
- goto found;
- im = xmalloc(sizeof(*im));
- im->next = *imp;
- im->index = ifi->ifi_index;
- *imp = im;
- found:
- im->type = ifi->ifi_type;
- im->flags = ifi->ifi_flags;
- if (tb[IFLA_ADDRESS]) {
- int alen;
- im->alen = alen = RTA_PAYLOAD(tb[IFLA_ADDRESS]);
- if (alen > (int)sizeof(im->addr))
- alen = sizeof(im->addr);
- memcpy(im->addr, RTA_DATA(tb[IFLA_ADDRESS]), alen);
- } else {
- im->alen = 0;
- memset(im->addr, 0, sizeof(im->addr));
- }
- strcpy(im->name, RTA_DATA(tb[IFLA_IFNAME]));
- return 0;
- }
- const char FAST_FUNC *ll_idx_n2a(int idx, char *buf)
- {
- struct idxmap *im;
- if (idx == 0)
- return "*";
- im = find_by_index(idx);
- if (im)
- return im->name;
- snprintf(buf, 16, "if%d", idx);
- return buf;
- }
- const char FAST_FUNC *ll_index_to_name(int idx)
- {
- static char nbuf[16];
- return ll_idx_n2a(idx, nbuf);
- }
- #ifdef UNUSED
- int ll_index_to_type(int idx)
- {
- struct idxmap *im;
- if (idx == 0)
- return -1;
- im = find_by_index(idx);
- if (im)
- return im->type;
- return -1;
- }
- #endif
- unsigned FAST_FUNC ll_index_to_flags(int idx)
- {
- struct idxmap *im;
- if (idx == 0)
- return 0;
- im = find_by_index(idx);
- if (im)
- return im->flags;
- return 0;
- }
- int FAST_FUNC xll_name_to_index(const char *name)
- {
- int ret = 0;
- int sock_fd;
- /* caching is not warranted - no users which repeatedly call it */
- #ifdef UNUSED
- static char ncache[16];
- static int icache;
- struct idxmap *im;
- int i;
- if (name == NULL)
- goto out;
- if (icache && strcmp(name, ncache) == 0) {
- ret = icache;
- goto out;
- }
- if (idxmap) {
- for (i = 0; i < 16; i++) {
- for (im = idxmap[i]; im; im = im->next) {
- if (strcmp(im->name, name) == 0) {
- icache = im->index;
- strcpy(ncache, name);
- ret = im->index;
- goto out;
- }
- }
- }
- }
- /* We have not found the interface in our cache, but the kernel
- * may still know about it. One reason is that we may be using
- * module on-demand loading, which means that the kernel will
- * load the module and make the interface exist only when
- * we explicitely request it (check for dev_load() in net/core/dev.c).
- * I can think of other similar scenario, but they are less common...
- * Jean II */
- #endif
- sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
- if (sock_fd >= 0) {
- struct ifreq ifr;
- int tmp;
- strncpy_IFNAMSIZ(ifr.ifr_name, name);
- ifr.ifr_ifindex = -1;
- tmp = ioctl(sock_fd, SIOCGIFINDEX, &ifr);
- close(sock_fd);
- if (tmp >= 0)
- /* In theory, we should redump the interface list
- * to update our cache, this is left as an exercise
- * to the reader... Jean II */
- ret = ifr.ifr_ifindex;
- }
- /* out:*/
- if (ret <= 0)
- bb_error_msg_and_die("can't find device '%s'", name);
- return ret;
- }
- int FAST_FUNC ll_init_map(struct rtnl_handle *rth)
- {
- xrtnl_wilddump_request(rth, AF_UNSPEC, RTM_GETLINK);
- xrtnl_dump_filter(rth, ll_remember_index, NULL);
- return 0;
- }
|