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