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