17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5219a2a31Shl157128 * Common Development and Distribution License (the "License"). 6219a2a31Shl157128 * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22d62bc4baSyz147064 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate #include <stdio.h> 290ba2cbe9Sxc151355 #include <ctype.h> 307c478bd9Sstevel@tonic-gate #include <locale.h> 310ba2cbe9Sxc151355 #include <signal.h> 327c478bd9Sstevel@tonic-gate #include <stdarg.h> 337c478bd9Sstevel@tonic-gate #include <stdlib.h> 347c478bd9Sstevel@tonic-gate #include <fcntl.h> 357c478bd9Sstevel@tonic-gate #include <string.h> 367c478bd9Sstevel@tonic-gate #include <stropts.h> 37d62bc4baSyz147064 #include <sys/stat.h> 387c478bd9Sstevel@tonic-gate #include <errno.h> 397c478bd9Sstevel@tonic-gate #include <kstat.h> 407c478bd9Sstevel@tonic-gate #include <strings.h> 417c478bd9Sstevel@tonic-gate #include <getopt.h> 427c478bd9Sstevel@tonic-gate #include <unistd.h> 43cd93090eSericheng #include <priv.h> 440ba2cbe9Sxc151355 #include <termios.h> 450ba2cbe9Sxc151355 #include <pwd.h> 460ba2cbe9Sxc151355 #include <auth_attr.h> 470ba2cbe9Sxc151355 #include <auth_list.h> 487c478bd9Sstevel@tonic-gate #include <libintl.h> 49d62bc4baSyz147064 #include <libdevinfo.h> 507c478bd9Sstevel@tonic-gate #include <libdlpi.h> 51f595a68aSyz147064 #include <libdllink.h> 52f595a68aSyz147064 #include <libdlaggr.h> 53f595a68aSyz147064 #include <libdlwlan.h> 54d62bc4baSyz147064 #include <libdlvlan.h> 55d62bc4baSyz147064 #include <libdlvnic.h> 560ba2cbe9Sxc151355 #include <libinetutil.h> 570ba2cbe9Sxc151355 #include <bsm/adt.h> 580ba2cbe9Sxc151355 #include <bsm/adt_event.h> 59*e7801d59Ssowmini #include <stddef.h> 607c478bd9Sstevel@tonic-gate 61ba2e4443Sseb #define AGGR_DRV "aggr" 62*e7801d59Ssowmini #define STR_UNDEF_VAL "--" 637c478bd9Sstevel@tonic-gate #define MAXPORT 256 64d62bc4baSyz147064 #define BUFLEN(lim, ptr) (((lim) > (ptr)) ? ((lim) - (ptr)) : 0) 65d62bc4baSyz147064 #define MAXLINELEN 1024 66d62bc4baSyz147064 #define SMF_UPGRADE_FILE "/var/svc/profile/upgrade" 67d62bc4baSyz147064 #define SMF_UPGRADEDATALINK_FILE "/var/svc/profile/upgrade_datalink" 68d62bc4baSyz147064 #define SMF_DLADM_UPGRADE_MSG " # added by dladm(1M)" 697c478bd9Sstevel@tonic-gate 70*e7801d59Ssowmini #define CMD_TYPE_ANY 0xffffffff 71*e7801d59Ssowmini #define WIFI_CMD_SCAN 0x00000001 72*e7801d59Ssowmini #define WIFI_CMD_SHOW 0x00000002 73*e7801d59Ssowmini #define WIFI_CMD_ALL (WIFI_CMD_SCAN | WIFI_CMD_SHOW) 74*e7801d59Ssowmini 75*e7801d59Ssowmini /* 76*e7801d59Ssowmini * data structures and routines for printing output. 77*e7801d59Ssowmini * All non-parseable output is assumed to be in a columnar format. 78*e7801d59Ssowmini * Parseable output will be printed as <pf_header>="<value>" 79*e7801d59Ssowmini * 80*e7801d59Ssowmini * Each sub-command is associated with a global array of pointers, 81*e7801d59Ssowmini * print_field_t *fields[], where the print_field_t contains information 82*e7801d59Ssowmini * about the format in which the output is to be printed. 83*e7801d59Ssowmini * 84*e7801d59Ssowmini * Sub-commands may be implemented in one of two ways: 85*e7801d59Ssowmini * (i) the implementation could get all field values into a character 86*e7801d59Ssowmini * buffer, with pf_offset containing the offset (for pf_name) within 87*e7801d59Ssowmini * the buffer. The sub-command would make the needed system calls 88*e7801d59Ssowmini * to obtain all possible column values and then invoke the 89*e7801d59Ssowmini * dladm_print_field() function to print the specific fields 90*e7801d59Ssowmini * requested in the command line. See the comments for dladm_print_field 91*e7801d59Ssowmini * for further details. 92*e7801d59Ssowmini * (ii) Alternatively, each fields[i] entry could store a pf_index value 93*e7801d59Ssowmini * that uniquely identifies the column to be printed. The implementation 94*e7801d59Ssowmini * of the sub-command would then invoke dladm_print_output() with a 95*e7801d59Ssowmini * callback function whose semantics are described below (see comments 96*e7801d59Ssowmini * for dladm_print_output()) 97*e7801d59Ssowmini * 98*e7801d59Ssowmini * Thus, an implementation of a sub-command must provide the following: 99*e7801d59Ssowmini * 100*e7801d59Ssowmini * static print_field_t sub_command_fields[] = { 101*e7801d59Ssowmini * {<name>, <header>,<field width>, <offset_or_index>, cmdtype}, 102*e7801d59Ssowmini * : 103*e7801d59Ssowmini * {<name>, <header>,<field width>, <offset_or_index>, cmdtype} 104*e7801d59Ssowmini * }; 105*e7801d59Ssowmini * 106*e7801d59Ssowmini * #define SUB_COMMAND_MAX_FIELDS sizeof \ 107*e7801d59Ssowmini * (sub_comand_fields) / sizeof (print_field_t)) 108*e7801d59Ssowmini * 109*e7801d59Ssowmini * print_state_t sub_command_print_state; 110*e7801d59Ssowmini * 111*e7801d59Ssowmini * The function that parses command line arguments (typically 112*e7801d59Ssowmini * do_sub_command()) should then contain an invocation like: 113*e7801d59Ssowmini * 114*e7801d59Ssowmini * fields = parse_output_fields(fields_str, sub_command_fields, 115*e7801d59Ssowmini * SUB_COMMAND_MAX_FIELDS, CMD_TYPE_ANY, &nfields); 116*e7801d59Ssowmini * 117*e7801d59Ssowmini * and store the resulting fields and nfields value in a print_state_t 118*e7801d59Ssowmini * structure tracked for the command. 119*e7801d59Ssowmini * 120*e7801d59Ssowmini * sub_command_print_state.ps_fields = fields; 121*e7801d59Ssowmini * sub_command_print_state.ps_nfields = nfields; 122*e7801d59Ssowmini * 123*e7801d59Ssowmini * To print the column header for the output, the print_header() 124*e7801d59Ssowmini * function must then be invoked by do_sub_command(). 125*e7801d59Ssowmini * 126*e7801d59Ssowmini * Then if method (i) is used for the sub_command, the do_sub_command() 127*e7801d59Ssowmini * function should make the necessary system calls to fill up the buffer 128*e7801d59Ssowmini * and then invoke dladm_print_field(). An example of this method is 129*e7801d59Ssowmini * the implementation of do_show_link() and show_link(); 130*e7801d59Ssowmini * 131*e7801d59Ssowmini * If method (ii) is used, do_sub_command should invoke dladm_print_output() 132*e7801d59Ssowmini * with a callback function that will be called for each field to be printed. 133*e7801d59Ssowmini * The callback function will be passed a pointer to the print_field_t 134*e7801d59Ssowmini * for the field, and the pf_index may then be used to identify the 135*e7801d59Ssowmini * system call required to find the value to be printed. An example of 136*e7801d59Ssowmini * this implementation may be found in the do_show_dev() and print_dev() 137*e7801d59Ssowmini * invocation. 138*e7801d59Ssowmini */ 139*e7801d59Ssowmini 140*e7801d59Ssowmini typedef struct print_field_s { 141*e7801d59Ssowmini const char *pf_name; /* name of column to be printed */ 142*e7801d59Ssowmini const char *pf_header; /* header for this column */ 143*e7801d59Ssowmini uint_t pf_width; 144*e7801d59Ssowmini union { 145*e7801d59Ssowmini uint_t _pf_index; /* private index for sub-command */ 146*e7801d59Ssowmini size_t _pf_offset; 147*e7801d59Ssowmini }_pf_un; 148*e7801d59Ssowmini #define pf_index _pf_un._pf_index 149*e7801d59Ssowmini #define pf_offset _pf_un._pf_offset; 150*e7801d59Ssowmini uint_t pf_cmdtype; 151*e7801d59Ssowmini } print_field_t; 152*e7801d59Ssowmini 153*e7801d59Ssowmini /* 154*e7801d59Ssowmini * The state of the output is tracked in a print_state_t structure. 155*e7801d59Ssowmini * Each ps_fields[i] entry points at the global print_field_t array for 156*e7801d59Ssowmini * the sub-command, where ps_nfields is the number of requested fields. 157*e7801d59Ssowmini */ 158*e7801d59Ssowmini typedef struct print_state_s { 159*e7801d59Ssowmini print_field_t **ps_fields; 160*e7801d59Ssowmini uint_t ps_nfields; 161*e7801d59Ssowmini boolean_t ps_lastfield; 162*e7801d59Ssowmini uint_t ps_overflow; 163*e7801d59Ssowmini } print_state_t; 164*e7801d59Ssowmini 165*e7801d59Ssowmini typedef char *(*print_callback_t)(print_field_t *, void *); 166*e7801d59Ssowmini static print_field_t **parse_output_fields(char *, print_field_t *, int, 167*e7801d59Ssowmini uint_t, uint_t *); 168*e7801d59Ssowmini /* 169*e7801d59Ssowmini * print the header for the output 170*e7801d59Ssowmini */ 171*e7801d59Ssowmini static void print_header(print_state_t *); 172*e7801d59Ssowmini static void print_field(print_state_t *, print_field_t *, const char *, 173*e7801d59Ssowmini boolean_t); 174*e7801d59Ssowmini 175*e7801d59Ssowmini /* 176*e7801d59Ssowmini * to print output values, call dladm_print_output with a callback 177*e7801d59Ssowmini * function (*func)() that should parse the args and return an 178*e7801d59Ssowmini * unformatted character buffer with the value to be printed. 179*e7801d59Ssowmini * 180*e7801d59Ssowmini * dladm_print_output() prints the character buffer using the formatting 181*e7801d59Ssowmini * information provided in the print_field_t for that column. 182*e7801d59Ssowmini */ 183*e7801d59Ssowmini static void dladm_print_output(print_state_t *, boolean_t, 184*e7801d59Ssowmini print_callback_t, void *); 185*e7801d59Ssowmini 186*e7801d59Ssowmini /* 187*e7801d59Ssowmini * helper function that, when invoked as dladm_print_field(pf, buf) 188*e7801d59Ssowmini * prints string which is offset by pf->pf_offset within buf 189*e7801d59Ssowmini */ 190*e7801d59Ssowmini static char *dladm_print_field(print_field_t *, void *); 191*e7801d59Ssowmini 192*e7801d59Ssowmini 193*e7801d59Ssowmini #define MAX_FIELD_LEN 32 194*e7801d59Ssowmini 195*e7801d59Ssowmini 1967c478bd9Sstevel@tonic-gate typedef struct pktsum_s { 1977c478bd9Sstevel@tonic-gate uint64_t ipackets; 1987c478bd9Sstevel@tonic-gate uint64_t opackets; 1997c478bd9Sstevel@tonic-gate uint64_t rbytes; 2007c478bd9Sstevel@tonic-gate uint64_t obytes; 2017c478bd9Sstevel@tonic-gate uint32_t ierrors; 2027c478bd9Sstevel@tonic-gate uint32_t oerrors; 2037c478bd9Sstevel@tonic-gate } pktsum_t; 2047c478bd9Sstevel@tonic-gate 205d62bc4baSyz147064 typedef struct show_state { 2067c478bd9Sstevel@tonic-gate boolean_t ls_firstonly; 2077c478bd9Sstevel@tonic-gate boolean_t ls_donefirst; 2087c478bd9Sstevel@tonic-gate pktsum_t ls_prevstats; 209d62bc4baSyz147064 uint32_t ls_flags; 210d62bc4baSyz147064 dladm_status_t ls_status; 211*e7801d59Ssowmini print_state_t ls_print; 212*e7801d59Ssowmini boolean_t ls_parseable; 213*e7801d59Ssowmini boolean_t ls_printheader; 214d62bc4baSyz147064 } show_state_t; 2157c478bd9Sstevel@tonic-gate 2167c478bd9Sstevel@tonic-gate typedef struct show_grp_state { 217*e7801d59Ssowmini pktsum_t gs_prevstats[MAXPORT]; 218*e7801d59Ssowmini uint32_t gs_flags; 219*e7801d59Ssowmini dladm_status_t gs_status; 220*e7801d59Ssowmini boolean_t gs_parseable; 2217c478bd9Sstevel@tonic-gate boolean_t gs_lacp; 222d62bc4baSyz147064 boolean_t gs_extended; 2237c478bd9Sstevel@tonic-gate boolean_t gs_stats; 2247c478bd9Sstevel@tonic-gate boolean_t gs_firstonly; 225d62bc4baSyz147064 boolean_t gs_donefirst; 226*e7801d59Ssowmini boolean_t gs_printheader; 227*e7801d59Ssowmini print_state_t gs_print; 2287c478bd9Sstevel@tonic-gate } show_grp_state_t; 2297c478bd9Sstevel@tonic-gate 2300ba2cbe9Sxc151355 typedef void cmdfunc_t(int, char **); 2310ba2cbe9Sxc151355 232d62bc4baSyz147064 static cmdfunc_t do_show_link, do_show_dev, do_show_wifi, do_show_phys; 2330ba2cbe9Sxc151355 static cmdfunc_t do_create_aggr, do_delete_aggr, do_add_aggr, do_remove_aggr; 234d62bc4baSyz147064 static cmdfunc_t do_modify_aggr, do_show_aggr, do_up_aggr; 2350ba2cbe9Sxc151355 static cmdfunc_t do_scan_wifi, do_connect_wifi, do_disconnect_wifi; 2360ba2cbe9Sxc151355 static cmdfunc_t do_show_linkprop, do_set_linkprop, do_reset_linkprop; 2370ba2cbe9Sxc151355 static cmdfunc_t do_create_secobj, do_delete_secobj, do_show_secobj; 2380ba2cbe9Sxc151355 static cmdfunc_t do_init_linkprop, do_init_secobj; 239d62bc4baSyz147064 static cmdfunc_t do_create_vlan, do_delete_vlan, do_up_vlan, do_show_vlan; 240d62bc4baSyz147064 static cmdfunc_t do_rename_link, do_delete_phys, do_init_phys; 241d62bc4baSyz147064 static cmdfunc_t do_show_linkmap; 242*e7801d59Ssowmini static cmdfunc_t do_show_ether; 2437c478bd9Sstevel@tonic-gate 244d62bc4baSyz147064 static void altroot_cmd(char *, int, char **); 245d62bc4baSyz147064 static int show_linkprop_onelink(datalink_id_t, void *); 246f4b3ec61Sdh155122 247d62bc4baSyz147064 static void link_stats(datalink_id_t, uint_t); 248d62bc4baSyz147064 static void aggr_stats(datalink_id_t, show_grp_state_t *, uint_t); 249*e7801d59Ssowmini static void dev_stats(const char *dev, uint32_t, char *, show_state_t *); 2507c478bd9Sstevel@tonic-gate 251d62bc4baSyz147064 static int get_one_kstat(const char *, const char *, uint8_t, 252d62bc4baSyz147064 void *, boolean_t); 253ba2e4443Sseb static void get_mac_stats(const char *, pktsum_t *); 2547c478bd9Sstevel@tonic-gate static void get_link_stats(const char *, pktsum_t *); 255d62bc4baSyz147064 static uint64_t get_ifspeed(const char *, boolean_t); 2567c478bd9Sstevel@tonic-gate static void stats_total(pktsum_t *, pktsum_t *, pktsum_t *); 2577c478bd9Sstevel@tonic-gate static void stats_diff(pktsum_t *, pktsum_t *, pktsum_t *); 258d62bc4baSyz147064 static const char *get_linkstate(const char *, boolean_t, char *); 259d62bc4baSyz147064 static const char *get_linkduplex(const char *, boolean_t, char *); 2607c478bd9Sstevel@tonic-gate 261*e7801d59Ssowmini static int show_etherprop(datalink_id_t, void *); 262*e7801d59Ssowmini static void show_ether_xprop(datalink_id_t, void *); 263*e7801d59Ssowmini static boolean_t get_speed_duplex(datalink_id_t, const char *, char *, 264*e7801d59Ssowmini char *, boolean_t); 265*e7801d59Ssowmini static char *pause_str(int, int); 266*e7801d59Ssowmini static boolean_t link_is_ether(const char *, datalink_id_t *); 267*e7801d59Ssowmini 268*e7801d59Ssowmini #define IS_FDX 0x10 269*e7801d59Ssowmini #define IS_HDX 0x01 270*e7801d59Ssowmini 27133343a97Smeem static boolean_t str2int(const char *, int *); 27233343a97Smeem static void die(const char *, ...); 27333343a97Smeem static void die_optdup(int); 27433343a97Smeem static void die_opterr(int, int); 27533343a97Smeem static void die_dlerr(dladm_status_t, const char *, ...); 27633343a97Smeem static void warn(const char *, ...); 27733343a97Smeem static void warn_dlerr(dladm_status_t, const char *, ...); 27833343a97Smeem 2797c478bd9Sstevel@tonic-gate typedef struct cmd { 2807c478bd9Sstevel@tonic-gate char *c_name; 2810ba2cbe9Sxc151355 cmdfunc_t *c_fn; 2827c478bd9Sstevel@tonic-gate } cmd_t; 2837c478bd9Sstevel@tonic-gate 2847c478bd9Sstevel@tonic-gate static cmd_t cmds[] = { 2857c478bd9Sstevel@tonic-gate { "show-link", do_show_link }, 286210db224Sericheng { "show-dev", do_show_dev }, 2877c478bd9Sstevel@tonic-gate { "create-aggr", do_create_aggr }, 2887c478bd9Sstevel@tonic-gate { "delete-aggr", do_delete_aggr }, 2897c478bd9Sstevel@tonic-gate { "add-aggr", do_add_aggr }, 2907c478bd9Sstevel@tonic-gate { "remove-aggr", do_remove_aggr }, 2917c478bd9Sstevel@tonic-gate { "modify-aggr", do_modify_aggr }, 2927c478bd9Sstevel@tonic-gate { "show-aggr", do_show_aggr }, 2937c478bd9Sstevel@tonic-gate { "up-aggr", do_up_aggr }, 2940ba2cbe9Sxc151355 { "scan-wifi", do_scan_wifi }, 2950ba2cbe9Sxc151355 { "connect-wifi", do_connect_wifi }, 2960ba2cbe9Sxc151355 { "disconnect-wifi", do_disconnect_wifi }, 2970ba2cbe9Sxc151355 { "show-wifi", do_show_wifi }, 2980ba2cbe9Sxc151355 { "show-linkprop", do_show_linkprop }, 2990ba2cbe9Sxc151355 { "set-linkprop", do_set_linkprop }, 3000ba2cbe9Sxc151355 { "reset-linkprop", do_reset_linkprop }, 301*e7801d59Ssowmini { "show-ether", do_show_ether }, 3020ba2cbe9Sxc151355 { "create-secobj", do_create_secobj }, 3030ba2cbe9Sxc151355 { "delete-secobj", do_delete_secobj }, 3040ba2cbe9Sxc151355 { "show-secobj", do_show_secobj }, 3050ba2cbe9Sxc151355 { "init-linkprop", do_init_linkprop }, 306d62bc4baSyz147064 { "init-secobj", do_init_secobj }, 307d62bc4baSyz147064 { "create-vlan", do_create_vlan }, 308d62bc4baSyz147064 { "delete-vlan", do_delete_vlan }, 309d62bc4baSyz147064 { "show-vlan", do_show_vlan }, 310d62bc4baSyz147064 { "up-vlan", do_up_vlan }, 311d62bc4baSyz147064 { "rename-link", do_rename_link }, 312d62bc4baSyz147064 { "delete-phys", do_delete_phys }, 313d62bc4baSyz147064 { "show-phys", do_show_phys }, 314d62bc4baSyz147064 { "init-phys", do_init_phys }, 315d62bc4baSyz147064 { "show-linkmap", do_show_linkmap } 3167c478bd9Sstevel@tonic-gate }; 3177c478bd9Sstevel@tonic-gate 318d62bc4baSyz147064 static const struct option lopts[] = { 3197c478bd9Sstevel@tonic-gate {"vlan-id", required_argument, 0, 'v'}, 320*e7801d59Ssowmini {"output", required_argument, 0, 'o'}, 3217c478bd9Sstevel@tonic-gate {"dev", required_argument, 0, 'd'}, 3227c478bd9Sstevel@tonic-gate {"policy", required_argument, 0, 'P'}, 323d62bc4baSyz147064 {"lacp-mode", required_argument, 0, 'L'}, 3247c478bd9Sstevel@tonic-gate {"lacp-timer", required_argument, 0, 'T'}, 3257c478bd9Sstevel@tonic-gate {"unicast", required_argument, 0, 'u'}, 326d62bc4baSyz147064 {"temporary", no_argument, 0, 't'}, 327d62bc4baSyz147064 {"root-dir", required_argument, 0, 'R'}, 328d62bc4baSyz147064 {"link", required_argument, 0, 'l'}, 329d62bc4baSyz147064 {"forcible", no_argument, 0, 'f'}, 330d62bc4baSyz147064 { 0, 0, 0, 0 } 331d62bc4baSyz147064 }; 332d62bc4baSyz147064 333d62bc4baSyz147064 static const struct option show_lopts[] = { 3347c478bd9Sstevel@tonic-gate {"statistics", no_argument, 0, 's'}, 3357c478bd9Sstevel@tonic-gate {"interval", required_argument, 0, 'i'}, 3367c478bd9Sstevel@tonic-gate {"parseable", no_argument, 0, 'p'}, 337d62bc4baSyz147064 {"extended", no_argument, 0, 'x'}, 338*e7801d59Ssowmini {"output", required_argument, 0, 'o'}, 339d62bc4baSyz147064 {"persistent", no_argument, 0, 'P'}, 340d62bc4baSyz147064 {"lacp", no_argument, 0, 'L'}, 3417c478bd9Sstevel@tonic-gate { 0, 0, 0, 0 } 3427c478bd9Sstevel@tonic-gate }; 3437c478bd9Sstevel@tonic-gate 3440ba2cbe9Sxc151355 static const struct option prop_longopts[] = { 3450ba2cbe9Sxc151355 {"temporary", no_argument, 0, 't' }, 346*e7801d59Ssowmini {"output", required_argument, 0, 'o' }, 3470ba2cbe9Sxc151355 {"root-dir", required_argument, 0, 'R' }, 3480ba2cbe9Sxc151355 {"prop", required_argument, 0, 'p' }, 3490ba2cbe9Sxc151355 {"parseable", no_argument, 0, 'c' }, 3500ba2cbe9Sxc151355 {"persistent", no_argument, 0, 'P' }, 3510ba2cbe9Sxc151355 { 0, 0, 0, 0 } 3520ba2cbe9Sxc151355 }; 3530ba2cbe9Sxc151355 3540ba2cbe9Sxc151355 static const struct option wifi_longopts[] = { 3550ba2cbe9Sxc151355 {"parseable", no_argument, 0, 'p' }, 3560ba2cbe9Sxc151355 {"output", required_argument, 0, 'o' }, 3570ba2cbe9Sxc151355 {"essid", required_argument, 0, 'e' }, 3580ba2cbe9Sxc151355 {"bsstype", required_argument, 0, 'b' }, 3590ba2cbe9Sxc151355 {"mode", required_argument, 0, 'm' }, 3600ba2cbe9Sxc151355 {"key", required_argument, 0, 'k' }, 3610ba2cbe9Sxc151355 {"sec", required_argument, 0, 's' }, 3620ba2cbe9Sxc151355 {"auth", required_argument, 0, 'a' }, 3630ba2cbe9Sxc151355 {"create-ibss", required_argument, 0, 'c' }, 3640ba2cbe9Sxc151355 {"timeout", required_argument, 0, 'T' }, 3650ba2cbe9Sxc151355 {"all-links", no_argument, 0, 'a' }, 3660ba2cbe9Sxc151355 {"temporary", no_argument, 0, 't' }, 3670ba2cbe9Sxc151355 {"root-dir", required_argument, 0, 'R' }, 3680ba2cbe9Sxc151355 {"persistent", no_argument, 0, 'P' }, 3690ba2cbe9Sxc151355 {"file", required_argument, 0, 'f' }, 3700ba2cbe9Sxc151355 { 0, 0, 0, 0 } 3710ba2cbe9Sxc151355 }; 372*e7801d59Ssowmini static const struct option showeth_lopts[] = { 373*e7801d59Ssowmini {"parseable", no_argument, 0, 'p' }, 374*e7801d59Ssowmini {"extended", no_argument, 0, 'x' }, 375*e7801d59Ssowmini {"output", required_argument, 0, 'o' }, 376*e7801d59Ssowmini { 0, 0, 0, 0 } 377*e7801d59Ssowmini }; 378*e7801d59Ssowmini 379*e7801d59Ssowmini /* 380*e7801d59Ssowmini * structures for 'dladm show-ether' 381*e7801d59Ssowmini */ 382*e7801d59Ssowmini typedef struct ether_fields_buf_s 383*e7801d59Ssowmini { 384*e7801d59Ssowmini char eth_link[15]; 385*e7801d59Ssowmini char eth_ptype[8]; 386*e7801d59Ssowmini char eth_state[8]; 387*e7801d59Ssowmini char eth_autoneg[5]; 388*e7801d59Ssowmini char eth_spdx[31]; 389*e7801d59Ssowmini char eth_pause[6]; 390*e7801d59Ssowmini char eth_rem_fault[16]; 391*e7801d59Ssowmini } ether_fields_buf_t; 392*e7801d59Ssowmini 393*e7801d59Ssowmini static print_field_t ether_fields[] = { 394*e7801d59Ssowmini /* name, header, field width, offset, cmdtype */ 395*e7801d59Ssowmini { "link", "LINK", 15, 396*e7801d59Ssowmini offsetof(ether_fields_buf_t, eth_link), CMD_TYPE_ANY}, 397*e7801d59Ssowmini { "ptype", "PTYPE", 8, 398*e7801d59Ssowmini offsetof(ether_fields_buf_t, eth_ptype), CMD_TYPE_ANY}, 399*e7801d59Ssowmini { "state", "STATE", 8, 400*e7801d59Ssowmini offsetof(ether_fields_buf_t, eth_state), CMD_TYPE_ANY}, 401*e7801d59Ssowmini { "auto", "AUTO", 5, 402*e7801d59Ssowmini offsetof(ether_fields_buf_t, eth_autoneg), CMD_TYPE_ANY}, 403*e7801d59Ssowmini { "speed-duplex", "SPEED-DUPLEX", 31, 404*e7801d59Ssowmini offsetof(ether_fields_buf_t, eth_spdx), CMD_TYPE_ANY}, 405*e7801d59Ssowmini { "pause", "PAUSE", 6, 406*e7801d59Ssowmini offsetof(ether_fields_buf_t, eth_pause), CMD_TYPE_ANY}, 407*e7801d59Ssowmini { "rem_fault", "REM_FAULT", 16, 408*e7801d59Ssowmini offsetof(ether_fields_buf_t, eth_rem_fault), CMD_TYPE_ANY}} 409*e7801d59Ssowmini ; 410*e7801d59Ssowmini #define ETHER_MAX_FIELDS (sizeof (ether_fields) / sizeof (print_field_t)) 411*e7801d59Ssowmini 412*e7801d59Ssowmini typedef struct print_ether_state { 413*e7801d59Ssowmini const char *es_link; 414*e7801d59Ssowmini boolean_t es_parseable; 415*e7801d59Ssowmini boolean_t es_header; 416*e7801d59Ssowmini boolean_t es_extended; 417*e7801d59Ssowmini print_state_t es_print; 418*e7801d59Ssowmini } print_ether_state_t; 419*e7801d59Ssowmini 420*e7801d59Ssowmini /* 421*e7801d59Ssowmini * structures for 'dladm show-dev'. 422*e7801d59Ssowmini */ 423*e7801d59Ssowmini typedef enum { 424*e7801d59Ssowmini DEV_LINK, 425*e7801d59Ssowmini DEV_STATE, 426*e7801d59Ssowmini DEV_SPEED, 427*e7801d59Ssowmini DEV_DUPLEX 428*e7801d59Ssowmini } dev_field_index_t; 429*e7801d59Ssowmini 430*e7801d59Ssowmini static print_field_t dev_fields[] = { 431*e7801d59Ssowmini /* name, header, field width, index, cmdtype */ 432*e7801d59Ssowmini { "link", "LINK", 15, DEV_LINK, CMD_TYPE_ANY}, 433*e7801d59Ssowmini { "state", "STATE", 6, DEV_STATE, CMD_TYPE_ANY}, 434*e7801d59Ssowmini { "speed", "SPEED", 8, DEV_SPEED, CMD_TYPE_ANY}, 435*e7801d59Ssowmini { "duplex", "DUPLEX", 8, DEV_DUPLEX, CMD_TYPE_ANY}} 436*e7801d59Ssowmini ; 437*e7801d59Ssowmini #define DEV_MAX_FIELDS (sizeof (dev_fields) / sizeof (print_field_t)) 438*e7801d59Ssowmini 439*e7801d59Ssowmini /* 440*e7801d59Ssowmini * structures for 'dladm show-dev -s' (print statistics) 441*e7801d59Ssowmini */ 442*e7801d59Ssowmini typedef enum { 443*e7801d59Ssowmini DEVS_LINK, 444*e7801d59Ssowmini DEVS_IPKTS, 445*e7801d59Ssowmini DEVS_RBYTES, 446*e7801d59Ssowmini DEVS_IERRORS, 447*e7801d59Ssowmini DEVS_OPKTS, 448*e7801d59Ssowmini DEVS_OBYTES, 449*e7801d59Ssowmini DEVS_OERRORS 450*e7801d59Ssowmini } devs_field_index_t; 451*e7801d59Ssowmini 452*e7801d59Ssowmini static print_field_t devs_fields[] = { 453*e7801d59Ssowmini /* name, header, field width, index, cmdtype */ 454*e7801d59Ssowmini { "link", "LINK", 15, DEVS_LINK, CMD_TYPE_ANY}, 455*e7801d59Ssowmini { "ipackets", "IPACKETS", 10, DEVS_IPKTS, CMD_TYPE_ANY}, 456*e7801d59Ssowmini { "rbytes", "RBYTES", 8, DEVS_RBYTES, CMD_TYPE_ANY}, 457*e7801d59Ssowmini { "ierrors", "IERRORS", 10, DEVS_IERRORS, CMD_TYPE_ANY}, 458*e7801d59Ssowmini { "opackets", "OPACKETS", 12, DEVS_OPKTS, CMD_TYPE_ANY}, 459*e7801d59Ssowmini { "obytes", "OBYTES", 12, DEVS_OBYTES, CMD_TYPE_ANY}, 460*e7801d59Ssowmini { "oerrors", "OERRORS", 8, DEVS_OERRORS, CMD_TYPE_ANY}} 461*e7801d59Ssowmini ; 462*e7801d59Ssowmini #define DEVS_MAX_FIELDS (sizeof (devs_fields) / sizeof (print_field_t)) 463*e7801d59Ssowmini typedef struct dev_args_s { 464*e7801d59Ssowmini char *devs_link; 465*e7801d59Ssowmini pktsum_t *devs_psum; 466*e7801d59Ssowmini } dev_args_t; 467*e7801d59Ssowmini static char *print_dev_stats(print_field_t *, void *); 468*e7801d59Ssowmini static char *print_dev(print_field_t *, void *); 469*e7801d59Ssowmini 470*e7801d59Ssowmini /* 471*e7801d59Ssowmini * buffer used by print functions for show-{link,phys,vlan} commands. 472*e7801d59Ssowmini */ 473*e7801d59Ssowmini typedef struct link_fields_buf_s { 474*e7801d59Ssowmini char link_name[MAXLINKNAMELEN]; 475*e7801d59Ssowmini char link_class[DLADM_STRSIZE]; 476*e7801d59Ssowmini char link_mtu[6]; 477*e7801d59Ssowmini char link_state[DLADM_STRSIZE]; 478*e7801d59Ssowmini char link_over[MAXLINKNAMELEN]; 479*e7801d59Ssowmini char link_phys_state[6]; 480*e7801d59Ssowmini char link_phys_media[DLADM_STRSIZE]; 481*e7801d59Ssowmini char link_phys_speed[DLADM_STRSIZE]; 482*e7801d59Ssowmini char link_phys_duplex[DLPI_LINKNAME_MAX]; 483*e7801d59Ssowmini char link_phys_device[DLPI_LINKNAME_MAX]; 484*e7801d59Ssowmini char link_flags[6]; 485*e7801d59Ssowmini char link_vlan_vid[6]; 486*e7801d59Ssowmini } link_fields_buf_t; 487*e7801d59Ssowmini 488*e7801d59Ssowmini /* 489*e7801d59Ssowmini * structures for 'dladm show-link' 490*e7801d59Ssowmini */ 491*e7801d59Ssowmini static print_field_t link_fields[] = { 492*e7801d59Ssowmini /* name, header, field width, offset, cmdtype */ 493*e7801d59Ssowmini { "link", "LINK", 11, 494*e7801d59Ssowmini offsetof(link_fields_buf_t, link_name), CMD_TYPE_ANY}, 495*e7801d59Ssowmini { "class", "CLASS", 8, 496*e7801d59Ssowmini offsetof(link_fields_buf_t, link_class), CMD_TYPE_ANY}, 497*e7801d59Ssowmini { "mtu", "MTU", 6, 498*e7801d59Ssowmini offsetof(link_fields_buf_t, link_mtu), CMD_TYPE_ANY}, 499*e7801d59Ssowmini { "state", "STATE", 8, 500*e7801d59Ssowmini offsetof(link_fields_buf_t, link_state), CMD_TYPE_ANY}, 501*e7801d59Ssowmini { "over", "OVER", DLPI_LINKNAME_MAX, 502*e7801d59Ssowmini offsetof(link_fields_buf_t, link_over), CMD_TYPE_ANY}} 503*e7801d59Ssowmini ; 504*e7801d59Ssowmini #define DEV_LINK_FIELDS (sizeof (link_fields) / sizeof (print_field_t)) 505*e7801d59Ssowmini 506*e7801d59Ssowmini /* 507*e7801d59Ssowmini * structures for 'dladm show-aggr' 508*e7801d59Ssowmini */ 509*e7801d59Ssowmini typedef struct laggr_fields_buf_s { 510*e7801d59Ssowmini char laggr_name[DLPI_LINKNAME_MAX]; 511*e7801d59Ssowmini char laggr_policy[9]; 512*e7801d59Ssowmini char laggr_addrpolicy[ETHERADDRL * 3 + 3]; 513*e7801d59Ssowmini char laggr_lacpactivity[14]; 514*e7801d59Ssowmini char laggr_lacptimer[DLADM_STRSIZE]; 515*e7801d59Ssowmini char laggr_flags[7]; 516*e7801d59Ssowmini } laggr_fields_buf_t; 517*e7801d59Ssowmini 518*e7801d59Ssowmini typedef struct laggr_args_s { 519*e7801d59Ssowmini int laggr_lport; /* -1 indicates the aggr itself */ 520*e7801d59Ssowmini const char *laggr_link; 521*e7801d59Ssowmini dladm_aggr_grp_attr_t *laggr_ginfop; 522*e7801d59Ssowmini dladm_status_t *laggr_status; 523*e7801d59Ssowmini pktsum_t *laggr_pktsumtot; /* -s only */ 524*e7801d59Ssowmini pktsum_t *laggr_prevstats; /* -s only */ 525*e7801d59Ssowmini boolean_t laggr_parseable; 526*e7801d59Ssowmini } laggr_args_t; 527*e7801d59Ssowmini 528*e7801d59Ssowmini static print_field_t laggr_fields[] = { 529*e7801d59Ssowmini /* name, header, field width, offset, cmdtype */ 530*e7801d59Ssowmini { "link", "LINK", 15, 531*e7801d59Ssowmini offsetof(laggr_fields_buf_t, laggr_name), CMD_TYPE_ANY}, 532*e7801d59Ssowmini { "policy", "POLICY", 8, 533*e7801d59Ssowmini offsetof(laggr_fields_buf_t, laggr_policy), CMD_TYPE_ANY}, 534*e7801d59Ssowmini { "addrpolicy", "ADDRPOLICY", ETHERADDRL * 3 + 2, 535*e7801d59Ssowmini offsetof(laggr_fields_buf_t, laggr_addrpolicy), CMD_TYPE_ANY}, 536*e7801d59Ssowmini { "lacpactivity", "LACPACTIVITY", 13, 537*e7801d59Ssowmini offsetof(laggr_fields_buf_t, laggr_lacpactivity), CMD_TYPE_ANY}, 538*e7801d59Ssowmini { "lacptimer", "LACPTIMER", 11, 539*e7801d59Ssowmini offsetof(laggr_fields_buf_t, laggr_lacptimer), CMD_TYPE_ANY}, 540*e7801d59Ssowmini { "flags", "FLAGS", 7, 541*e7801d59Ssowmini offsetof(laggr_fields_buf_t, laggr_flags), CMD_TYPE_ANY}} 542*e7801d59Ssowmini ; 543*e7801d59Ssowmini #define LAGGR_MAX_FIELDS (sizeof (laggr_fields) / sizeof (print_field_t)) 544*e7801d59Ssowmini 545*e7801d59Ssowmini /* 546*e7801d59Ssowmini * structures for 'dladm show-aggr -x'. 547*e7801d59Ssowmini */ 548*e7801d59Ssowmini typedef enum { 549*e7801d59Ssowmini AGGR_X_LINK, 550*e7801d59Ssowmini AGGR_X_PORT, 551*e7801d59Ssowmini AGGR_X_SPEED, 552*e7801d59Ssowmini AGGR_X_DUPLEX, 553*e7801d59Ssowmini AGGR_X_STATE, 554*e7801d59Ssowmini AGGR_X_ADDRESS, 555*e7801d59Ssowmini AGGR_X_PORTSTATE 556*e7801d59Ssowmini } aggr_x_field_index_t; 557*e7801d59Ssowmini 558*e7801d59Ssowmini static print_field_t aggr_x_fields[] = { 559*e7801d59Ssowmini /* name, header, field width, index, cmdtype */ 560*e7801d59Ssowmini { "link", "LINK", 11, AGGR_X_LINK, CMD_TYPE_ANY}, 561*e7801d59Ssowmini { "port", "PORT", 14, AGGR_X_PORT, CMD_TYPE_ANY}, 562*e7801d59Ssowmini { "speed", "SPEED", 4, AGGR_X_SPEED, CMD_TYPE_ANY}, 563*e7801d59Ssowmini { "duplex", "DUPLEX", 9, AGGR_X_DUPLEX, CMD_TYPE_ANY}, 564*e7801d59Ssowmini { "state", "STATE", 9, AGGR_X_STATE, CMD_TYPE_ANY}, 565*e7801d59Ssowmini { "address", "ADDRESS", 18, AGGR_X_ADDRESS, CMD_TYPE_ANY}, 566*e7801d59Ssowmini { "portstate", "PORTSTATE", 15, AGGR_X_PORTSTATE, CMD_TYPE_ANY}} 567*e7801d59Ssowmini ; 568*e7801d59Ssowmini #define AGGR_X_MAX_FIELDS \ 569*e7801d59Ssowmini (sizeof (aggr_x_fields) / sizeof (print_field_t)) 570*e7801d59Ssowmini 571*e7801d59Ssowmini /* 572*e7801d59Ssowmini * structures for 'dladm show-aggr -s'. 573*e7801d59Ssowmini */ 574*e7801d59Ssowmini typedef enum { 575*e7801d59Ssowmini AGGR_S_LINK, 576*e7801d59Ssowmini AGGR_S_PORT, 577*e7801d59Ssowmini AGGR_S_IPKTS, 578*e7801d59Ssowmini AGGR_S_RBYTES, 579*e7801d59Ssowmini AGGR_S_OPKTS, 580*e7801d59Ssowmini AGGR_S_OBYTES, 581*e7801d59Ssowmini AGGR_S_IPKTDIST, 582*e7801d59Ssowmini AGGR_S_OPKTDIST 583*e7801d59Ssowmini } aggr_s_field_index_t; 584*e7801d59Ssowmini 585*e7801d59Ssowmini static print_field_t aggr_s_fields[] = { 586*e7801d59Ssowmini /* name, header, field width, index, cmdtype */ 587*e7801d59Ssowmini { "link", "LINK", 11, AGGR_S_LINK, 588*e7801d59Ssowmini CMD_TYPE_ANY}, 589*e7801d59Ssowmini { "port", "PORT", 9, AGGR_S_PORT, 590*e7801d59Ssowmini CMD_TYPE_ANY}, 591*e7801d59Ssowmini { "ipackets", "IPACKETS", 7, AGGR_S_IPKTS, 592*e7801d59Ssowmini CMD_TYPE_ANY}, 593*e7801d59Ssowmini { "rbytes", "RBYTES", 7, AGGR_S_RBYTES, 594*e7801d59Ssowmini CMD_TYPE_ANY}, 595*e7801d59Ssowmini { "opackets", "OPACKETS", 7, AGGR_S_OPKTS, 596*e7801d59Ssowmini CMD_TYPE_ANY}, 597*e7801d59Ssowmini { "obytes", "OBYTES", 7, AGGR_S_OBYTES, 598*e7801d59Ssowmini CMD_TYPE_ANY}, 599*e7801d59Ssowmini { "ipktdist", "IPKTDIST", 8, AGGR_S_IPKTDIST, 600*e7801d59Ssowmini CMD_TYPE_ANY}, 601*e7801d59Ssowmini { "opktdist", "OPKTDIST", 14, AGGR_S_OPKTDIST, 602*e7801d59Ssowmini CMD_TYPE_ANY}} 603*e7801d59Ssowmini ; 604*e7801d59Ssowmini #define AGGR_S_MAX_FIELDS \ 605*e7801d59Ssowmini (sizeof (aggr_l_fields) / sizeof (print_field_t)) 606*e7801d59Ssowmini 607*e7801d59Ssowmini /* 608*e7801d59Ssowmini * structures for 'dladm show-dev -L'. 609*e7801d59Ssowmini */ 610*e7801d59Ssowmini typedef enum { 611*e7801d59Ssowmini AGGR_L_LINK, 612*e7801d59Ssowmini AGGR_L_PORT, 613*e7801d59Ssowmini AGGR_L_AGGREGATABLE, 614*e7801d59Ssowmini AGGR_L_SYNC, 615*e7801d59Ssowmini AGGR_L_COLL, 616*e7801d59Ssowmini AGGR_L_DIST, 617*e7801d59Ssowmini AGGR_L_DEFAULTED, 618*e7801d59Ssowmini AGGR_L_EXPIRED 619*e7801d59Ssowmini } aggr_l_field_index_t; 620*e7801d59Ssowmini 621*e7801d59Ssowmini static print_field_t aggr_l_fields[] = { 622*e7801d59Ssowmini /* name, header, field width, index, cmdtype */ 623*e7801d59Ssowmini { "link", "LINK", 11, AGGR_L_LINK, 624*e7801d59Ssowmini CMD_TYPE_ANY}, 625*e7801d59Ssowmini { "port", "PORT", 12, AGGR_L_PORT, 626*e7801d59Ssowmini CMD_TYPE_ANY}, 627*e7801d59Ssowmini { "aggregatable", "AGGREGATABLE", 12, AGGR_L_AGGREGATABLE, 628*e7801d59Ssowmini CMD_TYPE_ANY}, 629*e7801d59Ssowmini { "sync", "SYNC", 4, AGGR_L_SYNC, 630*e7801d59Ssowmini CMD_TYPE_ANY}, 631*e7801d59Ssowmini { "coll", "COLL", 4, AGGR_L_COLL, 632*e7801d59Ssowmini CMD_TYPE_ANY}, 633*e7801d59Ssowmini { "dist", "DIST", 4, AGGR_L_DIST, 634*e7801d59Ssowmini CMD_TYPE_ANY}, 635*e7801d59Ssowmini { "defaulted", "DEFAULTED", 9, AGGR_L_DEFAULTED, 636*e7801d59Ssowmini CMD_TYPE_ANY}, 637*e7801d59Ssowmini { "expired", "EXPIRED", 14, AGGR_L_EXPIRED, 638*e7801d59Ssowmini CMD_TYPE_ANY}} 639*e7801d59Ssowmini ; 640*e7801d59Ssowmini #define AGGR_L_MAX_FIELDS \ 641*e7801d59Ssowmini (sizeof (aggr_l_fields) / sizeof (print_field_t)) 642*e7801d59Ssowmini 643*e7801d59Ssowmini /* 644*e7801d59Ssowmini * structures for 'dladm show-phys' 645*e7801d59Ssowmini */ 646*e7801d59Ssowmini 647*e7801d59Ssowmini static print_field_t phys_fields[] = { 648*e7801d59Ssowmini /* name, header, field width, offset, cmdtype */ 649*e7801d59Ssowmini { "link", "LINK", 12, 650*e7801d59Ssowmini offsetof(link_fields_buf_t, link_name), CMD_TYPE_ANY}, 651*e7801d59Ssowmini { "media", "MEDIA", 20, 652*e7801d59Ssowmini offsetof(link_fields_buf_t, link_phys_media), CMD_TYPE_ANY}, 653*e7801d59Ssowmini { "state", "STATE", 10, 654*e7801d59Ssowmini offsetof(link_fields_buf_t, link_phys_state), CMD_TYPE_ANY}, 655*e7801d59Ssowmini { "speed", "SPEED", 4, 656*e7801d59Ssowmini offsetof(link_fields_buf_t, link_phys_speed), CMD_TYPE_ANY}, 657*e7801d59Ssowmini { "duplex", "DUPLEX", 9, 658*e7801d59Ssowmini offsetof(link_fields_buf_t, link_phys_duplex), CMD_TYPE_ANY}, 659*e7801d59Ssowmini { "device", "DEVICE", 12, 660*e7801d59Ssowmini offsetof(link_fields_buf_t, link_phys_device), CMD_TYPE_ANY}, 661*e7801d59Ssowmini { "flags", "FLAGS", 6, 662*e7801d59Ssowmini offsetof(link_fields_buf_t, link_flags), CMD_TYPE_ANY}} 663*e7801d59Ssowmini ; 664*e7801d59Ssowmini #define PHYS_MAX_FIELDS (sizeof (phys_fields) / sizeof (print_field_t)) 665*e7801d59Ssowmini 666*e7801d59Ssowmini /* 667*e7801d59Ssowmini * structures for 'dladm show-vlan' 668*e7801d59Ssowmini */ 669*e7801d59Ssowmini static print_field_t vlan_fields[] = { 670*e7801d59Ssowmini /* name, header, field width, offset, cmdtype */ 671*e7801d59Ssowmini { "link", "LINK", 15, 672*e7801d59Ssowmini offsetof(link_fields_buf_t, link_name), CMD_TYPE_ANY}, 673*e7801d59Ssowmini { "vid", "VID", 8, 674*e7801d59Ssowmini offsetof(link_fields_buf_t, link_vlan_vid), CMD_TYPE_ANY}, 675*e7801d59Ssowmini { "over", "OVER", 12, 676*e7801d59Ssowmini offsetof(link_fields_buf_t, link_over), CMD_TYPE_ANY}, 677*e7801d59Ssowmini { "flags", "FLAGS", 6, 678*e7801d59Ssowmini offsetof(link_fields_buf_t, link_flags), CMD_TYPE_ANY}} 679*e7801d59Ssowmini ; 680*e7801d59Ssowmini #define VLAN_MAX_FIELDS (sizeof (vlan_fields) / sizeof (print_field_t)) 681*e7801d59Ssowmini 682*e7801d59Ssowmini /* 683*e7801d59Ssowmini * structures for 'dladm show-wifi' 684*e7801d59Ssowmini */ 685*e7801d59Ssowmini static print_field_t wifi_fields[] = { 686*e7801d59Ssowmini { "link", "LINK", 10, 0, WIFI_CMD_ALL}, 687*e7801d59Ssowmini { "essid", "ESSID", 19, DLADM_WLAN_ATTR_ESSID, WIFI_CMD_ALL}, 688*e7801d59Ssowmini { "bssid", "BSSID/IBSSID", 17, DLADM_WLAN_ATTR_BSSID, WIFI_CMD_ALL}, 689*e7801d59Ssowmini { "ibssid", "BSSID/IBSSID", 17, DLADM_WLAN_ATTR_BSSID, WIFI_CMD_ALL}, 690*e7801d59Ssowmini { "mode", "MODE", 6, DLADM_WLAN_ATTR_MODE, WIFI_CMD_ALL}, 691*e7801d59Ssowmini { "speed", "SPEED", 6, DLADM_WLAN_ATTR_SPEED, WIFI_CMD_ALL}, 692*e7801d59Ssowmini { "auth", "AUTH", 8, DLADM_WLAN_ATTR_AUTH, WIFI_CMD_SHOW}, 693*e7801d59Ssowmini { "bsstype", "BSSTYPE", 8, DLADM_WLAN_ATTR_BSSTYPE, WIFI_CMD_ALL}, 694*e7801d59Ssowmini { "sec", "SEC", 6, DLADM_WLAN_ATTR_SECMODE, WIFI_CMD_ALL}, 695*e7801d59Ssowmini { "status", "STATUS", 17, DLADM_WLAN_LINKATTR_STATUS, WIFI_CMD_SHOW}, 696*e7801d59Ssowmini { "strength", "STRENGTH", 10, DLADM_WLAN_ATTR_STRENGTH, WIFI_CMD_ALL}} 697*e7801d59Ssowmini ; 698*e7801d59Ssowmini 699*e7801d59Ssowmini static char *all_scan_wifi_fields = 700*e7801d59Ssowmini "link,essid,bssid,sec,strength,mode,speed,bsstype"; 701*e7801d59Ssowmini static char *all_show_wifi_fields = 702*e7801d59Ssowmini "link,status,essid,sec,strength,mode,speed,auth,bssid,bsstype"; 703*e7801d59Ssowmini static char *def_scan_wifi_fields = 704*e7801d59Ssowmini "link,essid,bssid,sec,strength,mode,speed"; 705*e7801d59Ssowmini static char *def_show_wifi_fields = 706*e7801d59Ssowmini "link,status,essid,sec,strength,mode,speed"; 707*e7801d59Ssowmini 708*e7801d59Ssowmini #define WIFI_MAX_FIELDS (sizeof (wifi_fields) / sizeof (print_field_t)) 709*e7801d59Ssowmini 710*e7801d59Ssowmini /* 711*e7801d59Ssowmini * structures for 'dladm show-linkprop' 712*e7801d59Ssowmini */ 713*e7801d59Ssowmini typedef enum { 714*e7801d59Ssowmini LINKPROP_LINK, 715*e7801d59Ssowmini LINKPROP_PROPERTY, 716*e7801d59Ssowmini LINKPROP_VALUE, 717*e7801d59Ssowmini LINKPROP_DEFAULT, 718*e7801d59Ssowmini LINKPROP_POSSIBLE 719*e7801d59Ssowmini } linkprop_field_index_t; 720*e7801d59Ssowmini 721*e7801d59Ssowmini static print_field_t linkprop_fields[] = { 722*e7801d59Ssowmini /* name, header, field width, index, cmdtype */ 723*e7801d59Ssowmini { "link", "LINK", 12, LINKPROP_LINK, CMD_TYPE_ANY}, 724*e7801d59Ssowmini { "property", "PROPERTY", 15, LINKPROP_PROPERTY, CMD_TYPE_ANY}, 725*e7801d59Ssowmini { "value", "VALUE", 14, LINKPROP_VALUE, CMD_TYPE_ANY}, 726*e7801d59Ssowmini { "default", "DEFAULT", 14, LINKPROP_DEFAULT, CMD_TYPE_ANY}, 727*e7801d59Ssowmini { "possible", "POSSIBLE", 20, LINKPROP_POSSIBLE, CMD_TYPE_ANY}} 728*e7801d59Ssowmini ; 729*e7801d59Ssowmini #define LINKPROP_MAX_FIELDS \ 730*e7801d59Ssowmini (sizeof (linkprop_fields) / sizeof (print_field_t)) 731*e7801d59Ssowmini 732*e7801d59Ssowmini #define MAX_PROPS 32 733*e7801d59Ssowmini #define MAX_PROP_LINE 512 734*e7801d59Ssowmini 735*e7801d59Ssowmini typedef struct prop_info { 736*e7801d59Ssowmini char *pi_name; 737*e7801d59Ssowmini char *pi_val[DLADM_MAX_PROP_VALCNT]; 738*e7801d59Ssowmini uint_t pi_count; 739*e7801d59Ssowmini } prop_info_t; 740*e7801d59Ssowmini 741*e7801d59Ssowmini typedef struct prop_list { 742*e7801d59Ssowmini prop_info_t pl_info[MAX_PROPS]; 743*e7801d59Ssowmini uint_t pl_count; 744*e7801d59Ssowmini char *pl_buf; 745*e7801d59Ssowmini } prop_list_t; 746*e7801d59Ssowmini 747*e7801d59Ssowmini typedef struct show_linkprop_state { 748*e7801d59Ssowmini char ls_link[MAXLINKNAMELEN]; 749*e7801d59Ssowmini char *ls_line; 750*e7801d59Ssowmini char **ls_propvals; 751*e7801d59Ssowmini prop_list_t *ls_proplist; 752*e7801d59Ssowmini boolean_t ls_parseable; 753*e7801d59Ssowmini boolean_t ls_persist; 754*e7801d59Ssowmini boolean_t ls_header; 755*e7801d59Ssowmini dladm_status_t ls_status; 756*e7801d59Ssowmini dladm_status_t ls_retstatus; 757*e7801d59Ssowmini print_state_t ls_print; 758*e7801d59Ssowmini } show_linkprop_state_t; 759*e7801d59Ssowmini 760*e7801d59Ssowmini typedef struct linkprop_args_s { 761*e7801d59Ssowmini show_linkprop_state_t *ls_state; 762*e7801d59Ssowmini char *ls_propname; 763*e7801d59Ssowmini datalink_id_t ls_linkid; 764*e7801d59Ssowmini } linkprop_args_t; 765*e7801d59Ssowmini 766*e7801d59Ssowmini /* 767*e7801d59Ssowmini * structures for 'dladm show-secobj' 768*e7801d59Ssowmini */ 769*e7801d59Ssowmini typedef struct secobj_fields_buf_s { 770*e7801d59Ssowmini char ss_obj_name[DLADM_SECOBJ_VAL_MAX]; 771*e7801d59Ssowmini char ss_class[20]; 772*e7801d59Ssowmini char ss_val[30]; 773*e7801d59Ssowmini } secobj_fields_buf_t; 774*e7801d59Ssowmini static print_field_t secobj_fields[] = { 775*e7801d59Ssowmini /* name, header, field width, offset, cmdtype */ 776*e7801d59Ssowmini { "object", "OBJECT", 20, 777*e7801d59Ssowmini offsetof(secobj_fields_buf_t, ss_obj_name), CMD_TYPE_ANY}, 778*e7801d59Ssowmini { "class", "CLASS", 20, 779*e7801d59Ssowmini offsetof(secobj_fields_buf_t, ss_class), CMD_TYPE_ANY}, 780*e7801d59Ssowmini { "value", "VALUE", 30, 781*e7801d59Ssowmini offsetof(secobj_fields_buf_t, ss_val), CMD_TYPE_ANY}} 782*e7801d59Ssowmini ; 783*e7801d59Ssowmini #define DEV_SOBJ_FIELDS (sizeof (secobj_fields) / sizeof (print_field_t)) 7840ba2cbe9Sxc151355 7857c478bd9Sstevel@tonic-gate static char *progname; 7860ba2cbe9Sxc151355 static sig_atomic_t signalled; 7877c478bd9Sstevel@tonic-gate 7887c478bd9Sstevel@tonic-gate static void 7897c478bd9Sstevel@tonic-gate usage(void) 7907c478bd9Sstevel@tonic-gate { 7910ba2cbe9Sxc151355 (void) fprintf(stderr, gettext("usage: dladm <subcommand> <args> ...\n" 792*e7801d59Ssowmini "\tshow-link [-pP] [-o <field>,..] [-s [-i <interval>]] " 793*e7801d59Ssowmini "[<link>]\n" 794d62bc4baSyz147064 "\trename-link [-R <root-dir>] <oldlink> <newlink>\n" 795d62bc4baSyz147064 "\n" 796d62bc4baSyz147064 "\tdelete-phys <link>\n" 797*e7801d59Ssowmini "\tshow-phys [-pP] [-o <field>,..] [<link>]\n" 798*e7801d59Ssowmini "\tshow-dev [-p] [-o <field>,..] [-s [-i <interval>]] " 799*e7801d59Ssowmini "[<dev>]\n" 8000ba2cbe9Sxc151355 "\n" 801d62bc4baSyz147064 "\tcreate-aggr [-t] [-R <root-dir>] [-P <policy>] [-L <mode>]\n" 802d62bc4baSyz147064 "\t [-T <time>] [-u <address>] [-l <link>] ... <link>\n" 803d62bc4baSyz147064 "\tmodify-aggr [-t] [-R <root-dir>] [-P <policy>] [-L <mode>]\n" 804d62bc4baSyz147064 "\t [-T <time>] [-u <address>] <link>\n" 805d62bc4baSyz147064 "\tdelete-aggr [-t] [-R <root-dir>] <link>\n" 806d62bc4baSyz147064 "\tadd-aggr [-t] [-R <root-dir>] [-l <link>] ... <link>\n" 807d62bc4baSyz147064 "\tremove-aggr [-t] [-R <root-dir>] [-l <link>] ... <link>" 808*e7801d59Ssowmini "\n\tshow-aggr [-pPLx] [-o <field>,..] [-s [-i <interval>]] " 809*e7801d59Ssowmini "[<link>]\n" 8100ba2cbe9Sxc151355 "\n" 811d62bc4baSyz147064 "\tcreate-vlan [-ft] [-R <root-dir>] -l <link> -v <vid> [link]" 812d62bc4baSyz147064 "\n\tdelete-vlan [-t] [-R <root-dir>] <link>\n" 813*e7801d59Ssowmini "\tshow-vlan [-pP] [-o <field>,..] [<link>]\n" 814d62bc4baSyz147064 "\n" 815d62bc4baSyz147064 "\tscan-wifi [-p] [-o <field>,...] [<link>]\n" 8160ba2cbe9Sxc151355 "\tconnect-wifi [-e <essid>] [-i <bssid>] [-k <key>,...]" 817a399b765Szf162725 " [-s wep|wpa]\n" 8180ba2cbe9Sxc151355 "\t [-a open|shared] [-b bss|ibss] [-c] [-m a|b|g]\n" 819d62bc4baSyz147064 "\t [-T <time>] [<link>]\n" 820d62bc4baSyz147064 "\tdisconnect-wifi [-a] [<link>]\n" 821d62bc4baSyz147064 "\tshow-wifi [-p] [-o <field>,...] [<link>]\n" 8220ba2cbe9Sxc151355 "\n" 8230ba2cbe9Sxc151355 "\tset-linkprop [-t] [-R <root-dir>] -p <prop>=<value>[,...]" 8240ba2cbe9Sxc151355 " <name>\n" 8250ba2cbe9Sxc151355 "\treset-linkprop [-t] [-R <root-dir>] [-p <prop>,...] <name>\n" 826*e7801d59Ssowmini "\tshow-linkprop [-cP][-o <field>,...][-p <prop>,...] <name>\n" 8270ba2cbe9Sxc151355 "\n" 8280ba2cbe9Sxc151355 "\tcreate-secobj [-t] [-R <root-dir>] [-f <file>] -c <class>" 8290ba2cbe9Sxc151355 " <secobj>\n" 8300ba2cbe9Sxc151355 "\tdelete-secobj [-t] [-R <root-dir>] <secobj>[,...]\n" 831*e7801d59Ssowmini "\tshow-secobj [-pP][-o <field>,...][<secobj>,...]\n" 832*e7801d59Ssowmini "\n" 833*e7801d59Ssowmini "\tshow-ether [-px][-o <field>,...] <link>\n")); 834*e7801d59Ssowmini 8357c478bd9Sstevel@tonic-gate exit(1); 8367c478bd9Sstevel@tonic-gate } 8377c478bd9Sstevel@tonic-gate 8387c478bd9Sstevel@tonic-gate int 8397c478bd9Sstevel@tonic-gate main(int argc, char *argv[]) 8407c478bd9Sstevel@tonic-gate { 8417c478bd9Sstevel@tonic-gate int i; 8427c478bd9Sstevel@tonic-gate cmd_t *cmdp; 8437c478bd9Sstevel@tonic-gate 8447c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 8457c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) 8467c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" 8477c478bd9Sstevel@tonic-gate #endif 8487c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 8497c478bd9Sstevel@tonic-gate 8507c478bd9Sstevel@tonic-gate progname = argv[0]; 8517c478bd9Sstevel@tonic-gate 8527c478bd9Sstevel@tonic-gate if (argc < 2) 8537c478bd9Sstevel@tonic-gate usage(); 8547c478bd9Sstevel@tonic-gate 855cd93090eSericheng if (!priv_ineffect(PRIV_SYS_NET_CONFIG) || 85633343a97Smeem !priv_ineffect(PRIV_NET_RAWACCESS)) 85733343a97Smeem die("insufficient privileges"); 858cd93090eSericheng 8597c478bd9Sstevel@tonic-gate for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) { 8607c478bd9Sstevel@tonic-gate cmdp = &cmds[i]; 8617c478bd9Sstevel@tonic-gate if (strcmp(argv[1], cmdp->c_name) == 0) { 8627c478bd9Sstevel@tonic-gate cmdp->c_fn(argc - 1, &argv[1]); 8637c478bd9Sstevel@tonic-gate exit(0); 8647c478bd9Sstevel@tonic-gate } 8657c478bd9Sstevel@tonic-gate } 8667c478bd9Sstevel@tonic-gate 8677c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: unknown subcommand '%s'\n"), 8687c478bd9Sstevel@tonic-gate progname, argv[1]); 8697c478bd9Sstevel@tonic-gate usage(); 8707c478bd9Sstevel@tonic-gate 8717c478bd9Sstevel@tonic-gate return (0); 8727c478bd9Sstevel@tonic-gate } 8737c478bd9Sstevel@tonic-gate 8747c478bd9Sstevel@tonic-gate static void 8757c478bd9Sstevel@tonic-gate do_create_aggr(int argc, char *argv[]) 8767c478bd9Sstevel@tonic-gate { 8777c478bd9Sstevel@tonic-gate char option; 878d62bc4baSyz147064 int key = 0; 8797c478bd9Sstevel@tonic-gate uint32_t policy = AGGR_POLICY_L4; 8807c478bd9Sstevel@tonic-gate aggr_lacp_mode_t lacp_mode = AGGR_LACP_OFF; 8817c478bd9Sstevel@tonic-gate aggr_lacp_timer_t lacp_timer = AGGR_LACP_TIMER_SHORT; 882f595a68aSyz147064 dladm_aggr_port_attr_db_t port[MAXPORT]; 883d62bc4baSyz147064 uint_t n, ndev, nlink; 8847c478bd9Sstevel@tonic-gate uint8_t mac_addr[ETHERADDRL]; 8857c478bd9Sstevel@tonic-gate boolean_t mac_addr_fixed = B_FALSE; 8867c478bd9Sstevel@tonic-gate boolean_t P_arg = B_FALSE; 8877c478bd9Sstevel@tonic-gate boolean_t l_arg = B_FALSE; 8887c478bd9Sstevel@tonic-gate boolean_t u_arg = B_FALSE; 8897c478bd9Sstevel@tonic-gate boolean_t T_arg = B_FALSE; 890d62bc4baSyz147064 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 8917c478bd9Sstevel@tonic-gate char *altroot = NULL; 892d62bc4baSyz147064 char name[MAXLINKNAMELEN]; 893d62bc4baSyz147064 char *devs[MAXPORT]; 894d62bc4baSyz147064 char *links[MAXPORT]; 895f595a68aSyz147064 dladm_status_t status; 8967c478bd9Sstevel@tonic-gate 897d62bc4baSyz147064 ndev = nlink = opterr = 0; 898d62bc4baSyz147064 while ((option = getopt_long(argc, argv, ":d:l:L:P:R:tfu:T:", 899d62bc4baSyz147064 lopts, NULL)) != -1) { 9007c478bd9Sstevel@tonic-gate switch (option) { 9017c478bd9Sstevel@tonic-gate case 'd': 902d62bc4baSyz147064 if (ndev + nlink >= MAXPORT) 903d62bc4baSyz147064 die("too many ports specified"); 9047c478bd9Sstevel@tonic-gate 905d62bc4baSyz147064 devs[ndev++] = optarg; 9067c478bd9Sstevel@tonic-gate break; 9077c478bd9Sstevel@tonic-gate case 'P': 90833343a97Smeem if (P_arg) 90933343a97Smeem die_optdup(option); 9107c478bd9Sstevel@tonic-gate 9117c478bd9Sstevel@tonic-gate P_arg = B_TRUE; 912f595a68aSyz147064 if (!dladm_aggr_str2policy(optarg, &policy)) 91333343a97Smeem die("invalid policy '%s'", optarg); 9147c478bd9Sstevel@tonic-gate break; 9157c478bd9Sstevel@tonic-gate case 'u': 91633343a97Smeem if (u_arg) 91733343a97Smeem die_optdup(option); 9187c478bd9Sstevel@tonic-gate 9197c478bd9Sstevel@tonic-gate u_arg = B_TRUE; 920f595a68aSyz147064 if (!dladm_aggr_str2macaddr(optarg, &mac_addr_fixed, 92133343a97Smeem mac_addr)) 92233343a97Smeem die("invalid MAC address '%s'", optarg); 9237c478bd9Sstevel@tonic-gate break; 9247c478bd9Sstevel@tonic-gate case 'l': 925d62bc4baSyz147064 if (isdigit(optarg[strlen(optarg) - 1])) { 926d62bc4baSyz147064 927d62bc4baSyz147064 /* 928d62bc4baSyz147064 * Ended with digit, possibly a link name. 929d62bc4baSyz147064 */ 930d62bc4baSyz147064 if (ndev + nlink >= MAXPORT) 931d62bc4baSyz147064 die("too many ports specified"); 932d62bc4baSyz147064 933d62bc4baSyz147064 links[nlink++] = optarg; 934d62bc4baSyz147064 break; 935d62bc4baSyz147064 } 936d62bc4baSyz147064 /* FALLTHROUGH */ 937d62bc4baSyz147064 case 'L': 93833343a97Smeem if (l_arg) 93933343a97Smeem die_optdup(option); 9407c478bd9Sstevel@tonic-gate 9417c478bd9Sstevel@tonic-gate l_arg = B_TRUE; 942f595a68aSyz147064 if (!dladm_aggr_str2lacpmode(optarg, &lacp_mode)) 94333343a97Smeem die("invalid LACP mode '%s'", optarg); 9447c478bd9Sstevel@tonic-gate break; 9457c478bd9Sstevel@tonic-gate case 'T': 94633343a97Smeem if (T_arg) 94733343a97Smeem die_optdup(option); 9487c478bd9Sstevel@tonic-gate 9497c478bd9Sstevel@tonic-gate T_arg = B_TRUE; 950f595a68aSyz147064 if (!dladm_aggr_str2lacptimer(optarg, &lacp_timer)) 95133343a97Smeem die("invalid LACP timer value '%s'", optarg); 9527c478bd9Sstevel@tonic-gate break; 9537c478bd9Sstevel@tonic-gate case 't': 954d62bc4baSyz147064 flags &= ~DLADM_OPT_PERSIST; 955d62bc4baSyz147064 break; 956d62bc4baSyz147064 case 'f': 957d62bc4baSyz147064 flags |= DLADM_OPT_FORCE; 9587c478bd9Sstevel@tonic-gate break; 9597c478bd9Sstevel@tonic-gate case 'R': 9607c478bd9Sstevel@tonic-gate altroot = optarg; 9617c478bd9Sstevel@tonic-gate break; 9627c478bd9Sstevel@tonic-gate default: 96333343a97Smeem die_opterr(optopt, option); 96433343a97Smeem break; 9657c478bd9Sstevel@tonic-gate } 9667c478bd9Sstevel@tonic-gate } 9677c478bd9Sstevel@tonic-gate 968d62bc4baSyz147064 if (ndev + nlink == 0) 9697c478bd9Sstevel@tonic-gate usage(); 9707c478bd9Sstevel@tonic-gate 971d62bc4baSyz147064 /* get key value or the aggregation name (required last argument) */ 9727c478bd9Sstevel@tonic-gate if (optind != (argc-1)) 9737c478bd9Sstevel@tonic-gate usage(); 9747c478bd9Sstevel@tonic-gate 975d62bc4baSyz147064 if (!str2int(argv[optind], &key)) { 976d62bc4baSyz147064 if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= 977d62bc4baSyz147064 MAXLINKNAMELEN) { 978d62bc4baSyz147064 die("link name too long '%s'", argv[optind]); 979d62bc4baSyz147064 } 9807c478bd9Sstevel@tonic-gate 981d62bc4baSyz147064 if (!dladm_valid_linkname(name)) 982d62bc4baSyz147064 die("invalid link name '%s'", argv[optind]); 983d62bc4baSyz147064 } else { 984d62bc4baSyz147064 (void) snprintf(name, MAXLINKNAMELEN, "aggr%d", key); 985d62bc4baSyz147064 } 986d62bc4baSyz147064 987d62bc4baSyz147064 if (altroot != NULL) 988d62bc4baSyz147064 altroot_cmd(altroot, argc, argv); 989d62bc4baSyz147064 990d62bc4baSyz147064 for (n = 0; n < ndev; n++) { 991d62bc4baSyz147064 if (dladm_dev2linkid(devs[n], &port[n].lp_linkid) != 992d62bc4baSyz147064 DLADM_STATUS_OK) { 993d62bc4baSyz147064 die("invalid dev name '%s'", devs[n]); 994d62bc4baSyz147064 } 995d62bc4baSyz147064 } 996d62bc4baSyz147064 997d62bc4baSyz147064 for (n = 0; n < nlink; n++) { 998d62bc4baSyz147064 if (dladm_name2info(links[n], &port[ndev + n].lp_linkid, 999d62bc4baSyz147064 NULL, NULL, NULL) != DLADM_STATUS_OK) { 1000d62bc4baSyz147064 die("invalid link name '%s'", links[n]); 1001d62bc4baSyz147064 } 1002d62bc4baSyz147064 } 1003d62bc4baSyz147064 1004d62bc4baSyz147064 status = dladm_aggr_create(name, key, ndev + nlink, port, policy, 1005d62bc4baSyz147064 mac_addr_fixed, (const uchar_t *)mac_addr, lacp_mode, 1006d62bc4baSyz147064 lacp_timer, flags); 1007d62bc4baSyz147064 done: 1008d62bc4baSyz147064 if (status != DLADM_STATUS_OK) { 1009d62bc4baSyz147064 if (status == DLADM_STATUS_NONOTIF) { 1010d62bc4baSyz147064 die_dlerr(status, "not all links have link up/down " 1011d62bc4baSyz147064 "detection; must use -f (see dladm(1M))\n"); 1012d62bc4baSyz147064 } else { 1013f595a68aSyz147064 die_dlerr(status, "create operation failed"); 10147c478bd9Sstevel@tonic-gate } 1015d62bc4baSyz147064 } 1016d62bc4baSyz147064 } 1017d62bc4baSyz147064 1018d62bc4baSyz147064 /* 1019d62bc4baSyz147064 * arg is either the key or the aggr name. Validate it and convert it to 1020d62bc4baSyz147064 * the linkid if altroot is NULL. 1021d62bc4baSyz147064 */ 1022d62bc4baSyz147064 static dladm_status_t 1023d62bc4baSyz147064 i_dladm_aggr_get_linkid(const char *altroot, const char *arg, 1024d62bc4baSyz147064 datalink_id_t *linkidp, uint32_t flags) 1025d62bc4baSyz147064 { 1026d62bc4baSyz147064 int key = 0; 1027d62bc4baSyz147064 char *aggr = NULL; 1028d62bc4baSyz147064 dladm_status_t status; 1029d62bc4baSyz147064 1030d62bc4baSyz147064 if (!str2int(arg, &key)) 1031d62bc4baSyz147064 aggr = (char *)arg; 1032d62bc4baSyz147064 1033d62bc4baSyz147064 if (aggr == NULL && key == 0) 1034d62bc4baSyz147064 return (DLADM_STATUS_LINKINVAL); 1035d62bc4baSyz147064 1036d62bc4baSyz147064 if (altroot != NULL) 1037d62bc4baSyz147064 return (DLADM_STATUS_OK); 1038d62bc4baSyz147064 1039d62bc4baSyz147064 if (aggr != NULL) { 1040d62bc4baSyz147064 status = dladm_name2info(aggr, linkidp, NULL, NULL, NULL); 1041d62bc4baSyz147064 } else { 1042d62bc4baSyz147064 status = dladm_key2linkid(key, linkidp, flags); 1043d62bc4baSyz147064 } 1044d62bc4baSyz147064 1045d62bc4baSyz147064 return (status); 1046d62bc4baSyz147064 } 10477c478bd9Sstevel@tonic-gate 10487c478bd9Sstevel@tonic-gate static void 10497c478bd9Sstevel@tonic-gate do_delete_aggr(int argc, char *argv[]) 10507c478bd9Sstevel@tonic-gate { 10517c478bd9Sstevel@tonic-gate char option; 10527c478bd9Sstevel@tonic-gate char *altroot = NULL; 1053d62bc4baSyz147064 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 1054f595a68aSyz147064 dladm_status_t status; 1055d62bc4baSyz147064 datalink_id_t linkid; 10567c478bd9Sstevel@tonic-gate 10577c478bd9Sstevel@tonic-gate opterr = 0; 1058d62bc4baSyz147064 while ((option = getopt_long(argc, argv, ":R:t", lopts, NULL)) != -1) { 10597c478bd9Sstevel@tonic-gate switch (option) { 10607c478bd9Sstevel@tonic-gate case 't': 1061d62bc4baSyz147064 flags &= ~DLADM_OPT_PERSIST; 10627c478bd9Sstevel@tonic-gate break; 10637c478bd9Sstevel@tonic-gate case 'R': 10647c478bd9Sstevel@tonic-gate altroot = optarg; 10657c478bd9Sstevel@tonic-gate break; 10667c478bd9Sstevel@tonic-gate default: 106733343a97Smeem die_opterr(optopt, option); 10687c478bd9Sstevel@tonic-gate break; 10697c478bd9Sstevel@tonic-gate } 10707c478bd9Sstevel@tonic-gate } 10717c478bd9Sstevel@tonic-gate 1072d62bc4baSyz147064 /* get key value or the aggregation name (required last argument) */ 10737c478bd9Sstevel@tonic-gate if (optind != (argc-1)) 10747c478bd9Sstevel@tonic-gate usage(); 10757c478bd9Sstevel@tonic-gate 1076d62bc4baSyz147064 status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags); 1077d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 1078d62bc4baSyz147064 goto done; 10797c478bd9Sstevel@tonic-gate 1080d62bc4baSyz147064 if (altroot != NULL) 1081d62bc4baSyz147064 altroot_cmd(altroot, argc, argv); 1082d62bc4baSyz147064 1083d62bc4baSyz147064 status = dladm_aggr_delete(linkid, flags); 1084d62bc4baSyz147064 done: 1085f595a68aSyz147064 if (status != DLADM_STATUS_OK) 1086f595a68aSyz147064 die_dlerr(status, "delete operation failed"); 10877c478bd9Sstevel@tonic-gate } 10887c478bd9Sstevel@tonic-gate 10897c478bd9Sstevel@tonic-gate static void 10907c478bd9Sstevel@tonic-gate do_add_aggr(int argc, char *argv[]) 10917c478bd9Sstevel@tonic-gate { 10927c478bd9Sstevel@tonic-gate char option; 1093d62bc4baSyz147064 uint_t n, ndev, nlink; 10947c478bd9Sstevel@tonic-gate char *altroot = NULL; 1095d62bc4baSyz147064 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 1096d62bc4baSyz147064 datalink_id_t linkid; 1097f595a68aSyz147064 dladm_status_t status; 1098d62bc4baSyz147064 dladm_aggr_port_attr_db_t port[MAXPORT]; 1099d62bc4baSyz147064 char *devs[MAXPORT]; 1100d62bc4baSyz147064 char *links[MAXPORT]; 11017c478bd9Sstevel@tonic-gate 1102d62bc4baSyz147064 ndev = nlink = opterr = 0; 1103d62bc4baSyz147064 while ((option = getopt_long(argc, argv, ":d:l:R:tf", lopts, 11047c478bd9Sstevel@tonic-gate NULL)) != -1) { 11057c478bd9Sstevel@tonic-gate switch (option) { 11067c478bd9Sstevel@tonic-gate case 'd': 1107d62bc4baSyz147064 if (ndev + nlink >= MAXPORT) 1108d62bc4baSyz147064 die("too many ports specified"); 11097c478bd9Sstevel@tonic-gate 1110d62bc4baSyz147064 devs[ndev++] = optarg; 1111d62bc4baSyz147064 break; 1112d62bc4baSyz147064 case 'l': 1113d62bc4baSyz147064 if (ndev + nlink >= MAXPORT) 1114d62bc4baSyz147064 die("too many ports specified"); 111533343a97Smeem 1116d62bc4baSyz147064 links[nlink++] = optarg; 11177c478bd9Sstevel@tonic-gate break; 11187c478bd9Sstevel@tonic-gate case 't': 1119d62bc4baSyz147064 flags &= ~DLADM_OPT_PERSIST; 1120d62bc4baSyz147064 break; 1121d62bc4baSyz147064 case 'f': 1122d62bc4baSyz147064 flags |= DLADM_OPT_FORCE; 11237c478bd9Sstevel@tonic-gate break; 11247c478bd9Sstevel@tonic-gate case 'R': 11257c478bd9Sstevel@tonic-gate altroot = optarg; 11267c478bd9Sstevel@tonic-gate break; 11277c478bd9Sstevel@tonic-gate default: 112833343a97Smeem die_opterr(optopt, option); 112933343a97Smeem break; 11307c478bd9Sstevel@tonic-gate } 11317c478bd9Sstevel@tonic-gate } 11327c478bd9Sstevel@tonic-gate 1133d62bc4baSyz147064 if (ndev + nlink == 0) 11347c478bd9Sstevel@tonic-gate usage(); 11357c478bd9Sstevel@tonic-gate 1136d62bc4baSyz147064 /* get key value or the aggregation name (required last argument) */ 11377c478bd9Sstevel@tonic-gate if (optind != (argc-1)) 11387c478bd9Sstevel@tonic-gate usage(); 11397c478bd9Sstevel@tonic-gate 1140d62bc4baSyz147064 if ((status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, 1141d62bc4baSyz147064 flags & (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST))) != 1142d62bc4baSyz147064 DLADM_STATUS_OK) { 1143d62bc4baSyz147064 goto done; 1144d62bc4baSyz147064 } 11457c478bd9Sstevel@tonic-gate 1146d62bc4baSyz147064 if (altroot != NULL) 1147d62bc4baSyz147064 altroot_cmd(altroot, argc, argv); 1148d62bc4baSyz147064 1149d62bc4baSyz147064 for (n = 0; n < ndev; n++) { 1150d62bc4baSyz147064 if (dladm_dev2linkid(devs[n], &(port[n].lp_linkid)) != 1151d62bc4baSyz147064 DLADM_STATUS_OK) { 1152d62bc4baSyz147064 die("invalid <dev> '%s'", devs[n]); 1153d62bc4baSyz147064 } 1154d62bc4baSyz147064 } 1155d62bc4baSyz147064 1156d62bc4baSyz147064 for (n = 0; n < nlink; n++) { 1157d62bc4baSyz147064 if (dladm_name2info(links[n], &port[n + ndev].lp_linkid, 1158d62bc4baSyz147064 NULL, NULL, NULL) != DLADM_STATUS_OK) { 1159d62bc4baSyz147064 die("invalid <link> '%s'", links[n]); 1160d62bc4baSyz147064 } 1161d62bc4baSyz147064 } 1162d62bc4baSyz147064 1163d62bc4baSyz147064 status = dladm_aggr_add(linkid, ndev + nlink, port, flags); 1164d62bc4baSyz147064 done: 1165f595a68aSyz147064 if (status != DLADM_STATUS_OK) { 1166219a2a31Shl157128 /* 1167f595a68aSyz147064 * checking DLADM_STATUS_NOTSUP is a temporary workaround 1168219a2a31Shl157128 * and should be removed once 6399681 is fixed. 1169219a2a31Shl157128 */ 1170f595a68aSyz147064 if (status == DLADM_STATUS_NOTSUP) { 1171219a2a31Shl157128 (void) fprintf(stderr, 1172219a2a31Shl157128 gettext("%s: add operation failed: %s\n"), 1173219a2a31Shl157128 progname, 1174d62bc4baSyz147064 gettext("link capabilities don't match")); 1175219a2a31Shl157128 exit(ENOTSUP); 1176d62bc4baSyz147064 } else if (status == DLADM_STATUS_NONOTIF) { 1177d62bc4baSyz147064 die_dlerr(status, "not all links have link up/down " 1178d62bc4baSyz147064 "detection; must use -f (see dladm(1M))\n"); 1179d62bc4baSyz147064 } else { 1180f595a68aSyz147064 die_dlerr(status, "add operation failed"); 11817c478bd9Sstevel@tonic-gate } 11827c478bd9Sstevel@tonic-gate } 1183d62bc4baSyz147064 } 11847c478bd9Sstevel@tonic-gate 11857c478bd9Sstevel@tonic-gate static void 11867c478bd9Sstevel@tonic-gate do_remove_aggr(int argc, char *argv[]) 11877c478bd9Sstevel@tonic-gate { 11887c478bd9Sstevel@tonic-gate char option; 1189f595a68aSyz147064 dladm_aggr_port_attr_db_t port[MAXPORT]; 1190d62bc4baSyz147064 uint_t n, ndev, nlink; 1191d62bc4baSyz147064 char *devs[MAXPORT]; 1192d62bc4baSyz147064 char *links[MAXPORT]; 11937c478bd9Sstevel@tonic-gate char *altroot = NULL; 1194d62bc4baSyz147064 uint32_t flags; 1195d62bc4baSyz147064 datalink_id_t linkid; 1196f595a68aSyz147064 dladm_status_t status; 11977c478bd9Sstevel@tonic-gate 1198d62bc4baSyz147064 flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 1199d62bc4baSyz147064 ndev = nlink = opterr = 0; 1200d62bc4baSyz147064 while ((option = getopt_long(argc, argv, ":d:l:R:t", 1201d62bc4baSyz147064 lopts, NULL)) != -1) { 12027c478bd9Sstevel@tonic-gate switch (option) { 12037c478bd9Sstevel@tonic-gate case 'd': 1204d62bc4baSyz147064 if (ndev + nlink >= MAXPORT) 1205d62bc4baSyz147064 die("too many ports specified"); 12067c478bd9Sstevel@tonic-gate 1207d62bc4baSyz147064 devs[ndev++] = optarg; 1208d62bc4baSyz147064 break; 1209d62bc4baSyz147064 case 'l': 1210d62bc4baSyz147064 if (ndev + nlink >= MAXPORT) 1211d62bc4baSyz147064 die("too many ports specified"); 121233343a97Smeem 1213d62bc4baSyz147064 links[nlink++] = optarg; 12147c478bd9Sstevel@tonic-gate break; 12157c478bd9Sstevel@tonic-gate case 't': 1216d62bc4baSyz147064 flags &= ~DLADM_OPT_PERSIST; 12177c478bd9Sstevel@tonic-gate break; 12187c478bd9Sstevel@tonic-gate case 'R': 12197c478bd9Sstevel@tonic-gate altroot = optarg; 12207c478bd9Sstevel@tonic-gate break; 12217c478bd9Sstevel@tonic-gate default: 122233343a97Smeem die_opterr(optopt, option); 122333343a97Smeem break; 12247c478bd9Sstevel@tonic-gate } 12257c478bd9Sstevel@tonic-gate } 12267c478bd9Sstevel@tonic-gate 1227d62bc4baSyz147064 if (ndev + nlink == 0) 12287c478bd9Sstevel@tonic-gate usage(); 12297c478bd9Sstevel@tonic-gate 1230d62bc4baSyz147064 /* get key value or the aggregation name (required last argument) */ 12317c478bd9Sstevel@tonic-gate if (optind != (argc-1)) 12327c478bd9Sstevel@tonic-gate usage(); 12337c478bd9Sstevel@tonic-gate 1234d62bc4baSyz147064 status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags); 1235d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 1236d62bc4baSyz147064 goto done; 12377c478bd9Sstevel@tonic-gate 1238d62bc4baSyz147064 if (altroot != NULL) 1239d62bc4baSyz147064 altroot_cmd(altroot, argc, argv); 1240d62bc4baSyz147064 1241d62bc4baSyz147064 for (n = 0; n < ndev; n++) { 1242d62bc4baSyz147064 if (dladm_dev2linkid(devs[n], &(port[n].lp_linkid)) != 1243d62bc4baSyz147064 DLADM_STATUS_OK) { 1244d62bc4baSyz147064 die("invalid <dev> '%s'", devs[n]); 1245d62bc4baSyz147064 } 1246d62bc4baSyz147064 } 1247d62bc4baSyz147064 1248d62bc4baSyz147064 for (n = 0; n < nlink; n++) { 1249d62bc4baSyz147064 if (dladm_name2info(links[n], &port[n + ndev].lp_linkid, 1250d62bc4baSyz147064 NULL, NULL, NULL) != DLADM_STATUS_OK) { 1251d62bc4baSyz147064 die("invalid <link> '%s'", links[n]); 1252d62bc4baSyz147064 } 1253d62bc4baSyz147064 } 1254d62bc4baSyz147064 1255d62bc4baSyz147064 status = dladm_aggr_remove(linkid, ndev + nlink, port, flags); 1256d62bc4baSyz147064 done: 1257f595a68aSyz147064 if (status != DLADM_STATUS_OK) 1258f595a68aSyz147064 die_dlerr(status, "remove operation failed"); 12597c478bd9Sstevel@tonic-gate } 12607c478bd9Sstevel@tonic-gate 12617c478bd9Sstevel@tonic-gate static void 12627c478bd9Sstevel@tonic-gate do_modify_aggr(int argc, char *argv[]) 12637c478bd9Sstevel@tonic-gate { 12647c478bd9Sstevel@tonic-gate char option; 12657c478bd9Sstevel@tonic-gate uint32_t policy = AGGR_POLICY_L4; 12667c478bd9Sstevel@tonic-gate aggr_lacp_mode_t lacp_mode = AGGR_LACP_OFF; 12677c478bd9Sstevel@tonic-gate aggr_lacp_timer_t lacp_timer = AGGR_LACP_TIMER_SHORT; 12687c478bd9Sstevel@tonic-gate uint8_t mac_addr[ETHERADDRL]; 12697c478bd9Sstevel@tonic-gate boolean_t mac_addr_fixed = B_FALSE; 12707c478bd9Sstevel@tonic-gate uint8_t modify_mask = 0; 12717c478bd9Sstevel@tonic-gate char *altroot = NULL; 1272d62bc4baSyz147064 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 1273d62bc4baSyz147064 datalink_id_t linkid; 1274f595a68aSyz147064 dladm_status_t status; 12757c478bd9Sstevel@tonic-gate 12767c478bd9Sstevel@tonic-gate opterr = 0; 1277d62bc4baSyz147064 while ((option = getopt_long(argc, argv, ":L:l:P:R:tu:T:", lopts, 12787c478bd9Sstevel@tonic-gate NULL)) != -1) { 12797c478bd9Sstevel@tonic-gate switch (option) { 12807c478bd9Sstevel@tonic-gate case 'P': 1281f595a68aSyz147064 if (modify_mask & DLADM_AGGR_MODIFY_POLICY) 128233343a97Smeem die_optdup(option); 12837c478bd9Sstevel@tonic-gate 1284f595a68aSyz147064 modify_mask |= DLADM_AGGR_MODIFY_POLICY; 12857c478bd9Sstevel@tonic-gate 1286f595a68aSyz147064 if (!dladm_aggr_str2policy(optarg, &policy)) 128733343a97Smeem die("invalid policy '%s'", optarg); 12887c478bd9Sstevel@tonic-gate break; 12897c478bd9Sstevel@tonic-gate case 'u': 1290f595a68aSyz147064 if (modify_mask & DLADM_AGGR_MODIFY_MAC) 129133343a97Smeem die_optdup(option); 12927c478bd9Sstevel@tonic-gate 1293f595a68aSyz147064 modify_mask |= DLADM_AGGR_MODIFY_MAC; 12947c478bd9Sstevel@tonic-gate 1295f595a68aSyz147064 if (!dladm_aggr_str2macaddr(optarg, &mac_addr_fixed, 129633343a97Smeem mac_addr)) 129733343a97Smeem die("invalid MAC address '%s'", optarg); 12987c478bd9Sstevel@tonic-gate break; 12997c478bd9Sstevel@tonic-gate case 'l': 1300d62bc4baSyz147064 case 'L': 1301f595a68aSyz147064 if (modify_mask & DLADM_AGGR_MODIFY_LACP_MODE) 130233343a97Smeem die_optdup(option); 13037c478bd9Sstevel@tonic-gate 1304f595a68aSyz147064 modify_mask |= DLADM_AGGR_MODIFY_LACP_MODE; 13057c478bd9Sstevel@tonic-gate 1306f595a68aSyz147064 if (!dladm_aggr_str2lacpmode(optarg, &lacp_mode)) 130733343a97Smeem die("invalid LACP mode '%s'", optarg); 13087c478bd9Sstevel@tonic-gate break; 13097c478bd9Sstevel@tonic-gate case 'T': 1310f595a68aSyz147064 if (modify_mask & DLADM_AGGR_MODIFY_LACP_TIMER) 131133343a97Smeem die_optdup(option); 13127c478bd9Sstevel@tonic-gate 1313f595a68aSyz147064 modify_mask |= DLADM_AGGR_MODIFY_LACP_TIMER; 13147c478bd9Sstevel@tonic-gate 1315f595a68aSyz147064 if (!dladm_aggr_str2lacptimer(optarg, &lacp_timer)) 131633343a97Smeem die("invalid LACP timer value '%s'", optarg); 13177c478bd9Sstevel@tonic-gate break; 13187c478bd9Sstevel@tonic-gate case 't': 1319d62bc4baSyz147064 flags &= ~DLADM_OPT_PERSIST; 13207c478bd9Sstevel@tonic-gate break; 13217c478bd9Sstevel@tonic-gate case 'R': 13227c478bd9Sstevel@tonic-gate altroot = optarg; 13237c478bd9Sstevel@tonic-gate break; 13247c478bd9Sstevel@tonic-gate default: 132533343a97Smeem die_opterr(optopt, option); 132633343a97Smeem break; 13277c478bd9Sstevel@tonic-gate } 13287c478bd9Sstevel@tonic-gate } 13297c478bd9Sstevel@tonic-gate 133033343a97Smeem if (modify_mask == 0) 133133343a97Smeem die("at least one of the -PulT options must be specified"); 13327c478bd9Sstevel@tonic-gate 1333d62bc4baSyz147064 /* get key value or the aggregation name (required last argument) */ 13347c478bd9Sstevel@tonic-gate if (optind != (argc-1)) 13357c478bd9Sstevel@tonic-gate usage(); 13367c478bd9Sstevel@tonic-gate 1337d62bc4baSyz147064 status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags); 1338d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 1339d62bc4baSyz147064 goto done; 13407c478bd9Sstevel@tonic-gate 1341d62bc4baSyz147064 if (altroot != NULL) 1342d62bc4baSyz147064 altroot_cmd(altroot, argc, argv); 1343d62bc4baSyz147064 1344d62bc4baSyz147064 status = dladm_aggr_modify(linkid, modify_mask, policy, mac_addr_fixed, 1345d62bc4baSyz147064 (const uchar_t *)mac_addr, lacp_mode, lacp_timer, flags); 1346d62bc4baSyz147064 1347d62bc4baSyz147064 done: 1348f595a68aSyz147064 if (status != DLADM_STATUS_OK) 1349f595a68aSyz147064 die_dlerr(status, "modify operation failed"); 13507c478bd9Sstevel@tonic-gate } 13517c478bd9Sstevel@tonic-gate 13527c478bd9Sstevel@tonic-gate static void 13537c478bd9Sstevel@tonic-gate do_up_aggr(int argc, char *argv[]) 13547c478bd9Sstevel@tonic-gate { 1355d62bc4baSyz147064 datalink_id_t linkid = DATALINK_ALL_LINKID; 1356f595a68aSyz147064 dladm_status_t status; 13577c478bd9Sstevel@tonic-gate 1358d62bc4baSyz147064 /* 1359d62bc4baSyz147064 * get the key or the name of the aggregation (optional last argument) 1360d62bc4baSyz147064 */ 13617c478bd9Sstevel@tonic-gate if (argc == 2) { 1362d62bc4baSyz147064 if ((status = i_dladm_aggr_get_linkid(NULL, argv[1], &linkid, 1363d62bc4baSyz147064 DLADM_OPT_PERSIST)) != DLADM_STATUS_OK) { 1364d62bc4baSyz147064 goto done; 1365d62bc4baSyz147064 } 13667c478bd9Sstevel@tonic-gate } else if (argc > 2) { 13677c478bd9Sstevel@tonic-gate usage(); 13687c478bd9Sstevel@tonic-gate } 13697c478bd9Sstevel@tonic-gate 1370d62bc4baSyz147064 status = dladm_aggr_up(linkid); 1371d62bc4baSyz147064 done: 1372d62bc4baSyz147064 if (status != DLADM_STATUS_OK) { 1373d62bc4baSyz147064 if (argc == 2) { 1374d62bc4baSyz147064 die_dlerr(status, 1375d62bc4baSyz147064 "could not bring up aggregation '%s'", argv[1]); 13767c478bd9Sstevel@tonic-gate } else { 1377f595a68aSyz147064 die_dlerr(status, "could not bring aggregations up"); 13787c478bd9Sstevel@tonic-gate } 13797c478bd9Sstevel@tonic-gate } 13807c478bd9Sstevel@tonic-gate } 13817c478bd9Sstevel@tonic-gate 13827c478bd9Sstevel@tonic-gate static void 1383d62bc4baSyz147064 do_create_vlan(int argc, char *argv[]) 13847c478bd9Sstevel@tonic-gate { 1385d62bc4baSyz147064 char *link = NULL; 1386d62bc4baSyz147064 char drv[DLPI_LINKNAME_MAX]; 1387d62bc4baSyz147064 uint_t ppa; 1388d62bc4baSyz147064 datalink_id_t linkid; 1389d62bc4baSyz147064 int vid = 0; 1390d62bc4baSyz147064 char option; 1391d62bc4baSyz147064 uint32_t flags = (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST); 1392d62bc4baSyz147064 char *altroot = NULL; 1393d62bc4baSyz147064 char vlan[MAXLINKNAMELEN]; 1394f595a68aSyz147064 dladm_status_t status; 13957c478bd9Sstevel@tonic-gate 1396d62bc4baSyz147064 opterr = 0; 1397d62bc4baSyz147064 while ((option = getopt_long(argc, argv, ":tfl:v:", 1398d62bc4baSyz147064 lopts, NULL)) != -1) { 1399d62bc4baSyz147064 switch (option) { 1400d62bc4baSyz147064 case 'v': 1401d62bc4baSyz147064 if (vid != 0) 1402d62bc4baSyz147064 die_optdup(option); 1403d62bc4baSyz147064 1404d62bc4baSyz147064 if (!str2int(optarg, &vid) || vid < 1 || vid > 4094) 1405d62bc4baSyz147064 die("invalid VLAN identifier '%s'", optarg); 1406d62bc4baSyz147064 1407d62bc4baSyz147064 break; 1408d62bc4baSyz147064 case 'l': 1409d62bc4baSyz147064 if (link != NULL) 1410d62bc4baSyz147064 die_optdup(option); 1411d62bc4baSyz147064 1412d62bc4baSyz147064 link = optarg; 1413d62bc4baSyz147064 break; 1414d62bc4baSyz147064 case 'f': 1415d62bc4baSyz147064 flags |= DLADM_OPT_FORCE; 1416d62bc4baSyz147064 break; 1417d62bc4baSyz147064 case 't': 1418d62bc4baSyz147064 flags &= ~DLADM_OPT_PERSIST; 1419d62bc4baSyz147064 break; 1420d62bc4baSyz147064 case 'R': 1421d62bc4baSyz147064 altroot = optarg; 1422d62bc4baSyz147064 break; 1423d62bc4baSyz147064 default: 1424d62bc4baSyz147064 die_opterr(optopt, option); 1425d62bc4baSyz147064 break; 1426d62bc4baSyz147064 } 1427d62bc4baSyz147064 } 1428d62bc4baSyz147064 1429d62bc4baSyz147064 /* get vlan name if there is any */ 1430d62bc4baSyz147064 if ((vid == 0) || (link == NULL) || (argc - optind > 1)) 14317c478bd9Sstevel@tonic-gate usage(); 1432d62bc4baSyz147064 1433d62bc4baSyz147064 if (optind == (argc - 1)) { 1434d62bc4baSyz147064 if (strlcpy(vlan, argv[optind], MAXLINKNAMELEN) >= 1435d62bc4baSyz147064 MAXLINKNAMELEN) { 1436d62bc4baSyz147064 die("vlan name too long '%s'", argv[optind]); 1437d62bc4baSyz147064 } 1438d62bc4baSyz147064 } else { 1439d62bc4baSyz147064 if ((dlpi_parselink(link, drv, &ppa) != DLPI_SUCCESS) || 1440d62bc4baSyz147064 (ppa >= 1000) || 1441d62bc4baSyz147064 (dlpi_makelink(vlan, drv, vid * 1000 + ppa) != 1442d62bc4baSyz147064 DLPI_SUCCESS)) { 1443d62bc4baSyz147064 die("invalid link name '%s'", link); 1444d62bc4baSyz147064 } 14457c478bd9Sstevel@tonic-gate } 14467c478bd9Sstevel@tonic-gate 1447d62bc4baSyz147064 if (altroot != NULL) 1448d62bc4baSyz147064 altroot_cmd(altroot, argc, argv); 1449d62bc4baSyz147064 1450d62bc4baSyz147064 if (dladm_name2info(link, &linkid, NULL, NULL, NULL) != 1451d62bc4baSyz147064 DLADM_STATUS_OK) { 1452d62bc4baSyz147064 die("invalid link name '%s'", link); 1453d62bc4baSyz147064 } 1454d62bc4baSyz147064 1455d62bc4baSyz147064 if ((status = dladm_vlan_create(vlan, linkid, vid, flags)) != 1456d62bc4baSyz147064 DLADM_STATUS_OK) { 1457d62bc4baSyz147064 if (status == DLADM_STATUS_NOTSUP) { 1458*e7801d59Ssowmini die_dlerr(status, "not all links have link up/down " 1459*e7801d59Ssowmini "detection; must use -f (see dladm(1M))\n"); 1460d62bc4baSyz147064 } else { 1461d62bc4baSyz147064 die_dlerr(status, "create operation failed"); 1462d62bc4baSyz147064 } 1463d62bc4baSyz147064 } 1464d62bc4baSyz147064 } 1465d62bc4baSyz147064 1466d62bc4baSyz147064 static void 1467d62bc4baSyz147064 do_delete_vlan(int argc, char *argv[]) 1468d62bc4baSyz147064 { 1469d62bc4baSyz147064 char option; 1470d62bc4baSyz147064 uint32_t flags = (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST); 1471d62bc4baSyz147064 char *altroot = NULL; 1472d62bc4baSyz147064 datalink_id_t linkid; 1473d62bc4baSyz147064 dladm_status_t status; 1474d62bc4baSyz147064 1475d62bc4baSyz147064 opterr = 0; 1476d62bc4baSyz147064 while ((option = getopt_long(argc, argv, ":R:t", lopts, NULL)) != -1) { 1477d62bc4baSyz147064 switch (option) { 1478d62bc4baSyz147064 case 't': 1479d62bc4baSyz147064 flags &= ~DLADM_OPT_PERSIST; 1480d62bc4baSyz147064 break; 1481d62bc4baSyz147064 case 'R': 1482d62bc4baSyz147064 altroot = optarg; 1483d62bc4baSyz147064 break; 1484d62bc4baSyz147064 default: 1485d62bc4baSyz147064 die_opterr(optopt, option); 1486d62bc4baSyz147064 break; 1487d62bc4baSyz147064 } 1488d62bc4baSyz147064 } 1489d62bc4baSyz147064 1490d62bc4baSyz147064 /* get VLAN link name (required last argument) */ 1491d62bc4baSyz147064 if (optind != (argc - 1)) 1492d62bc4baSyz147064 usage(); 1493d62bc4baSyz147064 1494d62bc4baSyz147064 if (altroot != NULL) 1495d62bc4baSyz147064 altroot_cmd(altroot, argc, argv); 1496d62bc4baSyz147064 1497d62bc4baSyz147064 status = dladm_name2info(argv[optind], &linkid, NULL, NULL, NULL); 1498d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 1499d62bc4baSyz147064 goto done; 1500d62bc4baSyz147064 1501d62bc4baSyz147064 status = dladm_vlan_delete(linkid, flags); 1502d62bc4baSyz147064 done: 1503d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 1504d62bc4baSyz147064 die_dlerr(status, "delete operation failed"); 1505d62bc4baSyz147064 } 1506d62bc4baSyz147064 1507d62bc4baSyz147064 static void 1508d62bc4baSyz147064 do_up_vlan(int argc, char *argv[]) 1509d62bc4baSyz147064 { 1510d62bc4baSyz147064 datalink_id_t linkid = DATALINK_ALL_LINKID; 1511d62bc4baSyz147064 dladm_status_t status; 1512d62bc4baSyz147064 1513d62bc4baSyz147064 /* 1514d62bc4baSyz147064 * get the name of the VLAN (optional last argument) 1515d62bc4baSyz147064 */ 1516d62bc4baSyz147064 if (argc > 2) 1517d62bc4baSyz147064 usage(); 1518d62bc4baSyz147064 1519d62bc4baSyz147064 if (argc == 2) { 1520d62bc4baSyz147064 status = dladm_name2info(argv[1], &linkid, NULL, NULL, NULL); 1521d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 1522d62bc4baSyz147064 goto done; 1523d62bc4baSyz147064 } 1524d62bc4baSyz147064 1525d62bc4baSyz147064 status = dladm_vlan_up(linkid); 1526d62bc4baSyz147064 done: 1527d62bc4baSyz147064 if (status != DLADM_STATUS_OK) { 1528d62bc4baSyz147064 if (argc == 2) { 1529f595a68aSyz147064 die_dlerr(status, 1530d62bc4baSyz147064 "could not bring up VLAN '%s'", argv[1]); 15317c478bd9Sstevel@tonic-gate } else { 1532d62bc4baSyz147064 die_dlerr(status, "could not bring VLANs up"); 15337c478bd9Sstevel@tonic-gate } 15347c478bd9Sstevel@tonic-gate } 15357c478bd9Sstevel@tonic-gate } 15367c478bd9Sstevel@tonic-gate 1537210db224Sericheng static void 1538d62bc4baSyz147064 do_rename_link(int argc, char *argv[]) 1539210db224Sericheng { 1540d62bc4baSyz147064 char option; 1541d62bc4baSyz147064 char *link1, *link2; 1542d62bc4baSyz147064 char *altroot = NULL; 1543d62bc4baSyz147064 dladm_status_t status; 1544210db224Sericheng 1545d62bc4baSyz147064 opterr = 0; 1546d62bc4baSyz147064 while ((option = getopt_long(argc, argv, ":R:", lopts, NULL)) != -1) { 1547d62bc4baSyz147064 switch (option) { 1548d62bc4baSyz147064 case 'R': 1549d62bc4baSyz147064 altroot = optarg; 1550d62bc4baSyz147064 break; 1551d62bc4baSyz147064 default: 1552d62bc4baSyz147064 die_opterr(optopt, option); 1553d62bc4baSyz147064 break; 1554210db224Sericheng } 1555210db224Sericheng } 1556210db224Sericheng 1557d62bc4baSyz147064 /* get link1 and link2 name (required the last 2 arguments) */ 1558d62bc4baSyz147064 if (optind != (argc - 2)) 1559d62bc4baSyz147064 usage(); 1560d62bc4baSyz147064 1561d62bc4baSyz147064 if (altroot != NULL) 1562d62bc4baSyz147064 altroot_cmd(altroot, argc, argv); 1563d62bc4baSyz147064 1564d62bc4baSyz147064 link1 = argv[optind++]; 1565d62bc4baSyz147064 link2 = argv[optind]; 1566d62bc4baSyz147064 if ((status = dladm_rename_link(link1, link2)) != DLADM_STATUS_OK) 1567d62bc4baSyz147064 die_dlerr(status, "rename operation failed"); 1568d62bc4baSyz147064 } 1569d62bc4baSyz147064 1570d62bc4baSyz147064 static void 1571d62bc4baSyz147064 do_delete_phys(int argc, char *argv[]) 1572d62bc4baSyz147064 { 1573d62bc4baSyz147064 datalink_id_t linkid = DATALINK_ALL_LINKID; 1574d62bc4baSyz147064 dladm_status_t status; 1575d62bc4baSyz147064 1576d62bc4baSyz147064 /* get link name (required the last argument) */ 1577d62bc4baSyz147064 if (argc > 2) 1578d62bc4baSyz147064 usage(); 1579d62bc4baSyz147064 1580d62bc4baSyz147064 if (argc == 2) { 1581d62bc4baSyz147064 status = dladm_name2info(argv[1], &linkid, NULL, NULL, NULL); 1582d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 1583d62bc4baSyz147064 die_dlerr(status, "cannot delete '%s'", argv[1]); 1584d62bc4baSyz147064 } 1585d62bc4baSyz147064 1586d62bc4baSyz147064 if ((status = dladm_phys_delete(linkid)) != DLADM_STATUS_OK) { 1587d62bc4baSyz147064 if (argc == 2) 1588d62bc4baSyz147064 die_dlerr(status, "cannot delete '%s'", argv[1]); 1589d62bc4baSyz147064 else 1590d62bc4baSyz147064 die_dlerr(status, "delete operation failed"); 1591d62bc4baSyz147064 } 1592d62bc4baSyz147064 } 1593d62bc4baSyz147064 1594d62bc4baSyz147064 /*ARGSUSED*/ 1595210db224Sericheng static int 1596d62bc4baSyz147064 i_dladm_walk_linkmap(datalink_id_t linkid, void *arg) 1597210db224Sericheng { 1598d62bc4baSyz147064 char name[MAXLINKNAMELEN]; 1599d62bc4baSyz147064 char mediabuf[DLADM_STRSIZE]; 1600d62bc4baSyz147064 char classbuf[DLADM_STRSIZE]; 1601d62bc4baSyz147064 datalink_class_t class; 1602d62bc4baSyz147064 uint32_t media; 1603d62bc4baSyz147064 uint32_t flags; 1604210db224Sericheng 1605d62bc4baSyz147064 if (dladm_datalink_id2info(linkid, &flags, &class, &media, name, 1606d62bc4baSyz147064 MAXLINKNAMELEN) == DLADM_STATUS_OK) { 1607d62bc4baSyz147064 (void) dladm_class2str(class, classbuf); 1608d62bc4baSyz147064 (void) dladm_media2str(media, mediabuf); 1609d62bc4baSyz147064 (void) printf("%-12s%8d %-12s%-20s %6d\n", name, 1610d62bc4baSyz147064 linkid, classbuf, mediabuf, flags); 1611210db224Sericheng } 1612d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 1613210db224Sericheng } 16147c478bd9Sstevel@tonic-gate 16157c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 16167c478bd9Sstevel@tonic-gate static void 1617d62bc4baSyz147064 do_show_linkmap(int argc, char *argv[]) 16187c478bd9Sstevel@tonic-gate { 1619d62bc4baSyz147064 if (argc != 1) 1620d62bc4baSyz147064 die("invalid arguments"); 16217c478bd9Sstevel@tonic-gate 1622d62bc4baSyz147064 (void) printf("%-12s%8s %-12s%-20s %6s\n", "NAME", "LINKID", 1623d62bc4baSyz147064 "CLASS", "MEDIA", "FLAGS"); 1624d62bc4baSyz147064 (void) dladm_walk_datalink_id(i_dladm_walk_linkmap, NULL, 1625d62bc4baSyz147064 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, 1626d62bc4baSyz147064 DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST); 16277c478bd9Sstevel@tonic-gate } 1628d62bc4baSyz147064 1629d62bc4baSyz147064 /* 1630d62bc4baSyz147064 * Delete inactive physical links. 1631d62bc4baSyz147064 */ 1632d62bc4baSyz147064 /*ARGSUSED*/ 1633d62bc4baSyz147064 static int 1634d62bc4baSyz147064 purge_phys(datalink_id_t linkid, void *arg) 1635d62bc4baSyz147064 { 1636d62bc4baSyz147064 datalink_class_t class; 1637d62bc4baSyz147064 uint32_t flags; 1638d62bc4baSyz147064 1639d62bc4baSyz147064 if (dladm_datalink_id2info(linkid, &flags, &class, NULL, 1640d62bc4baSyz147064 NULL, 0) != DLADM_STATUS_OK) { 1641d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 1642d62bc4baSyz147064 } 1643d62bc4baSyz147064 1644d62bc4baSyz147064 if (class == DATALINK_CLASS_PHYS && !(flags & DLADM_OPT_ACTIVE)) 1645d62bc4baSyz147064 (void) dladm_phys_delete(linkid); 1646d62bc4baSyz147064 1647d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 1648d62bc4baSyz147064 } 1649d62bc4baSyz147064 1650d62bc4baSyz147064 /*ARGSUSED*/ 1651d62bc4baSyz147064 static void 1652d62bc4baSyz147064 do_init_phys(int argc, char *argv[]) 1653d62bc4baSyz147064 { 1654d62bc4baSyz147064 di_node_t devtree; 1655d62bc4baSyz147064 1656d62bc4baSyz147064 if (argc > 1) 1657d62bc4baSyz147064 usage(); 1658d62bc4baSyz147064 1659d62bc4baSyz147064 /* 1660d62bc4baSyz147064 * Force all the devices to attach, therefore all the network physical 1661d62bc4baSyz147064 * devices can be known to the dlmgmtd daemon. 1662d62bc4baSyz147064 */ 1663d62bc4baSyz147064 if ((devtree = di_init("/", DINFOFORCE | DINFOSUBTREE)) != DI_NODE_NIL) 1664d62bc4baSyz147064 di_fini(devtree); 1665d62bc4baSyz147064 1666d62bc4baSyz147064 (void) dladm_walk_datalink_id(purge_phys, NULL, 1667d62bc4baSyz147064 DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 16687c478bd9Sstevel@tonic-gate } 16697c478bd9Sstevel@tonic-gate 1670d62bc4baSyz147064 1671d62bc4baSyz147064 /* 1672d62bc4baSyz147064 * Print the active topology information. 1673d62bc4baSyz147064 */ 1674d62bc4baSyz147064 static dladm_status_t 1675d62bc4baSyz147064 print_link_topology(show_state_t *state, datalink_id_t linkid, 1676*e7801d59Ssowmini datalink_class_t class, link_fields_buf_t *lbuf) 1677d62bc4baSyz147064 { 1678d62bc4baSyz147064 uint32_t flags = state->ls_flags; 1679d62bc4baSyz147064 dladm_status_t status = DLADM_STATUS_OK; 1680d62bc4baSyz147064 1681*e7801d59Ssowmini if (!state->ls_parseable) 1682*e7801d59Ssowmini (void) sprintf(lbuf->link_over, STR_UNDEF_VAL); 1683d62bc4baSyz147064 else 1684*e7801d59Ssowmini (void) sprintf(lbuf->link_over, ""); 1685d62bc4baSyz147064 1686d62bc4baSyz147064 if (class == DATALINK_CLASS_VLAN) { 1687d62bc4baSyz147064 dladm_vlan_attr_t vinfo; 1688d62bc4baSyz147064 1689d62bc4baSyz147064 status = dladm_vlan_info(linkid, &vinfo, flags); 1690d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 1691d62bc4baSyz147064 goto done; 1692d62bc4baSyz147064 status = dladm_datalink_id2info(vinfo.dv_linkid, NULL, NULL, 1693*e7801d59Ssowmini NULL, lbuf->link_over, sizeof (lbuf->link_over)); 1694d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 1695d62bc4baSyz147064 goto done; 1696d62bc4baSyz147064 } else if (class == DATALINK_CLASS_AGGR) { 1697d62bc4baSyz147064 dladm_aggr_grp_attr_t ginfo; 1698d62bc4baSyz147064 int i; 1699d62bc4baSyz147064 1700d62bc4baSyz147064 status = dladm_aggr_info(linkid, &ginfo, flags); 1701d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 1702d62bc4baSyz147064 goto done; 1703d62bc4baSyz147064 1704d62bc4baSyz147064 if (ginfo.lg_nports == 0) { 1705d62bc4baSyz147064 status = DLADM_STATUS_BADVAL; 1706d62bc4baSyz147064 goto done; 1707d62bc4baSyz147064 } 1708d62bc4baSyz147064 for (i = 0; i < ginfo.lg_nports; i++) { 1709d62bc4baSyz147064 status = dladm_datalink_id2info( 1710*e7801d59Ssowmini ginfo.lg_ports[i].lp_linkid, NULL, NULL, NULL, 1711*e7801d59Ssowmini lbuf->link_over, sizeof (lbuf->link_over)); 1712d62bc4baSyz147064 if (status != DLADM_STATUS_OK) { 1713d62bc4baSyz147064 free(ginfo.lg_ports); 1714d62bc4baSyz147064 goto done; 1715d62bc4baSyz147064 } 1716d62bc4baSyz147064 } 1717d62bc4baSyz147064 free(ginfo.lg_ports); 1718d62bc4baSyz147064 } else if (class == DATALINK_CLASS_VNIC) { 1719d62bc4baSyz147064 dladm_vnic_attr_sys_t vinfo; 1720d62bc4baSyz147064 1721d62bc4baSyz147064 if ((status = dladm_vnic_info(linkid, &vinfo, flags)) != 1722d62bc4baSyz147064 DLADM_STATUS_OK || (status = dladm_datalink_id2info( 1723*e7801d59Ssowmini vinfo.va_link_id, NULL, NULL, NULL, lbuf->link_over, 1724*e7801d59Ssowmini sizeof (lbuf->link_over)) != DLADM_STATUS_OK)) { 1725d62bc4baSyz147064 goto done; 1726d62bc4baSyz147064 } 1727d62bc4baSyz147064 } 1728d62bc4baSyz147064 done: 1729d62bc4baSyz147064 return (status); 1730d62bc4baSyz147064 } 1731d62bc4baSyz147064 1732d62bc4baSyz147064 static dladm_status_t 1733*e7801d59Ssowmini print_link(show_state_t *state, datalink_id_t linkid, link_fields_buf_t *lbuf) 1734d62bc4baSyz147064 { 1735d62bc4baSyz147064 char link[MAXLINKNAMELEN]; 1736d62bc4baSyz147064 datalink_class_t class; 1737d62bc4baSyz147064 uint_t mtu; 1738d62bc4baSyz147064 uint32_t flags; 1739d62bc4baSyz147064 dladm_status_t status; 1740d62bc4baSyz147064 1741d62bc4baSyz147064 if ((status = dladm_datalink_id2info(linkid, &flags, &class, NULL, 1742d62bc4baSyz147064 link, sizeof (link))) != DLADM_STATUS_OK) { 1743d62bc4baSyz147064 goto done; 1744d62bc4baSyz147064 } 1745d62bc4baSyz147064 1746d62bc4baSyz147064 if (!(state->ls_flags & flags)) { 1747d62bc4baSyz147064 status = DLADM_STATUS_NOTFOUND; 1748d62bc4baSyz147064 goto done; 1749d62bc4baSyz147064 } 1750d62bc4baSyz147064 1751d62bc4baSyz147064 if (state->ls_flags == DLADM_OPT_ACTIVE) { 1752d62bc4baSyz147064 dladm_attr_t dlattr; 1753d62bc4baSyz147064 1754d62bc4baSyz147064 if (class == DATALINK_CLASS_PHYS) { 1755d62bc4baSyz147064 dladm_phys_attr_t dpa; 1756d62bc4baSyz147064 dlpi_handle_t dh; 1757d62bc4baSyz147064 dlpi_info_t dlinfo; 1758d62bc4baSyz147064 1759d62bc4baSyz147064 if ((status = dladm_phys_info(linkid, &dpa, 1760d62bc4baSyz147064 DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) { 1761d62bc4baSyz147064 goto done; 1762d62bc4baSyz147064 } 1763d62bc4baSyz147064 1764d62bc4baSyz147064 if (!dpa.dp_novanity) 1765d62bc4baSyz147064 goto link_mtu; 1766d62bc4baSyz147064 1767d62bc4baSyz147064 /* 1768d62bc4baSyz147064 * This is a physical link that does not have 1769d62bc4baSyz147064 * vanity naming support. 1770d62bc4baSyz147064 */ 1771d62bc4baSyz147064 if (dlpi_open(dpa.dp_dev, &dh, DLPI_DEVONLY) != 1772d62bc4baSyz147064 DLPI_SUCCESS) { 1773d62bc4baSyz147064 status = DLADM_STATUS_NOTFOUND; 1774d62bc4baSyz147064 goto done; 1775d62bc4baSyz147064 } 1776d62bc4baSyz147064 1777d62bc4baSyz147064 if (dlpi_info(dh, &dlinfo, 0) != DLPI_SUCCESS) { 1778d62bc4baSyz147064 dlpi_close(dh); 1779d62bc4baSyz147064 status = DLADM_STATUS_BADARG; 1780d62bc4baSyz147064 goto done; 1781d62bc4baSyz147064 } 1782d62bc4baSyz147064 1783d62bc4baSyz147064 dlpi_close(dh); 1784d62bc4baSyz147064 mtu = dlinfo.di_max_sdu; 1785d62bc4baSyz147064 } else { 1786d62bc4baSyz147064 link_mtu: 1787d62bc4baSyz147064 status = dladm_info(linkid, &dlattr); 1788d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 1789d62bc4baSyz147064 goto done; 1790d62bc4baSyz147064 mtu = dlattr.da_max_sdu; 1791d62bc4baSyz147064 } 1792d62bc4baSyz147064 } 1793d62bc4baSyz147064 1794*e7801d59Ssowmini (void) snprintf(lbuf->link_name, sizeof (lbuf->link_name), 1795*e7801d59Ssowmini "%s", link); 1796*e7801d59Ssowmini (void) dladm_class2str(class, lbuf->link_class); 1797d62bc4baSyz147064 if (state->ls_flags == DLADM_OPT_ACTIVE) { 1798*e7801d59Ssowmini (void) snprintf(lbuf->link_mtu, sizeof (lbuf->link_mtu), 1799*e7801d59Ssowmini "%d", mtu); 1800*e7801d59Ssowmini (void) get_linkstate(link, B_TRUE, lbuf->link_state); 1801d62bc4baSyz147064 } 1802d62bc4baSyz147064 1803*e7801d59Ssowmini status = print_link_topology(state, linkid, class, lbuf); 1804d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 1805d62bc4baSyz147064 goto done; 1806d62bc4baSyz147064 1807d62bc4baSyz147064 done: 1808d62bc4baSyz147064 return (status); 1809d62bc4baSyz147064 } 1810d62bc4baSyz147064 1811*e7801d59Ssowmini 1812d62bc4baSyz147064 static int 1813d62bc4baSyz147064 show_link(datalink_id_t linkid, void *arg) 1814d62bc4baSyz147064 { 1815*e7801d59Ssowmini show_state_t *state = (show_state_t *)arg; 1816d62bc4baSyz147064 dladm_status_t status; 1817*e7801d59Ssowmini link_fields_buf_t lbuf; 1818d62bc4baSyz147064 1819*e7801d59Ssowmini /* 1820*e7801d59Ssowmini * first get all the link attributes into lbuf; 1821*e7801d59Ssowmini */ 1822*e7801d59Ssowmini status = print_link(state, linkid, &lbuf); 1823*e7801d59Ssowmini 1824d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 1825d62bc4baSyz147064 goto done; 1826*e7801d59Ssowmini 1827*e7801d59Ssowmini if (!state->ls_parseable && !state->ls_printheader) { 1828*e7801d59Ssowmini print_header(&state->ls_print); 1829*e7801d59Ssowmini state->ls_printheader = B_TRUE; 1830*e7801d59Ssowmini } 1831*e7801d59Ssowmini 1832*e7801d59Ssowmini dladm_print_output(&state->ls_print, state->ls_parseable, 1833*e7801d59Ssowmini dladm_print_field, (void *)&lbuf); 1834d62bc4baSyz147064 1835d62bc4baSyz147064 done: 1836d62bc4baSyz147064 state->ls_status = status; 1837d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 1838d62bc4baSyz147064 } 1839d62bc4baSyz147064 1840d62bc4baSyz147064 static int 1841d62bc4baSyz147064 show_link_stats(datalink_id_t linkid, void *arg) 1842d62bc4baSyz147064 { 1843*e7801d59Ssowmini char link[DLPI_LINKNAME_MAX]; 1844d62bc4baSyz147064 datalink_class_t class; 1845*e7801d59Ssowmini show_state_t *state = (show_state_t *)arg; 18467c478bd9Sstevel@tonic-gate pktsum_t stats, diff_stats; 1847d62bc4baSyz147064 dladm_phys_attr_t dpa; 18487c478bd9Sstevel@tonic-gate 18497c478bd9Sstevel@tonic-gate if (state->ls_firstonly) { 18507c478bd9Sstevel@tonic-gate if (state->ls_donefirst) 1851d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 18527c478bd9Sstevel@tonic-gate state->ls_donefirst = B_TRUE; 18537c478bd9Sstevel@tonic-gate } else { 18547c478bd9Sstevel@tonic-gate bzero(&state->ls_prevstats, sizeof (state->ls_prevstats)); 18557c478bd9Sstevel@tonic-gate } 18567c478bd9Sstevel@tonic-gate 1857d62bc4baSyz147064 if (dladm_datalink_id2info(linkid, NULL, &class, NULL, link, 1858*e7801d59Ssowmini DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) { 1859d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 1860d62bc4baSyz147064 } 1861d62bc4baSyz147064 1862d62bc4baSyz147064 if (class == DATALINK_CLASS_PHYS) { 1863d62bc4baSyz147064 if (dladm_phys_info(linkid, &dpa, DLADM_OPT_ACTIVE) != 1864d62bc4baSyz147064 DLADM_STATUS_OK) { 1865d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 1866d62bc4baSyz147064 } 1867d62bc4baSyz147064 if (dpa.dp_novanity) 1868d62bc4baSyz147064 get_mac_stats(dpa.dp_dev, &stats); 1869d62bc4baSyz147064 else 1870d62bc4baSyz147064 get_link_stats(link, &stats); 1871d62bc4baSyz147064 } else { 1872d62bc4baSyz147064 get_link_stats(link, &stats); 1873d62bc4baSyz147064 } 18747c478bd9Sstevel@tonic-gate stats_diff(&diff_stats, &stats, &state->ls_prevstats); 18757c478bd9Sstevel@tonic-gate 1876d62bc4baSyz147064 (void) printf("%-12s", link); 1877d62bc4baSyz147064 (void) printf("%-10llu", diff_stats.ipackets); 18787c478bd9Sstevel@tonic-gate (void) printf("%-12llu", diff_stats.rbytes); 18797c478bd9Sstevel@tonic-gate (void) printf("%-8u", diff_stats.ierrors); 18807c478bd9Sstevel@tonic-gate (void) printf("%-10llu", diff_stats.opackets); 18817c478bd9Sstevel@tonic-gate (void) printf("%-12llu", diff_stats.obytes); 18827c478bd9Sstevel@tonic-gate (void) printf("%-8u\n", diff_stats.oerrors); 18837c478bd9Sstevel@tonic-gate 18847c478bd9Sstevel@tonic-gate state->ls_prevstats = stats; 1885d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 18867c478bd9Sstevel@tonic-gate } 18877c478bd9Sstevel@tonic-gate 1888d62bc4baSyz147064 1889d62bc4baSyz147064 static dladm_status_t 1890d62bc4baSyz147064 print_aggr_info(show_grp_state_t *state, const char *link, 1891*e7801d59Ssowmini dladm_aggr_grp_attr_t *ginfop) 1892d62bc4baSyz147064 { 1893d62bc4baSyz147064 char addr_str[ETHERADDRL * 3]; 1894*e7801d59Ssowmini laggr_fields_buf_t lbuf; 1895d62bc4baSyz147064 1896*e7801d59Ssowmini (void) snprintf(lbuf.laggr_name, sizeof (lbuf.laggr_name), 1897*e7801d59Ssowmini "%s", link); 1898*e7801d59Ssowmini 1899*e7801d59Ssowmini (void) dladm_aggr_policy2str(ginfop->lg_policy, 1900*e7801d59Ssowmini lbuf.laggr_policy); 1901d62bc4baSyz147064 1902d62bc4baSyz147064 if (ginfop->lg_mac_fixed) { 1903d62bc4baSyz147064 (void) dladm_aggr_macaddr2str(ginfop->lg_mac, addr_str); 1904*e7801d59Ssowmini (void) snprintf(lbuf.laggr_addrpolicy, 1905*e7801d59Ssowmini sizeof (lbuf.laggr_addrpolicy), "fixed (%s)", addr_str); 1906d62bc4baSyz147064 } else { 1907*e7801d59Ssowmini (void) snprintf(lbuf.laggr_addrpolicy, 1908*e7801d59Ssowmini sizeof (lbuf.laggr_addrpolicy), "auto"); 1909d62bc4baSyz147064 } 1910d62bc4baSyz147064 1911d62bc4baSyz147064 1912*e7801d59Ssowmini (void) dladm_aggr_lacpmode2str(ginfop->lg_lacp_mode, 1913*e7801d59Ssowmini lbuf.laggr_lacpactivity); 1914*e7801d59Ssowmini (void) dladm_aggr_lacptimer2str(ginfop->lg_lacp_timer, 1915*e7801d59Ssowmini lbuf.laggr_lacptimer); 1916*e7801d59Ssowmini (void) snprintf(lbuf.laggr_flags, sizeof (lbuf.laggr_flags), "%c----", 1917d62bc4baSyz147064 ginfop->lg_force ? 'f' : '-'); 1918*e7801d59Ssowmini 1919*e7801d59Ssowmini if (!state->gs_parseable && !state->gs_printheader) { 1920*e7801d59Ssowmini print_header(&state->gs_print); 1921*e7801d59Ssowmini state->gs_printheader = B_TRUE; 1922d62bc4baSyz147064 } 1923d62bc4baSyz147064 1924*e7801d59Ssowmini dladm_print_output(&state->gs_print, state->gs_parseable, 1925*e7801d59Ssowmini dladm_print_field, (void *)&lbuf); 1926*e7801d59Ssowmini 1927d62bc4baSyz147064 return (DLADM_STATUS_OK); 1928d62bc4baSyz147064 } 1929d62bc4baSyz147064 1930*e7801d59Ssowmini static char * 1931*e7801d59Ssowmini print_xaggr_callback(print_field_t *pf, void *arg) 1932d62bc4baSyz147064 { 1933*e7801d59Ssowmini const laggr_args_t *l = arg; 1934*e7801d59Ssowmini int portnum; 1935*e7801d59Ssowmini static char buf[DLADM_STRSIZE]; 1936*e7801d59Ssowmini boolean_t is_port = (l->laggr_lport >= 0); 1937*e7801d59Ssowmini dladm_aggr_port_attr_t *portp; 1938d62bc4baSyz147064 dladm_phys_attr_t dpa; 1939*e7801d59Ssowmini dladm_status_t *stat, status; 1940d62bc4baSyz147064 1941*e7801d59Ssowmini stat = l->laggr_status; 1942*e7801d59Ssowmini *stat = DLADM_STATUS_OK; 1943d62bc4baSyz147064 1944*e7801d59Ssowmini if (is_port) { 1945*e7801d59Ssowmini portnum = l->laggr_lport; 1946*e7801d59Ssowmini portp = &(l->laggr_ginfop->lg_ports[portnum]); 1947*e7801d59Ssowmini if ((status = dladm_datalink_id2info(portp->lp_linkid, 1948*e7801d59Ssowmini NULL, NULL, NULL, buf, sizeof (buf))) != 1949*e7801d59Ssowmini DLADM_STATUS_OK) { 1950*e7801d59Ssowmini goto err; 1951d62bc4baSyz147064 } 1952d62bc4baSyz147064 if ((status = dladm_phys_info(portp->lp_linkid, &dpa, 1953d62bc4baSyz147064 DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) { 1954*e7801d59Ssowmini goto err; 1955*e7801d59Ssowmini } 1956d62bc4baSyz147064 } 1957d62bc4baSyz147064 1958*e7801d59Ssowmini switch (pf->pf_index) { 1959*e7801d59Ssowmini case AGGR_X_LINK: 1960*e7801d59Ssowmini (void) snprintf(buf, sizeof (buf), "%s", 1961*e7801d59Ssowmini (is_port && !l->laggr_parseable ? " " : l->laggr_link)); 1962*e7801d59Ssowmini break; 1963*e7801d59Ssowmini case AGGR_X_PORT: 1964*e7801d59Ssowmini if (is_port) 1965*e7801d59Ssowmini break; 1966*e7801d59Ssowmini return (""); 1967*e7801d59Ssowmini break; 1968d62bc4baSyz147064 1969*e7801d59Ssowmini case AGGR_X_SPEED: 1970*e7801d59Ssowmini if (is_port) { 1971*e7801d59Ssowmini (void) snprintf(buf, sizeof (buf), "%uMb", 1972*e7801d59Ssowmini (uint_t)((get_ifspeed(dpa.dp_dev, 1973*e7801d59Ssowmini B_FALSE)) / 1000000ull)); 1974*e7801d59Ssowmini } else { 1975*e7801d59Ssowmini (void) snprintf(buf, sizeof (buf), "%uMb", 1976*e7801d59Ssowmini (uint_t)((get_ifspeed(l->laggr_link, 1977*e7801d59Ssowmini B_TRUE)) / 1000000ull)); 1978*e7801d59Ssowmini } 1979*e7801d59Ssowmini break; 1980*e7801d59Ssowmini 1981*e7801d59Ssowmini case AGGR_X_DUPLEX: 1982*e7801d59Ssowmini if (is_port) 1983*e7801d59Ssowmini (void) get_linkduplex(dpa.dp_dev, B_FALSE, buf); 1984d62bc4baSyz147064 else 1985*e7801d59Ssowmini (void) get_linkduplex(l->laggr_link, B_TRUE, buf); 1986*e7801d59Ssowmini break; 1987d62bc4baSyz147064 1988*e7801d59Ssowmini case AGGR_X_STATE: 1989*e7801d59Ssowmini if (is_port) { 1990d62bc4baSyz147064 (void) dladm_aggr_portstate2str( 1991*e7801d59Ssowmini portp->lp_state, buf); 1992d62bc4baSyz147064 } else { 1993*e7801d59Ssowmini return (STR_UNDEF_VAL); 1994d62bc4baSyz147064 } 1995*e7801d59Ssowmini break; 1996*e7801d59Ssowmini case AGGR_X_ADDRESS: 1997*e7801d59Ssowmini (void) dladm_aggr_macaddr2str( 1998*e7801d59Ssowmini (is_port ? portp->lp_mac : l->laggr_ginfop->lg_mac), 1999*e7801d59Ssowmini buf); 2000*e7801d59Ssowmini break; 2001*e7801d59Ssowmini 2002*e7801d59Ssowmini case AGGR_X_PORTSTATE: 2003*e7801d59Ssowmini (void) snprintf(buf, sizeof (buf), "%s", 2004*e7801d59Ssowmini (is_port ? dladm_aggr_portstate2str(portp->lp_state, buf): 2005*e7801d59Ssowmini (l->laggr_parseable ? "" : STR_UNDEF_VAL))); 2006*e7801d59Ssowmini break; 2007*e7801d59Ssowmini } 2008*e7801d59Ssowmini return (buf); 2009*e7801d59Ssowmini 2010*e7801d59Ssowmini err: 2011*e7801d59Ssowmini *stat = status; 2012*e7801d59Ssowmini buf[0] = '\0'; 2013*e7801d59Ssowmini return (buf); 2014*e7801d59Ssowmini } 2015*e7801d59Ssowmini 2016*e7801d59Ssowmini static dladm_status_t 2017*e7801d59Ssowmini print_aggr_extended(show_grp_state_t *state, const char *link, 2018*e7801d59Ssowmini dladm_aggr_grp_attr_t *ginfop) 2019*e7801d59Ssowmini { 2020*e7801d59Ssowmini int i; 2021*e7801d59Ssowmini dladm_status_t status; 2022*e7801d59Ssowmini laggr_args_t largs; 2023*e7801d59Ssowmini 2024*e7801d59Ssowmini if (!state->gs_parseable && !state->gs_printheader) { 2025*e7801d59Ssowmini print_header(&state->gs_print); 2026*e7801d59Ssowmini state->gs_printheader = B_TRUE; 2027*e7801d59Ssowmini } 2028*e7801d59Ssowmini 2029*e7801d59Ssowmini largs.laggr_lport = -1; 2030*e7801d59Ssowmini largs.laggr_link = link; 2031*e7801d59Ssowmini largs.laggr_ginfop = ginfop; 2032*e7801d59Ssowmini largs.laggr_status = &status; 2033*e7801d59Ssowmini largs.laggr_parseable = state->gs_parseable; 2034*e7801d59Ssowmini 2035*e7801d59Ssowmini dladm_print_output(&state->gs_print, state->gs_parseable, 2036*e7801d59Ssowmini print_xaggr_callback, &largs); 2037*e7801d59Ssowmini 2038*e7801d59Ssowmini if (status != DLADM_STATUS_OK) 2039*e7801d59Ssowmini goto done; 2040*e7801d59Ssowmini 2041*e7801d59Ssowmini for (i = 0; i < ginfop->lg_nports; i++) { 2042*e7801d59Ssowmini largs.laggr_lport = i; 2043*e7801d59Ssowmini dladm_print_output(&state->gs_print, state->gs_parseable, 2044*e7801d59Ssowmini print_xaggr_callback, &largs); 2045*e7801d59Ssowmini if (status != DLADM_STATUS_OK) 2046*e7801d59Ssowmini goto done; 2047d62bc4baSyz147064 } 2048d62bc4baSyz147064 2049d62bc4baSyz147064 status = DLADM_STATUS_OK; 2050d62bc4baSyz147064 done: 2051d62bc4baSyz147064 return (status); 2052d62bc4baSyz147064 } 2053d62bc4baSyz147064 2054*e7801d59Ssowmini 2055*e7801d59Ssowmini static char * 2056*e7801d59Ssowmini print_lacp_callback(print_field_t *pf, void *arg) 2057*e7801d59Ssowmini { 2058*e7801d59Ssowmini const laggr_args_t *l = arg; 2059*e7801d59Ssowmini int portnum; 2060*e7801d59Ssowmini static char buf[DLADM_STRSIZE]; 2061*e7801d59Ssowmini boolean_t is_port = (l->laggr_lport >= 0); 2062*e7801d59Ssowmini dladm_aggr_port_attr_t *portp; 2063*e7801d59Ssowmini dladm_status_t *stat, status; 2064*e7801d59Ssowmini aggr_lacp_state_t *lstate; 2065*e7801d59Ssowmini 2066*e7801d59Ssowmini if (!is_port) { 2067*e7801d59Ssowmini return (NULL); /* cannot happen! */ 2068*e7801d59Ssowmini } 2069*e7801d59Ssowmini 2070*e7801d59Ssowmini stat = l->laggr_status; 2071*e7801d59Ssowmini 2072*e7801d59Ssowmini portnum = l->laggr_lport; 2073*e7801d59Ssowmini portp = &(l->laggr_ginfop->lg_ports[portnum]); 2074*e7801d59Ssowmini if ((status = dladm_datalink_id2info(portp->lp_linkid, 2075*e7801d59Ssowmini NULL, NULL, NULL, buf, sizeof (buf))) != DLADM_STATUS_OK) { 2076*e7801d59Ssowmini goto err; 2077*e7801d59Ssowmini } 2078*e7801d59Ssowmini lstate = &(portp->lp_lacp_state); 2079*e7801d59Ssowmini 2080*e7801d59Ssowmini switch (pf->pf_index) { 2081*e7801d59Ssowmini case AGGR_L_LINK: 2082*e7801d59Ssowmini (void) snprintf(buf, sizeof (buf), "%s", 2083*e7801d59Ssowmini (portnum > 0 ? "" : l->laggr_link)); 2084*e7801d59Ssowmini break; 2085*e7801d59Ssowmini 2086*e7801d59Ssowmini case AGGR_L_PORT: 2087*e7801d59Ssowmini break; 2088*e7801d59Ssowmini 2089*e7801d59Ssowmini case AGGR_L_AGGREGATABLE: 2090*e7801d59Ssowmini (void) snprintf(buf, sizeof (buf), "%s", 2091*e7801d59Ssowmini (lstate->bit.aggregation ? "yes" : "no")); 2092*e7801d59Ssowmini break; 2093*e7801d59Ssowmini 2094*e7801d59Ssowmini case AGGR_L_SYNC: 2095*e7801d59Ssowmini (void) snprintf(buf, sizeof (buf), "%s", 2096*e7801d59Ssowmini (lstate->bit.sync ? "yes" : "no")); 2097*e7801d59Ssowmini break; 2098*e7801d59Ssowmini 2099*e7801d59Ssowmini case AGGR_L_COLL: 2100*e7801d59Ssowmini (void) snprintf(buf, sizeof (buf), "%s", 2101*e7801d59Ssowmini (lstate->bit.collecting ? "yes" : "no")); 2102*e7801d59Ssowmini break; 2103*e7801d59Ssowmini 2104*e7801d59Ssowmini case AGGR_L_DIST: 2105*e7801d59Ssowmini (void) snprintf(buf, sizeof (buf), "%s", 2106*e7801d59Ssowmini (lstate->bit.distributing ? "yes" : "no")); 2107*e7801d59Ssowmini break; 2108*e7801d59Ssowmini 2109*e7801d59Ssowmini case AGGR_L_DEFAULTED: 2110*e7801d59Ssowmini (void) snprintf(buf, sizeof (buf), "%s", 2111*e7801d59Ssowmini (lstate->bit.defaulted ? "yes" : "no")); 2112*e7801d59Ssowmini break; 2113*e7801d59Ssowmini 2114*e7801d59Ssowmini case AGGR_L_EXPIRED: 2115*e7801d59Ssowmini (void) snprintf(buf, sizeof (buf), "%s", 2116*e7801d59Ssowmini (lstate->bit.expired ? "yes" : "no")); 2117*e7801d59Ssowmini break; 2118*e7801d59Ssowmini } 2119*e7801d59Ssowmini 2120*e7801d59Ssowmini *stat = DLADM_STATUS_OK; 2121*e7801d59Ssowmini return (buf); 2122*e7801d59Ssowmini 2123*e7801d59Ssowmini err: 2124*e7801d59Ssowmini *stat = status; 2125*e7801d59Ssowmini buf[0] = '\0'; 2126*e7801d59Ssowmini return (buf); 2127*e7801d59Ssowmini } 2128*e7801d59Ssowmini 2129d62bc4baSyz147064 static dladm_status_t 2130d62bc4baSyz147064 print_aggr_lacp(show_grp_state_t *state, const char *link, 2131*e7801d59Ssowmini dladm_aggr_grp_attr_t *ginfop) 2132d62bc4baSyz147064 { 2133d62bc4baSyz147064 int i; 2134d62bc4baSyz147064 dladm_status_t status; 2135*e7801d59Ssowmini laggr_args_t largs; 2136d62bc4baSyz147064 2137*e7801d59Ssowmini if (!state->gs_parseable && !state->gs_printheader) { 2138*e7801d59Ssowmini print_header(&state->gs_print); 2139*e7801d59Ssowmini state->gs_printheader = B_TRUE; 2140d62bc4baSyz147064 } 2141d62bc4baSyz147064 2142*e7801d59Ssowmini largs.laggr_link = link; 2143*e7801d59Ssowmini largs.laggr_ginfop = ginfop; 2144*e7801d59Ssowmini largs.laggr_status = &status; 2145d62bc4baSyz147064 2146*e7801d59Ssowmini for (i = 0; i < ginfop->lg_nports; i++) { 2147*e7801d59Ssowmini largs.laggr_lport = i; 2148*e7801d59Ssowmini dladm_print_output(&state->gs_print, state->gs_parseable, 2149*e7801d59Ssowmini print_lacp_callback, &largs); 2150d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 2151d62bc4baSyz147064 goto done; 2152d62bc4baSyz147064 } 2153d62bc4baSyz147064 2154d62bc4baSyz147064 status = DLADM_STATUS_OK; 2155d62bc4baSyz147064 done: 2156d62bc4baSyz147064 return (status); 2157d62bc4baSyz147064 } 2158d62bc4baSyz147064 2159*e7801d59Ssowmini static char * 2160*e7801d59Ssowmini print_aggr_stats_callback(print_field_t *pf, void *arg) 2161*e7801d59Ssowmini { 2162*e7801d59Ssowmini const laggr_args_t *l = arg; 2163*e7801d59Ssowmini int portnum; 2164*e7801d59Ssowmini static char buf[DLADM_STRSIZE]; 2165*e7801d59Ssowmini boolean_t is_port = (l->laggr_lport >= 0); 2166*e7801d59Ssowmini dladm_aggr_port_attr_t *portp; 2167*e7801d59Ssowmini dladm_phys_attr_t dpa; 2168*e7801d59Ssowmini dladm_status_t *stat, status; 2169*e7801d59Ssowmini pktsum_t port_stat, diff_stats; 2170*e7801d59Ssowmini 2171*e7801d59Ssowmini stat = l->laggr_status; 2172*e7801d59Ssowmini *stat = DLADM_STATUS_OK; 2173*e7801d59Ssowmini 2174*e7801d59Ssowmini if (is_port) { 2175*e7801d59Ssowmini portnum = l->laggr_lport; 2176*e7801d59Ssowmini portp = &(l->laggr_ginfop->lg_ports[portnum]); 2177*e7801d59Ssowmini if ((status = dladm_phys_info(portp->lp_linkid, &dpa, 2178*e7801d59Ssowmini DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) { 2179*e7801d59Ssowmini goto err; 2180*e7801d59Ssowmini } 2181*e7801d59Ssowmini 2182*e7801d59Ssowmini get_mac_stats(dpa.dp_dev, &port_stat); 2183*e7801d59Ssowmini 2184*e7801d59Ssowmini if ((status = dladm_datalink_id2info(portp->lp_linkid, NULL, 2185*e7801d59Ssowmini NULL, NULL, buf, sizeof (buf))) != DLADM_STATUS_OK) { 2186*e7801d59Ssowmini goto err; 2187*e7801d59Ssowmini } 2188*e7801d59Ssowmini 2189*e7801d59Ssowmini stats_diff(&diff_stats, &port_stat, l->laggr_prevstats); 2190*e7801d59Ssowmini } 2191*e7801d59Ssowmini 2192*e7801d59Ssowmini switch (pf->pf_index) { 2193*e7801d59Ssowmini case AGGR_S_LINK: 2194*e7801d59Ssowmini (void) snprintf(buf, sizeof (buf), "%s", 2195*e7801d59Ssowmini (is_port ? "" : l->laggr_link)); 2196*e7801d59Ssowmini break; 2197*e7801d59Ssowmini case AGGR_S_PORT: 2198*e7801d59Ssowmini if (is_port) 2199*e7801d59Ssowmini break; 2200*e7801d59Ssowmini return (STR_UNDEF_VAL); 2201*e7801d59Ssowmini break; 2202*e7801d59Ssowmini 2203*e7801d59Ssowmini case AGGR_S_IPKTS: 2204*e7801d59Ssowmini if (is_port) { 2205*e7801d59Ssowmini (void) snprintf(buf, sizeof (buf), "%llu", 2206*e7801d59Ssowmini diff_stats.ipackets); 2207*e7801d59Ssowmini } else { 2208*e7801d59Ssowmini (void) snprintf(buf, sizeof (buf), "%llu", 2209*e7801d59Ssowmini l->laggr_pktsumtot->ipackets); 2210*e7801d59Ssowmini } 2211*e7801d59Ssowmini break; 2212*e7801d59Ssowmini 2213*e7801d59Ssowmini case AGGR_S_RBYTES: 2214*e7801d59Ssowmini if (is_port) { 2215*e7801d59Ssowmini (void) snprintf(buf, sizeof (buf), "%llu", 2216*e7801d59Ssowmini diff_stats.rbytes); 2217*e7801d59Ssowmini } else { 2218*e7801d59Ssowmini (void) snprintf(buf, sizeof (buf), "%llu", 2219*e7801d59Ssowmini l->laggr_pktsumtot->rbytes); 2220*e7801d59Ssowmini } 2221*e7801d59Ssowmini break; 2222*e7801d59Ssowmini 2223*e7801d59Ssowmini case AGGR_S_OPKTS: 2224*e7801d59Ssowmini if (is_port) { 2225*e7801d59Ssowmini (void) snprintf(buf, sizeof (buf), "%llu", 2226*e7801d59Ssowmini diff_stats.opackets); 2227*e7801d59Ssowmini } else { 2228*e7801d59Ssowmini (void) snprintf(buf, sizeof (buf), "%llu", 2229*e7801d59Ssowmini l->laggr_pktsumtot->opackets); 2230*e7801d59Ssowmini } 2231*e7801d59Ssowmini break; 2232*e7801d59Ssowmini case AGGR_S_OBYTES: 2233*e7801d59Ssowmini if (is_port) { 2234*e7801d59Ssowmini (void) snprintf(buf, sizeof (buf), "%llu", 2235*e7801d59Ssowmini diff_stats.obytes); 2236*e7801d59Ssowmini } else { 2237*e7801d59Ssowmini (void) snprintf(buf, sizeof (buf), "%llu", 2238*e7801d59Ssowmini l->laggr_pktsumtot->obytes); 2239*e7801d59Ssowmini 2240*e7801d59Ssowmini } 2241*e7801d59Ssowmini break; 2242*e7801d59Ssowmini 2243*e7801d59Ssowmini case AGGR_S_IPKTDIST: 2244*e7801d59Ssowmini if (is_port) { 2245*e7801d59Ssowmini (void) snprintf(buf, sizeof (buf), "%-6.1f", 2246*e7801d59Ssowmini (double)diff_stats.opackets/ 2247*e7801d59Ssowmini (double)l->laggr_pktsumtot->ipackets * 100); 2248*e7801d59Ssowmini } else { 2249*e7801d59Ssowmini return (STR_UNDEF_VAL); 2250*e7801d59Ssowmini } 2251*e7801d59Ssowmini break; 2252*e7801d59Ssowmini case AGGR_S_OPKTDIST: 2253*e7801d59Ssowmini if (is_port) { 2254*e7801d59Ssowmini (void) snprintf(buf, sizeof (buf), "%-6.1f", 2255*e7801d59Ssowmini (double)diff_stats.opackets/ 2256*e7801d59Ssowmini (double)l->laggr_pktsumtot->opackets * 100); 2257*e7801d59Ssowmini } else { 2258*e7801d59Ssowmini (void) sprintf(buf, STR_UNDEF_VAL); 2259*e7801d59Ssowmini } 2260*e7801d59Ssowmini break; 2261*e7801d59Ssowmini } 2262*e7801d59Ssowmini return (buf); 2263*e7801d59Ssowmini 2264*e7801d59Ssowmini err: 2265*e7801d59Ssowmini *stat = status; 2266*e7801d59Ssowmini buf[0] = '\0'; 2267*e7801d59Ssowmini return (buf); 2268*e7801d59Ssowmini } 2269*e7801d59Ssowmini 2270d62bc4baSyz147064 static dladm_status_t 2271d62bc4baSyz147064 print_aggr_stats(show_grp_state_t *state, const char *link, 2272*e7801d59Ssowmini dladm_aggr_grp_attr_t *ginfop) 2273d62bc4baSyz147064 { 2274d62bc4baSyz147064 dladm_phys_attr_t dpa; 2275d62bc4baSyz147064 dladm_aggr_port_attr_t *portp; 2276d62bc4baSyz147064 pktsum_t pktsumtot, port_stat; 2277d62bc4baSyz147064 dladm_status_t status; 2278d62bc4baSyz147064 int i; 2279*e7801d59Ssowmini laggr_args_t largs; 22807c478bd9Sstevel@tonic-gate 22817c478bd9Sstevel@tonic-gate /* sum the ports statistics */ 22827c478bd9Sstevel@tonic-gate bzero(&pktsumtot, sizeof (pktsumtot)); 2283d62bc4baSyz147064 2284d62bc4baSyz147064 for (i = 0; i < ginfop->lg_nports; i++) { 2285d62bc4baSyz147064 2286d62bc4baSyz147064 portp = &(ginfop->lg_ports[i]); 2287d62bc4baSyz147064 if ((status = dladm_phys_info(portp->lp_linkid, &dpa, 2288d62bc4baSyz147064 DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) { 2289d62bc4baSyz147064 goto done; 22907c478bd9Sstevel@tonic-gate } 22917c478bd9Sstevel@tonic-gate 2292d62bc4baSyz147064 get_mac_stats(dpa.dp_dev, &port_stat); 2293d62bc4baSyz147064 stats_total(&pktsumtot, &port_stat, &state->gs_prevstats[i]); 22947c478bd9Sstevel@tonic-gate } 22957c478bd9Sstevel@tonic-gate 2296*e7801d59Ssowmini if (!state->gs_parseable && !state->gs_printheader) { 2297*e7801d59Ssowmini print_header(&state->gs_print); 2298*e7801d59Ssowmini state->gs_printheader = B_TRUE; 2299*e7801d59Ssowmini } 2300*e7801d59Ssowmini 2301*e7801d59Ssowmini largs.laggr_lport = -1; 2302*e7801d59Ssowmini largs.laggr_link = link; 2303*e7801d59Ssowmini largs.laggr_ginfop = ginfop; 2304*e7801d59Ssowmini largs.laggr_status = &status; 2305*e7801d59Ssowmini largs.laggr_pktsumtot = &pktsumtot; 2306*e7801d59Ssowmini 2307*e7801d59Ssowmini dladm_print_output(&state->gs_print, state->gs_parseable, 2308*e7801d59Ssowmini print_aggr_stats_callback, &largs); 2309*e7801d59Ssowmini 2310*e7801d59Ssowmini if (status != DLADM_STATUS_OK) 2311*e7801d59Ssowmini goto done; 2312d62bc4baSyz147064 2313d62bc4baSyz147064 for (i = 0; i < ginfop->lg_nports; i++) { 2314*e7801d59Ssowmini largs.laggr_lport = i; 2315*e7801d59Ssowmini largs.laggr_prevstats = &state->gs_prevstats[i]; 2316*e7801d59Ssowmini dladm_print_output(&state->gs_print, state->gs_parseable, 2317*e7801d59Ssowmini print_aggr_stats_callback, &largs); 2318*e7801d59Ssowmini if (status != DLADM_STATUS_OK) 2319d62bc4baSyz147064 goto done; 2320d62bc4baSyz147064 } 2321d62bc4baSyz147064 2322d62bc4baSyz147064 status = DLADM_STATUS_OK; 2323d62bc4baSyz147064 done: 2324d62bc4baSyz147064 return (status); 2325d62bc4baSyz147064 } 2326d62bc4baSyz147064 2327d62bc4baSyz147064 static dladm_status_t 2328*e7801d59Ssowmini print_aggr(show_grp_state_t *state, datalink_id_t linkid) 2329d62bc4baSyz147064 { 2330d62bc4baSyz147064 char link[MAXLINKNAMELEN]; 2331d62bc4baSyz147064 dladm_aggr_grp_attr_t ginfo; 2332d62bc4baSyz147064 uint32_t flags; 2333d62bc4baSyz147064 dladm_status_t status; 2334d62bc4baSyz147064 2335d62bc4baSyz147064 if ((status = dladm_datalink_id2info(linkid, &flags, NULL, NULL, link, 2336*e7801d59Ssowmini MAXLINKNAMELEN)) != DLADM_STATUS_OK) { 2337d62bc4baSyz147064 return (status); 2338d62bc4baSyz147064 } 2339d62bc4baSyz147064 2340d62bc4baSyz147064 if (!(state->gs_flags & flags)) 2341d62bc4baSyz147064 return (DLADM_STATUS_NOTFOUND); 2342d62bc4baSyz147064 2343d62bc4baSyz147064 status = dladm_aggr_info(linkid, &ginfo, state->gs_flags); 2344d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 2345d62bc4baSyz147064 return (status); 2346d62bc4baSyz147064 2347d62bc4baSyz147064 if (state->gs_lacp) 2348*e7801d59Ssowmini status = print_aggr_lacp(state, link, &ginfo); 2349d62bc4baSyz147064 else if (state->gs_extended) 2350*e7801d59Ssowmini status = print_aggr_extended(state, link, &ginfo); 2351d62bc4baSyz147064 else if (state->gs_stats) 2352*e7801d59Ssowmini status = print_aggr_stats(state, link, &ginfo); 2353*e7801d59Ssowmini else { 2354*e7801d59Ssowmini status = print_aggr_info(state, link, &ginfo); 2355*e7801d59Ssowmini } 2356d62bc4baSyz147064 2357d62bc4baSyz147064 done: 2358d62bc4baSyz147064 free(ginfo.lg_ports); 2359d62bc4baSyz147064 return (status); 2360d62bc4baSyz147064 } 2361d62bc4baSyz147064 2362d62bc4baSyz147064 static int 2363d62bc4baSyz147064 show_aggr(datalink_id_t linkid, void *arg) 2364d62bc4baSyz147064 { 2365d62bc4baSyz147064 show_grp_state_t *state = arg; 2366d62bc4baSyz147064 dladm_status_t status; 2367d62bc4baSyz147064 2368*e7801d59Ssowmini status = print_aggr(state, linkid); 2369d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 2370d62bc4baSyz147064 goto done; 2371d62bc4baSyz147064 2372d62bc4baSyz147064 done: 2373d62bc4baSyz147064 state->gs_status = status; 2374d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 23757c478bd9Sstevel@tonic-gate } 23767c478bd9Sstevel@tonic-gate 2377*e7801d59Ssowmini static char * 2378*e7801d59Ssowmini print_dev(print_field_t *pf, void *arg) 23797c478bd9Sstevel@tonic-gate { 2380*e7801d59Ssowmini const char *dev = arg; 2381*e7801d59Ssowmini static char buf[DLADM_STRSIZE]; 23827c478bd9Sstevel@tonic-gate 2383*e7801d59Ssowmini switch (pf->pf_index) { 2384*e7801d59Ssowmini case DEV_LINK: 2385*e7801d59Ssowmini (void) snprintf(buf, sizeof (buf), "%s", dev); 23867c478bd9Sstevel@tonic-gate break; 2387*e7801d59Ssowmini case DEV_STATE: 2388*e7801d59Ssowmini (void) get_linkstate(dev, B_FALSE, buf); 2389*e7801d59Ssowmini break; 2390*e7801d59Ssowmini case DEV_SPEED: 2391*e7801d59Ssowmini (void) snprintf(buf, sizeof (buf), "%uMb", 2392*e7801d59Ssowmini (unsigned int)(get_ifspeed(dev, B_FALSE) / 1000000ull)); 2393*e7801d59Ssowmini break; 2394*e7801d59Ssowmini case DEV_DUPLEX: 2395*e7801d59Ssowmini (void) get_linkduplex(dev, B_FALSE, buf); 23967c478bd9Sstevel@tonic-gate break; 23977c478bd9Sstevel@tonic-gate default: 2398*e7801d59Ssowmini die("invalid index '%d'", pf->pf_index); 2399*e7801d59Ssowmini break; 24007c478bd9Sstevel@tonic-gate } 2401*e7801d59Ssowmini return (buf); 24027c478bd9Sstevel@tonic-gate } 24037c478bd9Sstevel@tonic-gate 2404d62bc4baSyz147064 static int 2405d62bc4baSyz147064 show_dev(const char *dev, void *arg) 24067c478bd9Sstevel@tonic-gate { 2407d62bc4baSyz147064 show_state_t *state = arg; 24087c478bd9Sstevel@tonic-gate 2409*e7801d59Ssowmini if (!state->ls_parseable && !state->ls_printheader) { 2410*e7801d59Ssowmini print_header(&state->ls_print); 2411*e7801d59Ssowmini state->ls_printheader = B_TRUE; 24127c478bd9Sstevel@tonic-gate } 24137c478bd9Sstevel@tonic-gate 2414*e7801d59Ssowmini dladm_print_output(&state->ls_print, state->ls_parseable, 2415*e7801d59Ssowmini print_dev, (void *)dev); 2416d62bc4baSyz147064 2417d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 2418d62bc4baSyz147064 } 2419d62bc4baSyz147064 2420*e7801d59Ssowmini static char * 2421*e7801d59Ssowmini print_dev_stats(print_field_t *pf, void *arg) 2422*e7801d59Ssowmini { 2423*e7801d59Ssowmini dev_args_t *dargs = arg; 2424*e7801d59Ssowmini pktsum_t *diff_stats = dargs->devs_psum; 2425*e7801d59Ssowmini static char buf[DLADM_STRSIZE]; 2426*e7801d59Ssowmini 2427*e7801d59Ssowmini switch (pf->pf_index) { 2428*e7801d59Ssowmini case DEVS_LINK: 2429*e7801d59Ssowmini (void) snprintf(buf, sizeof (buf), "%s", dargs->devs_link); 2430*e7801d59Ssowmini break; 2431*e7801d59Ssowmini case DEVS_IPKTS: 2432*e7801d59Ssowmini (void) snprintf(buf, sizeof (buf), "%llu", 2433*e7801d59Ssowmini diff_stats->ipackets); 2434*e7801d59Ssowmini break; 2435*e7801d59Ssowmini case DEVS_RBYTES: 2436*e7801d59Ssowmini (void) snprintf(buf, sizeof (buf), "%llu", 2437*e7801d59Ssowmini diff_stats->rbytes); 2438*e7801d59Ssowmini break; 2439*e7801d59Ssowmini case DEVS_IERRORS: 2440*e7801d59Ssowmini (void) snprintf(buf, sizeof (buf), "%u", 2441*e7801d59Ssowmini diff_stats->ierrors); 2442*e7801d59Ssowmini break; 2443*e7801d59Ssowmini case DEVS_OPKTS: 2444*e7801d59Ssowmini (void) snprintf(buf, sizeof (buf), "%llu", 2445*e7801d59Ssowmini diff_stats->opackets); 2446*e7801d59Ssowmini break; 2447*e7801d59Ssowmini case DEVS_OBYTES: 2448*e7801d59Ssowmini (void) snprintf(buf, sizeof (buf), "%llu", 2449*e7801d59Ssowmini diff_stats->obytes); 2450*e7801d59Ssowmini break; 2451*e7801d59Ssowmini case DEVS_OERRORS: 2452*e7801d59Ssowmini (void) snprintf(buf, sizeof (buf), "%u", 2453*e7801d59Ssowmini diff_stats->oerrors); 2454*e7801d59Ssowmini break; 2455*e7801d59Ssowmini default: 2456*e7801d59Ssowmini die("invalid input"); 2457*e7801d59Ssowmini break; 2458*e7801d59Ssowmini } 2459*e7801d59Ssowmini return (buf); 2460*e7801d59Ssowmini } 2461*e7801d59Ssowmini 2462d62bc4baSyz147064 static int 2463d62bc4baSyz147064 show_dev_stats(const char *dev, void *arg) 24647c478bd9Sstevel@tonic-gate { 2465d62bc4baSyz147064 show_state_t *state = arg; 24667c478bd9Sstevel@tonic-gate pktsum_t stats, diff_stats; 2467*e7801d59Ssowmini dev_args_t dargs; 24687c478bd9Sstevel@tonic-gate 2469d62bc4baSyz147064 if (state->ls_firstonly) { 2470d62bc4baSyz147064 if (state->ls_donefirst) 2471d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 2472d62bc4baSyz147064 state->ls_donefirst = B_TRUE; 24737c478bd9Sstevel@tonic-gate } else { 2474d62bc4baSyz147064 bzero(&state->ls_prevstats, sizeof (state->ls_prevstats)); 24757c478bd9Sstevel@tonic-gate } 24767c478bd9Sstevel@tonic-gate 2477ba2e4443Sseb get_mac_stats(dev, &stats); 2478d62bc4baSyz147064 stats_diff(&diff_stats, &stats, &state->ls_prevstats); 24797c478bd9Sstevel@tonic-gate 2480*e7801d59Ssowmini dargs.devs_link = (char *)dev; 2481*e7801d59Ssowmini dargs.devs_psum = &diff_stats; 2482*e7801d59Ssowmini dladm_print_output(&state->ls_print, state->ls_parseable, 2483*e7801d59Ssowmini print_dev_stats, &dargs); 24847c478bd9Sstevel@tonic-gate 2485d62bc4baSyz147064 state->ls_prevstats = stats; 2486d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 24877c478bd9Sstevel@tonic-gate } 24887c478bd9Sstevel@tonic-gate 24897c478bd9Sstevel@tonic-gate static void 24907c478bd9Sstevel@tonic-gate do_show_link(int argc, char *argv[]) 24917c478bd9Sstevel@tonic-gate { 24927c478bd9Sstevel@tonic-gate int option; 24937c478bd9Sstevel@tonic-gate boolean_t s_arg = B_FALSE; 24947c478bd9Sstevel@tonic-gate boolean_t i_arg = B_FALSE; 2495d62bc4baSyz147064 uint32_t flags = DLADM_OPT_ACTIVE; 2496d62bc4baSyz147064 boolean_t p_arg = B_FALSE; 2497d62bc4baSyz147064 datalink_id_t linkid = DATALINK_ALL_LINKID; 249833343a97Smeem int interval = 0; 2499d62bc4baSyz147064 show_state_t state; 2500d62bc4baSyz147064 dladm_status_t status; 2501*e7801d59Ssowmini boolean_t o_arg = B_FALSE; 2502*e7801d59Ssowmini char *fields_str = NULL; 2503*e7801d59Ssowmini print_field_t **fields; 2504*e7801d59Ssowmini uint_t nfields; 2505*e7801d59Ssowmini char *all_active_fields = "link,class,mtu,state,over"; 2506*e7801d59Ssowmini char *all_inactive_fields = "link,class,over"; 2507*e7801d59Ssowmini 2508*e7801d59Ssowmini bzero(&state, sizeof (state)); 25097c478bd9Sstevel@tonic-gate 25107c478bd9Sstevel@tonic-gate opterr = 0; 2511*e7801d59Ssowmini while ((option = getopt_long(argc, argv, ":pPsi:o:", 2512d62bc4baSyz147064 show_lopts, NULL)) != -1) { 25137c478bd9Sstevel@tonic-gate switch (option) { 25147c478bd9Sstevel@tonic-gate case 'p': 2515d62bc4baSyz147064 if (p_arg) 2516d62bc4baSyz147064 die_optdup(option); 2517d62bc4baSyz147064 2518d62bc4baSyz147064 p_arg = B_TRUE; 25197c478bd9Sstevel@tonic-gate break; 25207c478bd9Sstevel@tonic-gate case 's': 252133343a97Smeem if (s_arg) 252233343a97Smeem die_optdup(option); 25237c478bd9Sstevel@tonic-gate 25247c478bd9Sstevel@tonic-gate s_arg = B_TRUE; 25257c478bd9Sstevel@tonic-gate break; 2526d62bc4baSyz147064 case 'P': 2527d62bc4baSyz147064 if (flags != DLADM_OPT_ACTIVE) 2528d62bc4baSyz147064 die_optdup(option); 2529d62bc4baSyz147064 2530d62bc4baSyz147064 flags = DLADM_OPT_PERSIST; 2531d62bc4baSyz147064 break; 2532*e7801d59Ssowmini case 'o': 2533*e7801d59Ssowmini o_arg = B_TRUE; 2534*e7801d59Ssowmini fields_str = optarg; 2535*e7801d59Ssowmini break; 25367c478bd9Sstevel@tonic-gate case 'i': 253733343a97Smeem if (i_arg) 253833343a97Smeem die_optdup(option); 25397c478bd9Sstevel@tonic-gate 25407c478bd9Sstevel@tonic-gate i_arg = B_TRUE; 254133343a97Smeem if (!str2int(optarg, &interval) || interval == 0) 254233343a97Smeem die("invalid interval value '%s'", optarg); 25437c478bd9Sstevel@tonic-gate break; 25447c478bd9Sstevel@tonic-gate default: 254533343a97Smeem die_opterr(optopt, option); 254633343a97Smeem break; 25477c478bd9Sstevel@tonic-gate } 25487c478bd9Sstevel@tonic-gate } 25497c478bd9Sstevel@tonic-gate 255033343a97Smeem if (i_arg && !s_arg) 255133343a97Smeem die("the option -i can be used only with -s"); 25527c478bd9Sstevel@tonic-gate 2553d62bc4baSyz147064 if (s_arg && (p_arg || flags != DLADM_OPT_ACTIVE)) 2554d62bc4baSyz147064 die("the option -%c cannot be used with -s", p_arg ? 'p' : 'P'); 2555d62bc4baSyz147064 25567c478bd9Sstevel@tonic-gate /* get link name (optional last argument) */ 2557d62bc4baSyz147064 if (optind == (argc-1)) { 2558d62bc4baSyz147064 uint32_t f; 2559d62bc4baSyz147064 2560d62bc4baSyz147064 if ((status = dladm_name2info(argv[optind], &linkid, &f, 2561d62bc4baSyz147064 NULL, NULL)) != DLADM_STATUS_OK) { 2562d62bc4baSyz147064 die_dlerr(status, "link %s is not valid", argv[optind]); 2563d62bc4baSyz147064 } 2564d62bc4baSyz147064 2565d62bc4baSyz147064 if (!(f & flags)) { 2566d62bc4baSyz147064 die_dlerr(DLADM_STATUS_BADARG, "link %s is %s", 2567d62bc4baSyz147064 argv[optind], flags == DLADM_OPT_PERSIST ? 2568d62bc4baSyz147064 "a temporary link" : "temporarily removed"); 2569d62bc4baSyz147064 } 2570d62bc4baSyz147064 } else if (optind != argc) { 25717c478bd9Sstevel@tonic-gate usage(); 2572d62bc4baSyz147064 } 25737c478bd9Sstevel@tonic-gate 25747c478bd9Sstevel@tonic-gate if (s_arg) { 2575d62bc4baSyz147064 link_stats(linkid, interval); 25767c478bd9Sstevel@tonic-gate return; 25777c478bd9Sstevel@tonic-gate } 25787c478bd9Sstevel@tonic-gate 2579d62bc4baSyz147064 state.ls_parseable = p_arg; 2580d62bc4baSyz147064 state.ls_flags = flags; 2581d62bc4baSyz147064 state.ls_donefirst = B_FALSE; 2582*e7801d59Ssowmini 2583*e7801d59Ssowmini if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) { 2584*e7801d59Ssowmini if (state.ls_flags & DLADM_OPT_ACTIVE) 2585*e7801d59Ssowmini fields_str = all_active_fields; 2586*e7801d59Ssowmini else 2587*e7801d59Ssowmini fields_str = all_inactive_fields; 2588*e7801d59Ssowmini } 2589*e7801d59Ssowmini 2590*e7801d59Ssowmini 2591*e7801d59Ssowmini fields = parse_output_fields(fields_str, link_fields, DEV_LINK_FIELDS, 2592*e7801d59Ssowmini CMD_TYPE_ANY, &nfields); 2593*e7801d59Ssowmini 2594*e7801d59Ssowmini if (fields == NULL) { 2595*e7801d59Ssowmini die("invalid field(s) specified"); 2596*e7801d59Ssowmini return; 2597*e7801d59Ssowmini } 2598*e7801d59Ssowmini 2599*e7801d59Ssowmini state.ls_print.ps_fields = fields; 2600*e7801d59Ssowmini state.ls_print.ps_nfields = nfields; 2601*e7801d59Ssowmini 2602d62bc4baSyz147064 if (linkid == DATALINK_ALL_LINKID) { 2603d62bc4baSyz147064 (void) dladm_walk_datalink_id(show_link, &state, 2604d62bc4baSyz147064 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, flags); 2605210db224Sericheng } else { 2606d62bc4baSyz147064 (void) show_link(linkid, &state); 2607d62bc4baSyz147064 if (state.ls_status != DLADM_STATUS_OK) { 2608d62bc4baSyz147064 die_dlerr(state.ls_status, "failed to show link %s", 2609d62bc4baSyz147064 argv[optind]); 2610d62bc4baSyz147064 } 26117c478bd9Sstevel@tonic-gate } 2612210db224Sericheng } 26137c478bd9Sstevel@tonic-gate 26147c478bd9Sstevel@tonic-gate static void 26157c478bd9Sstevel@tonic-gate do_show_aggr(int argc, char *argv[]) 26167c478bd9Sstevel@tonic-gate { 26177c478bd9Sstevel@tonic-gate boolean_t L_arg = B_FALSE; 26187c478bd9Sstevel@tonic-gate boolean_t s_arg = B_FALSE; 26197c478bd9Sstevel@tonic-gate boolean_t i_arg = B_FALSE; 2620d62bc4baSyz147064 boolean_t p_arg = B_FALSE; 2621d62bc4baSyz147064 boolean_t x_arg = B_FALSE; 26227c478bd9Sstevel@tonic-gate show_grp_state_t state; 2623d62bc4baSyz147064 uint32_t flags = DLADM_OPT_ACTIVE; 2624d62bc4baSyz147064 datalink_id_t linkid = DATALINK_ALL_LINKID; 2625d62bc4baSyz147064 int option; 262633343a97Smeem int interval = 0; 2627d62bc4baSyz147064 int key; 2628d62bc4baSyz147064 dladm_status_t status; 2629*e7801d59Ssowmini boolean_t o_arg = B_FALSE; 2630*e7801d59Ssowmini char *fields_str = NULL; 2631*e7801d59Ssowmini print_field_t **fields; 2632*e7801d59Ssowmini uint_t nfields; 2633*e7801d59Ssowmini char *all_fields = 2634*e7801d59Ssowmini "link,policy,addrpolicy,lacpactivity,lacptimer,flags"; 2635*e7801d59Ssowmini char *all_lacp_fields = 2636*e7801d59Ssowmini "link,port,aggregatable,sync,coll,dist,defaulted,expired"; 2637*e7801d59Ssowmini char *all_stats_fields = 2638*e7801d59Ssowmini "link,port,ipackets,rbytes,opackets,obytes,ipktdist,opktdist"; 2639*e7801d59Ssowmini char *all_extended_fields = 2640*e7801d59Ssowmini "link,port,speed,duplex,state,address,portstate"; 2641*e7801d59Ssowmini print_field_t *pf; 2642*e7801d59Ssowmini int pfmax; 2643*e7801d59Ssowmini 2644*e7801d59Ssowmini bzero(&state, sizeof (state)); 26457c478bd9Sstevel@tonic-gate 26467c478bd9Sstevel@tonic-gate opterr = 0; 2647*e7801d59Ssowmini while ((option = getopt_long(argc, argv, ":LpPxsi:o:", 2648d62bc4baSyz147064 show_lopts, NULL)) != -1) { 26497c478bd9Sstevel@tonic-gate switch (option) { 26507c478bd9Sstevel@tonic-gate case 'L': 265133343a97Smeem if (L_arg) 265233343a97Smeem die_optdup(option); 26537c478bd9Sstevel@tonic-gate 26547c478bd9Sstevel@tonic-gate L_arg = B_TRUE; 26557c478bd9Sstevel@tonic-gate break; 26567c478bd9Sstevel@tonic-gate case 'p': 2657d62bc4baSyz147064 if (p_arg) 2658d62bc4baSyz147064 die_optdup(option); 2659d62bc4baSyz147064 2660d62bc4baSyz147064 p_arg = B_TRUE; 2661d62bc4baSyz147064 break; 2662d62bc4baSyz147064 case 'x': 2663d62bc4baSyz147064 if (x_arg) 2664d62bc4baSyz147064 die_optdup(option); 2665d62bc4baSyz147064 2666d62bc4baSyz147064 x_arg = B_TRUE; 2667d62bc4baSyz147064 break; 2668d62bc4baSyz147064 case 'P': 2669d62bc4baSyz147064 if (flags != DLADM_OPT_ACTIVE) 2670d62bc4baSyz147064 die_optdup(option); 2671d62bc4baSyz147064 2672d62bc4baSyz147064 flags = DLADM_OPT_PERSIST; 26737c478bd9Sstevel@tonic-gate break; 26747c478bd9Sstevel@tonic-gate case 's': 267533343a97Smeem if (s_arg) 267633343a97Smeem die_optdup(option); 26777c478bd9Sstevel@tonic-gate 26787c478bd9Sstevel@tonic-gate s_arg = B_TRUE; 26797c478bd9Sstevel@tonic-gate break; 2680*e7801d59Ssowmini case 'o': 2681*e7801d59Ssowmini o_arg = B_TRUE; 2682*e7801d59Ssowmini fields_str = optarg; 2683*e7801d59Ssowmini break; 26847c478bd9Sstevel@tonic-gate case 'i': 268533343a97Smeem if (i_arg) 268633343a97Smeem die_optdup(option); 26877c478bd9Sstevel@tonic-gate 26887c478bd9Sstevel@tonic-gate i_arg = B_TRUE; 268933343a97Smeem if (!str2int(optarg, &interval) || interval == 0) 269033343a97Smeem die("invalid interval value '%s'", optarg); 26917c478bd9Sstevel@tonic-gate break; 26927c478bd9Sstevel@tonic-gate default: 269333343a97Smeem die_opterr(optopt, option); 269433343a97Smeem break; 26957c478bd9Sstevel@tonic-gate } 26967c478bd9Sstevel@tonic-gate } 26977c478bd9Sstevel@tonic-gate 269833343a97Smeem if (i_arg && !s_arg) 269933343a97Smeem die("the option -i can be used only with -s"); 27007c478bd9Sstevel@tonic-gate 2701d62bc4baSyz147064 if (s_arg && (L_arg || p_arg || x_arg || flags != DLADM_OPT_ACTIVE)) { 2702d62bc4baSyz147064 die("the option -%c cannot be used with -s", 2703d62bc4baSyz147064 L_arg ? 'L' : (p_arg ? 'p' : (x_arg ? 'x' : 'P'))); 2704d62bc4baSyz147064 } 2705d62bc4baSyz147064 2706d62bc4baSyz147064 if (L_arg && flags != DLADM_OPT_ACTIVE) 2707d62bc4baSyz147064 die("the option -P cannot be used with -L"); 2708d62bc4baSyz147064 2709d62bc4baSyz147064 if (x_arg && (L_arg || flags != DLADM_OPT_ACTIVE)) 2710d62bc4baSyz147064 die("the option -%c cannot be used with -x", L_arg ? 'L' : 'P'); 2711d62bc4baSyz147064 2712d62bc4baSyz147064 /* get aggregation key or aggrname (optional last argument) */ 27137c478bd9Sstevel@tonic-gate if (optind == (argc-1)) { 2714d62bc4baSyz147064 if (!str2int(argv[optind], &key)) { 2715d62bc4baSyz147064 status = dladm_name2info(argv[optind], &linkid, NULL, 2716d62bc4baSyz147064 NULL, NULL); 2717d62bc4baSyz147064 } else { 2718d62bc4baSyz147064 status = dladm_key2linkid((uint16_t)key, 2719d62bc4baSyz147064 &linkid, DLADM_OPT_ACTIVE); 2720d62bc4baSyz147064 } 2721d62bc4baSyz147064 2722d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 2723d62bc4baSyz147064 die("non-existent aggregation '%s'", argv[optind]); 2724d62bc4baSyz147064 27257c478bd9Sstevel@tonic-gate } else if (optind != argc) { 27267c478bd9Sstevel@tonic-gate usage(); 27277c478bd9Sstevel@tonic-gate } 27287c478bd9Sstevel@tonic-gate 2729d62bc4baSyz147064 bzero(&state, sizeof (state)); 2730d62bc4baSyz147064 state.gs_lacp = L_arg; 2731d62bc4baSyz147064 state.gs_stats = s_arg; 2732d62bc4baSyz147064 state.gs_flags = flags; 2733d62bc4baSyz147064 state.gs_parseable = p_arg; 2734d62bc4baSyz147064 state.gs_extended = x_arg; 2735d62bc4baSyz147064 2736*e7801d59Ssowmini if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) { 2737*e7801d59Ssowmini if (state.gs_lacp) 2738*e7801d59Ssowmini fields_str = all_lacp_fields; 2739*e7801d59Ssowmini else if (state.gs_stats) 2740*e7801d59Ssowmini fields_str = all_stats_fields; 2741*e7801d59Ssowmini else if (state.gs_extended) 2742*e7801d59Ssowmini fields_str = all_extended_fields; 2743*e7801d59Ssowmini else 2744*e7801d59Ssowmini fields_str = all_fields; 2745*e7801d59Ssowmini } 2746*e7801d59Ssowmini 2747*e7801d59Ssowmini if (state.gs_lacp) { 2748*e7801d59Ssowmini pf = aggr_l_fields; 2749*e7801d59Ssowmini pfmax = AGGR_L_MAX_FIELDS; 2750*e7801d59Ssowmini } else if (state.gs_stats) { 2751*e7801d59Ssowmini pf = aggr_s_fields; 2752*e7801d59Ssowmini pfmax = AGGR_S_MAX_FIELDS; 2753*e7801d59Ssowmini } else if (state.gs_extended) { 2754*e7801d59Ssowmini pf = aggr_x_fields; 2755*e7801d59Ssowmini pfmax = AGGR_X_MAX_FIELDS; 2756*e7801d59Ssowmini } else { 2757*e7801d59Ssowmini pf = laggr_fields; 2758*e7801d59Ssowmini pfmax = LAGGR_MAX_FIELDS; 2759*e7801d59Ssowmini } 2760*e7801d59Ssowmini fields = parse_output_fields(fields_str, pf, pfmax, CMD_TYPE_ANY, 2761*e7801d59Ssowmini &nfields); 2762*e7801d59Ssowmini 2763*e7801d59Ssowmini if (fields == NULL) { 2764*e7801d59Ssowmini die("invalid field(s) specified"); 2765*e7801d59Ssowmini return; 2766*e7801d59Ssowmini } 2767*e7801d59Ssowmini 2768*e7801d59Ssowmini state.gs_print.ps_fields = fields; 2769*e7801d59Ssowmini state.gs_print.ps_nfields = nfields; 2770*e7801d59Ssowmini 27717c478bd9Sstevel@tonic-gate if (s_arg) { 2772d62bc4baSyz147064 aggr_stats(linkid, &state, interval); 27737c478bd9Sstevel@tonic-gate return; 27747c478bd9Sstevel@tonic-gate } 27757c478bd9Sstevel@tonic-gate 2776d62bc4baSyz147064 if (linkid == DATALINK_ALL_LINKID) { 2777d62bc4baSyz147064 (void) dladm_walk_datalink_id(show_aggr, &state, 2778d62bc4baSyz147064 DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, flags); 2779d62bc4baSyz147064 } else { 2780d62bc4baSyz147064 (void) show_aggr(linkid, &state); 2781d62bc4baSyz147064 if (state.gs_status != DLADM_STATUS_OK) { 2782d62bc4baSyz147064 die_dlerr(state.gs_status, "failed to show aggr %s", 2783d62bc4baSyz147064 argv[optind]); 2784d62bc4baSyz147064 } 2785d62bc4baSyz147064 } 27867c478bd9Sstevel@tonic-gate } 27877c478bd9Sstevel@tonic-gate 27887c478bd9Sstevel@tonic-gate static void 27897c478bd9Sstevel@tonic-gate do_show_dev(int argc, char *argv[]) 27907c478bd9Sstevel@tonic-gate { 27917c478bd9Sstevel@tonic-gate int option; 27927c478bd9Sstevel@tonic-gate char *dev = NULL; 27937c478bd9Sstevel@tonic-gate boolean_t s_arg = B_FALSE; 27947c478bd9Sstevel@tonic-gate boolean_t i_arg = B_FALSE; 2795*e7801d59Ssowmini boolean_t o_arg = B_FALSE; 2796d62bc4baSyz147064 boolean_t p_arg = B_FALSE; 2797d62bc4baSyz147064 datalink_id_t linkid; 279833343a97Smeem int interval = 0; 2799d62bc4baSyz147064 show_state_t state; 2800*e7801d59Ssowmini char *fields_str = NULL; 2801*e7801d59Ssowmini print_field_t **fields; 2802*e7801d59Ssowmini uint_t nfields; 2803*e7801d59Ssowmini char *all_fields = "link,state,speed,duplex"; 2804*e7801d59Ssowmini static char *allstat_fields = 2805*e7801d59Ssowmini "link,ipackets,rbytes,ierrors,opackets,obytes,oerrors"; 2806*e7801d59Ssowmini 2807*e7801d59Ssowmini bzero(&state, sizeof (state)); 2808*e7801d59Ssowmini fields_str = all_fields; 28097c478bd9Sstevel@tonic-gate 28107c478bd9Sstevel@tonic-gate opterr = 0; 2811*e7801d59Ssowmini while ((option = getopt_long(argc, argv, ":psi:o:", 2812d62bc4baSyz147064 show_lopts, NULL)) != -1) { 28137c478bd9Sstevel@tonic-gate switch (option) { 28147c478bd9Sstevel@tonic-gate case 'p': 2815d62bc4baSyz147064 if (p_arg) 2816d62bc4baSyz147064 die_optdup(option); 2817d62bc4baSyz147064 2818d62bc4baSyz147064 p_arg = B_TRUE; 28197c478bd9Sstevel@tonic-gate break; 28207c478bd9Sstevel@tonic-gate case 's': 282133343a97Smeem if (s_arg) 282233343a97Smeem die_optdup(option); 28237c478bd9Sstevel@tonic-gate 28247c478bd9Sstevel@tonic-gate s_arg = B_TRUE; 28257c478bd9Sstevel@tonic-gate break; 2826*e7801d59Ssowmini case 'o': 2827*e7801d59Ssowmini o_arg = B_TRUE; 2828*e7801d59Ssowmini fields_str = optarg; 2829*e7801d59Ssowmini break; 28307c478bd9Sstevel@tonic-gate case 'i': 283133343a97Smeem if (i_arg) 283233343a97Smeem die_optdup(option); 28337c478bd9Sstevel@tonic-gate 28347c478bd9Sstevel@tonic-gate i_arg = B_TRUE; 283533343a97Smeem if (!str2int(optarg, &interval) || interval == 0) 283633343a97Smeem die("invalid interval value '%s'", optarg); 28377c478bd9Sstevel@tonic-gate break; 28387c478bd9Sstevel@tonic-gate default: 283933343a97Smeem die_opterr(optopt, option); 284033343a97Smeem break; 28417c478bd9Sstevel@tonic-gate } 28427c478bd9Sstevel@tonic-gate } 28437c478bd9Sstevel@tonic-gate 284433343a97Smeem if (i_arg && !s_arg) 284533343a97Smeem die("the option -i can be used only with -s"); 28467c478bd9Sstevel@tonic-gate 2847*e7801d59Ssowmini if (o_arg && strcasecmp(fields_str, "all") == 0) { 2848*e7801d59Ssowmini if (!s_arg) 2849*e7801d59Ssowmini fields_str = all_fields; 2850*e7801d59Ssowmini else 2851*e7801d59Ssowmini fields_str = allstat_fields; 2852*e7801d59Ssowmini } 2853*e7801d59Ssowmini 2854*e7801d59Ssowmini if (!o_arg && s_arg) 2855*e7801d59Ssowmini fields_str = allstat_fields; 2856*e7801d59Ssowmini 2857d62bc4baSyz147064 if (s_arg && p_arg) 2858d62bc4baSyz147064 die("the option -s cannot be used with -p"); 2859d62bc4baSyz147064 28607c478bd9Sstevel@tonic-gate /* get dev name (optional last argument) */ 2861d62bc4baSyz147064 if (optind == (argc-1)) { 2862d62bc4baSyz147064 uint32_t flags; 2863d62bc4baSyz147064 28647c478bd9Sstevel@tonic-gate dev = argv[optind]; 2865d62bc4baSyz147064 2866d62bc4baSyz147064 if (dladm_dev2linkid(dev, &linkid) != DLADM_STATUS_OK) 2867d62bc4baSyz147064 die("invalid device %s", dev); 2868d62bc4baSyz147064 2869d62bc4baSyz147064 if ((dladm_datalink_id2info(linkid, &flags, NULL, NULL, 2870d62bc4baSyz147064 NULL, 0) != DLADM_STATUS_OK) || 2871d62bc4baSyz147064 !(flags & DLADM_OPT_ACTIVE)) { 2872d62bc4baSyz147064 die("device %s has been removed", dev); 2873d62bc4baSyz147064 } 2874d62bc4baSyz147064 } else if (optind != argc) { 28757c478bd9Sstevel@tonic-gate usage(); 2876cd93090eSericheng } 28777c478bd9Sstevel@tonic-gate 2878*e7801d59Ssowmini state.ls_parseable = p_arg; 2879*e7801d59Ssowmini state.ls_donefirst = B_FALSE; 2880*e7801d59Ssowmini 28817c478bd9Sstevel@tonic-gate if (s_arg) { 2882*e7801d59Ssowmini dev_stats(dev, interval, fields_str, &state); 28837c478bd9Sstevel@tonic-gate return; 28847c478bd9Sstevel@tonic-gate } 28857c478bd9Sstevel@tonic-gate 2886*e7801d59Ssowmini fields = parse_output_fields(fields_str, dev_fields, DEV_MAX_FIELDS, 2887*e7801d59Ssowmini CMD_TYPE_ANY, &nfields); 2888*e7801d59Ssowmini 2889*e7801d59Ssowmini if (fields == NULL) { 2890*e7801d59Ssowmini die("invalid field(s) specified"); 2891*e7801d59Ssowmini return; 2892*e7801d59Ssowmini } 2893*e7801d59Ssowmini 2894*e7801d59Ssowmini state.ls_print.ps_fields = fields; 2895*e7801d59Ssowmini state.ls_print.ps_nfields = nfields; 2896*e7801d59Ssowmini 2897d62bc4baSyz147064 if (dev == NULL) { 2898f595a68aSyz147064 (void) dladm_mac_walk(show_dev, &state); 2899d62bc4baSyz147064 } else { 2900d62bc4baSyz147064 (void) show_dev(dev, &state); 2901d62bc4baSyz147064 } 29027c478bd9Sstevel@tonic-gate } 29037c478bd9Sstevel@tonic-gate 2904d62bc4baSyz147064 2905d62bc4baSyz147064 static dladm_status_t 2906*e7801d59Ssowmini print_phys(show_state_t *state, datalink_id_t linkid, link_fields_buf_t *pattr) 2907d62bc4baSyz147064 { 2908d62bc4baSyz147064 char link[MAXLINKNAMELEN]; 2909d62bc4baSyz147064 dladm_phys_attr_t dpa; 2910d62bc4baSyz147064 uint32_t flags; 2911d62bc4baSyz147064 datalink_class_t class; 2912d62bc4baSyz147064 uint32_t media; 2913d62bc4baSyz147064 dladm_status_t status; 2914d62bc4baSyz147064 2915d62bc4baSyz147064 if ((status = dladm_datalink_id2info(linkid, &flags, &class, &media, 2916*e7801d59Ssowmini link, MAXLINKNAMELEN)) != DLADM_STATUS_OK) { 2917d62bc4baSyz147064 goto done; 2918d62bc4baSyz147064 } 2919d62bc4baSyz147064 2920d62bc4baSyz147064 if (class != DATALINK_CLASS_PHYS) { 2921d62bc4baSyz147064 status = DLADM_STATUS_BADARG; 2922d62bc4baSyz147064 goto done; 2923d62bc4baSyz147064 } 2924d62bc4baSyz147064 2925d62bc4baSyz147064 if (!(state->ls_flags & flags)) { 2926d62bc4baSyz147064 status = DLADM_STATUS_NOTFOUND; 2927d62bc4baSyz147064 goto done; 2928d62bc4baSyz147064 } 2929d62bc4baSyz147064 2930d62bc4baSyz147064 status = dladm_phys_info(linkid, &dpa, state->ls_flags); 2931d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 2932d62bc4baSyz147064 goto done; 2933d62bc4baSyz147064 2934*e7801d59Ssowmini (void) snprintf(pattr->link_phys_device, 2935*e7801d59Ssowmini sizeof (pattr->link_phys_device), "%s", dpa.dp_dev); 2936*e7801d59Ssowmini (void) dladm_media2str(media, pattr->link_phys_media); 2937d62bc4baSyz147064 if (state->ls_flags == DLADM_OPT_ACTIVE) { 2938d62bc4baSyz147064 boolean_t islink; 2939d62bc4baSyz147064 2940d62bc4baSyz147064 if (!dpa.dp_novanity) { 2941*e7801d59Ssowmini (void) strlcpy(pattr->link_name, link, 2942*e7801d59Ssowmini sizeof (pattr->link_name)); 2943d62bc4baSyz147064 islink = B_TRUE; 2944d62bc4baSyz147064 } else { 2945d62bc4baSyz147064 /* 2946d62bc4baSyz147064 * This is a physical link that does not have 2947d62bc4baSyz147064 * vanity naming support. 2948d62bc4baSyz147064 */ 2949*e7801d59Ssowmini (void) strlcpy(pattr->link_name, dpa.dp_dev, 2950*e7801d59Ssowmini sizeof (pattr->link_name)); 2951d62bc4baSyz147064 islink = B_FALSE; 2952d62bc4baSyz147064 } 2953d62bc4baSyz147064 2954*e7801d59Ssowmini (void) get_linkstate(pattr->link_name, islink, 2955*e7801d59Ssowmini pattr->link_phys_state); 2956*e7801d59Ssowmini (void) snprintf(pattr->link_phys_speed, 2957*e7801d59Ssowmini sizeof (pattr->link_phys_speed), "%u", 2958*e7801d59Ssowmini (uint_t)((get_ifspeed(pattr->link_name, 2959*e7801d59Ssowmini islink)) / 1000000ull)); 2960*e7801d59Ssowmini (void) get_linkduplex(pattr->link_name, islink, 2961*e7801d59Ssowmini pattr->link_phys_duplex); 2962d62bc4baSyz147064 } else { 2963*e7801d59Ssowmini (void) snprintf(pattr->link_name, sizeof (pattr->link_name), 2964*e7801d59Ssowmini "%s", link); 2965*e7801d59Ssowmini (void) snprintf(pattr->link_flags, sizeof (pattr->link_flags), 2966*e7801d59Ssowmini "%c----", flags & DLADM_OPT_ACTIVE ? '-' : 'r'); 2967d62bc4baSyz147064 } 2968d62bc4baSyz147064 2969d62bc4baSyz147064 done: 2970d62bc4baSyz147064 return (status); 2971d62bc4baSyz147064 } 2972d62bc4baSyz147064 2973d62bc4baSyz147064 static int 2974d62bc4baSyz147064 show_phys(datalink_id_t linkid, void *arg) 2975d62bc4baSyz147064 { 2976d62bc4baSyz147064 show_state_t *state = arg; 2977d62bc4baSyz147064 dladm_status_t status; 2978*e7801d59Ssowmini link_fields_buf_t pattr; 2979d62bc4baSyz147064 2980*e7801d59Ssowmini status = print_phys(state, linkid, &pattr); 2981d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 2982d62bc4baSyz147064 goto done; 2983*e7801d59Ssowmini 2984*e7801d59Ssowmini if (!state->ls_parseable && !state->ls_printheader) { 2985*e7801d59Ssowmini print_header(&state->ls_print); 2986*e7801d59Ssowmini state->ls_printheader = B_TRUE; 2987*e7801d59Ssowmini } 2988*e7801d59Ssowmini 2989*e7801d59Ssowmini dladm_print_output(&state->ls_print, state->ls_parseable, 2990*e7801d59Ssowmini dladm_print_field, (void *)&pattr); 2991d62bc4baSyz147064 2992d62bc4baSyz147064 done: 2993d62bc4baSyz147064 state->ls_status = status; 2994d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 2995d62bc4baSyz147064 } 2996d62bc4baSyz147064 2997d62bc4baSyz147064 2998d62bc4baSyz147064 /* 2999d62bc4baSyz147064 * Print the active topology information. 3000d62bc4baSyz147064 */ 3001d62bc4baSyz147064 static dladm_status_t 3002*e7801d59Ssowmini print_vlan(show_state_t *state, datalink_id_t linkid, link_fields_buf_t *l) 3003d62bc4baSyz147064 { 3004d62bc4baSyz147064 dladm_vlan_attr_t vinfo; 3005d62bc4baSyz147064 uint32_t flags; 3006d62bc4baSyz147064 dladm_status_t status; 3007d62bc4baSyz147064 3008*e7801d59Ssowmini if ((status = dladm_datalink_id2info(linkid, &flags, NULL, NULL, 3009*e7801d59Ssowmini l->link_name, sizeof (l->link_name))) != DLADM_STATUS_OK) { 3010d62bc4baSyz147064 goto done; 3011d62bc4baSyz147064 } 3012d62bc4baSyz147064 3013d62bc4baSyz147064 if (!(state->ls_flags & flags)) { 3014d62bc4baSyz147064 status = DLADM_STATUS_NOTFOUND; 3015d62bc4baSyz147064 goto done; 3016d62bc4baSyz147064 } 3017d62bc4baSyz147064 3018d62bc4baSyz147064 if ((status = dladm_vlan_info(linkid, &vinfo, state->ls_flags)) != 3019d62bc4baSyz147064 DLADM_STATUS_OK || (status = dladm_datalink_id2info( 3020*e7801d59Ssowmini vinfo.dv_linkid, NULL, NULL, NULL, l->link_over, 3021*e7801d59Ssowmini sizeof (l->link_over))) != DLADM_STATUS_OK) { 3022d62bc4baSyz147064 goto done; 3023d62bc4baSyz147064 } 3024d62bc4baSyz147064 3025*e7801d59Ssowmini (void) snprintf(l->link_vlan_vid, sizeof (l->link_vlan_vid), "%d", 3026*e7801d59Ssowmini vinfo.dv_vid); 3027*e7801d59Ssowmini (void) snprintf(l->link_flags, sizeof (l->link_flags), "%c%c---", 3028*e7801d59Ssowmini vinfo.dv_force ? 'f' : '-', vinfo.dv_implicit ? 'i' : '-'); 3029d62bc4baSyz147064 3030d62bc4baSyz147064 done: 3031d62bc4baSyz147064 return (status); 3032d62bc4baSyz147064 } 3033d62bc4baSyz147064 3034d62bc4baSyz147064 static int 3035d62bc4baSyz147064 show_vlan(datalink_id_t linkid, void *arg) 3036d62bc4baSyz147064 { 3037d62bc4baSyz147064 show_state_t *state = arg; 3038d62bc4baSyz147064 dladm_status_t status; 3039*e7801d59Ssowmini link_fields_buf_t lbuf; 3040d62bc4baSyz147064 3041*e7801d59Ssowmini status = print_vlan(state, linkid, &lbuf); 3042d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 3043d62bc4baSyz147064 goto done; 3044*e7801d59Ssowmini 3045*e7801d59Ssowmini if (!state->ls_parseable && !state->ls_printheader) { 3046*e7801d59Ssowmini print_header(&state->ls_print); 3047*e7801d59Ssowmini state->ls_printheader = B_TRUE; 3048*e7801d59Ssowmini } 3049*e7801d59Ssowmini 3050*e7801d59Ssowmini dladm_print_output(&state->ls_print, state->ls_parseable, 3051*e7801d59Ssowmini dladm_print_field, (void *)&lbuf); 3052d62bc4baSyz147064 3053d62bc4baSyz147064 done: 3054d62bc4baSyz147064 state->ls_status = status; 3055d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 3056d62bc4baSyz147064 } 3057d62bc4baSyz147064 3058d62bc4baSyz147064 static void 3059d62bc4baSyz147064 do_show_phys(int argc, char *argv[]) 3060d62bc4baSyz147064 { 3061d62bc4baSyz147064 int option; 3062d62bc4baSyz147064 uint32_t flags = DLADM_OPT_ACTIVE; 3063d62bc4baSyz147064 boolean_t p_arg = B_FALSE; 3064*e7801d59Ssowmini boolean_t o_arg = B_FALSE; 3065d62bc4baSyz147064 datalink_id_t linkid = DATALINK_ALL_LINKID; 3066d62bc4baSyz147064 show_state_t state; 3067d62bc4baSyz147064 dladm_status_t status; 3068*e7801d59Ssowmini char *fields_str = NULL; 3069*e7801d59Ssowmini print_field_t **fields; 3070*e7801d59Ssowmini uint_t nfields; 3071*e7801d59Ssowmini char *all_active_fields = 3072*e7801d59Ssowmini "link,media,state,speed,duplex,device"; 3073*e7801d59Ssowmini char *all_inactive_fields = 3074*e7801d59Ssowmini "link,device,media,flags"; 3075d62bc4baSyz147064 3076*e7801d59Ssowmini bzero(&state, sizeof (state)); 3077d62bc4baSyz147064 opterr = 0; 3078*e7801d59Ssowmini while ((option = getopt_long(argc, argv, ":pPo:", 3079d62bc4baSyz147064 show_lopts, NULL)) != -1) { 3080d62bc4baSyz147064 switch (option) { 3081d62bc4baSyz147064 case 'p': 3082d62bc4baSyz147064 if (p_arg) 3083d62bc4baSyz147064 die_optdup(option); 3084d62bc4baSyz147064 3085d62bc4baSyz147064 p_arg = B_TRUE; 3086d62bc4baSyz147064 break; 3087d62bc4baSyz147064 case 'P': 3088d62bc4baSyz147064 if (flags != DLADM_OPT_ACTIVE) 3089d62bc4baSyz147064 die_optdup(option); 3090d62bc4baSyz147064 3091d62bc4baSyz147064 flags = DLADM_OPT_PERSIST; 3092d62bc4baSyz147064 break; 3093*e7801d59Ssowmini case 'o': 3094*e7801d59Ssowmini o_arg = B_TRUE; 3095*e7801d59Ssowmini fields_str = optarg; 3096*e7801d59Ssowmini break; 3097d62bc4baSyz147064 default: 3098d62bc4baSyz147064 die_opterr(optopt, option); 3099d62bc4baSyz147064 break; 3100d62bc4baSyz147064 } 3101d62bc4baSyz147064 } 3102d62bc4baSyz147064 3103d62bc4baSyz147064 /* get link name (optional last argument) */ 3104d62bc4baSyz147064 if (optind == (argc-1)) { 3105d62bc4baSyz147064 if ((status = dladm_name2info(argv[optind], &linkid, NULL, 3106d62bc4baSyz147064 NULL, NULL)) != DLADM_STATUS_OK) { 3107d62bc4baSyz147064 die_dlerr(status, "link %s is not valid", argv[optind]); 3108d62bc4baSyz147064 } 3109d62bc4baSyz147064 } else if (optind != argc) { 3110d62bc4baSyz147064 usage(); 3111d62bc4baSyz147064 } 3112d62bc4baSyz147064 3113d62bc4baSyz147064 state.ls_parseable = p_arg; 3114d62bc4baSyz147064 state.ls_flags = flags; 3115d62bc4baSyz147064 state.ls_donefirst = B_FALSE; 3116d62bc4baSyz147064 3117*e7801d59Ssowmini if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) { 3118*e7801d59Ssowmini if (state.ls_flags & DLADM_OPT_ACTIVE) 3119*e7801d59Ssowmini fields_str = all_active_fields; 3120*e7801d59Ssowmini else 3121*e7801d59Ssowmini fields_str = all_inactive_fields; 3122*e7801d59Ssowmini } 3123*e7801d59Ssowmini 3124*e7801d59Ssowmini fields = parse_output_fields(fields_str, phys_fields, 3125*e7801d59Ssowmini PHYS_MAX_FIELDS, CMD_TYPE_ANY, &nfields); 3126*e7801d59Ssowmini 3127*e7801d59Ssowmini if (fields == NULL) { 3128*e7801d59Ssowmini die("invalid field(s) specified"); 3129*e7801d59Ssowmini return; 3130*e7801d59Ssowmini } 3131*e7801d59Ssowmini 3132*e7801d59Ssowmini state.ls_print.ps_fields = fields; 3133*e7801d59Ssowmini state.ls_print.ps_nfields = nfields; 3134*e7801d59Ssowmini 3135d62bc4baSyz147064 if (linkid == DATALINK_ALL_LINKID) { 3136d62bc4baSyz147064 (void) dladm_walk_datalink_id(show_phys, &state, 3137d62bc4baSyz147064 DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, flags); 3138d62bc4baSyz147064 } else { 3139d62bc4baSyz147064 (void) show_phys(linkid, &state); 3140d62bc4baSyz147064 if (state.ls_status != DLADM_STATUS_OK) { 3141d62bc4baSyz147064 die_dlerr(state.ls_status, 3142d62bc4baSyz147064 "failed to show physical link %s", argv[optind]); 3143d62bc4baSyz147064 } 3144d62bc4baSyz147064 } 3145d62bc4baSyz147064 } 3146d62bc4baSyz147064 3147d62bc4baSyz147064 static void 3148d62bc4baSyz147064 do_show_vlan(int argc, char *argv[]) 3149d62bc4baSyz147064 { 3150d62bc4baSyz147064 int option; 3151d62bc4baSyz147064 uint32_t flags = DLADM_OPT_ACTIVE; 3152d62bc4baSyz147064 boolean_t p_arg = B_FALSE; 3153d62bc4baSyz147064 datalink_id_t linkid = DATALINK_ALL_LINKID; 3154d62bc4baSyz147064 show_state_t state; 3155d62bc4baSyz147064 dladm_status_t status; 3156*e7801d59Ssowmini boolean_t o_arg = B_FALSE; 3157*e7801d59Ssowmini char *fields_str = NULL; 3158*e7801d59Ssowmini print_field_t **fields; 3159*e7801d59Ssowmini uint_t nfields; 3160*e7801d59Ssowmini char *all_fields = "link,vid,over,flags"; 3161*e7801d59Ssowmini 3162*e7801d59Ssowmini bzero(&state, sizeof (state)); 3163d62bc4baSyz147064 3164d62bc4baSyz147064 opterr = 0; 3165*e7801d59Ssowmini while ((option = getopt_long(argc, argv, ":pPo:", 3166d62bc4baSyz147064 show_lopts, NULL)) != -1) { 3167d62bc4baSyz147064 switch (option) { 3168d62bc4baSyz147064 case 'p': 3169d62bc4baSyz147064 if (p_arg) 3170d62bc4baSyz147064 die_optdup(option); 3171d62bc4baSyz147064 3172d62bc4baSyz147064 p_arg = B_TRUE; 3173d62bc4baSyz147064 break; 3174d62bc4baSyz147064 case 'P': 3175d62bc4baSyz147064 if (flags != DLADM_OPT_ACTIVE) 3176d62bc4baSyz147064 die_optdup(option); 3177d62bc4baSyz147064 3178d62bc4baSyz147064 flags = DLADM_OPT_PERSIST; 3179d62bc4baSyz147064 break; 3180*e7801d59Ssowmini case 'o': 3181*e7801d59Ssowmini o_arg = B_TRUE; 3182*e7801d59Ssowmini fields_str = optarg; 3183*e7801d59Ssowmini break; 3184d62bc4baSyz147064 default: 3185d62bc4baSyz147064 die_opterr(optopt, option); 3186d62bc4baSyz147064 break; 3187d62bc4baSyz147064 } 3188d62bc4baSyz147064 } 3189d62bc4baSyz147064 3190d62bc4baSyz147064 /* get link name (optional last argument) */ 3191d62bc4baSyz147064 if (optind == (argc-1)) { 3192d62bc4baSyz147064 if ((status = dladm_name2info(argv[optind], &linkid, NULL, 3193d62bc4baSyz147064 NULL, NULL)) != DLADM_STATUS_OK) { 3194d62bc4baSyz147064 die_dlerr(status, "link %s is not valid", argv[optind]); 3195d62bc4baSyz147064 } 3196d62bc4baSyz147064 } else if (optind != argc) { 3197d62bc4baSyz147064 usage(); 3198d62bc4baSyz147064 } 3199d62bc4baSyz147064 3200d62bc4baSyz147064 state.ls_parseable = p_arg; 3201d62bc4baSyz147064 state.ls_flags = flags; 3202d62bc4baSyz147064 state.ls_donefirst = B_FALSE; 3203d62bc4baSyz147064 3204*e7801d59Ssowmini if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) 3205*e7801d59Ssowmini fields_str = all_fields; 3206*e7801d59Ssowmini 3207*e7801d59Ssowmini fields = parse_output_fields(fields_str, vlan_fields, VLAN_MAX_FIELDS, 3208*e7801d59Ssowmini CMD_TYPE_ANY, &nfields); 3209*e7801d59Ssowmini 3210*e7801d59Ssowmini if (fields == NULL) { 3211*e7801d59Ssowmini die("invalid field(s) specified"); 3212*e7801d59Ssowmini return; 3213*e7801d59Ssowmini } 3214*e7801d59Ssowmini state.ls_print.ps_fields = fields; 3215*e7801d59Ssowmini state.ls_print.ps_nfields = nfields; 3216*e7801d59Ssowmini 3217d62bc4baSyz147064 if (linkid == DATALINK_ALL_LINKID) { 3218d62bc4baSyz147064 (void) dladm_walk_datalink_id(show_vlan, &state, 3219d62bc4baSyz147064 DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, flags); 3220d62bc4baSyz147064 } else { 3221d62bc4baSyz147064 (void) show_vlan(linkid, &state); 3222d62bc4baSyz147064 if (state.ls_status != DLADM_STATUS_OK) { 3223d62bc4baSyz147064 die_dlerr(state.ls_status, "failed to show vlan %s", 3224d62bc4baSyz147064 argv[optind]); 3225d62bc4baSyz147064 } 3226d62bc4baSyz147064 } 3227d62bc4baSyz147064 } 3228d62bc4baSyz147064 3229d62bc4baSyz147064 static void 3230d62bc4baSyz147064 link_stats(datalink_id_t linkid, uint_t interval) 3231d62bc4baSyz147064 { 3232d62bc4baSyz147064 show_state_t state; 323333343a97Smeem 32347c478bd9Sstevel@tonic-gate bzero(&state, sizeof (state)); 32357c478bd9Sstevel@tonic-gate 32367c478bd9Sstevel@tonic-gate /* 32377c478bd9Sstevel@tonic-gate * If an interval is specified, continuously show the stats 32387c478bd9Sstevel@tonic-gate * only for the first MAC port. 32397c478bd9Sstevel@tonic-gate */ 32407c478bd9Sstevel@tonic-gate state.ls_firstonly = (interval != 0); 32417c478bd9Sstevel@tonic-gate 32427c478bd9Sstevel@tonic-gate for (;;) { 3243d62bc4baSyz147064 (void) printf("%-12s%-10s%-12s%-8s%-10s%-12s%-8s\n", 3244d62bc4baSyz147064 "LINK", "IPACKETS", "RBYTES", "IERRORS", "OPACKETS", 3245d62bc4baSyz147064 "OBYTES", "OERRORS"); 32467c478bd9Sstevel@tonic-gate 32477c478bd9Sstevel@tonic-gate state.ls_donefirst = B_FALSE; 3248d62bc4baSyz147064 if (linkid == DATALINK_ALL_LINKID) { 3249d62bc4baSyz147064 (void) dladm_walk_datalink_id(show_link_stats, &state, 3250d62bc4baSyz147064 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, 3251d62bc4baSyz147064 DLADM_OPT_ACTIVE); 3252d62bc4baSyz147064 } else { 3253d62bc4baSyz147064 (void) show_link_stats(linkid, &state); 3254d62bc4baSyz147064 } 32557c478bd9Sstevel@tonic-gate 32567c478bd9Sstevel@tonic-gate if (interval == 0) 32577c478bd9Sstevel@tonic-gate break; 32587c478bd9Sstevel@tonic-gate 32597c478bd9Sstevel@tonic-gate (void) sleep(interval); 32607c478bd9Sstevel@tonic-gate } 32617c478bd9Sstevel@tonic-gate } 32627c478bd9Sstevel@tonic-gate 32637c478bd9Sstevel@tonic-gate static void 3264d62bc4baSyz147064 aggr_stats(datalink_id_t linkid, show_grp_state_t *state, uint_t interval) 32657c478bd9Sstevel@tonic-gate { 32667c478bd9Sstevel@tonic-gate /* 32677c478bd9Sstevel@tonic-gate * If an interval is specified, continuously show the stats 32687c478bd9Sstevel@tonic-gate * only for the first group. 32697c478bd9Sstevel@tonic-gate */ 3270d62bc4baSyz147064 state->gs_firstonly = (interval != 0); 32717c478bd9Sstevel@tonic-gate 32727c478bd9Sstevel@tonic-gate for (;;) { 3273d62bc4baSyz147064 state->gs_donefirst = B_FALSE; 3274d62bc4baSyz147064 if (linkid == DATALINK_ALL_LINKID) 3275d62bc4baSyz147064 (void) dladm_walk_datalink_id(show_aggr, state, 3276d62bc4baSyz147064 DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, 3277d62bc4baSyz147064 DLADM_OPT_ACTIVE); 3278d62bc4baSyz147064 else 3279d62bc4baSyz147064 (void) show_aggr(linkid, state); 32807c478bd9Sstevel@tonic-gate 32817c478bd9Sstevel@tonic-gate if (interval == 0) 32827c478bd9Sstevel@tonic-gate break; 32837c478bd9Sstevel@tonic-gate 32847c478bd9Sstevel@tonic-gate (void) sleep(interval); 32857c478bd9Sstevel@tonic-gate } 32867c478bd9Sstevel@tonic-gate } 32877c478bd9Sstevel@tonic-gate 32887c478bd9Sstevel@tonic-gate static void 3289*e7801d59Ssowmini dev_stats(const char *dev, uint32_t interval, char *fields_str, 3290*e7801d59Ssowmini show_state_t *state) 32917c478bd9Sstevel@tonic-gate { 3292*e7801d59Ssowmini print_field_t **fields; 3293*e7801d59Ssowmini uint_t nfields; 32947c478bd9Sstevel@tonic-gate 3295*e7801d59Ssowmini fields = parse_output_fields(fields_str, devs_fields, DEVS_MAX_FIELDS, 3296*e7801d59Ssowmini CMD_TYPE_ANY, &nfields); 3297*e7801d59Ssowmini 3298*e7801d59Ssowmini if (fields == NULL) { 3299*e7801d59Ssowmini die("invalid field(s) specified"); 3300*e7801d59Ssowmini return; 3301*e7801d59Ssowmini } 3302*e7801d59Ssowmini 3303*e7801d59Ssowmini state->ls_print.ps_fields = fields; 3304*e7801d59Ssowmini state->ls_print.ps_nfields = nfields; 3305*e7801d59Ssowmini 33067c478bd9Sstevel@tonic-gate 33077c478bd9Sstevel@tonic-gate /* 33087c478bd9Sstevel@tonic-gate * If an interval is specified, continuously show the stats 33097c478bd9Sstevel@tonic-gate * only for the first MAC port. 33107c478bd9Sstevel@tonic-gate */ 3311*e7801d59Ssowmini state->ls_firstonly = (interval != 0); 33127c478bd9Sstevel@tonic-gate 33137c478bd9Sstevel@tonic-gate for (;;) { 33147c478bd9Sstevel@tonic-gate 3315*e7801d59Ssowmini if (!state->ls_parseable) 3316*e7801d59Ssowmini print_header(&state->ls_print); 3317*e7801d59Ssowmini state->ls_donefirst = B_FALSE; 33187c478bd9Sstevel@tonic-gate 3319210db224Sericheng if (dev == NULL) 3320*e7801d59Ssowmini (void) dladm_mac_walk(show_dev_stats, state); 3321210db224Sericheng else 3322*e7801d59Ssowmini (void) show_dev_stats(dev, state); 33237c478bd9Sstevel@tonic-gate 33247c478bd9Sstevel@tonic-gate if (interval == 0) 33257c478bd9Sstevel@tonic-gate break; 33267c478bd9Sstevel@tonic-gate 33277c478bd9Sstevel@tonic-gate (void) sleep(interval); 33287c478bd9Sstevel@tonic-gate } 3329d62bc4baSyz147064 3330*e7801d59Ssowmini if (dev != NULL && state->ls_status != DLADM_STATUS_OK) 3331*e7801d59Ssowmini die_dlerr(state->ls_status, "cannot show device '%s'", dev); 33327c478bd9Sstevel@tonic-gate } 33337c478bd9Sstevel@tonic-gate 33347c478bd9Sstevel@tonic-gate /* accumulate stats (s1 += (s2 - s3)) */ 33357c478bd9Sstevel@tonic-gate static void 33367c478bd9Sstevel@tonic-gate stats_total(pktsum_t *s1, pktsum_t *s2, pktsum_t *s3) 33377c478bd9Sstevel@tonic-gate { 33387c478bd9Sstevel@tonic-gate s1->ipackets += (s2->ipackets - s3->ipackets); 33397c478bd9Sstevel@tonic-gate s1->opackets += (s2->opackets - s3->opackets); 33407c478bd9Sstevel@tonic-gate s1->rbytes += (s2->rbytes - s3->rbytes); 33417c478bd9Sstevel@tonic-gate s1->obytes += (s2->obytes - s3->obytes); 33427c478bd9Sstevel@tonic-gate s1->ierrors += (s2->ierrors - s3->ierrors); 33437c478bd9Sstevel@tonic-gate s1->oerrors += (s2->oerrors - s3->oerrors); 33447c478bd9Sstevel@tonic-gate } 33457c478bd9Sstevel@tonic-gate 33467c478bd9Sstevel@tonic-gate /* compute stats differences (s1 = s2 - s3) */ 33477c478bd9Sstevel@tonic-gate static void 33487c478bd9Sstevel@tonic-gate stats_diff(pktsum_t *s1, pktsum_t *s2, pktsum_t *s3) 33497c478bd9Sstevel@tonic-gate { 33507c478bd9Sstevel@tonic-gate s1->ipackets = s2->ipackets - s3->ipackets; 33517c478bd9Sstevel@tonic-gate s1->opackets = s2->opackets - s3->opackets; 33527c478bd9Sstevel@tonic-gate s1->rbytes = s2->rbytes - s3->rbytes; 33537c478bd9Sstevel@tonic-gate s1->obytes = s2->obytes - s3->obytes; 33547c478bd9Sstevel@tonic-gate s1->ierrors = s2->ierrors - s3->ierrors; 33557c478bd9Sstevel@tonic-gate s1->oerrors = s2->oerrors - s3->oerrors; 33567c478bd9Sstevel@tonic-gate } 33577c478bd9Sstevel@tonic-gate 33587c478bd9Sstevel@tonic-gate static void 3359d62bc4baSyz147064 get_stats(char *module, int instance, const char *name, pktsum_t *stats) 33607c478bd9Sstevel@tonic-gate { 33617c478bd9Sstevel@tonic-gate kstat_ctl_t *kcp; 33627c478bd9Sstevel@tonic-gate kstat_t *ksp; 33637c478bd9Sstevel@tonic-gate 33647c478bd9Sstevel@tonic-gate if ((kcp = kstat_open()) == NULL) { 336533343a97Smeem warn("kstat open operation failed"); 33667c478bd9Sstevel@tonic-gate return; 33677c478bd9Sstevel@tonic-gate } 33687c478bd9Sstevel@tonic-gate 3369d62bc4baSyz147064 if ((ksp = kstat_lookup(kcp, module, instance, (char *)name)) == NULL) { 33707c478bd9Sstevel@tonic-gate /* 33717c478bd9Sstevel@tonic-gate * The kstat query could fail if the underlying MAC 33727c478bd9Sstevel@tonic-gate * driver was already detached. 33737c478bd9Sstevel@tonic-gate */ 33747c478bd9Sstevel@tonic-gate (void) kstat_close(kcp); 33757c478bd9Sstevel@tonic-gate return; 33767c478bd9Sstevel@tonic-gate } 33777c478bd9Sstevel@tonic-gate 33787c478bd9Sstevel@tonic-gate if (kstat_read(kcp, ksp, NULL) == -1) 33797c478bd9Sstevel@tonic-gate goto bail; 33807c478bd9Sstevel@tonic-gate 3381*e7801d59Ssowmini if (dladm_kstat_value(ksp, "ipackets64", KSTAT_DATA_UINT64, 33827c478bd9Sstevel@tonic-gate &stats->ipackets) < 0) 33837c478bd9Sstevel@tonic-gate goto bail; 33847c478bd9Sstevel@tonic-gate 3385*e7801d59Ssowmini if (dladm_kstat_value(ksp, "opackets64", KSTAT_DATA_UINT64, 33867c478bd9Sstevel@tonic-gate &stats->opackets) < 0) 33877c478bd9Sstevel@tonic-gate goto bail; 33887c478bd9Sstevel@tonic-gate 3389*e7801d59Ssowmini if (dladm_kstat_value(ksp, "rbytes64", KSTAT_DATA_UINT64, 33907c478bd9Sstevel@tonic-gate &stats->rbytes) < 0) 33917c478bd9Sstevel@tonic-gate goto bail; 33927c478bd9Sstevel@tonic-gate 3393*e7801d59Ssowmini if (dladm_kstat_value(ksp, "obytes64", KSTAT_DATA_UINT64, 33947c478bd9Sstevel@tonic-gate &stats->obytes) < 0) 33957c478bd9Sstevel@tonic-gate goto bail; 33967c478bd9Sstevel@tonic-gate 3397*e7801d59Ssowmini if (dladm_kstat_value(ksp, "ierrors", KSTAT_DATA_UINT32, 33987c478bd9Sstevel@tonic-gate &stats->ierrors) < 0) 33997c478bd9Sstevel@tonic-gate goto bail; 34007c478bd9Sstevel@tonic-gate 3401*e7801d59Ssowmini if (dladm_kstat_value(ksp, "oerrors", KSTAT_DATA_UINT32, 34027c478bd9Sstevel@tonic-gate &stats->oerrors) < 0) 34037c478bd9Sstevel@tonic-gate goto bail; 34047c478bd9Sstevel@tonic-gate 3405d62bc4baSyz147064 bail: 34067c478bd9Sstevel@tonic-gate (void) kstat_close(kcp); 34077c478bd9Sstevel@tonic-gate return; 34087c478bd9Sstevel@tonic-gate 34097c478bd9Sstevel@tonic-gate } 34107c478bd9Sstevel@tonic-gate 34117c478bd9Sstevel@tonic-gate static void 3412ba2e4443Sseb get_mac_stats(const char *dev, pktsum_t *stats) 34137c478bd9Sstevel@tonic-gate { 3414c7e4935fSss150715 char module[DLPI_LINKNAME_MAX]; 3415c7e4935fSss150715 uint_t instance; 34167c478bd9Sstevel@tonic-gate 3417d62bc4baSyz147064 bzero(stats, sizeof (*stats)); 3418c7e4935fSss150715 if (dlpi_parselink(dev, module, &instance) != DLPI_SUCCESS) 3419ba2e4443Sseb return; 3420d62bc4baSyz147064 3421ba2e4443Sseb get_stats(module, instance, "mac", stats); 34227c478bd9Sstevel@tonic-gate } 34237c478bd9Sstevel@tonic-gate 34247c478bd9Sstevel@tonic-gate static void 34257c478bd9Sstevel@tonic-gate get_link_stats(const char *link, pktsum_t *stats) 34267c478bd9Sstevel@tonic-gate { 34277c478bd9Sstevel@tonic-gate bzero(stats, sizeof (*stats)); 3428d62bc4baSyz147064 get_stats("link", 0, link, stats); 34297c478bd9Sstevel@tonic-gate } 34307c478bd9Sstevel@tonic-gate 3431ba2e4443Sseb static int 3432d62bc4baSyz147064 query_kstat(char *module, int instance, const char *name, const char *stat, 3433d62bc4baSyz147064 uint8_t type, void *val) 34347c478bd9Sstevel@tonic-gate { 34357c478bd9Sstevel@tonic-gate kstat_ctl_t *kcp; 34367c478bd9Sstevel@tonic-gate kstat_t *ksp; 34377c478bd9Sstevel@tonic-gate 34387c478bd9Sstevel@tonic-gate if ((kcp = kstat_open()) == NULL) { 343933343a97Smeem warn("kstat open operation failed"); 3440ba2e4443Sseb return (-1); 34417c478bd9Sstevel@tonic-gate } 34427c478bd9Sstevel@tonic-gate 3443d62bc4baSyz147064 if ((ksp = kstat_lookup(kcp, module, instance, (char *)name)) == NULL) { 34447c478bd9Sstevel@tonic-gate /* 34457c478bd9Sstevel@tonic-gate * The kstat query could fail if the underlying MAC 34467c478bd9Sstevel@tonic-gate * driver was already detached. 34477c478bd9Sstevel@tonic-gate */ 34487c478bd9Sstevel@tonic-gate goto bail; 34497c478bd9Sstevel@tonic-gate } 34507c478bd9Sstevel@tonic-gate 34517c478bd9Sstevel@tonic-gate if (kstat_read(kcp, ksp, NULL) == -1) { 345233343a97Smeem warn("kstat read failed"); 34537c478bd9Sstevel@tonic-gate goto bail; 34547c478bd9Sstevel@tonic-gate } 34557c478bd9Sstevel@tonic-gate 3456*e7801d59Ssowmini if (dladm_kstat_value(ksp, stat, type, val) < 0) 34577c478bd9Sstevel@tonic-gate goto bail; 3458ba2e4443Sseb 3459ba2e4443Sseb (void) kstat_close(kcp); 3460ba2e4443Sseb return (0); 34617c478bd9Sstevel@tonic-gate 34627c478bd9Sstevel@tonic-gate bail: 34637c478bd9Sstevel@tonic-gate (void) kstat_close(kcp); 3464ba2e4443Sseb return (-1); 3465ba2e4443Sseb } 3466ba2e4443Sseb 3467d62bc4baSyz147064 static int 3468d62bc4baSyz147064 get_one_kstat(const char *name, const char *stat, uint8_t type, 3469d62bc4baSyz147064 void *val, boolean_t islink) 3470d62bc4baSyz147064 { 3471d62bc4baSyz147064 char module[DLPI_LINKNAME_MAX]; 3472d62bc4baSyz147064 uint_t instance; 3473d62bc4baSyz147064 3474d62bc4baSyz147064 if (islink) { 3475d62bc4baSyz147064 return (query_kstat("link", 0, name, stat, type, val)); 3476d62bc4baSyz147064 } else { 3477d62bc4baSyz147064 if (dlpi_parselink(name, module, &instance) != DLPI_SUCCESS) 3478d62bc4baSyz147064 return (-1); 3479d62bc4baSyz147064 3480d62bc4baSyz147064 return (query_kstat(module, instance, "mac", stat, type, val)); 3481d62bc4baSyz147064 } 3482d62bc4baSyz147064 } 3483d62bc4baSyz147064 3484ba2e4443Sseb static uint64_t 3485d62bc4baSyz147064 get_ifspeed(const char *name, boolean_t islink) 3486ba2e4443Sseb { 3487ba2e4443Sseb uint64_t ifspeed = 0; 3488ba2e4443Sseb 3489d62bc4baSyz147064 (void) get_one_kstat(name, "ifspeed", KSTAT_DATA_UINT64, 3490d62bc4baSyz147064 &ifspeed, islink); 3491d62bc4baSyz147064 34927c478bd9Sstevel@tonic-gate return (ifspeed); 34937c478bd9Sstevel@tonic-gate } 34947c478bd9Sstevel@tonic-gate 3495f595a68aSyz147064 static const char * 3496d62bc4baSyz147064 get_linkstate(const char *name, boolean_t islink, char *buf) 34977c478bd9Sstevel@tonic-gate { 3498d62bc4baSyz147064 link_state_t linkstate; 34997c478bd9Sstevel@tonic-gate 3500d62bc4baSyz147064 if (get_one_kstat(name, "link_state", KSTAT_DATA_UINT32, 3501d62bc4baSyz147064 &linkstate, islink) != 0) { 35023a62633bSyz147064 (void) strlcpy(buf, "unknown", DLADM_STRSIZE); 35033a62633bSyz147064 return (buf); 35047c478bd9Sstevel@tonic-gate } 3505d62bc4baSyz147064 return (dladm_linkstate2str(linkstate, buf)); 35067c478bd9Sstevel@tonic-gate } 35077c478bd9Sstevel@tonic-gate 3508f595a68aSyz147064 static const char * 3509d62bc4baSyz147064 get_linkduplex(const char *name, boolean_t islink, char *buf) 35107c478bd9Sstevel@tonic-gate { 3511d62bc4baSyz147064 link_duplex_t linkduplex; 35127c478bd9Sstevel@tonic-gate 3513d62bc4baSyz147064 if (get_one_kstat(name, "link_duplex", KSTAT_DATA_UINT32, 3514d62bc4baSyz147064 &linkduplex, islink) != 0) { 35153a62633bSyz147064 (void) strlcpy(buf, "unknown", DLADM_STRSIZE); 35163a62633bSyz147064 return (buf); 35177c478bd9Sstevel@tonic-gate } 35187c478bd9Sstevel@tonic-gate 3519d62bc4baSyz147064 return (dladm_linkduplex2str(linkduplex, buf)); 35207c478bd9Sstevel@tonic-gate } 35210ba2cbe9Sxc151355 35220ba2cbe9Sxc151355 typedef struct { 35230ba2cbe9Sxc151355 char *s_buf; 35240ba2cbe9Sxc151355 char **s_fields; /* array of pointer to the fields in s_buf */ 35250ba2cbe9Sxc151355 uint_t s_nfields; /* the number of fields in s_buf */ 35260ba2cbe9Sxc151355 } split_t; 35270ba2cbe9Sxc151355 35280ba2cbe9Sxc151355 /* 35290ba2cbe9Sxc151355 * Free the split_t structure pointed to by `sp'. 35300ba2cbe9Sxc151355 */ 35310ba2cbe9Sxc151355 static void 35320ba2cbe9Sxc151355 splitfree(split_t *sp) 35330ba2cbe9Sxc151355 { 35340ba2cbe9Sxc151355 free(sp->s_buf); 35350ba2cbe9Sxc151355 free(sp->s_fields); 35360ba2cbe9Sxc151355 free(sp); 35370ba2cbe9Sxc151355 } 35380ba2cbe9Sxc151355 35390ba2cbe9Sxc151355 /* 35400ba2cbe9Sxc151355 * Split `str' into at most `maxfields' fields, each field at most `maxlen' in 35410ba2cbe9Sxc151355 * length. Return a pointer to a split_t containing the split fields, or NULL 35420ba2cbe9Sxc151355 * on failure. 35430ba2cbe9Sxc151355 */ 35440ba2cbe9Sxc151355 static split_t * 35450ba2cbe9Sxc151355 split(const char *str, uint_t maxfields, uint_t maxlen) 35460ba2cbe9Sxc151355 { 35470ba2cbe9Sxc151355 char *field, *token, *lasts = NULL; 35480ba2cbe9Sxc151355 split_t *sp; 35490ba2cbe9Sxc151355 35500ba2cbe9Sxc151355 if (*str == '\0' || maxfields == 0 || maxlen == 0) 35510ba2cbe9Sxc151355 return (NULL); 35520ba2cbe9Sxc151355 35530ba2cbe9Sxc151355 sp = calloc(sizeof (split_t), 1); 35540ba2cbe9Sxc151355 if (sp == NULL) 35550ba2cbe9Sxc151355 return (NULL); 35560ba2cbe9Sxc151355 35570ba2cbe9Sxc151355 sp->s_buf = strdup(str); 35580ba2cbe9Sxc151355 sp->s_fields = malloc(sizeof (char *) * maxfields); 35590ba2cbe9Sxc151355 if (sp->s_buf == NULL || sp->s_fields == NULL) 35600ba2cbe9Sxc151355 goto fail; 35610ba2cbe9Sxc151355 35620ba2cbe9Sxc151355 token = sp->s_buf; 35630ba2cbe9Sxc151355 while ((field = strtok_r(token, ",", &lasts)) != NULL) { 35640ba2cbe9Sxc151355 if (sp->s_nfields == maxfields || strlen(field) > maxlen) 35650ba2cbe9Sxc151355 goto fail; 35660ba2cbe9Sxc151355 token = NULL; 35670ba2cbe9Sxc151355 sp->s_fields[sp->s_nfields++] = field; 35680ba2cbe9Sxc151355 } 35690ba2cbe9Sxc151355 return (sp); 35700ba2cbe9Sxc151355 fail: 35710ba2cbe9Sxc151355 splitfree(sp); 35720ba2cbe9Sxc151355 return (NULL); 35730ba2cbe9Sxc151355 } 35740ba2cbe9Sxc151355 35750ba2cbe9Sxc151355 static int 3576*e7801d59Ssowmini parse_wifi_fields(char *str, print_field_t ***fields, uint_t *countp, 35770ba2cbe9Sxc151355 uint_t cmdtype) 35780ba2cbe9Sxc151355 { 35790ba2cbe9Sxc151355 35800ba2cbe9Sxc151355 if (cmdtype == WIFI_CMD_SCAN) { 35810ba2cbe9Sxc151355 if (str == NULL) 35820ba2cbe9Sxc151355 str = def_scan_wifi_fields; 35830ba2cbe9Sxc151355 if (strcasecmp(str, "all") == 0) 35840ba2cbe9Sxc151355 str = all_scan_wifi_fields; 35850ba2cbe9Sxc151355 } else if (cmdtype == WIFI_CMD_SHOW) { 35860ba2cbe9Sxc151355 if (str == NULL) 35870ba2cbe9Sxc151355 str = def_show_wifi_fields; 35880ba2cbe9Sxc151355 if (strcasecmp(str, "all") == 0) 35890ba2cbe9Sxc151355 str = all_show_wifi_fields; 35900ba2cbe9Sxc151355 } else { 35910ba2cbe9Sxc151355 return (-1); 35920ba2cbe9Sxc151355 } 3593*e7801d59Ssowmini *fields = parse_output_fields(str, wifi_fields, WIFI_MAX_FIELDS, 3594*e7801d59Ssowmini cmdtype, countp); 3595*e7801d59Ssowmini if (*fields != NULL) 3596*e7801d59Ssowmini return (0); 35970ba2cbe9Sxc151355 return (-1); 3598*e7801d59Ssowmini } 3599*e7801d59Ssowmini static print_field_t ** 3600*e7801d59Ssowmini parse_output_fields(char *str, print_field_t *template, int max_fields, 3601*e7801d59Ssowmini uint_t cmdtype, uint_t *countp) 3602*e7801d59Ssowmini { 3603*e7801d59Ssowmini split_t *sp; 3604*e7801d59Ssowmini boolean_t good_match = B_FALSE; 3605*e7801d59Ssowmini uint_t i, j; 3606*e7801d59Ssowmini print_field_t **pf = NULL; 36070ba2cbe9Sxc151355 3608*e7801d59Ssowmini sp = split(str, max_fields, MAX_FIELD_LEN); 3609*e7801d59Ssowmini 3610*e7801d59Ssowmini if (sp == NULL) 3611*e7801d59Ssowmini return (NULL); 3612*e7801d59Ssowmini 3613*e7801d59Ssowmini pf = malloc(sp->s_nfields * sizeof (print_field_t *)); 3614*e7801d59Ssowmini if (pf == NULL) 36150ba2cbe9Sxc151355 goto fail; 36160ba2cbe9Sxc151355 36170ba2cbe9Sxc151355 for (i = 0; i < sp->s_nfields; i++) { 3618*e7801d59Ssowmini for (j = 0; j < max_fields; j++) { 36190ba2cbe9Sxc151355 if (strcasecmp(sp->s_fields[i], 3620*e7801d59Ssowmini template[j].pf_name) == 0) { 3621*e7801d59Ssowmini good_match = template[j]. pf_cmdtype & cmdtype; 36220ba2cbe9Sxc151355 break; 36230ba2cbe9Sxc151355 } 36240ba2cbe9Sxc151355 } 36250ba2cbe9Sxc151355 if (!good_match) 36260ba2cbe9Sxc151355 goto fail; 36270ba2cbe9Sxc151355 36280ba2cbe9Sxc151355 good_match = B_FALSE; 3629*e7801d59Ssowmini pf[i] = &template[j]; 36300ba2cbe9Sxc151355 } 36310ba2cbe9Sxc151355 *countp = i; 36320ba2cbe9Sxc151355 splitfree(sp); 3633*e7801d59Ssowmini return (pf); 36340ba2cbe9Sxc151355 fail: 3635*e7801d59Ssowmini free(pf); 36360ba2cbe9Sxc151355 splitfree(sp); 3637*e7801d59Ssowmini return (NULL); 36380ba2cbe9Sxc151355 } 36390ba2cbe9Sxc151355 36400ba2cbe9Sxc151355 typedef struct print_wifi_state { 3641d62bc4baSyz147064 char *ws_link; 36420ba2cbe9Sxc151355 boolean_t ws_parseable; 36430ba2cbe9Sxc151355 boolean_t ws_header; 3644*e7801d59Ssowmini print_state_t ws_print_state; 36450ba2cbe9Sxc151355 } print_wifi_state_t; 36460ba2cbe9Sxc151355 3647*e7801d59Ssowmini typedef struct wlan_scan_args_s { 3648*e7801d59Ssowmini print_wifi_state_t *ws_state; 3649*e7801d59Ssowmini void *ws_attr; 3650*e7801d59Ssowmini } wlan_scan_args_t; 36510ba2cbe9Sxc151355 36520ba2cbe9Sxc151355 36530ba2cbe9Sxc151355 static void 3654*e7801d59Ssowmini print_field(print_state_t *statep, print_field_t *pfp, const char *value, 3655*e7801d59Ssowmini boolean_t parseable) 36560ba2cbe9Sxc151355 { 3657*e7801d59Ssowmini uint_t width = pfp->pf_width; 36580ba2cbe9Sxc151355 uint_t valwidth = strlen(value); 36590ba2cbe9Sxc151355 uint_t compress; 36600ba2cbe9Sxc151355 3661*e7801d59Ssowmini if (parseable) { 3662*e7801d59Ssowmini (void) printf("%s=\"%s\"", pfp->pf_header, value); 36630ba2cbe9Sxc151355 } else { 36640ba2cbe9Sxc151355 if (value[0] == '\0') 3665*e7801d59Ssowmini value = STR_UNDEF_VAL; 3666*e7801d59Ssowmini if (statep->ps_lastfield) { 36670ba2cbe9Sxc151355 (void) printf("%s", value); 36680ba2cbe9Sxc151355 return; 36690ba2cbe9Sxc151355 } 36700ba2cbe9Sxc151355 36710ba2cbe9Sxc151355 if (valwidth > width) { 3672*e7801d59Ssowmini statep->ps_overflow += valwidth - width; 3673*e7801d59Ssowmini } else if (valwidth < width && statep->ps_overflow > 0) { 3674*e7801d59Ssowmini compress = min(statep->ps_overflow, width - valwidth); 3675*e7801d59Ssowmini statep->ps_overflow -= compress; 36760ba2cbe9Sxc151355 width -= compress; 36770ba2cbe9Sxc151355 } 36780ba2cbe9Sxc151355 (void) printf("%-*s", width, value); 36790ba2cbe9Sxc151355 } 36800ba2cbe9Sxc151355 3681*e7801d59Ssowmini if (!statep->ps_lastfield) 36820ba2cbe9Sxc151355 (void) putchar(' '); 36830ba2cbe9Sxc151355 } 36840ba2cbe9Sxc151355 3685*e7801d59Ssowmini static char * 3686*e7801d59Ssowmini print_wlan_attr(print_field_t *wfp, void *warg) 36870ba2cbe9Sxc151355 { 3688*e7801d59Ssowmini static char buf[DLADM_STRSIZE]; 3689*e7801d59Ssowmini wlan_scan_args_t *w = warg; 3690*e7801d59Ssowmini print_wifi_state_t *statep = w->ws_state; 3691*e7801d59Ssowmini dladm_wlan_attr_t *attrp = w->ws_attr; 36920ba2cbe9Sxc151355 3693*e7801d59Ssowmini if (wfp->pf_index == 0) { 3694*e7801d59Ssowmini return ((char *)statep->ws_link); 36950ba2cbe9Sxc151355 } 36960ba2cbe9Sxc151355 3697*e7801d59Ssowmini if ((wfp->pf_index & attrp->wa_valid) == 0) { 3698*e7801d59Ssowmini return (""); 36990ba2cbe9Sxc151355 } 37000ba2cbe9Sxc151355 3701*e7801d59Ssowmini switch (wfp->pf_index) { 3702f595a68aSyz147064 case DLADM_WLAN_ATTR_ESSID: 3703*e7801d59Ssowmini (void) dladm_wlan_essid2str(&attrp->wa_essid, buf); 37040ba2cbe9Sxc151355 break; 3705f595a68aSyz147064 case DLADM_WLAN_ATTR_BSSID: 3706*e7801d59Ssowmini (void) dladm_wlan_bssid2str(&attrp->wa_bssid, buf); 37070ba2cbe9Sxc151355 break; 3708f595a68aSyz147064 case DLADM_WLAN_ATTR_SECMODE: 3709*e7801d59Ssowmini (void) dladm_wlan_secmode2str(&attrp->wa_secmode, buf); 37100ba2cbe9Sxc151355 break; 3711f595a68aSyz147064 case DLADM_WLAN_ATTR_STRENGTH: 3712*e7801d59Ssowmini (void) dladm_wlan_strength2str(&attrp->wa_strength, buf); 37130ba2cbe9Sxc151355 break; 3714f595a68aSyz147064 case DLADM_WLAN_ATTR_MODE: 3715*e7801d59Ssowmini (void) dladm_wlan_mode2str(&attrp->wa_mode, buf); 37160ba2cbe9Sxc151355 break; 3717f595a68aSyz147064 case DLADM_WLAN_ATTR_SPEED: 3718*e7801d59Ssowmini (void) dladm_wlan_speed2str(&attrp->wa_speed, buf); 37190ba2cbe9Sxc151355 (void) strlcat(buf, "Mb", sizeof (buf)); 37200ba2cbe9Sxc151355 break; 3721f595a68aSyz147064 case DLADM_WLAN_ATTR_AUTH: 3722*e7801d59Ssowmini (void) dladm_wlan_auth2str(&attrp->wa_auth, buf); 37230ba2cbe9Sxc151355 break; 3724f595a68aSyz147064 case DLADM_WLAN_ATTR_BSSTYPE: 3725*e7801d59Ssowmini (void) dladm_wlan_bsstype2str(&attrp->wa_bsstype, buf); 37260ba2cbe9Sxc151355 break; 37270ba2cbe9Sxc151355 } 37280ba2cbe9Sxc151355 3729*e7801d59Ssowmini return (buf); 37300ba2cbe9Sxc151355 } 37310ba2cbe9Sxc151355 37320ba2cbe9Sxc151355 static boolean_t 3733f595a68aSyz147064 print_scan_results(void *arg, dladm_wlan_attr_t *attrp) 37340ba2cbe9Sxc151355 { 37350ba2cbe9Sxc151355 print_wifi_state_t *statep = arg; 3736*e7801d59Ssowmini wlan_scan_args_t warg; 37370ba2cbe9Sxc151355 37380ba2cbe9Sxc151355 if (statep->ws_header) { 37390ba2cbe9Sxc151355 statep->ws_header = B_FALSE; 37400ba2cbe9Sxc151355 if (!statep->ws_parseable) 3741*e7801d59Ssowmini print_header(&statep->ws_print_state); 37420ba2cbe9Sxc151355 } 37430ba2cbe9Sxc151355 3744*e7801d59Ssowmini statep->ws_print_state.ps_overflow = 0; 3745*e7801d59Ssowmini bzero(&warg, sizeof (warg)); 3746*e7801d59Ssowmini warg.ws_state = statep; 3747*e7801d59Ssowmini warg.ws_attr = attrp; 3748*e7801d59Ssowmini dladm_print_output(&statep->ws_print_state, statep->ws_parseable, 3749*e7801d59Ssowmini print_wlan_attr, &warg); 37500ba2cbe9Sxc151355 return (B_TRUE); 37510ba2cbe9Sxc151355 } 37520ba2cbe9Sxc151355 3753d62bc4baSyz147064 static int 3754d62bc4baSyz147064 scan_wifi(datalink_id_t linkid, void *arg) 37550ba2cbe9Sxc151355 { 37560ba2cbe9Sxc151355 print_wifi_state_t *statep = arg; 3757f595a68aSyz147064 dladm_status_t status; 3758d62bc4baSyz147064 char link[MAXLINKNAMELEN]; 3759d62bc4baSyz147064 3760*e7801d59Ssowmini if ((status = dladm_datalink_id2info(linkid, NULL, NULL, NULL, link, 3761*e7801d59Ssowmini sizeof (link))) != DLADM_STATUS_OK) { 3762d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 3763d62bc4baSyz147064 } 37640ba2cbe9Sxc151355 37650ba2cbe9Sxc151355 statep->ws_link = link; 3766d62bc4baSyz147064 status = dladm_wlan_scan(linkid, statep, print_scan_results); 3767f595a68aSyz147064 if (status != DLADM_STATUS_OK) 3768d62bc4baSyz147064 die_dlerr(status, "cannot scan link '%s'", statep->ws_link); 376933343a97Smeem 3770d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 37710ba2cbe9Sxc151355 } 37720ba2cbe9Sxc151355 3773*e7801d59Ssowmini static char * 3774*e7801d59Ssowmini print_link_attr(print_field_t *wfp, void *warg) 37750ba2cbe9Sxc151355 { 3776*e7801d59Ssowmini static char buf[DLADM_STRSIZE]; 3777*e7801d59Ssowmini char *ptr; 3778*e7801d59Ssowmini wlan_scan_args_t *w = warg, w1; 3779*e7801d59Ssowmini print_wifi_state_t *statep = w->ws_state; 3780*e7801d59Ssowmini dladm_wlan_linkattr_t *attrp = w->ws_attr; 37810ba2cbe9Sxc151355 3782*e7801d59Ssowmini if (strcmp(wfp->pf_name, "status") == 0) { 3783*e7801d59Ssowmini if ((wfp->pf_index & attrp->la_valid) != 0) 3784*e7801d59Ssowmini (void) dladm_wlan_linkstatus2str( 3785*e7801d59Ssowmini &attrp->la_status, buf); 3786*e7801d59Ssowmini return (buf); 37870ba2cbe9Sxc151355 } 3788*e7801d59Ssowmini statep->ws_print_state.ps_overflow = 0; 3789*e7801d59Ssowmini bzero(&w1, sizeof (w1)); 3790*e7801d59Ssowmini w1.ws_state = statep; 3791*e7801d59Ssowmini w1.ws_attr = &attrp->la_wlan_attr; 3792*e7801d59Ssowmini ptr = print_wlan_attr(wfp, &w1); 3793*e7801d59Ssowmini return (ptr); 37940ba2cbe9Sxc151355 } 37950ba2cbe9Sxc151355 3796d62bc4baSyz147064 static int 3797d62bc4baSyz147064 show_wifi(datalink_id_t linkid, void *arg) 37980ba2cbe9Sxc151355 { 37990ba2cbe9Sxc151355 print_wifi_state_t *statep = arg; 3800f595a68aSyz147064 dladm_wlan_linkattr_t attr; 3801f595a68aSyz147064 dladm_status_t status; 3802d62bc4baSyz147064 char link[MAXLINKNAMELEN]; 3803*e7801d59Ssowmini wlan_scan_args_t warg; 38040ba2cbe9Sxc151355 3805*e7801d59Ssowmini if ((status = dladm_datalink_id2info(linkid, NULL, NULL, NULL, link, 3806*e7801d59Ssowmini sizeof (link))) != DLADM_STATUS_OK) { 3807d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 3808d62bc4baSyz147064 } 3809d62bc4baSyz147064 3810d62bc4baSyz147064 status = dladm_wlan_get_linkattr(linkid, &attr); 3811f595a68aSyz147064 if (status != DLADM_STATUS_OK) 3812d62bc4baSyz147064 die_dlerr(status, "cannot get link attributes for %s", link); 3813d62bc4baSyz147064 3814d62bc4baSyz147064 statep->ws_link = link; 38150ba2cbe9Sxc151355 38160ba2cbe9Sxc151355 if (statep->ws_header) { 38170ba2cbe9Sxc151355 statep->ws_header = B_FALSE; 38180ba2cbe9Sxc151355 if (!statep->ws_parseable) 3819*e7801d59Ssowmini print_header(&statep->ws_print_state); 38200ba2cbe9Sxc151355 } 38210ba2cbe9Sxc151355 3822*e7801d59Ssowmini statep->ws_print_state.ps_overflow = 0; 3823*e7801d59Ssowmini bzero(&warg, sizeof (warg)); 3824*e7801d59Ssowmini warg.ws_state = statep; 3825*e7801d59Ssowmini warg.ws_attr = &attr; 3826*e7801d59Ssowmini dladm_print_output(&statep->ws_print_state, statep->ws_parseable, 3827*e7801d59Ssowmini print_link_attr, &warg); 3828d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 38290ba2cbe9Sxc151355 } 38300ba2cbe9Sxc151355 38310ba2cbe9Sxc151355 static void 38320ba2cbe9Sxc151355 do_display_wifi(int argc, char **argv, int cmd) 38330ba2cbe9Sxc151355 { 38340ba2cbe9Sxc151355 int option; 38350ba2cbe9Sxc151355 char *fields_str = NULL; 3836*e7801d59Ssowmini print_field_t **fields; 3837d62bc4baSyz147064 int (*callback)(datalink_id_t, void *); 38380ba2cbe9Sxc151355 uint_t nfields; 38390ba2cbe9Sxc151355 print_wifi_state_t state; 3840d62bc4baSyz147064 datalink_id_t linkid = DATALINK_ALL_LINKID; 3841f595a68aSyz147064 dladm_status_t status; 38420ba2cbe9Sxc151355 38430ba2cbe9Sxc151355 if (cmd == WIFI_CMD_SCAN) 38440ba2cbe9Sxc151355 callback = scan_wifi; 38450ba2cbe9Sxc151355 else if (cmd == WIFI_CMD_SHOW) 38460ba2cbe9Sxc151355 callback = show_wifi; 38470ba2cbe9Sxc151355 else 38480ba2cbe9Sxc151355 return; 38490ba2cbe9Sxc151355 38500ba2cbe9Sxc151355 state.ws_parseable = B_FALSE; 38510ba2cbe9Sxc151355 state.ws_header = B_TRUE; 38520ba2cbe9Sxc151355 opterr = 0; 38530ba2cbe9Sxc151355 while ((option = getopt_long(argc, argv, ":o:p", 38540ba2cbe9Sxc151355 wifi_longopts, NULL)) != -1) { 38550ba2cbe9Sxc151355 switch (option) { 38560ba2cbe9Sxc151355 case 'o': 38570ba2cbe9Sxc151355 fields_str = optarg; 38580ba2cbe9Sxc151355 break; 38590ba2cbe9Sxc151355 case 'p': 38600ba2cbe9Sxc151355 state.ws_parseable = B_TRUE; 38610ba2cbe9Sxc151355 if (fields_str == NULL) 38620ba2cbe9Sxc151355 fields_str = "all"; 38630ba2cbe9Sxc151355 break; 38640ba2cbe9Sxc151355 default: 386533343a97Smeem die_opterr(optopt, option); 38660ba2cbe9Sxc151355 break; 38670ba2cbe9Sxc151355 } 38680ba2cbe9Sxc151355 } 38690ba2cbe9Sxc151355 3870d62bc4baSyz147064 if (optind == (argc - 1)) { 3871d62bc4baSyz147064 if ((status = dladm_name2info(argv[optind], &linkid, NULL, 3872d62bc4baSyz147064 NULL, NULL)) != DLADM_STATUS_OK) { 3873d62bc4baSyz147064 die_dlerr(status, "link %s is not valid", argv[optind]); 3874d62bc4baSyz147064 } 3875d62bc4baSyz147064 } else if (optind != argc) { 38760ba2cbe9Sxc151355 usage(); 3877d62bc4baSyz147064 } 38780ba2cbe9Sxc151355 387933343a97Smeem if (parse_wifi_fields(fields_str, &fields, &nfields, cmd) < 0) 388033343a97Smeem die("invalid field(s) specified"); 388133343a97Smeem 3882*e7801d59Ssowmini bzero(&state.ws_print_state, sizeof (state.ws_print_state)); 3883*e7801d59Ssowmini state.ws_print_state.ps_fields = fields; 3884*e7801d59Ssowmini state.ws_print_state.ps_nfields = nfields; 38850ba2cbe9Sxc151355 3886d62bc4baSyz147064 if (linkid == DATALINK_ALL_LINKID) { 3887d62bc4baSyz147064 (void) dladm_walk_datalink_id(callback, &state, 3888d62bc4baSyz147064 DATALINK_CLASS_PHYS, DL_WIFI, DLADM_OPT_ACTIVE); 38890ba2cbe9Sxc151355 } else { 3890d62bc4baSyz147064 (void) (*callback)(linkid, &state); 38910ba2cbe9Sxc151355 } 38920ba2cbe9Sxc151355 free(fields); 38930ba2cbe9Sxc151355 } 38940ba2cbe9Sxc151355 38950ba2cbe9Sxc151355 static void 38960ba2cbe9Sxc151355 do_scan_wifi(int argc, char **argv) 38970ba2cbe9Sxc151355 { 38980ba2cbe9Sxc151355 do_display_wifi(argc, argv, WIFI_CMD_SCAN); 38990ba2cbe9Sxc151355 } 39000ba2cbe9Sxc151355 39010ba2cbe9Sxc151355 static void 39020ba2cbe9Sxc151355 do_show_wifi(int argc, char **argv) 39030ba2cbe9Sxc151355 { 39040ba2cbe9Sxc151355 do_display_wifi(argc, argv, WIFI_CMD_SHOW); 39050ba2cbe9Sxc151355 } 39060ba2cbe9Sxc151355 39070ba2cbe9Sxc151355 typedef struct wlan_count_attr { 39080ba2cbe9Sxc151355 uint_t wc_count; 3909d62bc4baSyz147064 datalink_id_t wc_linkid; 39100ba2cbe9Sxc151355 } wlan_count_attr_t; 39110ba2cbe9Sxc151355 3912d62bc4baSyz147064 static int 3913d62bc4baSyz147064 do_count_wlan(datalink_id_t linkid, void *arg) 39140ba2cbe9Sxc151355 { 391533343a97Smeem wlan_count_attr_t *cp = arg; 39160ba2cbe9Sxc151355 39170ba2cbe9Sxc151355 if (cp->wc_count == 0) 3918d62bc4baSyz147064 cp->wc_linkid = linkid; 39190ba2cbe9Sxc151355 cp->wc_count++; 3920d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 39210ba2cbe9Sxc151355 } 39220ba2cbe9Sxc151355 39230ba2cbe9Sxc151355 static int 3924a399b765Szf162725 parse_wlan_keys(char *str, dladm_wlan_key_t **keys, uint_t *key_countp) 39250ba2cbe9Sxc151355 { 39260ba2cbe9Sxc151355 uint_t i; 39270ba2cbe9Sxc151355 split_t *sp; 3928a399b765Szf162725 dladm_wlan_key_t *wk; 39290ba2cbe9Sxc151355 3930a399b765Szf162725 sp = split(str, DLADM_WLAN_MAX_WEPKEYS, DLADM_WLAN_MAX_KEYNAME_LEN); 39310ba2cbe9Sxc151355 if (sp == NULL) 39320ba2cbe9Sxc151355 return (-1); 39330ba2cbe9Sxc151355 3934a399b765Szf162725 wk = malloc(sp->s_nfields * sizeof (dladm_wlan_key_t)); 39350ba2cbe9Sxc151355 if (wk == NULL) 39360ba2cbe9Sxc151355 goto fail; 39370ba2cbe9Sxc151355 39380ba2cbe9Sxc151355 for (i = 0; i < sp->s_nfields; i++) { 39390ba2cbe9Sxc151355 char *s; 39400ba2cbe9Sxc151355 dladm_secobj_class_t class; 39410ba2cbe9Sxc151355 dladm_status_t status; 39420ba2cbe9Sxc151355 39430ba2cbe9Sxc151355 (void) strlcpy(wk[i].wk_name, sp->s_fields[i], 3944a399b765Szf162725 DLADM_WLAN_MAX_KEYNAME_LEN); 39450ba2cbe9Sxc151355 39460ba2cbe9Sxc151355 wk[i].wk_idx = 1; 39470ba2cbe9Sxc151355 if ((s = strrchr(wk[i].wk_name, ':')) != NULL) { 39480ba2cbe9Sxc151355 if (s[1] == '\0' || s[2] != '\0' || !isdigit(s[1])) 39490ba2cbe9Sxc151355 goto fail; 39500ba2cbe9Sxc151355 39510ba2cbe9Sxc151355 wk[i].wk_idx = (uint_t)(s[1] - '0'); 39520ba2cbe9Sxc151355 *s = '\0'; 39530ba2cbe9Sxc151355 } 3954a399b765Szf162725 wk[i].wk_len = DLADM_WLAN_MAX_KEY_LEN; 39550ba2cbe9Sxc151355 39560ba2cbe9Sxc151355 status = dladm_get_secobj(wk[i].wk_name, &class, 39570ba2cbe9Sxc151355 wk[i].wk_val, &wk[i].wk_len, 0); 39580ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 39590ba2cbe9Sxc151355 if (status == DLADM_STATUS_NOTFOUND) { 39600ba2cbe9Sxc151355 status = dladm_get_secobj(wk[i].wk_name, 39610ba2cbe9Sxc151355 &class, wk[i].wk_val, &wk[i].wk_len, 39620ba2cbe9Sxc151355 DLADM_OPT_PERSIST); 39630ba2cbe9Sxc151355 } 39640ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) 39650ba2cbe9Sxc151355 goto fail; 39660ba2cbe9Sxc151355 } 3967a399b765Szf162725 wk[i].wk_class = class; 39680ba2cbe9Sxc151355 } 39690ba2cbe9Sxc151355 *keys = wk; 39700ba2cbe9Sxc151355 *key_countp = i; 39710ba2cbe9Sxc151355 splitfree(sp); 39720ba2cbe9Sxc151355 return (0); 39730ba2cbe9Sxc151355 fail: 39740ba2cbe9Sxc151355 free(wk); 39750ba2cbe9Sxc151355 splitfree(sp); 39760ba2cbe9Sxc151355 return (-1); 39770ba2cbe9Sxc151355 } 39780ba2cbe9Sxc151355 39790ba2cbe9Sxc151355 static void 39800ba2cbe9Sxc151355 do_connect_wifi(int argc, char **argv) 39810ba2cbe9Sxc151355 { 39820ba2cbe9Sxc151355 int option; 3983f595a68aSyz147064 dladm_wlan_attr_t attr, *attrp; 3984f595a68aSyz147064 dladm_status_t status = DLADM_STATUS_OK; 3985f595a68aSyz147064 int timeout = DLADM_WLAN_CONNECT_TIMEOUT_DEFAULT; 3986d62bc4baSyz147064 datalink_id_t linkid = DATALINK_ALL_LINKID; 3987a399b765Szf162725 dladm_wlan_key_t *keys = NULL; 39880ba2cbe9Sxc151355 uint_t key_count = 0; 39890ba2cbe9Sxc151355 uint_t flags = 0; 3990f595a68aSyz147064 dladm_wlan_secmode_t keysecmode = DLADM_WLAN_SECMODE_NONE; 3991a399b765Szf162725 char buf[DLADM_STRSIZE]; 39920ba2cbe9Sxc151355 39930ba2cbe9Sxc151355 opterr = 0; 39940ba2cbe9Sxc151355 (void) memset(&attr, 0, sizeof (attr)); 39950ba2cbe9Sxc151355 while ((option = getopt_long(argc, argv, ":e:i:a:m:b:s:k:T:c", 39960ba2cbe9Sxc151355 wifi_longopts, NULL)) != -1) { 39970ba2cbe9Sxc151355 switch (option) { 39980ba2cbe9Sxc151355 case 'e': 3999f595a68aSyz147064 status = dladm_wlan_str2essid(optarg, &attr.wa_essid); 4000f595a68aSyz147064 if (status != DLADM_STATUS_OK) 400133343a97Smeem die("invalid ESSID '%s'", optarg); 400233343a97Smeem 4003f595a68aSyz147064 attr.wa_valid |= DLADM_WLAN_ATTR_ESSID; 40040ba2cbe9Sxc151355 /* 40050ba2cbe9Sxc151355 * Try to connect without doing a scan. 40060ba2cbe9Sxc151355 */ 4007f595a68aSyz147064 flags |= DLADM_WLAN_CONNECT_NOSCAN; 40080ba2cbe9Sxc151355 break; 40090ba2cbe9Sxc151355 case 'i': 4010f595a68aSyz147064 status = dladm_wlan_str2bssid(optarg, &attr.wa_bssid); 4011f595a68aSyz147064 if (status != DLADM_STATUS_OK) 401233343a97Smeem die("invalid BSSID %s", optarg); 401333343a97Smeem 4014f595a68aSyz147064 attr.wa_valid |= DLADM_WLAN_ATTR_BSSID; 40150ba2cbe9Sxc151355 break; 40160ba2cbe9Sxc151355 case 'a': 4017f595a68aSyz147064 status = dladm_wlan_str2auth(optarg, &attr.wa_auth); 4018f595a68aSyz147064 if (status != DLADM_STATUS_OK) 401933343a97Smeem die("invalid authentication mode '%s'", optarg); 402033343a97Smeem 4021f595a68aSyz147064 attr.wa_valid |= DLADM_WLAN_ATTR_AUTH; 40220ba2cbe9Sxc151355 break; 40230ba2cbe9Sxc151355 case 'm': 4024f595a68aSyz147064 status = dladm_wlan_str2mode(optarg, &attr.wa_mode); 4025f595a68aSyz147064 if (status != DLADM_STATUS_OK) 402633343a97Smeem die("invalid mode '%s'", optarg); 402733343a97Smeem 4028f595a68aSyz147064 attr.wa_valid |= DLADM_WLAN_ATTR_MODE; 40290ba2cbe9Sxc151355 break; 40300ba2cbe9Sxc151355 case 'b': 4031f595a68aSyz147064 if ((status = dladm_wlan_str2bsstype(optarg, 4032f595a68aSyz147064 &attr.wa_bsstype)) != DLADM_STATUS_OK) { 403333343a97Smeem die("invalid bsstype '%s'", optarg); 4034f595a68aSyz147064 } 403533343a97Smeem 4036f595a68aSyz147064 attr.wa_valid |= DLADM_WLAN_ATTR_BSSTYPE; 40370ba2cbe9Sxc151355 break; 40380ba2cbe9Sxc151355 case 's': 4039f595a68aSyz147064 if ((status = dladm_wlan_str2secmode(optarg, 4040f595a68aSyz147064 &attr.wa_secmode)) != DLADM_STATUS_OK) { 404133343a97Smeem die("invalid security mode '%s'", optarg); 4042f595a68aSyz147064 } 404333343a97Smeem 4044f595a68aSyz147064 attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE; 40450ba2cbe9Sxc151355 break; 40460ba2cbe9Sxc151355 case 'k': 4047a399b765Szf162725 if (parse_wlan_keys(optarg, &keys, &key_count) < 0) 404833343a97Smeem die("invalid key(s) '%s'", optarg); 404933343a97Smeem 4050a399b765Szf162725 if (keys[0].wk_class == DLADM_SECOBJ_CLASS_WEP) 4051f595a68aSyz147064 keysecmode = DLADM_WLAN_SECMODE_WEP; 4052a399b765Szf162725 else 4053a399b765Szf162725 keysecmode = DLADM_WLAN_SECMODE_WPA; 40540ba2cbe9Sxc151355 break; 40550ba2cbe9Sxc151355 case 'T': 40560ba2cbe9Sxc151355 if (strcasecmp(optarg, "forever") == 0) { 40570ba2cbe9Sxc151355 timeout = -1; 40580ba2cbe9Sxc151355 break; 40590ba2cbe9Sxc151355 } 406033343a97Smeem if (!str2int(optarg, &timeout) || timeout < 0) 406133343a97Smeem die("invalid timeout value '%s'", optarg); 40620ba2cbe9Sxc151355 break; 40630ba2cbe9Sxc151355 case 'c': 4064f595a68aSyz147064 flags |= DLADM_WLAN_CONNECT_CREATEIBSS; 4065a399b765Szf162725 flags |= DLADM_WLAN_CONNECT_CREATEIBSS; 40660ba2cbe9Sxc151355 break; 40670ba2cbe9Sxc151355 default: 406833343a97Smeem die_opterr(optopt, option); 40690ba2cbe9Sxc151355 break; 40700ba2cbe9Sxc151355 } 40710ba2cbe9Sxc151355 } 40720ba2cbe9Sxc151355 4073f595a68aSyz147064 if (keysecmode == DLADM_WLAN_SECMODE_NONE) { 4074a399b765Szf162725 if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0) { 4075a399b765Szf162725 die("key required for security mode '%s'", 4076a399b765Szf162725 dladm_wlan_secmode2str(&attr.wa_secmode, buf)); 4077a399b765Szf162725 } 40780ba2cbe9Sxc151355 } else { 4079f595a68aSyz147064 if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0 && 408033343a97Smeem attr.wa_secmode != keysecmode) 408133343a97Smeem die("incompatible -s and -k options"); 4082f595a68aSyz147064 attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE; 4083a399b765Szf162725 attr.wa_secmode = keysecmode; 4084a399b765Szf162725 } 40850ba2cbe9Sxc151355 4086d62bc4baSyz147064 if (optind == (argc - 1)) { 4087d62bc4baSyz147064 if ((status = dladm_name2info(argv[optind], &linkid, NULL, 4088d62bc4baSyz147064 NULL, NULL)) != DLADM_STATUS_OK) { 4089d62bc4baSyz147064 die_dlerr(status, "link %s is not valid", argv[optind]); 4090d62bc4baSyz147064 } 4091d62bc4baSyz147064 } else if (optind != argc) { 40920ba2cbe9Sxc151355 usage(); 4093d62bc4baSyz147064 } 40940ba2cbe9Sxc151355 4095d62bc4baSyz147064 if (linkid == DATALINK_ALL_LINKID) { 40960ba2cbe9Sxc151355 wlan_count_attr_t wcattr; 40970ba2cbe9Sxc151355 4098d62bc4baSyz147064 wcattr.wc_linkid = DATALINK_INVALID_LINKID; 40990ba2cbe9Sxc151355 wcattr.wc_count = 0; 4100d62bc4baSyz147064 (void) dladm_walk_datalink_id(do_count_wlan, &wcattr, 4101d62bc4baSyz147064 DATALINK_CLASS_PHYS, DL_WIFI, DLADM_OPT_ACTIVE); 41020ba2cbe9Sxc151355 if (wcattr.wc_count == 0) { 410333343a97Smeem die("no wifi links are available"); 41040ba2cbe9Sxc151355 } else if (wcattr.wc_count > 1) { 410533343a97Smeem die("link name is required when more than one wifi " 410633343a97Smeem "link is available"); 41070ba2cbe9Sxc151355 } 4108d62bc4baSyz147064 linkid = wcattr.wc_linkid; 41090ba2cbe9Sxc151355 } 41100ba2cbe9Sxc151355 attrp = (attr.wa_valid == 0) ? NULL : &attr; 411133343a97Smeem again: 4112d62bc4baSyz147064 if ((status = dladm_wlan_connect(linkid, attrp, timeout, keys, 4113f595a68aSyz147064 key_count, flags)) != DLADM_STATUS_OK) { 4114f595a68aSyz147064 if ((flags & DLADM_WLAN_CONNECT_NOSCAN) != 0) { 41150ba2cbe9Sxc151355 /* 411633343a97Smeem * Try again with scanning and filtering. 41170ba2cbe9Sxc151355 */ 4118f595a68aSyz147064 flags &= ~DLADM_WLAN_CONNECT_NOSCAN; 411933343a97Smeem goto again; 41200ba2cbe9Sxc151355 } 412133343a97Smeem 4122f595a68aSyz147064 if (status == DLADM_STATUS_NOTFOUND) { 41230ba2cbe9Sxc151355 if (attr.wa_valid == 0) { 412433343a97Smeem die("no wifi networks are available"); 41250ba2cbe9Sxc151355 } else { 412633343a97Smeem die("no wifi networks with the specified " 412733343a97Smeem "criteria are available"); 41280ba2cbe9Sxc151355 } 41290ba2cbe9Sxc151355 } 4130d62bc4baSyz147064 die_dlerr(status, "cannot connect"); 41310ba2cbe9Sxc151355 } 41320ba2cbe9Sxc151355 free(keys); 41330ba2cbe9Sxc151355 } 41340ba2cbe9Sxc151355 41350ba2cbe9Sxc151355 /* ARGSUSED */ 4136d62bc4baSyz147064 static int 4137d62bc4baSyz147064 do_all_disconnect_wifi(datalink_id_t linkid, void *arg) 41380ba2cbe9Sxc151355 { 4139f595a68aSyz147064 dladm_status_t status; 41400ba2cbe9Sxc151355 4141d62bc4baSyz147064 status = dladm_wlan_disconnect(linkid); 4142f595a68aSyz147064 if (status != DLADM_STATUS_OK) 4143d62bc4baSyz147064 warn_dlerr(status, "cannot disconnect link"); 414433343a97Smeem 4145d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 41460ba2cbe9Sxc151355 } 41470ba2cbe9Sxc151355 41480ba2cbe9Sxc151355 static void 41490ba2cbe9Sxc151355 do_disconnect_wifi(int argc, char **argv) 41500ba2cbe9Sxc151355 { 41510ba2cbe9Sxc151355 int option; 4152d62bc4baSyz147064 datalink_id_t linkid = DATALINK_ALL_LINKID; 41530ba2cbe9Sxc151355 boolean_t all_links = B_FALSE; 4154f595a68aSyz147064 dladm_status_t status; 41550ba2cbe9Sxc151355 wlan_count_attr_t wcattr; 41560ba2cbe9Sxc151355 41570ba2cbe9Sxc151355 opterr = 0; 41580ba2cbe9Sxc151355 while ((option = getopt_long(argc, argv, ":a", 41590ba2cbe9Sxc151355 wifi_longopts, NULL)) != -1) { 41600ba2cbe9Sxc151355 switch (option) { 41610ba2cbe9Sxc151355 case 'a': 41620ba2cbe9Sxc151355 all_links = B_TRUE; 41630ba2cbe9Sxc151355 break; 41640ba2cbe9Sxc151355 default: 416533343a97Smeem die_opterr(optopt, option); 41660ba2cbe9Sxc151355 break; 41670ba2cbe9Sxc151355 } 41680ba2cbe9Sxc151355 } 41690ba2cbe9Sxc151355 4170d62bc4baSyz147064 if (optind == (argc - 1)) { 4171d62bc4baSyz147064 if ((status = dladm_name2info(argv[optind], &linkid, NULL, 4172d62bc4baSyz147064 NULL, NULL)) != DLADM_STATUS_OK) { 4173d62bc4baSyz147064 die_dlerr(status, "link %s is not valid", argv[optind]); 4174d62bc4baSyz147064 } 4175d62bc4baSyz147064 } else if (optind != argc) { 41760ba2cbe9Sxc151355 usage(); 4177d62bc4baSyz147064 } 41780ba2cbe9Sxc151355 4179d62bc4baSyz147064 if (linkid == DATALINK_ALL_LINKID) { 41800ba2cbe9Sxc151355 if (!all_links) { 4181d62bc4baSyz147064 wcattr.wc_linkid = linkid; 41820ba2cbe9Sxc151355 wcattr.wc_count = 0; 4183d62bc4baSyz147064 (void) dladm_walk_datalink_id(do_count_wlan, &wcattr, 4184d62bc4baSyz147064 DATALINK_CLASS_PHYS, DL_WIFI, DLADM_OPT_ACTIVE); 41850ba2cbe9Sxc151355 if (wcattr.wc_count == 0) { 418633343a97Smeem die("no wifi links are available"); 41870ba2cbe9Sxc151355 } else if (wcattr.wc_count > 1) { 418833343a97Smeem die("link name is required when more than " 418933343a97Smeem "one wifi link is available"); 41900ba2cbe9Sxc151355 } 4191d62bc4baSyz147064 linkid = wcattr.wc_linkid; 41920ba2cbe9Sxc151355 } else { 4193d62bc4baSyz147064 (void) dladm_walk_datalink_id(do_all_disconnect_wifi, 4194d62bc4baSyz147064 NULL, DATALINK_CLASS_PHYS, DL_WIFI, 4195d62bc4baSyz147064 DLADM_OPT_ACTIVE); 41960ba2cbe9Sxc151355 return; 41970ba2cbe9Sxc151355 } 41980ba2cbe9Sxc151355 } 4199d62bc4baSyz147064 status = dladm_wlan_disconnect(linkid); 4200f595a68aSyz147064 if (status != DLADM_STATUS_OK) 4201d62bc4baSyz147064 die_dlerr(status, "cannot disconnect"); 42020ba2cbe9Sxc151355 } 42030ba2cbe9Sxc151355 42040ba2cbe9Sxc151355 42050ba2cbe9Sxc151355 static void 42060ba2cbe9Sxc151355 free_props(prop_list_t *list) 42070ba2cbe9Sxc151355 { 42080ba2cbe9Sxc151355 if (list != NULL) { 42090ba2cbe9Sxc151355 free(list->pl_buf); 42100ba2cbe9Sxc151355 free(list); 42110ba2cbe9Sxc151355 } 42120ba2cbe9Sxc151355 } 42130ba2cbe9Sxc151355 42140ba2cbe9Sxc151355 static int 42150ba2cbe9Sxc151355 parse_props(char *str, prop_list_t **listp, boolean_t novalues) 42160ba2cbe9Sxc151355 { 42170ba2cbe9Sxc151355 prop_list_t *list; 42180ba2cbe9Sxc151355 prop_info_t *pip; 42190ba2cbe9Sxc151355 char *buf, *curr; 42200ba2cbe9Sxc151355 int len, i; 42210ba2cbe9Sxc151355 42220ba2cbe9Sxc151355 list = malloc(sizeof (prop_list_t)); 42230ba2cbe9Sxc151355 if (list == NULL) 42240ba2cbe9Sxc151355 return (-1); 42250ba2cbe9Sxc151355 42260ba2cbe9Sxc151355 list->pl_count = 0; 42270ba2cbe9Sxc151355 list->pl_buf = buf = strdup(str); 42280ba2cbe9Sxc151355 if (buf == NULL) 42290ba2cbe9Sxc151355 goto fail; 42300ba2cbe9Sxc151355 4231*e7801d59Ssowmini /* 4232*e7801d59Ssowmini * buf is a string of form [<propname>=<value>][,<propname>=<value>]+ 4233*e7801d59Ssowmini * where each <value> string itself could be a comma-separated array. 4234*e7801d59Ssowmini * The loop below will count the number of propname assignments 4235*e7801d59Ssowmini * in pl_count; for each property, there is a pip entry with 4236*e7801d59Ssowmini * pi_name == <propname>, pi_count == # of elements in <value> array. 4237*e7801d59Ssowmini * pi_val[] contains the actual values. 4238*e7801d59Ssowmini * 4239*e7801d59Ssowmini * This could really be a combination of calls to 4240*e7801d59Ssowmini * strtok (token delimiter is ",") and strchr (chr '=') 4241*e7801d59Ssowmini * with appropriate null/string-bound-checks. 4242*e7801d59Ssowmini */ 4243*e7801d59Ssowmini 42440ba2cbe9Sxc151355 curr = buf; 42450ba2cbe9Sxc151355 len = strlen(buf); 42460ba2cbe9Sxc151355 pip = NULL; 42470ba2cbe9Sxc151355 for (i = 0; i < len; i++) { 42480ba2cbe9Sxc151355 char c = buf[i]; 42490ba2cbe9Sxc151355 boolean_t match = (c == '=' || c == ','); 42500ba2cbe9Sxc151355 42510ba2cbe9Sxc151355 if (!match && i != len - 1) 42520ba2cbe9Sxc151355 continue; 42530ba2cbe9Sxc151355 42540ba2cbe9Sxc151355 if (match) { 42550ba2cbe9Sxc151355 buf[i] = '\0'; 42560ba2cbe9Sxc151355 if (*curr == '\0') 42570ba2cbe9Sxc151355 goto fail; 42580ba2cbe9Sxc151355 } 42590ba2cbe9Sxc151355 42600ba2cbe9Sxc151355 if (pip != NULL && c != '=') { 4261d62bc4baSyz147064 if (pip->pi_count > DLADM_MAX_PROP_VALCNT) 42620ba2cbe9Sxc151355 goto fail; 42630ba2cbe9Sxc151355 42640ba2cbe9Sxc151355 if (novalues) 42650ba2cbe9Sxc151355 goto fail; 42660ba2cbe9Sxc151355 42670ba2cbe9Sxc151355 pip->pi_val[pip->pi_count] = curr; 42680ba2cbe9Sxc151355 pip->pi_count++; 42690ba2cbe9Sxc151355 } else { 42700ba2cbe9Sxc151355 if (list->pl_count > MAX_PROPS) 42710ba2cbe9Sxc151355 goto fail; 42720ba2cbe9Sxc151355 42730ba2cbe9Sxc151355 pip = &list->pl_info[list->pl_count]; 42740ba2cbe9Sxc151355 pip->pi_name = curr; 42750ba2cbe9Sxc151355 pip->pi_count = 0; 42760ba2cbe9Sxc151355 list->pl_count++; 42770ba2cbe9Sxc151355 if (c == ',') 42780ba2cbe9Sxc151355 pip = NULL; 42790ba2cbe9Sxc151355 } 42800ba2cbe9Sxc151355 curr = buf + i + 1; 42810ba2cbe9Sxc151355 } 42820ba2cbe9Sxc151355 *listp = list; 42830ba2cbe9Sxc151355 return (0); 42840ba2cbe9Sxc151355 42850ba2cbe9Sxc151355 fail: 42860ba2cbe9Sxc151355 free_props(list); 42870ba2cbe9Sxc151355 return (-1); 42880ba2cbe9Sxc151355 } 42890ba2cbe9Sxc151355 42900ba2cbe9Sxc151355 static void 4291d62bc4baSyz147064 print_linkprop(datalink_id_t linkid, show_linkprop_state_t *statep, 4292*e7801d59Ssowmini const char *propname, dladm_prop_type_t type, 4293d62bc4baSyz147064 const char *format, char **pptr) 42940ba2cbe9Sxc151355 { 42950ba2cbe9Sxc151355 int i; 42960ba2cbe9Sxc151355 char *ptr, *lim; 42970ba2cbe9Sxc151355 char buf[DLADM_STRSIZE]; 42980ba2cbe9Sxc151355 char *unknown = "?", *notsup = ""; 42990ba2cbe9Sxc151355 char **propvals = statep->ls_propvals; 4300d62bc4baSyz147064 uint_t valcnt = DLADM_MAX_PROP_VALCNT; 43010ba2cbe9Sxc151355 dladm_status_t status; 43020ba2cbe9Sxc151355 4303d62bc4baSyz147064 status = dladm_get_linkprop(linkid, type, propname, propvals, &valcnt); 43040ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 4305f595a68aSyz147064 if (status == DLADM_STATUS_TEMPONLY) { 4306d62bc4baSyz147064 if (type == DLADM_PROP_VAL_MODIFIABLE && 4307d62bc4baSyz147064 statep->ls_persist) { 4308d62bc4baSyz147064 valcnt = 1; 4309d62bc4baSyz147064 propvals = &unknown; 4310d62bc4baSyz147064 } else { 4311f595a68aSyz147064 statep->ls_status = status; 4312*e7801d59Ssowmini statep->ls_retstatus = status; 4313f595a68aSyz147064 return; 4314d62bc4baSyz147064 } 4315f595a68aSyz147064 } else if (status == DLADM_STATUS_NOTSUP || 4316f595a68aSyz147064 statep->ls_persist) { 43170ba2cbe9Sxc151355 valcnt = 1; 43180ba2cbe9Sxc151355 if (type == DLADM_PROP_VAL_CURRENT) 43190ba2cbe9Sxc151355 propvals = &unknown; 43200ba2cbe9Sxc151355 else 43210ba2cbe9Sxc151355 propvals = ¬sup; 43220ba2cbe9Sxc151355 } else { 4323*e7801d59Ssowmini if (statep->ls_proplist && 4324*e7801d59Ssowmini statep->ls_status == DLADM_STATUS_OK) { 4325f595a68aSyz147064 warn_dlerr(status, 4326f595a68aSyz147064 "cannot get link property '%s' for %s", 4327f595a68aSyz147064 propname, statep->ls_link); 4328d62bc4baSyz147064 } 4329*e7801d59Ssowmini statep->ls_status = status; 4330*e7801d59Ssowmini statep->ls_retstatus = status; 4331f595a68aSyz147064 return; 43320ba2cbe9Sxc151355 } 43330ba2cbe9Sxc151355 } 43340ba2cbe9Sxc151355 4335*e7801d59Ssowmini statep->ls_status = DLADM_STATUS_OK; 4336*e7801d59Ssowmini 43370ba2cbe9Sxc151355 ptr = buf; 43380ba2cbe9Sxc151355 lim = buf + DLADM_STRSIZE; 43390ba2cbe9Sxc151355 for (i = 0; i < valcnt; i++) { 43400ba2cbe9Sxc151355 if (propvals[i][0] == '\0' && !statep->ls_parseable) 4341*e7801d59Ssowmini ptr += snprintf(ptr, lim - ptr, STR_UNDEF_VAL","); 43420ba2cbe9Sxc151355 else 43430ba2cbe9Sxc151355 ptr += snprintf(ptr, lim - ptr, "%s,", propvals[i]); 43440ba2cbe9Sxc151355 if (ptr >= lim) 43450ba2cbe9Sxc151355 break; 43460ba2cbe9Sxc151355 } 43470ba2cbe9Sxc151355 if (valcnt > 0) 43480ba2cbe9Sxc151355 buf[strlen(buf) - 1] = '\0'; 43490ba2cbe9Sxc151355 43500ba2cbe9Sxc151355 lim = statep->ls_line + MAX_PROP_LINE; 43510ba2cbe9Sxc151355 if (statep->ls_parseable) { 43520ba2cbe9Sxc151355 *pptr += snprintf(*pptr, lim - *pptr, 4353*e7801d59Ssowmini "%s", buf); 43540ba2cbe9Sxc151355 } else { 43550ba2cbe9Sxc151355 *pptr += snprintf(*pptr, lim - *pptr, format, buf); 43560ba2cbe9Sxc151355 } 43570ba2cbe9Sxc151355 } 43580ba2cbe9Sxc151355 4359*e7801d59Ssowmini static char * 4360*e7801d59Ssowmini linkprop_callback(print_field_t *pf, void *ls_arg) 4361*e7801d59Ssowmini { 4362*e7801d59Ssowmini linkprop_args_t *arg = ls_arg; 4363*e7801d59Ssowmini char *propname = arg->ls_propname; 4364*e7801d59Ssowmini show_linkprop_state_t *statep = arg->ls_state; 4365*e7801d59Ssowmini char *ptr = statep->ls_line; 4366*e7801d59Ssowmini char *lim = ptr + MAX_PROP_LINE; 4367*e7801d59Ssowmini datalink_id_t linkid = arg->ls_linkid; 4368*e7801d59Ssowmini 4369*e7801d59Ssowmini switch (pf->pf_index) { 4370*e7801d59Ssowmini case LINKPROP_LINK: 4371*e7801d59Ssowmini (void) snprintf(ptr, lim - ptr, "%s", statep->ls_link); 4372*e7801d59Ssowmini break; 4373*e7801d59Ssowmini case LINKPROP_PROPERTY: 4374*e7801d59Ssowmini (void) snprintf(ptr, lim - ptr, "%s", propname); 4375*e7801d59Ssowmini break; 4376*e7801d59Ssowmini case LINKPROP_VALUE: 4377*e7801d59Ssowmini print_linkprop(linkid, statep, propname, 4378*e7801d59Ssowmini statep->ls_persist ? DLADM_PROP_VAL_PERSISTENT : 4379*e7801d59Ssowmini DLADM_PROP_VAL_CURRENT, "%s", &ptr); 4380*e7801d59Ssowmini /* 4381*e7801d59Ssowmini * If we failed to query the link property, for example, query 4382*e7801d59Ssowmini * the persistent value of a non-persistable link property, 4383*e7801d59Ssowmini * simply skip the output. 4384*e7801d59Ssowmini */ 4385*e7801d59Ssowmini if (statep->ls_status != DLADM_STATUS_OK) 4386*e7801d59Ssowmini goto skip; 4387*e7801d59Ssowmini ptr = statep->ls_line; 4388*e7801d59Ssowmini break; 4389*e7801d59Ssowmini case LINKPROP_DEFAULT: 4390*e7801d59Ssowmini print_linkprop(linkid, statep, propname, 4391*e7801d59Ssowmini DLADM_PROP_VAL_DEFAULT, "%s", &ptr); 4392*e7801d59Ssowmini if (statep->ls_status != DLADM_STATUS_OK) 4393*e7801d59Ssowmini goto skip; 4394*e7801d59Ssowmini ptr = statep->ls_line; 4395*e7801d59Ssowmini break; 4396*e7801d59Ssowmini case LINKPROP_POSSIBLE: 4397*e7801d59Ssowmini print_linkprop(linkid, statep, propname, 4398*e7801d59Ssowmini DLADM_PROP_VAL_MODIFIABLE, "%s ", &ptr); 4399*e7801d59Ssowmini if (statep->ls_status != DLADM_STATUS_OK) 4400*e7801d59Ssowmini goto skip; 4401*e7801d59Ssowmini ptr = statep->ls_line; 4402*e7801d59Ssowmini break; 4403*e7801d59Ssowmini default: 4404*e7801d59Ssowmini die("invalid input"); 4405*e7801d59Ssowmini break; 4406*e7801d59Ssowmini } 4407*e7801d59Ssowmini return (ptr); 4408*e7801d59Ssowmini skip: 4409*e7801d59Ssowmini if (statep->ls_status != DLADM_STATUS_OK) 4410*e7801d59Ssowmini return (NULL); 4411*e7801d59Ssowmini else 4412*e7801d59Ssowmini return (""); 4413*e7801d59Ssowmini } 4414*e7801d59Ssowmini 4415d62bc4baSyz147064 static int 4416d62bc4baSyz147064 show_linkprop(datalink_id_t linkid, const char *propname, void *arg) 44170ba2cbe9Sxc151355 { 44180ba2cbe9Sxc151355 show_linkprop_state_t *statep = arg; 4419*e7801d59Ssowmini linkprop_args_t ls_arg; 44200ba2cbe9Sxc151355 4421*e7801d59Ssowmini bzero(&ls_arg, sizeof (ls_arg)); 4422*e7801d59Ssowmini ls_arg.ls_state = statep; 4423*e7801d59Ssowmini ls_arg.ls_propname = (char *)propname; 4424*e7801d59Ssowmini ls_arg.ls_linkid = linkid; 44250ba2cbe9Sxc151355 44260ba2cbe9Sxc151355 if (statep->ls_header) { 44270ba2cbe9Sxc151355 statep->ls_header = B_FALSE; 44280ba2cbe9Sxc151355 if (!statep->ls_parseable) 4429*e7801d59Ssowmini print_header(&statep->ls_print); 44300ba2cbe9Sxc151355 } 4431*e7801d59Ssowmini dladm_print_output(&statep->ls_print, statep->ls_parseable, 4432*e7801d59Ssowmini linkprop_callback, (void *)&ls_arg); 4433*e7801d59Ssowmini 4434d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 44350ba2cbe9Sxc151355 } 44360ba2cbe9Sxc151355 44370ba2cbe9Sxc151355 static void 44380ba2cbe9Sxc151355 do_show_linkprop(int argc, char **argv) 44390ba2cbe9Sxc151355 { 4440f4b3ec61Sdh155122 int option; 44410ba2cbe9Sxc151355 prop_list_t *proplist = NULL; 4442d62bc4baSyz147064 datalink_id_t linkid = DATALINK_ALL_LINKID; 44430ba2cbe9Sxc151355 show_linkprop_state_t state; 4444d62bc4baSyz147064 uint32_t flags = DLADM_OPT_ACTIVE; 4445d62bc4baSyz147064 dladm_status_t status; 4446*e7801d59Ssowmini char *fields_str = NULL; 4447*e7801d59Ssowmini print_field_t **fields; 4448*e7801d59Ssowmini uint_t nfields; 4449*e7801d59Ssowmini char *all_fields = 4450*e7801d59Ssowmini "link,property,value,default,possible"; 4451*e7801d59Ssowmini 4452*e7801d59Ssowmini fields_str = all_fields; 44530ba2cbe9Sxc151355 44540ba2cbe9Sxc151355 opterr = 0; 44550ba2cbe9Sxc151355 state.ls_propvals = NULL; 44560ba2cbe9Sxc151355 state.ls_line = NULL; 44570ba2cbe9Sxc151355 state.ls_parseable = B_FALSE; 44580ba2cbe9Sxc151355 state.ls_persist = B_FALSE; 44590ba2cbe9Sxc151355 state.ls_header = B_TRUE; 4460*e7801d59Ssowmini state.ls_retstatus = DLADM_STATUS_OK; 4461*e7801d59Ssowmini while ((option = getopt_long(argc, argv, ":p:cPo:", 44620ba2cbe9Sxc151355 prop_longopts, NULL)) != -1) { 44630ba2cbe9Sxc151355 switch (option) { 44640ba2cbe9Sxc151355 case 'p': 446533343a97Smeem if (parse_props(optarg, &proplist, B_TRUE) < 0) 446613994ee8Sxz162242 die("invalid link properties specified"); 44670ba2cbe9Sxc151355 break; 44680ba2cbe9Sxc151355 case 'c': 44690ba2cbe9Sxc151355 state.ls_parseable = B_TRUE; 44700ba2cbe9Sxc151355 break; 44710ba2cbe9Sxc151355 case 'P': 44720ba2cbe9Sxc151355 state.ls_persist = B_TRUE; 4473d62bc4baSyz147064 flags = DLADM_OPT_PERSIST; 44740ba2cbe9Sxc151355 break; 4475*e7801d59Ssowmini case 'o': 4476*e7801d59Ssowmini if (strcasecmp(optarg, "all") == 0) 4477*e7801d59Ssowmini fields_str = all_fields; 4478*e7801d59Ssowmini else 4479*e7801d59Ssowmini fields_str = optarg; 4480*e7801d59Ssowmini break; 44810ba2cbe9Sxc151355 default: 448233343a97Smeem die_opterr(optopt, option); 44830ba2cbe9Sxc151355 break; 44840ba2cbe9Sxc151355 } 44850ba2cbe9Sxc151355 } 44860ba2cbe9Sxc151355 4487d62bc4baSyz147064 if (optind == (argc - 1)) { 4488d62bc4baSyz147064 if ((status = dladm_name2info(argv[optind], &linkid, NULL, 4489d62bc4baSyz147064 NULL, NULL)) != DLADM_STATUS_OK) { 4490d62bc4baSyz147064 die_dlerr(status, "link %s is not valid", argv[optind]); 4491d62bc4baSyz147064 } 4492d62bc4baSyz147064 } else if (optind != argc) { 44930ba2cbe9Sxc151355 usage(); 4494d62bc4baSyz147064 } 44950ba2cbe9Sxc151355 4496*e7801d59Ssowmini bzero(&state.ls_print, sizeof (print_state_t)); 4497f4b3ec61Sdh155122 state.ls_proplist = proplist; 4498f595a68aSyz147064 state.ls_status = DLADM_STATUS_OK; 4499f4b3ec61Sdh155122 4500*e7801d59Ssowmini fields = parse_output_fields(fields_str, linkprop_fields, 4501*e7801d59Ssowmini LINKPROP_MAX_FIELDS, CMD_TYPE_ANY, &nfields); 4502*e7801d59Ssowmini 4503*e7801d59Ssowmini if (fields == NULL) { 4504*e7801d59Ssowmini die("invalid field(s) specified"); 4505*e7801d59Ssowmini return; 4506*e7801d59Ssowmini } 4507*e7801d59Ssowmini 4508*e7801d59Ssowmini state.ls_print.ps_fields = fields; 4509*e7801d59Ssowmini state.ls_print.ps_nfields = nfields; 4510d62bc4baSyz147064 if (linkid == DATALINK_ALL_LINKID) { 4511d62bc4baSyz147064 (void) dladm_walk_datalink_id(show_linkprop_onelink, &state, 4512d62bc4baSyz147064 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, flags); 4513f4b3ec61Sdh155122 } else { 4514d62bc4baSyz147064 (void) show_linkprop_onelink(linkid, &state); 4515f4b3ec61Sdh155122 } 4516f4b3ec61Sdh155122 free_props(proplist); 4517f595a68aSyz147064 4518*e7801d59Ssowmini if (state.ls_retstatus != DLADM_STATUS_OK) 4519f595a68aSyz147064 exit(EXIT_FAILURE); 4520f4b3ec61Sdh155122 } 4521f4b3ec61Sdh155122 4522d62bc4baSyz147064 static int 4523d62bc4baSyz147064 show_linkprop_onelink(datalink_id_t linkid, void *arg) 4524f4b3ec61Sdh155122 { 4525948f2876Sss150715 int i; 4526f4b3ec61Sdh155122 char *buf; 4527d62bc4baSyz147064 uint32_t flags; 4528f4b3ec61Sdh155122 prop_list_t *proplist = NULL; 4529d62bc4baSyz147064 show_linkprop_state_t *statep = arg; 4530d62bc4baSyz147064 dlpi_handle_t dh = NULL; 4531f4b3ec61Sdh155122 4532d62bc4baSyz147064 statep->ls_status = DLADM_STATUS_OK; 4533d62bc4baSyz147064 4534d62bc4baSyz147064 if (dladm_datalink_id2info(linkid, &flags, NULL, NULL, statep->ls_link, 4535d62bc4baSyz147064 MAXLINKNAMELEN) != DLADM_STATUS_OK) { 4536d62bc4baSyz147064 statep->ls_status = DLADM_STATUS_NOTFOUND; 4537d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 4538d62bc4baSyz147064 } 4539d62bc4baSyz147064 4540d62bc4baSyz147064 if ((statep->ls_persist && !(flags & DLADM_OPT_PERSIST)) || 4541d62bc4baSyz147064 (!statep->ls_persist && !(flags & DLADM_OPT_ACTIVE))) { 4542d62bc4baSyz147064 statep->ls_status = DLADM_STATUS_BADARG; 4543d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 4544d62bc4baSyz147064 } 4545d62bc4baSyz147064 4546f4b3ec61Sdh155122 proplist = statep->ls_proplist; 45470ba2cbe9Sxc151355 45480ba2cbe9Sxc151355 /* 45490ba2cbe9Sxc151355 * When some WiFi links are opened for the first time, their hardware 45500ba2cbe9Sxc151355 * automatically scans for APs and does other slow operations. Thus, 45510ba2cbe9Sxc151355 * if there are no open links, the retrieval of link properties 45520ba2cbe9Sxc151355 * (below) will proceed slowly unless we hold the link open. 4553d62bc4baSyz147064 * 4554d62bc4baSyz147064 * Note that failure of dlpi_open() does not necessarily mean invalid 4555d62bc4baSyz147064 * link properties, because dlpi_open() may fail because of incorrect 4556d62bc4baSyz147064 * autopush configuration. Therefore, we ingore the return value of 4557d62bc4baSyz147064 * dlpi_open(). 45580ba2cbe9Sxc151355 */ 4559d62bc4baSyz147064 if (!statep->ls_persist) 4560d62bc4baSyz147064 (void) dlpi_open(statep->ls_link, &dh, 0); 45610ba2cbe9Sxc151355 4562d62bc4baSyz147064 buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) * 4563d62bc4baSyz147064 DLADM_MAX_PROP_VALCNT + MAX_PROP_LINE); 456433343a97Smeem if (buf == NULL) 456533343a97Smeem die("insufficient memory"); 456633343a97Smeem 4567f4b3ec61Sdh155122 statep->ls_propvals = (char **)(void *)buf; 4568d62bc4baSyz147064 for (i = 0; i < DLADM_MAX_PROP_VALCNT; i++) { 4569d62bc4baSyz147064 statep->ls_propvals[i] = buf + 4570d62bc4baSyz147064 sizeof (char *) * DLADM_MAX_PROP_VALCNT + 45710ba2cbe9Sxc151355 i * DLADM_PROP_VAL_MAX; 45720ba2cbe9Sxc151355 } 4573f4b3ec61Sdh155122 statep->ls_line = buf + 4574d62bc4baSyz147064 (sizeof (char *) + DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT; 45750ba2cbe9Sxc151355 45760ba2cbe9Sxc151355 if (proplist != NULL) { 4577d62bc4baSyz147064 for (i = 0; i < proplist->pl_count; i++) { 4578d62bc4baSyz147064 (void) show_linkprop(linkid, 4579d62bc4baSyz147064 proplist->pl_info[i].pi_name, statep); 45800ba2cbe9Sxc151355 } 4581d62bc4baSyz147064 } else { 4582d62bc4baSyz147064 (void) dladm_walk_linkprop(linkid, statep, show_linkprop); 4583d62bc4baSyz147064 } 4584d62bc4baSyz147064 if (dh != NULL) 4585948f2876Sss150715 dlpi_close(dh); 45860ba2cbe9Sxc151355 free(buf); 4587d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 45880ba2cbe9Sxc151355 } 45890ba2cbe9Sxc151355 45900ba2cbe9Sxc151355 static dladm_status_t 4591d62bc4baSyz147064 set_linkprop_persist(datalink_id_t linkid, const char *prop_name, 4592d62bc4baSyz147064 char **prop_val, uint_t val_cnt, boolean_t reset) 45930ba2cbe9Sxc151355 { 45940ba2cbe9Sxc151355 dladm_status_t status; 45950ba2cbe9Sxc151355 4596d62bc4baSyz147064 status = dladm_set_linkprop(linkid, prop_name, prop_val, val_cnt, 4597d62bc4baSyz147064 DLADM_OPT_PERSIST); 45980ba2cbe9Sxc151355 45990ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 4600d62bc4baSyz147064 warn_dlerr(status, "cannot persistently %s link property", 4601d62bc4baSyz147064 reset ? "reset" : "set"); 46020ba2cbe9Sxc151355 } 46030ba2cbe9Sxc151355 return (status); 46040ba2cbe9Sxc151355 } 46050ba2cbe9Sxc151355 46060ba2cbe9Sxc151355 static void 46070ba2cbe9Sxc151355 set_linkprop(int argc, char **argv, boolean_t reset) 46080ba2cbe9Sxc151355 { 46090ba2cbe9Sxc151355 int i, option; 46100ba2cbe9Sxc151355 char errmsg[DLADM_STRSIZE]; 4611d62bc4baSyz147064 char *altroot = NULL; 4612d62bc4baSyz147064 datalink_id_t linkid; 46130ba2cbe9Sxc151355 prop_list_t *proplist = NULL; 46140ba2cbe9Sxc151355 boolean_t temp = B_FALSE; 46150ba2cbe9Sxc151355 dladm_status_t status = DLADM_STATUS_OK; 46160ba2cbe9Sxc151355 46170ba2cbe9Sxc151355 opterr = 0; 46180ba2cbe9Sxc151355 while ((option = getopt_long(argc, argv, ":p:R:t", 46190ba2cbe9Sxc151355 prop_longopts, NULL)) != -1) { 46200ba2cbe9Sxc151355 switch (option) { 46210ba2cbe9Sxc151355 case 'p': 462233343a97Smeem if (parse_props(optarg, &proplist, reset) < 0) 462333343a97Smeem die("invalid link properties specified"); 46240ba2cbe9Sxc151355 break; 46250ba2cbe9Sxc151355 case 't': 46260ba2cbe9Sxc151355 temp = B_TRUE; 46270ba2cbe9Sxc151355 break; 46280ba2cbe9Sxc151355 case 'R': 4629d62bc4baSyz147064 altroot = optarg; 46300ba2cbe9Sxc151355 break; 46310ba2cbe9Sxc151355 default: 463233343a97Smeem die_opterr(optopt, option); 46330ba2cbe9Sxc151355 break; 46340ba2cbe9Sxc151355 } 46350ba2cbe9Sxc151355 } 46360ba2cbe9Sxc151355 4637d62bc4baSyz147064 /* get link name (required last argument) */ 4638d62bc4baSyz147064 if (optind != (argc - 1)) 46390ba2cbe9Sxc151355 usage(); 46400ba2cbe9Sxc151355 4641d62bc4baSyz147064 if (proplist == NULL && !reset) 464233343a97Smeem die("link property must be specified"); 464333343a97Smeem 4644d62bc4baSyz147064 if (altroot != NULL) { 4645d62bc4baSyz147064 free_props(proplist); 4646d62bc4baSyz147064 altroot_cmd(altroot, argc, argv); 4647d62bc4baSyz147064 } 4648d62bc4baSyz147064 4649d62bc4baSyz147064 status = dladm_name2info(argv[optind], &linkid, NULL, NULL, NULL); 4650d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 4651d62bc4baSyz147064 die_dlerr(status, "link %s is not valid", argv[optind]); 4652d62bc4baSyz147064 4653d62bc4baSyz147064 if (proplist == NULL) { 4654*e7801d59Ssowmini status = dladm_set_linkprop(linkid, NULL, NULL, 0, 4655*e7801d59Ssowmini DLADM_OPT_ACTIVE); 4656*e7801d59Ssowmini if (status != DLADM_STATUS_OK) { 4657d62bc4baSyz147064 warn_dlerr(status, "cannot reset link property " 4658d62bc4baSyz147064 "on '%s'", argv[optind]); 46590ba2cbe9Sxc151355 } 46600ba2cbe9Sxc151355 if (!temp) { 466113994ee8Sxz162242 dladm_status_t s; 466213994ee8Sxz162242 4663d62bc4baSyz147064 s = set_linkprop_persist(linkid, NULL, NULL, 0, reset); 466413994ee8Sxz162242 if (s != DLADM_STATUS_OK) 466513994ee8Sxz162242 status = s; 46660ba2cbe9Sxc151355 } 46670ba2cbe9Sxc151355 goto done; 46680ba2cbe9Sxc151355 } 46690ba2cbe9Sxc151355 46700ba2cbe9Sxc151355 for (i = 0; i < proplist->pl_count; i++) { 46710ba2cbe9Sxc151355 prop_info_t *pip = &proplist->pl_info[i]; 46720ba2cbe9Sxc151355 char **val; 46730ba2cbe9Sxc151355 uint_t count; 46740ba2cbe9Sxc151355 dladm_status_t s; 46750ba2cbe9Sxc151355 46760ba2cbe9Sxc151355 if (reset) { 46770ba2cbe9Sxc151355 val = NULL; 46780ba2cbe9Sxc151355 count = 0; 46790ba2cbe9Sxc151355 } else { 46800ba2cbe9Sxc151355 val = pip->pi_val; 46810ba2cbe9Sxc151355 count = pip->pi_count; 46820ba2cbe9Sxc151355 if (count == 0) { 468333343a97Smeem warn("no value specified for '%s'", 468433343a97Smeem pip->pi_name); 46850ba2cbe9Sxc151355 status = DLADM_STATUS_BADARG; 46860ba2cbe9Sxc151355 continue; 46870ba2cbe9Sxc151355 } 46880ba2cbe9Sxc151355 } 4689d62bc4baSyz147064 s = dladm_set_linkprop(linkid, pip->pi_name, val, count, 4690d62bc4baSyz147064 DLADM_OPT_ACTIVE); 46910ba2cbe9Sxc151355 if (s == DLADM_STATUS_OK) { 46920ba2cbe9Sxc151355 if (!temp) { 4693d62bc4baSyz147064 s = set_linkprop_persist(linkid, 46940ba2cbe9Sxc151355 pip->pi_name, val, count, reset); 46950ba2cbe9Sxc151355 if (s != DLADM_STATUS_OK) 46960ba2cbe9Sxc151355 status = s; 46970ba2cbe9Sxc151355 } 46980ba2cbe9Sxc151355 continue; 46990ba2cbe9Sxc151355 } 47000ba2cbe9Sxc151355 status = s; 47010ba2cbe9Sxc151355 switch (s) { 47020ba2cbe9Sxc151355 case DLADM_STATUS_NOTFOUND: 470333343a97Smeem warn("invalid link property '%s'", pip->pi_name); 47040ba2cbe9Sxc151355 break; 47050ba2cbe9Sxc151355 case DLADM_STATUS_BADVAL: { 47060ba2cbe9Sxc151355 int j; 47070ba2cbe9Sxc151355 char *ptr, *lim; 47080ba2cbe9Sxc151355 char **propvals = NULL; 4709d62bc4baSyz147064 uint_t valcnt = DLADM_MAX_PROP_VALCNT; 47100ba2cbe9Sxc151355 47110ba2cbe9Sxc151355 ptr = malloc((sizeof (char *) + 4712d62bc4baSyz147064 DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT + 47130ba2cbe9Sxc151355 MAX_PROP_LINE); 47140ba2cbe9Sxc151355 47150ba2cbe9Sxc151355 propvals = (char **)(void *)ptr; 471633343a97Smeem if (propvals == NULL) 471733343a97Smeem die("insufficient memory"); 471833343a97Smeem 4719d62bc4baSyz147064 for (j = 0; j < DLADM_MAX_PROP_VALCNT; j++) { 47200ba2cbe9Sxc151355 propvals[j] = ptr + sizeof (char *) * 4721d62bc4baSyz147064 DLADM_MAX_PROP_VALCNT + 47220ba2cbe9Sxc151355 j * DLADM_PROP_VAL_MAX; 47230ba2cbe9Sxc151355 } 4724d62bc4baSyz147064 s = dladm_get_linkprop(linkid, 4725d62bc4baSyz147064 DLADM_PROP_VAL_MODIFIABLE, pip->pi_name, propvals, 4726d62bc4baSyz147064 &valcnt); 4727d62bc4baSyz147064 4728d62bc4baSyz147064 if (s != DLADM_STATUS_OK) { 4729d62bc4baSyz147064 warn_dlerr(status, "cannot set link property " 4730d62bc4baSyz147064 "'%s' on '%s'", pip->pi_name, argv[optind]); 4731d62bc4baSyz147064 free(propvals); 4732d62bc4baSyz147064 break; 4733d62bc4baSyz147064 } 47340ba2cbe9Sxc151355 47350ba2cbe9Sxc151355 ptr = errmsg; 47360ba2cbe9Sxc151355 lim = ptr + DLADM_STRSIZE; 47370ba2cbe9Sxc151355 *ptr = '\0'; 4738d62bc4baSyz147064 for (j = 0; j < valcnt; j++) { 47390ba2cbe9Sxc151355 ptr += snprintf(ptr, lim - ptr, "%s,", 47400ba2cbe9Sxc151355 propvals[j]); 47410ba2cbe9Sxc151355 if (ptr >= lim) 47420ba2cbe9Sxc151355 break; 47430ba2cbe9Sxc151355 } 4744f4b3ec61Sdh155122 if (ptr > errmsg) { 47450ba2cbe9Sxc151355 *(ptr - 1) = '\0'; 474633343a97Smeem warn("link property '%s' must be one of: %s", 474733343a97Smeem pip->pi_name, errmsg); 4748f4b3ec61Sdh155122 } else 4749f4b3ec61Sdh155122 warn("invalid link property '%s'", *val); 47500ba2cbe9Sxc151355 free(propvals); 47510ba2cbe9Sxc151355 break; 47520ba2cbe9Sxc151355 } 47530ba2cbe9Sxc151355 default: 47540ba2cbe9Sxc151355 if (reset) { 475533343a97Smeem warn_dlerr(status, "cannot reset link property " 4756d62bc4baSyz147064 "'%s' on '%s'", pip->pi_name, argv[optind]); 47570ba2cbe9Sxc151355 } else { 475833343a97Smeem warn_dlerr(status, "cannot set link property " 4759d62bc4baSyz147064 "'%s' on '%s'", pip->pi_name, argv[optind]); 47600ba2cbe9Sxc151355 } 47610ba2cbe9Sxc151355 break; 47620ba2cbe9Sxc151355 } 47630ba2cbe9Sxc151355 } 47640ba2cbe9Sxc151355 done: 47650ba2cbe9Sxc151355 free_props(proplist); 47660ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) 47670ba2cbe9Sxc151355 exit(1); 47680ba2cbe9Sxc151355 } 47690ba2cbe9Sxc151355 47700ba2cbe9Sxc151355 static void 47710ba2cbe9Sxc151355 do_set_linkprop(int argc, char **argv) 47720ba2cbe9Sxc151355 { 47730ba2cbe9Sxc151355 set_linkprop(argc, argv, B_FALSE); 47740ba2cbe9Sxc151355 } 47750ba2cbe9Sxc151355 47760ba2cbe9Sxc151355 static void 47770ba2cbe9Sxc151355 do_reset_linkprop(int argc, char **argv) 47780ba2cbe9Sxc151355 { 47790ba2cbe9Sxc151355 set_linkprop(argc, argv, B_TRUE); 47800ba2cbe9Sxc151355 } 47810ba2cbe9Sxc151355 47820ba2cbe9Sxc151355 static int 47830ba2cbe9Sxc151355 convert_secobj(char *buf, uint_t len, uint8_t *obj_val, uint_t *obj_lenp, 47840ba2cbe9Sxc151355 dladm_secobj_class_t class) 47850ba2cbe9Sxc151355 { 47860ba2cbe9Sxc151355 int error = 0; 47870ba2cbe9Sxc151355 4788a399b765Szf162725 if (class == DLADM_SECOBJ_CLASS_WPA) { 4789a399b765Szf162725 if (len < 8 || len > 63) 4790a399b765Szf162725 return (EINVAL); 4791a399b765Szf162725 (void) memcpy(obj_val, buf, len); 4792a399b765Szf162725 *obj_lenp = len; 4793a399b765Szf162725 return (error); 4794a399b765Szf162725 } 47950ba2cbe9Sxc151355 4796a399b765Szf162725 if (class == DLADM_SECOBJ_CLASS_WEP) { 47970ba2cbe9Sxc151355 switch (len) { 47980ba2cbe9Sxc151355 case 5: /* ASCII key sizes */ 47990ba2cbe9Sxc151355 case 13: 48000ba2cbe9Sxc151355 (void) memcpy(obj_val, buf, len); 48010ba2cbe9Sxc151355 *obj_lenp = len; 48020ba2cbe9Sxc151355 break; 48030ba2cbe9Sxc151355 case 10: /* Hex key sizes, not preceded by 0x */ 48040ba2cbe9Sxc151355 case 26: 48050ba2cbe9Sxc151355 error = hexascii_to_octet(buf, len, obj_val, obj_lenp); 48060ba2cbe9Sxc151355 break; 48070ba2cbe9Sxc151355 case 12: /* Hex key sizes, preceded by 0x */ 48080ba2cbe9Sxc151355 case 28: 48090ba2cbe9Sxc151355 if (strncmp(buf, "0x", 2) != 0) 48100ba2cbe9Sxc151355 return (EINVAL); 4811a399b765Szf162725 error = hexascii_to_octet(buf + 2, len - 2, 4812a399b765Szf162725 obj_val, obj_lenp); 48130ba2cbe9Sxc151355 break; 48140ba2cbe9Sxc151355 default: 48150ba2cbe9Sxc151355 return (EINVAL); 48160ba2cbe9Sxc151355 } 48170ba2cbe9Sxc151355 return (error); 48180ba2cbe9Sxc151355 } 48190ba2cbe9Sxc151355 4820a399b765Szf162725 return (ENOENT); 4821a399b765Szf162725 } 4822a399b765Szf162725 48230ba2cbe9Sxc151355 /* ARGSUSED */ 48240ba2cbe9Sxc151355 static void 48250ba2cbe9Sxc151355 defersig(int sig) 48260ba2cbe9Sxc151355 { 48270ba2cbe9Sxc151355 signalled = sig; 48280ba2cbe9Sxc151355 } 48290ba2cbe9Sxc151355 48300ba2cbe9Sxc151355 static int 48310ba2cbe9Sxc151355 get_secobj_from_tty(uint_t try, const char *objname, char *buf) 48320ba2cbe9Sxc151355 { 48330ba2cbe9Sxc151355 uint_t len = 0; 48340ba2cbe9Sxc151355 int c; 48350ba2cbe9Sxc151355 struct termios stored, current; 48360ba2cbe9Sxc151355 void (*sigfunc)(int); 48370ba2cbe9Sxc151355 48380ba2cbe9Sxc151355 /* 48390ba2cbe9Sxc151355 * Turn off echo -- but before we do so, defer SIGINT handling 48400ba2cbe9Sxc151355 * so that a ^C doesn't leave the terminal corrupted. 48410ba2cbe9Sxc151355 */ 48420ba2cbe9Sxc151355 sigfunc = signal(SIGINT, defersig); 48430ba2cbe9Sxc151355 (void) fflush(stdin); 48440ba2cbe9Sxc151355 (void) tcgetattr(0, &stored); 48450ba2cbe9Sxc151355 current = stored; 48460ba2cbe9Sxc151355 current.c_lflag &= ~(ICANON|ECHO); 48470ba2cbe9Sxc151355 current.c_cc[VTIME] = 0; 48480ba2cbe9Sxc151355 current.c_cc[VMIN] = 1; 48490ba2cbe9Sxc151355 (void) tcsetattr(0, TCSANOW, ¤t); 48500ba2cbe9Sxc151355 again: 48510ba2cbe9Sxc151355 if (try == 1) 48520ba2cbe9Sxc151355 (void) printf(gettext("provide value for '%s': "), objname); 48530ba2cbe9Sxc151355 else 48540ba2cbe9Sxc151355 (void) printf(gettext("confirm value for '%s': "), objname); 48550ba2cbe9Sxc151355 48560ba2cbe9Sxc151355 (void) fflush(stdout); 48570ba2cbe9Sxc151355 while (signalled == 0) { 48580ba2cbe9Sxc151355 c = getchar(); 48590ba2cbe9Sxc151355 if (c == '\n' || c == '\r') { 48600ba2cbe9Sxc151355 if (len != 0) 48610ba2cbe9Sxc151355 break; 48620ba2cbe9Sxc151355 (void) putchar('\n'); 48630ba2cbe9Sxc151355 goto again; 48640ba2cbe9Sxc151355 } 48650ba2cbe9Sxc151355 48660ba2cbe9Sxc151355 buf[len++] = c; 48670ba2cbe9Sxc151355 if (len >= DLADM_SECOBJ_VAL_MAX - 1) 48680ba2cbe9Sxc151355 break; 48690ba2cbe9Sxc151355 (void) putchar('*'); 48700ba2cbe9Sxc151355 } 48710ba2cbe9Sxc151355 48720ba2cbe9Sxc151355 (void) putchar('\n'); 48730ba2cbe9Sxc151355 (void) fflush(stdin); 48740ba2cbe9Sxc151355 48750ba2cbe9Sxc151355 /* 48760ba2cbe9Sxc151355 * Restore terminal setting and handle deferred signals. 48770ba2cbe9Sxc151355 */ 48780ba2cbe9Sxc151355 (void) tcsetattr(0, TCSANOW, &stored); 48790ba2cbe9Sxc151355 48800ba2cbe9Sxc151355 (void) signal(SIGINT, sigfunc); 48810ba2cbe9Sxc151355 if (signalled != 0) 48820ba2cbe9Sxc151355 (void) kill(getpid(), signalled); 48830ba2cbe9Sxc151355 48840ba2cbe9Sxc151355 return (len); 48850ba2cbe9Sxc151355 } 48860ba2cbe9Sxc151355 48870ba2cbe9Sxc151355 static int 48880ba2cbe9Sxc151355 get_secobj_val(char *obj_name, uint8_t *obj_val, uint_t *obj_lenp, 48890ba2cbe9Sxc151355 dladm_secobj_class_t class, FILE *filep) 48900ba2cbe9Sxc151355 { 48910ba2cbe9Sxc151355 int rval; 48920ba2cbe9Sxc151355 uint_t len, len2; 48930ba2cbe9Sxc151355 char buf[DLADM_SECOBJ_VAL_MAX], buf2[DLADM_SECOBJ_VAL_MAX]; 48940ba2cbe9Sxc151355 48950ba2cbe9Sxc151355 if (filep == NULL) { 48960ba2cbe9Sxc151355 len = get_secobj_from_tty(1, obj_name, buf); 48970ba2cbe9Sxc151355 rval = convert_secobj(buf, len, obj_val, obj_lenp, class); 48980ba2cbe9Sxc151355 if (rval == 0) { 48990ba2cbe9Sxc151355 len2 = get_secobj_from_tty(2, obj_name, buf2); 49000ba2cbe9Sxc151355 if (len != len2 || memcmp(buf, buf2, len) != 0) 49010ba2cbe9Sxc151355 rval = ENOTSUP; 49020ba2cbe9Sxc151355 } 49030ba2cbe9Sxc151355 return (rval); 49040ba2cbe9Sxc151355 } else { 49050ba2cbe9Sxc151355 for (;;) { 49060ba2cbe9Sxc151355 if (fgets(buf, sizeof (buf), filep) == NULL) 49070ba2cbe9Sxc151355 break; 49080ba2cbe9Sxc151355 if (isspace(buf[0])) 49090ba2cbe9Sxc151355 continue; 49100ba2cbe9Sxc151355 49110ba2cbe9Sxc151355 len = strlen(buf); 49120ba2cbe9Sxc151355 if (buf[len - 1] == '\n') { 49130ba2cbe9Sxc151355 buf[len - 1] = '\0'; 49140ba2cbe9Sxc151355 len--; 49150ba2cbe9Sxc151355 } 49160ba2cbe9Sxc151355 break; 49170ba2cbe9Sxc151355 } 49180ba2cbe9Sxc151355 (void) fclose(filep); 49190ba2cbe9Sxc151355 } 49200ba2cbe9Sxc151355 return (convert_secobj(buf, len, obj_val, obj_lenp, class)); 49210ba2cbe9Sxc151355 } 49220ba2cbe9Sxc151355 49230ba2cbe9Sxc151355 static boolean_t 49240ba2cbe9Sxc151355 check_auth(const char *auth) 49250ba2cbe9Sxc151355 { 49260ba2cbe9Sxc151355 struct passwd *pw; 49270ba2cbe9Sxc151355 49280ba2cbe9Sxc151355 if ((pw = getpwuid(getuid())) == NULL) 49290ba2cbe9Sxc151355 return (B_FALSE); 49300ba2cbe9Sxc151355 49310ba2cbe9Sxc151355 return (chkauthattr(auth, pw->pw_name) != 0); 49320ba2cbe9Sxc151355 } 49330ba2cbe9Sxc151355 49340ba2cbe9Sxc151355 static void 49350ba2cbe9Sxc151355 audit_secobj(char *auth, char *class, char *obj, 49360ba2cbe9Sxc151355 boolean_t success, boolean_t create) 49370ba2cbe9Sxc151355 { 49380ba2cbe9Sxc151355 adt_session_data_t *ah; 49390ba2cbe9Sxc151355 adt_event_data_t *event; 49400ba2cbe9Sxc151355 au_event_t flag; 49410ba2cbe9Sxc151355 char *errstr; 49420ba2cbe9Sxc151355 49430ba2cbe9Sxc151355 if (create) { 49440ba2cbe9Sxc151355 flag = ADT_dladm_create_secobj; 49450ba2cbe9Sxc151355 errstr = "ADT_dladm_create_secobj"; 49460ba2cbe9Sxc151355 } else { 49470ba2cbe9Sxc151355 flag = ADT_dladm_delete_secobj; 49480ba2cbe9Sxc151355 errstr = "ADT_dladm_delete_secobj"; 49490ba2cbe9Sxc151355 } 49500ba2cbe9Sxc151355 495133343a97Smeem if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) 495233343a97Smeem die("adt_start_session: %s", strerror(errno)); 49530ba2cbe9Sxc151355 495433343a97Smeem if ((event = adt_alloc_event(ah, flag)) == NULL) 495533343a97Smeem die("adt_alloc_event (%s): %s", errstr, strerror(errno)); 49560ba2cbe9Sxc151355 49570ba2cbe9Sxc151355 /* fill in audit info */ 49580ba2cbe9Sxc151355 if (create) { 49590ba2cbe9Sxc151355 event->adt_dladm_create_secobj.auth_used = auth; 49600ba2cbe9Sxc151355 event->adt_dladm_create_secobj.obj_class = class; 49610ba2cbe9Sxc151355 event->adt_dladm_create_secobj.obj_name = obj; 49620ba2cbe9Sxc151355 } else { 49630ba2cbe9Sxc151355 event->adt_dladm_delete_secobj.auth_used = auth; 49640ba2cbe9Sxc151355 event->adt_dladm_delete_secobj.obj_class = class; 49650ba2cbe9Sxc151355 event->adt_dladm_delete_secobj.obj_name = obj; 49660ba2cbe9Sxc151355 } 49670ba2cbe9Sxc151355 49680ba2cbe9Sxc151355 if (success) { 49690ba2cbe9Sxc151355 if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) { 497033343a97Smeem die("adt_put_event (%s, success): %s", errstr, 497133343a97Smeem strerror(errno)); 49720ba2cbe9Sxc151355 } 49730ba2cbe9Sxc151355 } else { 49740ba2cbe9Sxc151355 if (adt_put_event(event, ADT_FAILURE, 49750ba2cbe9Sxc151355 ADT_FAIL_VALUE_AUTH) != 0) { 497633343a97Smeem die("adt_put_event: (%s, failure): %s", errstr, 497733343a97Smeem strerror(errno)); 49780ba2cbe9Sxc151355 } 49790ba2cbe9Sxc151355 } 49800ba2cbe9Sxc151355 49810ba2cbe9Sxc151355 adt_free_event(event); 49820ba2cbe9Sxc151355 (void) adt_end_session(ah); 49830ba2cbe9Sxc151355 } 49840ba2cbe9Sxc151355 49850ba2cbe9Sxc151355 #define MAX_SECOBJS 32 49860ba2cbe9Sxc151355 #define MAX_SECOBJ_NAMELEN 32 49870ba2cbe9Sxc151355 static void 49880ba2cbe9Sxc151355 do_create_secobj(int argc, char **argv) 49890ba2cbe9Sxc151355 { 49900ba2cbe9Sxc151355 int option, rval; 49910ba2cbe9Sxc151355 FILE *filep = NULL; 49920ba2cbe9Sxc151355 char *obj_name = NULL; 49930ba2cbe9Sxc151355 char *class_name = NULL; 49940ba2cbe9Sxc151355 uint8_t obj_val[DLADM_SECOBJ_VAL_MAX]; 49950ba2cbe9Sxc151355 uint_t obj_len; 49960ba2cbe9Sxc151355 boolean_t success, temp = B_FALSE; 49970ba2cbe9Sxc151355 dladm_status_t status; 49980ba2cbe9Sxc151355 dladm_secobj_class_t class = -1; 49990ba2cbe9Sxc151355 uid_t euid; 50000ba2cbe9Sxc151355 50010ba2cbe9Sxc151355 opterr = 0; 50020ba2cbe9Sxc151355 (void) memset(obj_val, 0, DLADM_SECOBJ_VAL_MAX); 50030ba2cbe9Sxc151355 while ((option = getopt_long(argc, argv, ":f:c:R:t", 50040ba2cbe9Sxc151355 wifi_longopts, NULL)) != -1) { 50050ba2cbe9Sxc151355 switch (option) { 50060ba2cbe9Sxc151355 case 'f': 50070ba2cbe9Sxc151355 euid = geteuid(); 50080ba2cbe9Sxc151355 (void) seteuid(getuid()); 50090ba2cbe9Sxc151355 filep = fopen(optarg, "r"); 50100ba2cbe9Sxc151355 if (filep == NULL) { 501133343a97Smeem die("cannot open %s: %s", optarg, 501233343a97Smeem strerror(errno)); 50130ba2cbe9Sxc151355 } 50140ba2cbe9Sxc151355 (void) seteuid(euid); 50150ba2cbe9Sxc151355 break; 50160ba2cbe9Sxc151355 case 'c': 50170ba2cbe9Sxc151355 class_name = optarg; 50180ba2cbe9Sxc151355 status = dladm_str2secobjclass(optarg, &class); 50190ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 502033343a97Smeem die("invalid secure object class '%s', " 5021a399b765Szf162725 "valid values are: wep, wpa", optarg); 50220ba2cbe9Sxc151355 } 50230ba2cbe9Sxc151355 break; 50240ba2cbe9Sxc151355 case 't': 50250ba2cbe9Sxc151355 temp = B_TRUE; 50260ba2cbe9Sxc151355 break; 50270ba2cbe9Sxc151355 case 'R': 50280ba2cbe9Sxc151355 status = dladm_set_rootdir(optarg); 50290ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 503033343a97Smeem die_dlerr(status, "invalid directory " 503133343a97Smeem "specified"); 50320ba2cbe9Sxc151355 } 50330ba2cbe9Sxc151355 break; 50340ba2cbe9Sxc151355 default: 503533343a97Smeem die_opterr(optopt, option); 50360ba2cbe9Sxc151355 break; 50370ba2cbe9Sxc151355 } 50380ba2cbe9Sxc151355 } 50390ba2cbe9Sxc151355 50400ba2cbe9Sxc151355 if (optind == (argc - 1)) 50410ba2cbe9Sxc151355 obj_name = argv[optind]; 50420ba2cbe9Sxc151355 else if (optind != argc) 50430ba2cbe9Sxc151355 usage(); 50440ba2cbe9Sxc151355 504533343a97Smeem if (class == -1) 504633343a97Smeem die("secure object class required"); 50470ba2cbe9Sxc151355 504833343a97Smeem if (obj_name == NULL) 504933343a97Smeem die("secure object name required"); 50500ba2cbe9Sxc151355 50510ba2cbe9Sxc151355 success = check_auth(LINK_SEC_AUTH); 50520ba2cbe9Sxc151355 audit_secobj(LINK_SEC_AUTH, class_name, obj_name, success, B_TRUE); 505333343a97Smeem if (!success) 505433343a97Smeem die("authorization '%s' is required", LINK_SEC_AUTH); 50550ba2cbe9Sxc151355 505633343a97Smeem rval = get_secobj_val(obj_name, obj_val, &obj_len, class, filep); 505733343a97Smeem if (rval != 0) { 50580ba2cbe9Sxc151355 switch (rval) { 50590ba2cbe9Sxc151355 case ENOENT: 506033343a97Smeem die("invalid secure object class"); 50610ba2cbe9Sxc151355 break; 50620ba2cbe9Sxc151355 case EINVAL: 506333343a97Smeem die("invalid secure object value"); 50640ba2cbe9Sxc151355 break; 50650ba2cbe9Sxc151355 case ENOTSUP: 506633343a97Smeem die("verification failed"); 50670ba2cbe9Sxc151355 break; 50680ba2cbe9Sxc151355 default: 506933343a97Smeem die("invalid secure object: %s", strerror(rval)); 50700ba2cbe9Sxc151355 break; 50710ba2cbe9Sxc151355 } 50720ba2cbe9Sxc151355 } 50730ba2cbe9Sxc151355 50740ba2cbe9Sxc151355 status = dladm_set_secobj(obj_name, class, obj_val, obj_len, 5075d62bc4baSyz147064 DLADM_OPT_CREATE | DLADM_OPT_ACTIVE); 50760ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 507733343a97Smeem die_dlerr(status, "could not create secure object '%s'", 507833343a97Smeem obj_name); 50790ba2cbe9Sxc151355 } 50800ba2cbe9Sxc151355 if (temp) 50810ba2cbe9Sxc151355 return; 50820ba2cbe9Sxc151355 50830ba2cbe9Sxc151355 status = dladm_set_secobj(obj_name, class, obj_val, obj_len, 50840ba2cbe9Sxc151355 DLADM_OPT_PERSIST); 50850ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 508633343a97Smeem warn_dlerr(status, "could not persistently create secure " 508733343a97Smeem "object '%s'", obj_name); 50880ba2cbe9Sxc151355 } 50890ba2cbe9Sxc151355 } 50900ba2cbe9Sxc151355 50910ba2cbe9Sxc151355 static void 50920ba2cbe9Sxc151355 do_delete_secobj(int argc, char **argv) 50930ba2cbe9Sxc151355 { 50940ba2cbe9Sxc151355 int i, option; 50950ba2cbe9Sxc151355 boolean_t temp = B_FALSE; 50960ba2cbe9Sxc151355 split_t *sp = NULL; 50970ba2cbe9Sxc151355 boolean_t success; 50980ba2cbe9Sxc151355 dladm_status_t status, pstatus; 50990ba2cbe9Sxc151355 51000ba2cbe9Sxc151355 opterr = 0; 51010ba2cbe9Sxc151355 status = pstatus = DLADM_STATUS_OK; 510233343a97Smeem while ((option = getopt_long(argc, argv, ":R:t", 51030ba2cbe9Sxc151355 wifi_longopts, NULL)) != -1) { 51040ba2cbe9Sxc151355 switch (option) { 51050ba2cbe9Sxc151355 case 't': 51060ba2cbe9Sxc151355 temp = B_TRUE; 51070ba2cbe9Sxc151355 break; 51080ba2cbe9Sxc151355 case 'R': 51090ba2cbe9Sxc151355 status = dladm_set_rootdir(optarg); 51100ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 511133343a97Smeem die_dlerr(status, "invalid directory " 511233343a97Smeem "specified"); 51130ba2cbe9Sxc151355 } 51140ba2cbe9Sxc151355 break; 51150ba2cbe9Sxc151355 default: 511633343a97Smeem die_opterr(optopt, option); 51170ba2cbe9Sxc151355 break; 51180ba2cbe9Sxc151355 } 51190ba2cbe9Sxc151355 } 51200ba2cbe9Sxc151355 51210ba2cbe9Sxc151355 if (optind == (argc - 1)) { 51220ba2cbe9Sxc151355 sp = split(argv[optind], MAX_SECOBJS, MAX_SECOBJ_NAMELEN); 51230ba2cbe9Sxc151355 if (sp == NULL) { 512433343a97Smeem die("invalid secure object name(s): '%s'", 512533343a97Smeem argv[optind]); 51260ba2cbe9Sxc151355 } 51270ba2cbe9Sxc151355 } else if (optind != argc) 51280ba2cbe9Sxc151355 usage(); 51290ba2cbe9Sxc151355 513033343a97Smeem if (sp == NULL || sp->s_nfields < 1) 513133343a97Smeem die("secure object name required"); 51320ba2cbe9Sxc151355 51330ba2cbe9Sxc151355 success = check_auth(LINK_SEC_AUTH); 5134a399b765Szf162725 audit_secobj(LINK_SEC_AUTH, "unknown", argv[optind], success, B_FALSE); 513533343a97Smeem if (!success) 513633343a97Smeem die("authorization '%s' is required", LINK_SEC_AUTH); 51370ba2cbe9Sxc151355 51380ba2cbe9Sxc151355 for (i = 0; i < sp->s_nfields; i++) { 5139d62bc4baSyz147064 status = dladm_unset_secobj(sp->s_fields[i], DLADM_OPT_ACTIVE); 51400ba2cbe9Sxc151355 if (!temp) { 51410ba2cbe9Sxc151355 pstatus = dladm_unset_secobj(sp->s_fields[i], 51420ba2cbe9Sxc151355 DLADM_OPT_PERSIST); 51430ba2cbe9Sxc151355 } else { 51440ba2cbe9Sxc151355 pstatus = DLADM_STATUS_OK; 51450ba2cbe9Sxc151355 } 51460ba2cbe9Sxc151355 51470ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 514833343a97Smeem warn_dlerr(status, "could not delete secure object " 514933343a97Smeem "'%s'", sp->s_fields[i]); 51500ba2cbe9Sxc151355 } 51510ba2cbe9Sxc151355 if (pstatus != DLADM_STATUS_OK) { 515233343a97Smeem warn_dlerr(pstatus, "could not persistently delete " 515333343a97Smeem "secure object '%s'", sp->s_fields[i]); 51540ba2cbe9Sxc151355 } 51550ba2cbe9Sxc151355 } 51560ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK || pstatus != DLADM_STATUS_OK) 51570ba2cbe9Sxc151355 exit(1); 51580ba2cbe9Sxc151355 } 51590ba2cbe9Sxc151355 51600ba2cbe9Sxc151355 typedef struct show_secobj_state { 51610ba2cbe9Sxc151355 boolean_t ss_persist; 51620ba2cbe9Sxc151355 boolean_t ss_parseable; 51630ba2cbe9Sxc151355 boolean_t ss_header; 5164*e7801d59Ssowmini print_state_t ss_print; 51650ba2cbe9Sxc151355 } show_secobj_state_t; 51660ba2cbe9Sxc151355 51670ba2cbe9Sxc151355 51680ba2cbe9Sxc151355 static boolean_t 51690ba2cbe9Sxc151355 show_secobj(void *arg, const char *obj_name) 51700ba2cbe9Sxc151355 { 51710ba2cbe9Sxc151355 uint_t obj_len = DLADM_SECOBJ_VAL_MAX; 51720ba2cbe9Sxc151355 uint8_t obj_val[DLADM_SECOBJ_VAL_MAX]; 51730ba2cbe9Sxc151355 char buf[DLADM_STRSIZE]; 51740ba2cbe9Sxc151355 uint_t flags = 0; 51750ba2cbe9Sxc151355 dladm_secobj_class_t class; 51760ba2cbe9Sxc151355 show_secobj_state_t *statep = arg; 51770ba2cbe9Sxc151355 dladm_status_t status; 5178*e7801d59Ssowmini secobj_fields_buf_t sbuf; 51790ba2cbe9Sxc151355 51800ba2cbe9Sxc151355 if (statep->ss_persist) 51810ba2cbe9Sxc151355 flags |= DLADM_OPT_PERSIST; 51820ba2cbe9Sxc151355 51830ba2cbe9Sxc151355 status = dladm_get_secobj(obj_name, &class, obj_val, &obj_len, flags); 518433343a97Smeem if (status != DLADM_STATUS_OK) 518533343a97Smeem die_dlerr(status, "cannot get secure object '%s'", obj_name); 51860ba2cbe9Sxc151355 51870ba2cbe9Sxc151355 if (statep->ss_header) { 51880ba2cbe9Sxc151355 statep->ss_header = B_FALSE; 51890ba2cbe9Sxc151355 if (!statep->ss_parseable) 5190*e7801d59Ssowmini print_header(&statep->ss_print); 51910ba2cbe9Sxc151355 } 51920ba2cbe9Sxc151355 5193*e7801d59Ssowmini (void) snprintf(sbuf.ss_obj_name, sizeof (sbuf.ss_obj_name), 5194*e7801d59Ssowmini obj_name); 5195*e7801d59Ssowmini (void) dladm_secobjclass2str(class, buf); 5196*e7801d59Ssowmini (void) snprintf(sbuf.ss_class, sizeof (sbuf.ss_class), "%s", buf); 5197*e7801d59Ssowmini if (getuid() == 0) { 51980ba2cbe9Sxc151355 char val[DLADM_SECOBJ_VAL_MAX * 2]; 51990ba2cbe9Sxc151355 uint_t len = sizeof (val); 52000ba2cbe9Sxc151355 5201*e7801d59Ssowmini if (octet_to_hexascii(obj_val, obj_len, val, &len) == 0) 5202*e7801d59Ssowmini (void) snprintf(sbuf.ss_val, 5203*e7801d59Ssowmini sizeof (sbuf.ss_val), "%s", val); 52040ba2cbe9Sxc151355 } 5205*e7801d59Ssowmini dladm_print_output(&statep->ss_print, statep->ss_parseable, 5206*e7801d59Ssowmini dladm_print_field, (void *)&sbuf); 52070ba2cbe9Sxc151355 return (B_TRUE); 52080ba2cbe9Sxc151355 } 52090ba2cbe9Sxc151355 52100ba2cbe9Sxc151355 static void 52110ba2cbe9Sxc151355 do_show_secobj(int argc, char **argv) 52120ba2cbe9Sxc151355 { 52130ba2cbe9Sxc151355 int option; 52140ba2cbe9Sxc151355 show_secobj_state_t state; 52150ba2cbe9Sxc151355 dladm_status_t status; 52160ba2cbe9Sxc151355 uint_t i; 52170ba2cbe9Sxc151355 split_t *sp; 52180ba2cbe9Sxc151355 uint_t flags; 5219*e7801d59Ssowmini char *fields_str = NULL; 5220*e7801d59Ssowmini print_field_t **fields; 5221*e7801d59Ssowmini uint_t nfields; 5222*e7801d59Ssowmini char *def_fields = "object,class"; 5223*e7801d59Ssowmini char *all_fields = "object,class,value"; 52240ba2cbe9Sxc151355 52250ba2cbe9Sxc151355 opterr = 0; 5226*e7801d59Ssowmini bzero(&state, sizeof (state)); 5227*e7801d59Ssowmini state.ss_parseable = B_FALSE; 5228*e7801d59Ssowmini fields_str = def_fields; 52290ba2cbe9Sxc151355 state.ss_persist = B_FALSE; 52300ba2cbe9Sxc151355 state.ss_parseable = B_FALSE; 52310ba2cbe9Sxc151355 state.ss_header = B_TRUE; 5232*e7801d59Ssowmini while ((option = getopt_long(argc, argv, ":pPo:", 52330ba2cbe9Sxc151355 wifi_longopts, NULL)) != -1) { 52340ba2cbe9Sxc151355 switch (option) { 52350ba2cbe9Sxc151355 case 'p': 52360ba2cbe9Sxc151355 state.ss_parseable = B_TRUE; 52370ba2cbe9Sxc151355 break; 52380ba2cbe9Sxc151355 case 'P': 52390ba2cbe9Sxc151355 state.ss_persist = B_TRUE; 52400ba2cbe9Sxc151355 break; 5241*e7801d59Ssowmini case 'o': 5242*e7801d59Ssowmini if (strcasecmp(optarg, "all") == 0) 5243*e7801d59Ssowmini fields_str = all_fields; 5244*e7801d59Ssowmini else 5245*e7801d59Ssowmini fields_str = optarg; 52460ba2cbe9Sxc151355 break; 52470ba2cbe9Sxc151355 default: 524833343a97Smeem die_opterr(optopt, option); 52490ba2cbe9Sxc151355 break; 52500ba2cbe9Sxc151355 } 52510ba2cbe9Sxc151355 } 52520ba2cbe9Sxc151355 5253*e7801d59Ssowmini fields = parse_output_fields(fields_str, secobj_fields, 5254*e7801d59Ssowmini DEV_SOBJ_FIELDS, CMD_TYPE_ANY, &nfields); 5255*e7801d59Ssowmini 5256*e7801d59Ssowmini if (fields == NULL) { 5257*e7801d59Ssowmini die("invalid field(s) specified"); 5258*e7801d59Ssowmini return; 5259*e7801d59Ssowmini } 5260*e7801d59Ssowmini state.ss_print.ps_fields = fields; 5261*e7801d59Ssowmini state.ss_print.ps_nfields = nfields; 5262*e7801d59Ssowmini 5263*e7801d59Ssowmini flags = state.ss_persist ? DLADM_OPT_PERSIST : 0; 52640ba2cbe9Sxc151355 if (optind == (argc - 1)) { 52650ba2cbe9Sxc151355 sp = split(argv[optind], MAX_SECOBJS, MAX_SECOBJ_NAMELEN); 52660ba2cbe9Sxc151355 if (sp == NULL) { 526733343a97Smeem die("invalid secure object name(s): '%s'", 526833343a97Smeem argv[optind]); 52690ba2cbe9Sxc151355 } 52700ba2cbe9Sxc151355 for (i = 0; i < sp->s_nfields; i++) { 52710ba2cbe9Sxc151355 if (!show_secobj(&state, sp->s_fields[i])) 52720ba2cbe9Sxc151355 break; 52730ba2cbe9Sxc151355 } 52740ba2cbe9Sxc151355 splitfree(sp); 52750ba2cbe9Sxc151355 return; 52760ba2cbe9Sxc151355 } else if (optind != argc) 52770ba2cbe9Sxc151355 usage(); 52780ba2cbe9Sxc151355 52790ba2cbe9Sxc151355 status = dladm_walk_secobj(&state, show_secobj, flags); 528033343a97Smeem if (status != DLADM_STATUS_OK) 528133343a97Smeem die_dlerr(status, "show-secobj"); 52820ba2cbe9Sxc151355 } 52830ba2cbe9Sxc151355 52840ba2cbe9Sxc151355 /*ARGSUSED*/ 5285d62bc4baSyz147064 static int 5286d62bc4baSyz147064 i_dladm_init_linkprop(datalink_id_t linkid, void *arg) 5287d62bc4baSyz147064 { 5288d62bc4baSyz147064 (void) dladm_init_linkprop(linkid); 5289d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 5290d62bc4baSyz147064 } 5291d62bc4baSyz147064 5292d62bc4baSyz147064 /* ARGSUSED */ 52930ba2cbe9Sxc151355 static void 52940ba2cbe9Sxc151355 do_init_linkprop(int argc, char **argv) 52950ba2cbe9Sxc151355 { 5296d62bc4baSyz147064 /* 5297d62bc4baSyz147064 * linkprops of links of other classes have been initialized as a 5298d62bc4baSyz147064 * part of the dladm up-xxx operation. 5299d62bc4baSyz147064 */ 5300d62bc4baSyz147064 (void) dladm_walk_datalink_id(i_dladm_init_linkprop, NULL, 5301d62bc4baSyz147064 DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 53020ba2cbe9Sxc151355 } 53030ba2cbe9Sxc151355 53040ba2cbe9Sxc151355 /* ARGSUSED */ 53050ba2cbe9Sxc151355 static void 5306*e7801d59Ssowmini do_show_ether(int argc, char **argv) 5307*e7801d59Ssowmini { 5308*e7801d59Ssowmini int option; 5309*e7801d59Ssowmini datalink_id_t linkid; 5310*e7801d59Ssowmini print_ether_state_t state; 5311*e7801d59Ssowmini print_field_t **fields; 5312*e7801d59Ssowmini char *fields_str; 5313*e7801d59Ssowmini uint_t nfields; 5314*e7801d59Ssowmini char *all_fields = 5315*e7801d59Ssowmini "link,ptype,state,auto,speed-duplex,pause,rem_fault"; 5316*e7801d59Ssowmini char *default_fields = 5317*e7801d59Ssowmini "link,ptype,state,auto,speed-duplex,pause"; 5318*e7801d59Ssowmini 5319*e7801d59Ssowmini fields_str = default_fields; 5320*e7801d59Ssowmini bzero(&state, sizeof (state)); 5321*e7801d59Ssowmini state.es_link = NULL; 5322*e7801d59Ssowmini state.es_parseable = B_FALSE; 5323*e7801d59Ssowmini 5324*e7801d59Ssowmini while ((option = getopt_long(argc, argv, "o:px", 5325*e7801d59Ssowmini showeth_lopts, NULL)) != -1) { 5326*e7801d59Ssowmini switch (option) { 5327*e7801d59Ssowmini case 'x': 5328*e7801d59Ssowmini state.es_extended = B_TRUE; 5329*e7801d59Ssowmini break; 5330*e7801d59Ssowmini case 'p': 5331*e7801d59Ssowmini state.es_parseable = B_TRUE; 5332*e7801d59Ssowmini break; 5333*e7801d59Ssowmini case 'o': 5334*e7801d59Ssowmini if (strcasecmp(optarg, "all") == 0) 5335*e7801d59Ssowmini fields_str = all_fields; 5336*e7801d59Ssowmini else 5337*e7801d59Ssowmini fields_str = optarg; 5338*e7801d59Ssowmini break; 5339*e7801d59Ssowmini default: 5340*e7801d59Ssowmini die_opterr(optopt, option); 5341*e7801d59Ssowmini break; 5342*e7801d59Ssowmini } 5343*e7801d59Ssowmini } 5344*e7801d59Ssowmini 5345*e7801d59Ssowmini if (optind == (argc - 1)) 5346*e7801d59Ssowmini state.es_link = argv[optind]; 5347*e7801d59Ssowmini 5348*e7801d59Ssowmini fields = parse_output_fields(fields_str, ether_fields, 5349*e7801d59Ssowmini ETHER_MAX_FIELDS, CMD_TYPE_ANY, &nfields); 5350*e7801d59Ssowmini 5351*e7801d59Ssowmini if (fields == NULL) { 5352*e7801d59Ssowmini die("invalid field(s) specified"); 5353*e7801d59Ssowmini exit(EXIT_FAILURE); 5354*e7801d59Ssowmini } 5355*e7801d59Ssowmini state.es_print.ps_fields = fields; 5356*e7801d59Ssowmini state.es_print.ps_nfields = nfields; 5357*e7801d59Ssowmini 5358*e7801d59Ssowmini if (state.es_link == NULL) { 5359*e7801d59Ssowmini (void) dladm_walk_datalink_id(show_etherprop, &state, 5360*e7801d59Ssowmini DATALINK_CLASS_PHYS, DL_ETHER, 5361*e7801d59Ssowmini DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST); 5362*e7801d59Ssowmini } else { 5363*e7801d59Ssowmini if (!link_is_ether(state.es_link, &linkid)) { 5364*e7801d59Ssowmini die("invalid link specified"); 5365*e7801d59Ssowmini } 5366*e7801d59Ssowmini (void) show_etherprop(linkid, &state); 5367*e7801d59Ssowmini } 5368*e7801d59Ssowmini 5369*e7801d59Ssowmini exit(DLADM_STATUS_OK); 5370*e7801d59Ssowmini 5371*e7801d59Ssowmini } 5372*e7801d59Ssowmini 5373*e7801d59Ssowmini static char * 5374*e7801d59Ssowmini dladm_print_field(print_field_t *pf, void *arg) 5375*e7801d59Ssowmini { 5376*e7801d59Ssowmini char *value; 5377*e7801d59Ssowmini 5378*e7801d59Ssowmini value = (char *)arg + pf->pf_offset; 5379*e7801d59Ssowmini return (value); 5380*e7801d59Ssowmini } 5381*e7801d59Ssowmini 5382*e7801d59Ssowmini static int 5383*e7801d59Ssowmini show_etherprop(datalink_id_t linkid, void *arg) 5384*e7801d59Ssowmini { 5385*e7801d59Ssowmini print_ether_state_t *statep = arg; 5386*e7801d59Ssowmini char buf[DLADM_STRSIZE]; 5387*e7801d59Ssowmini int speed; 5388*e7801d59Ssowmini uint64_t s; 5389*e7801d59Ssowmini uint32_t autoneg, pause, asmpause, adv_rf, cap_rf, lp_rf; 5390*e7801d59Ssowmini ether_fields_buf_t ebuf; 5391*e7801d59Ssowmini char speed_unit = 'M'; 5392*e7801d59Ssowmini 5393*e7801d59Ssowmini if (dladm_datalink_id2info(linkid, NULL, NULL, NULL, 5394*e7801d59Ssowmini ebuf.eth_link, sizeof (ebuf.eth_link)) != DLADM_STATUS_OK) { 5395*e7801d59Ssowmini return (DLADM_WALK_CONTINUE); 5396*e7801d59Ssowmini } 5397*e7801d59Ssowmini 5398*e7801d59Ssowmini if (!statep->es_header && !statep->es_parseable) { 5399*e7801d59Ssowmini print_header(&statep->es_print); 5400*e7801d59Ssowmini statep->es_header = B_TRUE; 5401*e7801d59Ssowmini } 5402*e7801d59Ssowmini (void) snprintf(ebuf.eth_ptype, sizeof (ebuf.eth_ptype), 5403*e7801d59Ssowmini "%s", "current"); 5404*e7801d59Ssowmini 5405*e7801d59Ssowmini (void) dladm_get_single_mac_stat(linkid, "link_autoneg", 5406*e7801d59Ssowmini KSTAT_DATA_UINT32, &autoneg); 5407*e7801d59Ssowmini (void) snprintf(ebuf.eth_autoneg, sizeof (ebuf.eth_autoneg), 5408*e7801d59Ssowmini "%s", (autoneg ? "yes" : "no")); 5409*e7801d59Ssowmini 5410*e7801d59Ssowmini (void) dladm_get_single_mac_stat(linkid, "link_pause", 5411*e7801d59Ssowmini KSTAT_DATA_UINT32, &pause); 5412*e7801d59Ssowmini (void) dladm_get_single_mac_stat(linkid, "link_asmpause", 5413*e7801d59Ssowmini KSTAT_DATA_UINT32, &asmpause); 5414*e7801d59Ssowmini (void) snprintf(ebuf.eth_pause, sizeof (ebuf.eth_pause), 5415*e7801d59Ssowmini "%s", pause_str(pause, asmpause)); 5416*e7801d59Ssowmini 5417*e7801d59Ssowmini (void) dladm_get_single_mac_stat(linkid, "ifspeed", 5418*e7801d59Ssowmini KSTAT_DATA_UINT64, &s); 5419*e7801d59Ssowmini speed = (int)(s/1000000ull); 5420*e7801d59Ssowmini 5421*e7801d59Ssowmini if (speed >= 1000) { 5422*e7801d59Ssowmini speed = speed/1000; 5423*e7801d59Ssowmini speed_unit = 'G'; 5424*e7801d59Ssowmini } 5425*e7801d59Ssowmini (void) get_linkduplex(ebuf.eth_link, B_FALSE, buf); 5426*e7801d59Ssowmini (void) snprintf(ebuf.eth_spdx, sizeof (ebuf.eth_spdx), "%d%c-%c", 5427*e7801d59Ssowmini speed, speed_unit, buf[0]); 5428*e7801d59Ssowmini 5429*e7801d59Ssowmini (void) get_linkstate(ebuf.eth_link, B_FALSE, buf); 5430*e7801d59Ssowmini (void) snprintf(ebuf.eth_state, sizeof (ebuf.eth_state), 5431*e7801d59Ssowmini "%s", buf); 5432*e7801d59Ssowmini 5433*e7801d59Ssowmini (void) dladm_get_single_mac_stat(linkid, "adv_rem_fault", 5434*e7801d59Ssowmini KSTAT_DATA_UINT32, &adv_rf); 5435*e7801d59Ssowmini (void) dladm_get_single_mac_stat(linkid, "cap_rem_fault", 5436*e7801d59Ssowmini KSTAT_DATA_UINT32, &cap_rf); 5437*e7801d59Ssowmini (void) dladm_get_single_mac_stat(linkid, "lp_rem_fault", 5438*e7801d59Ssowmini KSTAT_DATA_UINT32, &lp_rf); 5439*e7801d59Ssowmini (void) snprintf(ebuf.eth_rem_fault, sizeof (ebuf.eth_rem_fault), 5440*e7801d59Ssowmini "%s", (adv_rf == 0 && lp_rf == 0 ? "none" : "fault")); 5441*e7801d59Ssowmini 5442*e7801d59Ssowmini dladm_print_output(&statep->es_print, statep->es_parseable, 5443*e7801d59Ssowmini dladm_print_field, &ebuf); 5444*e7801d59Ssowmini 5445*e7801d59Ssowmini if (statep->es_extended) 5446*e7801d59Ssowmini show_ether_xprop(linkid, arg); 5447*e7801d59Ssowmini 5448*e7801d59Ssowmini return (DLADM_WALK_CONTINUE); 5449*e7801d59Ssowmini } 5450*e7801d59Ssowmini 5451*e7801d59Ssowmini /* ARGSUSED */ 5452*e7801d59Ssowmini static void 54530ba2cbe9Sxc151355 do_init_secobj(int argc, char **argv) 54540ba2cbe9Sxc151355 { 54550ba2cbe9Sxc151355 dladm_status_t status; 54560ba2cbe9Sxc151355 54570ba2cbe9Sxc151355 status = dladm_init_secobj(); 545833343a97Smeem if (status != DLADM_STATUS_OK) 545933343a97Smeem die_dlerr(status, "secure object initialization failed"); 546033343a97Smeem } 546133343a97Smeem 5462d62bc4baSyz147064 /* 5463d62bc4baSyz147064 * "-R" option support. It is used for live upgrading. Append dladm commands 5464d62bc4baSyz147064 * to a upgrade script which will be run when the alternative root boots up: 5465d62bc4baSyz147064 * 5466d62bc4baSyz147064 * - If the dlmgmtd door file exists on the alternative root, append dladm 5467d62bc4baSyz147064 * commands to the <altroot>/var/svc/profile/upgrade_datalink script. This 5468d62bc4baSyz147064 * script will be run as part of the network/physical service. We cannot defer 5469d62bc4baSyz147064 * this to /var/svc/profile/upgrade because then the configuration will not 5470d62bc4baSyz147064 * be able to take effect before network/physical plumbs various interfaces. 5471d62bc4baSyz147064 * 5472d62bc4baSyz147064 * - If the dlmgmtd door file does not exist on the alternative root, append 5473d62bc4baSyz147064 * dladm commands to the <altroot>/var/svc/profile/upgrade script, which will 5474d62bc4baSyz147064 * be run in the manifest-import service. 5475d62bc4baSyz147064 * 5476d62bc4baSyz147064 * Note that the SMF team is considering to move the manifest-import service 5477d62bc4baSyz147064 * to be run at the very begining of boot. Once that is done, the need for 5478d62bc4baSyz147064 * the /var/svc/profile/upgrade_datalink script will not exist any more. 5479d62bc4baSyz147064 */ 5480d62bc4baSyz147064 static void 5481d62bc4baSyz147064 altroot_cmd(char *altroot, int argc, char *argv[]) 5482d62bc4baSyz147064 { 5483d62bc4baSyz147064 char path[MAXPATHLEN]; 5484d62bc4baSyz147064 struct stat stbuf; 5485d62bc4baSyz147064 FILE *fp; 5486d62bc4baSyz147064 int i; 5487d62bc4baSyz147064 5488d62bc4baSyz147064 /* 5489d62bc4baSyz147064 * Check for the existence of the dlmgmtd door file, and determine 5490d62bc4baSyz147064 * the name of script file. 5491d62bc4baSyz147064 */ 5492d62bc4baSyz147064 (void) snprintf(path, MAXPATHLEN, "/%s/%s", altroot, DLMGMT_DOOR); 5493d62bc4baSyz147064 if (stat(path, &stbuf) < 0) { 5494d62bc4baSyz147064 (void) snprintf(path, MAXPATHLEN, "/%s/%s", altroot, 5495d62bc4baSyz147064 SMF_UPGRADE_FILE); 5496d62bc4baSyz147064 } else { 5497d62bc4baSyz147064 (void) snprintf(path, MAXPATHLEN, "/%s/%s", altroot, 5498d62bc4baSyz147064 SMF_UPGRADEDATALINK_FILE); 5499d62bc4baSyz147064 } 5500d62bc4baSyz147064 5501d62bc4baSyz147064 if ((fp = fopen(path, "a+")) == NULL) 5502d62bc4baSyz147064 die("operation not supported on %s", altroot); 5503d62bc4baSyz147064 5504d62bc4baSyz147064 (void) fprintf(fp, "/sbin/dladm "); 5505d62bc4baSyz147064 for (i = 0; i < argc; i++) { 5506d62bc4baSyz147064 /* 5507d62bc4baSyz147064 * Directly write to the file if it is not the "-R <altroot>" 5508d62bc4baSyz147064 * option. In which case, skip it. 5509d62bc4baSyz147064 */ 5510d62bc4baSyz147064 if (strcmp(argv[i], "-R") != 0) 5511d62bc4baSyz147064 (void) fprintf(fp, "%s ", argv[i]); 5512d62bc4baSyz147064 else 5513d62bc4baSyz147064 i ++; 5514d62bc4baSyz147064 } 5515d62bc4baSyz147064 (void) fprintf(fp, "%s\n", SMF_DLADM_UPGRADE_MSG); 5516d62bc4baSyz147064 (void) fclose(fp); 5517d62bc4baSyz147064 exit(0); 5518d62bc4baSyz147064 } 5519d62bc4baSyz147064 5520d62bc4baSyz147064 /* 5521d62bc4baSyz147064 * Convert the string to an integer. Note that the string must not have any 5522d62bc4baSyz147064 * trailing non-integer characters. 5523d62bc4baSyz147064 */ 552433343a97Smeem static boolean_t 552533343a97Smeem str2int(const char *str, int *valp) 552633343a97Smeem { 552733343a97Smeem int val; 552833343a97Smeem char *endp = NULL; 552933343a97Smeem 553033343a97Smeem errno = 0; 553133343a97Smeem val = strtol(str, &endp, 10); 553233343a97Smeem if (errno != 0 || *endp != '\0') 553333343a97Smeem return (B_FALSE); 553433343a97Smeem 553533343a97Smeem *valp = val; 553633343a97Smeem return (B_TRUE); 553733343a97Smeem } 553833343a97Smeem 553933343a97Smeem /* PRINTFLIKE1 */ 554033343a97Smeem static void 554133343a97Smeem warn(const char *format, ...) 554233343a97Smeem { 554333343a97Smeem va_list alist; 554433343a97Smeem 554533343a97Smeem format = gettext(format); 554633343a97Smeem (void) fprintf(stderr, "%s: warning: ", progname); 554733343a97Smeem 554833343a97Smeem va_start(alist, format); 554933343a97Smeem (void) vfprintf(stderr, format, alist); 555033343a97Smeem va_end(alist); 555133343a97Smeem 555233343a97Smeem (void) putchar('\n'); 555333343a97Smeem } 555433343a97Smeem 555533343a97Smeem /* PRINTFLIKE2 */ 555633343a97Smeem static void 555733343a97Smeem warn_dlerr(dladm_status_t err, const char *format, ...) 555833343a97Smeem { 555933343a97Smeem va_list alist; 556033343a97Smeem char errmsg[DLADM_STRSIZE]; 556133343a97Smeem 556233343a97Smeem format = gettext(format); 556333343a97Smeem (void) fprintf(stderr, gettext("%s: warning: "), progname); 556433343a97Smeem 556533343a97Smeem va_start(alist, format); 556633343a97Smeem (void) vfprintf(stderr, format, alist); 556733343a97Smeem va_end(alist); 556833343a97Smeem (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg)); 556933343a97Smeem } 557033343a97Smeem 557133343a97Smeem /* PRINTFLIKE2 */ 557233343a97Smeem static void 557333343a97Smeem die_dlerr(dladm_status_t err, const char *format, ...) 557433343a97Smeem { 557533343a97Smeem va_list alist; 557633343a97Smeem char errmsg[DLADM_STRSIZE]; 557733343a97Smeem 557833343a97Smeem format = gettext(format); 557933343a97Smeem (void) fprintf(stderr, "%s: ", progname); 558033343a97Smeem 558133343a97Smeem va_start(alist, format); 558233343a97Smeem (void) vfprintf(stderr, format, alist); 558333343a97Smeem va_end(alist); 558433343a97Smeem (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg)); 558533343a97Smeem 558633343a97Smeem exit(EXIT_FAILURE); 558733343a97Smeem } 558833343a97Smeem 558933343a97Smeem /* PRINTFLIKE1 */ 559033343a97Smeem static void 559133343a97Smeem die(const char *format, ...) 559233343a97Smeem { 559333343a97Smeem va_list alist; 559433343a97Smeem 559533343a97Smeem format = gettext(format); 559633343a97Smeem (void) fprintf(stderr, "%s: ", progname); 559733343a97Smeem 559833343a97Smeem va_start(alist, format); 559933343a97Smeem (void) vfprintf(stderr, format, alist); 560033343a97Smeem va_end(alist); 560133343a97Smeem 560233343a97Smeem (void) putchar('\n'); 560333343a97Smeem exit(EXIT_FAILURE); 560433343a97Smeem } 560533343a97Smeem 560633343a97Smeem static void 560733343a97Smeem die_optdup(int opt) 560833343a97Smeem { 560933343a97Smeem die("the option -%c cannot be specified more than once", opt); 561033343a97Smeem } 561133343a97Smeem 561233343a97Smeem static void 561333343a97Smeem die_opterr(int opt, int opterr) 561433343a97Smeem { 561533343a97Smeem switch (opterr) { 561633343a97Smeem case ':': 561733343a97Smeem die("option '-%c' requires a value", opt); 561833343a97Smeem break; 561933343a97Smeem case '?': 562033343a97Smeem default: 562133343a97Smeem die("unrecognized option '-%c'", opt); 562233343a97Smeem break; 56230ba2cbe9Sxc151355 } 56240ba2cbe9Sxc151355 } 5625*e7801d59Ssowmini 5626*e7801d59Ssowmini static void 5627*e7801d59Ssowmini show_ether_xprop(datalink_id_t linkid, void *arg) 5628*e7801d59Ssowmini { 5629*e7801d59Ssowmini print_ether_state_t *statep = arg; 5630*e7801d59Ssowmini char buf[DLADM_STRSIZE]; 5631*e7801d59Ssowmini uint32_t autoneg, pause, asmpause, adv_rf, cap_rf, lp_rf; 5632*e7801d59Ssowmini boolean_t add_comma, r1; 5633*e7801d59Ssowmini ether_fields_buf_t ebuf; 5634*e7801d59Ssowmini 5635*e7801d59Ssowmini /* capable */ 5636*e7801d59Ssowmini bzero(&ebuf, sizeof (ebuf)); 5637*e7801d59Ssowmini (void) snprintf(ebuf.eth_link, sizeof (ebuf.eth_link), ""); 5638*e7801d59Ssowmini 5639*e7801d59Ssowmini (void) snprintf(ebuf.eth_ptype, sizeof (ebuf.eth_ptype), 5640*e7801d59Ssowmini "%s", "capable"); 5641*e7801d59Ssowmini (void) snprintf(ebuf.eth_state, sizeof (ebuf.eth_state), 5642*e7801d59Ssowmini STR_UNDEF_VAL); 5643*e7801d59Ssowmini 5644*e7801d59Ssowmini (void) dladm_get_single_mac_stat(linkid, "cap_autoneg", 5645*e7801d59Ssowmini KSTAT_DATA_UINT32, &autoneg); 5646*e7801d59Ssowmini (void) snprintf(ebuf.eth_autoneg, sizeof (ebuf.eth_autoneg), 5647*e7801d59Ssowmini "%s", (autoneg ? "yes" : "no")); 5648*e7801d59Ssowmini 5649*e7801d59Ssowmini add_comma = B_FALSE; 5650*e7801d59Ssowmini bzero(buf, sizeof (buf)); 5651*e7801d59Ssowmini r1 = get_speed_duplex(linkid, "cap_1000", buf, "1G", B_FALSE); 5652*e7801d59Ssowmini if (r1) 5653*e7801d59Ssowmini add_comma = B_TRUE; 5654*e7801d59Ssowmini r1 = get_speed_duplex(linkid, "cap_100", buf, "100M", add_comma); 5655*e7801d59Ssowmini if (r1) 5656*e7801d59Ssowmini add_comma = B_TRUE; 5657*e7801d59Ssowmini r1 = get_speed_duplex(linkid, "cap_10", buf, "10M", add_comma); 5658*e7801d59Ssowmini add_comma = B_FALSE; 5659*e7801d59Ssowmini (void) snprintf(ebuf.eth_spdx, sizeof (ebuf.eth_spdx), "%s", buf); 5660*e7801d59Ssowmini 5661*e7801d59Ssowmini (void) dladm_get_single_mac_stat(linkid, "cap_pause", 5662*e7801d59Ssowmini KSTAT_DATA_UINT32, &pause); 5663*e7801d59Ssowmini (void) dladm_get_single_mac_stat(linkid, "cap_asmpause", 5664*e7801d59Ssowmini KSTAT_DATA_UINT32, &asmpause); 5665*e7801d59Ssowmini (void) snprintf(ebuf.eth_pause, sizeof (ebuf.eth_pause), 5666*e7801d59Ssowmini "%s", pause_str(pause, asmpause)); 5667*e7801d59Ssowmini 5668*e7801d59Ssowmini (void) dladm_get_single_mac_stat(linkid, "adv_rem_fault", 5669*e7801d59Ssowmini KSTAT_DATA_UINT32, &adv_rf); 5670*e7801d59Ssowmini (void) dladm_get_single_mac_stat(linkid, "cap_rem_fault", 5671*e7801d59Ssowmini KSTAT_DATA_UINT32, &cap_rf); 5672*e7801d59Ssowmini (void) dladm_get_single_mac_stat(linkid, "lp_rem_fault", 5673*e7801d59Ssowmini KSTAT_DATA_UINT32, &lp_rf); 5674*e7801d59Ssowmini 5675*e7801d59Ssowmini (void) snprintf(ebuf.eth_rem_fault, sizeof (ebuf.eth_rem_fault), 5676*e7801d59Ssowmini "%s", (cap_rf ? "yes" : "no")); 5677*e7801d59Ssowmini 5678*e7801d59Ssowmini dladm_print_output(&statep->es_print, statep->es_parseable, 5679*e7801d59Ssowmini dladm_print_field, &ebuf); 5680*e7801d59Ssowmini 5681*e7801d59Ssowmini /* advertised */ 5682*e7801d59Ssowmini bzero(&ebuf, sizeof (ebuf)); 5683*e7801d59Ssowmini (void) snprintf(ebuf.eth_ptype, sizeof (ebuf.eth_ptype), 5684*e7801d59Ssowmini "%s", "adv"); 5685*e7801d59Ssowmini (void) snprintf(ebuf.eth_state, sizeof (ebuf.eth_state), 5686*e7801d59Ssowmini STR_UNDEF_VAL); 5687*e7801d59Ssowmini 5688*e7801d59Ssowmini (void) dladm_get_single_mac_stat(linkid, "adv_cap_autoneg", 5689*e7801d59Ssowmini KSTAT_DATA_UINT32, &autoneg); 5690*e7801d59Ssowmini (void) snprintf(ebuf.eth_autoneg, sizeof (ebuf.eth_autoneg), 5691*e7801d59Ssowmini "%s", (autoneg ? "yes" : "no")); 5692*e7801d59Ssowmini 5693*e7801d59Ssowmini add_comma = B_FALSE; 5694*e7801d59Ssowmini bzero(buf, sizeof (buf)); 5695*e7801d59Ssowmini r1 = get_speed_duplex(linkid, "adv_cap_1000", buf, "1G", add_comma); 5696*e7801d59Ssowmini if (r1) 5697*e7801d59Ssowmini add_comma = B_TRUE; 5698*e7801d59Ssowmini r1 = get_speed_duplex(linkid, "adv_cap_100", buf, "100M", add_comma); 5699*e7801d59Ssowmini if (r1) 5700*e7801d59Ssowmini add_comma = B_TRUE; 5701*e7801d59Ssowmini r1 = get_speed_duplex(linkid, "adv_cap_10", buf, "10M", add_comma); 5702*e7801d59Ssowmini add_comma = B_FALSE; 5703*e7801d59Ssowmini (void) snprintf(ebuf.eth_spdx, sizeof (ebuf.eth_spdx), "%s", buf); 5704*e7801d59Ssowmini 5705*e7801d59Ssowmini (void) dladm_get_single_mac_stat(linkid, "adv_cap_pause", 5706*e7801d59Ssowmini KSTAT_DATA_UINT32, &pause); 5707*e7801d59Ssowmini (void) dladm_get_single_mac_stat(linkid, "adv_cap_asmpause", 5708*e7801d59Ssowmini KSTAT_DATA_UINT32, &asmpause); 5709*e7801d59Ssowmini (void) snprintf(ebuf.eth_pause, sizeof (ebuf.eth_pause), 5710*e7801d59Ssowmini "%s", pause_str(pause, asmpause)); 5711*e7801d59Ssowmini 5712*e7801d59Ssowmini (void) snprintf(ebuf.eth_rem_fault, sizeof (ebuf.eth_rem_fault), 5713*e7801d59Ssowmini "%s", (adv_rf ? "fault" : "none")); 5714*e7801d59Ssowmini 5715*e7801d59Ssowmini dladm_print_output(&statep->es_print, statep->es_parseable, 5716*e7801d59Ssowmini dladm_print_field, &ebuf); 5717*e7801d59Ssowmini 5718*e7801d59Ssowmini /* peeradv */ 5719*e7801d59Ssowmini bzero(&ebuf, sizeof (ebuf)); 5720*e7801d59Ssowmini (void) snprintf(ebuf.eth_ptype, sizeof (ebuf.eth_ptype), 5721*e7801d59Ssowmini "%s", "peeradv"); 5722*e7801d59Ssowmini (void) snprintf(ebuf.eth_state, sizeof (ebuf.eth_state), 5723*e7801d59Ssowmini STR_UNDEF_VAL); 5724*e7801d59Ssowmini 5725*e7801d59Ssowmini (void) dladm_get_single_mac_stat(linkid, "lp_cap_autoneg", 5726*e7801d59Ssowmini KSTAT_DATA_UINT32, &autoneg); 5727*e7801d59Ssowmini (void) snprintf(ebuf.eth_autoneg, sizeof (ebuf.eth_autoneg), 5728*e7801d59Ssowmini "%s", (autoneg ? "yes" : "no")); 5729*e7801d59Ssowmini 5730*e7801d59Ssowmini add_comma = B_FALSE; 5731*e7801d59Ssowmini bzero(buf, sizeof (buf)); 5732*e7801d59Ssowmini r1 = get_speed_duplex(linkid, "lp_cap_1000", buf, "1G", add_comma); 5733*e7801d59Ssowmini if (r1) 5734*e7801d59Ssowmini add_comma = B_TRUE; 5735*e7801d59Ssowmini r1 = get_speed_duplex(linkid, "lp_cap_100", buf, "100M", add_comma); 5736*e7801d59Ssowmini if (r1) 5737*e7801d59Ssowmini add_comma = B_TRUE; 5738*e7801d59Ssowmini r1 = get_speed_duplex(linkid, "lp_cap_10", buf, "10M", add_comma); 5739*e7801d59Ssowmini (void) snprintf(ebuf.eth_spdx, sizeof (ebuf.eth_spdx), "%s", buf); 5740*e7801d59Ssowmini 5741*e7801d59Ssowmini (void) dladm_get_single_mac_stat(linkid, "lp_cap_pause", 5742*e7801d59Ssowmini KSTAT_DATA_UINT32, &pause); 5743*e7801d59Ssowmini (void) dladm_get_single_mac_stat(linkid, "lp_cap_asmpause", 5744*e7801d59Ssowmini KSTAT_DATA_UINT32, &asmpause); 5745*e7801d59Ssowmini (void) snprintf(ebuf.eth_pause, sizeof (ebuf.eth_pause), 5746*e7801d59Ssowmini "%s", pause_str(pause, asmpause)); 5747*e7801d59Ssowmini 5748*e7801d59Ssowmini (void) snprintf(ebuf.eth_rem_fault, sizeof (ebuf.eth_rem_fault), 5749*e7801d59Ssowmini "%s", (lp_rf ? "fault" : "none")); 5750*e7801d59Ssowmini 5751*e7801d59Ssowmini dladm_print_output(&statep->es_print, statep->es_parseable, 5752*e7801d59Ssowmini dladm_print_field, &ebuf); 5753*e7801d59Ssowmini } 5754*e7801d59Ssowmini 5755*e7801d59Ssowmini static boolean_t 5756*e7801d59Ssowmini get_speed_duplex(datalink_id_t linkid, const char *mii_prop_prefix, 5757*e7801d59Ssowmini char *spbuf, char *sp, boolean_t add_comma) 5758*e7801d59Ssowmini { 5759*e7801d59Ssowmini int speed, duplex = 0; 5760*e7801d59Ssowmini boolean_t ret = B_FALSE; 5761*e7801d59Ssowmini char mii_prop[DLADM_STRSIZE]; 5762*e7801d59Ssowmini 5763*e7801d59Ssowmini (void) snprintf(mii_prop, DLADM_STRSIZE, "%sfdx", mii_prop_prefix); 5764*e7801d59Ssowmini (void) dladm_get_single_mac_stat(linkid, mii_prop, KSTAT_DATA_UINT32, 5765*e7801d59Ssowmini &speed); 5766*e7801d59Ssowmini if (speed) { 5767*e7801d59Ssowmini ret = B_TRUE; 5768*e7801d59Ssowmini duplex |= IS_FDX; 5769*e7801d59Ssowmini } 5770*e7801d59Ssowmini (void) snprintf(mii_prop, DLADM_STRSIZE, "%shdx", mii_prop_prefix); 5771*e7801d59Ssowmini (void) dladm_get_single_mac_stat(linkid, mii_prop, 5772*e7801d59Ssowmini KSTAT_DATA_UINT32, &speed); 5773*e7801d59Ssowmini if (speed) { 5774*e7801d59Ssowmini ret = B_TRUE; 5775*e7801d59Ssowmini duplex |= IS_HDX; 5776*e7801d59Ssowmini } 5777*e7801d59Ssowmini if (ret) { 5778*e7801d59Ssowmini if (add_comma) 5779*e7801d59Ssowmini (void) strncat(spbuf, ",", DLADM_STRSIZE); 5780*e7801d59Ssowmini (void) strncat(spbuf, sp, DLADM_STRSIZE); 5781*e7801d59Ssowmini if ((duplex & (IS_FDX|IS_HDX)) == (IS_FDX|IS_HDX)) 5782*e7801d59Ssowmini (void) strncat(spbuf, "-fh", DLADM_STRSIZE); 5783*e7801d59Ssowmini else if (duplex & IS_FDX) 5784*e7801d59Ssowmini (void) strncat(spbuf, "-f", DLADM_STRSIZE); 5785*e7801d59Ssowmini else if (duplex & IS_HDX) 5786*e7801d59Ssowmini (void) strncat(spbuf, "-h", DLADM_STRSIZE); 5787*e7801d59Ssowmini } 5788*e7801d59Ssowmini return (ret); 5789*e7801d59Ssowmini } 5790*e7801d59Ssowmini 5791*e7801d59Ssowmini static void 5792*e7801d59Ssowmini dladm_print_output(print_state_t *statep, boolean_t parseable, 5793*e7801d59Ssowmini print_callback_t fn, void *arg) 5794*e7801d59Ssowmini { 5795*e7801d59Ssowmini int i; 5796*e7801d59Ssowmini char *value; 5797*e7801d59Ssowmini print_field_t **pf; 5798*e7801d59Ssowmini 5799*e7801d59Ssowmini pf = statep->ps_fields; 5800*e7801d59Ssowmini for (i = 0; i < statep->ps_nfields; i++) { 5801*e7801d59Ssowmini statep->ps_lastfield = (i + 1 == statep->ps_nfields); 5802*e7801d59Ssowmini value = (*fn)(pf[i], arg); 5803*e7801d59Ssowmini if (value != NULL) 5804*e7801d59Ssowmini print_field(statep, pf[i], value, parseable); 5805*e7801d59Ssowmini } 5806*e7801d59Ssowmini (void) putchar('\n'); 5807*e7801d59Ssowmini } 5808*e7801d59Ssowmini 5809*e7801d59Ssowmini static void 5810*e7801d59Ssowmini print_header(print_state_t *ps) 5811*e7801d59Ssowmini { 5812*e7801d59Ssowmini int i; 5813*e7801d59Ssowmini print_field_t **pf; 5814*e7801d59Ssowmini 5815*e7801d59Ssowmini pf = ps->ps_fields; 5816*e7801d59Ssowmini for (i = 0; i < ps->ps_nfields; i++) { 5817*e7801d59Ssowmini ps->ps_lastfield = (i + 1 == ps->ps_nfields); 5818*e7801d59Ssowmini print_field(ps, pf[i], pf[i]->pf_header, B_FALSE); 5819*e7801d59Ssowmini } 5820*e7801d59Ssowmini (void) putchar('\n'); 5821*e7801d59Ssowmini } 5822*e7801d59Ssowmini 5823*e7801d59Ssowmini static char * 5824*e7801d59Ssowmini pause_str(int pause, int asmpause) 5825*e7801d59Ssowmini { 5826*e7801d59Ssowmini if (pause == 1) 5827*e7801d59Ssowmini return ("bi"); 5828*e7801d59Ssowmini if (asmpause == 1) 5829*e7801d59Ssowmini return ("tx"); 5830*e7801d59Ssowmini return ("none"); 5831*e7801d59Ssowmini } 5832*e7801d59Ssowmini 5833*e7801d59Ssowmini static boolean_t 5834*e7801d59Ssowmini link_is_ether(const char *link, datalink_id_t *linkid) 5835*e7801d59Ssowmini { 5836*e7801d59Ssowmini uint32_t media; 5837*e7801d59Ssowmini datalink_class_t class; 5838*e7801d59Ssowmini 5839*e7801d59Ssowmini if (dladm_name2info(link, linkid, NULL, &class, &media) == 5840*e7801d59Ssowmini DLADM_STATUS_OK) { 5841*e7801d59Ssowmini if (class == DATALINK_CLASS_PHYS && media == DL_ETHER) 5842*e7801d59Ssowmini return (B_TRUE); 5843*e7801d59Ssowmini } 5844*e7801d59Ssowmini return (B_FALSE); 5845*e7801d59Ssowmini } 5846