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 #pragma ident "%Z%%M% %I% %E% SMI" 273871Syz147064 283871Syz147064 #include <sys/types.h> 293871Syz147064 #include <unistd.h> 303871Syz147064 #include <errno.h> 313871Syz147064 #include <fcntl.h> 325895Syz147064 #include <assert.h> 335895Syz147064 #include <ctype.h> 343871Syz147064 #include <strings.h> 353871Syz147064 #include <sys/stat.h> 363871Syz147064 #include <sys/dld.h> 375895Syz147064 #include <sys/vlan.h> 385895Syz147064 #include <librcm.h> 393871Syz147064 #include <libdlpi.h> 403871Syz147064 #include <libdevinfo.h> 415895Syz147064 #include <libdlaggr.h> 425895Syz147064 #include <libdlvlan.h> 433871Syz147064 #include <libdllink.h> 445895Syz147064 #include <libdlmgmt.h> 453871Syz147064 #include <libdladm_impl.h> 46*5903Ssowmini #include <libinetutil.h> 473871Syz147064 483871Syz147064 /* 493871Syz147064 * Return the attributes of the specified datalink from the DLD driver. 503871Syz147064 */ 515895Syz147064 static dladm_status_t 525895Syz147064 i_dladm_info(int fd, const datalink_id_t linkid, dladm_attr_t *dap) 533871Syz147064 { 543871Syz147064 dld_ioc_attr_t dia; 553871Syz147064 565895Syz147064 dia.dia_linkid = linkid; 573871Syz147064 585895Syz147064 if (i_dladm_ioctl(fd, DLDIOC_ATTR, &dia, sizeof (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 665895Syz147064 struct i_dladm_walk_arg { 675895Syz147064 dladm_walkcb_t *fn; 685895Syz147064 void *arg; 695895Syz147064 }; 703871Syz147064 715895Syz147064 static int 725895Syz147064 i_dladm_walk(datalink_id_t linkid, void *arg) 735895Syz147064 { 745895Syz147064 struct i_dladm_walk_arg *walk_arg = arg; 755895Syz147064 char link[MAXLINKNAMELEN]; 763871Syz147064 775895Syz147064 if (dladm_datalink_id2info(linkid, NULL, NULL, NULL, link, 785895Syz147064 sizeof (link)) == DLADM_STATUS_OK) { 795895Syz147064 return (walk_arg->fn(link, walk_arg->arg)); 803871Syz147064 } 813871Syz147064 825895Syz147064 return (DLADM_WALK_CONTINUE); 833871Syz147064 } 843871Syz147064 853871Syz147064 /* 865895Syz147064 * Walk all datalinks. 873871Syz147064 */ 885895Syz147064 dladm_status_t 895895Syz147064 dladm_walk(dladm_walkcb_t *fn, void *arg, datalink_class_t class, 905895Syz147064 datalink_media_t dmedia, uint32_t flags) 913871Syz147064 { 925895Syz147064 struct i_dladm_walk_arg walk_arg; 933871Syz147064 945895Syz147064 walk_arg.fn = fn; 955895Syz147064 walk_arg.arg = arg; 965895Syz147064 return (dladm_walk_datalink_id(i_dladm_walk, &walk_arg, 975895Syz147064 class, dmedia, flags)); 983871Syz147064 } 993871Syz147064 1003871Syz147064 /* 1015895Syz147064 * These routines are used by administration tools such as dladm(1M) to 1023871Syz147064 * iterate through the list of MAC interfaces 1033871Syz147064 */ 1043871Syz147064 1053871Syz147064 typedef struct dladm_mac_dev { 1063871Syz147064 char dm_name[MAXNAMELEN]; 1075895Syz147064 struct dladm_mac_dev *dm_next; 1083871Syz147064 } dladm_mac_dev_t; 1093871Syz147064 1103871Syz147064 typedef struct macadm_walk { 1115895Syz147064 dladm_mac_dev_t *dmd_dev_list; 1123871Syz147064 } dladm_mac_walk_t; 1133871Syz147064 1143871Syz147064 /* 1153871Syz147064 * Local callback invoked for each DDI_NT_NET node. 1163871Syz147064 */ 1173871Syz147064 /* ARGSUSED */ 1183871Syz147064 static int 1193871Syz147064 i_dladm_mac_walk(di_node_t node, di_minor_t minor, void *arg) 1203871Syz147064 { 1213871Syz147064 dladm_mac_walk_t *dmwp = arg; 1223871Syz147064 dladm_mac_dev_t *dmdp = dmwp->dmd_dev_list; 1233871Syz147064 dladm_mac_dev_t **last_dmdp = &dmwp->dmd_dev_list; 1243871Syz147064 char mac[MAXNAMELEN]; 1253871Syz147064 1263871Syz147064 (void) snprintf(mac, MAXNAMELEN, "%s%d", 1273871Syz147064 di_driver_name(node), di_instance(node)); 1283871Syz147064 1293871Syz147064 /* 1303871Syz147064 * Skip aggregations. 1313871Syz147064 */ 1323871Syz147064 if (strcmp("aggr", di_driver_name(node)) == 0) 1333871Syz147064 return (DI_WALK_CONTINUE); 1343871Syz147064 1355895Syz147064 /* 1365895Syz147064 * Skip softmacs. 1375895Syz147064 */ 1385895Syz147064 if (strcmp("softmac", di_driver_name(node)) == 0) 1395895Syz147064 return (DI_WALK_CONTINUE); 1405895Syz147064 1413871Syz147064 while (dmdp) { 1423871Syz147064 /* 1433871Syz147064 * Skip duplicates. 1443871Syz147064 */ 1453871Syz147064 if (strcmp(dmdp->dm_name, mac) == 0) 1463871Syz147064 return (DI_WALK_CONTINUE); 1473871Syz147064 1483871Syz147064 last_dmdp = &dmdp->dm_next; 1493871Syz147064 dmdp = dmdp->dm_next; 1503871Syz147064 } 1513871Syz147064 1523871Syz147064 if ((dmdp = malloc(sizeof (*dmdp))) == NULL) 1533871Syz147064 return (DI_WALK_CONTINUE); 1543871Syz147064 1553871Syz147064 (void) strlcpy(dmdp->dm_name, mac, MAXNAMELEN); 1563871Syz147064 dmdp->dm_next = NULL; 1573871Syz147064 *last_dmdp = dmdp; 1583871Syz147064 1593871Syz147064 return (DI_WALK_CONTINUE); 1603871Syz147064 } 1613871Syz147064 1623871Syz147064 /* 1635895Syz147064 * Invoke the specified callback for each DDI_NT_NET node. 1643871Syz147064 */ 1655895Syz147064 dladm_status_t 1665895Syz147064 dladm_mac_walk(int (*fn)(const char *, void *arg), void *arg) 1673871Syz147064 { 1683871Syz147064 di_node_t root; 1693871Syz147064 dladm_mac_walk_t dmw; 1703871Syz147064 dladm_mac_dev_t *dmdp, *next; 1715895Syz147064 boolean_t done = B_FALSE; 1723871Syz147064 1733871Syz147064 if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL) 1745895Syz147064 return (dladm_errno2status(errno)); 1753871Syz147064 1763871Syz147064 dmw.dmd_dev_list = NULL; 1773871Syz147064 1783871Syz147064 (void) di_walk_minor(root, DDI_NT_NET, DI_CHECK_ALIAS, &dmw, 1793871Syz147064 i_dladm_mac_walk); 1803871Syz147064 1813871Syz147064 di_fini(root); 1823871Syz147064 1833871Syz147064 dmdp = dmw.dmd_dev_list; 1843871Syz147064 for (dmdp = dmw.dmd_dev_list; dmdp != NULL; dmdp = next) { 1853871Syz147064 next = dmdp->dm_next; 1865895Syz147064 if (!done && 1875895Syz147064 ((*fn)(dmdp->dm_name, arg) == DLADM_WALK_TERMINATE)) { 1885895Syz147064 done = B_TRUE; 1895895Syz147064 } 1903871Syz147064 free(dmdp); 1913871Syz147064 } 1923871Syz147064 1935895Syz147064 return (DLADM_STATUS_OK); 1943871Syz147064 } 1953871Syz147064 1963871Syz147064 /* 1975895Syz147064 * Get the current attributes of the specified datalink. 1983871Syz147064 */ 1995895Syz147064 dladm_status_t 2005895Syz147064 dladm_info(datalink_id_t linkid, dladm_attr_t *dap) 2013871Syz147064 { 2023871Syz147064 int fd; 2035895Syz147064 dladm_status_t status; 2043871Syz147064 2053871Syz147064 if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) 2065895Syz147064 return (dladm_errno2status(errno)); 2073871Syz147064 2085895Syz147064 status = i_dladm_info(fd, linkid, dap); 2093871Syz147064 2103871Syz147064 (void) close(fd); 2115895Syz147064 return (status); 2123871Syz147064 } 2133871Syz147064 2143871Syz147064 const char * 2153871Syz147064 dladm_linkstate2str(link_state_t state, char *buf) 2163871Syz147064 { 2173871Syz147064 const char *s; 2183871Syz147064 2193871Syz147064 switch (state) { 2203871Syz147064 case LINK_STATE_UP: 2213871Syz147064 s = "up"; 2223871Syz147064 break; 2233871Syz147064 case LINK_STATE_DOWN: 2243871Syz147064 s = "down"; 2253871Syz147064 break; 2263871Syz147064 default: 2273871Syz147064 s = "unknown"; 2283871Syz147064 break; 2293871Syz147064 } 2303871Syz147064 (void) snprintf(buf, DLADM_STRSIZE, "%s", s); 2313871Syz147064 return (buf); 2323871Syz147064 } 2333871Syz147064 2343871Syz147064 const char * 2353871Syz147064 dladm_linkduplex2str(link_duplex_t duplex, char *buf) 2363871Syz147064 { 2373871Syz147064 const char *s; 2383871Syz147064 2393871Syz147064 switch (duplex) { 2403871Syz147064 case LINK_DUPLEX_FULL: 2413871Syz147064 s = "full"; 2423871Syz147064 break; 2433871Syz147064 case LINK_DUPLEX_HALF: 2443871Syz147064 s = "half"; 2453871Syz147064 break; 2463871Syz147064 default: 2473871Syz147064 s = "unknown"; 2483871Syz147064 break; 2493871Syz147064 } 2503871Syz147064 (void) snprintf(buf, DLADM_STRSIZE, "%s", s); 2513871Syz147064 return (buf); 2523871Syz147064 } 2533871Syz147064 2543871Syz147064 /* 2555895Syz147064 * Set zoneid of a given link 2565895Syz147064 */ 2575895Syz147064 dladm_status_t 2585895Syz147064 dladm_setzid(const char *link, zoneid_t zoneid) 2595895Syz147064 { 2605895Syz147064 int fd; 2615895Syz147064 dladm_status_t status = DLADM_STATUS_OK; 2625895Syz147064 dld_ioc_setzid_t dis; 2635895Syz147064 2645895Syz147064 if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) 2655895Syz147064 return (dladm_errno2status(errno)); 2665895Syz147064 2675895Syz147064 bzero(&dis, sizeof (dld_ioc_setzid_t)); 2685895Syz147064 (void) strlcpy(dis.dis_link, link, MAXLINKNAMELEN); 2695895Syz147064 dis.dis_zid = zoneid; 2705895Syz147064 2715895Syz147064 if (i_dladm_ioctl(fd, DLDIOC_SETZID, &dis, sizeof (dis)) < 0) 2725895Syz147064 status = dladm_errno2status(errno); 2735895Syz147064 2745895Syz147064 (void) close(fd); 2755895Syz147064 return (status); 2765895Syz147064 } 2775895Syz147064 2785895Syz147064 /* 2795895Syz147064 * Get zoneid of a given link 2805895Syz147064 */ 2815895Syz147064 dladm_status_t 2825895Syz147064 dladm_getzid(datalink_id_t linkid, zoneid_t *zoneidp) 2835895Syz147064 { 2845895Syz147064 int fd; 2855895Syz147064 dladm_status_t status = DLADM_STATUS_OK; 2865895Syz147064 dld_ioc_getzid_t dig; 2875895Syz147064 2885895Syz147064 if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) 2895895Syz147064 return (dladm_errno2status(errno)); 2905895Syz147064 2915895Syz147064 bzero(&dig, sizeof (dld_ioc_getzid_t)); 2925895Syz147064 dig.dig_linkid = linkid; 2935895Syz147064 dig.dig_zid = -1; 2945895Syz147064 2955895Syz147064 if (i_dladm_ioctl(fd, DLDIOC_GETZID, &dig, sizeof (dig)) < 0) 2965895Syz147064 status = dladm_errno2status(errno); 2975895Syz147064 2985895Syz147064 (void) close(fd); 2995895Syz147064 3005895Syz147064 if (status == DLADM_STATUS_OK) 3015895Syz147064 *zoneidp = dig.dig_zid; 3025895Syz147064 3035895Syz147064 return (status); 3045895Syz147064 } 3055895Syz147064 3065895Syz147064 /* 3075895Syz147064 * Case 1: rename an existing link1 to a link2 that does not exist. 3085895Syz147064 * Result: <linkid1, link2> 3093871Syz147064 */ 3105895Syz147064 static dladm_status_t 3115895Syz147064 i_dladm_rename_link_c1(datalink_id_t linkid1, const char *link1, 3125895Syz147064 const char *link2, uint32_t flags) 3135895Syz147064 { 3145895Syz147064 dld_ioc_rename_t dir; 3155895Syz147064 dladm_conf_t conf; 3165895Syz147064 dladm_status_t status = DLADM_STATUS_OK; 3175895Syz147064 int fd; 3185895Syz147064 3195895Syz147064 /* 3205895Syz147064 * Link is currently available. Check to see whether anything is 3215895Syz147064 * holding this link to prevent a rename operation. 3225895Syz147064 */ 3235895Syz147064 if (flags & DLADM_OPT_ACTIVE) { 3245895Syz147064 dir.dir_linkid1 = linkid1; 3255895Syz147064 dir.dir_linkid2 = DATALINK_INVALID_LINKID; 3265895Syz147064 (void) strlcpy(dir.dir_link, link2, MAXLINKNAMELEN); 3275895Syz147064 if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) 3285895Syz147064 return (dladm_errno2status(errno)); 3295895Syz147064 3305895Syz147064 if (i_dladm_ioctl(fd, DLDIOC_RENAME, &dir, sizeof (dir)) < 0) { 3315895Syz147064 status = dladm_errno2status(errno); 3325895Syz147064 (void) close(fd); 3335895Syz147064 return (status); 3345895Syz147064 } 3355895Syz147064 } 3365895Syz147064 3375895Syz147064 status = dladm_remap_datalink_id(linkid1, link2); 3385895Syz147064 if (status != DLADM_STATUS_OK) 3395895Syz147064 goto done; 3405895Syz147064 3415895Syz147064 /* 3425895Syz147064 * Flush the current mapping to persistent configuration. 3435895Syz147064 */ 3445895Syz147064 if ((flags & DLADM_OPT_PERSIST) && 3455895Syz147064 (((status = dladm_read_conf(linkid1, &conf)) != DLADM_STATUS_OK) || 3465895Syz147064 ((status = dladm_write_conf(conf)) != DLADM_STATUS_OK))) { 3475895Syz147064 (void) dladm_remap_datalink_id(linkid1, link1); 3485895Syz147064 } 3495895Syz147064 done: 3505895Syz147064 if (flags & DLADM_OPT_ACTIVE) { 3515895Syz147064 if (status != DLADM_STATUS_OK) { 3525895Syz147064 (void) strlcpy(dir.dir_link, link1, MAXLINKNAMELEN); 3535895Syz147064 (void) i_dladm_ioctl(fd, DLDIOC_RENAME, &dir, 3545895Syz147064 sizeof (dir)); 3555895Syz147064 } 3565895Syz147064 (void) close(fd); 3575895Syz147064 } 3585895Syz147064 return (status); 3595895Syz147064 } 3605895Syz147064 3615895Syz147064 typedef struct link_hold_arg_s { 3625895Syz147064 datalink_id_t linkid; 3635895Syz147064 datalink_id_t holder; 3645895Syz147064 uint32_t flags; 3655895Syz147064 } link_hold_arg_t; 3665895Syz147064 3675895Syz147064 static int 3685895Syz147064 i_dladm_aggr_link_hold(datalink_id_t aggrid, void *arg) 3695895Syz147064 { 3705895Syz147064 link_hold_arg_t *hold_arg = arg; 3715895Syz147064 dladm_aggr_grp_attr_t ginfo; 3725895Syz147064 dladm_status_t status; 3735895Syz147064 int i; 3745895Syz147064 3755895Syz147064 status = dladm_aggr_info(aggrid, &ginfo, hold_arg->flags); 3765895Syz147064 if (status != DLADM_STATUS_OK) 3775895Syz147064 return (DLADM_WALK_CONTINUE); 3785895Syz147064 3795895Syz147064 for (i = 0; i < ginfo.lg_nports; i++) { 3805895Syz147064 if (ginfo.lg_ports[i].lp_linkid == hold_arg->linkid) { 3815895Syz147064 hold_arg->holder = aggrid; 3825895Syz147064 return (DLADM_WALK_TERMINATE); 3835895Syz147064 } 3845895Syz147064 } 3855895Syz147064 return (DLADM_WALK_CONTINUE); 3865895Syz147064 } 3875895Syz147064 3885895Syz147064 static int 3895895Syz147064 i_dladm_vlan_link_hold(datalink_id_t vlanid, void *arg) 3905895Syz147064 { 3915895Syz147064 link_hold_arg_t *hold_arg = arg; 3925895Syz147064 dladm_vlan_attr_t vinfo; 3935895Syz147064 dladm_status_t status; 3945895Syz147064 3955895Syz147064 status = dladm_vlan_info(vlanid, &vinfo, hold_arg->flags); 3965895Syz147064 if (status != DLADM_STATUS_OK) 3975895Syz147064 return (DLADM_WALK_CONTINUE); 3985895Syz147064 3995895Syz147064 if (vinfo.dv_linkid == hold_arg->linkid) { 4005895Syz147064 hold_arg->holder = vlanid; 4015895Syz147064 return (DLADM_WALK_TERMINATE); 4025895Syz147064 } 4035895Syz147064 return (DLADM_WALK_CONTINUE); 4045895Syz147064 } 4055895Syz147064 4065895Syz147064 /* 4075895Syz147064 * Case 2: rename an available physical link link1 to a REMOVED physical link 4085895Syz147064 * link2. As a result, link1 directly inherits all datalinks configured 4095895Syz147064 * over link2 (linkid2). 4105895Syz147064 * Result: <linkid2, link2, link1_phymaj, link1_phyinst, link1_devname, 4115895Syz147064 * link2_other_attr> 4125895Syz147064 */ 4135895Syz147064 static dladm_status_t 4145895Syz147064 i_dladm_rename_link_c2(datalink_id_t linkid1, datalink_id_t linkid2) 4153871Syz147064 { 4165895Syz147064 rcm_handle_t *rcm_hdl = NULL; 4175895Syz147064 nvlist_t *nvl = NULL; 4185895Syz147064 link_hold_arg_t arg; 4195895Syz147064 dld_ioc_rename_t dir; 4205895Syz147064 int fd; 4215895Syz147064 dladm_conf_t conf1, conf2; 4225895Syz147064 char devname[MAXLINKNAMELEN]; 4235895Syz147064 uint64_t phymaj, phyinst; 4245895Syz147064 dladm_status_t status = DLADM_STATUS_OK; 4255895Syz147064 4265895Syz147064 /* 4275895Syz147064 * First check if linkid1 is associated with any persistent 4285895Syz147064 * aggregations or VLANs. If yes, return BUSY. 4295895Syz147064 */ 4305895Syz147064 arg.linkid = linkid1; 4315895Syz147064 arg.holder = DATALINK_INVALID_LINKID; 4325895Syz147064 arg.flags = DLADM_OPT_PERSIST; 4335895Syz147064 (void) dladm_walk_datalink_id(i_dladm_aggr_link_hold, &arg, 4345895Syz147064 DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 4355895Syz147064 if (arg.holder != DATALINK_INVALID_LINKID) 4365895Syz147064 return (DLADM_STATUS_LINKBUSY); 4375895Syz147064 4385895Syz147064 arg.flags = DLADM_OPT_PERSIST; 4395895Syz147064 (void) dladm_walk_datalink_id(i_dladm_vlan_link_hold, &arg, 4405895Syz147064 DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 4415895Syz147064 if (arg.holder != DATALINK_INVALID_LINKID) 4425895Syz147064 return (DLADM_STATUS_LINKBUSY); 4435895Syz147064 4445895Syz147064 /* 4455895Syz147064 * Send DLDIOC_RENAME to request to rename link1's linkid to 4465895Syz147064 * be linkid2. This will check whether link1 is used by any 4475895Syz147064 * aggregations or VLANs, or is held by any application. If yes, 4485895Syz147064 * return failure. 4495895Syz147064 */ 4505895Syz147064 if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) 4515895Syz147064 return (dladm_errno2status(errno)); 4525895Syz147064 4535895Syz147064 dir.dir_linkid1 = linkid1; 4545895Syz147064 dir.dir_linkid2 = linkid2; 4555895Syz147064 if (i_dladm_ioctl(fd, DLDIOC_RENAME, &dir, sizeof (dir)) < 0) 4565895Syz147064 status = dladm_errno2status(errno); 4575895Syz147064 4585895Syz147064 if (status != DLADM_STATUS_OK) { 4595895Syz147064 (void) close(fd); 4605895Syz147064 return (status); 4615895Syz147064 } 4625895Syz147064 4635895Syz147064 /* 4645895Syz147064 * Now change the phymaj, phyinst and devname associated with linkid1 4655895Syz147064 * to be associated with linkid2. Before doing that, the old active 4665895Syz147064 * linkprop of linkid1 should be deleted. 4675895Syz147064 */ 4685895Syz147064 (void) dladm_set_linkprop(linkid1, NULL, NULL, 0, DLADM_OPT_ACTIVE); 4695895Syz147064 4705895Syz147064 if (((status = dladm_read_conf(linkid1, &conf1)) != DLADM_STATUS_OK) || 4715895Syz147064 ((status = dladm_get_conf_field(conf1, FDEVNAME, devname, 4725895Syz147064 MAXLINKNAMELEN)) != DLADM_STATUS_OK) || 4735895Syz147064 ((status = dladm_get_conf_field(conf1, FPHYMAJ, &phymaj, 4745895Syz147064 sizeof (uint64_t))) != DLADM_STATUS_OK) || 4755895Syz147064 ((status = dladm_get_conf_field(conf1, FPHYINST, &phyinst, 4765895Syz147064 sizeof (uint64_t))) != DLADM_STATUS_OK) || 4775895Syz147064 ((status = dladm_read_conf(linkid2, &conf2)) != DLADM_STATUS_OK)) { 4785895Syz147064 dir.dir_linkid1 = linkid2; 4795895Syz147064 dir.dir_linkid2 = linkid1; 4805895Syz147064 (void) dladm_init_linkprop(linkid1); 4815895Syz147064 (void) i_dladm_ioctl(fd, DLDIOC_RENAME, &dir, sizeof (dir)); 4825895Syz147064 (void) close(fd); 4835895Syz147064 return (status); 4845895Syz147064 } 4855895Syz147064 (void) close(fd); 4865895Syz147064 4875895Syz147064 dladm_destroy_conf(conf1); 4885895Syz147064 (void) dladm_set_conf_field(conf2, FDEVNAME, DLADM_TYPE_STR, devname); 4895895Syz147064 (void) dladm_set_conf_field(conf2, FPHYMAJ, DLADM_TYPE_UINT64, &phymaj); 4905895Syz147064 (void) dladm_set_conf_field(conf2, FPHYINST, 4915895Syz147064 DLADM_TYPE_UINT64, &phyinst); 4925895Syz147064 (void) dladm_write_conf(conf2); 4935895Syz147064 dladm_destroy_conf(conf2); 4945895Syz147064 4955895Syz147064 /* 4965895Syz147064 * Delete link1 and mark link2 up. 4975895Syz147064 */ 4985895Syz147064 (void) dladm_destroy_datalink_id(linkid1, DLADM_OPT_ACTIVE | 4995895Syz147064 DLADM_OPT_PERSIST); 5005895Syz147064 (void) dladm_remove_conf(linkid1); 5015895Syz147064 (void) dladm_up_datalink_id(linkid2); 5025895Syz147064 5035895Syz147064 /* 5045895Syz147064 * Now generate the RCM_RESOURCE_LINK_NEW sysevent which can be 5055895Syz147064 * consumed by the RCM framework to restore all the datalink and 5065895Syz147064 * IP configuration. 5075895Syz147064 */ 5085895Syz147064 status = DLADM_STATUS_FAILED; 5095895Syz147064 if ((nvlist_alloc(&nvl, 0, 0) != 0) || 5105895Syz147064 (nvlist_add_uint64(nvl, RCM_NV_LINKID, linkid2) != 0)) { 5115895Syz147064 goto done; 5125895Syz147064 } 5135895Syz147064 5145895Syz147064 if (rcm_alloc_handle(NULL, 0, NULL, &rcm_hdl) != RCM_SUCCESS) 5155895Syz147064 goto done; 5165895Syz147064 5175895Syz147064 if (rcm_notify_event(rcm_hdl, RCM_RESOURCE_LINK_NEW, 0, nvl, NULL) == 5185895Syz147064 RCM_SUCCESS) { 5195895Syz147064 status = DLADM_STATUS_OK; 5205895Syz147064 } 5215895Syz147064 5225895Syz147064 done: 5235895Syz147064 if (rcm_hdl != NULL) 5245895Syz147064 (void) rcm_free_handle(rcm_hdl); 5255895Syz147064 if (nvl != NULL) 5265895Syz147064 nvlist_free(nvl); 5275895Syz147064 return (status); 5283871Syz147064 } 5293871Syz147064 5303871Syz147064 /* 5315895Syz147064 * case 3: rename a non-existent link to a REMOVED physical link. 5325895Syz147064 * Set the removed physical link's device name to link1, so that 5335895Syz147064 * when link1 attaches, it inherits all the link configuration of 5345895Syz147064 * the removed physical link. 5353871Syz147064 */ 5365895Syz147064 static dladm_status_t 5375895Syz147064 i_dladm_rename_link_c3(const char *link1, datalink_id_t linkid2) 5385895Syz147064 { 5395895Syz147064 dladm_conf_t conf; 5405895Syz147064 dladm_status_t status; 5415895Syz147064 5425895Syz147064 if (!dladm_valid_linkname(link1)) 5435895Syz147064 return (DLADM_STATUS_LINKINVAL); 5445895Syz147064 5455895Syz147064 status = dladm_read_conf(linkid2, &conf); 5465895Syz147064 if (status != DLADM_STATUS_OK) 5475895Syz147064 goto done; 5485895Syz147064 5495895Syz147064 if ((status = dladm_set_conf_field(conf, FDEVNAME, DLADM_TYPE_STR, 5505895Syz147064 link1)) == DLADM_STATUS_OK) { 5515895Syz147064 status = dladm_write_conf(conf); 5525895Syz147064 } 5535895Syz147064 5545895Syz147064 dladm_destroy_conf(conf); 5555895Syz147064 5565895Syz147064 done: 5575895Syz147064 return (status); 5585895Syz147064 } 5595895Syz147064 5605895Syz147064 dladm_status_t 5615895Syz147064 dladm_rename_link(const char *link1, const char *link2) 5625895Syz147064 { 5635895Syz147064 datalink_id_t linkid1 = DATALINK_INVALID_LINKID; 5645895Syz147064 datalink_id_t linkid2 = DATALINK_INVALID_LINKID; 5655895Syz147064 uint32_t flags1, flags2; 5665895Syz147064 datalink_class_t class1, class2; 5675895Syz147064 uint32_t media1, media2; 5685895Syz147064 boolean_t remphy2 = B_FALSE; 5695895Syz147064 dladm_status_t status; 5705895Syz147064 5715895Syz147064 (void) dladm_name2info(link1, &linkid1, &flags1, &class1, &media1); 5725895Syz147064 if ((dladm_name2info(link2, &linkid2, &flags2, &class2, &media2) == 5735895Syz147064 DLADM_STATUS_OK) && (class2 == DATALINK_CLASS_PHYS) && 5745895Syz147064 (flags2 == DLADM_OPT_PERSIST)) { 5755895Syz147064 /* 5765895Syz147064 * see whether link2 is a removed physical link. 5775895Syz147064 */ 5785895Syz147064 remphy2 = B_TRUE; 5795895Syz147064 } 5805895Syz147064 5815895Syz147064 if (linkid1 != DATALINK_INVALID_LINKID) { 5825895Syz147064 if (linkid2 == DATALINK_INVALID_LINKID) { 5835895Syz147064 /* 5845895Syz147064 * case 1: rename an existing link to a link that 5855895Syz147064 * does not exist. 5865895Syz147064 */ 5875895Syz147064 status = i_dladm_rename_link_c1(linkid1, link1, link2, 5885895Syz147064 flags1); 5895895Syz147064 } else if (remphy2) { 5905895Syz147064 /* 5915895Syz147064 * case 2: rename an available link to a REMOVED 5925895Syz147064 * physical link. Return failure if link1 is not 5935895Syz147064 * an active physical link. 5945895Syz147064 */ 5955895Syz147064 if ((class1 != class2) || (media1 != media2) || 5965895Syz147064 !(flags1 & DLADM_OPT_ACTIVE)) { 5975895Syz147064 status = DLADM_STATUS_BADARG; 5985895Syz147064 } else { 5995895Syz147064 status = i_dladm_rename_link_c2(linkid1, 6005895Syz147064 linkid2); 6015895Syz147064 } 6025895Syz147064 } else { 6035895Syz147064 status = DLADM_STATUS_EXIST; 6045895Syz147064 } 6055895Syz147064 } else if (remphy2) { 6065895Syz147064 status = i_dladm_rename_link_c3(link1, linkid2); 6075895Syz147064 } else { 6085895Syz147064 status = DLADM_STATUS_NOTFOUND; 6095895Syz147064 } 6105895Syz147064 return (status); 6115895Syz147064 } 6125895Syz147064 6135895Syz147064 typedef struct consumer_del_phys_arg_s { 6145895Syz147064 datalink_id_t linkid; 6155895Syz147064 } consumer_del_phys_arg_t; 6165895Syz147064 6175895Syz147064 static int 6185895Syz147064 i_dladm_vlan_link_del(datalink_id_t vlanid, void *arg) 6195895Syz147064 { 6205895Syz147064 consumer_del_phys_arg_t *del_arg = arg; 6215895Syz147064 dladm_vlan_attr_t vinfo; 6225895Syz147064 dladm_status_t status; 6235895Syz147064 6245895Syz147064 status = dladm_vlan_info(vlanid, &vinfo, DLADM_OPT_PERSIST); 6255895Syz147064 if (status != DLADM_STATUS_OK) 6265895Syz147064 return (DLADM_WALK_CONTINUE); 6275895Syz147064 6285895Syz147064 if (vinfo.dv_linkid == del_arg->linkid) 6295895Syz147064 (void) dladm_vlan_delete(vlanid, DLADM_OPT_PERSIST); 6305895Syz147064 return (DLADM_WALK_CONTINUE); 6315895Syz147064 } 6325895Syz147064 6335895Syz147064 static int 6345895Syz147064 i_dladm_aggr_link_del(datalink_id_t aggrid, void *arg) 6355895Syz147064 { 6365895Syz147064 consumer_del_phys_arg_t *del_arg = arg; 6375895Syz147064 dladm_aggr_grp_attr_t ginfo; 6385895Syz147064 dladm_status_t status; 6395895Syz147064 dladm_aggr_port_attr_db_t port[1]; 6405895Syz147064 int i; 6415895Syz147064 6425895Syz147064 status = dladm_aggr_info(aggrid, &ginfo, DLADM_OPT_PERSIST); 6435895Syz147064 if (status != DLADM_STATUS_OK) 6445895Syz147064 return (DLADM_WALK_CONTINUE); 6455895Syz147064 6465895Syz147064 for (i = 0; i < ginfo.lg_nports; i++) 6475895Syz147064 if (ginfo.lg_ports[i].lp_linkid == del_arg->linkid) 6485895Syz147064 break; 6495895Syz147064 6505895Syz147064 if (i != ginfo.lg_nports) { 6515895Syz147064 if (ginfo.lg_nports == 1 && i == 0) { 6525895Syz147064 consumer_del_phys_arg_t aggr_del_arg; 6535895Syz147064 6545895Syz147064 /* 6555895Syz147064 * First delete all the VLANs on this aggregation, then 6565895Syz147064 * delete the aggregation itself. 6575895Syz147064 */ 6585895Syz147064 aggr_del_arg.linkid = aggrid; 6595895Syz147064 (void) dladm_walk_datalink_id(i_dladm_vlan_link_del, 6605895Syz147064 &aggr_del_arg, DATALINK_CLASS_VLAN, 6615895Syz147064 DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 6625895Syz147064 (void) dladm_aggr_delete(aggrid, DLADM_OPT_PERSIST); 6635895Syz147064 } else { 6645895Syz147064 port[0].lp_linkid = del_arg->linkid; 6655895Syz147064 (void) dladm_aggr_remove(aggrid, 1, port, 6665895Syz147064 DLADM_OPT_PERSIST); 6675895Syz147064 } 6685895Syz147064 } 6695895Syz147064 return (DLADM_WALK_CONTINUE); 6705895Syz147064 } 6715895Syz147064 6725895Syz147064 typedef struct del_phys_arg_s { 6735895Syz147064 dladm_status_t rval; 6745895Syz147064 } del_phys_arg_t; 6755895Syz147064 6765895Syz147064 static int 6775895Syz147064 i_dladm_phys_delete(datalink_id_t linkid, void *arg) 6785895Syz147064 { 6795895Syz147064 uint32_t flags; 6805895Syz147064 datalink_class_t class; 6815895Syz147064 uint32_t media; 6825895Syz147064 dladm_status_t status = DLADM_STATUS_OK; 6835895Syz147064 del_phys_arg_t *del_phys_arg = arg; 6845895Syz147064 consumer_del_phys_arg_t del_arg; 6855895Syz147064 6865895Syz147064 if ((status = dladm_datalink_id2info(linkid, &flags, &class, 6875895Syz147064 &media, NULL, 0)) != DLADM_STATUS_OK) { 6885895Syz147064 goto done; 6895895Syz147064 } 6905895Syz147064 6915895Syz147064 /* 6925895Syz147064 * see whether this link is a removed physical link. 6935895Syz147064 */ 6945895Syz147064 if ((class != DATALINK_CLASS_PHYS) || !(flags & DLADM_OPT_PERSIST) || 6955895Syz147064 (flags & DLADM_OPT_ACTIVE)) { 6965895Syz147064 status = DLADM_STATUS_BADARG; 6975895Syz147064 goto done; 6985895Syz147064 } 6995895Syz147064 7005895Syz147064 if (media == DL_ETHER) { 7015895Syz147064 del_arg.linkid = linkid; 7025895Syz147064 (void) dladm_walk_datalink_id(i_dladm_aggr_link_del, &del_arg, 7035895Syz147064 DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, 7045895Syz147064 DLADM_OPT_PERSIST); 7055895Syz147064 (void) dladm_walk_datalink_id(i_dladm_vlan_link_del, &del_arg, 7065895Syz147064 DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, 7075895Syz147064 DLADM_OPT_PERSIST); 7085895Syz147064 } 7095895Syz147064 7105895Syz147064 (void) dladm_destroy_datalink_id(linkid, DLADM_OPT_PERSIST); 7115895Syz147064 (void) dladm_remove_conf(linkid); 7125895Syz147064 7135895Syz147064 done: 7145895Syz147064 del_phys_arg->rval = status; 7155895Syz147064 return (DLADM_WALK_CONTINUE); 7165895Syz147064 } 7175895Syz147064 7185895Syz147064 dladm_status_t 7195895Syz147064 dladm_phys_delete(datalink_id_t linkid) 7205895Syz147064 { 7215895Syz147064 del_phys_arg_t arg = {DLADM_STATUS_OK}; 7225895Syz147064 7235895Syz147064 if (linkid == DATALINK_ALL_LINKID) { 7245895Syz147064 (void) dladm_walk_datalink_id(i_dladm_phys_delete, &arg, 7255895Syz147064 DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, 7265895Syz147064 DLADM_OPT_PERSIST); 7275895Syz147064 return (DLADM_STATUS_OK); 7285895Syz147064 } else { 7295895Syz147064 (void) i_dladm_phys_delete(linkid, &arg); 7305895Syz147064 return (arg.rval); 7315895Syz147064 } 7325895Syz147064 } 7335895Syz147064 7345895Syz147064 dladm_status_t 7355895Syz147064 dladm_phys_info(datalink_id_t linkid, dladm_phys_attr_t *dpap, uint32_t flags) 7365895Syz147064 { 7375895Syz147064 dladm_status_t status; 7385895Syz147064 7395895Syz147064 assert(flags == DLADM_OPT_ACTIVE || flags == DLADM_OPT_PERSIST); 7405895Syz147064 7415895Syz147064 switch (flags) { 7425895Syz147064 case DLADM_OPT_PERSIST: { 7435895Syz147064 dladm_conf_t conf; 7445895Syz147064 7455895Syz147064 status = dladm_read_conf(linkid, &conf); 7465895Syz147064 if (status != DLADM_STATUS_OK) 7475895Syz147064 return (status); 7485895Syz147064 7495895Syz147064 status = dladm_get_conf_field(conf, FDEVNAME, dpap->dp_dev, 7505895Syz147064 MAXLINKNAMELEN); 7515895Syz147064 dladm_destroy_conf(conf); 7525895Syz147064 return (status); 7535895Syz147064 } 7545895Syz147064 case DLADM_OPT_ACTIVE: { 7555895Syz147064 dld_ioc_phys_attr_t dip; 7565895Syz147064 int fd; 7575895Syz147064 7585895Syz147064 if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) 7595895Syz147064 return (dladm_errno2status(errno)); 7605895Syz147064 7615895Syz147064 dip.dip_linkid = linkid; 7625895Syz147064 if (i_dladm_ioctl(fd, DLDIOC_PHYS_ATTR, &dip, sizeof (dip)) 7635895Syz147064 < 0) { 7645895Syz147064 status = dladm_errno2status(errno); 7655895Syz147064 (void) close(fd); 7665895Syz147064 return (status); 7675895Syz147064 } 7685895Syz147064 (void) close(fd); 7695895Syz147064 dpap->dp_novanity = dip.dip_novanity; 7705895Syz147064 (void) strlcpy(dpap->dp_dev, dip.dip_dev, MAXLINKNAMELEN); 7715895Syz147064 return (DLADM_STATUS_OK); 7725895Syz147064 } 7735895Syz147064 default: 7745895Syz147064 return (DLADM_STATUS_BADARG); 7755895Syz147064 } 7765895Syz147064 } 7775895Syz147064 7785895Syz147064 typedef struct i_walk_dev_state_s { 7795895Syz147064 const char *devname; 7805895Syz147064 datalink_id_t linkid; 7815895Syz147064 boolean_t found; 7825895Syz147064 } i_walk_dev_state_t; 7835895Syz147064 7843871Syz147064 int 7855895Syz147064 i_dladm_walk_dev2linkid(datalink_id_t linkid, void *arg) 7865895Syz147064 { 7875895Syz147064 dladm_phys_attr_t dpa; 7885895Syz147064 dladm_status_t status; 7895895Syz147064 i_walk_dev_state_t *statep = arg; 7905895Syz147064 7915895Syz147064 status = dladm_phys_info(linkid, &dpa, DLADM_OPT_PERSIST); 7925895Syz147064 if ((status == DLADM_STATUS_OK) && 7935895Syz147064 (strcmp(statep->devname, dpa.dp_dev) == 0)) { 7945895Syz147064 statep->found = B_TRUE; 7955895Syz147064 statep->linkid = linkid; 7965895Syz147064 return (DLADM_WALK_TERMINATE); 7975895Syz147064 } 7985895Syz147064 return (DLADM_WALK_CONTINUE); 7995895Syz147064 } 8005895Syz147064 8015895Syz147064 /* 8025895Syz147064 * Get the linkid from the physical device name. 8035895Syz147064 */ 8045895Syz147064 dladm_status_t 8055895Syz147064 dladm_dev2linkid(const char *devname, datalink_id_t *linkidp) 8065895Syz147064 { 8075895Syz147064 i_walk_dev_state_t state; 8085895Syz147064 8095895Syz147064 state.found = B_FALSE; 8105895Syz147064 state.devname = devname; 8115895Syz147064 8125895Syz147064 (void) dladm_walk_datalink_id(i_dladm_walk_dev2linkid, &state, 8135895Syz147064 DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 8145895Syz147064 if (state.found == B_TRUE) { 8155895Syz147064 *linkidp = state.linkid; 8165895Syz147064 return (DLADM_STATUS_OK); 8175895Syz147064 } else { 8185895Syz147064 return (dladm_errno2status(ENOENT)); 8195895Syz147064 } 8205895Syz147064 } 8215895Syz147064 8225895Syz147064 static int 8235895Syz147064 parse_devname(const char *devname, char *driver, uint_t *ppa, size_t maxlen) 8245895Syz147064 { 8255895Syz147064 char *cp, *tp; 8265895Syz147064 int len; 8275895Syz147064 8285895Syz147064 /* 8295895Syz147064 * device name length must not be 0, and it must end with digit. 8305895Syz147064 */ 8315895Syz147064 if (((len = strlen(devname)) == 0) || !isdigit(devname[len - 1])) 8325895Syz147064 return (EINVAL); 8335895Syz147064 8345895Syz147064 (void) strlcpy(driver, devname, maxlen); 8355895Syz147064 cp = (char *)&driver[len - 1]; 8365895Syz147064 8375895Syz147064 for (tp = cp; isdigit(*tp); tp--) { 8385895Syz147064 if (tp <= driver) 8395895Syz147064 return (EINVAL); 8405895Syz147064 } 8415895Syz147064 8425895Syz147064 *ppa = atoi(tp + 1); 8435895Syz147064 *(tp + 1) = '\0'; 8445895Syz147064 return (0); 8455895Syz147064 } 8465895Syz147064 8475895Syz147064 dladm_status_t 8485895Syz147064 dladm_linkid2legacyname(datalink_id_t linkid, char *dev, size_t len) 8493871Syz147064 { 8505895Syz147064 char devname[MAXLINKNAMELEN]; 8515895Syz147064 uint16_t vid = VLAN_ID_NONE; 8525895Syz147064 datalink_class_t class; 8535895Syz147064 dladm_status_t status; 8545895Syz147064 8555895Syz147064 status = dladm_datalink_id2info(linkid, NULL, &class, NULL, NULL, 0); 8565895Syz147064 if (status != DLADM_STATUS_OK) 8575895Syz147064 goto done; 8585895Syz147064 8595895Syz147064 /* 8605895Syz147064 * If this is a VLAN, we must first determine the class and linkid of 8615895Syz147064 * the link the VLAN has been created over. 8625895Syz147064 */ 8635895Syz147064 if (class == DATALINK_CLASS_VLAN) { 8645895Syz147064 dladm_vlan_attr_t dva; 8655895Syz147064 8665895Syz147064 status = dladm_vlan_info(linkid, &dva, DLADM_OPT_ACTIVE); 8675895Syz147064 if (status != DLADM_STATUS_OK) 8685895Syz147064 goto done; 8695895Syz147064 linkid = dva.dv_linkid; 8705895Syz147064 vid = dva.dv_vid; 8715895Syz147064 8725895Syz147064 if ((status = dladm_datalink_id2info(linkid, NULL, &class, NULL, 8735895Syz147064 NULL, 0)) != DLADM_STATUS_OK) { 8745895Syz147064 goto done; 8755895Syz147064 } 8765895Syz147064 } 8775895Syz147064 8785895Syz147064 switch (class) { 8795895Syz147064 case DATALINK_CLASS_AGGR: { 8805895Syz147064 dladm_aggr_grp_attr_t dga; 8815895Syz147064 8825895Syz147064 status = dladm_aggr_info(linkid, &dga, DLADM_OPT_ACTIVE); 8835895Syz147064 if (status != DLADM_STATUS_OK) 8845895Syz147064 goto done; 8855895Syz147064 8865895Syz147064 if (dga.lg_key == 0) { 8875895Syz147064 /* 8885895Syz147064 * If the key was not specified when the aggregation 8895895Syz147064 * is created, we cannot guess its /dev node name. 8905895Syz147064 */ 8915895Syz147064 status = DLADM_STATUS_BADARG; 8925895Syz147064 goto done; 8935895Syz147064 } 8945895Syz147064 (void) snprintf(devname, MAXLINKNAMELEN, "aggr%d", dga.lg_key); 8955895Syz147064 break; 8965895Syz147064 } 8975895Syz147064 case DATALINK_CLASS_PHYS: { 8985895Syz147064 dladm_phys_attr_t dpa; 8995895Syz147064 9005895Syz147064 status = dladm_phys_info(linkid, &dpa, DLADM_OPT_PERSIST); 9015895Syz147064 if (status != DLADM_STATUS_OK) 9025895Syz147064 goto done; 9035895Syz147064 9045895Syz147064 (void) strlcpy(devname, dpa.dp_dev, MAXLINKNAMELEN); 9055895Syz147064 break; 9065895Syz147064 } 9075895Syz147064 default: 9085895Syz147064 status = DLADM_STATUS_BADARG; 9095895Syz147064 goto done; 9105895Syz147064 } 9115895Syz147064 9125895Syz147064 if (vid != VLAN_ID_NONE) { 9135895Syz147064 char drv[MAXNAMELEN]; 9145895Syz147064 uint_t ppa; 9155895Syz147064 9165895Syz147064 if (parse_devname(devname, drv, &ppa, MAXNAMELEN) != 0) { 9175895Syz147064 status = DLADM_STATUS_BADARG; 9185895Syz147064 goto done; 9195895Syz147064 } 9205895Syz147064 if (snprintf(dev, len, "%s%d", drv, vid * 1000 + ppa) >= len) 9215895Syz147064 status = DLADM_STATUS_TOOSMALL; 9225895Syz147064 } else { 9235895Syz147064 if (strlcpy(dev, devname, len) >= len) 9245895Syz147064 status = DLADM_STATUS_TOOSMALL; 9255895Syz147064 } 9265895Syz147064 9275895Syz147064 done: 9285895Syz147064 return (status); 9293871Syz147064 } 930*5903Ssowmini 931*5903Ssowmini dladm_status_t 932*5903Ssowmini dladm_get_single_mac_stat(datalink_id_t linkid, const char *name, uint8_t type, 933*5903Ssowmini void *val) 934*5903Ssowmini { 935*5903Ssowmini char module[DLPI_LINKNAME_MAX]; 936*5903Ssowmini uint_t instance; 937*5903Ssowmini char link[DLPI_LINKNAME_MAX]; 938*5903Ssowmini dladm_status_t status; 939*5903Ssowmini uint32_t flags, media; 940*5903Ssowmini kstat_ctl_t *kcp; 941*5903Ssowmini kstat_t *ksp; 942*5903Ssowmini dladm_phys_attr_t dpap; 943*5903Ssowmini 944*5903Ssowmini if ((status = dladm_datalink_id2info(linkid, &flags, NULL, &media, 945*5903Ssowmini link, DLPI_LINKNAME_MAX)) != DLADM_STATUS_OK) 946*5903Ssowmini return (status); 947*5903Ssowmini 948*5903Ssowmini if (media != DL_ETHER) 949*5903Ssowmini return (DLADM_STATUS_LINKINVAL); 950*5903Ssowmini 951*5903Ssowmini status = dladm_phys_info(linkid, &dpap, DLADM_OPT_PERSIST); 952*5903Ssowmini 953*5903Ssowmini if (status != DLADM_STATUS_OK) 954*5903Ssowmini return (status); 955*5903Ssowmini 956*5903Ssowmini status = dladm_parselink(dpap.dp_dev, module, &instance); 957*5903Ssowmini 958*5903Ssowmini if (status != DLADM_STATUS_OK) 959*5903Ssowmini return (status); 960*5903Ssowmini 961*5903Ssowmini if ((kcp = kstat_open()) == NULL) 962*5903Ssowmini return (dladm_errno2status(errno)); 963*5903Ssowmini 964*5903Ssowmini /* 965*5903Ssowmini * The kstat query could fail if the underlying MAC 966*5903Ssowmini * driver was already detached. 967*5903Ssowmini */ 968*5903Ssowmini if ((ksp = kstat_lookup(kcp, module, instance, "mac")) == NULL && 969*5903Ssowmini (ksp = kstat_lookup(kcp, module, instance, NULL)) == NULL) 970*5903Ssowmini goto bail; 971*5903Ssowmini 972*5903Ssowmini if (kstat_read(kcp, ksp, NULL) == -1) 973*5903Ssowmini goto bail; 974*5903Ssowmini 975*5903Ssowmini if (dladm_kstat_value(ksp, name, type, val) < 0) 976*5903Ssowmini goto bail; 977*5903Ssowmini 978*5903Ssowmini (void) kstat_close(kcp); 979*5903Ssowmini return (DLADM_STATUS_OK); 980*5903Ssowmini bail: 981*5903Ssowmini (void) kstat_close(kcp); 982*5903Ssowmini return (dladm_errno2status(errno)); 983*5903Ssowmini 984*5903Ssowmini } 985*5903Ssowmini 986*5903Ssowmini int 987*5903Ssowmini dladm_kstat_value(kstat_t *ksp, const char *name, uint8_t type, void *buf) 988*5903Ssowmini { 989*5903Ssowmini kstat_named_t *knp; 990*5903Ssowmini 991*5903Ssowmini if ((knp = kstat_data_lookup(ksp, (char *)name)) == NULL) 992*5903Ssowmini return (-1); 993*5903Ssowmini 994*5903Ssowmini if (knp->data_type != type) 995*5903Ssowmini return (-1); 996*5903Ssowmini 997*5903Ssowmini switch (type) { 998*5903Ssowmini case KSTAT_DATA_UINT64: 999*5903Ssowmini *(uint64_t *)buf = knp->value.ui64; 1000*5903Ssowmini break; 1001*5903Ssowmini case KSTAT_DATA_UINT32: 1002*5903Ssowmini *(uint32_t *)buf = knp->value.ui32; 1003*5903Ssowmini break; 1004*5903Ssowmini default: 1005*5903Ssowmini return (-1); 1006*5903Ssowmini } 1007*5903Ssowmini 1008*5903Ssowmini return (0); 1009*5903Ssowmini } 1010*5903Ssowmini 1011*5903Ssowmini dladm_status_t 1012*5903Ssowmini dladm_parselink(const char *dev, char *provider, uint_t *ppa) 1013*5903Ssowmini { 1014*5903Ssowmini ifspec_t ifsp; 1015*5903Ssowmini 1016*5903Ssowmini if (dev == NULL || !ifparse_ifspec(dev, &ifsp)) 1017*5903Ssowmini return (DLADM_STATUS_LINKINVAL); 1018*5903Ssowmini 1019*5903Ssowmini if (provider != NULL) 1020*5903Ssowmini (void) strlcpy(provider, ifsp.ifsp_devnm, DLPI_LINKNAME_MAX); 1021*5903Ssowmini 1022*5903Ssowmini if (ppa != NULL) 1023*5903Ssowmini *ppa = ifsp.ifsp_ppa; 1024*5903Ssowmini 1025*5903Ssowmini return (DLADM_STATUS_OK); 1026*5903Ssowmini } 1027