Home | History | Annotate | Download | only in lib
      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 
    165 	if (name == NULL)
    166 		return 0;
    167 	if (icache && strcmp(name, ncache) == 0)
    168 		return icache;
    169 	for (i=0; i<16; i++) {
    170 		for (im = idxmap[i]; im; im = im->next) {
    171 			if (strcmp(im->name, name) == 0) {
    172 				icache = im->index;
    173 				strcpy(ncache, name);
    174 				return im->index;
    175 			}
    176 		}
    177 	}
    178 
    179 	return if_nametoindex(name);
    180 }
    181 
    182 int ll_init_map(struct rtnl_handle *rth)
    183 {
    184 	if (rtnl_wilddump_request(rth, AF_UNSPEC, RTM_GETLINK) < 0) {
    185 		perror("Cannot send dump request");
    186 		exit(1);
    187 	}
    188 
    189 	if (rtnl_dump_filter(rth, ll_remember_index, &idxmap, NULL, NULL) < 0) {
    190 		fprintf(stderr, "Dump terminated\n");
    191 		exit(1);
    192 	}
    193 	return 0;
    194 }
    195