diff options
Diffstat (limited to 'usr/src')
34 files changed, 3748 insertions, 1026 deletions
diff --git a/usr/src/cmd/dladm/dladm.c b/usr/src/cmd/dladm/dladm.c index 22cc5c515e..0de78dfd63 100644 --- a/usr/src/cmd/dladm/dladm.c +++ b/usr/src/cmd/dladm/dladm.c @@ -56,8 +56,10 @@ #include <libinetutil.h> #include <bsm/adt.h> #include <bsm/adt_event.h> +#include <stddef.h> #define AGGR_DRV "aggr" +#define STR_UNDEF_VAL "--" #define MAXPORT 256 #define BUFLEN(lim, ptr) (((lim) > (ptr)) ? ((lim) - (ptr)) : 0) #define MAXLINELEN 1024 @@ -65,6 +67,132 @@ #define SMF_UPGRADEDATALINK_FILE "/var/svc/profile/upgrade_datalink" #define SMF_DLADM_UPGRADE_MSG " # added by dladm(1M)" +#define CMD_TYPE_ANY 0xffffffff +#define WIFI_CMD_SCAN 0x00000001 +#define WIFI_CMD_SHOW 0x00000002 +#define WIFI_CMD_ALL (WIFI_CMD_SCAN | WIFI_CMD_SHOW) + +/* + * data structures and routines for printing output. + * All non-parseable output is assumed to be in a columnar format. + * Parseable output will be printed as <pf_header>="<value>" + * + * Each sub-command is associated with a global array of pointers, + * print_field_t *fields[], where the print_field_t contains information + * about the format in which the output is to be printed. + * + * Sub-commands may be implemented in one of two ways: + * (i) the implementation could get all field values into a character + * buffer, with pf_offset containing the offset (for pf_name) within + * the buffer. The sub-command would make the needed system calls + * to obtain all possible column values and then invoke the + * dladm_print_field() function to print the specific fields + * requested in the command line. See the comments for dladm_print_field + * for further details. + * (ii) Alternatively, each fields[i] entry could store a pf_index value + * that uniquely identifies the column to be printed. The implementation + * of the sub-command would then invoke dladm_print_output() with a + * callback function whose semantics are described below (see comments + * for dladm_print_output()) + * + * Thus, an implementation of a sub-command must provide the following: + * + * static print_field_t sub_command_fields[] = { + * {<name>, <header>,<field width>, <offset_or_index>, cmdtype}, + * : + * {<name>, <header>,<field width>, <offset_or_index>, cmdtype} + * }; + * + * #define SUB_COMMAND_MAX_FIELDS sizeof \ + * (sub_comand_fields) / sizeof (print_field_t)) + * + * print_state_t sub_command_print_state; + * + * The function that parses command line arguments (typically + * do_sub_command()) should then contain an invocation like: + * + * fields = parse_output_fields(fields_str, sub_command_fields, + * SUB_COMMAND_MAX_FIELDS, CMD_TYPE_ANY, &nfields); + * + * and store the resulting fields and nfields value in a print_state_t + * structure tracked for the command. + * + * sub_command_print_state.ps_fields = fields; + * sub_command_print_state.ps_nfields = nfields; + * + * To print the column header for the output, the print_header() + * function must then be invoked by do_sub_command(). + * + * Then if method (i) is used for the sub_command, the do_sub_command() + * function should make the necessary system calls to fill up the buffer + * and then invoke dladm_print_field(). An example of this method is + * the implementation of do_show_link() and show_link(); + * + * If method (ii) is used, do_sub_command should invoke dladm_print_output() + * with a callback function that will be called for each field to be printed. + * The callback function will be passed a pointer to the print_field_t + * for the field, and the pf_index may then be used to identify the + * system call required to find the value to be printed. An example of + * this implementation may be found in the do_show_dev() and print_dev() + * invocation. + */ + +typedef struct print_field_s { + const char *pf_name; /* name of column to be printed */ + const char *pf_header; /* header for this column */ + uint_t pf_width; + union { + uint_t _pf_index; /* private index for sub-command */ + size_t _pf_offset; + }_pf_un; +#define pf_index _pf_un._pf_index +#define pf_offset _pf_un._pf_offset; + uint_t pf_cmdtype; +} print_field_t; + +/* + * The state of the output is tracked in a print_state_t structure. + * Each ps_fields[i] entry points at the global print_field_t array for + * the sub-command, where ps_nfields is the number of requested fields. + */ +typedef struct print_state_s { + print_field_t **ps_fields; + uint_t ps_nfields; + boolean_t ps_lastfield; + uint_t ps_overflow; +} print_state_t; + +typedef char *(*print_callback_t)(print_field_t *, void *); +static print_field_t **parse_output_fields(char *, print_field_t *, int, + uint_t, uint_t *); +/* + * print the header for the output + */ +static void print_header(print_state_t *); +static void print_field(print_state_t *, print_field_t *, const char *, + boolean_t); + +/* + * to print output values, call dladm_print_output with a callback + * function (*func)() that should parse the args and return an + * unformatted character buffer with the value to be printed. + * + * dladm_print_output() prints the character buffer using the formatting + * information provided in the print_field_t for that column. + */ +static void dladm_print_output(print_state_t *, boolean_t, + print_callback_t, void *); + +/* + * helper function that, when invoked as dladm_print_field(pf, buf) + * prints string which is offset by pf->pf_offset within buf + */ +static char *dladm_print_field(print_field_t *, void *); + + +#define MAX_FIELD_LEN 32 + + typedef struct pktsum_s { uint64_t ipackets; uint64_t opackets; @@ -78,21 +206,25 @@ typedef struct show_state { boolean_t ls_firstonly; boolean_t ls_donefirst; pktsum_t ls_prevstats; - boolean_t ls_parseable; uint32_t ls_flags; dladm_status_t ls_status; + print_state_t ls_print; + boolean_t ls_parseable; + boolean_t ls_printheader; } show_state_t; typedef struct show_grp_state { + pktsum_t gs_prevstats[MAXPORT]; + uint32_t gs_flags; + dladm_status_t gs_status; + boolean_t gs_parseable; boolean_t gs_lacp; boolean_t gs_extended; boolean_t gs_stats; boolean_t gs_firstonly; boolean_t gs_donefirst; - pktsum_t gs_prevstats[MAXPORT]; - boolean_t gs_parseable; - uint32_t gs_flags; - dladm_status_t gs_status; + boolean_t gs_printheader; + print_state_t gs_print; } show_grp_state_t; typedef void cmdfunc_t(int, char **); @@ -107,13 +239,14 @@ static cmdfunc_t do_init_linkprop, do_init_secobj; static cmdfunc_t do_create_vlan, do_delete_vlan, do_up_vlan, do_show_vlan; static cmdfunc_t do_rename_link, do_delete_phys, do_init_phys; static cmdfunc_t do_show_linkmap; +static cmdfunc_t do_show_ether; static void altroot_cmd(char *, int, char **); static int show_linkprop_onelink(datalink_id_t, void *); static void link_stats(datalink_id_t, uint_t); static void aggr_stats(datalink_id_t, show_grp_state_t *, uint_t); -static void dev_stats(const char *dev, uint32_t); +static void dev_stats(const char *dev, uint32_t, char *, show_state_t *); static int get_one_kstat(const char *, const char *, uint8_t, void *, boolean_t); @@ -125,6 +258,16 @@ static void stats_diff(pktsum_t *, pktsum_t *, pktsum_t *); static const char *get_linkstate(const char *, boolean_t, char *); static const char *get_linkduplex(const char *, boolean_t, char *); +static int show_etherprop(datalink_id_t, void *); +static void show_ether_xprop(datalink_id_t, void *); +static boolean_t get_speed_duplex(datalink_id_t, const char *, char *, + char *, boolean_t); +static char *pause_str(int, int); +static boolean_t link_is_ether(const char *, datalink_id_t *); + +#define IS_FDX 0x10 +#define IS_HDX 0x01 + static boolean_t str2int(const char *, int *); static void die(const char *, ...); static void die_optdup(int); @@ -155,6 +298,7 @@ static cmd_t cmds[] = { { "show-linkprop", do_show_linkprop }, { "set-linkprop", do_set_linkprop }, { "reset-linkprop", do_reset_linkprop }, + { "show-ether", do_show_ether }, { "create-secobj", do_create_secobj }, { "delete-secobj", do_delete_secobj }, { "show-secobj", do_show_secobj }, @@ -173,6 +317,7 @@ static cmd_t cmds[] = { static const struct option lopts[] = { {"vlan-id", required_argument, 0, 'v'}, + {"output", required_argument, 0, 'o'}, {"dev", required_argument, 0, 'd'}, {"policy", required_argument, 0, 'P'}, {"lacp-mode", required_argument, 0, 'L'}, @@ -190,6 +335,7 @@ static const struct option show_lopts[] = { {"interval", required_argument, 0, 'i'}, {"parseable", no_argument, 0, 'p'}, {"extended", no_argument, 0, 'x'}, + {"output", required_argument, 0, 'o'}, {"persistent", no_argument, 0, 'P'}, {"lacp", no_argument, 0, 'L'}, { 0, 0, 0, 0 } @@ -197,6 +343,7 @@ static const struct option show_lopts[] = { static const struct option prop_longopts[] = { {"temporary", no_argument, 0, 't' }, + {"output", required_argument, 0, 'o' }, {"root-dir", required_argument, 0, 'R' }, {"prop", required_argument, 0, 'p' }, {"parseable", no_argument, 0, 'c' }, @@ -222,6 +369,418 @@ static const struct option wifi_longopts[] = { {"file", required_argument, 0, 'f' }, { 0, 0, 0, 0 } }; +static const struct option showeth_lopts[] = { + {"parseable", no_argument, 0, 'p' }, + {"extended", no_argument, 0, 'x' }, + {"output", required_argument, 0, 'o' }, + { 0, 0, 0, 0 } +}; + +/* + * structures for 'dladm show-ether' + */ +typedef struct ether_fields_buf_s +{ + char eth_link[15]; + char eth_ptype[8]; + char eth_state[8]; + char eth_autoneg[5]; + char eth_spdx[31]; + char eth_pause[6]; + char eth_rem_fault[16]; +} ether_fields_buf_t; + +static print_field_t ether_fields[] = { +/* name, header, field width, offset, cmdtype */ +{ "link", "LINK", 15, + offsetof(ether_fields_buf_t, eth_link), CMD_TYPE_ANY}, +{ "ptype", "PTYPE", 8, + offsetof(ether_fields_buf_t, eth_ptype), CMD_TYPE_ANY}, +{ "state", "STATE", 8, + offsetof(ether_fields_buf_t, eth_state), CMD_TYPE_ANY}, +{ "auto", "AUTO", 5, + offsetof(ether_fields_buf_t, eth_autoneg), CMD_TYPE_ANY}, +{ "speed-duplex", "SPEED-DUPLEX", 31, + offsetof(ether_fields_buf_t, eth_spdx), CMD_TYPE_ANY}, +{ "pause", "PAUSE", 6, + offsetof(ether_fields_buf_t, eth_pause), CMD_TYPE_ANY}, +{ "rem_fault", "REM_FAULT", 16, + offsetof(ether_fields_buf_t, eth_rem_fault), CMD_TYPE_ANY}} +; +#define ETHER_MAX_FIELDS (sizeof (ether_fields) / sizeof (print_field_t)) + +typedef struct print_ether_state { + const char *es_link; + boolean_t es_parseable; + boolean_t es_header; + boolean_t es_extended; + print_state_t es_print; +} print_ether_state_t; + +/* + * structures for 'dladm show-dev'. + */ +typedef enum { + DEV_LINK, + DEV_STATE, + DEV_SPEED, + DEV_DUPLEX +} dev_field_index_t; + +static print_field_t dev_fields[] = { +/* name, header, field width, index, cmdtype */ +{ "link", "LINK", 15, DEV_LINK, CMD_TYPE_ANY}, +{ "state", "STATE", 6, DEV_STATE, CMD_TYPE_ANY}, +{ "speed", "SPEED", 8, DEV_SPEED, CMD_TYPE_ANY}, +{ "duplex", "DUPLEX", 8, DEV_DUPLEX, CMD_TYPE_ANY}} +; +#define DEV_MAX_FIELDS (sizeof (dev_fields) / sizeof (print_field_t)) + +/* + * structures for 'dladm show-dev -s' (print statistics) + */ +typedef enum { + DEVS_LINK, + DEVS_IPKTS, + DEVS_RBYTES, + DEVS_IERRORS, + DEVS_OPKTS, + DEVS_OBYTES, + DEVS_OERRORS +} devs_field_index_t; + +static print_field_t devs_fields[] = { +/* name, header, field width, index, cmdtype */ +{ "link", "LINK", 15, DEVS_LINK, CMD_TYPE_ANY}, +{ "ipackets", "IPACKETS", 10, DEVS_IPKTS, CMD_TYPE_ANY}, +{ "rbytes", "RBYTES", 8, DEVS_RBYTES, CMD_TYPE_ANY}, +{ "ierrors", "IERRORS", 10, DEVS_IERRORS, CMD_TYPE_ANY}, +{ "opackets", "OPACKETS", 12, DEVS_OPKTS, CMD_TYPE_ANY}, +{ "obytes", "OBYTES", 12, DEVS_OBYTES, CMD_TYPE_ANY}, +{ "oerrors", "OERRORS", 8, DEVS_OERRORS, CMD_TYPE_ANY}} +; +#define DEVS_MAX_FIELDS (sizeof (devs_fields) / sizeof (print_field_t)) +typedef struct dev_args_s { + char *devs_link; + pktsum_t *devs_psum; +} dev_args_t; +static char *print_dev_stats(print_field_t *, void *); +static char *print_dev(print_field_t *, void *); + +/* + * buffer used by print functions for show-{link,phys,vlan} commands. + */ +typedef struct link_fields_buf_s { + char link_name[MAXLINKNAMELEN]; + char link_class[DLADM_STRSIZE]; + char link_mtu[6]; + char link_state[DLADM_STRSIZE]; + char link_over[MAXLINKNAMELEN]; + char link_phys_state[6]; + char link_phys_media[DLADM_STRSIZE]; + char link_phys_speed[DLADM_STRSIZE]; + char link_phys_duplex[DLPI_LINKNAME_MAX]; + char link_phys_device[DLPI_LINKNAME_MAX]; + char link_flags[6]; + char link_vlan_vid[6]; +} link_fields_buf_t; + +/* + * structures for 'dladm show-link' + */ +static print_field_t link_fields[] = { +/* name, header, field width, offset, cmdtype */ +{ "link", "LINK", 11, + offsetof(link_fields_buf_t, link_name), CMD_TYPE_ANY}, +{ "class", "CLASS", 8, + offsetof(link_fields_buf_t, link_class), CMD_TYPE_ANY}, +{ "mtu", "MTU", 6, + offsetof(link_fields_buf_t, link_mtu), CMD_TYPE_ANY}, +{ "state", "STATE", 8, + offsetof(link_fields_buf_t, link_state), CMD_TYPE_ANY}, +{ "over", "OVER", DLPI_LINKNAME_MAX, + offsetof(link_fields_buf_t, link_over), CMD_TYPE_ANY}} +; +#define DEV_LINK_FIELDS (sizeof (link_fields) / sizeof (print_field_t)) + +/* + * structures for 'dladm show-aggr' + */ +typedef struct laggr_fields_buf_s { + char laggr_name[DLPI_LINKNAME_MAX]; + char laggr_policy[9]; + char laggr_addrpolicy[ETHERADDRL * 3 + 3]; + char laggr_lacpactivity[14]; + char laggr_lacptimer[DLADM_STRSIZE]; + char laggr_flags[7]; +} laggr_fields_buf_t; + +typedef struct laggr_args_s { + int laggr_lport; /* -1 indicates the aggr itself */ + const char *laggr_link; + dladm_aggr_grp_attr_t *laggr_ginfop; + dladm_status_t *laggr_status; + pktsum_t *laggr_pktsumtot; /* -s only */ + pktsum_t *laggr_prevstats; /* -s only */ + boolean_t laggr_parseable; +} laggr_args_t; + +static print_field_t laggr_fields[] = { +/* name, header, field width, offset, cmdtype */ +{ "link", "LINK", 15, + offsetof(laggr_fields_buf_t, laggr_name), CMD_TYPE_ANY}, +{ "policy", "POLICY", 8, + offsetof(laggr_fields_buf_t, laggr_policy), CMD_TYPE_ANY}, +{ "addrpolicy", "ADDRPOLICY", ETHERADDRL * 3 + 2, + offsetof(laggr_fields_buf_t, laggr_addrpolicy), CMD_TYPE_ANY}, +{ "lacpactivity", "LACPACTIVITY", 13, + offsetof(laggr_fields_buf_t, laggr_lacpactivity), CMD_TYPE_ANY}, +{ "lacptimer", "LACPTIMER", 11, + offsetof(laggr_fields_buf_t, laggr_lacptimer), CMD_TYPE_ANY}, +{ "flags", "FLAGS", 7, + offsetof(laggr_fields_buf_t, laggr_flags), CMD_TYPE_ANY}} +; +#define LAGGR_MAX_FIELDS (sizeof (laggr_fields) / sizeof (print_field_t)) + +/* + * structures for 'dladm show-aggr -x'. + */ +typedef enum { + AGGR_X_LINK, + AGGR_X_PORT, + AGGR_X_SPEED, + AGGR_X_DUPLEX, + AGGR_X_STATE, + AGGR_X_ADDRESS, + AGGR_X_PORTSTATE +} aggr_x_field_index_t; + +static print_field_t aggr_x_fields[] = { +/* name, header, field width, index, cmdtype */ +{ "link", "LINK", 11, AGGR_X_LINK, CMD_TYPE_ANY}, +{ "port", "PORT", 14, AGGR_X_PORT, CMD_TYPE_ANY}, +{ "speed", "SPEED", 4, AGGR_X_SPEED, CMD_TYPE_ANY}, +{ "duplex", "DUPLEX", 9, AGGR_X_DUPLEX, CMD_TYPE_ANY}, +{ "state", "STATE", 9, AGGR_X_STATE, CMD_TYPE_ANY}, +{ "address", "ADDRESS", 18, AGGR_X_ADDRESS, CMD_TYPE_ANY}, +{ "portstate", "PORTSTATE", 15, AGGR_X_PORTSTATE, CMD_TYPE_ANY}} +; +#define AGGR_X_MAX_FIELDS \ + (sizeof (aggr_x_fields) / sizeof (print_field_t)) + +/* + * structures for 'dladm show-aggr -s'. + */ +typedef enum { + AGGR_S_LINK, + AGGR_S_PORT, + AGGR_S_IPKTS, + AGGR_S_RBYTES, + AGGR_S_OPKTS, + AGGR_S_OBYTES, + AGGR_S_IPKTDIST, + AGGR_S_OPKTDIST +} aggr_s_field_index_t; + +static print_field_t aggr_s_fields[] = { +/* name, header, field width, index, cmdtype */ +{ "link", "LINK", 11, AGGR_S_LINK, + CMD_TYPE_ANY}, +{ "port", "PORT", 9, AGGR_S_PORT, + CMD_TYPE_ANY}, +{ "ipackets", "IPACKETS", 7, AGGR_S_IPKTS, + CMD_TYPE_ANY}, +{ "rbytes", "RBYTES", 7, AGGR_S_RBYTES, + CMD_TYPE_ANY}, +{ "opackets", "OPACKETS", 7, AGGR_S_OPKTS, + CMD_TYPE_ANY}, +{ "obytes", "OBYTES", 7, AGGR_S_OBYTES, + CMD_TYPE_ANY}, +{ "ipktdist", "IPKTDIST", 8, AGGR_S_IPKTDIST, + CMD_TYPE_ANY}, +{ "opktdist", "OPKTDIST", 14, AGGR_S_OPKTDIST, + CMD_TYPE_ANY}} +; +#define AGGR_S_MAX_FIELDS \ + (sizeof (aggr_l_fields) / sizeof (print_field_t)) + +/* + * structures for 'dladm show-dev -L'. + */ +typedef enum { + AGGR_L_LINK, + AGGR_L_PORT, + AGGR_L_AGGREGATABLE, + AGGR_L_SYNC, + AGGR_L_COLL, + AGGR_L_DIST, + AGGR_L_DEFAULTED, + AGGR_L_EXPIRED +} aggr_l_field_index_t; + +static print_field_t aggr_l_fields[] = { +/* name, header, field width, index, cmdtype */ +{ "link", "LINK", 11, AGGR_L_LINK, + CMD_TYPE_ANY}, +{ "port", "PORT", 12, AGGR_L_PORT, + CMD_TYPE_ANY}, +{ "aggregatable", "AGGREGATABLE", 12, AGGR_L_AGGREGATABLE, + CMD_TYPE_ANY}, +{ "sync", "SYNC", 4, AGGR_L_SYNC, + CMD_TYPE_ANY}, +{ "coll", "COLL", 4, AGGR_L_COLL, + CMD_TYPE_ANY}, +{ "dist", "DIST", 4, AGGR_L_DIST, + CMD_TYPE_ANY}, +{ "defaulted", "DEFAULTED", 9, AGGR_L_DEFAULTED, + CMD_TYPE_ANY}, +{ "expired", "EXPIRED", 14, AGGR_L_EXPIRED, + CMD_TYPE_ANY}} +; +#define AGGR_L_MAX_FIELDS \ + (sizeof (aggr_l_fields) / sizeof (print_field_t)) + +/* + * structures for 'dladm show-phys' + */ + +static print_field_t phys_fields[] = { +/* name, header, field width, offset, cmdtype */ +{ "link", "LINK", 12, + offsetof(link_fields_buf_t, link_name), CMD_TYPE_ANY}, +{ "media", "MEDIA", 20, + offsetof(link_fields_buf_t, link_phys_media), CMD_TYPE_ANY}, +{ "state", "STATE", 10, + offsetof(link_fields_buf_t, link_phys_state), CMD_TYPE_ANY}, +{ "speed", "SPEED", 4, + offsetof(link_fields_buf_t, link_phys_speed), CMD_TYPE_ANY}, +{ "duplex", "DUPLEX", 9, + offsetof(link_fields_buf_t, link_phys_duplex), CMD_TYPE_ANY}, +{ "device", "DEVICE", 12, + offsetof(link_fields_buf_t, link_phys_device), CMD_TYPE_ANY}, +{ "flags", "FLAGS", 6, + offsetof(link_fields_buf_t, link_flags), CMD_TYPE_ANY}} +; +#define PHYS_MAX_FIELDS (sizeof (phys_fields) / sizeof (print_field_t)) + +/* + * structures for 'dladm show-vlan' + */ +static print_field_t vlan_fields[] = { +/* name, header, field width, offset, cmdtype */ +{ "link", "LINK", 15, + offsetof(link_fields_buf_t, link_name), CMD_TYPE_ANY}, +{ "vid", "VID", 8, + offsetof(link_fields_buf_t, link_vlan_vid), CMD_TYPE_ANY}, +{ "over", "OVER", 12, + offsetof(link_fields_buf_t, link_over), CMD_TYPE_ANY}, +{ "flags", "FLAGS", 6, + offsetof(link_fields_buf_t, link_flags), CMD_TYPE_ANY}} +; +#define VLAN_MAX_FIELDS (sizeof (vlan_fields) / sizeof (print_field_t)) + +/* + * structures for 'dladm show-wifi' + */ +static print_field_t wifi_fields[] = { +{ "link", "LINK", 10, 0, WIFI_CMD_ALL}, +{ "essid", "ESSID", 19, DLADM_WLAN_ATTR_ESSID, WIFI_CMD_ALL}, +{ "bssid", "BSSID/IBSSID", 17, DLADM_WLAN_ATTR_BSSID, WIFI_CMD_ALL}, +{ "ibssid", "BSSID/IBSSID", 17, DLADM_WLAN_ATTR_BSSID, WIFI_CMD_ALL}, +{ "mode", "MODE", 6, DLADM_WLAN_ATTR_MODE, WIFI_CMD_ALL}, +{ "speed", "SPEED", 6, DLADM_WLAN_ATTR_SPEED, WIFI_CMD_ALL}, +{ "auth", "AUTH", 8, DLADM_WLAN_ATTR_AUTH, WIFI_CMD_SHOW}, +{ "bsstype", "BSSTYPE", 8, DLADM_WLAN_ATTR_BSSTYPE, WIFI_CMD_ALL}, +{ "sec", "SEC", 6, DLADM_WLAN_ATTR_SECMODE, WIFI_CMD_ALL}, +{ "status", "STATUS", 17, DLADM_WLAN_LINKATTR_STATUS, WIFI_CMD_SHOW}, +{ "strength", "STRENGTH", 10, DLADM_WLAN_ATTR_STRENGTH, WIFI_CMD_ALL}} +; + +static char *all_scan_wifi_fields = + "link,essid,bssid,sec,strength,mode,speed,bsstype"; +static char *all_show_wifi_fields = + "link,status,essid,sec,strength,mode,speed,auth,bssid,bsstype"; +static char *def_scan_wifi_fields = + "link,essid,bssid,sec,strength,mode,speed"; +static char *def_show_wifi_fields = + "link,status,essid,sec,strength,mode,speed"; + +#define WIFI_MAX_FIELDS (sizeof (wifi_fields) / sizeof (print_field_t)) + +/* + * structures for 'dladm show-linkprop' + */ +typedef enum { + LINKPROP_LINK, + LINKPROP_PROPERTY, + LINKPROP_VALUE, + LINKPROP_DEFAULT, + LINKPROP_POSSIBLE +} linkprop_field_index_t; + +static print_field_t linkprop_fields[] = { +/* name, header, field width, index, cmdtype */ +{ "link", "LINK", 12, LINKPROP_LINK, CMD_TYPE_ANY}, +{ "property", "PROPERTY", 15, LINKPROP_PROPERTY, CMD_TYPE_ANY}, +{ "value", "VALUE", 14, LINKPROP_VALUE, CMD_TYPE_ANY}, +{ "default", "DEFAULT", 14, LINKPROP_DEFAULT, CMD_TYPE_ANY}, +{ "possible", "POSSIBLE", 20, LINKPROP_POSSIBLE, CMD_TYPE_ANY}} +; +#define LINKPROP_MAX_FIELDS \ + (sizeof (linkprop_fields) / sizeof (print_field_t)) + +#define MAX_PROPS 32 +#define MAX_PROP_LINE 512 + +typedef struct prop_info { + char *pi_name; + char *pi_val[DLADM_MAX_PROP_VALCNT]; + uint_t pi_count; +} prop_info_t; + +typedef struct prop_list { + prop_info_t pl_info[MAX_PROPS]; + uint_t pl_count; + char *pl_buf; +} prop_list_t; + +typedef struct show_linkprop_state { + char ls_link[MAXLINKNAMELEN]; + char *ls_line; + char **ls_propvals; + prop_list_t *ls_proplist; + boolean_t ls_parseable; + boolean_t ls_persist; + boolean_t ls_header; + dladm_status_t ls_status; + dladm_status_t ls_retstatus; + print_state_t ls_print; +} show_linkprop_state_t; + +typedef struct linkprop_args_s { + show_linkprop_state_t *ls_state; + char *ls_propname; + datalink_id_t ls_linkid; +} linkprop_args_t; + +/* + * structures for 'dladm show-secobj' + */ +typedef struct secobj_fields_buf_s { + char ss_obj_name[DLADM_SECOBJ_VAL_MAX]; + char ss_class[20]; + char ss_val[30]; +} secobj_fields_buf_t; +static print_field_t secobj_fields[] = { +/* name, header, field width, offset, cmdtype */ +{ "object", "OBJECT", 20, + offsetof(secobj_fields_buf_t, ss_obj_name), CMD_TYPE_ANY}, +{ "class", "CLASS", 20, + offsetof(secobj_fields_buf_t, ss_class), CMD_TYPE_ANY}, +{ "value", "VALUE", 30, + offsetof(secobj_fields_buf_t, ss_val), CMD_TYPE_ANY}} +; +#define DEV_SOBJ_FIELDS (sizeof (secobj_fields) / sizeof (print_field_t)) static char *progname; static sig_atomic_t signalled; @@ -230,25 +789,28 @@ static void usage(void) { (void) fprintf(stderr, gettext("usage: dladm <subcommand> <args> ...\n" - "\tshow-link [-pP] [-s [-i <interval>]] [<link>]\n" + "\tshow-link [-pP] [-o <field>,..] [-s [-i <interval>]] " + "[<link>]\n" "\trename-link [-R <root-dir>] <oldlink> <newlink>\n" "\n" "\tdelete-phys <link>\n" - "\tshow-phys [-pP] [<link>]\n" - "\tshow-dev [-p] [-s [-i <interval>]] [<dev>]\n" + "\tshow-phys [-pP] [-o <field>,..] [<link>]\n" + "\tshow-dev [-p] [-o <field>,..] [-s [-i <interval>]] " + "[<dev>]\n" "\n" "\tcreate-aggr [-t] [-R <root-dir>] [-P <policy>] [-L <mode>]\n" "\t [-T <time>] [-u <address>] [-l <link>] ... <link>\n" "\tmodify-aggr [-t] [-R <root-dir>] [-P <policy>] [-L <mode>]\n" "\t [-T <time>] [-u <address>] <link>\n" "\tdelete-aggr [-t] [-R <root-dir>] <link>\n" - "\tadd-aggr [-t] [-R <root-dir>] [-l <link>] ... <link>\n" + "\tadd-aggr [-t] [-R <root-dir>] [-l <link>] ... <link>\n" "\tremove-aggr [-t] [-R <root-dir>] [-l <link>] ... <link>" - "\n\tshow-aggr [-pPLx][-s [-i <interval>]] [<link>]\n" + "\n\tshow-aggr [-pPLx] [-o <field>,..] [-s [-i <interval>]] " + "[<link>]\n" "\n" "\tcreate-vlan [-ft] [-R <root-dir>] -l <link> -v <vid> [link]" "\n\tdelete-vlan [-t] [-R <root-dir>] <link>\n" - "\tshow-vlan [-pP] [<link>]\n" + "\tshow-vlan [-pP] [-o <field>,..] [<link>]\n" "\n" "\tscan-wifi [-p] [-o <field>,...] [<link>]\n" "\tconnect-wifi [-e <essid>] [-i <bssid>] [-k <key>,...]" @@ -261,12 +823,15 @@ usage(void) "\tset-linkprop [-t] [-R <root-dir>] -p <prop>=<value>[,...]" " <name>\n" "\treset-linkprop [-t] [-R <root-dir>] [-p <prop>,...] <name>\n" - "\tshow-linkprop [-cP][-p <prop>,...] <name>\n" + "\tshow-linkprop [-cP][-o <field>,...][-p <prop>,...] <name>\n" "\n" "\tcreate-secobj [-t] [-R <root-dir>] [-f <file>] -c <class>" " <secobj>\n" "\tdelete-secobj [-t] [-R <root-dir>] <secobj>[,...]\n" - "\tshow-secobj [-pP][<secobj>,...]\n")); + "\tshow-secobj [-pP][-o <field>,...][<secobj>,...]\n" + "\n" + "\tshow-ether [-px][-o <field>,...] <link>\n")); + exit(1); } @@ -890,8 +1455,8 @@ do_create_vlan(int argc, char *argv[]) if ((status = dladm_vlan_create(vlan, linkid, vid, flags)) != DLADM_STATUS_OK) { if (status == DLADM_STATUS_NOTSUP) { - die_dlerr(status, "VLAN over '%s' may require lowered " - "MTU; must use -f (see dladm(1M))\n", link); + die_dlerr(status, "not all links have link up/down " + "detection; must use -f (see dladm(1M))\n"); } else { die_dlerr(status, "create operation failed"); } @@ -1102,40 +1667,21 @@ do_init_phys(int argc, char *argv[]) DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); } -static void -print_link_head(show_state_t *state) -{ - if (state->ls_donefirst) - return; - state->ls_donefirst = B_TRUE; - - if (state->ls_parseable) - return; - - if (state->ls_flags & DLADM_OPT_ACTIVE) { - (void) printf("%-12s%-8s%6s %-9s%s\n", "LINK", "CLASS", "MTU", - "STATE", "OVER"); - } else { - (void) printf("%-12s%-8s%s\n", "LINK", "CLASS", "OVER"); - } -} /* * Print the active topology information. */ static dladm_status_t print_link_topology(show_state_t *state, datalink_id_t linkid, - datalink_class_t class, char **pptr, char *lim) + datalink_class_t class, link_fields_buf_t *lbuf) { - char *fmt; - char over[MAXLINKNAMELEN]; uint32_t flags = state->ls_flags; dladm_status_t status = DLADM_STATUS_OK; - if (state->ls_parseable) - fmt = "OVER=\"%s"; + if (!state->ls_parseable) + (void) sprintf(lbuf->link_over, STR_UNDEF_VAL); else - fmt = "%s"; + (void) sprintf(lbuf->link_over, ""); if (class == DATALINK_CLASS_VLAN) { dladm_vlan_attr_t vinfo; @@ -1144,12 +1690,9 @@ print_link_topology(show_state_t *state, datalink_id_t linkid, if (status != DLADM_STATUS_OK) goto done; status = dladm_datalink_id2info(vinfo.dv_linkid, NULL, NULL, - NULL, over, sizeof (over)); + NULL, lbuf->link_over, sizeof (lbuf->link_over)); if (status != DLADM_STATUS_OK) goto done; - - /*LINTED: E_SEC_PRINTF_VAR_FMT*/ - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), fmt, over); } else if (class == DATALINK_CLASS_AGGR) { dladm_aggr_grp_attr_t ginfo; int i; @@ -1164,15 +1707,12 @@ print_link_topology(show_state_t *state, datalink_id_t linkid, } for (i = 0; i < ginfo.lg_nports; i++) { status = dladm_datalink_id2info( - ginfo.lg_ports[i].lp_linkid, NULL, NULL, NULL, over, - sizeof (over)); + ginfo.lg_ports[i].lp_linkid, NULL, NULL, NULL, + lbuf->link_over, sizeof (lbuf->link_over)); if (status != DLADM_STATUS_OK) { free(ginfo.lg_ports); goto done; } - /*LINTED: E_SEC_PRINTF_VAR_FMT*/ - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), fmt, over); - fmt = " %s"; } free(ginfo.lg_ports); } else if (class == DATALINK_CLASS_VNIC) { @@ -1180,35 +1720,21 @@ print_link_topology(show_state_t *state, datalink_id_t linkid, if ((status = dladm_vnic_info(linkid, &vinfo, flags)) != DLADM_STATUS_OK || (status = dladm_datalink_id2info( - vinfo.va_link_id, NULL, NULL, NULL, over, - sizeof (over))) != DLADM_STATUS_OK) { + vinfo.va_link_id, NULL, NULL, NULL, lbuf->link_over, + sizeof (lbuf->link_over)) != DLADM_STATUS_OK)) { goto done; } - - /*LINTED: E_SEC_PRINTF_VAR_FMT*/ - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), fmt, over); - } else { - /*LINTED: E_SEC_PRINTF_VAR_FMT*/ - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), fmt, - state->ls_parseable ? "" : "--"); } - if (state->ls_parseable) - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), "\"\n"); - else - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), "\n"); - done: return (status); } static dladm_status_t -print_link(show_state_t *state, datalink_id_t linkid, char **pptr, char *lim) +print_link(show_state_t *state, datalink_id_t linkid, link_fields_buf_t *lbuf) { char link[MAXLINKNAMELEN]; - char buf[DLADM_STRSIZE]; datalink_class_t class; uint_t mtu; - char *fmt; uint32_t flags; dladm_status_t status; @@ -1265,40 +1791,16 @@ link_mtu: } } + (void) snprintf(lbuf->link_name, sizeof (lbuf->link_name), + "%s", link); + (void) dladm_class2str(class, lbuf->link_class); if (state->ls_flags == DLADM_OPT_ACTIVE) { - if (state->ls_parseable) - fmt = "LINK=\"%s\" CLASS=\"%s\" MTU=\"%d\" "; - else - fmt = "%-12s%-8s%6d "; - } else { - if (state->ls_parseable) - fmt = "LINK=\"%s\" CLASS=\"%s\" "; - else - fmt = "%-12s%-8s"; - } - - (void) dladm_class2str(class, buf); - if (state->ls_flags == DLADM_OPT_ACTIVE) { - /*LINTED: E_SEC_PRINTF_VAR_FMT*/ - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), fmt, link, - buf, mtu); - } else { - /*LINTED: E_SEC_PRINTF_VAR_FMT*/ - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), fmt, link, buf); - } - - (void) get_linkstate(link, B_TRUE, buf); - if (state->ls_flags == DLADM_OPT_ACTIVE) { - if (state->ls_parseable) { - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), - "STATE=\"%s\" ", buf); - } else { - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), - "%-9s", buf); - } + (void) snprintf(lbuf->link_mtu, sizeof (lbuf->link_mtu), + "%d", mtu); + (void) get_linkstate(link, B_TRUE, lbuf->link_state); } - status = print_link_topology(state, linkid, class, pptr, lim); + status = print_link_topology(state, linkid, class, lbuf); if (status != DLADM_STATUS_OK) goto done; @@ -1306,19 +1808,29 @@ done: return (status); } + static int show_link(datalink_id_t linkid, void *arg) { - show_state_t *state = arg; - dladm_status_t status; - char buf[MAXLINELEN]; - char *ptr = buf, *lim = buf + MAXLINELEN; + show_state_t *state = (show_state_t *)arg; + dladm_status_t status; + link_fields_buf_t lbuf; + + /* + * first get all the link attributes into lbuf; + */ + status = print_link(state, linkid, &lbuf); - status = print_link(state, linkid, &ptr, lim); if (status != DLADM_STATUS_OK) goto done; - print_link_head(state); - (void) printf("%s", buf); + + if (!state->ls_parseable && !state->ls_printheader) { + print_header(&state->ls_print); + state->ls_printheader = B_TRUE; + } + + dladm_print_output(&state->ls_print, state->ls_parseable, + dladm_print_field, (void *)&lbuf); done: state->ls_status = status; @@ -1328,9 +1840,9 @@ done: static int show_link_stats(datalink_id_t linkid, void *arg) { - char link[MAXLINKNAMELEN]; + char link[DLPI_LINKNAME_MAX]; datalink_class_t class; - show_state_t *state = arg; + show_state_t *state = (show_state_t *)arg; pktsum_t stats, diff_stats; dladm_phys_attr_t dpa; @@ -1343,7 +1855,7 @@ show_link_stats(datalink_id_t linkid, void *arg) } if (dladm_datalink_id2info(linkid, NULL, &class, NULL, link, - sizeof (link)) != DLADM_STATUS_OK) { + DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) { return (DLADM_WALK_CONTINUE); } @@ -1373,233 +1885,270 @@ show_link_stats(datalink_id_t linkid, void *arg) return (DLADM_WALK_CONTINUE); } -static void -print_port_stat(const char *port, pktsum_t *old_stats, pktsum_t *port_stats, - pktsum_t *tot_stats, char **pptr, char *lim) + +static dladm_status_t +print_aggr_info(show_grp_state_t *state, const char *link, + dladm_aggr_grp_attr_t *ginfop) { - pktsum_t diff_stats; + char addr_str[ETHERADDRL * 3]; + laggr_fields_buf_t lbuf; - stats_diff(&diff_stats, port_stats, old_stats); - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), - "%-12s%-10s%8llu %8llu %8llu %8llu ", "", port, - diff_stats.ipackets, diff_stats.rbytes, diff_stats.opackets, - diff_stats.obytes); + (void) snprintf(lbuf.laggr_name, sizeof (lbuf.laggr_name), + "%s", link); - if (tot_stats->ipackets == 0) { - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), "%8s ", "--"); - } else { - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), "%7.1f%% ", - (double)diff_stats.ipackets/ - (double)tot_stats->ipackets * 100); - } + (void) dladm_aggr_policy2str(ginfop->lg_policy, + lbuf.laggr_policy); - if (tot_stats->opackets == 0) { - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), "%8s\n", "--"); + if (ginfop->lg_mac_fixed) { + (void) dladm_aggr_macaddr2str(ginfop->lg_mac, addr_str); + (void) snprintf(lbuf.laggr_addrpolicy, + sizeof (lbuf.laggr_addrpolicy), "fixed (%s)", addr_str); } else { - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), "%7.1f%%\n", - (double)diff_stats.opackets/ - (double)tot_stats->opackets * 100); + (void) snprintf(lbuf.laggr_addrpolicy, + sizeof (lbuf.laggr_addrpolicy), "auto"); } - *old_stats = *port_stats; -} -static void -print_aggr_head(show_grp_state_t *state) -{ - if (state->gs_donefirst) - return; - state->gs_donefirst = B_TRUE; + (void) dladm_aggr_lacpmode2str(ginfop->lg_lacp_mode, + lbuf.laggr_lacpactivity); + (void) dladm_aggr_lacptimer2str(ginfop->lg_lacp_timer, + lbuf.laggr_lacptimer); + (void) snprintf(lbuf.laggr_flags, sizeof (lbuf.laggr_flags), "%c----", + ginfop->lg_force ? 'f' : '-'); - if (state->gs_parseable) - return; - - if (state->gs_lacp) { - (void) printf("%-12s%-12s%-13s%-5s%-5s%-5s%-10s%s\n", "LINK", - "PORT", "AGGREGATABLE", "SYNC", "COLL", "DIST", - "DEFAULTED", "EXPIRED"); - } else if (state->gs_extended) { - (void) printf("%-12s%-14s%6s %-9s%-9s%-18s%s\n", "LINK", - "PORT", "SPEED", "DUPLEX", "STATE", "ADDRESS", "PORTSTATE"); - } else if (!state->gs_stats) { - (void) printf("%-12s%-8s%-24s%-13s%-11s%s\n", "LINK", "POLICY", - "ADDRPOLICY", "LACPACTIVITY", "LACPTIMER", "FLAGS"); + if (!state->gs_parseable && !state->gs_printheader) { + print_header(&state->gs_print); + state->gs_printheader = B_TRUE; } + + dladm_print_output(&state->gs_print, state->gs_parseable, + dladm_print_field, (void *)&lbuf); + + return (DLADM_STATUS_OK); } -static dladm_status_t -print_aggr_info(show_grp_state_t *state, const char *link, - dladm_aggr_grp_attr_t *ginfop, char **pptr, char *lim) +static char * +print_xaggr_callback(print_field_t *pf, void *arg) { - char buf[DLADM_STRSIZE]; - char *fmt; - char addr_str[ETHERADDRL * 3]; - char str[ETHERADDRL * 3 + 2]; + const laggr_args_t *l = arg; + int portnum; + static char buf[DLADM_STRSIZE]; + boolean_t is_port = (l->laggr_lport >= 0); + dladm_aggr_port_attr_t *portp; + dladm_phys_attr_t dpa; + dladm_status_t *stat, status; - if (state->gs_parseable) - fmt = "LINK=\"%s\" POLICY=\"%s\" ADDRPOLICY=\"%s%s\" "; - else - fmt = "%-12s%-8s%-6s%-18s"; + stat = l->laggr_status; + *stat = DLADM_STATUS_OK; - if (ginfop->lg_mac_fixed) { - (void) dladm_aggr_macaddr2str(ginfop->lg_mac, addr_str); - (void) snprintf(str, ETHERADDRL * 3 + 3, " (%s)", addr_str); - } else { - str[0] = '\0'; + if (is_port) { + portnum = l->laggr_lport; + portp = &(l->laggr_ginfop->lg_ports[portnum]); + if ((status = dladm_datalink_id2info(portp->lp_linkid, + NULL, NULL, NULL, buf, sizeof (buf))) != + DLADM_STATUS_OK) { + goto err; + } + if ((status = dladm_phys_info(portp->lp_linkid, &dpa, + DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) { + goto err; + } } - /*LINTED: E_SEC_PRINTF_VAR_FMT*/ - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), fmt, link, - dladm_aggr_policy2str(ginfop->lg_policy, buf), - ginfop->lg_mac_fixed ? "fixed" : "auto", str); + switch (pf->pf_index) { + case AGGR_X_LINK: + (void) snprintf(buf, sizeof (buf), "%s", + (is_port && !l->laggr_parseable ? " " : l->laggr_link)); + break; + case AGGR_X_PORT: + if (is_port) + break; + return (""); + break; - (void) dladm_aggr_lacpmode2str(ginfop->lg_lacp_mode, buf); - if (state->gs_parseable) { - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), - "LACPACTIVITY=\"%s\" ", buf); - } else { - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), "%-13s", buf); - } + case AGGR_X_SPEED: + if (is_port) { + (void) snprintf(buf, sizeof (buf), "%uMb", + (uint_t)((get_ifspeed(dpa.dp_dev, + B_FALSE)) / 1000000ull)); + } else { + (void) snprintf(buf, sizeof (buf), "%uMb", + (uint_t)((get_ifspeed(l->laggr_link, + B_TRUE)) / 1000000ull)); + } + break; - (void) dladm_aggr_lacptimer2str(ginfop->lg_lacp_timer, buf); - if (state->gs_parseable) { - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), - "LACPTIMER=\"%s\" FLAGS=\"%c----\"\n", buf, - ginfop->lg_force ? 'f' : '-'); - } else { - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), - "%-11s%c----\n", buf, ginfop->lg_force ? 'f' : '-'); + case AGGR_X_DUPLEX: + if (is_port) + (void) get_linkduplex(dpa.dp_dev, B_FALSE, buf); + else + (void) get_linkduplex(l->laggr_link, B_TRUE, buf); + break; + + case AGGR_X_STATE: + if (is_port) { + (void) dladm_aggr_portstate2str( + portp->lp_state, buf); + } else { + return (STR_UNDEF_VAL); + } + break; + case AGGR_X_ADDRESS: + (void) dladm_aggr_macaddr2str( + (is_port ? portp->lp_mac : l->laggr_ginfop->lg_mac), + buf); + break; + + case AGGR_X_PORTSTATE: + (void) snprintf(buf, sizeof (buf), "%s", + (is_port ? dladm_aggr_portstate2str(portp->lp_state, buf): + (l->laggr_parseable ? "" : STR_UNDEF_VAL))); + break; } + return (buf); - return (DLADM_STATUS_OK); +err: + *stat = status; + buf[0] = '\0'; + return (buf); } static dladm_status_t print_aggr_extended(show_grp_state_t *state, const char *link, - dladm_aggr_grp_attr_t *ginfop, char **pptr, char *lim) + dladm_aggr_grp_attr_t *ginfop) { - char addr_str[ETHERADDRL * 3]; - char port[MAXLINKNAMELEN]; - dladm_phys_attr_t dpa; - char buf[DLADM_STRSIZE]; - char *fmt; int i; dladm_status_t status; + laggr_args_t largs; - if (state->gs_parseable) - fmt = "LINK=\"%s\" PORT=\"%s\" SPEED=\"%uMb\" DUPLEX=\"%s\" "; - else - fmt = "%-12s%-14s%4uMb %-9s"; + if (!state->gs_parseable && !state->gs_printheader) { + print_header(&state->gs_print); + state->gs_printheader = B_TRUE; + } - (void) dladm_aggr_macaddr2str(ginfop->lg_mac, addr_str); + largs.laggr_lport = -1; + largs.laggr_link = link; + largs.laggr_ginfop = ginfop; + largs.laggr_status = &status; + largs.laggr_parseable = state->gs_parseable; - /*LINTED: E_SEC_PRINTF_VAR_FMT*/ - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), fmt, link, - state->gs_parseable ? "" : "--", - (uint_t)((get_ifspeed(link, B_TRUE)) / 1000000ull), - get_linkduplex(link, B_TRUE, buf)); + dladm_print_output(&state->gs_print, state->gs_parseable, + print_xaggr_callback, &largs); - (void) get_linkstate(link, B_TRUE, buf); - if (state->gs_parseable) { - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), - "STATE=\"%s\" ADDRESS=\"%s\" PORTSTATE=\"%s\"\n", buf, - addr_str, ""); - } else { - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), "%-9s%-18s%s\n", - buf, addr_str, "--"); - } + if (status != DLADM_STATUS_OK) + goto done; for (i = 0; i < ginfop->lg_nports; i++) { - dladm_aggr_port_attr_t *portp = &(ginfop->lg_ports[i]); - const char *tmp; - - if ((status = dladm_datalink_id2info(portp->lp_linkid, NULL, - NULL, NULL, port, sizeof (port))) != DLADM_STATUS_OK) { + largs.laggr_lport = i; + dladm_print_output(&state->gs_print, state->gs_parseable, + print_xaggr_callback, &largs); + if (status != DLADM_STATUS_OK) goto done; - } + } - if ((status = dladm_phys_info(portp->lp_linkid, &dpa, - DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) { - goto done; - } + status = DLADM_STATUS_OK; +done: + return (status); +} - (void) dladm_aggr_macaddr2str(portp->lp_mac, addr_str); - if (state->gs_parseable) - tmp = link; - else - tmp = ""; +static char * +print_lacp_callback(print_field_t *pf, void *arg) +{ + const laggr_args_t *l = arg; + int portnum; + static char buf[DLADM_STRSIZE]; + boolean_t is_port = (l->laggr_lport >= 0); + dladm_aggr_port_attr_t *portp; + dladm_status_t *stat, status; + aggr_lacp_state_t *lstate; - /*LINTED: E_SEC_PRINTF_VAR_FMT*/ - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), fmt, tmp, port, - (uint_t)((get_ifspeed(dpa.dp_dev, B_FALSE)) / 1000000ull), - get_linkduplex(dpa.dp_dev, B_FALSE, buf)); + if (!is_port) { + return (NULL); /* cannot happen! */ + } - (void) get_linkstate(dpa.dp_dev, B_FALSE, buf); - if (state->gs_parseable) { - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), - "STATE=\"%s\" ADDRESS=\"%s\" ", buf, addr_str); - } else { - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), - "%-9s%-18s", buf, addr_str); - } + stat = l->laggr_status; - (void) dladm_aggr_portstate2str( - ginfop->lg_ports[i].lp_state, buf); - if (state->gs_parseable) { - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), - "PORTSTATE=\"%s\"\n", buf); - } else { - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), - "%s\n", buf); - } + portnum = l->laggr_lport; + portp = &(l->laggr_ginfop->lg_ports[portnum]); + if ((status = dladm_datalink_id2info(portp->lp_linkid, + NULL, NULL, NULL, buf, sizeof (buf))) != DLADM_STATUS_OK) { + goto err; } + lstate = &(portp->lp_lacp_state); - status = DLADM_STATUS_OK; -done: - return (status); + switch (pf->pf_index) { + case AGGR_L_LINK: + (void) snprintf(buf, sizeof (buf), "%s", + (portnum > 0 ? "" : l->laggr_link)); + break; + + case AGGR_L_PORT: + break; + + case AGGR_L_AGGREGATABLE: + (void) snprintf(buf, sizeof (buf), "%s", + (lstate->bit.aggregation ? "yes" : "no")); + break; + + case AGGR_L_SYNC: + (void) snprintf(buf, sizeof (buf), "%s", + (lstate->bit.sync ? "yes" : "no")); + break; + + case AGGR_L_COLL: + (void) snprintf(buf, sizeof (buf), "%s", + (lstate->bit.collecting ? "yes" : "no")); + break; + + case AGGR_L_DIST: + (void) snprintf(buf, sizeof (buf), "%s", + (lstate->bit.distributing ? "yes" : "no")); + break; + + case AGGR_L_DEFAULTED: + (void) snprintf(buf, sizeof (buf), "%s", + (lstate->bit.defaulted ? "yes" : "no")); + break; + + case AGGR_L_EXPIRED: + (void) snprintf(buf, sizeof (buf), "%s", + (lstate->bit.expired ? "yes" : "no")); + break; + } + + *stat = DLADM_STATUS_OK; + return (buf); + +err: + *stat = status; + buf[0] = '\0'; + return (buf); } static dladm_status_t print_aggr_lacp(show_grp_state_t *state, const char *link, - dladm_aggr_grp_attr_t *ginfop, char **pptr, char *lim) + dladm_aggr_grp_attr_t *ginfop) { - char port[MAXLINKNAMELEN]; - char *fmt; - const char *dlink = link; int i; dladm_status_t status; + laggr_args_t largs; - if (state->gs_parseable) { - fmt = "LINK=\"%s\" PORT=\"%s\" AGGREGATABLE=\"%s\" SYNC=\"%s\" " - "COLL=\"%s\" DIST=\"%s\" DEFAULTED=\"%s\" EXPITED=\"%s\"\n"; - } else { - fmt = "%-12s%-12s%-13s%-5s%-5s%-5s%-10s%s\n"; + if (!state->gs_parseable && !state->gs_printheader) { + print_header(&state->gs_print); + state->gs_printheader = B_TRUE; } - for (i = 0; i < ginfop->lg_nports; i++) { - aggr_lacp_state_t *lstate; + largs.laggr_link = link; + largs.laggr_ginfop = ginfop; + largs.laggr_status = &status; - status = dladm_datalink_id2info(ginfop->lg_ports[i].lp_linkid, - NULL, NULL, NULL, port, sizeof (port)); + for (i = 0; i < ginfop->lg_nports; i++) { + largs.laggr_lport = i; + dladm_print_output(&state->gs_print, state->gs_parseable, + print_lacp_callback, &largs); if (status != DLADM_STATUS_OK) goto done; - - /* - * Only display link for the first port. - */ - if ((i > 0) && !(state->gs_parseable)) - dlink = ""; - lstate = &(ginfop->lg_ports[i].lp_lacp_state); - - /*LINTED: E_SEC_PRINTF_VAR_FMT*/ - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), fmt, dlink, port, - lstate->bit.aggregation ? "yes" : "no", - lstate->bit.sync ? "yes" : "no", - lstate->bit.collecting ? "yes" : "no", - lstate->bit.distributing ? "yes" : "no", - lstate->bit.defaulted ? "yes" : "no", - lstate->bit.expired ? "yes" : "no"); } status = DLADM_STATUS_OK; @@ -1607,24 +2156,127 @@ done: return (status); } +static char * +print_aggr_stats_callback(print_field_t *pf, void *arg) +{ + const laggr_args_t *l = arg; + int portnum; + static char buf[DLADM_STRSIZE]; + boolean_t is_port = (l->laggr_lport >= 0); + dladm_aggr_port_attr_t *portp; + dladm_phys_attr_t dpa; + dladm_status_t *stat, status; + pktsum_t port_stat, diff_stats; + + stat = l->laggr_status; + *stat = DLADM_STATUS_OK; + + if (is_port) { + portnum = l->laggr_lport; + portp = &(l->laggr_ginfop->lg_ports[portnum]); + if ((status = dladm_phys_info(portp->lp_linkid, &dpa, + DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) { + goto err; + } + + get_mac_stats(dpa.dp_dev, &port_stat); + + if ((status = dladm_datalink_id2info(portp->lp_linkid, NULL, + NULL, NULL, buf, sizeof (buf))) != DLADM_STATUS_OK) { + goto err; + } + + stats_diff(&diff_stats, &port_stat, l->laggr_prevstats); + } + + switch (pf->pf_index) { + case AGGR_S_LINK: + (void) snprintf(buf, sizeof (buf), "%s", + (is_port ? "" : l->laggr_link)); + break; + case AGGR_S_PORT: + if (is_port) + break; + return (STR_UNDEF_VAL); + break; + + case AGGR_S_IPKTS: + if (is_port) { + (void) snprintf(buf, sizeof (buf), "%llu", + diff_stats.ipackets); + } else { + (void) snprintf(buf, sizeof (buf), "%llu", + l->laggr_pktsumtot->ipackets); + } + break; + + case AGGR_S_RBYTES: + if (is_port) { + (void) snprintf(buf, sizeof (buf), "%llu", + diff_stats.rbytes); + } else { + (void) snprintf(buf, sizeof (buf), "%llu", + l->laggr_pktsumtot->rbytes); + } + break; + + case AGGR_S_OPKTS: + if (is_port) { + (void) snprintf(buf, sizeof (buf), "%llu", + diff_stats.opackets); + } else { + (void) snprintf(buf, sizeof (buf), "%llu", + l->laggr_pktsumtot->opackets); + } + break; + case AGGR_S_OBYTES: + if (is_port) { + (void) snprintf(buf, sizeof (buf), "%llu", + diff_stats.obytes); + } else { + (void) snprintf(buf, sizeof (buf), "%llu", + l->laggr_pktsumtot->obytes); + + } + break; + + case AGGR_S_IPKTDIST: + if (is_port) { + (void) snprintf(buf, sizeof (buf), "%-6.1f", + (double)diff_stats.opackets/ + (double)l->laggr_pktsumtot->ipackets * 100); + } else { + return (STR_UNDEF_VAL); + } + break; + case AGGR_S_OPKTDIST: + if (is_port) { + (void) snprintf(buf, sizeof (buf), "%-6.1f", + (double)diff_stats.opackets/ + (double)l->laggr_pktsumtot->opackets * 100); + } else { + (void) sprintf(buf, STR_UNDEF_VAL); + } + break; + } + return (buf); + +err: + *stat = status; + buf[0] = '\0'; + return (buf); +} + static dladm_status_t print_aggr_stats(show_grp_state_t *state, const char *link, - dladm_aggr_grp_attr_t *ginfop, char **pptr, char *lim) + dladm_aggr_grp_attr_t *ginfop) { - char port[MAXLINKNAMELEN]; dladm_phys_attr_t dpa; dladm_aggr_port_attr_t *portp; pktsum_t pktsumtot, port_stat; dladm_status_t status; int i; - - if (state->gs_firstonly) { - if (state->gs_donefirst) - return (DLADM_WALK_CONTINUE); - state->gs_donefirst = B_TRUE; - } else { - bzero(&state->gs_prevstats, sizeof (state->gs_prevstats)); - } + laggr_args_t largs; /* sum the ports statistics */ bzero(&pktsumtot, sizeof (pktsumtot)); @@ -1641,28 +2293,30 @@ print_aggr_stats(show_grp_state_t *state, const char *link, stats_total(&pktsumtot, &port_stat, &state->gs_prevstats[i]); } - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), - "%-12s%-10s%8llu %8llu %8llu %8llu %8s %8s\n", link, "--", - pktsumtot.ipackets, pktsumtot.rbytes, pktsumtot.opackets, - pktsumtot.obytes, "--", "--"); + if (!state->gs_parseable && !state->gs_printheader) { + print_header(&state->gs_print); + state->gs_printheader = B_TRUE; + } - for (i = 0; i < ginfop->lg_nports; i++) { - portp = &(ginfop->lg_ports[i]); + largs.laggr_lport = -1; + largs.laggr_link = link; + largs.laggr_ginfop = ginfop; + largs.laggr_status = &status; + largs.laggr_pktsumtot = &pktsumtot; - if ((status = dladm_phys_info(portp->lp_linkid, &dpa, - DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) { - goto done; - } + dladm_print_output(&state->gs_print, state->gs_parseable, + print_aggr_stats_callback, &largs); - get_mac_stats(dpa.dp_dev, &port_stat); + if (status != DLADM_STATUS_OK) + goto done; - if ((status = dladm_datalink_id2info(portp->lp_linkid, NULL, - NULL, NULL, port, sizeof (port))) != DLADM_STATUS_OK) { + for (i = 0; i < ginfop->lg_nports; i++) { + largs.laggr_lport = i; + largs.laggr_prevstats = &state->gs_prevstats[i]; + dladm_print_output(&state->gs_print, state->gs_parseable, + print_aggr_stats_callback, &largs); + if (status != DLADM_STATUS_OK) goto done; - } - - print_port_stat(port, &state->gs_prevstats[i], &port_stat, - &pktsumtot, pptr, lim); } status = DLADM_STATUS_OK; @@ -1671,8 +2325,7 @@ done: } static dladm_status_t -print_aggr(show_grp_state_t *state, datalink_id_t linkid, char **pptr, - char *lim) +print_aggr(show_grp_state_t *state, datalink_id_t linkid) { char link[MAXLINKNAMELEN]; dladm_aggr_grp_attr_t ginfo; @@ -1680,7 +2333,7 @@ print_aggr(show_grp_state_t *state, datalink_id_t linkid, char **pptr, dladm_status_t status; if ((status = dladm_datalink_id2info(linkid, &flags, NULL, NULL, link, - sizeof (link))) != DLADM_STATUS_OK) { + MAXLINKNAMELEN)) != DLADM_STATUS_OK) { return (status); } @@ -1692,13 +2345,14 @@ print_aggr(show_grp_state_t *state, datalink_id_t linkid, char **pptr, return (status); if (state->gs_lacp) - status = print_aggr_lacp(state, link, &ginfo, pptr, lim); + status = print_aggr_lacp(state, link, &ginfo); else if (state->gs_extended) - status = print_aggr_extended(state, link, &ginfo, pptr, lim); + status = print_aggr_extended(state, link, &ginfo); else if (state->gs_stats) - status = print_aggr_stats(state, link, &ginfo, pptr, lim); - else - status = print_aggr_info(state, link, &ginfo, pptr, lim); + status = print_aggr_stats(state, link, &ginfo); + else { + status = print_aggr_info(state, link, &ginfo); + } done: free(ginfo.lg_ports); @@ -1710,83 +2364,107 @@ show_aggr(datalink_id_t linkid, void *arg) { show_grp_state_t *state = arg; dladm_status_t status; - char buf[MAXLINELEN]; - char *ptr = buf, *lim = buf + MAXLINELEN; - status = print_aggr(state, linkid, &ptr, lim); + status = print_aggr(state, linkid); if (status != DLADM_STATUS_OK) goto done; - print_aggr_head(state); - (void) printf("%s", buf); done: state->gs_status = status; return (DLADM_WALK_CONTINUE); } -static int -kstat_value(kstat_t *ksp, const char *name, uint8_t type, void *buf) +static char * +print_dev(print_field_t *pf, void *arg) { - kstat_named_t *knp; - - if ((knp = kstat_data_lookup(ksp, (char *)name)) == NULL) - return (-1); - - if (knp->data_type != type) - return (-1); + const char *dev = arg; + static char buf[DLADM_STRSIZE]; - switch (type) { - case KSTAT_DATA_UINT64: - *(uint64_t *)buf = knp->value.ui64; + switch (pf->pf_index) { + case DEV_LINK: + (void) snprintf(buf, sizeof (buf), "%s", dev); + break; + case DEV_STATE: + (void) get_linkstate(dev, B_FALSE, buf); + break; + case DEV_SPEED: + (void) snprintf(buf, sizeof (buf), "%uMb", + (unsigned int)(get_ifspeed(dev, B_FALSE) / 1000000ull)); break; - case KSTAT_DATA_UINT32: - *(uint32_t *)buf = knp->value.ui32; + case DEV_DUPLEX: + (void) get_linkduplex(dev, B_FALSE, buf); break; default: - return (-1); + die("invalid index '%d'", pf->pf_index); + break; } - - return (0); + return (buf); } static int show_dev(const char *dev, void *arg) { show_state_t *state = arg; - char buf[DLADM_STRSIZE]; - char *fmt; - - if (state->ls_parseable) - fmt = "DEV=\"%s\" STATE=\"%s\" SPEED=\"%u\" "; - else - fmt = "%-12s%-10s%4uMb "; - if (!state->ls_donefirst) { - if (!state->ls_parseable) { - (void) printf("%-12s%-10s%6s %s\n", "DEV", "STATE", - "SPEED", "DUPLEX"); - } - state->ls_donefirst = B_TRUE; + if (!state->ls_parseable && !state->ls_printheader) { + print_header(&state->ls_print); + state->ls_printheader = B_TRUE; } - /*LINTED: E_SEC_PRINTF_VAR_FMT*/ - (void) printf(fmt, dev, get_linkstate(dev, B_FALSE, buf), - (uint_t)(get_ifspeed(dev, B_FALSE) / 1000000ull)); - - (void) get_linkduplex(dev, B_FALSE, buf); - if (state->ls_parseable) - (void) printf("DUPLEX=\"%s\"\n", buf); - else - (void) printf("%s\n", buf); + dladm_print_output(&state->ls_print, state->ls_parseable, + print_dev, (void *)dev); return (DLADM_WALK_CONTINUE); } +static char * +print_dev_stats(print_field_t *pf, void *arg) +{ + dev_args_t *dargs = arg; + pktsum_t *diff_stats = dargs->devs_psum; + static char buf[DLADM_STRSIZE]; + + switch (pf->pf_index) { + case DEVS_LINK: + (void) snprintf(buf, sizeof (buf), "%s", dargs->devs_link); + break; + case DEVS_IPKTS: + (void) snprintf(buf, sizeof (buf), "%llu", + diff_stats->ipackets); + break; + case DEVS_RBYTES: + (void) snprintf(buf, sizeof (buf), "%llu", + diff_stats->rbytes); + break; + case DEVS_IERRORS: + (void) snprintf(buf, sizeof (buf), "%u", + diff_stats->ierrors); + break; + case DEVS_OPKTS: + (void) snprintf(buf, sizeof (buf), "%llu", + diff_stats->opackets); + break; + case DEVS_OBYTES: + (void) snprintf(buf, sizeof (buf), "%llu", + diff_stats->obytes); + break; + case DEVS_OERRORS: + (void) snprintf(buf, sizeof (buf), "%u", + diff_stats->oerrors); + break; + default: + die("invalid input"); + break; + } + return (buf); +} + static int show_dev_stats(const char *dev, void *arg) { show_state_t *state = arg; pktsum_t stats, diff_stats; + dev_args_t dargs; if (state->ls_firstonly) { if (state->ls_donefirst) @@ -1799,13 +2477,10 @@ show_dev_stats(const char *dev, void *arg) get_mac_stats(dev, &stats); stats_diff(&diff_stats, &stats, &state->ls_prevstats); - (void) printf("%-12s", dev); - (void) printf("%-10llu", diff_stats.ipackets); - (void) printf("%-12llu", diff_stats.rbytes); - (void) printf("%-8u", diff_stats.ierrors); - (void) printf("%-10llu", diff_stats.opackets); - (void) printf("%-12llu", diff_stats.obytes); - (void) printf("%-8u\n", diff_stats.oerrors); + dargs.devs_link = (char *)dev; + dargs.devs_psum = &diff_stats; + dladm_print_output(&state->ls_print, state->ls_parseable, + print_dev_stats, &dargs); state->ls_prevstats = stats; return (DLADM_WALK_CONTINUE); @@ -1823,9 +2498,17 @@ do_show_link(int argc, char *argv[]) int interval = 0; show_state_t state; dladm_status_t status; + boolean_t o_arg = B_FALSE; + char *fields_str = NULL; + print_field_t **fields; + uint_t nfields; + char *all_active_fields = "link,class,mtu,state,over"; + char *all_inactive_fields = "link,class,over"; + + bzero(&state, sizeof (state)); opterr = 0; - while ((option = getopt_long(argc, argv, ":pPsi:", + while ((option = getopt_long(argc, argv, ":pPsi:o:", show_lopts, NULL)) != -1) { switch (option) { case 'p': @@ -1846,6 +2529,10 @@ do_show_link(int argc, char *argv[]) flags = DLADM_OPT_PERSIST; break; + case 'o': + o_arg = B_TRUE; + fields_str = optarg; + break; case 'i': if (i_arg) die_optdup(option); @@ -1892,6 +2579,26 @@ do_show_link(int argc, char *argv[]) state.ls_parseable = p_arg; state.ls_flags = flags; state.ls_donefirst = B_FALSE; + + if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) { + if (state.ls_flags & DLADM_OPT_ACTIVE) + fields_str = all_active_fields; + else + fields_str = all_inactive_fields; + } + + + fields = parse_output_fields(fields_str, link_fields, DEV_LINK_FIELDS, + CMD_TYPE_ANY, &nfields); + + if (fields == NULL) { + die("invalid field(s) specified"); + return; + } + + state.ls_print.ps_fields = fields; + state.ls_print.ps_nfields = nfields; + if (linkid == DATALINK_ALL_LINKID) { (void) dladm_walk_datalink_id(show_link, &state, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, flags); @@ -1919,9 +2626,25 @@ do_show_aggr(int argc, char *argv[]) int interval = 0; int key; dladm_status_t status; + boolean_t o_arg = B_FALSE; + char *fields_str = NULL; + print_field_t **fields; + uint_t nfields; + char *all_fields = + "link,policy,addrpolicy,lacpactivity,lacptimer,flags"; + char *all_lacp_fields = + "link,port,aggregatable,sync,coll,dist,defaulted,expired"; + char *all_stats_fields = + "link,port,ipackets,rbytes,opackets,obytes,ipktdist,opktdist"; + char *all_extended_fields = + "link,port,speed,duplex,state,address,portstate"; + print_field_t *pf; + int pfmax; + + bzero(&state, sizeof (state)); opterr = 0; - while ((option = getopt_long(argc, argv, ":LpPxsi:", + while ((option = getopt_long(argc, argv, ":LpPxsi:o:", show_lopts, NULL)) != -1) { switch (option) { case 'L': @@ -1954,6 +2677,10 @@ do_show_aggr(int argc, char *argv[]) s_arg = B_TRUE; break; + case 'o': + o_arg = B_TRUE; + fields_str = optarg; + break; case 'i': if (i_arg) die_optdup(option); @@ -2006,6 +2733,41 @@ do_show_aggr(int argc, char *argv[]) state.gs_parseable = p_arg; state.gs_extended = x_arg; + if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) { + if (state.gs_lacp) + fields_str = all_lacp_fields; + else if (state.gs_stats) + fields_str = all_stats_fields; + else if (state.gs_extended) + fields_str = all_extended_fields; + else + fields_str = all_fields; + } + + if (state.gs_lacp) { + pf = aggr_l_fields; + pfmax = AGGR_L_MAX_FIELDS; + } else if (state.gs_stats) { + pf = aggr_s_fields; + pfmax = AGGR_S_MAX_FIELDS; + } else if (state.gs_extended) { + pf = aggr_x_fields; + pfmax = AGGR_X_MAX_FIELDS; + } else { + pf = laggr_fields; + pfmax = LAGGR_MAX_FIELDS; + } + fields = parse_output_fields(fields_str, pf, pfmax, CMD_TYPE_ANY, + &nfields); + + if (fields == NULL) { + die("invalid field(s) specified"); + return; + } + + state.gs_print.ps_fields = fields; + state.gs_print.ps_nfields = nfields; + if (s_arg) { aggr_stats(linkid, &state, interval); return; @@ -2030,13 +2792,23 @@ do_show_dev(int argc, char *argv[]) char *dev = NULL; boolean_t s_arg = B_FALSE; boolean_t i_arg = B_FALSE; + boolean_t o_arg = B_FALSE; boolean_t p_arg = B_FALSE; datalink_id_t linkid; int interval = 0; show_state_t state; + char *fields_str = NULL; + print_field_t **fields; + uint_t nfields; + char *all_fields = "link,state,speed,duplex"; + static char *allstat_fields = + "link,ipackets,rbytes,ierrors,opackets,obytes,oerrors"; + + bzero(&state, sizeof (state)); + fields_str = all_fields; opterr = 0; - while ((option = getopt_long(argc, argv, ":psi:", + while ((option = getopt_long(argc, argv, ":psi:o:", show_lopts, NULL)) != -1) { switch (option) { case 'p': @@ -2051,6 +2823,10 @@ do_show_dev(int argc, char *argv[]) s_arg = B_TRUE; break; + case 'o': + o_arg = B_TRUE; + fields_str = optarg; + break; case 'i': if (i_arg) die_optdup(option); @@ -2068,6 +2844,16 @@ do_show_dev(int argc, char *argv[]) if (i_arg && !s_arg) die("the option -i can be used only with -s"); + if (o_arg && strcasecmp(fields_str, "all") == 0) { + if (!s_arg) + fields_str = all_fields; + else + fields_str = allstat_fields; + } + + if (!o_arg && s_arg) + fields_str = allstat_fields; + if (s_arg && p_arg) die("the option -s cannot be used with -p"); @@ -2089,52 +2875,45 @@ do_show_dev(int argc, char *argv[]) usage(); } + state.ls_parseable = p_arg; + state.ls_donefirst = B_FALSE; + if (s_arg) { - dev_stats(dev, interval); + dev_stats(dev, interval, fields_str, &state); return; } - state.ls_donefirst = B_FALSE; - state.ls_parseable = p_arg; - if (dev == NULL) { - (void) dladm_mac_walk(show_dev, &state); - } else { - (void) show_dev(dev, &state); - } -} + fields = parse_output_fields(fields_str, dev_fields, DEV_MAX_FIELDS, + CMD_TYPE_ANY, &nfields); -static void -print_phys_head(show_state_t *state) -{ - if (state->ls_donefirst) + if (fields == NULL) { + die("invalid field(s) specified"); return; - state->ls_donefirst = B_TRUE; + } - if (state->ls_parseable) - return; + state.ls_print.ps_fields = fields; + state.ls_print.ps_nfields = nfields; - if (state->ls_flags == DLADM_OPT_ACTIVE) { - (void) printf("%-12s%-20s%-10s%6s %-9s%s\n", "LINK", - "MEDIA", "STATE", "SPEED", "DUPLEX", "DEVICE"); + if (dev == NULL) { + (void) dladm_mac_walk(show_dev, &state); } else { - (void) printf("%-12s%-12s%-20s%s\n", "LINK", "DEVICE", - "MEDIA", "FLAGS"); + (void) show_dev(dev, &state); } } + static dladm_status_t -print_phys(show_state_t *state, datalink_id_t linkid, char **pptr, char *lim) +print_phys(show_state_t *state, datalink_id_t linkid, link_fields_buf_t *pattr) { char link[MAXLINKNAMELEN]; dladm_phys_attr_t dpa; - char buf[DLADM_STRSIZE]; uint32_t flags; datalink_class_t class; uint32_t media; dladm_status_t status; if ((status = dladm_datalink_id2info(linkid, &flags, &class, &media, - link, sizeof (link))) != DLADM_STATUS_OK) { + link, MAXLINKNAMELEN)) != DLADM_STATUS_OK) { goto done; } @@ -2152,58 +2931,39 @@ print_phys(show_state_t *state, datalink_id_t linkid, char **pptr, char *lim) if (status != DLADM_STATUS_OK) goto done; + (void) snprintf(pattr->link_phys_device, + sizeof (pattr->link_phys_device), "%s", dpa.dp_dev); + (void) dladm_media2str(media, pattr->link_phys_media); if (state->ls_flags == DLADM_OPT_ACTIVE) { - char name[MAXLINKNAMELEN]; boolean_t islink; if (!dpa.dp_novanity) { - (void) strlcpy(name, link, sizeof (name)); + (void) strlcpy(pattr->link_name, link, + sizeof (pattr->link_name)); islink = B_TRUE; } else { /* * This is a physical link that does not have * vanity naming support. */ - (void) strlcpy(name, dpa.dp_dev, sizeof (name)); + (void) strlcpy(pattr->link_name, dpa.dp_dev, + sizeof (pattr->link_name)); islink = B_FALSE; } - if (state->ls_parseable) { - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), - "LINK=\"%s\" MEDIA=\"%s\" ", link, - dladm_media2str(media, buf)); - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), - "STATE=\"%s\" SPEED=\"%uMb\" ", - get_linkstate(name, islink, buf), - (uint_t)((get_ifspeed(name, islink)) / 1000000ull)); - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), - "DUPLEX=\"%s\" DEVICE=\"%s\"\n", - get_linkduplex(name, islink, buf), dpa.dp_dev); - } else { - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), - "%-12s%-20s", link, - dladm_media2str(media, buf)); - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), - "%-10s%4uMb ", - get_linkstate(name, islink, buf), - (uint_t)((get_ifspeed(name, islink)) / 1000000ull)); - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), - "%-9s%s\n", get_linkduplex(name, islink, buf), - dpa.dp_dev); - } + (void) get_linkstate(pattr->link_name, islink, + pattr->link_phys_state); + (void) snprintf(pattr->link_phys_speed, + sizeof (pattr->link_phys_speed), "%u", + (uint_t)((get_ifspeed(pattr->link_name, + islink)) / 1000000ull)); + (void) get_linkduplex(pattr->link_name, islink, + pattr->link_phys_duplex); } else { - if (state->ls_parseable) { - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), - "LINK=\"%s\" DEVICE=\"%s\" MEDIA=\"%s\" " - "FLAGS=\"%c----\"\n", link, dpa.dp_dev, - dladm_media2str(media, buf), - flags & DLADM_OPT_ACTIVE ? '-' : 'r'); - } else { - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), - "%-12s%-12s%-20s%c----\n", link, - dpa.dp_dev, dladm_media2str(media, buf), - flags & DLADM_OPT_ACTIVE ? '-' : 'r'); - } + (void) snprintf(pattr->link_name, sizeof (pattr->link_name), + "%s", link); + (void) snprintf(pattr->link_flags, sizeof (pattr->link_flags), + "%c----", flags & DLADM_OPT_ACTIVE ? '-' : 'r'); } done: @@ -2215,48 +2975,38 @@ show_phys(datalink_id_t linkid, void *arg) { show_state_t *state = arg; dladm_status_t status; - char buf[MAXLINELEN]; - char *ptr = buf, *lim = buf + MAXLINELEN; + link_fields_buf_t pattr; - status = print_phys(state, linkid, &ptr, lim); + status = print_phys(state, linkid, &pattr); if (status != DLADM_STATUS_OK) goto done; - print_phys_head(state); - (void) printf("%s", buf); + + if (!state->ls_parseable && !state->ls_printheader) { + print_header(&state->ls_print); + state->ls_printheader = B_TRUE; + } + + dladm_print_output(&state->ls_print, state->ls_parseable, + dladm_print_field, (void *)&pattr); done: state->ls_status = status; return (DLADM_WALK_CONTINUE); } -static void -print_vlan_head(show_state_t *state) -{ - if (state->ls_donefirst) - return; - state->ls_donefirst = B_TRUE; - - if (state->ls_parseable) - return; - - (void) printf("%-12s%5s %-12s%s\n", "LINK", "VID", "OVER", "FLAGS"); -} /* * Print the active topology information. */ static dladm_status_t -print_vlan(show_state_t *state, datalink_id_t linkid, char **pptr, char *lim) +print_vlan(show_state_t *state, datalink_id_t linkid, link_fields_buf_t *l) { - char link[MAXLINKNAMELEN]; - char over[MAXLINKNAMELEN]; - char *fmt; dladm_vlan_attr_t vinfo; uint32_t flags; dladm_status_t status; - if ((status = dladm_datalink_id2info(linkid, &flags, NULL, NULL, link, - sizeof (link))) != DLADM_STATUS_OK) { + if ((status = dladm_datalink_id2info(linkid, &flags, NULL, NULL, + l->link_name, sizeof (l->link_name))) != DLADM_STATUS_OK) { goto done; } @@ -2267,19 +3017,15 @@ print_vlan(show_state_t *state, datalink_id_t linkid, char **pptr, char *lim) if ((status = dladm_vlan_info(linkid, &vinfo, state->ls_flags)) != DLADM_STATUS_OK || (status = dladm_datalink_id2info( - vinfo.dv_linkid, NULL, NULL, NULL, over, sizeof (over))) != - DLADM_STATUS_OK) { + vinfo.dv_linkid, NULL, NULL, NULL, l->link_over, + sizeof (l->link_over))) != DLADM_STATUS_OK) { goto done; } - if (state->ls_parseable) - fmt = "LINK=\"%s\" VID=\"%d\" OVER=\"%s\" FLAGS=\"%c%c---\"\n"; - else - fmt = "%-12s%5d %-12s%c%c---\n"; - /*LINTED: E_SEC_PRINTF_VAR_FMT*/ - *pptr += snprintf(*pptr, BUFLEN(lim, *pptr), fmt, link, - vinfo.dv_vid, over, vinfo.dv_force ? 'f' : '-', - vinfo.dv_implicit ? 'i' : '-'); + (void) snprintf(l->link_vlan_vid, sizeof (l->link_vlan_vid), "%d", + vinfo.dv_vid); + (void) snprintf(l->link_flags, sizeof (l->link_flags), "%c%c---", + vinfo.dv_force ? 'f' : '-', vinfo.dv_implicit ? 'i' : '-'); done: return (status); @@ -2290,14 +3036,19 @@ show_vlan(datalink_id_t linkid, void *arg) { show_state_t *state = arg; dladm_status_t status; - char buf[MAXLINELEN]; - char *ptr = buf, *lim = buf + MAXLINELEN; + link_fields_buf_t lbuf; - status = print_vlan(state, linkid, &ptr, lim); + status = print_vlan(state, linkid, &lbuf); if (status != DLADM_STATUS_OK) goto done; - print_vlan_head(state); - (void) printf("%s", buf); + + if (!state->ls_parseable && !state->ls_printheader) { + print_header(&state->ls_print); + state->ls_printheader = B_TRUE; + } + + dladm_print_output(&state->ls_print, state->ls_parseable, + dladm_print_field, (void *)&lbuf); done: state->ls_status = status; @@ -2310,12 +3061,21 @@ do_show_phys(int argc, char *argv[]) int option; uint32_t flags = DLADM_OPT_ACTIVE; boolean_t p_arg = B_FALSE; + boolean_t o_arg = B_FALSE; datalink_id_t linkid = DATALINK_ALL_LINKID; show_state_t state; dladm_status_t status; + char *fields_str = NULL; + print_field_t **fields; + uint_t nfields; + char *all_active_fields = + "link,media,state,speed,duplex,device"; + char *all_inactive_fields = + "link,device,media,flags"; + bzero(&state, sizeof (state)); opterr = 0; - while ((option = getopt_long(argc, argv, ":pP", + while ((option = getopt_long(argc, argv, ":pPo:", show_lopts, NULL)) != -1) { switch (option) { case 'p': @@ -2330,6 +3090,10 @@ do_show_phys(int argc, char *argv[]) flags = DLADM_OPT_PERSIST; break; + case 'o': + o_arg = B_TRUE; + fields_str = optarg; + break; default: die_opterr(optopt, option); break; @@ -2350,6 +3114,24 @@ do_show_phys(int argc, char *argv[]) state.ls_flags = flags; state.ls_donefirst = B_FALSE; + if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) { + if (state.ls_flags & DLADM_OPT_ACTIVE) + fields_str = all_active_fields; + else + fields_str = all_inactive_fields; + } + + fields = parse_output_fields(fields_str, phys_fields, + PHYS_MAX_FIELDS, CMD_TYPE_ANY, &nfields); + + if (fields == NULL) { + die("invalid field(s) specified"); + return; + } + + state.ls_print.ps_fields = fields; + state.ls_print.ps_nfields = nfields; + if (linkid == DATALINK_ALL_LINKID) { (void) dladm_walk_datalink_id(show_phys, &state, DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, flags); @@ -2371,9 +3153,16 @@ do_show_vlan(int argc, char *argv[]) datalink_id_t linkid = DATALINK_ALL_LINKID; show_state_t state; dladm_status_t status; + boolean_t o_arg = B_FALSE; + char *fields_str = NULL; + print_field_t **fields; + uint_t nfields; + char *all_fields = "link,vid,over,flags"; + + bzero(&state, sizeof (state)); opterr = 0; - while ((option = getopt_long(argc, argv, ":pP", + while ((option = getopt_long(argc, argv, ":pPo:", show_lopts, NULL)) != -1) { switch (option) { case 'p': @@ -2388,6 +3177,10 @@ do_show_vlan(int argc, char *argv[]) flags = DLADM_OPT_PERSIST; break; + case 'o': + o_arg = B_TRUE; + fields_str = optarg; + break; default: die_opterr(optopt, option); break; @@ -2408,6 +3201,19 @@ do_show_vlan(int argc, char *argv[]) state.ls_flags = flags; state.ls_donefirst = B_FALSE; + if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) + fields_str = all_fields; + + fields = parse_output_fields(fields_str, vlan_fields, VLAN_MAX_FIELDS, + CMD_TYPE_ANY, &nfields); + + if (fields == NULL) { + die("invalid field(s) specified"); + return; + } + state.ls_print.ps_fields = fields; + state.ls_print.ps_nfields = nfields; + if (linkid == DATALINK_ALL_LINKID) { (void) dladm_walk_datalink_id(show_vlan, &state, DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, flags); @@ -2464,11 +3270,6 @@ aggr_stats(datalink_id_t linkid, show_grp_state_t *state, uint_t interval) state->gs_firstonly = (interval != 0); for (;;) { - - (void) printf("%-12s%-10s%8s %8s %8s %8s %-9s%s\n", - "LINK", "PORT", "IPACKETS", "RBYTES", "OPACKETS", - "OBYTES", "IPKTDIST", "OPKTDIST"); - state->gs_donefirst = B_FALSE; if (linkid == DATALINK_ALL_LINKID) (void) dladm_walk_datalink_id(show_aggr, state, @@ -2485,29 +3286,40 @@ aggr_stats(datalink_id_t linkid, show_grp_state_t *state, uint_t interval) } static void -dev_stats(const char *dev, uint32_t interval) +dev_stats(const char *dev, uint32_t interval, char *fields_str, + show_state_t *state) { - show_state_t state; + print_field_t **fields; + uint_t nfields; + + fields = parse_output_fields(fields_str, devs_fields, DEVS_MAX_FIELDS, + CMD_TYPE_ANY, &nfields); + + if (fields == NULL) { + die("invalid field(s) specified"); + return; + } + + state->ls_print.ps_fields = fields; + state->ls_print.ps_nfields = nfields; - bzero(&state, sizeof (state)); /* * If an interval is specified, continuously show the stats * only for the first MAC port. */ - state.ls_firstonly = (interval != 0); + state->ls_firstonly = (interval != 0); for (;;) { - (void) printf("%-12s%-10s%-12s%-8s%-10s%-12s%-8s\n", - "DEV", "IPACKETS", "RBYTES", "IERRORS", "OPACKETS", - "OBYTES", "OERRORS"); + if (!state->ls_parseable) + print_header(&state->ls_print); + state->ls_donefirst = B_FALSE; - state.ls_donefirst = B_FALSE; if (dev == NULL) - (void) dladm_mac_walk(show_dev_stats, &state); + (void) dladm_mac_walk(show_dev_stats, state); else - (void) show_dev_stats(dev, &state); + (void) show_dev_stats(dev, state); if (interval == 0) break; @@ -2515,8 +3327,8 @@ dev_stats(const char *dev, uint32_t interval) (void) sleep(interval); } - if (dev != NULL && state.ls_status != DLADM_STATUS_OK) - die_dlerr(state.ls_status, "cannot show device '%s'", dev); + if (dev != NULL && state->ls_status != DLADM_STATUS_OK) + die_dlerr(state->ls_status, "cannot show device '%s'", dev); } /* accumulate stats (s1 += (s2 - s3)) */ @@ -2566,27 +3378,27 @@ get_stats(char *module, int instance, const char *name, pktsum_t *stats) if (kstat_read(kcp, ksp, NULL) == -1) goto bail; - if (kstat_value(ksp, "ipackets64", KSTAT_DATA_UINT64, + if (dladm_kstat_value(ksp, "ipackets64", KSTAT_DATA_UINT64, &stats->ipackets) < 0) goto bail; - if (kstat_value(ksp, "opackets64", KSTAT_DATA_UINT64, + if (dladm_kstat_value(ksp, "opackets64", KSTAT_DATA_UINT64, &stats->opackets) < 0) goto bail; - if (kstat_value(ksp, "rbytes64", KSTAT_DATA_UINT64, + if (dladm_kstat_value(ksp, "rbytes64", KSTAT_DATA_UINT64, &stats->rbytes) < 0) goto bail; - if (kstat_value(ksp, "obytes64", KSTAT_DATA_UINT64, + if (dladm_kstat_value(ksp, "obytes64", KSTAT_DATA_UINT64, &stats->obytes) < 0) goto bail; - if (kstat_value(ksp, "ierrors", KSTAT_DATA_UINT32, + if (dladm_kstat_value(ksp, "ierrors", KSTAT_DATA_UINT32, &stats->ierrors) < 0) goto bail; - if (kstat_value(ksp, "oerrors", KSTAT_DATA_UINT32, + if (dladm_kstat_value(ksp, "oerrors", KSTAT_DATA_UINT32, &stats->oerrors) < 0) goto bail; @@ -2641,7 +3453,7 @@ query_kstat(char *module, int instance, const char *name, const char *stat, goto bail; } - if (kstat_value(ksp, stat, type, val) < 0) + if (dladm_kstat_value(ksp, stat, type, val) < 0) goto bail; (void) kstat_close(kcp); @@ -2707,43 +3519,6 @@ get_linkduplex(const char *name, boolean_t islink, char *buf) return (dladm_linkduplex2str(linkduplex, buf)); } -#define WIFI_CMD_SCAN 0x00000001 -#define WIFI_CMD_SHOW 0x00000002 -#define WIFI_CMD_ALL (WIFI_CMD_SCAN | WIFI_CMD_SHOW) -typedef struct wifi_field { - const char *wf_name; - const char *wf_header; - uint_t wf_width; - uint_t wf_mask; - uint_t wf_cmdtype; -} wifi_field_t; - -static wifi_field_t wifi_fields[] = { -{ "link", "LINK", 10, 0, WIFI_CMD_ALL}, -{ "essid", "ESSID", 19, DLADM_WLAN_ATTR_ESSID, WIFI_CMD_ALL}, -{ "bssid", "BSSID/IBSSID", 17, DLADM_WLAN_ATTR_BSSID, WIFI_CMD_ALL}, -{ "ibssid", "BSSID/IBSSID", 17, DLADM_WLAN_ATTR_BSSID, WIFI_CMD_ALL}, -{ "mode", "MODE", 6, DLADM_WLAN_ATTR_MODE, WIFI_CMD_ALL}, -{ "speed", "SPEED", 6, DLADM_WLAN_ATTR_SPEED, WIFI_CMD_ALL}, -{ "auth", "AUTH", 8, DLADM_WLAN_ATTR_AUTH, WIFI_CMD_SHOW}, -{ "bsstype", "BSSTYPE", 8, DLADM_WLAN_ATTR_BSSTYPE, WIFI_CMD_ALL}, -{ "sec", "SEC", 6, DLADM_WLAN_ATTR_SECMODE, WIFI_CMD_ALL}, -{ "status", "STATUS", 17, DLADM_WLAN_LINKATTR_STATUS, WIFI_CMD_SHOW}, -{ "strength", "STRENGTH", 10, DLADM_WLAN_ATTR_STRENGTH, WIFI_CMD_ALL}} -; - -static char *all_scan_wifi_fields = - "link,essid,bssid,sec,strength,mode,speed,bsstype"; -static char *all_show_wifi_fields = - "link,status,essid,sec,strength,mode,speed,auth,bssid,bsstype"; -static char *def_scan_wifi_fields = - "link,essid,bssid,sec,strength,mode,speed"; -static char *def_show_wifi_fields = - "link,status,essid,sec,strength,mode,speed"; - -#define WIFI_MAX_FIELDS (sizeof (wifi_fields) / sizeof (wifi_field_t)) -#define WIFI_MAX_FIELD_LEN 32 - typedef struct { char *s_buf; char **s_fields; /* array of pointer to the fields in s_buf */ @@ -2798,13 +3573,9 @@ fail: } static int -parse_wifi_fields(char *str, wifi_field_t ***fields, uint_t *countp, +parse_wifi_fields(char *str, print_field_t ***fields, uint_t *countp, uint_t cmdtype) { - uint_t i, j; - wifi_field_t **wf = NULL; - split_t *sp; - boolean_t good_match = B_FALSE; if (cmdtype == WIFI_CMD_SCAN) { if (str == NULL) @@ -2819,21 +3590,35 @@ parse_wifi_fields(char *str, wifi_field_t ***fields, uint_t *countp, } else { return (-1); } + *fields = parse_output_fields(str, wifi_fields, WIFI_MAX_FIELDS, + cmdtype, countp); + if (*fields != NULL) + return (0); + return (-1); +} +static print_field_t ** +parse_output_fields(char *str, print_field_t *template, int max_fields, + uint_t cmdtype, uint_t *countp) +{ + split_t *sp; + boolean_t good_match = B_FALSE; + uint_t i, j; + print_field_t **pf = NULL; + + sp = split(str, max_fields, MAX_FIELD_LEN); - sp = split(str, WIFI_MAX_FIELDS, WIFI_MAX_FIELD_LEN); if (sp == NULL) - return (-1); + return (NULL); - wf = malloc(sp->s_nfields * sizeof (wifi_field_t *)); - if (wf == NULL) + pf = malloc(sp->s_nfields * sizeof (print_field_t *)); + if (pf == NULL) goto fail; for (i = 0; i < sp->s_nfields; i++) { - for (j = 0; j < WIFI_MAX_FIELDS; j++) { + for (j = 0; j < max_fields; j++) { if (strcasecmp(sp->s_fields[i], - wifi_fields[j].wf_name) == 0) { - good_match = wifi_fields[j]. - wf_cmdtype & cmdtype; + template[j].pf_name) == 0) { + good_match = template[j]. pf_cmdtype & cmdtype; break; } } @@ -2841,142 +3626,127 @@ parse_wifi_fields(char *str, wifi_field_t ***fields, uint_t *countp, goto fail; good_match = B_FALSE; - wf[i] = &wifi_fields[j]; + pf[i] = &template[j]; } *countp = i; - *fields = wf; splitfree(sp); - return (0); + return (pf); fail: - free(wf); + free(pf); splitfree(sp); - return (-1); + return (NULL); } typedef struct print_wifi_state { char *ws_link; boolean_t ws_parseable; boolean_t ws_header; - wifi_field_t **ws_fields; - uint_t ws_nfields; - boolean_t ws_lastfield; - uint_t ws_overflow; + print_state_t ws_print_state; } print_wifi_state_t; -static void -print_wifi_head(print_wifi_state_t *statep) -{ - int i; - wifi_field_t *wfp; +typedef struct wlan_scan_args_s { + print_wifi_state_t *ws_state; + void *ws_attr; +} wlan_scan_args_t; - for (i = 0; i < statep->ws_nfields; i++) { - wfp = statep->ws_fields[i]; - if (i + 1 < statep->ws_nfields) - (void) printf("%-*s ", wfp->wf_width, wfp->wf_header); - else - (void) printf("%s", wfp->wf_header); - } - (void) printf("\n"); -} static void -print_wifi_field(print_wifi_state_t *statep, wifi_field_t *wfp, - const char *value) +print_field(print_state_t *statep, print_field_t *pfp, const char *value, + boolean_t parseable) { - uint_t width = wfp->wf_width; + uint_t width = pfp->pf_width; uint_t valwidth = strlen(value); uint_t compress; - if (statep->ws_parseable) { - (void) printf("%s=\"%s\"", wfp->wf_header, value); + if (parseable) { + (void) printf("%s=\"%s\"", pfp->pf_header, value); } else { if (value[0] == '\0') - value = "--"; - if (statep->ws_lastfield) { + value = STR_UNDEF_VAL; + if (statep->ps_lastfield) { (void) printf("%s", value); return; } if (valwidth > width) { - statep->ws_overflow += valwidth - width; - } else if (valwidth < width && statep->ws_overflow > 0) { - compress = min(statep->ws_overflow, width - valwidth); - statep->ws_overflow -= compress; + statep->ps_overflow += valwidth - width; + } else if (valwidth < width && statep->ps_overflow > 0) { + compress = min(statep->ps_overflow, width - valwidth); + statep->ps_overflow -= compress; width -= compress; } (void) printf("%-*s", width, value); } - if (!statep->ws_lastfield) + if (!statep->ps_lastfield) (void) putchar(' '); } -static void -print_wlan_attr(print_wifi_state_t *statep, wifi_field_t *wfp, - dladm_wlan_attr_t *attrp) +static char * +print_wlan_attr(print_field_t *wfp, void *warg) { - char buf[DLADM_STRSIZE]; - const char *str = ""; + static char buf[DLADM_STRSIZE]; + wlan_scan_args_t *w = warg; + print_wifi_state_t *statep = w->ws_state; + dladm_wlan_attr_t *attrp = w->ws_attr; - if (wfp->wf_mask == 0) { - print_wifi_field(statep, wfp, statep->ws_link); - return; + if (wfp->pf_index == 0) { + return ((char *)statep->ws_link); } - if ((wfp->wf_mask & attrp->wa_valid) == 0) { - print_wifi_field(statep, wfp, ""); - return; + if ((wfp->pf_index & attrp->wa_valid) == 0) { + return (""); } - switch (wfp->wf_mask) { + switch (wfp->pf_index) { case DLADM_WLAN_ATTR_ESSID: - str = dladm_wlan_essid2str(&attrp->wa_essid, buf); + (void) dladm_wlan_essid2str(&attrp->wa_essid, buf); break; case DLADM_WLAN_ATTR_BSSID: - str = dladm_wlan_bssid2str(&attrp->wa_bssid, buf); + (void) dladm_wlan_bssid2str(&attrp->wa_bssid, buf); break; case DLADM_WLAN_ATTR_SECMODE: - str = dladm_wlan_secmode2str(&attrp->wa_secmode, buf); + (void) dladm_wlan_secmode2str(&attrp->wa_secmode, buf); break; case DLADM_WLAN_ATTR_STRENGTH: - str = dladm_wlan_strength2str(&attrp->wa_strength, buf); + (void) dladm_wlan_strength2str(&attrp->wa_strength, buf); break; case DLADM_WLAN_ATTR_MODE: - str = dladm_wlan_mode2str(&attrp->wa_mode, buf); + (void) dladm_wlan_mode2str(&attrp->wa_mode, buf); break; case DLADM_WLAN_ATTR_SPEED: - str = dladm_wlan_speed2str(&attrp->wa_speed, buf); + (void) dladm_wlan_speed2str(&attrp->wa_speed, buf); (void) strlcat(buf, "Mb", sizeof (buf)); break; case DLADM_WLAN_ATTR_AUTH: - str = dladm_wlan_auth2str(&attrp->wa_auth, buf); + (void) dladm_wlan_auth2str(&attrp->wa_auth, buf); break; case DLADM_WLAN_ATTR_BSSTYPE: - str = dladm_wlan_bsstype2str(&attrp->wa_bsstype, buf); + (void) dladm_wlan_bsstype2str(&attrp->wa_bsstype, buf); break; } - print_wifi_field(statep, wfp, str); + return (buf); } static boolean_t print_scan_results(void *arg, dladm_wlan_attr_t *attrp) { print_wifi_state_t *statep = arg; - int i; + wlan_scan_args_t warg; if (statep->ws_header) { statep->ws_header = B_FALSE; if (!statep->ws_parseable) - print_wifi_head(statep); + print_header(&statep->ws_print_state); } - statep->ws_overflow = 0; - for (i = 0; i < statep->ws_nfields; i++) { - statep->ws_lastfield = (i + 1 == statep->ws_nfields); - print_wlan_attr(statep, statep->ws_fields[i], attrp); - } - (void) putchar('\n'); + statep->ws_print_state.ps_overflow = 0; + bzero(&warg, sizeof (warg)); + warg.ws_state = statep; + warg.ws_attr = attrp; + dladm_print_output(&statep->ws_print_state, statep->ws_parseable, + print_wlan_attr, &warg); return (B_TRUE); } @@ -2987,8 +3757,8 @@ scan_wifi(datalink_id_t linkid, void *arg) dladm_status_t status; char link[MAXLINKNAMELEN]; - if (dladm_datalink_id2info(linkid, NULL, NULL, NULL, link, - sizeof (link)) != DLADM_STATUS_OK) { + if ((status = dladm_datalink_id2info(linkid, NULL, NULL, NULL, link, + sizeof (link))) != DLADM_STATUS_OK) { return (DLADM_WALK_CONTINUE); } @@ -3000,33 +3770,40 @@ scan_wifi(datalink_id_t linkid, void *arg) return (DLADM_WALK_CONTINUE); } -static void -print_link_attr(print_wifi_state_t *statep, wifi_field_t *wfp, - dladm_wlan_linkattr_t *attrp) +static char * +print_link_attr(print_field_t *wfp, void *warg) { - char buf[DLADM_STRSIZE]; - const char *str = ""; - - if (strcmp(wfp->wf_name, "status") == 0) { - if ((wfp->wf_mask & attrp->la_valid) != 0) - str = dladm_wlan_linkstatus2str(&attrp->la_status, buf); - print_wifi_field(statep, wfp, str); - return; + static char buf[DLADM_STRSIZE]; + char *ptr; + wlan_scan_args_t *w = warg, w1; + print_wifi_state_t *statep = w->ws_state; + dladm_wlan_linkattr_t *attrp = w->ws_attr; + + if (strcmp(wfp->pf_name, "status") == 0) { + if ((wfp->pf_index & attrp->la_valid) != 0) + (void) dladm_wlan_linkstatus2str( + &attrp->la_status, buf); + return (buf); } - print_wlan_attr(statep, wfp, &attrp->la_wlan_attr); + statep->ws_print_state.ps_overflow = 0; + bzero(&w1, sizeof (w1)); + w1.ws_state = statep; + w1.ws_attr = &attrp->la_wlan_attr; + ptr = print_wlan_attr(wfp, &w1); + return (ptr); } static int show_wifi(datalink_id_t linkid, void *arg) { - int i; print_wifi_state_t *statep = arg; dladm_wlan_linkattr_t attr; dladm_status_t status; char link[MAXLINKNAMELEN]; + wlan_scan_args_t warg; - if (dladm_datalink_id2info(linkid, NULL, NULL, NULL, link, - sizeof (link)) != DLADM_STATUS_OK) { + if ((status = dladm_datalink_id2info(linkid, NULL, NULL, NULL, link, + sizeof (link))) != DLADM_STATUS_OK) { return (DLADM_WALK_CONTINUE); } @@ -3039,15 +3816,15 @@ show_wifi(datalink_id_t linkid, void *arg) if (statep->ws_header) { statep->ws_header = B_FALSE; if (!statep->ws_parseable) - print_wifi_head(statep); + print_header(&statep->ws_print_state); } - statep->ws_overflow = 0; - for (i = 0; i < statep->ws_nfields; i++) { - statep->ws_lastfield = (i + 1 == statep->ws_nfields); - print_link_attr(statep, statep->ws_fields[i], &attr); - } - (void) putchar('\n'); + statep->ws_print_state.ps_overflow = 0; + bzero(&warg, sizeof (warg)); + warg.ws_state = statep; + warg.ws_attr = &attr; + dladm_print_output(&statep->ws_print_state, statep->ws_parseable, + print_link_attr, &warg); return (DLADM_WALK_CONTINUE); } @@ -3056,7 +3833,7 @@ do_display_wifi(int argc, char **argv, int cmd) { int option; char *fields_str = NULL; - wifi_field_t **fields; + print_field_t **fields; int (*callback)(datalink_id_t, void *); uint_t nfields; print_wifi_state_t state; @@ -3102,8 +3879,9 @@ do_display_wifi(int argc, char **argv, int cmd) if (parse_wifi_fields(fields_str, &fields, &nfields, cmd) < 0) die("invalid field(s) specified"); - state.ws_fields = fields; - state.ws_nfields = nfields; + bzero(&state.ws_print_state, sizeof (state.ws_print_state)); + state.ws_print_state.ps_fields = fields; + state.ws_print_state.ps_nfields = nfields; if (linkid == DATALINK_ALL_LINKID) { (void) dladm_walk_datalink_id(callback, &state, @@ -3423,32 +4201,6 @@ do_disconnect_wifi(int argc, char **argv) die_dlerr(status, "cannot disconnect"); } -#define MAX_PROPS 32 -#define MAX_PROP_LINE 512 - -typedef struct prop_info { - char *pi_name; - char *pi_val[DLADM_MAX_PROP_VALCNT]; - uint_t pi_count; -} prop_info_t; - -typedef struct prop_list { - prop_info_t pl_info[MAX_PROPS]; - uint_t pl_count; - char *pl_buf; -} prop_list_t; - -typedef struct show_linkprop_state { - char ls_link[MAXLINKNAMELEN]; - char *ls_line; - char **ls_propvals; - prop_list_t *ls_proplist; - uint32_t ls_parseable : 1, - ls_persist : 1, - ls_header : 1, - ls_pad_bits : 29; - dladm_status_t ls_status; -} show_linkprop_state_t; static void free_props(prop_list_t *list) @@ -3476,6 +4228,19 @@ parse_props(char *str, prop_list_t **listp, boolean_t novalues) if (buf == NULL) goto fail; + /* + * buf is a string of form [<propname>=<value>][,<propname>=<value>]+ + * where each <value> string itself could be a comma-separated array. + * The loop below will count the number of propname assignments + * in pl_count; for each property, there is a pip entry with + * pi_name == <propname>, pi_count == # of elements in <value> array. + * pi_val[] contains the actual values. + * + * This could really be a combination of calls to + * strtok (token delimiter is ",") and strchr (chr '=') + * with appropriate null/string-bound-checks. + */ + curr = buf; len = strlen(buf); pip = NULL; @@ -3523,15 +4288,8 @@ fail: } static void -print_linkprop_head(void) -{ - (void) printf("%-12s %-15s %-14s %-14s %-20s \n", - "LINK", "PROPERTY", "VALUE", "DEFAULT", "POSSIBLE"); -} - -static void print_linkprop(datalink_id_t linkid, show_linkprop_state_t *statep, - const char *propname, dladm_prop_type_t type, const char *typename, + const char *propname, dladm_prop_type_t type, const char *format, char **pptr) { int i; @@ -3551,6 +4309,7 @@ print_linkprop(datalink_id_t linkid, show_linkprop_state_t *statep, propvals = &unknown; } else { statep->ls_status = status; + statep->ls_retstatus = status; return; } } else if (status == DLADM_STATUS_NOTSUP || @@ -3561,21 +4320,25 @@ print_linkprop(datalink_id_t linkid, show_linkprop_state_t *statep, else propvals = ¬sup; } else { - statep->ls_status = status; - if (statep->ls_proplist) { + if (statep->ls_proplist && + statep->ls_status == DLADM_STATUS_OK) { warn_dlerr(status, "cannot get link property '%s' for %s", propname, statep->ls_link); } + statep->ls_status = status; + statep->ls_retstatus = status; return; } } + statep->ls_status = DLADM_STATUS_OK; + ptr = buf; lim = buf + DLADM_STRSIZE; for (i = 0; i < valcnt; i++) { if (propvals[i][0] == '\0' && !statep->ls_parseable) - ptr += snprintf(ptr, lim - ptr, "--,"); + ptr += snprintf(ptr, lim - ptr, STR_UNDEF_VAL","); else ptr += snprintf(ptr, lim - ptr, "%s,", propvals[i]); if (ptr >= lim) @@ -3587,58 +4350,87 @@ print_linkprop(datalink_id_t linkid, show_linkprop_state_t *statep, lim = statep->ls_line + MAX_PROP_LINE; if (statep->ls_parseable) { *pptr += snprintf(*pptr, lim - *pptr, - "%s=\"%s\" ", typename, buf); + "%s", buf); } else { *pptr += snprintf(*pptr, lim - *pptr, format, buf); } } -static int -show_linkprop(datalink_id_t linkid, const char *propname, void *arg) +static char * +linkprop_callback(print_field_t *pf, void *ls_arg) { - show_linkprop_state_t *statep = arg; + linkprop_args_t *arg = ls_arg; + char *propname = arg->ls_propname; + show_linkprop_state_t *statep = arg->ls_state; char *ptr = statep->ls_line; char *lim = ptr + MAX_PROP_LINE; + datalink_id_t linkid = arg->ls_linkid; - if (statep->ls_parseable) - ptr += snprintf(ptr, lim - ptr, "LINK=\"%s\" ", - statep->ls_link); - else - ptr += snprintf(ptr, lim - ptr, "%-12s ", statep->ls_link); - - if (statep->ls_parseable) - ptr += snprintf(ptr, lim - ptr, "PROPERTY=\"%s\" ", propname); - else - ptr += snprintf(ptr, lim - ptr, "%-15s ", propname); - - print_linkprop(linkid, statep, propname, - statep->ls_persist ? DLADM_PROP_VAL_PERSISTENT : - DLADM_PROP_VAL_CURRENT, "VALUE", "%-14s ", &ptr); - - /* - * If we failed to query the link property, for example, query - * the persistent value of a non-persistable link property, simply - * skip the output. - */ + switch (pf->pf_index) { + case LINKPROP_LINK: + (void) snprintf(ptr, lim - ptr, "%s", statep->ls_link); + break; + case LINKPROP_PROPERTY: + (void) snprintf(ptr, lim - ptr, "%s", propname); + break; + case LINKPROP_VALUE: + print_linkprop(linkid, statep, propname, + statep->ls_persist ? DLADM_PROP_VAL_PERSISTENT : + DLADM_PROP_VAL_CURRENT, "%s", &ptr); + /* + * If we failed to query the link property, for example, query + * the persistent value of a non-persistable link property, + * simply skip the output. + */ + if (statep->ls_status != DLADM_STATUS_OK) + goto skip; + ptr = statep->ls_line; + break; + case LINKPROP_DEFAULT: + print_linkprop(linkid, statep, propname, + DLADM_PROP_VAL_DEFAULT, "%s", &ptr); + if (statep->ls_status != DLADM_STATUS_OK) + goto skip; + ptr = statep->ls_line; + break; + case LINKPROP_POSSIBLE: + print_linkprop(linkid, statep, propname, + DLADM_PROP_VAL_MODIFIABLE, "%s ", &ptr); + if (statep->ls_status != DLADM_STATUS_OK) + goto skip; + ptr = statep->ls_line; + break; + default: + die("invalid input"); + break; + } + return (ptr); +skip: if (statep->ls_status != DLADM_STATUS_OK) - return (DLADM_WALK_CONTINUE); + return (NULL); + else + return (""); +} - print_linkprop(linkid, statep, propname, DLADM_PROP_VAL_DEFAULT, - "DEFAULT", "%-14s ", &ptr); - if (statep->ls_status != DLADM_STATUS_OK) - return (DLADM_WALK_CONTINUE); +static int +show_linkprop(datalink_id_t linkid, const char *propname, void *arg) +{ + show_linkprop_state_t *statep = arg; + linkprop_args_t ls_arg; - print_linkprop(linkid, statep, propname, DLADM_PROP_VAL_MODIFIABLE, - "POSSIBLE", "%-20s ", &ptr); - if (statep->ls_status != DLADM_STATUS_OK) - return (DLADM_WALK_CONTINUE); + bzero(&ls_arg, sizeof (ls_arg)); + ls_arg.ls_state = statep; + ls_arg.ls_propname = (char *)propname; + ls_arg.ls_linkid = linkid; if (statep->ls_header) { statep->ls_header = B_FALSE; if (!statep->ls_parseable) - print_linkprop_head(); + print_header(&statep->ls_print); } - (void) printf("%s\n", statep->ls_line); + dladm_print_output(&statep->ls_print, statep->ls_parseable, + linkprop_callback, (void *)&ls_arg); + return (DLADM_WALK_CONTINUE); } @@ -3651,6 +4443,13 @@ do_show_linkprop(int argc, char **argv) show_linkprop_state_t state; uint32_t flags = DLADM_OPT_ACTIVE; dladm_status_t status; + char *fields_str = NULL; + print_field_t **fields; + uint_t nfields; + char *all_fields = + "link,property,value,default,possible"; + + fields_str = all_fields; opterr = 0; state.ls_propvals = NULL; @@ -3658,7 +4457,8 @@ do_show_linkprop(int argc, char **argv) state.ls_parseable = B_FALSE; state.ls_persist = B_FALSE; state.ls_header = B_TRUE; - while ((option = getopt_long(argc, argv, ":p:cP", + state.ls_retstatus = DLADM_STATUS_OK; + while ((option = getopt_long(argc, argv, ":p:cPo:", prop_longopts, NULL)) != -1) { switch (option) { case 'p': @@ -3672,6 +4472,12 @@ do_show_linkprop(int argc, char **argv) state.ls_persist = B_TRUE; flags = DLADM_OPT_PERSIST; break; + case 'o': + if (strcasecmp(optarg, "all") == 0) + fields_str = all_fields; + else + fields_str = optarg; + break; default: die_opterr(optopt, option); break; @@ -3687,9 +4493,20 @@ do_show_linkprop(int argc, char **argv) usage(); } + bzero(&state.ls_print, sizeof (print_state_t)); state.ls_proplist = proplist; state.ls_status = DLADM_STATUS_OK; + fields = parse_output_fields(fields_str, linkprop_fields, + LINKPROP_MAX_FIELDS, CMD_TYPE_ANY, &nfields); + + if (fields == NULL) { + die("invalid field(s) specified"); + return; + } + + state.ls_print.ps_fields = fields; + state.ls_print.ps_nfields = nfields; if (linkid == DATALINK_ALL_LINKID) { (void) dladm_walk_datalink_id(show_linkprop_onelink, &state, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, flags); @@ -3698,13 +4515,8 @@ do_show_linkprop(int argc, char **argv) } free_props(proplist); - if (state.ls_status != DLADM_STATUS_OK) { - if (optind == (argc - 1)) { - warn_dlerr(state.ls_status, - "show-linkprop failed for %s", argv[optind]); - } + if (state.ls_retstatus != DLADM_STATUS_OK) exit(EXIT_FAILURE); - } } static int @@ -3839,8 +4651,9 @@ set_linkprop(int argc, char **argv, boolean_t reset) die_dlerr(status, "link %s is not valid", argv[optind]); if (proplist == NULL) { - if ((status = dladm_set_linkprop(linkid, NULL, NULL, 0, - DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) { + status = dladm_set_linkprop(linkid, NULL, NULL, 0, + DLADM_OPT_ACTIVE); + if (status != DLADM_STATUS_OK) { warn_dlerr(status, "cannot reset link property " "on '%s'", argv[optind]); } @@ -4347,18 +5160,10 @@ do_delete_secobj(int argc, char **argv) typedef struct show_secobj_state { boolean_t ss_persist; boolean_t ss_parseable; - boolean_t ss_debug; boolean_t ss_header; + print_state_t ss_print; } show_secobj_state_t; -static void -print_secobj_head(show_secobj_state_t *statep) -{ - (void) printf("%-20s %-20s ", "OBJECT", "CLASS"); - if (statep->ss_debug) - (void) printf("%-30s", "VALUE"); - (void) putchar('\n'); -} static boolean_t show_secobj(void *arg, const char *obj_name) @@ -4370,6 +5175,7 @@ show_secobj(void *arg, const char *obj_name) dladm_secobj_class_t class; show_secobj_state_t *statep = arg; dladm_status_t status; + secobj_fields_buf_t sbuf; if (statep->ss_persist) flags |= DLADM_OPT_PERSIST; @@ -4381,29 +5187,23 @@ show_secobj(void *arg, const char *obj_name) if (statep->ss_header) { statep->ss_header = B_FALSE; if (!statep->ss_parseable) - print_secobj_head(statep); - } - - if (statep->ss_parseable) { - (void) printf("OBJECT=\"%s\" CLASS=\"%s\" ", obj_name, - dladm_secobjclass2str(class, buf)); - } else { - (void) printf("%-20s %-20s ", obj_name, - dladm_secobjclass2str(class, buf)); + print_header(&statep->ss_print); } - if (statep->ss_debug) { + (void) snprintf(sbuf.ss_obj_name, sizeof (sbuf.ss_obj_name), + obj_name); + (void) dladm_secobjclass2str(class, buf); + (void) snprintf(sbuf.ss_class, sizeof (sbuf.ss_class), "%s", buf); + if (getuid() == 0) { char val[DLADM_SECOBJ_VAL_MAX * 2]; uint_t len = sizeof (val); - if (octet_to_hexascii(obj_val, obj_len, val, &len) == 0) { - if (statep->ss_parseable) - (void) printf("VALUE=\"0x%s\"", val); - else - (void) printf("0x%-30s", val); - } + if (octet_to_hexascii(obj_val, obj_len, val, &len) == 0) + (void) snprintf(sbuf.ss_val, + sizeof (sbuf.ss_val), "%s", val); } - (void) putchar('\n'); + dladm_print_output(&statep->ss_print, statep->ss_parseable, + dladm_print_field, (void *)&sbuf); return (B_TRUE); } @@ -4416,13 +5216,20 @@ do_show_secobj(int argc, char **argv) uint_t i; split_t *sp; uint_t flags; + char *fields_str = NULL; + print_field_t **fields; + uint_t nfields; + char *def_fields = "object,class"; + char *all_fields = "object,class,value"; opterr = 0; + bzero(&state, sizeof (state)); + state.ss_parseable = B_FALSE; + fields_str = def_fields; state.ss_persist = B_FALSE; state.ss_parseable = B_FALSE; - state.ss_debug = B_FALSE; state.ss_header = B_TRUE; - while ((option = getopt_long(argc, argv, ":pPd", + while ((option = getopt_long(argc, argv, ":pPo:", wifi_longopts, NULL)) != -1) { switch (option) { case 'p': @@ -4431,10 +5238,11 @@ do_show_secobj(int argc, char **argv) case 'P': state.ss_persist = B_TRUE; break; - case 'd': - if (getuid() != 0) - die("insufficient privileges"); - state.ss_debug = B_TRUE; + case 'o': + if (strcasecmp(optarg, "all") == 0) + fields_str = all_fields; + else + fields_str = optarg; break; default: die_opterr(optopt, option); @@ -4442,6 +5250,17 @@ do_show_secobj(int argc, char **argv) } } + fields = parse_output_fields(fields_str, secobj_fields, + DEV_SOBJ_FIELDS, CMD_TYPE_ANY, &nfields); + + if (fields == NULL) { + die("invalid field(s) specified"); + return; + } + state.ss_print.ps_fields = fields; + state.ss_print.ps_nfields = nfields; + + flags = state.ss_persist ? DLADM_OPT_PERSIST : 0; if (optind == (argc - 1)) { sp = split(argv[optind], MAX_SECOBJS, MAX_SECOBJ_NAMELEN); if (sp == NULL) { @@ -4457,7 +5276,6 @@ do_show_secobj(int argc, char **argv) } else if (optind != argc) usage(); - flags = state.ss_persist ? DLADM_OPT_PERSIST : 0; status = dladm_walk_secobj(&state, show_secobj, flags); if (status != DLADM_STATUS_OK) die_dlerr(status, "show-secobj"); @@ -4485,6 +5303,153 @@ do_init_linkprop(int argc, char **argv) /* ARGSUSED */ static void +do_show_ether(int argc, char **argv) +{ + int option; + datalink_id_t linkid; + print_ether_state_t state; + print_field_t **fields; + char *fields_str; + uint_t nfields; + char *all_fields = + "link,ptype,state,auto,speed-duplex,pause,rem_fault"; + char *default_fields = + "link,ptype,state,auto,speed-duplex,pause"; + + fields_str = default_fields; + bzero(&state, sizeof (state)); + state.es_link = NULL; + state.es_parseable = B_FALSE; + + while ((option = getopt_long(argc, argv, "o:px", + showeth_lopts, NULL)) != -1) { + switch (option) { + case 'x': + state.es_extended = B_TRUE; + break; + case 'p': + state.es_parseable = B_TRUE; + break; + case 'o': + if (strcasecmp(optarg, "all") == 0) + fields_str = all_fields; + else + fields_str = optarg; + break; + default: + die_opterr(optopt, option); + break; + } + } + + if (optind == (argc - 1)) + state.es_link = argv[optind]; + + fields = parse_output_fields(fields_str, ether_fields, + ETHER_MAX_FIELDS, CMD_TYPE_ANY, &nfields); + + if (fields == NULL) { + die("invalid field(s) specified"); + exit(EXIT_FAILURE); + } + state.es_print.ps_fields = fields; + state.es_print.ps_nfields = nfields; + + if (state.es_link == NULL) { + (void) dladm_walk_datalink_id(show_etherprop, &state, + DATALINK_CLASS_PHYS, DL_ETHER, + DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST); + } else { + if (!link_is_ether(state.es_link, &linkid)) { + die("invalid link specified"); + } + (void) show_etherprop(linkid, &state); + } + + exit(DLADM_STATUS_OK); + +} + +static char * +dladm_print_field(print_field_t *pf, void *arg) +{ + char *value; + + value = (char *)arg + pf->pf_offset; + return (value); +} + +static int +show_etherprop(datalink_id_t linkid, void *arg) +{ + print_ether_state_t *statep = arg; + char buf[DLADM_STRSIZE]; + int speed; + uint64_t s; + uint32_t autoneg, pause, asmpause, adv_rf, cap_rf, lp_rf; + ether_fields_buf_t ebuf; + char speed_unit = 'M'; + + if (dladm_datalink_id2info(linkid, NULL, NULL, NULL, + ebuf.eth_link, sizeof (ebuf.eth_link)) != DLADM_STATUS_OK) { + return (DLADM_WALK_CONTINUE); + } + + if (!statep->es_header && !statep->es_parseable) { + print_header(&statep->es_print); + statep->es_header = B_TRUE; + } + (void) snprintf(ebuf.eth_ptype, sizeof (ebuf.eth_ptype), + "%s", "current"); + + (void) dladm_get_single_mac_stat(linkid, "link_autoneg", + KSTAT_DATA_UINT32, &autoneg); + (void) snprintf(ebuf.eth_autoneg, sizeof (ebuf.eth_autoneg), + "%s", (autoneg ? "yes" : "no")); + + (void) dladm_get_single_mac_stat(linkid, "link_pause", + KSTAT_DATA_UINT32, &pause); + (void) dladm_get_single_mac_stat(linkid, "link_asmpause", + KSTAT_DATA_UINT32, &asmpause); + (void) snprintf(ebuf.eth_pause, sizeof (ebuf.eth_pause), + "%s", pause_str(pause, asmpause)); + + (void) dladm_get_single_mac_stat(linkid, "ifspeed", + KSTAT_DATA_UINT64, &s); + speed = (int)(s/1000000ull); + + if (speed >= 1000) { + speed = speed/1000; + speed_unit = 'G'; + } + (void) get_linkduplex(ebuf.eth_link, B_FALSE, buf); + (void) snprintf(ebuf.eth_spdx, sizeof (ebuf.eth_spdx), "%d%c-%c", + speed, speed_unit, buf[0]); + + (void) get_linkstate(ebuf.eth_link, B_FALSE, buf); + (void) snprintf(ebuf.eth_state, sizeof (ebuf.eth_state), + "%s", buf); + + (void) dladm_get_single_mac_stat(linkid, "adv_rem_fault", + KSTAT_DATA_UINT32, &adv_rf); + (void) dladm_get_single_mac_stat(linkid, "cap_rem_fault", + KSTAT_DATA_UINT32, &cap_rf); + (void) dladm_get_single_mac_stat(linkid, "lp_rem_fault", + KSTAT_DATA_UINT32, &lp_rf); + (void) snprintf(ebuf.eth_rem_fault, sizeof (ebuf.eth_rem_fault), + "%s", (adv_rf == 0 && lp_rf == 0 ? "none" : "fault")); + + dladm_print_output(&statep->es_print, statep->es_parseable, + dladm_print_field, &ebuf); + + if (statep->es_extended) + show_ether_xprop(linkid, arg); + + return (DLADM_WALK_CONTINUE); +} + +/* ARGSUSED */ +static void do_init_secobj(int argc, char **argv) { dladm_status_t status; @@ -4657,3 +5622,224 @@ die_opterr(int opt, int opterr) break; } } + +static void +show_ether_xprop(datalink_id_t linkid, void *arg) +{ + print_ether_state_t *statep = arg; + char buf[DLADM_STRSIZE]; + uint32_t autoneg, pause, asmpause, adv_rf, cap_rf, lp_rf; + boolean_t add_comma, r1; + ether_fields_buf_t ebuf; + + /* capable */ + bzero(&ebuf, sizeof (ebuf)); + (void) snprintf(ebuf.eth_link, sizeof (ebuf.eth_link), ""); + + (void) snprintf(ebuf.eth_ptype, sizeof (ebuf.eth_ptype), + "%s", "capable"); + (void) snprintf(ebuf.eth_state, sizeof (ebuf.eth_state), + STR_UNDEF_VAL); + + (void) dladm_get_single_mac_stat(linkid, "cap_autoneg", + KSTAT_DATA_UINT32, &autoneg); + (void) snprintf(ebuf.eth_autoneg, sizeof (ebuf.eth_autoneg), + "%s", (autoneg ? "yes" : "no")); + + add_comma = B_FALSE; + bzero(buf, sizeof (buf)); + r1 = get_speed_duplex(linkid, "cap_1000", buf, "1G", B_FALSE); + if (r1) + add_comma = B_TRUE; + r1 = get_speed_duplex(linkid, "cap_100", buf, "100M", add_comma); + if (r1) + add_comma = B_TRUE; + r1 = get_speed_duplex(linkid, "cap_10", buf, "10M", add_comma); + add_comma = B_FALSE; + (void) snprintf(ebuf.eth_spdx, sizeof (ebuf.eth_spdx), "%s", buf); + + (void) dladm_get_single_mac_stat(linkid, "cap_pause", + KSTAT_DATA_UINT32, &pause); + (void) dladm_get_single_mac_stat(linkid, "cap_asmpause", + KSTAT_DATA_UINT32, &asmpause); + (void) snprintf(ebuf.eth_pause, sizeof (ebuf.eth_pause), + "%s", pause_str(pause, asmpause)); + + (void) dladm_get_single_mac_stat(linkid, "adv_rem_fault", + KSTAT_DATA_UINT32, &adv_rf); + (void) dladm_get_single_mac_stat(linkid, "cap_rem_fault", + KSTAT_DATA_UINT32, &cap_rf); + (void) dladm_get_single_mac_stat(linkid, "lp_rem_fault", + KSTAT_DATA_UINT32, &lp_rf); + + (void) snprintf(ebuf.eth_rem_fault, sizeof (ebuf.eth_rem_fault), + "%s", (cap_rf ? "yes" : "no")); + + dladm_print_output(&statep->es_print, statep->es_parseable, + dladm_print_field, &ebuf); + + /* advertised */ + bzero(&ebuf, sizeof (ebuf)); + (void) snprintf(ebuf.eth_ptype, sizeof (ebuf.eth_ptype), + "%s", "adv"); + (void) snprintf(ebuf.eth_state, sizeof (ebuf.eth_state), + STR_UNDEF_VAL); + + (void) dladm_get_single_mac_stat(linkid, "adv_cap_autoneg", + KSTAT_DATA_UINT32, &autoneg); + (void) snprintf(ebuf.eth_autoneg, sizeof (ebuf.eth_autoneg), + "%s", (autoneg ? "yes" : "no")); + + add_comma = B_FALSE; + bzero(buf, sizeof (buf)); + r1 = get_speed_duplex(linkid, "adv_cap_1000", buf, "1G", add_comma); + if (r1) + add_comma = B_TRUE; + r1 = get_speed_duplex(linkid, "adv_cap_100", buf, "100M", add_comma); + if (r1) + add_comma = B_TRUE; + r1 = get_speed_duplex(linkid, "adv_cap_10", buf, "10M", add_comma); + add_comma = B_FALSE; + (void) snprintf(ebuf.eth_spdx, sizeof (ebuf.eth_spdx), "%s", buf); + + (void) dladm_get_single_mac_stat(linkid, "adv_cap_pause", + KSTAT_DATA_UINT32, &pause); + (void) dladm_get_single_mac_stat(linkid, "adv_cap_asmpause", + KSTAT_DATA_UINT32, &asmpause); + (void) snprintf(ebuf.eth_pause, sizeof (ebuf.eth_pause), + "%s", pause_str(pause, asmpause)); + + (void) snprintf(ebuf.eth_rem_fault, sizeof (ebuf.eth_rem_fault), + "%s", (adv_rf ? "fault" : "none")); + + dladm_print_output(&statep->es_print, statep->es_parseable, + dladm_print_field, &ebuf); + + /* peeradv */ + bzero(&ebuf, sizeof (ebuf)); + (void) snprintf(ebuf.eth_ptype, sizeof (ebuf.eth_ptype), + "%s", "peeradv"); + (void) snprintf(ebuf.eth_state, sizeof (ebuf.eth_state), + STR_UNDEF_VAL); + + (void) dladm_get_single_mac_stat(linkid, "lp_cap_autoneg", + KSTAT_DATA_UINT32, &autoneg); + (void) snprintf(ebuf.eth_autoneg, sizeof (ebuf.eth_autoneg), + "%s", (autoneg ? "yes" : "no")); + + add_comma = B_FALSE; + bzero(buf, sizeof (buf)); + r1 = get_speed_duplex(linkid, "lp_cap_1000", buf, "1G", add_comma); + if (r1) + add_comma = B_TRUE; + r1 = get_speed_duplex(linkid, "lp_cap_100", buf, "100M", add_comma); + if (r1) + add_comma = B_TRUE; + r1 = get_speed_duplex(linkid, "lp_cap_10", buf, "10M", add_comma); + (void) snprintf(ebuf.eth_spdx, sizeof (ebuf.eth_spdx), "%s", buf); + + (void) dladm_get_single_mac_stat(linkid, "lp_cap_pause", + KSTAT_DATA_UINT32, &pause); + (void) dladm_get_single_mac_stat(linkid, "lp_cap_asmpause", + KSTAT_DATA_UINT32, &asmpause); + (void) snprintf(ebuf.eth_pause, sizeof (ebuf.eth_pause), + "%s", pause_str(pause, asmpause)); + + (void) snprintf(ebuf.eth_rem_fault, sizeof (ebuf.eth_rem_fault), + "%s", (lp_rf ? "fault" : "none")); + + dladm_print_output(&statep->es_print, statep->es_parseable, + dladm_print_field, &ebuf); +} + +static boolean_t +get_speed_duplex(datalink_id_t linkid, const char *mii_prop_prefix, + char *spbuf, char *sp, boolean_t add_comma) +{ + int speed, duplex = 0; + boolean_t ret = B_FALSE; + char mii_prop[DLADM_STRSIZE]; + + (void) snprintf(mii_prop, DLADM_STRSIZE, "%sfdx", mii_prop_prefix); + (void) dladm_get_single_mac_stat(linkid, mii_prop, KSTAT_DATA_UINT32, + &speed); + if (speed) { + ret = B_TRUE; + duplex |= IS_FDX; + } + (void) snprintf(mii_prop, DLADM_STRSIZE, "%shdx", mii_prop_prefix); + (void) dladm_get_single_mac_stat(linkid, mii_prop, + KSTAT_DATA_UINT32, &speed); + if (speed) { + ret = B_TRUE; + duplex |= IS_HDX; + } + if (ret) { + if (add_comma) + (void) strncat(spbuf, ",", DLADM_STRSIZE); + (void) strncat(spbuf, sp, DLADM_STRSIZE); + if ((duplex & (IS_FDX|IS_HDX)) == (IS_FDX|IS_HDX)) + (void) strncat(spbuf, "-fh", DLADM_STRSIZE); + else if (duplex & IS_FDX) + (void) strncat(spbuf, "-f", DLADM_STRSIZE); + else if (duplex & IS_HDX) + (void) strncat(spbuf, "-h", DLADM_STRSIZE); + } + return (ret); +} + +static void +dladm_print_output(print_state_t *statep, boolean_t parseable, + print_callback_t fn, void *arg) +{ + int i; + char *value; + print_field_t **pf; + + pf = statep->ps_fields; + for (i = 0; i < statep->ps_nfields; i++) { + statep->ps_lastfield = (i + 1 == statep->ps_nfields); + value = (*fn)(pf[i], arg); + if (value != NULL) + print_field(statep, pf[i], value, parseable); + } + (void) putchar('\n'); +} + +static void +print_header(print_state_t *ps) +{ + int i; + print_field_t **pf; + + pf = ps->ps_fields; + for (i = 0; i < ps->ps_nfields; i++) { + ps->ps_lastfield = (i + 1 == ps->ps_nfields); + print_field(ps, pf[i], pf[i]->pf_header, B_FALSE); + } + (void) putchar('\n'); +} + +static char * +pause_str(int pause, int asmpause) +{ + if (pause == 1) + return ("bi"); + if (asmpause == 1) + return ("tx"); + return ("none"); +} + +static boolean_t +link_is_ether(const char *link, datalink_id_t *linkid) +{ + uint32_t media; + datalink_class_t class; + + if (dladm_name2info(link, linkid, NULL, &class, &media) == + DLADM_STATUS_OK) { + if (class == DATALINK_CLASS_PHYS && media == DL_ETHER) + return (B_TRUE); + } + return (B_FALSE); +} diff --git a/usr/src/cmd/dladm/dladm.xcl b/usr/src/cmd/dladm/dladm.xcl index c48e5d4bbb..b849b22f79 100644 --- a/usr/src/cmd/dladm/dladm.xcl +++ b/usr/src/cmd/dladm/dladm.xcl @@ -83,24 +83,30 @@ msgid ":p:cP" msgid ":pPd" msgid ":psi:" msgid "?" +msgid "100M" msgid "ADT_dladm_create_secobj" msgid "ADT_dladm_delete_secobj" msgid "AUTH" +msgid "AUTO" msgid "BSSID/IBSSID" msgid "BSSTYPE" msgid "CLASS" msgid "DEFAULT" +msgid "DUPLEX" msgid "ESSID" msgid "LINK" msgid "MODE" msgid "Mb" msgid "OBJECT" msgid "OBJECT=\"%s\" CLASS=\"%s\" " +msgid "PAUSE" msgid "POSSIBLE" msgid "PROPERTY" msgid "PROPERTY=\"%s\" " +msgid "REM_FAULT" msgid "SEC" msgid "SPEED" +msgid "SPEED-DUPLEX" msgid "STATUS" msgid "STRENGTH" msgid "VALUE" @@ -116,6 +122,12 @@ msgid "\t\t%-10llu" msgid "\t\tipackets rbytes ierrors " msgid "\tipackets rbytes opackets obytes " msgid "active" +msgid "adv_cap_10" +msgid "adv_cap_100" +msgid "adv_cap_1000" +msgid "adv_cap_asmpause" +msgid "adv_cap_autoneg" +msgid "adv_cap_pause" msgid "add-aggr" msgid "adt_alloc_event (%s): %s" msgid "adt_start_session: %s" @@ -125,13 +137,20 @@ msgid "all" msgid "all-links" msgid "attached" msgid "auth" +msgid "auto" msgid "bssid" msgid "bsstype" +msgid "cap_pause" +msgid "cap_10" +msgid "cap_1000" +msgid "cap_autoneg" +msgid "capable" msgid "connect-wifi" msgid "create-aggr" msgid "create-ibss" msgid "create-secobj" msgid "create-vlan" +msgid "current" msgid "delete-aggr" msgid "delete-phys" msgid "delete-secobj" @@ -141,7 +160,9 @@ msgid "dev" msgid "disconnect-wifi" msgid "down" msgid "down-aggr" +msgid "duplex" msgid "essid" +msgid "fault" msgid "file" msgid "forever" msgid "full" @@ -152,19 +173,41 @@ msgid "ifspeed" msgid "init-linkprop" msgid "init-secobj" msgid "interval" +msgid "invalid input" msgid "ipackets64" msgid "key" msgid "lacp" msgid "lacp-mode" msgid "lacp-timer" msgid "link" +msgid "link,class,mtu,state,over" +msgid "link,device,media,flags" msgid "link,essid,bssid,sec,strength,mode,speed" msgid "link,essid,bssid,sec,strength,mode,speed,auth,bsstype" +msgid "link,ipackets,rbytes,ierrors,opackets,obytes,oerrors" +msgid "link,media,state,speed,duplex,device" +msgid "link,property,value,default,possible" +msgid "link,policy,addrpolicy,lacpactivity,lacptimer,flags" +msigd "link,port,aggregatable,sync,coll,dist,defaulted,expired" +msgid "link,port,ipackets,rbytes,opackets,obytes,ipktdist,opktdist" +msgid "link,port,speed,duplex,state,address,portstate" +msgid "link,state,speed,duplex" +msgid "link,vid,over,flags" msgid "link,status,essid,sec,strength,mode,speed" msgid "link,status,essid,sec,strength,mode,speed,auth,bssid,bsstype" +msgid "link_asmpause" +msgid "link_autoneg" msgid "link_duplex" +msgid "link_pause" msgid "link_state" msgid "long" +msgid "lp_cap_10" +msgid "lp_cap_100" +msgid "lp_cap_1000" +msgid "lp_cap_autoneg" +msgid "lp_cap_asmpause" +msgid "lp_cap_pause" +msgid "lp_rem_fault" msgid "mac" msgid "mode" msgid "modify-aggr" @@ -177,11 +220,14 @@ msgid "opackets64" msgid "output" msgid "parseable" msgid "passive" +msgid "pause" +msgid "peeradv" msgid "persistent" msgid "policy" msgid "prop" msgid "r" msgid "rbytes64" +msgid "rem_fault" msgid "remove-aggr" msgid "rename-link" msgid "reset-linkprop" @@ -198,8 +244,10 @@ msgid "show-phys" msgid "show-secobj" msgid "show-wifi" msgid "show-vlan" +msgid "show-ether" msgid "solaris.network.link.security" msgid "speed" +msgid "speed-duplex" msgid "standby" msgid "statistics" msgid "status" diff --git a/usr/src/lib/libdladm/Makefile.com b/usr/src/lib/libdladm/Makefile.com index 4caeb08465..0f6419bd29 100644 --- a/usr/src/lib/libdladm/Makefile.com +++ b/usr/src/lib/libdladm/Makefile.com @@ -36,7 +36,8 @@ include ../../Makefile.lib include ../../Makefile.rootfs LIBS = $(DYNLIB) $(LINTLIB) -LDLIBS += -ldevinfo -lc -linetutil -lsocket -lscf -lrcm -lnvpair +LDLIBS += -ldevinfo -lc -linetutil -lsocket -lscf -lrcm \ + -lnvpair -lkstat SRCDIR = ../common $(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC) diff --git a/usr/src/lib/libdladm/common/libdladm.c b/usr/src/lib/libdladm/common/libdladm.c index 58f15038bc..5a25d01c9d 100644 --- a/usr/src/lib/libdladm/common/libdladm.c +++ b/usr/src/lib/libdladm/common/libdladm.c @@ -163,6 +163,8 @@ dladm_status_t dladm_errno2status(int err) { switch (err) { + case 0: + return (DLADM_STATUS_OK); case EINVAL: return (DLADM_STATUS_BADARG); case EEXIST: diff --git a/usr/src/lib/libdladm/common/libdllink.c b/usr/src/lib/libdladm/common/libdllink.c index bd046acda9..79e644c4e7 100644 --- a/usr/src/lib/libdladm/common/libdllink.c +++ b/usr/src/lib/libdladm/common/libdllink.c @@ -43,6 +43,7 @@ #include <libdllink.h> #include <libdlmgmt.h> #include <libdladm_impl.h> +#include <libinetutil.h> /* * Return the attributes of the specified datalink from the DLD driver. @@ -926,3 +927,100 @@ dladm_linkid2legacyname(datalink_id_t linkid, char *dev, size_t len) done: return (status); } + +dladm_status_t +dladm_get_single_mac_stat(datalink_id_t linkid, const char *name, uint8_t type, + void *val) +{ + char module[DLPI_LINKNAME_MAX]; + uint_t instance; + char link[DLPI_LINKNAME_MAX]; + dladm_status_t status; + uint32_t flags, media; + kstat_ctl_t *kcp; + kstat_t *ksp; + dladm_phys_attr_t dpap; + + if ((status = dladm_datalink_id2info(linkid, &flags, NULL, &media, + link, DLPI_LINKNAME_MAX)) != DLADM_STATUS_OK) + return (status); + + if (media != DL_ETHER) + return (DLADM_STATUS_LINKINVAL); + + status = dladm_phys_info(linkid, &dpap, DLADM_OPT_PERSIST); + + if (status != DLADM_STATUS_OK) + return (status); + + status = dladm_parselink(dpap.dp_dev, module, &instance); + + if (status != DLADM_STATUS_OK) + return (status); + + if ((kcp = kstat_open()) == NULL) + return (dladm_errno2status(errno)); + + /* + * The kstat query could fail if the underlying MAC + * driver was already detached. + */ + if ((ksp = kstat_lookup(kcp, module, instance, "mac")) == NULL && + (ksp = kstat_lookup(kcp, module, instance, NULL)) == NULL) + goto bail; + + if (kstat_read(kcp, ksp, NULL) == -1) + goto bail; + + if (dladm_kstat_value(ksp, name, type, val) < 0) + goto bail; + + (void) kstat_close(kcp); + return (DLADM_STATUS_OK); +bail: + (void) kstat_close(kcp); + return (dladm_errno2status(errno)); + +} + +int +dladm_kstat_value(kstat_t *ksp, const char *name, uint8_t type, void *buf) +{ + kstat_named_t *knp; + + if ((knp = kstat_data_lookup(ksp, (char *)name)) == NULL) + return (-1); + + if (knp->data_type != type) + return (-1); + + switch (type) { + case KSTAT_DATA_UINT64: + *(uint64_t *)buf = knp->value.ui64; + break; + case KSTAT_DATA_UINT32: + *(uint32_t *)buf = knp->value.ui32; + break; + default: + return (-1); + } + + return (0); +} + +dladm_status_t +dladm_parselink(const char *dev, char *provider, uint_t *ppa) +{ + ifspec_t ifsp; + + if (dev == NULL || !ifparse_ifspec(dev, &ifsp)) + return (DLADM_STATUS_LINKINVAL); + + if (provider != NULL) + (void) strlcpy(provider, ifsp.ifsp_devnm, DLPI_LINKNAME_MAX); + + if (ppa != NULL) + *ppa = ifsp.ifsp_ppa; + + return (DLADM_STATUS_OK); +} diff --git a/usr/src/lib/libdladm/common/libdllink.h b/usr/src/lib/libdladm/common/libdllink.h index 2b762ff6d8..80f6f725e6 100644 --- a/usr/src/lib/libdladm/common/libdllink.h +++ b/usr/src/lib/libdladm/common/libdllink.h @@ -36,6 +36,7 @@ #include <sys/types.h> #include <sys/param.h> #include <libdladm.h> +#include <kstat.h> #ifdef __cplusplus extern "C" { @@ -74,6 +75,10 @@ typedef enum { #define DLADM_SECOBJ_NAME_MAX 32 #define DLADM_MAX_PROP_VALCNT 32 +/* + * Size of prop_val buffer passed to pd_get function must be at + * least DLADM_PROP_VAL_MAX + */ #define DLADM_PROP_VAL_MAX 128 #define DLADM_SECOBJ_CLASS_WEP 0 @@ -145,6 +150,11 @@ extern dladm_status_t dladm_phys_delete(datalink_id_t); extern dladm_status_t dladm_phys_info(datalink_id_t, dladm_phys_attr_t *, uint32_t); +extern dladm_status_t dladm_get_single_mac_stat(datalink_id_t, const char *, + uint8_t, void *); +extern int dladm_kstat_value(kstat_t *, const char *, uint8_t, + void *); +extern dladm_status_t dladm_parselink(const char *, char *, uint_t *); #ifdef __cplusplus } diff --git a/usr/src/lib/libdladm/common/libdlwlan.c b/usr/src/lib/libdladm/common/libdlwlan.c index 6597b84ce0..47eb8823c0 100644 --- a/usr/src/lib/libdladm/common/libdlwlan.c +++ b/usr/src/lib/libdladm/common/libdlwlan.c @@ -83,39 +83,39 @@ static dladm_status_t dladm_wlan_wlresult2status(wldp_t *); static dladm_status_t dladm_wlan_validate(datalink_id_t); static val_desc_t linkstatus_vals[] = { - { "disconnected", DLADM_WLAN_LINK_DISCONNECTED }, - { "connected", DLADM_WLAN_LINK_CONNECTED } + { "disconnected", DLADM_WLAN_LINK_DISCONNECTED }, + { "connected", DLADM_WLAN_LINK_CONNECTED } }; static val_desc_t secmode_vals[] = { - { "none", DLADM_WLAN_SECMODE_NONE }, - { "wep", DLADM_WLAN_SECMODE_WEP }, - { "wpa", DLADM_WLAN_SECMODE_WPA } + { "none", DLADM_WLAN_SECMODE_NONE }, + { "wep", DLADM_WLAN_SECMODE_WEP }, + { "wpa", DLADM_WLAN_SECMODE_WPA } }; static val_desc_t strength_vals[] = { - { "very weak", DLADM_WLAN_STRENGTH_VERY_WEAK }, + { "very weak", DLADM_WLAN_STRENGTH_VERY_WEAK }, { "weak", DLADM_WLAN_STRENGTH_WEAK }, { "good", DLADM_WLAN_STRENGTH_GOOD }, - { "very good", DLADM_WLAN_STRENGTH_VERY_GOOD}, - { "excellent", DLADM_WLAN_STRENGTH_EXCELLENT} + { "very good", DLADM_WLAN_STRENGTH_VERY_GOOD }, + { "excellent", DLADM_WLAN_STRENGTH_EXCELLENT } }; static val_desc_t mode_vals[] = { - { "a", DLADM_WLAN_MODE_80211A }, - { "b", DLADM_WLAN_MODE_80211B }, - { "g", DLADM_WLAN_MODE_80211G }, + { "a", DLADM_WLAN_MODE_80211A }, + { "b", DLADM_WLAN_MODE_80211B }, + { "g", DLADM_WLAN_MODE_80211G }, }; static val_desc_t auth_vals[] = { { "open", DLADM_WLAN_AUTH_OPEN }, - { "shared", DLADM_WLAN_AUTH_SHARED } + { "shared", DLADM_WLAN_AUTH_SHARED } }; static val_desc_t bsstype_vals[] = { - { "bss", DLADM_WLAN_BSSTYPE_BSS }, - { "ibss", DLADM_WLAN_BSSTYPE_IBSS }, - { "any", DLADM_WLAN_BSSTYPE_ANY } + { "bss", DLADM_WLAN_BSSTYPE_BSS }, + { "ibss", DLADM_WLAN_BSSTYPE_IBSS }, + { "any", DLADM_WLAN_BSSTYPE_ANY } }; #define IS_CONNECTED(gbuf) \ diff --git a/usr/src/lib/libdladm/common/linkprop.c b/usr/src/lib/libdladm/common/linkprop.c index a05f6ce877..8742dbbd44 100644 --- a/usr/src/lib/libdladm/common/linkprop.c +++ b/usr/src/lib/libdladm/common/linkprop.c @@ -46,42 +46,81 @@ #include <dlfcn.h> #include <link.h> #include <inet/wifi_ioctl.h> +#include <libdladm.h> +#include <sys/param.h> +#include <sys/dld.h> +#include <inttypes.h> +#include <sys/ethernet.h> /* * The linkprop get() callback. + * - pd: pointer to the struct prop_desc * - propstrp: a property string array to keep the returned property. * Caller allocated. * - cntp: number of returned properties. * Caller also uses it to indicate how many it expects. */ -typedef dladm_status_t pd_getf_t(datalink_id_t, char **propstp, uint_t *cntp); +struct prop_desc; + +typedef dladm_status_t pd_getf_t(struct prop_desc *pd, + datalink_id_t, char **propstp, uint_t *cntp); /* * The linkprop set() callback. * - propval: a val_desc_t array which keeps the property values to be set. * - cnt: number of properties to be set. + * - flags: additional flags passed down the system call. + * + * pd_set takes val_desc_t given by pd_check(), translates it into + * a format suitable for kernel consumption. This may require allocation + * of ioctl buffers etc. pd_set() may call another common routine (used + * by all other pd_sets) which invokes the ioctl. */ -typedef dladm_status_t pd_setf_t(datalink_id_t, val_desc_t *propval, - uint_t cnt); +typedef dladm_status_t pd_setf_t(struct prop_desc *, datalink_id_t, + val_desc_t *propval, uint_t cnt, uint_t flags); -#define PD_TEMPONLY 0x1 /* * The linkprop check() callback. * - propstrp: property string array which keeps the property to be checked. * - cnt: number of properties. * - propval: return value; the property values of the given property strings. - * - dofree: indicates whether the caller needs to free propvalp->vd_val. + * + * pd_check checks that the input values are valid. It does so by + * iteraring through the pd_modval list for the property. If + * the modifiable values cannot be expressed as a list, a pd_check + * specific to this property can be used. If the input values are + * verified to be valid, pd_check allocates a val_desc_t and fills it + * with either a val_desc_t found on the pd_modval list or something + * generated on the fly. */ -typedef dladm_status_t pd_checkf_t(datalink_id_t, char **propstrp, - uint_t cnt, val_desc_t *propval, boolean_t *dofree); - +typedef dladm_status_t pd_checkf_t(struct prop_desc *pd, + datalink_id_t, char **propstrp, + uint_t cnt, val_desc_t *propval); + +typedef struct dld_public_prop_s { + dld_prop_id_t pp_id; + size_t pp_valsize; + char *pp_name; + char *pp_desc; +} dld_public_prop_t; + +static dld_ioc_prop_t *dld_buf_alloc(size_t, datalink_id_t, const char *, + dladm_status_t *); +static dladm_status_t dld_set_prop(datalink_id_t, const char *, char **, + uint_t, uint_t); +static dladm_status_t dld_get_prop(datalink_id_t, const char *, char **, + uint_t *, dladm_prop_type_t); static pd_getf_t do_get_zone, do_get_autopush, do_get_rate_mod, do_get_rate_prop, do_get_channel_prop, - do_get_powermode_prop, do_get_radio_prop; + do_get_powermode_prop, do_get_radio_prop, + dld_duplex_get, dld_speed_get, dld_status_get, + dld_binary_get, dld_uint64_get, dld_flowctl_get; static pd_setf_t do_set_zone, do_set_autopush, do_set_rate_prop, - do_set_powermode_prop, do_set_radio_prop; -static pd_checkf_t do_check_zone, do_check_autopush, do_check_rate; + do_set_powermode_prop, do_set_radio_prop, + dld_set_public_prop; +static pd_checkf_t do_check_zone, do_check_autopush, do_check_rate, + dld_defmtu_check; typedef struct prop_desc { /* @@ -131,12 +170,9 @@ typedef struct prop_desc { */ pd_checkf_t *pd_check; - /* - * currently only PD_TEMPONLY is valid, which indicates the property - * is temporary only. - */ uint_t pd_flags; - +#define PD_TEMPONLY 0x1 /* property is temporary only */ +#define PD_CHECK_ALLOC 0x2 /* alloc vd_val as part of pd_check */ /* * indicate link classes this property applies to. */ @@ -148,6 +184,97 @@ typedef struct prop_desc { datalink_media_t pd_dmedia; } prop_desc_t; +#define DLD_PROPBUF_SIZE(v) sizeof (dld_ioc_prop_t) + (v) - 1 + + +static dld_public_prop_t dld_prop[] = { + { DLD_PROP_DUPLEX, sizeof (uint8_t), + "link_duplex", "link duplex mode" }, + + {DLD_PROP_SPEED, sizeof (uint8_t), + "ifspeed", "link speed (Mbps)" }, + + { DLD_PROP_STATUS, sizeof (uint8_t), + "link_up", "link up/down" }, + + { DLD_PROP_AUTONEG, sizeof (uint8_t), + "adv_autoneg_cap", "Advertised auto-negotiation" }, + + { DLD_PROP_DEFMTU, sizeof (uint64_t), + "default_mtu", "default frame mtu" }, + + { DLD_PROP_FLOWCTRL, sizeof (link_flowctrl_t), + "flowctrl", "flowcontrol" }, + + { DLD_PROP_ADV_1000FDX_CAP, sizeof (uint8_t), + "adv_1000fdx_cap", "Adv 1000 Mbps fdx" }, + + { DLD_PROP_EN_1000FDX_CAP, sizeof (uint8_t), + "en_1000fdx_cap", "Enable 1000 Mbps fdx" }, + + { DLD_PROP_ADV_1000HDX_CAP, sizeof (uint8_t), + "adv_1000hdx_cap", "Adv 1000 Mbps hdx" }, + + { DLD_PROP_EN_1000HDX_CAP, sizeof (uint8_t), + "en_1000hdx_cap", "Enable 1000 Mbps hdx" }, + + { DLD_PROP_ADV_100FDX_CAP, sizeof (uint8_t), + "adv_100fdx_cap", "Adv 100 Mbps fdx" }, + + { DLD_PROP_EN_100FDX_CAP, sizeof (uint8_t), + "en_100fdx_cap", "Enable 100 Mbps fdx" }, + + { DLD_PROP_ADV_100HDX_CAP, sizeof (uint8_t), + "adv_100hdx_cap", "Adv 100 Mbps hdx" }, + + { DLD_PROP_EN_100HDX_CAP, sizeof (uint8_t), + "en_100hdx_cap", "Enable 100 Mbps hdx" }, + + { DLD_PROP_ADV_10FDX_CAP, sizeof (uint8_t), + "adv_10fdx_cap", "Adv 10 Mbps fdx" }, + + { DLD_PROP_EN_10FDX_CAP, sizeof (uint8_t), + "en_10fdx_cap", "Enable 10 Mbps fdx" }, + + { DLD_PROP_ADV_10HDX_CAP, sizeof (uint8_t), + "adv_10hdx_cap", "Adv 10 Mbps hdx" }, + + { DLD_PROP_EN_10HDX_CAP, sizeof (uint8_t), + "en_10hdx_cap", "Enable 10 Mbps hdx" }, + + { DLD_PROP_PRIVATE, 0, + "driver-private", "" } +}; + +static val_desc_t link_duplex_vals[] = { + { "half", LINK_DUPLEX_HALF }, + { "full", LINK_DUPLEX_HALF } +}; +static val_desc_t link_speed_vals[] = { + { "10", 10 }, + { "100", 100 }, + { "1000", 1000 } +}; +static val_desc_t link_status_vals[] = { + { "up", LINK_STATE_UP }, + { "down", LINK_STATE_DOWN } +}; +static val_desc_t link_01_vals[] = { + { "1", 1 }, + { "0", 0 } +}; +static val_desc_t link_flow_vals[] = { + { "no", LINK_FLOWCTRL_NONE }, + { "tx", LINK_FLOWCTRL_TX }, + { "rx", LINK_FLOWCTRL_RX }, + { "bi", LINK_FLOWCTRL_BI } +}; +static val_desc_t macdefaultmtu_vals[] = { + { "68-9000", NULL } +}; + +#define VALCNT(vals) (sizeof ((vals)) / sizeof (val_desc_t)) + static val_desc_t dladm_wlan_radio_vals[] = { { "on", DLADM_WLAN_RADIO_ON }, { "off", DLADM_WLAN_RADIO_OFF } @@ -161,36 +288,128 @@ static val_desc_t dladm_wlan_powermode_vals[] = { static prop_desc_t prop_table[] = { - { "channel", { NULL, 0 }, NULL, 0, NULL, NULL, + { "channel", { NULL, 0 }, + NULL, 0, NULL, NULL, do_get_channel_prop, NULL, 0, - DATALINK_CLASS_PHYS, DL_WIFI}, + DATALINK_CLASS_PHYS, DL_WIFI }, { "powermode", { "off", DLADM_WLAN_PM_OFF }, dladm_wlan_powermode_vals, VALCNT(dladm_wlan_powermode_vals), do_set_powermode_prop, NULL, do_get_powermode_prop, NULL, 0, - DATALINK_CLASS_PHYS, DL_WIFI}, + DATALINK_CLASS_PHYS, DL_WIFI }, { "radio", { "on", DLADM_WLAN_RADIO_ON }, dladm_wlan_radio_vals, VALCNT(dladm_wlan_radio_vals), do_set_radio_prop, NULL, do_get_radio_prop, NULL, 0, - DATALINK_CLASS_PHYS, DL_WIFI}, + DATALINK_CLASS_PHYS, DL_WIFI }, { "speed", { "", 0 }, NULL, 0, do_set_rate_prop, do_get_rate_mod, do_get_rate_prop, do_check_rate, 0, - DATALINK_CLASS_PHYS, DL_WIFI}, + DATALINK_CLASS_PHYS, DL_WIFI }, { "autopush", { "", NULL }, NULL, 0, do_set_autopush, NULL, - do_get_autopush, do_check_autopush, 0, - DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE}, + do_get_autopush, do_check_autopush, PD_CHECK_ALLOC, + DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE }, { "zone", { "", NULL }, NULL, 0, do_set_zone, NULL, do_get_zone, do_check_zone, PD_TEMPONLY, - DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE} + DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE }, + + { "link_duplex", { "full", LINK_DUPLEX_FULL }, + link_duplex_vals, VALCNT(link_duplex_vals), + NULL, NULL, dld_duplex_get, NULL, + 0, DATALINK_CLASS_PHYS, DL_ETHER }, + + { "ifspeed", { "1000", 1000 }, + link_speed_vals, VALCNT(link_speed_vals), + NULL, NULL, dld_speed_get, NULL, + 0, DATALINK_CLASS_PHYS, DL_ETHER }, + + { "link_up", { "up", LINK_STATE_UP }, + link_status_vals, VALCNT(link_status_vals), + NULL, NULL, dld_status_get, NULL, + 0, DATALINK_CLASS_PHYS, DL_ETHER }, + + { "adv_autoneg_cap", { "1", 1 }, + link_01_vals, VALCNT(link_01_vals), + dld_set_public_prop, NULL, dld_binary_get, NULL, + 0, DATALINK_CLASS_PHYS, DL_ETHER }, + + { "default_mtu", { NULL, NULL }, + macdefaultmtu_vals, VALCNT(macdefaultmtu_vals), + dld_set_public_prop, NULL, dld_uint64_get, dld_defmtu_check, + PD_CHECK_ALLOC, DATALINK_CLASS_PHYS, DL_ETHER }, + + { "flowctrl", { "bi", LINK_FLOWCTRL_BI }, + link_flow_vals, VALCNT(link_flow_vals), + dld_set_public_prop, NULL, dld_flowctl_get, NULL, + 0, DATALINK_CLASS_PHYS, DL_ETHER }, + + { "adv_1000fdx_cap", { NULL, NULL }, + link_01_vals, 0, + NULL, NULL, dld_binary_get, NULL, + 0, DATALINK_CLASS_PHYS, DL_ETHER }, + + { "en_1000fdx_cap", { NULL, NULL }, + link_01_vals, VALCNT(link_01_vals), + dld_set_public_prop, NULL, dld_binary_get, NULL, + 0, DATALINK_CLASS_PHYS, DL_ETHER }, + + { "adv_1000hdx_cap", { NULL, NULL }, + link_01_vals, VALCNT(link_01_vals), + NULL, NULL, dld_binary_get, NULL, + 0, DATALINK_CLASS_PHYS, DL_ETHER }, + + { "en_1000hdx_cap", { NULL, NULL }, + link_01_vals, VALCNT(link_01_vals), + dld_set_public_prop, NULL, dld_binary_get, NULL, + 0, DATALINK_CLASS_PHYS, DL_ETHER }, + + { "adv_100fdx_cap", { NULL, NULL }, + link_01_vals, VALCNT(link_01_vals), + NULL, NULL, dld_binary_get, NULL, + 0, DATALINK_CLASS_PHYS, DL_ETHER }, + + { "en_100fdx_cap", { NULL, NULL }, + link_01_vals, VALCNT(link_01_vals), + dld_set_public_prop, NULL, dld_binary_get, NULL, + 0, DATALINK_CLASS_PHYS, DL_ETHER }, + + { "adv_100hdx_cap", { NULL, NULL }, + link_01_vals, VALCNT(link_01_vals), + NULL, NULL, dld_binary_get, NULL, + 0, DATALINK_CLASS_PHYS, DL_ETHER }, + + { "en_100hdx_cap", { NULL, NULL }, + link_01_vals, VALCNT(link_01_vals), + dld_set_public_prop, NULL, dld_binary_get, NULL, + 0, DATALINK_CLASS_PHYS, DL_ETHER }, + + { "adv_10fdx_cap", { NULL, NULL }, + link_01_vals, VALCNT(link_01_vals), + NULL, NULL, dld_binary_get, NULL, + 0, DATALINK_CLASS_PHYS, DL_ETHER }, + + { "en_10fdx_cap", { NULL, NULL }, + link_01_vals, VALCNT(link_01_vals), + dld_set_public_prop, NULL, dld_binary_get, NULL, + 0, DATALINK_CLASS_PHYS, DL_ETHER }, + + { "adv_10hdx_cap", { NULL, NULL }, + link_01_vals, VALCNT(link_01_vals), + NULL, NULL, dld_binary_get, NULL, + 0, DATALINK_CLASS_PHYS, DL_ETHER }, + + { "en_10hdx_cap", { NULL, NULL }, + link_01_vals, VALCNT(link_01_vals), + dld_set_public_prop, NULL, dld_binary_get, NULL, + 0, DATALINK_CLASS_PHYS, DL_ETHER } + }; #define DLADM_MAX_PROPS (sizeof (prop_table) / sizeof (prop_desc_t)) @@ -266,14 +485,19 @@ i_dladm_set_single_prop(datalink_id_t linkid, datalink_class_t class, if (pdp->pd_set == NULL) return (DLADM_STATUS_PROPRDONLY); + if (pdp->pd_flags & PD_CHECK_ALLOC) + needfree = B_TRUE; + else + needfree = B_FALSE; if (prop_val != NULL) { vdp = malloc(sizeof (val_desc_t) * val_cnt); if (vdp == NULL) return (DLADM_STATUS_NOMEM); + if (pdp->pd_check != NULL) { - status = pdp->pd_check(linkid, prop_val, val_cnt, vdp, - &needfree); + status = pdp->pd_check(pdp, linkid, prop_val, val_cnt, + vdp); } else if (pdp->pd_optval != NULL) { status = do_check_prop(pdp, prop_val, val_cnt, vdp); } else { @@ -294,10 +518,10 @@ i_dladm_set_single_prop(datalink_id_t linkid, datalink_class_t class, (void) memcpy(vdp, &pdp->pd_defval, sizeof (val_desc_t)); cnt = 1; } - status = pdp->pd_set(linkid, vdp, cnt); + status = pdp->pd_set(pdp, linkid, vdp, cnt, flags); if (needfree) { for (i = 0; i < cnt; i++) - free((void *)(((val_desc_t *)vdp + i)->vd_val)); + free((void *)((val_desc_t *)vdp + i)->vd_val); } done: free(vdp); @@ -339,8 +563,15 @@ i_dladm_set_linkprop(datalink_id_t linkid, const char *prop_name, status = s; } } - if (!found) - status = DLADM_STATUS_NOTFOUND; + if (!found) { + if (prop_name[0] == '_') { + /* other private properties */ + status = dld_set_prop(linkid, prop_name, prop_val, + val_cnt, flags); + } else { + status = DLADM_STATUS_NOTFOUND; + } + } return (status); } @@ -430,8 +661,17 @@ dladm_get_linkprop(datalink_id_t linkid, dladm_prop_type_t type, if (strcasecmp(prop_name, prop_table[i].pd_name) == 0) break; - if (i == DLADM_MAX_PROPS) - return (DLADM_STATUS_NOTFOUND); + if (i == DLADM_MAX_PROPS) { + if (prop_name[0] == '_') { + /* + * private property. + */ + return (dld_get_prop(linkid, prop_name, + prop_val, val_cntp, type)); + } else { + return (DLADM_STATUS_NOTFOUND); + } + } pdp = &prop_table[i]; @@ -447,7 +687,7 @@ dladm_get_linkprop(datalink_id_t linkid, dladm_prop_type_t type, switch (type) { case DLADM_PROP_VAL_CURRENT: - status = pdp->pd_get(linkid, prop_val, val_cntp); + status = pdp->pd_get(pdp, linkid, prop_val, val_cntp); break; case DLADM_PROP_VAL_DEFAULT: @@ -461,7 +701,8 @@ dladm_get_linkprop(datalink_id_t linkid, dladm_prop_type_t type, case DLADM_PROP_VAL_MODIFIABLE: if (pdp->pd_getmod != NULL) { - status = pdp->pd_getmod(linkid, prop_val, val_cntp); + status = pdp->pd_getmod(pdp, linkid, prop_val, + val_cntp); break; } cnt = pdp->pd_noptval; @@ -546,8 +787,10 @@ dladm_init_linkprop(datalink_id_t linkid) return (DLADM_STATUS_OK); } +/* ARGSUSED */ static dladm_status_t -do_get_zone(datalink_id_t linkid, char **prop_val, uint_t *val_cnt) +do_get_zone(struct prop_desc *pd, datalink_id_t linkid, + char **prop_val, uint_t *val_cnt) { char zone_name[ZONENAME_MAX]; zoneid_t zid; @@ -637,8 +880,10 @@ cleanup: return (status); } +/* ARGSUSED */ static dladm_status_t -do_set_zone(datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt) +do_set_zone(prop_desc_t *pd, datalink_id_t linkid, + val_desc_t *vdp, uint_t val_cnt, uint_t flags) { dladm_status_t status; zoneid_t zid_old, zid_new; @@ -721,8 +966,8 @@ rollback1: /* ARGSUSED */ static dladm_status_t -do_check_zone(datalink_id_t linkid, char **prop_val, uint_t val_cnt, - val_desc_t *vdp, boolean_t *needfreep) +do_check_zone(struct prop_desc *pd, datalink_id_t linkid, char **prop_val, + uint_t val_cnt, val_desc_t *vdp) { zoneid_t zid; @@ -746,12 +991,13 @@ do_check_zone(datalink_id_t linkid, char **prop_val, uint_t val_cnt, } vdp->vd_val = zid; - *needfreep = B_FALSE; return (DLADM_STATUS_OK); } +/* ARGSUSED */ static dladm_status_t -do_get_autopush(datalink_id_t linkid, char **prop_val, uint_t *val_cnt) +do_get_autopush(struct prop_desc *pd, datalink_id_t linkid, + char **prop_val, uint_t *val_cnt) { dld_ioc_ap_t dia; int fd, i, len; @@ -788,8 +1034,10 @@ done: return (DLADM_STATUS_OK); } +/* ARGSUSED */ static dladm_status_t -do_set_autopush(datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt) +do_set_autopush(prop_desc_t *pd, datalink_id_t linkid, + val_desc_t *vdp, uint_t val_cnt, uint_t flags) { dld_ioc_ap_t dia; struct dlautopush *dlap = (struct dlautopush *)vdp->vd_val; @@ -862,8 +1110,8 @@ i_dladm_add_ap_module(const char *module, struct dlautopush *dlap) */ /* ARGSUSED */ static dladm_status_t -do_check_autopush(datalink_id_t linkid, char **prop_val, uint_t val_cnt, - val_desc_t *vdp, boolean_t *needfreep) +do_check_autopush(struct prop_desc *pd, datalink_id_t linkid, char **prop_val, + uint_t val_cnt, val_desc_t *vdp) { char *module; struct dlautopush *dlap; @@ -890,13 +1138,13 @@ do_check_autopush(datalink_id_t linkid, char **prop_val, uint_t val_cnt, } vdp->vd_val = (uintptr_t)dlap; - *needfreep = B_TRUE; return (DLADM_STATUS_OK); } +/* ARGSUSED */ static dladm_status_t -do_get_rate_common(datalink_id_t linkid, char **prop_val, uint_t *val_cnt, - uint_t id) +do_get_rate_common(struct prop_desc *pd, datalink_id_t linkid, + char **prop_val, uint_t *val_cnt, uint_t id) { wl_rates_t *wrp; uint_t i; @@ -937,16 +1185,18 @@ done: } static dladm_status_t -do_get_rate_prop(datalink_id_t linkid, char **prop_val, uint_t *val_cnt) +do_get_rate_prop(struct prop_desc *pd, datalink_id_t linkid, + char **prop_val, uint_t *val_cnt) { - return (do_get_rate_common(linkid, prop_val, val_cnt, + return (do_get_rate_common(pd, linkid, prop_val, val_cnt, WL_DESIRED_RATES)); } static dladm_status_t -do_get_rate_mod(datalink_id_t linkid, char **prop_val, uint_t *val_cnt) +do_get_rate_mod(struct prop_desc *pd, datalink_id_t linkid, + char **prop_val, uint_t *val_cnt) { - return (do_get_rate_common(linkid, prop_val, val_cnt, + return (do_get_rate_common(pd, linkid, prop_val, val_cnt, WL_SUPPORTED_RATES)); } @@ -978,8 +1228,10 @@ do_set_rate(datalink_id_t linkid, dladm_wlan_rates_t *rates) return (status); } +/* ARGSUSED */ static dladm_status_t -do_set_rate_prop(datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt) +do_set_rate_prop(prop_desc_t *pd, datalink_id_t linkid, + val_desc_t *vdp, uint_t val_cnt, uint_t flags) { dladm_wlan_rates_t rates; dladm_status_t status; @@ -998,8 +1250,8 @@ done: /* ARGSUSED */ static dladm_status_t -do_check_rate(datalink_id_t linkid, char **prop_val, uint_t val_cnt, - val_desc_t *vdp, boolean_t *needfreep) +do_check_rate(struct prop_desc *pd, datalink_id_t linkid, char **prop_val, + uint_t val_cnt, val_desc_t *vdp) { int i; uint_t modval_cnt = MAX_SUPPORT_RATES; @@ -1022,19 +1274,15 @@ do_check_rate(datalink_id_t linkid, char **prop_val, uint_t val_cnt, i * DLADM_STRSIZE; } - status = do_get_rate_mod(linkid, modval, &modval_cnt); + status = do_get_rate_mod(NULL, linkid, modval, &modval_cnt); if (status != DLADM_STATUS_OK) goto done; for (i = 0; i < modval_cnt; i++) { if (strcasecmp(*prop_val, modval[i]) == 0) { - vdp->vd_val = (uint_t)(atof(*prop_val) * 2); + vdp->vd_val = (uintptr_t)(uint_t) + (atof(*prop_val) * 2); status = DLADM_STATUS_OK; - - /* - * Does not need the caller to free the vdp->vd_val - */ - *needfreep = B_FALSE; break; } } @@ -1051,8 +1299,10 @@ do_get_phyconf(datalink_id_t linkid, wldp_t *gbuf) return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_PHY_CONFIG)); } +/* ARGSUSED */ static dladm_status_t -do_get_channel_prop(datalink_id_t linkid, char **prop_val, uint_t *val_cnt) +do_get_channel_prop(struct prop_desc *pd, datalink_id_t linkid, + char **prop_val, uint_t *val_cnt) { uint32_t channel; wldp_t *gbuf; @@ -1084,8 +1334,10 @@ do_get_powermode(datalink_id_t linkid, wldp_t *gbuf) return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_POWER_MODE)); } +/* ARGSUSED */ static dladm_status_t -do_get_powermode_prop(datalink_id_t linkid, char **prop_val, uint_t *val_cnt) +do_get_powermode_prop(struct prop_desc *pd, datalink_id_t linkid, + char **prop_val, uint_t *val_cnt) { wl_ps_mode_t *mode; const char *s; @@ -1147,7 +1399,8 @@ do_set_powermode(datalink_id_t linkid, dladm_wlan_powermode_t *pm) /* ARGSUSED */ static dladm_status_t -do_set_powermode_prop(datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt) +do_set_powermode_prop(prop_desc_t *pd, datalink_id_t linkid, + val_desc_t *vdp, uint_t val_cnt, uint_t flags) { dladm_wlan_powermode_t powermode = (dladm_wlan_powermode_t)vdp->vd_val; dladm_status_t status; @@ -1166,8 +1419,10 @@ do_get_radio(datalink_id_t linkid, wldp_t *gbuf) return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_RADIO)); } +/* ARGSUSED */ static dladm_status_t -do_get_radio_prop(datalink_id_t linkid, char **prop_val, uint_t *val_cnt) +do_get_radio_prop(struct prop_desc *pd, datalink_id_t linkid, + char **prop_val, uint_t *val_cnt) { wl_radio_t radio; const char *s; @@ -1220,7 +1475,8 @@ do_set_radio(datalink_id_t linkid, dladm_wlan_radio_t *radio) /* ARGSUSED */ static dladm_status_t -do_set_radio_prop(datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt) +do_set_radio_prop(prop_desc_t *pd, datalink_id_t linkid, + val_desc_t *vdp, uint_t val_cnt, uint_t fags) { dladm_wlan_radio_t radio = (dladm_wlan_radio_t)vdp->vd_val; dladm_status_t status; @@ -1305,3 +1561,410 @@ done: dladm_destroy_conf(conf); return (status); } + +static dld_public_prop_t * +dladm_name2prop(const char *prop_name) +{ + dld_public_prop_t *p; + + for (p = dld_prop; p->pp_id != DLD_PROP_PRIVATE; p++) { + if (strcmp(p->pp_name, prop_name) == 0) + break; + } + return (p); +} + + +static dld_ioc_prop_t * +dld_buf_alloc(size_t valsize, datalink_id_t linkid, const char *prop_name, + dladm_status_t *status) +{ + int dsize; + dld_ioc_prop_t *dip; + dld_public_prop_t *p; + char link[DLPI_LINKNAME_MAX]; + uint32_t flags; + + *status = DLADM_STATUS_OK; + p = dladm_name2prop(prop_name); + if (p->pp_id != DLD_PROP_PRIVATE) + valsize = p->pp_valsize; + + dsize = DLD_PROPBUF_SIZE(valsize); + dip = malloc(dsize); + if (dip == NULL) { + *status = DLADM_STATUS_NOMEM; + return (NULL); + } + bzero(dip, dsize); + dip->pr_valsize = valsize; + (void) strlcpy(dip->pr_name, prop_name, DLD_LINKPROP_NAME_MAX); + dip->pr_version = DLD_PROP_VERSION; + + if ((*status = dladm_datalink_id2info(linkid, &flags, NULL, NULL, + (char *)link, DLPI_LINKNAME_MAX)) != DLADM_STATUS_OK) { + free(dip); + return (NULL); + } + + if (!(flags & DLADM_OPT_ACTIVE)) { + free(dip); + *status = DLADM_STATUS_TEMPONLY; + return (NULL); + } + (void) strlcpy(dip->pr_linkname, link, IFNAMSIZ); + dip->pr_num = p->pp_id; + return (dip); +} + +/* ARGSUSED */ +static dladm_status_t +dld_set_public_prop(prop_desc_t *pd, datalink_id_t linkid, + val_desc_t *vdp, uint_t val_cnt, uint_t flags) +{ + dld_ioc_prop_t *dip; + int fd, dsize; + dladm_status_t status = DLADM_STATUS_OK; + uint8_t u8; + uint16_t u16; + uint32_t u32; + void *val; + + dip = dld_buf_alloc(0, linkid, pd->pd_name, &status); + if (dip == NULL) + return (status); + + if (pd->pd_flags & PD_CHECK_ALLOC) + val = (void *)vdp->vd_val; + else { + /* + * Currently all 1/2/4-byte size properties are byte/word/int. + * No need (yet) to distinguish these from arrays of same size. + */ + switch (dip->pr_valsize) { + case 1: + u8 = vdp->vd_val; + val = &u8; + break; + case 2: + u16 = vdp->vd_val; + val = &u16; + break; + case 4: + u32 = vdp->vd_val; + val = &u32; + break; + default: + val = &vdp->vd_val; + break; + } + } + + (void) memcpy(dip->pr_val, val, dip->pr_valsize); + dsize = DLD_PROPBUF_SIZE(dip->pr_valsize); + if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) { + status = dladm_errno2status(errno); + goto done; + } + if (i_dladm_ioctl(fd, DLDIOCSETPROP, dip, dsize) < 0) + status = dladm_errno2status(errno); + + (void) close(fd); +done: + return (status); +} + +static dladm_status_t +dld_get_public_prop(dld_ioc_prop_t *dip) +{ + int fd, dsize; + dladm_status_t status = DLADM_STATUS_OK; + + dsize = DLD_PROPBUF_SIZE(dip->pr_valsize); + + if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) { + status = dladm_errno2status(errno); + goto done; + } + if (i_dladm_ioctl(fd, DLDIOCGETPROP, dip, dsize) < 0) { + status = dladm_errno2status(errno); + } +done: + return (status); +} + + +/* ARGSUSED */ +static dladm_status_t +dld_defmtu_check(struct prop_desc *pd, datalink_id_t linkid, char **prop_val, + uint_t val_cnt, val_desc_t *v) +{ + uint64_t mtu; + + if (val_cnt != 1) + return (DLADM_STATUS_BADVAL); + mtu = atoll(prop_val[0]); + v->vd_val = (uintptr_t)malloc(sizeof (uint64_t)); + if ((void *)v->vd_val == NULL) + return (DLADM_STATUS_NOMEM); + bcopy(&mtu, (void *)v->vd_val, sizeof (mtu)); + return (DLADM_STATUS_OK); +} + +/* ARGSUSED */ +static dladm_status_t +dld_duplex_get(struct prop_desc *pd, datalink_id_t linkid, + char **prop_val, uint_t *val_cnt) +{ + link_duplex_t link_duplex; + dladm_status_t status; + + if ((status = dladm_get_single_mac_stat(linkid, "link_duplex", + KSTAT_DATA_UINT32, &link_duplex)) != 0) + return (status); + + switch (link_duplex) { + case LINK_DUPLEX_FULL: + (void) strcpy(*prop_val, "full"); + break; + case LINK_DUPLEX_HALF: + (void) strcpy(*prop_val, "half"); + break; + default: + (void) strcpy(*prop_val, "unknown"); + break; + } + *val_cnt = 1; + return (DLADM_STATUS_OK); +} + +/* ARGSUSED */ +static dladm_status_t +dld_speed_get(struct prop_desc *pd, datalink_id_t linkid, + char **prop_val, uint_t *val_cnt) +{ + uint64_t ifspeed = 0; + dladm_status_t status; + + if ((status = dladm_get_single_mac_stat(linkid, "ifspeed", + KSTAT_DATA_UINT64, &ifspeed)) != 0) + return (status); + + (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, + "%llu", ifspeed / 1000000); /* Mbps */ + *val_cnt = 1; + return (DLADM_STATUS_OK); +} + +/* ARGSUSED */ +static dladm_status_t +dld_status_get(struct prop_desc *pd, datalink_id_t linkid, + char **prop_val, uint_t *val_cnt) +{ + link_state_t link_state; + dladm_status_t status; + + if ((status = dladm_get_single_mac_stat(linkid, "link_state", + KSTAT_DATA_UINT32, &link_state)) != 0) + return (status); + + switch (link_state) { + case LINK_STATE_UP: + (void) strcpy(*prop_val, "up"); + break; + case LINK_STATE_DOWN: + (void) strcpy(*prop_val, "down"); + break; + default: + (void) strcpy(*prop_val, "unknown"); + break; + } + *val_cnt = 1; + return (DLADM_STATUS_OK); +} + +/* ARGSUSED */ +static dladm_status_t +dld_binary_get(struct prop_desc *pd, datalink_id_t linkid, + char **prop_val, uint_t *val_cnt) +{ + dld_ioc_prop_t *dip; + dladm_status_t status; + + if ((dip = dld_buf_alloc(0, linkid, pd->pd_name, &status)) == NULL) + return (status); + if ((status = dld_get_public_prop(dip)) != DLADM_STATUS_OK) { + free(dip); + return (status); + } + (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%x", dip->pr_val[0]); + free(dip); + *val_cnt = 1; + return (DLADM_STATUS_OK); +} + +static dladm_status_t +dld_uint64_get(struct prop_desc *pd, datalink_id_t linkid, + char **prop_val, uint_t *val_cnt) +{ + dld_ioc_prop_t *dip; + uint64_t v = 0; + uchar_t *cp; + dladm_status_t status; + + if ((dip = dld_buf_alloc(0, linkid, pd->pd_name, &status)) == NULL) + return (status); + if ((status = dld_get_public_prop(dip)) != DLADM_STATUS_OK) { + free(dip); + return (status); + } + cp = (uchar_t *)dip->pr_val; + (void) memcpy(&v, cp, sizeof (v)); + (void) snprintf(*prop_val, DLADM_PROP_VAL_MAX, "%" PRIu64, v); + free(dip); + *val_cnt = 1; + return (DLADM_STATUS_OK); +} + +static dladm_status_t +dld_flowctl_get(struct prop_desc *pd, datalink_id_t linkid, + char **prop_val, uint_t *val_cnt) +{ + dld_ioc_prop_t *dip; + link_flowctrl_t v; + dladm_status_t status; + uchar_t *cp; + + if ((dip = dld_buf_alloc(0, linkid, pd->pd_name, &status)) == NULL) + return (status); + + if ((status = dld_get_public_prop(dip)) != DLADM_STATUS_OK) { + free(dip); + return (status); + } + cp = (uchar_t *)dip->pr_val; + (void) memcpy(&v, cp, sizeof (v)); + switch (v) { + case LINK_FLOWCTRL_NONE: + (void) sprintf(*prop_val, "no"); + break; + case LINK_FLOWCTRL_RX: + (void) sprintf(*prop_val, "rx"); + break; + case LINK_FLOWCTRL_TX: + (void) sprintf(*prop_val, "tx"); + break; + case LINK_FLOWCTRL_BI: + (void) sprintf(*prop_val, "bi"); + break; + } + free(dip); + *val_cnt = 1; + return (DLADM_STATUS_OK); +} + + +/* ARGSUSED */ +static dladm_status_t +dld_set_prop(datalink_id_t linkid, const char *prop_name, + char **prop_val, uint_t val_cnt, uint_t flags) +{ + int fd, i, slen; + int bufsize = 0, dsize; + dld_ioc_prop_t *dip = NULL; + uchar_t *dp; + dld_public_prop_t *p; + dladm_status_t status; + + if ((prop_name == NULL && prop_val != NULL) || + (prop_val != NULL && val_cnt == 0)) + return (DLADM_STATUS_BADARG); + p = dladm_name2prop(prop_name); + if (p->pp_id != DLD_PROP_PRIVATE) + return (DLADM_STATUS_BADARG); + + /* + * private properties: all parsing is done in the kernel. + * allocate a enough space for each property + its separator (','). + */ + for (i = 0; i < val_cnt; i++) { + bufsize += strlen(prop_val[i]) + 1; + } + dip = dld_buf_alloc(bufsize + 1, linkid, prop_name, &status); + if (dip == NULL) + return (status); + + dp = (uchar_t *)dip->pr_val; + dsize = sizeof (dld_ioc_prop_t) + bufsize; + slen = 0; + for (i = 0; i < val_cnt; i++) { + int plen = 0; + + plen = strlen(prop_val[i]); + bcopy(prop_val[i], dp, plen); + slen += plen; + /* + * add a "," separator and update dp. + */ + if (i != (val_cnt -1)) + dp[slen++] = ','; + dp += (plen + 1); + } + if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) { + free(dip); + return (dladm_errno2status(errno)); + } + if ((status = i_dladm_ioctl(fd, DLDIOCSETPROP, dip, dsize)) < 0) { + free(dip); + return (status); + } + free(dip); + (void) close(fd); + return (DLADM_STATUS_OK); +} + +static dladm_status_t +dld_get_prop(datalink_id_t linkid, const char *prop_name, + char **prop_val, uint_t *val_cnt, dladm_prop_type_t type) +{ + int fd; + dladm_status_t status = DLADM_STATUS_OK; + uint_t dsize; + dld_ioc_prop_t *dip = NULL; + dld_public_prop_t *p; + char tmp = '\0'; + + if ((prop_name == NULL && prop_val != NULL) || + (prop_val != NULL && val_cnt == 0)) + return (DLADM_STATUS_BADARG); + + p = dladm_name2prop(prop_name); + if (p->pp_id != DLD_PROP_PRIVATE) + return (DLADM_STATUS_BADARG); + + if (type == DLADM_PROP_VAL_DEFAULT || + type == DLADM_PROP_VAL_MODIFIABLE) { + *prop_val = &tmp; + *val_cnt = 1; + return (DLADM_STATUS_OK); + } + + /* + * private properties: all parsing is done in the kernel. + */ + dip = dld_buf_alloc(1024, linkid, prop_name, &status); + if (dip == NULL) + return (status); + dsize = DLD_PROPBUF_SIZE(dip->pr_valsize); + + if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) + return (DLADM_STATUS_BADARG); + + if ((status = i_dladm_ioctl(fd, DLDIOCGETPROP, dip, dsize)) < 0) { + status = dladm_errno2status(errno); + } else { + (void) strncpy(*prop_val, dip->pr_val, DLADM_PROP_VAL_MAX); + *val_cnt = 1; + } + return (status); +} diff --git a/usr/src/lib/libdladm/common/mapfile-vers b/usr/src/lib/libdladm/common/mapfile-vers index 25ab048469..ce7f994420 100644 --- a/usr/src/lib/libdladm/common/mapfile-vers +++ b/usr/src/lib/libdladm/common/mapfile-vers @@ -38,6 +38,7 @@ SUNWprivate_1.1 { dladm_valid_linkname; dladm_mac_walk; dladm_init_linkprop; + dladm_get_single_mac_stat; dladm_get_linkprop; dladm_set_linkprop; dladm_walk_linkprop; @@ -124,7 +125,8 @@ SUNWprivate_1.1 { dladm_vnic_delete; dladm_vnic_info; dladm_vnic_str2macaddrtype; - + dladm_kstat_value; + dladm_parselink; local: *; }; diff --git a/usr/src/lib/libdlpi/common/libdlpi.c b/usr/src/lib/libdlpi/common/libdlpi.c index f403135b6a..3849824ff0 100644 --- a/usr/src/lib/libdlpi/common/libdlpi.c +++ b/usr/src/lib/libdlpi/common/libdlpi.c @@ -368,16 +368,12 @@ dlpi_info(dlpi_handle_t dh, dlpi_info_t *infop, uint_t opt) int dlpi_parselink(const char *linkname, char *provider, uint_t *ppa) { - ifspec_t ifsp; - - if (linkname == NULL || !ifparse_ifspec(linkname, &ifsp)) - return (DLPI_ELINKNAMEINVAL); + dladm_status_t status; - if (provider != NULL) - (void) strlcpy(provider, ifsp.ifsp_devnm, DLPI_LINKNAME_MAX); + status = dladm_parselink(linkname, provider, ppa); - if (ppa != NULL) - *ppa = ifsp.ifsp_ppa; + if (status != DLADM_STATUS_OK) + return (DLPI_ELINKNAMEINVAL); return (DLPI_SUCCESS); } diff --git a/usr/src/uts/common/io/aggr/aggr_grp.c b/usr/src/uts/common/io/aggr/aggr_grp.c index 65105e298e..2668c23790 100644 --- a/usr/src/uts/common/io/aggr/aggr_grp.c +++ b/usr/src/uts/common/io/aggr/aggr_grp.c @@ -1520,9 +1520,11 @@ aggr_grp_max_sdu(aggr_grp_t *grp) ASSERT(grp->lg_ports != NULL); for (port = grp->lg_ports; port != NULL; port = port->lp_next) { - const mac_info_t *port_mi = mac_info(port->lp_mh); - if (max_sdu > port_mi->mi_sdu_max) - max_sdu = port_mi->mi_sdu_max; + uint_t port_sdu_max; + + mac_sdu_get(port->lp_mh, NULL, &port_sdu_max); + if (max_sdu > port_sdu_max) + max_sdu = port_sdu_max; } return (max_sdu); @@ -1536,9 +1538,10 @@ aggr_grp_max_sdu(aggr_grp_t *grp) static boolean_t aggr_grp_sdu_check(aggr_grp_t *grp, aggr_port_t *port) { - const mac_info_t *port_mi = mac_info(port->lp_mh); + uint_t port_sdu_max; - return (port_mi->mi_sdu_max >= grp->lg_max_sdu); + mac_sdu_get(port->lp_mh, NULL, &port_sdu_max); + return (port_sdu_max >= grp->lg_max_sdu); } /* diff --git a/usr/src/uts/common/io/bge/bge_chip2.c b/usr/src/uts/common/io/bge/bge_chip2.c index 1f29ac14a9..f4a46a15da 100644 --- a/usr/src/uts/common/io/bge/bge_chip2.c +++ b/usr/src/uts/common/io/bge/bge_chip2.c @@ -20,7 +20,7 @@ */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -1934,8 +1934,6 @@ bge_chip_id_init(bge_t *bgep) int err; uint_t i; - ASSERT(bgep->bge_chip_state == BGE_CHIP_INITIAL); - sys_ok = dev_ok = B_FALSE; cidp = &bgep->chipid; @@ -1963,6 +1961,8 @@ bge_chip_id_init(bge_t *bgep) cidp->mbuf_lo_water_rdma = bge_mbuf_lo_water_rdma; cidp->mbuf_lo_water_rmac = bge_mbuf_lo_water_rmac; cidp->mbuf_hi_water = bge_mbuf_hi_water; + cidp->rx_ticks_norm = bge_rx_ticks_norm; + cidp->rx_count_norm = bge_rx_count_norm; if (cidp->rx_rings == 0 || cidp->rx_rings > BGE_RECV_RINGS_MAX) cidp->rx_rings = BGE_RECV_RINGS_DEFAULT; @@ -2649,10 +2649,10 @@ bge_chip_enable_engine(bge_t *bgep, bge_regno_t regno, uint32_t morebits) * Reprogram the Ethernet, Transmit, and Receive MAC * modes to match the param_* variables */ -static void bge_sync_mac_modes(bge_t *bgep); +void bge_sync_mac_modes(bge_t *bgep); #pragma no_inline(bge_sync_mac_modes) -static void +void bge_sync_mac_modes(bge_t *bgep) { uint32_t macmode; @@ -2741,7 +2741,7 @@ bge_chip_sync(bge_t *bgep) int retval = DDI_SUCCESS; BGE_TRACE(("bge_chip_sync($%p)", - (void *)bgep)); + (void *)bgep)); ASSERT(mutex_owned(bgep->genlock)); @@ -2945,7 +2945,9 @@ bge_chip_stop(bge_t *bgep, boolean_t fault) if (fault) { if (bgep->bge_chip_state != BGE_CHIP_FAULT) { bgep->bge_chip_state = BGE_CHIP_FAULT; - ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST); + if (!bgep->manual_reset) + ddi_fm_service_impact(bgep->devinfo, + DDI_SERVICE_LOST); if (bgep->bge_dma_error) { /* * need to free buffers in case the fault was @@ -3926,10 +3928,10 @@ bge_status_sync(bge_t *bgep, uint64_t bits, uint64_t *flags) return (retval); } -static void bge_wake_factotum(bge_t *bgep); +void bge_wake_factotum(bge_t *bgep); #pragma inline(bge_wake_factotum) -static void +void bge_wake_factotum(bge_t *bgep) { mutex_enter(bgep->softintrlock); @@ -4464,8 +4466,10 @@ bge_chip_factotum(caddr_t arg) bgep->asf_status = ASF_STAT_RUN; } #endif - ddi_fm_service_impact(bgep->devinfo, - DDI_SERVICE_RESTORED); + if (!bgep->manual_reset) { + ddi_fm_service_impact(bgep->devinfo, + DDI_SERVICE_RESTORED); + } } } break; @@ -4507,6 +4511,9 @@ bge_chip_factotum(caddr_t arg) */ if (linkchg) mac_link_update(bgep->mh, bgep->link_state); + if (bgep->manual_reset) { + bgep->manual_reset = B_FALSE; + } return (result); } diff --git a/usr/src/uts/common/io/bge/bge_impl.h b/usr/src/uts/common/io/bge/bge_impl.h index 8b2bbaebc7..2da4240765 100644 --- a/usr/src/uts/common/io/bge/bge_impl.h +++ b/usr/src/uts/common/io/bge/bge_impl.h @@ -20,7 +20,7 @@ */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -63,6 +63,7 @@ extern "C" { #include <sys/pattr.h> #include <sys/disp.h> +#include <sys/cmn_err.h> #include <sys/ddi.h> #include <sys/sunddi.h> @@ -616,6 +617,9 @@ typedef struct { uint64_t hw_mac_addr; /* from chip register */ bge_mac_addr_t vendor_addr; /* transform of same */ boolean_t msi_enabled; /* default to true */ + + uint32_t rx_ticks_norm; + uint32_t rx_count_norm; } chip_id_t; #define CHIP_FLAG_SUPPORTED 0x80 @@ -696,7 +700,6 @@ enum { PARAM_LINK_RX_PAUSE, PARAM_LINK_TX_PAUSE, - PARAM_LOOP_MODE, PARAM_MSI_CNT, PARAM_DRAIN_MAX, @@ -916,6 +919,7 @@ typedef struct bge { boolean_t send_hw_tcp_csum; boolean_t recv_hw_tcp_csum; boolean_t promisc; + boolean_t manual_reset; /* * Miscellaneous operating variables (not synchronised) @@ -960,6 +964,17 @@ typedef struct bge { uint32_t asf_status; timeout_id_t asf_timeout_id; #endif + uint32_t param_en_pause:1, + param_en_asym_pause:1, + param_en_1000hdx:1, + param_en_1000fdx:1, + param_en_100fdx:1, + param_en_100hdx:1, + param_en_10fdx:1, + param_en_10hdx:1, + param_pad_to_32:24; + + uint32_t param_loop_mode; } bge_t; /* @@ -1009,7 +1024,6 @@ typedef struct bge { #define param_link_rx_pause nd_params[PARAM_LINK_RX_PAUSE].ndp_val #define param_link_tx_pause nd_params[PARAM_LINK_TX_PAUSE].ndp_val -#define param_loop_mode nd_params[PARAM_LOOP_MODE].ndp_val #define param_msi_cnt nd_params[PARAM_MSI_CNT].ndp_val #define param_drain_max nd_params[PARAM_DRAIN_MAX].ndp_val @@ -1220,6 +1234,7 @@ void bge_chip_cyclic(void *arg); enum ioc_reply bge_chip_ioctl(bge_t *bgep, queue_t *wq, mblk_t *mp, struct iocblk *iocp); uint_t bge_intr(caddr_t arg1, caddr_t arg2); +void bge_sync_mac_modes(bge_t *); extern uint32_t bge_rx_ticks_norm; extern uint32_t bge_tx_ticks_norm; extern uint32_t bge_rx_count_norm; @@ -1260,6 +1275,7 @@ int bge_alloc_bufs(bge_t *bgep); void bge_free_bufs(bge_t *bgep); void bge_intr_enable(bge_t *bgep); void bge_intr_disable(bge_t *bgep); +int bge_reprogram(bge_t *); /* bge_phys.c */ int bge_phys_init(bge_t *bgep); diff --git a/usr/src/uts/common/io/bge/bge_kstats.c b/usr/src/uts/common/io/bge/bge_kstats.c index 98141d92ce..32af1a2b13 100644 --- a/usr/src/uts/common/io/bge/bge_kstats.c +++ b/usr/src/uts/common/io/bge/bge_kstats.c @@ -20,7 +20,7 @@ */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -600,31 +600,6 @@ bge_setup_named_kstat(bge_t *bgep, int instance, char *name, return (ksp); } -/* - * Create kstats corresponding to NDD parameters - */ -static kstat_t * -bge_setup_params_kstat(bge_t *bgep, int instance, char *name, - int (*update)(kstat_t *, int)) -{ - kstat_t *ksp; - kstat_named_t *knp; - int i; - - ksp = kstat_create(BGE_DRIVER_NAME, instance, name, "net", - KSTAT_TYPE_NAMED, PARAM_COUNT, KSTAT_FLAG_PERSISTENT); - if (ksp != NULL) { - ksp->ks_private = bgep; - ksp->ks_update = update; - for (knp = ksp->ks_data, i = 0; i < PARAM_COUNT; ++knp, ++i) - kstat_named_init(knp, bgep->nd_params[i].ndp_name+1, - KSTAT_DATA_UINT64); - kstat_install(ksp); - } - - return (ksp); -} - void bge_init_kstats(bge_t *bgep, int instance) { diff --git a/usr/src/uts/common/io/bge/bge_main2.c b/usr/src/uts/common/io/bge/bge_main2.c index f80a750652..7a13f85e50 100644 --- a/usr/src/uts/common/io/bge/bge_main2.c +++ b/usr/src/uts/common/io/bge/bge_main2.c @@ -28,6 +28,7 @@ #include "bge_impl.h" #include <sys/sdt.h> +#include <sys/dld.h> /* * This is the string displayed by modinfo, etc. @@ -127,8 +128,17 @@ static int bge_m_unicst_add(void *, mac_multi_addr_t *); static int bge_m_unicst_remove(void *, mac_addr_slot_t); static int bge_m_unicst_modify(void *, mac_multi_addr_t *); static int bge_m_unicst_get(void *, mac_multi_addr_t *); - -#define BGE_M_CALLBACK_FLAGS (MC_RESOURCES | MC_IOCTL | MC_GETCAPAB) +static int bge_m_setprop(void *, const char *, mac_prop_id_t, + uint_t, const void *); +static int bge_m_getprop(void *, const char *, mac_prop_id_t, + uint_t, void *); +static int bge_set_priv_prop(bge_t *, const char *, uint_t, + const void *); +static int bge_get_priv_prop(bge_t *, const char *, uint_t, + void *); + +#define BGE_M_CALLBACK_FLAGS\ + (MC_RESOURCES | MC_IOCTL | MC_GETCAPAB | MC_SETPROP | MC_GETPROP) static mac_callbacks_t bge_m_callbacks = { BGE_M_CALLBACK_FLAGS, @@ -141,7 +151,11 @@ static mac_callbacks_t bge_m_callbacks = { bge_m_tx, bge_m_resources, bge_m_ioctl, - bge_m_getcapab + bge_m_getcapab, + NULL, + NULL, + bge_m_setprop, + bge_m_getprop }; /* @@ -834,6 +848,439 @@ bge_m_unicst_get(void *arg, mac_multi_addr_t *maddr) return (0); } +extern void bge_wake_factotum(bge_t *); + +static boolean_t +bge_param_locked(mac_prop_id_t pr_num) +{ + /* + * All adv_* parameters are locked (read-only) while + * the device is in any sort of loopback mode ... + */ + switch (pr_num) { + case DLD_PROP_ADV_1000FDX_CAP: + case DLD_PROP_EN_1000FDX_CAP: + case DLD_PROP_ADV_1000HDX_CAP: + case DLD_PROP_EN_1000HDX_CAP: + case DLD_PROP_ADV_100FDX_CAP: + case DLD_PROP_EN_100FDX_CAP: + case DLD_PROP_ADV_100HDX_CAP: + case DLD_PROP_EN_100HDX_CAP: + case DLD_PROP_ADV_10FDX_CAP: + case DLD_PROP_EN_10FDX_CAP: + case DLD_PROP_ADV_10HDX_CAP: + case DLD_PROP_EN_10HDX_CAP: + case DLD_PROP_AUTONEG: + case DLD_PROP_FLOWCTRL: + return (B_TRUE); + } + return (B_FALSE); +} +/* + * callback functions for set/get of properties + */ +static int +bge_m_setprop(void *barg, const char *pr_name, mac_prop_id_t pr_num, + uint_t pr_valsize, const void *pr_val) +{ + bge_t *bgep = barg; + int err = 0; + uint64_t cur_mtu, new_mtu; + uint_t maxsdu; + link_flowctrl_t fl; + + mutex_enter(bgep->genlock); + if (bgep->param_loop_mode != BGE_LOOP_NONE && + bge_param_locked(pr_num)) { + /* + * All adv_* parameters are locked (read-only) + * while the device is in any sort of loopback mode. + */ + mutex_exit(bgep->genlock); + return (EBUSY); + } + switch (pr_num) { + case DLD_PROP_EN_1000FDX_CAP: + bgep->param_en_1000fdx = *(uint8_t *)pr_val; + bgep->param_adv_1000fdx = *(uint8_t *)pr_val; + goto reprogram; + case DLD_PROP_EN_1000HDX_CAP: + bgep->param_en_1000hdx = *(uint8_t *)pr_val; + bgep->param_adv_1000hdx = *(uint8_t *)pr_val; + goto reprogram; + case DLD_PROP_EN_100FDX_CAP: + bgep->param_en_100fdx = *(uint8_t *)pr_val; + bgep->param_adv_100fdx = *(uint8_t *)pr_val; + goto reprogram; + case DLD_PROP_EN_100HDX_CAP: + bgep->param_en_100hdx = *(uint8_t *)pr_val; + bgep->param_adv_100hdx = *(uint8_t *)pr_val; + goto reprogram; + case DLD_PROP_EN_10FDX_CAP: + bgep->param_en_10fdx = *(uint8_t *)pr_val; + bgep->param_adv_10fdx = *(uint8_t *)pr_val; + goto reprogram; + case DLD_PROP_EN_10HDX_CAP: + bgep->param_en_10hdx = *(uint8_t *)pr_val; + bgep->param_adv_10hdx = *(uint8_t *)pr_val; +reprogram: + if (err == 0 && bge_reprogram(bgep) == IOC_INVAL) + err = EINVAL; + break; + case DLD_PROP_ADV_1000FDX_CAP: + case DLD_PROP_ADV_1000HDX_CAP: + case DLD_PROP_ADV_100FDX_CAP: + case DLD_PROP_ADV_100HDX_CAP: + case DLD_PROP_ADV_10FDX_CAP: + case DLD_PROP_ADV_10HDX_CAP: + case DLD_PROP_STATUS: + case DLD_PROP_SPEED: + case DLD_PROP_DUPLEX: + err = EINVAL; /* read-only prop. Can't set this */ + break; + case DLD_PROP_AUTONEG: + bgep->param_adv_autoneg = *(uint8_t *)pr_val; + if (bge_reprogram(bgep) == IOC_INVAL) + err = EINVAL; + break; + case DLD_PROP_DEFMTU: + cur_mtu = bgep->chipid.default_mtu; + bcopy(pr_val, &new_mtu, sizeof (new_mtu)); + if (new_mtu == cur_mtu) { + err = 0; + break; + } + if (new_mtu < BGE_DEFAULT_MTU || + new_mtu > BGE_MAXIMUM_MTU) { + err = EINVAL; + break; + } + if ((new_mtu > BGE_DEFAULT_MTU) && + (bgep->chipid.flags & CHIP_FLAG_NO_JUMBO)) { + err = EINVAL; + break; + } + if (bgep->bge_mac_state == BGE_MAC_STARTED) { + err = EBUSY; + break; + } + bgep->chipid.default_mtu = new_mtu; + if (bge_chip_id_init(bgep)) { + err = EINVAL; + break; + } + maxsdu = bgep->chipid.ethmax_size - + sizeof (struct ether_header); + err = mac_maxsdu_update(bgep->mh, maxsdu); + if (err == 0) { + bgep->bge_dma_error = B_TRUE; + bgep->manual_reset = B_TRUE; + bge_chip_stop(bgep, B_TRUE); + bge_wake_factotum(bgep); + err = 0; + } + break; + case DLD_PROP_FLOWCTRL: + bcopy(pr_val, &fl, sizeof (fl)); + switch (fl) { + default: + err = EINVAL; + break; + case LINK_FLOWCTRL_NONE: + bgep->param_adv_pause = 0; + bgep->param_adv_asym_pause = 0; + + bgep->param_link_rx_pause = B_FALSE; + bgep->param_link_tx_pause = B_FALSE; + break; + case LINK_FLOWCTRL_RX: + if (!((bgep->param_lp_pause == 0) && + (bgep->param_lp_asym_pause == 1))) { + err = EINVAL; + break; + } + bgep->param_adv_pause = 1; + bgep->param_adv_asym_pause = 1; + + bgep->param_link_rx_pause = B_TRUE; + bgep->param_link_tx_pause = B_FALSE; + break; + case LINK_FLOWCTRL_TX: + if (!((bgep->param_lp_pause == 1) && + (bgep->param_lp_asym_pause == 1))) { + err = EINVAL; + break; + } + bgep->param_adv_pause = 0; + bgep->param_adv_asym_pause = 1; + + bgep->param_link_rx_pause = B_FALSE; + bgep->param_link_tx_pause = B_TRUE; + break; + case LINK_FLOWCTRL_BI: + if (bgep->param_lp_pause != 1) { + err = EINVAL; + break; + } + bgep->param_adv_pause = 1; + + bgep->param_link_rx_pause = B_TRUE; + bgep->param_link_tx_pause = B_TRUE; + break; + } + + if (err == 0) { + if (bge_reprogram(bgep) == IOC_INVAL) + err = EINVAL; + } + + break; + default: + err = bge_set_priv_prop(bgep, pr_name, pr_valsize, + pr_val); + break; + } + mutex_exit(bgep->genlock); + return (err); +} +static int +bge_m_getprop(void *barg, const char *pr_name, mac_prop_id_t pr_num, + uint_t pr_valsize, void *pr_val) +{ + bge_t *bgep = barg; + int err = 0; + link_flowctrl_t fl; + + bzero(pr_val, pr_valsize); + switch (pr_num) { + case DLD_PROP_DUPLEX: + if (pr_valsize < sizeof (uint8_t)) + return (EINVAL); + *(uint8_t *)pr_val = bgep->param_link_duplex; + break; + case DLD_PROP_SPEED: + if (pr_valsize < sizeof (uint_t)) + return (EINVAL); + bcopy(&(bgep->param_link_speed), pr_val, + sizeof (bgep->param_link_speed)); + break; + case DLD_PROP_STATUS: + if (pr_valsize < sizeof (uint8_t)) + return (EINVAL); + *(uint8_t *)pr_val = bgep->param_link_up; + break; + case DLD_PROP_AUTONEG: + if (pr_valsize < sizeof (uint8_t)) + return (EINVAL); + *(uint8_t *)pr_val = bgep->param_adv_autoneg; + break; + case DLD_PROP_DEFMTU: { + uint64_t tmp = 0; + + if (pr_valsize < sizeof (uint64_t)) + return (EINVAL); + tmp = bgep->chipid.default_mtu; + bcopy(&tmp, pr_val, sizeof (tmp)); + break; + } + case DLD_PROP_FLOWCTRL: + if (pr_valsize < sizeof (link_flowctrl_t)) + return (EINVAL); + if (bgep->param_link_rx_pause && + !bgep->param_link_tx_pause) + fl = LINK_FLOWCTRL_RX; + + if (!bgep->param_link_rx_pause && + !bgep->param_link_tx_pause) + fl = LINK_FLOWCTRL_NONE; + + if (!bgep->param_link_rx_pause && + bgep->param_link_tx_pause) + fl = LINK_FLOWCTRL_TX; + + if (bgep->param_link_rx_pause && + bgep->param_link_tx_pause) + fl = LINK_FLOWCTRL_BI; + bcopy(&fl, pr_val, sizeof (fl)); + break; + case DLD_PROP_ADV_1000FDX_CAP: + if (pr_valsize < sizeof (uint8_t)) + return (EINVAL); + *(uint8_t *)pr_val = bgep->param_adv_1000fdx; + break; + case DLD_PROP_EN_1000FDX_CAP: + if (pr_valsize < sizeof (uint8_t)) + return (EINVAL); + *(uint8_t *)pr_val = bgep->param_en_1000fdx; + break; + case DLD_PROP_ADV_1000HDX_CAP: + if (pr_valsize < sizeof (uint8_t)) + return (EINVAL); + *(uint8_t *)pr_val = bgep->param_adv_1000hdx; + break; + case DLD_PROP_EN_1000HDX_CAP: + if (pr_valsize < sizeof (uint8_t)) + return (EINVAL); + *(uint8_t *)pr_val = bgep->param_en_1000hdx; + break; + case DLD_PROP_ADV_100FDX_CAP: + if (pr_valsize < sizeof (uint8_t)) + return (EINVAL); + *(uint8_t *)pr_val = bgep->param_adv_100fdx; + break; + case DLD_PROP_EN_100FDX_CAP: + if (pr_valsize < sizeof (uint8_t)) + return (EINVAL); + *(uint8_t *)pr_val = bgep->param_en_100fdx; + break; + case DLD_PROP_ADV_100HDX_CAP: + if (pr_valsize < sizeof (uint8_t)) + return (EINVAL); + *(uint8_t *)pr_val = bgep->param_adv_100hdx; + break; + case DLD_PROP_EN_100HDX_CAP: + if (pr_valsize < sizeof (uint8_t)) + return (EINVAL); + *(uint8_t *)pr_val = bgep->param_en_100hdx; + break; + case DLD_PROP_ADV_10FDX_CAP: + if (pr_valsize < sizeof (uint8_t)) + return (EINVAL); + *(uint8_t *)pr_val = bgep->param_adv_10fdx; + break; + case DLD_PROP_EN_10FDX_CAP: + if (pr_valsize < sizeof (uint8_t)) + return (EINVAL); + *(uint8_t *)pr_val = bgep->param_en_10fdx; + break; + case DLD_PROP_ADV_10HDX_CAP: + if (pr_valsize < sizeof (uint8_t)) + return (EINVAL); + *(uint8_t *)pr_val = bgep->param_adv_10hdx; + break; + case DLD_PROP_EN_10HDX_CAP: + if (pr_valsize < sizeof (uint8_t)) + return (EINVAL); + *(uint8_t *)pr_val = bgep->param_en_10hdx; + break; + default: + err = bge_get_priv_prop(bgep, pr_name, pr_valsize, + pr_val); + return (err); + } + return (0); +} + +/* ARGSUSED */ +static int +bge_set_priv_prop(bge_t *bgep, const char *pr_name, uint_t pr_valsize, + const void *pr_val) +{ + int err = 0; + long result; + + if (strcmp(pr_name, "_drain_max") == 0) { + + /* + * on the Tx side, we need to update the h/w register for + * real packet transmission per packet. The drain_max parameter + * is used to reduce the register access. This parameter + * controls the max number of packets that we will hold before + * updating the bge h/w to trigger h/w transmit. The bge + * chipset usually has a max of 512 Tx descriptors, thus + * the upper bound on drain_max is 512. + */ + if (pr_val == NULL) { + err = EINVAL; + return (err); + } + (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); + if (result > 512 || result < 1) + err = EINVAL; + else { + bgep->param_drain_max = (uint32_t)result; + if (bge_reprogram(bgep) == IOC_INVAL) + err = EINVAL; + } + return (err); + } + if (strcmp(pr_name, "_msi_cnt") == 0) { + + if (pr_val == NULL) { + err = EINVAL; + return (err); + } + (void) ddi_strtol(pr_val, (char **)NULL, 0, &result); + if (result > 7 || result < 0) + err = EINVAL; + else { + bgep->param_msi_cnt = (uint32_t)result; + if (bge_reprogram(bgep) == IOC_INVAL) + err = EINVAL; + } + return (err); + } + if (strcmp(pr_name, "_intr_coalesce_blank_time") == 0) { + if (ddi_strtol(pr_val, (char **)NULL, 0, &result) != 0) { + return (EINVAL); + } + + bgep->chipid.rx_ticks_norm = result; + return (0); + } + + if (strcmp(pr_name, "_intr_coalesce_pkt_cnt") == 0) { + if (ddi_strtol(pr_val, (char **)NULL, 0, &result) != 0) + return (EINVAL); + + bgep->chipid.rx_count_norm = result; + return (0); + } + return (EINVAL); +} + +static int +bge_get_priv_prop(bge_t *bge, const char *pr_name, uint_t pr_valsize, + void *pr_val) +{ + char valstr[MAXNAMELEN]; + int err = EINVAL; + uint_t strsize; + + + if (strcmp(pr_name, "_drain_max") == 0) { + (void) sprintf(valstr, "%d", bge->param_drain_max); + err = 0; + goto done; + } + if (strcmp(pr_name, "_msi_cnt") == 0) { + (void) sprintf(valstr, "%d", bge->param_msi_cnt); + err = 0; + goto done; + } + + if (strcmp(pr_name, "_intr_coalesce_blank_time") == 0) { + (void) sprintf(valstr, "%d", bge->chipid.rx_ticks_norm); + err = 0; + goto done; + } + + if (strcmp(pr_name, "_intr_coalesce_pkt_cnt") == 0) { + (void) sprintf(valstr, "%d", bge->chipid.rx_count_norm); + err = 0; + goto done; + } + +done: + strsize = (uint_t)strlen(valstr); + if (pr_valsize < strsize) { + err = ENOBUFS; + } else { + (void) strlcpy(pr_val, valstr, pr_valsize); + } + return (err); +} + /* * Compute the index of the required bit in the multicast hash map. * This must mirror the way the hardware actually does it! @@ -1262,22 +1709,8 @@ bge_m_ioctl(void *arg, queue_t *wq, mblk_t *mp) switch (status) { case IOC_RESTART_REPLY: case IOC_RESTART_ACK: - if (bge_phys_update(bgep) != DDI_SUCCESS) { - ddi_fm_service_impact(bgep->devinfo, - DDI_SERVICE_DEGRADED); - status = IOC_INVAL; - } -#ifdef BGE_IPMI_ASF - if (bge_chip_sync(bgep, B_TRUE) == DDI_FAILURE) { -#else - if (bge_chip_sync(bgep) == DDI_FAILURE) { -#endif - ddi_fm_service_impact(bgep->devinfo, - DDI_SERVICE_DEGRADED); + if (bge_reprogram(bgep) == IOC_INVAL) status = IOC_INVAL; - } - if (bgep->intr_type == DDI_INTR_TYPE_MSI) - bge_chip_msi_trig(bgep); break; } @@ -1331,15 +1764,13 @@ bge_m_ioctl(void *arg, queue_t *wq, mblk_t *mp) } static void -bge_m_resources(void *arg) +bge_resources_add(bge_t *bgep, time_t time, uint_t pkt_cnt) { - bge_t *bgep = arg; + recv_ring_t *rrp; mac_rx_fifo_t mrf; int ring; - mutex_enter(bgep->genlock); - /* * Register Rx rings as resources and save mac * resource id for future reference @@ -1347,15 +1778,25 @@ bge_m_resources(void *arg) mrf.mrf_type = MAC_RX_FIFO; mrf.mrf_blank = bge_chip_blank; mrf.mrf_arg = (void *)bgep; - mrf.mrf_normal_blank_time = bge_rx_ticks_norm; - mrf.mrf_normal_pkt_count = bge_rx_count_norm; + mrf.mrf_normal_blank_time = time; + mrf.mrf_normal_pkt_count = pkt_cnt; for (ring = 0; ring < bgep->chipid.rx_rings; ring++) { rrp = &bgep->recv[ring]; rrp->handle = mac_resource_add(bgep->mh, (mac_resource_t *)&mrf); } +} +static void +bge_m_resources(void *arg) +{ + bge_t *bgep = arg; + + mutex_enter(bgep->genlock); + + bge_resources_add(bgep, bgep->chipid.rx_ticks_norm, + bgep->chipid.rx_count_norm); mutex_exit(bgep->genlock); } @@ -2520,6 +2961,9 @@ bge_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd) ddi_set_driver_private(devinfo, bgep); bgep->bge_guard = BGE_GUARD; bgep->devinfo = devinfo; + bgep->param_drain_max = 64; + bgep->param_msi_cnt = 0; + bgep->param_loop_mode = 0; /* * Initialize more fields in BGE private data @@ -3241,3 +3685,27 @@ bge_intr_disable(bge_t *bgep) } } } + +int +bge_reprogram(bge_t *bgep) +{ + int status = 0; + + ASSERT(mutex_owned(bgep->genlock)); + + if (bge_phys_update(bgep) != DDI_SUCCESS) { + ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); + status = IOC_INVAL; + } +#ifdef BGE_IPMI_ASF + if (bge_chip_sync(bgep, B_TRUE) == DDI_FAILURE) { +#else + if (bge_chip_sync(bgep) == DDI_FAILURE) { +#endif + ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_DEGRADED); + status = IOC_INVAL; + } + if (bgep->intr_type == DDI_INTR_TYPE_MSI) + bge_chip_msi_trig(bgep); + return (status); +} diff --git a/usr/src/uts/common/io/bge/bge_ndd.c b/usr/src/uts/common/io/bge/bge_ndd.c index ca993b64f7..280f3b6bcb 100644 --- a/usr/src/uts/common/io/bge/bge_ndd.c +++ b/usr/src/uts/common/io/bge/bge_ndd.c @@ -20,7 +20,7 @@ */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -30,7 +30,6 @@ #define BGE_DBG BGE_DBG_NDD /* debug flag for this code */ - /* * Property names */ @@ -112,15 +111,6 @@ static const nd_param_t nd_template[] = { { PARAM_LINK_RX_PAUSE, 0, 1, 0, "-link_rx_pause" }, { PARAM_LINK_TX_PAUSE, 0, 1, 0, "-link_tx_pause" }, -/* Loopback status */ -{ PARAM_LOOP_MODE, 0, 5, 0, "-loop_mode" }, - -/* MSI count */ -{ PARAM_MSI_CNT, 0, 7, 0, "+msi_cnt" }, - -/* Performance tuning */ -{ PARAM_DRAIN_MAX, 1, 512, 64, "+drain_max" }, - /* Terminator */ { PARAM_COUNT, 0, 0, 0, NULL } }; @@ -146,6 +136,27 @@ bge_param_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp) } /* + * synchronize the adv* and en* parameters. + * + * See comments in <sys/dld.h> for details of the *_en_* + * parameters. The usage of ndd for setting adv parameters will + * synchronize all the en parameters with the bge parameters, + * implicitly disabling any settings made via dladm. + */ +static void +bge_param_sync(bge_t *bgep) +{ + bgep->param_en_pause = bgep->param_adv_pause; + bgep->param_en_asym_pause = bgep->param_adv_asym_pause; + bgep->param_en_1000fdx = bgep->param_adv_1000fdx; + bgep->param_en_1000hdx = bgep->param_adv_1000hdx; + bgep->param_en_100fdx = bgep->param_adv_100fdx; + bgep->param_en_100hdx = bgep->param_adv_100hdx; + bgep->param_en_10fdx = bgep->param_adv_10fdx; + bgep->param_en_10hdx = bgep->param_adv_10hdx; +} + +/* * Validates the request to set a BGE parameter to a specific value. * If the request is OK, the parameter is set. Also the <info> field * is incremented to show that the parameter was touched, even though @@ -251,7 +262,7 @@ bge_param_register(bge_t *bgep) nd_fail: BGE_DEBUG(("bge_param_register: FAILED at index %d [info %d]", - tmplp-nd_template, tmplp->ndp_info)); + tmplp-nd_template, tmplp->ndp_info)); nd_free(nddpp); return (DDI_FAILURE); } @@ -280,8 +291,8 @@ bge_nd_init(bge_t *bgep) */ if (BGE_PROP_EXISTS(bgep->devinfo, supported_net)) { if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, bgep->devinfo, - DDI_PROP_DONTPASS, supported_net, - &options, &noptions) == DDI_PROP_SUCCESS) { + DDI_PROP_DONTPASS, supported_net, + &options, &noptions) == DDI_PROP_SUCCESS) { bgep->param_adv_autoneg = 0; bgep->param_adv_1000fdx = 0; @@ -342,7 +353,7 @@ bge_nd_init(bge_t *bgep) speed = BGE_PROP_GET_INT(dip, transfer_speed_propname); bge_log(bgep, "%s property is %d", - transfer_speed_propname, speed); + transfer_speed_propname, speed); switch (speed) { case 1000: @@ -401,9 +412,9 @@ bge_nd_init(bge_t *bgep) speed = BGE_PROP_GET_INT(dip, speed_propname); duplex = BGE_PROP_GET_INT(dip, duplex_propname); bge_log(bgep, "%s property is %d", - speed_propname, speed); + speed_propname, speed); bge_log(bgep, "%s property is %d", - duplex_propname, duplex); + duplex_propname, duplex); switch (speed) { case 1000: @@ -446,15 +457,17 @@ bge_nd_init(bge_t *bgep) } BGE_DEBUG(("bge_nd_init: autoneg %d" - "pause %d asym_pause %d " - "1000fdx %d 1000hdx %d " - "100fdx %d 100hdx %d " - "10fdx %d 10hdx %d ", - bgep->param_adv_autoneg, - bgep->param_adv_pause, bgep->param_adv_asym_pause, - bgep->param_adv_1000fdx, bgep->param_adv_1000hdx, - bgep->param_adv_100fdx, bgep->param_adv_100hdx, - bgep->param_adv_10fdx, bgep->param_adv_10hdx)); + "pause %d asym_pause %d " + "1000fdx %d 1000hdx %d " + "100fdx %d 100hdx %d " + "10fdx %d 10hdx %d ", + bgep->param_adv_autoneg, + bgep->param_adv_pause, bgep->param_adv_asym_pause, + bgep->param_adv_1000fdx, bgep->param_adv_1000hdx, + bgep->param_adv_100fdx, bgep->param_adv_100hdx, + bgep->param_adv_10fdx, bgep->param_adv_10hdx)); + + bge_param_sync(bgep); return (0); } @@ -468,7 +481,7 @@ bge_nd_ioctl(bge_t *bgep, queue_t *wq, mblk_t *mp, struct iocblk *iocp) int cmd; BGE_TRACE(("bge_nd_ioctl($%p, $%p, $%p, $%p)", - (void *)bgep, (void *)wq, (void *)mp, (void *)iocp)); + (void *)bgep, (void *)wq, (void *)mp, (void *)iocp)); ASSERT(mutex_owned(bgep->genlock)); @@ -513,6 +526,8 @@ bge_nd_ioctl(bge_t *bgep, queue_t *wq, mblk_t *mp, struct iocblk *iocp) info = ndp->ndp_info; ok = nd_getset(wq, bgep->nd_data_p, mp); + bge_param_sync(bgep); + /* * If nd_getset() returns B_FALSE, the command was * not valid (e.g. unknown name), so we just tell @@ -526,8 +541,8 @@ bge_nd_ioctl(bge_t *bgep, queue_t *wq, mblk_t *mp, struct iocblk *iocp) * So, we also drop out in that case ... */ BGE_DEBUG(("bge_nd_ioctl: set %s err %d autoneg %d info %d/%d", - ok ? "OK" : "FAIL", iocp->ioc_error, - ndp->ndp_val, info, ndp->ndp_info)); + ok ? "OK" : "FAIL", iocp->ioc_error, + ndp->ndp_val, info, ndp->ndp_info)); if (!ok) return (IOC_INVAL); if (iocp->ioc_error) diff --git a/usr/src/uts/common/io/bge/bge_recv2.c b/usr/src/uts/common/io/bge/bge_recv2.c index 78a5913ae2..06282b461b 100644 --- a/usr/src/uts/common/io/bge/bge_recv2.c +++ b/usr/src/uts/common/io/bge/bge_recv2.c @@ -20,7 +20,7 @@ */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -211,8 +211,8 @@ bge_receive_packet(bge_t *bgep, bge_rbd_t *hw_rbd_p) ehp->ether_tpid = ntohs(ETHERTYPE_VLAN); ehp->ether_tci = ntohs(hw_rbd.vlan_tci); bcopy(((uchar_t *)(DMA_VPTR(srbdp->pbuf))) + 2 * ETHERADDRL, - dp + 2 * ETHERADDRL + VLAN_TAGSZ, - len - 2 * ETHERADDRL); + dp + 2 * ETHERADDRL + VLAN_TAGSZ, + len - 2 * ETHERADDRL); } else { #endif mp->b_rptr = dp = mp->b_rptr + BGE_HEADROOM; @@ -312,7 +312,7 @@ bge_receive_ring(bge_t *bgep, recv_ring_t *rrp) slot = rrp->rx_next; while ((slot != *rrp->prod_index_p) && /* Note: volatile */ - (recv_cnt < BGE_MAXPKT_RCVED)) { + (recv_cnt < BGE_MAXPKT_RCVED)) { if ((mp = bge_receive_packet(bgep, &hw_rbd_p[slot])) != NULL) { *tail = mp; tail = &mp->b_next; diff --git a/usr/src/uts/common/io/dld/dld_drv.c b/usr/src/uts/common/io/dld/dld_drv.c index 2b394c051d..e09b6eff13 100644 --- a/usr/src/uts/common/io/dld/dld_drv.c +++ b/usr/src/uts/common/io/dld/dld_drv.c @@ -431,8 +431,8 @@ drv_ioc_attr(dld_ctl_str_t *ctls, mblk_t *mp) dls_devnet_rele_tmp(dlh); goto failed; } + mac_sdu_get(dvp->dv_dlp->dl_mh, NULL, &diap->dia_max_sdu); - diap->dia_max_sdu = dvp->dv_dlp->dl_mip->mi_sdu_max; dls_vlan_rele(dvp); dls_devnet_rele_tmp(dlh); @@ -507,6 +507,72 @@ failed: } /* + * DLDIOCSETPROP + */ +static void +drv_ioc_prop_common(dld_ctl_str_t *ctls, mblk_t *mp, boolean_t set) +{ + int err = EINVAL, dsize; + queue_t *q = ctls->cs_wq; + dld_ioc_prop_t *dipp; + dls_dl_handle_t dlh; + dls_vlan_t *dvp; + datalink_id_t linkid; + mac_prop_t macprop; + + if ((err = miocpullup(mp, sizeof (dld_ioc_prop_t))) != 0) + goto done; + dipp = (dld_ioc_prop_t *)mp->b_cont->b_rptr; + + dsize = sizeof (dld_ioc_prop_t) + dipp->pr_valsize - 1; + if ((err = miocpullup(mp, dsize)) != 0) + goto done; + dipp = (dld_ioc_prop_t *)mp->b_cont->b_rptr; + + if ((err = dls_mgmt_get_linkid(dipp->pr_linkname, &linkid)) != 0) + goto done; + + if ((err = dls_devnet_hold_tmp(linkid, &dlh)) != 0) + goto done; + + if ((err = dls_vlan_hold(dls_devnet_mac(dlh), + dls_devnet_vid(dlh), &dvp, B_FALSE, B_FALSE)) != 0) { + dls_devnet_rele_tmp(dlh); + goto done; + } + + macprop.mp_name = dipp->pr_name; + macprop.mp_id = dipp->pr_num; + + if (set) + err = mac_set_prop(dvp->dv_dlp->dl_mh, &macprop, + dipp->pr_val, dipp->pr_valsize); + else + err = mac_get_prop(dvp->dv_dlp->dl_mh, &macprop, + dipp->pr_val, dipp->pr_valsize); + + dls_vlan_rele(dvp); + dls_devnet_rele_tmp(dlh); +done: + if (err == 0) + miocack(q, mp, dsize, 0); + else + miocnak(q, mp, 0, err); +} + +static void +drv_ioc_setprop(dld_ctl_str_t *ctls, mblk_t *mp) +{ + drv_ioc_prop_common(ctls, mp, B_TRUE); +} + +static void +drv_ioc_getprop(dld_ctl_str_t *ctls, mblk_t *mp) +{ + drv_ioc_prop_common(ctls, mp, B_FALSE); +} + +/* * DLDIOC_CREATE_VLAN */ static void @@ -900,6 +966,12 @@ drv_ioc(dld_ctl_str_t *ctls, mblk_t *mp) case DLDIOC_SECOBJ_UNSET: drv_ioc_secobj_unset(ctls, mp); return; + case DLDIOCSETPROP: + drv_ioc_setprop(ctls, mp); + return; + case DLDIOCGETPROP: + drv_ioc_getprop(ctls, mp); + return; case DLDIOC_CREATE_VLAN: drv_ioc_create_vlan(ctls, mp); return; diff --git a/usr/src/uts/common/io/dld/dld_proto.c b/usr/src/uts/common/io/dld/dld_proto.c index 78543294d4..f572c3c322 100644 --- a/usr/src/uts/common/io/dld/dld_proto.c +++ b/usr/src/uts/common/io/dld/dld_proto.c @@ -238,6 +238,8 @@ proto_info_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) minfop = &minfo; } else { minfop = (mac_info_t *)dsp->ds_mip; + /* We can only get the sdu if we're attached. */ + mac_sdu_get(dsp->ds_mh, &dlp->dl_min_sdu, &dlp->dl_max_sdu); } /* @@ -255,12 +257,6 @@ proto_info_req(dld_str_t *dsp, union DL_primitives *udlp, mblk_t *mp) sap_length = sizeof (uint16_t); dlp->dl_sap_length = NEG(sap_length); - /* - * Set the minimum and maximum payload sizes. - */ - dlp->dl_min_sdu = minfop->mi_sdu_min; - dlp->dl_max_sdu = minfop->mi_sdu_max; - addr_length = minfop->mi_addr_length; /* @@ -1322,6 +1318,7 @@ dld_wput_proto_data(dld_str_t *dsp, mblk_t *mp) mblk_t *bp, *payload; uint32_t start, stuff, end, value, flags; t_uscalar_t dl_err; + uint_t max_sdu; if (MBLKL(mp) < sizeof (dl_unitdata_req_t) || mp->b_cont == NULL) { dl_err = DL_BADPRIM; @@ -1358,7 +1355,8 @@ dld_wput_proto_data(dld_str_t *dsp, mblk_t *mp) size += MBLKL(bp); } - if (size > dsp->ds_mip->mi_sdu_max) + mac_sdu_get(dsp->ds_mh, NULL, &max_sdu); + if (size > max_sdu) goto baddata; /* diff --git a/usr/src/uts/common/io/dld/dld_str.c b/usr/src/uts/common/io/dld/dld_str.c index f89e4a5f94..bb39729813 100644 --- a/usr/src/uts/common/io/dld/dld_str.c +++ b/usr/src/uts/common/io/dld/dld_str.c @@ -1008,6 +1008,7 @@ str_mdata_raw_put(dld_str_t *dsp, mblk_t *mp) size_t size; mac_header_info_t mhi; uint_t pri, vid; + uint_t max_sdu; /* * Certain MAC type plugins provide an illusion for raw DLPI @@ -1042,12 +1043,13 @@ str_mdata_raw_put(dld_str_t *dsp, mblk_t *mp) if (dls_header_info(dsp->ds_dc, mp, &mhi) != 0) goto discard; + mac_sdu_get(dsp->ds_mh, NULL, &max_sdu); /* * If LSO is enabled, check the size against lso_max. Otherwise, - * compare the packet size with sdu_max. + * compare the packet size with max_sdu. */ - if (size > (dsp->ds_lso ? dsp->ds_lso_max : dsp->ds_mip->mi_sdu_max) - + mhi.mhi_hdrsize) + max_sdu = dsp->ds_lso ? dsp->ds_lso_max : max_sdu; + if (size > max_sdu + mhi.mhi_hdrsize) goto discard; if (is_ethernet) { @@ -1473,6 +1475,31 @@ dld_str_rx_unitdata(void *arg, mac_resource_handle_t mrh, mblk_t *mp, } /* + * DL_NOTIFY_IND: DL_NOTE_SDU_SIZE + */ +static void +str_notify_sdu_size(dld_str_t *dsp, uint_t max_sdu) +{ + mblk_t *mp; + dl_notify_ind_t *dlip; + + if (!(dsp->ds_notifications & DL_NOTE_SDU_SIZE)) + return; + + if ((mp = mexchange(dsp->ds_wq, NULL, sizeof (dl_notify_ind_t), + M_PROTO, 0)) == NULL) + return; + + bzero(mp->b_rptr, sizeof (dl_notify_ind_t)); + dlip = (dl_notify_ind_t *)mp->b_rptr; + dlip->dl_primitive = DL_NOTIFY_IND; + dlip->dl_notification = DL_NOTE_SDU_SIZE; + dlip->dl_data = max_sdu; + + qreply(dsp->ds_wq, mp); +} + +/* * Generate DL_NOTIFY_IND messages to notify the DLPI consumer of the * current state of the interface. */ @@ -1857,12 +1884,20 @@ str_notify(void *arg, mac_notify_type_t type) str_notify_capab_reneg(dsp); break; + case MAC_NOTE_SDU_SIZE: { + uint_t max_sdu; + mac_sdu_get(dsp->ds_mh, NULL, &max_sdu); + str_notify_sdu_size(dsp, max_sdu); + break; + } + case MAC_NOTE_FASTPATH_FLUSH: str_notify_fastpath_flush(dsp); break; case MAC_NOTE_MARGIN: break; + default: ASSERT(B_FALSE); break; diff --git a/usr/src/uts/common/io/gld.c b/usr/src/uts/common/io/gld.c index d14b0eff00..0aa1ae890a 100644 --- a/usr/src/uts/common/io/gld.c +++ b/usr/src/uts/common/io/gld.c @@ -204,7 +204,7 @@ extern void gld_sr_dump(gld_mac_info_t *); * Allocate and zero-out "number" structures each of type "structure" in * kernel memory. */ -#define GETSTRUCT(structure, number) \ +#define GLD_GETSTRUCT(structure, number) \ (kmem_zalloc((uint_t)(sizeof (structure) * (number)), KM_NOSLEEP)) #define abs(a) ((a) < 0 ? -(a) : a) @@ -574,7 +574,7 @@ gld_register(dev_info_t *devinfo, char *devname, gld_mac_info_t *macinfo) */ if (glddev == NULL) { /* first occurrence of this device name (major number) */ - glddev = GETSTRUCT(glddev_t, 1); + glddev = GLD_GETSTRUCT(glddev_t, 1); if (glddev == NULL) { mutex_exit(&gld_device_list.gld_devlock); return (DDI_FAILURE); @@ -584,9 +584,9 @@ gld_register(dev_info_t *devinfo, char *devname, gld_mac_info_t *macinfo) glddev->gld_major = major; glddev->gld_nextminor = GLD_MIN_CLONE_MINOR; glddev->gld_mac_next = glddev->gld_mac_prev = - (gld_mac_info_t *)&glddev->gld_mac_next; + (gld_mac_info_t *)&glddev->gld_mac_next; glddev->gld_str_next = glddev->gld_str_prev = - (gld_t *)&glddev->gld_str_next; + (gld_t *)&glddev->gld_str_next; mutex_init(&glddev->gld_devlock, NULL, MUTEX_DRIVER, NULL); /* allow increase of number of supported multicast addrs */ @@ -806,9 +806,9 @@ late_failure: ddi_remove_minor_node(devinfo, NULL); GLDM_LOCK_DESTROY(macinfo); if (mac_pvt->curr_macaddr != NULL) - kmem_free(mac_pvt->curr_macaddr, macinfo->gldm_addrlen); + kmem_free(mac_pvt->curr_macaddr, macinfo->gldm_addrlen); if (mac_pvt->statistics != NULL) - kmem_free(mac_pvt->statistics, sizeof (struct gld_stats)); + kmem_free(mac_pvt->statistics, sizeof (struct gld_stats)); kmem_free(macinfo->gldm_mac_pvt, sizeof (gld_mac_pvt_t)); macinfo->gldm_mac_pvt = NULL; @@ -3243,13 +3243,13 @@ gld_addudind(gld_t *gld, mblk_t *mp, pktinfo_t *pktinfo, boolean_t tagged) dludindp->dl_primitive = DL_UNITDATA_IND; dludindp->dl_src_addr_length = dludindp->dl_dest_addr_length = macinfo->gldm_addrlen + - abs(macinfo->gldm_saplen); + abs(macinfo->gldm_saplen); dludindp->dl_dest_addr_offset = sizeof (dl_unitdata_ind_t); dludindp->dl_src_addr_offset = dludindp->dl_dest_addr_offset + - dludindp->dl_dest_addr_length; + dludindp->dl_dest_addr_length; dludindp->dl_group_address = (pktinfo->isMulticast || - pktinfo->isBroadcast); + pktinfo->isBroadcast); nmp->b_wptr = nmp->b_rptr + dludindp->dl_dest_addr_offset; @@ -4001,14 +4001,14 @@ gld_notify_req(queue_t *q, mblk_t *mp) #ifdef GLD_DEBUG if (gld_debug & GLDTRACE) cmn_err(CE_NOTE, "gld_notify_req(%p %p)", - (void *)q, (void *)mp); + (void *)q, (void *)mp); #endif if (gld->gld_state == DL_UNATTACHED) { #ifdef GLD_DEBUG if (gld_debug & GLDERRS) cmn_err(CE_NOTE, "gld_notify_req: wrong state (%d)", - gld->gld_state); + gld->gld_state); #endif return (DL_OUTSTATE); } @@ -4205,7 +4205,7 @@ gld_bind(queue_t *q, mblk_t *mp) #ifdef GLD_DEBUG if (gld_debug & GLDERRS) cmn_err(CE_NOTE, "gld_bind: bound or not attached (%d)", - gld->gld_state); + gld->gld_state); #endif return (DL_OUTSTATE); } @@ -4285,7 +4285,7 @@ gld_unbind(queue_t *q, mblk_t *mp) #ifdef GLD_DEBUG if (gld_debug & GLDERRS) cmn_err(CE_NOTE, "gld_unbind: wrong state (%d)", - gld->gld_state); + gld->gld_state); #endif return (DL_OUTSTATE); } @@ -4516,7 +4516,7 @@ gld_unitdata(queue_t *q, mblk_t *mp) #ifdef GLD_DEBUG if (gld_debug & GLDERRS) cmn_err(CE_NOTE, "gld_unitdata: wrong state (%d)", - gld->gld_state); + gld->gld_state); #endif dluderrorind(q, mp, mp->b_rptr + dlp->dl_dest_addr_offset, dlp->dl_dest_addr_length, DL_OUTSTATE, 0); @@ -4539,7 +4539,7 @@ gld_unitdata(queue_t *q, mblk_t *mp) #ifdef GLD_DEBUG if (gld_debug & GLDERRS) cmn_err(CE_NOTE, "gld_unitdata: bad msglen (%d)", - (int)msglen); + (int)msglen); #endif dluderrorind(q, mp, mp->b_rptr + dlp->dl_dest_addr_offset, dlp->dl_dest_addr_length, DL_BADDATA, 0); @@ -4886,8 +4886,8 @@ gld_enable_multi(queue_t *q, mblk_t *mp) /* does this address appear in current table? */ if (gld->gld_mcast == NULL) { /* no mcast addresses -- allocate table */ - gld->gld_mcast = GETSTRUCT(gld_mcast_t *, - glddev->gld_multisize); + gld->gld_mcast = GLD_GETSTRUCT(gld_mcast_t *, + glddev->gld_multisize); if (gld->gld_mcast == NULL) { GLDM_UNLOCK(macinfo); dlerrorack(q, mp, DL_ENABMULTI_REQ, DL_SYSERR, ENOSR); @@ -4898,7 +4898,7 @@ gld_enable_multi(queue_t *q, mblk_t *mp) for (i = 0; i < gld->gld_multicnt; i++) { if (gld->gld_mcast[i] && mac_eq(gld->gld_mcast[i]->gldm_addr, - maddr, macinfo->gldm_addrlen)) { + maddr, macinfo->gldm_addrlen)) { /* this is a match -- just succeed */ ASSERT(gld->gld_mcast[i]->gldm_refcnt); GLDM_UNLOCK(macinfo); @@ -4913,8 +4913,8 @@ gld_enable_multi(queue_t *q, mblk_t *mp) */ mcast = NULL; if (mac_pvt->mcast_table == NULL) { - mac_pvt->mcast_table = GETSTRUCT(gld_mcast_t, - glddev->gld_multisize); + mac_pvt->mcast_table = GLD_GETSTRUCT(gld_mcast_t, + glddev->gld_multisize); if (mac_pvt->mcast_table == NULL) { GLDM_UNLOCK(macinfo); dlerrorack(q, mp, DL_ENABMULTI_REQ, DL_SYSERR, ENOSR); @@ -5685,7 +5685,7 @@ nextminor: ; } cmn_err(CE_WARN, "GLD ran out of minor numbers for %s", - device->gld_name); + device->gld_name); return (0); } diff --git a/usr/src/uts/common/io/ipw/ipw2100.c b/usr/src/uts/common/io/ipw/ipw2100.c index 34fcc32a6e..10e5c7f65c 100644 --- a/usr/src/uts/common/io/ipw/ipw2100.c +++ b/usr/src/uts/common/io/ipw/ipw2100.c @@ -51,6 +51,7 @@ #include <sys/devops.h> #include <sys/dlpi.h> #include <sys/mac.h> +#include <net/if.h> #include <sys/mac_wifi.h> #include <sys/varargs.h> #include <sys/policy.h> diff --git a/usr/src/uts/common/io/ipw/ipw2100_impl.h b/usr/src/uts/common/io/ipw/ipw2100_impl.h index b0800d8e80..269ed55eb5 100644 --- a/usr/src/uts/common/io/ipw/ipw2100_impl.h +++ b/usr/src/uts/common/io/ipw/ipw2100_impl.h @@ -1,5 +1,5 @@ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -166,12 +166,7 @@ struct ipw2100_softc { kcondvar_t sc_scan_cv; /* used for active scan */ kthread_t *sc_mf_thread; uint32_t sc_mfthread_switch; /* 0/1 indicate off/on */ - int if_flags; -#define IFF_DEBUG (0x0004) -#define IFF_PROMISC (0x0100) -#define IFF_SIMPLEX (0x0800) - }; /* diff --git a/usr/src/uts/common/io/mac/mac.c b/usr/src/uts/common/io/mac/mac.c index d12bfdf021..3bc71547de 100644 --- a/usr/src/uts/common/io/mac/mac.c +++ b/usr/src/uts/common/io/mac/mac.c @@ -53,6 +53,7 @@ #include <sys/cpuvar.h> #include <sys/atomic.h> #include <sys/sdt.h> +#include <inet/nd.h> #define IMPL_HASHSZ 67 /* prime */ @@ -1004,6 +1005,17 @@ mac_promisc_get(mac_handle_t mh, mac_promisc_type_t ptype) } void +mac_sdu_get(mac_handle_t mh, uint_t *min_sdu, uint_t *max_sdu) +{ + mac_impl_t *mip = (mac_impl_t *)mh; + + if (min_sdu != NULL) + *min_sdu = mip->mi_sdu_min; + if (max_sdu != NULL) + *max_sdu = mip->mi_sdu_max; +} + +void mac_resources(mac_handle_t mh) { mac_impl_t *mip = (mac_impl_t *)mh; @@ -1020,7 +1032,20 @@ void mac_ioctl(mac_handle_t mh, queue_t *wq, mblk_t *bp) { mac_impl_t *mip = (mac_impl_t *)mh; + int cmd; + if (mip->mi_callbacks->mc_callbacks & (MC_SETPROP|MC_GETPROP)) { + cmd = ((struct iocblk *)bp->b_rptr)->ioc_cmd; + if (cmd == ND_SET || cmd == ND_GET) { + /* + * ndd ioctls are Obsolete + */ + cmn_err(CE_WARN, + "The ndd commands are obsolete and may be removed " + "in a future release of Solaris. " + "Use dladm(1M) to manage driver tunables\n"); + } + } /* * Call the driver to handle the ioctl. The driver may not support * any ioctls, in which case we reply with a NAK on its behalf. @@ -1511,10 +1536,10 @@ mac_register(mac_register_t *mregp, mac_handle_t *mhp) mip->mi_margin = mregp->m_margin; mip->mi_info.mi_media = mtype->mt_type; mip->mi_info.mi_nativemedia = mtype->mt_nativetype; - mip->mi_info.mi_sdu_min = mregp->m_min_sdu; if (mregp->m_max_sdu <= mregp->m_min_sdu) goto fail; - mip->mi_info.mi_sdu_max = mregp->m_max_sdu; + mip->mi_sdu_min = mregp->m_min_sdu; + mip->mi_sdu_max = mregp->m_max_sdu; mip->mi_info.mi_addr_length = mip->mi_type->mt_addr_length; /* * If the media supports a broadcast address, cache a pointer to it @@ -1667,6 +1692,9 @@ mac_register(mac_register_t *mregp, mac_handle_t *mhp) goto fail; } + DTRACE_PROBE2(mac__register, struct devnames *, dnp, + (mac_impl_t *), mip); + /* * Mark the MAC to be ready for open. */ @@ -2817,3 +2845,43 @@ done: mutex_exit(&i_mactype_lock); return (err); } + +int +mac_set_prop(mac_handle_t mh, mac_prop_t *macprop, void *val, uint_t valsize) +{ + int err = ENOTSUP; + mac_impl_t *mip = (mac_impl_t *)mh; + + if (mip->mi_callbacks->mc_callbacks & MC_SETPROP) { + err = mip->mi_callbacks->mc_setprop(mip->mi_driver, + macprop->mp_name, macprop->mp_id, valsize, val); + } + return (err); +} + +int +mac_get_prop(mac_handle_t mh, mac_prop_t *macprop, void *val, uint_t valsize) +{ + int err = ENOTSUP; + mac_impl_t *mip = (mac_impl_t *)mh; + + if (mip->mi_callbacks->mc_callbacks & MC_GETPROP) { + err = mip->mi_callbacks->mc_getprop(mip->mi_driver, + macprop->mp_name, macprop->mp_id, valsize, val); + } + return (err); +} + +int +mac_maxsdu_update(mac_handle_t mh, uint_t sdu_max) +{ + mac_impl_t *mip = (mac_impl_t *)mh; + + if (sdu_max <= mip->mi_sdu_min) + return (EINVAL); + mip->mi_sdu_max = sdu_max; + + /* Send a MAC_NOTE_SDU_SIZE notification. */ + i_mac_notify(mip, MAC_NOTE_SDU_SIZE); + return (0); +} diff --git a/usr/src/uts/common/io/nge/nge_kstats.c b/usr/src/uts/common/io/nge/nge_kstats.c index 66350d6125..28069a836b 100644 --- a/usr/src/uts/common/io/nge/nge_kstats.c +++ b/usr/src/uts/common/io/nge/nge_kstats.c @@ -243,31 +243,6 @@ nge_setup_named_kstat(nge_t *ngep, int instance, char *name, return (ksp); } -/* - * Create kstats corresponding to NDD parameters - */ -static kstat_t * -nge_setup_params_kstat(nge_t *ngep, int instance, char *name, - int (*update)(kstat_t *, int)) -{ - kstat_t *ksp; - kstat_named_t *knp; - int i; - - ksp = kstat_create(NGE_DRIVER_NAME, instance, name, "net", - KSTAT_TYPE_NAMED, PARAM_COUNT, KSTAT_FLAG_PERSISTENT); - if (ksp != NULL) { - ksp->ks_private = ngep; - ksp->ks_update = update; - for (knp = ksp->ks_data, i = 0; i < PARAM_COUNT; ++knp, ++i) - kstat_named_init(knp, ngep->nd_params[i].ndp_name+1, - KSTAT_DATA_UINT64); - kstat_install(ksp); - } - - return (ksp); -} - void nge_init_kstats(nge_t *ngep, int instance) { diff --git a/usr/src/uts/common/io/strplumb.c b/usr/src/uts/common/io/strplumb.c index 6f20d98a5a..4eaf8e20ac 100644 --- a/usr/src/uts/common/io/strplumb.c +++ b/usr/src/uts/common/io/strplumb.c @@ -71,6 +71,7 @@ #include <sys/ddi_implfuncs.h> #include <sys/dld.h> +#include <sys/mac.h> /* * Debug Macros diff --git a/usr/src/uts/common/io/vnic/vnic_dev.c b/usr/src/uts/common/io/vnic/vnic_dev.c index 676bcc1e6f..7d98003a17 100644 --- a/usr/src/uts/common/io/vnic/vnic_dev.c +++ b/usr/src/uts/common/io/vnic/vnic_dev.c @@ -729,7 +729,6 @@ vnic_dev_create(datalink_id_t vnic_id, datalink_id_t linkid, int mac_len, mac_register_t *mac; int err; vnic_mac_t *vnic_mac; - const mac_info_t *lower_mac_info; mac_multi_addr_t maddr; mac_txinfo_t tx_info; @@ -796,9 +795,7 @@ vnic_dev_create(datalink_id_t vnic_id, datalink_id_t linkid, int mac_len, mac->m_src_addr = vnic->vn_addr; mac->m_callbacks = &vnic_m_callbacks; - lower_mac_info = mac_info(vnic_mac->va_mh); - mac->m_min_sdu = lower_mac_info->mi_sdu_min; - mac->m_max_sdu = lower_mac_info->mi_sdu_max; + mac_sdu_get(vnic_mac->va_mh, &mac->m_min_sdu, &mac->m_max_sdu); /* * As the current margin size of the underlying mac is used to diff --git a/usr/src/uts/common/sys/dld.h b/usr/src/uts/common/sys/dld.h index 8cc70e52f9..ad3530c1a3 100644 --- a/usr/src/uts/common/sys/dld.h +++ b/usr/src/uts/common/sys/dld.h @@ -34,11 +34,11 @@ #include <sys/types.h> #include <sys/stream.h> -#include <sys/mac.h> -#include <sys/dls.h> #include <sys/conf.h> #include <sys/sad.h> #include <net/if.h> +#include <sys/ddi.h> +#include <sys/sunddi.h> #ifdef __cplusplus extern "C" { @@ -94,6 +94,8 @@ extern "C" { #define DLDIOC_ATTR (DLDIOC | 0x03) +typedef uint32_t datalink_id_t; + typedef struct dld_ioc_attr { datalink_id_t dia_linkid; uint_t dia_max_sdu; @@ -109,6 +111,8 @@ typedef struct dld_ioc_vlan_attr { } dld_ioc_vlan_attr_t; #define DLDIOC_PHYS_ATTR (DLDIOC | 0x05) +#define DLPI_LINKNAME_MAX 32 + typedef struct dld_ioc_phys_attr { datalink_id_t dip_linkid; /* @@ -223,7 +227,63 @@ struct dlautopush { char dap_aplist[MAXAPUSH][FMNAMESZ+1]; }; +/* + * Encodings for public properties. + * A most significant bit value of 1 indicates private property, intended + * to allow private property implementations to use internal encodings + * if desired. + * + * Note that there are 2 sets of parameters: the *_EN_* + * values are those that the Administrator configures for autonegotiation. + * The _ADV_* values are those that are currently exposed over the wire. + */ +typedef enum { + DLD_PROP_DUPLEX = 0x00000001, + DLD_PROP_SPEED, + DLD_PROP_STATUS, + DLD_PROP_AUTONEG, + DLD_PROP_EN_AUTONEG, + DLD_PROP_DEFMTU, + DLD_PROP_NDD_LEGACY, + DLD_PROP_FLOWCTRL, + DLD_PROP_ADV_1000FDX_CAP, + DLD_PROP_EN_1000FDX_CAP, + DLD_PROP_ADV_1000HDX_CAP, + DLD_PROP_EN_1000HDX_CAP, + DLD_PROP_ADV_100FDX_CAP, + DLD_PROP_EN_100FDX_CAP, + DLD_PROP_ADV_100HDX_CAP, + DLD_PROP_EN_100HDX_CAP, + DLD_PROP_ADV_10FDX_CAP, + DLD_PROP_EN_10FDX_CAP, + DLD_PROP_ADV_10HDX_CAP, + DLD_PROP_EN_10HDX_CAP, + DLD_PROP_PRIVATE = -1 +} dld_prop_id_t; + +/* + * to figure out r/w status of legacy ndd props. + */ +#define DLD_NDD_READ 0x01 +#define DLD_NDD_WRITE 0x10 + +#define DLDIOCSETPROP (DLDIOC | 0x14) +#define DLDIOCGETPROP (DLDIOC | 0x15) +#define DLD_LINKPROP_NAME_MAX 256 +#define DLD_PROP_VERSION 1 + +typedef struct dld_ioc_prop_s { + int pr_version; + uint_t pr_flags; /* private to libdladm */ + char pr_linkname[DLPI_LINKNAME_MAX]; /* interface name */ + dld_prop_id_t pr_num; + char pr_name[DLD_LINKPROP_NAME_MAX]; + uint_t pr_valsize; /* sizeof pr_val */ + char pr_val[1]; +} dld_ioc_prop_t; + #ifdef _KERNEL +typedef dld_prop_id_t mac_prop_id_t; int dld_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); int dld_open(queue_t *, dev_t *, int, int, cred_t *); int dld_close(queue_t *); diff --git a/usr/src/uts/common/sys/mac.h b/usr/src/uts/common/sys/mac.h index 4fd83059c4..b83f5cb981 100644 --- a/usr/src/uts/common/sys/mac.h +++ b/usr/src/uts/common/sys/mac.h @@ -32,6 +32,7 @@ #include <sys/ddi.h> #include <sys/sunddi.h> #include <sys/stream.h> +#include <sys/dld.h> /* * MAC Services Module @@ -84,11 +85,17 @@ typedef enum { LINK_DUPLEX_FULL } link_duplex_t; -typedef uint32_t datalink_id_t; #define DATALINK_INVALID_LINKID 0 #define DATALINK_ALL_LINKID 0 #define DATALINK_MAX_LINKID 0xffffffff +typedef enum { + LINK_FLOWCTRL_NONE = 0, + LINK_FLOWCTRL_RX, + LINK_FLOWCTRL_TX, + LINK_FLOWCTRL_BI +} link_flowctrl_t; + /* * Maximum MAC address length */ @@ -177,8 +184,6 @@ enum mac_driver_stat { typedef struct mac_info_s { uint_t mi_media; uint_t mi_nativemedia; - uint_t mi_sdu_min; - uint_t mi_sdu_max; uint_t mi_addr_length; uint8_t *mi_unicst_addr; uint8_t *mi_brdcst_addr; @@ -292,6 +297,10 @@ typedef mblk_t *(*mac_tx_t)(void *, mblk_t *); typedef boolean_t (*mac_getcapab_t)(void *, mac_capab_t, void *); typedef int (*mac_open_t)(void *); typedef void (*mac_close_t)(void *); +typedef int (*mac_set_prop_t)(void *, const char *, mac_prop_id_t, + uint_t, const void *); +typedef int (*mac_get_prop_t)(void *, const char *, mac_prop_id_t, + uint_t, void *); /* * Drivers must set all of these callbacks except for mc_resources, @@ -315,6 +324,8 @@ typedef struct mac_callbacks_s { mac_getcapab_t mc_getcapab; /* Get capability information */ mac_open_t mc_open; /* Open the device */ mac_close_t mc_close; /* Close the device */ + mac_set_prop_t mc_setprop; + mac_get_prop_t mc_getprop; } mac_callbacks_t; /* @@ -328,6 +339,8 @@ typedef struct mac_callbacks_s { #define MC_GETCAPAB 0x004 #define MC_OPEN 0x008 #define MC_CLOSE 0x010 +#define MC_SETPROP 0x020 +#define MC_GETPROP 0x040 #define MAC_MAX_MINOR 1000 @@ -367,6 +380,7 @@ typedef enum { MAC_NOTE_RESOURCE, MAC_NOTE_DEVPROMISC, MAC_NOTE_FASTPATH_FLUSH, + MAC_NOTE_SDU_SIZE, MAC_NOTE_VNIC, MAC_NOTE_MARGIN, MAC_NNOTE /* must be the last entry */ @@ -534,6 +548,11 @@ typedef struct mactype_register_s { size_t mtr_statcount; } mactype_register_t; +typedef struct mac_prop_s { + mac_prop_id_t mp_id; + char *mp_name; +} mac_prop_t; + /* * Client interface functions. */ @@ -560,6 +579,7 @@ extern boolean_t mac_unicst_verify(mac_handle_t, extern int mac_unicst_set(mac_handle_t, const uint8_t *); extern void mac_unicst_get(mac_handle_t, uint8_t *); extern void mac_dest_get(mac_handle_t, uint8_t *); +extern void mac_sdu_get(mac_handle_t, uint_t *, uint_t *); extern void mac_resources(mac_handle_t); extern void mac_ioctl(mac_handle_t, queue_t *, mblk_t *); extern const mac_txinfo_t *mac_tx_get(mac_handle_t); @@ -626,6 +646,7 @@ extern void mac_tx_update(mac_handle_t); extern void mac_resource_update(mac_handle_t); extern mac_resource_handle_t mac_resource_add(mac_handle_t, mac_resource_t *); +extern int mac_maxsdu_update(mac_handle_t, uint_t); extern int mac_pdata_update(mac_handle_t, void *, size_t); extern void mac_multicst_refresh(mac_handle_t, @@ -650,6 +671,10 @@ extern mactype_register_t *mactype_alloc(uint_t); extern void mactype_free(mactype_register_t *); extern int mactype_register(mactype_register_t *); extern int mactype_unregister(const char *); +extern int mac_set_prop(mac_handle_t, mac_prop_t *, + void *, uint_t); +extern int mac_get_prop(mac_handle_t, mac_prop_t *, + void *, uint_t); #endif /* _KERNEL */ diff --git a/usr/src/uts/common/sys/mac_impl.h b/usr/src/uts/common/sys/mac_impl.h index c0acfc5c37..6e39232224 100644 --- a/usr/src/uts/common/sys/mac_impl.h +++ b/usr/src/uts/common/sys/mac_impl.h @@ -152,6 +152,8 @@ typedef struct mac_impl_s { uint_t mi_devpromisc; uint8_t mi_addr[MAXMACADDRLEN]; uint8_t mi_dstaddr[MAXMACADDRLEN]; + uint_t mi_sdu_min; + uint_t mi_sdu_max; mac_multicst_addr_t *mi_mmap; krwlock_t mi_notify_lock; diff --git a/usr/src/uts/common/xen/io/xnbo.c b/usr/src/uts/common/xen/io/xnbo.c index 91714e9117..833cf96576 100644 --- a/usr/src/uts/common/xen/io/xnbo.c +++ b/usr/src/uts/common/xen/io/xnbo.c @@ -245,6 +245,7 @@ xnbo_open_mac(xnb_t *xnbp, char *mac) const mac_info_t *mi; char *xsname; void (*rx_fn)(void *, mac_resource_handle_t, mblk_t *); + uint_t max_sdu; xsname = xvdi_get_xsname(xnbp->xnb_devinfo); @@ -271,9 +272,11 @@ xnbo_open_mac(xnb_t *xnbp, char *mac) xnbo_close_mac(xnbop); return (B_FALSE); } - if (mi->mi_sdu_max > XNBMAXPKT) { - cmn_err(CE_WARN, "xnbo_open_mac: " - "mac device SDU too big (%d)", mi->mi_sdu_max); + + mac_sdu_get(xnbop->o_mh, NULL, &max_sdu); + if (max_sdu > XNBMAXPKT) { + cmn_err(CE_WARN, "xnbo_open_mac: mac device SDU too big (%d)", + max_sdu); xnbo_close_mac(xnbop); return (B_FALSE); } diff --git a/usr/src/uts/intel/mac/Makefile b/usr/src/uts/intel/mac/Makefile index 8e34b910a9..12bd648ee0 100644 --- a/usr/src/uts/intel/mac/Makefile +++ b/usr/src/uts/intel/mac/Makefile @@ -2,9 +2,8 @@ # CDDL HEADER START # # The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -54,6 +53,7 @@ include $(UTSBASE)/intel/Makefile.intel ALL_TARGET = $(BINARY) LINT_TARGET = $(MODULE).lint INSTALL_TARGET = $(BINARY) $(ROOTMODULE) +LINTTAGS += -erroff=E_BAD_PTR_CAST_ALIGN # # Overrides. diff --git a/usr/src/uts/sparc/mac/Makefile b/usr/src/uts/sparc/mac/Makefile index ecf5b2cfa2..d343e0bc74 100644 --- a/usr/src/uts/sparc/mac/Makefile +++ b/usr/src/uts/sparc/mac/Makefile @@ -2,9 +2,8 @@ # CDDL HEADER START # # The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -55,6 +54,7 @@ include $(UTSBASE)/sparc/Makefile.sparc ALL_TARGET = $(BINARY) LINT_TARGET = $(MODULE).lint INSTALL_TARGET = $(BINARY) $(ROOTMODULE) +LINTTAGS += -erroff=E_BAD_PTR_CAST_ALIGN # # Overrides. diff --git a/usr/src/uts/sun/io/hme.c b/usr/src/uts/sun/io/hme.c index f57bcd697b..b5d91a728a 100644 --- a/usr/src/uts/sun/io/hme.c +++ b/usr/src/uts/sun/io/hme.c @@ -2341,7 +2341,7 @@ _info(struct modinfo *modinfop) * Allocate and zero-out "number" structures * each of type "structure" in kernel memory. */ -#define GETSTRUCT(structure, number) \ +#define HME_GETSTRUCT(structure, number) \ ((structure *)kmem_zalloc(\ (size_t)(sizeof (structure) * (number)), KM_SLEEP)) @@ -2763,7 +2763,7 @@ hmeattach(dev_info_t *dip, ddi_attach_cmd_t cmd) /* * Allocate soft device data structure */ - hmep = GETSTRUCT(struct hme, 1); + hmep = HME_GETSTRUCT(struct hme, 1); /* * Might as well set up elements of data structure |