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[16]; 31 32static struct idxmap *find_by_index(int idx) 33{ 34 struct idxmap *im; 35 36 for (im = idxmap[idx & 0xF]; im; im = im->next) 37 if (im->index == idx) 38 return im; 39 return NULL; 40} 41 42int ll_remember_index(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) 43{ 44 int h; 45 struct ifinfomsg *ifi = NLMSG_DATA(n); 46 struct idxmap *im, **imp; 47 struct rtattr *tb[IFLA_MAX+1]; 48 49 if (n->nlmsg_type != RTM_NEWLINK) 50 return 0; 51 52 if (n->nlmsg_len < NLMSG_LENGTH(sizeof(ifi))) 53 return -1; 54 55 memset(tb, 0, sizeof(tb)); 56 parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), IFLA_PAYLOAD(n)); 57 if (tb[IFLA_IFNAME] == NULL) 58 return 0; 59 60 h = ifi->ifi_index & 0xF; 61 62 for (imp = &idxmap[h]; (im = *imp) != NULL; imp = &im->next) 63 if (im->index == ifi->ifi_index) 64 goto found; 65 66 im = xmalloc(sizeof(*im)); 67 im->next = *imp; 68 im->index = ifi->ifi_index; 69 *imp = im; 70 found: 71 im->type = ifi->ifi_type; 72 im->flags = ifi->ifi_flags; 73 if (tb[IFLA_ADDRESS]) { 74 int alen; 75 im->alen = alen = RTA_PAYLOAD(tb[IFLA_ADDRESS]); 76 if (alen > sizeof(im->addr)) 77 alen = sizeof(im->addr); 78 memcpy(im->addr, RTA_DATA(tb[IFLA_ADDRESS]), alen); 79 } else { 80 im->alen = 0; 81 memset(im->addr, 0, sizeof(im->addr)); 82 } 83 strcpy(im->name, RTA_DATA(tb[IFLA_IFNAME])); 84 return 0; 85} 86 87const char *ll_idx_n2a(int idx, char *buf) 88{ 89 struct idxmap *im; 90 91 if (idx == 0) 92 return "*"; 93 im = find_by_index(idx); 94 if (im) 95 return im->name; 96 snprintf(buf, 16, "if%d", idx); 97 return buf; 98} 99 100 101const char *ll_index_to_name(int idx) 102{ 103 static char nbuf[16]; 104 105 return ll_idx_n2a(idx, nbuf); 106} 107 108#ifdef UNUSED 109int ll_index_to_type(int idx) 110{ 111 struct idxmap *im; 112 113 if (idx == 0) 114 return -1; 115 im = find_by_index(idx); 116 if (im) 117 return im->type; 118 return -1; 119} 120#endif 121 122unsigned ll_index_to_flags(int idx) 123{ 124 struct idxmap *im; 125 126 if (idx == 0) 127 return 0; 128 im = find_by_index(idx); 129 if (im) 130 return im->flags; 131 return 0; 132} 133 134int xll_name_to_index(const char *const name) 135{ 136 int ret = 0; 137 int sock_fd; 138 139/* caching is not warranted - no users which repeatedly call it */ 140#ifdef UNUSED 141 static char ncache[16]; 142 static int icache; 143 144 struct idxmap *im; 145 int i; 146 147 if (name == NULL) 148 goto out; 149 if (icache && strcmp(name, ncache) == 0) { 150 ret = icache; 151 goto out; 152 } 153 for (i = 0; i < 16; i++) { 154 for (im = idxmap[i]; im; im = im->next) { 155 if (strcmp(im->name, name) == 0) { 156 icache = im->index; 157 strcpy(ncache, name); 158 ret = im->index; 159 goto out; 160 } 161 } 162 } 163 /* We have not found the interface in our cache, but the kernel 164 * may still know about it. One reason is that we may be using 165 * module on-demand loading, which means that the kernel will 166 * load the module and make the interface exist only when 167 * we explicitely request it (check for dev_load() in net/core/dev.c). 168 * I can think of other similar scenario, but they are less common... 169 * Jean II */ 170#endif 171 172 sock_fd = socket(AF_INET, SOCK_DGRAM, 0); 173 if (sock_fd) { 174 struct ifreq ifr; 175 int tmp; 176 177 strncpy(ifr.ifr_name, name, IFNAMSIZ); 178 ifr.ifr_ifindex = -1; 179 tmp = ioctl(sock_fd, SIOCGIFINDEX, &ifr); 180 close(sock_fd); 181 if (tmp >= 0) 182 /* In theory, we should redump the interface list 183 * to update our cache, this is left as an exercise 184 * to the reader... Jean II */ 185 ret = ifr.ifr_ifindex; 186 } 187/* out:*/ 188 if (ret <= 0) 189 bb_error_msg_and_die("cannot find device \"%s\"", name); 190 return ret; 191} 192 193int ll_init_map(struct rtnl_handle *rth) 194{ 195 xrtnl_wilddump_request(rth, AF_UNSPEC, RTM_GETLINK); 196 xrtnl_dump_filter(rth, ll_remember_index, &idxmap); 197 return 0; 198} 199