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