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