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