1 /* vi: set sw=4 ts=4: */
3 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
5 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
8 * Laszlo Valko <valko@linux.karinthy.hu> 990223: address label must be zero terminated
13 #include <net/if_arp.h>
15 #include "ip_common.h" /* #include "libbb.h" is inside */
16 #include "common_bufsiz.h"
22 #define IFF_LOWER_UP 0x10000 /* driver signals L1 up */
28 struct rtnl_handle
*rth
;
41 typedef struct filter_t filter_t
;
43 #define G_filter (*(filter_t*)bb_common_bufsiz1)
44 #define INIT_G() do { setup_common_bufsiz(); } while (0)
46 static void print_link_flags(unsigned flags
, unsigned mdown
)
48 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";
56 if (flags
& IFF_UP
&& !(flags
& IFF_RUNNING
))
57 printf("NO-CARRIER,");
58 flags
&= ~IFF_RUNNING
;
70 flags
= print_flags_separated(flag_masks
, flag_labels
, flags
, ",");
78 static void print_queuelen(char *name
)
83 s
= socket(AF_INET
, SOCK_STREAM
, 0);
87 memset(&ifr
, 0, sizeof(ifr
));
88 strncpy_IFNAMSIZ(ifr
.ifr_name
, name
);
89 if (ioctl_or_warn(s
, SIOCGIFTXQLEN
, &ifr
) < 0) {
96 printf("qlen %d", ifr
.ifr_qlen
);
99 static NOINLINE
int print_linkinfo(const struct nlmsghdr
*n
)
101 struct ifinfomsg
*ifi
= NLMSG_DATA(n
);
102 struct rtattr
*tb
[IFLA_MAX
+1];
103 int len
= n
->nlmsg_len
;
105 if (n
->nlmsg_type
!= RTM_NEWLINK
&& n
->nlmsg_type
!= RTM_DELLINK
)
108 len
-= NLMSG_LENGTH(sizeof(*ifi
));
112 if (G_filter
.ifindex
&& ifi
->ifi_index
!= G_filter
.ifindex
)
114 if (G_filter
.up
&& !(ifi
->ifi_flags
& IFF_UP
))
117 memset(tb
, 0, sizeof(tb
));
118 parse_rtattr(tb
, IFLA_MAX
, IFLA_RTA(ifi
), len
);
119 if (tb
[IFLA_IFNAME
] == NULL
) {
120 bb_error_msg("nil ifname");
124 && (!G_filter
.family
|| G_filter
.family
== AF_PACKET
)
125 && fnmatch(G_filter
.label
, RTA_DATA(tb
[IFLA_IFNAME
]), 0)
130 if (n
->nlmsg_type
== RTM_DELLINK
)
133 printf("%d: %s", ifi
->ifi_index
,
134 /*tb[IFLA_IFNAME] ? (char*)RTA_DATA(tb[IFLA_IFNAME]) : "<nil>" - we checked tb[IFLA_IFNAME] above*/
135 (char*)RTA_DATA(tb
[IFLA_IFNAME
])
141 int iflink
= *(int*)RTA_DATA(tb
[IFLA_LINK
]);
145 printf("@%s: ", ll_index_to_name(iflink
));
146 m_flag
= ll_index_to_flags(iflink
);
147 m_flag
= !(m_flag
& IFF_UP
);
152 print_link_flags(ifi
->ifi_flags
, m_flag
);
156 printf("mtu %u ", *(int*)RTA_DATA(tb
[IFLA_MTU
]));
158 printf("qdisc %s ", (char*)RTA_DATA(tb
[IFLA_QDISC
]));
160 if (tb
[IFLA_MASTER
]) {
161 printf("master %s ", ll_index_to_name(*(int*)RTA_DATA(tb
[IFLA_MASTER
])));
164 /* IFLA_OPERSTATE was added to kernel with the same commit as IFF_DORMANT */
166 if (tb
[IFLA_OPERSTATE
]) {
167 static const char operstate_labels
[] ALIGN1
=
168 "UNKNOWN\0""NOTPRESENT\0""DOWN\0""LOWERLAYERDOWN\0"
169 "TESTING\0""DORMANT\0""UP\0";
170 printf("state %s ", nth_string(operstate_labels
,
171 *(uint8_t *)RTA_DATA(tb
[IFLA_OPERSTATE
])));
174 if (G_filter
.showqueue
)
175 print_queuelen((char*)RTA_DATA(tb
[IFLA_IFNAME
]));
177 if (!G_filter
.family
|| G_filter
.family
== AF_PACKET
) {
179 printf("%c link/%s ", _SL_
, ll_type_n2a(ifi
->ifi_type
, b1
));
181 if (tb
[IFLA_ADDRESS
]) {
182 fputs(ll_addr_n2a(RTA_DATA(tb
[IFLA_ADDRESS
]),
183 RTA_PAYLOAD(tb
[IFLA_ADDRESS
]),
185 b1
, sizeof(b1
)), stdout
);
187 if (tb
[IFLA_BROADCAST
]) {
188 if (ifi
->ifi_flags
& IFF_POINTOPOINT
)
192 fputs(ll_addr_n2a(RTA_DATA(tb
[IFLA_BROADCAST
]),
193 RTA_PAYLOAD(tb
[IFLA_BROADCAST
]),
195 b1
, sizeof(b1
)), stdout
);
203 static int flush_update(void)
205 if (rtnl_send(G_filter
.rth
, G_filter
.flushb
, G_filter
.flushp
) < 0) {
206 bb_perror_msg("can't send flush request");
213 static int FAST_FUNC
print_addrinfo(const struct sockaddr_nl
*who UNUSED_PARAM
,
214 struct nlmsghdr
*n
, void *arg UNUSED_PARAM
)
216 struct ifaddrmsg
*ifa
= NLMSG_DATA(n
);
217 int len
= n
->nlmsg_len
;
218 struct rtattr
*rta_tb
[IFA_MAX
+1];
220 if (n
->nlmsg_type
!= RTM_NEWADDR
&& n
->nlmsg_type
!= RTM_DELADDR
)
222 len
-= NLMSG_LENGTH(sizeof(*ifa
));
224 bb_error_msg("wrong nlmsg len %d", len
);
228 if (G_filter
.flushb
&& n
->nlmsg_type
!= RTM_NEWADDR
)
231 memset(rta_tb
, 0, sizeof(rta_tb
));
232 parse_rtattr(rta_tb
, IFA_MAX
, IFA_RTA(ifa
), n
->nlmsg_len
- NLMSG_LENGTH(sizeof(*ifa
)));
234 if (!rta_tb
[IFA_LOCAL
])
235 rta_tb
[IFA_LOCAL
] = rta_tb
[IFA_ADDRESS
];
236 if (!rta_tb
[IFA_ADDRESS
])
237 rta_tb
[IFA_ADDRESS
] = rta_tb
[IFA_LOCAL
];
239 if (G_filter
.ifindex
&& G_filter
.ifindex
!= ifa
->ifa_index
)
241 if ((G_filter
.scope
^ ifa
->ifa_scope
) & G_filter
.scopemask
)
243 if ((G_filter
.flags
^ ifa
->ifa_flags
) & G_filter
.flagmask
)
245 if (G_filter
.label
) {
247 if (rta_tb
[IFA_LABEL
])
248 label
= RTA_DATA(rta_tb
[IFA_LABEL
]);
250 label
= ll_index_to_name(ifa
->ifa_index
);
251 if (fnmatch(G_filter
.label
, label
, 0) != 0)
254 if (G_filter
.pfx
.family
) {
255 if (rta_tb
[IFA_LOCAL
]) {
257 memset(&dst
, 0, sizeof(dst
));
258 dst
.family
= ifa
->ifa_family
;
259 memcpy(&dst
.data
, RTA_DATA(rta_tb
[IFA_LOCAL
]), RTA_PAYLOAD(rta_tb
[IFA_LOCAL
]));
260 if (inet_addr_match(&dst
, &G_filter
.pfx
, G_filter
.pfx
.bitlen
))
265 if (G_filter
.flushb
) {
267 if (NLMSG_ALIGN(G_filter
.flushp
) + n
->nlmsg_len
> G_filter
.flushe
) {
271 fn
= (struct nlmsghdr
*)(G_filter
.flushb
+ NLMSG_ALIGN(G_filter
.flushp
));
272 memcpy(fn
, n
, n
->nlmsg_len
);
273 fn
->nlmsg_type
= RTM_DELADDR
;
274 fn
->nlmsg_flags
= NLM_F_REQUEST
;
275 fn
->nlmsg_seq
= ++G_filter
.rth
->seq
;
276 G_filter
.flushp
= (((char*)fn
) + n
->nlmsg_len
) - G_filter
.flushb
;
277 G_filter
.flushed
= 1;
281 if (n
->nlmsg_type
== RTM_DELADDR
)
284 if (G_filter
.oneline
)
285 printf("%u: %s", ifa
->ifa_index
, ll_index_to_name(ifa
->ifa_index
));
286 if (ifa
->ifa_family
== AF_INET
)
288 else if (ifa
->ifa_family
== AF_INET6
)
291 printf(" family %d ", ifa
->ifa_family
);
293 if (rta_tb
[IFA_LOCAL
]) {
294 fputs(rt_addr_n2a(ifa
->ifa_family
, RTA_DATA(rta_tb
[IFA_LOCAL
])),
298 if (rta_tb
[IFA_ADDRESS
] == NULL
299 || memcmp(RTA_DATA(rta_tb
[IFA_ADDRESS
]), RTA_DATA(rta_tb
[IFA_LOCAL
]), 4) == 0
301 printf("/%d ", ifa
->ifa_prefixlen
);
303 printf(" peer %s/%d ",
304 rt_addr_n2a(ifa
->ifa_family
, RTA_DATA(rta_tb
[IFA_ADDRESS
])),
310 if (rta_tb
[IFA_BROADCAST
]) {
312 rt_addr_n2a(ifa
->ifa_family
,
313 RTA_DATA(rta_tb
[IFA_BROADCAST
]))
316 if (rta_tb
[IFA_ANYCAST
]) {
318 rt_addr_n2a(ifa
->ifa_family
,
319 RTA_DATA(rta_tb
[IFA_ANYCAST
]))
322 printf("scope %s ", rtnl_rtscope_n2a(ifa
->ifa_scope
));
323 if (ifa
->ifa_flags
& IFA_F_SECONDARY
) {
324 ifa
->ifa_flags
&= ~IFA_F_SECONDARY
;
325 printf("secondary ");
327 if (ifa
->ifa_flags
& IFA_F_TENTATIVE
) {
328 ifa
->ifa_flags
&= ~IFA_F_TENTATIVE
;
329 printf("tentative ");
331 if (ifa
->ifa_flags
& IFA_F_DEPRECATED
) {
332 ifa
->ifa_flags
&= ~IFA_F_DEPRECATED
;
333 printf("deprecated ");
335 if (!(ifa
->ifa_flags
& IFA_F_PERMANENT
)) {
338 ifa
->ifa_flags
&= ~IFA_F_PERMANENT
;
340 printf("flags %02x ", ifa
->ifa_flags
);
341 if (rta_tb
[IFA_LABEL
])
342 fputs((char*)RTA_DATA(rta_tb
[IFA_LABEL
]), stdout
);
343 if (rta_tb
[IFA_CACHEINFO
]) {
344 struct ifa_cacheinfo
*ci
= RTA_DATA(rta_tb
[IFA_CACHEINFO
]);
347 if (ci
->ifa_valid
== 0xFFFFFFFFU
)
348 sprintf(buf
, "valid_lft forever");
350 sprintf(buf
, "valid_lft %dsec", ci
->ifa_valid
);
351 if (ci
->ifa_prefered
== 0xFFFFFFFFU
)
352 sprintf(buf
+strlen(buf
), " preferred_lft forever");
354 sprintf(buf
+strlen(buf
), " preferred_lft %dsec", ci
->ifa_prefered
);
364 struct nlmsg_list
*next
;
368 static int print_selected_addrinfo(int ifindex
, struct nlmsg_list
*ainfo
)
370 for (; ainfo
; ainfo
= ainfo
->next
) {
371 struct nlmsghdr
*n
= &ainfo
->h
;
372 struct ifaddrmsg
*ifa
= NLMSG_DATA(n
);
374 if (n
->nlmsg_type
!= RTM_NEWADDR
)
376 if (n
->nlmsg_len
< NLMSG_LENGTH(sizeof(ifa
)))
378 if (ifa
->ifa_index
!= ifindex
379 || (G_filter
.family
&& G_filter
.family
!= ifa
->ifa_family
)
383 print_addrinfo(NULL
, n
, NULL
);
389 static int FAST_FUNC
store_nlmsg(const struct sockaddr_nl
*who
, struct nlmsghdr
*n
, void *arg
)
391 struct nlmsg_list
**linfo
= (struct nlmsg_list
**)arg
;
392 struct nlmsg_list
*h
;
393 struct nlmsg_list
**lp
;
395 h
= xzalloc(n
->nlmsg_len
+ sizeof(void*));
397 memcpy(&h
->h
, n
, n
->nlmsg_len
);
398 /*h->next = NULL; - xzalloc did it */
400 for (lp
= linfo
; *lp
; lp
= &(*lp
)->next
)
404 ll_remember_index(who
, n
, NULL
);
408 static void ipaddr_reset_filter(int _oneline
)
410 memset(&G_filter
, 0, sizeof(G_filter
));
411 G_filter
.oneline
= _oneline
;
414 /* Return value becomes exitcode. It's okay to not return at all */
415 int FAST_FUNC
ipaddr_list_or_flush(char **argv
, int flush
)
417 static const char option
[] ALIGN1
= "to\0""scope\0""up\0""label\0""dev\0";
419 struct nlmsg_list
*linfo
= NULL
;
420 struct nlmsg_list
*ainfo
= NULL
;
421 struct nlmsg_list
*l
;
422 struct rtnl_handle rth
;
423 char *filter_dev
= NULL
;
426 ipaddr_reset_filter(oneline
);
427 G_filter
.showqueue
= 1;
429 if (G_filter
.family
== AF_UNSPEC
)
430 G_filter
.family
= preferred_family
;
434 bb_error_msg_and_die(bb_msg_requires_arg
, "flush");
436 if (G_filter
.family
== AF_PACKET
) {
437 bb_error_msg_and_die("can't flush link addresses");
442 const smalluint key
= index_in_strings(option
, *argv
);
443 if (key
== 0) { /* to */
445 get_prefix(&G_filter
.pfx
, *argv
, G_filter
.family
);
446 if (G_filter
.family
== AF_UNSPEC
) {
447 G_filter
.family
= G_filter
.pfx
.family
;
449 } else if (key
== 1) { /* scope */
452 G_filter
.scopemask
= -1;
453 if (rtnl_rtscope_a2n(&scope
, *argv
)) {
454 if (strcmp(*argv
, "all") != 0) {
455 invarg_1_to_2(*argv
, "scope");
457 scope
= RT_SCOPE_NOWHERE
;
458 G_filter
.scopemask
= 0;
460 G_filter
.scope
= scope
;
461 } else if (key
== 2) { /* up */
463 } else if (key
== 3) { /* label */
465 G_filter
.label
= *argv
;
467 if (key
== 4) /* dev */
470 duparg2("dev", *argv
);
478 xrtnl_wilddump_request(&rth
, preferred_family
, RTM_GETLINK
);
479 xrtnl_dump_filter(&rth
, store_nlmsg
, &linfo
);
482 G_filter
.ifindex
= xll_name_to_index(filter_dev
);
486 char flushb
[4096-512];
488 G_filter
.flushb
= flushb
;
490 G_filter
.flushe
= sizeof(flushb
);
494 xrtnl_wilddump_request(&rth
, G_filter
.family
, RTM_GETADDR
);
495 G_filter
.flushed
= 0;
496 xrtnl_dump_filter(&rth
, print_addrinfo
, NULL
);
497 if (G_filter
.flushed
== 0) {
500 if (flush_update() < 0) {
506 if (G_filter
.family
!= AF_PACKET
) {
507 xrtnl_wilddump_request(&rth
, G_filter
.family
, RTM_GETADDR
);
508 xrtnl_dump_filter(&rth
, store_nlmsg
, &ainfo
);
512 if (G_filter
.family
&& G_filter
.family
!= AF_PACKET
) {
513 struct nlmsg_list
**lp
;
516 if (G_filter
.oneline
)
519 while ((l
= *lp
) != NULL
) {
521 struct ifinfomsg
*ifi
= NLMSG_DATA(&l
->h
);
522 struct nlmsg_list
*a
;
524 for (a
= ainfo
; a
; a
= a
->next
) {
525 struct nlmsghdr
*n
= &a
->h
;
526 struct ifaddrmsg
*ifa
= NLMSG_DATA(n
);
528 if (ifa
->ifa_index
!= ifi
->ifi_index
529 || (G_filter
.family
&& G_filter
.family
!= ifa
->ifa_family
)
533 if ((G_filter
.scope
^ ifa
->ifa_scope
) & G_filter
.scopemask
)
535 if ((G_filter
.flags
^ ifa
->ifa_flags
) & G_filter
.flagmask
)
537 if (G_filter
.pfx
.family
|| G_filter
.label
) {
538 struct rtattr
*tb
[IFA_MAX
+1];
539 memset(tb
, 0, sizeof(tb
));
540 parse_rtattr(tb
, IFA_MAX
, IFA_RTA(ifa
), IFA_PAYLOAD(n
));
542 tb
[IFA_LOCAL
] = tb
[IFA_ADDRESS
];
544 if (G_filter
.pfx
.family
&& tb
[IFA_LOCAL
]) {
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
]));
549 if (inet_addr_match(&dst
, &G_filter
.pfx
, G_filter
.pfx
.bitlen
))
552 if (G_filter
.label
) {
555 label
= RTA_DATA(tb
[IFA_LABEL
]);
557 label
= ll_index_to_name(ifa
->ifa_index
);
558 if (fnmatch(G_filter
.label
, label
, 0) != 0)
573 for (l
= linfo
; l
; l
= l
->next
) {
574 if (no_link
|| print_linkinfo(&l
->h
) == 0) {
575 struct ifinfomsg
*ifi
= NLMSG_DATA(&l
->h
);
576 if (G_filter
.family
!= AF_PACKET
)
577 print_selected_addrinfo(ifi
->ifi_index
, ainfo
);
584 static int default_scope(inet_prefix
*lcl
)
586 if (lcl
->family
== AF_INET
) {
587 if (lcl
->bytelen
>= 1 && *(uint8_t*)&lcl
->data
== 127)
588 return RT_SCOPE_HOST
;
593 /* Return value becomes exitcode. It's okay to not return at all */
594 static int ipaddr_modify(int cmd
, int flags
, char **argv
)
596 static const char option
[] ALIGN1
=
597 "peer\0""remote\0""broadcast\0""brd\0"
598 "anycast\0""scope\0""dev\0""label\0""local\0";
599 struct rtnl_handle rth
;
602 struct ifaddrmsg ifa
;
615 memset(&req
, 0, sizeof(req
));
617 req
.n
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct ifaddrmsg
));
618 req
.n
.nlmsg_flags
= NLM_F_REQUEST
| flags
;
619 req
.n
.nlmsg_type
= cmd
;
620 req
.ifa
.ifa_family
= preferred_family
;
623 unsigned arg
= index_in_strings(option
, *argv
);
624 /* if search fails, "local" is assumed */
628 if (arg
<= 1) { /* peer, remote */
630 duparg("peer", *argv
);
632 get_prefix(&peer
, *argv
, req
.ifa
.ifa_family
);
633 peer_len
= peer
.bytelen
;
634 if (req
.ifa
.ifa_family
== AF_UNSPEC
) {
635 req
.ifa
.ifa_family
= peer
.family
;
637 addattr_l(&req
.n
, sizeof(req
), IFA_ADDRESS
, &peer
.data
, peer
.bytelen
);
638 req
.ifa
.ifa_prefixlen
= peer
.bitlen
;
639 } else if (arg
<= 3) { /* broadcast, brd */
642 duparg("broadcast", *argv
);
644 if (LONE_CHAR(*argv
, '+')) {
646 } else if (LONE_DASH(*argv
)) {
649 get_addr(&addr
, *argv
, req
.ifa
.ifa_family
);
650 if (req
.ifa
.ifa_family
== AF_UNSPEC
)
651 req
.ifa
.ifa_family
= addr
.family
;
652 addattr_l(&req
.n
, sizeof(req
), IFA_BROADCAST
, &addr
.data
, addr
.bytelen
);
653 brd_len
= addr
.bytelen
;
655 } else if (arg
== 4) { /* anycast */
658 duparg("anycast", *argv
);
660 get_addr(&addr
, *argv
, req
.ifa
.ifa_family
);
661 if (req
.ifa
.ifa_family
== AF_UNSPEC
) {
662 req
.ifa
.ifa_family
= addr
.family
;
664 addattr_l(&req
.n
, sizeof(req
), IFA_ANYCAST
, &addr
.data
, addr
.bytelen
);
665 any_len
= addr
.bytelen
;
666 } else if (arg
== 5) { /* scope */
668 if (rtnl_rtscope_a2n(&scope
, *argv
)) {
669 invarg_1_to_2(*argv
, "scope");
671 req
.ifa
.ifa_scope
= scope
;
673 } else if (arg
== 6) { /* dev */
675 } else if (arg
== 7) { /* label */
677 addattr_l(&req
.n
, sizeof(req
), IFA_LABEL
, l
, strlen(l
) + 1);
679 /* local (specified or assumed) */
681 duparg2("local", *argv
);
683 get_prefix(&lcl
, *argv
, req
.ifa
.ifa_family
);
684 if (req
.ifa
.ifa_family
== AF_UNSPEC
) {
685 req
.ifa
.ifa_family
= lcl
.family
;
687 addattr_l(&req
.n
, sizeof(req
), IFA_LOCAL
, &lcl
.data
, lcl
.bytelen
);
688 local_len
= lcl
.bytelen
;
694 /* There was no "dev IFACE", but we need that */
695 bb_error_msg_and_die("need \"dev IFACE\"");
697 if (l
&& !is_prefixed_with(l
, d
)) {
698 bb_error_msg_and_die("\"dev\" (%s) must match \"label\" (%s)", d
, l
);
701 if (peer_len
== 0 && local_len
&& cmd
!= RTM_DELADDR
) {
703 addattr_l(&req
.n
, sizeof(req
), IFA_ADDRESS
, &lcl
.data
, lcl
.bytelen
);
705 if (req
.ifa
.ifa_prefixlen
== 0)
706 req
.ifa
.ifa_prefixlen
= lcl
.bitlen
;
708 if (brd_len
< 0 && cmd
!= RTM_DELADDR
) {
711 if (req
.ifa
.ifa_family
!= AF_INET
) {
712 bb_error_msg_and_die("broadcast can be set only for IPv4 addresses");
715 if (brd
.bitlen
<= 30) {
716 for (i
= 31; i
>= brd
.bitlen
; i
--) {
718 brd
.data
[0] |= htonl(1<<(31-i
));
720 brd
.data
[0] &= ~htonl(1<<(31-i
));
722 addattr_l(&req
.n
, sizeof(req
), IFA_BROADCAST
, &brd
.data
, brd
.bytelen
);
723 brd_len
= brd
.bytelen
;
726 if (!scoped
&& cmd
!= RTM_DELADDR
)
727 req
.ifa
.ifa_scope
= default_scope(&lcl
);
733 req
.ifa
.ifa_index
= xll_name_to_index(d
);
735 if (rtnl_talk(&rth
, &req
.n
, 0, 0, NULL
, NULL
, NULL
) < 0)
741 /* Return value becomes exitcode. It's okay to not return at all */
742 int FAST_FUNC
do_ipaddr(char **argv
)
744 static const char commands
[] ALIGN1
=
745 /* 0 1 2 3 4 5 6 7 8 */
746 "add\0""change\0""chg\0""replace\0""delete\0""list\0""show\0""lst\0""flush\0";
752 cmd
= index_in_substrings(commands
, *argv
);
754 invarg_1_to_2(*argv
, applet_name
);
757 return ipaddr_modify(
758 /*cmd:*/ cmd
== 4 ? RTM_DELADDR
: RTM_NEWADDR
,
760 cmd
== 0 ? NLM_F_CREATE
|NLM_F_EXCL
: /* add */
761 cmd
== 1 || cmd
== 2 ? NLM_F_REPLACE
: /* change */
762 cmd
== 3 ? NLM_F_CREATE
|NLM_F_REPLACE
: /* replace */
767 return ipaddr_list_or_flush(argv
, cmd
== 8);