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