Home | History | Annotate | Download | only in ifconfig
      1      0     stevel /*
      2   8485      Peter  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
      3      0     stevel  * Use is subject to license terms.
      4      0     stevel  */
      5      0     stevel /*
      6      0     stevel  * Copyright (c) 1983 Regents of the University of California.
      7      0     stevel  * All rights reserved.  The Berkeley software License Agreement
      8      0     stevel  * specifies the terms and conditions for redistribution.
      9      0     stevel  */
     10      0     stevel 
     11      0     stevel #include "defs.h"
     12      0     stevel #include "strings.h"
     13      0     stevel #include "ifconfig.h"
     14      0     stevel #include <compat.h>
     15      0     stevel #include <libdlpi.h>
     16   8275       Eric #include <libdllink.h>
     17  10616  Sebastien #include <libdliptun.h>
     18  10616  Sebastien #include <libdllink.h>
     19    741   masputra #include <inet/ip.h>
     20   6524    pwernau #include <inet/ipsec_impl.h>
     21    741   masputra 
     22      0     stevel #define	LOOPBACK_IF	"lo0"
     23      0     stevel #define	NONE_STR	"none"
     24      0     stevel #define	ARP_MOD_NAME	"arp"
     25   8485      Peter #define	IPMPSTUB	(void *)-1
     26      0     stevel 
     27      0     stevel typedef struct if_flags {
     28      0     stevel 	uint64_t iff_value;
     29      0     stevel 	char	*iff_name;
     30      0     stevel } if_flags_t;
     31      0     stevel 
     32      0     stevel static if_flags_t	if_flags_tbl[] = {
     33      0     stevel 	{ IFF_UP,		"UP" },
     34      0     stevel 	{ IFF_BROADCAST,	"BROADCAST" },
     35      0     stevel 	{ IFF_DEBUG,		"DEBUG" },
     36      0     stevel 	{ IFF_LOOPBACK,		"LOOPBACK" },
     37      0     stevel 	{ IFF_POINTOPOINT,	"POINTOPOINT" },
     38      0     stevel 	{ IFF_NOTRAILERS,	"NOTRAILERS" },
     39      0     stevel 	{ IFF_RUNNING,		"RUNNING" },
     40      0     stevel 	{ IFF_NOARP,		"NOARP" },
     41      0     stevel 	{ IFF_PROMISC,		"PROMISC" },
     42      0     stevel 	{ IFF_ALLMULTI,		"ALLMULTI" },
     43      0     stevel 	{ IFF_INTELLIGENT,	"INTELLIGENT" },
     44      0     stevel 	{ IFF_MULTICAST,	"MULTICAST" },
     45      0     stevel 	{ IFF_MULTI_BCAST,	"MULTI_BCAST" },
     46      0     stevel 	{ IFF_UNNUMBERED,	"UNNUMBERED" },
     47      0     stevel 	{ IFF_DHCPRUNNING,	"DHCP" },
     48      0     stevel 	{ IFF_PRIVATE,		"PRIVATE" },
     49      0     stevel 	{ IFF_NOXMIT,		"NOXMIT" },
     50      0     stevel 	{ IFF_NOLOCAL,		"NOLOCAL" },
     51      0     stevel 	{ IFF_DEPRECATED,	"DEPRECATED" },
     52      0     stevel 	{ IFF_ADDRCONF,		"ADDRCONF" },
     53      0     stevel 	{ IFF_ROUTER,		"ROUTER" },
     54      0     stevel 	{ IFF_NONUD,		"NONUD" },
     55      0     stevel 	{ IFF_ANYCAST,		"ANYCAST" },
     56      0     stevel 	{ IFF_NORTEXCH,		"NORTEXCH" },
     57      0     stevel 	{ IFF_IPV4,		"IPv4" },
     58      0     stevel 	{ IFF_IPV6,		"IPv6" },
     59      0     stevel 	{ IFF_NOFAILOVER,	"NOFAILOVER" },
     60      0     stevel 	{ IFF_FAILED,		"FAILED" },
     61      0     stevel 	{ IFF_STANDBY,		"STANDBY" },
     62      0     stevel 	{ IFF_INACTIVE,		"INACTIVE" },
     63      0     stevel 	{ IFF_OFFLINE,		"OFFLINE" },
     64      0     stevel 	{ IFF_XRESOLV,		"XRESOLV" },
     65      0     stevel 	{ IFF_COS_ENABLED,	"CoS" },
     66      0     stevel 	{ IFF_PREFERRED,	"PREFERRED" },
     67      0     stevel 	{ IFF_TEMPORARY,	"TEMPORARY" },
     68      0     stevel 	{ IFF_FIXEDMTU,		"FIXEDMTU" },
     69   2546   carlsonj 	{ IFF_VIRTUAL,		"VIRTUAL" },
     70   8485      Peter 	{ IFF_DUPLICATE,	"DUPLICATE" },
     71  11076      Cathy 	{ IFF_IPMP,		"IPMP"},
     72  11076      Cathy 	{ IFF_VRRP,		"VRRP"},
     73  11076      Cathy 	{ IFF_NOACCEPT,		"NOACCEPT"}
     74   8485      Peter };
     75   8485      Peter 
     76   8485      Peter typedef struct {
     77   8485      Peter 	const char		*ia_app;
     78   8485      Peter 	uint64_t		ia_flag;
     79   8485      Peter 	uint_t			ia_tries;
     80   8485      Peter } if_appflags_t;
     81   8485      Peter 
     82   8485      Peter static const if_appflags_t if_appflags_tbl[] = {
     83   8485      Peter 	{ "dhcpagent(1M)",	IFF_DHCPRUNNING,	1 },
     84   8485      Peter 	{ "in.ndpd(1M)",	IFF_ADDRCONF,		3 },
     85   8485      Peter 	{  NULL,		0,			0 }
     86      0     stevel };
     87      0     stevel 
     88  10616  Sebastien static dladm_handle_t	dlh;
     89  10616  Sebastien boolean_t		dlh_opened;
     90  10616  Sebastien static struct		lifreq lifr;
     91   2346       meem /* current interface name a particular function is accessing */
     92  10616  Sebastien static char		name[LIFNAMSIZ];
     93      0     stevel /* foreach interface saved name */
     94  10616  Sebastien static char		origname[LIFNAMSIZ];
     95  10616  Sebastien static int		setaddr;
     96  10616  Sebastien static boolean_t	ipsec_policy_set;
     97  10616  Sebastien static boolean_t	ipsec_auth_covered;
     98      0     stevel 
     99      0     stevel /*
    100      0     stevel  * Make sure the algorithm variables hold more than the sizeof an algorithm
    101      0     stevel  * in PF_KEY.  (For now, more than a uint8_t.)  The NO_***_?ALG indicates that
    102      0     stevel  * there was no algorithm requested, and in the ipsec_req that service should
    103      0     stevel  * be disabled.  (E.g. if ah_aalg remains NO_AH_AALG, then AH will be
    104      0     stevel  * disabled on that tunnel.)
    105      0     stevel  */
    106      0     stevel #define	NO_AH_AALG 256
    107      0     stevel #define	NO_ESP_AALG 256
    108      0     stevel #define	NO_ESP_EALG 256
    109      0     stevel 
    110   8485      Peter int	s, s4, s6;
    111      0     stevel int	af = AF_INET;	/* default address family */
    112      0     stevel int	debug = 0;
    113      0     stevel int	all = 0;	/* setifdhcp() needs to know this */
    114      0     stevel int	verbose = 0;
    115      0     stevel int	v4compat = 0;	/* Compatible printing format */
    116      0     stevel 
    117      0     stevel /*
    118      0     stevel  * Function prototypes for command functions.
    119      0     stevel  */
    120      0     stevel static int	addif(char *arg, int64_t param);
    121   8485      Peter static int	inetipmp(char *arg, int64_t param);
    122      0     stevel static int	inetplumb(char *arg, int64_t param);
    123      0     stevel static int	inetunplumb(char *arg, int64_t param);
    124      0     stevel static int	removeif(char *arg, int64_t param);
    125      0     stevel static int	setdebugflag(char *arg, int64_t param);
    126      0     stevel static int	setifaddr(char *arg, int64_t param);
    127      0     stevel static int	setifbroadaddr(char *arg, int64_t param);
    128      0     stevel static int	setifdstaddr(char *arg, int64_t param);
    129      0     stevel static int	setifether(char *arg, int64_t param);
    130      0     stevel static int	setifflags(char *arg, int64_t param);
    131      0     stevel static int	setifindex(char *arg, int64_t param);
    132      0     stevel static int	setifmetric(char *arg, int64_t param);
    133      0     stevel static int	setifmtu(char *arg, int64_t param);
    134      0     stevel static int	setifnetmask(char *arg, int64_t param);
    135      0     stevel static int	setifprefixlen(char *arg, int64_t param);
    136      0     stevel static int	setifrevarp(char *arg, int64_t param);
    137      0     stevel static int	setifsubnet(char *arg, int64_t param);
    138      0     stevel static int	setiftdst(char *arg, int64_t param);
    139      0     stevel static int	setiftoken(char *arg, int64_t param);
    140      0     stevel static int	setiftsrc(char *arg, int64_t param);
    141      0     stevel static int	setverboseflag(char *arg, int64_t param);
    142      0     stevel static int	set_tun_ah_alg(char *arg, int64_t param);
    143      0     stevel static int	set_tun_esp_auth_alg(char *arg, int64_t param);
    144      0     stevel static int	set_tun_esp_encr_alg(char *arg, int64_t param);
    145      0     stevel static int	modlist(char *arg, int64_t param);
    146      0     stevel static int	modinsert(char *arg, int64_t param);
    147      0     stevel static int	modremove(char *arg, int64_t param);
    148      0     stevel static int	setifgroupname(char *arg, int64_t param);
    149      0     stevel static int	configinfo(char *arg, int64_t param);
    150   8485      Peter static void	print_config_flags(int af, uint64_t flags);
    151      0     stevel static void	print_flags(uint64_t flags);
    152      0     stevel static void	print_ifether(char *ifname);
    153      0     stevel static int	set_tun_encap_limit(char *arg, int64_t param);
    154      0     stevel static int	clr_tun_encap_limit(char *arg, int64_t param);
    155      0     stevel static int	set_tun_hop_limit(char *arg, int64_t param);
    156      0     stevel static int	setzone(char *arg, int64_t param);
    157   1676        jpk static int	setallzones(char *arg, int64_t param);
    158      0     stevel static int	setifsrc(char *arg, int64_t param);
    159   8485      Peter static int	lifnum(const char *ifname);
    160      0     stevel 
    161      0     stevel /*
    162      0     stevel  * Address family specific function prototypes.
    163      0     stevel  */
    164      0     stevel static void	in_getaddr(char *s, struct sockaddr *saddr, int *plenp);
    165      0     stevel static void	in_status(int force, uint64_t flags);
    166      0     stevel static void	in_configinfo(int force, uint64_t flags);
    167      0     stevel static void	in6_getaddr(char *s, struct sockaddr *saddr, int *plenp);
    168      0     stevel static void	in6_status(int force, uint64_t flags);
    169      0     stevel static void	in6_configinfo(int force, uint64_t flags);
    170      0     stevel 
    171      0     stevel /*
    172      0     stevel  * Misc support functions
    173      0     stevel  */
    174   5895   yz147064 static boolean_t	ni_entry(const char *, void *);
    175      0     stevel static void	foreachinterface(void (*func)(), int argc, char *argv[],
    176      0     stevel 		    int af, int64_t onflags, int64_t offflags,
    177      0     stevel 		    int64_t lifc_flags);
    178      0     stevel static void	ifconfig(int argc, char *argv[], int af, struct lifreq *lifrp);
    179    198     kcpoon static boolean_t	in_getmask(struct sockaddr_in *saddr,
    180    198     kcpoon 			    boolean_t addr_set);
    181      0     stevel static int	in_getprefixlen(char *addr, boolean_t slash, int plen);
    182      0     stevel static boolean_t	in_prefixlentomask(int prefixlen, int maxlen,
    183      0     stevel 			    uchar_t *mask);
    184      0     stevel static void	status(void);
    185      0     stevel static void	ifstatus(const char *);
    186  10616  Sebastien static void	tun_status(datalink_id_t);
    187      0     stevel static void	usage(void);
    188   8485      Peter static int	strioctl(int s, int cmd, void *buf, int buflen);
    189      0     stevel static int	setifdhcp(const char *caller, const char *ifname,
    190      0     stevel 		    int argc, char *argv[]);
    191   5240   nordmark static int	ip_domux2fd(int *, int *, int *, int *, int *);
    192   5240   nordmark static int	ip_plink(int, int, int, int, int);
    193      0     stevel static int	modop(char *arg, char op);
    194  10616  Sebastien static int	find_all_interfaces(struct lifconf *lifcp, char **buf,
    195   3448   dh155122 		    int64_t lifc_flags);
    196   8485      Peter static int	create_ipmp(const char *grname, int af, const char *ifname,
    197   8485      Peter 		    boolean_t implicit);
    198   8485      Peter static int	create_ipmp_peer(int af, const char *ifname);
    199   8485      Peter static void	start_ipmp_daemon(void);
    200   8485      Peter static boolean_t ifaddr_up(ifaddrlistx_t *ifaddrp);
    201   8485      Peter static boolean_t ifaddr_down(ifaddrlistx_t *ifaddrp);
    202  10616  Sebastien static dladm_status_t	ifconfig_dladm_open(const char *, datalink_class_t,
    203  10616  Sebastien 		    datalink_id_t *);
    204  10616  Sebastien static void	dladmerr_exit(dladm_status_t status, const char *str);
    205      0     stevel 
    206      0     stevel #define	max(a, b)	((a) < (b) ? (b) : (a))
    207      0     stevel 
    208      0     stevel /*
    209      0     stevel  * DHCP_EXIT_IF_FAILURE indicates that the operation failed, but if there
    210      0     stevel  * are more interfaces to act on (i.e., ifconfig was invoked with -a), keep
    211      0     stevel  * on going rather than exit with an error.
    212      0     stevel  */
    213      0     stevel 
    214      0     stevel #define	DHCP_EXIT_IF_FAILURE	-1
    215      0     stevel 
    216      0     stevel #define	NEXTARG		0xffffff	/* command takes an argument */
    217      0     stevel #define	OPTARG		0xfffffe 	/* command takes an optional argument */
    218      0     stevel #define	AF_ANY		(-1)
    219      0     stevel 
    220      0     stevel /* Refer to the comments in ifconfig() on the netmask "hack" */
    221      0     stevel #define	NETMASK_CMD	"netmask"
    222      0     stevel struct sockaddr_storage	g_netmask;
    223    198     kcpoon enum { G_NETMASK_NIL, G_NETMASK_PENDING, G_NETMASK_SET }
    224    198     kcpoon     g_netmask_set = G_NETMASK_NIL;
    225      0     stevel 
    226      0     stevel struct	cmd {
    227      0     stevel 	char		*c_name;
    228      0     stevel 	int64_t		c_parameter;	/* NEXTARG means next argv */
    229      0     stevel 	int		(*c_func)(char *, int64_t);
    230      0     stevel 	int		c_abortonfail;	/* don't continue parsing args */
    231      0     stevel 					/* for the current interface */
    232      0     stevel 	int	c_af;			/* address family restrictions */
    233      0     stevel } cmds[] = {
    234      0     stevel 	{ "up",		IFF_UP,		setifflags,	0,	AF_ANY },
    235      0     stevel 	{ "down",	-IFF_UP,	setifflags,	0,	AF_ANY },
    236      0     stevel 	{ "trailers",	-IFF_NOTRAILERS, setifflags,	0,	AF_ANY },
    237      0     stevel 	{ "-trailers",	IFF_NOTRAILERS,	setifflags,	0,	AF_ANY },
    238      0     stevel 	{ "arp",	-IFF_NOARP,	setifflags,	0,	AF_INET },
    239      0     stevel 	{ "-arp",	IFF_NOARP,	setifflags,	0,	AF_INET },
    240      0     stevel 	{ "router",	IFF_ROUTER,	setifflags,	0,	AF_ANY },
    241      0     stevel 	{ "-router",	-IFF_ROUTER,	setifflags,	0,	AF_ANY },
    242      0     stevel 	{ "private",	IFF_PRIVATE,	setifflags,	0,	AF_ANY },
    243      0     stevel 	{ "-private",	-IFF_PRIVATE,	setifflags,	0,	AF_ANY },
    244      0     stevel 	{ "xmit",	-IFF_NOXMIT,	setifflags,	0,	AF_ANY },
    245      0     stevel 	{ "-xmit",	IFF_NOXMIT,	setifflags,	0,	AF_ANY },
    246      0     stevel 	{ "-nud",	IFF_NONUD,	setifflags,	0,	AF_INET6 },
    247      0     stevel 	{ "nud",	-IFF_NONUD,	setifflags,	0,	AF_INET6 },
    248      0     stevel 	{ "anycast",	IFF_ANYCAST,	setifflags,	0,	AF_ANY },
    249      0     stevel 	{ "-anycast",	-IFF_ANYCAST,	setifflags,	0,	AF_ANY },
    250      0     stevel 	{ "local",	-IFF_NOLOCAL,	setifflags,	0,	AF_ANY },
    251      0     stevel 	{ "-local",	IFF_NOLOCAL,	setifflags,	0,	AF_ANY },
    252      0     stevel 	{ "deprecated",	IFF_DEPRECATED,	setifflags,	0,	AF_ANY },
    253      0     stevel 	{ "-deprecated", -IFF_DEPRECATED, setifflags,	0,	AF_ANY },
    254      0     stevel 	{ "preferred",	IFF_PREFERRED,	setifflags,	0,	AF_INET6 },
    255      0     stevel 	{ "-preferred",	-IFF_PREFERRED,	setifflags,	0,	AF_INET6 },
    256      0     stevel 	{ "debug",	0,		setdebugflag,	0,	AF_ANY },
    257      0     stevel 	{ "verbose",	0,		setverboseflag,	0,	AF_ANY },
    258      0     stevel 	{ NETMASK_CMD,	NEXTARG,	setifnetmask,	0,	AF_INET },
    259      0     stevel 	{ "metric",	NEXTARG,	setifmetric,	0,	AF_ANY },
    260      0     stevel 	{ "mtu",	NEXTARG,	setifmtu,	0,	AF_ANY },
    261      0     stevel 	{ "index",	NEXTARG,	setifindex,	0,	AF_ANY },
    262      0     stevel 	{ "broadcast",	NEXTARG,	setifbroadaddr,	0,	AF_INET },
    263      0     stevel 	{ "auto-revarp", 0,		setifrevarp,	1,	AF_INET },
    264   8485      Peter 	{ "ipmp",	0,		inetipmp,	1,	AF_ANY },
    265      0     stevel 	{ "plumb",	0,		inetplumb,	1,	AF_ANY },
    266      0     stevel 	{ "unplumb",	0,		inetunplumb,	0,	AF_ANY },
    267      0     stevel 	{ "subnet",	NEXTARG,	setifsubnet,	0,	AF_ANY },
    268      0     stevel 	{ "token",	NEXTARG,	setiftoken,	0,	AF_INET6 },
    269      0     stevel 	{ "tsrc",	NEXTARG,	setiftsrc,	0,	AF_ANY },
    270      0     stevel 	{ "tdst",	NEXTARG,	setiftdst,	0,	AF_ANY },
    271      0     stevel 	{ "encr_auth_algs", NEXTARG,	set_tun_esp_auth_alg, 0, AF_ANY },
    272      0     stevel 	{ "encr_algs",	NEXTARG,	set_tun_esp_encr_alg, 0, AF_ANY },
    273      0     stevel 	{ "auth_algs",	NEXTARG,	set_tun_ah_alg,	0,	AF_ANY },
    274      0     stevel 	{ "addif",	NEXTARG,	addif,		1,	AF_ANY },
    275      0     stevel 	{ "removeif",	NEXTARG,	removeif,	1,	AF_ANY },
    276      0     stevel 	{ "modlist",	0,		modlist,	1,	AF_ANY },
    277      0     stevel 	{ "modinsert",	NEXTARG,	modinsert,	1,	AF_ANY },
    278      0     stevel 	{ "modremove",	NEXTARG,	modremove,	1,	AF_ANY },
    279      0     stevel 	{ "failover",	-IFF_NOFAILOVER, setifflags,	1,	AF_ANY },
    280      0     stevel 	{ "-failover",	IFF_NOFAILOVER, setifflags,	1,	AF_ANY },
    281      0     stevel 	{ "standby",	IFF_STANDBY,	setifflags,	1,	AF_ANY },
    282      0     stevel 	{ "-standby",	-IFF_STANDBY,	setifflags,	1,	AF_ANY },
    283      0     stevel 	{ "failed",	IFF_FAILED,	setifflags,	1,	AF_ANY },
    284      0     stevel 	{ "-failed",	-IFF_FAILED,	setifflags,	1,	AF_ANY },
    285      0     stevel 	{ "group",	NEXTARG,	setifgroupname,	1,	AF_ANY },
    286      0     stevel 	{ "configinfo",	0,		configinfo,	1,	AF_ANY },
    287   2346       meem 	{ "encaplimit",	NEXTARG,	set_tun_encap_limit,	0, AF_ANY },
    288   2346       meem 	{ "-encaplimit", 0,		clr_tun_encap_limit,	0, AF_ANY },
    289   2346       meem 	{ "thoplimit",	NEXTARG,	set_tun_hop_limit,	0, AF_ANY },
    290      0     stevel 	{ "set",	NEXTARG,	setifaddr,	0,	AF_ANY },
    291      0     stevel 	{ "destination", NEXTARG,	setifdstaddr,	0,	AF_ANY },
    292      0     stevel 	{ "zone",	NEXTARG,	setzone,	0,	AF_ANY },
    293      0     stevel 	{ "-zone",	0,		setzone,	0,	AF_ANY },
    294   1676        jpk 	{ "all-zones",	0,		setallzones,	0,	AF_ANY },
    295      0     stevel 	{ "ether",	OPTARG,		setifether,	0,	AF_ANY },
    296      0     stevel 	{ "usesrc",	NEXTARG,	setifsrc,	0,	AF_ANY },
    297   5978       meem 
    298   5978       meem 	/*
    299   5978       meem 	 * NOTE: any additions to this table must also be applied to ifparse
    300   5978       meem 	 *	(usr/src/cmd/cmd-inet/sbin/ifparse/ifparse.c)
    301   5978       meem 	 */
    302   5978       meem 
    303      0     stevel 	{ 0,		0,		setifaddr,	0,	AF_ANY },
    304      0     stevel 	{ 0,		0,		setifdstaddr,	0,	AF_ANY },
    305      0     stevel 	{ 0,		0,		0,		0,	0 },
    306      0     stevel };
    307      0     stevel 
    308      0     stevel 
    309      0     stevel typedef struct if_config_cmd {
    310      0     stevel 	uint64_t	iff_flag;
    311   8485      Peter 	int		iff_af;
    312      0     stevel 	char		*iff_name;
    313      0     stevel } if_config_cmd_t;
    314      0     stevel 
    315   8485      Peter /*
    316   8485      Peter  * NOTE: print_config_flags() processes this table in order, so we put "up"
    317   8485      Peter  * last so that we can be sure "-failover" will take effect first.  Otherwise,
    318   8485      Peter  * IPMP test addresses will erroneously migrate to the IPMP interface.
    319   8485      Peter  */
    320      0     stevel static if_config_cmd_t	if_config_cmd_tbl[] = {
    321   8485      Peter 	{ IFF_NOTRAILERS,	AF_UNSPEC,	"-trailers"	},
    322   8485      Peter 	{ IFF_PRIVATE,		AF_UNSPEC,	"private"	},
    323   8485      Peter 	{ IFF_NOXMIT,		AF_UNSPEC,	"-xmit"		},
    324   8485      Peter 	{ IFF_ANYCAST,		AF_INET6,	"anycast"	},
    325   8485      Peter 	{ IFF_NOLOCAL,		AF_UNSPEC,	"-local"	},
    326   8485      Peter 	{ IFF_DEPRECATED,	AF_UNSPEC,	"deprecated"	},
    327   8485      Peter 	{ IFF_NOFAILOVER,	AF_UNSPEC,	"-failover"	},
    328   8485      Peter 	{ IFF_STANDBY,		AF_UNSPEC,	"standby"	},
    329   8485      Peter 	{ IFF_FAILED,		AF_UNSPEC,	"failed"	},
    330   8485      Peter 	{ IFF_PREFERRED,	AF_UNSPEC,	"preferred"	},
    331   8485      Peter 	{ IFF_NONUD,		AF_INET6,	"-nud"		},
    332   8485      Peter 	{ IFF_NOARP,		AF_INET,	"-arp"		},
    333   8485      Peter 	{ IFF_UP,		AF_UNSPEC, 	"up" 		},
    334   8485      Peter 	{ 0,			0,		NULL		},
    335      0     stevel };
    336      0     stevel 
    337      0     stevel typedef struct ni {
    338      0     stevel 	char		ni_name[LIFNAMSIZ];
    339      0     stevel 	struct ni	*ni_next;
    340      0     stevel } ni_t;
    341      0     stevel 
    342      0     stevel static ni_t	*ni_list = NULL;
    343      0     stevel static int	num_ni = 0;
    344      0     stevel 
    345      0     stevel /* End defines and structure definitions for ifconfig -a plumb */
    346      0     stevel 
    347      0     stevel /* Known address families */
    348      0     stevel struct afswtch {
    349      0     stevel 	char *af_name;
    350      0     stevel 	short af_af;
    351      0     stevel 	void (*af_status)();
    352      0     stevel 	void (*af_getaddr)();
    353      0     stevel 	void (*af_configinfo)();
    354      0     stevel } afs[] = {
    355      0     stevel 	{ "inet", AF_INET, in_status, in_getaddr, in_configinfo },
    356      0     stevel 	{ "inet6", AF_INET6, in6_status, in6_getaddr, in6_configinfo },
    357      0     stevel 	{ 0, 0,	0, 0, 0 }
    358      0     stevel };
    359      0     stevel 
    360      0     stevel #define	SOCKET_AF(af)	(((af) == AF_UNSPEC) ? AF_INET : (af))
    361      0     stevel 
    362      0     stevel struct afswtch *afp;	/* the address family being set or asked about */
    363      0     stevel 
    364      0     stevel int
    365      0     stevel main(int argc, char *argv[])
    366      0     stevel {
    367  10616  Sebastien 	int64_t		lifc_flags;
    368  10616  Sebastien 	char		*default_ip_str;
    369   8485      Peter 
    370   8485      Peter 	lifc_flags = LIFC_NOXMIT|LIFC_TEMPORARY|LIFC_ALLZONES|LIFC_UNDER_IPMP;
    371      0     stevel 
    372      0     stevel 	if (argc < 2) {
    373      0     stevel 		usage();
    374      0     stevel 		exit(1);
    375      0     stevel 	}
    376      0     stevel 	argc--, argv++;
    377      0     stevel 	if (strlen(*argv) > sizeof (name) - 1) {
    378      0     stevel 		(void) fprintf(stderr, "%s: interface name too long\n", *argv);
    379      0     stevel 		exit(1);
    380      0     stevel 	}
    381      0     stevel 	(void) strncpy(name, *argv, sizeof (name));
    382      0     stevel 	name[sizeof (name) - 1] = '\0';
    383      0     stevel 	(void) strncpy(origname, name, sizeof (origname));	/* For addif */
    384      0     stevel 	default_ip_str = NULL;
    385      0     stevel 	v4compat = get_compat_flag(&default_ip_str);
    386      0     stevel 	if (v4compat == DEFAULT_PROT_BAD_VALUE) {
    387      0     stevel 		(void) fprintf(stderr,
    388      0     stevel 		    "ifconfig: %s: Bad value for %s in %s\n", default_ip_str,
    389      0     stevel 		    DEFAULT_IP, INET_DEFAULT_FILE);
    390      0     stevel 		free(default_ip_str);
    391      0     stevel 		exit(2);
    392      0     stevel 	}
    393      0     stevel 	free(default_ip_str);
    394      0     stevel 	argc--, argv++;
    395      0     stevel 	if (argc > 0) {
    396      0     stevel 		struct afswtch *myafp;
    397      0     stevel 
    398      0     stevel 		for (myafp = afp = afs; myafp->af_name; myafp++) {
    399      0     stevel 			if (strcmp(myafp->af_name, *argv) == 0) {
    400      0     stevel 				afp = myafp; argc--; argv++;
    401      0     stevel 				break;
    402      0     stevel 			}
    403      0     stevel 		}
    404      0     stevel 		af = lifr.lifr_addr.ss_family = afp->af_af;
    405      0     stevel 		if (af == AF_INET6) {
    406      0     stevel 			v4compat = 0;
    407      0     stevel 		}
    408      0     stevel 	}
    409      0     stevel 
    410      0     stevel 	s = socket(SOCKET_AF(af), SOCK_DGRAM, 0);
    411   8485      Peter 	s4 = socket(AF_INET, SOCK_DGRAM, 0);
    412   8485      Peter 	s6 = socket(AF_INET6, SOCK_DGRAM, 0);
    413   8485      Peter 	if (s == -1 || s4 == -1 || s6 == -1)
    414      0     stevel 		Perror0_exit("socket");
    415      0     stevel 
    416      0     stevel 	/*
    417      0     stevel 	 * Special interface names is any combination of these flags.
    418      0     stevel 	 * Note that due to the ifconfig syntax they have to be combined
    419      0     stevel 	 * as a single '-' option.
    420      0     stevel 	 *	-a	All interfaces
    421      0     stevel 	 *	-u	"up" interfaces
    422      0     stevel 	 *	-d	"down" interfaces
    423      0     stevel 	 *	-D	Interfaces not controlled by DHCP
    424      0     stevel 	 *	-4	IPv4 interfaces
    425      0     stevel 	 *	-6	IPv6 interfaces
    426      0     stevel 	 *	-X	Turn on debug (not documented)
    427      0     stevel 	 *	-v	Turn on verbose
    428      0     stevel 	 *	-Z	Only interfaces in caller's zone
    429      0     stevel 	 */
    430      0     stevel 
    431      0     stevel 	if (name[0] == '-') {
    432      0     stevel 		/* One or more options */
    433      0     stevel 		int64_t onflags = 0;
    434      0     stevel 		int64_t offflags = 0;
    435      0     stevel 		int c;
    436      0     stevel 		char *av[2] = { "ifconfig", name };
    437      0     stevel 
    438      0     stevel 		while ((c = getopt(2, av, "audDXZ46v")) != -1) {
    439      0     stevel 			switch ((char)c) {
    440      0     stevel 			case 'a':
    441      0     stevel 				all = 1;
    442      0     stevel 				break;
    443      0     stevel 			case 'u':
    444      0     stevel 				onflags |= IFF_UP;
    445      0     stevel 				break;
    446      0     stevel 			case 'd':
    447      0     stevel 				offflags |= IFF_UP;
    448      0     stevel 				break;
    449      0     stevel 			case 'D':
    450      0     stevel 				offflags |= IFF_DHCPRUNNING;
    451      0     stevel 				break;
    452      0     stevel 			case 'X':
    453      0     stevel 				debug += 3;
    454      0     stevel 				break;
    455      0     stevel 			case 'Z':
    456      0     stevel 				lifc_flags &= ~LIFC_ALLZONES;
    457      0     stevel 				break;
    458      0     stevel 			case '4':
    459      0     stevel 				/*
    460      0     stevel 				 * -4 is not a compatable flag, therefore
    461      0     stevel 				 * we assume they want v4compat turned off
    462      0     stevel 				 */
    463      0     stevel 				v4compat = 0;
    464      0     stevel 				onflags |= IFF_IPV4;
    465      0     stevel 				break;
    466      0     stevel 			case '6':
    467      0     stevel 				/*
    468      0     stevel 				 * If they want IPv6, well then we'll assume
    469      0     stevel 				 * they don't want IPv4 compat
    470      0     stevel 				 */
    471      0     stevel 				v4compat = 0;
    472      0     stevel 				onflags |= IFF_IPV6;
    473      0     stevel 				break;
    474      0     stevel 			case 'v':
    475      0     stevel 				verbose = 1;
    476      0     stevel 				break;
    477      0     stevel 			case '?':
    478      0     stevel 				usage();
    479      0     stevel 				exit(1);
    480      0     stevel 			}
    481      0     stevel 		}
    482      0     stevel 		if (!all) {
    483      0     stevel 			(void) fprintf(stderr,
    484   3628   ss150715 			    "ifconfig: %s: no such interface\n", name);
    485      0     stevel 			exit(1);
    486      0     stevel 		}
    487      0     stevel 		foreachinterface(ifconfig, argc, argv, af, onflags, offflags,
    488      0     stevel 		    lifc_flags);
    489      0     stevel 	} else {
    490      0     stevel 		ifconfig(argc, argv, af, (struct lifreq *)NULL);
    491      0     stevel 	}
    492      0     stevel 	return (0);
    493      0     stevel }
    494      0     stevel 
    495      0     stevel /*
    496      0     stevel  * For each interface, call (*func)(argc, argv, af, lifrp).
    497      0     stevel  * Only call function if onflags and offflags are set or clear, respectively,
    498      0     stevel  * in the interfaces flags field.
    499      0     stevel  */
    500      0     stevel static void
    501      0     stevel foreachinterface(void (*func)(), int argc, char *argv[], int af,
    502      0     stevel     int64_t onflags, int64_t offflags, int64_t lifc_flags)
    503      0     stevel {
    504      0     stevel 	int n;
    505      0     stevel 	char *buf;
    506      0     stevel 	struct lifnum lifn;
    507      0     stevel 	struct lifconf lifc;
    508      0     stevel 	struct lifreq *lifrp;
    509      0     stevel 	struct lifreq lifrl;	/* Local lifreq struct */
    510      0     stevel 	int numifs;
    511      0     stevel 	unsigned bufsize;
    512      0     stevel 	int plumball = 0;
    513      0     stevel 	int save_af = af;
    514      0     stevel 
    515   3448   dh155122 	buf = NULL;
    516      0     stevel 	/*
    517      0     stevel 	 * Special case:
    518  10616  Sebastien 	 * ifconfig -a plumb should find all network interfaces in the current
    519  10616  Sebastien 	 * zone.
    520      0     stevel 	 */
    521      0     stevel 	if (argc > 0 && (strcmp(*argv, "plumb") == 0)) {
    522  10616  Sebastien 		if (find_all_interfaces(&lifc, &buf, lifc_flags) != 0 ||
    523  10616  Sebastien 		    lifc.lifc_len == 0)
    524   3448   dh155122 			return;
    525      0     stevel 		plumball = 1;
    526      0     stevel 	} else {
    527      0     stevel 		lifn.lifn_family = AF_UNSPEC;
    528      0     stevel 		lifn.lifn_flags = lifc_flags;
    529      0     stevel 		if (ioctl(s, SIOCGLIFNUM, (char *)&lifn) < 0) {
    530      0     stevel 			Perror0_exit("Could not determine number"
    531      0     stevel 			    " of interfaces");
    532      0     stevel 		}
    533      0     stevel 		numifs = lifn.lifn_count;
    534      0     stevel 		if (debug)
    535      0     stevel 			(void) printf("ifconfig: %d interfaces\n",  numifs);
    536      0     stevel 
    537      0     stevel 		bufsize = numifs * sizeof (struct lifreq);
    538      0     stevel 		if ((buf = malloc(bufsize)) == NULL) {
    539      0     stevel 			Perror0("out of memory\n");
    540      0     stevel 			(void) close(s);
    541      0     stevel 			return;
    542      0     stevel 		}
    543      0     stevel 
    544      0     stevel 		lifc.lifc_family = AF_UNSPEC;
    545      0     stevel 		lifc.lifc_flags = lifc_flags;
    546      0     stevel 		lifc.lifc_len = bufsize;
    547      0     stevel 		lifc.lifc_buf = buf;
    548      0     stevel 
    549      0     stevel 		if (ioctl(s, SIOCGLIFCONF, (char *)&lifc) < 0) {
    550      0     stevel 			Perror0("SIOCGLIFCONF");
    551      0     stevel 			(void) close(s);
    552      0     stevel 			free(buf);
    553      0     stevel 			return;
    554      0     stevel 		}
    555      0     stevel 	}
    556      0     stevel 
    557      0     stevel 	lifrp = lifc.lifc_req;
    558      0     stevel 	for (n = lifc.lifc_len / sizeof (struct lifreq); n > 0; n--, lifrp++) {
    559      0     stevel 
    560      0     stevel 		if (!plumball) {
    561      0     stevel 			/*
    562      0     stevel 			 * We must close and recreate the socket each time
    563      0     stevel 			 * since we don't know what type of socket it is now
    564      0     stevel 			 * (each status function may change it).
    565      0     stevel 			 */
    566      0     stevel 
    567      0     stevel 			(void) close(s);
    568      0     stevel 
    569      0     stevel 			af = lifrp->lifr_addr.ss_family;
    570      0     stevel 			s = socket(SOCKET_AF(af), SOCK_DGRAM, 0);
    571      0     stevel 			if (s == -1) {
    572      0     stevel 				/*
    573      0     stevel 				 * Perror0() assumes the name to be in the
    574      0     stevel 				 * globally defined lifreq structure.
    575      0     stevel 				 */
    576      0     stevel 				(void) strncpy(lifr.lifr_name,
    577      0     stevel 				    lifrp->lifr_name, sizeof (lifr.lifr_name));
    578      0     stevel 				Perror0_exit("socket");
    579      0     stevel 			}
    580      0     stevel 		}
    581      0     stevel 
    582      0     stevel 		/*
    583      0     stevel 		 * Only service interfaces that match the on and off
    584      0     stevel 		 * flags masks.
    585      0     stevel 		 */
    586      0     stevel 		if (onflags || offflags) {
    587      0     stevel 			(void) memset(&lifrl, 0, sizeof (lifrl));
    588      0     stevel 			(void) strncpy(lifrl.lifr_name, lifrp->lifr_name,
    589   5240   nordmark 			    sizeof (lifrl.lifr_name));
    590      0     stevel 			if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifrl) < 0) {
    591      0     stevel 				/*
    592      0     stevel 				 * Perror0() assumes the name to be in the
    593      0     stevel 				 * globally defined lifreq structure.
    594      0     stevel 				 */
    595      0     stevel 				(void) strncpy(lifr.lifr_name,
    596      0     stevel 				    lifrp->lifr_name, sizeof (lifr.lifr_name));
    597      0     stevel 				Perror0_exit("foreachinterface: SIOCGLIFFLAGS");
    598      0     stevel 			}
    599      0     stevel 			if ((lifrl.lifr_flags & onflags) != onflags)
    600      0     stevel 				continue;
    601      0     stevel 			if ((~lifrl.lifr_flags & offflags) != offflags)
    602      0     stevel 				continue;
    603      0     stevel 		}
    604      0     stevel 
    605      0     stevel 		if (!plumball) {
    606      0     stevel 			(void) strncpy(lifrl.lifr_name, lifrp->lifr_name,
    607      0     stevel 			    sizeof (lifrl.lifr_name));
    608      0     stevel 			if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifrl) < 0) {
    609      0     stevel 				/*
    610      0     stevel 				 * Perror0() assumes the name to be in the
    611      0     stevel 				 * globally defined lifreq structure.
    612      0     stevel 				 */
    613      0     stevel 				(void) strncpy(lifr.lifr_name,
    614      0     stevel 				    lifrp->lifr_name, sizeof (lifr.lifr_name));
    615      0     stevel 				Perror0("foreachinterface: SIOCGLIFADDR");
    616      0     stevel 				continue;
    617      0     stevel 			}
    618      0     stevel 			if (lifrl.lifr_addr.ss_family != af) {
    619      0     stevel 				/* Switch address family */
    620      0     stevel 				af = lifrl.lifr_addr.ss_family;
    621      0     stevel 				(void) close(s);
    622      0     stevel 
    623      0     stevel 				s = socket(SOCKET_AF(af), SOCK_DGRAM, 0);
    624      0     stevel 				if (s == -1) {
    625      0     stevel 					/*
    626      0     stevel 					 * Perror0() assumes the name to be in
    627      0     stevel 					 * the globally defined lifreq
    628      0     stevel 					 * structure.
    629      0     stevel 					 */
    630      0     stevel 					(void) strncpy(lifr.lifr_name,
    631      0     stevel 					    lifrp->lifr_name,
    632      0     stevel 					    sizeof (lifr.lifr_name));
    633      0     stevel 					Perror0_exit("socket");
    634      0     stevel 				}
    635      0     stevel 			}
    636      0     stevel 		}
    637      0     stevel 
    638      0     stevel 		/*
    639      0     stevel 		 * Reset global state
    640      0     stevel 		 * setaddr: Used by parser to tear apart source and dest
    641      0     stevel 		 * name and origname contain the name of the 'current'
    642      0     stevel 		 * interface.
    643      0     stevel 		 */
    644      0     stevel 		setaddr = 0;
    645      0     stevel 		(void) strncpy(name, lifrp->lifr_name, sizeof (name));
    646      0     stevel 		(void) strncpy(origname, name, sizeof (origname));
    647      0     stevel 
    648      0     stevel 		(*func)(argc, argv, save_af, lifrp);
    649      0     stevel 		/* the func could have overwritten origname, so restore */
    650      0     stevel 		(void) strncpy(name, origname, sizeof (name));
    651      0     stevel 	}
    652   3448   dh155122 	if (buf != NULL)
    653   3448   dh155122 		free(buf);
    654      0     stevel }
    655      0     stevel 
    656      0     stevel /*
    657      0     stevel  * for the specified interface call (*func)(argc, argv, af, lifrp).
    658      0     stevel  */
    659      0     stevel 
    660      0     stevel static void
    661      0     stevel ifconfig(int argc, char *argv[], int af, struct lifreq *lifrp)
    662      0     stevel {
    663      0     stevel 	static boolean_t scan_netmask = _B_FALSE;
    664      0     stevel 	int ret;
    665      0     stevel 
    666      0     stevel 	if (argc == 0) {
    667      0     stevel 		status();
    668      0     stevel 		return;
    669      0     stevel 	}
    670      0     stevel 
    671      0     stevel 	if (strcmp(*argv, "auto-dhcp") == 0 || strcmp(*argv, "dhcp") == 0) {
    672   3431   carlsonj 		/*
    673   3431   carlsonj 		 * Some errors are ignored in the case where more than one
    674   3431   carlsonj 		 * interface is being operated on.
    675   3431   carlsonj 		 */
    676   3431   carlsonj 		ret = setifdhcp("ifconfig", name, argc, argv);
    677   3431   carlsonj 		if (ret == DHCP_EXIT_IF_FAILURE) {
    678   3431   carlsonj 			if (!all)
    679   3431   carlsonj 				exit(DHCP_EXIT_FAILURE);
    680   3431   carlsonj 		} else if (ret != DHCP_EXIT_SUCCESS) {
    681   3431   carlsonj 			exit(ret);
    682   3431   carlsonj 		}
    683      0     stevel 		return;
    684      0     stevel 	}
    685      0     stevel 
    686      0     stevel 	/*
    687      0     stevel 	 * The following is a "hack" to get around the existing interface
    688      0     stevel 	 * setting mechanism.  Currently, each interface attribute,
    689      0     stevel 	 * such as address, netmask, broadcast, ... is set separately.  But
    690      0     stevel 	 * sometimes two or more attributes must be set together.  For
    691      0     stevel 	 * example, setting an address without a netmask does not make sense.
    692      0     stevel 	 * Yet they can be set separately for IPv4 address using the current
    693      0     stevel 	 * ifconfig(1M) syntax.  The kernel then "infers" the correct netmask
    694      0     stevel 	 * using the deprecated "IP address classes."  This is simply not
    695      0     stevel 	 * correct.
    696      0     stevel 	 *
    697      0     stevel 	 * The "hack" below is to go thru the whole command list looking for
    698      0     stevel 	 * the netmask command first.  Then use this netmask to set the
    699      0     stevel 	 * address.  This does not provide an extensible way to accommodate
    700      0     stevel 	 * future need for setting more than one attributes together.
    701      0     stevel 	 *
    702    198     kcpoon 	 * Note that if the "netmask" command argument is a "+", we need
    703    198     kcpoon 	 * to save this info and do the query after we know the address to
    704    198     kcpoon 	 * be set.  The reason is that if "addif" is used, the working
    705    198     kcpoon 	 * interface name will be changed later when the logical interface
    706    198     kcpoon 	 * is created.  In in_getmask(), if an address is not provided,
    707    198     kcpoon 	 * it will use the working interface's address to do the query.
    708    198     kcpoon 	 * It will be wrong now as we don't know the logical interface's name.
    709    198     kcpoon 	 *
    710      0     stevel 	 * ifconfig(1M) is too overloaded and the code is so convoluted
    711      0     stevel 	 * that it is "safer" not to re-architect the code to fix the above
    712      0     stevel 	 * issue, hence this "hack."  We may be better off to have a new
    713      0     stevel 	 * command with better syntax for configuring network interface
    714      0     stevel 	 * parameters...
    715      0     stevel 	 */
    716      0     stevel 	if (!scan_netmask && afp->af_af == AF_INET) {
    717      0     stevel 		int	largc;
    718      0     stevel 		char	**largv;
    719      0     stevel 
    720      0     stevel 		/* Only go thru the command list once to find the netmask. */
    721      0     stevel 		scan_netmask = _B_TRUE;
    722      0     stevel 
    723      0     stevel 		/*
    724      0     stevel 		 * Currently, if multiple netmask commands are specified, the
    725      0     stevel 		 * last one will be used as the final netmask.  So we need
    726      0     stevel 		 * to scan the whole list to preserve this behavior.
    727      0     stevel 		 */
    728      0     stevel 		for (largc = argc, largv = argv; largc > 0; largc--, largv++) {
    729      0     stevel 			if (strcmp(*largv, NETMASK_CMD) == 0) {
    730      0     stevel 				if (--largc == 0)
    731      0     stevel 					break;
    732      0     stevel 				largv++;
    733      0     stevel 				if (strcmp(*largv, "+") == 0) {
    734    198     kcpoon 					g_netmask_set = G_NETMASK_PENDING;
    735      0     stevel 				} else {
    736      0     stevel 					in_getaddr(*largv, (struct sockaddr *)
    737      0     stevel 					    &g_netmask, NULL);
    738    198     kcpoon 					g_netmask_set = G_NETMASK_SET;
    739      0     stevel 				}
    740      0     stevel 				/* Continue the scan. */
    741      0     stevel 			}
    742      0     stevel 		}
    743      0     stevel 	}
    744      0     stevel 
    745      0     stevel 	while (argc > 0) {
    746      0     stevel 		struct cmd *p;
    747      0     stevel 		boolean_t found_cmd;
    748      0     stevel 
    749      0     stevel 		if (debug)
    750      0     stevel 			(void) printf("ifconfig: argv %s\n", *argv);
    751      0     stevel 
    752      0     stevel 		found_cmd = _B_FALSE;
    753      0     stevel 		for (p = cmds; p->c_func; p++) {
    754      0     stevel 			if (p->c_name) {
    755      0     stevel 				if (strcmp(*argv, p->c_name) == 0) {
    756      0     stevel 					/*
    757      0     stevel 					 * indicate that the command was
    758      0     stevel 					 * found and check to see if
    759      0     stevel 					 * the address family is valid
    760      0     stevel 					 */
    761      0     stevel 					found_cmd = _B_TRUE;
    762      0     stevel 					if (p->c_af == AF_ANY ||
    763      0     stevel 					    af == p->c_af)
    764      0     stevel 						break;
    765      0     stevel 				}
    766      0     stevel 			} else {
    767      0     stevel 				if (p->c_af == AF_ANY ||
    768      0     stevel 				    af == p->c_af)
    769      0     stevel 					break;
    770      0     stevel 			}
    771      0     stevel 		}
    772      0     stevel 		/*
    773      0     stevel 		 * If we found the keyword, but the address family
    774      0     stevel 		 * did not match spit out an error
    775      0     stevel 		 */
    776      0     stevel 		if (found_cmd && p->c_name == 0) {
    777      0     stevel 			(void) fprintf(stderr, "ifconfig: Operation %s not"
    778      0     stevel 			    " supported for %s\n", *argv, afp->af_name);
    779      0     stevel 			exit(1);
    780      0     stevel 		}
    781      0     stevel 		/*
    782      0     stevel 		 * else (no keyword found), we assume it's an address
    783      0     stevel 		 * of some sort
    784      0     stevel 		 */
    785      0     stevel 		if (p->c_name == 0 && setaddr)
    786      0     stevel 			p++;	/* got src, do dst */
    787      0     stevel 		if (p->c_func) {
    788      0     stevel 			if (p->c_af == AF_INET6) {
    789      0     stevel 				v4compat = 0;
    790      0     stevel 			}
    791      0     stevel 			if (p->c_parameter == NEXTARG ||
    792      0     stevel 			    p->c_parameter == OPTARG) {
    793      0     stevel 				argc--, argv++;
    794      0     stevel 				if (argc == 0 && p->c_parameter == NEXTARG) {
    795      0     stevel 					(void) fprintf(stderr,
    796      0     stevel 					    "ifconfig: no argument for %s\n",
    797      0     stevel 					    p->c_name);
    798      0     stevel 					exit(1);
    799      0     stevel 				}
    800      0     stevel 			}
    801      0     stevel 			/*
    802      0     stevel 			 *	Call the function if:
    803      0     stevel 			 *
    804      0     stevel 			 *		there's no address family
    805      0     stevel 			 *		restriction
    806      0     stevel 			 *	OR
    807      0     stevel 			 *		we don't know the address yet
    808      0     stevel 			 *		(because we were called from
    809      0     stevel 			 *		main)
    810      0     stevel 			 *	OR
    811      0     stevel 			 *		there is a restriction AND
    812      0     stevel 			 *		the address families match
    813      0     stevel 			 */
    814      0     stevel 			if ((p->c_af == AF_ANY)	||
    815      0     stevel 			    (lifrp == (struct lifreq *)NULL) ||
    816      0     stevel 			    (lifrp->lifr_addr.ss_family == p->c_af)) {
    817      0     stevel 				ret = (*p->c_func)(*argv, p->c_parameter);
    818      0     stevel 				/*
    819      0     stevel 				 *	If c_func failed and we should
    820      0     stevel 				 *	abort processing for this
    821      0     stevel 				 *	interface on failure, return
    822      0     stevel 				 *	now rather than going on to
    823      0     stevel 				 *	process other commands for
    824      0     stevel 				 *	the same interface.
    825      0     stevel 				 */
    826      0     stevel 				if (ret != 0 && p->c_abortonfail)
    827      0     stevel 					return;
    828      0     stevel 			}
    829      0     stevel 		}
    830      0     stevel 		argc--, argv++;
    831      0     stevel 	}
    832      0     stevel 
    833      0     stevel 	/* Check to see if there's a security hole in the tunnel setup. */
    834  10616  Sebastien 	if (ipsec_policy_set && !ipsec_auth_covered) {
    835  10616  Sebastien 		(void) fprintf(stderr, "ifconfig: WARNING: tunnel with only "
    836  10616  Sebastien 		    "ESP and no authentication.\n");
    837  10616  Sebastien 	}
    838      0     stevel }
    839      0     stevel 
    840      0     stevel /* ARGSUSED */
    841      0     stevel static int
    842      0     stevel setdebugflag(char *val, int64_t arg)
    843      0     stevel {
    844      0     stevel 	debug++;
    845      0     stevel 	return (0);
    846      0     stevel }
    847      0     stevel 
    848      0     stevel /* ARGSUSED */
    849      0     stevel static int
    850      0     stevel setverboseflag(char *val, int64_t arg)
    851      0     stevel {
    852      0     stevel 	verbose++;
    853      0     stevel 	return (0);
    854      0     stevel }
    855      0     stevel 
    856      0     stevel /*
    857    198     kcpoon  * This function fills in the given lifreq's lifr_addr field based on
    858    198     kcpoon  * g_netmask_set.
    859    198     kcpoon  */
    860    198     kcpoon static void
    861    198     kcpoon set_mask_lifreq(struct lifreq *lifr, struct sockaddr_storage *addr,
    862    198     kcpoon     struct sockaddr_storage *mask)
    863    198     kcpoon {
    864    198     kcpoon 	assert(addr != NULL);
    865    198     kcpoon 	assert(mask != NULL);
    866    198     kcpoon 
    867    198     kcpoon 	switch (g_netmask_set) {
    868    198     kcpoon 	case G_NETMASK_SET:
    869    198     kcpoon 		lifr->lifr_addr = g_netmask;
    870    198     kcpoon 		break;
    871    198     kcpoon 
    872    198     kcpoon 	case G_NETMASK_PENDING:
    873    198     kcpoon 		/*
    874    198     kcpoon 		 * "+" is used as the argument to "netmask" command.  Query
    875    198     kcpoon 		 * the database on the correct netmask based on the address to
    876    198     kcpoon 		 * be set.
    877    198     kcpoon 		 */
    878    198     kcpoon 		assert(afp->af_af == AF_INET);
    879    198     kcpoon 		g_netmask = *addr;
    880    198     kcpoon 		if (!in_getmask((struct sockaddr_in *)&g_netmask, _B_TRUE)) {
    881    198     kcpoon 			lifr->lifr_addr = *mask;
    882    198     kcpoon 			g_netmask_set = G_NETMASK_NIL;
    883    198     kcpoon 		} else {
    884    198     kcpoon 			lifr->lifr_addr = g_netmask;
    885    198     kcpoon 			g_netmask_set = G_NETMASK_SET;
    886    198     kcpoon 		}
    887    198     kcpoon 		break;
    888    198     kcpoon 
    889    198     kcpoon 	case G_NETMASK_NIL:
    890    198     kcpoon 	default:
    891    198     kcpoon 		lifr->lifr_addr = *mask;
    892    198     kcpoon 		break;
    893    198     kcpoon 	}
    894    198     kcpoon }
    895    198     kcpoon 
    896    198     kcpoon /*
    897      0     stevel  * Set the interface address. Handles <addr>, <addr>/<n> as well as /<n>
    898      0     stevel  * syntax for setting the address, the address plus netmask, and just
    899      0     stevel  * the netmask respectively.
    900      0     stevel  */
    901      0     stevel /* ARGSUSED */
    902      0     stevel static int
    903      0     stevel setifaddr(char *addr, int64_t param)
    904      0     stevel {
    905      0     stevel 	int prefixlen = 0;
    906      0     stevel 	struct	sockaddr_storage laddr;
    907      0     stevel 	struct	sockaddr_storage netmask;
    908      0     stevel 	struct	sockaddr_in6 *sin6;
    909      0     stevel 	struct	sockaddr_in *sin;
    910      0     stevel 	struct	sockaddr_storage sav_netmask;
    911      0     stevel 
    912      0     stevel 	if (addr[0] == '/')
    913      0     stevel 		return (setifprefixlen(addr, 0));
    914      0     stevel 
    915      0     stevel 	(*afp->af_getaddr)(addr, (struct sockaddr *)&laddr, &prefixlen);
    916      0     stevel 
    917      0     stevel 	(void) memset(&netmask, 0, sizeof (netmask));
    918      0     stevel 	netmask.ss_family = afp->af_af;
    919      0     stevel 	switch (prefixlen) {
    920      0     stevel 	case NO_PREFIX:
    921      0     stevel 		/* Nothing there - ok */
    922      0     stevel 		break;
    923      0     stevel 	case BAD_ADDR:
    924      0     stevel 		(void) fprintf(stderr, "ifconfig: Bad prefix length in %s\n",
    925      0     stevel 		    addr);
    926      0     stevel 		exit(1);
    927      0     stevel 	default:
    928      0     stevel 		if (afp->af_af == AF_INET6) {
    929      0     stevel 			sin6 = (struct sockaddr_in6 *)&netmask;
    930   2346       meem 			if (!in_prefixlentomask(prefixlen, IPV6_ABITS,
    931      0     stevel 			    (uchar_t *)&sin6->sin6_addr)) {
    932      0     stevel 				(void) fprintf(stderr, "ifconfig: "
    933      0     stevel 				    "Bad prefix length: %d\n",
    934      0     stevel 				    prefixlen);
    935      0     stevel 				exit(1);
    936      0     stevel 			}
    937      0     stevel 		} else {
    938      0     stevel 			sin = (struct sockaddr_in *)&netmask;
    939   2346       meem 			if (!in_prefixlentomask(prefixlen, IP_ABITS,
    940      0     stevel 			    (uchar_t *)&sin->sin_addr)) {
    941      0     stevel 				(void) fprintf(stderr, "ifconfig: "
    942      0     stevel 				    "Bad prefix length: %d\n",
    943      0     stevel 				    prefixlen);
    944      0     stevel 				exit(1);
    945      0     stevel 			}
    946      0     stevel 		}
    947      0     stevel 		/*
    948      0     stevel 		 * Just in case of funny setting of both prefix and netmask,
    949      0     stevel 		 * prefix should override the netmask command.
    950      0     stevel 		 */
    951    198     kcpoon 		g_netmask_set = G_NETMASK_NIL;
    952      0     stevel 		break;
    953      0     stevel 	}
    954      0     stevel 	/* Tell parser that an address was set */
    955      0     stevel 	setaddr++;
    956      0     stevel 	/* save copy of netmask to restore in case of error */
    957      0     stevel 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
    958      0     stevel 	if (ioctl(s, SIOCGLIFNETMASK, (caddr_t)&lifr) < 0)
    959      0     stevel 		Perror0_exit("SIOCGLIFNETMASK");
    960      0     stevel 	sav_netmask = lifr.lifr_addr;
    961      0     stevel 
    962      0     stevel 	/*
    963      0     stevel 	 * If setting the address and not the mask, clear any existing mask
    964      0     stevel 	 * and the kernel will then assign the default (netmask has been set
    965      0     stevel 	 * to 0 in this case).  If setting both (either by using a prefix or
    966      0     stevel 	 * using the netmask command), set the mask first, so the address will
    967      0     stevel 	 * be interpreted correctly.
    968      0     stevel 	 */
    969    198     kcpoon 	set_mask_lifreq(&lifr, &laddr, &netmask);
    970      0     stevel 	if (ioctl(s, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0)
    971      0     stevel 		Perror0_exit("SIOCSLIFNETMASK");
    972      0     stevel 
    973      0     stevel 	if (debug) {
    974      0     stevel 		char abuf[INET6_ADDRSTRLEN];
    975      0     stevel 		void *addr = (afp->af_af == AF_INET) ?
    976      0     stevel 		    (void *)&((struct sockaddr_in *)&laddr)->sin_addr :
    977      0     stevel 		    (void *)&((struct sockaddr_in6 *)&laddr)->sin6_addr;
    978      0     stevel 
    979      0     stevel 		(void) printf("Setting %s af %d addr %s\n",
    980      0     stevel 		    lifr.lifr_name, afp->af_af,
    981      0     stevel 		    inet_ntop(afp->af_af, addr, abuf, sizeof (abuf)));
    982      0     stevel 	}
    983      0     stevel 	lifr.lifr_addr = laddr;
    984      0     stevel 	lifr.lifr_addr.ss_family = afp->af_af;
    985      0     stevel 	if (ioctl(s, SIOCSLIFADDR, (caddr_t)&lifr) < 0) {
    986      0     stevel 		/*
    987      0     stevel 		 * Restore the netmask
    988      0     stevel 		 */
    989      0     stevel 		int saverr = errno;
    990      0     stevel 
    991      0     stevel 		(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
    992      0     stevel 		lifr.lifr_addr = sav_netmask;
    993      0     stevel 		(void) ioctl(s, SIOCSLIFNETMASK, (caddr_t)&lifr);
    994      0     stevel 		errno = saverr;
    995      0     stevel 		Perror0_exit("SIOCSLIFADDR");
    996      0     stevel 	}
    997      0     stevel 
    998      0     stevel 	return (0);
    999      0     stevel }
   1000      0     stevel 
   1001      0     stevel /*
   1002      0     stevel  * The following functions are stolen from the ipseckey(1m) program.
   1003      0     stevel  * Perhaps they should be somewhere common, but for now, we just maintain
   1004      0     stevel  * two versions.  We do this because of the different semantics for which
   1005      0     stevel  * algorithms we select ("requested" for ifconfig vs. "actual" for key).
   1006      0     stevel  */
   1007      0     stevel 
   1008      0     stevel static ulong_t
   1009      0     stevel parsenum(char *num)
   1010      0     stevel {
   1011      0     stevel 	ulong_t rc;
   1012      0     stevel 	char *end = NULL;
   1013      0     stevel 
   1014      0     stevel 	errno = 0;
   1015      0     stevel 	rc = strtoul(num, &end, 0);
   1016      0     stevel 	if (errno != 0 || end == num || *end != '\0') {
   1017      0     stevel 		rc = (ulong_t)-1;
   1018      0     stevel 	}
   1019      0     stevel 
   1020      0     stevel 	return (rc);
   1021      0     stevel }
   1022      0     stevel 
   1023      0     stevel /*
   1024      0     stevel  * Parse and reverse parse possible algorithm values, include numbers.
   1025      0     stevel  * Mostly stolen from ipseckey.c. See the comments above parsenum() for why
   1026      0     stevel  * this isn't common to ipseckey.c.
   1027      0     stevel  *
   1028      0     stevel  * NOTE: Static buffer in this function for the return value.  Since ifconfig
   1029  10616  Sebastien  *       isn't multithreaded, this isn't a huge problem.
   1030      0     stevel  */
   1031      0     stevel 
   1032      0     stevel #define	NBUF_SIZE 20	/* Enough to print a large integer. */
   1033      0     stevel 
   1034      0     stevel static char *
   1035      0     stevel rparsealg(uint8_t alg_value, int proto_num)
   1036      0     stevel {
   1037      0     stevel 	struct ipsecalgent *alg;
   1038      0     stevel 	static char numprint[128];	/* Enough to hold an algorithm name. */
   1039      0     stevel 
   1040   6524    pwernau 	/*
   1041   6524    pwernau 	 * Special cases for "any" and "none"
   1042   6524    pwernau 	 * The kernel needs to be able to distinguish between "any"
   1043   6524    pwernau 	 * and "none" and the APIs are underdefined in this area for auth.
   1044   6524    pwernau 	 */
   1045   6524    pwernau 	if (proto_num == IPSEC_PROTO_AH) {
   1046   6524    pwernau 		if (alg_value == SADB_AALG_NONE)
   1047   6524    pwernau 			return ("none");
   1048   6524    pwernau 		if (alg_value == SADB_AALG_ANY)
   1049   6524    pwernau 			return ("any");
   1050   6524    pwernau 	}
   1051      0     stevel 
   1052      0     stevel 	alg = getipsecalgbynum(alg_value, proto_num, NULL);
   1053      0     stevel 	if (alg != NULL) {
   1054      0     stevel 		(void) strlcpy(numprint, alg->a_names[0], sizeof (numprint));
   1055      0     stevel 		freeipsecalgent(alg);
   1056      0     stevel 	} else {
   1057      0     stevel 		(void) snprintf(numprint, sizeof (numprint), "%d", alg_value);
   1058      0     stevel 	}
   1059      0     stevel 
   1060      0     stevel 	return (numprint);
   1061      0     stevel }
   1062      0     stevel 
   1063      0     stevel static uint_t
   1064      0     stevel parsealg(char *algname, int proto_num)
   1065      0     stevel {
   1066      0     stevel 	struct ipsecalgent *alg;
   1067      0     stevel 	ulong_t invalue;
   1068      0     stevel 
   1069      0     stevel 	if (algname == NULL) {
   1070      0     stevel 		(void) fprintf(stderr, "ifconfig: Unexpected end of command "
   1071      0     stevel 		    "line.\n");
   1072      0     stevel 		exit(1);
   1073      0     stevel 	}
   1074      0     stevel 
   1075      0     stevel 	/*
   1076   6524    pwernau 	 * Special-case "none" and "any".
   1077   6524    pwernau 	 * Use strcasecmp because its length is bounded.
   1078      0     stevel 	 */
   1079      0     stevel 	if (strcasecmp("none", algname) == 0) {
   1080      0     stevel 		return ((proto_num == IPSEC_PROTO_ESP) ?
   1081      0     stevel 		    NO_ESP_EALG : NO_ESP_AALG);
   1082      0     stevel 	}
   1083   6524    pwernau 	if ((strcasecmp("any", algname) == 0) && (proto_num == IPSEC_PROTO_AH))
   1084   6524    pwernau 		return (SADB_AALG_ANY);
   1085      0     stevel 
   1086      0     stevel 	alg = getipsecalgbyname(algname, proto_num, NULL);
   1087      0     stevel 	if (alg != NULL) {
   1088      0     stevel 		invalue = alg->a_alg_num;
   1089      0     stevel 		freeipsecalgent(alg);
   1090      0     stevel 		return ((uint_t)invalue);
   1091      0     stevel 	}
   1092      0     stevel 
   1093      0     stevel 	/*
   1094      0     stevel 	 * Since algorithms can be loaded during kernel run-time, check for
   1095      0     stevel 	 * numeric algorithm values too.
   1096      0     stevel 	 */
   1097      0     stevel 	invalue = parsenum(algname);
   1098      0     stevel 	if ((invalue & (ulong_t)0xff) == invalue)
   1099      0     stevel 		return ((uint_t)invalue);
   1100      0     stevel 
   1101      0     stevel 	(void) fprintf(stderr, "ifconfig: %s algorithm type %s unknown.\n",
   1102      0     stevel 	    (proto_num == IPSEC_PROTO_ESP) ?
   1103      0     stevel 	    "Encryption" : "Authentication", algname);
   1104      0     stevel 	exit(1);
   1105      0     stevel 	/* NOTREACHED */
   1106      0     stevel }
   1107      0     stevel 
   1108      0     stevel /*
   1109      0     stevel  * Actual ifconfig functions to set tunnel security properties.
   1110      0     stevel  */
   1111      0     stevel 
   1112      0     stevel enum ipsec_alg_type { ESP_ENCR_ALG = 1, ESP_AUTH_ALG, AH_AUTH_ALG };
   1113      0     stevel 
   1114      0     stevel static int
   1115      0     stevel set_tun_algs(int which_alg, int alg)
   1116      0     stevel {
   1117  10616  Sebastien 	boolean_t	encr_alg_set = _B_FALSE;
   1118  10616  Sebastien 	iptun_params_t	params;
   1119  10616  Sebastien 	dladm_status_t	status;
   1120  10616  Sebastien 	ipsec_req_t	*ipsr;
   1121  10616  Sebastien 
   1122  10616  Sebastien 	if ((status = ifconfig_dladm_open(name, DATALINK_CLASS_IPTUN,
   1123  10616  Sebastien 	    &params.iptun_param_linkid)) != DLADM_STATUS_OK)
   1124  10616  Sebastien 		goto done;
   1125  10616  Sebastien 
   1126  10616  Sebastien 	status = dladm_iptun_getparams(dlh, &params, DLADM_OPT_ACTIVE);
   1127  10616  Sebastien 	if (status != DLADM_STATUS_OK)
   1128  10616  Sebastien 		goto done;
   1129  10616  Sebastien 
   1130  10616  Sebastien 	ipsr = &params.iptun_param_secinfo;
   1131      0     stevel 
   1132      0     stevel 	/*
   1133      0     stevel 	 * If I'm just starting off this ifconfig, I want a clean slate,
   1134      0     stevel 	 * otherwise, I've captured the current tunnel security settings.
   1135      0     stevel 	 * In the case of continuation, I merely add to the settings.
   1136      0     stevel 	 */
   1137  10616  Sebastien 	if (!(params.iptun_param_flags & IPTUN_PARAM_SECINFO))
   1138      0     stevel 		(void) memset(ipsr, 0, sizeof (*ipsr));
   1139  10616  Sebastien 
   1140  10616  Sebastien 	/* We're only modifying the IPsec information */
   1141  10616  Sebastien 	params.iptun_param_flags = IPTUN_PARAM_SECINFO;
   1142      0     stevel 
   1143      0     stevel 	switch (which_alg) {
   1144      0     stevel 	case ESP_ENCR_ALG:
   1145      0     stevel 		if (alg == NO_ESP_EALG) {
   1146      0     stevel 			if (ipsr->ipsr_esp_auth_alg == SADB_AALG_NONE)
   1147      0     stevel 				ipsr->ipsr_esp_req = 0;
   1148      0     stevel 			ipsr->ipsr_esp_alg = SADB_EALG_NONE;
   1149   6524    pwernau 
   1150   6524    pwernau 			/* Let the user specify NULL encryption implicitly. */
   1151   6524    pwernau 			if (ipsr->ipsr_esp_auth_alg != SADB_AALG_NONE) {
   1152   6524    pwernau 				encr_alg_set = _B_TRUE;
   1153   6524    pwernau 				ipsr->ipsr_esp_alg = SADB_EALG_NULL;
   1154   6524    pwernau 			}
   1155      0     stevel 		} else {
   1156      0     stevel 			encr_alg_set = _B_TRUE;
   1157      0     stevel 			ipsr->ipsr_esp_req =
   1158      0     stevel 			    IPSEC_PREF_REQUIRED | IPSEC_PREF_UNIQUE;
   1159      0     stevel 			ipsr->ipsr_esp_alg = alg;
   1160      0     stevel 		}
   1161      0     stevel 		break;
   1162      0     stevel 	case ESP_AUTH_ALG:
   1163      0     stevel 		if (alg == NO_ESP_AALG) {
   1164   6524    pwernau 			if ((ipsr->ipsr_esp_alg == SADB_EALG_NONE ||
   1165   6524    pwernau 			    ipsr->ipsr_esp_alg == SADB_EALG_NULL) &&
   1166   6524    pwernau 			    !encr_alg_set)
   1167      0     stevel 				ipsr->ipsr_esp_req = 0;
   1168      0     stevel 			ipsr->ipsr_esp_auth_alg = SADB_AALG_NONE;
   1169      0     stevel 		} else {
   1170      0     stevel 			ipsr->ipsr_esp_req =
   1171      0     stevel 			    IPSEC_PREF_REQUIRED | IPSEC_PREF_UNIQUE;
   1172      0     stevel 			ipsr->ipsr_esp_auth_alg = alg;
   1173      0     stevel 
   1174      0     stevel 			/* Let the user specify NULL encryption implicitly. */
   1175      0     stevel 			if (ipsr->ipsr_esp_alg == SADB_EALG_NONE &&
   1176      0     stevel 			    !encr_alg_set)
   1177      0     stevel 				ipsr->ipsr_esp_alg = SADB_EALG_NULL;
   1178      0     stevel 		}
   1179      0     stevel 		break;
   1180      0     stevel 	case AH_AUTH_ALG:
   1181      0     stevel 		if (alg == NO_AH_AALG) {
   1182      0     stevel 			ipsr->ipsr_ah_req = 0;
   1183      0     stevel 			ipsr->ipsr_auth_alg = SADB_AALG_NONE;
   1184      0     stevel 		} else {
   1185      0     stevel 			ipsr->ipsr_ah_req =
   1186      0     stevel 			    IPSEC_PREF_REQUIRED | IPSEC_PREF_UNIQUE;
   1187      0     stevel 			ipsr->ipsr_auth_alg = alg;
   1188      0     stevel 		}
   1189      0     stevel 		break;
   1190      0     stevel 		/* Will never hit DEFAULT */
   1191      0     stevel 	}
   1192      0     stevel 
   1193  10616  Sebastien 	status = dladm_iptun_modify(dlh, &params, DLADM_OPT_ACTIVE);
   1194  10616  Sebastien 
   1195  10616  Sebastien done:
   1196  10616  Sebastien 	if (status != DLADM_STATUS_OK)
   1197  10616  Sebastien 		dladmerr_exit(status, name);
   1198  10616  Sebastien 	else {
   1199  10616  Sebastien 		ipsec_policy_set = _B_TRUE;
   1200  10616  Sebastien 		if ((ipsr->ipsr_esp_req != 0 &&
   1201  10616  Sebastien 		    ipsr->ipsr_esp_auth_alg != SADB_AALG_NONE) ||
   1202  10616  Sebastien 		    (ipsr->ipsr_ah_req != 0 &&
   1203  10616  Sebastien 		    ipsr->ipsr_auth_alg != SADB_AALG_NONE))
   1204  10616  Sebastien 			ipsec_auth_covered = _B_TRUE;
   1205  10616  Sebastien 	}
   1206      0     stevel 	return (0);
   1207      0     stevel }
   1208      0     stevel 
   1209      0     stevel /* ARGSUSED */
   1210      0     stevel static int
   1211      0     stevel set_tun_esp_encr_alg(char *addr, int64_t param)
   1212      0     stevel {
   1213      0     stevel 	return (set_tun_algs(ESP_ENCR_ALG,
   1214   5240   nordmark 	    parsealg(addr, IPSEC_PROTO_ESP)));
   1215      0     stevel }
   1216      0     stevel 
   1217      0     stevel /* ARGSUSED */
   1218      0     stevel static int
   1219      0     stevel set_tun_esp_auth_alg(char *addr, int64_t param)
   1220      0     stevel {
   1221      0     stevel 	return (set_tun_algs(ESP_AUTH_ALG,
   1222   5240   nordmark 	    parsealg(addr, IPSEC_PROTO_AH)));
   1223      0     stevel }
   1224      0     stevel 
   1225      0     stevel /* ARGSUSED */
   1226      0     stevel static int
   1227      0     stevel set_tun_ah_alg(char *addr, int64_t param)
   1228      0     stevel {
   1229      0     stevel 	return (set_tun_algs(AH_AUTH_ALG,
   1230   5240   nordmark 	    parsealg(addr, IPSEC_PROTO_AH)));
   1231      0     stevel }
   1232      0     stevel 
   1233      0     stevel /* ARGSUSED */
   1234      0     stevel static int
   1235      0     stevel setifrevarp(char *arg, int64_t param)
   1236      0     stevel {
   1237      0     stevel 	struct sockaddr_in	laddr;
   1238      0     stevel 
   1239      0     stevel 	if (afp->af_af == AF_INET6) {
   1240      0     stevel 		(void) fprintf(stderr,
   1241      0     stevel 		    "ifconfig: revarp not possible on IPv6 interface %s\n",
   1242      0     stevel 		    name);
   1243      0     stevel 		exit(1);
   1244      0     stevel 	}
   1245      0     stevel 	if (doifrevarp(name, &laddr)) {
   1246      0     stevel 		(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   1247      0     stevel 		laddr.sin_family = AF_INET;
   1248      0     stevel 		(void) memcpy(&lifr.lifr_addr, &laddr, sizeof (laddr));
   1249      0     stevel 		if (ioctl(s, SIOCSLIFADDR, (caddr_t)&lifr) < 0)
   1250      0     stevel 			Perror0_exit("SIOCSLIFADDR");
   1251      0     stevel 	}
   1252      0     stevel 	return (0);
   1253      0     stevel }
   1254      0     stevel 
   1255      0     stevel /* ARGSUSED */
   1256      0     stevel static int
   1257      0     stevel setifsubnet(char *addr, int64_t param)
   1258      0     stevel {
   1259      0     stevel 	int prefixlen = 0;
   1260      0     stevel 	struct	sockaddr_storage subnet;
   1261      0     stevel 
   1262      0     stevel 	(*afp->af_getaddr)(addr, &subnet, &prefixlen);
   1263      0     stevel 
   1264      0     stevel 	switch (prefixlen) {
   1265      0     stevel 	case NO_PREFIX:
   1266      0     stevel 		(void) fprintf(stderr,
   1267      0     stevel 		    "ifconfig: Missing prefix length in subnet %s\n", addr);
   1268      0     stevel 		exit(1);
   1269      0     stevel 		/* NOTREACHED */
   1270      0     stevel 	case BAD_ADDR:
   1271      0     stevel 		(void) fprintf(stderr,
   1272      0     stevel 		    "ifconfig: Bad prefix length in %s\n", addr);
   1273      0     stevel 		exit(1);
   1274      0     stevel 	default:
   1275      0     stevel 		break;
   1276      0     stevel 	}
   1277      0     stevel 
   1278      0     stevel 	lifr.lifr_addr = subnet;
   1279      0     stevel 	lifr.lifr_addrlen = prefixlen;
   1280      0     stevel 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   1281      0     stevel 	if (ioctl(s, SIOCSLIFSUBNET, (caddr_t)&lifr) < 0)
   1282      0     stevel 		Perror0_exit("SIOCSLIFSUBNET");
   1283      0     stevel 
   1284      0     stevel 	return (0);
   1285      0     stevel }
   1286      0     stevel 
   1287      0     stevel /* ARGSUSED */
   1288      0     stevel static int
   1289      0     stevel setifnetmask(char *addr, int64_t param)
   1290      0     stevel {
   1291      0     stevel 	struct sockaddr_in netmask;
   1292      0     stevel 
   1293      0     stevel 	assert(afp->af_af != AF_INET6);
   1294      0     stevel 
   1295      0     stevel 	if (strcmp(addr, "+") == 0) {
   1296    198     kcpoon 		if (!in_getmask(&netmask, _B_FALSE))
   1297      0     stevel 			return (0);
   1298    198     kcpoon 		(void) printf("Setting netmask of %s to %s\n", name,
   1299    198     kcpoon 		    inet_ntoa(netmask.sin_addr));
   1300      0     stevel 	} else {
   1301      0     stevel 		in_getaddr(addr, (struct sockaddr *)&netmask, NULL);
   1302      0     stevel 	}
   1303      0     stevel 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   1304      0     stevel 	(void) memcpy(&lifr.lifr_addr, &netmask, sizeof (netmask));
   1305      0     stevel 	if (ioctl(s, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0)
   1306      0     stevel 		Perror0_exit("SIOCSLIFNETMASK");
   1307      0     stevel 	return (0);
   1308      0     stevel }
   1309      0     stevel 
   1310      0     stevel /*
   1311      0     stevel  * Parse '/<n>' as a netmask.
   1312      0     stevel  */
   1313      0     stevel /* ARGSUSED */
   1314      0     stevel static int
   1315      0     stevel setifprefixlen(char *addr, int64_t param)
   1316      0     stevel {
   1317      0     stevel 	int prefixlen;
   1318      0     stevel 	int af = afp->af_af;
   1319      0     stevel 
   1320      0     stevel 	prefixlen = in_getprefixlen(addr, _B_TRUE,
   1321   2346       meem 	    (af == AF_INET) ? IP_ABITS : IPV6_ABITS);
   1322      0     stevel 	if (prefixlen < 0) {
   1323      0     stevel 		(void) fprintf(stderr,
   1324      0     stevel 		    "ifconfig: Bad prefix length in %s\n", addr);
   1325      0     stevel 		exit(1);
   1326      0     stevel 	}
   1327      0     stevel 	(void) memset(&lifr.lifr_addr, 0, sizeof (lifr.lifr_addr));
   1328      0     stevel 	lifr.lifr_addr.ss_family = af;
   1329      0     stevel 	if (af == AF_INET6) {
   1330      0     stevel 		struct sockaddr_in6 *sin6;
   1331      0     stevel 
   1332      0     stevel 		sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr;
   1333   2346       meem 		if (!in_prefixlentomask(prefixlen, IPV6_ABITS,
   1334      0     stevel 		    (uchar_t *)&sin6->sin6_addr)) {
   1335      0     stevel 			(void) fprintf(stderr, "ifconfig: "
   1336      0     stevel 			    "Bad prefix length: %d\n",
   1337      0     stevel 			    prefixlen);
   1338      0     stevel 			exit(1);
   1339      0     stevel 		}
   1340      0     stevel 	} else if (af == AF_INET) {
   1341      0     stevel 		struct sockaddr_in *sin;
   1342      0     stevel 
   1343      0     stevel 		sin = (struct sockaddr_in *)&lifr.lifr_addr;
   1344   2346       meem 		if (!in_prefixlentomask(prefixlen, IP_ABITS,
   1345      0     stevel 		    (uchar_t *)&sin->sin_addr)) {
   1346      0     stevel 			(void) fprintf(stderr, "ifconfig: "
   1347      0     stevel 			    "Bad prefix length: %d\n",
   1348      0     stevel 			    prefixlen);
   1349      0     stevel 			exit(1);
   1350      0     stevel 		}
   1351      0     stevel 	} else {
   1352      0     stevel 		(void) fprintf(stderr, "ifconfig: setting prefix only supported"
   1353      0     stevel 		    " for address family inet or inet6\n");
   1354      0     stevel 		exit(1);
   1355      0     stevel 	}
   1356      0     stevel 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   1357      0     stevel 	if (ioctl(s, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0)
   1358      0     stevel 		Perror0_exit("SIOCSLIFNETMASK");
   1359      0     stevel 	return (0);
   1360      0     stevel }
   1361      0     stevel 
   1362      0     stevel /* ARGSUSED */
   1363      0     stevel static int
   1364      0     stevel setifbroadaddr(char *addr, int64_t param)
   1365      0     stevel {
   1366      0     stevel 	struct	sockaddr_in broadaddr;
   1367      0     stevel 
   1368      0     stevel 	assert(afp->af_af != AF_INET6);
   1369      0     stevel 
   1370      0     stevel 	if (strcmp(addr, "+") == 0) {
   1371      0     stevel 		/*
   1372      0     stevel 		 * This doesn't set the broadcast address at all. Rather, it
   1373      0     stevel 		 * gets, then sets the interface's address, relying on the fact
   1374      0     stevel 		 * that resetting the address will reset the broadcast address.
   1375      0     stevel 		 */
   1376      0     stevel 		(void) strncpy(lifr.lifr_name, name,
   1377      0     stevel 		    sizeof (lifr.lifr_name));
   1378      0     stevel 		if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) < 0) {
   1379      0     stevel 			if (errno != EADDRNOTAVAIL)
   1380      0     stevel 				Perror0_exit("SIOCGLIFADDR");
   1381      0     stevel 			return (0);
   1382      0     stevel 		}
   1383      0     stevel 		if (ioctl(s, SIOCSLIFADDR, (caddr_t)&lifr) < 0)
   1384      0     stevel 			Perror0_exit("SIOCGLIFADDR");
   1385      0     stevel 
   1386      0     stevel 		return (0);
   1387      0     stevel 	}
   1388      0     stevel 	in_getaddr(addr, (struct sockaddr *)&broadaddr, NULL);
   1389      0     stevel 
   1390      0     stevel 	(void) memcpy(&lifr.lifr_addr, &broadaddr, sizeof (broadaddr));
   1391      0     stevel 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   1392      0     stevel 	if (ioctl(s, SIOCSLIFBRDADDR, (caddr_t)&lifr) < 0)
   1393      0     stevel 		Perror0_exit("SIOCSLIFBRDADDR");
   1394      0     stevel 	return (0);
   1395      0     stevel }
   1396      0     stevel 
   1397      0     stevel /*
   1398      0     stevel  * set interface destination address
   1399      0     stevel  */
   1400      0     stevel /* ARGSUSED */
   1401      0     stevel static int
   1402      0     stevel setifdstaddr(char *addr, int64_t param)
   1403      0     stevel {
   1404      0     stevel 	(*afp->af_getaddr)(addr, (struct sockaddr *)&lifr.lifr_addr, NULL);
   1405      0     stevel 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   1406      0     stevel 	if (ioctl(s, SIOCSLIFDSTADDR, (caddr_t)&lifr) < 0)
   1407      0     stevel 		Perror0_exit("setifdstaddr: SIOCSLIFDSTADDR");
   1408      0     stevel 	return (0);
   1409      0     stevel }
   1410      0     stevel 
   1411      0     stevel /* ARGSUSED */
   1412      0     stevel static int
   1413      0     stevel setifflags(char *val, int64_t value)
   1414      0     stevel {
   1415   8485      Peter 	struct lifreq lifrl;	/* local lifreq struct */
   1416   8485      Peter 	boolean_t bringup = _B_FALSE;
   1417      0     stevel 
   1418      0     stevel 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   1419      0     stevel 	if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0)
   1420      0     stevel 		Perror0_exit("setifflags: SIOCGLIFFLAGS");
   1421      0     stevel 
   1422      0     stevel 	if (value < 0) {
   1423      0     stevel 		value = -value;
   1424   8485      Peter 
   1425   8485      Peter 		if ((value & IFF_NOFAILOVER) && (lifr.lifr_flags & IFF_UP)) {
   1426   8485      Peter 			/*
   1427   8485      Peter 			 * The kernel does not allow administratively up test
   1428   8485      Peter 			 * addresses to be converted to data addresses.  Bring
   1429   8485      Peter 			 * the address down first, then bring it up after it's
   1430   8485      Peter 			 * been converted to a data address.
   1431   8485      Peter 			 */
   1432   8485      Peter 			lifr.lifr_flags &= ~IFF_UP;
   1433   8485      Peter 			(void) ioctl(s, SIOCSLIFFLAGS, (caddr_t)&lifr);
   1434   8485      Peter 			bringup = _B_TRUE;
   1435   8485      Peter 		}
   1436   8485      Peter 
   1437      0     stevel 		lifr.lifr_flags &= ~value;
   1438   8485      Peter 		if ((value & (IFF_UP | IFF_NOFAILOVER)) &&
   1439   8485      Peter 		    (lifr.lifr_flags & IFF_DUPLICATE)) {
   1440   2546   carlsonj 			/*
   1441   2546   carlsonj 			 * If the user is trying to mark an interface with a
   1442   8485      Peter 			 * duplicate address as "down," or convert a duplicate
   1443   8485      Peter 			 * test address to a data address, then fetch the
   1444   8485      Peter 			 * address and set it.  This will cause IP to clear
   1445   8485      Peter 			 * the IFF_DUPLICATE flag and stop the automatic
   1446   8485      Peter 			 * recovery timer.
   1447   2546   carlsonj 			 */
   1448   2546   carlsonj 			value = lifr.lifr_flags;
   1449   2546   carlsonj 			if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) >= 0)
   1450   2546   carlsonj 				(void) ioctl(s, SIOCSLIFADDR, (caddr_t)&lifr);
   1451   2546   carlsonj 			lifr.lifr_flags = value;
   1452   2546   carlsonj 		}
   1453   2546   carlsonj 	} else {
   1454      0     stevel 		lifr.lifr_flags |= value;
   1455   2546   carlsonj 	}
   1456   8485      Peter 
   1457   8485      Peter 	/*
   1458   8485      Peter 	 * If we're about to bring up an underlying physical IPv6 interface in
   1459   8485      Peter 	 * an IPMP group, ensure the IPv6 IPMP interface is also up.  This is
   1460   8485      Peter 	 * for backward compatibility with legacy configurations in which
   1461   8485      Peter 	 * there are no explicit hostname files for IPMP interfaces.  (For
   1462   8485      Peter 	 * IPv4, this is automatically handled by the kernel when migrating
   1463   8485      Peter 	 * the underlying interface's data address to the IPMP interface.)
   1464   8485      Peter 	 */
   1465   8485      Peter 	(void) strlcpy(lifrl.lifr_name, name, LIFNAMSIZ);
   1466   8485      Peter 
   1467   8485      Peter 	if (lifnum(lifr.lifr_name) == 0 &&
   1468   8485      Peter 	    (lifr.lifr_flags & (IFF_UP|IFF_IPV6)) == (IFF_UP|IFF_IPV6) &&
   1469   8485      Peter 	    ioctl(s, SIOCGLIFGROUPNAME, &lifrl) == 0 &&
   1470   8485      Peter 	    lifrl.lifr_groupname[0] != '\0') {
   1471   8485      Peter 		lifgroupinfo_t lifgr;
   1472   8485      Peter 
   1473   8485      Peter 		(void) strlcpy(lifgr.gi_grname, lifrl.lifr_groupname,
   1474   8485      Peter 		    LIFGRNAMSIZ);
   1475   8485      Peter 		if (ioctl(s, SIOCGLIFGROUPINFO, &lifgr) == -1)
   1476   8485      Peter 			Perror0_exit("setifflags: SIOCGLIFGROUPINFO");
   1477   8485      Peter 
   1478   8485      Peter 		(void) strlcpy(lifrl.lifr_name, lifgr.gi_grifname, LIFNAMSIZ);
   1479   8485      Peter 		if (ioctl(s, SIOCGLIFFLAGS, &lifrl) == -1)
   1480   8485      Peter 			Perror0_exit("setifflags: SIOCGLIFFLAGS");
   1481   8485      Peter 		if (!(lifrl.lifr_flags & IFF_UP)) {
   1482   8485      Peter 			lifrl.lifr_flags |= IFF_UP;
   1483   8485      Peter 			if (ioctl(s, SIOCSLIFFLAGS, &lifrl) == -1)
   1484   8485      Peter 				Perror0_exit("setifflags: SIOCSLIFFLAGS");
   1485   8485      Peter 		}
   1486   8485      Peter 	}
   1487   8485      Peter 
   1488   8485      Peter 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   1489   8485      Peter 	if (ioctl(s, SIOCSLIFFLAGS, (caddr_t)&lifr) < 0)
   1490      0     stevel 		Perror0_exit("setifflags: SIOCSLIFFLAGS");
   1491   8485      Peter 
   1492   8485      Peter 	if (bringup) {
   1493   8485      Peter 		lifr.lifr_flags |= IFF_UP;
   1494   8485      Peter 		if (ioctl(s, SIOCSLIFFLAGS, (caddr_t)&lifr) < 0)
   1495   8485      Peter 			Perror0_exit("setifflags: SIOCSLIFFLAGS IFF_UP");
   1496   8485      Peter 	}
   1497   8485      Peter 
   1498      0     stevel 	return (0);
   1499      0     stevel }
   1500      0     stevel 
   1501      0     stevel /* ARGSUSED */
   1502      0     stevel static int
   1503      0     stevel setifmetric(char *val, int64_t param)
   1504      0     stevel {
   1505      0     stevel 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   1506      0     stevel 	lifr.lifr_metric = atoi(val);
   1507      0     stevel 	if (ioctl(s, SIOCSLIFMETRIC, (caddr_t)&lifr) < 0)
   1508      0     stevel 		Perror0_exit("setifmetric: SIOCSLIFMETRIC");
   1509      0     stevel 	return (0);
   1510      0     stevel }
   1511      0     stevel 
   1512      0     stevel /* ARGSUSED */
   1513      0     stevel static int
   1514      0     stevel setifmtu(char *val, int64_t param)
   1515      0     stevel {
   1516      0     stevel 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   1517      0     stevel 	lifr.lifr_mtu = atoi(val);
   1518      0     stevel 	if (ioctl(s, SIOCSLIFMTU, (caddr_t)&lifr) < 0)
   1519      0     stevel 		Perror0_exit("setifmtu: SIOCSLIFMTU");
   1520      0     stevel 	return (0);
   1521      0     stevel }
   1522      0     stevel 
   1523      0     stevel /* ARGSUSED */
   1524      0     stevel static int
   1525      0     stevel setifindex(char *val, int64_t param)
   1526      0     stevel {
   1527      0     stevel 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   1528      0     stevel 	lifr.lifr_index = atoi(val);
   1529      0     stevel 	if (ioctl(s, SIOCSLIFINDEX, (caddr_t)&lifr) < 0)
   1530      0     stevel 		Perror0_exit("setifindex: SIOCSLIFINDEX");
   1531      0     stevel 	return (0);
   1532      0     stevel }
   1533      0     stevel 
   1534      0     stevel /* ARGSUSED */
   1535   8485      Peter static void
   1536   8485      Peter notifycb(dlpi_handle_t dh, dlpi_notifyinfo_t *dnip, void *arg)
   1537   8485      Peter {
   1538   8485      Peter }
   1539   8485      Peter 
   1540   8485      Peter /* ARGSUSED */
   1541      0     stevel static int
   1542      0     stevel setifether(char *addr, int64_t param)
   1543      0     stevel {
   1544   8485      Peter 	uchar_t		*hwaddr;
   1545   8485      Peter 	int		hwaddrlen;
   1546   8485      Peter 	int		retval;
   1547   8485      Peter 	ifaddrlistx_t	*ifaddrp, *ifaddrs = NULL;
   1548   8485      Peter 	dlpi_handle_t	dh;
   1549   8485      Peter 	dlpi_notifyid_t id;
   1550      0     stevel 
   1551      0     stevel 	if (addr == NULL) {
   1552      0     stevel 		ifstatus(name);
   1553      0     stevel 		print_ifether(name);
   1554      0     stevel 		return (0);
   1555      0     stevel 	}
   1556      0     stevel 
   1557      0     stevel 	/*
   1558      0     stevel 	 * if the IP interface in the arguments is a logical
   1559      0     stevel 	 * interface, exit with an error now.
   1560      0     stevel 	 */
   1561      0     stevel 	if (strchr(name, ':') != NULL) {
   1562      0     stevel 		(void) fprintf(stderr, "ifconfig: cannot change"
   1563      0     stevel 		    " ethernet address of a logical interface\n");
   1564      0     stevel 		exit(1);
   1565      0     stevel 	}
   1566      0     stevel 
   1567   8485      Peter 	if ((hwaddr = _link_aton(addr, &hwaddrlen)) == NULL) {
   1568   8485      Peter 		if (hwaddrlen == -1)
   1569      0     stevel 			(void) fprintf(stderr,
   1570   8485      Peter 			    "ifconfig: %s: bad address\n", hwaddr);
   1571      0     stevel 		else
   1572      0     stevel 			(void) fprintf(stderr, "ifconfig: malloc() failed\n");
   1573      0     stevel 		exit(1);
   1574      0     stevel 	}
   1575      0     stevel 
   1576   8485      Peter 	if ((retval = dlpi_open(name, &dh, 0)) != DLPI_SUCCESS)
   1577   8485      Peter 		Perrdlpi_exit("cannot dlpi_open() link", name, retval);
   1578   8485      Peter 
   1579   8485      Peter 	retval = dlpi_enabnotify(dh, DL_NOTE_PHYS_ADDR, notifycb, NULL, &id);
   1580   8485      Peter 	if (retval == DLPI_SUCCESS) {
   1581   8485      Peter 		(void) dlpi_disabnotify(dh, id, NULL);
   1582   8485      Peter 	} else {
   1583   8485      Peter 		/*
   1584   8485      Peter 		 * This link does not support DL_NOTE_PHYS_ADDR: bring down
   1585   8485      Peter 		 * all of the addresses to flush the old hardware address
   1586   8485      Peter 		 * information out of IP.
   1587   8485      Peter 		 *
   1588   8485      Peter 		 * NOTE: Skipping this when DL_NOTE_PHYS_ADDR is supported is
   1589   8485      Peter 		 * more than an optimization: in.mpathd will set IFF_OFFLINE
   1590   8485      Peter 		 * if it's notified and the new address is a duplicate of
   1591   8485      Peter 		 * another in the group -- but the flags manipulation in
   1592   8485      Peter 		 * ifaddr_{down,up}() cannot be atomic and thus might clobber
   1593   8485      Peter 		 * IFF_OFFLINE, confusing in.mpathd.
   1594   8485      Peter 		 */
   1595   8485      Peter 		if (ifaddrlistx(name, IFF_UP, 0, &ifaddrs) == -1)
   1596   8485      Peter 			Perror2_exit(name, "cannot get address list");
   1597   8485      Peter 
   1598   8485      Peter 		ifaddrp = ifaddrs;
   1599   8485      Peter 		for (; ifaddrp != NULL; ifaddrp = ifaddrp->ia_next) {
   1600   8485      Peter 			if (!ifaddr_down(ifaddrp)) {
   1601   8485      Peter 				Perror2_exit(ifaddrp->ia_name,
   1602   8485      Peter 				    "cannot bring down");
   1603   8485      Peter 			}
   1604   8485      Peter 		}
   1605   8485      Peter 	}
   1606   8485      Peter 
   1607   8485      Peter 	/*
   1608   8485      Peter 	 * Change the hardware address.
   1609   8485      Peter 	 */
   1610   8485      Peter 	retval = dlpi_set_physaddr(dh, DL_CURR_PHYS_ADDR, hwaddr, hwaddrlen);
   1611   8485      Peter 	if (retval != DLPI_SUCCESS) {
   1612   8485      Peter 		(void) fprintf(stderr,
   1613   8485      Peter 		    "ifconfig: failed setting mac address on %s\n", name);
   1614   8485      Peter 	}
   1615   8485      Peter 	dlpi_close(dh);
   1616   8485      Peter 
   1617   8485      Peter 	/*
   1618   8485      Peter 	 * If any addresses were brought down before changing the hardware
   1619   8485      Peter 	 * address, bring them up again.
   1620   8485      Peter 	 */
   1621   8485      Peter 	for (ifaddrp = ifaddrs; ifaddrp != NULL; ifaddrp = ifaddrp->ia_next) {
   1622   8485      Peter 		if (!ifaddr_up(ifaddrp))
   1623   8485      Peter 			Perror2_exit(ifaddrp->ia_name, "cannot bring up");
   1624   8485      Peter 	}
   1625   8485      Peter 	ifaddrlistx_free(ifaddrs);
   1626      0     stevel 
   1627      0     stevel 	return (0);
   1628      0     stevel }
   1629      0     stevel 
   1630      0     stevel /*
   1631      0     stevel  * Print an interface's Ethernet address, if it has one.
   1632      0     stevel  */
   1633      0     stevel static void
   1634      0     stevel print_ifether(char *ifname)
   1635      0     stevel {
   1636  10616  Sebastien 	int fd;
   1637      0     stevel 
   1638      0     stevel 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   1639      0     stevel 
   1640      0     stevel 	fd = socket(AF_INET, SOCK_DGRAM, 0);
   1641      0     stevel 	if (fd == -1 || ioctl(fd, SIOCGLIFFLAGS, &lifr) == -1) {
   1642      0     stevel 		/*
   1643      0     stevel 		 * It's possible the interface is only configured for
   1644      0     stevel 		 * IPv6; check again with AF_INET6.
   1645      0     stevel 		 */
   1646      0     stevel 		(void) close(fd);
   1647      0     stevel 		fd = socket(AF_INET6, SOCK_DGRAM, 0);
   1648      0     stevel 		if (fd == -1 || ioctl(fd, SIOCGLIFFLAGS, &lifr) == -1) {
   1649      0     stevel 			(void) close(fd);
   1650      0     stevel 			return;
   1651      0     stevel 		}
   1652      0     stevel 	}
   1653      0     stevel 	(void) close(fd);
   1654      0     stevel 
   1655   8485      Peter 	/* VNI and IPMP interfaces don't have MAC addresses */
   1656   8485      Peter 	if (lifr.lifr_flags & (IFF_VIRTUAL|IFF_IPMP))
   1657      0     stevel 		return;
   1658      0     stevel 
   1659  10616  Sebastien 	/* IP tunnels also don't have Ethernet-like MAC addresses */
   1660  10616  Sebastien 	if (ifconfig_dladm_open(ifname, DATALINK_CLASS_IPTUN, NULL) ==
   1661  10616  Sebastien 	    DLADM_STATUS_OK)
   1662  10616  Sebastien 		return;
   1663      0     stevel 
   1664      0     stevel 	dlpi_print_address(ifname);
   1665      0     stevel }
   1666      0     stevel 
   1667      0     stevel /*
   1668  10616  Sebastien  * static int find_all_interfaces(struct lifconf *lifcp, char **buf,
   1669   3448   dh155122  *     int64_t lifc_flags)
   1670   3448   dh155122  *
   1671  10616  Sebastien  * It finds all active data links.
   1672   3448   dh155122  *
   1673   3448   dh155122  * It takes in input a pointer to struct lifconf to receive interfaces
   1674   3448   dh155122  * informations, a **char to hold allocated buffer, and a lifc_flags.
   1675   3448   dh155122  *
   1676   3448   dh155122  * Return values:
   1677   3448   dh155122  *  0 = everything OK
   1678   3448   dh155122  * -1 = problem
   1679   3448   dh155122  */
   1680   3448   dh155122 static int
   1681  10616  Sebastien find_all_interfaces(struct lifconf *lifcp, char **buf, int64_t lifc_flags)
   1682   3448   dh155122 {
   1683   3448   dh155122 	unsigned bufsize;
   1684   3448   dh155122 	int n;
   1685   3448   dh155122 	ni_t *nip;
   1686   3448   dh155122 	struct lifreq *lifrp;
   1687   8673  Vasumathi 	dladm_status_t status;
   1688  10616  Sebastien 
   1689  10616  Sebastien 	if (!dlh_opened) {
   1690  10616  Sebastien 		status = ifconfig_dladm_open(NULL, 0, NULL);
   1691  10616  Sebastien 		if (status != DLADM_STATUS_OK)
   1692  10616  Sebastien 			dladmerr_exit(status, "unable to open dladm handle");
   1693  10616  Sebastien 	}
   1694  10616  Sebastien 
   1695  10616  Sebastien 	(void) dlpi_walk(ni_entry, dlh, 0);
   1696  10616  Sebastien 
   1697  10616  Sebastien 	/* Now, translate the linked list into a struct lifreq buffer */
   1698   3448   dh155122 	if (num_ni == 0) {
   1699   3448   dh155122 		lifcp->lifc_family = AF_UNSPEC;
   1700   3448   dh155122 		lifcp->lifc_flags = lifc_flags;
   1701   3448   dh155122 		lifcp->lifc_len = 0;
   1702   3448   dh155122 		lifcp->lifc_buf = NULL;
   1703   3448   dh155122 		return (0);
   1704   3448   dh155122 	}
   1705   3448   dh155122 
   1706   3448   dh155122 	bufsize = num_ni * sizeof (struct lifreq);
   1707   3448   dh155122 	if ((*buf = malloc(bufsize)) == NULL)
   1708   3448   dh155122 		Perror0_exit("find_all_interfaces: malloc failed");
   1709   3448   dh155122 
   1710   3448   dh155122 	lifcp->lifc_family = AF_UNSPEC;
   1711   3448   dh155122 	lifcp->lifc_flags = lifc_flags;
   1712   3448   dh155122 	lifcp->lifc_len = bufsize;
   1713   3448   dh155122 	lifcp->lifc_buf = *buf;
   1714   3448   dh155122 
   1715   3448   dh155122 	for (n = 0, lifrp = lifcp->lifc_req; n < num_ni; n++, lifrp++) {
   1716   3448   dh155122 		nip = ni_list;
   1717   3448   dh155122 		(void) strncpy(lifrp->lifr_name, nip->ni_name,
   1718   3448   dh155122 		    sizeof (lifr.lifr_name));
   1719   3448   dh155122 		ni_list = nip->ni_next;
   1720   3448   dh155122 		free(nip);
   1721   3448   dh155122 	}
   1722   3448   dh155122 	return (0);
   1723   3448   dh155122 }
   1724   3448   dh155122 
   1725   3448   dh155122 /*
   1726      0     stevel  * Create the next unused logical interface using the original name
   1727      0     stevel  * and assign the address (and mask if '/<n>' is part of the address).
   1728      0     stevel  * Use the new logical interface for subsequent subcommands by updating
   1729      0     stevel  * the name variable.
   1730      0     stevel  *
   1731      0     stevel  * This allows syntax like:
   1732      0     stevel  *	ifconfig le0 addif 109.106.86.130 netmask + up \
   1733      0     stevel  *	addif 109.106.86.131 netmask + up
   1734      0     stevel  */
   1735      0     stevel /* ARGSUSED */
   1736      0     stevel static int
   1737      0     stevel addif(char *str, int64_t param)
   1738      0     stevel {
   1739      0     stevel 	int prefixlen = 0;
   1740      0     stevel 	struct sockaddr_storage laddr;
   1741      0     stevel 	struct sockaddr_storage mask;
   1742      0     stevel 
   1743      0     stevel 	(void) strncpy(name, origname, sizeof (name));
   1744      0     stevel 
   1745      0     stevel 	if (strchr(name, ':') != NULL) {
   1746      0     stevel 		(void) fprintf(stderr,
   1747      0     stevel 		    "ifconfig: addif: bad physical interface name %s\n",
   1748      0     stevel 		    name);
   1749      0     stevel 		exit(1);
   1750      0     stevel 	}
   1751      0     stevel 
   1752      0     stevel 	/*
   1753      0     stevel 	 * clear so parser will interpret next address as source followed
   1754      0     stevel 	 * by possible dest
   1755      0     stevel 	 */
   1756      0     stevel 	setaddr = 0;
   1757      0     stevel 	(*afp->af_getaddr)(str, (struct sockaddr *)&laddr, &prefixlen);
   1758      0     stevel 
   1759      0     stevel 	switch (prefixlen) {
   1760      0     stevel 	case NO_PREFIX:
   1761      0     stevel 		/* Nothing there - ok */
   1762      0     stevel 		break;
   1763      0     stevel 	case BAD_ADDR:
   1764      0     stevel 		(void) fprintf(stderr,
   1765      0     stevel 		    "ifconfig: Bad prefix length in %s\n", str);
   1766      0     stevel 		exit(1);
   1767      0     stevel 	default:
   1768      0     stevel 		(void) memset(&mask, 0, sizeof (mask));
   1769      0     stevel 		mask.ss_family = afp->af_af;
   1770      0     stevel 		if (afp->af_af == AF_INET6) {
   1771      0     stevel 			struct sockaddr_in6 *sin6;
   1772      0     stevel 			sin6 = (struct sockaddr_in6 *)&mask;
   1773   2346       meem 			if (!in_prefixlentomask(prefixlen, IPV6_ABITS,
   1774      0     stevel 			    (uchar_t *)&sin6->sin6_addr)) {
   1775      0     stevel 				(void) fprintf(stderr, "ifconfig: "
   1776      0     stevel 				    "Bad prefix length: %d\n",
   1777      0     stevel 				    prefixlen);
   1778      0     stevel 				exit(1);
   1779      0     stevel 			}
   1780      0     stevel 		} else {
   1781      0     stevel 			struct sockaddr_in *sin;
   1782      0     stevel 
   1783      0     stevel 			sin = (struct sockaddr_in *)&mask;
   1784   2346       meem 			if (!in_prefixlentomask(prefixlen, IP_ABITS,
   1785      0     stevel 			    (uchar_t *)&sin->sin_addr)) {
   1786      0     stevel 				(void) fprintf(stderr, "ifconfig: "
   1787      0     stevel 				    "Bad prefix length: %d\n",
   1788      0     stevel 				    prefixlen);
   1789      0     stevel 				exit(1);
   1790      0     stevel 			}
   1791      0     stevel 		}
   1792    198     kcpoon 		g_netmask_set = G_NETMASK_NIL;
   1793    198     kcpoon 		break;
   1794    198     kcpoon 	}
   1795    198     kcpoon 
   1796    198     kcpoon 	/*
   1797    198     kcpoon 	 * This is a "hack" to get around the problem of SIOCLIFADDIF.  The
   1798    198     kcpoon 	 * problem is that this ioctl does not include the netmask when
   1799    198     kcpoon 	 * adding a logical interface.  This is the same problem described
   1800    198     kcpoon 	 * in the ifconfig() comments.  To get around this problem, we first
   1801    198     kcpoon 	 * add the logical interface with a 0 address.  After that, we set
   1802    198     kcpoon 	 * the netmask if provided.  Finally we set the interface address.
   1803    198     kcpoon 	 */
   1804    198     kcpoon 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   1805    198     kcpoon 	(void) memset(&lifr.lifr_addr, 0, sizeof (lifr.lifr_addr));
   1806      0     stevel 
   1807      0     stevel 	/* Note: no need to do DAD here since the interface isn't up yet. */
   1808      0     stevel 
   1809      0     stevel 	if (ioctl(s, SIOCLIFADDIF, (caddr_t)&lifr) < 0)
   1810      0     stevel 		Perror0_exit("addif: SIOCLIFADDIF");
   1811      0     stevel 
   1812      0     stevel 	(void) printf("Created new logical interface %s\n",
   1813      0     stevel 	    lifr.lifr_name);
   1814      0     stevel 	(void) strncpy(name, lifr.lifr_name, sizeof (name));
   1815      0     stevel 
   1816    198     kcpoon 	/*
   1817    198     kcpoon 	 * Check and see if any "netmask" command is used and perform the
   1818    198     kcpoon 	 * necessary operation.
   1819    198     kcpoon 	 */
   1820    198     kcpoon 	set_mask_lifreq(&lifr, &laddr, &mask);
   1821    198     kcpoon 	/*
   1822    198     kcpoon 	 * Only set the netmask if "netmask" command is used or a prefix is
   1823    198     kcpoon 	 * provided.
   1824    198     kcpoon 	 */
   1825    198     kcpoon 	if (g_netmask_set == G_NETMASK_SET || prefixlen >= 0) {
   1826      0     stevel 		if (ioctl(s, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0)
   1827      0     stevel 			Perror0_exit("addif: SIOCSLIFNETMASK");
   1828      0     stevel 	}
   1829    198     kcpoon 
   1830    198     kcpoon 	/* Finally, we set the interface address. */
   1831    198     kcpoon 	lifr.lifr_addr = laddr;
   1832    198     kcpoon 	if (ioctl(s, SIOCSLIFADDR, (caddr_t)&lifr) < 0)
   1833    198     kcpoon 		Perror0_exit("SIOCSLIFADDR");
   1834    198     kcpoon 
   1835      0     stevel 	/*
   1836      0     stevel 	 * let parser know we got a source.
   1837      0     stevel 	 * Next address, if given, should be dest
   1838      0     stevel 	 */
   1839      0     stevel 	setaddr++;
   1840      0     stevel 	return (0);
   1841      0     stevel }
   1842      0     stevel 
   1843      0     stevel /*
   1844      0     stevel  * Remove a logical interface based on its IP address. Unlike addif
   1845      0     stevel  * there is no '/<n>' here.
   1846      0     stevel  * Verifies that the interface is down before it is removed.
   1847      0     stevel  */
   1848      0     stevel /* ARGSUSED */
   1849      0     stevel static int
   1850      0     stevel removeif(char *str, int64_t param)
   1851      0     stevel {
   1852      0     stevel 	struct sockaddr_storage laddr;
   1853      0     stevel 
   1854      0     stevel 	if (strchr(name, ':') != NULL) {
   1855      0     stevel 		(void) fprintf(stderr,
   1856      0     stevel 		    "ifconfig: removeif: bad physical interface name %s\n",
   1857      0     stevel 		    name);
   1858      0     stevel 		exit(1);
   1859      0     stevel 	}
   1860      0     stevel 
   1861      0     stevel 	(*afp->af_getaddr)(str, &laddr, NULL);
   1862      0     stevel 	lifr.lifr_addr = laddr;
   1863      0     stevel 
   1864      0     stevel 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   1865      0     stevel 	if (ioctl(s, SIOCLIFREMOVEIF, (caddr_t)&lifr) < 0) {
   1866      0     stevel 		if (errno == EBUSY) {
   1867      0     stevel 			/* This can only happen if ipif_id = 0 */
   1868      0     stevel 			(void) fprintf(stderr,
   1869      0     stevel 			    "ifconfig: removeif: can't remove interface: %s\n",
   1870      0     stevel 			    name);
   1871      0     stevel 			exit(1);
   1872      0     stevel 		}
   1873      0     stevel 		Perror0_exit("removeif: SIOCLIFREMOVEIF");
   1874      0     stevel 	}
   1875      0     stevel 	return (0);
   1876      0     stevel }
   1877      0     stevel 
   1878      0     stevel /*
   1879      0     stevel  * Set the address token for IPv6.
   1880      0     stevel  */
   1881      0     stevel /* ARGSUSED */
   1882      0     stevel static int
   1883      0     stevel setiftoken(char *addr, int64_t param)
   1884      0     stevel {
   1885      0     stevel 	int prefixlen = 0;
   1886      0     stevel 	struct sockaddr_in6 token;
   1887      0     stevel 
   1888      0     stevel 	in6_getaddr(addr, (struct sockaddr *)&token, &prefixlen);
   1889      0     stevel 	switch (prefixlen) {
   1890      0     stevel 	case NO_PREFIX:
   1891      0     stevel 		(void) fprintf(stderr,
   1892      0     stevel 		    "ifconfig: Missing prefix length in subnet %s\n", addr);
   1893      0     stevel 		exit(1);
   1894      0     stevel 		/* NOTREACHED */
   1895      0     stevel 	case BAD_ADDR:
   1896      0     stevel 		(void) fprintf(stderr,
   1897      0     stevel 		    "ifconfig: Bad prefix length in %s\n", addr);
   1898      0     stevel 		exit(1);
   1899      0     stevel 	default:
   1900      0     stevel 		break;
   1901      0     stevel 	}
   1902      0     stevel 	(void) memcpy(&lifr.lifr_addr, &token, sizeof (token));
   1903      0     stevel 	lifr.lifr_addrlen = prefixlen;
   1904      0     stevel 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   1905      0     stevel 	if (ioctl(s, SIOCSLIFTOKEN, (caddr_t)&lifr) < 0)  {
   1906      0     stevel 		Perror0_exit("setiftoken: SIOCSLIFTOKEN");
   1907      0     stevel 	}
   1908      0     stevel 	return (0);
   1909      0     stevel }
   1910      0     stevel 
   1911   8485      Peter /* ARGSUSED */
   1912   8485      Peter static int
   1913   8485      Peter setifgroupname(char *grname, int64_t param)
   1914   8485      Peter {
   1915   8485      Peter 	lifgroupinfo_t		lifgr;
   1916   8485      Peter 	struct lifreq		lifrl;
   1917   8485      Peter 	ifaddrlistx_t		*ifaddrp, *nextifaddrp;
   1918   8485      Peter 	ifaddrlistx_t		*ifaddrs = NULL, *downaddrs = NULL;
   1919   8485      Peter 	int			af;
   1920   8485      Peter 
   1921      0     stevel 	if (debug) {
   1922      0     stevel 		(void) printf("Setting groupname %s on interface %s\n",
   1923   8485      Peter 		    grname, name);
   1924   8485      Peter 	}
   1925   8485      Peter 
   1926   8485      Peter 	(void) strlcpy(lifrl.lifr_name, name, LIFNAMSIZ);
   1927   8485      Peter 	(void) strlcpy(lifrl.lifr_groupname, grname, LIFGRNAMSIZ);
   1928   8485      Peter 
   1929   8485      Peter 	while (ioctl(s, SIOCSLIFGROUPNAME, &lifrl) == -1) {
   1930   8485      Peter 		switch (errno) {
   1931   8485      Peter 		case ENOENT:
   1932   8485      Peter 			/*
   1933   8485      Peter 			 * The group doesn't yet exist; create it and repeat.
   1934   8485      Peter 			 */
   1935   8485      Peter 			af = afp->af_af;
   1936   8485      Peter 			if (create_ipmp(grname, af, NULL, _B_TRUE) == -1) {
   1937   8485      Peter 				if (errno == EEXIST)
   1938   8485      Peter 					continue;
   1939   8485      Peter 
   1940   8485      Peter 				Perror2(grname, "cannot create IPMP group");
   1941   8485      Peter 				goto fail;
   1942   8485      Peter 			}
   1943   8485      Peter 			continue;
   1944   8485      Peter 
   1945   8485      Peter 		case EALREADY:
   1946   8485      Peter 			/*
   1947   8485      Peter 			 * The interface is already in another group; must
   1948   8485      Peter 			 * remove existing membership first.
   1949   8485      Peter 			 */
   1950   8485      Peter 			lifrl.lifr_groupname[0] = '\0';
   1951   8485      Peter 			if (ioctl(s, SIOCSLIFGROUPNAME, &lifrl) == -1) {
   1952   8485      Peter 				Perror2(name, "cannot remove existing "
   1953   8485      Peter 				    "IPMP group membership");
   1954   8485      Peter 				goto fail;
   1955   8485      Peter 			}
   1956   8485      Peter 			(void) strlcpy(lifrl.lifr_groupname, grname,
   1957   8485      Peter 			    LIFGRNAMSIZ);
   1958   8485      Peter 			continue;
   1959   8485      Peter 
   1960   8485      Peter 		case EAFNOSUPPORT:
   1961   8485      Peter 			/*
   1962   8485      Peter 			 * The group exists, but it's not configured with the
   1963   8485      Peter 			 * address families the interface needs.  Since only
   1964   8485      Peter 			 * two address families are currently supported, just
   1965   8485      Peter 			 * configure the "other" address family.  Note that we
   1966   8485      Peter 			 * may race with group deletion or creation by another
   1967   8485      Peter 			 * process (ENOENT or EEXIST); in such cases we repeat
   1968   8485      Peter 			 * our original SIOCSLIFGROUPNAME.
   1969   8485      Peter 			 */
   1970   8485      Peter 			(void) strlcpy(lifgr.gi_grname, grname, LIFGRNAMSIZ);
   1971   8485      Peter 			if (ioctl(s, SIOCGLIFGROUPINFO, &lifgr) == -1) {
   1972   8485      Peter 				if (errno == ENOENT)
   1973   8485      Peter 					continue;
   1974   8485      Peter 
   1975   8485      Peter 				Perror2(grname, "SIOCGLIFGROUPINFO");
   1976   8485      Peter 				goto fail;
   1977   8485      Peter 			}
   1978   8485      Peter 
   1979   8485      Peter 			af = lifgr.gi_v4 ? AF_INET6 : AF_INET;
   1980   8485      Peter 			if (create_ipmp(grname, af, lifgr.gi_grifname,
   1981   8485      Peter 			    _B_TRUE) == -1) {
   1982   8485      Peter 				if (errno == EEXIST)
   1983   8485      Peter 					continue;
   1984   8485      Peter 
   1985   8485      Peter 				Perror2(grname, "cannot configure IPMP group");
   1986   8485      Peter 				goto fail;
   1987   8485      Peter 			}
   1988   8485      Peter 			continue;
   1989   8485      Peter 
   1990   8485      Peter 		case EADDRINUSE:
   1991   8485      Peter 			/*
   1992   8485      Peter 			 * Some addresses are in-use (or under control of DAD).
   1993   8485      Peter 			 * Bring them down and retry the group join operation.
   1994   8485      Peter 			 * We will bring them back up after the interface has
   1995   8485      Peter 			 * been placed in the group.
   1996   8485      Peter 			 */
   1997   8485      Peter 			if (ifaddrlistx(lifrl.lifr_name, IFF_UP|IFF_DUPLICATE,
   1998   8485      Peter 			    0, &ifaddrs) == -1) {
   1999   8485      Peter 				Perror2(grname, "cannot get address list");
   2000   8485      Peter 				goto fail;
   2001   8485      Peter 			}
   2002   8485      Peter 
   2003   8485      Peter 			ifaddrp = ifaddrs;
   2004   8485      Peter 			for (; ifaddrp != NULL; ifaddrp = nextifaddrp) {
   2005   8485      Peter 				if (!ifaddr_down(ifaddrp)) {
   2006   8485      Peter 					ifaddrs = ifaddrp;
   2007   8485      Peter 					goto fail;
   2008   8485      Peter 				}
   2009   8485      Peter 				nextifaddrp = ifaddrp->ia_next;
   2010   8485      Peter 				ifaddrp->ia_next = downaddrs;
   2011   8485      Peter 				downaddrs = ifaddrp;
   2012   8485      Peter 			}
   2013   8485      Peter 			ifaddrs = NULL;
   2014   8485      Peter 			continue;
   2015   8485      Peter 
   2016   8485      Peter 		case EADDRNOTAVAIL: {
   2017   8485      Peter 			/*
   2018   8485      Peter 			 * Some data addresses are under application control.
   2019   8485      Peter 			 * For some of these (e.g., ADDRCONF), the application
   2020   8485      Peter 			 * should remove the address, in which case we retry a
   2021   8485      Peter 			 * few times (since the application's action is not
   2022   8485      Peter 			 * atomic with respect to us) before bailing out and
   2023   8485      Peter 			 * informing the user.
   2024   8485      Peter 			 */
   2025   8485      Peter 			int ntries, nappaddr = 0;
   2026   8485      Peter 			const if_appflags_t *iap = if_appflags_tbl;
   2027   8485      Peter 
   2028   8485      Peter 			for (; iap->ia_app != NULL; iap++) {
   2029   8485      Peter 				ntries = 0;
   2030   8485      Peter again:
   2031   8485      Peter 				if (ifaddrlistx(lifrl.lifr_name, iap->ia_flag,
   2032   8485      Peter 				    IFF_NOFAILOVER, &ifaddrs) == -1) {
   2033   8485      Peter 					(void) fprintf(stderr, "ifconfig: %s: "
   2034   8485      Peter 					    "cannot get data addresses managed "
   2035   8485      Peter 					    "by %s\n", lifrl.lifr_name,
   2036   8485      Peter 					    iap->ia_app);
   2037   8485      Peter 					goto fail;
   2038   8485      Peter 				}
   2039   8485      Peter 
   2040   8485      Peter 				if (ifaddrs == NULL)
   2041   8485      Peter 					continue;
   2042   8485      Peter 
   2043   8485      Peter 				ifaddrlistx_free(ifaddrs);
   2044   8485      Peter 				ifaddrs = NULL;
   2045   8485      Peter 
   2046   8485      Peter 				if (++ntries < iap->ia_tries) {
   2047   8485      Peter 					(void) poll(NULL, 0, 100);
   2048   8485      Peter 					goto again;
   2049   8485      Peter 				}
   2050   8485      Peter 
   2051   8485      Peter 				(void) fprintf(stderr, "ifconfig: cannot join "
   2052   8485      Peter 				    "IPMP group: %s has data addresses managed "
   2053   8485      Peter 				    "by %s\n", lifrl.lifr_name, iap->ia_app);
   2054   8485      Peter 				nappaddr++;
   2055   8485      Peter 			}
   2056   8485      Peter 			if (nappaddr > 0)
   2057   8485      Peter 				goto fail;
   2058   8485      Peter 			continue;
   2059   8485      Peter 		}
   2060   8485      Peter 		default:
   2061   8485      Peter 			Perror2(name, "SIOCSLIFGROUPNAME");
   2062   8485      Peter 			goto fail;
   2063   8485      Peter 		}
   2064   8485      Peter 	}
   2065   8485      Peter 
   2066   8485      Peter 	/*
   2067   8485      Peter 	 * If there were addresses that we had to bring down, it's time to
   2068   8485      Peter 	 * bring them up again.  As part of bringing them up, the kernel will
   2069   8485      Peter 	 * automatically move them to the new IPMP interface.
   2070   8485      Peter 	 */
   2071   8485      Peter 	for (ifaddrp = downaddrs; ifaddrp != NULL; ifaddrp = ifaddrp->ia_next) {
   2072   8485      Peter 		if (!ifaddr_up(ifaddrp) && errno != ENXIO) {
   2073   8485      Peter 			(void) fprintf(stderr, "ifconfig: cannot bring back up "
   2074   8485      Peter 			    "%s: %s\n", ifaddrp->ia_name, strerror(errno));
   2075   8485      Peter 		}
   2076   8485      Peter 	}
   2077   8485      Peter 	ifaddrlistx_free(downaddrs);
   2078   8485      Peter 	return (0);
   2079   8485      Peter fail:
   2080   8485      Peter 	/*
   2081   8485      Peter 	 * Attempt to bring back up any interfaces that we downed.
   2082   8485      Peter 	 */
   2083   8485      Peter 	for (ifaddrp = downaddrs; ifaddrp != NULL; ifaddrp = ifaddrp->ia_next) {
   2084   8485      Peter 		if (!ifaddr_up(ifaddrp) && errno != ENXIO) {
   2085   8485      Peter 			(void) fprintf(stderr, "ifconfig: cannot bring back up "
   2086   8485      Peter 			    "%s: %s\n", ifaddrp->ia_name, strerror(errno));
   2087   8485      Peter 		}
   2088   8485      Peter 	}
   2089   8485      Peter 	ifaddrlistx_free(downaddrs);
   2090   8485      Peter 	ifaddrlistx_free(ifaddrs);
   2091   8485      Peter 
   2092   8485      Peter 	/*
   2093   8485      Peter 	 * We'd return -1, but foreachinterface() doesn't propagate the error
   2094   8485      Peter 	 * into the exit status, so we're forced to explicitly exit().
   2095   8485      Peter 	 */
   2096   8485      Peter 	exit(1);
   2097   8485      Peter 	/* NOTREACHED */
   2098   8485      Peter }
   2099   8485      Peter 
   2100   8485      Peter static boolean_t
   2101   8485      Peter modcheck(const char *ifname)
   2102   8485      Peter {
   2103   8485      Peter 	(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
   2104   8485      Peter 
   2105   8485      Peter 	if (ioctl(s, SIOCGLIFFLAGS, &lifr) < 0) {
   2106   8485      Peter 		Perror0("SIOCGLIFFLAGS");
   2107   8485      Peter 		return (_B_FALSE);
   2108   8485      Peter 	}
   2109   8485      Peter 
   2110   8485      Peter 	if (lifr.lifr_flags & IFF_IPMP) {
   2111   8485      Peter 		(void) fprintf(stderr, "ifconfig: %s: module operations not"
   2112   8485      Peter 		    " supported on IPMP interfaces\n", ifname);
   2113   8485      Peter 		return (_B_FALSE);
   2114   8485      Peter 	}
   2115   8485      Peter 	if (lifr.lifr_flags & IFF_VIRTUAL) {
   2116   8485      Peter 		(void) fprintf(stderr, "ifconfig: %s: module operations not"
   2117   8485      Peter 		    " supported on virtual IP interfaces\n", ifname);
   2118   8485      Peter 		return (_B_FALSE);
   2119   8485      Peter 	}
   2120   8485      Peter 	return (_B_TRUE);
   2121   8485      Peter }
   2122      0     stevel 
   2123      0     stevel /*
   2124      0     stevel  * To list all the modules above a given network interface.
   2125      0     stevel  */
   2126      0     stevel /* ARGSUSED */
   2127      0     stevel static int
   2128      0     stevel modlist(char *null, int64_t param)
   2129      0     stevel {
   2130   5240   nordmark 	int muxid_fd;
   2131      0     stevel 	int muxfd;
   2132      0     stevel 	int ipfd_lowstr;
   2133      0     stevel 	int arpfd_lowstr;
   2134      0     stevel 	int num_mods;
   2135      0     stevel 	int i;
   2136      0     stevel 	struct str_list strlist;
   2137      0     stevel 	int orig_arpid;
   2138      0     stevel 
   2139   8485      Peter 	/*
   2140   8485      Peter 	 * We'd return -1, but foreachinterface() doesn't propagate the error
   2141   8485      Peter 	 * into the exit status, so we're forced to explicitly exit().
   2142   8485      Peter 	 */
   2143   8485      Peter 	if (!modcheck(name))
   2144   8485      Peter 		exit(1);
   2145   8485      Peter 
   2146   5240   nordmark 	if (ip_domux2fd(&muxfd, &muxid_fd, &ipfd_lowstr, &arpfd_lowstr,
   2147      0     stevel 	    &orig_arpid) < 0) {
   2148      0     stevel 		return (-1);
   2149      0     stevel 	}
   2150      0     stevel 	if ((num_mods = ioctl(ipfd_lowstr, I_LIST, NULL)) < 0) {
   2151      0     stevel 		Perror0("cannot I_LIST to get the number of modules");
   2152      0     stevel 	} else {
   2153      0     stevel 		if (debug > 0) {
   2154      0     stevel 			(void) printf("Listing (%d) modules above %s\n",
   2155      0     stevel 			    num_mods, name);
   2156      0     stevel 		}
   2157      0     stevel 
   2158      0     stevel 		strlist.sl_nmods = num_mods;
   2159      0     stevel 		strlist.sl_modlist = malloc(sizeof (struct str_mlist) *
   2160      0     stevel 		    num_mods);
   2161      0     stevel 		if (strlist.sl_modlist == NULL) {
   2162      0     stevel 			Perror0("cannot malloc");
   2163      0     stevel 		} else {
   2164      0     stevel 			if (ioctl(ipfd_lowstr, I_LIST, (caddr_t)&strlist) < 0) {
   2165      0     stevel 				Perror0("cannot I_LIST for module names");
   2166      0     stevel 			} else {
   2167      0     stevel 				for (i = 0; i < strlist.sl_nmods; i++) {
   2168   5240   nordmark 					(void) printf("%d %s\n", i,
   2169   5240   nordmark 					    strlist.sl_modlist[i].l_name);
   2170      0     stevel 				}
   2171      0     stevel 			}
   2172      0     stevel 			free(strlist.sl_modlist);
   2173      0     stevel 		}
   2174      0     stevel 	}
   2175   5240   nordmark 	return (ip_plink(muxfd, muxid_fd, ipfd_lowstr, arpfd_lowstr,
   2176   5240   nordmark 	    orig_arpid));
   2177      0     stevel }
   2178      0     stevel 
   2179      0     stevel #define	MODINSERT_OP	'i'
   2180      0     stevel #define	MODREMOVE_OP	'r'
   2181      0     stevel 
   2182      0     stevel /*
   2183      0     stevel  * To insert a module to the stream of the interface.  It is just a
   2184      0     stevel  * wrapper.  The real function is modop().
   2185      0     stevel  */
   2186      0     stevel /* ARGSUSED */
   2187      0     stevel static int
   2188      0     stevel modinsert(char *arg, int64_t param)
   2189      0     stevel {
   2190      0     stevel 	return (modop(arg, MODINSERT_OP));
   2191      0     stevel }
   2192      0     stevel 
   2193      0     stevel /*
   2194      0     stevel  * To remove a module from the stream of the interface.  It is just a
   2195      0     stevel  * wrapper.  The real function is modop().
   2196      0     stevel  */
   2197      0     stevel /* ARGSUSED */
   2198      0     stevel static int
   2199      0     stevel modremove(char *arg, int64_t param)
   2200      0     stevel {
   2201      0     stevel 	return (modop(arg, MODREMOVE_OP));
   2202      0     stevel }
   2203      0     stevel 
   2204      0     stevel /*
   2205   5240   nordmark  * Open a stream on /dev/udp{,6}, pop off all undesired modules (note that
   2206   5240   nordmark  * the user may have configured autopush to add modules above
   2207   5240   nordmark  * udp), and push the arp module onto the resulting stream.
   2208   5240   nordmark  * This is used to make IP+ARP be able to atomically track the muxid
   2209   5240   nordmark  * for the I_PLINKed STREAMS, thus it isn't related to ARP running the ARP
   2210   5240   nordmark  * protocol.
   2211      0     stevel  */
   2212      0     stevel static int
   2213      0     stevel open_arp_on_udp(char *udp_dev_name)
   2214      0     stevel {
   2215      0     stevel 	int fd;
   2216      0     stevel 
   2217      0     stevel 	if ((fd = open(udp_dev_name, O_RDWR)) == -1) {
   2218      0     stevel 		Perror2("open", udp_dev_name);
   2219      0     stevel 		return (-1);
   2220      0     stevel 	}
   2221      0     stevel 	errno = 0;
   2222      0     stevel 	while (ioctl(fd, I_POP, 0) != -1)
   2223   5240   nordmark 		;
   2224   5240   nordmark 	if (errno != EINVAL) {
   2225      0     stevel 		Perror2("pop", udp_dev_name);
   2226      0     stevel 	} else if (ioctl(fd, I_PUSH, ARP_MOD_NAME) == -1) {
   2227      0     stevel 		Perror2("arp PUSH", udp_dev_name);
   2228      0     stevel 	} else {
   2229      0     stevel 		return (fd);
   2230      0     stevel 	}
   2231      0     stevel 	(void) close(fd);
   2232      0     stevel 	return (-1);
   2233      0     stevel }
   2234      0     stevel 
   2235      0     stevel /*
   2236      0     stevel  * Helper function for mod*() functions.  It gets a fd to the lower IP
   2237      0     stevel  * stream and I_PUNLINK's the lower stream.  It also initializes the
   2238      0     stevel  * global variable lifr.
   2239      0     stevel  *
   2240      0     stevel  * Param:
   2241   5240   nordmark  *	int *muxfd: fd to /dev/udp{,6} for I_PLINK/I_PUNLINK
   2242   5240   nordmark  *	int *muxid_fd: fd to /dev/udp{,6} for LIFMUXID
   2243   5240   nordmark  *	int *ipfd_lowstr: fd to the lower IP stream.
   2244   5240   nordmark  *	int *arpfd_lowstr: fd to the lower ARP stream.
   2245      0     stevel  *
   2246      0     stevel  * Return:
   2247      0     stevel  *	-1 if operation fails, 0 otherwise.
   2248      0     stevel  *
   2249   8485      Peter  * Please see the big block comment above ifplumb() for the logic of the
   2250   8485      Peter  * PLINK/PUNLINK
   2251      0     stevel  */
   2252      0     stevel static int
   2253   5240   nordmark ip_domux2fd(int *muxfd, int *muxid_fd, int *ipfd_lowstr, int *arpfd_lowstr,
   2254   5240   nordmark     int *orig_arpid)
   2255   5240   nordmark {
   2256      0     stevel 	uint64_t	flags;
   2257      0     stevel 	char		*udp_dev_name;
   2258      0     stevel 
   2259      0     stevel 	*orig_arpid = 0;
   2260      0     stevel 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   2261      0     stevel 	if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
   2262      0     stevel 		Perror0_exit("status: SIOCGLIFFLAGS");
   2263      0     stevel 	}
   2264      0     stevel 	flags = lifr.lifr_flags;
   2265      0     stevel 	if (flags & IFF_IPV4) {
   2266      0     stevel 		udp_dev_name = UDP_DEV_NAME;
   2267      0     stevel 	} else if (flags & IFF_IPV6) {
   2268      0     stevel 		udp_dev_name = UDP6_DEV_NAME;
   2269   5240   nordmark 	} else {
   2270   5240   nordmark 		return (-1);
   2271   5240   nordmark 	}
   2272   5240   nordmark 
   2273   5240   nordmark 	if ((*muxid_fd = open(udp_dev_name, O_RDWR)) < 0) {
   2274   5240   nordmark 		Perror2("open", udp_dev_name);
   2275   5240   nordmark 		return (-1);
   2276   5240   nordmark 	}
   2277   5240   nordmark 	if (ioctl(*muxid_fd, SIOCGLIFMUXID, (caddr_t)&lifr) < 0) {
   2278   5240   nordmark 		Perror2("SIOCGLIFMUXID", udp_dev_name);
   2279      0     stevel 		return (-1);
   2280      0     stevel 	}
   2281      0     stevel 	if (debug > 0) {
   2282      0     stevel 		(void) printf("ARP_muxid %d IP_muxid %d\n",
   2283      0     stevel 		    lifr.lifr_arp_muxid, lifr.lifr_ip_muxid);
   2284      0     stevel 	}
   2285      0     stevel 
   2286   5240   nordmark 	/*
   2287   5240   nordmark 	 * Use /dev/udp{,6} as the mux to avoid linkcycles.
   2288   5240   nordmark 	 */
   2289      0     stevel 	if ((*muxfd = open_arp_on_udp(udp_dev_name)) == -1)
   2290      0     stevel 		return (-1);
   2291      0     stevel 
   2292      0     stevel 	if (lifr.lifr_arp_muxid != 0) {
   2293      0     stevel 		if ((*arpfd_lowstr = ioctl(*muxfd, _I_MUXID2FD,
   2294      0     stevel 		    lifr.lifr_arp_muxid)) < 0) {
   2295      0     stevel 			if ((errno == EINVAL) &&
   2296      0     stevel 			    (flags & (IFF_NOARP | IFF_IPV6))) {
   2297      0     stevel 				/*
   2298      0     stevel 				 * Some plumbing utilities set the muxid to
   2299      0     stevel 				 * -1 or some invalid value to signify that
   2300      0     stevel 				 * there is no arp stream. Set the muxid to 0
   2301      0     stevel 				 * before trying to unplumb the IP stream.
   2302      0     stevel 				 * IP does not allow the IP stream to be
   2303      0     stevel 				 * unplumbed if it sees a non-null arp muxid,
   2304      0     stevel 				 * for consistency of IP-ARP streams.
   2305      0     stevel 				 */
   2306      0     stevel 				*orig_arpid = lifr.lifr_arp_muxid;
   2307      0     stevel 				lifr.lifr_arp_muxid = 0;
   2308   5240   nordmark 				(void) ioctl(*muxid_fd, SIOCSLIFMUXID,
   2309      0     stevel 				    (caddr_t)&lifr);
   2310      0     stevel 				*arpfd_lowstr = -1;
   2311      0     stevel 			} else {
   2312      0     stevel 				Perror0("_I_MUXID2FD");
   2313      0     stevel 				return (-1);
   2314      0     stevel 			}
   2315      0     stevel 		} else if (ioctl(*muxfd, I_PUNLINK,
   2316      0     stevel 		    lifr.lifr_arp_muxid) < 0) {
   2317      0     stevel 			Perror2("I_PUNLINK", udp_dev_name);
   2318      0     stevel 			return (-1);
   2319      0     stevel 		}
   2320      0     stevel 	} else {
   2321      0     stevel 		*arpfd_lowstr = -1;
   2322      0     stevel 	}
   2323      0     stevel 
   2324      0     stevel 	if ((*ipfd_lowstr = ioctl(*muxfd, _I_MUXID2FD,
   2325      0     stevel 	    lifr.lifr_ip_muxid)) < 0) {
   2326      0     stevel 		Perror0("_I_MUXID2FD");
   2327      0     stevel 		/* Undo any changes we made */
   2328      0     stevel 		if (*orig_arpid != 0) {
   2329      0     stevel 			lifr.lifr_arp_muxid = *orig_arpid;
   2330   5240   nordmark 			(void) ioctl(*muxid_fd, SIOCSLIFMUXID, (caddr_t)&lifr);
   2331      0     stevel 		}
   2332      0     stevel 		return (-1);
   2333      0     stevel 	}
   2334      0     stevel 	if (ioctl(*muxfd, I_PUNLINK, lifr.lifr_ip_muxid) < 0) {
   2335      0     stevel 		Perror2("I_PUNLINK", udp_dev_name);
   2336      0     stevel 		/* Undo any changes we made */
   2337      0     stevel 		if (*orig_arpid != 0) {
   2338      0     stevel 			lifr.lifr_arp_muxid = *orig_arpid;
   2339   5240   nordmark 			(void) ioctl(*muxid_fd, SIOCSLIFMUXID, (caddr_t)&lifr);
   2340      0     stevel 		}
   2341      0     stevel 		return (-1);
   2342      0     stevel 	}
   2343      0     stevel 	return (0);
   2344      0     stevel }
   2345      0     stevel 
   2346      0     stevel /*
   2347      0     stevel  * Helper function for mod*() functions.  It I_PLINK's back the upper and
   2348      0     stevel  * lower IP streams.  Note that this function must be called after
   2349      0     stevel  * ip_domux2fd().  In ip_domux2fd(), the global variable lifr is initialized
   2350      0     stevel  * and ip_plink() needs information in lifr.  So ip_domux2fd() and ip_plink()
   2351      0     stevel  * must be called in pairs.
   2352      0     stevel  *
   2353      0     stevel  * Param:
   2354   5240   nordmark  *	int muxfd: fd to /dev/udp{,6} for I_PLINK/I_PUNLINK
   2355   5240   nordmark  *	int muxid_fd: fd to /dev/udp{,6} for LIFMUXID
   2356   5240   nordmark  *	int ipfd_lowstr: fd to the lower IP stream.
   2357   5240   nordmark  *	int arpfd_lowstr: fd to the lower ARP stream.
   2358      0     stevel  *
   2359      0     stevel  * Return:
   2360      0     stevel  *	-1 if operation fails, 0 otherwise.
   2361      0     stevel  *
   2362   8485      Peter  * Please see the big block comment above ifplumb() for the logic of the
   2363   8485      Peter  * PLINK/PUNLINK
   2364      0     stevel  */
   2365      0     stevel static int
   2366   5240   nordmark ip_plink(int muxfd, int muxid_fd, int ipfd_lowstr, int arpfd_lowstr,
   2367   5240   nordmark     int orig_arpid)
   2368      0     stevel {
   2369      0     stevel 	int ip_muxid;
   2370      0     stevel 
   2371      0     stevel 	ip_muxid = ioctl(muxfd, I_PLINK, ipfd_lowstr);
   2372      0     stevel 	if (ip_muxid < 0) {
   2373      0     stevel 		Perror2("I_PLINK", UDP_DEV_NAME);
   2374      0     stevel 		return (-1);
   2375      0     stevel 	}
   2376      0     stevel 
   2377      0     stevel 	/*
   2378      0     stevel 	 * If there is an arp stream, plink it. If there is no
   2379      0     stevel 	 * arp stream, then it is possible that the plumbing
   2380      0     stevel 	 * utility could have stored any value in the arp_muxid.
   2381      0     stevel 	 * If so, restore it from orig_arpid.
   2382      0     stevel 	 */
   2383      0     stevel 	if (arpfd_lowstr != -1) {
   2384      0     stevel 		if (ioctl(muxfd, I_PLINK, arpfd_lowstr) < 0) {
   2385      0     stevel 			Perror2("I_PLINK", UDP_DEV_NAME);
   2386      0     stevel 			return (-1);
   2387      0     stevel 		}
   2388      0     stevel 	} else if (orig_arpid != 0) {
   2389      0     stevel 		/* Undo the changes we did in ip_domux2fd */
   2390      0     stevel 		lifr.lifr_arp_muxid = orig_arpid;
   2391      0     stevel 		lifr.lifr_ip_muxid = ip_muxid;
   2392   5240   nordmark 		(void) ioctl(muxid_fd, SIOCSLIFMUXID, (caddr_t)&lifr);
   2393   5240   nordmark 	}
   2394   5240   nordmark 
   2395   5240   nordmark 	(void) close(muxfd);
   2396   5240   nordmark 	(void) close(muxid_fd);
   2397      0     stevel 	return (0);
   2398      0     stevel }
   2399      0     stevel 
   2400      0     stevel /*
   2401      0     stevel  * The real function to perform module insertion/removal.
   2402      0     stevel  *
   2403      0     stevel  * Param:
   2404      0     stevel  *	char *arg: the argument string module_name@position
   2405      0     stevel  *	char op: operation, either MODINSERT_OP or MODREMOVE_OP.
   2406      0     stevel  *
   2407      0     stevel  * Return:
   2408      0     stevel  *	Before doing ip_domux2fd(), this function calls exit(1) in case of
   2409      0     stevel  *	error.  After ip_domux2fd() is done, it returns -1 for error, 0
   2410      0     stevel  *	otherwise.
   2411      0     stevel  */
   2412      0     stevel static int
   2413      0     stevel modop(char *arg, char op)
   2414      0     stevel {
   2415      0     stevel 	char *pos_p;
   2416      0     stevel 	int muxfd;
   2417   5240   nordmark 	int muxid_fd;
   2418      0     stevel 	int ipfd_lowstr;  /* IP stream (lower stream of mux) to be plinked */
   2419      0     stevel 	int arpfd_lowstr; /* ARP stream (lower stream of mux) to be plinked */
   2420      0     stevel 	struct strmodconf mod;
   2421      0     stevel 	char *at_char = "@";
   2422      0     stevel 	char *arg_str;
   2423      0     stevel 	int orig_arpid;
   2424      0     stevel 
   2425   8485      Peter 	/*
   2426   8485      Peter 	 * We'd return -1, but foreachinterface() doesn't propagate the error
   2427   8485      Peter 	 * into the exit status, so we're forced to explicitly exit().
   2428   8485      Peter 	 */
   2429   8485      Peter 	if (!modcheck(name))
   2430   8485      Peter 		exit(1);
   2431      0     stevel 
   2432      0     stevel 	/* Need to save the original string for -a option. */
   2433      0     stevel 	if ((arg_str = malloc(strlen(arg) + 1)) == NULL) {
   2434      0     stevel 		Perror0("cannot malloc");
   2435      0     stevel 		return (-1);
   2436      0     stevel 	}
   2437      0     stevel 	(void) strcpy(arg_str, arg);
   2438      0     stevel 
   2439      0     stevel 	if (*arg_str == *at_char) {
   2440      0     stevel 		(void) fprintf(stderr,
   2441      0     stevel 		    "ifconfig: must supply a module name\n");
   2442      0     stevel 		exit(1);
   2443      0     stevel 	}
   2444      0     stevel 	mod.mod_name = strtok(arg_str, at_char);
   2445      0     stevel 	if (strlen(mod.mod_name) > FMNAMESZ) {
   2446      0     stevel 		(void) fprintf(stderr, "ifconfig: module name too long: %s\n",
   2447      0     stevel 		    mod.mod_name);
   2448      0     stevel 		exit(1);
   2449      0     stevel 	}
   2450      0     stevel 
   2451      0     stevel 	/*
   2452      0     stevel 	 * Need to make sure that the core TCP/IP stack modules are not
   2453      0     stevel 	 * removed.  Otherwise, "bad" things can happen.  If a module
   2454      0     stevel 	 * is removed and inserted back, it loses its old state.  But
   2455      0     stevel 	 * the modules above it still have the old state.  E.g. IP assumes
   2456      0     stevel 	 * fast data path while tunnel after re-inserted assumes that it can
   2457      0     stevel 	 * receive M_DATA only in fast data path for which it does not have
   2458      0     stevel 	 * any state.  This is a general caveat of _I_REMOVE/_I_INSERT.
   2459      0     stevel 	 */
   2460      0     stevel 	if (op == MODREMOVE_OP &&
   2461      0     stevel 	    (strcmp(mod.mod_name, ARP_MOD_NAME) == 0 ||
   2462  10616  Sebastien 	    strcmp(mod.mod_name, IP_MOD_NAME) == 0)) {
   2463      0     stevel 		(void) fprintf(stderr, "ifconfig: cannot remove %s\n",
   2464      0     stevel 		    mod.mod_name);
   2465      0     stevel 		exit(1);
   2466      0     stevel 	}
   2467      0     stevel 
   2468      0     stevel 	if ((pos_p = strtok(NULL, at_char)) == NULL) {
   2469      0     stevel 		(void) fprintf(stderr, "ifconfig: must supply a position\n");
   2470      0     stevel 		exit(1);
   2471      0     stevel 	}
   2472      0     stevel 	mod.pos = atoi(pos_p);
   2473      0     stevel 
   2474   5240   nordmark 	if (ip_domux2fd(&muxfd, &muxid_fd, &ipfd_lowstr, &arpfd_lowstr,
   2475      0     stevel 	    &orig_arpid) < 0) {
   2476      0     stevel 		free(arg_str);
   2477      0     stevel 		return (-1);
   2478      0     stevel 	}
   2479      0     stevel 	switch (op) {
   2480      0     stevel 	case MODINSERT_OP:
   2481      0     stevel 		if (debug > 0) {
   2482      0     stevel 			(void) printf("Inserting module %s at %d\n",
   2483      0     stevel 			    mod.mod_name, mod.pos);
   2484      0     stevel 		}
   2485      0     stevel 		if (ioctl(ipfd_lowstr, _I_INSERT, (caddr_t)&mod) < 0) {
   2486      0     stevel 			Perror2("fail to insert module", mod.mod_name);
   2487      0     stevel 		}
   2488      0     stevel 		break;
   2489      0     stevel 	case MODREMOVE_OP:
   2490      0     stevel 		if (debug > 0) {
   2491      0     stevel 			(void) printf("Removing module %s at %d\n",
   2492      0     stevel 			    mod.mod_name, mod.pos);
   2493      0     stevel 		}
   2494      0     stevel 		if (ioctl(ipfd_lowstr, _I_REMOVE, (caddr_t)&mod) < 0) {
   2495      0     stevel 			Perror2("fail to remove module", mod.mod_name);
   2496      0     stevel 		}
   2497      0     stevel 		break;
   2498      0     stevel 	default:
   2499      0     stevel 		/* Should never get to here. */
   2500      0     stevel 		(void) fprintf(stderr, "Unknown operation\n");
   2501      0     stevel 		break;
   2502      0     stevel 	}
   2503      0     stevel 	free(arg_str);
   2504   5240   nordmark 	return (ip_plink(muxfd, muxid_fd, ipfd_lowstr, arpfd_lowstr,
   2505   5240   nordmark 	    orig_arpid));
   2506      0     stevel }
   2507      0     stevel 
   2508  10616  Sebastien static int
   2509  10616  Sebastien modify_tun(iptun_params_t *params)
   2510  10616  Sebastien {
   2511  10616  Sebastien 	dladm_status_t status;
   2512  10616  Sebastien 
   2513  10616  Sebastien 	if ((status = ifconfig_dladm_open(name, DATALINK_CLASS_IPTUN,
   2514  10616  Sebastien 	    &params->iptun_param_linkid)) == DLADM_STATUS_OK)
   2515  10616  Sebastien 		status = dladm_iptun_modify(dlh, params, DLADM_OPT_ACTIVE);
   2516  10616  Sebastien 	if (status != DLADM_STATUS_OK)
   2517  10616  Sebastien 		dladmerr_exit(status, name);
   2518  10616  Sebastien 	return (0);
   2519  10616  Sebastien }
   2520  10616  Sebastien 
   2521      0     stevel /*
   2522      0     stevel  * Set tunnel source address
   2523      0     stevel  */
   2524      0     stevel /* ARGSUSED */
   2525      0     stevel static int
   2526      0     stevel setiftsrc(char *addr, int64_t param)
   2527      0     stevel {
   2528  10616  Sebastien 	iptun_params_t params;
   2529  10616  Sebastien 
   2530  10616  Sebastien 	params.iptun_param_flags = IPTUN_PARAM_LADDR;
   2531  10616  Sebastien 	(void) strlcpy(params.iptun_param_laddr, addr,
   2532  10616  Sebastien 	    sizeof (params.iptun_param_laddr));
   2533  10616  Sebastien 	return (modify_tun(&params));
   2534      0     stevel }
   2535      0     stevel 
   2536      0     stevel /*
   2537      0     stevel  * Set tunnel destination address
   2538      0     stevel  */
   2539      0     stevel /* ARGSUSED */
   2540      0     stevel static int
   2541      0     stevel setiftdst(char *addr, int64_t param)
   2542      0     stevel {
   2543  10616  Sebastien 	iptun_params_t params;
   2544  10616  Sebastien 
   2545  10616  Sebastien 	params.iptun_param_flags = IPTUN_PARAM_RADDR;
   2546  10616  Sebastien 	(void) strlcpy(params.iptun_param_raddr, addr,
   2547  10616  Sebastien 	    sizeof (params.iptun_param_raddr));
   2548  10616  Sebastien 	return (modify_tun(&params));
   2549  10616  Sebastien }
   2550  10616  Sebastien 
   2551  10616  Sebastien static int
   2552  10616  Sebastien set_tun_prop(const char *propname, char *value)
   2553  10616  Sebastien {
   2554  10616  Sebastien 	dladm_status_t	status;
   2555  10616  Sebastien 	datalink_id_t	linkid;
   2556  10616  Sebastien 
   2557  10616  Sebastien 	status = ifconfig_dladm_open(name, DATALINK_CLASS_IPTUN, &linkid);
   2558  10616  Sebastien 	if (status == DLADM_STATUS_OK) {
   2559  10616  Sebastien 		status = dladm_set_linkprop(dlh, linkid, propname, &value, 1,
   2560  10616  Sebastien 		    DLADM_OPT_ACTIVE);
   2561  10616  Sebastien 	}
   2562  10616  Sebastien 	if (status != DLADM_STATUS_OK)
   2563  10616  Sebastien 		dladmerr_exit(status, name);
   2564      0     stevel 	return (0);
   2565      0     stevel }
   2566      0     stevel 
   2567      0     stevel /* Set tunnel encapsulation limit. */
   2568      0     stevel /* ARGSUSED */
   2569      0     stevel static int
   2570      0     stevel set_tun_encap_limit(char *arg, int64_t param)
   2571      0     stevel {
   2572  10616  Sebastien 	return (set_tun_prop("encaplimit", arg));
   2573      0     stevel }
   2574      0     stevel 
   2575      0     stevel /* Disable encapsulation limit. */
   2576      0     stevel /* ARGSUSED */
   2577      0     stevel static int
   2578      0     stevel clr_tun_encap_limit(char *arg, int64_t param)
   2579      0     stevel {
   2580  10616  Sebastien 	return (set_tun_encap_limit("-1", 0));
   2581      0     stevel }
   2582      0     stevel 
   2583      0     stevel /* Set tunnel hop limit. */
   2584      0     stevel /* ARGSUSED */
   2585      0     stevel static int
   2586      0     stevel set_tun_hop_limit(char *arg, int64_t param)
   2587      0     stevel {
   2588  10616  Sebastien 	return (set_tun_prop("hoplimit", arg));
   2589      0     stevel }
   2590      0     stevel 
   2591      0     stevel /* Set zone ID */
   2592      0     stevel static int
   2593      0     stevel setzone(char *arg, int64_t param)
   2594      0     stevel {
   2595      0     stevel 	zoneid_t zoneid = GLOBAL_ZONEID;
   2596      0     stevel 
   2597      0     stevel 	if (param == NEXTARG) {
   2598      0     stevel 		/* zone must be active */
   2599      0     stevel 		if ((zoneid = getzoneidbyname(arg)) == -1) {
   2600      0     stevel 			(void) fprintf(stderr,
   2601      0     stevel 			    "ifconfig: unknown zone '%s'\n", arg);
   2602      0     stevel 			exit(1);
   2603      0     stevel 		}
   2604      0     stevel 	}
   2605      0     stevel 	(void) strlcpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   2606      0     stevel 	lifr.lifr_zoneid = zoneid;
   2607      0     stevel 	if (ioctl(s, SIOCSLIFZONE, (caddr_t)&lifr) == -1)
   2608      0     stevel 		Perror0_exit("SIOCSLIFZONE");
   2609      0     stevel 	return (0);
   2610      0     stevel }
   2611      0     stevel 
   2612   1676        jpk /* Put interface into all zones */
   2613   1676        jpk /* ARGSUSED */
   2614   1676        jpk static int
   2615   1676        jpk setallzones(char *arg, int64_t param)
   2616   1676        jpk {
   2617   1676        jpk 	(void) strlcpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   2618   1676        jpk 	lifr.lifr_zoneid = ALL_ZONES;
   2619   1676        jpk 	if (ioctl(s, SIOCSLIFZONE, (caddr_t)&lifr) == -1)
   2620   1676        jpk 		Perror0_exit("SIOCSLIFZONE");
   2621   1676        jpk 	return (0);
   2622   1676        jpk }
   2623   1676        jpk 
   2624      0     stevel /* Set source address to use */
   2625      0     stevel /* ARGSUSED */
   2626      0     stevel static int
   2627      0     stevel setifsrc(char *arg, int64_t param)
   2628      0     stevel {
   2629      0     stevel 	uint_t ifindex = 0;
   2630      0     stevel 	int rval;
   2631      0     stevel 
   2632      0     stevel 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   2633      0     stevel 
   2634      0     stevel 	/*
   2635      0     stevel 	 * Argument can be either an interface name or "none". The latter means
   2636      0     stevel 	 * that any previous selection is cleared.
   2637      0     stevel 	 */
   2638      0     stevel 
   2639      0     stevel 	rval = strcmp(arg, name);
   2640      0     stevel 	if (rval == 0) {
   2641      0     stevel 		(void) fprintf(stderr,
   2642      0     stevel 		    "ifconfig: Cannot specify same interface for usesrc"
   2643      0     stevel 		    " group\n");
   2644      0     stevel 		exit(1);
   2645      0     stevel 	}
   2646      0     stevel 
   2647      0     stevel 	rval = strcmp(arg, NONE_STR);
   2648      0     stevel 	if (rval != 0) {
   2649      0     stevel 		if ((ifindex = if_nametoindex(arg)) == 0) {
   2650      0     stevel 			(void) strncpy(lifr.lifr_name, arg, LIFNAMSIZ);
   2651      0     stevel 			Perror0_exit("Could not get interface index");
   2652      0     stevel 		}
   2653      0     stevel 		lifr.lifr_index = ifindex;
   2654      0     stevel 	} else {
   2655      0     stevel 		if (ioctl(s, SIOCGLIFUSESRC, (caddr_t)&lifr) != 0)
   2656      0     stevel 			Perror0_exit("Not a valid usesrc consumer");
   2657      0     stevel 		lifr.lifr_index = 0;
   2658      0     stevel 	}
   2659      0     stevel 
   2660      0     stevel 	if (debug)
   2661      0     stevel 		(void) printf("setifsrc: lifr_name %s, lifr_index %d\n",
   2662      0     stevel 		    lifr.lifr_name, lifr.lifr_index);
   2663      0     stevel 
   2664      0     stevel 	if (ioctl(s, SIOCSLIFUSESRC, (caddr_t)&lifr) == -1) {
   2665      0     stevel 		if (rval == 0)
   2666      0     stevel 			Perror0_exit("Cannot reset usesrc group");
   2667      0     stevel 		else
   2668      0     stevel 			Perror0_exit("Could not set source interface");
   2669      0     stevel 	}
   2670      0     stevel 
   2671      0     stevel 	return (0);
   2672      0     stevel }
   2673      0     stevel 
   2674      0     stevel /*
   2675      0     stevel  * Print the interface status line associated with `ifname'
   2676      0     stevel  */
   2677      0     stevel static void
   2678      0     stevel ifstatus(const char *ifname)
   2679      0     stevel {
   2680      0     stevel 	uint64_t flags;
   2681      0     stevel 	char if_usesrc_name[LIFNAMSIZ];
   2682      0     stevel 	char *newbuf;
   2683      0     stevel 	int n, numifs, rval = 0;
   2684      0     stevel 	struct lifreq *lifrp;
   2685      0     stevel 	struct lifsrcof lifs;
   2686      0     stevel 
   2687      0     stevel 	(void) strncpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
   2688      0     stevel 	if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
   2689      0     stevel 		Perror0_exit("status: SIOCGLIFFLAGS");
   2690      0     stevel 	}
   2691      0     stevel 	flags = lifr.lifr_flags;
   2692      0     stevel 
   2693      0     stevel 	/*
   2694      0     stevel 	 * In V4 compatibility mode, we don't print the IFF_IPV4 flag or
   2695      0     stevel 	 * interfaces with IFF_IPV6 set.
   2696      0     stevel 	 */
   2697      0     stevel 	if (v4compat) {
   2698      0     stevel 		flags &= ~IFF_IPV4;
   2699      0     stevel 		if (flags & IFF_IPV6)
   2700      0     stevel 			return;
   2701      0     stevel 	}
   2702      0     stevel 
   2703      0     stevel 	(void) printf("%s: ", ifname);
   2704      0     stevel 	print_flags(flags);
   2705      0     stevel 
   2706      0     stevel 	(void) strncpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
   2707      0     stevel 	if (ioctl(s, SIOCGLIFMETRIC, (caddr_t)&lifr) < 0) {
   2708      0     stevel 		Perror0_exit("status: SIOCGLIFMETRIC");
   2709      0     stevel 	} else {
   2710      0     stevel 		if (lifr.lifr_metric)
   2711      0     stevel 			(void) printf(" metric %d", lifr.lifr_metric);
   2712      0     stevel 	}
   2713      0     stevel 	if (ioctl(s, SIOCGLIFMTU, (caddr_t)&lifr) >= 0)
   2714   6353   dr146992 		(void) printf(" mtu %u", lifr.lifr_mtu);
   2715      0     stevel 
   2716      0     stevel 	/* don't print index or zone when in compatibility mode */
   2717      0     stevel 	if (!v4compat) {
   2718      0     stevel 		if (ioctl(s, SIOCGLIFINDEX, (caddr_t)&lifr) >= 0)
   2719      0     stevel 			(void) printf(" index %d", lifr.lifr_index);
   2720   3448   dh155122 		/*
   2721   3448   dh155122 		 * Stack instances use GLOBAL_ZONEID for IP data structures
   2722   3448   dh155122 		 * even in the non-global zone.
   2723   3448   dh155122 		 */
   2724      0     stevel 		if (ioctl(s, SIOCGLIFZONE, (caddr_t)&lifr) >= 0 &&
   2725   3448   dh155122 		    lifr.lifr_zoneid != getzoneid() &&
   2726   3448   dh155122 		    lifr.lifr_zoneid != GLOBAL_ZONEID) {
   2727      0     stevel 			char zone_name[ZONENAME_MAX];
   2728      0     stevel 
   2729   1676        jpk 			if (lifr.lifr_zoneid == ALL_ZONES) {
   2730   1676        jpk 				(void) printf("\n\tall-zones");
   2731   1676        jpk 			} else if (getzonenamebyid(lifr.lifr_zoneid, zone_name,
   2732      0     stevel 			    sizeof (zone_name)) < 0) {
   2733      0     stevel 				(void) printf("\n\tzone %d", lifr.lifr_zoneid);
   2734      0     stevel 			} else {
   2735      0     stevel 				(void) printf("\n\tzone %s", zone_name);
   2736      0     stevel 			}
   2737      0     stevel 		}
   2738      0     stevel 	}
   2739      0     stevel 
   2740      0     stevel 	if (ioctl(s, SIOCGLIFINDEX, (caddr_t)&lifr) >= 0) {
   2741      0     stevel 		lifs.lifs_ifindex = lifr.lifr_index;
   2742      0     stevel 
   2743      0     stevel 		/*
   2744      0     stevel 		 * Find the number of interfaces that use this interfaces'
   2745      0     stevel 		 * address as a source address
   2746      0     stevel 		 */
   2747      0     stevel 		lifs.lifs_buf = NULL;
   2748      0     stevel 		lifs.lifs_maxlen = 0;
   2749      0     stevel 		for (;;) {
   2750      0     stevel 			/* The first pass will give the bufsize we need */
   2751      0     stevel 			rval = ioctl(s, SIOCGLIFSRCOF, (char *)&lifs);
   2752      0     stevel 			if (rval < 0) {
   2753      0     stevel 				if (lifs.lifs_buf != NULL) {
   2754      0     stevel 					free(lifs.lifs_buf);
   2755      0     stevel 					lifs.lifs_buf = NULL;
   2756      0     stevel 				}
   2757      0     stevel 				lifs.lifs_len = 0;
   2758      0     stevel 				break;
   2759      0     stevel 			}
   2760      0     stevel 			if (lifs.lifs_len <= lifs.lifs_maxlen)
   2761      0     stevel 				break;
   2762      0     stevel 			/* Use kernel's size + a small margin to avoid loops */
   2763      0     stevel 			lifs.lifs_maxlen = lifs.lifs_len +
   2764      0     stevel 			    5 * sizeof (struct lifreq);
   2765      0     stevel 			/* For the first pass, realloc acts like malloc */
   2766      0     stevel 			newbuf = realloc(lifs.lifs_buf, lifs.lifs_maxlen);
   2767      0     stevel 			if (newbuf == NULL) {
   2768      0     stevel 				if (lifs.lifs_buf != NULL) {
   2769      0     stevel 					free(lifs.lifs_buf);
   2770      0     stevel 					lifs.lifs_buf = NULL;
   2771      0     stevel 				}
   2772      0     stevel 				lifs.lifs_len = 0;
   2773      0     stevel 				break;
   2774      0     stevel 			}
   2775      0     stevel 			lifs.lifs_buf = newbuf;
   2776      0     stevel 		}
   2777      0     stevel 
   2778      0     stevel 
   2779      0     stevel 		numifs = lifs.lifs_len / sizeof (struct lifreq);
   2780      0     stevel 		if (numifs > 0) {
   2781      0     stevel 			lifrp = lifs.lifs_req;
   2782      0     stevel 			(void) printf("\n\tsrcof");
   2783      0     stevel 			for (n = numifs; n > 0; n--, lifrp++) {
   2784      0     stevel 				(void) printf(" %s", lifrp->lifr_name);
   2785      0     stevel 			}
   2786      0     stevel 		}
   2787      0     stevel 
   2788      0     stevel 		if (lifs.lifs_buf != NULL)
   2789      0     stevel 			free(lifs.lifs_buf);
   2790      0     stevel 	}
   2791      0     stevel 
   2792      0     stevel 	/* Find the interface whose source address this interface uses */
   2793      0     stevel 	if (ioctl(s, SIOCGLIFUSESRC, (caddr_t)&lifr) == 0) {
   2794      0     stevel 		if (lifr.lifr_index != 0) {
   2795      0     stevel 			if (if_indextoname(lifr.lifr_index,
   2796      0     stevel 			    if_usesrc_name) == NULL) {
   2797      0     stevel 				(void) printf("\n\tusesrc ifIndex %d",
   2798      0     stevel 				    lifr.lifr_index);
   2799      0     stevel 			} else {
   2800      0     stevel 				(void) printf("\n\tusesrc %s", if_usesrc_name);
   2801      0     stevel 			}
   2802      0     stevel 		}
   2803      0     stevel 	}
   2804      0     stevel 
   2805      0     stevel 	(void) putchar('\n');
   2806      0     stevel }
   2807      0     stevel 
   2808      0     stevel 
   2809      0     stevel /*
   2810      0     stevel  * Print the status of the interface.  If an address family was
   2811      0     stevel  * specified, show it and it only; otherwise, show them all.
   2812      0     stevel  */
   2813      0     stevel static void
   2814      0     stevel status(void)
   2815      0     stevel {
   2816  10616  Sebastien 	struct afswtch	*p = afp;
   2817  10616  Sebastien 	uint64_t	flags;
   2818  10616  Sebastien 	datalink_id_t	linkid;
   2819      0     stevel 
   2820      0     stevel 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   2821      0     stevel 	if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
   2822      0     stevel 		Perror0_exit("status: SIOCGLIFFLAGS");
   2823      0     stevel 	}
   2824      0     stevel 
   2825      0     stevel 	flags = lifr.lifr_flags;
   2826      0     stevel 
   2827      0     stevel 	/*
   2828      0     stevel 	 * Only print the interface status if the address family matches
   2829      0     stevel 	 * the interface family flag.
   2830      0     stevel 	 */
   2831      0     stevel 	if (p != NULL) {
   2832      0     stevel 		if (((p->af_af == AF_INET6) && (flags & IFF_IPV4)) ||
   2833      0     stevel 		    ((p->af_af == AF_INET) && (flags & IFF_IPV6)))
   2834      0     stevel 			return;
   2835      0     stevel 	}
   2836      0     stevel 
   2837      0     stevel 	/*
   2838      0     stevel 	 * In V4 compatibility mode, don't print IFF_IPV6 interfaces.
   2839      0     stevel 	 */
   2840      0     stevel 	if (v4compat && (flags & IFF_IPV6))
   2841      0     stevel 		return;
   2842      0     stevel 
   2843      0     stevel 	ifstatus(name);
   2844  10616  Sebastien 
   2845  10616  Sebastien 	if (ifconfig_dladm_open(name, DATALINK_CLASS_IPTUN, &linkid) ==
   2846  10616  Sebastien 	    DLADM_STATUS_OK)
   2847  10616  Sebastien 		tun_status(linkid);
   2848      0     stevel 
   2849      0     stevel 	if (p != NULL) {
   2850      0     stevel 		(*p->af_status)(1, flags);
   2851      0     stevel 	} else {
   2852      0     stevel 		for (p = afs; p->af_name; p++) {
   2853      0     stevel 			(void) close(s);
   2854      0     stevel 			s = socket(SOCKET_AF(p->af_af), SOCK_DGRAM, 0);
   2855      0     stevel 			/* set global af for use in p->af_status */
   2856      0     stevel 			af = p->af_af;
   2857      0     stevel 			if (s == -1) {
   2858      0     stevel 				Perror0_exit("socket");
   2859      0     stevel 			}
   2860      0     stevel 			(*p->af_status)(0, flags);
   2861      0     stevel 		}
   2862      0     stevel 
   2863      0     stevel 		/*
   2864      0     stevel 		 * Historically, 'ether' has been an address family,
   2865      0     stevel 		 * so print it here.
   2866      0     stevel 		 */
   2867      0     stevel 		print_ifether(name);
   2868      0     stevel 	}
   2869      0     stevel }
   2870      0     stevel 
   2871      0     stevel /*
   2872      0     stevel  * Print the status of the interface in a format that can be used to
   2873      0     stevel  * reconfigure the interface later. Code stolen from status() above.
   2874      0     stevel  */
   2875      0     stevel /* ARGSUSED */
   2876      0     stevel static int
   2877      0     stevel configinfo(char *null, int64_t param)
   2878      0     stevel {
   2879   8485      Peter 	char *cp;
   2880      0     stevel 	struct afswtch *p = afp;
   2881      0     stevel 	uint64_t flags;
   2882   8485      Peter 	char lifname[LIFNAMSIZ];
   2883      0     stevel 	char if_usesrc_name[LIFNAMSIZ];
   2884   8485      Peter 
   2885   8485      Peter 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   2886   8485      Peter 
   2887      0     stevel 	if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
   2888      0     stevel 		Perror0_exit("status: SIOCGLIFFLAGS");
   2889      0     stevel 	}
   2890      0     stevel 	flags = lifr.lifr_flags;
   2891      0     stevel 
   2892      0     stevel 	if (debug) {
   2893      0     stevel 		(void) printf("configinfo: name %s flags  0x%llx af_af %d\n",
   2894      0     stevel 		    name, flags, p != NULL ? p->af_af : -1);
   2895      0     stevel 	}
   2896      0     stevel 
   2897   8485      Peter 	/*
   2898   8485      Peter 	 * Build the interface name to print (we can't directly use `name'
   2899   8485      Peter 	 * because one cannot "plumb" ":0" interfaces).
   2900   8485      Peter 	 */
   2901   8485      Peter 	(void) strlcpy(lifname, name, LIFNAMSIZ);
   2902   8485      Peter 	if ((cp = strchr(lifname, ':')) != NULL && atoi(cp + 1) == 0)
   2903   8485      Peter 		*cp = '\0';
   2904      0     stevel 
   2905      0     stevel 	/*
   2906      0     stevel 	 * if the interface is IPv4
   2907      0     stevel 	 *	if we have a IPv6 address family restriction return
   2908      0     stevel 	 *		so it won't print
   2909      0     stevel 	 *	if we are in IPv4 compatibility mode, clear out IFF_IPV4
   2910      0     stevel 	 *		so we don't print it.
   2911      0     stevel 	 */
   2912      0     stevel 	if (flags & IFF_IPV4) {
   2913      0     stevel 		if (p && p->af_af == AF_INET6)
   2914      0     stevel 			return (-1);
   2915      0     stevel 		if (v4compat)
   2916      0     stevel 			flags &= ~IFF_IPV4;
   2917      0     stevel 
   2918   8485      Peter 		(void) printf("%s inet plumb", lifname);
   2919      0     stevel 	} else if (flags & IFF_IPV6) {
   2920      0     stevel 		/*
   2921      0     stevel 		 * else if the interface is IPv6
   2922      0     stevel 		 *	if we have a IPv4 address family restriction return
   2923      0     stevel 		 *	or we are in IPv4 compatibiltiy mode, return.
   2924      0     stevel 		 */
   2925      0     stevel 		if (p && p->af_af == AF_INET)
   2926      0     stevel 			return (-1);
   2927      0     stevel 		if (v4compat)
   2928      0     stevel 			return (-1);
   2929      0     stevel 
   2930   8485      Peter 		(void) printf("%s inet6 plumb", lifname);
   2931      0     stevel 	}
   2932      0     stevel 
   2933      0     stevel 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
   2934      0     stevel 	if (ioctl(s, SIOCGLIFMETRIC, (caddr_t)&lifr) < 0) {
   2935      0     stevel 		Perror0_exit("configinfo: SIOCGLIFMETRIC");
   2936      0     stevel 	} else {
   2937      0     stevel 		if (lifr.lifr_metric)
   2938      0     stevel 			(void) printf(" metric %d ", lifr.lifr_metric);
   2939      0     stevel 	}
   2940      0     stevel 	if (((flags & (IFF_VIRTUAL|IFF_LOOPBACK)) != IFF_VIRTUAL) &&
   2941   5240   nordmark 	    ioctl(s, SIOCGLIFMTU, (caddr_t)&lifr) >= 0)
   2942      0     stevel 		(void) printf(" mtu %d", lifr.lifr_metric);
   2943      0     stevel 
   2944   8485      Peter 	/* Index only applies to the zeroth interface */
   2945   8485      Peter 	if (lifnum(name) == 0) {
   2946      0     stevel 		if (ioctl(s, SIOCGLIFINDEX, (caddr_t)&lifr) >= 0)
   2947      0     stevel 			(void) printf(" index %d", lifr.lifr_index);
   2948      0     stevel 	}
   2949      0     stevel 
   2950      0     stevel 	if (ioctl(s, SIOCGLIFUSESRC, (caddr_t)&lifr) == 0) {
   2951      0     stevel 		if (lifr.lifr_index != 0) {
   2952      0     stevel 			if (if_indextoname(lifr.lifr_index,
   2953      0     stevel 			    if_usesrc_name) != NULL) {
   2954      0     stevel 				(void) printf(" usesrc %s", if_usesrc_name);
   2955      0     stevel 			}
   2956      0     stevel 		}
   2957      0     stevel 	}
   2958      0     stevel 
   2959      0     stevel 	if (p != NULL) {
   2960      0     stevel 		(*p->af_configinfo)(1, flags);
   2961      0     stevel 	} else {
   2962      0     stevel 		for (p = afs; p->af_name; p++) {
   2963      0     stevel 			(void) close(s);
   2964      0     stevel 			s = socket(SOCKET_AF(p->af_af), SOCK_DGRAM, 0);
   2965      0     stevel 			/* set global af for use in p->af_configinfo */
   2966      0     stevel 			af = p->af_af;
   2967      0     stevel 			if (s == -1) {
   2968      0     stevel 				Perror0_exit("socket");
   2969      0     stevel 			}
   2970      0     stevel 			(*p->af_configinfo)(0, flags);
   2971      0     stevel 		}
   2972      0     stevel 	}
   2973      0     stevel 
   2974  10616  Sebastien 	(void) putchar('\n');
   2975  10616  Sebastien 	return (0);
   2976  10616  Sebastien }
   2977  10616  Sebastien 
   2978  10616  Sebastien static void
   2979  10616  Sebastien print_tsec(iptun_params_t *params)
   2980      0     stevel {
   2981      0     stevel 	ipsec_req_t *ipsr;
   2982      0     stevel 
   2983      0     stevel 	(void) printf("\ttunnel security settings  ");
   2984  10616  Sebastien 	if (!(params->iptun_param_flags & IPTUN_PARAM_SECINFO)) {
   2985  10616  Sebastien 		(void) printf("-->  use 'ipsecconf -ln -i %s'", name);
   2986  10616  Sebastien 	} else {
   2987  10616  Sebastien 		ipsr = &params->iptun_param_secinfo;
   2988   3055     danmcd 		if (ipsr->ipsr_ah_req & IPSEC_PREF_REQUIRED) {
   2989   3055     danmcd 			(void) printf("ah (%s)  ",
   2990   3055     danmcd 			    rparsealg(ipsr->ipsr_auth_alg, IPSEC_PROTO_AH));
   2991   3055     danmcd 		}
   2992   3055     danmcd 		if (ipsr->ipsr_esp_req & IPSEC_PREF_REQUIRED) {
   2993   3055     danmcd 			(void) printf("esp (%s",
   2994   3055     danmcd 			    rparsealg(ipsr->ipsr_esp_alg, IPSEC_PROTO_ESP));
   2995   3055     danmcd 			(void) printf("/%s)",
   2996   3055     danmcd 			    rparsealg(ipsr->ipsr_esp_auth_alg, IPSEC_PROTO_AH));
   2997   3055     danmcd 		}
   2998      0     stevel 	}
   2999      0     stevel 	(void) printf("\n");
   3000      0     stevel }
   3001      0     stevel 
   3002      0     stevel static void
   3003  10616  Sebastien tun_status(datalink_id_t linkid)
   3004  10616  Sebastien {
   3005  10616  Sebastien 	iptun_params_t	params;
   3006  10616  Sebastien 	char		propval[DLADM_PROP_VAL_MAX];
   3007  10616  Sebastien 	char		*valptr[1];
   3008  10616  Sebastien 	uint_t		valcnt = 1;
   3009  10616  Sebastien 	boolean_t	tabbed = _B_FALSE;
   3010  10616  Sebastien 
   3011  10616  Sebastien 	params.iptun_param_linkid = linkid;
   3012  10616  Sebastien 
   3013  10616  Sebastien 	/* If dladm_iptun_getparams() fails, assume we are not a tunnel. */
   3014  10616  Sebastien 	assert(dlh_opened);
   3015  10616  Sebastien 	if (dladm_iptun_getparams(dlh, &params, DLADM_OPT_ACTIVE) !=
   3016  10616  Sebastien 	    DLADM_STATUS_OK)
   3017  10616  Sebastien 		return;
   3018  10616  Sebastien 
   3019  10616  Sebastien 	switch (params.iptun_param_type) {
   3020  10616  Sebastien 	case IPTUN_TYPE_IPV4:
   3021  10616  Sebastien 	case IPTUN_TYPE_6TO4:
   3022      0     stevel 		(void) printf("\tinet");
   3023      0     stevel 		break;
   3024  10616  Sebastien 	case IPTUN_TYPE_IPV6:
   3025      0     stevel 		(void) printf("\tinet6");
   3026      0     stevel 		break;
   3027      0     stevel 	default:
   3028  10616  Sebastien 		dladmerr_exit(DLADM_STATUS_IPTUNTYPE, name);
   3029  10616  Sebastien 		break;
   3030  10616  Sebastien 	}
   3031  10616  Sebastien 
   3032  10616  Sebastien 	/*
   3033  10616  Sebastien 	 * There is always a source address.  If it hasn't been explicitly
   3034  10616  Sebastien 	 * set, the API will pass back a buffer containing the unspecified
   3035  10616  Sebastien 	 * address.
   3036  10616  Sebastien 	 */
   3037  10616  Sebastien 	(void) printf(" tunnel src %s ", params.iptun_param_laddr);
   3038  10616  Sebastien 
   3039  10616  Sebastien 	if (params.iptun_param_flags & IPTUN_PARAM_RADDR)
   3040  10616  Sebastien 		(void) printf("tunnel dst %s\n", params.iptun_param_raddr);
   3041  10616  Sebastien 	else
   3042  10616  Sebastien 		(void) putchar('\n');
   3043  10616  Sebastien 
   3044  10616  Sebastien 	if (params.iptun_param_flags & IPTUN_PARAM_IPSECPOL)
   3045  10616  Sebastien 		print_tsec(&params);
   3046  10616  Sebastien 
   3047  10616  Sebastien 	valptr[0] = propval;
   3048  10616  Sebastien 	if (dladm_get_linkprop(dlh, linkid, DLADM_PROP_VAL_CURRENT, "hoplimit",
   3049  10616  Sebastien 	    (char **)valptr, &valcnt) == DLADM_STATUS_OK) {
   3050  10616  Sebastien 		(void) printf("\ttunnel hop limit %s ", propval);
   3051      0     stevel 		tabbed = _B_TRUE;
   3052      0     stevel 	}
   3053      0     stevel 
   3054  10616  Sebastien 	if (dladm_get_linkprop(dlh, linkid, DLADM_PROP_VAL_CURRENT,
   3055  10616  Sebastien 	    "encaplimit", (char **)valptr, &valcnt) == DLADM_STATUS_OK) {
   3056  10616  Sebastien 		uint32_t elim;
   3057  10616  Sebastien 
   3058      0     stevel 		if (!tabbed) {
   3059  10616  Sebastien 			(void) putchar('\t');
   3060      0     stevel 			tabbed =