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 2006 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 <stdio.h> 29 #include <sys/types.h> 30 #include <string.h> 31 #include <fcntl.h> 32 #include <unistd.h> 33 #include <stropts.h> 34 #include <stdlib.h> 35 #include <errno.h> 36 #include <libdevinfo.h> 37 #include <libdlpi.h> 38 #include <libdladm.h> 39 #include <sys/dld.h> 40 #include <net/if.h> 41 42 typedef struct dladm_dev { 43 char dd_name[IFNAMSIZ]; 44 struct dladm_dev *dd_next; 45 } dladm_dev_t; 46 47 typedef struct dladm_walk { 48 dladm_dev_t *dw_dev_list; 49 } dladm_walk_t; 50 51 /* 52 * Issue an ioctl to the specified file descriptor attached to the 53 * DLD control driver interface. 54 */ 55 static int 56 i_dladm_ioctl(int fd, int ic_cmd, void *ic_dp, int ic_len) 57 { 58 struct strioctl iocb; 59 60 iocb.ic_cmd = ic_cmd; 61 iocb.ic_timout = 0; 62 iocb.ic_len = ic_len; 63 iocb.ic_dp = (char *)ic_dp; 64 65 return (ioctl(fd, I_STR, &iocb)); 66 } 67 68 /* 69 * Return the attributes of the specified datalink from the DLD driver. 70 */ 71 static int 72 i_dladm_info(int fd, const char *name, dladm_attr_t *dap) 73 { 74 dld_ioc_attr_t dia; 75 76 if (strlen(name) >= IFNAMSIZ) { 77 errno = EINVAL; 78 return (-1); 79 } 80 81 (void) strlcpy(dia.dia_name, name, IFNAMSIZ); 82 83 if (i_dladm_ioctl(fd, DLDIOCATTR, &dia, sizeof (dia)) < 0) 84 return (-1); 85 86 (void) strlcpy(dap->da_dev, dia.dia_dev, MAXNAMELEN); 87 dap->da_max_sdu = dia.dia_max_sdu; 88 dap->da_vid = dia.dia_vid; 89 90 return (0); 91 } 92 93 /* 94 * Adds a datalink to the array corresponding to arg. 95 */ 96 static void 97 i_dladm_nt_net_add(void *arg, char *name) 98 { 99 dladm_walk_t *dwp = arg; 100 dladm_dev_t *ddp = dwp->dw_dev_list; 101 dladm_dev_t **lastp = &dwp->dw_dev_list; 102 103 while (ddp) { 104 /* 105 * Skip duplicates. 106 */ 107 if (strcmp(ddp->dd_name, name) == 0) 108 return; 109 110 lastp = &ddp->dd_next; 111 ddp = ddp->dd_next; 112 } 113 114 if ((ddp = malloc(sizeof (*ddp))) == NULL) 115 return; 116 117 (void) strlcpy(ddp->dd_name, name, IFNAMSIZ); 118 ddp->dd_next = NULL; 119 *lastp = ddp; 120 } 121 122 /* 123 * Walker callback invoked for each DDI_NT_NET node. 124 */ 125 static int 126 i_dladm_nt_net_walk(di_node_t node, di_minor_t minor, void *arg) 127 { 128 dl_info_ack_t dlia; 129 char name[IFNAMSIZ]; 130 int fd; 131 char *provider; 132 uint_t ppa; 133 134 provider = di_minor_name(minor); 135 136 if ((fd = dlpi_open(provider)) < 0) 137 return (DI_WALK_CONTINUE); 138 139 if (dlpi_info(fd, -1, &dlia, NULL, NULL, NULL, NULL, NULL, NULL) < 0) { 140 (void) dlpi_close(fd); 141 return (DI_WALK_CONTINUE); 142 } 143 144 if (dlia.dl_provider_style == DL_STYLE1) { 145 i_dladm_nt_net_add(arg, provider); 146 (void) dlpi_close(fd); 147 return (DI_WALK_CONTINUE); 148 } 149 150 ppa = di_instance(node); 151 152 if (dlpi_attach(fd, -1, ppa) < 0) { 153 (void) dlpi_close(fd); 154 return (DI_WALK_CONTINUE); 155 } 156 (void) snprintf(name, IFNAMSIZ - 1, "%s%d", provider, ppa); 157 i_dladm_nt_net_add(arg, name); 158 (void) dlpi_close(fd); 159 return (DI_WALK_CONTINUE); 160 } 161 162 /* 163 * Invoke the specified callback function for each active DDI_NT_NET 164 * node. 165 */ 166 int 167 dladm_walk(void (*fn)(void *, const char *), void *arg) 168 { 169 di_node_t root; 170 dladm_walk_t dw; 171 dladm_dev_t *ddp, *last_ddp; 172 173 if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL) { 174 errno = EFAULT; 175 return (-1); 176 } 177 dw.dw_dev_list = NULL; 178 179 (void) di_walk_minor(root, DDI_NT_NET, DI_CHECK_ALIAS, &dw, 180 i_dladm_nt_net_walk); 181 182 di_fini(root); 183 184 ddp = dw.dw_dev_list; 185 while (ddp) { 186 fn(arg, ddp->dd_name); 187 (void) dladm_walk_vlan(fn, arg, ddp->dd_name); 188 last_ddp = ddp; 189 ddp = ddp->dd_next; 190 free(last_ddp); 191 } 192 193 return (0); 194 } 195 196 /* 197 * Invoke the specified callback function for each vlan managed by dld 198 */ 199 int 200 dladm_walk_vlan(void (*fn)(void *, const char *), void *arg, const char *name) 201 { 202 int fd, bufsize, i; 203 int nvlan = 4094; 204 dld_ioc_vlan_t *iocp = NULL; 205 dld_vlan_info_t *dvip; 206 207 if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) 208 return (-1); 209 210 bufsize = sizeof (dld_ioc_vlan_t) + nvlan * sizeof (dld_vlan_info_t); 211 212 if ((iocp = (dld_ioc_vlan_t *)calloc(1, bufsize)) == NULL) 213 return (-1); 214 215 (void) strlcpy((char *)iocp->div_name, name, IFNAMSIZ); 216 if (i_dladm_ioctl(fd, DLDIOCVLAN, iocp, bufsize) == 0) { 217 dvip = (dld_vlan_info_t *)(iocp + 1); 218 for (i = 0; i < iocp->div_count; i++) 219 (*fn)(arg, dvip[i].dvi_name); 220 } 221 /* 222 * Note: Callers of dladm_walk_vlan() ignore the return 223 * value of this routine. So ignoring ioctl failure case 224 * and just returning 0. 225 */ 226 free(iocp); 227 (void) close(fd); 228 return (0); 229 } 230 231 232 /* 233 * Returns the current attributes of the specified datalink. 234 */ 235 int 236 dladm_info(const char *name, dladm_attr_t *dap) 237 { 238 int fd; 239 240 if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) 241 return (-1); 242 243 if (i_dladm_info(fd, name, dap) < 0) 244 goto failed; 245 246 (void) close(fd); 247 return (0); 248 249 failed: 250 (void) close(fd); 251 return (-1); 252 } 253