1*3871Syz147064 /* 2*3871Syz147064 * CDDL HEADER START 3*3871Syz147064 * 4*3871Syz147064 * The contents of this file are subject to the terms of the 5*3871Syz147064 * Common Development and Distribution License (the "License"). 6*3871Syz147064 * You may not use this file except in compliance with the License. 7*3871Syz147064 * 8*3871Syz147064 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*3871Syz147064 * or http://www.opensolaris.org/os/licensing. 10*3871Syz147064 * See the License for the specific language governing permissions 11*3871Syz147064 * and limitations under the License. 12*3871Syz147064 * 13*3871Syz147064 * When distributing Covered Code, include this CDDL HEADER in each 14*3871Syz147064 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*3871Syz147064 * If applicable, add the following below this CDDL HEADER, with the 16*3871Syz147064 * fields enclosed by brackets "[]" replaced with your own identifying 17*3871Syz147064 * information: Portions Copyright [yyyy] [name of copyright owner] 18*3871Syz147064 * 19*3871Syz147064 * CDDL HEADER END 20*3871Syz147064 */ 21*3871Syz147064 /* 22*3871Syz147064 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23*3871Syz147064 * Use is subject to license terms. 24*3871Syz147064 */ 25*3871Syz147064 26*3871Syz147064 #pragma ident "%Z%%M% %I% %E% SMI" 27*3871Syz147064 28*3871Syz147064 #include <sys/types.h> 29*3871Syz147064 #include <unistd.h> 30*3871Syz147064 #include <errno.h> 31*3871Syz147064 #include <fcntl.h> 32*3871Syz147064 #include <strings.h> 33*3871Syz147064 #include <sys/stat.h> 34*3871Syz147064 #include <sys/dld.h> 35*3871Syz147064 #include <libdlpi.h> 36*3871Syz147064 #include <libdevinfo.h> 37*3871Syz147064 #include <libdllink.h> 38*3871Syz147064 #include <libdladm_impl.h> 39*3871Syz147064 40*3871Syz147064 typedef struct dladm_dev { 41*3871Syz147064 char dd_name[IFNAMSIZ]; 42*3871Syz147064 struct dladm_dev *dd_next; 43*3871Syz147064 } dladm_dev_t; 44*3871Syz147064 45*3871Syz147064 typedef struct dladm_walk { 46*3871Syz147064 dladm_dev_t *dw_dev_list; 47*3871Syz147064 } dladm_walk_t; 48*3871Syz147064 49*3871Syz147064 /* 50*3871Syz147064 * Return the attributes of the specified datalink from the DLD driver. 51*3871Syz147064 */ 52*3871Syz147064 static int 53*3871Syz147064 i_dladm_info(int fd, const char *name, dladm_attr_t *dap) 54*3871Syz147064 { 55*3871Syz147064 dld_ioc_attr_t dia; 56*3871Syz147064 57*3871Syz147064 if (strlen(name) >= IFNAMSIZ) { 58*3871Syz147064 errno = EINVAL; 59*3871Syz147064 return (-1); 60*3871Syz147064 } 61*3871Syz147064 62*3871Syz147064 (void) strlcpy(dia.dia_name, name, IFNAMSIZ); 63*3871Syz147064 64*3871Syz147064 if (i_dladm_ioctl(fd, DLDIOCATTR, &dia, sizeof (dia)) < 0) 65*3871Syz147064 return (-1); 66*3871Syz147064 67*3871Syz147064 (void) strlcpy(dap->da_dev, dia.dia_dev, MAXNAMELEN); 68*3871Syz147064 dap->da_max_sdu = dia.dia_max_sdu; 69*3871Syz147064 dap->da_vid = dia.dia_vid; 70*3871Syz147064 71*3871Syz147064 return (0); 72*3871Syz147064 } 73*3871Syz147064 74*3871Syz147064 /* 75*3871Syz147064 * Adds a datalink to the array corresponding to arg. 76*3871Syz147064 */ 77*3871Syz147064 static void 78*3871Syz147064 i_dladm_nt_net_add(void *arg, char *name) 79*3871Syz147064 { 80*3871Syz147064 dladm_walk_t *dwp = arg; 81*3871Syz147064 dladm_dev_t *ddp = dwp->dw_dev_list; 82*3871Syz147064 dladm_dev_t **lastp = &dwp->dw_dev_list; 83*3871Syz147064 84*3871Syz147064 while (ddp) { 85*3871Syz147064 /* 86*3871Syz147064 * Skip duplicates. 87*3871Syz147064 */ 88*3871Syz147064 if (strcmp(ddp->dd_name, name) == 0) 89*3871Syz147064 return; 90*3871Syz147064 91*3871Syz147064 lastp = &ddp->dd_next; 92*3871Syz147064 ddp = ddp->dd_next; 93*3871Syz147064 } 94*3871Syz147064 95*3871Syz147064 if ((ddp = malloc(sizeof (*ddp))) == NULL) 96*3871Syz147064 return; 97*3871Syz147064 98*3871Syz147064 (void) strlcpy(ddp->dd_name, name, IFNAMSIZ); 99*3871Syz147064 ddp->dd_next = NULL; 100*3871Syz147064 *lastp = ddp; 101*3871Syz147064 } 102*3871Syz147064 103*3871Syz147064 /* 104*3871Syz147064 * Walker callback invoked for each DDI_NT_NET node. 105*3871Syz147064 */ 106*3871Syz147064 static int 107*3871Syz147064 i_dladm_nt_net_walk(di_node_t node, di_minor_t minor, void *arg) 108*3871Syz147064 { 109*3871Syz147064 char linkname[DLPI_LINKNAME_MAX]; 110*3871Syz147064 dlpi_handle_t dh; 111*3871Syz147064 112*3871Syz147064 if (dlpi_makelink(linkname, di_minor_name(minor), 113*3871Syz147064 di_instance(node)) != DLPI_SUCCESS) 114*3871Syz147064 return (DI_WALK_CONTINUE); 115*3871Syz147064 116*3871Syz147064 if (dlpi_open(linkname, &dh, 0) == DLPI_SUCCESS) { 117*3871Syz147064 i_dladm_nt_net_add(arg, linkname); 118*3871Syz147064 dlpi_close(dh); 119*3871Syz147064 } 120*3871Syz147064 return (DI_WALK_CONTINUE); 121*3871Syz147064 } 122*3871Syz147064 123*3871Syz147064 /* 124*3871Syz147064 * Hold a data-link. 125*3871Syz147064 */ 126*3871Syz147064 static int 127*3871Syz147064 i_dladm_hold_link(const char *name, zoneid_t zoneid, boolean_t docheck) 128*3871Syz147064 { 129*3871Syz147064 int fd; 130*3871Syz147064 dld_hold_vlan_t dhv; 131*3871Syz147064 132*3871Syz147064 if (strlen(name) >= IFNAMSIZ) { 133*3871Syz147064 errno = EINVAL; 134*3871Syz147064 return (-1); 135*3871Syz147064 } 136*3871Syz147064 137*3871Syz147064 if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) 138*3871Syz147064 return (-1); 139*3871Syz147064 140*3871Syz147064 bzero(&dhv, sizeof (dld_hold_vlan_t)); 141*3871Syz147064 (void) strlcpy(dhv.dhv_name, name, IFNAMSIZ); 142*3871Syz147064 dhv.dhv_zid = zoneid; 143*3871Syz147064 dhv.dhv_docheck = docheck; 144*3871Syz147064 145*3871Syz147064 if (i_dladm_ioctl(fd, DLDIOCHOLDVLAN, &dhv, sizeof (dhv)) < 0) { 146*3871Syz147064 int olderrno = errno; 147*3871Syz147064 148*3871Syz147064 (void) close(fd); 149*3871Syz147064 errno = olderrno; 150*3871Syz147064 return (-1); 151*3871Syz147064 } 152*3871Syz147064 153*3871Syz147064 (void) close(fd); 154*3871Syz147064 return (0); 155*3871Syz147064 } 156*3871Syz147064 157*3871Syz147064 /* 158*3871Syz147064 * Release a data-link. 159*3871Syz147064 */ 160*3871Syz147064 static int 161*3871Syz147064 i_dladm_rele_link(const char *name, zoneid_t zoneid, boolean_t docheck) 162*3871Syz147064 { 163*3871Syz147064 int fd; 164*3871Syz147064 dld_hold_vlan_t dhv; 165*3871Syz147064 166*3871Syz147064 if (strlen(name) >= IFNAMSIZ) { 167*3871Syz147064 errno = EINVAL; 168*3871Syz147064 return (-1); 169*3871Syz147064 } 170*3871Syz147064 171*3871Syz147064 if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) 172*3871Syz147064 return (-1); 173*3871Syz147064 174*3871Syz147064 bzero(&dhv, sizeof (dld_hold_vlan_t)); 175*3871Syz147064 (void) strlcpy(dhv.dhv_name, name, IFNAMSIZ); 176*3871Syz147064 dhv.dhv_zid = zoneid; 177*3871Syz147064 dhv.dhv_docheck = docheck; 178*3871Syz147064 179*3871Syz147064 if (i_dladm_ioctl(fd, DLDIOCRELEVLAN, &dhv, sizeof (dhv)) < 0) { 180*3871Syz147064 int olderrno = errno; 181*3871Syz147064 182*3871Syz147064 (void) close(fd); 183*3871Syz147064 errno = olderrno; 184*3871Syz147064 return (-1); 185*3871Syz147064 } 186*3871Syz147064 187*3871Syz147064 (void) close(fd); 188*3871Syz147064 return (0); 189*3871Syz147064 } 190*3871Syz147064 191*3871Syz147064 /* 192*3871Syz147064 * Invoke the specified callback function for each active DDI_NT_NET 193*3871Syz147064 * node. 194*3871Syz147064 */ 195*3871Syz147064 int 196*3871Syz147064 dladm_walk(void (*fn)(void *, const char *), void *arg) 197*3871Syz147064 { 198*3871Syz147064 di_node_t root; 199*3871Syz147064 dladm_walk_t dw; 200*3871Syz147064 dladm_dev_t *ddp, *last_ddp; 201*3871Syz147064 202*3871Syz147064 if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL) { 203*3871Syz147064 errno = EFAULT; 204*3871Syz147064 return (-1); 205*3871Syz147064 } 206*3871Syz147064 dw.dw_dev_list = NULL; 207*3871Syz147064 208*3871Syz147064 (void) di_walk_minor(root, DDI_NT_NET, DI_CHECK_ALIAS, &dw, 209*3871Syz147064 i_dladm_nt_net_walk); 210*3871Syz147064 211*3871Syz147064 di_fini(root); 212*3871Syz147064 213*3871Syz147064 ddp = dw.dw_dev_list; 214*3871Syz147064 while (ddp) { 215*3871Syz147064 fn(arg, ddp->dd_name); 216*3871Syz147064 last_ddp = ddp; 217*3871Syz147064 ddp = ddp->dd_next; 218*3871Syz147064 free(last_ddp); 219*3871Syz147064 } 220*3871Syz147064 221*3871Syz147064 return (0); 222*3871Syz147064 } 223*3871Syz147064 224*3871Syz147064 /* 225*3871Syz147064 * MAC Administration Library. 226*3871Syz147064 * 227*3871Syz147064 * This library is used by administration tools such as dladm(1M) to 228*3871Syz147064 * iterate through the list of MAC interfaces 229*3871Syz147064 * 230*3871Syz147064 */ 231*3871Syz147064 232*3871Syz147064 typedef struct dladm_mac_dev { 233*3871Syz147064 char dm_name[MAXNAMELEN]; 234*3871Syz147064 struct dladm_mac_dev *dm_next; 235*3871Syz147064 } dladm_mac_dev_t; 236*3871Syz147064 237*3871Syz147064 typedef struct macadm_walk { 238*3871Syz147064 dladm_mac_dev_t *dmd_dev_list; 239*3871Syz147064 } dladm_mac_walk_t; 240*3871Syz147064 241*3871Syz147064 /* 242*3871Syz147064 * Local callback invoked for each DDI_NT_NET node. 243*3871Syz147064 */ 244*3871Syz147064 /* ARGSUSED */ 245*3871Syz147064 static int 246*3871Syz147064 i_dladm_mac_walk(di_node_t node, di_minor_t minor, void *arg) 247*3871Syz147064 { 248*3871Syz147064 dladm_mac_walk_t *dmwp = arg; 249*3871Syz147064 dladm_mac_dev_t *dmdp = dmwp->dmd_dev_list; 250*3871Syz147064 dladm_mac_dev_t **last_dmdp = &dmwp->dmd_dev_list; 251*3871Syz147064 char mac[MAXNAMELEN]; 252*3871Syz147064 253*3871Syz147064 (void) snprintf(mac, MAXNAMELEN, "%s%d", 254*3871Syz147064 di_driver_name(node), di_instance(node)); 255*3871Syz147064 256*3871Syz147064 /* 257*3871Syz147064 * Skip aggregations. 258*3871Syz147064 */ 259*3871Syz147064 if (strcmp("aggr", di_driver_name(node)) == 0) 260*3871Syz147064 return (DI_WALK_CONTINUE); 261*3871Syz147064 262*3871Syz147064 while (dmdp) { 263*3871Syz147064 /* 264*3871Syz147064 * Skip duplicates. 265*3871Syz147064 */ 266*3871Syz147064 if (strcmp(dmdp->dm_name, mac) == 0) 267*3871Syz147064 return (DI_WALK_CONTINUE); 268*3871Syz147064 269*3871Syz147064 last_dmdp = &dmdp->dm_next; 270*3871Syz147064 dmdp = dmdp->dm_next; 271*3871Syz147064 } 272*3871Syz147064 273*3871Syz147064 if ((dmdp = malloc(sizeof (*dmdp))) == NULL) 274*3871Syz147064 return (DI_WALK_CONTINUE); 275*3871Syz147064 276*3871Syz147064 (void) strlcpy(dmdp->dm_name, mac, MAXNAMELEN); 277*3871Syz147064 dmdp->dm_next = NULL; 278*3871Syz147064 *last_dmdp = dmdp; 279*3871Syz147064 280*3871Syz147064 return (DI_WALK_CONTINUE); 281*3871Syz147064 } 282*3871Syz147064 283*3871Syz147064 /* 284*3871Syz147064 * Invoke the specified callback for each DDI_NT_MAC node. 285*3871Syz147064 */ 286*3871Syz147064 int 287*3871Syz147064 dladm_mac_walk(void (*fn)(void *, const char *), void *arg) 288*3871Syz147064 { 289*3871Syz147064 di_node_t root; 290*3871Syz147064 dladm_mac_walk_t dmw; 291*3871Syz147064 dladm_mac_dev_t *dmdp, *next; 292*3871Syz147064 293*3871Syz147064 if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL) 294*3871Syz147064 return (-1); 295*3871Syz147064 296*3871Syz147064 dmw.dmd_dev_list = NULL; 297*3871Syz147064 298*3871Syz147064 (void) di_walk_minor(root, DDI_NT_NET, DI_CHECK_ALIAS, &dmw, 299*3871Syz147064 i_dladm_mac_walk); 300*3871Syz147064 301*3871Syz147064 di_fini(root); 302*3871Syz147064 303*3871Syz147064 dmdp = dmw.dmd_dev_list; 304*3871Syz147064 for (dmdp = dmw.dmd_dev_list; dmdp != NULL; dmdp = next) { 305*3871Syz147064 next = dmdp->dm_next; 306*3871Syz147064 (*fn)(arg, dmdp->dm_name); 307*3871Syz147064 free(dmdp); 308*3871Syz147064 } 309*3871Syz147064 310*3871Syz147064 return (0); 311*3871Syz147064 } 312*3871Syz147064 313*3871Syz147064 /* 314*3871Syz147064 * Returns the current attributes of the specified datalink. 315*3871Syz147064 */ 316*3871Syz147064 int 317*3871Syz147064 dladm_info(const char *name, dladm_attr_t *dap) 318*3871Syz147064 { 319*3871Syz147064 int fd; 320*3871Syz147064 321*3871Syz147064 if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) 322*3871Syz147064 return (-1); 323*3871Syz147064 324*3871Syz147064 if (i_dladm_info(fd, name, dap) < 0) 325*3871Syz147064 goto failed; 326*3871Syz147064 327*3871Syz147064 (void) close(fd); 328*3871Syz147064 return (0); 329*3871Syz147064 330*3871Syz147064 failed: 331*3871Syz147064 (void) close(fd); 332*3871Syz147064 return (-1); 333*3871Syz147064 } 334*3871Syz147064 335*3871Syz147064 const char * 336*3871Syz147064 dladm_linkstate2str(link_state_t state, char *buf) 337*3871Syz147064 { 338*3871Syz147064 const char *s; 339*3871Syz147064 340*3871Syz147064 switch (state) { 341*3871Syz147064 case LINK_STATE_UP: 342*3871Syz147064 s = "up"; 343*3871Syz147064 break; 344*3871Syz147064 case LINK_STATE_DOWN: 345*3871Syz147064 s = "down"; 346*3871Syz147064 break; 347*3871Syz147064 default: 348*3871Syz147064 s = "unknown"; 349*3871Syz147064 break; 350*3871Syz147064 } 351*3871Syz147064 (void) snprintf(buf, DLADM_STRSIZE, "%s", s); 352*3871Syz147064 return (buf); 353*3871Syz147064 } 354*3871Syz147064 355*3871Syz147064 const char * 356*3871Syz147064 dladm_linkduplex2str(link_duplex_t duplex, char *buf) 357*3871Syz147064 { 358*3871Syz147064 const char *s; 359*3871Syz147064 360*3871Syz147064 switch (duplex) { 361*3871Syz147064 case LINK_DUPLEX_FULL: 362*3871Syz147064 s = "full"; 363*3871Syz147064 break; 364*3871Syz147064 case LINK_DUPLEX_HALF: 365*3871Syz147064 s = "half"; 366*3871Syz147064 break; 367*3871Syz147064 default: 368*3871Syz147064 s = "unknown"; 369*3871Syz147064 break; 370*3871Syz147064 } 371*3871Syz147064 (void) snprintf(buf, DLADM_STRSIZE, "%s", s); 372*3871Syz147064 return (buf); 373*3871Syz147064 } 374*3871Syz147064 375*3871Syz147064 /* 376*3871Syz147064 * Do a "hold" operation to a link. 377*3871Syz147064 */ 378*3871Syz147064 int 379*3871Syz147064 dladm_hold_link(const char *name, zoneid_t zoneid, boolean_t docheck) 380*3871Syz147064 { 381*3871Syz147064 return (i_dladm_hold_link(name, zoneid, docheck)); 382*3871Syz147064 } 383*3871Syz147064 384*3871Syz147064 /* 385*3871Syz147064 * Do a "release" operation to a link. 386*3871Syz147064 */ 387*3871Syz147064 int 388*3871Syz147064 dladm_rele_link(const char *name, zoneid_t zoneid, boolean_t docheck) 389*3871Syz147064 { 390*3871Syz147064 return (i_dladm_rele_link(name, zoneid, docheck)); 391*3871Syz147064 } 392