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