13871Syz147064 /*
23871Syz147064  * CDDL HEADER START
33871Syz147064  *
43871Syz147064  * The contents of this file are subject to the terms of the
53871Syz147064  * Common Development and Distribution License (the "License").
63871Syz147064  * You may not use this file except in compliance with the License.
73871Syz147064  *
83871Syz147064  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93871Syz147064  * or http://www.opensolaris.org/os/licensing.
103871Syz147064  * See the License for the specific language governing permissions
113871Syz147064  * and limitations under the License.
123871Syz147064  *
133871Syz147064  * When distributing Covered Code, include this CDDL HEADER in each
143871Syz147064  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153871Syz147064  * If applicable, add the following below this CDDL HEADER, with the
163871Syz147064  * fields enclosed by brackets "[]" replaced with your own identifying
173871Syz147064  * information: Portions Copyright [yyyy] [name of copyright owner]
183871Syz147064  *
193871Syz147064  * CDDL HEADER END
203871Syz147064  */
213871Syz147064 /*
225895Syz147064  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
233871Syz147064  * Use is subject to license terms.
243871Syz147064  */
253871Syz147064 
263871Syz147064 #include <sys/types.h>
273871Syz147064 #include <unistd.h>
283871Syz147064 #include <errno.h>
293871Syz147064 #include <fcntl.h>
305895Syz147064 #include <assert.h>
315895Syz147064 #include <ctype.h>
323871Syz147064 #include <strings.h>
333871Syz147064 #include <sys/stat.h>
343871Syz147064 #include <sys/dld.h>
355895Syz147064 #include <sys/vlan.h>
367342SAruna.Ramakrishna@Sun.COM #include <zone.h>
375895Syz147064 #include <librcm.h>
383871Syz147064 #include <libdlpi.h>
393871Syz147064 #include <libdevinfo.h>
405895Syz147064 #include <libdlaggr.h>
415895Syz147064 #include <libdlvlan.h>
423871Syz147064 #include <libdllink.h>
435895Syz147064 #include <libdlmgmt.h>
443871Syz147064 #include <libdladm_impl.h>
455903Ssowmini #include <libinetutil.h>
463871Syz147064 
473871Syz147064 /*
483871Syz147064  * Return the attributes of the specified datalink from the DLD driver.
493871Syz147064  */
505895Syz147064 static dladm_status_t
51*8453SAnurag.Maskey@Sun.COM i_dladm_info(dladm_handle_t handle, const datalink_id_t linkid,
52*8453SAnurag.Maskey@Sun.COM     dladm_attr_t *dap)
533871Syz147064 {
543871Syz147064 	dld_ioc_attr_t	dia;
553871Syz147064 
565895Syz147064 	dia.dia_linkid = linkid;
573871Syz147064 
58*8453SAnurag.Maskey@Sun.COM 	if (ioctl(dladm_dld_fd(handle), DLDIOC_ATTR, &dia) < 0)
595895Syz147064 		return (dladm_errno2status(errno));
603871Syz147064 
613871Syz147064 	dap->da_max_sdu = dia.dia_max_sdu;
623871Syz147064 
635895Syz147064 	return (DLADM_STATUS_OK);
643871Syz147064 }
653871Syz147064 
668275SEric Cheng static dladm_status_t
67*8453SAnurag.Maskey@Sun.COM dladm_usagelog(dladm_handle_t handle, dladm_logtype_t type,
68*8453SAnurag.Maskey@Sun.COM     dld_ioc_usagelog_t *log_info)
698275SEric Cheng {
708275SEric Cheng 	if (type == DLADM_LOGTYPE_FLOW)
718275SEric Cheng 		log_info->ul_type = MAC_LOGTYPE_FLOW;
728275SEric Cheng 	else
738275SEric Cheng 		log_info->ul_type = MAC_LOGTYPE_LINK;
748275SEric Cheng 
75*8453SAnurag.Maskey@Sun.COM 	if (ioctl(dladm_dld_fd(handle), DLDIOC_USAGELOG, log_info) < 0)
768275SEric Cheng 		return (DLADM_STATUS_IOERR);
77*8453SAnurag.Maskey@Sun.COM 
788275SEric Cheng 	return (DLADM_STATUS_OK);
798275SEric Cheng }
808275SEric Cheng 
818275SEric Cheng dladm_status_t
82*8453SAnurag.Maskey@Sun.COM dladm_start_usagelog(dladm_handle_t handle, dladm_logtype_t type,
83*8453SAnurag.Maskey@Sun.COM     uint_t interval)
848275SEric Cheng {
858275SEric Cheng 	dld_ioc_usagelog_t	log_info;
868275SEric Cheng 
878275SEric Cheng 	log_info.ul_onoff = B_TRUE;
888275SEric Cheng 	log_info.ul_interval = interval;
898275SEric Cheng 
90*8453SAnurag.Maskey@Sun.COM 	return (dladm_usagelog(handle, type, &log_info));
918275SEric Cheng }
928275SEric Cheng 
938275SEric Cheng dladm_status_t
94*8453SAnurag.Maskey@Sun.COM dladm_stop_usagelog(dladm_handle_t handle, dladm_logtype_t type)
958275SEric Cheng {
968275SEric Cheng 	dld_ioc_usagelog_t	log_info;
978275SEric Cheng 
988275SEric Cheng 	log_info.ul_onoff = B_FALSE;
998275SEric Cheng 	log_info.ul_interval = 0;
1008275SEric Cheng 
101*8453SAnurag.Maskey@Sun.COM 	return (dladm_usagelog(handle, type, &log_info));
1028275SEric Cheng }
1038275SEric Cheng 
1045895Syz147064 struct i_dladm_walk_arg {
1055895Syz147064 	dladm_walkcb_t *fn;
1065895Syz147064 	void *arg;
1075895Syz147064 };
1083871Syz147064 
1095895Syz147064 static int
110*8453SAnurag.Maskey@Sun.COM i_dladm_walk(dladm_handle_t handle, datalink_id_t linkid, void *arg)
1115895Syz147064 {
1125895Syz147064 	struct i_dladm_walk_arg *walk_arg = arg;
1135895Syz147064 	char link[MAXLINKNAMELEN];
1143871Syz147064 
115*8453SAnurag.Maskey@Sun.COM 	if (dladm_datalink_id2info(handle, linkid, NULL, NULL, NULL, link,
1165895Syz147064 	    sizeof (link)) == DLADM_STATUS_OK) {
1175895Syz147064 		return (walk_arg->fn(link, walk_arg->arg));
1183871Syz147064 	}
1193871Syz147064 
1205895Syz147064 	return (DLADM_WALK_CONTINUE);
1213871Syz147064 }
1223871Syz147064 
1233871Syz147064 /*
1245895Syz147064  * Walk all datalinks.
1253871Syz147064  */
1265895Syz147064 dladm_status_t
127*8453SAnurag.Maskey@Sun.COM dladm_walk(dladm_walkcb_t *fn, dladm_handle_t handle, void *arg,
128*8453SAnurag.Maskey@Sun.COM     datalink_class_t class, datalink_media_t dmedia, uint32_t flags)
1293871Syz147064 {
1305895Syz147064 	struct i_dladm_walk_arg walk_arg;
1313871Syz147064 
1325895Syz147064 	walk_arg.fn = fn;
1335895Syz147064 	walk_arg.arg = arg;
134*8453SAnurag.Maskey@Sun.COM 	return (dladm_walk_datalink_id(i_dladm_walk, handle, &walk_arg,
1355895Syz147064 	    class, dmedia, flags));
1363871Syz147064 }
1373871Syz147064 
1388275SEric Cheng #define	MAXGRPPERLINK	64
1398275SEric Cheng 
1408275SEric Cheng int
141*8453SAnurag.Maskey@Sun.COM dladm_walk_hwgrp(dladm_handle_t handle, datalink_id_t linkid, void *arg,
1428275SEric Cheng     boolean_t (*fn)(void *, dladm_hwgrp_attr_t *))
1438275SEric Cheng {
144*8453SAnurag.Maskey@Sun.COM 	int		bufsize, ret;
1458275SEric Cheng 	int		nhwgrp = MAXGRPPERLINK;
1468275SEric Cheng 	dld_ioc_hwgrpget_t *iomp = NULL;
1478275SEric Cheng 
1488275SEric Cheng 	bufsize = sizeof (dld_ioc_hwgrpget_t) +
1498275SEric Cheng 	    nhwgrp * sizeof (dld_hwgrpinfo_t);
1508275SEric Cheng 
1518275SEric Cheng 	if ((iomp = (dld_ioc_hwgrpget_t *)calloc(1, bufsize)) == NULL)
1528275SEric Cheng 		return (-1);
1538275SEric Cheng 
1548275SEric Cheng 	iomp->dih_size = nhwgrp * sizeof (dld_hwgrpinfo_t);
1558275SEric Cheng 	iomp->dih_linkid = linkid;
1568275SEric Cheng 
157*8453SAnurag.Maskey@Sun.COM 	ret = ioctl(dladm_dld_fd(handle), DLDIOC_GETHWGRP, iomp);
1588275SEric Cheng 	if (ret == 0) {
1598275SEric Cheng 		int i;
1608275SEric Cheng 		dld_hwgrpinfo_t *dhip;
1618275SEric Cheng 		dladm_hwgrp_attr_t attr;
1628275SEric Cheng 
1638275SEric Cheng 		dhip = (dld_hwgrpinfo_t *)(iomp + 1);
1648275SEric Cheng 		for (i = 0; i < iomp->dih_n_groups; i++) {
1658275SEric Cheng 			bzero(&attr, sizeof (attr));
1668275SEric Cheng 
1678275SEric Cheng 			(void) strlcpy(attr.hg_link_name,
1688275SEric Cheng 			    dhip->dhi_link_name, sizeof (attr.hg_link_name));
1698275SEric Cheng 			attr.hg_grp_num = dhip->dhi_grp_num;
1708275SEric Cheng 			attr.hg_grp_type = dhip->dhi_grp_type;
1718275SEric Cheng 			attr.hg_n_rings = dhip->dhi_n_rings;
1728275SEric Cheng 			attr.hg_n_clnts = dhip->dhi_n_clnts;
1738275SEric Cheng 			(void) strlcpy(attr.hg_client_names,
1748275SEric Cheng 			    dhip->dhi_clnts, sizeof (attr.hg_client_names));
1758275SEric Cheng 
1768275SEric Cheng 			if (!(*fn)(arg, &attr))
1778275SEric Cheng 				break;
1788275SEric Cheng 			dhip++;
1798275SEric Cheng 		}
1808275SEric Cheng 	}
1818275SEric Cheng 	free(iomp);
1828275SEric Cheng 	return (ret);
1838275SEric Cheng }
1848275SEric Cheng 
1858275SEric Cheng /*
1868275SEric Cheng  * Invoke the specified callback for each MAC address entry defined on
1878275SEric Cheng  * the specified device.
1888275SEric Cheng  */
1898275SEric Cheng int
190*8453SAnurag.Maskey@Sun.COM dladm_walk_macaddr(dladm_handle_t handle, datalink_id_t linkid, void *arg,
1918275SEric Cheng     boolean_t (*fn)(void *, dladm_macaddr_attr_t *))
1928275SEric Cheng {
193*8453SAnurag.Maskey@Sun.COM 	int		bufsize, ret;
1948275SEric Cheng 	int		nmacaddr = 1024;
1958275SEric Cheng 	dld_ioc_macaddrget_t *iomp = NULL;
1968275SEric Cheng 
1978275SEric Cheng 	bufsize = sizeof (dld_ioc_macaddrget_t) +
1988275SEric Cheng 	    nmacaddr * sizeof (dld_macaddrinfo_t);
1998275SEric Cheng 
2008275SEric Cheng 	if ((iomp = (dld_ioc_macaddrget_t *)calloc(1, bufsize)) == NULL)
2018275SEric Cheng 		return (-1);
2028275SEric Cheng 
2038275SEric Cheng 	iomp->dig_size = nmacaddr * sizeof (dld_macaddrinfo_t);
2048275SEric Cheng 	iomp->dig_linkid = linkid;
2058275SEric Cheng 
206*8453SAnurag.Maskey@Sun.COM 	ret = ioctl(dladm_dld_fd(handle), DLDIOC_MACADDRGET, iomp);
2078275SEric Cheng 	if (ret == 0) {
2088275SEric Cheng 		int i;
2098275SEric Cheng 		dld_macaddrinfo_t *dmip;
2108275SEric Cheng 		dladm_macaddr_attr_t attr;
2118275SEric Cheng 
2128275SEric Cheng 		dmip = (dld_macaddrinfo_t *)(iomp + 1);
2138275SEric Cheng 		for (i = 0; i < iomp->dig_count; i++) {
2148275SEric Cheng 			bzero(&attr, sizeof (attr));
2158275SEric Cheng 
2168275SEric Cheng 			attr.ma_slot = dmip->dmi_slot;
2178275SEric Cheng 			attr.ma_flags = 0;
2188275SEric Cheng 			if (dmip->dmi_flags & DLDIOCMACADDR_USED)
2198275SEric Cheng 				attr.ma_flags |= DLADM_MACADDR_USED;
2208275SEric Cheng 			bcopy(dmip->dmi_addr, attr.ma_addr,
2218275SEric Cheng 			    dmip->dmi_addrlen);
2228275SEric Cheng 			attr.ma_addrlen = dmip->dmi_addrlen;
2238275SEric Cheng 			(void) strlcpy(attr.ma_client_name,
2248275SEric Cheng 			    dmip->dmi_client_name, MAXNAMELEN);
2258275SEric Cheng 			attr.ma_client_linkid = dmip->dma_client_linkid;
2268275SEric Cheng 
2278275SEric Cheng 			if (!(*fn)(arg, &attr))
2288275SEric Cheng 				break;
2298275SEric Cheng 			dmip++;
2308275SEric Cheng 		}
2318275SEric Cheng 	}
2328275SEric Cheng 	free(iomp);
2338275SEric Cheng 	return (ret);
2348275SEric Cheng }
2358275SEric Cheng 
2363871Syz147064 /*
2375895Syz147064  * These routines are used by administration tools such as dladm(1M) to
2383871Syz147064  * iterate through the list of MAC interfaces
2393871Syz147064  */
2403871Syz147064 
2413871Syz147064 typedef struct dladm_mac_dev {
2423871Syz147064 	char			dm_name[MAXNAMELEN];
2435895Syz147064 	struct dladm_mac_dev    *dm_next;
2443871Syz147064 } dladm_mac_dev_t;
2453871Syz147064 
2463871Syz147064 typedef struct macadm_walk {
2475895Syz147064 	dladm_mac_dev_t	 *dmd_dev_list;
2483871Syz147064 } dladm_mac_walk_t;
2493871Syz147064 
2503871Syz147064 /*
2513871Syz147064  * Local callback invoked for each DDI_NT_NET node.
2523871Syz147064  */
2533871Syz147064 /* ARGSUSED */
2543871Syz147064 static int
2553871Syz147064 i_dladm_mac_walk(di_node_t node, di_minor_t minor, void *arg)
2563871Syz147064 {
2573871Syz147064 	dladm_mac_walk_t	*dmwp = arg;
2583871Syz147064 	dladm_mac_dev_t		*dmdp = dmwp->dmd_dev_list;
2593871Syz147064 	dladm_mac_dev_t		**last_dmdp = &dmwp->dmd_dev_list;
2603871Syz147064 	char			mac[MAXNAMELEN];
2613871Syz147064 
2623871Syz147064 	(void) snprintf(mac, MAXNAMELEN, "%s%d",
2633871Syz147064 	    di_driver_name(node), di_instance(node));
2643871Syz147064 
2653871Syz147064 	/*
2663871Syz147064 	 * Skip aggregations.
2673871Syz147064 	 */
2683871Syz147064 	if (strcmp("aggr", di_driver_name(node)) == 0)
2693871Syz147064 		return (DI_WALK_CONTINUE);
2703871Syz147064 
2715895Syz147064 	/*
2725895Syz147064 	 * Skip softmacs.
2735895Syz147064 	 */
2745895Syz147064 	if (strcmp("softmac", di_driver_name(node)) == 0)
2755895Syz147064 		return (DI_WALK_CONTINUE);
2765895Syz147064 
2773871Syz147064 	while (dmdp) {
2783871Syz147064 		/*
2793871Syz147064 		 * Skip duplicates.
2803871Syz147064 		 */
2813871Syz147064 		if (strcmp(dmdp->dm_name, mac) == 0)
2823871Syz147064 			return (DI_WALK_CONTINUE);
2833871Syz147064 
2843871Syz147064 		last_dmdp = &dmdp->dm_next;
2853871Syz147064 		dmdp = dmdp->dm_next;
2863871Syz147064 	}
2873871Syz147064 
2883871Syz147064 	if ((dmdp = malloc(sizeof (*dmdp))) == NULL)
2893871Syz147064 		return (DI_WALK_CONTINUE);
2903871Syz147064 
2913871Syz147064 	(void) strlcpy(dmdp->dm_name, mac, MAXNAMELEN);
2923871Syz147064 	dmdp->dm_next = NULL;
2933871Syz147064 	*last_dmdp = dmdp;
2943871Syz147064 
2953871Syz147064 	return (DI_WALK_CONTINUE);
2963871Syz147064 }
2973871Syz147064 
2983871Syz147064 /*
2995895Syz147064  * Invoke the specified callback for each DDI_NT_NET node.
3003871Syz147064  */
3015895Syz147064 dladm_status_t
3025895Syz147064 dladm_mac_walk(int (*fn)(const char *, void *arg), void *arg)
3033871Syz147064 {
3043871Syz147064 	di_node_t		root;
3053871Syz147064 	dladm_mac_walk_t	dmw;
3063871Syz147064 	dladm_mac_dev_t		*dmdp, *next;
3075895Syz147064 	boolean_t		done = B_FALSE;
3083871Syz147064 
3093871Syz147064 	if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL)
3105895Syz147064 		return (dladm_errno2status(errno));
3113871Syz147064 
3123871Syz147064 	dmw.dmd_dev_list = NULL;
3133871Syz147064 
3143871Syz147064 	(void) di_walk_minor(root, DDI_NT_NET, DI_CHECK_ALIAS, &dmw,
3153871Syz147064 	    i_dladm_mac_walk);
3163871Syz147064 
3173871Syz147064 	di_fini(root);
3183871Syz147064 
3193871Syz147064 	dmdp = dmw.dmd_dev_list;
3203871Syz147064 	for (dmdp = dmw.dmd_dev_list; dmdp != NULL; dmdp = next) {
3213871Syz147064 		next = dmdp->dm_next;
3225895Syz147064 		if (!done &&
3235895Syz147064 		    ((*fn)(dmdp->dm_name, arg) == DLADM_WALK_TERMINATE)) {
3245895Syz147064 			done = B_TRUE;
3255895Syz147064 		}
3263871Syz147064 		free(dmdp);
3273871Syz147064 	}
3283871Syz147064 
3295895Syz147064 	return (DLADM_STATUS_OK);
3303871Syz147064 }
3313871Syz147064 
3323871Syz147064 /*
3335895Syz147064  * Get the current attributes of the specified datalink.
3343871Syz147064  */
3355895Syz147064 dladm_status_t
336*8453SAnurag.Maskey@Sun.COM dladm_info(dladm_handle_t handle, datalink_id_t linkid, dladm_attr_t *dap)
3373871Syz147064 {
338*8453SAnurag.Maskey@Sun.COM 	return (i_dladm_info(handle, linkid, dap));
3393871Syz147064 }
3403871Syz147064 
3413871Syz147064 const char *
3423871Syz147064 dladm_linkstate2str(link_state_t state, char *buf)
3433871Syz147064 {
3443871Syz147064 	const char	*s;
3453871Syz147064 
3463871Syz147064 	switch (state) {
3473871Syz147064 	case LINK_STATE_UP:
3483871Syz147064 		s = "up";
3493871Syz147064 		break;
3503871Syz147064 	case LINK_STATE_DOWN:
3513871Syz147064 		s = "down";
3523871Syz147064 		break;
3533871Syz147064 	default:
3543871Syz147064 		s = "unknown";
3553871Syz147064 		break;
3563871Syz147064 	}
3573871Syz147064 	(void) snprintf(buf, DLADM_STRSIZE, "%s", s);
3583871Syz147064 	return (buf);
3593871Syz147064 }
3603871Syz147064 
3613871Syz147064 const char *
3623871Syz147064 dladm_linkduplex2str(link_duplex_t duplex, char *buf)
3633871Syz147064 {
3643871Syz147064 	const char	*s;
3653871Syz147064 
3663871Syz147064 	switch (duplex) {
3673871Syz147064 	case LINK_DUPLEX_FULL:
3683871Syz147064 		s = "full";
3693871Syz147064 		break;
3703871Syz147064 	case LINK_DUPLEX_HALF:
3713871Syz147064 		s = "half";
3723871Syz147064 		break;
3733871Syz147064 	default:
3743871Syz147064 		s = "unknown";
3753871Syz147064 		break;
3763871Syz147064 	}
3773871Syz147064 	(void) snprintf(buf, DLADM_STRSIZE, "%s", s);
3783871Syz147064 	return (buf);
3793871Syz147064 }
3803871Syz147064 
3813871Syz147064 /*
3826233Syz147064  * Set zoneid of a given link. Note that this function takes a link name
3836233Syz147064  * argument instead of a linkid, because a data-link (and its linkid) could
3848275SEric Cheng  * be created implicitly as the result of this function.
3855895Syz147064  */
3865895Syz147064 dladm_status_t
387*8453SAnurag.Maskey@Sun.COM dladm_setzid(dladm_handle_t handle, const char *dlname, char *zone_name)
3885895Syz147064 {
3897342SAruna.Ramakrishna@Sun.COM 	datalink_id_t	linkid;
3907342SAruna.Ramakrishna@Sun.COM 	dladm_status_t	status = DLADM_STATUS_OK;
3915895Syz147064 
3927342SAruna.Ramakrishna@Sun.COM 	/* If the link does not exist, it is a ppa-hacked vlan. */
393*8453SAnurag.Maskey@Sun.COM 	status = dladm_name2info(handle, dlname, &linkid, NULL, NULL, NULL);
3948275SEric Cheng 	if (status != DLADM_STATUS_OK)
3958275SEric Cheng 		return (status);
3965895Syz147064 
397*8453SAnurag.Maskey@Sun.COM 	status = dladm_set_linkprop(handle, linkid, "zone", &zone_name, 1,
3987342SAruna.Ramakrishna@Sun.COM 	    DLADM_OPT_ACTIVE);
3995895Syz147064 
4005895Syz147064 	return (status);
4015895Syz147064 }
4025895Syz147064 
4035895Syz147064 /*
4045895Syz147064  * Case 1: rename an existing link1 to a link2 that does not exist.
4055895Syz147064  * Result: <linkid1, link2>
4063871Syz147064  */
4075895Syz147064 static dladm_status_t
408*8453SAnurag.Maskey@Sun.COM i_dladm_rename_link_c1(dladm_handle_t handle, datalink_id_t linkid1,
409*8453SAnurag.Maskey@Sun.COM     const char *link1, const char *link2, uint32_t flags)
4105895Syz147064 {
4115895Syz147064 	dld_ioc_rename_t	dir;
4125895Syz147064 	dladm_conf_t		conf;
4135895Syz147064 	dladm_status_t		status = DLADM_STATUS_OK;
4145895Syz147064 
4155895Syz147064 	/*
4165895Syz147064 	 * Link is currently available. Check to see whether anything is
4175895Syz147064 	 * holding this link to prevent a rename operation.
4185895Syz147064 	 */
4195895Syz147064 	if (flags & DLADM_OPT_ACTIVE) {
4205895Syz147064 		dir.dir_linkid1 = linkid1;
4215895Syz147064 		dir.dir_linkid2 = DATALINK_INVALID_LINKID;
4225895Syz147064 		(void) strlcpy(dir.dir_link, link2, MAXLINKNAMELEN);
4235895Syz147064 
424*8453SAnurag.Maskey@Sun.COM 		if (ioctl(dladm_dld_fd(handle), DLDIOC_RENAME, &dir) < 0) {
4255895Syz147064 			status = dladm_errno2status(errno);
4265895Syz147064 			return (status);
4275895Syz147064 		}
4285895Syz147064 	}
4295895Syz147064 
430*8453SAnurag.Maskey@Sun.COM 	status = dladm_remap_datalink_id(handle, linkid1, link2);
4315895Syz147064 	if (status != DLADM_STATUS_OK)
4325895Syz147064 		goto done;
4335895Syz147064 
4345895Syz147064 	/*
4355895Syz147064 	 * Flush the current mapping to persistent configuration.
4365895Syz147064 	 */
4375895Syz147064 	if ((flags & DLADM_OPT_PERSIST) &&
438*8453SAnurag.Maskey@Sun.COM 	    (((status = dladm_read_conf(handle, linkid1, &conf)) !=
439*8453SAnurag.Maskey@Sun.COM 	    DLADM_STATUS_OK) ||
440*8453SAnurag.Maskey@Sun.COM 	    ((status = dladm_write_conf(handle, conf)) != DLADM_STATUS_OK))) {
441*8453SAnurag.Maskey@Sun.COM 		(void) dladm_remap_datalink_id(handle, linkid1, link1);
4425895Syz147064 	}
4435895Syz147064 done:
4445895Syz147064 	if (flags & DLADM_OPT_ACTIVE) {
4455895Syz147064 		if (status != DLADM_STATUS_OK) {
4465895Syz147064 			(void) strlcpy(dir.dir_link, link1, MAXLINKNAMELEN);
447*8453SAnurag.Maskey@Sun.COM 			(void) ioctl(dladm_dld_fd(handle), DLDIOC_RENAME, &dir);
4485895Syz147064 		}
4495895Syz147064 	}
4505895Syz147064 	return (status);
4515895Syz147064 }
4525895Syz147064 
4535895Syz147064 typedef struct link_hold_arg_s {
4545895Syz147064 	datalink_id_t	linkid;
4555895Syz147064 	datalink_id_t	holder;
4565895Syz147064 	uint32_t	flags;
4575895Syz147064 } link_hold_arg_t;
4585895Syz147064 
4595895Syz147064 static int
460*8453SAnurag.Maskey@Sun.COM i_dladm_aggr_link_hold(dladm_handle_t handle, datalink_id_t aggrid, void *arg)
4615895Syz147064 {
4625895Syz147064 	link_hold_arg_t		*hold_arg = arg;
4635895Syz147064 	dladm_aggr_grp_attr_t	ginfo;
4645895Syz147064 	dladm_status_t		status;
4655895Syz147064 	int			i;
4665895Syz147064 
467*8453SAnurag.Maskey@Sun.COM 	status = dladm_aggr_info(handle, aggrid, &ginfo, hold_arg->flags);
4685895Syz147064 	if (status != DLADM_STATUS_OK)
4695895Syz147064 		return (DLADM_WALK_CONTINUE);
4705895Syz147064 
4715895Syz147064 	for (i = 0; i < ginfo.lg_nports; i++) {
4725895Syz147064 		if (ginfo.lg_ports[i].lp_linkid == hold_arg->linkid) {
4735895Syz147064 			hold_arg->holder = aggrid;
4745895Syz147064 			return (DLADM_WALK_TERMINATE);
4755895Syz147064 		}
4765895Syz147064 	}
4775895Syz147064 	return (DLADM_WALK_CONTINUE);
4785895Syz147064 }
4795895Syz147064 
4805895Syz147064 static int
481*8453SAnurag.Maskey@Sun.COM i_dladm_vlan_link_hold(dladm_handle_t handle, datalink_id_t vlanid, void *arg)
4825895Syz147064 {
4835895Syz147064 	link_hold_arg_t		*hold_arg = arg;
4845895Syz147064 	dladm_vlan_attr_t	vinfo;
4855895Syz147064 	dladm_status_t		status;
4865895Syz147064 
487*8453SAnurag.Maskey@Sun.COM 	status = dladm_vlan_info(handle, vlanid, &vinfo, hold_arg->flags);
4885895Syz147064 	if (status != DLADM_STATUS_OK)
4895895Syz147064 		return (DLADM_WALK_CONTINUE);
4905895Syz147064 
4915895Syz147064 	if (vinfo.dv_linkid == hold_arg->linkid) {
4925895Syz147064 		hold_arg->holder = vlanid;
4935895Syz147064 		return (DLADM_WALK_TERMINATE);
4945895Syz147064 	}
4955895Syz147064 	return (DLADM_WALK_CONTINUE);
4965895Syz147064 }
4975895Syz147064 
4985895Syz147064 /*
4995895Syz147064  * Case 2: rename an available physical link link1 to a REMOVED physical link
5005895Syz147064  *     link2.  As a result, link1 directly inherits all datalinks configured
5015895Syz147064  *     over link2 (linkid2).
5025895Syz147064  * Result: <linkid2, link2, link1_phymaj, link1_phyinst, link1_devname,
5035895Syz147064  *     link2_other_attr>
5045895Syz147064  */
5055895Syz147064 static dladm_status_t
506*8453SAnurag.Maskey@Sun.COM i_dladm_rename_link_c2(dladm_handle_t handle, datalink_id_t linkid1,
507*8453SAnurag.Maskey@Sun.COM     datalink_id_t linkid2)
5083871Syz147064 {
5095895Syz147064 	rcm_handle_t		*rcm_hdl = NULL;
5105895Syz147064 	nvlist_t		*nvl = NULL;
5115895Syz147064 	link_hold_arg_t		arg;
5125895Syz147064 	dld_ioc_rename_t	dir;
5135895Syz147064 	dladm_conf_t		conf1, conf2;
5145895Syz147064 	char			devname[MAXLINKNAMELEN];
5155895Syz147064 	uint64_t		phymaj, phyinst;
5165895Syz147064 	dladm_status_t		status = DLADM_STATUS_OK;
5175895Syz147064 
5185895Syz147064 	/*
5195895Syz147064 	 * First check if linkid1 is associated with any persistent
5205895Syz147064 	 * aggregations or VLANs. If yes, return BUSY.
5215895Syz147064 	 */
5225895Syz147064 	arg.linkid = linkid1;
5235895Syz147064 	arg.holder = DATALINK_INVALID_LINKID;
5245895Syz147064 	arg.flags = DLADM_OPT_PERSIST;
525*8453SAnurag.Maskey@Sun.COM 	(void) dladm_walk_datalink_id(i_dladm_aggr_link_hold, handle, &arg,
5265895Syz147064 	    DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST);
5275895Syz147064 	if (arg.holder != DATALINK_INVALID_LINKID)
5285895Syz147064 		return (DLADM_STATUS_LINKBUSY);
5295895Syz147064 
5305895Syz147064 	arg.flags = DLADM_OPT_PERSIST;
531*8453SAnurag.Maskey@Sun.COM 	(void) dladm_walk_datalink_id(i_dladm_vlan_link_hold, handle, &arg,
5325895Syz147064 	    DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST);
5335895Syz147064 	if (arg.holder != DATALINK_INVALID_LINKID)
5345895Syz147064 		return (DLADM_STATUS_LINKBUSY);
5355895Syz147064 
5365895Syz147064 	/*
5375895Syz147064 	 * Send DLDIOC_RENAME to request to rename link1's linkid to
5385895Syz147064 	 * be linkid2. This will check whether link1 is used by any
5395895Syz147064 	 * aggregations or VLANs, or is held by any application. If yes,
5405895Syz147064 	 * return failure.
5415895Syz147064 	 */
5425895Syz147064 	dir.dir_linkid1 = linkid1;
5435895Syz147064 	dir.dir_linkid2 = linkid2;
544*8453SAnurag.Maskey@Sun.COM 	if (ioctl(dladm_dld_fd(handle), DLDIOC_RENAME, &dir) < 0)
5455895Syz147064 		status = dladm_errno2status(errno);
5465895Syz147064 
5475895Syz147064 	if (status != DLADM_STATUS_OK) {
5485895Syz147064 		return (status);
5495895Syz147064 	}
5505895Syz147064 
5515895Syz147064 	/*
5525895Syz147064 	 * Now change the phymaj, phyinst and devname associated with linkid1
5535895Syz147064 	 * to be associated with linkid2. Before doing that, the old active
5545895Syz147064 	 * linkprop of linkid1 should be deleted.
5555895Syz147064 	 */
556*8453SAnurag.Maskey@Sun.COM 	(void) dladm_set_linkprop(handle, linkid1, NULL, NULL, 0,
557*8453SAnurag.Maskey@Sun.COM 	    DLADM_OPT_ACTIVE);
5585895Syz147064 
559*8453SAnurag.Maskey@Sun.COM 	if (((status = dladm_read_conf(handle, linkid1, &conf1)) !=
560*8453SAnurag.Maskey@Sun.COM 	    DLADM_STATUS_OK) ||
561*8453SAnurag.Maskey@Sun.COM 	    ((status = dladm_get_conf_field(handle, conf1, FDEVNAME, devname,
5625895Syz147064 	    MAXLINKNAMELEN)) != DLADM_STATUS_OK) ||
563*8453SAnurag.Maskey@Sun.COM 	    ((status = dladm_get_conf_field(handle, conf1, FPHYMAJ, &phymaj,
5645895Syz147064 	    sizeof (uint64_t))) != DLADM_STATUS_OK) ||
565*8453SAnurag.Maskey@Sun.COM 	    ((status = dladm_get_conf_field(handle, conf1, FPHYINST, &phyinst,
5665895Syz147064 	    sizeof (uint64_t))) != DLADM_STATUS_OK) ||
567*8453SAnurag.Maskey@Sun.COM 	    ((status = dladm_read_conf(handle, linkid2, &conf2)) !=
568*8453SAnurag.Maskey@Sun.COM 	    DLADM_STATUS_OK)) {
5695895Syz147064 		dir.dir_linkid1 = linkid2;
5705895Syz147064 		dir.dir_linkid2 = linkid1;
571*8453SAnurag.Maskey@Sun.COM 		(void) dladm_init_linkprop(handle, linkid1, B_FALSE);
572*8453SAnurag.Maskey@Sun.COM 		(void) ioctl(dladm_dld_fd(handle), DLDIOC_RENAME, &dir);
5735895Syz147064 		return (status);
5745895Syz147064 	}
5755895Syz147064 
576*8453SAnurag.Maskey@Sun.COM 	dladm_destroy_conf(handle, conf1);
577*8453SAnurag.Maskey@Sun.COM 	(void) dladm_set_conf_field(handle, conf2, FDEVNAME, DLADM_TYPE_STR,
578*8453SAnurag.Maskey@Sun.COM 	    devname);
579*8453SAnurag.Maskey@Sun.COM 	(void) dladm_set_conf_field(handle, conf2, FPHYMAJ, DLADM_TYPE_UINT64,
580*8453SAnurag.Maskey@Sun.COM 	    &phymaj);
581*8453SAnurag.Maskey@Sun.COM 	(void) dladm_set_conf_field(handle, conf2, FPHYINST,
5825895Syz147064 	    DLADM_TYPE_UINT64, &phyinst);
583*8453SAnurag.Maskey@Sun.COM 	(void) dladm_write_conf(handle, conf2);
584*8453SAnurag.Maskey@Sun.COM 	dladm_destroy_conf(handle, conf2);
5855895Syz147064 
5865895Syz147064 	/*
5875895Syz147064 	 * Delete link1 and mark link2 up.
5885895Syz147064 	 */
589*8453SAnurag.Maskey@Sun.COM 	(void) dladm_destroy_datalink_id(handle, linkid1, DLADM_OPT_ACTIVE |
5905895Syz147064 	    DLADM_OPT_PERSIST);
591*8453SAnurag.Maskey@Sun.COM 	(void) dladm_remove_conf(handle, linkid1);
592*8453SAnurag.Maskey@Sun.COM 	(void) dladm_up_datalink_id(handle, linkid2);
5935895Syz147064 
5945895Syz147064 	/*
5955895Syz147064 	 * Now generate the RCM_RESOURCE_LINK_NEW sysevent which can be
5965895Syz147064 	 * consumed by the RCM framework to restore all the datalink and
5975895Syz147064 	 * IP configuration.
5985895Syz147064 	 */
5995895Syz147064 	status = DLADM_STATUS_FAILED;
6005895Syz147064 	if ((nvlist_alloc(&nvl, 0, 0) != 0) ||
6015895Syz147064 	    (nvlist_add_uint64(nvl, RCM_NV_LINKID, linkid2) != 0)) {
6025895Syz147064 		goto done;
6035895Syz147064 	}
6045895Syz147064 
6055895Syz147064 	if (rcm_alloc_handle(NULL, 0, NULL, &rcm_hdl) != RCM_SUCCESS)
6065895Syz147064 		goto done;
6075895Syz147064 
6085895Syz147064 	if (rcm_notify_event(rcm_hdl, RCM_RESOURCE_LINK_NEW, 0, nvl, NULL) ==
6095895Syz147064 	    RCM_SUCCESS) {
6105895Syz147064 		status = DLADM_STATUS_OK;
6115895Syz147064 	}
6125895Syz147064 
6135895Syz147064 done:
6145895Syz147064 	if (rcm_hdl != NULL)
6155895Syz147064 		(void) rcm_free_handle(rcm_hdl);
6165895Syz147064 	if (nvl != NULL)
6175895Syz147064 		nvlist_free(nvl);
6185895Syz147064 	return (status);
6193871Syz147064 }
6203871Syz147064 
6213871Syz147064 /*
6225895Syz147064  * case 3: rename a non-existent link to a REMOVED physical link.
6235895Syz147064  * Set the removed physical link's device name to link1, so that
6245895Syz147064  * when link1 attaches, it inherits all the link configuration of
6255895Syz147064  * the removed physical link.
6263871Syz147064  */
6275895Syz147064 static dladm_status_t
628*8453SAnurag.Maskey@Sun.COM i_dladm_rename_link_c3(dladm_handle_t handle, const char *link1,
629*8453SAnurag.Maskey@Sun.COM     datalink_id_t linkid2)
6305895Syz147064 {
6315895Syz147064 	dladm_conf_t	conf;
6325895Syz147064 	dladm_status_t	status;
6335895Syz147064 
6345895Syz147064 	if (!dladm_valid_linkname(link1))
6355895Syz147064 		return (DLADM_STATUS_LINKINVAL);
6365895Syz147064 
637*8453SAnurag.Maskey@Sun.COM 	status = dladm_read_conf(handle, linkid2, &conf);
6385895Syz147064 	if (status != DLADM_STATUS_OK)
6395895Syz147064 		goto done;
6405895Syz147064 
641*8453SAnurag.Maskey@Sun.COM 	if ((status = dladm_set_conf_field(handle, conf, FDEVNAME,
642*8453SAnurag.Maskey@Sun.COM 	    DLADM_TYPE_STR, link1)) == DLADM_STATUS_OK) {
643*8453SAnurag.Maskey@Sun.COM 		status = dladm_write_conf(handle, conf);
6445895Syz147064 	}
6455895Syz147064 
646*8453SAnurag.Maskey@Sun.COM 	dladm_destroy_conf(handle, conf);
6475895Syz147064 
6485895Syz147064 done:
6495895Syz147064 	return (status);
6505895Syz147064 }
6515895Syz147064 
6525895Syz147064 dladm_status_t
653*8453SAnurag.Maskey@Sun.COM dladm_rename_link(dladm_handle_t handle, const char *link1, const char *link2)
6545895Syz147064 {
6555895Syz147064 	datalink_id_t		linkid1 = DATALINK_INVALID_LINKID;
6565895Syz147064 	datalink_id_t		linkid2 = DATALINK_INVALID_LINKID;
6575895Syz147064 	uint32_t		flags1, flags2;
6585895Syz147064 	datalink_class_t	class1, class2;
6595895Syz147064 	uint32_t		media1, media2;
6605895Syz147064 	boolean_t		remphy2 = B_FALSE;
6615895Syz147064 	dladm_status_t  	status;
6625895Syz147064 
663*8453SAnurag.Maskey@Sun.COM 	(void) dladm_name2info(handle, link1, &linkid1, &flags1, &class1,
664*8453SAnurag.Maskey@Sun.COM 	    &media1);
665*8453SAnurag.Maskey@Sun.COM 	if ((dladm_name2info(handle, link2, &linkid2, &flags2, &class2,
666*8453SAnurag.Maskey@Sun.COM 	    &media2) == DLADM_STATUS_OK) && (class2 == DATALINK_CLASS_PHYS) &&
6675895Syz147064 	    (flags2 == DLADM_OPT_PERSIST)) {
6685895Syz147064 		/*
6695895Syz147064 		 * see whether link2 is a removed physical link.
6705895Syz147064 		 */
6715895Syz147064 		remphy2 = B_TRUE;
6725895Syz147064 	}
6735895Syz147064 
6745895Syz147064 	if (linkid1 != DATALINK_INVALID_LINKID) {
6755895Syz147064 		if (linkid2 == DATALINK_INVALID_LINKID) {
6765895Syz147064 			/*
6775895Syz147064 			 * case 1: rename an existing link to a link that
6785895Syz147064 			 * does not exist.
6795895Syz147064 			 */
680*8453SAnurag.Maskey@Sun.COM 			status = i_dladm_rename_link_c1(handle, linkid1, link1,
681*8453SAnurag.Maskey@Sun.COM 			    link2, flags1);
6825895Syz147064 		} else if (remphy2) {
6835895Syz147064 			/*
6845895Syz147064 			 * case 2: rename an available link to a REMOVED
6855895Syz147064 			 * physical link. Return failure if link1 is not
6865895Syz147064 			 * an active physical link.
6875895Syz147064 			 */
6885895Syz147064 			if ((class1 != class2) || (media1 != media2) ||
6895895Syz147064 			    !(flags1 & DLADM_OPT_ACTIVE)) {
6905895Syz147064 				status = DLADM_STATUS_BADARG;
6915895Syz147064 			} else {
692*8453SAnurag.Maskey@Sun.COM 				status = i_dladm_rename_link_c2(handle, linkid1,
6935895Syz147064 				    linkid2);
6945895Syz147064 			}
6955895Syz147064 		} else {
6965895Syz147064 			status = DLADM_STATUS_EXIST;
6975895Syz147064 		}
6985895Syz147064 	} else if (remphy2) {
699*8453SAnurag.Maskey@Sun.COM 		status = i_dladm_rename_link_c3(handle, link1, linkid2);
7005895Syz147064 	} else {
7015895Syz147064 		status = DLADM_STATUS_NOTFOUND;
7025895Syz147064 	}
7035895Syz147064 	return (status);
7045895Syz147064 }
7055895Syz147064 
7065895Syz147064 typedef struct consumer_del_phys_arg_s {
7075895Syz147064 	datalink_id_t	linkid;
7085895Syz147064 } consumer_del_phys_arg_t;
7095895Syz147064 
7105895Syz147064 static int
711*8453SAnurag.Maskey@Sun.COM i_dladm_vlan_link_del(dladm_handle_t handle, datalink_id_t vlanid, void *arg)
7125895Syz147064 {
7135895Syz147064 	consumer_del_phys_arg_t	*del_arg = arg;
7145895Syz147064 	dladm_vlan_attr_t	vinfo;
7155895Syz147064 	dladm_status_t		status;
7165895Syz147064 
717*8453SAnurag.Maskey@Sun.COM 	status = dladm_vlan_info(handle, vlanid, &vinfo, DLADM_OPT_PERSIST);
7185895Syz147064 	if (status != DLADM_STATUS_OK)
7195895Syz147064 		return (DLADM_WALK_CONTINUE);
7205895Syz147064 
7215895Syz147064 	if (vinfo.dv_linkid == del_arg->linkid)
722*8453SAnurag.Maskey@Sun.COM 		(void) dladm_vlan_delete(handle, vlanid, DLADM_OPT_PERSIST);
7235895Syz147064 	return (DLADM_WALK_CONTINUE);
7245895Syz147064 }
7255895Syz147064 
7265895Syz147064 static int
727*8453SAnurag.Maskey@Sun.COM i_dladm_aggr_link_del(dladm_handle_t handle, datalink_id_t aggrid, void *arg)
7285895Syz147064 {
7295895Syz147064 	consumer_del_phys_arg_t		*del_arg = arg;
7305895Syz147064 	dladm_aggr_grp_attr_t		ginfo;
7315895Syz147064 	dladm_status_t			status;
7325895Syz147064 	dladm_aggr_port_attr_db_t	port[1];
7335895Syz147064 	int				i;
7345895Syz147064 
735*8453SAnurag.Maskey@Sun.COM 	status = dladm_aggr_info(handle, aggrid, &ginfo, DLADM_OPT_PERSIST);
7365895Syz147064 	if (status != DLADM_STATUS_OK)
7375895Syz147064 		return (DLADM_WALK_CONTINUE);
7385895Syz147064 
7395895Syz147064 	for (i = 0; i < ginfo.lg_nports; i++)
7405895Syz147064 		if (ginfo.lg_ports[i].lp_linkid == del_arg->linkid)
7415895Syz147064 			break;
7425895Syz147064 
7435895Syz147064 	if (i != ginfo.lg_nports) {
7445895Syz147064 		if (ginfo.lg_nports == 1 && i == 0) {
7455895Syz147064 			consumer_del_phys_arg_t	aggr_del_arg;
7465895Syz147064 
7475895Syz147064 			/*
7485895Syz147064 			 * First delete all the VLANs on this aggregation, then
7495895Syz147064 			 * delete the aggregation itself.
7505895Syz147064 			 */
7515895Syz147064 			aggr_del_arg.linkid = aggrid;
7525895Syz147064 			(void) dladm_walk_datalink_id(i_dladm_vlan_link_del,
753*8453SAnurag.Maskey@Sun.COM 			    handle, &aggr_del_arg, DATALINK_CLASS_VLAN,
7545895Syz147064 			    DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST);
755*8453SAnurag.Maskey@Sun.COM 			(void) dladm_aggr_delete(handle, aggrid,
756*8453SAnurag.Maskey@Sun.COM 			    DLADM_OPT_PERSIST);
7575895Syz147064 		} else {
7585895Syz147064 			port[0].lp_linkid = del_arg->linkid;
759*8453SAnurag.Maskey@Sun.COM 			(void) dladm_aggr_remove(handle, aggrid, 1, port,
7605895Syz147064 			    DLADM_OPT_PERSIST);
7615895Syz147064 		}
7625895Syz147064 	}
7635895Syz147064 	return (DLADM_WALK_CONTINUE);
7645895Syz147064 }
7655895Syz147064 
7665895Syz147064 typedef struct del_phys_arg_s {
7675895Syz147064 	dladm_status_t	rval;
7685895Syz147064 } del_phys_arg_t;
7695895Syz147064 
7705895Syz147064 static int
771*8453SAnurag.Maskey@Sun.COM i_dladm_phys_delete(dladm_handle_t handle, datalink_id_t linkid, void *arg)
7725895Syz147064 {
7735895Syz147064 	uint32_t		flags;
7745895Syz147064 	datalink_class_t	class;
7755895Syz147064 	uint32_t		media;
7765895Syz147064 	dladm_status_t		status = DLADM_STATUS_OK;
7775895Syz147064 	del_phys_arg_t		*del_phys_arg = arg;
7785895Syz147064 	consumer_del_phys_arg_t	del_arg;
7795895Syz147064 
780*8453SAnurag.Maskey@Sun.COM 	if ((status = dladm_datalink_id2info(handle, linkid, &flags, &class,
7815895Syz147064 	    &media, NULL, 0)) != DLADM_STATUS_OK) {
7825895Syz147064 		goto done;
7835895Syz147064 	}
7845895Syz147064 
7855895Syz147064 	/*
7865895Syz147064 	 * see whether this link is a removed physical link.
7875895Syz147064 	 */
7885895Syz147064 	if ((class != DATALINK_CLASS_PHYS) || !(flags & DLADM_OPT_PERSIST) ||
7895895Syz147064 	    (flags & DLADM_OPT_ACTIVE)) {
7905895Syz147064 		status = DLADM_STATUS_BADARG;
7915895Syz147064 		goto done;
7925895Syz147064 	}
7935895Syz147064 
7945895Syz147064 	if (media == DL_ETHER) {
7955895Syz147064 		del_arg.linkid = linkid;
796*8453SAnurag.Maskey@Sun.COM 		(void) dladm_walk_datalink_id(i_dladm_aggr_link_del, handle,
797*8453SAnurag.Maskey@Sun.COM 		    &del_arg, DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE,
7985895Syz147064 		    DLADM_OPT_PERSIST);
799*8453SAnurag.Maskey@Sun.COM 		(void) dladm_walk_datalink_id(i_dladm_vlan_link_del, handle,
800*8453SAnurag.Maskey@Sun.COM 		    &del_arg, DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE,
8015895Syz147064 		    DLADM_OPT_PERSIST);
8025895Syz147064 	}
8035895Syz147064 
804*8453SAnurag.Maskey@Sun.COM 	(void) dladm_destroy_datalink_id(handle, linkid, DLADM_OPT_PERSIST);
805*8453SAnurag.Maskey@Sun.COM 	(void) dladm_remove_conf(handle, linkid);
8065895Syz147064 
8075895Syz147064 done:
8085895Syz147064 	del_phys_arg->rval = status;
8095895Syz147064 	return (DLADM_WALK_CONTINUE);
8105895Syz147064 }
8115895Syz147064 
8125895Syz147064 dladm_status_t
813*8453SAnurag.Maskey@Sun.COM dladm_phys_delete(dladm_handle_t handle, datalink_id_t linkid)
8145895Syz147064 {
8155895Syz147064 	del_phys_arg_t	arg = {DLADM_STATUS_OK};
8165895Syz147064 
8175895Syz147064 	if (linkid == DATALINK_ALL_LINKID) {
818*8453SAnurag.Maskey@Sun.COM 		(void) dladm_walk_datalink_id(i_dladm_phys_delete, handle, &arg,
8195895Syz147064 		    DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE,
8205895Syz147064 		    DLADM_OPT_PERSIST);
8215895Syz147064 		return (DLADM_STATUS_OK);
8225895Syz147064 	} else {
823*8453SAnurag.Maskey@Sun.COM 		(void) i_dladm_phys_delete(handle, linkid, &arg);
8245895Syz147064 		return (arg.rval);
8255895Syz147064 	}
8265895Syz147064 }
8275895Syz147064 
8285895Syz147064 dladm_status_t
829*8453SAnurag.Maskey@Sun.COM dladm_phys_info(dladm_handle_t handle, datalink_id_t linkid,
830*8453SAnurag.Maskey@Sun.COM     dladm_phys_attr_t *dpap, uint32_t flags)
8315895Syz147064 {
8325895Syz147064 	dladm_status_t	status;
8335895Syz147064 
8345895Syz147064 	assert(flags == DLADM_OPT_ACTIVE || flags == DLADM_OPT_PERSIST);
8355895Syz147064 
8365895Syz147064 	switch (flags) {
8375895Syz147064 	case DLADM_OPT_PERSIST: {
8385895Syz147064 		dladm_conf_t	conf;
8395895Syz147064 
840*8453SAnurag.Maskey@Sun.COM 		status = dladm_read_conf(handle, linkid, &conf);
8415895Syz147064 		if (status != DLADM_STATUS_OK)
8425895Syz147064 			return (status);
8435895Syz147064 
844*8453SAnurag.Maskey@Sun.COM 		status = dladm_get_conf_field(handle, conf, FDEVNAME,
845*8453SAnurag.Maskey@Sun.COM 		    dpap->dp_dev, MAXLINKNAMELEN);
846*8453SAnurag.Maskey@Sun.COM 		dladm_destroy_conf(handle, conf);
8475895Syz147064 		return (status);
8485895Syz147064 	}
8495895Syz147064 	case DLADM_OPT_ACTIVE: {
8505895Syz147064 		dld_ioc_phys_attr_t	dip;
8515895Syz147064 
8525895Syz147064 		dip.dip_linkid = linkid;
853*8453SAnurag.Maskey@Sun.COM 		if (ioctl(dladm_dld_fd(handle), DLDIOC_PHYS_ATTR, &dip) < 0) {
8545895Syz147064 			status = dladm_errno2status(errno);
8555895Syz147064 			return (status);
8565895Syz147064 		}
8575895Syz147064 		dpap->dp_novanity = dip.dip_novanity;
8585895Syz147064 		(void) strlcpy(dpap->dp_dev, dip.dip_dev, MAXLINKNAMELEN);
8595895Syz147064 		return (DLADM_STATUS_OK);
8605895Syz147064 	}
8615895Syz147064 	default:
8625895Syz147064 		return (DLADM_STATUS_BADARG);
8635895Syz147064 	}
8645895Syz147064 }
8655895Syz147064 
8665895Syz147064 typedef struct i_walk_dev_state_s {
8675895Syz147064 	const char *devname;
8685895Syz147064 	datalink_id_t linkid;
8695895Syz147064 	boolean_t found;
8705895Syz147064 } i_walk_dev_state_t;
8715895Syz147064 
8723871Syz147064 int
873*8453SAnurag.Maskey@Sun.COM i_dladm_walk_dev2linkid(dladm_handle_t handle, datalink_id_t linkid, void *arg)
8745895Syz147064 {
8755895Syz147064 	dladm_phys_attr_t dpa;
8765895Syz147064 	dladm_status_t status;
8775895Syz147064 	i_walk_dev_state_t *statep = arg;
8785895Syz147064 
879*8453SAnurag.Maskey@Sun.COM 	status = dladm_phys_info(handle, linkid, &dpa, DLADM_OPT_PERSIST);
8805895Syz147064 	if ((status == DLADM_STATUS_OK) &&
8815895Syz147064 	    (strcmp(statep->devname, dpa.dp_dev) == 0)) {
8825895Syz147064 		statep->found = B_TRUE;
8835895Syz147064 		statep->linkid = linkid;
8845895Syz147064 		return (DLADM_WALK_TERMINATE);
8855895Syz147064 	}
8865895Syz147064 	return (DLADM_WALK_CONTINUE);
8875895Syz147064 }
8885895Syz147064 
8895895Syz147064 /*
8905895Syz147064  * Get the linkid from the physical device name.
8915895Syz147064  */
8925895Syz147064 dladm_status_t
893*8453SAnurag.Maskey@Sun.COM dladm_dev2linkid(dladm_handle_t handle, const char *devname,
894*8453SAnurag.Maskey@Sun.COM     datalink_id_t *linkidp)
8955895Syz147064 {
8965895Syz147064 	i_walk_dev_state_t state;
8975895Syz147064 
8985895Syz147064 	state.found = B_FALSE;
8995895Syz147064 	state.devname = devname;
9005895Syz147064 
901*8453SAnurag.Maskey@Sun.COM 	(void) dladm_walk_datalink_id(i_dladm_walk_dev2linkid, handle, &state,
9025895Syz147064 	    DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST);
9035895Syz147064 	if (state.found == B_TRUE) {
9045895Syz147064 		*linkidp = state.linkid;
9055895Syz147064 		return (DLADM_STATUS_OK);
9065895Syz147064 	} else {
9075895Syz147064 		return (dladm_errno2status(ENOENT));
9085895Syz147064 	}
9095895Syz147064 }
9105895Syz147064 
9115895Syz147064 static int
9125895Syz147064 parse_devname(const char *devname, char *driver, uint_t *ppa, size_t maxlen)
9135895Syz147064 {
9145895Syz147064 	char	*cp, *tp;
9155895Syz147064 	int	len;
9165895Syz147064 
9175895Syz147064 	/*
9185895Syz147064 	 * device name length must not be 0, and it must end with digit.
9195895Syz147064 	 */
9205895Syz147064 	if (((len = strlen(devname)) == 0) || !isdigit(devname[len - 1]))
9215895Syz147064 		return (EINVAL);
9225895Syz147064 
9235895Syz147064 	(void) strlcpy(driver, devname, maxlen);
9245895Syz147064 	cp = (char *)&driver[len - 1];
9255895Syz147064 
9265895Syz147064 	for (tp = cp; isdigit(*tp); tp--) {
9275895Syz147064 		if (tp <= driver)
9285895Syz147064 			return (EINVAL);
9295895Syz147064 	}
9305895Syz147064 
9315895Syz147064 	*ppa = atoi(tp + 1);
9325895Syz147064 	*(tp + 1) = '\0';
9335895Syz147064 	return (0);
9345895Syz147064 }
9355895Syz147064 
9365895Syz147064 dladm_status_t
937*8453SAnurag.Maskey@Sun.COM dladm_linkid2legacyname(dladm_handle_t handle, datalink_id_t linkid, char *dev,
938*8453SAnurag.Maskey@Sun.COM     size_t len)
9393871Syz147064 {
9405895Syz147064 	char			devname[MAXLINKNAMELEN];
9415895Syz147064 	uint16_t		vid = VLAN_ID_NONE;
9425895Syz147064 	datalink_class_t	class;
9435895Syz147064 	dladm_status_t		status;
9445895Syz147064 
945*8453SAnurag.Maskey@Sun.COM 	status = dladm_datalink_id2info(handle, linkid, NULL, &class, NULL,
946*8453SAnurag.Maskey@Sun.COM 	    NULL, 0);
9475895Syz147064 	if (status != DLADM_STATUS_OK)
9485895Syz147064 		goto done;
9495895Syz147064 
9505895Syz147064 	/*
9515895Syz147064 	 * If this is a VLAN, we must first determine the class and linkid of
9525895Syz147064 	 * the link the VLAN has been created over.
9535895Syz147064 	 */
9545895Syz147064 	if (class == DATALINK_CLASS_VLAN) {
9555895Syz147064 		dladm_vlan_attr_t	dva;
9565895Syz147064 
957*8453SAnurag.Maskey@Sun.COM 		status = dladm_vlan_info(handle, linkid, &dva,
958*8453SAnurag.Maskey@Sun.COM 		    DLADM_OPT_ACTIVE);
9595895Syz147064 		if (status != DLADM_STATUS_OK)
9605895Syz147064 			goto done;
9615895Syz147064 		linkid = dva.dv_linkid;
9625895Syz147064 		vid = dva.dv_vid;
9635895Syz147064 
964*8453SAnurag.Maskey@Sun.COM 		if ((status = dladm_datalink_id2info(handle, linkid, NULL,
965*8453SAnurag.Maskey@Sun.COM 		    &class, NULL, NULL, 0)) != DLADM_STATUS_OK) {
9665895Syz147064 			goto done;
9675895Syz147064 		}
9685895Syz147064 	}
9695895Syz147064 
9705895Syz147064 	switch (class) {
9715895Syz147064 	case DATALINK_CLASS_AGGR: {
9725895Syz147064 		dladm_aggr_grp_attr_t	dga;
9735895Syz147064 
974*8453SAnurag.Maskey@Sun.COM 		status = dladm_aggr_info(handle, linkid, &dga,
975*8453SAnurag.Maskey@Sun.COM 		    DLADM_OPT_ACTIVE);
9765895Syz147064 		if (status != DLADM_STATUS_OK)
9775895Syz147064 			goto done;
9785895Syz147064 
9795895Syz147064 		if (dga.lg_key == 0) {
9805895Syz147064 			/*
9815895Syz147064 			 * If the key was not specified when the aggregation
9825895Syz147064 			 * is created, we cannot guess its /dev node name.
9835895Syz147064 			 */
9845895Syz147064 			status = DLADM_STATUS_BADARG;
9855895Syz147064 			goto done;
9865895Syz147064 		}
9875895Syz147064 		(void) snprintf(devname, MAXLINKNAMELEN, "aggr%d", dga.lg_key);
9885895Syz147064 		break;
9895895Syz147064 	}
9905895Syz147064 	case DATALINK_CLASS_PHYS: {
9915895Syz147064 		dladm_phys_attr_t	dpa;
9925895Syz147064 
993*8453SAnurag.Maskey@Sun.COM 		status = dladm_phys_info(handle, linkid, &dpa,
994*8453SAnurag.Maskey@Sun.COM 		    DLADM_OPT_PERSIST);
9955895Syz147064 		if (status != DLADM_STATUS_OK)
9965895Syz147064 			goto done;
9975895Syz147064 
9985895Syz147064 		(void) strlcpy(devname, dpa.dp_dev, MAXLINKNAMELEN);
9995895Syz147064 		break;
10005895Syz147064 	}
10015895Syz147064 	default:
10025895Syz147064 		status = DLADM_STATUS_BADARG;
10035895Syz147064 		goto done;
10045895Syz147064 	}
10055895Syz147064 
10065895Syz147064 	if (vid != VLAN_ID_NONE) {
10075895Syz147064 		char		drv[MAXNAMELEN];
10085895Syz147064 		uint_t		ppa;
10095895Syz147064 
10105895Syz147064 		if (parse_devname(devname, drv, &ppa, MAXNAMELEN) != 0) {
10115895Syz147064 			status = DLADM_STATUS_BADARG;
10125895Syz147064 			goto done;
10135895Syz147064 		}
10145895Syz147064 		if (snprintf(dev, len, "%s%d", drv, vid * 1000 + ppa) >= len)
10155895Syz147064 			status = DLADM_STATUS_TOOSMALL;
10165895Syz147064 	} else {
10175895Syz147064 		if (strlcpy(dev, devname, len) >= len)
10185895Syz147064 			status = DLADM_STATUS_TOOSMALL;
10195895Syz147064 	}
10205895Syz147064 
10215895Syz147064 done:
10225895Syz147064 	return (status);
10233871Syz147064 }
10245903Ssowmini 
10255903Ssowmini dladm_status_t
10265903Ssowmini dladm_parselink(const char *dev, char *provider, uint_t *ppa)
10275903Ssowmini {
10285903Ssowmini 	ifspec_t	ifsp;
10295903Ssowmini 
10305903Ssowmini 	if (dev == NULL || !ifparse_ifspec(dev, &ifsp))
10315903Ssowmini 		return (DLADM_STATUS_LINKINVAL);
10325903Ssowmini 
10335903Ssowmini 	if (provider != NULL)
10345903Ssowmini 		(void) strlcpy(provider, ifsp.ifsp_devnm, DLPI_LINKNAME_MAX);
10355903Ssowmini 
10365903Ssowmini 	if (ppa != NULL)
10375903Ssowmini 		*ppa = ifsp.ifsp_ppa;
10385903Ssowmini 
10395903Ssowmini 	return (DLADM_STATUS_OK);
10405903Ssowmini }
1041