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