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 22 #include "libnetlink.h" 23 #include "ll_map.h" 24 25 extern unsigned int if_nametoindex (const char *); 26 27 struct idxmap 28 { 29 struct idxmap * next; 30 unsigned index; 31 int type; 32 int alen; 33 unsigned flags; 34 unsigned char addr[20]; 35 char name[16]; 36 }; 37 38 static struct idxmap *idxmap[16]; 39 40 int ll_remember_index(const struct sockaddr_nl *who, 41 struct nlmsghdr *n, void *arg) 42 { 43 int h; 44 struct ifinfomsg *ifi = NLMSG_DATA(n); 45 struct idxmap *im, **imp; 46 struct rtattr *tb[IFLA_MAX+1]; 47 48 if (n->nlmsg_type != RTM_NEWLINK) 49 return 0; 50 51 if (n->nlmsg_len < NLMSG_LENGTH(sizeof(ifi))) 52 return -1; 53 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 break; 65 66 if (im == NULL) { 67 im = malloc(sizeof(*im)); 68 if (im == NULL) 69 return 0; 70 im->next = *imp; 71 im->index = ifi->ifi_index; 72 *imp = im; 73 } 74 75 im->type = ifi->ifi_type; 76 im->flags = ifi->ifi_flags; 77 if (tb[IFLA_ADDRESS]) { 78 int alen; 79 im->alen = alen = RTA_PAYLOAD(tb[IFLA_ADDRESS]); 80 if (alen > sizeof(im->addr)) 81 alen = sizeof(im->addr); 82 memcpy(im->addr, RTA_DATA(tb[IFLA_ADDRESS]), alen); 83 } else { 84 im->alen = 0; 85 memset(im->addr, 0, sizeof(im->addr)); 86 } 87 strcpy(im->name, RTA_DATA(tb[IFLA_IFNAME])); 88 return 0; 89 } 90 91 const char *ll_idx_n2a(unsigned idx, char *buf) 92 { 93 struct idxmap *im; 94 95 if (idx == 0) 96 return "*"; 97 for (im = idxmap[idx&0xF]; im; im = im->next) 98 if (im->index == idx) 99 return im->name; 100 snprintf(buf, 16, "if%d", idx); 101 return buf; 102 } 103 104 105 const char *ll_index_to_name(unsigned idx) 106 { 107 static char nbuf[16]; 108 109 return ll_idx_n2a(idx, nbuf); 110 } 111 112 int ll_index_to_type(unsigned idx) 113 { 114 struct idxmap *im; 115 116 if (idx == 0) 117 return -1; 118 for (im = idxmap[idx&0xF]; im; im = im->next) 119 if (im->index == idx) 120 return im->type; 121 return -1; 122 } 123 124 unsigned ll_index_to_flags(unsigned idx) 125 { 126 struct idxmap *im; 127 128 if (idx == 0) 129 return 0; 130 131 for (im = idxmap[idx&0xF]; im; im = im->next) 132 if (im->index == idx) 133 return im->flags; 134 return 0; 135 } 136 137 unsigned ll_index_to_addr(unsigned idx, unsigned char *addr, 138 unsigned alen) 139 { 140 struct idxmap *im; 141 142 if (idx == 0) 143 return 0; 144 145 for (im = idxmap[idx&0xF]; im; im = im->next) { 146 if (im->index == idx) { 147 if (alen > sizeof(im->addr)) 148 alen = sizeof(im->addr); 149 if (alen > im->alen) 150 alen = im->alen; 151 memcpy(addr, im->addr, alen); 152 return alen; 153 } 154 } 155 return 0; 156 } 157 158 unsigned ll_name_to_index(const char *name) 159 { 160 static char ncache[16]; 161 static int icache; 162 struct idxmap *im; 163 int i; 164 unsigned idx; 165 166 if (name == NULL) 167 return 0; 168 if (icache && strcmp(name, ncache) == 0) 169 return icache; 170 for (i=0; i<16; i++) { 171 for (im = idxmap[i]; im; im = im->next) { 172 if (strcmp(im->name, name) == 0) { 173 icache = im->index; 174 strcpy(ncache, name); 175 return im->index; 176 } 177 } 178 } 179 180 idx = if_nametoindex(name); 181 if (idx == 0) 182 sscanf(name, "if%u", &idx); 183 return idx; 184 } 185 186 int ll_init_map(struct rtnl_handle *rth) 187 { 188 if (rtnl_wilddump_request(rth, AF_UNSPEC, RTM_GETLINK) < 0) { 189 perror("Cannot send dump request"); 190 exit(1); 191 } 192 193 if (rtnl_dump_filter(rth, ll_remember_index, &idxmap, NULL, NULL) < 0) { 194 fprintf(stderr, "Dump terminated\n"); 195 exit(1); 196 } 197 return 0; 198 } 199