1 /*
2 * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
3 */
4 /*
5 * Copyright (c) 1983 Regents of the University of California.
6 * All rights reserved. The Berkeley software License Agreement
7 * specifies the terms and conditions for redistribution.
8 */
9
10 #include "defs.h"
11 #include "strings.h"
12 #include "ifconfig.h"
13 #include <compat.h>
14 #include <libdlpi.h>
15 #include <libdllink.h>
16 #include <libdliptun.h>
17 #include <libdllink.h>
18 #include <inet/ip.h>
19 #include <inet/ipsec_impl.h>
20 #include <libipadm.h>
21 #include <ifaddrs.h>
22 #include <libsocket_priv.h>
23
24 #define LOOPBACK_IF "lo0"
25 #define NONE_STR "none"
26 #define ARP_MOD_NAME "arp"
27 #define LIFC_DEFAULT (LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES |\
28 LIFC_UNDER_IPMP)
29
30 typedef struct if_flags {
31 uint64_t iff_value;
32 char *iff_name;
33 } if_flags_t;
34
35 static if_flags_t if_flags_tbl[] = {
36 { IFF_UP, "UP" },
37 { IFF_BROADCAST, "BROADCAST" },
38 { IFF_DEBUG, "DEBUG" },
39 { IFF_LOOPBACK, "LOOPBACK" },
40 { IFF_POINTOPOINT, "POINTOPOINT" },
41 { IFF_NOTRAILERS, "NOTRAILERS" },
42 { IFF_RUNNING, "RUNNING" },
43 { IFF_NOARP, "NOARP" },
44 { IFF_PROMISC, "PROMISC" },
45 { IFF_ALLMULTI, "ALLMULTI" },
46 { IFF_INTELLIGENT, "INTELLIGENT" },
47 { IFF_MULTICAST, "MULTICAST" },
48 { IFF_MULTI_BCAST, "MULTI_BCAST" },
49 { IFF_UNNUMBERED, "UNNUMBERED" },
50 { IFF_DHCPRUNNING, "DHCP" },
51 { IFF_PRIVATE, "PRIVATE" },
52 { IFF_NOXMIT, "NOXMIT" },
53 { IFF_NOLOCAL, "NOLOCAL" },
54 { IFF_DEPRECATED, "DEPRECATED" },
55 { IFF_ADDRCONF, "ADDRCONF" },
56 { IFF_ROUTER, "ROUTER" },
57 { IFF_NONUD, "NONUD" },
58 { IFF_ANYCAST, "ANYCAST" },
59 { IFF_NORTEXCH, "NORTEXCH" },
60 { IFF_IPV4, "IPv4" },
61 { IFF_IPV6, "IPv6" },
62 { IFF_NOFAILOVER, "NOFAILOVER" },
63 { IFF_FAILED, "FAILED" },
64 { IFF_STANDBY, "STANDBY" },
65 { IFF_INACTIVE, "INACTIVE" },
66 { IFF_OFFLINE, "OFFLINE" },
67 { IFF_XRESOLV, "XRESOLV" },
68 { IFF_COS_ENABLED, "CoS" },
69 { IFF_PREFERRED, "PREFERRED" },
70 { IFF_TEMPORARY, "TEMPORARY" },
71 { IFF_FIXEDMTU, "FIXEDMTU" },
72 { IFF_VIRTUAL, "VIRTUAL" },
73 { IFF_DUPLICATE, "DUPLICATE" },
74 { IFF_IPMP, "IPMP"},
75 { IFF_VRRP, "VRRP"},
76 { IFF_NOACCEPT, "NOACCEPT"},
77 { IFF_L3PROTECT, "L3PROTECT"}
78 };
79
80 typedef struct {
81 const char *ia_app;
82 uint64_t ia_flag;
83 uint_t ia_tries;
84 } if_appflags_t;
85
86 static const if_appflags_t if_appflags_tbl[] = {
87 { "dhcpagent(1M)", IFF_DHCPRUNNING, 1 },
88 { "in.ndpd(1M)", IFF_ADDRCONF, 3 },
89 { NULL, 0, 0 }
90 };
91
92 static dladm_handle_t dlh;
93 boolean_t dlh_opened;
94 static struct lifreq lifr;
95 /* current interface name a particular function is accessing */
96 static char name[LIFNAMSIZ];
97 /* foreach interface saved name */
98 static char origname[LIFNAMSIZ];
99 static int setaddr;
100 static boolean_t setaddr_done = _B_FALSE;
101 static boolean_t ipsec_policy_set;
102 static boolean_t ipsec_auth_covered;
103 static ipadm_handle_t iph;
104 static ipadm_addrobj_t ipaddr;
105
106 /*
107 * Make sure the algorithm variables hold more than the sizeof an algorithm
108 * in PF_KEY. (For now, more than a uint8_t.) The NO_***_?ALG indicates that
109 * there was no algorithm requested, and in the ipsec_req that service should
110 * be disabled. (E.g. if ah_aalg remains NO_AH_AALG, then AH will be
111 * disabled on that tunnel.)
112 */
113 #define NO_AH_AALG 256
114 #define NO_ESP_AALG 256
115 #define NO_ESP_EALG 256
116
117 int s, s4, s6;
118 int af = AF_INET; /* default address family */
119 int debug = 0;
120 int all = 0; /* setifdhcp() needs to know this */
121 int verbose = 0;
122 int v4compat = 0; /* Compatible printing format */
123
124 /*
125 * Function prototypes for command functions.
126 */
127 static int addif(char *arg, int64_t param);
128 static int inetipmp(char *arg, int64_t param);
129 static int inetplumb(char *arg, int64_t param);
130 static int inetunplumb(char *arg, int64_t param);
131 static int removeif(char *arg, int64_t param);
132 static int setdebugflag(char *arg, int64_t param);
133 static int setifaddr(char *arg, int64_t param);
134 static int setifbroadaddr(char *arg, int64_t param);
135 static int setifdstaddr(char *arg, int64_t param);
136 static int setifether(char *arg, int64_t param);
137 static int setifflags(char *arg, int64_t param);
138 static int setifindex(char *arg, int64_t param);
139 static int setifmetric(char *arg, int64_t param);
140 static int setifmtu(char *arg, int64_t param);
141 static int setifnetmask(char *arg, int64_t param);
142 static int setifprefixlen(char *arg, int64_t param);
143 static int setifrevarp(char *arg, int64_t param);
144 static int setifsubnet(char *arg, int64_t param);
145 static int setiftdst(char *arg, int64_t param);
146 static int setiftoken(char *arg, int64_t param);
147 static int setiftsrc(char *arg, int64_t param);
148 static int setverboseflag(char *arg, int64_t param);
149 static int set_tun_ah_alg(char *arg, int64_t param);
150 static int set_tun_esp_auth_alg(char *arg, int64_t param);
151 static int set_tun_esp_encr_alg(char *arg, int64_t param);
152 static int modlist(char *arg, int64_t param);
153 static int modinsert(char *arg, int64_t param);
154 static int modremove(char *arg, int64_t param);
155 static int setifgroupname(char *arg, int64_t param);
156 static int configinfo(char *arg, int64_t param);
157 static void print_config_flags(int af, uint64_t flags);
158 static void print_flags(uint64_t flags);
159 static void print_ifether(const char *ifname);
160 static int set_tun_encap_limit(char *arg, int64_t param);
161 static int clr_tun_encap_limit(char *arg, int64_t param);
162 static int set_tun_hop_limit(char *arg, int64_t param);
163 static int setzone(char *arg, int64_t param);
164 static int setallzones(char *arg, int64_t param);
165 static int setifsrc(char *arg, int64_t param);
166 static int lifnum(const char *ifname);
167 static void plumball(int, char **, int64_t, int64_t, int64_t);
168
169 /*
170 * Address family specific function prototypes.
171 */
172 static void in_getaddr(char *s, struct sockaddr *saddr, int *plenp);
173 static void in_status(int force, uint64_t flags);
174 static void in_configinfo(int force, uint64_t flags);
175 static void in6_getaddr(char *s, struct sockaddr *saddr, int *plenp);
176 static void in6_status(int force, uint64_t flags);
177 static void in6_configinfo(int force, uint64_t flags);
178
179 /*
180 * Misc support functions
181 */
182 static boolean_t ni_entry(const char *, void *);
183 static void foreachinterface(int argc, char *argv[],
184 int af, int64_t onflags, int64_t offflags,
185 int64_t lifc_flags);
186 static void ifconfig(int argc, char *argv[], int af,
187 struct ifaddrs *ifa);
188 static boolean_t in_getmask(struct sockaddr_in *saddr,
189 boolean_t addr_set);
190 static int in_getprefixlen(char *addr, boolean_t slash, int plen);
191 static boolean_t in_prefixlentomask(int prefixlen, int maxlen,
192 uchar_t *mask);
193 static void status(void);
194 static void ifstatus(const char *ifname);
195 static void tun_status(datalink_id_t);
196 static void usage(void);
197 static int setifdhcp(const char *caller, const char *ifname,
198 int argc, char *argv[]);
199 static int ip_domux2fd(int *, int *, int *, int *, int *);
200 static int ip_plink(int, int, int, int, int);
201 static int modop(char *arg, char op);
202 static int find_all_interfaces(struct lifconf *lifcp, char **buf,
203 int64_t lifc_flags);
204 static int create_ipmp(const char *grname, int af,
205 const char *ifname, boolean_t implicit);
206 static void start_ipmp_daemon(void);
207 static boolean_t ifaddr_up(ifaddrlistx_t *ifaddrp);
208 static boolean_t ifaddr_down(ifaddrlistx_t *ifaddrp);
209 static dladm_status_t ifconfig_dladm_open(const char *, datalink_class_t,
210 datalink_id_t *);
211 static void dladmerr_exit(dladm_status_t status, const char *str);
212 static void ipadmerr_exit(ipadm_status_t status, const char *str);
213 static boolean_t ifconfig_use_libipadm(int, const char *);
214
215 #define max(a, b) ((a) < (b) ? (b) : (a))
216
217 /*
218 * DHCP_EXIT_IF_FAILURE indicates that the operation failed, but if there
219 * are more interfaces to act on (i.e., ifconfig was invoked with -a), keep
220 * on going rather than exit with an error.
221 */
222
223 #define DHCP_EXIT_IF_FAILURE -1
224
225 #define NEXTARG 0xffffff /* command takes an argument */
226 #define OPTARG 0xfffffe /* command takes an optional argument */
227 #define AF_ANY (-1)
228
229 /* Refer to the comments in ifconfig() on the netmask "hack" */
230 #define NETMASK_CMD "netmask"
231 struct sockaddr_storage g_netmask;
232 enum { G_NETMASK_NIL, G_NETMASK_PENDING, G_NETMASK_SET }
233 g_netmask_set = G_NETMASK_NIL;
234
235 struct cmd {
236 char *c_name;
237 int64_t c_parameter; /* NEXTARG means next argv */
238 int (*c_func)(char *, int64_t);
239 int c_abortonfail; /* don't continue parsing args */
240 /* for the current interface */
241 int c_af; /* address family restrictions */
242 } cmds[] = {
243 { "up", IFF_UP, setifflags, 0, AF_ANY },
244 { "down", -IFF_UP, setifflags, 0, AF_ANY },
245 { "trailers", -IFF_NOTRAILERS, setifflags, 0, AF_ANY },
246 { "-trailers", IFF_NOTRAILERS, setifflags, 0, AF_ANY },
247 { "arp", -IFF_NOARP, setifflags, 0, AF_INET },
248 { "-arp", IFF_NOARP, setifflags, 0, AF_INET },
249 { "router", IFF_ROUTER, setifflags, 0, AF_ANY },
250 { "-router", -IFF_ROUTER, setifflags, 0, AF_ANY },
251 { "private", IFF_PRIVATE, setifflags, 0, AF_ANY },
252 { "-private", -IFF_PRIVATE, setifflags, 0, AF_ANY },
253 { "xmit", -IFF_NOXMIT, setifflags, 0, AF_ANY },
254 { "-xmit", IFF_NOXMIT, setifflags, 0, AF_ANY },
255 { "-nud", IFF_NONUD, setifflags, 0, AF_INET6 },
256 { "nud", -IFF_NONUD, setifflags, 0, AF_INET6 },
257 { "anycast", IFF_ANYCAST, setifflags, 0, AF_ANY },
258 { "-anycast", -IFF_ANYCAST, setifflags, 0, AF_ANY },
259 { "local", -IFF_NOLOCAL, setifflags, 0, AF_ANY },
260 { "-local", IFF_NOLOCAL, setifflags, 0, AF_ANY },
261 { "deprecated", IFF_DEPRECATED, setifflags, 0, AF_ANY },
262 { "-deprecated", -IFF_DEPRECATED, setifflags, 0, AF_ANY },
263 { "preferred", IFF_PREFERRED, setifflags, 0, AF_INET6 },
264 { "-preferred", -IFF_PREFERRED, setifflags, 0, AF_INET6 },
265 { "debug", 0, setdebugflag, 0, AF_ANY },
266 { "verbose", 0, setverboseflag, 0, AF_ANY },
267 { NETMASK_CMD, NEXTARG, setifnetmask, 0, AF_INET },
268 { "metric", NEXTARG, setifmetric, 0, AF_ANY },
269 { "mtu", NEXTARG, setifmtu, 0, AF_ANY },
270 { "index", NEXTARG, setifindex, 0, AF_ANY },
271 { "broadcast", NEXTARG, setifbroadaddr, 0, AF_INET },
272 { "auto-revarp", 0, setifrevarp, 1, AF_INET },
273 { "ipmp", 0, inetipmp, 1, AF_ANY },
274 { "plumb", 0, inetplumb, 1, AF_ANY },
275 { "unplumb", 0, inetunplumb, 0, AF_ANY },
276 { "subnet", NEXTARG, setifsubnet, 0, AF_ANY },
277 { "token", NEXTARG, setiftoken, 0, AF_INET6 },
278 { "tsrc", NEXTARG, setiftsrc, 0, AF_ANY },
279 { "tdst", NEXTARG, setiftdst, 0, AF_ANY },
280 { "encr_auth_algs", NEXTARG, set_tun_esp_auth_alg, 0, AF_ANY },
281 { "encr_algs", NEXTARG, set_tun_esp_encr_alg, 0, AF_ANY },
282 { "auth_algs", NEXTARG, set_tun_ah_alg, 0, AF_ANY },
283 { "addif", NEXTARG, addif, 1, AF_ANY },
284 { "removeif", NEXTARG, removeif, 1, AF_ANY },
285 { "modlist", 0, modlist, 1, AF_ANY },
286 { "modinsert", NEXTARG, modinsert, 1, AF_ANY },
287 { "modremove", NEXTARG, modremove, 1, AF_ANY },
288 { "failover", -IFF_NOFAILOVER, setifflags, 1, AF_ANY },
289 { "-failover", IFF_NOFAILOVER, setifflags, 1, AF_ANY },
290 { "standby", IFF_STANDBY, setifflags, 1, AF_ANY },
291 { "-standby", -IFF_STANDBY, setifflags, 1, AF_ANY },
292 { "failed", IFF_FAILED, setifflags, 1, AF_ANY },
293 { "-failed", -IFF_FAILED, setifflags, 1, AF_ANY },
294 { "group", NEXTARG, setifgroupname, 1, AF_ANY },
295 { "configinfo", 0, configinfo, 1, AF_ANY },
296 { "encaplimit", NEXTARG, set_tun_encap_limit, 0, AF_ANY },
297 { "-encaplimit", 0, clr_tun_encap_limit, 0, AF_ANY },
298 { "thoplimit", NEXTARG, set_tun_hop_limit, 0, AF_ANY },
299 { "set", NEXTARG, setifaddr, 0, AF_ANY },
300 { "destination", NEXTARG, setifdstaddr, 0, AF_ANY },
301 { "zone", NEXTARG, setzone, 0, AF_ANY },
302 { "-zone", 0, setzone, 0, AF_ANY },
303 { "all-zones", 0, setallzones, 0, AF_ANY },
304 { "ether", OPTARG, setifether, 0, AF_ANY },
305 { "usesrc", NEXTARG, setifsrc, 0, AF_ANY },
306
307 /*
308 * NOTE: any additions to this table must also be applied to ifparse
309 * (usr/src/cmd/cmd-inet/sbin/ifparse/ifparse.c)
310 */
311
312 { 0, 0, setifaddr, 0, AF_ANY },
313 { 0, 0, setifdstaddr, 0, AF_ANY },
314 { 0, 0, 0, 0, 0 },
315 };
316
317
318 typedef struct if_config_cmd {
319 uint64_t iff_flag;
320 int iff_af;
321 char *iff_name;
322 } if_config_cmd_t;
323
324 /*
325 * NOTE: print_config_flags() processes this table in order, so we put "up"
326 * last so that we can be sure "-failover" will take effect first. Otherwise,
327 * IPMP test addresses will erroneously migrate to the IPMP interface.
328 */
329 static if_config_cmd_t if_config_cmd_tbl[] = {
330 { IFF_NOTRAILERS, AF_UNSPEC, "-trailers" },
331 { IFF_PRIVATE, AF_UNSPEC, "private" },
332 { IFF_NOXMIT, AF_UNSPEC, "-xmit" },
333 { IFF_ANYCAST, AF_INET6, "anycast" },
334 { IFF_NOLOCAL, AF_UNSPEC, "-local" },
335 { IFF_DEPRECATED, AF_UNSPEC, "deprecated" },
336 { IFF_NOFAILOVER, AF_UNSPEC, "-failover" },
337 { IFF_STANDBY, AF_UNSPEC, "standby" },
338 { IFF_FAILED, AF_UNSPEC, "failed" },
339 { IFF_PREFERRED, AF_UNSPEC, "preferred" },
340 { IFF_NONUD, AF_INET6, "-nud" },
341 { IFF_NOARP, AF_INET, "-arp" },
342 { IFF_UP, AF_UNSPEC, "up" },
343 { 0, 0, NULL },
344 };
345
346 typedef struct ni {
347 char ni_name[LIFNAMSIZ];
348 struct ni *ni_next;
349 } ni_t;
350
351 static ni_t *ni_list = NULL;
352 static int num_ni = 0;
353
354 /* End defines and structure definitions for ifconfig -a plumb */
355
356 /* Known address families */
357 struct afswtch {
358 char *af_name;
359 short af_af;
360 void (*af_status)();
361 void (*af_getaddr)();
362 void (*af_configinfo)();
363 } afs[] = {
364 { "inet", AF_INET, in_status, in_getaddr, in_configinfo },
365 { "inet6", AF_INET6, in6_status, in6_getaddr, in6_configinfo },
366 { 0, 0, 0, 0, 0 }
367 };
368
369 #define SOCKET_AF(af) (((af) == AF_UNSPEC) ? AF_INET : (af))
370
371 struct afswtch *afp; /* the address family being set or asked about */
372
373 int
main(int argc,char * argv[])374 main(int argc, char *argv[])
375 {
376 int64_t lifc_flags;
377 char *default_ip_str;
378 ipadm_status_t istatus;
379
380 lifc_flags = LIFC_DEFAULT;
381
382 if (argc < 2) {
383 usage();
384 exit(1);
385 }
386 argc--, argv++;
387 if (strlen(*argv) > sizeof (name) - 1) {
388 (void) fprintf(stderr, "%s: interface name too long\n", *argv);
389 exit(1);
390 }
391 (void) strncpy(name, *argv, sizeof (name));
392 name[sizeof (name) - 1] = '\0';
393 (void) strncpy(origname, name, sizeof (origname)); /* For addif */
394 default_ip_str = NULL;
395 v4compat = get_compat_flag(&default_ip_str);
396 if (v4compat == DEFAULT_PROT_BAD_VALUE) {
397 (void) fprintf(stderr,
398 "ifconfig: %s: Bad value for %s in %s\n", default_ip_str,
399 DEFAULT_IP, INET_DEFAULT_FILE);
400 free(default_ip_str);
401 exit(2);
402 }
403 free(default_ip_str);
404 argc--, argv++;
405 if (argc > 0) {
406 struct afswtch *myafp;
407
408 for (myafp = afp = afs; myafp->af_name; myafp++) {
409 if (strcmp(myafp->af_name, *argv) == 0) {
410 afp = myafp; argc--; argv++;
411 break;
412 }
413 }
414 af = lifr.lifr_addr.ss_family = afp->af_af;
415 if (af == AF_INET6) {
416 v4compat = 0;
417 }
418 }
419
420 s = socket(SOCKET_AF(af), SOCK_DGRAM, 0);
421 s4 = socket(AF_INET, SOCK_DGRAM, 0);
422 s6 = socket(AF_INET6, SOCK_DGRAM, 0);
423 if (s == -1 || s4 == -1 || s6 == -1)
424 Perror0_exit("socket");
425 /*
426 * Open the global libipadm handle. The flag IPH_LEGACY has to
427 * be specified to indicate that logical interface names will
428 * be used during interface creation and address creation.
429 */
430 if ((istatus = ipadm_open(&iph, IPH_LEGACY)) != IPADM_SUCCESS)
431 ipadmerr_exit(istatus, "unable to open handle to libipadm");
432
433 /*
434 * Special interface names is any combination of these flags.
435 * Note that due to the ifconfig syntax they have to be combined
436 * as a single '-' option.
437 * -a All interfaces
438 * -u "up" interfaces
439 * -d "down" interfaces
440 * -D Interfaces not controlled by DHCP
441 * -4 IPv4 interfaces
442 * -6 IPv6 interfaces
443 * -X Turn on debug (not documented)
444 * -v Turn on verbose
445 * -Z Only interfaces in caller's zone
446 */
447
448 if (name[0] == '-') {
449 /* One or more options */
450 int64_t onflags = 0;
451 int64_t offflags = 0;
452 int c;
453 char *av[2] = { "ifconfig", name };
454
455 while ((c = getopt(2, av, "audDXZ46v")) != -1) {
456 switch ((char)c) {
457 case 'a':
458 all = 1;
459 break;
460 case 'u':
461 onflags |= IFF_UP;
462 break;
463 case 'd':
464 offflags |= IFF_UP;
465 break;
466 case 'D':
467 offflags |= IFF_DHCPRUNNING;
468 break;
469 case 'X':
470 debug += 3;
471 break;
472 case 'Z':
473 lifc_flags &= ~LIFC_ALLZONES;
474 break;
475 case '4':
476 /*
477 * -4 is not a compatable flag, therefore
478 * we assume they want v4compat turned off
479 */
480 v4compat = 0;
481 onflags |= IFF_IPV4;
482 break;
483 case '6':
484 /*
485 * If they want IPv6, well then we'll assume
486 * they don't want IPv4 compat
487 */
488 v4compat = 0;
489 onflags |= IFF_IPV6;
490 break;
491 case 'v':
492 verbose = 1;
493 break;
494 case '?':
495 usage();
496 exit(1);
497 }
498 }
499 if (!all) {
500 (void) fprintf(stderr,
501 "ifconfig: %s: no such interface\n", name);
502 exit(1);
503 }
504 foreachinterface(argc, argv, af, onflags, offflags,
505 lifc_flags);
506 } else {
507 ifconfig(argc, argv, af, NULL);
508 }
509 ipadm_close(iph);
510 return (0);
511 }
512
513 /*
514 * For each interface, call ifconfig(argc, argv, af, ifa).
515 * Only call function if onflags and offflags are set or clear, respectively,
516 * in the interfaces flags field.
517 */
518 static void
foreachinterface(int argc,char * argv[],int af,int64_t onflags,int64_t offflags,int64_t lifc_flags)519 foreachinterface(int argc, char *argv[], int af,
520 int64_t onflags, int64_t offflags, int64_t lifc_flags)
521 {
522 ipadm_addr_info_t *ainfo, *ainfop;
523 struct ifaddrs *ifa;
524 ipadm_status_t istatus;
525
526 /*
527 * Special case:
528 * ifconfig -a plumb should find all network interfaces in the current
529 * zone.
530 */
531 if (argc > 0 && (strcmp(*argv, "plumb") == 0)) {
532 plumball(argc, argv, onflags, offflags, lifc_flags);
533 return;
534 }
535 /* Get all addresses in kernel including addresses that are zero. */
536 istatus = ipadm_addr_info(iph, NULL, &ainfo, IPADM_OPT_ZEROADDR,
537 lifc_flags);
538 if (istatus != IPADM_SUCCESS)
539 ipadmerr_exit(istatus, "could not get addresses from kernel");
540
541 /*
542 * For each logical interface, call ifconfig() with the
543 * given arguments.
544 */
545 for (ainfop = ainfo; ainfop != NULL; ainfop = IA_NEXT(ainfop)) {
546 if (ainfop->ia_state == IFA_DISABLED)
547 continue;
548 ifa = &ainfop->ia_ifa;
549 if (onflags || offflags) {
550 if ((ifa->ifa_flags & onflags) != onflags)
551 continue;
552 if ((~ifa->ifa_flags & offflags) != offflags)
553 continue;
554 }
555 s = (ifa->ifa_addr->sa_family == AF_INET ? s4 : s6);
556 (void) strncpy(name, ifa->ifa_name, sizeof (name));
557 (void) strncpy(origname, name, sizeof (origname));
558 ifconfig(argc, argv, af, ifa);
559 }
560 ipadm_free_addr_info(ainfo);
561 }
562
563 /*
564 * Used for `ifconfig -a plumb'. Finds all datalinks and plumbs the interface.
565 */
566 static void
plumball(int argc,char * argv[],int64_t onflags,int64_t offflags,int64_t lifc_flags)567 plumball(int argc, char *argv[], int64_t onflags, int64_t offflags,
568 int64_t lifc_flags)
569 {
570 int n;
571 struct lifreq *lifrp;
572 struct lifconf lifc;
573 char *buf;
574
575 if (onflags != 0 || offflags != 0) {
576 (void) fprintf(stderr, "ifconfig: invalid syntax used to "
577 "plumb all interfaces.\n");
578 exit(1);
579 }
580
581 if (find_all_interfaces(&lifc, &buf, lifc_flags) != 0 ||
582 lifc.lifc_len == 0)
583 return;
584
585 lifrp = lifc.lifc_req;
586 for (n = lifc.lifc_len / sizeof (struct lifreq); n > 0; n--, lifrp++) {
587 /*
588 * Reset global state
589 * setaddr: Used by parser to tear apart source and dest
590 * name and origname contain the name of the 'current'
591 * interface.
592 */
593 setaddr = 0;
594 (void) strncpy(name, lifrp->lifr_name, sizeof (name));
595 (void) strncpy(origname, name, sizeof (origname));
596 ifconfig(argc, argv, af, NULL);
597 }
598 }
599
600 /*
601 * Parses the interface name and the command in argv[]. Calls the
602 * appropriate callback function for the given command from `cmds[]'
603 * table.
604 * If there is no command specified, it prints all addresses.
605 */
606 static void
ifconfig(int argc,char * argv[],int af,struct ifaddrs * ifa)607 ifconfig(int argc, char *argv[], int af, struct ifaddrs *ifa)
608 {
609 static boolean_t scan_netmask = _B_FALSE;
610 int ret;
611 ipadm_status_t istatus;
612 struct lifreq lifr;
613
614 if (argc == 0) {
615 status();
616 return;
617 }
618
619 if (strcmp(*argv, "auto-dhcp") == 0 || strcmp(*argv, "dhcp") == 0) {
620 /*
621 * Some errors are ignored in the case where more than one
622 * interface is being operated on.
623 */
624 ret = setifdhcp("ifconfig", name, argc, argv);
625 if (ret == DHCP_EXIT_IF_FAILURE) {
626 if (!all)
627 exit(DHCP_EXIT_FAILURE);
628 } else if (ret != DHCP_EXIT_SUCCESS) {
629 exit(ret);
630 }
631 return;
632 }
633
634 /*
635 * The following is a "hack" to get around the existing interface
636 * setting mechanism. Currently, each interface attribute,
637 * such as address, netmask, broadcast, ... is set separately. But
638 * sometimes two or more attributes must be set together. For
639 * example, setting an address without a netmask does not make sense.
640 * Yet they can be set separately for IPv4 address using the current
641 * ifconfig(1M) syntax. The kernel then "infers" the correct netmask
642 * using the deprecated "IP address classes." This is simply not
643 * correct.
644 *
645 * The "hack" below is to go thru the whole command list looking for
646 * the netmask command first. Then use this netmask to set the
647 * address. This does not provide an extensible way to accommodate
648 * future need for setting more than one attributes together.
649 *
650 * Note that if the "netmask" command argument is a "+", we need
651 * to save this info and do the query after we know the address to
652 * be set. The reason is that if "addif" is used, the working
653 * interface name will be changed later when the logical interface
654 * is created. In in_getmask(), if an address is not provided,
655 * it will use the working interface's address to do the query.
656 * It will be wrong now as we don't know the logical interface's name.
657 *
658 * ifconfig(1M) is too overloaded and the code is so convoluted
659 * that it is "safer" not to re-architect the code to fix the above
660 * issue, hence this "hack." We may be better off to have a new
661 * command with better syntax for configuring network interface
662 * parameters...
663 */
664 if (!scan_netmask && afp->af_af == AF_INET) {
665 int largc;
666 char **largv;
667
668 /* Only go thru the command list once to find the netmask. */
669 scan_netmask = _B_TRUE;
670
671 /*
672 * Currently, if multiple netmask commands are specified, the
673 * last one will be used as the final netmask. So we need
674 * to scan the whole list to preserve this behavior.
675 */
676 for (largc = argc, largv = argv; largc > 0; largc--, largv++) {
677 if (strcmp(*largv, NETMASK_CMD) == 0) {
678 if (--largc == 0)
679 break;
680 largv++;
681 if (strcmp(*largv, "+") == 0) {
682 g_netmask_set = G_NETMASK_PENDING;
683 } else {
684 in_getaddr(*largv, (struct sockaddr *)
685 &g_netmask, NULL);
686 g_netmask_set = G_NETMASK_SET;
687 }
688 /* Continue the scan. */
689 }
690 }
691 }
692
693 while (argc > 0) {
694 struct cmd *p;
695 boolean_t found_cmd;
696
697 if (debug)
698 (void) printf("ifconfig: argv %s\n", *argv);
699
700 found_cmd = _B_FALSE;
701 for (p = cmds; p->c_func; p++) {
702 if (p->c_name) {
703 if (strcmp(*argv, p->c_name) == 0) {
704 /*
705 * indicate that the command was
706 * found and check to see if
707 * the address family is valid
708 */
709 found_cmd = _B_TRUE;
710 if (p->c_af == AF_ANY ||
711 af == p->c_af)
712 break;
713 }
714 } else {
715 if (p->c_af == AF_ANY ||
716 af == p->c_af)
717 break;
718 }
719 }
720 /*
721 * If we found the keyword, but the address family
722 * did not match spit out an error
723 */
724 if (found_cmd && p->c_name == 0) {
725 (void) fprintf(stderr, "ifconfig: Operation %s not"
726 " supported for %s\n", *argv, afp->af_name);
727 exit(1);
728 }
729 /*
730 * else (no keyword found), we assume it's an address
731 * of some sort
732 */
733 if (setaddr && ipaddr != NULL) {
734 /*
735 * We must have already filled in a source address in
736 * `ipaddr' and we now got a destination address.
737 * Fill it in `ipaddr' and call libipadm to create
738 * the static address.
739 */
740 if (p->c_name == 0) {
741 istatus = ipadm_set_dst_addr(ipaddr, *argv,
742 (p->c_af == AF_ANY ? AF_UNSPEC : af));
743 if (istatus != IPADM_SUCCESS) {
744 ipadmerr_exit(istatus, "could not "
745 "set destination address");
746 }
747 /*
748 * finished processing dstaddr, so reset setaddr
749 */
750 setaddr = 0;
751 }
752 /*
753 * Both source and destination address are in `ipaddr'.
754 * Add the address by calling libipadm.
755 */
756 istatus = ipadm_create_addr(iph, ipaddr,
757 IPADM_OPT_ACTIVE);
758 if (istatus != IPADM_SUCCESS)
759 goto createfailed;
760 ipadm_destroy_addrobj(ipaddr);
761 ipaddr = NULL;
762 setaddr_done = _B_TRUE;
763 if (p->c_name == 0) {
764 /* move parser along */
765 argc--, argv++;
766 continue;
767 }
768 }
769 if (p->c_name == 0 && setaddr_done) {
770 /*
771 * catch odd commands like
772 * "ifconfig <intf> addr1 addr2 addr3 addr4 up"
773 */
774 (void) fprintf(stderr, "%s",
775 "ifconfig: cannot configure more than two "
776 "addresses in one command\n");
777 exit(1);
778 }
779 if (p->c_func) {
780 if (p->c_af == AF_INET6) {
781 v4compat = 0;
782 }
783 if (p->c_parameter == NEXTARG ||
784 p->c_parameter == OPTARG) {
785 argc--, argv++;
786 if (argc == 0 && p->c_parameter == NEXTARG) {
787 (void) fprintf(stderr,
788 "ifconfig: no argument for %s\n",
789 p->c_name);
790 exit(1);
791 }
792 }
793 /*
794 * Call the function if:
795 *
796 * there's no address family
797 * restriction
798 * OR
799 * we don't know the address yet
800 * (because we were called from
801 * main)
802 * OR
803 * there is a restriction AND
804 * the address families match
805 */
806 if ((p->c_af == AF_ANY) ||
807 (ifa == NULL) ||
808 (ifa->ifa_addr->sa_family == p->c_af)) {
809 ret = (*p->c_func)(*argv, p->c_parameter);
810 /*
811 * If c_func failed and we should
812 * abort processing for this
813 * interface on failure, return
814 * now rather than going on to
815 * process other commands for
816 * the same interface.
817 */
818 if (ret != 0 && p->c_abortonfail)
819 return;
820 }
821 }
822 argc--, argv++;
823 }
824
825 if (setaddr && ipaddr != NULL) {
826 /*
827 * Only the source address was provided, which was already
828 * set in `ipaddr'. Add the address by calling libipadm.
829 */
830 istatus = ipadm_create_addr(iph, ipaddr, IPADM_OPT_ACTIVE);
831 if (istatus != IPADM_SUCCESS)
832 goto createfailed;
833 ipadm_destroy_addrobj(ipaddr);
834 ipaddr = NULL;
835 setaddr_done = _B_TRUE;
836 }
837
838 /* Check to see if there's a security hole in the tunnel setup. */
839 if (ipsec_policy_set && !ipsec_auth_covered) {
840 (void) fprintf(stderr, "ifconfig: WARNING: tunnel with only "
841 "ESP and no authentication.\n");
842 }
843 return;
844
845 createfailed:
846 (void) fprintf(stderr, "ifconfig: could not create address:% s\n",
847 ipadm_status2str(istatus));
848 /* Remove the newly created logical interface. */
849 if (strcmp(name, origname) != 0) {
850 assert(strchr(name, ':') != NULL);
851 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
852 (void) ioctl(s, SIOCLIFREMOVEIF, (caddr_t)&lifr);
853 }
854 exit(1);
855 }
856
857 /* ARGSUSED */
858 static int
setdebugflag(char * val,int64_t arg)859 setdebugflag(char *val, int64_t arg)
860 {
861 debug++;
862 return (0);
863 }
864
865 /* ARGSUSED */
866 static int
setverboseflag(char * val,int64_t arg)867 setverboseflag(char *val, int64_t arg)
868 {
869 verbose++;
870 return (0);
871 }
872
873 /*
874 * This function fills in the given lifreq's lifr_addr field based on
875 * g_netmask_set.
876 */
877 static void
set_mask_lifreq(struct lifreq * lifr,struct sockaddr_storage * addr,struct sockaddr_storage * mask)878 set_mask_lifreq(struct lifreq *lifr, struct sockaddr_storage *addr,
879 struct sockaddr_storage *mask)
880 {
881 assert(addr != NULL);
882 assert(mask != NULL);
883
884 switch (g_netmask_set) {
885 case G_NETMASK_SET:
886 lifr->lifr_addr = g_netmask;
887 break;
888
889 case G_NETMASK_PENDING:
890 /*
891 * "+" is used as the argument to "netmask" command. Query
892 * the database on the correct netmask based on the address to
893 * be set.
894 */
895 assert(afp->af_af == AF_INET);
896 g_netmask = *addr;
897 if (!in_getmask((struct sockaddr_in *)&g_netmask, _B_TRUE)) {
898 lifr->lifr_addr = *mask;
899 g_netmask_set = G_NETMASK_NIL;
900 } else {
901 lifr->lifr_addr = g_netmask;
902 g_netmask_set = G_NETMASK_SET;
903 }
904 break;
905
906 case G_NETMASK_NIL:
907 default:
908 lifr->lifr_addr = *mask;
909 break;
910 }
911 }
912
913 /*
914 * Set the interface address. Handles <addr>, <addr>/<n> as well as /<n>
915 * syntax for setting the address, the address plus netmask, and just
916 * the netmask respectively.
917 */
918 /* ARGSUSED */
919 static int
setifaddr(char * addr,int64_t param)920 setifaddr(char *addr, int64_t param)
921 {
922 ipadm_status_t istatus;
923 int prefixlen = 0;
924 struct lifreq lifr1;
925 struct sockaddr_storage laddr;
926 struct sockaddr_storage netmask;
927 struct sockaddr_in6 *sin6;
928 struct sockaddr_in *sin;
929 struct sockaddr_storage sav_netmask;
930 char cidraddr[BUFSIZ];
931
932 if (addr[0] == '/')
933 return (setifprefixlen(addr, 0));
934
935 (*afp->af_getaddr)(addr, (struct sockaddr *)&laddr, &prefixlen);
936
937 (void) memset(&netmask, 0, sizeof (netmask));
938 netmask.ss_family = afp->af_af;
939 switch (prefixlen) {
940 case NO_PREFIX:
941 /* Nothing there - ok */
942 break;
943 case BAD_ADDR:
944 (void) fprintf(stderr, "ifconfig: Bad prefix length in %s\n",
945 addr);
946 exit(1);
947 default:
948 if (afp->af_af == AF_INET6) {
949 sin6 = (struct sockaddr_in6 *)&netmask;
950 if (!in_prefixlentomask(prefixlen, IPV6_ABITS,
951 (uchar_t *)&sin6->sin6_addr)) {
952 (void) fprintf(stderr, "ifconfig: "
953 "Bad prefix length: %d\n",
954 prefixlen);
955 exit(1);
956 }
957 } else {
958 sin = (struct sockaddr_in *)&netmask;
959 if (!in_prefixlentomask(prefixlen, IP_ABITS,
960 (uchar_t *)&sin->sin_addr)) {
961 (void) fprintf(stderr, "ifconfig: "
962 "Bad prefix length: %d\n",
963 prefixlen);
964 exit(1);
965 }
966 }
967 /*
968 * Just in case of funny setting of both prefix and netmask,
969 * prefix should override the netmask command.
970 */
971 g_netmask_set = G_NETMASK_NIL;
972 break;
973 }
974
975 /*
976 * Check and see if any "netmask" command is used and perform the
977 * necessary operation.
978 */
979 set_mask_lifreq(&lifr, &laddr, &netmask);
980
981 /* This check is temporary until libipadm supports IPMP interfaces. */
982 if (ifconfig_use_libipadm(s, name)) {
983 char addrstr[INET6_ADDRSTRLEN];
984
985 if (af == AF_INET) {
986 sin = (struct sockaddr_in *)&laddr;
987 (void) inet_ntop(AF_INET, &sin->sin_addr, addrstr,
988 sizeof (addrstr));
989 } else {
990 sin6 = (struct sockaddr_in6 *)&laddr;
991 (void) inet_ntop(AF_INET6, &sin6->sin6_addr, addrstr,
992 sizeof (addrstr));
993 }
994 istatus = ipadm_create_addrobj(IPADM_ADDR_STATIC, name,
995 &ipaddr);
996 if (istatus != IPADM_SUCCESS)
997 ipadmerr_exit(istatus, "setifaddr");
998
999 /*
1000 * lifr.lifr_addr, which is updated by set_mask_lifreq()
1001 * will contain the right mask to use.
1002 */
1003 prefixlen = mask2plen((struct sockaddr *)&lifr.lifr_addr);
1004 (void) snprintf(cidraddr, sizeof (cidraddr), "%s/%d",
1005 addrstr, prefixlen);
1006
1007 istatus = ipadm_set_addr(ipaddr, cidraddr, af);
1008 if (istatus != IPADM_SUCCESS)
1009 ipadmerr_exit(istatus, "could not set address");
1010 /*
1011 * let parser know we got a source.
1012 * Next address, if given, should be dest
1013 */
1014 setaddr++;
1015
1016 /*
1017 * address will be set by the parser after nextarg has
1018 * been scanned
1019 */
1020 return (0);
1021 }
1022
1023 /* Tell parser that an address was set */
1024 setaddr++;
1025 /* save copy of netmask to restore in case of error */
1026 (void) strncpy(lifr1.lifr_name, name, sizeof (lifr1.lifr_name));
1027 if (ioctl(s, SIOCGLIFNETMASK, (caddr_t)&lifr1) < 0)
1028 Perror0_exit("SIOCGLIFNETMASK");
1029 sav_netmask = lifr1.lifr_addr;
1030
1031 /*
1032 * If setting the address and not the mask, clear any existing mask
1033 * and the kernel will then assign the default (netmask has been set
1034 * to 0 in this case). If setting both (either by using a prefix or
1035 * using the netmask command), set the mask first, so the address will
1036 * be interpreted correctly.
1037 */
1038 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1039 /* lifr.lifr_addr already contains netmask from set_mask_lifreq() */
1040 if (ioctl(s, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0)
1041 Perror0_exit("SIOCSLIFNETMASK");
1042
1043 if (debug) {
1044 char abuf[INET6_ADDRSTRLEN];
1045 void *addr = (afp->af_af == AF_INET) ?
1046 (void *)&((struct sockaddr_in *)&laddr)->sin_addr :
1047 (void *)&((struct sockaddr_in6 *)&laddr)->sin6_addr;
1048
1049 (void) printf("Setting %s af %d addr %s\n",
1050 lifr.lifr_name, afp->af_af,
1051 inet_ntop(afp->af_af, addr, abuf, sizeof (abuf)));
1052 }
1053 lifr.lifr_addr = laddr;
1054 lifr.lifr_addr.ss_family = afp->af_af;
1055 if (ioctl(s, SIOCSLIFADDR, (caddr_t)&lifr) < 0) {
1056 /*
1057 * Restore the netmask
1058 */
1059 int saverr = errno;
1060
1061 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1062 lifr.lifr_addr = sav_netmask;
1063 (void) ioctl(s, SIOCSLIFNETMASK, (caddr_t)&lifr);
1064 errno = saverr;
1065 Perror0_exit("SIOCSLIFADDR");
1066 }
1067
1068 return (0);
1069 }
1070
1071 /*
1072 * The following functions are stolen from the ipseckey(1m) program.
1073 * Perhaps they should be somewhere common, but for now, we just maintain
1074 * two versions. We do this because of the different semantics for which
1075 * algorithms we select ("requested" for ifconfig vs. "actual" for key).
1076 */
1077
1078 static ulong_t
parsenum(char * num)1079 parsenum(char *num)
1080 {
1081 ulong_t rc;
1082 char *end = NULL;
1083
1084 errno = 0;
1085 rc = strtoul(num, &end, 0);
1086 if (errno != 0 || end == num || *end != '\0') {
1087 rc = (ulong_t)-1;
1088 }
1089
1090 return (rc);
1091 }
1092
1093 /*
1094 * Parse and reverse parse possible algorithm values, include numbers.
1095 * Mostly stolen from ipseckey.c. See the comments above parsenum() for why
1096 * this isn't common to ipseckey.c.
1097 *
1098 * NOTE: Static buffer in this function for the return value. Since ifconfig
1099 * isn't multithreaded, this isn't a huge problem.
1100 */
1101
1102 #define NBUF_SIZE 20 /* Enough to print a large integer. */
1103
1104 static char *
rparsealg(uint8_t alg_value,int proto_num)1105 rparsealg(uint8_t alg_value, int proto_num)
1106 {
1107 struct ipsecalgent *alg;
1108 static char numprint[128]; /* Enough to hold an algorithm name. */
1109
1110 /*
1111 * Special cases for "any" and "none"
1112 * The kernel needs to be able to distinguish between "any"
1113 * and "none" and the APIs are underdefined in this area for auth.
1114 */
1115 if (proto_num == IPSEC_PROTO_AH) {
1116 if (alg_value == SADB_AALG_NONE)
1117 return ("none");
1118 if (alg_value == SADB_AALG_ANY)
1119 return ("any");
1120 }
1121
1122 alg = getipsecalgbynum(alg_value, proto_num, NULL);
1123 if (alg != NULL) {
1124 (void) strlcpy(numprint, alg->a_names[0], sizeof (numprint));
1125 freeipsecalgent(alg);
1126 } else {
1127 (void) snprintf(numprint, sizeof (numprint), "%d", alg_value);
1128 }
1129
1130 return (numprint);
1131 }
1132
1133 static uint_t
parsealg(char * algname,int proto_num)1134 parsealg(char *algname, int proto_num)
1135 {
1136 struct ipsecalgent *alg;
1137 ulong_t invalue;
1138
1139 if (algname == NULL) {
1140 (void) fprintf(stderr, "ifconfig: Unexpected end of command "
1141 "line.\n");
1142 exit(1);
1143 }
1144
1145 /*
1146 * Special-case "none" and "any".
1147 * Use strcasecmp because its length is bounded.
1148 */
1149 if (strcasecmp("none", algname) == 0) {
1150 return ((proto_num == IPSEC_PROTO_ESP) ?
1151 NO_ESP_EALG : NO_ESP_AALG);
1152 }
1153 if ((strcasecmp("any", algname) == 0) && (proto_num == IPSEC_PROTO_AH))
1154 return (SADB_AALG_ANY);
1155
1156 alg = getipsecalgbyname(algname, proto_num, NULL);
1157 if (alg != NULL) {
1158 invalue = alg->a_alg_num;
1159 freeipsecalgent(alg);
1160 return ((uint_t)invalue);
1161 }
1162
1163 /*
1164 * Since algorithms can be loaded during kernel run-time, check for
1165 * numeric algorithm values too.
1166 */
1167 invalue = parsenum(algname);
1168 if ((invalue & (ulong_t)0xff) == invalue)
1169 return ((uint_t)invalue);
1170
1171 (void) fprintf(stderr, "ifconfig: %s algorithm type %s unknown.\n",
1172 (proto_num == IPSEC_PROTO_ESP) ?
1173 "Encryption" : "Authentication", algname);
1174 exit(1);
1175 /* NOTREACHED */
1176 }
1177
1178 /*
1179 * Actual ifconfig functions to set tunnel security properties.
1180 */
1181
1182 enum ipsec_alg_type { ESP_ENCR_ALG = 1, ESP_AUTH_ALG, AH_AUTH_ALG };
1183
1184 static int
set_tun_algs(int which_alg,int alg)1185 set_tun_algs(int which_alg, int alg)
1186 {
1187 boolean_t encr_alg_set = _B_FALSE;
1188 iptun_params_t params;
1189 dladm_status_t status;
1190 ipsec_req_t *ipsr;
1191
1192 if ((status = ifconfig_dladm_open(name, DATALINK_CLASS_IPTUN,
1193 ¶ms.iptun_param_linkid)) != DLADM_STATUS_OK)
1194 goto done;
1195
1196 status = dladm_iptun_getparams(dlh, ¶ms, DLADM_OPT_ACTIVE);
1197 if (status != DLADM_STATUS_OK)
1198 goto done;
1199
1200 ipsr = ¶ms.iptun_param_secinfo;
1201
1202 /*
1203 * If I'm just starting off this ifconfig, I want a clean slate,
1204 * otherwise, I've captured the current tunnel security settings.
1205 * In the case of continuation, I merely add to the settings.
1206 */
1207 if (!(params.iptun_param_flags & IPTUN_PARAM_SECINFO))
1208 (void) memset(ipsr, 0, sizeof (*ipsr));
1209
1210 /* We're only modifying the IPsec information */
1211 params.iptun_param_flags = IPTUN_PARAM_SECINFO;
1212
1213 switch (which_alg) {
1214 case ESP_ENCR_ALG:
1215 if (alg == NO_ESP_EALG) {
1216 if (ipsr->ipsr_esp_auth_alg == SADB_AALG_NONE)
1217 ipsr->ipsr_esp_req = 0;
1218 ipsr->ipsr_esp_alg = SADB_EALG_NONE;
1219
1220 /* Let the user specify NULL encryption implicitly. */
1221 if (ipsr->ipsr_esp_auth_alg != SADB_AALG_NONE) {
1222 encr_alg_set = _B_TRUE;
1223 ipsr->ipsr_esp_alg = SADB_EALG_NULL;
1224 }
1225 } else {
1226 encr_alg_set = _B_TRUE;
1227 ipsr->ipsr_esp_req =
1228 IPSEC_PREF_REQUIRED | IPSEC_PREF_UNIQUE;
1229 ipsr->ipsr_esp_alg = alg;
1230 }
1231 break;
1232 case ESP_AUTH_ALG:
1233 if (alg == NO_ESP_AALG) {
1234 if ((ipsr->ipsr_esp_alg == SADB_EALG_NONE ||
1235 ipsr->ipsr_esp_alg == SADB_EALG_NULL) &&
1236 !encr_alg_set)
1237 ipsr->ipsr_esp_req = 0;
1238 ipsr->ipsr_esp_auth_alg = SADB_AALG_NONE;
1239 } else {
1240 ipsr->ipsr_esp_req =
1241 IPSEC_PREF_REQUIRED | IPSEC_PREF_UNIQUE;
1242 ipsr->ipsr_esp_auth_alg = alg;
1243
1244 /* Let the user specify NULL encryption implicitly. */
1245 if (ipsr->ipsr_esp_alg == SADB_EALG_NONE &&
1246 !encr_alg_set)
1247 ipsr->ipsr_esp_alg = SADB_EALG_NULL;
1248 }
1249 break;
1250 case AH_AUTH_ALG:
1251 if (alg == NO_AH_AALG) {
1252 ipsr->ipsr_ah_req = 0;
1253 ipsr->ipsr_auth_alg = SADB_AALG_NONE;
1254 } else {
1255 ipsr->ipsr_ah_req =
1256 IPSEC_PREF_REQUIRED | IPSEC_PREF_UNIQUE;
1257 ipsr->ipsr_auth_alg = alg;
1258 }
1259 break;
1260 /* Will never hit DEFAULT */
1261 }
1262
1263 status = dladm_iptun_modify(dlh, ¶ms, DLADM_OPT_ACTIVE);
1264
1265 done:
1266 if (status != DLADM_STATUS_OK)
1267 dladmerr_exit(status, name);
1268 else {
1269 ipsec_policy_set = _B_TRUE;
1270 if ((ipsr->ipsr_esp_req != 0 &&
1271 ipsr->ipsr_esp_auth_alg != SADB_AALG_NONE) ||
1272 (ipsr->ipsr_ah_req != 0 &&
1273 ipsr->ipsr_auth_alg != SADB_AALG_NONE))
1274 ipsec_auth_covered = _B_TRUE;
1275 }
1276 return (0);
1277 }
1278
1279 /* ARGSUSED */
1280 static int
set_tun_esp_encr_alg(char * addr,int64_t param)1281 set_tun_esp_encr_alg(char *addr, int64_t param)
1282 {
1283 return (set_tun_algs(ESP_ENCR_ALG,
1284 parsealg(addr, IPSEC_PROTO_ESP)));
1285 }
1286
1287 /* ARGSUSED */
1288 static int
set_tun_esp_auth_alg(char * addr,int64_t param)1289 set_tun_esp_auth_alg(char *addr, int64_t param)
1290 {
1291 return (set_tun_algs(ESP_AUTH_ALG,
1292 parsealg(addr, IPSEC_PROTO_AH)));
1293 }
1294
1295 /* ARGSUSED */
1296 static int
set_tun_ah_alg(char * addr,int64_t param)1297 set_tun_ah_alg(char *addr, int64_t param)
1298 {
1299 return (set_tun_algs(AH_AUTH_ALG,
1300 parsealg(addr, IPSEC_PROTO_AH)));
1301 }
1302
1303 /* ARGSUSED */
1304 static int
setifrevarp(char * arg,int64_t param)1305 setifrevarp(char *arg, int64_t param)
1306 {
1307 struct sockaddr_in laddr;
1308
1309 if (afp->af_af == AF_INET6) {
1310 (void) fprintf(stderr,
1311 "ifconfig: revarp not possible on IPv6 interface %s\n",
1312 name);
1313 exit(1);
1314 }
1315 if (doifrevarp(name, &laddr)) {
1316 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1317 laddr.sin_family = AF_INET;
1318 (void) memcpy(&lifr.lifr_addr, &laddr, sizeof (laddr));
1319 if (ioctl(s, SIOCSLIFADDR, (caddr_t)&lifr) < 0)
1320 Perror0_exit("SIOCSLIFADDR");
1321 }
1322 return (0);
1323 }
1324
1325 /* ARGSUSED */
1326 static int
setifsubnet(char * addr,int64_t param)1327 setifsubnet(char *addr, int64_t param)
1328 {
1329 int prefixlen = 0;
1330 struct sockaddr_storage subnet;
1331
1332 (*afp->af_getaddr)(addr, &subnet, &prefixlen);
1333
1334 switch (prefixlen) {
1335 case NO_PREFIX:
1336 (void) fprintf(stderr,
1337 "ifconfig: Missing prefix length in subnet %s\n", addr);
1338 exit(1);
1339 /* NOTREACHED */
1340 case BAD_ADDR:
1341 (void) fprintf(stderr,
1342 "ifconfig: Bad prefix length in %s\n", addr);
1343 exit(1);
1344 default:
1345 break;
1346 }
1347
1348 lifr.lifr_addr = subnet;
1349 lifr.lifr_addrlen = prefixlen;
1350 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1351 if (ioctl(s, SIOCSLIFSUBNET, (caddr_t)&lifr) < 0)
1352 Perror0_exit("SIOCSLIFSUBNET");
1353
1354 return (0);
1355 }
1356
1357 /* ARGSUSED */
1358 static int
setifnetmask(char * addr,int64_t param)1359 setifnetmask(char *addr, int64_t param)
1360 {
1361 struct sockaddr_in netmask;
1362
1363 assert(afp->af_af != AF_INET6);
1364
1365 if (strcmp(addr, "+") == 0) {
1366 if (!in_getmask(&netmask, _B_FALSE))
1367 return (0);
1368 (void) printf("Setting netmask of %s to %s\n", name,
1369 inet_ntoa(netmask.sin_addr));
1370 } else {
1371 in_getaddr(addr, (struct sockaddr *)&netmask, NULL);
1372 }
1373 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1374 (void) memcpy(&lifr.lifr_addr, &netmask, sizeof (netmask));
1375 if (ioctl(s, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0)
1376 Perror0_exit("SIOCSLIFNETMASK");
1377 return (0);
1378 }
1379
1380 /*
1381 * Parse '/<n>' as a netmask.
1382 */
1383 /* ARGSUSED */
1384 static int
setifprefixlen(char * addr,int64_t param)1385 setifprefixlen(char *addr, int64_t param)
1386 {
1387 int prefixlen;
1388 int af = afp->af_af;
1389
1390 prefixlen = in_getprefixlen(addr, _B_TRUE,
1391 (af == AF_INET) ? IP_ABITS : IPV6_ABITS);
1392 if (prefixlen < 0) {
1393 (void) fprintf(stderr,
1394 "ifconfig: Bad prefix length in %s\n", addr);
1395 exit(1);
1396 }
1397 (void) memset(&lifr.lifr_addr, 0, sizeof (lifr.lifr_addr));
1398 lifr.lifr_addr.ss_family = af;
1399 if (af == AF_INET6) {
1400 struct sockaddr_in6 *sin6;
1401
1402 sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr;
1403 if (!in_prefixlentomask(prefixlen, IPV6_ABITS,
1404 (uchar_t *)&sin6->sin6_addr)) {
1405 (void) fprintf(stderr, "ifconfig: "
1406 "Bad prefix length: %d\n",
1407 prefixlen);
1408 exit(1);
1409 }
1410 } else if (af == AF_INET) {
1411 struct sockaddr_in *sin;
1412
1413 sin = (struct sockaddr_in *)&lifr.lifr_addr;
1414 if (!in_prefixlentomask(prefixlen, IP_ABITS,
1415 (uchar_t *)&sin->sin_addr)) {
1416 (void) fprintf(stderr, "ifconfig: "
1417 "Bad prefix length: %d\n",
1418 prefixlen);
1419 exit(1);
1420 }
1421 } else {
1422 (void) fprintf(stderr, "ifconfig: setting prefix only supported"
1423 " for address family inet or inet6\n");
1424 exit(1);
1425 }
1426 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1427 if (ioctl(s, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0)
1428 Perror0_exit("SIOCSLIFNETMASK");
1429 return (0);
1430 }
1431
1432 /* ARGSUSED */
1433 static int
setifbroadaddr(char * addr,int64_t param)1434 setifbroadaddr(char *addr, int64_t param)
1435 {
1436 struct sockaddr_in broadaddr;
1437
1438 assert(afp->af_af != AF_INET6);
1439
1440 if (strcmp(addr, "+") == 0) {
1441 /*
1442 * This doesn't set the broadcast address at all. Rather, it
1443 * gets, then sets the interface's address, relying on the fact
1444 * that resetting the address will reset the broadcast address.
1445 */
1446 (void) strncpy(lifr.lifr_name, name,
1447 sizeof (lifr.lifr_name));
1448 if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) < 0) {
1449 if (errno != EADDRNOTAVAIL)
1450 Perror0_exit("SIOCGLIFADDR");
1451 return (0);
1452 }
1453 if (ioctl(s, SIOCSLIFADDR, (caddr_t)&lifr) < 0)
1454 Perror0_exit("SIOCGLIFADDR");
1455
1456 return (0);
1457 }
1458 in_getaddr(addr, (struct sockaddr *)&broadaddr, NULL);
1459
1460 (void) memcpy(&lifr.lifr_addr, &broadaddr, sizeof (broadaddr));
1461 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1462 if (ioctl(s, SIOCSLIFBRDADDR, (caddr_t)&lifr) < 0)
1463 Perror0_exit("SIOCSLIFBRDADDR");
1464 return (0);
1465 }
1466
1467 /*
1468 * set interface destination address
1469 */
1470 /* ARGSUSED */
1471 static int
setifdstaddr(char * addr,int64_t param)1472 setifdstaddr(char *addr, int64_t param)
1473 {
1474 (*afp->af_getaddr)(addr, (struct sockaddr *)&lifr.lifr_addr, NULL);
1475 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1476 if (ioctl(s, SIOCSLIFDSTADDR, (caddr_t)&lifr) < 0)
1477 Perror0_exit("setifdstaddr: SIOCSLIFDSTADDR");
1478 return (0);
1479 }
1480
1481 /* ARGSUSED */
1482 static int
setifflags(char * val,int64_t value)1483 setifflags(char *val, int64_t value)
1484 {
1485 struct lifreq lifrl; /* local lifreq struct */
1486 boolean_t bringup = _B_FALSE;
1487
1488 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1489 if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0)
1490 Perror0_exit("setifflags: SIOCGLIFFLAGS");
1491
1492 if (value < 0) {
1493 value = -value;
1494
1495 if ((value & IFF_NOFAILOVER) && (lifr.lifr_flags & IFF_UP)) {
1496 /*
1497 * The kernel does not allow administratively up test
1498 * addresses to be converted to data addresses. Bring
1499 * the address down first, then bring it up after it's
1500 * been converted to a data address.
1501 */
1502 lifr.lifr_flags &= ~IFF_UP;
1503 (void) ioctl(s, SIOCSLIFFLAGS, (caddr_t)&lifr);
1504 bringup = _B_TRUE;
1505 }
1506
1507 lifr.lifr_flags &= ~value;
1508 if ((value & (IFF_UP | IFF_NOFAILOVER)) &&
1509 (lifr.lifr_flags & IFF_DUPLICATE)) {
1510 /*
1511 * If the user is trying to mark an interface with a
1512 * duplicate address as "down," or convert a duplicate
1513 * test address to a data address, then fetch the
1514 * address and set it. This will cause IP to clear
1515 * the IFF_DUPLICATE flag and stop the automatic
1516 * recovery timer.
1517 */
1518 value = lifr.lifr_flags;
1519 if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) >= 0)
1520 (void) ioctl(s, SIOCSLIFADDR, (caddr_t)&lifr);
1521 lifr.lifr_flags = value;
1522 }
1523 } else {
1524 lifr.lifr_flags |= value;
1525 }
1526
1527 /*
1528 * If we're about to bring up an underlying physical IPv6 interface in
1529 * an IPMP group, ensure the IPv6 IPMP interface is also up. This is
1530 * for backward compatibility with legacy configurations in which
1531 * there are no explicit hostname files for IPMP interfaces. (For
1532 * IPv4, this is automatically handled by the kernel when migrating
1533 * the underlying interface's data address to the IPMP interface.)
1534 */
1535 (void) strlcpy(lifrl.lifr_name, name, LIFNAMSIZ);
1536
1537 if (lifnum(lifr.lifr_name) == 0 &&
1538 (lifr.lifr_flags & (IFF_UP|IFF_IPV6)) == (IFF_UP|IFF_IPV6) &&
1539 ioctl(s, SIOCGLIFGROUPNAME, &lifrl) == 0 &&
1540 lifrl.lifr_groupname[0] != '\0') {
1541 lifgroupinfo_t lifgr;
1542
1543 (void) strlcpy(lifgr.gi_grname, lifrl.lifr_groupname,
1544 LIFGRNAMSIZ);
1545 if (ioctl(s, SIOCGLIFGROUPINFO, &lifgr) == -1)
1546 Perror0_exit("setifflags: SIOCGLIFGROUPINFO");
1547
1548 (void) strlcpy(lifrl.lifr_name, lifgr.gi_grifname, LIFNAMSIZ);
1549 if (ioctl(s, SIOCGLIFFLAGS, &lifrl) == -1)
1550 Perror0_exit("setifflags: SIOCGLIFFLAGS");
1551 if (!(lifrl.lifr_flags & IFF_UP)) {
1552 lifrl.lifr_flags |= IFF_UP;
1553 if (ioctl(s, SIOCSLIFFLAGS, &lifrl) == -1)
1554 Perror0_exit("setifflags: SIOCSLIFFLAGS");
1555 }
1556 }
1557
1558 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1559 if (ioctl(s, SIOCSLIFFLAGS, (caddr_t)&lifr) < 0)
1560 Perror0_exit("setifflags: SIOCSLIFFLAGS");
1561
1562 if (bringup) {
1563 lifr.lifr_flags |= IFF_UP;
1564 if (ioctl(s, SIOCSLIFFLAGS, (caddr_t)&lifr) < 0)
1565 Perror0_exit("setifflags: SIOCSLIFFLAGS IFF_UP");
1566 }
1567
1568 return (0);
1569 }
1570
1571 /* ARGSUSED */
1572 static int
setifmetric(char * val,int64_t param)1573 setifmetric(char *val, int64_t param)
1574 {
1575 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1576 lifr.lifr_metric = atoi(val);
1577 if (ioctl(s, SIOCSLIFMETRIC, (caddr_t)&lifr) < 0)
1578 Perror0_exit("setifmetric: SIOCSLIFMETRIC");
1579 return (0);
1580 }
1581
1582 /* ARGSUSED */
1583 static int
setifmtu(char * val,int64_t param)1584 setifmtu(char *val, int64_t param)
1585 {
1586 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1587 lifr.lifr_mtu = atoi(val);
1588 if (ioctl(s, SIOCSLIFMTU, (caddr_t)&lifr) < 0)
1589 Perror0_exit("setifmtu: SIOCSLIFMTU");
1590 return (0);
1591 }
1592
1593 /* ARGSUSED */
1594 static int
setifindex(char * val,int64_t param)1595 setifindex(char *val, int64_t param)
1596 {
1597 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1598 lifr.lifr_index = atoi(val);
1599 if (ioctl(s, SIOCSLIFINDEX, (caddr_t)&lifr) < 0)
1600 Perror0_exit("setifindex: SIOCSLIFINDEX");
1601 return (0);
1602 }
1603
1604 /* ARGSUSED */
1605 static void
notifycb(dlpi_handle_t dh,dlpi_notifyinfo_t * dnip,void * arg)1606 notifycb(dlpi_handle_t dh, dlpi_notifyinfo_t *dnip, void *arg)
1607 {
1608 }
1609
1610 /* ARGSUSED */
1611 static int
setifether(char * addr,int64_t param)1612 setifether(char *addr, int64_t param)
1613 {
1614 uchar_t *hwaddr;
1615 int hwaddrlen;
1616 int retval;
1617 ifaddrlistx_t *ifaddrp, *ifaddrs = NULL;
1618 dlpi_handle_t dh;
1619 dlpi_notifyid_t id;
1620
1621 if (addr == NULL) {
1622 ifstatus(name);
1623 print_ifether(name);
1624 return (0);
1625 }
1626
1627 /*
1628 * if the IP interface in the arguments is a logical
1629 * interface, exit with an error now.
1630 */
1631 if (strchr(name, ':') != NULL) {
1632 (void) fprintf(stderr, "ifconfig: cannot change"
1633 " ethernet address of a logical interface\n");
1634 exit(1);
1635 }
1636
1637 if ((hwaddr = _link_aton(addr, &hwaddrlen)) == NULL) {
1638 if (hwaddrlen == -1)
1639 (void) fprintf(stderr,
1640 "ifconfig: bad ethernet address\n");
1641 else
1642 (void) fprintf(stderr, "ifconfig: malloc() failed\n");
1643 exit(1);
1644 }
1645
1646 if ((retval = dlpi_open(name, &dh, 0)) != DLPI_SUCCESS)
1647 Perrdlpi_exit("cannot dlpi_open() link", name, retval);
1648
1649 retval = dlpi_enabnotify(dh, DL_NOTE_PHYS_ADDR, notifycb, NULL, &id);
1650 if (retval == DLPI_SUCCESS) {
1651 (void) dlpi_disabnotify(dh, id, NULL);
1652 } else {
1653 /*
1654 * This link does not support DL_NOTE_PHYS_ADDR: bring down
1655 * all of the addresses to flush the old hardware address
1656 * information out of IP.
1657 *
1658 * NOTE: Skipping this when DL_NOTE_PHYS_ADDR is supported is
1659 * more than an optimization: in.mpathd will set IFF_OFFLINE
1660 * if it's notified and the new address is a duplicate of
1661 * another in the group -- but the flags manipulation in
1662 * ifaddr_{down,up}() cannot be atomic and thus might clobber
1663 * IFF_OFFLINE, confusing in.mpathd.
1664 */
1665 if (ifaddrlistx(name, IFF_UP, 0, &ifaddrs) == -1)
1666 Perror2_exit(name, "cannot get address list");
1667
1668 ifaddrp = ifaddrs;
1669 for (; ifaddrp != NULL; ifaddrp = ifaddrp->ia_next) {
1670 if (!ifaddr_down(ifaddrp)) {
1671 Perror2_exit(ifaddrp->ia_name,
1672 "cannot bring down");
1673 }
1674 }
1675 }
1676
1677 /*
1678 * Change the hardware address.
1679 */
1680 retval = dlpi_set_physaddr(dh, DL_CURR_PHYS_ADDR, hwaddr, hwaddrlen);
1681 if (retval != DLPI_SUCCESS) {
1682 (void) fprintf(stderr,
1683 "ifconfig: failed setting mac address on %s\n", name);
1684 }
1685 dlpi_close(dh);
1686
1687 /*
1688 * If any addresses were brought down before changing the hardware
1689 * address, bring them up again.
1690 */
1691 for (ifaddrp = ifaddrs; ifaddrp != NULL; ifaddrp = ifaddrp->ia_next) {
1692 if (!ifaddr_up(ifaddrp))
1693 Perror2_exit(ifaddrp->ia_name, "cannot bring up");
1694 }
1695 ifaddrlistx_free(ifaddrs);
1696
1697 return (0);
1698 }
1699
1700 /*
1701 * Print an interface's Ethernet address, if it has one.
1702 */
1703 static void
print_ifether(const char * ifname)1704 print_ifether(const char *ifname)
1705 {
1706 int fd;
1707
1708 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1709
1710 fd = socket(AF_INET, SOCK_DGRAM, 0);
1711 if (fd == -1 || ioctl(fd, SIOCGLIFFLAGS, &lifr) == -1) {
1712 /*
1713 * It's possible the interface is only configured for
1714 * IPv6; check again with AF_INET6.
1715 */
1716 (void) close(fd);
1717 fd = socket(AF_INET6, SOCK_DGRAM, 0);
1718 if (fd == -1 || ioctl(fd, SIOCGLIFFLAGS, &lifr) == -1) {
1719 (void) close(fd);
1720 return;
1721 }
1722 }
1723 (void) close(fd);
1724
1725 /* VNI and IPMP interfaces don't have MAC addresses */
1726 if (lifr.lifr_flags & (IFF_VIRTUAL|IFF_IPMP))
1727 return;
1728
1729 /* IP tunnels also don't have Ethernet-like MAC addresses */
1730 if (ifconfig_dladm_open(ifname, DATALINK_CLASS_IPTUN, NULL) ==
1731 DLADM_STATUS_OK)
1732 return;
1733
1734 dlpi_print_address(ifname);
1735 }
1736
1737 /*
1738 * static int find_all_interfaces(struct lifconf *lifcp, char **buf,
1739 * int64_t lifc_flags)
1740 *
1741 * It finds all active data links.
1742 *
1743 * It takes in input a pointer to struct lifconf to receive interfaces
1744 * informations, a **char to hold allocated buffer, and a lifc_flags.
1745 *
1746 * Return values:
1747 * 0 = everything OK
1748 * -1 = problem
1749 */
1750 static int
find_all_interfaces(struct lifconf * lifcp,char ** buf,int64_t lifc_flags)1751 find_all_interfaces(struct lifconf *lifcp, char **buf, int64_t lifc_flags)
1752 {
1753 unsigned bufsize;
1754 int n;
1755 ni_t *nip;
1756 struct lifreq *lifrp;
1757 dladm_status_t status;
1758
1759 if (!dlh_opened) {
1760 status = ifconfig_dladm_open(NULL, 0, NULL);
1761 if (status != DLADM_STATUS_OK)
1762 dladmerr_exit(status, "unable to open dladm handle");
1763 }
1764
1765 (void) dlpi_walk(ni_entry, dlh, 0);
1766
1767 /* Now, translate the linked list into a struct lifreq buffer */
1768 if (num_ni == 0) {
1769 lifcp->lifc_family = AF_UNSPEC;
1770 lifcp->lifc_flags = lifc_flags;
1771 lifcp->lifc_len = 0;
1772 lifcp->lifc_buf = NULL;
1773 return (0);
1774 }
1775
1776 bufsize = num_ni * sizeof (struct lifreq);
1777 if ((*buf = malloc(bufsize)) == NULL)
1778 Perror0_exit("find_all_interfaces: malloc failed");
1779
1780 lifcp->lifc_family = AF_UNSPEC;
1781 lifcp->lifc_flags = lifc_flags;
1782 lifcp->lifc_len = bufsize;
1783 lifcp->lifc_buf = *buf;
1784
1785 for (n = 0, lifrp = lifcp->lifc_req; n < num_ni; n++, lifrp++) {
1786 nip = ni_list;
1787 (void) strncpy(lifrp->lifr_name, nip->ni_name,
1788 sizeof (lifr.lifr_name));
1789 ni_list = nip->ni_next;
1790 free(nip);
1791 }
1792 return (0);
1793 }
1794
1795 /*
1796 * Create the next unused logical interface using the original name
1797 * and assign the address (and mask if '/<n>' is part of the address).
1798 * Use the new logical interface for subsequent subcommands by updating
1799 * the name variable.
1800 *
1801 * This allows syntax like:
1802 * ifconfig le0 addif 109.106.86.130 netmask + up \
1803 * addif 109.106.86.131 netmask + up
1804 */
1805 /* ARGSUSED */
1806 static int
addif(char * str,int64_t param)1807 addif(char *str, int64_t param)
1808 {
1809 int prefixlen = 0;
1810 struct sockaddr_storage laddr;
1811 struct sockaddr_storage mask;
1812 struct sockaddr_in6 *sin6;
1813 struct sockaddr_in *sin;
1814 ipadm_status_t istatus;
1815 char cidraddr[BUFSIZ];
1816 char addrstr[INET6_ADDRSTRLEN];
1817
1818 (void) strncpy(name, origname, sizeof (name));
1819
1820 if (strchr(name, ':') != NULL) {
1821 (void) fprintf(stderr,
1822 "ifconfig: addif: bad physical interface name %s\n",
1823 name);
1824 exit(1);
1825 }
1826
1827 /*
1828 * clear so parser will interpret next address as source followed
1829 * by possible dest
1830 */
1831 setaddr = 0;
1832 (*afp->af_getaddr)(str, (struct sockaddr *)&laddr, &prefixlen);
1833
1834 switch (prefixlen) {
1835 case NO_PREFIX:
1836 /* Nothing there - ok */
1837 break;
1838 case BAD_ADDR:
1839 (void) fprintf(stderr,
1840 "ifconfig: Bad prefix length in %s\n", str);
1841 exit(1);
1842 default:
1843 (void) memset(&mask, 0, sizeof (mask));
1844 mask.ss_family = afp->af_af;
1845 if (afp->af_af == AF_INET6) {
1846 sin6 = (struct sockaddr_in6 *)&mask;
1847 if (!in_prefixlentomask(prefixlen, IPV6_ABITS,
1848 (uchar_t *)&sin6->sin6_addr)) {
1849 (void) fprintf(stderr, "ifconfig: "
1850 "Bad prefix length: %d\n",
1851 prefixlen);
1852 exit(1);
1853 }
1854 } else {
1855 sin = (struct sockaddr_in *)&mask;
1856 if (!in_prefixlentomask(prefixlen, IP_ABITS,
1857 (uchar_t *)&sin->sin_addr)) {
1858 (void) fprintf(stderr, "ifconfig: "
1859 "Bad prefix length: %d\n",
1860 prefixlen);
1861 exit(1);
1862 }
1863 }
1864 g_netmask_set = G_NETMASK_NIL;
1865 break;
1866 }
1867
1868 /*
1869 * This is a "hack" to get around the problem of SIOCLIFADDIF. The
1870 * problem is that this ioctl does not include the netmask when
1871 * adding a logical interface. This is the same problem described
1872 * in the ifconfig() comments. To get around this problem, we first
1873 * add the logical interface with a 0 address. After that, we set
1874 * the netmask if provided. Finally we set the interface address.
1875 */
1876 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1877 (void) memset(&lifr.lifr_addr, 0, sizeof (lifr.lifr_addr));
1878
1879 /* Note: no need to do DAD here since the interface isn't up yet. */
1880
1881 if (ioctl(s, SIOCLIFADDIF, (caddr_t)&lifr) < 0)
1882 Perror0_exit("addif: SIOCLIFADDIF");
1883
1884 (void) printf("Created new logical interface %s\n",
1885 lifr.lifr_name);
1886 (void) strncpy(name, lifr.lifr_name, sizeof (name));
1887
1888 /*
1889 * Check and see if any "netmask" command is used and perform the
1890 * necessary operation.
1891 */
1892 set_mask_lifreq(&lifr, &laddr, &mask);
1893
1894 /* This check is temporary until libipadm supports IPMP interfaces. */
1895 if (ifconfig_use_libipadm(s, name)) {
1896 /*
1897 * We added the logical interface above before calling
1898 * ipadm_create_addr(), because, with IPH_LEGACY, we need
1899 * to do an addif for `ifconfig ce0 addif <addr>' but not for
1900 * `ifconfig ce0 <addr>'. libipadm does not have a flag to
1901 * to differentiate between these two cases. To keep it simple,
1902 * we always create the logical interface and pass it to
1903 * libipadm instead of requiring libipadm to addif for some
1904 * cases and not do addif for other cases.
1905 */
1906 istatus = ipadm_create_addrobj(IPADM_ADDR_STATIC, name,
1907 &ipaddr);
1908 if (istatus != IPADM_SUCCESS)
1909 ipadmerr_exit(istatus, "addif");
1910
1911 if (af == AF_INET) {
1912 sin = (struct sockaddr_in *)&laddr;
1913 (void) inet_ntop(AF_INET, &sin->sin_addr, addrstr,
1914 sizeof (addrstr));
1915 } else {
1916 sin6 = (struct sockaddr_in6 *)&laddr;
1917 (void) inet_ntop(AF_INET6, &sin6->sin6_addr, addrstr,
1918 sizeof (addrstr));
1919 }
1920 /*
1921 * lifr.lifr_addr, which is updated by set_mask_lifreq()
1922 * will contain the right mask to use.
1923 */
1924 prefixlen = mask2plen((struct sockaddr *)&lifr.lifr_addr);
1925
1926 (void) snprintf(cidraddr, sizeof (cidraddr), "%s/%d",
1927 addrstr, prefixlen);
1928
1929 istatus = ipadm_set_addr(ipaddr, cidraddr, af);
1930
1931 if (istatus != IPADM_SUCCESS)
1932 ipadmerr_exit(istatus, "could not set address");
1933 setaddr++;
1934 /*
1935 * address will be set by the parser after nextarg
1936 * has been scanned
1937 */
1938 return (0);
1939 }
1940
1941 /*
1942 * Only set the netmask if "netmask" command is used or a prefix is
1943 * provided.
1944 */
1945 if (g_netmask_set == G_NETMASK_SET || prefixlen >= 0) {
1946 /*
1947 * lifr.lifr_addr already contains netmask from
1948 * set_mask_lifreq().
1949 */
1950 if (ioctl(s, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0)
1951 Perror0_exit("addif: SIOCSLIFNETMASK");
1952 }
1953
1954 /* Finally, we set the interface address. */
1955 lifr.lifr_addr = laddr;
1956 if (ioctl(s, SIOCSLIFADDR, (caddr_t)&lifr) < 0)
1957 Perror0_exit("SIOCSLIFADDR");
1958
1959 /*
1960 * let parser know we got a source.
1961 * Next address, if given, should be dest
1962 */
1963 setaddr++;
1964 return (0);
1965 }
1966
1967 /*
1968 * Remove a logical interface based on its IP address. Unlike addif
1969 * there is no '/<n>' here.
1970 * Verifies that the interface is down before it is removed.
1971 */
1972 /* ARGSUSED */
1973 static int
removeif(char * str,int64_t param)1974 removeif(char *str, int64_t param)
1975 {
1976 struct sockaddr_storage laddr;
1977 ipadm_status_t istatus;
1978 ipadm_addr_info_t *ainfo, *ainfop;
1979
1980 if (strchr(name, ':') != NULL) {
1981 (void) fprintf(stderr,
1982 "ifconfig: removeif: bad physical interface name %s\n",
1983 name);
1984 exit(1);
1985 }
1986
1987 (*afp->af_getaddr)(str, &laddr, NULL);
1988
1989 /*
1990 * Following check is temporary until libipadm supports
1991 * IPMP interfaces.
1992 */
1993 if (!ifconfig_use_libipadm(s, name))
1994 goto delete;
1995
1996 /*
1997 * Get all addresses and search this address among the active
1998 * addresses. If an address object was found, delete using
1999 * ipadm_delete_addr().
2000 */
2001 istatus = ipadm_addr_info(iph, name, &ainfo, 0, LIFC_DEFAULT);
2002 if (istatus != IPADM_SUCCESS)
2003 ipadmerr_exit(istatus, "removeif");
2004
2005 for (ainfop = ainfo; ainfop != NULL; ainfop = IA_NEXT(ainfop))
2006 if (sockaddrcmp(
2007 (struct sockaddr_storage *)ainfop->ia_ifa.ifa_addr, &laddr))
2008 break;
2009
2010 if (ainfop != NULL) {
2011 if (strchr(ainfop->ia_ifa.ifa_name, ':') == NULL) {
2012 (void) fprintf(stderr,
2013 "ifconfig: removeif: cannot remove interface: %s\n",
2014 name);
2015 exit(1);
2016 }
2017 if (ainfop->ia_aobjname[0] != '\0') {
2018 istatus = ipadm_delete_addr(iph, ainfop->ia_aobjname,
2019 IPADM_OPT_ACTIVE);
2020 if (istatus != IPADM_SUCCESS) {
2021 ipadmerr_exit(istatus,
2022 "could not delete address");
2023 }
2024 ipadm_free_addr_info(ainfo);
2025 return (0);
2026 }
2027 }
2028 ipadm_free_addr_info(ainfo);
2029
2030 delete:
2031 /*
2032 * An address object for this address was not found in ipadm.
2033 * Delete with SIOCLIFREMOVEIF.
2034 */
2035 lifr.lifr_addr = laddr;
2036 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
2037 if (ioctl(s, SIOCLIFREMOVEIF, (caddr_t)&lifr) < 0) {
2038 if (errno == EBUSY) {
2039 /* This can only happen if ipif_id = 0 */
2040 (void) fprintf(stderr,
2041 "ifconfig: removeif: cannot remove interface: %s\n",
2042 name);
2043 exit(1);
2044 }
2045 Perror0_exit("removeif: SIOCLIFREMOVEIF");
2046 }
2047 return (0);
2048 }
2049
2050 /*
2051 * Set the address token for IPv6.
2052 */
2053 /* ARGSUSED */
2054 static int
setiftoken(char * addr,int64_t param)2055 setiftoken(char *addr, int64_t param)
2056 {
2057 int prefixlen = 0;
2058 struct sockaddr_in6 token;
2059
2060 in6_getaddr(addr, (struct sockaddr *)&token, &prefixlen);
2061 switch (prefixlen) {
2062 case NO_PREFIX:
2063 (void) fprintf(stderr,
2064 "ifconfig: Missing prefix length in subnet %s\n", addr);
2065 exit(1);
2066 /* NOTREACHED */
2067 case BAD_ADDR:
2068 (void) fprintf(stderr,
2069 "ifconfig: Bad prefix length in %s\n", addr);
2070 exit(1);
2071 default:
2072 break;
2073 }
2074 (void) memcpy(&lifr.lifr_addr, &token, sizeof (token));
2075 lifr.lifr_addrlen = prefixlen;
2076 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
2077 if (ioctl(s, SIOCSLIFTOKEN, (caddr_t)&lifr) < 0) {
2078 Perror0_exit("setiftoken: SIOCSLIFTOKEN");
2079 }
2080 return (0);
2081 }
2082
2083 /* ARGSUSED */
2084 static int
setifgroupname(char * grname,int64_t param)2085 setifgroupname(char *grname, int64_t param)
2086 {
2087 lifgroupinfo_t lifgr;
2088 struct lifreq lifrl;
2089 ifaddrlistx_t *ifaddrp, *nextifaddrp;
2090 ifaddrlistx_t *ifaddrs = NULL, *downaddrs = NULL;
2091 int af;
2092
2093 if (debug) {
2094 (void) printf("Setting groupname %s on interface %s\n",
2095 grname, name);
2096 }
2097
2098 (void) strlcpy(lifrl.lifr_name, name, LIFNAMSIZ);
2099 (void) strlcpy(lifrl.lifr_groupname, grname, LIFGRNAMSIZ);
2100
2101 while (ioctl(s, SIOCSLIFGROUPNAME, &lifrl) == -1) {
2102 switch (errno) {
2103 case ENOENT:
2104 /*
2105 * The group doesn't yet exist; create it and repeat.
2106 */
2107 af = afp->af_af;
2108 if (create_ipmp(grname, af, NULL, _B_TRUE) == -1) {
2109 if (errno == EEXIST)
2110 continue;
2111
2112 Perror2(grname, "cannot create IPMP group");
2113 goto fail;
2114 }
2115 continue;
2116
2117 case EALREADY:
2118 /*
2119 * The interface is already in another group; must
2120 * remove existing membership first.
2121 */
2122 lifrl.lifr_groupname[0] = '\0';
2123 if (ioctl(s, SIOCSLIFGROUPNAME, &lifrl) == -1) {
2124 Perror2(name, "cannot remove existing "
2125 "IPMP group membership");
2126 goto fail;
2127 }
2128 (void) strlcpy(lifrl.lifr_groupname, grname,
2129 LIFGRNAMSIZ);
2130 continue;
2131
2132 case EAFNOSUPPORT:
2133 /*
2134 * The group exists, but it's not configured with the
2135 * address families the interface needs. Since only
2136 * two address families are currently supported, just
2137 * configure the "other" address family. Note that we
2138 * may race with group deletion or creation by another
2139 * process (ENOENT or EEXIST); in such cases we repeat
2140 * our original SIOCSLIFGROUPNAME.
2141 */
2142 (void) strlcpy(lifgr.gi_grname, grname, LIFGRNAMSIZ);
2143 if (ioctl(s, SIOCGLIFGROUPINFO, &lifgr) == -1) {
2144 if (errno == ENOENT)
2145 continue;
2146
2147 Perror2(grname, "SIOCGLIFGROUPINFO");
2148 goto fail;
2149 }
2150
2151 af = lifgr.gi_v4 ? AF_INET6 : AF_INET;
2152 if (create_ipmp(grname, af, lifgr.gi_grifname,
2153 _B_TRUE) == -1) {
2154 if (errno == EEXIST)
2155 continue;
2156
2157 Perror2(grname, "cannot configure IPMP group");
2158 goto fail;
2159 }
2160 continue;
2161
2162 case EADDRINUSE:
2163 /*
2164 * Some addresses are in-use (or under control of DAD).
2165 * Bring them down and retry the group join operation.
2166 * We will bring them back up after the interface has
2167 * been placed in the group.
2168 */
2169 if (ifaddrlistx(lifrl.lifr_name, IFF_UP|IFF_DUPLICATE,
2170 0, &ifaddrs) == -1) {
2171 Perror2(grname, "cannot get address list");
2172 goto fail;
2173 }
2174
2175 ifaddrp = ifaddrs;
2176 for (; ifaddrp != NULL; ifaddrp = nextifaddrp) {
2177 if (!ifaddr_down(ifaddrp)) {
2178 ifaddrs = ifaddrp;
2179 goto fail;
2180 }
2181 nextifaddrp = ifaddrp->ia_next;
2182 ifaddrp->ia_next = downaddrs;
2183 downaddrs = ifaddrp;
2184 }
2185 ifaddrs = NULL;
2186 continue;
2187
2188 case EADDRNOTAVAIL: {
2189 /*
2190 * Some data addresses are under application control.
2191 * For some of these (e.g., ADDRCONF), the application
2192 * should remove the address, in which case we retry a
2193 * few times (since the application's action is not
2194 * atomic with respect to us) before bailing out and
2195 * informing the user.
2196 */
2197 int ntries, nappaddr = 0;
2198 const if_appflags_t *iap = if_appflags_tbl;
2199
2200 for (; iap->ia_app != NULL; iap++) {
2201 ntries = 0;
2202 again:
2203 if (ifaddrlistx(lifrl.lifr_name, iap->ia_flag,
2204 IFF_NOFAILOVER, &ifaddrs) == -1) {
2205 (void) fprintf(stderr, "ifconfig: %s: "
2206 "cannot get data addresses managed "
2207 "by %s\n", lifrl.lifr_name,
2208 iap->ia_app);
2209 goto fail;
2210 }
2211
2212 if (ifaddrs == NULL)
2213 continue;
2214
2215 ifaddrlistx_free(ifaddrs);
2216 ifaddrs = NULL;
2217
2218 if (++ntries < iap->ia_tries) {
2219 (void) poll(NULL, 0, 100);
2220 goto again;
2221 }
2222
2223 (void) fprintf(stderr, "ifconfig: cannot join "
2224 "IPMP group: %s has data addresses managed "
2225 "by %s\n", lifrl.lifr_name, iap->ia_app);
2226 nappaddr++;
2227 }
2228 if (nappaddr > 0)
2229 goto fail;
2230 continue;
2231 }
2232 default:
2233 Perror2(name, "SIOCSLIFGROUPNAME");
2234 goto fail;
2235 }
2236 }
2237
2238 /*
2239 * If the interface being moved is under the control of `ipmgmtd(1M)'
2240 * dameon then we should inform the daemon about this move, so that
2241 * the daemon can delete the state associated with this interface.
2242 *
2243 * This workaround is needed until the IPMP support in ipadm(1M).
2244 */
2245 ipadm_if_move(iph, name);
2246
2247 /*
2248 * If there were addresses that we had to bring down, it's time to
2249 * bring them up again. As part of bringing them up, the kernel will
2250 * automatically move them to the new IPMP interface.
2251 */
2252 for (ifaddrp = downaddrs; ifaddrp != NULL; ifaddrp = ifaddrp->ia_next) {
2253 if (!ifaddr_up(ifaddrp) && errno != ENXIO) {
2254 (void) fprintf(stderr, "ifconfig: cannot bring back up "
2255 "%s: %s\n", ifaddrp->ia_name, strerror(errno));
2256 }
2257 }
2258 ifaddrlistx_free(downaddrs);
2259 return (0);
2260 fail:
2261 /*
2262 * Attempt to bring back up any interfaces that we downed.
2263 */
2264 for (ifaddrp = downaddrs; ifaddrp != NULL; ifaddrp = ifaddrp->ia_next) {
2265 if (!ifaddr_up(ifaddrp) && errno != ENXIO) {
2266 (void) fprintf(stderr, "ifconfig: cannot bring back up "
2267 "%s: %s\n", ifaddrp->ia_name, strerror(errno));
2268 }
2269 }
2270 ifaddrlistx_free(downaddrs);
2271 ifaddrlistx_free(ifaddrs);
2272
2273 /*
2274 * We'd return -1, but foreachinterface() doesn't propagate the error
2275 * into the exit status, so we're forced to explicitly exit().
2276 */
2277 exit(1);
2278 /* NOTREACHED */
2279 }
2280
2281 static boolean_t
modcheck(const char * ifname)2282 modcheck(const char *ifname)
2283 {
2284 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
2285
2286 if (ioctl(s, SIOCGLIFFLAGS, &lifr) < 0) {
2287 Perror0("SIOCGLIFFLAGS");
2288 return (_B_FALSE);
2289 }
2290
2291 if (lifr.lifr_flags & IFF_IPMP) {
2292 (void) fprintf(stderr, "ifconfig: %s: module operations not"
2293 " supported on IPMP interfaces\n", ifname);
2294 return (_B_FALSE);
2295 }
2296 if (lifr.lifr_flags & IFF_VIRTUAL) {
2297 (void) fprintf(stderr, "ifconfig: %s: module operations not"
2298 " supported on virtual IP interfaces\n", ifname);
2299 return (_B_FALSE);
2300 }
2301 return (_B_TRUE);
2302 }
2303
2304 /*
2305 * To list all the modules above a given network interface.
2306 */
2307 /* ARGSUSED */
2308 static int
modlist(char * null,int64_t param)2309 modlist(char *null, int64_t param)
2310 {
2311 int muxid_fd;
2312 int muxfd;
2313 int ipfd_lowstr;
2314 int arpfd_lowstr;
2315 int num_mods;
2316 int i;
2317 struct str_list strlist;
2318 int orig_arpid;
2319
2320 /*
2321 * We'd return -1, but foreachinterface() doesn't propagate the error
2322 * into the exit status, so we're forced to explicitly exit().
2323 */
2324 if (!modcheck(name))
2325 exit(1);
2326
2327 if (ip_domux2fd(&muxfd, &muxid_fd, &ipfd_lowstr, &arpfd_lowstr,
2328 &orig_arpid) < 0) {
2329 return (-1);
2330 }
2331 if ((num_mods = ioctl(ipfd_lowstr, I_LIST, NULL)) < 0) {
2332 Perror0("cannot I_LIST to get the number of modules");
2333 } else {
2334 if (debug > 0) {
2335 (void) printf("Listing (%d) modules above %s\n",
2336 num_mods, name);
2337 }
2338
2339 strlist.sl_nmods = num_mods;
2340 strlist.sl_modlist = malloc(sizeof (struct str_mlist) *
2341 num_mods);
2342 if (strlist.sl_modlist == NULL) {
2343 Perror0("cannot malloc");
2344 } else {
2345 if (ioctl(ipfd_lowstr, I_LIST, (caddr_t)&strlist) < 0) {
2346 Perror0("cannot I_LIST for module names");
2347 } else {
2348 for (i = 0; i < strlist.sl_nmods; i++) {
2349 (void) printf("%d %s\n", i,
2350 strlist.sl_modlist[i].l_name);
2351 }
2352 }
2353 free(strlist.sl_modlist);
2354 }
2355 }
2356 return (ip_plink(muxfd, muxid_fd, ipfd_lowstr, arpfd_lowstr,
2357 orig_arpid));
2358 }
2359
2360 #define MODINSERT_OP 'i'
2361 #define MODREMOVE_OP 'r'
2362
2363 /*
2364 * To insert a module to the stream of the interface. It is just a
2365 * wrapper. The real function is modop().
2366 */
2367 /* ARGSUSED */
2368 static int
modinsert(char * arg,int64_t param)2369 modinsert(char *arg, int64_t param)
2370 {
2371 return (modop(arg, MODINSERT_OP));
2372 }
2373
2374 /*
2375 * To remove a module from the stream of the interface. It is just a
2376 * wrapper. The real function is modop().
2377 */
2378 /* ARGSUSED */
2379 static int
modremove(char * arg,int64_t param)2380 modremove(char *arg, int64_t param)
2381 {
2382 return (modop(arg, MODREMOVE_OP));
2383 }
2384
2385 /*
2386 * Helper function for mod*() functions. It gets a fd to the lower IP
2387 * stream and I_PUNLINK's the lower stream. It also initializes the
2388 * global variable lifr.
2389 *
2390 * Param:
2391 * int *muxfd: fd to /dev/udp{,6} for I_PLINK/I_PUNLINK
2392 * int *muxid_fd: fd to /dev/udp{,6} for LIFMUXID
2393 * int *ipfd_lowstr: fd to the lower IP stream.
2394 * int *arpfd_lowstr: fd to the lower ARP stream.
2395 *
2396 * Return:
2397 * -1 if operation fails, 0 otherwise.
2398 *
2399 * Please see the big block comment above ifplumb() for the logic of the
2400 * PLINK/PUNLINK
2401 */
2402 static int
ip_domux2fd(int * muxfd,int * muxid_fd,int * ipfd_lowstr,int * arpfd_lowstr,int * orig_arpid)2403 ip_domux2fd(int *muxfd, int *muxid_fd, int *ipfd_lowstr, int *arpfd_lowstr,
2404 int *orig_arpid)
2405 {
2406 uint64_t flags;
2407 char *udp_dev_name;
2408
2409 *orig_arpid = 0;
2410 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
2411 if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
2412 Perror0_exit("status: SIOCGLIFFLAGS");
2413 }
2414 flags = lifr.lifr_flags;
2415 if (flags & IFF_IPV4) {
2416 udp_dev_name = UDP_DEV_NAME;
2417 } else if (flags & IFF_IPV6) {
2418 udp_dev_name = UDP6_DEV_NAME;
2419 } else {
2420 return (-1);
2421 }
2422
2423 if ((*muxid_fd = open(udp_dev_name, O_RDWR)) < 0) {
2424 Perror2("open", udp_dev_name);
2425 return (-1);
2426 }
2427 if (ioctl(*muxid_fd, SIOCGLIFMUXID, (caddr_t)&lifr) < 0) {
2428 Perror2("SIOCGLIFMUXID", udp_dev_name);
2429 return (-1);
2430 }
2431 if (debug > 0) {
2432 (void) printf("ARP_muxid %d IP_muxid %d\n",
2433 lifr.lifr_arp_muxid, lifr.lifr_ip_muxid);
2434 }
2435
2436 /*
2437 * Use /dev/udp{,6} as the mux to avoid linkcycles.
2438 */
2439 if (ipadm_open_arp_on_udp(udp_dev_name, muxfd) != IPADM_SUCCESS)
2440 return (-1);
2441
2442 if (lifr.lifr_arp_muxid != 0) {
2443 if ((*arpfd_lowstr = ioctl(*muxfd, _I_MUXID2FD,
2444 lifr.lifr_arp_muxid)) < 0) {
2445 if ((errno == EINVAL) &&
2446 (flags & (IFF_NOARP | IFF_IPV6))) {
2447 /*
2448 * Some plumbing utilities set the muxid to
2449 * -1 or some invalid value to signify that
2450 * there is no arp stream. Set the muxid to 0
2451 * before trying to unplumb the IP stream.
2452 * IP does not allow the IP stream to be
2453 * unplumbed if it sees a non-null arp muxid,
2454 * for consistency of IP-ARP streams.
2455 */
2456 *orig_arpid = lifr.lifr_arp_muxid;
2457 lifr.lifr_arp_muxid = 0;
2458 (void) ioctl(*muxid_fd, SIOCSLIFMUXID,
2459 (caddr_t)&lifr);
2460 *arpfd_lowstr = -1;
2461 } else {
2462 Perror0("_I_MUXID2FD");
2463 return (-1);
2464 }
2465 } else if (ioctl(*muxfd, I_PUNLINK,
2466 lifr.lifr_arp_muxid) < 0) {
2467 Perror2("I_PUNLINK", udp_dev_name);
2468 return (-1);
2469 }
2470 } else {
2471 *arpfd_lowstr = -1;
2472 }
2473
2474 if ((*ipfd_lowstr = ioctl(*muxfd, _I_MUXID2FD,
2475 lifr.lifr_ip_muxid)) < 0) {
2476 Perror0("_I_MUXID2FD");
2477 /* Undo any changes we made */
2478 if (*orig_arpid != 0) {
2479 lifr.lifr_arp_muxid = *orig_arpid;
2480 (void) ioctl(*muxid_fd, SIOCSLIFMUXID, (caddr_t)&lifr);
2481 }
2482 return (-1);
2483 }
2484 if (ioctl(*muxfd, I_PUNLINK, lifr.lifr_ip_muxid) < 0) {
2485 Perror2("I_PUNLINK", udp_dev_name);
2486 /* Undo any changes we made */
2487 if (*orig_arpid != 0) {
2488 lifr.lifr_arp_muxid = *orig_arpid;
2489 (void) ioctl(*muxid_fd, SIOCSLIFMUXID, (caddr_t)&lifr);
2490 }
2491 return (-1);
2492 }
2493 return (0);
2494 }
2495
2496 /*
2497 * Helper function for mod*() functions. It I_PLINK's back the upper and
2498 * lower IP streams. Note that this function must be called after
2499 * ip_domux2fd(). In ip_domux2fd(), the global variable lifr is initialized
2500 * and ip_plink() needs information in lifr. So ip_domux2fd() and ip_plink()
2501 * must be called in pairs.
2502 *
2503 * Param:
2504 * int muxfd: fd to /dev/udp{,6} for I_PLINK/I_PUNLINK
2505 * int muxid_fd: fd to /dev/udp{,6} for LIFMUXID
2506 * int ipfd_lowstr: fd to the lower IP stream.
2507 * int arpfd_lowstr: fd to the lower ARP stream.
2508 *
2509 * Return:
2510 * -1 if operation fails, 0 otherwise.
2511 *
2512 * Please see the big block comment above ifplumb() for the logic of the
2513 * PLINK/PUNLINK
2514 */
2515 static int
ip_plink(int muxfd,int muxid_fd,int ipfd_lowstr,int arpfd_lowstr,int orig_arpid)2516 ip_plink(int muxfd, int muxid_fd, int ipfd_lowstr, int arpfd_lowstr,
2517 int orig_arpid)
2518 {
2519 int ip_muxid;
2520
2521 ip_muxid = ioctl(muxfd, I_PLINK, ipfd_lowstr);
2522 if (ip_muxid < 0) {
2523 Perror2("I_PLINK", UDP_DEV_NAME);
2524 return (-1);
2525 }
2526
2527 /*
2528 * If there is an arp stream, plink it. If there is no
2529 * arp stream, then it is possible that the plumbing
2530 * utility could have stored any value in the arp_muxid.
2531 * If so, restore it from orig_arpid.
2532 */
2533 if (arpfd_lowstr != -1) {
2534 if (ioctl(muxfd, I_PLINK, arpfd_lowstr) < 0) {
2535 Perror2("I_PLINK", UDP_DEV_NAME);
2536 return (-1);
2537 }
2538 } else if (orig_arpid != 0) {
2539 /* Undo the changes we did in ip_domux2fd */
2540 lifr.lifr_arp_muxid = orig_arpid;
2541 lifr.lifr_ip_muxid = ip_muxid;
2542 (void) ioctl(muxid_fd, SIOCSLIFMUXID, (caddr_t)&lifr);
2543 }
2544
2545 (void) close(muxfd);
2546 (void) close(muxid_fd);
2547 return (0);
2548 }
2549
2550 /*
2551 * The real function to perform module insertion/removal.
2552 *
2553 * Param:
2554 * char *arg: the argument string module_name@position
2555 * char op: operation, either MODINSERT_OP or MODREMOVE_OP.
2556 *
2557 * Return:
2558 * Before doing ip_domux2fd(), this function calls exit(1) in case of
2559 * error. After ip_domux2fd() is done, it returns -1 for error, 0
2560 * otherwise.
2561 */
2562 static int
modop(char * arg,char op)2563 modop(char *arg, char op)
2564 {
2565 char *pos_p;
2566 int muxfd;
2567 int muxid_fd;
2568 int ipfd_lowstr; /* IP stream (lower stream of mux) to be plinked */
2569 int arpfd_lowstr; /* ARP stream (lower stream of mux) to be plinked */
2570 struct strmodconf mod;
2571 char *at_char = "@";
2572 char *arg_str;
2573 int orig_arpid;
2574
2575 /*
2576 * We'd return -1, but foreachinterface() doesn't propagate the error
2577 * into the exit status, so we're forced to explicitly exit().
2578 */
2579 if (!modcheck(name))
2580 exit(1);
2581
2582 /* Need to save the original string for -a option. */
2583 if ((arg_str = malloc(strlen(arg) + 1)) == NULL) {
2584 Perror0("cannot malloc");
2585 return (-1);
2586 }
2587 (void) strcpy(arg_str, arg);
2588
2589 if (*arg_str == *at_char) {
2590 (void) fprintf(stderr,
2591 "ifconfig: must supply a module name\n");
2592 exit(1);
2593 }
2594 mod.mod_name = strtok(arg_str, at_char);
2595 if (strlen(mod.mod_name) > FMNAMESZ) {
2596 (void) fprintf(stderr, "ifconfig: module name too long: %s\n",
2597 mod.mod_name);
2598 exit(1);
2599 }
2600
2601 /*
2602 * Need to make sure that the core TCP/IP stack modules are not
2603 * removed. Otherwise, "bad" things can happen. If a module
2604 * is removed and inserted back, it loses its old state. But
2605 * the modules above it still have the old state. E.g. IP assumes
2606 * fast data path while tunnel after re-inserted assumes that it can
2607 * receive M_DATA only in fast data path for which it does not have
2608 * any state. This is a general caveat of _I_REMOVE/_I_INSERT.
2609 */
2610 if (op == MODREMOVE_OP &&
2611 (strcmp(mod.mod_name, ARP_MOD_NAME) == 0 ||
2612 strcmp(mod.mod_name, IP_MOD_NAME) == 0)) {
2613 (void) fprintf(stderr, "ifconfig: cannot remove %s\n",
2614 mod.mod_name);
2615 exit(1);
2616 }
2617
2618 if ((pos_p = strtok(NULL, at_char)) == NULL) {
2619 (void) fprintf(stderr, "ifconfig: must supply a position\n");
2620 exit(1);
2621 }
2622 mod.pos = atoi(pos_p);
2623
2624 if (ip_domux2fd(&muxfd, &muxid_fd, &ipfd_lowstr, &arpfd_lowstr,
2625 &orig_arpid) < 0) {
2626 free(arg_str);
2627 return (-1);
2628 }
2629 switch (op) {
2630 case MODINSERT_OP:
2631 if (debug > 0) {
2632 (void) printf("Inserting module %s at %d\n",
2633 mod.mod_name, mod.pos);
2634 }
2635 if (ioctl(ipfd_lowstr, _I_INSERT, (caddr_t)&mod) < 0) {
2636 Perror2("fail to insert module", mod.mod_name);
2637 }
2638 break;
2639 case MODREMOVE_OP:
2640 if (debug > 0) {
2641 (void) printf("Removing module %s at %d\n",
2642 mod.mod_name, mod.pos);
2643 }
2644 if (ioctl(ipfd_lowstr, _I_REMOVE, (caddr_t)&mod) < 0) {
2645 Perror2("fail to remove module", mod.mod_name);
2646 }
2647 break;
2648 default:
2649 /* Should never get to here. */
2650 (void) fprintf(stderr, "Unknown operation\n");
2651 break;
2652 }
2653 free(arg_str);
2654 return (ip_plink(muxfd, muxid_fd, ipfd_lowstr, arpfd_lowstr,
2655 orig_arpid));
2656 }
2657
2658 static int
modify_tun(iptun_params_t * params)2659 modify_tun(iptun_params_t *params)
2660 {
2661 dladm_status_t status;
2662
2663 if ((status = ifconfig_dladm_open(name, DATALINK_CLASS_IPTUN,
2664 ¶ms->iptun_param_linkid)) == DLADM_STATUS_OK)
2665 status = dladm_iptun_modify(dlh, params, DLADM_OPT_ACTIVE);
2666 if (status != DLADM_STATUS_OK)
2667 dladmerr_exit(status, name);
2668 return (0);
2669 }
2670
2671 /*
2672 * Set tunnel source address
2673 */
2674 /* ARGSUSED */
2675 static int
setiftsrc(char * addr,int64_t param)2676 setiftsrc(char *addr, int64_t param)
2677 {
2678 iptun_params_t params;
2679
2680 params.iptun_param_flags = IPTUN_PARAM_LADDR;
2681 (void) strlcpy(params.iptun_param_laddr, addr,
2682 sizeof (params.iptun_param_laddr));
2683 return (modify_tun(¶ms));
2684 }
2685
2686 /*
2687 * Set tunnel destination address
2688 */
2689 /* ARGSUSED */
2690 static int
setiftdst(char * addr,int64_t param)2691 setiftdst(char *addr, int64_t param)
2692 {
2693 iptun_params_t params;
2694
2695 params.iptun_param_flags = IPTUN_PARAM_RADDR;
2696 (void) strlcpy(params.iptun_param_raddr, addr,
2697 sizeof (params.iptun_param_raddr));
2698 return (modify_tun(¶ms));
2699 }
2700
2701 static int
set_tun_prop(const char * propname,char * value)2702 set_tun_prop(const char *propname, char *value)
2703 {
2704 dladm_status_t status;
2705 datalink_id_t linkid;
2706
2707 status = ifconfig_dladm_open(name, DATALINK_CLASS_IPTUN, &linkid);
2708 if (status == DLADM_STATUS_OK) {
2709 status = dladm_set_linkprop(dlh, linkid, propname, &value, 1,
2710 DLADM_OPT_ACTIVE);
2711 }
2712 if (status != DLADM_STATUS_OK)
2713 dladmerr_exit(status, name);
2714 return (0);
2715 }
2716
2717 /* Set tunnel encapsulation limit. */
2718 /* ARGSUSED */
2719 static int
set_tun_encap_limit(char * arg,int64_t param)2720 set_tun_encap_limit(char *arg, int64_t param)
2721 {
2722 return (set_tun_prop("encaplimit", arg));
2723 }
2724
2725 /* Disable encapsulation limit. */
2726 /* ARGSUSED */
2727 static int
clr_tun_encap_limit(char * arg,int64_t param)2728 clr_tun_encap_limit(char *arg, int64_t param)
2729 {
2730 return (set_tun_encap_limit("-1", 0));
2731 }
2732
2733 /* Set tunnel hop limit. */
2734 /* ARGSUSED */
2735 static int
set_tun_hop_limit(char * arg,int64_t param)2736 set_tun_hop_limit(char *arg, int64_t param)
2737 {
2738 return (set_tun_prop("hoplimit", arg));
2739 }
2740
2741 /* Set zone ID */
2742 static int
setzone(char * arg,int64_t param)2743 setzone(char *arg, int64_t param)
2744 {
2745 zoneid_t zoneid = GLOBAL_ZONEID;
2746
2747 if (param == NEXTARG) {
2748 /* zone must be active */
2749 if ((zoneid = getzoneidbyname(arg)) == -1) {
2750 (void) fprintf(stderr,
2751 "ifconfig: unknown zone '%s'\n", arg);
2752 exit(1);
2753 }
2754 }
2755 (void) strlcpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
2756 lifr.lifr_zoneid = zoneid;
2757 if (ioctl(s, SIOCSLIFZONE, (caddr_t)&lifr) == -1)
2758 Perror0_exit("SIOCSLIFZONE");
2759 return (0);
2760 }
2761
2762 /* Put interface into all zones */
2763 /* ARGSUSED */
2764 static int
setallzones(char * arg,int64_t param)2765 setallzones(char *arg, int64_t param)
2766 {
2767 (void) strlcpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
2768 lifr.lifr_zoneid = ALL_ZONES;
2769 if (ioctl(s, SIOCSLIFZONE, (caddr_t)&lifr) == -1)
2770 Perror0_exit("SIOCSLIFZONE");
2771 return (0);
2772 }
2773
2774 /* Set source address to use */
2775 /* ARGSUSED */
2776 static int
setifsrc(char * arg,int64_t param)2777 setifsrc(char *arg, int64_t param)
2778 {
2779 uint_t ifindex = 0;
2780 int rval;
2781
2782 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
2783
2784 /*
2785 * Argument can be either an interface name or "none". The latter means
2786 * that any previous selection is cleared.
2787 */
2788
2789 if (strchr(arg, ':') != NULL) {
2790 (void) fprintf(stderr,
2791 "ifconfig: Cannot specify logical interface for usesrc \n");
2792 exit(1);
2793 }
2794
2795 rval = strcmp(arg, NONE_STR);
2796 if (rval != 0) {
2797 if ((ifindex = if_nametoindex(arg)) == 0) {
2798 (void) strncpy(lifr.lifr_name, arg, LIFNAMSIZ);
2799 Perror0_exit("Could not get interface index");
2800 }
2801 lifr.lifr_index = ifindex;
2802 } else {
2803 if (ioctl(s, SIOCGLIFUSESRC, (caddr_t)&lifr) != 0)
2804 Perror0_exit("Not a valid usesrc consumer");
2805 lifr.lifr_index = 0;
2806 }
2807
2808 if (debug)
2809 (void) printf("setifsrc: lifr_name %s, lifr_index %d\n",
2810 lifr.lifr_name, lifr.lifr_index);
2811
2812 if (ioctl(s, SIOCSLIFUSESRC, (caddr_t)&lifr) == -1) {
2813 if (rval == 0)
2814 Perror0_exit("Cannot reset usesrc group");
2815 else
2816 Perror0_exit("Could not set source interface");
2817 }
2818
2819 return (0);
2820 }
2821
2822 /*
2823 * Print the interface status line associated with `ifname'
2824 */
2825 static void
ifstatus(const char * ifname)2826 ifstatus(const char *ifname)
2827 {
2828 uint64_t flags;
2829 char if_usesrc_name[LIFNAMSIZ];
2830 char *newbuf;
2831 int n, numifs, rval = 0;
2832 struct lifreq *lifrp;
2833 struct lifsrcof lifs;
2834
2835 (void) strncpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
2836 if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
2837 Perror0_exit("status: SIOCGLIFFLAGS");
2838 }
2839 flags = lifr.lifr_flags;
2840
2841 /*
2842 * In V4 compatibility mode, we don't print the IFF_IPV4 flag or
2843 * interfaces with IFF_IPV6 set.
2844 */
2845 if (v4compat) {
2846 flags &= ~IFF_IPV4;
2847 if (flags & IFF_IPV6)
2848 return;
2849 }
2850
2851 (void) printf("%s: ", ifname);
2852 print_flags(flags);
2853
2854 (void) strncpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
2855 if (ioctl(s, SIOCGLIFMETRIC, (caddr_t)&lifr) < 0) {
2856 Perror0_exit("status: SIOCGLIFMETRIC");
2857 } else {
2858 if (lifr.lifr_metric)
2859 (void) printf(" metric %d", lifr.lifr_metric);
2860 }
2861 if (ioctl(s, SIOCGLIFMTU, (caddr_t)&lifr) >= 0)
2862 (void) printf(" mtu %u", lifr.lifr_mtu);
2863
2864 /* don't print index or zone when in compatibility mode */
2865 if (!v4compat) {
2866 if (ioctl(s, SIOCGLIFINDEX, (caddr_t)&lifr) >= 0)
2867 (void) printf(" index %d", lifr.lifr_index);
2868 /*
2869 * Stack instances use GLOBAL_ZONEID for IP data structures
2870 * even in the non-global zone.
2871 */
2872 if (ioctl(s, SIOCGLIFZONE, (caddr_t)&lifr) >= 0 &&
2873 lifr.lifr_zoneid != getzoneid() &&
2874 lifr.lifr_zoneid != GLOBAL_ZONEID) {
2875 char zone_name[ZONENAME_MAX];
2876
2877 if (lifr.lifr_zoneid == ALL_ZONES) {
2878 (void) printf("\n\tall-zones");
2879 } else if (getzonenamebyid(lifr.lifr_zoneid, zone_name,
2880 sizeof (zone_name)) < 0) {
2881 (void) printf("\n\tzone %d", lifr.lifr_zoneid);
2882 } else {
2883 (void) printf("\n\tzone %s", zone_name);
2884 }
2885 }
2886 }
2887
2888 if (ioctl(s, SIOCGLIFINDEX, (caddr_t)&lifr) >= 0) {
2889 lifs.lifs_ifindex = lifr.lifr_index;
2890
2891 /*
2892 * Find the number of interfaces that use this interfaces'
2893 * address as a source address
2894 */
2895 lifs.lifs_buf = NULL;
2896 lifs.lifs_maxlen = 0;
2897 for (;;) {
2898 /* The first pass will give the bufsize we need */
2899 rval = ioctl(s, SIOCGLIFSRCOF, (char *)&lifs);
2900 if (rval < 0) {
2901 if (lifs.lifs_buf != NULL) {
2902 free(lifs.lifs_buf);
2903 lifs.lifs_buf = NULL;
2904 }
2905 lifs.lifs_len = 0;
2906 break;
2907 }
2908 if (lifs.lifs_len <= lifs.lifs_maxlen)
2909 break;
2910 /* Use kernel's size + a small margin to avoid loops */
2911 lifs.lifs_maxlen = lifs.lifs_len +
2912 5 * sizeof (struct lifreq);
2913 /* For the first pass, realloc acts like malloc */
2914 newbuf = realloc(lifs.lifs_buf, lifs.lifs_maxlen);
2915 if (newbuf == NULL) {
2916 if (lifs.lifs_buf != NULL) {
2917 free(lifs.lifs_buf);
2918 lifs.lifs_buf = NULL;
2919 }
2920 lifs.lifs_len = 0;
2921 break;
2922 }
2923 lifs.lifs_buf = newbuf;
2924 }
2925
2926
2927 numifs = lifs.lifs_len / sizeof (struct lifreq);
2928 if (numifs > 0) {
2929 lifrp = lifs.lifs_req;
2930 (void) printf("\n\tsrcof");
2931 for (n = numifs; n > 0; n--, lifrp++) {
2932 (void) printf(" %s", lifrp->lifr_name);
2933 }
2934 }
2935
2936 if (lifs.lifs_buf != NULL)
2937 free(lifs.lifs_buf);
2938 }
2939
2940 /* Find the interface whose source address this interface uses */
2941 if (ioctl(s, SIOCGLIFUSESRC, (caddr_t)&lifr) == 0) {
2942 if (lifr.lifr_index != 0) {
2943 if (if_indextoname(lifr.lifr_index,
2944 if_usesrc_name) == NULL) {
2945 (void) printf("\n\tusesrc ifIndex %d",
2946 lifr.lifr_index);
2947 } else {
2948 (void) printf("\n\tusesrc %s", if_usesrc_name);
2949 }
2950 }
2951 }
2952
2953 (void) putchar('\n');
2954 }
2955
2956 /*
2957 * Print the status of the interface. If an address family was
2958 * specified, show it and it only; otherwise, show them all.
2959 */
2960 static void
status(void)2961 status(void)
2962 {
2963 struct afswtch *p = afp;
2964 uint64_t flags;
2965 datalink_id_t linkid;
2966
2967 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
2968 if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
2969 Perror0_exit("status: SIOCGLIFFLAGS");
2970 }
2971
2972 flags = lifr.lifr_flags;
2973
2974 /*
2975 * Only print the interface status if the address family matches
2976 * the interface family flag.
2977 */
2978 if (p != NULL) {
2979 if (((p->af_af == AF_INET6) && (flags & IFF_IPV4)) ||
2980 ((p->af_af == AF_INET) && (flags & IFF_IPV6)))
2981 return;
2982 }
2983
2984 /*
2985 * In V4 compatibility mode, don't print IFF_IPV6 interfaces.
2986 */
2987 if (v4compat && (flags & IFF_IPV6))
2988 return;
2989
2990 ifstatus(name);
2991
2992 if (ifconfig_dladm_open(name, DATALINK_CLASS_IPTUN, &linkid) ==
2993 DLADM_STATUS_OK)
2994 tun_status(linkid);
2995
2996 if (p != NULL) {
2997 (*p->af_status)(1, flags);
2998 } else {
2999 for (p = afs; p->af_name; p++) {
3000 /* set global af for use in p->af_status */
3001 af = p->af_af;
3002 (*p->af_status)(0, flags);
3003 }
3004
3005 /*
3006 * Historically, 'ether' has been an address family,
3007 * so print it here.
3008 */
3009 print_ifether(name);
3010 }
3011 }
3012
3013 /*
3014 * Print the status of the interface in a format that can be used to
3015 * reconfigure the interface later. Code stolen from status() above.
3016 */
3017 /* ARGSUSED */
3018 static int
configinfo(char * null,int64_t param)3019 configinfo(char *null, int64_t param)
3020 {
3021 char *cp;
3022 struct afswtch *p = afp;
3023 uint64_t flags;
3024 char lifname[LIFNAMSIZ];
3025 char if_usesrc_name[LIFNAMSIZ];
3026
3027 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
3028
3029 if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
3030 Perror0_exit("status: SIOCGLIFFLAGS");
3031 }
3032 flags = lifr.lifr_flags;
3033
3034 if (debug) {
3035 (void) printf("configinfo: name %s flags 0x%llx af_af %d\n",
3036 name, flags, p != NULL ? p->af_af : -1);
3037 }
3038
3039 /*
3040 * Build the interface name to print (we cannot directly use `name'
3041 * because one cannot "plumb" ":0" interfaces).
3042 */
3043 (void) strlcpy(lifname, name, LIFNAMSIZ);
3044 if ((cp = strchr(lifname, ':')) != NULL && atoi(cp + 1) == 0)
3045 *cp = '\0';
3046
3047 /*
3048 * if the interface is IPv4
3049 * if we have a IPv6 address family restriction return
3050 * so it won't print
3051 * if we are in IPv4 compatibility mode, clear out IFF_IPV4
3052 * so we don't print it.
3053 */
3054 if (flags & IFF_IPV4) {
3055 if (p && p->af_af == AF_INET6)
3056 return (-1);
3057 if (v4compat)
3058 flags &= ~IFF_IPV4;
3059
3060 (void) printf("%s inet plumb", lifname);
3061 } else if (flags & IFF_IPV6) {
3062 /*
3063 * else if the interface is IPv6
3064 * if we have a IPv4 address family restriction return
3065 * or we are in IPv4 compatibiltiy mode, return.
3066 */
3067 if (p && p->af_af == AF_INET)
3068 return (-1);
3069 if (v4compat)
3070 return (-1);
3071
3072 (void) printf("%s inet6 plumb", lifname);
3073 }
3074
3075 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
3076 if (ioctl(s, SIOCGLIFMETRIC, (caddr_t)&lifr) < 0) {
3077 Perror0_exit("configinfo: SIOCGLIFMETRIC");
3078 } else {
3079 if (lifr.lifr_metric)
3080 (void) printf(" metric %d ", lifr.lifr_metric);
3081 }
3082 if (((flags & (IFF_VIRTUAL|IFF_LOOPBACK)) != IFF_VIRTUAL) &&
3083 ioctl(s, SIOCGLIFMTU, (caddr_t)&lifr) >= 0)
3084 (void) printf(" mtu %d", lifr.lifr_metric);
3085
3086 /* Index only applies to the zeroth interface */
3087 if (lifnum(name) == 0) {
3088 if (ioctl(s, SIOCGLIFINDEX, (caddr_t)&lifr) >= 0)
3089 (void) printf(" index %d", lifr.lifr_index);
3090 }
3091
3092 if (ioctl(s, SIOCGLIFUSESRC, (caddr_t)&lifr) == 0) {
3093 if (lifr.lifr_index != 0) {
3094 if (if_indextoname(lifr.lifr_index,
3095 if_usesrc_name) != NULL) {
3096 (void) printf(" usesrc %s", if_usesrc_name);
3097 }
3098 }
3099 }
3100
3101 if (p != NULL) {
3102 (*p->af_configinfo)(1, flags);
3103 } else {
3104 for (p = afs; p->af_name; p++) {
3105 (void) close(s);
3106 s = socket(SOCKET_AF(p->af_af), SOCK_DGRAM, 0);
3107 /* set global af for use in p->af_configinfo */
3108 af = p->af_af;
3109 if (s == -1) {
3110 Perror0_exit("socket");
3111 }
3112 (*p->af_configinfo)(0, flags);
3113 }
3114 }
3115
3116 (void) putchar('\n');
3117 return (0);
3118 }
3119
3120 static void
print_tsec(iptun_params_t * params)3121 print_tsec(iptun_params_t *params)
3122 {
3123 ipsec_req_t *ipsr;
3124
3125 (void) printf("\ttunnel security settings ");
3126 if (!(params->iptun_param_flags & IPTUN_PARAM_SECINFO)) {
3127 (void) printf("--> use 'ipsecconf -ln -i %s'", name);
3128 } else {
3129 ipsr = ¶ms->iptun_param_secinfo;
3130 if (ipsr->ipsr_ah_req & IPSEC_PREF_REQUIRED) {
3131 (void) printf("ah (%s) ",
3132 rparsealg(ipsr->ipsr_auth_alg, IPSEC_PROTO_AH));
3133 }
3134 if (ipsr->ipsr_esp_req & IPSEC_PREF_REQUIRED) {
3135 (void) printf("esp (%s",
3136 rparsealg(ipsr->ipsr_esp_alg, IPSEC_PROTO_ESP));
3137 (void) printf("/%s)",
3138 rparsealg(ipsr->ipsr_esp_auth_alg, IPSEC_PROTO_AH));
3139 }
3140 }
3141 (void) printf("\n");
3142 }
3143
3144 static void
tun_status(datalink_id_t linkid)3145 tun_status(datalink_id_t linkid)
3146 {
3147 iptun_params_t params;
3148 char propval[DLADM_PROP_VAL_MAX];
3149 char *valptr[1];
3150 uint_t valcnt = 1;
3151 boolean_t tabbed = _B_FALSE;
3152
3153 params.iptun_param_linkid = linkid;
3154
3155 /* If dladm_iptun_getparams() fails, assume we are not a tunnel. */
3156 assert(dlh_opened);
3157 if (dladm_iptun_getparams(dlh, ¶ms, DLADM_OPT_ACTIVE) !=
3158 DLADM_STATUS_OK)
3159 return;
3160
3161 switch (params.iptun_param_type) {
3162 case IPTUN_TYPE_IPV4:
3163 case IPTUN_TYPE_6TO4:
3164 (void) printf("\tinet");
3165 break;
3166 case IPTUN_TYPE_IPV6:
3167 (void) printf("\tinet6");
3168 break;
3169 default:
3170 dladmerr_exit(DLADM_STATUS_IPTUNTYPE, name);
3171 break;
3172 }
3173
3174 /*
3175 * There is always a source address. If it hasn't been explicitly
3176 * set, the API will pass back a buffer containing the unspecified
3177 * address.
3178 */
3179 (void) printf(" tunnel src %s ", params.iptun_param_laddr);
3180
3181 if (params.iptun_param_flags & IPTUN_PARAM_RADDR)
3182 (void) printf("tunnel dst %s\n", params.iptun_param_raddr);
3183 else
3184 (void) putchar('\n');
3185
3186 if (params.iptun_param_flags & IPTUN_PARAM_IPSECPOL)
3187 print_tsec(¶ms);
3188
3189 valptr[0] = propval;
3190 if (dladm_get_linkprop(dlh, linkid, DLADM_PROP_VAL_CURRENT, "hoplimit",
3191 (char **)valptr, &valcnt) == DLADM_STATUS_OK) {
3192 (void) printf("\ttunnel hop limit %s ", propval);
3193 tabbed = _B_TRUE;
3194 }
3195
3196 if (dladm_get_linkprop(dlh, linkid, DLADM_PROP_VAL_CURRENT,
3197 "encaplimit", (char **)valptr, &valcnt) == DLADM_STATUS_OK) {
3198 uint32_t elim;
3199
3200 if (!tabbed) {
3201 (void) putchar('\t');
3202 tabbed = _B_TRUE;
3203 }
3204 elim = strtol(propval, NULL, 10);
3205 if (elim > 0)
3206 (void) printf("tunnel encapsulation limit %s", propval);
3207 else
3208 (void) printf("tunnel encapsulation limit disabled");
3209 }
3210
3211 if (tabbed)
3212 (void) putchar('\n');
3213 }
3214
3215 static void
in_status(int force,uint64_t flags)3216 in_status(int force, uint64_t flags)
3217 {
3218 struct sockaddr_in *sin, *laddr;
3219 struct sockaddr_in netmask = { AF_INET };
3220
3221 if (debug)
3222 (void) printf("in_status(%s) flags 0x%llx\n", name, flags);
3223
3224 /* only print status for IPv4 interfaces */
3225 if (!(flags & IFF_IPV4))
3226 return;
3227
3228 if (!(flags & IFF_NOLOCAL)) {
3229 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
3230 if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) < 0) {
3231 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT ||
3232 errno == ENXIO) {
3233 if (!force)
3234 return;
3235 (void) memset(&lifr.lifr_addr, 0,
3236 sizeof (lifr.lifr_addr));
3237 } else
3238 Perror0_exit("in_status: SIOCGLIFADDR");
3239 }
3240 sin = (struct sockaddr_in *)&lifr.lifr_addr;
3241 (void) printf("\tinet %s ", inet_ntoa(sin->sin_addr));
3242 laddr = sin;
3243 } else {
3244 (void) printf("\tinet ");
3245 }
3246
3247 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
3248 if (ioctl(s, SIOCGLIFSUBNET, (caddr_t)&lifr) < 0) {
3249 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT ||
3250 errno == ENXIO) {
3251 if (!force)
3252 return;
3253 (void) memset(&lifr.lifr_addr, 0,
3254 sizeof (lifr.lifr_addr));
3255 } else {
3256 Perror0_exit("in_status: SIOCGLIFSUBNET");
3257 }
3258 }
3259 sin = (struct sockaddr_in *)&lifr.lifr_addr;
3260 if ((flags & IFF_NOLOCAL) ||
3261 sin->sin_addr.s_addr != laddr->sin_addr.s_addr) {
3262 (void) printf("subnet %s/%d ", inet_ntoa(sin->sin_addr),
3263 lifr.lifr_addrlen);
3264 }
3265 if (sin->sin_family != AF_INET) {
3266 (void) printf("Wrong family: %d\n", sin->sin_family);
3267 }
3268
3269 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
3270 if (ioctl(s, SIOCGLIFNETMASK, (caddr_t)&lifr) < 0) {
3271 if (errno != EADDRNOTAVAIL)
3272 Perror0_exit("in_status: SIOCGLIFNETMASK");
3273 (void) memset(&lifr.lifr_addr, 0, sizeof (lifr.lifr_addr));
3274 } else
3275 netmask.sin_addr =
3276 ((struct sockaddr_in *)&lifr.lifr_addr)->sin_addr;
3277 if (flags & IFF_POINTOPOINT) {
3278 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
3279 if (ioctl(s, SIOCGLIFDSTADDR, (caddr_t)&lifr) < 0) {
3280 if (errno == EADDRNOTAVAIL)
3281 (void) memset(&lifr.lifr_addr, 0,
3282 sizeof (lifr.lifr_addr));
3283 else
3284 Perror0_exit("in_status: SIOCGLIFDSTADDR");
3285 }
3286 sin = (struct sockaddr_in *)&lifr.lifr_dstaddr;
3287 (void) printf("--> %s ", inet_ntoa(sin->sin_addr));
3288 }
3289 (void) printf("netmask %x ", ntohl(netmask.sin_addr.s_addr));
3290 if (flags & IFF_BROADCAST) {
3291 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
3292 if (ioctl(s, SIOCGLIFBRDADDR, (caddr_t)&lifr) < 0) {
3293 if (errno == EADDRNOTAVAIL)
3294 (void) memset(&lifr.lifr_addr, 0,
3295 sizeof (lifr.lifr_addr));
3296 else
3297 Perror0_exit("in_status: SIOCGLIFBRDADDR");
3298 }
3299 sin = (struct sockaddr_in *)&lifr.lifr_addr;
3300 if (sin->sin_addr.s_addr != 0) {
3301 (void) printf("broadcast %s",
3302 inet_ntoa(sin->sin_addr));
3303 }
3304 }
3305 /* If there is a groupname, print it for only the physical interface */
3306 if (strchr(name, ':') == NULL) {
3307 if (ioctl(s, SIOCGLIFGROUPNAME, &lifr) >= 0 &&
3308 lifr.lifr_groupname[0] != '\0') {
3309 (void) printf("\n\tgroupname %s", lifr.lifr_groupname);
3310 }
3311 }
3312 (void) putchar('\n');
3313 }
3314
3315 static void
in6_status(int force,uint64_t flags)3316 in6_status(int force, uint64_t flags)
3317 {
3318 char abuf[INET6_ADDRSTRLEN];
3319 struct sockaddr_in6 *sin6, *laddr6;
3320
3321 if (debug)
3322 (void) printf("in6_status(%s) flags 0x%llx\n", name, flags);
3323
3324 if (!(flags & IFF_IPV6))
3325 return;
3326
3327 if (!(flags & IFF_NOLOCAL)) {
3328 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
3329 if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) < 0) {
3330 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT ||
3331 errno == ENXIO) {
3332 if (!force)
3333 return;
3334 (void) memset(&lifr.lifr_addr, 0,
3335 sizeof (lifr.lifr_addr));
3336 } else
3337 Perror0_exit("in_status6: SIOCGLIFADDR");
3338 }
3339 sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr;
3340 (void) printf("\tinet6 %s/%d ",
3341 inet_ntop(AF_INET6, (void *)&sin6->sin6_addr,
3342 abuf, sizeof (abuf)),
3343 lifr.lifr_addrlen);
3344 laddr6 = sin6;
3345 } else {
3346 (void) printf("\tinet6 ");
3347 }
3348 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
3349 if (ioctl(s, SIOCGLIFSUBNET, (caddr_t)&lifr) < 0) {
3350 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT ||
3351 errno == ENXIO) {
3352 if (!force)
3353 return;
3354 (void) memset(&lifr.lifr_addr, 0,
3355 sizeof (lifr.lifr_addr));
3356 } else
3357 Perror0_exit("in_status6: SIOCGLIFSUBNET");
3358 }
3359 sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr;
3360 if ((flags & IFF_NOLOCAL) ||
3361 !IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &laddr6->sin6_addr)) {
3362 (void) printf("subnet %s/%d ",
3363 inet_ntop(AF_INET6, (void *)&sin6->sin6_addr,
3364 abuf, sizeof (abuf)),
3365 lifr.lifr_addrlen);
3366 }
3367 if (sin6->sin6_family != AF_INET6) {
3368 (void) printf("Wrong family: %d\n", sin6->sin6_family);
3369 }
3370 if (flags & IFF_POINTOPOINT) {
3371 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
3372 if (ioctl(s, SIOCGLIFDSTADDR, (caddr_t)&lifr) < 0) {
3373 if (errno == EADDRNOTAVAIL)
3374 (void) memset(&lifr.lifr_addr, 0,
3375 sizeof (lifr.lifr_addr));
3376 else
3377 Perror0_exit("in_status6: SIOCGLIFDSTADDR");
3378 }
3379 sin6 = (struct sockaddr_in6 *)&lifr.lifr_dstaddr;
3380 (void) printf("--> %s ",
3381 inet_ntop(AF_INET6, (void *)&sin6->sin6_addr,
3382 abuf, sizeof (abuf)));
3383 }
3384 if (verbose) {
3385 (void) putchar('\n');
3386 (void) putchar('\t');
3387 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
3388 if (ioctl(s, SIOCGLIFTOKEN, (caddr_t)&lifr) < 0) {
3389 if (errno == EADDRNOTAVAIL || errno == EINVAL)
3390 (void) memset(&lifr.lifr_addr, 0,
3391 sizeof (lifr.lifr_addr));
3392 else
3393 Perror0_exit("in_status6: SIOCGLIFTOKEN");
3394 } else {
3395 sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr;
3396 (void) printf("token %s/%d ",
3397 inet_ntop(AF_INET6, (void *)&sin6->sin6_addr,
3398 abuf, sizeof (abuf)),
3399 lifr.lifr_addrlen);
3400 }
3401 if (ioctl(s, SIOCGLIFLNKINFO, (caddr_t)&lifr) < 0) {
3402 if (errno != EINVAL) {
3403 Perror0_exit("in_status6: SIOCGLIFLNKINFO");
3404 }
3405 } else {
3406 (void) printf("maxhops %u, reachtime %u ms, "
3407 "reachretrans %u ms, maxmtu %u ",
3408 lifr.lifr_ifinfo.lir_maxhops,
3409 lifr.lifr_ifinfo.lir_reachtime,
3410 lifr.lifr_ifinfo.lir_reachretrans,
3411 lifr.lifr_ifinfo.lir_maxmtu);
3412 }
3413 }
3414 /* If there is a groupname, print it for only the physical interface */
3415 if (strchr(name, ':') == NULL) {
3416 if (ioctl(s, SIOCGLIFGROUPNAME, &lifr) >= 0 &&
3417 lifr.lifr_groupname[0] != '\0') {
3418 (void) printf("\n\tgroupname %s", lifr.lifr_groupname);
3419 }
3420 }
3421 (void) putchar('\n');
3422 }
3423
3424 static void
in_configinfo(int force,uint64_t flags)3425 in_configinfo(int force, uint64_t flags)
3426 {
3427 struct sockaddr_in *sin, *laddr;
3428 struct sockaddr_in netmask = { AF_INET };
3429
3430 if (debug)
3431 (void) printf("in_configinfo(%s) flags 0x%llx\n", name, flags);
3432
3433 /* only configinfo info for IPv4 interfaces */
3434 if (!(flags & IFF_IPV4))
3435 return;
3436
3437 if (!(flags & IFF_NOLOCAL)) {
3438 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
3439 if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) < 0) {
3440 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT ||
3441 errno == ENXIO) {
3442 if (!force)
3443 return;
3444 (void) memset(&lifr.lifr_addr, 0,
3445 sizeof (lifr.lifr_addr));
3446 } else
3447 Perror0_exit("in_configinfo: SIOCGLIFADDR");
3448 }
3449 sin = (struct sockaddr_in *)&lifr.lifr_addr;
3450 (void) printf(" set %s ", inet_ntoa(sin->sin_addr));
3451 laddr = sin;
3452 }
3453
3454 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
3455 if (ioctl(s, SIOCGLIFSUBNET, (caddr_t)&lifr) < 0) {
3456 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT ||
3457 errno == ENXIO) {
3458 if (!force)
3459 return;
3460 (void) memset(&lifr.lifr_addr, 0,
3461 sizeof (lifr.lifr_addr));
3462 } else {
3463 Perror0_exit("in_configinfo: SIOCGLIFSUBNET");
3464 }
3465 }
3466 sin = (struct sockaddr_in *)&lifr.lifr_addr;
3467
3468 if ((flags & IFF_NOLOCAL) ||
3469 sin->sin_addr.s_addr != laddr->sin_addr.s_addr) {
3470 (void) printf(" subnet %s/%d ", inet_ntoa(sin->sin_addr),
3471 lifr.lifr_addrlen);
3472 }
3473 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
3474 if (ioctl(s, SIOCGLIFNETMASK, (caddr_t)&lifr) < 0) {
3475 if (errno != EADDRNOTAVAIL)
3476 Perror0_exit("in_configinfo: SIOCGLIFNETMASK");
3477 (void) memset(&lifr.lifr_addr, 0, sizeof (lifr.lifr_addr));
3478 } else
3479 netmask.sin_addr =
3480 ((struct sockaddr_in *)&lifr.lifr_addr)->sin_addr;
3481 if (flags & IFF_POINTOPOINT) {
3482 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
3483 if (ioctl(s, SIOCGLIFDSTADDR, (caddr_t)&lifr) < 0) {
3484 if (errno == EADDRNOTAVAIL)
3485 (void) memset(&lifr.lifr_addr, 0,
3486 sizeof (lifr.lifr_addr));
3487 else
3488 Perror0_exit("in_configinfo: SIOCGLIFDSTADDR");
3489 }
3490 sin = (struct sockaddr_in *)&lifr.lifr_dstaddr;
3491 (void) printf(" destination %s ", inet_ntoa(sin->sin_addr));
3492 }
3493 (void) printf(" netmask 0x%x ", ntohl(netmask.sin_addr.s_addr));
3494 if (flags & IFF_BROADCAST) {
3495 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
3496 if (ioctl(s, SIOCGLIFBRDADDR, (caddr_t)&lifr) < 0) {
3497 if (errno == EADDRNOTAVAIL)
3498 (void) memset(&lifr.lifr_addr, 0,
3499 sizeof (lifr.lifr_addr));
3500 else
3501 Perror0_exit("in_configinfo: SIOCGLIFBRDADDR");
3502 }
3503 sin = (struct sockaddr_in *)&lifr.lifr_addr;
3504 if (sin->sin_addr.s_addr != 0) {
3505 (void) printf(" broadcast %s ",
3506 inet_ntoa(sin->sin_addr));
3507 }
3508 }
3509
3510 /* If there is a groupname, print it for only the zeroth interface */
3511 if (lifnum(name) == 0) {
3512 if (ioctl(s, SIOCGLIFGROUPNAME, &lifr) >= 0 &&
3513 lifr.lifr_groupname[0] != '\0') {
3514 (void) printf(" group %s ", lifr.lifr_groupname);
3515 }
3516 }
3517
3518 /* Print flags to configure */
3519 print_config_flags(AF_INET, flags);
3520 }
3521
3522 static void
in6_configinfo(int force,uint64_t flags)3523 in6_configinfo(int force, uint64_t flags)
3524 {
3525 char abuf[INET6_ADDRSTRLEN];
3526 struct sockaddr_in6 *sin6, *laddr6;
3527
3528 if (debug)
3529 (void) printf("in6_configinfo(%s) flags 0x%llx\n", name,
3530 flags);
3531
3532 if (!(flags & IFF_IPV6))
3533 return;
3534
3535 if (!(flags & IFF_NOLOCAL)) {
3536 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
3537 if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) < 0) {
3538 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT ||
3539 errno == ENXIO) {
3540 if (!force)
3541 return;
3542 (void) memset(&lifr.lifr_addr, 0,
3543 sizeof (lifr.lifr_addr));
3544 } else
3545 Perror0_exit("in6_configinfo: SIOCGLIFADDR");
3546 }
3547 sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr;
3548 (void) printf(" set %s/%d ",
3549 inet_ntop(AF_INET6, &sin6->sin6_addr, abuf, sizeof (abuf)),
3550 lifr.lifr_addrlen);
3551 laddr6 = sin6;
3552 }
3553 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
3554 if (ioctl(s, SIOCGLIFSUBNET, (caddr_t)&lifr) < 0) {
3555 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT ||
3556 errno == ENXIO) {
3557 if (!force)
3558 return;
3559 (void) memset(&lifr.lifr_addr, 0,
3560 sizeof (lifr.lifr_addr));
3561 } else
3562 Perror0_exit("in6_configinfo: SIOCGLIFSUBNET");
3563 }
3564 sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr;
3565 if ((flags & IFF_NOLOCAL) ||
3566 !IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &laddr6->sin6_addr)) {
3567 (void) printf(" subnet %s/%d ",
3568 inet_ntop(AF_INET6, (void *)&sin6->sin6_addr,
3569 abuf, sizeof (abuf)),
3570 lifr.lifr_addrlen);
3571 }
3572
3573 if (flags & IFF_POINTOPOINT) {
3574 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
3575 if (ioctl(s, SIOCGLIFDSTADDR, (caddr_t)&lifr) < 0) {
3576 if (errno == EADDRNOTAVAIL)
3577 (void) memset(&lifr.lifr_addr, 0,
3578 sizeof (lifr.lifr_addr));
3579 else
3580 Perror0_exit("in6_configinfo: SIOCGLIFDSTADDR");
3581 }
3582 sin6 = (struct sockaddr_in6 *)&lifr.lifr_dstaddr;
3583 (void) printf(" destination %s ",
3584 inet_ntop(AF_INET6, (void *)&sin6->sin6_addr,
3585 abuf, sizeof (abuf)));
3586 }
3587
3588 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
3589 if (ioctl(s, SIOCGLIFTOKEN, (caddr_t)&lifr) < 0) {
3590 if (errno == EADDRNOTAVAIL || errno == EINVAL)
3591 (void) memset(&lifr.lifr_addr, 0,
3592 sizeof (lifr.lifr_addr));
3593 else
3594 Perror0_exit("in6_configinfo: SIOCGLIFTOKEN");
3595 } else {
3596 sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr;
3597 (void) printf(" token %s/%d ",
3598 inet_ntop(AF_INET6, (void *)&sin6->sin6_addr,
3599 abuf, sizeof (abuf)),
3600 lifr.lifr_addrlen);
3601 }
3602
3603 /* If there is a groupname, print it for only the zeroth interface */
3604 if (lifnum(name) == 0) {
3605 if (ioctl(s, SIOCGLIFGROUPNAME, &lifr) >= 0 &&
3606 lifr.lifr_groupname[0] != '\0') {
3607 (void) printf(" group %s ", lifr.lifr_groupname);
3608 }
3609 }
3610
3611 /* Print flags to configure */
3612 print_config_flags(AF_INET6, flags);
3613 }
3614
3615 /*
3616 * If this is a physical interface then remove it.
3617 * If it is a logical interface name use SIOCLIFREMOVEIF to
3618 * remove it. In both cases fail if it doesn't exist.
3619 */
3620 /* ARGSUSED */
3621 static int
inetunplumb(char * arg,int64_t param)3622 inetunplumb(char *arg, int64_t param)
3623 {
3624 ipadm_status_t istatus;
3625
3626 istatus = ipadm_delete_if(iph, name, afp->af_af, IPADM_OPT_ACTIVE);
3627 if (istatus != IPADM_SUCCESS) {
3628 (void) fprintf(stderr, "ifconfig: cannot unplumb %s: %s\n",
3629 name, ipadm_status2str(istatus));
3630 exit(1);
3631 }
3632
3633 return (0);
3634 }
3635
3636 /*
3637 * Create the interface in `name', using ipadm_create_if(). If `name' is a
3638 * logical interface or loopback interface, ipadm_create_if() uses
3639 * SIOCLIFADDIF to create it.
3640 */
3641 /* ARGSUSED */
3642 static int
inetplumb(char * arg,int64_t param)3643 inetplumb(char *arg, int64_t param)
3644 {
3645 ipadm_status_t istatus;
3646
3647 istatus = ipadm_create_if(iph, name, afp->af_af, IPADM_OPT_ACTIVE);
3648 if (istatus != IPADM_SUCCESS) {
3649 (void) fprintf(stderr, "ifconfig: cannot plumb %s: %s\n",
3650 name, ipadm_status2str(istatus));
3651 if (istatus != IPADM_IF_EXISTS)
3652 exit(1);
3653 }
3654 return (0);
3655 }
3656
3657 /* ARGSUSED */
3658 static int
inetipmp(char * arg,int64_t param)3659 inetipmp(char *arg, int64_t param)
3660 {
3661 int retval;
3662
3663 /*
3664 * Treat e.g. "ifconfig ipmp0:2 ipmp" as "ifconfig ipmp0:2 plumb".
3665 * Otherwise, try to create the requested IPMP interface.
3666 */
3667 if (strchr(name, ':') != NULL)
3668 retval = inetplumb(arg, param);
3669 else
3670 retval = create_ipmp(name, afp->af_af, name, _B_FALSE);
3671
3672 /*
3673 * We'd return -1, but foreachinterface() doesn't propagate the error
3674 * into the exit status, so we're forced to explicitly exit().
3675 */
3676 if (retval == -1)
3677 exit(1);
3678 return (0);
3679 }
3680
3681 /*
3682 * Create an IPMP group `grname' with address family `af'. If `ifname' is
3683 * non-NULL, it specifies the interface name to use. Otherwise, use the name
3684 * ipmpN, where N corresponds to the lowest available integer. If `implicit'
3685 * is set, then the group is being created as a side-effect of placing an
3686 * underlying interface in a group. Also start in.mpathd if necessary.
3687 */
3688 static int
create_ipmp(const char * grname,int af,const char * ifname,boolean_t implicit)3689 create_ipmp(const char *grname, int af, const char *ifname, boolean_t implicit)
3690 {
3691 static int ipmp_daemon_started;
3692 uint32_t flags = IPADM_OPT_IPMP|IPADM_OPT_ACTIVE;
3693 ipadm_status_t istatus;
3694
3695 if (debug) {
3696 (void) printf("create_ipmp: ifname %s grname %s af %d\n",
3697 ifname != NULL ? ifname : "NULL", grname, af);
3698 }
3699
3700 /*
3701 * ipadm_create_if() creates the IPMP interface and fills in the
3702 * ppa in lifr.lifr_name, if `ifname'="ipmp".
3703 */
3704 (void) strlcpy(lifr.lifr_name, (ifname ? ifname : "ipmp"),
3705 sizeof (lifr.lifr_name));
3706 if (ifname == NULL)
3707 flags |= IPADM_OPT_GENPPA;
3708 istatus = ipadm_create_if(iph, lifr.lifr_name, af, flags);
3709 if (istatus != IPADM_SUCCESS) {
3710 (void) fprintf(stderr, "ifconfig: cannot create IPMP interface "
3711 "%s: %s\n", grname, ipadm_status2str(istatus));
3712 return (-1);
3713 }
3714
3715 /*
3716 * To preserve backward-compatibility, always bring up the link-local
3717 * address for implicitly-created IPv6 IPMP interfaces.
3718 */
3719 if (implicit && af == AF_INET6) {
3720 if (ioctl(s6, SIOCGLIFFLAGS, &lifr) == 0) {
3721 lifr.lifr_flags |= IFF_UP;
3722 (void) ioctl(s6, SIOCSLIFFLAGS, &lifr);
3723 }
3724 }
3725
3726 /*
3727 * If the caller requested a different group name, issue a
3728 * SIOCSLIFGROUPNAME on the new IPMP interface.
3729 */
3730 if (strcmp(lifr.lifr_name, grname) != 0) {
3731 (void) strlcpy(lifr.lifr_groupname, grname, LIFGRNAMSIZ);
3732 if (ioctl(s, SIOCSLIFGROUPNAME, &lifr) == -1) {
3733 Perror0("SIOCSLIFGROUPNAME");
3734 return (-1);
3735 }
3736 }
3737
3738 /*
3739 * If we haven't done so yet, ensure in.mpathd is started.
3740 */
3741 if (ipmp_daemon_started++ == 0)
3742 start_ipmp_daemon();
3743
3744 return (0);
3745 }
3746
3747 /*
3748 * Start in.mpathd if it's not already running.
3749 */
3750 static void
start_ipmp_daemon(void)3751 start_ipmp_daemon(void)
3752 {
3753 int retval;
3754 ipmp_handle_t ipmp_handle;
3755
3756 /*
3757 * Ping in.mpathd to see if it's running already.
3758 */
3759 if ((retval = ipmp_open(&ipmp_handle)) != IPMP_SUCCESS) {
3760 (void) fprintf(stderr, "ifconfig: cannot create IPMP handle: "
3761 "%s\n", ipmp_errmsg(retval));
3762 return;
3763 }
3764
3765 retval = ipmp_ping_daemon(ipmp_handle);
3766 ipmp_close(ipmp_handle);
3767
3768 switch (retval) {
3769 case IPMP_ENOMPATHD:
3770 break;
3771 case IPMP_SUCCESS:
3772 return;
3773 default:
3774 (void) fprintf(stderr, "ifconfig: cannot ping in.mpathd: %s\n",
3775 ipmp_errmsg(retval));
3776 break;
3777 }
3778
3779 /*
3780 * Start in.mpathd. Note that in.mpathd will handle multiple
3781 * incarnations (ipmp_ping_daemon() is just an optimization) so we
3782 * don't need to worry about racing with another ifconfig process.
3783 */
3784 switch (fork()) {
3785 case -1:
3786 Perror0_exit("start_ipmp_daemon: fork");
3787 /* NOTREACHED */
3788 case 0:
3789 (void) execl(MPATHD_PATH, MPATHD_PATH, NULL);
3790 _exit(1);
3791 /* NOTREACHED */
3792 default:
3793 break;
3794 }
3795 }
3796
3797 /*
3798 * Bring the address named by `ifaddrp' up or down. Doesn't trust any mutable
3799 * values in ia_flags since they may be stale.
3800 */
3801 static boolean_t
ifaddr_op(ifaddrlistx_t * ifaddrp,boolean_t up)3802 ifaddr_op(ifaddrlistx_t *ifaddrp, boolean_t up)
3803 {
3804 struct lifreq lifrl; /* Local lifreq struct */
3805 int fd = (ifaddrp->ia_flags & IFF_IPV4) ? s4 : s6;
3806
3807 (void) memset(&lifrl, 0, sizeof (lifrl));
3808 (void) strlcpy(lifrl.lifr_name, ifaddrp->ia_name, LIFNAMSIZ);
3809 if (ioctl(fd, SIOCGLIFFLAGS, &lifrl) == -1)
3810 return (_B_FALSE);
3811
3812 if (up)
3813 lifrl.lifr_flags |= IFF_UP;
3814 else
3815 lifrl.lifr_flags &= ~IFF_UP;
3816
3817 if (ioctl(fd, SIOCSLIFFLAGS, &lifrl) == -1)
3818 return (_B_FALSE);
3819
3820 /*
3821 * If we're trying to bring the address down, ensure that DAD activity
3822 * (observable by IFF_DUPLICATE) has also been stopped.
3823 */
3824 if (!up && ioctl(fd, SIOCGLIFFLAGS, &lifrl) != -1 &&
3825 lifrl.lifr_flags & IFF_DUPLICATE) {
3826 if (ioctl(fd, SIOCGLIFADDR, &lifrl) == -1 ||
3827 ioctl(fd, SIOCSLIFADDR, &lifrl) == -1) {
3828 return (_B_FALSE);
3829 }
3830 }
3831 return (_B_TRUE);
3832 }
3833
3834 static boolean_t
ifaddr_up(ifaddrlistx_t * ifaddrp)3835 ifaddr_up(ifaddrlistx_t *ifaddrp)
3836 {
3837 return (ifaddr_op(ifaddrp, _B_TRUE));
3838 }
3839
3840 static boolean_t
ifaddr_down(ifaddrlistx_t * ifaddrp)3841 ifaddr_down(ifaddrlistx_t *ifaddrp)
3842 {
3843 return (ifaddr_op(ifaddrp, _B_FALSE));
3844 }
3845
3846 /*
3847 * Open the global libdladm handle "dlh" if it isn't already opened. The
3848 * caller may optionally supply a link name to obtain its linkid. If a link
3849 * of a specific class or classes is required, reqclass specifies the class
3850 * mask.
3851 */
3852 static dladm_status_t
ifconfig_dladm_open(const char * name,datalink_class_t reqclass,datalink_id_t * linkid)3853 ifconfig_dladm_open(const char *name, datalink_class_t reqclass,
3854 datalink_id_t *linkid)
3855 {
3856 dladm_status_t status = DLADM_STATUS_OK;
3857 datalink_class_t class;
3858
3859 if (!dlh_opened) {
3860 if ((status = dladm_open(&dlh)) != DLADM_STATUS_OK)
3861 return (status);
3862 dlh_opened = _B_TRUE;
3863 }
3864 if (name != NULL) {
3865 status = dladm_name2info(dlh, name, linkid, NULL, &class, NULL);
3866 if (status == DLADM_STATUS_OK) {
3867 if (!(class & reqclass))
3868 status = DLADM_STATUS_LINKINVAL;
3869 }
3870 }
3871 return (status);
3872 }
3873
3874 /*
3875 * This function checks if we can use libipadm API's. We will only
3876 * call libipadm functions for non-IPMP interfaces. This check is
3877 * temporary until libipadm supports IPMP interfaces.
3878 */
3879 static boolean_t
ifconfig_use_libipadm(int s,const char * lifname)3880 ifconfig_use_libipadm(int s, const char *lifname)
3881 {
3882 struct lifreq lifr1;
3883
3884 (void) strlcpy(lifr1.lifr_name, lifname, sizeof (lifr1.lifr_name));
3885 if (ioctl(s, SIOCGLIFGROUPNAME, (caddr_t)&lifr1) < 0) {
3886 (void) strncpy(lifr.lifr_name, lifname,
3887 sizeof (lifr.lifr_name));
3888 Perror0_exit("error");
3889 }
3890
3891 return (lifr1.lifr_groupname[0] == '\0');
3892 }
3893
3894 static void
ipadmerr_exit(ipadm_status_t status,const char * str)3895 ipadmerr_exit(ipadm_status_t status, const char *str)
3896 {
3897 (void) fprintf(stderr, "ifconfig: %s: %s\n", str,
3898 ipadm_status2str(status));
3899 exit(1);
3900 }
3901
3902 static void
dladmerr_exit(dladm_status_t status,const char * str)3903 dladmerr_exit(dladm_status_t status, const char *str)
3904 {
3905 char errstr[DLADM_STRSIZE];
3906
3907 (void) fprintf(stderr, "%s: %s\n", str,
3908 dladm_status2str(status, errstr));
3909 exit(1);
3910 }
3911
3912 void
Perror0(const char * cmd)3913 Perror0(const char *cmd)
3914 {
3915 Perror2(cmd, lifr.lifr_name);
3916 }
3917
3918 void
Perror0_exit(const char * cmd)3919 Perror0_exit(const char *cmd)
3920 {
3921 Perror0(cmd);
3922 exit(1);
3923 }
3924
3925 void
Perror2(const char * cmd,const char * str)3926 Perror2(const char *cmd, const char *str)
3927 {
3928 int error = errno;
3929
3930 (void) fprintf(stderr, "ifconfig: %s: ", cmd);
3931
3932 switch (error) {
3933 case ENXIO:
3934 (void) fprintf(stderr, "%s: no such interface\n", str);
3935 break;
3936 case EPERM:
3937 (void) fprintf(stderr, "%s: permission denied\n", str);
3938 break;
3939 case EEXIST:
3940 (void) fprintf(stderr, "%s: already exists\n", str);
3941 break;
3942 case ENAMETOOLONG:
3943 (void) fprintf(stderr, "%s: interface name too long\n", str);
3944 break;
3945 case ERANGE:
3946 (void) fprintf(stderr, "%s: logical interface id is outside "
3947 "allowed range\n", str);
3948 break;
3949 default:
3950 errno = error;
3951 perror(str);
3952 }
3953 }
3954
3955 /*
3956 * Print out error message (Perror2()) and exit
3957 */
3958 void
Perror2_exit(const char * cmd,const char * str)3959 Perror2_exit(const char *cmd, const char *str)
3960 {
3961 Perror2(cmd, str);
3962 exit(1);
3963 /* NOTREACHED */
3964 }
3965
3966 void
Perrdlpi(const char * cmd,const char * linkname,int err)3967 Perrdlpi(const char *cmd, const char *linkname, int err)
3968 {
3969 (void) fprintf(stderr, "ifconfig: %s \"%s\": %s\n", cmd,
3970 linkname, dlpi_strerror(err));
3971 }
3972
3973 /*
3974 * Print out error message (Perrdlpi()) and exit
3975 */
3976 void
Perrdlpi_exit(const char * cmd,const char * linkname,int err)3977 Perrdlpi_exit(const char *cmd, const char *linkname, int err)
3978 {
3979 Perrdlpi(cmd, linkname, err);
3980 exit(1);
3981 }
3982
3983 /*
3984 * If the last argument is non-NULL allow a <addr>/<n> syntax and
3985 * pass out <n> in *plenp.
3986 * If <n> doesn't parse return BAD_ADDR as *plenp.
3987 * If no /<n> is present return NO_PREFIX as *plenp.
3988 */
3989 static void
in_getaddr(char * s,struct sockaddr * saddr,int * plenp)3990 in_getaddr(char *s, struct sockaddr *saddr, int *plenp)
3991 {
3992 /* LINTED: alignment */
3993 struct sockaddr_in *sin = (struct sockaddr_in *)saddr;
3994 struct hostent *hp;
3995 struct netent *np;
3996 char str[BUFSIZ];
3997 int error_num;
3998
3999 (void) strncpy(str, s, sizeof (str));
4000
4001 /*
4002 * Look for '/'<n> is plenp
4003 */
4004 if (plenp != NULL) {
4005 char *cp;
4006
4007 *plenp = in_getprefixlen(str, _B_TRUE, IP_ABITS);
4008 if (*plenp == BAD_ADDR)
4009 return;
4010 cp = strchr(str, '/');
4011 if (cp != NULL)
4012 *cp = '\0';
4013 } else if (strchr(str, '/') != NULL) {
4014 (void) fprintf(stderr, "ifconfig: %s: unexpected '/'\n", str);
4015 exit(1);
4016 }
4017
4018 (void) memset(sin, 0, sizeof (*sin));
4019
4020 /*
4021 * Try to catch attempts to set the broadcast address to all 1's.
4022 */
4023 if (strcmp(str, "255.255.255.255") == 0 ||
4024 (strtoul(str, (char **)NULL, 0) == 0xffffffffUL)) {
4025 sin->sin_family = AF_INET;
4026 sin->sin_addr.s_addr = 0xffffffff;
4027 return;
4028 }
4029
4030 hp = getipnodebyname(str, AF_INET, 0, &error_num);
4031 if (hp) {
4032 sin->sin_family = hp->h_addrtype;
4033 (void) memcpy(&sin->sin_addr, hp->h_addr, hp->h_length);
4034 freehostent(hp);
4035 return;
4036 }
4037 np = getnetbyname(str);
4038 if (np) {
4039 sin->sin_family = np->n_addrtype;
4040 sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY);
4041 return;
4042 }
4043 if (error_num == TRY_AGAIN) {
4044 (void) fprintf(stderr, "ifconfig: %s: bad address "
4045 "(try again later)\n", s);
4046 } else {
4047 (void) fprintf(stderr, "ifconfig: %s: bad address\n", s);
4048 }
4049 exit(1);
4050 }
4051
4052 /*
4053 * If the last argument is non-NULL allow a <addr>/<n> syntax and
4054 * pass out <n> in *plenp.
4055 * If <n> doesn't parse return BAD_ADDR as *plenp.
4056 * If no /<n> is present return NO_PREFIX as *plenp.
4057 */
4058 static void
in6_getaddr(char * s,struct sockaddr * saddr,int * plenp)4059 in6_getaddr(char *s, struct sockaddr *saddr, int *plenp)
4060 {
4061 /* LINTED: alignment */
4062 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)saddr;
4063 struct hostent *hp;
4064 char str[BUFSIZ];
4065 int error_num;
4066
4067 (void) strncpy(str, s, sizeof (str));
4068
4069 /*
4070 * Look for '/'<n> is plenp
4071 */
4072 if (plenp != NULL) {
4073 char *cp;
4074
4075 *plenp = in_getprefixlen(str, _B_TRUE, IPV6_ABITS);
4076 if (*plenp == BAD_ADDR)
4077 return;
4078 cp = strchr(str, '/');
4079 if (cp != NULL)
4080 *cp = '\0';
4081 } else if (strchr(str, '/') != NULL) {
4082 (void) fprintf(stderr, "ifconfig: %s: unexpected '/'\n", str);
4083 exit(1);
4084 }
4085
4086 (void) memset(sin6, 0, sizeof (*sin6));
4087
4088 hp = getipnodebyname(str, AF_INET6, 0, &error_num);
4089 if (hp) {
4090 sin6->sin6_family = hp->h_addrtype;
4091 (void) memcpy(&sin6->sin6_addr, hp->h_addr, hp->h_length);
4092 freehostent(hp);
4093 return;
4094 }
4095 if (error_num == TRY_AGAIN) {
4096 (void) fprintf(stderr, "ifconfig: %s: bad address "
4097 "(try again later)\n", s);
4098 } else {
4099 (void) fprintf(stderr, "ifconfig: %s: bad address\n", s);
4100 }
4101 exit(1);
4102 }
4103
4104 /*
4105 * If "slash" is zero this parses the whole string as
4106 * an integer. With "slash" non zero it parses the tail part as an integer.
4107 *
4108 * If it is not a valid integer this returns BAD_ADDR.
4109 * If there is /<n> present this returns NO_PREFIX.
4110 */
4111 static int
in_getprefixlen(char * addr,boolean_t slash,int max_plen)4112 in_getprefixlen(char *addr, boolean_t slash, int max_plen)
4113 {
4114 int prefixlen;
4115 char *str, *end;
4116
4117 if (slash) {
4118 str = strchr(addr, '/');
4119 if (str == NULL)
4120 return (NO_PREFIX);
4121 str++;
4122 } else
4123 str = addr;
4124
4125 prefixlen = strtol(str, &end, 10);
4126 if (prefixlen < 0)
4127 return (BAD_ADDR);
4128 if (str == end)
4129 return (BAD_ADDR);
4130 if (max_plen != 0 && max_plen < prefixlen)
4131 return (BAD_ADDR);
4132 return (prefixlen);
4133 }
4134
4135 /*
4136 * Convert a prefix length to a mask.
4137 * Returns 1 if ok. 0 otherwise.
4138 * Assumes the mask array is zero'ed by the caller.
4139 */
4140 static boolean_t
in_prefixlentomask(int prefixlen,int maxlen,uchar_t * mask)4141 in_prefixlentomask(int prefixlen, int maxlen, uchar_t *mask)
4142 {
4143 if (prefixlen < 0 || prefixlen > maxlen)
4144 return (0);
4145
4146 while (prefixlen > 0) {
4147 if (prefixlen >= 8) {
4148 *mask++ = 0xFF;
4149 prefixlen -= 8;
4150 continue;
4151 }
4152 *mask |= 1 << (8 - prefixlen);
4153 prefixlen--;
4154 }
4155 return (1);
4156 }
4157
4158 static void
print_flags(uint64_t flags)4159 print_flags(uint64_t flags)
4160 {
4161 boolean_t first = _B_TRUE;
4162 int cnt, i;
4163
4164 (void) printf("flags=%llx", flags);
4165 cnt = sizeof (if_flags_tbl) / sizeof (if_flags_t);
4166 for (i = 0; i < cnt; i++) {
4167 if (flags & if_flags_tbl[i].iff_value) {
4168 if (first) {
4169 (void) printf("<");
4170 first = _B_FALSE;
4171 } else {
4172 /*
4173 * It has to be here and not with the
4174 * printf below because for the last one,
4175 * we don't want a comma before the ">".
4176 */
4177 (void) printf(",");
4178 }
4179 (void) printf("%s", if_flags_tbl[i].iff_name);
4180 }
4181 }
4182 if (!first)
4183 (void) printf(">");
4184 }
4185
4186 static void
print_config_flags(int af,uint64_t flags)4187 print_config_flags(int af, uint64_t flags)
4188 {
4189 if_config_cmd_t *cmdp;
4190
4191 for (cmdp = if_config_cmd_tbl; cmdp->iff_flag != 0; cmdp++) {
4192 if ((flags & cmdp->iff_flag) &&
4193 (cmdp->iff_af == AF_UNSPEC || cmdp->iff_af == af)) {
4194 (void) printf("%s ", cmdp->iff_name);
4195 }
4196 }
4197 }
4198
4199 /*
4200 * Use the configured directory lookup mechanism (e.g. files/NIS/...)
4201 * to find the network mask. Returns true if we found one to set.
4202 *
4203 * The parameter addr_set controls whether we should get the address of
4204 * the working interface for the netmask query. If addr_set is true,
4205 * we will use the address provided. Otherwise, we will find the working
4206 * interface's address and use it instead.
4207 */
4208 static boolean_t
in_getmask(struct sockaddr_in * saddr,boolean_t addr_set)4209 in_getmask(struct sockaddr_in *saddr, boolean_t addr_set)
4210 {
4211 struct sockaddr_in ifaddr;
4212
4213 /*
4214 * Read the address from the interface if it is not passed in.
4215 */
4216 if (!addr_set) {
4217 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
4218 if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) < 0) {
4219 if (errno != EADDRNOTAVAIL) {
4220 (void) fprintf(stderr, "Need net number for "
4221 "mask\n");
4222 }
4223 return (_B_FALSE);
4224 }
4225 ifaddr = *((struct sockaddr_in *)&lifr.lifr_addr);
4226 } else {
4227 ifaddr.sin_addr = saddr->sin_addr;
4228 }
4229 if (getnetmaskbyaddr(ifaddr.sin_addr, &saddr->sin_addr) == 0) {
4230 saddr->sin_family = AF_INET;
4231 return (_B_TRUE);
4232 }
4233 return (_B_FALSE);
4234 }
4235
4236 static int
lifnum(const char * ifname)4237 lifnum(const char *ifname)
4238 {
4239 const char *cp;
4240
4241 if ((cp = strchr(ifname, ':')) == NULL)
4242 return (0);
4243 else
4244 return (atoi(cp + 1));
4245 }
4246
4247 static void
add_ni(const char * name)4248 add_ni(const char *name)
4249 {
4250 ni_t **pp;
4251 ni_t *p;
4252
4253 for (pp = &ni_list; (p = *pp) != NULL; pp = &(p->ni_next)) {
4254 if (strcmp(p->ni_name, name) == 0) {
4255 if (debug > 2)
4256 (void) fprintf(stderr, "'%s' is a duplicate\n",
4257 name);
4258 return;
4259 }
4260 }
4261
4262 if (debug > 2)
4263 (void) fprintf(stderr, "adding '%s'\n",
4264 name);
4265
4266 if ((p = malloc(sizeof (ni_t))) == NULL)
4267 return;
4268
4269 (void) strlcpy(p->ni_name, name, sizeof (p->ni_name));
4270 p->ni_next = NULL;
4271
4272 *pp = p;
4273 num_ni++;
4274 }
4275
4276 static boolean_t
ni_entry(const char * linkname,void * arg)4277 ni_entry(const char *linkname, void *arg)
4278 {
4279 dlpi_handle_t dh;
4280 datalink_class_t class;
4281
4282 (void) dladm_name2info(arg, linkname, NULL, NULL, &class, NULL);
4283
4284 if (class == DATALINK_CLASS_ETHERSTUB)
4285 return (_B_FALSE);
4286 if (dlpi_open(linkname, &dh, 0) != DLPI_SUCCESS)
4287 return (_B_FALSE);
4288
4289 add_ni(linkname);
4290
4291 dlpi_close(dh);
4292 return (_B_FALSE);
4293 }
4294
4295 /*
4296 * dhcp-related routines
4297 */
4298
4299 static int
setifdhcp(const char * caller,const char * ifname,int argc,char * argv[])4300 setifdhcp(const char *caller, const char *ifname, int argc, char *argv[])
4301 {
4302 dhcp_ipc_request_t *request;
4303 dhcp_ipc_reply_t *reply = NULL;
4304 int timeout = DHCP_IPC_WAIT_DEFAULT;
4305 dhcp_ipc_type_t type = DHCP_START;
4306 int error;
4307 boolean_t is_primary = _B_FALSE;
4308 boolean_t started = _B_FALSE;
4309
4310 for (argv++; --argc > 0; argv++) {
4311
4312 if (strcmp(*argv, "primary") == 0) {
4313 is_primary = _B_TRUE;
4314 continue;
4315 }
4316
4317 if (strcmp(*argv, "wait") == 0) {
4318 if (--argc <= 0) {
4319 usage();
4320 return (DHCP_EXIT_BADARGS);
4321 }
4322 argv++;
4323
4324 if (strcmp(*argv, "forever") == 0) {
4325 timeout = DHCP_IPC_WAIT_FOREVER;
4326 continue;
4327 }
4328
4329 if (sscanf(*argv, "%d", &timeout) != 1) {
4330 usage();
4331 return (DHCP_EXIT_BADARGS);
4332 }
4333
4334 if (timeout < 0) {
4335 usage();
4336 return (DHCP_EXIT_BADARGS);
4337 }
4338 continue;
4339 }
4340
4341 type = dhcp_string_to_request(*argv);
4342 if (type == -1) {
4343 usage();
4344 return (DHCP_EXIT_BADARGS);
4345 }
4346 }
4347
4348 /*
4349 * Only try to start agent on start or inform; in all other cases it
4350 * has to already be running for anything to make sense.
4351 */
4352 if (type == DHCP_START || type == DHCP_INFORM) {
4353 if (dhcp_start_agent(DHCP_IPC_MAX_WAIT) == -1) {
4354 (void) fprintf(stderr, "%s: unable to start %s\n",
4355 caller, DHCP_AGENT_PATH);
4356 return (DHCP_EXIT_FAILURE);
4357 }
4358 started = _B_TRUE;
4359 }
4360
4361 if (is_primary)
4362 type |= DHCP_PRIMARY;
4363
4364 if (af != AF_INET)
4365 type |= DHCP_V6;
4366
4367 request = dhcp_ipc_alloc_request(type, ifname, NULL, 0, DHCP_TYPE_NONE);
4368 if (request == NULL) {
4369 (void) fprintf(stderr, "%s: out of memory\n", caller);
4370 return (DHCP_EXIT_SYSTEM);
4371 }
4372
4373 error = dhcp_ipc_make_request(request, &reply, timeout);
4374 if (error != 0) {
4375 free(request);
4376 /*
4377 * Re-map connect error to not under control if we didn't try a
4378 * start operation, as this has to be true and results in a
4379 * clearer message, not to mention preserving compatibility
4380 * with the days when we always started dhcpagent for every
4381 * request.
4382 */
4383 if (error == DHCP_IPC_E_CONNECT && !started)
4384 error = DHCP_IPC_E_UNKIF;
4385 (void) fprintf(stderr, "%s: %s: %s\n", caller, ifname,
4386 dhcp_ipc_strerror(error));
4387 return (DHCP_EXIT_FAILURE);
4388 }
4389
4390 error = reply->return_code;
4391 if (error != 0) {
4392 free(request);
4393 free(reply);
4394
4395 if (error == DHCP_IPC_E_TIMEOUT && timeout == 0)
4396 return (DHCP_EXIT_SUCCESS);
4397
4398 (void) fprintf(stderr, "%s: %s: %s\n", caller, ifname,
4399 dhcp_ipc_strerror(error));
4400
4401 if (error == DHCP_IPC_E_TIMEOUT)
4402 return (DHCP_EXIT_TIMEOUT);
4403 else
4404 return (DHCP_EXIT_IF_FAILURE);
4405 }
4406
4407 if (DHCP_IPC_CMD(type) == DHCP_STATUS) {
4408 (void) printf("%s", dhcp_status_hdr_string());
4409 (void) printf("%s", dhcp_status_reply_to_string(reply));
4410 }
4411
4412 free(request);
4413 free(reply);
4414 return (DHCP_EXIT_SUCCESS);
4415 }
4416
4417 static void
usage(void)4418 usage(void)
4419 {
4420 (void) fprintf(stderr,
4421 "usage: ifconfig <interface> | -a[ 4 | 6 | D ][ u | d ][ Z ]\n");
4422
4423 (void) fprintf(stderr, "%s",
4424 "\t[ <addr_family> ]\n"
4425 "\t[ <address>[/<prefix_length>] [ <dest_address> ] ]\n"
4426 "\t[ set [ <address>][/<prefix_length>] ]"
4427 " [ <address>/<prefix_length>] ]\n"
4428 "\t[ destination <dest_address> ]\n"
4429 "\t[ addif <address>[/<prefix_length>]"
4430 " [ <dest_address> ] ]\n"
4431 "\t[ removeif <address>[/<prefix_length>] ]\n"
4432 "\t[ arp | -arp ]\n"
4433 "\t[ auto-revarp ]\n"
4434 "\t[ broadcast <broad_addr> ]\n"
4435 "\t[ index <if_index> ]\n"
4436 "\t[ metric <n> ] [ mtu <n> ]\n"
4437 "\t[ netmask <mask> ]\n"
4438 "\t[ plumb ] [ unplumb ]\n"
4439 "\t[ preferred | -preferred ]\n"
4440 "\t[ private | -private ]\n"
4441 "\t[ local | -local ]\n"
4442 "\t[ router | -router ]\n"
4443 "\t[ subnet <subnet_address>]\n"
4444 "\t[ trailers | -trailers ]\n"
4445 "\t[ token <address>/<prefix_length> ]\n"
4446 "\t[ tsrc <tunnel_src_address> ]\n"
4447 "\t[ tdst <tunnel_dest_address> ]\n"
4448 "\t[ auth_algs <tunnel_AH_authentication_algorithm> ]\n"
4449 "\t[ encr_algs <tunnel_ESP_encryption_algorithm> ]\n"
4450 "\t[ encr_auth_algs <tunnel_ESP_authentication_algorithm> ]\n"
4451 "\t[ up ] [ down ]\n"
4452 "\t[ xmit | -xmit ]\n"
4453 "\t[ modlist ]\n"
4454 "\t[ modinsert <module_name@position> ]\n"
4455 "\t[ modremove <module_name@position> ]\n"
4456 "\t[ ipmp ]\n"
4457 "\t[ group <groupname>] | [ group \"\"]\n"
4458 "\t[ deprecated | -deprecated ]\n"
4459 "\t[ standby | -standby ]\n"
4460 "\t[ failover | -failover ]\n"
4461 "\t[ zone <zonename> | -zone ]\n"
4462 "\t[ usesrc <interface> ]\n"
4463 "\t[ all-zones ]\n");
4464
4465 (void) fprintf(stderr, "or\n");
4466 (void) fprintf(stderr,
4467 "\tifconfig <interface> | -a[ 4 | 6 | D ] [ u | d ]\n");
4468
4469 (void) fprintf(stderr, "%s", "\tauto-dhcp | dhcp\n"
4470 "\t[ wait <time> | forever ]\n\t[ primary ]\n"
4471 "\tstart | drop | ping | release | status | inform\n");
4472 }
4473