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