]> rtime.felk.cvut.cz Git - lisovros/iproute2_canprio.git/blob - ip/ipmaddr.c
(Logical change 1.3)
[lisovros/iproute2_canprio.git] / ip / ipmaddr.c
1 /*
2  * ipmaddr.c            "ip maddress".
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/ioctl.h>
19 #include <sys/socket.h>
20 #include <linux/netdevice.h>
21 #include <linux/if.h>
22 #include <linux/if_arp.h>
23 #include <linux/sockios.h>
24 #include <netinet/in.h>
25 #include <arpa/inet.h>
26 #include <string.h>
27
28 #include "rt_names.h"
29 #include "utils.h"
30
31 static struct {
32         char *dev;
33         int  family;
34 } filter;
35
36 static void usage(void) __attribute__((noreturn));
37
38 static void usage(void)
39 {
40         fprintf(stderr, "Usage: ip maddr [ add | del ] MULTIADDR dev STRING\n");
41         fprintf(stderr, "       ip maddr show [ dev STRING ]\n");
42         exit(-1);
43 }
44
45 static int parse_hex(char *str, unsigned char *addr)
46 {
47         int len=0;
48
49         while (*str) {
50                 int tmp;
51                 if (str[1] == 0)
52                         return -1;
53                 if (sscanf(str, "%02x", &tmp) != 1)
54                         return -1;
55                 addr[len] = tmp;
56                 len++;
57                 str += 2;
58         }
59         return len;
60 }
61
62 struct ma_info
63 {
64         struct ma_info *next;
65         int             index;
66         int             users;
67         char            *features;
68         char            name[IFNAMSIZ];
69         inet_prefix     addr;
70 };
71
72 void maddr_ins(struct ma_info **lst, struct ma_info *m)
73 {
74         struct ma_info *mp;
75
76         for (; (mp=*lst) != NULL; lst = &mp->next) {
77                 if (mp->index > m->index)
78                         break;
79         }
80         m->next = *lst;
81         *lst = m;
82 }
83
84 void read_dev_mcast(struct ma_info **result_p)
85 {
86         char buf[256];
87         FILE *fp = fopen("/proc/net/dev_mcast", "r");
88
89         if (!fp)
90                 return;
91
92         while (fgets(buf, sizeof(buf), fp)) {
93                 char hexa[256];
94                 struct ma_info m;
95                 int len;
96                 int st;
97
98                 memset(&m, 0, sizeof(m));
99                 sscanf(buf, "%d%s%d%d%s", &m.index, m.name, &m.users, &st,
100                        hexa);
101                 if (filter.dev && strcmp(filter.dev, m.name))
102                         continue;
103
104                 m.addr.family = AF_PACKET;
105
106                 len = parse_hex(hexa, (unsigned char*)&m.addr.data);
107                 if (len >= 0) {
108                         struct ma_info *ma = malloc(sizeof(m));
109
110                         memcpy(ma, &m, sizeof(m));
111                         ma->addr.bytelen = len;
112                         ma->addr.bitlen = len<<3;
113                         if (st)
114                                 ma->features = "static";
115                         maddr_ins(result_p, ma);
116                 }
117         }
118         fclose(fp);
119 }
120
121 void read_igmp(struct ma_info **result_p)
122 {
123         struct ma_info m;
124         char buf[256];
125         FILE *fp = fopen("/proc/net/igmp", "r");
126
127         if (!fp)
128                 return;
129         memset(&m, 0, sizeof(m));
130         fgets(buf, sizeof(buf), fp);
131
132         m.addr.family = AF_INET;
133         m.addr.bitlen = 32;
134         m.addr.bytelen = 4;
135
136         while (fgets(buf, sizeof(buf), fp)) {
137                 struct ma_info *ma = malloc(sizeof(m));
138
139                 if (buf[0] != '\t') {
140                         sscanf(buf, "%d%s", &m.index, m.name);
141                         continue;
142                 }
143
144                 if (filter.dev && strcmp(filter.dev, m.name))
145                         continue;
146
147                 sscanf(buf, "%08x%d", (__u32*)&m.addr.data, &m.users);
148
149                 ma = malloc(sizeof(m));
150                 memcpy(ma, &m, sizeof(m));
151                 maddr_ins(result_p, ma);
152         }
153         fclose(fp);
154 }
155
156
157 void read_igmp6(struct ma_info **result_p)
158 {
159         char buf[256];
160         FILE *fp = fopen("/proc/net/igmp6", "r");
161
162         if (!fp)
163                 return;
164
165         while (fgets(buf, sizeof(buf), fp)) {
166                 char hexa[256];
167                 struct ma_info m;
168                 int len;
169
170                 memset(&m, 0, sizeof(m));
171                 sscanf(buf, "%d%s%s%d", &m.index, m.name, hexa, &m.users);
172
173                 if (filter.dev && strcmp(filter.dev, m.name))
174                         continue;
175
176                 m.addr.family = AF_INET6;
177
178                 len = parse_hex(hexa, (unsigned char*)&m.addr.data);
179                 if (len >= 0) {
180                         struct ma_info *ma = malloc(sizeof(m));
181
182                         memcpy(ma, &m, sizeof(m));
183
184                         ma->addr.bytelen = len;
185                         ma->addr.bitlen = len<<3;
186                         maddr_ins(result_p, ma);
187                 }
188         }
189         fclose(fp);
190 }
191
192 static void print_maddr(FILE *fp, struct ma_info *list)
193 {
194         fprintf(fp, "\t");
195
196         if (list->addr.family == AF_PACKET) {
197                 SPRINT_BUF(b1);
198                 fprintf(fp, "link  %s", ll_addr_n2a((unsigned char*)list->addr.data,
199                                                     list->addr.bytelen, 0,
200                                                     b1, sizeof(b1)));
201         } else {
202                 char abuf[256];
203                 switch(list->addr.family) {
204                 case AF_INET:
205                         fprintf(fp, "inet  ");
206                         break;
207                 case AF_INET6:
208                         fprintf(fp, "inet6 ");
209                         break;
210                 default:
211                         fprintf(fp, "family %d ", list->addr.family);
212                         break;
213                 }
214                 fprintf(fp, "%s", 
215                         format_host(list->addr.family,
216                                     -1,
217                                     list->addr.data,
218                                     abuf, sizeof(abuf)));
219         }
220         if (list->users != 1)
221                 fprintf(fp, " users %d", list->users);
222         if (list->features)
223                 fprintf(fp, " %s", list->features);
224         fprintf(fp, "\n");
225 }
226
227 static void print_mlist(FILE *fp, struct ma_info *list)
228 {
229         int cur_index = 0;
230
231         for (; list; list = list->next) {
232                 if (oneline) {
233                         cur_index = list->index;
234                         fprintf(fp, "%d:\t%s%s", cur_index, list->name, _SL_);
235                 } else if (cur_index != list->index) {
236                         cur_index = list->index;
237                         fprintf(fp, "%d:\t%s\n", cur_index, list->name);
238                 }
239                 print_maddr(fp, list);
240         }
241 }
242
243 static int multiaddr_list(int argc, char **argv)
244 {
245         struct ma_info *list = NULL;
246
247         if (!filter.family)
248                 filter.family = preferred_family;
249
250         while (argc > 0) {
251                 if (1) {
252                         if (strcmp(*argv, "dev") == 0) {
253                                 NEXT_ARG();
254                         }
255                         if (matches(*argv, "help") == 0)
256                                 usage();
257                         if (filter.dev)
258                                 duparg2("dev", *argv);
259                         filter.dev = *argv;
260                 }
261                 argv++; argc--;
262         }
263
264         if (!filter.family || filter.family == AF_PACKET)
265                 read_dev_mcast(&list);
266         if (!filter.family || filter.family == AF_INET)
267                 read_igmp(&list);
268         if (!filter.family || filter.family == AF_INET6)
269                 read_igmp6(&list);
270         print_mlist(stdout, list);
271         return 0;
272 }
273
274 int multiaddr_modify(int cmd, int argc, char **argv)
275 {
276         struct ifreq ifr;
277         int fd;
278
279         memset(&ifr, 0, sizeof(ifr));
280
281         if (cmd == RTM_NEWADDR)
282                 cmd = SIOCADDMULTI;
283         else
284                 cmd = SIOCDELMULTI;
285
286         while (argc > 0) {
287                 if (strcmp(*argv, "dev") == 0) {
288                         NEXT_ARG();
289                         if (ifr.ifr_name[0])
290                                 duparg("dev", *argv);
291                         strncpy(ifr.ifr_name, *argv, IFNAMSIZ);
292                 } else {
293                         if (matches(*argv, "address") == 0) {
294                                 NEXT_ARG();
295                         }
296                         if (matches(*argv, "help") == 0)
297                                 usage();
298                         if (ifr.ifr_hwaddr.sa_data[0])
299                                 duparg("address", *argv);
300                         if (ll_addr_a2n(ifr.ifr_hwaddr.sa_data, 14, *argv) < 0) {
301                                 fprintf(stderr, "Error: \"%s\" is not a legal ll address.\n", *argv);
302                                 exit(1);
303                         }
304                 }
305                 argc--; argv++;
306         }
307         if (ifr.ifr_name[0] == 0) {
308                 fprintf(stderr, "Not enough information: \"dev\" is required.\n");
309                 exit(-1);
310         }
311
312         fd = socket(AF_INET, SOCK_DGRAM, 0);
313         if (fd < 0) {
314                 perror("Cannot create socket");
315                 exit(1);
316         }
317         if (ioctl(fd, cmd, (char*)&ifr) != 0) {
318                 perror("ioctl");
319                 exit(1);
320         }
321         close(fd);
322
323         exit(0);
324 }
325
326
327 int do_multiaddr(int argc, char **argv)
328 {
329         if (argc < 1)
330                 return multiaddr_list(0, NULL);
331         if (matches(*argv, "add") == 0)
332                 return multiaddr_modify(RTM_NEWADDR, argc-1, argv+1);
333         if (matches(*argv, "delete") == 0)
334                 return multiaddr_modify(RTM_DELADDR, argc-1, argv+1);
335         if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0
336             || matches(*argv, "lst") == 0)
337                 return multiaddr_list(argc-1, argv+1);
338         if (matches(*argv, "help") == 0)
339                 usage();
340         fprintf(stderr, "Command \"%s\" is unknown, try \"ip maddr help\".\n", *argv);
341         exit(-1);
342 }