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_diffstats; /* -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_status_t *stat, status; 2592 pktsum_t *diff_stats; 2593 2594 stat = l->laggr_status; 2595 *stat = DLADM_STATUS_OK; 2596 2597 if (is_port) { 2598 portnum = l->laggr_lport; 2599 portp = &(l->laggr_ginfop->lg_ports[portnum]); 2600 2601 if ((status = dladm_datalink_id2info(handle, 2602 portp->lp_linkid, NULL, NULL, NULL, buf, bufsize)) != 2603 DLADM_STATUS_OK) { 2604 goto err; 2605 } 2606 diff_stats = l->laggr_diffstats; 2607 } 2608 2609 switch (ofarg->ofmt_id) { 2610 case AGGR_S_LINK: 2611 (void) snprintf(buf, bufsize, "%s", 2612 (is_port ? "" : l->laggr_link)); 2613 break; 2614 case AGGR_S_PORT: 2615 /* 2616 * if (is_port), buf has port name. Otherwise we print 2617 * STR_UNDEF_VAL 2618 */ 2619 break; 2620 2621 case AGGR_S_IPKTS: 2622 if (is_port) { 2623 (void) snprintf(buf, bufsize, "%llu", 2624 diff_stats->ipackets); 2625 } else { 2626 (void) snprintf(buf, bufsize, "%llu", 2627 l->laggr_pktsumtot->ipackets); 2628 } 2629 break; 2630 2631 case AGGR_S_RBYTES: 2632 if (is_port) { 2633 (void) snprintf(buf, bufsize, "%llu", 2634 diff_stats->rbytes); 2635 } else { 2636 (void) snprintf(buf, bufsize, "%llu", 2637 l->laggr_pktsumtot->rbytes); 2638 } 2639 break; 2640 2641 case AGGR_S_OPKTS: 2642 if (is_port) { 2643 (void) snprintf(buf, bufsize, "%llu", 2644 diff_stats->opackets); 2645 } else { 2646 (void) snprintf(buf, bufsize, "%llu", 2647 l->laggr_pktsumtot->opackets); 2648 } 2649 break; 2650 case AGGR_S_OBYTES: 2651 if (is_port) { 2652 (void) snprintf(buf, bufsize, "%llu", 2653 diff_stats->obytes); 2654 } else { 2655 (void) snprintf(buf, bufsize, "%llu", 2656 l->laggr_pktsumtot->obytes); 2657 } 2658 break; 2659 2660 case AGGR_S_IPKTDIST: 2661 if (is_port) { 2662 (void) snprintf(buf, bufsize, "%-6.1f", 2663 (double)diff_stats->ipackets/ 2664 (double)l->laggr_pktsumtot->ipackets * 100); 2665 } 2666 break; 2667 case AGGR_S_OPKTDIST: 2668 if (is_port) { 2669 (void) snprintf(buf, bufsize, "%-6.1f", 2670 (double)diff_stats->opackets/ 2671 (double)l->laggr_pktsumtot->opackets * 100); 2672 } 2673 break; 2674 } 2675 return (B_TRUE); 2676 2677 err: 2678 *stat = status; 2679 return (B_TRUE); 2680 } 2681 2682 static dladm_status_t 2683 print_aggr_stats(show_grp_state_t *state, const char *link, 2684 dladm_aggr_grp_attr_t *ginfop) 2685 { 2686 dladm_phys_attr_t dpa; 2687 dladm_aggr_port_attr_t *portp; 2688 pktsum_t pktsumtot, *port_stat; 2689 dladm_status_t status; 2690 int i; 2691 laggr_args_t largs; 2692 2693 /* sum the ports statistics */ 2694 bzero(&pktsumtot, sizeof (pktsumtot)); 2695 2696 /* Allocate memory to keep stats of each port */ 2697 port_stat = malloc(ginfop->lg_nports * sizeof (pktsum_t)); 2698 if (port_stat == NULL) { 2699 /* Bail out; no memory */ 2700 return (DLADM_STATUS_NOMEM); 2701 } 2702 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[i]); 2713 2714 /* 2715 * Let's re-use gs_prevstats[] to store the difference of the 2716 * counters since last use. We will store the new stats from 2717 * port_stat[] once we have the stats displayed. 2718 */ 2719 2720 dladm_stats_diff(&state->gs_prevstats[i], &port_stat[i], 2721 &state->gs_prevstats[i]); 2722 dladm_stats_total(&pktsumtot, &pktsumtot, 2723 &state->gs_prevstats[i]); 2724 } 2725 2726 largs.laggr_lport = -1; 2727 largs.laggr_link = link; 2728 largs.laggr_ginfop = ginfop; 2729 largs.laggr_status = &status; 2730 largs.laggr_pktsumtot = &pktsumtot; 2731 2732 ofmt_print(state->gs_ofmt, &largs); 2733 2734 if (status != DLADM_STATUS_OK) 2735 goto done; 2736 2737 for (i = 0; i < ginfop->lg_nports; i++) { 2738 largs.laggr_lport = i; 2739 largs.laggr_diffstats = &state->gs_prevstats[i]; 2740 ofmt_print(state->gs_ofmt, &largs); 2741 if (status != DLADM_STATUS_OK) 2742 goto done; 2743 } 2744 2745 status = DLADM_STATUS_OK; 2746 for (i = 0; i < ginfop->lg_nports; i++) 2747 state->gs_prevstats[i] = port_stat[i]; 2748 2749 done: 2750 free(port_stat); 2751 return (status); 2752 } 2753 2754 static dladm_status_t 2755 print_aggr(show_grp_state_t *state, datalink_id_t linkid) 2756 { 2757 char link[MAXLINKNAMELEN]; 2758 dladm_aggr_grp_attr_t ginfo; 2759 uint32_t flags; 2760 dladm_status_t status; 2761 2762 bzero(&ginfo, sizeof (dladm_aggr_grp_attr_t)); 2763 if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL, 2764 NULL, link, MAXLINKNAMELEN)) != DLADM_STATUS_OK) { 2765 return (status); 2766 } 2767 2768 if (!(state->gs_flags & flags)) 2769 return (DLADM_STATUS_NOTFOUND); 2770 2771 status = dladm_aggr_info(handle, linkid, &ginfo, state->gs_flags); 2772 if (status != DLADM_STATUS_OK) 2773 return (status); 2774 2775 if (state->gs_lacp) 2776 status = print_aggr_lacp(state, link, &ginfo); 2777 else if (state->gs_extended) 2778 status = print_aggr_extended(state, link, &ginfo); 2779 else if (state->gs_stats) 2780 status = print_aggr_stats(state, link, &ginfo); 2781 else 2782 status = print_aggr_info(state, link, &ginfo); 2783 2784 done: 2785 free(ginfo.lg_ports); 2786 return (status); 2787 } 2788 2789 /* ARGSUSED */ 2790 static int 2791 show_aggr(dladm_handle_t dh, datalink_id_t linkid, void *arg) 2792 { 2793 show_grp_state_t *state = arg; 2794 2795 state->gs_status = print_aggr(state, linkid); 2796 return (DLADM_WALK_CONTINUE); 2797 } 2798 2799 static void 2800 do_show_link(int argc, char *argv[], const char *use) 2801 { 2802 int option; 2803 boolean_t s_arg = B_FALSE; 2804 boolean_t S_arg = B_FALSE; 2805 boolean_t i_arg = B_FALSE; 2806 uint32_t flags = DLADM_OPT_ACTIVE; 2807 boolean_t p_arg = B_FALSE; 2808 datalink_id_t linkid = DATALINK_ALL_LINKID; 2809 char linkname[MAXLINKNAMELEN]; 2810 uint32_t interval = 0; 2811 show_state_t state; 2812 dladm_status_t status; 2813 boolean_t o_arg = B_FALSE; 2814 char *fields_str = NULL; 2815 char *all_active_fields = "link,class,mtu,state,over"; 2816 char *all_inactive_fields = "link,class,over"; 2817 char *allstat_fields = 2818 "link,ipackets,rbytes,ierrors,opackets,obytes,oerrors"; 2819 ofmt_handle_t ofmt; 2820 ofmt_status_t oferr; 2821 uint_t ofmtflags = 0; 2822 2823 bzero(&state, sizeof (state)); 2824 2825 opterr = 0; 2826 while ((option = getopt_long(argc, argv, ":pPsSi:o:", 2827 show_lopts, NULL)) != -1) { 2828 switch (option) { 2829 case 'p': 2830 if (p_arg) 2831 die_optdup(option); 2832 2833 p_arg = B_TRUE; 2834 break; 2835 case 's': 2836 if (s_arg) 2837 die_optdup(option); 2838 2839 s_arg = B_TRUE; 2840 break; 2841 case 'P': 2842 if (flags != DLADM_OPT_ACTIVE) 2843 die_optdup(option); 2844 2845 flags = DLADM_OPT_PERSIST; 2846 break; 2847 case 'S': 2848 if (S_arg) 2849 die_optdup(option); 2850 2851 S_arg = B_TRUE; 2852 break; 2853 case 'o': 2854 o_arg = B_TRUE; 2855 fields_str = optarg; 2856 break; 2857 case 'i': 2858 if (i_arg) 2859 die_optdup(option); 2860 2861 i_arg = B_TRUE; 2862 if (!dladm_str2interval(optarg, &interval)) 2863 die("invalid interval value '%s'", optarg); 2864 break; 2865 default: 2866 die_opterr(optopt, option, use); 2867 break; 2868 } 2869 } 2870 2871 if (i_arg && !(s_arg || S_arg)) 2872 die("the option -i can be used only with -s or -S"); 2873 2874 if (s_arg && S_arg) 2875 die("the -s option cannot be used with -S"); 2876 2877 if (s_arg && flags != DLADM_OPT_ACTIVE) 2878 die("the option -P cannot be used with -s"); 2879 2880 if (S_arg && (p_arg || flags != DLADM_OPT_ACTIVE)) 2881 die("the option -%c cannot be used with -S", p_arg ? 'p' : 'P'); 2882 2883 /* get link name (optional last argument) */ 2884 if (optind == (argc-1)) { 2885 uint32_t f; 2886 2887 if (strlcpy(linkname, argv[optind], MAXLINKNAMELEN) 2888 >= MAXLINKNAMELEN) { 2889 (void) fprintf(stderr, 2890 gettext("%s: link name too long\n"), 2891 progname); 2892 dladm_close(handle); 2893 exit(1); 2894 } 2895 if ((status = dladm_name2info(handle, linkname, &linkid, &f, 2896 NULL, NULL)) != DLADM_STATUS_OK) { 2897 die_dlerr(status, "link %s is not valid", linkname); 2898 } 2899 2900 if (!(f & flags)) { 2901 die_dlerr(DLADM_STATUS_BADARG, "link %s is %s", 2902 argv[optind], flags == DLADM_OPT_PERSIST ? 2903 "a temporary link" : "temporarily removed"); 2904 } 2905 } else if (optind != argc) { 2906 usage(); 2907 } 2908 2909 if (p_arg && !o_arg) 2910 die("-p requires -o"); 2911 2912 if (S_arg) { 2913 dladm_continuous(handle, linkid, NULL, interval, LINK_REPORT); 2914 return; 2915 } 2916 2917 if (p_arg && strcasecmp(fields_str, "all") == 0) 2918 die("\"-o all\" is invalid with -p"); 2919 2920 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) { 2921 if (s_arg) 2922 fields_str = allstat_fields; 2923 else if (flags & DLADM_OPT_ACTIVE) 2924 fields_str = all_active_fields; 2925 else 2926 fields_str = all_inactive_fields; 2927 } 2928 2929 state.ls_parsable = p_arg; 2930 state.ls_flags = flags; 2931 state.ls_donefirst = B_FALSE; 2932 2933 if (s_arg) { 2934 link_stats(linkid, interval, fields_str, &state); 2935 return; 2936 } 2937 if (state.ls_parsable) 2938 ofmtflags |= OFMT_PARSABLE; 2939 oferr = ofmt_open(fields_str, link_fields, ofmtflags, 0, &ofmt); 2940 dladm_ofmt_check(oferr, state.ls_parsable, ofmt); 2941 state.ls_ofmt = ofmt; 2942 2943 if (linkid == DATALINK_ALL_LINKID) { 2944 (void) dladm_walk_datalink_id(show_link, handle, &state, 2945 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, flags); 2946 } else { 2947 (void) show_link(handle, linkid, &state); 2948 if (state.ls_status != DLADM_STATUS_OK) { 2949 die_dlerr(state.ls_status, "failed to show link %s", 2950 argv[optind]); 2951 } 2952 } 2953 ofmt_close(ofmt); 2954 } 2955 2956 static void 2957 do_show_aggr(int argc, char *argv[], const char *use) 2958 { 2959 boolean_t L_arg = B_FALSE; 2960 boolean_t s_arg = B_FALSE; 2961 boolean_t i_arg = B_FALSE; 2962 boolean_t p_arg = B_FALSE; 2963 boolean_t x_arg = B_FALSE; 2964 show_grp_state_t state; 2965 uint32_t flags = DLADM_OPT_ACTIVE; 2966 datalink_id_t linkid = DATALINK_ALL_LINKID; 2967 int option; 2968 uint32_t interval = 0; 2969 int key; 2970 dladm_status_t status; 2971 boolean_t o_arg = B_FALSE; 2972 char *fields_str = NULL; 2973 char *all_fields = 2974 "link,policy,addrpolicy,lacpactivity,lacptimer,flags"; 2975 char *all_lacp_fields = 2976 "link,port,aggregatable,sync,coll,dist,defaulted,expired"; 2977 char *all_stats_fields = 2978 "link,port,ipackets,rbytes,opackets,obytes,ipktdist,opktdist"; 2979 char *all_extended_fields = 2980 "link,port,speed,duplex,state,address,portstate"; 2981 ofmt_field_t *pf; 2982 ofmt_handle_t ofmt; 2983 ofmt_status_t oferr; 2984 uint_t ofmtflags = 0; 2985 2986 opterr = 0; 2987 while ((option = getopt_long(argc, argv, ":LpPxsi:o:", 2988 show_lopts, NULL)) != -1) { 2989 switch (option) { 2990 case 'L': 2991 if (L_arg) 2992 die_optdup(option); 2993 2994 L_arg = B_TRUE; 2995 break; 2996 case 'p': 2997 if (p_arg) 2998 die_optdup(option); 2999 3000 p_arg = B_TRUE; 3001 break; 3002 case 'x': 3003 if (x_arg) 3004 die_optdup(option); 3005 3006 x_arg = B_TRUE; 3007 break; 3008 case 'P': 3009 if (flags != DLADM_OPT_ACTIVE) 3010 die_optdup(option); 3011 3012 flags = DLADM_OPT_PERSIST; 3013 break; 3014 case 's': 3015 if (s_arg) 3016 die_optdup(option); 3017 3018 s_arg = B_TRUE; 3019 break; 3020 case 'o': 3021 o_arg = B_TRUE; 3022 fields_str = optarg; 3023 break; 3024 case 'i': 3025 if (i_arg) 3026 die_optdup(option); 3027 3028 i_arg = B_TRUE; 3029 if (!dladm_str2interval(optarg, &interval)) 3030 die("invalid interval value '%s'", optarg); 3031 break; 3032 default: 3033 die_opterr(optopt, option, use); 3034 break; 3035 } 3036 } 3037 3038 if (p_arg && !o_arg) 3039 die("-p requires -o"); 3040 3041 if (p_arg && strcasecmp(fields_str, "all") == 0) 3042 die("\"-o all\" is invalid with -p"); 3043 3044 if (i_arg && !s_arg) 3045 die("the option -i can be used only with -s"); 3046 3047 if (s_arg && (L_arg || p_arg || x_arg || flags != DLADM_OPT_ACTIVE)) { 3048 die("the option -%c cannot be used with -s", 3049 L_arg ? 'L' : (p_arg ? 'p' : (x_arg ? 'x' : 'P'))); 3050 } 3051 3052 if (L_arg && flags != DLADM_OPT_ACTIVE) 3053 die("the option -P cannot be used with -L"); 3054 3055 if (x_arg && (L_arg || flags != DLADM_OPT_ACTIVE)) 3056 die("the option -%c cannot be used with -x", L_arg ? 'L' : 'P'); 3057 3058 /* get aggregation key or aggrname (optional last argument) */ 3059 if (optind == (argc-1)) { 3060 if (!str2int(argv[optind], &key)) { 3061 status = dladm_name2info(handle, argv[optind], 3062 &linkid, NULL, NULL, NULL); 3063 } else { 3064 status = dladm_key2linkid(handle, (uint16_t)key, 3065 &linkid, DLADM_OPT_ACTIVE); 3066 } 3067 3068 if (status != DLADM_STATUS_OK) 3069 die("non-existent aggregation '%s'", argv[optind]); 3070 3071 } else if (optind != argc) { 3072 usage(); 3073 } 3074 3075 bzero(&state, sizeof (state)); 3076 state.gs_lacp = L_arg; 3077 state.gs_stats = s_arg; 3078 state.gs_flags = flags; 3079 state.gs_parsable = p_arg; 3080 state.gs_extended = x_arg; 3081 3082 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) { 3083 if (state.gs_lacp) 3084 fields_str = all_lacp_fields; 3085 else if (state.gs_stats) 3086 fields_str = all_stats_fields; 3087 else if (state.gs_extended) 3088 fields_str = all_extended_fields; 3089 else 3090 fields_str = all_fields; 3091 } 3092 3093 if (state.gs_lacp) { 3094 pf = aggr_l_fields; 3095 } else if (state.gs_stats) { 3096 pf = aggr_s_fields; 3097 } else if (state.gs_extended) { 3098 pf = aggr_x_fields; 3099 } else { 3100 pf = laggr_fields; 3101 } 3102 3103 if (state.gs_parsable) 3104 ofmtflags |= OFMT_PARSABLE; 3105 oferr = ofmt_open(fields_str, pf, ofmtflags, 0, &ofmt); 3106 dladm_ofmt_check(oferr, state.gs_parsable, ofmt); 3107 state.gs_ofmt = ofmt; 3108 3109 if (s_arg) { 3110 aggr_stats(linkid, &state, interval); 3111 ofmt_close(ofmt); 3112 return; 3113 } 3114 3115 if (linkid == DATALINK_ALL_LINKID) { 3116 (void) dladm_walk_datalink_id(show_aggr, handle, &state, 3117 DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, flags); 3118 } else { 3119 (void) show_aggr(handle, linkid, &state); 3120 if (state.gs_status != DLADM_STATUS_OK) { 3121 die_dlerr(state.gs_status, "failed to show aggr %s", 3122 argv[optind]); 3123 } 3124 } 3125 ofmt_close(ofmt); 3126 } 3127 3128 static dladm_status_t 3129 print_phys_default(show_state_t *state, datalink_id_t linkid, 3130 const char *link, uint32_t flags, uint32_t media) 3131 { 3132 dladm_phys_attr_t dpa; 3133 dladm_status_t status; 3134 link_fields_buf_t pattr; 3135 3136 status = dladm_phys_info(handle, linkid, &dpa, state->ls_flags); 3137 if (status != DLADM_STATUS_OK) 3138 goto done; 3139 3140 (void) snprintf(pattr.link_phys_device, 3141 sizeof (pattr.link_phys_device), "%s", dpa.dp_dev); 3142 (void) dladm_media2str(media, pattr.link_phys_media); 3143 if (state->ls_flags == DLADM_OPT_ACTIVE) { 3144 boolean_t islink; 3145 3146 if (!dpa.dp_novanity) { 3147 (void) strlcpy(pattr.link_name, link, 3148 sizeof (pattr.link_name)); 3149 islink = B_TRUE; 3150 } else { 3151 /* 3152 * This is a physical link that does not have 3153 * vanity naming support. 3154 */ 3155 (void) strlcpy(pattr.link_name, dpa.dp_dev, 3156 sizeof (pattr.link_name)); 3157 islink = B_FALSE; 3158 } 3159 3160 (void) get_linkstate(pattr.link_name, islink, 3161 pattr.link_phys_state); 3162 (void) snprintf(pattr.link_phys_speed, 3163 sizeof (pattr.link_phys_speed), "%u", 3164 (uint_t)((get_ifspeed(pattr.link_name, 3165 islink)) / 1000000ull)); 3166 (void) get_linkduplex(pattr.link_name, islink, 3167 pattr.link_phys_duplex); 3168 } else { 3169 (void) snprintf(pattr.link_name, sizeof (pattr.link_name), 3170 "%s", link); 3171 (void) snprintf(pattr.link_flags, sizeof (pattr.link_flags), 3172 "%c----", flags & DLADM_OPT_ACTIVE ? '-' : 'r'); 3173 } 3174 3175 ofmt_print(state->ls_ofmt, &pattr); 3176 3177 done: 3178 return (status); 3179 } 3180 3181 typedef struct { 3182 show_state_t *ms_state; 3183 char *ms_link; 3184 dladm_macaddr_attr_t *ms_mac_attr; 3185 } print_phys_mac_state_t; 3186 3187 /* 3188 * callback for ofmt_print() 3189 */ 3190 static boolean_t 3191 print_phys_one_mac_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 3192 { 3193 print_phys_mac_state_t *mac_state = ofarg->ofmt_cbarg; 3194 dladm_macaddr_attr_t *attr = mac_state->ms_mac_attr; 3195 boolean_t is_primary = (attr->ma_slot == 0); 3196 boolean_t is_parsable = mac_state->ms_state->ls_parsable; 3197 3198 switch (ofarg->ofmt_id) { 3199 case PHYS_M_LINK: 3200 (void) snprintf(buf, bufsize, "%s", 3201 (is_primary || is_parsable) ? mac_state->ms_link : " "); 3202 break; 3203 case PHYS_M_SLOT: 3204 if (is_primary) 3205 (void) snprintf(buf, bufsize, gettext("primary")); 3206 else 3207 (void) snprintf(buf, bufsize, "%d", attr->ma_slot); 3208 break; 3209 case PHYS_M_ADDRESS: 3210 (void) dladm_aggr_macaddr2str(attr->ma_addr, buf); 3211 break; 3212 case PHYS_M_INUSE: 3213 (void) snprintf(buf, bufsize, "%s", 3214 attr->ma_flags & DLADM_MACADDR_USED ? gettext("yes") : 3215 gettext("no")); 3216 break; 3217 case PHYS_M_CLIENT: 3218 /* 3219 * CR 6678526: resolve link id to actual link name if 3220 * it is valid. 3221 */ 3222 (void) snprintf(buf, bufsize, "%s", attr->ma_client_name); 3223 break; 3224 } 3225 3226 return (B_TRUE); 3227 } 3228 3229 typedef struct { 3230 show_state_t *hs_state; 3231 char *hs_link; 3232 dladm_hwgrp_attr_t *hs_grp_attr; 3233 } print_phys_hwgrp_state_t; 3234 3235 static boolean_t 3236 print_phys_one_hwgrp_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 3237 { 3238 print_phys_hwgrp_state_t *hg_state = ofarg->ofmt_cbarg; 3239 dladm_hwgrp_attr_t *attr = hg_state->hs_grp_attr; 3240 3241 switch (ofarg->ofmt_id) { 3242 case PHYS_H_LINK: 3243 (void) snprintf(buf, bufsize, "%s", attr->hg_link_name); 3244 break; 3245 case PHYS_H_GROUP: 3246 (void) snprintf(buf, bufsize, "%d", attr->hg_grp_num); 3247 break; 3248 case PHYS_H_GRPTYPE: 3249 (void) snprintf(buf, bufsize, "%s", 3250 attr->hg_grp_type == DLADM_HWGRP_TYPE_RX ? "RX" : "TX"); 3251 break; 3252 case PHYS_H_RINGS: 3253 (void) snprintf(buf, bufsize, "%d", attr->hg_n_rings); 3254 break; 3255 case PHYS_H_CLIENTS: 3256 if (attr->hg_client_names[0] == '\0') { 3257 (void) snprintf(buf, bufsize, "--"); 3258 } else { 3259 (void) snprintf(buf, bufsize, "%s ", 3260 attr->hg_client_names); 3261 } 3262 break; 3263 } 3264 3265 return (B_TRUE); 3266 } 3267 3268 /* 3269 * callback for dladm_walk_macaddr, invoked for each MAC address slot 3270 */ 3271 static boolean_t 3272 print_phys_mac_callback(void *arg, dladm_macaddr_attr_t *attr) 3273 { 3274 print_phys_mac_state_t *mac_state = arg; 3275 show_state_t *state = mac_state->ms_state; 3276 3277 mac_state->ms_mac_attr = attr; 3278 ofmt_print(state->ls_ofmt, mac_state); 3279 3280 return (B_TRUE); 3281 } 3282 3283 /* 3284 * invoked by show-phys -m for each physical data-link 3285 */ 3286 static dladm_status_t 3287 print_phys_mac(show_state_t *state, datalink_id_t linkid, char *link) 3288 { 3289 print_phys_mac_state_t mac_state; 3290 3291 mac_state.ms_state = state; 3292 mac_state.ms_link = link; 3293 3294 return (dladm_walk_macaddr(handle, linkid, &mac_state, 3295 print_phys_mac_callback)); 3296 } 3297 3298 /* 3299 * callback for dladm_walk_hwgrp, invoked for each MAC hwgrp 3300 */ 3301 static boolean_t 3302 print_phys_hwgrp_callback(void *arg, dladm_hwgrp_attr_t *attr) 3303 { 3304 print_phys_hwgrp_state_t *hwgrp_state = arg; 3305 show_state_t *state = hwgrp_state->hs_state; 3306 3307 hwgrp_state->hs_grp_attr = attr; 3308 ofmt_print(state->ls_ofmt, hwgrp_state); 3309 3310 return (B_TRUE); 3311 } 3312 3313 /* invoked by show-phys -H for each physical data-link */ 3314 static dladm_status_t 3315 print_phys_hwgrp(show_state_t *state, datalink_id_t linkid, char *link) 3316 { 3317 print_phys_hwgrp_state_t hwgrp_state; 3318 3319 hwgrp_state.hs_state = state; 3320 hwgrp_state.hs_link = link; 3321 return (dladm_walk_hwgrp(handle, linkid, &hwgrp_state, 3322 print_phys_hwgrp_callback)); 3323 } 3324 3325 static dladm_status_t 3326 print_phys(show_state_t *state, datalink_id_t linkid) 3327 { 3328 char link[MAXLINKNAMELEN]; 3329 uint32_t flags; 3330 dladm_status_t status; 3331 datalink_class_t class; 3332 uint32_t media; 3333 3334 if ((status = dladm_datalink_id2info(handle, linkid, &flags, &class, 3335 &media, link, MAXLINKNAMELEN)) != DLADM_STATUS_OK) { 3336 goto done; 3337 } 3338 3339 if (class != DATALINK_CLASS_PHYS) { 3340 status = DLADM_STATUS_BADARG; 3341 goto done; 3342 } 3343 3344 if (!(state->ls_flags & flags)) { 3345 status = DLADM_STATUS_NOTFOUND; 3346 goto done; 3347 } 3348 3349 if (state->ls_mac) 3350 status = print_phys_mac(state, linkid, link); 3351 else if (state->ls_hwgrp) 3352 status = print_phys_hwgrp(state, linkid, link); 3353 else 3354 status = print_phys_default(state, linkid, link, flags, media); 3355 3356 done: 3357 return (status); 3358 } 3359 3360 /* ARGSUSED */ 3361 static int 3362 show_phys(dladm_handle_t dh, datalink_id_t linkid, void *arg) 3363 { 3364 show_state_t *state = arg; 3365 3366 state->ls_status = print_phys(state, linkid); 3367 return (DLADM_WALK_CONTINUE); 3368 } 3369 3370 /* 3371 * Print the active topology information. 3372 */ 3373 static dladm_status_t 3374 print_vlan(show_state_t *state, datalink_id_t linkid, link_fields_buf_t *l) 3375 { 3376 dladm_vlan_attr_t vinfo; 3377 uint32_t flags; 3378 dladm_status_t status; 3379 3380 if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL, NULL, 3381 l->link_name, sizeof (l->link_name))) != DLADM_STATUS_OK) { 3382 goto done; 3383 } 3384 3385 if (!(state->ls_flags & flags)) { 3386 status = DLADM_STATUS_NOTFOUND; 3387 goto done; 3388 } 3389 3390 if ((status = dladm_vlan_info(handle, linkid, &vinfo, 3391 state->ls_flags)) != DLADM_STATUS_OK || 3392 (status = dladm_datalink_id2info(handle, vinfo.dv_linkid, NULL, 3393 NULL, NULL, l->link_over, sizeof (l->link_over))) != 3394 DLADM_STATUS_OK) { 3395 goto done; 3396 } 3397 3398 (void) snprintf(l->link_vlan_vid, sizeof (l->link_vlan_vid), "%d", 3399 vinfo.dv_vid); 3400 (void) snprintf(l->link_flags, sizeof (l->link_flags), "%c----", 3401 vinfo.dv_force ? 'f' : '-'); 3402 3403 done: 3404 return (status); 3405 } 3406 3407 /* ARGSUSED */ 3408 static int 3409 show_vlan(dladm_handle_t dh, datalink_id_t linkid, void *arg) 3410 { 3411 show_state_t *state = arg; 3412 dladm_status_t status; 3413 link_fields_buf_t lbuf; 3414 3415 bzero(&lbuf, sizeof (link_fields_buf_t)); 3416 status = print_vlan(state, linkid, &lbuf); 3417 if (status != DLADM_STATUS_OK) 3418 goto done; 3419 3420 ofmt_print(state->ls_ofmt, &lbuf); 3421 3422 done: 3423 state->ls_status = status; 3424 return (DLADM_WALK_CONTINUE); 3425 } 3426 3427 static void 3428 do_show_phys(int argc, char *argv[], const char *use) 3429 { 3430 int option; 3431 uint32_t flags = DLADM_OPT_ACTIVE; 3432 boolean_t p_arg = B_FALSE; 3433 boolean_t o_arg = B_FALSE; 3434 boolean_t m_arg = B_FALSE; 3435 boolean_t H_arg = B_FALSE; 3436 datalink_id_t linkid = DATALINK_ALL_LINKID; 3437 show_state_t state; 3438 dladm_status_t status; 3439 char *fields_str = NULL; 3440 char *all_active_fields = 3441 "link,media,state,speed,duplex,device"; 3442 char *all_inactive_fields = "link,device,media,flags"; 3443 char *all_mac_fields = "link,slot,address,inuse,client"; 3444 char *all_hwgrp_fields = 3445 "link,group,grouptype,rings,clients"; 3446 ofmt_field_t *pf; 3447 ofmt_handle_t ofmt; 3448 ofmt_status_t oferr; 3449 uint_t ofmtflags = 0; 3450 3451 bzero(&state, sizeof (state)); 3452 opterr = 0; 3453 while ((option = getopt_long(argc, argv, ":pPo:mH", 3454 show_lopts, NULL)) != -1) { 3455 switch (option) { 3456 case 'p': 3457 if (p_arg) 3458 die_optdup(option); 3459 3460 p_arg = B_TRUE; 3461 break; 3462 case 'P': 3463 if (flags != DLADM_OPT_ACTIVE) 3464 die_optdup(option); 3465 3466 flags = DLADM_OPT_PERSIST; 3467 break; 3468 case 'o': 3469 o_arg = B_TRUE; 3470 fields_str = optarg; 3471 break; 3472 case 'm': 3473 m_arg = B_TRUE; 3474 break; 3475 case 'H': 3476 H_arg = B_TRUE; 3477 break; 3478 default: 3479 die_opterr(optopt, option, use); 3480 break; 3481 } 3482 } 3483 3484 if (p_arg && !o_arg) 3485 die("-p requires -o"); 3486 3487 if (m_arg && H_arg) 3488 die("-m cannot combine with -H"); 3489 3490 if (p_arg && strcasecmp(fields_str, "all") == 0) 3491 die("\"-o all\" is invalid with -p"); 3492 3493 /* get link name (optional last argument) */ 3494 if (optind == (argc-1)) { 3495 if ((status = dladm_name2info(handle, argv[optind], &linkid, 3496 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 3497 die_dlerr(status, "link %s is not valid", argv[optind]); 3498 } 3499 } else if (optind != argc) { 3500 usage(); 3501 } 3502 3503 state.ls_parsable = p_arg; 3504 state.ls_flags = flags; 3505 state.ls_donefirst = B_FALSE; 3506 state.ls_mac = m_arg; 3507 state.ls_hwgrp = H_arg; 3508 3509 if (m_arg && !(flags & DLADM_OPT_ACTIVE)) { 3510 /* 3511 * We can only display the factory MAC addresses of 3512 * active data-links. 3513 */ 3514 die("-m not compatible with -P"); 3515 } 3516 3517 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) { 3518 if (state.ls_mac) 3519 fields_str = all_mac_fields; 3520 else if (state.ls_hwgrp) 3521 fields_str = all_hwgrp_fields; 3522 else if (state.ls_flags & DLADM_OPT_ACTIVE) { 3523 fields_str = all_active_fields; 3524 } else { 3525 fields_str = all_inactive_fields; 3526 } 3527 } 3528 3529 if (state.ls_mac) { 3530 pf = phys_m_fields; 3531 } else if (state.ls_hwgrp) { 3532 pf = phys_h_fields; 3533 } else { 3534 pf = phys_fields; 3535 } 3536 3537 if (state.ls_parsable) 3538 ofmtflags |= OFMT_PARSABLE; 3539 oferr = ofmt_open(fields_str, pf, ofmtflags, 0, &ofmt); 3540 dladm_ofmt_check(oferr, state.ls_parsable, ofmt); 3541 state.ls_ofmt = ofmt; 3542 3543 if (linkid == DATALINK_ALL_LINKID) { 3544 (void) dladm_walk_datalink_id(show_phys, handle, &state, 3545 DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, flags); 3546 } else { 3547 (void) show_phys(handle, linkid, &state); 3548 if (state.ls_status != DLADM_STATUS_OK) { 3549 die_dlerr(state.ls_status, 3550 "failed to show physical link %s", argv[optind]); 3551 } 3552 } 3553 ofmt_close(ofmt); 3554 } 3555 3556 static void 3557 do_show_vlan(int argc, char *argv[], const char *use) 3558 { 3559 int option; 3560 uint32_t flags = DLADM_OPT_ACTIVE; 3561 boolean_t p_arg = B_FALSE; 3562 datalink_id_t linkid = DATALINK_ALL_LINKID; 3563 show_state_t state; 3564 dladm_status_t status; 3565 boolean_t o_arg = B_FALSE; 3566 char *fields_str = NULL; 3567 ofmt_handle_t ofmt; 3568 ofmt_status_t oferr; 3569 uint_t ofmtflags = 0; 3570 3571 bzero(&state, sizeof (state)); 3572 3573 opterr = 0; 3574 while ((option = getopt_long(argc, argv, ":pPo:", 3575 show_lopts, NULL)) != -1) { 3576 switch (option) { 3577 case 'p': 3578 if (p_arg) 3579 die_optdup(option); 3580 3581 p_arg = B_TRUE; 3582 break; 3583 case 'P': 3584 if (flags != DLADM_OPT_ACTIVE) 3585 die_optdup(option); 3586 3587 flags = DLADM_OPT_PERSIST; 3588 break; 3589 case 'o': 3590 o_arg = B_TRUE; 3591 fields_str = optarg; 3592 break; 3593 default: 3594 die_opterr(optopt, option, use); 3595 break; 3596 } 3597 } 3598 3599 /* get link name (optional last argument) */ 3600 if (optind == (argc-1)) { 3601 if ((status = dladm_name2info(handle, argv[optind], &linkid, 3602 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 3603 die_dlerr(status, "link %s is not valid", argv[optind]); 3604 } 3605 } else if (optind != argc) { 3606 usage(); 3607 } 3608 3609 state.ls_parsable = p_arg; 3610 state.ls_flags = flags; 3611 state.ls_donefirst = B_FALSE; 3612 3613 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) 3614 fields_str = NULL; 3615 3616 if (state.ls_parsable) 3617 ofmtflags |= OFMT_PARSABLE; 3618 oferr = ofmt_open(fields_str, vlan_fields, ofmtflags, 0, &ofmt); 3619 dladm_ofmt_check(oferr, state.ls_parsable, ofmt); 3620 state.ls_ofmt = ofmt; 3621 3622 if (linkid == DATALINK_ALL_LINKID) { 3623 (void) dladm_walk_datalink_id(show_vlan, handle, &state, 3624 DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, flags); 3625 } else { 3626 (void) show_vlan(handle, linkid, &state); 3627 if (state.ls_status != DLADM_STATUS_OK) { 3628 die_dlerr(state.ls_status, "failed to show vlan %s", 3629 argv[optind]); 3630 } 3631 } 3632 ofmt_close(ofmt); 3633 } 3634 3635 static void 3636 do_create_vnic(int argc, char *argv[], const char *use) 3637 { 3638 datalink_id_t linkid, dev_linkid; 3639 char devname[MAXLINKNAMELEN]; 3640 char name[MAXLINKNAMELEN]; 3641 boolean_t l_arg = B_FALSE; 3642 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 3643 char *altroot = NULL; 3644 char option; 3645 char *endp = NULL; 3646 dladm_status_t status; 3647 vnic_mac_addr_type_t mac_addr_type = VNIC_MAC_ADDR_TYPE_AUTO; 3648 uchar_t *mac_addr; 3649 int mac_slot = -1, maclen = 0, mac_prefix_len = 0; 3650 char propstr[DLADM_STRSIZE]; 3651 dladm_arg_list_t *proplist = NULL; 3652 int vid = 0; 3653 3654 opterr = 0; 3655 bzero(propstr, DLADM_STRSIZE); 3656 3657 while ((option = getopt_long(argc, argv, ":tfR:l:m:n:p:r:v:H", 3658 vnic_lopts, NULL)) != -1) { 3659 switch (option) { 3660 case 't': 3661 flags &= ~DLADM_OPT_PERSIST; 3662 break; 3663 case 'R': 3664 altroot = optarg; 3665 break; 3666 case 'l': 3667 if (strlcpy(devname, optarg, MAXLINKNAMELEN) >= 3668 MAXLINKNAMELEN) 3669 die("link name too long"); 3670 l_arg = B_TRUE; 3671 break; 3672 case 'm': 3673 if (strcmp(optarg, "fixed") == 0) { 3674 /* 3675 * A fixed MAC address must be specified 3676 * by its value, not by the keyword 'fixed'. 3677 */ 3678 die("'fixed' is not a valid MAC address"); 3679 } 3680 if (dladm_vnic_str2macaddrtype(optarg, 3681 &mac_addr_type) != DLADM_STATUS_OK) { 3682 mac_addr_type = VNIC_MAC_ADDR_TYPE_FIXED; 3683 /* MAC address specified by value */ 3684 mac_addr = _link_aton(optarg, &maclen); 3685 if (mac_addr == NULL) { 3686 if (maclen == -1) 3687 die("invalid MAC address"); 3688 else 3689 die("out of memory"); 3690 } 3691 } 3692 break; 3693 case 'n': 3694 errno = 0; 3695 mac_slot = (int)strtol(optarg, &endp, 10); 3696 if (errno != 0 || *endp != '\0') 3697 die("invalid slot number"); 3698 break; 3699 case 'p': 3700 (void) strlcat(propstr, optarg, DLADM_STRSIZE); 3701 if (strlcat(propstr, ",", DLADM_STRSIZE) >= 3702 DLADM_STRSIZE) 3703 die("property list too long '%s'", propstr); 3704 break; 3705 case 'r': 3706 mac_addr = _link_aton(optarg, &mac_prefix_len); 3707 if (mac_addr == NULL) { 3708 if (mac_prefix_len == -1) 3709 die("invalid MAC address"); 3710 else 3711 die("out of memory"); 3712 } 3713 break; 3714 case 'v': 3715 if (vid != 0) 3716 die_optdup(option); 3717 3718 if (!str2int(optarg, &vid) || vid < 1 || vid > 4094) 3719 die("invalid VLAN identifier '%s'", optarg); 3720 3721 break; 3722 case 'f': 3723 flags |= DLADM_OPT_FORCE; 3724 break; 3725 case 'H': 3726 flags |= DLADM_OPT_HWRINGS; 3727 break; 3728 default: 3729 die_opterr(optopt, option, use); 3730 } 3731 } 3732 3733 /* 3734 * 'f' - force, flag can be specified only with 'v' - vlan. 3735 */ 3736 if ((flags & DLADM_OPT_FORCE) != 0 && vid == 0) 3737 die("-f option can only be used with -v"); 3738 3739 if (mac_prefix_len != 0 && mac_addr_type != VNIC_MAC_ADDR_TYPE_RANDOM && 3740 mac_addr_type != VNIC_MAC_ADDR_TYPE_FIXED) 3741 usage(); 3742 3743 /* check required options */ 3744 if (!l_arg) 3745 usage(); 3746 3747 if (mac_slot != -1 && mac_addr_type != VNIC_MAC_ADDR_TYPE_FACTORY) 3748 usage(); 3749 3750 /* the VNIC id is the required operand */ 3751 if (optind != (argc - 1)) 3752 usage(); 3753 3754 if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= MAXLINKNAMELEN) 3755 die("link name too long '%s'", argv[optind]); 3756 3757 if (!dladm_valid_linkname(name)) 3758 die("invalid link name '%s'", argv[optind]); 3759 3760 if (altroot != NULL) 3761 altroot_cmd(altroot, argc, argv); 3762 3763 if (dladm_name2info(handle, devname, &dev_linkid, NULL, NULL, NULL) != 3764 DLADM_STATUS_OK) 3765 die("invalid link name '%s'", devname); 3766 3767 if (dladm_parse_link_props(propstr, &proplist, B_FALSE) 3768 != DLADM_STATUS_OK) 3769 die("invalid vnic property"); 3770 3771 status = dladm_vnic_create(handle, name, dev_linkid, mac_addr_type, 3772 mac_addr, maclen, &mac_slot, mac_prefix_len, vid, &linkid, proplist, 3773 flags); 3774 if (status != DLADM_STATUS_OK) 3775 die_dlerr(status, "vnic creation over %s failed", devname); 3776 3777 dladm_free_props(proplist); 3778 } 3779 3780 static void 3781 do_etherstub_check(const char *name, datalink_id_t linkid, boolean_t etherstub, 3782 uint32_t flags) 3783 { 3784 boolean_t is_etherstub; 3785 dladm_vnic_attr_t attr; 3786 3787 if (dladm_vnic_info(handle, linkid, &attr, flags) != DLADM_STATUS_OK) { 3788 /* 3789 * Let the delete continue anyway. 3790 */ 3791 return; 3792 } 3793 is_etherstub = (attr.va_link_id == DATALINK_INVALID_LINKID); 3794 if (is_etherstub != etherstub) { 3795 die("'%s' is not %s", name, 3796 (is_etherstub ? "a vnic" : "an etherstub")); 3797 } 3798 } 3799 3800 static void 3801 do_delete_vnic_common(int argc, char *argv[], const char *use, 3802 boolean_t etherstub) 3803 { 3804 char option; 3805 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 3806 datalink_id_t linkid; 3807 char *altroot = NULL; 3808 dladm_status_t status; 3809 3810 opterr = 0; 3811 while ((option = getopt_long(argc, argv, ":R:t", lopts, 3812 NULL)) != -1) { 3813 switch (option) { 3814 case 't': 3815 flags &= ~DLADM_OPT_PERSIST; 3816 break; 3817 case 'R': 3818 altroot = optarg; 3819 break; 3820 default: 3821 die_opterr(optopt, option, use); 3822 } 3823 } 3824 3825 /* get vnic name (required last argument) */ 3826 if (optind != (argc - 1)) 3827 usage(); 3828 3829 if (altroot != NULL) 3830 altroot_cmd(altroot, argc, argv); 3831 3832 status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL, 3833 NULL); 3834 if (status != DLADM_STATUS_OK) 3835 die("invalid link name '%s'", argv[optind]); 3836 3837 if ((flags & DLADM_OPT_ACTIVE) != 0) { 3838 do_etherstub_check(argv[optind], linkid, etherstub, 3839 DLADM_OPT_ACTIVE); 3840 } 3841 if ((flags & DLADM_OPT_PERSIST) != 0) { 3842 do_etherstub_check(argv[optind], linkid, etherstub, 3843 DLADM_OPT_PERSIST); 3844 } 3845 3846 status = dladm_vnic_delete(handle, linkid, flags); 3847 if (status != DLADM_STATUS_OK) 3848 die_dlerr(status, "vnic deletion failed"); 3849 } 3850 3851 static void 3852 do_delete_vnic(int argc, char *argv[], const char *use) 3853 { 3854 do_delete_vnic_common(argc, argv, use, B_FALSE); 3855 } 3856 3857 /* ARGSUSED */ 3858 static void 3859 do_up_vnic_common(int argc, char *argv[], const char *use, boolean_t vlan) 3860 { 3861 datalink_id_t linkid = DATALINK_ALL_LINKID; 3862 dladm_status_t status; 3863 char *type; 3864 3865 type = vlan ? "vlan" : "vnic"; 3866 3867 /* 3868 * get the id or the name of the vnic/vlan (optional last argument) 3869 */ 3870 if (argc == 2) { 3871 status = dladm_name2info(handle, argv[1], &linkid, NULL, NULL, 3872 NULL); 3873 if (status != DLADM_STATUS_OK) 3874 goto done; 3875 3876 } else if (argc > 2) { 3877 usage(); 3878 } 3879 3880 if (vlan) 3881 status = dladm_vlan_up(handle, linkid); 3882 else 3883 status = dladm_vnic_up(handle, linkid, 0); 3884 3885 done: 3886 if (status != DLADM_STATUS_OK) { 3887 if (argc == 2) { 3888 die_dlerr(status, 3889 "could not bring up %s '%s'", type, argv[1]); 3890 } else { 3891 die_dlerr(status, "could not bring %ss up", type); 3892 } 3893 } 3894 } 3895 3896 static void 3897 do_up_vnic(int argc, char *argv[], const char *use) 3898 { 3899 do_up_vnic_common(argc, argv, use, B_FALSE); 3900 } 3901 3902 static void 3903 dump_vnics_head(const char *dev) 3904 { 3905 if (strlen(dev)) 3906 (void) printf("%s", dev); 3907 3908 (void) printf("\tipackets rbytes opackets obytes "); 3909 3910 if (strlen(dev)) 3911 (void) printf("%%ipkts %%opkts\n"); 3912 else 3913 (void) printf("\n"); 3914 } 3915 3916 static void 3917 dump_vnic_stat(const char *name, datalink_id_t vnic_id, 3918 show_vnic_state_t *state, pktsum_t *vnic_stats, pktsum_t *tot_stats) 3919 { 3920 pktsum_t diff_stats; 3921 pktsum_t *old_stats = &state->vs_prevstats[vnic_id]; 3922 3923 dladm_stats_diff(&diff_stats, vnic_stats, old_stats); 3924 3925 (void) printf("%s", name); 3926 3927 (void) printf("\t%-10llu", diff_stats.ipackets); 3928 (void) printf("%-12llu", diff_stats.rbytes); 3929 (void) printf("%-10llu", diff_stats.opackets); 3930 (void) printf("%-12llu", diff_stats.obytes); 3931 3932 if (tot_stats) { 3933 if (tot_stats->ipackets == 0) { 3934 (void) printf("\t-"); 3935 } else { 3936 (void) printf("\t%-6.1f", (double)diff_stats.ipackets/ 3937 (double)tot_stats->ipackets * 100); 3938 } 3939 if (tot_stats->opackets == 0) { 3940 (void) printf("\t-"); 3941 } else { 3942 (void) printf("\t%-6.1f", (double)diff_stats.opackets/ 3943 (double)tot_stats->opackets * 100); 3944 } 3945 } 3946 (void) printf("\n"); 3947 3948 *old_stats = *vnic_stats; 3949 } 3950 3951 /* 3952 * Called from the walker dladm_vnic_walk_sys() for each vnic to display 3953 * vnic information or statistics. 3954 */ 3955 static dladm_status_t 3956 print_vnic(show_vnic_state_t *state, datalink_id_t linkid) 3957 { 3958 dladm_vnic_attr_t attr, *vnic = &attr; 3959 dladm_status_t status; 3960 boolean_t is_etherstub; 3961 char devname[MAXLINKNAMELEN]; 3962 char vnic_name[MAXLINKNAMELEN]; 3963 char mstr[MAXMACADDRLEN * 3]; 3964 vnic_fields_buf_t vbuf; 3965 3966 if ((status = dladm_vnic_info(handle, linkid, vnic, state->vs_flags)) != 3967 DLADM_STATUS_OK) 3968 return (status); 3969 3970 is_etherstub = (vnic->va_link_id == DATALINK_INVALID_LINKID); 3971 if (state->vs_etherstub != is_etherstub) { 3972 /* 3973 * Want all etherstub but it's not one, or want 3974 * non-etherstub and it's one. 3975 */ 3976 return (DLADM_STATUS_OK); 3977 } 3978 3979 if (state->vs_link_id != DATALINK_ALL_LINKID) { 3980 if (state->vs_link_id != vnic->va_link_id) 3981 return (DLADM_STATUS_OK); 3982 } 3983 3984 if (dladm_datalink_id2info(handle, linkid, NULL, NULL, 3985 NULL, vnic_name, sizeof (vnic_name)) != DLADM_STATUS_OK) 3986 return (DLADM_STATUS_BADARG); 3987 3988 bzero(devname, sizeof (devname)); 3989 if (!is_etherstub && 3990 dladm_datalink_id2info(handle, vnic->va_link_id, NULL, NULL, 3991 NULL, devname, sizeof (devname)) != DLADM_STATUS_OK) 3992 return (DLADM_STATUS_BADARG); 3993 3994 state->vs_found = B_TRUE; 3995 if (state->vs_stats) { 3996 /* print vnic statistics */ 3997 pktsum_t vnic_stats; 3998 3999 if (state->vs_firstonly) { 4000 if (state->vs_donefirst) 4001 return (0); 4002 state->vs_donefirst = B_TRUE; 4003 } 4004 4005 if (!state->vs_printstats) { 4006 /* 4007 * get vnic statistics and add to the sum for the 4008 * named device. 4009 */ 4010 get_link_stats(vnic_name, &vnic_stats); 4011 dladm_stats_total(&state->vs_totalstats, &vnic_stats, 4012 &state->vs_prevstats[vnic->va_vnic_id]); 4013 } else { 4014 /* get and print vnic statistics */ 4015 get_link_stats(vnic_name, &vnic_stats); 4016 dump_vnic_stat(vnic_name, linkid, state, &vnic_stats, 4017 &state->vs_totalstats); 4018 } 4019 return (DLADM_STATUS_OK); 4020 } else { 4021 (void) snprintf(vbuf.vnic_link, sizeof (vbuf.vnic_link), 4022 "%s", vnic_name); 4023 4024 if (!is_etherstub) { 4025 4026 (void) snprintf(vbuf.vnic_over, sizeof (vbuf.vnic_over), 4027 "%s", devname); 4028 (void) snprintf(vbuf.vnic_speed, 4029 sizeof (vbuf.vnic_speed), "%u", 4030 (uint_t)((get_ifspeed(vnic_name, B_TRUE)) 4031 / 1000000ull)); 4032 4033 switch (vnic->va_mac_addr_type) { 4034 case VNIC_MAC_ADDR_TYPE_FIXED: 4035 case VNIC_MAC_ADDR_TYPE_PRIMARY: 4036 (void) snprintf(vbuf.vnic_macaddrtype, 4037 sizeof (vbuf.vnic_macaddrtype), 4038 gettext("fixed")); 4039 break; 4040 case VNIC_MAC_ADDR_TYPE_RANDOM: 4041 (void) snprintf(vbuf.vnic_macaddrtype, 4042 sizeof (vbuf.vnic_macaddrtype), 4043 gettext("random")); 4044 break; 4045 case VNIC_MAC_ADDR_TYPE_FACTORY: 4046 (void) snprintf(vbuf.vnic_macaddrtype, 4047 sizeof (vbuf.vnic_macaddrtype), 4048 gettext("factory, slot %d"), 4049 vnic->va_mac_slot); 4050 break; 4051 } 4052 4053 if (strlen(vbuf.vnic_macaddrtype) > 0) { 4054 (void) snprintf(vbuf.vnic_macaddr, 4055 sizeof (vbuf.vnic_macaddr), "%s", 4056 dladm_aggr_macaddr2str(vnic->va_mac_addr, 4057 mstr)); 4058 } 4059 4060 (void) snprintf(vbuf.vnic_vid, sizeof (vbuf.vnic_vid), 4061 "%d", vnic->va_vid); 4062 } 4063 4064 ofmt_print(state->vs_ofmt, &vbuf); 4065 4066 return (DLADM_STATUS_OK); 4067 } 4068 } 4069 4070 /* ARGSUSED */ 4071 static int 4072 show_vnic(dladm_handle_t dh, datalink_id_t linkid, void *arg) 4073 { 4074 show_vnic_state_t *state = arg; 4075 4076 state->vs_status = print_vnic(state, linkid); 4077 return (DLADM_WALK_CONTINUE); 4078 } 4079 4080 static void 4081 do_show_vnic_common(int argc, char *argv[], const char *use, 4082 boolean_t etherstub) 4083 { 4084 int option; 4085 boolean_t s_arg = B_FALSE; 4086 boolean_t i_arg = B_FALSE; 4087 boolean_t l_arg = B_FALSE; 4088 uint32_t interval = 0, flags = DLADM_OPT_ACTIVE; 4089 datalink_id_t linkid = DATALINK_ALL_LINKID; 4090 datalink_id_t dev_linkid = DATALINK_ALL_LINKID; 4091 show_vnic_state_t state; 4092 dladm_status_t status; 4093 boolean_t o_arg = B_FALSE; 4094 char *fields_str = NULL; 4095 ofmt_field_t *pf; 4096 char *all_e_fields = "link"; 4097 ofmt_handle_t ofmt; 4098 ofmt_status_t oferr; 4099 uint_t ofmtflags = 0; 4100 4101 bzero(&state, sizeof (state)); 4102 opterr = 0; 4103 while ((option = getopt_long(argc, argv, ":pPl:si:o:", lopts, 4104 NULL)) != -1) { 4105 switch (option) { 4106 case 'p': 4107 state.vs_parsable = B_TRUE; 4108 break; 4109 case 'P': 4110 flags = DLADM_OPT_PERSIST; 4111 break; 4112 case 'l': 4113 if (etherstub) 4114 die("option not supported for this command"); 4115 4116 if (strlcpy(state.vs_link, optarg, MAXLINKNAMELEN) >= 4117 MAXLINKNAMELEN) 4118 die("link name too long"); 4119 4120 l_arg = B_TRUE; 4121 break; 4122 case 's': 4123 if (s_arg) { 4124 die("the option -s cannot be specified " 4125 "more than once"); 4126 } 4127 s_arg = B_TRUE; 4128 break; 4129 case 'i': 4130 if (i_arg) { 4131 die("the option -i cannot be specified " 4132 "more than once"); 4133 } 4134 i_arg = B_TRUE; 4135 if (!dladm_str2interval(optarg, &interval)) 4136 die("invalid interval value '%s'", optarg); 4137 break; 4138 case 'o': 4139 o_arg = B_TRUE; 4140 fields_str = optarg; 4141 break; 4142 default: 4143 die_opterr(optopt, option, use); 4144 } 4145 } 4146 4147 if (i_arg && !s_arg) 4148 die("the option -i can be used only with -s"); 4149 4150 /* get vnic ID (optional last argument) */ 4151 if (optind == (argc - 1)) { 4152 status = dladm_name2info(handle, argv[optind], &linkid, NULL, 4153 NULL, NULL); 4154 if (status != DLADM_STATUS_OK) { 4155 die_dlerr(status, "invalid vnic name '%s'", 4156 argv[optind]); 4157 } 4158 (void) strlcpy(state.vs_vnic, argv[optind], MAXLINKNAMELEN); 4159 } else if (optind != argc) { 4160 usage(); 4161 } 4162 4163 if (l_arg) { 4164 status = dladm_name2info(handle, state.vs_link, &dev_linkid, 4165 NULL, NULL, NULL); 4166 if (status != DLADM_STATUS_OK) { 4167 die_dlerr(status, "invalid link name '%s'", 4168 state.vs_link); 4169 } 4170 } 4171 4172 state.vs_vnic_id = linkid; 4173 state.vs_link_id = dev_linkid; 4174 state.vs_etherstub = etherstub; 4175 state.vs_found = B_FALSE; 4176 state.vs_flags = flags; 4177 4178 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) { 4179 if (etherstub) 4180 fields_str = all_e_fields; 4181 } 4182 pf = vnic_fields; 4183 4184 if (state.vs_parsable) 4185 ofmtflags |= OFMT_PARSABLE; 4186 oferr = ofmt_open(fields_str, pf, ofmtflags, 0, &ofmt); 4187 dladm_ofmt_check(oferr, state.vs_parsable, ofmt); 4188 state.vs_ofmt = ofmt; 4189 4190 if (s_arg) { 4191 /* Display vnic statistics */ 4192 vnic_stats(&state, interval); 4193 ofmt_close(ofmt); 4194 return; 4195 } 4196 4197 /* Display vnic information */ 4198 state.vs_donefirst = B_FALSE; 4199 4200 if (linkid == DATALINK_ALL_LINKID) { 4201 (void) dladm_walk_datalink_id(show_vnic, handle, &state, 4202 DATALINK_CLASS_VNIC | DATALINK_CLASS_ETHERSTUB, 4203 DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE); 4204 } else { 4205 (void) show_vnic(handle, linkid, &state); 4206 if (state.vs_status != DLADM_STATUS_OK) { 4207 ofmt_close(ofmt); 4208 die_dlerr(state.vs_status, "failed to show vnic '%s'", 4209 state.vs_vnic); 4210 } 4211 } 4212 ofmt_close(ofmt); 4213 } 4214 4215 static void 4216 do_show_vnic(int argc, char *argv[], const char *use) 4217 { 4218 do_show_vnic_common(argc, argv, use, B_FALSE); 4219 } 4220 4221 static void 4222 do_create_etherstub(int argc, char *argv[], const char *use) 4223 { 4224 uint32_t flags; 4225 char *altroot = NULL; 4226 char option; 4227 dladm_status_t status; 4228 char name[MAXLINKNAMELEN]; 4229 uchar_t mac_addr[ETHERADDRL]; 4230 4231 name[0] = '\0'; 4232 bzero(mac_addr, sizeof (mac_addr)); 4233 flags = DLADM_OPT_ANCHOR | DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 4234 4235 opterr = 0; 4236 while ((option = getopt_long(argc, argv, "tR:", 4237 etherstub_lopts, NULL)) != -1) { 4238 switch (option) { 4239 case 't': 4240 flags &= ~DLADM_OPT_PERSIST; 4241 break; 4242 case 'R': 4243 altroot = optarg; 4244 break; 4245 default: 4246 die_opterr(optopt, option, use); 4247 } 4248 } 4249 4250 /* the etherstub id is the required operand */ 4251 if (optind != (argc - 1)) 4252 usage(); 4253 4254 if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= MAXLINKNAMELEN) 4255 die("link name too long '%s'", argv[optind]); 4256 4257 if (!dladm_valid_linkname(name)) 4258 die("invalid link name '%s'", argv[optind]); 4259 4260 if (altroot != NULL) 4261 altroot_cmd(altroot, argc, argv); 4262 4263 status = dladm_vnic_create(handle, name, DATALINK_INVALID_LINKID, 4264 VNIC_MAC_ADDR_TYPE_AUTO, mac_addr, ETHERADDRL, NULL, 0, 0, NULL, 4265 NULL, flags); 4266 if (status != DLADM_STATUS_OK) 4267 die_dlerr(status, "etherstub creation failed"); 4268 4269 4270 } 4271 4272 static void 4273 do_delete_etherstub(int argc, char *argv[], const char *use) 4274 { 4275 do_delete_vnic_common(argc, argv, use, B_TRUE); 4276 } 4277 4278 /* ARGSUSED */ 4279 static void 4280 do_show_etherstub(int argc, char *argv[], const char *use) 4281 { 4282 do_show_vnic_common(argc, argv, use, B_TRUE); 4283 } 4284 4285 static void 4286 link_stats(datalink_id_t linkid, uint_t interval, char *fields_str, 4287 show_state_t *state) 4288 { 4289 ofmt_handle_t ofmt; 4290 ofmt_status_t oferr; 4291 uint_t ofmtflags = 0; 4292 4293 if (state->ls_parsable) 4294 ofmtflags |= OFMT_PARSABLE; 4295 oferr = ofmt_open(fields_str, link_s_fields, ofmtflags, 0, &ofmt); 4296 dladm_ofmt_check(oferr, state->ls_parsable, ofmt); 4297 state->ls_ofmt = ofmt; 4298 4299 /* 4300 * If an interval is specified, continuously show the stats 4301 * only for the first MAC port. 4302 */ 4303 state->ls_firstonly = (interval != 0); 4304 4305 for (;;) { 4306 state->ls_donefirst = B_FALSE; 4307 if (linkid == DATALINK_ALL_LINKID) { 4308 (void) dladm_walk_datalink_id(show_link_stats, handle, 4309 state, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, 4310 DLADM_OPT_ACTIVE); 4311 } else { 4312 (void) show_link_stats(handle, linkid, state); 4313 } 4314 4315 if (interval == 0) 4316 break; 4317 4318 (void) sleep(interval); 4319 } 4320 ofmt_close(ofmt); 4321 } 4322 4323 static void 4324 aggr_stats(datalink_id_t linkid, show_grp_state_t *state, uint_t interval) 4325 { 4326 /* 4327 * If an interval is specified, continuously show the stats 4328 * only for the first group. 4329 */ 4330 state->gs_firstonly = (interval != 0); 4331 4332 for (;;) { 4333 state->gs_donefirst = B_FALSE; 4334 if (linkid == DATALINK_ALL_LINKID) 4335 (void) dladm_walk_datalink_id(show_aggr, handle, state, 4336 DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, 4337 DLADM_OPT_ACTIVE); 4338 else 4339 (void) show_aggr(handle, linkid, state); 4340 4341 if (interval == 0) 4342 break; 4343 4344 (void) sleep(interval); 4345 } 4346 } 4347 4348 /* ARGSUSED */ 4349 static void 4350 vnic_stats(show_vnic_state_t *sp, uint32_t interval) 4351 { 4352 show_vnic_state_t state; 4353 boolean_t specific_link, specific_dev; 4354 4355 /* Display vnic statistics */ 4356 dump_vnics_head(sp->vs_link); 4357 4358 bzero(&state, sizeof (state)); 4359 state.vs_stats = B_TRUE; 4360 state.vs_vnic_id = sp->vs_vnic_id; 4361 state.vs_link_id = sp->vs_link_id; 4362 4363 /* 4364 * If an interval is specified, and a vnic ID is not specified, 4365 * continuously show the stats only for the first vnic. 4366 */ 4367 specific_link = (sp->vs_vnic_id != DATALINK_ALL_LINKID); 4368 specific_dev = (sp->vs_link_id != DATALINK_ALL_LINKID); 4369 4370 for (;;) { 4371 /* Get stats for each vnic */ 4372 state.vs_found = B_FALSE; 4373 state.vs_donefirst = B_FALSE; 4374 state.vs_printstats = B_FALSE; 4375 state.vs_flags = DLADM_OPT_ACTIVE; 4376 4377 if (!specific_link) { 4378 (void) dladm_walk_datalink_id(show_vnic, handle, &state, 4379 DATALINK_CLASS_VNIC, DATALINK_ANY_MEDIATYPE, 4380 DLADM_OPT_ACTIVE); 4381 } else { 4382 (void) show_vnic(handle, sp->vs_vnic_id, &state); 4383 if (state.vs_status != DLADM_STATUS_OK) { 4384 die_dlerr(state.vs_status, 4385 "failed to show vnic '%s'", sp->vs_vnic); 4386 } 4387 } 4388 4389 if (specific_link && !state.vs_found) 4390 die("non-existent vnic '%s'", sp->vs_vnic); 4391 if (specific_dev && !state.vs_found) 4392 die("device %s has no vnics", sp->vs_link); 4393 4394 /* Show totals */ 4395 if ((specific_link | specific_dev) && !interval) { 4396 (void) printf("Total"); 4397 (void) printf("\t%-10llu", 4398 state.vs_totalstats.ipackets); 4399 (void) printf("%-12llu", 4400 state.vs_totalstats.rbytes); 4401 (void) printf("%-10llu", 4402 state.vs_totalstats.opackets); 4403 (void) printf("%-12llu\n", 4404 state.vs_totalstats.obytes); 4405 } 4406 4407 /* Show stats for each vnic */ 4408 state.vs_donefirst = B_FALSE; 4409 state.vs_printstats = B_TRUE; 4410 4411 if (!specific_link) { 4412 (void) dladm_walk_datalink_id(show_vnic, handle, &state, 4413 DATALINK_CLASS_VNIC, DATALINK_ANY_MEDIATYPE, 4414 DLADM_OPT_ACTIVE); 4415 } else { 4416 (void) show_vnic(handle, sp->vs_vnic_id, &state); 4417 if (state.vs_status != DLADM_STATUS_OK) { 4418 die_dlerr(state.vs_status, 4419 "failed to show vnic '%s'", sp->vs_vnic); 4420 } 4421 } 4422 4423 if (interval == 0) 4424 break; 4425 4426 (void) sleep(interval); 4427 } 4428 } 4429 4430 static void 4431 get_mac_stats(const char *dev, pktsum_t *stats) 4432 { 4433 kstat_ctl_t *kcp; 4434 kstat_t *ksp; 4435 char module[DLPI_LINKNAME_MAX]; 4436 uint_t instance; 4437 4438 4439 bzero(stats, sizeof (*stats)); 4440 4441 if (dlpi_parselink(dev, module, &instance) != DLPI_SUCCESS) 4442 return; 4443 4444 if ((kcp = kstat_open()) == NULL) { 4445 warn("kstat open operation failed"); 4446 return; 4447 } 4448 4449 ksp = dladm_kstat_lookup(kcp, module, instance, "mac", NULL); 4450 if (ksp != NULL) 4451 dladm_get_stats(kcp, ksp, stats); 4452 4453 (void) kstat_close(kcp); 4454 4455 } 4456 4457 static void 4458 get_link_stats(const char *link, pktsum_t *stats) 4459 { 4460 kstat_ctl_t *kcp; 4461 kstat_t *ksp; 4462 4463 bzero(stats, sizeof (*stats)); 4464 4465 if ((kcp = kstat_open()) == NULL) { 4466 warn("kstat_open operation failed"); 4467 return; 4468 } 4469 4470 ksp = dladm_kstat_lookup(kcp, "link", 0, link, NULL); 4471 4472 if (ksp != NULL) 4473 dladm_get_stats(kcp, ksp, stats); 4474 4475 (void) kstat_close(kcp); 4476 } 4477 4478 static int 4479 query_kstat(char *module, int instance, const char *name, const char *stat, 4480 uint8_t type, void *val) 4481 { 4482 kstat_ctl_t *kcp; 4483 kstat_t *ksp; 4484 4485 if ((kcp = kstat_open()) == NULL) { 4486 warn("kstat open operation failed"); 4487 return (-1); 4488 } 4489 4490 if ((ksp = kstat_lookup(kcp, module, instance, (char *)name)) == NULL) { 4491 /* 4492 * The kstat query could fail if the underlying MAC 4493 * driver was already detached. 4494 */ 4495 goto bail; 4496 } 4497 4498 if (kstat_read(kcp, ksp, NULL) == -1) { 4499 warn("kstat read failed"); 4500 goto bail; 4501 } 4502 4503 if (dladm_kstat_value(ksp, stat, type, val) < 0) 4504 goto bail; 4505 4506 (void) kstat_close(kcp); 4507 return (0); 4508 4509 bail: 4510 (void) kstat_close(kcp); 4511 return (-1); 4512 } 4513 4514 static int 4515 get_one_kstat(const char *name, const char *stat, uint8_t type, 4516 void *val, boolean_t islink) 4517 { 4518 char module[DLPI_LINKNAME_MAX]; 4519 uint_t instance; 4520 4521 if (islink) { 4522 return (query_kstat("link", 0, name, stat, type, val)); 4523 } else { 4524 if (dlpi_parselink(name, module, &instance) != DLPI_SUCCESS) 4525 return (-1); 4526 4527 return (query_kstat(module, instance, "mac", stat, type, val)); 4528 } 4529 } 4530 4531 static uint64_t 4532 get_ifspeed(const char *name, boolean_t islink) 4533 { 4534 uint64_t ifspeed = 0; 4535 4536 (void) get_one_kstat(name, "ifspeed", KSTAT_DATA_UINT64, 4537 &ifspeed, islink); 4538 4539 return (ifspeed); 4540 } 4541 4542 static const char * 4543 get_linkstate(const char *name, boolean_t islink, char *buf) 4544 { 4545 link_state_t linkstate; 4546 4547 if (get_one_kstat(name, "link_state", KSTAT_DATA_UINT32, 4548 &linkstate, islink) != 0) { 4549 (void) strlcpy(buf, "?", DLADM_STRSIZE); 4550 return (buf); 4551 } 4552 return (dladm_linkstate2str(linkstate, buf)); 4553 } 4554 4555 static const char * 4556 get_linkduplex(const char *name, boolean_t islink, char *buf) 4557 { 4558 link_duplex_t linkduplex; 4559 4560 if (get_one_kstat(name, "link_duplex", KSTAT_DATA_UINT32, 4561 &linkduplex, islink) != 0) { 4562 (void) strlcpy(buf, "unknown", DLADM_STRSIZE); 4563 return (buf); 4564 } 4565 4566 return (dladm_linkduplex2str(linkduplex, buf)); 4567 } 4568 4569 static int 4570 parse_wifi_fields(char *str, ofmt_handle_t *ofmt, uint_t cmdtype, 4571 boolean_t parsable) 4572 { 4573 ofmt_field_t *template, *of; 4574 ofmt_cb_t *fn; 4575 ofmt_status_t oferr; 4576 4577 if (cmdtype == WIFI_CMD_SCAN) { 4578 template = wifi_common_fields; 4579 if (str == NULL) 4580 str = def_scan_wifi_fields; 4581 if (strcasecmp(str, "all") == 0) 4582 str = all_scan_wifi_fields; 4583 fn = print_wlan_attr_cb; 4584 } else if (cmdtype == WIFI_CMD_SHOW) { 4585 bcopy(wifi_common_fields, &wifi_show_fields[2], 4586 sizeof (wifi_common_fields)); 4587 template = wifi_show_fields; 4588 if (str == NULL) 4589 str = def_show_wifi_fields; 4590 if (strcasecmp(str, "all") == 0) 4591 str = all_show_wifi_fields; 4592 fn = print_link_attr_cb; 4593 } else { 4594 return (-1); 4595 } 4596 4597 for (of = template; of->of_name != NULL; of++) { 4598 if (of->of_cb == NULL) 4599 of->of_cb = fn; 4600 } 4601 4602 oferr = ofmt_open(str, template, (parsable ? OFMT_PARSABLE : 0), 4603 0, ofmt); 4604 dladm_ofmt_check(oferr, parsable, *ofmt); 4605 return (0); 4606 } 4607 4608 typedef struct print_wifi_state { 4609 char *ws_link; 4610 boolean_t ws_parsable; 4611 boolean_t ws_header; 4612 ofmt_handle_t ws_ofmt; 4613 } print_wifi_state_t; 4614 4615 typedef struct wlan_scan_args_s { 4616 print_wifi_state_t *ws_state; 4617 void *ws_attr; 4618 } wlan_scan_args_t; 4619 4620 static boolean_t 4621 print_wlan_attr_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 4622 { 4623 wlan_scan_args_t *w = ofarg->ofmt_cbarg; 4624 print_wifi_state_t *statep = w->ws_state; 4625 dladm_wlan_attr_t *attrp = w->ws_attr; 4626 char tmpbuf[DLADM_STRSIZE]; 4627 4628 if (ofarg->ofmt_id == 0) { 4629 (void) strlcpy(buf, (char *)statep->ws_link, bufsize); 4630 return (B_TRUE); 4631 } 4632 4633 if ((ofarg->ofmt_id & attrp->wa_valid) == 0) 4634 return (B_TRUE); 4635 4636 switch (ofarg->ofmt_id) { 4637 case DLADM_WLAN_ATTR_ESSID: 4638 (void) dladm_wlan_essid2str(&attrp->wa_essid, tmpbuf); 4639 break; 4640 case DLADM_WLAN_ATTR_BSSID: 4641 (void) dladm_wlan_bssid2str(&attrp->wa_bssid, tmpbuf); 4642 break; 4643 case DLADM_WLAN_ATTR_SECMODE: 4644 (void) dladm_wlan_secmode2str(&attrp->wa_secmode, tmpbuf); 4645 break; 4646 case DLADM_WLAN_ATTR_STRENGTH: 4647 (void) dladm_wlan_strength2str(&attrp->wa_strength, tmpbuf); 4648 break; 4649 case DLADM_WLAN_ATTR_MODE: 4650 (void) dladm_wlan_mode2str(&attrp->wa_mode, tmpbuf); 4651 break; 4652 case DLADM_WLAN_ATTR_SPEED: 4653 (void) dladm_wlan_speed2str(&attrp->wa_speed, tmpbuf); 4654 (void) strlcat(tmpbuf, "Mb", sizeof (tmpbuf)); 4655 break; 4656 case DLADM_WLAN_ATTR_AUTH: 4657 (void) dladm_wlan_auth2str(&attrp->wa_auth, tmpbuf); 4658 break; 4659 case DLADM_WLAN_ATTR_BSSTYPE: 4660 (void) dladm_wlan_bsstype2str(&attrp->wa_bsstype, tmpbuf); 4661 break; 4662 } 4663 (void) strlcpy(buf, tmpbuf, bufsize); 4664 4665 return (B_TRUE); 4666 } 4667 4668 static boolean_t 4669 print_scan_results(void *arg, dladm_wlan_attr_t *attrp) 4670 { 4671 print_wifi_state_t *statep = arg; 4672 wlan_scan_args_t warg; 4673 4674 bzero(&warg, sizeof (warg)); 4675 warg.ws_state = statep; 4676 warg.ws_attr = attrp; 4677 ofmt_print(statep->ws_ofmt, &warg); 4678 return (B_TRUE); 4679 } 4680 4681 static int 4682 scan_wifi(dladm_handle_t dh, datalink_id_t linkid, void *arg) 4683 { 4684 print_wifi_state_t *statep = arg; 4685 dladm_status_t status; 4686 char link[MAXLINKNAMELEN]; 4687 4688 if ((status = dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, link, 4689 sizeof (link))) != DLADM_STATUS_OK) { 4690 return (DLADM_WALK_CONTINUE); 4691 } 4692 4693 statep->ws_link = link; 4694 status = dladm_wlan_scan(dh, linkid, statep, print_scan_results); 4695 if (status != DLADM_STATUS_OK) 4696 die_dlerr(status, "cannot scan link '%s'", statep->ws_link); 4697 4698 return (DLADM_WALK_CONTINUE); 4699 } 4700 4701 static boolean_t 4702 print_wifi_status_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 4703 { 4704 static char tmpbuf[DLADM_STRSIZE]; 4705 wlan_scan_args_t *w = ofarg->ofmt_cbarg; 4706 dladm_wlan_linkattr_t *attrp = w->ws_attr; 4707 4708 if ((ofarg->ofmt_id & attrp->la_valid) != 0) { 4709 (void) dladm_wlan_linkstatus2str(&attrp->la_status, tmpbuf); 4710 (void) strlcpy(buf, tmpbuf, bufsize); 4711 } 4712 return (B_TRUE); 4713 } 4714 4715 static boolean_t 4716 print_link_attr_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 4717 { 4718 wlan_scan_args_t *w = ofarg->ofmt_cbarg, w1; 4719 print_wifi_state_t *statep = w->ws_state; 4720 dladm_wlan_linkattr_t *attrp = w->ws_attr; 4721 4722 bzero(&w1, sizeof (w1)); 4723 w1.ws_state = statep; 4724 w1.ws_attr = &attrp->la_wlan_attr; 4725 ofarg->ofmt_cbarg = &w1; 4726 return (print_wlan_attr_cb(ofarg, buf, bufsize)); 4727 } 4728 4729 static int 4730 show_wifi(dladm_handle_t dh, datalink_id_t linkid, void *arg) 4731 { 4732 print_wifi_state_t *statep = arg; 4733 dladm_wlan_linkattr_t attr; 4734 dladm_status_t status; 4735 char link[MAXLINKNAMELEN]; 4736 wlan_scan_args_t warg; 4737 4738 if ((status = dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, link, 4739 sizeof (link))) != DLADM_STATUS_OK) { 4740 return (DLADM_WALK_CONTINUE); 4741 } 4742 4743 /* dladm_wlan_get_linkattr() memsets attr with 0 */ 4744 status = dladm_wlan_get_linkattr(dh, linkid, &attr); 4745 if (status != DLADM_STATUS_OK) 4746 die_dlerr(status, "cannot get link attributes for %s", link); 4747 4748 statep->ws_link = link; 4749 4750 bzero(&warg, sizeof (warg)); 4751 warg.ws_state = statep; 4752 warg.ws_attr = &attr; 4753 ofmt_print(statep->ws_ofmt, &warg); 4754 return (DLADM_WALK_CONTINUE); 4755 } 4756 4757 static void 4758 do_display_wifi(int argc, char **argv, int cmd, const char *use) 4759 { 4760 int option; 4761 char *fields_str = NULL; 4762 int (*callback)(dladm_handle_t, datalink_id_t, void *); 4763 print_wifi_state_t state; 4764 datalink_id_t linkid = DATALINK_ALL_LINKID; 4765 dladm_status_t status; 4766 4767 if (cmd == WIFI_CMD_SCAN) 4768 callback = scan_wifi; 4769 else if (cmd == WIFI_CMD_SHOW) 4770 callback = show_wifi; 4771 else 4772 return; 4773 4774 state.ws_parsable = B_FALSE; 4775 state.ws_header = B_TRUE; 4776 opterr = 0; 4777 while ((option = getopt_long(argc, argv, ":o:p", 4778 wifi_longopts, NULL)) != -1) { 4779 switch (option) { 4780 case 'o': 4781 fields_str = optarg; 4782 break; 4783 case 'p': 4784 state.ws_parsable = B_TRUE; 4785 break; 4786 default: 4787 die_opterr(optopt, option, use); 4788 } 4789 } 4790 4791 if (state.ws_parsable && fields_str == NULL) 4792 die("-p requires -o"); 4793 4794 if (state.ws_parsable && strcasecmp(fields_str, "all") == 0) 4795 die("\"-o all\" is invalid with -p"); 4796 4797 if (optind == (argc - 1)) { 4798 if ((status = dladm_name2info(handle, argv[optind], &linkid, 4799 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 4800 die_dlerr(status, "link %s is not valid", argv[optind]); 4801 } 4802 } else if (optind != argc) { 4803 usage(); 4804 } 4805 4806 if (parse_wifi_fields(fields_str, &state.ws_ofmt, cmd, 4807 state.ws_parsable) < 0) 4808 die("invalid field(s) specified"); 4809 4810 if (linkid == DATALINK_ALL_LINKID) { 4811 (void) dladm_walk_datalink_id(callback, handle, &state, 4812 DATALINK_CLASS_PHYS, DL_WIFI, DLADM_OPT_ACTIVE); 4813 } else { 4814 (void) (*callback)(handle, linkid, &state); 4815 } 4816 ofmt_close(state.ws_ofmt); 4817 } 4818 4819 static void 4820 do_scan_wifi(int argc, char **argv, const char *use) 4821 { 4822 do_display_wifi(argc, argv, WIFI_CMD_SCAN, use); 4823 } 4824 4825 static void 4826 do_show_wifi(int argc, char **argv, const char *use) 4827 { 4828 do_display_wifi(argc, argv, WIFI_CMD_SHOW, use); 4829 } 4830 4831 typedef struct wlan_count_attr { 4832 uint_t wc_count; 4833 datalink_id_t wc_linkid; 4834 } wlan_count_attr_t; 4835 4836 /* ARGSUSED */ 4837 static int 4838 do_count_wlan(dladm_handle_t dh, datalink_id_t linkid, void *arg) 4839 { 4840 wlan_count_attr_t *cp = arg; 4841 4842 if (cp->wc_count == 0) 4843 cp->wc_linkid = linkid; 4844 cp->wc_count++; 4845 return (DLADM_WALK_CONTINUE); 4846 } 4847 4848 static int 4849 parse_wlan_keys(char *str, dladm_wlan_key_t **keys, uint_t *key_countp) 4850 { 4851 uint_t i; 4852 dladm_wlan_key_t *wk; 4853 int nfields = 1; 4854 char *field, *token, *lasts = NULL, c; 4855 4856 token = str; 4857 while ((c = *token++) != NULL) { 4858 if (c == ',') 4859 nfields++; 4860 } 4861 token = strdup(str); 4862 if (token == NULL) 4863 return (-1); 4864 4865 wk = malloc(nfields * sizeof (dladm_wlan_key_t)); 4866 if (wk == NULL) 4867 goto fail; 4868 4869 token = str; 4870 for (i = 0; i < nfields; i++) { 4871 char *s; 4872 dladm_secobj_class_t class; 4873 dladm_status_t status; 4874 4875 field = strtok_r(token, ",", &lasts); 4876 token = NULL; 4877 4878 (void) strlcpy(wk[i].wk_name, field, 4879 DLADM_WLAN_MAX_KEYNAME_LEN); 4880 4881 wk[i].wk_idx = 1; 4882 if ((s = strrchr(wk[i].wk_name, ':')) != NULL) { 4883 if (s[1] == '\0' || s[2] != '\0' || !isdigit(s[1])) 4884 goto fail; 4885 4886 wk[i].wk_idx = (uint_t)(s[1] - '0'); 4887 *s = '\0'; 4888 } 4889 wk[i].wk_len = DLADM_WLAN_MAX_KEY_LEN; 4890 4891 status = dladm_get_secobj(handle, wk[i].wk_name, &class, 4892 wk[i].wk_val, &wk[i].wk_len, 0); 4893 if (status != DLADM_STATUS_OK) { 4894 if (status == DLADM_STATUS_NOTFOUND) { 4895 status = dladm_get_secobj(handle, wk[i].wk_name, 4896 &class, wk[i].wk_val, &wk[i].wk_len, 4897 DLADM_OPT_PERSIST); 4898 } 4899 if (status != DLADM_STATUS_OK) 4900 goto fail; 4901 } 4902 wk[i].wk_class = class; 4903 } 4904 *keys = wk; 4905 *key_countp = i; 4906 free(token); 4907 return (0); 4908 fail: 4909 free(wk); 4910 free(token); 4911 return (-1); 4912 } 4913 4914 static void 4915 do_connect_wifi(int argc, char **argv, const char *use) 4916 { 4917 int option; 4918 dladm_wlan_attr_t attr, *attrp; 4919 dladm_status_t status = DLADM_STATUS_OK; 4920 int timeout = DLADM_WLAN_CONNECT_TIMEOUT_DEFAULT; 4921 datalink_id_t linkid = DATALINK_ALL_LINKID; 4922 dladm_wlan_key_t *keys = NULL; 4923 uint_t key_count = 0; 4924 uint_t flags = 0; 4925 dladm_wlan_secmode_t keysecmode = DLADM_WLAN_SECMODE_NONE; 4926 char buf[DLADM_STRSIZE]; 4927 4928 opterr = 0; 4929 (void) memset(&attr, 0, sizeof (attr)); 4930 while ((option = getopt_long(argc, argv, ":e:i:a:m:b:s:k:T:c", 4931 wifi_longopts, NULL)) != -1) { 4932 switch (option) { 4933 case 'e': 4934 status = dladm_wlan_str2essid(optarg, &attr.wa_essid); 4935 if (status != DLADM_STATUS_OK) 4936 die("invalid ESSID '%s'", optarg); 4937 4938 attr.wa_valid |= DLADM_WLAN_ATTR_ESSID; 4939 /* 4940 * Try to connect without doing a scan. 4941 */ 4942 flags |= DLADM_WLAN_CONNECT_NOSCAN; 4943 break; 4944 case 'i': 4945 status = dladm_wlan_str2bssid(optarg, &attr.wa_bssid); 4946 if (status != DLADM_STATUS_OK) 4947 die("invalid BSSID %s", optarg); 4948 4949 attr.wa_valid |= DLADM_WLAN_ATTR_BSSID; 4950 break; 4951 case 'a': 4952 status = dladm_wlan_str2auth(optarg, &attr.wa_auth); 4953 if (status != DLADM_STATUS_OK) 4954 die("invalid authentication mode '%s'", optarg); 4955 4956 attr.wa_valid |= DLADM_WLAN_ATTR_AUTH; 4957 break; 4958 case 'm': 4959 status = dladm_wlan_str2mode(optarg, &attr.wa_mode); 4960 if (status != DLADM_STATUS_OK) 4961 die("invalid mode '%s'", optarg); 4962 4963 attr.wa_valid |= DLADM_WLAN_ATTR_MODE; 4964 break; 4965 case 'b': 4966 if ((status = dladm_wlan_str2bsstype(optarg, 4967 &attr.wa_bsstype)) != DLADM_STATUS_OK) { 4968 die("invalid bsstype '%s'", optarg); 4969 } 4970 4971 attr.wa_valid |= DLADM_WLAN_ATTR_BSSTYPE; 4972 break; 4973 case 's': 4974 if ((status = dladm_wlan_str2secmode(optarg, 4975 &attr.wa_secmode)) != DLADM_STATUS_OK) { 4976 die("invalid security mode '%s'", optarg); 4977 } 4978 4979 attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE; 4980 break; 4981 case 'k': 4982 if (parse_wlan_keys(optarg, &keys, &key_count) < 0) 4983 die("invalid key(s) '%s'", optarg); 4984 4985 if (keys[0].wk_class == DLADM_SECOBJ_CLASS_WEP) 4986 keysecmode = DLADM_WLAN_SECMODE_WEP; 4987 else 4988 keysecmode = DLADM_WLAN_SECMODE_WPA; 4989 break; 4990 case 'T': 4991 if (strcasecmp(optarg, "forever") == 0) { 4992 timeout = -1; 4993 break; 4994 } 4995 if (!str2int(optarg, &timeout) || timeout < 0) 4996 die("invalid timeout value '%s'", optarg); 4997 break; 4998 case 'c': 4999 flags |= DLADM_WLAN_CONNECT_CREATEIBSS; 5000 flags |= DLADM_WLAN_CONNECT_CREATEIBSS; 5001 break; 5002 default: 5003 die_opterr(optopt, option, use); 5004 break; 5005 } 5006 } 5007 5008 if (keysecmode == DLADM_WLAN_SECMODE_NONE) { 5009 if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0) { 5010 die("key required for security mode '%s'", 5011 dladm_wlan_secmode2str(&attr.wa_secmode, buf)); 5012 } 5013 } else { 5014 if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0 && 5015 attr.wa_secmode != keysecmode) 5016 die("incompatible -s and -k options"); 5017 attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE; 5018 attr.wa_secmode = keysecmode; 5019 } 5020 5021 if (optind == (argc - 1)) { 5022 if ((status = dladm_name2info(handle, argv[optind], &linkid, 5023 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 5024 die_dlerr(status, "link %s is not valid", argv[optind]); 5025 } 5026 } else if (optind != argc) { 5027 usage(); 5028 } 5029 5030 if (linkid == DATALINK_ALL_LINKID) { 5031 wlan_count_attr_t wcattr; 5032 5033 wcattr.wc_linkid = DATALINK_INVALID_LINKID; 5034 wcattr.wc_count = 0; 5035 (void) dladm_walk_datalink_id(do_count_wlan, handle, &wcattr, 5036 DATALINK_CLASS_PHYS, DL_WIFI, DLADM_OPT_ACTIVE); 5037 if (wcattr.wc_count == 0) { 5038 die("no wifi links are available"); 5039 } else if (wcattr.wc_count > 1) { 5040 die("link name is required when more than one wifi " 5041 "link is available"); 5042 } 5043 linkid = wcattr.wc_linkid; 5044 } 5045 attrp = (attr.wa_valid == 0) ? NULL : &attr; 5046 again: 5047 if ((status = dladm_wlan_connect(handle, linkid, attrp, timeout, keys, 5048 key_count, flags)) != DLADM_STATUS_OK) { 5049 if ((flags & DLADM_WLAN_CONNECT_NOSCAN) != 0) { 5050 /* 5051 * Try again with scanning and filtering. 5052 */ 5053 flags &= ~DLADM_WLAN_CONNECT_NOSCAN; 5054 goto again; 5055 } 5056 5057 if (status == DLADM_STATUS_NOTFOUND) { 5058 if (attr.wa_valid == 0) { 5059 die("no wifi networks are available"); 5060 } else { 5061 die("no wifi networks with the specified " 5062 "criteria are available"); 5063 } 5064 } 5065 die_dlerr(status, "cannot connect"); 5066 } 5067 free(keys); 5068 } 5069 5070 /* ARGSUSED */ 5071 static int 5072 do_all_disconnect_wifi(dladm_handle_t dh, datalink_id_t linkid, void *arg) 5073 { 5074 dladm_status_t status; 5075 5076 status = dladm_wlan_disconnect(dh, linkid); 5077 if (status != DLADM_STATUS_OK) 5078 warn_dlerr(status, "cannot disconnect link"); 5079 5080 return (DLADM_WALK_CONTINUE); 5081 } 5082 5083 static void 5084 do_disconnect_wifi(int argc, char **argv, const char *use) 5085 { 5086 int option; 5087 datalink_id_t linkid = DATALINK_ALL_LINKID; 5088 boolean_t all_links = B_FALSE; 5089 dladm_status_t status; 5090 wlan_count_attr_t wcattr; 5091 5092 opterr = 0; 5093 while ((option = getopt_long(argc, argv, ":a", 5094 wifi_longopts, NULL)) != -1) { 5095 switch (option) { 5096 case 'a': 5097 all_links = B_TRUE; 5098 break; 5099 default: 5100 die_opterr(optopt, option, use); 5101 break; 5102 } 5103 } 5104 5105 if (optind == (argc - 1)) { 5106 if ((status = dladm_name2info(handle, argv[optind], &linkid, 5107 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 5108 die_dlerr(status, "link %s is not valid", argv[optind]); 5109 } 5110 } else if (optind != argc) { 5111 usage(); 5112 } 5113 5114 if (linkid == DATALINK_ALL_LINKID) { 5115 if (!all_links) { 5116 wcattr.wc_linkid = linkid; 5117 wcattr.wc_count = 0; 5118 (void) dladm_walk_datalink_id(do_count_wlan, handle, 5119 &wcattr, DATALINK_CLASS_PHYS, DL_WIFI, 5120 DLADM_OPT_ACTIVE); 5121 if (wcattr.wc_count == 0) { 5122 die("no wifi links are available"); 5123 } else if (wcattr.wc_count > 1) { 5124 die("link name is required when more than " 5125 "one wifi link is available"); 5126 } 5127 linkid = wcattr.wc_linkid; 5128 } else { 5129 (void) dladm_walk_datalink_id(do_all_disconnect_wifi, 5130 handle, NULL, DATALINK_CLASS_PHYS, DL_WIFI, 5131 DLADM_OPT_ACTIVE); 5132 return; 5133 } 5134 } 5135 status = dladm_wlan_disconnect(handle, linkid); 5136 if (status != DLADM_STATUS_OK) 5137 die_dlerr(status, "cannot disconnect"); 5138 } 5139 5140 static void 5141 print_linkprop(datalink_id_t linkid, show_linkprop_state_t *statep, 5142 const char *propname, dladm_prop_type_t type, const char *format, 5143 char **pptr) 5144 { 5145 int i; 5146 char *ptr, *lim; 5147 char buf[DLADM_STRSIZE]; 5148 char *unknown = "--", *notsup = ""; 5149 char **propvals = statep->ls_propvals; 5150 uint_t valcnt = DLADM_MAX_PROP_VALCNT; 5151 dladm_status_t status; 5152 5153 status = dladm_get_linkprop(handle, linkid, type, propname, propvals, 5154 &valcnt); 5155 if (status != DLADM_STATUS_OK) { 5156 if (status == DLADM_STATUS_TEMPONLY) { 5157 if (type == DLADM_PROP_VAL_MODIFIABLE && 5158 statep->ls_persist) { 5159 valcnt = 1; 5160 propvals = &unknown; 5161 } else { 5162 statep->ls_status = status; 5163 statep->ls_retstatus = status; 5164 return; 5165 } 5166 } else if (status == DLADM_STATUS_NOTSUP || 5167 statep->ls_persist) { 5168 valcnt = 1; 5169 if (type == DLADM_PROP_VAL_CURRENT || 5170 type == DLADM_PROP_VAL_PERM) 5171 propvals = &unknown; 5172 else 5173 propvals = ¬sup; 5174 } else if (status == DLADM_STATUS_NOTDEFINED) { 5175 propvals = ¬sup; /* STR_UNDEF_VAL */ 5176 } else { 5177 if (statep->ls_proplist && 5178 statep->ls_status == DLADM_STATUS_OK) { 5179 warn_dlerr(status, 5180 "cannot get link property '%s' for %s", 5181 propname, statep->ls_link); 5182 } 5183 statep->ls_status = status; 5184 statep->ls_retstatus = status; 5185 return; 5186 } 5187 } 5188 5189 statep->ls_status = DLADM_STATUS_OK; 5190 5191 ptr = buf; 5192 lim = buf + DLADM_STRSIZE; 5193 for (i = 0; i < valcnt; i++) { 5194 if (propvals[i][0] == '\0' && !statep->ls_parsable) 5195 ptr += snprintf(ptr, lim - ptr, "--,"); 5196 else 5197 ptr += snprintf(ptr, lim - ptr, "%s,", propvals[i]); 5198 if (ptr >= lim) 5199 break; 5200 } 5201 if (valcnt > 0) 5202 buf[strlen(buf) - 1] = '\0'; 5203 5204 lim = statep->ls_line + MAX_PROP_LINE; 5205 if (statep->ls_parsable) { 5206 *pptr += snprintf(*pptr, lim - *pptr, 5207 "%s", buf); 5208 } else { 5209 *pptr += snprintf(*pptr, lim - *pptr, format, buf); 5210 } 5211 } 5212 5213 static boolean_t 5214 print_linkprop_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 5215 { 5216 linkprop_args_t *arg = ofarg->ofmt_cbarg; 5217 char *propname = arg->ls_propname; 5218 show_linkprop_state_t *statep = arg->ls_state; 5219 char *ptr = statep->ls_line; 5220 char *lim = ptr + MAX_PROP_LINE; 5221 datalink_id_t linkid = arg->ls_linkid; 5222 5223 switch (ofarg->ofmt_id) { 5224 case LINKPROP_LINK: 5225 (void) snprintf(ptr, lim - ptr, "%s", statep->ls_link); 5226 break; 5227 case LINKPROP_PROPERTY: 5228 (void) snprintf(ptr, lim - ptr, "%s", propname); 5229 break; 5230 case LINKPROP_VALUE: 5231 print_linkprop(linkid, statep, propname, 5232 statep->ls_persist ? DLADM_PROP_VAL_PERSISTENT : 5233 DLADM_PROP_VAL_CURRENT, "%s", &ptr); 5234 /* 5235 * If we failed to query the link property, for example, query 5236 * the persistent value of a non-persistable link property, 5237 * simply skip the output. 5238 */ 5239 if (statep->ls_status != DLADM_STATUS_OK) 5240 goto skip; 5241 ptr = statep->ls_line; 5242 break; 5243 case LINKPROP_PERM: 5244 print_linkprop(linkid, statep, propname, 5245 DLADM_PROP_VAL_PERM, "%s", &ptr); 5246 if (statep->ls_status != DLADM_STATUS_OK) 5247 goto skip; 5248 ptr = statep->ls_line; 5249 break; 5250 case LINKPROP_DEFAULT: 5251 print_linkprop(linkid, statep, propname, 5252 DLADM_PROP_VAL_DEFAULT, "%s", &ptr); 5253 if (statep->ls_status != DLADM_STATUS_OK) 5254 goto skip; 5255 ptr = statep->ls_line; 5256 break; 5257 case LINKPROP_POSSIBLE: 5258 print_linkprop(linkid, statep, propname, 5259 DLADM_PROP_VAL_MODIFIABLE, "%s ", &ptr); 5260 if (statep->ls_status != DLADM_STATUS_OK) 5261 goto skip; 5262 ptr = statep->ls_line; 5263 break; 5264 default: 5265 die("invalid input"); 5266 break; 5267 } 5268 (void) strlcpy(buf, ptr, bufsize); 5269 return (B_TRUE); 5270 skip: 5271 return ((statep->ls_status == DLADM_STATUS_OK) ? 5272 B_TRUE : B_FALSE); 5273 } 5274 5275 static boolean_t 5276 linkprop_is_supported(datalink_id_t linkid, const char *propname, 5277 show_linkprop_state_t *statep) 5278 { 5279 dladm_status_t status; 5280 uint_t valcnt = DLADM_MAX_PROP_VALCNT; 5281 5282 /* if used with -p flag, always print output */ 5283 if (statep->ls_proplist != NULL) 5284 return (B_TRUE); 5285 5286 status = dladm_get_linkprop(handle, linkid, DLADM_PROP_VAL_DEFAULT, 5287 propname, statep->ls_propvals, &valcnt); 5288 5289 if (status == DLADM_STATUS_OK) 5290 return (B_TRUE); 5291 5292 /* 5293 * A system wide default value is not available for the 5294 * property. Check if current value can be retrieved. 5295 */ 5296 status = dladm_get_linkprop(handle, linkid, DLADM_PROP_VAL_CURRENT, 5297 propname, statep->ls_propvals, &valcnt); 5298 5299 return (status == DLADM_STATUS_OK); 5300 } 5301 5302 /* ARGSUSED */ 5303 static int 5304 show_linkprop(dladm_handle_t dh, datalink_id_t linkid, const char *propname, 5305 void *arg) 5306 { 5307 show_linkprop_state_t *statep = arg; 5308 linkprop_args_t ls_arg; 5309 5310 bzero(&ls_arg, sizeof (ls_arg)); 5311 ls_arg.ls_state = statep; 5312 ls_arg.ls_propname = (char *)propname; 5313 ls_arg.ls_linkid = linkid; 5314 5315 /* 5316 * This will need to be fixed when kernel interfaces are added 5317 * to enable walking of all known private properties. For now, 5318 * we are limited to walking persistent private properties only. 5319 */ 5320 if ((propname[0] == '_') && !statep->ls_persist && 5321 (statep->ls_proplist == NULL)) 5322 return (DLADM_WALK_CONTINUE); 5323 if (!statep->ls_parsable && 5324 !linkprop_is_supported(linkid, propname, statep)) 5325 return (DLADM_WALK_CONTINUE); 5326 5327 ofmt_print(statep->ls_ofmt, &ls_arg); 5328 5329 return (DLADM_WALK_CONTINUE); 5330 } 5331 5332 static void 5333 do_show_linkprop(int argc, char **argv, const char *use) 5334 { 5335 int option; 5336 char propstr[DLADM_STRSIZE]; 5337 dladm_arg_list_t *proplist = NULL; 5338 datalink_id_t linkid = DATALINK_ALL_LINKID; 5339 show_linkprop_state_t state; 5340 uint32_t flags = DLADM_OPT_ACTIVE; 5341 dladm_status_t status; 5342 char *fields_str = NULL; 5343 ofmt_handle_t ofmt; 5344 ofmt_status_t oferr; 5345 uint_t ofmtflags = 0; 5346 5347 bzero(propstr, DLADM_STRSIZE); 5348 opterr = 0; 5349 state.ls_propvals = NULL; 5350 state.ls_line = NULL; 5351 state.ls_parsable = B_FALSE; 5352 state.ls_persist = B_FALSE; 5353 state.ls_header = B_TRUE; 5354 state.ls_retstatus = DLADM_STATUS_OK; 5355 5356 while ((option = getopt_long(argc, argv, ":p:cPo:", 5357 prop_longopts, NULL)) != -1) { 5358 switch (option) { 5359 case 'p': 5360 (void) strlcat(propstr, optarg, DLADM_STRSIZE); 5361 if (strlcat(propstr, ",", DLADM_STRSIZE) >= 5362 DLADM_STRSIZE) 5363 die("property list too long '%s'", propstr); 5364 break; 5365 case 'c': 5366 state.ls_parsable = B_TRUE; 5367 break; 5368 case 'P': 5369 state.ls_persist = B_TRUE; 5370 flags = DLADM_OPT_PERSIST; 5371 break; 5372 case 'o': 5373 fields_str = optarg; 5374 break; 5375 default: 5376 die_opterr(optopt, option, use); 5377 break; 5378 } 5379 } 5380 5381 if (optind == (argc - 1)) { 5382 if ((status = dladm_name2info(handle, argv[optind], &linkid, 5383 NULL, NULL, NULL)) != DLADM_STATUS_OK) { 5384 die_dlerr(status, "link %s is not valid", argv[optind]); 5385 } 5386 } else if (optind != argc) { 5387 usage(); 5388 } 5389 5390 if (dladm_parse_link_props(propstr, &proplist, B_TRUE) 5391 != DLADM_STATUS_OK) 5392 die("invalid link properties specified"); 5393 state.ls_proplist = proplist; 5394 state.ls_status = DLADM_STATUS_OK; 5395 5396 if (state.ls_parsable) 5397 ofmtflags |= OFMT_PARSABLE; 5398 oferr = ofmt_open(fields_str, linkprop_fields, ofmtflags, 0, &ofmt); 5399 dladm_ofmt_check(oferr, state.ls_parsable, ofmt); 5400 state.ls_ofmt = ofmt; 5401 5402 if (linkid == DATALINK_ALL_LINKID) { 5403 (void) dladm_walk_datalink_id(show_linkprop_onelink, handle, 5404 &state, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, flags); 5405 } else { 5406 (void) show_linkprop_onelink(handle, linkid, &state); 5407 } 5408 ofmt_close(ofmt); 5409 dladm_free_props(proplist); 5410 5411 if (state.ls_retstatus != DLADM_STATUS_OK) { 5412 dladm_close(handle); 5413 exit(EXIT_FAILURE); 5414 } 5415 } 5416 5417 static int 5418 show_linkprop_onelink(dladm_handle_t hdl, datalink_id_t linkid, void *arg) 5419 { 5420 int i; 5421 char *buf; 5422 uint32_t flags; 5423 dladm_arg_list_t *proplist = NULL; 5424 show_linkprop_state_t *statep = arg; 5425 dlpi_handle_t dh = NULL; 5426 5427 statep->ls_status = DLADM_STATUS_OK; 5428 5429 if (dladm_datalink_id2info(hdl, linkid, &flags, NULL, NULL, 5430 statep->ls_link, MAXLINKNAMELEN) != DLADM_STATUS_OK) { 5431 statep->ls_status = DLADM_STATUS_NOTFOUND; 5432 return (DLADM_WALK_CONTINUE); 5433 } 5434 5435 if ((statep->ls_persist && !(flags & DLADM_OPT_PERSIST)) || 5436 (!statep->ls_persist && !(flags & DLADM_OPT_ACTIVE))) { 5437 statep->ls_status = DLADM_STATUS_BADARG; 5438 return (DLADM_WALK_CONTINUE); 5439 } 5440 5441 proplist = statep->ls_proplist; 5442 5443 /* 5444 * When some WiFi links are opened for the first time, their hardware 5445 * automatically scans for APs and does other slow operations. Thus, 5446 * if there are no open links, the retrieval of link properties 5447 * (below) will proceed slowly unless we hold the link open. 5448 * 5449 * Note that failure of dlpi_open() does not necessarily mean invalid 5450 * link properties, because dlpi_open() may fail because of incorrect 5451 * autopush configuration. Therefore, we ingore the return value of 5452 * dlpi_open(). 5453 */ 5454 if (!statep->ls_persist) 5455 (void) dlpi_open(statep->ls_link, &dh, 0); 5456 5457 buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) * 5458 DLADM_MAX_PROP_VALCNT + MAX_PROP_LINE); 5459 if (buf == NULL) 5460 die("insufficient memory"); 5461 5462 statep->ls_propvals = (char **)(void *)buf; 5463 for (i = 0; i < DLADM_MAX_PROP_VALCNT; i++) { 5464 statep->ls_propvals[i] = buf + 5465 sizeof (char *) * DLADM_MAX_PROP_VALCNT + 5466 i * DLADM_PROP_VAL_MAX; 5467 } 5468 statep->ls_line = buf + 5469 (sizeof (char *) + DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT; 5470 5471 if (proplist != NULL) { 5472 for (i = 0; i < proplist->al_count; i++) { 5473 (void) show_linkprop(hdl, linkid, 5474 proplist->al_info[i].ai_name, statep); 5475 } 5476 } else { 5477 (void) dladm_walk_linkprop(hdl, linkid, statep, 5478 show_linkprop); 5479 } 5480 if (dh != NULL) 5481 dlpi_close(dh); 5482 free(buf); 5483 return (DLADM_WALK_CONTINUE); 5484 } 5485 5486 static dladm_status_t 5487 set_linkprop_persist(datalink_id_t linkid, const char *prop_name, 5488 char **prop_val, uint_t val_cnt, boolean_t reset) 5489 { 5490 dladm_status_t status; 5491 5492 status = dladm_set_linkprop(handle, linkid, prop_name, prop_val, 5493 val_cnt, DLADM_OPT_PERSIST); 5494 5495 if (status != DLADM_STATUS_OK) { 5496 warn_dlerr(status, "cannot persistently %s link property '%s'", 5497 reset ? "reset" : "set", prop_name); 5498 } 5499 return (status); 5500 } 5501 5502 static int 5503 reset_one_linkprop(dladm_handle_t dh, datalink_id_t linkid, 5504 const char *propname, void *arg) 5505 { 5506 set_linkprop_state_t *statep = arg; 5507 dladm_status_t status; 5508 5509 status = dladm_set_linkprop(dh, linkid, propname, NULL, 0, 5510 DLADM_OPT_ACTIVE); 5511 if (status != DLADM_STATUS_OK) { 5512 warn_dlerr(status, "cannot reset link property '%s' on '%s'", 5513 propname, statep->ls_name); 5514 } 5515 if (!statep->ls_temp) { 5516 dladm_status_t s; 5517 5518 s = set_linkprop_persist(linkid, propname, NULL, 0, 5519 statep->ls_reset); 5520 if (s != DLADM_STATUS_OK) 5521 status = s; 5522 } 5523 if (status != DLADM_STATUS_OK) 5524 statep->ls_status = status; 5525 5526 return (DLADM_WALK_CONTINUE); 5527 } 5528 5529 static void 5530 set_linkprop(int argc, char **argv, boolean_t reset, const char *use) 5531 { 5532 int i, option; 5533 char errmsg[DLADM_STRSIZE]; 5534 char *altroot = NULL; 5535 datalink_id_t linkid; 5536 boolean_t temp = B_FALSE; 5537 dladm_status_t status = DLADM_STATUS_OK; 5538 char propstr[DLADM_STRSIZE]; 5539 dladm_arg_list_t *proplist = NULL; 5540 5541 opterr = 0; 5542 bzero(propstr, DLADM_STRSIZE); 5543 5544 while ((option = getopt_long(argc, argv, ":p:R:t", 5545 prop_longopts, NULL)) != -1) { 5546 switch (option) { 5547 case 'p': 5548 (void) strlcat(propstr, optarg, DLADM_STRSIZE); 5549 if (strlcat(propstr, ",", DLADM_STRSIZE) >= 5550 DLADM_STRSIZE) 5551 die("property list too long '%s'", propstr); 5552 break; 5553 case 't': 5554 temp = B_TRUE; 5555 break; 5556 case 'R': 5557 altroot = optarg; 5558 break; 5559 default: 5560 die_opterr(optopt, option, use); 5561 5562 } 5563 } 5564 5565 /* get link name (required last argument) */ 5566 if (optind != (argc - 1)) 5567 usage(); 5568 5569 if (dladm_parse_link_props(propstr, &proplist, reset) != 5570 DLADM_STATUS_OK) 5571 die("invalid link properties specified"); 5572 5573 if (proplist == NULL && !reset) 5574 die("link property must be specified"); 5575 5576 if (altroot != NULL) { 5577 dladm_free_props(proplist); 5578 altroot_cmd(altroot, argc, argv); 5579 } 5580 5581 status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL, 5582 NULL); 5583 if (status != DLADM_STATUS_OK) 5584 die_dlerr(status, "link %s is not valid", argv[optind]); 5585 5586 if (proplist == NULL) { 5587 set_linkprop_state_t state; 5588 5589 state.ls_name = argv[optind]; 5590 state.ls_reset = reset; 5591 state.ls_temp = temp; 5592 state.ls_status = DLADM_STATUS_OK; 5593 5594 (void) dladm_walk_linkprop(handle, linkid, &state, 5595 reset_one_linkprop); 5596 5597 status = state.ls_status; 5598 goto done; 5599 } 5600 5601 for (i = 0; i < proplist->al_count; i++) { 5602 dladm_arg_info_t *aip = &proplist->al_info[i]; 5603 char **val; 5604 uint_t count; 5605 dladm_status_t s; 5606 5607 if (reset) { 5608 val = NULL; 5609 count = 0; 5610 } else { 5611 val = aip->ai_val; 5612 count = aip->ai_count; 5613 if (count == 0) { 5614 warn("no value specified for '%s'", 5615 aip->ai_name); 5616 status = DLADM_STATUS_BADARG; 5617 continue; 5618 } 5619 } 5620 s = dladm_set_linkprop(handle, linkid, aip->ai_name, val, count, 5621 DLADM_OPT_ACTIVE); 5622 if (s == DLADM_STATUS_OK) { 5623 if (!temp) { 5624 s = set_linkprop_persist(linkid, 5625 aip->ai_name, val, count, reset); 5626 if (s != DLADM_STATUS_OK) 5627 status = s; 5628 } 5629 continue; 5630 } 5631 status = s; 5632 switch (s) { 5633 case DLADM_STATUS_NOTFOUND: 5634 warn("invalid link property '%s'", aip->ai_name); 5635 break; 5636 case DLADM_STATUS_BADVAL: { 5637 int j; 5638 char *ptr, *lim; 5639 char **propvals = NULL; 5640 uint_t valcnt = DLADM_MAX_PROP_VALCNT; 5641 5642 ptr = malloc((sizeof (char *) + 5643 DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT + 5644 MAX_PROP_LINE); 5645 5646 propvals = (char **)(void *)ptr; 5647 if (propvals == NULL) 5648 die("insufficient memory"); 5649 5650 for (j = 0; j < DLADM_MAX_PROP_VALCNT; j++) { 5651 propvals[j] = ptr + sizeof (char *) * 5652 DLADM_MAX_PROP_VALCNT + 5653 j * DLADM_PROP_VAL_MAX; 5654 } 5655 s = dladm_get_linkprop(handle, linkid, 5656 DLADM_PROP_VAL_MODIFIABLE, aip->ai_name, propvals, 5657 &valcnt); 5658 5659 if (s != DLADM_STATUS_OK) { 5660 warn_dlerr(status, "cannot set link property " 5661 "'%s' on '%s'", aip->ai_name, argv[optind]); 5662 free(propvals); 5663 break; 5664 } 5665 5666 ptr = errmsg; 5667 lim = ptr + DLADM_STRSIZE; 5668 *ptr = '\0'; 5669 for (j = 0; j < valcnt; j++) { 5670 ptr += snprintf(ptr, lim - ptr, "%s,", 5671 propvals[j]); 5672 if (ptr >= lim) 5673 break; 5674 } 5675 if (ptr > errmsg) { 5676 *(ptr - 1) = '\0'; 5677 warn("link property '%s' must be one of: %s", 5678 aip->ai_name, errmsg); 5679 } else 5680 warn("invalid link property '%s'", *val); 5681 free(propvals); 5682 break; 5683 } 5684 default: 5685 if (reset) { 5686 warn_dlerr(status, "cannot reset link property " 5687 "'%s' on '%s'", aip->ai_name, argv[optind]); 5688 } else { 5689 warn_dlerr(status, "cannot set link property " 5690 "'%s' on '%s'", aip->ai_name, argv[optind]); 5691 } 5692 break; 5693 } 5694 } 5695 done: 5696 dladm_free_props(proplist); 5697 if (status != DLADM_STATUS_OK) { 5698 dladm_close(handle); 5699 exit(1); 5700 } 5701 } 5702 5703 static void 5704 do_set_linkprop(int argc, char **argv, const char *use) 5705 { 5706 set_linkprop(argc, argv, B_FALSE, use); 5707 } 5708 5709 static void 5710 do_reset_linkprop(int argc, char **argv, const char *use) 5711 { 5712 set_linkprop(argc, argv, B_TRUE, use); 5713 } 5714 5715 static int 5716 convert_secobj(char *buf, uint_t len, uint8_t *obj_val, uint_t *obj_lenp, 5717 dladm_secobj_class_t class) 5718 { 5719 int error = 0; 5720 5721 if (class == DLADM_SECOBJ_CLASS_WPA) { 5722 if (len < 8 || len > 63) 5723 return (EINVAL); 5724 (void) memcpy(obj_val, buf, len); 5725 *obj_lenp = len; 5726 return (error); 5727 } 5728 5729 if (class == DLADM_SECOBJ_CLASS_WEP) { 5730 switch (len) { 5731 case 5: /* ASCII key sizes */ 5732 case 13: 5733 (void) memcpy(obj_val, buf, len); 5734 *obj_lenp = len; 5735 break; 5736 case 10: /* Hex key sizes, not preceded by 0x */ 5737 case 26: 5738 error = hexascii_to_octet(buf, len, obj_val, obj_lenp); 5739 break; 5740 case 12: /* Hex key sizes, preceded by 0x */ 5741 case 28: 5742 if (strncmp(buf, "0x", 2) != 0) 5743 return (EINVAL); 5744 error = hexascii_to_octet(buf + 2, len - 2, 5745 obj_val, obj_lenp); 5746 break; 5747 default: 5748 return (EINVAL); 5749 } 5750 return (error); 5751 } 5752 5753 return (ENOENT); 5754 } 5755 5756 static void 5757 defersig(int sig) 5758 { 5759 signalled = sig; 5760 } 5761 5762 static int 5763 get_secobj_from_tty(uint_t try, const char *objname, char *buf) 5764 { 5765 uint_t len = 0; 5766 int c; 5767 struct termios stored, current; 5768 void (*sigfunc)(int); 5769 5770 /* 5771 * Turn off echo -- but before we do so, defer SIGINT handling 5772 * so that a ^C doesn't leave the terminal corrupted. 5773 */ 5774 sigfunc = signal(SIGINT, defersig); 5775 (void) fflush(stdin); 5776 (void) tcgetattr(0, &stored); 5777 current = stored; 5778 current.c_lflag &= ~(ICANON|ECHO); 5779 current.c_cc[VTIME] = 0; 5780 current.c_cc[VMIN] = 1; 5781 (void) tcsetattr(0, TCSANOW, ¤t); 5782 again: 5783 if (try == 1) 5784 (void) printf(gettext("provide value for '%s': "), objname); 5785 else 5786 (void) printf(gettext("confirm value for '%s': "), objname); 5787 5788 (void) fflush(stdout); 5789 while (signalled == 0) { 5790 c = getchar(); 5791 if (c == '\n' || c == '\r') { 5792 if (len != 0) 5793 break; 5794 (void) putchar('\n'); 5795 goto again; 5796 } 5797 5798 buf[len++] = c; 5799 if (len >= DLADM_SECOBJ_VAL_MAX - 1) 5800 break; 5801 (void) putchar('*'); 5802 } 5803 5804 (void) putchar('\n'); 5805 (void) fflush(stdin); 5806 5807 /* 5808 * Restore terminal setting and handle deferred signals. 5809 */ 5810 (void) tcsetattr(0, TCSANOW, &stored); 5811 5812 (void) signal(SIGINT, sigfunc); 5813 if (signalled != 0) 5814 (void) kill(getpid(), signalled); 5815 5816 return (len); 5817 } 5818 5819 static int 5820 get_secobj_val(char *obj_name, uint8_t *obj_val, uint_t *obj_lenp, 5821 dladm_secobj_class_t class, FILE *filep) 5822 { 5823 int rval; 5824 uint_t len, len2; 5825 char buf[DLADM_SECOBJ_VAL_MAX], buf2[DLADM_SECOBJ_VAL_MAX]; 5826 5827 if (filep == NULL) { 5828 len = get_secobj_from_tty(1, obj_name, buf); 5829 rval = convert_secobj(buf, len, obj_val, obj_lenp, class); 5830 if (rval == 0) { 5831 len2 = get_secobj_from_tty(2, obj_name, buf2); 5832 if (len != len2 || memcmp(buf, buf2, len) != 0) 5833 rval = ENOTSUP; 5834 } 5835 return (rval); 5836 } else { 5837 for (;;) { 5838 if (fgets(buf, sizeof (buf), filep) == NULL) 5839 break; 5840 if (isspace(buf[0])) 5841 continue; 5842 5843 len = strlen(buf); 5844 if (buf[len - 1] == '\n') { 5845 buf[len - 1] = '\0'; 5846 len--; 5847 } 5848 break; 5849 } 5850 (void) fclose(filep); 5851 } 5852 return (convert_secobj(buf, len, obj_val, obj_lenp, class)); 5853 } 5854 5855 static boolean_t 5856 check_auth(const char *auth) 5857 { 5858 struct passwd *pw; 5859 5860 if ((pw = getpwuid(getuid())) == NULL) 5861 return (B_FALSE); 5862 5863 return (chkauthattr(auth, pw->pw_name) != 0); 5864 } 5865 5866 static void 5867 audit_secobj(char *auth, char *class, char *obj, 5868 boolean_t success, boolean_t create) 5869 { 5870 adt_session_data_t *ah; 5871 adt_event_data_t *event; 5872 au_event_t flag; 5873 char *errstr; 5874 5875 if (create) { 5876 flag = ADT_dladm_create_secobj; 5877 errstr = "ADT_dladm_create_secobj"; 5878 } else { 5879 flag = ADT_dladm_delete_secobj; 5880 errstr = "ADT_dladm_delete_secobj"; 5881 } 5882 5883 if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) 5884 die("adt_start_session: %s", strerror(errno)); 5885 5886 if ((event = adt_alloc_event(ah, flag)) == NULL) 5887 die("adt_alloc_event (%s): %s", errstr, strerror(errno)); 5888 5889 /* fill in audit info */ 5890 if (create) { 5891 event->adt_dladm_create_secobj.auth_used = auth; 5892 event->adt_dladm_create_secobj.obj_class = class; 5893 event->adt_dladm_create_secobj.obj_name = obj; 5894 } else { 5895 event->adt_dladm_delete_secobj.auth_used = auth; 5896 event->adt_dladm_delete_secobj.obj_class = class; 5897 event->adt_dladm_delete_secobj.obj_name = obj; 5898 } 5899 5900 if (success) { 5901 if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) { 5902 die("adt_put_event (%s, success): %s", errstr, 5903 strerror(errno)); 5904 } 5905 } else { 5906 if (adt_put_event(event, ADT_FAILURE, 5907 ADT_FAIL_VALUE_AUTH) != 0) { 5908 die("adt_put_event: (%s, failure): %s", errstr, 5909 strerror(errno)); 5910 } 5911 } 5912 5913 adt_free_event(event); 5914 (void) adt_end_session(ah); 5915 } 5916 5917 #define MAX_SECOBJS 32 5918 #define MAX_SECOBJ_NAMELEN 32 5919 static void 5920 do_create_secobj(int argc, char **argv, const char *use) 5921 { 5922 int option, rval; 5923 FILE *filep = NULL; 5924 char *obj_name = NULL; 5925 char *class_name = NULL; 5926 uint8_t obj_val[DLADM_SECOBJ_VAL_MAX]; 5927 uint_t obj_len; 5928 boolean_t success, temp = B_FALSE; 5929 dladm_status_t status; 5930 dladm_secobj_class_t class = -1; 5931 uid_t euid; 5932 5933 opterr = 0; 5934 (void) memset(obj_val, 0, DLADM_SECOBJ_VAL_MAX); 5935 while ((option = getopt_long(argc, argv, ":f:c:R:t", 5936 wifi_longopts, NULL)) != -1) { 5937 switch (option) { 5938 case 'f': 5939 euid = geteuid(); 5940 (void) seteuid(getuid()); 5941 filep = fopen(optarg, "r"); 5942 if (filep == NULL) { 5943 die("cannot open %s: %s", optarg, 5944 strerror(errno)); 5945 } 5946 (void) seteuid(euid); 5947 break; 5948 case 'c': 5949 class_name = optarg; 5950 status = dladm_str2secobjclass(optarg, &class); 5951 if (status != DLADM_STATUS_OK) { 5952 die("invalid secure object class '%s', " 5953 "valid values are: wep, wpa", optarg); 5954 } 5955 break; 5956 case 't': 5957 temp = B_TRUE; 5958 break; 5959 case 'R': 5960 status = dladm_set_rootdir(optarg); 5961 if (status != DLADM_STATUS_OK) { 5962 die_dlerr(status, "invalid directory " 5963 "specified"); 5964 } 5965 break; 5966 default: 5967 die_opterr(optopt, option, use); 5968 break; 5969 } 5970 } 5971 5972 if (optind == (argc - 1)) 5973 obj_name = argv[optind]; 5974 else if (optind != argc) 5975 usage(); 5976 5977 if (class == -1) 5978 die("secure object class required"); 5979 5980 if (obj_name == NULL) 5981 die("secure object name required"); 5982 5983 if (!dladm_valid_secobj_name(obj_name)) 5984 die("invalid secure object name '%s'", obj_name); 5985 5986 success = check_auth(LINK_SEC_AUTH); 5987 audit_secobj(LINK_SEC_AUTH, class_name, obj_name, success, B_TRUE); 5988 if (!success) 5989 die("authorization '%s' is required", LINK_SEC_AUTH); 5990 5991 rval = get_secobj_val(obj_name, obj_val, &obj_len, class, filep); 5992 if (rval != 0) { 5993 switch (rval) { 5994 case ENOENT: 5995 die("invalid secure object class"); 5996 break; 5997 case EINVAL: 5998 die("invalid secure object value"); 5999 break; 6000 case ENOTSUP: 6001 die("verification failed"); 6002 break; 6003 default: 6004 die("invalid secure object: %s", strerror(rval)); 6005 break; 6006 } 6007 } 6008 6009 status = dladm_set_secobj(handle, obj_name, class, obj_val, obj_len, 6010 DLADM_OPT_CREATE | DLADM_OPT_ACTIVE); 6011 if (status != DLADM_STATUS_OK) { 6012 die_dlerr(status, "could not create secure object '%s'", 6013 obj_name); 6014 } 6015 if (temp) 6016 return; 6017 6018 status = dladm_set_secobj(handle, obj_name, class, obj_val, obj_len, 6019 DLADM_OPT_PERSIST); 6020 if (status != DLADM_STATUS_OK) { 6021 warn_dlerr(status, "could not persistently create secure " 6022 "object '%s'", obj_name); 6023 } 6024 } 6025 6026 static void 6027 do_delete_secobj(int argc, char **argv, const char *use) 6028 { 6029 int i, option; 6030 boolean_t temp = B_FALSE; 6031 boolean_t success; 6032 dladm_status_t status, pstatus; 6033 int nfields = 1; 6034 char *field, *token, *lasts = NULL, c; 6035 6036 opterr = 0; 6037 status = pstatus = DLADM_STATUS_OK; 6038 while ((option = getopt_long(argc, argv, ":R:t", 6039 wifi_longopts, NULL)) != -1) { 6040 switch (option) { 6041 case 't': 6042 temp = B_TRUE; 6043 break; 6044 case 'R': 6045 status = dladm_set_rootdir(optarg); 6046 if (status != DLADM_STATUS_OK) { 6047 die_dlerr(status, "invalid directory " 6048 "specified"); 6049 } 6050 break; 6051 default: 6052 die_opterr(optopt, option, use); 6053 break; 6054 } 6055 } 6056 6057 if (optind == (argc - 1)) { 6058 token = argv[optind]; 6059 if (token == NULL) 6060 die("secure object name required"); 6061 while ((c = *token++) != NULL) { 6062 if (c == ',') 6063 nfields++; 6064 } 6065 token = strdup(argv[optind]); 6066 if (token == NULL) 6067 die("no memory"); 6068 } else if (optind != argc) 6069 usage(); 6070 6071 success = check_auth(LINK_SEC_AUTH); 6072 audit_secobj(LINK_SEC_AUTH, "unknown", argv[optind], success, B_FALSE); 6073 if (!success) 6074 die("authorization '%s' is required", LINK_SEC_AUTH); 6075 6076 for (i = 0; i < nfields; i++) { 6077 6078 field = strtok_r(token, ",", &lasts); 6079 token = NULL; 6080 status = dladm_unset_secobj(handle, field, DLADM_OPT_ACTIVE); 6081 if (!temp) { 6082 pstatus = dladm_unset_secobj(handle, field, 6083 DLADM_OPT_PERSIST); 6084 } else { 6085 pstatus = DLADM_STATUS_OK; 6086 } 6087 6088 if (status != DLADM_STATUS_OK) { 6089 warn_dlerr(status, "could not delete secure object " 6090 "'%s'", field); 6091 } 6092 if (pstatus != DLADM_STATUS_OK) { 6093 warn_dlerr(pstatus, "could not persistently delete " 6094 "secure object '%s'", field); 6095 } 6096 } 6097 free(token); 6098 6099 if (status != DLADM_STATUS_OK || pstatus != DLADM_STATUS_OK) { 6100 dladm_close(handle); 6101 exit(1); 6102 } 6103 } 6104 6105 typedef struct show_secobj_state { 6106 boolean_t ss_persist; 6107 boolean_t ss_parsable; 6108 boolean_t ss_header; 6109 ofmt_handle_t ss_ofmt; 6110 } show_secobj_state_t; 6111 6112 6113 static boolean_t 6114 show_secobj(dladm_handle_t dh, void *arg, const char *obj_name) 6115 { 6116 uint_t obj_len = DLADM_SECOBJ_VAL_MAX; 6117 uint8_t obj_val[DLADM_SECOBJ_VAL_MAX]; 6118 char buf[DLADM_STRSIZE]; 6119 uint_t flags = 0; 6120 dladm_secobj_class_t class; 6121 show_secobj_state_t *statep = arg; 6122 dladm_status_t status; 6123 secobj_fields_buf_t sbuf; 6124 6125 bzero(&sbuf, sizeof (secobj_fields_buf_t)); 6126 if (statep->ss_persist) 6127 flags |= DLADM_OPT_PERSIST; 6128 6129 status = dladm_get_secobj(dh, obj_name, &class, obj_val, &obj_len, 6130 flags); 6131 if (status != DLADM_STATUS_OK) 6132 die_dlerr(status, "cannot get secure object '%s'", obj_name); 6133 6134 (void) snprintf(sbuf.ss_obj_name, sizeof (sbuf.ss_obj_name), 6135 obj_name); 6136 (void) dladm_secobjclass2str(class, buf); 6137 (void) snprintf(sbuf.ss_class, sizeof (sbuf.ss_class), "%s", buf); 6138 if (getuid() == 0) { 6139 char val[DLADM_SECOBJ_VAL_MAX * 2]; 6140 uint_t len = sizeof (val); 6141 6142 if (octet_to_hexascii(obj_val, obj_len, val, &len) == 0) 6143 (void) snprintf(sbuf.ss_val, 6144 sizeof (sbuf.ss_val), "%s", val); 6145 } 6146 ofmt_print(statep->ss_ofmt, &sbuf); 6147 return (B_TRUE); 6148 } 6149 6150 static void 6151 do_show_secobj(int argc, char **argv, const char *use) 6152 { 6153 int option; 6154 show_secobj_state_t state; 6155 dladm_status_t status; 6156 boolean_t o_arg = B_FALSE; 6157 uint_t i; 6158 uint_t flags; 6159 char *fields_str = NULL; 6160 char *def_fields = "object,class"; 6161 char *all_fields = "object,class,value"; 6162 char *field, *token, *lasts = NULL, c; 6163 ofmt_handle_t ofmt; 6164 ofmt_status_t oferr; 6165 uint_t ofmtflags = 0; 6166 6167 opterr = 0; 6168 bzero(&state, sizeof (state)); 6169 state.ss_parsable = B_FALSE; 6170 fields_str = def_fields; 6171 state.ss_persist = B_FALSE; 6172 state.ss_parsable = B_FALSE; 6173 state.ss_header = B_TRUE; 6174 while ((option = getopt_long(argc, argv, ":pPo:", 6175 wifi_longopts, NULL)) != -1) { 6176 switch (option) { 6177 case 'p': 6178 state.ss_parsable = B_TRUE; 6179 break; 6180 case 'P': 6181 state.ss_persist = B_TRUE; 6182 break; 6183 case 'o': 6184 o_arg = B_TRUE; 6185 if (strcasecmp(optarg, "all") == 0) 6186 fields_str = all_fields; 6187 else 6188 fields_str = optarg; 6189 break; 6190 default: 6191 die_opterr(optopt, option, use); 6192 break; 6193 } 6194 } 6195 6196 if (state.ss_parsable && !o_arg) 6197 die("option -c requires -o"); 6198 6199 if (state.ss_parsable && fields_str == all_fields) 6200 die("\"-o all\" is invalid with -p"); 6201 6202 if (state.ss_parsable) 6203 ofmtflags |= OFMT_PARSABLE; 6204 oferr = ofmt_open(fields_str, secobj_fields, ofmtflags, 0, &ofmt); 6205 dladm_ofmt_check(oferr, state.ss_parsable, ofmt); 6206 state.ss_ofmt = ofmt; 6207 6208 flags = state.ss_persist ? DLADM_OPT_PERSIST : 0; 6209 6210 if (optind == (argc - 1)) { 6211 uint_t obj_fields = 1; 6212 6213 token = argv[optind]; 6214 if (token == NULL) 6215 die("secure object name required"); 6216 while ((c = *token++) != NULL) { 6217 if (c == ',') 6218 obj_fields++; 6219 } 6220 token = strdup(argv[optind]); 6221 if (token == NULL) 6222 die("no memory"); 6223 for (i = 0; i < obj_fields; i++) { 6224 field = strtok_r(token, ",", &lasts); 6225 token = NULL; 6226 if (!show_secobj(handle, &state, field)) 6227 break; 6228 } 6229 free(token); 6230 ofmt_close(ofmt); 6231 return; 6232 } else if (optind != argc) 6233 usage(); 6234 6235 status = dladm_walk_secobj(handle, &state, show_secobj, flags); 6236 6237 if (status != DLADM_STATUS_OK) 6238 die_dlerr(status, "show-secobj"); 6239 ofmt_close(ofmt); 6240 } 6241 6242 /*ARGSUSED*/ 6243 static int 6244 i_dladm_init_linkprop(dladm_handle_t dh, datalink_id_t linkid, void *arg) 6245 { 6246 (void) dladm_init_linkprop(dh, linkid, B_TRUE); 6247 return (DLADM_WALK_CONTINUE); 6248 } 6249 6250 /*ARGSUSED*/ 6251 void 6252 do_init_linkprop(int argc, char **argv, const char *use) 6253 { 6254 int option; 6255 dladm_status_t status; 6256 datalink_id_t linkid = DATALINK_ALL_LINKID; 6257 datalink_media_t media = DATALINK_ANY_MEDIATYPE; 6258 uint_t any_media = B_TRUE; 6259 6260 opterr = 0; 6261 while ((option = getopt(argc, argv, ":w")) != -1) { 6262 switch (option) { 6263 case 'w': 6264 media = DL_WIFI; 6265 any_media = B_FALSE; 6266 break; 6267 default: 6268 /* 6269 * Because init-linkprop is not a public command, 6270 * print the usage instead. 6271 */ 6272 usage(); 6273 break; 6274 } 6275 } 6276 6277 if (optind == (argc - 1)) { 6278 if ((status = dladm_name2info(handle, argv[optind], &linkid, 6279 NULL, NULL, NULL)) != DLADM_STATUS_OK) 6280 die_dlerr(status, "link %s is not valid", argv[optind]); 6281 } else if (optind != argc) { 6282 usage(); 6283 } 6284 6285 if (linkid == DATALINK_ALL_LINKID) { 6286 /* 6287 * linkprops of links of other classes have been initialized as 6288 * part of the dladm up-xxx operation. 6289 */ 6290 (void) dladm_walk_datalink_id(i_dladm_init_linkprop, handle, 6291 NULL, DATALINK_CLASS_PHYS, media, DLADM_OPT_PERSIST); 6292 } else { 6293 (void) dladm_init_linkprop(handle, linkid, any_media); 6294 } 6295 } 6296 6297 static void 6298 do_show_ether(int argc, char **argv, const char *use) 6299 { 6300 int option; 6301 datalink_id_t linkid; 6302 print_ether_state_t state; 6303 char *fields_str = NULL; 6304 ofmt_handle_t ofmt; 6305 ofmt_status_t oferr; 6306 uint_t ofmtflags = 0; 6307 6308 bzero(&state, sizeof (state)); 6309 state.es_link = NULL; 6310 state.es_parsable = B_FALSE; 6311 6312 while ((option = getopt_long(argc, argv, "o:px", 6313 showeth_lopts, NULL)) != -1) { 6314 switch (option) { 6315 case 'x': 6316 state.es_extended = B_TRUE; 6317 break; 6318 case 'p': 6319 state.es_parsable = B_TRUE; 6320 break; 6321 case 'o': 6322 fields_str = optarg; 6323 break; 6324 default: 6325 die_opterr(optopt, option, use); 6326 break; 6327 } 6328 } 6329 6330 if (optind == (argc - 1)) 6331 state.es_link = argv[optind]; 6332 6333 if (state.es_parsable) 6334 ofmtflags |= OFMT_PARSABLE; 6335 oferr = ofmt_open(fields_str, ether_fields, ofmtflags, 6336 DLADM_DEFAULT_COL, &ofmt); 6337 dladm_ofmt_check(oferr, state.es_parsable, ofmt); 6338 state.es_ofmt = ofmt; 6339 6340 if (state.es_link == NULL) { 6341 (void) dladm_walk_datalink_id(show_etherprop, handle, &state, 6342 DATALINK_CLASS_PHYS, DL_ETHER, 6343 DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST); 6344 } else { 6345 if (!link_is_ether(state.es_link, &linkid)) 6346 die("invalid link specified"); 6347 (void) show_etherprop(handle, linkid, &state); 6348 } 6349 ofmt_close(ofmt); 6350 } 6351 6352 static int 6353 show_etherprop(dladm_handle_t dh, datalink_id_t linkid, void *arg) 6354 { 6355 print_ether_state_t *statep = arg; 6356 ether_fields_buf_t ebuf; 6357 dladm_ether_info_t eattr; 6358 dladm_status_t status; 6359 6360 bzero(&ebuf, sizeof (ether_fields_buf_t)); 6361 if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, 6362 ebuf.eth_link, sizeof (ebuf.eth_link)) != DLADM_STATUS_OK) { 6363 return (DLADM_WALK_CONTINUE); 6364 } 6365 6366 status = dladm_ether_info(dh, linkid, &eattr); 6367 if (status != DLADM_STATUS_OK) 6368 goto cleanup; 6369 6370 (void) strlcpy(ebuf.eth_ptype, "current", sizeof (ebuf.eth_ptype)); 6371 6372 (void) dladm_ether_autoneg2str(ebuf.eth_autoneg, 6373 sizeof (ebuf.eth_autoneg), &eattr, CURRENT); 6374 (void) dladm_ether_pause2str(ebuf.eth_pause, 6375 sizeof (ebuf.eth_pause), &eattr, CURRENT); 6376 (void) dladm_ether_spdx2str(ebuf.eth_spdx, 6377 sizeof (ebuf.eth_spdx), &eattr, CURRENT); 6378 (void) strlcpy(ebuf.eth_state, 6379 dladm_linkstate2str(eattr.lei_state, ebuf.eth_state), 6380 sizeof (ebuf.eth_state)); 6381 (void) strlcpy(ebuf.eth_rem_fault, 6382 (eattr.lei_attr[CURRENT].le_fault ? "fault" : "none"), 6383 sizeof (ebuf.eth_rem_fault)); 6384 6385 ofmt_print(statep->es_ofmt, &ebuf); 6386 6387 if (statep->es_extended) 6388 show_ether_xprop(arg, &eattr); 6389 6390 cleanup: 6391 dladm_ether_info_done(&eattr); 6392 return (DLADM_WALK_CONTINUE); 6393 } 6394 6395 /* ARGSUSED */ 6396 static void 6397 do_init_secobj(int argc, char **argv, const char *use) 6398 { 6399 dladm_status_t status; 6400 6401 status = dladm_init_secobj(handle); 6402 if (status != DLADM_STATUS_OK) 6403 die_dlerr(status, "secure object initialization failed"); 6404 } 6405 6406 /* 6407 * "-R" option support. It is used for live upgrading. Append dladm commands 6408 * to a upgrade script which will be run when the alternative root boots up: 6409 * 6410 * - If the /etc/dladm/datalink.conf file exists on the alternative root, 6411 * append dladm commands to the <altroot>/var/svc/profile/upgrade_datalink 6412 * script. This script will be run as part of the network/physical service. 6413 * We cannot defer this to /var/svc/profile/upgrade because then the 6414 * configuration will not be able to take effect before network/physical 6415 * plumbs various interfaces. 6416 * 6417 * - If the /etc/dladm/datalink.conf file does not exist on the alternative 6418 * root, append dladm commands to the <altroot>/var/svc/profile/upgrade script, 6419 * which will be run in the manifest-import service. 6420 * 6421 * Note that the SMF team is considering to move the manifest-import service 6422 * to be run at the very begining of boot. Once that is done, the need for 6423 * the /var/svc/profile/upgrade_datalink script will not exist any more. 6424 */ 6425 static void 6426 altroot_cmd(char *altroot, int argc, char *argv[]) 6427 { 6428 char path[MAXPATHLEN]; 6429 struct stat stbuf; 6430 FILE *fp; 6431 int i; 6432 6433 /* 6434 * Check for the existence of the /etc/dladm/datalink.conf 6435 * configuration file, and determine the name of script file. 6436 */ 6437 (void) snprintf(path, MAXPATHLEN, "/%s/etc/dladm/datalink.conf", 6438 altroot); 6439 if (stat(path, &stbuf) < 0) { 6440 (void) snprintf(path, MAXPATHLEN, "/%s/%s", altroot, 6441 SMF_UPGRADE_FILE); 6442 } else { 6443 (void) snprintf(path, MAXPATHLEN, "/%s/%s", altroot, 6444 SMF_UPGRADEDATALINK_FILE); 6445 } 6446 6447 if ((fp = fopen(path, "a+")) == NULL) 6448 die("operation not supported on %s", altroot); 6449 6450 (void) fprintf(fp, "/sbin/dladm "); 6451 for (i = 0; i < argc; i++) { 6452 /* 6453 * Directly write to the file if it is not the "-R <altroot>" 6454 * option. In which case, skip it. 6455 */ 6456 if (strcmp(argv[i], "-R") != 0) 6457 (void) fprintf(fp, "%s ", argv[i]); 6458 else 6459 i ++; 6460 } 6461 (void) fprintf(fp, "%s\n", SMF_DLADM_UPGRADE_MSG); 6462 (void) fclose(fp); 6463 dladm_close(handle); 6464 exit(0); 6465 } 6466 6467 /* 6468 * Convert the string to an integer. Note that the string must not have any 6469 * trailing non-integer characters. 6470 */ 6471 static boolean_t 6472 str2int(const char *str, int *valp) 6473 { 6474 int val; 6475 char *endp = NULL; 6476 6477 errno = 0; 6478 val = strtol(str, &endp, 10); 6479 if (errno != 0 || *endp != '\0') 6480 return (B_FALSE); 6481 6482 *valp = val; 6483 return (B_TRUE); 6484 } 6485 6486 /* PRINTFLIKE1 */ 6487 static void 6488 warn(const char *format, ...) 6489 { 6490 va_list alist; 6491 6492 format = gettext(format); 6493 (void) fprintf(stderr, "%s: warning: ", progname); 6494 6495 va_start(alist, format); 6496 (void) vfprintf(stderr, format, alist); 6497 va_end(alist); 6498 6499 (void) putchar('\n'); 6500 } 6501 6502 /* PRINTFLIKE2 */ 6503 static void 6504 warn_dlerr(dladm_status_t err, const char *format, ...) 6505 { 6506 va_list alist; 6507 char errmsg[DLADM_STRSIZE]; 6508 6509 format = gettext(format); 6510 (void) fprintf(stderr, gettext("%s: warning: "), progname); 6511 6512 va_start(alist, format); 6513 (void) vfprintf(stderr, format, alist); 6514 va_end(alist); 6515 (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg)); 6516 } 6517 6518 /* 6519 * Also closes the dladm handle if it is not NULL. 6520 */ 6521 /* PRINTFLIKE2 */ 6522 static void 6523 die_dlerr(dladm_status_t err, const char *format, ...) 6524 { 6525 va_list alist; 6526 char errmsg[DLADM_STRSIZE]; 6527 6528 format = gettext(format); 6529 (void) fprintf(stderr, "%s: ", progname); 6530 6531 va_start(alist, format); 6532 (void) vfprintf(stderr, format, alist); 6533 va_end(alist); 6534 (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg)); 6535 6536 /* close dladm handle if it was opened */ 6537 if (handle != NULL) 6538 dladm_close(handle); 6539 6540 exit(EXIT_FAILURE); 6541 } 6542 6543 /* PRINTFLIKE1 */ 6544 static void 6545 die(const char *format, ...) 6546 { 6547 va_list alist; 6548 6549 format = gettext(format); 6550 (void) fprintf(stderr, "%s: ", progname); 6551 6552 va_start(alist, format); 6553 (void) vfprintf(stderr, format, alist); 6554 va_end(alist); 6555 6556 (void) putchar('\n'); 6557 6558 /* close dladm handle if it was opened */ 6559 if (handle != NULL) 6560 dladm_close(handle); 6561 6562 exit(EXIT_FAILURE); 6563 } 6564 6565 static void 6566 die_optdup(int opt) 6567 { 6568 die("the option -%c cannot be specified more than once", opt); 6569 } 6570 6571 static void 6572 die_opterr(int opt, int opterr, const char *usage) 6573 { 6574 switch (opterr) { 6575 case ':': 6576 die("option '-%c' requires a value\nusage: %s", opt, 6577 gettext(usage)); 6578 break; 6579 case '?': 6580 default: 6581 die("unrecognized option '-%c'\nusage: %s", opt, 6582 gettext(usage)); 6583 break; 6584 } 6585 } 6586 6587 static void 6588 show_ether_xprop(void *arg, dladm_ether_info_t *eattr) 6589 { 6590 print_ether_state_t *statep = arg; 6591 ether_fields_buf_t ebuf; 6592 int i; 6593 6594 for (i = CAPABLE; i <= PEERADV; i++) { 6595 bzero(&ebuf, sizeof (ebuf)); 6596 (void) strlcpy(ebuf.eth_ptype, ptype[i], 6597 sizeof (ebuf.eth_ptype)); 6598 (void) dladm_ether_autoneg2str(ebuf.eth_autoneg, 6599 sizeof (ebuf.eth_autoneg), eattr, i); 6600 (void) dladm_ether_spdx2str(ebuf.eth_spdx, 6601 sizeof (ebuf.eth_spdx), eattr, i); 6602 (void) dladm_ether_pause2str(ebuf.eth_pause, 6603 sizeof (ebuf.eth_pause), eattr, i); 6604 (void) strlcpy(ebuf.eth_rem_fault, 6605 (eattr->lei_attr[i].le_fault ? "fault" : "none"), 6606 sizeof (ebuf.eth_rem_fault)); 6607 ofmt_print(statep->es_ofmt, &ebuf); 6608 } 6609 6610 } 6611 6612 static boolean_t 6613 link_is_ether(const char *link, datalink_id_t *linkid) 6614 { 6615 uint32_t media; 6616 datalink_class_t class; 6617 6618 if (dladm_name2info(handle, link, linkid, NULL, &class, &media) == 6619 DLADM_STATUS_OK) { 6620 if (class == DATALINK_CLASS_PHYS && media == DL_ETHER) 6621 return (B_TRUE); 6622 } 6623 return (B_FALSE); 6624 } 6625 6626 /* 6627 * default output callback function that, when invoked, 6628 * prints string which is offset by ofmt_arg->ofmt_id within buf. 6629 */ 6630 static boolean_t 6631 print_default_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) 6632 { 6633 char *value; 6634 6635 value = (char *)ofarg->ofmt_cbarg + ofarg->ofmt_id; 6636 (void) strlcpy(buf, value, bufsize); 6637 return (B_TRUE); 6638 } 6639 6640 static void 6641 dladm_ofmt_check(ofmt_status_t oferr, boolean_t parsable, 6642 ofmt_handle_t ofmt) 6643 { 6644 char buf[OFMT_BUFSIZE]; 6645 6646 if (oferr == OFMT_SUCCESS) 6647 return; 6648 (void) ofmt_strerror(ofmt, oferr, buf, sizeof (buf)); 6649 /* 6650 * All errors are considered fatal in parsable mode. 6651 * NOMEM errors are always fatal, regardless of mode. 6652 * For other errors, we print diagnostics in human-readable 6653 * mode and processs what we can. 6654 */ 6655 if (parsable || oferr == OFMT_ENOFIELDS) { 6656 ofmt_close(ofmt); 6657 die(buf); 6658 } else { 6659 warn(buf); 6660 } 6661 } 6662