]> git.proxmox.com Git - mirror_iproute2.git/blame - ip/iplink.c
bpf: check for owner_prog_type and notify users when differ
[mirror_iproute2.git] / ip / iplink.c
CommitLineData
aba5acdf
SH
1/*
2 * iplink.c "ip link".
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>
1d934839 18#include <dlfcn.h>
aba5acdf
SH
19#include <errno.h>
20#include <sys/socket.h>
21#include <linux/if.h>
22#include <linux/if_packet.h>
23#include <linux/if_ether.h>
24#include <linux/sockios.h>
25#include <netinet/in.h>
26#include <arpa/inet.h>
27#include <string.h>
28#include <sys/ioctl.h>
29#include <linux/sockios.h>
fbea6115 30#include <stdbool.h>
aba5acdf
SH
31
32#include "rt_names.h"
33#include "utils.h"
34#include "ip_common.h"
c3087c10 35#include "namespace.h"
aba5acdf 36
1d934839 37#define IPLINK_IOCTL_COMPAT 1
5e3bb534 38#ifndef LIBDIR
5c434a9e 39#define LIBDIR "/usr/lib"
b514b358 40#endif
aba5acdf
SH
41
42static void usage(void) __attribute__((noreturn));
750a405a 43static int iplink_have_newlink(void);
aba5acdf
SH
44
45void iplink_usage(void)
46{
750a405a 47 if (iplink_have_newlink()) {
6773bcc2
SH
48 fprintf(stderr,
49 "Usage: ip link add [link DEV] [ name ] NAME\n"
50 " [ txqueuelen PACKETS ]\n"
51 " [ address LLADDR ]\n"
52 " [ broadcast LLADDR ]\n"
53 " [ mtu MTU ] [index IDX ]\n"
54 " [ numtxqueues QUEUE_COUNT ]\n"
55 " [ numrxqueues QUEUE_COUNT ]\n"
56 " type TYPE [ ARGS ]\n"
57 " ip link delete { DEVICE | dev DEVICE | group DEVGROUP } type TYPE [ ARGS ]\n"
58 "\n"
59 " ip link set { DEVICE | dev DEVICE | group DEVGROUP }\n"
60 " [ { up | down } ]\n"
61 " [ type TYPE ARGS ]\n");
750a405a
SH
62 } else
63 fprintf(stderr, "Usage: ip link set DEVICE [ { up | down } ]\n");
64
6773bcc2
SH
65 fprintf(stderr,
66 " [ arp { on | off } ]\n"
67 " [ dynamic { on | off } ]\n"
68 " [ multicast { on | off } ]\n"
69 " [ allmulticast { on | off } ]\n"
70 " [ promisc { on | off } ]\n"
71 " [ trailers { on | off } ]\n"
72 " [ txqueuelen PACKETS ]\n"
73 " [ name NEWNAME ]\n"
74 " [ address LLADDR ]\n"
75 " [ broadcast LLADDR ]\n"
76 " [ mtu MTU ]\n"
77 " [ netns { PID | NAME } ]\n"
78 " [ link-netnsid ID ]\n"
79 " [ alias NAME ]\n"
80 " [ vf NUM [ mac LLADDR ]\n"
81 " [ vlan VLANID [ qos VLAN-QOS ] [ proto VLAN-PROTO ] ]\n"
82
83 " [ rate TXRATE ]\n"
84 " [ max_tx_rate TXRATE ]\n"
85 " [ min_tx_rate TXRATE ]\n"
86
87 " [ spoofchk { on | off} ]\n"
88 " [ query_rss { on | off} ]\n"
89 " [ state { auto | enable | disable} ] ]\n"
90 " [ trust { on | off} ] ]\n"
91 " [ master DEVICE ][ vrf NAME ]\n"
92 " [ nomaster ]\n"
93 " [ addrgenmode { eui64 | none | stable_secret | random } ]\n"
94 " [ protodown { on | off } ]\n"
95 " ip link show [ DEVICE | group GROUP ] [up] [master DEV] [vrf NAME] [type TYPE]\n");
750a405a
SH
96
97 if (iplink_have_newlink()) {
6773bcc2
SH
98 fprintf(stderr,
99 " ip link help [ TYPE ]\n\n"
100 "TYPE := { vlan | veth | vcan | dummy | ifb | macvlan | macvtap |\n"
6bd1ea28
ZS
101 " bridge | bond | team | ipoib | ip6tnl | ipip | sit | vxlan |\n"
102 " gre | gretap | ip6gre | ip6gretap | vti | nlmon | team_slave |\n"
6773bcc2 103 " bond_slave | ipvlan | geneve | bridge_slave | vrf | macsec }\n");
750a405a 104 }
aba5acdf
SH
105 exit(-1);
106}
107
108static void usage(void)
109{
110 iplink_usage();
111}
112
14645ec2 113static int on_off(const char *msg, const char *realval)
aba5acdf 114{
6c5ffb9a
SH
115 fprintf(stderr,
116 "Error: argument of \"%s\" must be \"on\" or \"off\", not \"%s\"\n",
117 msg, realval);
aba5acdf
SH
118 return -1;
119}
120
1d934839
PM
121static void *BODY; /* cached dlopen(NULL) handle */
122static struct link_util *linkutil_list;
123
22a84711 124struct link_util *get_link_kind(const char *id)
1d934839
PM
125{
126 void *dlh;
127 char buf[256];
128 struct link_util *l;
129
130 for (l = linkutil_list; l; l = l->next)
22a84711 131 if (strcmp(l->id, id) == 0)
1d934839
PM
132 return l;
133
5e3bb534 134 snprintf(buf, sizeof(buf), LIBDIR "/ip/link_%s.so", id);
1d934839
PM
135 dlh = dlopen(buf, RTLD_LAZY);
136 if (dlh == NULL) {
137 /* look in current binary, only open once */
138 dlh = BODY;
139 if (dlh == NULL) {
140 dlh = BODY = dlopen(NULL, RTLD_LAZY);
141 if (dlh == NULL)
142 return NULL;
143 }
144 }
145
22a84711 146 snprintf(buf, sizeof(buf), "%s_link_util", id);
1d934839
PM
147 l = dlsym(dlh, buf);
148 if (l == NULL)
149 return NULL;
150
151 l->next = linkutil_list;
152 linkutil_list = l;
153 return l;
154}
155
d1f28cf1 156static int get_link_mode(const char *mode)
82499282 157{
4ccfb44d 158 if (strcasecmp(mode, "default") == 0)
82499282 159 return IF_LINK_MODE_DEFAULT;
4ccfb44d 160 if (strcasecmp(mode, "dormant") == 0)
82499282
SH
161 return IF_LINK_MODE_DORMANT;
162 return -1;
163}
164
ff7c2084
JP
165static int get_addr_gen_mode(const char *mode)
166{
167 if (strcasecmp(mode, "eui64") == 0)
168 return IN6_ADDR_GEN_MODE_EUI64;
169 if (strcasecmp(mode, "none") == 0)
170 return IN6_ADDR_GEN_MODE_NONE;
8e098dd8
BM
171 if (strcasecmp(mode, "stable_secret") == 0)
172 return IN6_ADDR_GEN_MODE_STABLE_PRIVACY;
8e12bc0a
BM
173 if (strcasecmp(mode, "random") == 0)
174 return IN6_ADDR_GEN_MODE_RANDOM;
ff7c2084
JP
175 return -1;
176}
177
1d934839
PM
178#if IPLINK_IOCTL_COMPAT
179static int have_rtnl_newlink = -1;
180
181static int accept_msg(const struct sockaddr_nl *who,
0628cddd 182 struct rtnl_ctrl_data *ctrl,
1d934839
PM
183 struct nlmsghdr *n, void *arg)
184{
185 struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(n);
186
66e529f5
PM
187 if (n->nlmsg_type == NLMSG_ERROR &&
188 (err->error == -EOPNOTSUPP || err->error == -EINVAL))
1d934839
PM
189 have_rtnl_newlink = 0;
190 else
191 have_rtnl_newlink = 1;
192 return -1;
193}
194
195static int iplink_have_newlink(void)
196{
197 struct {
198 struct nlmsghdr n;
199 struct ifinfomsg i;
200 char buf[1024];
d17b136f
PS
201 } req = {
202 .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
203 .n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
204 .n.nlmsg_type = RTM_NEWLINK,
205 .i.ifi_family = AF_UNSPEC,
206 };
1d934839
PM
207
208 if (have_rtnl_newlink < 0) {
d2468da0
SH
209 if (rtnl_send(&rth, &req.n, req.n.nlmsg_len) < 0) {
210 perror("request send failed");
211 exit(1);
212 }
1d934839
PM
213 rtnl_listen(&rth, accept_msg, NULL);
214 }
215 return have_rtnl_newlink;
216}
217#else /* IPLINK_IOCTL_COMPAT */
218static int iplink_have_newlink(void)
219{
220 return 1;
221}
222#endif /* ! IPLINK_IOCTL_COMPAT */
223
909dfe2c
PE
224struct iplink_req {
225 struct nlmsghdr n;
226 struct ifinfomsg i;
227 char buf[1024];
228};
229
8fe58d58
PS
230static int nl_get_ll_addr_len(unsigned int dev_index)
231{
232 int len;
233 struct iplink_req req = {
234 .n = {
235 .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
236 .nlmsg_type = RTM_GETLINK,
237 .nlmsg_flags = NLM_F_REQUEST
238 },
239 .i = {
240 .ifi_family = preferred_family,
241 .ifi_index = dev_index,
242 }
243 };
244 struct rtattr *tb[IFLA_MAX+1];
245
246 if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0)
247 return -1;
248
249 len = req.n.nlmsg_len - NLMSG_LENGTH(sizeof(req.i));
250 if (len < 0)
251 return -1;
252
253 parse_rtattr_flags(tb, IFLA_MAX, IFLA_RTA(&req.i), len, NLA_F_NESTED);
254 if (!tb[IFLA_ADDRESS])
255 return -1;
256
257 return RTA_PAYLOAD(tb[IFLA_ADDRESS]);
258}
259
56e9f0ab
MS
260static void iplink_parse_vf_vlan_info(int vf, int *argcp, char ***argvp,
261 struct ifla_vf_vlan_info *ivvip)
262{
263 int argc = *argcp;
264 char **argv = *argvp;
265
266 NEXT_ARG();
267 if (get_unsigned(&ivvip->vlan, *argv, 0))
268 invarg("Invalid \"vlan\" value\n", *argv);
269
270 ivvip->vf = vf;
271 ivvip->qos = 0;
272 ivvip->vlan_proto = htons(ETH_P_8021Q);
273 if (NEXT_ARG_OK()) {
274 NEXT_ARG();
275 if (matches(*argv, "qos") == 0) {
276 NEXT_ARG();
277 if (get_unsigned(&ivvip->qos, *argv, 0))
278 invarg("Invalid \"qos\" value\n", *argv);
279 } else {
280 /* rewind arg */
281 PREV_ARG();
282 }
283 }
284 if (NEXT_ARG_OK()) {
285 NEXT_ARG();
286 if (matches(*argv, "proto") == 0) {
287 NEXT_ARG();
288 if (ll_proto_a2n(&ivvip->vlan_proto, *argv))
289 invarg("protocol is invalid\n", *argv);
290 if (ivvip->vlan_proto != htons(ETH_P_8021AD) &&
291 ivvip->vlan_proto != htons(ETH_P_8021Q)) {
292 SPRINT_BUF(b1);
293 SPRINT_BUF(b2);
294 char msg[64 + sizeof(b1) + sizeof(b2)];
295
6773bcc2 296 sprintf(msg, "Invalid \"vlan protocol\" value - supported %s, %s\n",
56e9f0ab
MS
297 ll_proto_n2a(htons(ETH_P_8021Q),
298 b1, sizeof(b1)),
299 ll_proto_n2a(htons(ETH_P_8021AD),
300 b2, sizeof(b2)));
301 invarg(msg, *argv);
302 }
303 } else {
304 /* rewind arg */
305 PREV_ARG();
306 }
307 }
308
309 *argcp = argc;
310 *argvp = argv;
311}
312
d1f28cf1 313static int iplink_parse_vf(int vf, int *argcp, char ***argvp,
f89a2a05 314 struct iplink_req *req, int dev_index)
3fd86630 315{
f89a2a05
SC
316 char new_rate_api = 0, count = 0, override_legacy_rate = 0;
317 struct ifla_vf_rate tivt;
3fd86630
CW
318 int len, argc = *argcp;
319 char **argv = *argvp;
320 struct rtattr *vfinfo;
1598b9ef 321
f89a2a05
SC
322 tivt.min_tx_rate = -1;
323 tivt.max_tx_rate = -1;
324
1598b9ef 325 vfinfo = addattr_nest(&req->n, sizeof(*req), IFLA_VF_INFO);
3fd86630 326
f89a2a05
SC
327 while (NEXT_ARG_OK()) {
328 NEXT_ARG();
329 count++;
330 if (!matches(*argv, "max_tx_rate")) {
331 /* new API in use */
332 new_rate_api = 1;
333 /* override legacy rate */
334 override_legacy_rate = 1;
335 } else if (!matches(*argv, "min_tx_rate")) {
336 /* new API in use */
337 new_rate_api = 1;
338 }
339 }
340
341 while (count--) {
342 /* rewind arg */
343 PREV_ARG();
344 }
345
3fd86630
CW
346 while (NEXT_ARG_OK()) {
347 NEXT_ARG();
1598b9ef 348 if (matches(*argv, "mac") == 0) {
a89193a7 349 struct ifla_vf_mac ivm = { 0 };
8fe58d58 350 int halen = nl_get_ll_addr_len(dev_index);
6c5ffb9a 351
3fd86630 352 NEXT_ARG();
1598b9ef
SH
353 ivm.vf = vf;
354 len = ll_addr_a2n((char *)ivm.mac, 32, *argv);
355 if (len < 0)
356 return -1;
8fe58d58
PS
357 if (halen > 0 && len != halen) {
358 fprintf(stderr,
359 "Invalid address length %d - must be %d bytes\n",
360 len, halen);
361 return -1;
362 }
ef0a738c
SH
363 addattr_l(&req->n, sizeof(*req), IFLA_VF_MAC,
364 &ivm, sizeof(ivm));
3fd86630 365 } else if (matches(*argv, "vlan") == 0) {
56e9f0ab 366 struct ifla_vf_vlan_info ivvi;
6c5ffb9a 367
56e9f0ab
MS
368 iplink_parse_vf_vlan_info(vf, &argc, &argv, &ivvi);
369 /* support the old interface in case of older kernel*/
370 if (ivvi.vlan_proto == htons(ETH_P_8021Q)) {
371 struct ifla_vf_vlan ivv;
372
373 ivv.vf = ivvi.vf;
374 ivv.vlan = ivvi.vlan;
375 ivv.qos = ivvi.qos;
376 addattr_l(&req->n, sizeof(*req),
377 IFLA_VF_VLAN, &ivv, sizeof(ivv));
378 } else {
379 struct rtattr *vfvlanlist;
380
381 vfvlanlist = addattr_nest(&req->n, sizeof(*req),
382 IFLA_VF_VLAN_LIST);
383 addattr_l(&req->n, sizeof(*req),
384 IFLA_VF_VLAN_INFO, &ivvi,
385 sizeof(ivvi));
386
387 while (NEXT_ARG_OK()) {
3fd86630 388 NEXT_ARG();
56e9f0ab
MS
389 if (matches(*argv, "vlan") != 0) {
390 PREV_ARG();
391 break;
392 }
393 iplink_parse_vf_vlan_info(vf, &argc,
394 &argv, &ivvi);
395 addattr_l(&req->n, sizeof(*req),
396 IFLA_VF_VLAN_INFO, &ivvi,
397 sizeof(ivvi));
3fd86630 398 }
56e9f0ab 399 addattr_nest_end(&req->n, vfvlanlist);
3fd86630 400 }
3fd86630 401 } else if (matches(*argv, "rate") == 0) {
1598b9ef 402 struct ifla_vf_tx_rate ivt;
6c5ffb9a 403
3fd86630 404 NEXT_ARG();
6c5ffb9a 405 if (get_unsigned(&ivt.rate, *argv, 0))
1598b9ef 406 invarg("Invalid \"rate\" value\n", *argv);
6c5ffb9a 407
1598b9ef 408 ivt.vf = vf;
f89a2a05
SC
409 if (!new_rate_api)
410 addattr_l(&req->n, sizeof(*req),
411 IFLA_VF_TX_RATE, &ivt, sizeof(ivt));
412 else if (!override_legacy_rate)
413 tivt.max_tx_rate = ivt.rate;
414
415 } else if (matches(*argv, "max_tx_rate") == 0) {
416 NEXT_ARG();
417 if (get_unsigned(&tivt.max_tx_rate, *argv, 0))
418 invarg("Invalid \"max tx rate\" value\n",
419 *argv);
420 tivt.vf = vf;
421
422 } else if (matches(*argv, "min_tx_rate") == 0) {
423 NEXT_ARG();
424 if (get_unsigned(&tivt.min_tx_rate, *argv, 0))
425 invarg("Invalid \"min tx rate\" value\n",
426 *argv);
427 tivt.vf = vf;
af89576d 428
7b8179c7
GR
429 } else if (matches(*argv, "spoofchk") == 0) {
430 struct ifla_vf_spoofchk ivs;
6c5ffb9a 431
7b8179c7
GR
432 NEXT_ARG();
433 if (matches(*argv, "on") == 0)
434 ivs.setting = 1;
435 else if (matches(*argv, "off") == 0)
436 ivs.setting = 0;
437 else
ff1e35ed 438 return on_off("spoofchk", *argv);
7b8179c7 439 ivs.vf = vf;
ef0a738c
SH
440 addattr_l(&req->n, sizeof(*req), IFLA_VF_SPOOFCHK,
441 &ivs, sizeof(ivs));
7b8179c7 442
6c55c8c4
VZ
443 } else if (matches(*argv, "query_rss") == 0) {
444 struct ifla_vf_rss_query_en ivs;
6c5ffb9a 445
6c55c8c4
VZ
446 NEXT_ARG();
447 if (matches(*argv, "on") == 0)
448 ivs.setting = 1;
449 else if (matches(*argv, "off") == 0)
450 ivs.setting = 0;
451 else
ff1e35ed 452 return on_off("query_rss", *argv);
6c55c8c4 453 ivs.vf = vf;
ef0a738c
SH
454 addattr_l(&req->n, sizeof(*req), IFLA_VF_RSS_QUERY_EN,
455 &ivs, sizeof(ivs));
6c55c8c4 456
b6d77d9e
HS
457 } else if (matches(*argv, "trust") == 0) {
458 struct ifla_vf_trust ivt;
56f5daac 459
b6d77d9e
HS
460 NEXT_ARG();
461 if (matches(*argv, "on") == 0)
462 ivt.setting = 1;
463 else if (matches(*argv, "off") == 0)
464 ivt.setting = 0;
465 else
466 invarg("Invalid \"trust\" value\n", *argv);
467 ivt.vf = vf;
ef0a738c
SH
468 addattr_l(&req->n, sizeof(*req), IFLA_VF_TRUST,
469 &ivt, sizeof(ivt));
b6d77d9e 470
07fa9c15
RE
471 } else if (matches(*argv, "state") == 0) {
472 struct ifla_vf_link_state ivl;
6c5ffb9a 473
07fa9c15
RE
474 NEXT_ARG();
475 if (matches(*argv, "auto") == 0)
476 ivl.link_state = IFLA_VF_LINK_STATE_AUTO;
477 else if (matches(*argv, "enable") == 0)
478 ivl.link_state = IFLA_VF_LINK_STATE_ENABLE;
479 else if (matches(*argv, "disable") == 0)
480 ivl.link_state = IFLA_VF_LINK_STATE_DISABLE;
481 else
482 invarg("Invalid \"state\" value\n", *argv);
483 ivl.vf = vf;
ef0a738c
SH
484 addattr_l(&req->n, sizeof(*req), IFLA_VF_LINK_STATE,
485 &ivl, sizeof(ivl));
d91fb3f4
EC
486 } else if (matches(*argv, "node_guid") == 0) {
487 struct ifla_vf_guid ivg;
488
489 NEXT_ARG();
490 ivg.vf = vf;
491 if (get_guid(&ivg.guid, *argv)) {
492 invarg("Invalid GUID format\n", *argv);
493 return -1;
494 }
ef0a738c
SH
495 addattr_l(&req->n, sizeof(*req), IFLA_VF_IB_NODE_GUID,
496 &ivg, sizeof(ivg));
d91fb3f4
EC
497 } else if (matches(*argv, "port_guid") == 0) {
498 struct ifla_vf_guid ivg;
499
500 NEXT_ARG();
501 ivg.vf = vf;
502 if (get_guid(&ivg.guid, *argv)) {
503 invarg("Invalid GUID format\n", *argv);
504 return -1;
505 }
ef0a738c
SH
506 addattr_l(&req->n, sizeof(*req), IFLA_VF_IB_PORT_GUID,
507 &ivg, sizeof(ivg));
3fd86630
CW
508 } else {
509 /* rewind arg */
510 PREV_ARG();
511 break;
512 }
513 }
514
f89a2a05
SC
515 if (new_rate_api) {
516 int tmin, tmax;
9a02651a 517
f89a2a05
SC
518 if (tivt.min_tx_rate == -1 || tivt.max_tx_rate == -1) {
519 ipaddr_get_vf_rate(tivt.vf, &tmin, &tmax, dev_index);
520 if (tivt.min_tx_rate == -1)
521 tivt.min_tx_rate = tmin;
522 if (tivt.max_tx_rate == -1)
523 tivt.max_tx_rate = tmax;
524 }
525 addattr_l(&req->n, sizeof(*req), IFLA_VF_RATE, &tivt,
526 sizeof(tivt));
527 }
528
3fd86630
CW
529 if (argc == *argcp)
530 incomplete_command();
531
1598b9ef 532 addattr_nest_end(&req->n, vfinfo);
3fd86630
CW
533
534 *argcp = argc;
535 *argvp = argv;
1598b9ef 536 return 0;
3fd86630
CW
537}
538
909dfe2c 539int iplink_parse(int argc, char **argv, struct iplink_req *req,
6c5ffb9a
SH
540 char **name, char **type, char **link, char **dev,
541 int *group, int *index)
1d934839 542{
909dfe2c
PE
543 int ret, len;
544 char abuf[32];
1d934839
PM
545 int qlen = -1;
546 int mtu = -1;
e2613dc8 547 int netns = -1;
ae7229d5 548 int vf = -1;
d992f3e6
JP
549 int numtxqueues = -1;
550 int numrxqueues = -1;
9a02651a 551 int dev_index = 0;
ccdcbf35 552 int link_netnsid = -1;
8fe58d58 553 int addr_len = 0;
1d934839 554
db02608b 555 *group = -1;
909dfe2c 556 ret = argc;
1d934839
PM
557
558 while (argc > 0) {
559 if (strcmp(*argv, "up") == 0) {
909dfe2c
PE
560 req->i.ifi_change |= IFF_UP;
561 req->i.ifi_flags |= IFF_UP;
1d934839 562 } else if (strcmp(*argv, "down") == 0) {
909dfe2c
PE
563 req->i.ifi_change |= IFF_UP;
564 req->i.ifi_flags &= ~IFF_UP;
1d934839
PM
565 } else if (strcmp(*argv, "name") == 0) {
566 NEXT_ARG();
909dfe2c 567 *name = *argv;
5e25cf77
PE
568 } else if (strcmp(*argv, "index") == 0) {
569 NEXT_ARG();
570 *index = atoi(*argv);
3c682146
WC
571 if (*index < 0)
572 invarg("Invalid \"index\" value", *argv);
1d934839
PM
573 } else if (matches(*argv, "link") == 0) {
574 NEXT_ARG();
909dfe2c 575 *link = *argv;
1d934839
PM
576 } else if (matches(*argv, "address") == 0) {
577 NEXT_ARG();
8fe58d58 578 addr_len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
0aae2346 579 if (addr_len < 0)
cb2eb999 580 return -1;
8fe58d58 581 addattr_l(&req->n, sizeof(*req), IFLA_ADDRESS, abuf, addr_len);
1d934839 582 } else if (matches(*argv, "broadcast") == 0 ||
6c5ffb9a 583 strcmp(*argv, "brd") == 0) {
1d934839
PM
584 NEXT_ARG();
585 len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
cb2eb999
AH
586 if (len < 0)
587 return -1;
909dfe2c 588 addattr_l(&req->n, sizeof(*req), IFLA_BROADCAST, abuf, len);
1d934839 589 } else if (matches(*argv, "txqueuelen") == 0 ||
6c5ffb9a
SH
590 strcmp(*argv, "qlen") == 0 ||
591 matches(*argv, "txqlen") == 0) {
1d934839
PM
592 NEXT_ARG();
593 if (qlen != -1)
594 duparg("txqueuelen", *argv);
595 if (get_integer(&qlen, *argv, 0))
596 invarg("Invalid \"txqueuelen\" value\n", *argv);
909dfe2c 597 addattr_l(&req->n, sizeof(*req), IFLA_TXQLEN, &qlen, 4);
1d934839
PM
598 } else if (strcmp(*argv, "mtu") == 0) {
599 NEXT_ARG();
600 if (mtu != -1)
601 duparg("mtu", *argv);
602 if (get_integer(&mtu, *argv, 0))
603 invarg("Invalid \"mtu\" value\n", *argv);
909dfe2c 604 addattr_l(&req->n, sizeof(*req), IFLA_MTU, &mtu, 4);
4b726cb1
SH
605 } else if (strcmp(*argv, "netns") == 0) {
606 NEXT_ARG();
607 if (netns != -1)
608 duparg("netns", *argv);
6c5ffb9a
SH
609 netns = netns_get_fd(*argv);
610 if (netns >= 0)
ef0a738c
SH
611 addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_FD,
612 &netns, 4);
0dc34c77 613 else if (get_integer(&netns, *argv, 0) == 0)
ef0a738c
SH
614 addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_PID,
615 &netns, 4);
0dc34c77 616 else
4b726cb1 617 invarg("Invalid \"netns\" value\n", *argv);
1d934839
PM
618 } else if (strcmp(*argv, "multicast") == 0) {
619 NEXT_ARG();
909dfe2c 620 req->i.ifi_change |= IFF_MULTICAST;
6c5ffb9a
SH
621
622 if (strcmp(*argv, "on") == 0)
909dfe2c 623 req->i.ifi_flags |= IFF_MULTICAST;
6c5ffb9a 624 else if (strcmp(*argv, "off") == 0)
909dfe2c 625 req->i.ifi_flags &= ~IFF_MULTICAST;
6c5ffb9a 626 else
14645ec2 627 return on_off("multicast", *argv);
1d934839
PM
628 } else if (strcmp(*argv, "allmulticast") == 0) {
629 NEXT_ARG();
909dfe2c 630 req->i.ifi_change |= IFF_ALLMULTI;
6c5ffb9a
SH
631
632 if (strcmp(*argv, "on") == 0)
909dfe2c 633 req->i.ifi_flags |= IFF_ALLMULTI;
6c5ffb9a 634 else if (strcmp(*argv, "off") == 0)
909dfe2c 635 req->i.ifi_flags &= ~IFF_ALLMULTI;
6c5ffb9a 636 else
14645ec2 637 return on_off("allmulticast", *argv);
1d934839
PM
638 } else if (strcmp(*argv, "promisc") == 0) {
639 NEXT_ARG();
909dfe2c 640 req->i.ifi_change |= IFF_PROMISC;
6c5ffb9a
SH
641
642 if (strcmp(*argv, "on") == 0)
909dfe2c 643 req->i.ifi_flags |= IFF_PROMISC;
6c5ffb9a 644 else if (strcmp(*argv, "off") == 0)
909dfe2c 645 req->i.ifi_flags &= ~IFF_PROMISC;
6c5ffb9a 646 else
14645ec2 647 return on_off("promisc", *argv);
1d934839
PM
648 } else if (strcmp(*argv, "trailers") == 0) {
649 NEXT_ARG();
909dfe2c 650 req->i.ifi_change |= IFF_NOTRAILERS;
6c5ffb9a
SH
651
652 if (strcmp(*argv, "off") == 0)
909dfe2c 653 req->i.ifi_flags |= IFF_NOTRAILERS;
6c5ffb9a 654 else if (strcmp(*argv, "on") == 0)
909dfe2c 655 req->i.ifi_flags &= ~IFF_NOTRAILERS;
6c5ffb9a 656 else
14645ec2 657 return on_off("trailers", *argv);
1d934839
PM
658 } else if (strcmp(*argv, "arp") == 0) {
659 NEXT_ARG();
909dfe2c 660 req->i.ifi_change |= IFF_NOARP;
6c5ffb9a
SH
661
662 if (strcmp(*argv, "on") == 0)
909dfe2c 663 req->i.ifi_flags &= ~IFF_NOARP;
6c5ffb9a 664 else if (strcmp(*argv, "off") == 0)
909dfe2c 665 req->i.ifi_flags |= IFF_NOARP;
6c5ffb9a 666 else
e543a6a8 667 return on_off("arp", *argv);
ae7229d5 668 } else if (strcmp(*argv, "vf") == 0) {
1598b9ef 669 struct rtattr *vflist;
6c5ffb9a 670
ae7229d5 671 NEXT_ARG();
6c5ffb9a 672 if (get_integer(&vf, *argv, 0))
ae7229d5 673 invarg("Invalid \"vf\" value\n", *argv);
6c5ffb9a 674
1598b9ef
SH
675 vflist = addattr_nest(&req->n, sizeof(*req),
676 IFLA_VFINFO_LIST);
9a02651a
SH
677 if (dev_index == 0)
678 missarg("dev");
679
f89a2a05 680 len = iplink_parse_vf(vf, &argc, &argv, req, dev_index);
1598b9ef
SH
681 if (len < 0)
682 return -1;
683 addattr_nest_end(&req->n, vflist);
a1e191b9
JP
684 } else if (matches(*argv, "master") == 0) {
685 int ifindex;
6c5ffb9a 686
a1e191b9
JP
687 NEXT_ARG();
688 ifindex = ll_name_to_index(*argv);
689 if (!ifindex)
690 invarg("Device does not exist\n", *argv);
691 addattr_l(&req->n, sizeof(*req), IFLA_MASTER,
692 &ifindex, 4);
104444c2
DA
693 } else if (strcmp(*argv, "vrf") == 0) {
694 int ifindex;
695
696 NEXT_ARG();
697 ifindex = ll_name_to_index(*argv);
698 if (!ifindex)
699 invarg("Not a valid VRF name\n", *argv);
700 if (!name_is_vrf(*argv))
701 invarg("Not a valid VRF name\n", *argv);
702 addattr_l(&req->n, sizeof(*req), IFLA_MASTER,
703 &ifindex, sizeof(ifindex));
a1e191b9
JP
704 } else if (matches(*argv, "nomaster") == 0) {
705 int ifindex = 0;
6c5ffb9a 706
a1e191b9
JP
707 addattr_l(&req->n, sizeof(*req), IFLA_MASTER,
708 &ifindex, 4);
1d934839
PM
709 } else if (matches(*argv, "dynamic") == 0) {
710 NEXT_ARG();
909dfe2c 711 req->i.ifi_change |= IFF_DYNAMIC;
6c5ffb9a
SH
712
713 if (strcmp(*argv, "on") == 0)
909dfe2c 714 req->i.ifi_flags |= IFF_DYNAMIC;
6c5ffb9a 715 else if (strcmp(*argv, "off") == 0)
909dfe2c 716 req->i.ifi_flags &= ~IFF_DYNAMIC;
6c5ffb9a 717 else
14645ec2 718 return on_off("dynamic", *argv);
1d934839
PM
719 } else if (matches(*argv, "type") == 0) {
720 NEXT_ARG();
909dfe2c 721 *type = *argv;
1d934839
PM
722 argc--; argv++;
723 break;
ace9c961
SH
724 } else if (matches(*argv, "alias") == 0) {
725 NEXT_ARG();
726 addattr_l(&req->n, sizeof(*req), IFLA_IFALIAS,
727 *argv, strlen(*argv));
728 argc--; argv++;
729 break;
db02608b
VD
730 } else if (strcmp(*argv, "group") == 0) {
731 NEXT_ARG();
732 if (*group != -1)
733 duparg("group", *argv);
734 if (rtnl_group_a2n(group, *argv))
735 invarg("Invalid \"group\" value\n", *argv);
82499282
SH
736 } else if (strcmp(*argv, "mode") == 0) {
737 int mode;
6c5ffb9a 738
82499282 739 NEXT_ARG();
4ccfb44d 740 mode = get_link_mode(*argv);
82499282
SH
741 if (mode < 0)
742 invarg("Invalid link mode\n", *argv);
743 addattr8(&req->n, sizeof(*req), IFLA_LINKMODE, mode);
4f2fdd44
SH
744 } else if (strcmp(*argv, "state") == 0) {
745 int state;
6c5ffb9a 746
4f2fdd44
SH
747 NEXT_ARG();
748 state = get_operstate(*argv);
749 if (state < 0)
750 invarg("Invalid operstate\n", *argv);
751
752 addattr8(&req->n, sizeof(*req), IFLA_OPERSTATE, state);
d992f3e6
JP
753 } else if (matches(*argv, "numtxqueues") == 0) {
754 NEXT_ARG();
755 if (numtxqueues != -1)
756 duparg("numtxqueues", *argv);
757 if (get_integer(&numtxqueues, *argv, 0))
758 invarg("Invalid \"numtxqueues\" value\n", *argv);
759 addattr_l(&req->n, sizeof(*req), IFLA_NUM_TX_QUEUES,
760 &numtxqueues, 4);
761 } else if (matches(*argv, "numrxqueues") == 0) {
762 NEXT_ARG();
763 if (numrxqueues != -1)
764 duparg("numrxqueues", *argv);
765 if (get_integer(&numrxqueues, *argv, 0))
766 invarg("Invalid \"numrxqueues\" value\n", *argv);
767 addattr_l(&req->n, sizeof(*req), IFLA_NUM_RX_QUEUES,
768 &numrxqueues, 4);
ff7c2084
JP
769 } else if (matches(*argv, "addrgenmode") == 0) {
770 struct rtattr *afs, *afs6;
771 int mode;
6c5ffb9a 772
ff7c2084
JP
773 NEXT_ARG();
774 mode = get_addr_gen_mode(*argv);
775 if (mode < 0)
776 invarg("Invalid address generation mode\n", *argv);
777 afs = addattr_nest(&req->n, sizeof(*req), IFLA_AF_SPEC);
778 afs6 = addattr_nest(&req->n, sizeof(*req), AF_INET6);
ef0a738c
SH
779 addattr8(&req->n, sizeof(*req),
780 IFLA_INET6_ADDR_GEN_MODE, mode);
ff7c2084
JP
781 addattr_nest_end(&req->n, afs6);
782 addattr_nest_end(&req->n, afs);
ccdcbf35
ND
783 } else if (matches(*argv, "link-netnsid") == 0) {
784 NEXT_ARG();
785 if (link_netnsid != -1)
786 duparg("link-netnsid", *argv);
787 if (get_integer(&link_netnsid, *argv, 0))
788 invarg("Invalid \"link-netnsid\" value\n", *argv);
789 addattr32(&req->n, sizeof(*req), IFLA_LINK_NETNSID,
790 link_netnsid);
18864827
AK
791 } else if (strcmp(*argv, "protodown") == 0) {
792 unsigned int proto_down;
793
794 NEXT_ARG();
795 if (strcmp(*argv, "on") == 0)
796 proto_down = 1;
797 else if (strcmp(*argv, "off") == 0)
798 proto_down = 0;
799 else
800 return on_off("protodown", *argv);
801 addattr8(&req->n, sizeof(*req), IFLA_PROTO_DOWN,
802 proto_down);
1d934839 803 } else {
05325552
PM
804 if (matches(*argv, "help") == 0)
805 usage();
940a96e6
PS
806
807 if (strcmp(*argv, "dev") == 0)
808 NEXT_ARG();
909dfe2c 809 if (*dev)
1d934839 810 duparg2("dev", *argv);
909dfe2c 811 *dev = *argv;
f89a2a05 812 dev_index = ll_name_to_index(*dev);
1d934839
PM
813 }
814 argc--; argv++;
815 }
816
8fe58d58
PS
817 if (dev_index && addr_len) {
818 int halen = nl_get_ll_addr_len(dev_index);
ef0a738c 819
8fe58d58
PS
820 if (halen >= 0 && halen != addr_len) {
821 fprintf(stderr,
ef0a738c
SH
822 "Invalid address length %d - must be %d bytes\n",
823 addr_len, halen);
8fe58d58
PS
824 return -1;
825 }
826 }
827
909dfe2c
PE
828 return ret - argc;
829}
830
831static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv)
832{
833 int len;
834 char *dev = NULL;
835 char *name = NULL;
836 char *link = NULL;
837 char *type = NULL;
3c682146 838 int index = -1;
db02608b 839 int group;
909dfe2c 840 struct link_util *lu = NULL;
d17b136f
PS
841 struct iplink_req req = {
842 .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
843 .n.nlmsg_flags = NLM_F_REQUEST | flags,
844 .n.nlmsg_type = cmd,
845 .i.ifi_family = preferred_family,
846 };
909dfe2c
PE
847 int ret;
848
ef0a738c
SH
849 ret = iplink_parse(argc, argv,
850 &req, &name, &type, &link, &dev, &group, &index);
909dfe2c
PE
851 if (ret < 0)
852 return ret;
853
854 argc -= ret;
855 argv += ret;
db02608b
VD
856
857 if (group != -1) {
858 if (dev)
859 addattr_l(&req.n, sizeof(req), IFLA_GROUP,
860 &group, sizeof(group));
861 else {
862 if (argc) {
6773bcc2
SH
863 fprintf(stderr,
864 "Garbage instead of arguments \"%s ...\". Try \"ip link help\".\n",
865 *argv);
db02608b
VD
866 return -1;
867 }
868 if (flags & NLM_F_CREATE) {
56f5daac 869 fprintf(stderr, "group cannot be used when creating devices.\n");
db02608b
VD
870 return -1;
871 }
872
873 req.i.ifi_index = 0;
874 addattr32(&req.n, sizeof(req), IFLA_GROUP, group);
c079e121 875 if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
f921f567 876 return -2;
db02608b
VD
877 return 0;
878 }
879 }
880
1d934839
PM
881 if (!(flags & NLM_F_CREATE)) {
882 if (!dev) {
56f5daac 883 fprintf(stderr, "Not enough information: \"dev\" argument is required.\n");
1d934839
PM
884 exit(-1);
885 }
3c682146 886 if (cmd == RTM_NEWLINK && index != -1) {
56f5daac 887 fprintf(stderr, "index can be used only when creating devices.\n");
3c682146
WC
888 exit(-1);
889 }
1d934839
PM
890
891 req.i.ifi_index = ll_name_to_index(dev);
892 if (req.i.ifi_index == 0) {
893 fprintf(stderr, "Cannot find device \"%s\"\n", dev);
894 return -1;
895 }
896 } else {
897 /* Allow "ip link add dev" and "ip link add name" */
898 if (!name)
899 name = dev;
900
901 if (link) {
902 int ifindex;
903
904 ifindex = ll_name_to_index(link);
905 if (ifindex == 0) {
906 fprintf(stderr, "Cannot find device \"%s\"\n",
907 link);
908 return -1;
909 }
910 addattr_l(&req.n, sizeof(req), IFLA_LINK, &ifindex, 4);
911 }
5e25cf77 912
68ac9ab3
AW
913 if (index == -1)
914 req.i.ifi_index = 0;
915 else
916 req.i.ifi_index = index;
1d934839
PM
917 }
918
919 if (name) {
920 len = strlen(name) + 1;
ca78b0e7 921 if (len == 1)
ef0a738c
SH
922 invarg("\"\" is not a valid device identifier\n",
923 "name");
1d934839 924 if (len > IFNAMSIZ)
ca78b0e7 925 invarg("\"name\" too long\n", name);
1d934839
PM
926 addattr_l(&req.n, sizeof(req), IFLA_IFNAME, name, len);
927 }
928
09fa3279 929 if (type) {
a1e2e5fc 930 struct rtattr *linkinfo;
22a84711 931 char *ulinep = strchr(type, '_');
620ddeda
NA
932 int iflatype;
933
a1e2e5fc 934 linkinfo = addattr_nest(&req.n, sizeof(req), IFLA_LINKINFO);
09fa3279
SH
935 addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, type,
936 strlen(type));
937
22a84711
HL
938 lu = get_link_kind(type);
939 if (ulinep && !strcmp(ulinep, "_slave"))
620ddeda 940 iflatype = IFLA_INFO_SLAVE_DATA;
22a84711 941 else
620ddeda 942 iflatype = IFLA_INFO_DATA;
09fa3279 943 if (lu && argc) {
ef0a738c
SH
944 struct rtattr *data = addattr_nest(&req.n,
945 sizeof(req), iflatype);
09fa3279
SH
946
947 if (lu->parse_opt &&
948 lu->parse_opt(lu, argc, argv, &req.n))
949 return -1;
950
a1e2e5fc 951 addattr_nest_end(&req.n, data);
09fa3279
SH
952 } else if (argc) {
953 if (matches(*argv, "help") == 0)
954 usage();
6773bcc2
SH
955 fprintf(stderr,
956 "Garbage instead of arguments \"%s ...\". Try \"ip link help\".\n",
957 *argv);
09fa3279
SH
958 return -1;
959 }
a1e2e5fc 960 addattr_nest_end(&req.n, linkinfo);
09fa3279 961 } else if (flags & NLM_F_CREATE) {
56f5daac 962 fprintf(stderr, "Not enough information: \"type\" argument is required\n");
09fa3279
SH
963 return -1;
964 }
965
c079e121 966 if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
f921f567 967 return -2;
1d934839
PM
968
969 return 0;
970}
971
50b9950d
RP
972int iplink_get(unsigned int flags, char *name, __u32 filt_mask)
973{
974 int len;
d17b136f
PS
975 struct iplink_req req = {
976 .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
977 .n.nlmsg_flags = NLM_F_REQUEST | flags,
978 .n.nlmsg_type = RTM_GETLINK,
979 .i.ifi_family = preferred_family,
980 };
c079e121
SH
981 struct {
982 struct nlmsghdr n;
983 char buf[16384];
984 } answer;
50b9950d 985
50b9950d
RP
986 if (name) {
987 len = strlen(name) + 1;
988 if (len == 1)
989 invarg("\"\" is not a valid device identifier\n",
990 "name");
991 if (len > IFNAMSIZ)
992 invarg("\"name\" too long\n", name);
993 addattr_l(&req.n, sizeof(req), IFLA_IFNAME, name, len);
994 }
995 addattr32(&req.n, sizeof(req), IFLA_EXT_MASK, filt_mask);
996
c079e121 997 if (rtnl_talk(&rth, &req.n, &answer.n, sizeof(answer)) < 0)
50b9950d
RP
998 return -2;
999
5d295bb8
AG
1000 if (brief)
1001 print_linkinfo_brief(NULL, &answer.n, stdout);
1002 else
1003 print_linkinfo(NULL, &answer.n, stdout);
50b9950d
RP
1004
1005 return 0;
1006}
1007
1d934839 1008#if IPLINK_IOCTL_COMPAT
aba5acdf
SH
1009static int get_ctl_fd(void)
1010{
1011 int s_errno;
1012 int fd;
1013
1014 fd = socket(PF_INET, SOCK_DGRAM, 0);
1015 if (fd >= 0)
1016 return fd;
1017 s_errno = errno;
1018 fd = socket(PF_PACKET, SOCK_DGRAM, 0);
1019 if (fd >= 0)
1020 return fd;
1021 fd = socket(PF_INET6, SOCK_DGRAM, 0);
1022 if (fd >= 0)
1023 return fd;
1024 errno = s_errno;
1025 perror("Cannot create control socket");
1026 return -1;
1027}
1028
71058eb8 1029static int do_chflags(const char *dev, __u32 flags, __u32 mask)
aba5acdf
SH
1030{
1031 struct ifreq ifr;
1032 int fd;
1033 int err;
1034
71058eb8 1035 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
aba5acdf
SH
1036 fd = get_ctl_fd();
1037 if (fd < 0)
1038 return -1;
1039 err = ioctl(fd, SIOCGIFFLAGS, &ifr);
1040 if (err) {
1041 perror("SIOCGIFFLAGS");
1042 close(fd);
1043 return -1;
1044 }
1045 if ((ifr.ifr_flags^flags)&mask) {
1046 ifr.ifr_flags &= ~mask;
1047 ifr.ifr_flags |= mask&flags;
1048 err = ioctl(fd, SIOCSIFFLAGS, &ifr);
1049 if (err)
1050 perror("SIOCSIFFLAGS");
1051 }
1052 close(fd);
1053 return err;
1054}
1055
71058eb8 1056static int do_changename(const char *dev, const char *newdev)
aba5acdf
SH
1057{
1058 struct ifreq ifr;
1059 int fd;
1060 int err;
1061
71058eb8
SH
1062 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
1063 strncpy(ifr.ifr_newname, newdev, IFNAMSIZ);
aba5acdf
SH
1064 fd = get_ctl_fd();
1065 if (fd < 0)
1066 return -1;
1067 err = ioctl(fd, SIOCSIFNAME, &ifr);
1068 if (err) {
1069 perror("SIOCSIFNAME");
1070 close(fd);
1071 return -1;
1072 }
1073 close(fd);
1074 return err;
1075}
1076
71058eb8 1077static int set_qlen(const char *dev, int qlen)
aba5acdf 1078{
d17b136f 1079 struct ifreq ifr = { .ifr_qlen = qlen };
aba5acdf
SH
1080 int s;
1081
1082 s = get_ctl_fd();
1083 if (s < 0)
1084 return -1;
1085
ae665a52 1086 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
aba5acdf
SH
1087 if (ioctl(s, SIOCSIFTXQLEN, &ifr) < 0) {
1088 perror("SIOCSIFXQLEN");
1089 close(s);
1090 return -1;
1091 }
1092 close(s);
1093
ae665a52 1094 return 0;
aba5acdf
SH
1095}
1096
71058eb8 1097static int set_mtu(const char *dev, int mtu)
aba5acdf 1098{
d17b136f 1099 struct ifreq ifr = { .ifr_mtu = mtu };
aba5acdf
SH
1100 int s;
1101
1102 s = get_ctl_fd();
1103 if (s < 0)
1104 return -1;
1105
ae665a52 1106 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
aba5acdf
SH
1107 if (ioctl(s, SIOCSIFMTU, &ifr) < 0) {
1108 perror("SIOCSIFMTU");
1109 close(s);
1110 return -1;
1111 }
1112 close(s);
1113
ae665a52 1114 return 0;
aba5acdf
SH
1115}
1116
71058eb8 1117static int get_address(const char *dev, int *htype)
aba5acdf 1118{
d17b136f
PS
1119 struct ifreq ifr = {};
1120 struct sockaddr_ll me = {
1121 .sll_family = AF_PACKET,
1122 .sll_protocol = htons(ETH_P_LOOP),
1123 };
f332d169 1124 socklen_t alen;
aba5acdf
SH
1125 int s;
1126
1127 s = socket(PF_PACKET, SOCK_DGRAM, 0);
ae665a52 1128 if (s < 0) {
aba5acdf
SH
1129 perror("socket(PF_PACKET)");
1130 return -1;
1131 }
1132
71058eb8 1133 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
aba5acdf
SH
1134 if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
1135 perror("SIOCGIFINDEX");
1136 close(s);
1137 return -1;
1138 }
1139
aba5acdf 1140 me.sll_ifindex = ifr.ifr_ifindex;
6c5ffb9a 1141 if (bind(s, (struct sockaddr *)&me, sizeof(me)) == -1) {
aba5acdf
SH
1142 perror("bind");
1143 close(s);
1144 return -1;
1145 }
1146
1147 alen = sizeof(me);
6c5ffb9a 1148 if (getsockname(s, (struct sockaddr *)&me, &alen) == -1) {
aba5acdf
SH
1149 perror("getsockname");
1150 close(s);
1151 return -1;
1152 }
1153 close(s);
1154 *htype = me.sll_hatype;
1155 return me.sll_halen;
1156}
1157
ae665a52 1158static int parse_address(const char *dev, int hatype, int halen,
7b565754 1159 char *lla, struct ifreq *ifr)
aba5acdf
SH
1160{
1161 int alen;
1162
1163 memset(ifr, 0, sizeof(*ifr));
71058eb8 1164 strncpy(ifr->ifr_name, dev, IFNAMSIZ);
aba5acdf
SH
1165 ifr->ifr_hwaddr.sa_family = hatype;
1166 alen = ll_addr_a2n(ifr->ifr_hwaddr.sa_data, 14, lla);
1167 if (alen < 0)
1168 return -1;
1169 if (alen != halen) {
ef0a738c
SH
1170 fprintf(stderr, "Wrong address (%s) length: expected %d bytes\n",
1171 lla, halen);
aba5acdf
SH
1172 return -1;
1173 }
ae665a52 1174 return 0;
aba5acdf
SH
1175}
1176
1177static int set_address(struct ifreq *ifr, int brd)
1178{
1179 int s;
1180
1181 s = get_ctl_fd();
1182 if (s < 0)
1183 return -1;
1184 if (ioctl(s, brd?SIOCSIFHWBROADCAST:SIOCSIFHWADDR, ifr) < 0) {
1185 perror(brd?"SIOCSIFHWBROADCAST":"SIOCSIFHWADDR");
1186 close(s);
1187 return -1;
1188 }
1189 close(s);
ae665a52 1190 return 0;
aba5acdf
SH
1191}
1192
aba5acdf
SH
1193static int do_set(int argc, char **argv)
1194{
1195 char *dev = NULL;
1196 __u32 mask = 0;
1197 __u32 flags = 0;
1198 int qlen = -1;
1199 int mtu = -1;
1200 char *newaddr = NULL;
1201 char *newbrd = NULL;
1202 struct ifreq ifr0, ifr1;
1203 char *newname = NULL;
1204 int htype, halen;
1205
1206 while (argc > 0) {
1207 if (strcmp(*argv, "up") == 0) {
1208 mask |= IFF_UP;
1209 flags |= IFF_UP;
1210 } else if (strcmp(*argv, "down") == 0) {
1211 mask |= IFF_UP;
1212 flags &= ~IFF_UP;
1213 } else if (strcmp(*argv, "name") == 0) {
1214 NEXT_ARG();
1215 newname = *argv;
1216 } else if (matches(*argv, "address") == 0) {
1217 NEXT_ARG();
1218 newaddr = *argv;
1219 } else if (matches(*argv, "broadcast") == 0 ||
1220 strcmp(*argv, "brd") == 0) {
1221 NEXT_ARG();
1222 newbrd = *argv;
1223 } else if (matches(*argv, "txqueuelen") == 0 ||
1224 strcmp(*argv, "qlen") == 0 ||
1225 matches(*argv, "txqlen") == 0) {
1226 NEXT_ARG();
1227 if (qlen != -1)
1228 duparg("txqueuelen", *argv);
1229 if (get_integer(&qlen, *argv, 0))
1230 invarg("Invalid \"txqueuelen\" value\n", *argv);
1231 } else if (strcmp(*argv, "mtu") == 0) {
1232 NEXT_ARG();
1233 if (mtu != -1)
1234 duparg("mtu", *argv);
1235 if (get_integer(&mtu, *argv, 0))
1236 invarg("Invalid \"mtu\" value\n", *argv);
1237 } else if (strcmp(*argv, "multicast") == 0) {
1238 NEXT_ARG();
1239 mask |= IFF_MULTICAST;
6c5ffb9a
SH
1240
1241 if (strcmp(*argv, "on") == 0)
aba5acdf 1242 flags |= IFF_MULTICAST;
6c5ffb9a 1243 else if (strcmp(*argv, "off") == 0)
aba5acdf 1244 flags &= ~IFF_MULTICAST;
6c5ffb9a 1245 else
14645ec2 1246 return on_off("multicast", *argv);
d27b1b5b 1247 } else if (strcmp(*argv, "allmulticast") == 0) {
1248 NEXT_ARG();
1249 mask |= IFF_ALLMULTI;
6c5ffb9a
SH
1250
1251 if (strcmp(*argv, "on") == 0)
d27b1b5b 1252 flags |= IFF_ALLMULTI;
6c5ffb9a 1253 else if (strcmp(*argv, "off") == 0)
d27b1b5b 1254 flags &= ~IFF_ALLMULTI;
6c5ffb9a 1255 else
14645ec2 1256 return on_off("allmulticast", *argv);
d27b1b5b 1257 } else if (strcmp(*argv, "promisc") == 0) {
1258 NEXT_ARG();
1259 mask |= IFF_PROMISC;
6c5ffb9a
SH
1260
1261 if (strcmp(*argv, "on") == 0)
d27b1b5b 1262 flags |= IFF_PROMISC;
6c5ffb9a 1263 else if (strcmp(*argv, "off") == 0)
d27b1b5b 1264 flags &= ~IFF_PROMISC;
6c5ffb9a 1265 else
14645ec2 1266 return on_off("promisc", *argv);
d27b1b5b 1267 } else if (strcmp(*argv, "trailers") == 0) {
1268 NEXT_ARG();
1269 mask |= IFF_NOTRAILERS;
6c5ffb9a
SH
1270
1271 if (strcmp(*argv, "off") == 0)
d27b1b5b 1272 flags |= IFF_NOTRAILERS;
6c5ffb9a 1273 else if (strcmp(*argv, "on") == 0)
d27b1b5b 1274 flags &= ~IFF_NOTRAILERS;
6c5ffb9a 1275 else
14645ec2 1276 return on_off("trailers", *argv);
aba5acdf
SH
1277 } else if (strcmp(*argv, "arp") == 0) {
1278 NEXT_ARG();
1279 mask |= IFF_NOARP;
6c5ffb9a
SH
1280
1281 if (strcmp(*argv, "on") == 0)
aba5acdf 1282 flags &= ~IFF_NOARP;
6c5ffb9a 1283 else if (strcmp(*argv, "off") == 0)
aba5acdf 1284 flags |= IFF_NOARP;
6c5ffb9a 1285 else
ff1e35ed 1286 return on_off("arp", *argv);
aba5acdf
SH
1287 } else if (matches(*argv, "dynamic") == 0) {
1288 NEXT_ARG();
1289 mask |= IFF_DYNAMIC;
6c5ffb9a
SH
1290
1291 if (strcmp(*argv, "on") == 0)
aba5acdf 1292 flags |= IFF_DYNAMIC;
6c5ffb9a 1293 else if (strcmp(*argv, "off") == 0)
aba5acdf 1294 flags &= ~IFF_DYNAMIC;
6c5ffb9a 1295 else
14645ec2 1296 return on_off("dynamic", *argv);
aba5acdf 1297 } else {
6c5ffb9a 1298 if (strcmp(*argv, "dev") == 0)
aba5acdf 1299 NEXT_ARG();
8aacb9bb 1300 else if (matches(*argv, "help") == 0)
aba5acdf 1301 usage();
6c5ffb9a 1302
aba5acdf
SH
1303 if (dev)
1304 duparg2("dev", *argv);
1305 dev = *argv;
1306 }
1307 argc--; argv++;
1308 }
1309
1310 if (!dev) {
ef0a738c
SH
1311 fprintf(stderr,
1312 "Not enough of information: \"dev\" argument is required.\n");
aba5acdf
SH
1313 exit(-1);
1314 }
1315
1316 if (newaddr || newbrd) {
1317 halen = get_address(dev, &htype);
1318 if (halen < 0)
1319 return -1;
1320 if (newaddr) {
1321 if (parse_address(dev, htype, halen, newaddr, &ifr0) < 0)
1322 return -1;
1323 }
1324 if (newbrd) {
1325 if (parse_address(dev, htype, halen, newbrd, &ifr1) < 0)
ae665a52 1326 return -1;
aba5acdf
SH
1327 }
1328 }
1329
1330 if (newname && strcmp(dev, newname)) {
ca78b0e7
PM
1331 if (strlen(newname) == 0)
1332 invarg("\"\" is not a valid device identifier\n", "name");
aba5acdf
SH
1333 if (do_changename(dev, newname) < 0)
1334 return -1;
1335 dev = newname;
1336 }
ae665a52 1337 if (qlen != -1) {
aba5acdf 1338 if (set_qlen(dev, qlen) < 0)
ae665a52 1339 return -1;
aba5acdf 1340 }
ae665a52 1341 if (mtu != -1) {
aba5acdf 1342 if (set_mtu(dev, mtu) < 0)
ae665a52 1343 return -1;
aba5acdf
SH
1344 }
1345 if (newaddr || newbrd) {
1346 if (newbrd) {
1347 if (set_address(&ifr1, 1) < 0)
ae665a52 1348 return -1;
aba5acdf
SH
1349 }
1350 if (newaddr) {
1351 if (set_address(&ifr0, 0) < 0)
1352 return -1;
1353 }
1354 }
1355 if (mask)
1356 return do_chflags(dev, flags, mask);
1357 return 0;
1358}
1d934839 1359#endif /* IPLINK_IOCTL_COMPAT */
aba5acdf 1360
561e650e 1361static void do_help(int argc, char **argv)
1362{
1363 struct link_util *lu = NULL;
1364
1365 if (argc <= 0) {
1366 usage();
6c5ffb9a 1367 return;
561e650e 1368 }
1369
1370 lu = get_link_kind(*argv);
561e650e 1371 if (lu && lu->print_help)
1372 lu->print_help(lu, argc-1, argv+1, stdout);
1373 else
1374 usage();
1375}
1376
aba5acdf
SH
1377int do_iplink(int argc, char **argv)
1378{
6843d36e
ZS
1379 if (argc < 1)
1380 return ipaddr_list_link(0, NULL);
1381
1382 if (iplink_have_newlink()) {
1383 if (matches(*argv, "add") == 0)
1384 return iplink_modify(RTM_NEWLINK,
6c5ffb9a
SH
1385 NLM_F_CREATE|NLM_F_EXCL,
1386 argc-1, argv+1);
6843d36e 1387 if (matches(*argv, "set") == 0 ||
6c5ffb9a 1388 matches(*argv, "change") == 0)
6843d36e 1389 return iplink_modify(RTM_NEWLINK, 0,
6c5ffb9a 1390 argc-1, argv+1);
6843d36e
ZS
1391 if (matches(*argv, "replace") == 0)
1392 return iplink_modify(RTM_NEWLINK,
6c5ffb9a
SH
1393 NLM_F_CREATE|NLM_F_REPLACE,
1394 argc-1, argv+1);
6843d36e
ZS
1395 if (matches(*argv, "delete") == 0)
1396 return iplink_modify(RTM_DELLINK, 0,
6c5ffb9a 1397 argc-1, argv+1);
6843d36e 1398 } else {
1d934839 1399#if IPLINK_IOCTL_COMPAT
6843d36e
ZS
1400 if (matches(*argv, "set") == 0)
1401 return do_set(argc-1, argv+1);
1d934839 1402#endif
6843d36e 1403 }
6c5ffb9a 1404
6843d36e 1405 if (matches(*argv, "show") == 0 ||
6c5ffb9a
SH
1406 matches(*argv, "lst") == 0 ||
1407 matches(*argv, "list") == 0)
6843d36e 1408 return ipaddr_list_link(argc-1, argv+1);
6c5ffb9a 1409
6843d36e
ZS
1410 if (matches(*argv, "help") == 0) {
1411 do_help(argc-1, argv+1);
1412 return 0;
1413 }
aba5acdf 1414
6843d36e 1415 fprintf(stderr, "Command \"%s\" is unknown, try \"ip link help\".\n",
6c5ffb9a 1416 *argv);
aba5acdf
SH
1417 exit(-1);
1418}