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 */
21 #define IFF_LOWER_UP 0x10000 /* driver signals L1 up */
27 struct rtnl_handle
*rth
;
40 typedef struct filter_t filter_t
;
42 #define G_filter (*(filter_t*)&bb_common_bufsiz1)
45 static void print_link_flags(unsigned flags
, unsigned mdown
)
47 static const int flag_masks
[] = {
48 IFF_LOOPBACK
, IFF_BROADCAST
, IFF_POINTOPOINT
,
49 IFF_MULTICAST
, IFF_NOARP
, IFF_UP
, IFF_LOWER_UP
};
50 static const char flag_labels
[] ALIGN1
=
51 "LOOPBACK\0""BROADCAST\0""POINTOPOINT\0"
52 "MULTICAST\0""NOARP\0""UP\0""LOWER_UP\0";
55 if (flags
& IFF_UP
&& !(flags
& IFF_RUNNING
))
56 printf("NO-CARRIER,");
57 flags
&= ~IFF_RUNNING
;
69 flags
= print_flags_separated(flag_masks
, flag_labels
, flags
, ",");
77 static void print_queuelen(char *name
)
82 s
= socket(AF_INET
, SOCK_STREAM
, 0);
86 memset(&ifr
, 0, sizeof(ifr
));
87 strncpy_IFNAMSIZ(ifr
.ifr_name
, name
);
88 if (ioctl_or_warn(s
, SIOCGIFTXQLEN
, &ifr
) < 0) {
95 printf("qlen %d", ifr
.ifr_qlen
);
98 static NOINLINE
int print_linkinfo(const struct nlmsghdr
*n
)
100 struct ifinfomsg
*ifi
= NLMSG_DATA(n
);
101 struct rtattr
*tb
[IFLA_MAX
+1];
102 int len
= n
->nlmsg_len
;
104 if (n
->nlmsg_type
!= RTM_NEWLINK
&& n
->nlmsg_type
!= RTM_DELLINK
)
107 len
-= NLMSG_LENGTH(sizeof(*ifi
));
111 if (G_filter
.ifindex
&& ifi
->ifi_index
!= G_filter
.ifindex
)
113 if (G_filter
.up
&& !(ifi
->ifi_flags
& IFF_UP
))
116 memset(tb
, 0, sizeof(tb
));
117 parse_rtattr(tb
, IFLA_MAX
, IFLA_RTA(ifi
), len
);
118 if (tb
[IFLA_IFNAME
] == NULL
) {
119 bb_error_msg("nil ifname");
123 && (!G_filter
.family
|| G_filter
.family
== AF_PACKET
)
124 && fnmatch(G_filter
.label
, RTA_DATA(tb
[IFLA_IFNAME
]), 0)
129 if (n
->nlmsg_type
== RTM_DELLINK
)
132 printf("%d: %s", ifi
->ifi_index
,
133 /*tb[IFLA_IFNAME] ? (char*)RTA_DATA(tb[IFLA_IFNAME]) : "<nil>" - we checked tb[IFLA_IFNAME] above*/
134 (char*)RTA_DATA(tb
[IFLA_IFNAME
])
141 int iflink
= *(int*)RTA_DATA(tb
[IFLA_LINK
]);
145 printf("@%s: ", ll_idx_n2a(iflink
, b1
));
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
]) {
162 printf("master %s ", ll_idx_n2a(*(int*)RTA_DATA(tb
[IFLA_MASTER
]), b1
));
165 /* IFLA_OPERSTATE was added to kernel with the same commit as IFF_DORMANT */
167 if (tb
[IFLA_OPERSTATE
]) {
168 static const char operstate_labels
[] ALIGN1
=
169 "UNKNOWN\0""NOTPRESENT\0""DOWN\0""LOWERLAYERDOWN\0"
170 "TESTING\0""DORMANT\0""UP\0";
171 printf("state %s ", nth_string(operstate_labels
,
172 *(uint8_t *)RTA_DATA(tb
[IFLA_OPERSTATE
])));
175 if (G_filter
.showqueue
)
176 print_queuelen((char*)RTA_DATA(tb
[IFLA_IFNAME
]));
178 if (!G_filter
.family
|| G_filter
.family
== AF_PACKET
) {
180 printf("%c link/%s ", _SL_
, ll_type_n2a(ifi
->ifi_type
, b1
));
182 if (tb
[IFLA_ADDRESS
]) {
183 fputs(ll_addr_n2a(RTA_DATA(tb
[IFLA_ADDRESS
]),
184 RTA_PAYLOAD(tb
[IFLA_ADDRESS
]),
186 b1
, sizeof(b1
)), stdout
);
188 if (tb
[IFLA_BROADCAST
]) {
189 if (ifi
->ifi_flags
& IFF_POINTOPOINT
)
193 fputs(ll_addr_n2a(RTA_DATA(tb
[IFLA_BROADCAST
]),
194 RTA_PAYLOAD(tb
[IFLA_BROADCAST
]),
196 b1
, sizeof(b1
)), stdout
);
204 static int flush_update(void)
206 if (rtnl_send(G_filter
.rth
, G_filter
.flushb
, G_filter
.flushp
) < 0) {
207 bb_perror_msg("can't send flush request");
214 static int FAST_FUNC
print_addrinfo(const struct sockaddr_nl
*who UNUSED_PARAM
,
215 struct nlmsghdr
*n
, void *arg UNUSED_PARAM
)
217 struct ifaddrmsg
*ifa
= NLMSG_DATA(n
);
218 int len
= n
->nlmsg_len
;
219 struct rtattr
* rta_tb
[IFA_MAX
+1];
223 if (n
->nlmsg_type
!= RTM_NEWADDR
&& n
->nlmsg_type
!= RTM_DELADDR
)
225 len
-= NLMSG_LENGTH(sizeof(*ifa
));
227 bb_error_msg("wrong nlmsg len %d", len
);
231 if (G_filter
.flushb
&& n
->nlmsg_type
!= RTM_NEWADDR
)
234 memset(rta_tb
, 0, sizeof(rta_tb
));
235 parse_rtattr(rta_tb
, IFA_MAX
, IFA_RTA(ifa
), n
->nlmsg_len
- NLMSG_LENGTH(sizeof(*ifa
)));
237 if (!rta_tb
[IFA_LOCAL
])
238 rta_tb
[IFA_LOCAL
] = rta_tb
[IFA_ADDRESS
];
239 if (!rta_tb
[IFA_ADDRESS
])
240 rta_tb
[IFA_ADDRESS
] = rta_tb
[IFA_LOCAL
];
242 if (G_filter
.ifindex
&& G_filter
.ifindex
!= ifa
->ifa_index
)
244 if ((G_filter
.scope
^ ifa
->ifa_scope
) & G_filter
.scopemask
)
246 if ((G_filter
.flags
^ ifa
->ifa_flags
) & G_filter
.flagmask
)
248 if (G_filter
.label
) {
250 if (rta_tb
[IFA_LABEL
])
251 label
= RTA_DATA(rta_tb
[IFA_LABEL
]);
253 label
= ll_idx_n2a(ifa
->ifa_index
, b1
);
254 if (fnmatch(G_filter
.label
, label
, 0) != 0)
257 if (G_filter
.pfx
.family
) {
258 if (rta_tb
[IFA_LOCAL
]) {
260 memset(&dst
, 0, sizeof(dst
));
261 dst
.family
= ifa
->ifa_family
;
262 memcpy(&dst
.data
, RTA_DATA(rta_tb
[IFA_LOCAL
]), RTA_PAYLOAD(rta_tb
[IFA_LOCAL
]));
263 if (inet_addr_match(&dst
, &G_filter
.pfx
, G_filter
.pfx
.bitlen
))
268 if (G_filter
.flushb
) {
270 if (NLMSG_ALIGN(G_filter
.flushp
) + n
->nlmsg_len
> G_filter
.flushe
) {
274 fn
= (struct nlmsghdr
*)(G_filter
.flushb
+ NLMSG_ALIGN(G_filter
.flushp
));
275 memcpy(fn
, n
, n
->nlmsg_len
);
276 fn
->nlmsg_type
= RTM_DELADDR
;
277 fn
->nlmsg_flags
= NLM_F_REQUEST
;
278 fn
->nlmsg_seq
= ++G_filter
.rth
->seq
;
279 G_filter
.flushp
= (((char*)fn
) + n
->nlmsg_len
) - G_filter
.flushb
;
280 G_filter
.flushed
= 1;
284 if (n
->nlmsg_type
== RTM_DELADDR
)
287 if (G_filter
.oneline
)
288 printf("%u: %s", ifa
->ifa_index
, ll_index_to_name(ifa
->ifa_index
));
289 if (ifa
->ifa_family
== AF_INET
)
291 else if (ifa
->ifa_family
== AF_INET6
)
294 printf(" family %d ", ifa
->ifa_family
);
296 if (rta_tb
[IFA_LOCAL
]) {
297 fputs(rt_addr_n2a(ifa
->ifa_family
,
298 RTA_DATA(rta_tb
[IFA_LOCAL
]),
299 abuf
, sizeof(abuf
)), stdout
);
301 if (rta_tb
[IFA_ADDRESS
] == NULL
302 || memcmp(RTA_DATA(rta_tb
[IFA_ADDRESS
]), RTA_DATA(rta_tb
[IFA_LOCAL
]), 4) == 0
304 printf("/%d ", ifa
->ifa_prefixlen
);
306 printf(" peer %s/%d ",
307 rt_addr_n2a(ifa
->ifa_family
,
308 RTA_DATA(rta_tb
[IFA_ADDRESS
]),
314 if (rta_tb
[IFA_BROADCAST
]) {
316 rt_addr_n2a(ifa
->ifa_family
,
317 RTA_DATA(rta_tb
[IFA_BROADCAST
]),
318 abuf
, sizeof(abuf
)));
320 if (rta_tb
[IFA_ANYCAST
]) {
322 rt_addr_n2a(ifa
->ifa_family
,
323 RTA_DATA(rta_tb
[IFA_ANYCAST
]),
324 abuf
, sizeof(abuf
)));
326 printf("scope %s ", rtnl_rtscope_n2a(ifa
->ifa_scope
, b1
));
327 if (ifa
->ifa_flags
& IFA_F_SECONDARY
) {
328 ifa
->ifa_flags
&= ~IFA_F_SECONDARY
;
329 printf("secondary ");
331 if (ifa
->ifa_flags
& IFA_F_TENTATIVE
) {
332 ifa
->ifa_flags
&= ~IFA_F_TENTATIVE
;
333 printf("tentative ");
335 if (ifa
->ifa_flags
& IFA_F_DEPRECATED
) {
336 ifa
->ifa_flags
&= ~IFA_F_DEPRECATED
;
337 printf("deprecated ");
339 if (!(ifa
->ifa_flags
& IFA_F_PERMANENT
)) {
342 ifa
->ifa_flags
&= ~IFA_F_PERMANENT
;
344 printf("flags %02x ", ifa
->ifa_flags
);
345 if (rta_tb
[IFA_LABEL
])
346 fputs((char*)RTA_DATA(rta_tb
[IFA_LABEL
]), stdout
);
347 if (rta_tb
[IFA_CACHEINFO
]) {
348 struct ifa_cacheinfo
*ci
= RTA_DATA(rta_tb
[IFA_CACHEINFO
]);
351 if (ci
->ifa_valid
== 0xFFFFFFFFU
)
352 sprintf(buf
, "valid_lft forever");
354 sprintf(buf
, "valid_lft %dsec", ci
->ifa_valid
);
355 if (ci
->ifa_prefered
== 0xFFFFFFFFU
)
356 sprintf(buf
+strlen(buf
), " preferred_lft forever");
358 sprintf(buf
+strlen(buf
), " preferred_lft %dsec", ci
->ifa_prefered
);
368 struct nlmsg_list
*next
;
372 static int print_selected_addrinfo(int ifindex
, struct nlmsg_list
*ainfo
)
374 for (; ainfo
; ainfo
= ainfo
->next
) {
375 struct nlmsghdr
*n
= &ainfo
->h
;
376 struct ifaddrmsg
*ifa
= NLMSG_DATA(n
);
378 if (n
->nlmsg_type
!= RTM_NEWADDR
)
380 if (n
->nlmsg_len
< NLMSG_LENGTH(sizeof(ifa
)))
382 if (ifa
->ifa_index
!= ifindex
383 || (G_filter
.family
&& G_filter
.family
!= ifa
->ifa_family
)
387 print_addrinfo(NULL
, n
, NULL
);
393 static int FAST_FUNC
store_nlmsg(const struct sockaddr_nl
*who
, struct nlmsghdr
*n
, void *arg
)
395 struct nlmsg_list
**linfo
= (struct nlmsg_list
**)arg
;
396 struct nlmsg_list
*h
;
397 struct nlmsg_list
**lp
;
399 h
= xzalloc(n
->nlmsg_len
+ sizeof(void*));
401 memcpy(&h
->h
, n
, n
->nlmsg_len
);
402 /*h->next = NULL; - xzalloc did it */
404 for (lp
= linfo
; *lp
; lp
= &(*lp
)->next
)
408 ll_remember_index(who
, n
, NULL
);
412 static void ipaddr_reset_filter(int _oneline
)
414 memset(&G_filter
, 0, sizeof(G_filter
));
415 G_filter
.oneline
= _oneline
;
418 /* Return value becomes exitcode. It's okay to not return at all */
419 int FAST_FUNC
ipaddr_list_or_flush(char **argv
, int flush
)
421 static const char option
[] ALIGN1
= "to\0""scope\0""up\0""label\0""dev\0";
423 struct nlmsg_list
*linfo
= NULL
;
424 struct nlmsg_list
*ainfo
= NULL
;
425 struct nlmsg_list
*l
;
426 struct rtnl_handle rth
;
427 char *filter_dev
= NULL
;
430 ipaddr_reset_filter(oneline
);
431 G_filter
.showqueue
= 1;
433 if (G_filter
.family
== AF_UNSPEC
)
434 G_filter
.family
= preferred_family
;
438 bb_error_msg_and_die(bb_msg_requires_arg
, "flush");
440 if (G_filter
.family
== AF_PACKET
) {
441 bb_error_msg_and_die("can't flush link addresses");
446 const smalluint key
= index_in_strings(option
, *argv
);
447 if (key
== 0) { /* to */
449 get_prefix(&G_filter
.pfx
, *argv
, G_filter
.family
);
450 if (G_filter
.family
== AF_UNSPEC
) {
451 G_filter
.family
= G_filter
.pfx
.family
;
453 } else if (key
== 1) { /* scope */
456 G_filter
.scopemask
= -1;
457 if (rtnl_rtscope_a2n(&scope
, *argv
)) {
458 if (strcmp(*argv
, "all") != 0) {
459 invarg(*argv
, "scope");
461 scope
= RT_SCOPE_NOWHERE
;
462 G_filter
.scopemask
= 0;
464 G_filter
.scope
= scope
;
465 } else if (key
== 2) { /* up */
467 } else if (key
== 3) { /* label */
469 G_filter
.label
= *argv
;
471 if (key
== 4) /* dev */
474 duparg2("dev", *argv
);
482 xrtnl_wilddump_request(&rth
, preferred_family
, RTM_GETLINK
);
483 xrtnl_dump_filter(&rth
, store_nlmsg
, &linfo
);
486 G_filter
.ifindex
= xll_name_to_index(filter_dev
);
490 char flushb
[4096-512];
492 G_filter
.flushb
= flushb
;
494 G_filter
.flushe
= sizeof(flushb
);
498 xrtnl_wilddump_request(&rth
, G_filter
.family
, RTM_GETADDR
);
499 G_filter
.flushed
= 0;
500 xrtnl_dump_filter(&rth
, print_addrinfo
, NULL
);
501 if (G_filter
.flushed
== 0) {
504 if (flush_update() < 0) {
510 if (G_filter
.family
!= AF_PACKET
) {
511 xrtnl_wilddump_request(&rth
, G_filter
.family
, RTM_GETADDR
);
512 xrtnl_dump_filter(&rth
, store_nlmsg
, &ainfo
);
516 if (G_filter
.family
&& G_filter
.family
!= AF_PACKET
) {
517 struct nlmsg_list
**lp
;
520 if (G_filter
.oneline
)
523 while ((l
= *lp
) != NULL
) {
525 struct ifinfomsg
*ifi
= NLMSG_DATA(&l
->h
);
526 struct nlmsg_list
*a
;
528 for (a
= ainfo
; a
; a
= a
->next
) {
529 struct nlmsghdr
*n
= &a
->h
;
530 struct ifaddrmsg
*ifa
= NLMSG_DATA(n
);
532 if (ifa
->ifa_index
!= ifi
->ifi_index
533 || (G_filter
.family
&& G_filter
.family
!= ifa
->ifa_family
)
537 if ((G_filter
.scope
^ ifa
->ifa_scope
) & G_filter
.scopemask
)
539 if ((G_filter
.flags
^ ifa
->ifa_flags
) & G_filter
.flagmask
)
541 if (G_filter
.pfx
.family
|| G_filter
.label
) {
542 struct rtattr
*tb
[IFA_MAX
+1];
543 memset(tb
, 0, sizeof(tb
));
544 parse_rtattr(tb
, IFA_MAX
, IFA_RTA(ifa
), IFA_PAYLOAD(n
));
546 tb
[IFA_LOCAL
] = tb
[IFA_ADDRESS
];
548 if (G_filter
.pfx
.family
&& tb
[IFA_LOCAL
]) {
550 memset(&dst
, 0, sizeof(dst
));
551 dst
.family
= ifa
->ifa_family
;
552 memcpy(&dst
.data
, RTA_DATA(tb
[IFA_LOCAL
]), RTA_PAYLOAD(tb
[IFA_LOCAL
]));
553 if (inet_addr_match(&dst
, &G_filter
.pfx
, G_filter
.pfx
.bitlen
))
556 if (G_filter
.label
) {
560 label
= RTA_DATA(tb
[IFA_LABEL
]);
562 label
= ll_idx_n2a(ifa
->ifa_index
, b1
);
563 if (fnmatch(G_filter
.label
, label
, 0) != 0)
578 for (l
= linfo
; l
; l
= l
->next
) {
579 if (no_link
|| print_linkinfo(&l
->h
) == 0) {
580 struct ifinfomsg
*ifi
= NLMSG_DATA(&l
->h
);
581 if (G_filter
.family
!= AF_PACKET
)
582 print_selected_addrinfo(ifi
->ifi_index
, ainfo
);
589 static int default_scope(inet_prefix
*lcl
)
591 if (lcl
->family
== AF_INET
) {
592 if (lcl
->bytelen
>= 1 && *(uint8_t*)&lcl
->data
== 127)
593 return RT_SCOPE_HOST
;
598 /* Return value becomes exitcode. It's okay to not return at all */
599 static int ipaddr_modify(int cmd
, char **argv
)
601 static const char option
[] ALIGN1
=
602 "peer\0""remote\0""broadcast\0""brd\0"
603 "anycast\0""scope\0""dev\0""label\0""local\0";
604 struct rtnl_handle rth
;
607 struct ifaddrmsg ifa
;
620 memset(&req
, 0, sizeof(req
));
622 req
.n
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct ifaddrmsg
));
623 req
.n
.nlmsg_flags
= NLM_F_REQUEST
;
624 req
.n
.nlmsg_type
= cmd
;
625 req
.ifa
.ifa_family
= preferred_family
;
628 const smalluint arg
= index_in_strings(option
, *argv
);
629 if (arg
<= 1) { /* peer, remote */
633 duparg("peer", *argv
);
635 get_prefix(&peer
, *argv
, req
.ifa
.ifa_family
);
636 peer_len
= peer
.bytelen
;
637 if (req
.ifa
.ifa_family
== AF_UNSPEC
) {
638 req
.ifa
.ifa_family
= peer
.family
;
640 addattr_l(&req
.n
, sizeof(req
), IFA_ADDRESS
, &peer
.data
, peer
.bytelen
);
641 req
.ifa
.ifa_prefixlen
= peer
.bitlen
;
642 } else if (arg
<= 3) { /* broadcast, brd */
646 duparg("broadcast", *argv
);
648 if (LONE_CHAR(*argv
, '+')) {
650 } else if (LONE_DASH(*argv
)) {
653 get_addr(&addr
, *argv
, req
.ifa
.ifa_family
);
654 if (req
.ifa
.ifa_family
== AF_UNSPEC
)
655 req
.ifa
.ifa_family
= addr
.family
;
656 addattr_l(&req
.n
, sizeof(req
), IFA_BROADCAST
, &addr
.data
, addr
.bytelen
);
657 brd_len
= addr
.bytelen
;
659 } else if (arg
== 4) { /* anycast */
663 duparg("anycast", *argv
);
665 get_addr(&addr
, *argv
, req
.ifa
.ifa_family
);
666 if (req
.ifa
.ifa_family
== AF_UNSPEC
) {
667 req
.ifa
.ifa_family
= addr
.family
;
669 addattr_l(&req
.n
, sizeof(req
), IFA_ANYCAST
, &addr
.data
, addr
.bytelen
);
670 any_len
= addr
.bytelen
;
671 } else if (arg
== 5) { /* scope */
674 if (rtnl_rtscope_a2n(&scope
, *argv
)) {
675 invarg(*argv
, "scope");
677 req
.ifa
.ifa_scope
= scope
;
679 } else if (arg
== 6) { /* dev */
682 } else if (arg
== 7) { /* label */
685 addattr_l(&req
.n
, sizeof(req
), IFA_LABEL
, l
, strlen(l
) + 1);
687 if (arg
== 8) /* local */
690 duparg2("local", *argv
);
692 get_prefix(&lcl
, *argv
, req
.ifa
.ifa_family
);
693 if (req
.ifa
.ifa_family
== AF_UNSPEC
) {
694 req
.ifa
.ifa_family
= lcl
.family
;
696 addattr_l(&req
.n
, sizeof(req
), IFA_LOCAL
, &lcl
.data
, lcl
.bytelen
);
697 local_len
= lcl
.bytelen
;
703 /* There was no "dev IFACE", but we need that */
704 bb_error_msg_and_die("need \"dev IFACE\"");
706 if (l
&& strncmp(d
, l
, strlen(d
)) != 0) {
707 bb_error_msg_and_die("\"dev\" (%s) must match \"label\" (%s)", d
, l
);
710 if (peer_len
== 0 && local_len
&& cmd
!= RTM_DELADDR
) {
712 addattr_l(&req
.n
, sizeof(req
), IFA_ADDRESS
, &lcl
.data
, lcl
.bytelen
);
714 if (req
.ifa
.ifa_prefixlen
== 0)
715 req
.ifa
.ifa_prefixlen
= lcl
.bitlen
;
717 if (brd_len
< 0 && cmd
!= RTM_DELADDR
) {
720 if (req
.ifa
.ifa_family
!= AF_INET
) {
721 bb_error_msg_and_die("broadcast can be set only for IPv4 addresses");
724 if (brd
.bitlen
<= 30) {
725 for (i
=31; i
>=brd
.bitlen
; i
--) {
727 brd
.data
[0] |= htonl(1<<(31-i
));
729 brd
.data
[0] &= ~htonl(1<<(31-i
));
731 addattr_l(&req
.n
, sizeof(req
), IFA_BROADCAST
, &brd
.data
, brd
.bytelen
);
732 brd_len
= brd
.bytelen
;
735 if (!scoped
&& cmd
!= RTM_DELADDR
)
736 req
.ifa
.ifa_scope
= default_scope(&lcl
);
742 req
.ifa
.ifa_index
= xll_name_to_index(d
);
744 if (rtnl_talk(&rth
, &req
.n
, 0, 0, NULL
, NULL
, NULL
) < 0)
750 /* Return value becomes exitcode. It's okay to not return at all */
751 int FAST_FUNC
do_ipaddr(char **argv
)
753 static const char commands
[] ALIGN1
=
754 "add\0""delete\0""list\0""show\0""lst\0""flush\0";
757 cmd
= index_in_substrings(commands
, *argv
);
759 bb_error_msg_and_die(bb_msg_invalid_arg
, *argv
, applet_name
);
762 return ipaddr_modify((cmd
== 0) ? RTM_NEWADDR
: RTM_DELADDR
, argv
);
764 /* 2 == list, 3 == show, 4 == lst */
765 return ipaddr_list_or_flush(argv
, cmd
== 5);