1 /* 2 * ll_map.c 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 7 * 2 of the License, or (at your option) any later version. 8 * 9 * Authors: Alexey Kuznetsov, <kuznet (at) ms2.inr.ac.ru> 10 * 11 */ 12 13 #include <stdio.h> 14 #include <stdlib.h> 15 #include <unistd.h> 16 #include <syslog.h> 17 #include <fcntl.h> 18 #include <sys/socket.h> 19 #include <netinet/in.h> 20 #include <string.h> 21 #include <linux/if.h> 22 23 #include "libnetlink.h" 24 #include "ll_map.h" 25 26 extern unsigned int if_nametoindex (const char *); 27 28 struct ll_cache 29 { 30 struct ll_cache *idx_next; 31 unsigned flags; 32 int index; 33 unsigned short type; 34 unsigned short alen; 35 char name[IFNAMSIZ]; 36 unsigned char addr[20]; 37 }; 38 39 #define IDXMAP_SIZE 1024 40 static struct ll_cache *idx_head[IDXMAP_SIZE]; 41 42 static inline struct ll_cache *idxhead(int idx) 43 { 44 return idx_head[idx & (IDXMAP_SIZE - 1)]; 45 } 46 47 int ll_remember_index(const struct sockaddr_nl *who, 48 struct nlmsghdr *n, void *arg) 49 { 50 int h; 51 struct ifinfomsg *ifi = NLMSG_DATA(n); 52 struct ll_cache *im, **imp; 53 struct rtattr *tb[IFLA_MAX+1]; 54 55 if (n->nlmsg_type != RTM_NEWLINK) 56 return 0; 57 58 if (n->nlmsg_len < NLMSG_LENGTH(sizeof(ifi))) 59 return -1; 60 61 memset(tb, 0, sizeof(tb)); 62 parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), IFLA_PAYLOAD(n)); 63 if (tb[IFLA_IFNAME] == NULL) 64 return 0; 65 66 h = ifi->ifi_index & (IDXMAP_SIZE - 1); 67 for (imp = &idx_head[h]; (im=*imp)!=NULL; imp = &im->idx_next) 68 if (im->index == ifi->ifi_index) 69 break; 70 71 if (im == NULL) { 72 im = malloc(sizeof(*im)); 73 if (im == NULL) 74 return 0; 75 im->idx_next = *imp; 76 im->index = ifi->ifi_index; 77 *imp = im; 78 } 79 80 im->type = ifi->ifi_type; 81 im->flags = ifi->ifi_flags; 82 if (tb[IFLA_ADDRESS]) { 83 int alen; 84 im->alen = alen = RTA_PAYLOAD(tb[IFLA_ADDRESS]); 85 if (alen > sizeof(im->addr)) 86 alen = sizeof(im->addr); 87 memcpy(im->addr, RTA_DATA(tb[IFLA_ADDRESS]), alen); 88 } else { 89 im->alen = 0; 90 memset(im->addr, 0, sizeof(im->addr)); 91 } 92 strcpy(im->name, RTA_DATA(tb[IFLA_IFNAME])); 93 return 0; 94 } 95 96 const char *ll_idx_n2a(unsigned idx, char *buf) 97 { 98 const struct ll_cache *im; 99 100 if (idx == 0) 101 return "*"; 102 103 for (im = idxhead(idx); im; im = im->idx_next) 104 if (im->index == idx) 105 return im->name; 106 107 snprintf(buf, IFNAMSIZ, "if%d", idx); 108 return buf; 109 } 110 111 112 const char *ll_index_to_name(unsigned idx) 113 { 114 static char nbuf[IFNAMSIZ]; 115 116 return ll_idx_n2a(idx, nbuf); 117 } 118 119 int ll_index_to_type(unsigned idx) 120 { 121 const struct ll_cache *im; 122 123 if (idx == 0) 124 return -1; 125 for (im = idxhead(idx); im; im = im->idx_next) 126 if (im->index == idx) 127 return im->type; 128 return -1; 129 } 130 131 unsigned ll_index_to_flags(unsigned idx) 132 { 133 const struct ll_cache *im; 134 135 if (idx == 0) 136 return 0; 137 138 for (im = idxhead(idx); im; im = im->idx_next) 139 if (im->index == idx) 140 return im->flags; 141 return 0; 142 } 143 144 unsigned ll_index_to_addr(unsigned idx, unsigned char *addr, 145 unsigned alen) 146 { 147 const struct ll_cache *im; 148 149 if (idx == 0) 150 return 0; 151 152 for (im = idxhead(idx); im; im = im->idx_next) { 153 if (im->index == idx) { 154 if (alen > sizeof(im->addr)) 155 alen = sizeof(im->addr); 156 if (alen > im->alen) 157 alen = im->alen; 158 memcpy(addr, im->addr, alen); 159 return alen; 160 } 161 } 162 return 0; 163 } 164 165 unsigned ll_name_to_index(const char *name) 166 { 167 static char ncache[IFNAMSIZ]; 168 static int icache; 169 struct ll_cache *im; 170 int i; 171 unsigned idx; 172 173 if (name == NULL) 174 return 0; 175 176 if (icache && strcmp(name, ncache) == 0) 177 return icache; 178 179 for (i=0; i<IDXMAP_SIZE; i++) { 180 for (im = idx_head[i]; im; im = im->idx_next) { 181 if (strcmp(im->name, name) == 0) { 182 icache = im->index; 183 strcpy(ncache, name); 184 return im->index; 185 } 186 } 187 } 188 189 idx = if_nametoindex(name); 190 if (idx == 0) 191 sscanf(name, "if%u", &idx); 192 return idx; 193 } 194 195 int ll_init_map(struct rtnl_handle *rth) 196 { 197 static int initialized; 198 199 if (initialized) 200 return 0; 201 202 if (rtnl_wilddump_request(rth, AF_UNSPEC, RTM_GETLINK) < 0) { 203 perror("Cannot send dump request"); 204 exit(1); 205 } 206 207 if (rtnl_dump_filter(rth, ll_remember_index, NULL) < 0) { 208 fprintf(stderr, "Dump terminated\n"); 209 exit(1); 210 } 211 212 initialized = 1; 213 214 return 0; 215 } 216