]>
git.proxmox.com Git - mirror_iproute2.git/blob - ip/ipmaddr.c
2 * ipmaddr.c "ip maddress".
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.
9 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
18 #include <sys/ioctl.h>
19 #include <sys/socket.h>
20 #include <netinet/in.h>
21 #include <arpa/inet.h>
24 #include <linux/netdevice.h>
26 #include <linux/if_arp.h>
27 #include <linux/sockios.h>
31 #include "ip_common.h"
38 static void usage(void) __attribute__((noreturn
));
40 static void usage(void)
42 fprintf(stderr
, "Usage: ip maddr [ add | del ] MULTIADDR dev STRING\n");
43 fprintf(stderr
, " ip maddr show [ dev STRING ]\n");
47 static int parse_hex(char *str
, unsigned char *addr
, size_t size
)
51 while (*str
&& (len
< 2 * size
)) {
56 if (sscanf(str
, "%02x", &tmp
) != 1)
74 static void maddr_ins(struct ma_info
**lst
, struct ma_info
*m
)
78 for (; (mp
= *lst
) != NULL
; lst
= &mp
->next
) {
79 if (mp
->index
> m
->index
)
86 static void read_dev_mcast(struct ma_info
**result_p
)
89 FILE *fp
= fopen("/proc/net/dev_mcast", "r");
94 while (fgets(buf
, sizeof(buf
), fp
)) {
96 struct ma_info m
= { .addr
.family
= AF_PACKET
};
100 sscanf(buf
, "%d%s%d%d%s", &m
.index
, m
.name
, &m
.users
, &st
,
102 if (filter
.dev
&& strcmp(filter
.dev
, m
.name
))
105 len
= parse_hex(hexa
, (unsigned char *)&m
.addr
.data
, sizeof(m
.addr
.data
));
107 struct ma_info
*ma
= malloc(sizeof(m
));
109 memcpy(ma
, &m
, sizeof(m
));
110 ma
->addr
.bytelen
= len
;
111 ma
->addr
.bitlen
= len
<<3;
113 ma
->features
= "static";
114 maddr_ins(result_p
, ma
);
120 static void read_igmp(struct ma_info
**result_p
)
123 .addr
.family
= AF_INET
,
128 FILE *fp
= fopen("/proc/net/igmp", "r");
132 if (!fgets(buf
, sizeof(buf
), fp
)) {
137 while (fgets(buf
, sizeof(buf
), fp
)) {
140 if (buf
[0] != '\t') {
143 sscanf(buf
, "%d%s", &m
.index
, m
.name
);
144 len
= strlen(m
.name
);
145 if (m
.name
[len
- 1] == ':')
146 m
.name
[len
- 1] = '\0';
150 if (filter
.dev
&& strcmp(filter
.dev
, m
.name
))
153 sscanf(buf
, "%08x%d", (__u32
*)&m
.addr
.data
, &m
.users
);
155 ma
= malloc(sizeof(m
));
156 memcpy(ma
, &m
, sizeof(m
));
157 maddr_ins(result_p
, ma
);
163 static void read_igmp6(struct ma_info
**result_p
)
166 FILE *fp
= fopen("/proc/net/igmp6", "r");
171 while (fgets(buf
, sizeof(buf
), fp
)) {
173 struct ma_info m
= { .addr
.family
= AF_INET6
};
176 sscanf(buf
, "%d%s%s%d", &m
.index
, m
.name
, hexa
, &m
.users
);
178 if (filter
.dev
&& strcmp(filter
.dev
, m
.name
))
181 len
= parse_hex(hexa
, (unsigned char *)&m
.addr
.data
, sizeof(m
.addr
.data
));
183 struct ma_info
*ma
= malloc(sizeof(m
));
185 memcpy(ma
, &m
, sizeof(m
));
187 ma
->addr
.bytelen
= len
;
188 ma
->addr
.bitlen
= len
<<3;
189 maddr_ins(result_p
, ma
);
195 static void print_maddr(FILE *fp
, struct ma_info
*list
)
199 if (list
->addr
.family
== AF_PACKET
) {
201 fprintf(fp
, "link %s", ll_addr_n2a((unsigned char *)list
->addr
.data
,
202 list
->addr
.bytelen
, 0,
205 switch (list
->addr
.family
) {
207 fprintf(fp
, "inet ");
210 fprintf(fp
, "inet6 ");
213 fprintf(fp
, "family %d ", list
->addr
.family
);
217 format_host(list
->addr
.family
,
218 -1, list
->addr
.data
));
220 if (list
->users
!= 1)
221 fprintf(fp
, " users %d", list
->users
);
223 fprintf(fp
, " %s", list
->features
);
227 static void print_mlist(FILE *fp
, struct ma_info
*list
)
231 for (; list
; list
= list
->next
) {
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
);
239 print_maddr(fp
, list
);
243 static int multiaddr_list(int argc
, char **argv
)
245 struct ma_info
*list
= NULL
;
248 filter
.family
= preferred_family
;
252 if (strcmp(*argv
, "dev") == 0) {
254 } else if (matches(*argv
, "help") == 0)
257 duparg2("dev", *argv
);
263 if (!filter
.family
|| filter
.family
== AF_PACKET
)
264 read_dev_mcast(&list
);
265 if (!filter
.family
|| filter
.family
== AF_INET
)
267 if (!filter
.family
|| filter
.family
== AF_INET6
)
269 print_mlist(stdout
, list
);
273 static int multiaddr_modify(int cmd
, int argc
, char **argv
)
275 struct ifreq ifr
= {};
278 if (cmd
== RTM_NEWADDR
)
284 if (strcmp(*argv
, "dev") == 0) {
287 duparg("dev", *argv
);
288 if (get_ifname(ifr
.ifr_name
, *argv
))
289 invarg("\"dev\" not a valid ifname", *argv
);
291 if (matches(*argv
, "address") == 0) {
294 if (matches(*argv
, "help") == 0)
296 if (ifr
.ifr_hwaddr
.sa_data
[0])
297 duparg("address", *argv
);
298 if (ll_addr_a2n(ifr
.ifr_hwaddr
.sa_data
,
300 fprintf(stderr
, "Error: \"%s\" is not a legal ll address.\n", *argv
);
306 if (ifr
.ifr_name
[0] == 0) {
307 fprintf(stderr
, "Not enough information: \"dev\" is required.\n");
311 fd
= socket(AF_INET
, SOCK_DGRAM
, 0);
313 perror("Cannot create socket");
316 if (ioctl(fd
, cmd
, (char *)&ifr
) != 0) {
326 int do_multiaddr(int argc
, char **argv
)
329 return multiaddr_list(0, NULL
);
330 if (matches(*argv
, "add") == 0)
331 return multiaddr_modify(RTM_NEWADDR
, argc
-1, argv
+1);
332 if (matches(*argv
, "delete") == 0)
333 return multiaddr_modify(RTM_DELADDR
, argc
-1, argv
+1);
334 if (matches(*argv
, "list") == 0 || matches(*argv
, "show") == 0
335 || matches(*argv
, "lst") == 0)
336 return multiaddr_list(argc
-1, argv
+1);
337 if (matches(*argv
, "help") == 0)
339 fprintf(stderr
, "Command \"%s\" is unknown, try \"ip maddr help\".\n", *argv
);