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