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[11]; 477 char link_state[DLADM_STRSIZE]; 478 char link_over[MAXLINKNAMELEN]; 479 char link_phys_state[DLADM_STRSIZE]; 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, "VLAN over '%s' may require lowered " 1459 "MTU; must use -f (see dladm(1M))\n", link); 1460 } else { 1461 die_dlerr(status, "create operation failed"); 1462 } 1463 } 1464 } 1465 1466 static void 1467 do_delete_vlan(int argc, char *argv[]) 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 char tmpbuf[MAXLINKNAMELEN]; 1681 1682 if (!state->ls_parseable) 1683 (void) sprintf(lbuf->link_over, STR_UNDEF_VAL); 1684 else 1685 (void) sprintf(lbuf->link_over, ""); 1686 1687 if (class == DATALINK_CLASS_VLAN) { 1688 dladm_vlan_attr_t vinfo; 1689 1690 status = dladm_vlan_info(linkid, &vinfo, flags); 1691 if (status != DLADM_STATUS_OK) 1692 goto done; 1693 status = dladm_datalink_id2info(vinfo.dv_linkid, NULL, NULL, 1694 NULL, lbuf->link_over, sizeof (lbuf->link_over)); 1695 if (status != DLADM_STATUS_OK) 1696 goto done; 1697 } else if (class == DATALINK_CLASS_AGGR) { 1698 dladm_aggr_grp_attr_t ginfo; 1699 int i; 1700 1701 (void) sprintf(lbuf->link_over, ""); 1702 1703 status = dladm_aggr_info(linkid, &ginfo, flags); 1704 if (status != DLADM_STATUS_OK) 1705 goto done; 1706 1707 if (ginfo.lg_nports == 0) { 1708 status = DLADM_STATUS_BADVAL; 1709 goto done; 1710 } 1711 for (i = 0; i < ginfo.lg_nports; i++) { 1712 status = dladm_datalink_id2info( 1713 ginfo.lg_ports[i].lp_linkid, NULL, NULL, NULL, 1714 tmpbuf, sizeof (tmpbuf)); 1715 if (status != DLADM_STATUS_OK) { 1716 free(ginfo.lg_ports); 1717 goto done; 1718 } 1719 (void) strlcat(lbuf->link_over, tmpbuf, 1720 sizeof (lbuf->link_over)); 1721 if (i != (ginfo.lg_nports - 1)) { 1722 (void) strlcat(lbuf->link_over, " ", 1723 sizeof (lbuf->link_over)); 1724 } 1725 } 1726 free(ginfo.lg_ports); 1727 } else if (class == DATALINK_CLASS_VNIC) { 1728 dladm_vnic_attr_sys_t vinfo; 1729 1730 if ((status = dladm_vnic_info(linkid, &vinfo, flags)) != 1731 DLADM_STATUS_OK || (status = dladm_datalink_id2info( 1732 vinfo.va_link_id, NULL, NULL, NULL, lbuf->link_over, 1733 sizeof (lbuf->link_over)) != DLADM_STATUS_OK)) { 1734 goto done; 1735 } 1736 } 1737 done: 1738 return (status); 1739 } 1740 1741 static dladm_status_t 1742 print_link(show_state_t *state, datalink_id_t linkid, link_fields_buf_t *lbuf) 1743 { 1744 char link[MAXLINKNAMELEN]; 1745 datalink_class_t class; 1746 uint_t mtu; 1747 uint32_t flags; 1748 dladm_status_t status; 1749 1750 if ((status = dladm_datalink_id2info(linkid, &flags, &class, NULL, 1751 link, sizeof (link))) != DLADM_STATUS_OK) { 1752 goto done; 1753 } 1754 1755 if (!(state->ls_flags & flags)) { 1756 status = DLADM_STATUS_NOTFOUND; 1757 goto done; 1758 } 1759 1760 if (state->ls_flags == DLADM_OPT_ACTIVE) { 1761 dladm_attr_t dlattr; 1762 1763 if (class == DATALINK_CLASS_PHYS) { 1764 dladm_phys_attr_t dpa; 1765 dlpi_handle_t dh; 1766 dlpi_info_t dlinfo; 1767 1768 if ((status = dladm_phys_info(linkid, &dpa, 1769 DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) { 1770 goto done; 1771 } 1772 1773 if (!dpa.dp_novanity) 1774 goto link_mtu; 1775 1776 /* 1777 * This is a physical link that does not have 1778 * vanity naming support. 1779 */ 1780 if (dlpi_open(dpa.dp_dev, &dh, DLPI_DEVONLY) != 1781 DLPI_SUCCESS) { 1782 status = DLADM_STATUS_NOTFOUND; 1783 goto done; 1784 } 1785 1786 if (dlpi_info(dh, &dlinfo, 0) != DLPI_SUCCESS) { 1787 dlpi_close(dh); 1788 status = DLADM_STATUS_BADARG; 1789 goto done; 1790 } 1791 1792 dlpi_close(dh); 1793 mtu = dlinfo.di_max_sdu; 1794 } else { 1795 link_mtu: 1796 status = dladm_info(linkid, &dlattr); 1797 if (status != DLADM_STATUS_OK) 1798 goto done; 1799 mtu = dlattr.da_max_sdu; 1800 } 1801 } 1802 1803 (void) snprintf(lbuf->link_name, sizeof (lbuf->link_name), 1804 "%s", link); 1805 (void) dladm_class2str(class, lbuf->link_class); 1806 if (state->ls_flags == DLADM_OPT_ACTIVE) { 1807 (void) snprintf(lbuf->link_mtu, sizeof (lbuf->link_mtu), 1808 "%u", mtu); 1809 (void) get_linkstate(link, B_TRUE, lbuf->link_state); 1810 } 1811 1812 status = print_link_topology(state, linkid, class, lbuf); 1813 if (status != DLADM_STATUS_OK) 1814 goto done; 1815 1816 done: 1817 return (status); 1818 } 1819 1820 1821 static int 1822 show_link(datalink_id_t linkid, void *arg) 1823 { 1824 show_state_t *state = (show_state_t *)arg; 1825 dladm_status_t status; 1826 link_fields_buf_t lbuf; 1827 1828 /* 1829 * first get all the link attributes into lbuf; 1830 */ 1831 status = print_link(state, linkid, &lbuf); 1832 1833 if (status != DLADM_STATUS_OK) 1834 goto done; 1835 1836 if (!state->ls_parseable && !state->ls_printheader) { 1837 print_header(&state->ls_print); 1838 state->ls_printheader = B_TRUE; 1839 } 1840 1841 dladm_print_output(&state->ls_print, state->ls_parseable, 1842 dladm_print_field, (void *)&lbuf); 1843 1844 done: 1845 state->ls_status = status; 1846 return (DLADM_WALK_CONTINUE); 1847 } 1848 1849 static int 1850 show_link_stats(datalink_id_t linkid, void *arg) 1851 { 1852 char link[DLPI_LINKNAME_MAX]; 1853 datalink_class_t class; 1854 show_state_t *state = (show_state_t *)arg; 1855 pktsum_t stats, diff_stats; 1856 dladm_phys_attr_t dpa; 1857 1858 if (state->ls_firstonly) { 1859 if (state->ls_donefirst) 1860 return (DLADM_WALK_CONTINUE); 1861 state->ls_donefirst = B_TRUE; 1862 } else { 1863 bzero(&state->ls_prevstats, sizeof (state->ls_prevstats)); 1864 } 1865 1866 if (dladm_datalink_id2info(linkid, NULL, &class, NULL, link, 1867 DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) { 1868 return (DLADM_WALK_CONTINUE); 1869 } 1870 1871 if (class == DATALINK_CLASS_PHYS) { 1872 if (dladm_phys_info(linkid, &dpa, DLADM_OPT_ACTIVE) != 1873 DLADM_STATUS_OK) { 1874 return (DLADM_WALK_CONTINUE); 1875 } 1876 if (dpa.dp_novanity) 1877 get_mac_stats(dpa.dp_dev, &stats); 1878 else 1879 get_link_stats(link, &stats); 1880 } else { 1881 get_link_stats(link, &stats); 1882 } 1883 stats_diff(&diff_stats, &stats, &state->ls_prevstats); 1884 1885 (void) printf("%-12s", link); 1886 (void) printf("%-10llu", diff_stats.ipackets); 1887 (void) printf("%-12llu", diff_stats.rbytes); 1888 (void) printf("%-8u", diff_stats.ierrors); 1889 (void) printf("%-10llu", diff_stats.opackets); 1890 (void) printf("%-12llu", diff_stats.obytes); 1891 (void) printf("%-8u\n", diff_stats.oerrors); 1892 1893 state->ls_prevstats = stats; 1894 return (DLADM_WALK_CONTINUE); 1895 } 1896 1897 1898 static dladm_status_t 1899 print_aggr_info(show_grp_state_t *state, const char *link, 1900 dladm_aggr_grp_attr_t *ginfop) 1901 { 1902 char addr_str[ETHERADDRL * 3]; 1903 laggr_fields_buf_t lbuf; 1904 1905 (void) snprintf(lbuf.laggr_name, sizeof (lbuf.laggr_name), 1906 "%s", link); 1907 1908 (void) dladm_aggr_policy2str(ginfop->lg_policy, 1909 lbuf.laggr_policy); 1910 1911 if (ginfop->lg_mac_fixed) { 1912 (void) dladm_aggr_macaddr2str(ginfop->lg_mac, addr_str); 1913 (void) snprintf(lbuf.laggr_addrpolicy, 1914 sizeof (lbuf.laggr_addrpolicy), "fixed (%s)", addr_str); 1915 } else { 1916 (void) snprintf(lbuf.laggr_addrpolicy, 1917 sizeof (lbuf.laggr_addrpolicy), "auto"); 1918 } 1919 1920 1921 (void) dladm_aggr_lacpmode2str(ginfop->lg_lacp_mode, 1922 lbuf.laggr_lacpactivity); 1923 (void) dladm_aggr_lacptimer2str(ginfop->lg_lacp_timer, 1924 lbuf.laggr_lacptimer); 1925 (void) snprintf(lbuf.laggr_flags, sizeof (lbuf.laggr_flags), "%c----", 1926 ginfop->lg_force ? 'f' : '-'); 1927 1928 if (!state->gs_parseable && !state->gs_printheader) { 1929 print_header(&state->gs_print); 1930 state->gs_printheader = B_TRUE; 1931 } 1932 1933 dladm_print_output(&state->gs_print, state->gs_parseable, 1934 dladm_print_field, (void *)&lbuf); 1935 1936 return (DLADM_STATUS_OK); 1937 } 1938 1939 static char * 1940 print_xaggr_callback(print_field_t *pf, void *arg) 1941 { 1942 const laggr_args_t *l = arg; 1943 int portnum; 1944 static char buf[DLADM_STRSIZE]; 1945 boolean_t is_port = (l->laggr_lport >= 0); 1946 dladm_aggr_port_attr_t *portp; 1947 dladm_phys_attr_t dpa; 1948 dladm_status_t *stat, status; 1949 1950 stat = l->laggr_status; 1951 *stat = DLADM_STATUS_OK; 1952 1953 if (is_port) { 1954 portnum = l->laggr_lport; 1955 portp = &(l->laggr_ginfop->lg_ports[portnum]); 1956 if ((status = dladm_datalink_id2info(portp->lp_linkid, 1957 NULL, NULL, NULL, buf, sizeof (buf))) != 1958 DLADM_STATUS_OK) { 1959 goto err; 1960 } 1961 if ((status = dladm_phys_info(portp->lp_linkid, &dpa, 1962 DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) { 1963 goto err; 1964 } 1965 } 1966 1967 switch (pf->pf_index) { 1968 case AGGR_X_LINK: 1969 (void) snprintf(buf, sizeof (buf), "%s", 1970 (is_port && !l->laggr_parseable ? " " : l->laggr_link)); 1971 break; 1972 case AGGR_X_PORT: 1973 if (is_port) 1974 break; 1975 return (""); 1976 break; 1977 1978 case AGGR_X_SPEED: 1979 if (is_port) { 1980 (void) snprintf(buf, sizeof (buf), "%uMb", 1981 (uint_t)((get_ifspeed(dpa.dp_dev, 1982 B_FALSE)) / 1000000ull)); 1983 } else { 1984 (void) snprintf(buf, sizeof (buf), "%uMb", 1985 (uint_t)((get_ifspeed(l->laggr_link, 1986 B_TRUE)) / 1000000ull)); 1987 } 1988 break; 1989 1990 case AGGR_X_DUPLEX: 1991 if (is_port) 1992 (void) get_linkduplex(dpa.dp_dev, B_FALSE, buf); 1993 else 1994 (void) get_linkduplex(l->laggr_link, B_TRUE, buf); 1995 break; 1996 1997 case AGGR_X_STATE: 1998 if (is_port) { 1999 (void) dladm_aggr_portstate2str( 2000 portp->lp_state, buf); 2001 } else { 2002 return (STR_UNDEF_VAL); 2003 } 2004 break; 2005 case AGGR_X_ADDRESS: 2006 (void) dladm_aggr_macaddr2str( 2007 (is_port ? portp->lp_mac : l->laggr_ginfop->lg_mac), 2008 buf); 2009 break; 2010 2011 case AGGR_X_PORTSTATE: 2012 (void) snprintf(buf, sizeof (buf), "%s", 2013 (is_port ? dladm_aggr_portstate2str(portp->lp_state, buf): 2014 (l->laggr_parseable ? "" : STR_UNDEF_VAL))); 2015 break; 2016 } 2017 return (buf); 2018 2019 err: 2020 *stat = status; 2021 buf[0] = '\0'; 2022 return (buf); 2023 } 2024 2025 static dladm_status_t 2026 print_aggr_extended(show_grp_state_t *state, const char *link, 2027 dladm_aggr_grp_attr_t *ginfop) 2028 { 2029 int i; 2030 dladm_status_t status; 2031 laggr_args_t largs; 2032 2033 if (!state->gs_parseable && !state->gs_printheader) { 2034 print_header(&state->gs_print); 2035 state->gs_printheader = B_TRUE; 2036 } 2037 2038 largs.laggr_lport = -1; 2039 largs.laggr_link = link; 2040 largs.laggr_ginfop = ginfop; 2041 largs.laggr_status = &status; 2042 largs.laggr_parseable = state->gs_parseable; 2043 2044 dladm_print_output(&state->gs_print, state->gs_parseable, 2045 print_xaggr_callback, &largs); 2046 2047 if (status != DLADM_STATUS_OK) 2048 goto done; 2049 2050 for (i = 0; i < ginfop->lg_nports; i++) { 2051 largs.laggr_lport = i; 2052 dladm_print_output(&state->gs_print, state->gs_parseable, 2053 print_xaggr_callback, &largs); 2054 if (status != DLADM_STATUS_OK) 2055 goto done; 2056 } 2057 2058 status = DLADM_STATUS_OK; 2059 done: 2060 return (status); 2061 } 2062 2063 2064 static char * 2065 print_lacp_callback(print_field_t *pf, void *arg) 2066 { 2067 const laggr_args_t *l = arg; 2068 int portnum; 2069 static char buf[DLADM_STRSIZE]; 2070 boolean_t is_port = (l->laggr_lport >= 0); 2071 dladm_aggr_port_attr_t *portp; 2072 dladm_status_t *stat, status; 2073 aggr_lacp_state_t *lstate; 2074 2075 if (!is_port) { 2076 return (NULL); /* cannot happen! */ 2077 } 2078 2079 stat = l->laggr_status; 2080 2081 portnum = l->laggr_lport; 2082 portp = &(l->laggr_ginfop->lg_ports[portnum]); 2083 if ((status = dladm_datalink_id2info(portp->lp_linkid, 2084 NULL, NULL, NULL, buf, sizeof (buf))) != DLADM_STATUS_OK) { 2085 goto err; 2086 } 2087 lstate = &(portp->lp_lacp_state); 2088 2089 switch (pf->pf_index) { 2090 case AGGR_L_LINK: 2091 (void) snprintf(buf, sizeof (buf), "%s", 2092 (portnum > 0 ? "" : l->laggr_link)); 2093 break; 2094 2095 case AGGR_L_PORT: 2096 break; 2097 2098 case AGGR_L_AGGREGATABLE: 2099 (void) snprintf(buf, sizeof (buf), "%s", 2100 (lstate->bit.aggregation ? "yes" : "no")); 2101 break; 2102 2103 case AGGR_L_SYNC: 2104 (void) snprintf(buf, sizeof (buf), "%s", 2105 (lstate->bit.sync ? "yes" : "no")); 2106 break; 2107 2108 case AGGR_L_COLL: 2109 (void) snprintf(buf, sizeof (buf), "%s", 2110 (lstate->bit.collecting ? "yes" : "no")); 2111 break; 2112 2113 case AGGR_L_DIST: 2114 (void) snprintf(buf, sizeof (buf), "%s", 2115 (lstate->bit.distributing ? "yes" : "no")); 2116 break; 2117 2118 case AGGR_L_DEFAULTED: 2119 (void) snprintf(buf, sizeof (buf), "%s", 2120 (lstate->bit.defaulted ? "yes" : "no")); 2121 break; 2122 2123 case AGGR_L_EXPIRED: 2124 (void) snprintf(buf, sizeof (buf), "%s", 2125 (lstate->bit.expired ? "yes" : "no")); 2126 break; 2127 } 2128 2129 *stat = DLADM_STATUS_OK; 2130 return (buf); 2131 2132 err: 2133 *stat = status; 2134 buf[0] = '\0'; 2135 return (buf); 2136 } 2137 2138 static dladm_status_t 2139 print_aggr_lacp(show_grp_state_t *state, const char *link, 2140 dladm_aggr_grp_attr_t *ginfop) 2141 { 2142 int i; 2143 dladm_status_t status; 2144 laggr_args_t largs; 2145 2146 if (!state->gs_parseable && !state->gs_printheader) { 2147 print_header(&state->gs_print); 2148 state->gs_printheader = B_TRUE; 2149 } 2150 2151 largs.laggr_link = link; 2152 largs.laggr_ginfop = ginfop; 2153 largs.laggr_status = &status; 2154 2155 for (i = 0; i < ginfop->lg_nports; i++) { 2156 largs.laggr_lport = i; 2157 dladm_print_output(&state->gs_print, state->gs_parseable, 2158 print_lacp_callback, &largs); 2159 if (status != DLADM_STATUS_OK) 2160 goto done; 2161 } 2162 2163 status = DLADM_STATUS_OK; 2164 done: 2165 return (status); 2166 } 2167 2168 static char * 2169 print_aggr_stats_callback(print_field_t *pf, void *arg) 2170 { 2171 const laggr_args_t *l = arg; 2172 int portnum; 2173 static char buf[DLADM_STRSIZE]; 2174 boolean_t is_port = (l->laggr_lport >= 0); 2175 dladm_aggr_port_attr_t *portp; 2176 dladm_phys_attr_t dpa; 2177 dladm_status_t *stat, status; 2178 pktsum_t port_stat, diff_stats; 2179 2180 stat = l->laggr_status; 2181 *stat = DLADM_STATUS_OK; 2182 2183 if (is_port) { 2184 portnum = l->laggr_lport; 2185 portp = &(l->laggr_ginfop->lg_ports[portnum]); 2186 if ((status = dladm_phys_info(portp->lp_linkid, &dpa, 2187 DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) { 2188 goto err; 2189 } 2190 2191 get_mac_stats(dpa.dp_dev, &port_stat); 2192 2193 if ((status = dladm_datalink_id2info(portp->lp_linkid, NULL, 2194 NULL, NULL, buf, sizeof (buf))) != DLADM_STATUS_OK) { 2195 goto err; 2196 } 2197 2198 stats_diff(&diff_stats, &port_stat, l->laggr_prevstats); 2199 } 2200 2201 switch (pf->pf_index) { 2202 case AGGR_S_LINK: 2203 (void) snprintf(buf, sizeof (buf), "%s", 2204 (is_port ? "" : l->laggr_link)); 2205 break; 2206 case AGGR_S_PORT: 2207 if (is_port) 2208 break; 2209 return (STR_UNDEF_VAL); 2210 break; 2211 2212 case AGGR_S_IPKTS: 2213 if (is_port) { 2214 (void) snprintf(buf, sizeof (buf), "%llu", 2215 diff_stats.ipackets); 2216 } else { 2217 (void) snprintf(buf, sizeof (buf), "%llu", 2218 l->laggr_pktsumtot->ipackets); 2219 } 2220 break; 2221 2222 case AGGR_S_RBYTES: 2223 if (is_port) { 2224 (void) snprintf(buf, sizeof (buf), "%llu", 2225 diff_stats.rbytes); 2226 } else { 2227 (void) snprintf(buf, sizeof (buf), "%llu", 2228 l->laggr_pktsumtot->rbytes); 2229 } 2230 break; 2231 2232 case AGGR_S_OPKTS: 2233 if (is_port) { 2234 (void) snprintf(buf, sizeof (buf), "%llu", 2235 diff_stats.opackets); 2236 } else { 2237 (void) snprintf(buf, sizeof (buf), "%llu", 2238 l->laggr_pktsumtot->opackets); 2239 } 2240 break; 2241 case AGGR_S_OBYTES: 2242 if (is_port) { 2243 (void) snprintf(buf, sizeof (buf), "%llu", 2244 diff_stats.obytes); 2245 } else { 2246 (void) snprintf(buf, sizeof (buf), "%llu", 2247 l->laggr_pktsumtot->obytes); 2248 2249 } 2250 break; 2251 2252 case AGGR_S_IPKTDIST: 2253 if (is_port) { 2254 (void) snprintf(buf, sizeof (buf), "%-6.1f", 2255 (double)diff_stats.opackets/ 2256 (double)l->laggr_pktsumtot->ipackets * 100); 2257 } else { 2258 return (STR_UNDEF_VAL); 2259 } 2260 break; 2261 case AGGR_S_OPKTDIST: 2262 if (is_port) { 2263 (void) snprintf(buf, sizeof (buf), "%-6.1f", 2264 (double)diff_stats.opackets/ 2265 (double)l->laggr_pktsumtot->opackets * 100); 2266 } else { 2267 (void) sprintf(buf, STR_UNDEF_VAL); 2268 } 2269 break; 2270 } 2271 return (buf); 2272 2273 err: 2274 *stat = status; 2275 buf[0] = '\0'; 2276 return (buf); 2277 } 2278 2279 static dladm_status_t 2280 print_aggr_stats(show_grp_state_t *state, const char *link, 2281 dladm_aggr_grp_attr_t *ginfop) 2282 { 2283 dladm_phys_attr_t dpa; 2284 dladm_aggr_port_attr_t *portp; 2285 pktsum_t pktsumtot, port_stat; 2286 dladm_status_t status; 2287 int i; 2288 laggr_args_t largs; 2289 2290 /* sum the ports statistics */ 2291 bzero(&pktsumtot, sizeof (pktsumtot)); 2292 2293 for (i = 0; i < ginfop->lg_nports; i++) { 2294 2295 portp = &(ginfop->lg_ports[i]); 2296 if ((status = dladm_phys_info(portp->lp_linkid, &dpa, 2297 DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) { 2298 goto done; 2299 } 2300 2301 get_mac_stats(dpa.dp_dev, &port_stat); 2302 stats_total(&pktsumtot, &port_stat, &state->gs_prevstats[i]); 2303 } 2304 2305 if (!state->gs_parseable && !state->gs_printheader) { 2306 print_header(&state->gs_print); 2307 state->gs_printheader = B_TRUE; 2308 } 2309 2310 largs.laggr_lport = -1; 2311 largs.laggr_link = link; 2312 largs.laggr_ginfop = ginfop; 2313 largs.laggr_status = &status; 2314 largs.laggr_pktsumtot = &pktsumtot; 2315 2316 dladm_print_output(&state->gs_print, state->gs_parseable, 2317 print_aggr_stats_callback, &largs); 2318 2319 if (status != DLADM_STATUS_OK) 2320 goto done; 2321 2322 for (i = 0; i < ginfop->lg_nports; i++) { 2323 largs.laggr_lport = i; 2324 largs.laggr_prevstats = &state->gs_prevstats[i]; 2325 dladm_print_output(&state->gs_print, state->gs_parseable, 2326 print_aggr_stats_callback, &largs); 2327 if (status != DLADM_STATUS_OK) 2328 goto done; 2329 } 2330 2331 status = DLADM_STATUS_OK; 2332 done: 2333 return (status); 2334 } 2335 2336 static dladm_status_t 2337 print_aggr(show_grp_state_t *state, datalink_id_t linkid) 2338 { 2339 char link[MAXLINKNAMELEN]; 2340 dladm_aggr_grp_attr_t ginfo; 2341 uint32_t flags; 2342 dladm_status_t status; 2343 2344 if ((status = dladm_datalink_id2info(linkid, &flags, NULL, NULL, link, 2345 MAXLINKNAMELEN)) != DLADM_STATUS_OK) { 2346 return (status); 2347 } 2348 2349 if (!(state->gs_flags & flags)) 2350 return (DLADM_STATUS_NOTFOUND); 2351 2352 status = dladm_aggr_info(linkid, &ginfo, state->gs_flags); 2353 if (status != DLADM_STATUS_OK) 2354 return (status); 2355 2356 if (state->gs_lacp) 2357 status = print_aggr_lacp(state, link, &ginfo); 2358 else if (state->gs_extended) 2359 status = print_aggr_extended(state, link, &ginfo); 2360 else if (state->gs_stats) 2361 status = print_aggr_stats(state, link, &ginfo); 2362 else { 2363 status = print_aggr_info(state, link, &ginfo); 2364 } 2365 2366 done: 2367 free(ginfo.lg_ports); 2368 return (status); 2369 } 2370 2371 static int 2372 show_aggr(datalink_id_t linkid, void *arg) 2373 { 2374 show_grp_state_t *state = arg; 2375 dladm_status_t status; 2376 2377 status = print_aggr(state, linkid); 2378 if (status != DLADM_STATUS_OK) 2379 goto done; 2380 2381 done: 2382 state->gs_status = status; 2383 return (DLADM_WALK_CONTINUE); 2384 } 2385 2386 static char * 2387 print_dev(print_field_t *pf, void *arg) 2388 { 2389 const char *dev = arg; 2390 static char buf[DLADM_STRSIZE]; 2391 2392 switch (pf->pf_index) { 2393 case DEV_LINK: 2394 (void) snprintf(buf, sizeof (buf), "%s", dev); 2395 break; 2396 case DEV_STATE: 2397 (void) get_linkstate(dev, B_FALSE, buf); 2398 break; 2399 case DEV_SPEED: 2400 (void) snprintf(buf, sizeof (buf), "%uMb", 2401 (unsigned int)(get_ifspeed(dev, B_FALSE) / 1000000ull)); 2402 break; 2403 case DEV_DUPLEX: 2404 (void) get_linkduplex(dev, B_FALSE, buf); 2405 break; 2406 default: 2407 die("invalid index '%d'", pf->pf_index); 2408 break; 2409 } 2410 return (buf); 2411 } 2412 2413 static int 2414 show_dev(const char *dev, void *arg) 2415 { 2416 show_state_t *state = arg; 2417 2418 if (!state->ls_parseable && !state->ls_printheader) { 2419 print_header(&state->ls_print); 2420 state->ls_printheader = B_TRUE; 2421 } 2422 2423 dladm_print_output(&state->ls_print, state->ls_parseable, 2424 print_dev, (void *)dev); 2425 2426 return (DLADM_WALK_CONTINUE); 2427 } 2428 2429 static char * 2430 print_dev_stats(print_field_t *pf, void *arg) 2431 { 2432 dev_args_t *dargs = arg; 2433 pktsum_t *diff_stats = dargs->devs_psum; 2434 static char buf[DLADM_STRSIZE]; 2435 2436 switch (pf->pf_index) { 2437 case DEVS_LINK: 2438 (void) snprintf(buf, sizeof (buf), "%s", dargs->devs_link); 2439 break; 2440 case DEVS_IPKTS: 2441 (void) snprintf(buf, sizeof (buf), "%llu", 2442 diff_stats->ipackets); 2443 break; 2444 case DEVS_RBYTES: 2445 (void) snprintf(buf, sizeof (buf), "%llu", 2446 diff_stats->rbytes); 2447 break; 2448 case DEVS_IERRORS: 2449 (void) snprintf(buf, sizeof (buf), "%u", 2450 diff_stats->ierrors); 2451 break; 2452 case DEVS_OPKTS: 2453 (void) snprintf(buf, sizeof (buf), "%llu", 2454 diff_stats->opackets); 2455 break; 2456 case DEVS_OBYTES: 2457 (void) snprintf(buf, sizeof (buf), "%llu", 2458 diff_stats->obytes); 2459 break; 2460 case DEVS_OERRORS: 2461 (void) snprintf(buf, sizeof (buf), "%u", 2462 diff_stats->oerrors); 2463 break; 2464 default: 2465 die("invalid input"); 2466 break; 2467 } 2468 return (buf); 2469 } 2470 2471 static int 2472 show_dev_stats(const char *dev, void *arg) 2473 { 2474 show_state_t *state = arg; 2475 pktsum_t stats, diff_stats; 2476 dev_args_t dargs; 2477 2478 if (state->ls_firstonly) { 2479 if (state->ls_donefirst) 2480 return (DLADM_WALK_CONTINUE); 2481 state->ls_donefirst = B_TRUE; 2482 } else { 2483 bzero(&state->ls_prevstats, sizeof (state->ls_prevstats)); 2484 } 2485 2486 get_mac_stats(dev, &stats); 2487 stats_diff(&diff_stats, &stats, &state->ls_prevstats); 2488 2489 dargs.devs_link = (char *)dev; 2490 dargs.devs_psum = &diff_stats; 2491 dladm_print_output(&state->ls_print, state->ls_parseable, 2492 print_dev_stats, &dargs); 2493 2494 state->ls_prevstats = stats; 2495 return (DLADM_WALK_CONTINUE); 2496 } 2497 2498 static void 2499 do_show_link(int argc, char *argv[]) 2500 { 2501 int option; 2502 boolean_t s_arg = B_FALSE; 2503 boolean_t i_arg = B_FALSE; 2504 uint32_t flags = DLADM_OPT_ACTIVE; 2505 boolean_t p_arg = B_FALSE; 2506 datalink_id_t linkid = DATALINK_ALL_LINKID; 2507 int interval = 0; 2508 show_state_t state; 2509 dladm_status_t status; 2510 boolean_t o_arg = B_FALSE; 2511 char *fields_str = NULL; 2512 print_field_t **fields; 2513 uint_t nfields; 2514 char *all_active_fields = "link,class,mtu,state,over"; 2515 char *all_inactive_fields = "link,class,over"; 2516 2517 bzero(&state, sizeof (state)); 2518 2519 opterr = 0; 2520 while ((option = getopt_long(argc, argv, ":pPsi:o:", 2521 show_lopts, NULL)) != -1) { 2522 switch (option) { 2523 case 'p': 2524 if (p_arg) 2525 die_optdup(option); 2526 2527 p_arg = B_TRUE; 2528 break; 2529 case 's': 2530 if (s_arg) 2531 die_optdup(option); 2532 2533 s_arg = B_TRUE; 2534 break; 2535 case 'P': 2536 if (flags != DLADM_OPT_ACTIVE) 2537 die_optdup(option); 2538 2539 flags = DLADM_OPT_PERSIST; 2540 break; 2541 case 'o': 2542 o_arg = B_TRUE; 2543 fields_str = optarg; 2544 break; 2545 case 'i': 2546 if (i_arg) 2547 die_optdup(option); 2548 2549 i_arg = B_TRUE; 2550 if (!str2int(optarg, &interval) || interval == 0) 2551 die("invalid interval value '%s'", optarg); 2552 break; 2553 default: 2554 die_opterr(optopt, option); 2555 break; 2556 } 2557 } 2558 2559 if (i_arg && !s_arg) 2560 die("the option -i can be used only with -s"); 2561 2562 if (s_arg && (p_arg || flags != DLADM_OPT_ACTIVE)) 2563 die("the option -%c cannot be used with -s", p_arg ? 'p' : 'P'); 2564 2565 /* get link name (optional last argument) */ 2566 if (optind == (argc-1)) { 2567 uint32_t f; 2568 2569 if ((status = dladm_name2info(argv[optind], &linkid, &f, 2570 NULL, NULL)) != DLADM_STATUS_OK) { 2571 die_dlerr(status, "link %s is not valid", argv[optind]); 2572 } 2573 2574 if (!(f & flags)) { 2575 die_dlerr(DLADM_STATUS_BADARG, "link %s is %s", 2576 argv[optind], flags == DLADM_OPT_PERSIST ? 2577 "a temporary link" : "temporarily removed"); 2578 } 2579 } else if (optind != argc) { 2580 usage(); 2581 } 2582 2583 if (s_arg) { 2584 link_stats(linkid, interval); 2585 return; 2586 } 2587 2588 state.ls_parseable = p_arg; 2589 state.ls_flags = flags; 2590 state.ls_donefirst = B_FALSE; 2591 2592 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) { 2593 if (state.ls_flags & DLADM_OPT_ACTIVE) 2594 fields_str = all_active_fields; 2595 else 2596 fields_str = all_inactive_fields; 2597 } 2598 2599 2600 fields = parse_output_fields(fields_str, link_fields, DEV_LINK_FIELDS, 2601 CMD_TYPE_ANY, &nfields); 2602 2603 if (fields == NULL) { 2604 die("invalid field(s) specified"); 2605 return; 2606 } 2607 2608 state.ls_print.ps_fields = fields; 2609 state.ls_print.ps_nfields = nfields; 2610 2611 if (linkid == DATALINK_ALL_LINKID) { 2612 (void) dladm_walk_datalink_id(show_link, &state, 2613 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, flags); 2614 } else { 2615 (void) show_link(linkid, &state); 2616 if (state.ls_status != DLADM_STATUS_OK) { 2617 die_dlerr(state.ls_status, "failed to show link %s", 2618 argv[optind]); 2619 } 2620 } 2621 } 2622 2623 static void 2624 do_show_aggr(int argc, char *argv[]) 2625 { 2626 boolean_t L_arg = B_FALSE; 2627 boolean_t s_arg = B_FALSE; 2628 boolean_t i_arg = B_FALSE; 2629 boolean_t p_arg = B_FALSE; 2630 boolean_t x_arg = B_FALSE; 2631 show_grp_state_t state; 2632 uint32_t flags = DLADM_OPT_ACTIVE; 2633 datalink_id_t linkid = DATALINK_ALL_LINKID; 2634 int option; 2635 int interval = 0; 2636 int key; 2637 dladm_status_t status; 2638 boolean_t o_arg = B_FALSE; 2639 char *fields_str = NULL; 2640 print_field_t **fields; 2641 uint_t nfields; 2642 char *all_fields = 2643 "link,policy,addrpolicy,lacpactivity,lacptimer,flags"; 2644 char *all_lacp_fields = 2645 "link,port,aggregatable,sync,coll,dist,defaulted,expired"; 2646 char *all_stats_fields = 2647 "link,port,ipackets,rbytes,opackets,obytes,ipktdist,opktdist"; 2648 char *all_extended_fields = 2649 "link,port,speed,duplex,state,address,portstate"; 2650 print_field_t *pf; 2651 int pfmax; 2652 2653 bzero(&state, sizeof (state)); 2654 2655 opterr = 0; 2656 while ((option = getopt_long(argc, argv, ":LpPxsi:o:", 2657 show_lopts, NULL)) != -1) { 2658 switch (option) { 2659 case 'L': 2660 if (L_arg) 2661 die_optdup(option); 2662 2663 L_arg = B_TRUE; 2664 break; 2665 case 'p': 2666 if (p_arg) 2667 die_optdup(option); 2668 2669 p_arg = B_TRUE; 2670 break; 2671 case 'x': 2672 if (x_arg) 2673 die_optdup(option); 2674 2675 x_arg = B_TRUE; 2676 break; 2677 case 'P': 2678 if (flags != DLADM_OPT_ACTIVE) 2679 die_optdup(option); 2680 2681 flags = DLADM_OPT_PERSIST; 2682 break; 2683 case 's': 2684 if (s_arg) 2685 die_optdup(option); 2686 2687 s_arg = B_TRUE; 2688 break; 2689 case 'o': 2690 o_arg = B_TRUE; 2691 fields_str = optarg; 2692 break; 2693 case 'i': 2694 if (i_arg) 2695 die_optdup(option); 2696 2697 i_arg = B_TRUE; 2698 if (!str2int(optarg, &interval) || interval == 0) 2699 die("invalid interval value '%s'", optarg); 2700 break; 2701 default: 2702 die_opterr(optopt, option); 2703 break; 2704 } 2705 } 2706 2707 if (i_arg && !s_arg) 2708 die("the option -i can be used only with -s"); 2709 2710 if (s_arg && (L_arg || p_arg || x_arg || flags != DLADM_OPT_ACTIVE)) { 2711 die("the option -%c cannot be used with -s", 2712 L_arg ? 'L' : (p_arg ? 'p' : (x_arg ? 'x' : 'P'))); 2713 } 2714 2715 if (L_arg && flags != DLADM_OPT_ACTIVE) 2716 die("the option -P cannot be used with -L"); 2717 2718 if (x_arg && (L_arg || flags != DLADM_OPT_ACTIVE)) 2719 die("the option -%c cannot be used with -x", L_arg ? 'L' : 'P'); 2720 2721 /* get aggregation key or aggrname (optional last argument) */ 2722 if (optind == (argc-1)) { 2723 if (!str2int(argv[optind], &key)) { 2724 status = dladm_name2info(argv[optind], &linkid, NULL, 2725 NULL, NULL); 2726 } else { 2727 status = dladm_key2linkid((uint16_t)key, 2728 &linkid, DLADM_OPT_ACTIVE); 2729 } 2730 2731 if (status != DLADM_STATUS_OK) 2732 die("non-existent aggregation '%s'", argv[optind]); 2733 2734 } else if (optind != argc) { 2735 usage(); 2736 } 2737 2738 bzero(&state, sizeof (state)); 2739 state.gs_lacp = L_arg; 2740 state.gs_stats = s_arg; 2741 state.gs_flags = flags; 2742 state.gs_parseable = p_arg; 2743 state.gs_extended = x_arg; 2744 2745 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) { 2746 if (state.gs_lacp) 2747 fields_str = all_lacp_fields; 2748 else if (state.gs_stats) 2749 fields_str = all_stats_fields; 2750 else if (state.gs_extended) 2751 fields_str = all_extended_fields; 2752 else 2753 fields_str = all_fields; 2754 } 2755 2756 if (state.gs_lacp) { 2757 pf = aggr_l_fields; 2758 pfmax = AGGR_L_MAX_FIELDS; 2759 } else if (state.gs_stats) { 2760 pf = aggr_s_fields; 2761 pfmax = AGGR_S_MAX_FIELDS; 2762 } else if (state.gs_extended) { 2763 pf = aggr_x_fields; 2764 pfmax = AGGR_X_MAX_FIELDS; 2765 } else { 2766 pf = laggr_fields; 2767 pfmax = LAGGR_MAX_FIELDS; 2768 } 2769 fields = parse_output_fields(fields_str, pf, pfmax, CMD_TYPE_ANY, 2770 &nfields); 2771 2772 if (fields == NULL) { 2773 die("invalid field(s) specified"); 2774 return; 2775 } 2776 2777 state.gs_print.ps_fields = fields; 2778 state.gs_print.ps_nfields = nfields; 2779 2780 if (s_arg) { 2781 aggr_stats(linkid, &state, interval); 2782 return; 2783 } 2784 2785 if (linkid == DATALINK_ALL_LINKID) { 2786 (void) dladm_walk_datalink_id(show_aggr, &state, 2787 DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, flags); 2788 } else { 2789 (void) show_aggr(linkid, &state); 2790 if (state.gs_status != DLADM_STATUS_OK) { 2791 die_dlerr(state.gs_status, "failed to show aggr %s", 2792 argv[optind]); 2793 } 2794 } 2795 } 2796 2797 static void 2798 do_show_dev(int argc, char *argv[]) 2799 { 2800 int option; 2801 char *dev = NULL; 2802 boolean_t s_arg = B_FALSE; 2803 boolean_t i_arg = B_FALSE; 2804 boolean_t o_arg = B_FALSE; 2805 boolean_t p_arg = B_FALSE; 2806 datalink_id_t linkid; 2807 int interval = 0; 2808 show_state_t state; 2809 char *fields_str = NULL; 2810 print_field_t **fields; 2811 uint_t nfields; 2812 char *all_fields = "link,state,speed,duplex"; 2813 static char *allstat_fields = 2814 "link,ipackets,rbytes,ierrors,opackets,obytes,oerrors"; 2815 2816 bzero(&state, sizeof (state)); 2817 fields_str = all_fields; 2818 2819 opterr = 0; 2820 while ((option = getopt_long(argc, argv, ":psi:o:", 2821 show_lopts, NULL)) != -1) { 2822 switch (option) { 2823 case 'p': 2824 if (p_arg) 2825 die_optdup(option); 2826 2827 p_arg = B_TRUE; 2828 break; 2829 case 's': 2830 if (s_arg) 2831 die_optdup(option); 2832 2833 s_arg = B_TRUE; 2834 break; 2835 case 'o': 2836 o_arg = B_TRUE; 2837 fields_str = optarg; 2838 break; 2839 case 'i': 2840 if (i_arg) 2841 die_optdup(option); 2842 2843 i_arg = B_TRUE; 2844 if (!str2int(optarg, &interval) || interval == 0) 2845 die("invalid interval value '%s'", optarg); 2846 break; 2847 default: 2848 die_opterr(optopt, option); 2849 break; 2850 } 2851 } 2852 2853 if (i_arg && !s_arg) 2854 die("the option -i can be used only with -s"); 2855 2856 if (o_arg && strcasecmp(fields_str, "all") == 0) { 2857 if (!s_arg) 2858 fields_str = all_fields; 2859 else 2860 fields_str = allstat_fields; 2861 } 2862 2863 if (!o_arg && s_arg) 2864 fields_str = allstat_fields; 2865 2866 if (s_arg && p_arg) 2867 die("the option -s cannot be used with -p"); 2868 2869 /* get dev name (optional last argument) */ 2870 if (optind == (argc-1)) { 2871 uint32_t flags; 2872 2873 dev = argv[optind]; 2874 2875 if (dladm_dev2linkid(dev, &linkid) != DLADM_STATUS_OK) 2876 die("invalid device %s", dev); 2877 2878 if ((dladm_datalink_id2info(linkid, &flags, NULL, NULL, 2879 NULL, 0) != DLADM_STATUS_OK) || 2880 !(flags & DLADM_OPT_ACTIVE)) { 2881 die("device %s has been removed", dev); 2882 } 2883 } else if (optind != argc) { 2884 usage(); 2885 } 2886 2887 state.ls_parseable = p_arg; 2888 state.ls_donefirst = B_FALSE; 2889 2890 if (s_arg) { 2891 dev_stats(dev, interval, fields_str, &state); 2892 return; 2893 } 2894 2895 fields = parse_output_fields(fields_str, dev_fields, DEV_MAX_FIELDS, 2896 CMD_TYPE_ANY, &nfields); 2897 2898 if (fields == NULL) { 2899 die("invalid field(s) specified"); 2900 return; 2901 } 2902 2903 state.ls_print.ps_fields = fields; 2904 state.ls_print.ps_nfields = nfields; 2905 2906 if (dev == NULL) { 2907 (void) dladm_mac_walk(show_dev, &state); 2908 } else { 2909 (void) show_dev(dev, &state); 2910 } 2911 } 2912 2913 2914 static dladm_status_t 2915 print_phys(show_state_t *state, datalink_id_t linkid, link_fields_buf_t *pattr) 2916 { 2917 char link[MAXLINKNAMELEN]; 2918 dladm_phys_attr_t dpa; 2919 uint32_t flags; 2920 datalink_class_t class; 2921 uint32_t media; 2922 dladm_status_t status; 2923 2924 if ((status = dladm_datalink_id2info(linkid, &flags, &class, &media, 2925 link, MAXLINKNAMELEN)) != DLADM_STATUS_OK) { 2926 goto done; 2927 } 2928 2929 if (class != DATALINK_CLASS_PHYS) { 2930 status = DLADM_STATUS_BADARG; 2931 goto done; 2932 } 2933 2934 if (!(state->ls_flags & flags)) { 2935 status = DLADM_STATUS_NOTFOUND; 2936 goto done; 2937 } 2938 2939 status = dladm_phys_info(linkid, &dpa, state->ls_flags); 2940 if (status != DLADM_STATUS_OK) 2941 goto done; 2942 2943 (void) snprintf(pattr->link_phys_device, 2944 sizeof (pattr->link_phys_device), "%s", dpa.dp_dev); 2945 (void) dladm_media2str(media, pattr->link_phys_media); 2946 if (state->ls_flags == DLADM_OPT_ACTIVE) { 2947 boolean_t islink; 2948 2949 if (!dpa.dp_novanity) { 2950 (void) strlcpy(pattr->link_name, link, 2951 sizeof (pattr->link_name)); 2952 islink = B_TRUE; 2953 } else { 2954 /* 2955 * This is a physical link that does not have 2956 * vanity naming support. 2957 */ 2958 (void) strlcpy(pattr->link_name, dpa.dp_dev, 2959 sizeof (pattr->link_name)); 2960 islink = B_FALSE; 2961 } 2962 2963 (void) get_linkstate(pattr->link_name, islink, 2964 pattr->link_phys_state); 2965 (void) snprintf(pattr->link_phys_speed, 2966 sizeof (pattr->link_phys_speed), "%u", 2967 (uint_t)((get_ifspeed(pattr->link_name, 2968 islink)) / 1000000ull)); 2969 (void) get_linkduplex(pattr->link_name, islink, 2970 pattr->link_phys_duplex); 2971 } else { 2972 (void) snprintf(pattr->link_name, sizeof (pattr->link_name), 2973 "%s", link); 2974 (void) snprintf(pattr->link_flags, sizeof (pattr->link_flags), 2975 "%c----", flags & DLADM_OPT_ACTIVE ? '-' : 'r'); 2976 } 2977 2978 done: 2979 return (status); 2980 } 2981 2982 static int 2983 show_phys(datalink_id_t linkid, void *arg) 2984 { 2985 show_state_t *state = arg; 2986 dladm_status_t status; 2987 link_fields_buf_t pattr; 2988 2989 status = print_phys(state, linkid, &pattr); 2990 if (status != DLADM_STATUS_OK) 2991 goto done; 2992 2993 if (!state->ls_parseable && !state->ls_printheader) { 2994 print_header(&state->ls_print); 2995 state->ls_printheader = B_TRUE; 2996 } 2997 2998 dladm_print_output(&state->ls_print, state->ls_parseable, 2999 dladm_print_field, (void *)&pattr); 3000 3001 done: 3002 state->ls_status = status; 3003 return (DLADM_WALK_CONTINUE); 3004 } 3005 3006 3007 /* 3008 * Print the active topology information. 3009 */ 3010 static dladm_status_t 3011 print_vlan(show_state_t *state, datalink_id_t linkid, link_fields_buf_t *l) 3012 { 3013 dladm_vlan_attr_t vinfo; 3014 uint32_t flags; 3015 dladm_status_t status; 3016 3017 if ((status = dladm_datalink_id2info(linkid, &flags, NULL, NULL, 3018 l->link_name, sizeof (l->link_name))) != DLADM_STATUS_OK) { 3019 goto done; 3020 } 3021 3022 if (!(state->ls_flags & flags)) { 3023 status = DLADM_STATUS_NOTFOUND; 3024 goto done; 3025 } 3026 3027 if ((status = dladm_vlan_info(linkid, &vinfo, state->ls_flags)) != 3028 DLADM_STATUS_OK || (status = dladm_datalink_id2info( 3029 vinfo.dv_linkid, NULL, NULL, NULL, l->link_over, 3030 sizeof (l->link_over))) != DLADM_STATUS_OK) { 3031 goto done; 3032 } 3033 3034 (void) snprintf(l->link_vlan_vid, sizeof (l->link_vlan_vid), "%d", 3035 vinfo.dv_vid); 3036 (void) snprintf(l->link_flags, sizeof (l->link_flags), "%c%c---", 3037 vinfo.dv_force ? 'f' : '-', vinfo.dv_implicit ? 'i' : '-'); 3038 3039 done: 3040 return (status); 3041 } 3042 3043 static int 3044 show_vlan(datalink_id_t linkid, void *arg) 3045 { 3046 show_state_t *state = arg; 3047 dladm_status_t status; 3048 link_fields_buf_t lbuf; 3049 3050 status = print_vlan(state, linkid, &lbuf); 3051 if (status != DLADM_STATUS_OK) 3052 goto done; 3053 3054 if (!state->ls_parseable && !state->ls_printheader) { 3055 print_header(&state->ls_print); 3056 state->ls_printheader = B_TRUE; 3057 } 3058 3059 dladm_print_output(&state->ls_print, state->ls_parseable, 3060 dladm_print_field, (void *)&lbuf); 3061 3062 done: 3063 state->ls_status = status; 3064 return (DLADM_WALK_CONTINUE); 3065 } 3066 3067 static void 3068 do_show_phys(int argc, char *argv[]) 3069 { 3070 int option; 3071 uint32_t flags = DLADM_OPT_ACTIVE; 3072 boolean_t p_arg = B_FALSE; 3073 boolean_t o_arg = B_FALSE; 3074 datalink_id_t linkid = DATALINK_ALL_LINKID; 3075 show_state_t state; 3076 dladm_status_t status; 3077 char *fields_str = NULL; 3078 print_field_t **fields; 3079 uint_t nfields; 3080 char *all_active_fields = 3081 "link,media,state,speed,duplex,device"; 3082 char *all_inactive_fields = 3083 "link,device,media,flags"; 3084 3085 bzero(&state, sizeof (state)); 3086 opterr = 0; 3087 while ((option = getopt_long(argc, argv, ":pPo:", 3088 show_lopts, NULL)) != -1) { 3089 switch (option) { 3090 case 'p': 3091 if (p_arg) 3092 die_optdup(option); 3093 3094 p_arg = B_TRUE; 3095 break; 3096 case 'P': 3097 if (flags != DLADM_OPT_ACTIVE) 3098 die_optdup(option); 3099 3100 flags = DLADM_OPT_PERSIST; 3101 break; 3102 case 'o': 3103 o_arg = B_TRUE; 3104 fields_str = optarg; 3105 break; 3106 default: 3107 die_opterr(optopt, option); 3108 break; 3109 } 3110 } 3111 3112 /* get link name (optional last argument) */ 3113 if (optind == (argc-1)) { 3114 if ((status = dladm_name2info(argv[optind], &linkid, NULL, 3115 NULL, NULL)) != DLADM_STATUS_OK) { 3116 die_dlerr(status, "link %s is not valid", argv[optind]); 3117 } 3118 } else if (optind != argc) { 3119 usage(); 3120 } 3121 3122 state.ls_parseable = p_arg; 3123 state.ls_flags = flags; 3124 state.ls_donefirst = B_FALSE; 3125 3126 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) { 3127 if (state.ls_flags & DLADM_OPT_ACTIVE) 3128 fields_str = all_active_fields; 3129 else 3130 fields_str = all_inactive_fields; 3131 } 3132 3133 fields = parse_output_fields(fields_str, phys_fields, 3134 PHYS_MAX_FIELDS, CMD_TYPE_ANY, &nfields); 3135 3136 if (fields == NULL) { 3137 die("invalid field(s) specified"); 3138 return; 3139 } 3140 3141 state.ls_print.ps_fields = fields; 3142 state.ls_print.ps_nfields = nfields; 3143 3144 if (linkid == DATALINK_ALL_LINKID) { 3145 (void) dladm_walk_datalink_id(show_phys, &state, 3146 DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, flags); 3147 } else { 3148 (void) show_phys(linkid, &state); 3149 if (state.ls_status != DLADM_STATUS_OK) { 3150 die_dlerr(state.ls_status, 3151 "failed to show physical link %s", argv[optind]); 3152 } 3153 } 3154 } 3155 3156 static void 3157 do_show_vlan(int argc, char *argv[]) 3158 { 3159 int option; 3160 uint32_t flags = DLADM_OPT_ACTIVE; 3161 boolean_t p_arg = B_FALSE; 3162 datalink_id_t linkid = DATALINK_ALL_LINKID; 3163 show_state_t state; 3164 dladm_status_t status; 3165 boolean_t o_arg = B_FALSE; 3166 char *fields_str = NULL; 3167 print_field_t **fields; 3168 uint_t nfields; 3169 char *all_fields = "link,vid,over,flags"; 3170 3171 bzero(&state, sizeof (state)); 3172 3173 opterr = 0; 3174 while ((option = getopt_long(argc, argv, ":pPo:", 3175 show_lopts, NULL)) != -1) { 3176 switch (option) { 3177 case 'p': 3178 if (p_arg) 3179 die_optdup(option); 3180 3181 p_arg = B_TRUE; 3182 break; 3183 case 'P': 3184 if (flags != DLADM_OPT_ACTIVE) 3185 die_optdup(option); 3186 3187 flags = DLADM_OPT_PERSIST; 3188 break; 3189 case 'o': 3190 o_arg = B_TRUE; 3191 fields_str = optarg; 3192 break; 3193 default: 3194 die_opterr(optopt, option); 3195 break; 3196 } 3197 } 3198 3199 /* get link name (optional last argument) */ 3200 if (optind == (argc-1)) { 3201 if ((status = dladm_name2info(argv[optind], &linkid, NULL, 3202 NULL, NULL)) != DLADM_STATUS_OK) { 3203 die_dlerr(status, "link %s is not valid", argv[optind]); 3204 } 3205 } else if (optind != argc) { 3206 usage(); 3207 } 3208 3209 state.ls_parseable = p_arg; 3210 state.ls_flags = flags; 3211 state.ls_donefirst = B_FALSE; 3212 3213 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) 3214 fields_str = all_fields; 3215 3216 fields = parse_output_fields(fields_str, vlan_fields, VLAN_MAX_FIELDS, 3217 CMD_TYPE_ANY, &nfields); 3218 3219 if (fields == NULL) { 3220 die("invalid field(s) specified"); 3221 return; 3222 } 3223 state.ls_print.ps_fields = fields; 3224 state.ls_print.ps_nfields = nfields; 3225 3226 if (linkid == DATALINK_ALL_LINKID) { 3227 (void) dladm_walk_datalink_id(show_vlan, &state, 3228 DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, flags); 3229 } else { 3230 (void) show_vlan(linkid, &state); 3231 if (state.ls_status != DLADM_STATUS_OK) { 3232 die_dlerr(state.ls_status, "failed to show vlan %s", 3233 argv[optind]); 3234 } 3235 } 3236 } 3237 3238 static void 3239 link_stats(datalink_id_t linkid, uint_t interval) 3240 { 3241 show_state_t state; 3242 3243 bzero(&state, sizeof (state)); 3244 3245 /* 3246 * If an interval is specified, continuously show the stats 3247 * only for the first MAC port. 3248 */ 3249 state.ls_firstonly = (interval != 0); 3250 3251 for (;;) { 3252 (void) printf("%-12s%-10s%-12s%-8s%-10s%-12s%-8s\n", 3253 "LINK", "IPACKETS", "RBYTES", "IERRORS", "OPACKETS", 3254 "OBYTES", "OERRORS"); 3255 3256 state.ls_donefirst = B_FALSE; 3257 if (linkid == DATALINK_ALL_LINKID) { 3258 (void) dladm_walk_datalink_id(show_link_stats, &state, 3259 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, 3260 DLADM_OPT_ACTIVE); 3261 } else { 3262 (void) show_link_stats(linkid, &state); 3263 } 3264 3265 if (interval == 0) 3266 break; 3267 3268 (void) sleep(interval); 3269 } 3270 } 3271 3272 static void 3273 aggr_stats(datalink_id_t linkid, show_grp_state_t *state, uint_t interval) 3274 { 3275 /* 3276 * If an interval is specified, continuously show the stats 3277 * only for the first group. 3278 */ 3279 state->gs_firstonly = (interval != 0); 3280 3281 for (;;) { 3282 state->gs_donefirst = B_FALSE; 3283 if (linkid == DATALINK_ALL_LINKID) 3284 (void) dladm_walk_datalink_id(show_aggr, state, 3285 DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, 3286 DLADM_OPT_ACTIVE); 3287 else 3288 (void) show_aggr(linkid, state); 3289 3290 if (interval == 0) 3291 break; 3292 3293 (void) sleep(interval); 3294 } 3295 } 3296 3297 static void 3298 dev_stats(const char *dev, uint32_t interval, char *fields_str, 3299 show_state_t *state) 3300 { 3301 print_field_t **fields; 3302 uint_t nfields; 3303 3304 fields = parse_output_fields(fields_str, devs_fields, DEVS_MAX_FIELDS, 3305 CMD_TYPE_ANY, &nfields); 3306 3307 if (fields == NULL) { 3308 die("invalid field(s) specified"); 3309 return; 3310 } 3311 3312 state->ls_print.ps_fields = fields; 3313 state->ls_print.ps_nfields = nfields; 3314 3315 3316 /* 3317 * If an interval is specified, continuously show the stats 3318 * only for the first MAC port. 3319 */ 3320 state->ls_firstonly = (interval != 0); 3321 3322 for (;;) { 3323 3324 if (!state->ls_parseable) 3325 print_header(&state->ls_print); 3326 state->ls_donefirst = B_FALSE; 3327 3328 if (dev == NULL) 3329 (void) dladm_mac_walk(show_dev_stats, state); 3330 else 3331 (void) show_dev_stats(dev, state); 3332 3333 if (interval == 0) 3334 break; 3335 3336 (void) sleep(interval); 3337 } 3338 3339 if (dev != NULL && state->ls_status != DLADM_STATUS_OK) 3340 die_dlerr(state->ls_status, "cannot show device '%s'", dev); 3341 } 3342 3343 /* accumulate stats (s1 += (s2 - s3)) */ 3344 static void 3345 stats_total(pktsum_t *s1, pktsum_t *s2, pktsum_t *s3) 3346 { 3347 s1->ipackets += (s2->ipackets - s3->ipackets); 3348 s1->opackets += (s2->opackets - s3->opackets); 3349 s1->rbytes += (s2->rbytes - s3->rbytes); 3350 s1->obytes += (s2->obytes - s3->obytes); 3351 s1->ierrors += (s2->ierrors - s3->ierrors); 3352 s1->oerrors += (s2->oerrors - s3->oerrors); 3353 } 3354 3355 /* compute stats differences (s1 = s2 - s3) */ 3356 static void 3357 stats_diff(pktsum_t *s1, pktsum_t *s2, pktsum_t *s3) 3358 { 3359 s1->ipackets = s2->ipackets - s3->ipackets; 3360 s1->opackets = s2->opackets - s3->opackets; 3361 s1->rbytes = s2->rbytes - s3->rbytes; 3362 s1->obytes = s2->obytes - s3->obytes; 3363 s1->ierrors = s2->ierrors - s3->ierrors; 3364 s1->oerrors = s2->oerrors - s3->oerrors; 3365 } 3366 3367 static void 3368 get_stats(char *module, int instance, const char *name, pktsum_t *stats) 3369 { 3370 kstat_ctl_t *kcp; 3371 kstat_t *ksp; 3372 3373 if ((kcp = kstat_open()) == NULL) { 3374 warn("kstat open operation failed"); 3375 return; 3376 } 3377 3378 if ((ksp = kstat_lookup(kcp, module, instance, (char *)name)) == NULL) { 3379 /* 3380 * The kstat query could fail if the underlying MAC 3381 * driver was already detached. 3382 */ 3383 (void) kstat_close(kcp); 3384 return; 3385 } 3386 3387 if (kstat_read(kcp, ksp, NULL) == -1) 3388 goto bail; 3389 3390 if (dladm_kstat_value(ksp, "ipackets64", KSTAT_DATA_UINT64, 3391 &stats->ipackets) < 0) 3392 goto bail; 3393 3394 if (dladm_kstat_value(ksp, "opackets64", KSTAT_DATA_UINT64, 3395 &stats->opackets) < 0) 3396 goto bail; 3397 3398 if (dladm_kstat_value(ksp, "rbytes64", KSTAT_DATA_UINT64, 3399 &stats->rbytes) < 0) 3400 goto bail; 3401 3402 if (dladm_kstat_value(ksp, "obytes64", KSTAT_DATA_UINT64, 3403 &stats->obytes) < 0) 3404 goto bail; 3405 3406 if (dladm_kstat_value(ksp, "ierrors", KSTAT_DATA_UINT32, 3407 &stats->ierrors) < 0) 3408 goto bail; 3409 3410 if (dladm_kstat_value(ksp, "oerrors", KSTAT_DATA_UINT32, 3411 &stats->oerrors) < 0) 3412 goto bail; 3413 3414 bail: 3415 (void) kstat_close(kcp); 3416 return; 3417 3418 } 3419 3420 static void 3421 get_mac_stats(const char *dev, pktsum_t *stats) 3422 { 3423 char module[DLPI_LINKNAME_MAX]; 3424 uint_t instance; 3425 3426 bzero(stats, sizeof (*stats)); 3427 if (dlpi_parselink(dev, module, &instance) != DLPI_SUCCESS) 3428 return; 3429 3430 get_stats(module, instance, "mac", stats); 3431 } 3432 3433 static void 3434 get_link_stats(const char *link, pktsum_t *stats) 3435 { 3436 bzero(stats, sizeof (*stats)); 3437 get_stats("link", 0, link, stats); 3438 } 3439 3440 static int 3441 query_kstat(char *module, int instance, const char *name, const char *stat, 3442 uint8_t type, void *val) 3443 { 3444 kstat_ctl_t *kcp; 3445 kstat_t *ksp; 3446 3447 if ((kcp = kstat_open()) == NULL) { 3448 warn("kstat open operation failed"); 3449 return (-1); 3450 } 3451 3452 if ((ksp = kstat_lookup(kcp, module, instance, (char *)name)) == NULL) { 3453 /* 3454 * The kstat query could fail if the underlying MAC 3455 * driver was already detached. 3456 */ 3457 goto bail; 3458 } 3459 3460 if (kstat_read(kcp, ksp, NULL) == -1) { 3461 warn("kstat read failed"); 3462 goto bail; 3463 } 3464 3465 if (dladm_kstat_value(ksp, stat, type, val) < 0) 3466 goto bail; 3467 3468 (void) kstat_close(kcp); 3469 return (0); 3470 3471 bail: 3472 (void) kstat_close(kcp); 3473 return (-1); 3474 } 3475 3476 static int 3477 get_one_kstat(const char *name, const char *stat, uint8_t type, 3478 void *val, boolean_t islink) 3479 { 3480 char module[DLPI_LINKNAME_MAX]; 3481 uint_t instance; 3482 3483 if (islink) { 3484 return (query_kstat("link", 0, name, stat, type, val)); 3485 } else { 3486 if (dlpi_parselink(name, module, &instance) != DLPI_SUCCESS) 3487 return (-1); 3488 3489 return (query_kstat(module, instance, "mac", stat, type, val)); 3490 } 3491 } 3492 3493 static uint64_t 3494 get_ifspeed(const char *name, boolean_t islink) 3495 { 3496 uint64_t ifspeed = 0; 3497 3498 (void) get_one_kstat(name, "ifspeed", KSTAT_DATA_UINT64, 3499 &ifspeed, islink); 3500 3501 return (ifspeed); 3502 } 3503 3504 static const char * 3505 get_linkstate(const char *name, boolean_t islink, char *buf) 3506 { 3507 link_state_t linkstate; 3508 3509 if (get_one_kstat(name, "link_state", KSTAT_DATA_UINT32, 3510 &linkstate, islink) != 0) { 3511 (void) strlcpy(buf, "unknown", DLADM_STRSIZE); 3512 return (buf); 3513 } 3514 return (dladm_linkstate2str(linkstate, buf)); 3515 } 3516 3517 static const char * 3518 get_linkduplex(const char *name, boolean_t islink, char *buf) 3519 { 3520 link_duplex_t linkduplex; 3521 3522 if (get_one_kstat(name, "link_duplex", KSTAT_DATA_UINT32, 3523 &linkduplex, islink) != 0) { 3524 (void) strlcpy(buf, "unknown", DLADM_STRSIZE); 3525 return (buf); 3526 } 3527 3528 return (dladm_linkduplex2str(linkduplex, buf)); 3529 } 3530 3531 typedef struct { 3532 char *s_buf; 3533 char **s_fields; /* array of pointer to the fields in s_buf */ 3534 uint_t s_nfields; /* the number of fields in s_buf */ 3535 } split_t; 3536 3537 /* 3538 * Free the split_t structure pointed to by `sp'. 3539 */ 3540 static void 3541 splitfree(split_t *sp) 3542 { 3543 free(sp->s_buf); 3544 free(sp->s_fields); 3545 free(sp); 3546 } 3547 3548 /* 3549 * Split `str' into at most `maxfields' fields, each field at most `maxlen' in 3550 * length. Return a pointer to a split_t containing the split fields, or NULL 3551 * on failure. 3552 */ 3553 static split_t * 3554 split(const char *str, uint_t maxfields, uint_t maxlen) 3555 { 3556 char *field, *token, *lasts = NULL; 3557 split_t *sp; 3558 3559 if (*str == '\0' || maxfields == 0 || maxlen == 0) 3560 return (NULL); 3561 3562 sp = calloc(sizeof (split_t), 1); 3563 if (sp == NULL) 3564 return (NULL); 3565 3566 sp->s_buf = strdup(str); 3567 sp->s_fields = malloc(sizeof (char *) * maxfields); 3568 if (sp->s_buf == NULL || sp->s_fields == NULL) 3569 goto fail; 3570 3571 token = sp->s_buf; 3572 while ((field = strtok_r(token, ",", &lasts)) != NULL) { 3573 if (sp->s_nfields == maxfields || strlen(field) > maxlen) 3574 goto fail; 3575 token = NULL; 3576 sp->s_fields[sp->s_nfields++] = field; 3577 } 3578 return (sp); 3579 fail: 3580 splitfree(sp); 3581 return (NULL); 3582 } 3583 3584 static int 3585 parse_wifi_fields(char *str, print_field_t ***fields, uint_t *countp, 3586 uint_t cmdtype) 3587 { 3588 3589 if (cmdtype == WIFI_CMD_SCAN) { 3590 if (str == NULL) 3591 str = def_scan_wifi_fields; 3592 if (strcasecmp(str, "all") == 0) 3593 str = all_scan_wifi_fields; 3594 } else if (cmdtype == WIFI_CMD_SHOW) { 3595 if (str == NULL) 3596 str = def_show_wifi_fields; 3597 if (strcasecmp(str, "all") == 0) 3598 str = all_show_wifi_fields; 3599 } else { 3600 return (-1); 3601 } 3602 *fields = parse_output_fields(str, wifi_fields, WIFI_MAX_FIELDS, 3603 cmdtype, countp); 3604 if (*fields != NULL) 3605 return (0); 3606 return (-1); 3607 } 3608 static print_field_t ** 3609 parse_output_fields(char *str, print_field_t *template, int max_fields, 3610 uint_t cmdtype, uint_t *countp) 3611 { 3612 split_t *sp; 3613 boolean_t good_match = B_FALSE; 3614 uint_t i, j; 3615 print_field_t **pf = NULL; 3616 3617 sp = split(str, max_fields, MAX_FIELD_LEN); 3618 3619 if (sp == NULL) 3620 return (NULL); 3621 3622 pf = malloc(sp->s_nfields * sizeof (print_field_t *)); 3623 if (pf == NULL) 3624 goto fail; 3625 3626 for (i = 0; i < sp->s_nfields; i++) { 3627 for (j = 0; j < max_fields; j++) { 3628 if (strcasecmp(sp->s_fields[i], 3629 template[j].pf_name) == 0) { 3630 good_match = template[j]. pf_cmdtype & cmdtype; 3631 break; 3632 } 3633 } 3634 if (!good_match) 3635 goto fail; 3636 3637 good_match = B_FALSE; 3638 pf[i] = &template[j]; 3639 } 3640 *countp = i; 3641 splitfree(sp); 3642 return (pf); 3643 fail: 3644 free(pf); 3645 splitfree(sp); 3646 return (NULL); 3647 } 3648 3649 typedef struct print_wifi_state { 3650 char *ws_link; 3651 boolean_t ws_parseable; 3652 boolean_t ws_header; 3653 print_state_t ws_print_state; 3654 } print_wifi_state_t; 3655 3656 typedef struct wlan_scan_args_s { 3657 print_wifi_state_t *ws_state; 3658 void *ws_attr; 3659 } wlan_scan_args_t; 3660 3661 3662 static void 3663 print_field(print_state_t *statep, print_field_t *pfp, const char *value, 3664 boolean_t parseable) 3665 { 3666 uint_t width = pfp->pf_width; 3667 uint_t valwidth = strlen(value); 3668 uint_t compress; 3669 3670 if (parseable) { 3671 (void) printf("%s=\"%s\"", pfp->pf_header, value); 3672 } else { 3673 if (value[0] == '\0') 3674 value = STR_UNDEF_VAL; 3675 if (statep->ps_lastfield) { 3676 (void) printf("%s", value); 3677 return; 3678 } 3679 3680 if (valwidth > width) { 3681 statep->ps_overflow += valwidth - width; 3682 } else if (valwidth < width && statep->ps_overflow > 0) { 3683 compress = min(statep->ps_overflow, width - valwidth); 3684 statep->ps_overflow -= compress; 3685 width -= compress; 3686 } 3687 (void) printf("%-*s", width, value); 3688 } 3689 3690 if (!statep->ps_lastfield) 3691 (void) putchar(' '); 3692 } 3693 3694 static char * 3695 print_wlan_attr(print_field_t *wfp, void *warg) 3696 { 3697 static char buf[DLADM_STRSIZE]; 3698 wlan_scan_args_t *w = warg; 3699 print_wifi_state_t *statep = w->ws_state; 3700 dladm_wlan_attr_t *attrp = w->ws_attr; 3701 3702 if (wfp->pf_index == 0) { 3703 return ((char *)statep->ws_link); 3704 } 3705 3706 if ((wfp->pf_index & attrp->wa_valid) == 0) { 3707 return (""); 3708 } 3709 3710 switch (wfp->pf_index) { 3711 case DLADM_WLAN_ATTR_ESSID: 3712 (void) dladm_wlan_essid2str(&attrp->wa_essid, buf); 3713 break; 3714 case DLADM_WLAN_ATTR_BSSID: 3715 (void) dladm_wlan_bssid2str(&attrp->wa_bssid, buf); 3716 break; 3717 case DLADM_WLAN_ATTR_SECMODE: 3718 (void) dladm_wlan_secmode2str(&attrp->wa_secmode, buf); 3719 break; 3720 case DLADM_WLAN_ATTR_STRENGTH: 3721 (void) dladm_wlan_strength2str(&attrp->wa_strength, buf); 3722 break; 3723 case DLADM_WLAN_ATTR_MODE: 3724 (void) dladm_wlan_mode2str(&attrp->wa_mode, buf); 3725 break; 3726 case DLADM_WLAN_ATTR_SPEED: 3727 (void) dladm_wlan_speed2str(&attrp->wa_speed, buf); 3728 (void) strlcat(buf, "Mb", sizeof (buf)); 3729 break; 3730 case DLADM_WLAN_ATTR_AUTH: 3731 (void) dladm_wlan_auth2str(&attrp->wa_auth, buf); 3732 break; 3733 case DLADM_WLAN_ATTR_BSSTYPE: 3734 (void) dladm_wlan_bsstype2str(&attrp->wa_bsstype, buf); 3735 break; 3736 } 3737 3738 return (buf); 3739 } 3740 3741 static boolean_t 3742 print_scan_results(void *arg, dladm_wlan_attr_t *attrp) 3743 { 3744 print_wifi_state_t *statep = arg; 3745 wlan_scan_args_t warg; 3746 3747 if (statep->ws_header) { 3748 statep->ws_header = B_FALSE; 3749 if (!statep->ws_parseable) 3750 print_header(&statep->ws_print_state); 3751 } 3752 3753 statep->ws_print_state.ps_overflow = 0; 3754 bzero(&warg, sizeof (warg)); 3755 warg.ws_state = statep; 3756 warg.ws_attr = attrp; 3757 dladm_print_output(&statep->ws_print_state, statep->ws_parseable, 3758 print_wlan_attr, &warg); 3759 return (B_TRUE); 3760 } 3761 3762 static int 3763 scan_wifi(datalink_id_t linkid, void *arg) 3764 { 3765 print_wifi_state_t *statep = arg; 3766 dladm_status_t status; 3767 char link[MAXLINKNAMELEN]; 3768 3769 if ((status = dladm_datalink_id2info(linkid, NULL, NULL, NULL, link, 3770 sizeof (link))) != DLADM_STATUS_OK) { 3771 return (DLADM_WALK_CONTINUE); 3772 } 3773 3774 statep->ws_link = link; 3775 status = dladm_wlan_scan(linkid, statep, print_scan_results); 3776 if (status != DLADM_STATUS_OK) 3777 die_dlerr(status, "cannot scan link '%s'", statep->ws_link); 3778 3779 return (DLADM_WALK_CONTINUE); 3780 } 3781 3782 static char * 3783 print_link_attr(print_field_t *wfp, void *warg) 3784 { 3785 static char buf[DLADM_STRSIZE]; 3786 char *ptr; 3787 wlan_scan_args_t *w = warg, w1; 3788 print_wifi_state_t *statep = w->ws_state; 3789 dladm_wlan_linkattr_t *attrp = w->ws_attr; 3790 3791 if (strcmp(wfp->pf_name, "status") == 0) { 3792 if ((wfp->pf_index & attrp->la_valid) != 0) 3793 (void) dladm_wlan_linkstatus2str( 3794 &attrp->la_status, buf); 3795 return (buf); 3796 } 3797 statep->ws_print_state.ps_overflow = 0; 3798 bzero(&w1, sizeof (w1)); 3799 w1.ws_state = statep; 3800 w1.ws_attr = &attrp->la_wlan_attr; 3801 ptr = print_wlan_attr(wfp, &w1); 3802 return (ptr); 3803 } 3804 3805 static int 3806 show_wifi(datalink_id_t linkid, void *arg) 3807 { 3808 print_wifi_state_t *statep = arg; 3809 dladm_wlan_linkattr_t attr; 3810 dladm_status_t status; 3811 char link[MAXLINKNAMELEN]; 3812 wlan_scan_args_t warg; 3813 3814 if ((status = dladm_datalink_id2info(linkid, NULL, NULL, NULL, link, 3815 sizeof (link))) != DLADM_STATUS_OK) { 3816 return (DLADM_WALK_CONTINUE); 3817 } 3818 3819 status = dladm_wlan_get_linkattr(linkid, &attr); 3820 if (status != DLADM_STATUS_OK) 3821 die_dlerr(status, "cannot get link attributes for %s", link); 3822 3823 statep->ws_link = link; 3824 3825 if (statep->ws_header) { 3826 statep->ws_header = B_FALSE; 3827 if (!statep->ws_parseable) 3828 print_header(&statep->ws_print_state); 3829 } 3830 3831 statep->ws_print_state.ps_overflow = 0; 3832 bzero(&warg, sizeof (warg)); 3833 warg.ws_state = statep; 3834 warg.ws_attr = &attr; 3835 dladm_print_output(&statep->ws_print_state, statep->ws_parseable, 3836 print_link_attr, &warg); 3837 return (DLADM_WALK_CONTINUE); 3838 } 3839 3840 static void 3841 do_display_wifi(int argc, char **argv, int cmd) 3842 { 3843 int option; 3844 char *fields_str = NULL; 3845 print_field_t **fields; 3846 int (*callback)(datalink_id_t, void *); 3847 uint_t nfields; 3848 print_wifi_state_t state; 3849 datalink_id_t linkid = DATALINK_ALL_LINKID; 3850 dladm_status_t status; 3851 3852 if (cmd == WIFI_CMD_SCAN) 3853 callback = scan_wifi; 3854 else if (cmd == WIFI_CMD_SHOW) 3855 callback = show_wifi; 3856 else 3857 return; 3858 3859 state.ws_parseable = B_FALSE; 3860 state.ws_header = B_TRUE; 3861 opterr = 0; 3862 while ((option = getopt_long(argc, argv, ":o:p", 3863 wifi_longopts, NULL)) != -1) { 3864 switch (option) { 3865 case 'o': 3866 fields_str = optarg; 3867 break; 3868 case 'p': 3869 state.ws_parseable = B_TRUE; 3870 if (fields_str == NULL) 3871 fields_str = "all"; 3872 break; 3873 default: 3874 die_opterr(optopt, option); 3875 break; 3876 } 3877 } 3878 3879 if (optind == (argc - 1)) { 3880 if ((status = dladm_name2info(argv[optind], &linkid, NULL, 3881 NULL, NULL)) != DLADM_STATUS_OK) { 3882 die_dlerr(status, "link %s is not valid", argv[optind]); 3883 } 3884 } else if (optind != argc) { 3885 usage(); 3886 } 3887 3888 if (parse_wifi_fields(fields_str, &fields, &nfields, cmd) < 0) 3889 die("invalid field(s) specified"); 3890 3891 bzero(&state.ws_print_state, sizeof (state.ws_print_state)); 3892 state.ws_print_state.ps_fields = fields; 3893 state.ws_print_state.ps_nfields = nfields; 3894 3895 if (linkid == DATALINK_ALL_LINKID) { 3896 (void) dladm_walk_datalink_id(callback, &state, 3897 DATALINK_CLASS_PHYS, DL_WIFI, DLADM_OPT_ACTIVE); 3898 } else { 3899 (void) (*callback)(linkid, &state); 3900 } 3901 free(fields); 3902 } 3903 3904 static void 3905 do_scan_wifi(int argc, char **argv) 3906 { 3907 do_display_wifi(argc, argv, WIFI_CMD_SCAN); 3908 } 3909 3910 static void 3911 do_show_wifi(int argc, char **argv) 3912 { 3913 do_display_wifi(argc, argv, WIFI_CMD_SHOW); 3914 } 3915 3916 typedef struct wlan_count_attr { 3917 uint_t wc_count; 3918 datalink_id_t wc_linkid; 3919 } wlan_count_attr_t; 3920 3921 static int 3922 do_count_wlan(datalink_id_t linkid, void *arg) 3923 { 3924 wlan_count_attr_t *cp = arg; 3925 3926 if (cp->wc_count == 0) 3927 cp->wc_linkid = linkid; 3928 cp->wc_count++; 3929 return (DLADM_WALK_CONTINUE); 3930 } 3931 3932 static int 3933 parse_wlan_keys(char *str, dladm_wlan_key_t **keys, uint_t *key_countp) 3934 { 3935 uint_t i; 3936 split_t *sp; 3937 dladm_wlan_key_t *wk; 3938 3939 sp = split(str, DLADM_WLAN_MAX_WEPKEYS, DLADM_WLAN_MAX_KEYNAME_LEN); 3940 if (sp == NULL) 3941 return (-1); 3942 3943 wk = malloc(sp->s_nfields * sizeof (dladm_wlan_key_t)); 3944 if (wk == NULL) 3945 goto fail; 3946 3947 for (i = 0; i < sp->s_nfields; i++) { 3948 char *s; 3949 dladm_secobj_class_t class; 3950 dladm_status_t status; 3951 3952 (void) strlcpy(wk[i].wk_name, sp->s_fields[i], 3953 DLADM_WLAN_MAX_KEYNAME_LEN); 3954 3955 wk[i].wk_idx = 1; 3956 if ((s = strrchr(wk[i].wk_name, ':')) != NULL) { 3957 if (s[1] == '\0' || s[2] != '\0' || !isdigit(s[1])) 3958 goto fail; 3959 3960 wk[i].wk_idx = (uint_t)(s[1] - '0'); 3961 *s = '\0'; 3962 } 3963 wk[i].wk_len = DLADM_WLAN_MAX_KEY_LEN; 3964 3965 status = dladm_get_secobj(wk[i].wk_name, &class, 3966 wk[i].wk_val, &wk[i].wk_len, 0); 3967 if (status != DLADM_STATUS_OK) { 3968 if (status == DLADM_STATUS_NOTFOUND) { 3969 status = dladm_get_secobj(wk[i].wk_name, 3970 &class, wk[i].wk_val, &wk[i].wk_len, 3971 DLADM_OPT_PERSIST); 3972 } 3973 if (status != DLADM_STATUS_OK) 3974 goto fail; 3975 } 3976 wk[i].wk_class = class; 3977 } 3978 *keys = wk; 3979 *key_countp = i; 3980 splitfree(sp); 3981 return (0); 3982 fail: 3983 free(wk); 3984 splitfree(sp); 3985 return (-1); 3986 } 3987 3988 static void 3989 do_connect_wifi(int argc, char **argv) 3990 { 3991 int option; 3992 dladm_wlan_attr_t attr, *attrp; 3993 dladm_status_t status = DLADM_STATUS_OK; 3994 int timeout = DLADM_WLAN_CONNECT_TIMEOUT_DEFAULT; 3995 datalink_id_t linkid = DATALINK_ALL_LINKID; 3996 dladm_wlan_key_t *keys = NULL; 3997 uint_t key_count = 0; 3998 uint_t flags = 0; 3999 dladm_wlan_secmode_t keysecmode = DLADM_WLAN_SECMODE_NONE; 4000 char buf[DLADM_STRSIZE]; 4001 4002 opterr = 0; 4003 (void) memset(&attr, 0, sizeof (attr)); 4004 while ((option = getopt_long(argc, argv, ":e:i:a:m:b:s:k:T:c", 4005 wifi_longopts, NULL)) != -1) { 4006 switch (option) { 4007 case 'e': 4008 status = dladm_wlan_str2essid(optarg, &attr.wa_essid); 4009 if (status != DLADM_STATUS_OK) 4010 die("invalid ESSID '%s'", optarg); 4011 4012 attr.wa_valid |= DLADM_WLAN_ATTR_ESSID; 4013 /* 4014 * Try to connect without doing a scan. 4015 */ 4016 flags |= DLADM_WLAN_CONNECT_NOSCAN; 4017 break; 4018 case 'i': 4019 status = dladm_wlan_str2bssid(optarg, &attr.wa_bssid); 4020 if (status != DLADM_STATUS_OK) 4021 die("invalid BSSID %s", optarg); 4022 4023 attr.wa_valid |= DLADM_WLAN_ATTR_BSSID; 4024 break; 4025 case 'a': 4026 status = dladm_wlan_str2auth(optarg, &attr.wa_auth); 4027 if (status != DLADM_STATUS_OK) 4028 die("invalid authentication mode '%s'", optarg); 4029 4030 attr.wa_valid |= DLADM_WLAN_ATTR_AUTH; 4031 break; 4032 case 'm': 4033 status = dladm_wlan_str2mode(optarg, &attr.wa_mode); 4034 if (status != DLADM_STATUS_OK) 4035 die("invalid mode '%s'", optarg); 4036 4037 attr.wa_valid |= DLADM_WLAN_ATTR_MODE; 4038 break; 4039 case 'b': 4040 if ((status = dladm_wlan_str2bsstype(optarg, 4041 &attr.wa_bsstype)) != DLADM_STATUS_OK) { 4042 die("invalid bsstype '%s'", optarg); 4043 } 4044 4045 attr.wa_valid |= DLADM_WLAN_ATTR_BSSTYPE; 4046 break; 4047 case 's': 4048 if ((status = dladm_wlan_str2secmode(optarg, 4049 &attr.wa_secmode)) != DLADM_STATUS_OK) { 4050 die("invalid security mode '%s'", optarg); 4051 } 4052 4053 attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE; 4054 break; 4055 case 'k': 4056 if (parse_wlan_keys(optarg, &keys, &key_count) < 0) 4057 die("invalid key(s) '%s'", optarg); 4058 4059 if (keys[0].wk_class == DLADM_SECOBJ_CLASS_WEP) 4060 keysecmode = DLADM_WLAN_SECMODE_WEP; 4061 else 4062 keysecmode = DLADM_WLAN_SECMODE_WPA; 4063 break; 4064 case 'T': 4065 if (strcasecmp(optarg, "forever") == 0) { 4066 timeout = -1; 4067 break; 4068 } 4069 if (!str2int(optarg, &timeout) || timeout < 0) 4070 die("invalid timeout value '%s'", optarg); 4071 break; 4072 case 'c': 4073 flags |= DLADM_WLAN_CONNECT_CREATEIBSS; 4074 flags |= DLADM_WLAN_CONNECT_CREATEIBSS; 4075 break; 4076 default: 4077 die_opterr(optopt, option); 4078 break; 4079 } 4080 } 4081 4082 if (keysecmode == DLADM_WLAN_SECMODE_NONE) { 4083 if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0) { 4084 die("key required for security mode '%s'", 4085 dladm_wlan_secmode2str(&attr.wa_secmode, buf)); 4086 } 4087 } else { 4088 if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0 && 4089 attr.wa_secmode != keysecmode) 4090 die("incompatible -s and -k options"); 4091 attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE; 4092 attr.wa_secmode = keysecmode; 4093 } 4094 4095 if (optind == (argc - 1)) { 4096 if ((status = dladm_name2info(argv[optind], &linkid, NULL, 4097 NULL, NULL)) != DLADM_STATUS_OK) { 4098 die_dlerr(status, "link %s is not valid", argv[optind]); 4099 } 4100 } else if (optind != argc) { 4101 usage(); 4102 } 4103 4104 if (linkid == DATALINK_ALL_LINKID) { 4105 wlan_count_attr_t wcattr; 4106 4107 wcattr.wc_linkid = DATALINK_INVALID_LINKID; 4108 wcattr.wc_count = 0; 4109 (void) dladm_walk_datalink_id(do_count_wlan, &wcattr, 4110 DATALINK_CLASS_PHYS, DL_WIFI, DLADM_OPT_ACTIVE); 4111 if (wcattr.wc_count == 0) { 4112 die("no wifi links are available"); 4113 } else if (wcattr.wc_count > 1) { 4114 die("link name is required when more than one wifi " 4115 "link is available"); 4116 } 4117 linkid = wcattr.wc_linkid; 4118 } 4119 attrp = (attr.wa_valid == 0) ? NULL : &attr; 4120 again: 4121 if ((status = dladm_wlan_connect(linkid, attrp, timeout, keys, 4122 key_count, flags)) != DLADM_STATUS_OK) { 4123 if ((flags & DLADM_WLAN_CONNECT_NOSCAN) != 0) { 4124 /* 4125 * Try again with scanning and filtering. 4126 */ 4127 flags &= ~DLADM_WLAN_CONNECT_NOSCAN; 4128 goto again; 4129 } 4130 4131 if (status == DLADM_STATUS_NOTFOUND) { 4132 if (attr.wa_valid == 0) { 4133 die("no wifi networks are available"); 4134 } else { 4135 die("no wifi networks with the specified " 4136 "criteria are available"); 4137 } 4138 } 4139 die_dlerr(status, "cannot connect"); 4140 } 4141 free(keys); 4142 } 4143 4144 /* ARGSUSED */ 4145 static int 4146 do_all_disconnect_wifi(datalink_id_t linkid, void *arg) 4147 { 4148 dladm_status_t status; 4149 4150 status = dladm_wlan_disconnect(linkid); 4151 if (status != DLADM_STATUS_OK) 4152 warn_dlerr(status, "cannot disconnect link"); 4153 4154 return (DLADM_WALK_CONTINUE); 4155 } 4156 4157 static void 4158 do_disconnect_wifi(int argc, char **argv) 4159 { 4160 int option; 4161 datalink_id_t linkid = DATALINK_ALL_LINKID; 4162 boolean_t all_links = B_FALSE; 4163 dladm_status_t status; 4164 wlan_count_attr_t wcattr; 4165 4166 opterr = 0; 4167 while ((option = getopt_long(argc, argv, ":a", 4168 wifi_longopts, NULL)) != -1) { 4169 switch (option) { 4170 case 'a': 4171 all_links = B_TRUE; 4172 break; 4173 default: 4174 die_opterr(optopt, option); 4175 break; 4176 } 4177 } 4178 4179 if (optind == (argc - 1)) { 4180 if ((status = dladm_name2info(argv[optind], &linkid, NULL, 4181 NULL, NULL)) != DLADM_STATUS_OK) { 4182 die_dlerr(status, "link %s is not valid", argv[optind]); 4183 } 4184 } else if (optind != argc) { 4185 usage(); 4186 } 4187 4188 if (linkid == DATALINK_ALL_LINKID) { 4189 if (!all_links) { 4190 wcattr.wc_linkid = linkid; 4191 wcattr.wc_count = 0; 4192 (void) dladm_walk_datalink_id(do_count_wlan, &wcattr, 4193 DATALINK_CLASS_PHYS, DL_WIFI, DLADM_OPT_ACTIVE); 4194 if (wcattr.wc_count == 0) { 4195 die("no wifi links are available"); 4196 } else if (wcattr.wc_count > 1) { 4197 die("link name is required when more than " 4198 "one wifi link is available"); 4199 } 4200 linkid = wcattr.wc_linkid; 4201 } else { 4202 (void) dladm_walk_datalink_id(do_all_disconnect_wifi, 4203 NULL, DATALINK_CLASS_PHYS, DL_WIFI, 4204 DLADM_OPT_ACTIVE); 4205 return; 4206 } 4207 } 4208 status = dladm_wlan_disconnect(linkid); 4209 if (status != DLADM_STATUS_OK) 4210 die_dlerr(status, "cannot disconnect"); 4211 } 4212 4213 4214 static void 4215 free_props(prop_list_t *list) 4216 { 4217 if (list != NULL) { 4218 free(list->pl_buf); 4219 free(list); 4220 } 4221 } 4222 4223 static int 4224 parse_props(char *str, prop_list_t **listp, boolean_t novalues) 4225 { 4226 prop_list_t *list; 4227 prop_info_t *pip; 4228 char *buf, *curr; 4229 int len, i; 4230 4231 list = malloc(sizeof (prop_list_t)); 4232 if (list == NULL) 4233 return (-1); 4234 4235 list->pl_count = 0; 4236 list->pl_buf = buf = strdup(str); 4237 if (buf == NULL) 4238 goto fail; 4239 4240 /* 4241 * buf is a string of form [<propname>=<value>][,<propname>=<value>]+ 4242 * where each <value> string itself could be a comma-separated array. 4243 * The loop below will count the number of propname assignments 4244 * in pl_count; for each property, there is a pip entry with 4245 * pi_name == <propname>, pi_count == # of elements in <value> array. 4246 * pi_val[] contains the actual values. 4247 * 4248 * This could really be a combination of calls to 4249 * strtok (token delimiter is ",") and strchr (chr '=') 4250 * with appropriate null/string-bound-checks. 4251 */ 4252 4253 curr = buf; 4254 len = strlen(buf); 4255 pip = NULL; 4256 for (i = 0; i < len; i++) { 4257 char c = buf[i]; 4258 boolean_t match = (c == '=' || c == ','); 4259 4260 if (!match && i != len - 1) 4261 continue; 4262 4263 if (match) { 4264 buf[i] = '\0'; 4265 if (*curr == '\0') 4266 goto fail; 4267 } 4268 4269 if (pip != NULL && c != '=') { 4270 if (pip->pi_count > DLADM_MAX_PROP_VALCNT) 4271 goto fail; 4272 4273 if (novalues) 4274 goto fail; 4275 4276 pip->pi_val[pip->pi_count] = curr; 4277 pip->pi_count++; 4278 } else { 4279 if (list->pl_count > MAX_PROPS) 4280 goto fail; 4281 4282 pip = &list->pl_info[list->pl_count]; 4283 pip->pi_name = curr; 4284 pip->pi_count = 0; 4285 list->pl_count++; 4286 if (c == ',') 4287 pip = NULL; 4288 } 4289 curr = buf + i + 1; 4290 } 4291 *listp = list; 4292 return (0); 4293 4294 fail: 4295 free_props(list); 4296 return (-1); 4297 } 4298 4299 static void 4300 print_linkprop(datalink_id_t linkid, show_linkprop_state_t *statep, 4301 const char *propname, dladm_prop_type_t type, 4302 const char *format, char **pptr) 4303 { 4304 int i; 4305 char *ptr, *lim; 4306 char buf[DLADM_STRSIZE]; 4307 char *unknown = "?", *notsup = ""; 4308 char **propvals = statep->ls_propvals; 4309 uint_t valcnt = DLADM_MAX_PROP_VALCNT; 4310 dladm_status_t status; 4311 4312 status = dladm_get_linkprop(linkid, type, propname, propvals, &valcnt); 4313 if (status != DLADM_STATUS_OK) { 4314 if (status == DLADM_STATUS_TEMPONLY) { 4315 if (type == DLADM_PROP_VAL_MODIFIABLE && 4316 statep->ls_persist) { 4317 valcnt = 1; 4318 propvals = &unknown; 4319 } else { 4320 statep->ls_status = status; 4321 statep->ls_retstatus = status; 4322 return; 4323 } 4324 } else if (status == DLADM_STATUS_NOTSUP || 4325 statep->ls_persist) { 4326 valcnt = 1; 4327 if (type == DLADM_PROP_VAL_CURRENT) 4328 propvals = &unknown; 4329 else 4330 propvals = ¬sup; 4331 } else { 4332 if (statep->ls_proplist && 4333 statep->ls_status == DLADM_STATUS_OK) { 4334 warn_dlerr(status, 4335 "cannot get link property '%s' for %s", 4336 propname, statep->ls_link); 4337 } 4338 statep->ls_status = status; 4339 statep->ls_retstatus = status; 4340 return; 4341 } 4342 } 4343 4344 statep->ls_status = DLADM_STATUS_OK; 4345 4346 ptr = buf; 4347 lim = buf + DLADM_STRSIZE; 4348 for (i = 0; i < valcnt; i++) { 4349 if (propvals[i][0] == '\0' && !statep->ls_parseable) 4350 ptr += snprintf(ptr, lim - ptr, STR_UNDEF_VAL","); 4351 else 4352 ptr += snprintf(ptr, lim - ptr, "%s,", propvals[i]); 4353 if (ptr >= lim) 4354 break; 4355 } 4356 if (valcnt > 0) 4357 buf[strlen(buf) - 1] = '\0'; 4358 4359 lim = statep->ls_line + MAX_PROP_LINE; 4360 if (statep->ls_parseable) { 4361 *pptr += snprintf(*pptr, lim - *pptr, 4362 "%s", buf); 4363 } else { 4364 *pptr += snprintf(*pptr, lim - *pptr, format, buf); 4365 } 4366 } 4367 4368 static char * 4369 linkprop_callback(print_field_t *pf, void *ls_arg) 4370 { 4371 linkprop_args_t *arg = ls_arg; 4372 char *propname = arg->ls_propname; 4373 show_linkprop_state_t *statep = arg->ls_state; 4374 char *ptr = statep->ls_line; 4375 char *lim = ptr + MAX_PROP_LINE; 4376 datalink_id_t linkid = arg->ls_linkid; 4377 4378 switch (pf->pf_index) { 4379 case LINKPROP_LINK: 4380 (void) snprintf(ptr, lim - ptr, "%s", statep->ls_link); 4381 break; 4382 case LINKPROP_PROPERTY: 4383 (void) snprintf(ptr, lim - ptr, "%s", propname); 4384 break; 4385 case LINKPROP_VALUE: 4386 print_linkprop(linkid, statep, propname, 4387 statep->ls_persist ? DLADM_PROP_VAL_PERSISTENT : 4388 DLADM_PROP_VAL_CURRENT, "%s", &ptr); 4389 /* 4390 * If we failed to query the link property, for example, query 4391 * the persistent value of a non-persistable link property, 4392 * simply skip the output. 4393 */ 4394 if (statep->ls_status != DLADM_STATUS_OK) 4395 goto skip; 4396 ptr = statep->ls_line; 4397 break; 4398 case LINKPROP_DEFAULT: 4399 print_linkprop(linkid, statep, propname, 4400 DLADM_PROP_VAL_DEFAULT, "%s", &ptr); 4401 if (statep->ls_status != DLADM_STATUS_OK) 4402 goto skip; 4403 ptr = statep->ls_line; 4404 break; 4405 case LINKPROP_POSSIBLE: 4406 print_linkprop(linkid, statep, propname, 4407 DLADM_PROP_VAL_MODIFIABLE, "%s ", &ptr); 4408 if (statep->ls_status != DLADM_STATUS_OK) 4409 goto skip; 4410 ptr = statep->ls_line; 4411 break; 4412 default: 4413 die("invalid input"); 4414 break; 4415 } 4416 return (ptr); 4417 skip: 4418 if (statep->ls_status != DLADM_STATUS_OK) 4419 return (NULL); 4420 else 4421 return (""); 4422 } 4423 4424 static int 4425 show_linkprop(datalink_id_t linkid, const char *propname, void *arg) 4426 { 4427 show_linkprop_state_t *statep = arg; 4428 linkprop_args_t ls_arg; 4429 4430 bzero(&ls_arg, sizeof (ls_arg)); 4431 ls_arg.ls_state = statep; 4432 ls_arg.ls_propname = (char *)propname; 4433 ls_arg.ls_linkid = linkid; 4434 4435 if (statep->ls_header) { 4436 statep->ls_header = B_FALSE; 4437 if (!statep->ls_parseable) 4438 print_header(&statep->ls_print); 4439 } 4440 dladm_print_output(&statep->ls_print, statep->ls_parseable, 4441 linkprop_callback, (void *)&ls_arg); 4442 4443 return (DLADM_WALK_CONTINUE); 4444 } 4445 4446 static void 4447 do_show_linkprop(int argc, char **argv) 4448 { 4449 int option; 4450 prop_list_t *proplist = NULL; 4451 datalink_id_t linkid = DATALINK_ALL_LINKID; 4452 show_linkprop_state_t state; 4453 uint32_t flags = DLADM_OPT_ACTIVE; 4454 dladm_status_t status; 4455 char *fields_str = NULL; 4456 print_field_t **fields; 4457 uint_t nfields; 4458 char *all_fields = 4459 "link,property,value,default,possible"; 4460 4461 fields_str = all_fields; 4462 4463 opterr = 0; 4464 state.ls_propvals = NULL; 4465 state.ls_line = NULL; 4466 state.ls_parseable = B_FALSE; 4467 state.ls_persist = B_FALSE; 4468 state.ls_header = B_TRUE; 4469 state.ls_retstatus = DLADM_STATUS_OK; 4470 while ((option = getopt_long(argc, argv, ":p:cPo:", 4471 prop_longopts, NULL)) != -1) { 4472 switch (option) { 4473 case 'p': 4474 if (parse_props(optarg, &proplist, B_TRUE) < 0) 4475 die("invalid link properties specified"); 4476 break; 4477 case 'c': 4478 state.ls_parseable = B_TRUE; 4479 break; 4480 case 'P': 4481 state.ls_persist = B_TRUE; 4482 flags = DLADM_OPT_PERSIST; 4483 break; 4484 case 'o': 4485 if (strcasecmp(optarg, "all") == 0) 4486 fields_str = all_fields; 4487 else 4488 fields_str = optarg; 4489 break; 4490 default: 4491 die_opterr(optopt, option); 4492 break; 4493 } 4494 } 4495 4496 if (optind == (argc - 1)) { 4497 if ((status = dladm_name2info(argv[optind], &linkid, NULL, 4498 NULL, NULL)) != DLADM_STATUS_OK) { 4499 die_dlerr(status, "link %s is not valid", argv[optind]); 4500 } 4501 } else if (optind != argc) { 4502 usage(); 4503 } 4504 4505 bzero(&state.ls_print, sizeof (print_state_t)); 4506 state.ls_proplist = proplist; 4507 state.ls_status = DLADM_STATUS_OK; 4508 4509 fields = parse_output_fields(fields_str, linkprop_fields, 4510 LINKPROP_MAX_FIELDS, CMD_TYPE_ANY, &nfields); 4511 4512 if (fields == NULL) { 4513 die("invalid field(s) specified"); 4514 return; 4515 } 4516 4517 state.ls_print.ps_fields = fields; 4518 state.ls_print.ps_nfields = nfields; 4519 if (linkid == DATALINK_ALL_LINKID) { 4520 (void) dladm_walk_datalink_id(show_linkprop_onelink, &state, 4521 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, flags); 4522 } else { 4523 (void) show_linkprop_onelink(linkid, &state); 4524 } 4525 free_props(proplist); 4526 4527 if (state.ls_retstatus != DLADM_STATUS_OK) 4528 exit(EXIT_FAILURE); 4529 } 4530 4531 static int 4532 show_linkprop_onelink(datalink_id_t linkid, void *arg) 4533 { 4534 int i; 4535 char *buf; 4536 uint32_t flags; 4537 prop_list_t *proplist = NULL; 4538 show_linkprop_state_t *statep = arg; 4539 dlpi_handle_t dh = NULL; 4540 4541 statep->ls_status = DLADM_STATUS_OK; 4542 4543 if (dladm_datalink_id2info(linkid, &flags, NULL, NULL, statep->ls_link, 4544 MAXLINKNAMELEN) != DLADM_STATUS_OK) { 4545 statep->ls_status = DLADM_STATUS_NOTFOUND; 4546 return (DLADM_WALK_CONTINUE); 4547 } 4548 4549 if ((statep->ls_persist && !(flags & DLADM_OPT_PERSIST)) || 4550 (!statep->ls_persist && !(flags & DLADM_OPT_ACTIVE))) { 4551 statep->ls_status = DLADM_STATUS_BADARG; 4552 return (DLADM_WALK_CONTINUE); 4553 } 4554 4555 proplist = statep->ls_proplist; 4556 4557 /* 4558 * When some WiFi links are opened for the first time, their hardware 4559 * automatically scans for APs and does other slow operations. Thus, 4560 * if there are no open links, the retrieval of link properties 4561 * (below) will proceed slowly unless we hold the link open. 4562 * 4563 * Note that failure of dlpi_open() does not necessarily mean invalid 4564 * link properties, because dlpi_open() may fail because of incorrect 4565 * autopush configuration. Therefore, we ingore the return value of 4566 * dlpi_open(). 4567 */ 4568 if (!statep->ls_persist) 4569 (void) dlpi_open(statep->ls_link, &dh, 0); 4570 4571 buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) * 4572 DLADM_MAX_PROP_VALCNT + MAX_PROP_LINE); 4573 if (buf == NULL) 4574 die("insufficient memory"); 4575 4576 statep->ls_propvals = (char **)(void *)buf; 4577 for (i = 0; i < DLADM_MAX_PROP_VALCNT; i++) { 4578 statep->ls_propvals[i] = buf + 4579 sizeof (char *) * DLADM_MAX_PROP_VALCNT + 4580 i * DLADM_PROP_VAL_MAX; 4581 } 4582 statep->ls_line = buf + 4583 (sizeof (char *) + DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT; 4584 4585 if (proplist != NULL) { 4586 for (i = 0; i < proplist->pl_count; i++) { 4587 (void) show_linkprop(linkid, 4588 proplist->pl_info[i].pi_name, statep); 4589 } 4590 } else { 4591 (void) dladm_walk_linkprop(linkid, statep, show_linkprop); 4592 } 4593 if (dh != NULL) 4594 dlpi_close(dh); 4595 free(buf); 4596 return (DLADM_WALK_CONTINUE); 4597 } 4598 4599 static dladm_status_t 4600 set_linkprop_persist(datalink_id_t linkid, const char *prop_name, 4601 char **prop_val, uint_t val_cnt, boolean_t reset) 4602 { 4603 dladm_status_t status; 4604 4605 status = dladm_set_linkprop(linkid, prop_name, prop_val, val_cnt, 4606 DLADM_OPT_PERSIST); 4607 4608 if (status != DLADM_STATUS_OK) { 4609 warn_dlerr(status, "cannot persistently %s link property", 4610 reset ? "reset" : "set"); 4611 } 4612 return (status); 4613 } 4614 4615 static void 4616 set_linkprop(int argc, char **argv, boolean_t reset) 4617 { 4618 int i, option; 4619 char errmsg[DLADM_STRSIZE]; 4620 char *altroot = NULL; 4621 datalink_id_t linkid; 4622 prop_list_t *proplist = NULL; 4623 boolean_t temp = B_FALSE; 4624 dladm_status_t status = DLADM_STATUS_OK; 4625 4626 opterr = 0; 4627 while ((option = getopt_long(argc, argv, ":p:R:t", 4628 prop_longopts, NULL)) != -1) { 4629 switch (option) { 4630 case 'p': 4631 if (parse_props(optarg, &proplist, reset) < 0) 4632 die("invalid link properties specified"); 4633 break; 4634 case 't': 4635 temp = B_TRUE; 4636 break; 4637 case 'R': 4638 altroot = optarg; 4639 break; 4640 default: 4641 die_opterr(optopt, option); 4642 break; 4643 } 4644 } 4645 4646 /* get link name (required last argument) */ 4647 if (optind != (argc - 1)) 4648 usage(); 4649 4650 if (proplist == NULL && !reset) 4651 die("link property must be specified"); 4652 4653 if (altroot != NULL) { 4654 free_props(proplist); 4655 altroot_cmd(altroot, argc, argv); 4656 } 4657 4658 status = dladm_name2info(argv[optind], &linkid, NULL, NULL, NULL); 4659 if (status != DLADM_STATUS_OK) 4660 die_dlerr(status, "link %s is not valid", argv[optind]); 4661 4662 if (proplist == NULL) { 4663 status = dladm_set_linkprop(linkid, NULL, NULL, 0, 4664 DLADM_OPT_ACTIVE); 4665 if (status != DLADM_STATUS_OK) { 4666 warn_dlerr(status, "cannot reset link property " 4667 "on '%s'", argv[optind]); 4668 } 4669 if (!temp) { 4670 dladm_status_t s; 4671 4672 s = set_linkprop_persist(linkid, NULL, NULL, 0, reset); 4673 if (s != DLADM_STATUS_OK) 4674 status = s; 4675 } 4676 goto done; 4677 } 4678 4679 for (i = 0; i < proplist->pl_count; i++) { 4680 prop_info_t *pip = &proplist->pl_info[i]; 4681 char **val; 4682 uint_t count; 4683 dladm_status_t s; 4684 4685 if (reset) { 4686 val = NULL; 4687 count = 0; 4688 } else { 4689 val = pip->pi_val; 4690 count = pip->pi_count; 4691 if (count == 0) { 4692 warn("no value specified for '%s'", 4693 pip->pi_name); 4694 status = DLADM_STATUS_BADARG; 4695 continue; 4696 } 4697 } 4698 s = dladm_set_linkprop(linkid, pip->pi_name, val, count, 4699 DLADM_OPT_ACTIVE); 4700 if (s == DLADM_STATUS_OK) { 4701 if (!temp) { 4702 s = set_linkprop_persist(linkid, 4703 pip->pi_name, val, count, reset); 4704 if (s != DLADM_STATUS_OK) 4705 status = s; 4706 } 4707 continue; 4708 } 4709 status = s; 4710 switch (s) { 4711 case DLADM_STATUS_NOTFOUND: 4712 warn("invalid link property '%s'", pip->pi_name); 4713 break; 4714 case DLADM_STATUS_BADVAL: { 4715 int j; 4716 char *ptr, *lim; 4717 char **propvals = NULL; 4718 uint_t valcnt = DLADM_MAX_PROP_VALCNT; 4719 4720 ptr = malloc((sizeof (char *) + 4721 DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT + 4722 MAX_PROP_LINE); 4723 4724 propvals = (char **)(void *)ptr; 4725 if (propvals == NULL) 4726 die("insufficient memory"); 4727 4728 for (j = 0; j < DLADM_MAX_PROP_VALCNT; j++) { 4729 propvals[j] = ptr + sizeof (char *) * 4730 DLADM_MAX_PROP_VALCNT + 4731 j * DLADM_PROP_VAL_MAX; 4732 } 4733 s = dladm_get_linkprop(linkid, 4734 DLADM_PROP_VAL_MODIFIABLE, pip->pi_name, propvals, 4735 &valcnt); 4736 4737 if (s != DLADM_STATUS_OK) { 4738 warn_dlerr(status, "cannot set link property " 4739 "'%s' on '%s'", pip->pi_name, argv[optind]); 4740 free(propvals); 4741 break; 4742 } 4743 4744 ptr = errmsg; 4745 lim = ptr + DLADM_STRSIZE; 4746 *ptr = '\0'; 4747 for (j = 0; j < valcnt; j++) { 4748 ptr += snprintf(ptr, lim - ptr, "%s,", 4749 propvals[j]); 4750 if (ptr >= lim) 4751 break; 4752 } 4753 if (ptr > errmsg) { 4754 *(ptr - 1) = '\0'; 4755 warn("link property '%s' must be one of: %s", 4756 pip->pi_name, errmsg); 4757 } else 4758 warn("invalid link property '%s'", *val); 4759 free(propvals); 4760 break; 4761 } 4762 default: 4763 if (reset) { 4764 warn_dlerr(status, "cannot reset link property " 4765 "'%s' on '%s'", pip->pi_name, argv[optind]); 4766 } else { 4767 warn_dlerr(status, "cannot set link property " 4768 "'%s' on '%s'", pip->pi_name, argv[optind]); 4769 } 4770 break; 4771 } 4772 } 4773 done: 4774 free_props(proplist); 4775 if (status != DLADM_STATUS_OK) 4776 exit(1); 4777 } 4778 4779 static void 4780 do_set_linkprop(int argc, char **argv) 4781 { 4782 set_linkprop(argc, argv, B_FALSE); 4783 } 4784 4785 static void 4786 do_reset_linkprop(int argc, char **argv) 4787 { 4788 set_linkprop(argc, argv, B_TRUE); 4789 } 4790 4791 static int 4792 convert_secobj(char *buf, uint_t len, uint8_t *obj_val, uint_t *obj_lenp, 4793 dladm_secobj_class_t class) 4794 { 4795 int error = 0; 4796 4797 if (class == DLADM_SECOBJ_CLASS_WPA) { 4798 if (len < 8 || len > 63) 4799 return (EINVAL); 4800 (void) memcpy(obj_val, buf, len); 4801 *obj_lenp = len; 4802 return (error); 4803 } 4804 4805 if (class == DLADM_SECOBJ_CLASS_WEP) { 4806 switch (len) { 4807 case 5: /* ASCII key sizes */ 4808 case 13: 4809 (void) memcpy(obj_val, buf, len); 4810 *obj_lenp = len; 4811 break; 4812 case 10: /* Hex key sizes, not preceded by 0x */ 4813 case 26: 4814 error = hexascii_to_octet(buf, len, obj_val, obj_lenp); 4815 break; 4816 case 12: /* Hex key sizes, preceded by 0x */ 4817 case 28: 4818 if (strncmp(buf, "0x", 2) != 0) 4819 return (EINVAL); 4820 error = hexascii_to_octet(buf + 2, len - 2, 4821 obj_val, obj_lenp); 4822 break; 4823 default: 4824 return (EINVAL); 4825 } 4826 return (error); 4827 } 4828 4829 return (ENOENT); 4830 } 4831 4832 /* ARGSUSED */ 4833 static void 4834 defersig(int sig) 4835 { 4836 signalled = sig; 4837 } 4838 4839 static int 4840 get_secobj_from_tty(uint_t try, const char *objname, char *buf) 4841 { 4842 uint_t len = 0; 4843 int c; 4844 struct termios stored, current; 4845 void (*sigfunc)(int); 4846 4847 /* 4848 * Turn off echo -- but before we do so, defer SIGINT handling 4849 * so that a ^C doesn't leave the terminal corrupted. 4850 */ 4851 sigfunc = signal(SIGINT, defersig); 4852 (void) fflush(stdin); 4853 (void) tcgetattr(0, &stored); 4854 current = stored; 4855 current.c_lflag &= ~(ICANON|ECHO); 4856 current.c_cc[VTIME] = 0; 4857 current.c_cc[VMIN] = 1; 4858 (void) tcsetattr(0, TCSANOW, ¤t); 4859 again: 4860 if (try == 1) 4861 (void) printf(gettext("provide value for '%s': "), objname); 4862 else 4863 (void) printf(gettext("confirm value for '%s': "), objname); 4864 4865 (void) fflush(stdout); 4866 while (signalled == 0) { 4867 c = getchar(); 4868 if (c == '\n' || c == '\r') { 4869 if (len != 0) 4870 break; 4871 (void) putchar('\n'); 4872 goto again; 4873 } 4874 4875 buf[len++] = c; 4876 if (len >= DLADM_SECOBJ_VAL_MAX - 1) 4877 break; 4878 (void) putchar('*'); 4879 } 4880 4881 (void) putchar('\n'); 4882 (void) fflush(stdin); 4883 4884 /* 4885 * Restore terminal setting and handle deferred signals. 4886 */ 4887 (void) tcsetattr(0, TCSANOW, &stored); 4888 4889 (void) signal(SIGINT, sigfunc); 4890 if (signalled != 0) 4891 (void) kill(getpid(), signalled); 4892 4893 return (len); 4894 } 4895 4896 static int 4897 get_secobj_val(char *obj_name, uint8_t *obj_val, uint_t *obj_lenp, 4898 dladm_secobj_class_t class, FILE *filep) 4899 { 4900 int rval; 4901 uint_t len, len2; 4902 char buf[DLADM_SECOBJ_VAL_MAX], buf2[DLADM_SECOBJ_VAL_MAX]; 4903 4904 if (filep == NULL) { 4905 len = get_secobj_from_tty(1, obj_name, buf); 4906 rval = convert_secobj(buf, len, obj_val, obj_lenp, class); 4907 if (rval == 0) { 4908 len2 = get_secobj_from_tty(2, obj_name, buf2); 4909 if (len != len2 || memcmp(buf, buf2, len) != 0) 4910 rval = ENOTSUP; 4911 } 4912 return (rval); 4913 } else { 4914 for (;;) { 4915 if (fgets(buf, sizeof (buf), filep) == NULL) 4916 break; 4917 if (isspace(buf[0])) 4918 continue; 4919 4920 len = strlen(buf); 4921 if (buf[len - 1] == '\n') { 4922 buf[len - 1] = '\0'; 4923 len--; 4924 } 4925 break; 4926 } 4927 (void) fclose(filep); 4928 } 4929 return (convert_secobj(buf, len, obj_val, obj_lenp, class)); 4930 } 4931 4932 static boolean_t 4933 check_auth(const char *auth) 4934 { 4935 struct passwd *pw; 4936 4937 if ((pw = getpwuid(getuid())) == NULL) 4938 return (B_FALSE); 4939 4940 return (chkauthattr(auth, pw->pw_name) != 0); 4941 } 4942 4943 static void 4944 audit_secobj(char *auth, char *class, char *obj, 4945 boolean_t success, boolean_t create) 4946 { 4947 adt_session_data_t *ah; 4948 adt_event_data_t *event; 4949 au_event_t flag; 4950 char *errstr; 4951 4952 if (create) { 4953 flag = ADT_dladm_create_secobj; 4954 errstr = "ADT_dladm_create_secobj"; 4955 } else { 4956 flag = ADT_dladm_delete_secobj; 4957 errstr = "ADT_dladm_delete_secobj"; 4958 } 4959 4960 if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) 4961 die("adt_start_session: %s", strerror(errno)); 4962 4963 if ((event = adt_alloc_event(ah, flag)) == NULL) 4964 die("adt_alloc_event (%s): %s", errstr, strerror(errno)); 4965 4966 /* fill in audit info */ 4967 if (create) { 4968 event->adt_dladm_create_secobj.auth_used = auth; 4969 event->adt_dladm_create_secobj.obj_class = class; 4970 event->adt_dladm_create_secobj.obj_name = obj; 4971 } else { 4972 event->adt_dladm_delete_secobj.auth_used = auth; 4973 event->adt_dladm_delete_secobj.obj_class = class; 4974 event->adt_dladm_delete_secobj.obj_name = obj; 4975 } 4976 4977 if (success) { 4978 if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) { 4979 die("adt_put_event (%s, success): %s", errstr, 4980 strerror(errno)); 4981 } 4982 } else { 4983 if (adt_put_event(event, ADT_FAILURE, 4984 ADT_FAIL_VALUE_AUTH) != 0) { 4985 die("adt_put_event: (%s, failure): %s", errstr, 4986 strerror(errno)); 4987 } 4988 } 4989 4990 adt_free_event(event); 4991 (void) adt_end_session(ah); 4992 } 4993 4994 #define MAX_SECOBJS 32 4995 #define MAX_SECOBJ_NAMELEN 32 4996 static void 4997 do_create_secobj(int argc, char **argv) 4998 { 4999 int option, rval; 5000 FILE *filep = NULL; 5001 char *obj_name = NULL; 5002 char *class_name = NULL; 5003 uint8_t obj_val[DLADM_SECOBJ_VAL_MAX]; 5004 uint_t obj_len; 5005 boolean_t success, temp = B_FALSE; 5006 dladm_status_t status; 5007 dladm_secobj_class_t class = -1; 5008 uid_t euid; 5009 5010 opterr = 0; 5011 (void) memset(obj_val, 0, DLADM_SECOBJ_VAL_MAX); 5012 while ((option = getopt_long(argc, argv, ":f:c:R:t", 5013 wifi_longopts, NULL)) != -1) { 5014 switch (option) { 5015 case 'f': 5016 euid = geteuid(); 5017 (void) seteuid(getuid()); 5018 filep = fopen(optarg, "r"); 5019 if (filep == NULL) { 5020 die("cannot open %s: %s", optarg, 5021 strerror(errno)); 5022 } 5023 (void) seteuid(euid); 5024 break; 5025 case 'c': 5026 class_name = optarg; 5027 status = dladm_str2secobjclass(optarg, &class); 5028 if (status != DLADM_STATUS_OK) { 5029 die("invalid secure object class '%s', " 5030 "valid values are: wep, wpa", optarg); 5031 } 5032 break; 5033 case 't': 5034 temp = B_TRUE; 5035 break; 5036 case 'R': 5037 status = dladm_set_rootdir(optarg); 5038 if (status != DLADM_STATUS_OK) { 5039 die_dlerr(status, "invalid directory " 5040 "specified"); 5041 } 5042 break; 5043 default: 5044 die_opterr(optopt, option); 5045 break; 5046 } 5047 } 5048 5049 if (optind == (argc - 1)) 5050 obj_name = argv[optind]; 5051 else if (optind != argc) 5052 usage(); 5053 5054 if (class == -1) 5055 die("secure object class required"); 5056 5057 if (obj_name == NULL) 5058 die("secure object name required"); 5059 5060 success = check_auth(LINK_SEC_AUTH); 5061 audit_secobj(LINK_SEC_AUTH, class_name, obj_name, success, B_TRUE); 5062 if (!success) 5063 die("authorization '%s' is required", LINK_SEC_AUTH); 5064 5065 rval = get_secobj_val(obj_name, obj_val, &obj_len, class, filep); 5066 if (rval != 0) { 5067 switch (rval) { 5068 case ENOENT: 5069 die("invalid secure object class"); 5070 break; 5071 case EINVAL: 5072 die("invalid secure object value"); 5073 break; 5074 case ENOTSUP: 5075 die("verification failed"); 5076 break; 5077 default: 5078 die("invalid secure object: %s", strerror(rval)); 5079 break; 5080 } 5081 } 5082 5083 status = dladm_set_secobj(obj_name, class, obj_val, obj_len, 5084 DLADM_OPT_CREATE | DLADM_OPT_ACTIVE); 5085 if (status != DLADM_STATUS_OK) { 5086 die_dlerr(status, "could not create secure object '%s'", 5087 obj_name); 5088 } 5089 if (temp) 5090 return; 5091 5092 status = dladm_set_secobj(obj_name, class, obj_val, obj_len, 5093 DLADM_OPT_PERSIST); 5094 if (status != DLADM_STATUS_OK) { 5095 warn_dlerr(status, "could not persistently create secure " 5096 "object '%s'", obj_name); 5097 } 5098 } 5099 5100 static void 5101 do_delete_secobj(int argc, char **argv) 5102 { 5103 int i, option; 5104 boolean_t temp = B_FALSE; 5105 split_t *sp = NULL; 5106 boolean_t success; 5107 dladm_status_t status, pstatus; 5108 5109 opterr = 0; 5110 status = pstatus = DLADM_STATUS_OK; 5111 while ((option = getopt_long(argc, argv, ":R:t", 5112 wifi_longopts, NULL)) != -1) { 5113 switch (option) { 5114 case 't': 5115 temp = B_TRUE; 5116 break; 5117 case 'R': 5118 status = dladm_set_rootdir(optarg); 5119 if (status != DLADM_STATUS_OK) { 5120 die_dlerr(status, "invalid directory " 5121 "specified"); 5122 } 5123 break; 5124 default: 5125 die_opterr(optopt, option); 5126 break; 5127 } 5128 } 5129 5130 if (optind == (argc - 1)) { 5131 sp = split(argv[optind], MAX_SECOBJS, MAX_SECOBJ_NAMELEN); 5132 if (sp == NULL) { 5133 die("invalid secure object name(s): '%s'", 5134 argv[optind]); 5135 } 5136 } else if (optind != argc) 5137 usage(); 5138 5139 if (sp == NULL || sp->s_nfields < 1) 5140 die("secure object name required"); 5141 5142 success = check_auth(LINK_SEC_AUTH); 5143 audit_secobj(LINK_SEC_AUTH, "unknown", argv[optind], success, B_FALSE); 5144 if (!success) 5145 die("authorization '%s' is required", LINK_SEC_AUTH); 5146 5147 for (i = 0; i < sp->s_nfields; i++) { 5148 status = dladm_unset_secobj(sp->s_fields[i], DLADM_OPT_ACTIVE); 5149 if (!temp) { 5150 pstatus = dladm_unset_secobj(sp->s_fields[i], 5151 DLADM_OPT_PERSIST); 5152 } else { 5153 pstatus = DLADM_STATUS_OK; 5154 } 5155 5156 if (status != DLADM_STATUS_OK) { 5157 warn_dlerr(status, "could not delete secure object " 5158 "'%s'", sp->s_fields[i]); 5159 } 5160 if (pstatus != DLADM_STATUS_OK) { 5161 warn_dlerr(pstatus, "could not persistently delete " 5162 "secure object '%s'", sp->s_fields[i]); 5163 } 5164 } 5165 if (status != DLADM_STATUS_OK || pstatus != DLADM_STATUS_OK) 5166 exit(1); 5167 } 5168 5169 typedef struct show_secobj_state { 5170 boolean_t ss_persist; 5171 boolean_t ss_parseable; 5172 boolean_t ss_header; 5173 print_state_t ss_print; 5174 } show_secobj_state_t; 5175 5176 5177 static boolean_t 5178 show_secobj(void *arg, const char *obj_name) 5179 { 5180 uint_t obj_len = DLADM_SECOBJ_VAL_MAX; 5181 uint8_t obj_val[DLADM_SECOBJ_VAL_MAX]; 5182 char buf[DLADM_STRSIZE]; 5183 uint_t flags = 0; 5184 dladm_secobj_class_t class; 5185 show_secobj_state_t *statep = arg; 5186 dladm_status_t status; 5187 secobj_fields_buf_t sbuf; 5188 5189 if (statep->ss_persist) 5190 flags |= DLADM_OPT_PERSIST; 5191 5192 status = dladm_get_secobj(obj_name, &class, obj_val, &obj_len, flags); 5193 if (status != DLADM_STATUS_OK) 5194 die_dlerr(status, "cannot get secure object '%s'", obj_name); 5195 5196 if (statep->ss_header) { 5197 statep->ss_header = B_FALSE; 5198 if (!statep->ss_parseable) 5199 print_header(&statep->ss_print); 5200 } 5201 5202 (void) snprintf(sbuf.ss_obj_name, sizeof (sbuf.ss_obj_name), 5203 obj_name); 5204 (void) dladm_secobjclass2str(class, buf); 5205 (void) snprintf(sbuf.ss_class, sizeof (sbuf.ss_class), "%s", buf); 5206 if (getuid() == 0) { 5207 char val[DLADM_SECOBJ_VAL_MAX * 2]; 5208 uint_t len = sizeof (val); 5209 5210 if (octet_to_hexascii(obj_val, obj_len, val, &len) == 0) 5211 (void) snprintf(sbuf.ss_val, 5212 sizeof (sbuf.ss_val), "%s", val); 5213 } 5214 dladm_print_output(&statep->ss_print, statep->ss_parseable, 5215 dladm_print_field, (void *)&sbuf); 5216 return (B_TRUE); 5217 } 5218 5219 static void 5220 do_show_secobj(int argc, char **argv) 5221 { 5222 int option; 5223 show_secobj_state_t state; 5224 dladm_status_t status; 5225 uint_t i; 5226 split_t *sp; 5227 uint_t flags; 5228 char *fields_str = NULL; 5229 print_field_t **fields; 5230 uint_t nfields; 5231 char *def_fields = "object,class"; 5232 char *all_fields = "object,class,value"; 5233 5234 opterr = 0; 5235 bzero(&state, sizeof (state)); 5236 state.ss_parseable = B_FALSE; 5237 fields_str = def_fields; 5238 state.ss_persist = B_FALSE; 5239 state.ss_parseable = B_FALSE; 5240 state.ss_header = B_TRUE; 5241 while ((option = getopt_long(argc, argv, ":pPo:", 5242 wifi_longopts, NULL)) != -1) { 5243 switch (option) { 5244 case 'p': 5245 state.ss_parseable = B_TRUE; 5246 break; 5247 case 'P': 5248 state.ss_persist = B_TRUE; 5249 break; 5250 case 'o': 5251 if (strcasecmp(optarg, "all") == 0) 5252 fields_str = all_fields; 5253 else 5254 fields_str = optarg; 5255 break; 5256 default: 5257 die_opterr(optopt, option); 5258 break; 5259 } 5260 } 5261 5262 fields = parse_output_fields(fields_str, secobj_fields, 5263 DEV_SOBJ_FIELDS, CMD_TYPE_ANY, &nfields); 5264 5265 if (fields == NULL) { 5266 die("invalid field(s) specified"); 5267 return; 5268 } 5269 state.ss_print.ps_fields = fields; 5270 state.ss_print.ps_nfields = nfields; 5271 5272 flags = state.ss_persist ? DLADM_OPT_PERSIST : 0; 5273 if (optind == (argc - 1)) { 5274 sp = split(argv[optind], MAX_SECOBJS, MAX_SECOBJ_NAMELEN); 5275 if (sp == NULL) { 5276 die("invalid secure object name(s): '%s'", 5277 argv[optind]); 5278 } 5279 for (i = 0; i < sp->s_nfields; i++) { 5280 if (!show_secobj(&state, sp->s_fields[i])) 5281 break; 5282 } 5283 splitfree(sp); 5284 return; 5285 } else if (optind != argc) 5286 usage(); 5287 5288 status = dladm_walk_secobj(&state, show_secobj, flags); 5289 if (status != DLADM_STATUS_OK) 5290 die_dlerr(status, "show-secobj"); 5291 } 5292 5293 /*ARGSUSED*/ 5294 static int 5295 i_dladm_init_linkprop(datalink_id_t linkid, void *arg) 5296 { 5297 (void) dladm_init_linkprop(linkid); 5298 return (DLADM_WALK_CONTINUE); 5299 } 5300 5301 /* ARGSUSED */ 5302 static void 5303 do_init_linkprop(int argc, char **argv) 5304 { 5305 /* 5306 * linkprops of links of other classes have been initialized as a 5307 * part of the dladm up-xxx operation. 5308 */ 5309 (void) dladm_walk_datalink_id(i_dladm_init_linkprop, NULL, 5310 DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 5311 } 5312 5313 /* ARGSUSED */ 5314 static void 5315 do_show_ether(int argc, char **argv) 5316 { 5317 int option; 5318 datalink_id_t linkid; 5319 print_ether_state_t state; 5320 print_field_t **fields; 5321 char *fields_str; 5322 uint_t nfields; 5323 char *all_fields = 5324 "link,ptype,state,auto,speed-duplex,pause,rem_fault"; 5325 char *default_fields = 5326 "link,ptype,state,auto,speed-duplex,pause"; 5327 5328 fields_str = default_fields; 5329 bzero(&state, sizeof (state)); 5330 state.es_link = NULL; 5331 state.es_parseable = B_FALSE; 5332 5333 while ((option = getopt_long(argc, argv, "o:px", 5334 showeth_lopts, NULL)) != -1) { 5335 switch (option) { 5336 case 'x': 5337 state.es_extended = B_TRUE; 5338 break; 5339 case 'p': 5340 state.es_parseable = B_TRUE; 5341 break; 5342 case 'o': 5343 if (strcasecmp(optarg, "all") == 0) 5344 fields_str = all_fields; 5345 else 5346 fields_str = optarg; 5347 break; 5348 default: 5349 die_opterr(optopt, option); 5350 break; 5351 } 5352 } 5353 5354 if (optind == (argc - 1)) 5355 state.es_link = argv[optind]; 5356 5357 fields = parse_output_fields(fields_str, ether_fields, 5358 ETHER_MAX_FIELDS, CMD_TYPE_ANY, &nfields); 5359 5360 if (fields == NULL) { 5361 die("invalid field(s) specified"); 5362 exit(EXIT_FAILURE); 5363 } 5364 state.es_print.ps_fields = fields; 5365 state.es_print.ps_nfields = nfields; 5366 5367 if (state.es_link == NULL) { 5368 (void) dladm_walk_datalink_id(show_etherprop, &state, 5369 DATALINK_CLASS_PHYS, DL_ETHER, 5370 DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST); 5371 } else { 5372 if (!link_is_ether(state.es_link, &linkid)) { 5373 die("invalid link specified"); 5374 } 5375 (void) show_etherprop(linkid, &state); 5376 } 5377 5378 exit(DLADM_STATUS_OK); 5379 5380 } 5381 5382 static char * 5383 dladm_print_field(print_field_t *pf, void *arg) 5384 { 5385 char *value; 5386 5387 value = (char *)arg + pf->pf_offset; 5388 return (value); 5389 } 5390 5391 static int 5392 show_etherprop(datalink_id_t linkid, void *arg) 5393 { 5394 print_ether_state_t *statep = arg; 5395 char buf[DLADM_STRSIZE]; 5396 int speed; 5397 uint64_t s; 5398 uint32_t autoneg, pause, asmpause, adv_rf, cap_rf, lp_rf; 5399 ether_fields_buf_t ebuf; 5400 char speed_unit = 'M'; 5401 5402 if (dladm_datalink_id2info(linkid, NULL, NULL, NULL, 5403 ebuf.eth_link, sizeof (ebuf.eth_link)) != DLADM_STATUS_OK) { 5404 return (DLADM_WALK_CONTINUE); 5405 } 5406 5407 if (!statep->es_header && !statep->es_parseable) { 5408 print_header(&statep->es_print); 5409 statep->es_header = B_TRUE; 5410 } 5411 (void) snprintf(ebuf.eth_ptype, sizeof (ebuf.eth_ptype), 5412 "%s", "current"); 5413 5414 (void) dladm_get_single_mac_stat(linkid, "link_autoneg", 5415 KSTAT_DATA_UINT32, &autoneg); 5416 (void) snprintf(ebuf.eth_autoneg, sizeof (ebuf.eth_autoneg), 5417 "%s", (autoneg ? "yes" : "no")); 5418 5419 (void) dladm_get_single_mac_stat(linkid, "link_pause", 5420 KSTAT_DATA_UINT32, &pause); 5421 (void) dladm_get_single_mac_stat(linkid, "link_asmpause", 5422 KSTAT_DATA_UINT32, &asmpause); 5423 (void) snprintf(ebuf.eth_pause, sizeof (ebuf.eth_pause), 5424 "%s", pause_str(pause, asmpause)); 5425 5426 (void) dladm_get_single_mac_stat(linkid, "ifspeed", 5427 KSTAT_DATA_UINT64, &s); 5428 speed = (int)(s/1000000ull); 5429 5430 if (speed >= 1000) { 5431 speed = speed/1000; 5432 speed_unit = 'G'; 5433 } 5434 (void) get_linkduplex(ebuf.eth_link, B_TRUE, buf); 5435 (void) snprintf(ebuf.eth_spdx, sizeof (ebuf.eth_spdx), "%d%c-%c", 5436 speed, speed_unit, buf[0]); 5437 5438 (void) get_linkstate(ebuf.eth_link, B_TRUE, buf); 5439 (void) snprintf(ebuf.eth_state, sizeof (ebuf.eth_state), 5440 "%s", buf); 5441 5442 (void) dladm_get_single_mac_stat(linkid, "adv_rem_fault", 5443 KSTAT_DATA_UINT32, &adv_rf); 5444 (void) dladm_get_single_mac_stat(linkid, "cap_rem_fault", 5445 KSTAT_DATA_UINT32, &cap_rf); 5446 (void) dladm_get_single_mac_stat(linkid, "lp_rem_fault", 5447 KSTAT_DATA_UINT32, &lp_rf); 5448 (void) snprintf(ebuf.eth_rem_fault, sizeof (ebuf.eth_rem_fault), 5449 "%s", (adv_rf == 0 && lp_rf == 0 ? "none" : "fault")); 5450 5451 dladm_print_output(&statep->es_print, statep->es_parseable, 5452 dladm_print_field, &ebuf); 5453 5454 if (statep->es_extended) 5455 show_ether_xprop(linkid, arg); 5456 5457 return (DLADM_WALK_CONTINUE); 5458 } 5459 5460 /* ARGSUSED */ 5461 static void 5462 do_init_secobj(int argc, char **argv) 5463 { 5464 dladm_status_t status; 5465 5466 status = dladm_init_secobj(); 5467 if (status != DLADM_STATUS_OK) 5468 die_dlerr(status, "secure object initialization failed"); 5469 } 5470 5471 /* 5472 * "-R" option support. It is used for live upgrading. Append dladm commands 5473 * to a upgrade script which will be run when the alternative root boots up: 5474 * 5475 * - If the /etc/dladm/datalink.conf file exists on the alternative root, 5476 * append dladm commands to the <altroot>/var/svc/profile/upgrade_datalink 5477 * script. This script will be run as part of the network/physical service. 5478 * We cannot defer this to /var/svc/profile/upgrade because then the 5479 * configuration will not be able to take effect before network/physical 5480 * plumbs various interfaces. 5481 * 5482 * - If the /etc/dladm/datalink.conf file does not exist on the alternative 5483 * root, append dladm commands to the <altroot>/var/svc/profile/upgrade script, 5484 * which will be run in the manifest-import service. 5485 * 5486 * Note that the SMF team is considering to move the manifest-import service 5487 * to be run at the very begining of boot. Once that is done, the need for 5488 * the /var/svc/profile/upgrade_datalink script will not exist any more. 5489 */ 5490 static void 5491 altroot_cmd(char *altroot, int argc, char *argv[]) 5492 { 5493 char path[MAXPATHLEN]; 5494 struct stat stbuf; 5495 FILE *fp; 5496 int i; 5497 5498 /* 5499 * Check for the existence of the /etc/dladm/datalink.conf 5500 * configuration file, and determine the name of script file. 5501 */ 5502 (void) snprintf(path, MAXPATHLEN, "/%s/etc/dladm/datalink.conf", 5503 altroot); 5504 if (stat(path, &stbuf) < 0) { 5505 (void) snprintf(path, MAXPATHLEN, "/%s/%s", altroot, 5506 SMF_UPGRADE_FILE); 5507 } else { 5508 (void) snprintf(path, MAXPATHLEN, "/%s/%s", altroot, 5509 SMF_UPGRADEDATALINK_FILE); 5510 } 5511 5512 if ((fp = fopen(path, "a+")) == NULL) 5513 die("operation not supported on %s", altroot); 5514 5515 (void) fprintf(fp, "/sbin/dladm "); 5516 for (i = 0; i < argc; i++) { 5517 /* 5518 * Directly write to the file if it is not the "-R <altroot>" 5519 * option. In which case, skip it. 5520 */ 5521 if (strcmp(argv[i], "-R") != 0) 5522 (void) fprintf(fp, "%s ", argv[i]); 5523 else 5524 i ++; 5525 } 5526 (void) fprintf(fp, "%s\n", SMF_DLADM_UPGRADE_MSG); 5527 (void) fclose(fp); 5528 exit(0); 5529 } 5530 5531 /* 5532 * Convert the string to an integer. Note that the string must not have any 5533 * trailing non-integer characters. 5534 */ 5535 static boolean_t 5536 str2int(const char *str, int *valp) 5537 { 5538 int val; 5539 char *endp = NULL; 5540 5541 errno = 0; 5542 val = strtol(str, &endp, 10); 5543 if (errno != 0 || *endp != '\0') 5544 return (B_FALSE); 5545 5546 *valp = val; 5547 return (B_TRUE); 5548 } 5549 5550 /* PRINTFLIKE1 */ 5551 static void 5552 warn(const char *format, ...) 5553 { 5554 va_list alist; 5555 5556 format = gettext(format); 5557 (void) fprintf(stderr, "%s: warning: ", progname); 5558 5559 va_start(alist, format); 5560 (void) vfprintf(stderr, format, alist); 5561 va_end(alist); 5562 5563 (void) putchar('\n'); 5564 } 5565 5566 /* PRINTFLIKE2 */ 5567 static void 5568 warn_dlerr(dladm_status_t err, const char *format, ...) 5569 { 5570 va_list alist; 5571 char errmsg[DLADM_STRSIZE]; 5572 5573 format = gettext(format); 5574 (void) fprintf(stderr, gettext("%s: warning: "), progname); 5575 5576 va_start(alist, format); 5577 (void) vfprintf(stderr, format, alist); 5578 va_end(alist); 5579 (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg)); 5580 } 5581 5582 /* PRINTFLIKE2 */ 5583 static void 5584 die_dlerr(dladm_status_t err, const char *format, ...) 5585 { 5586 va_list alist; 5587 char errmsg[DLADM_STRSIZE]; 5588 5589 format = gettext(format); 5590 (void) fprintf(stderr, "%s: ", progname); 5591 5592 va_start(alist, format); 5593 (void) vfprintf(stderr, format, alist); 5594 va_end(alist); 5595 (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg)); 5596 5597 exit(EXIT_FAILURE); 5598 } 5599 5600 /* PRINTFLIKE1 */ 5601 static void 5602 die(const char *format, ...) 5603 { 5604 va_list alist; 5605 5606 format = gettext(format); 5607 (void) fprintf(stderr, "%s: ", progname); 5608 5609 va_start(alist, format); 5610 (void) vfprintf(stderr, format, alist); 5611 va_end(alist); 5612 5613 (void) putchar('\n'); 5614 exit(EXIT_FAILURE); 5615 } 5616 5617 static void 5618 die_optdup(int opt) 5619 { 5620 die("the option -%c cannot be specified more than once", opt); 5621 } 5622 5623 static void 5624 die_opterr(int opt, int opterr) 5625 { 5626 switch (opterr) { 5627 case ':': 5628 die("option '-%c' requires a value", opt); 5629 break; 5630 case '?': 5631 default: 5632 die("unrecognized option '-%c'", opt); 5633 break; 5634 } 5635 } 5636 5637 static void 5638 show_ether_xprop(datalink_id_t linkid, void *arg) 5639 { 5640 print_ether_state_t *statep = arg; 5641 char buf[DLADM_STRSIZE]; 5642 uint32_t autoneg, pause, asmpause, adv_rf, cap_rf, lp_rf; 5643 boolean_t add_comma, r1; 5644 ether_fields_buf_t ebuf; 5645 5646 /* capable */ 5647 bzero(&ebuf, sizeof (ebuf)); 5648 (void) snprintf(ebuf.eth_link, sizeof (ebuf.eth_link), ""); 5649 5650 (void) snprintf(ebuf.eth_ptype, sizeof (ebuf.eth_ptype), 5651 "%s", "capable"); 5652 (void) snprintf(ebuf.eth_state, sizeof (ebuf.eth_state), 5653 STR_UNDEF_VAL); 5654 5655 (void) dladm_get_single_mac_stat(linkid, "cap_autoneg", 5656 KSTAT_DATA_UINT32, &autoneg); 5657 (void) snprintf(ebuf.eth_autoneg, sizeof (ebuf.eth_autoneg), 5658 "%s", (autoneg ? "yes" : "no")); 5659 5660 add_comma = B_FALSE; 5661 bzero(buf, sizeof (buf)); 5662 r1 = get_speed_duplex(linkid, "cap_1000", buf, "1G", B_FALSE); 5663 if (r1) 5664 add_comma = B_TRUE; 5665 r1 = get_speed_duplex(linkid, "cap_100", buf, "100M", add_comma); 5666 if (r1) 5667 add_comma = B_TRUE; 5668 r1 = get_speed_duplex(linkid, "cap_10", buf, "10M", add_comma); 5669 add_comma = B_FALSE; 5670 (void) snprintf(ebuf.eth_spdx, sizeof (ebuf.eth_spdx), "%s", buf); 5671 5672 (void) dladm_get_single_mac_stat(linkid, "cap_pause", 5673 KSTAT_DATA_UINT32, &pause); 5674 (void) dladm_get_single_mac_stat(linkid, "cap_asmpause", 5675 KSTAT_DATA_UINT32, &asmpause); 5676 (void) snprintf(ebuf.eth_pause, sizeof (ebuf.eth_pause), 5677 "%s", pause_str(pause, asmpause)); 5678 5679 (void) dladm_get_single_mac_stat(linkid, "adv_rem_fault", 5680 KSTAT_DATA_UINT32, &adv_rf); 5681 (void) dladm_get_single_mac_stat(linkid, "cap_rem_fault", 5682 KSTAT_DATA_UINT32, &cap_rf); 5683 (void) dladm_get_single_mac_stat(linkid, "lp_rem_fault", 5684 KSTAT_DATA_UINT32, &lp_rf); 5685 5686 (void) snprintf(ebuf.eth_rem_fault, sizeof (ebuf.eth_rem_fault), 5687 "%s", (cap_rf ? "yes" : "no")); 5688 5689 dladm_print_output(&statep->es_print, statep->es_parseable, 5690 dladm_print_field, &ebuf); 5691 5692 /* advertised */ 5693 bzero(&ebuf, sizeof (ebuf)); 5694 (void) snprintf(ebuf.eth_ptype, sizeof (ebuf.eth_ptype), 5695 "%s", "adv"); 5696 (void) snprintf(ebuf.eth_state, sizeof (ebuf.eth_state), 5697 STR_UNDEF_VAL); 5698 5699 (void) dladm_get_single_mac_stat(linkid, "adv_cap_autoneg", 5700 KSTAT_DATA_UINT32, &autoneg); 5701 (void) snprintf(ebuf.eth_autoneg, sizeof (ebuf.eth_autoneg), 5702 "%s", (autoneg ? "yes" : "no")); 5703 5704 add_comma = B_FALSE; 5705 bzero(buf, sizeof (buf)); 5706 r1 = get_speed_duplex(linkid, "adv_cap_1000", buf, "1G", add_comma); 5707 if (r1) 5708 add_comma = B_TRUE; 5709 r1 = get_speed_duplex(linkid, "adv_cap_100", buf, "100M", add_comma); 5710 if (r1) 5711 add_comma = B_TRUE; 5712 r1 = get_speed_duplex(linkid, "adv_cap_10", buf, "10M", add_comma); 5713 add_comma = B_FALSE; 5714 (void) snprintf(ebuf.eth_spdx, sizeof (ebuf.eth_spdx), "%s", buf); 5715 5716 (void) dladm_get_single_mac_stat(linkid, "adv_cap_pause", 5717 KSTAT_DATA_UINT32, &pause); 5718 (void) dladm_get_single_mac_stat(linkid, "adv_cap_asmpause", 5719 KSTAT_DATA_UINT32, &asmpause); 5720 (void) snprintf(ebuf.eth_pause, sizeof (ebuf.eth_pause), 5721 "%s", pause_str(pause, asmpause)); 5722 5723 (void) snprintf(ebuf.eth_rem_fault, sizeof (ebuf.eth_rem_fault), 5724 "%s", (adv_rf ? "fault" : "none")); 5725 5726 dladm_print_output(&statep->es_print, statep->es_parseable, 5727 dladm_print_field, &ebuf); 5728 5729 /* peeradv */ 5730 bzero(&ebuf, sizeof (ebuf)); 5731 (void) snprintf(ebuf.eth_ptype, sizeof (ebuf.eth_ptype), 5732 "%s", "peeradv"); 5733 (void) snprintf(ebuf.eth_state, sizeof (ebuf.eth_state), 5734 STR_UNDEF_VAL); 5735 5736 (void) dladm_get_single_mac_stat(linkid, "lp_cap_autoneg", 5737 KSTAT_DATA_UINT32, &autoneg); 5738 (void) snprintf(ebuf.eth_autoneg, sizeof (ebuf.eth_autoneg), 5739 "%s", (autoneg ? "yes" : "no")); 5740 5741 add_comma = B_FALSE; 5742 bzero(buf, sizeof (buf)); 5743 r1 = get_speed_duplex(linkid, "lp_cap_1000", buf, "1G", add_comma); 5744 if (r1) 5745 add_comma = B_TRUE; 5746 r1 = get_speed_duplex(linkid, "lp_cap_100", buf, "100M", add_comma); 5747 if (r1) 5748 add_comma = B_TRUE; 5749 r1 = get_speed_duplex(linkid, "lp_cap_10", buf, "10M", add_comma); 5750 (void) snprintf(ebuf.eth_spdx, sizeof (ebuf.eth_spdx), "%s", buf); 5751 5752 (void) dladm_get_single_mac_stat(linkid, "lp_cap_pause", 5753 KSTAT_DATA_UINT32, &pause); 5754 (void) dladm_get_single_mac_stat(linkid, "lp_cap_asmpause", 5755 KSTAT_DATA_UINT32, &asmpause); 5756 (void) snprintf(ebuf.eth_pause, sizeof (ebuf.eth_pause), 5757 "%s", pause_str(pause, asmpause)); 5758 5759 (void) snprintf(ebuf.eth_rem_fault, sizeof (ebuf.eth_rem_fault), 5760 "%s", (lp_rf ? "fault" : "none")); 5761 5762 dladm_print_output(&statep->es_print, statep->es_parseable, 5763 dladm_print_field, &ebuf); 5764 } 5765 5766 static boolean_t 5767 get_speed_duplex(datalink_id_t linkid, const char *mii_prop_prefix, 5768 char *spbuf, char *sp, boolean_t add_comma) 5769 { 5770 int speed, duplex = 0; 5771 boolean_t ret = B_FALSE; 5772 char mii_prop[DLADM_STRSIZE]; 5773 5774 (void) snprintf(mii_prop, DLADM_STRSIZE, "%sfdx", mii_prop_prefix); 5775 (void) dladm_get_single_mac_stat(linkid, mii_prop, KSTAT_DATA_UINT32, 5776 &speed); 5777 if (speed) { 5778 ret = B_TRUE; 5779 duplex |= IS_FDX; 5780 } 5781 (void) snprintf(mii_prop, DLADM_STRSIZE, "%shdx", mii_prop_prefix); 5782 (void) dladm_get_single_mac_stat(linkid, mii_prop, 5783 KSTAT_DATA_UINT32, &speed); 5784 if (speed) { 5785 ret = B_TRUE; 5786 duplex |= IS_HDX; 5787 } 5788 if (ret) { 5789 if (add_comma) 5790 (void) strncat(spbuf, ",", DLADM_STRSIZE); 5791 (void) strncat(spbuf, sp, DLADM_STRSIZE); 5792 if ((duplex & (IS_FDX|IS_HDX)) == (IS_FDX|IS_HDX)) 5793 (void) strncat(spbuf, "-fh", DLADM_STRSIZE); 5794 else if (duplex & IS_FDX) 5795 (void) strncat(spbuf, "-f", DLADM_STRSIZE); 5796 else if (duplex & IS_HDX) 5797 (void) strncat(spbuf, "-h", DLADM_STRSIZE); 5798 } 5799 return (ret); 5800 } 5801 5802 static void 5803 dladm_print_output(print_state_t *statep, boolean_t parseable, 5804 print_callback_t fn, void *arg) 5805 { 5806 int i; 5807 char *value; 5808 print_field_t **pf; 5809 5810 pf = statep->ps_fields; 5811 for (i = 0; i < statep->ps_nfields; i++) { 5812 statep->ps_lastfield = (i + 1 == statep->ps_nfields); 5813 value = (*fn)(pf[i], arg); 5814 if (value != NULL) 5815 print_field(statep, pf[i], value, parseable); 5816 } 5817 (void) putchar('\n'); 5818 } 5819 5820 static void 5821 print_header(print_state_t *ps) 5822 { 5823 int i; 5824 print_field_t **pf; 5825 5826 pf = ps->ps_fields; 5827 for (i = 0; i < ps->ps_nfields; i++) { 5828 ps->ps_lastfield = (i + 1 == ps->ps_nfields); 5829 print_field(ps, pf[i], pf[i]->pf_header, B_FALSE); 5830 } 5831 (void) putchar('\n'); 5832 } 5833 5834 static char * 5835 pause_str(int pause, int asmpause) 5836 { 5837 if (pause == 1) 5838 return ("bi"); 5839 if (asmpause == 1) 5840 return ("tx"); 5841 return ("none"); 5842 } 5843 5844 static boolean_t 5845 link_is_ether(const char *link, datalink_id_t *linkid) 5846 { 5847 uint32_t media; 5848 datalink_class_t class; 5849 5850 if (dladm_name2info(link, linkid, NULL, &class, &media) == 5851 DLADM_STATUS_OK) { 5852 if (class == DATALINK_CLASS_PHYS && media == DL_ETHER) 5853 return (B_TRUE); 5854 } 5855 return (B_FALSE); 5856 } 5857