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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <stdio.h> 30 #include <sys/types.h> 31 #include <string.h> 32 #include <fcntl.h> 33 #include <unistd.h> 34 #include <stropts.h> 35 #include <stdlib.h> 36 #include <errno.h> 37 #include <libdevinfo.h> 38 #include <libdlpi.h> 39 #include <libdladm.h> 40 #include <sys/dld.h> 41 #include <net/if.h> 42 43 /* 44 * Issue an ioctl to the specified file descriptor attached to the 45 * DLD control driver interface. 46 */ 47 static int 48 i_dladm_ioctl(int fd, int ic_cmd, void *ic_dp, int ic_len) 49 { 50 struct strioctl iocb; 51 52 iocb.ic_cmd = ic_cmd; 53 iocb.ic_timout = 0; 54 iocb.ic_len = ic_len; 55 iocb.ic_dp = (char *)ic_dp; 56 57 return (ioctl(fd, I_STR, &iocb)); 58 } 59 60 /* 61 * Return the attributes of the specified datalink from the DLD driver. 62 */ 63 static int 64 i_dladm_info(int fd, const char *name, dladm_attr_t *dap) 65 { 66 dld_ioc_attr_t dia; 67 68 if (strlen(name) >= IFNAMSIZ) { 69 errno = EINVAL; 70 return (-1); 71 } 72 73 (void) strlcpy(dia.dia_name, name, IFNAMSIZ); 74 75 if (i_dladm_ioctl(fd, DLDIOCATTR, &dia, sizeof (dia)) < 0) 76 return (-1); 77 78 (void) strlcpy(dap->da_dev, dia.dia_dev, MAXNAMELEN); 79 dap->da_max_sdu = dia.dia_max_sdu; 80 dap->da_port = dia.dia_port; 81 dap->da_vid = dia.dia_vid; 82 83 return (0); 84 } 85 86 /* 87 * Callback function used to count the number of DDI_NT_NET. 88 */ 89 /* ARGSUSED */ 90 static int 91 i_dladm_nt_net_count(di_node_t node, di_minor_t minor, void *arg) 92 { 93 uint_t *countp = arg; 94 95 (*countp)++; 96 return (DI_WALK_CONTINUE); 97 } 98 99 /* 100 * Adds a datalink to the array corresponding to arg. 101 */ 102 static void 103 i_dladm_nt_net_add(void *arg, char *name) 104 { 105 char **array = arg; 106 char *elem; 107 108 for (;;) { 109 elem = *(array++); 110 if (elem[0] == '\0') 111 break; 112 if (strcmp(elem, name) == 0) 113 return; 114 } 115 116 (void) strlcpy(elem, name, MAXNAMELEN); 117 } 118 119 /* 120 * Walker callback invoked for each DDI_NT_NET node. 121 */ 122 static int 123 i_dladm_nt_net_walk(di_node_t node, di_minor_t minor, void *arg) 124 { 125 dl_info_ack_t dlia; 126 char name[IFNAMSIZ]; 127 int fd; 128 char *provider; 129 uint_t ppa; 130 131 provider = di_minor_name(minor); 132 133 if ((fd = dlpi_open(provider)) < 0) 134 return (DI_WALK_CONTINUE); 135 136 if (dlpi_info(fd, -1, &dlia, NULL, NULL, NULL, NULL, NULL, NULL) < 0) { 137 (void) dlpi_close(fd); 138 return (DI_WALK_CONTINUE); 139 } 140 141 if (dlia.dl_provider_style == DL_STYLE1) { 142 i_dladm_nt_net_add(arg, provider); 143 (void) dlpi_close(fd); 144 return (DI_WALK_CONTINUE); 145 } 146 147 ppa = di_instance(node); 148 149 if (dlpi_attach(fd, -1, ppa) < 0) { 150 (void) dlpi_close(fd); 151 return (DI_WALK_CONTINUE); 152 } 153 154 (void) snprintf(name, IFNAMSIZ - 1, "%s%d", provider, ppa); 155 i_dladm_nt_net_add(arg, name); 156 (void) dlpi_close(fd); 157 return (DI_WALK_CONTINUE); 158 } 159 160 /* 161 * Invoke the specified callback function for each active DDI_NT_NET 162 * node. 163 */ 164 int 165 dladm_walk(void (*fn)(void *, const char *), void *arg) 166 { 167 di_node_t root; 168 uint_t count; 169 char **array; 170 char *elem; 171 int i; 172 173 if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL) { 174 errno = EFAULT; 175 return (-1); 176 } 177 178 count = 0; 179 (void) di_walk_minor(root, DDI_NT_NET, DI_CHECK_ALIAS, (void *)&count, 180 i_dladm_nt_net_count); 181 182 if (count == 0) 183 return (dladm_walk_vlan(fn, arg)); 184 185 if ((array = malloc(count * sizeof (char *))) == NULL) 186 goto done; 187 188 for (i = 0; i < count; i++) { 189 if ((array[i] = malloc(IFNAMSIZ)) != NULL) { 190 (void) memset(array[i], '\0', IFNAMSIZ); 191 continue; 192 } 193 194 while (--i >= 0) 195 free(array[i]); 196 goto done; 197 } 198 199 (void) di_walk_minor(root, DDI_NT_NET, DI_CHECK_ALIAS, (void *)array, 200 i_dladm_nt_net_walk); 201 di_fini(root); 202 203 for (i = 0; i < count; i++) { 204 elem = array[i]; 205 if (elem[0] != '\0') 206 fn(arg, (const char *)elem); 207 free(elem); 208 } 209 210 done: 211 free(array); 212 return (dladm_walk_vlan(fn, arg)); 213 } 214 215 /* 216 * Invoke the specified callback function for each vlan managed by dld 217 */ 218 int 219 dladm_walk_vlan(void (*fn)(void *, const char *), void *arg) 220 { 221 int fd, bufsize, rc, i; 222 int nvlan = 512; 223 dld_ioc_vlan_t *iocp = NULL; 224 dld_vlan_info_t *dvip; 225 226 if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) 227 return (-1); 228 229 for (;;) { 230 bufsize = sizeof (dld_ioc_vlan_t) + 231 nvlan * sizeof (dld_vlan_info_t); 232 233 iocp = (dld_ioc_vlan_t *)calloc(1, bufsize); 234 if (iocp == NULL) 235 goto done; 236 237 rc = i_dladm_ioctl(fd, DLDIOCVLAN, iocp, bufsize); 238 if (rc == 0) 239 break; 240 241 if (errno == ENOSPC) { 242 nvlan *= 2; 243 free(iocp); 244 continue; 245 } 246 goto done; 247 } 248 249 dvip = (dld_vlan_info_t *)(iocp + 1); 250 251 for (i = 0; i < iocp->div_count; i++) { 252 if (dvip[i].dvi_vid != 0) 253 (*fn)(arg, dvip[i].dvi_name); 254 } 255 256 done: 257 free(iocp); 258 (void) close(fd); 259 return (0); 260 } 261 262 263 /* 264 * Returns the current attributes of the specified datalink. 265 */ 266 int 267 dladm_info(const char *name, dladm_attr_t *dap) 268 { 269 int fd; 270 271 if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) 272 return (-1); 273 274 if (i_dladm_info(fd, name, dap) < 0) 275 goto failed; 276 277 (void) close(fd); 278 return (0); 279 280 failed: 281 (void) close(fd); 282 return (-1); 283 } 284