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 #include <stdio.h> 270ba2cbe9Sxc151355 #include <ctype.h> 287c478bd9Sstevel@tonic-gate #include <locale.h> 290ba2cbe9Sxc151355 #include <signal.h> 307c478bd9Sstevel@tonic-gate #include <stdarg.h> 317c478bd9Sstevel@tonic-gate #include <stdlib.h> 327c478bd9Sstevel@tonic-gate #include <fcntl.h> 337c478bd9Sstevel@tonic-gate #include <string.h> 347c478bd9Sstevel@tonic-gate #include <stropts.h> 35d62bc4baSyz147064 #include <sys/stat.h> 367c478bd9Sstevel@tonic-gate #include <errno.h> 377c478bd9Sstevel@tonic-gate #include <kstat.h> 387c478bd9Sstevel@tonic-gate #include <strings.h> 397c478bd9Sstevel@tonic-gate #include <getopt.h> 407c478bd9Sstevel@tonic-gate #include <unistd.h> 41cd93090eSericheng #include <priv.h> 420ba2cbe9Sxc151355 #include <termios.h> 430ba2cbe9Sxc151355 #include <pwd.h> 440ba2cbe9Sxc151355 #include <auth_attr.h> 450ba2cbe9Sxc151355 #include <auth_list.h> 467c478bd9Sstevel@tonic-gate #include <libintl.h> 47d62bc4baSyz147064 #include <libdevinfo.h> 487c478bd9Sstevel@tonic-gate #include <libdlpi.h> 49*da14cebeSEric Cheng #include <libdladm.h> 50f595a68aSyz147064 #include <libdllink.h> 51*da14cebeSEric Cheng #include <libdlstat.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*da14cebeSEric Cheng #include <libdlvnic.h> 60*da14cebeSEric Cheng #include <sys/types.h> 61*da14cebeSEric Cheng #include <sys/socket.h> 62*da14cebeSEric Cheng #include <sys/processor.h> 63*da14cebeSEric Cheng #include <netinet/in.h> 64*da14cebeSEric Cheng #include <arpa/inet.h> 65*da14cebeSEric Cheng #include <net/if_types.h> 66e7801d59Ssowmini #include <stddef.h> 677c478bd9Sstevel@tonic-gate 68e7801d59Ssowmini #define STR_UNDEF_VAL "--" 697c478bd9Sstevel@tonic-gate #define MAXPORT 256 70*da14cebeSEric Cheng #define MAXVNIC 256 71d62bc4baSyz147064 #define BUFLEN(lim, ptr) (((lim) > (ptr)) ? ((lim) - (ptr)) : 0) 72d62bc4baSyz147064 #define MAXLINELEN 1024 73d62bc4baSyz147064 #define SMF_UPGRADE_FILE "/var/svc/profile/upgrade" 74d62bc4baSyz147064 #define SMF_UPGRADEDATALINK_FILE "/var/svc/profile/upgrade_datalink" 75d62bc4baSyz147064 #define SMF_DLADM_UPGRADE_MSG " # added by dladm(1M)" 767c478bd9Sstevel@tonic-gate 77e7801d59Ssowmini #define CMD_TYPE_ANY 0xffffffff 78e7801d59Ssowmini #define WIFI_CMD_SCAN 0x00000001 79e7801d59Ssowmini #define WIFI_CMD_SHOW 0x00000002 80e7801d59Ssowmini #define WIFI_CMD_ALL (WIFI_CMD_SCAN | WIFI_CMD_SHOW) 81e7801d59Ssowmini 82e7801d59Ssowmini /* 830d365605Sschuster * Data structures and routines for printing output. 84e7801d59Ssowmini * All non-parseable output is assumed to be in a columnar format. 850d365605Sschuster * Multiple fields in parsable output are separated by ':'; single 860d365605Sschuster * field output is printed as-is. 87e7801d59Ssowmini * 88e7801d59Ssowmini * Each sub-command is associated with a global array of pointers, 89e7801d59Ssowmini * print_field_t *fields[], where the print_field_t contains information 90e7801d59Ssowmini * about the format in which the output is to be printed. 91e7801d59Ssowmini * 92e7801d59Ssowmini * Sub-commands may be implemented in one of two ways: 93e7801d59Ssowmini * (i) the implementation could get all field values into a character 94e7801d59Ssowmini * buffer, with pf_offset containing the offset (for pf_name) within 95e7801d59Ssowmini * the buffer. The sub-command would make the needed system calls 96e7801d59Ssowmini * to obtain all possible column values and then invoke the 97e7801d59Ssowmini * dladm_print_field() function to print the specific fields 98e7801d59Ssowmini * requested in the command line. See the comments for dladm_print_field 99e7801d59Ssowmini * for further details. 100e7801d59Ssowmini * (ii) Alternatively, each fields[i] entry could store a pf_index value 101e7801d59Ssowmini * that uniquely identifies the column to be printed. The implementation 102e7801d59Ssowmini * of the sub-command would then invoke dladm_print_output() with a 103e7801d59Ssowmini * callback function whose semantics are described below (see comments 104e7801d59Ssowmini * for dladm_print_output()) 105e7801d59Ssowmini * 106e7801d59Ssowmini * Thus, an implementation of a sub-command must provide the following: 107e7801d59Ssowmini * 108e7801d59Ssowmini * static print_field_t sub_command_fields[] = { 109e7801d59Ssowmini * {<name>, <header>,<field width>, <offset_or_index>, cmdtype}, 110e7801d59Ssowmini * : 111e7801d59Ssowmini * {<name>, <header>,<field width>, <offset_or_index>, cmdtype} 112e7801d59Ssowmini * }; 113e7801d59Ssowmini * 114e7801d59Ssowmini * #define SUB_COMMAND_MAX_FIELDS sizeof \ 115e7801d59Ssowmini * (sub_comand_fields) / sizeof (print_field_t)) 116e7801d59Ssowmini * 117e7801d59Ssowmini * print_state_t sub_command_print_state; 118e7801d59Ssowmini * 119e7801d59Ssowmini * The function that parses command line arguments (typically 120e7801d59Ssowmini * do_sub_command()) should then contain an invocation like: 121e7801d59Ssowmini * 122e7801d59Ssowmini * fields = parse_output_fields(fields_str, sub_command_fields, 123e7801d59Ssowmini * SUB_COMMAND_MAX_FIELDS, CMD_TYPE_ANY, &nfields); 124e7801d59Ssowmini * 125e7801d59Ssowmini * and store the resulting fields and nfields value in a print_state_t 126e7801d59Ssowmini * structure tracked for the command. 127e7801d59Ssowmini * 128e7801d59Ssowmini * sub_command_print_state.ps_fields = fields; 129e7801d59Ssowmini * sub_command_print_state.ps_nfields = nfields; 130e7801d59Ssowmini * 131e7801d59Ssowmini * To print the column header for the output, the print_header() 132e7801d59Ssowmini * function must then be invoked by do_sub_command(). 133e7801d59Ssowmini * 134e7801d59Ssowmini * Then if method (i) is used for the sub_command, the do_sub_command() 135e7801d59Ssowmini * function should make the necessary system calls to fill up the buffer 136e7801d59Ssowmini * and then invoke dladm_print_field(). An example of this method is 137e7801d59Ssowmini * the implementation of do_show_link() and show_link(); 138e7801d59Ssowmini * 139e7801d59Ssowmini * If method (ii) is used, do_sub_command should invoke dladm_print_output() 140e7801d59Ssowmini * with a callback function that will be called for each field to be printed. 141e7801d59Ssowmini * The callback function will be passed a pointer to the print_field_t 142e7801d59Ssowmini * for the field, and the pf_index may then be used to identify the 143*da14cebeSEric Cheng * system call required to find the value to be printed. 144e7801d59Ssowmini */ 145e7801d59Ssowmini 146e7801d59Ssowmini typedef struct print_field_s { 147e7801d59Ssowmini const char *pf_name; /* name of column to be printed */ 148e7801d59Ssowmini const char *pf_header; /* header for this column */ 149e7801d59Ssowmini uint_t pf_width; 150e7801d59Ssowmini union { 151e7801d59Ssowmini uint_t _pf_index; /* private index for sub-command */ 152e7801d59Ssowmini size_t _pf_offset; 153e7801d59Ssowmini }_pf_un; 154e7801d59Ssowmini #define pf_index _pf_un._pf_index 155e7801d59Ssowmini #define pf_offset _pf_un._pf_offset; 156e7801d59Ssowmini uint_t pf_cmdtype; 157e7801d59Ssowmini } print_field_t; 158e7801d59Ssowmini 159e7801d59Ssowmini /* 160e7801d59Ssowmini * The state of the output is tracked in a print_state_t structure. 161e7801d59Ssowmini * Each ps_fields[i] entry points at the global print_field_t array for 162e7801d59Ssowmini * the sub-command, where ps_nfields is the number of requested fields. 163e7801d59Ssowmini */ 164e7801d59Ssowmini typedef struct print_state_s { 165e7801d59Ssowmini print_field_t **ps_fields; 166e7801d59Ssowmini uint_t ps_nfields; 167e7801d59Ssowmini boolean_t ps_lastfield; 168e7801d59Ssowmini uint_t ps_overflow; 169e7801d59Ssowmini } print_state_t; 170e7801d59Ssowmini 171e7801d59Ssowmini typedef char *(*print_callback_t)(print_field_t *, void *); 172e7801d59Ssowmini static print_field_t **parse_output_fields(char *, print_field_t *, int, 173e7801d59Ssowmini uint_t, uint_t *); 174e7801d59Ssowmini /* 175e7801d59Ssowmini * print the header for the output 176e7801d59Ssowmini */ 177e7801d59Ssowmini static void print_header(print_state_t *); 178e7801d59Ssowmini static void print_field(print_state_t *, print_field_t *, const char *, 179e7801d59Ssowmini boolean_t); 180e7801d59Ssowmini 181e7801d59Ssowmini /* 182e7801d59Ssowmini * to print output values, call dladm_print_output with a callback 183e7801d59Ssowmini * function (*func)() that should parse the args and return an 184e7801d59Ssowmini * unformatted character buffer with the value to be printed. 185e7801d59Ssowmini * 186e7801d59Ssowmini * dladm_print_output() prints the character buffer using the formatting 187e7801d59Ssowmini * information provided in the print_field_t for that column. 188e7801d59Ssowmini */ 189e7801d59Ssowmini static void dladm_print_output(print_state_t *, boolean_t, 190e7801d59Ssowmini print_callback_t, void *); 191e7801d59Ssowmini 192e7801d59Ssowmini /* 193e7801d59Ssowmini * helper function that, when invoked as dladm_print_field(pf, buf) 194e7801d59Ssowmini * prints string which is offset by pf->pf_offset within buf 195e7801d59Ssowmini */ 196e7801d59Ssowmini static char *dladm_print_field(print_field_t *, void *); 197e7801d59Ssowmini 198e7801d59Ssowmini 199e7801d59Ssowmini #define MAX_FIELD_LEN 32 200e7801d59Ssowmini 201e7801d59Ssowmini 202d62bc4baSyz147064 typedef struct show_state { 2037c478bd9Sstevel@tonic-gate boolean_t ls_firstonly; 2047c478bd9Sstevel@tonic-gate boolean_t ls_donefirst; 2057c478bd9Sstevel@tonic-gate pktsum_t ls_prevstats; 206d62bc4baSyz147064 uint32_t ls_flags; 207d62bc4baSyz147064 dladm_status_t ls_status; 208e7801d59Ssowmini print_state_t ls_print; 209e7801d59Ssowmini boolean_t ls_parseable; 210e7801d59Ssowmini boolean_t ls_printheader; 211*da14cebeSEric Cheng boolean_t ls_mac; 212*da14cebeSEric Cheng boolean_t ls_hwgrp; 213d62bc4baSyz147064 } show_state_t; 2147c478bd9Sstevel@tonic-gate 2157c478bd9Sstevel@tonic-gate typedef struct show_grp_state { 216e7801d59Ssowmini pktsum_t gs_prevstats[MAXPORT]; 217e7801d59Ssowmini uint32_t gs_flags; 218e7801d59Ssowmini dladm_status_t gs_status; 219e7801d59Ssowmini boolean_t gs_parseable; 2207c478bd9Sstevel@tonic-gate boolean_t gs_lacp; 221d62bc4baSyz147064 boolean_t gs_extended; 2227c478bd9Sstevel@tonic-gate boolean_t gs_stats; 2237c478bd9Sstevel@tonic-gate boolean_t gs_firstonly; 224d62bc4baSyz147064 boolean_t gs_donefirst; 225e7801d59Ssowmini boolean_t gs_printheader; 226e7801d59Ssowmini print_state_t gs_print; 2277c478bd9Sstevel@tonic-gate } show_grp_state_t; 2287c478bd9Sstevel@tonic-gate 229*da14cebeSEric Cheng typedef struct show_vnic_state { 230*da14cebeSEric Cheng datalink_id_t vs_vnic_id; 231*da14cebeSEric Cheng datalink_id_t vs_link_id; 232*da14cebeSEric Cheng char vs_vnic[MAXLINKNAMELEN]; 233*da14cebeSEric Cheng char vs_link[MAXLINKNAMELEN]; 234*da14cebeSEric Cheng boolean_t vs_parseable; 235*da14cebeSEric Cheng boolean_t vs_printheader; 236*da14cebeSEric Cheng boolean_t vs_found; 237*da14cebeSEric Cheng boolean_t vs_firstonly; 238*da14cebeSEric Cheng boolean_t vs_donefirst; 239*da14cebeSEric Cheng boolean_t vs_stats; 240*da14cebeSEric Cheng boolean_t vs_printstats; 241*da14cebeSEric Cheng pktsum_t vs_totalstats; 242*da14cebeSEric Cheng pktsum_t vs_prevstats[MAXVNIC]; 243*da14cebeSEric Cheng boolean_t vs_etherstub; 244*da14cebeSEric Cheng dladm_status_t vs_status; 245*da14cebeSEric Cheng uint32_t vs_flags; 246*da14cebeSEric Cheng print_state_t vs_print; 247*da14cebeSEric Cheng } show_vnic_state_t; 248*da14cebeSEric Cheng 249*da14cebeSEric Cheng typedef struct show_usage_state_s { 250*da14cebeSEric Cheng boolean_t us_plot; 251*da14cebeSEric Cheng boolean_t us_parseable; 252*da14cebeSEric Cheng boolean_t us_printheader; 253*da14cebeSEric Cheng boolean_t us_first; 254*da14cebeSEric Cheng print_state_t us_print; 255*da14cebeSEric Cheng } show_usage_state_t; 256*da14cebeSEric Cheng 2578d5c46e6Sam223141 typedef void cmdfunc_t(int, char **, const char *); 2580ba2cbe9Sxc151355 259*da14cebeSEric Cheng static cmdfunc_t do_show_link, do_show_wifi, do_show_phys; 2600ba2cbe9Sxc151355 static cmdfunc_t do_create_aggr, do_delete_aggr, do_add_aggr, do_remove_aggr; 261d62bc4baSyz147064 static cmdfunc_t do_modify_aggr, do_show_aggr, do_up_aggr; 2620ba2cbe9Sxc151355 static cmdfunc_t do_scan_wifi, do_connect_wifi, do_disconnect_wifi; 2630ba2cbe9Sxc151355 static cmdfunc_t do_show_linkprop, do_set_linkprop, do_reset_linkprop; 2640ba2cbe9Sxc151355 static cmdfunc_t do_create_secobj, do_delete_secobj, do_show_secobj; 2650ba2cbe9Sxc151355 static cmdfunc_t do_init_linkprop, do_init_secobj; 266d62bc4baSyz147064 static cmdfunc_t do_create_vlan, do_delete_vlan, do_up_vlan, do_show_vlan; 267d62bc4baSyz147064 static cmdfunc_t do_rename_link, do_delete_phys, do_init_phys; 268d62bc4baSyz147064 static cmdfunc_t do_show_linkmap; 269e7801d59Ssowmini static cmdfunc_t do_show_ether; 270*da14cebeSEric Cheng static cmdfunc_t do_create_vnic, do_delete_vnic, do_show_vnic; 271*da14cebeSEric Cheng static cmdfunc_t do_up_vnic; 272*da14cebeSEric Cheng static cmdfunc_t do_create_etherstub, do_delete_etherstub, do_show_etherstub; 273*da14cebeSEric Cheng static cmdfunc_t do_show_usage; 274*da14cebeSEric Cheng 275*da14cebeSEric Cheng static void do_up_vnic_common(int, char **, const char *, boolean_t); 2767c478bd9Sstevel@tonic-gate 277d62bc4baSyz147064 static void altroot_cmd(char *, int, char **); 278d62bc4baSyz147064 static int show_linkprop_onelink(datalink_id_t, void *); 279f4b3ec61Sdh155122 2806be03d0bSVasumathi Sundaram - Sun Microsystems static void link_stats(datalink_id_t, uint_t, char *, show_state_t *); 281d62bc4baSyz147064 static void aggr_stats(datalink_id_t, show_grp_state_t *, uint_t); 282*da14cebeSEric Cheng static void vnic_stats(show_vnic_state_t *, uint32_t); 2837c478bd9Sstevel@tonic-gate 284d62bc4baSyz147064 static int get_one_kstat(const char *, const char *, uint8_t, 285d62bc4baSyz147064 void *, boolean_t); 286ba2e4443Sseb static void get_mac_stats(const char *, pktsum_t *); 2877c478bd9Sstevel@tonic-gate static void get_link_stats(const char *, pktsum_t *); 288d62bc4baSyz147064 static uint64_t get_ifspeed(const char *, boolean_t); 289d62bc4baSyz147064 static const char *get_linkstate(const char *, boolean_t, char *); 290d62bc4baSyz147064 static const char *get_linkduplex(const char *, boolean_t, char *); 2917c478bd9Sstevel@tonic-gate 292e7801d59Ssowmini static int show_etherprop(datalink_id_t, void *); 293e7801d59Ssowmini static void show_ether_xprop(datalink_id_t, void *); 294e7801d59Ssowmini static boolean_t get_speed_duplex(datalink_id_t, const char *, char *, 295e7801d59Ssowmini char *, boolean_t); 296e7801d59Ssowmini static char *pause_str(int, int); 297e7801d59Ssowmini static boolean_t link_is_ether(const char *, datalink_id_t *); 298e7801d59Ssowmini 299e7801d59Ssowmini #define IS_FDX 0x10 300e7801d59Ssowmini #define IS_HDX 0x01 301e7801d59Ssowmini 30233343a97Smeem static boolean_t str2int(const char *, int *); 30333343a97Smeem static void die(const char *, ...); 30433343a97Smeem static void die_optdup(int); 3058d5c46e6Sam223141 static void die_opterr(int, int, const char *); 30633343a97Smeem static void die_dlerr(dladm_status_t, const char *, ...); 30733343a97Smeem static void warn(const char *, ...); 30833343a97Smeem static void warn_dlerr(dladm_status_t, const char *, ...); 30933343a97Smeem 3107c478bd9Sstevel@tonic-gate typedef struct cmd { 3117c478bd9Sstevel@tonic-gate char *c_name; 3120ba2cbe9Sxc151355 cmdfunc_t *c_fn; 3138d5c46e6Sam223141 const char *c_usage; 3147c478bd9Sstevel@tonic-gate } cmd_t; 3157c478bd9Sstevel@tonic-gate 3167c478bd9Sstevel@tonic-gate static cmd_t cmds[] = { 3178d5c46e6Sam223141 { "show-link", do_show_link, 3188d5c46e6Sam223141 "\tshow-link\t[-pP] [-o <field>,..] [-s [-i <interval>]] [<link>]"}, 3198d5c46e6Sam223141 { "rename-link", do_rename_link, 3208d5c46e6Sam223141 "\trename-link\t[-R <root-dir>] <oldlink> <newlink>\n" }, 3218d5c46e6Sam223141 { "create-aggr", do_create_aggr, 3228d5c46e6Sam223141 "\tcreate-aggr\t[-t] [-R <root-dir>] [-P <policy>] [-L <mode>]\n" 3238d5c46e6Sam223141 "\t\t\t[-T <time>] [-u <address>] [-l <link>] ... <link>" }, 3248d5c46e6Sam223141 { "delete-aggr", do_delete_aggr, 3258d5c46e6Sam223141 "\tdelete-aggr\t[-t] [-R <root-dir>] <link>" }, 3268d5c46e6Sam223141 { "add-aggr", do_add_aggr, 3278d5c46e6Sam223141 "\tadd-aggr\t[-t] [-R <root-dir>] [-l <link>] ... <link>" }, 3288d5c46e6Sam223141 { "remove-aggr", do_remove_aggr, 3298d5c46e6Sam223141 "\tremove-aggr\t[-t] [-R <root-dir>] [-l <link>] ... <link>"}, 3308d5c46e6Sam223141 { "modify-aggr", do_modify_aggr, 3318d5c46e6Sam223141 "\tmodify-aggr\t[-t] [-R <root-dir>] [-P <policy>] [-L <mode>]\n" 3328d5c46e6Sam223141 "\t\t\t[-T <time>] [-u <address>] <link>" }, 3338d5c46e6Sam223141 { "show-aggr", do_show_aggr, 3348d5c46e6Sam223141 "\tshow-aggr\t[-pPLx] [-o <field>,..] [-s [-i <interval>]] " 3358d5c46e6Sam223141 "[<link>]\n" }, 3368d5c46e6Sam223141 { "up-aggr", do_up_aggr, NULL }, 3378d5c46e6Sam223141 { "scan-wifi", do_scan_wifi, 3388d5c46e6Sam223141 "\tscan-wifi\t[-p] [-o <field>,...] [<link>]" }, 3398d5c46e6Sam223141 { "connect-wifi", do_connect_wifi, 3408d5c46e6Sam223141 "\tconnect-wifi\t[-e <essid>] [-i <bssid>] [-k <key>,...] " 3418d5c46e6Sam223141 "[-s wep|wpa]\n" 3428d5c46e6Sam223141 "\t\t\t[-a open|shared] [-b bss|ibss] [-c] [-m a|b|g]\n" 3438d5c46e6Sam223141 "\t\t\t[-T <time>] [<link>]" }, 3448d5c46e6Sam223141 { "disconnect-wifi", do_disconnect_wifi, 3458d5c46e6Sam223141 "\tdisconnect-wifi\t[-a] [<link>]" }, 3468d5c46e6Sam223141 { "show-wifi", do_show_wifi, 3478d5c46e6Sam223141 "\tshow-wifi\t[-p] [-o <field>,...] [<link>]\n" }, 3488d5c46e6Sam223141 { "show-linkprop", do_show_linkprop, 3498d5c46e6Sam223141 "\tshow-linkprop\t[-cP] [-o <field>,...] [-p <prop>,...] <name>"}, 3508d5c46e6Sam223141 { "set-linkprop", do_set_linkprop, 3518d5c46e6Sam223141 "\tset-linkprop\t[-t] [-R <root-dir>] -p <prop>=<value>[,...] " 3528d5c46e6Sam223141 "<name>" }, 3538d5c46e6Sam223141 { "reset-linkprop", do_reset_linkprop, 3548d5c46e6Sam223141 "\treset-linkprop\t[-t] [-R <root-dir>] [-p <prop>,...] <name>\n" }, 3558d5c46e6Sam223141 { "show-ether", do_show_ether, 3568d5c46e6Sam223141 "\tshow-ether\t[-px][-o <field>,...] <link>\n" }, 3578d5c46e6Sam223141 { "create-secobj", do_create_secobj, 3588d5c46e6Sam223141 "\tcreate-secobj\t[-t] [-R <root-dir>] [-f <file>] -c <class> " 3598d5c46e6Sam223141 "<secobj>" }, 3608d5c46e6Sam223141 { "delete-secobj", do_delete_secobj, 3618d5c46e6Sam223141 "\tdelete-secobj\t[-t] [-R <root-dir>] <secobj>[,...]" }, 3628d5c46e6Sam223141 { "show-secobj", do_show_secobj, 3638d5c46e6Sam223141 "\tshow-secobj\t[-pP] [-o <field>,...] [<secobj>,...]\n" }, 3648d5c46e6Sam223141 { "init-linkprop", do_init_linkprop, NULL }, 3658d5c46e6Sam223141 { "init-secobj", do_init_secobj, NULL }, 3668d5c46e6Sam223141 { "create-vlan", do_create_vlan, 3678d5c46e6Sam223141 "\tcreate-vlan\t[-ft] [-R <root-dir>] -l <link> -v <vid> [link]" }, 3688d5c46e6Sam223141 { "delete-vlan", do_delete_vlan, 3698d5c46e6Sam223141 "\tdelete-vlan\t[-t] [-R <root-dir>] <link>" }, 3708d5c46e6Sam223141 { "show-vlan", do_show_vlan, 3718d5c46e6Sam223141 "\tshow-vlan\t[-pP] [-o <field>,..] [<link>]\n" }, 3728d5c46e6Sam223141 { "up-vlan", do_up_vlan, NULL }, 3738d5c46e6Sam223141 { "delete-phys", do_delete_phys, 3748d5c46e6Sam223141 "\tdelete-phys\t<link>" }, 3758d5c46e6Sam223141 { "show-phys", do_show_phys, 376*da14cebeSEric Cheng "\tshow-phys\t[-pP] [-o <field>,..] [-H] [<link>]" }, 3778d5c46e6Sam223141 { "init-phys", do_init_phys, NULL }, 378*da14cebeSEric Cheng { "show-linkmap", do_show_linkmap, NULL }, 379*da14cebeSEric Cheng { "create-vnic", do_create_vnic, 380*da14cebeSEric Cheng "\tcreate-vnic [-t] [-R <root-dir>] -l <link> [-m <value> |" 381*da14cebeSEric Cheng " auto |\n" 382*da14cebeSEric Cheng "\t {factory [-n <slot-identifier>]} |\n" 383*da14cebeSEric Cheng "\t {random [-r <prefix>]}] [-v vlan-tag [-f]]\n" 384*da14cebeSEric Cheng "\t -p <prop>=<value>[,...] [-H]" 385*da14cebeSEric Cheng " <vnic-link>\n" }, 386*da14cebeSEric Cheng { "delete-vnic", do_delete_vnic, 387*da14cebeSEric Cheng "\tdelete-vnic [-t] [-R <root-dir>] <vnic-link>\n" }, 388*da14cebeSEric Cheng { "show-vnic", do_show_vnic, 389*da14cebeSEric Cheng "\tshow-vnic [-pP] [-l <link>] [-s [-i <interval>]]" }, 390*da14cebeSEric Cheng { "up-vnic", do_up_vnic, NULL }, 391*da14cebeSEric Cheng { "create-etherstub", do_create_etherstub, 392*da14cebeSEric Cheng "\tcreate-etherstub [-t] [-R <root-dir>] <link>\n" }, 393*da14cebeSEric Cheng { "delete-etherstub", do_delete_etherstub, 394*da14cebeSEric Cheng "\tdelete-etherstub [-t] [-R <root-dir>] <link>\n" }, 395*da14cebeSEric Cheng { "show-etherstub", do_show_etherstub, 396*da14cebeSEric Cheng "\tshow-etherstub [-t] [-R <root-dir>] [<link>]\n" }, 397*da14cebeSEric Cheng { "show-usage", do_show_usage, 398*da14cebeSEric Cheng "\tshow-usage [-d|-p -F <format>] [-f <filename>]\n" 399*da14cebeSEric Cheng "\t [-s <time>] [-e <time>] <link>\n" } 4007c478bd9Sstevel@tonic-gate }; 4017c478bd9Sstevel@tonic-gate 402d62bc4baSyz147064 static const struct option lopts[] = { 4037c478bd9Sstevel@tonic-gate {"vlan-id", required_argument, 0, 'v'}, 404e7801d59Ssowmini {"output", required_argument, 0, 'o'}, 4057c478bd9Sstevel@tonic-gate {"dev", required_argument, 0, 'd'}, 4067c478bd9Sstevel@tonic-gate {"policy", required_argument, 0, 'P'}, 407d62bc4baSyz147064 {"lacp-mode", required_argument, 0, 'L'}, 4087c478bd9Sstevel@tonic-gate {"lacp-timer", required_argument, 0, 'T'}, 4097c478bd9Sstevel@tonic-gate {"unicast", required_argument, 0, 'u'}, 410d62bc4baSyz147064 {"temporary", no_argument, 0, 't'}, 411d62bc4baSyz147064 {"root-dir", required_argument, 0, 'R'}, 412d62bc4baSyz147064 {"link", required_argument, 0, 'l'}, 413d62bc4baSyz147064 {"forcible", no_argument, 0, 'f'}, 414*da14cebeSEric Cheng {"bw-limit", required_argument, 0, 'b'}, 415*da14cebeSEric Cheng {"mac-address", required_argument, 0, 'm'}, 416*da14cebeSEric Cheng {"slot", required_argument, 0, 'n'}, 417d62bc4baSyz147064 { 0, 0, 0, 0 } 418d62bc4baSyz147064 }; 419d62bc4baSyz147064 420d62bc4baSyz147064 static const struct option show_lopts[] = { 4217c478bd9Sstevel@tonic-gate {"statistics", no_argument, 0, 's'}, 422*da14cebeSEric Cheng {"continuous", no_argument, 0, 'S'}, 4237c478bd9Sstevel@tonic-gate {"interval", required_argument, 0, 'i'}, 4247c478bd9Sstevel@tonic-gate {"parseable", no_argument, 0, 'p'}, 425d62bc4baSyz147064 {"extended", no_argument, 0, 'x'}, 426e7801d59Ssowmini {"output", required_argument, 0, 'o'}, 427d62bc4baSyz147064 {"persistent", no_argument, 0, 'P'}, 428d62bc4baSyz147064 {"lacp", no_argument, 0, 'L'}, 4297c478bd9Sstevel@tonic-gate { 0, 0, 0, 0 } 4307c478bd9Sstevel@tonic-gate }; 4317c478bd9Sstevel@tonic-gate 4320ba2cbe9Sxc151355 static const struct option prop_longopts[] = { 4330ba2cbe9Sxc151355 {"temporary", no_argument, 0, 't' }, 434e7801d59Ssowmini {"output", required_argument, 0, 'o' }, 4350ba2cbe9Sxc151355 {"root-dir", required_argument, 0, 'R' }, 4360ba2cbe9Sxc151355 {"prop", required_argument, 0, 'p' }, 4370ba2cbe9Sxc151355 {"parseable", no_argument, 0, 'c' }, 4380ba2cbe9Sxc151355 {"persistent", no_argument, 0, 'P' }, 4390ba2cbe9Sxc151355 { 0, 0, 0, 0 } 4400ba2cbe9Sxc151355 }; 4410ba2cbe9Sxc151355 4420ba2cbe9Sxc151355 static const struct option wifi_longopts[] = { 4430ba2cbe9Sxc151355 {"parseable", no_argument, 0, 'p' }, 4440ba2cbe9Sxc151355 {"output", required_argument, 0, 'o' }, 4450ba2cbe9Sxc151355 {"essid", required_argument, 0, 'e' }, 4460ba2cbe9Sxc151355 {"bsstype", required_argument, 0, 'b' }, 4470ba2cbe9Sxc151355 {"mode", required_argument, 0, 'm' }, 4480ba2cbe9Sxc151355 {"key", required_argument, 0, 'k' }, 4490ba2cbe9Sxc151355 {"sec", required_argument, 0, 's' }, 4500ba2cbe9Sxc151355 {"auth", required_argument, 0, 'a' }, 4510ba2cbe9Sxc151355 {"create-ibss", required_argument, 0, 'c' }, 4520ba2cbe9Sxc151355 {"timeout", required_argument, 0, 'T' }, 4530ba2cbe9Sxc151355 {"all-links", no_argument, 0, 'a' }, 4540ba2cbe9Sxc151355 {"temporary", no_argument, 0, 't' }, 4550ba2cbe9Sxc151355 {"root-dir", required_argument, 0, 'R' }, 4560ba2cbe9Sxc151355 {"persistent", no_argument, 0, 'P' }, 4570ba2cbe9Sxc151355 {"file", required_argument, 0, 'f' }, 4580ba2cbe9Sxc151355 { 0, 0, 0, 0 } 4590ba2cbe9Sxc151355 }; 460e7801d59Ssowmini static const struct option showeth_lopts[] = { 461e7801d59Ssowmini {"parseable", no_argument, 0, 'p' }, 462e7801d59Ssowmini {"extended", no_argument, 0, 'x' }, 463e7801d59Ssowmini {"output", required_argument, 0, 'o' }, 464e7801d59Ssowmini { 0, 0, 0, 0 } 465e7801d59Ssowmini }; 466e7801d59Ssowmini 467*da14cebeSEric Cheng static const struct option vnic_lopts[] = { 468*da14cebeSEric Cheng {"temporary", no_argument, 0, 't' }, 469*da14cebeSEric Cheng {"root-dir", required_argument, 0, 'R' }, 470*da14cebeSEric Cheng {"dev", required_argument, 0, 'd' }, 471*da14cebeSEric Cheng {"mac-address", required_argument, 0, 'm' }, 472*da14cebeSEric Cheng {"cpus", required_argument, 0, 'c' }, 473*da14cebeSEric Cheng {"bw-limit", required_argument, 0, 'b' }, 474*da14cebeSEric Cheng {"slot", required_argument, 0, 'n' }, 475*da14cebeSEric Cheng {"mac-prefix", required_argument, 0, 'r' }, 476*da14cebeSEric Cheng { 0, 0, 0, 0 } 477*da14cebeSEric Cheng }; 478*da14cebeSEric Cheng 479*da14cebeSEric Cheng static const struct option etherstub_lopts[] = { 480*da14cebeSEric Cheng {"temporary", no_argument, 0, 't' }, 481*da14cebeSEric Cheng {"root-dir", required_argument, 0, 'R' }, 482*da14cebeSEric Cheng { 0, 0, 0, 0 } 483*da14cebeSEric Cheng }; 484*da14cebeSEric Cheng 485e7801d59Ssowmini /* 486e7801d59Ssowmini * structures for 'dladm show-ether' 487e7801d59Ssowmini */ 488e7801d59Ssowmini typedef struct ether_fields_buf_s 489e7801d59Ssowmini { 490e7801d59Ssowmini char eth_link[15]; 491e7801d59Ssowmini char eth_ptype[8]; 492e7801d59Ssowmini char eth_state[8]; 493e7801d59Ssowmini char eth_autoneg[5]; 494e7801d59Ssowmini char eth_spdx[31]; 495e7801d59Ssowmini char eth_pause[6]; 496e7801d59Ssowmini char eth_rem_fault[16]; 497e7801d59Ssowmini } ether_fields_buf_t; 498e7801d59Ssowmini 499e7801d59Ssowmini static print_field_t ether_fields[] = { 500e7801d59Ssowmini /* name, header, field width, offset, cmdtype */ 501e7801d59Ssowmini { "link", "LINK", 15, 502e7801d59Ssowmini offsetof(ether_fields_buf_t, eth_link), CMD_TYPE_ANY}, 503e7801d59Ssowmini { "ptype", "PTYPE", 8, 504e7801d59Ssowmini offsetof(ether_fields_buf_t, eth_ptype), CMD_TYPE_ANY}, 505e7801d59Ssowmini { "state", "STATE", 8, 506e7801d59Ssowmini offsetof(ether_fields_buf_t, eth_state), CMD_TYPE_ANY}, 507e7801d59Ssowmini { "auto", "AUTO", 5, 508e7801d59Ssowmini offsetof(ether_fields_buf_t, eth_autoneg), CMD_TYPE_ANY}, 509e7801d59Ssowmini { "speed-duplex", "SPEED-DUPLEX", 31, 510e7801d59Ssowmini offsetof(ether_fields_buf_t, eth_spdx), CMD_TYPE_ANY}, 511e7801d59Ssowmini { "pause", "PAUSE", 6, 512e7801d59Ssowmini offsetof(ether_fields_buf_t, eth_pause), CMD_TYPE_ANY}, 513e7801d59Ssowmini { "rem_fault", "REM_FAULT", 16, 514e7801d59Ssowmini offsetof(ether_fields_buf_t, eth_rem_fault), CMD_TYPE_ANY}} 515e7801d59Ssowmini ; 516e7801d59Ssowmini #define ETHER_MAX_FIELDS (sizeof (ether_fields) / sizeof (print_field_t)) 517e7801d59Ssowmini 518e7801d59Ssowmini typedef struct print_ether_state { 519e7801d59Ssowmini const char *es_link; 520e7801d59Ssowmini boolean_t es_parseable; 521e7801d59Ssowmini boolean_t es_header; 522e7801d59Ssowmini boolean_t es_extended; 523e7801d59Ssowmini print_state_t es_print; 524e7801d59Ssowmini } print_ether_state_t; 525e7801d59Ssowmini 526e7801d59Ssowmini /* 527*da14cebeSEric Cheng * structures for 'dladm show-link -s' (print statistics) 528e7801d59Ssowmini */ 529e7801d59Ssowmini typedef enum { 530e7801d59Ssowmini DEVS_LINK, 531e7801d59Ssowmini DEVS_IPKTS, 532e7801d59Ssowmini DEVS_RBYTES, 533e7801d59Ssowmini DEVS_IERRORS, 534e7801d59Ssowmini DEVS_OPKTS, 535e7801d59Ssowmini DEVS_OBYTES, 536e7801d59Ssowmini DEVS_OERRORS 537e7801d59Ssowmini } devs_field_index_t; 538e7801d59Ssowmini 539e7801d59Ssowmini static print_field_t devs_fields[] = { 540e7801d59Ssowmini /* name, header, field width, index, cmdtype */ 541e7801d59Ssowmini { "link", "LINK", 15, DEVS_LINK, CMD_TYPE_ANY}, 542e7801d59Ssowmini { "ipackets", "IPACKETS", 10, DEVS_IPKTS, CMD_TYPE_ANY}, 543e7801d59Ssowmini { "rbytes", "RBYTES", 8, DEVS_RBYTES, CMD_TYPE_ANY}, 544e7801d59Ssowmini { "ierrors", "IERRORS", 10, DEVS_IERRORS, CMD_TYPE_ANY}, 545e7801d59Ssowmini { "opackets", "OPACKETS", 12, DEVS_OPKTS, CMD_TYPE_ANY}, 546e7801d59Ssowmini { "obytes", "OBYTES", 12, DEVS_OBYTES, CMD_TYPE_ANY}, 547e7801d59Ssowmini { "oerrors", "OERRORS", 8, DEVS_OERRORS, CMD_TYPE_ANY}} 548e7801d59Ssowmini ; 549e7801d59Ssowmini #define DEVS_MAX_FIELDS (sizeof (devs_fields) / sizeof (print_field_t)) 550e7801d59Ssowmini 551e7801d59Ssowmini /* 552e7801d59Ssowmini * buffer used by print functions for show-{link,phys,vlan} commands. 553e7801d59Ssowmini */ 554e7801d59Ssowmini typedef struct link_fields_buf_s { 555e7801d59Ssowmini char link_name[MAXLINKNAMELEN]; 556e7801d59Ssowmini char link_class[DLADM_STRSIZE]; 557c08e5e1aSdr146992 char link_mtu[11]; 558e7801d59Ssowmini char link_state[DLADM_STRSIZE]; 559e7801d59Ssowmini char link_over[MAXLINKNAMELEN]; 5604045d941Ssowmini char link_phys_state[DLADM_STRSIZE]; 561e7801d59Ssowmini char link_phys_media[DLADM_STRSIZE]; 562e7801d59Ssowmini char link_phys_speed[DLADM_STRSIZE]; 563e7801d59Ssowmini char link_phys_duplex[DLPI_LINKNAME_MAX]; 564e7801d59Ssowmini char link_phys_device[DLPI_LINKNAME_MAX]; 565e7801d59Ssowmini char link_flags[6]; 566e7801d59Ssowmini char link_vlan_vid[6]; 567e7801d59Ssowmini } link_fields_buf_t; 568e7801d59Ssowmini 569e7801d59Ssowmini /* 570e7801d59Ssowmini * structures for 'dladm show-link' 571e7801d59Ssowmini */ 572e7801d59Ssowmini static print_field_t link_fields[] = { 573e7801d59Ssowmini /* name, header, field width, offset, cmdtype */ 574e7801d59Ssowmini { "link", "LINK", 11, 575e7801d59Ssowmini offsetof(link_fields_buf_t, link_name), CMD_TYPE_ANY}, 576e7801d59Ssowmini { "class", "CLASS", 8, 577e7801d59Ssowmini offsetof(link_fields_buf_t, link_class), CMD_TYPE_ANY}, 578e7801d59Ssowmini { "mtu", "MTU", 6, 579e7801d59Ssowmini offsetof(link_fields_buf_t, link_mtu), CMD_TYPE_ANY}, 580e7801d59Ssowmini { "state", "STATE", 8, 581e7801d59Ssowmini offsetof(link_fields_buf_t, link_state), CMD_TYPE_ANY}, 582e7801d59Ssowmini { "over", "OVER", DLPI_LINKNAME_MAX, 583e7801d59Ssowmini offsetof(link_fields_buf_t, link_over), CMD_TYPE_ANY}} 584e7801d59Ssowmini ; 585e7801d59Ssowmini #define DEV_LINK_FIELDS (sizeof (link_fields) / sizeof (print_field_t)) 586e7801d59Ssowmini 587e7801d59Ssowmini /* 588e7801d59Ssowmini * structures for 'dladm show-aggr' 589e7801d59Ssowmini */ 590e7801d59Ssowmini typedef struct laggr_fields_buf_s { 591e7801d59Ssowmini char laggr_name[DLPI_LINKNAME_MAX]; 592e7801d59Ssowmini char laggr_policy[9]; 593e7801d59Ssowmini char laggr_addrpolicy[ETHERADDRL * 3 + 3]; 594e7801d59Ssowmini char laggr_lacpactivity[14]; 595e7801d59Ssowmini char laggr_lacptimer[DLADM_STRSIZE]; 596e7801d59Ssowmini char laggr_flags[7]; 597e7801d59Ssowmini } laggr_fields_buf_t; 598e7801d59Ssowmini 599e7801d59Ssowmini typedef struct laggr_args_s { 600e7801d59Ssowmini int laggr_lport; /* -1 indicates the aggr itself */ 601e7801d59Ssowmini const char *laggr_link; 602e7801d59Ssowmini dladm_aggr_grp_attr_t *laggr_ginfop; 603e7801d59Ssowmini dladm_status_t *laggr_status; 604e7801d59Ssowmini pktsum_t *laggr_pktsumtot; /* -s only */ 605e7801d59Ssowmini pktsum_t *laggr_prevstats; /* -s only */ 606e7801d59Ssowmini boolean_t laggr_parseable; 607e7801d59Ssowmini } laggr_args_t; 608e7801d59Ssowmini 609e7801d59Ssowmini static print_field_t laggr_fields[] = { 610e7801d59Ssowmini /* name, header, field width, offset, cmdtype */ 611e7801d59Ssowmini { "link", "LINK", 15, 612e7801d59Ssowmini offsetof(laggr_fields_buf_t, laggr_name), CMD_TYPE_ANY}, 613e7801d59Ssowmini { "policy", "POLICY", 8, 614e7801d59Ssowmini offsetof(laggr_fields_buf_t, laggr_policy), CMD_TYPE_ANY}, 615e7801d59Ssowmini { "addrpolicy", "ADDRPOLICY", ETHERADDRL * 3 + 2, 616e7801d59Ssowmini offsetof(laggr_fields_buf_t, laggr_addrpolicy), CMD_TYPE_ANY}, 617e7801d59Ssowmini { "lacpactivity", "LACPACTIVITY", 13, 618e7801d59Ssowmini offsetof(laggr_fields_buf_t, laggr_lacpactivity), CMD_TYPE_ANY}, 619e7801d59Ssowmini { "lacptimer", "LACPTIMER", 11, 620e7801d59Ssowmini offsetof(laggr_fields_buf_t, laggr_lacptimer), CMD_TYPE_ANY}, 621e7801d59Ssowmini { "flags", "FLAGS", 7, 622e7801d59Ssowmini offsetof(laggr_fields_buf_t, laggr_flags), CMD_TYPE_ANY}} 623e7801d59Ssowmini ; 624e7801d59Ssowmini #define LAGGR_MAX_FIELDS (sizeof (laggr_fields) / sizeof (print_field_t)) 625e7801d59Ssowmini 626e7801d59Ssowmini /* 627e7801d59Ssowmini * structures for 'dladm show-aggr -x'. 628e7801d59Ssowmini */ 629e7801d59Ssowmini typedef enum { 630e7801d59Ssowmini AGGR_X_LINK, 631e7801d59Ssowmini AGGR_X_PORT, 632e7801d59Ssowmini AGGR_X_SPEED, 633e7801d59Ssowmini AGGR_X_DUPLEX, 634e7801d59Ssowmini AGGR_X_STATE, 635e7801d59Ssowmini AGGR_X_ADDRESS, 636e7801d59Ssowmini AGGR_X_PORTSTATE 637e7801d59Ssowmini } aggr_x_field_index_t; 638e7801d59Ssowmini 639e7801d59Ssowmini static print_field_t aggr_x_fields[] = { 640e7801d59Ssowmini /* name, header, field width, index, cmdtype */ 641e7801d59Ssowmini { "link", "LINK", 11, AGGR_X_LINK, CMD_TYPE_ANY}, 642e7801d59Ssowmini { "port", "PORT", 14, AGGR_X_PORT, CMD_TYPE_ANY}, 643e7801d59Ssowmini { "speed", "SPEED", 4, AGGR_X_SPEED, CMD_TYPE_ANY}, 644e7801d59Ssowmini { "duplex", "DUPLEX", 9, AGGR_X_DUPLEX, CMD_TYPE_ANY}, 645e7801d59Ssowmini { "state", "STATE", 9, AGGR_X_STATE, CMD_TYPE_ANY}, 646e7801d59Ssowmini { "address", "ADDRESS", 18, AGGR_X_ADDRESS, CMD_TYPE_ANY}, 647e7801d59Ssowmini { "portstate", "PORTSTATE", 15, AGGR_X_PORTSTATE, CMD_TYPE_ANY}} 648e7801d59Ssowmini ; 649e7801d59Ssowmini #define AGGR_X_MAX_FIELDS \ 650e7801d59Ssowmini (sizeof (aggr_x_fields) / sizeof (print_field_t)) 651e7801d59Ssowmini 652e7801d59Ssowmini /* 653e7801d59Ssowmini * structures for 'dladm show-aggr -s'. 654e7801d59Ssowmini */ 655e7801d59Ssowmini typedef enum { 656e7801d59Ssowmini AGGR_S_LINK, 657e7801d59Ssowmini AGGR_S_PORT, 658e7801d59Ssowmini AGGR_S_IPKTS, 659e7801d59Ssowmini AGGR_S_RBYTES, 660e7801d59Ssowmini AGGR_S_OPKTS, 661e7801d59Ssowmini AGGR_S_OBYTES, 662e7801d59Ssowmini AGGR_S_IPKTDIST, 663e7801d59Ssowmini AGGR_S_OPKTDIST 664e7801d59Ssowmini } aggr_s_field_index_t; 665e7801d59Ssowmini 666e7801d59Ssowmini static print_field_t aggr_s_fields[] = { 667e7801d59Ssowmini /* name, header, field width, index, cmdtype */ 668e7801d59Ssowmini { "link", "LINK", 11, AGGR_S_LINK, 669e7801d59Ssowmini CMD_TYPE_ANY}, 670e7801d59Ssowmini { "port", "PORT", 9, AGGR_S_PORT, 671e7801d59Ssowmini CMD_TYPE_ANY}, 672e7801d59Ssowmini { "ipackets", "IPACKETS", 7, AGGR_S_IPKTS, 673e7801d59Ssowmini CMD_TYPE_ANY}, 674e7801d59Ssowmini { "rbytes", "RBYTES", 7, AGGR_S_RBYTES, 675e7801d59Ssowmini CMD_TYPE_ANY}, 676e7801d59Ssowmini { "opackets", "OPACKETS", 7, AGGR_S_OPKTS, 677e7801d59Ssowmini CMD_TYPE_ANY}, 678e7801d59Ssowmini { "obytes", "OBYTES", 7, AGGR_S_OBYTES, 679e7801d59Ssowmini CMD_TYPE_ANY}, 680e7801d59Ssowmini { "ipktdist", "IPKTDIST", 8, AGGR_S_IPKTDIST, 681e7801d59Ssowmini CMD_TYPE_ANY}, 682e7801d59Ssowmini { "opktdist", "OPKTDIST", 14, AGGR_S_OPKTDIST, 683e7801d59Ssowmini CMD_TYPE_ANY}} 684e7801d59Ssowmini ; 685e7801d59Ssowmini #define AGGR_S_MAX_FIELDS \ 686*da14cebeSEric Cheng (sizeof (aggr_s_fields) / sizeof (print_field_t)) 687e7801d59Ssowmini 688e7801d59Ssowmini /* 689*da14cebeSEric Cheng * structures for 'dladm show-aggr -L'. 690e7801d59Ssowmini */ 691e7801d59Ssowmini typedef enum { 692e7801d59Ssowmini AGGR_L_LINK, 693e7801d59Ssowmini AGGR_L_PORT, 694e7801d59Ssowmini AGGR_L_AGGREGATABLE, 695e7801d59Ssowmini AGGR_L_SYNC, 696e7801d59Ssowmini AGGR_L_COLL, 697e7801d59Ssowmini AGGR_L_DIST, 698e7801d59Ssowmini AGGR_L_DEFAULTED, 699e7801d59Ssowmini AGGR_L_EXPIRED 700e7801d59Ssowmini } aggr_l_field_index_t; 701e7801d59Ssowmini 702e7801d59Ssowmini static print_field_t aggr_l_fields[] = { 703e7801d59Ssowmini /* name, header, field width, index, cmdtype */ 704e7801d59Ssowmini { "link", "LINK", 11, AGGR_L_LINK, 705e7801d59Ssowmini CMD_TYPE_ANY}, 706e7801d59Ssowmini { "port", "PORT", 12, AGGR_L_PORT, 707e7801d59Ssowmini CMD_TYPE_ANY}, 708e7801d59Ssowmini { "aggregatable", "AGGREGATABLE", 12, AGGR_L_AGGREGATABLE, 709e7801d59Ssowmini CMD_TYPE_ANY}, 710e7801d59Ssowmini { "sync", "SYNC", 4, AGGR_L_SYNC, 711e7801d59Ssowmini CMD_TYPE_ANY}, 712e7801d59Ssowmini { "coll", "COLL", 4, AGGR_L_COLL, 713e7801d59Ssowmini CMD_TYPE_ANY}, 714e7801d59Ssowmini { "dist", "DIST", 4, AGGR_L_DIST, 715e7801d59Ssowmini CMD_TYPE_ANY}, 716e7801d59Ssowmini { "defaulted", "DEFAULTED", 9, AGGR_L_DEFAULTED, 717e7801d59Ssowmini CMD_TYPE_ANY}, 718e7801d59Ssowmini { "expired", "EXPIRED", 14, AGGR_L_EXPIRED, 719e7801d59Ssowmini CMD_TYPE_ANY}} 720e7801d59Ssowmini ; 721e7801d59Ssowmini #define AGGR_L_MAX_FIELDS \ 722e7801d59Ssowmini (sizeof (aggr_l_fields) / sizeof (print_field_t)) 723e7801d59Ssowmini 724e7801d59Ssowmini /* 725e7801d59Ssowmini * structures for 'dladm show-phys' 726e7801d59Ssowmini */ 727e7801d59Ssowmini 728e7801d59Ssowmini static print_field_t phys_fields[] = { 729e7801d59Ssowmini /* name, header, field width, offset, cmdtype */ 730e7801d59Ssowmini { "link", "LINK", 12, 731e7801d59Ssowmini offsetof(link_fields_buf_t, link_name), CMD_TYPE_ANY}, 732e7801d59Ssowmini { "media", "MEDIA", 20, 733e7801d59Ssowmini offsetof(link_fields_buf_t, link_phys_media), CMD_TYPE_ANY}, 734e7801d59Ssowmini { "state", "STATE", 10, 735e7801d59Ssowmini offsetof(link_fields_buf_t, link_phys_state), CMD_TYPE_ANY}, 7366be03d0bSVasumathi Sundaram - Sun Microsystems { "speed", "SPEED", 6, 737e7801d59Ssowmini offsetof(link_fields_buf_t, link_phys_speed), CMD_TYPE_ANY}, 738e7801d59Ssowmini { "duplex", "DUPLEX", 9, 739e7801d59Ssowmini offsetof(link_fields_buf_t, link_phys_duplex), CMD_TYPE_ANY}, 740e7801d59Ssowmini { "device", "DEVICE", 12, 741e7801d59Ssowmini offsetof(link_fields_buf_t, link_phys_device), CMD_TYPE_ANY}, 742e7801d59Ssowmini { "flags", "FLAGS", 6, 743e7801d59Ssowmini offsetof(link_fields_buf_t, link_flags), CMD_TYPE_ANY}} 744e7801d59Ssowmini ; 745e7801d59Ssowmini #define PHYS_MAX_FIELDS (sizeof (phys_fields) / sizeof (print_field_t)) 746e7801d59Ssowmini 747e7801d59Ssowmini /* 748*da14cebeSEric Cheng * structures for 'dladm show-phys -m' 749*da14cebeSEric Cheng */ 750*da14cebeSEric Cheng 751*da14cebeSEric Cheng typedef enum { 752*da14cebeSEric Cheng PHYS_M_LINK, 753*da14cebeSEric Cheng PHYS_M_SLOT, 754*da14cebeSEric Cheng PHYS_M_ADDRESS, 755*da14cebeSEric Cheng PHYS_M_INUSE, 756*da14cebeSEric Cheng PHYS_M_CLIENT 757*da14cebeSEric Cheng } phys_m_field_index_t; 758*da14cebeSEric Cheng 759*da14cebeSEric Cheng static print_field_t phys_m_fields[] = { 760*da14cebeSEric Cheng /* name, header, field width, offset, cmdtype */ 761*da14cebeSEric Cheng { "link", "LINK", 12, PHYS_M_LINK, CMD_TYPE_ANY}, 762*da14cebeSEric Cheng { "slot", "SLOT", 8, PHYS_M_SLOT, CMD_TYPE_ANY}, 763*da14cebeSEric Cheng { "address", "ADDRESS", 18, PHYS_M_ADDRESS, CMD_TYPE_ANY}, 764*da14cebeSEric Cheng { "inuse", "INUSE", 4, PHYS_M_INUSE, CMD_TYPE_ANY}, 765*da14cebeSEric Cheng { "client", "CLIENT", 12, PHYS_M_CLIENT, CMD_TYPE_ANY}} 766*da14cebeSEric Cheng ; 767*da14cebeSEric Cheng #define PHYS_M_MAX_FIELDS (sizeof (phys_m_fields) / sizeof (print_field_t)) 768*da14cebeSEric Cheng 769*da14cebeSEric Cheng /* 770*da14cebeSEric Cheng * structures for 'dladm show-phys -H' 771*da14cebeSEric Cheng */ 772*da14cebeSEric Cheng 773*da14cebeSEric Cheng typedef enum { 774*da14cebeSEric Cheng PHYS_H_LINK, 775*da14cebeSEric Cheng PHYS_H_GROUP, 776*da14cebeSEric Cheng PHYS_H_GRPTYPE, 777*da14cebeSEric Cheng PHYS_H_RINGS, 778*da14cebeSEric Cheng PHYS_H_CLIENTS 779*da14cebeSEric Cheng } phys_h_field_index_t; 780*da14cebeSEric Cheng 781*da14cebeSEric Cheng static print_field_t phys_h_fields[] = { 782*da14cebeSEric Cheng /* name, header, field width, offset, cmdtype */ 783*da14cebeSEric Cheng { "link", "LINK", 12, PHYS_H_LINK, CMD_TYPE_ANY}, 784*da14cebeSEric Cheng { "group", "GROUP", 8, PHYS_H_GROUP, CMD_TYPE_ANY}, 785*da14cebeSEric Cheng { "grouptype", "TYPE", 6, PHYS_H_GRPTYPE, CMD_TYPE_ANY}, 786*da14cebeSEric Cheng { "rings", "NUM-RINGS", 16, PHYS_H_RINGS, CMD_TYPE_ANY}, 787*da14cebeSEric Cheng { "clients", "CLIENTS", 20, PHYS_H_CLIENTS, CMD_TYPE_ANY}} 788*da14cebeSEric Cheng ; 789*da14cebeSEric Cheng #define PHYS_H_MAX_FIELDS (sizeof (phys_h_fields) / sizeof (print_field_t)) 790*da14cebeSEric Cheng 791*da14cebeSEric Cheng /* 792e7801d59Ssowmini * structures for 'dladm show-vlan' 793e7801d59Ssowmini */ 794e7801d59Ssowmini static print_field_t vlan_fields[] = { 795e7801d59Ssowmini /* name, header, field width, offset, cmdtype */ 796e7801d59Ssowmini { "link", "LINK", 15, 797e7801d59Ssowmini offsetof(link_fields_buf_t, link_name), CMD_TYPE_ANY}, 798e7801d59Ssowmini { "vid", "VID", 8, 799e7801d59Ssowmini offsetof(link_fields_buf_t, link_vlan_vid), CMD_TYPE_ANY}, 800e7801d59Ssowmini { "over", "OVER", 12, 801e7801d59Ssowmini offsetof(link_fields_buf_t, link_over), CMD_TYPE_ANY}, 802e7801d59Ssowmini { "flags", "FLAGS", 6, 803e7801d59Ssowmini offsetof(link_fields_buf_t, link_flags), CMD_TYPE_ANY}} 804e7801d59Ssowmini ; 805e7801d59Ssowmini #define VLAN_MAX_FIELDS (sizeof (vlan_fields) / sizeof (print_field_t)) 806e7801d59Ssowmini 807*da14cebeSEric Cheng 808e7801d59Ssowmini /* 809e7801d59Ssowmini * structures for 'dladm show-wifi' 810e7801d59Ssowmini */ 811e7801d59Ssowmini static print_field_t wifi_fields[] = { 812e7801d59Ssowmini { "link", "LINK", 10, 0, WIFI_CMD_ALL}, 813e7801d59Ssowmini { "essid", "ESSID", 19, DLADM_WLAN_ATTR_ESSID, WIFI_CMD_ALL}, 814e7801d59Ssowmini { "bssid", "BSSID/IBSSID", 17, DLADM_WLAN_ATTR_BSSID, WIFI_CMD_ALL}, 815e7801d59Ssowmini { "ibssid", "BSSID/IBSSID", 17, DLADM_WLAN_ATTR_BSSID, WIFI_CMD_ALL}, 816e7801d59Ssowmini { "mode", "MODE", 6, DLADM_WLAN_ATTR_MODE, WIFI_CMD_ALL}, 817e7801d59Ssowmini { "speed", "SPEED", 6, DLADM_WLAN_ATTR_SPEED, WIFI_CMD_ALL}, 818e7801d59Ssowmini { "auth", "AUTH", 8, DLADM_WLAN_ATTR_AUTH, WIFI_CMD_SHOW}, 819e7801d59Ssowmini { "bsstype", "BSSTYPE", 8, DLADM_WLAN_ATTR_BSSTYPE, WIFI_CMD_ALL}, 820e7801d59Ssowmini { "sec", "SEC", 6, DLADM_WLAN_ATTR_SECMODE, WIFI_CMD_ALL}, 821e7801d59Ssowmini { "status", "STATUS", 17, DLADM_WLAN_LINKATTR_STATUS, WIFI_CMD_SHOW}, 822e7801d59Ssowmini { "strength", "STRENGTH", 10, DLADM_WLAN_ATTR_STRENGTH, WIFI_CMD_ALL}} 823e7801d59Ssowmini ; 824e7801d59Ssowmini 825e7801d59Ssowmini static char *all_scan_wifi_fields = 826e7801d59Ssowmini "link,essid,bssid,sec,strength,mode,speed,bsstype"; 827e7801d59Ssowmini static char *all_show_wifi_fields = 828e7801d59Ssowmini "link,status,essid,sec,strength,mode,speed,auth,bssid,bsstype"; 829e7801d59Ssowmini static char *def_scan_wifi_fields = 830e7801d59Ssowmini "link,essid,bssid,sec,strength,mode,speed"; 831e7801d59Ssowmini static char *def_show_wifi_fields = 832e7801d59Ssowmini "link,status,essid,sec,strength,mode,speed"; 833e7801d59Ssowmini 834e7801d59Ssowmini #define WIFI_MAX_FIELDS (sizeof (wifi_fields) / sizeof (print_field_t)) 835e7801d59Ssowmini 836e7801d59Ssowmini /* 837e7801d59Ssowmini * structures for 'dladm show-linkprop' 838e7801d59Ssowmini */ 839e7801d59Ssowmini typedef enum { 840e7801d59Ssowmini LINKPROP_LINK, 841e7801d59Ssowmini LINKPROP_PROPERTY, 842afdda45fSVasumathi Sundaram - Sun Microsystems LINKPROP_PERM, 843e7801d59Ssowmini LINKPROP_VALUE, 844e7801d59Ssowmini LINKPROP_DEFAULT, 845e7801d59Ssowmini LINKPROP_POSSIBLE 846e7801d59Ssowmini } linkprop_field_index_t; 847e7801d59Ssowmini 848e7801d59Ssowmini static print_field_t linkprop_fields[] = { 849e7801d59Ssowmini /* name, header, field width, index, cmdtype */ 850e7801d59Ssowmini { "link", "LINK", 12, LINKPROP_LINK, CMD_TYPE_ANY}, 851e7801d59Ssowmini { "property", "PROPERTY", 15, LINKPROP_PROPERTY, CMD_TYPE_ANY}, 852afdda45fSVasumathi Sundaram - Sun Microsystems { "perm", "PERM", 4, LINKPROP_PERM, CMD_TYPE_ANY}, 853e7801d59Ssowmini { "value", "VALUE", 14, LINKPROP_VALUE, CMD_TYPE_ANY}, 854e7801d59Ssowmini { "default", "DEFAULT", 14, LINKPROP_DEFAULT, CMD_TYPE_ANY}, 855e7801d59Ssowmini { "possible", "POSSIBLE", 20, LINKPROP_POSSIBLE, CMD_TYPE_ANY}} 856e7801d59Ssowmini ; 857e7801d59Ssowmini #define LINKPROP_MAX_FIELDS \ 858e7801d59Ssowmini (sizeof (linkprop_fields) / sizeof (print_field_t)) 859e7801d59Ssowmini 860e7801d59Ssowmini #define MAX_PROP_LINE 512 861e7801d59Ssowmini 862e7801d59Ssowmini typedef struct show_linkprop_state { 863e7801d59Ssowmini char ls_link[MAXLINKNAMELEN]; 864e7801d59Ssowmini char *ls_line; 865e7801d59Ssowmini char **ls_propvals; 866*da14cebeSEric Cheng dladm_arg_list_t *ls_proplist; 867e7801d59Ssowmini boolean_t ls_parseable; 868e7801d59Ssowmini boolean_t ls_persist; 869e7801d59Ssowmini boolean_t ls_header; 870e7801d59Ssowmini dladm_status_t ls_status; 871e7801d59Ssowmini dladm_status_t ls_retstatus; 872e7801d59Ssowmini print_state_t ls_print; 873e7801d59Ssowmini } show_linkprop_state_t; 874e7801d59Ssowmini 875*da14cebeSEric Cheng typedef struct set_linkprop_state { 876*da14cebeSEric Cheng const char *ls_name; 877*da14cebeSEric Cheng boolean_t ls_reset; 878*da14cebeSEric Cheng boolean_t ls_temp; 879*da14cebeSEric Cheng dladm_status_t ls_status; 880*da14cebeSEric Cheng } set_linkprop_state_t; 881*da14cebeSEric Cheng 882e7801d59Ssowmini typedef struct linkprop_args_s { 883e7801d59Ssowmini show_linkprop_state_t *ls_state; 884e7801d59Ssowmini char *ls_propname; 885e7801d59Ssowmini datalink_id_t ls_linkid; 886e7801d59Ssowmini } linkprop_args_t; 887e7801d59Ssowmini 888e7801d59Ssowmini /* 889e7801d59Ssowmini * structures for 'dladm show-secobj' 890e7801d59Ssowmini */ 891e7801d59Ssowmini typedef struct secobj_fields_buf_s { 892e7801d59Ssowmini char ss_obj_name[DLADM_SECOBJ_VAL_MAX]; 893e7801d59Ssowmini char ss_class[20]; 894e7801d59Ssowmini char ss_val[30]; 895e7801d59Ssowmini } secobj_fields_buf_t; 896e7801d59Ssowmini static print_field_t secobj_fields[] = { 897e7801d59Ssowmini /* name, header, field width, offset, cmdtype */ 898e7801d59Ssowmini { "object", "OBJECT", 20, 899e7801d59Ssowmini offsetof(secobj_fields_buf_t, ss_obj_name), CMD_TYPE_ANY}, 900e7801d59Ssowmini { "class", "CLASS", 20, 901e7801d59Ssowmini offsetof(secobj_fields_buf_t, ss_class), CMD_TYPE_ANY}, 902e7801d59Ssowmini { "value", "VALUE", 30, 903e7801d59Ssowmini offsetof(secobj_fields_buf_t, ss_val), CMD_TYPE_ANY}} 904e7801d59Ssowmini ; 905e7801d59Ssowmini #define DEV_SOBJ_FIELDS (sizeof (secobj_fields) / sizeof (print_field_t)) 9060ba2cbe9Sxc151355 907*da14cebeSEric Cheng /* 908*da14cebeSEric Cheng * structures for 'dladm show-vnic' 909*da14cebeSEric Cheng */ 910*da14cebeSEric Cheng typedef struct vnic_fields_buf_s 911*da14cebeSEric Cheng { 912*da14cebeSEric Cheng char vnic_link[DLPI_LINKNAME_MAX]; 913*da14cebeSEric Cheng char vnic_over[DLPI_LINKNAME_MAX]; 914*da14cebeSEric Cheng char vnic_speed[6]; 915*da14cebeSEric Cheng char vnic_macaddr[19]; 916*da14cebeSEric Cheng char vnic_macaddrtype[19]; 917*da14cebeSEric Cheng char vnic_vid[6]; 918*da14cebeSEric Cheng } vnic_fields_buf_t; 919*da14cebeSEric Cheng 920*da14cebeSEric Cheng static print_field_t vnic_fields[] = { 921*da14cebeSEric Cheng /* name, header, field width, offset, cmdtype */ 922*da14cebeSEric Cheng { "link", "LINK", 12, 923*da14cebeSEric Cheng offsetof(vnic_fields_buf_t, vnic_link), CMD_TYPE_ANY}, 924*da14cebeSEric Cheng { "over", "OVER", 12, 925*da14cebeSEric Cheng offsetof(vnic_fields_buf_t, vnic_over), CMD_TYPE_ANY}, 926*da14cebeSEric Cheng { "speed", "SPEED", 6, 927*da14cebeSEric Cheng offsetof(vnic_fields_buf_t, vnic_speed), CMD_TYPE_ANY}, 928*da14cebeSEric Cheng { "macaddr", "MACADDRESS", 20, 929*da14cebeSEric Cheng offsetof(vnic_fields_buf_t, vnic_macaddr), CMD_TYPE_ANY}, 930*da14cebeSEric Cheng { "macaddrtype", "MACADDRTYPE", 19, 931*da14cebeSEric Cheng offsetof(vnic_fields_buf_t, vnic_macaddrtype), CMD_TYPE_ANY}, 932*da14cebeSEric Cheng { "vid", "VID", 6, 933*da14cebeSEric Cheng offsetof(vnic_fields_buf_t, vnic_vid), CMD_TYPE_ANY}} 934*da14cebeSEric Cheng ; 935*da14cebeSEric Cheng #define VNIC_MAX_FIELDS (sizeof (vnic_fields) / sizeof (print_field_t)) 936*da14cebeSEric Cheng 937*da14cebeSEric Cheng /* 938*da14cebeSEric Cheng * structures for 'dladm show-usage' 939*da14cebeSEric Cheng */ 940*da14cebeSEric Cheng 941*da14cebeSEric Cheng typedef struct usage_fields_buf_s { 942*da14cebeSEric Cheng char usage_link[12]; 943*da14cebeSEric Cheng char usage_duration[10]; 944*da14cebeSEric Cheng char usage_ipackets[9]; 945*da14cebeSEric Cheng char usage_rbytes[10]; 946*da14cebeSEric Cheng char usage_opackets[9]; 947*da14cebeSEric Cheng char usage_obytes[10]; 948*da14cebeSEric Cheng char usage_bandwidth[14]; 949*da14cebeSEric Cheng } usage_fields_buf_t; 950*da14cebeSEric Cheng 951*da14cebeSEric Cheng static print_field_t usage_fields[] = { 952*da14cebeSEric Cheng /* name, header, field width, offset, cmdtype */ 953*da14cebeSEric Cheng { "link", "LINK", 12, 954*da14cebeSEric Cheng offsetof(usage_fields_buf_t, usage_link), CMD_TYPE_ANY}, 955*da14cebeSEric Cheng { "duration", "DURATION", 10, 956*da14cebeSEric Cheng offsetof(usage_fields_buf_t, usage_duration), CMD_TYPE_ANY}, 957*da14cebeSEric Cheng { "ipackets", "IPACKETS", 9, 958*da14cebeSEric Cheng offsetof(usage_fields_buf_t, usage_ipackets), CMD_TYPE_ANY}, 959*da14cebeSEric Cheng { "rbytes", "RBYTES", 10, 960*da14cebeSEric Cheng offsetof(usage_fields_buf_t, usage_rbytes), CMD_TYPE_ANY}, 961*da14cebeSEric Cheng { "opackets", "OPACKETS", 9, 962*da14cebeSEric Cheng offsetof(usage_fields_buf_t, usage_opackets), CMD_TYPE_ANY}, 963*da14cebeSEric Cheng { "obytes", "OBYTES", 10, 964*da14cebeSEric Cheng offsetof(usage_fields_buf_t, usage_obytes), CMD_TYPE_ANY}, 965*da14cebeSEric Cheng { "bandwidth", "BANDWIDTH", 14, 966*da14cebeSEric Cheng offsetof(usage_fields_buf_t, usage_bandwidth), CMD_TYPE_ANY}} 967*da14cebeSEric Cheng ; 968*da14cebeSEric Cheng 969*da14cebeSEric Cheng #define USAGE_MAX_FIELDS (sizeof (usage_fields) / sizeof (print_field_t)) 970*da14cebeSEric Cheng 971*da14cebeSEric Cheng /* 972*da14cebeSEric Cheng * structures for 'dladm show-usage link' 973*da14cebeSEric Cheng */ 974*da14cebeSEric Cheng 975*da14cebeSEric Cheng typedef struct usage_l_fields_buf_s { 976*da14cebeSEric Cheng char usage_l_link[12]; 977*da14cebeSEric Cheng char usage_l_stime[13]; 978*da14cebeSEric Cheng char usage_l_etime[13]; 979*da14cebeSEric Cheng char usage_l_rbytes[8]; 980*da14cebeSEric Cheng char usage_l_obytes[8]; 981*da14cebeSEric Cheng char usage_l_bandwidth[14]; 982*da14cebeSEric Cheng } usage_l_fields_buf_t; 983*da14cebeSEric Cheng 984*da14cebeSEric Cheng static print_field_t usage_l_fields[] = { 985*da14cebeSEric Cheng /* name, header, field width, offset, cmdtype */ 986*da14cebeSEric Cheng { "link", "LINK", 12, 987*da14cebeSEric Cheng offsetof(usage_l_fields_buf_t, usage_l_link), CMD_TYPE_ANY}, 988*da14cebeSEric Cheng { "start", "START", 13, 989*da14cebeSEric Cheng offsetof(usage_l_fields_buf_t, usage_l_stime), CMD_TYPE_ANY}, 990*da14cebeSEric Cheng { "end", "END", 13, 991*da14cebeSEric Cheng offsetof(usage_l_fields_buf_t, usage_l_etime), CMD_TYPE_ANY}, 992*da14cebeSEric Cheng { "rbytes", "RBYTES", 8, 993*da14cebeSEric Cheng offsetof(usage_l_fields_buf_t, usage_l_rbytes), CMD_TYPE_ANY}, 994*da14cebeSEric Cheng { "obytes", "OBYTES", 8, 995*da14cebeSEric Cheng offsetof(usage_l_fields_buf_t, usage_l_obytes), CMD_TYPE_ANY}, 996*da14cebeSEric Cheng { "bandwidth", "BANDWIDTH", 14, 997*da14cebeSEric Cheng offsetof(usage_l_fields_buf_t, usage_l_bandwidth), CMD_TYPE_ANY}} 998*da14cebeSEric Cheng ; 999*da14cebeSEric Cheng 1000*da14cebeSEric Cheng #define USAGE_L_MAX_FIELDS \ 1001*da14cebeSEric Cheng (sizeof (usage_l_fields) /sizeof (print_field_t)) 1002*da14cebeSEric Cheng 10037c478bd9Sstevel@tonic-gate static char *progname; 10040ba2cbe9Sxc151355 static sig_atomic_t signalled; 10057c478bd9Sstevel@tonic-gate 1006*da14cebeSEric Cheng #define DLADM_ETHERSTUB_NAME "etherstub" 1007*da14cebeSEric Cheng #define DLADM_IS_ETHERSTUB(id) (id == DATALINK_INVALID_LINKID) 1008*da14cebeSEric Cheng 10097c478bd9Sstevel@tonic-gate static void 10107c478bd9Sstevel@tonic-gate usage(void) 10117c478bd9Sstevel@tonic-gate { 10128d5c46e6Sam223141 int i; 10138d5c46e6Sam223141 cmd_t *cmdp; 10148d5c46e6Sam223141 (void) fprintf(stderr, gettext("usage: dladm <subcommand> <args> ..." 10158d5c46e6Sam223141 "\n")); 10168d5c46e6Sam223141 for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) { 10178d5c46e6Sam223141 cmdp = &cmds[i]; 10188d5c46e6Sam223141 if (cmdp->c_usage != NULL) 10198d5c46e6Sam223141 (void) fprintf(stderr, "%s\n", gettext(cmdp->c_usage)); 10208d5c46e6Sam223141 } 10217c478bd9Sstevel@tonic-gate exit(1); 10227c478bd9Sstevel@tonic-gate } 10237c478bd9Sstevel@tonic-gate 10247c478bd9Sstevel@tonic-gate int 10257c478bd9Sstevel@tonic-gate main(int argc, char *argv[]) 10267c478bd9Sstevel@tonic-gate { 10277c478bd9Sstevel@tonic-gate int i; 10287c478bd9Sstevel@tonic-gate cmd_t *cmdp; 10297c478bd9Sstevel@tonic-gate 10307c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 10317c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) 10327c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" 10337c478bd9Sstevel@tonic-gate #endif 10347c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 10357c478bd9Sstevel@tonic-gate 10367c478bd9Sstevel@tonic-gate progname = argv[0]; 10377c478bd9Sstevel@tonic-gate 10387c478bd9Sstevel@tonic-gate if (argc < 2) 10397c478bd9Sstevel@tonic-gate usage(); 10407c478bd9Sstevel@tonic-gate 10417c478bd9Sstevel@tonic-gate for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) { 10427c478bd9Sstevel@tonic-gate cmdp = &cmds[i]; 10437c478bd9Sstevel@tonic-gate if (strcmp(argv[1], cmdp->c_name) == 0) { 10448d5c46e6Sam223141 cmdp->c_fn(argc - 1, &argv[1], cmdp->c_usage); 10457c478bd9Sstevel@tonic-gate exit(0); 10467c478bd9Sstevel@tonic-gate } 10477c478bd9Sstevel@tonic-gate } 10487c478bd9Sstevel@tonic-gate 10497c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: unknown subcommand '%s'\n"), 10507c478bd9Sstevel@tonic-gate progname, argv[1]); 10517c478bd9Sstevel@tonic-gate usage(); 10527c478bd9Sstevel@tonic-gate 10537c478bd9Sstevel@tonic-gate return (0); 10547c478bd9Sstevel@tonic-gate } 10557c478bd9Sstevel@tonic-gate 1056*da14cebeSEric Cheng /*ARGSUSED*/ 1057*da14cebeSEric Cheng static int 1058*da14cebeSEric Cheng show_usage_date(dladm_usage_t *usage, void *arg) 1059*da14cebeSEric Cheng { 1060*da14cebeSEric Cheng 1061*da14cebeSEric Cheng time_t stime; 1062*da14cebeSEric Cheng char timebuf[20]; 1063*da14cebeSEric Cheng 1064*da14cebeSEric Cheng stime = usage->du_stime; 1065*da14cebeSEric Cheng (void) strftime(timebuf, sizeof (timebuf), "%m/%d/%Y", 1066*da14cebeSEric Cheng localtime(&stime)); 1067*da14cebeSEric Cheng (void) printf("%s\n", timebuf); 1068*da14cebeSEric Cheng 1069*da14cebeSEric Cheng return (DLADM_STATUS_OK); 1070*da14cebeSEric Cheng } 1071*da14cebeSEric Cheng 1072*da14cebeSEric Cheng static int 1073*da14cebeSEric Cheng show_usage_time(dladm_usage_t *usage, void *arg) 1074*da14cebeSEric Cheng { 1075*da14cebeSEric Cheng show_usage_state_t *state = (show_usage_state_t *)arg; 1076*da14cebeSEric Cheng char buf[DLADM_STRSIZE]; 1077*da14cebeSEric Cheng usage_l_fields_buf_t ubuf; 1078*da14cebeSEric Cheng time_t time; 1079*da14cebeSEric Cheng double bw; 1080*da14cebeSEric Cheng 1081*da14cebeSEric Cheng if (state->us_plot) { 1082*da14cebeSEric Cheng if (!state->us_printheader) { 1083*da14cebeSEric Cheng if (state->us_first) { 1084*da14cebeSEric Cheng (void) printf("# Time"); 1085*da14cebeSEric Cheng state->us_first = B_FALSE; 1086*da14cebeSEric Cheng } 1087*da14cebeSEric Cheng (void) printf(" %s", usage->du_name); 1088*da14cebeSEric Cheng if (usage->du_last) { 1089*da14cebeSEric Cheng (void) printf("\n"); 1090*da14cebeSEric Cheng state->us_first = B_TRUE; 1091*da14cebeSEric Cheng state->us_printheader = B_TRUE; 1092*da14cebeSEric Cheng } 1093*da14cebeSEric Cheng } else { 1094*da14cebeSEric Cheng if (state->us_first) { 1095*da14cebeSEric Cheng time = usage->du_etime; 1096*da14cebeSEric Cheng (void) strftime(buf, sizeof (buf), "%T", 1097*da14cebeSEric Cheng localtime(&time)); 1098*da14cebeSEric Cheng state->us_first = B_FALSE; 1099*da14cebeSEric Cheng (void) printf("%s", buf); 1100*da14cebeSEric Cheng } 1101*da14cebeSEric Cheng bw = (double)usage->du_bandwidth/1000; 1102*da14cebeSEric Cheng (void) printf(" %.2f", bw); 1103*da14cebeSEric Cheng if (usage->du_last) { 1104*da14cebeSEric Cheng (void) printf("\n"); 1105*da14cebeSEric Cheng state->us_first = B_TRUE; 1106*da14cebeSEric Cheng } 1107*da14cebeSEric Cheng } 1108*da14cebeSEric Cheng return (DLADM_STATUS_OK); 1109*da14cebeSEric Cheng } 1110*da14cebeSEric Cheng 1111*da14cebeSEric Cheng bzero(&ubuf, sizeof (ubuf)); 1112*da14cebeSEric Cheng 1113*da14cebeSEric Cheng (void) snprintf(ubuf.usage_l_link, sizeof (ubuf.usage_l_link), "%s", 1114*da14cebeSEric Cheng usage->du_name); 1115*da14cebeSEric Cheng time = usage->du_stime; 1116*da14cebeSEric Cheng (void) strftime(buf, sizeof (buf), "%T", localtime(&time)); 1117*da14cebeSEric Cheng (void) snprintf(ubuf.usage_l_stime, sizeof (ubuf.usage_l_stime), "%s", 1118*da14cebeSEric Cheng buf); 1119*da14cebeSEric Cheng time = usage->du_etime; 1120*da14cebeSEric Cheng (void) strftime(buf, sizeof (buf), "%T", localtime(&time)); 1121*da14cebeSEric Cheng (void) snprintf(ubuf.usage_l_etime, sizeof (ubuf.usage_l_etime), "%s", 1122*da14cebeSEric Cheng buf); 1123*da14cebeSEric Cheng (void) snprintf(ubuf.usage_l_rbytes, sizeof (ubuf.usage_l_rbytes), 1124*da14cebeSEric Cheng "%llu", usage->du_rbytes); 1125*da14cebeSEric Cheng (void) snprintf(ubuf.usage_l_obytes, sizeof (ubuf.usage_l_obytes), 1126*da14cebeSEric Cheng "%llu", usage->du_obytes); 1127*da14cebeSEric Cheng (void) snprintf(ubuf.usage_l_bandwidth, sizeof (ubuf.usage_l_bandwidth), 1128*da14cebeSEric Cheng "%s Mbps", dladm_bw2str(usage->du_bandwidth, buf)); 1129*da14cebeSEric Cheng 1130*da14cebeSEric Cheng if (!state->us_parseable && !state->us_printheader) { 1131*da14cebeSEric Cheng print_header(&state->us_print); 1132*da14cebeSEric Cheng state->us_printheader = B_TRUE; 1133*da14cebeSEric Cheng } 1134*da14cebeSEric Cheng 1135*da14cebeSEric Cheng dladm_print_output(&state->us_print, state->us_parseable, 1136*da14cebeSEric Cheng dladm_print_field, (void *)&ubuf); 1137*da14cebeSEric Cheng 1138*da14cebeSEric Cheng return (DLADM_STATUS_OK); 1139*da14cebeSEric Cheng } 1140*da14cebeSEric Cheng 1141*da14cebeSEric Cheng static int 1142*da14cebeSEric Cheng show_usage_res(dladm_usage_t *usage, void *arg) 1143*da14cebeSEric Cheng { 1144*da14cebeSEric Cheng show_usage_state_t *state = (show_usage_state_t *)arg; 1145*da14cebeSEric Cheng char buf[DLADM_STRSIZE]; 1146*da14cebeSEric Cheng usage_fields_buf_t ubuf; 1147*da14cebeSEric Cheng 1148*da14cebeSEric Cheng bzero(&ubuf, sizeof (ubuf)); 1149*da14cebeSEric Cheng 1150*da14cebeSEric Cheng (void) snprintf(ubuf.usage_link, sizeof (ubuf.usage_link), "%s", 1151*da14cebeSEric Cheng usage->du_name); 1152*da14cebeSEric Cheng (void) snprintf(ubuf.usage_duration, sizeof (ubuf.usage_duration), 1153*da14cebeSEric Cheng "%llu", usage->du_duration); 1154*da14cebeSEric Cheng (void) snprintf(ubuf.usage_ipackets, sizeof (ubuf.usage_ipackets), 1155*da14cebeSEric Cheng "%llu", usage->du_ipackets); 1156*da14cebeSEric Cheng (void) snprintf(ubuf.usage_rbytes, sizeof (ubuf.usage_rbytes), 1157*da14cebeSEric Cheng "%llu", usage->du_rbytes); 1158*da14cebeSEric Cheng (void) snprintf(ubuf.usage_opackets, sizeof (ubuf.usage_opackets), 1159*da14cebeSEric Cheng "%llu", usage->du_opackets); 1160*da14cebeSEric Cheng (void) snprintf(ubuf.usage_obytes, sizeof (ubuf.usage_obytes), 1161*da14cebeSEric Cheng "%llu", usage->du_obytes); 1162*da14cebeSEric Cheng (void) snprintf(ubuf.usage_bandwidth, sizeof (ubuf.usage_bandwidth), 1163*da14cebeSEric Cheng "%s Mbps", dladm_bw2str(usage->du_bandwidth, buf)); 1164*da14cebeSEric Cheng 1165*da14cebeSEric Cheng if (!state->us_parseable && !state->us_printheader) { 1166*da14cebeSEric Cheng print_header(&state->us_print); 1167*da14cebeSEric Cheng state->us_printheader = B_TRUE; 1168*da14cebeSEric Cheng } 1169*da14cebeSEric Cheng 1170*da14cebeSEric Cheng dladm_print_output(&state->us_print, state->us_parseable, 1171*da14cebeSEric Cheng dladm_print_field, (void *)&ubuf); 1172*da14cebeSEric Cheng 1173*da14cebeSEric Cheng return (DLADM_STATUS_OK); 1174*da14cebeSEric Cheng } 1175*da14cebeSEric Cheng 1176*da14cebeSEric Cheng static boolean_t 1177*da14cebeSEric Cheng valid_formatspec(char *formatspec_str) 1178*da14cebeSEric Cheng { 1179*da14cebeSEric Cheng if (strcmp(formatspec_str, "gnuplot") == 0) 1180*da14cebeSEric Cheng return (B_TRUE); 1181*da14cebeSEric Cheng return (B_FALSE); 1182*da14cebeSEric Cheng 1183*da14cebeSEric Cheng } 1184*da14cebeSEric Cheng 1185*da14cebeSEric Cheng /*ARGSUSED*/ 1186*da14cebeSEric Cheng static void 1187*da14cebeSEric Cheng do_show_usage(int argc, char *argv[], const char *use) 1188*da14cebeSEric Cheng { 1189*da14cebeSEric Cheng char *file = NULL; 1190*da14cebeSEric Cheng int opt; 1191*da14cebeSEric Cheng dladm_status_t status; 1192*da14cebeSEric Cheng boolean_t d_arg = B_FALSE; 1193*da14cebeSEric Cheng boolean_t p_arg = B_FALSE; 1194*da14cebeSEric Cheng char *stime = NULL; 1195*da14cebeSEric Cheng char *etime = NULL; 1196*da14cebeSEric Cheng char *resource = NULL; 1197*da14cebeSEric Cheng show_usage_state_t state; 1198*da14cebeSEric Cheng boolean_t o_arg = B_FALSE; 1199*da14cebeSEric Cheng boolean_t F_arg = B_FALSE; 1200*da14cebeSEric Cheng char *fields_str = NULL; 1201*da14cebeSEric Cheng char *formatspec_str = NULL; 1202*da14cebeSEric Cheng print_field_t **fields; 1203*da14cebeSEric Cheng uint_t nfields; 1204*da14cebeSEric Cheng char *all_fields = 1205*da14cebeSEric Cheng "link,duration,ipackets,rbytes,opackets,obytes,bandwidth"; 1206*da14cebeSEric Cheng char *all_l_fields = 1207*da14cebeSEric Cheng "link,start,end,rbytes,obytes,bandwidth"; 1208*da14cebeSEric Cheng 1209*da14cebeSEric Cheng bzero(&state, sizeof (show_usage_state_t)); 1210*da14cebeSEric Cheng state.us_parseable = B_FALSE; 1211*da14cebeSEric Cheng state.us_printheader = B_FALSE; 1212*da14cebeSEric Cheng state.us_plot = B_FALSE; 1213*da14cebeSEric Cheng state.us_first = B_TRUE; 1214*da14cebeSEric Cheng 1215*da14cebeSEric Cheng while ((opt = getopt(argc, argv, "dps:e:o:f:F:")) != -1) { 1216*da14cebeSEric Cheng switch (opt) { 1217*da14cebeSEric Cheng case 'd': 1218*da14cebeSEric Cheng d_arg = B_TRUE; 1219*da14cebeSEric Cheng break; 1220*da14cebeSEric Cheng case 'p': 1221*da14cebeSEric Cheng state.us_plot = p_arg = B_TRUE; 1222*da14cebeSEric Cheng break; 1223*da14cebeSEric Cheng case 'f': 1224*da14cebeSEric Cheng file = optarg; 1225*da14cebeSEric Cheng break; 1226*da14cebeSEric Cheng case 's': 1227*da14cebeSEric Cheng stime = optarg; 1228*da14cebeSEric Cheng break; 1229*da14cebeSEric Cheng case 'e': 1230*da14cebeSEric Cheng etime = optarg; 1231*da14cebeSEric Cheng break; 1232*da14cebeSEric Cheng case 'o': 1233*da14cebeSEric Cheng o_arg = B_TRUE; 1234*da14cebeSEric Cheng fields_str = optarg; 1235*da14cebeSEric Cheng break; 1236*da14cebeSEric Cheng case 'F': 1237*da14cebeSEric Cheng F_arg = B_TRUE; 1238*da14cebeSEric Cheng formatspec_str = optarg; 1239*da14cebeSEric Cheng break; 1240*da14cebeSEric Cheng default: 1241*da14cebeSEric Cheng die_opterr(optopt, opt, use); 1242*da14cebeSEric Cheng break; 1243*da14cebeSEric Cheng } 1244*da14cebeSEric Cheng } 1245*da14cebeSEric Cheng 1246*da14cebeSEric Cheng if (file == NULL) 1247*da14cebeSEric Cheng die("show-usage requires a file"); 1248*da14cebeSEric Cheng 1249*da14cebeSEric Cheng if (optind == (argc-1)) { 1250*da14cebeSEric Cheng resource = argv[optind]; 1251*da14cebeSEric Cheng } 1252*da14cebeSEric Cheng 1253*da14cebeSEric Cheng if (resource == NULL && stime == NULL && etime == NULL) { 1254*da14cebeSEric Cheng if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) 1255*da14cebeSEric Cheng fields_str = all_fields; 1256*da14cebeSEric Cheng fields = parse_output_fields(fields_str, usage_fields, 1257*da14cebeSEric Cheng USAGE_MAX_FIELDS, CMD_TYPE_ANY, &nfields); 1258*da14cebeSEric Cheng } else { 1259*da14cebeSEric Cheng if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) 1260*da14cebeSEric Cheng fields_str = all_l_fields; 1261*da14cebeSEric Cheng fields = parse_output_fields(fields_str, usage_l_fields, 1262*da14cebeSEric Cheng USAGE_L_MAX_FIELDS, CMD_TYPE_ANY, &nfields); 1263*da14cebeSEric Cheng } 1264*da14cebeSEric Cheng 1265*da14cebeSEric Cheng if (fields == NULL) { 1266*da14cebeSEric Cheng die("invalid fields(s) specified"); 1267*da14cebeSEric Cheng return; 1268*da14cebeSEric Cheng } 1269*da14cebeSEric Cheng state.us_print.ps_fields = fields; 1270*da14cebeSEric Cheng state.us_print.ps_nfields = nfields; 1271*da14cebeSEric Cheng 1272*da14cebeSEric Cheng if (p_arg && d_arg) 1273*da14cebeSEric Cheng die("plot and date options are incompatible"); 1274*da14cebeSEric Cheng 1275*da14cebeSEric Cheng if (p_arg && !F_arg) 1276*da14cebeSEric Cheng die("specify format speicifier: -F <format>"); 1277*da14cebeSEric Cheng 1278*da14cebeSEric Cheng if (F_arg && valid_formatspec(formatspec_str) == B_FALSE) 1279*da14cebeSEric Cheng die("Format specifier %s not supported", formatspec_str); 1280*da14cebeSEric Cheng 1281*da14cebeSEric Cheng if (d_arg) { 1282*da14cebeSEric Cheng /* Print log dates */ 1283*da14cebeSEric Cheng status = dladm_usage_dates(show_usage_date, 1284*da14cebeSEric Cheng DLADM_LOGTYPE_LINK, file, resource, &state); 1285*da14cebeSEric Cheng } else if (resource == NULL && stime == NULL && etime == NULL && 1286*da14cebeSEric Cheng !p_arg) { 1287*da14cebeSEric Cheng /* Print summary */ 1288*da14cebeSEric Cheng status = dladm_usage_summary(show_usage_res, 1289*da14cebeSEric Cheng DLADM_LOGTYPE_LINK, file, &state); 1290*da14cebeSEric Cheng } else if (resource != NULL) { 1291*da14cebeSEric Cheng /* Print log entries for named resource */ 1292*da14cebeSEric Cheng status = dladm_walk_usage_res(show_usage_time, 1293*da14cebeSEric Cheng DLADM_LOGTYPE_LINK, file, resource, stime, etime, &state); 1294*da14cebeSEric Cheng } else { 1295*da14cebeSEric Cheng /* Print time and information for each link */ 1296*da14cebeSEric Cheng status = dladm_walk_usage_time(show_usage_time, 1297*da14cebeSEric Cheng DLADM_LOGTYPE_LINK, file, stime, etime, &state); 1298*da14cebeSEric Cheng } 1299*da14cebeSEric Cheng 1300*da14cebeSEric Cheng if (status != DLADM_STATUS_OK) 1301*da14cebeSEric Cheng die_dlerr(status, "show-usage"); 1302*da14cebeSEric Cheng } 1303*da14cebeSEric Cheng 13047c478bd9Sstevel@tonic-gate static void 13058d5c46e6Sam223141 do_create_aggr(int argc, char *argv[], const char *use) 13067c478bd9Sstevel@tonic-gate { 13077c478bd9Sstevel@tonic-gate char option; 1308d62bc4baSyz147064 int key = 0; 13097c478bd9Sstevel@tonic-gate uint32_t policy = AGGR_POLICY_L4; 13107c478bd9Sstevel@tonic-gate aggr_lacp_mode_t lacp_mode = AGGR_LACP_OFF; 13117c478bd9Sstevel@tonic-gate aggr_lacp_timer_t lacp_timer = AGGR_LACP_TIMER_SHORT; 1312f595a68aSyz147064 dladm_aggr_port_attr_db_t port[MAXPORT]; 1313d62bc4baSyz147064 uint_t n, ndev, nlink; 13147c478bd9Sstevel@tonic-gate uint8_t mac_addr[ETHERADDRL]; 13157c478bd9Sstevel@tonic-gate boolean_t mac_addr_fixed = B_FALSE; 13167c478bd9Sstevel@tonic-gate boolean_t P_arg = B_FALSE; 13177c478bd9Sstevel@tonic-gate boolean_t l_arg = B_FALSE; 13187c478bd9Sstevel@tonic-gate boolean_t u_arg = B_FALSE; 13197c478bd9Sstevel@tonic-gate boolean_t T_arg = B_FALSE; 1320d62bc4baSyz147064 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 13217c478bd9Sstevel@tonic-gate char *altroot = NULL; 1322d62bc4baSyz147064 char name[MAXLINKNAMELEN]; 1323d62bc4baSyz147064 char *devs[MAXPORT]; 1324d62bc4baSyz147064 char *links[MAXPORT]; 1325f595a68aSyz147064 dladm_status_t status; 1326*da14cebeSEric Cheng dladm_status_t pstatus; 1327*da14cebeSEric Cheng dladm_arg_list_t *proplist = NULL; 1328*da14cebeSEric Cheng int i; 1329*da14cebeSEric Cheng datalink_id_t linkid; 13307c478bd9Sstevel@tonic-gate 1331d62bc4baSyz147064 ndev = nlink = opterr = 0; 1332*da14cebeSEric Cheng while ((option = getopt_long(argc, argv, ":d:l:L:P:R:tfu:T:p:", 1333d62bc4baSyz147064 lopts, NULL)) != -1) { 13347c478bd9Sstevel@tonic-gate switch (option) { 13357c478bd9Sstevel@tonic-gate case 'd': 1336d62bc4baSyz147064 if (ndev + nlink >= MAXPORT) 1337d62bc4baSyz147064 die("too many ports specified"); 13387c478bd9Sstevel@tonic-gate 1339d62bc4baSyz147064 devs[ndev++] = optarg; 13407c478bd9Sstevel@tonic-gate break; 13417c478bd9Sstevel@tonic-gate case 'P': 134233343a97Smeem if (P_arg) 134333343a97Smeem die_optdup(option); 13447c478bd9Sstevel@tonic-gate 13457c478bd9Sstevel@tonic-gate P_arg = B_TRUE; 1346f595a68aSyz147064 if (!dladm_aggr_str2policy(optarg, &policy)) 134733343a97Smeem die("invalid policy '%s'", optarg); 13487c478bd9Sstevel@tonic-gate break; 13497c478bd9Sstevel@tonic-gate case 'u': 135033343a97Smeem if (u_arg) 135133343a97Smeem die_optdup(option); 13527c478bd9Sstevel@tonic-gate 13537c478bd9Sstevel@tonic-gate u_arg = B_TRUE; 1354f595a68aSyz147064 if (!dladm_aggr_str2macaddr(optarg, &mac_addr_fixed, 135533343a97Smeem mac_addr)) 135633343a97Smeem die("invalid MAC address '%s'", optarg); 13577c478bd9Sstevel@tonic-gate break; 13587c478bd9Sstevel@tonic-gate case 'l': 1359d62bc4baSyz147064 if (isdigit(optarg[strlen(optarg) - 1])) { 1360d62bc4baSyz147064 1361d62bc4baSyz147064 /* 1362d62bc4baSyz147064 * Ended with digit, possibly a link name. 1363d62bc4baSyz147064 */ 1364d62bc4baSyz147064 if (ndev + nlink >= MAXPORT) 1365d62bc4baSyz147064 die("too many ports specified"); 1366d62bc4baSyz147064 1367d62bc4baSyz147064 links[nlink++] = optarg; 1368d62bc4baSyz147064 break; 1369d62bc4baSyz147064 } 1370d62bc4baSyz147064 /* FALLTHROUGH */ 1371d62bc4baSyz147064 case 'L': 137233343a97Smeem if (l_arg) 137333343a97Smeem die_optdup(option); 13747c478bd9Sstevel@tonic-gate 13757c478bd9Sstevel@tonic-gate l_arg = B_TRUE; 1376f595a68aSyz147064 if (!dladm_aggr_str2lacpmode(optarg, &lacp_mode)) 137733343a97Smeem die("invalid LACP mode '%s'", optarg); 13787c478bd9Sstevel@tonic-gate break; 13797c478bd9Sstevel@tonic-gate case 'T': 138033343a97Smeem if (T_arg) 138133343a97Smeem die_optdup(option); 13827c478bd9Sstevel@tonic-gate 13837c478bd9Sstevel@tonic-gate T_arg = B_TRUE; 1384f595a68aSyz147064 if (!dladm_aggr_str2lacptimer(optarg, &lacp_timer)) 138533343a97Smeem die("invalid LACP timer value '%s'", optarg); 13867c478bd9Sstevel@tonic-gate break; 13877c478bd9Sstevel@tonic-gate case 't': 1388d62bc4baSyz147064 flags &= ~DLADM_OPT_PERSIST; 1389d62bc4baSyz147064 break; 1390d62bc4baSyz147064 case 'f': 1391d62bc4baSyz147064 flags |= DLADM_OPT_FORCE; 13927c478bd9Sstevel@tonic-gate break; 13937c478bd9Sstevel@tonic-gate case 'R': 13947c478bd9Sstevel@tonic-gate altroot = optarg; 13957c478bd9Sstevel@tonic-gate break; 1396*da14cebeSEric Cheng case 'p': 1397*da14cebeSEric Cheng if (dladm_parse_link_props(optarg, &proplist, B_FALSE) 1398*da14cebeSEric Cheng != DLADM_STATUS_OK) 1399*da14cebeSEric Cheng die("invalid aggregation property"); 1400*da14cebeSEric Cheng break; 14017c478bd9Sstevel@tonic-gate default: 14028d5c46e6Sam223141 die_opterr(optopt, option, use); 140333343a97Smeem break; 14047c478bd9Sstevel@tonic-gate } 14057c478bd9Sstevel@tonic-gate } 14067c478bd9Sstevel@tonic-gate 1407d62bc4baSyz147064 if (ndev + nlink == 0) 14087c478bd9Sstevel@tonic-gate usage(); 14097c478bd9Sstevel@tonic-gate 1410d62bc4baSyz147064 /* get key value or the aggregation name (required last argument) */ 14117c478bd9Sstevel@tonic-gate if (optind != (argc-1)) 14127c478bd9Sstevel@tonic-gate usage(); 14137c478bd9Sstevel@tonic-gate 1414d62bc4baSyz147064 if (!str2int(argv[optind], &key)) { 1415d62bc4baSyz147064 if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= 1416d62bc4baSyz147064 MAXLINKNAMELEN) { 1417d62bc4baSyz147064 die("link name too long '%s'", argv[optind]); 1418d62bc4baSyz147064 } 14197c478bd9Sstevel@tonic-gate 1420d62bc4baSyz147064 if (!dladm_valid_linkname(name)) 1421d62bc4baSyz147064 die("invalid link name '%s'", argv[optind]); 1422d62bc4baSyz147064 } else { 1423d62bc4baSyz147064 (void) snprintf(name, MAXLINKNAMELEN, "aggr%d", key); 1424d62bc4baSyz147064 } 1425d62bc4baSyz147064 1426d62bc4baSyz147064 if (altroot != NULL) 1427d62bc4baSyz147064 altroot_cmd(altroot, argc, argv); 1428d62bc4baSyz147064 1429d62bc4baSyz147064 for (n = 0; n < ndev; n++) { 1430d62bc4baSyz147064 if (dladm_dev2linkid(devs[n], &port[n].lp_linkid) != 1431d62bc4baSyz147064 DLADM_STATUS_OK) { 1432d62bc4baSyz147064 die("invalid dev name '%s'", devs[n]); 1433d62bc4baSyz147064 } 1434d62bc4baSyz147064 } 1435d62bc4baSyz147064 1436d62bc4baSyz147064 for (n = 0; n < nlink; n++) { 1437d62bc4baSyz147064 if (dladm_name2info(links[n], &port[ndev + n].lp_linkid, 1438d62bc4baSyz147064 NULL, NULL, NULL) != DLADM_STATUS_OK) { 1439d62bc4baSyz147064 die("invalid link name '%s'", links[n]); 1440d62bc4baSyz147064 } 1441d62bc4baSyz147064 } 1442d62bc4baSyz147064 1443d62bc4baSyz147064 status = dladm_aggr_create(name, key, ndev + nlink, port, policy, 1444d62bc4baSyz147064 mac_addr_fixed, (const uchar_t *)mac_addr, lacp_mode, 1445d62bc4baSyz147064 lacp_timer, flags); 1446*da14cebeSEric Cheng if (status != DLADM_STATUS_OK) 1447*da14cebeSEric Cheng goto done; 1448*da14cebeSEric Cheng 1449*da14cebeSEric Cheng if (proplist == NULL) 1450*da14cebeSEric Cheng return; 1451*da14cebeSEric Cheng 1452*da14cebeSEric Cheng status = dladm_name2info(name, &linkid, NULL, NULL, NULL); 1453*da14cebeSEric Cheng if (status != DLADM_STATUS_OK) 1454*da14cebeSEric Cheng goto done; 1455*da14cebeSEric Cheng 1456*da14cebeSEric Cheng for (i = 0; i < proplist->al_count; i++) { 1457*da14cebeSEric Cheng dladm_arg_info_t *aip = &proplist->al_info[i]; 1458*da14cebeSEric Cheng 1459*da14cebeSEric Cheng pstatus = dladm_set_linkprop(linkid, aip->ai_name, 1460*da14cebeSEric Cheng aip->ai_val, aip->ai_count, flags); 1461*da14cebeSEric Cheng 1462*da14cebeSEric Cheng if (pstatus != DLADM_STATUS_OK) { 1463*da14cebeSEric Cheng die_dlerr(pstatus, 1464*da14cebeSEric Cheng "aggr creation succeeded but " 1465*da14cebeSEric Cheng "could not set property '%s'", aip->ai_name); 1466*da14cebeSEric Cheng } 1467*da14cebeSEric Cheng } 1468d62bc4baSyz147064 done: 1469*da14cebeSEric Cheng dladm_free_props(proplist); 1470d62bc4baSyz147064 if (status != DLADM_STATUS_OK) { 1471d62bc4baSyz147064 if (status == DLADM_STATUS_NONOTIF) { 1472d62bc4baSyz147064 die_dlerr(status, "not all links have link up/down " 1473d62bc4baSyz147064 "detection; must use -f (see dladm(1M))\n"); 1474d62bc4baSyz147064 } else { 1475f595a68aSyz147064 die_dlerr(status, "create operation failed"); 14767c478bd9Sstevel@tonic-gate } 1477d62bc4baSyz147064 } 1478d62bc4baSyz147064 } 1479d62bc4baSyz147064 1480d62bc4baSyz147064 /* 1481d62bc4baSyz147064 * arg is either the key or the aggr name. Validate it and convert it to 1482d62bc4baSyz147064 * the linkid if altroot is NULL. 1483d62bc4baSyz147064 */ 1484d62bc4baSyz147064 static dladm_status_t 1485d62bc4baSyz147064 i_dladm_aggr_get_linkid(const char *altroot, const char *arg, 1486d62bc4baSyz147064 datalink_id_t *linkidp, uint32_t flags) 1487d62bc4baSyz147064 { 1488d62bc4baSyz147064 int key = 0; 1489d62bc4baSyz147064 char *aggr = NULL; 1490d62bc4baSyz147064 dladm_status_t status; 1491d62bc4baSyz147064 1492d62bc4baSyz147064 if (!str2int(arg, &key)) 1493d62bc4baSyz147064 aggr = (char *)arg; 1494d62bc4baSyz147064 1495d62bc4baSyz147064 if (aggr == NULL && key == 0) 1496d62bc4baSyz147064 return (DLADM_STATUS_LINKINVAL); 1497d62bc4baSyz147064 1498d62bc4baSyz147064 if (altroot != NULL) 1499d62bc4baSyz147064 return (DLADM_STATUS_OK); 1500d62bc4baSyz147064 1501d62bc4baSyz147064 if (aggr != NULL) { 1502d62bc4baSyz147064 status = dladm_name2info(aggr, linkidp, NULL, NULL, NULL); 1503d62bc4baSyz147064 } else { 1504d62bc4baSyz147064 status = dladm_key2linkid(key, linkidp, flags); 1505d62bc4baSyz147064 } 1506d62bc4baSyz147064 1507d62bc4baSyz147064 return (status); 1508d62bc4baSyz147064 } 15097c478bd9Sstevel@tonic-gate 15107c478bd9Sstevel@tonic-gate static void 15118d5c46e6Sam223141 do_delete_aggr(int argc, char *argv[], const char *use) 15127c478bd9Sstevel@tonic-gate { 15137c478bd9Sstevel@tonic-gate char option; 15147c478bd9Sstevel@tonic-gate char *altroot = NULL; 1515d62bc4baSyz147064 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 1516f595a68aSyz147064 dladm_status_t status; 1517d62bc4baSyz147064 datalink_id_t linkid; 15187c478bd9Sstevel@tonic-gate 15197c478bd9Sstevel@tonic-gate opterr = 0; 1520d62bc4baSyz147064 while ((option = getopt_long(argc, argv, ":R:t", lopts, NULL)) != -1) { 15217c478bd9Sstevel@tonic-gate switch (option) { 15227c478bd9Sstevel@tonic-gate case 't': 1523d62bc4baSyz147064 flags &= ~DLADM_OPT_PERSIST; 15247c478bd9Sstevel@tonic-gate break; 15257c478bd9Sstevel@tonic-gate case 'R': 15267c478bd9Sstevel@tonic-gate altroot = optarg; 15277c478bd9Sstevel@tonic-gate break; 15287c478bd9Sstevel@tonic-gate default: 15298d5c46e6Sam223141 die_opterr(optopt, option, use); 15307c478bd9Sstevel@tonic-gate break; 15317c478bd9Sstevel@tonic-gate } 15327c478bd9Sstevel@tonic-gate } 15337c478bd9Sstevel@tonic-gate 1534d62bc4baSyz147064 /* get key value or the aggregation name (required last argument) */ 15357c478bd9Sstevel@tonic-gate if (optind != (argc-1)) 15367c478bd9Sstevel@tonic-gate usage(); 15377c478bd9Sstevel@tonic-gate 1538d62bc4baSyz147064 status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags); 1539d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 1540d62bc4baSyz147064 goto done; 15417c478bd9Sstevel@tonic-gate 1542d62bc4baSyz147064 if (altroot != NULL) 1543d62bc4baSyz147064 altroot_cmd(altroot, argc, argv); 1544d62bc4baSyz147064 1545d62bc4baSyz147064 status = dladm_aggr_delete(linkid, flags); 1546d62bc4baSyz147064 done: 1547f595a68aSyz147064 if (status != DLADM_STATUS_OK) 1548f595a68aSyz147064 die_dlerr(status, "delete operation failed"); 15497c478bd9Sstevel@tonic-gate } 15507c478bd9Sstevel@tonic-gate 15517c478bd9Sstevel@tonic-gate static void 15528d5c46e6Sam223141 do_add_aggr(int argc, char *argv[], const char *use) 15537c478bd9Sstevel@tonic-gate { 15547c478bd9Sstevel@tonic-gate char option; 1555d62bc4baSyz147064 uint_t n, ndev, nlink; 15567c478bd9Sstevel@tonic-gate char *altroot = NULL; 1557d62bc4baSyz147064 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 1558d62bc4baSyz147064 datalink_id_t linkid; 1559f595a68aSyz147064 dladm_status_t status; 1560d62bc4baSyz147064 dladm_aggr_port_attr_db_t port[MAXPORT]; 1561d62bc4baSyz147064 char *devs[MAXPORT]; 1562d62bc4baSyz147064 char *links[MAXPORT]; 15637c478bd9Sstevel@tonic-gate 1564d62bc4baSyz147064 ndev = nlink = opterr = 0; 1565d62bc4baSyz147064 while ((option = getopt_long(argc, argv, ":d:l:R:tf", lopts, 15667c478bd9Sstevel@tonic-gate NULL)) != -1) { 15677c478bd9Sstevel@tonic-gate switch (option) { 15687c478bd9Sstevel@tonic-gate case 'd': 1569d62bc4baSyz147064 if (ndev + nlink >= MAXPORT) 1570d62bc4baSyz147064 die("too many ports specified"); 15717c478bd9Sstevel@tonic-gate 1572d62bc4baSyz147064 devs[ndev++] = optarg; 1573d62bc4baSyz147064 break; 1574d62bc4baSyz147064 case 'l': 1575d62bc4baSyz147064 if (ndev + nlink >= MAXPORT) 1576d62bc4baSyz147064 die("too many ports specified"); 157733343a97Smeem 1578d62bc4baSyz147064 links[nlink++] = optarg; 15797c478bd9Sstevel@tonic-gate break; 15807c478bd9Sstevel@tonic-gate case 't': 1581d62bc4baSyz147064 flags &= ~DLADM_OPT_PERSIST; 1582d62bc4baSyz147064 break; 1583d62bc4baSyz147064 case 'f': 1584d62bc4baSyz147064 flags |= DLADM_OPT_FORCE; 15857c478bd9Sstevel@tonic-gate break; 15867c478bd9Sstevel@tonic-gate case 'R': 15877c478bd9Sstevel@tonic-gate altroot = optarg; 15887c478bd9Sstevel@tonic-gate break; 15897c478bd9Sstevel@tonic-gate default: 15908d5c46e6Sam223141 die_opterr(optopt, option, use); 159133343a97Smeem break; 15927c478bd9Sstevel@tonic-gate } 15937c478bd9Sstevel@tonic-gate } 15947c478bd9Sstevel@tonic-gate 1595d62bc4baSyz147064 if (ndev + nlink == 0) 15967c478bd9Sstevel@tonic-gate usage(); 15977c478bd9Sstevel@tonic-gate 1598d62bc4baSyz147064 /* get key value or the aggregation name (required last argument) */ 15997c478bd9Sstevel@tonic-gate if (optind != (argc-1)) 16007c478bd9Sstevel@tonic-gate usage(); 16017c478bd9Sstevel@tonic-gate 1602d62bc4baSyz147064 if ((status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, 1603d62bc4baSyz147064 flags & (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST))) != 1604d62bc4baSyz147064 DLADM_STATUS_OK) { 1605d62bc4baSyz147064 goto done; 1606d62bc4baSyz147064 } 16077c478bd9Sstevel@tonic-gate 1608d62bc4baSyz147064 if (altroot != NULL) 1609d62bc4baSyz147064 altroot_cmd(altroot, argc, argv); 1610d62bc4baSyz147064 1611d62bc4baSyz147064 for (n = 0; n < ndev; n++) { 1612d62bc4baSyz147064 if (dladm_dev2linkid(devs[n], &(port[n].lp_linkid)) != 1613d62bc4baSyz147064 DLADM_STATUS_OK) { 1614d62bc4baSyz147064 die("invalid <dev> '%s'", devs[n]); 1615d62bc4baSyz147064 } 1616d62bc4baSyz147064 } 1617d62bc4baSyz147064 1618d62bc4baSyz147064 for (n = 0; n < nlink; n++) { 1619d62bc4baSyz147064 if (dladm_name2info(links[n], &port[n + ndev].lp_linkid, 1620d62bc4baSyz147064 NULL, NULL, NULL) != DLADM_STATUS_OK) { 1621d62bc4baSyz147064 die("invalid <link> '%s'", links[n]); 1622d62bc4baSyz147064 } 1623d62bc4baSyz147064 } 1624d62bc4baSyz147064 1625d62bc4baSyz147064 status = dladm_aggr_add(linkid, ndev + nlink, port, flags); 1626d62bc4baSyz147064 done: 1627f595a68aSyz147064 if (status != DLADM_STATUS_OK) { 1628219a2a31Shl157128 /* 1629f595a68aSyz147064 * checking DLADM_STATUS_NOTSUP is a temporary workaround 1630219a2a31Shl157128 * and should be removed once 6399681 is fixed. 1631219a2a31Shl157128 */ 1632f595a68aSyz147064 if (status == DLADM_STATUS_NOTSUP) { 1633219a2a31Shl157128 (void) fprintf(stderr, 1634219a2a31Shl157128 gettext("%s: add operation failed: %s\n"), 1635219a2a31Shl157128 progname, 1636d62bc4baSyz147064 gettext("link capabilities don't match")); 1637219a2a31Shl157128 exit(ENOTSUP); 1638d62bc4baSyz147064 } else if (status == DLADM_STATUS_NONOTIF) { 1639d62bc4baSyz147064 die_dlerr(status, "not all links have link up/down " 1640d62bc4baSyz147064 "detection; must use -f (see dladm(1M))\n"); 1641d62bc4baSyz147064 } else { 1642f595a68aSyz147064 die_dlerr(status, "add operation failed"); 16437c478bd9Sstevel@tonic-gate } 16447c478bd9Sstevel@tonic-gate } 1645d62bc4baSyz147064 } 16467c478bd9Sstevel@tonic-gate 16477c478bd9Sstevel@tonic-gate static void 16488d5c46e6Sam223141 do_remove_aggr(int argc, char *argv[], const char *use) 16497c478bd9Sstevel@tonic-gate { 16507c478bd9Sstevel@tonic-gate char option; 1651f595a68aSyz147064 dladm_aggr_port_attr_db_t port[MAXPORT]; 1652d62bc4baSyz147064 uint_t n, ndev, nlink; 1653d62bc4baSyz147064 char *devs[MAXPORT]; 1654d62bc4baSyz147064 char *links[MAXPORT]; 16557c478bd9Sstevel@tonic-gate char *altroot = NULL; 1656d62bc4baSyz147064 uint32_t flags; 1657d62bc4baSyz147064 datalink_id_t linkid; 1658f595a68aSyz147064 dladm_status_t status; 16597c478bd9Sstevel@tonic-gate 1660d62bc4baSyz147064 flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 1661d62bc4baSyz147064 ndev = nlink = opterr = 0; 1662d62bc4baSyz147064 while ((option = getopt_long(argc, argv, ":d:l:R:t", 1663d62bc4baSyz147064 lopts, NULL)) != -1) { 16647c478bd9Sstevel@tonic-gate switch (option) { 16657c478bd9Sstevel@tonic-gate case 'd': 1666d62bc4baSyz147064 if (ndev + nlink >= MAXPORT) 1667d62bc4baSyz147064 die("too many ports specified"); 16687c478bd9Sstevel@tonic-gate 1669d62bc4baSyz147064 devs[ndev++] = optarg; 1670d62bc4baSyz147064 break; 1671d62bc4baSyz147064 case 'l': 1672d62bc4baSyz147064 if (ndev + nlink >= MAXPORT) 1673d62bc4baSyz147064 die("too many ports specified"); 167433343a97Smeem 1675d62bc4baSyz147064 links[nlink++] = optarg; 16767c478bd9Sstevel@tonic-gate break; 16777c478bd9Sstevel@tonic-gate case 't': 1678d62bc4baSyz147064 flags &= ~DLADM_OPT_PERSIST; 16797c478bd9Sstevel@tonic-gate break; 16807c478bd9Sstevel@tonic-gate case 'R': 16817c478bd9Sstevel@tonic-gate altroot = optarg; 16827c478bd9Sstevel@tonic-gate break; 16837c478bd9Sstevel@tonic-gate default: 16848d5c46e6Sam223141 die_opterr(optopt, option, use); 168533343a97Smeem break; 16867c478bd9Sstevel@tonic-gate } 16877c478bd9Sstevel@tonic-gate } 16887c478bd9Sstevel@tonic-gate 1689d62bc4baSyz147064 if (ndev + nlink == 0) 16907c478bd9Sstevel@tonic-gate usage(); 16917c478bd9Sstevel@tonic-gate 1692d62bc4baSyz147064 /* get key value or the aggregation name (required last argument) */ 16937c478bd9Sstevel@tonic-gate if (optind != (argc-1)) 16947c478bd9Sstevel@tonic-gate usage(); 16957c478bd9Sstevel@tonic-gate 1696d62bc4baSyz147064 status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags); 1697d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 1698d62bc4baSyz147064 goto done; 16997c478bd9Sstevel@tonic-gate 1700d62bc4baSyz147064 if (altroot != NULL) 1701d62bc4baSyz147064 altroot_cmd(altroot, argc, argv); 1702d62bc4baSyz147064 1703d62bc4baSyz147064 for (n = 0; n < ndev; n++) { 1704d62bc4baSyz147064 if (dladm_dev2linkid(devs[n], &(port[n].lp_linkid)) != 1705d62bc4baSyz147064 DLADM_STATUS_OK) { 1706d62bc4baSyz147064 die("invalid <dev> '%s'", devs[n]); 1707d62bc4baSyz147064 } 1708d62bc4baSyz147064 } 1709d62bc4baSyz147064 1710d62bc4baSyz147064 for (n = 0; n < nlink; n++) { 1711d62bc4baSyz147064 if (dladm_name2info(links[n], &port[n + ndev].lp_linkid, 1712d62bc4baSyz147064 NULL, NULL, NULL) != DLADM_STATUS_OK) { 1713d62bc4baSyz147064 die("invalid <link> '%s'", links[n]); 1714d62bc4baSyz147064 } 1715d62bc4baSyz147064 } 1716d62bc4baSyz147064 1717d62bc4baSyz147064 status = dladm_aggr_remove(linkid, ndev + nlink, port, flags); 1718d62bc4baSyz147064 done: 1719f595a68aSyz147064 if (status != DLADM_STATUS_OK) 1720f595a68aSyz147064 die_dlerr(status, "remove operation failed"); 17217c478bd9Sstevel@tonic-gate } 17227c478bd9Sstevel@tonic-gate 17237c478bd9Sstevel@tonic-gate static void 17248d5c46e6Sam223141 do_modify_aggr(int argc, char *argv[], const char *use) 17257c478bd9Sstevel@tonic-gate { 17267c478bd9Sstevel@tonic-gate char option; 17277c478bd9Sstevel@tonic-gate uint32_t policy = AGGR_POLICY_L4; 17287c478bd9Sstevel@tonic-gate aggr_lacp_mode_t lacp_mode = AGGR_LACP_OFF; 17297c478bd9Sstevel@tonic-gate aggr_lacp_timer_t lacp_timer = AGGR_LACP_TIMER_SHORT; 17307c478bd9Sstevel@tonic-gate uint8_t mac_addr[ETHERADDRL]; 17317c478bd9Sstevel@tonic-gate boolean_t mac_addr_fixed = B_FALSE; 17327c478bd9Sstevel@tonic-gate uint8_t modify_mask = 0; 17337c478bd9Sstevel@tonic-gate char *altroot = NULL; 1734d62bc4baSyz147064 uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 1735d62bc4baSyz147064 datalink_id_t linkid; 1736f595a68aSyz147064 dladm_status_t status; 17377c478bd9Sstevel@tonic-gate 17387c478bd9Sstevel@tonic-gate opterr = 0; 1739d62bc4baSyz147064 while ((option = getopt_long(argc, argv, ":L:l:P:R:tu:T:", lopts, 17407c478bd9Sstevel@tonic-gate NULL)) != -1) { 17417c478bd9Sstevel@tonic-gate switch (option) { 17427c478bd9Sstevel@tonic-gate case 'P': 1743f595a68aSyz147064 if (modify_mask & DLADM_AGGR_MODIFY_POLICY) 174433343a97Smeem die_optdup(option); 17457c478bd9Sstevel@tonic-gate 1746f595a68aSyz147064 modify_mask |= DLADM_AGGR_MODIFY_POLICY; 17477c478bd9Sstevel@tonic-gate 1748f595a68aSyz147064 if (!dladm_aggr_str2policy(optarg, &policy)) 174933343a97Smeem die("invalid policy '%s'", optarg); 17507c478bd9Sstevel@tonic-gate break; 17517c478bd9Sstevel@tonic-gate case 'u': 1752f595a68aSyz147064 if (modify_mask & DLADM_AGGR_MODIFY_MAC) 175333343a97Smeem die_optdup(option); 17547c478bd9Sstevel@tonic-gate 1755f595a68aSyz147064 modify_mask |= DLADM_AGGR_MODIFY_MAC; 17567c478bd9Sstevel@tonic-gate 1757f595a68aSyz147064 if (!dladm_aggr_str2macaddr(optarg, &mac_addr_fixed, 175833343a97Smeem mac_addr)) 175933343a97Smeem die("invalid MAC address '%s'", optarg); 17607c478bd9Sstevel@tonic-gate break; 17617c478bd9Sstevel@tonic-gate case 'l': 1762d62bc4baSyz147064 case 'L': 1763f595a68aSyz147064 if (modify_mask & DLADM_AGGR_MODIFY_LACP_MODE) 176433343a97Smeem die_optdup(option); 17657c478bd9Sstevel@tonic-gate 1766f595a68aSyz147064 modify_mask |= DLADM_AGGR_MODIFY_LACP_MODE; 17677c478bd9Sstevel@tonic-gate 1768f595a68aSyz147064 if (!dladm_aggr_str2lacpmode(optarg, &lacp_mode)) 176933343a97Smeem die("invalid LACP mode '%s'", optarg); 17707c478bd9Sstevel@tonic-gate break; 17717c478bd9Sstevel@tonic-gate case 'T': 1772f595a68aSyz147064 if (modify_mask & DLADM_AGGR_MODIFY_LACP_TIMER) 177333343a97Smeem die_optdup(option); 17747c478bd9Sstevel@tonic-gate 1775f595a68aSyz147064 modify_mask |= DLADM_AGGR_MODIFY_LACP_TIMER; 17767c478bd9Sstevel@tonic-gate 1777f595a68aSyz147064 if (!dladm_aggr_str2lacptimer(optarg, &lacp_timer)) 177833343a97Smeem die("invalid LACP timer value '%s'", optarg); 17797c478bd9Sstevel@tonic-gate break; 17807c478bd9Sstevel@tonic-gate case 't': 1781d62bc4baSyz147064 flags &= ~DLADM_OPT_PERSIST; 17827c478bd9Sstevel@tonic-gate break; 17837c478bd9Sstevel@tonic-gate case 'R': 17847c478bd9Sstevel@tonic-gate altroot = optarg; 17857c478bd9Sstevel@tonic-gate break; 17867c478bd9Sstevel@tonic-gate default: 17878d5c46e6Sam223141 die_opterr(optopt, option, use); 178833343a97Smeem break; 17897c478bd9Sstevel@tonic-gate } 17907c478bd9Sstevel@tonic-gate } 17917c478bd9Sstevel@tonic-gate 179233343a97Smeem if (modify_mask == 0) 179333343a97Smeem die("at least one of the -PulT options must be specified"); 17947c478bd9Sstevel@tonic-gate 1795d62bc4baSyz147064 /* get key value or the aggregation name (required last argument) */ 17967c478bd9Sstevel@tonic-gate if (optind != (argc-1)) 17977c478bd9Sstevel@tonic-gate usage(); 17987c478bd9Sstevel@tonic-gate 1799d62bc4baSyz147064 status = i_dladm_aggr_get_linkid(altroot, argv[optind], &linkid, flags); 1800d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 1801d62bc4baSyz147064 goto done; 18027c478bd9Sstevel@tonic-gate 1803d62bc4baSyz147064 if (altroot != NULL) 1804d62bc4baSyz147064 altroot_cmd(altroot, argc, argv); 1805d62bc4baSyz147064 1806d62bc4baSyz147064 status = dladm_aggr_modify(linkid, modify_mask, policy, mac_addr_fixed, 1807d62bc4baSyz147064 (const uchar_t *)mac_addr, lacp_mode, lacp_timer, flags); 1808d62bc4baSyz147064 1809d62bc4baSyz147064 done: 1810f595a68aSyz147064 if (status != DLADM_STATUS_OK) 1811f595a68aSyz147064 die_dlerr(status, "modify operation failed"); 18127c478bd9Sstevel@tonic-gate } 18137c478bd9Sstevel@tonic-gate 18148d5c46e6Sam223141 /*ARGSUSED*/ 18157c478bd9Sstevel@tonic-gate static void 18168d5c46e6Sam223141 do_up_aggr(int argc, char *argv[], const char *use) 18177c478bd9Sstevel@tonic-gate { 1818d62bc4baSyz147064 datalink_id_t linkid = DATALINK_ALL_LINKID; 1819f595a68aSyz147064 dladm_status_t status; 18207c478bd9Sstevel@tonic-gate 1821d62bc4baSyz147064 /* 1822d62bc4baSyz147064 * get the key or the name of the aggregation (optional last argument) 1823d62bc4baSyz147064 */ 18247c478bd9Sstevel@tonic-gate if (argc == 2) { 1825d62bc4baSyz147064 if ((status = i_dladm_aggr_get_linkid(NULL, argv[1], &linkid, 1826d62bc4baSyz147064 DLADM_OPT_PERSIST)) != DLADM_STATUS_OK) { 1827d62bc4baSyz147064 goto done; 1828d62bc4baSyz147064 } 18297c478bd9Sstevel@tonic-gate } else if (argc > 2) { 18307c478bd9Sstevel@tonic-gate usage(); 18317c478bd9Sstevel@tonic-gate } 18327c478bd9Sstevel@tonic-gate 1833d62bc4baSyz147064 status = dladm_aggr_up(linkid); 1834d62bc4baSyz147064 done: 1835d62bc4baSyz147064 if (status != DLADM_STATUS_OK) { 1836d62bc4baSyz147064 if (argc == 2) { 1837d62bc4baSyz147064 die_dlerr(status, 1838d62bc4baSyz147064 "could not bring up aggregation '%s'", argv[1]); 18397c478bd9Sstevel@tonic-gate } else { 1840f595a68aSyz147064 die_dlerr(status, "could not bring aggregations up"); 18417c478bd9Sstevel@tonic-gate } 18427c478bd9Sstevel@tonic-gate } 18437c478bd9Sstevel@tonic-gate } 18447c478bd9Sstevel@tonic-gate 18457c478bd9Sstevel@tonic-gate static void 18468d5c46e6Sam223141 do_create_vlan(int argc, char *argv[], const char *use) 18477c478bd9Sstevel@tonic-gate { 1848d62bc4baSyz147064 char *link = NULL; 1849d62bc4baSyz147064 char drv[DLPI_LINKNAME_MAX]; 1850d62bc4baSyz147064 uint_t ppa; 1851d62bc4baSyz147064 datalink_id_t linkid; 1852*da14cebeSEric Cheng datalink_id_t dev_linkid; 1853d62bc4baSyz147064 int vid = 0; 1854d62bc4baSyz147064 char option; 1855d62bc4baSyz147064 uint32_t flags = (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST); 1856d62bc4baSyz147064 char *altroot = NULL; 1857d62bc4baSyz147064 char vlan[MAXLINKNAMELEN]; 1858*da14cebeSEric Cheng dladm_arg_list_t *proplist = NULL; 1859f595a68aSyz147064 dladm_status_t status; 18607c478bd9Sstevel@tonic-gate 1861d62bc4baSyz147064 opterr = 0; 1862*da14cebeSEric Cheng while ((option = getopt_long(argc, argv, ":tfR:l:v:p:", 1863d62bc4baSyz147064 lopts, NULL)) != -1) { 1864d62bc4baSyz147064 switch (option) { 1865d62bc4baSyz147064 case 'v': 1866d62bc4baSyz147064 if (vid != 0) 1867d62bc4baSyz147064 die_optdup(option); 1868d62bc4baSyz147064 1869d62bc4baSyz147064 if (!str2int(optarg, &vid) || vid < 1 || vid > 4094) 1870d62bc4baSyz147064 die("invalid VLAN identifier '%s'", optarg); 1871d62bc4baSyz147064 1872d62bc4baSyz147064 break; 1873d62bc4baSyz147064 case 'l': 1874d62bc4baSyz147064 if (link != NULL) 1875d62bc4baSyz147064 die_optdup(option); 1876d62bc4baSyz147064 1877d62bc4baSyz147064 link = optarg; 1878d62bc4baSyz147064 break; 1879d62bc4baSyz147064 case 't': 1880d62bc4baSyz147064 flags &= ~DLADM_OPT_PERSIST; 1881d62bc4baSyz147064 break; 1882d62bc4baSyz147064 case 'R': 1883d62bc4baSyz147064 altroot = optarg; 1884d62bc4baSyz147064 break; 1885*da14cebeSEric Cheng case 'p': 1886*da14cebeSEric Cheng if (dladm_parse_link_props(optarg, &proplist, B_FALSE) 1887*da14cebeSEric Cheng != DLADM_STATUS_OK) { 1888*da14cebeSEric Cheng die("invalid vlan property"); 1889*da14cebeSEric Cheng } 1890*da14cebeSEric Cheng break; 1891*da14cebeSEric Cheng case 'f': 1892*da14cebeSEric Cheng flags |= DLADM_OPT_FORCE; 1893*da14cebeSEric Cheng break; 1894d62bc4baSyz147064 default: 18958d5c46e6Sam223141 die_opterr(optopt, option, use); 1896d62bc4baSyz147064 break; 1897d62bc4baSyz147064 } 1898d62bc4baSyz147064 } 1899d62bc4baSyz147064 1900d62bc4baSyz147064 /* get vlan name if there is any */ 1901d62bc4baSyz147064 if ((vid == 0) || (link == NULL) || (argc - optind > 1)) 19027c478bd9Sstevel@tonic-gate usage(); 1903d62bc4baSyz147064 1904d62bc4baSyz147064 if (optind == (argc - 1)) { 1905d62bc4baSyz147064 if (strlcpy(vlan, argv[optind], MAXLINKNAMELEN) >= 1906d62bc4baSyz147064 MAXLINKNAMELEN) { 1907d62bc4baSyz147064 die("vlan name too long '%s'", argv[optind]); 1908d62bc4baSyz147064 } 1909d62bc4baSyz147064 } else { 1910d62bc4baSyz147064 if ((dlpi_parselink(link, drv, &ppa) != DLPI_SUCCESS) || 1911d62bc4baSyz147064 (ppa >= 1000) || 1912d62bc4baSyz147064 (dlpi_makelink(vlan, drv, vid * 1000 + ppa) != 1913d62bc4baSyz147064 DLPI_SUCCESS)) { 1914d62bc4baSyz147064 die("invalid link name '%s'", link); 1915d62bc4baSyz147064 } 19167c478bd9Sstevel@tonic-gate } 19177c478bd9Sstevel@tonic-gate 1918d62bc4baSyz147064 if (altroot != NULL) 1919d62bc4baSyz147064 altroot_cmd(altroot, argc, argv); 1920d62bc4baSyz147064 1921*da14cebeSEric Cheng if (dladm_name2info(link, &dev_linkid, NULL, NULL, NULL) != 1922d62bc4baSyz147064 DLADM_STATUS_OK) { 1923d62bc4baSyz147064 die("invalid link name '%s'", link); 1924d62bc4baSyz147064 } 1925d62bc4baSyz147064 1926*da14cebeSEric Cheng if ((status = dladm_vlan_create(vlan, dev_linkid, vid, proplist, flags, 1927*da14cebeSEric Cheng &linkid)) != DLADM_STATUS_OK) { 1928*da14cebeSEric Cheng die_dlerr(status, "create operation over %s failed", link); 1929d62bc4baSyz147064 } 1930d62bc4baSyz147064 } 1931d62bc4baSyz147064 1932d62bc4baSyz147064 static void 19338d5c46e6Sam223141 do_delete_vlan(int argc, char *argv[], const char *use) 1934d62bc4baSyz147064 { 1935d62bc4baSyz147064 char option; 1936d62bc4baSyz147064 uint32_t flags = (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST); 1937d62bc4baSyz147064 char *altroot = NULL; 1938d62bc4baSyz147064 datalink_id_t linkid; 1939d62bc4baSyz147064 dladm_status_t status; 1940d62bc4baSyz147064 1941d62bc4baSyz147064 opterr = 0; 1942d62bc4baSyz147064 while ((option = getopt_long(argc, argv, ":R:t", lopts, NULL)) != -1) { 1943d62bc4baSyz147064 switch (option) { 1944d62bc4baSyz147064 case 't': 1945d62bc4baSyz147064 flags &= ~DLADM_OPT_PERSIST; 1946d62bc4baSyz147064 break; 1947d62bc4baSyz147064 case 'R': 1948d62bc4baSyz147064 altroot = optarg; 1949d62bc4baSyz147064 break; 1950d62bc4baSyz147064 default: 19518d5c46e6Sam223141 die_opterr(optopt, option, use); 1952d62bc4baSyz147064 break; 1953d62bc4baSyz147064 } 1954d62bc4baSyz147064 } 1955d62bc4baSyz147064 1956d62bc4baSyz147064 /* get VLAN link name (required last argument) */ 1957d62bc4baSyz147064 if (optind != (argc - 1)) 1958d62bc4baSyz147064 usage(); 1959d62bc4baSyz147064 1960d62bc4baSyz147064 if (altroot != NULL) 1961d62bc4baSyz147064 altroot_cmd(altroot, argc, argv); 1962d62bc4baSyz147064 1963d62bc4baSyz147064 status = dladm_name2info(argv[optind], &linkid, NULL, NULL, NULL); 1964d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 1965d62bc4baSyz147064 goto done; 1966d62bc4baSyz147064 1967d62bc4baSyz147064 status = dladm_vlan_delete(linkid, flags); 1968d62bc4baSyz147064 done: 1969d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 1970d62bc4baSyz147064 die_dlerr(status, "delete operation failed"); 1971d62bc4baSyz147064 } 1972d62bc4baSyz147064 19738d5c46e6Sam223141 /*ARGSUSED*/ 1974d62bc4baSyz147064 static void 19758d5c46e6Sam223141 do_up_vlan(int argc, char *argv[], const char *use) 1976d62bc4baSyz147064 { 1977*da14cebeSEric Cheng do_up_vnic_common(argc, argv, use, B_TRUE); 19787c478bd9Sstevel@tonic-gate } 19797c478bd9Sstevel@tonic-gate 1980210db224Sericheng static void 19818d5c46e6Sam223141 do_rename_link(int argc, char *argv[], const char *use) 1982210db224Sericheng { 1983d62bc4baSyz147064 char option; 1984d62bc4baSyz147064 char *link1, *link2; 1985d62bc4baSyz147064 char *altroot = NULL; 1986d62bc4baSyz147064 dladm_status_t status; 1987210db224Sericheng 1988d62bc4baSyz147064 opterr = 0; 1989d62bc4baSyz147064 while ((option = getopt_long(argc, argv, ":R:", lopts, NULL)) != -1) { 1990d62bc4baSyz147064 switch (option) { 1991d62bc4baSyz147064 case 'R': 1992d62bc4baSyz147064 altroot = optarg; 1993d62bc4baSyz147064 break; 1994d62bc4baSyz147064 default: 19958d5c46e6Sam223141 die_opterr(optopt, option, use); 1996d62bc4baSyz147064 break; 1997210db224Sericheng } 1998210db224Sericheng } 1999210db224Sericheng 2000d62bc4baSyz147064 /* get link1 and link2 name (required the last 2 arguments) */ 2001d62bc4baSyz147064 if (optind != (argc - 2)) 2002d62bc4baSyz147064 usage(); 2003d62bc4baSyz147064 2004d62bc4baSyz147064 if (altroot != NULL) 2005d62bc4baSyz147064 altroot_cmd(altroot, argc, argv); 2006d62bc4baSyz147064 2007d62bc4baSyz147064 link1 = argv[optind++]; 2008d62bc4baSyz147064 link2 = argv[optind]; 2009d62bc4baSyz147064 if ((status = dladm_rename_link(link1, link2)) != DLADM_STATUS_OK) 2010d62bc4baSyz147064 die_dlerr(status, "rename operation failed"); 2011d62bc4baSyz147064 } 2012d62bc4baSyz147064 20138d5c46e6Sam223141 /*ARGSUSED*/ 2014d62bc4baSyz147064 static void 20158d5c46e6Sam223141 do_delete_phys(int argc, char *argv[], const char *use) 2016d62bc4baSyz147064 { 2017d62bc4baSyz147064 datalink_id_t linkid = DATALINK_ALL_LINKID; 2018d62bc4baSyz147064 dladm_status_t status; 2019d62bc4baSyz147064 2020d62bc4baSyz147064 /* get link name (required the last argument) */ 2021d62bc4baSyz147064 if (argc > 2) 2022d62bc4baSyz147064 usage(); 2023d62bc4baSyz147064 2024d62bc4baSyz147064 if (argc == 2) { 2025d62bc4baSyz147064 status = dladm_name2info(argv[1], &linkid, NULL, NULL, NULL); 2026d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 2027d62bc4baSyz147064 die_dlerr(status, "cannot delete '%s'", argv[1]); 2028d62bc4baSyz147064 } 2029d62bc4baSyz147064 2030d62bc4baSyz147064 if ((status = dladm_phys_delete(linkid)) != DLADM_STATUS_OK) { 2031d62bc4baSyz147064 if (argc == 2) 2032d62bc4baSyz147064 die_dlerr(status, "cannot delete '%s'", argv[1]); 2033d62bc4baSyz147064 else 2034d62bc4baSyz147064 die_dlerr(status, "delete operation failed"); 2035d62bc4baSyz147064 } 2036d62bc4baSyz147064 } 2037d62bc4baSyz147064 2038d62bc4baSyz147064 /*ARGSUSED*/ 2039210db224Sericheng static int 2040d62bc4baSyz147064 i_dladm_walk_linkmap(datalink_id_t linkid, void *arg) 2041210db224Sericheng { 2042d62bc4baSyz147064 char name[MAXLINKNAMELEN]; 2043d62bc4baSyz147064 char mediabuf[DLADM_STRSIZE]; 2044d62bc4baSyz147064 char classbuf[DLADM_STRSIZE]; 2045d62bc4baSyz147064 datalink_class_t class; 2046d62bc4baSyz147064 uint32_t media; 2047d62bc4baSyz147064 uint32_t flags; 2048210db224Sericheng 2049d62bc4baSyz147064 if (dladm_datalink_id2info(linkid, &flags, &class, &media, name, 2050d62bc4baSyz147064 MAXLINKNAMELEN) == DLADM_STATUS_OK) { 2051d62bc4baSyz147064 (void) dladm_class2str(class, classbuf); 2052d62bc4baSyz147064 (void) dladm_media2str(media, mediabuf); 2053d62bc4baSyz147064 (void) printf("%-12s%8d %-12s%-20s %6d\n", name, 2054d62bc4baSyz147064 linkid, classbuf, mediabuf, flags); 2055210db224Sericheng } 2056d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 2057210db224Sericheng } 20587c478bd9Sstevel@tonic-gate 20597c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 20607c478bd9Sstevel@tonic-gate static void 20618d5c46e6Sam223141 do_show_linkmap(int argc, char *argv[], const char *use) 20627c478bd9Sstevel@tonic-gate { 2063d62bc4baSyz147064 if (argc != 1) 2064d62bc4baSyz147064 die("invalid arguments"); 20657c478bd9Sstevel@tonic-gate 2066d62bc4baSyz147064 (void) printf("%-12s%8s %-12s%-20s %6s\n", "NAME", "LINKID", 2067d62bc4baSyz147064 "CLASS", "MEDIA", "FLAGS"); 2068d62bc4baSyz147064 (void) dladm_walk_datalink_id(i_dladm_walk_linkmap, NULL, 2069d62bc4baSyz147064 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, 2070d62bc4baSyz147064 DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST); 20717c478bd9Sstevel@tonic-gate } 2072d62bc4baSyz147064 2073d62bc4baSyz147064 /* 2074d62bc4baSyz147064 * Delete inactive physical links. 2075d62bc4baSyz147064 */ 2076d62bc4baSyz147064 /*ARGSUSED*/ 2077d62bc4baSyz147064 static int 2078d62bc4baSyz147064 purge_phys(datalink_id_t linkid, void *arg) 2079d62bc4baSyz147064 { 2080d62bc4baSyz147064 datalink_class_t class; 2081d62bc4baSyz147064 uint32_t flags; 2082d62bc4baSyz147064 2083d62bc4baSyz147064 if (dladm_datalink_id2info(linkid, &flags, &class, NULL, 2084d62bc4baSyz147064 NULL, 0) != DLADM_STATUS_OK) { 2085d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 2086d62bc4baSyz147064 } 2087d62bc4baSyz147064 2088d62bc4baSyz147064 if (class == DATALINK_CLASS_PHYS && !(flags & DLADM_OPT_ACTIVE)) 2089d62bc4baSyz147064 (void) dladm_phys_delete(linkid); 2090d62bc4baSyz147064 2091d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 2092d62bc4baSyz147064 } 2093d62bc4baSyz147064 2094d62bc4baSyz147064 /*ARGSUSED*/ 2095d62bc4baSyz147064 static void 20968d5c46e6Sam223141 do_init_phys(int argc, char *argv[], const char *use) 2097d62bc4baSyz147064 { 2098d62bc4baSyz147064 di_node_t devtree; 2099d62bc4baSyz147064 2100d62bc4baSyz147064 if (argc > 1) 2101d62bc4baSyz147064 usage(); 2102d62bc4baSyz147064 2103d62bc4baSyz147064 /* 2104d62bc4baSyz147064 * Force all the devices to attach, therefore all the network physical 2105d62bc4baSyz147064 * devices can be known to the dlmgmtd daemon. 2106d62bc4baSyz147064 */ 2107d62bc4baSyz147064 if ((devtree = di_init("/", DINFOFORCE | DINFOSUBTREE)) != DI_NODE_NIL) 2108d62bc4baSyz147064 di_fini(devtree); 2109d62bc4baSyz147064 2110d62bc4baSyz147064 (void) dladm_walk_datalink_id(purge_phys, NULL, 2111d62bc4baSyz147064 DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 21127c478bd9Sstevel@tonic-gate } 21137c478bd9Sstevel@tonic-gate 2114d62bc4baSyz147064 2115d62bc4baSyz147064 /* 2116d62bc4baSyz147064 * Print the active topology information. 2117d62bc4baSyz147064 */ 2118d62bc4baSyz147064 static dladm_status_t 2119d62bc4baSyz147064 print_link_topology(show_state_t *state, datalink_id_t linkid, 2120e7801d59Ssowmini datalink_class_t class, link_fields_buf_t *lbuf) 2121d62bc4baSyz147064 { 2122d62bc4baSyz147064 uint32_t flags = state->ls_flags; 2123d62bc4baSyz147064 dladm_status_t status = DLADM_STATUS_OK; 21246b9e797cSsowmini char tmpbuf[MAXLINKNAMELEN]; 2125d62bc4baSyz147064 2126e7801d59Ssowmini if (!state->ls_parseable) 2127e7801d59Ssowmini (void) sprintf(lbuf->link_over, STR_UNDEF_VAL); 2128d62bc4baSyz147064 else 2129e7801d59Ssowmini (void) sprintf(lbuf->link_over, ""); 2130d62bc4baSyz147064 2131d62bc4baSyz147064 if (class == DATALINK_CLASS_VLAN) { 2132d62bc4baSyz147064 dladm_vlan_attr_t vinfo; 2133d62bc4baSyz147064 2134d62bc4baSyz147064 status = dladm_vlan_info(linkid, &vinfo, flags); 2135d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 2136d62bc4baSyz147064 goto done; 2137d62bc4baSyz147064 status = dladm_datalink_id2info(vinfo.dv_linkid, NULL, NULL, 2138e7801d59Ssowmini NULL, lbuf->link_over, sizeof (lbuf->link_over)); 2139d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 2140d62bc4baSyz147064 goto done; 2141d62bc4baSyz147064 } else if (class == DATALINK_CLASS_AGGR) { 2142d62bc4baSyz147064 dladm_aggr_grp_attr_t ginfo; 2143d62bc4baSyz147064 int i; 2144d62bc4baSyz147064 21456b9e797cSsowmini (void) sprintf(lbuf->link_over, ""); 21466b9e797cSsowmini 2147d62bc4baSyz147064 status = dladm_aggr_info(linkid, &ginfo, flags); 2148d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 2149d62bc4baSyz147064 goto done; 2150d62bc4baSyz147064 2151d62bc4baSyz147064 if (ginfo.lg_nports == 0) { 2152d62bc4baSyz147064 status = DLADM_STATUS_BADVAL; 2153d62bc4baSyz147064 goto done; 2154d62bc4baSyz147064 } 2155d62bc4baSyz147064 for (i = 0; i < ginfo.lg_nports; i++) { 2156d62bc4baSyz147064 status = dladm_datalink_id2info( 2157e7801d59Ssowmini ginfo.lg_ports[i].lp_linkid, NULL, NULL, NULL, 21586b9e797cSsowmini tmpbuf, sizeof (tmpbuf)); 2159d62bc4baSyz147064 if (status != DLADM_STATUS_OK) { 2160d62bc4baSyz147064 free(ginfo.lg_ports); 2161d62bc4baSyz147064 goto done; 2162d62bc4baSyz147064 } 21636b9e797cSsowmini (void) strlcat(lbuf->link_over, tmpbuf, 21646b9e797cSsowmini sizeof (lbuf->link_over)); 21656b9e797cSsowmini if (i != (ginfo.lg_nports - 1)) { 21666b9e797cSsowmini (void) strlcat(lbuf->link_over, " ", 21676b9e797cSsowmini sizeof (lbuf->link_over)); 21686b9e797cSsowmini } 2169d62bc4baSyz147064 } 2170d62bc4baSyz147064 free(ginfo.lg_ports); 2171d62bc4baSyz147064 } else if (class == DATALINK_CLASS_VNIC) { 2172*da14cebeSEric Cheng dladm_vnic_attr_t vinfo; 2173d62bc4baSyz147064 2174d62bc4baSyz147064 if ((status = dladm_vnic_info(linkid, &vinfo, flags)) != 2175d62bc4baSyz147064 DLADM_STATUS_OK || (status = dladm_datalink_id2info( 2176e7801d59Ssowmini vinfo.va_link_id, NULL, NULL, NULL, lbuf->link_over, 2177e7801d59Ssowmini sizeof (lbuf->link_over)) != DLADM_STATUS_OK)) { 2178d62bc4baSyz147064 goto done; 2179d62bc4baSyz147064 } 2180d62bc4baSyz147064 } 2181d62bc4baSyz147064 done: 2182d62bc4baSyz147064 return (status); 2183d62bc4baSyz147064 } 2184d62bc4baSyz147064 2185d62bc4baSyz147064 static dladm_status_t 2186e7801d59Ssowmini print_link(show_state_t *state, datalink_id_t linkid, link_fields_buf_t *lbuf) 2187d62bc4baSyz147064 { 2188d62bc4baSyz147064 char link[MAXLINKNAMELEN]; 2189d62bc4baSyz147064 datalink_class_t class; 2190d62bc4baSyz147064 uint_t mtu; 2191d62bc4baSyz147064 uint32_t flags; 2192d62bc4baSyz147064 dladm_status_t status; 2193d62bc4baSyz147064 2194d62bc4baSyz147064 if ((status = dladm_datalink_id2info(linkid, &flags, &class, NULL, 2195d62bc4baSyz147064 link, sizeof (link))) != DLADM_STATUS_OK) { 2196d62bc4baSyz147064 goto done; 2197d62bc4baSyz147064 } 2198d62bc4baSyz147064 2199d62bc4baSyz147064 if (!(state->ls_flags & flags)) { 2200d62bc4baSyz147064 status = DLADM_STATUS_NOTFOUND; 2201d62bc4baSyz147064 goto done; 2202d62bc4baSyz147064 } 2203d62bc4baSyz147064 2204d62bc4baSyz147064 if (state->ls_flags == DLADM_OPT_ACTIVE) { 2205d62bc4baSyz147064 dladm_attr_t dlattr; 2206d62bc4baSyz147064 2207d62bc4baSyz147064 if (class == DATALINK_CLASS_PHYS) { 2208d62bc4baSyz147064 dladm_phys_attr_t dpa; 2209d62bc4baSyz147064 dlpi_handle_t dh; 2210d62bc4baSyz147064 dlpi_info_t dlinfo; 2211d62bc4baSyz147064 2212d62bc4baSyz147064 if ((status = dladm_phys_info(linkid, &dpa, 2213d62bc4baSyz147064 DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) { 2214d62bc4baSyz147064 goto done; 2215d62bc4baSyz147064 } 2216d62bc4baSyz147064 2217d62bc4baSyz147064 if (!dpa.dp_novanity) 2218d62bc4baSyz147064 goto link_mtu; 2219d62bc4baSyz147064 2220d62bc4baSyz147064 /* 2221d62bc4baSyz147064 * This is a physical link that does not have 2222d62bc4baSyz147064 * vanity naming support. 2223d62bc4baSyz147064 */ 2224d62bc4baSyz147064 if (dlpi_open(dpa.dp_dev, &dh, DLPI_DEVONLY) != 2225d62bc4baSyz147064 DLPI_SUCCESS) { 2226d62bc4baSyz147064 status = DLADM_STATUS_NOTFOUND; 2227d62bc4baSyz147064 goto done; 2228d62bc4baSyz147064 } 2229d62bc4baSyz147064 2230d62bc4baSyz147064 if (dlpi_info(dh, &dlinfo, 0) != DLPI_SUCCESS) { 2231d62bc4baSyz147064 dlpi_close(dh); 2232d62bc4baSyz147064 status = DLADM_STATUS_BADARG; 2233d62bc4baSyz147064 goto done; 2234d62bc4baSyz147064 } 2235d62bc4baSyz147064 2236d62bc4baSyz147064 dlpi_close(dh); 2237d62bc4baSyz147064 mtu = dlinfo.di_max_sdu; 2238d62bc4baSyz147064 } else { 2239d62bc4baSyz147064 link_mtu: 2240d62bc4baSyz147064 status = dladm_info(linkid, &dlattr); 2241d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 2242d62bc4baSyz147064 goto done; 2243d62bc4baSyz147064 mtu = dlattr.da_max_sdu; 2244d62bc4baSyz147064 } 2245d62bc4baSyz147064 } 2246d62bc4baSyz147064 2247e7801d59Ssowmini (void) snprintf(lbuf->link_name, sizeof (lbuf->link_name), 2248e7801d59Ssowmini "%s", link); 2249e7801d59Ssowmini (void) dladm_class2str(class, lbuf->link_class); 2250d62bc4baSyz147064 if (state->ls_flags == DLADM_OPT_ACTIVE) { 2251e7801d59Ssowmini (void) snprintf(lbuf->link_mtu, sizeof (lbuf->link_mtu), 2252c08e5e1aSdr146992 "%u", mtu); 2253e7801d59Ssowmini (void) get_linkstate(link, B_TRUE, lbuf->link_state); 2254d62bc4baSyz147064 } 2255d62bc4baSyz147064 2256e7801d59Ssowmini status = print_link_topology(state, linkid, class, lbuf); 2257d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 2258d62bc4baSyz147064 goto done; 2259d62bc4baSyz147064 2260d62bc4baSyz147064 done: 2261d62bc4baSyz147064 return (status); 2262d62bc4baSyz147064 } 2263d62bc4baSyz147064 2264d62bc4baSyz147064 static int 2265d62bc4baSyz147064 show_link(datalink_id_t linkid, void *arg) 2266d62bc4baSyz147064 { 2267e7801d59Ssowmini show_state_t *state = (show_state_t *)arg; 2268d62bc4baSyz147064 dladm_status_t status; 2269e7801d59Ssowmini link_fields_buf_t lbuf; 2270d62bc4baSyz147064 2271e7801d59Ssowmini /* 2272e7801d59Ssowmini * first get all the link attributes into lbuf; 2273e7801d59Ssowmini */ 22745f5c9f54SAnurag S. Maskey bzero(&lbuf, sizeof (link_fields_buf_t)); 2275e7801d59Ssowmini status = print_link(state, linkid, &lbuf); 2276e7801d59Ssowmini 2277d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 2278d62bc4baSyz147064 goto done; 2279e7801d59Ssowmini 2280e7801d59Ssowmini if (!state->ls_parseable && !state->ls_printheader) { 2281e7801d59Ssowmini print_header(&state->ls_print); 2282e7801d59Ssowmini state->ls_printheader = B_TRUE; 2283e7801d59Ssowmini } 2284e7801d59Ssowmini 2285e7801d59Ssowmini dladm_print_output(&state->ls_print, state->ls_parseable, 2286e7801d59Ssowmini dladm_print_field, (void *)&lbuf); 2287d62bc4baSyz147064 2288d62bc4baSyz147064 done: 2289d62bc4baSyz147064 state->ls_status = status; 2290d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 2291d62bc4baSyz147064 } 2292d62bc4baSyz147064 2293d62bc4baSyz147064 static int 2294d62bc4baSyz147064 show_link_stats(datalink_id_t linkid, void *arg) 2295d62bc4baSyz147064 { 2296e7801d59Ssowmini char link[DLPI_LINKNAME_MAX]; 2297d62bc4baSyz147064 datalink_class_t class; 2298e7801d59Ssowmini show_state_t *state = (show_state_t *)arg; 22997c478bd9Sstevel@tonic-gate pktsum_t stats, diff_stats; 2300d62bc4baSyz147064 dladm_phys_attr_t dpa; 23017c478bd9Sstevel@tonic-gate 23027c478bd9Sstevel@tonic-gate if (state->ls_firstonly) { 23037c478bd9Sstevel@tonic-gate if (state->ls_donefirst) 2304d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 23057c478bd9Sstevel@tonic-gate state->ls_donefirst = B_TRUE; 23067c478bd9Sstevel@tonic-gate } else { 23077c478bd9Sstevel@tonic-gate bzero(&state->ls_prevstats, sizeof (state->ls_prevstats)); 23087c478bd9Sstevel@tonic-gate } 23097c478bd9Sstevel@tonic-gate 2310d62bc4baSyz147064 if (dladm_datalink_id2info(linkid, NULL, &class, NULL, link, 2311e7801d59Ssowmini DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) { 2312d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 2313d62bc4baSyz147064 } 2314d62bc4baSyz147064 2315d62bc4baSyz147064 if (class == DATALINK_CLASS_PHYS) { 2316d62bc4baSyz147064 if (dladm_phys_info(linkid, &dpa, DLADM_OPT_ACTIVE) != 2317d62bc4baSyz147064 DLADM_STATUS_OK) { 2318d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 2319d62bc4baSyz147064 } 2320d62bc4baSyz147064 if (dpa.dp_novanity) 2321d62bc4baSyz147064 get_mac_stats(dpa.dp_dev, &stats); 2322d62bc4baSyz147064 else 2323d62bc4baSyz147064 get_link_stats(link, &stats); 2324d62bc4baSyz147064 } else { 2325d62bc4baSyz147064 get_link_stats(link, &stats); 2326d62bc4baSyz147064 } 2327*da14cebeSEric Cheng dladm_stats_diff(&diff_stats, &stats, &state->ls_prevstats); 23287c478bd9Sstevel@tonic-gate 2329*da14cebeSEric Cheng (void) printf("%-12s", link); 2330*da14cebeSEric Cheng (void) printf("%-10llu", diff_stats.ipackets); 2331*da14cebeSEric Cheng (void) printf("%-12llu", diff_stats.rbytes); 2332*da14cebeSEric Cheng (void) printf("%-8llu", diff_stats.ierrors); 2333*da14cebeSEric Cheng (void) printf("%-10llu", diff_stats.opackets); 2334*da14cebeSEric Cheng (void) printf("%-12llu", diff_stats.obytes); 2335*da14cebeSEric Cheng (void) printf("%-8llu\n", diff_stats.oerrors); 23367c478bd9Sstevel@tonic-gate 23377c478bd9Sstevel@tonic-gate state->ls_prevstats = stats; 2338d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 23397c478bd9Sstevel@tonic-gate } 23407c478bd9Sstevel@tonic-gate 2341d62bc4baSyz147064 2342d62bc4baSyz147064 static dladm_status_t 2343d62bc4baSyz147064 print_aggr_info(show_grp_state_t *state, const char *link, 2344e7801d59Ssowmini dladm_aggr_grp_attr_t *ginfop) 2345d62bc4baSyz147064 { 2346d62bc4baSyz147064 char addr_str[ETHERADDRL * 3]; 2347e7801d59Ssowmini laggr_fields_buf_t lbuf; 2348d62bc4baSyz147064 2349e7801d59Ssowmini (void) snprintf(lbuf.laggr_name, sizeof (lbuf.laggr_name), 2350e7801d59Ssowmini "%s", link); 2351e7801d59Ssowmini 2352e7801d59Ssowmini (void) dladm_aggr_policy2str(ginfop->lg_policy, 2353e7801d59Ssowmini lbuf.laggr_policy); 2354d62bc4baSyz147064 2355d62bc4baSyz147064 if (ginfop->lg_mac_fixed) { 2356d62bc4baSyz147064 (void) dladm_aggr_macaddr2str(ginfop->lg_mac, addr_str); 2357e7801d59Ssowmini (void) snprintf(lbuf.laggr_addrpolicy, 2358e7801d59Ssowmini sizeof (lbuf.laggr_addrpolicy), "fixed (%s)", addr_str); 2359d62bc4baSyz147064 } else { 2360e7801d59Ssowmini (void) snprintf(lbuf.laggr_addrpolicy, 2361e7801d59Ssowmini sizeof (lbuf.laggr_addrpolicy), "auto"); 2362d62bc4baSyz147064 } 2363d62bc4baSyz147064 2364d62bc4baSyz147064 2365e7801d59Ssowmini (void) dladm_aggr_lacpmode2str(ginfop->lg_lacp_mode, 2366e7801d59Ssowmini lbuf.laggr_lacpactivity); 2367e7801d59Ssowmini (void) dladm_aggr_lacptimer2str(ginfop->lg_lacp_timer, 2368e7801d59Ssowmini lbuf.laggr_lacptimer); 2369e7801d59Ssowmini (void) snprintf(lbuf.laggr_flags, sizeof (lbuf.laggr_flags), "%c----", 2370d62bc4baSyz147064 ginfop->lg_force ? 'f' : '-'); 2371e7801d59Ssowmini 2372e7801d59Ssowmini if (!state->gs_parseable && !state->gs_printheader) { 2373e7801d59Ssowmini print_header(&state->gs_print); 2374e7801d59Ssowmini state->gs_printheader = B_TRUE; 2375d62bc4baSyz147064 } 2376d62bc4baSyz147064 2377e7801d59Ssowmini dladm_print_output(&state->gs_print, state->gs_parseable, 2378e7801d59Ssowmini dladm_print_field, (void *)&lbuf); 2379e7801d59Ssowmini 2380d62bc4baSyz147064 return (DLADM_STATUS_OK); 2381d62bc4baSyz147064 } 2382d62bc4baSyz147064 2383e7801d59Ssowmini static char * 2384e7801d59Ssowmini print_xaggr_callback(print_field_t *pf, void *arg) 2385d62bc4baSyz147064 { 2386e7801d59Ssowmini const laggr_args_t *l = arg; 2387e7801d59Ssowmini int portnum; 2388e7801d59Ssowmini static char buf[DLADM_STRSIZE]; 2389e7801d59Ssowmini boolean_t is_port = (l->laggr_lport >= 0); 2390e7801d59Ssowmini dladm_aggr_port_attr_t *portp; 2391d62bc4baSyz147064 dladm_phys_attr_t dpa; 2392e7801d59Ssowmini dladm_status_t *stat, status; 2393d62bc4baSyz147064 2394e7801d59Ssowmini stat = l->laggr_status; 2395e7801d59Ssowmini *stat = DLADM_STATUS_OK; 2396d62bc4baSyz147064 2397e7801d59Ssowmini if (is_port) { 2398e7801d59Ssowmini portnum = l->laggr_lport; 2399e7801d59Ssowmini portp = &(l->laggr_ginfop->lg_ports[portnum]); 2400e7801d59Ssowmini if ((status = dladm_datalink_id2info(portp->lp_linkid, 2401e7801d59Ssowmini NULL, NULL, NULL, buf, sizeof (buf))) != 2402e7801d59Ssowmini DLADM_STATUS_OK) { 2403e7801d59Ssowmini goto err; 2404d62bc4baSyz147064 } 2405d62bc4baSyz147064 if ((status = dladm_phys_info(portp->lp_linkid, &dpa, 2406d62bc4baSyz147064 DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) { 2407e7801d59Ssowmini goto err; 2408e7801d59Ssowmini } 2409d62bc4baSyz147064 } 2410d62bc4baSyz147064 2411e7801d59Ssowmini switch (pf->pf_index) { 2412e7801d59Ssowmini case AGGR_X_LINK: 2413e7801d59Ssowmini (void) snprintf(buf, sizeof (buf), "%s", 2414e7801d59Ssowmini (is_port && !l->laggr_parseable ? " " : l->laggr_link)); 2415e7801d59Ssowmini break; 2416e7801d59Ssowmini case AGGR_X_PORT: 2417e7801d59Ssowmini if (is_port) 2418e7801d59Ssowmini break; 2419e7801d59Ssowmini return (""); 2420e7801d59Ssowmini break; 2421d62bc4baSyz147064 2422e7801d59Ssowmini case AGGR_X_SPEED: 2423e7801d59Ssowmini if (is_port) { 2424e7801d59Ssowmini (void) snprintf(buf, sizeof (buf), "%uMb", 2425e7801d59Ssowmini (uint_t)((get_ifspeed(dpa.dp_dev, 2426e7801d59Ssowmini B_FALSE)) / 1000000ull)); 2427e7801d59Ssowmini } else { 2428e7801d59Ssowmini (void) snprintf(buf, sizeof (buf), "%uMb", 2429e7801d59Ssowmini (uint_t)((get_ifspeed(l->laggr_link, 2430e7801d59Ssowmini B_TRUE)) / 1000000ull)); 2431e7801d59Ssowmini } 2432e7801d59Ssowmini break; 2433e7801d59Ssowmini 2434e7801d59Ssowmini case AGGR_X_DUPLEX: 2435e7801d59Ssowmini if (is_port) 2436e7801d59Ssowmini (void) get_linkduplex(dpa.dp_dev, B_FALSE, buf); 2437d62bc4baSyz147064 else 2438e7801d59Ssowmini (void) get_linkduplex(l->laggr_link, B_TRUE, buf); 2439e7801d59Ssowmini break; 2440d62bc4baSyz147064 2441e7801d59Ssowmini case AGGR_X_STATE: 24421a1811a0Svs226613 if (is_port) 24431a1811a0Svs226613 (void) get_linkstate(dpa.dp_dev, B_FALSE, buf); 24441a1811a0Svs226613 else 24451a1811a0Svs226613 (void) get_linkstate(l->laggr_link, B_TRUE, buf); 2446e7801d59Ssowmini break; 2447e7801d59Ssowmini case AGGR_X_ADDRESS: 2448e7801d59Ssowmini (void) dladm_aggr_macaddr2str( 2449e7801d59Ssowmini (is_port ? portp->lp_mac : l->laggr_ginfop->lg_mac), 2450e7801d59Ssowmini buf); 2451e7801d59Ssowmini break; 2452e7801d59Ssowmini case AGGR_X_PORTSTATE: 24530d365605Sschuster if (is_port) 24540d365605Sschuster (void) dladm_aggr_portstate2str( 24550d365605Sschuster portp->lp_state, buf); 24560d365605Sschuster else 24570d365605Sschuster return (""); 2458e7801d59Ssowmini break; 2459e7801d59Ssowmini } 2460e7801d59Ssowmini return (buf); 2461e7801d59Ssowmini 2462e7801d59Ssowmini err: 2463e7801d59Ssowmini *stat = status; 2464e7801d59Ssowmini buf[0] = '\0'; 2465e7801d59Ssowmini return (buf); 2466e7801d59Ssowmini } 2467e7801d59Ssowmini 2468e7801d59Ssowmini static dladm_status_t 2469e7801d59Ssowmini print_aggr_extended(show_grp_state_t *state, const char *link, 2470e7801d59Ssowmini dladm_aggr_grp_attr_t *ginfop) 2471e7801d59Ssowmini { 2472e7801d59Ssowmini int i; 2473e7801d59Ssowmini dladm_status_t status; 2474e7801d59Ssowmini laggr_args_t largs; 2475e7801d59Ssowmini 2476e7801d59Ssowmini if (!state->gs_parseable && !state->gs_printheader) { 2477e7801d59Ssowmini print_header(&state->gs_print); 2478e7801d59Ssowmini state->gs_printheader = B_TRUE; 2479e7801d59Ssowmini } 2480e7801d59Ssowmini 2481e7801d59Ssowmini largs.laggr_lport = -1; 2482e7801d59Ssowmini largs.laggr_link = link; 2483e7801d59Ssowmini largs.laggr_ginfop = ginfop; 2484e7801d59Ssowmini largs.laggr_status = &status; 2485e7801d59Ssowmini largs.laggr_parseable = state->gs_parseable; 2486e7801d59Ssowmini 2487e7801d59Ssowmini dladm_print_output(&state->gs_print, state->gs_parseable, 2488e7801d59Ssowmini print_xaggr_callback, &largs); 2489e7801d59Ssowmini 2490e7801d59Ssowmini if (status != DLADM_STATUS_OK) 2491e7801d59Ssowmini goto done; 2492e7801d59Ssowmini 2493e7801d59Ssowmini for (i = 0; i < ginfop->lg_nports; i++) { 2494e7801d59Ssowmini largs.laggr_lport = i; 2495e7801d59Ssowmini dladm_print_output(&state->gs_print, state->gs_parseable, 2496e7801d59Ssowmini print_xaggr_callback, &largs); 2497e7801d59Ssowmini if (status != DLADM_STATUS_OK) 2498e7801d59Ssowmini goto done; 2499d62bc4baSyz147064 } 2500d62bc4baSyz147064 2501d62bc4baSyz147064 status = DLADM_STATUS_OK; 2502d62bc4baSyz147064 done: 2503d62bc4baSyz147064 return (status); 2504d62bc4baSyz147064 } 2505d62bc4baSyz147064 2506e7801d59Ssowmini 2507e7801d59Ssowmini static char * 2508e7801d59Ssowmini print_lacp_callback(print_field_t *pf, void *arg) 2509e7801d59Ssowmini { 2510e7801d59Ssowmini const laggr_args_t *l = arg; 2511e7801d59Ssowmini int portnum; 2512e7801d59Ssowmini static char buf[DLADM_STRSIZE]; 2513e7801d59Ssowmini boolean_t is_port = (l->laggr_lport >= 0); 2514e7801d59Ssowmini dladm_aggr_port_attr_t *portp; 2515e7801d59Ssowmini dladm_status_t *stat, status; 2516e7801d59Ssowmini aggr_lacp_state_t *lstate; 2517e7801d59Ssowmini 2518e7801d59Ssowmini if (!is_port) { 2519e7801d59Ssowmini return (NULL); /* cannot happen! */ 2520e7801d59Ssowmini } 2521e7801d59Ssowmini 2522e7801d59Ssowmini stat = l->laggr_status; 2523e7801d59Ssowmini 2524e7801d59Ssowmini portnum = l->laggr_lport; 2525e7801d59Ssowmini portp = &(l->laggr_ginfop->lg_ports[portnum]); 2526e7801d59Ssowmini if ((status = dladm_datalink_id2info(portp->lp_linkid, 2527e7801d59Ssowmini NULL, NULL, NULL, buf, sizeof (buf))) != DLADM_STATUS_OK) { 2528e7801d59Ssowmini goto err; 2529e7801d59Ssowmini } 2530e7801d59Ssowmini lstate = &(portp->lp_lacp_state); 2531e7801d59Ssowmini 2532e7801d59Ssowmini switch (pf->pf_index) { 2533e7801d59Ssowmini case AGGR_L_LINK: 2534e7801d59Ssowmini (void) snprintf(buf, sizeof (buf), "%s", 2535e7801d59Ssowmini (portnum > 0 ? "" : l->laggr_link)); 2536e7801d59Ssowmini break; 2537e7801d59Ssowmini 2538e7801d59Ssowmini case AGGR_L_PORT: 2539e7801d59Ssowmini break; 2540e7801d59Ssowmini 2541e7801d59Ssowmini case AGGR_L_AGGREGATABLE: 2542e7801d59Ssowmini (void) snprintf(buf, sizeof (buf), "%s", 2543e7801d59Ssowmini (lstate->bit.aggregation ? "yes" : "no")); 2544e7801d59Ssowmini break; 2545e7801d59Ssowmini 2546e7801d59Ssowmini case AGGR_L_SYNC: 2547e7801d59Ssowmini (void) snprintf(buf, sizeof (buf), "%s", 2548e7801d59Ssowmini (lstate->bit.sync ? "yes" : "no")); 2549e7801d59Ssowmini break; 2550e7801d59Ssowmini 2551e7801d59Ssowmini case AGGR_L_COLL: 2552e7801d59Ssowmini (void) snprintf(buf, sizeof (buf), "%s", 2553e7801d59Ssowmini (lstate->bit.collecting ? "yes" : "no")); 2554e7801d59Ssowmini break; 2555e7801d59Ssowmini 2556e7801d59Ssowmini case AGGR_L_DIST: 2557e7801d59Ssowmini (void) snprintf(buf, sizeof (buf), "%s", 2558e7801d59Ssowmini (lstate->bit.distributing ? "yes" : "no")); 2559e7801d59Ssowmini break; 2560e7801d59Ssowmini 2561e7801d59Ssowmini case AGGR_L_DEFAULTED: 2562e7801d59Ssowmini (void) snprintf(buf, sizeof (buf), "%s", 2563e7801d59Ssowmini (lstate->bit.defaulted ? "yes" : "no")); 2564e7801d59Ssowmini break; 2565e7801d59Ssowmini 2566e7801d59Ssowmini case AGGR_L_EXPIRED: 2567e7801d59Ssowmini (void) snprintf(buf, sizeof (buf), "%s", 2568e7801d59Ssowmini (lstate->bit.expired ? "yes" : "no")); 2569e7801d59Ssowmini break; 2570e7801d59Ssowmini } 2571e7801d59Ssowmini 2572e7801d59Ssowmini *stat = DLADM_STATUS_OK; 2573e7801d59Ssowmini return (buf); 2574e7801d59Ssowmini 2575e7801d59Ssowmini err: 2576e7801d59Ssowmini *stat = status; 2577e7801d59Ssowmini buf[0] = '\0'; 2578e7801d59Ssowmini return (buf); 2579e7801d59Ssowmini } 2580e7801d59Ssowmini 2581d62bc4baSyz147064 static dladm_status_t 2582d62bc4baSyz147064 print_aggr_lacp(show_grp_state_t *state, const char *link, 2583e7801d59Ssowmini dladm_aggr_grp_attr_t *ginfop) 2584d62bc4baSyz147064 { 2585d62bc4baSyz147064 int i; 2586d62bc4baSyz147064 dladm_status_t status; 2587e7801d59Ssowmini laggr_args_t largs; 2588d62bc4baSyz147064 2589e7801d59Ssowmini if (!state->gs_parseable && !state->gs_printheader) { 2590e7801d59Ssowmini print_header(&state->gs_print); 2591e7801d59Ssowmini state->gs_printheader = B_TRUE; 2592d62bc4baSyz147064 } 2593d62bc4baSyz147064 2594e7801d59Ssowmini largs.laggr_link = link; 2595e7801d59Ssowmini largs.laggr_ginfop = ginfop; 2596e7801d59Ssowmini largs.laggr_status = &status; 2597d62bc4baSyz147064 2598e7801d59Ssowmini for (i = 0; i < ginfop->lg_nports; i++) { 2599e7801d59Ssowmini largs.laggr_lport = i; 2600e7801d59Ssowmini dladm_print_output(&state->gs_print, state->gs_parseable, 2601e7801d59Ssowmini print_lacp_callback, &largs); 2602d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 2603d62bc4baSyz147064 goto done; 2604d62bc4baSyz147064 } 2605d62bc4baSyz147064 2606d62bc4baSyz147064 status = DLADM_STATUS_OK; 2607d62bc4baSyz147064 done: 2608d62bc4baSyz147064 return (status); 2609d62bc4baSyz147064 } 2610d62bc4baSyz147064 2611e7801d59Ssowmini static char * 2612e7801d59Ssowmini print_aggr_stats_callback(print_field_t *pf, void *arg) 2613e7801d59Ssowmini { 2614e7801d59Ssowmini const laggr_args_t *l = arg; 2615e7801d59Ssowmini int portnum; 2616e7801d59Ssowmini static char buf[DLADM_STRSIZE]; 2617e7801d59Ssowmini boolean_t is_port = (l->laggr_lport >= 0); 2618e7801d59Ssowmini dladm_aggr_port_attr_t *portp; 2619e7801d59Ssowmini dladm_phys_attr_t dpa; 2620e7801d59Ssowmini dladm_status_t *stat, status; 2621e7801d59Ssowmini pktsum_t port_stat, diff_stats; 2622e7801d59Ssowmini 2623e7801d59Ssowmini stat = l->laggr_status; 2624e7801d59Ssowmini *stat = DLADM_STATUS_OK; 2625e7801d59Ssowmini 2626e7801d59Ssowmini if (is_port) { 2627e7801d59Ssowmini portnum = l->laggr_lport; 2628e7801d59Ssowmini portp = &(l->laggr_ginfop->lg_ports[portnum]); 2629e7801d59Ssowmini if ((status = dladm_phys_info(portp->lp_linkid, &dpa, 2630e7801d59Ssowmini DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) { 2631e7801d59Ssowmini goto err; 2632e7801d59Ssowmini } 2633e7801d59Ssowmini 2634e7801d59Ssowmini get_mac_stats(dpa.dp_dev, &port_stat); 2635e7801d59Ssowmini 2636e7801d59Ssowmini if ((status = dladm_datalink_id2info(portp->lp_linkid, NULL, 2637e7801d59Ssowmini NULL, NULL, buf, sizeof (buf))) != DLADM_STATUS_OK) { 2638e7801d59Ssowmini goto err; 2639e7801d59Ssowmini } 2640e7801d59Ssowmini 2641*da14cebeSEric Cheng dladm_stats_diff(&diff_stats, &port_stat, l->laggr_prevstats); 2642e7801d59Ssowmini } 2643e7801d59Ssowmini 2644e7801d59Ssowmini switch (pf->pf_index) { 2645e7801d59Ssowmini case AGGR_S_LINK: 2646e7801d59Ssowmini (void) snprintf(buf, sizeof (buf), "%s", 2647e7801d59Ssowmini (is_port ? "" : l->laggr_link)); 2648e7801d59Ssowmini break; 2649e7801d59Ssowmini case AGGR_S_PORT: 2650e7801d59Ssowmini if (is_port) 2651e7801d59Ssowmini break; 26520d365605Sschuster return (""); 2653e7801d59Ssowmini break; 2654e7801d59Ssowmini 2655e7801d59Ssowmini case AGGR_S_IPKTS: 2656e7801d59Ssowmini if (is_port) { 2657e7801d59Ssowmini (void) snprintf(buf, sizeof (buf), "%llu", 2658e7801d59Ssowmini diff_stats.ipackets); 2659e7801d59Ssowmini } else { 2660e7801d59Ssowmini (void) snprintf(buf, sizeof (buf), "%llu", 2661e7801d59Ssowmini l->laggr_pktsumtot->ipackets); 2662e7801d59Ssowmini } 2663e7801d59Ssowmini break; 2664e7801d59Ssowmini 2665e7801d59Ssowmini case AGGR_S_RBYTES: 2666e7801d59Ssowmini if (is_port) { 2667e7801d59Ssowmini (void) snprintf(buf, sizeof (buf), "%llu", 2668e7801d59Ssowmini diff_stats.rbytes); 2669e7801d59Ssowmini } else { 2670e7801d59Ssowmini (void) snprintf(buf, sizeof (buf), "%llu", 2671e7801d59Ssowmini l->laggr_pktsumtot->rbytes); 2672e7801d59Ssowmini } 2673e7801d59Ssowmini break; 2674e7801d59Ssowmini 2675e7801d59Ssowmini case AGGR_S_OPKTS: 2676e7801d59Ssowmini if (is_port) { 2677e7801d59Ssowmini (void) snprintf(buf, sizeof (buf), "%llu", 2678e7801d59Ssowmini diff_stats.opackets); 2679e7801d59Ssowmini } else { 2680e7801d59Ssowmini (void) snprintf(buf, sizeof (buf), "%llu", 2681e7801d59Ssowmini l->laggr_pktsumtot->opackets); 2682e7801d59Ssowmini } 2683e7801d59Ssowmini break; 2684e7801d59Ssowmini case AGGR_S_OBYTES: 2685e7801d59Ssowmini if (is_port) { 2686e7801d59Ssowmini (void) snprintf(buf, sizeof (buf), "%llu", 2687e7801d59Ssowmini diff_stats.obytes); 2688e7801d59Ssowmini } else { 2689e7801d59Ssowmini (void) snprintf(buf, sizeof (buf), "%llu", 2690e7801d59Ssowmini l->laggr_pktsumtot->obytes); 2691e7801d59Ssowmini 2692e7801d59Ssowmini } 2693e7801d59Ssowmini break; 2694e7801d59Ssowmini 2695e7801d59Ssowmini case AGGR_S_IPKTDIST: 2696e7801d59Ssowmini if (is_port) { 2697e7801d59Ssowmini (void) snprintf(buf, sizeof (buf), "%-6.1f", 2698e7801d59Ssowmini (double)diff_stats.opackets/ 2699e7801d59Ssowmini (double)l->laggr_pktsumtot->ipackets * 100); 2700e7801d59Ssowmini } else { 27010d365605Sschuster return (""); 2702e7801d59Ssowmini } 2703e7801d59Ssowmini break; 2704e7801d59Ssowmini case AGGR_S_OPKTDIST: 2705e7801d59Ssowmini if (is_port) { 2706e7801d59Ssowmini (void) snprintf(buf, sizeof (buf), "%-6.1f", 2707e7801d59Ssowmini (double)diff_stats.opackets/ 2708e7801d59Ssowmini (double)l->laggr_pktsumtot->opackets * 100); 2709e7801d59Ssowmini } else { 27100d365605Sschuster return (""); 2711e7801d59Ssowmini } 2712e7801d59Ssowmini break; 2713e7801d59Ssowmini } 2714e7801d59Ssowmini return (buf); 2715e7801d59Ssowmini 2716e7801d59Ssowmini err: 2717e7801d59Ssowmini *stat = status; 2718e7801d59Ssowmini buf[0] = '\0'; 2719e7801d59Ssowmini return (buf); 2720e7801d59Ssowmini } 2721e7801d59Ssowmini 2722d62bc4baSyz147064 static dladm_status_t 2723d62bc4baSyz147064 print_aggr_stats(show_grp_state_t *state, const char *link, 2724e7801d59Ssowmini dladm_aggr_grp_attr_t *ginfop) 2725d62bc4baSyz147064 { 2726d62bc4baSyz147064 dladm_phys_attr_t dpa; 2727d62bc4baSyz147064 dladm_aggr_port_attr_t *portp; 2728d62bc4baSyz147064 pktsum_t pktsumtot, port_stat; 2729d62bc4baSyz147064 dladm_status_t status; 2730d62bc4baSyz147064 int i; 2731e7801d59Ssowmini laggr_args_t largs; 27327c478bd9Sstevel@tonic-gate 27337c478bd9Sstevel@tonic-gate /* sum the ports statistics */ 27347c478bd9Sstevel@tonic-gate bzero(&pktsumtot, sizeof (pktsumtot)); 2735d62bc4baSyz147064 2736d62bc4baSyz147064 for (i = 0; i < ginfop->lg_nports; i++) { 2737d62bc4baSyz147064 2738d62bc4baSyz147064 portp = &(ginfop->lg_ports[i]); 2739d62bc4baSyz147064 if ((status = dladm_phys_info(portp->lp_linkid, &dpa, 2740d62bc4baSyz147064 DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) { 2741d62bc4baSyz147064 goto done; 27427c478bd9Sstevel@tonic-gate } 27437c478bd9Sstevel@tonic-gate 2744d62bc4baSyz147064 get_mac_stats(dpa.dp_dev, &port_stat); 2745*da14cebeSEric Cheng dladm_stats_total(&pktsumtot, &port_stat, 2746*da14cebeSEric Cheng &state->gs_prevstats[i]); 27477c478bd9Sstevel@tonic-gate } 27487c478bd9Sstevel@tonic-gate 2749e7801d59Ssowmini if (!state->gs_parseable && !state->gs_printheader) { 2750e7801d59Ssowmini print_header(&state->gs_print); 2751e7801d59Ssowmini state->gs_printheader = B_TRUE; 2752e7801d59Ssowmini } 2753e7801d59Ssowmini 2754e7801d59Ssowmini largs.laggr_lport = -1; 2755e7801d59Ssowmini largs.laggr_link = link; 2756e7801d59Ssowmini largs.laggr_ginfop = ginfop; 2757e7801d59Ssowmini largs.laggr_status = &status; 2758e7801d59Ssowmini largs.laggr_pktsumtot = &pktsumtot; 2759e7801d59Ssowmini 2760e7801d59Ssowmini dladm_print_output(&state->gs_print, state->gs_parseable, 2761e7801d59Ssowmini print_aggr_stats_callback, &largs); 2762e7801d59Ssowmini 2763e7801d59Ssowmini if (status != DLADM_STATUS_OK) 2764e7801d59Ssowmini goto done; 2765d62bc4baSyz147064 2766d62bc4baSyz147064 for (i = 0; i < ginfop->lg_nports; i++) { 2767e7801d59Ssowmini largs.laggr_lport = i; 2768e7801d59Ssowmini largs.laggr_prevstats = &state->gs_prevstats[i]; 2769e7801d59Ssowmini dladm_print_output(&state->gs_print, state->gs_parseable, 2770e7801d59Ssowmini print_aggr_stats_callback, &largs); 2771e7801d59Ssowmini if (status != DLADM_STATUS_OK) 2772d62bc4baSyz147064 goto done; 2773d62bc4baSyz147064 } 2774d62bc4baSyz147064 2775d62bc4baSyz147064 status = DLADM_STATUS_OK; 2776d62bc4baSyz147064 done: 2777d62bc4baSyz147064 return (status); 2778d62bc4baSyz147064 } 2779d62bc4baSyz147064 2780d62bc4baSyz147064 static dladm_status_t 2781e7801d59Ssowmini print_aggr(show_grp_state_t *state, datalink_id_t linkid) 2782d62bc4baSyz147064 { 2783d62bc4baSyz147064 char link[MAXLINKNAMELEN]; 2784d62bc4baSyz147064 dladm_aggr_grp_attr_t ginfo; 2785d62bc4baSyz147064 uint32_t flags; 2786d62bc4baSyz147064 dladm_status_t status; 2787d62bc4baSyz147064 27885f5c9f54SAnurag S. Maskey bzero(&ginfo, sizeof (dladm_aggr_grp_attr_t)); 2789d62bc4baSyz147064 if ((status = dladm_datalink_id2info(linkid, &flags, NULL, NULL, link, 2790e7801d59Ssowmini MAXLINKNAMELEN)) != DLADM_STATUS_OK) { 2791d62bc4baSyz147064 return (status); 2792d62bc4baSyz147064 } 2793d62bc4baSyz147064 2794d62bc4baSyz147064 if (!(state->gs_flags & flags)) 2795d62bc4baSyz147064 return (DLADM_STATUS_NOTFOUND); 2796d62bc4baSyz147064 2797d62bc4baSyz147064 status = dladm_aggr_info(linkid, &ginfo, state->gs_flags); 2798d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 2799d62bc4baSyz147064 return (status); 2800d62bc4baSyz147064 2801d62bc4baSyz147064 if (state->gs_lacp) 2802e7801d59Ssowmini status = print_aggr_lacp(state, link, &ginfo); 2803d62bc4baSyz147064 else if (state->gs_extended) 2804e7801d59Ssowmini status = print_aggr_extended(state, link, &ginfo); 2805d62bc4baSyz147064 else if (state->gs_stats) 2806e7801d59Ssowmini status = print_aggr_stats(state, link, &ginfo); 2807e7801d59Ssowmini else { 2808e7801d59Ssowmini status = print_aggr_info(state, link, &ginfo); 2809e7801d59Ssowmini } 2810d62bc4baSyz147064 2811d62bc4baSyz147064 done: 2812d62bc4baSyz147064 free(ginfo.lg_ports); 2813d62bc4baSyz147064 return (status); 2814d62bc4baSyz147064 } 2815d62bc4baSyz147064 2816d62bc4baSyz147064 static int 2817d62bc4baSyz147064 show_aggr(datalink_id_t linkid, void *arg) 2818d62bc4baSyz147064 { 2819d62bc4baSyz147064 show_grp_state_t *state = arg; 2820d62bc4baSyz147064 dladm_status_t status; 2821d62bc4baSyz147064 2822e7801d59Ssowmini status = print_aggr(state, linkid); 2823d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 2824d62bc4baSyz147064 goto done; 2825d62bc4baSyz147064 2826d62bc4baSyz147064 done: 2827d62bc4baSyz147064 state->gs_status = status; 2828d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 28297c478bd9Sstevel@tonic-gate } 28307c478bd9Sstevel@tonic-gate 28317c478bd9Sstevel@tonic-gate static void 28328d5c46e6Sam223141 do_show_link(int argc, char *argv[], const char *use) 28337c478bd9Sstevel@tonic-gate { 28347c478bd9Sstevel@tonic-gate int option; 28357c478bd9Sstevel@tonic-gate boolean_t s_arg = B_FALSE; 2836*da14cebeSEric Cheng boolean_t S_arg = B_FALSE; 28377c478bd9Sstevel@tonic-gate boolean_t i_arg = B_FALSE; 2838d62bc4baSyz147064 uint32_t flags = DLADM_OPT_ACTIVE; 2839d62bc4baSyz147064 boolean_t p_arg = B_FALSE; 2840d62bc4baSyz147064 datalink_id_t linkid = DATALINK_ALL_LINKID; 2841*da14cebeSEric Cheng char linkname[MAXLINKNAMELEN]; 284233343a97Smeem int interval = 0; 2843d62bc4baSyz147064 show_state_t state; 2844d62bc4baSyz147064 dladm_status_t status; 2845e7801d59Ssowmini boolean_t o_arg = B_FALSE; 2846e7801d59Ssowmini char *fields_str = NULL; 2847e7801d59Ssowmini print_field_t **fields; 2848e7801d59Ssowmini uint_t nfields; 2849e7801d59Ssowmini char *all_active_fields = "link,class,mtu,state,over"; 2850e7801d59Ssowmini char *all_inactive_fields = "link,class,over"; 28516be03d0bSVasumathi Sundaram - Sun Microsystems char *allstat_fields = 28526be03d0bSVasumathi Sundaram - Sun Microsystems "link,ipackets,rbytes,ierrors,opackets,obytes,oerrors"; 2853e7801d59Ssowmini 2854e7801d59Ssowmini bzero(&state, sizeof (state)); 28557c478bd9Sstevel@tonic-gate 28567c478bd9Sstevel@tonic-gate opterr = 0; 2857*da14cebeSEric Cheng while ((option = getopt_long(argc, argv, ":pPsSi:o:", 2858d62bc4baSyz147064 show_lopts, NULL)) != -1) { 28597c478bd9Sstevel@tonic-gate switch (option) { 28607c478bd9Sstevel@tonic-gate case 'p': 2861d62bc4baSyz147064 if (p_arg) 2862d62bc4baSyz147064 die_optdup(option); 2863d62bc4baSyz147064 2864d62bc4baSyz147064 p_arg = B_TRUE; 28657c478bd9Sstevel@tonic-gate break; 28667c478bd9Sstevel@tonic-gate case 's': 286733343a97Smeem if (s_arg) 286833343a97Smeem die_optdup(option); 28697c478bd9Sstevel@tonic-gate 28707c478bd9Sstevel@tonic-gate s_arg = B_TRUE; 28717c478bd9Sstevel@tonic-gate break; 2872d62bc4baSyz147064 case 'P': 2873d62bc4baSyz147064 if (flags != DLADM_OPT_ACTIVE) 2874d62bc4baSyz147064 die_optdup(option); 2875d62bc4baSyz147064 2876d62bc4baSyz147064 flags = DLADM_OPT_PERSIST; 2877d62bc4baSyz147064 break; 2878*da14cebeSEric Cheng case 'S': 2879*da14cebeSEric Cheng if (S_arg) 2880*da14cebeSEric Cheng die_optdup(option); 2881*da14cebeSEric Cheng 2882*da14cebeSEric Cheng S_arg = B_TRUE; 2883*da14cebeSEric Cheng break; 2884e7801d59Ssowmini case 'o': 2885e7801d59Ssowmini o_arg = B_TRUE; 2886e7801d59Ssowmini fields_str = optarg; 2887e7801d59Ssowmini break; 28887c478bd9Sstevel@tonic-gate case 'i': 288933343a97Smeem if (i_arg) 289033343a97Smeem die_optdup(option); 28917c478bd9Sstevel@tonic-gate 28927c478bd9Sstevel@tonic-gate i_arg = B_TRUE; 289333343a97Smeem if (!str2int(optarg, &interval) || interval == 0) 289433343a97Smeem die("invalid interval value '%s'", optarg); 28957c478bd9Sstevel@tonic-gate break; 28967c478bd9Sstevel@tonic-gate default: 28978d5c46e6Sam223141 die_opterr(optopt, option, use); 289833343a97Smeem break; 28997c478bd9Sstevel@tonic-gate } 29007c478bd9Sstevel@tonic-gate } 29017c478bd9Sstevel@tonic-gate 2902*da14cebeSEric Cheng if (i_arg && !(s_arg || S_arg)) 2903*da14cebeSEric Cheng die("the option -i can be used only with -s or -S"); 2904*da14cebeSEric Cheng 2905*da14cebeSEric Cheng if (s_arg && S_arg) 2906*da14cebeSEric Cheng die("the -s option cannot be used with -S"); 29077c478bd9Sstevel@tonic-gate 29086be03d0bSVasumathi Sundaram - Sun Microsystems if (s_arg && flags != DLADM_OPT_ACTIVE) 29096be03d0bSVasumathi Sundaram - Sun Microsystems die("the option -P cannot be used with -s"); 2910d62bc4baSyz147064 2911*da14cebeSEric Cheng if (S_arg && (p_arg || flags != DLADM_OPT_ACTIVE)) 2912*da14cebeSEric Cheng die("the option -%c cannot be used with -S", p_arg ? 'p' : 'P'); 2913*da14cebeSEric Cheng 29147c478bd9Sstevel@tonic-gate /* get link name (optional last argument) */ 2915d62bc4baSyz147064 if (optind == (argc-1)) { 2916d62bc4baSyz147064 uint32_t f; 2917d62bc4baSyz147064 2918*da14cebeSEric Cheng if (strlcpy(linkname, argv[optind], MAXLINKNAMELEN) 2919*da14cebeSEric Cheng >= MAXLINKNAMELEN) { 2920*da14cebeSEric Cheng (void) fprintf(stderr, 2921*da14cebeSEric Cheng gettext("%s: link name too long\n"), 2922*da14cebeSEric Cheng progname); 2923*da14cebeSEric Cheng exit(1); 2924*da14cebeSEric Cheng } 2925*da14cebeSEric Cheng if ((status = dladm_name2info(linkname, &linkid, &f, 2926d62bc4baSyz147064 NULL, NULL)) != DLADM_STATUS_OK) { 2927*da14cebeSEric Cheng die_dlerr(status, "link %s is not valid", linkname); 2928d62bc4baSyz147064 } 2929d62bc4baSyz147064 2930d62bc4baSyz147064 if (!(f & flags)) { 2931d62bc4baSyz147064 die_dlerr(DLADM_STATUS_BADARG, "link %s is %s", 2932d62bc4baSyz147064 argv[optind], flags == DLADM_OPT_PERSIST ? 2933d62bc4baSyz147064 "a temporary link" : "temporarily removed"); 2934d62bc4baSyz147064 } 2935d62bc4baSyz147064 } else if (optind != argc) { 29367c478bd9Sstevel@tonic-gate usage(); 2937d62bc4baSyz147064 } 29387c478bd9Sstevel@tonic-gate 29390d365605Sschuster if (p_arg && !o_arg) 29400d365605Sschuster die("-p requires -o"); 29410d365605Sschuster 2942*da14cebeSEric Cheng if (S_arg) { 2943*da14cebeSEric Cheng dladm_continuous(linkid, NULL, interval, LINK_REPORT); 2944*da14cebeSEric Cheng return; 2945*da14cebeSEric Cheng } 2946*da14cebeSEric Cheng 29470d365605Sschuster if (p_arg && strcasecmp(fields_str, "all") == 0) 29480d365605Sschuster die("\"-o all\" is invalid with -p"); 29490d365605Sschuster 2950e7801d59Ssowmini if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) { 29516be03d0bSVasumathi Sundaram - Sun Microsystems if (s_arg) 29526be03d0bSVasumathi Sundaram - Sun Microsystems fields_str = allstat_fields; 29536be03d0bSVasumathi Sundaram - Sun Microsystems else if (flags & DLADM_OPT_ACTIVE) 2954e7801d59Ssowmini fields_str = all_active_fields; 2955e7801d59Ssowmini else 2956e7801d59Ssowmini fields_str = all_inactive_fields; 2957e7801d59Ssowmini } 2958e7801d59Ssowmini 29596be03d0bSVasumathi Sundaram - Sun Microsystems state.ls_parseable = p_arg; 29606be03d0bSVasumathi Sundaram - Sun Microsystems state.ls_flags = flags; 29616be03d0bSVasumathi Sundaram - Sun Microsystems state.ls_donefirst = B_FALSE; 29626be03d0bSVasumathi Sundaram - Sun Microsystems 29636be03d0bSVasumathi Sundaram - Sun Microsystems if (s_arg) { 29646be03d0bSVasumathi Sundaram - Sun Microsystems link_stats(linkid, interval, fields_str, &state); 29656be03d0bSVasumathi Sundaram - Sun Microsystems return; 29666be03d0bSVasumathi Sundaram - Sun Microsystems } 29676be03d0bSVasumathi Sundaram - Sun Microsystems 2968e7801d59Ssowmini fields = parse_output_fields(fields_str, link_fields, DEV_LINK_FIELDS, 2969e7801d59Ssowmini CMD_TYPE_ANY, &nfields); 2970e7801d59Ssowmini 29710d365605Sschuster if (fields == NULL) 2972e7801d59Ssowmini die("invalid field(s) specified"); 2973e7801d59Ssowmini 2974e7801d59Ssowmini state.ls_print.ps_fields = fields; 2975e7801d59Ssowmini state.ls_print.ps_nfields = nfields; 2976e7801d59Ssowmini 2977d62bc4baSyz147064 if (linkid == DATALINK_ALL_LINKID) { 2978d62bc4baSyz147064 (void) dladm_walk_datalink_id(show_link, &state, 2979d62bc4baSyz147064 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, flags); 2980210db224Sericheng } else { 2981d62bc4baSyz147064 (void) show_link(linkid, &state); 2982d62bc4baSyz147064 if (state.ls_status != DLADM_STATUS_OK) { 2983d62bc4baSyz147064 die_dlerr(state.ls_status, "failed to show link %s", 2984d62bc4baSyz147064 argv[optind]); 2985d62bc4baSyz147064 } 29867c478bd9Sstevel@tonic-gate } 2987210db224Sericheng } 29887c478bd9Sstevel@tonic-gate 29897c478bd9Sstevel@tonic-gate static void 29908d5c46e6Sam223141 do_show_aggr(int argc, char *argv[], const char *use) 29917c478bd9Sstevel@tonic-gate { 29927c478bd9Sstevel@tonic-gate boolean_t L_arg = B_FALSE; 29937c478bd9Sstevel@tonic-gate boolean_t s_arg = B_FALSE; 29947c478bd9Sstevel@tonic-gate boolean_t i_arg = B_FALSE; 2995d62bc4baSyz147064 boolean_t p_arg = B_FALSE; 2996d62bc4baSyz147064 boolean_t x_arg = B_FALSE; 29977c478bd9Sstevel@tonic-gate show_grp_state_t state; 2998d62bc4baSyz147064 uint32_t flags = DLADM_OPT_ACTIVE; 2999d62bc4baSyz147064 datalink_id_t linkid = DATALINK_ALL_LINKID; 3000d62bc4baSyz147064 int option; 300133343a97Smeem int interval = 0; 3002d62bc4baSyz147064 int key; 3003d62bc4baSyz147064 dladm_status_t status; 3004e7801d59Ssowmini boolean_t o_arg = B_FALSE; 3005e7801d59Ssowmini char *fields_str = NULL; 3006e7801d59Ssowmini print_field_t **fields; 3007e7801d59Ssowmini uint_t nfields; 3008e7801d59Ssowmini char *all_fields = 3009e7801d59Ssowmini "link,policy,addrpolicy,lacpactivity,lacptimer,flags"; 3010e7801d59Ssowmini char *all_lacp_fields = 3011e7801d59Ssowmini "link,port,aggregatable,sync,coll,dist,defaulted,expired"; 3012e7801d59Ssowmini char *all_stats_fields = 3013e7801d59Ssowmini "link,port,ipackets,rbytes,opackets,obytes,ipktdist,opktdist"; 3014e7801d59Ssowmini char *all_extended_fields = 3015e7801d59Ssowmini "link,port,speed,duplex,state,address,portstate"; 3016e7801d59Ssowmini print_field_t *pf; 3017e7801d59Ssowmini int pfmax; 3018e7801d59Ssowmini 3019e7801d59Ssowmini bzero(&state, sizeof (state)); 30207c478bd9Sstevel@tonic-gate 30217c478bd9Sstevel@tonic-gate opterr = 0; 3022e7801d59Ssowmini while ((option = getopt_long(argc, argv, ":LpPxsi:o:", 3023d62bc4baSyz147064 show_lopts, NULL)) != -1) { 30247c478bd9Sstevel@tonic-gate switch (option) { 30257c478bd9Sstevel@tonic-gate case 'L': 302633343a97Smeem if (L_arg) 302733343a97Smeem die_optdup(option); 30287c478bd9Sstevel@tonic-gate 30297c478bd9Sstevel@tonic-gate L_arg = B_TRUE; 30307c478bd9Sstevel@tonic-gate break; 30317c478bd9Sstevel@tonic-gate case 'p': 3032d62bc4baSyz147064 if (p_arg) 3033d62bc4baSyz147064 die_optdup(option); 3034d62bc4baSyz147064 3035d62bc4baSyz147064 p_arg = B_TRUE; 3036d62bc4baSyz147064 break; 3037d62bc4baSyz147064 case 'x': 3038d62bc4baSyz147064 if (x_arg) 3039d62bc4baSyz147064 die_optdup(option); 3040d62bc4baSyz147064 3041d62bc4baSyz147064 x_arg = B_TRUE; 3042d62bc4baSyz147064 break; 3043d62bc4baSyz147064 case 'P': 3044d62bc4baSyz147064 if (flags != DLADM_OPT_ACTIVE) 3045d62bc4baSyz147064 die_optdup(option); 3046d62bc4baSyz147064 3047d62bc4baSyz147064 flags = DLADM_OPT_PERSIST; 30487c478bd9Sstevel@tonic-gate break; 30497c478bd9Sstevel@tonic-gate case 's': 305033343a97Smeem if (s_arg) 305133343a97Smeem die_optdup(option); 30527c478bd9Sstevel@tonic-gate 30537c478bd9Sstevel@tonic-gate s_arg = B_TRUE; 30547c478bd9Sstevel@tonic-gate break; 3055e7801d59Ssowmini case 'o': 3056e7801d59Ssowmini o_arg = B_TRUE; 3057e7801d59Ssowmini fields_str = optarg; 3058e7801d59Ssowmini break; 30597c478bd9Sstevel@tonic-gate case 'i': 306033343a97Smeem if (i_arg) 306133343a97Smeem die_optdup(option); 30627c478bd9Sstevel@tonic-gate 30637c478bd9Sstevel@tonic-gate i_arg = B_TRUE; 306433343a97Smeem if (!str2int(optarg, &interval) || interval == 0) 306533343a97Smeem die("invalid interval value '%s'", optarg); 30667c478bd9Sstevel@tonic-gate break; 30677c478bd9Sstevel@tonic-gate default: 30688d5c46e6Sam223141 die_opterr(optopt, option, use); 306933343a97Smeem break; 30707c478bd9Sstevel@tonic-gate } 30717c478bd9Sstevel@tonic-gate } 30727c478bd9Sstevel@tonic-gate 30730d365605Sschuster if (p_arg && !o_arg) 30740d365605Sschuster die("-p requires -o"); 30750d365605Sschuster 30760d365605Sschuster if (p_arg && strcasecmp(fields_str, "all") == 0) 30770d365605Sschuster die("\"-o all\" is invalid with -p"); 30780d365605Sschuster 307933343a97Smeem if (i_arg && !s_arg) 308033343a97Smeem die("the option -i can be used only with -s"); 30817c478bd9Sstevel@tonic-gate 3082d62bc4baSyz147064 if (s_arg && (L_arg || p_arg || x_arg || flags != DLADM_OPT_ACTIVE)) { 3083d62bc4baSyz147064 die("the option -%c cannot be used with -s", 3084d62bc4baSyz147064 L_arg ? 'L' : (p_arg ? 'p' : (x_arg ? 'x' : 'P'))); 3085d62bc4baSyz147064 } 3086d62bc4baSyz147064 3087d62bc4baSyz147064 if (L_arg && flags != DLADM_OPT_ACTIVE) 3088d62bc4baSyz147064 die("the option -P cannot be used with -L"); 3089d62bc4baSyz147064 3090d62bc4baSyz147064 if (x_arg && (L_arg || flags != DLADM_OPT_ACTIVE)) 3091d62bc4baSyz147064 die("the option -%c cannot be used with -x", L_arg ? 'L' : 'P'); 3092d62bc4baSyz147064 3093d62bc4baSyz147064 /* get aggregation key or aggrname (optional last argument) */ 30947c478bd9Sstevel@tonic-gate if (optind == (argc-1)) { 3095d62bc4baSyz147064 if (!str2int(argv[optind], &key)) { 3096d62bc4baSyz147064 status = dladm_name2info(argv[optind], &linkid, NULL, 3097d62bc4baSyz147064 NULL, NULL); 3098d62bc4baSyz147064 } else { 3099d62bc4baSyz147064 status = dladm_key2linkid((uint16_t)key, 3100d62bc4baSyz147064 &linkid, DLADM_OPT_ACTIVE); 3101d62bc4baSyz147064 } 3102d62bc4baSyz147064 3103d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 3104d62bc4baSyz147064 die("non-existent aggregation '%s'", argv[optind]); 3105d62bc4baSyz147064 31067c478bd9Sstevel@tonic-gate } else if (optind != argc) { 31077c478bd9Sstevel@tonic-gate usage(); 31087c478bd9Sstevel@tonic-gate } 31097c478bd9Sstevel@tonic-gate 3110d62bc4baSyz147064 bzero(&state, sizeof (state)); 3111d62bc4baSyz147064 state.gs_lacp = L_arg; 3112d62bc4baSyz147064 state.gs_stats = s_arg; 3113d62bc4baSyz147064 state.gs_flags = flags; 3114d62bc4baSyz147064 state.gs_parseable = p_arg; 3115d62bc4baSyz147064 state.gs_extended = x_arg; 3116d62bc4baSyz147064 3117e7801d59Ssowmini if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) { 3118e7801d59Ssowmini if (state.gs_lacp) 3119e7801d59Ssowmini fields_str = all_lacp_fields; 3120e7801d59Ssowmini else if (state.gs_stats) 3121e7801d59Ssowmini fields_str = all_stats_fields; 3122e7801d59Ssowmini else if (state.gs_extended) 3123e7801d59Ssowmini fields_str = all_extended_fields; 3124e7801d59Ssowmini else 3125e7801d59Ssowmini fields_str = all_fields; 3126e7801d59Ssowmini } 3127e7801d59Ssowmini 3128e7801d59Ssowmini if (state.gs_lacp) { 3129e7801d59Ssowmini pf = aggr_l_fields; 3130e7801d59Ssowmini pfmax = AGGR_L_MAX_FIELDS; 3131e7801d59Ssowmini } else if (state.gs_stats) { 3132e7801d59Ssowmini pf = aggr_s_fields; 3133e7801d59Ssowmini pfmax = AGGR_S_MAX_FIELDS; 3134e7801d59Ssowmini } else if (state.gs_extended) { 3135e7801d59Ssowmini pf = aggr_x_fields; 3136e7801d59Ssowmini pfmax = AGGR_X_MAX_FIELDS; 3137e7801d59Ssowmini } else { 3138e7801d59Ssowmini pf = laggr_fields; 3139e7801d59Ssowmini pfmax = LAGGR_MAX_FIELDS; 3140e7801d59Ssowmini } 3141e7801d59Ssowmini fields = parse_output_fields(fields_str, pf, pfmax, CMD_TYPE_ANY, 3142e7801d59Ssowmini &nfields); 3143e7801d59Ssowmini 3144e7801d59Ssowmini if (fields == NULL) { 3145e7801d59Ssowmini die("invalid field(s) specified"); 3146e7801d59Ssowmini return; 3147e7801d59Ssowmini } 3148e7801d59Ssowmini 3149e7801d59Ssowmini state.gs_print.ps_fields = fields; 3150e7801d59Ssowmini state.gs_print.ps_nfields = nfields; 3151e7801d59Ssowmini 31527c478bd9Sstevel@tonic-gate if (s_arg) { 3153d62bc4baSyz147064 aggr_stats(linkid, &state, interval); 31547c478bd9Sstevel@tonic-gate return; 31557c478bd9Sstevel@tonic-gate } 31567c478bd9Sstevel@tonic-gate 3157d62bc4baSyz147064 if (linkid == DATALINK_ALL_LINKID) { 3158d62bc4baSyz147064 (void) dladm_walk_datalink_id(show_aggr, &state, 3159d62bc4baSyz147064 DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, flags); 3160d62bc4baSyz147064 } else { 3161d62bc4baSyz147064 (void) show_aggr(linkid, &state); 3162d62bc4baSyz147064 if (state.gs_status != DLADM_STATUS_OK) { 3163d62bc4baSyz147064 die_dlerr(state.gs_status, "failed to show aggr %s", 3164d62bc4baSyz147064 argv[optind]); 3165d62bc4baSyz147064 } 3166d62bc4baSyz147064 } 31677c478bd9Sstevel@tonic-gate } 31687c478bd9Sstevel@tonic-gate 3169*da14cebeSEric Cheng static dladm_status_t 3170*da14cebeSEric Cheng print_phys_default(show_state_t *state, datalink_id_t linkid, 3171*da14cebeSEric Cheng const char *link, uint32_t flags, uint32_t media) 31727c478bd9Sstevel@tonic-gate { 3173*da14cebeSEric Cheng dladm_phys_attr_t dpa; 3174*da14cebeSEric Cheng dladm_status_t status; 3175*da14cebeSEric Cheng link_fields_buf_t pattr; 3176e7801d59Ssowmini 3177*da14cebeSEric Cheng status = dladm_phys_info(linkid, &dpa, state->ls_flags); 3178*da14cebeSEric Cheng if (status != DLADM_STATUS_OK) 3179*da14cebeSEric Cheng goto done; 31807c478bd9Sstevel@tonic-gate 3181*da14cebeSEric Cheng (void) snprintf(pattr.link_phys_device, 3182*da14cebeSEric Cheng sizeof (pattr.link_phys_device), "%s", dpa.dp_dev); 3183*da14cebeSEric Cheng (void) dladm_media2str(media, pattr.link_phys_media); 3184*da14cebeSEric Cheng if (state->ls_flags == DLADM_OPT_ACTIVE) { 3185*da14cebeSEric Cheng boolean_t islink; 3186d62bc4baSyz147064 3187*da14cebeSEric Cheng if (!dpa.dp_novanity) { 3188*da14cebeSEric Cheng (void) strlcpy(pattr.link_name, link, 3189*da14cebeSEric Cheng sizeof (pattr.link_name)); 3190*da14cebeSEric Cheng islink = B_TRUE; 3191d62bc4baSyz147064 } else { 3192*da14cebeSEric Cheng /* 3193*da14cebeSEric Cheng * This is a physical link that does not have 3194*da14cebeSEric Cheng * vanity naming support. 3195*da14cebeSEric Cheng */ 3196*da14cebeSEric Cheng (void) strlcpy(pattr.link_name, dpa.dp_dev, 3197*da14cebeSEric Cheng sizeof (pattr.link_name)); 3198*da14cebeSEric Cheng islink = B_FALSE; 31997c478bd9Sstevel@tonic-gate } 32007c478bd9Sstevel@tonic-gate 3201*da14cebeSEric Cheng (void) get_linkstate(pattr.link_name, islink, 3202*da14cebeSEric Cheng pattr.link_phys_state); 3203*da14cebeSEric Cheng (void) snprintf(pattr.link_phys_speed, 3204*da14cebeSEric Cheng sizeof (pattr.link_phys_speed), "%u", 3205*da14cebeSEric Cheng (uint_t)((get_ifspeed(pattr.link_name, 3206*da14cebeSEric Cheng islink)) / 1000000ull)); 3207*da14cebeSEric Cheng (void) get_linkduplex(pattr.link_name, islink, 3208*da14cebeSEric Cheng pattr.link_phys_duplex); 3209*da14cebeSEric Cheng } else { 3210*da14cebeSEric Cheng (void) snprintf(pattr.link_name, sizeof (pattr.link_name), 3211*da14cebeSEric Cheng "%s", link); 3212*da14cebeSEric Cheng (void) snprintf(pattr.link_flags, sizeof (pattr.link_flags), 3213*da14cebeSEric Cheng "%c----", flags & DLADM_OPT_ACTIVE ? '-' : 'r'); 3214*da14cebeSEric Cheng } 3215*da14cebeSEric Cheng 3216*da14cebeSEric Cheng if (!state->ls_parseable && !state->ls_printheader) { 3217*da14cebeSEric Cheng print_header(&state->ls_print); 3218*da14cebeSEric Cheng state->ls_printheader = B_TRUE; 3219*da14cebeSEric Cheng } 3220*da14cebeSEric Cheng 3221*da14cebeSEric Cheng dladm_print_output(&state->ls_print, state->ls_parseable, 3222*da14cebeSEric Cheng dladm_print_field, (void *)&pattr); 3223*da14cebeSEric Cheng 3224*da14cebeSEric Cheng done: 3225*da14cebeSEric Cheng return (status); 3226*da14cebeSEric Cheng } 3227*da14cebeSEric Cheng 3228*da14cebeSEric Cheng typedef struct { 3229*da14cebeSEric Cheng show_state_t *ms_state; 3230*da14cebeSEric Cheng char *ms_link; 3231*da14cebeSEric Cheng dladm_macaddr_attr_t *ms_mac_attr; 3232*da14cebeSEric Cheng } print_phys_mac_state_t; 3233*da14cebeSEric Cheng 3234*da14cebeSEric Cheng /* callback of dladm_print_output() */ 3235*da14cebeSEric Cheng static char * 3236*da14cebeSEric Cheng print_phys_one_mac_callback(print_field_t *pf, void *arg) 3237*da14cebeSEric Cheng { 3238*da14cebeSEric Cheng print_phys_mac_state_t *mac_state = arg; 3239*da14cebeSEric Cheng dladm_macaddr_attr_t *attr = mac_state->ms_mac_attr; 3240*da14cebeSEric Cheng static char buf[DLADM_STRSIZE]; 3241*da14cebeSEric Cheng boolean_t is_primary = (attr->ma_slot == 0); 3242*da14cebeSEric Cheng boolean_t is_parseable = mac_state->ms_state->ls_parseable; 3243*da14cebeSEric Cheng 3244*da14cebeSEric Cheng switch (pf->pf_index) { 3245*da14cebeSEric Cheng case PHYS_M_LINK: 3246*da14cebeSEric Cheng (void) snprintf(buf, sizeof (buf), "%s", 3247*da14cebeSEric Cheng (is_primary || is_parseable) ? mac_state->ms_link : " "); 3248*da14cebeSEric Cheng break; 3249*da14cebeSEric Cheng case PHYS_M_SLOT: 3250*da14cebeSEric Cheng if (is_primary) 3251*da14cebeSEric Cheng (void) snprintf(buf, sizeof (buf), gettext("primary")); 3252*da14cebeSEric Cheng else 3253*da14cebeSEric Cheng (void) snprintf(buf, sizeof (buf), "%d", attr->ma_slot); 3254*da14cebeSEric Cheng break; 3255*da14cebeSEric Cheng case PHYS_M_ADDRESS: 3256*da14cebeSEric Cheng (void) dladm_aggr_macaddr2str(attr->ma_addr, buf); 3257*da14cebeSEric Cheng break; 3258*da14cebeSEric Cheng case PHYS_M_INUSE: 3259*da14cebeSEric Cheng (void) snprintf(buf, sizeof (buf), "%s", 3260*da14cebeSEric Cheng attr->ma_flags & DLADM_MACADDR_USED ? gettext("yes") : 3261*da14cebeSEric Cheng gettext("no")); 3262*da14cebeSEric Cheng break; 3263*da14cebeSEric Cheng case PHYS_M_CLIENT: 3264*da14cebeSEric Cheng /* 3265*da14cebeSEric Cheng * CR 6678526: resolve link id to actual link name if 3266*da14cebeSEric Cheng * it is valid. 3267*da14cebeSEric Cheng */ 3268*da14cebeSEric Cheng (void) snprintf(buf, sizeof (buf), "%s", attr->ma_client_name); 3269*da14cebeSEric Cheng break; 3270*da14cebeSEric Cheng } 3271*da14cebeSEric Cheng 3272*da14cebeSEric Cheng return (buf); 3273*da14cebeSEric Cheng } 3274*da14cebeSEric Cheng 3275*da14cebeSEric Cheng typedef struct { 3276*da14cebeSEric Cheng show_state_t *hs_state; 3277*da14cebeSEric Cheng char *hs_link; 3278*da14cebeSEric Cheng dladm_hwgrp_attr_t *hs_grp_attr; 3279*da14cebeSEric Cheng } print_phys_hwgrp_state_t; 3280*da14cebeSEric Cheng 3281*da14cebeSEric Cheng static char * 3282*da14cebeSEric Cheng print_phys_one_hwgrp_callback(print_field_t *pf, void *arg) 3283*da14cebeSEric Cheng { 3284*da14cebeSEric Cheng print_phys_hwgrp_state_t *hg_state = arg; 3285*da14cebeSEric Cheng dladm_hwgrp_attr_t *attr = hg_state->hs_grp_attr; 3286*da14cebeSEric Cheng static char buf[DLADM_STRSIZE]; 3287*da14cebeSEric Cheng 3288*da14cebeSEric Cheng switch (pf->pf_index) { 3289*da14cebeSEric Cheng case PHYS_H_LINK: 3290*da14cebeSEric Cheng (void) snprintf(buf, sizeof (buf), "%s", attr->hg_link_name); 3291*da14cebeSEric Cheng break; 3292*da14cebeSEric Cheng case PHYS_H_GROUP: 3293*da14cebeSEric Cheng (void) snprintf(buf, sizeof (buf), "%d", attr->hg_grp_num); 3294*da14cebeSEric Cheng break; 3295*da14cebeSEric Cheng case PHYS_H_GRPTYPE: 3296*da14cebeSEric Cheng (void) snprintf(buf, sizeof (buf), "%s", 3297*da14cebeSEric Cheng attr->hg_grp_type == DLADM_HWGRP_TYPE_RX ? "RX" : "TX"); 3298*da14cebeSEric Cheng break; 3299*da14cebeSEric Cheng case PHYS_H_RINGS: 3300*da14cebeSEric Cheng (void) snprintf(buf, sizeof (buf), "%d", attr->hg_n_rings); 3301*da14cebeSEric Cheng break; 3302*da14cebeSEric Cheng case PHYS_H_CLIENTS: 3303*da14cebeSEric Cheng if (attr->hg_client_names[0] == '\0') { 3304*da14cebeSEric Cheng (void) snprintf(buf, sizeof (buf), "--"); 3305*da14cebeSEric Cheng } else { 3306*da14cebeSEric Cheng (void) snprintf(buf, sizeof (buf), "%s ", 3307*da14cebeSEric Cheng attr->hg_client_names); 3308*da14cebeSEric Cheng } 3309*da14cebeSEric Cheng break; 3310*da14cebeSEric Cheng } 3311*da14cebeSEric Cheng 3312*da14cebeSEric Cheng return (buf); 3313*da14cebeSEric Cheng } 3314*da14cebeSEric Cheng 3315*da14cebeSEric Cheng /* callback of dladm_walk_macaddr, invoked for each MAC address slot */ 3316*da14cebeSEric Cheng static boolean_t 3317*da14cebeSEric Cheng print_phys_mac_callback(void *arg, dladm_macaddr_attr_t *attr) 3318*da14cebeSEric Cheng { 3319*da14cebeSEric Cheng print_phys_mac_state_t *mac_state = arg; 3320*da14cebeSEric Cheng show_state_t *state = mac_state->ms_state; 3321*da14cebeSEric Cheng 3322*da14cebeSEric Cheng if (!state->ls_parseable && !state->ls_printheader) { 3323*da14cebeSEric Cheng print_header(&state->ls_print); 3324*da14cebeSEric Cheng state->ls_printheader = B_TRUE; 3325*da14cebeSEric Cheng } 3326*da14cebeSEric Cheng 3327*da14cebeSEric Cheng mac_state->ms_mac_attr = attr; 3328*da14cebeSEric Cheng dladm_print_output(&state->ls_print, state->ls_parseable, 3329*da14cebeSEric Cheng print_phys_one_mac_callback, mac_state); 3330*da14cebeSEric Cheng 3331*da14cebeSEric Cheng return (B_TRUE); 3332*da14cebeSEric Cheng } 3333*da14cebeSEric Cheng 3334*da14cebeSEric Cheng /* invoked by show-phys -m for each physical data-link */ 3335*da14cebeSEric Cheng static dladm_status_t 3336*da14cebeSEric Cheng print_phys_mac(show_state_t *state, datalink_id_t linkid, char *link) 3337*da14cebeSEric Cheng { 3338*da14cebeSEric Cheng print_phys_mac_state_t mac_state; 3339*da14cebeSEric Cheng 3340*da14cebeSEric Cheng mac_state.ms_state = state; 3341*da14cebeSEric Cheng mac_state.ms_link = link; 3342*da14cebeSEric Cheng 3343*da14cebeSEric Cheng return (dladm_walk_macaddr(linkid, &mac_state, 3344*da14cebeSEric Cheng print_phys_mac_callback)); 3345*da14cebeSEric Cheng } 3346*da14cebeSEric Cheng 3347*da14cebeSEric Cheng /* callback of dladm_walk_hwgrp, invoked for each MAC hwgrp */ 3348*da14cebeSEric Cheng static boolean_t 3349*da14cebeSEric Cheng print_phys_hwgrp_callback(void *arg, dladm_hwgrp_attr_t *attr) 3350*da14cebeSEric Cheng { 3351*da14cebeSEric Cheng print_phys_hwgrp_state_t *hwgrp_state = arg; 3352*da14cebeSEric Cheng show_state_t *state = hwgrp_state->hs_state; 3353*da14cebeSEric Cheng 3354*da14cebeSEric Cheng if (!state->ls_parseable && !state->ls_printheader) { 3355*da14cebeSEric Cheng print_header(&state->ls_print); 3356*da14cebeSEric Cheng state->ls_printheader = B_TRUE; 3357*da14cebeSEric Cheng } 3358*da14cebeSEric Cheng hwgrp_state->hs_grp_attr = attr; 3359*da14cebeSEric Cheng dladm_print_output(&state->ls_print, state->ls_parseable, 3360*da14cebeSEric Cheng print_phys_one_hwgrp_callback, hwgrp_state); 3361*da14cebeSEric Cheng 3362*da14cebeSEric Cheng return (B_TRUE); 3363*da14cebeSEric Cheng } 3364*da14cebeSEric Cheng 3365*da14cebeSEric Cheng /* invoked by show-phys -H for each physical data-link */ 3366*da14cebeSEric Cheng static dladm_status_t 3367*da14cebeSEric Cheng print_phys_hwgrp(show_state_t *state, datalink_id_t linkid, char *link) 3368*da14cebeSEric Cheng { 3369*da14cebeSEric Cheng print_phys_hwgrp_state_t hwgrp_state; 3370*da14cebeSEric Cheng 3371*da14cebeSEric Cheng hwgrp_state.hs_state = state; 3372*da14cebeSEric Cheng hwgrp_state.hs_link = link; 3373*da14cebeSEric Cheng return (dladm_walk_hwgrp(linkid, &hwgrp_state, 3374*da14cebeSEric Cheng print_phys_hwgrp_callback)); 3375*da14cebeSEric Cheng } 3376d62bc4baSyz147064 3377d62bc4baSyz147064 static dladm_status_t 3378*da14cebeSEric Cheng print_phys(show_state_t *state, datalink_id_t linkid) 3379d62bc4baSyz147064 { 3380d62bc4baSyz147064 char link[MAXLINKNAMELEN]; 3381d62bc4baSyz147064 uint32_t flags; 3382*da14cebeSEric Cheng dladm_status_t status; 3383d62bc4baSyz147064 datalink_class_t class; 3384d62bc4baSyz147064 uint32_t media; 3385d62bc4baSyz147064 3386d62bc4baSyz147064 if ((status = dladm_datalink_id2info(linkid, &flags, &class, &media, 3387e7801d59Ssowmini link, MAXLINKNAMELEN)) != DLADM_STATUS_OK) { 3388d62bc4baSyz147064 goto done; 3389d62bc4baSyz147064 } 3390d62bc4baSyz147064 3391d62bc4baSyz147064 if (class != DATALINK_CLASS_PHYS) { 3392d62bc4baSyz147064 status = DLADM_STATUS_BADARG; 3393d62bc4baSyz147064 goto done; 3394d62bc4baSyz147064 } 3395d62bc4baSyz147064 3396d62bc4baSyz147064 if (!(state->ls_flags & flags)) { 3397d62bc4baSyz147064 status = DLADM_STATUS_NOTFOUND; 3398d62bc4baSyz147064 goto done; 3399d62bc4baSyz147064 } 3400d62bc4baSyz147064 3401*da14cebeSEric Cheng if (state->ls_mac) 3402*da14cebeSEric Cheng status = print_phys_mac(state, linkid, link); 3403*da14cebeSEric Cheng else if (state->ls_hwgrp) 3404*da14cebeSEric Cheng status = print_phys_hwgrp(state, linkid, link); 3405*da14cebeSEric Cheng else 3406*da14cebeSEric Cheng status = print_phys_default(state, linkid, link, flags, media); 3407d62bc4baSyz147064 3408d62bc4baSyz147064 done: 3409d62bc4baSyz147064 return (status); 3410d62bc4baSyz147064 } 3411d62bc4baSyz147064 3412d62bc4baSyz147064 static int 3413d62bc4baSyz147064 show_phys(datalink_id_t linkid, void *arg) 3414d62bc4baSyz147064 { 3415d62bc4baSyz147064 show_state_t *state = arg; 3416d62bc4baSyz147064 3417*da14cebeSEric Cheng state->ls_status = print_phys(state, linkid); 3418d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 3419d62bc4baSyz147064 } 3420d62bc4baSyz147064 3421d62bc4baSyz147064 /* 3422d62bc4baSyz147064 * Print the active topology information. 3423d62bc4baSyz147064 */ 3424d62bc4baSyz147064 static dladm_status_t 3425e7801d59Ssowmini print_vlan(show_state_t *state, datalink_id_t linkid, link_fields_buf_t *l) 3426d62bc4baSyz147064 { 3427d62bc4baSyz147064 dladm_vlan_attr_t vinfo; 3428d62bc4baSyz147064 uint32_t flags; 3429d62bc4baSyz147064 dladm_status_t status; 3430d62bc4baSyz147064 3431e7801d59Ssowmini if ((status = dladm_datalink_id2info(linkid, &flags, NULL, NULL, 3432e7801d59Ssowmini l->link_name, sizeof (l->link_name))) != DLADM_STATUS_OK) { 3433d62bc4baSyz147064 goto done; 3434d62bc4baSyz147064 } 3435d62bc4baSyz147064 3436d62bc4baSyz147064 if (!(state->ls_flags & flags)) { 3437d62bc4baSyz147064 status = DLADM_STATUS_NOTFOUND; 3438d62bc4baSyz147064 goto done; 3439d62bc4baSyz147064 } 3440d62bc4baSyz147064 3441d62bc4baSyz147064 if ((status = dladm_vlan_info(linkid, &vinfo, state->ls_flags)) != 3442d62bc4baSyz147064 DLADM_STATUS_OK || (status = dladm_datalink_id2info( 3443e7801d59Ssowmini vinfo.dv_linkid, NULL, NULL, NULL, l->link_over, 3444e7801d59Ssowmini sizeof (l->link_over))) != DLADM_STATUS_OK) { 3445d62bc4baSyz147064 goto done; 3446d62bc4baSyz147064 } 3447d62bc4baSyz147064 3448e7801d59Ssowmini (void) snprintf(l->link_vlan_vid, sizeof (l->link_vlan_vid), "%d", 3449e7801d59Ssowmini vinfo.dv_vid); 3450*da14cebeSEric Cheng (void) snprintf(l->link_flags, sizeof (l->link_flags), "%c----", 3451*da14cebeSEric Cheng vinfo.dv_force ? 'f' : '-'); 3452d62bc4baSyz147064 3453d62bc4baSyz147064 done: 3454d62bc4baSyz147064 return (status); 3455d62bc4baSyz147064 } 3456d62bc4baSyz147064 3457d62bc4baSyz147064 static int 3458d62bc4baSyz147064 show_vlan(datalink_id_t linkid, void *arg) 3459d62bc4baSyz147064 { 3460d62bc4baSyz147064 show_state_t *state = arg; 3461d62bc4baSyz147064 dladm_status_t status; 3462e7801d59Ssowmini link_fields_buf_t lbuf; 3463d62bc4baSyz147064 34645f5c9f54SAnurag S. Maskey bzero(&lbuf, sizeof (link_fields_buf_t)); 3465e7801d59Ssowmini status = print_vlan(state, linkid, &lbuf); 3466d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 3467d62bc4baSyz147064 goto done; 3468e7801d59Ssowmini 3469e7801d59Ssowmini if (!state->ls_parseable && !state->ls_printheader) { 3470e7801d59Ssowmini print_header(&state->ls_print); 3471e7801d59Ssowmini state->ls_printheader = B_TRUE; 3472e7801d59Ssowmini } 3473e7801d59Ssowmini 3474e7801d59Ssowmini dladm_print_output(&state->ls_print, state->ls_parseable, 3475e7801d59Ssowmini dladm_print_field, (void *)&lbuf); 3476d62bc4baSyz147064 3477d62bc4baSyz147064 done: 3478d62bc4baSyz147064 state->ls_status = status; 3479d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 3480d62bc4baSyz147064 } 3481d62bc4baSyz147064 3482d62bc4baSyz147064 static void 34838d5c46e6Sam223141 do_show_phys(int argc, char *argv[], const char *use) 3484d62bc4baSyz147064 { 3485d62bc4baSyz147064 int option; 3486d62bc4baSyz147064 uint32_t flags = DLADM_OPT_ACTIVE; 3487d62bc4baSyz147064 boolean_t p_arg = B_FALSE; 3488e7801d59Ssowmini boolean_t o_arg = B_FALSE; 3489*da14cebeSEric Cheng boolean_t m_arg = B_FALSE; 3490*da14cebeSEric Cheng boolean_t H_arg = B_FALSE; 3491d62bc4baSyz147064 datalink_id_t linkid = DATALINK_ALL_LINKID; 3492d62bc4baSyz147064 show_state_t state; 3493d62bc4baSyz147064 dladm_status_t status; 3494e7801d59Ssowmini char *fields_str = NULL; 3495e7801d59Ssowmini print_field_t **fields; 3496e7801d59Ssowmini uint_t nfields; 3497e7801d59Ssowmini char *all_active_fields = 3498e7801d59Ssowmini "link,media,state,speed,duplex,device"; 34995f5c9f54SAnurag S. Maskey char *all_inactive_fields = "link,device,media,flags"; 3500*da14cebeSEric Cheng char *all_mac_fields = "link,slot,address,inuse,client"; 3501*da14cebeSEric Cheng char *all_hwgrp_fields = 3502*da14cebeSEric Cheng "link,group,grouptype,rings,clients"; 3503*da14cebeSEric Cheng print_field_t *pf; 3504*da14cebeSEric Cheng int pfmax; 3505d62bc4baSyz147064 3506e7801d59Ssowmini bzero(&state, sizeof (state)); 3507d62bc4baSyz147064 opterr = 0; 3508*da14cebeSEric Cheng while ((option = getopt_long(argc, argv, ":pPo:mH", 3509d62bc4baSyz147064 show_lopts, NULL)) != -1) { 3510d62bc4baSyz147064 switch (option) { 3511d62bc4baSyz147064 case 'p': 3512d62bc4baSyz147064 if (p_arg) 3513d62bc4baSyz147064 die_optdup(option); 3514d62bc4baSyz147064 3515d62bc4baSyz147064 p_arg = B_TRUE; 3516d62bc4baSyz147064 break; 3517d62bc4baSyz147064 case 'P': 3518d62bc4baSyz147064 if (flags != DLADM_OPT_ACTIVE) 3519d62bc4baSyz147064 die_optdup(option); 3520d62bc4baSyz147064 3521d62bc4baSyz147064 flags = DLADM_OPT_PERSIST; 3522d62bc4baSyz147064 break; 3523e7801d59Ssowmini case 'o': 3524e7801d59Ssowmini o_arg = B_TRUE; 3525e7801d59Ssowmini fields_str = optarg; 3526e7801d59Ssowmini break; 3527*da14cebeSEric Cheng case 'm': 3528*da14cebeSEric Cheng m_arg = B_TRUE; 3529*da14cebeSEric Cheng break; 3530*da14cebeSEric Cheng case 'H': 3531*da14cebeSEric Cheng H_arg = B_TRUE; 3532*da14cebeSEric Cheng break; 3533d62bc4baSyz147064 default: 35348d5c46e6Sam223141 die_opterr(optopt, option, use); 3535d62bc4baSyz147064 break; 3536d62bc4baSyz147064 } 3537d62bc4baSyz147064 } 3538d62bc4baSyz147064 35390d365605Sschuster if (p_arg && !o_arg) 35400d365605Sschuster die("-p requires -o"); 35410d365605Sschuster 3542*da14cebeSEric Cheng if (m_arg && H_arg) 3543*da14cebeSEric Cheng die("-m cannot combine with -H"); 3544*da14cebeSEric Cheng 35450d365605Sschuster if (p_arg && strcasecmp(fields_str, "all") == 0) 35460d365605Sschuster die("\"-o all\" is invalid with -p"); 35470d365605Sschuster 3548d62bc4baSyz147064 /* get link name (optional last argument) */ 3549d62bc4baSyz147064 if (optind == (argc-1)) { 3550d62bc4baSyz147064 if ((status = dladm_name2info(argv[optind], &linkid, NULL, 3551d62bc4baSyz147064 NULL, NULL)) != DLADM_STATUS_OK) { 3552d62bc4baSyz147064 die_dlerr(status, "link %s is not valid", argv[optind]); 3553d62bc4baSyz147064 } 3554d62bc4baSyz147064 } else if (optind != argc) { 3555d62bc4baSyz147064 usage(); 3556d62bc4baSyz147064 } 3557d62bc4baSyz147064 3558d62bc4baSyz147064 state.ls_parseable = p_arg; 3559d62bc4baSyz147064 state.ls_flags = flags; 3560d62bc4baSyz147064 state.ls_donefirst = B_FALSE; 3561*da14cebeSEric Cheng state.ls_mac = m_arg; 3562*da14cebeSEric Cheng state.ls_hwgrp = H_arg; 3563d62bc4baSyz147064 3564*da14cebeSEric Cheng if (m_arg && !(flags & DLADM_OPT_ACTIVE)) { 3565*da14cebeSEric Cheng /* 3566*da14cebeSEric Cheng * We can only display the factory MAC addresses of 3567*da14cebeSEric Cheng * active data-links. 3568*da14cebeSEric Cheng */ 3569*da14cebeSEric Cheng die("-m not compatible with -P"); 3570e7801d59Ssowmini } 3571e7801d59Ssowmini 3572*da14cebeSEric Cheng if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) { 3573*da14cebeSEric Cheng if (state.ls_mac) 3574*da14cebeSEric Cheng fields_str = all_mac_fields; 3575*da14cebeSEric Cheng else if (state.ls_hwgrp) 3576*da14cebeSEric Cheng fields_str = all_hwgrp_fields; 3577*da14cebeSEric Cheng else if (state.ls_flags & DLADM_OPT_ACTIVE) { 3578*da14cebeSEric Cheng fields_str = all_active_fields; 3579*da14cebeSEric Cheng } else { 3580*da14cebeSEric Cheng fields_str = all_inactive_fields; 3581*da14cebeSEric Cheng } 3582*da14cebeSEric Cheng } 3583*da14cebeSEric Cheng 3584*da14cebeSEric Cheng if (state.ls_mac) { 3585*da14cebeSEric Cheng pf = phys_m_fields; 3586*da14cebeSEric Cheng pfmax = PHYS_M_MAX_FIELDS; 3587*da14cebeSEric Cheng } else if (state.ls_hwgrp) { 3588*da14cebeSEric Cheng pf = phys_h_fields; 3589*da14cebeSEric Cheng pfmax = PHYS_H_MAX_FIELDS; 3590*da14cebeSEric Cheng } else { 3591*da14cebeSEric Cheng pf = phys_fields; 3592*da14cebeSEric Cheng pfmax = PHYS_MAX_FIELDS; 3593*da14cebeSEric Cheng } 3594*da14cebeSEric Cheng 3595*da14cebeSEric Cheng fields = parse_output_fields(fields_str, pf, 3596*da14cebeSEric Cheng pfmax, CMD_TYPE_ANY, &nfields); 3597e7801d59Ssowmini 3598e7801d59Ssowmini if (fields == NULL) { 3599e7801d59Ssowmini die("invalid field(s) specified"); 3600e7801d59Ssowmini return; 3601e7801d59Ssowmini } 3602e7801d59Ssowmini 3603e7801d59Ssowmini state.ls_print.ps_fields = fields; 3604e7801d59Ssowmini state.ls_print.ps_nfields = nfields; 3605e7801d59Ssowmini 3606d62bc4baSyz147064 if (linkid == DATALINK_ALL_LINKID) { 3607d62bc4baSyz147064 (void) dladm_walk_datalink_id(show_phys, &state, 3608d62bc4baSyz147064 DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, flags); 3609d62bc4baSyz147064 } else { 3610d62bc4baSyz147064 (void) show_phys(linkid, &state); 3611d62bc4baSyz147064 if (state.ls_status != DLADM_STATUS_OK) { 3612d62bc4baSyz147064 die_dlerr(state.ls_status, 3613d62bc4baSyz147064 "failed to show physical link %s", argv[optind]); 3614d62bc4baSyz147064 } 3615d62bc4baSyz147064 } 3616d62bc4baSyz147064 } 3617d62bc4baSyz147064 3618d62bc4baSyz147064 static void 36198d5c46e6Sam223141 do_show_vlan(int argc, char *argv[], const char *use) 3620d62bc4baSyz147064 { 3621d62bc4baSyz147064 int option; 3622d62bc4baSyz147064 uint32_t flags = DLADM_OPT_ACTIVE; 3623d62bc4baSyz147064 boolean_t p_arg = B_FALSE; 3624d62bc4baSyz147064 datalink_id_t linkid = DATALINK_ALL_LINKID; 3625d62bc4baSyz147064 show_state_t state; 3626d62bc4baSyz147064 dladm_status_t status; 3627e7801d59Ssowmini boolean_t o_arg = B_FALSE; 3628e7801d59Ssowmini char *fields_str = NULL; 3629e7801d59Ssowmini print_field_t **fields; 3630e7801d59Ssowmini uint_t nfields; 3631e7801d59Ssowmini char *all_fields = "link,vid,over,flags"; 3632e7801d59Ssowmini 3633e7801d59Ssowmini bzero(&state, sizeof (state)); 3634d62bc4baSyz147064 3635d62bc4baSyz147064 opterr = 0; 3636e7801d59Ssowmini while ((option = getopt_long(argc, argv, ":pPo:", 3637d62bc4baSyz147064 show_lopts, NULL)) != -1) { 3638d62bc4baSyz147064 switch (option) { 3639d62bc4baSyz147064 case 'p': 3640d62bc4baSyz147064 if (p_arg) 3641d62bc4baSyz147064 die_optdup(option); 3642d62bc4baSyz147064 3643d62bc4baSyz147064 p_arg = B_TRUE; 3644d62bc4baSyz147064 break; 3645d62bc4baSyz147064 case 'P': 3646d62bc4baSyz147064 if (flags != DLADM_OPT_ACTIVE) 3647d62bc4baSyz147064 die_optdup(option); 3648d62bc4baSyz147064 3649d62bc4baSyz147064 flags = DLADM_OPT_PERSIST; 3650d62bc4baSyz147064 break; 3651e7801d59Ssowmini case 'o': 3652e7801d59Ssowmini o_arg = B_TRUE; 3653e7801d59Ssowmini fields_str = optarg; 3654e7801d59Ssowmini break; 3655d62bc4baSyz147064 default: 36568d5c46e6Sam223141 die_opterr(optopt, option, use); 3657d62bc4baSyz147064 break; 3658d62bc4baSyz147064 } 3659d62bc4baSyz147064 } 3660d62bc4baSyz147064 36610d365605Sschuster if (p_arg && !o_arg) 36620d365605Sschuster die("-p requires -o"); 36630d365605Sschuster 36640d365605Sschuster if (p_arg && strcasecmp(fields_str, "all") == 0) 36650d365605Sschuster die("\"-o all\" is invalid with -p"); 36660d365605Sschuster 3667d62bc4baSyz147064 /* get link name (optional last argument) */ 3668d62bc4baSyz147064 if (optind == (argc-1)) { 3669d62bc4baSyz147064 if ((status = dladm_name2info(argv[optind], &linkid, NULL, 3670d62bc4baSyz147064 NULL, NULL)) != DLADM_STATUS_OK) { 3671d62bc4baSyz147064 die_dlerr(status, "link %s is not valid", argv[optind]); 3672d62bc4baSyz147064 } 3673d62bc4baSyz147064 } else if (optind != argc) { 3674d62bc4baSyz147064 usage(); 3675d62bc4baSyz147064 } 3676d62bc4baSyz147064 3677d62bc4baSyz147064 state.ls_parseable = p_arg; 3678d62bc4baSyz147064 state.ls_flags = flags; 3679d62bc4baSyz147064 state.ls_donefirst = B_FALSE; 3680d62bc4baSyz147064 3681e7801d59Ssowmini if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) 3682e7801d59Ssowmini fields_str = all_fields; 3683e7801d59Ssowmini 3684e7801d59Ssowmini fields = parse_output_fields(fields_str, vlan_fields, VLAN_MAX_FIELDS, 3685e7801d59Ssowmini CMD_TYPE_ANY, &nfields); 3686e7801d59Ssowmini 3687e7801d59Ssowmini if (fields == NULL) { 3688e7801d59Ssowmini die("invalid field(s) specified"); 3689e7801d59Ssowmini return; 3690e7801d59Ssowmini } 3691e7801d59Ssowmini state.ls_print.ps_fields = fields; 3692e7801d59Ssowmini state.ls_print.ps_nfields = nfields; 3693e7801d59Ssowmini 3694d62bc4baSyz147064 if (linkid == DATALINK_ALL_LINKID) { 3695d62bc4baSyz147064 (void) dladm_walk_datalink_id(show_vlan, &state, 3696d62bc4baSyz147064 DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, flags); 3697d62bc4baSyz147064 } else { 3698d62bc4baSyz147064 (void) show_vlan(linkid, &state); 3699d62bc4baSyz147064 if (state.ls_status != DLADM_STATUS_OK) { 3700d62bc4baSyz147064 die_dlerr(state.ls_status, "failed to show vlan %s", 3701d62bc4baSyz147064 argv[optind]); 3702d62bc4baSyz147064 } 3703d62bc4baSyz147064 } 3704d62bc4baSyz147064 } 3705d62bc4baSyz147064 3706d62bc4baSyz147064 static void 3707*da14cebeSEric Cheng do_create_vnic(int argc, char *argv[], const char *use) 3708*da14cebeSEric Cheng { 3709*da14cebeSEric Cheng datalink_id_t linkid, dev_linkid; 3710*da14cebeSEric Cheng char devname[MAXLINKNAMELEN]; 3711*da14cebeSEric Cheng char name[MAXLINKNAMELEN]; 3712*da14cebeSEric Cheng boolean_t l_arg = B_FALSE; 3713*da14cebeSEric Cheng uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 3714*da14cebeSEric Cheng char *altroot = NULL; 3715*da14cebeSEric Cheng char option; 3716*da14cebeSEric Cheng char *endp = NULL; 3717*da14cebeSEric Cheng dladm_status_t status; 3718*da14cebeSEric Cheng vnic_mac_addr_type_t mac_addr_type = VNIC_MAC_ADDR_TYPE_AUTO; 3719*da14cebeSEric Cheng uchar_t *mac_addr; 3720*da14cebeSEric Cheng int mac_slot = -1, maclen = 0, mac_prefix_len = 0; 3721*da14cebeSEric Cheng dladm_arg_list_t *proplist = NULL; 3722*da14cebeSEric Cheng uint16_t vid = 0; 3723*da14cebeSEric Cheng 3724*da14cebeSEric Cheng opterr = 0; 3725*da14cebeSEric Cheng while ((option = getopt_long(argc, argv, ":tfR:l:m:n:p:r:v:H", 3726*da14cebeSEric Cheng vnic_lopts, NULL)) != -1) { 3727*da14cebeSEric Cheng switch (option) { 3728*da14cebeSEric Cheng case 't': 3729*da14cebeSEric Cheng flags &= ~DLADM_OPT_PERSIST; 3730*da14cebeSEric Cheng break; 3731*da14cebeSEric Cheng case 'R': 3732*da14cebeSEric Cheng altroot = optarg; 3733*da14cebeSEric Cheng break; 3734*da14cebeSEric Cheng case 'l': 3735*da14cebeSEric Cheng if (strlcpy(devname, optarg, MAXLINKNAMELEN) >= 3736*da14cebeSEric Cheng MAXLINKNAMELEN) 3737*da14cebeSEric Cheng die("link name too long"); 3738*da14cebeSEric Cheng l_arg = B_TRUE; 3739*da14cebeSEric Cheng break; 3740*da14cebeSEric Cheng case 'm': 3741*da14cebeSEric Cheng if (strcmp(optarg, "fixed") == 0) { 3742*da14cebeSEric Cheng /* 3743*da14cebeSEric Cheng * A fixed MAC address must be specified 3744*da14cebeSEric Cheng * by its value, not by the keyword 'fixed'. 3745*da14cebeSEric Cheng */ 3746*da14cebeSEric Cheng die("'fixed' is not a valid MAC address"); 3747*da14cebeSEric Cheng } 3748*da14cebeSEric Cheng if (dladm_vnic_str2macaddrtype(optarg, 3749*da14cebeSEric Cheng &mac_addr_type) != DLADM_STATUS_OK) { 3750*da14cebeSEric Cheng mac_addr_type = VNIC_MAC_ADDR_TYPE_FIXED; 3751*da14cebeSEric Cheng /* MAC address specified by value */ 3752*da14cebeSEric Cheng mac_addr = _link_aton(optarg, &maclen); 3753*da14cebeSEric Cheng if (mac_addr == NULL) { 3754*da14cebeSEric Cheng if (maclen == -1) 3755*da14cebeSEric Cheng die("invalid MAC address"); 3756*da14cebeSEric Cheng else 3757*da14cebeSEric Cheng die("out of memory"); 3758*da14cebeSEric Cheng exit(1); 3759*da14cebeSEric Cheng } 3760*da14cebeSEric Cheng } 3761*da14cebeSEric Cheng break; 3762*da14cebeSEric Cheng case 'n': 3763*da14cebeSEric Cheng errno = 0; 3764*da14cebeSEric Cheng mac_slot = (int)strtol(optarg, &endp, 10); 3765*da14cebeSEric Cheng if (errno != 0 || *endp != '\0') 3766*da14cebeSEric Cheng die("invalid slot number"); 3767*da14cebeSEric Cheng break; 3768*da14cebeSEric Cheng case 'p': 3769*da14cebeSEric Cheng if (dladm_parse_link_props(optarg, &proplist, B_FALSE) 3770*da14cebeSEric Cheng != DLADM_STATUS_OK) 3771*da14cebeSEric Cheng die("invalid vnic property"); 3772*da14cebeSEric Cheng break; 3773*da14cebeSEric Cheng case 'r': 3774*da14cebeSEric Cheng mac_addr = _link_aton(optarg, &mac_prefix_len); 3775*da14cebeSEric Cheng if (mac_addr == NULL) { 3776*da14cebeSEric Cheng if (mac_prefix_len == -1) 3777*da14cebeSEric Cheng die("invalid MAC address"); 3778*da14cebeSEric Cheng else 3779*da14cebeSEric Cheng die("out of memory"); 3780*da14cebeSEric Cheng exit(1); 3781*da14cebeSEric Cheng } 3782*da14cebeSEric Cheng break; 3783*da14cebeSEric Cheng case 'v': 3784*da14cebeSEric Cheng vid = (int)strtol(optarg, &endp, 10); 3785*da14cebeSEric Cheng if (errno != 0 || *endp != '\0' || vid == 0) 3786*da14cebeSEric Cheng /* VID of 0 is invalid */ 3787*da14cebeSEric Cheng die("invalid VLAN id"); 3788*da14cebeSEric Cheng break; 3789*da14cebeSEric Cheng case 'f': 3790*da14cebeSEric Cheng flags |= DLADM_OPT_FORCE; 3791*da14cebeSEric Cheng break; 3792*da14cebeSEric Cheng case 'H': 3793*da14cebeSEric Cheng flags |= DLADM_OPT_HWRINGS; 3794*da14cebeSEric Cheng break; 3795*da14cebeSEric Cheng default: 3796*da14cebeSEric Cheng die_opterr(optopt, option, use); 3797*da14cebeSEric Cheng } 3798*da14cebeSEric Cheng } 3799*da14cebeSEric Cheng 3800*da14cebeSEric Cheng /* 3801*da14cebeSEric Cheng * 'f' - force, flag can be specified only with 'v' - vlan. 3802*da14cebeSEric Cheng */ 3803*da14cebeSEric Cheng if ((flags & DLADM_OPT_FORCE) != 0 && vid == 0) 3804*da14cebeSEric Cheng die("-f option can only be used with -v"); 3805*da14cebeSEric Cheng 3806*da14cebeSEric Cheng if (mac_prefix_len != 0 && mac_addr_type != VNIC_MAC_ADDR_TYPE_RANDOM && 3807*da14cebeSEric Cheng mac_addr_type != VNIC_MAC_ADDR_TYPE_FIXED) 3808*da14cebeSEric Cheng usage(); 3809*da14cebeSEric Cheng 3810*da14cebeSEric Cheng /* check required options */ 3811*da14cebeSEric Cheng if (!l_arg) 3812*da14cebeSEric Cheng usage(); 3813*da14cebeSEric Cheng 3814*da14cebeSEric Cheng if (mac_slot != -1 && mac_addr_type != VNIC_MAC_ADDR_TYPE_FACTORY) 3815*da14cebeSEric Cheng usage(); 3816*da14cebeSEric Cheng 3817*da14cebeSEric Cheng /* the VNIC id is the required operand */ 3818*da14cebeSEric Cheng if (optind != (argc - 1)) 3819*da14cebeSEric Cheng usage(); 3820*da14cebeSEric Cheng 3821*da14cebeSEric Cheng if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= MAXLINKNAMELEN) 3822*da14cebeSEric Cheng die("link name too long '%s'", argv[optind]); 3823*da14cebeSEric Cheng 3824*da14cebeSEric Cheng if (!dladm_valid_linkname(name)) 3825*da14cebeSEric Cheng die("invalid link name '%s'", argv[optind]); 3826*da14cebeSEric Cheng 3827*da14cebeSEric Cheng if (altroot != NULL) 3828*da14cebeSEric Cheng altroot_cmd(altroot, argc, argv); 3829*da14cebeSEric Cheng 3830*da14cebeSEric Cheng if (dladm_name2info(devname, &dev_linkid, NULL, NULL, NULL) != 3831*da14cebeSEric Cheng DLADM_STATUS_OK) 3832*da14cebeSEric Cheng die("invalid link name '%s'", devname); 3833*da14cebeSEric Cheng 3834*da14cebeSEric Cheng status = dladm_vnic_create(name, dev_linkid, mac_addr_type, mac_addr, 3835*da14cebeSEric Cheng maclen, &mac_slot, mac_prefix_len, vid, &linkid, proplist, flags); 3836*da14cebeSEric Cheng if (status != DLADM_STATUS_OK) 3837*da14cebeSEric Cheng die_dlerr(status, "vnic creation over %s failed", devname); 3838*da14cebeSEric Cheng 3839*da14cebeSEric Cheng dladm_free_props(proplist); 3840*da14cebeSEric Cheng } 3841*da14cebeSEric Cheng 3842*da14cebeSEric Cheng static void 3843*da14cebeSEric Cheng do_etherstub_check(const char *name, datalink_id_t linkid, boolean_t etherstub, 3844*da14cebeSEric Cheng uint32_t flags) 3845*da14cebeSEric Cheng { 3846*da14cebeSEric Cheng boolean_t is_etherstub; 3847*da14cebeSEric Cheng dladm_vnic_attr_t attr; 3848*da14cebeSEric Cheng 3849*da14cebeSEric Cheng if (dladm_vnic_info(linkid, &attr, flags) != DLADM_STATUS_OK) { 3850*da14cebeSEric Cheng /* 3851*da14cebeSEric Cheng * Let the delete continue anyway. 3852*da14cebeSEric Cheng */ 3853*da14cebeSEric Cheng return; 3854*da14cebeSEric Cheng } 3855*da14cebeSEric Cheng is_etherstub = (attr.va_link_id == DATALINK_INVALID_LINKID); 3856*da14cebeSEric Cheng if (is_etherstub != etherstub) { 3857*da14cebeSEric Cheng die("'%s' is not %s", name, 3858*da14cebeSEric Cheng (is_etherstub ? "a vnic" : "an etherstub")); 3859*da14cebeSEric Cheng } 3860*da14cebeSEric Cheng } 3861*da14cebeSEric Cheng 3862*da14cebeSEric Cheng static void 3863*da14cebeSEric Cheng do_delete_vnic_common(int argc, char *argv[], const char *use, 3864*da14cebeSEric Cheng boolean_t etherstub) 3865*da14cebeSEric Cheng { 3866*da14cebeSEric Cheng char option; 3867*da14cebeSEric Cheng uint32_t flags = DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 3868*da14cebeSEric Cheng datalink_id_t linkid; 3869*da14cebeSEric Cheng char *altroot = NULL; 3870*da14cebeSEric Cheng dladm_status_t status; 3871*da14cebeSEric Cheng 3872*da14cebeSEric Cheng opterr = 0; 3873*da14cebeSEric Cheng while ((option = getopt_long(argc, argv, ":R:t", lopts, 3874*da14cebeSEric Cheng NULL)) != -1) { 3875*da14cebeSEric Cheng switch (option) { 3876*da14cebeSEric Cheng case 't': 3877*da14cebeSEric Cheng flags &= ~DLADM_OPT_PERSIST; 3878*da14cebeSEric Cheng break; 3879*da14cebeSEric Cheng case 'R': 3880*da14cebeSEric Cheng altroot = optarg; 3881*da14cebeSEric Cheng break; 3882*da14cebeSEric Cheng default: 3883*da14cebeSEric Cheng die_opterr(optopt, option, use); 3884*da14cebeSEric Cheng } 3885*da14cebeSEric Cheng } 3886*da14cebeSEric Cheng 3887*da14cebeSEric Cheng /* get vnic name (required last argument) */ 3888*da14cebeSEric Cheng if (optind != (argc - 1)) 3889*da14cebeSEric Cheng usage(); 3890*da14cebeSEric Cheng 3891*da14cebeSEric Cheng if (altroot != NULL) 3892*da14cebeSEric Cheng altroot_cmd(altroot, argc, argv); 3893*da14cebeSEric Cheng 3894*da14cebeSEric Cheng status = dladm_name2info(argv[optind], &linkid, NULL, NULL, NULL); 3895*da14cebeSEric Cheng if (status != DLADM_STATUS_OK) 3896*da14cebeSEric Cheng die("invalid link name '%s'", argv[optind]); 3897*da14cebeSEric Cheng 3898*da14cebeSEric Cheng if ((flags & DLADM_OPT_ACTIVE) != 0) { 3899*da14cebeSEric Cheng do_etherstub_check(argv[optind], linkid, etherstub, 3900*da14cebeSEric Cheng DLADM_OPT_ACTIVE); 3901*da14cebeSEric Cheng } 3902*da14cebeSEric Cheng if ((flags & DLADM_OPT_PERSIST) != 0) { 3903*da14cebeSEric Cheng do_etherstub_check(argv[optind], linkid, etherstub, 3904*da14cebeSEric Cheng DLADM_OPT_PERSIST); 3905*da14cebeSEric Cheng } 3906*da14cebeSEric Cheng 3907*da14cebeSEric Cheng status = dladm_vnic_delete(linkid, flags); 3908*da14cebeSEric Cheng if (status != DLADM_STATUS_OK) 3909*da14cebeSEric Cheng die_dlerr(status, "vnic deletion failed"); 3910*da14cebeSEric Cheng } 3911*da14cebeSEric Cheng 3912*da14cebeSEric Cheng static void 3913*da14cebeSEric Cheng do_delete_vnic(int argc, char *argv[], const char *use) 3914*da14cebeSEric Cheng { 3915*da14cebeSEric Cheng do_delete_vnic_common(argc, argv, use, B_FALSE); 3916*da14cebeSEric Cheng } 3917*da14cebeSEric Cheng 3918*da14cebeSEric Cheng /* ARGSUSED */ 3919*da14cebeSEric Cheng static void 3920*da14cebeSEric Cheng do_up_vnic_common(int argc, char *argv[], const char *use, boolean_t vlan) 3921*da14cebeSEric Cheng { 3922*da14cebeSEric Cheng datalink_id_t linkid = DATALINK_ALL_LINKID; 3923*da14cebeSEric Cheng dladm_status_t status; 3924*da14cebeSEric Cheng char *type; 3925*da14cebeSEric Cheng 3926*da14cebeSEric Cheng type = vlan ? "vlan" : "vnic"; 3927*da14cebeSEric Cheng 3928*da14cebeSEric Cheng /* 3929*da14cebeSEric Cheng * get the id or the name of the vnic/vlan (optional last argument) 3930*da14cebeSEric Cheng */ 3931*da14cebeSEric Cheng if (argc == 2) { 3932*da14cebeSEric Cheng status = dladm_name2info(argv[1], &linkid, NULL, NULL, NULL); 3933*da14cebeSEric Cheng if (status != DLADM_STATUS_OK) 3934*da14cebeSEric Cheng goto done; 3935*da14cebeSEric Cheng 3936*da14cebeSEric Cheng } else if (argc > 2) { 3937*da14cebeSEric Cheng usage(); 3938*da14cebeSEric Cheng } 3939*da14cebeSEric Cheng 3940*da14cebeSEric Cheng if (vlan) 3941*da14cebeSEric Cheng status = dladm_vlan_up(linkid); 3942*da14cebeSEric Cheng else 3943*da14cebeSEric Cheng status = dladm_vnic_up(linkid, 0); 3944*da14cebeSEric Cheng 3945*da14cebeSEric Cheng done: 3946*da14cebeSEric Cheng if (status != DLADM_STATUS_OK) { 3947*da14cebeSEric Cheng if (argc == 2) { 3948*da14cebeSEric Cheng die_dlerr(status, 3949*da14cebeSEric Cheng "could not bring up %s '%s'", type, argv[1]); 3950*da14cebeSEric Cheng } else { 3951*da14cebeSEric Cheng die_dlerr(status, "could not bring %ss up", type); 3952*da14cebeSEric Cheng } 3953*da14cebeSEric Cheng } 3954*da14cebeSEric Cheng } 3955*da14cebeSEric Cheng 3956*da14cebeSEric Cheng static void 3957*da14cebeSEric Cheng do_up_vnic(int argc, char *argv[], const char *use) 3958*da14cebeSEric Cheng { 3959*da14cebeSEric Cheng do_up_vnic_common(argc, argv, use, B_FALSE); 3960*da14cebeSEric Cheng } 3961*da14cebeSEric Cheng 3962*da14cebeSEric Cheng static void 3963*da14cebeSEric Cheng dump_vnics_head(const char *dev) 3964*da14cebeSEric Cheng { 3965*da14cebeSEric Cheng if (strlen(dev)) 3966*da14cebeSEric Cheng (void) printf("%s", dev); 3967*da14cebeSEric Cheng 3968*da14cebeSEric Cheng (void) printf("\tipackets rbytes opackets obytes "); 3969*da14cebeSEric Cheng 3970*da14cebeSEric Cheng if (strlen(dev)) 3971*da14cebeSEric Cheng (void) printf("%%ipkts %%opkts\n"); 3972*da14cebeSEric Cheng else 3973*da14cebeSEric Cheng (void) printf("\n"); 3974*da14cebeSEric Cheng } 3975*da14cebeSEric Cheng 3976*da14cebeSEric Cheng static void 3977*da14cebeSEric Cheng dump_vnic_stat(const char *name, datalink_id_t vnic_id, 3978*da14cebeSEric Cheng show_vnic_state_t *state, pktsum_t *vnic_stats, pktsum_t *tot_stats) 3979*da14cebeSEric Cheng { 3980*da14cebeSEric Cheng pktsum_t diff_stats; 3981*da14cebeSEric Cheng pktsum_t *old_stats = &state->vs_prevstats[vnic_id]; 3982*da14cebeSEric Cheng 3983*da14cebeSEric Cheng dladm_stats_diff(&diff_stats, vnic_stats, old_stats); 3984*da14cebeSEric Cheng 3985*da14cebeSEric Cheng (void) printf("%s", name); 3986*da14cebeSEric Cheng 3987*da14cebeSEric Cheng (void) printf("\t%-10llu", diff_stats.ipackets); 3988*da14cebeSEric Cheng (void) printf("%-12llu", diff_stats.rbytes); 3989*da14cebeSEric Cheng (void) printf("%-10llu", diff_stats.opackets); 3990*da14cebeSEric Cheng (void) printf("%-12llu", diff_stats.obytes); 3991*da14cebeSEric Cheng 3992*da14cebeSEric Cheng if (tot_stats) { 3993*da14cebeSEric Cheng if (tot_stats->ipackets == 0) { 3994*da14cebeSEric Cheng (void) printf("\t-"); 3995*da14cebeSEric Cheng } else { 3996*da14cebeSEric Cheng (void) printf("\t%-6.1f", (double)diff_stats.ipackets/ 3997*da14cebeSEric Cheng (double)tot_stats->ipackets * 100); 3998*da14cebeSEric Cheng } 3999*da14cebeSEric Cheng if (tot_stats->opackets == 0) { 4000*da14cebeSEric Cheng (void) printf("\t-"); 4001*da14cebeSEric Cheng } else { 4002*da14cebeSEric Cheng (void) printf("\t%-6.1f", (double)diff_stats.opackets/ 4003*da14cebeSEric Cheng (double)tot_stats->opackets * 100); 4004*da14cebeSEric Cheng } 4005*da14cebeSEric Cheng } 4006*da14cebeSEric Cheng (void) printf("\n"); 4007*da14cebeSEric Cheng 4008*da14cebeSEric Cheng *old_stats = *vnic_stats; 4009*da14cebeSEric Cheng } 4010*da14cebeSEric Cheng 4011*da14cebeSEric Cheng /* 4012*da14cebeSEric Cheng * Called from the walker dladm_vnic_walk_sys() for each vnic to display 4013*da14cebeSEric Cheng * vnic information or statistics. 4014*da14cebeSEric Cheng */ 4015*da14cebeSEric Cheng static dladm_status_t 4016*da14cebeSEric Cheng print_vnic(show_vnic_state_t *state, datalink_id_t linkid) 4017*da14cebeSEric Cheng { 4018*da14cebeSEric Cheng dladm_vnic_attr_t attr, *vnic = &attr; 4019*da14cebeSEric Cheng dladm_status_t status; 4020*da14cebeSEric Cheng boolean_t is_etherstub; 4021*da14cebeSEric Cheng char devname[MAXLINKNAMELEN]; 4022*da14cebeSEric Cheng char vnic_name[MAXLINKNAMELEN]; 4023*da14cebeSEric Cheng char mstr[MAXMACADDRLEN * 3]; 4024*da14cebeSEric Cheng vnic_fields_buf_t vbuf; 4025*da14cebeSEric Cheng 4026*da14cebeSEric Cheng if ((status = dladm_vnic_info(linkid, vnic, state->vs_flags)) != 4027*da14cebeSEric Cheng DLADM_STATUS_OK) 4028*da14cebeSEric Cheng return (status); 4029*da14cebeSEric Cheng 4030*da14cebeSEric Cheng is_etherstub = (vnic->va_link_id == DATALINK_INVALID_LINKID); 4031*da14cebeSEric Cheng if (state->vs_etherstub != is_etherstub) { 4032*da14cebeSEric Cheng /* 4033*da14cebeSEric Cheng * Want all etherstub but it's not one, or want 4034*da14cebeSEric Cheng * non-etherstub and it's one. 4035*da14cebeSEric Cheng */ 4036*da14cebeSEric Cheng return (DLADM_STATUS_OK); 4037*da14cebeSEric Cheng } 4038*da14cebeSEric Cheng 4039*da14cebeSEric Cheng if (state->vs_link_id != DATALINK_ALL_LINKID) { 4040*da14cebeSEric Cheng if (state->vs_link_id != vnic->va_link_id) 4041*da14cebeSEric Cheng return (DLADM_STATUS_OK); 4042*da14cebeSEric Cheng } 4043*da14cebeSEric Cheng 4044*da14cebeSEric Cheng if (dladm_datalink_id2info(linkid, NULL, NULL, 4045*da14cebeSEric Cheng NULL, vnic_name, sizeof (vnic_name)) != DLADM_STATUS_OK) 4046*da14cebeSEric Cheng return (DLADM_STATUS_BADARG); 4047*da14cebeSEric Cheng 4048*da14cebeSEric Cheng bzero(devname, sizeof (devname)); 4049*da14cebeSEric Cheng if (!is_etherstub && 4050*da14cebeSEric Cheng dladm_datalink_id2info(vnic->va_link_id, NULL, NULL, 4051*da14cebeSEric Cheng NULL, devname, sizeof (devname)) != DLADM_STATUS_OK) 4052*da14cebeSEric Cheng return (DLADM_STATUS_BADARG); 4053*da14cebeSEric Cheng 4054*da14cebeSEric Cheng state->vs_found = B_TRUE; 4055*da14cebeSEric Cheng if (state->vs_stats) { 4056*da14cebeSEric Cheng /* print vnic statistics */ 4057*da14cebeSEric Cheng pktsum_t vnic_stats; 4058*da14cebeSEric Cheng 4059*da14cebeSEric Cheng if (state->vs_firstonly) { 4060*da14cebeSEric Cheng if (state->vs_donefirst) 4061*da14cebeSEric Cheng return (0); 4062*da14cebeSEric Cheng state->vs_donefirst = B_TRUE; 4063*da14cebeSEric Cheng } 4064*da14cebeSEric Cheng 4065*da14cebeSEric Cheng if (!state->vs_printstats) { 4066*da14cebeSEric Cheng /* 4067*da14cebeSEric Cheng * get vnic statistics and add to the sum for the 4068*da14cebeSEric Cheng * named device. 4069*da14cebeSEric Cheng */ 4070*da14cebeSEric Cheng get_link_stats(vnic_name, &vnic_stats); 4071*da14cebeSEric Cheng dladm_stats_total(&state->vs_totalstats, &vnic_stats, 4072*da14cebeSEric Cheng &state->vs_prevstats[vnic->va_vnic_id]); 4073*da14cebeSEric Cheng } else { 4074*da14cebeSEric Cheng /* get and print vnic statistics */ 4075*da14cebeSEric Cheng get_link_stats(vnic_name, &vnic_stats); 4076*da14cebeSEric Cheng dump_vnic_stat(vnic_name, linkid, state, &vnic_stats, 4077*da14cebeSEric Cheng &state->vs_totalstats); 4078*da14cebeSEric Cheng } 4079*da14cebeSEric Cheng return (DLADM_STATUS_OK); 4080*da14cebeSEric Cheng } else { 4081*da14cebeSEric Cheng (void) snprintf(vbuf.vnic_link, sizeof (vbuf.vnic_link), 4082*da14cebeSEric Cheng "%s", vnic_name); 4083*da14cebeSEric Cheng 4084*da14cebeSEric Cheng if (!is_etherstub) { 4085*da14cebeSEric Cheng 4086*da14cebeSEric Cheng (void) snprintf(vbuf.vnic_over, sizeof (vbuf.vnic_over), 4087*da14cebeSEric Cheng "%s", devname); 4088*da14cebeSEric Cheng (void) snprintf(vbuf.vnic_speed, 4089*da14cebeSEric Cheng sizeof (vbuf.vnic_speed), "%u", 4090*da14cebeSEric Cheng (uint_t)((get_ifspeed(vnic_name, B_TRUE)) 4091*da14cebeSEric Cheng / 1000000ull)); 4092*da14cebeSEric Cheng 4093*da14cebeSEric Cheng switch (vnic->va_mac_addr_type) { 4094*da14cebeSEric Cheng case VNIC_MAC_ADDR_TYPE_FIXED: 4095*da14cebeSEric Cheng case VNIC_MAC_ADDR_TYPE_PRIMARY: 4096*da14cebeSEric Cheng (void) snprintf(vbuf.vnic_macaddrtype, 4097*da14cebeSEric Cheng sizeof (vbuf.vnic_macaddrtype), 4098*da14cebeSEric Cheng gettext("fixed")); 4099*da14cebeSEric Cheng break; 4100*da14cebeSEric Cheng case VNIC_MAC_ADDR_TYPE_RANDOM: 4101*da14cebeSEric Cheng (void) snprintf(vbuf.vnic_macaddrtype, 4102*da14cebeSEric Cheng sizeof (vbuf.vnic_macaddrtype), 4103*da14cebeSEric Cheng gettext("random")); 4104*da14cebeSEric Cheng break; 4105*da14cebeSEric Cheng case VNIC_MAC_ADDR_TYPE_FACTORY: 4106*da14cebeSEric Cheng (void) snprintf(vbuf.vnic_macaddrtype, 4107*da14cebeSEric Cheng sizeof (vbuf.vnic_macaddrtype), 4108*da14cebeSEric Cheng gettext("factory, slot %d"), 4109*da14cebeSEric Cheng vnic->va_mac_slot); 4110*da14cebeSEric Cheng break; 4111*da14cebeSEric Cheng } 4112*da14cebeSEric Cheng 4113*da14cebeSEric Cheng if (strlen(vbuf.vnic_macaddrtype) > 0) { 4114*da14cebeSEric Cheng (void) snprintf(vbuf.vnic_macaddr, 4115*da14cebeSEric Cheng sizeof (vbuf.vnic_macaddr), "%s", 4116*da14cebeSEric Cheng dladm_aggr_macaddr2str(vnic->va_mac_addr, 4117*da14cebeSEric Cheng mstr)); 4118*da14cebeSEric Cheng } 4119*da14cebeSEric Cheng 4120*da14cebeSEric Cheng (void) snprintf(vbuf.vnic_vid, sizeof (vbuf.vnic_vid), 4121*da14cebeSEric Cheng "%d", vnic->va_vid); 4122*da14cebeSEric Cheng } 4123*da14cebeSEric Cheng 4124*da14cebeSEric Cheng if (!state->vs_parseable && !state->vs_printheader) { 4125*da14cebeSEric Cheng print_header(&state->vs_print); 4126*da14cebeSEric Cheng state->vs_printheader = B_TRUE; 4127*da14cebeSEric Cheng } 4128*da14cebeSEric Cheng 4129*da14cebeSEric Cheng dladm_print_output(&state->vs_print, state->vs_parseable, 4130*da14cebeSEric Cheng dladm_print_field, (void *)&vbuf); 4131*da14cebeSEric Cheng 4132*da14cebeSEric Cheng return (DLADM_STATUS_OK); 4133*da14cebeSEric Cheng } 4134*da14cebeSEric Cheng } 4135*da14cebeSEric Cheng 4136*da14cebeSEric Cheng static int 4137*da14cebeSEric Cheng show_vnic(datalink_id_t linkid, void *arg) 4138*da14cebeSEric Cheng { 4139*da14cebeSEric Cheng show_vnic_state_t *state = arg; 4140*da14cebeSEric Cheng 4141*da14cebeSEric Cheng state->vs_status = print_vnic(state, linkid); 4142*da14cebeSEric Cheng return (DLADM_WALK_CONTINUE); 4143*da14cebeSEric Cheng } 4144*da14cebeSEric Cheng 4145*da14cebeSEric Cheng static void 4146*da14cebeSEric Cheng do_show_vnic_common(int argc, char *argv[], const char *use, 4147*da14cebeSEric Cheng boolean_t etherstub) 4148*da14cebeSEric Cheng { 4149*da14cebeSEric Cheng int option; 4150*da14cebeSEric Cheng boolean_t s_arg = B_FALSE; 4151*da14cebeSEric Cheng boolean_t i_arg = B_FALSE; 4152*da14cebeSEric Cheng boolean_t l_arg = B_FALSE; 4153*da14cebeSEric Cheng char *endp = NULL; 4154*da14cebeSEric Cheng uint32_t interval = 0, flags = DLADM_OPT_ACTIVE; 4155*da14cebeSEric Cheng datalink_id_t linkid = DATALINK_ALL_LINKID; 4156*da14cebeSEric Cheng datalink_id_t dev_linkid = DATALINK_ALL_LINKID; 4157*da14cebeSEric Cheng show_vnic_state_t state; 4158*da14cebeSEric Cheng dladm_status_t status; 4159*da14cebeSEric Cheng boolean_t o_arg = B_FALSE; 4160*da14cebeSEric Cheng char *fields_str = NULL; 4161*da14cebeSEric Cheng print_field_t **fields; 4162*da14cebeSEric Cheng print_field_t *pf; 4163*da14cebeSEric Cheng int pfmax; 4164*da14cebeSEric Cheng uint_t nfields; 4165*da14cebeSEric Cheng char *all_fields = 4166*da14cebeSEric Cheng "link,over,speed,macaddr,macaddrtype,vid"; 4167*da14cebeSEric Cheng char *all_e_fields = 4168*da14cebeSEric Cheng "link"; 4169*da14cebeSEric Cheng 4170*da14cebeSEric Cheng bzero(&state, sizeof (state)); 4171*da14cebeSEric Cheng opterr = 0; 4172*da14cebeSEric Cheng while ((option = getopt_long(argc, argv, ":pPl:si:o:", lopts, 4173*da14cebeSEric Cheng NULL)) != -1) { 4174*da14cebeSEric Cheng switch (option) { 4175*da14cebeSEric Cheng case 'p': 4176*da14cebeSEric Cheng state.vs_parseable = B_TRUE; 4177*da14cebeSEric Cheng break; 4178*da14cebeSEric Cheng case 'P': 4179*da14cebeSEric Cheng flags = DLADM_OPT_PERSIST; 4180*da14cebeSEric Cheng break; 4181*da14cebeSEric Cheng case 'l': 4182*da14cebeSEric Cheng if (etherstub) 4183*da14cebeSEric Cheng die("option not supported for this command"); 4184*da14cebeSEric Cheng 4185*da14cebeSEric Cheng if (strlcpy(state.vs_link, optarg, MAXLINKNAMELEN) >= 4186*da14cebeSEric Cheng MAXLINKNAMELEN) 4187*da14cebeSEric Cheng die("link name too long"); 4188*da14cebeSEric Cheng 4189*da14cebeSEric Cheng l_arg = B_TRUE; 4190*da14cebeSEric Cheng break; 4191*da14cebeSEric Cheng case 's': 4192*da14cebeSEric Cheng if (s_arg) { 4193*da14cebeSEric Cheng die("the option -s cannot be specified " 4194*da14cebeSEric Cheng "more than once"); 4195*da14cebeSEric Cheng } 4196*da14cebeSEric Cheng s_arg = B_TRUE; 4197*da14cebeSEric Cheng break; 4198*da14cebeSEric Cheng case 'i': 4199*da14cebeSEric Cheng if (i_arg) { 4200*da14cebeSEric Cheng die("the option -i cannot be specified " 4201*da14cebeSEric Cheng "more than once"); 4202*da14cebeSEric Cheng } 4203*da14cebeSEric Cheng i_arg = B_TRUE; 4204*da14cebeSEric Cheng interval = (int)strtol(optarg, &endp, 10); 4205*da14cebeSEric Cheng if (errno != 0 || interval == 0 || *endp != '\0') 4206*da14cebeSEric Cheng die("invalid interval value '%s'", optarg); 4207*da14cebeSEric Cheng break; 4208*da14cebeSEric Cheng case 'o': 4209*da14cebeSEric Cheng o_arg = B_TRUE; 4210*da14cebeSEric Cheng fields_str = optarg; 4211*da14cebeSEric Cheng break; 4212*da14cebeSEric Cheng default: 4213*da14cebeSEric Cheng die_opterr(optopt, option, use); 4214*da14cebeSEric Cheng } 4215*da14cebeSEric Cheng } 4216*da14cebeSEric Cheng 4217*da14cebeSEric Cheng if (i_arg && !s_arg) 4218*da14cebeSEric Cheng die("the option -i can be used only with -s"); 4219*da14cebeSEric Cheng 4220*da14cebeSEric Cheng /* get vnic ID (optional last argument) */ 4221*da14cebeSEric Cheng if (optind == (argc - 1)) { 4222*da14cebeSEric Cheng status = dladm_name2info(argv[optind], &linkid, NULL, 4223*da14cebeSEric Cheng NULL, NULL); 4224*da14cebeSEric Cheng if (status != DLADM_STATUS_OK) { 4225*da14cebeSEric Cheng die_dlerr(status, "invalid vnic name '%s'", 4226*da14cebeSEric Cheng argv[optind]); 4227*da14cebeSEric Cheng } 4228*da14cebeSEric Cheng (void) strlcpy(state.vs_vnic, argv[optind], MAXLINKNAMELEN); 4229*da14cebeSEric Cheng } else if (optind != argc) { 4230*da14cebeSEric Cheng usage(); 4231*da14cebeSEric Cheng } 4232*da14cebeSEric Cheng 4233*da14cebeSEric Cheng if (l_arg) { 4234*da14cebeSEric Cheng status = dladm_name2info(state.vs_link, &dev_linkid, NULL, 4235*da14cebeSEric Cheng NULL, NULL); 4236*da14cebeSEric Cheng if (status != DLADM_STATUS_OK) { 4237*da14cebeSEric Cheng die_dlerr(status, "invalid link name '%s'", 4238*da14cebeSEric Cheng state.vs_link); 4239*da14cebeSEric Cheng } 4240*da14cebeSEric Cheng } 4241*da14cebeSEric Cheng 4242*da14cebeSEric Cheng state.vs_vnic_id = linkid; 4243*da14cebeSEric Cheng state.vs_link_id = dev_linkid; 4244*da14cebeSEric Cheng state.vs_etherstub = etherstub; 4245*da14cebeSEric Cheng state.vs_found = B_FALSE; 4246*da14cebeSEric Cheng state.vs_flags = flags; 4247*da14cebeSEric Cheng 4248*da14cebeSEric Cheng if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) { 4249*da14cebeSEric Cheng if (etherstub) 4250*da14cebeSEric Cheng fields_str = all_e_fields; 4251*da14cebeSEric Cheng else 4252*da14cebeSEric Cheng fields_str = all_fields; 4253*da14cebeSEric Cheng } 4254*da14cebeSEric Cheng 4255*da14cebeSEric Cheng pf = vnic_fields; 4256*da14cebeSEric Cheng pfmax = VNIC_MAX_FIELDS; 4257*da14cebeSEric Cheng 4258*da14cebeSEric Cheng fields = parse_output_fields(fields_str, pf, pfmax, CMD_TYPE_ANY, 4259*da14cebeSEric Cheng &nfields); 4260*da14cebeSEric Cheng 4261*da14cebeSEric Cheng if (fields == NULL) { 4262*da14cebeSEric Cheng die("invalid field(s) specified"); 4263*da14cebeSEric Cheng return; 4264*da14cebeSEric Cheng } 4265*da14cebeSEric Cheng 4266*da14cebeSEric Cheng state.vs_print.ps_fields = fields; 4267*da14cebeSEric Cheng state.vs_print.ps_nfields = nfields; 4268*da14cebeSEric Cheng 4269*da14cebeSEric Cheng if (s_arg) { 4270*da14cebeSEric Cheng /* Display vnic statistics */ 4271*da14cebeSEric Cheng vnic_stats(&state, interval); 4272*da14cebeSEric Cheng return; 4273*da14cebeSEric Cheng } 4274*da14cebeSEric Cheng 4275*da14cebeSEric Cheng /* Display vnic information */ 4276*da14cebeSEric Cheng state.vs_donefirst = B_FALSE; 4277*da14cebeSEric Cheng 4278*da14cebeSEric Cheng if (linkid == DATALINK_ALL_LINKID) { 4279*da14cebeSEric Cheng (void) dladm_walk_datalink_id(show_vnic, &state, 4280*da14cebeSEric Cheng DATALINK_CLASS_VNIC | DATALINK_CLASS_ETHERSTUB, 4281*da14cebeSEric Cheng DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE); 4282*da14cebeSEric Cheng } else { 4283*da14cebeSEric Cheng (void) show_vnic(linkid, &state); 4284*da14cebeSEric Cheng if (state.vs_status != DLADM_STATUS_OK) { 4285*da14cebeSEric Cheng die_dlerr(state.vs_status, "failed to show vnic '%s'", 4286*da14cebeSEric Cheng state.vs_vnic); 4287*da14cebeSEric Cheng } 4288*da14cebeSEric Cheng } 4289*da14cebeSEric Cheng } 4290*da14cebeSEric Cheng 4291*da14cebeSEric Cheng static void 4292*da14cebeSEric Cheng do_show_vnic(int argc, char *argv[], const char *use) 4293*da14cebeSEric Cheng { 4294*da14cebeSEric Cheng do_show_vnic_common(argc, argv, use, B_FALSE); 4295*da14cebeSEric Cheng } 4296*da14cebeSEric Cheng 4297*da14cebeSEric Cheng static void 4298*da14cebeSEric Cheng do_create_etherstub(int argc, char *argv[], const char *use) 4299*da14cebeSEric Cheng { 4300*da14cebeSEric Cheng uint32_t flags; 4301*da14cebeSEric Cheng char *altroot = NULL; 4302*da14cebeSEric Cheng char option; 4303*da14cebeSEric Cheng dladm_status_t status; 4304*da14cebeSEric Cheng char name[MAXLINKNAMELEN]; 4305*da14cebeSEric Cheng uchar_t mac_addr[ETHERADDRL]; 4306*da14cebeSEric Cheng 4307*da14cebeSEric Cheng name[0] = '\0'; 4308*da14cebeSEric Cheng bzero(mac_addr, sizeof (mac_addr)); 4309*da14cebeSEric Cheng flags = DLADM_OPT_ANCHOR | DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST; 4310*da14cebeSEric Cheng 4311*da14cebeSEric Cheng opterr = 0; 4312*da14cebeSEric Cheng while ((option = getopt_long(argc, argv, "tR:", 4313*da14cebeSEric Cheng etherstub_lopts, NULL)) != -1) { 4314*da14cebeSEric Cheng switch (option) { 4315*da14cebeSEric Cheng case 't': 4316*da14cebeSEric Cheng flags &= ~DLADM_OPT_PERSIST; 4317*da14cebeSEric Cheng break; 4318*da14cebeSEric Cheng case 'R': 4319*da14cebeSEric Cheng altroot = optarg; 4320*da14cebeSEric Cheng break; 4321*da14cebeSEric Cheng default: 4322*da14cebeSEric Cheng die_opterr(optopt, option, use); 4323*da14cebeSEric Cheng } 4324*da14cebeSEric Cheng } 4325*da14cebeSEric Cheng 4326*da14cebeSEric Cheng /* the etherstub id is the required operand */ 4327*da14cebeSEric Cheng if (optind != (argc - 1)) 4328*da14cebeSEric Cheng usage(); 4329*da14cebeSEric Cheng 4330*da14cebeSEric Cheng if (strlcpy(name, argv[optind], MAXLINKNAMELEN) >= MAXLINKNAMELEN) 4331*da14cebeSEric Cheng die("link name too long '%s'", argv[optind]); 4332*da14cebeSEric Cheng 4333*da14cebeSEric Cheng if (!dladm_valid_linkname(name)) 4334*da14cebeSEric Cheng die("invalid link name '%s'", argv[optind]); 4335*da14cebeSEric Cheng 4336*da14cebeSEric Cheng if (altroot != NULL) 4337*da14cebeSEric Cheng altroot_cmd(altroot, argc, argv); 4338*da14cebeSEric Cheng 4339*da14cebeSEric Cheng status = dladm_vnic_create(name, DATALINK_INVALID_LINKID, 4340*da14cebeSEric Cheng VNIC_MAC_ADDR_TYPE_AUTO, mac_addr, ETHERADDRL, NULL, 0, 0, NULL, 4341*da14cebeSEric Cheng NULL, flags); 4342*da14cebeSEric Cheng if (status != DLADM_STATUS_OK) 4343*da14cebeSEric Cheng die_dlerr(status, "etherstub creation failed"); 4344*da14cebeSEric Cheng 4345*da14cebeSEric Cheng 4346*da14cebeSEric Cheng } 4347*da14cebeSEric Cheng 4348*da14cebeSEric Cheng static void 4349*da14cebeSEric Cheng do_delete_etherstub(int argc, char *argv[], const char *use) 4350*da14cebeSEric Cheng { 4351*da14cebeSEric Cheng do_delete_vnic_common(argc, argv, use, B_TRUE); 4352*da14cebeSEric Cheng } 4353*da14cebeSEric Cheng 4354*da14cebeSEric Cheng /* ARGSUSED */ 4355*da14cebeSEric Cheng static void 4356*da14cebeSEric Cheng do_show_etherstub(int argc, char *argv[], const char *use) 4357*da14cebeSEric Cheng { 4358*da14cebeSEric Cheng do_show_vnic_common(argc, argv, use, B_TRUE); 4359*da14cebeSEric Cheng } 4360*da14cebeSEric Cheng 4361*da14cebeSEric Cheng static void 43626be03d0bSVasumathi Sundaram - Sun Microsystems link_stats(datalink_id_t linkid, uint_t interval, char *fields_str, 43636be03d0bSVasumathi Sundaram - Sun Microsystems show_state_t *state) 4364d62bc4baSyz147064 { 43656be03d0bSVasumathi Sundaram - Sun Microsystems print_field_t **fields; 43666be03d0bSVasumathi Sundaram - Sun Microsystems uint_t nfields; 436733343a97Smeem 43686be03d0bSVasumathi Sundaram - Sun Microsystems fields = parse_output_fields(fields_str, devs_fields, DEVS_MAX_FIELDS, 43696be03d0bSVasumathi Sundaram - Sun Microsystems CMD_TYPE_ANY, &nfields); 43706be03d0bSVasumathi Sundaram - Sun Microsystems if (fields == NULL) { 43716be03d0bSVasumathi Sundaram - Sun Microsystems die("invalid field(s) specified"); 43726be03d0bSVasumathi Sundaram - Sun Microsystems return; 43736be03d0bSVasumathi Sundaram - Sun Microsystems } 43746be03d0bSVasumathi Sundaram - Sun Microsystems 43756be03d0bSVasumathi Sundaram - Sun Microsystems state->ls_print.ps_fields = fields; 43766be03d0bSVasumathi Sundaram - Sun Microsystems state->ls_print.ps_nfields = nfields; 43777c478bd9Sstevel@tonic-gate 43787c478bd9Sstevel@tonic-gate /* 43797c478bd9Sstevel@tonic-gate * If an interval is specified, continuously show the stats 43807c478bd9Sstevel@tonic-gate * only for the first MAC port. 43817c478bd9Sstevel@tonic-gate */ 43826be03d0bSVasumathi Sundaram - Sun Microsystems state->ls_firstonly = (interval != 0); 43837c478bd9Sstevel@tonic-gate 43846be03d0bSVasumathi Sundaram - Sun Microsystems if (!state->ls_parseable) 43856be03d0bSVasumathi Sundaram - Sun Microsystems print_header(&state->ls_print); 43867c478bd9Sstevel@tonic-gate for (;;) { 43876be03d0bSVasumathi Sundaram - Sun Microsystems state->ls_donefirst = B_FALSE; 4388d62bc4baSyz147064 if (linkid == DATALINK_ALL_LINKID) { 43896be03d0bSVasumathi Sundaram - Sun Microsystems (void) dladm_walk_datalink_id(show_link_stats, state, 4390d62bc4baSyz147064 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, 4391d62bc4baSyz147064 DLADM_OPT_ACTIVE); 4392d62bc4baSyz147064 } else { 43936be03d0bSVasumathi Sundaram - Sun Microsystems (void) show_link_stats(linkid, state); 4394d62bc4baSyz147064 } 43957c478bd9Sstevel@tonic-gate 43967c478bd9Sstevel@tonic-gate if (interval == 0) 43977c478bd9Sstevel@tonic-gate break; 43987c478bd9Sstevel@tonic-gate 43997c478bd9Sstevel@tonic-gate (void) sleep(interval); 44007c478bd9Sstevel@tonic-gate } 44017c478bd9Sstevel@tonic-gate } 44027c478bd9Sstevel@tonic-gate 44037c478bd9Sstevel@tonic-gate static void 4404d62bc4baSyz147064 aggr_stats(datalink_id_t linkid, show_grp_state_t *state, uint_t interval) 44057c478bd9Sstevel@tonic-gate { 44067c478bd9Sstevel@tonic-gate /* 44077c478bd9Sstevel@tonic-gate * If an interval is specified, continuously show the stats 44087c478bd9Sstevel@tonic-gate * only for the first group. 44097c478bd9Sstevel@tonic-gate */ 4410d62bc4baSyz147064 state->gs_firstonly = (interval != 0); 44117c478bd9Sstevel@tonic-gate 44127c478bd9Sstevel@tonic-gate for (;;) { 4413d62bc4baSyz147064 state->gs_donefirst = B_FALSE; 4414d62bc4baSyz147064 if (linkid == DATALINK_ALL_LINKID) 4415d62bc4baSyz147064 (void) dladm_walk_datalink_id(show_aggr, state, 4416d62bc4baSyz147064 DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, 4417d62bc4baSyz147064 DLADM_OPT_ACTIVE); 4418d62bc4baSyz147064 else 4419d62bc4baSyz147064 (void) show_aggr(linkid, state); 44207c478bd9Sstevel@tonic-gate 44217c478bd9Sstevel@tonic-gate if (interval == 0) 44227c478bd9Sstevel@tonic-gate break; 44237c478bd9Sstevel@tonic-gate 44247c478bd9Sstevel@tonic-gate (void) sleep(interval); 44257c478bd9Sstevel@tonic-gate } 44267c478bd9Sstevel@tonic-gate } 44277c478bd9Sstevel@tonic-gate 4428*da14cebeSEric Cheng /* ARGSUSED */ 44297c478bd9Sstevel@tonic-gate static void 4430*da14cebeSEric Cheng vnic_stats(show_vnic_state_t *sp, uint32_t interval) 44317c478bd9Sstevel@tonic-gate { 4432*da14cebeSEric Cheng show_vnic_state_t state; 4433*da14cebeSEric Cheng boolean_t specific_link, specific_dev; 44347c478bd9Sstevel@tonic-gate 4435*da14cebeSEric Cheng /* Display vnic statistics */ 4436*da14cebeSEric Cheng dump_vnics_head(sp->vs_link); 4437e7801d59Ssowmini 4438*da14cebeSEric Cheng bzero(&state, sizeof (state)); 4439*da14cebeSEric Cheng state.vs_stats = B_TRUE; 4440*da14cebeSEric Cheng state.vs_vnic_id = sp->vs_vnic_id; 4441*da14cebeSEric Cheng state.vs_link_id = sp->vs_link_id; 44427c478bd9Sstevel@tonic-gate 44437c478bd9Sstevel@tonic-gate /* 4444*da14cebeSEric Cheng * If an interval is specified, and a vnic ID is not specified, 4445*da14cebeSEric Cheng * continuously show the stats only for the first vnic. 44467c478bd9Sstevel@tonic-gate */ 4447*da14cebeSEric Cheng specific_link = (sp->vs_vnic_id != DATALINK_ALL_LINKID); 4448*da14cebeSEric Cheng specific_dev = (sp->vs_link_id != DATALINK_ALL_LINKID); 44497c478bd9Sstevel@tonic-gate 44507c478bd9Sstevel@tonic-gate for (;;) { 4451*da14cebeSEric Cheng /* Get stats for each vnic */ 4452*da14cebeSEric Cheng state.vs_found = B_FALSE; 4453*da14cebeSEric Cheng state.vs_donefirst = B_FALSE; 4454*da14cebeSEric Cheng state.vs_printstats = B_FALSE; 4455*da14cebeSEric Cheng state.vs_flags = DLADM_OPT_ACTIVE; 44567c478bd9Sstevel@tonic-gate 4457*da14cebeSEric Cheng if (!specific_link) { 4458*da14cebeSEric Cheng (void) dladm_walk_datalink_id(show_vnic, &state, 4459*da14cebeSEric Cheng DATALINK_CLASS_VNIC, DATALINK_ANY_MEDIATYPE, 4460*da14cebeSEric Cheng DLADM_OPT_ACTIVE); 4461*da14cebeSEric Cheng } else { 4462*da14cebeSEric Cheng (void) show_vnic(sp->vs_vnic_id, &state); 4463*da14cebeSEric Cheng if (state.vs_status != DLADM_STATUS_OK) { 4464*da14cebeSEric Cheng die_dlerr(state.vs_status, 4465*da14cebeSEric Cheng "failed to show vnic '%s'", sp->vs_vnic); 4466*da14cebeSEric Cheng } 4467*da14cebeSEric Cheng } 44687c478bd9Sstevel@tonic-gate 4469*da14cebeSEric Cheng if (specific_link && !state.vs_found) 4470*da14cebeSEric Cheng die("non-existent vnic '%s'", sp->vs_vnic); 4471*da14cebeSEric Cheng if (specific_dev && !state.vs_found) 4472*da14cebeSEric Cheng die("device %s has no vnics", sp->vs_link); 4473*da14cebeSEric Cheng 4474*da14cebeSEric Cheng /* Show totals */ 4475*da14cebeSEric Cheng if ((specific_link | specific_dev) && !interval) { 4476*da14cebeSEric Cheng (void) printf("Total"); 4477*da14cebeSEric Cheng (void) printf("\t%-10llu", 4478*da14cebeSEric Cheng state.vs_totalstats.ipackets); 4479*da14cebeSEric Cheng (void) printf("%-12llu", 4480*da14cebeSEric Cheng state.vs_totalstats.rbytes); 4481*da14cebeSEric Cheng (void) printf("%-10llu", 4482*da14cebeSEric Cheng state.vs_totalstats.opackets); 4483*da14cebeSEric Cheng (void) printf("%-12llu\n", 4484*da14cebeSEric Cheng state.vs_totalstats.obytes); 4485*da14cebeSEric Cheng } 4486*da14cebeSEric Cheng 4487*da14cebeSEric Cheng /* Show stats for each vnic */ 4488*da14cebeSEric Cheng state.vs_donefirst = B_FALSE; 4489*da14cebeSEric Cheng state.vs_printstats = B_TRUE; 4490*da14cebeSEric Cheng 4491*da14cebeSEric Cheng if (!specific_link) { 4492*da14cebeSEric Cheng (void) dladm_walk_datalink_id(show_vnic, &state, 4493*da14cebeSEric Cheng DATALINK_CLASS_VNIC, DATALINK_ANY_MEDIATYPE, 4494*da14cebeSEric Cheng DLADM_OPT_ACTIVE); 4495*da14cebeSEric Cheng } else { 4496*da14cebeSEric Cheng (void) show_vnic(sp->vs_vnic_id, &state); 4497*da14cebeSEric Cheng if (state.vs_status != DLADM_STATUS_OK) { 4498*da14cebeSEric Cheng die_dlerr(state.vs_status, 4499*da14cebeSEric Cheng "failed to show vnic '%s'", sp->vs_vnic); 4500*da14cebeSEric Cheng } 4501*da14cebeSEric Cheng } 45027c478bd9Sstevel@tonic-gate 45037c478bd9Sstevel@tonic-gate if (interval == 0) 45047c478bd9Sstevel@tonic-gate break; 45057c478bd9Sstevel@tonic-gate 45067c478bd9Sstevel@tonic-gate (void) sleep(interval); 45077c478bd9Sstevel@tonic-gate } 45087c478bd9Sstevel@tonic-gate } 45097c478bd9Sstevel@tonic-gate 45107c478bd9Sstevel@tonic-gate static void 4511*da14cebeSEric Cheng get_mac_stats(const char *dev, pktsum_t *stats) 45127c478bd9Sstevel@tonic-gate { 45137c478bd9Sstevel@tonic-gate kstat_ctl_t *kcp; 45147c478bd9Sstevel@tonic-gate kstat_t *ksp; 4515*da14cebeSEric Cheng char module[DLPI_LINKNAME_MAX]; 4516*da14cebeSEric Cheng uint_t instance; 4517*da14cebeSEric Cheng 4518*da14cebeSEric Cheng 4519*da14cebeSEric Cheng bzero(stats, sizeof (*stats)); 4520*da14cebeSEric Cheng 4521*da14cebeSEric Cheng if (dlpi_parselink(dev, module, &instance) != DLPI_SUCCESS) 4522*da14cebeSEric Cheng return; 45237c478bd9Sstevel@tonic-gate 45247c478bd9Sstevel@tonic-gate if ((kcp = kstat_open()) == NULL) { 452533343a97Smeem warn("kstat open operation failed"); 45267c478bd9Sstevel@tonic-gate return; 45277c478bd9Sstevel@tonic-gate } 45287c478bd9Sstevel@tonic-gate 4529*da14cebeSEric Cheng ksp = dladm_kstat_lookup(kcp, module, instance, "mac", NULL); 4530*da14cebeSEric Cheng if (ksp != NULL) 4531*da14cebeSEric Cheng dladm_get_stats(kcp, ksp, stats); 4532*da14cebeSEric Cheng 45337c478bd9Sstevel@tonic-gate (void) kstat_close(kcp); 45347c478bd9Sstevel@tonic-gate 45357c478bd9Sstevel@tonic-gate } 45367c478bd9Sstevel@tonic-gate 45377c478bd9Sstevel@tonic-gate static void 45387c478bd9Sstevel@tonic-gate get_link_stats(const char *link, pktsum_t *stats) 45397c478bd9Sstevel@tonic-gate { 4540*da14cebeSEric Cheng kstat_ctl_t *kcp; 4541*da14cebeSEric Cheng kstat_t *ksp; 4542*da14cebeSEric Cheng 45437c478bd9Sstevel@tonic-gate bzero(stats, sizeof (*stats)); 4544*da14cebeSEric Cheng 4545*da14cebeSEric Cheng if ((kcp = kstat_open()) == NULL) { 4546*da14cebeSEric Cheng warn("kstat_open operation failed"); 4547*da14cebeSEric Cheng return; 4548*da14cebeSEric Cheng } 4549*da14cebeSEric Cheng 4550*da14cebeSEric Cheng ksp = dladm_kstat_lookup(kcp, "link", 0, link, NULL); 4551*da14cebeSEric Cheng 4552*da14cebeSEric Cheng if (ksp != NULL) 4553*da14cebeSEric Cheng dladm_get_stats(kcp, ksp, stats); 4554*da14cebeSEric Cheng 4555*da14cebeSEric Cheng (void) kstat_close(kcp); 45567c478bd9Sstevel@tonic-gate } 45577c478bd9Sstevel@tonic-gate 4558ba2e4443Sseb static int 4559d62bc4baSyz147064 query_kstat(char *module, int instance, const char *name, const char *stat, 4560d62bc4baSyz147064 uint8_t type, void *val) 45617c478bd9Sstevel@tonic-gate { 45627c478bd9Sstevel@tonic-gate kstat_ctl_t *kcp; 45637c478bd9Sstevel@tonic-gate kstat_t *ksp; 45647c478bd9Sstevel@tonic-gate 45657c478bd9Sstevel@tonic-gate if ((kcp = kstat_open()) == NULL) { 456633343a97Smeem warn("kstat open operation failed"); 4567ba2e4443Sseb return (-1); 45687c478bd9Sstevel@tonic-gate } 45697c478bd9Sstevel@tonic-gate 4570d62bc4baSyz147064 if ((ksp = kstat_lookup(kcp, module, instance, (char *)name)) == NULL) { 45717c478bd9Sstevel@tonic-gate /* 45727c478bd9Sstevel@tonic-gate * The kstat query could fail if the underlying MAC 45737c478bd9Sstevel@tonic-gate * driver was already detached. 45747c478bd9Sstevel@tonic-gate */ 45757c478bd9Sstevel@tonic-gate goto bail; 45767c478bd9Sstevel@tonic-gate } 45777c478bd9Sstevel@tonic-gate 45787c478bd9Sstevel@tonic-gate if (kstat_read(kcp, ksp, NULL) == -1) { 457933343a97Smeem warn("kstat read failed"); 45807c478bd9Sstevel@tonic-gate goto bail; 45817c478bd9Sstevel@tonic-gate } 45827c478bd9Sstevel@tonic-gate 4583e7801d59Ssowmini if (dladm_kstat_value(ksp, stat, type, val) < 0) 45847c478bd9Sstevel@tonic-gate goto bail; 4585ba2e4443Sseb 4586ba2e4443Sseb (void) kstat_close(kcp); 4587ba2e4443Sseb return (0); 45887c478bd9Sstevel@tonic-gate 45897c478bd9Sstevel@tonic-gate bail: 45907c478bd9Sstevel@tonic-gate (void) kstat_close(kcp); 4591ba2e4443Sseb return (-1); 4592ba2e4443Sseb } 4593ba2e4443Sseb 4594d62bc4baSyz147064 static int 4595d62bc4baSyz147064 get_one_kstat(const char *name, const char *stat, uint8_t type, 4596d62bc4baSyz147064 void *val, boolean_t islink) 4597d62bc4baSyz147064 { 4598d62bc4baSyz147064 char module[DLPI_LINKNAME_MAX]; 4599d62bc4baSyz147064 uint_t instance; 4600d62bc4baSyz147064 4601d62bc4baSyz147064 if (islink) { 4602d62bc4baSyz147064 return (query_kstat("link", 0, name, stat, type, val)); 4603d62bc4baSyz147064 } else { 4604d62bc4baSyz147064 if (dlpi_parselink(name, module, &instance) != DLPI_SUCCESS) 4605d62bc4baSyz147064 return (-1); 4606d62bc4baSyz147064 4607d62bc4baSyz147064 return (query_kstat(module, instance, "mac", stat, type, val)); 4608d62bc4baSyz147064 } 4609d62bc4baSyz147064 } 4610d62bc4baSyz147064 4611ba2e4443Sseb static uint64_t 4612d62bc4baSyz147064 get_ifspeed(const char *name, boolean_t islink) 4613ba2e4443Sseb { 4614ba2e4443Sseb uint64_t ifspeed = 0; 4615ba2e4443Sseb 4616d62bc4baSyz147064 (void) get_one_kstat(name, "ifspeed", KSTAT_DATA_UINT64, 4617d62bc4baSyz147064 &ifspeed, islink); 4618d62bc4baSyz147064 46197c478bd9Sstevel@tonic-gate return (ifspeed); 46207c478bd9Sstevel@tonic-gate } 46217c478bd9Sstevel@tonic-gate 4622f595a68aSyz147064 static const char * 4623d62bc4baSyz147064 get_linkstate(const char *name, boolean_t islink, char *buf) 46247c478bd9Sstevel@tonic-gate { 4625d62bc4baSyz147064 link_state_t linkstate; 46267c478bd9Sstevel@tonic-gate 4627d62bc4baSyz147064 if (get_one_kstat(name, "link_state", KSTAT_DATA_UINT32, 4628d62bc4baSyz147064 &linkstate, islink) != 0) { 4629*da14cebeSEric Cheng (void) strlcpy(buf, "?", DLADM_STRSIZE); 46303a62633bSyz147064 return (buf); 46317c478bd9Sstevel@tonic-gate } 4632d62bc4baSyz147064 return (dladm_linkstate2str(linkstate, buf)); 46337c478bd9Sstevel@tonic-gate } 46347c478bd9Sstevel@tonic-gate 4635f595a68aSyz147064 static const char * 4636d62bc4baSyz147064 get_linkduplex(const char *name, boolean_t islink, char *buf) 46377c478bd9Sstevel@tonic-gate { 4638d62bc4baSyz147064 link_duplex_t linkduplex; 46397c478bd9Sstevel@tonic-gate 4640d62bc4baSyz147064 if (get_one_kstat(name, "link_duplex", KSTAT_DATA_UINT32, 4641d62bc4baSyz147064 &linkduplex, islink) != 0) { 46423a62633bSyz147064 (void) strlcpy(buf, "unknown", DLADM_STRSIZE); 46433a62633bSyz147064 return (buf); 46447c478bd9Sstevel@tonic-gate } 46457c478bd9Sstevel@tonic-gate 4646d62bc4baSyz147064 return (dladm_linkduplex2str(linkduplex, buf)); 46477c478bd9Sstevel@tonic-gate } 46480ba2cbe9Sxc151355 46490ba2cbe9Sxc151355 typedef struct { 46500ba2cbe9Sxc151355 char *s_buf; 46510ba2cbe9Sxc151355 char **s_fields; /* array of pointer to the fields in s_buf */ 46520ba2cbe9Sxc151355 uint_t s_nfields; /* the number of fields in s_buf */ 46530ba2cbe9Sxc151355 } split_t; 46540ba2cbe9Sxc151355 46550ba2cbe9Sxc151355 /* 46560ba2cbe9Sxc151355 * Free the split_t structure pointed to by `sp'. 46570ba2cbe9Sxc151355 */ 46580ba2cbe9Sxc151355 static void 46590ba2cbe9Sxc151355 splitfree(split_t *sp) 46600ba2cbe9Sxc151355 { 46610ba2cbe9Sxc151355 free(sp->s_buf); 46620ba2cbe9Sxc151355 free(sp->s_fields); 46630ba2cbe9Sxc151355 free(sp); 46640ba2cbe9Sxc151355 } 46650ba2cbe9Sxc151355 46660ba2cbe9Sxc151355 /* 46670ba2cbe9Sxc151355 * Split `str' into at most `maxfields' fields, each field at most `maxlen' in 46680ba2cbe9Sxc151355 * length. Return a pointer to a split_t containing the split fields, or NULL 46690ba2cbe9Sxc151355 * on failure. 46700ba2cbe9Sxc151355 */ 46710ba2cbe9Sxc151355 static split_t * 46720ba2cbe9Sxc151355 split(const char *str, uint_t maxfields, uint_t maxlen) 46730ba2cbe9Sxc151355 { 46740ba2cbe9Sxc151355 char *field, *token, *lasts = NULL; 46750ba2cbe9Sxc151355 split_t *sp; 46760ba2cbe9Sxc151355 46770ba2cbe9Sxc151355 if (*str == '\0' || maxfields == 0 || maxlen == 0) 46780ba2cbe9Sxc151355 return (NULL); 46790ba2cbe9Sxc151355 46800ba2cbe9Sxc151355 sp = calloc(sizeof (split_t), 1); 46810ba2cbe9Sxc151355 if (sp == NULL) 46820ba2cbe9Sxc151355 return (NULL); 46830ba2cbe9Sxc151355 46840ba2cbe9Sxc151355 sp->s_buf = strdup(str); 46850ba2cbe9Sxc151355 sp->s_fields = malloc(sizeof (char *) * maxfields); 46860ba2cbe9Sxc151355 if (sp->s_buf == NULL || sp->s_fields == NULL) 46870ba2cbe9Sxc151355 goto fail; 46880ba2cbe9Sxc151355 46890ba2cbe9Sxc151355 token = sp->s_buf; 46900ba2cbe9Sxc151355 while ((field = strtok_r(token, ",", &lasts)) != NULL) { 46910ba2cbe9Sxc151355 if (sp->s_nfields == maxfields || strlen(field) > maxlen) 46920ba2cbe9Sxc151355 goto fail; 46930ba2cbe9Sxc151355 token = NULL; 46940ba2cbe9Sxc151355 sp->s_fields[sp->s_nfields++] = field; 46950ba2cbe9Sxc151355 } 46960ba2cbe9Sxc151355 return (sp); 46970ba2cbe9Sxc151355 fail: 46980ba2cbe9Sxc151355 splitfree(sp); 46990ba2cbe9Sxc151355 return (NULL); 47000ba2cbe9Sxc151355 } 47010ba2cbe9Sxc151355 47020ba2cbe9Sxc151355 static int 4703e7801d59Ssowmini parse_wifi_fields(char *str, print_field_t ***fields, uint_t *countp, 47040ba2cbe9Sxc151355 uint_t cmdtype) 47050ba2cbe9Sxc151355 { 47060ba2cbe9Sxc151355 47070ba2cbe9Sxc151355 if (cmdtype == WIFI_CMD_SCAN) { 47080ba2cbe9Sxc151355 if (str == NULL) 47090ba2cbe9Sxc151355 str = def_scan_wifi_fields; 47100ba2cbe9Sxc151355 if (strcasecmp(str, "all") == 0) 47110ba2cbe9Sxc151355 str = all_scan_wifi_fields; 47120ba2cbe9Sxc151355 } else if (cmdtype == WIFI_CMD_SHOW) { 47130ba2cbe9Sxc151355 if (str == NULL) 47140ba2cbe9Sxc151355 str = def_show_wifi_fields; 47150ba2cbe9Sxc151355 if (strcasecmp(str, "all") == 0) 47160ba2cbe9Sxc151355 str = all_show_wifi_fields; 47170ba2cbe9Sxc151355 } else { 47180ba2cbe9Sxc151355 return (-1); 47190ba2cbe9Sxc151355 } 4720e7801d59Ssowmini *fields = parse_output_fields(str, wifi_fields, WIFI_MAX_FIELDS, 4721e7801d59Ssowmini cmdtype, countp); 4722e7801d59Ssowmini if (*fields != NULL) 4723e7801d59Ssowmini return (0); 47240ba2cbe9Sxc151355 return (-1); 4725e7801d59Ssowmini } 4726e7801d59Ssowmini static print_field_t ** 4727e7801d59Ssowmini parse_output_fields(char *str, print_field_t *template, int max_fields, 4728e7801d59Ssowmini uint_t cmdtype, uint_t *countp) 4729e7801d59Ssowmini { 4730e7801d59Ssowmini split_t *sp; 4731e7801d59Ssowmini boolean_t good_match = B_FALSE; 4732e7801d59Ssowmini uint_t i, j; 4733e7801d59Ssowmini print_field_t **pf = NULL; 47340ba2cbe9Sxc151355 4735e7801d59Ssowmini sp = split(str, max_fields, MAX_FIELD_LEN); 4736e7801d59Ssowmini 4737e7801d59Ssowmini if (sp == NULL) 4738e7801d59Ssowmini return (NULL); 4739e7801d59Ssowmini 4740e7801d59Ssowmini pf = malloc(sp->s_nfields * sizeof (print_field_t *)); 4741e7801d59Ssowmini if (pf == NULL) 47420ba2cbe9Sxc151355 goto fail; 47430ba2cbe9Sxc151355 47440ba2cbe9Sxc151355 for (i = 0; i < sp->s_nfields; i++) { 4745e7801d59Ssowmini for (j = 0; j < max_fields; j++) { 47460ba2cbe9Sxc151355 if (strcasecmp(sp->s_fields[i], 4747e7801d59Ssowmini template[j].pf_name) == 0) { 4748e7801d59Ssowmini good_match = template[j]. pf_cmdtype & cmdtype; 47490ba2cbe9Sxc151355 break; 47500ba2cbe9Sxc151355 } 47510ba2cbe9Sxc151355 } 47520ba2cbe9Sxc151355 if (!good_match) 47530ba2cbe9Sxc151355 goto fail; 47540ba2cbe9Sxc151355 47550ba2cbe9Sxc151355 good_match = B_FALSE; 4756e7801d59Ssowmini pf[i] = &template[j]; 47570ba2cbe9Sxc151355 } 47580ba2cbe9Sxc151355 *countp = i; 47590ba2cbe9Sxc151355 splitfree(sp); 4760e7801d59Ssowmini return (pf); 47610ba2cbe9Sxc151355 fail: 4762e7801d59Ssowmini free(pf); 47630ba2cbe9Sxc151355 splitfree(sp); 4764e7801d59Ssowmini return (NULL); 47650ba2cbe9Sxc151355 } 47660ba2cbe9Sxc151355 47670ba2cbe9Sxc151355 typedef struct print_wifi_state { 4768d62bc4baSyz147064 char *ws_link; 47690ba2cbe9Sxc151355 boolean_t ws_parseable; 47700ba2cbe9Sxc151355 boolean_t ws_header; 4771e7801d59Ssowmini print_state_t ws_print_state; 47720ba2cbe9Sxc151355 } print_wifi_state_t; 47730ba2cbe9Sxc151355 4774e7801d59Ssowmini typedef struct wlan_scan_args_s { 4775e7801d59Ssowmini print_wifi_state_t *ws_state; 4776e7801d59Ssowmini void *ws_attr; 4777e7801d59Ssowmini } wlan_scan_args_t; 47780ba2cbe9Sxc151355 47790ba2cbe9Sxc151355 static void 4780e7801d59Ssowmini print_field(print_state_t *statep, print_field_t *pfp, const char *value, 4781e7801d59Ssowmini boolean_t parseable) 47820ba2cbe9Sxc151355 { 4783e7801d59Ssowmini uint_t width = pfp->pf_width; 47846be03d0bSVasumathi Sundaram - Sun Microsystems uint_t valwidth; 47850ba2cbe9Sxc151355 uint_t compress; 47860ba2cbe9Sxc151355 47870d365605Sschuster /* 47880d365605Sschuster * Parsable fields are separated by ':'. If such a field contains 47890d365605Sschuster * a ':' or '\', this character is prefixed by a '\'. 47900d365605Sschuster */ 4791e7801d59Ssowmini if (parseable) { 47920d365605Sschuster char c; 47930d365605Sschuster 47940d365605Sschuster if (statep->ps_nfields == 1) { 47950d365605Sschuster (void) printf("%s", value); 47960d365605Sschuster return; 47970d365605Sschuster } 47980d365605Sschuster while ((c = *value++) != '\0') { 47990d365605Sschuster if (c == ':' || c == '\\') 48000d365605Sschuster (void) putchar('\\'); 48010d365605Sschuster (void) putchar(c); 48020d365605Sschuster } 48030d365605Sschuster if (!statep->ps_lastfield) 48040d365605Sschuster (void) putchar(':'); 48050d365605Sschuster return; 48060ba2cbe9Sxc151355 } else { 48070ba2cbe9Sxc151355 if (value[0] == '\0') 4808e7801d59Ssowmini value = STR_UNDEF_VAL; 4809e7801d59Ssowmini if (statep->ps_lastfield) { 48100ba2cbe9Sxc151355 (void) printf("%s", value); 48116be03d0bSVasumathi Sundaram - Sun Microsystems statep->ps_overflow = 0; 48120ba2cbe9Sxc151355 return; 48130ba2cbe9Sxc151355 } 48140ba2cbe9Sxc151355 48156be03d0bSVasumathi Sundaram - Sun Microsystems valwidth = strlen(value); 48160ba2cbe9Sxc151355 if (valwidth > width) { 4817e7801d59Ssowmini statep->ps_overflow += valwidth - width; 4818e7801d59Ssowmini } else if (valwidth < width && statep->ps_overflow > 0) { 4819e7801d59Ssowmini compress = min(statep->ps_overflow, width - valwidth); 4820e7801d59Ssowmini statep->ps_overflow -= compress; 48210ba2cbe9Sxc151355 width -= compress; 48220ba2cbe9Sxc151355 } 48230ba2cbe9Sxc151355 (void) printf("%-*s", width, value); 48240ba2cbe9Sxc151355 } 48250ba2cbe9Sxc151355 4826e7801d59Ssowmini if (!statep->ps_lastfield) 48270ba2cbe9Sxc151355 (void) putchar(' '); 48280ba2cbe9Sxc151355 } 48290ba2cbe9Sxc151355 4830e7801d59Ssowmini static char * 4831e7801d59Ssowmini print_wlan_attr(print_field_t *wfp, void *warg) 48320ba2cbe9Sxc151355 { 4833e7801d59Ssowmini static char buf[DLADM_STRSIZE]; 4834e7801d59Ssowmini wlan_scan_args_t *w = warg; 4835e7801d59Ssowmini print_wifi_state_t *statep = w->ws_state; 4836e7801d59Ssowmini dladm_wlan_attr_t *attrp = w->ws_attr; 48370ba2cbe9Sxc151355 4838e7801d59Ssowmini if (wfp->pf_index == 0) { 4839e7801d59Ssowmini return ((char *)statep->ws_link); 48400ba2cbe9Sxc151355 } 48410ba2cbe9Sxc151355 4842e7801d59Ssowmini if ((wfp->pf_index & attrp->wa_valid) == 0) { 4843e7801d59Ssowmini return (""); 48440ba2cbe9Sxc151355 } 48450ba2cbe9Sxc151355 4846e7801d59Ssowmini switch (wfp->pf_index) { 4847f595a68aSyz147064 case DLADM_WLAN_ATTR_ESSID: 4848e7801d59Ssowmini (void) dladm_wlan_essid2str(&attrp->wa_essid, buf); 48490ba2cbe9Sxc151355 break; 4850f595a68aSyz147064 case DLADM_WLAN_ATTR_BSSID: 4851e7801d59Ssowmini (void) dladm_wlan_bssid2str(&attrp->wa_bssid, buf); 48520ba2cbe9Sxc151355 break; 4853f595a68aSyz147064 case DLADM_WLAN_ATTR_SECMODE: 4854e7801d59Ssowmini (void) dladm_wlan_secmode2str(&attrp->wa_secmode, buf); 48550ba2cbe9Sxc151355 break; 4856f595a68aSyz147064 case DLADM_WLAN_ATTR_STRENGTH: 4857e7801d59Ssowmini (void) dladm_wlan_strength2str(&attrp->wa_strength, buf); 48580ba2cbe9Sxc151355 break; 4859f595a68aSyz147064 case DLADM_WLAN_ATTR_MODE: 4860e7801d59Ssowmini (void) dladm_wlan_mode2str(&attrp->wa_mode, buf); 48610ba2cbe9Sxc151355 break; 4862f595a68aSyz147064 case DLADM_WLAN_ATTR_SPEED: 4863e7801d59Ssowmini (void) dladm_wlan_speed2str(&attrp->wa_speed, buf); 48640ba2cbe9Sxc151355 (void) strlcat(buf, "Mb", sizeof (buf)); 48650ba2cbe9Sxc151355 break; 4866f595a68aSyz147064 case DLADM_WLAN_ATTR_AUTH: 4867e7801d59Ssowmini (void) dladm_wlan_auth2str(&attrp->wa_auth, buf); 48680ba2cbe9Sxc151355 break; 4869f595a68aSyz147064 case DLADM_WLAN_ATTR_BSSTYPE: 4870e7801d59Ssowmini (void) dladm_wlan_bsstype2str(&attrp->wa_bsstype, buf); 48710ba2cbe9Sxc151355 break; 48720ba2cbe9Sxc151355 } 48730ba2cbe9Sxc151355 4874e7801d59Ssowmini return (buf); 48750ba2cbe9Sxc151355 } 48760ba2cbe9Sxc151355 48770ba2cbe9Sxc151355 static boolean_t 4878f595a68aSyz147064 print_scan_results(void *arg, dladm_wlan_attr_t *attrp) 48790ba2cbe9Sxc151355 { 48800ba2cbe9Sxc151355 print_wifi_state_t *statep = arg; 4881e7801d59Ssowmini wlan_scan_args_t warg; 48820ba2cbe9Sxc151355 48830ba2cbe9Sxc151355 if (statep->ws_header) { 48840ba2cbe9Sxc151355 statep->ws_header = B_FALSE; 48850ba2cbe9Sxc151355 if (!statep->ws_parseable) 4886e7801d59Ssowmini print_header(&statep->ws_print_state); 48870ba2cbe9Sxc151355 } 48880ba2cbe9Sxc151355 4889e7801d59Ssowmini statep->ws_print_state.ps_overflow = 0; 4890e7801d59Ssowmini bzero(&warg, sizeof (warg)); 4891e7801d59Ssowmini warg.ws_state = statep; 4892e7801d59Ssowmini warg.ws_attr = attrp; 4893e7801d59Ssowmini dladm_print_output(&statep->ws_print_state, statep->ws_parseable, 4894e7801d59Ssowmini print_wlan_attr, &warg); 48950ba2cbe9Sxc151355 return (B_TRUE); 48960ba2cbe9Sxc151355 } 48970ba2cbe9Sxc151355 4898d62bc4baSyz147064 static int 4899d62bc4baSyz147064 scan_wifi(datalink_id_t linkid, void *arg) 49000ba2cbe9Sxc151355 { 49010ba2cbe9Sxc151355 print_wifi_state_t *statep = arg; 4902f595a68aSyz147064 dladm_status_t status; 4903d62bc4baSyz147064 char link[MAXLINKNAMELEN]; 4904d62bc4baSyz147064 4905e7801d59Ssowmini if ((status = dladm_datalink_id2info(linkid, NULL, NULL, NULL, link, 4906e7801d59Ssowmini sizeof (link))) != DLADM_STATUS_OK) { 4907d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 4908d62bc4baSyz147064 } 49090ba2cbe9Sxc151355 49100ba2cbe9Sxc151355 statep->ws_link = link; 4911d62bc4baSyz147064 status = dladm_wlan_scan(linkid, statep, print_scan_results); 4912f595a68aSyz147064 if (status != DLADM_STATUS_OK) 4913d62bc4baSyz147064 die_dlerr(status, "cannot scan link '%s'", statep->ws_link); 491433343a97Smeem 4915d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 49160ba2cbe9Sxc151355 } 49170ba2cbe9Sxc151355 4918e7801d59Ssowmini static char * 4919e7801d59Ssowmini print_link_attr(print_field_t *wfp, void *warg) 49200ba2cbe9Sxc151355 { 4921e7801d59Ssowmini static char buf[DLADM_STRSIZE]; 4922e7801d59Ssowmini char *ptr; 4923e7801d59Ssowmini wlan_scan_args_t *w = warg, w1; 4924e7801d59Ssowmini print_wifi_state_t *statep = w->ws_state; 4925e7801d59Ssowmini dladm_wlan_linkattr_t *attrp = w->ws_attr; 49260ba2cbe9Sxc151355 4927e7801d59Ssowmini if (strcmp(wfp->pf_name, "status") == 0) { 4928e7801d59Ssowmini if ((wfp->pf_index & attrp->la_valid) != 0) 4929e7801d59Ssowmini (void) dladm_wlan_linkstatus2str( 4930e7801d59Ssowmini &attrp->la_status, buf); 4931e7801d59Ssowmini return (buf); 49320ba2cbe9Sxc151355 } 4933e7801d59Ssowmini statep->ws_print_state.ps_overflow = 0; 4934e7801d59Ssowmini bzero(&w1, sizeof (w1)); 4935e7801d59Ssowmini w1.ws_state = statep; 4936e7801d59Ssowmini w1.ws_attr = &attrp->la_wlan_attr; 4937e7801d59Ssowmini ptr = print_wlan_attr(wfp, &w1); 4938e7801d59Ssowmini return (ptr); 49390ba2cbe9Sxc151355 } 49400ba2cbe9Sxc151355 4941d62bc4baSyz147064 static int 4942d62bc4baSyz147064 show_wifi(datalink_id_t linkid, void *arg) 49430ba2cbe9Sxc151355 { 49440ba2cbe9Sxc151355 print_wifi_state_t *statep = arg; 4945f595a68aSyz147064 dladm_wlan_linkattr_t attr; 4946f595a68aSyz147064 dladm_status_t status; 4947d62bc4baSyz147064 char link[MAXLINKNAMELEN]; 4948e7801d59Ssowmini wlan_scan_args_t warg; 49490ba2cbe9Sxc151355 4950e7801d59Ssowmini if ((status = dladm_datalink_id2info(linkid, NULL, NULL, NULL, link, 4951e7801d59Ssowmini sizeof (link))) != DLADM_STATUS_OK) { 4952d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 4953d62bc4baSyz147064 } 4954d62bc4baSyz147064 49555f5c9f54SAnurag S. Maskey /* dladm_wlan_get_linkattr() memsets attr with 0 */ 4956d62bc4baSyz147064 status = dladm_wlan_get_linkattr(linkid, &attr); 4957f595a68aSyz147064 if (status != DLADM_STATUS_OK) 4958d62bc4baSyz147064 die_dlerr(status, "cannot get link attributes for %s", link); 4959d62bc4baSyz147064 4960d62bc4baSyz147064 statep->ws_link = link; 49610ba2cbe9Sxc151355 49620ba2cbe9Sxc151355 if (statep->ws_header) { 49630ba2cbe9Sxc151355 statep->ws_header = B_FALSE; 49640ba2cbe9Sxc151355 if (!statep->ws_parseable) 4965e7801d59Ssowmini print_header(&statep->ws_print_state); 49660ba2cbe9Sxc151355 } 49670ba2cbe9Sxc151355 4968e7801d59Ssowmini statep->ws_print_state.ps_overflow = 0; 4969e7801d59Ssowmini bzero(&warg, sizeof (warg)); 4970e7801d59Ssowmini warg.ws_state = statep; 4971e7801d59Ssowmini warg.ws_attr = &attr; 4972e7801d59Ssowmini dladm_print_output(&statep->ws_print_state, statep->ws_parseable, 4973e7801d59Ssowmini print_link_attr, &warg); 4974d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 49750ba2cbe9Sxc151355 } 49760ba2cbe9Sxc151355 49770ba2cbe9Sxc151355 static void 49788d5c46e6Sam223141 do_display_wifi(int argc, char **argv, int cmd, const char *use) 49790ba2cbe9Sxc151355 { 49800ba2cbe9Sxc151355 int option; 49810ba2cbe9Sxc151355 char *fields_str = NULL; 4982e7801d59Ssowmini print_field_t **fields; 4983d62bc4baSyz147064 int (*callback)(datalink_id_t, void *); 49840ba2cbe9Sxc151355 uint_t nfields; 49850ba2cbe9Sxc151355 print_wifi_state_t state; 4986d62bc4baSyz147064 datalink_id_t linkid = DATALINK_ALL_LINKID; 4987f595a68aSyz147064 dladm_status_t status; 49880ba2cbe9Sxc151355 49890ba2cbe9Sxc151355 if (cmd == WIFI_CMD_SCAN) 49900ba2cbe9Sxc151355 callback = scan_wifi; 49910ba2cbe9Sxc151355 else if (cmd == WIFI_CMD_SHOW) 49920ba2cbe9Sxc151355 callback = show_wifi; 49930ba2cbe9Sxc151355 else 49940ba2cbe9Sxc151355 return; 49950ba2cbe9Sxc151355 49960ba2cbe9Sxc151355 state.ws_parseable = B_FALSE; 49970ba2cbe9Sxc151355 state.ws_header = B_TRUE; 49980ba2cbe9Sxc151355 opterr = 0; 49990ba2cbe9Sxc151355 while ((option = getopt_long(argc, argv, ":o:p", 50000ba2cbe9Sxc151355 wifi_longopts, NULL)) != -1) { 50010ba2cbe9Sxc151355 switch (option) { 50020ba2cbe9Sxc151355 case 'o': 50030ba2cbe9Sxc151355 fields_str = optarg; 50040ba2cbe9Sxc151355 break; 50050ba2cbe9Sxc151355 case 'p': 50060ba2cbe9Sxc151355 state.ws_parseable = B_TRUE; 50070ba2cbe9Sxc151355 break; 50080ba2cbe9Sxc151355 default: 50098d5c46e6Sam223141 die_opterr(optopt, option, use); 50100ba2cbe9Sxc151355 } 50110ba2cbe9Sxc151355 } 50120ba2cbe9Sxc151355 50130d365605Sschuster if (state.ws_parseable && fields_str == NULL) 50140d365605Sschuster die("-p requires -o"); 50150d365605Sschuster 50160d365605Sschuster if (state.ws_parseable && strcasecmp(fields_str, "all") == 0) 50170d365605Sschuster die("\"-o all\" is invalid with -p"); 50180d365605Sschuster 5019d62bc4baSyz147064 if (optind == (argc - 1)) { 5020d62bc4baSyz147064 if ((status = dladm_name2info(argv[optind], &linkid, NULL, 5021d62bc4baSyz147064 NULL, NULL)) != DLADM_STATUS_OK) { 5022d62bc4baSyz147064 die_dlerr(status, "link %s is not valid", argv[optind]); 5023d62bc4baSyz147064 } 5024d62bc4baSyz147064 } else if (optind != argc) { 50250ba2cbe9Sxc151355 usage(); 5026d62bc4baSyz147064 } 50270ba2cbe9Sxc151355 502833343a97Smeem if (parse_wifi_fields(fields_str, &fields, &nfields, cmd) < 0) 502933343a97Smeem die("invalid field(s) specified"); 503033343a97Smeem 5031e7801d59Ssowmini bzero(&state.ws_print_state, sizeof (state.ws_print_state)); 5032e7801d59Ssowmini state.ws_print_state.ps_fields = fields; 5033e7801d59Ssowmini state.ws_print_state.ps_nfields = nfields; 50340ba2cbe9Sxc151355 5035d62bc4baSyz147064 if (linkid == DATALINK_ALL_LINKID) { 5036d62bc4baSyz147064 (void) dladm_walk_datalink_id(callback, &state, 5037d62bc4baSyz147064 DATALINK_CLASS_PHYS, DL_WIFI, DLADM_OPT_ACTIVE); 50380ba2cbe9Sxc151355 } else { 5039d62bc4baSyz147064 (void) (*callback)(linkid, &state); 50400ba2cbe9Sxc151355 } 50410ba2cbe9Sxc151355 free(fields); 50420ba2cbe9Sxc151355 } 50430ba2cbe9Sxc151355 50440ba2cbe9Sxc151355 static void 50458d5c46e6Sam223141 do_scan_wifi(int argc, char **argv, const char *use) 50460ba2cbe9Sxc151355 { 50478d5c46e6Sam223141 do_display_wifi(argc, argv, WIFI_CMD_SCAN, use); 50480ba2cbe9Sxc151355 } 50490ba2cbe9Sxc151355 50500ba2cbe9Sxc151355 static void 50518d5c46e6Sam223141 do_show_wifi(int argc, char **argv, const char *use) 50520ba2cbe9Sxc151355 { 50538d5c46e6Sam223141 do_display_wifi(argc, argv, WIFI_CMD_SHOW, use); 50540ba2cbe9Sxc151355 } 50550ba2cbe9Sxc151355 50560ba2cbe9Sxc151355 typedef struct wlan_count_attr { 50570ba2cbe9Sxc151355 uint_t wc_count; 5058d62bc4baSyz147064 datalink_id_t wc_linkid; 50590ba2cbe9Sxc151355 } wlan_count_attr_t; 50600ba2cbe9Sxc151355 5061d62bc4baSyz147064 static int 5062d62bc4baSyz147064 do_count_wlan(datalink_id_t linkid, void *arg) 50630ba2cbe9Sxc151355 { 506433343a97Smeem wlan_count_attr_t *cp = arg; 50650ba2cbe9Sxc151355 50660ba2cbe9Sxc151355 if (cp->wc_count == 0) 5067d62bc4baSyz147064 cp->wc_linkid = linkid; 50680ba2cbe9Sxc151355 cp->wc_count++; 5069d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 50700ba2cbe9Sxc151355 } 50710ba2cbe9Sxc151355 50720ba2cbe9Sxc151355 static int 5073a399b765Szf162725 parse_wlan_keys(char *str, dladm_wlan_key_t **keys, uint_t *key_countp) 50740ba2cbe9Sxc151355 { 50750ba2cbe9Sxc151355 uint_t i; 50760ba2cbe9Sxc151355 split_t *sp; 5077a399b765Szf162725 dladm_wlan_key_t *wk; 50780ba2cbe9Sxc151355 5079a399b765Szf162725 sp = split(str, DLADM_WLAN_MAX_WEPKEYS, DLADM_WLAN_MAX_KEYNAME_LEN); 50800ba2cbe9Sxc151355 if (sp == NULL) 50810ba2cbe9Sxc151355 return (-1); 50820ba2cbe9Sxc151355 5083a399b765Szf162725 wk = malloc(sp->s_nfields * sizeof (dladm_wlan_key_t)); 50840ba2cbe9Sxc151355 if (wk == NULL) 50850ba2cbe9Sxc151355 goto fail; 50860ba2cbe9Sxc151355 50870ba2cbe9Sxc151355 for (i = 0; i < sp->s_nfields; i++) { 50880ba2cbe9Sxc151355 char *s; 50890ba2cbe9Sxc151355 dladm_secobj_class_t class; 50900ba2cbe9Sxc151355 dladm_status_t status; 50910ba2cbe9Sxc151355 50920ba2cbe9Sxc151355 (void) strlcpy(wk[i].wk_name, sp->s_fields[i], 5093a399b765Szf162725 DLADM_WLAN_MAX_KEYNAME_LEN); 50940ba2cbe9Sxc151355 50950ba2cbe9Sxc151355 wk[i].wk_idx = 1; 50960ba2cbe9Sxc151355 if ((s = strrchr(wk[i].wk_name, ':')) != NULL) { 50970ba2cbe9Sxc151355 if (s[1] == '\0' || s[2] != '\0' || !isdigit(s[1])) 50980ba2cbe9Sxc151355 goto fail; 50990ba2cbe9Sxc151355 51000ba2cbe9Sxc151355 wk[i].wk_idx = (uint_t)(s[1] - '0'); 51010ba2cbe9Sxc151355 *s = '\0'; 51020ba2cbe9Sxc151355 } 5103a399b765Szf162725 wk[i].wk_len = DLADM_WLAN_MAX_KEY_LEN; 51040ba2cbe9Sxc151355 51050ba2cbe9Sxc151355 status = dladm_get_secobj(wk[i].wk_name, &class, 51060ba2cbe9Sxc151355 wk[i].wk_val, &wk[i].wk_len, 0); 51070ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 51080ba2cbe9Sxc151355 if (status == DLADM_STATUS_NOTFOUND) { 51090ba2cbe9Sxc151355 status = dladm_get_secobj(wk[i].wk_name, 51100ba2cbe9Sxc151355 &class, wk[i].wk_val, &wk[i].wk_len, 51110ba2cbe9Sxc151355 DLADM_OPT_PERSIST); 51120ba2cbe9Sxc151355 } 51130ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) 51140ba2cbe9Sxc151355 goto fail; 51150ba2cbe9Sxc151355 } 5116a399b765Szf162725 wk[i].wk_class = class; 51170ba2cbe9Sxc151355 } 51180ba2cbe9Sxc151355 *keys = wk; 51190ba2cbe9Sxc151355 *key_countp = i; 51200ba2cbe9Sxc151355 splitfree(sp); 51210ba2cbe9Sxc151355 return (0); 51220ba2cbe9Sxc151355 fail: 51230ba2cbe9Sxc151355 free(wk); 51240ba2cbe9Sxc151355 splitfree(sp); 51250ba2cbe9Sxc151355 return (-1); 51260ba2cbe9Sxc151355 } 51270ba2cbe9Sxc151355 51280ba2cbe9Sxc151355 static void 51298d5c46e6Sam223141 do_connect_wifi(int argc, char **argv, const char *use) 51300ba2cbe9Sxc151355 { 51310ba2cbe9Sxc151355 int option; 5132f595a68aSyz147064 dladm_wlan_attr_t attr, *attrp; 5133f595a68aSyz147064 dladm_status_t status = DLADM_STATUS_OK; 5134f595a68aSyz147064 int timeout = DLADM_WLAN_CONNECT_TIMEOUT_DEFAULT; 5135d62bc4baSyz147064 datalink_id_t linkid = DATALINK_ALL_LINKID; 5136a399b765Szf162725 dladm_wlan_key_t *keys = NULL; 51370ba2cbe9Sxc151355 uint_t key_count = 0; 51380ba2cbe9Sxc151355 uint_t flags = 0; 5139f595a68aSyz147064 dladm_wlan_secmode_t keysecmode = DLADM_WLAN_SECMODE_NONE; 5140a399b765Szf162725 char buf[DLADM_STRSIZE]; 51410ba2cbe9Sxc151355 51420ba2cbe9Sxc151355 opterr = 0; 51430ba2cbe9Sxc151355 (void) memset(&attr, 0, sizeof (attr)); 51440ba2cbe9Sxc151355 while ((option = getopt_long(argc, argv, ":e:i:a:m:b:s:k:T:c", 51450ba2cbe9Sxc151355 wifi_longopts, NULL)) != -1) { 51460ba2cbe9Sxc151355 switch (option) { 51470ba2cbe9Sxc151355 case 'e': 5148f595a68aSyz147064 status = dladm_wlan_str2essid(optarg, &attr.wa_essid); 5149f595a68aSyz147064 if (status != DLADM_STATUS_OK) 515033343a97Smeem die("invalid ESSID '%s'", optarg); 515133343a97Smeem 5152f595a68aSyz147064 attr.wa_valid |= DLADM_WLAN_ATTR_ESSID; 51530ba2cbe9Sxc151355 /* 51540ba2cbe9Sxc151355 * Try to connect without doing a scan. 51550ba2cbe9Sxc151355 */ 5156f595a68aSyz147064 flags |= DLADM_WLAN_CONNECT_NOSCAN; 51570ba2cbe9Sxc151355 break; 51580ba2cbe9Sxc151355 case 'i': 5159f595a68aSyz147064 status = dladm_wlan_str2bssid(optarg, &attr.wa_bssid); 5160f595a68aSyz147064 if (status != DLADM_STATUS_OK) 516133343a97Smeem die("invalid BSSID %s", optarg); 516233343a97Smeem 5163f595a68aSyz147064 attr.wa_valid |= DLADM_WLAN_ATTR_BSSID; 51640ba2cbe9Sxc151355 break; 51650ba2cbe9Sxc151355 case 'a': 5166f595a68aSyz147064 status = dladm_wlan_str2auth(optarg, &attr.wa_auth); 5167f595a68aSyz147064 if (status != DLADM_STATUS_OK) 516833343a97Smeem die("invalid authentication mode '%s'", optarg); 516933343a97Smeem 5170f595a68aSyz147064 attr.wa_valid |= DLADM_WLAN_ATTR_AUTH; 51710ba2cbe9Sxc151355 break; 51720ba2cbe9Sxc151355 case 'm': 5173f595a68aSyz147064 status = dladm_wlan_str2mode(optarg, &attr.wa_mode); 5174f595a68aSyz147064 if (status != DLADM_STATUS_OK) 517533343a97Smeem die("invalid mode '%s'", optarg); 517633343a97Smeem 5177f595a68aSyz147064 attr.wa_valid |= DLADM_WLAN_ATTR_MODE; 51780ba2cbe9Sxc151355 break; 51790ba2cbe9Sxc151355 case 'b': 5180f595a68aSyz147064 if ((status = dladm_wlan_str2bsstype(optarg, 5181f595a68aSyz147064 &attr.wa_bsstype)) != DLADM_STATUS_OK) { 518233343a97Smeem die("invalid bsstype '%s'", optarg); 5183f595a68aSyz147064 } 518433343a97Smeem 5185f595a68aSyz147064 attr.wa_valid |= DLADM_WLAN_ATTR_BSSTYPE; 51860ba2cbe9Sxc151355 break; 51870ba2cbe9Sxc151355 case 's': 5188f595a68aSyz147064 if ((status = dladm_wlan_str2secmode(optarg, 5189f595a68aSyz147064 &attr.wa_secmode)) != DLADM_STATUS_OK) { 519033343a97Smeem die("invalid security mode '%s'", optarg); 5191f595a68aSyz147064 } 519233343a97Smeem 5193f595a68aSyz147064 attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE; 51940ba2cbe9Sxc151355 break; 51950ba2cbe9Sxc151355 case 'k': 5196a399b765Szf162725 if (parse_wlan_keys(optarg, &keys, &key_count) < 0) 519733343a97Smeem die("invalid key(s) '%s'", optarg); 519833343a97Smeem 5199a399b765Szf162725 if (keys[0].wk_class == DLADM_SECOBJ_CLASS_WEP) 5200f595a68aSyz147064 keysecmode = DLADM_WLAN_SECMODE_WEP; 5201a399b765Szf162725 else 5202a399b765Szf162725 keysecmode = DLADM_WLAN_SECMODE_WPA; 52030ba2cbe9Sxc151355 break; 52040ba2cbe9Sxc151355 case 'T': 52050ba2cbe9Sxc151355 if (strcasecmp(optarg, "forever") == 0) { 52060ba2cbe9Sxc151355 timeout = -1; 52070ba2cbe9Sxc151355 break; 52080ba2cbe9Sxc151355 } 520933343a97Smeem if (!str2int(optarg, &timeout) || timeout < 0) 521033343a97Smeem die("invalid timeout value '%s'", optarg); 52110ba2cbe9Sxc151355 break; 52120ba2cbe9Sxc151355 case 'c': 5213f595a68aSyz147064 flags |= DLADM_WLAN_CONNECT_CREATEIBSS; 5214a399b765Szf162725 flags |= DLADM_WLAN_CONNECT_CREATEIBSS; 52150ba2cbe9Sxc151355 break; 52160ba2cbe9Sxc151355 default: 52178d5c46e6Sam223141 die_opterr(optopt, option, use); 52180ba2cbe9Sxc151355 break; 52190ba2cbe9Sxc151355 } 52200ba2cbe9Sxc151355 } 52210ba2cbe9Sxc151355 5222f595a68aSyz147064 if (keysecmode == DLADM_WLAN_SECMODE_NONE) { 5223a399b765Szf162725 if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0) { 5224a399b765Szf162725 die("key required for security mode '%s'", 5225a399b765Szf162725 dladm_wlan_secmode2str(&attr.wa_secmode, buf)); 5226a399b765Szf162725 } 52270ba2cbe9Sxc151355 } else { 5228f595a68aSyz147064 if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0 && 522933343a97Smeem attr.wa_secmode != keysecmode) 523033343a97Smeem die("incompatible -s and -k options"); 5231f595a68aSyz147064 attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE; 5232a399b765Szf162725 attr.wa_secmode = keysecmode; 5233a399b765Szf162725 } 52340ba2cbe9Sxc151355 5235d62bc4baSyz147064 if (optind == (argc - 1)) { 5236d62bc4baSyz147064 if ((status = dladm_name2info(argv[optind], &linkid, NULL, 5237d62bc4baSyz147064 NULL, NULL)) != DLADM_STATUS_OK) { 5238d62bc4baSyz147064 die_dlerr(status, "link %s is not valid", argv[optind]); 5239d62bc4baSyz147064 } 5240d62bc4baSyz147064 } else if (optind != argc) { 52410ba2cbe9Sxc151355 usage(); 5242d62bc4baSyz147064 } 52430ba2cbe9Sxc151355 5244d62bc4baSyz147064 if (linkid == DATALINK_ALL_LINKID) { 52450ba2cbe9Sxc151355 wlan_count_attr_t wcattr; 52460ba2cbe9Sxc151355 5247d62bc4baSyz147064 wcattr.wc_linkid = DATALINK_INVALID_LINKID; 52480ba2cbe9Sxc151355 wcattr.wc_count = 0; 5249d62bc4baSyz147064 (void) dladm_walk_datalink_id(do_count_wlan, &wcattr, 5250d62bc4baSyz147064 DATALINK_CLASS_PHYS, DL_WIFI, DLADM_OPT_ACTIVE); 52510ba2cbe9Sxc151355 if (wcattr.wc_count == 0) { 525233343a97Smeem die("no wifi links are available"); 52530ba2cbe9Sxc151355 } else if (wcattr.wc_count > 1) { 525433343a97Smeem die("link name is required when more than one wifi " 525533343a97Smeem "link is available"); 52560ba2cbe9Sxc151355 } 5257d62bc4baSyz147064 linkid = wcattr.wc_linkid; 52580ba2cbe9Sxc151355 } 52590ba2cbe9Sxc151355 attrp = (attr.wa_valid == 0) ? NULL : &attr; 526033343a97Smeem again: 5261d62bc4baSyz147064 if ((status = dladm_wlan_connect(linkid, attrp, timeout, keys, 5262f595a68aSyz147064 key_count, flags)) != DLADM_STATUS_OK) { 5263f595a68aSyz147064 if ((flags & DLADM_WLAN_CONNECT_NOSCAN) != 0) { 52640ba2cbe9Sxc151355 /* 526533343a97Smeem * Try again with scanning and filtering. 52660ba2cbe9Sxc151355 */ 5267f595a68aSyz147064 flags &= ~DLADM_WLAN_CONNECT_NOSCAN; 526833343a97Smeem goto again; 52690ba2cbe9Sxc151355 } 527033343a97Smeem 5271f595a68aSyz147064 if (status == DLADM_STATUS_NOTFOUND) { 52720ba2cbe9Sxc151355 if (attr.wa_valid == 0) { 527333343a97Smeem die("no wifi networks are available"); 52740ba2cbe9Sxc151355 } else { 527533343a97Smeem die("no wifi networks with the specified " 527633343a97Smeem "criteria are available"); 52770ba2cbe9Sxc151355 } 52780ba2cbe9Sxc151355 } 5279d62bc4baSyz147064 die_dlerr(status, "cannot connect"); 52800ba2cbe9Sxc151355 } 52810ba2cbe9Sxc151355 free(keys); 52820ba2cbe9Sxc151355 } 52830ba2cbe9Sxc151355 52840ba2cbe9Sxc151355 /* ARGSUSED */ 5285d62bc4baSyz147064 static int 5286d62bc4baSyz147064 do_all_disconnect_wifi(datalink_id_t linkid, void *arg) 52870ba2cbe9Sxc151355 { 5288f595a68aSyz147064 dladm_status_t status; 52890ba2cbe9Sxc151355 5290d62bc4baSyz147064 status = dladm_wlan_disconnect(linkid); 5291f595a68aSyz147064 if (status != DLADM_STATUS_OK) 5292d62bc4baSyz147064 warn_dlerr(status, "cannot disconnect link"); 529333343a97Smeem 5294d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 52950ba2cbe9Sxc151355 } 52960ba2cbe9Sxc151355 52970ba2cbe9Sxc151355 static void 52988d5c46e6Sam223141 do_disconnect_wifi(int argc, char **argv, const char *use) 52990ba2cbe9Sxc151355 { 53000ba2cbe9Sxc151355 int option; 5301d62bc4baSyz147064 datalink_id_t linkid = DATALINK_ALL_LINKID; 53020ba2cbe9Sxc151355 boolean_t all_links = B_FALSE; 5303f595a68aSyz147064 dladm_status_t status; 53040ba2cbe9Sxc151355 wlan_count_attr_t wcattr; 53050ba2cbe9Sxc151355 53060ba2cbe9Sxc151355 opterr = 0; 53070ba2cbe9Sxc151355 while ((option = getopt_long(argc, argv, ":a", 53080ba2cbe9Sxc151355 wifi_longopts, NULL)) != -1) { 53090ba2cbe9Sxc151355 switch (option) { 53100ba2cbe9Sxc151355 case 'a': 53110ba2cbe9Sxc151355 all_links = B_TRUE; 53120ba2cbe9Sxc151355 break; 53130ba2cbe9Sxc151355 default: 53148d5c46e6Sam223141 die_opterr(optopt, option, use); 53150ba2cbe9Sxc151355 break; 53160ba2cbe9Sxc151355 } 53170ba2cbe9Sxc151355 } 53180ba2cbe9Sxc151355 5319d62bc4baSyz147064 if (optind == (argc - 1)) { 5320d62bc4baSyz147064 if ((status = dladm_name2info(argv[optind], &linkid, NULL, 5321d62bc4baSyz147064 NULL, NULL)) != DLADM_STATUS_OK) { 5322d62bc4baSyz147064 die_dlerr(status, "link %s is not valid", argv[optind]); 5323d62bc4baSyz147064 } 5324d62bc4baSyz147064 } else if (optind != argc) { 53250ba2cbe9Sxc151355 usage(); 5326d62bc4baSyz147064 } 53270ba2cbe9Sxc151355 5328d62bc4baSyz147064 if (linkid == DATALINK_ALL_LINKID) { 53290ba2cbe9Sxc151355 if (!all_links) { 5330d62bc4baSyz147064 wcattr.wc_linkid = linkid; 53310ba2cbe9Sxc151355 wcattr.wc_count = 0; 5332d62bc4baSyz147064 (void) dladm_walk_datalink_id(do_count_wlan, &wcattr, 5333d62bc4baSyz147064 DATALINK_CLASS_PHYS, DL_WIFI, DLADM_OPT_ACTIVE); 53340ba2cbe9Sxc151355 if (wcattr.wc_count == 0) { 533533343a97Smeem die("no wifi links are available"); 53360ba2cbe9Sxc151355 } else if (wcattr.wc_count > 1) { 533733343a97Smeem die("link name is required when more than " 533833343a97Smeem "one wifi link is available"); 53390ba2cbe9Sxc151355 } 5340d62bc4baSyz147064 linkid = wcattr.wc_linkid; 53410ba2cbe9Sxc151355 } else { 5342d62bc4baSyz147064 (void) dladm_walk_datalink_id(do_all_disconnect_wifi, 5343d62bc4baSyz147064 NULL, DATALINK_CLASS_PHYS, DL_WIFI, 5344d62bc4baSyz147064 DLADM_OPT_ACTIVE); 53450ba2cbe9Sxc151355 return; 53460ba2cbe9Sxc151355 } 53470ba2cbe9Sxc151355 } 5348d62bc4baSyz147064 status = dladm_wlan_disconnect(linkid); 5349f595a68aSyz147064 if (status != DLADM_STATUS_OK) 5350d62bc4baSyz147064 die_dlerr(status, "cannot disconnect"); 53510ba2cbe9Sxc151355 } 53520ba2cbe9Sxc151355 53530ba2cbe9Sxc151355 static void 5354d62bc4baSyz147064 print_linkprop(datalink_id_t linkid, show_linkprop_state_t *statep, 5355e7801d59Ssowmini const char *propname, dladm_prop_type_t type, 5356d62bc4baSyz147064 const char *format, char **pptr) 53570ba2cbe9Sxc151355 { 53580ba2cbe9Sxc151355 int i; 53590ba2cbe9Sxc151355 char *ptr, *lim; 53600ba2cbe9Sxc151355 char buf[DLADM_STRSIZE]; 5361*da14cebeSEric Cheng char *unknown = "--", *notsup = ""; 53620ba2cbe9Sxc151355 char **propvals = statep->ls_propvals; 5363d62bc4baSyz147064 uint_t valcnt = DLADM_MAX_PROP_VALCNT; 53640ba2cbe9Sxc151355 dladm_status_t status; 53650ba2cbe9Sxc151355 5366d62bc4baSyz147064 status = dladm_get_linkprop(linkid, type, propname, propvals, &valcnt); 53670ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 5368f595a68aSyz147064 if (status == DLADM_STATUS_TEMPONLY) { 5369d62bc4baSyz147064 if (type == DLADM_PROP_VAL_MODIFIABLE && 5370d62bc4baSyz147064 statep->ls_persist) { 5371d62bc4baSyz147064 valcnt = 1; 5372d62bc4baSyz147064 propvals = &unknown; 5373d62bc4baSyz147064 } else { 5374f595a68aSyz147064 statep->ls_status = status; 5375e7801d59Ssowmini statep->ls_retstatus = status; 5376f595a68aSyz147064 return; 5377d62bc4baSyz147064 } 5378f595a68aSyz147064 } else if (status == DLADM_STATUS_NOTSUP || 5379f595a68aSyz147064 statep->ls_persist) { 53800ba2cbe9Sxc151355 valcnt = 1; 5381afdda45fSVasumathi Sundaram - Sun Microsystems if (type == DLADM_PROP_VAL_CURRENT || 5382afdda45fSVasumathi Sundaram - Sun Microsystems type == DLADM_PROP_VAL_PERM) 53830ba2cbe9Sxc151355 propvals = &unknown; 53840ba2cbe9Sxc151355 else 53850ba2cbe9Sxc151355 propvals = ¬sup; 5386149b7eb2SSowmini Varadhan } else if (status == DLADM_STATUS_NOTDEFINED) { 5387149b7eb2SSowmini Varadhan propvals = ¬sup; /* STR_UNDEF_VAL */ 53880ba2cbe9Sxc151355 } else { 5389e7801d59Ssowmini if (statep->ls_proplist && 5390e7801d59Ssowmini statep->ls_status == DLADM_STATUS_OK) { 5391f595a68aSyz147064 warn_dlerr(status, 5392f595a68aSyz147064 "cannot get link property '%s' for %s", 5393f595a68aSyz147064 propname, statep->ls_link); 5394d62bc4baSyz147064 } 5395e7801d59Ssowmini statep->ls_status = status; 5396e7801d59Ssowmini statep->ls_retstatus = status; 5397f595a68aSyz147064 return; 53980ba2cbe9Sxc151355 } 53990ba2cbe9Sxc151355 } 54000ba2cbe9Sxc151355 5401e7801d59Ssowmini statep->ls_status = DLADM_STATUS_OK; 5402e7801d59Ssowmini 54030ba2cbe9Sxc151355 ptr = buf; 54040ba2cbe9Sxc151355 lim = buf + DLADM_STRSIZE; 54050ba2cbe9Sxc151355 for (i = 0; i < valcnt; i++) { 54060ba2cbe9Sxc151355 if (propvals[i][0] == '\0' && !statep->ls_parseable) 5407e7801d59Ssowmini ptr += snprintf(ptr, lim - ptr, STR_UNDEF_VAL","); 54080ba2cbe9Sxc151355 else 54090ba2cbe9Sxc151355 ptr += snprintf(ptr, lim - ptr, "%s,", propvals[i]); 54100ba2cbe9Sxc151355 if (ptr >= lim) 54110ba2cbe9Sxc151355 break; 54120ba2cbe9Sxc151355 } 54130ba2cbe9Sxc151355 if (valcnt > 0) 54140ba2cbe9Sxc151355 buf[strlen(buf) - 1] = '\0'; 54150ba2cbe9Sxc151355 54160ba2cbe9Sxc151355 lim = statep->ls_line + MAX_PROP_LINE; 54170ba2cbe9Sxc151355 if (statep->ls_parseable) { 54180ba2cbe9Sxc151355 *pptr += snprintf(*pptr, lim - *pptr, 5419e7801d59Ssowmini "%s", buf); 54200ba2cbe9Sxc151355 } else { 54210ba2cbe9Sxc151355 *pptr += snprintf(*pptr, lim - *pptr, format, buf); 54220ba2cbe9Sxc151355 } 54230ba2cbe9Sxc151355 } 54240ba2cbe9Sxc151355 5425e7801d59Ssowmini static char * 5426e7801d59Ssowmini linkprop_callback(print_field_t *pf, void *ls_arg) 5427e7801d59Ssowmini { 5428e7801d59Ssowmini linkprop_args_t *arg = ls_arg; 5429e7801d59Ssowmini char *propname = arg->ls_propname; 5430e7801d59Ssowmini show_linkprop_state_t *statep = arg->ls_state; 5431e7801d59Ssowmini char *ptr = statep->ls_line; 5432e7801d59Ssowmini char *lim = ptr + MAX_PROP_LINE; 5433e7801d59Ssowmini datalink_id_t linkid = arg->ls_linkid; 5434e7801d59Ssowmini 5435e7801d59Ssowmini switch (pf->pf_index) { 5436e7801d59Ssowmini case LINKPROP_LINK: 5437e7801d59Ssowmini (void) snprintf(ptr, lim - ptr, "%s", statep->ls_link); 5438e7801d59Ssowmini break; 5439e7801d59Ssowmini case LINKPROP_PROPERTY: 5440e7801d59Ssowmini (void) snprintf(ptr, lim - ptr, "%s", propname); 5441e7801d59Ssowmini break; 5442e7801d59Ssowmini case LINKPROP_VALUE: 5443e7801d59Ssowmini print_linkprop(linkid, statep, propname, 5444e7801d59Ssowmini statep->ls_persist ? DLADM_PROP_VAL_PERSISTENT : 5445e7801d59Ssowmini DLADM_PROP_VAL_CURRENT, "%s", &ptr); 5446e7801d59Ssowmini /* 5447e7801d59Ssowmini * If we failed to query the link property, for example, query 5448e7801d59Ssowmini * the persistent value of a non-persistable link property, 5449e7801d59Ssowmini * simply skip the output. 5450e7801d59Ssowmini */ 5451e7801d59Ssowmini if (statep->ls_status != DLADM_STATUS_OK) 5452e7801d59Ssowmini goto skip; 5453e7801d59Ssowmini ptr = statep->ls_line; 5454e7801d59Ssowmini break; 5455afdda45fSVasumathi Sundaram - Sun Microsystems case LINKPROP_PERM: 5456afdda45fSVasumathi Sundaram - Sun Microsystems print_linkprop(linkid, statep, propname, 5457afdda45fSVasumathi Sundaram - Sun Microsystems DLADM_PROP_VAL_PERM, "%s", &ptr); 5458afdda45fSVasumathi Sundaram - Sun Microsystems if (statep->ls_status != DLADM_STATUS_OK) 5459afdda45fSVasumathi Sundaram - Sun Microsystems goto skip; 5460afdda45fSVasumathi Sundaram - Sun Microsystems ptr = statep->ls_line; 5461afdda45fSVasumathi Sundaram - Sun Microsystems break; 5462e7801d59Ssowmini case LINKPROP_DEFAULT: 5463e7801d59Ssowmini print_linkprop(linkid, statep, propname, 5464e7801d59Ssowmini DLADM_PROP_VAL_DEFAULT, "%s", &ptr); 5465e7801d59Ssowmini if (statep->ls_status != DLADM_STATUS_OK) 5466e7801d59Ssowmini goto skip; 5467e7801d59Ssowmini ptr = statep->ls_line; 5468e7801d59Ssowmini break; 5469e7801d59Ssowmini case LINKPROP_POSSIBLE: 5470e7801d59Ssowmini print_linkprop(linkid, statep, propname, 5471e7801d59Ssowmini DLADM_PROP_VAL_MODIFIABLE, "%s ", &ptr); 5472e7801d59Ssowmini if (statep->ls_status != DLADM_STATUS_OK) 5473e7801d59Ssowmini goto skip; 5474e7801d59Ssowmini ptr = statep->ls_line; 5475e7801d59Ssowmini break; 5476e7801d59Ssowmini default: 5477e7801d59Ssowmini die("invalid input"); 5478e7801d59Ssowmini break; 5479e7801d59Ssowmini } 5480e7801d59Ssowmini return (ptr); 5481e7801d59Ssowmini skip: 5482e7801d59Ssowmini if (statep->ls_status != DLADM_STATUS_OK) 5483e7801d59Ssowmini return (NULL); 5484e7801d59Ssowmini else 5485e7801d59Ssowmini return (""); 5486e7801d59Ssowmini } 5487e7801d59Ssowmini 5488bcb5c89dSSowmini Varadhan static boolean_t 5489bcb5c89dSSowmini Varadhan linkprop_is_supported(datalink_id_t linkid, const char *propname, 5490bcb5c89dSSowmini Varadhan show_linkprop_state_t *statep) 5491bcb5c89dSSowmini Varadhan { 5492bcb5c89dSSowmini Varadhan dladm_status_t status; 5493bcb5c89dSSowmini Varadhan uint_t valcnt = DLADM_MAX_PROP_VALCNT; 5494bcb5c89dSSowmini Varadhan 5495bcb5c89dSSowmini Varadhan status = dladm_get_linkprop(linkid, DLADM_PROP_VAL_DEFAULT, 5496bcb5c89dSSowmini Varadhan propname, statep->ls_propvals, &valcnt); 5497bcb5c89dSSowmini Varadhan 5498149b7eb2SSowmini Varadhan if (status == DLADM_STATUS_OK) 5499149b7eb2SSowmini Varadhan return (B_TRUE); 5500149b7eb2SSowmini Varadhan 5501149b7eb2SSowmini Varadhan /* 5502149b7eb2SSowmini Varadhan * A system wide default value is not available for the 5503149b7eb2SSowmini Varadhan * property. Check if current value can be retrieved. 5504149b7eb2SSowmini Varadhan */ 5505149b7eb2SSowmini Varadhan status = dladm_get_linkprop(linkid, DLADM_PROP_VAL_CURRENT, 5506149b7eb2SSowmini Varadhan propname, statep->ls_propvals, &valcnt); 5507149b7eb2SSowmini Varadhan 5508149b7eb2SSowmini Varadhan return (status == DLADM_STATUS_OK); 5509bcb5c89dSSowmini Varadhan } 5510bcb5c89dSSowmini Varadhan 5511d62bc4baSyz147064 static int 5512d62bc4baSyz147064 show_linkprop(datalink_id_t linkid, const char *propname, void *arg) 55130ba2cbe9Sxc151355 { 55140ba2cbe9Sxc151355 show_linkprop_state_t *statep = arg; 5515e7801d59Ssowmini linkprop_args_t ls_arg; 55160ba2cbe9Sxc151355 5517e7801d59Ssowmini bzero(&ls_arg, sizeof (ls_arg)); 5518e7801d59Ssowmini ls_arg.ls_state = statep; 5519e7801d59Ssowmini ls_arg.ls_propname = (char *)propname; 5520e7801d59Ssowmini ls_arg.ls_linkid = linkid; 55210ba2cbe9Sxc151355 55220ba2cbe9Sxc151355 if (statep->ls_header) { 55230ba2cbe9Sxc151355 statep->ls_header = B_FALSE; 55240ba2cbe9Sxc151355 if (!statep->ls_parseable) 5525e7801d59Ssowmini print_header(&statep->ls_print); 55260ba2cbe9Sxc151355 } 5527149b7eb2SSowmini Varadhan if (!statep->ls_parseable && 5528149b7eb2SSowmini Varadhan !linkprop_is_supported(linkid, propname, statep)) 5529bcb5c89dSSowmini Varadhan return (DLADM_WALK_CONTINUE); 5530bcb5c89dSSowmini Varadhan 5531e7801d59Ssowmini dladm_print_output(&statep->ls_print, statep->ls_parseable, 5532e7801d59Ssowmini linkprop_callback, (void *)&ls_arg); 5533e7801d59Ssowmini 5534d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 55350ba2cbe9Sxc151355 } 55360ba2cbe9Sxc151355 55370ba2cbe9Sxc151355 static void 55388d5c46e6Sam223141 do_show_linkprop(int argc, char **argv, const char *use) 55390ba2cbe9Sxc151355 { 5540f4b3ec61Sdh155122 int option; 5541*da14cebeSEric Cheng dladm_arg_list_t *proplist = NULL; 5542d62bc4baSyz147064 datalink_id_t linkid = DATALINK_ALL_LINKID; 55430ba2cbe9Sxc151355 show_linkprop_state_t state; 5544d62bc4baSyz147064 uint32_t flags = DLADM_OPT_ACTIVE; 5545d62bc4baSyz147064 dladm_status_t status; 5546e7801d59Ssowmini char *fields_str = NULL; 5547e7801d59Ssowmini print_field_t **fields; 5548e7801d59Ssowmini uint_t nfields; 55490d365605Sschuster boolean_t o_arg = B_FALSE; 5550e7801d59Ssowmini char *all_fields = 5551afdda45fSVasumathi Sundaram - Sun Microsystems "link,property,perm,value,default,possible"; 5552e7801d59Ssowmini 5553e7801d59Ssowmini fields_str = all_fields; 55540ba2cbe9Sxc151355 55550ba2cbe9Sxc151355 opterr = 0; 55560ba2cbe9Sxc151355 state.ls_propvals = NULL; 55570ba2cbe9Sxc151355 state.ls_line = NULL; 55580ba2cbe9Sxc151355 state.ls_parseable = B_FALSE; 55590ba2cbe9Sxc151355 state.ls_persist = B_FALSE; 55600ba2cbe9Sxc151355 state.ls_header = B_TRUE; 5561e7801d59Ssowmini state.ls_retstatus = DLADM_STATUS_OK; 5562e7801d59Ssowmini while ((option = getopt_long(argc, argv, ":p:cPo:", 55630ba2cbe9Sxc151355 prop_longopts, NULL)) != -1) { 55640ba2cbe9Sxc151355 switch (option) { 55650ba2cbe9Sxc151355 case 'p': 5566*da14cebeSEric Cheng if (dladm_parse_link_props(optarg, &proplist, B_TRUE) 5567*da14cebeSEric Cheng != DLADM_STATUS_OK) 556813994ee8Sxz162242 die("invalid link properties specified"); 55690ba2cbe9Sxc151355 break; 55700ba2cbe9Sxc151355 case 'c': 55710ba2cbe9Sxc151355 state.ls_parseable = B_TRUE; 55720ba2cbe9Sxc151355 break; 55730ba2cbe9Sxc151355 case 'P': 55740ba2cbe9Sxc151355 state.ls_persist = B_TRUE; 5575d62bc4baSyz147064 flags = DLADM_OPT_PERSIST; 55760ba2cbe9Sxc151355 break; 5577e7801d59Ssowmini case 'o': 55780d365605Sschuster o_arg = B_TRUE; 5579e7801d59Ssowmini if (strcasecmp(optarg, "all") == 0) 5580e7801d59Ssowmini fields_str = all_fields; 5581e7801d59Ssowmini else 5582e7801d59Ssowmini fields_str = optarg; 5583e7801d59Ssowmini break; 55840ba2cbe9Sxc151355 default: 55858d5c46e6Sam223141 die_opterr(optopt, option, use); 55860ba2cbe9Sxc151355 break; 55870ba2cbe9Sxc151355 } 55880ba2cbe9Sxc151355 } 55890ba2cbe9Sxc151355 55900d365605Sschuster if (state.ls_parseable && !o_arg) 55910d365605Sschuster die("-c requires -o"); 55920d365605Sschuster 55930d365605Sschuster if (state.ls_parseable && fields_str == all_fields) 55940d365605Sschuster die("\"-o all\" is invalid with -c"); 55950d365605Sschuster 5596d62bc4baSyz147064 if (optind == (argc - 1)) { 5597d62bc4baSyz147064 if ((status = dladm_name2info(argv[optind], &linkid, NULL, 5598d62bc4baSyz147064 NULL, NULL)) != DLADM_STATUS_OK) { 5599d62bc4baSyz147064 die_dlerr(status, "link %s is not valid", argv[optind]); 5600d62bc4baSyz147064 } 5601d62bc4baSyz147064 } else if (optind != argc) { 56020ba2cbe9Sxc151355 usage(); 5603d62bc4baSyz147064 } 56040ba2cbe9Sxc151355 5605e7801d59Ssowmini bzero(&state.ls_print, sizeof (print_state_t)); 5606f4b3ec61Sdh155122 state.ls_proplist = proplist; 5607f595a68aSyz147064 state.ls_status = DLADM_STATUS_OK; 5608f4b3ec61Sdh155122 5609e7801d59Ssowmini fields = parse_output_fields(fields_str, linkprop_fields, 5610e7801d59Ssowmini LINKPROP_MAX_FIELDS, CMD_TYPE_ANY, &nfields); 5611e7801d59Ssowmini 5612e7801d59Ssowmini if (fields == NULL) { 5613e7801d59Ssowmini die("invalid field(s) specified"); 5614e7801d59Ssowmini return; 5615e7801d59Ssowmini } 5616e7801d59Ssowmini 5617e7801d59Ssowmini state.ls_print.ps_fields = fields; 5618e7801d59Ssowmini state.ls_print.ps_nfields = nfields; 5619d62bc4baSyz147064 if (linkid == DATALINK_ALL_LINKID) { 5620d62bc4baSyz147064 (void) dladm_walk_datalink_id(show_linkprop_onelink, &state, 5621d62bc4baSyz147064 DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, flags); 5622f4b3ec61Sdh155122 } else { 5623d62bc4baSyz147064 (void) show_linkprop_onelink(linkid, &state); 5624f4b3ec61Sdh155122 } 5625*da14cebeSEric Cheng dladm_free_props(proplist); 5626f595a68aSyz147064 5627e7801d59Ssowmini if (state.ls_retstatus != DLADM_STATUS_OK) 5628f595a68aSyz147064 exit(EXIT_FAILURE); 5629f4b3ec61Sdh155122 } 5630f4b3ec61Sdh155122 5631d62bc4baSyz147064 static int 5632d62bc4baSyz147064 show_linkprop_onelink(datalink_id_t linkid, void *arg) 5633f4b3ec61Sdh155122 { 5634948f2876Sss150715 int i; 5635f4b3ec61Sdh155122 char *buf; 5636d62bc4baSyz147064 uint32_t flags; 5637*da14cebeSEric Cheng dladm_arg_list_t *proplist = NULL; 5638d62bc4baSyz147064 show_linkprop_state_t *statep = arg; 5639d62bc4baSyz147064 dlpi_handle_t dh = NULL; 5640f4b3ec61Sdh155122 5641d62bc4baSyz147064 statep->ls_status = DLADM_STATUS_OK; 5642d62bc4baSyz147064 5643d62bc4baSyz147064 if (dladm_datalink_id2info(linkid, &flags, NULL, NULL, statep->ls_link, 5644d62bc4baSyz147064 MAXLINKNAMELEN) != DLADM_STATUS_OK) { 5645d62bc4baSyz147064 statep->ls_status = DLADM_STATUS_NOTFOUND; 5646d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 5647d62bc4baSyz147064 } 5648d62bc4baSyz147064 5649d62bc4baSyz147064 if ((statep->ls_persist && !(flags & DLADM_OPT_PERSIST)) || 5650d62bc4baSyz147064 (!statep->ls_persist && !(flags & DLADM_OPT_ACTIVE))) { 5651d62bc4baSyz147064 statep->ls_status = DLADM_STATUS_BADARG; 5652d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 5653d62bc4baSyz147064 } 5654d62bc4baSyz147064 5655f4b3ec61Sdh155122 proplist = statep->ls_proplist; 56560ba2cbe9Sxc151355 56570ba2cbe9Sxc151355 /* 56580ba2cbe9Sxc151355 * When some WiFi links are opened for the first time, their hardware 56590ba2cbe9Sxc151355 * automatically scans for APs and does other slow operations. Thus, 56600ba2cbe9Sxc151355 * if there are no open links, the retrieval of link properties 56610ba2cbe9Sxc151355 * (below) will proceed slowly unless we hold the link open. 5662d62bc4baSyz147064 * 5663d62bc4baSyz147064 * Note that failure of dlpi_open() does not necessarily mean invalid 5664d62bc4baSyz147064 * link properties, because dlpi_open() may fail because of incorrect 5665d62bc4baSyz147064 * autopush configuration. Therefore, we ingore the return value of 5666d62bc4baSyz147064 * dlpi_open(). 56670ba2cbe9Sxc151355 */ 5668d62bc4baSyz147064 if (!statep->ls_persist) 5669d62bc4baSyz147064 (void) dlpi_open(statep->ls_link, &dh, 0); 56700ba2cbe9Sxc151355 5671d62bc4baSyz147064 buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) * 5672d62bc4baSyz147064 DLADM_MAX_PROP_VALCNT + MAX_PROP_LINE); 567333343a97Smeem if (buf == NULL) 567433343a97Smeem die("insufficient memory"); 567533343a97Smeem 5676f4b3ec61Sdh155122 statep->ls_propvals = (char **)(void *)buf; 5677d62bc4baSyz147064 for (i = 0; i < DLADM_MAX_PROP_VALCNT; i++) { 5678d62bc4baSyz147064 statep->ls_propvals[i] = buf + 5679d62bc4baSyz147064 sizeof (char *) * DLADM_MAX_PROP_VALCNT + 56800ba2cbe9Sxc151355 i * DLADM_PROP_VAL_MAX; 56810ba2cbe9Sxc151355 } 5682f4b3ec61Sdh155122 statep->ls_line = buf + 5683d62bc4baSyz147064 (sizeof (char *) + DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT; 56840ba2cbe9Sxc151355 56850ba2cbe9Sxc151355 if (proplist != NULL) { 5686*da14cebeSEric Cheng for (i = 0; i < proplist->al_count; i++) { 5687d62bc4baSyz147064 (void) show_linkprop(linkid, 5688*da14cebeSEric Cheng proplist->al_info[i].ai_name, statep); 56890ba2cbe9Sxc151355 } 5690d62bc4baSyz147064 } else { 5691d62bc4baSyz147064 (void) dladm_walk_linkprop(linkid, statep, show_linkprop); 5692d62bc4baSyz147064 } 5693d62bc4baSyz147064 if (dh != NULL) 5694948f2876Sss150715 dlpi_close(dh); 56950ba2cbe9Sxc151355 free(buf); 5696d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 56970ba2cbe9Sxc151355 } 56980ba2cbe9Sxc151355 56990ba2cbe9Sxc151355 static dladm_status_t 5700d62bc4baSyz147064 set_linkprop_persist(datalink_id_t linkid, const char *prop_name, 5701d62bc4baSyz147064 char **prop_val, uint_t val_cnt, boolean_t reset) 57020ba2cbe9Sxc151355 { 57030ba2cbe9Sxc151355 dladm_status_t status; 57040ba2cbe9Sxc151355 5705d62bc4baSyz147064 status = dladm_set_linkprop(linkid, prop_name, prop_val, val_cnt, 5706d62bc4baSyz147064 DLADM_OPT_PERSIST); 57070ba2cbe9Sxc151355 57080ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 5709*da14cebeSEric Cheng warn_dlerr(status, "cannot persistently %s link property '%s'", 5710*da14cebeSEric Cheng reset ? "reset" : "set", prop_name); 57110ba2cbe9Sxc151355 } 57120ba2cbe9Sxc151355 return (status); 57130ba2cbe9Sxc151355 } 57140ba2cbe9Sxc151355 5715*da14cebeSEric Cheng static int 5716*da14cebeSEric Cheng reset_one_linkprop(datalink_id_t linkid, const char *propname, void *arg) 5717*da14cebeSEric Cheng { 5718*da14cebeSEric Cheng set_linkprop_state_t *statep = arg; 5719*da14cebeSEric Cheng dladm_status_t status; 5720*da14cebeSEric Cheng 5721*da14cebeSEric Cheng status = dladm_set_linkprop(linkid, propname, NULL, 0, 5722*da14cebeSEric Cheng DLADM_OPT_ACTIVE); 5723*da14cebeSEric Cheng if (status != DLADM_STATUS_OK) { 5724*da14cebeSEric Cheng warn_dlerr(status, "cannot reset link property '%s' on '%s'", 5725*da14cebeSEric Cheng propname, statep->ls_name); 5726*da14cebeSEric Cheng } 5727*da14cebeSEric Cheng if (!statep->ls_temp) { 5728*da14cebeSEric Cheng dladm_status_t s; 5729*da14cebeSEric Cheng 5730*da14cebeSEric Cheng s = set_linkprop_persist(linkid, propname, NULL, 0, 5731*da14cebeSEric Cheng statep->ls_reset); 5732*da14cebeSEric Cheng if (s != DLADM_STATUS_OK) 5733*da14cebeSEric Cheng status = s; 5734*da14cebeSEric Cheng } 5735*da14cebeSEric Cheng if (status != DLADM_STATUS_OK) 5736*da14cebeSEric Cheng statep->ls_status = status; 5737*da14cebeSEric Cheng 5738*da14cebeSEric Cheng return (DLADM_WALK_CONTINUE); 5739*da14cebeSEric Cheng } 5740*da14cebeSEric Cheng 57410ba2cbe9Sxc151355 static void 57428d5c46e6Sam223141 set_linkprop(int argc, char **argv, boolean_t reset, const char *use) 57430ba2cbe9Sxc151355 { 57440ba2cbe9Sxc151355 int i, option; 57450ba2cbe9Sxc151355 char errmsg[DLADM_STRSIZE]; 5746d62bc4baSyz147064 char *altroot = NULL; 5747d62bc4baSyz147064 datalink_id_t linkid; 57480ba2cbe9Sxc151355 boolean_t temp = B_FALSE; 57490ba2cbe9Sxc151355 dladm_status_t status = DLADM_STATUS_OK; 5750*da14cebeSEric Cheng dladm_arg_list_t *proplist = NULL; 57510ba2cbe9Sxc151355 57520ba2cbe9Sxc151355 opterr = 0; 57530ba2cbe9Sxc151355 while ((option = getopt_long(argc, argv, ":p:R:t", 57540ba2cbe9Sxc151355 prop_longopts, NULL)) != -1) { 57550ba2cbe9Sxc151355 switch (option) { 57560ba2cbe9Sxc151355 case 'p': 5757*da14cebeSEric Cheng if (dladm_parse_link_props(optarg, &proplist, reset) != 5758*da14cebeSEric Cheng DLADM_STATUS_OK) { 575933343a97Smeem die("invalid link properties specified"); 5760*da14cebeSEric Cheng } 57610ba2cbe9Sxc151355 break; 57620ba2cbe9Sxc151355 case 't': 57630ba2cbe9Sxc151355 temp = B_TRUE; 57640ba2cbe9Sxc151355 break; 57650ba2cbe9Sxc151355 case 'R': 5766d62bc4baSyz147064 altroot = optarg; 57670ba2cbe9Sxc151355 break; 57680ba2cbe9Sxc151355 default: 57698d5c46e6Sam223141 die_opterr(optopt, option, use); 57708d5c46e6Sam223141 57710ba2cbe9Sxc151355 } 57720ba2cbe9Sxc151355 } 57730ba2cbe9Sxc151355 5774d62bc4baSyz147064 /* get link name (required last argument) */ 5775d62bc4baSyz147064 if (optind != (argc - 1)) 57760ba2cbe9Sxc151355 usage(); 57770ba2cbe9Sxc151355 5778d62bc4baSyz147064 if (proplist == NULL && !reset) 577933343a97Smeem die("link property must be specified"); 578033343a97Smeem 5781d62bc4baSyz147064 if (altroot != NULL) { 5782*da14cebeSEric Cheng dladm_free_props(proplist); 5783d62bc4baSyz147064 altroot_cmd(altroot, argc, argv); 5784d62bc4baSyz147064 } 5785d62bc4baSyz147064 5786d62bc4baSyz147064 status = dladm_name2info(argv[optind], &linkid, NULL, NULL, NULL); 5787d62bc4baSyz147064 if (status != DLADM_STATUS_OK) 5788d62bc4baSyz147064 die_dlerr(status, "link %s is not valid", argv[optind]); 5789d62bc4baSyz147064 5790d62bc4baSyz147064 if (proplist == NULL) { 5791*da14cebeSEric Cheng set_linkprop_state_t state; 579213994ee8Sxz162242 5793*da14cebeSEric Cheng state.ls_name = argv[optind]; 5794*da14cebeSEric Cheng state.ls_reset = reset; 5795*da14cebeSEric Cheng state.ls_temp = temp; 5796*da14cebeSEric Cheng state.ls_status = DLADM_STATUS_OK; 5797*da14cebeSEric Cheng 5798*da14cebeSEric Cheng (void) dladm_walk_linkprop(linkid, &state, reset_one_linkprop); 5799*da14cebeSEric Cheng 5800*da14cebeSEric Cheng status = state.ls_status; 58010ba2cbe9Sxc151355 goto done; 58020ba2cbe9Sxc151355 } 58030ba2cbe9Sxc151355 5804*da14cebeSEric Cheng for (i = 0; i < proplist->al_count; i++) { 5805*da14cebeSEric Cheng dladm_arg_info_t *aip = &proplist->al_info[i]; 58060ba2cbe9Sxc151355 char **val; 58070ba2cbe9Sxc151355 uint_t count; 58080ba2cbe9Sxc151355 dladm_status_t s; 58090ba2cbe9Sxc151355 58100ba2cbe9Sxc151355 if (reset) { 58110ba2cbe9Sxc151355 val = NULL; 58120ba2cbe9Sxc151355 count = 0; 58130ba2cbe9Sxc151355 } else { 5814*da14cebeSEric Cheng val = aip->ai_val; 5815*da14cebeSEric Cheng count = aip->ai_count; 58160ba2cbe9Sxc151355 if (count == 0) { 581733343a97Smeem warn("no value specified for '%s'", 5818*da14cebeSEric Cheng aip->ai_name); 58190ba2cbe9Sxc151355 status = DLADM_STATUS_BADARG; 58200ba2cbe9Sxc151355 continue; 58210ba2cbe9Sxc151355 } 58220ba2cbe9Sxc151355 } 5823*da14cebeSEric Cheng s = dladm_set_linkprop(linkid, aip->ai_name, val, count, 5824d62bc4baSyz147064 DLADM_OPT_ACTIVE); 58250ba2cbe9Sxc151355 if (s == DLADM_STATUS_OK) { 58260ba2cbe9Sxc151355 if (!temp) { 5827d62bc4baSyz147064 s = set_linkprop_persist(linkid, 5828*da14cebeSEric Cheng aip->ai_name, val, count, reset); 58290ba2cbe9Sxc151355 if (s != DLADM_STATUS_OK) 58300ba2cbe9Sxc151355 status = s; 58310ba2cbe9Sxc151355 } 58320ba2cbe9Sxc151355 continue; 58330ba2cbe9Sxc151355 } 58340ba2cbe9Sxc151355 status = s; 58350ba2cbe9Sxc151355 switch (s) { 58360ba2cbe9Sxc151355 case DLADM_STATUS_NOTFOUND: 5837*da14cebeSEric Cheng warn("invalid link property '%s'", aip->ai_name); 58380ba2cbe9Sxc151355 break; 58390ba2cbe9Sxc151355 case DLADM_STATUS_BADVAL: { 58400ba2cbe9Sxc151355 int j; 58410ba2cbe9Sxc151355 char *ptr, *lim; 58420ba2cbe9Sxc151355 char **propvals = NULL; 5843d62bc4baSyz147064 uint_t valcnt = DLADM_MAX_PROP_VALCNT; 58440ba2cbe9Sxc151355 58450ba2cbe9Sxc151355 ptr = malloc((sizeof (char *) + 5846d62bc4baSyz147064 DLADM_PROP_VAL_MAX) * DLADM_MAX_PROP_VALCNT + 58470ba2cbe9Sxc151355 MAX_PROP_LINE); 58480ba2cbe9Sxc151355 58490ba2cbe9Sxc151355 propvals = (char **)(void *)ptr; 585033343a97Smeem if (propvals == NULL) 585133343a97Smeem die("insufficient memory"); 585233343a97Smeem 5853d62bc4baSyz147064 for (j = 0; j < DLADM_MAX_PROP_VALCNT; j++) { 58540ba2cbe9Sxc151355 propvals[j] = ptr + sizeof (char *) * 5855d62bc4baSyz147064 DLADM_MAX_PROP_VALCNT + 58560ba2cbe9Sxc151355 j * DLADM_PROP_VAL_MAX; 58570ba2cbe9Sxc151355 } 5858d62bc4baSyz147064 s = dladm_get_linkprop(linkid, 5859*da14cebeSEric Cheng DLADM_PROP_VAL_MODIFIABLE, aip->ai_name, propvals, 5860d62bc4baSyz147064 &valcnt); 5861d62bc4baSyz147064 5862d62bc4baSyz147064 if (s != DLADM_STATUS_OK) { 5863d62bc4baSyz147064 warn_dlerr(status, "cannot set link property " 5864*da14cebeSEric Cheng "'%s' on '%s'", aip->ai_name, argv[optind]); 5865d62bc4baSyz147064 free(propvals); 5866d62bc4baSyz147064 break; 5867d62bc4baSyz147064 } 58680ba2cbe9Sxc151355 58690ba2cbe9Sxc151355 ptr = errmsg; 58700ba2cbe9Sxc151355 lim = ptr + DLADM_STRSIZE; 58710ba2cbe9Sxc151355 *ptr = '\0'; 5872d62bc4baSyz147064 for (j = 0; j < valcnt; j++) { 58730ba2cbe9Sxc151355 ptr += snprintf(ptr, lim - ptr, "%s,", 58740ba2cbe9Sxc151355 propvals[j]); 58750ba2cbe9Sxc151355 if (ptr >= lim) 58760ba2cbe9Sxc151355 break; 58770ba2cbe9Sxc151355 } 5878f4b3ec61Sdh155122 if (ptr > errmsg) { 58790ba2cbe9Sxc151355 *(ptr - 1) = '\0'; 588033343a97Smeem warn("link property '%s' must be one of: %s", 5881*da14cebeSEric Cheng aip->ai_name, errmsg); 5882f4b3ec61Sdh155122 } else 5883f4b3ec61Sdh155122 warn("invalid link property '%s'", *val); 58840ba2cbe9Sxc151355 free(propvals); 58850ba2cbe9Sxc151355 break; 58860ba2cbe9Sxc151355 } 58870ba2cbe9Sxc151355 default: 58880ba2cbe9Sxc151355 if (reset) { 588933343a97Smeem warn_dlerr(status, "cannot reset link property " 5890*da14cebeSEric Cheng "'%s' on '%s'", aip->ai_name, argv[optind]); 58910ba2cbe9Sxc151355 } else { 589233343a97Smeem warn_dlerr(status, "cannot set link property " 5893*da14cebeSEric Cheng "'%s' on '%s'", aip->ai_name, argv[optind]); 58940ba2cbe9Sxc151355 } 58950ba2cbe9Sxc151355 break; 58960ba2cbe9Sxc151355 } 58970ba2cbe9Sxc151355 } 58980ba2cbe9Sxc151355 done: 5899*da14cebeSEric Cheng dladm_free_props(proplist); 59000ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) 59010ba2cbe9Sxc151355 exit(1); 59020ba2cbe9Sxc151355 } 59030ba2cbe9Sxc151355 59040ba2cbe9Sxc151355 static void 59058d5c46e6Sam223141 do_set_linkprop(int argc, char **argv, const char *use) 59060ba2cbe9Sxc151355 { 59078d5c46e6Sam223141 set_linkprop(argc, argv, B_FALSE, use); 59080ba2cbe9Sxc151355 } 59090ba2cbe9Sxc151355 59100ba2cbe9Sxc151355 static void 59118d5c46e6Sam223141 do_reset_linkprop(int argc, char **argv, const char *use) 59120ba2cbe9Sxc151355 { 59138d5c46e6Sam223141 set_linkprop(argc, argv, B_TRUE, use); 59140ba2cbe9Sxc151355 } 59150ba2cbe9Sxc151355 59160ba2cbe9Sxc151355 static int 59170ba2cbe9Sxc151355 convert_secobj(char *buf, uint_t len, uint8_t *obj_val, uint_t *obj_lenp, 59180ba2cbe9Sxc151355 dladm_secobj_class_t class) 59190ba2cbe9Sxc151355 { 59200ba2cbe9Sxc151355 int error = 0; 59210ba2cbe9Sxc151355 5922a399b765Szf162725 if (class == DLADM_SECOBJ_CLASS_WPA) { 5923a399b765Szf162725 if (len < 8 || len > 63) 5924a399b765Szf162725 return (EINVAL); 5925a399b765Szf162725 (void) memcpy(obj_val, buf, len); 5926a399b765Szf162725 *obj_lenp = len; 5927a399b765Szf162725 return (error); 5928a399b765Szf162725 } 59290ba2cbe9Sxc151355 5930a399b765Szf162725 if (class == DLADM_SECOBJ_CLASS_WEP) { 59310ba2cbe9Sxc151355 switch (len) { 59320ba2cbe9Sxc151355 case 5: /* ASCII key sizes */ 59330ba2cbe9Sxc151355 case 13: 59340ba2cbe9Sxc151355 (void) memcpy(obj_val, buf, len); 59350ba2cbe9Sxc151355 *obj_lenp = len; 59360ba2cbe9Sxc151355 break; 59370ba2cbe9Sxc151355 case 10: /* Hex key sizes, not preceded by 0x */ 59380ba2cbe9Sxc151355 case 26: 59390ba2cbe9Sxc151355 error = hexascii_to_octet(buf, len, obj_val, obj_lenp); 59400ba2cbe9Sxc151355 break; 59410ba2cbe9Sxc151355 case 12: /* Hex key sizes, preceded by 0x */ 59420ba2cbe9Sxc151355 case 28: 59430ba2cbe9Sxc151355 if (strncmp(buf, "0x", 2) != 0) 59440ba2cbe9Sxc151355 return (EINVAL); 5945a399b765Szf162725 error = hexascii_to_octet(buf + 2, len - 2, 5946a399b765Szf162725 obj_val, obj_lenp); 59470ba2cbe9Sxc151355 break; 59480ba2cbe9Sxc151355 default: 59490ba2cbe9Sxc151355 return (EINVAL); 59500ba2cbe9Sxc151355 } 59510ba2cbe9Sxc151355 return (error); 59520ba2cbe9Sxc151355 } 59530ba2cbe9Sxc151355 5954a399b765Szf162725 return (ENOENT); 5955a399b765Szf162725 } 5956a399b765Szf162725 59570ba2cbe9Sxc151355 /* ARGSUSED */ 59580ba2cbe9Sxc151355 static void 59590ba2cbe9Sxc151355 defersig(int sig) 59600ba2cbe9Sxc151355 { 59610ba2cbe9Sxc151355 signalled = sig; 59620ba2cbe9Sxc151355 } 59630ba2cbe9Sxc151355 59640ba2cbe9Sxc151355 static int 59650ba2cbe9Sxc151355 get_secobj_from_tty(uint_t try, const char *objname, char *buf) 59660ba2cbe9Sxc151355 { 59670ba2cbe9Sxc151355 uint_t len = 0; 59680ba2cbe9Sxc151355 int c; 59690ba2cbe9Sxc151355 struct termios stored, current; 59700ba2cbe9Sxc151355 void (*sigfunc)(int); 59710ba2cbe9Sxc151355 59720ba2cbe9Sxc151355 /* 59730ba2cbe9Sxc151355 * Turn off echo -- but before we do so, defer SIGINT handling 59740ba2cbe9Sxc151355 * so that a ^C doesn't leave the terminal corrupted. 59750ba2cbe9Sxc151355 */ 59760ba2cbe9Sxc151355 sigfunc = signal(SIGINT, defersig); 59770ba2cbe9Sxc151355 (void) fflush(stdin); 59780ba2cbe9Sxc151355 (void) tcgetattr(0, &stored); 59790ba2cbe9Sxc151355 current = stored; 59800ba2cbe9Sxc151355 current.c_lflag &= ~(ICANON|ECHO); 59810ba2cbe9Sxc151355 current.c_cc[VTIME] = 0; 59820ba2cbe9Sxc151355 current.c_cc[VMIN] = 1; 59830ba2cbe9Sxc151355 (void) tcsetattr(0, TCSANOW, ¤t); 59840ba2cbe9Sxc151355 again: 59850ba2cbe9Sxc151355 if (try == 1) 59860ba2cbe9Sxc151355 (void) printf(gettext("provide value for '%s': "), objname); 59870ba2cbe9Sxc151355 else 59880ba2cbe9Sxc151355 (void) printf(gettext("confirm value for '%s': "), objname); 59890ba2cbe9Sxc151355 59900ba2cbe9Sxc151355 (void) fflush(stdout); 59910ba2cbe9Sxc151355 while (signalled == 0) { 59920ba2cbe9Sxc151355 c = getchar(); 59930ba2cbe9Sxc151355 if (c == '\n' || c == '\r') { 59940ba2cbe9Sxc151355 if (len != 0) 59950ba2cbe9Sxc151355 break; 59960ba2cbe9Sxc151355 (void) putchar('\n'); 59970ba2cbe9Sxc151355 goto again; 59980ba2cbe9Sxc151355 } 59990ba2cbe9Sxc151355 60000ba2cbe9Sxc151355 buf[len++] = c; 60010ba2cbe9Sxc151355 if (len >= DLADM_SECOBJ_VAL_MAX - 1) 60020ba2cbe9Sxc151355 break; 60030ba2cbe9Sxc151355 (void) putchar('*'); 60040ba2cbe9Sxc151355 } 60050ba2cbe9Sxc151355 60060ba2cbe9Sxc151355 (void) putchar('\n'); 60070ba2cbe9Sxc151355 (void) fflush(stdin); 60080ba2cbe9Sxc151355 60090ba2cbe9Sxc151355 /* 60100ba2cbe9Sxc151355 * Restore terminal setting and handle deferred signals. 60110ba2cbe9Sxc151355 */ 60120ba2cbe9Sxc151355 (void) tcsetattr(0, TCSANOW, &stored); 60130ba2cbe9Sxc151355 60140ba2cbe9Sxc151355 (void) signal(SIGINT, sigfunc); 60150ba2cbe9Sxc151355 if (signalled != 0) 60160ba2cbe9Sxc151355 (void) kill(getpid(), signalled); 60170ba2cbe9Sxc151355 60180ba2cbe9Sxc151355 return (len); 60190ba2cbe9Sxc151355 } 60200ba2cbe9Sxc151355 60210ba2cbe9Sxc151355 static int 60220ba2cbe9Sxc151355 get_secobj_val(char *obj_name, uint8_t *obj_val, uint_t *obj_lenp, 60230ba2cbe9Sxc151355 dladm_secobj_class_t class, FILE *filep) 60240ba2cbe9Sxc151355 { 60250ba2cbe9Sxc151355 int rval; 60260ba2cbe9Sxc151355 uint_t len, len2; 60270ba2cbe9Sxc151355 char buf[DLADM_SECOBJ_VAL_MAX], buf2[DLADM_SECOBJ_VAL_MAX]; 60280ba2cbe9Sxc151355 60290ba2cbe9Sxc151355 if (filep == NULL) { 60300ba2cbe9Sxc151355 len = get_secobj_from_tty(1, obj_name, buf); 60310ba2cbe9Sxc151355 rval = convert_secobj(buf, len, obj_val, obj_lenp, class); 60320ba2cbe9Sxc151355 if (rval == 0) { 60330ba2cbe9Sxc151355 len2 = get_secobj_from_tty(2, obj_name, buf2); 60340ba2cbe9Sxc151355 if (len != len2 || memcmp(buf, buf2, len) != 0) 60350ba2cbe9Sxc151355 rval = ENOTSUP; 60360ba2cbe9Sxc151355 } 60370ba2cbe9Sxc151355 return (rval); 60380ba2cbe9Sxc151355 } else { 60390ba2cbe9Sxc151355 for (;;) { 60400ba2cbe9Sxc151355 if (fgets(buf, sizeof (buf), filep) == NULL) 60410ba2cbe9Sxc151355 break; 60420ba2cbe9Sxc151355 if (isspace(buf[0])) 60430ba2cbe9Sxc151355 continue; 60440ba2cbe9Sxc151355 60450ba2cbe9Sxc151355 len = strlen(buf); 60460ba2cbe9Sxc151355 if (buf[len - 1] == '\n') { 60470ba2cbe9Sxc151355 buf[len - 1] = '\0'; 60480ba2cbe9Sxc151355 len--; 60490ba2cbe9Sxc151355 } 60500ba2cbe9Sxc151355 break; 60510ba2cbe9Sxc151355 } 60520ba2cbe9Sxc151355 (void) fclose(filep); 60530ba2cbe9Sxc151355 } 60540ba2cbe9Sxc151355 return (convert_secobj(buf, len, obj_val, obj_lenp, class)); 60550ba2cbe9Sxc151355 } 60560ba2cbe9Sxc151355 60570ba2cbe9Sxc151355 static boolean_t 60580ba2cbe9Sxc151355 check_auth(const char *auth) 60590ba2cbe9Sxc151355 { 60600ba2cbe9Sxc151355 struct passwd *pw; 60610ba2cbe9Sxc151355 60620ba2cbe9Sxc151355 if ((pw = getpwuid(getuid())) == NULL) 60630ba2cbe9Sxc151355 return (B_FALSE); 60640ba2cbe9Sxc151355 60650ba2cbe9Sxc151355 return (chkauthattr(auth, pw->pw_name) != 0); 60660ba2cbe9Sxc151355 } 60670ba2cbe9Sxc151355 60680ba2cbe9Sxc151355 static void 60690ba2cbe9Sxc151355 audit_secobj(char *auth, char *class, char *obj, 60700ba2cbe9Sxc151355 boolean_t success, boolean_t create) 60710ba2cbe9Sxc151355 { 60720ba2cbe9Sxc151355 adt_session_data_t *ah; 60730ba2cbe9Sxc151355 adt_event_data_t *event; 60740ba2cbe9Sxc151355 au_event_t flag; 60750ba2cbe9Sxc151355 char *errstr; 60760ba2cbe9Sxc151355 60770ba2cbe9Sxc151355 if (create) { 60780ba2cbe9Sxc151355 flag = ADT_dladm_create_secobj; 60790ba2cbe9Sxc151355 errstr = "ADT_dladm_create_secobj"; 60800ba2cbe9Sxc151355 } else { 60810ba2cbe9Sxc151355 flag = ADT_dladm_delete_secobj; 60820ba2cbe9Sxc151355 errstr = "ADT_dladm_delete_secobj"; 60830ba2cbe9Sxc151355 } 60840ba2cbe9Sxc151355 608533343a97Smeem if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) 608633343a97Smeem die("adt_start_session: %s", strerror(errno)); 60870ba2cbe9Sxc151355 608833343a97Smeem if ((event = adt_alloc_event(ah, flag)) == NULL) 608933343a97Smeem die("adt_alloc_event (%s): %s", errstr, strerror(errno)); 60900ba2cbe9Sxc151355 60910ba2cbe9Sxc151355 /* fill in audit info */ 60920ba2cbe9Sxc151355 if (create) { 60930ba2cbe9Sxc151355 event->adt_dladm_create_secobj.auth_used = auth; 60940ba2cbe9Sxc151355 event->adt_dladm_create_secobj.obj_class = class; 60950ba2cbe9Sxc151355 event->adt_dladm_create_secobj.obj_name = obj; 60960ba2cbe9Sxc151355 } else { 60970ba2cbe9Sxc151355 event->adt_dladm_delete_secobj.auth_used = auth; 60980ba2cbe9Sxc151355 event->adt_dladm_delete_secobj.obj_class = class; 60990ba2cbe9Sxc151355 event->adt_dladm_delete_secobj.obj_name = obj; 61000ba2cbe9Sxc151355 } 61010ba2cbe9Sxc151355 61020ba2cbe9Sxc151355 if (success) { 61030ba2cbe9Sxc151355 if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) { 610433343a97Smeem die("adt_put_event (%s, success): %s", errstr, 610533343a97Smeem strerror(errno)); 61060ba2cbe9Sxc151355 } 61070ba2cbe9Sxc151355 } else { 61080ba2cbe9Sxc151355 if (adt_put_event(event, ADT_FAILURE, 61090ba2cbe9Sxc151355 ADT_FAIL_VALUE_AUTH) != 0) { 611033343a97Smeem die("adt_put_event: (%s, failure): %s", errstr, 611133343a97Smeem strerror(errno)); 61120ba2cbe9Sxc151355 } 61130ba2cbe9Sxc151355 } 61140ba2cbe9Sxc151355 61150ba2cbe9Sxc151355 adt_free_event(event); 61160ba2cbe9Sxc151355 (void) adt_end_session(ah); 61170ba2cbe9Sxc151355 } 61180ba2cbe9Sxc151355 61190ba2cbe9Sxc151355 #define MAX_SECOBJS 32 61200ba2cbe9Sxc151355 #define MAX_SECOBJ_NAMELEN 32 61210ba2cbe9Sxc151355 static void 61228d5c46e6Sam223141 do_create_secobj(int argc, char **argv, const char *use) 61230ba2cbe9Sxc151355 { 61240ba2cbe9Sxc151355 int option, rval; 61250ba2cbe9Sxc151355 FILE *filep = NULL; 61260ba2cbe9Sxc151355 char *obj_name = NULL; 61270ba2cbe9Sxc151355 char *class_name = NULL; 61280ba2cbe9Sxc151355 uint8_t obj_val[DLADM_SECOBJ_VAL_MAX]; 61290ba2cbe9Sxc151355 uint_t obj_len; 61300ba2cbe9Sxc151355 boolean_t success, temp = B_FALSE; 61310ba2cbe9Sxc151355 dladm_status_t status; 61320ba2cbe9Sxc151355 dladm_secobj_class_t class = -1; 61330ba2cbe9Sxc151355 uid_t euid; 61340ba2cbe9Sxc151355 61350ba2cbe9Sxc151355 opterr = 0; 61360ba2cbe9Sxc151355 (void) memset(obj_val, 0, DLADM_SECOBJ_VAL_MAX); 61370ba2cbe9Sxc151355 while ((option = getopt_long(argc, argv, ":f:c:R:t", 61380ba2cbe9Sxc151355 wifi_longopts, NULL)) != -1) { 61390ba2cbe9Sxc151355 switch (option) { 61400ba2cbe9Sxc151355 case 'f': 61410ba2cbe9Sxc151355 euid = geteuid(); 61420ba2cbe9Sxc151355 (void) seteuid(getuid()); 61430ba2cbe9Sxc151355 filep = fopen(optarg, "r"); 61440ba2cbe9Sxc151355 if (filep == NULL) { 614533343a97Smeem die("cannot open %s: %s", optarg, 614633343a97Smeem strerror(errno)); 61470ba2cbe9Sxc151355 } 61480ba2cbe9Sxc151355 (void) seteuid(euid); 61490ba2cbe9Sxc151355 break; 61500ba2cbe9Sxc151355 case 'c': 61510ba2cbe9Sxc151355 class_name = optarg; 61520ba2cbe9Sxc151355 status = dladm_str2secobjclass(optarg, &class); 61530ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 615433343a97Smeem die("invalid secure object class '%s', " 6155a399b765Szf162725 "valid values are: wep, wpa", optarg); 61560ba2cbe9Sxc151355 } 61570ba2cbe9Sxc151355 break; 61580ba2cbe9Sxc151355 case 't': 61590ba2cbe9Sxc151355 temp = B_TRUE; 61600ba2cbe9Sxc151355 break; 61610ba2cbe9Sxc151355 case 'R': 61620ba2cbe9Sxc151355 status = dladm_set_rootdir(optarg); 61630ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 616433343a97Smeem die_dlerr(status, "invalid directory " 616533343a97Smeem "specified"); 61660ba2cbe9Sxc151355 } 61670ba2cbe9Sxc151355 break; 61680ba2cbe9Sxc151355 default: 61698d5c46e6Sam223141 die_opterr(optopt, option, use); 61700ba2cbe9Sxc151355 break; 61710ba2cbe9Sxc151355 } 61720ba2cbe9Sxc151355 } 61730ba2cbe9Sxc151355 61740ba2cbe9Sxc151355 if (optind == (argc - 1)) 61750ba2cbe9Sxc151355 obj_name = argv[optind]; 61760ba2cbe9Sxc151355 else if (optind != argc) 61770ba2cbe9Sxc151355 usage(); 61780ba2cbe9Sxc151355 617933343a97Smeem if (class == -1) 618033343a97Smeem die("secure object class required"); 61810ba2cbe9Sxc151355 618233343a97Smeem if (obj_name == NULL) 618333343a97Smeem die("secure object name required"); 61840ba2cbe9Sxc151355 61850ba2cbe9Sxc151355 success = check_auth(LINK_SEC_AUTH); 61860ba2cbe9Sxc151355 audit_secobj(LINK_SEC_AUTH, class_name, obj_name, success, B_TRUE); 618733343a97Smeem if (!success) 618833343a97Smeem die("authorization '%s' is required", LINK_SEC_AUTH); 61890ba2cbe9Sxc151355 619033343a97Smeem rval = get_secobj_val(obj_name, obj_val, &obj_len, class, filep); 619133343a97Smeem if (rval != 0) { 61920ba2cbe9Sxc151355 switch (rval) { 61930ba2cbe9Sxc151355 case ENOENT: 619433343a97Smeem die("invalid secure object class"); 61950ba2cbe9Sxc151355 break; 61960ba2cbe9Sxc151355 case EINVAL: 619733343a97Smeem die("invalid secure object value"); 61980ba2cbe9Sxc151355 break; 61990ba2cbe9Sxc151355 case ENOTSUP: 620033343a97Smeem die("verification failed"); 62010ba2cbe9Sxc151355 break; 62020ba2cbe9Sxc151355 default: 620333343a97Smeem die("invalid secure object: %s", strerror(rval)); 62040ba2cbe9Sxc151355 break; 62050ba2cbe9Sxc151355 } 62060ba2cbe9Sxc151355 } 62070ba2cbe9Sxc151355 62080ba2cbe9Sxc151355 status = dladm_set_secobj(obj_name, class, obj_val, obj_len, 6209d62bc4baSyz147064 DLADM_OPT_CREATE | DLADM_OPT_ACTIVE); 62100ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 621133343a97Smeem die_dlerr(status, "could not create secure object '%s'", 621233343a97Smeem obj_name); 62130ba2cbe9Sxc151355 } 62140ba2cbe9Sxc151355 if (temp) 62150ba2cbe9Sxc151355 return; 62160ba2cbe9Sxc151355 62170ba2cbe9Sxc151355 status = dladm_set_secobj(obj_name, class, obj_val, obj_len, 62180ba2cbe9Sxc151355 DLADM_OPT_PERSIST); 62190ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 622033343a97Smeem warn_dlerr(status, "could not persistently create secure " 622133343a97Smeem "object '%s'", obj_name); 62220ba2cbe9Sxc151355 } 62230ba2cbe9Sxc151355 } 62240ba2cbe9Sxc151355 62250ba2cbe9Sxc151355 static void 62268d5c46e6Sam223141 do_delete_secobj(int argc, char **argv, const char *use) 62270ba2cbe9Sxc151355 { 62280ba2cbe9Sxc151355 int i, option; 62290ba2cbe9Sxc151355 boolean_t temp = B_FALSE; 62300ba2cbe9Sxc151355 split_t *sp = NULL; 62310ba2cbe9Sxc151355 boolean_t success; 62320ba2cbe9Sxc151355 dladm_status_t status, pstatus; 62330ba2cbe9Sxc151355 62340ba2cbe9Sxc151355 opterr = 0; 62350ba2cbe9Sxc151355 status = pstatus = DLADM_STATUS_OK; 623633343a97Smeem while ((option = getopt_long(argc, argv, ":R:t", 62370ba2cbe9Sxc151355 wifi_longopts, NULL)) != -1) { 62380ba2cbe9Sxc151355 switch (option) { 62390ba2cbe9Sxc151355 case 't': 62400ba2cbe9Sxc151355 temp = B_TRUE; 62410ba2cbe9Sxc151355 break; 62420ba2cbe9Sxc151355 case 'R': 62430ba2cbe9Sxc151355 status = dladm_set_rootdir(optarg); 62440ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 624533343a97Smeem die_dlerr(status, "invalid directory " 624633343a97Smeem "specified"); 62470ba2cbe9Sxc151355 } 62480ba2cbe9Sxc151355 break; 62490ba2cbe9Sxc151355 default: 62508d5c46e6Sam223141 die_opterr(optopt, option, use); 62510ba2cbe9Sxc151355 break; 62520ba2cbe9Sxc151355 } 62530ba2cbe9Sxc151355 } 62540ba2cbe9Sxc151355 62550ba2cbe9Sxc151355 if (optind == (argc - 1)) { 62560ba2cbe9Sxc151355 sp = split(argv[optind], MAX_SECOBJS, MAX_SECOBJ_NAMELEN); 62570ba2cbe9Sxc151355 if (sp == NULL) { 625833343a97Smeem die("invalid secure object name(s): '%s'", 625933343a97Smeem argv[optind]); 62600ba2cbe9Sxc151355 } 62610ba2cbe9Sxc151355 } else if (optind != argc) 62620ba2cbe9Sxc151355 usage(); 62630ba2cbe9Sxc151355 626433343a97Smeem if (sp == NULL || sp->s_nfields < 1) 626533343a97Smeem die("secure object name required"); 62660ba2cbe9Sxc151355 62670ba2cbe9Sxc151355 success = check_auth(LINK_SEC_AUTH); 6268a399b765Szf162725 audit_secobj(LINK_SEC_AUTH, "unknown", argv[optind], success, B_FALSE); 626933343a97Smeem if (!success) 627033343a97Smeem die("authorization '%s' is required", LINK_SEC_AUTH); 62710ba2cbe9Sxc151355 62720ba2cbe9Sxc151355 for (i = 0; i < sp->s_nfields; i++) { 6273d62bc4baSyz147064 status = dladm_unset_secobj(sp->s_fields[i], DLADM_OPT_ACTIVE); 62740ba2cbe9Sxc151355 if (!temp) { 62750ba2cbe9Sxc151355 pstatus = dladm_unset_secobj(sp->s_fields[i], 62760ba2cbe9Sxc151355 DLADM_OPT_PERSIST); 62770ba2cbe9Sxc151355 } else { 62780ba2cbe9Sxc151355 pstatus = DLADM_STATUS_OK; 62790ba2cbe9Sxc151355 } 62800ba2cbe9Sxc151355 62810ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK) { 628233343a97Smeem warn_dlerr(status, "could not delete secure object " 628333343a97Smeem "'%s'", sp->s_fields[i]); 62840ba2cbe9Sxc151355 } 62850ba2cbe9Sxc151355 if (pstatus != DLADM_STATUS_OK) { 628633343a97Smeem warn_dlerr(pstatus, "could not persistently delete " 628733343a97Smeem "secure object '%s'", sp->s_fields[i]); 62880ba2cbe9Sxc151355 } 62890ba2cbe9Sxc151355 } 62900ba2cbe9Sxc151355 if (status != DLADM_STATUS_OK || pstatus != DLADM_STATUS_OK) 62910ba2cbe9Sxc151355 exit(1); 62920ba2cbe9Sxc151355 } 62930ba2cbe9Sxc151355 62940ba2cbe9Sxc151355 typedef struct show_secobj_state { 62950ba2cbe9Sxc151355 boolean_t ss_persist; 62960ba2cbe9Sxc151355 boolean_t ss_parseable; 62970ba2cbe9Sxc151355 boolean_t ss_header; 6298e7801d59Ssowmini print_state_t ss_print; 62990ba2cbe9Sxc151355 } show_secobj_state_t; 63000ba2cbe9Sxc151355 63010ba2cbe9Sxc151355 63020ba2cbe9Sxc151355 static boolean_t 63030ba2cbe9Sxc151355 show_secobj(void *arg, const char *obj_name) 63040ba2cbe9Sxc151355 { 63050ba2cbe9Sxc151355 uint_t obj_len = DLADM_SECOBJ_VAL_MAX; 63060ba2cbe9Sxc151355 uint8_t obj_val[DLADM_SECOBJ_VAL_MAX]; 63070ba2cbe9Sxc151355 char buf[DLADM_STRSIZE]; 63080ba2cbe9Sxc151355 uint_t flags = 0; 63090ba2cbe9Sxc151355 dladm_secobj_class_t class; 63100ba2cbe9Sxc151355 show_secobj_state_t *statep = arg; 63110ba2cbe9Sxc151355 dladm_status_t status; 6312e7801d59Ssowmini secobj_fields_buf_t sbuf; 63130ba2cbe9Sxc151355 63145f5c9f54SAnurag S. Maskey bzero(&sbuf, sizeof (secobj_fields_buf_t)); 63150ba2cbe9Sxc151355 if (statep->ss_persist) 63160ba2cbe9Sxc151355 flags |= DLADM_OPT_PERSIST; 63170ba2cbe9Sxc151355 63180ba2cbe9Sxc151355 status = dladm_get_secobj(obj_name, &class, obj_val, &obj_len, flags); 631933343a97Smeem if (status != DLADM_STATUS_OK) 632033343a97Smeem die_dlerr(status, "cannot get secure object '%s'", obj_name); 63210ba2cbe9Sxc151355 63220ba2cbe9Sxc151355 if (statep->ss_header) { 63230ba2cbe9Sxc151355 statep->ss_header = B_FALSE; 63240ba2cbe9Sxc151355 if (!statep->ss_parseable) 6325e7801d59Ssowmini print_header(&statep->ss_print); 63260ba2cbe9Sxc151355 } 63270ba2cbe9Sxc151355 6328e7801d59Ssowmini (void) snprintf(sbuf.ss_obj_name, sizeof (sbuf.ss_obj_name), 6329e7801d59Ssowmini obj_name); 6330e7801d59Ssowmini (void) dladm_secobjclass2str(class, buf); 6331e7801d59Ssowmini (void) snprintf(sbuf.ss_class, sizeof (sbuf.ss_class), "%s", buf); 6332e7801d59Ssowmini if (getuid() == 0) { 63330ba2cbe9Sxc151355 char val[DLADM_SECOBJ_VAL_MAX * 2]; 63340ba2cbe9Sxc151355 uint_t len = sizeof (val); 63350ba2cbe9Sxc151355 6336e7801d59Ssowmini if (octet_to_hexascii(obj_val, obj_len, val, &len) == 0) 6337e7801d59Ssowmini (void) snprintf(sbuf.ss_val, 6338e7801d59Ssowmini sizeof (sbuf.ss_val), "%s", val); 63390ba2cbe9Sxc151355 } 6340e7801d59Ssowmini dladm_print_output(&statep->ss_print, statep->ss_parseable, 6341e7801d59Ssowmini dladm_print_field, (void *)&sbuf); 63420ba2cbe9Sxc151355 return (B_TRUE); 63430ba2cbe9Sxc151355 } 63440ba2cbe9Sxc151355 63450ba2cbe9Sxc151355 static void 63468d5c46e6Sam223141 do_show_secobj(int argc, char **argv, const char *use) 63470ba2cbe9Sxc151355 { 63480ba2cbe9Sxc151355 int option; 63490ba2cbe9Sxc151355 show_secobj_state_t state; 63500ba2cbe9Sxc151355 dladm_status_t status; 63510d365605Sschuster boolean_t o_arg = B_FALSE; 63520ba2cbe9Sxc151355 uint_t i; 63530ba2cbe9Sxc151355 split_t *sp; 63540ba2cbe9Sxc151355 uint_t flags; 6355e7801d59Ssowmini char *fields_str = NULL; 6356e7801d59Ssowmini print_field_t **fields; 6357e7801d59Ssowmini uint_t nfields; 6358e7801d59Ssowmini char *def_fields = "object,class"; 6359e7801d59Ssowmini char *all_fields = "object,class,value"; 63600ba2cbe9Sxc151355 63610ba2cbe9Sxc151355 opterr = 0; 6362e7801d59Ssowmini bzero(&state, sizeof (state)); 6363e7801d59Ssowmini state.ss_parseable = B_FALSE; 6364e7801d59Ssowmini fields_str = def_fields; 63650ba2cbe9Sxc151355 state.ss_persist = B_FALSE; 63660ba2cbe9Sxc151355 state.ss_parseable = B_FALSE; 63670ba2cbe9Sxc151355 state.ss_header = B_TRUE; 6368e7801d59Ssowmini while ((option = getopt_long(argc, argv, ":pPo:", 63690ba2cbe9Sxc151355 wifi_longopts, NULL)) != -1) { 63700ba2cbe9Sxc151355 switch (option) { 63710ba2cbe9Sxc151355 case 'p': 63720ba2cbe9Sxc151355 state.ss_parseable = B_TRUE; 63730ba2cbe9Sxc151355 break; 63740ba2cbe9Sxc151355 case 'P': 63750ba2cbe9Sxc151355 state.ss_persist = B_TRUE; 63760ba2cbe9Sxc151355 break; 6377e7801d59Ssowmini case 'o': 63780d365605Sschuster o_arg = B_TRUE; 6379e7801d59Ssowmini if (strcasecmp(optarg, "all") == 0) 6380e7801d59Ssowmini fields_str = all_fields; 6381e7801d59Ssowmini else 6382e7801d59Ssowmini fields_str = optarg; 63830ba2cbe9Sxc151355 break; 63840ba2cbe9Sxc151355 default: 63858d5c46e6Sam223141 die_opterr(optopt, option, use); 63860ba2cbe9Sxc151355 break; 63870ba2cbe9Sxc151355 } 63880ba2cbe9Sxc151355 } 63890ba2cbe9Sxc151355 63900d365605Sschuster if (state.ss_parseable && !o_arg) 63910d365605Sschuster die("option -c requires -o"); 63920d365605Sschuster 63930d365605Sschuster if (state.ss_parseable && fields_str == all_fields) 63940d365605Sschuster die("\"-o all\" is invalid with -p"); 63950d365605Sschuster 6396e7801d59Ssowmini fields = parse_output_fields(fields_str, secobj_fields, 6397e7801d59Ssowmini DEV_SOBJ_FIELDS, CMD_TYPE_ANY, &nfields); 6398e7801d59Ssowmini 6399e7801d59Ssowmini if (fields == NULL) { 6400e7801d59Ssowmini die("invalid field(s) specified"); 6401e7801d59Ssowmini return; 6402e7801d59Ssowmini } 6403e7801d59Ssowmini state.ss_print.ps_fields = fields; 6404e7801d59Ssowmini state.ss_print.ps_nfields = nfields; 6405e7801d59Ssowmini 6406e7801d59Ssowmini flags = state.ss_persist ? DLADM_OPT_PERSIST : 0; 64070ba2cbe9Sxc151355 if (optind == (argc - 1)) { 64080ba2cbe9Sxc151355 sp = split(argv[optind], MAX_SECOBJS, MAX_SECOBJ_NAMELEN); 64090ba2cbe9Sxc151355 if (sp == NULL) { 641033343a97Smeem die("invalid secure object name(s): '%s'", 641133343a97Smeem argv[optind]); 64120ba2cbe9Sxc151355 } 64130ba2cbe9Sxc151355 for (i = 0; i < sp->s_nfields; i++) { 64140ba2cbe9Sxc151355 if (!show_secobj(&state, sp->s_fields[i])) 64150ba2cbe9Sxc151355 break; 64160ba2cbe9Sxc151355 } 64170ba2cbe9Sxc151355 splitfree(sp); 64180ba2cbe9Sxc151355 return; 64190ba2cbe9Sxc151355 } else if (optind != argc) 64200ba2cbe9Sxc151355 usage(); 64210ba2cbe9Sxc151355 64220ba2cbe9Sxc151355 status = dladm_walk_secobj(&state, show_secobj, flags); 642333343a97Smeem if (status != DLADM_STATUS_OK) 642433343a97Smeem die_dlerr(status, "show-secobj"); 64250ba2cbe9Sxc151355 } 64260ba2cbe9Sxc151355 64270ba2cbe9Sxc151355 /*ARGSUSED*/ 6428d62bc4baSyz147064 static int 6429d62bc4baSyz147064 i_dladm_init_linkprop(datalink_id_t linkid, void *arg) 6430d62bc4baSyz147064 { 643130890389Sartem (void) dladm_init_linkprop(linkid, B_TRUE); 6432d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 6433d62bc4baSyz147064 } 6434d62bc4baSyz147064 64358d5c46e6Sam223141 /*ARGSUSED*/ 6436*da14cebeSEric Cheng void 64378d5c46e6Sam223141 do_init_linkprop(int argc, char **argv, const char *use) 64380ba2cbe9Sxc151355 { 643930890389Sartem int option; 644030890389Sartem dladm_status_t status; 644130890389Sartem datalink_id_t linkid = DATALINK_ALL_LINKID; 644230890389Sartem datalink_media_t media = DATALINK_ANY_MEDIATYPE; 644330890389Sartem uint_t any_media = B_TRUE; 644430890389Sartem 644530890389Sartem opterr = 0; 644630890389Sartem while ((option = getopt(argc, argv, ":w")) != -1) { 644730890389Sartem switch (option) { 644830890389Sartem case 'w': 644930890389Sartem media = DL_WIFI; 645030890389Sartem any_media = B_FALSE; 645130890389Sartem break; 645230890389Sartem default: 64538d5c46e6Sam223141 /* 64548d5c46e6Sam223141 * Because init-linkprop is not a public command, 64558d5c46e6Sam223141 * print the usage instead. 64568d5c46e6Sam223141 */ 64578d5c46e6Sam223141 usage(); 645830890389Sartem break; 645930890389Sartem } 646030890389Sartem } 646130890389Sartem 646230890389Sartem if (optind == (argc - 1)) { 646330890389Sartem if ((status = dladm_name2info(argv[optind], &linkid, NULL, NULL, 646430890389Sartem NULL)) != DLADM_STATUS_OK) 646530890389Sartem die_dlerr(status, "link %s is not valid", argv[optind]); 646630890389Sartem } else if (optind != argc) { 646730890389Sartem usage(); 646830890389Sartem } 646930890389Sartem 647030890389Sartem if (linkid == DATALINK_ALL_LINKID) { 6471d62bc4baSyz147064 /* 647230890389Sartem * linkprops of links of other classes have been initialized as 6473d62bc4baSyz147064 * part of the dladm up-xxx operation. 6474d62bc4baSyz147064 */ 6475d62bc4baSyz147064 (void) dladm_walk_datalink_id(i_dladm_init_linkprop, NULL, 647630890389Sartem DATALINK_CLASS_PHYS, media, DLADM_OPT_PERSIST); 647730890389Sartem } else { 647830890389Sartem (void) dladm_init_linkprop(linkid, any_media); 647930890389Sartem } 64800ba2cbe9Sxc151355 } 64810ba2cbe9Sxc151355 64820ba2cbe9Sxc151355 /* ARGSUSED */ 64830ba2cbe9Sxc151355 static void 64848d5c46e6Sam223141 do_show_ether(int argc, char **argv, const char *use) 6485e7801d59Ssowmini { 6486e7801d59Ssowmini int option; 6487e7801d59Ssowmini datalink_id_t linkid; 6488e7801d59Ssowmini print_ether_state_t state; 6489e7801d59Ssowmini print_field_t **fields; 64900d365605Sschuster boolean_t o_arg = B_FALSE; 6491e7801d59Ssowmini char *fields_str; 6492e7801d59Ssowmini uint_t nfields; 6493e7801d59Ssowmini char *all_fields = 6494e7801d59Ssowmini "link,ptype,state,auto,speed-duplex,pause,rem_fault"; 6495e7801d59Ssowmini char *default_fields = 6496e7801d59Ssowmini "link,ptype,state,auto,speed-duplex,pause"; 6497e7801d59Ssowmini 6498e7801d59Ssowmini fields_str = default_fields; 6499e7801d59Ssowmini bzero(&state, sizeof (state)); 6500e7801d59Ssowmini state.es_link = NULL; 6501e7801d59Ssowmini state.es_parseable = B_FALSE; 6502e7801d59Ssowmini 6503e7801d59Ssowmini while ((option = getopt_long(argc, argv, "o:px", 6504e7801d59Ssowmini showeth_lopts, NULL)) != -1) { 6505e7801d59Ssowmini switch (option) { 6506e7801d59Ssowmini case 'x': 6507e7801d59Ssowmini state.es_extended = B_TRUE; 6508e7801d59Ssowmini break; 6509e7801d59Ssowmini case 'p': 6510e7801d59Ssowmini state.es_parseable = B_TRUE; 6511e7801d59Ssowmini break; 6512e7801d59Ssowmini case 'o': 65130d365605Sschuster o_arg = B_TRUE; 6514e7801d59Ssowmini if (strcasecmp(optarg, "all") == 0) 6515e7801d59Ssowmini fields_str = all_fields; 6516e7801d59Ssowmini else 6517e7801d59Ssowmini fields_str = optarg; 6518e7801d59Ssowmini break; 6519e7801d59Ssowmini default: 65208d5c46e6Sam223141 die_opterr(optopt, option, use); 6521e7801d59Ssowmini break; 6522e7801d59Ssowmini } 6523e7801d59Ssowmini } 6524e7801d59Ssowmini 65250d365605Sschuster if (state.es_parseable && !o_arg) 65260d365605Sschuster die("-p requires -o"); 65270d365605Sschuster 65280d365605Sschuster if (state.es_parseable && fields_str == all_fields) 65290d365605Sschuster die("\"-o all\" is invalid with -p"); 65300d365605Sschuster 6531e7801d59Ssowmini if (optind == (argc - 1)) 6532e7801d59Ssowmini state.es_link = argv[optind]; 6533e7801d59Ssowmini 6534e7801d59Ssowmini fields = parse_output_fields(fields_str, ether_fields, 6535e7801d59Ssowmini ETHER_MAX_FIELDS, CMD_TYPE_ANY, &nfields); 6536e7801d59Ssowmini 6537e7801d59Ssowmini if (fields == NULL) { 6538e7801d59Ssowmini die("invalid field(s) specified"); 6539e7801d59Ssowmini exit(EXIT_FAILURE); 6540e7801d59Ssowmini } 6541e7801d59Ssowmini state.es_print.ps_fields = fields; 6542e7801d59Ssowmini state.es_print.ps_nfields = nfields; 6543e7801d59Ssowmini 6544e7801d59Ssowmini if (state.es_link == NULL) { 6545e7801d59Ssowmini (void) dladm_walk_datalink_id(show_etherprop, &state, 6546e7801d59Ssowmini DATALINK_CLASS_PHYS, DL_ETHER, 6547e7801d59Ssowmini DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST); 6548e7801d59Ssowmini } else { 6549e7801d59Ssowmini if (!link_is_ether(state.es_link, &linkid)) { 6550e7801d59Ssowmini die("invalid link specified"); 6551e7801d59Ssowmini } 6552e7801d59Ssowmini (void) show_etherprop(linkid, &state); 6553e7801d59Ssowmini } 6554e7801d59Ssowmini 6555e7801d59Ssowmini exit(DLADM_STATUS_OK); 6556e7801d59Ssowmini 6557e7801d59Ssowmini } 6558e7801d59Ssowmini 6559e7801d59Ssowmini static char * 6560e7801d59Ssowmini dladm_print_field(print_field_t *pf, void *arg) 6561e7801d59Ssowmini { 6562e7801d59Ssowmini char *value; 6563e7801d59Ssowmini 6564e7801d59Ssowmini value = (char *)arg + pf->pf_offset; 6565e7801d59Ssowmini return (value); 6566e7801d59Ssowmini } 6567e7801d59Ssowmini 6568e7801d59Ssowmini static int 6569e7801d59Ssowmini show_etherprop(datalink_id_t linkid, void *arg) 6570e7801d59Ssowmini { 6571e7801d59Ssowmini print_ether_state_t *statep = arg; 6572e7801d59Ssowmini char buf[DLADM_STRSIZE]; 6573e7801d59Ssowmini int speed; 6574e7801d59Ssowmini uint64_t s; 6575e7801d59Ssowmini uint32_t autoneg, pause, asmpause, adv_rf, cap_rf, lp_rf; 6576e7801d59Ssowmini ether_fields_buf_t ebuf; 6577e7801d59Ssowmini char speed_unit = 'M'; 6578e7801d59Ssowmini 65795f5c9f54SAnurag S. Maskey bzero(&ebuf, sizeof (ether_fields_buf_t)); 6580e7801d59Ssowmini if (dladm_datalink_id2info(linkid, NULL, NULL, NULL, 6581e7801d59Ssowmini ebuf.eth_link, sizeof (ebuf.eth_link)) != DLADM_STATUS_OK) { 6582e7801d59Ssowmini return (DLADM_WALK_CONTINUE); 6583e7801d59Ssowmini } 6584e7801d59Ssowmini 6585e7801d59Ssowmini if (!statep->es_header && !statep->es_parseable) { 6586e7801d59Ssowmini print_header(&statep->es_print); 6587e7801d59Ssowmini statep->es_header = B_TRUE; 6588e7801d59Ssowmini } 6589e7801d59Ssowmini (void) snprintf(ebuf.eth_ptype, sizeof (ebuf.eth_ptype), 6590e7801d59Ssowmini "%s", "current"); 6591e7801d59Ssowmini 6592e7801d59Ssowmini (void) dladm_get_single_mac_stat(linkid, "link_autoneg", 6593e7801d59Ssowmini KSTAT_DATA_UINT32, &autoneg); 6594e7801d59Ssowmini (void) snprintf(ebuf.eth_autoneg, sizeof (ebuf.eth_autoneg), 6595e7801d59Ssowmini "%s", (autoneg ? "yes" : "no")); 6596e7801d59Ssowmini 6597e7801d59Ssowmini (void) dladm_get_single_mac_stat(linkid, "link_pause", 6598e7801d59Ssowmini KSTAT_DATA_UINT32, &pause); 6599e7801d59Ssowmini (void) dladm_get_single_mac_stat(linkid, "link_asmpause", 6600e7801d59Ssowmini KSTAT_DATA_UINT32, &asmpause); 6601e7801d59Ssowmini (void) snprintf(ebuf.eth_pause, sizeof (ebuf.eth_pause), 6602e7801d59Ssowmini "%s", pause_str(pause, asmpause)); 6603e7801d59Ssowmini 6604e7801d59Ssowmini (void) dladm_get_single_mac_stat(linkid, "ifspeed", 6605e7801d59Ssowmini KSTAT_DATA_UINT64, &s); 6606e7801d59Ssowmini speed = (int)(s/1000000ull); 6607e7801d59Ssowmini 6608e7801d59Ssowmini if (speed >= 1000) { 6609e7801d59Ssowmini speed = speed/1000; 6610e7801d59Ssowmini speed_unit = 'G'; 6611e7801d59Ssowmini } 66124045d941Ssowmini (void) get_linkduplex(ebuf.eth_link, B_TRUE, buf); 6613e7801d59Ssowmini (void) snprintf(ebuf.eth_spdx, sizeof (ebuf.eth_spdx), "%d%c-%c", 6614e7801d59Ssowmini speed, speed_unit, buf[0]); 6615e7801d59Ssowmini 66164045d941Ssowmini (void) get_linkstate(ebuf.eth_link, B_TRUE, buf); 6617e7801d59Ssowmini (void) snprintf(ebuf.eth_state, sizeof (ebuf.eth_state), 6618e7801d59Ssowmini "%s", buf); 6619e7801d59Ssowmini 6620e7801d59Ssowmini (void) dladm_get_single_mac_stat(linkid, "adv_rem_fault", 6621e7801d59Ssowmini KSTAT_DATA_UINT32, &adv_rf); 6622e7801d59Ssowmini (void) dladm_get_single_mac_stat(linkid, "cap_rem_fault", 6623e7801d59Ssowmini KSTAT_DATA_UINT32, &cap_rf); 6624e7801d59Ssowmini (void) dladm_get_single_mac_stat(linkid, "lp_rem_fault", 6625e7801d59Ssowmini KSTAT_DATA_UINT32, &lp_rf); 6626e7801d59Ssowmini (void) snprintf(ebuf.eth_rem_fault, sizeof (ebuf.eth_rem_fault), 6627e7801d59Ssowmini "%s", (adv_rf == 0 && lp_rf == 0 ? "none" : "fault")); 6628e7801d59Ssowmini 6629e7801d59Ssowmini dladm_print_output(&statep->es_print, statep->es_parseable, 6630e7801d59Ssowmini dladm_print_field, &ebuf); 6631e7801d59Ssowmini 6632e7801d59Ssowmini if (statep->es_extended) 6633e7801d59Ssowmini show_ether_xprop(linkid, arg); 6634e7801d59Ssowmini 6635e7801d59Ssowmini return (DLADM_WALK_CONTINUE); 6636e7801d59Ssowmini } 6637e7801d59Ssowmini 6638e7801d59Ssowmini /* ARGSUSED */ 6639e7801d59Ssowmini static void 66408d5c46e6Sam223141 do_init_secobj(int argc, char **argv, const char *use) 66410ba2cbe9Sxc151355 { 66420ba2cbe9Sxc151355 dladm_status_t status; 66430ba2cbe9Sxc151355 66440ba2cbe9Sxc151355 status = dladm_init_secobj(); 664533343a97Smeem if (status != DLADM_STATUS_OK) 664633343a97Smeem die_dlerr(status, "secure object initialization failed"); 664733343a97Smeem } 664833343a97Smeem 6649d62bc4baSyz147064 /* 6650d62bc4baSyz147064 * "-R" option support. It is used for live upgrading. Append dladm commands 6651d62bc4baSyz147064 * to a upgrade script which will be run when the alternative root boots up: 6652d62bc4baSyz147064 * 6653b9e076dcSyz147064 * - If the /etc/dladm/datalink.conf file exists on the alternative root, 6654b9e076dcSyz147064 * append dladm commands to the <altroot>/var/svc/profile/upgrade_datalink 6655b9e076dcSyz147064 * script. This script will be run as part of the network/physical service. 6656b9e076dcSyz147064 * We cannot defer this to /var/svc/profile/upgrade because then the 6657b9e076dcSyz147064 * configuration will not be able to take effect before network/physical 6658b9e076dcSyz147064 * plumbs various interfaces. 6659d62bc4baSyz147064 * 6660b9e076dcSyz147064 * - If the /etc/dladm/datalink.conf file does not exist on the alternative 6661b9e076dcSyz147064 * root, append dladm commands to the <altroot>/var/svc/profile/upgrade script, 6662b9e076dcSyz147064 * which will be run in the manifest-import service. 6663d62bc4baSyz147064 * 6664d62bc4baSyz147064 * Note that the SMF team is considering to move the manifest-import service 6665d62bc4baSyz147064 * to be run at the very begining of boot. Once that is done, the need for 6666d62bc4baSyz147064 * the /var/svc/profile/upgrade_datalink script will not exist any more. 6667d62bc4baSyz147064 */ 6668d62bc4baSyz147064 static void 6669d62bc4baSyz147064 altroot_cmd(char *altroot, int argc, char *argv[]) 6670d62bc4baSyz147064 { 6671d62bc4baSyz147064 char path[MAXPATHLEN]; 6672d62bc4baSyz147064 struct stat stbuf; 6673d62bc4baSyz147064 FILE *fp; 6674d62bc4baSyz147064 int i; 6675d62bc4baSyz147064 6676d62bc4baSyz147064 /* 6677b9e076dcSyz147064 * Check for the existence of the /etc/dladm/datalink.conf 6678b9e076dcSyz147064 * configuration file, and determine the name of script file. 6679d62bc4baSyz147064 */ 6680b9e076dcSyz147064 (void) snprintf(path, MAXPATHLEN, "/%s/etc/dladm/datalink.conf", 6681b9e076dcSyz147064 altroot); 6682d62bc4baSyz147064 if (stat(path, &stbuf) < 0) { 6683d62bc4baSyz147064 (void) snprintf(path, MAXPATHLEN, "/%s/%s", altroot, 6684d62bc4baSyz147064 SMF_UPGRADE_FILE); 6685d62bc4baSyz147064 } else { 6686d62bc4baSyz147064 (void) snprintf(path, MAXPATHLEN, "/%s/%s", altroot, 6687d62bc4baSyz147064 SMF_UPGRADEDATALINK_FILE); 6688d62bc4baSyz147064 } 6689d62bc4baSyz147064 6690d62bc4baSyz147064 if ((fp = fopen(path, "a+")) == NULL) 6691d62bc4baSyz147064 die("operation not supported on %s", altroot); 6692d62bc4baSyz147064 6693d62bc4baSyz147064 (void) fprintf(fp, "/sbin/dladm "); 6694d62bc4baSyz147064 for (i = 0; i < argc; i++) { 6695d62bc4baSyz147064 /* 6696d62bc4baSyz147064 * Directly write to the file if it is not the "-R <altroot>" 6697d62bc4baSyz147064 * option. In which case, skip it. 6698d62bc4baSyz147064 */ 6699d62bc4baSyz147064 if (strcmp(argv[i], "-R") != 0) 6700d62bc4baSyz147064 (void) fprintf(fp, "%s ", argv[i]); 6701d62bc4baSyz147064 else 6702d62bc4baSyz147064 i ++; 6703d62bc4baSyz147064 } 6704d62bc4baSyz147064 (void) fprintf(fp, "%s\n", SMF_DLADM_UPGRADE_MSG); 6705d62bc4baSyz147064 (void) fclose(fp); 6706d62bc4baSyz147064 exit(0); 6707d62bc4baSyz147064 } 6708d62bc4baSyz147064 6709d62bc4baSyz147064 /* 6710d62bc4baSyz147064 * Convert the string to an integer. Note that the string must not have any 6711d62bc4baSyz147064 * trailing non-integer characters. 6712d62bc4baSyz147064 */ 671333343a97Smeem static boolean_t 671433343a97Smeem str2int(const char *str, int *valp) 671533343a97Smeem { 671633343a97Smeem int val; 671733343a97Smeem char *endp = NULL; 671833343a97Smeem 671933343a97Smeem errno = 0; 672033343a97Smeem val = strtol(str, &endp, 10); 672133343a97Smeem if (errno != 0 || *endp != '\0') 672233343a97Smeem return (B_FALSE); 672333343a97Smeem 672433343a97Smeem *valp = val; 672533343a97Smeem return (B_TRUE); 672633343a97Smeem } 672733343a97Smeem 672833343a97Smeem /* PRINTFLIKE1 */ 672933343a97Smeem static void 673033343a97Smeem warn(const char *format, ...) 673133343a97Smeem { 673233343a97Smeem va_list alist; 673333343a97Smeem 673433343a97Smeem format = gettext(format); 673533343a97Smeem (void) fprintf(stderr, "%s: warning: ", progname); 673633343a97Smeem 673733343a97Smeem va_start(alist, format); 673833343a97Smeem (void) vfprintf(stderr, format, alist); 673933343a97Smeem va_end(alist); 674033343a97Smeem 674133343a97Smeem (void) putchar('\n'); 674233343a97Smeem } 674333343a97Smeem 674433343a97Smeem /* PRINTFLIKE2 */ 674533343a97Smeem static void 674633343a97Smeem warn_dlerr(dladm_status_t err, const char *format, ...) 674733343a97Smeem { 674833343a97Smeem va_list alist; 674933343a97Smeem char errmsg[DLADM_STRSIZE]; 675033343a97Smeem 675133343a97Smeem format = gettext(format); 675233343a97Smeem (void) fprintf(stderr, gettext("%s: warning: "), progname); 675333343a97Smeem 675433343a97Smeem va_start(alist, format); 675533343a97Smeem (void) vfprintf(stderr, format, alist); 675633343a97Smeem va_end(alist); 675733343a97Smeem (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg)); 675833343a97Smeem } 675933343a97Smeem 676033343a97Smeem /* PRINTFLIKE2 */ 676133343a97Smeem static void 676233343a97Smeem die_dlerr(dladm_status_t err, const char *format, ...) 676333343a97Smeem { 676433343a97Smeem va_list alist; 676533343a97Smeem char errmsg[DLADM_STRSIZE]; 676633343a97Smeem 676733343a97Smeem format = gettext(format); 676833343a97Smeem (void) fprintf(stderr, "%s: ", progname); 676933343a97Smeem 677033343a97Smeem va_start(alist, format); 677133343a97Smeem (void) vfprintf(stderr, format, alist); 677233343a97Smeem va_end(alist); 677333343a97Smeem (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg)); 677433343a97Smeem 677533343a97Smeem exit(EXIT_FAILURE); 677633343a97Smeem } 677733343a97Smeem 677833343a97Smeem /* PRINTFLIKE1 */ 677933343a97Smeem static void 678033343a97Smeem die(const char *format, ...) 678133343a97Smeem { 678233343a97Smeem va_list alist; 678333343a97Smeem 678433343a97Smeem format = gettext(format); 678533343a97Smeem (void) fprintf(stderr, "%s: ", progname); 678633343a97Smeem 678733343a97Smeem va_start(alist, format); 678833343a97Smeem (void) vfprintf(stderr, format, alist); 678933343a97Smeem va_end(alist); 679033343a97Smeem 679133343a97Smeem (void) putchar('\n'); 679233343a97Smeem exit(EXIT_FAILURE); 679333343a97Smeem } 679433343a97Smeem 679533343a97Smeem static void 679633343a97Smeem die_optdup(int opt) 679733343a97Smeem { 679833343a97Smeem die("the option -%c cannot be specified more than once", opt); 679933343a97Smeem } 680033343a97Smeem 680133343a97Smeem static void 68028d5c46e6Sam223141 die_opterr(int opt, int opterr, const char *usage) 680333343a97Smeem { 680433343a97Smeem switch (opterr) { 680533343a97Smeem case ':': 68068d5c46e6Sam223141 die("option '-%c' requires a value\nusage: %s", opt, 68078d5c46e6Sam223141 gettext(usage)); 680833343a97Smeem break; 680933343a97Smeem case '?': 681033343a97Smeem default: 68118d5c46e6Sam223141 die("unrecognized option '-%c'\nusage: %s", opt, 68128d5c46e6Sam223141 gettext(usage)); 681333343a97Smeem break; 68140ba2cbe9Sxc151355 } 68150ba2cbe9Sxc151355 } 6816e7801d59Ssowmini 6817e7801d59Ssowmini static void 6818e7801d59Ssowmini show_ether_xprop(datalink_id_t linkid, void *arg) 6819e7801d59Ssowmini { 6820e7801d59Ssowmini print_ether_state_t *statep = arg; 6821e7801d59Ssowmini char buf[DLADM_STRSIZE]; 6822e7801d59Ssowmini uint32_t autoneg, pause, asmpause, adv_rf, cap_rf, lp_rf; 6823e7801d59Ssowmini boolean_t add_comma, r1; 6824e7801d59Ssowmini ether_fields_buf_t ebuf; 6825e7801d59Ssowmini 6826e7801d59Ssowmini /* capable */ 6827e7801d59Ssowmini bzero(&ebuf, sizeof (ebuf)); 6828e7801d59Ssowmini (void) snprintf(ebuf.eth_link, sizeof (ebuf.eth_link), ""); 6829e7801d59Ssowmini 6830e7801d59Ssowmini (void) snprintf(ebuf.eth_ptype, sizeof (ebuf.eth_ptype), 6831e7801d59Ssowmini "%s", "capable"); 68320d365605Sschuster (void) snprintf(ebuf.eth_state, sizeof (ebuf.eth_state), ""); 6833e7801d59Ssowmini 6834e7801d59Ssowmini (void) dladm_get_single_mac_stat(linkid, "cap_autoneg", 6835e7801d59Ssowmini KSTAT_DATA_UINT32, &autoneg); 6836e7801d59Ssowmini (void) snprintf(ebuf.eth_autoneg, sizeof (ebuf.eth_autoneg), 6837e7801d59Ssowmini "%s", (autoneg ? "yes" : "no")); 6838e7801d59Ssowmini 6839e7801d59Ssowmini add_comma = B_FALSE; 6840e7801d59Ssowmini bzero(buf, sizeof (buf)); 6841e7801d59Ssowmini r1 = get_speed_duplex(linkid, "cap_1000", buf, "1G", B_FALSE); 6842e7801d59Ssowmini if (r1) 6843e7801d59Ssowmini add_comma = B_TRUE; 6844e7801d59Ssowmini r1 = get_speed_duplex(linkid, "cap_100", buf, "100M", add_comma); 6845e7801d59Ssowmini if (r1) 6846e7801d59Ssowmini add_comma = B_TRUE; 6847e7801d59Ssowmini r1 = get_speed_duplex(linkid, "cap_10", buf, "10M", add_comma); 6848e7801d59Ssowmini add_comma = B_FALSE; 6849e7801d59Ssowmini (void) snprintf(ebuf.eth_spdx, sizeof (ebuf.eth_spdx), "%s", buf); 6850e7801d59Ssowmini 6851e7801d59Ssowmini (void) dladm_get_single_mac_stat(linkid, "cap_pause", 6852e7801d59Ssowmini KSTAT_DATA_UINT32, &pause); 6853e7801d59Ssowmini (void) dladm_get_single_mac_stat(linkid, "cap_asmpause", 6854e7801d59Ssowmini KSTAT_DATA_UINT32, &asmpause); 6855e7801d59Ssowmini (void) snprintf(ebuf.eth_pause, sizeof (ebuf.eth_pause), 6856e7801d59Ssowmini "%s", pause_str(pause, asmpause)); 6857e7801d59Ssowmini 6858e7801d59Ssowmini (void) dladm_get_single_mac_stat(linkid, "adv_rem_fault", 6859e7801d59Ssowmini KSTAT_DATA_UINT32, &adv_rf); 6860e7801d59Ssowmini (void) dladm_get_single_mac_stat(linkid, "cap_rem_fault", 6861e7801d59Ssowmini KSTAT_DATA_UINT32, &cap_rf); 6862e7801d59Ssowmini (void) dladm_get_single_mac_stat(linkid, "lp_rem_fault", 6863e7801d59Ssowmini KSTAT_DATA_UINT32, &lp_rf); 6864e7801d59Ssowmini 6865e7801d59Ssowmini (void) snprintf(ebuf.eth_rem_fault, sizeof (ebuf.eth_rem_fault), 6866e7801d59Ssowmini "%s", (cap_rf ? "yes" : "no")); 6867e7801d59Ssowmini 6868e7801d59Ssowmini dladm_print_output(&statep->es_print, statep->es_parseable, 6869e7801d59Ssowmini dladm_print_field, &ebuf); 6870e7801d59Ssowmini 6871e7801d59Ssowmini /* advertised */ 6872e7801d59Ssowmini bzero(&ebuf, sizeof (ebuf)); 6873e7801d59Ssowmini (void) snprintf(ebuf.eth_ptype, sizeof (ebuf.eth_ptype), 6874e7801d59Ssowmini "%s", "adv"); 68750d365605Sschuster (void) snprintf(ebuf.eth_state, sizeof (ebuf.eth_state), ""); 6876e7801d59Ssowmini 6877e7801d59Ssowmini (void) dladm_get_single_mac_stat(linkid, "adv_cap_autoneg", 6878e7801d59Ssowmini KSTAT_DATA_UINT32, &autoneg); 6879e7801d59Ssowmini (void) snprintf(ebuf.eth_autoneg, sizeof (ebuf.eth_autoneg), 6880e7801d59Ssowmini "%s", (autoneg ? "yes" : "no")); 6881e7801d59Ssowmini 6882e7801d59Ssowmini add_comma = B_FALSE; 6883e7801d59Ssowmini bzero(buf, sizeof (buf)); 6884e7801d59Ssowmini r1 = get_speed_duplex(linkid, "adv_cap_1000", buf, "1G", add_comma); 6885e7801d59Ssowmini if (r1) 6886e7801d59Ssowmini add_comma = B_TRUE; 6887e7801d59Ssowmini r1 = get_speed_duplex(linkid, "adv_cap_100", buf, "100M", add_comma); 6888e7801d59Ssowmini if (r1) 6889e7801d59Ssowmini add_comma = B_TRUE; 6890e7801d59Ssowmini r1 = get_speed_duplex(linkid, "adv_cap_10", buf, "10M", add_comma); 6891e7801d59Ssowmini add_comma = B_FALSE; 6892e7801d59Ssowmini (void) snprintf(ebuf.eth_spdx, sizeof (ebuf.eth_spdx), "%s", buf); 6893e7801d59Ssowmini 6894e7801d59Ssowmini (void) dladm_get_single_mac_stat(linkid, "adv_cap_pause", 6895e7801d59Ssowmini KSTAT_DATA_UINT32, &pause); 6896e7801d59Ssowmini (void) dladm_get_single_mac_stat(linkid, "adv_cap_asmpause", 6897e7801d59Ssowmini KSTAT_DATA_UINT32, &asmpause); 6898e7801d59Ssowmini (void) snprintf(ebuf.eth_pause, sizeof (ebuf.eth_pause), 6899e7801d59Ssowmini "%s", pause_str(pause, asmpause)); 6900e7801d59Ssowmini 6901e7801d59Ssowmini (void) snprintf(ebuf.eth_rem_fault, sizeof (ebuf.eth_rem_fault), 6902e7801d59Ssowmini "%s", (adv_rf ? "fault" : "none")); 6903e7801d59Ssowmini 6904e7801d59Ssowmini dladm_print_output(&statep->es_print, statep->es_parseable, 6905e7801d59Ssowmini dladm_print_field, &ebuf); 6906e7801d59Ssowmini 6907e7801d59Ssowmini /* peeradv */ 6908e7801d59Ssowmini bzero(&ebuf, sizeof (ebuf)); 6909e7801d59Ssowmini (void) snprintf(ebuf.eth_ptype, sizeof (ebuf.eth_ptype), 6910e7801d59Ssowmini "%s", "peeradv"); 69110d365605Sschuster (void) snprintf(ebuf.eth_state, sizeof (ebuf.eth_state), ""); 6912*da14cebeSEric Cheng 6913e7801d59Ssowmini (void) dladm_get_single_mac_stat(linkid, "lp_cap_autoneg", 6914e7801d59Ssowmini KSTAT_DATA_UINT32, &autoneg); 6915e7801d59Ssowmini (void) snprintf(ebuf.eth_autoneg, sizeof (ebuf.eth_autoneg), 6916e7801d59Ssowmini "%s", (autoneg ? "yes" : "no")); 6917e7801d59Ssowmini 6918e7801d59Ssowmini add_comma = B_FALSE; 6919e7801d59Ssowmini bzero(buf, sizeof (buf)); 6920e7801d59Ssowmini r1 = get_speed_duplex(linkid, "lp_cap_1000", buf, "1G", add_comma); 6921e7801d59Ssowmini if (r1) 6922e7801d59Ssowmini add_comma = B_TRUE; 6923e7801d59Ssowmini r1 = get_speed_duplex(linkid, "lp_cap_100", buf, "100M", add_comma); 6924e7801d59Ssowmini if (r1) 6925e7801d59Ssowmini add_comma = B_TRUE; 6926e7801d59Ssowmini r1 = get_speed_duplex(linkid, "lp_cap_10", buf, "10M", add_comma); 6927e7801d59Ssowmini (void) snprintf(ebuf.eth_spdx, sizeof (ebuf.eth_spdx), "%s", buf); 6928e7801d59Ssowmini 6929e7801d59Ssowmini (void) dladm_get_single_mac_stat(linkid, "lp_cap_pause", 6930e7801d59Ssowmini KSTAT_DATA_UINT32, &pause); 6931e7801d59Ssowmini (void) dladm_get_single_mac_stat(linkid, "lp_cap_asmpause", 6932e7801d59Ssowmini KSTAT_DATA_UINT32, &asmpause); 6933e7801d59Ssowmini (void) snprintf(ebuf.eth_pause, sizeof (ebuf.eth_pause), 6934e7801d59Ssowmini "%s", pause_str(pause, asmpause)); 6935e7801d59Ssowmini 6936e7801d59Ssowmini (void) snprintf(ebuf.eth_rem_fault, sizeof (ebuf.eth_rem_fault), 6937e7801d59Ssowmini "%s", (lp_rf ? "fault" : "none")); 6938e7801d59Ssowmini 6939e7801d59Ssowmini dladm_print_output(&statep->es_print, statep->es_parseable, 6940e7801d59Ssowmini dladm_print_field, &ebuf); 6941e7801d59Ssowmini } 6942e7801d59Ssowmini 6943e7801d59Ssowmini static boolean_t 6944e7801d59Ssowmini get_speed_duplex(datalink_id_t linkid, const char *mii_prop_prefix, 6945e7801d59Ssowmini char *spbuf, char *sp, boolean_t add_comma) 6946e7801d59Ssowmini { 6947e7801d59Ssowmini int speed, duplex = 0; 6948e7801d59Ssowmini boolean_t ret = B_FALSE; 6949e7801d59Ssowmini char mii_prop[DLADM_STRSIZE]; 6950e7801d59Ssowmini 6951e7801d59Ssowmini (void) snprintf(mii_prop, DLADM_STRSIZE, "%sfdx", mii_prop_prefix); 6952e7801d59Ssowmini (void) dladm_get_single_mac_stat(linkid, mii_prop, KSTAT_DATA_UINT32, 6953e7801d59Ssowmini &speed); 6954e7801d59Ssowmini if (speed) { 6955e7801d59Ssowmini ret = B_TRUE; 6956e7801d59Ssowmini duplex |= IS_FDX; 6957e7801d59Ssowmini } 6958e7801d59Ssowmini (void) snprintf(mii_prop, DLADM_STRSIZE, "%shdx", mii_prop_prefix); 6959e7801d59Ssowmini (void) dladm_get_single_mac_stat(linkid, mii_prop, 6960e7801d59Ssowmini KSTAT_DATA_UINT32, &speed); 6961e7801d59Ssowmini if (speed) { 6962e7801d59Ssowmini ret = B_TRUE; 6963e7801d59Ssowmini duplex |= IS_HDX; 6964e7801d59Ssowmini } 6965e7801d59Ssowmini if (ret) { 6966e7801d59Ssowmini if (add_comma) 6967e7801d59Ssowmini (void) strncat(spbuf, ",", DLADM_STRSIZE); 6968e7801d59Ssowmini (void) strncat(spbuf, sp, DLADM_STRSIZE); 6969e7801d59Ssowmini if ((duplex & (IS_FDX|IS_HDX)) == (IS_FDX|IS_HDX)) 6970e7801d59Ssowmini (void) strncat(spbuf, "-fh", DLADM_STRSIZE); 6971e7801d59Ssowmini else if (duplex & IS_FDX) 6972e7801d59Ssowmini (void) strncat(spbuf, "-f", DLADM_STRSIZE); 6973e7801d59Ssowmini else if (duplex & IS_HDX) 6974e7801d59Ssowmini (void) strncat(spbuf, "-h", DLADM_STRSIZE); 6975e7801d59Ssowmini } 6976e7801d59Ssowmini return (ret); 6977e7801d59Ssowmini } 6978e7801d59Ssowmini 6979e7801d59Ssowmini static void 6980e7801d59Ssowmini dladm_print_output(print_state_t *statep, boolean_t parseable, 6981e7801d59Ssowmini print_callback_t fn, void *arg) 6982e7801d59Ssowmini { 6983e7801d59Ssowmini int i; 6984e7801d59Ssowmini char *value; 6985e7801d59Ssowmini print_field_t **pf; 6986e7801d59Ssowmini 6987e7801d59Ssowmini pf = statep->ps_fields; 6988e7801d59Ssowmini for (i = 0; i < statep->ps_nfields; i++) { 6989e7801d59Ssowmini statep->ps_lastfield = (i + 1 == statep->ps_nfields); 6990e7801d59Ssowmini value = (*fn)(pf[i], arg); 6991e7801d59Ssowmini if (value != NULL) 6992e7801d59Ssowmini print_field(statep, pf[i], value, parseable); 6993e7801d59Ssowmini } 6994e7801d59Ssowmini (void) putchar('\n'); 6995e7801d59Ssowmini } 6996e7801d59Ssowmini 6997e7801d59Ssowmini static void 6998e7801d59Ssowmini print_header(print_state_t *ps) 6999e7801d59Ssowmini { 7000e7801d59Ssowmini int i; 7001e7801d59Ssowmini print_field_t **pf; 7002e7801d59Ssowmini 7003e7801d59Ssowmini pf = ps->ps_fields; 7004e7801d59Ssowmini for (i = 0; i < ps->ps_nfields; i++) { 7005e7801d59Ssowmini ps->ps_lastfield = (i + 1 == ps->ps_nfields); 7006e7801d59Ssowmini print_field(ps, pf[i], pf[i]->pf_header, B_FALSE); 7007e7801d59Ssowmini } 7008e7801d59Ssowmini (void) putchar('\n'); 7009e7801d59Ssowmini } 7010e7801d59Ssowmini 7011e7801d59Ssowmini static char * 7012e7801d59Ssowmini pause_str(int pause, int asmpause) 7013e7801d59Ssowmini { 7014e7801d59Ssowmini if (pause == 1) 7015e7801d59Ssowmini return ("bi"); 7016e7801d59Ssowmini if (asmpause == 1) 7017e7801d59Ssowmini return ("tx"); 7018e7801d59Ssowmini return ("none"); 7019e7801d59Ssowmini } 7020e7801d59Ssowmini 7021e7801d59Ssowmini static boolean_t 7022e7801d59Ssowmini link_is_ether(const char *link, datalink_id_t *linkid) 7023e7801d59Ssowmini { 7024e7801d59Ssowmini uint32_t media; 7025e7801d59Ssowmini datalink_class_t class; 7026e7801d59Ssowmini 7027e7801d59Ssowmini if (dladm_name2info(link, linkid, NULL, &class, &media) == 7028e7801d59Ssowmini DLADM_STATUS_OK) { 7029e7801d59Ssowmini if (class == DATALINK_CLASS_PHYS && media == DL_ETHER) 7030e7801d59Ssowmini return (B_TRUE); 7031e7801d59Ssowmini } 7032e7801d59Ssowmini return (B_FALSE); 7033e7801d59Ssowmini } 7034