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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <stdio.h> 27 #include <ctype.h> 28 #include <locale.h> 29 #include <signal.h> 30 #include <stdarg.h> 31 #include <stdlib.h> 32 #include <fcntl.h> 33 #include <string.h> 34 #include <stropts.h> 35 #include <sys/stat.h> 36 #include <errno.h> 37 #include <kstat.h> 38 #include <strings.h> 39 #include <getopt.h> 40 #include <unistd.h> 41 #include <priv.h> 42 #include <termios.h> 43 #include <pwd.h> 44 #include <auth_attr.h> 45 #include <auth_list.h> 46 #include <libintl.h> 47 #include <libdevinfo.h> 48 #include <libdlpi.h> 49 #include <libdladm.h> 50 #include <libdllink.h> 51 #include <libdlstat.h> 52 #include <libdlaggr.h> 53 #include <libdlwlan.h> 54 #include <libdlvlan.h> 55 #include <libdlvnic.h> 56 #include <libdlether.h> 57 #include <libinetutil.h> 58 #include <bsm/adt.h> 59 #include <bsm/adt_event.h> 60 #include <libdlvnic.h> 61 #include <sys/types.h> 62 #include <sys/socket.h> 63 #include <sys/processor.h> 64 #include <netinet/in.h> 65 #include <arpa/inet.h> 66 #include <net/if_types.h> 67 #include <stddef.h> 68 #include <ofmt.h> 69 70 #define MAXPORT 256 71 #define MAXVNIC 256 72 #define BUFLEN(lim, ptr) (((lim) > (ptr)) ? ((lim) - (ptr)) : 0) 73 #define MAXLINELEN 1024 74 #define SMF_UPGRADE_FILE "/var/svc/profile/upgrade" 75 #define SMF_UPGRADEDATALINK_FILE "/var/svc/profile/upgrade_datalink" 76 #define SMF_DLADM_UPGRADE_MSG " # added by dladm(1M)" 77 #define DLADM_DEFAULT_COL 80 78 79 /* 80 * used by the wifi show-* commands to set up ofmt_field_t structures. 81 */ 82 #define WIFI_CMD_SCAN 0x00000001 83 #define WIFI_CMD_SHOW 0x00000002 84 #define WIFI_CMD_ALL (WIFI_CMD_SCAN | WIFI_CMD_SHOW) 85 86 typedef struct show_state { 87 boolean_t ls_firstonly; 88 boolean_t ls_donefirst; 89 pktsum_t ls_prevstats; 90 uint32_t ls_flags; 91 dladm_status_t ls_status; 92 ofmt_handle_t ls_ofmt; 93 boolean_t ls_parsable; 94 boolean_t ls_mac; 95 boolean_t ls_hwgrp; 96 } show_state_t; 97 98 typedef struct show_grp_state { 99 pktsum_t gs_prevstats[MAXPORT]; 100 uint32_t gs_flags; 101 dladm_status_t gs_status; 102 boolean_t gs_parsable; 103 boolean_t gs_lacp; 104 boolean_t gs_extended; 105 boolean_t gs_stats; 106 boolean_t gs_firstonly; 107 boolean_t gs_donefirst; 108 ofmt_handle_t gs_ofmt; 109 } show_grp_state_t; 110 111 typedef struct show_vnic_state { 112 datalink_id_t vs_vnic_id; 113 datalink_id_t vs_link_id; 114 char vs_vnic[MAXLINKNAMELEN]; 115 char vs_link[MAXLINKNAMELEN]; 116 boolean_t vs_parsable; 117 boolean_t vs_found; 118 boolean_t vs_firstonly; 119 boolean_t vs_donefirst; 120 boolean_t vs_stats; 121 boolean_t vs_printstats; 122 pktsum_t vs_totalstats; 123 pktsum_t vs_prevstats[MAXVNIC]; 124 boolean_t vs_etherstub; 125 dladm_status_t vs_status; 126 uint32_t vs_flags; 127 ofmt_handle_t vs_ofmt; 128 } show_vnic_state_t; 129 130 typedef struct show_usage_state_s { 131 boolean_t us_plot; 132 boolean_t us_parsable; 133 boolean_t us_printheader; 134 boolean_t us_first; 135 boolean_t us_showall; 136 ofmt_handle_t us_ofmt; 137 } show_usage_state_t; 138 139 /* 140 * callback functions for printing output and error diagnostics. 141 */ 142 static ofmt_cb_t print_default_cb, print_link_stats_cb, print_linkprop_cb; 143 static ofmt_cb_t print_lacp_cb, print_phys_one_mac_cb; 144 static ofmt_cb_t print_xaggr_cb, print_aggr_stats_cb; 145 static ofmt_cb_t print_phys_one_hwgrp_cb, print_wlan_attr_cb; 146 static ofmt_cb_t print_wifi_status_cb, print_link_attr_cb; 147 static void dladm_ofmt_check(ofmt_status_t, boolean_t, ofmt_handle_t); 148 149 typedef void cmdfunc_t(int, char **, const char *); 150 151 static cmdfunc_t do_show_link, do_show_wifi, do_show_phys; 152 static cmdfunc_t do_create_aggr, do_delete_aggr, do_add_aggr, do_remove_aggr; 153 static cmdfunc_t do_modify_aggr, do_show_aggr, do_up_aggr; 154 static cmdfunc_t do_scan_wifi, do_connect_wifi, do_disconnect_wifi; 155 static cmdfunc_t do_show_linkprop, do_set_linkprop, do_reset_linkprop; 156 static cmdfunc_t do_create_secobj, do_delete_secobj, do_show_secobj; 157 static cmdfunc_t do_init_linkprop, do_init_secobj; 158 static cmdfunc_t do_create_vlan, do_delete_vlan, do_up_vlan, do_show_vlan; 159 static cmdfunc_t do_rename_link, do_delete_phys, do_init_phys; 160 static cmdfunc_t do_show_linkmap; 161 static cmdfunc_t do_show_ether; 162 static cmdfunc_t do_create_vnic, do_delete_vnic, do_show_vnic; 163 static cmdfunc_t do_up_vnic; 164 static cmdfunc_t do_create_etherstub, do_delete_etherstub, do_show_etherstub; 165 static cmdfunc_t do_show_usage; 166 167 static void do_up_vnic_common(int, char **, const char *, boolean_t); 168 169 static void altroot_cmd(char *, int, char **); 170 static int show_linkprop_onelink(dladm_handle_t, datalink_id_t, void *); 171 172 static void link_stats(datalink_id_t, uint_t, char *, show_state_t *); 173 static void aggr_stats(datalink_id_t, show_grp_state_t *, uint_t); 174 static void vnic_stats(show_vnic_state_t *, uint32_t); 175 176 static int get_one_kstat(const char *, const char *, uint8_t, 177 void *, boolean_t); 178 static void get_mac_stats(const char *, pktsum_t *); 179 static void get_link_stats(const char *, pktsum_t *); 180 static uint64_t get_ifspeed(const char *, boolean_t); 181 static const char *get_linkstate(const char *, boolean_t, char *); 182 static const char *get_linkduplex(const char *, boolean_t, char *); 183 184 static int show_etherprop(dladm_handle_t, datalink_id_t, void *); 185 static void show_ether_xprop(void *, dladm_ether_info_t *); 186 static boolean_t link_is_ether(const char *, datalink_id_t *); 187 188 static boolean_t str2int(const char *, int *); 189 static void die(const char *, ...); 190 static void die_optdup(int); 191 static void die_opterr(int, int, const char *); 192 static void die_dlerr(dladm_status_t, const char *, ...); 193 static void warn(const char *, ...); 194 static void warn_dlerr(dladm_status_t, const char *, ...); 195 196 typedef struct cmd { 197 char *c_name; 198 cmdfunc_t *c_fn; 199 const char *c_usage; 200 } cmd_t; 201 202 static cmd_t cmds[] = { 203 { "rename-link", do_rename_link, 204 " rename-link <oldlink> <newlink>" }, 205 { "show-link", do_show_link, 206 " show-link [-pP] [-o <field>,..] [-s [-i <interval>]] " 207 "[<link>]\n" }, 208 { "create-aggr", do_create_aggr, 209 " create-aggr [-t] [-P <policy>] [-L <mode>] [-T <time>] " 210 "[-u <address>]\n" 211 "\t\t -l <link> [-l <link>...] <link>" }, 212 { "delete-aggr", do_delete_aggr, 213 " delete-aggr [-t] <link>" }, 214 { "add-aggr", do_add_aggr, 215 " add-aggr [-t] -l <link> [-l <link>...] <link>" }, 216 { "remove-aggr", do_remove_aggr, 217 " remove-aggr [-t] -l <link> [-l <link>...] <link>" }, 218 { "modify-aggr", do_modify_aggr, 219 " modify-aggr [-t] [-P <policy>] [-L <mode>] [-T <time>] " 220 "[-u <address>]\n" 221 "\t\t <link>" }, 222 { "show-aggr", do_show_aggr, 223 " show-aggr [-pPLx] [-o <field>,..] [-s [-i <interval>]] " 224 "[<link>]\n" }, 225 { "up-aggr", do_up_aggr, NULL }, 226 { "scan-wifi", do_scan_wifi, 227 " scan-wifi [-p] [-o <field>,...] [<link>]" }, 228 { "connect-wifi", do_connect_wifi, 229 " connect-wifi [-e <essid>] [-i <bssid>] [-k <key>,...] " 230 "[-s wep|wpa]\n" 231 "\t\t [-a open|shared] [-b bss|ibss] [-c] [-m a|b|g] " 232 "[-T <time>]\n" 233 "\t\t [<link>]" }, 234 { "disconnect-wifi", do_disconnect_wifi, 235 " disconnect-wifi [-a] [<link>]" }, 236 { "show-wifi", do_show_wifi, 237 " show-wifi [-p] [-o <field>,...] [<link>]\n" }, 238 { "set-linkprop", do_set_linkprop, 239 " set-linkprop [-t] -p <prop>=<value>[,...] <name>" }, 240 { "reset-linkprop", do_reset_linkprop, 241 " reset-linkprop [-t] [-p <prop>,...] <name>" }, 242 { "show-linkprop", do_show_linkprop, 243 " show-linkprop [-cP] [-o <field>,...] [-p <prop>,...] " 244 "<name>\n" }, 245 { "show-ether", do_show_ether, 246 " show-ether [-px][-o <field>,...] <link>\n" }, 247 { "create-secobj", do_create_secobj, 248 " create-secobj [-t] [-f <file>] -c <class> <secobj>" }, 249 { "delete-secobj", do_delete_secobj, 250 " delete-secobj [-t] <secobj>[,...]" }, 251 { "show-secobj", do_show_secobj, 252 " show-secobj [-pP] [-o <field>,...] [<secobj>,...]\n" }, 253 { "init-linkprop", do_init_linkprop, NULL }, 254 { "init-secobj", do_init_secobj, NULL }, 255 { "create-vlan", do_create_vlan, 256 " create-vlan [-ft] -l <link> -v <vid> [link]" }, 257 { "delete-vlan", do_delete_vlan, 258 " delete-vlan [-t] <link>" }, 259 { "show-vlan", do_show_vlan, 260 " show-vlan [-pP] [-o <field>,..] [<link>]\n" }, 261 { "up-vlan", do_up_vlan, NULL }, 262 { "delete-phys", do_delete_phys, 263 " delete-phys <link>" }, 264 { "show-phys", do_show_phys, 265 " show-phys [-pP] [-o <field>,..] [-H] [<link>]\n"}, 266 { "init-phys", do_init_phys, NULL }, 267 { "show-linkmap", do_show_linkmap, NULL }, 268 { "create-vnic", do_create_vnic, 269 " create-vnic [-t] -l <link> [-m <value> | auto |\n" 270 "\t\t {factory [-n <slot-id>]} | {random [-r <prefix>]}]\n" 271 "\t\t [-v <vid> [-f]] [-p <prop>=<value>[,...]] [-H] " 272 "<vnic-link>" }, 273 { "delete-vnic", do_delete_vnic, 274 " delete-vnic [-t] <vnic-link>" }, 275 { "show-vnic", do_show_vnic, 276 " show-vnic [-pP] [-l <link>] [-s [-i <interval>]] " 277 "[<link>]\n" }, 278 { "up-vnic", do_up_vnic, NULL }, 279 { "create-etherstub", do_create_etherstub, 280 " create-etherstub [-t] <link>" }, 281 { "delete-etherstub", do_delete_etherstub, 282 " delete-etherstub [-t] <link>" }, 283 { "show-etherstub", do_show_etherstub, 284 " show-etherstub [-t] [<link>]\n" }, 285 { "show-usage", do_show_usage, 286 " show-usage [-a] [-d | -F <format>] " 287 "[-s <DD/MM/YYYY,HH:MM:SS>]\n" 288 "\t\t [-e <DD/MM/YYYY,HH:MM:SS>] -f <logfile> [<link>]" } 289 }; 290 291 static const struct option lopts[] = { 292 {"vlan-id", required_argument, 0, 'v'}, 293 {"output", required_argument, 0, 'o'}, 294 {"dev", required_argument, 0, 'd'}, 295 {"policy", required_argument, 0, 'P'}, 296 {"lacp-mode", required_argument, 0, 'L'}, 297 {"lacp-timer", required_argument, 0, 'T'}, 298 {"unicast", required_argument, 0, 'u'}, 299 {"temporary", no_argument, 0, 't'}, 300 {"root-dir", required_argument, 0, 'R'}, 301 {"link", required_argument, 0, 'l'}, 302 {"forcible", no_argument, 0, 'f'}, 303 {"bw-limit", required_argument, 0, 'b'}, 304 {"mac-address", required_argument, 0, 'm'}, 305 {"slot", required_argument, 0, 'n'}, 306 { 0, 0, 0, 0 } 307 }; 308 309 static const struct option show_lopts[] = { 310 {"statistics", no_argument, 0, 's'}, 311 {"continuous", no_argument, 0, 'S'}, 312 {"interval", required_argument, 0, 'i'}, 313 {"parsable", no_argument, 0, 'p'}, 314 {"parseable", no_argument, 0, 'p'}, 315 {"extended", no_argument, 0, 'x'}, 316 {"output", required_argument, 0, 'o'}, 317 {"persistent", no_argument, 0, 'P'}, 318 {"lacp", no_argument, 0, 'L'}, 319 { 0, 0, 0, 0 } 320 }; 321 322 static const struct option prop_longopts[] = { 323 {"temporary", no_argument, 0, 't' }, 324 {"output", required_argument, 0, 'o' }, 325 {"root-dir", required_argument, 0, 'R' }, 326 {"prop", required_argument, 0, 'p' }, 327 {"parsable", no_argument, 0, 'c' }, 328 {"parseable", no_argument, 0, 'c' }, 329 {"persistent", no_argument, 0, 'P' }, 330 { 0, 0, 0, 0 } 331 }; 332 333 static const struct option wifi_longopts[] = { 334 {"parsable", no_argument, 0, 'p' }, 335 {"parseable", no_argument, 0, 'p' }, 336 {"output", required_argument, 0, 'o' }, 337 {"essid", required_argument, 0, 'e' }, 338 {"bsstype", required_argument, 0, 'b' }, 339 {"mode", required_argument, 0, 'm' }, 340 {"key", required_argument, 0, 'k' }, 341 {"sec", required_argument, 0, 's' }, 342 {"auth", required_argument, 0, 'a' }, 343 {"create-ibss", required_argument, 0, 'c' }, 344 {"timeout", required_argument, 0, 'T' }, 345 {"all-links", no_argument, 0, 'a' }, 346 {"temporary", no_argument, 0, 't' }, 347 {"root-dir", required_argument, 0, 'R' }, 348 {"persistent", no_argument, 0, 'P' }, 349 {"file", required_argument, 0, 'f' }, 350 { 0, 0, 0, 0 } 351 }; 352 static const struct option showeth_lopts[] = { 353 {"parsable", no_argument, 0, 'p' }, 354 {"parseable", no_argument, 0, 'p' }, 355 {"extended", no_argument, 0, 'x' }, 356 {"output", required_argument, 0, 'o' }, 357 { 0, 0, 0, 0 } 358 }; 359 360 static const struct option vnic_lopts[] = { 361 {"temporary", no_argument, 0, 't' }, 362 {"root-dir", required_argument, 0, 'R' }, 363 {"dev", required_argument, 0, 'd' }, 364 {"mac-address", required_argument, 0, 'm' }, 365 {"cpus", required_argument, 0, 'c' }, 366 {"bw-limit", required_argument, 0, 'b' }, 367 {"slot", required_argument, 0, 'n' }, 368 {"mac-prefix", required_argument, 0, 'r' }, 369 { 0, 0, 0, 0 } 370 }; 371 372 static const struct option etherstub_lopts[] = { 373 {"temporary", no_argument, 0, 't' }, 374 {"root-dir", required_argument, 0, 'R' }, 375 { 0, 0, 0, 0 } 376 }; 377 378 static const struct option usage_opts[] = { 379 {"file", required_argument, 0, 'f' }, 380 {"format", required_argument, 0, 'F' }, 381 {"start", required_argument, 0, 's' }, 382 {"stop", required_argument, 0, 'e' }, 383 { 0, 0, 0, 0 } 384 }; 385 386 /* 387 * structures for 'dladm show-ether' 388 */ 389 static const char *ptype[] = {LEI_ATTR_NAMES}; 390 391 typedef struct ether_fields_buf_s 392 { 393 char eth_link[15]; 394 char eth_ptype[8]; 395 char eth_state[8]; 396 char eth_autoneg[5]; 397 char eth_spdx[31]; 398 char eth_pause[6]; 399 char eth_rem_fault[16]; 400 } ether_fields_buf_t; 401 402 static ofmt_field_t ether_fields[] = { 403 /* name, field width, offset callback */ 404 { "LINK", 16, 405 offsetof(ether_fields_buf_t, eth_link), print_default_cb}, 406 { "PTYPE", 9, 407 offsetof(ether_fields_buf_t, eth_ptype), print_default_cb}, 408 { "STATE", 9, 409 offsetof(ether_fields_buf_t, eth_state), 410 print_default_cb}, 411 { "AUTO", 6, 412 offsetof(ether_fields_buf_t, eth_autoneg), print_default_cb}, 413 { "SPEED-DUPLEX", 32, 414 offsetof(ether_fields_buf_t, eth_spdx), print_default_cb}, 415 { "PAUSE", 7, 416 offsetof(ether_fields_buf_t, eth_pause), print_default_cb}, 417 { "REM_FAULT", 17, 418 offsetof(ether_fields_buf_t, eth_rem_fault), print_default_cb}, 419 {NULL, 0, 420 0, NULL}} 421 ; 422 423 typedef struct print_ether_state { 424 const char *es_link; 425 boolean_t es_parsable; 426 boolean_t es_header; 427 boolean_t es_extended; 428 ofmt_handle_t es_ofmt; 429 } print_ether_state_t; 430 431 /* 432 * structures for 'dladm show-link -s' (print statistics) 433 */ 434 typedef enum { 435 LINK_S_LINK, 436 LINK_S_IPKTS, 437 LINK_S_RBYTES, 438 LINK_S_IERRORS, 439 LINK_S_OPKTS, 440 LINK_S_OBYTES, 441 LINK_S_OERRORS 442 } link_s_field_index_t; 443 444 static ofmt_field_t link_s_fields[] = { 445 /* name, field width, index, callback */ 446 { "LINK", 15, LINK_S_LINK, print_link_stats_cb}, 447 { "IPACKETS", 10, LINK_S_IPKTS, print_link_stats_cb}, 448 { "RBYTES", 8, LINK_S_RBYTES, print_link_stats_cb}, 449 { "IERRORS", 10, LINK_S_IERRORS, print_link_stats_cb}, 450 { "OPACKETS", 12, LINK_S_OPKTS, print_link_stats_cb}, 451 { "OBYTES", 12, LINK_S_OBYTES, print_link_stats_cb}, 452 { "OERRORS", 8, LINK_S_OERRORS, print_link_stats_cb}} 453 ; 454 455 typedef struct link_args_s { 456 char *link_s_link; 457 pktsum_t *link_s_psum; 458 } link_args_t; 459 460 /* 461 * buffer used by print functions for show-{link,phys,vlan} commands. 462 */ 463 typedef struct link_fields_buf_s { 464 char link_name[MAXLINKNAMELEN]; 465 char link_class[DLADM_STRSIZE]; 466 char link_mtu[11]; 467 char link_state[DLADM_STRSIZE]; 468 char link_over[MAXLINKNAMELEN]; 469 char link_phys_state[DLADM_STRSIZE]; 470 char link_phys_media[DLADM_STRSIZE]; 471 char link_phys_speed[DLADM_STRSIZE]; 472 char link_phys_duplex[DLPI_LINKNAME_MAX]; 473 char link_phys_device[DLPI_LINKNAME_MAX]; 474 char link_flags[6]; 475 char link_vlan_vid[6]; 476 } link_fields_buf_t; 477 478 /* 479 * structures for 'dladm show-link' 480 */ 481 static ofmt_field_t link_fields[] = { 482 /* name, field width, index, callback */ 483 { "LINK", 12, 484 offsetof(link_fields_buf_t, link_name), print_default_cb}, 485 { "CLASS", 9, 486 offsetof(link_fields_buf_t, link_class), print_default_cb}, 487 { "MTU", 7, 488 offsetof(link_fields_buf_t, link_mtu), print_default_cb}, 489 { "STATE", 9, 490 offsetof(link_fields_buf_t, link_state), print_default_cb}, 491 { "OVER", DLPI_LINKNAME_MAX, 492 offsetof(link_fields_buf_t, link_over), print_default_cb}, 493 { NULL, 0, 0, NULL}} 494 ; 495 496 /* 497 * structures for 'dladm show-aggr' 498 */ 499 typedef struct laggr_fields_buf_s { 500 char laggr_name[DLPI_LINKNAME_MAX]; 501 char laggr_policy[9]; 502 char laggr_addrpolicy[ETHERADDRL * 3 + 3]; 503 char laggr_lacpactivity[14]; 504 char laggr_lacptimer[DLADM_STRSIZE]; 505 char laggr_flags[7]; 506 } laggr_fields_buf_t; 507 508 typedef struct laggr_args_s { 509 int laggr_lport; /* -1 indicates the aggr itself */ 510 const char *laggr_link; 511 dladm_aggr_grp_attr_t *laggr_ginfop; 512 dladm_status_t *laggr_status; 513 pktsum_t *laggr_pktsumtot; /* -s only */ 514 pktsum_t *laggr_diffstats; /* -s only */ 515 boolean_t laggr_parsable; 516 } laggr_args_t; 517 518 static ofmt_field_t laggr_fields[] = { 519 /* name, field width, offset, callback */ 520 { "LINK", 16, 521 offsetof(laggr_fields_buf_t, laggr_name), print_default_cb}, 522 { "POLICY", 9, 523 offsetof(laggr_fields_buf_t, laggr_policy), print_default_cb}, 524 { "ADDRPOLICY", ETHERADDRL * 3 + 3, 525 offsetof(laggr_fields_buf_t, laggr_addrpolicy), print_default_cb}, 526 { "LACPACTIVITY", 14, 527 offsetof(laggr_fields_buf_t, laggr_lacpactivity), print_default_cb}, 528 { "LACPTIMER", 12, 529 offsetof(laggr_fields_buf_t, laggr_lacptimer), print_default_cb}, 530 { "FLAGS", 8, 531 offsetof(laggr_fields_buf_t, laggr_flags), print_default_cb}, 532 { NULL, 0, 0, NULL}} 533 ; 534 535 /* 536 * structures for 'dladm show-aggr -x'. 537 */ 538 typedef enum { 539 AGGR_X_LINK, 540 AGGR_X_PORT, 541 AGGR_X_SPEED, 542 AGGR_X_DUPLEX, 543 AGGR_X_STATE, 544 AGGR_X_ADDRESS, 545 AGGR_X_PORTSTATE 546 } aggr_x_field_index_t; 547 548 static ofmt_field_t aggr_x_fields[] = { 549 /* name, field width, index callback */ 550 { "LINK", 12, AGGR_X_LINK, print_xaggr_cb}, 551 { "PORT", 15, AGGR_X_PORT, print_xaggr_cb}, 552 { "SPEED", 5, AGGR_X_SPEED, print_xaggr_cb}, 553 { "DUPLEX", 10, AGGR_X_DUPLEX, print_xaggr_cb}, 554 { "STATE", 10, AGGR_X_STATE, print_xaggr_cb}, 555 { "ADDRESS", 19, AGGR_X_ADDRESS, print_xaggr_cb}, 556 { "PORTSTATE", 16, AGGR_X_PORTSTATE, print_xaggr_cb}, 557 { NULL, 0, 0, NULL}} 558 ; 559 560 /* 561 * structures for 'dladm show-aggr -s'. 562 */ 563 typedef enum { 564 AGGR_S_LINK, 565 AGGR_S_PORT, 566 AGGR_S_IPKTS, 567 AGGR_S_RBYTES, 568 AGGR_S_OPKTS, 569 AGGR_S_OBYTES, 570 AGGR_S_IPKTDIST, 571 AGGR_S_OPKTDIST 572 } aggr_s_field_index_t; 573 574 static ofmt_field_t aggr_s_fields[] = { 575 { "LINK", 12, AGGR_S_LINK, print_aggr_stats_cb}, 576 { "PORT", 10, AGGR_S_PORT, print_aggr_stats_cb}, 577 { "IPACKETS", 8, AGGR_S_IPKTS, print_aggr_stats_cb}, 578 { "RBYTES", 8, AGGR_S_RBYTES, print_aggr_stats_cb}, 579 { "OPACKETS", 8, AGGR_S_OPKTS, print_aggr_stats_cb}, 580 { "OBYTES", 8, AGGR_S_OBYTES, print_aggr_stats_cb}, 581 { "IPKTDIST", 9, AGGR_S_IPKTDIST, print_aggr_stats_cb}, 582 { "OPKTDIST", 15, AGGR_S_OPKTDIST, print_aggr_stats_cb}, 583 { NULL, 0, 0, NULL}} 584 ; 585 586 /* 587 * structures for 'dladm show-aggr -L'. 588 */ 589 typedef enum { 590 AGGR_L_LINK, 591 AGGR_L_PORT, 592 AGGR_L_AGGREGATABLE, 593 AGGR_L_SYNC, 594 AGGR_L_COLL, 595 AGGR_L_DIST, 596 AGGR_L_DEFAULTED, 597 AGGR_L_EXPIRED 598 } aggr_l_field_index_t; 599 600 static ofmt_field_t aggr_l_fields[] = { 601 /* name, field width, index */ 602 { "LINK", 12, AGGR_L_LINK, print_lacp_cb}, 603 { "PORT", 13, AGGR_L_PORT, print_lacp_cb}, 604 { "AGGREGATABLE", 13, AGGR_L_AGGREGATABLE, print_lacp_cb}, 605 { "SYNC", 5, AGGR_L_SYNC, print_lacp_cb}, 606 { "COLL", 5, AGGR_L_COLL, print_lacp_cb}, 607 { "DIST", 5, AGGR_L_DIST, print_lacp_cb}, 608 { "DEFAULTED", 10, AGGR_L_DEFAULTED, print_lacp_cb}, 609 { "EXPIRED", 15, AGGR_L_EXPIRED, print_lacp_cb}, 610 { NULL, 0, 0, NULL}} 611 ; 612 613 /* 614 * structures for 'dladm show-phys' 615 */ 616 617 static ofmt_field_t phys_fields[] = { 618 /* name, field width, offset */ 619 { "LINK", 13, 620 offsetof(link_fields_buf_t, link_name), print_default_cb}, 621 { "MEDIA", 21, 622 offsetof(link_fields_buf_t, link_phys_media), print_default_cb}, 623 { "STATE", 11, 624 offsetof(link_fields_buf_t, link_phys_state), print_default_cb}, 625 { "SPEED", 7, 626 offsetof(link_fields_buf_t, link_phys_speed), print_default_cb}, 627 { "DUPLEX", 10, 628 offsetof(link_fields_buf_t, link_phys_duplex), print_default_cb}, 629 { "DEVICE", 13, 630 offsetof(link_fields_buf_t, link_phys_device), print_default_cb}, 631 { "FLAGS", 7, 632 offsetof(link_fields_buf_t, link_flags), print_default_cb}, 633 { NULL, 0, NULL, 0}} 634 ; 635 636 /* 637 * structures for 'dladm show-phys -m' 638 */ 639 640 typedef enum { 641 PHYS_M_LINK, 642 PHYS_M_SLOT, 643 PHYS_M_ADDRESS, 644 PHYS_M_INUSE, 645 PHYS_M_CLIENT 646 } phys_m_field_index_t; 647 648 static ofmt_field_t phys_m_fields[] = { 649 /* name, field width, offset */ 650 { "LINK", 13, PHYS_M_LINK, print_phys_one_mac_cb}, 651 { "SLOT", 9, PHYS_M_SLOT, print_phys_one_mac_cb}, 652 { "ADDRESS", 19, PHYS_M_ADDRESS, print_phys_one_mac_cb}, 653 { "INUSE", 5, PHYS_M_INUSE, print_phys_one_mac_cb}, 654 { "CLIENT", 13, PHYS_M_CLIENT, print_phys_one_mac_cb}, 655 { NULL, 0, 0, NULL}} 656 ; 657 658 /* 659 * structures for 'dladm show-phys -H' 660 */ 661 662 typedef enum { 663 PHYS_H_LINK, 664 PHYS_H_GROUP, 665 PHYS_H_GRPTYPE, 666 PHYS_H_RINGS, 667 PHYS_H_CLIENTS 668 } phys_h_field_index_t; 669 670 static ofmt_field_t phys_h_fields[] = { 671 { "LINK", 13, PHYS_H_LINK, print_phys_one_hwgrp_cb}, 672 { "GROUP", 9, PHYS_H_GROUP, print_phys_one_hwgrp_cb}, 673 { "GROUPTYPE", 7, PHYS_H_GRPTYPE, print_phys_one_hwgrp_cb}, 674 { "RINGS", 17, PHYS_H_RINGS, print_phys_one_hwgrp_cb}, 675 { "CLIENTS", 21, PHYS_H_CLIENTS, print_phys_one_hwgrp_cb}, 676 { NULL, 0, 0, NULL}} 677 ; 678 679 /* 680 * structures for 'dladm show-vlan' 681 */ 682 static ofmt_field_t vlan_fields[] = { 683 { "LINK", 16, 684 offsetof(link_fields_buf_t, link_name), print_default_cb}, 685 { "VID", 9, 686 offsetof(link_fields_buf_t, link_vlan_vid), print_default_cb}, 687 { "OVER", 13, 688 offsetof(link_fields_buf_t, link_over), print_default_cb}, 689 { "FLAGS", 7, 690 offsetof(link_fields_buf_t, link_flags), print_default_cb}, 691 { NULL, 0, 0, NULL}} 692 ; 693 694 /* 695 * structures common to 'dladm scan-wifi' and 'dladm show-wifi' 696 * callback will be determined in parse_wifi_fields. 697 */ 698 static ofmt_field_t wifi_common_fields[] = { 699 { "LINK", 11, 0, NULL}, 700 { "ESSID", 20, DLADM_WLAN_ATTR_ESSID, NULL}, 701 { "BSSID", 18, DLADM_WLAN_ATTR_BSSID, NULL}, 702 { "IBSSID", 18, DLADM_WLAN_ATTR_BSSID, NULL}, 703 { "MODE", 7, DLADM_WLAN_ATTR_MODE, NULL}, 704 { "SPEED", 7, DLADM_WLAN_ATTR_SPEED, NULL}, 705 { "BSSTYPE", 9, DLADM_WLAN_ATTR_BSSTYPE, NULL}, 706 { "SEC", 7, DLADM_WLAN_ATTR_SECMODE, NULL}, 707 { "STRENGTH", 11, DLADM_WLAN_ATTR_STRENGTH, NULL}, 708 { NULL, 0, 0, NULL}}; 709 710 /* 711 * the 'show-wifi' command supports all the fields in wifi_common_fields 712 * plus the AUTH and STATUS fields. 713 */ 714 static ofmt_field_t wifi_show_fields[A_CNT(wifi_common_fields) + 2] = { 715 { "AUTH", 9, DLADM_WLAN_ATTR_AUTH, NULL}, 716 { "STATUS", 18, DLADM_WLAN_LINKATTR_STATUS, print_wifi_status_cb}, 717 /* copy wifi_common_fields here */ 718 }; 719 720 static char *all_scan_wifi_fields = 721 "link,essid,bssid,sec,strength,mode,speed,bsstype"; 722 static char *all_show_wifi_fields = 723 "link,status,essid,sec,strength,mode,speed,auth,bssid,bsstype"; 724 static char *def_scan_wifi_fields = 725 "link,essid,bssid,sec,strength,mode,speed"; 726 static char *def_show_wifi_fields = 727 "link,status,essid,sec,strength,mode,speed"; 728 729 /* 730 * structures for 'dladm show-linkprop' 731 */ 732 typedef enum { 733 LINKPROP_LINK, 734 LINKPROP_PROPERTY, 735 LINKPROP_PERM, 736 LINKPROP_VALUE, 737 LINKPROP_DEFAULT, 738 LINKPROP_POSSIBLE 739 } linkprop_field_index_t; 740 741 static ofmt_field_t linkprop_fields[] = { 742 /* name, field width, index */ 743 { "LINK", 13, LINKPROP_LINK, print_linkprop_cb}, 744 { "PROPERTY", 16, LINKPROP_PROPERTY, print_linkprop_cb}, 745 { "PERM", 5, LINKPROP_PERM, print_linkprop_cb}, 746 { "VALUE", 15, LINKPROP_VALUE, print_linkprop_cb}, 747 { "DEFAULT", 15, LINKPROP_DEFAULT, print_linkprop_cb}, 748 { "POSSIBLE", 21, LINKPROP_POSSIBLE, print_linkprop_cb}, 749 { NULL, 0, 0, NULL}} 750 ; 751 752 #define MAX_PROP_LINE 512 753 754 typedef struct show_linkprop_state { 755 char ls_link[MAXLINKNAMELEN]; 756 char *ls_line; 757 char **ls_propvals; 758 dladm_arg_list_t *ls_proplist; 759 boolean_t ls_parsable; 760 boolean_t ls_persist; 761 boolean_t ls_header; 762 dladm_status_t ls_status; 763 dladm_status_t ls_retstatus; 764 ofmt_handle_t ls_ofmt; 765 } show_linkprop_state_t; 766 767 typedef struct set_linkprop_state { 768 const char *ls_name; 769 boolean_t ls_reset; 770 boolean_t ls_temp; 771 dladm_status_t ls_status; 772 } set_linkprop_state_t; 773 774 typedef struct linkprop_args_s { 775 show_linkprop_state_t *ls_state; 776 char *ls_propname; 777 datalink_id_t ls_linkid; 778 } linkprop_args_t; 779 780 /* 781 * structures for 'dladm show-secobj' 782 */ 783 typedef struct secobj_fields_buf_s { 784 char ss_obj_name[DLADM_SECOBJ_VAL_MAX]; 785 char ss_class[20]; 786 char ss_val[30]; 787 } secobj_fields_buf_t; 788 789 static ofmt_field_t secobj_fields[] = { 790 { "OBJECT", 21, 791 offsetof(secobj_fields_buf_t, ss_obj_name), print_default_cb}, 792 { "CLASS", 21, 793 offsetof(secobj_fields_buf_t, ss_class), print_default_cb}, 794 { "VALUE", 31, 795 offsetof(secobj_fields_buf_t, ss_val), print_default_cb}, 796 { NULL, 0, 0, NULL}} 797 ; 798 799 /* 800 * structures for 'dladm show-vnic' 801 */ 802 typedef struct vnic_fields_buf_s 803 { 804 char vnic_link[DLPI_LINKNAME_MAX]; 805 char vnic_over[DLPI_LINKNAME_MAX]; 806 char vnic_speed[6]; 807 char vnic_macaddr[19]; 808 char vnic_macaddrtype[19]; 809 char vnic_vid[6]; 810 } vnic_fields_buf_t; 811 812 static ofmt_field_t vnic_fields[] = { 813 { "LINK", 13, 814 offsetof(vnic_fields_buf_t, vnic_link), print_default_cb}, 815 { "OVER", 13, 816 offsetof(vnic_fields_buf_t, vnic_over), print_default_cb}, 817 { "SPEED", 7, 818 offsetof(vnic_fields_buf_t, vnic_speed), print_default_cb}, 819 { "MACADDRESS", 21, 820 offsetof(vnic_fields_buf_t, vnic_macaddr), print_default_cb}, 821 { "MACADDRTYPE", 20, 822 offsetof(vnic_fields_buf_t, vnic_macaddrtype), print_default_cb}, 823 { "VID", 7, 824 offsetof(vnic_fields_buf_t, vnic_vid), print_default_cb}, 825 { NULL, 0, 0, NULL}} 826 ; 827 828 /* 829 * structures for 'dladm show-usage' 830 */ 831 832 typedef struct usage_fields_buf_s { 833 char usage_link[12]; 834 char usage_duration[10]; 835 char usage_ipackets[9]; 836 char usage_rbytes[10]; 837 char usage_opackets[9]; 838 char usage_obytes[10]; 839 char usage_bandwidth[14]; 840 } usage_fields_buf_t; 841 842 static ofmt_field_t usage_fields[] = { 843 { "LINK", 13, 844 offsetof(usage_fields_buf_t, usage_link), print_default_cb}, 845 { "DURATION", 11, 846 offsetof(usage_fields_buf_t, usage_duration), print_default_cb}, 847 { "IPACKETS", 10, 848 offsetof(usage_fields_buf_t, usage_ipackets), print_default_cb}, 849 { "RBYTES", 11, 850 offsetof(usage_fields_buf_t, usage_rbytes), print_default_cb}, 851 { "OPACKETS", 10, 852 offsetof(usage_fields_buf_t, usage_opackets), print_default_cb}, 853 { "OBYTES", 11, 854 offsetof(usage_fields_buf_t, usage_obytes), print_default_cb}, 855 { "BANDWIDTH", 15, 856 offsetof(usage_fields_buf_t, usage_bandwidth), print_default_cb}, 857 { NULL, 0, 0, NULL}} 858 ; 859 860 861 /* 862 * structures for 'dladm show-usage link' 863 */ 864 865 typedef struct usage_l_fields_buf_s { 866 char usage_l_link[12]; 867 char usage_l_stime[13]; 868 char usage_l_etime[13]; 869 char usage_l_rbytes[8]; 870 char usage_l_obytes[8]; 871 char usage_l_bandwidth[14]; 872 } usage_l_fields_buf_t; 873 874 static ofmt_field_t usage_l_fields[] = { 875 /* name, field width, offset */ 876 { "LINK", 13, 877 offsetof(usage_l_fields_buf_t, usage_l_link), print_default_cb}, 878 { "START", 14, 879 offsetof(usage_l_fields_buf_t, usage_l_stime), print_default_cb}, 880 { "END", 14, 881 offsetof(usage_l_fields_buf_t, usage_l_etime), print_default_cb}, 882 { "RBYTES", 9, 883 offsetof(usage_l_fields_buf_t, usage_l_rbytes), print_default_cb}, 884 { "OBYTES", 9, 885 offsetof(usage_l_fields_buf_t, usage_l_obytes), print_default_cb}, 886 { "BANDWIDTH", 15, 887 offsetof(usage_l_fields_buf_t, usage_l_bandwidth), print_default_cb}, 888 { NULL, 0, 0, NULL}} 889 ; 890 891 static char *progname; 892 static sig_atomic_t signalled; 893 894 /* 895 * Handle to libdladm. Opened in main() before the sub-command 896 * specific function is called. 897 */ 898 static dladm_handle_t handle = NULL; 899 900 #define DLADM_ETHERSTUB_NAME "etherstub" 901 #define DLADM_IS_ETHERSTUB(id) (id == DATALINK_INVALID_LINKID) 902 903 static void 904 usage(void) 905 { 906 int i; 907 cmd_t *cmdp; 908 (void) fprintf(stderr, gettext("usage: dladm <subcommand> <args> ..." 909 "\n")); 910 for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) { 911 cmdp = &cmds[i]; 912 if (cmdp->c_usage != NULL) 913 (void) fprintf(stderr, "%s\n", gettext(cmdp->c_usage)); 914 } 915 916 /* close dladm handle if it was opened */ 917 if (handle != NULL) 918 dladm_close(handle); 919 920 exit(1); 921 } 922 923 int 924 main(int argc, char *argv[]) 925 { 926 int i; 927 cmd_t *cmdp; 928 dladm_status_t status; 929 930 (void) setlocale(LC_ALL, ""); 931 #if !defined(TEXT_DOMAIN) 932 #define TEXT_DOMAIN "SYS_TEST" 933 #endif 934 (void) textdomain(TEXT_DOMAIN); 935 936 progname = argv[0]; 937 938 if (argc < 2) 939 usage(); 940 941 for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) { 942 cmdp = &cmds[i]; 943 if (strcmp(argv[1], cmdp->c_name) == 0) { 944 /* Open the libdladm handle */ 945 if ((status = dladm_open(&handle)) != DLADM_STATUS_OK) { 946 die_dlerr(status, 947 "could not open /dev/dld"); 948 } 949 950 cmdp->c_fn(argc - 1, &argv[1], cmdp->c_usage); 951 952 dladm_close(handle); 953 exit(0); 954 } 955 } 956 957 (void) fprintf(stderr, gettext("%s: unknown subcommand '%s'\n"), 958 progname, argv[1]); 959 usage(); 960 961 return (0); 962 } 963 964 /*ARGSUSED*/ 965 static int 966 show_usage_date(dladm_usage_t *usage, void *arg) 967 { 968 show_usage_state_t *state = (show_usage_state_t *)arg; 969 time_t stime; 970 char timebuf[20]; 971 dladm_status_t status; 972 uint32_t flags; 973 974 /* 975 * Only show usage information for existing links unless '-a' 976 * is specified. 977 */ 978 if (!state->us_showall) { 979 if ((status = dladm_name2info(handle, usage->du_name, 980 NULL, &flags, NULL, NULL)) != DLADM_STATUS_OK) { 981 return (status); 982 } 983 if ((flags & DLADM_OPT_ACTIVE) == 0) 984 return (DLADM_STATUS_LINKINVAL); 985 } 986 987 stime = usage->du_stime; 988 (void) strftime(timebuf, sizeof (timebuf), "%m/%d/%Y", 989 localtime(&stime)); 990 (void) printf("%s\n", timebuf); 991 992 return (DLADM_STATUS_OK); 993 } 994 995 static int 996 show_usage_time(dladm_usage_t *usage, void *arg) 997 { 998 show_usage_state_t *state = (show_usage_state_t *)arg; 999 char buf[DLADM_STRSIZE]; 1000 usage_l_fields_buf_t ubuf; 1001 time_t time; 1002 double bw; 1003 dladm_status_t status; 1004 uint32_t flags; 1005 1006 /* 1007 * Only show usage information for existing links unless '-a' 1008 * is specified. 1009 */ 1010 if (!state->us_showall) { 1011 if ((status = dladm_name2info(handle, usage->du_name, 1012 NULL, &flags, NULL, NULL)) != DLADM_STATUS_OK) { 1013 return (status); 1014 } 1015 if ((flags & DLADM_OPT_ACTIVE) == 0) 1016 return (DLADM_STATUS_LINKINVAL); 1017 } 1018 1019 if (state->us_plot) { 1020 if (!state->us_printheader) { 1021 if (state->us_first) { 1022 (void) printf("# Time"); 1023 state->us_first = B_FALSE; 1024 } 1025 (void) printf(" %s", usage->du_name); 1026 if (usage->du_last) { 1027 (void) printf("\n"); 1028 state->us_first = B_TRUE; 1029 state->us_printheader = B_TRUE; 1030 } 1031 } else { 1032 if (state->us_first) { 1033 time = usage->du_etime; 1034 (void) strftime(buf, sizeof (buf), "%T", 1035 localtime(&time)); 1036 state->us_first = B_FALSE; 1037 (void) printf("%s", buf); 1038 } 1039 bw = (double)usage->du_bandwidth/1000; 1040 (void) printf(" %.2f", bw); 1041 if (usage->du_last) { 1042 (void) printf("\n"); 1043 state->us_first = B_TRUE; 1044 } 1045 } 1046 return (DLADM_STATUS_OK); 1047 } 1048 1049 bzero(&ubuf, sizeof (ubuf)); 1050 1051 (void) snprintf(ubuf.usage_l_link, sizeof (ubuf.usage_l_link), "%s", 1052 usage->du_name); 1053 time = usage->du_stime; 1054 (void) strftime(buf, sizeof (buf), "%T", localtime(&time)); 1055 (void) snprintf(ubuf.usage_l_stime, sizeof (ubuf.usage_l_stime), "%s", 1056 buf); 1057 time = usage->du_etime; 1058 (void) strftime(buf, sizeof (buf), "%T", localtime(&time)); 1059 (void) snprintf(ubuf.usage_l_etime, sizeof (ubuf.usage_l_etime), "%s", 1060 buf); 1061 (void) snprintf(ubuf.usage_l_rbytes, sizeof (ubuf.usage_l_rbytes), 1062 "%llu", usage->du_rbytes); 1063 (void) snprintf(ubuf.usage_l_obytes, sizeof (ubuf.usage_l_obytes), 1064 "%llu", usage->du_obytes); 1065 (void) snprintf(ubuf.usage_l_bandwidth, sizeof (ubuf.usage_l_bandwidth), 1066 "%s Mbps", dladm_bw2str(usage->du_bandwidth, buf)); 1067 1068 ofmt_print(state->us_ofmt, &ubuf); 1069 return (DLADM_STATUS_OK); 1070 } 1071 1072 static int 1073 show_usage_res(dladm_usage_t *usage, void *arg) 1074 { 1075 show_usage_state_t *state = (show_usage_state_t *)arg; 1076 char buf[DLADM_STRSIZE]; 1077 usage_fields_buf_t ubuf; 1078 dladm_status_t status; 1079 uint32_t flags; 1080 1081 /* 1082 * Only show usage information for existing links unless '-a' 1083 * is specified. 1084 */ 1085 if (!state->us_showall) { 1086 if ((status = dladm_name2info(handle, usage->du_name, 1087 NULL, &flags, NULL, NULL)) != DLADM_STATUS_OK) { 1088 return (status); 1089 } 1090 if ((flags & DLADM_OPT_ACTIVE) == 0) 1091 return (DLADM_STATUS_LINKINVAL); 1092 } 1093 1094 bzero(&ubuf, sizeof (ubuf)); 1095 1096 (void) snprintf(ubuf.usage_link, sizeof (ubuf.usage_link), "%s", 1097 usage->du_name); 1098 (void) snprintf(ubuf.usage_duration, sizeof (ubuf.usage_duration), 1099 "%llu", usage->du_duration); 1100 (void) snprintf(ubuf.usage_ipackets, sizeof (ubuf.usage_ipackets), 1101 "%llu", usage->du_ipackets); 1102 (void) snprintf(ubuf.usage_rbytes, sizeof (ubuf.usage_rbytes), 1103 "%llu", usage->du_rbytes); 1104 (void) snprintf(ubuf.usage_opackets, sizeof (ubuf.usage_opackets), 1105 "%llu", usage->du_opackets); 1106 (void) snprintf(ubuf.usage_obytes, sizeof (ubuf.usage_obytes), 1107 "%llu", usage->du_obytes); 1108 (void) snprintf(ubuf.usage_bandwidth, sizeof (ubuf.usage_bandwidth), 1109 "%s Mbps", dladm_bw2str(usage->du_bandwidth, buf)); 1110 1111 ofmt_print(state->us_ofmt, &ubuf); 1112 1113 return (DLADM_STATUS_OK); 1114 } 1115 1116 static boolean_t 1117 valid_formatspec(char *formatspec_str) 1118 { 1119 if (strcmp(formatspec_str, "gnuplot") == 0) 1120 return (B_TRUE); 1121 return (B_FALSE); 1122 1123 } 1124 1125 /*ARGSUSED*/ 1126 static void 1127 do_show_usage(int argc, char *argv[], const char *use) 1128 { 1129 char *file = NULL; 1130 int opt; 1131 dladm_status_t status; 1132 boolean_t d_arg = B_FALSE; 1133 char *stime = NULL; 1134 char *etime = NULL; 1135 char *resource = NULL; 1136 show_usage_state_t state; 1137 boolean_t o_arg = B_FALSE; 1138 boolean_t F_arg = B_FALSE; 1139 char *fields_str = NULL; 1140 char *formatspec_str = NULL; 1141 char *all_l_fields = 1142 "link,start,end,rbytes,obytes,bandwidth"; 1143 ofmt_handle_t ofmt; 1144 ofmt_status_t oferr; 1145 uint_t ofmtflags = 0; 1146 1147 bzero(&state, sizeof (show_usage_state_t)); 1148 state.us_parsable = B_FALSE; 1149 state.us_printheader = B_FALSE; 1150 state.us_plot = B_FALSE; 1151 state.us_first = B_TRUE; 1152 1153 while ((opt = getopt_long(argc, argv, "das:e:o:f:F:", 1154 usage_opts, NULL)) != -1) { 1155 switch (opt) { 1156 case 'd': 1157 d_arg = B_TRUE; 1158 break; 1159 case 'a': 1160 state.us_showall = B_TRUE; 1161 break; 1162 case 'f': 1163 file = optarg; 1164 break; 1165 case 's': 1166 stime = optarg; 1167 break; 1168 case 'e': 1169 etime = optarg; 1170 break; 1171 case 'o': 1172 o_arg = B_TRUE; 1173 fields_str = optarg; 1174 break; 1175 case 'F': 1176 state.us_plot = F_arg = B_TRUE; 1177 formatspec_str = optarg; 1178 break; 1179 default: 1180 die_opterr(optopt, opt, use); 1181 break; 1182 } 1183 } 1184 1185 if (file == NULL) 1186 die("show-usage requires a file"); 1187 1188 if (optind == (argc-1)) { 1189 uint32_t flags; 1190 1191 resource = argv[optind]; 1192 if (!state.us_showall && 1193 (((status = dladm_name2info(handle, resource, NULL, &flags, 1194 NULL, NULL)) != DLADM_STATUS_OK) || 1195 ((flags & DLADM_OPT_ACTIVE) == 0))) { 1196 die("invalid link: '%s'", resource); 1197 } 1198 } 1199 1200 if (F_arg && d_arg) 1201 die("incompatible -d and -F options"); 1202 1203 if (F_arg && valid_formatspec(formatspec_str) == B_FALSE) 1204 die("Format specifier %s not supported", formatspec_str); 1205 1206 if (state.us_parsable) 1207 ofmtflags |= OFMT_PARSABLE; 1208 1209 if (resource == NULL && stime == NULL && etime == NULL) { 1210 oferr = ofmt_open(fields_str, usage_fields, ofmtflags, 0, 1211 &ofmt); 1212 } else { 1213 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) 1214 fields_str = all_l_fields; 1215 oferr = ofmt_open(fields_str, usage_l_fields, ofmtflags, 0, 1216 &ofmt); 1217 1218 } 1219 dladm_ofmt_check(oferr, state.us_parsable, ofmt); 1220 state.us_ofmt = ofmt; 1221 1222 if (d_arg) { 1223 /* Print log dates */ 1224 status = dladm_usage_dates(show_usage_date, 1225 DLADM_LOGTYPE_LINK, file, resource, &state); 1226 } else if (resource == NULL && stime == NULL && etime == NULL && 1227 !F_arg) { 1228 /* Print summary */ 1229 status = dladm_usage_summary(show_usage_res, 1230 DLADM_LOGTYPE_LINK, file, &state); 1231 } else if (resource != NULL) { 1232 /* Print log entries for named resource */ 1233 status = dladm_walk_usage_res(show_usage_time, 1234 DLADM_LOGTYPE_LINK, file, resource, stime, etime, &state); 1235 } else { 1236 /* Print time and information for each link */ 1237 status = dladm_walk_usage_time(show_usage_time, 1238 DLADM_LOGTYPE_LINK, file, stime, etime, &state); 1239 } 1240 1241 if (status != DLADM_STATUS_OK) 1242 die_dlerr(status, "show-usage"); 1243 ofmt_close(ofmt); 1244 } 1245 1246 static void 1247 do_create_aggr(int argc, char *argv[], const char *use) 1248 { 1249 char option; 1250 int key = 0; 1251 uint32_t policy = AGGR_POLICY_L4; 1252 aggr_lacp_mode_t lacp_mode = AGGR_LACP_OFF; 1253 aggr_lacp_timer_t lacp_timer = AGGR_LACP_TIMER_SHORT; 1254 dladm_aggr_port_attr_db_t port[MAXPORT]; 1255 uint_t n, ndev, nlink; 1256 uint8_t mac_addr[ETHERADDRL]; 1257 boolean_t mac_addr_fixed = B_FALSE; 1258 boolean_t P_arg = B_FALSE; 1259 boolean_t l_arg = B_FALSE; 1260 boolean_t u_arg = B_FALSE; 1261 boolean_t T_arg = B_FALSE; 1262 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 1263 char *altroot = NULL; 1264 char name[MAXLINKNAMELEN]; 1265 char *devs[MAXPORT]; 1266 char *links[MAXPORT]; 1267 dladm_status_t status; 1268 dladm_status_t pstatus; 1269 char propstr[DLADM_STRSIZE]; 1270 dladm_arg_list_t *proplist = NULL; 1271 int i; 1272 datalink_id_t linkid; 1273 1274 ndev = nlink = opterr = 0; 1275 bzero(propstr, DLADM_STRSIZE); 1276 1277 while ((option = getopt_long(argc, argv, ":d:l:L:P:R:tfu:T:p:", 1278 lopts, NULL)) != -1) { 1279 switch (option) { 1280 case 'd': 1281 if (ndev + nlink >= MAXPORT) 1282 die("too many ports specified"); 1283 1284 devs[ndev++] = optarg; 1285 break; 1286 case 'P': 1287 if (P_arg) 1288 die_optdup(option); 1289 1290 P_arg = B_TRUE; 1291 if (!dladm_aggr_str2policy(optarg, &policy)) 1292 die("invalid policy '%s'", optarg); 1293 break; 1294 case 'u': 1295 if (u_arg) 1296 die_optdup(option); 1297 1298 u_arg = B_TRUE; 1299 if (!dladm_aggr_str2macaddr(optarg, &mac_addr_fixed, 1300 mac_addr)) 1301 die("invalid MAC address '%s'", optarg); 1302 break; 1303 case 'l': 1304 if (isdigit(optarg[strlen(optarg) - 1])) { 1305 1306 /* 1307 * Ended with digit, possibly a link name. 1308 */ 1309 if (ndev + nlink >= MAXPORT) 1310 die("too many ports specified"); 1311 1312 links[nlink++] = optarg; 1313 break; 1314 } 1315 /* FALLTHROUGH */ 1316 case 'L': 1317 if (l_arg) 1318 die_optdup(option); 1319 1320 l_arg = B_TRUE; 1321 if (!dladm_aggr_str2lacpmode(optarg, &lacp_mode)) 1322 die("invalid LACP mode '%s'", optarg); 1323 break; 1324 case 'T': 1325 if (T_arg) 1326 die_optdup(option); 1327 1328 T_arg = B_TRUE; 1329 if (!dladm_aggr_str2lacptimer(optarg, &lacp_timer)) 1330 die("invalid LACP timer value '%s'", optarg); 1331 break; 1332 case 't': 1333 flags &= ~DLADM_OPT_PERSIST; 1334 break; 1335 case 'f': 1336 flags |= DLADM_OPT_FORCE; 1337 break; 1338 case 'R': 1339 altroot = optarg; 1340 break; 1341 case 'p': 1342 (void) strlcat(propstr, optarg, DLADM_STRSIZE); 1343 if (strlcat(propstr, ",", DLADM_STRSIZE) >= 1344 DLADM_STRSIZE) 1345 die("property list too long '%s'", propstr); 1346 break; 1347 1348 default: 1349 die_opterr(optopt, option, use); 1350 break; 1351 } 1352 } 1353 1354 if (ndev + nlink == 0) 1355 usage(); 1356 1357 /* get key value or the aggregation name (required last argument) */ 1358 if (optind != (argc-1)) 1359 usage(); 1360 1361 if (!str2int(argv[optind], &key)) { 1362 if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= 1363 MAXLINKNAMELEN) { 1364 die("link name too long '%s'", argv[optind]); 1365 } 1366 1367 if (!dladm_valid_linkname(name)) 1368 die("invalid link name '%s'", argv[optind]); 1369 } else { 1370 (void) snprintf(name, MAXLINKNAMELEN, "aggr%d", key); 1371 } 1372 1373 if (altroot != NULL) 1374 altroot_cmd(altroot, argc, argv); 1375 1376 for (n = 0; n < ndev; n++) { 1377 if ((status = dladm_dev2linkid(handle, devs[n], 1378 &port[n].lp_linkid)) != DLADM_STATUS_OK) { 1379 die_dlerr(status, "invalid dev name '%s'", devs[n]); 1380 } 1381 } 1382 1383 for (n = 0; n < nlink; n++) { 1384 if ((status = dladm_name2info(handle, links[n], 1385 &port[ndev + n].lp_linkid, NULL, NULL, NULL)) != 1386 DLADM_STATUS_OK) { 1387 die_dlerr(status, "invalid link name '%s'", links[n]); 1388 } 1389 } 1390 1391 status = dladm_aggr_create(handle, name, key, ndev + nlink, port, 1392 policy, mac_addr_fixed, (const uchar_t *)mac_addr, lacp_mode, 1393 lacp_timer, flags); 1394 if (status != DLADM_STATUS_OK) 1395 goto done; 1396 1397 if (dladm_parse_link_props(propstr, &proplist, B_FALSE) 1398 != DLADM_STATUS_OK) 1399 die("invalid aggregation property"); 1400 1401 if (proplist == NULL) 1402 return; 1403 1404 status = dladm_name2info(handle, name, &linkid, NULL, NULL, NULL); 1405 if (status != DLADM_STATUS_OK) 1406 goto done; 1407 1408 for (i = 0; i < proplist->al_count; i++) { 1409 dladm_arg_info_t *aip = &proplist->al_info[i]; 1410 1411 pstatus = dladm_set_linkprop(handle, linkid, aip->ai_name, 1412 aip->ai_val, aip->ai_count, flags); 1413 1414 if (pstatus != DLADM_STATUS_OK) { 1415 die_dlerr(pstatus, 1416 "aggr creation succeeded but " 1417 "could not set property '%s'", aip->ai_name); 1418 } 1419 } 1420 done: 1421 dladm_free_props(proplist); 1422 if (status != DLADM_STATUS_OK) { 1423 if (status == DLADM_STATUS_NONOTIF) { 1424 die_dlerr(status, "not all links have link up/down " 1425 "detection; must use -f (see dladm(1M))\n"); 1426 } else { 1427 die_dlerr(status, "create operation failed"); 1428 } 1429 } 1430 } 1431 1432 /* 1433 * arg is either the key or the aggr name. Validate it and convert it to 1434 * the linkid if altroot is NULL. 1435 */ 1436 static dladm_status_t 1437 i_dladm_aggr_get_linkid(const char *altroot, const char *arg, 1438 datalink_id_t *linkidp, uint32_t flags) 1439 { 1440 int key = 0; 1441 char *aggr = NULL; 1442 dladm_status_t status; 1443 1444 if (!str2int(arg, &key)) 1445 aggr = (char *)arg; 1446 1447 if (aggr == NULL && key == 0) 1448 return (DLADM_STATUS_LINKINVAL); 1449 1450 if (altroot != NULL) 1451 return (DLADM_STATUS_OK); 1452 1453 if (aggr != NULL) { 1454 status = dladm_name2info(handle, aggr, linkidp, NULL, NULL, 1455 NULL); 1456 } else { 1457 status = dladm_key2linkid(handle, key, linkidp, flags); 1458 } 1459 1460 return (status); 1461 } 1462 1463 static void 1464 do_delete_aggr(int argc, char *argv[], const char *use) 1465 { 1466 char option; 1467 char *altroot = NULL; 1468 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 1469 dladm_status_t status; 1470 datalink_id_t linkid; 1471 1472 opterr = 0; 1473 while ((option = getopt_long(argc, argv, ":R:t", lopts, NULL)) != -1) { 1474 switch (option) { 1475 case 't': 1476 flags &= ~DLADM_OPT_PERSIST; 1477 break; 1478 case 'R': 1479 altroot = optarg; 1480 break; 1481 default: 1482 die_opterr(optopt, option, use); 1483 break; 1484 } 1485 } 1486 1487 /* get key value or the aggregation name (required last argument) */ 1488 if (optind != (argc-1)) 1489 usage(); 1490 1491 status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags); 1492 if (status != DLADM_STATUS_OK) 1493 goto done; 1494 1495 if (altroot != NULL) 1496 altroot_cmd(altroot, argc, argv); 1497 1498 status = dladm_aggr_delete(handle, linkid, flags); 1499 done: 1500 if (status != DLADM_STATUS_OK) 1501 die_dlerr(status, "delete operation failed"); 1502 } 1503 1504 static void 1505 do_add_aggr(int argc, char *argv[], const char *use) 1506 { 1507 char option; 1508 uint_t n, ndev, nlink; 1509 char *altroot = NULL; 1510 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 1511 datalink_id_t linkid; 1512 dladm_status_t status; 1513 dladm_aggr_port_attr_db_t port[MAXPORT]; 1514 char *devs[MAXPORT]; 1515 char *links[MAXPORT]; 1516 1517 ndev = nlink = opterr = 0; 1518 while ((option = getopt_long(argc, argv, ":d:l:R:tf", lopts, 1519 NULL)) != -1) { 1520 switch (option) { 1521 case 'd': 1522 if (ndev + nlink >= MAXPORT) 1523 die("too many ports specified"); 1524 1525 devs[ndev++] = optarg; 1526 break; 1527 case 'l': 1528 if (ndev + nlink >= MAXPORT) 1529 die("too many ports specified"); 1530 1531 links[nlink++] = optarg; 1532 break; 1533 case 't': 1534 flags &= ~DLADM_OPT_PERSIST; 1535 break; 1536 case 'f': 1537 flags |= DLADM_OPT_FORCE; 1538 break; 1539 case 'R': 1540 altroot = optarg; 1541 break; 1542 default: 1543 die_opterr(optopt, option, use); 1544 break; 1545 } 1546 } 1547 1548 if (ndev + nlink == 0) 1549 usage(); 1550 1551 /* get key value or the aggregation name (required last argument) */ 1552 if (optind != (argc-1)) 1553 usage(); 1554 1555 if ((status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, 1556 flags & (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST))) != 1557 DLADM_STATUS_OK) { 1558 goto done; 1559 } 1560 1561 if (altroot != NULL) 1562 altroot_cmd(altroot, argc, argv); 1563 1564 for (n = 0; n < ndev; n++) { 1565 if ((status = dladm_dev2linkid(handle, devs[n], 1566 &(port[n].lp_linkid))) != DLADM_STATUS_OK) { 1567 die_dlerr(status, "invalid <dev> '%s'", devs[n]); 1568 } 1569 } 1570 1571 for (n = 0; n < nlink; n++) { 1572 if ((status = dladm_name2info(handle, links[n], 1573 &port[n + ndev].lp_linkid, NULL, NULL, NULL)) != 1574 DLADM_STATUS_OK) { 1575 die_dlerr(status, "invalid <link> '%s'", links[n]); 1576 } 1577 } 1578 1579 status = dladm_aggr_add(handle, linkid, ndev + nlink, port, flags); 1580 done: 1581 if (status != DLADM_STATUS_OK) { 1582 /* 1583 * checking DLADM_STATUS_NOTSUP is a temporary workaround 1584 * and should be removed once 6399681 is fixed. 1585 */ 1586 if (status == DLADM_STATUS_NOTSUP) { 1587 (void) fprintf(stderr, 1588 gettext("%s: add operation failed: %s\n"), 1589 progname, 1590 gettext("link capabilities don't match")); 1591 dladm_close(handle); 1592 exit(ENOTSUP); 1593 } else if (status == DLADM_STATUS_NONOTIF) { 1594 die_dlerr(status, "not all links have link up/down " 1595 "detection; must use -f (see dladm(1M))\n"); 1596 } else { 1597 die_dlerr(status, "add operation failed"); 1598 } 1599 } 1600 } 1601 1602 static void 1603 do_remove_aggr(int argc, char *argv[], const char *use) 1604 { 1605 char option; 1606 dladm_aggr_port_attr_db_t port[MAXPORT]; 1607 uint_t n, ndev, nlink; 1608 char *devs[MAXPORT]; 1609 char *links[MAXPORT]; 1610 char *altroot = NULL; 1611 uint32_t flags; 1612 datalink_id_t linkid; 1613 dladm_status_t status; 1614 1615 flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 1616 ndev = nlink = opterr = 0; 1617 while ((option = getopt_long(argc, argv, ":d:l:R:t", 1618 lopts, NULL)) != -1) { 1619 switch (option) { 1620 case 'd': 1621 if (ndev + nlink >= MAXPORT) 1622 die("too many ports specified"); 1623 1624 devs[ndev++] = optarg; 1625 break; 1626 case 'l': 1627 if (ndev + nlink >= MAXPORT) 1628 die("too many ports specified"); 1629 1630 links[nlink++] = optarg; 1631 break; 1632 case 't': 1633 flags &= ~DLADM_OPT_PERSIST; 1634 break; 1635 case 'R': 1636 altroot = optarg; 1637 break; 1638 default: 1639 die_opterr(optopt, option, use); 1640 break; 1641 } 1642 } 1643 1644 if (ndev + nlink == 0) 1645 usage(); 1646 1647 /* get key value or the aggregation name (required last argument) */ 1648 if (optind != (argc-1)) 1649 usage(); 1650 1651 status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags); 1652 if (status != DLADM_STATUS_OK) 1653 goto done; 1654 1655 if (altroot != NULL) 1656 altroot_cmd(altroot, argc, argv); 1657 1658 for (n = 0; n < ndev; n++) { 1659 if ((status = dladm_dev2linkid(handle, devs[n], 1660 &(port[n].lp_linkid))) != DLADM_STATUS_OK) { 1661 die_dlerr(status, "invalid <dev> '%s'", devs[n]); 1662 } 1663 } 1664 1665 for (n = 0; n < nlink; n++) { 1666 if ((status = dladm_name2info(handle, links[n], 1667 &port[n + ndev].lp_linkid, NULL, NULL, NULL)) != 1668 DLADM_STATUS_OK) { 1669 die_dlerr(status, "invalid <link> '%s'", links[n]); 1670 } 1671 } 1672 1673 status = dladm_aggr_remove(handle, linkid, ndev + nlink, port, flags); 1674 done: 1675 if (status != DLADM_STATUS_OK) 1676 die_dlerr(status, "remove operation failed"); 1677 } 1678 1679 static void 1680 do_modify_aggr(int argc, char *argv[], const char *use) 1681 { 1682 char option; 1683 uint32_t policy = AGGR_POLICY_L4; 1684 aggr_lacp_mode_t lacp_mode = AGGR_LACP_OFF; 1685 aggr_lacp_timer_t lacp_timer = AGGR_LACP_TIMER_SHORT; 1686 uint8_t mac_addr[ETHERADDRL]; 1687 boolean_t mac_addr_fixed = B_FALSE; 1688 uint8_t modify_mask = 0; 1689 char *altroot = NULL; 1690 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 1691 datalink_id_t linkid; 1692 dladm_status_t status; 1693 1694 opterr = 0; 1695 while ((option = getopt_long(argc, argv, ":L:l:P:R:tu:T:", lopts, 1696 NULL)) != -1) { 1697 switch (option) { 1698 case 'P': 1699 if (modify_mask & DLADM_AGGR_MODIFY_POLICY) 1700 die_optdup(option); 1701 1702 modify_mask |= DLADM_AGGR_MODIFY_POLICY; 1703 1704 if (!dladm_aggr_str2policy(optarg, &policy)) 1705 die("invalid policy '%s'", optarg); 1706 break; 1707 case 'u': 1708 if (modify_mask & DLADM_AGGR_MODIFY_MAC) 1709 die_optdup(option); 1710 1711 modify_mask |= DLADM_AGGR_MODIFY_MAC; 1712 1713 if (!dladm_aggr_str2macaddr(optarg, &mac_addr_fixed, 1714 mac_addr)) 1715 die("invalid MAC address '%s'", optarg); 1716 break; 1717 case 'l': 1718 case 'L': 1719 if (modify_mask & DLADM_AGGR_MODIFY_LACP_MODE) 1720 die_optdup(option); 1721 1722 modify_mask |= DLADM_AGGR_MODIFY_LACP_MODE; 1723 1724 if (!dladm_aggr_str2lacpmode(optarg, &lacp_mode)) 1725 die("invalid LACP mode '%s'", optarg); 1726 break; 1727 case 'T': 1728 if (modify_mask & DLADM_AGGR_MODIFY_LACP_TIMER) 1729 die_optdup(option); 1730 1731 modify_mask |= DLADM_AGGR_MODIFY_LACP_TIMER; 1732 1733 if (!dladm_aggr_str2lacptimer(optarg, &lacp_timer)) 1734 die("invalid LACP timer value '%s'", optarg); 1735 break; 1736 case 't': 1737 flags &= ~DLADM_OPT_PERSIST; 1738 break; 1739 case 'R': 1740 altroot = optarg; 1741 break; 1742 default: 1743 die_opterr(optopt, option, use); 1744 break; 1745 } 1746 } 1747 1748 if (modify_mask == 0) 1749 die("at least one of the -PulT options must be specified"); 1750 1751 /* get key value or the aggregation name (required last argument) */ 1752 if (optind != (argc-1)) 1753 usage(); 1754 1755 status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags); 1756 if (status != DLADM_STATUS_OK) 1757 goto done; 1758 1759 if (altroot != NULL) 1760 altroot_cmd(altroot, argc, argv); 1761 1762 status = dladm_aggr_modify(handle, linkid, modify_mask, policy, 1763 mac_addr_fixed, (const uchar_t *)mac_addr, lacp_mode, lacp_timer, 1764 flags); 1765 1766 done: 1767 if (status != DLADM_STATUS_OK) 1768 die_dlerr(status, "modify operation failed"); 1769 } 1770 1771 /*ARGSUSED*/ 1772 static void 1773 do_up_aggr(int argc, char *argv[], const char *use) 1774 { 1775 datalink_id_t linkid = DATALINK_ALL_LINKID; 1776 dladm_status_t status; 1777 1778 /* 1779 * get the key or the name of the aggregation (optional last argument) 1780 */ 1781 if (argc == 2) { 1782 if ((status = i_dladm_aggr_get_linkid(NULL, argv[1], &linkid, 1783 DLADM_OPT_PERSIST)) != DLADM_STATUS_OK) 1784 goto done; 1785 } else if (argc > 2) { 1786 usage(); 1787 } 1788 1789 status = dladm_aggr_up(handle, linkid); 1790 done: 1791 if (status != DLADM_STATUS_OK) { 1792 if (argc == 2) { 1793 die_dlerr(status, 1794 "could not bring up aggregation '%s'", argv[1]); 1795 } else { 1796 die_dlerr(status, "could not bring aggregations up"); 1797 } 1798 } 1799 } 1800 1801 static void 1802 do_create_vlan(int argc, char *argv[], const char *use) 1803 { 1804 char *link = NULL; 1805 char drv[DLPI_LINKNAME_MAX]; 1806 uint_t ppa; 1807 datalink_id_t linkid; 1808 datalink_id_t dev_linkid; 1809 int vid = 0; 1810 char option; 1811 uint32_t flags = (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST); 1812 char *altroot = NULL; 1813 char vlan[MAXLINKNAMELEN]; 1814 char propstr[DLADM_STRSIZE]; 1815 dladm_arg_list_t *proplist = NULL; 1816 dladm_status_t status; 1817 1818 opterr = 0; 1819 bzero(propstr, DLADM_STRSIZE); 1820 1821 while ((option = getopt_long(argc, argv, ":tfR:l:v:p:", 1822 lopts, NULL)) != -1) { 1823 switch (option) { 1824 case 'v': 1825 if (vid != 0) 1826 die_optdup(option); 1827 1828 if (!str2int(optarg, &vid) || vid < 1 || vid > 4094) 1829 die("invalid VLAN identifier '%s'", optarg); 1830 1831 break; 1832 case 'l': 1833 if (link != NULL) 1834 die_optdup(option); 1835 1836 link = optarg; 1837 break; 1838 case 't': 1839 flags &= ~DLADM_OPT_PERSIST; 1840 break; 1841 case 'R': 1842 altroot = optarg; 1843 break; 1844 case 'p': 1845 (void) strlcat(propstr, optarg, DLADM_STRSIZE); 1846 if (strlcat(propstr, ",", DLADM_STRSIZE) >= 1847 DLADM_STRSIZE) 1848 die("property list too long '%s'", propstr); 1849 break; 1850 case 'f': 1851 flags |= DLADM_OPT_FORCE; 1852 break; 1853 default: 1854 die_opterr(optopt, option, use); 1855 break; 1856 } 1857 } 1858 1859 /* get vlan name if there is any */ 1860 if ((vid == 0) || (link == NULL) || (argc - optind > 1)) 1861 usage(); 1862 1863 if (optind == (argc - 1)) { 1864 if (strlcpy(vlan, argv[optind], MAXLINKNAMELEN) >= 1865 MAXLINKNAMELEN) { 1866 die("vlan name too long '%s'", argv[optind]); 1867 } 1868 } else { 1869 if ((dlpi_parselink(link, drv, &ppa) != DLPI_SUCCESS) || 1870 (ppa >= 1000) || 1871 (dlpi_makelink(vlan, drv, vid * 1000 + ppa) != 1872 DLPI_SUCCESS)) { 1873 die("invalid link name '%s'", link); 1874 } 1875 } 1876 1877 if (altroot != NULL) 1878 altroot_cmd(altroot, argc, argv); 1879 1880 if (dladm_name2info(handle, link, &dev_linkid, NULL, NULL, NULL) != 1881 DLADM_STATUS_OK) { 1882 die("invalid link name '%s'", link); 1883 } 1884 1885 if (dladm_parse_link_props(propstr, &proplist, B_FALSE) 1886 != DLADM_STATUS_OK) 1887 die("invalid vlan property"); 1888 1889 if ((status = dladm_vlan_create(handle, vlan, dev_linkid, vid, proplist, 1890 flags, &linkid)) != DLADM_STATUS_OK) { 1891 die_dlerr(status, "create operation over %s failed", link); 1892 } 1893 } 1894 1895 static void 1896 do_delete_vlan(int argc, char *argv[], const char *use) 1897 { 1898 char option; 1899 uint32_t flags = (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST); 1900 char *altroot = NULL; 1901 datalink_id_t linkid; 1902 dladm_status_t status; 1903 1904 opterr = 0; 1905 while ((option = getopt_long(argc, argv, ":R:t", lopts, NULL)) != -1) { 1906 switch (option) { 1907 case 't': 1908 flags &= ~DLADM_OPT_PERSIST; 1909 break; 1910 case 'R': 1911 altroot = optarg; 1912 break; 1913 default: 1914 die_opterr(optopt, option, use); 1915 break; 1916 } 1917 } 1918 1919 /* get VLAN link name (required last argument) */ 1920 if (optind != (argc - 1)) 1921 usage(); 1922 1923 if (altroot != NULL) 1924 altroot_cmd(altroot, argc, argv); 1925 1926 status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL, 1927 NULL); 1928 if (status != DLADM_STATUS_OK) 1929 goto done; 1930 1931 status = dladm_vlan_delete(handle, linkid, flags); 1932 done: 1933 if (status != DLADM_STATUS_OK) 1934 die_dlerr(status, "delete operation failed"); 1935 } 1936 1937 /*ARGSUSED*/ 1938 static void 1939 do_up_vlan(int argc, char *argv[], const char *use) 1940 { 1941 do_up_vnic_common(argc, argv, use, B_TRUE); 1942 } 1943 1944 static void 1945 do_rename_link(int argc, char *argv[], const char *use) 1946 { 1947 char option; 1948 char *link1, *link2; 1949 char *altroot = NULL; 1950 dladm_status_t status; 1951 1952 opterr = 0; 1953 while ((option = getopt_long(argc, argv, ":R:", lopts, NULL)) != -1) { 1954 switch (option) { 1955 case 'R': 1956 altroot = optarg; 1957 break; 1958 default: 1959 die_opterr(optopt, option, use); 1960 break; 1961 } 1962 } 1963 1964 /* get link1 and link2 name (required the last 2 arguments) */ 1965 if (optind != (argc - 2)) 1966 usage(); 1967 1968 if (altroot != NULL) 1969 altroot_cmd(altroot, argc, argv); 1970 1971 link1 = argv[optind++]; 1972 link2 = argv[optind]; 1973 if ((status = dladm_rename_link(handle, link1, link2)) != 1974 DLADM_STATUS_OK) 1975 die_dlerr(status, "rename operation failed"); 1976 } 1977 1978 /*ARGSUSED*/ 1979 static void 1980 do_delete_phys(int argc, char *argv[], const char *use) 1981 { 1982 datalink_id_t linkid = DATALINK_ALL_LINKID; 1983 dladm_status_t status; 1984 1985 /* get link name (required the last argument) */ 1986 if (argc > 2) 1987 usage(); 1988 1989 if (argc == 2) { 1990 if ((status = dladm_name2info(handle, argv[1], &linkid, NULL, 1991 NULL, NULL)) != DLADM_STATUS_OK) 1992 die_dlerr(status, "cannot delete '%s'", argv[1]); 1993 } 1994 1995 if ((status = dladm_phys_delete(handle, linkid)) != DLADM_STATUS_OK) { 1996 if (argc == 2) 1997 die_dlerr(status, "cannot delete '%s'", argv[1]); 1998 else 1999 die_dlerr(status, "delete operation failed"); 2000 } 2001 } 2002 2003 /*ARGSUSED*/ 2004 static int 2005 i_dladm_walk_linkmap(dladm_handle_t dh, datalink_id_t linkid, void *arg) 2006 { 2007 char name[MAXLINKNAMELEN]; 2008 char mediabuf[DLADM_STRSIZE]; 2009 char classbuf[DLADM_STRSIZE]; 2010 datalink_class_t class; 2011 uint32_t media; 2012 uint32_t flags; 2013 2014 if (dladm_datalink_id2info(dh, linkid, &flags, &class, &media, name, 2015 MAXLINKNAMELEN) == DLADM_STATUS_OK) { 2016 (void) dladm_class2str(class, classbuf); 2017 (void) dladm_media2str(media, mediabuf); 2018 (void) printf("%-12s%8d %-12s%-20s %6d\n", name, 2019 linkid, classbuf, mediabuf, flags); 2020 } 2021 return (DLADM_WALK_CONTINUE); 2022 } 2023 2024 /*ARGSUSED*/ 2025 static void 2026 do_show_linkmap(int argc, char *argv[], const char *use) 2027 { 2028 if (argc != 1) 2029 die("invalid arguments"); 2030 2031 (void) printf("%-12s%8s %-12s%-20s %6s\n", "NAME", "LINKID", 2032 "CLASS", "MEDIA", "FLAGS"); 2033 2034 (void) dladm_walk_datalink_id(i_dladm_walk_linkmap, handle, NULL, 2035 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, 2036 DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST); 2037 } 2038 2039 /* 2040 * Delete inactive physical links. 2041 */ 2042 /*ARGSUSED*/ 2043 static int 2044 purge_phys(dladm_handle_t dh, datalink_id_t linkid, void *arg) 2045 { 2046 datalink_class_t class; 2047 uint32_t flags; 2048 2049 if (dladm_datalink_id2info(dh, linkid, &flags, &class, NULL, NULL, 0) 2050 != DLADM_STATUS_OK) { 2051 return (DLADM_WALK_CONTINUE); 2052 } 2053 2054 if (class == DATALINK_CLASS_PHYS && !(flags & DLADM_OPT_ACTIVE)) 2055 (void) dladm_phys_delete(dh, linkid); 2056 2057 return (DLADM_WALK_CONTINUE); 2058 } 2059 2060 /*ARGSUSED*/ 2061 static void 2062 do_init_phys(int argc, char *argv[], const char *use) 2063 { 2064 di_node_t devtree; 2065 2066 if (argc > 1) 2067 usage(); 2068 2069 /* 2070 * Force all the devices to attach, therefore all the network physical 2071 * devices can be known to the dlmgmtd daemon. 2072 */ 2073 if ((devtree = di_init("/", DINFOFORCE | DINFOSUBTREE)) != DI_NODE_NIL) 2074 di_fini(devtree); 2075 2076 (void) dladm_walk_datalink_id(purge_phys, handle, NULL, 2077 DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 2078 } 2079 2080 2081 /* 2082 * Print the active topology information. 2083 */ 2084 static dladm_status_t 2085 print_link_topology(show_state_t *state, datalink_id_t linkid, 2086 datalink_class_t class, link_fields_buf_t *lbuf) 2087 { 2088 uint32_t flags = state->ls_flags; 2089 dladm_status_t status = DLADM_STATUS_OK; 2090 char tmpbuf[MAXLINKNAMELEN]; 2091 2092 (void) sprintf(lbuf->link_over, ""); 2093 if (class == DATALINK_CLASS_VLAN) { 2094 dladm_vlan_attr_t vinfo; 2095 2096 status = dladm_vlan_info(handle, linkid, &vinfo, flags); 2097 if (status != DLADM_STATUS_OK) 2098 goto done; 2099 status = dladm_datalink_id2info(handle, vinfo.dv_linkid, NULL, 2100 NULL, NULL, lbuf->link_over, sizeof (lbuf->link_over)); 2101 if (status != DLADM_STATUS_OK) 2102 goto done; 2103 } else if (class == DATALINK_CLASS_AGGR) { 2104 dladm_aggr_grp_attr_t ginfo; 2105 int i; 2106 2107 (void) sprintf(lbuf->link_over, ""); 2108 2109 status = dladm_aggr_info(handle, linkid, &ginfo, flags); 2110 if (status != DLADM_STATUS_OK) 2111 goto done; 2112 2113 if (ginfo.lg_nports == 0) { 2114 status = DLADM_STATUS_BADVAL; 2115 goto done; 2116 } 2117 for (i = 0; i < ginfo.lg_nports; i++) { 2118 status = dladm_datalink_id2info(handle, 2119 ginfo.lg_ports[i].lp_linkid, NULL, NULL, NULL, 2120 tmpbuf, sizeof (tmpbuf)); 2121 if (status != DLADM_STATUS_OK) { 2122 free(ginfo.lg_ports); 2123 goto done; 2124 } 2125 (void) strlcat(lbuf->link_over, tmpbuf, 2126 sizeof (lbuf->link_over)); 2127 if (i != (ginfo.lg_nports - 1)) { 2128 (void) strlcat(lbuf->link_over, " ", 2129 sizeof (lbuf->link_over)); 2130 } 2131 } 2132 free(ginfo.lg_ports); 2133 } else if (class == DATALINK_CLASS_VNIC) { 2134 dladm_vnic_attr_t vinfo; 2135 2136 if ((status = dladm_vnic_info(handle, linkid, &vinfo, flags)) != 2137 DLADM_STATUS_OK || 2138 (status = dladm_datalink_id2info(handle, vinfo.va_link_id, 2139 NULL, NULL, NULL, lbuf->link_over, 2140 sizeof (lbuf->link_over)) != DLADM_STATUS_OK)) { 2141 goto done; 2142 } 2143 } 2144 done: 2145 return (status); 2146 } 2147 2148 static dladm_status_t 2149 print_link(show_state_t *state, datalink_id_t linkid, link_fields_buf_t *lbuf) 2150 { 2151 char link[MAXLINKNAMELEN]; 2152 datalink_class_t class; 2153 uint_t mtu; 2154 uint32_t flags; 2155 dladm_status_t status; 2156 2157 if ((status = dladm_datalink_id2info(handle, linkid, &flags, &class, 2158 NULL, link, sizeof (link))) != DLADM_STATUS_OK) { 2159 goto done; 2160 } 2161 2162 if (!(state->ls_flags & flags)) { 2163 status = DLADM_STATUS_NOTFOUND; 2164 goto done; 2165 } 2166 2167 if (state->ls_flags == DLADM_OPT_ACTIVE) { 2168 dladm_attr_t dlattr; 2169 2170 if (class == DATALINK_CLASS_PHYS) { 2171 dladm_phys_attr_t dpa; 2172 dlpi_handle_t dh; 2173 dlpi_info_t dlinfo; 2174 2175 if ((status = dladm_phys_info(handle, linkid, &dpa, 2176 DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) { 2177 goto done; 2178 } 2179 2180 if (!dpa.dp_novanity) 2181 goto link_mtu; 2182 2183 /* 2184 * This is a physical link that does not have 2185 * vanity naming support. 2186 */ 2187 if (dlpi_open(dpa.dp_dev, &dh, DLPI_DEVONLY) != 2188 DLPI_SUCCESS) { 2189 status = DLADM_STATUS_NOTFOUND; 2190 goto done; 2191 } 2192 2193 if (dlpi_info(dh, &dlinfo, 0) != DLPI_SUCCESS) { 2194 dlpi_close(dh); 2195 status = DLADM_STATUS_BADARG; 2196 goto done; 2197 } 2198 2199 dlpi_close(dh); 2200 mtu = dlinfo.di_max_sdu; 2201 } else { 2202 link_mtu: 2203 status = dladm_info(handle, linkid, &dlattr); 2204 if (status != DLADM_STATUS_OK) 2205 goto done; 2206 mtu = dlattr.da_max_sdu; 2207 } 2208 } 2209 2210 (void) snprintf(lbuf->link_name, sizeof (lbuf->link_name), 2211 "%s", link); 2212 (void) dladm_class2str(class, lbuf->link_class); 2213 if (state->ls_flags == DLADM_OPT_ACTIVE) { 2214 (void) snprintf(lbuf->link_mtu, sizeof (lbuf->link_mtu), 2215 "%u", mtu); 2216 (void) get_linkstate(link, B_TRUE, lbuf->link_state); 2217 } 2218 2219 status = print_link_topology(state, linkid, class, lbuf); 2220 if (status != DLADM_STATUS_OK) 2221 goto done; 2222 2223 done: 2224 return (status); 2225 } 2226 2227 /* ARGSUSED */ 2228 static int 2229 show_link(dladm_handle_t dh, datalink_id_t linkid, void *arg) 2230 { 2231 show_state_t *state = (show_state_t *)arg; 2232 dladm_status_t status; 2233 link_fields_buf_t lbuf; 2234 2235 /* 2236 * first get all the link attributes into lbuf; 2237 */ 2238 bzero(&lbuf, sizeof (link_fields_buf_t)); 2239 status = print_link(state, linkid, &lbuf); 2240 2241 if (status != DLADM_STATUS_OK) 2242 goto done; 2243 2244 ofmt_print(state->ls_ofmt, &lbuf); 2245 2246 done: 2247 state->ls_status = status; 2248 return (DLADM_WALK_CONTINUE); 2249 } 2250 2251 static boolean_t 2252 print_link_stats_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 2253 { 2254 link_args_t *largs = ofarg->ofmt_cbarg; 2255 pktsum_t *diff_stats = largs->link_s_psum; 2256 2257 switch (ofarg->ofmt_id) { 2258 case LINK_S_LINK: 2259 (void) snprintf(buf, bufsize, "%s", largs->link_s_link); 2260 break; 2261 case LINK_S_IPKTS: 2262 (void) snprintf(buf, bufsize, "%llu", diff_stats->ipackets); 2263 break; 2264 case LINK_S_RBYTES: 2265 (void) snprintf(buf, bufsize, "%llu", diff_stats->rbytes); 2266 break; 2267 case LINK_S_IERRORS: 2268 (void) snprintf(buf, bufsize, "%u", diff_stats->ierrors); 2269 break; 2270 case LINK_S_OPKTS: 2271 (void) snprintf(buf, bufsize, "%llu", diff_stats->opackets); 2272 break; 2273 case LINK_S_OBYTES: 2274 (void) snprintf(buf, bufsize, "%llu", diff_stats->obytes); 2275 break; 2276 case LINK_S_OERRORS: 2277 (void) snprintf(buf, bufsize, "%u", diff_stats->oerrors); 2278 break; 2279 default: 2280 die("invalid input"); 2281 break; 2282 } 2283 return (B_TRUE); 2284 } 2285 2286 static int 2287 show_link_stats(dladm_handle_t dh, datalink_id_t linkid, void *arg) 2288 { 2289 char link[DLPI_LINKNAME_MAX]; 2290 datalink_class_t class; 2291 show_state_t *state = (show_state_t *)arg; 2292 pktsum_t stats, diff_stats; 2293 dladm_phys_attr_t dpa; 2294 link_args_t largs; 2295 2296 if (state->ls_firstonly) { 2297 if (state->ls_donefirst) 2298 return (DLADM_WALK_CONTINUE); 2299 state->ls_donefirst = B_TRUE; 2300 } else { 2301 bzero(&state->ls_prevstats, sizeof (state->ls_prevstats)); 2302 } 2303 2304 if (dladm_datalink_id2info(dh, linkid, NULL, &class, NULL, link, 2305 DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) { 2306 return (DLADM_WALK_CONTINUE); 2307 } 2308 2309 if (class == DATALINK_CLASS_PHYS) { 2310 if (dladm_phys_info(dh, linkid, &dpa, DLADM_OPT_ACTIVE) != 2311 DLADM_STATUS_OK) { 2312 return (DLADM_WALK_CONTINUE); 2313 } 2314 if (dpa.dp_novanity) 2315 get_mac_stats(dpa.dp_dev, &stats); 2316 else 2317 get_link_stats(link, &stats); 2318 } else { 2319 get_link_stats(link, &stats); 2320 } 2321 dladm_stats_diff(&diff_stats, &stats, &state->ls_prevstats); 2322 2323 largs.link_s_link = link; 2324 largs.link_s_psum = &diff_stats; 2325 ofmt_print(state->ls_ofmt, &largs); 2326 2327 state->ls_prevstats = stats; 2328 return (DLADM_WALK_CONTINUE); 2329 } 2330 2331 2332 static dladm_status_t 2333 print_aggr_info(show_grp_state_t *state, const char *link, 2334 dladm_aggr_grp_attr_t *ginfop) 2335 { 2336 char addr_str[ETHERADDRL * 3]; 2337 laggr_fields_buf_t lbuf; 2338 2339 (void) snprintf(lbuf.laggr_name, sizeof (lbuf.laggr_name), 2340 "%s", link); 2341 2342 (void) dladm_aggr_policy2str(ginfop->lg_policy, 2343 lbuf.laggr_policy); 2344 2345 if (ginfop->lg_mac_fixed) { 2346 (void) dladm_aggr_macaddr2str(ginfop->lg_mac, addr_str); 2347 (void) snprintf(lbuf.laggr_addrpolicy, 2348 sizeof (lbuf.laggr_addrpolicy), "fixed (%s)", addr_str); 2349 } else { 2350 (void) snprintf(lbuf.laggr_addrpolicy, 2351 sizeof (lbuf.laggr_addrpolicy), "auto"); 2352 } 2353 2354 2355 (void) dladm_aggr_lacpmode2str(ginfop->lg_lacp_mode, 2356 lbuf.laggr_lacpactivity); 2357 (void) dladm_aggr_lacptimer2str(ginfop->lg_lacp_timer, 2358 lbuf.laggr_lacptimer); 2359 (void) snprintf(lbuf.laggr_flags, sizeof (lbuf.laggr_flags), "%c----", 2360 ginfop->lg_force ? 'f' : '-'); 2361 2362 ofmt_print(state->gs_ofmt, &lbuf); 2363 2364 return (DLADM_STATUS_OK); 2365 } 2366 2367 static boolean_t 2368 print_xaggr_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 2369 { 2370 const laggr_args_t *l = ofarg->ofmt_cbarg; 2371 int portnum; 2372 boolean_t is_port = (l->laggr_lport >= 0); 2373 static char tmpbuf[DLADM_STRSIZE]; 2374 dladm_aggr_port_attr_t *portp; 2375 dladm_phys_attr_t dpa; 2376 dladm_status_t *stat, status = DLADM_STATUS_OK; 2377 2378 stat = l->laggr_status; 2379 2380 if (is_port) { 2381 portnum = l->laggr_lport; 2382 portp = &(l->laggr_ginfop->lg_ports[portnum]); 2383 if ((status = dladm_datalink_id2info(handle, 2384 portp->lp_linkid, NULL, NULL, NULL, buf, bufsize)) != 2385 DLADM_STATUS_OK) { 2386 goto err; 2387 } 2388 2389 if ((status = dladm_phys_info(handle, portp->lp_linkid, 2390 &dpa, DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) { 2391 goto err; 2392 } 2393 } 2394 2395 switch (ofarg->ofmt_id) { 2396 case AGGR_X_LINK: 2397 (void) snprintf(buf, bufsize, "%s", 2398 (is_port && !l->laggr_parsable ? " " : l->laggr_link)); 2399 break; 2400 case AGGR_X_PORT: 2401 if (is_port) 2402 break; 2403 *stat = DLADM_STATUS_OK; 2404 return (B_TRUE); 2405 2406 case AGGR_X_SPEED: 2407 if (is_port) { 2408 (void) snprintf(buf, bufsize, "%uMb", 2409 (uint_t)((get_ifspeed(dpa.dp_dev, 2410 B_FALSE)) / 1000000ull)); 2411 } else { 2412 (void) snprintf(buf, bufsize, "%uMb", 2413 (uint_t)((get_ifspeed(l->laggr_link, 2414 B_TRUE)) / 1000000ull)); 2415 } 2416 break; 2417 2418 case AGGR_X_DUPLEX: 2419 if (is_port) 2420 (void) get_linkduplex(dpa.dp_dev, B_FALSE, tmpbuf); 2421 else 2422 (void) get_linkduplex(l->laggr_link, B_TRUE, tmpbuf); 2423 (void) strlcpy(buf, tmpbuf, bufsize); 2424 break; 2425 2426 case AGGR_X_STATE: 2427 if (is_port) 2428 (void) get_linkstate(dpa.dp_dev, B_FALSE, tmpbuf); 2429 else 2430 (void) get_linkstate(l->laggr_link, B_TRUE, tmpbuf); 2431 (void) strlcpy(buf, tmpbuf, bufsize); 2432 break; 2433 case AGGR_X_ADDRESS: 2434 (void) dladm_aggr_macaddr2str( 2435 (is_port ? portp->lp_mac : l->laggr_ginfop->lg_mac), 2436 tmpbuf); 2437 (void) strlcpy(buf, tmpbuf, bufsize); 2438 break; 2439 case AGGR_X_PORTSTATE: 2440 if (is_port) { 2441 (void) dladm_aggr_portstate2str(portp->lp_state, 2442 tmpbuf); 2443 (void) strlcpy(buf, tmpbuf, bufsize); 2444 } 2445 break; 2446 } 2447 err: 2448 *stat = status; 2449 return (B_TRUE); 2450 } 2451 2452 static dladm_status_t 2453 print_aggr_extended(show_grp_state_t *state, const char *link, 2454 dladm_aggr_grp_attr_t *ginfop) 2455 { 2456 int i; 2457 dladm_status_t status; 2458 laggr_args_t largs; 2459 2460 largs.laggr_lport = -1; 2461 largs.laggr_link = link; 2462 largs.laggr_ginfop = ginfop; 2463 largs.laggr_status = &status; 2464 largs.laggr_parsable = state->gs_parsable; 2465 2466 ofmt_print(state->gs_ofmt, &largs); 2467 2468 if (status != DLADM_STATUS_OK) 2469 goto done; 2470 2471 for (i = 0; i < ginfop->lg_nports; i++) { 2472 largs.laggr_lport = i; 2473 ofmt_print(state->gs_ofmt, &largs); 2474 if (status != DLADM_STATUS_OK) 2475 goto done; 2476 } 2477 2478 status = DLADM_STATUS_OK; 2479 done: 2480 return (status); 2481 } 2482 2483 static boolean_t 2484 print_lacp_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 2485 { 2486 const laggr_args_t *l = ofarg->ofmt_cbarg; 2487 int portnum; 2488 boolean_t is_port = (l->laggr_lport >= 0); 2489 dladm_aggr_port_attr_t *portp; 2490 dladm_status_t *stat, status; 2491 aggr_lacp_state_t *lstate; 2492 2493 if (!is_port) { 2494 return (B_FALSE); /* cannot happen! */ 2495 } 2496 2497 stat = l->laggr_status; 2498 2499 portnum = l->laggr_lport; 2500 portp = &(l->laggr_ginfop->lg_ports[portnum]); 2501 2502 if ((status = dladm_datalink_id2info(handle, portp->lp_linkid, 2503 NULL, NULL, NULL, buf, bufsize)) != DLADM_STATUS_OK) { 2504 goto err; 2505 } 2506 lstate = &(portp->lp_lacp_state); 2507 2508 switch (ofarg->ofmt_id) { 2509 case AGGR_L_LINK: 2510 (void) snprintf(buf, bufsize, "%s", 2511 (portnum > 0 ? "" : l->laggr_link)); 2512 break; 2513 2514 case AGGR_L_PORT: 2515 /* 2516 * buf already contains portname as a result of the 2517 * earlier call to dladm_datalink_id2info(). 2518 */ 2519 break; 2520 2521 case AGGR_L_AGGREGATABLE: 2522 (void) snprintf(buf, bufsize, "%s", 2523 (lstate->bit.aggregation ? "yes" : "no")); 2524 break; 2525 2526 case AGGR_L_SYNC: 2527 (void) snprintf(buf, bufsize, "%s", 2528 (lstate->bit.sync ? "yes" : "no")); 2529 break; 2530 2531 case AGGR_L_COLL: 2532 (void) snprintf(buf, bufsize, "%s", 2533 (lstate->bit.collecting ? "yes" : "no")); 2534 break; 2535 2536 case AGGR_L_DIST: 2537 (void) snprintf(buf, bufsize, "%s", 2538 (lstate->bit.distributing ? "yes" : "no")); 2539 break; 2540 2541 case AGGR_L_DEFAULTED: 2542 (void) snprintf(buf, bufsize, "%s", 2543 (lstate->bit.defaulted ? "yes" : "no")); 2544 break; 2545 2546 case AGGR_L_EXPIRED: 2547 (void) snprintf(buf, bufsize, "%s", 2548 (lstate->bit.expired ? "yes" : "no")); 2549 break; 2550 } 2551 2552 *stat = DLADM_STATUS_OK; 2553 return (B_TRUE); 2554 2555 err: 2556 *stat = status; 2557 return (B_TRUE); 2558 } 2559 2560 static dladm_status_t 2561 print_aggr_lacp(show_grp_state_t *state, const char *link, 2562 dladm_aggr_grp_attr_t *ginfop) 2563 { 2564 int i; 2565 dladm_status_t status; 2566 laggr_args_t largs; 2567 2568 largs.laggr_link = link; 2569 largs.laggr_ginfop = ginfop; 2570 largs.laggr_status = &status; 2571 2572 for (i = 0; i < ginfop->lg_nports; i++) { 2573 largs.laggr_lport = i; 2574 ofmt_print(state->gs_ofmt, &largs); 2575 if (status != DLADM_STATUS_OK) 2576 goto done; 2577 } 2578 2579 status = DLADM_STATUS_OK; 2580 done: 2581 return (status); 2582 } 2583 2584 static boolean_t 2585 print_aggr_stats_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 2586 { 2587 const laggr_args_t *l = ofarg->ofmt_cbarg; 2588 int portnum; 2589 boolean_t is_port = (l->laggr_lport >= 0); 2590 dladm_aggr_port_attr_t *portp; 2591 dladm_status_t *stat, status; 2592 pktsum_t *diff_stats; 2593 2594 stat = l->laggr_status; 2595 *stat = DLADM_STATUS_OK; 2596 2597 if (is_port) { 2598 portnum = l->laggr_lport; 2599 portp = &(l->laggr_ginfop->lg_ports[portnum]); 2600 2601 if ((status = dladm_datalink_id2info(handle, 2602 portp->lp_linkid, NULL, NULL, NULL, buf, bufsize)) != 2603 DLADM_STATUS_OK) { 2604 goto err; 2605 } 2606 diff_stats = l->laggr_diffstats; 2607 } 2608 2609 switch (ofarg->ofmt_id) { 2610 case AGGR_S_LINK: 2611 (void) snprintf(buf, bufsize, "%s", 2612 (is_port ? "" : l->laggr_link)); 2613 break; 2614 case AGGR_S_PORT: 2615 /* 2616 * if (is_port), buf has port name. Otherwise we print 2617 * STR_UNDEF_VAL 2618 */ 2619 break; 2620 2621 case AGGR_S_IPKTS: 2622 if (is_port) { 2623 (void) snprintf(buf, bufsize, "%llu", 2624 diff_stats->ipackets); 2625 } else { 2626 (void) snprintf(buf, bufsize, "%llu", 2627 l->laggr_pktsumtot->ipackets); 2628 } 2629 break; 2630 2631 case AGGR_S_RBYTES: 2632 if (is_port) { 2633 (void) snprintf(buf, bufsize, "%llu", 2634 diff_stats->rbytes); 2635 } else { 2636 (void) snprintf(buf, bufsize, "%llu", 2637 l->laggr_pktsumtot->rbytes); 2638 } 2639 break; 2640 2641 case AGGR_S_OPKTS: 2642 if (is_port) { 2643 (void) snprintf(buf, bufsize, "%llu", 2644 diff_stats->opackets); 2645 } else { 2646 (void) snprintf(buf, bufsize, "%llu", 2647 l->laggr_pktsumtot->opackets); 2648 } 2649 break; 2650 case AGGR_S_OBYTES: 2651 if (is_port) { 2652 (void) snprintf(buf, bufsize, "%llu", 2653 diff_stats->obytes); 2654 } else { 2655 (void) snprintf(buf, bufsize, "%llu", 2656 l->laggr_pktsumtot->obytes); 2657 } 2658 break; 2659 2660 case AGGR_S_IPKTDIST: 2661 if (is_port) { 2662 (void) snprintf(buf, bufsize, "%-6.1f", 2663 (double)diff_stats->ipackets/ 2664 (double)l->laggr_pktsumtot->ipackets * 100); 2665 } 2666 break; 2667 case AGGR_S_OPKTDIST: 2668 if (is_port) { 2669 (void) snprintf(buf, bufsize, "%-6.1f", 2670 (double)diff_stats->opackets/ 2671 (double)l->laggr_pktsumtot->opackets * 100); 2672 } 2673 break; 2674 } 2675 return (B_TRUE); 2676 2677 err: 2678 *stat = status; 2679 return (B_TRUE); 2680 } 2681 2682 static dladm_status_t 2683 print_aggr_stats(show_grp_state_t *state, const char *link, 2684 dladm_aggr_grp_attr_t *ginfop) 2685 { 2686 dladm_phys_attr_t dpa; 2687 dladm_aggr_port_attr_t *portp; 2688 pktsum_t pktsumtot, *port_stat; 2689 dladm_status_t status; 2690 int i; 2691 laggr_args_t largs; 2692 2693 /* sum the ports statistics */ 2694 bzero(&pktsumtot, sizeof (pktsumtot)); 2695 2696 /* Allocate memory to keep stats of each port */ 2697 port_stat = malloc(ginfop->lg_nports * sizeof (pktsum_t)); 2698 if (port_stat == NULL) { 2699 /* Bail out; no memory */ 2700 return (DLADM_STATUS_NOMEM); 2701 } 2702 2703 2704 for (i = 0; i < ginfop->lg_nports; i++) { 2705 2706 portp = &(ginfop->lg_ports[i]); 2707 if ((status = dladm_phys_info(handle, portp->lp_linkid, &dpa, 2708 DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) { 2709 goto done; 2710 } 2711 2712 get_mac_stats(dpa.dp_dev, &port_stat[i]); 2713 2714 /* 2715 * Let's re-use gs_prevstats[] to store the difference of the 2716 * counters since last use. We will store the new stats from 2717 * port_stat[] once we have the stats displayed. 2718 */ 2719 2720 dladm_stats_diff(&state->gs_prevstats[i], &port_stat[i], 2721 &state->gs_prevstats[i]); 2722 dladm_stats_total(&pktsumtot, &pktsumtot, 2723 &state->gs_prevstats[i]); 2724 } 2725 2726 largs.laggr_lport = -1; 2727 largs.laggr_link = link; 2728 largs.laggr_ginfop = ginfop; 2729 largs.laggr_status = &status; 2730 largs.laggr_pktsumtot = &pktsumtot; 2731 2732 ofmt_print(state->gs_ofmt, &largs); 2733 2734 if (status != DLADM_STATUS_OK) 2735 goto done; 2736 2737 for (i = 0; i < ginfop->lg_nports; i++) { 2738 largs.laggr_lport = i; 2739 largs.laggr_diffstats = &state->gs_prevstats[i]; 2740 ofmt_print(state->gs_ofmt, &largs); 2741 if (status != DLADM_STATUS_OK) 2742 goto done; 2743 } 2744 2745 status = DLADM_STATUS_OK; 2746 for (i = 0; i < ginfop->lg_nports; i++) 2747 state->gs_prevstats[i] = port_stat[i]; 2748 2749 done: 2750 free(port_stat); 2751 return (status); 2752 } 2753 2754 static dladm_status_t 2755 print_aggr(show_grp_state_t *state, datalink_id_t linkid) 2756 { 2757 char link[MAXLINKNAMELEN]; 2758 dladm_aggr_grp_attr_t ginfo; 2759 uint32_t flags; 2760 dladm_status_t status; 2761 2762 bzero(&ginfo, sizeof (dladm_aggr_grp_attr_t)); 2763 if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL, 2764 NULL, link, MAXLINKNAMELEN)) != DLADM_STATUS_OK) { 2765 return (status); 2766 } 2767 2768 if (!(state->gs_flags & flags)) 2769 return (DLADM_STATUS_NOTFOUND); 2770 2771 status = dladm_aggr_info(handle, linkid, &ginfo, state->gs_flags); 2772 if (status != DLADM_STATUS_OK) 2773 return (status); 2774 2775 if (state->gs_lacp) 2776 status = print_aggr_lacp(state, link, &ginfo); 2777 else if (state->gs_extended) 2778 status = print_aggr_extended(state, link, &ginfo); 2779 else if (state->gs_stats) 2780 status = print_aggr_stats(state, link, &ginfo); 2781 else 2782 status = print_aggr_info(state, link, &ginfo); 2783 2784 done: 2785 free(ginfo.lg_ports); 2786 return (status); 2787 } 2788 2789 /* ARGSUSED */ 2790 static int 2791 show_aggr(dladm_handle_t dh, datalink_id_t linkid, void *arg) 2792 { 2793 show_grp_state_t *state = arg; 2794 2795 state->gs_status = print_aggr(state, linkid); 2796 return (DLADM_WALK_CONTINUE); 2797 } 2798 2799 static void 2800 do_show_link(int argc, char *argv[], const char *use) 2801 { 2802 int option; 2803 boolean_t s_arg = B_FALSE; 2804 boolean_t S_arg = B_FALSE; 2805 boolean_t i_arg = B_FALSE; 2806 uint32_t flags = DLADM_OPT_ACTIVE; 2807 boolean_t p_arg = B_FALSE; 2808 datalink_id_t linkid = DATALINK_ALL_LINKID; 2809 char linkname[MAXLINKNAMELEN]; 2810 uint32_t interval = 0; 2811 show_state_t state; 2812 dladm_status_t status; 2813 boolean_t o_arg = B_FALSE; 2814 char *fields_str = NULL; 2815 char *all_active_fields = "link,class,mtu,state,over"; 2816 char *all_inactive_fields = "link,class,over"; 2817 char *allstat_fields = 2818 "link,ipackets,rbytes,ierrors,opackets,obytes,oerrors"; 2819 ofmt_handle_t ofmt; 2820 ofmt_status_t oferr; 2821 uint_t ofmtflags = 0; 2822 2823 bzero(&state, sizeof (state)); 2824 2825 opterr = 0; 2826 while ((option = getopt_long(argc, argv, ":pPsSi:o:", 2827 show_lopts, NULL)) != -1) { 2828 switch (option) { 2829 case 'p': 2830 if (p_arg) 2831 die_optdup(option); 2832 2833 p_arg = B_TRUE; 2834 break; 2835 case 's': 2836 if (s_arg) 2837 die_optdup(option); 2838 2839 s_arg = B_TRUE; 2840 break; 2841 case 'P': 2842 if (flags != DLADM_OPT_ACTIVE) 2843 die_optdup(option); 2844 2845 flags = DLADM_OPT_PERSIST; 2846 break; 2847 case 'S': 2848 if (S_arg) 2849 die_optdup(option); 2850 2851 S_arg = B_TRUE; 2852 break; 2853 case 'o': 2854 o_arg = B_TRUE; 2855 fields_str = optarg; 2856 break; 2857 case 'i': 2858 if (i_arg) 2859 die_optdup(option); 2860 2861 i_arg = B_TRUE; 2862 if (!dladm_str2interval(optarg, &interval)) 2863 die("invalid interval value '%s'", optarg); 2864 break; 2865 default: 2866 die_opterr(optopt, option, use); 2867 break; 2868 } 2869 } 2870 2871 if (i_arg && !(s_arg || S_arg)) 2872 die("the option -i can be used only with -s or -S"); 2873 2874 if (s_arg && S_arg) 2875 die("the -s option cannot be used with -S"); 2876 2877 if (s_arg && flags != DLADM_OPT_ACTIVE) 2878 die("the option -P cannot be used with -s"); 2879 2880 if (S_arg && (p_arg || flags != DLADM_OPT_ACTIVE)) 2881 die("the option -%c cannot be used with -S", p_arg ? 'p' : 'P'); 2882 2883 /* get link name (optional last argument) */ 2884 if (optind == (argc-1)) { 2885 uint32_t f; 2886 2887 if (strlcpy(linkname, argv[optind], MAXLINKNAMELEN) 2888 >= MAXLINKNAMELEN) { 2889 (void) fprintf(stderr, 2890 gettext("%s: link name too long\n"), 2891 progname); 2892 dladm_close(handle); 2893 exit(1); 2894 } 2895 if ((status = dladm_name2info(handle, linkname, &linkid, &f, 2896 NULL, NULL)) != DLADM_STATUS_OK) { 2897 die_dlerr(status, "link %s is not valid", linkname); 2898 } 2899 2900 if (!(f & flags)) { 2901 die_dlerr(DLADM_STATUS_BADARG, "link %s is %s", 2902 argv[optind], flags == DLADM_OPT_PERSIST ? 2903 "a temporary link" : "temporarily removed"); 2904 } 2905 } else if (optind != argc) { 2906 usage(); 2907 } 2908 2909 if (p_arg && !o_arg) 2910 die("-p requires -o"); 2911 2912 if (S_arg) { 2913 dladm_continuous(handle, linkid, NULL, interval, LINK_REPORT); 2914 return; 2915 } 2916 2917 if (p_arg && strcasecmp(fields_str, "all") == 0) 2918 die("\"-o all\" is invalid with -p"); 2919 2920 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) { 2921 if (s_arg) 2922 fields_str = allstat_fields; 2923 else if (flags & DLADM_OPT_ACTIVE) 2924 fields_str = all_active_fields; 2925 else 2926 fields_str = all_inactive_fields; 2927 } 2928 2929 state.ls_parsable = p_arg; 2930 state.ls_flags = flags; 2931 state.ls_donefirst = B_FALSE; 2932 2933 if (s_arg) { 2934 link_stats(linkid, interval, fields_str, &state); 2935 return; 2936 } 2937 if (state.ls_parsable) 2938 ofmtflags |= OFMT_PARSABLE; 2939 oferr = ofmt_open(fields_str, link_fields, ofmtflags, 0, &ofmt); 2940 dladm_ofmt_check(oferr, state.ls_parsable, ofmt); 2941 state.ls_ofmt = ofmt; 2942 2943 if (linkid == DATALINK_ALL_LINKID) { 2944 (void) dladm_walk_datalink_id(show_link, handle, &state, 2945 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, flags); 2946 } else { 2947 (void) show_link(handle, linkid, &state); 2948 if (state.ls_status != DLADM_STATUS_OK) { 2949 die_dlerr(state.ls_status, "failed to show link %s", 2950 argv[optind]); 2951 } 2952 } 2953 ofmt_close(ofmt); 2954 } 2955 2956 static void 2957 do_show_aggr(int argc, char *argv[], const char *use) 2958 { 2959 boolean_t L_arg = B_FALSE; 2960 boolean_t s_arg = B_FALSE; 2961 boolean_t i_arg = B_FALSE; 2962 boolean_t p_arg = B_FALSE; 2963 boolean_t x_arg = B_FALSE; 2964 show_grp_state_t state; 2965 uint32_t flags = DLADM_OPT_ACTIVE; 2966 datalink_id_t linkid = DATALINK_ALL_LINKID; 2967 int option; 2968 uint32_t interval = 0; 2969 int key; 2970 dladm_status_t status; 2971 boolean_t o_arg = B_FALSE; 2972 char *fields_str = NULL; 2973 char *all_fields = 2974 "link,policy,addrpolicy,lacpactivity,lacptimer,flags"; 2975 char *all_lacp_fields = 2976 "link,port,aggregatable,sync,coll,dist,defaulted,expired"; 2977 char *all_stats_fields = 2978 "link,port,ipackets,rbytes,opackets,obytes,ipktdist,opktdist"; 2979 char *all_extended_fields = 2980 "link,port,speed,duplex,state,address,portstate"; 2981 ofmt_field_t *pf; 2982 ofmt_handle_t ofmt; 2983 ofmt_status_t oferr; 2984 uint_t ofmtflags = 0; 2985 2986 opterr = 0; 2987 while ((option = getopt_long(argc, argv, ":LpPxsi:o:", 2988 show_lopts, NULL)) != -1) { 2989 switch (option) { 2990 case 'L': 2991 if (L_arg) 2992 die_optdup(option); 2993 2994 L_arg = B_TRUE; 2995 break; 2996 case 'p': 2997 if (p_arg) 2998 die_optdup(option); 2999 3000 p_arg = B_TRUE; 3001 break; 3002 case 'x': 3003 if (x_arg) 3004 die_optdup(option); 3005 3006 x_arg = B_TRUE; 3007 break; 3008 case 'P': 3009 if (flags != DLADM_OPT_ACTIVE) 3010 die_optdup(option); 3011 3012 flags = DLADM_OPT_PERSIST; 3013 break; 3014 case 's': 3015 if (s_arg) 3016 die_optdup(option); 3017 3018 s_arg = B_TRUE; 3019 break; 3020 case 'o': 3021 o_arg = B_TRUE; 3022 fields_str = optarg; 3023 break; 3024 case 'i': 3025 if (i_arg) 3026 die_optdup(option); 3027 3028 i_arg = B_TRUE; 3029 if (!dladm_str2interval(optarg, &interval)) 3030 die("invalid interval value '%s'", optarg); 3031 break; 3032 default: 3033 die_opterr(optopt, option, use); 3034 break; 3035 } 3036 } 3037 3038 if (p_arg && !o_arg) 3039 die("-p requires -o"); 3040 3041 if (p_arg && strcasecmp(fields_str, "all") == 0) 3042 die("\"-o all\" is invalid with -p"); 3043 3044 if (i_arg && !s_arg) 3045 die("the option -i can be used only with -s"); 3046 3047 if (s_arg && (L_arg || p_arg || x_arg || flags != DLADM_OPT_ACTIVE)) { 3048 die("the option -%c cannot be used with -s", 3049 L_arg ? 'L' : (p_arg ? 'p' : (x_arg ? 'x' : 'P'))); 3050 } 3051 3052 if (L_arg && flags != DLADM_OPT_ACTIVE) 3053 die("the option -P cannot be used with -L"); 3054 3055 if (x_arg && (L_arg || flags != DLADM_OPT_ACTIVE)) 3056 die("the option -%c cannot be used with -x", L_arg ? 'L' : 'P'); 3057 3058 /* get aggregation key or aggrname (optional last argument) */ 3059 if (optind == (argc-1)) { 3060 if (!str2int(argv[optind], &key)) { 3061 status = dladm_name2info(handle, argv[optind], 3062 &linkid, NULL, NULL, NULL); 3063 } else { 3064 status = dladm_key2linkid(handle, (uint16_t)key, 3065 &linkid, DLADM_OPT_ACTIVE); 3066 } 3067 3068 if (status != DLADM_STATUS_OK) 3069 die("non-existent aggregation '%s'", argv[optind]); 3070 3071 } else if (optind != argc) { 3072 usage(); 3073 } 3074 3075 bzero(&state, sizeof (state)); 3076 state.gs_lacp = L_arg; 3077 state.gs_stats = s_arg; 3078 state.gs_flags = flags; 3079 state.gs_parsable = p_arg; 3080 state.gs_extended = x_arg; 3081 3082 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) { 3083 if (state.gs_lacp) 3084 fields_str = all_lacp_fields; 3085 else if (state.gs_stats) 3086 fields_str = all_stats_fields; 3087 else if (state.gs_extended) 3088 fields_str = all_extended_fields; 3089 else 3090 fields_str = all_fields; 3091 } 3092 3093 if (state.gs_lacp) { 3094 pf = aggr_l_fields; 3095 } else if (state.gs_stats) { 3096 pf = aggr_s_fields; 3097 } else if (state.gs_extended) { 3098 pf = aggr_x_fields; 3099 } else { 3100 pf = laggr_fields; 3101 } 3102 3103 if (state.gs_parsable) 3104 ofmtflags |= OFMT_PARSABLE; 3105 oferr = ofmt_open(fields_str, pf, ofmtflags, 0, &ofmt); 3106 dladm_ofmt_check(oferr, state.gs_parsable, ofmt); 3107 state.gs_ofmt = ofmt; 3108 3109 if (s_arg) { 3110 aggr_stats(linkid, &state, interval); 3111 ofmt_close(ofmt); 3112 return; 3113 } 3114 3115 if (linkid == DATALINK_ALL_LINKID) { 3116 (void) dladm_walk_datalink_id(show_aggr, handle, &state, 3117 DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, flags); 3118 } else { 3119 (void) show_aggr(handle, linkid, &state); 3120 if (state.gs_status != DLADM_STATUS_OK) { 3121 die_dlerr(state.gs_status, "failed to show aggr %s", 3122 argv[optind]); 3123 } 3124 } 3125 ofmt_close(ofmt); 3126 } 3127 3128 static dladm_status_t 3129 print_phys_default(show_state_t *state, datalink_id_t linkid, 3130 const char *link, uint32_t flags, uint32_t media) 3131 { 3132 dladm_phys_attr_t dpa; 3133 dladm_status_t status; 3134 link_fields_buf_t pattr; 3135 3136 status = dladm_phys_info(handle, linkid, &dpa, state->ls_flags); 3137 if (status != DLADM_STATUS_OK) 3138 goto done; 3139 3140 (void) snprintf(pattr.link_phys_device, 3141 sizeof (pattr.link_phys_device), "%s", dpa.dp_dev); 3142 (void) dladm_media2str(media, pattr.link_phys_media); 3143 if (state->ls_flags == DLADM_OPT_ACTIVE) { 3144 boolean_t islink; 3145 3146 if (!dpa.dp_novanity) { 3147 (void) strlcpy(pattr.link_name, link, 3148 sizeof (pattr.link_name)); 3149 islink = B_TRUE; 3150 } else { 3151 /* 3152 * This is a physical link that does not have 3153 * vanity naming support. 3154 */ 3155 (void) strlcpy(pattr.link_name, dpa.dp_dev, 3156 sizeof (pattr.link_name)); 3157 islink = B_FALSE; 3158 } 3159 3160 (void) get_linkstate(pattr.link_name, islink, 3161 pattr.link_phys_state); 3162 (void) snprintf(pattr.link_phys_speed, 3163 sizeof (pattr.link_phys_speed), "%u", 3164 (uint_t)((get_ifspeed(pattr.link_name, 3165 islink)) / 1000000ull)); 3166 (void) get_linkduplex(pattr.link_name, islink, 3167 pattr.link_phys_duplex); 3168 } else { 3169 (void) snprintf(pattr.link_name, sizeof (pattr.link_name), 3170 "%s", link); 3171 (void) snprintf(pattr.link_flags, sizeof (pattr.link_flags), 3172 "%c----", flags & DLADM_OPT_ACTIVE ? '-' : 'r'); 3173 } 3174 3175 ofmt_print(state->ls_ofmt, &pattr); 3176 3177 done: 3178 return (status); 3179 } 3180 3181 typedef struct { 3182 show_state_t *ms_state; 3183 char *ms_link; 3184 dladm_macaddr_attr_t *ms_mac_attr; 3185 } print_phys_mac_state_t; 3186 3187 /* 3188 * callback for ofmt_print() 3189 */ 3190 static boolean_t 3191 print_phys_one_mac_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 3192 { 3193 print_phys_mac_state_t *mac_state = ofarg->ofmt_cbarg; 3194 dladm_macaddr_attr_t *attr = mac_state->ms_mac_attr; 3195 boolean_t is_primary = (attr->ma_slot == 0); 3196 boolean_t is_parsable = mac_state->ms_state->ls_parsable; 3197 3198 switch (ofarg->ofmt_id) { 3199 case PHYS_M_LINK: 3200 (void) snprintf(buf, bufsize, "%s", 3201 (is_primary || is_parsable) ? mac_state->ms_link : " "); 3202 break; 3203 case PHYS_M_SLOT: 3204 if (is_primary) 3205 (void) snprintf(buf, bufsize, gettext("primary")); 3206 else 3207 (void) snprintf(buf, bufsize, "%d", attr->ma_slot); 3208 break; 3209 case PHYS_M_ADDRESS: 3210 (void) dladm_aggr_macaddr2str(attr->ma_addr, buf); 3211 break; 3212 case PHYS_M_INUSE: 3213 (void) snprintf(buf, bufsize, "%s", 3214 attr->ma_flags & DLADM_MACADDR_USED ? gettext("yes") : 3215 gettext("no")); 3216 break; 3217 case PHYS_M_CLIENT: 3218 /* 3219 * CR 6678526: resolve link id to actual link name if 3220 * it is valid. 3221 */ 3222 (void) snprintf(buf, bufsize, "%s", attr->ma_client_name); 3223 break; 3224 } 3225 3226 return (B_TRUE); 3227 } 3228 3229 typedef struct { 3230 show_state_t *hs_state; 3231 char *hs_link; 3232 dladm_hwgrp_attr_t *hs_grp_attr; 3233 } print_phys_hwgrp_state_t; 3234 3235 static boolean_t 3236 print_phys_one_hwgrp_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 3237 { 3238 print_phys_hwgrp_state_t *hg_state = ofarg->ofmt_cbarg; 3239 dladm_hwgrp_attr_t *attr = hg_state->hs_grp_attr; 3240 3241 switch (ofarg->ofmt_id) { 3242 case PHYS_H_LINK: 3243 (void) snprintf(buf, bufsize, "%s", attr->hg_link_name); 3244 break; 3245 case PHYS_H_GROUP: 3246 (void) snprintf(buf, bufsize, "%d", attr->hg_grp_num); 3247 break; 3248 case PHYS_H_GRPTYPE: 3249 (void) snprintf(buf, bufsize, "%s", 3250 attr->hg_grp_type == DLADM_HWGRP_TYPE_RX ? "RX" : "TX"); 3251 break; 3252 case PHYS_H_RINGS: 3253 (void) snprintf(buf, bufsize, "%d", attr->hg_n_rings); 3254 break; 3255 case PHYS_H_CLIENTS: 3256 if (attr->hg_client_names[0] == '\0') { 3257 (void) snprintf(buf, bufsize, "--"); 3258 } else { 3259 (void) snprintf(buf, bufsize, "%s ", 3260 attr->hg_client_names); 3261 } 3262 break; 3263 } 3264 3265 return (B_TRUE); 3266 } 3267 3268 /* 3269 * callback for dladm_walk_macaddr, invoked for each MAC address slot 3270 */ 3271 static boolean_t 3272 print_phys_mac_callback(void *arg, dladm_macaddr_attr_t *attr) 3273 { 3274 print_phys_mac_state_t *mac_state = arg; 3275 show_state_t *state = mac_state->ms_state; 3276 3277 mac_state->ms_mac_attr = attr; 3278 ofmt_print(state->ls_ofmt, mac_state); 3279 3280 return (B_TRUE); 3281 } 3282 3283 /* 3284 * invoked by show-phys -m for each physical data-link 3285 */ 3286 static dladm_status_t 3287 print_phys_mac(show_state_t *state, datalink_id_t linkid, char *link) 3288 { 3289 print_phys_mac_state_t mac_state; 3290 3291 mac_state.ms_state = state; 3292 mac_state.ms_link = link; 3293 3294 return (dladm_walk_macaddr(handle, linkid, &mac_state, 3295 print_phys_mac_callback)); 3296 } 3297 3298 /* 3299 * callback for dladm_walk_hwgrp, invoked for each MAC hwgrp 3300 */ 3301 static boolean_t 3302 print_phys_hwgrp_callback(void *arg, dladm_hwgrp_attr_t *attr) 3303 { 3304 print_phys_hwgrp_state_t *hwgrp_state = arg; 3305 show_state_t *state = hwgrp_state->hs_state; 3306 3307 hwgrp_state->hs_grp_attr = attr; 3308 ofmt_print(state->ls_ofmt, hwgrp_state); 3309 3310 return (B_TRUE); 3311 } 3312 3313 /* invoked by show-phys -H for each physical data-link */ 3314 static dladm_status_t 3315 print_phys_hwgrp(show_state_t *state, datalink_id_t linkid, char *link) 3316 { 3317 print_phys_hwgrp_state_t hwgrp_state; 3318 3319 hwgrp_state.hs_state = state; 3320 hwgrp_state.hs_link = link; 3321 return (dladm_walk_hwgrp(handle, linkid, &hwgrp_state, 3322 print_phys_hwgrp_callback)); 3323 } 3324 3325 static dladm_status_t 3326 print_phys(show_state_t *state, datalink_id_t linkid) 3327 { 3328 char link[MAXLINKNAMELEN]; 3329 uint32_t flags; 3330 dladm_status_t status; 3331 datalink_class_t class; 3332 uint32_t media; 3333 3334 if ((status = dladm_datalink_id2info(handle, linkid, &flags, &class, 3335 &media, link, MAXLINKNAMELEN)) != DLADM_STATUS_OK) { 3336 goto done; 3337 } 3338 3339 if (class != DATALINK_CLASS_PHYS) { 3340 status = DLADM_STATUS_BADARG; 3341 goto done; 3342 } 3343 3344 if (!(state->ls_flags & flags)) { 3345 status = DLADM_STATUS_NOTFOUND; 3346 goto done; 3347 } 3348 3349 if (state->ls_mac) 3350 status = print_phys_mac(state, linkid, link); 3351 else if (state->ls_hwgrp) 3352 status = print_phys_hwgrp(state, linkid, link); 3353 else 3354 status = print_phys_default(state, linkid, link, flags, media); 3355 3356 done: 3357 return (status); 3358 } 3359 3360 /* ARGSUSED */ 3361 static int 3362 show_phys(dladm_handle_t dh, datalink_id_t linkid, void *arg) 3363 { 3364 show_state_t *state = arg; 3365 3366 state->ls_status = print_phys(state, linkid); 3367 return (DLADM_WALK_CONTINUE); 3368 } 3369 3370 /* 3371 * Print the active topology information. 3372 */ 3373 static dladm_status_t 3374 print_vlan(show_state_t *state, datalink_id_t linkid, link_fields_buf_t *l) 3375 { 3376 dladm_vlan_attr_t vinfo; 3377 uint32_t flags; 3378 dladm_status_t status; 3379 3380 if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL, NULL, 3381 l->link_name, sizeof (l->link_name))) != DLADM_STATUS_OK) { 3382 goto done; 3383 } 3384 3385 if (!(state->ls_flags & flags)) { 3386 status = DLADM_STATUS_NOTFOUND; 3387 goto done; 3388 } 3389 3390 if ((status = dladm_vlan_info(handle, linkid, &vinfo, 3391 state->ls_flags)) != DLADM_STATUS_OK || 3392 (status = dladm_datalink_id2info(handle, vinfo.dv_linkid, NULL, 3393 NULL, NULL, l->link_over, sizeof (l->link_over))) != 3394 DLADM_STATUS_OK) { 3395 goto done; 3396 } 3397 3398 (void) snprintf(l->link_vlan_vid, sizeof (l->link_vlan_vid), "%d", 3399 vinfo.dv_vid); 3400 (void) snprintf(l->link_flags, sizeof (l->link_flags), "%c----", 3401 vinfo.dv_force ? 'f' : '-'); 3402 3403 done: 3404 return (status); 3405 } 3406 3407 /* ARGSUSED */ 3408 static int 3409 show_vlan(dladm_handle_t dh, datalink_id_t linkid, void *arg) 3410 { 3411 show_state_t *state = arg; 3412 dladm_status_t status; 3413 link_fields_buf_t lbuf; 3414 3415 bzero(&lbuf, sizeof (link_fields_buf_t)); 3416 status = print_vlan(state, linkid, &lbuf); 3417 if (status != DLADM_STATUS_OK) 3418 goto done; 3419 3420 ofmt_print(state->ls_ofmt, &lbuf); 3421 3422 done: 3423 state->ls_status = status; 3424 return (DLADM_WALK_CONTINUE); 3425 } 3426 3427 static void 3428 do_show_phys(int argc, char *argv[], const char *use) 3429 { 3430 int option; 3431 uint32_t flags = DLADM_OPT_ACTIVE; 3432 boolean_t p_arg = B_FALSE; 3433 boolean_t o_arg = B_FALSE; 3434 boolean_t m_arg = B_FALSE; 3435 boolean_t H_arg = B_FALSE; 3436 datalink_id_t linkid = DATALINK_ALL_LINKID; 3437 show_state_t state; 3438 dladm_status_t status; 3439 char *fields_str = NULL; 3440 char *all_active_fields = 3441 "link,media,state,speed,duplex,device"; 3442 char *all_inactive_fields = "link,device,media,flags"; 3443 char *all_mac_fields = "link,slot,address,inuse,client"; 3444 char *all_hwgrp_fields = 3445 "link,group,grouptype,rings,clients"; 3446 ofmt_field_t *pf; 3447 ofmt_handle_t ofmt; 3448 ofmt_status_t oferr; 3449 uint_t ofmtflags = 0; 3450 3451 bzero(&state, sizeof (state)); 3452 opterr = 0; 3453 while ((option = getopt_long(argc, argv, ":pPo:mH", 3454 show_lopts, NULL)) != -1) { 3455 switch (option) { 3456 case 'p': 3457 if (p_arg) 3458 die_optdup(option); 3459 3460 p_arg = B_TRUE; 3461 break; 3462 case 'P': 3463 if (flags != DLADM_OPT_ACTIVE) 3464 die_optdup(option); 3465 3466 flags = DLADM_OPT_PERSIST; 3467 break; 3468 case 'o': 3469 o_arg = B_TRUE; 3470 fields_str = optarg; 3471 break; 3472 case 'm': 3473 m_arg = B_TRUE; 3474 break; 3475 case 'H': 3476 H_arg = B_TRUE; 3477 break; 3478 default: 3479 die_opterr(optopt, option, use); 3480 break; 3481 } 3482 } 3483 3484 if (p_arg && !o_arg) 3485 die("-p requires -o"); 3486 3487 if (m_arg && H_arg) 3488 die("-m cannot combine with -H"); 3489 3490 if (p_arg && strcasecmp(fields_str, "all") == 0) 3491 die("\"-o all\" is invalid with -p"); 3492 3493 /* get link name (optional last argument) */ 3494 if (optind == (argc-1)) { 3495 if ((status = dladm_name2info(handle, argv[optind], &linkid, 3496 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 3497 die_dlerr(status, "link %s is not valid", argv[optind]); 3498 } 3499 } else if (optind != argc) { 3500 usage(); 3501 } 3502 3503 state.ls_parsable = p_arg; 3504 state.ls_flags = flags; 3505 state.ls_donefirst = B_FALSE; 3506 state.ls_mac = m_arg; 3507 state.ls_hwgrp = H_arg; 3508 3509 if (m_arg && !(flags & DLADM_OPT_ACTIVE)) { 3510 /* 3511 * We can only display the factory MAC addresses of 3512 * active data-links. 3513 */ 3514 die("-m not compatible with -P"); 3515 } 3516 3517 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) { 3518 if (state.ls_mac) 3519 fields_str = all_mac_fields; 3520 else if (state.ls_hwgrp) 3521 fields_str = all_hwgrp_fields; 3522 else if (state.ls_flags & DLADM_OPT_ACTIVE) { 3523 fields_str = all_active_fields; 3524 } else { 3525 fields_str = all_inactive_fields; 3526 } 3527 } 3528 3529 if (state.ls_mac) { 3530 pf = phys_m_fields; 3531 } else if (state.ls_hwgrp) { 3532 pf = phys_h_fields; 3533 } else { 3534 pf = phys_fields; 3535 } 3536 3537 if (state.ls_parsable) 3538 ofmtflags |= OFMT_PARSABLE; 3539 oferr = ofmt_open(fields_str, pf, ofmtflags, 0, &ofmt); 3540 dladm_ofmt_check(oferr, state.ls_parsable, ofmt); 3541 state.ls_ofmt = ofmt; 3542 3543 if (linkid == DATALINK_ALL_LINKID) { 3544 (void) dladm_walk_datalink_id(show_phys, handle, &state, 3545 DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, flags); 3546 } else { 3547 (void) show_phys(handle, linkid, &state); 3548 if (state.ls_status != DLADM_STATUS_OK) { 3549 die_dlerr(state.ls_status, 3550 "failed to show physical link %s", argv[optind]); 3551 } 3552 } 3553 ofmt_close(ofmt); 3554 } 3555 3556 static void 3557 do_show_vlan(int argc, char *argv[], const char *use) 3558 { 3559 int option; 3560 uint32_t flags = DLADM_OPT_ACTIVE; 3561 boolean_t p_arg = B_FALSE; 3562 datalink_id_t linkid = DATALINK_ALL_LINKID; 3563 show_state_t state; 3564 dladm_status_t status; 3565 boolean_t o_arg = B_FALSE; 3566 char *fields_str = NULL; 3567 ofmt_handle_t ofmt; 3568 ofmt_status_t oferr; 3569 uint_t ofmtflags = 0; 3570 3571 bzero(&state, sizeof (state)); 3572 3573 opterr = 0; 3574 while ((option = getopt_long(argc, argv, ":pPo:", 3575 show_lopts, NULL)) != -1) { 3576 switch (option) { 3577 case 'p': 3578 if (p_arg) 3579 die_optdup(option); 3580 3581 p_arg = B_TRUE; 3582 break; 3583 case 'P': 3584 if (flags != DLADM_OPT_ACTIVE) 3585 die_optdup(option); 3586 3587 flags = DLADM_OPT_PERSIST; 3588 break; 3589 case 'o': 3590 o_arg = B_TRUE; 3591 fields_str = optarg; 3592 break; 3593 default: 3594 die_opterr(optopt, option, use); 3595 break; 3596 } 3597 } 3598 3599 /* get link name (optional last argument) */ 3600 if (optind == (argc-1)) { 3601 if ((status = dladm_name2info(handle, argv[optind], &linkid, 3602 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 3603 die_dlerr(status, "link %s is not valid", argv[optind]); 3604 } 3605 } else if (optind != argc) { 3606 usage(); 3607 } 3608 3609 state.ls_parsable = p_arg; 3610 state.ls_flags = flags; 3611 state.ls_donefirst = B_FALSE; 3612 3613 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) 3614 fields_str = NULL; 3615 3616 if (state.ls_parsable) 3617 ofmtflags |= OFMT_PARSABLE; 3618 oferr = ofmt_open(fields_str, vlan_fields, ofmtflags, 0, &ofmt); 3619 dladm_ofmt_check(oferr, state.ls_parsable, ofmt); 3620 state.ls_ofmt = ofmt; 3621 3622 if (linkid == DATALINK_ALL_LINKID) { 3623 (void) dladm_walk_datalink_id(show_vlan, handle, &state, 3624 DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, flags); 3625 } else { 3626 (void) show_vlan(handle, linkid, &state); 3627 if (state.ls_status != DLADM_STATUS_OK) { 3628 die_dlerr(state.ls_status, "failed to show vlan %s", 3629 argv[optind]); 3630 } 3631 } 3632 ofmt_close(ofmt); 3633 } 3634 3635 static void 3636 do_create_vnic(int argc, char *argv[], const char *use) 3637 { 3638 datalink_id_t linkid, dev_linkid; 3639 char devname[MAXLINKNAMELEN]; 3640 char name[MAXLINKNAMELEN]; 3641 boolean_t l_arg = B_FALSE; 3642 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 3643 char *altroot = NULL; 3644 char option; 3645 char *endp = NULL; 3646 dladm_status_t status; 3647 vnic_mac_addr_type_t mac_addr_type = VNIC_MAC_ADDR_TYPE_AUTO; 3648 uchar_t *mac_addr; 3649 int mac_slot = -1, maclen = 0, mac_prefix_len = 0; 3650 char propstr[DLADM_STRSIZE]; 3651 dladm_arg_list_t *proplist = NULL; 3652 int vid = 0; 3653 3654 opterr = 0; 3655 bzero(propstr, DLADM_STRSIZE); 3656 3657 while ((option = getopt_long(argc, argv, ":tfR:l:m:n:p:r:v:H", 3658 vnic_lopts, NULL)) != -1) { 3659 switch (option) { 3660 case 't': 3661 flags &= ~DLADM_OPT_PERSIST; 3662 break; 3663 case 'R': 3664 altroot = optarg; 3665 break; 3666 case 'l': 3667 if (strlcpy(devname, optarg, MAXLINKNAMELEN) >= 3668 MAXLINKNAMELEN) 3669 die("link name too long"); 3670 l_arg = B_TRUE; 3671 break; 3672 case 'm': 3673 if (strcmp(optarg, "fixed") == 0) { 3674 /* 3675 * A fixed MAC address must be specified 3676 * by its value, not by the keyword 'fixed'. 3677 */ 3678 die("'fixed' is not a valid MAC address"); 3679 } 3680 if (dladm_vnic_str2macaddrtype(optarg, 3681 &mac_addr_type) != DLADM_STATUS_OK) { 3682 mac_addr_type = VNIC_MAC_ADDR_TYPE_FIXED; 3683 /* MAC address specified by value */ 3684 mac_addr = _link_aton(optarg, &maclen); 3685 if (mac_addr == NULL) { 3686 if (maclen == -1) 3687 die("invalid MAC address"); 3688 else 3689 die("out of memory"); 3690 } 3691 } 3692 break; 3693 case 'n': 3694 errno = 0; 3695 mac_slot = (int)strtol(optarg, &endp, 10); 3696 if (errno != 0 || *endp != '\0') 3697 die("invalid slot number"); 3698 break; 3699 case 'p': 3700 (void) strlcat(propstr, optarg, DLADM_STRSIZE); 3701 if (strlcat(propstr, ",", DLADM_STRSIZE) >= 3702 DLADM_STRSIZE) 3703 die("property list too long '%s'", propstr); 3704 break; 3705 case 'r': 3706 mac_addr = _link_aton(optarg, &mac_prefix_len); 3707 if (mac_addr == NULL) { 3708 if (mac_prefix_len == -1) 3709 die("invalid MAC address"); 3710 else 3711 die("out of memory"); 3712 } 3713 break; 3714 case 'v': 3715 if (vid != 0) 3716 die_optdup(option); 3717 3718 if (!str2int(optarg, &vid) || vid < 1 || vid > 4094) 3719 die("invalid VLAN identifier '%s'", optarg); 3720 3721 break; 3722 case 'f': 3723 flags |= DLADM_OPT_FORCE; 3724 break; 3725 case 'H': 3726 flags |= DLADM_OPT_HWRINGS; 3727 break; 3728 default: 3729 die_opterr(optopt, option, use); 3730 } 3731 } 3732 3733 /* 3734 * 'f' - force, flag can be specified only with 'v' - vlan. 3735 */ 3736 if ((flags & DLADM_OPT_FORCE) != 0 && vid == 0) 3737 die("-f option can only be used with -v"); 3738 3739 if (mac_prefix_len != 0 && mac_addr_type != VNIC_MAC_ADDR_TYPE_RANDOM && 3740 mac_addr_type != VNIC_MAC_ADDR_TYPE_FIXED) 3741 usage(); 3742 3743 /* check required options */ 3744 if (!l_arg) 3745 usage(); 3746 3747 if (mac_slot != -1 && mac_addr_type != VNIC_MAC_ADDR_TYPE_FACTORY) 3748 usage(); 3749 3750 /* the VNIC id is the required operand */ 3751 if (optind != (argc - 1)) 3752 usage(); 3753 3754 if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= MAXLINKNAMELEN) 3755 die("link name too long '%s'", argv[optind]); 3756 3757 if (!dladm_valid_linkname(name)) 3758 die("invalid link name '%s'", argv[optind]); 3759 3760 if (altroot != NULL) 3761 altroot_cmd(altroot, argc, argv); 3762 3763 if (dladm_name2info(handle, devname, &dev_linkid, NULL, NULL, NULL) != 3764 DLADM_STATUS_OK) 3765 die("invalid link name '%s'", devname); 3766 3767 if (dladm_parse_link_props(propstr, &proplist, B_FALSE) 3768 != DLADM_STATUS_OK) 3769 die("invalid vnic property"); 3770 3771 status = dladm_vnic_create(handle, name, dev_linkid, mac_addr_type, 3772 mac_addr, maclen, &mac_slot, mac_prefix_len, vid, &linkid, proplist, 3773 flags); 3774 if (status != DLADM_STATUS_OK) 3775 die_dlerr(status, "vnic creation over %s failed", devname); 3776 3777 dladm_free_props(proplist); 3778 } 3779 3780 static void 3781 do_etherstub_check(const char *name, datalink_id_t linkid, boolean_t etherstub, 3782 uint32_t flags) 3783 { 3784 boolean_t is_etherstub; 3785 dladm_vnic_attr_t attr; 3786 3787 if (dladm_vnic_info(handle, linkid, &attr, flags) != DLADM_STATUS_OK) { 3788 /* 3789 * Let the delete continue anyway. 3790 */ 3791 return; 3792 } 3793 is_etherstub = (attr.va_link_id == DATALINK_INVALID_LINKID); 3794 if (is_etherstub != etherstub) { 3795 die("'%s' is not %s", name, 3796 (is_etherstub ? "a vnic" : "an etherstub")); 3797 } 3798 } 3799 3800 static void 3801 do_delete_vnic_common(int argc, char *argv[], const char *use, 3802 boolean_t etherstub) 3803 { 3804 char option; 3805 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 3806 datalink_id_t linkid; 3807 char *altroot = NULL; 3808 dladm_status_t status; 3809 3810 opterr = 0; 3811 while ((option = getopt_long(argc, argv, ":R:t", lopts, 3812 NULL)) != -1) { 3813 switch (option) { 3814 case 't': 3815 flags &= ~DLADM_OPT_PERSIST; 3816 break; 3817 case 'R': 3818 altroot = optarg; 3819 break; 3820 default: 3821 die_opterr(optopt, option, use); 3822 } 3823 } 3824 3825 /* get vnic name (required last argument) */ 3826 if (optind != (argc - 1)) 3827 usage(); 3828 3829 if (altroot != NULL) 3830 altroot_cmd(altroot, argc, argv); 3831 3832 status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL, 3833 NULL); 3834 if (status != DLADM_STATUS_OK) 3835 die("invalid link name '%s'", argv[optind]); 3836 3837 if ((flags & DLADM_OPT_ACTIVE) != 0) { 3838 do_etherstub_check(argv[optind], linkid, etherstub, 3839 DLADM_OPT_ACTIVE); 3840 } 3841 if ((flags & DLADM_OPT_PERSIST) != 0) { 3842 do_etherstub_check(argv[optind], linkid, etherstub, 3843 DLADM_OPT_PERSIST); 3844 } 3845 3846 status = dladm_vnic_delete(handle, linkid, flags); 3847 if (status != DLADM_STATUS_OK) 3848 die_dlerr(status, "vnic deletion failed"); 3849 } 3850 3851 static void 3852 do_delete_vnic(int argc, char *argv[], const char *use) 3853 { 3854 do_delete_vnic_common(argc, argv, use, B_FALSE); 3855 } 3856 3857 /* ARGSUSED */ 3858 static void 3859 do_up_vnic_common(int argc, char *argv[], const char *use, boolean_t vlan) 3860 { 3861 datalink_id_t linkid = DATALINK_ALL_LINKID; 3862 dladm_status_t status; 3863 char *type; 3864 3865 type = vlan ? "vlan" : "vnic"; 3866 3867 /* 3868 * get the id or the name of the vnic/vlan (optional last argument) 3869 */ 3870 if (argc == 2) { 3871 status = dladm_name2info(handle, argv[1], &linkid, NULL, NULL, 3872 NULL); 3873 if (status != DLADM_STATUS_OK) 3874 goto done; 3875 3876 } else if (argc > 2) { 3877 usage(); 3878 } 3879 3880 if (vlan) 3881 status = dladm_vlan_up(handle, linkid); 3882 else 3883 status = dladm_vnic_up(handle, linkid, 0); 3884 3885 done: 3886 if (status != DLADM_STATUS_OK) { 3887 if (argc == 2) { 3888 die_dlerr(status, 3889 "could not bring up %s '%s'", type, argv[1]); 3890 } else { 3891 die_dlerr(status, "could not bring %ss up", type); 3892 } 3893 } 3894 } 3895 3896 static void 3897 do_up_vnic(int argc, char *argv[], const char *use) 3898 { 3899 do_up_vnic_common(argc, argv, use, B_FALSE); 3900 } 3901 3902 static void 3903 dump_vnics_head(const char *dev) 3904 { 3905 if (strlen(dev)) 3906 (void) printf("%s", dev); 3907 3908 (void) printf("\tipackets rbytes opackets obytes "); 3909 3910 if (strlen(dev)) 3911 (void) printf("%%ipkts %%opkts\n"); 3912 else 3913 (void) printf("\n"); 3914 } 3915 3916 static void 3917 dump_vnic_stat(const char *name, datalink_id_t vnic_id, 3918 show_vnic_state_t *state, pktsum_t *vnic_stats, pktsum_t *tot_stats) 3919 { 3920 pktsum_t diff_stats; 3921 pktsum_t *old_stats = &state->vs_prevstats[vnic_id]; 3922 3923 dladm_stats_diff(&diff_stats, vnic_stats, old_stats); 3924 3925 (void) printf("%s", name); 3926 3927 (void) printf("\t%-10llu", diff_stats.ipackets); 3928 (void) printf("%-12llu", diff_stats.rbytes); 3929 (void) printf("%-10llu", diff_stats.opackets); 3930 (void) printf("%-12llu", diff_stats.obytes); 3931 3932 if (tot_stats) { 3933 if (tot_stats->ipackets == 0) { 3934 (void) printf("\t-"); 3935 } else { 3936 (void) printf("\t%-6.1f", (double)diff_stats.ipackets/ 3937 (double)tot_stats->ipackets * 100); 3938 } 3939 if (tot_stats->opackets == 0) { 3940 (void) printf("\t-"); 3941 } else { 3942 (void) printf("\t%-6.1f", (double)diff_stats.opackets/ 3943 (double)tot_stats->opackets * 100); 3944 } 3945 } 3946 (void) printf("\n"); 3947 3948 *old_stats = *vnic_stats; 3949 } 3950 3951 /* 3952 * Called from the walker dladm_vnic_walk_sys() for each vnic to display 3953 * vnic information or statistics. 3954 */ 3955 static dladm_status_t 3956 print_vnic(show_vnic_state_t *state, datalink_id_t linkid) 3957 { 3958 dladm_vnic_attr_t attr, *vnic = &attr; 3959 dladm_status_t status; 3960 boolean_t is_etherstub; 3961 char devname[MAXLINKNAMELEN]; 3962 char vnic_name[MAXLINKNAMELEN]; 3963 char mstr[MAXMACADDRLEN * 3]; 3964 vnic_fields_buf_t vbuf; 3965 3966 if ((status = dladm_vnic_info(handle, linkid, vnic, state->vs_flags)) != 3967 DLADM_STATUS_OK) 3968 return (status); 3969 3970 is_etherstub = (vnic->va_link_id == DATALINK_INVALID_LINKID); 3971 if (state->vs_etherstub != is_etherstub) { 3972 /* 3973 * Want all etherstub but it's not one, or want 3974 * non-etherstub and it's one. 3975 */ 3976 return (DLADM_STATUS_OK); 3977 } 3978 3979 if (state->vs_link_id != DATALINK_ALL_LINKID) { 3980 if (state->vs_link_id != vnic->va_link_id) 3981 return (DLADM_STATUS_OK); 3982 } 3983 3984 if (dladm_datalink_id2info(handle, linkid, NULL, NULL, 3985 NULL, vnic_name, sizeof (vnic_name)) != DLADM_STATUS_OK) 3986 return (DLADM_STATUS_BADARG); 3987 3988 bzero(devname, sizeof (devname)); 3989 if (!is_etherstub && 3990 dladm_datalink_id2info(handle, vnic->va_link_id, NULL, NULL, 3991 NULL, devname, sizeof (devname)) != DLADM_STATUS_OK) 3992 return (DLADM_STATUS_BADARG); 3993 3994 state->vs_found = B_TRUE; 3995 if (state->vs_stats) { 3996 /* print vnic statistics */ 3997 pktsum_t vnic_stats; 3998 3999 if (state->vs_firstonly) { 4000 if (state->vs_donefirst) 4001 return (0); 4002 state->vs_donefirst = B_TRUE; 4003 } 4004 4005 if (!state->vs_printstats) { 4006 /* 4007 * get vnic statistics and add to the sum for the 4008 * named device. 4009 */ 4010 get_link_stats(vnic_name, &vnic_stats); 4011 dladm_stats_total(&state->vs_totalstats, &vnic_stats, 4012 &state->vs_prevstats[vnic->va_vnic_id]); 4013 } else { 4014 /* get and print vnic statistics */ 4015 get_link_stats(vnic_name, &vnic_stats); 4016 dump_vnic_stat(vnic_name, linkid, state, &vnic_stats, 4017 &state->vs_totalstats); 4018 } 4019 return (DLADM_STATUS_OK); 4020 } else { 4021 (void) snprintf(vbuf.vnic_link, sizeof (vbuf.vnic_link), 4022 "%s", vnic_name); 4023 4024 if (!is_etherstub) { 4025 4026 (void) snprintf(vbuf.vnic_over, sizeof (vbuf.vnic_over), 4027 "%s", devname); 4028 (void) snprintf(vbuf.vnic_speed, 4029 sizeof (vbuf.vnic_speed), "%u", 4030 (uint_t)((get_ifspeed(vnic_name, B_TRUE)) 4031 / 1000000ull)); 4032 4033 switch (vnic->va_mac_addr_type) { 4034 case VNIC_MAC_ADDR_TYPE_FIXED: 4035 case VNIC_MAC_ADDR_TYPE_PRIMARY: 4036 (void) snprintf(vbuf.vnic_macaddrtype, 4037 sizeof (vbuf.vnic_macaddrtype), 4038 gettext("fixed")); 4039 break; 4040 case VNIC_MAC_ADDR_TYPE_RANDOM: 4041 (void) snprintf(vbuf.vnic_macaddrtype, 4042 sizeof (vbuf.vnic_macaddrtype), 4043 gettext("random")); 4044 break; 4045 case VNIC_MAC_ADDR_TYPE_FACTORY: 4046 (void) snprintf(vbuf.vnic_macaddrtype, 4047 sizeof (vbuf.vnic_macaddrtype), 4048 gettext("factory, slot %d"), 4049 vnic->va_mac_slot); 4050 break; 4051 } 4052 4053 if (strlen(vbuf.vnic_macaddrtype) > 0) { 4054 (void) snprintf(vbuf.vnic_macaddr, 4055 sizeof (vbuf.vnic_macaddr), "%s", 4056 dladm_aggr_macaddr2str(vnic->va_mac_addr, 4057 mstr)); 4058 } 4059 4060 (void) snprintf(vbuf.vnic_vid, sizeof (vbuf.vnic_vid), 4061 "%d", vnic->va_vid); 4062 } 4063 4064 ofmt_print(state->vs_ofmt, &vbuf); 4065 4066 return (DLADM_STATUS_OK); 4067 } 4068 } 4069 4070 /* ARGSUSED */ 4071 static int 4072 show_vnic(dladm_handle_t dh, datalink_id_t linkid, void *arg) 4073 { 4074 show_vnic_state_t *state = arg; 4075 4076 state->vs_status = print_vnic(state, linkid); 4077 return (DLADM_WALK_CONTINUE); 4078 } 4079 4080 static void 4081 do_show_vnic_common(int argc, char *argv[], const char *use, 4082 boolean_t etherstub) 4083 { 4084 int option; 4085 boolean_t s_arg = B_FALSE; 4086 boolean_t i_arg = B_FALSE; 4087 boolean_t l_arg = B_FALSE; 4088 uint32_t interval = 0, flags = DLADM_OPT_ACTIVE; 4089 datalink_id_t linkid = DATALINK_ALL_LINKID; 4090 datalink_id_t dev_linkid = DATALINK_ALL_LINKID; 4091 show_vnic_state_t state; 4092 dladm_status_t status; 4093 boolean_t o_arg = B_FALSE; 4094 char *fields_str = NULL; 4095 ofmt_field_t *pf; 4096 char *all_e_fields = "link"; 4097 ofmt_handle_t ofmt; 4098 ofmt_status_t oferr; 4099 uint_t ofmtflags = 0; 4100 4101 bzero(&state, sizeof (state)); 4102 opterr = 0; 4103 while ((option = getopt_long(argc, argv, ":pPl:si:o:", lopts, 4104 NULL)) != -1) { 4105 switch (option) { 4106 case 'p': 4107 state.vs_parsable = B_TRUE; 4108 break; 4109 case 'P': 4110 flags = DLADM_OPT_PERSIST; 4111 break; 4112 case 'l': 4113 if (etherstub) 4114 die("option not supported for this command"); 4115 4116 if (strlcpy(state.vs_link, optarg, MAXLINKNAMELEN) >= 4117 MAXLINKNAMELEN) 4118 die("link name too long"); 4119 4120 l_arg = B_TRUE; 4121 break; 4122 case 's': 4123 if (s_arg) { 4124 die("the option -s cannot be specified " 4125 "more than once"); 4126 } 4127 s_arg = B_TRUE; 4128 break; 4129 case 'i': 4130 if (i_arg) { 4131 die("the option -i cannot be specified " 4132 "more than once"); 4133 } 4134 i_arg = B_TRUE; 4135 if (!dladm_str2interval(optarg, &interval)) 4136 die("invalid interval value '%s'", optarg); 4137 break; 4138 case 'o': 4139 o_arg = B_TRUE; 4140 fields_str = optarg; 4141 break; 4142 default: 4143 die_opterr(optopt, option, use); 4144 } 4145 } 4146 4147 if (i_arg && !s_arg) 4148 die("the option -i can be used only with -s"); 4149 4150 /* get vnic ID (optional last argument) */ 4151 if (optind == (argc - 1)) { 4152 status = dladm_name2info(handle, argv[optind], &linkid, NULL, 4153 NULL, NULL); 4154 if (status != DLADM_STATUS_OK) { 4155 die_dlerr(status, "invalid vnic name '%s'", 4156 argv[optind]); 4157 } 4158 (void) strlcpy(state.vs_vnic, argv[optind], MAXLINKNAMELEN); 4159 } else if (optind != argc) { 4160 usage(); 4161 } 4162 4163 if (l_arg) { 4164 status = dladm_name2info(handle, state.vs_link, &dev_linkid, 4165 NULL, NULL, NULL); 4166 if (status != DLADM_STATUS_OK) { 4167 die_dlerr(status, "invalid link name '%s'", 4168 state.vs_link); 4169 } 4170 } 4171 4172 state.vs_vnic_id = linkid; 4173 state.vs_link_id = dev_linkid; 4174 state.vs_etherstub = etherstub; 4175 state.vs_found = B_FALSE; 4176 state.vs_flags = flags; 4177 4178 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) { 4179 if (etherstub) 4180 fields_str = all_e_fields; 4181 } 4182 pf = vnic_fields; 4183 4184 if (state.vs_parsable) 4185 ofmtflags |= OFMT_PARSABLE; 4186 oferr = ofmt_open(fields_str, pf, ofmtflags, 0, &ofmt); 4187 dladm_ofmt_check(oferr, state.vs_parsable, ofmt); 4188 state.vs_ofmt = ofmt; 4189 4190 if (s_arg) { 4191 /* Display vnic statistics */ 4192 vnic_stats(&state, interval); 4193 ofmt_close(ofmt); 4194 return; 4195 } 4196 4197 /* Display vnic information */ 4198 state.vs_donefirst = B_FALSE; 4199 4200 if (linkid == DATALINK_ALL_LINKID) { 4201 (void) dladm_walk_datalink_id(show_vnic, handle, &state, 4202 DATALINK_CLASS_VNIC | DATALINK_CLASS_ETHERSTUB, 4203 DATALINK_ANY_MEDIATYPE, flags); 4204 } else { 4205 (void) show_vnic(handle, linkid, &state); 4206 if (state.vs_status != DLADM_STATUS_OK) { 4207 ofmt_close(ofmt); 4208 die_dlerr(state.vs_status, "failed to show vnic '%s'", 4209 state.vs_vnic); 4210 } 4211 } 4212 ofmt_close(ofmt); 4213 } 4214 4215 static void 4216 do_show_vnic(int argc, char *argv[], const char *use) 4217 { 4218 do_show_vnic_common(argc, argv, use, B_FALSE); 4219 } 4220 4221 static void 4222 do_create_etherstub(int argc, char *argv[], const char *use) 4223 { 4224 uint32_t flags; 4225 char *altroot = NULL; 4226 char option; 4227 dladm_status_t status; 4228 char name[MAXLINKNAMELEN]; 4229 uchar_t mac_addr[ETHERADDRL]; 4230 4231 name[0] = '\0'; 4232 bzero(mac_addr, sizeof (mac_addr)); 4233 flags = DLADM_OPT_ANCHOR | DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 4234 4235 opterr = 0; 4236 while ((option = getopt_long(argc, argv, "tR:", 4237 etherstub_lopts, NULL)) != -1) { 4238 switch (option) { 4239 case 't': 4240 flags &= ~DLADM_OPT_PERSIST; 4241 break; 4242 case 'R': 4243 altroot = optarg; 4244 break; 4245 default: 4246 die_opterr(optopt, option, use); 4247 } 4248 } 4249 4250 /* the etherstub id is the required operand */ 4251 if (optind != (argc - 1)) 4252 usage(); 4253 4254 if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= MAXLINKNAMELEN) 4255 die("link name too long '%s'", argv[optind]); 4256 4257 if (!dladm_valid_linkname(name)) 4258 die("invalid link name '%s'", argv[optind]); 4259 4260 if (altroot != NULL) 4261 altroot_cmd(altroot, argc, argv); 4262 4263 status = dladm_vnic_create(handle, name, DATALINK_INVALID_LINKID, 4264 VNIC_MAC_ADDR_TYPE_AUTO, mac_addr, ETHERADDRL, NULL, 0, 0, NULL, 4265 NULL, flags); 4266 if (status != DLADM_STATUS_OK) 4267 die_dlerr(status, "etherstub creation failed"); 4268 4269 4270 } 4271 4272 static void 4273 do_delete_etherstub(int argc, char *argv[], const char *use) 4274 { 4275 do_delete_vnic_common(argc, argv, use, B_TRUE); 4276 } 4277 4278 /* ARGSUSED */ 4279 static void 4280 do_show_etherstub(int argc, char *argv[], const char *use) 4281 { 4282 do_show_vnic_common(argc, argv, use, B_TRUE); 4283 } 4284 4285 static void 4286 link_stats(datalink_id_t linkid, uint_t interval, char *fields_str, 4287 show_state_t *state) 4288 { 4289 ofmt_handle_t ofmt; 4290 ofmt_status_t oferr; 4291 uint_t ofmtflags = 0; 4292 4293 if (state->ls_parsable) 4294 ofmtflags |= OFMT_PARSABLE; 4295 oferr = ofmt_open(fields_str, link_s_fields, ofmtflags, 0, &ofmt); 4296 dladm_ofmt_check(oferr, state->ls_parsable, ofmt); 4297 state->ls_ofmt = ofmt; 4298 4299 /* 4300 * If an interval is specified, continuously show the stats 4301 * only for the first MAC port. 4302 */ 4303 state->ls_firstonly = (interval != 0); 4304 4305 for (;;) { 4306 state->ls_donefirst = B_FALSE; 4307 if (linkid == DATALINK_ALL_LINKID) { 4308 (void) dladm_walk_datalink_id(show_link_stats, handle, 4309 state, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, 4310 DLADM_OPT_ACTIVE); 4311 } else { 4312 (void) show_link_stats(handle, linkid, state); 4313 } 4314 4315 if (interval == 0) 4316 break; 4317 4318 (void) fflush(stdout); 4319 (void) sleep(interval); 4320 } 4321 ofmt_close(ofmt); 4322 } 4323 4324 static void 4325 aggr_stats(datalink_id_t linkid, show_grp_state_t *state, uint_t interval) 4326 { 4327 /* 4328 * If an interval is specified, continuously show the stats 4329 * only for the first group. 4330 */ 4331 state->gs_firstonly = (interval != 0); 4332 4333 for (;;) { 4334 state->gs_donefirst = B_FALSE; 4335 if (linkid == DATALINK_ALL_LINKID) 4336 (void) dladm_walk_datalink_id(show_aggr, handle, state, 4337 DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, 4338 DLADM_OPT_ACTIVE); 4339 else 4340 (void) show_aggr(handle, linkid, state); 4341 4342 if (interval == 0) 4343 break; 4344 4345 (void) fflush(stdout); 4346 (void) sleep(interval); 4347 } 4348 } 4349 4350 /* ARGSUSED */ 4351 static void 4352 vnic_stats(show_vnic_state_t *sp, uint32_t interval) 4353 { 4354 show_vnic_state_t state; 4355 boolean_t specific_link, specific_dev; 4356 4357 /* Display vnic statistics */ 4358 dump_vnics_head(sp->vs_link); 4359 4360 bzero(&state, sizeof (state)); 4361 state.vs_stats = B_TRUE; 4362 state.vs_vnic_id = sp->vs_vnic_id; 4363 state.vs_link_id = sp->vs_link_id; 4364 4365 /* 4366 * If an interval is specified, and a vnic ID is not specified, 4367 * continuously show the stats only for the first vnic. 4368 */ 4369 specific_link = (sp->vs_vnic_id != DATALINK_ALL_LINKID); 4370 specific_dev = (sp->vs_link_id != DATALINK_ALL_LINKID); 4371 4372 for (;;) { 4373 /* Get stats for each vnic */ 4374 state.vs_found = B_FALSE; 4375 state.vs_donefirst = B_FALSE; 4376 state.vs_printstats = B_FALSE; 4377 state.vs_flags = DLADM_OPT_ACTIVE; 4378 4379 if (!specific_link) { 4380 (void) dladm_walk_datalink_id(show_vnic, handle, &state, 4381 DATALINK_CLASS_VNIC, DATALINK_ANY_MEDIATYPE, 4382 DLADM_OPT_ACTIVE); 4383 } else { 4384 (void) show_vnic(handle, sp->vs_vnic_id, &state); 4385 if (state.vs_status != DLADM_STATUS_OK) { 4386 die_dlerr(state.vs_status, 4387 "failed to show vnic '%s'", sp->vs_vnic); 4388 } 4389 } 4390 4391 if (specific_link && !state.vs_found) 4392 die("non-existent vnic '%s'", sp->vs_vnic); 4393 if (specific_dev && !state.vs_found) 4394 die("device %s has no vnics", sp->vs_link); 4395 4396 /* Show totals */ 4397 if ((specific_link | specific_dev) && !interval) { 4398 (void) printf("Total"); 4399 (void) printf("\t%-10llu", 4400 state.vs_totalstats.ipackets); 4401 (void) printf("%-12llu", 4402 state.vs_totalstats.rbytes); 4403 (void) printf("%-10llu", 4404 state.vs_totalstats.opackets); 4405 (void) printf("%-12llu\n", 4406 state.vs_totalstats.obytes); 4407 } 4408 4409 /* Show stats for each vnic */ 4410 state.vs_donefirst = B_FALSE; 4411 state.vs_printstats = B_TRUE; 4412 4413 if (!specific_link) { 4414 (void) dladm_walk_datalink_id(show_vnic, handle, &state, 4415 DATALINK_CLASS_VNIC, DATALINK_ANY_MEDIATYPE, 4416 DLADM_OPT_ACTIVE); 4417 } else { 4418 (void) show_vnic(handle, sp->vs_vnic_id, &state); 4419 if (state.vs_status != DLADM_STATUS_OK) { 4420 die_dlerr(state.vs_status, 4421 "failed to show vnic '%s'", sp->vs_vnic); 4422 } 4423 } 4424 4425 if (interval == 0) 4426 break; 4427 4428 (void) fflush(stdout); 4429 (void) sleep(interval); 4430 } 4431 } 4432 4433 static void 4434 get_mac_stats(const char *dev, pktsum_t *stats) 4435 { 4436 kstat_ctl_t *kcp; 4437 kstat_t *ksp; 4438 char module[DLPI_LINKNAME_MAX]; 4439 uint_t instance; 4440 4441 4442 bzero(stats, sizeof (*stats)); 4443 4444 if (dlpi_parselink(dev, module, &instance) != DLPI_SUCCESS) 4445 return; 4446 4447 if ((kcp = kstat_open()) == NULL) { 4448 warn("kstat open operation failed"); 4449 return; 4450 } 4451 4452 ksp = dladm_kstat_lookup(kcp, module, instance, "mac", NULL); 4453 if (ksp != NULL) 4454 dladm_get_stats(kcp, ksp, stats); 4455 4456 (void) kstat_close(kcp); 4457 4458 } 4459 4460 static void 4461 get_link_stats(const char *link, pktsum_t *stats) 4462 { 4463 kstat_ctl_t *kcp; 4464 kstat_t *ksp; 4465 4466 bzero(stats, sizeof (*stats)); 4467 4468 if ((kcp = kstat_open()) == NULL) { 4469 warn("kstat_open operation failed"); 4470 return; 4471 } 4472 4473 ksp = dladm_kstat_lookup(kcp, "link", 0, link, NULL); 4474 4475 if (ksp != NULL) 4476 dladm_get_stats(kcp, ksp, stats); 4477 4478 (void) kstat_close(kcp); 4479 } 4480 4481 static int 4482 query_kstat(char *module, int instance, const char *name, const char *stat, 4483 uint8_t type, void *val) 4484 { 4485 kstat_ctl_t *kcp; 4486 kstat_t *ksp; 4487 4488 if ((kcp = kstat_open()) == NULL) { 4489 warn("kstat open operation failed"); 4490 return (-1); 4491 } 4492 4493 if ((ksp = kstat_lookup(kcp, module, instance, (char *)name)) == NULL) { 4494 /* 4495 * The kstat query could fail if the underlying MAC 4496 * driver was already detached. 4497 */ 4498 goto bail; 4499 } 4500 4501 if (kstat_read(kcp, ksp, NULL) == -1) { 4502 warn("kstat read failed"); 4503 goto bail; 4504 } 4505 4506 if (dladm_kstat_value(ksp, stat, type, val) < 0) 4507 goto bail; 4508 4509 (void) kstat_close(kcp); 4510 return (0); 4511 4512 bail: 4513 (void) kstat_close(kcp); 4514 return (-1); 4515 } 4516 4517 static int 4518 get_one_kstat(const char *name, const char *stat, uint8_t type, 4519 void *val, boolean_t islink) 4520 { 4521 char module[DLPI_LINKNAME_MAX]; 4522 uint_t instance; 4523 4524 if (islink) { 4525 return (query_kstat("link", 0, name, stat, type, val)); 4526 } else { 4527 if (dlpi_parselink(name, module, &instance) != DLPI_SUCCESS) 4528 return (-1); 4529 4530 return (query_kstat(module, instance, "mac", stat, type, val)); 4531 } 4532 } 4533 4534 static uint64_t 4535 get_ifspeed(const char *name, boolean_t islink) 4536 { 4537 uint64_t ifspeed = 0; 4538 4539 (void) get_one_kstat(name, "ifspeed", KSTAT_DATA_UINT64, 4540 &ifspeed, islink); 4541 4542 return (ifspeed); 4543 } 4544 4545 static const char * 4546 get_linkstate(const char *name, boolean_t islink, char *buf) 4547 { 4548 link_state_t linkstate; 4549 4550 if (get_one_kstat(name, "link_state", KSTAT_DATA_UINT32, 4551 &linkstate, islink) != 0) { 4552 (void) strlcpy(buf, "?", DLADM_STRSIZE); 4553 return (buf); 4554 } 4555 return (dladm_linkstate2str(linkstate, buf)); 4556 } 4557 4558 static const char * 4559 get_linkduplex(const char *name, boolean_t islink, char *buf) 4560 { 4561 link_duplex_t linkduplex; 4562 4563 if (get_one_kstat(name, "link_duplex", KSTAT_DATA_UINT32, 4564 &linkduplex, islink) != 0) { 4565 (void) strlcpy(buf, "unknown", DLADM_STRSIZE); 4566 return (buf); 4567 } 4568 4569 return (dladm_linkduplex2str(linkduplex, buf)); 4570 } 4571 4572 static int 4573 parse_wifi_fields(char *str, ofmt_handle_t *ofmt, uint_t cmdtype, 4574 boolean_t parsable) 4575 { 4576 ofmt_field_t *template, *of; 4577 ofmt_cb_t *fn; 4578 ofmt_status_t oferr; 4579 4580 if (cmdtype == WIFI_CMD_SCAN) { 4581 template = wifi_common_fields; 4582 if (str == NULL) 4583 str = def_scan_wifi_fields; 4584 if (strcasecmp(str, "all") == 0) 4585 str = all_scan_wifi_fields; 4586 fn = print_wlan_attr_cb; 4587 } else if (cmdtype == WIFI_CMD_SHOW) { 4588 bcopy(wifi_common_fields, &wifi_show_fields[2], 4589 sizeof (wifi_common_fields)); 4590 template = wifi_show_fields; 4591 if (str == NULL) 4592 str = def_show_wifi_fields; 4593 if (strcasecmp(str, "all") == 0) 4594 str = all_show_wifi_fields; 4595 fn = print_link_attr_cb; 4596 } else { 4597 return (-1); 4598 } 4599 4600 for (of = template; of->of_name != NULL; of++) { 4601 if (of->of_cb == NULL) 4602 of->of_cb = fn; 4603 } 4604 4605 oferr = ofmt_open(str, template, (parsable ? OFMT_PARSABLE : 0), 4606 0, ofmt); 4607 dladm_ofmt_check(oferr, parsable, *ofmt); 4608 return (0); 4609 } 4610 4611 typedef struct print_wifi_state { 4612 char *ws_link; 4613 boolean_t ws_parsable; 4614 boolean_t ws_header; 4615 ofmt_handle_t ws_ofmt; 4616 } print_wifi_state_t; 4617 4618 typedef struct wlan_scan_args_s { 4619 print_wifi_state_t *ws_state; 4620 void *ws_attr; 4621 } wlan_scan_args_t; 4622 4623 static boolean_t 4624 print_wlan_attr_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 4625 { 4626 wlan_scan_args_t *w = ofarg->ofmt_cbarg; 4627 print_wifi_state_t *statep = w->ws_state; 4628 dladm_wlan_attr_t *attrp = w->ws_attr; 4629 char tmpbuf[DLADM_STRSIZE]; 4630 4631 if (ofarg->ofmt_id == 0) { 4632 (void) strlcpy(buf, (char *)statep->ws_link, bufsize); 4633 return (B_TRUE); 4634 } 4635 4636 if ((ofarg->ofmt_id & attrp->wa_valid) == 0) 4637 return (B_TRUE); 4638 4639 switch (ofarg->ofmt_id) { 4640 case DLADM_WLAN_ATTR_ESSID: 4641 (void) dladm_wlan_essid2str(&attrp->wa_essid, tmpbuf); 4642 break; 4643 case DLADM_WLAN_ATTR_BSSID: 4644 (void) dladm_wlan_bssid2str(&attrp->wa_bssid, tmpbuf); 4645 break; 4646 case DLADM_WLAN_ATTR_SECMODE: 4647 (void) dladm_wlan_secmode2str(&attrp->wa_secmode, tmpbuf); 4648 break; 4649 case DLADM_WLAN_ATTR_STRENGTH: 4650 (void) dladm_wlan_strength2str(&attrp->wa_strength, tmpbuf); 4651 break; 4652 case DLADM_WLAN_ATTR_MODE: 4653 (void) dladm_wlan_mode2str(&attrp->wa_mode, tmpbuf); 4654 break; 4655 case DLADM_WLAN_ATTR_SPEED: 4656 (void) dladm_wlan_speed2str(&attrp->wa_speed, tmpbuf); 4657 (void) strlcat(tmpbuf, "Mb", sizeof (tmpbuf)); 4658 break; 4659 case DLADM_WLAN_ATTR_AUTH: 4660 (void) dladm_wlan_auth2str(&attrp->wa_auth, tmpbuf); 4661 break; 4662 case DLADM_WLAN_ATTR_BSSTYPE: 4663 (void) dladm_wlan_bsstype2str(&attrp->wa_bsstype, tmpbuf); 4664 break; 4665 } 4666 (void) strlcpy(buf, tmpbuf, bufsize); 4667 4668 return (B_TRUE); 4669 } 4670 4671 static boolean_t 4672 print_scan_results(void *arg, dladm_wlan_attr_t *attrp) 4673 { 4674 print_wifi_state_t *statep = arg; 4675 wlan_scan_args_t warg; 4676 4677 bzero(&warg, sizeof (warg)); 4678 warg.ws_state = statep; 4679 warg.ws_attr = attrp; 4680 ofmt_print(statep->ws_ofmt, &warg); 4681 return (B_TRUE); 4682 } 4683 4684 static int 4685 scan_wifi(dladm_handle_t dh, datalink_id_t linkid, void *arg) 4686 { 4687 print_wifi_state_t *statep = arg; 4688 dladm_status_t status; 4689 char link[MAXLINKNAMELEN]; 4690 4691 if ((status = dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, link, 4692 sizeof (link))) != DLADM_STATUS_OK) { 4693 return (DLADM_WALK_CONTINUE); 4694 } 4695 4696 statep->ws_link = link; 4697 status = dladm_wlan_scan(dh, linkid, statep, print_scan_results); 4698 if (status != DLADM_STATUS_OK) 4699 die_dlerr(status, "cannot scan link '%s'", statep->ws_link); 4700 4701 return (DLADM_WALK_CONTINUE); 4702 } 4703 4704 static boolean_t 4705 print_wifi_status_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 4706 { 4707 static char tmpbuf[DLADM_STRSIZE]; 4708 wlan_scan_args_t *w = ofarg->ofmt_cbarg; 4709 dladm_wlan_linkattr_t *attrp = w->ws_attr; 4710 4711 if ((ofarg->ofmt_id & attrp->la_valid) != 0) { 4712 (void) dladm_wlan_linkstatus2str(&attrp->la_status, tmpbuf); 4713 (void) strlcpy(buf, tmpbuf, bufsize); 4714 } 4715 return (B_TRUE); 4716 } 4717 4718 static boolean_t 4719 print_link_attr_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 4720 { 4721 wlan_scan_args_t *w = ofarg->ofmt_cbarg, w1; 4722 print_wifi_state_t *statep = w->ws_state; 4723 dladm_wlan_linkattr_t *attrp = w->ws_attr; 4724 4725 bzero(&w1, sizeof (w1)); 4726 w1.ws_state = statep; 4727 w1.ws_attr = &attrp->la_wlan_attr; 4728 ofarg->ofmt_cbarg = &w1; 4729 return (print_wlan_attr_cb(ofarg, buf, bufsize)); 4730 } 4731 4732 static int 4733 show_wifi(dladm_handle_t dh, datalink_id_t linkid, void *arg) 4734 { 4735 print_wifi_state_t *statep = arg; 4736 dladm_wlan_linkattr_t attr; 4737 dladm_status_t status; 4738 char link[MAXLINKNAMELEN]; 4739 wlan_scan_args_t warg; 4740 4741 if ((status = dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, link, 4742 sizeof (link))) != DLADM_STATUS_OK) { 4743 return (DLADM_WALK_CONTINUE); 4744 } 4745 4746 /* dladm_wlan_get_linkattr() memsets attr with 0 */ 4747 status = dladm_wlan_get_linkattr(dh, linkid, &attr); 4748 if (status != DLADM_STATUS_OK) 4749 die_dlerr(status, "cannot get link attributes for %s", link); 4750 4751 statep->ws_link = link; 4752 4753 bzero(&warg, sizeof (warg)); 4754 warg.ws_state = statep; 4755 warg.ws_attr = &attr; 4756 ofmt_print(statep->ws_ofmt, &warg); 4757 return (DLADM_WALK_CONTINUE); 4758 } 4759 4760 static void 4761 do_display_wifi(int argc, char **argv, int cmd, const char *use) 4762 { 4763 int option; 4764 char *fields_str = NULL; 4765 int (*callback)(dladm_handle_t, datalink_id_t, void *); 4766 print_wifi_state_t state; 4767 datalink_id_t linkid = DATALINK_ALL_LINKID; 4768 dladm_status_t status; 4769 4770 if (cmd == WIFI_CMD_SCAN) 4771 callback = scan_wifi; 4772 else if (cmd == WIFI_CMD_SHOW) 4773 callback = show_wifi; 4774 else 4775 return; 4776 4777 state.ws_parsable = B_FALSE; 4778 state.ws_header = B_TRUE; 4779 opterr = 0; 4780 while ((option = getopt_long(argc, argv, ":o:p", 4781 wifi_longopts, NULL)) != -1) { 4782 switch (option) { 4783 case 'o': 4784 fields_str = optarg; 4785 break; 4786 case 'p': 4787 state.ws_parsable = B_TRUE; 4788 break; 4789 default: 4790 die_opterr(optopt, option, use); 4791 } 4792 } 4793 4794 if (state.ws_parsable && fields_str == NULL) 4795 die("-p requires -o"); 4796 4797 if (state.ws_parsable && strcasecmp(fields_str, "all") == 0) 4798 die("\"-o all\" is invalid with -p"); 4799 4800 if (optind == (argc - 1)) { 4801 if ((status = dladm_name2info(handle, argv[optind], &linkid, 4802 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 4803 die_dlerr(status, "link %s is not valid", argv[optind]); 4804 } 4805 } else if (optind != argc) { 4806 usage(); 4807 } 4808 4809 if (parse_wifi_fields(fields_str, &state.ws_ofmt, cmd, 4810 state.ws_parsable) < 0) 4811 die("invalid field(s) specified"); 4812 4813 if (linkid == DATALINK_ALL_LINKID) { 4814 (void) dladm_walk_datalink_id(callback, handle, &state, 4815 DATALINK_CLASS_PHYS, DL_WIFI, DLADM_OPT_ACTIVE); 4816 } else { 4817 (void) (*callback)(handle, linkid, &state); 4818 } 4819 ofmt_close(state.ws_ofmt); 4820 } 4821 4822 static void 4823 do_scan_wifi(int argc, char **argv, const char *use) 4824 { 4825 do_display_wifi(argc, argv, WIFI_CMD_SCAN, use); 4826 } 4827 4828 static void 4829 do_show_wifi(int argc, char **argv, const char *use) 4830 { 4831 do_display_wifi(argc, argv, WIFI_CMD_SHOW, use); 4832 } 4833 4834 typedef struct wlan_count_attr { 4835 uint_t wc_count; 4836 datalink_id_t wc_linkid; 4837 } wlan_count_attr_t; 4838 4839 /* ARGSUSED */ 4840 static int 4841 do_count_wlan(dladm_handle_t dh, datalink_id_t linkid, void *arg) 4842 { 4843 wlan_count_attr_t *cp = arg; 4844 4845 if (cp->wc_count == 0) 4846 cp->wc_linkid = linkid; 4847 cp->wc_count++; 4848 return (DLADM_WALK_CONTINUE); 4849 } 4850 4851 static int 4852 parse_wlan_keys(char *str, dladm_wlan_key_t **keys, uint_t *key_countp) 4853 { 4854 uint_t i; 4855 dladm_wlan_key_t *wk; 4856 int nfields = 1; 4857 char *field, *token, *lasts = NULL, c; 4858 4859 token = str; 4860 while ((c = *token++) != NULL) { 4861 if (c == ',') 4862 nfields++; 4863 } 4864 token = strdup(str); 4865 if (token == NULL) 4866 return (-1); 4867 4868 wk = malloc(nfields * sizeof (dladm_wlan_key_t)); 4869 if (wk == NULL) 4870 goto fail; 4871 4872 token = str; 4873 for (i = 0; i < nfields; i++) { 4874 char *s; 4875 dladm_secobj_class_t class; 4876 dladm_status_t status; 4877 4878 field = strtok_r(token, ",", &lasts); 4879 token = NULL; 4880 4881 (void) strlcpy(wk[i].wk_name, field, 4882 DLADM_WLAN_MAX_KEYNAME_LEN); 4883 4884 wk[i].wk_idx = 1; 4885 if ((s = strrchr(wk[i].wk_name, ':')) != NULL) { 4886 if (s[1] == '\0' || s[2] != '\0' || !isdigit(s[1])) 4887 goto fail; 4888 4889 wk[i].wk_idx = (uint_t)(s[1] - '0'); 4890 *s = '\0'; 4891 } 4892 wk[i].wk_len = DLADM_WLAN_MAX_KEY_LEN; 4893 4894 status = dladm_get_secobj(handle, wk[i].wk_name, &class, 4895 wk[i].wk_val, &wk[i].wk_len, 0); 4896 if (status != DLADM_STATUS_OK) { 4897 if (status == DLADM_STATUS_NOTFOUND) { 4898 status = dladm_get_secobj(handle, wk[i].wk_name, 4899 &class, wk[i].wk_val, &wk[i].wk_len, 4900 DLADM_OPT_PERSIST); 4901 } 4902 if (status != DLADM_STATUS_OK) 4903 goto fail; 4904 } 4905 wk[i].wk_class = class; 4906 } 4907 *keys = wk; 4908 *key_countp = i; 4909 free(token); 4910 return (0); 4911 fail: 4912 free(wk); 4913 free(token); 4914 return (-1); 4915 } 4916 4917 static void 4918 do_connect_wifi(int argc, char **argv, const char *use) 4919 { 4920 int option; 4921 dladm_wlan_attr_t attr, *attrp; 4922 dladm_status_t status = DLADM_STATUS_OK; 4923 int timeout = DLADM_WLAN_CONNECT_TIMEOUT_DEFAULT; 4924 datalink_id_t linkid = DATALINK_ALL_LINKID; 4925 dladm_wlan_key_t *keys = NULL; 4926 uint_t key_count = 0; 4927 uint_t flags = 0; 4928 dladm_wlan_secmode_t keysecmode = DLADM_WLAN_SECMODE_NONE; 4929 char buf[DLADM_STRSIZE]; 4930 4931 opterr = 0; 4932 (void) memset(&attr, 0, sizeof (attr)); 4933 while ((option = getopt_long(argc, argv, ":e:i:a:m:b:s:k:T:c", 4934 wifi_longopts, NULL)) != -1) { 4935 switch (option) { 4936 case 'e': 4937 status = dladm_wlan_str2essid(optarg, &attr.wa_essid); 4938 if (status != DLADM_STATUS_OK) 4939 die("invalid ESSID '%s'", optarg); 4940 4941 attr.wa_valid |= DLADM_WLAN_ATTR_ESSID; 4942 /* 4943 * Try to connect without doing a scan. 4944 */ 4945 flags |= DLADM_WLAN_CONNECT_NOSCAN; 4946 break; 4947 case 'i': 4948 status = dladm_wlan_str2bssid(optarg, &attr.wa_bssid); 4949 if (status != DLADM_STATUS_OK) 4950 die("invalid BSSID %s", optarg); 4951 4952 attr.wa_valid |= DLADM_WLAN_ATTR_BSSID; 4953 break; 4954 case 'a': 4955 status = dladm_wlan_str2auth(optarg, &attr.wa_auth); 4956 if (status != DLADM_STATUS_OK) 4957 die("invalid authentication mode '%s'", optarg); 4958 4959 attr.wa_valid |= DLADM_WLAN_ATTR_AUTH; 4960 break; 4961 case 'm': 4962 status = dladm_wlan_str2mode(optarg, &attr.wa_mode); 4963 if (status != DLADM_STATUS_OK) 4964 die("invalid mode '%s'", optarg); 4965 4966 attr.wa_valid |= DLADM_WLAN_ATTR_MODE; 4967 break; 4968 case 'b': 4969 if ((status = dladm_wlan_str2bsstype(optarg, 4970 &attr.wa_bsstype)) != DLADM_STATUS_OK) { 4971 die("invalid bsstype '%s'", optarg); 4972 } 4973 4974 attr.wa_valid |= DLADM_WLAN_ATTR_BSSTYPE; 4975 break; 4976 case 's': 4977 if ((status = dladm_wlan_str2secmode(optarg, 4978 &attr.wa_secmode)) != DLADM_STATUS_OK) { 4979 die("invalid security mode '%s'", optarg); 4980 } 4981 4982 attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE; 4983 break; 4984 case 'k': 4985 if (parse_wlan_keys(optarg, &keys, &key_count) < 0) 4986 die("invalid key(s) '%s'", optarg); 4987 4988 if (keys[0].wk_class == DLADM_SECOBJ_CLASS_WEP) 4989 keysecmode = DLADM_WLAN_SECMODE_WEP; 4990 else 4991 keysecmode = DLADM_WLAN_SECMODE_WPA; 4992 break; 4993 case 'T': 4994 if (strcasecmp(optarg, "forever") == 0) { 4995 timeout = -1; 4996 break; 4997 } 4998 if (!str2int(optarg, &timeout) || timeout < 0) 4999 die("invalid timeout value '%s'", optarg); 5000 break; 5001 case 'c': 5002 flags |= DLADM_WLAN_CONNECT_CREATEIBSS; 5003 flags |= DLADM_WLAN_CONNECT_CREATEIBSS; 5004 break; 5005 default: 5006 die_opterr(optopt, option, use); 5007 break; 5008 } 5009 } 5010 5011 if (keysecmode == DLADM_WLAN_SECMODE_NONE) { 5012 if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0) { 5013 die("key required for security mode '%s'", 5014 dladm_wlan_secmode2str(&attr.wa_secmode, buf)); 5015 } 5016 } else { 5017 if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0 && 5018 attr.wa_secmode != keysecmode) 5019 die("incompatible -s and -k options"); 5020 attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE; 5021 attr.wa_secmode = keysecmode; 5022 } 5023 5024 if (optind == (argc - 1)) { 5025 if ((status = dladm_name2info(handle, argv[optind], &linkid, 5026 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 5027 die_dlerr(status, "link %s is not valid", argv[optind]); 5028 } 5029 } else if (optind != argc) { 5030 usage(); 5031 } 5032 5033 if (linkid == DATALINK_ALL_LINKID) { 5034 wlan_count_attr_t wcattr; 5035 5036 wcattr.wc_linkid = DATALINK_INVALID_LINKID; 5037 wcattr.wc_count = 0; 5038 (void) dladm_walk_datalink_id(do_count_wlan, handle, &wcattr, 5039 DATALINK_CLASS_PHYS, DL_WIFI, DLADM_OPT_ACTIVE); 5040 if (wcattr.wc_count == 0) { 5041 die("no wifi links are available"); 5042 } else if (wcattr.wc_count > 1) { 5043 die("link name is required when more than one wifi " 5044 "link is available"); 5045 } 5046 linkid = wcattr.wc_linkid; 5047 } 5048 attrp = (attr.wa_valid == 0) ? NULL : &attr; 5049 again: 5050 if ((status = dladm_wlan_connect(handle, linkid, attrp, timeout, keys, 5051 key_count, flags)) != DLADM_STATUS_OK) { 5052 if ((flags & DLADM_WLAN_CONNECT_NOSCAN) != 0) { 5053 /* 5054 * Try again with scanning and filtering. 5055 */ 5056 flags &= ~DLADM_WLAN_CONNECT_NOSCAN; 5057 goto again; 5058 } 5059 5060 if (status == DLADM_STATUS_NOTFOUND) { 5061 if (attr.wa_valid == 0) { 5062 die("no wifi networks are available"); 5063 } else { 5064 die("no wifi networks with the specified " 5065 "criteria are available"); 5066 } 5067 } 5068 die_dlerr(status, "cannot connect"); 5069 } 5070 free(keys); 5071 } 5072 5073 /* ARGSUSED */ 5074 static int 5075 do_all_disconnect_wifi(dladm_handle_t dh, datalink_id_t linkid, void *arg) 5076 { 5077 dladm_status_t status; 5078 5079 status = dladm_wlan_disconnect(dh, linkid); 5080 if (status != DLADM_STATUS_OK) 5081 warn_dlerr(status, "cannot disconnect link"); 5082 5083 return (DLADM_WALK_CONTINUE); 5084 } 5085 5086 static void 5087 do_disconnect_wifi(int argc, char **argv, const char *use) 5088 { 5089 int option; 5090 datalink_id_t linkid = DATALINK_ALL_LINKID; 5091 boolean_t all_links = B_FALSE; 5092 dladm_status_t status; 5093 wlan_count_attr_t wcattr; 5094 5095 opterr = 0; 5096 while ((option = getopt_long(argc, argv, ":a", 5097 wifi_longopts, NULL)) != -1) { 5098 switch (option) { 5099 case 'a': 5100 all_links = B_TRUE; 5101 break; 5102 default: 5103 die_opterr(optopt, option, use); 5104 break; 5105 } 5106 } 5107 5108 if (optind == (argc - 1)) { 5109 if ((status = dladm_name2info(handle, argv[optind], &linkid, 5110 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 5111 die_dlerr(status, "link %s is not valid", argv[optind]); 5112 } 5113 } else if (optind != argc) { 5114 usage(); 5115 } 5116 5117 if (linkid == DATALINK_ALL_LINKID) { 5118 if (!all_links) { 5119 wcattr.wc_linkid = linkid; 5120 wcattr.wc_count = 0; 5121 (void) dladm_walk_datalink_id(do_count_wlan, handle, 5122 &wcattr, DATALINK_CLASS_PHYS, DL_WIFI, 5123 DLADM_OPT_ACTIVE); 5124 if (wcattr.wc_count == 0) { 5125 die("no wifi links are available"); 5126 } else if (wcattr.wc_count > 1) { 5127 die("link name is required when more than " 5128 "one wifi link is available"); 5129 } 5130 linkid = wcattr.wc_linkid; 5131 } else { 5132 (void) dladm_walk_datalink_id(do_all_disconnect_wifi, 5133 handle, NULL, DATALINK_CLASS_PHYS, DL_WIFI, 5134 DLADM_OPT_ACTIVE); 5135 return; 5136 } 5137 } 5138 status = dladm_wlan_disconnect(handle, linkid); 5139 if (status != DLADM_STATUS_OK) 5140 die_dlerr(status, "cannot disconnect"); 5141 } 5142 5143 static void 5144 print_linkprop(datalink_id_t linkid, show_linkprop_state_t *statep, 5145 const char *propname, dladm_prop_type_t type, const char *format, 5146 char **pptr) 5147 { 5148 int i; 5149 char *ptr, *lim; 5150 char buf[DLADM_STRSIZE]; 5151 char *unknown = "--", *notsup = ""; 5152 char **propvals = statep->ls_propvals; 5153 uint_t valcnt = DLADM_MAX_PROP_VALCNT; 5154 dladm_status_t status; 5155 5156 status = dladm_get_linkprop(handle, linkid, type, propname, propvals, 5157 &valcnt); 5158 if (status != DLADM_STATUS_OK) { 5159 if (status == DLADM_STATUS_TEMPONLY) { 5160 if (type == DLADM_PROP_VAL_MODIFIABLE && 5161 statep->ls_persist) { 5162 valcnt = 1; 5163 propvals = &unknown; 5164 } else { 5165 statep->ls_status = status; 5166 statep->ls_retstatus = status; 5167 return; 5168 } 5169 } else if (status == DLADM_STATUS_NOTSUP || 5170 statep->ls_persist) { 5171 valcnt = 1; 5172 if (type == DLADM_PROP_VAL_CURRENT || 5173 type == DLADM_PROP_VAL_PERM) 5174 propvals = &unknown; 5175 else 5176 propvals = ¬sup; 5177 } else if (status == DLADM_STATUS_NOTDEFINED) { 5178 propvals = ¬sup; /* STR_UNDEF_VAL */ 5179 } else { 5180 if (statep->ls_proplist && 5181 statep->ls_status == DLADM_STATUS_OK) { 5182 warn_dlerr(status, 5183 "cannot get link property '%s' for %s", 5184 propname, statep->ls_link); 5185 } 5186 statep->ls_status = status; 5187 statep->ls_retstatus = status; 5188 return; 5189 } 5190 } 5191 5192 statep->ls_status = DLADM_STATUS_OK; 5193 5194 ptr = buf; 5195 lim = buf + DLADM_STRSIZE; 5196 for (i = 0; i < valcnt; i++) { 5197 if (propvals[i][0] == '\0' && !statep->ls_parsable) 5198 ptr += snprintf(ptr, lim - ptr, "--,"); 5199 else 5200 ptr += snprintf(ptr, lim - ptr, "%s,", propvals[i]); 5201 if (ptr >= lim) 5202 break; 5203 } 5204 if (valcnt > 0) 5205 buf[strlen(buf) - 1] = '\0'; 5206 5207 lim = statep->ls_line + MAX_PROP_LINE; 5208 if (statep->ls_parsable) { 5209 *pptr += snprintf(*pptr, lim - *pptr, 5210 "%s", buf); 5211 } else { 5212 *pptr += snprintf(*pptr, lim - *pptr, format, buf); 5213 } 5214 } 5215 5216 static boolean_t 5217 print_linkprop_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 5218 { 5219 linkprop_args_t *arg = ofarg->ofmt_cbarg; 5220 char *propname = arg->ls_propname; 5221 show_linkprop_state_t *statep = arg->ls_state; 5222 char *ptr = statep->ls_line; 5223 char *lim = ptr + MAX_PROP_LINE; 5224 datalink_id_t linkid = arg->ls_linkid; 5225 5226 switch (ofarg->ofmt_id) { 5227 case LINKPROP_LINK: 5228 (void) snprintf(ptr, lim - ptr, "%s", statep->ls_link); 5229 break; 5230 case LINKPROP_PROPERTY: 5231 (void) snprintf(ptr, lim - ptr, "%s", propname); 5232 break; 5233 case LINKPROP_VALUE: 5234 print_linkprop(linkid, statep, propname, 5235 statep->ls_persist ? DLADM_PROP_VAL_PERSISTENT : 5236 DLADM_PROP_VAL_CURRENT, "%s", &ptr); 5237 /* 5238 * If we failed to query the link property, for example, query 5239 * the persistent value of a non-persistable link property, 5240 * simply skip the output. 5241 */ 5242 if (statep->ls_status != DLADM_STATUS_OK) 5243 goto skip; 5244 ptr = statep->ls_line; 5245 break; 5246 case LINKPROP_PERM: 5247 print_linkprop(linkid, statep, propname, 5248 DLADM_PROP_VAL_PERM, "%s", &ptr); 5249 if (statep->ls_status != DLADM_STATUS_OK) 5250 goto skip; 5251 ptr = statep->ls_line; 5252 break; 5253 case LINKPROP_DEFAULT: 5254 print_linkprop(linkid, statep, propname, 5255 DLADM_PROP_VAL_DEFAULT, "%s", &ptr); 5256 if (statep->ls_status != DLADM_STATUS_OK) 5257 goto skip; 5258 ptr = statep->ls_line; 5259 break; 5260 case LINKPROP_POSSIBLE: 5261 print_linkprop(linkid, statep, propname, 5262 DLADM_PROP_VAL_MODIFIABLE, "%s ", &ptr); 5263 if (statep->ls_status != DLADM_STATUS_OK) 5264 goto skip; 5265 ptr = statep->ls_line; 5266 break; 5267 default: 5268 die("invalid input"); 5269 break; 5270 } 5271 (void) strlcpy(buf, ptr, bufsize); 5272 return (B_TRUE); 5273 skip: 5274 return ((statep->ls_status == DLADM_STATUS_OK) ? 5275 B_TRUE : B_FALSE); 5276 } 5277 5278 static boolean_t 5279 linkprop_is_supported(datalink_id_t linkid, const char *propname, 5280 show_linkprop_state_t *statep) 5281 { 5282 dladm_status_t status; 5283 uint_t valcnt = DLADM_MAX_PROP_VALCNT; 5284 5285 /* if used with -p flag, always print output */ 5286 if (statep->ls_proplist != NULL) 5287 return (B_TRUE); 5288 5289 status = dladm_get_linkprop(handle, linkid, DLADM_PROP_VAL_DEFAULT, 5290 propname, statep->ls_propvals, &valcnt); 5291 5292 if (status == DLADM_STATUS_OK) 5293 return (B_TRUE); 5294 5295 /* 5296 * A system wide default value is not available for the 5297 * property. Check if current value can be retrieved. 5298 */ 5299 status = dladm_get_linkprop(handle, linkid, DLADM_PROP_VAL_CURRENT, 5300 propname, statep->ls_propvals, &valcnt); 5301 5302 return (status == DLADM_STATUS_OK); 5303 } 5304 5305 /* ARGSUSED */ 5306 static int 5307 show_linkprop(dladm_handle_t dh, datalink_id_t linkid, const char *propname, 5308 void *arg) 5309 { 5310 show_linkprop_state_t *statep = arg; 5311 linkprop_args_t ls_arg; 5312 5313 bzero(&ls_arg, sizeof (ls_arg)); 5314 ls_arg.ls_state = statep; 5315 ls_arg.ls_propname = (char *)propname; 5316 ls_arg.ls_linkid = linkid; 5317 5318 /* 5319 * This will need to be fixed when kernel interfaces are added 5320 * to enable walking of all known private properties. For now, 5321 * we are limited to walking persistent private properties only. 5322 */ 5323 if ((propname[0] == '_') && !statep->ls_persist && 5324 (statep->ls_proplist == NULL)) 5325 return (DLADM_WALK_CONTINUE); 5326 if (!statep->ls_parsable && 5327 !linkprop_is_supported(linkid, propname, statep)) 5328 return (DLADM_WALK_CONTINUE); 5329 5330 ofmt_print(statep->ls_ofmt, &ls_arg); 5331 5332 return (DLADM_WALK_CONTINUE); 5333 } 5334 5335 static void 5336 do_show_linkprop(int argc, char **argv, const char *use) 5337 { 5338 int option; 5339 char propstr[DLADM_STRSIZE]; 5340 dladm_arg_list_t *proplist = NULL; 5341 datalink_id_t linkid = DATALINK_ALL_LINKID; 5342 show_linkprop_state_t state; 5343 uint32_t flags = DLADM_OPT_ACTIVE; 5344 dladm_status_t status; 5345 char *fields_str = NULL; 5346 ofmt_handle_t ofmt; 5347 ofmt_status_t oferr; 5348 uint_t ofmtflags = 0; 5349 5350 bzero(propstr, DLADM_STRSIZE); 5351 opterr = 0; 5352 state.ls_propvals = NULL; 5353 state.ls_line = NULL; 5354 state.ls_parsable = B_FALSE; 5355 state.ls_persist = B_FALSE; 5356 state.ls_header = B_TRUE; 5357 state.ls_retstatus = DLADM_STATUS_OK; 5358 5359 while ((option = getopt_long(argc, argv, ":p:cPo:", 5360 prop_longopts, NULL)) != -1) { 5361 switch (option) { 5362 case 'p': 5363 (void) strlcat(propstr, optarg, DLADM_STRSIZE); 5364 if (strlcat(propstr, ",", DLADM_STRSIZE) >= 5365 DLADM_STRSIZE) 5366 die("property list too long '%s'", propstr); 5367 break; 5368 case 'c': 5369 state.ls_parsable = B_TRUE; 5370 break; 5371 case 'P': 5372 state.ls_persist = B_TRUE; 5373 flags = DLADM_OPT_PERSIST; 5374 break; 5375 case 'o': 5376 fields_str = optarg; 5377 break; 5378 default: 5379 die_opterr(optopt, option, use); 5380 break; 5381 } 5382 } 5383 5384 if (optind == (argc - 1)) { 5385 if ((status = dladm_name2info(handle, argv[optind], &linkid, 5386 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 5387 die_dlerr(status, "link %s is not valid", argv[optind]); 5388 } 5389 } else if (optind != argc) { 5390 usage(); 5391 } 5392 5393 if (dladm_parse_link_props(propstr, &proplist, B_TRUE) 5394 != DLADM_STATUS_OK) 5395 die("invalid link properties specified"); 5396 state.ls_proplist = proplist; 5397 state.ls_status = DLADM_STATUS_OK; 5398 5399 if (state.ls_parsable) 5400 ofmtflags |= OFMT_PARSABLE; 5401 oferr = ofmt_open(fields_str, linkprop_fields, ofmtflags, 0, &ofmt); 5402 dladm_ofmt_check(oferr, state.ls_parsable, ofmt); 5403 state.ls_ofmt = ofmt; 5404 5405 if (linkid == DATALINK_ALL_LINKID) { 5406 (void) dladm_walk_datalink_id(show_linkprop_onelink, handle, 5407 &state, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, flags); 5408 } else { 5409 (void) show_linkprop_onelink(handle, linkid, &state); 5410 } 5411 ofmt_close(ofmt); 5412 dladm_free_props(proplist); 5413 5414 if (state.ls_retstatus != DLADM_STATUS_OK) { 5415 dladm_close(handle); 5416 exit(EXIT_FAILURE); 5417 } 5418 } 5419 5420 static int 5421 show_linkprop_onelink(dladm_handle_t hdl, datalink_id_t linkid, void *arg) 5422 { 5423 int i; 5424 char *buf; 5425 uint32_t flags; 5426 dladm_arg_list_t *proplist = NULL; 5427 show_linkprop_state_t *statep = arg; 5428 dlpi_handle_t dh = NULL; 5429 5430 statep->ls_status = DLADM_STATUS_OK; 5431 5432 if (dladm_datalink_id2info(hdl, linkid, &flags, NULL, NULL, 5433 statep->ls_link, MAXLINKNAMELEN) != DLADM_STATUS_OK) { 5434 statep->ls_status = DLADM_STATUS_NOTFOUND; 5435 return (DLADM_WALK_CONTINUE); 5436 } 5437 5438 if ((statep->ls_persist && !(flags & DLADM_OPT_PERSIST)) || 5439 (!statep->ls_persist && !(flags & DLADM_OPT_ACTIVE))) { 5440 statep->ls_status = DLADM_STATUS_BADARG; 5441 return (DLADM_WALK_CONTINUE); 5442 } 5443 5444 proplist = statep->ls_proplist; 5445 5446 /* 5447 * When some WiFi links are opened for the first time, their hardware 5448 * automatically scans for APs and does other slow operations. Thus, 5449 * if there are no open links, the retrieval of link properties 5450 * (below) will proceed slowly unless we hold the link open. 5451 * 5452 * Note that failure of dlpi_open() does not necessarily mean invalid 5453 * link properties, because dlpi_open() may fail because of incorrect 5454 * autopush configuration. Therefore, we ingore the return value of 5455 * dlpi_open(). 5456 */ 5457 if (!statep->ls_persist) 5458 (void) dlpi_open(statep->ls_link, &dh, 0); 5459 5460 buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) * 5461 DLADM_MAX_PROP_VALCNT + MAX_PROP_LINE); 5462 if (buf == NULL) 5463 die("insufficient memory"); 5464 5465 statep->ls_propvals = (char **)(void *)buf; 5466 for (i = 0; i < DLADM_MAX_PROP_VALCNT; i++) { 5467 statep->ls_propvals[i] = buf + 5468 sizeof (char *) * DLADM_MAX_PROP_VALCNT + 5469 i * DLADM_PROP_VAL_MAX; 5470 } 5471 statep->ls_line = buf + 5472 (sizeof (char *) + DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT; 5473 5474 if (proplist != NULL) { 5475 for (i = 0; i < proplist->al_count; i++) { 5476 (void) show_linkprop(hdl, linkid, 5477 proplist->al_info[i].ai_name, statep); 5478 } 5479 } else { 5480 (void) dladm_walk_linkprop(hdl, linkid, statep, 5481 show_linkprop); 5482 } 5483 if (dh != NULL) 5484 dlpi_close(dh); 5485 free(buf); 5486 return (DLADM_WALK_CONTINUE); 5487 } 5488 5489 static dladm_status_t 5490 set_linkprop_persist(datalink_id_t linkid, const char *prop_name, 5491 char **prop_val, uint_t val_cnt, boolean_t reset) 5492 { 5493 dladm_status_t status; 5494 5495 status = dladm_set_linkprop(handle, linkid, prop_name, prop_val, 5496 val_cnt, DLADM_OPT_PERSIST); 5497 5498 if (status != DLADM_STATUS_OK) { 5499 warn_dlerr(status, "cannot persistently %s link property '%s'", 5500 reset ? "reset" : "set", prop_name); 5501 } 5502 return (status); 5503 } 5504 5505 static int 5506 reset_one_linkprop(dladm_handle_t dh, datalink_id_t linkid, 5507 const char *propname, void *arg) 5508 { 5509 set_linkprop_state_t *statep = arg; 5510 dladm_status_t status; 5511 5512 status = dladm_set_linkprop(dh, linkid, propname, NULL, 0, 5513 DLADM_OPT_ACTIVE); 5514 if (status != DLADM_STATUS_OK) { 5515 warn_dlerr(status, "cannot reset link property '%s' on '%s'", 5516 propname, statep->ls_name); 5517 } 5518 if (!statep->ls_temp) { 5519 dladm_status_t s; 5520 5521 s = set_linkprop_persist(linkid, propname, NULL, 0, 5522 statep->ls_reset); 5523 if (s != DLADM_STATUS_OK) 5524 status = s; 5525 } 5526 if (status != DLADM_STATUS_OK) 5527 statep->ls_status = status; 5528 5529 return (DLADM_WALK_CONTINUE); 5530 } 5531 5532 static void 5533 set_linkprop(int argc, char **argv, boolean_t reset, const char *use) 5534 { 5535 int i, option; 5536 char errmsg[DLADM_STRSIZE]; 5537 char *altroot = NULL; 5538 datalink_id_t linkid; 5539 boolean_t temp = B_FALSE; 5540 dladm_status_t status = DLADM_STATUS_OK; 5541 char propstr[DLADM_STRSIZE]; 5542 dladm_arg_list_t *proplist = NULL; 5543 5544 opterr = 0; 5545 bzero(propstr, DLADM_STRSIZE); 5546 5547 while ((option = getopt_long(argc, argv, ":p:R:t", 5548 prop_longopts, NULL)) != -1) { 5549 switch (option) { 5550 case 'p': 5551 (void) strlcat(propstr, optarg, DLADM_STRSIZE); 5552 if (strlcat(propstr, ",", DLADM_STRSIZE) >= 5553 DLADM_STRSIZE) 5554 die("property list too long '%s'", propstr); 5555 break; 5556 case 't': 5557 temp = B_TRUE; 5558 break; 5559 case 'R': 5560 altroot = optarg; 5561 break; 5562 default: 5563 die_opterr(optopt, option, use); 5564 5565 } 5566 } 5567 5568 /* get link name (required last argument) */ 5569 if (optind != (argc - 1)) 5570 usage(); 5571 5572 if (dladm_parse_link_props(propstr, &proplist, reset) != 5573 DLADM_STATUS_OK) 5574 die("invalid link properties specified"); 5575 5576 if (proplist == NULL && !reset) 5577 die("link property must be specified"); 5578 5579 if (altroot != NULL) { 5580 dladm_free_props(proplist); 5581 altroot_cmd(altroot, argc, argv); 5582 } 5583 5584 status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL, 5585 NULL); 5586 if (status != DLADM_STATUS_OK) 5587 die_dlerr(status, "link %s is not valid", argv[optind]); 5588 5589 if (proplist == NULL) { 5590 set_linkprop_state_t state; 5591 5592 state.ls_name = argv[optind]; 5593 state.ls_reset = reset; 5594 state.ls_temp = temp; 5595 state.ls_status = DLADM_STATUS_OK; 5596 5597 (void) dladm_walk_linkprop(handle, linkid, &state, 5598 reset_one_linkprop); 5599 5600 status = state.ls_status; 5601 goto done; 5602 } 5603 5604 for (i = 0; i < proplist->al_count; i++) { 5605 dladm_arg_info_t *aip = &proplist->al_info[i]; 5606 char **val; 5607 uint_t count; 5608 dladm_status_t s; 5609 5610 if (reset) { 5611 val = NULL; 5612 count = 0; 5613 } else { 5614 val = aip->ai_val; 5615 count = aip->ai_count; 5616 if (count == 0) { 5617 warn("no value specified for '%s'", 5618 aip->ai_name); 5619 status = DLADM_STATUS_BADARG; 5620 continue; 5621 } 5622 } 5623 s = dladm_set_linkprop(handle, linkid, aip->ai_name, val, count, 5624 DLADM_OPT_ACTIVE); 5625 if (s == DLADM_STATUS_OK) { 5626 if (!temp) { 5627 s = set_linkprop_persist(linkid, 5628 aip->ai_name, val, count, reset); 5629 if (s != DLADM_STATUS_OK) 5630 status = s; 5631 } 5632 continue; 5633 } 5634 status = s; 5635 switch (s) { 5636 case DLADM_STATUS_NOTFOUND: 5637 warn("invalid link property '%s'", aip->ai_name); 5638 break; 5639 case DLADM_STATUS_BADVAL: { 5640 int j; 5641 char *ptr, *lim; 5642 char **propvals = NULL; 5643 uint_t valcnt = DLADM_MAX_PROP_VALCNT; 5644 5645 ptr = malloc((sizeof (char *) + 5646 DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT + 5647 MAX_PROP_LINE); 5648 5649 propvals = (char **)(void *)ptr; 5650 if (propvals == NULL) 5651 die("insufficient memory"); 5652 5653 for (j = 0; j < DLADM_MAX_PROP_VALCNT; j++) { 5654 propvals[j] = ptr + sizeof (char *) * 5655 DLADM_MAX_PROP_VALCNT + 5656 j * DLADM_PROP_VAL_MAX; 5657 } 5658 s = dladm_get_linkprop(handle, linkid, 5659 DLADM_PROP_VAL_MODIFIABLE, aip->ai_name, propvals, 5660 &valcnt); 5661 5662 if (s != DLADM_STATUS_OK) { 5663 warn_dlerr(status, "cannot set link property " 5664 "'%s' on '%s'", aip->ai_name, argv[optind]); 5665 free(propvals); 5666 break; 5667 } 5668 5669 ptr = errmsg; 5670 lim = ptr + DLADM_STRSIZE; 5671 *ptr = '\0'; 5672 for (j = 0; j < valcnt; j++) { 5673 ptr += snprintf(ptr, lim - ptr, "%s,", 5674 propvals[j]); 5675 if (ptr >= lim) 5676 break; 5677 } 5678 if (ptr > errmsg) { 5679 *(ptr - 1) = '\0'; 5680 warn("link property '%s' must be one of: %s", 5681 aip->ai_name, errmsg); 5682 } else 5683 warn("invalid link property '%s'", *val); 5684 free(propvals); 5685 break; 5686 } 5687 default: 5688 if (reset) { 5689 warn_dlerr(status, "cannot reset link property " 5690 "'%s' on '%s'", aip->ai_name, argv[optind]); 5691 } else { 5692 warn_dlerr(status, "cannot set link property " 5693 "'%s' on '%s'", aip->ai_name, argv[optind]); 5694 } 5695 break; 5696 } 5697 } 5698 done: 5699 dladm_free_props(proplist); 5700 if (status != DLADM_STATUS_OK) { 5701 dladm_close(handle); 5702 exit(1); 5703 } 5704 } 5705 5706 static void 5707 do_set_linkprop(int argc, char **argv, const char *use) 5708 { 5709 set_linkprop(argc, argv, B_FALSE, use); 5710 } 5711 5712 static void 5713 do_reset_linkprop(int argc, char **argv, const char *use) 5714 { 5715 set_linkprop(argc, argv, B_TRUE, use); 5716 } 5717 5718 static int 5719 convert_secobj(char *buf, uint_t len, uint8_t *obj_val, uint_t *obj_lenp, 5720 dladm_secobj_class_t class) 5721 { 5722 int error = 0; 5723 5724 if (class == DLADM_SECOBJ_CLASS_WPA) { 5725 if (len < 8 || len > 63) 5726 return (EINVAL); 5727 (void) memcpy(obj_val, buf, len); 5728 *obj_lenp = len; 5729 return (error); 5730 } 5731 5732 if (class == DLADM_SECOBJ_CLASS_WEP) { 5733 switch (len) { 5734 case 5: /* ASCII key sizes */ 5735 case 13: 5736 (void) memcpy(obj_val, buf, len); 5737 *obj_lenp = len; 5738 break; 5739 case 10: /* Hex key sizes, not preceded by 0x */ 5740 case 26: 5741 error = hexascii_to_octet(buf, len, obj_val, obj_lenp); 5742 break; 5743 case 12: /* Hex key sizes, preceded by 0x */ 5744 case 28: 5745 if (strncmp(buf, "0x", 2) != 0) 5746 return (EINVAL); 5747 error = hexascii_to_octet(buf + 2, len - 2, 5748 obj_val, obj_lenp); 5749 break; 5750 default: 5751 return (EINVAL); 5752 } 5753 return (error); 5754 } 5755 5756 return (ENOENT); 5757 } 5758 5759 static void 5760 defersig(int sig) 5761 { 5762 signalled = sig; 5763 } 5764 5765 static int 5766 get_secobj_from_tty(uint_t try, const char *objname, char *buf) 5767 { 5768 uint_t len = 0; 5769 int c; 5770 struct termios stored, current; 5771 void (*sigfunc)(int); 5772 5773 /* 5774 * Turn off echo -- but before we do so, defer SIGINT handling 5775 * so that a ^C doesn't leave the terminal corrupted. 5776 */ 5777 sigfunc = signal(SIGINT, defersig); 5778 (void) fflush(stdin); 5779 (void) tcgetattr(0, &stored); 5780 current = stored; 5781 current.c_lflag &= ~(ICANON|ECHO); 5782 current.c_cc[VTIME] = 0; 5783 current.c_cc[VMIN] = 1; 5784 (void) tcsetattr(0, TCSANOW, ¤t); 5785 again: 5786 if (try == 1) 5787 (void) printf(gettext("provide value for '%s': "), objname); 5788 else 5789 (void) printf(gettext("confirm value for '%s': "), objname); 5790 5791 (void) fflush(stdout); 5792 while (signalled == 0) { 5793 c = getchar(); 5794 if (c == '\n' || c == '\r') { 5795 if (len != 0) 5796 break; 5797 (void) putchar('\n'); 5798 goto again; 5799 } 5800 5801 buf[len++] = c; 5802 if (len >= DLADM_SECOBJ_VAL_MAX - 1) 5803 break; 5804 (void) putchar('*'); 5805 } 5806 5807 (void) putchar('\n'); 5808 (void) fflush(stdin); 5809 5810 /* 5811 * Restore terminal setting and handle deferred signals. 5812 */ 5813 (void) tcsetattr(0, TCSANOW, &stored); 5814 5815 (void) signal(SIGINT, sigfunc); 5816 if (signalled != 0) 5817 (void) kill(getpid(), signalled); 5818 5819 return (len); 5820 } 5821 5822 static int 5823 get_secobj_val(char *obj_name, uint8_t *obj_val, uint_t *obj_lenp, 5824 dladm_secobj_class_t class, FILE *filep) 5825 { 5826 int rval; 5827 uint_t len, len2; 5828 char buf[DLADM_SECOBJ_VAL_MAX], buf2[DLADM_SECOBJ_VAL_MAX]; 5829 5830 if (filep == NULL) { 5831 len = get_secobj_from_tty(1, obj_name, buf); 5832 rval = convert_secobj(buf, len, obj_val, obj_lenp, class); 5833 if (rval == 0) { 5834 len2 = get_secobj_from_tty(2, obj_name, buf2); 5835 if (len != len2 || memcmp(buf, buf2, len) != 0) 5836 rval = ENOTSUP; 5837 } 5838 return (rval); 5839 } else { 5840 for (;;) { 5841 if (fgets(buf, sizeof (buf), filep) == NULL) 5842 break; 5843 if (isspace(buf[0])) 5844 continue; 5845 5846 len = strlen(buf); 5847 if (buf[len - 1] == '\n') { 5848 buf[len - 1] = '\0'; 5849 len--; 5850 } 5851 break; 5852 } 5853 (void) fclose(filep); 5854 } 5855 return (convert_secobj(buf, len, obj_val, obj_lenp, class)); 5856 } 5857 5858 static boolean_t 5859 check_auth(const char *auth) 5860 { 5861 struct passwd *pw; 5862 5863 if ((pw = getpwuid(getuid())) == NULL) 5864 return (B_FALSE); 5865 5866 return (chkauthattr(auth, pw->pw_name) != 0); 5867 } 5868 5869 static void 5870 audit_secobj(char *auth, char *class, char *obj, 5871 boolean_t success, boolean_t create) 5872 { 5873 adt_session_data_t *ah; 5874 adt_event_data_t *event; 5875 au_event_t flag; 5876 char *errstr; 5877 5878 if (create) { 5879 flag = ADT_dladm_create_secobj; 5880 errstr = "ADT_dladm_create_secobj"; 5881 } else { 5882 flag = ADT_dladm_delete_secobj; 5883 errstr = "ADT_dladm_delete_secobj"; 5884 } 5885 5886 if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) 5887 die("adt_start_session: %s", strerror(errno)); 5888 5889 if ((event = adt_alloc_event(ah, flag)) == NULL) 5890 die("adt_alloc_event (%s): %s", errstr, strerror(errno)); 5891 5892 /* fill in audit info */ 5893 if (create) { 5894 event->adt_dladm_create_secobj.auth_used = auth; 5895 event->adt_dladm_create_secobj.obj_class = class; 5896 event->adt_dladm_create_secobj.obj_name = obj; 5897 } else { 5898 event->adt_dladm_delete_secobj.auth_used = auth; 5899 event->adt_dladm_delete_secobj.obj_class = class; 5900 event->adt_dladm_delete_secobj.obj_name = obj; 5901 } 5902 5903 if (success) { 5904 if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) { 5905 die("adt_put_event (%s, success): %s", errstr, 5906 strerror(errno)); 5907 } 5908 } else { 5909 if (adt_put_event(event, ADT_FAILURE, 5910 ADT_FAIL_VALUE_AUTH) != 0) { 5911 die("adt_put_event: (%s, failure): %s", errstr, 5912 strerror(errno)); 5913 } 5914 } 5915 5916 adt_free_event(event); 5917 (void) adt_end_session(ah); 5918 } 5919 5920 #define MAX_SECOBJS 32 5921 #define MAX_SECOBJ_NAMELEN 32 5922 static void 5923 do_create_secobj(int argc, char **argv, const char *use) 5924 { 5925 int option, rval; 5926 FILE *filep = NULL; 5927 char *obj_name = NULL; 5928 char *class_name = NULL; 5929 uint8_t obj_val[DLADM_SECOBJ_VAL_MAX]; 5930 uint_t obj_len; 5931 boolean_t success, temp = B_FALSE; 5932 dladm_status_t status; 5933 dladm_secobj_class_t class = -1; 5934 uid_t euid; 5935 5936 opterr = 0; 5937 (void) memset(obj_val, 0, DLADM_SECOBJ_VAL_MAX); 5938 while ((option = getopt_long(argc, argv, ":f:c:R:t", 5939 wifi_longopts, NULL)) != -1) { 5940 switch (option) { 5941 case 'f': 5942 euid = geteuid(); 5943 (void) seteuid(getuid()); 5944 filep = fopen(optarg, "r"); 5945 if (filep == NULL) { 5946 die("cannot open %s: %s", optarg, 5947 strerror(errno)); 5948 } 5949 (void) seteuid(euid); 5950 break; 5951 case 'c': 5952 class_name = optarg; 5953 status = dladm_str2secobjclass(optarg, &class); 5954 if (status != DLADM_STATUS_OK) { 5955 die("invalid secure object class '%s', " 5956 "valid values are: wep, wpa", optarg); 5957 } 5958 break; 5959 case 't': 5960 temp = B_TRUE; 5961 break; 5962 case 'R': 5963 status = dladm_set_rootdir(optarg); 5964 if (status != DLADM_STATUS_OK) { 5965 die_dlerr(status, "invalid directory " 5966 "specified"); 5967 } 5968 break; 5969 default: 5970 die_opterr(optopt, option, use); 5971 break; 5972 } 5973 } 5974 5975 if (optind == (argc - 1)) 5976 obj_name = argv[optind]; 5977 else if (optind != argc) 5978 usage(); 5979 5980 if (class == -1) 5981 die("secure object class required"); 5982 5983 if (obj_name == NULL) 5984 die("secure object name required"); 5985 5986 if (!dladm_valid_secobj_name(obj_name)) 5987 die("invalid secure object name '%s'", obj_name); 5988 5989 success = check_auth(LINK_SEC_AUTH); 5990 audit_secobj(LINK_SEC_AUTH, class_name, obj_name, success, B_TRUE); 5991 if (!success) 5992 die("authorization '%s' is required", LINK_SEC_AUTH); 5993 5994 rval = get_secobj_val(obj_name, obj_val, &obj_len, class, filep); 5995 if (rval != 0) { 5996 switch (rval) { 5997 case ENOENT: 5998 die("invalid secure object class"); 5999 break; 6000 case EINVAL: 6001 die("invalid secure object value"); 6002 break; 6003 case ENOTSUP: 6004 die("verification failed"); 6005 break; 6006 default: 6007 die("invalid secure object: %s", strerror(rval)); 6008 break; 6009 } 6010 } 6011 6012 status = dladm_set_secobj(handle, obj_name, class, obj_val, obj_len, 6013 DLADM_OPT_CREATE | DLADM_OPT_ACTIVE); 6014 if (status != DLADM_STATUS_OK) { 6015 die_dlerr(status, "could not create secure object '%s'", 6016 obj_name); 6017 } 6018 if (temp) 6019 return; 6020 6021 status = dladm_set_secobj(handle, obj_name, class, obj_val, obj_len, 6022 DLADM_OPT_PERSIST); 6023 if (status != DLADM_STATUS_OK) { 6024 warn_dlerr(status, "could not persistently create secure " 6025 "object '%s'", obj_name); 6026 } 6027 } 6028 6029 static void 6030 do_delete_secobj(int argc, char **argv, const char *use) 6031 { 6032 int i, option; 6033 boolean_t temp = B_FALSE; 6034 boolean_t success; 6035 dladm_status_t status, pstatus; 6036 int nfields = 1; 6037 char *field, *token, *lasts = NULL, c; 6038 6039 opterr = 0; 6040 status = pstatus = DLADM_STATUS_OK; 6041 while ((option = getopt_long(argc, argv, ":R:t", 6042 wifi_longopts, NULL)) != -1) { 6043 switch (option) { 6044 case 't': 6045 temp = B_TRUE; 6046 break; 6047 case 'R': 6048 status = dladm_set_rootdir(optarg); 6049 if (status != DLADM_STATUS_OK) { 6050 die_dlerr(status, "invalid directory " 6051 "specified"); 6052 } 6053 break; 6054 default: 6055 die_opterr(optopt, option, use); 6056 break; 6057 } 6058 } 6059 6060 if (optind == (argc - 1)) { 6061 token = argv[optind]; 6062 if (token == NULL) 6063 die("secure object name required"); 6064 while ((c = *token++) != NULL) { 6065 if (c == ',') 6066 nfields++; 6067 } 6068 token = strdup(argv[optind]); 6069 if (token == NULL) 6070 die("no memory"); 6071 } else if (optind != argc) 6072 usage(); 6073 6074 success = check_auth(LINK_SEC_AUTH); 6075 audit_secobj(LINK_SEC_AUTH, "unknown", argv[optind], success, B_FALSE); 6076 if (!success) 6077 die("authorization '%s' is required", LINK_SEC_AUTH); 6078 6079 for (i = 0; i < nfields; i++) { 6080 6081 field = strtok_r(token, ",", &lasts); 6082 token = NULL; 6083 status = dladm_unset_secobj(handle, field, DLADM_OPT_ACTIVE); 6084 if (!temp) { 6085 pstatus = dladm_unset_secobj(handle, field, 6086 DLADM_OPT_PERSIST); 6087 } else { 6088 pstatus = DLADM_STATUS_OK; 6089 } 6090 6091 if (status != DLADM_STATUS_OK) { 6092 warn_dlerr(status, "could not delete secure object " 6093 "'%s'", field); 6094 } 6095 if (pstatus != DLADM_STATUS_OK) { 6096 warn_dlerr(pstatus, "could not persistently delete " 6097 "secure object '%s'", field); 6098 } 6099 } 6100 free(token); 6101 6102 if (status != DLADM_STATUS_OK || pstatus != DLADM_STATUS_OK) { 6103 dladm_close(handle); 6104 exit(1); 6105 } 6106 } 6107 6108 typedef struct show_secobj_state { 6109 boolean_t ss_persist; 6110 boolean_t ss_parsable; 6111 boolean_t ss_header; 6112 ofmt_handle_t ss_ofmt; 6113 } show_secobj_state_t; 6114 6115 6116 static boolean_t 6117 show_secobj(dladm_handle_t dh, void *arg, const char *obj_name) 6118 { 6119 uint_t obj_len = DLADM_SECOBJ_VAL_MAX; 6120 uint8_t obj_val[DLADM_SECOBJ_VAL_MAX]; 6121 char buf[DLADM_STRSIZE]; 6122 uint_t flags = 0; 6123 dladm_secobj_class_t class; 6124 show_secobj_state_t *statep = arg; 6125 dladm_status_t status; 6126 secobj_fields_buf_t sbuf; 6127 6128 bzero(&sbuf, sizeof (secobj_fields_buf_t)); 6129 if (statep->ss_persist) 6130 flags |= DLADM_OPT_PERSIST; 6131 6132 status = dladm_get_secobj(dh, obj_name, &class, obj_val, &obj_len, 6133 flags); 6134 if (status != DLADM_STATUS_OK) 6135 die_dlerr(status, "cannot get secure object '%s'", obj_name); 6136 6137 (void) snprintf(sbuf.ss_obj_name, sizeof (sbuf.ss_obj_name), 6138 obj_name); 6139 (void) dladm_secobjclass2str(class, buf); 6140 (void) snprintf(sbuf.ss_class, sizeof (sbuf.ss_class), "%s", buf); 6141 if (getuid() == 0) { 6142 char val[DLADM_SECOBJ_VAL_MAX * 2]; 6143 uint_t len = sizeof (val); 6144 6145 if (octet_to_hexascii(obj_val, obj_len, val, &len) == 0) 6146 (void) snprintf(sbuf.ss_val, 6147 sizeof (sbuf.ss_val), "%s", val); 6148 } 6149 ofmt_print(statep->ss_ofmt, &sbuf); 6150 return (B_TRUE); 6151 } 6152 6153 static void 6154 do_show_secobj(int argc, char **argv, const char *use) 6155 { 6156 int option; 6157 show_secobj_state_t state; 6158 dladm_status_t status; 6159 boolean_t o_arg = B_FALSE; 6160 uint_t i; 6161 uint_t flags; 6162 char *fields_str = NULL; 6163 char *def_fields = "object,class"; 6164 char *all_fields = "object,class,value"; 6165 char *field, *token, *lasts = NULL, c; 6166 ofmt_handle_t ofmt; 6167 ofmt_status_t oferr; 6168 uint_t ofmtflags = 0; 6169 6170 opterr = 0; 6171 bzero(&state, sizeof (state)); 6172 state.ss_parsable = B_FALSE; 6173 fields_str = def_fields; 6174 state.ss_persist = B_FALSE; 6175 state.ss_parsable = B_FALSE; 6176 state.ss_header = B_TRUE; 6177 while ((option = getopt_long(argc, argv, ":pPo:", 6178 wifi_longopts, NULL)) != -1) { 6179 switch (option) { 6180 case 'p': 6181 state.ss_parsable = B_TRUE; 6182 break; 6183 case 'P': 6184 state.ss_persist = B_TRUE; 6185 break; 6186 case 'o': 6187 o_arg = B_TRUE; 6188 if (strcasecmp(optarg, "all") == 0) 6189 fields_str = all_fields; 6190 else 6191 fields_str = optarg; 6192 break; 6193 default: 6194 die_opterr(optopt, option, use); 6195 break; 6196 } 6197 } 6198 6199 if (state.ss_parsable && !o_arg) 6200 die("option -c requires -o"); 6201 6202 if (state.ss_parsable && fields_str == all_fields) 6203 die("\"-o all\" is invalid with -p"); 6204 6205 if (state.ss_parsable) 6206 ofmtflags |= OFMT_PARSABLE; 6207 oferr = ofmt_open(fields_str, secobj_fields, ofmtflags, 0, &ofmt); 6208 dladm_ofmt_check(oferr, state.ss_parsable, ofmt); 6209 state.ss_ofmt = ofmt; 6210 6211 flags = state.ss_persist ? DLADM_OPT_PERSIST : 0; 6212 6213 if (optind == (argc - 1)) { 6214 uint_t obj_fields = 1; 6215 6216 token = argv[optind]; 6217 if (token == NULL) 6218 die("secure object name required"); 6219 while ((c = *token++) != NULL) { 6220 if (c == ',') 6221 obj_fields++; 6222 } 6223 token = strdup(argv[optind]); 6224 if (token == NULL) 6225 die("no memory"); 6226 for (i = 0; i < obj_fields; i++) { 6227 field = strtok_r(token, ",", &lasts); 6228 token = NULL; 6229 if (!show_secobj(handle, &state, field)) 6230 break; 6231 } 6232 free(token); 6233 ofmt_close(ofmt); 6234 return; 6235 } else if (optind != argc) 6236 usage(); 6237 6238 status = dladm_walk_secobj(handle, &state, show_secobj, flags); 6239 6240 if (status != DLADM_STATUS_OK) 6241 die_dlerr(status, "show-secobj"); 6242 ofmt_close(ofmt); 6243 } 6244 6245 /*ARGSUSED*/ 6246 static int 6247 i_dladm_init_linkprop(dladm_handle_t dh, datalink_id_t linkid, void *arg) 6248 { 6249 (void) dladm_init_linkprop(dh, linkid, B_TRUE); 6250 return (DLADM_WALK_CONTINUE); 6251 } 6252 6253 /*ARGSUSED*/ 6254 void 6255 do_init_linkprop(int argc, char **argv, const char *use) 6256 { 6257 int option; 6258 dladm_status_t status; 6259 datalink_id_t linkid = DATALINK_ALL_LINKID; 6260 datalink_media_t media = DATALINK_ANY_MEDIATYPE; 6261 uint_t any_media = B_TRUE; 6262 6263 opterr = 0; 6264 while ((option = getopt(argc, argv, ":w")) != -1) { 6265 switch (option) { 6266 case 'w': 6267 media = DL_WIFI; 6268 any_media = B_FALSE; 6269 break; 6270 default: 6271 /* 6272 * Because init-linkprop is not a public command, 6273 * print the usage instead. 6274 */ 6275 usage(); 6276 break; 6277 } 6278 } 6279 6280 if (optind == (argc - 1)) { 6281 if ((status = dladm_name2info(handle, argv[optind], &linkid, 6282 NULL, NULL, NULL)) != DLADM_STATUS_OK) 6283 die_dlerr(status, "link %s is not valid", argv[optind]); 6284 } else if (optind != argc) { 6285 usage(); 6286 } 6287 6288 if (linkid == DATALINK_ALL_LINKID) { 6289 /* 6290 * linkprops of links of other classes have been initialized as 6291 * part of the dladm up-xxx operation. 6292 */ 6293 (void) dladm_walk_datalink_id(i_dladm_init_linkprop, handle, 6294 NULL, DATALINK_CLASS_PHYS, media, DLADM_OPT_PERSIST); 6295 } else { 6296 (void) dladm_init_linkprop(handle, linkid, any_media); 6297 } 6298 } 6299 6300 static void 6301 do_show_ether(int argc, char **argv, const char *use) 6302 { 6303 int option; 6304 datalink_id_t linkid; 6305 print_ether_state_t state; 6306 char *fields_str = NULL; 6307 ofmt_handle_t ofmt; 6308 ofmt_status_t oferr; 6309 uint_t ofmtflags = 0; 6310 6311 bzero(&state, sizeof (state)); 6312 state.es_link = NULL; 6313 state.es_parsable = B_FALSE; 6314 6315 while ((option = getopt_long(argc, argv, "o:px", 6316 showeth_lopts, NULL)) != -1) { 6317 switch (option) { 6318 case 'x': 6319 state.es_extended = B_TRUE; 6320 break; 6321 case 'p': 6322 state.es_parsable = B_TRUE; 6323 break; 6324 case 'o': 6325 fields_str = optarg; 6326 break; 6327 default: 6328 die_opterr(optopt, option, use); 6329 break; 6330 } 6331 } 6332 6333 if (optind == (argc - 1)) 6334 state.es_link = argv[optind]; 6335 6336 if (state.es_parsable) 6337 ofmtflags |= OFMT_PARSABLE; 6338 oferr = ofmt_open(fields_str, ether_fields, ofmtflags, 6339 DLADM_DEFAULT_COL, &ofmt); 6340 dladm_ofmt_check(oferr, state.es_parsable, ofmt); 6341 state.es_ofmt = ofmt; 6342 6343 if (state.es_link == NULL) { 6344 (void) dladm_walk_datalink_id(show_etherprop, handle, &state, 6345 DATALINK_CLASS_PHYS, DL_ETHER, DLADM_OPT_ACTIVE); 6346 } else { 6347 if (!link_is_ether(state.es_link, &linkid)) 6348 die("invalid link specified"); 6349 (void) show_etherprop(handle, linkid, &state); 6350 } 6351 ofmt_close(ofmt); 6352 } 6353 6354 static int 6355 show_etherprop(dladm_handle_t dh, datalink_id_t linkid, void *arg) 6356 { 6357 print_ether_state_t *statep = arg; 6358 ether_fields_buf_t ebuf; 6359 dladm_ether_info_t eattr; 6360 dladm_status_t status; 6361 6362 bzero(&ebuf, sizeof (ether_fields_buf_t)); 6363 if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, 6364 ebuf.eth_link, sizeof (ebuf.eth_link)) != DLADM_STATUS_OK) { 6365 return (DLADM_WALK_CONTINUE); 6366 } 6367 6368 status = dladm_ether_info(dh, linkid, &eattr); 6369 if (status != DLADM_STATUS_OK) 6370 goto cleanup; 6371 6372 (void) strlcpy(ebuf.eth_ptype, "current", sizeof (ebuf.eth_ptype)); 6373 6374 (void) dladm_ether_autoneg2str(ebuf.eth_autoneg, 6375 sizeof (ebuf.eth_autoneg), &eattr, CURRENT); 6376 (void) dladm_ether_pause2str(ebuf.eth_pause, 6377 sizeof (ebuf.eth_pause), &eattr, CURRENT); 6378 (void) dladm_ether_spdx2str(ebuf.eth_spdx, 6379 sizeof (ebuf.eth_spdx), &eattr, CURRENT); 6380 (void) strlcpy(ebuf.eth_state, 6381 dladm_linkstate2str(eattr.lei_state, ebuf.eth_state), 6382 sizeof (ebuf.eth_state)); 6383 (void) strlcpy(ebuf.eth_rem_fault, 6384 (eattr.lei_attr[CURRENT].le_fault ? "fault" : "none"), 6385 sizeof (ebuf.eth_rem_fault)); 6386 6387 ofmt_print(statep->es_ofmt, &ebuf); 6388 6389 if (statep->es_extended) 6390 show_ether_xprop(arg, &eattr); 6391 6392 cleanup: 6393 dladm_ether_info_done(&eattr); 6394 return (DLADM_WALK_CONTINUE); 6395 } 6396 6397 /* ARGSUSED */ 6398 static void 6399 do_init_secobj(int argc, char **argv, const char *use) 6400 { 6401 dladm_status_t status; 6402 6403 status = dladm_init_secobj(handle); 6404 if (status != DLADM_STATUS_OK) 6405 die_dlerr(status, "secure object initialization failed"); 6406 } 6407 6408 /* 6409 * "-R" option support. It is used for live upgrading. Append dladm commands 6410 * to a upgrade script which will be run when the alternative root boots up: 6411 * 6412 * - If the /etc/dladm/datalink.conf file exists on the alternative root, 6413 * append dladm commands to the <altroot>/var/svc/profile/upgrade_datalink 6414 * script. This script will be run as part of the network/physical service. 6415 * We cannot defer this to /var/svc/profile/upgrade because then the 6416 * configuration will not be able to take effect before network/physical 6417 * plumbs various interfaces. 6418 * 6419 * - If the /etc/dladm/datalink.conf file does not exist on the alternative 6420 * root, append dladm commands to the <altroot>/var/svc/profile/upgrade script, 6421 * which will be run in the manifest-import service. 6422 * 6423 * Note that the SMF team is considering to move the manifest-import service 6424 * to be run at the very begining of boot. Once that is done, the need for 6425 * the /var/svc/profile/upgrade_datalink script will not exist any more. 6426 */ 6427 static void 6428 altroot_cmd(char *altroot, int argc, char *argv[]) 6429 { 6430 char path[MAXPATHLEN]; 6431 struct stat stbuf; 6432 FILE *fp; 6433 int i; 6434 6435 /* 6436 * Check for the existence of the /etc/dladm/datalink.conf 6437 * configuration file, and determine the name of script file. 6438 */ 6439 (void) snprintf(path, MAXPATHLEN, "/%s/etc/dladm/datalink.conf", 6440 altroot); 6441 if (stat(path, &stbuf) < 0) { 6442 (void) snprintf(path, MAXPATHLEN, "/%s/%s", altroot, 6443 SMF_UPGRADE_FILE); 6444 } else { 6445 (void) snprintf(path, MAXPATHLEN, "/%s/%s", altroot, 6446 SMF_UPGRADEDATALINK_FILE); 6447 } 6448 6449 if ((fp = fopen(path, "a+")) == NULL) 6450 die("operation not supported on %s", altroot); 6451 6452 (void) fprintf(fp, "/sbin/dladm "); 6453 for (i = 0; i < argc; i++) { 6454 /* 6455 * Directly write to the file if it is not the "-R <altroot>" 6456 * option. In which case, skip it. 6457 */ 6458 if (strcmp(argv[i], "-R") != 0) 6459 (void) fprintf(fp, "%s ", argv[i]); 6460 else 6461 i ++; 6462 } 6463 (void) fprintf(fp, "%s\n", SMF_DLADM_UPGRADE_MSG); 6464 (void) fclose(fp); 6465 dladm_close(handle); 6466 exit(0); 6467 } 6468 6469 /* 6470 * Convert the string to an integer. Note that the string must not have any 6471 * trailing non-integer characters. 6472 */ 6473 static boolean_t 6474 str2int(const char *str, int *valp) 6475 { 6476 int val; 6477 char *endp = NULL; 6478 6479 errno = 0; 6480 val = strtol(str, &endp, 10); 6481 if (errno != 0 || *endp != '\0') 6482 return (B_FALSE); 6483 6484 *valp = val; 6485 return (B_TRUE); 6486 } 6487 6488 /* PRINTFLIKE1 */ 6489 static void 6490 warn(const char *format, ...) 6491 { 6492 va_list alist; 6493 6494 format = gettext(format); 6495 (void) fprintf(stderr, "%s: warning: ", progname); 6496 6497 va_start(alist, format); 6498 (void) vfprintf(stderr, format, alist); 6499 va_end(alist); 6500 6501 (void) putchar('\n'); 6502 } 6503 6504 /* PRINTFLIKE2 */ 6505 static void 6506 warn_dlerr(dladm_status_t err, const char *format, ...) 6507 { 6508 va_list alist; 6509 char errmsg[DLADM_STRSIZE]; 6510 6511 format = gettext(format); 6512 (void) fprintf(stderr, gettext("%s: warning: "), progname); 6513 6514 va_start(alist, format); 6515 (void) vfprintf(stderr, format, alist); 6516 va_end(alist); 6517 (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg)); 6518 } 6519 6520 /* 6521 * Also closes the dladm handle if it is not NULL. 6522 */ 6523 /* PRINTFLIKE2 */ 6524 static void 6525 die_dlerr(dladm_status_t err, const char *format, ...) 6526 { 6527 va_list alist; 6528 char errmsg[DLADM_STRSIZE]; 6529 6530 format = gettext(format); 6531 (void) fprintf(stderr, "%s: ", progname); 6532 6533 va_start(alist, format); 6534 (void) vfprintf(stderr, format, alist); 6535 va_end(alist); 6536 (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg)); 6537 6538 /* close dladm handle if it was opened */ 6539 if (handle != NULL) 6540 dladm_close(handle); 6541 6542 exit(EXIT_FAILURE); 6543 } 6544 6545 /* PRINTFLIKE1 */ 6546 static void 6547 die(const char *format, ...) 6548 { 6549 va_list alist; 6550 6551 format = gettext(format); 6552 (void) fprintf(stderr, "%s: ", progname); 6553 6554 va_start(alist, format); 6555 (void) vfprintf(stderr, format, alist); 6556 va_end(alist); 6557 6558 (void) putchar('\n'); 6559 6560 /* close dladm handle if it was opened */ 6561 if (handle != NULL) 6562 dladm_close(handle); 6563 6564 exit(EXIT_FAILURE); 6565 } 6566 6567 static void 6568 die_optdup(int opt) 6569 { 6570 die("the option -%c cannot be specified more than once", opt); 6571 } 6572 6573 static void 6574 die_opterr(int opt, int opterr, const char *usage) 6575 { 6576 switch (opterr) { 6577 case ':': 6578 die("option '-%c' requires a value\nusage: %s", opt, 6579 gettext(usage)); 6580 break; 6581 case '?': 6582 default: 6583 die("unrecognized option '-%c'\nusage: %s", opt, 6584 gettext(usage)); 6585 break; 6586 } 6587 } 6588 6589 static void 6590 show_ether_xprop(void *arg, dladm_ether_info_t *eattr) 6591 { 6592 print_ether_state_t *statep = arg; 6593 ether_fields_buf_t ebuf; 6594 int i; 6595 6596 for (i = CAPABLE; i <= PEERADV; i++) { 6597 bzero(&ebuf, sizeof (ebuf)); 6598 (void) strlcpy(ebuf.eth_ptype, ptype[i], 6599 sizeof (ebuf.eth_ptype)); 6600 (void) dladm_ether_autoneg2str(ebuf.eth_autoneg, 6601 sizeof (ebuf.eth_autoneg), eattr, i); 6602 (void) dladm_ether_spdx2str(ebuf.eth_spdx, 6603 sizeof (ebuf.eth_spdx), eattr, i); 6604 (void) dladm_ether_pause2str(ebuf.eth_pause, 6605 sizeof (ebuf.eth_pause), eattr, i); 6606 (void) strlcpy(ebuf.eth_rem_fault, 6607 (eattr->lei_attr[i].le_fault ? "fault" : "none"), 6608 sizeof (ebuf.eth_rem_fault)); 6609 ofmt_print(statep->es_ofmt, &ebuf); 6610 } 6611 6612 } 6613 6614 static boolean_t 6615 link_is_ether(const char *link, datalink_id_t *linkid) 6616 { 6617 uint32_t media; 6618 datalink_class_t class; 6619 6620 if (dladm_name2info(handle, link, linkid, NULL, &class, &media) == 6621 DLADM_STATUS_OK) { 6622 if (class == DATALINK_CLASS_PHYS && media == DL_ETHER) 6623 return (B_TRUE); 6624 } 6625 return (B_FALSE); 6626 } 6627 6628 /* 6629 * default output callback function that, when invoked, 6630 * prints string which is offset by ofmt_arg->ofmt_id within buf. 6631 */ 6632 static boolean_t 6633 print_default_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 6634 { 6635 char *value; 6636 6637 value = (char *)ofarg->ofmt_cbarg + ofarg->ofmt_id; 6638 (void) strlcpy(buf, value, bufsize); 6639 return (B_TRUE); 6640 } 6641 6642 static void 6643 dladm_ofmt_check(ofmt_status_t oferr, boolean_t parsable, 6644 ofmt_handle_t ofmt) 6645 { 6646 char buf[OFMT_BUFSIZE]; 6647 6648 if (oferr == OFMT_SUCCESS) 6649 return; 6650 (void) ofmt_strerror(ofmt, oferr, buf, sizeof (buf)); 6651 /* 6652 * All errors are considered fatal in parsable mode. 6653 * NOMEM errors are always fatal, regardless of mode. 6654 * For other errors, we print diagnostics in human-readable 6655 * mode and processs what we can. 6656 */ 6657 if (parsable || oferr == OFMT_ENOFIELDS) { 6658 ofmt_close(ofmt); 6659 die(buf); 6660 } else { 6661 warn(buf); 6662 } 6663 } 6664