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