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 /* 22*5895Syz147064 * 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> 32*5895Syz147064 #include <assert.h> 33*5895Syz147064 #include <ctype.h> 343871Syz147064 #include <strings.h> 353871Syz147064 #include <sys/stat.h> 363871Syz147064 #include <sys/dld.h> 37*5895Syz147064 #include <sys/vlan.h> 38*5895Syz147064 #include <librcm.h> 393871Syz147064 #include <libdlpi.h> 403871Syz147064 #include <libdevinfo.h> 41*5895Syz147064 #include <libdlaggr.h> 42*5895Syz147064 #include <libdlvlan.h> 433871Syz147064 #include <libdllink.h> 44*5895Syz147064 #include <libdlmgmt.h> 453871Syz147064 #include <libdladm_impl.h> 463871Syz147064 473871Syz147064 /* 483871Syz147064 * Return the attributes of the specified datalink from the DLD driver. 493871Syz147064 */ 50*5895Syz147064 static dladm_status_t 51*5895Syz147064 i_dladm_info(int fd, const datalink_id_t linkid, dladm_attr_t *dap) 523871Syz147064 { 533871Syz147064 dld_ioc_attr_t dia; 543871Syz147064 55*5895Syz147064 dia.dia_linkid = linkid; 563871Syz147064 57*5895Syz147064 if (i_dladm_ioctl(fd, DLDIOC_ATTR, &dia, sizeof (dia)) < 0) 58*5895Syz147064 return (dladm_errno2status(errno)); 593871Syz147064 603871Syz147064 dap->da_max_sdu = dia.dia_max_sdu; 613871Syz147064 62*5895Syz147064 return (DLADM_STATUS_OK); 633871Syz147064 } 643871Syz147064 65*5895Syz147064 struct i_dladm_walk_arg { 66*5895Syz147064 dladm_walkcb_t *fn; 67*5895Syz147064 void *arg; 68*5895Syz147064 }; 693871Syz147064 70*5895Syz147064 static int 71*5895Syz147064 i_dladm_walk(datalink_id_t linkid, void *arg) 72*5895Syz147064 { 73*5895Syz147064 struct i_dladm_walk_arg *walk_arg = arg; 74*5895Syz147064 char link[MAXLINKNAMELEN]; 753871Syz147064 76*5895Syz147064 if (dladm_datalink_id2info(linkid, NULL, NULL, NULL, link, 77*5895Syz147064 sizeof (link)) == DLADM_STATUS_OK) { 78*5895Syz147064 return (walk_arg->fn(link, walk_arg->arg)); 793871Syz147064 } 803871Syz147064 81*5895Syz147064 return (DLADM_WALK_CONTINUE); 823871Syz147064 } 833871Syz147064 843871Syz147064 /* 85*5895Syz147064 * Walk all datalinks. 863871Syz147064 */ 87*5895Syz147064 dladm_status_t 88*5895Syz147064 dladm_walk(dladm_walkcb_t *fn, void *arg, datalink_class_t class, 89*5895Syz147064 datalink_media_t dmedia, uint32_t flags) 903871Syz147064 { 91*5895Syz147064 struct i_dladm_walk_arg walk_arg; 923871Syz147064 93*5895Syz147064 walk_arg.fn = fn; 94*5895Syz147064 walk_arg.arg = arg; 95*5895Syz147064 return (dladm_walk_datalink_id(i_dladm_walk, &walk_arg, 96*5895Syz147064 class, dmedia, flags)); 973871Syz147064 } 983871Syz147064 993871Syz147064 /* 100*5895Syz147064 * These routines are used by administration tools such as dladm(1M) to 1013871Syz147064 * iterate through the list of MAC interfaces 1023871Syz147064 */ 1033871Syz147064 1043871Syz147064 typedef struct dladm_mac_dev { 1053871Syz147064 char dm_name[MAXNAMELEN]; 106*5895Syz147064 struct dladm_mac_dev *dm_next; 1073871Syz147064 } dladm_mac_dev_t; 1083871Syz147064 1093871Syz147064 typedef struct macadm_walk { 110*5895Syz147064 dladm_mac_dev_t *dmd_dev_list; 1113871Syz147064 } dladm_mac_walk_t; 1123871Syz147064 1133871Syz147064 /* 1143871Syz147064 * Local callback invoked for each DDI_NT_NET node. 1153871Syz147064 */ 1163871Syz147064 /* ARGSUSED */ 1173871Syz147064 static int 1183871Syz147064 i_dladm_mac_walk(di_node_t node, di_minor_t minor, void *arg) 1193871Syz147064 { 1203871Syz147064 dladm_mac_walk_t *dmwp = arg; 1213871Syz147064 dladm_mac_dev_t *dmdp = dmwp->dmd_dev_list; 1223871Syz147064 dladm_mac_dev_t **last_dmdp = &dmwp->dmd_dev_list; 1233871Syz147064 char mac[MAXNAMELEN]; 1243871Syz147064 1253871Syz147064 (void) snprintf(mac, MAXNAMELEN, "%s%d", 1263871Syz147064 di_driver_name(node), di_instance(node)); 1273871Syz147064 1283871Syz147064 /* 1293871Syz147064 * Skip aggregations. 1303871Syz147064 */ 1313871Syz147064 if (strcmp("aggr", di_driver_name(node)) == 0) 1323871Syz147064 return (DI_WALK_CONTINUE); 1333871Syz147064 134*5895Syz147064 /* 135*5895Syz147064 * Skip softmacs. 136*5895Syz147064 */ 137*5895Syz147064 if (strcmp("softmac", di_driver_name(node)) == 0) 138*5895Syz147064 return (DI_WALK_CONTINUE); 139*5895Syz147064 1403871Syz147064 while (dmdp) { 1413871Syz147064 /* 1423871Syz147064 * Skip duplicates. 1433871Syz147064 */ 1443871Syz147064 if (strcmp(dmdp->dm_name, mac) == 0) 1453871Syz147064 return (DI_WALK_CONTINUE); 1463871Syz147064 1473871Syz147064 last_dmdp = &dmdp->dm_next; 1483871Syz147064 dmdp = dmdp->dm_next; 1493871Syz147064 } 1503871Syz147064 1513871Syz147064 if ((dmdp = malloc(sizeof (*dmdp))) == NULL) 1523871Syz147064 return (DI_WALK_CONTINUE); 1533871Syz147064 1543871Syz147064 (void) strlcpy(dmdp->dm_name, mac, MAXNAMELEN); 1553871Syz147064 dmdp->dm_next = NULL; 1563871Syz147064 *last_dmdp = dmdp; 1573871Syz147064 1583871Syz147064 return (DI_WALK_CONTINUE); 1593871Syz147064 } 1603871Syz147064 1613871Syz147064 /* 162*5895Syz147064 * Invoke the specified callback for each DDI_NT_NET node. 1633871Syz147064 */ 164*5895Syz147064 dladm_status_t 165*5895Syz147064 dladm_mac_walk(int (*fn)(const char *, void *arg), void *arg) 1663871Syz147064 { 1673871Syz147064 di_node_t root; 1683871Syz147064 dladm_mac_walk_t dmw; 1693871Syz147064 dladm_mac_dev_t *dmdp, *next; 170*5895Syz147064 boolean_t done = B_FALSE; 1713871Syz147064 1723871Syz147064 if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL) 173*5895Syz147064 return (dladm_errno2status(errno)); 1743871Syz147064 1753871Syz147064 dmw.dmd_dev_list = NULL; 1763871Syz147064 1773871Syz147064 (void) di_walk_minor(root, DDI_NT_NET, DI_CHECK_ALIAS, &dmw, 1783871Syz147064 i_dladm_mac_walk); 1793871Syz147064 1803871Syz147064 di_fini(root); 1813871Syz147064 1823871Syz147064 dmdp = dmw.dmd_dev_list; 1833871Syz147064 for (dmdp = dmw.dmd_dev_list; dmdp != NULL; dmdp = next) { 1843871Syz147064 next = dmdp->dm_next; 185*5895Syz147064 if (!done && 186*5895Syz147064 ((*fn)(dmdp->dm_name, arg) == DLADM_WALK_TERMINATE)) { 187*5895Syz147064 done = B_TRUE; 188*5895Syz147064 } 1893871Syz147064 free(dmdp); 1903871Syz147064 } 1913871Syz147064 192*5895Syz147064 return (DLADM_STATUS_OK); 1933871Syz147064 } 1943871Syz147064 1953871Syz147064 /* 196*5895Syz147064 * Get the current attributes of the specified datalink. 1973871Syz147064 */ 198*5895Syz147064 dladm_status_t 199*5895Syz147064 dladm_info(datalink_id_t linkid, dladm_attr_t *dap) 2003871Syz147064 { 2013871Syz147064 int fd; 202*5895Syz147064 dladm_status_t status; 2033871Syz147064 2043871Syz147064 if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) 205*5895Syz147064 return (dladm_errno2status(errno)); 2063871Syz147064 207*5895Syz147064 status = i_dladm_info(fd, linkid, dap); 2083871Syz147064 2093871Syz147064 (void) close(fd); 210*5895Syz147064 return (status); 2113871Syz147064 } 2123871Syz147064 2133871Syz147064 const char * 2143871Syz147064 dladm_linkstate2str(link_state_t state, char *buf) 2153871Syz147064 { 2163871Syz147064 const char *s; 2173871Syz147064 2183871Syz147064 switch (state) { 2193871Syz147064 case LINK_STATE_UP: 2203871Syz147064 s = "up"; 2213871Syz147064 break; 2223871Syz147064 case LINK_STATE_DOWN: 2233871Syz147064 s = "down"; 2243871Syz147064 break; 2253871Syz147064 default: 2263871Syz147064 s = "unknown"; 2273871Syz147064 break; 2283871Syz147064 } 2293871Syz147064 (void) snprintf(buf, DLADM_STRSIZE, "%s", s); 2303871Syz147064 return (buf); 2313871Syz147064 } 2323871Syz147064 2333871Syz147064 const char * 2343871Syz147064 dladm_linkduplex2str(link_duplex_t duplex, char *buf) 2353871Syz147064 { 2363871Syz147064 const char *s; 2373871Syz147064 2383871Syz147064 switch (duplex) { 2393871Syz147064 case LINK_DUPLEX_FULL: 2403871Syz147064 s = "full"; 2413871Syz147064 break; 2423871Syz147064 case LINK_DUPLEX_HALF: 2433871Syz147064 s = "half"; 2443871Syz147064 break; 2453871Syz147064 default: 2463871Syz147064 s = "unknown"; 2473871Syz147064 break; 2483871Syz147064 } 2493871Syz147064 (void) snprintf(buf, DLADM_STRSIZE, "%s", s); 2503871Syz147064 return (buf); 2513871Syz147064 } 2523871Syz147064 2533871Syz147064 /* 254*5895Syz147064 * Set zoneid of a given link 255*5895Syz147064 */ 256*5895Syz147064 dladm_status_t 257*5895Syz147064 dladm_setzid(const char *link, zoneid_t zoneid) 258*5895Syz147064 { 259*5895Syz147064 int fd; 260*5895Syz147064 dladm_status_t status = DLADM_STATUS_OK; 261*5895Syz147064 dld_ioc_setzid_t dis; 262*5895Syz147064 263*5895Syz147064 if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) 264*5895Syz147064 return (dladm_errno2status(errno)); 265*5895Syz147064 266*5895Syz147064 bzero(&dis, sizeof (dld_ioc_setzid_t)); 267*5895Syz147064 (void) strlcpy(dis.dis_link, link, MAXLINKNAMELEN); 268*5895Syz147064 dis.dis_zid = zoneid; 269*5895Syz147064 270*5895Syz147064 if (i_dladm_ioctl(fd, DLDIOC_SETZID, &dis, sizeof (dis)) < 0) 271*5895Syz147064 status = dladm_errno2status(errno); 272*5895Syz147064 273*5895Syz147064 (void) close(fd); 274*5895Syz147064 return (status); 275*5895Syz147064 } 276*5895Syz147064 277*5895Syz147064 /* 278*5895Syz147064 * Get zoneid of a given link 279*5895Syz147064 */ 280*5895Syz147064 dladm_status_t 281*5895Syz147064 dladm_getzid(datalink_id_t linkid, zoneid_t *zoneidp) 282*5895Syz147064 { 283*5895Syz147064 int fd; 284*5895Syz147064 dladm_status_t status = DLADM_STATUS_OK; 285*5895Syz147064 dld_ioc_getzid_t dig; 286*5895Syz147064 287*5895Syz147064 if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) 288*5895Syz147064 return (dladm_errno2status(errno)); 289*5895Syz147064 290*5895Syz147064 bzero(&dig, sizeof (dld_ioc_getzid_t)); 291*5895Syz147064 dig.dig_linkid = linkid; 292*5895Syz147064 dig.dig_zid = -1; 293*5895Syz147064 294*5895Syz147064 if (i_dladm_ioctl(fd, DLDIOC_GETZID, &dig, sizeof (dig)) < 0) 295*5895Syz147064 status = dladm_errno2status(errno); 296*5895Syz147064 297*5895Syz147064 (void) close(fd); 298*5895Syz147064 299*5895Syz147064 if (status == DLADM_STATUS_OK) 300*5895Syz147064 *zoneidp = dig.dig_zid; 301*5895Syz147064 302*5895Syz147064 return (status); 303*5895Syz147064 } 304*5895Syz147064 305*5895Syz147064 /* 306*5895Syz147064 * Case 1: rename an existing link1 to a link2 that does not exist. 307*5895Syz147064 * Result: <linkid1, link2> 3083871Syz147064 */ 309*5895Syz147064 static dladm_status_t 310*5895Syz147064 i_dladm_rename_link_c1(datalink_id_t linkid1, const char *link1, 311*5895Syz147064 const char *link2, uint32_t flags) 312*5895Syz147064 { 313*5895Syz147064 dld_ioc_rename_t dir; 314*5895Syz147064 dladm_conf_t conf; 315*5895Syz147064 dladm_status_t status = DLADM_STATUS_OK; 316*5895Syz147064 int fd; 317*5895Syz147064 318*5895Syz147064 /* 319*5895Syz147064 * Link is currently available. Check to see whether anything is 320*5895Syz147064 * holding this link to prevent a rename operation. 321*5895Syz147064 */ 322*5895Syz147064 if (flags & DLADM_OPT_ACTIVE) { 323*5895Syz147064 dir.dir_linkid1 = linkid1; 324*5895Syz147064 dir.dir_linkid2 = DATALINK_INVALID_LINKID; 325*5895Syz147064 (void) strlcpy(dir.dir_link, link2, MAXLINKNAMELEN); 326*5895Syz147064 if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) 327*5895Syz147064 return (dladm_errno2status(errno)); 328*5895Syz147064 329*5895Syz147064 if (i_dladm_ioctl(fd, DLDIOC_RENAME, &dir, sizeof (dir)) < 0) { 330*5895Syz147064 status = dladm_errno2status(errno); 331*5895Syz147064 (void) close(fd); 332*5895Syz147064 return (status); 333*5895Syz147064 } 334*5895Syz147064 } 335*5895Syz147064 336*5895Syz147064 status = dladm_remap_datalink_id(linkid1, link2); 337*5895Syz147064 if (status != DLADM_STATUS_OK) 338*5895Syz147064 goto done; 339*5895Syz147064 340*5895Syz147064 /* 341*5895Syz147064 * Flush the current mapping to persistent configuration. 342*5895Syz147064 */ 343*5895Syz147064 if ((flags & DLADM_OPT_PERSIST) && 344*5895Syz147064 (((status = dladm_read_conf(linkid1, &conf)) != DLADM_STATUS_OK) || 345*5895Syz147064 ((status = dladm_write_conf(conf)) != DLADM_STATUS_OK))) { 346*5895Syz147064 (void) dladm_remap_datalink_id(linkid1, link1); 347*5895Syz147064 } 348*5895Syz147064 done: 349*5895Syz147064 if (flags & DLADM_OPT_ACTIVE) { 350*5895Syz147064 if (status != DLADM_STATUS_OK) { 351*5895Syz147064 (void) strlcpy(dir.dir_link, link1, MAXLINKNAMELEN); 352*5895Syz147064 (void) i_dladm_ioctl(fd, DLDIOC_RENAME, &dir, 353*5895Syz147064 sizeof (dir)); 354*5895Syz147064 } 355*5895Syz147064 (void) close(fd); 356*5895Syz147064 } 357*5895Syz147064 return (status); 358*5895Syz147064 } 359*5895Syz147064 360*5895Syz147064 typedef struct link_hold_arg_s { 361*5895Syz147064 datalink_id_t linkid; 362*5895Syz147064 datalink_id_t holder; 363*5895Syz147064 uint32_t flags; 364*5895Syz147064 } link_hold_arg_t; 365*5895Syz147064 366*5895Syz147064 static int 367*5895Syz147064 i_dladm_aggr_link_hold(datalink_id_t aggrid, void *arg) 368*5895Syz147064 { 369*5895Syz147064 link_hold_arg_t *hold_arg = arg; 370*5895Syz147064 dladm_aggr_grp_attr_t ginfo; 371*5895Syz147064 dladm_status_t status; 372*5895Syz147064 int i; 373*5895Syz147064 374*5895Syz147064 status = dladm_aggr_info(aggrid, &ginfo, hold_arg->flags); 375*5895Syz147064 if (status != DLADM_STATUS_OK) 376*5895Syz147064 return (DLADM_WALK_CONTINUE); 377*5895Syz147064 378*5895Syz147064 for (i = 0; i < ginfo.lg_nports; i++) { 379*5895Syz147064 if (ginfo.lg_ports[i].lp_linkid == hold_arg->linkid) { 380*5895Syz147064 hold_arg->holder = aggrid; 381*5895Syz147064 return (DLADM_WALK_TERMINATE); 382*5895Syz147064 } 383*5895Syz147064 } 384*5895Syz147064 return (DLADM_WALK_CONTINUE); 385*5895Syz147064 } 386*5895Syz147064 387*5895Syz147064 static int 388*5895Syz147064 i_dladm_vlan_link_hold(datalink_id_t vlanid, void *arg) 389*5895Syz147064 { 390*5895Syz147064 link_hold_arg_t *hold_arg = arg; 391*5895Syz147064 dladm_vlan_attr_t vinfo; 392*5895Syz147064 dladm_status_t status; 393*5895Syz147064 394*5895Syz147064 status = dladm_vlan_info(vlanid, &vinfo, hold_arg->flags); 395*5895Syz147064 if (status != DLADM_STATUS_OK) 396*5895Syz147064 return (DLADM_WALK_CONTINUE); 397*5895Syz147064 398*5895Syz147064 if (vinfo.dv_linkid == hold_arg->linkid) { 399*5895Syz147064 hold_arg->holder = vlanid; 400*5895Syz147064 return (DLADM_WALK_TERMINATE); 401*5895Syz147064 } 402*5895Syz147064 return (DLADM_WALK_CONTINUE); 403*5895Syz147064 } 404*5895Syz147064 405*5895Syz147064 /* 406*5895Syz147064 * Case 2: rename an available physical link link1 to a REMOVED physical link 407*5895Syz147064 * link2. As a result, link1 directly inherits all datalinks configured 408*5895Syz147064 * over link2 (linkid2). 409*5895Syz147064 * Result: <linkid2, link2, link1_phymaj, link1_phyinst, link1_devname, 410*5895Syz147064 * link2_other_attr> 411*5895Syz147064 */ 412*5895Syz147064 static dladm_status_t 413*5895Syz147064 i_dladm_rename_link_c2(datalink_id_t linkid1, datalink_id_t linkid2) 4143871Syz147064 { 415*5895Syz147064 rcm_handle_t *rcm_hdl = NULL; 416*5895Syz147064 nvlist_t *nvl = NULL; 417*5895Syz147064 link_hold_arg_t arg; 418*5895Syz147064 dld_ioc_rename_t dir; 419*5895Syz147064 int fd; 420*5895Syz147064 dladm_conf_t conf1, conf2; 421*5895Syz147064 char devname[MAXLINKNAMELEN]; 422*5895Syz147064 uint64_t phymaj, phyinst; 423*5895Syz147064 dladm_status_t status = DLADM_STATUS_OK; 424*5895Syz147064 425*5895Syz147064 /* 426*5895Syz147064 * First check if linkid1 is associated with any persistent 427*5895Syz147064 * aggregations or VLANs. If yes, return BUSY. 428*5895Syz147064 */ 429*5895Syz147064 arg.linkid = linkid1; 430*5895Syz147064 arg.holder = DATALINK_INVALID_LINKID; 431*5895Syz147064 arg.flags = DLADM_OPT_PERSIST; 432*5895Syz147064 (void) dladm_walk_datalink_id(i_dladm_aggr_link_hold, &arg, 433*5895Syz147064 DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 434*5895Syz147064 if (arg.holder != DATALINK_INVALID_LINKID) 435*5895Syz147064 return (DLADM_STATUS_LINKBUSY); 436*5895Syz147064 437*5895Syz147064 arg.flags = DLADM_OPT_PERSIST; 438*5895Syz147064 (void) dladm_walk_datalink_id(i_dladm_vlan_link_hold, &arg, 439*5895Syz147064 DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 440*5895Syz147064 if (arg.holder != DATALINK_INVALID_LINKID) 441*5895Syz147064 return (DLADM_STATUS_LINKBUSY); 442*5895Syz147064 443*5895Syz147064 /* 444*5895Syz147064 * Send DLDIOC_RENAME to request to rename link1's linkid to 445*5895Syz147064 * be linkid2. This will check whether link1 is used by any 446*5895Syz147064 * aggregations or VLANs, or is held by any application. If yes, 447*5895Syz147064 * return failure. 448*5895Syz147064 */ 449*5895Syz147064 if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) 450*5895Syz147064 return (dladm_errno2status(errno)); 451*5895Syz147064 452*5895Syz147064 dir.dir_linkid1 = linkid1; 453*5895Syz147064 dir.dir_linkid2 = linkid2; 454*5895Syz147064 if (i_dladm_ioctl(fd, DLDIOC_RENAME, &dir, sizeof (dir)) < 0) 455*5895Syz147064 status = dladm_errno2status(errno); 456*5895Syz147064 457*5895Syz147064 if (status != DLADM_STATUS_OK) { 458*5895Syz147064 (void) close(fd); 459*5895Syz147064 return (status); 460*5895Syz147064 } 461*5895Syz147064 462*5895Syz147064 /* 463*5895Syz147064 * Now change the phymaj, phyinst and devname associated with linkid1 464*5895Syz147064 * to be associated with linkid2. Before doing that, the old active 465*5895Syz147064 * linkprop of linkid1 should be deleted. 466*5895Syz147064 */ 467*5895Syz147064 (void) dladm_set_linkprop(linkid1, NULL, NULL, 0, DLADM_OPT_ACTIVE); 468*5895Syz147064 469*5895Syz147064 if (((status = dladm_read_conf(linkid1, &conf1)) != DLADM_STATUS_OK) || 470*5895Syz147064 ((status = dladm_get_conf_field(conf1, FDEVNAME, devname, 471*5895Syz147064 MAXLINKNAMELEN)) != DLADM_STATUS_OK) || 472*5895Syz147064 ((status = dladm_get_conf_field(conf1, FPHYMAJ, &phymaj, 473*5895Syz147064 sizeof (uint64_t))) != DLADM_STATUS_OK) || 474*5895Syz147064 ((status = dladm_get_conf_field(conf1, FPHYINST, &phyinst, 475*5895Syz147064 sizeof (uint64_t))) != DLADM_STATUS_OK) || 476*5895Syz147064 ((status = dladm_read_conf(linkid2, &conf2)) != DLADM_STATUS_OK)) { 477*5895Syz147064 dir.dir_linkid1 = linkid2; 478*5895Syz147064 dir.dir_linkid2 = linkid1; 479*5895Syz147064 (void) dladm_init_linkprop(linkid1); 480*5895Syz147064 (void) i_dladm_ioctl(fd, DLDIOC_RENAME, &dir, sizeof (dir)); 481*5895Syz147064 (void) close(fd); 482*5895Syz147064 return (status); 483*5895Syz147064 } 484*5895Syz147064 (void) close(fd); 485*5895Syz147064 486*5895Syz147064 dladm_destroy_conf(conf1); 487*5895Syz147064 (void) dladm_set_conf_field(conf2, FDEVNAME, DLADM_TYPE_STR, devname); 488*5895Syz147064 (void) dladm_set_conf_field(conf2, FPHYMAJ, DLADM_TYPE_UINT64, &phymaj); 489*5895Syz147064 (void) dladm_set_conf_field(conf2, FPHYINST, 490*5895Syz147064 DLADM_TYPE_UINT64, &phyinst); 491*5895Syz147064 (void) dladm_write_conf(conf2); 492*5895Syz147064 dladm_destroy_conf(conf2); 493*5895Syz147064 494*5895Syz147064 /* 495*5895Syz147064 * Delete link1 and mark link2 up. 496*5895Syz147064 */ 497*5895Syz147064 (void) dladm_destroy_datalink_id(linkid1, DLADM_OPT_ACTIVE | 498*5895Syz147064 DLADM_OPT_PERSIST); 499*5895Syz147064 (void) dladm_remove_conf(linkid1); 500*5895Syz147064 (void) dladm_up_datalink_id(linkid2); 501*5895Syz147064 502*5895Syz147064 /* 503*5895Syz147064 * Now generate the RCM_RESOURCE_LINK_NEW sysevent which can be 504*5895Syz147064 * consumed by the RCM framework to restore all the datalink and 505*5895Syz147064 * IP configuration. 506*5895Syz147064 */ 507*5895Syz147064 status = DLADM_STATUS_FAILED; 508*5895Syz147064 if ((nvlist_alloc(&nvl, 0, 0) != 0) || 509*5895Syz147064 (nvlist_add_uint64(nvl, RCM_NV_LINKID, linkid2) != 0)) { 510*5895Syz147064 goto done; 511*5895Syz147064 } 512*5895Syz147064 513*5895Syz147064 if (rcm_alloc_handle(NULL, 0, NULL, &rcm_hdl) != RCM_SUCCESS) 514*5895Syz147064 goto done; 515*5895Syz147064 516*5895Syz147064 if (rcm_notify_event(rcm_hdl, RCM_RESOURCE_LINK_NEW, 0, nvl, NULL) == 517*5895Syz147064 RCM_SUCCESS) { 518*5895Syz147064 status = DLADM_STATUS_OK; 519*5895Syz147064 } 520*5895Syz147064 521*5895Syz147064 done: 522*5895Syz147064 if (rcm_hdl != NULL) 523*5895Syz147064 (void) rcm_free_handle(rcm_hdl); 524*5895Syz147064 if (nvl != NULL) 525*5895Syz147064 nvlist_free(nvl); 526*5895Syz147064 return (status); 5273871Syz147064 } 5283871Syz147064 5293871Syz147064 /* 530*5895Syz147064 * case 3: rename a non-existent link to a REMOVED physical link. 531*5895Syz147064 * Set the removed physical link's device name to link1, so that 532*5895Syz147064 * when link1 attaches, it inherits all the link configuration of 533*5895Syz147064 * the removed physical link. 5343871Syz147064 */ 535*5895Syz147064 static dladm_status_t 536*5895Syz147064 i_dladm_rename_link_c3(const char *link1, datalink_id_t linkid2) 537*5895Syz147064 { 538*5895Syz147064 dladm_conf_t conf; 539*5895Syz147064 dladm_status_t status; 540*5895Syz147064 541*5895Syz147064 if (!dladm_valid_linkname(link1)) 542*5895Syz147064 return (DLADM_STATUS_LINKINVAL); 543*5895Syz147064 544*5895Syz147064 status = dladm_read_conf(linkid2, &conf); 545*5895Syz147064 if (status != DLADM_STATUS_OK) 546*5895Syz147064 goto done; 547*5895Syz147064 548*5895Syz147064 if ((status = dladm_set_conf_field(conf, FDEVNAME, DLADM_TYPE_STR, 549*5895Syz147064 link1)) == DLADM_STATUS_OK) { 550*5895Syz147064 status = dladm_write_conf(conf); 551*5895Syz147064 } 552*5895Syz147064 553*5895Syz147064 dladm_destroy_conf(conf); 554*5895Syz147064 555*5895Syz147064 done: 556*5895Syz147064 return (status); 557*5895Syz147064 } 558*5895Syz147064 559*5895Syz147064 dladm_status_t 560*5895Syz147064 dladm_rename_link(const char *link1, const char *link2) 561*5895Syz147064 { 562*5895Syz147064 datalink_id_t linkid1 = DATALINK_INVALID_LINKID; 563*5895Syz147064 datalink_id_t linkid2 = DATALINK_INVALID_LINKID; 564*5895Syz147064 uint32_t flags1, flags2; 565*5895Syz147064 datalink_class_t class1, class2; 566*5895Syz147064 uint32_t media1, media2; 567*5895Syz147064 boolean_t remphy2 = B_FALSE; 568*5895Syz147064 dladm_status_t status; 569*5895Syz147064 570*5895Syz147064 (void) dladm_name2info(link1, &linkid1, &flags1, &class1, &media1); 571*5895Syz147064 if ((dladm_name2info(link2, &linkid2, &flags2, &class2, &media2) == 572*5895Syz147064 DLADM_STATUS_OK) && (class2 == DATALINK_CLASS_PHYS) && 573*5895Syz147064 (flags2 == DLADM_OPT_PERSIST)) { 574*5895Syz147064 /* 575*5895Syz147064 * see whether link2 is a removed physical link. 576*5895Syz147064 */ 577*5895Syz147064 remphy2 = B_TRUE; 578*5895Syz147064 } 579*5895Syz147064 580*5895Syz147064 if (linkid1 != DATALINK_INVALID_LINKID) { 581*5895Syz147064 if (linkid2 == DATALINK_INVALID_LINKID) { 582*5895Syz147064 /* 583*5895Syz147064 * case 1: rename an existing link to a link that 584*5895Syz147064 * does not exist. 585*5895Syz147064 */ 586*5895Syz147064 status = i_dladm_rename_link_c1(linkid1, link1, link2, 587*5895Syz147064 flags1); 588*5895Syz147064 } else if (remphy2) { 589*5895Syz147064 /* 590*5895Syz147064 * case 2: rename an available link to a REMOVED 591*5895Syz147064 * physical link. Return failure if link1 is not 592*5895Syz147064 * an active physical link. 593*5895Syz147064 */ 594*5895Syz147064 if ((class1 != class2) || (media1 != media2) || 595*5895Syz147064 !(flags1 & DLADM_OPT_ACTIVE)) { 596*5895Syz147064 status = DLADM_STATUS_BADARG; 597*5895Syz147064 } else { 598*5895Syz147064 status = i_dladm_rename_link_c2(linkid1, 599*5895Syz147064 linkid2); 600*5895Syz147064 } 601*5895Syz147064 } else { 602*5895Syz147064 status = DLADM_STATUS_EXIST; 603*5895Syz147064 } 604*5895Syz147064 } else if (remphy2) { 605*5895Syz147064 status = i_dladm_rename_link_c3(link1, linkid2); 606*5895Syz147064 } else { 607*5895Syz147064 status = DLADM_STATUS_NOTFOUND; 608*5895Syz147064 } 609*5895Syz147064 return (status); 610*5895Syz147064 } 611*5895Syz147064 612*5895Syz147064 typedef struct consumer_del_phys_arg_s { 613*5895Syz147064 datalink_id_t linkid; 614*5895Syz147064 } consumer_del_phys_arg_t; 615*5895Syz147064 616*5895Syz147064 static int 617*5895Syz147064 i_dladm_vlan_link_del(datalink_id_t vlanid, void *arg) 618*5895Syz147064 { 619*5895Syz147064 consumer_del_phys_arg_t *del_arg = arg; 620*5895Syz147064 dladm_vlan_attr_t vinfo; 621*5895Syz147064 dladm_status_t status; 622*5895Syz147064 623*5895Syz147064 status = dladm_vlan_info(vlanid, &vinfo, DLADM_OPT_PERSIST); 624*5895Syz147064 if (status != DLADM_STATUS_OK) 625*5895Syz147064 return (DLADM_WALK_CONTINUE); 626*5895Syz147064 627*5895Syz147064 if (vinfo.dv_linkid == del_arg->linkid) 628*5895Syz147064 (void) dladm_vlan_delete(vlanid, DLADM_OPT_PERSIST); 629*5895Syz147064 return (DLADM_WALK_CONTINUE); 630*5895Syz147064 } 631*5895Syz147064 632*5895Syz147064 static int 633*5895Syz147064 i_dladm_aggr_link_del(datalink_id_t aggrid, void *arg) 634*5895Syz147064 { 635*5895Syz147064 consumer_del_phys_arg_t *del_arg = arg; 636*5895Syz147064 dladm_aggr_grp_attr_t ginfo; 637*5895Syz147064 dladm_status_t status; 638*5895Syz147064 dladm_aggr_port_attr_db_t port[1]; 639*5895Syz147064 int i; 640*5895Syz147064 641*5895Syz147064 status = dladm_aggr_info(aggrid, &ginfo, DLADM_OPT_PERSIST); 642*5895Syz147064 if (status != DLADM_STATUS_OK) 643*5895Syz147064 return (DLADM_WALK_CONTINUE); 644*5895Syz147064 645*5895Syz147064 for (i = 0; i < ginfo.lg_nports; i++) 646*5895Syz147064 if (ginfo.lg_ports[i].lp_linkid == del_arg->linkid) 647*5895Syz147064 break; 648*5895Syz147064 649*5895Syz147064 if (i != ginfo.lg_nports) { 650*5895Syz147064 if (ginfo.lg_nports == 1 && i == 0) { 651*5895Syz147064 consumer_del_phys_arg_t aggr_del_arg; 652*5895Syz147064 653*5895Syz147064 /* 654*5895Syz147064 * First delete all the VLANs on this aggregation, then 655*5895Syz147064 * delete the aggregation itself. 656*5895Syz147064 */ 657*5895Syz147064 aggr_del_arg.linkid = aggrid; 658*5895Syz147064 (void) dladm_walk_datalink_id(i_dladm_vlan_link_del, 659*5895Syz147064 &aggr_del_arg, DATALINK_CLASS_VLAN, 660*5895Syz147064 DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 661*5895Syz147064 (void) dladm_aggr_delete(aggrid, DLADM_OPT_PERSIST); 662*5895Syz147064 } else { 663*5895Syz147064 port[0].lp_linkid = del_arg->linkid; 664*5895Syz147064 (void) dladm_aggr_remove(aggrid, 1, port, 665*5895Syz147064 DLADM_OPT_PERSIST); 666*5895Syz147064 } 667*5895Syz147064 } 668*5895Syz147064 return (DLADM_WALK_CONTINUE); 669*5895Syz147064 } 670*5895Syz147064 671*5895Syz147064 typedef struct del_phys_arg_s { 672*5895Syz147064 dladm_status_t rval; 673*5895Syz147064 } del_phys_arg_t; 674*5895Syz147064 675*5895Syz147064 static int 676*5895Syz147064 i_dladm_phys_delete(datalink_id_t linkid, void *arg) 677*5895Syz147064 { 678*5895Syz147064 uint32_t flags; 679*5895Syz147064 datalink_class_t class; 680*5895Syz147064 uint32_t media; 681*5895Syz147064 dladm_status_t status = DLADM_STATUS_OK; 682*5895Syz147064 del_phys_arg_t *del_phys_arg = arg; 683*5895Syz147064 consumer_del_phys_arg_t del_arg; 684*5895Syz147064 685*5895Syz147064 if ((status = dladm_datalink_id2info(linkid, &flags, &class, 686*5895Syz147064 &media, NULL, 0)) != DLADM_STATUS_OK) { 687*5895Syz147064 goto done; 688*5895Syz147064 } 689*5895Syz147064 690*5895Syz147064 /* 691*5895Syz147064 * see whether this link is a removed physical link. 692*5895Syz147064 */ 693*5895Syz147064 if ((class != DATALINK_CLASS_PHYS) || !(flags & DLADM_OPT_PERSIST) || 694*5895Syz147064 (flags & DLADM_OPT_ACTIVE)) { 695*5895Syz147064 status = DLADM_STATUS_BADARG; 696*5895Syz147064 goto done; 697*5895Syz147064 } 698*5895Syz147064 699*5895Syz147064 if (media == DL_ETHER) { 700*5895Syz147064 del_arg.linkid = linkid; 701*5895Syz147064 (void) dladm_walk_datalink_id(i_dladm_aggr_link_del, &del_arg, 702*5895Syz147064 DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, 703*5895Syz147064 DLADM_OPT_PERSIST); 704*5895Syz147064 (void) dladm_walk_datalink_id(i_dladm_vlan_link_del, &del_arg, 705*5895Syz147064 DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, 706*5895Syz147064 DLADM_OPT_PERSIST); 707*5895Syz147064 } 708*5895Syz147064 709*5895Syz147064 (void) dladm_destroy_datalink_id(linkid, DLADM_OPT_PERSIST); 710*5895Syz147064 (void) dladm_remove_conf(linkid); 711*5895Syz147064 712*5895Syz147064 done: 713*5895Syz147064 del_phys_arg->rval = status; 714*5895Syz147064 return (DLADM_WALK_CONTINUE); 715*5895Syz147064 } 716*5895Syz147064 717*5895Syz147064 dladm_status_t 718*5895Syz147064 dladm_phys_delete(datalink_id_t linkid) 719*5895Syz147064 { 720*5895Syz147064 del_phys_arg_t arg = {DLADM_STATUS_OK}; 721*5895Syz147064 722*5895Syz147064 if (linkid == DATALINK_ALL_LINKID) { 723*5895Syz147064 (void) dladm_walk_datalink_id(i_dladm_phys_delete, &arg, 724*5895Syz147064 DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, 725*5895Syz147064 DLADM_OPT_PERSIST); 726*5895Syz147064 return (DLADM_STATUS_OK); 727*5895Syz147064 } else { 728*5895Syz147064 (void) i_dladm_phys_delete(linkid, &arg); 729*5895Syz147064 return (arg.rval); 730*5895Syz147064 } 731*5895Syz147064 } 732*5895Syz147064 733*5895Syz147064 dladm_status_t 734*5895Syz147064 dladm_phys_info(datalink_id_t linkid, dladm_phys_attr_t *dpap, uint32_t flags) 735*5895Syz147064 { 736*5895Syz147064 dladm_status_t status; 737*5895Syz147064 738*5895Syz147064 assert(flags == DLADM_OPT_ACTIVE || flags == DLADM_OPT_PERSIST); 739*5895Syz147064 740*5895Syz147064 switch (flags) { 741*5895Syz147064 case DLADM_OPT_PERSIST: { 742*5895Syz147064 dladm_conf_t conf; 743*5895Syz147064 744*5895Syz147064 status = dladm_read_conf(linkid, &conf); 745*5895Syz147064 if (status != DLADM_STATUS_OK) 746*5895Syz147064 return (status); 747*5895Syz147064 748*5895Syz147064 status = dladm_get_conf_field(conf, FDEVNAME, dpap->dp_dev, 749*5895Syz147064 MAXLINKNAMELEN); 750*5895Syz147064 dladm_destroy_conf(conf); 751*5895Syz147064 return (status); 752*5895Syz147064 } 753*5895Syz147064 case DLADM_OPT_ACTIVE: { 754*5895Syz147064 dld_ioc_phys_attr_t dip; 755*5895Syz147064 int fd; 756*5895Syz147064 757*5895Syz147064 if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) 758*5895Syz147064 return (dladm_errno2status(errno)); 759*5895Syz147064 760*5895Syz147064 dip.dip_linkid = linkid; 761*5895Syz147064 if (i_dladm_ioctl(fd, DLDIOC_PHYS_ATTR, &dip, sizeof (dip)) 762*5895Syz147064 < 0) { 763*5895Syz147064 status = dladm_errno2status(errno); 764*5895Syz147064 (void) close(fd); 765*5895Syz147064 return (status); 766*5895Syz147064 } 767*5895Syz147064 (void) close(fd); 768*5895Syz147064 dpap->dp_novanity = dip.dip_novanity; 769*5895Syz147064 (void) strlcpy(dpap->dp_dev, dip.dip_dev, MAXLINKNAMELEN); 770*5895Syz147064 return (DLADM_STATUS_OK); 771*5895Syz147064 } 772*5895Syz147064 default: 773*5895Syz147064 return (DLADM_STATUS_BADARG); 774*5895Syz147064 } 775*5895Syz147064 } 776*5895Syz147064 777*5895Syz147064 typedef struct i_walk_dev_state_s { 778*5895Syz147064 const char *devname; 779*5895Syz147064 datalink_id_t linkid; 780*5895Syz147064 boolean_t found; 781*5895Syz147064 } i_walk_dev_state_t; 782*5895Syz147064 7833871Syz147064 int 784*5895Syz147064 i_dladm_walk_dev2linkid(datalink_id_t linkid, void *arg) 785*5895Syz147064 { 786*5895Syz147064 dladm_phys_attr_t dpa; 787*5895Syz147064 dladm_status_t status; 788*5895Syz147064 i_walk_dev_state_t *statep = arg; 789*5895Syz147064 790*5895Syz147064 status = dladm_phys_info(linkid, &dpa, DLADM_OPT_PERSIST); 791*5895Syz147064 if ((status == DLADM_STATUS_OK) && 792*5895Syz147064 (strcmp(statep->devname, dpa.dp_dev) == 0)) { 793*5895Syz147064 statep->found = B_TRUE; 794*5895Syz147064 statep->linkid = linkid; 795*5895Syz147064 return (DLADM_WALK_TERMINATE); 796*5895Syz147064 } 797*5895Syz147064 return (DLADM_WALK_CONTINUE); 798*5895Syz147064 } 799*5895Syz147064 800*5895Syz147064 /* 801*5895Syz147064 * Get the linkid from the physical device name. 802*5895Syz147064 */ 803*5895Syz147064 dladm_status_t 804*5895Syz147064 dladm_dev2linkid(const char *devname, datalink_id_t *linkidp) 805*5895Syz147064 { 806*5895Syz147064 i_walk_dev_state_t state; 807*5895Syz147064 808*5895Syz147064 state.found = B_FALSE; 809*5895Syz147064 state.devname = devname; 810*5895Syz147064 811*5895Syz147064 (void) dladm_walk_datalink_id(i_dladm_walk_dev2linkid, &state, 812*5895Syz147064 DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 813*5895Syz147064 if (state.found == B_TRUE) { 814*5895Syz147064 *linkidp = state.linkid; 815*5895Syz147064 return (DLADM_STATUS_OK); 816*5895Syz147064 } else { 817*5895Syz147064 return (dladm_errno2status(ENOENT)); 818*5895Syz147064 } 819*5895Syz147064 } 820*5895Syz147064 821*5895Syz147064 static int 822*5895Syz147064 parse_devname(const char *devname, char *driver, uint_t *ppa, size_t maxlen) 823*5895Syz147064 { 824*5895Syz147064 char *cp, *tp; 825*5895Syz147064 int len; 826*5895Syz147064 827*5895Syz147064 /* 828*5895Syz147064 * device name length must not be 0, and it must end with digit. 829*5895Syz147064 */ 830*5895Syz147064 if (((len = strlen(devname)) == 0) || !isdigit(devname[len - 1])) 831*5895Syz147064 return (EINVAL); 832*5895Syz147064 833*5895Syz147064 (void) strlcpy(driver, devname, maxlen); 834*5895Syz147064 cp = (char *)&driver[len - 1]; 835*5895Syz147064 836*5895Syz147064 for (tp = cp; isdigit(*tp); tp--) { 837*5895Syz147064 if (tp <= driver) 838*5895Syz147064 return (EINVAL); 839*5895Syz147064 } 840*5895Syz147064 841*5895Syz147064 *ppa = atoi(tp + 1); 842*5895Syz147064 *(tp + 1) = '\0'; 843*5895Syz147064 return (0); 844*5895Syz147064 } 845*5895Syz147064 846*5895Syz147064 dladm_status_t 847*5895Syz147064 dladm_linkid2legacyname(datalink_id_t linkid, char *dev, size_t len) 8483871Syz147064 { 849*5895Syz147064 char devname[MAXLINKNAMELEN]; 850*5895Syz147064 uint16_t vid = VLAN_ID_NONE; 851*5895Syz147064 datalink_class_t class; 852*5895Syz147064 dladm_status_t status; 853*5895Syz147064 854*5895Syz147064 status = dladm_datalink_id2info(linkid, NULL, &class, NULL, NULL, 0); 855*5895Syz147064 if (status != DLADM_STATUS_OK) 856*5895Syz147064 goto done; 857*5895Syz147064 858*5895Syz147064 /* 859*5895Syz147064 * If this is a VLAN, we must first determine the class and linkid of 860*5895Syz147064 * the link the VLAN has been created over. 861*5895Syz147064 */ 862*5895Syz147064 if (class == DATALINK_CLASS_VLAN) { 863*5895Syz147064 dladm_vlan_attr_t dva; 864*5895Syz147064 865*5895Syz147064 status = dladm_vlan_info(linkid, &dva, DLADM_OPT_ACTIVE); 866*5895Syz147064 if (status != DLADM_STATUS_OK) 867*5895Syz147064 goto done; 868*5895Syz147064 linkid = dva.dv_linkid; 869*5895Syz147064 vid = dva.dv_vid; 870*5895Syz147064 871*5895Syz147064 if ((status = dladm_datalink_id2info(linkid, NULL, &class, NULL, 872*5895Syz147064 NULL, 0)) != DLADM_STATUS_OK) { 873*5895Syz147064 goto done; 874*5895Syz147064 } 875*5895Syz147064 } 876*5895Syz147064 877*5895Syz147064 switch (class) { 878*5895Syz147064 case DATALINK_CLASS_AGGR: { 879*5895Syz147064 dladm_aggr_grp_attr_t dga; 880*5895Syz147064 881*5895Syz147064 status = dladm_aggr_info(linkid, &dga, DLADM_OPT_ACTIVE); 882*5895Syz147064 if (status != DLADM_STATUS_OK) 883*5895Syz147064 goto done; 884*5895Syz147064 885*5895Syz147064 if (dga.lg_key == 0) { 886*5895Syz147064 /* 887*5895Syz147064 * If the key was not specified when the aggregation 888*5895Syz147064 * is created, we cannot guess its /dev node name. 889*5895Syz147064 */ 890*5895Syz147064 status = DLADM_STATUS_BADARG; 891*5895Syz147064 goto done; 892*5895Syz147064 } 893*5895Syz147064 (void) snprintf(devname, MAXLINKNAMELEN, "aggr%d", dga.lg_key); 894*5895Syz147064 break; 895*5895Syz147064 } 896*5895Syz147064 case DATALINK_CLASS_PHYS: { 897*5895Syz147064 dladm_phys_attr_t dpa; 898*5895Syz147064 899*5895Syz147064 status = dladm_phys_info(linkid, &dpa, DLADM_OPT_PERSIST); 900*5895Syz147064 if (status != DLADM_STATUS_OK) 901*5895Syz147064 goto done; 902*5895Syz147064 903*5895Syz147064 (void) strlcpy(devname, dpa.dp_dev, MAXLINKNAMELEN); 904*5895Syz147064 break; 905*5895Syz147064 } 906*5895Syz147064 default: 907*5895Syz147064 status = DLADM_STATUS_BADARG; 908*5895Syz147064 goto done; 909*5895Syz147064 } 910*5895Syz147064 911*5895Syz147064 if (vid != VLAN_ID_NONE) { 912*5895Syz147064 char drv[MAXNAMELEN]; 913*5895Syz147064 uint_t ppa; 914*5895Syz147064 915*5895Syz147064 if (parse_devname(devname, drv, &ppa, MAXNAMELEN) != 0) { 916*5895Syz147064 status = DLADM_STATUS_BADARG; 917*5895Syz147064 goto done; 918*5895Syz147064 } 919*5895Syz147064 if (snprintf(dev, len, "%s%d", drv, vid * 1000 + ppa) >= len) 920*5895Syz147064 status = DLADM_STATUS_TOOSMALL; 921*5895Syz147064 } else { 922*5895Syz147064 if (strlcpy(dev, devname, len) >= len) 923*5895Syz147064 status = DLADM_STATUS_TOOSMALL; 924*5895Syz147064 } 925*5895Syz147064 926*5895Syz147064 done: 927*5895Syz147064 return (status); 9283871Syz147064 } 929