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