blob: f2e340a42b1253d5aff063ec1b85291bd04c3c0b [file] [log] [blame]
"Robert P. J. Day"63fc1a92006-07-02 19:47:05 +00001/* vi: set sw=4 ts=4: */
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00002/*
3 * ipaddress.c "ip address".
4 *
Bernhard Reutner-Fischer20f40002006-01-30 17:17:14 +00005 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
Glenn L McGrath9a2d2722002-11-10 01:33:55 +00006 *
7 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
8 *
9 * Changes:
10 * Laszlo Valko <valko@linux.karinthy.hu> 990223: address label must be zero terminated
11 */
12
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000013#include <fnmatch.h>
Eric Andersen8004bb72003-01-14 08:06:07 +000014#include <net/if.h>
15#include <net/if_arp.h>
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000016
Denis Vlasenko9a7d38f2007-05-31 22:42:12 +000017#include "ip_common.h" /* #include "libbb.h" is inside */
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000018#include "rt_names.h"
19#include "utils.h"
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000020
Denis Vlasenko9b6f4aa2008-06-05 14:01:04 +000021#ifndef IFF_LOWER_UP
22/* from linux/if.h */
23#define IFF_LOWER_UP 0x10000 /* driver signals L1 up*/
24#endif
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000025
Denis Vlasenko540a2a12007-04-07 01:14:45 +000026typedef struct filter_t {
Denis Vlasenko3e57adb2008-05-31 07:33:18 +000027 char *label;
28 char *flushb;
29 struct rtnl_handle *rth;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000030 int scope, scopemask;
31 int flags, flagmask;
Glenn L McGrathd66370c2003-01-13 21:40:38 +000032 int flushp;
33 int flushe;
Denis Vlasenko3e57adb2008-05-31 07:33:18 +000034 int ifindex;
35 family_t family;
36 smallint showqueue;
37 smallint oneline;
38 smallint up;
39 smallint flushed;
40 inet_prefix pfx;
Denis Vlasenko540a2a12007-04-07 01:14:45 +000041} filter_t;
42
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +010043#define G_filter (*(filter_t*)&bb_common_bufsiz1)
Denis Vlasenko540a2a12007-04-07 01:14:45 +000044
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000045
Denis Vlasenkobedfabd2008-06-05 05:00:24 +000046static void print_link_flags(unsigned flags, unsigned mdown)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000047{
Denis Vlasenko53354ac2008-06-07 15:10:29 +000048 static const int flag_masks[] = {
49 IFF_LOOPBACK, IFF_BROADCAST, IFF_POINTOPOINT,
50 IFF_MULTICAST, IFF_NOARP, IFF_UP, IFF_LOWER_UP };
51 static const char flag_labels[] ALIGN1 =
52 "LOOPBACK\0""BROADCAST\0""POINTOPOINT\0"
53 "MULTICAST\0""NOARP\0""UP\0""LOWER_UP\0";
54
Denis Vlasenko7d60fc12008-06-05 06:51:06 +000055 bb_putchar('<');
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000056 flags &= ~IFF_RUNNING;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000057#if 0
58 _PF(ALLMULTI);
59 _PF(PROMISC);
60 _PF(MASTER);
61 _PF(SLAVE);
62 _PF(DEBUG);
63 _PF(DYNAMIC);
64 _PF(AUTOMEDIA);
65 _PF(PORTSEL);
66 _PF(NOTRAILERS);
67#endif
Denis Vlasenko53354ac2008-06-07 15:10:29 +000068 flags = print_flags_separated(flag_masks, flag_labels, flags, ",");
Tim Rikerc1ef7bd2006-01-25 00:08:53 +000069 if (flags)
Denis Vlasenkobedfabd2008-06-05 05:00:24 +000070 printf("%x", flags);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000071 if (mdown)
Denis Vlasenkobedfabd2008-06-05 05:00:24 +000072 printf(",M-DOWN");
73 printf("> ");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000074}
75
Glenn L McGrath2626ef62002-12-02 01:40:05 +000076static void print_queuelen(char *name)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000077{
78 struct ifreq ifr;
79 int s;
80
81 s = socket(AF_INET, SOCK_STREAM, 0);
82 if (s < 0)
83 return;
84
85 memset(&ifr, 0, sizeof(ifr));
Denis Vlasenko360d9662008-12-02 18:18:50 +000086 strncpy_IFNAMSIZ(ifr.ifr_name, name);
Denis Vlasenkofb79a2e2007-07-14 22:07:14 +000087 if (ioctl_or_warn(s, SIOCGIFTXQLEN, &ifr) < 0) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000088 close(s);
89 return;
90 }
91 close(s);
92
93 if (ifr.ifr_qlen)
94 printf("qlen %d", ifr.ifr_qlen);
95}
96
Denys Vlasenkoadf922e2009-10-08 14:35:37 +020097static NOINLINE int print_linkinfo(const struct nlmsghdr *n)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000098{
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000099 struct ifinfomsg *ifi = NLMSG_DATA(n);
Denys Vlasenko90377872010-01-08 09:07:50 +0100100 struct rtattr *tb[IFLA_MAX+1];
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000101 int len = n->nlmsg_len;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000102
103 if (n->nlmsg_type != RTM_NEWLINK && n->nlmsg_type != RTM_DELLINK)
104 return 0;
105
106 len -= NLMSG_LENGTH(sizeof(*ifi));
107 if (len < 0)
108 return -1;
109
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100110 if (G_filter.ifindex && ifi->ifi_index != G_filter.ifindex)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000111 return 0;
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100112 if (G_filter.up && !(ifi->ifi_flags & IFF_UP))
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000113 return 0;
114
115 memset(tb, 0, sizeof(tb));
116 parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len);
117 if (tb[IFLA_IFNAME] == NULL) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000118 bb_error_msg("nil ifname");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000119 return -1;
120 }
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100121 if (G_filter.label
122 && (!G_filter.family || G_filter.family == AF_PACKET)
123 && fnmatch(G_filter.label, RTA_DATA(tb[IFLA_IFNAME]), 0)
Denis Vlasenko540a2a12007-04-07 01:14:45 +0000124 ) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000125 return 0;
Denis Vlasenko540a2a12007-04-07 01:14:45 +0000126 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000127
128 if (n->nlmsg_type == RTM_DELLINK)
Denis Vlasenkobedfabd2008-06-05 05:00:24 +0000129 printf("Deleted ");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000130
Denis Vlasenkobedfabd2008-06-05 05:00:24 +0000131 printf("%d: %s", ifi->ifi_index,
Denys Vlasenko90377872010-01-08 09:07:50 +0100132 /*tb[IFLA_IFNAME] ? (char*)RTA_DATA(tb[IFLA_IFNAME]) : "<nil>" - we checked tb[IFLA_IFNAME] above*/
133 (char*)RTA_DATA(tb[IFLA_IFNAME])
134 );
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000135
Denys Vlasenko90377872010-01-08 09:07:50 +0100136 {
137 unsigned m_flag = 0;
138 if (tb[IFLA_LINK]) {
139 SPRINT_BUF(b1);
140 int iflink = *(int*)RTA_DATA(tb[IFLA_LINK]);
141 if (iflink == 0)
142 printf("@NONE: ");
143 else {
144 printf("@%s: ", ll_idx_n2a(iflink, b1));
145 m_flag = ll_index_to_flags(iflink);
146 m_flag = !(m_flag & IFF_UP);
147 }
148 } else {
149 printf(": ");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000150 }
Denys Vlasenko90377872010-01-08 09:07:50 +0100151 print_link_flags(ifi->ifi_flags, m_flag);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000152 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000153
154 if (tb[IFLA_MTU])
Denis Vlasenkobedfabd2008-06-05 05:00:24 +0000155 printf("mtu %u ", *(int*)RTA_DATA(tb[IFLA_MTU]));
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000156 if (tb[IFLA_QDISC])
Denis Vlasenkobedfabd2008-06-05 05:00:24 +0000157 printf("qdisc %s ", (char*)RTA_DATA(tb[IFLA_QDISC]));
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000158#ifdef IFLA_MASTER
159 if (tb[IFLA_MASTER]) {
160 SPRINT_BUF(b1);
Denis Vlasenkobedfabd2008-06-05 05:00:24 +0000161 printf("master %s ", ll_idx_n2a(*(int*)RTA_DATA(tb[IFLA_MASTER]), b1));
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000162 }
163#endif
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100164 if (G_filter.showqueue)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000165 print_queuelen((char*)RTA_DATA(tb[IFLA_IFNAME]));
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000166
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100167 if (!G_filter.family || G_filter.family == AF_PACKET) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000168 SPRINT_BUF(b1);
Denys Vlasenkod31575a2009-10-13 17:58:24 +0200169 printf("%c link/%s ", _SL_, ll_type_n2a(ifi->ifi_type, b1));
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000170
171 if (tb[IFLA_ADDRESS]) {
Denis Vlasenko605b20e2007-09-30 16:22:36 +0000172 fputs(ll_addr_n2a(RTA_DATA(tb[IFLA_ADDRESS]),
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000173 RTA_PAYLOAD(tb[IFLA_ADDRESS]),
174 ifi->ifi_type,
Denis Vlasenkobedfabd2008-06-05 05:00:24 +0000175 b1, sizeof(b1)), stdout);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000176 }
177 if (tb[IFLA_BROADCAST]) {
Denis Vlasenkodfc07402007-10-29 19:33:26 +0000178 if (ifi->ifi_flags & IFF_POINTOPOINT)
Denis Vlasenkobedfabd2008-06-05 05:00:24 +0000179 printf(" peer ");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000180 else
Denis Vlasenkobedfabd2008-06-05 05:00:24 +0000181 printf(" brd ");
Denis Vlasenko605b20e2007-09-30 16:22:36 +0000182 fputs(ll_addr_n2a(RTA_DATA(tb[IFLA_BROADCAST]),
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000183 RTA_PAYLOAD(tb[IFLA_BROADCAST]),
184 ifi->ifi_type,
Denis Vlasenkobedfabd2008-06-05 05:00:24 +0000185 b1, sizeof(b1)), stdout);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000186 }
187 }
Denis Vlasenkobedfabd2008-06-05 05:00:24 +0000188 bb_putchar('\n');
Denys Vlasenko8131eea2009-11-02 14:19:51 +0100189 /*fflush_all();*/
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000190 return 0;
191}
192
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000193static int flush_update(void)
194{
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100195 if (rtnl_send(G_filter.rth, G_filter.flushb, G_filter.flushp) < 0) {
Denis Vlasenko540a2a12007-04-07 01:14:45 +0000196 bb_perror_msg("failed to send flush request");
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000197 return -1;
198 }
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100199 G_filter.flushp = 0;
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000200 return 0;
201}
202
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +0200203static int FAST_FUNC print_addrinfo(const struct sockaddr_nl *who UNUSED_PARAM,
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000204 struct nlmsghdr *n, void *arg UNUSED_PARAM)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000205{
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000206 struct ifaddrmsg *ifa = NLMSG_DATA(n);
207 int len = n->nlmsg_len;
208 struct rtattr * rta_tb[IFA_MAX+1];
209 char abuf[256];
210 SPRINT_BUF(b1);
211
212 if (n->nlmsg_type != RTM_NEWADDR && n->nlmsg_type != RTM_DELADDR)
213 return 0;
214 len -= NLMSG_LENGTH(sizeof(*ifa));
215 if (len < 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000216 bb_error_msg("wrong nlmsg len %d", len);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000217 return -1;
218 }
219
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100220 if (G_filter.flushb && n->nlmsg_type != RTM_NEWADDR)
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000221 return 0;
222
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000223 memset(rta_tb, 0, sizeof(rta_tb));
224 parse_rtattr(rta_tb, IFA_MAX, IFA_RTA(ifa), n->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa)));
225
226 if (!rta_tb[IFA_LOCAL])
227 rta_tb[IFA_LOCAL] = rta_tb[IFA_ADDRESS];
228 if (!rta_tb[IFA_ADDRESS])
229 rta_tb[IFA_ADDRESS] = rta_tb[IFA_LOCAL];
230
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100231 if (G_filter.ifindex && G_filter.ifindex != ifa->ifa_index)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000232 return 0;
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100233 if ((G_filter.scope ^ ifa->ifa_scope) & G_filter.scopemask)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000234 return 0;
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100235 if ((G_filter.flags ^ ifa->ifa_flags) & G_filter.flagmask)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000236 return 0;
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100237 if (G_filter.label) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000238 const char *label;
239 if (rta_tb[IFA_LABEL])
240 label = RTA_DATA(rta_tb[IFA_LABEL]);
241 else
242 label = ll_idx_n2a(ifa->ifa_index, b1);
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100243 if (fnmatch(G_filter.label, label, 0) != 0)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000244 return 0;
245 }
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100246 if (G_filter.pfx.family) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000247 if (rta_tb[IFA_LOCAL]) {
248 inet_prefix dst;
249 memset(&dst, 0, sizeof(dst));
250 dst.family = ifa->ifa_family;
251 memcpy(&dst.data, RTA_DATA(rta_tb[IFA_LOCAL]), RTA_PAYLOAD(rta_tb[IFA_LOCAL]));
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100252 if (inet_addr_match(&dst, &G_filter.pfx, G_filter.pfx.bitlen))
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000253 return 0;
254 }
255 }
256
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100257 if (G_filter.flushb) {
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000258 struct nlmsghdr *fn;
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100259 if (NLMSG_ALIGN(G_filter.flushp) + n->nlmsg_len > G_filter.flushe) {
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000260 if (flush_update())
261 return -1;
262 }
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100263 fn = (struct nlmsghdr*)(G_filter.flushb + NLMSG_ALIGN(G_filter.flushp));
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000264 memcpy(fn, n, n->nlmsg_len);
265 fn->nlmsg_type = RTM_DELADDR;
266 fn->nlmsg_flags = NLM_F_REQUEST;
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100267 fn->nlmsg_seq = ++G_filter.rth->seq;
268 G_filter.flushp = (((char*)fn) + n->nlmsg_len) - G_filter.flushb;
269 G_filter.flushed = 1;
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000270 return 0;
271 }
272
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000273 if (n->nlmsg_type == RTM_DELADDR)
Denis Vlasenkobedfabd2008-06-05 05:00:24 +0000274 printf("Deleted ");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000275
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100276 if (G_filter.oneline)
Denis Vlasenkobedfabd2008-06-05 05:00:24 +0000277 printf("%u: %s", ifa->ifa_index, ll_index_to_name(ifa->ifa_index));
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000278 if (ifa->ifa_family == AF_INET)
Denis Vlasenkobedfabd2008-06-05 05:00:24 +0000279 printf(" inet ");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000280 else if (ifa->ifa_family == AF_INET6)
Denis Vlasenkobedfabd2008-06-05 05:00:24 +0000281 printf(" inet6 ");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000282 else
Denis Vlasenkobedfabd2008-06-05 05:00:24 +0000283 printf(" family %d ", ifa->ifa_family);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000284
285 if (rta_tb[IFA_LOCAL]) {
Denis Vlasenko605b20e2007-09-30 16:22:36 +0000286 fputs(rt_addr_n2a(ifa->ifa_family,
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000287 RTA_DATA(rta_tb[IFA_LOCAL]),
Denis Vlasenkobedfabd2008-06-05 05:00:24 +0000288 abuf, sizeof(abuf)), stdout);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000289
Denis Vlasenko76140a72009-03-05 09:21:57 +0000290 if (rta_tb[IFA_ADDRESS] == NULL
291 || memcmp(RTA_DATA(rta_tb[IFA_ADDRESS]), RTA_DATA(rta_tb[IFA_LOCAL]), 4) == 0
292 ) {
Denis Vlasenkobedfabd2008-06-05 05:00:24 +0000293 printf("/%d ", ifa->ifa_prefixlen);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000294 } else {
Denis Vlasenkobedfabd2008-06-05 05:00:24 +0000295 printf(" peer %s/%d ",
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000296 rt_addr_n2a(ifa->ifa_family,
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000297 RTA_DATA(rta_tb[IFA_ADDRESS]),
298 abuf, sizeof(abuf)),
299 ifa->ifa_prefixlen);
300 }
301 }
302
303 if (rta_tb[IFA_BROADCAST]) {
Denis Vlasenkobedfabd2008-06-05 05:00:24 +0000304 printf("brd %s ",
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000305 rt_addr_n2a(ifa->ifa_family,
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000306 RTA_DATA(rta_tb[IFA_BROADCAST]),
307 abuf, sizeof(abuf)));
308 }
309 if (rta_tb[IFA_ANYCAST]) {
Denis Vlasenkobedfabd2008-06-05 05:00:24 +0000310 printf("any %s ",
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000311 rt_addr_n2a(ifa->ifa_family,
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000312 RTA_DATA(rta_tb[IFA_ANYCAST]),
313 abuf, sizeof(abuf)));
314 }
Denys Vlasenkod31575a2009-10-13 17:58:24 +0200315 printf("scope %s ", rtnl_rtscope_n2a(ifa->ifa_scope, b1));
Denis Vlasenko3e57adb2008-05-31 07:33:18 +0000316 if (ifa->ifa_flags & IFA_F_SECONDARY) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000317 ifa->ifa_flags &= ~IFA_F_SECONDARY;
Denis Vlasenkobedfabd2008-06-05 05:00:24 +0000318 printf("secondary ");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000319 }
Denis Vlasenko3e57adb2008-05-31 07:33:18 +0000320 if (ifa->ifa_flags & IFA_F_TENTATIVE) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000321 ifa->ifa_flags &= ~IFA_F_TENTATIVE;
Denis Vlasenkobedfabd2008-06-05 05:00:24 +0000322 printf("tentative ");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000323 }
Denis Vlasenko3e57adb2008-05-31 07:33:18 +0000324 if (ifa->ifa_flags & IFA_F_DEPRECATED) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000325 ifa->ifa_flags &= ~IFA_F_DEPRECATED;
Denis Vlasenkobedfabd2008-06-05 05:00:24 +0000326 printf("deprecated ");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000327 }
Denis Vlasenko3e57adb2008-05-31 07:33:18 +0000328 if (!(ifa->ifa_flags & IFA_F_PERMANENT)) {
Denis Vlasenkobedfabd2008-06-05 05:00:24 +0000329 printf("dynamic ");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000330 } else
331 ifa->ifa_flags &= ~IFA_F_PERMANENT;
332 if (ifa->ifa_flags)
Denis Vlasenkobedfabd2008-06-05 05:00:24 +0000333 printf("flags %02x ", ifa->ifa_flags);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000334 if (rta_tb[IFA_LABEL])
Denis Vlasenkobedfabd2008-06-05 05:00:24 +0000335 fputs((char*)RTA_DATA(rta_tb[IFA_LABEL]), stdout);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000336 if (rta_tb[IFA_CACHEINFO]) {
337 struct ifa_cacheinfo *ci = RTA_DATA(rta_tb[IFA_CACHEINFO]);
338 char buf[128];
Denis Vlasenkobedfabd2008-06-05 05:00:24 +0000339 bb_putchar(_SL_);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000340 if (ci->ifa_valid == 0xFFFFFFFFU)
341 sprintf(buf, "valid_lft forever");
342 else
343 sprintf(buf, "valid_lft %dsec", ci->ifa_valid);
344 if (ci->ifa_prefered == 0xFFFFFFFFU)
345 sprintf(buf+strlen(buf), " preferred_lft forever");
346 else
347 sprintf(buf+strlen(buf), " preferred_lft %dsec", ci->ifa_prefered);
Denis Vlasenkobedfabd2008-06-05 05:00:24 +0000348 printf(" %s", buf);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000349 }
Denis Vlasenkobedfabd2008-06-05 05:00:24 +0000350 bb_putchar('\n');
Denys Vlasenko8131eea2009-11-02 14:19:51 +0100351 /*fflush_all();*/
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000352 return 0;
353}
354
355
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +0200356struct nlmsg_list {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000357 struct nlmsg_list *next;
358 struct nlmsghdr h;
359};
360
Denis Vlasenkobedfabd2008-06-05 05:00:24 +0000361static int print_selected_addrinfo(int ifindex, struct nlmsg_list *ainfo)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000362{
Denis Vlasenko540a2a12007-04-07 01:14:45 +0000363 for (; ainfo; ainfo = ainfo->next) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000364 struct nlmsghdr *n = &ainfo->h;
365 struct ifaddrmsg *ifa = NLMSG_DATA(n);
366
367 if (n->nlmsg_type != RTM_NEWADDR)
368 continue;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000369 if (n->nlmsg_len < NLMSG_LENGTH(sizeof(ifa)))
370 return -1;
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100371 if (ifa->ifa_index != ifindex
372 || (G_filter.family && G_filter.family != ifa->ifa_family)
373 ) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000374 continue;
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100375 }
Denis Vlasenkobedfabd2008-06-05 05:00:24 +0000376 print_addrinfo(NULL, n, NULL);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000377 }
378 return 0;
379}
380
381
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +0200382static int FAST_FUNC store_nlmsg(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000383{
384 struct nlmsg_list **linfo = (struct nlmsg_list**)arg;
385 struct nlmsg_list *h;
386 struct nlmsg_list **lp;
387
Denys Vlasenko90377872010-01-08 09:07:50 +0100388 h = xzalloc(n->nlmsg_len + sizeof(void*));
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000389
390 memcpy(&h->h, n, n->nlmsg_len);
Denys Vlasenko90377872010-01-08 09:07:50 +0100391 /*h->next = NULL; - xzalloc did it */
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000392
Denis Vlasenko3e57adb2008-05-31 07:33:18 +0000393 for (lp = linfo; *lp; lp = &(*lp)->next)
394 continue;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000395 *lp = h;
396
397 ll_remember_index(who, n, NULL);
398 return 0;
399}
400
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000401static void ipaddr_reset_filter(int _oneline)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000402{
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100403 memset(&G_filter, 0, sizeof(G_filter));
404 G_filter.oneline = _oneline;
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000405}
406
Denis Vlasenko540a2a12007-04-07 01:14:45 +0000407/* Return value becomes exitcode. It's okay to not return at all */
Denis Vlasenkoed6a49c2007-11-18 22:56:25 +0000408int ipaddr_list_or_flush(char **argv, int flush)
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000409{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000410 static const char option[] ALIGN1 = "to\0""scope\0""up\0""label\0""dev\0";
Rob Landley0a7c8ef2006-02-22 17:01:00 +0000411
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000412 struct nlmsg_list *linfo = NULL;
413 struct nlmsg_list *ainfo = NULL;
414 struct nlmsg_list *l;
415 struct rtnl_handle rth;
416 char *filter_dev = NULL;
417 int no_link = 0;
418
419 ipaddr_reset_filter(oneline);
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100420 G_filter.showqueue = 1;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000421
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100422 if (G_filter.family == AF_UNSPEC)
423 G_filter.family = preferred_family;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000424
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000425 if (flush) {
Denis Vlasenkoed6a49c2007-11-18 22:56:25 +0000426 if (!*argv) {
Denis Vlasenko540a2a12007-04-07 01:14:45 +0000427 bb_error_msg_and_die(bb_msg_requires_arg, "flush");
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000428 }
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100429 if (G_filter.family == AF_PACKET) {
Denys Vlasenko6331cf02009-11-13 09:08:27 +0100430 bb_error_msg_and_die("can't flush link addresses");
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000431 }
432 }
433
Denis Vlasenkoed6a49c2007-11-18 22:56:25 +0000434 while (*argv) {
Denis Vlasenko990d0f62007-07-24 15:54:42 +0000435 const int option_num = index_in_strings(option, *argv);
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000436 switch (option_num) {
437 case 0: /* to */
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000438 NEXT_ARG();
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100439 get_prefix(&G_filter.pfx, *argv, G_filter.family);
440 if (G_filter.family == AF_UNSPEC) {
441 G_filter.family = G_filter.pfx.family;
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000442 }
443 break;
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100444 case 1: { /* scope */
Eric Andersend78aea82006-01-30 18:00:02 +0000445 uint32_t scope = 0;
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000446 NEXT_ARG();
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100447 G_filter.scopemask = -1;
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000448 if (rtnl_rtscope_a2n(&scope, *argv)) {
449 if (strcmp(*argv, "all") != 0) {
Bernhard Reutner-Fischer19008b82006-06-07 20:17:41 +0000450 invarg(*argv, "scope");
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000451 }
452 scope = RT_SCOPE_NOWHERE;
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100453 G_filter.scopemask = 0;
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000454 }
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100455 G_filter.scope = scope;
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000456 break;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000457 }
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000458 case 2: /* up */
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100459 G_filter.up = 1;
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000460 break;
461 case 3: /* label */
462 NEXT_ARG();
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100463 G_filter.label = *argv;
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000464 break;
465 case 4: /* dev */
466 NEXT_ARG();
467 default:
468 if (filter_dev) {
469 duparg2("dev", *argv);
470 }
471 filter_dev = *argv;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000472 }
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000473 argv++;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000474 }
475
Bernhard Reutner-Fischerb2908892007-04-12 11:34:39 +0000476 xrtnl_open(&rth);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000477
Bernhard Reutner-Fischerb2908892007-04-12 11:34:39 +0000478 xrtnl_wilddump_request(&rth, preferred_family, RTM_GETLINK);
479 xrtnl_dump_filter(&rth, store_nlmsg, &linfo);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000480
481 if (filter_dev) {
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100482 G_filter.ifindex = xll_name_to_index(filter_dev);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000483 }
484
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000485 if (flush) {
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000486 char flushb[4096-512];
487
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100488 G_filter.flushb = flushb;
489 G_filter.flushp = 0;
490 G_filter.flushe = sizeof(flushb);
491 G_filter.rth = &rth;
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000492
493 for (;;) {
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100494 xrtnl_wilddump_request(&rth, G_filter.family, RTM_GETADDR);
495 G_filter.flushed = 0;
Denis Vlasenkobedfabd2008-06-05 05:00:24 +0000496 xrtnl_dump_filter(&rth, print_addrinfo, NULL);
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100497 if (G_filter.flushed == 0) {
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000498 return 0;
499 }
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100500 if (flush_update() < 0) {
Denis Vlasenko540a2a12007-04-07 01:14:45 +0000501 return 1;
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100502 }
Glenn L McGrathd66370c2003-01-13 21:40:38 +0000503 }
504 }
505
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100506 if (G_filter.family != AF_PACKET) {
507 xrtnl_wilddump_request(&rth, G_filter.family, RTM_GETADDR);
Bernhard Reutner-Fischerb2908892007-04-12 11:34:39 +0000508 xrtnl_dump_filter(&rth, store_nlmsg, &ainfo);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000509 }
510
511
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100512 if (G_filter.family && G_filter.family != AF_PACKET) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000513 struct nlmsg_list **lp;
Denis Vlasenkoed6a49c2007-11-18 22:56:25 +0000514 lp = &linfo;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000515
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100516 if (G_filter.oneline)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000517 no_link = 1;
518
Denis Vlasenkoed6a49c2007-11-18 22:56:25 +0000519 while ((l = *lp) != NULL) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000520 int ok = 0;
521 struct ifinfomsg *ifi = NLMSG_DATA(&l->h);
522 struct nlmsg_list *a;
523
Denis Vlasenkoed6a49c2007-11-18 22:56:25 +0000524 for (a = ainfo; a; a = a->next) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000525 struct nlmsghdr *n = &a->h;
526 struct ifaddrmsg *ifa = NLMSG_DATA(n);
527
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100528 if (ifa->ifa_index != ifi->ifi_index
529 || (G_filter.family && G_filter.family != ifa->ifa_family)
530 ) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000531 continue;
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100532 }
533 if ((G_filter.scope ^ ifa->ifa_scope) & G_filter.scopemask)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000534 continue;
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100535 if ((G_filter.flags ^ ifa->ifa_flags) & G_filter.flagmask)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000536 continue;
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100537 if (G_filter.pfx.family || G_filter.label) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000538 struct rtattr *tb[IFA_MAX+1];
539 memset(tb, 0, sizeof(tb));
540 parse_rtattr(tb, IFA_MAX, IFA_RTA(ifa), IFA_PAYLOAD(n));
541 if (!tb[IFA_LOCAL])
542 tb[IFA_LOCAL] = tb[IFA_ADDRESS];
543
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100544 if (G_filter.pfx.family && tb[IFA_LOCAL]) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000545 inet_prefix dst;
546 memset(&dst, 0, sizeof(dst));
547 dst.family = ifa->ifa_family;
548 memcpy(&dst.data, RTA_DATA(tb[IFA_LOCAL]), RTA_PAYLOAD(tb[IFA_LOCAL]));
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100549 if (inet_addr_match(&dst, &G_filter.pfx, G_filter.pfx.bitlen))
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000550 continue;
551 }
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100552 if (G_filter.label) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000553 SPRINT_BUF(b1);
554 const char *label;
555 if (tb[IFA_LABEL])
556 label = RTA_DATA(tb[IFA_LABEL]);
557 else
558 label = ll_idx_n2a(ifa->ifa_index, b1);
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100559 if (fnmatch(G_filter.label, label, 0) != 0)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000560 continue;
561 }
562 }
563
564 ok = 1;
565 break;
566 }
567 if (!ok)
568 *lp = l->next;
569 else
570 lp = &l->next;
571 }
572 }
573
Denis Vlasenko540a2a12007-04-07 01:14:45 +0000574 for (l = linfo; l; l = l->next) {
Denis Vlasenkobedfabd2008-06-05 05:00:24 +0000575 if (no_link || print_linkinfo(&l->h) == 0) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000576 struct ifinfomsg *ifi = NLMSG_DATA(&l->h);
Denys Vlasenkoffc4bce2010-01-26 11:03:16 +0100577 if (G_filter.family != AF_PACKET)
Denis Vlasenkobedfabd2008-06-05 05:00:24 +0000578 print_selected_addrinfo(ifi->ifi_index, ainfo);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000579 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000580 }
581
Denis Vlasenko540a2a12007-04-07 01:14:45 +0000582 return 0;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000583}
584
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000585static int default_scope(inet_prefix *lcl)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000586{
587 if (lcl->family == AF_INET) {
Denis Vlasenko98ee06d2006-12-31 18:57:37 +0000588 if (lcl->bytelen >= 1 && *(uint8_t*)&lcl->data == 127)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000589 return RT_SCOPE_HOST;
590 }
591 return 0;
592}
593
Denis Vlasenko540a2a12007-04-07 01:14:45 +0000594/* Return value becomes exitcode. It's okay to not return at all */
Denis Vlasenkoed6a49c2007-11-18 22:56:25 +0000595static int ipaddr_modify(int cmd, char **argv)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000596{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000597 static const char option[] ALIGN1 =
Denis Vlasenko990d0f62007-07-24 15:54:42 +0000598 "peer\0""remote\0""broadcast\0""brd\0"
599 "anycast\0""scope\0""dev\0""label\0""local\0";
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000600 struct rtnl_handle rth;
601 struct {
Denis Vlasenko990d0f62007-07-24 15:54:42 +0000602 struct nlmsghdr n;
603 struct ifaddrmsg ifa;
604 char buf[256];
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000605 } req;
Denis Vlasenko990d0f62007-07-24 15:54:42 +0000606 char *d = NULL;
607 char *l = NULL;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000608 inet_prefix lcl;
609 inet_prefix peer;
610 int local_len = 0;
611 int peer_len = 0;
612 int brd_len = 0;
613 int any_len = 0;
Bernhard Reutner-Fischercd0e80c2007-06-20 14:53:49 +0000614 bool scoped = 0;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000615
616 memset(&req, 0, sizeof(req));
617
618 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
619 req.n.nlmsg_flags = NLM_F_REQUEST;
620 req.n.nlmsg_type = cmd;
621 req.ifa.ifa_family = preferred_family;
622
Denis Vlasenkoed6a49c2007-11-18 22:56:25 +0000623 while (*argv) {
Denis Vlasenko990d0f62007-07-24 15:54:42 +0000624 const int option_num = index_in_strings(option, *argv);
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000625 switch (option_num) {
626 case 0: /* peer */
627 case 1: /* remote */
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000628 NEXT_ARG();
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000629
630 if (peer_len) {
631 duparg("peer", *argv);
632 }
633 get_prefix(&peer, *argv, req.ifa.ifa_family);
634 peer_len = peer.bytelen;
635 if (req.ifa.ifa_family == AF_UNSPEC) {
636 req.ifa.ifa_family = peer.family;
637 }
638 addattr_l(&req.n, sizeof(req), IFA_ADDRESS, &peer.data, peer.bytelen);
639 req.ifa.ifa_prefixlen = peer.bitlen;
640 break;
641 case 2: /* broadcast */
642 case 3: /* brd */
643 {
644 inet_prefix addr;
645 NEXT_ARG();
646 if (brd_len) {
647 duparg("broadcast", *argv);
648 }
Denis Vlasenkobf66fbc2006-12-21 13:23:14 +0000649 if (LONE_CHAR(*argv, '+')) {
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000650 brd_len = -1;
Denis Vlasenkoed6a49c2007-11-18 22:56:25 +0000651 } else if (LONE_DASH(*argv)) {
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000652 brd_len = -2;
653 } else {
654 get_addr(&addr, *argv, req.ifa.ifa_family);
655 if (req.ifa.ifa_family == AF_UNSPEC)
656 req.ifa.ifa_family = addr.family;
657 addattr_l(&req.n, sizeof(req), IFA_BROADCAST, &addr.data, addr.bytelen);
658 brd_len = addr.bytelen;
659 }
660 break;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000661 }
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000662 case 4: /* anycast */
663 {
664 inet_prefix addr;
665 NEXT_ARG();
666 if (any_len) {
667 duparg("anycast", *argv);
668 }
669 get_addr(&addr, *argv, req.ifa.ifa_family);
670 if (req.ifa.ifa_family == AF_UNSPEC) {
671 req.ifa.ifa_family = addr.family;
672 }
673 addattr_l(&req.n, sizeof(req), IFA_ANYCAST, &addr.data, addr.bytelen);
674 any_len = addr.bytelen;
675 break;
676 }
677 case 5: /* scope */
678 {
Eric Andersend78aea82006-01-30 18:00:02 +0000679 uint32_t scope = 0;
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000680 NEXT_ARG();
681 if (rtnl_rtscope_a2n(&scope, *argv)) {
Bernhard Reutner-Fischer19008b82006-06-07 20:17:41 +0000682 invarg(*argv, "scope");
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000683 }
684 req.ifa.ifa_scope = scope;
685 scoped = 1;
686 break;
687 }
688 case 6: /* dev */
689 NEXT_ARG();
690 d = *argv;
691 break;
692 case 7: /* label */
693 NEXT_ARG();
694 l = *argv;
695 addattr_l(&req.n, sizeof(req), IFA_LABEL, l, strlen(l)+1);
696 break;
697 case 8: /* local */
698 NEXT_ARG();
699 default:
700 if (local_len) {
701 duparg2("local", *argv);
702 }
703 get_prefix(&lcl, *argv, req.ifa.ifa_family);
704 if (req.ifa.ifa_family == AF_UNSPEC) {
705 req.ifa.ifa_family = lcl.family;
706 }
707 addattr_l(&req.n, sizeof(req), IFA_LOCAL, &lcl.data, lcl.bytelen);
708 local_len = lcl.bytelen;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000709 }
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000710 argv++;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000711 }
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000712
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000713 if (d == NULL) {
Denis Vlasenkoed6a49c2007-11-18 22:56:25 +0000714 bb_error_msg(bb_msg_requires_arg, "\"dev\"");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000715 return -1;
716 }
Bernhard Reutner-Fischercd0e80c2007-06-20 14:53:49 +0000717 if (l && strncmp(d, l, strlen(d)) != 0) {
Rob Landley0a7c8ef2006-02-22 17:01:00 +0000718 bb_error_msg_and_die("\"dev\" (%s) must match \"label\" (%s)", d, l);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000719 }
720
721 if (peer_len == 0 && local_len && cmd != RTM_DELADDR) {
722 peer = lcl;
723 addattr_l(&req.n, sizeof(req), IFA_ADDRESS, &lcl.data, lcl.bytelen);
724 }
725 if (req.ifa.ifa_prefixlen == 0)
726 req.ifa.ifa_prefixlen = lcl.bitlen;
727
728 if (brd_len < 0 && cmd != RTM_DELADDR) {
729 inet_prefix brd;
730 int i;
731 if (req.ifa.ifa_family != AF_INET) {
Denis Vlasenko540a2a12007-04-07 01:14:45 +0000732 bb_error_msg_and_die("broadcast can be set only for IPv4 addresses");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000733 }
734 brd = peer;
735 if (brd.bitlen <= 30) {
736 for (i=31; i>=brd.bitlen; i--) {
737 if (brd_len == -1)
738 brd.data[0] |= htonl(1<<(31-i));
739 else
740 brd.data[0] &= ~htonl(1<<(31-i));
741 }
742 addattr_l(&req.n, sizeof(req), IFA_BROADCAST, &brd.data, brd.bytelen);
743 brd_len = brd.bytelen;
744 }
745 }
746 if (!scoped && cmd != RTM_DELADDR)
747 req.ifa.ifa_scope = default_scope(&lcl);
748
Bernhard Reutner-Fischerb2908892007-04-12 11:34:39 +0000749 xrtnl_open(&rth);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000750
751 ll_init_map(&rth);
752
Bernhard Reutner-Fischerb2908892007-04-12 11:34:39 +0000753 req.ifa.ifa_index = xll_name_to_index(d);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000754
755 if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
Denis Vlasenko540a2a12007-04-07 01:14:45 +0000756 return 2;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000757
Denis Vlasenko540a2a12007-04-07 01:14:45 +0000758 return 0;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000759}
760
Denis Vlasenko540a2a12007-04-07 01:14:45 +0000761/* Return value becomes exitcode. It's okay to not return at all */
Denis Vlasenkoed6a49c2007-11-18 22:56:25 +0000762int do_ipaddr(char **argv)
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000763{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000764 static const char commands[] ALIGN1 =
Denis Vlasenko990d0f62007-07-24 15:54:42 +0000765 "add\0""delete\0""list\0""show\0""lst\0""flush\0";
Rob Landley0a7c8ef2006-02-22 17:01:00 +0000766
Bernhard Reutner-Fischercd0e80c2007-06-20 14:53:49 +0000767 int command_num = 2; /* default command is list */
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000768
769 if (*argv) {
Denis Vlasenko990d0f62007-07-24 15:54:42 +0000770 command_num = index_in_substrings(commands, *argv);
Denis Vlasenkoed6a49c2007-11-18 22:56:25 +0000771 if (command_num < 0 || command_num > 5)
772 bb_error_msg_and_die("unknown command %s", *argv);
773 argv++;
Glenn L McGrath2626ef62002-12-02 01:40:05 +0000774 }
Bernhard Reutner-Fischercd0e80c2007-06-20 14:53:49 +0000775 if (command_num == 0) /* add */
Denis Vlasenkoed6a49c2007-11-18 22:56:25 +0000776 return ipaddr_modify(RTM_NEWADDR, argv);
777 if (command_num == 1) /* delete */
778 return ipaddr_modify(RTM_DELADDR, argv);
779 if (command_num == 5) /* flush */
780 return ipaddr_list_or_flush(argv, 1);
781 /* 2 == list, 3 == show, 4 == lst */
782 return ipaddr_list_or_flush(argv, 0);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000783}