2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
6 * Copyright (c) 1983 Regents of the University of California.
7 * All rights reserved. The Berkeley software License Agreement
8 * specifies the terms and conditions for redistribution.
17 #include <inet/ipsec_impl.h>
19 #define LOOPBACK_IF "lo0"
20 #define NONE_STR "none"
21 #define ARP_MOD_NAME "arp"
22 #define TUN_NAME "tun"
23 #define ATUN_NAME "atun"
24 #define TUN6TO4_NAME "6to4tun"
26 typedef struct if_flags
{
31 static if_flags_t if_flags_tbl
[] = {
33 { IFF_BROADCAST
, "BROADCAST" },
34 { IFF_DEBUG
, "DEBUG" },
35 { IFF_LOOPBACK
, "LOOPBACK" },
36 { IFF_POINTOPOINT
, "POINTOPOINT" },
37 { IFF_NOTRAILERS
, "NOTRAILERS" },
38 { IFF_RUNNING
, "RUNNING" },
39 { IFF_NOARP
, "NOARP" },
40 { IFF_PROMISC
, "PROMISC" },
41 { IFF_ALLMULTI
, "ALLMULTI" },
42 { IFF_INTELLIGENT
, "INTELLIGENT" },
43 { IFF_MULTICAST
, "MULTICAST" },
44 { IFF_MULTI_BCAST
, "MULTI_BCAST" },
45 { IFF_UNNUMBERED
, "UNNUMBERED" },
46 { IFF_DHCPRUNNING
, "DHCP" },
47 { IFF_PRIVATE
, "PRIVATE" },
48 { IFF_NOXMIT
, "NOXMIT" },
49 { IFF_NOLOCAL
, "NOLOCAL" },
50 { IFF_DEPRECATED
, "DEPRECATED" },
51 { IFF_ADDRCONF
, "ADDRCONF" },
52 { IFF_ROUTER
, "ROUTER" },
53 { IFF_NONUD
, "NONUD" },
54 { IFF_ANYCAST
, "ANYCAST" },
55 { IFF_NORTEXCH
, "NORTEXCH" },
58 { IFF_NOFAILOVER
, "NOFAILOVER" },
59 { IFF_FAILED
, "FAILED" },
60 { IFF_STANDBY
, "STANDBY" },
61 { IFF_INACTIVE
, "INACTIVE" },
62 { IFF_OFFLINE
, "OFFLINE" },
63 { IFF_XRESOLV
, "XRESOLV" },
64 { IFF_COS_ENABLED
, "CoS" },
65 { IFF_PREFERRED
, "PREFERRED" },
66 { IFF_TEMPORARY
, "TEMPORARY" },
67 { IFF_FIXEDMTU
, "FIXEDMTU" },
68 { IFF_VIRTUAL
, "VIRTUAL" },
69 { IFF_DUPLICATE
, "DUPLICATE" }
72 static struct lifreq lifr
;
73 /* current interface name a particular function is accessing */
74 static char name
[LIFNAMSIZ
];
75 /* foreach interface saved name */
76 static char origname
[LIFNAMSIZ
];
77 static char savedname
[LIFNAMSIZ
]; /* For addif */
81 * Make sure the algorithm variables hold more than the sizeof an algorithm
82 * in PF_KEY. (For now, more than a uint8_t.) The NO_***_?ALG indicates that
83 * there was no algorithm requested, and in the ipsec_req that service should
84 * be disabled. (E.g. if ah_aalg remains NO_AH_AALG, then AH will be
85 * disabled on that tunnel.)
87 #define NO_AH_AALG 256
88 #define NO_ESP_AALG 256
89 #define NO_ESP_EALG 256
93 * used by setifether to create a list of interfaces to mark
94 * down-up when changing the ethernet address of an interface
96 typedef struct iface
{
98 struct iface
*next
; /* pointer to the next list element */
101 static iface_t
*logifs
= NULL
; /* list of logical interfaces */
102 static iface_t
*phyif
= NULL
; /* physical interface */
105 int af
= AF_INET
; /* default address family */
107 int all
= 0; /* setifdhcp() needs to know this */
109 int v4compat
= 0; /* Compatible printing format */
112 * Function prototypes for command functions.
114 static int addif(char *arg
, int64_t param
);
115 static int inetplumb(char *arg
, int64_t param
);
116 static int inetunplumb(char *arg
, int64_t param
);
117 static int removeif(char *arg
, int64_t param
);
118 static int setdebugflag(char *arg
, int64_t param
);
119 static int setifaddr(char *arg
, int64_t param
);
120 static int setifbroadaddr(char *arg
, int64_t param
);
121 static int setifdstaddr(char *arg
, int64_t param
);
122 static int setifether(char *arg
, int64_t param
);
123 static int setifflags(char *arg
, int64_t param
);
124 static int setifindex(char *arg
, int64_t param
);
125 static int setifmetric(char *arg
, int64_t param
);
126 static int setifmtu(char *arg
, int64_t param
);
127 static int setifnetmask(char *arg
, int64_t param
);
128 static int setifprefixlen(char *arg
, int64_t param
);
129 static int setifrevarp(char *arg
, int64_t param
);
130 static int setifsubnet(char *arg
, int64_t param
);
131 static int setiftdst(char *arg
, int64_t param
);
132 static int setiftoken(char *arg
, int64_t param
);
133 static int setiftsrc(char *arg
, int64_t param
);
134 static int setverboseflag(char *arg
, int64_t param
);
135 static int set_tun_ah_alg(char *arg
, int64_t param
);
136 static int set_tun_esp_auth_alg(char *arg
, int64_t param
);
137 static int set_tun_esp_encr_alg(char *arg
, int64_t param
);
138 static int modlist(char *arg
, int64_t param
);
139 static int modinsert(char *arg
, int64_t param
);
140 static int modremove(char *arg
, int64_t param
);
141 static int setifgroupname(char *arg
, int64_t param
);
142 static int configinfo(char *arg
, int64_t param
);
143 static void print_config_flags(uint64_t flags
);
144 static void print_flags(uint64_t flags
);
145 static void print_ifether(char *ifname
);
146 static int set_tun_encap_limit(char *arg
, int64_t param
);
147 static int clr_tun_encap_limit(char *arg
, int64_t param
);
148 static int set_tun_hop_limit(char *arg
, int64_t param
);
149 static int setzone(char *arg
, int64_t param
);
150 static int setallzones(char *arg
, int64_t param
);
151 static int setifsrc(char *arg
, int64_t param
);
154 * Address family specific function prototypes.
156 static void in_getaddr(char *s
, struct sockaddr
*saddr
, int *plenp
);
157 static void in_status(int force
, uint64_t flags
);
158 static void in_configinfo(int force
, uint64_t flags
);
159 static void in6_getaddr(char *s
, struct sockaddr
*saddr
, int *plenp
);
160 static void in6_status(int force
, uint64_t flags
);
161 static void in6_configinfo(int force
, uint64_t flags
);
164 * Misc support functions
166 static boolean_t
ni_entry(const char *, void *);
167 static void foreachinterface(void (*func
)(), int argc
, char *argv
[],
168 int af
, int64_t onflags
, int64_t offflags
,
170 static void ifconfig(int argc
, char *argv
[], int af
, struct lifreq
*lifrp
);
171 static boolean_t
in_getmask(struct sockaddr_in
*saddr
,
173 static int in_getprefixlen(char *addr
, boolean_t slash
, int plen
);
174 static boolean_t
in_prefixlentomask(int prefixlen
, int maxlen
,
176 static int settaddr(char *, int (*)(icfg_handle_t
,
177 const struct sockaddr
*, socklen_t
));
178 static void status(void);
179 static void ifstatus(const char *);
180 static void usage(void);
181 static int strioctl(int s
, int cmd
, char *buf
, int buflen
);
182 static int setifdhcp(const char *caller
, const char *ifname
,
183 int argc
, char *argv
[]);
184 static int ip_domux2fd(int *, int *, int *, int *, int *);
185 static int ip_plink(int, int, int, int, int);
186 static int modop(char *arg
, char op
);
187 static void selectifs(int argc
, char *argv
[], int af
,
188 struct lifreq
*lifrp
);
189 static int updownifs(iface_t
*ifs
, int up
);
190 static int find_all_global_interfaces(struct lifconf
*lifcp
, char **buf
,
192 static int find_all_zone_interfaces(struct lifconf
*lifcp
, char **buf
,
195 #define max(a, b) ((a) < (b) ? (b) : (a))
198 * DHCP_EXIT_IF_FAILURE indicates that the operation failed, but if there
199 * are more interfaces to act on (i.e., ifconfig was invoked with -a), keep
200 * on going rather than exit with an error.
203 #define DHCP_EXIT_IF_FAILURE -1
205 #define NEXTARG 0xffffff /* command takes an argument */
206 #define OPTARG 0xfffffe /* command takes an optional argument */
209 /* Refer to the comments in ifconfig() on the netmask "hack" */
210 #define NETMASK_CMD "netmask"
211 struct sockaddr_storage g_netmask
;
212 enum { G_NETMASK_NIL
, G_NETMASK_PENDING
, G_NETMASK_SET
}
213 g_netmask_set
= G_NETMASK_NIL
;
217 int64_t c_parameter
; /* NEXTARG means next argv */
218 int (*c_func
)(char *, int64_t);
219 int c_abortonfail
; /* don't continue parsing args */
220 /* for the current interface */
221 int c_af
; /* address family restrictions */
223 { "up", IFF_UP
, setifflags
, 0, AF_ANY
},
224 { "down", -IFF_UP
, setifflags
, 0, AF_ANY
},
225 { "trailers", -IFF_NOTRAILERS
, setifflags
, 0, AF_ANY
},
226 { "-trailers", IFF_NOTRAILERS
, setifflags
, 0, AF_ANY
},
227 { "arp", -IFF_NOARP
, setifflags
, 0, AF_INET
},
228 { "-arp", IFF_NOARP
, setifflags
, 0, AF_INET
},
229 { "router", IFF_ROUTER
, setifflags
, 0, AF_ANY
},
230 { "-router", -IFF_ROUTER
, setifflags
, 0, AF_ANY
},
231 { "private", IFF_PRIVATE
, setifflags
, 0, AF_ANY
},
232 { "-private", -IFF_PRIVATE
, setifflags
, 0, AF_ANY
},
233 { "xmit", -IFF_NOXMIT
, setifflags
, 0, AF_ANY
},
234 { "-xmit", IFF_NOXMIT
, setifflags
, 0, AF_ANY
},
235 { "-nud", IFF_NONUD
, setifflags
, 0, AF_INET6
},
236 { "nud", -IFF_NONUD
, setifflags
, 0, AF_INET6
},
237 { "anycast", IFF_ANYCAST
, setifflags
, 0, AF_ANY
},
238 { "-anycast", -IFF_ANYCAST
, setifflags
, 0, AF_ANY
},
239 { "local", -IFF_NOLOCAL
, setifflags
, 0, AF_ANY
},
240 { "-local", IFF_NOLOCAL
, setifflags
, 0, AF_ANY
},
241 { "deprecated", IFF_DEPRECATED
, setifflags
, 0, AF_ANY
},
242 { "-deprecated", -IFF_DEPRECATED
, setifflags
, 0, AF_ANY
},
243 { "preferred", IFF_PREFERRED
, setifflags
, 0, AF_INET6
},
244 { "-preferred", -IFF_PREFERRED
, setifflags
, 0, AF_INET6
},
245 { "debug", 0, setdebugflag
, 0, AF_ANY
},
246 { "verbose", 0, setverboseflag
, 0, AF_ANY
},
247 { NETMASK_CMD
, NEXTARG
, setifnetmask
, 0, AF_INET
},
248 { "metric", NEXTARG
, setifmetric
, 0, AF_ANY
},
249 { "mtu", NEXTARG
, setifmtu
, 0, AF_ANY
},
250 { "index", NEXTARG
, setifindex
, 0, AF_ANY
},
251 { "broadcast", NEXTARG
, setifbroadaddr
, 0, AF_INET
},
252 { "auto-revarp", 0, setifrevarp
, 1, AF_INET
},
253 { "plumb", 0, inetplumb
, 1, AF_ANY
},
254 { "unplumb", 0, inetunplumb
, 0, AF_ANY
},
255 { "subnet", NEXTARG
, setifsubnet
, 0, AF_ANY
},
256 { "token", NEXTARG
, setiftoken
, 0, AF_INET6
},
257 { "tsrc", NEXTARG
, setiftsrc
, 0, AF_ANY
},
258 { "tdst", NEXTARG
, setiftdst
, 0, AF_ANY
},
259 { "encr_auth_algs", NEXTARG
, set_tun_esp_auth_alg
, 0, AF_ANY
},
260 { "encr_algs", NEXTARG
, set_tun_esp_encr_alg
, 0, AF_ANY
},
261 { "auth_algs", NEXTARG
, set_tun_ah_alg
, 0, AF_ANY
},
262 { "addif", NEXTARG
, addif
, 1, AF_ANY
},
263 { "removeif", NEXTARG
, removeif
, 1, AF_ANY
},
264 { "modlist", 0, modlist
, 1, AF_ANY
},
265 { "modinsert", NEXTARG
, modinsert
, 1, AF_ANY
},
266 { "modremove", NEXTARG
, modremove
, 1, AF_ANY
},
267 { "failover", -IFF_NOFAILOVER
, setifflags
, 1, AF_ANY
},
268 { "-failover", IFF_NOFAILOVER
, setifflags
, 1, AF_ANY
},
269 { "standby", IFF_STANDBY
, setifflags
, 1, AF_ANY
},
270 { "-standby", -IFF_STANDBY
, setifflags
, 1, AF_ANY
},
271 { "failed", IFF_FAILED
, setifflags
, 1, AF_ANY
},
272 { "-failed", -IFF_FAILED
, setifflags
, 1, AF_ANY
},
273 { "group", NEXTARG
, setifgroupname
, 1, AF_ANY
},
274 { "configinfo", 0, configinfo
, 1, AF_ANY
},
275 { "encaplimit", NEXTARG
, set_tun_encap_limit
, 0, AF_ANY
},
276 { "-encaplimit", 0, clr_tun_encap_limit
, 0, AF_ANY
},
277 { "thoplimit", NEXTARG
, set_tun_hop_limit
, 0, AF_ANY
},
278 { "set", NEXTARG
, setifaddr
, 0, AF_ANY
},
279 { "destination", NEXTARG
, setifdstaddr
, 0, AF_ANY
},
280 { "zone", NEXTARG
, setzone
, 0, AF_ANY
},
281 { "-zone", 0, setzone
, 0, AF_ANY
},
282 { "all-zones", 0, setallzones
, 0, AF_ANY
},
283 { "ether", OPTARG
, setifether
, 0, AF_ANY
},
284 { "usesrc", NEXTARG
, setifsrc
, 0, AF_ANY
},
287 * NOTE: any additions to this table must also be applied to ifparse
288 * (usr/src/cmd/cmd-inet/sbin/ifparse/ifparse.c)
291 { 0, 0, setifaddr
, 0, AF_ANY
},
292 { 0, 0, setifdstaddr
, 0, AF_ANY
},
297 typedef struct if_config_cmd
{
302 static if_config_cmd_t if_config_cmd_tbl
[] = {
304 { IFF_NOTRAILERS
, "-trailers" },
305 { IFF_PRIVATE
, "private" },
306 { IFF_NOXMIT
, "-xmit" },
307 { IFF_ANYCAST
, "anycast" },
308 { IFF_NOLOCAL
, "-local" },
309 { IFF_DEPRECATED
, "deprecated" },
310 { IFF_NOFAILOVER
, "-failover" },
311 { IFF_STANDBY
, "standby" },
312 { IFF_FAILED
, "failed" },
313 { IFF_PREFERRED
, "preferred" },
318 char ni_name
[LIFNAMSIZ
];
322 static ni_t
*ni_list
= NULL
;
323 static int num_ni
= 0;
325 /* End defines and structure definitions for ifconfig -a plumb */
327 /* Known address families */
332 void (*af_getaddr
)();
333 void (*af_configinfo
)();
335 { "inet", AF_INET
, in_status
, in_getaddr
, in_configinfo
},
336 { "inet6", AF_INET6
, in6_status
, in6_getaddr
, in6_configinfo
},
340 #define SOCKET_AF(af) (((af) == AF_UNSPEC) ? AF_INET : (af))
342 struct afswtch
*afp
; /* the address family being set or asked about */
345 main(int argc
, char *argv
[])
347 /* Include IFF_NOXMIT, IFF_TEMPORARY and all zone interfaces */
348 int64_t lifc_flags
= LIFC_NOXMIT
| LIFC_TEMPORARY
| LIFC_ALLZONES
;
349 char *default_ip_str
;
356 if (strlen(*argv
) > sizeof (name
) - 1) {
357 (void) fprintf(stderr
, "%s: interface name too long\n", *argv
);
360 (void) strncpy(name
, *argv
, sizeof (name
));
361 name
[sizeof (name
) - 1] = '\0';
362 (void) strncpy(origname
, name
, sizeof (origname
)); /* For addif */
363 default_ip_str
= NULL
;
364 v4compat
= get_compat_flag(&default_ip_str
);
365 if (v4compat
== DEFAULT_PROT_BAD_VALUE
) {
366 (void) fprintf(stderr
,
367 "ifconfig: %s: Bad value for %s in %s\n", default_ip_str
,
368 DEFAULT_IP
, INET_DEFAULT_FILE
);
369 free(default_ip_str
);
372 free(default_ip_str
);
375 struct afswtch
*myafp
;
377 for (myafp
= afp
= afs
; myafp
->af_name
; myafp
++) {
378 if (strcmp(myafp
->af_name
, *argv
) == 0) {
379 afp
= myafp
; argc
--; argv
++;
383 af
= lifr
.lifr_addr
.ss_family
= afp
->af_af
;
384 if (af
== AF_INET6
) {
389 s
= socket(SOCKET_AF(af
), SOCK_DGRAM
, 0);
391 Perror0_exit("socket");
395 * Special interface names is any combination of these flags.
396 * Note that due to the ifconfig syntax they have to be combined
397 * as a single '-' option.
400 * -d "down" interfaces
401 * -D Interfaces not controlled by DHCP
404 * -X Turn on debug (not documented)
406 * -Z Only interfaces in caller's zone
409 if (name
[0] == '-') {
410 /* One or more options */
412 int64_t offflags
= 0;
414 char *av
[2] = { "ifconfig", name
};
416 while ((c
= getopt(2, av
, "audDXZ46v")) != -1) {
428 offflags
|= IFF_DHCPRUNNING
;
434 lifc_flags
&= ~LIFC_ALLZONES
;
438 * -4 is not a compatable flag, therefore
439 * we assume they want v4compat turned off
446 * If they want IPv6, well then we'll assume
447 * they don't want IPv4 compat
461 (void) fprintf(stderr
,
462 "ifconfig: %s: no such interface\n", name
);
465 foreachinterface(ifconfig
, argc
, argv
, af
, onflags
, offflags
,
468 ifconfig(argc
, argv
, af
, (struct lifreq
*)NULL
);
474 * For each interface, call (*func)(argc, argv, af, lifrp).
475 * Only call function if onflags and offflags are set or clear, respectively,
476 * in the interfaces flags field.
479 foreachinterface(void (*func
)(), int argc
, char *argv
[], int af
,
480 int64_t onflags
, int64_t offflags
, int64_t lifc_flags
)
486 struct lifreq
*lifrp
;
487 struct lifreq lifrl
; /* Local lifreq struct */
496 * ifconfig -a plumb should find all network interfaces
497 * in the machine for the global zone.
498 * For non-global zones, only find the assigned interfaces.
499 * Also, there is no need to SIOCGLIF* ioctls, since
500 * those interfaces have already been plumbed
502 if (argc
> 0 && (strcmp(*argv
, "plumb") == 0)) {
503 if (getzoneid() == GLOBAL_ZONEID
) {
504 if (find_all_global_interfaces(&lifc
, &buf
,
508 if (find_all_zone_interfaces(&lifc
, &buf
,
512 if (lifc
.lifc_len
== 0)
516 lifn
.lifn_family
= AF_UNSPEC
;
517 lifn
.lifn_flags
= lifc_flags
;
518 if (ioctl(s
, SIOCGLIFNUM
, (char *)&lifn
) < 0) {
519 Perror0_exit("Could not determine number"
522 numifs
= lifn
.lifn_count
;
524 (void) printf("ifconfig: %d interfaces\n", numifs
);
526 bufsize
= numifs
* sizeof (struct lifreq
);
527 if ((buf
= malloc(bufsize
)) == NULL
) {
528 Perror0("out of memory\n");
533 lifc
.lifc_family
= AF_UNSPEC
;
534 lifc
.lifc_flags
= lifc_flags
;
535 lifc
.lifc_len
= bufsize
;
538 if (ioctl(s
, SIOCGLIFCONF
, (char *)&lifc
) < 0) {
539 Perror0("SIOCGLIFCONF");
546 lifrp
= lifc
.lifc_req
;
547 for (n
= lifc
.lifc_len
/ sizeof (struct lifreq
); n
> 0; n
--, lifrp
++) {
551 * We must close and recreate the socket each time
552 * since we don't know what type of socket it is now
553 * (each status function may change it).
558 af
= lifrp
->lifr_addr
.ss_family
;
559 s
= socket(SOCKET_AF(af
), SOCK_DGRAM
, 0);
562 * Perror0() assumes the name to be in the
563 * globally defined lifreq structure.
565 (void) strncpy(lifr
.lifr_name
,
566 lifrp
->lifr_name
, sizeof (lifr
.lifr_name
));
567 Perror0_exit("socket");
572 * Only service interfaces that match the on and off
575 if (onflags
|| offflags
) {
576 (void) memset(&lifrl
, 0, sizeof (lifrl
));
577 (void) strncpy(lifrl
.lifr_name
, lifrp
->lifr_name
,
578 sizeof (lifrl
.lifr_name
));
579 if (ioctl(s
, SIOCGLIFFLAGS
, (caddr_t
)&lifrl
) < 0) {
581 * Perror0() assumes the name to be in the
582 * globally defined lifreq structure.
584 (void) strncpy(lifr
.lifr_name
,
585 lifrp
->lifr_name
, sizeof (lifr
.lifr_name
));
586 Perror0_exit("foreachinterface: SIOCGLIFFLAGS");
588 if ((lifrl
.lifr_flags
& onflags
) != onflags
)
590 if ((~lifrl
.lifr_flags
& offflags
) != offflags
)
595 (void) strncpy(lifrl
.lifr_name
, lifrp
->lifr_name
,
596 sizeof (lifrl
.lifr_name
));
597 if (ioctl(s
, SIOCGLIFADDR
, (caddr_t
)&lifrl
) < 0) {
599 * Perror0() assumes the name to be in the
600 * globally defined lifreq structure.
602 (void) strncpy(lifr
.lifr_name
,
603 lifrp
->lifr_name
, sizeof (lifr
.lifr_name
));
604 Perror0("foreachinterface: SIOCGLIFADDR");
607 if (lifrl
.lifr_addr
.ss_family
!= af
) {
608 /* Switch address family */
609 af
= lifrl
.lifr_addr
.ss_family
;
612 s
= socket(SOCKET_AF(af
), SOCK_DGRAM
, 0);
615 * Perror0() assumes the name to be in
616 * the globally defined lifreq
619 (void) strncpy(lifr
.lifr_name
,
621 sizeof (lifr
.lifr_name
));
622 Perror0_exit("socket");
629 * setaddr: Used by parser to tear apart source and dest
630 * name and origname contain the name of the 'current'
634 (void) strncpy(name
, lifrp
->lifr_name
, sizeof (name
));
635 (void) strncpy(origname
, name
, sizeof (origname
));
637 (*func
)(argc
, argv
, save_af
, lifrp
);
638 /* the func could have overwritten origname, so restore */
639 (void) strncpy(name
, origname
, sizeof (name
));
646 tun_reality_check(void)
648 struct iftun_req treq
;
651 (void) strncpy(treq
.ifta_lifr_name
, name
, sizeof (treq
.ifta_lifr_name
));
652 if (strchr(name
, ':') != NULL
) {
653 /* Return, we don't need to check. */
656 if (ioctl(s
, SIOCGTUNPARAM
, (caddr_t
)&treq
) < 0 ||
657 !(treq
.ifta_flags
& IFTUN_SECURITY
) ||
658 (treq
.ifta_flags
& IFTUN_COMPLEX_SECURITY
)) {
660 * Either not a tunnel (the SIOCGTUNPARAM fails on
661 * non-tunnels), the security flag is not set, or
662 * this is a tunnel with ipsecconf(1M)-set policy.
663 * Regardless, return.
668 ipsr
= (ipsec_req_t
*)&treq
.ifta_secinfo
;
670 if (ipsr
->ipsr_esp_req
!= 0 &&
671 ipsr
->ipsr_esp_auth_alg
== SADB_AALG_NONE
&&
672 ipsr
->ipsr_ah_req
== 0)
673 (void) fprintf(stderr
, "ifconfig: WARNING - tunnel with "
674 "only ESP and no authentication.\n");
678 * for the specified interface call (*func)(argc, argv, af, lifrp).
682 ifconfig(int argc
, char *argv
[], int af
, struct lifreq
*lifrp
)
684 static boolean_t scan_netmask
= _B_FALSE
;
692 if (strcmp(*argv
, "auto-dhcp") == 0 || strcmp(*argv
, "dhcp") == 0) {
694 * Some errors are ignored in the case where more than one
695 * interface is being operated on.
697 ret
= setifdhcp("ifconfig", name
, argc
, argv
);
698 if (ret
== DHCP_EXIT_IF_FAILURE
) {
700 exit(DHCP_EXIT_FAILURE
);
701 } else if (ret
!= DHCP_EXIT_SUCCESS
) {
708 * The following is a "hack" to get around the existing interface
709 * setting mechanism. Currently, each interface attribute,
710 * such as address, netmask, broadcast, ... is set separately. But
711 * sometimes two or more attributes must be set together. For
712 * example, setting an address without a netmask does not make sense.
713 * Yet they can be set separately for IPv4 address using the current
714 * ifconfig(1M) syntax. The kernel then "infers" the correct netmask
715 * using the deprecated "IP address classes." This is simply not
718 * The "hack" below is to go thru the whole command list looking for
719 * the netmask command first. Then use this netmask to set the
720 * address. This does not provide an extensible way to accommodate
721 * future need for setting more than one attributes together.
723 * Note that if the "netmask" command argument is a "+", we need
724 * to save this info and do the query after we know the address to
725 * be set. The reason is that if "addif" is used, the working
726 * interface name will be changed later when the logical interface
727 * is created. In in_getmask(), if an address is not provided,
728 * it will use the working interface's address to do the query.
729 * It will be wrong now as we don't know the logical interface's name.
731 * ifconfig(1M) is too overloaded and the code is so convoluted
732 * that it is "safer" not to re-architect the code to fix the above
733 * issue, hence this "hack." We may be better off to have a new
734 * command with better syntax for configuring network interface
737 if (!scan_netmask
&& afp
->af_af
== AF_INET
) {
741 /* Only go thru the command list once to find the netmask. */
742 scan_netmask
= _B_TRUE
;
745 * Currently, if multiple netmask commands are specified, the
746 * last one will be used as the final netmask. So we need
747 * to scan the whole list to preserve this behavior.
749 for (largc
= argc
, largv
= argv
; largc
> 0; largc
--, largv
++) {
750 if (strcmp(*largv
, NETMASK_CMD
) == 0) {
754 if (strcmp(*largv
, "+") == 0) {
755 g_netmask_set
= G_NETMASK_PENDING
;
757 in_getaddr(*largv
, (struct sockaddr
*)
759 g_netmask_set
= G_NETMASK_SET
;
761 /* Continue the scan. */
771 (void) printf("ifconfig: argv %s\n", *argv
);
773 found_cmd
= _B_FALSE
;
774 for (p
= cmds
; p
->c_func
; p
++) {
776 if (strcmp(*argv
, p
->c_name
) == 0) {
778 * indicate that the command was
779 * found and check to see if
780 * the address family is valid
783 if (p
->c_af
== AF_ANY
||
788 if (p
->c_af
== AF_ANY
||
794 * If we found the keyword, but the address family
795 * did not match spit out an error
797 if (found_cmd
&& p
->c_name
== 0) {
798 (void) fprintf(stderr
, "ifconfig: Operation %s not"
799 " supported for %s\n", *argv
, afp
->af_name
);
803 * else (no keyword found), we assume it's an address
806 if (p
->c_name
== 0 && setaddr
)
807 p
++; /* got src, do dst */
809 if (p
->c_af
== AF_INET6
) {
812 if (p
->c_parameter
== NEXTARG
||
813 p
->c_parameter
== OPTARG
) {
815 if (argc
== 0 && p
->c_parameter
== NEXTARG
) {
816 (void) fprintf(stderr
,
817 "ifconfig: no argument for %s\n",
823 * Call the function if:
825 * there's no address family
828 * we don't know the address yet
829 * (because we were called from
832 * there is a restriction AND
833 * the address families match
835 if ((p
->c_af
== AF_ANY
) ||
836 (lifrp
== (struct lifreq
*)NULL
) ||
837 (lifrp
->lifr_addr
.ss_family
== p
->c_af
)) {
838 ret
= (*p
->c_func
)(*argv
, p
->c_parameter
);
840 * If c_func failed and we should
841 * abort processing for this
842 * interface on failure, return
843 * now rather than going on to
844 * process other commands for
845 * the same interface.
847 if (ret
!= 0 && p
->c_abortonfail
)
854 /* Check to see if there's a security hole in the tunnel setup. */
860 setdebugflag(char *val
, int64_t arg
)
868 setverboseflag(char *val
, int64_t arg
)
875 * This function fills in the given lifreq's lifr_addr field based on
879 set_mask_lifreq(struct lifreq
*lifr
, struct sockaddr_storage
*addr
,
880 struct sockaddr_storage
*mask
)
882 assert(addr
!= NULL
);
883 assert(mask
!= NULL
);
885 switch (g_netmask_set
) {
887 lifr
->lifr_addr
= g_netmask
;
890 case G_NETMASK_PENDING
:
892 * "+" is used as the argument to "netmask" command. Query
893 * the database on the correct netmask based on the address to
896 assert(afp
->af_af
== AF_INET
);
898 if (!in_getmask((struct sockaddr_in
*)&g_netmask
, _B_TRUE
)) {
899 lifr
->lifr_addr
= *mask
;
900 g_netmask_set
= G_NETMASK_NIL
;
902 lifr
->lifr_addr
= g_netmask
;
903 g_netmask_set
= G_NETMASK_SET
;
909 lifr
->lifr_addr
= *mask
;
915 * Set the interface address. Handles <addr>, <addr>/<n> as well as /<n>
916 * syntax for setting the address, the address plus netmask, and just
917 * the netmask respectively.
921 setifaddr(char *addr
, int64_t param
)
924 struct sockaddr_storage laddr
;
925 struct sockaddr_storage netmask
;
926 struct sockaddr_in6
*sin6
;
927 struct sockaddr_in
*sin
;
928 struct sockaddr_storage sav_netmask
;
931 return (setifprefixlen(addr
, 0));
933 (*afp
->af_getaddr
)(addr
, (struct sockaddr
*)&laddr
, &prefixlen
);
935 (void) memset(&netmask
, 0, sizeof (netmask
));
936 netmask
.ss_family
= afp
->af_af
;
939 /* Nothing there - ok */
942 (void) fprintf(stderr
, "ifconfig: Bad prefix length in %s\n",
946 if (afp
->af_af
== AF_INET6
) {
947 sin6
= (struct sockaddr_in6
*)&netmask
;
948 if (!in_prefixlentomask(prefixlen
, IPV6_ABITS
,
949 (uchar_t
*)&sin6
->sin6_addr
)) {
950 (void) fprintf(stderr
, "ifconfig: "
951 "Bad prefix length: %d\n",
956 sin
= (struct sockaddr_in
*)&netmask
;
957 if (!in_prefixlentomask(prefixlen
, IP_ABITS
,
958 (uchar_t
*)&sin
->sin_addr
)) {
959 (void) fprintf(stderr
, "ifconfig: "
960 "Bad prefix length: %d\n",
966 * Just in case of funny setting of both prefix and netmask,
967 * prefix should override the netmask command.
969 g_netmask_set
= G_NETMASK_NIL
;
972 /* Tell parser that an address was set */
974 /* save copy of netmask to restore in case of error */
975 (void) strncpy(lifr
.lifr_name
, name
, sizeof (lifr
.lifr_name
));
976 if (ioctl(s
, SIOCGLIFNETMASK
, (caddr_t
)&lifr
) < 0)
977 Perror0_exit("SIOCGLIFNETMASK");
978 sav_netmask
= lifr
.lifr_addr
;
981 * If setting the address and not the mask, clear any existing mask
982 * and the kernel will then assign the default (netmask has been set
983 * to 0 in this case). If setting both (either by using a prefix or
984 * using the netmask command), set the mask first, so the address will
985 * be interpreted correctly.
987 set_mask_lifreq(&lifr
, &laddr
, &netmask
);
988 if (ioctl(s
, SIOCSLIFNETMASK
, (caddr_t
)&lifr
) < 0)
989 Perror0_exit("SIOCSLIFNETMASK");
992 char abuf
[INET6_ADDRSTRLEN
];
993 void *addr
= (afp
->af_af
== AF_INET
) ?
994 (void *)&((struct sockaddr_in
*)&laddr
)->sin_addr
:
995 (void *)&((struct sockaddr_in6
*)&laddr
)->sin6_addr
;
997 (void) printf("Setting %s af %d addr %s\n",
998 lifr
.lifr_name
, afp
->af_af
,
999 inet_ntop(afp
->af_af
, addr
, abuf
, sizeof (abuf
)));
1001 lifr
.lifr_addr
= laddr
;
1002 lifr
.lifr_addr
.ss_family
= afp
->af_af
;
1003 if (ioctl(s
, SIOCSLIFADDR
, (caddr_t
)&lifr
) < 0) {
1005 * Restore the netmask
1009 (void) strncpy(lifr
.lifr_name
, name
, sizeof (lifr
.lifr_name
));
1010 lifr
.lifr_addr
= sav_netmask
;
1011 (void) ioctl(s
, SIOCSLIFNETMASK
, (caddr_t
)&lifr
);
1013 Perror0_exit("SIOCSLIFADDR");
1020 * The following functions are stolen from the ipseckey(1m) program.
1021 * Perhaps they should be somewhere common, but for now, we just maintain
1022 * two versions. We do this because of the different semantics for which
1023 * algorithms we select ("requested" for ifconfig vs. "actual" for key).
1033 rc
= strtoul(num
, &end
, 0);
1034 if (errno
!= 0 || end
== num
|| *end
!= '\0') {
1042 * Parse and reverse parse possible algorithm values, include numbers.
1043 * Mostly stolen from ipseckey.c. See the comments above parsenum() for why
1044 * this isn't common to ipseckey.c.
1046 * NOTE: Static buffer in this function for the return value. Since ifconfig
1047 * isn't multithreaded, this isn't a huge problem.
1050 #define NBUF_SIZE 20 /* Enough to print a large integer. */
1053 rparsealg(uint8_t alg_value
, int proto_num
)
1055 struct ipsecalgent
*alg
;
1056 static char numprint
[128]; /* Enough to hold an algorithm name. */
1059 * Special cases for "any" and "none"
1060 * The kernel needs to be able to distinguish between "any"
1061 * and "none" and the APIs are underdefined in this area for auth.
1063 if (proto_num
== IPSEC_PROTO_AH
) {
1064 if (alg_value
== SADB_AALG_NONE
)
1066 if (alg_value
== SADB_AALG_ANY
)
1070 alg
= getipsecalgbynum(alg_value
, proto_num
, NULL
);
1072 (void) strlcpy(numprint
, alg
->a_names
[0], sizeof (numprint
));
1073 freeipsecalgent(alg
);
1075 (void) snprintf(numprint
, sizeof (numprint
), "%d", alg_value
);
1082 parsealg(char *algname
, int proto_num
)
1084 struct ipsecalgent
*alg
;
1087 if (algname
== NULL
) {
1088 (void) fprintf(stderr
, "ifconfig: Unexpected end of command "
1094 * Special-case "none" and "any".
1095 * Use strcasecmp because its length is bounded.
1097 if (strcasecmp("none", algname
) == 0) {
1098 return ((proto_num
== IPSEC_PROTO_ESP
) ?
1099 NO_ESP_EALG
: NO_ESP_AALG
);
1101 if ((strcasecmp("any", algname
) == 0) && (proto_num
== IPSEC_PROTO_AH
))
1102 return (SADB_AALG_ANY
);
1104 alg
= getipsecalgbyname(algname
, proto_num
, NULL
);
1106 invalue
= alg
->a_alg_num
;
1107 freeipsecalgent(alg
);
1108 return ((uint_t
)invalue
);
1112 * Since algorithms can be loaded during kernel run-time, check for
1113 * numeric algorithm values too.
1115 invalue
= parsenum(algname
);
1116 if ((invalue
& (ulong_t
)0xff) == invalue
)
1117 return ((uint_t
)invalue
);
1119 (void) fprintf(stderr
, "ifconfig: %s algorithm type %s unknown.\n",
1120 (proto_num
== IPSEC_PROTO_ESP
) ?
1121 "Encryption" : "Authentication", algname
);
1127 * Actual ifconfig functions to set tunnel security properties.
1130 enum ipsec_alg_type
{ ESP_ENCR_ALG
= 1, ESP_AUTH_ALG
, AH_AUTH_ALG
};
1132 boolean_t first_set_tun
= _B_TRUE
;
1133 boolean_t encr_alg_set
= _B_FALSE
;
1136 * Need global for multiple calls to set_tun_algs
1137 * because we accumulate algorithm selections over
1138 * the lifetime of this ifconfig(1M) invocation.
1140 static struct iftun_req treq_tun
;
1143 set_tun_algs(int which_alg
, int alg
)
1147 (void) strncpy(treq_tun
.ifta_lifr_name
, name
,
1148 sizeof (treq_tun
.ifta_lifr_name
));
1149 if (strchr(name
, ':') != NULL
) {
1151 Perror0_exit("Tunnel params on logical interfaces");
1153 if (ioctl(s
, SIOCGTUNPARAM
, (caddr_t
)&treq_tun
) < 0) {
1154 if (errno
== EOPNOTSUPP
|| errno
== EINVAL
)
1155 Perror0_exit("Not a tunnel");
1156 else Perror0_exit("SIOCGTUNPARAM");
1159 ipsr
= (ipsec_req_t
*)&treq_tun
.ifta_secinfo
;
1161 if (treq_tun
.ifta_vers
!= IFTUN_VERSION
) {
1162 (void) fprintf(stderr
,
1163 "Kernel tunnel secinfo version mismatch.\n");
1168 * If I'm just starting off this ifconfig, I want a clean slate,
1169 * otherwise, I've captured the current tunnel security settings.
1170 * In the case of continuation, I merely add to the settings.
1172 if (first_set_tun
) {
1173 first_set_tun
= _B_FALSE
;
1174 (void) memset(ipsr
, 0, sizeof (*ipsr
));
1177 treq_tun
.ifta_flags
= IFTUN_SECURITY
;
1179 switch (which_alg
) {
1181 if (alg
== NO_ESP_EALG
) {
1182 if (ipsr
->ipsr_esp_auth_alg
== SADB_AALG_NONE
)
1183 ipsr
->ipsr_esp_req
= 0;
1184 ipsr
->ipsr_esp_alg
= SADB_EALG_NONE
;
1186 /* Let the user specify NULL encryption implicitly. */
1187 if (ipsr
->ipsr_esp_auth_alg
!= SADB_AALG_NONE
) {
1188 encr_alg_set
= _B_TRUE
;
1189 ipsr
->ipsr_esp_alg
= SADB_EALG_NULL
;
1192 encr_alg_set
= _B_TRUE
;
1193 ipsr
->ipsr_esp_req
=
1194 IPSEC_PREF_REQUIRED
| IPSEC_PREF_UNIQUE
;
1195 ipsr
->ipsr_esp_alg
= alg
;
1199 if (alg
== NO_ESP_AALG
) {
1200 if ((ipsr
->ipsr_esp_alg
== SADB_EALG_NONE
||
1201 ipsr
->ipsr_esp_alg
== SADB_EALG_NULL
) &&
1203 ipsr
->ipsr_esp_req
= 0;
1204 ipsr
->ipsr_esp_auth_alg
= SADB_AALG_NONE
;
1206 ipsr
->ipsr_esp_req
=
1207 IPSEC_PREF_REQUIRED
| IPSEC_PREF_UNIQUE
;
1208 ipsr
->ipsr_esp_auth_alg
= alg
;
1210 /* Let the user specify NULL encryption implicitly. */
1211 if (ipsr
->ipsr_esp_alg
== SADB_EALG_NONE
&&
1213 ipsr
->ipsr_esp_alg
= SADB_EALG_NULL
;
1217 if (alg
== NO_AH_AALG
) {
1218 ipsr
->ipsr_ah_req
= 0;
1219 ipsr
->ipsr_auth_alg
= SADB_AALG_NONE
;
1222 IPSEC_PREF_REQUIRED
| IPSEC_PREF_UNIQUE
;
1223 ipsr
->ipsr_auth_alg
= alg
;
1226 /* Will never hit DEFAULT */
1229 if (ioctl(s
, SIOCSTUNPARAM
, (caddr_t
)&treq_tun
) < 0) {
1230 Perror2_exit("set tunnel security properties",
1231 treq_tun
.ifta_lifr_name
);
1239 set_tun_esp_encr_alg(char *addr
, int64_t param
)
1241 return (set_tun_algs(ESP_ENCR_ALG
,
1242 parsealg(addr
, IPSEC_PROTO_ESP
)));
1247 set_tun_esp_auth_alg(char *addr
, int64_t param
)
1249 return (set_tun_algs(ESP_AUTH_ALG
,
1250 parsealg(addr
, IPSEC_PROTO_AH
)));
1255 set_tun_ah_alg(char *addr
, int64_t param
)
1257 return (set_tun_algs(AH_AUTH_ALG
,
1258 parsealg(addr
, IPSEC_PROTO_AH
)));
1263 setifrevarp(char *arg
, int64_t param
)
1265 struct sockaddr_in laddr
;
1267 if (afp
->af_af
== AF_INET6
) {
1268 (void) fprintf(stderr
,
1269 "ifconfig: revarp not possible on IPv6 interface %s\n",
1273 if (doifrevarp(name
, &laddr
)) {
1274 (void) strncpy(lifr
.lifr_name
, name
, sizeof (lifr
.lifr_name
));
1275 laddr
.sin_family
= AF_INET
;
1276 (void) memcpy(&lifr
.lifr_addr
, &laddr
, sizeof (laddr
));
1277 if (ioctl(s
, SIOCSLIFADDR
, (caddr_t
)&lifr
) < 0)
1278 Perror0_exit("SIOCSLIFADDR");
1285 setifsubnet(char *addr
, int64_t param
)
1288 struct sockaddr_storage subnet
;
1290 (*afp
->af_getaddr
)(addr
, &subnet
, &prefixlen
);
1292 switch (prefixlen
) {
1294 (void) fprintf(stderr
,
1295 "ifconfig: Missing prefix length in subnet %s\n", addr
);
1299 (void) fprintf(stderr
,
1300 "ifconfig: Bad prefix length in %s\n", addr
);
1306 lifr
.lifr_addr
= subnet
;
1307 lifr
.lifr_addrlen
= prefixlen
;
1308 (void) strncpy(lifr
.lifr_name
, name
, sizeof (lifr
.lifr_name
));
1309 if (ioctl(s
, SIOCSLIFSUBNET
, (caddr_t
)&lifr
) < 0)
1310 Perror0_exit("SIOCSLIFSUBNET");
1317 setifnetmask(char *addr
, int64_t param
)
1319 struct sockaddr_in netmask
;
1321 assert(afp
->af_af
!= AF_INET6
);
1323 if (strcmp(addr
, "+") == 0) {
1324 if (!in_getmask(&netmask
, _B_FALSE
))
1326 (void) printf("Setting netmask of %s to %s\n", name
,
1327 inet_ntoa(netmask
.sin_addr
));
1329 in_getaddr(addr
, (struct sockaddr
*)&netmask
, NULL
);
1331 (void) strncpy(lifr
.lifr_name
, name
, sizeof (lifr
.lifr_name
));
1332 (void) memcpy(&lifr
.lifr_addr
, &netmask
, sizeof (netmask
));
1333 if (ioctl(s
, SIOCSLIFNETMASK
, (caddr_t
)&lifr
) < 0)
1334 Perror0_exit("SIOCSLIFNETMASK");
1339 * Parse '/<n>' as a netmask.
1343 setifprefixlen(char *addr
, int64_t param
)
1346 int af
= afp
->af_af
;
1348 prefixlen
= in_getprefixlen(addr
, _B_TRUE
,
1349 (af
== AF_INET
) ? IP_ABITS
: IPV6_ABITS
);
1350 if (prefixlen
< 0) {
1351 (void) fprintf(stderr
,
1352 "ifconfig: Bad prefix length in %s\n", addr
);
1355 (void) memset(&lifr
.lifr_addr
, 0, sizeof (lifr
.lifr_addr
));
1356 lifr
.lifr_addr
.ss_family
= af
;
1357 if (af
== AF_INET6
) {
1358 struct sockaddr_in6
*sin6
;
1360 sin6
= (struct sockaddr_in6
*)&lifr
.lifr_addr
;
1361 if (!in_prefixlentomask(prefixlen
, IPV6_ABITS
,
1362 (uchar_t
*)&sin6
->sin6_addr
)) {
1363 (void) fprintf(stderr
, "ifconfig: "
1364 "Bad prefix length: %d\n",
1368 } else if (af
== AF_INET
) {
1369 struct sockaddr_in
*sin
;
1371 sin
= (struct sockaddr_in
*)&lifr
.lifr_addr
;
1372 if (!in_prefixlentomask(prefixlen
, IP_ABITS
,
1373 (uchar_t
*)&sin
->sin_addr
)) {
1374 (void) fprintf(stderr
, "ifconfig: "
1375 "Bad prefix length: %d\n",
1380 (void) fprintf(stderr
, "ifconfig: setting prefix only supported"
1381 " for address family inet or inet6\n");
1384 (void) strncpy(lifr
.lifr_name
, name
, sizeof (lifr
.lifr_name
));
1385 if (ioctl(s
, SIOCSLIFNETMASK
, (caddr_t
)&lifr
) < 0)
1386 Perror0_exit("SIOCSLIFNETMASK");
1392 setifbroadaddr(char *addr
, int64_t param
)
1394 struct sockaddr_in broadaddr
;
1396 assert(afp
->af_af
!= AF_INET6
);
1398 if (strcmp(addr
, "+") == 0) {
1400 * This doesn't set the broadcast address at all. Rather, it
1401 * gets, then sets the interface's address, relying on the fact
1402 * that resetting the address will reset the broadcast address.
1404 (void) strncpy(lifr
.lifr_name
, name
,
1405 sizeof (lifr
.lifr_name
));
1406 if (ioctl(s
, SIOCGLIFADDR
, (caddr_t
)&lifr
) < 0) {
1407 if (errno
!= EADDRNOTAVAIL
)
1408 Perror0_exit("SIOCGLIFADDR");
1411 if (ioctl(s
, SIOCSLIFADDR
, (caddr_t
)&lifr
) < 0)
1412 Perror0_exit("SIOCGLIFADDR");
1416 in_getaddr(addr
, (struct sockaddr
*)&broadaddr
, NULL
);
1418 (void) memcpy(&lifr
.lifr_addr
, &broadaddr
, sizeof (broadaddr
));
1419 (void) strncpy(lifr
.lifr_name
, name
, sizeof (lifr
.lifr_name
));
1420 if (ioctl(s
, SIOCSLIFBRDADDR
, (caddr_t
)&lifr
) < 0)
1421 Perror0_exit("SIOCSLIFBRDADDR");
1426 * set interface destination address
1430 setifdstaddr(char *addr
, int64_t param
)
1432 (*afp
->af_getaddr
)(addr
, (struct sockaddr
*)&lifr
.lifr_addr
, NULL
);
1433 (void) strncpy(lifr
.lifr_name
, name
, sizeof (lifr
.lifr_name
));
1434 if (ioctl(s
, SIOCSLIFDSTADDR
, (caddr_t
)&lifr
) < 0)
1435 Perror0_exit("setifdstaddr: SIOCSLIFDSTADDR");
1441 setifflags(char *val
, int64_t value
)
1443 int phyintlen
, origphyintlen
;
1445 (void) strncpy(lifr
.lifr_name
, name
, sizeof (lifr
.lifr_name
));
1446 if (ioctl(s
, SIOCGLIFFLAGS
, (caddr_t
)&lifr
) < 0)
1447 Perror0_exit("setifflags: SIOCGLIFFLAGS");
1449 if (value
== IFF_NOFAILOVER
) {
1451 * Fail if '-failover' is set after a prior addif created the
1452 * alias on a different interface. This can happen when the
1453 * interface is part of an IPMP group.
1455 phyintlen
= strcspn(name
, ":");
1456 origphyintlen
= strcspn(origname
, ":");
1457 if (phyintlen
!= origphyintlen
||
1458 strncmp(name
, origname
, phyintlen
) != 0) {
1459 (void) fprintf(stderr
, "ifconfig: can't set -failover "
1460 "on failed/standby/offlined interface %s\n",
1468 lifr
.lifr_flags
&= ~value
;
1469 if ((value
& IFF_UP
) && (lifr
.lifr_flags
& IFF_DUPLICATE
)) {
1471 * If the user is trying to mark an interface with a
1472 * duplicate address as "down," then fetch the address
1473 * and set it. This will cause IP to clear the
1474 * IFF_DUPLICATE flag and stop the automatic recovery
1477 value
= lifr
.lifr_flags
;
1478 if (ioctl(s
, SIOCGLIFADDR
, (caddr_t
)&lifr
) >= 0)
1479 (void) ioctl(s
, SIOCSLIFADDR
, (caddr_t
)&lifr
);
1480 lifr
.lifr_flags
= value
;
1483 lifr
.lifr_flags
|= value
;
1485 (void) strncpy(lifr
.lifr_name
, name
, sizeof (lifr
.lifr_name
));
1486 if (ioctl(s
, SIOCSLIFFLAGS
, (caddr_t
)&lifr
) < 0) {
1487 Perror0_exit("setifflags: SIOCSLIFFLAGS");
1494 setifmetric(char *val
, int64_t param
)
1496 (void) strncpy(lifr
.lifr_name
, name
, sizeof (lifr
.lifr_name
));
1497 lifr
.lifr_metric
= atoi(val
);
1498 if (ioctl(s
, SIOCSLIFMETRIC
, (caddr_t
)&lifr
) < 0)
1499 Perror0_exit("setifmetric: SIOCSLIFMETRIC");
1505 setifmtu(char *val
, int64_t param
)
1507 (void) strncpy(lifr
.lifr_name
, name
, sizeof (lifr
.lifr_name
));
1508 lifr
.lifr_mtu
= atoi(val
);
1509 if (ioctl(s
, SIOCSLIFMTU
, (caddr_t
)&lifr
) < 0)
1510 Perror0_exit("setifmtu: SIOCSLIFMTU");
1516 setifindex(char *val
, int64_t param
)
1518 (void) strncpy(lifr
.lifr_name
, name
, sizeof (lifr
.lifr_name
));
1519 lifr
.lifr_index
= atoi(val
);
1520 if (ioctl(s
, SIOCSLIFINDEX
, (caddr_t
)&lifr
) < 0)
1521 Perror0_exit("setifindex: SIOCSLIFINDEX");
1527 setifether(char *addr
, int64_t param
)
1535 print_ifether(name
);
1543 * if the IP interface in the arguments is a logical
1544 * interface, exit with an error now.
1546 if (strchr(name
, ':') != NULL
) {
1547 (void) fprintf(stderr
, "ifconfig: cannot change"
1548 " ethernet address of a logical interface\n");
1552 ea
= _link_aton(addr
, &maclen
);
1555 (void) fprintf(stderr
,
1556 "ifconfig: %s: bad address\n", addr
);
1558 (void) fprintf(stderr
, "ifconfig: malloc() failed\n");
1562 (void) strncpy(savedname
, name
, sizeof (savedname
));
1565 * Call selectifs only for the IP interfaces that are ipv4.
1566 * offflags == IFF_IPV6 because you should not change the
1567 * Ethernet address of an ipv6 interface
1569 foreachinterface(selectifs
, 0, (char **)NULL
, 0, 0, IFF_IPV6
, 0);
1571 /* If physical interface not found, exit now */
1572 if (phyif
== NULL
) {
1573 (void) fprintf(stderr
,
1574 "ifconfig: interface %s not found\n", savedname
);
1579 (void) strncpy(name
, savedname
, sizeof (name
));
1580 (void) strncpy(origname
, savedname
, sizeof (origname
));
1581 (void) strncpy(lifr
.lifr_name
, name
, sizeof (lifr
.lifr_name
));
1584 * close and reopen the socket
1585 * we don't know which type of socket we have now
1588 s
= socket(SOCKET_AF(AF_UNSPEC
), SOCK_DGRAM
, 0);
1590 Perror0_exit("socket");
1594 * mark down the logical interfaces first,
1595 * and then the physical interface
1597 if (updownifs(logifs
, 0) < 0 || updownifs(phyif
, 0) < 0) {
1598 Perror0_exit("mark down interface failed");
1602 * Change the physical address
1604 if (dlpi_set_address(savedname
, ea
, maclen
) == -1) {
1605 (void) fprintf(stderr
,
1606 "ifconfig: failed setting mac address on %s\n",
1611 * if any interfaces were marked down before changing the
1612 * ethernet address, put them up again.
1613 * First the physical interface, then the logical ones.
1615 if (updownifs(phyif
, 1) < 0 || updownifs(logifs
, 1) < 0) {
1616 Perror0_exit("mark down interface failed");
1619 /* Free the memory allocated by selectifs */
1621 for (current
= logifs
; current
!= NULL
; current
= logifs
) {
1622 logifs
= logifs
->next
;
1630 * Print an interface's Ethernet address, if it has one.
1633 print_ifether(char *ifname
)
1636 icfg_if_t interface
;
1637 icfg_handle_t handle
;
1640 (void) strncpy(lifr
.lifr_name
, name
, sizeof (lifr
.lifr_name
));
1642 fd
= socket(AF_INET
, SOCK_DGRAM
, 0);
1643 if (fd
== -1 || ioctl(fd
, SIOCGLIFFLAGS
, &lifr
) == -1) {
1645 * It's possible the interface is only configured for
1646 * IPv6; check again with AF_INET6.
1649 fd
= socket(AF_INET6
, SOCK_DGRAM
, 0);
1650 if (fd
== -1 || ioctl(fd
, SIOCGLIFFLAGS
, &lifr
) == -1) {
1657 /* Virtual interfaces don't have MAC addresses */
1658 if (lifr
.lifr_flags
& IFF_VIRTUAL
)
1662 * We must be careful to set if_protocol based on the current
1663 * properties of the interface. For instance, if "ip.tun0" is
1664 * configured only as an IPv6 tunnel, then if_protocol must be
1665 * set to AF_INET6 or icfg_get_tunnel_lower() will fail and
1666 * we will falsely conclude that it's not a tunnel.
1668 interface
.if_protocol
= AF_INET
;
1669 if (lifr
.lifr_flags
& IFF_IPV6
)
1670 interface
.if_protocol
= AF_INET6
;
1672 (void) strncpy(interface
.if_name
, ifname
, sizeof (interface
.if_name
));
1674 if (icfg_open(&handle
, &interface
) == ICFG_SUCCESS
) {
1675 if (icfg_get_tunnel_lower(handle
, &protocol
) == ICFG_SUCCESS
) {
1676 /* Tunnel op succeeded -- it's a tunnel so skip */
1683 dlpi_print_address(ifname
);
1687 * static void selectifs(int argc, char *argv[], int af, struct lifreq *rp)
1689 * Called inside setifether() to create a list of interfaces to
1690 * mark down/up when changing the Ethernet address.
1691 * If the current interface is the physical interface passed
1692 * as an argument to ifconfig, update phyif.
1693 * If the current interface is a logical interface associated
1694 * to the physical interface, add it to the logifs list.
1698 selectifs(int argc
, char *argv
[], int af
, struct lifreq
*rp
)
1705 * savedname= name of the IP interface to which you want to
1706 * change ethernet address
1707 * name= name of the current IP interface
1709 colonp
= strchr(name
, ':');
1711 length
= max(strlen(savedname
), strlen(name
));
1713 length
= max(strlen(savedname
), colonp
- name
);
1714 if (strncmp(savedname
, name
, length
) == 0) {
1715 (void) strcpy(lifr
.lifr_name
, name
);
1716 if (ioctl(s
, SIOCGLIFFLAGS
, &lifr
) < 0) {
1717 Perror0("selectifs: SIOCGLIFFLAGS");
1721 if ((current
= malloc(sizeof (iface_t
))) == NULL
) {
1722 Perror0_exit("selectifs: malloc failed\n");
1725 if (colonp
== NULL
) {
1726 /* this is the physical interface */
1728 bcopy(&lifr
, &phyif
->lifr
, sizeof (struct lifreq
));
1731 /* this is a logical interface */
1732 bcopy(&lifr
, ¤t
->lifr
, sizeof (struct lifreq
));
1733 current
->next
= logifs
;
1740 * static int updownifs(iface_t *ifs, int up)
1742 * It takes in input a list of IP interfaces (ifs)
1744 * It marks each interface in the list down (up = 0)
1745 * or up (up > 0). This is done ONLY if the IP
1746 * interface was originally up.
1753 updownifs(iface_t
*ifs
, int up
)
1758 char savename
[LIFNAMSIZ
];
1759 uint64_t orig_flags
;
1761 for (current
= ifs
; current
!= NULL
; current
= current
->next
) {
1762 if (current
->lifr
.lifr_flags
& IFF_UP
) {
1763 orig_flags
= current
->lifr
.lifr_flags
;
1765 current
->lifr
.lifr_flags
&= ~IFF_UP
;
1766 if (ioctl(s
, SIOCSLIFFLAGS
, ¤t
->lifr
) < 0) {
1768 (void) strcpy(savename
,
1769 current
->lifr
.lifr_name
);
1772 if (!up
) /* restore the original flags */
1773 current
->lifr
.lifr_flags
= orig_flags
;
1778 (void) strcpy(lifr
.lifr_name
, savename
);
1785 * static int find_all_global_interfaces(struct lifconf *lifcp, char **buf,
1786 * int64_t lifc_flags)
1788 * It finds all data links for the global zone.
1790 * It takes in input a pointer to struct lifconf to receive interfaces
1791 * informations, a **char to hold allocated buffer, and a lifc_flags.
1798 find_all_global_interfaces(struct lifconf
*lifcp
, char **buf
,
1804 struct lifreq
*lifrp
;
1806 (void) dlpi_walk(ni_entry
, NULL
, 0);
1809 * Now, translate the linked list into
1810 * a struct lifreq buffer
1813 lifcp
->lifc_family
= AF_UNSPEC
;
1814 lifcp
->lifc_flags
= lifc_flags
;
1815 lifcp
->lifc_len
= 0;
1816 lifcp
->lifc_buf
= NULL
;
1820 bufsize
= num_ni
* sizeof (struct lifreq
);
1821 if ((*buf
= malloc(bufsize
)) == NULL
)
1822 Perror0_exit("find_all_interfaces: malloc failed");
1824 lifcp
->lifc_family
= AF_UNSPEC
;
1825 lifcp
->lifc_flags
= lifc_flags
;
1826 lifcp
->lifc_len
= bufsize
;
1827 lifcp
->lifc_buf
= *buf
;
1829 for (n
= 0, lifrp
= lifcp
->lifc_req
; n
< num_ni
; n
++, lifrp
++) {
1831 (void) strncpy(lifrp
->lifr_name
, nip
->ni_name
,
1832 sizeof (lifr
.lifr_name
));
1833 ni_list
= nip
->ni_next
;
1840 * static int find_all_zone_interfaces(struct lifconf *lifcp, char **buf,
1841 * int64_t lifc_flags)
1843 * It finds all interfaces for an exclusive-IP zone, that is all the interfaces
1846 * It takes in input a pointer to struct lifconf to receive interfaces
1847 * informations, a **char to hold allocated buffer, and a lifc_flags.
1854 find_all_zone_interfaces(struct lifconf
*lifcp
, char **buf
, int64_t lifc_flags
)
1858 char *dlnames
, *ptr
;
1859 struct lifreq
*lifrp
;
1860 int num_ni_saved
, i
;
1862 zoneid
= getzoneid();
1865 if (zone_list_datalink(zoneid
, &num_ni
, NULL
) != 0)
1866 Perror0_exit("find_all_interfaces: list interfaces failed");
1868 /* this zone doesn't have any data-links */
1870 lifcp
->lifc_family
= AF_UNSPEC
;
1871 lifcp
->lifc_flags
= lifc_flags
;
1872 lifcp
->lifc_len
= 0;
1873 lifcp
->lifc_buf
= NULL
;
1877 dlnames
= malloc(num_ni
* LIFNAMSIZ
);
1878 if (dlnames
== NULL
)
1879 Perror0_exit("find_all_interfaces: out of memory");
1880 num_ni_saved
= num_ni
;
1882 if (zone_list_datalink(zoneid
, &num_ni
, dlnames
) != 0)
1883 Perror0_exit("find_all_interfaces: list interfaces failed");
1885 if (num_ni_saved
< num_ni
) {
1886 /* list increased, try again */
1891 /* this zone doesn't have any data-links now */
1894 lifcp
->lifc_family
= AF_UNSPEC
;
1895 lifcp
->lifc_flags
= lifc_flags
;
1896 lifcp
->lifc_len
= 0;
1897 lifcp
->lifc_buf
= NULL
;
1901 bufsize
= num_ni
* sizeof (struct lifreq
);
1902 if ((*buf
= malloc(bufsize
)) == NULL
) {
1904 Perror0_exit("find_all_interfaces: malloc failed");
1907 lifrp
= (struct lifreq
*)*buf
;
1909 for (i
= 0; i
< num_ni
; i
++) {
1910 if (strlcpy(lifrp
->lifr_name
, ptr
, LIFNAMSIZ
) >=
1912 Perror0_exit("find_all_interfaces: overflow");
1918 lifcp
->lifc_family
= AF_UNSPEC
;
1919 lifcp
->lifc_flags
= lifc_flags
;
1920 lifcp
->lifc_len
= bufsize
;
1921 lifcp
->lifc_buf
= *buf
;
1926 * Create the next unused logical interface using the original name
1927 * and assign the address (and mask if '/<n>' is part of the address).
1928 * Use the new logical interface for subsequent subcommands by updating
1929 * the name variable.
1931 * This allows syntax like:
1932 * ifconfig le0 addif 109.106.86.130 netmask + up \
1933 * addif 109.106.86.131 netmask + up
1937 addif(char *str
, int64_t param
)
1940 struct sockaddr_storage laddr
;
1941 struct sockaddr_storage mask
;
1943 (void) strncpy(name
, origname
, sizeof (name
));
1945 if (strchr(name
, ':') != NULL
) {
1946 (void) fprintf(stderr
,
1947 "ifconfig: addif: bad physical interface name %s\n",
1953 * clear so parser will interpret next address as source followed
1957 (*afp
->af_getaddr
)(str
, (struct sockaddr
*)&laddr
, &prefixlen
);
1959 switch (prefixlen
) {
1961 /* Nothing there - ok */
1964 (void) fprintf(stderr
,
1965 "ifconfig: Bad prefix length in %s\n", str
);
1968 (void) memset(&mask
, 0, sizeof (mask
));
1969 mask
.ss_family
= afp
->af_af
;
1970 if (afp
->af_af
== AF_INET6
) {
1971 struct sockaddr_in6
*sin6
;
1972 sin6
= (struct sockaddr_in6
*)&mask
;
1973 if (!in_prefixlentomask(prefixlen
, IPV6_ABITS
,
1974 (uchar_t
*)&sin6
->sin6_addr
)) {
1975 (void) fprintf(stderr
, "ifconfig: "
1976 "Bad prefix length: %d\n",
1981 struct sockaddr_in
*sin
;
1983 sin
= (struct sockaddr_in
*)&mask
;
1984 if (!in_prefixlentomask(prefixlen
, IP_ABITS
,
1985 (uchar_t
*)&sin
->sin_addr
)) {
1986 (void) fprintf(stderr
, "ifconfig: "
1987 "Bad prefix length: %d\n",
1992 g_netmask_set
= G_NETMASK_NIL
;
1997 * This is a "hack" to get around the problem of SIOCLIFADDIF. The
1998 * problem is that this ioctl does not include the netmask when
1999 * adding a logical interface. This is the same problem described
2000 * in the ifconfig() comments. To get around this problem, we first
2001 * add the logical interface with a 0 address. After that, we set
2002 * the netmask if provided. Finally we set the interface address.
2004 (void) strncpy(lifr
.lifr_name
, name
, sizeof (lifr
.lifr_name
));
2005 (void) memset(&lifr
.lifr_addr
, 0, sizeof (lifr
.lifr_addr
));
2007 /* Note: no need to do DAD here since the interface isn't up yet. */
2009 if (ioctl(s
, SIOCLIFADDIF
, (caddr_t
)&lifr
) < 0)
2010 Perror0_exit("addif: SIOCLIFADDIF");
2012 (void) printf("Created new logical interface %s\n",
2014 (void) strncpy(name
, lifr
.lifr_name
, sizeof (name
));
2017 * Check and see if any "netmask" command is used and perform the
2018 * necessary operation.
2020 set_mask_lifreq(&lifr
, &laddr
, &mask
);
2022 * Only set the netmask if "netmask" command is used or a prefix is
2025 if (g_netmask_set
== G_NETMASK_SET
|| prefixlen
>= 0) {
2026 if (ioctl(s
, SIOCSLIFNETMASK
, (caddr_t
)&lifr
) < 0)
2027 Perror0_exit("addif: SIOCSLIFNETMASK");
2030 /* Finally, we set the interface address. */
2031 lifr
.lifr_addr
= laddr
;
2032 if (ioctl(s
, SIOCSLIFADDR
, (caddr_t
)&lifr
) < 0)
2033 Perror0_exit("SIOCSLIFADDR");
2036 * let parser know we got a source.
2037 * Next address, if given, should be dest
2044 * Remove a logical interface based on its IP address. Unlike addif
2045 * there is no '/<n>' here.
2046 * Verifies that the interface is down before it is removed.
2050 removeif(char *str
, int64_t param
)
2052 struct sockaddr_storage laddr
;
2054 if (strchr(name
, ':') != NULL
) {
2055 (void) fprintf(stderr
,
2056 "ifconfig: removeif: bad physical interface name %s\n",
2061 (*afp
->af_getaddr
)(str
, &laddr
, NULL
);
2062 lifr
.lifr_addr
= laddr
;
2064 (void) strncpy(lifr
.lifr_name
, name
, sizeof (lifr
.lifr_name
));
2065 if (ioctl(s
, SIOCLIFREMOVEIF
, (caddr_t
)&lifr
) < 0) {
2066 if (errno
== EBUSY
) {
2067 /* This can only happen if ipif_id = 0 */
2068 (void) fprintf(stderr
,
2069 "ifconfig: removeif: can't remove interface: %s\n",
2073 Perror0_exit("removeif: SIOCLIFREMOVEIF");
2079 * Set the address token for IPv6.
2083 setiftoken(char *addr
, int64_t param
)
2086 struct sockaddr_in6 token
;
2088 in6_getaddr(addr
, (struct sockaddr
*)&token
, &prefixlen
);
2089 switch (prefixlen
) {
2091 (void) fprintf(stderr
,
2092 "ifconfig: Missing prefix length in subnet %s\n", addr
);
2096 (void) fprintf(stderr
,
2097 "ifconfig: Bad prefix length in %s\n", addr
);
2102 (void) memcpy(&lifr
.lifr_addr
, &token
, sizeof (token
));
2103 lifr
.lifr_addrlen
= prefixlen
;
2104 (void) strncpy(lifr
.lifr_name
, name
, sizeof (lifr
.lifr_name
));
2105 if (ioctl(s
, SIOCSLIFTOKEN
, (caddr_t
)&lifr
) < 0) {
2106 Perror0_exit("setiftoken: SIOCSLIFTOKEN");
2112 * Return value: 0 on success, -1 on failure.
2115 connect_to_mpathd(int family
)
2118 struct sockaddr_storage ss
;
2119 struct sockaddr_in
*sin
= (struct sockaddr_in
*)&ss
;
2120 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&ss
;
2121 struct in6_addr loopback_addr
= IN6ADDR_LOOPBACK_INIT
;
2126 s
= socket(family
, SOCK_STREAM
, 0);
2128 Perror0_exit("connect_to_mpathd: socket");
2130 (void) bzero((char *)&ss
, sizeof (ss
));
2131 ss
.ss_family
= family
;
2133 * Need to bind to a privileged port. For non-root, this
2134 * will fail. in.mpathd verifies that only commands coming
2135 * from privileged ports succeed so that ordinary users
2136 * can't connect and start talking to in.mpathd
2139 if (setsockopt(s
, IPPROTO_TCP
, TCP_ANONPRIVBIND
, &on
,
2141 Perror0_exit("connect_to_mpathd: setsockopt");
2146 sin
->sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
2147 addrlen
= sizeof (struct sockaddr_in
);
2150 sin6
->sin6_port
= 0;
2151 sin6
->sin6_addr
= loopback_addr
;
2152 addrlen
= sizeof (struct sockaddr_in6
);
2155 ret
= bind(s
, (struct sockaddr
*)&ss
, addrlen
);
2163 sin
->sin_port
= htons(MPATHD_PORT
);
2166 sin6
->sin6_port
= htons(MPATHD_PORT
);
2169 ret
= connect(s
, (struct sockaddr
*)&ss
, addrlen
);
2176 setifgroupname(char *grpname
, int64_t param
)
2179 (void) printf("Setting groupname %s on interface %s\n",
2182 (void) strncpy(lifr
.lifr_name
, name
, sizeof (lifr
.lifr_name
));
2183 (void) strncpy(lifr
.lifr_groupname
, grpname
,
2184 sizeof (lifr
.lifr_groupname
));
2185 if (ioctl(s
, SIOCSLIFGROUPNAME
, (caddr_t
)&lifr
) < 0) {
2186 Perror0_exit("setifgroupname: SIOCSLIFGROUPNAME");
2190 * If the SUNW_NO_MPATHD environment variable is set then don't
2191 * bother starting up in.mpathd. See PSARC/2002/249 for the
2192 * depressing details on this bit of stupidity.
2194 if (getenv("SUNW_NO_MPATHD") != NULL
) {
2199 * Try to connect to in.mpathd using IPv4. If we succeed,
2200 * we conclude that in.mpathd is running, and quit.
2202 if (connect_to_mpathd(AF_INET
) == 0) {
2203 /* connect succeeded, mpathd is already running */
2207 * Try to connect to in.mpathd using IPv6. If we succeed,
2208 * we conclude that in.mpathd is running, and quit.
2210 if (connect_to_mpathd(AF_INET6
) == 0) {
2211 /* connect succeeded, mpathd is already running */
2216 * in.mpathd may not be running. Start it now. If it is already
2217 * running, in.mpathd will take care of handling multiple incarnations
2218 * of itself. ifconfig only tries to optimize performance by not
2219 * starting another incarnation of in.mpathd.
2224 Perror0_exit("setifgroupname: fork");
2227 (void) execl(MPATHD_PATH
, MPATHD_PATH
, NULL
);
2237 * To list all the modules above a given network interface.
2241 modlist(char *null
, int64_t param
)
2249 struct str_list strlist
;
2252 (void) strncpy(lifr
.lifr_name
, name
, sizeof (lifr
.lifr_name
));
2253 if (ip_domux2fd(&muxfd
, &muxid_fd
, &ipfd_lowstr
, &arpfd_lowstr
,
2257 if ((num_mods
= ioctl(ipfd_lowstr
, I_LIST
, NULL
)) < 0) {
2258 Perror0("cannot I_LIST to get the number of modules");
2261 (void) printf("Listing (%d) modules above %s\n",
2265 strlist
.sl_nmods
= num_mods
;
2266 strlist
.sl_modlist
= malloc(sizeof (struct str_mlist
) *
2268 if (strlist
.sl_modlist
== NULL
) {
2269 Perror0("cannot malloc");
2271 if (ioctl(ipfd_lowstr
, I_LIST
, (caddr_t
)&strlist
) < 0) {
2272 Perror0("cannot I_LIST for module names");
2274 for (i
= 0; i
< strlist
.sl_nmods
; i
++) {
2275 (void) printf("%d %s\n", i
,
2276 strlist
.sl_modlist
[i
].l_name
);
2279 free(strlist
.sl_modlist
);
2282 return (ip_plink(muxfd
, muxid_fd
, ipfd_lowstr
, arpfd_lowstr
,
2286 #define MODINSERT_OP 'i'
2287 #define MODREMOVE_OP 'r'
2290 * To insert a module to the stream of the interface. It is just a
2291 * wrapper. The real function is modop().
2295 modinsert(char *arg
, int64_t param
)
2297 return (modop(arg
, MODINSERT_OP
));
2301 * To remove a module from the stream of the interface. It is just a
2302 * wrapper. The real function is modop().
2306 modremove(char *arg
, int64_t param
)
2308 return (modop(arg
, MODREMOVE_OP
));
2312 * Open a stream on /dev/udp{,6}, pop off all undesired modules (note that
2313 * the user may have configured autopush to add modules above
2314 * udp), and push the arp module onto the resulting stream.
2315 * This is used to make IP+ARP be able to atomically track the muxid
2316 * for the I_PLINKed STREAMS, thus it isn't related to ARP running the ARP
2320 open_arp_on_udp(char *udp_dev_name
)
2324 if ((fd
= open(udp_dev_name
, O_RDWR
)) == -1) {
2325 Perror2("open", udp_dev_name
);
2329 while (ioctl(fd
, I_POP
, 0) != -1)
2331 if (errno
!= EINVAL
) {
2332 Perror2("pop", udp_dev_name
);
2333 } else if (ioctl(fd
, I_PUSH
, ARP_MOD_NAME
) == -1) {
2334 Perror2("arp PUSH", udp_dev_name
);
2343 * Helper function for mod*() functions. It gets a fd to the lower IP
2344 * stream and I_PUNLINK's the lower stream. It also initializes the
2345 * global variable lifr.
2348 * int *muxfd: fd to /dev/udp{,6} for I_PLINK/I_PUNLINK
2349 * int *muxid_fd: fd to /dev/udp{,6} for LIFMUXID
2350 * int *ipfd_lowstr: fd to the lower IP stream.
2351 * int *arpfd_lowstr: fd to the lower ARP stream.
2354 * -1 if operation fails, 0 otherwise.
2356 * Please see the big block comment above plumb_one_device()
2357 * for the logic of the PLINK/PUNLINK
2360 ip_domux2fd(int *muxfd
, int *muxid_fd
, int *ipfd_lowstr
, int *arpfd_lowstr
,
2367 (void) strncpy(lifr
.lifr_name
, name
, sizeof (lifr
.lifr_name
));
2368 if (ioctl(s
, SIOCGLIFFLAGS
, (caddr_t
)&lifr
) < 0) {
2369 Perror0_exit("status: SIOCGLIFFLAGS");
2371 flags
= lifr
.lifr_flags
;
2372 if (flags
& IFF_IPV4
) {
2373 udp_dev_name
= UDP_DEV_NAME
;
2374 } else if (flags
& IFF_IPV6
) {
2375 udp_dev_name
= UDP6_DEV_NAME
;
2380 if ((*muxid_fd
= open(udp_dev_name
, O_RDWR
)) < 0) {
2381 Perror2("open", udp_dev_name
);
2384 if (ioctl(*muxid_fd
, SIOCGLIFMUXID
, (caddr_t
)&lifr
) < 0) {
2385 Perror2("SIOCGLIFMUXID", udp_dev_name
);
2389 (void) printf("ARP_muxid %d IP_muxid %d\n",
2390 lifr
.lifr_arp_muxid
, lifr
.lifr_ip_muxid
);
2394 * Use /dev/udp{,6} as the mux to avoid linkcycles.
2396 if ((*muxfd
= open_arp_on_udp(udp_dev_name
)) == -1)
2399 if (lifr
.lifr_arp_muxid
!= 0) {
2400 if ((*arpfd_lowstr
= ioctl(*muxfd
, _I_MUXID2FD
,
2401 lifr
.lifr_arp_muxid
)) < 0) {
2402 if ((errno
== EINVAL
) &&
2403 (flags
& (IFF_NOARP
| IFF_IPV6
))) {
2405 * Some plumbing utilities set the muxid to
2406 * -1 or some invalid value to signify that
2407 * there is no arp stream. Set the muxid to 0
2408 * before trying to unplumb the IP stream.
2409 * IP does not allow the IP stream to be
2410 * unplumbed if it sees a non-null arp muxid,
2411 * for consistency of IP-ARP streams.
2413 *orig_arpid
= lifr
.lifr_arp_muxid
;
2414 lifr
.lifr_arp_muxid
= 0;
2415 (void) ioctl(*muxid_fd
, SIOCSLIFMUXID
,
2419 Perror0("_I_MUXID2FD");
2422 } else if (ioctl(*muxfd
, I_PUNLINK
,
2423 lifr
.lifr_arp_muxid
) < 0) {
2424 Perror2("I_PUNLINK", udp_dev_name
);
2431 if ((*ipfd_lowstr
= ioctl(*muxfd
, _I_MUXID2FD
,
2432 lifr
.lifr_ip_muxid
)) < 0) {
2433 Perror0("_I_MUXID2FD");
2434 /* Undo any changes we made */
2435 if (*orig_arpid
!= 0) {
2436 lifr
.lifr_arp_muxid
= *orig_arpid
;
2437 (void) ioctl(*muxid_fd
, SIOCSLIFMUXID
, (caddr_t
)&lifr
);
2441 if (ioctl(*muxfd
, I_PUNLINK
, lifr
.lifr_ip_muxid
) < 0) {
2442 Perror2("I_PUNLINK", udp_dev_name
);
2443 /* Undo any changes we made */
2444 if (*orig_arpid
!= 0) {
2445 lifr
.lifr_arp_muxid
= *orig_arpid
;
2446 (void) ioctl(*muxid_fd
, SIOCSLIFMUXID
, (caddr_t
)&lifr
);
2454 * Helper function for mod*() functions. It I_PLINK's back the upper and
2455 * lower IP streams. Note that this function must be called after
2456 * ip_domux2fd(). In ip_domux2fd(), the global variable lifr is initialized
2457 * and ip_plink() needs information in lifr. So ip_domux2fd() and ip_plink()
2458 * must be called in pairs.
2461 * int muxfd: fd to /dev/udp{,6} for I_PLINK/I_PUNLINK
2462 * int muxid_fd: fd to /dev/udp{,6} for LIFMUXID
2463 * int ipfd_lowstr: fd to the lower IP stream.
2464 * int arpfd_lowstr: fd to the lower ARP stream.
2467 * -1 if operation fails, 0 otherwise.
2469 * Please see the big block comment above plumb_one_device()
2470 * for the logic of the PLINK/PUNLINK
2473 ip_plink(int muxfd
, int muxid_fd
, int ipfd_lowstr
, int arpfd_lowstr
,
2478 ip_muxid
= ioctl(muxfd
, I_PLINK
, ipfd_lowstr
);
2480 Perror2("I_PLINK", UDP_DEV_NAME
);
2485 * If there is an arp stream, plink it. If there is no
2486 * arp stream, then it is possible that the plumbing
2487 * utility could have stored any value in the arp_muxid.
2488 * If so, restore it from orig_arpid.
2490 if (arpfd_lowstr
!= -1) {
2491 if (ioctl(muxfd
, I_PLINK
, arpfd_lowstr
) < 0) {
2492 Perror2("I_PLINK", UDP_DEV_NAME
);
2495 } else if (orig_arpid
!= 0) {
2496 /* Undo the changes we did in ip_domux2fd */
2497 lifr
.lifr_arp_muxid
= orig_arpid
;
2498 lifr
.lifr_ip_muxid
= ip_muxid
;
2499 (void) ioctl(muxid_fd
, SIOCSLIFMUXID
, (caddr_t
)&lifr
);
2502 (void) close(muxfd
);
2503 (void) close(muxid_fd
);
2508 * The real function to perform module insertion/removal.
2511 * char *arg: the argument string module_name@position
2512 * char op: operation, either MODINSERT_OP or MODREMOVE_OP.
2515 * Before doing ip_domux2fd(), this function calls exit(1) in case of
2516 * error. After ip_domux2fd() is done, it returns -1 for error, 0
2520 modop(char *arg
, char op
)
2525 int ipfd_lowstr
; /* IP stream (lower stream of mux) to be plinked */
2526 int arpfd_lowstr
; /* ARP stream (lower stream of mux) to be plinked */
2527 struct strmodconf mod
;
2528 char *at_char
= "@";
2532 (void) strncpy(lifr
.lifr_name
, name
, sizeof (lifr
.lifr_name
));
2534 /* Need to save the original string for -a option. */
2535 if ((arg_str
= malloc(strlen(arg
) + 1)) == NULL
) {
2536 Perror0("cannot malloc");
2539 (void) strcpy(arg_str
, arg
);
2541 if (*arg_str
== *at_char
) {
2542 (void) fprintf(stderr
,
2543 "ifconfig: must supply a module name\n");
2546 mod
.mod_name
= strtok(arg_str
, at_char
);
2547 if (strlen(mod
.mod_name
) > FMNAMESZ
) {
2548 (void) fprintf(stderr
, "ifconfig: module name too long: %s\n",
2554 * Need to make sure that the core TCP/IP stack modules are not
2555 * removed. Otherwise, "bad" things can happen. If a module
2556 * is removed and inserted back, it loses its old state. But
2557 * the modules above it still have the old state. E.g. IP assumes
2558 * fast data path while tunnel after re-inserted assumes that it can
2559 * receive M_DATA only in fast data path for which it does not have
2560 * any state. This is a general caveat of _I_REMOVE/_I_INSERT.
2562 if (op
== MODREMOVE_OP
&&
2563 (strcmp(mod
.mod_name
, ARP_MOD_NAME
) == 0 ||
2564 strcmp(mod
.mod_name
, IP_MOD_NAME
) == 0 ||
2565 strcmp(mod
.mod_name
, TUN_NAME
) == 0 ||
2566 strcmp(mod
.mod_name
, ATUN_NAME
) == 0 ||
2567 strcmp(mod
.mod_name
, TUN6TO4_NAME
) == 0)) {
2568 (void) fprintf(stderr
, "ifconfig: cannot remove %s\n",
2573 if ((pos_p
= strtok(NULL
, at_char
)) == NULL
) {
2574 (void) fprintf(stderr
, "ifconfig: must supply a position\n");
2577 mod
.pos
= atoi(pos_p
);
2579 if (ip_domux2fd(&muxfd
, &muxid_fd
, &ipfd_lowstr
, &arpfd_lowstr
,
2587 (void) printf("Inserting module %s at %d\n",
2588 mod
.mod_name
, mod
.pos
);
2590 if (ioctl(ipfd_lowstr
, _I_INSERT
, (caddr_t
)&mod
) < 0) {
2591 Perror2("fail to insert module", mod
.mod_name
);
2596 (void) printf("Removing module %s at %d\n",
2597 mod
.mod_name
, mod
.pos
);
2599 if (ioctl(ipfd_lowstr
, _I_REMOVE
, (caddr_t
)&mod
) < 0) {
2600 Perror2("fail to remove module", mod
.mod_name
);
2604 /* Should never get to here. */
2605 (void) fprintf(stderr
, "Unknown operation\n");
2609 return (ip_plink(muxfd
, muxid_fd
, ipfd_lowstr
, arpfd_lowstr
,
2614 * Set tunnel source address
2618 setiftsrc(char *addr
, int64_t param
)
2620 return (settaddr(addr
, icfg_set_tunnel_src
));
2624 * Set tunnel destination address
2628 setiftdst(char *addr
, int64_t param
)
2630 return (settaddr(addr
, icfg_set_tunnel_dest
));
2634 * sets tunnels src|dst address. settaddr() expects the following:
2635 * addr: Points to a printable string containing the address to be
2636 * set, e.g. 129.153.128.110.
2637 * fn: Pointer to a libinetcfg routine that will do the actual work.
2638 * The only valid functions are icfg_set_tunnel_src and
2639 * icfg_set_tunnel_dest.
2642 settaddr(char *addr
,
2643 int (*fn
)(icfg_handle_t
, const struct sockaddr
*, socklen_t
))
2645 icfg_handle_t handle
;
2646 icfg_if_t interface
;
2647 struct sockaddr_storage laddr
;
2651 if (strchr(name
, ':') != NULL
) {
2653 Perror0_exit("Tunnel params on logical interfaces");
2655 (void) strncpy(interface
.if_name
, name
, sizeof (interface
.if_name
));
2656 interface
.if_protocol
= SOCKET_AF(af
);
2658 /* Open interface. */
2659 if ((rc
= icfg_open(&handle
, &interface
)) != ICFG_SUCCESS
)
2660 Perror0_exit((char *)icfg_errmsg(rc
));
2662 rc
= icfg_get_tunnel_lower(handle
, &lower
);
2663 if (rc
!= ICFG_SUCCESS
)
2664 Perror0_exit((char *)icfg_errmsg(rc
));
2666 if (lower
== AF_INET
) {
2667 in_getaddr(addr
, (struct sockaddr
*)&laddr
, NULL
);
2669 in6_getaddr(addr
, (struct sockaddr
*)&laddr
, NULL
);
2672 /* Call fn to do the real work, and close the interface. */
2673 rc
= (*fn
)(handle
, (struct sockaddr
*)&laddr
,
2674 sizeof (struct sockaddr_storage
));
2677 if (rc
!= ICFG_SUCCESS
)
2678 Perror0_exit((char *)icfg_errmsg(rc
));
2683 /* Set tunnel encapsulation limit. */
2686 set_tun_encap_limit(char *arg
, int64_t param
)
2689 icfg_if_t interface
;
2690 icfg_handle_t handle
;
2693 if (strchr(name
, ':') != NULL
) {
2695 Perror0_exit("Tunnel params on logical interfaces");
2698 if ((sscanf(arg
, "%hd", &limit
) != 1) || (limit
< 0) ||
2701 Perror0_exit("Invalid encapsulation limit");
2704 /* Open interface for configuration. */
2705 (void) strncpy(interface
.if_name
, name
, sizeof (interface
.if_name
));
2706 interface
.if_protocol
= SOCKET_AF(af
);
2707 if (icfg_open(&handle
, &interface
) != ICFG_SUCCESS
)
2708 Perror0_exit("couldn't open interface");
2710 rc
= icfg_set_tunnel_encaplimit(handle
, (int)limit
);
2713 if (rc
!= ICFG_SUCCESS
)
2714 Perror0_exit("Could not configure tunnel encapsulation limit");
2719 /* Disable encapsulation limit. */
2722 clr_tun_encap_limit(char *arg
, int64_t param
)
2724 icfg_if_t interface
;
2725 icfg_handle_t handle
;
2728 if (strchr(name
, ':') != NULL
) {
2730 Perror0_exit("Tunnel params on logical interfaces");
2733 /* Open interface for configuration. */
2734 (void) strncpy(interface
.if_name
, name
, sizeof (interface
.if_name
));
2735 interface
.if_protocol
= SOCKET_AF(af
);
2736 if (icfg_open(&handle
, &interface
) != ICFG_SUCCESS
)
2737 Perror0_exit("couldn't open interface");
2739 rc
= icfg_set_tunnel_encaplimit(handle
, -1);
2742 if (rc
!= ICFG_SUCCESS
)
2743 Perror0_exit((char *)icfg_errmsg(rc
));
2748 /* Set tunnel hop limit. */
2751 set_tun_hop_limit(char *arg
, int64_t param
)
2753 unsigned short limit
;
2754 icfg_if_t interface
;
2755 icfg_handle_t handle
;
2758 if (strchr(name
, ':') != NULL
) {
2760 Perror0_exit("Tunnel params on logical interfaces");
2764 * Check limit here since it's really only an 8-bit unsigned quantity.
2766 if ((sscanf(arg
, "%hu", &limit
) != 1) || (limit
> 255)) {
2768 Perror0_exit("Invalid hop limit");
2771 /* Open interface for configuration. */
2772 (void) strncpy(interface
.if_name
, name
, sizeof (interface
.if_name
));
2773 interface
.if_protocol
= SOCKET_AF(af
);
2774 if (icfg_open(&handle
, &interface
) != ICFG_SUCCESS
)
2775 Perror0_exit("couldn't open interface");
2777 rc
= icfg_set_tunnel_hoplimit(handle
, (uint8_t)limit
);
2780 if (rc
!= ICFG_SUCCESS
)
2781 Perror0_exit("Could not configure tunnel hop limit");
2788 setzone(char *arg
, int64_t param
)
2790 zoneid_t zoneid
= GLOBAL_ZONEID
;
2792 if (param
== NEXTARG
) {
2793 /* zone must be active */
2794 if ((zoneid
= getzoneidbyname(arg
)) == -1) {
2795 (void) fprintf(stderr
,
2796 "ifconfig: unknown zone '%s'\n", arg
);
2800 (void) strlcpy(lifr
.lifr_name
, name
, sizeof (lifr
.lifr_name
));
2801 lifr
.lifr_zoneid
= zoneid
;
2802 if (ioctl(s
, SIOCSLIFZONE
, (caddr_t
)&lifr
) == -1)
2803 Perror0_exit("SIOCSLIFZONE");
2807 /* Put interface into all zones */
2810 setallzones(char *arg
, int64_t param
)
2812 (void) strlcpy(lifr
.lifr_name
, name
, sizeof (lifr
.lifr_name
));
2813 lifr
.lifr_zoneid
= ALL_ZONES
;
2814 if (ioctl(s
, SIOCSLIFZONE
, (caddr_t
)&lifr
) == -1)
2815 Perror0_exit("SIOCSLIFZONE");
2819 /* Set source address to use */
2822 setifsrc(char *arg
, int64_t param
)
2827 (void) strncpy(lifr
.lifr_name
, name
, sizeof (lifr
.lifr_name
));
2830 * Argument can be either an interface name or "none". The latter means
2831 * that any previous selection is cleared.
2834 rval
= strcmp(arg
, name
);
2836 (void) fprintf(stderr
,
2837 "ifconfig: Cannot specify same interface for usesrc"
2842 rval
= strcmp(arg
, NONE_STR
);
2844 if ((ifindex
= if_nametoindex(arg
)) == 0) {
2845 (void) strncpy(lifr
.lifr_name
, arg
, LIFNAMSIZ
);
2846 Perror0_exit("Could not get interface index");
2848 lifr
.lifr_index
= ifindex
;
2850 if (ioctl(s
, SIOCGLIFUSESRC
, (caddr_t
)&lifr
) != 0)
2851 Perror0_exit("Not a valid usesrc consumer");
2852 lifr
.lifr_index
= 0;
2856 (void) printf("setifsrc: lifr_name %s, lifr_index %d\n",
2857 lifr
.lifr_name
, lifr
.lifr_index
);
2859 if (ioctl(s
, SIOCSLIFUSESRC
, (caddr_t
)&lifr
) == -1) {
2861 Perror0_exit("Cannot reset usesrc group");
2863 Perror0_exit("Could not set source interface");
2870 * Print the interface status line associated with `ifname'
2873 ifstatus(const char *ifname
)
2876 char if_usesrc_name
[LIFNAMSIZ
];
2878 int n
, numifs
, rval
= 0;
2879 struct lifreq
*lifrp
;
2880 struct lifsrcof lifs
;
2882 (void) strncpy(lifr
.lifr_name
, ifname
, sizeof (lifr
.lifr_name
));
2883 if (ioctl(s
, SIOCGLIFFLAGS
, (caddr_t
)&lifr
) < 0) {
2884 Perror0_exit("status: SIOCGLIFFLAGS");
2886 flags
= lifr
.lifr_flags
;
2889 * In V4 compatibility mode, we don't print the IFF_IPV4 flag or
2890 * interfaces with IFF_IPV6 set.
2894 if (flags
& IFF_IPV6
)
2898 (void) printf("%s: ", ifname
);
2901 (void) strncpy(lifr
.lifr_name
, ifname
, sizeof (lifr
.lifr_name
));
2902 if (ioctl(s
, SIOCGLIFMETRIC
, (caddr_t
)&lifr
) < 0) {
2903 Perror0_exit("status: SIOCGLIFMETRIC");
2905 if (lifr
.lifr_metric
)
2906 (void) printf(" metric %d", lifr
.lifr_metric
);
2908 if (ioctl(s
, SIOCGLIFMTU
, (caddr_t
)&lifr
) >= 0)
2909 (void) printf(" mtu %u", lifr
.lifr_mtu
);
2911 /* don't print index or zone when in compatibility mode */
2913 if (ioctl(s
, SIOCGLIFINDEX
, (caddr_t
)&lifr
) >= 0)
2914 (void) printf(" index %d", lifr
.lifr_index
);
2916 * Stack instances use GLOBAL_ZONEID for IP data structures
2917 * even in the non-global zone.
2919 if (ioctl(s
, SIOCGLIFZONE
, (caddr_t
)&lifr
) >= 0 &&
2920 lifr
.lifr_zoneid
!= getzoneid() &&
2921 lifr
.lifr_zoneid
!= GLOBAL_ZONEID
) {
2922 char zone_name
[ZONENAME_MAX
];
2924 if (lifr
.lifr_zoneid
== ALL_ZONES
) {
2925 (void) printf("\n\tall-zones");
2926 } else if (getzonenamebyid(lifr
.lifr_zoneid
, zone_name
,
2927 sizeof (zone_name
)) < 0) {
2928 (void) printf("\n\tzone %d", lifr
.lifr_zoneid
);
2930 (void) printf("\n\tzone %s", zone_name
);
2935 if (ioctl(s
, SIOCGLIFINDEX
, (caddr_t
)&lifr
) >= 0) {
2936 lifs
.lifs_ifindex
= lifr
.lifr_index
;
2939 * Find the number of interfaces that use this interfaces'
2940 * address as a source address
2942 lifs
.lifs_buf
= NULL
;
2943 lifs
.lifs_maxlen
= 0;
2945 /* The first pass will give the bufsize we need */
2946 rval
= ioctl(s
, SIOCGLIFSRCOF
, (char *)&lifs
);
2948 if (lifs
.lifs_buf
!= NULL
) {
2949 free(lifs
.lifs_buf
);
2950 lifs
.lifs_buf
= NULL
;
2955 if (lifs
.lifs_len
<= lifs
.lifs_maxlen
)
2957 /* Use kernel's size + a small margin to avoid loops */
2958 lifs
.lifs_maxlen
= lifs
.lifs_len
+
2959 5 * sizeof (struct lifreq
);
2960 /* For the first pass, realloc acts like malloc */
2961 newbuf
= realloc(lifs
.lifs_buf
, lifs
.lifs_maxlen
);
2962 if (newbuf
== NULL
) {
2963 if (lifs
.lifs_buf
!= NULL
) {
2964 free(lifs
.lifs_buf
);
2965 lifs
.lifs_buf
= NULL
;
2970 lifs
.lifs_buf
= newbuf
;
2974 numifs
= lifs
.lifs_len
/ sizeof (struct lifreq
);
2976 lifrp
= lifs
.lifs_req
;
2977 (void) printf("\n\tsrcof");
2978 for (n
= numifs
; n
> 0; n
--, lifrp
++) {
2979 (void) printf(" %s", lifrp
->lifr_name
);
2983 if (lifs
.lifs_buf
!= NULL
)
2984 free(lifs
.lifs_buf
);
2987 /* Find the interface whose source address this interface uses */
2988 if (ioctl(s
, SIOCGLIFUSESRC
, (caddr_t
)&lifr
) == 0) {
2989 if (lifr
.lifr_index
!= 0) {
2990 if (if_indextoname(lifr
.lifr_index
,
2991 if_usesrc_name
) == NULL
) {
2992 (void) printf("\n\tusesrc ifIndex %d",
2995 (void) printf("\n\tusesrc %s", if_usesrc_name
);
3000 (void) putchar('\n');
3005 * Print the status of the interface. If an address family was
3006 * specified, show it and it only; otherwise, show them all.
3011 struct afswtch
*p
= afp
;
3014 (void) strncpy(lifr
.lifr_name
, name
, sizeof (lifr
.lifr_name
));
3015 if (ioctl(s
, SIOCGLIFFLAGS
, (caddr_t
)&lifr
) < 0) {
3016 Perror0_exit("status: SIOCGLIFFLAGS");
3019 flags
= lifr
.lifr_flags
;
3022 * Only print the interface status if the address family matches
3023 * the interface family flag.
3026 if (((p
->af_af
== AF_INET6
) && (flags
& IFF_IPV4
)) ||
3027 ((p
->af_af
== AF_INET
) && (flags
& IFF_IPV6
)))
3032 * In V4 compatibility mode, don't print IFF_IPV6 interfaces.
3034 if (v4compat
&& (flags
& IFF_IPV6
))
3040 (*p
->af_status
)(1, flags
);
3042 for (p
= afs
; p
->af_name
; p
++) {
3044 s
= socket(SOCKET_AF(p
->af_af
), SOCK_DGRAM
, 0);
3045 /* set global af for use in p->af_status */
3048 Perror0_exit("socket");
3050 (*p
->af_status
)(0, flags
);
3054 * Historically, 'ether' has been an address family,
3057 print_ifether(name
);
3062 * Print the status of the interface in a format that can be used to
3063 * reconfigure the interface later. Code stolen from status() above.
3067 configinfo(char *null
, int64_t param
)
3069 struct afswtch
*p
= afp
;
3071 char phydevname
[LIFNAMSIZ
];
3072 char if_usesrc_name
[LIFNAMSIZ
];
3075 (void) strncpy(lifr
.lifr_name
, name
, sizeof (lifr
.lifr_name
));
3076 if (ioctl(s
, SIOCGLIFFLAGS
, (caddr_t
)&lifr
) < 0) {
3077 Perror0_exit("status: SIOCGLIFFLAGS");
3079 flags
= lifr
.lifr_flags
;
3082 (void) printf("configinfo: name %s flags 0x%llx af_af %d\n",
3083 name
, flags
, p
!= NULL
? p
->af_af
: -1);
3086 /* remove LIF component */
3087 (void) strncpy(phydevname
, name
, sizeof (phydevname
));
3088 cp
= strchr(phydevname
, ':');
3092 phydevname
[sizeof (phydevname
) - 1] = '\0';
3095 * if the interface is IPv4
3096 * if we have a IPv6 address family restriction return
3098 * if we are in IPv4 compatibility mode, clear out IFF_IPV4
3099 * so we don't print it.
3101 if (flags
& IFF_IPV4
) {
3102 if (p
&& p
->af_af
== AF_INET6
)
3107 (void) printf("%s inet plumb", phydevname
);
3108 } else if (flags
& IFF_IPV6
) {
3110 * else if the interface is IPv6
3111 * if we have a IPv4 address family restriction return
3112 * or we are in IPv4 compatibiltiy mode, return.
3114 if (p
&& p
->af_af
== AF_INET
)
3119 (void) printf("%s inet6 plumb", phydevname
);
3122 (void) strncpy(lifr
.lifr_name
, name
, sizeof (lifr
.lifr_name
));
3123 if (ioctl(s
, SIOCGLIFMETRIC
, (caddr_t
)&lifr
) < 0) {
3124 Perror0_exit("configinfo: SIOCGLIFMETRIC");
3126 if (lifr
.lifr_metric
)
3127 (void) printf(" metric %d ", lifr
.lifr_metric
);
3129 if (((flags
& (IFF_VIRTUAL
|IFF_LOOPBACK
)) != IFF_VIRTUAL
) &&
3130 ioctl(s
, SIOCGLIFMTU
, (caddr_t
)&lifr
) >= 0)
3131 (void) printf(" mtu %d", lifr
.lifr_metric
);
3133 /* don't print index when in compatibility mode */
3135 if (ioctl(s
, SIOCGLIFINDEX
, (caddr_t
)&lifr
) >= 0)
3136 (void) printf(" index %d", lifr
.lifr_index
);
3139 if (ioctl(s
, SIOCGLIFUSESRC
, (caddr_t
)&lifr
) == 0) {
3140 if (lifr
.lifr_index
!= 0) {
3141 if (if_indextoname(lifr
.lifr_index
,
3142 if_usesrc_name
) != NULL
) {
3143 (void) printf(" usesrc %s", if_usesrc_name
);
3149 (*p
->af_configinfo
)(1, flags
);
3151 for (p
= afs
; p
->af_name
; p
++) {
3153 s
= socket(SOCKET_AF(p
->af_af
), SOCK_DGRAM
, 0);
3154 /* set global af for use in p->af_configinfo */
3157 Perror0_exit("socket");
3159 (*p
->af_configinfo
)(0, flags
);
3163 (void) printf("\n");
3169 print_tsec(struct iftun_req
*tparams
)
3173 (void) printf("\ttunnel security settings ");
3175 * Deal with versioning, for now just point
3176 * an ipsec_req_t at ifta_secinfo. If versions
3177 * change, something else will overlay ifta_secinfo.
3179 assert(tparams
->ifta_vers
== IFTUN_VERSION
);
3181 if (tparams
->ifta_flags
& IFTUN_COMPLEX_SECURITY
) {
3182 (void) printf("--> use 'ipsecconf -ln -i %s'",
3183 tparams
->ifta_lifr_name
);
3185 ipsr
= (ipsec_req_t
*)(&tparams
->ifta_secinfo
);
3186 if (ipsr
->ipsr_ah_req
& IPSEC_PREF_REQUIRED
) {
3187 (void) printf("ah (%s) ",
3188 rparsealg(ipsr
->ipsr_auth_alg
, IPSEC_PROTO_AH
));
3190 if (ipsr
->ipsr_esp_req
& IPSEC_PREF_REQUIRED
) {
3191 (void) printf("esp (%s",
3192 rparsealg(ipsr
->ipsr_esp_alg
, IPSEC_PROTO_ESP
));
3193 (void) printf("/%s)",
3194 rparsealg(ipsr
->ipsr_esp_auth_alg
, IPSEC_PROTO_AH
));
3197 (void) printf("\n");
3203 icfg_if_t interface
;
3205 icfg_handle_t handle
;
3207 char srcbuf
[INET6_ADDRSTRLEN
];
3208 char dstbuf
[INET6_ADDRSTRLEN
];
3212 struct sockaddr_storage taddr
;
3213 socklen_t socklen
= sizeof (taddr
);
3215 (void) strncpy(interface
.if_name
, name
, sizeof (interface
.if_name
));
3216 interface
.if_protocol
= SOCKET_AF(af
);
3217 if ((rc
= icfg_open(&handle
, &interface
)) != ICFG_SUCCESS
)
3218 Perror0_exit((char *)icfg_errmsg(rc
));
3221 * only print tunnel info for lun 0. If ioctl fails, assume
3222 * we are not a tunnel
3224 if (strchr(name
, ':') != NULL
||
3225 icfg_get_tunnel_lower(handle
, &protocol
) != ICFG_SUCCESS
) {
3232 (void) printf("\tinet");
3235 (void) printf("\tinet6");
3238 Perror0_exit("\ttunnel: Illegal lower stream\n\t");
3242 rc
= icfg_get_tunnel_src(handle
, (struct sockaddr
*)&taddr
, &socklen
);
3243 if (rc
== ICFG_NOT_SET
) {
3244 (void) strlcpy(srcbuf
, (protocol
== AF_INET
) ? "0.0.0.0" :
3245 "::", sizeof (srcbuf
));
3246 } else if (rc
!= ICFG_SUCCESS
) {
3247 Perror0_exit((char *)icfg_errmsg(rc
));
3249 rc
= icfg_sockaddr_to_str(protocol
, (struct sockaddr
*)&taddr
,
3250 srcbuf
, sizeof (srcbuf
));
3251 if (rc
!= ICFG_SUCCESS
) {
3252 Perror0_exit((char *)icfg_errmsg(rc
));
3256 (void) printf(" tunnel src %s ", srcbuf
);
3258 rc
= icfg_get_tunnel_dest(handle
, (struct sockaddr
*)&taddr
, &socklen
);
3259 if (rc
== ICFG_NOT_SET
) {
3260 (void) printf("\n");
3262 rc
= icfg_sockaddr_to_str(protocol
, (struct sockaddr
*)&taddr
,
3263 dstbuf
, sizeof (dstbuf
));
3264 if (rc
!= ICFG_SUCCESS
) {
3265 Perror0_exit((char *)icfg_errmsg(rc
));
3267 (void) printf("tunnel dst %s\n", dstbuf
);
3270 if (handle
->ifh_tunnel_params
!= NULL
&&
3271 (handle
->ifh_tunnel_params
->ifta_flags
& IFTUN_SECURITY
))
3272 print_tsec(handle
->ifh_tunnel_params
);
3275 * tabbed indicates tabbed and printed. Use it tell us whether
3276 * to tab and that we've printed something here, so we need a
3281 if (icfg_get_tunnel_hoplimit(handle
, &hoplimit
) == ICFG_SUCCESS
) {
3282 (void) printf("\ttunnel hop limit %d ", hoplimit
);
3286 if ((protocol
== AF_INET6
) &&
3287 (icfg_get_tunnel_encaplimit(handle
, &encaplimit
) ==
3290 (void) printf("\t");
3293 if (encaplimit
>= 0) {
3294 (void) printf("tunnel encapsulation limit %d",
3297 (void) printf("tunnel encapsulation limit disabled");
3302 (void) printf("\n");
3308 in_status(int force
, uint64_t flags
)
3310 struct sockaddr_in
*sin
, *laddr
;
3311 struct sockaddr_in netmask
= { AF_INET
};
3314 (void) printf("in_status(%s) flags 0x%llx\n", name
, flags
);
3316 /* only print status for IPv4 interfaces */
3317 if (!(flags
& IFF_IPV4
))
3320 /* if the interface is a tunnel, print the tunnel status */
3323 if (!(flags
& IFF_NOLOCAL
)) {
3324 (void) strncpy(lifr
.lifr_name
, name
, sizeof (lifr
.lifr_name
));
3325 if (ioctl(s
, SIOCGLIFADDR
, (caddr_t
)&lifr
) < 0) {
3326 if (errno
== EADDRNOTAVAIL
|| errno
== EAFNOSUPPORT
||
3330 (void) memset(&lifr
.lifr_addr
, 0,
3331 sizeof (lifr
.lifr_addr
));
3333 Perror0_exit("in_status: SIOCGLIFADDR");
3335 sin
= (struct sockaddr_in
*)&lifr
.lifr_addr
;
3336 (void) printf("\tinet %s ", inet_ntoa(sin
->sin_addr
));
3339 (void) printf("\tinet ");
3342 (void) strncpy(lifr
.lifr_name
, name
, sizeof (lifr
.lifr_name
));
3343 if (ioctl(s
, SIOCGLIFSUBNET
, (caddr_t
)&lifr
) < 0) {
3344 if (errno
== EADDRNOTAVAIL
|| errno
== EAFNOSUPPORT
||
3348 (void) memset(&lifr
.lifr_addr
, 0,
3349 sizeof (lifr
.lifr_addr
));
3351 Perror0_exit("in_status: SIOCGLIFSUBNET");
3354 sin
= (struct sockaddr_in
*)&lifr
.lifr_addr
;
3355 if ((flags
& IFF_NOLOCAL
) ||
3356 sin
->sin_addr
.s_addr
!= laddr
->sin_addr
.s_addr
) {
3357 (void) printf("subnet %s/%d ", inet_ntoa(sin
->sin_addr
),
3360 if (sin
->sin_family
!= AF_INET
) {
3361 (void) printf("Wrong family: %d\n", sin
->sin_family
);
3364 (void) strncpy(lifr
.lifr_name
, name
, sizeof (lifr
.lifr_name
));
3365 if (ioctl(s
, SIOCGLIFNETMASK
, (caddr_t
)&lifr
) < 0) {
3366 if (errno
!= EADDRNOTAVAIL
)
3367 Perror0_exit("in_status: SIOCGLIFNETMASK");
3368 (void) memset(&lifr
.lifr_addr
, 0, sizeof (lifr
.lifr_addr
));
3371 ((struct sockaddr_in
*)&lifr
.lifr_addr
)->sin_addr
;
3372 if (flags
& IFF_POINTOPOINT
) {
3373 (void) strncpy(lifr
.lifr_name
, name
, sizeof (lifr
.lifr_name
));
3374 if (ioctl(s
, SIOCGLIFDSTADDR
, (caddr_t
)&lifr
) < 0) {
3375 if (errno
== EADDRNOTAVAIL
)
3376 (void) memset(&lifr
.lifr_addr
, 0,
3377 sizeof (lifr
.lifr_addr
));
3379 Perror0_exit("in_status: SIOCGLIFDSTADDR");
3381 sin
= (struct sockaddr_in
*)&lifr
.lifr_dstaddr
;
3382 (void) printf("--> %s ", inet_ntoa(sin
->sin_addr
));
3384 (void) printf("netmask %x ", ntohl(netmask
.sin_addr
.s_addr
));
3385 if (flags
& IFF_BROADCAST
) {
3386 (void) strncpy(lifr
.lifr_name
, name
, sizeof (lifr
.lifr_name
));
3387 if (ioctl(s
, SIOCGLIFBRDADDR
, (caddr_t
)&lifr
) < 0) {
3388 if (errno
== EADDRNOTAVAIL
)
3389 (void) memset(&lifr
.lifr_addr
, 0,
3390 sizeof (lifr
.lifr_addr
));
3392 Perror0_exit("in_status: SIOCGLIFBRDADDR");
3394 sin
= (struct sockaddr_in
*)&lifr
.lifr_addr
;
3395 if (sin
->sin_addr
.s_addr
!= 0) {
3396 (void) printf("broadcast %s",
3397 inet_ntoa(sin
->sin_addr
));
3400 /* If there is a groupname, print it for lun 0 alone */
3401 if (strchr(name
, ':') == NULL
) {
3402 (void) memset(lifr
.lifr_groupname
, 0,
3403 sizeof (lifr
.lifr_groupname
));
3404 if (ioctl(s
, SIOCGLIFGROUPNAME
, (caddr_t
)&lifr
) >= 0) {
3405 if (strlen(lifr
.lifr_groupname
) > 0) {
3406 (void) printf("\n\tgroupname %s",
3407 lifr
.lifr_groupname
);
3411 (void) putchar('\n');
3415 in6_status(int force
, uint64_t flags
)
3417 char abuf
[INET6_ADDRSTRLEN
];
3418 struct sockaddr_in6
*sin6
, *laddr6
;
3421 (void) printf("in6_status(%s) flags 0x%llx\n", name
, flags
);
3423 if (!(flags
& IFF_IPV6
))
3426 /* if the interface is a tunnel, print the tunnel status */
3429 if (!(flags
& IFF_NOLOCAL
)) {
3430 (void) strncpy(lifr
.lifr_name
, name
, sizeof (lifr
.lifr_name
));
3431 if (ioctl(s
, SIOCGLIFADDR
, (caddr_t
)&lifr
) < 0) {
3432 if (errno
== EADDRNOTAVAIL
|| errno
== EAFNOSUPPORT
||
3436 (void) memset(&lifr
.lifr_addr
, 0,
3437 sizeof (lifr
.lifr_addr
));
3439 Perror0_exit("in_status6: SIOCGLIFADDR");
3441 sin6
= (struct sockaddr_in6
*)&lifr
.lifr_addr
;
3442 (void) printf("\tinet6 %s/%d ",
3443 inet_ntop(AF_INET6
, (void *)&sin6
->sin6_addr
,
3444 abuf
, sizeof (abuf
)),
3448 (void) printf("\tinet6 ");
3450 (void) strncpy(lifr
.lifr_name
, name
, sizeof (lifr
.lifr_name
));
3451 if (ioctl(s
, SIOCGLIFSUBNET
, (caddr_t
)&lifr
) < 0) {
3452 if (errno
== EADDRNOTAVAIL
|| errno
== EAFNOSUPPORT
||
3456 (void) memset(&lifr
.lifr_addr
, 0,
3457 sizeof (lifr
.lifr_addr
));
3459 Perror0_exit("in_status6: SIOCGLIFSUBNET");
3461 sin6
= (struct sockaddr_in6
*)&lifr
.lifr_addr
;
3462 if ((flags
& IFF_NOLOCAL
) ||
3463 !IN6_ARE_ADDR_EQUAL(&sin6
->sin6_addr
, &laddr6
->sin6_addr
)) {
3464 (void) printf("subnet %s/%d ",
3465 inet_ntop(AF_INET6
, (void *)&sin6
->sin6_addr
,
3466 abuf
, sizeof (abuf
)),
3469 if (sin6
->sin6_family
!= AF_INET6
) {
3470 (void) printf("Wrong family: %d\n", sin6
->sin6_family
);
3472 if (flags
& IFF_POINTOPOINT
) {
3473 (void) strncpy(lifr
.lifr_name
, name
, sizeof (lifr
.lifr_name
));
3474 if (ioctl(s
, SIOCGLIFDSTADDR
, (caddr_t
)&lifr
) < 0) {
3475 if (errno
== EADDRNOTAVAIL
)
3476 (void) memset(&lifr
.lifr_addr
, 0,
3477 sizeof (lifr
.lifr_addr
));
3479 Perror0_exit("in_status6: SIOCGLIFDSTADDR");
3481 sin6
= (struct sockaddr_in6
*)&lifr
.lifr_dstaddr
;
3482 (void) printf("--> %s ",
3483 inet_ntop(AF_INET6
, (void *)&sin6
->sin6_addr
,
3484 abuf
, sizeof (abuf
)));
3487 (void) putchar('\n');
3488 (void) putchar('\t');
3489 (void) strncpy(lifr
.lifr_name
, name
, sizeof (lifr
.lifr_name
));
3490 if (ioctl(s
, SIOCGLIFTOKEN
, (caddr_t
)&lifr
) < 0) {
3491 if (errno
== EADDRNOTAVAIL
|| errno
== EINVAL
)
3492 (void) memset(&lifr
.lifr_addr
, 0,
3493 sizeof (lifr
.lifr_addr
));
3495 Perror0_exit("in_status6: SIOCGLIFTOKEN");
3497 sin6
= (struct sockaddr_in6
*)&lifr
.lifr_addr
;
3498 (void) printf("token %s/%d ",
3499 inet_ntop(AF_INET6
, (void *)&sin6
->sin6_addr
,
3500 abuf
, sizeof (abuf
)),
3503 if (ioctl(s
, SIOCGLIFLNKINFO
, (caddr_t
)&lifr
) < 0) {
3504 if (errno
!= EINVAL
) {
3505 Perror0_exit("in_status6: SIOCGLIFLNKINFO");
3508 (void) printf("maxhops %u, reachtime %u ms, "
3509 "reachretrans %u ms, maxmtu %u ",
3510 lifr
.lifr_ifinfo
.lir_maxhops
,
3511 lifr
.lifr_ifinfo
.lir_reachtime
,
3512 lifr
.lifr_ifinfo
.lir_reachretrans
,
3513 lifr
.lifr_ifinfo
.lir_maxmtu
);
3516 /* If there is a groupname, print it for only the physical interface */
3517 if (strchr(name
, ':') == NULL
) {
3518 if (ioctl(s
, SIOCGLIFGROUPNAME
, &lifr
) >= 0 &&
3519 lifr
.lifr_groupname
[0] != '\0') {
3520 (void) printf("\n\tgroupname %s", lifr
.lifr_groupname
);
3523 (void) putchar('\n');
3527 in_configinfo(int force
, uint64_t flags
)
3529 struct sockaddr_in
*sin
, *laddr
;
3530 struct sockaddr_in netmask
= { AF_INET
};
3533 (void) printf("in_configinfo(%s) flags 0x%llx\n", name
, flags
);
3535 /* only configinfo info for IPv4 interfaces */
3536 if (!(flags
& IFF_IPV4
))
3539 if (!(flags
& IFF_NOLOCAL
)) {
3540 (void) strncpy(lifr
.lifr_name
, name
, sizeof (lifr
.lifr_name
));
3541 if (ioctl(s
, SIOCGLIFADDR
, (caddr_t
)&lifr
) < 0) {
3542 if (errno
== EADDRNOTAVAIL
|| errno
== EAFNOSUPPORT
||
3546 (void) memset(&lifr
.lifr_addr
, 0,
3547 sizeof (lifr
.lifr_addr
));
3549 Perror0_exit("in_configinfo: SIOCGLIFADDR");
3551 sin
= (struct sockaddr_in
*)&lifr
.lifr_addr
;
3552 if (strchr(name
, ':') != NULL
) {
3553 (void) printf(" addif %s ", inet_ntoa(sin
->sin_addr
));
3555 (void) printf(" set %s ", inet_ntoa(sin
->sin_addr
));
3560 (void) strncpy(lifr
.lifr_name
, name
, sizeof (lifr
.lifr_name
));
3561 if (ioctl(s
, SIOCGLIFSUBNET
, (caddr_t
)&lifr
) < 0) {
3562 if (errno
== EADDRNOTAVAIL
|| errno
== EAFNOSUPPORT
||
3566 (void) memset(&lifr
.lifr_addr
, 0,
3567 sizeof (lifr
.lifr_addr
));
3569 Perror0_exit("in_configinfo: SIOCGLIFSUBNET");
3572 sin
= (struct sockaddr_in
*)&lifr
.lifr_addr
;
3574 if ((flags
& IFF_NOLOCAL
) ||
3575 sin
->sin_addr
.s_addr
!= laddr
->sin_addr
.s_addr
) {
3576 (void) printf(" subnet %s/%d ", inet_ntoa(sin
->sin_addr
),
3579 (void) strncpy(lifr
.lifr_name
, name
, sizeof (lifr
.lifr_name
));
3580 if (ioctl(s
, SIOCGLIFNETMASK
, (caddr_t
)&lifr
) < 0) {
3581 if (errno
!= EADDRNOTAVAIL
)
3582 Perror0_exit("in_configinfo: SIOCGLIFNETMASK");
3583 (void) memset(&lifr
.lifr_addr
, 0, sizeof (lifr
.lifr_addr
));
3586 ((struct sockaddr_in
*)&lifr
.lifr_addr
)->sin_addr
;
3587 if (flags
& IFF_POINTOPOINT
) {
3588 (void) strncpy(lifr
.lifr_name
, name
, sizeof (lifr
.lifr_name
));
3589 if (ioctl(s
, SIOCGLIFDSTADDR
, (caddr_t
)&lifr
) < 0) {
3590 if (errno
== EADDRNOTAVAIL
)
3591 (void) memset(&lifr
.lifr_addr
, 0,
3592 sizeof (lifr
.lifr_addr
));
3594 Perror0_exit("in_configinfo: SIOCGLIFDSTADDR");
3596 sin
= (struct sockaddr_in
*)&lifr
.lifr_dstaddr
;
3597 (void) printf(" destination %s ", inet_ntoa(sin
->sin_addr
));
3599 (void) printf(" netmask 0x%x ", ntohl(netmask
.sin_addr
.s_addr
));
3600 if (flags
& IFF_BROADCAST
) {
3601 (void) strncpy(lifr
.lifr_name
, name
, sizeof (lifr
.lifr_name
));
3602 if (ioctl(s
, SIOCGLIFBRDADDR
, (caddr_t
)&lifr
) < 0) {
3603 if (errno
== EADDRNOTAVAIL
)
3604 (void) memset(&lifr
.lifr_addr
, 0,
3605 sizeof (lifr
.lifr_addr
));
3607 Perror0_exit("in_configinfo: SIOCGLIFBRDADDR");
3609 sin
= (struct sockaddr_in
*)&lifr
.lifr_addr
;
3610 if (sin
->sin_addr
.s_addr
!= 0) {
3611 (void) printf(" broadcast %s ",
3612 inet_ntoa(sin
->sin_addr
));
3616 /* If there is a groupname, print it for only the physical interface */
3617 if (strchr(name
, ':') == NULL
) {
3618 if (ioctl(s
, SIOCGLIFGROUPNAME
, &lifr
) >= 0 &&
3619 lifr
.lifr_groupname
[0] != '\0') {
3620 (void) printf(" group %s ", lifr
.lifr_groupname
);
3624 /* Print flags to configure */
3625 print_config_flags(flags
);
3627 /* IFF_NOARP applies to AF_INET only */
3628 if (flags
& IFF_NOARP
) {
3629 (void) printf("-arp ");
3634 in6_configinfo(int force
, uint64_t flags
)
3636 char abuf
[INET6_ADDRSTRLEN
];
3637 struct sockaddr_in6
*sin6
, *laddr6
;
3640 (void) printf("in6_configinfo(%s) flags 0x%llx\n", name
,
3643 if (!(flags
& IFF_IPV6
))
3646 if (!(flags
& IFF_NOLOCAL
)) {
3647 (void) strncpy(lifr
.lifr_name
, name
, sizeof (lifr
.lifr_name
));
3648 if (ioctl(s
, SIOCGLIFADDR
, (caddr_t
)&lifr
) < 0) {
3649 if (errno
== EADDRNOTAVAIL
|| errno
== EAFNOSUPPORT
||
3653 (void) memset(&lifr
.lifr_addr
, 0,
3654 sizeof (lifr
.lifr_addr
));
3656 Perror0_exit("in6_configinfo: SIOCGLIFADDR");
3658 sin6
= (struct sockaddr_in6
*)&lifr
.lifr_addr
;
3659 if (strchr(name
, ':') != NULL
) {
3660 (void) printf(" addif %s/%d ",
3661 inet_ntop(AF_INET6
, (void *)&sin6
->sin6_addr
,
3662 abuf
, sizeof (abuf
)),
3665 (void) printf(" set %s/%d ",
3666 inet_ntop(AF_INET6
, (void *)&sin6
->sin6_addr
,
3667 abuf
, sizeof (abuf
)),
3672 (void) strncpy(lifr
.lifr_name
, name
, sizeof (lifr
.lifr_name
));
3673 if (ioctl(s
, SIOCGLIFSUBNET
, (caddr_t
)&lifr
) < 0) {
3674 if (errno
== EADDRNOTAVAIL
|| errno
== EAFNOSUPPORT
||
3678 (void) memset(&lifr
.lifr_addr
, 0,
3679 sizeof (lifr
.lifr_addr
));
3681 Perror0_exit("in6_configinfo: SIOCGLIFSUBNET");
3683 sin6
= (struct sockaddr_in6
*)&lifr
.lifr_addr
;
3684 if ((flags
& IFF_NOLOCAL
) ||
3685 !IN6_ARE_ADDR_EQUAL(&sin6
->sin6_addr
, &laddr6
->sin6_addr
)) {
3686 (void) printf(" subnet %s/%d ",
3687 inet_ntop(AF_INET6
, (void *)&sin6
->sin6_addr
,
3688 abuf
, sizeof (abuf
)),
3692 if (flags
& IFF_POINTOPOINT
) {
3693 (void) strncpy(lifr
.lifr_name
, name
, sizeof (lifr
.lifr_name
));
3694 if (ioctl(s
, SIOCGLIFDSTADDR
, (caddr_t
)&lifr
) < 0) {
3695 if (errno
== EADDRNOTAVAIL
)
3696 (void) memset(&lifr
.lifr_addr
, 0,
3697 sizeof (lifr
.lifr_addr
));
3699 Perror0_exit("in6_configinfo: SIOCGLIFDSTADDR");
3701 sin6
= (struct sockaddr_in6
*)&lifr
.lifr_dstaddr
;
3702 (void) printf(" destination %s ",
3703 inet_ntop(AF_INET6
, (void *)&sin6
->sin6_addr
,
3704 abuf
, sizeof (abuf
)));
3707 (void) strncpy(lifr
.lifr_name
, name
, sizeof (lifr
.lifr_name
));
3708 if (ioctl(s
, SIOCGLIFTOKEN
, (caddr_t
)&lifr
) < 0) {
3709 if (errno
== EADDRNOTAVAIL
|| errno
== EINVAL
)
3710 (void) memset(&lifr
.lifr_addr
, 0,
3711 sizeof (lifr
.lifr_addr
));
3713 Perror0_exit("in6_configinfo: SIOCGLIFTOKEN");
3715 sin6
= (struct sockaddr_in6
*)&lifr
.lifr_addr
;
3716 (void) printf(" token %s/%d ",
3717 inet_ntop(AF_INET6
, (void *)&sin6
->sin6_addr
,
3718 abuf
, sizeof (abuf
)),
3722 /* If there is a groupname, print it for only the physical interface */
3723 if (strchr(name
, ':') == NULL
) {
3724 if (ioctl(s
, SIOCGLIFGROUPNAME
, &lifr
) >= 0 &&
3725 lifr
.lifr_groupname
[0] != '\0') {
3726 (void) printf(" group %s ", lifr
.lifr_groupname
);
3730 /* Print flags to configure */
3731 print_config_flags(flags
);
3733 /* IFF_NONUD applies to AF_INET6 only */
3734 if (flags
& IFF_NONUD
) {
3735 (void) printf("-nud ");
3740 * We need to plink both the arp-device stream and the arp-ip-device stream.
3741 * However the muxid is stored only in IP. Plumbing 2 streams individually
3742 * is not atomic, and if ifconfig is killed, the resulting plumbing can
3743 * be inconsistent. For eg. if only the arp stream is plumbed, we have lost
3744 * the muxid, and the half-baked plumbing can neither be unplumbed nor
3745 * replumbed, thus requiring a reboot. To avoid the above the following
3748 * Ifconfig asks IP to enforce atomicity of plumbing the arp and IP streams.
3749 * This is done by pushing arp on to the mux (/dev/udp). ARP adds some
3750 * extra information in the I_PLINK and I_PUNLINK ioctls to let IP know
3751 * that the plumbing/unplumbing has to be done atomically. Ifconfig plumbs
3752 * the IP stream first, and unplumbs it last. The kernel (IP) does not
3753 * allow IP stream to be unplumbed without unplumbing arp stream. Similarly
3754 * it does not allow arp stream to be plumbed before IP stream is plumbed.
3755 * There is no need to use SIOCSLIFMUXID, since the whole operation is atomic,
3756 * and IP uses the info in the I_PLINK message to get the muxid.
3758 * a. STREAMS does not allow us to use /dev/ip itself as the mux. So we use
3760 * b. SIOCGLIFMUXID returns the muxid corresponding to the V4 or V6 stream
3761 * depending on the open i.e. V4 vs V6 open. So we need to use /dev/udp
3762 * or /dev/udp6 for SIOCGLIFMUXID and SIOCSLIFMUXID.
3763 * c. We need to push ARP in order to get the required kernel support for
3764 * atomic plumbings. The actual work done by ARP is explained in arp.c
3765 * Without pushing ARP, we will still be able to plumb/unplumb. But
3766 * it is not atomic, and is supported by the kernel for backward
3767 * compatibility for other utilities like atmifconfig etc. In this case
3768 * the utility must use SIOCSLIFMUXID.
3771 plumb_one_device(int af
)
3773 int arp_muxid
= -1, ip_muxid
;
3774 int mux_fd
, ip_fd
, arp_fd
;
3778 char provider
[DLPI_LINKNAME_MAX
];
3779 dlpi_handle_t dh_arp
, dh_ip
;
3782 * We use DLPI_NOATTACH because the ip module will do the attach
3783 * itself for DLPI style-2 devices.
3785 retval
= dlpi_open(name
, &dh_ip
, DLPI_NOATTACH
);
3786 if (retval
!= DLPI_SUCCESS
)
3787 Perrdlpi_exit("cannot open link", name
, retval
);
3789 if ((retval
= dlpi_parselink(name
, provider
, &ppa
)) != DLPI_SUCCESS
)
3790 Perrdlpi_exit("dlpi_parselink", name
, retval
);
3793 (void) printf("ifconfig: plumb_one_device: provider %s,"
3794 " ppa %u\n", provider
, ppa
);
3797 ip_fd
= dlpi_fd(dh_ip
);
3798 if (ioctl(ip_fd
, I_PUSH
, IP_MOD_NAME
) == -1)
3799 Perror2_exit("I_PUSH", IP_MOD_NAME
);
3802 * Push the ARP module onto the interface stream. IP uses
3803 * this to send resolution requests up to ARP. We need to
3804 * do this before the SLIFNAME ioctl is sent down because
3805 * the interface becomes publicly known as soon as the SLIFNAME
3806 * ioctl completes. Thus some other process trying to bring up
3807 * the interface after SLIFNAME but before we have pushed ARP
3808 * could hang. We pop the module again later if it is not needed.
3810 if (ioctl(ip_fd
, I_PUSH
, ARP_MOD_NAME
) == -1)
3811 Perror2_exit("I_PUSH", ARP_MOD_NAME
);
3814 * Set IFF_IPV4/IFF_IPV6 flags.
3815 * At this point in time the kernel also allows an
3816 * override of the CANTCHANGE flags.
3818 lifr
.lifr_name
[0] = '\0';
3819 if (ioctl(ip_fd
, SIOCGLIFFLAGS
, (char *)&lifr
) == -1)
3820 Perror0_exit("plumb_one_device: SIOCGLIFFLAGS");
3822 /* Set the name string and the IFF_IPV* flag */
3823 if (af
== AF_INET6
) {
3824 lifr
.lifr_flags
|= IFF_IPV6
;
3825 lifr
.lifr_flags
&= ~(IFF_BROADCAST
| IFF_IPV4
);
3827 lifr
.lifr_flags
|= IFF_IPV4
;
3828 lifr
.lifr_flags
&= ~IFF_IPV6
;
3831 /* record the device and module names as interface name */
3832 lifr
.lifr_ppa
= ppa
;
3833 (void) strncpy(lifr
.lifr_name
, name
, sizeof (lifr
.lifr_name
));
3835 /* set the interface name */
3836 if (ioctl(ip_fd
, SIOCSLIFNAME
, (char *)&lifr
) == -1) {
3837 if (errno
!= EEXIST
)
3838 Perror0_exit("SIOCSLIFNAME for ip");
3840 * This difference between the way we behave for EEXIST
3841 * and that with other errors exists to preserve legacy
3842 * behaviour. Earlier when foreachinterface() and matchif()
3843 * were doing the duplicate interface name checks, for
3844 * already existing interfaces, inetplumb() returned "0".
3845 * To preserve this behaviour, Perror0() and return are
3846 * called for EEXIST.
3848 Perror0("SIOCSLIFNAME for ip");
3852 /* Get the full set of existing flags for this stream */
3853 if (ioctl(ip_fd
, SIOCGLIFFLAGS
, (char *)&lifr
) == -1)
3854 Perror0_exit("plumb_one_device: SIOCFLIFFLAGS");
3857 (void) printf("ifconfig: plumb_one_device: %s got flags:\n",
3859 print_flags(lifr
.lifr_flags
);
3860 (void) putchar('\n');
3863 /* Check if arp is not actually needed */
3864 if (lifr
.lifr_flags
& (IFF_NOARP
|IFF_IPV6
)) {
3865 if (ioctl(ip_fd
, I_POP
, 0) == -1)
3866 Perror2_exit("I_POP", ARP_MOD_NAME
);
3870 * Open "/dev/udp" for use as a multiplexor to PLINK the
3871 * interface stream under. We use "/dev/udp" instead of "/dev/ip"
3872 * since STREAMS will not let you PLINK a driver under itself,
3873 * and "/dev/ip" is typically the driver at the bottom of
3874 * the stream for tunneling interfaces.
3877 udp_dev_name
= UDP6_DEV_NAME
;
3879 udp_dev_name
= UDP_DEV_NAME
;
3880 if ((mux_fd
= open_arp_on_udp(udp_dev_name
)) == -1)
3883 /* Check if arp is not needed */
3884 if (lifr
.lifr_flags
& (IFF_NOARP
|IFF_IPV6
)) {
3886 * PLINK the interface stream so that ifconfig can exit
3887 * without tearing down the stream.
3889 if ((ip_muxid
= ioctl(mux_fd
, I_PLINK
, ip_fd
)) == -1)
3890 Perror0_exit("I_PLINK for ip");
3891 (void) close(mux_fd
);
3896 * This interface does use ARP, so set up a separate stream
3897 * from the interface to ARP.
3899 * Note: modules specified by the user are pushed
3900 * only on the interface stream, not on the ARP stream.
3903 (void) printf("ifconfig: plumb_one_device: ifname: %s\n", name
);
3906 * We use DLPI_NOATTACH because the arp module will do the attach
3907 * itself for DLPI style-2 devices.
3909 retval
= dlpi_open(name
, &dh_arp
, DLPI_NOATTACH
);
3910 if (retval
!= DLPI_SUCCESS
)
3911 Perrdlpi_exit("cannot open link", name
, retval
);
3913 arp_fd
= dlpi_fd(dh_arp
);
3914 if (ioctl(arp_fd
, I_PUSH
, ARP_MOD_NAME
) == -1)
3915 Perror2_exit("I_PUSH", ARP_MOD_NAME
);
3918 * Tell ARP the name and unit number for this interface.
3919 * Note that arp has no support for transparent ioctls.
3921 if (strioctl(arp_fd
, SIOCSLIFNAME
, (char *)&lifr
,
3922 sizeof (lifr
)) == -1) {
3923 if (errno
!= EEXIST
)
3924 Perror0_exit("SIOCSLIFNAME for arp");
3925 Perror0("SIOCSLIFNAME for arp");
3928 (void) close(mux_fd
);
3932 * PLINK the IP and ARP streams so that ifconfig can exit
3933 * without tearing down the stream.
3935 if ((ip_muxid
= ioctl(mux_fd
, I_PLINK
, ip_fd
)) == -1)
3936 Perror0_exit("I_PLINK for ip");
3937 if ((arp_muxid
= ioctl(mux_fd
, I_PLINK
, arp_fd
)) == -1) {
3938 (void) ioctl(mux_fd
, I_PUNLINK
, ip_muxid
);
3939 Perror0_exit("I_PLINK for arp");
3943 (void) printf("arp muxid = %d\n", arp_muxid
);
3946 (void) close(mux_fd
);
3951 * If this is a physical interface then remove it.
3952 * If it is a logical interface name use SIOCLIFREMOVEIF to
3953 * remove it. In both cases fail if it doesn't exist.
3957 inetunplumb(char *arg
, int64_t param
)
3959 int ip_muxid
, arp_muxid
;
3965 boolean_t changed_arp_muxid
= _B_FALSE
;
3968 strptr
= strchr(name
, ':');
3969 if (strptr
!= NULL
|| strcmp(name
, LOOPBACK_IF
) == 0) {
3970 /* Can't unplumb logical interface zero */
3971 if (strptr
!= NULL
&& strcmp(strptr
, ":0") == 0) {
3972 (void) fprintf(stderr
, "ifconfig: unplumb:"
3973 " Cannot unplumb %s: Invalid interface\n", name
);
3976 (void) strncpy(lifr
.lifr_name
, name
, sizeof (lifr
.lifr_name
));
3977 (void) memset(&lifr
.lifr_addr
, 0, sizeof (lifr
.lifr_addr
));
3979 if (ioctl(s
, SIOCLIFREMOVEIF
, (caddr_t
)&lifr
) < 0)
3980 Perror0_exit("unplumb: SIOCLIFREMOVEIF");
3985 * We used /dev/udp or udp6 to set up the mux. So we have to use
3986 * the same now for PUNLINK also.
3988 if (afp
->af_af
== AF_INET6
)
3989 udp_dev_name
= UDP6_DEV_NAME
;
3991 udp_dev_name
= UDP_DEV_NAME
;
3993 if ((muxid_fd
= open(udp_dev_name
, O_RDWR
)) == -1)
3996 if ((mux_fd
= open_arp_on_udp(udp_dev_name
)) == -1)
3999 (void) strncpy(lifr
.lifr_name
, name
, sizeof (lifr
.lifr_name
));
4000 if (ioctl(muxid_fd
, SIOCGLIFFLAGS
, (caddr_t
)&lifr
) < 0) {
4001 Perror0_exit("unplumb: SIOCGLIFFLAGS");
4003 flags
= lifr
.lifr_flags
;
4004 if (ioctl(muxid_fd
, SIOCGLIFMUXID
, (caddr_t
)&lifr
) < 0) {
4005 Perror0_exit("unplumb: SIOCGLIFMUXID");
4007 arp_muxid
= lifr
.lifr_arp_muxid
;
4008 ip_muxid
= lifr
.lifr_ip_muxid
;
4010 * We don't have a good way of knowing whether the arp stream is
4011 * plumbed. We can't rely on IFF_NOARP because someone could
4012 * have turned it off later using "ifconfig xxx -arp".
4014 if (arp_muxid
!= 0) {
4016 (void) printf("arp_muxid %d\n", arp_muxid
);
4017 if (ioctl(mux_fd
, I_PUNLINK
, arp_muxid
) < 0) {
4018 if ((errno
== EINVAL
) &&
4019 (flags
& (IFF_NOARP
| IFF_IPV6
))) {
4021 * Some plumbing utilities set the muxid to
4022 * -1 or some invalid value to signify that
4023 * there is no arp stream. Set the muxid to 0
4024 * before trying to unplumb the IP stream.
4025 * IP does not allow the IP stream to be
4026 * unplumbed if it sees a non-null arp muxid,
4027 * for consistency of IP-ARP streams.
4029 lifr
.lifr_arp_muxid
= 0;
4030 (void) ioctl(muxid_fd
, SIOCSLIFMUXID
,
4032 changed_arp_muxid
= _B_TRUE
;
4034 Perror0("I_PUNLINK for arp");
4039 (void) printf("ip_muxid %d\n", ip_muxid
);
4041 if (ioctl(mux_fd
, I_PUNLINK
, ip_muxid
) < 0) {
4042 if (changed_arp_muxid
) {
4044 * Some error occurred, and we need to restore
4045 * everything back to what it was.
4048 lifr
.lifr_arp_muxid
= arp_muxid
;
4049 lifr
.lifr_ip_muxid
= ip_muxid
;
4050 (void) ioctl(muxid_fd
, SIOCSLIFMUXID
, (caddr_t
)&lifr
);
4053 Perror0_exit("I_PUNLINK for ip");
4055 (void) close(mux_fd
);
4056 (void) close(muxid_fd
);
4061 * If this is a physical interface then create it unless it is already
4062 * present. If it is a logical interface name use SIOCLIFADDIF to
4063 * create and (and fail it if already exists.)
4064 * As a special case send SIOCLIFADDIF for the loopback interface. This
4065 * is needed since there is no other notion of plumbing the loopback
4070 inetplumb(char *arg
, int64_t param
)
4076 strptr
= strchr(name
, ':');
4077 islo
= (strcmp(name
, LOOPBACK_IF
) == 0);
4079 if (strptr
!= NULL
|| islo
) {
4080 (void) memset(&lifr
, 0, sizeof (lifr
));
4081 (void) strlcpy(lifr
.lifr_name
, name
, sizeof (lifr
.lifr_name
));
4082 if (islo
&& ioctl(s
, SIOCGLIFADDR
, (caddr_t
)&lifr
) >= 0) {
4084 (void) fprintf(stderr
,
4085 "ifconfig: %s already exists\n", name
);
4089 if (ioctl(s
, SIOCLIFADDIF
, (caddr_t
)&lifr
) < 0) {
4090 if (errno
== EEXIST
) {
4092 (void) fprintf(stderr
,
4093 "ifconfig: %s already exists\n",
4097 Perror2_exit("plumb: SIOCLIFADDIF", name
);
4101 * IP can create the new logical interface on a different
4102 * physical interface in the same IPMP group. Take the new
4103 * interface into account for further operations.
4105 (void) strncpy(name
, lifr
.lifr_name
, sizeof (name
));
4110 * For global zone, check if the interface is used by a non-global
4111 * zone, note that the non-global zones doesn't need this check,
4112 * because zoneadm has taken care of this when the zone boots.
4114 zoneid
= getzoneid();
4115 if (zoneid
== GLOBAL_ZONEID
) {
4119 ret
= zone_check_datalink(&zoneid
, name
);
4121 char zonename
[ZONENAME_MAX
];
4123 (void) getzonenamebyid(zoneid
, zonename
, ZONENAME_MAX
);
4124 (void) fprintf(stderr
, "%s is used by non-global"
4125 "zone: %s\n", name
, zonename
);
4131 (void) printf("inetplumb: %s af %d\n", name
, afp
->af_af
);
4133 plumb_one_device(afp
->af_af
);
4138 Perror0(const char *cmd
)
4140 Perror2(cmd
, lifr
.lifr_name
);
4144 Perror0_exit(const char *cmd
)
4152 Perror2(const char *cmd
, const char *str
)
4156 (void) fprintf(stderr
, "ifconfig: %s: ", cmd
);
4160 (void) fprintf(stderr
, "%s: no such interface\n", str
);
4163 (void) fprintf(stderr
, "%s: permission denied\n", str
);
4166 (void) fprintf(stderr
, "%s: already exists\n", str
);
4175 * Print out error message (Perror2()) and exit
4178 Perror2_exit(const char *cmd
, const char *str
)
4186 Perrdlpi(const char *cmd
, const char *linkname
, int err
)
4188 (void) fprintf(stderr
, "ifconfig: %s \"%s\": %s\n", cmd
,
4189 linkname
, dlpi_strerror(err
));
4193 * Print out error message (Perrdlpi()) and exit
4196 Perrdlpi_exit(const char *cmd
, const char *linkname
, int err
)
4198 Perrdlpi(cmd
, linkname
, err
);
4203 * If the last argument is non-NULL allow a <addr>/<n> syntax and
4204 * pass out <n> in *plenp.
4205 * If <n> doesn't parse return BAD_ADDR as *plenp.
4206 * If no /<n> is present return NO_PREFIX as *plenp.
4209 in_getaddr(char *s
, struct sockaddr
*saddr
, int *plenp
)
4211 /* LINTED: alignment */
4212 struct sockaddr_in
*sin
= (struct sockaddr_in
*)saddr
;
4218 (void) strncpy(str
, s
, sizeof (str
));
4221 * Look for '/'<n> is plenp
4223 if (plenp
!= NULL
) {
4226 *plenp
= in_getprefixlen(str
, _B_TRUE
, IP_ABITS
);
4227 if (*plenp
== BAD_ADDR
)
4229 cp
= strchr(str
, '/');
4232 } else if (strchr(str
, '/') != NULL
) {
4233 (void) fprintf(stderr
, "ifconfig: %s: unexpected '/'\n", str
);
4237 (void) memset(sin
, 0, sizeof (*sin
));
4240 * Try to catch attempts to set the broadcast address to all 1's.
4242 if (strcmp(str
, "255.255.255.255") == 0 ||
4243 (strtoul(str
, (char **)NULL
, 0) == 0xffffffffUL
)) {
4244 sin
->sin_family
= AF_INET
;
4245 sin
->sin_addr
.s_addr
= 0xffffffff;
4249 hp
= getipnodebyname(str
, AF_INET
, 0, &error_num
);
4251 sin
->sin_family
= hp
->h_addrtype
;
4252 (void) memcpy(&sin
->sin_addr
, hp
->h_addr
, hp
->h_length
);
4256 np
= getnetbyname(str
);
4258 sin
->sin_family
= np
->n_addrtype
;
4259 sin
->sin_addr
= inet_makeaddr(np
->n_net
, INADDR_ANY
);
4262 if (error_num
== TRY_AGAIN
) {
4263 (void) fprintf(stderr
, "ifconfig: %s: bad address "
4264 "(try again later)\n", s
);
4266 (void) fprintf(stderr
, "ifconfig: %s: bad address\n", s
);
4272 * If the last argument is non-NULL allow a <addr>/<n> syntax and
4273 * pass out <n> in *plenp.
4274 * If <n> doesn't parse return BAD_ADDR as *plenp.
4275 * If no /<n> is present return NO_PREFIX as *plenp.
4278 in6_getaddr(char *s
, struct sockaddr
*saddr
, int *plenp
)
4280 /* LINTED: alignment */
4281 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)saddr
;
4286 (void) strncpy(str
, s
, sizeof (str
));
4289 * Look for '/'<n> is plenp
4291 if (plenp
!= NULL
) {
4294 *plenp
= in_getprefixlen(str
, _B_TRUE
, IPV6_ABITS
);
4295 if (*plenp
== BAD_ADDR
)
4297 cp
= strchr(str
, '/');
4300 } else if (strchr(str
, '/') != NULL
) {
4301 (void) fprintf(stderr
, "ifconfig: %s: unexpected '/'\n", str
);
4305 (void) memset(sin6
, 0, sizeof (*sin6
));
4307 hp
= getipnodebyname(str
, AF_INET6
, 0, &error_num
);
4309 sin6
->sin6_family
= hp
->h_addrtype
;
4310 (void) memcpy(&sin6
->sin6_addr
, hp
->h_addr
, hp
->h_length
);
4314 if (error_num
== TRY_AGAIN
) {
4315 (void) fprintf(stderr
, "ifconfig: %s: bad address "
4316 "(try again later)\n", s
);
4318 (void) fprintf(stderr
, "ifconfig: %s: bad address\n", s
);
4324 * If "slash" is zero this parses the whole string as
4325 * an integer. With "slash" non zero it parses the tail part as an integer.
4327 * If it is not a valid integer this returns BAD_ADDR.
4328 * If there is /<n> present this returns NO_PREFIX.
4331 in_getprefixlen(char *addr
, boolean_t slash
, int max_plen
)
4337 str
= strchr(addr
, '/');
4344 prefixlen
= strtol(str
, &end
, 10);
4349 if (max_plen
!= 0 && max_plen
< prefixlen
)
4355 * Convert a prefix length to a mask.
4356 * Returns 1 if ok. 0 otherwise.
4357 * Assumes the mask array is zero'ed by the caller.
4360 in_prefixlentomask(int prefixlen
, int maxlen
, uchar_t
*mask
)
4362 if (prefixlen
< 0 || prefixlen
> maxlen
)
4365 while (prefixlen
> 0) {
4366 if (prefixlen
>= 8) {
4371 *mask
|= 1 << (8 - prefixlen
);
4378 print_flags(uint64_t flags
)
4380 boolean_t first
= _B_TRUE
;
4383 (void) printf("flags=%llx", flags
);
4384 cnt
= sizeof (if_flags_tbl
) / sizeof (if_flags_t
);
4385 for (i
= 0; i
< cnt
; i
++) {
4386 if (flags
& if_flags_tbl
[i
].iff_value
) {
4392 * It has to be here and not with the
4393 * printf below because for the last one,
4394 * we don't want a comma before the ">".
4398 (void) printf("%s", if_flags_tbl
[i
].iff_name
);
4406 print_config_flags(uint64_t flags
)
4410 cnt
= sizeof (if_config_cmd_tbl
) / sizeof (if_config_cmd_t
);
4411 for (i
= 0; i
< cnt
; i
++) {
4412 if (flags
& if_config_cmd_tbl
[i
].iff_flag
) {
4413 (void) printf("%s ", if_config_cmd_tbl
[i
].iff_name
);
4419 * Use the configured directory lookup mechanism (e.g. files/NIS/NIS+/...)
4420 * to find the network mask. Returns true if we found one to set.
4422 * The parameter addr_set controls whether we should get the address of
4423 * the working interface for the netmask query. If addr_set is true,
4424 * we will use the address provided. Otherwise, we will find the working
4425 * interface's address and use it instead.
4428 in_getmask(struct sockaddr_in
*saddr
, boolean_t addr_set
)
4430 struct sockaddr_in ifaddr
;
4433 * Read the address from the interface if it is not passed in.
4436 (void) strncpy(lifr
.lifr_name
, name
, sizeof (lifr
.lifr_name
));
4437 if (ioctl(s
, SIOCGLIFADDR
, (caddr_t
)&lifr
) < 0) {
4438 if (errno
!= EADDRNOTAVAIL
) {
4439 (void) fprintf(stderr
, "Need net number for "
4444 ifaddr
= *((struct sockaddr_in
*)&lifr
.lifr_addr
);
4446 ifaddr
.sin_addr
= saddr
->sin_addr
;
4448 if (getnetmaskbyaddr(ifaddr
.sin_addr
, &saddr
->sin_addr
) == 0) {
4449 saddr
->sin_family
= AF_INET
;
4456 strioctl(int s
, int cmd
, char *buf
, int buflen
)
4458 struct strioctl ioc
;
4460 (void) memset(&ioc
, 0, sizeof (ioc
));
4463 ioc
.ic_len
= buflen
;
4465 return (ioctl(s
, I_STR
, (char *)&ioc
));
4469 add_ni(const char *name
)
4474 for (pp
= &ni_list
; (p
= *pp
) != NULL
; pp
= &(p
->ni_next
)) {
4475 if (strcmp(p
->ni_name
, name
) == 0) {
4477 (void) fprintf(stderr
, "'%s' is a duplicate\n",
4484 (void) fprintf(stderr
, "adding '%s'\n",
4487 if ((p
= malloc(sizeof (ni_t
))) == NULL
)
4490 (void) strlcpy(p
->ni_name
, name
, sizeof (p
->ni_name
));
4499 ni_entry(const char *linkname
, void *arg
)
4503 if (dlpi_open(linkname
, &dh
, 0) != DLPI_SUCCESS
)
4513 * dhcp-related routines
4517 setifdhcp(const char *caller
, const char *ifname
, int argc
, char *argv
[])
4519 dhcp_ipc_request_t
*request
;
4520 dhcp_ipc_reply_t
*reply
= NULL
;
4521 int timeout
= DHCP_IPC_WAIT_DEFAULT
;
4522 dhcp_ipc_type_t type
= DHCP_START
;
4524 boolean_t is_primary
= _B_FALSE
;
4525 boolean_t started
= _B_FALSE
;
4527 for (argv
++; --argc
> 0; argv
++) {
4529 if (strcmp(*argv
, "primary") == 0) {
4530 is_primary
= _B_TRUE
;
4534 if (strcmp(*argv
, "wait") == 0) {
4537 return (DHCP_EXIT_BADARGS
);
4541 if (strcmp(*argv
, "forever") == 0) {
4542 timeout
= DHCP_IPC_WAIT_FOREVER
;
4546 if (sscanf(*argv
, "%d", &timeout
) != 1) {
4548 return (DHCP_EXIT_BADARGS
);
4553 return (DHCP_EXIT_BADARGS
);
4558 type
= dhcp_string_to_request(*argv
);
4561 return (DHCP_EXIT_BADARGS
);
4566 * Only try to start agent on start or inform; in all other cases it
4567 * has to already be running for anything to make sense.
4569 if (type
== DHCP_START
|| type
== DHCP_INFORM
) {
4570 if (dhcp_start_agent(DHCP_IPC_MAX_WAIT
) == -1) {
4571 (void) fprintf(stderr
, "%s: unable to start %s\n",
4572 caller
, DHCP_AGENT_PATH
);
4573 return (DHCP_EXIT_FAILURE
);
4579 type
|= DHCP_PRIMARY
;
4584 request
= dhcp_ipc_alloc_request(type
, ifname
, NULL
, 0, DHCP_TYPE_NONE
);
4585 if (request
== NULL
) {
4586 (void) fprintf(stderr
, "%s: out of memory\n", caller
);
4587 return (DHCP_EXIT_SYSTEM
);
4590 error
= dhcp_ipc_make_request(request
, &reply
, timeout
);
4594 * Re-map connect error to not under control if we didn't try a
4595 * start operation, as this has to be true and results in a
4596 * clearer message, not to mention preserving compatibility
4597 * with the days when we always started dhcpagent for every
4600 if (error
== DHCP_IPC_E_CONNECT
&& !started
)
4601 error
= DHCP_IPC_E_UNKIF
;
4602 (void) fprintf(stderr
, "%s: %s: %s\n", caller
, ifname
,
4603 dhcp_ipc_strerror(error
));
4604 return (DHCP_EXIT_FAILURE
);
4607 error
= reply
->return_code
;
4612 if (error
== DHCP_IPC_E_TIMEOUT
&& timeout
== 0)
4613 return (DHCP_EXIT_SUCCESS
);
4615 (void) fprintf(stderr
, "%s: %s: %s\n", caller
, ifname
,
4616 dhcp_ipc_strerror(error
));
4618 if (error
== DHCP_IPC_E_TIMEOUT
)
4619 return (DHCP_EXIT_TIMEOUT
);
4621 return (DHCP_EXIT_IF_FAILURE
);
4624 if (DHCP_IPC_CMD(type
) == DHCP_STATUS
) {
4625 (void) printf("%s", dhcp_status_hdr_string());
4626 (void) printf("%s", dhcp_status_reply_to_string(reply
));
4631 return (DHCP_EXIT_SUCCESS
);
4637 (void) fprintf(stderr
,
4638 "usage: ifconfig <interface> | -a[ 4 | 6 | D ][ u | d ][ Z ]\n");
4640 (void) fprintf(stderr
, "%s",
4641 "\t[ <addr_family> ]\n"
4642 "\t[ <address>[/<prefix_length>] [ <dest_address> ] ]\n"
4643 "\t[ set [ <address>][/<prefix_length>] ]"
4644 " [ <address>/<prefix_length>] ]\n"
4645 "\t[ destination <dest_address> ]\n"
4646 "\t[ addif <address>[/<prefix_length>]"
4647 " [ <dest_address> ] ]\n"
4648 "\t[ removeif <address>[/<prefix_length>] ]\n"
4649 "\t[ arp | -arp ]\n"
4650 "\t[ auto-revarp ]\n"
4651 "\t[ broadcast <broad_addr> ]\n"
4652 "\t[ index <if_index> ]\n"
4653 "\t[ metric <n> ] [ mtu <n> ]\n"
4654 "\t[ netmask <mask> ]\n"
4655 "\t[ plumb ] [ unplumb ]\n"
4656 "\t[ preferred | -preferred ]\n"
4657 "\t[ private | -private ]\n"
4658 "\t[ local | -local ]\n"
4659 "\t[ router | -router ]\n"
4660 "\t[ subnet <subnet_address>]\n"
4661 "\t[ trailers | -trailers ]\n"
4662 "\t[ token <address>/<prefix_length> ]\n"
4663 "\t[ tsrc <tunnel_src_address> ]\n"
4664 "\t[ tdst <tunnel_dest_address> ]\n"
4665 "\t[ auth_algs <tunnel_AH_authentication_algorithm> ]\n"
4666 "\t[ encr_algs <tunnel_ESP_encryption_algorithm> ]\n"
4667 "\t[ encr_auth_algs <tunnel_ESP_authentication_algorithm> ]\n"
4668 "\t[ up ] [ down ]\n"
4669 "\t[ xmit | -xmit ]\n"
4671 "\t[ modinsert <module_name@position> ]\n"
4672 "\t[ modremove <module_name@position> ]\n"
4673 "\t[ group <groupname>] | [ group \"\"]\n"
4674 "\t[ deprecated | -deprecated ]\n"
4675 "\t[ standby | -standby ]\n"
4676 "\t[ failover | -failover ]\n"
4677 "\t[ zone <zonename> | -zone ]\n"
4678 "\t[ usesrc <interface> ]\n"
4679 "\t[ all-zones ]\n");
4681 (void) fprintf(stderr
, "or\n");
4682 (void) fprintf(stderr
,
4683 "\tifconfig <interface> | -a[ 4 | 6 | D ] [ u | d ]\n");
4685 (void) fprintf(stderr
, "%s", "\tauto-dhcp | dhcp\n"
4686 "\t[ wait <time> | forever ]\n\t[ primary ]\n"
4687 "\tstart | drop | ping | release | status | inform\n");