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