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 uint16_t 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 vid = (int)strtol(optarg, &endp, 10); 3924 if (errno != 0 || *endp != '\0' || vid == 0) 3925 /* VID of 0 is invalid */ 3926 die("invalid VLAN id"); 3927 break; 3928 case 'f': 3929 flags |= DLADM_OPT_FORCE; 3930 break; 3931 case 'H': 3932 flags |= DLADM_OPT_HWRINGS; 3933 break; 3934 default: 3935 die_opterr(optopt, option, use); 3936 } 3937 } 3938 3939 /* 3940 * 'f' - force, flag can be specified only with 'v' - vlan. 3941 */ 3942 if ((flags & DLADM_OPT_FORCE) != 0 && vid == 0) 3943 die("-f option can only be used with -v"); 3944 3945 if (mac_prefix_len != 0 && mac_addr_type != VNIC_MAC_ADDR_TYPE_RANDOM && 3946 mac_addr_type != VNIC_MAC_ADDR_TYPE_FIXED) 3947 usage(); 3948 3949 /* check required options */ 3950 if (!l_arg) 3951 usage(); 3952 3953 if (mac_slot != -1 && mac_addr_type != VNIC_MAC_ADDR_TYPE_FACTORY) 3954 usage(); 3955 3956 /* the VNIC id is the required operand */ 3957 if (optind != (argc - 1)) 3958 usage(); 3959 3960 if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= MAXLINKNAMELEN) 3961 die("link name too long '%s'", argv[optind]); 3962 3963 if (!dladm_valid_linkname(name)) 3964 die("invalid link name '%s'", argv[optind]); 3965 3966 if (altroot != NULL) 3967 altroot_cmd(altroot, argc, argv); 3968 3969 if (dladm_name2info(handle, devname, &dev_linkid, NULL, NULL, NULL) != 3970 DLADM_STATUS_OK) 3971 die("invalid link name '%s'", devname); 3972 3973 status = dladm_vnic_create(handle, name, dev_linkid, mac_addr_type, 3974 mac_addr, maclen, &mac_slot, mac_prefix_len, vid, &linkid, proplist, 3975 flags); 3976 if (status != DLADM_STATUS_OK) 3977 die_dlerr(status, "vnic creation over %s failed", devname); 3978 3979 dladm_free_props(proplist); 3980 } 3981 3982 static void 3983 do_etherstub_check(const char *name, datalink_id_t linkid, boolean_t etherstub, 3984 uint32_t flags) 3985 { 3986 boolean_t is_etherstub; 3987 dladm_vnic_attr_t attr; 3988 3989 if (dladm_vnic_info(handle, linkid, &attr, flags) != DLADM_STATUS_OK) { 3990 /* 3991 * Let the delete continue anyway. 3992 */ 3993 return; 3994 } 3995 is_etherstub = (attr.va_link_id == DATALINK_INVALID_LINKID); 3996 if (is_etherstub != etherstub) { 3997 die("'%s' is not %s", name, 3998 (is_etherstub ? "a vnic" : "an etherstub")); 3999 } 4000 } 4001 4002 static void 4003 do_delete_vnic_common(int argc, char *argv[], const char *use, 4004 boolean_t etherstub) 4005 { 4006 char option; 4007 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 4008 datalink_id_t linkid; 4009 char *altroot = NULL; 4010 dladm_status_t status; 4011 4012 opterr = 0; 4013 while ((option = getopt_long(argc, argv, ":R:t", lopts, 4014 NULL)) != -1) { 4015 switch (option) { 4016 case 't': 4017 flags &= ~DLADM_OPT_PERSIST; 4018 break; 4019 case 'R': 4020 altroot = optarg; 4021 break; 4022 default: 4023 die_opterr(optopt, option, use); 4024 } 4025 } 4026 4027 /* get vnic name (required last argument) */ 4028 if (optind != (argc - 1)) 4029 usage(); 4030 4031 if (altroot != NULL) 4032 altroot_cmd(altroot, argc, argv); 4033 4034 status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL, 4035 NULL); 4036 if (status != DLADM_STATUS_OK) 4037 die("invalid link name '%s'", argv[optind]); 4038 4039 if ((flags & DLADM_OPT_ACTIVE) != 0) { 4040 do_etherstub_check(argv[optind], linkid, etherstub, 4041 DLADM_OPT_ACTIVE); 4042 } 4043 if ((flags & DLADM_OPT_PERSIST) != 0) { 4044 do_etherstub_check(argv[optind], linkid, etherstub, 4045 DLADM_OPT_PERSIST); 4046 } 4047 4048 status = dladm_vnic_delete(handle, linkid, flags); 4049 if (status != DLADM_STATUS_OK) 4050 die_dlerr(status, "vnic deletion failed"); 4051 } 4052 4053 static void 4054 do_delete_vnic(int argc, char *argv[], const char *use) 4055 { 4056 do_delete_vnic_common(argc, argv, use, B_FALSE); 4057 } 4058 4059 /* ARGSUSED */ 4060 static void 4061 do_up_vnic_common(int argc, char *argv[], const char *use, boolean_t vlan) 4062 { 4063 datalink_id_t linkid = DATALINK_ALL_LINKID; 4064 dladm_status_t status; 4065 char *type; 4066 4067 type = vlan ? "vlan" : "vnic"; 4068 4069 /* 4070 * get the id or the name of the vnic/vlan (optional last argument) 4071 */ 4072 if (argc == 2) { 4073 status = dladm_name2info(handle, argv[1], &linkid, NULL, NULL, 4074 NULL); 4075 if (status != DLADM_STATUS_OK) 4076 goto done; 4077 4078 } else if (argc > 2) { 4079 usage(); 4080 } 4081 4082 if (vlan) 4083 status = dladm_vlan_up(handle, linkid); 4084 else 4085 status = dladm_vnic_up(handle, linkid, 0); 4086 4087 done: 4088 if (status != DLADM_STATUS_OK) { 4089 if (argc == 2) { 4090 die_dlerr(status, 4091 "could not bring up %s '%s'", type, argv[1]); 4092 } else { 4093 die_dlerr(status, "could not bring %ss up", type); 4094 } 4095 } 4096 } 4097 4098 static void 4099 do_up_vnic(int argc, char *argv[], const char *use) 4100 { 4101 do_up_vnic_common(argc, argv, use, B_FALSE); 4102 } 4103 4104 static void 4105 dump_vnics_head(const char *dev) 4106 { 4107 if (strlen(dev)) 4108 (void) printf("%s", dev); 4109 4110 (void) printf("\tipackets rbytes opackets obytes "); 4111 4112 if (strlen(dev)) 4113 (void) printf("%%ipkts %%opkts\n"); 4114 else 4115 (void) printf("\n"); 4116 } 4117 4118 static void 4119 dump_vnic_stat(const char *name, datalink_id_t vnic_id, 4120 show_vnic_state_t *state, pktsum_t *vnic_stats, pktsum_t *tot_stats) 4121 { 4122 pktsum_t diff_stats; 4123 pktsum_t *old_stats = &state->vs_prevstats[vnic_id]; 4124 4125 dladm_stats_diff(&diff_stats, vnic_stats, old_stats); 4126 4127 (void) printf("%s", name); 4128 4129 (void) printf("\t%-10llu", diff_stats.ipackets); 4130 (void) printf("%-12llu", diff_stats.rbytes); 4131 (void) printf("%-10llu", diff_stats.opackets); 4132 (void) printf("%-12llu", diff_stats.obytes); 4133 4134 if (tot_stats) { 4135 if (tot_stats->ipackets == 0) { 4136 (void) printf("\t-"); 4137 } else { 4138 (void) printf("\t%-6.1f", (double)diff_stats.ipackets/ 4139 (double)tot_stats->ipackets * 100); 4140 } 4141 if (tot_stats->opackets == 0) { 4142 (void) printf("\t-"); 4143 } else { 4144 (void) printf("\t%-6.1f", (double)diff_stats.opackets/ 4145 (double)tot_stats->opackets * 100); 4146 } 4147 } 4148 (void) printf("\n"); 4149 4150 *old_stats = *vnic_stats; 4151 } 4152 4153 /* 4154 * Called from the walker dladm_vnic_walk_sys() for each vnic to display 4155 * vnic information or statistics. 4156 */ 4157 static dladm_status_t 4158 print_vnic(show_vnic_state_t *state, datalink_id_t linkid) 4159 { 4160 dladm_vnic_attr_t attr, *vnic = &attr; 4161 dladm_status_t status; 4162 boolean_t is_etherstub; 4163 char devname[MAXLINKNAMELEN]; 4164 char vnic_name[MAXLINKNAMELEN]; 4165 char mstr[MAXMACADDRLEN * 3]; 4166 vnic_fields_buf_t vbuf; 4167 4168 if ((status = dladm_vnic_info(handle, linkid, vnic, state->vs_flags)) != 4169 DLADM_STATUS_OK) 4170 return (status); 4171 4172 is_etherstub = (vnic->va_link_id == DATALINK_INVALID_LINKID); 4173 if (state->vs_etherstub != is_etherstub) { 4174 /* 4175 * Want all etherstub but it's not one, or want 4176 * non-etherstub and it's one. 4177 */ 4178 return (DLADM_STATUS_OK); 4179 } 4180 4181 if (state->vs_link_id != DATALINK_ALL_LINKID) { 4182 if (state->vs_link_id != vnic->va_link_id) 4183 return (DLADM_STATUS_OK); 4184 } 4185 4186 if (dladm_datalink_id2info(handle, linkid, NULL, NULL, 4187 NULL, vnic_name, sizeof (vnic_name)) != DLADM_STATUS_OK) 4188 return (DLADM_STATUS_BADARG); 4189 4190 bzero(devname, sizeof (devname)); 4191 if (!is_etherstub && 4192 dladm_datalink_id2info(handle, vnic->va_link_id, NULL, NULL, 4193 NULL, devname, sizeof (devname)) != DLADM_STATUS_OK) 4194 return (DLADM_STATUS_BADARG); 4195 4196 state->vs_found = B_TRUE; 4197 if (state->vs_stats) { 4198 /* print vnic statistics */ 4199 pktsum_t vnic_stats; 4200 4201 if (state->vs_firstonly) { 4202 if (state->vs_donefirst) 4203 return (0); 4204 state->vs_donefirst = B_TRUE; 4205 } 4206 4207 if (!state->vs_printstats) { 4208 /* 4209 * get vnic statistics and add to the sum for the 4210 * named device. 4211 */ 4212 get_link_stats(vnic_name, &vnic_stats); 4213 dladm_stats_total(&state->vs_totalstats, &vnic_stats, 4214 &state->vs_prevstats[vnic->va_vnic_id]); 4215 } else { 4216 /* get and print vnic statistics */ 4217 get_link_stats(vnic_name, &vnic_stats); 4218 dump_vnic_stat(vnic_name, linkid, state, &vnic_stats, 4219 &state->vs_totalstats); 4220 } 4221 return (DLADM_STATUS_OK); 4222 } else { 4223 (void) snprintf(vbuf.vnic_link, sizeof (vbuf.vnic_link), 4224 "%s", vnic_name); 4225 4226 if (!is_etherstub) { 4227 4228 (void) snprintf(vbuf.vnic_over, sizeof (vbuf.vnic_over), 4229 "%s", devname); 4230 (void) snprintf(vbuf.vnic_speed, 4231 sizeof (vbuf.vnic_speed), "%u", 4232 (uint_t)((get_ifspeed(vnic_name, B_TRUE)) 4233 / 1000000ull)); 4234 4235 switch (vnic->va_mac_addr_type) { 4236 case VNIC_MAC_ADDR_TYPE_FIXED: 4237 case VNIC_MAC_ADDR_TYPE_PRIMARY: 4238 (void) snprintf(vbuf.vnic_macaddrtype, 4239 sizeof (vbuf.vnic_macaddrtype), 4240 gettext("fixed")); 4241 break; 4242 case VNIC_MAC_ADDR_TYPE_RANDOM: 4243 (void) snprintf(vbuf.vnic_macaddrtype, 4244 sizeof (vbuf.vnic_macaddrtype), 4245 gettext("random")); 4246 break; 4247 case VNIC_MAC_ADDR_TYPE_FACTORY: 4248 (void) snprintf(vbuf.vnic_macaddrtype, 4249 sizeof (vbuf.vnic_macaddrtype), 4250 gettext("factory, slot %d"), 4251 vnic->va_mac_slot); 4252 break; 4253 } 4254 4255 if (strlen(vbuf.vnic_macaddrtype) > 0) { 4256 (void) snprintf(vbuf.vnic_macaddr, 4257 sizeof (vbuf.vnic_macaddr), "%s", 4258 dladm_aggr_macaddr2str(vnic->va_mac_addr, 4259 mstr)); 4260 } 4261 4262 (void) snprintf(vbuf.vnic_vid, sizeof (vbuf.vnic_vid), 4263 "%d", vnic->va_vid); 4264 } 4265 4266 if (!state->vs_parseable && !state->vs_printheader) { 4267 print_header(&state->vs_print); 4268 state->vs_printheader = B_TRUE; 4269 } 4270 4271 dladm_print_output(&state->vs_print, state->vs_parseable, 4272 dladm_print_field, (void *)&vbuf); 4273 4274 return (DLADM_STATUS_OK); 4275 } 4276 } 4277 4278 /* ARGSUSED */ 4279 static int 4280 show_vnic(dladm_handle_t dh, datalink_id_t linkid, void *arg) 4281 { 4282 show_vnic_state_t *state = arg; 4283 4284 state->vs_status = print_vnic(state, linkid); 4285 return (DLADM_WALK_CONTINUE); 4286 } 4287 4288 static void 4289 do_show_vnic_common(int argc, char *argv[], const char *use, 4290 boolean_t etherstub) 4291 { 4292 int option; 4293 boolean_t s_arg = B_FALSE; 4294 boolean_t i_arg = B_FALSE; 4295 boolean_t l_arg = B_FALSE; 4296 char *endp = NULL; 4297 uint32_t interval = 0, flags = DLADM_OPT_ACTIVE; 4298 datalink_id_t linkid = DATALINK_ALL_LINKID; 4299 datalink_id_t dev_linkid = DATALINK_ALL_LINKID; 4300 show_vnic_state_t state; 4301 dladm_status_t status; 4302 boolean_t o_arg = B_FALSE; 4303 char *fields_str = NULL; 4304 print_field_t **fields; 4305 print_field_t *pf; 4306 int pfmax; 4307 uint_t nfields; 4308 char *all_fields = 4309 "link,over,speed,macaddress,macaddrtype,vid"; 4310 char *all_e_fields = 4311 "link"; 4312 4313 bzero(&state, sizeof (state)); 4314 opterr = 0; 4315 while ((option = getopt_long(argc, argv, ":pPl:si:o:", lopts, 4316 NULL)) != -1) { 4317 switch (option) { 4318 case 'p': 4319 state.vs_parseable = B_TRUE; 4320 break; 4321 case 'P': 4322 flags = DLADM_OPT_PERSIST; 4323 break; 4324 case 'l': 4325 if (etherstub) 4326 die("option not supported for this command"); 4327 4328 if (strlcpy(state.vs_link, optarg, MAXLINKNAMELEN) >= 4329 MAXLINKNAMELEN) 4330 die("link name too long"); 4331 4332 l_arg = B_TRUE; 4333 break; 4334 case 's': 4335 if (s_arg) { 4336 die("the option -s cannot be specified " 4337 "more than once"); 4338 } 4339 s_arg = B_TRUE; 4340 break; 4341 case 'i': 4342 if (i_arg) { 4343 die("the option -i cannot be specified " 4344 "more than once"); 4345 } 4346 i_arg = B_TRUE; 4347 interval = (int)strtol(optarg, &endp, 10); 4348 if (errno != 0 || interval == 0 || *endp != '\0') 4349 die("invalid interval value '%s'", optarg); 4350 break; 4351 case 'o': 4352 o_arg = B_TRUE; 4353 fields_str = optarg; 4354 break; 4355 default: 4356 die_opterr(optopt, option, use); 4357 } 4358 } 4359 4360 if (state.vs_parseable && !o_arg) 4361 die("-p requires -o"); 4362 4363 if (state.vs_parseable && strcasecmp(fields_str, "all") == 0) 4364 die("\"-o all\" is invalid with -p"); 4365 4366 if (i_arg && !s_arg) 4367 die("the option -i can be used only with -s"); 4368 4369 /* get vnic ID (optional last argument) */ 4370 if (optind == (argc - 1)) { 4371 status = dladm_name2info(handle, argv[optind], &linkid, NULL, 4372 NULL, NULL); 4373 if (status != DLADM_STATUS_OK) { 4374 die_dlerr(status, "invalid vnic name '%s'", 4375 argv[optind]); 4376 } 4377 (void) strlcpy(state.vs_vnic, argv[optind], MAXLINKNAMELEN); 4378 } else if (optind != argc) { 4379 usage(); 4380 } 4381 4382 if (l_arg) { 4383 status = dladm_name2info(handle, state.vs_link, &dev_linkid, 4384 NULL, NULL, NULL); 4385 if (status != DLADM_STATUS_OK) { 4386 die_dlerr(status, "invalid link name '%s'", 4387 state.vs_link); 4388 } 4389 } 4390 4391 state.vs_vnic_id = linkid; 4392 state.vs_link_id = dev_linkid; 4393 state.vs_etherstub = etherstub; 4394 state.vs_found = B_FALSE; 4395 state.vs_flags = flags; 4396 4397 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) { 4398 if (etherstub) 4399 fields_str = all_e_fields; 4400 else 4401 fields_str = all_fields; 4402 } 4403 4404 pf = vnic_fields; 4405 pfmax = VNIC_MAX_FIELDS; 4406 4407 fields = parse_output_fields(fields_str, pf, pfmax, CMD_TYPE_ANY, 4408 &nfields); 4409 4410 if (fields == NULL) { 4411 die("invalid field(s) specified"); 4412 return; 4413 } 4414 4415 state.vs_print.ps_fields = fields; 4416 state.vs_print.ps_nfields = nfields; 4417 4418 if (s_arg) { 4419 /* Display vnic statistics */ 4420 vnic_stats(&state, interval); 4421 return; 4422 } 4423 4424 /* Display vnic information */ 4425 state.vs_donefirst = B_FALSE; 4426 4427 if (linkid == DATALINK_ALL_LINKID) { 4428 (void) dladm_walk_datalink_id(show_vnic, handle, &state, 4429 DATALINK_CLASS_VNIC | DATALINK_CLASS_ETHERSTUB, 4430 DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE); 4431 } else { 4432 (void) show_vnic(handle, linkid, &state); 4433 if (state.vs_status != DLADM_STATUS_OK) { 4434 die_dlerr(state.vs_status, "failed to show vnic '%s'", 4435 state.vs_vnic); 4436 } 4437 } 4438 } 4439 4440 static void 4441 do_show_vnic(int argc, char *argv[], const char *use) 4442 { 4443 do_show_vnic_common(argc, argv, use, B_FALSE); 4444 } 4445 4446 static void 4447 do_create_etherstub(int argc, char *argv[], const char *use) 4448 { 4449 uint32_t flags; 4450 char *altroot = NULL; 4451 char option; 4452 dladm_status_t status; 4453 char name[MAXLINKNAMELEN]; 4454 uchar_t mac_addr[ETHERADDRL]; 4455 4456 name[0] = '\0'; 4457 bzero(mac_addr, sizeof (mac_addr)); 4458 flags = DLADM_OPT_ANCHOR | DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 4459 4460 opterr = 0; 4461 while ((option = getopt_long(argc, argv, "tR:", 4462 etherstub_lopts, NULL)) != -1) { 4463 switch (option) { 4464 case 't': 4465 flags &= ~DLADM_OPT_PERSIST; 4466 break; 4467 case 'R': 4468 altroot = optarg; 4469 break; 4470 default: 4471 die_opterr(optopt, option, use); 4472 } 4473 } 4474 4475 /* the etherstub id is the required operand */ 4476 if (optind != (argc - 1)) 4477 usage(); 4478 4479 if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= MAXLINKNAMELEN) 4480 die("link name too long '%s'", argv[optind]); 4481 4482 if (!dladm_valid_linkname(name)) 4483 die("invalid link name '%s'", argv[optind]); 4484 4485 if (altroot != NULL) 4486 altroot_cmd(altroot, argc, argv); 4487 4488 status = dladm_vnic_create(handle, name, DATALINK_INVALID_LINKID, 4489 VNIC_MAC_ADDR_TYPE_AUTO, mac_addr, ETHERADDRL, NULL, 0, 0, NULL, 4490 NULL, flags); 4491 if (status != DLADM_STATUS_OK) 4492 die_dlerr(status, "etherstub creation failed"); 4493 4494 4495 } 4496 4497 static void 4498 do_delete_etherstub(int argc, char *argv[], const char *use) 4499 { 4500 do_delete_vnic_common(argc, argv, use, B_TRUE); 4501 } 4502 4503 /* ARGSUSED */ 4504 static void 4505 do_show_etherstub(int argc, char *argv[], const char *use) 4506 { 4507 do_show_vnic_common(argc, argv, use, B_TRUE); 4508 } 4509 4510 static void 4511 link_stats(datalink_id_t linkid, uint_t interval, char *fields_str, 4512 show_state_t *state) 4513 { 4514 print_field_t **fields; 4515 uint_t nfields; 4516 4517 fields = parse_output_fields(fields_str, link_s_fields, 4518 LINK_S_MAX_FIELDS, CMD_TYPE_ANY, &nfields); 4519 if (fields == NULL) { 4520 die("invalid field(s) specified"); 4521 return; 4522 } 4523 4524 state->ls_print.ps_fields = fields; 4525 state->ls_print.ps_nfields = nfields; 4526 4527 /* 4528 * If an interval is specified, continuously show the stats 4529 * only for the first MAC port. 4530 */ 4531 state->ls_firstonly = (interval != 0); 4532 4533 if (!state->ls_parseable) 4534 print_header(&state->ls_print); 4535 for (;;) { 4536 state->ls_donefirst = B_FALSE; 4537 if (linkid == DATALINK_ALL_LINKID) { 4538 (void) dladm_walk_datalink_id(show_link_stats, handle, 4539 state, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, 4540 DLADM_OPT_ACTIVE); 4541 } else { 4542 (void) show_link_stats(handle, linkid, state); 4543 } 4544 4545 if (interval == 0) 4546 break; 4547 4548 (void) sleep(interval); 4549 } 4550 } 4551 4552 static void 4553 aggr_stats(datalink_id_t linkid, show_grp_state_t *state, uint_t interval) 4554 { 4555 /* 4556 * If an interval is specified, continuously show the stats 4557 * only for the first group. 4558 */ 4559 state->gs_firstonly = (interval != 0); 4560 4561 for (;;) { 4562 state->gs_donefirst = B_FALSE; 4563 if (linkid == DATALINK_ALL_LINKID) 4564 (void) dladm_walk_datalink_id(show_aggr, handle, state, 4565 DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, 4566 DLADM_OPT_ACTIVE); 4567 else 4568 (void) show_aggr(handle, linkid, state); 4569 4570 if (interval == 0) 4571 break; 4572 4573 (void) sleep(interval); 4574 } 4575 } 4576 4577 /* ARGSUSED */ 4578 static void 4579 vnic_stats(show_vnic_state_t *sp, uint32_t interval) 4580 { 4581 show_vnic_state_t state; 4582 boolean_t specific_link, specific_dev; 4583 4584 /* Display vnic statistics */ 4585 dump_vnics_head(sp->vs_link); 4586 4587 bzero(&state, sizeof (state)); 4588 state.vs_stats = B_TRUE; 4589 state.vs_vnic_id = sp->vs_vnic_id; 4590 state.vs_link_id = sp->vs_link_id; 4591 4592 /* 4593 * If an interval is specified, and a vnic ID is not specified, 4594 * continuously show the stats only for the first vnic. 4595 */ 4596 specific_link = (sp->vs_vnic_id != DATALINK_ALL_LINKID); 4597 specific_dev = (sp->vs_link_id != DATALINK_ALL_LINKID); 4598 4599 for (;;) { 4600 /* Get stats for each vnic */ 4601 state.vs_found = B_FALSE; 4602 state.vs_donefirst = B_FALSE; 4603 state.vs_printstats = B_FALSE; 4604 state.vs_flags = DLADM_OPT_ACTIVE; 4605 4606 if (!specific_link) { 4607 (void) dladm_walk_datalink_id(show_vnic, handle, &state, 4608 DATALINK_CLASS_VNIC, DATALINK_ANY_MEDIATYPE, 4609 DLADM_OPT_ACTIVE); 4610 } else { 4611 (void) show_vnic(handle, sp->vs_vnic_id, &state); 4612 if (state.vs_status != DLADM_STATUS_OK) { 4613 die_dlerr(state.vs_status, 4614 "failed to show vnic '%s'", sp->vs_vnic); 4615 } 4616 } 4617 4618 if (specific_link && !state.vs_found) 4619 die("non-existent vnic '%s'", sp->vs_vnic); 4620 if (specific_dev && !state.vs_found) 4621 die("device %s has no vnics", sp->vs_link); 4622 4623 /* Show totals */ 4624 if ((specific_link | specific_dev) && !interval) { 4625 (void) printf("Total"); 4626 (void) printf("\t%-10llu", 4627 state.vs_totalstats.ipackets); 4628 (void) printf("%-12llu", 4629 state.vs_totalstats.rbytes); 4630 (void) printf("%-10llu", 4631 state.vs_totalstats.opackets); 4632 (void) printf("%-12llu\n", 4633 state.vs_totalstats.obytes); 4634 } 4635 4636 /* Show stats for each vnic */ 4637 state.vs_donefirst = B_FALSE; 4638 state.vs_printstats = B_TRUE; 4639 4640 if (!specific_link) { 4641 (void) dladm_walk_datalink_id(show_vnic, handle, &state, 4642 DATALINK_CLASS_VNIC, DATALINK_ANY_MEDIATYPE, 4643 DLADM_OPT_ACTIVE); 4644 } else { 4645 (void) show_vnic(handle, sp->vs_vnic_id, &state); 4646 if (state.vs_status != DLADM_STATUS_OK) { 4647 die_dlerr(state.vs_status, 4648 "failed to show vnic '%s'", sp->vs_vnic); 4649 } 4650 } 4651 4652 if (interval == 0) 4653 break; 4654 4655 (void) sleep(interval); 4656 } 4657 } 4658 4659 static void 4660 get_mac_stats(const char *dev, pktsum_t *stats) 4661 { 4662 kstat_ctl_t *kcp; 4663 kstat_t *ksp; 4664 char module[DLPI_LINKNAME_MAX]; 4665 uint_t instance; 4666 4667 4668 bzero(stats, sizeof (*stats)); 4669 4670 if (dlpi_parselink(dev, module, &instance) != DLPI_SUCCESS) 4671 return; 4672 4673 if ((kcp = kstat_open()) == NULL) { 4674 warn("kstat open operation failed"); 4675 return; 4676 } 4677 4678 ksp = dladm_kstat_lookup(kcp, module, instance, "mac", NULL); 4679 if (ksp != NULL) 4680 dladm_get_stats(kcp, ksp, stats); 4681 4682 (void) kstat_close(kcp); 4683 4684 } 4685 4686 static void 4687 get_link_stats(const char *link, pktsum_t *stats) 4688 { 4689 kstat_ctl_t *kcp; 4690 kstat_t *ksp; 4691 4692 bzero(stats, sizeof (*stats)); 4693 4694 if ((kcp = kstat_open()) == NULL) { 4695 warn("kstat_open operation failed"); 4696 return; 4697 } 4698 4699 ksp = dladm_kstat_lookup(kcp, "link", 0, link, NULL); 4700 4701 if (ksp != NULL) 4702 dladm_get_stats(kcp, ksp, stats); 4703 4704 (void) kstat_close(kcp); 4705 } 4706 4707 static int 4708 query_kstat(char *module, int instance, const char *name, const char *stat, 4709 uint8_t type, void *val) 4710 { 4711 kstat_ctl_t *kcp; 4712 kstat_t *ksp; 4713 4714 if ((kcp = kstat_open()) == NULL) { 4715 warn("kstat open operation failed"); 4716 return (-1); 4717 } 4718 4719 if ((ksp = kstat_lookup(kcp, module, instance, (char *)name)) == NULL) { 4720 /* 4721 * The kstat query could fail if the underlying MAC 4722 * driver was already detached. 4723 */ 4724 goto bail; 4725 } 4726 4727 if (kstat_read(kcp, ksp, NULL) == -1) { 4728 warn("kstat read failed"); 4729 goto bail; 4730 } 4731 4732 if (dladm_kstat_value(ksp, stat, type, val) < 0) 4733 goto bail; 4734 4735 (void) kstat_close(kcp); 4736 return (0); 4737 4738 bail: 4739 (void) kstat_close(kcp); 4740 return (-1); 4741 } 4742 4743 static int 4744 get_one_kstat(const char *name, const char *stat, uint8_t type, 4745 void *val, boolean_t islink) 4746 { 4747 char module[DLPI_LINKNAME_MAX]; 4748 uint_t instance; 4749 4750 if (islink) { 4751 return (query_kstat("link", 0, name, stat, type, val)); 4752 } else { 4753 if (dlpi_parselink(name, module, &instance) != DLPI_SUCCESS) 4754 return (-1); 4755 4756 return (query_kstat(module, instance, "mac", stat, type, val)); 4757 } 4758 } 4759 4760 static uint64_t 4761 get_ifspeed(const char *name, boolean_t islink) 4762 { 4763 uint64_t ifspeed = 0; 4764 4765 (void) get_one_kstat(name, "ifspeed", KSTAT_DATA_UINT64, 4766 &ifspeed, islink); 4767 4768 return (ifspeed); 4769 } 4770 4771 static const char * 4772 get_linkstate(const char *name, boolean_t islink, char *buf) 4773 { 4774 link_state_t linkstate; 4775 4776 if (get_one_kstat(name, "link_state", KSTAT_DATA_UINT32, 4777 &linkstate, islink) != 0) { 4778 (void) strlcpy(buf, "?", DLADM_STRSIZE); 4779 return (buf); 4780 } 4781 return (dladm_linkstate2str(linkstate, buf)); 4782 } 4783 4784 static const char * 4785 get_linkduplex(const char *name, boolean_t islink, char *buf) 4786 { 4787 link_duplex_t linkduplex; 4788 4789 if (get_one_kstat(name, "link_duplex", KSTAT_DATA_UINT32, 4790 &linkduplex, islink) != 0) { 4791 (void) strlcpy(buf, "unknown", DLADM_STRSIZE); 4792 return (buf); 4793 } 4794 4795 return (dladm_linkduplex2str(linkduplex, buf)); 4796 } 4797 4798 typedef struct { 4799 char *s_buf; 4800 char **s_fields; /* array of pointer to the fields in s_buf */ 4801 uint_t s_nfields; /* the number of fields in s_buf */ 4802 } split_t; 4803 4804 /* 4805 * Free the split_t structure pointed to by `sp'. 4806 */ 4807 static void 4808 splitfree(split_t *sp) 4809 { 4810 free(sp->s_buf); 4811 free(sp->s_fields); 4812 free(sp); 4813 } 4814 4815 /* 4816 * Split `str' into at most `maxfields' fields, each field at most `maxlen' in 4817 * length. Return a pointer to a split_t containing the split fields, or NULL 4818 * on failure. 4819 */ 4820 static split_t * 4821 split(const char *str, uint_t maxfields, uint_t maxlen) 4822 { 4823 char *field, *token, *lasts = NULL; 4824 split_t *sp; 4825 4826 if (*str == '\0' || maxfields == 0 || maxlen == 0) 4827 return (NULL); 4828 4829 sp = calloc(sizeof (split_t), 1); 4830 if (sp == NULL) 4831 return (NULL); 4832 4833 sp->s_buf = strdup(str); 4834 sp->s_fields = malloc(sizeof (char *) * maxfields); 4835 if (sp->s_buf == NULL || sp->s_fields == NULL) 4836 goto fail; 4837 4838 token = sp->s_buf; 4839 while ((field = strtok_r(token, ",", &lasts)) != NULL) { 4840 if (sp->s_nfields == maxfields || strlen(field) > maxlen) 4841 goto fail; 4842 token = NULL; 4843 sp->s_fields[sp->s_nfields++] = field; 4844 } 4845 return (sp); 4846 fail: 4847 splitfree(sp); 4848 return (NULL); 4849 } 4850 4851 static int 4852 parse_wifi_fields(char *str, print_field_t ***fields, uint_t *countp, 4853 uint_t cmdtype) 4854 { 4855 4856 if (cmdtype == WIFI_CMD_SCAN) { 4857 if (str == NULL) 4858 str = def_scan_wifi_fields; 4859 if (strcasecmp(str, "all") == 0) 4860 str = all_scan_wifi_fields; 4861 } else if (cmdtype == WIFI_CMD_SHOW) { 4862 if (str == NULL) 4863 str = def_show_wifi_fields; 4864 if (strcasecmp(str, "all") == 0) 4865 str = all_show_wifi_fields; 4866 } else { 4867 return (-1); 4868 } 4869 *fields = parse_output_fields(str, wifi_fields, WIFI_MAX_FIELDS, 4870 cmdtype, countp); 4871 if (*fields != NULL) 4872 return (0); 4873 return (-1); 4874 } 4875 static print_field_t ** 4876 parse_output_fields(char *str, print_field_t *template, int max_fields, 4877 uint_t cmdtype, uint_t *countp) 4878 { 4879 split_t *sp; 4880 boolean_t good_match = B_FALSE; 4881 uint_t i, j; 4882 print_field_t **pf = NULL; 4883 4884 sp = split(str, max_fields, MAX_FIELD_LEN); 4885 4886 if (sp == NULL) 4887 return (NULL); 4888 4889 pf = malloc(sp->s_nfields * sizeof (print_field_t *)); 4890 if (pf == NULL) 4891 goto fail; 4892 4893 for (i = 0; i < sp->s_nfields; i++) { 4894 for (j = 0; j < max_fields; j++) { 4895 if (strcasecmp(sp->s_fields[i], 4896 template[j].pf_name) == 0) { 4897 good_match = template[j]. pf_cmdtype & cmdtype; 4898 break; 4899 } 4900 } 4901 if (!good_match) 4902 goto fail; 4903 4904 good_match = B_FALSE; 4905 pf[i] = &template[j]; 4906 } 4907 *countp = i; 4908 splitfree(sp); 4909 return (pf); 4910 fail: 4911 free(pf); 4912 splitfree(sp); 4913 return (NULL); 4914 } 4915 4916 typedef struct print_wifi_state { 4917 char *ws_link; 4918 boolean_t ws_parseable; 4919 boolean_t ws_header; 4920 print_state_t ws_print_state; 4921 } print_wifi_state_t; 4922 4923 typedef struct wlan_scan_args_s { 4924 print_wifi_state_t *ws_state; 4925 void *ws_attr; 4926 } wlan_scan_args_t; 4927 4928 static void 4929 print_field(print_state_t *statep, print_field_t *pfp, const char *value, 4930 boolean_t parseable) 4931 { 4932 uint_t width = pfp->pf_width; 4933 uint_t valwidth; 4934 uint_t compress; 4935 4936 /* 4937 * Parsable fields are separated by ':'. If such a field contains 4938 * a ':' or '\', this character is prefixed by a '\'. 4939 */ 4940 if (parseable) { 4941 char c; 4942 4943 if (statep->ps_nfields == 1) { 4944 (void) printf("%s", value); 4945 return; 4946 } 4947 while ((c = *value++) != '\0') { 4948 if (c == ':' || c == '\\') 4949 (void) putchar('\\'); 4950 (void) putchar(c); 4951 } 4952 if (!statep->ps_lastfield) 4953 (void) putchar(':'); 4954 return; 4955 } else { 4956 if (value[0] == '\0') 4957 value = STR_UNDEF_VAL; 4958 if (statep->ps_lastfield) { 4959 (void) printf("%s", value); 4960 statep->ps_overflow = 0; 4961 return; 4962 } 4963 4964 valwidth = strlen(value); 4965 if (valwidth > width) { 4966 statep->ps_overflow += valwidth - width; 4967 } else if (valwidth < width && statep->ps_overflow > 0) { 4968 compress = min(statep->ps_overflow, width - valwidth); 4969 statep->ps_overflow -= compress; 4970 width -= compress; 4971 } 4972 (void) printf("%-*s", width, value); 4973 } 4974 4975 if (!statep->ps_lastfield) 4976 (void) putchar(' '); 4977 } 4978 4979 static char * 4980 print_wlan_attr(print_field_t *wfp, void *warg) 4981 { 4982 static char buf[DLADM_STRSIZE]; 4983 wlan_scan_args_t *w = warg; 4984 print_wifi_state_t *statep = w->ws_state; 4985 dladm_wlan_attr_t *attrp = w->ws_attr; 4986 4987 if (wfp->pf_index == 0) { 4988 return ((char *)statep->ws_link); 4989 } 4990 4991 if ((wfp->pf_index & attrp->wa_valid) == 0) { 4992 return (""); 4993 } 4994 4995 switch (wfp->pf_index) { 4996 case DLADM_WLAN_ATTR_ESSID: 4997 (void) dladm_wlan_essid2str(&attrp->wa_essid, buf); 4998 break; 4999 case DLADM_WLAN_ATTR_BSSID: 5000 (void) dladm_wlan_bssid2str(&attrp->wa_bssid, buf); 5001 break; 5002 case DLADM_WLAN_ATTR_SECMODE: 5003 (void) dladm_wlan_secmode2str(&attrp->wa_secmode, buf); 5004 break; 5005 case DLADM_WLAN_ATTR_STRENGTH: 5006 (void) dladm_wlan_strength2str(&attrp->wa_strength, buf); 5007 break; 5008 case DLADM_WLAN_ATTR_MODE: 5009 (void) dladm_wlan_mode2str(&attrp->wa_mode, buf); 5010 break; 5011 case DLADM_WLAN_ATTR_SPEED: 5012 (void) dladm_wlan_speed2str(&attrp->wa_speed, buf); 5013 (void) strlcat(buf, "Mb", sizeof (buf)); 5014 break; 5015 case DLADM_WLAN_ATTR_AUTH: 5016 (void) dladm_wlan_auth2str(&attrp->wa_auth, buf); 5017 break; 5018 case DLADM_WLAN_ATTR_BSSTYPE: 5019 (void) dladm_wlan_bsstype2str(&attrp->wa_bsstype, buf); 5020 break; 5021 } 5022 5023 return (buf); 5024 } 5025 5026 static boolean_t 5027 print_scan_results(void *arg, dladm_wlan_attr_t *attrp) 5028 { 5029 print_wifi_state_t *statep = arg; 5030 wlan_scan_args_t warg; 5031 5032 if (statep->ws_header) { 5033 statep->ws_header = B_FALSE; 5034 if (!statep->ws_parseable) 5035 print_header(&statep->ws_print_state); 5036 } 5037 5038 statep->ws_print_state.ps_overflow = 0; 5039 bzero(&warg, sizeof (warg)); 5040 warg.ws_state = statep; 5041 warg.ws_attr = attrp; 5042 dladm_print_output(&statep->ws_print_state, statep->ws_parseable, 5043 print_wlan_attr, &warg); 5044 return (B_TRUE); 5045 } 5046 5047 static int 5048 scan_wifi(dladm_handle_t dh, datalink_id_t linkid, void *arg) 5049 { 5050 print_wifi_state_t *statep = arg; 5051 dladm_status_t status; 5052 char link[MAXLINKNAMELEN]; 5053 5054 if ((status = dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, link, 5055 sizeof (link))) != DLADM_STATUS_OK) { 5056 return (DLADM_WALK_CONTINUE); 5057 } 5058 5059 statep->ws_link = link; 5060 status = dladm_wlan_scan(dh, linkid, statep, print_scan_results); 5061 if (status != DLADM_STATUS_OK) 5062 die_dlerr(status, "cannot scan link '%s'", statep->ws_link); 5063 5064 return (DLADM_WALK_CONTINUE); 5065 } 5066 5067 static char * 5068 print_link_attr(print_field_t *wfp, void *warg) 5069 { 5070 static char buf[DLADM_STRSIZE]; 5071 char *ptr; 5072 wlan_scan_args_t *w = warg, w1; 5073 print_wifi_state_t *statep = w->ws_state; 5074 dladm_wlan_linkattr_t *attrp = w->ws_attr; 5075 5076 if (strcmp(wfp->pf_name, "status") == 0) { 5077 if ((wfp->pf_index & attrp->la_valid) != 0) 5078 (void) dladm_wlan_linkstatus2str( 5079 &attrp->la_status, buf); 5080 return (buf); 5081 } 5082 statep->ws_print_state.ps_overflow = 0; 5083 bzero(&w1, sizeof (w1)); 5084 w1.ws_state = statep; 5085 w1.ws_attr = &attrp->la_wlan_attr; 5086 ptr = print_wlan_attr(wfp, &w1); 5087 return (ptr); 5088 } 5089 5090 static int 5091 show_wifi(dladm_handle_t dh, datalink_id_t linkid, void *arg) 5092 { 5093 print_wifi_state_t *statep = arg; 5094 dladm_wlan_linkattr_t attr; 5095 dladm_status_t status; 5096 char link[MAXLINKNAMELEN]; 5097 wlan_scan_args_t warg; 5098 5099 if ((status = dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, link, 5100 sizeof (link))) != DLADM_STATUS_OK) { 5101 return (DLADM_WALK_CONTINUE); 5102 } 5103 5104 /* dladm_wlan_get_linkattr() memsets attr with 0 */ 5105 status = dladm_wlan_get_linkattr(dh, linkid, &attr); 5106 if (status != DLADM_STATUS_OK) 5107 die_dlerr(status, "cannot get link attributes for %s", link); 5108 5109 statep->ws_link = link; 5110 5111 if (statep->ws_header) { 5112 statep->ws_header = B_FALSE; 5113 if (!statep->ws_parseable) 5114 print_header(&statep->ws_print_state); 5115 } 5116 5117 statep->ws_print_state.ps_overflow = 0; 5118 bzero(&warg, sizeof (warg)); 5119 warg.ws_state = statep; 5120 warg.ws_attr = &attr; 5121 dladm_print_output(&statep->ws_print_state, statep->ws_parseable, 5122 print_link_attr, &warg); 5123 return (DLADM_WALK_CONTINUE); 5124 } 5125 5126 static void 5127 do_display_wifi(int argc, char **argv, int cmd, const char *use) 5128 { 5129 int option; 5130 char *fields_str = NULL; 5131 print_field_t **fields; 5132 int (*callback)(dladm_handle_t, datalink_id_t, void *); 5133 uint_t nfields; 5134 print_wifi_state_t state; 5135 datalink_id_t linkid = DATALINK_ALL_LINKID; 5136 dladm_status_t status; 5137 5138 if (cmd == WIFI_CMD_SCAN) 5139 callback = scan_wifi; 5140 else if (cmd == WIFI_CMD_SHOW) 5141 callback = show_wifi; 5142 else 5143 return; 5144 5145 state.ws_parseable = B_FALSE; 5146 state.ws_header = B_TRUE; 5147 opterr = 0; 5148 while ((option = getopt_long(argc, argv, ":o:p", 5149 wifi_longopts, NULL)) != -1) { 5150 switch (option) { 5151 case 'o': 5152 fields_str = optarg; 5153 break; 5154 case 'p': 5155 state.ws_parseable = B_TRUE; 5156 break; 5157 default: 5158 die_opterr(optopt, option, use); 5159 } 5160 } 5161 5162 if (state.ws_parseable && fields_str == NULL) 5163 die("-p requires -o"); 5164 5165 if (state.ws_parseable && strcasecmp(fields_str, "all") == 0) 5166 die("\"-o all\" is invalid with -p"); 5167 5168 if (optind == (argc - 1)) { 5169 if ((status = dladm_name2info(handle, argv[optind], &linkid, 5170 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 5171 die_dlerr(status, "link %s is not valid", argv[optind]); 5172 } 5173 } else if (optind != argc) { 5174 usage(); 5175 } 5176 5177 if (parse_wifi_fields(fields_str, &fields, &nfields, cmd) < 0) 5178 die("invalid field(s) specified"); 5179 5180 bzero(&state.ws_print_state, sizeof (state.ws_print_state)); 5181 state.ws_print_state.ps_fields = fields; 5182 state.ws_print_state.ps_nfields = nfields; 5183 5184 if (linkid == DATALINK_ALL_LINKID) { 5185 (void) dladm_walk_datalink_id(callback, handle, &state, 5186 DATALINK_CLASS_PHYS, DL_WIFI, DLADM_OPT_ACTIVE); 5187 } else { 5188 (void) (*callback)(handle, linkid, &state); 5189 } 5190 free(fields); 5191 } 5192 5193 static void 5194 do_scan_wifi(int argc, char **argv, const char *use) 5195 { 5196 do_display_wifi(argc, argv, WIFI_CMD_SCAN, use); 5197 } 5198 5199 static void 5200 do_show_wifi(int argc, char **argv, const char *use) 5201 { 5202 do_display_wifi(argc, argv, WIFI_CMD_SHOW, use); 5203 } 5204 5205 typedef struct wlan_count_attr { 5206 uint_t wc_count; 5207 datalink_id_t wc_linkid; 5208 } wlan_count_attr_t; 5209 5210 /* ARGSUSED */ 5211 static int 5212 do_count_wlan(dladm_handle_t dh, datalink_id_t linkid, void *arg) 5213 { 5214 wlan_count_attr_t *cp = arg; 5215 5216 if (cp->wc_count == 0) 5217 cp->wc_linkid = linkid; 5218 cp->wc_count++; 5219 return (DLADM_WALK_CONTINUE); 5220 } 5221 5222 static int 5223 parse_wlan_keys(char *str, dladm_wlan_key_t **keys, uint_t *key_countp) 5224 { 5225 uint_t i; 5226 split_t *sp; 5227 dladm_wlan_key_t *wk; 5228 5229 sp = split(str, DLADM_WLAN_MAX_WEPKEYS, DLADM_WLAN_MAX_KEYNAME_LEN); 5230 if (sp == NULL) 5231 return (-1); 5232 5233 wk = malloc(sp->s_nfields * sizeof (dladm_wlan_key_t)); 5234 if (wk == NULL) 5235 goto fail; 5236 5237 for (i = 0; i < sp->s_nfields; i++) { 5238 char *s; 5239 dladm_secobj_class_t class; 5240 dladm_status_t status; 5241 5242 (void) strlcpy(wk[i].wk_name, sp->s_fields[i], 5243 DLADM_WLAN_MAX_KEYNAME_LEN); 5244 5245 wk[i].wk_idx = 1; 5246 if ((s = strrchr(wk[i].wk_name, ':')) != NULL) { 5247 if (s[1] == '\0' || s[2] != '\0' || !isdigit(s[1])) 5248 goto fail; 5249 5250 wk[i].wk_idx = (uint_t)(s[1] - '0'); 5251 *s = '\0'; 5252 } 5253 wk[i].wk_len = DLADM_WLAN_MAX_KEY_LEN; 5254 5255 status = dladm_get_secobj(handle, wk[i].wk_name, &class, 5256 wk[i].wk_val, &wk[i].wk_len, 0); 5257 if (status != DLADM_STATUS_OK) { 5258 if (status == DLADM_STATUS_NOTFOUND) { 5259 status = dladm_get_secobj(handle, wk[i].wk_name, 5260 &class, wk[i].wk_val, &wk[i].wk_len, 5261 DLADM_OPT_PERSIST); 5262 } 5263 if (status != DLADM_STATUS_OK) 5264 goto fail; 5265 } 5266 wk[i].wk_class = class; 5267 } 5268 *keys = wk; 5269 *key_countp = i; 5270 splitfree(sp); 5271 return (0); 5272 fail: 5273 free(wk); 5274 splitfree(sp); 5275 return (-1); 5276 } 5277 5278 static void 5279 do_connect_wifi(int argc, char **argv, const char *use) 5280 { 5281 int option; 5282 dladm_wlan_attr_t attr, *attrp; 5283 dladm_status_t status = DLADM_STATUS_OK; 5284 int timeout = DLADM_WLAN_CONNECT_TIMEOUT_DEFAULT; 5285 datalink_id_t linkid = DATALINK_ALL_LINKID; 5286 dladm_wlan_key_t *keys = NULL; 5287 uint_t key_count = 0; 5288 uint_t flags = 0; 5289 dladm_wlan_secmode_t keysecmode = DLADM_WLAN_SECMODE_NONE; 5290 char buf[DLADM_STRSIZE]; 5291 5292 opterr = 0; 5293 (void) memset(&attr, 0, sizeof (attr)); 5294 while ((option = getopt_long(argc, argv, ":e:i:a:m:b:s:k:T:c", 5295 wifi_longopts, NULL)) != -1) { 5296 switch (option) { 5297 case 'e': 5298 status = dladm_wlan_str2essid(optarg, &attr.wa_essid); 5299 if (status != DLADM_STATUS_OK) 5300 die("invalid ESSID '%s'", optarg); 5301 5302 attr.wa_valid |= DLADM_WLAN_ATTR_ESSID; 5303 /* 5304 * Try to connect without doing a scan. 5305 */ 5306 flags |= DLADM_WLAN_CONNECT_NOSCAN; 5307 break; 5308 case 'i': 5309 status = dladm_wlan_str2bssid(optarg, &attr.wa_bssid); 5310 if (status != DLADM_STATUS_OK) 5311 die("invalid BSSID %s", optarg); 5312 5313 attr.wa_valid |= DLADM_WLAN_ATTR_BSSID; 5314 break; 5315 case 'a': 5316 status = dladm_wlan_str2auth(optarg, &attr.wa_auth); 5317 if (status != DLADM_STATUS_OK) 5318 die("invalid authentication mode '%s'", optarg); 5319 5320 attr.wa_valid |= DLADM_WLAN_ATTR_AUTH; 5321 break; 5322 case 'm': 5323 status = dladm_wlan_str2mode(optarg, &attr.wa_mode); 5324 if (status != DLADM_STATUS_OK) 5325 die("invalid mode '%s'", optarg); 5326 5327 attr.wa_valid |= DLADM_WLAN_ATTR_MODE; 5328 break; 5329 case 'b': 5330 if ((status = dladm_wlan_str2bsstype(optarg, 5331 &attr.wa_bsstype)) != DLADM_STATUS_OK) { 5332 die("invalid bsstype '%s'", optarg); 5333 } 5334 5335 attr.wa_valid |= DLADM_WLAN_ATTR_BSSTYPE; 5336 break; 5337 case 's': 5338 if ((status = dladm_wlan_str2secmode(optarg, 5339 &attr.wa_secmode)) != DLADM_STATUS_OK) { 5340 die("invalid security mode '%s'", optarg); 5341 } 5342 5343 attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE; 5344 break; 5345 case 'k': 5346 if (parse_wlan_keys(optarg, &keys, &key_count) < 0) 5347 die("invalid key(s) '%s'", optarg); 5348 5349 if (keys[0].wk_class == DLADM_SECOBJ_CLASS_WEP) 5350 keysecmode = DLADM_WLAN_SECMODE_WEP; 5351 else 5352 keysecmode = DLADM_WLAN_SECMODE_WPA; 5353 break; 5354 case 'T': 5355 if (strcasecmp(optarg, "forever") == 0) { 5356 timeout = -1; 5357 break; 5358 } 5359 if (!str2int(optarg, &timeout) || timeout < 0) 5360 die("invalid timeout value '%s'", optarg); 5361 break; 5362 case 'c': 5363 flags |= DLADM_WLAN_CONNECT_CREATEIBSS; 5364 flags |= DLADM_WLAN_CONNECT_CREATEIBSS; 5365 break; 5366 default: 5367 die_opterr(optopt, option, use); 5368 break; 5369 } 5370 } 5371 5372 if (keysecmode == DLADM_WLAN_SECMODE_NONE) { 5373 if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0) { 5374 die("key required for security mode '%s'", 5375 dladm_wlan_secmode2str(&attr.wa_secmode, buf)); 5376 } 5377 } else { 5378 if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0 && 5379 attr.wa_secmode != keysecmode) 5380 die("incompatible -s and -k options"); 5381 attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE; 5382 attr.wa_secmode = keysecmode; 5383 } 5384 5385 if (optind == (argc - 1)) { 5386 if ((status = dladm_name2info(handle, argv[optind], &linkid, 5387 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 5388 die_dlerr(status, "link %s is not valid", argv[optind]); 5389 } 5390 } else if (optind != argc) { 5391 usage(); 5392 } 5393 5394 if (linkid == DATALINK_ALL_LINKID) { 5395 wlan_count_attr_t wcattr; 5396 5397 wcattr.wc_linkid = DATALINK_INVALID_LINKID; 5398 wcattr.wc_count = 0; 5399 (void) dladm_walk_datalink_id(do_count_wlan, handle, &wcattr, 5400 DATALINK_CLASS_PHYS, DL_WIFI, DLADM_OPT_ACTIVE); 5401 if (wcattr.wc_count == 0) { 5402 die("no wifi links are available"); 5403 } else if (wcattr.wc_count > 1) { 5404 die("link name is required when more than one wifi " 5405 "link is available"); 5406 } 5407 linkid = wcattr.wc_linkid; 5408 } 5409 attrp = (attr.wa_valid == 0) ? NULL : &attr; 5410 again: 5411 if ((status = dladm_wlan_connect(handle, linkid, attrp, timeout, keys, 5412 key_count, flags)) != DLADM_STATUS_OK) { 5413 if ((flags & DLADM_WLAN_CONNECT_NOSCAN) != 0) { 5414 /* 5415 * Try again with scanning and filtering. 5416 */ 5417 flags &= ~DLADM_WLAN_CONNECT_NOSCAN; 5418 goto again; 5419 } 5420 5421 if (status == DLADM_STATUS_NOTFOUND) { 5422 if (attr.wa_valid == 0) { 5423 die("no wifi networks are available"); 5424 } else { 5425 die("no wifi networks with the specified " 5426 "criteria are available"); 5427 } 5428 } 5429 die_dlerr(status, "cannot connect"); 5430 } 5431 free(keys); 5432 } 5433 5434 /* ARGSUSED */ 5435 static int 5436 do_all_disconnect_wifi(dladm_handle_t dh, datalink_id_t linkid, void *arg) 5437 { 5438 dladm_status_t status; 5439 5440 status = dladm_wlan_disconnect(dh, linkid); 5441 if (status != DLADM_STATUS_OK) 5442 warn_dlerr(status, "cannot disconnect link"); 5443 5444 return (DLADM_WALK_CONTINUE); 5445 } 5446 5447 static void 5448 do_disconnect_wifi(int argc, char **argv, const char *use) 5449 { 5450 int option; 5451 datalink_id_t linkid = DATALINK_ALL_LINKID; 5452 boolean_t all_links = B_FALSE; 5453 dladm_status_t status; 5454 wlan_count_attr_t wcattr; 5455 5456 opterr = 0; 5457 while ((option = getopt_long(argc, argv, ":a", 5458 wifi_longopts, NULL)) != -1) { 5459 switch (option) { 5460 case 'a': 5461 all_links = B_TRUE; 5462 break; 5463 default: 5464 die_opterr(optopt, option, use); 5465 break; 5466 } 5467 } 5468 5469 if (optind == (argc - 1)) { 5470 if ((status = dladm_name2info(handle, argv[optind], &linkid, 5471 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 5472 die_dlerr(status, "link %s is not valid", argv[optind]); 5473 } 5474 } else if (optind != argc) { 5475 usage(); 5476 } 5477 5478 if (linkid == DATALINK_ALL_LINKID) { 5479 if (!all_links) { 5480 wcattr.wc_linkid = linkid; 5481 wcattr.wc_count = 0; 5482 (void) dladm_walk_datalink_id(do_count_wlan, handle, 5483 &wcattr, DATALINK_CLASS_PHYS, DL_WIFI, 5484 DLADM_OPT_ACTIVE); 5485 if (wcattr.wc_count == 0) { 5486 die("no wifi links are available"); 5487 } else if (wcattr.wc_count > 1) { 5488 die("link name is required when more than " 5489 "one wifi link is available"); 5490 } 5491 linkid = wcattr.wc_linkid; 5492 } else { 5493 (void) dladm_walk_datalink_id(do_all_disconnect_wifi, 5494 handle, NULL, DATALINK_CLASS_PHYS, DL_WIFI, 5495 DLADM_OPT_ACTIVE); 5496 return; 5497 } 5498 } 5499 status = dladm_wlan_disconnect(handle, linkid); 5500 if (status != DLADM_STATUS_OK) 5501 die_dlerr(status, "cannot disconnect"); 5502 } 5503 5504 static void 5505 print_linkprop(datalink_id_t linkid, show_linkprop_state_t *statep, 5506 const char *propname, dladm_prop_type_t type, const char *format, 5507 char **pptr) 5508 { 5509 int i; 5510 char *ptr, *lim; 5511 char buf[DLADM_STRSIZE]; 5512 char *unknown = "--", *notsup = ""; 5513 char **propvals = statep->ls_propvals; 5514 uint_t valcnt = DLADM_MAX_PROP_VALCNT; 5515 dladm_status_t status; 5516 5517 status = dladm_get_linkprop(handle, linkid, type, propname, propvals, 5518 &valcnt); 5519 if (status != DLADM_STATUS_OK) { 5520 if (status == DLADM_STATUS_TEMPONLY) { 5521 if (type == DLADM_PROP_VAL_MODIFIABLE && 5522 statep->ls_persist) { 5523 valcnt = 1; 5524 propvals = &unknown; 5525 } else { 5526 statep->ls_status = status; 5527 statep->ls_retstatus = status; 5528 return; 5529 } 5530 } else if (status == DLADM_STATUS_NOTSUP || 5531 statep->ls_persist) { 5532 valcnt = 1; 5533 if (type == DLADM_PROP_VAL_CURRENT || 5534 type == DLADM_PROP_VAL_PERM) 5535 propvals = &unknown; 5536 else 5537 propvals = ¬sup; 5538 } else if (status == DLADM_STATUS_NOTDEFINED) { 5539 propvals = ¬sup; /* STR_UNDEF_VAL */ 5540 } else { 5541 if (statep->ls_proplist && 5542 statep->ls_status == DLADM_STATUS_OK) { 5543 warn_dlerr(status, 5544 "cannot get link property '%s' for %s", 5545 propname, statep->ls_link); 5546 } 5547 statep->ls_status = status; 5548 statep->ls_retstatus = status; 5549 return; 5550 } 5551 } 5552 5553 statep->ls_status = DLADM_STATUS_OK; 5554 5555 ptr = buf; 5556 lim = buf + DLADM_STRSIZE; 5557 for (i = 0; i < valcnt; i++) { 5558 if (propvals[i][0] == '\0' && !statep->ls_parseable) 5559 ptr += snprintf(ptr, lim - ptr, STR_UNDEF_VAL","); 5560 else 5561 ptr += snprintf(ptr, lim - ptr, "%s,", propvals[i]); 5562 if (ptr >= lim) 5563 break; 5564 } 5565 if (valcnt > 0) 5566 buf[strlen(buf) - 1] = '\0'; 5567 5568 lim = statep->ls_line + MAX_PROP_LINE; 5569 if (statep->ls_parseable) { 5570 *pptr += snprintf(*pptr, lim - *pptr, 5571 "%s", buf); 5572 } else { 5573 *pptr += snprintf(*pptr, lim - *pptr, format, buf); 5574 } 5575 } 5576 5577 static char * 5578 linkprop_callback(print_field_t *pf, void *ls_arg) 5579 { 5580 linkprop_args_t *arg = ls_arg; 5581 char *propname = arg->ls_propname; 5582 show_linkprop_state_t *statep = arg->ls_state; 5583 char *ptr = statep->ls_line; 5584 char *lim = ptr + MAX_PROP_LINE; 5585 datalink_id_t linkid = arg->ls_linkid; 5586 5587 switch (pf->pf_index) { 5588 case LINKPROP_LINK: 5589 (void) snprintf(ptr, lim - ptr, "%s", statep->ls_link); 5590 break; 5591 case LINKPROP_PROPERTY: 5592 (void) snprintf(ptr, lim - ptr, "%s", propname); 5593 break; 5594 case LINKPROP_VALUE: 5595 print_linkprop(linkid, statep, propname, 5596 statep->ls_persist ? DLADM_PROP_VAL_PERSISTENT : 5597 DLADM_PROP_VAL_CURRENT, "%s", &ptr); 5598 /* 5599 * If we failed to query the link property, for example, query 5600 * the persistent value of a non-persistable link property, 5601 * simply skip the output. 5602 */ 5603 if (statep->ls_status != DLADM_STATUS_OK) 5604 goto skip; 5605 ptr = statep->ls_line; 5606 break; 5607 case LINKPROP_PERM: 5608 print_linkprop(linkid, statep, propname, 5609 DLADM_PROP_VAL_PERM, "%s", &ptr); 5610 if (statep->ls_status != DLADM_STATUS_OK) 5611 goto skip; 5612 ptr = statep->ls_line; 5613 break; 5614 case LINKPROP_DEFAULT: 5615 print_linkprop(linkid, statep, propname, 5616 DLADM_PROP_VAL_DEFAULT, "%s", &ptr); 5617 if (statep->ls_status != DLADM_STATUS_OK) 5618 goto skip; 5619 ptr = statep->ls_line; 5620 break; 5621 case LINKPROP_POSSIBLE: 5622 print_linkprop(linkid, statep, propname, 5623 DLADM_PROP_VAL_MODIFIABLE, "%s ", &ptr); 5624 if (statep->ls_status != DLADM_STATUS_OK) 5625 goto skip; 5626 ptr = statep->ls_line; 5627 break; 5628 default: 5629 die("invalid input"); 5630 break; 5631 } 5632 return (ptr); 5633 skip: 5634 if (statep->ls_status != DLADM_STATUS_OK) 5635 return (NULL); 5636 else 5637 return (""); 5638 } 5639 5640 static boolean_t 5641 linkprop_is_supported(datalink_id_t linkid, const char *propname, 5642 show_linkprop_state_t *statep) 5643 { 5644 dladm_status_t status; 5645 uint_t valcnt = DLADM_MAX_PROP_VALCNT; 5646 5647 /* if used with -p flag, always print output */ 5648 if (statep->ls_proplist != NULL) 5649 return (B_TRUE); 5650 5651 status = dladm_get_linkprop(handle, linkid, DLADM_PROP_VAL_DEFAULT, 5652 propname, statep->ls_propvals, &valcnt); 5653 5654 if (status == DLADM_STATUS_OK) 5655 return (B_TRUE); 5656 5657 /* 5658 * A system wide default value is not available for the 5659 * property. Check if current value can be retrieved. 5660 */ 5661 status = dladm_get_linkprop(handle, linkid, DLADM_PROP_VAL_CURRENT, 5662 propname, statep->ls_propvals, &valcnt); 5663 5664 return (status == DLADM_STATUS_OK); 5665 } 5666 5667 /* ARGSUSED */ 5668 static int 5669 show_linkprop(dladm_handle_t dh, datalink_id_t linkid, const char *propname, 5670 void *arg) 5671 { 5672 show_linkprop_state_t *statep = arg; 5673 linkprop_args_t ls_arg; 5674 5675 bzero(&ls_arg, sizeof (ls_arg)); 5676 ls_arg.ls_state = statep; 5677 ls_arg.ls_propname = (char *)propname; 5678 ls_arg.ls_linkid = linkid; 5679 5680 if (statep->ls_header) { 5681 statep->ls_header = B_FALSE; 5682 if (!statep->ls_parseable) 5683 print_header(&statep->ls_print); 5684 } 5685 /* 5686 * This will need to be fixed when kernel interfaces are added 5687 * to enable walking of all known private properties. For now, 5688 * we are limited to walking persistent private properties only. 5689 */ 5690 if ((propname[0] == '_') && !statep->ls_persist && 5691 (statep->ls_proplist == NULL)) 5692 return (DLADM_WALK_CONTINUE); 5693 if (!statep->ls_parseable && 5694 !linkprop_is_supported(linkid, propname, statep)) 5695 return (DLADM_WALK_CONTINUE); 5696 5697 dladm_print_output(&statep->ls_print, statep->ls_parseable, 5698 linkprop_callback, (void *)&ls_arg); 5699 5700 return (DLADM_WALK_CONTINUE); 5701 } 5702 5703 static void 5704 do_show_linkprop(int argc, char **argv, const char *use) 5705 { 5706 int option; 5707 dladm_arg_list_t *proplist = NULL; 5708 datalink_id_t linkid = DATALINK_ALL_LINKID; 5709 show_linkprop_state_t state; 5710 uint32_t flags = DLADM_OPT_ACTIVE; 5711 dladm_status_t status; 5712 char *fields_str = NULL; 5713 print_field_t **fields; 5714 uint_t nfields; 5715 boolean_t o_arg = B_FALSE; 5716 char *all_fields = 5717 "link,property,perm,value,default,possible"; 5718 5719 fields_str = all_fields; 5720 5721 opterr = 0; 5722 state.ls_propvals = NULL; 5723 state.ls_line = NULL; 5724 state.ls_parseable = B_FALSE; 5725 state.ls_persist = B_FALSE; 5726 state.ls_header = B_TRUE; 5727 state.ls_retstatus = DLADM_STATUS_OK; 5728 while ((option = getopt_long(argc, argv, ":p:cPo:", 5729 prop_longopts, NULL)) != -1) { 5730 switch (option) { 5731 case 'p': 5732 if (dladm_parse_link_props(optarg, &proplist, B_TRUE) 5733 != DLADM_STATUS_OK) 5734 die("invalid link properties specified"); 5735 break; 5736 case 'c': 5737 state.ls_parseable = B_TRUE; 5738 break; 5739 case 'P': 5740 state.ls_persist = B_TRUE; 5741 flags = DLADM_OPT_PERSIST; 5742 break; 5743 case 'o': 5744 o_arg = B_TRUE; 5745 if (strcasecmp(optarg, "all") == 0) 5746 fields_str = all_fields; 5747 else 5748 fields_str = optarg; 5749 break; 5750 default: 5751 die_opterr(optopt, option, use); 5752 break; 5753 } 5754 } 5755 5756 if (state.ls_parseable && !o_arg) 5757 die("-c requires -o"); 5758 5759 if (state.ls_parseable && fields_str == all_fields) 5760 die("\"-o all\" is invalid with -c"); 5761 5762 if (optind == (argc - 1)) { 5763 if ((status = dladm_name2info(handle, argv[optind], &linkid, 5764 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 5765 die_dlerr(status, "link %s is not valid", argv[optind]); 5766 } 5767 } else if (optind != argc) { 5768 usage(); 5769 } 5770 5771 bzero(&state.ls_print, sizeof (print_state_t)); 5772 state.ls_proplist = proplist; 5773 state.ls_status = DLADM_STATUS_OK; 5774 5775 fields = parse_output_fields(fields_str, linkprop_fields, 5776 LINKPROP_MAX_FIELDS, CMD_TYPE_ANY, &nfields); 5777 5778 if (fields == NULL) { 5779 die("invalid field(s) specified"); 5780 return; 5781 } 5782 5783 state.ls_print.ps_fields = fields; 5784 state.ls_print.ps_nfields = nfields; 5785 if (linkid == DATALINK_ALL_LINKID) { 5786 (void) dladm_walk_datalink_id(show_linkprop_onelink, handle, 5787 &state, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, flags); 5788 } else { 5789 (void) show_linkprop_onelink(handle, linkid, &state); 5790 } 5791 dladm_free_props(proplist); 5792 5793 if (state.ls_retstatus != DLADM_STATUS_OK) { 5794 dladm_close(handle); 5795 exit(EXIT_FAILURE); 5796 } 5797 } 5798 5799 static int 5800 show_linkprop_onelink(dladm_handle_t hdl, datalink_id_t linkid, void *arg) 5801 { 5802 int i; 5803 char *buf; 5804 uint32_t flags; 5805 dladm_arg_list_t *proplist = NULL; 5806 show_linkprop_state_t *statep = arg; 5807 dlpi_handle_t dh = NULL; 5808 5809 statep->ls_status = DLADM_STATUS_OK; 5810 5811 if (dladm_datalink_id2info(hdl, linkid, &flags, NULL, NULL, 5812 statep->ls_link, MAXLINKNAMELEN) != DLADM_STATUS_OK) { 5813 statep->ls_status = DLADM_STATUS_NOTFOUND; 5814 return (DLADM_WALK_CONTINUE); 5815 } 5816 5817 if ((statep->ls_persist && !(flags & DLADM_OPT_PERSIST)) || 5818 (!statep->ls_persist && !(flags & DLADM_OPT_ACTIVE))) { 5819 statep->ls_status = DLADM_STATUS_BADARG; 5820 return (DLADM_WALK_CONTINUE); 5821 } 5822 5823 proplist = statep->ls_proplist; 5824 5825 /* 5826 * When some WiFi links are opened for the first time, their hardware 5827 * automatically scans for APs and does other slow operations. Thus, 5828 * if there are no open links, the retrieval of link properties 5829 * (below) will proceed slowly unless we hold the link open. 5830 * 5831 * Note that failure of dlpi_open() does not necessarily mean invalid 5832 * link properties, because dlpi_open() may fail because of incorrect 5833 * autopush configuration. Therefore, we ingore the return value of 5834 * dlpi_open(). 5835 */ 5836 if (!statep->ls_persist) 5837 (void) dlpi_open(statep->ls_link, &dh, 0); 5838 5839 buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) * 5840 DLADM_MAX_PROP_VALCNT + MAX_PROP_LINE); 5841 if (buf == NULL) 5842 die("insufficient memory"); 5843 5844 statep->ls_propvals = (char **)(void *)buf; 5845 for (i = 0; i < DLADM_MAX_PROP_VALCNT; i++) { 5846 statep->ls_propvals[i] = buf + 5847 sizeof (char *) * DLADM_MAX_PROP_VALCNT + 5848 i * DLADM_PROP_VAL_MAX; 5849 } 5850 statep->ls_line = buf + 5851 (sizeof (char *) + DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT; 5852 5853 if (proplist != NULL) { 5854 for (i = 0; i < proplist->al_count; i++) { 5855 (void) show_linkprop(hdl, linkid, 5856 proplist->al_info[i].ai_name, statep); 5857 } 5858 } else { 5859 (void) dladm_walk_linkprop(hdl, linkid, statep, 5860 show_linkprop); 5861 } 5862 if (dh != NULL) 5863 dlpi_close(dh); 5864 free(buf); 5865 return (DLADM_WALK_CONTINUE); 5866 } 5867 5868 static dladm_status_t 5869 set_linkprop_persist(datalink_id_t linkid, const char *prop_name, 5870 char **prop_val, uint_t val_cnt, boolean_t reset) 5871 { 5872 dladm_status_t status; 5873 5874 status = dladm_set_linkprop(handle, linkid, prop_name, prop_val, 5875 val_cnt, DLADM_OPT_PERSIST); 5876 5877 if (status != DLADM_STATUS_OK) { 5878 warn_dlerr(status, "cannot persistently %s link property '%s'", 5879 reset ? "reset" : "set", prop_name); 5880 } 5881 return (status); 5882 } 5883 5884 static int 5885 reset_one_linkprop(dladm_handle_t dh, datalink_id_t linkid, 5886 const char *propname, void *arg) 5887 { 5888 set_linkprop_state_t *statep = arg; 5889 dladm_status_t status; 5890 5891 status = dladm_set_linkprop(dh, linkid, propname, NULL, 0, 5892 DLADM_OPT_ACTIVE); 5893 if (status != DLADM_STATUS_OK) { 5894 warn_dlerr(status, "cannot reset link property '%s' on '%s'", 5895 propname, statep->ls_name); 5896 } 5897 if (!statep->ls_temp) { 5898 dladm_status_t s; 5899 5900 s = set_linkprop_persist(linkid, propname, NULL, 0, 5901 statep->ls_reset); 5902 if (s != DLADM_STATUS_OK) 5903 status = s; 5904 } 5905 if (status != DLADM_STATUS_OK) 5906 statep->ls_status = status; 5907 5908 return (DLADM_WALK_CONTINUE); 5909 } 5910 5911 static void 5912 set_linkprop(int argc, char **argv, boolean_t reset, const char *use) 5913 { 5914 int i, option; 5915 char errmsg[DLADM_STRSIZE]; 5916 char *altroot = NULL; 5917 datalink_id_t linkid; 5918 boolean_t temp = B_FALSE; 5919 dladm_status_t status = DLADM_STATUS_OK; 5920 dladm_arg_list_t *proplist = NULL; 5921 5922 opterr = 0; 5923 while ((option = getopt_long(argc, argv, ":p:R:t", 5924 prop_longopts, NULL)) != -1) { 5925 switch (option) { 5926 case 'p': 5927 if (dladm_parse_link_props(optarg, &proplist, reset) != 5928 DLADM_STATUS_OK) { 5929 die("invalid link properties specified"); 5930 } 5931 break; 5932 case 't': 5933 temp = B_TRUE; 5934 break; 5935 case 'R': 5936 altroot = optarg; 5937 break; 5938 default: 5939 die_opterr(optopt, option, use); 5940 5941 } 5942 } 5943 5944 /* get link name (required last argument) */ 5945 if (optind != (argc - 1)) 5946 usage(); 5947 5948 if (proplist == NULL && !reset) 5949 die("link property must be specified"); 5950 5951 if (altroot != NULL) { 5952 dladm_free_props(proplist); 5953 altroot_cmd(altroot, argc, argv); 5954 } 5955 5956 status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL, 5957 NULL); 5958 if (status != DLADM_STATUS_OK) 5959 die_dlerr(status, "link %s is not valid", argv[optind]); 5960 5961 if (proplist == NULL) { 5962 set_linkprop_state_t state; 5963 5964 state.ls_name = argv[optind]; 5965 state.ls_reset = reset; 5966 state.ls_temp = temp; 5967 state.ls_status = DLADM_STATUS_OK; 5968 5969 (void) dladm_walk_linkprop(handle, linkid, &state, 5970 reset_one_linkprop); 5971 5972 status = state.ls_status; 5973 goto done; 5974 } 5975 5976 for (i = 0; i < proplist->al_count; i++) { 5977 dladm_arg_info_t *aip = &proplist->al_info[i]; 5978 char **val; 5979 uint_t count; 5980 dladm_status_t s; 5981 5982 if (reset) { 5983 val = NULL; 5984 count = 0; 5985 } else { 5986 val = aip->ai_val; 5987 count = aip->ai_count; 5988 if (count == 0) { 5989 warn("no value specified for '%s'", 5990 aip->ai_name); 5991 status = DLADM_STATUS_BADARG; 5992 continue; 5993 } 5994 } 5995 s = dladm_set_linkprop(handle, linkid, aip->ai_name, val, count, 5996 DLADM_OPT_ACTIVE); 5997 if (s == DLADM_STATUS_OK) { 5998 if (!temp) { 5999 s = set_linkprop_persist(linkid, 6000 aip->ai_name, val, count, reset); 6001 if (s != DLADM_STATUS_OK) 6002 status = s; 6003 } 6004 continue; 6005 } 6006 status = s; 6007 switch (s) { 6008 case DLADM_STATUS_NOTFOUND: 6009 warn("invalid link property '%s'", aip->ai_name); 6010 break; 6011 case DLADM_STATUS_BADVAL: { 6012 int j; 6013 char *ptr, *lim; 6014 char **propvals = NULL; 6015 uint_t valcnt = DLADM_MAX_PROP_VALCNT; 6016 6017 ptr = malloc((sizeof (char *) + 6018 DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT + 6019 MAX_PROP_LINE); 6020 6021 propvals = (char **)(void *)ptr; 6022 if (propvals == NULL) 6023 die("insufficient memory"); 6024 6025 for (j = 0; j < DLADM_MAX_PROP_VALCNT; j++) { 6026 propvals[j] = ptr + sizeof (char *) * 6027 DLADM_MAX_PROP_VALCNT + 6028 j * DLADM_PROP_VAL_MAX; 6029 } 6030 s = dladm_get_linkprop(handle, linkid, 6031 DLADM_PROP_VAL_MODIFIABLE, aip->ai_name, propvals, 6032 &valcnt); 6033 6034 if (s != DLADM_STATUS_OK) { 6035 warn_dlerr(status, "cannot set link property " 6036 "'%s' on '%s'", aip->ai_name, argv[optind]); 6037 free(propvals); 6038 break; 6039 } 6040 6041 ptr = errmsg; 6042 lim = ptr + DLADM_STRSIZE; 6043 *ptr = '\0'; 6044 for (j = 0; j < valcnt; j++) { 6045 ptr += snprintf(ptr, lim - ptr, "%s,", 6046 propvals[j]); 6047 if (ptr >= lim) 6048 break; 6049 } 6050 if (ptr > errmsg) { 6051 *(ptr - 1) = '\0'; 6052 warn("link property '%s' must be one of: %s", 6053 aip->ai_name, errmsg); 6054 } else 6055 warn("invalid link property '%s'", *val); 6056 free(propvals); 6057 break; 6058 } 6059 default: 6060 if (reset) { 6061 warn_dlerr(status, "cannot reset link property " 6062 "'%s' on '%s'", aip->ai_name, argv[optind]); 6063 } else { 6064 warn_dlerr(status, "cannot set link property " 6065 "'%s' on '%s'", aip->ai_name, argv[optind]); 6066 } 6067 break; 6068 } 6069 } 6070 done: 6071 dladm_free_props(proplist); 6072 if (status != DLADM_STATUS_OK) { 6073 dladm_close(handle); 6074 exit(1); 6075 } 6076 } 6077 6078 static void 6079 do_set_linkprop(int argc, char **argv, const char *use) 6080 { 6081 set_linkprop(argc, argv, B_FALSE, use); 6082 } 6083 6084 static void 6085 do_reset_linkprop(int argc, char **argv, const char *use) 6086 { 6087 set_linkprop(argc, argv, B_TRUE, use); 6088 } 6089 6090 static int 6091 convert_secobj(char *buf, uint_t len, uint8_t *obj_val, uint_t *obj_lenp, 6092 dladm_secobj_class_t class) 6093 { 6094 int error = 0; 6095 6096 if (class == DLADM_SECOBJ_CLASS_WPA) { 6097 if (len < 8 || len > 63) 6098 return (EINVAL); 6099 (void) memcpy(obj_val, buf, len); 6100 *obj_lenp = len; 6101 return (error); 6102 } 6103 6104 if (class == DLADM_SECOBJ_CLASS_WEP) { 6105 switch (len) { 6106 case 5: /* ASCII key sizes */ 6107 case 13: 6108 (void) memcpy(obj_val, buf, len); 6109 *obj_lenp = len; 6110 break; 6111 case 10: /* Hex key sizes, not preceded by 0x */ 6112 case 26: 6113 error = hexascii_to_octet(buf, len, obj_val, obj_lenp); 6114 break; 6115 case 12: /* Hex key sizes, preceded by 0x */ 6116 case 28: 6117 if (strncmp(buf, "0x", 2) != 0) 6118 return (EINVAL); 6119 error = hexascii_to_octet(buf + 2, len - 2, 6120 obj_val, obj_lenp); 6121 break; 6122 default: 6123 return (EINVAL); 6124 } 6125 return (error); 6126 } 6127 6128 return (ENOENT); 6129 } 6130 6131 static void 6132 defersig(int sig) 6133 { 6134 signalled = sig; 6135 } 6136 6137 static int 6138 get_secobj_from_tty(uint_t try, const char *objname, char *buf) 6139 { 6140 uint_t len = 0; 6141 int c; 6142 struct termios stored, current; 6143 void (*sigfunc)(int); 6144 6145 /* 6146 * Turn off echo -- but before we do so, defer SIGINT handling 6147 * so that a ^C doesn't leave the terminal corrupted. 6148 */ 6149 sigfunc = signal(SIGINT, defersig); 6150 (void) fflush(stdin); 6151 (void) tcgetattr(0, &stored); 6152 current = stored; 6153 current.c_lflag &= ~(ICANON|ECHO); 6154 current.c_cc[VTIME] = 0; 6155 current.c_cc[VMIN] = 1; 6156 (void) tcsetattr(0, TCSANOW, ¤t); 6157 again: 6158 if (try == 1) 6159 (void) printf(gettext("provide value for '%s': "), objname); 6160 else 6161 (void) printf(gettext("confirm value for '%s': "), objname); 6162 6163 (void) fflush(stdout); 6164 while (signalled == 0) { 6165 c = getchar(); 6166 if (c == '\n' || c == '\r') { 6167 if (len != 0) 6168 break; 6169 (void) putchar('\n'); 6170 goto again; 6171 } 6172 6173 buf[len++] = c; 6174 if (len >= DLADM_SECOBJ_VAL_MAX - 1) 6175 break; 6176 (void) putchar('*'); 6177 } 6178 6179 (void) putchar('\n'); 6180 (void) fflush(stdin); 6181 6182 /* 6183 * Restore terminal setting and handle deferred signals. 6184 */ 6185 (void) tcsetattr(0, TCSANOW, &stored); 6186 6187 (void) signal(SIGINT, sigfunc); 6188 if (signalled != 0) 6189 (void) kill(getpid(), signalled); 6190 6191 return (len); 6192 } 6193 6194 static int 6195 get_secobj_val(char *obj_name, uint8_t *obj_val, uint_t *obj_lenp, 6196 dladm_secobj_class_t class, FILE *filep) 6197 { 6198 int rval; 6199 uint_t len, len2; 6200 char buf[DLADM_SECOBJ_VAL_MAX], buf2[DLADM_SECOBJ_VAL_MAX]; 6201 6202 if (filep == NULL) { 6203 len = get_secobj_from_tty(1, obj_name, buf); 6204 rval = convert_secobj(buf, len, obj_val, obj_lenp, class); 6205 if (rval == 0) { 6206 len2 = get_secobj_from_tty(2, obj_name, buf2); 6207 if (len != len2 || memcmp(buf, buf2, len) != 0) 6208 rval = ENOTSUP; 6209 } 6210 return (rval); 6211 } else { 6212 for (;;) { 6213 if (fgets(buf, sizeof (buf), filep) == NULL) 6214 break; 6215 if (isspace(buf[0])) 6216 continue; 6217 6218 len = strlen(buf); 6219 if (buf[len - 1] == '\n') { 6220 buf[len - 1] = '\0'; 6221 len--; 6222 } 6223 break; 6224 } 6225 (void) fclose(filep); 6226 } 6227 return (convert_secobj(buf, len, obj_val, obj_lenp, class)); 6228 } 6229 6230 static boolean_t 6231 check_auth(const char *auth) 6232 { 6233 struct passwd *pw; 6234 6235 if ((pw = getpwuid(getuid())) == NULL) 6236 return (B_FALSE); 6237 6238 return (chkauthattr(auth, pw->pw_name) != 0); 6239 } 6240 6241 static void 6242 audit_secobj(char *auth, char *class, char *obj, 6243 boolean_t success, boolean_t create) 6244 { 6245 adt_session_data_t *ah; 6246 adt_event_data_t *event; 6247 au_event_t flag; 6248 char *errstr; 6249 6250 if (create) { 6251 flag = ADT_dladm_create_secobj; 6252 errstr = "ADT_dladm_create_secobj"; 6253 } else { 6254 flag = ADT_dladm_delete_secobj; 6255 errstr = "ADT_dladm_delete_secobj"; 6256 } 6257 6258 if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) 6259 die("adt_start_session: %s", strerror(errno)); 6260 6261 if ((event = adt_alloc_event(ah, flag)) == NULL) 6262 die("adt_alloc_event (%s): %s", errstr, strerror(errno)); 6263 6264 /* fill in audit info */ 6265 if (create) { 6266 event->adt_dladm_create_secobj.auth_used = auth; 6267 event->adt_dladm_create_secobj.obj_class = class; 6268 event->adt_dladm_create_secobj.obj_name = obj; 6269 } else { 6270 event->adt_dladm_delete_secobj.auth_used = auth; 6271 event->adt_dladm_delete_secobj.obj_class = class; 6272 event->adt_dladm_delete_secobj.obj_name = obj; 6273 } 6274 6275 if (success) { 6276 if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) { 6277 die("adt_put_event (%s, success): %s", errstr, 6278 strerror(errno)); 6279 } 6280 } else { 6281 if (adt_put_event(event, ADT_FAILURE, 6282 ADT_FAIL_VALUE_AUTH) != 0) { 6283 die("adt_put_event: (%s, failure): %s", errstr, 6284 strerror(errno)); 6285 } 6286 } 6287 6288 adt_free_event(event); 6289 (void) adt_end_session(ah); 6290 } 6291 6292 #define MAX_SECOBJS 32 6293 #define MAX_SECOBJ_NAMELEN 32 6294 static void 6295 do_create_secobj(int argc, char **argv, const char *use) 6296 { 6297 int option, rval; 6298 FILE *filep = NULL; 6299 char *obj_name = NULL; 6300 char *class_name = NULL; 6301 uint8_t obj_val[DLADM_SECOBJ_VAL_MAX]; 6302 uint_t obj_len; 6303 boolean_t success, temp = B_FALSE; 6304 dladm_status_t status; 6305 dladm_secobj_class_t class = -1; 6306 uid_t euid; 6307 6308 opterr = 0; 6309 (void) memset(obj_val, 0, DLADM_SECOBJ_VAL_MAX); 6310 while ((option = getopt_long(argc, argv, ":f:c:R:t", 6311 wifi_longopts, NULL)) != -1) { 6312 switch (option) { 6313 case 'f': 6314 euid = geteuid(); 6315 (void) seteuid(getuid()); 6316 filep = fopen(optarg, "r"); 6317 if (filep == NULL) { 6318 die("cannot open %s: %s", optarg, 6319 strerror(errno)); 6320 } 6321 (void) seteuid(euid); 6322 break; 6323 case 'c': 6324 class_name = optarg; 6325 status = dladm_str2secobjclass(optarg, &class); 6326 if (status != DLADM_STATUS_OK) { 6327 die("invalid secure object class '%s', " 6328 "valid values are: wep, wpa", optarg); 6329 } 6330 break; 6331 case 't': 6332 temp = B_TRUE; 6333 break; 6334 case 'R': 6335 status = dladm_set_rootdir(optarg); 6336 if (status != DLADM_STATUS_OK) { 6337 die_dlerr(status, "invalid directory " 6338 "specified"); 6339 } 6340 break; 6341 default: 6342 die_opterr(optopt, option, use); 6343 break; 6344 } 6345 } 6346 6347 if (optind == (argc - 1)) 6348 obj_name = argv[optind]; 6349 else if (optind != argc) 6350 usage(); 6351 6352 if (class == -1) 6353 die("secure object class required"); 6354 6355 if (obj_name == NULL) 6356 die("secure object name required"); 6357 6358 if (!dladm_valid_secobj_name(obj_name)) 6359 die("invalid secure object name '%s'", obj_name); 6360 6361 success = check_auth(LINK_SEC_AUTH); 6362 audit_secobj(LINK_SEC_AUTH, class_name, obj_name, success, B_TRUE); 6363 if (!success) 6364 die("authorization '%s' is required", LINK_SEC_AUTH); 6365 6366 rval = get_secobj_val(obj_name, obj_val, &obj_len, class, filep); 6367 if (rval != 0) { 6368 switch (rval) { 6369 case ENOENT: 6370 die("invalid secure object class"); 6371 break; 6372 case EINVAL: 6373 die("invalid secure object value"); 6374 break; 6375 case ENOTSUP: 6376 die("verification failed"); 6377 break; 6378 default: 6379 die("invalid secure object: %s", strerror(rval)); 6380 break; 6381 } 6382 } 6383 6384 status = dladm_set_secobj(handle, obj_name, class, obj_val, obj_len, 6385 DLADM_OPT_CREATE | DLADM_OPT_ACTIVE); 6386 if (status != DLADM_STATUS_OK) { 6387 die_dlerr(status, "could not create secure object '%s'", 6388 obj_name); 6389 } 6390 if (temp) 6391 return; 6392 6393 status = dladm_set_secobj(handle, obj_name, class, obj_val, obj_len, 6394 DLADM_OPT_PERSIST); 6395 if (status != DLADM_STATUS_OK) { 6396 warn_dlerr(status, "could not persistently create secure " 6397 "object '%s'", obj_name); 6398 } 6399 } 6400 6401 static void 6402 do_delete_secobj(int argc, char **argv, const char *use) 6403 { 6404 int i, option; 6405 boolean_t temp = B_FALSE; 6406 split_t *sp = NULL; 6407 boolean_t success; 6408 dladm_status_t status, pstatus; 6409 6410 opterr = 0; 6411 status = pstatus = DLADM_STATUS_OK; 6412 while ((option = getopt_long(argc, argv, ":R:t", 6413 wifi_longopts, NULL)) != -1) { 6414 switch (option) { 6415 case 't': 6416 temp = B_TRUE; 6417 break; 6418 case 'R': 6419 status = dladm_set_rootdir(optarg); 6420 if (status != DLADM_STATUS_OK) { 6421 die_dlerr(status, "invalid directory " 6422 "specified"); 6423 } 6424 break; 6425 default: 6426 die_opterr(optopt, option, use); 6427 break; 6428 } 6429 } 6430 6431 if (optind == (argc - 1)) { 6432 sp = split(argv[optind], MAX_SECOBJS, MAX_SECOBJ_NAMELEN); 6433 if (sp == NULL) { 6434 die("invalid secure object name(s): '%s'", 6435 argv[optind]); 6436 } 6437 } else if (optind != argc) 6438 usage(); 6439 6440 if (sp == NULL || sp->s_nfields < 1) 6441 die("secure object name required"); 6442 6443 success = check_auth(LINK_SEC_AUTH); 6444 audit_secobj(LINK_SEC_AUTH, "unknown", argv[optind], success, B_FALSE); 6445 if (!success) 6446 die("authorization '%s' is required", LINK_SEC_AUTH); 6447 6448 for (i = 0; i < sp->s_nfields; i++) { 6449 status = dladm_unset_secobj(handle, sp->s_fields[i], 6450 DLADM_OPT_ACTIVE); 6451 if (!temp) { 6452 pstatus = dladm_unset_secobj(handle, sp->s_fields[i], 6453 DLADM_OPT_PERSIST); 6454 } else { 6455 pstatus = DLADM_STATUS_OK; 6456 } 6457 6458 if (status != DLADM_STATUS_OK) { 6459 warn_dlerr(status, "could not delete secure object " 6460 "'%s'", sp->s_fields[i]); 6461 } 6462 if (pstatus != DLADM_STATUS_OK) { 6463 warn_dlerr(pstatus, "could not persistently delete " 6464 "secure object '%s'", sp->s_fields[i]); 6465 } 6466 } 6467 6468 if (status != DLADM_STATUS_OK || pstatus != DLADM_STATUS_OK) { 6469 dladm_close(handle); 6470 exit(1); 6471 } 6472 } 6473 6474 typedef struct show_secobj_state { 6475 boolean_t ss_persist; 6476 boolean_t ss_parseable; 6477 boolean_t ss_header; 6478 print_state_t ss_print; 6479 } show_secobj_state_t; 6480 6481 6482 static boolean_t 6483 show_secobj(dladm_handle_t dh, void *arg, const char *obj_name) 6484 { 6485 uint_t obj_len = DLADM_SECOBJ_VAL_MAX; 6486 uint8_t obj_val[DLADM_SECOBJ_VAL_MAX]; 6487 char buf[DLADM_STRSIZE]; 6488 uint_t flags = 0; 6489 dladm_secobj_class_t class; 6490 show_secobj_state_t *statep = arg; 6491 dladm_status_t status; 6492 secobj_fields_buf_t sbuf; 6493 6494 bzero(&sbuf, sizeof (secobj_fields_buf_t)); 6495 if (statep->ss_persist) 6496 flags |= DLADM_OPT_PERSIST; 6497 6498 status = dladm_get_secobj(dh, obj_name, &class, obj_val, &obj_len, 6499 flags); 6500 if (status != DLADM_STATUS_OK) 6501 die_dlerr(status, "cannot get secure object '%s'", obj_name); 6502 6503 if (statep->ss_header) { 6504 statep->ss_header = B_FALSE; 6505 if (!statep->ss_parseable) 6506 print_header(&statep->ss_print); 6507 } 6508 6509 (void) snprintf(sbuf.ss_obj_name, sizeof (sbuf.ss_obj_name), 6510 obj_name); 6511 (void) dladm_secobjclass2str(class, buf); 6512 (void) snprintf(sbuf.ss_class, sizeof (sbuf.ss_class), "%s", buf); 6513 if (getuid() == 0) { 6514 char val[DLADM_SECOBJ_VAL_MAX * 2]; 6515 uint_t len = sizeof (val); 6516 6517 if (octet_to_hexascii(obj_val, obj_len, val, &len) == 0) 6518 (void) snprintf(sbuf.ss_val, 6519 sizeof (sbuf.ss_val), "%s", val); 6520 } 6521 dladm_print_output(&statep->ss_print, statep->ss_parseable, 6522 dladm_print_field, (void *)&sbuf); 6523 return (B_TRUE); 6524 } 6525 6526 static void 6527 do_show_secobj(int argc, char **argv, const char *use) 6528 { 6529 int option; 6530 show_secobj_state_t state; 6531 dladm_status_t status; 6532 boolean_t o_arg = B_FALSE; 6533 uint_t i; 6534 split_t *sp; 6535 uint_t flags; 6536 char *fields_str = NULL; 6537 print_field_t **fields; 6538 uint_t nfields; 6539 char *def_fields = "object,class"; 6540 char *all_fields = "object,class,value"; 6541 6542 opterr = 0; 6543 bzero(&state, sizeof (state)); 6544 state.ss_parseable = B_FALSE; 6545 fields_str = def_fields; 6546 state.ss_persist = B_FALSE; 6547 state.ss_parseable = B_FALSE; 6548 state.ss_header = B_TRUE; 6549 while ((option = getopt_long(argc, argv, ":pPo:", 6550 wifi_longopts, NULL)) != -1) { 6551 switch (option) { 6552 case 'p': 6553 state.ss_parseable = B_TRUE; 6554 break; 6555 case 'P': 6556 state.ss_persist = B_TRUE; 6557 break; 6558 case 'o': 6559 o_arg = B_TRUE; 6560 if (strcasecmp(optarg, "all") == 0) 6561 fields_str = all_fields; 6562 else 6563 fields_str = optarg; 6564 break; 6565 default: 6566 die_opterr(optopt, option, use); 6567 break; 6568 } 6569 } 6570 6571 if (state.ss_parseable && !o_arg) 6572 die("option -c requires -o"); 6573 6574 if (state.ss_parseable && fields_str == all_fields) 6575 die("\"-o all\" is invalid with -p"); 6576 6577 fields = parse_output_fields(fields_str, secobj_fields, 6578 DEV_SOBJ_FIELDS, CMD_TYPE_ANY, &nfields); 6579 6580 if (fields == NULL) { 6581 die("invalid field(s) specified"); 6582 return; 6583 } 6584 state.ss_print.ps_fields = fields; 6585 state.ss_print.ps_nfields = nfields; 6586 6587 flags = state.ss_persist ? DLADM_OPT_PERSIST : 0; 6588 6589 if (optind == (argc - 1)) { 6590 sp = split(argv[optind], MAX_SECOBJS, MAX_SECOBJ_NAMELEN); 6591 if (sp == NULL) { 6592 die("invalid secure object name(s): '%s'", 6593 argv[optind]); 6594 } 6595 for (i = 0; i < sp->s_nfields; i++) { 6596 if (!show_secobj(handle, &state, sp->s_fields[i])) 6597 break; 6598 } 6599 splitfree(sp); 6600 return; 6601 } else if (optind != argc) 6602 usage(); 6603 6604 status = dladm_walk_secobj(handle, &state, show_secobj, flags); 6605 6606 if (status != DLADM_STATUS_OK) 6607 die_dlerr(status, "show-secobj"); 6608 } 6609 6610 /*ARGSUSED*/ 6611 static int 6612 i_dladm_init_linkprop(dladm_handle_t dh, datalink_id_t linkid, void *arg) 6613 { 6614 (void) dladm_init_linkprop(dh, linkid, B_TRUE); 6615 return (DLADM_WALK_CONTINUE); 6616 } 6617 6618 /*ARGSUSED*/ 6619 void 6620 do_init_linkprop(int argc, char **argv, const char *use) 6621 { 6622 int option; 6623 dladm_status_t status; 6624 datalink_id_t linkid = DATALINK_ALL_LINKID; 6625 datalink_media_t media = DATALINK_ANY_MEDIATYPE; 6626 uint_t any_media = B_TRUE; 6627 6628 opterr = 0; 6629 while ((option = getopt(argc, argv, ":w")) != -1) { 6630 switch (option) { 6631 case 'w': 6632 media = DL_WIFI; 6633 any_media = B_FALSE; 6634 break; 6635 default: 6636 /* 6637 * Because init-linkprop is not a public command, 6638 * print the usage instead. 6639 */ 6640 usage(); 6641 break; 6642 } 6643 } 6644 6645 if (optind == (argc - 1)) { 6646 if ((status = dladm_name2info(handle, argv[optind], &linkid, 6647 NULL, NULL, NULL)) != DLADM_STATUS_OK) 6648 die_dlerr(status, "link %s is not valid", argv[optind]); 6649 } else if (optind != argc) { 6650 usage(); 6651 } 6652 6653 if (linkid == DATALINK_ALL_LINKID) { 6654 /* 6655 * linkprops of links of other classes have been initialized as 6656 * part of the dladm up-xxx operation. 6657 */ 6658 (void) dladm_walk_datalink_id(i_dladm_init_linkprop, handle, 6659 NULL, DATALINK_CLASS_PHYS, media, DLADM_OPT_PERSIST); 6660 } else { 6661 (void) dladm_init_linkprop(handle, linkid, any_media); 6662 } 6663 } 6664 6665 static void 6666 do_show_ether(int argc, char **argv, const char *use) 6667 { 6668 int option; 6669 datalink_id_t linkid; 6670 print_ether_state_t state; 6671 print_field_t **fields; 6672 boolean_t o_arg = B_FALSE; 6673 char *fields_str; 6674 uint_t nfields; 6675 char *all_fields = 6676 "link,ptype,state,auto,speed-duplex,pause,rem_fault"; 6677 char *default_fields = 6678 "link,ptype,state,auto,speed-duplex,pause"; 6679 6680 fields_str = default_fields; 6681 bzero(&state, sizeof (state)); 6682 state.es_link = NULL; 6683 state.es_parseable = B_FALSE; 6684 6685 while ((option = getopt_long(argc, argv, "o:px", 6686 showeth_lopts, NULL)) != -1) { 6687 switch (option) { 6688 case 'x': 6689 state.es_extended = B_TRUE; 6690 break; 6691 case 'p': 6692 state.es_parseable = B_TRUE; 6693 break; 6694 case 'o': 6695 o_arg = B_TRUE; 6696 if (strcasecmp(optarg, "all") == 0) 6697 fields_str = all_fields; 6698 else 6699 fields_str = optarg; 6700 break; 6701 default: 6702 die_opterr(optopt, option, use); 6703 break; 6704 } 6705 } 6706 6707 if (state.es_parseable && !o_arg) 6708 die("-p requires -o"); 6709 6710 if (state.es_parseable && fields_str == all_fields) 6711 die("\"-o all\" is invalid with -p"); 6712 6713 if (optind == (argc - 1)) 6714 state.es_link = argv[optind]; 6715 6716 fields = parse_output_fields(fields_str, ether_fields, 6717 ETHER_MAX_FIELDS, CMD_TYPE_ANY, &nfields); 6718 6719 if (fields == NULL) 6720 die("invalid field(s) specified"); 6721 6722 state.es_print.ps_fields = fields; 6723 state.es_print.ps_nfields = nfields; 6724 6725 6726 if (state.es_link == NULL) { 6727 (void) dladm_walk_datalink_id(show_etherprop, handle, &state, 6728 DATALINK_CLASS_PHYS, DL_ETHER, 6729 DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST); 6730 } else { 6731 if (!link_is_ether(state.es_link, &linkid)) 6732 die("invalid link specified"); 6733 (void) show_etherprop(handle, linkid, &state); 6734 } 6735 } 6736 6737 static char * 6738 dladm_print_field(print_field_t *pf, void *arg) 6739 { 6740 char *value; 6741 6742 value = (char *)arg + pf->pf_offset; 6743 return (value); 6744 } 6745 6746 static int 6747 show_etherprop(dladm_handle_t dh, datalink_id_t linkid, void *arg) 6748 { 6749 print_ether_state_t *statep = arg; 6750 ether_fields_buf_t ebuf; 6751 dladm_ether_info_t eattr; 6752 dladm_status_t status; 6753 6754 bzero(&ebuf, sizeof (ether_fields_buf_t)); 6755 if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, 6756 ebuf.eth_link, sizeof (ebuf.eth_link)) != DLADM_STATUS_OK) { 6757 return (DLADM_WALK_CONTINUE); 6758 } 6759 6760 if (!statep->es_header && !statep->es_parseable) { 6761 print_header(&statep->es_print); 6762 statep->es_header = B_TRUE; 6763 } 6764 6765 status = dladm_ether_info(dh, linkid, &eattr); 6766 if (status != DLADM_STATUS_OK) 6767 goto cleanup; 6768 6769 (void) strlcpy(ebuf.eth_ptype, "current", sizeof (ebuf.eth_ptype)); 6770 6771 (void) dladm_ether_autoneg2str(ebuf.eth_autoneg, 6772 sizeof (ebuf.eth_autoneg), &eattr, CURRENT); 6773 (void) dladm_ether_pause2str(ebuf.eth_pause, 6774 sizeof (ebuf.eth_pause), &eattr, CURRENT); 6775 (void) dladm_ether_spdx2str(ebuf.eth_spdx, 6776 sizeof (ebuf.eth_spdx), &eattr, CURRENT); 6777 (void) strlcpy(ebuf.eth_state, 6778 dladm_linkstate2str(eattr.lei_state, ebuf.eth_state), 6779 sizeof (ebuf.eth_state)); 6780 (void) strlcpy(ebuf.eth_rem_fault, 6781 (eattr.lei_attr[CURRENT].le_fault ? "fault" : "none"), 6782 sizeof (ebuf.eth_rem_fault)); 6783 6784 dladm_print_output(&statep->es_print, statep->es_parseable, 6785 dladm_print_field, &ebuf); 6786 6787 if (statep->es_extended) 6788 show_ether_xprop(arg, &eattr); 6789 6790 cleanup: 6791 dladm_ether_info_done(&eattr); 6792 return (DLADM_WALK_CONTINUE); 6793 } 6794 6795 /* ARGSUSED */ 6796 static void 6797 do_init_secobj(int argc, char **argv, const char *use) 6798 { 6799 dladm_status_t status; 6800 6801 status = dladm_init_secobj(handle); 6802 if (status != DLADM_STATUS_OK) 6803 die_dlerr(status, "secure object initialization failed"); 6804 } 6805 6806 /* 6807 * "-R" option support. It is used for live upgrading. Append dladm commands 6808 * to a upgrade script which will be run when the alternative root boots up: 6809 * 6810 * - If the /etc/dladm/datalink.conf file exists on the alternative root, 6811 * append dladm commands to the <altroot>/var/svc/profile/upgrade_datalink 6812 * script. This script will be run as part of the network/physical service. 6813 * We cannot defer this to /var/svc/profile/upgrade because then the 6814 * configuration will not be able to take effect before network/physical 6815 * plumbs various interfaces. 6816 * 6817 * - If the /etc/dladm/datalink.conf file does not exist on the alternative 6818 * root, append dladm commands to the <altroot>/var/svc/profile/upgrade script, 6819 * which will be run in the manifest-import service. 6820 * 6821 * Note that the SMF team is considering to move the manifest-import service 6822 * to be run at the very begining of boot. Once that is done, the need for 6823 * the /var/svc/profile/upgrade_datalink script will not exist any more. 6824 */ 6825 static void 6826 altroot_cmd(char *altroot, int argc, char *argv[]) 6827 { 6828 char path[MAXPATHLEN]; 6829 struct stat stbuf; 6830 FILE *fp; 6831 int i; 6832 6833 /* 6834 * Check for the existence of the /etc/dladm/datalink.conf 6835 * configuration file, and determine the name of script file. 6836 */ 6837 (void) snprintf(path, MAXPATHLEN, "/%s/etc/dladm/datalink.conf", 6838 altroot); 6839 if (stat(path, &stbuf) < 0) { 6840 (void) snprintf(path, MAXPATHLEN, "/%s/%s", altroot, 6841 SMF_UPGRADE_FILE); 6842 } else { 6843 (void) snprintf(path, MAXPATHLEN, "/%s/%s", altroot, 6844 SMF_UPGRADEDATALINK_FILE); 6845 } 6846 6847 if ((fp = fopen(path, "a+")) == NULL) 6848 die("operation not supported on %s", altroot); 6849 6850 (void) fprintf(fp, "/sbin/dladm "); 6851 for (i = 0; i < argc; i++) { 6852 /* 6853 * Directly write to the file if it is not the "-R <altroot>" 6854 * option. In which case, skip it. 6855 */ 6856 if (strcmp(argv[i], "-R") != 0) 6857 (void) fprintf(fp, "%s ", argv[i]); 6858 else 6859 i ++; 6860 } 6861 (void) fprintf(fp, "%s\n", SMF_DLADM_UPGRADE_MSG); 6862 (void) fclose(fp); 6863 dladm_close(handle); 6864 exit(0); 6865 } 6866 6867 /* 6868 * Convert the string to an integer. Note that the string must not have any 6869 * trailing non-integer characters. 6870 */ 6871 static boolean_t 6872 str2int(const char *str, int *valp) 6873 { 6874 int val; 6875 char *endp = NULL; 6876 6877 errno = 0; 6878 val = strtol(str, &endp, 10); 6879 if (errno != 0 || *endp != '\0') 6880 return (B_FALSE); 6881 6882 *valp = val; 6883 return (B_TRUE); 6884 } 6885 6886 /* PRINTFLIKE1 */ 6887 static void 6888 warn(const char *format, ...) 6889 { 6890 va_list alist; 6891 6892 format = gettext(format); 6893 (void) fprintf(stderr, "%s: warning: ", progname); 6894 6895 va_start(alist, format); 6896 (void) vfprintf(stderr, format, alist); 6897 va_end(alist); 6898 6899 (void) putchar('\n'); 6900 } 6901 6902 /* PRINTFLIKE2 */ 6903 static void 6904 warn_dlerr(dladm_status_t err, const char *format, ...) 6905 { 6906 va_list alist; 6907 char errmsg[DLADM_STRSIZE]; 6908 6909 format = gettext(format); 6910 (void) fprintf(stderr, gettext("%s: warning: "), progname); 6911 6912 va_start(alist, format); 6913 (void) vfprintf(stderr, format, alist); 6914 va_end(alist); 6915 (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg)); 6916 } 6917 6918 /* 6919 * Also closes the dladm handle if it is not NULL. 6920 */ 6921 /* PRINTFLIKE2 */ 6922 static void 6923 die_dlerr(dladm_status_t err, const char *format, ...) 6924 { 6925 va_list alist; 6926 char errmsg[DLADM_STRSIZE]; 6927 6928 format = gettext(format); 6929 (void) fprintf(stderr, "%s: ", progname); 6930 6931 va_start(alist, format); 6932 (void) vfprintf(stderr, format, alist); 6933 va_end(alist); 6934 (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg)); 6935 6936 /* close dladm handle if it was opened */ 6937 if (handle != NULL) 6938 dladm_close(handle); 6939 6940 exit(EXIT_FAILURE); 6941 } 6942 6943 /* PRINTFLIKE1 */ 6944 static void 6945 die(const char *format, ...) 6946 { 6947 va_list alist; 6948 6949 format = gettext(format); 6950 (void) fprintf(stderr, "%s: ", progname); 6951 6952 va_start(alist, format); 6953 (void) vfprintf(stderr, format, alist); 6954 va_end(alist); 6955 6956 (void) putchar('\n'); 6957 6958 /* close dladm handle if it was opened */ 6959 if (handle != NULL) 6960 dladm_close(handle); 6961 6962 exit(EXIT_FAILURE); 6963 } 6964 6965 static void 6966 die_optdup(int opt) 6967 { 6968 die("the option -%c cannot be specified more than once", opt); 6969 } 6970 6971 static void 6972 die_opterr(int opt, int opterr, const char *usage) 6973 { 6974 switch (opterr) { 6975 case ':': 6976 die("option '-%c' requires a value\nusage: %s", opt, 6977 gettext(usage)); 6978 break; 6979 case '?': 6980 default: 6981 die("unrecognized option '-%c'\nusage: %s", opt, 6982 gettext(usage)); 6983 break; 6984 } 6985 } 6986 6987 static void 6988 show_ether_xprop(void *arg, dladm_ether_info_t *eattr) 6989 { 6990 print_ether_state_t *statep = arg; 6991 ether_fields_buf_t ebuf; 6992 int i; 6993 6994 for (i = CAPABLE; i <= PEERADV; i++) { 6995 bzero(&ebuf, sizeof (ebuf)); 6996 (void) strlcpy(ebuf.eth_ptype, ptype[i], 6997 sizeof (ebuf.eth_ptype)); 6998 (void) dladm_ether_autoneg2str(ebuf.eth_autoneg, 6999 sizeof (ebuf.eth_autoneg), eattr, i); 7000 (void) dladm_ether_spdx2str(ebuf.eth_spdx, 7001 sizeof (ebuf.eth_spdx), eattr, i); 7002 (void) dladm_ether_pause2str(ebuf.eth_pause, 7003 sizeof (ebuf.eth_pause), eattr, i); 7004 (void) strlcpy(ebuf.eth_rem_fault, 7005 (eattr->lei_attr[i].le_fault ? "fault" : "none"), 7006 sizeof (ebuf.eth_rem_fault)); 7007 dladm_print_output(&statep->es_print, statep->es_parseable, 7008 dladm_print_field, &ebuf); 7009 } 7010 7011 } 7012 7013 static void 7014 dladm_print_output(print_state_t *statep, boolean_t parseable, 7015 print_callback_t fn, void *arg) 7016 { 7017 int i; 7018 char *value; 7019 print_field_t **pf; 7020 7021 pf = statep->ps_fields; 7022 for (i = 0; i < statep->ps_nfields; i++) { 7023 statep->ps_lastfield = (i + 1 == statep->ps_nfields); 7024 value = (*fn)(pf[i], arg); 7025 if (value != NULL) 7026 print_field(statep, pf[i], value, parseable); 7027 } 7028 (void) putchar('\n'); 7029 } 7030 7031 static void 7032 print_header(print_state_t *ps) 7033 { 7034 int i; 7035 print_field_t **pf; 7036 7037 pf = ps->ps_fields; 7038 for (i = 0; i < ps->ps_nfields; i++) { 7039 ps->ps_lastfield = (i + 1 == ps->ps_nfields); 7040 print_field(ps, pf[i], pf[i]->pf_header, B_FALSE); 7041 } 7042 (void) putchar('\n'); 7043 } 7044 7045 static boolean_t 7046 link_is_ether(const char *link, datalink_id_t *linkid) 7047 { 7048 uint32_t media; 7049 datalink_class_t class; 7050 7051 if (dladm_name2info(handle, link, linkid, NULL, &class, &media) == 7052 DLADM_STATUS_OK) { 7053 if (class == DATALINK_CLASS_PHYS && media == DL_ETHER) 7054 return (B_TRUE); 7055 } 7056 return (B_FALSE); 7057 } 7058