diff options
author | yz147064 <none@none> | 2008-01-23 18:09:15 -0800 |
---|---|---|
committer | yz147064 <none@none> | 2008-01-23 18:09:15 -0800 |
commit | d62bc4badc1c1f1549c961cfb8b420e650e1272b (patch) | |
tree | 9f466859e9cfb73da13b64261432aba4683f19ad /usr/src/lib/libdladm | |
parent | d38257c4392a9dd690c2f7f2383236c1fc80e509 (diff) | |
download | illumos-joyent-d62bc4badc1c1f1549c961cfb8b420e650e1272b.tar.gz |
PSARC/2006/499 Clearview Nemo unification and vanity naming
PSARC/2007/527 Addendum for Clearview Vanity Naming and Nemo Unification
PSARC/2008/002 Clearview UV Updates
6310766 vlan statistics get reset at unplumb time
6320515 dladm commands with "-R" option should not take effect immediately
6433732 Simplify the GLDv3 control path by making its processing asynchronous
6445912 dladm show-link fails to show a specific link in the debug version
6452413 dladm show-link doesn't show VLAN links for GLDv2 drivers
6504433 libwladm's use of wladm_wlresult2status() needs an overhaul
6504507 dladm set-linkprop failure message is unclear
6534289 DR should work with aggregations
6535719 dladm_aggr_port_attr_db_t`lp_devname should be MAXNAMELEN, not MAXNAMELEN + 1
6539634 GLDv3 should DL_ERROR_ACK a DL_UDQOS_REQ with DL_OUTSTATE when the stream is DL_UNATTACHED
6540246 libdladm should not guess zoneid from DLDIOCZIDGET ioctl errno
6544195 dladm show-dev assumes GLDv3 stats.. incompatible with GLDv2
6563295 dladm show-linkprop -P does not work properly for unavailable links
6577618 integrate network vanity naming and nemo unification
6600446 links assigned to a local zone are still aggregatable by global zone
6607572 "boot net - install" can trigger assertion failure in dld_str_attach()
6613956 "svccfg import -" does not work as bfu expects
6637596 invalid assertion in ip_soft_ring_assignment()
6642350 kernel DLPI processing routines are long overdue
6643338 GLDv3 PPA hack VLAN ID checks don't always work
6647203 bfu: smf_delete_manifest() does not work for non-global zones
6649885 DL_IB GLDv3 mactype plugin must fill in its mtr_nativetype
6650395 libuuid should be lint-clean and linted nightly
--HG--
rename : usr/src/cmd/dladm/aggregation.conf => deleted_files/usr/src/cmd/dladm/aggregation.conf
rename : usr/src/cmd/dladm/linkprop.conf => deleted_files/usr/src/cmd/dladm/linkprop.conf
rename : usr/src/lib/libinetcfg/common/inetcfg_nic.c => deleted_files/usr/src/lib/libinetcfg/common/inetcfg_nic.c
rename : usr/src/lib/libinetcfg/common/inetcfg_nic.h => deleted_files/usr/src/lib/libinetcfg/common/inetcfg_nic.h
Diffstat (limited to 'usr/src/lib/libdladm')
22 files changed, 4712 insertions, 3505 deletions
diff --git a/usr/src/lib/libdladm/Makefile b/usr/src/lib/libdladm/Makefile index ceae6a3ad5..630a7e2e19 100644 --- a/usr/src/lib/libdladm/Makefile +++ b/usr/src/lib/libdladm/Makefile @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2007 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" @@ -28,7 +28,8 @@ include $(SRC)/lib/Makefile.lib HDRS = libdladm.h libdladm_impl.h libdllink.h libdlaggr.h \ - libdlwlan.h libdlwlan_impl.h libdlvnic.h + libdlwlan.h libdlwlan_impl.h libdlvnic.h libdlvlan.h \ + libdlmgmt.h HDRDIR = common SUBDIRS = $(MACH) @@ -37,7 +38,8 @@ $(BUILD64)SUBDIRS += $(MACH64) POFILE = libdladm.po MSGFILES = common/libdladm.c common/linkprop.c common/secobj.c \ common/libdllink.c common/libdlaggr.c \ - common/libdlwlan.c common/libdlvnic.c + common/libdlwlan.c common/libdlvnic.c \ + common/libdlvlan.c common/libdlmgmt.c XGETFLAGS = -a -x libdladm.xcl all := TARGET = all diff --git a/usr/src/lib/libdladm/Makefile.com b/usr/src/lib/libdladm/Makefile.com index cbb912d3ed..4caeb08465 100644 --- a/usr/src/lib/libdladm/Makefile.com +++ b/usr/src/lib/libdladm/Makefile.com @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2007 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" @@ -28,7 +28,7 @@ LIBRARY = libdladm.a VERS = .1 OBJECTS = libdladm.o secobj.o linkprop.o libdllink.o libdlaggr.o \ - libdlwlan.o libdlvnic.o + libdlwlan.o libdlvnic.o libdlmgmt.o libdlvlan.o include ../../Makefile.lib @@ -36,7 +36,7 @@ include ../../Makefile.lib include ../../Makefile.rootfs LIBS = $(DYNLIB) $(LINTLIB) -LDLIBS += -ldevinfo -ldlpi -lc -linetutil -lsocket -lscf +LDLIBS += -ldevinfo -lc -linetutil -lsocket -lscf -lrcm -lnvpair 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 ea440f76e3..58f15038bc 100644 --- a/usr/src/lib/libdladm/common/libdladm.c +++ b/usr/src/lib/libdladm/common/libdladm.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -28,13 +28,14 @@ #include <unistd.h> #include <stropts.h> #include <errno.h> +#include <ctype.h> #include <fcntl.h> #include <strings.h> #include <dirent.h> #include <sys/stat.h> -#include <libdladm.h> #include <libdladm_impl.h> #include <libintl.h> +#include <libdlpi.h> static char dladm_rootdir[MAXPATHLEN] = "/"; @@ -127,24 +128,23 @@ dladm_status2str(dladm_status_t status, char *buf) case DLADM_STATUS_KEYINVAL: s = "invalid key"; break; - case DLADM_STATUS_INVALIDID: - s = "invalid VNIC id"; - break; case DLADM_STATUS_INVALIDMACADDRLEN: s = "invalid MAC address length"; break; case DLADM_STATUS_INVALIDMACADDRTYPE: s = "invalid MAC address type"; break; - case DLADM_STATUS_AUTOIDNOTEMP: - s = "automatic VNIC ID assigment not supported with" - "persistant operations"; + case DLADM_STATUS_LINKBUSY: + s = "link busy"; + break; + case DLADM_STATUS_VIDINVAL: + s = "invalid VLAN identifier"; break; - case DLADM_STATUS_AUTOIDNOAVAILABLEID: - s = "no available VNIC ID for automatic assignment"; + case DLADM_STATUS_TRYAGAIN: + s = "try again later"; break; - case DLADM_STATUS_BUSY: - s = "device busy"; + case DLADM_STATUS_NONOTIF: + s = "link notification is not supported"; break; default: s = "<unknown error>"; @@ -175,12 +175,16 @@ dladm_errno2status(int err) return (DLADM_STATUS_NOMEM); case ENOTSUP: return (DLADM_STATUS_NOTSUP); + case ENETDOWN: + return (DLADM_STATUS_NONOTIF); case EACCES: return (DLADM_STATUS_DENIED); case EIO: return (DLADM_STATUS_IOERR); case EBUSY: - return (DLADM_STATUS_BUSY); + return (DLADM_STATUS_LINKBUSY); + case EAGAIN: + return (DLADM_STATUS_TRYAGAIN); default: return (DLADM_STATUS_FAILED); } @@ -190,15 +194,15 @@ dladm_errno2status(int err) * These are the uid and gid of the user 'dladm'. * The directory /etc/dladm and all files under it are owned by this user. */ -#define DLADM_DB_OWNER 15 -#define DLADM_DB_GROUP 3 -#define LOCK_DB_PERMS S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH +#define DLADM_DB_OWNER 15 +#define DLADM_DB_GROUP 3 +#define LOCK_DB_PERMS S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH static int i_dladm_lock_db(const char *lock_file, short type) { int lock_fd; - struct flock lock; + struct flock lock; if ((lock_fd = open(lock_file, O_RDWR | O_CREAT | O_TRUNC, LOCK_DB_PERMS)) < 0) @@ -238,6 +242,135 @@ i_dladm_unlock_db(const char *lock_file, int fd) (void) unlink(lock_file); } +/* + * Given a link class, returns its class string. + */ +const char * +dladm_class2str(datalink_class_t class, char *buf) +{ + const char *s; + + switch (class) { + case DATALINK_CLASS_PHYS: + s = "phys"; + break; + case DATALINK_CLASS_VLAN: + s = "vlan"; + break; + case DATALINK_CLASS_AGGR: + s = "aggr"; + break; + case DATALINK_CLASS_VNIC: + s = "vnic"; + break; + default: + s = "unknown"; + break; + } + + (void) snprintf(buf, DLADM_STRSIZE, "%s", s); + return (buf); +} + +/* + * Given a physical link media type, returns its media type string. + */ +const char * +dladm_media2str(uint32_t media, char *buf) +{ + const char *s; + + switch (media) { + case DL_ETHER: + s = "Ethernet"; + break; + case DL_WIFI: + s = "WiFi"; + break; + case DL_IB: + s = "Infiniband"; + break; + case DL_IPV4: + s = "IPv4Tunnel"; + break; + case DL_IPV6: + s = "IPv6Tunnel"; + break; + case DL_CSMACD: + s = "CSMA/CD"; + break; + case DL_TPB: + s = "TokenBus"; + break; + case DL_TPR: + s = "TokenRing"; + break; + case DL_METRO: + s = "MetroNet"; + break; + case DL_HDLC: + s = "HDLC"; + break; + case DL_CHAR: + s = "SyncCharacter"; + break; + case DL_CTCA: + s = "CTCA"; + break; + case DL_FDDI: + s = "FDDI"; + break; + case DL_FC: + s = "FiberChannel"; + break; + case DL_ATM: + s = "ATM"; + break; + case DL_IPATM: + s = "ATM(ClassicIP)"; + break; + case DL_X25: + s = "X.25"; + break; + case DL_IPX25: + s = "X.25(ClassicIP)"; + break; + case DL_ISDN: + s = "ISDN"; + break; + case DL_HIPPI: + s = "HIPPI"; + break; + case DL_100VG: + s = "100BaseVGEthernet"; + break; + case DL_100VGTPR: + s = "100BaseVGTokenRing"; + break; + case DL_ETH_CSMA: + s = "IEEE802.3"; + break; + case DL_100BT: + s = "100BaseT"; + break; + case DL_FRAME: + s = "FrameRelay"; + break; + case DL_MPFRAME: + s = "MPFrameRelay"; + break; + case DL_ASYNC: + s = "AsyncCharacter"; + break; + default: + s = "--"; + break; + } + + (void) snprintf(buf, DLADM_STRSIZE, "%s", s); + return (buf); +} + dladm_status_t i_dladm_rw_db(const char *db_file, mode_t db_perms, dladm_status_t (*process_db)(void *, FILE *, FILE *), @@ -350,3 +483,30 @@ dladm_set_rootdir(const char *rootdir) (void) closedir(dp); return (DLADM_STATUS_OK); } + +boolean_t +dladm_valid_linkname(const char *link) +{ + size_t len = strlen(link); + const char *cp; + + if (len + 1 >= MAXLINKNAMELEN) + return (B_FALSE); + + /* + * The link name cannot start with a digit and must end with a digit. + */ + if ((isdigit(link[0]) != 0) || (isdigit(link[len - 1]) == 0)) + return (B_FALSE); + + /* + * The legal characters in a link name are: + * alphanumeric (a-z, A-Z, 0-9), and the underscore ('_'). + */ + for (cp = link; *cp != '\0'; cp++) { + if ((isalnum(*cp) == 0) && (*cp != '_')) + return (B_FALSE); + } + + return (B_TRUE); +} diff --git a/usr/src/lib/libdladm/common/libdladm.h b/usr/src/lib/libdladm/common/libdladm.h index 8ed30b4ebf..a7077f5900 100644 --- a/usr/src/lib/libdladm/common/libdladm.h +++ b/usr/src/lib/libdladm/common/libdladm.h @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -28,6 +28,9 @@ #pragma ident "%Z%%M% %I% %E% SMI" +#include <sys/dls.h> +#include <sys/dlpi.h> + /* * This file includes structures, macros and common routines shared by all * data-link administration, and routines which do not directly administrate @@ -38,10 +41,36 @@ extern "C" { #endif +#define LINKID_STR_WIDTH 10 #define DLADM_STRSIZE 256 -#define DLADM_OPT_TEMP 0x00000001 -#define DLADM_OPT_CREATE 0x00000002 -#define DLADM_OPT_PERSIST 0x00000004 + +/* + * option flags taken by the libdladm functions + * + * - DLADM_OPT_ACTIVE: + * The function requests to bringup some configuration that only take + * effect on active system (not persistent). + * + * - DLADM_OPT_PERSIST: + * The function requests to persist some configuration. + * + * - DLADM_OPT_CREATE: + * Today, only used by dladm_set_secobj() - requests to create a secobj. + * + * - DLADM_OPT_FORCE: + * The function requests to execute a specific operation forcefully. + * + * - DLADM_OPT_PREFIX: + * The function requests to generate a link name using the specified prefix. + */ +#define DLADM_OPT_ACTIVE 0x00000001 +#define DLADM_OPT_PERSIST 0x00000002 +#define DLADM_OPT_CREATE 0x00000004 +#define DLADM_OPT_FORCE 0x00000008 +#define DLADM_OPT_PREFIX 0x00000010 + +#define DLADM_WALK_TERMINATE 0 +#define DLADM_WALK_CONTINUE -1 typedef enum { DLADM_STATUS_OK = 0, @@ -66,23 +95,28 @@ typedef enum { DLADM_STATUS_REPOSITORYINVAL, DLADM_STATUS_MACADDRINVAL, DLADM_STATUS_KEYINVAL, - DLADM_STATUS_INVALIDID, DLADM_STATUS_INVALIDMACADDRLEN, DLADM_STATUS_INVALIDMACADDRTYPE, - DLADM_STATUS_AUTOIDNOTEMP, - DLADM_STATUS_AUTOIDNOAVAILABLEID, - DLADM_STATUS_BUSY + DLADM_STATUS_LINKBUSY, + DLADM_STATUS_VIDINVAL, + DLADM_STATUS_NONOTIF, + DLADM_STATUS_TRYAGAIN } dladm_status_t; typedef enum { - DLADM_PROP_VAL_CURRENT = 1, - DLADM_PROP_VAL_DEFAULT, - DLADM_PROP_VAL_MODIFIABLE, - DLADM_PROP_VAL_PERSISTENT -} dladm_prop_type_t; + DLADM_TYPE_STR, + DLADM_TYPE_BOOLEAN, + DLADM_TYPE_UINT64 +} dladm_datatype_t; + +typedef int dladm_conf_t; +#define DLADM_INVALID_CONF 0 extern const char *dladm_status2str(dladm_status_t, char *); extern dladm_status_t dladm_set_rootdir(const char *); +extern const char *dladm_class2str(datalink_class_t, char *); +extern const char *dladm_media2str(uint32_t, char *); +extern boolean_t dladm_valid_linkname(const char *); #ifdef __cplusplus } diff --git a/usr/src/lib/libdladm/common/libdladm_impl.h b/usr/src/lib/libdladm/common/libdladm_impl.h index c949219a5b..f71495e5d9 100644 --- a/usr/src/lib/libdladm/common/libdladm_impl.h +++ b/usr/src/lib/libdladm/common/libdladm_impl.h @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -38,12 +38,41 @@ extern "C" { #define MAXLINELEN 1024 #define BUFLEN(lim, ptr) (((lim) > (ptr)) ? ((lim) - (ptr)) : 0) +typedef struct val_desc { + char *vd_name; + uintptr_t vd_val; +} val_desc_t; + +#define VALCNT(vals) (sizeof ((vals)) / sizeof (val_desc_t)) + extern int i_dladm_ioctl(int, int, void *, int); extern dladm_status_t dladm_errno2status(int); -extern dladm_status_t i_dladm_rw_db(const char *, mode_t, +extern dladm_status_t i_dladm_rw_db(const char *, mode_t, dladm_status_t (*)(void *, FILE *, FILE *), void *, boolean_t); +/* + * Link attributes persisted by dlmgmtd. + */ +/* + * Set for VLANs only + */ +#define FVLANID "vid" /* uint64_t */ +#define FLINKOVER "linkover" /* uint64_t */ + +/* + * Set for AGGRs only + */ +#define FKEY "key" /* uint64_t */ +#define FNPORTS "nports" /* uint64_t */ +#define FPORTS "portnames" /* string */ +#define FPOLICY "policy" /* uint64_t */ +#define FFIXMACADDR "fix_macaddr" /* boolean_t */ +#define FMACADDR "macaddr" /* string */ +#define FFORCE "force" /* boolean_t */ +#define FLACPMODE "lacp_mode" /* uint64_t */ +#define FLACPTIMER "lacp_timer" /* uint64_t */ + #ifdef __cplusplus } #endif diff --git a/usr/src/lib/libdladm/common/libdlaggr.c b/usr/src/lib/libdladm/common/libdlaggr.c index 0c622fc8a2..75291d0d1d 100644 --- a/usr/src/lib/libdladm/common/libdlaggr.c +++ b/usr/src/lib/libdladm/common/libdlaggr.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -34,10 +34,13 @@ #include <stropts.h> #include <stdlib.h> #include <errno.h> +#include <assert.h> #include <strings.h> #include <libintl.h> #include <net/if_types.h> #include <net/if_dl.h> +#include <libdllink.h> +#include <libdlvlan.h> #include <libdlaggr.h> #include <libdladm_impl.h> @@ -46,78 +49,39 @@ * * This library is used by administration tools such as dladm(1M) to * configure link aggregations. - * - * Link aggregation configuration information is saved in a text - * file of the following format: - * - * <db-file> ::= <groups>* - * <group> ::= <key> <sep> <policy> <sep> <nports> <sep> <ports> <sep> - * <mac> <sep> <lacp-mode> <sep> <lacp-timer> - * <sep> ::= ' ' | '\t' - * <key> ::= <number> - * <nports> ::= <number> - * <ports> ::= <port> <m-port>* - * <m-port> ::= ',' <port> - * <port> ::= <devname> - * <devname> ::= <string> - * <port-num> ::= <number> - * <policy> ::= <pol-level> <m-pol>* - * <m-pol> ::= ',' <pol-level> - * <pol-level> ::= 'L2' | 'L3' | 'L4' - * <mac> ::= 'auto' | <mac-addr> - * <mac-addr> ::= <hex> ':' <hex> ':' <hex> ':' <hex> ':' <hex> ':' <hex> - * <lacp-mode> ::= 'off' | 'active' | 'passive' - * <lacp-timer> ::= 'short' | 'long' */ -#define DLADM_AGGR_DEV "/devices/pseudo/aggr@0:" AGGR_DEVNAME_CTL -#define DLADM_AGGR_DB "/etc/dladm/aggregation.conf" -#define DLADM_AGGR_DB_TMP "/etc/dladm/aggregation.conf.new" -#define DLADM_AGGR_DB_LOCK "/tmp/aggregation.conf.lock" - -#define DLADM_AGGR_DB_PERMS S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH -#define DLADM_AGGR_DB_OWNER 15 /* "dladm" UID */ -#define DLADM_AGGR_DB_GROUP 3 /* "sys" GID */ - -/* - * The largest configurable aggregation key. Because by default the key is - * used as the DLPI device PPA and default VLAN PPA's are calculated as - * ((1000 * vid) + PPA), the largest key can't be > 999. - */ -#define DLADM_AGGR_MAX_KEY 999 - -#define BLANK_LINE(s) ((s[0] == '\0') || (s[0] == '#') || (s[0] == '\n')) +#define DLADM_AGGR_DEV "/devices/pseudo/aggr@0:" AGGR_DEVNAME_CTL /* Limits on buffer size for LAIOC_INFO request */ #define MIN_INFO_SIZE (4*1024) #define MAX_INFO_SIZE (128*1024) -#define MAXPATHLEN 1024 - static uchar_t zero_mac[] = {0, 0, 0, 0, 0, 0}; +#define VALID_PORT_MAC(mac) \ + (((mac) != NULL) && (bcmp(zero_mac, (mac), ETHERADDRL) != 0) && \ + (!(mac)[0] & 0x01)) -/* configuration database entry */ -typedef struct dladm_aggr_grp_attr_db { - uint32_t lt_key; - uint32_t lt_policy; - uint32_t lt_nports; - dladm_aggr_port_attr_db_t *lt_ports; - boolean_t lt_mac_fixed; - uchar_t lt_mac[ETHERADDRL]; - aggr_lacp_mode_t lt_lacp_mode; - aggr_lacp_timer_t lt_lacp_timer; -} dladm_aggr_grp_attr_db_t; - -typedef struct dladm_aggr_up { - uint32_t lu_key; - boolean_t lu_found; - int lu_fd; -} dladm_aggr_up_t; - -typedef struct dladm_aggr_down { - uint32_t ld_key; - boolean_t ld_found; -} dladm_aggr_down_t; +#define PORT_DELIMITER '.' + +#define WRITE_PORT(portstr, portid, size) { \ + char pstr[LINKID_STR_WIDTH + 2]; \ + (void) snprintf(pstr, LINKID_STR_WIDTH + 2, "%d%c", \ + (portid), PORT_DELIMITER); \ + (void) strlcat((portstr), pstr, (size)); \ +} + +#define READ_PORT(portstr, portid, status) { \ + errno = 0; \ + (status) = DLADM_STATUS_OK; \ + (portid) = (int)strtol((portstr), &(portstr), 10); \ + if (errno != 0 || *(portstr) != PORT_DELIMITER) { \ + (status) = DLADM_STATUS_REPOSITORYINVAL; \ + } else { \ + /* Skip the delimiter. */ \ + (portstr)++; \ + } \ +} typedef struct dladm_aggr_modify_attr { uint32_t ld_policy; @@ -175,106 +139,93 @@ static dladm_aggr_port_state_t port_states[] = { #define NPORT_STATES \ (sizeof (port_states) / sizeof (dladm_aggr_port_state_t)) -typedef struct delete_db_state { - uint32_t ds_key; - boolean_t ds_found; -} delete_db_state_t; +static int +i_dladm_aggr_strioctl(int cmd, void *ptr, int ilen) +{ + int err, fd; -typedef struct modify_db_state { - uint32_t us_key; - uint32_t us_mask; - dladm_aggr_modify_attr_t *us_attr_new; - dladm_aggr_modify_attr_t *us_attr_old; - boolean_t us_found; -} modify_db_state_t; + if ((fd = open(DLADM_AGGR_DEV, O_RDWR)) < 0) + return (-1); -typedef struct add_db_state { - dladm_aggr_grp_attr_db_t *as_attr; - boolean_t as_found; -} add_db_state_t; + err = i_dladm_ioctl(fd, cmd, ptr, ilen); + (void) close(fd); -static int i_dladm_aggr_fput_grp(FILE *, dladm_aggr_grp_attr_db_t *); + return (err); +} /* - * Open and lock the aggregation configuration file lock. The lock is - * acquired as a reader (F_RDLCK) or writer (F_WRLCK). + * Caller must free attr.lg_ports. The ptr pointer is advanced while convert + * the laioc_info_t to the dladm_aggr_grp_attr_t structure. */ static int -i_dladm_aggr_lock_db(short type) +i_dladm_aggr_iocp2grpattr(void **ptr, dladm_aggr_grp_attr_t *attrp) { - int lock_fd; - struct flock lock; - int errno_save; + laioc_info_group_t *grp; + laioc_info_port_t *port; + int i; + void *where = (*ptr); - if ((lock_fd = open(DLADM_AGGR_DB_LOCK, O_RDWR | O_CREAT | O_TRUNC, - DLADM_AGGR_DB_PERMS)) < 0) - return (-1); + grp = (laioc_info_group_t *)where; - lock.l_type = type; - lock.l_whence = SEEK_SET; - lock.l_start = 0; - lock.l_len = 0; + attrp->lg_linkid = grp->lg_linkid; + attrp->lg_key = grp->lg_key; + attrp->lg_nports = grp->lg_nports; + attrp->lg_policy = grp->lg_policy; + attrp->lg_lacp_mode = grp->lg_lacp_mode; + attrp->lg_lacp_timer = grp->lg_lacp_timer; + attrp->lg_force = grp->lg_force; - if (fcntl(lock_fd, F_SETLKW, &lock) < 0) { - errno_save = errno; - (void) close(lock_fd); - (void) unlink(DLADM_AGGR_DB_LOCK); - errno = errno_save; - return (-1); + bcopy(grp->lg_mac, attrp->lg_mac, ETHERADDRL); + attrp->lg_mac_fixed = grp->lg_mac_fixed; + + if ((attrp->lg_ports = malloc(grp->lg_nports * + sizeof (dladm_aggr_port_attr_t))) == NULL) { + errno = ENOMEM; + goto fail; } - return (lock_fd); -} -/* - * Unlock and close the specified file. - */ -static void -i_dladm_aggr_unlock_db(int fd) -{ - struct flock lock; + where = (grp + 1); - if (fd < 0) - return; + /* + * Go through each port that is part of the group. + */ + for (i = 0; i < grp->lg_nports; i++) { + port = (laioc_info_port_t *)where; - lock.l_type = F_UNLCK; - lock.l_whence = SEEK_SET; - lock.l_start = 0; - lock.l_len = 0; + attrp->lg_ports[i].lp_linkid = port->lp_linkid; + bcopy(port->lp_mac, attrp->lg_ports[i].lp_mac, ETHERADDRL); + attrp->lg_ports[i].lp_state = port->lp_state; + attrp->lg_ports[i].lp_lacp_state = port->lp_lacp_state; - (void) fcntl(fd, F_SETLKW, &lock); - (void) close(fd); - (void) unlink(DLADM_AGGR_DB_LOCK); + where = (port + 1); + } + *ptr = where; + return (0); +fail: + return (-1); } /* - * Walk through the groups defined on the system and for each group <grp>, - * invoke <fn>(<arg>, <grp>); - * Terminate the walk if at any time <fn> returns non-NULL value + * Get active configuration of a specific aggregation. + * Caller must free attrp->la_ports. */ -int -dladm_aggr_walk(int (*fn)(void *, dladm_aggr_grp_attr_t *), void *arg) +static dladm_status_t +i_dladm_aggr_info_active(datalink_id_t linkid, dladm_aggr_grp_attr_t *attrp) { laioc_info_t *ioc; - laioc_info_group_t *grp; - laioc_info_port_t *port; - dladm_aggr_grp_attr_t attr; - int rc, i, j, bufsize, fd; - char *where; - - if ((fd = open(DLADM_AGGR_DEV, O_RDWR)) == -1) - return (-1); + int rc, bufsize; + void *where; + dladm_status_t status = DLADM_STATUS_OK; bufsize = MIN_INFO_SIZE; ioc = (laioc_info_t *)calloc(1, bufsize); - if (ioc == NULL) { - (void) close(fd); - errno = ENOMEM; - return (-1); - } + if (ioc == NULL) + return (DLADM_STATUS_NOMEM); -tryagain: - rc = i_dladm_ioctl(fd, LAIOC_INFO, ioc, bufsize); + ioc->li_group_linkid = linkid; +tryagain: + rc = i_dladm_aggr_strioctl(LAIOC_INFO, ioc, bufsize); if (rc != 0) { if (errno == ENOSPC) { /* @@ -290,6 +241,7 @@ tryagain: } } } + status = dladm_errno2status(errno); goto bail; } @@ -297,257 +249,329 @@ tryagain: * Go through each group returned by the aggregation driver. */ where = (char *)(ioc + 1); - for (i = 0; i < ioc->li_ngroups; i++) { - /* LINTED E_BAD_PTR_CAST_ALIGN */ - grp = (laioc_info_group_t *)where; - - attr.lg_key = grp->lg_key; - attr.lg_nports = grp->lg_nports; - attr.lg_policy = grp->lg_policy; - attr.lg_lacp_mode = grp->lg_lacp_mode; - attr.lg_lacp_timer = grp->lg_lacp_timer; - - bcopy(grp->lg_mac, attr.lg_mac, ETHERADDRL); - attr.lg_mac_fixed = grp->lg_mac_fixed; - - attr.lg_ports = malloc(grp->lg_nports * - sizeof (dladm_aggr_port_attr_t)); - if (attr.lg_ports == NULL) { - errno = ENOMEM; - goto bail; - } - - where = (char *)(grp + 1); - - /* - * Go through each port that is part of the group. - */ - for (j = 0; j < grp->lg_nports; j++) { - /* LINTED E_BAD_PTR_CAST_ALIGN */ - port = (laioc_info_port_t *)where; - - bcopy(port->lp_devname, attr.lg_ports[j].lp_devname, - MAXNAMELEN + 1); - bcopy(port->lp_mac, attr.lg_ports[j].lp_mac, - ETHERADDRL); - attr.lg_ports[j].lp_state = port->lp_state; - attr.lg_ports[j].lp_lacp_state = port->lp_lacp_state; - - where = (char *)(port + 1); - } - - rc = fn(arg, &attr); - free(attr.lg_ports); - if (rc != 0) - goto bail; + if (i_dladm_aggr_iocp2grpattr(&where, attrp) != 0) { + status = dladm_errno2status(errno); + goto bail; } bail: free(ioc); - (void) close(fd); - return (rc); + return (status); } /* - * Parse one line of the link aggregation DB, and return the corresponding - * group. Memory for the ports associated with the aggregation may be - * allocated. It is the responsibility of the caller to free the lt_ports - * aggregation group attribute. - * - * Returns -1 on parsing failure, or 0 on success. + * Get configuration information of a specific aggregation. + * Caller must free attrp->la_ports. */ -static int -i_dladm_aggr_parse_db(char *line, dladm_aggr_grp_attr_db_t *attr) +static dladm_status_t +i_dladm_aggr_info_persist(datalink_id_t linkid, dladm_aggr_grp_attr_t *attrp) { - char *token; - int i; - int value; - char *endp = NULL; - char *lasts = NULL; - - bzero(attr, sizeof (*attr)); + dladm_conf_t conf; + uint32_t nports, i; + char *portstr, *next; + dladm_status_t status; + uint64_t u64; + int size; + char macstr[ETHERADDRL * 3]; - /* key */ - if ((token = strtok_r(line, " \t", &lasts)) == NULL) - goto failed; + attrp->lg_linkid = linkid; + if ((status = dladm_read_conf(linkid, &conf)) != DLADM_STATUS_OK) + return (status); - errno = 0; - value = (int)strtol(token, &endp, 10); - if (errno != 0 || *endp != '\0') - goto failed; + status = dladm_get_conf_field(conf, FKEY, &u64, sizeof (u64)); + if (status != DLADM_STATUS_OK) + goto done; + attrp->lg_key = (uint16_t)u64; - attr->lt_key = value; + status = dladm_get_conf_field(conf, FPOLICY, &u64, sizeof (u64)); + if (status != DLADM_STATUS_OK) + goto done; + attrp->lg_policy = (uint32_t)u64; - /* policy */ - if ((token = strtok_r(NULL, " \t", &lasts)) == NULL || - !dladm_aggr_str2policy(token, &attr->lt_policy)) - goto failed; + status = dladm_get_conf_field(conf, FFIXMACADDR, &attrp->lg_mac_fixed, + sizeof (boolean_t)); + if (status != DLADM_STATUS_OK) + goto done; - /* number of ports */ - if ((token = strtok_r(NULL, " \t", &lasts)) == NULL) - return (-1); + if (attrp->lg_mac_fixed) { + boolean_t fixed; - errno = 0; - value = (int)strtol(token, &endp, 10); - if (errno != 0 || *endp != '\0') - goto failed; + if ((status = dladm_get_conf_field(conf, FMACADDR, macstr, + sizeof (macstr))) != DLADM_STATUS_OK) { + goto done; + } + if (!dladm_aggr_str2macaddr(macstr, &fixed, attrp->lg_mac)) { + status = DLADM_STATUS_REPOSITORYINVAL; + goto done; + } + } - attr->lt_nports = value; + status = dladm_get_conf_field(conf, FFORCE, &attrp->lg_force, + sizeof (boolean_t)); + if (status != DLADM_STATUS_OK) + goto done; - /* ports */ - if ((attr->lt_ports = malloc(attr->lt_nports * - sizeof (dladm_aggr_port_attr_db_t))) == NULL) - goto failed; + status = dladm_get_conf_field(conf, FLACPMODE, &u64, sizeof (u64)); + if (status != DLADM_STATUS_OK) + goto done; + attrp->lg_lacp_mode = (aggr_lacp_mode_t)u64; - for (i = 0; i < attr->lt_nports; i++) { - char *where, *devname; + status = dladm_get_conf_field(conf, FLACPTIMER, &u64, sizeof (u64)); + if (status != DLADM_STATUS_OK) + goto done; + attrp->lg_lacp_timer = (aggr_lacp_timer_t)u64; - /* port */ - if ((token = strtok_r(NULL, ", \t\n", &lasts)) == NULL) - goto failed; + status = dladm_get_conf_field(conf, FNPORTS, &u64, sizeof (u64)); + if (status != DLADM_STATUS_OK) + goto done; + nports = (uint32_t)u64; + attrp->lg_nports = nports; - /* - * device name: In a previous version of this file, a port - * number could be specified using <devname>/<portnum>. - * This syntax is unecessary and obsolete. - */ - if ((devname = strtok_r(token, "/", &where)) == NULL) - goto failed; - if (strlcpy(attr->lt_ports[i].lp_devname, devname, - MAXNAMELEN) >= MAXNAMELEN) - goto failed; + size = nports * (LINKID_STR_WIDTH + 1) + 1; + if ((portstr = calloc(1, size)) == NULL) { + status = DLADM_STATUS_NOMEM; + goto done; } - /* unicast MAC address */ - if ((token = strtok_r(NULL, " \t\n", &lasts)) == NULL || - !dladm_aggr_str2macaddr(token, &attr->lt_mac_fixed, - attr->lt_mac)) - goto failed; + status = dladm_get_conf_field(conf, FPORTS, portstr, size); + if (status != DLADM_STATUS_OK) { + free(portstr); + goto done; + } - /* LACP mode */ - if ((token = strtok_r(NULL, " \t\n", &lasts)) == NULL || - !dladm_aggr_str2lacpmode(token, &attr->lt_lacp_mode)) - attr->lt_lacp_mode = AGGR_LACP_OFF; + if ((attrp->lg_ports = malloc(nports * + sizeof (dladm_aggr_port_attr_t))) == NULL) { + free(portstr); + status = DLADM_STATUS_NOMEM; + goto done; + } - /* LACP timer */ - if ((token = strtok_r(NULL, " \t\n", &lasts)) == NULL || - !dladm_aggr_str2lacptimer(token, &attr->lt_lacp_timer)) - attr->lt_lacp_timer = AGGR_LACP_TIMER_SHORT; + for (next = portstr, i = 0; i < nports; i++) { + READ_PORT(next, attrp->lg_ports[i].lp_linkid, status); + if (status != DLADM_STATUS_OK) { + free(portstr); + free(attrp->lg_ports); + goto done; + } + } + free(portstr); - return (0); +done: + dladm_destroy_conf(conf); + return (status); +} -failed: - free(attr->lt_ports); - attr->lt_ports = NULL; - return (-1); +dladm_status_t +dladm_aggr_info(datalink_id_t linkid, dladm_aggr_grp_attr_t *attrp, + uint32_t flags) +{ + assert(flags == DLADM_OPT_ACTIVE || flags == DLADM_OPT_PERSIST); + if (flags == DLADM_OPT_ACTIVE) + return (i_dladm_aggr_info_active(linkid, attrp)); + else + return (i_dladm_aggr_info_persist(linkid, attrp)); } /* - * Walk through the groups defined in the DB and for each group <grp>, - * invoke <fn>(<arg>, <grp>); + * Add or remove one or more ports to/from an existing link aggregation. */ static dladm_status_t -i_dladm_aggr_walk_db(dladm_status_t (*fn)(void *, dladm_aggr_grp_attr_db_t *), - void *arg, const char *root) +i_dladm_aggr_add_rmv(datalink_id_t linkid, uint32_t nports, + dladm_aggr_port_attr_db_t *ports, uint32_t flags, int cmd) { - FILE *fp; - char line[MAXLINELEN]; - dladm_aggr_grp_attr_db_t attr; - char *db_file; - char db_file_buf[MAXPATHLEN]; - int lock_fd; + char *orig_portstr = NULL, *portstr = NULL; + laioc_add_rem_t *iocp; + laioc_port_t *ioc_ports; + uint32_t orig_nports, result_nports, len, i, j; + dladm_conf_t conf; + datalink_class_t class; dladm_status_t status = DLADM_STATUS_OK; + int size; + uint64_t u64; + uint32_t media; - if (root == NULL) { - db_file = DLADM_AGGR_DB; - } else { - (void) snprintf(db_file_buf, MAXPATHLEN, "%s%s", root, - DLADM_AGGR_DB); - db_file = db_file_buf; - } - - lock_fd = i_dladm_aggr_lock_db(F_RDLCK); + if (nports == 0) + return (DLADM_STATUS_BADARG); - if ((fp = fopen(db_file, "r")) == NULL) { - status = dladm_errno2status(errno); - i_dladm_aggr_unlock_db(lock_fd); - return (status); + /* + * Sanity check - aggregations can only be created over Ethernet + * physical links. + */ + for (i = 0; i < nports; i++) { + if ((dladm_datalink_id2info(ports[i].lp_linkid, NULL, + &class, &media, NULL, 0) != DLADM_STATUS_OK) || + (class != DATALINK_CLASS_PHYS) || (media != DL_ETHER)) { + return (DLADM_STATUS_BADARG); + } } - bzero(&attr, sizeof (attr)); + /* + * First, update the persistent configuration if requested. We only + * need to update the FPORTS and FNPORTS fields of this aggregation. + * Note that FPORTS is a list of port linkids separated by + * PORT_DELIMITER ('.'). + */ + if (flags & DLADM_OPT_PERSIST) { + status = dladm_read_conf(linkid, &conf); + if (status != DLADM_STATUS_OK) + return (status); - while (fgets(line, MAXLINELEN, fp) != NULL) { - /* skip comments */ - if (BLANK_LINE(line)) - continue; + /* + * Get the original configuration of FNPORTS and FPORTS. + */ + status = dladm_get_conf_field(conf, FNPORTS, &u64, + sizeof (u64)); + if (status != DLADM_STATUS_OK) + goto destroyconf; + orig_nports = (uint32_t)u64; - if (i_dladm_aggr_parse_db(line, &attr) != 0) { - status = DLADM_STATUS_REPOSITORYINVAL; - goto done; + /* + * At least one port needs to be in the aggregation. + */ + if ((cmd == LAIOC_REMOVE) && (orig_nports <= nports)) { + status = DLADM_STATUS_BADARG; + goto destroyconf; } - if ((status = fn(arg, &attr)) != DLADM_STATUS_OK) - goto done; + size = orig_nports * (LINKID_STR_WIDTH + 1) + 1; + if ((orig_portstr = calloc(1, size)) == NULL) { + status = dladm_errno2status(errno); + goto destroyconf; + } - free(attr.lt_ports); - attr.lt_ports = NULL; - } + status = dladm_get_conf_field(conf, FPORTS, orig_portstr, size); + if (status != DLADM_STATUS_OK) + goto destroyconf; -done: - free(attr.lt_ports); - (void) fclose(fp); - i_dladm_aggr_unlock_db(lock_fd); - return (status); -} + result_nports = (cmd == LAIOC_ADD) ? orig_nports + nports : + orig_nports; -/* - * Send an add or remove command to the link aggregation driver. - */ -static dladm_status_t -i_dladm_aggr_add_rem_sys(dladm_aggr_grp_attr_db_t *attr, int cmd) -{ - int i, rc, fd, len; - laioc_add_rem_t *iocp; - laioc_port_t *ports; - dladm_status_t status = DLADM_STATUS_OK; + size = result_nports * (LINKID_STR_WIDTH + 1) + 1; + if ((portstr = calloc(1, size)) == NULL) { + status = dladm_errno2status(errno); + goto destroyconf; + } - len = sizeof (*iocp) + attr->lt_nports * sizeof (laioc_port_t); - iocp = malloc(len); - if (iocp == NULL) { - status = DLADM_STATUS_NOMEM; - goto done; - } + /* + * get the new configuration and set to result_nports and + * portstr. + */ + if (cmd == LAIOC_ADD) { + (void) strlcpy(portstr, orig_portstr, size); + for (i = 0; i < nports; i++) + WRITE_PORT(portstr, ports[i].lp_linkid, size); + } else { + char *next; + datalink_id_t portid; + uint32_t remove = 0; + + for (next = orig_portstr, j = 0; j < orig_nports; j++) { + /* + * Read the portids from the old configuration + * one by one. + */ + READ_PORT(next, portid, status); + if (status != DLADM_STATUS_OK) { + free(portstr); + goto destroyconf; + } + + /* + * See whether this port is in the removal + * list. If not, copy to the new config. + */ + for (i = 0; i < nports; i++) { + if (ports[i].lp_linkid == portid) + break; + } + if (i == nports) { + WRITE_PORT(portstr, portid, size); + } else { + remove++; + } + } + if (remove != nports) { + status = DLADM_STATUS_LINKINVAL; + free(portstr); + goto destroyconf; + } + result_nports -= nports; + } + + u64 = result_nports; + if ((status = dladm_set_conf_field(conf, FNPORTS, + DLADM_TYPE_UINT64, &u64)) != DLADM_STATUS_OK) { + free(portstr); + goto destroyconf; + } - iocp->la_key = attr->lt_key; - iocp->la_nports = attr->lt_nports; - ports = (laioc_port_t *)(iocp + 1); + status = dladm_set_conf_field(conf, FPORTS, DLADM_TYPE_STR, + portstr); + free(portstr); + if (status != DLADM_STATUS_OK) + goto destroyconf; - for (i = 0; i < attr->lt_nports; i++) { - if (strlcpy(ports[i].lp_devname, - attr->lt_ports[i].lp_devname, - MAXNAMELEN) >= MAXNAMELEN) { - status = DLADM_STATUS_BADARG; - goto done; + /* + * Write the new configuration to the persistent repository. + */ + status = dladm_write_conf(conf); + +destroyconf: + dladm_destroy_conf(conf); + if (status != DLADM_STATUS_OK) { + free(orig_portstr); + return (status); } } - if ((fd = open(DLADM_AGGR_DEV, O_RDWR)) < 0) { - status = dladm_errno2status(errno); + /* + * If the caller only requested to update the persistent + * configuration, we are done. + */ + if (!(flags & DLADM_OPT_ACTIVE)) goto done; - } - rc = i_dladm_ioctl(fd, cmd, iocp, len); - if (rc < 0) { - if (errno == EINVAL) - status = DLADM_STATUS_LINKINVAL; - else - status = dladm_errno2status(errno); + /* + * Update the active configuration. + */ + len = sizeof (*iocp) + nports * sizeof (laioc_port_t); + if ((iocp = malloc(len)) == NULL) { + status = DLADM_STATUS_NOMEM; + goto done; } - (void) close(fd); + iocp->la_linkid = linkid; + iocp->la_nports = nports; + if (cmd == LAIOC_ADD) + iocp->la_force = (flags & DLADM_OPT_FORCE); + + ioc_ports = (laioc_port_t *)(iocp + 1); + for (i = 0; i < nports; i++) + ioc_ports[i].lp_linkid = ports[i].lp_linkid; + + if (i_dladm_aggr_strioctl(cmd, iocp, len) < 0) + status = dladm_errno2status(errno); done: free(iocp); + + /* + * If the active configuration update fails, restore the old + * persistent configuration if we've changed that. + */ + if ((status != DLADM_STATUS_OK) && (flags & DLADM_OPT_PERSIST)) { + if (dladm_read_conf(linkid, &conf) == DLADM_STATUS_OK) { + u64 = orig_nports; + if ((dladm_set_conf_field(conf, FNPORTS, + DLADM_TYPE_UINT64, &u64) == DLADM_STATUS_OK) && + (dladm_set_conf_field(conf, FPORTS, DLADM_TYPE_STR, + orig_portstr) == DLADM_STATUS_OK)) { + (void) dladm_write_conf(conf); + } + (void) dladm_destroy_conf(conf); + } + } + free(orig_portstr); return (status); } @@ -555,14 +579,12 @@ done: * Send a modify command to the link aggregation driver. */ static dladm_status_t -i_dladm_aggr_modify_sys(uint32_t key, uint32_t mask, +i_dladm_aggr_modify_sys(datalink_id_t linkid, uint32_t mask, dladm_aggr_modify_attr_t *attr) { - int rc, fd; laioc_modify_t ioc; - dladm_status_t status = DLADM_STATUS_OK; - ioc.lu_key = key; + ioc.lu_linkid = linkid; ioc.lu_modify_mask = 0; if (mask & DLADM_AGGR_MODIFY_POLICY) @@ -580,68 +602,60 @@ i_dladm_aggr_modify_sys(uint32_t key, uint32_t mask, ioc.lu_lacp_mode = attr->ld_lacp_mode; ioc.lu_lacp_timer = attr->ld_lacp_timer; - if ((fd = open(DLADM_AGGR_DEV, O_RDWR)) < 0) - return (dladm_errno2status(errno)); - - rc = i_dladm_ioctl(fd, LAIOC_MODIFY, &ioc, sizeof (ioc)); - if (rc < 0) { + if (i_dladm_aggr_strioctl(LAIOC_MODIFY, &ioc, sizeof (ioc)) < 0) { if (errno == EINVAL) - status = DLADM_STATUS_MACADDRINVAL; + return (DLADM_STATUS_MACADDRINVAL); else - status = dladm_errno2status(errno); + return (dladm_errno2status(errno)); + } else { + return (DLADM_STATUS_OK); } - - (void) close(fd); - return (status); } /* * Send a create command to the link aggregation driver. */ static dladm_status_t -i_dladm_aggr_create_sys(int fd, dladm_aggr_grp_attr_db_t *attr) +i_dladm_aggr_create_sys(datalink_id_t linkid, uint16_t key, uint32_t nports, + dladm_aggr_port_attr_db_t *ports, uint32_t policy, + boolean_t mac_addr_fixed, const uchar_t *mac_addr, + aggr_lacp_mode_t lacp_mode, aggr_lacp_timer_t lacp_timer, boolean_t force) { int i, rc, len; - laioc_create_t *iocp; - laioc_port_t *ports; + laioc_create_t *iocp = NULL; + laioc_port_t *ioc_ports; dladm_status_t status = DLADM_STATUS_OK; - len = sizeof (*iocp) + attr->lt_nports * sizeof (laioc_port_t); + len = sizeof (*iocp) + nports * sizeof (laioc_port_t); iocp = malloc(len); if (iocp == NULL) return (DLADM_STATUS_NOMEM); - iocp->lc_key = attr->lt_key; - iocp->lc_nports = attr->lt_nports; - iocp->lc_policy = attr->lt_policy; - iocp->lc_lacp_mode = attr->lt_lacp_mode; - iocp->lc_lacp_timer = attr->lt_lacp_timer; - - ports = (laioc_port_t *)(iocp + 1); + iocp->lc_key = key; + iocp->lc_linkid = linkid; + iocp->lc_nports = nports; + iocp->lc_policy = policy; + iocp->lc_lacp_mode = lacp_mode; + iocp->lc_lacp_timer = lacp_timer; + ioc_ports = (laioc_port_t *)(iocp + 1); + iocp->lc_force = force; - for (i = 0; i < attr->lt_nports; i++) { - if (strlcpy(ports[i].lp_devname, - attr->lt_ports[i].lp_devname, - MAXNAMELEN) >= MAXNAMELEN) { - free(iocp); - return (DLADM_STATUS_BADARG); - } - } + for (i = 0; i < nports; i++) + ioc_ports[i].lp_linkid = ports[i].lp_linkid; - if (attr->lt_mac_fixed && - ((bcmp(zero_mac, attr->lt_mac, ETHERADDRL) == 0) || - (attr->lt_mac[0] & 0x01))) { - free(iocp); - return (DLADM_STATUS_MACADDRINVAL); + if (mac_addr_fixed && !VALID_PORT_MAC(mac_addr)) { + status = DLADM_STATUS_MACADDRINVAL; + goto done; } - bcopy(attr->lt_mac, iocp->lc_mac, ETHERADDRL); - iocp->lc_mac_fixed = attr->lt_mac_fixed; + bcopy(mac_addr, iocp->lc_mac, ETHERADDRL); + iocp->lc_mac_fixed = mac_addr_fixed; - rc = i_dladm_ioctl(fd, LAIOC_CREATE, iocp, len); + rc = i_dladm_aggr_strioctl(LAIOC_CREATE, iocp, len); if (rc < 0) - status = DLADM_STATUS_LINKINVAL; + status = dladm_errno2status(errno); +done: free(iocp); return (status); } @@ -649,518 +663,109 @@ i_dladm_aggr_create_sys(int fd, dladm_aggr_grp_attr_db_t *attr) /* * Invoked to bring up a link aggregation group. */ -static dladm_status_t -i_dladm_aggr_up(void *arg, dladm_aggr_grp_attr_db_t *attr) -{ - dladm_aggr_up_t *up = (dladm_aggr_up_t *)arg; - dladm_status_t status; - - if (up->lu_key != 0 && up->lu_key != attr->lt_key) - return (DLADM_STATUS_OK); - - up->lu_found = B_TRUE; - - status = i_dladm_aggr_create_sys(up->lu_fd, attr); - if (status != DLADM_STATUS_OK && up->lu_key != 0) - return (status); - - return (DLADM_STATUS_OK); -} - -/* - * Bring up a link aggregation group or all of them if the key is zero. - * If key is 0, walk may terminate early if any of the links fail - */ -dladm_status_t -dladm_aggr_up(uint32_t key, const char *root) +static int +i_dladm_aggr_up(datalink_id_t linkid, void *arg) { - dladm_aggr_up_t up; + dladm_status_t *statusp = (dladm_status_t *)arg; + dladm_aggr_grp_attr_t attr; + dladm_aggr_port_attr_db_t *ports = NULL; + uint16_t key = 0; + int i, j; dladm_status_t status; - if ((up.lu_fd = open(DLADM_AGGR_DEV, O_RDWR)) < 0) - return (dladm_errno2status(errno)); - - up.lu_key = key; - up.lu_found = B_FALSE; - - status = i_dladm_aggr_walk_db(i_dladm_aggr_up, &up, root); + status = dladm_aggr_info(linkid, &attr, DLADM_OPT_PERSIST); if (status != DLADM_STATUS_OK) { - (void) close(up.lu_fd); - return (status); + *statusp = status; + return (DLADM_WALK_CONTINUE); } - (void) close(up.lu_fd); - - /* - * only return error if user specified key and key was - * not found - */ - if (!up.lu_found && key != 0) - return (DLADM_STATUS_NOTFOUND); - - return (DLADM_STATUS_OK); -} -/* - * Send a delete command to the link aggregation driver. - */ -static int -i_dladm_aggr_delete_sys(int fd, dladm_aggr_grp_attr_t *attr) -{ - laioc_delete_t ioc; - - ioc.ld_key = attr->lg_key; - - return (i_dladm_ioctl(fd, LAIOC_DELETE, &ioc, sizeof (ioc))); -} - -/* - * Invoked to bring down a link aggregation group. - */ -static int -i_dladm_aggr_down(void *arg, dladm_aggr_grp_attr_t *attr) -{ - dladm_aggr_down_t *down = (dladm_aggr_down_t *)arg; - int fd, errno_save; - - if (down->ld_key != 0 && down->ld_key != attr->lg_key) - return (0); - down->ld_found = B_TRUE; - - if ((fd = open(DLADM_AGGR_DEV, O_RDWR)) < 0) - return (-1); + if (attr.lg_key <= AGGR_MAX_KEY) + key = attr.lg_key; - if (i_dladm_aggr_delete_sys(fd, attr) < 0 && down->ld_key != 0) { - errno_save = errno; - (void) close(fd); - errno = errno_save; - return (-1); + ports = malloc(attr.lg_nports * sizeof (dladm_aggr_port_attr_db_t)); + if (ports == NULL) { + status = DLADM_STATUS_NOMEM; + goto done; } - (void) close(fd); - return (0); -} - -/* - * Bring down a link aggregation group or all of them if the key is zero. - * If key is 0, walk may terminate early if any of the links fail - */ -dladm_status_t -dladm_aggr_down(uint32_t key) -{ - dladm_aggr_down_t down; - - down.ld_key = key; - down.ld_found = B_FALSE; - - if (dladm_aggr_walk(i_dladm_aggr_down, &down) < 0) - return (dladm_errno2status(errno)); - /* - * only return error if user specified key and key was - * not found + * Validate (and purge) each physical link associated with this + * aggregation, if the specific hardware has been removed during + * the system shutdown. */ - if (!down.ld_found && key != 0) - return (DLADM_STATUS_NOTFOUND); + for (i = 0, j = 0; i < attr.lg_nports; i++) { + datalink_id_t portid = attr.lg_ports[i].lp_linkid; + uint32_t flags; + dladm_status_t s; - return (DLADM_STATUS_OK); -} - -/* - * For each group <grp> found in the DB, invokes <fn>(<grp>, <arg>). - * - * The following values can be returned by <fn>(): - * - * -1: an error occured. This will cause the walk to be terminated, - * and the original DB file to be preserved. - * - * 0: success and write. The walker will write the contents of - * the attribute passed as argument to <fn>(), and continue walking - * the entries found in the DB. - * - * 1: skip. The walker should not write the contents of the current - * group attributes to the new DB, but should continue walking - * the entries found in the DB. - */ -static dladm_status_t -i_dladm_aggr_walk_rw_db(int (*fn)(void *, dladm_aggr_grp_attr_db_t *), - void *arg, const char *root) -{ - FILE *fp, *nfp; - int nfd, fn_rc, lock_fd; - char line[MAXLINELEN]; - dladm_aggr_grp_attr_db_t attr; - char *db_file, *tmp_db_file; - char db_file_buf[MAXPATHLEN]; - char tmp_db_file_buf[MAXPATHLEN]; - dladm_status_t status; - - if (root == NULL) { - db_file = DLADM_AGGR_DB; - tmp_db_file = DLADM_AGGR_DB_TMP; - } else { - (void) snprintf(db_file_buf, MAXPATHLEN, "%s%s", root, - DLADM_AGGR_DB); - (void) snprintf(tmp_db_file_buf, MAXPATHLEN, "%s%s", root, - DLADM_AGGR_DB_TMP); - db_file = db_file_buf; - tmp_db_file = tmp_db_file_buf; - } - - if ((lock_fd = i_dladm_aggr_lock_db(F_WRLCK)) < 0) - return (dladm_errno2status(errno)); - - if ((fp = fopen(db_file, "r")) == NULL) { - status = dladm_errno2status(errno); - i_dladm_aggr_unlock_db(lock_fd); - return (status); - } - - if ((nfd = open(tmp_db_file, O_WRONLY|O_CREAT|O_TRUNC, - DLADM_AGGR_DB_PERMS)) == -1) { - status = dladm_errno2status(errno); - (void) fclose(fp); - i_dladm_aggr_unlock_db(lock_fd); - return (status); - } - - if ((nfp = fdopen(nfd, "w")) == NULL) { - status = dladm_errno2status(errno); - (void) close(nfd); - (void) fclose(fp); - (void) unlink(tmp_db_file); - i_dladm_aggr_unlock_db(lock_fd); - return (status); - } - - attr.lt_ports = NULL; - - while (fgets(line, MAXLINELEN, fp) != NULL) { - - /* skip comments */ - if (BLANK_LINE(line)) { - if (fputs(line, nfp) == EOF) { - status = dladm_errno2status(errno); - goto failed; - } + s = dladm_datalink_id2info(portid, &flags, NULL, NULL, NULL, 0); + if (s != DLADM_STATUS_OK || !(flags & DLADM_OPT_ACTIVE)) continue; - } - - if (i_dladm_aggr_parse_db(line, &attr) != 0) { - status = DLADM_STATUS_REPOSITORYINVAL; - goto failed; - } - - fn_rc = fn(arg, &attr); - - switch (fn_rc) { - case -1: - /* failure, stop walking */ - status = dladm_errno2status(errno); - goto failed; - case 0: - /* - * Success, write group attributes, which could - * have been modified by fn(). - */ - if (i_dladm_aggr_fput_grp(nfp, &attr) != 0) { - status = dladm_errno2status(errno); - goto failed; - } - break; - case 1: - /* skip current group */ - break; - } - - free(attr.lt_ports); - attr.lt_ports = NULL; - } - - if (getuid() == 0 || geteuid() == 0) { - if (fchmod(nfd, DLADM_AGGR_DB_PERMS) == -1) { - status = dladm_errno2status(errno); - goto failed; - } - - if (fchown(nfd, DLADM_AGGR_DB_OWNER, - DLADM_AGGR_DB_GROUP) == -1) { - status = dladm_errno2status(errno); - goto failed; - } - } - - if (fflush(nfp) == EOF) { - status = dladm_errno2status(errno); - goto failed; - } - - (void) fclose(fp); - (void) fclose(nfp); - - if (rename(tmp_db_file, db_file) == -1) { - status = dladm_errno2status(errno); - (void) unlink(tmp_db_file); - i_dladm_aggr_unlock_db(lock_fd); - return (status); - } - i_dladm_aggr_unlock_db(lock_fd); - return (DLADM_STATUS_OK); - -failed: - free(attr.lt_ports); - (void) fclose(fp); - (void) fclose(nfp); - (void) unlink(tmp_db_file); - i_dladm_aggr_unlock_db(lock_fd); - - return (status); -} - -/* - * Remove an entry from the DB. - */ -static int -i_dladm_aggr_del_db_fn(void *arg, dladm_aggr_grp_attr_db_t *grp) -{ - delete_db_state_t *state = arg; - - if (grp->lt_key != state->ds_key) - return (0); - - state->ds_found = B_TRUE; - - /* don't save matching group */ - return (1); -} - -static dladm_status_t -i_dladm_aggr_del_db(dladm_aggr_grp_attr_db_t *attr, const char *root) -{ - delete_db_state_t state; - dladm_status_t status; - - state.ds_key = attr->lt_key; - state.ds_found = B_FALSE; - - status = i_dladm_aggr_walk_rw_db(i_dladm_aggr_del_db_fn, &state, root); - if (status != DLADM_STATUS_OK) - return (status); - - if (!state.ds_found) - return (DLADM_STATUS_NOTFOUND); - - return (DLADM_STATUS_OK); -} - -/* - * Modify the properties of an existing group in the DB. - */ -static int -i_dladm_aggr_modify_db_fn(void *arg, dladm_aggr_grp_attr_db_t *grp) -{ - modify_db_state_t *state = arg; - dladm_aggr_modify_attr_t *new_attr = state->us_attr_new; - dladm_aggr_modify_attr_t *old_attr = state->us_attr_old; - - if (grp->lt_key != state->us_key) - return (0); - - state->us_found = B_TRUE; - - if (state->us_mask & DLADM_AGGR_MODIFY_POLICY) { - if (old_attr != NULL) - old_attr->ld_policy = grp->lt_policy; - grp->lt_policy = new_attr->ld_policy; + ports[j++].lp_linkid = portid; } - if (state->us_mask & DLADM_AGGR_MODIFY_MAC) { - if (old_attr != NULL) { - old_attr->ld_mac_fixed = grp->lt_mac_fixed; - bcopy(grp->lt_mac, old_attr->ld_mac, ETHERADDRL); - } - grp->lt_mac_fixed = new_attr->ld_mac_fixed; - bcopy(new_attr->ld_mac, grp->lt_mac, ETHERADDRL); + if (j == 0) { + /* + * All of the physical links are removed. + */ + status = DLADM_STATUS_BADARG; + goto done; } - if (state->us_mask & DLADM_AGGR_MODIFY_LACP_MODE) { - if (old_attr != NULL) - old_attr->ld_lacp_mode = grp->lt_lacp_mode; - grp->lt_lacp_mode = new_attr->ld_lacp_mode; + /* + * Create active aggregation. + */ + if ((status = i_dladm_aggr_create_sys(linkid, + key, j, ports, attr.lg_policy, attr.lg_mac_fixed, + (const uchar_t *)attr.lg_mac, attr.lg_lacp_mode, + attr.lg_lacp_timer, attr.lg_force)) != DLADM_STATUS_OK) { + goto done; } - if (state->us_mask & DLADM_AGGR_MODIFY_LACP_TIMER) { - if (old_attr != NULL) - old_attr->ld_lacp_timer = grp->lt_lacp_timer; - grp->lt_lacp_timer = new_attr->ld_lacp_timer; + if ((status = dladm_up_datalink_id(linkid)) != DLADM_STATUS_OK) { + laioc_delete_t ioc; + ioc.ld_linkid = linkid; + (void) i_dladm_aggr_strioctl(LAIOC_DELETE, &ioc, sizeof (ioc)); + goto done; } - /* save modified group */ - return (0); -} - -static dladm_status_t -i_dladm_aggr_modify_db(uint32_t key, uint32_t mask, - dladm_aggr_modify_attr_t *new, dladm_aggr_modify_attr_t *old, - const char *root) -{ - modify_db_state_t state; - dladm_status_t status; - - state.us_key = key; - state.us_mask = mask; - state.us_attr_new = new; - state.us_attr_old = old; - state.us_found = B_FALSE; - - if ((status = i_dladm_aggr_walk_rw_db(i_dladm_aggr_modify_db_fn, - &state, root)) != DLADM_STATUS_OK) { - return (status); - } + /* + * Reset the active linkprop of this specific link. + */ + (void) dladm_init_linkprop(linkid); - if (!state.us_found) - return (DLADM_STATUS_NOTFOUND); +done: + free(attr.lg_ports); + free(ports); - return (DLADM_STATUS_OK); + *statusp = status; + return (DLADM_WALK_CONTINUE); } /* - * Add ports to an existing group in the DB. + * Bring up one aggregation, or all persistent aggregations. In the latter + * case, the walk may terminate early if bringup of an aggregation fails. */ -static int -i_dladm_aggr_add_db_fn(void *arg, dladm_aggr_grp_attr_db_t *grp) -{ - add_db_state_t *state = arg; - dladm_aggr_grp_attr_db_t *attr = state->as_attr; - void *ports; - int i, j; - - if (grp->lt_key != attr->lt_key) - return (0); - - state->as_found = B_TRUE; - - /* are any of the ports to be added already members of the group? */ - for (i = 0; i < grp->lt_nports; i++) { - for (j = 0; j < attr->lt_nports; j++) { - if (strcmp(grp->lt_ports[i].lp_devname, - attr->lt_ports[j].lp_devname) == 0) { - errno = EEXIST; - return (-1); - } - } - } - - /* add groups specified by attr to grp */ - ports = realloc(grp->lt_ports, (grp->lt_nports + - attr->lt_nports) * sizeof (dladm_aggr_port_attr_db_t)); - if (ports == NULL) - return (-1); - grp->lt_ports = ports; - - for (i = 0; i < attr->lt_nports; i++) { - if (strlcpy(grp->lt_ports[grp->lt_nports + i].lp_devname, - attr->lt_ports[i].lp_devname, MAXNAMELEN + 1) >= - MAXNAMELEN + 1) - return (-1); - } - - grp->lt_nports += attr->lt_nports; - - /* save modified group */ - return (0); -} - -static dladm_status_t -i_dladm_aggr_add_db(dladm_aggr_grp_attr_db_t *attr, const char *root) +dladm_status_t +dladm_aggr_up(datalink_id_t linkid) { - add_db_state_t state; dladm_status_t status; - state.as_attr = attr; - state.as_found = B_FALSE; - - status = i_dladm_aggr_walk_rw_db(i_dladm_aggr_add_db_fn, &state, root); - if (status != DLADM_STATUS_OK) + if (linkid == DATALINK_ALL_LINKID) { + (void) dladm_walk_datalink_id(i_dladm_aggr_up, &status, + DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, + DLADM_OPT_PERSIST); + return (DLADM_STATUS_OK); + } else { + (void) i_dladm_aggr_up(linkid, &status); return (status); - - if (!state.as_found) - return (DLADM_STATUS_NOTFOUND); - - return (DLADM_STATUS_OK); -} - -/* - * Remove ports from an existing group in the DB. - */ - -typedef struct remove_db_state { - dladm_aggr_grp_attr_db_t *rs_attr; - boolean_t rs_found; -} remove_db_state_t; - -static int -i_dladm_aggr_remove_db_fn(void *arg, dladm_aggr_grp_attr_db_t *grp) -{ - remove_db_state_t *state = (remove_db_state_t *)arg; - dladm_aggr_grp_attr_db_t *attr = state->rs_attr; - int i, j, k, nremoved; - boolean_t match; - - if (grp->lt_key != attr->lt_key) - return (0); - - state->rs_found = B_TRUE; - - /* remove the ports specified by attr from the group */ - nremoved = 0; - k = 0; - for (i = 0; i < grp->lt_nports; i++) { - match = B_FALSE; - for (j = 0; j < attr->lt_nports && !match; j++) { - match = (strcmp(grp->lt_ports[i].lp_devname, - attr->lt_ports[j].lp_devname) == 0); - } - if (match) - nremoved++; - else - grp->lt_ports[k++] = grp->lt_ports[i]; - } - - if (nremoved != attr->lt_nports) { - errno = ENOENT; - return (-1); } - - grp->lt_nports -= nremoved; - - /* save modified group */ - return (0); -} - -static dladm_status_t -i_dladm_aggr_remove_db(dladm_aggr_grp_attr_db_t *attr, const char *root) -{ - remove_db_state_t state; - dladm_status_t status; - - state.rs_attr = attr; - state.rs_found = B_FALSE; - - status = i_dladm_aggr_walk_rw_db(i_dladm_aggr_remove_db_fn, - &state, root); - if (status != DLADM_STATUS_OK) - return (status); - - if (!state.rs_found) - return (DLADM_STATUS_NOTFOUND); - - return (DLADM_STATUS_OK); } /* * Given a policy string, return a policy mask. Returns B_TRUE on - * success, or B_FALSE if an error occured during parsing. + * success, or B_FALSE if an error occurred during parsing. */ boolean_t dladm_aggr_str2policy(const char *str, uint32_t *policy) @@ -1199,6 +804,9 @@ dladm_aggr_policy2str(uint32_t policy, char *str) int i, npolicies = 0; policy_t *pol; + if (str == NULL) + return (NULL); + str[0] = '\0'; for (i = 0; i < NPOLICIES; i++) { @@ -1206,8 +814,8 @@ dladm_aggr_policy2str(uint32_t policy, char *str) if ((policy & pol->policy) != 0) { npolicies++; if (npolicies > 1) - (void) strcat(str, ","); - (void) strcat(str, pol->pol_name); + (void) strlcat(str, ",", DLADM_STRSIZE); + (void) strlcat(str, pol->pol_name, DLADM_STRSIZE); } } @@ -1257,7 +865,7 @@ dladm_aggr_str2macaddr(const char *str, boolean_t *mac_fixed, uchar_t *mac_addr) * Returns a string containing a printable representation of a MAC address. */ const char * -dladm_aggr_macaddr2str(unsigned char *mac, char *buf) +dladm_aggr_macaddr2str(const unsigned char *mac, char *buf) { static char unknown_mac[] = {0, 0, 0, 0, 0, 0}; @@ -1265,9 +873,11 @@ dladm_aggr_macaddr2str(unsigned char *mac, char *buf) return (NULL); if (bcmp(unknown_mac, mac, ETHERADDRL) == 0) - return (gettext("<unknown>")); + (void) strlcpy(buf, "unknown", DLADM_STRSIZE); else return (_link_ntoa(mac, buf, ETHERADDRL, IFT_OTHER)); + + return (buf); } /* @@ -1302,6 +912,9 @@ dladm_aggr_lacpmode2str(aggr_lacp_mode_t mode_id, char *buf) int i; dladm_aggr_lacpmode_t *mode; + if (buf == NULL) + return (NULL); + for (i = 0; i < NLACP_MODES; i++) { mode = &lacp_modes[i]; if (mode->mode_id == mode_id) { @@ -1347,6 +960,9 @@ dladm_aggr_lacptimer2str(aggr_lacp_timer_t timer_id, char *buf) int i; dladm_aggr_lacptimer_t *timer; + if (buf == NULL) + return (NULL); + for (i = 0; i < NLACP_TIMERS; i++) { timer = &lacp_timers[i]; if (timer->lt_id == timer_id) { @@ -1364,7 +980,10 @@ const char * dladm_aggr_portstate2str(aggr_port_state_t state_id, char *buf) { int i; - dladm_aggr_port_state_t *state; + dladm_aggr_port_state_t *state; + + if (buf == NULL) + return (NULL); for (i = 0; i < NPORT_STATES; i++) { state = &port_states[i]; @@ -1379,123 +998,94 @@ dladm_aggr_portstate2str(aggr_port_state_t state_id, char *buf) return (buf); } -#define FPRINTF_ERR(fcall) if ((fcall) < 0) return (-1); - -/* - * Write the attribute of a group to the specified file. Returns 0 on - * success, -1 on failure. - */ -static int -i_dladm_aggr_fput_grp(FILE *fp, dladm_aggr_grp_attr_db_t *attr) +static dladm_status_t +dladm_aggr_persist_aggr_conf(const char *link, datalink_id_t linkid, + uint16_t key, uint32_t nports, dladm_aggr_port_attr_db_t *ports, + uint32_t policy, boolean_t mac_addr_fixed, const uchar_t *mac_addr, + aggr_lacp_mode_t lacp_mode, aggr_lacp_timer_t lacp_timer, + boolean_t force) { - int i; - char addr_str[ETHERADDRL * 3]; - char buf[DLADM_STRSIZE]; - - /* key, policy */ - FPRINTF_ERR(fprintf(fp, "%d\t%s\t", attr->lt_key, - dladm_aggr_policy2str(attr->lt_policy, buf))); - - /* number of ports, ports */ - FPRINTF_ERR(fprintf(fp, "%d\t", attr->lt_nports)); - for (i = 0; i < attr->lt_nports; i++) { - if (i > 0) - FPRINTF_ERR(fprintf(fp, ",")); - FPRINTF_ERR(fprintf(fp, "%s", attr->lt_ports[i].lp_devname)); - } - FPRINTF_ERR(fprintf(fp, "\t")); + dladm_conf_t conf = DLADM_INVALID_CONF; + char *portstr = NULL; + char macstr[ETHERADDRL * 3]; + dladm_status_t status; + int i, size; + uint64_t u64; - /* MAC address */ - if (!attr->lt_mac_fixed) { - FPRINTF_ERR(fprintf(fp, "auto")); - } else { - FPRINTF_ERR(fprintf(fp, "%s", - dladm_aggr_macaddr2str(attr->lt_mac, addr_str))); + if ((status = dladm_create_conf(link, linkid, DATALINK_CLASS_AGGR, + DL_ETHER, &conf)) != DLADM_STATUS_OK) { + return (status); } - FPRINTF_ERR(fprintf(fp, "\t")); - - FPRINTF_ERR(fprintf(fp, "%s\t", - dladm_aggr_lacpmode2str(attr->lt_lacp_mode, buf))); - - FPRINTF_ERR(fprintf(fp, "%s\n", - dladm_aggr_lacptimer2str(attr->lt_lacp_timer, buf))); - return (0); -} + u64 = key; + status = dladm_set_conf_field(conf, FKEY, DLADM_TYPE_UINT64, &u64); + if (status != DLADM_STATUS_OK) + goto done; -static dladm_status_t -i_dladm_aggr_create_db(dladm_aggr_grp_attr_db_t *attr, const char *root) -{ - FILE *fp; - char line[MAXLINELEN]; - uint32_t key; - int lock_fd; - char *db_file; - char db_file_buf[MAXPATHLEN]; - char *endp = NULL; - dladm_status_t status; + u64 = nports; + status = dladm_set_conf_field(conf, FNPORTS, DLADM_TYPE_UINT64, &u64); + if (status != DLADM_STATUS_OK) + goto done; - if (root == NULL) { - db_file = DLADM_AGGR_DB; - } else { - (void) snprintf(db_file_buf, MAXPATHLEN, "%s%s", root, - DLADM_AGGR_DB); - db_file = db_file_buf; + size = nports * (LINKID_STR_WIDTH + 1) + 1; + if ((portstr = calloc(1, size)) == NULL) { + status = DLADM_STATUS_NOMEM; + goto done; } - if ((lock_fd = i_dladm_aggr_lock_db(F_WRLCK)) < 0) - return (dladm_errno2status(errno)); + for (i = 0; i < nports; i++) + WRITE_PORT(portstr, ports[i].lp_linkid, size); + status = dladm_set_conf_field(conf, FPORTS, DLADM_TYPE_STR, portstr); + free(portstr); - if ((fp = fopen(db_file, "r+")) == NULL && - (fp = fopen(db_file, "w")) == NULL) { - status = dladm_errno2status(errno); - i_dladm_aggr_unlock_db(lock_fd); - return (status); - } - - /* look for existing group with same key */ - while (fgets(line, MAXLINELEN, fp) != NULL) { - char *holder, *lasts; + if (status != DLADM_STATUS_OK) + goto done; - /* skip comments */ - if (BLANK_LINE(line)) - continue; + u64 = policy; + status = dladm_set_conf_field(conf, FPOLICY, DLADM_TYPE_UINT64, &u64); + if (status != DLADM_STATUS_OK) + goto done; - /* ignore corrupted lines */ - holder = strtok_r(line, " \t", &lasts); - if (holder == NULL) - continue; + status = dladm_set_conf_field(conf, FFIXMACADDR, DLADM_TYPE_BOOLEAN, + &mac_addr_fixed); + if (status != DLADM_STATUS_OK) + goto done; - /* port number */ - errno = 0; - key = (int)strtol(holder, &endp, 10); - if (errno != 0 || *endp != '\0') { - status = DLADM_STATUS_REPOSITORYINVAL; + if (mac_addr_fixed) { + if (!VALID_PORT_MAC(mac_addr)) { + status = DLADM_STATUS_MACADDRINVAL; goto done; } - if (key == attr->lt_key) { - /* group with key already exists */ - status = DLADM_STATUS_EXIST; + (void) dladm_aggr_macaddr2str(mac_addr, macstr); + status = dladm_set_conf_field(conf, FMACADDR, DLADM_TYPE_STR, + macstr); + if (status != DLADM_STATUS_OK) goto done; - } } - /* - * If we get here, we've verified that no existing group with - * the same key already exists. It's now time to add the - * new group to the DB. - */ - if (i_dladm_aggr_fput_grp(fp, attr) != 0) { - status = dladm_errno2status(errno); + status = dladm_set_conf_field(conf, FFORCE, DLADM_TYPE_BOOLEAN, &force); + if (status != DLADM_STATUS_OK) goto done; - } - status = DLADM_STATUS_OK; + u64 = lacp_mode; + status = dladm_set_conf_field(conf, FLACPMODE, DLADM_TYPE_UINT64, &u64); + if (status != DLADM_STATUS_OK) + goto done; + + u64 = lacp_timer; + status = dladm_set_conf_field(conf, FLACPTIMER, DLADM_TYPE_UINT64, + &u64); + if (status != DLADM_STATUS_OK) + goto done; + + /* + * Commit the link aggregation configuration. + */ + status = dladm_write_conf(conf); done: - (void) fclose(fp); - i_dladm_aggr_unlock_db(lock_fd); + dladm_destroy_conf(conf); return (status); } @@ -1504,60 +1094,168 @@ done: * file and bring it up. */ dladm_status_t -dladm_aggr_create(uint32_t key, uint32_t nports, +dladm_aggr_create(const char *name, uint16_t key, uint32_t nports, dladm_aggr_port_attr_db_t *ports, uint32_t policy, boolean_t mac_addr_fixed, - uchar_t *mac_addr, aggr_lacp_mode_t lacp_mode, aggr_lacp_timer_t lacp_timer, - boolean_t tempop, const char *root) + const uchar_t *mac_addr, aggr_lacp_mode_t lacp_mode, + aggr_lacp_timer_t lacp_timer, uint32_t flags) { - dladm_aggr_grp_attr_db_t attr; + datalink_id_t linkid = DATALINK_INVALID_LINKID; + uint32_t media; + uint32_t i; + datalink_class_t class; dladm_status_t status; + boolean_t force = (flags & DLADM_OPT_FORCE) ? B_TRUE : B_FALSE; - if (key == 0 || key > DLADM_AGGR_MAX_KEY) + if (key != 0 && key > AGGR_MAX_KEY) return (DLADM_STATUS_KEYINVAL); - attr.lt_key = key; - attr.lt_nports = nports; - attr.lt_ports = ports; - attr.lt_policy = policy; - attr.lt_mac_fixed = mac_addr_fixed; - if (attr.lt_mac_fixed) - bcopy(mac_addr, attr.lt_mac, ETHERADDRL); - else - bzero(attr.lt_mac, ETHERADDRL); - attr.lt_lacp_mode = lacp_mode; - attr.lt_lacp_timer = lacp_timer; + if (nports == 0) + return (DLADM_STATUS_BADARG); - /* add the link aggregation group to the DB */ - if (!tempop) { - status = i_dladm_aggr_create_db(&attr, root); + for (i = 0; i < nports; i++) { + if ((dladm_datalink_id2info(ports[i].lp_linkid, NULL, + &class, &media, NULL, 0) != DLADM_STATUS_OK) || + (class != DATALINK_CLASS_PHYS) && (media != DL_ETHER)) { + return (DLADM_STATUS_BADARG); + } + } + + flags &= (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST); + if ((status = dladm_create_datalink_id(name, DATALINK_CLASS_AGGR, + DL_ETHER, flags, &linkid)) != DLADM_STATUS_OK) { + goto fail; + } + + if ((flags & DLADM_OPT_PERSIST) && + (status = dladm_aggr_persist_aggr_conf(name, linkid, key, nports, + ports, policy, mac_addr_fixed, mac_addr, lacp_mode, lacp_timer, + force)) != DLADM_STATUS_OK) { + goto fail; + } + + if (!(flags & DLADM_OPT_ACTIVE)) + return (DLADM_STATUS_OK); + + status = i_dladm_aggr_create_sys(linkid, key, nports, ports, policy, + mac_addr_fixed, mac_addr, lacp_mode, lacp_timer, force); + + if (status != DLADM_STATUS_OK) { + if (flags & DLADM_OPT_PERSIST) + (void) dladm_remove_conf(linkid); + goto fail; + } + + return (DLADM_STATUS_OK); + +fail: + if (linkid != DATALINK_INVALID_LINKID) + (void) dladm_destroy_datalink_id(linkid, flags); + + return (status); +} + +static dladm_status_t +i_dladm_aggr_get_aggr_attr(dladm_conf_t conf, uint32_t mask, + dladm_aggr_modify_attr_t *attrp) +{ + dladm_status_t status = DLADM_STATUS_OK; + char macstr[ETHERADDRL * 3]; + uint64_t u64; + + if (mask & DLADM_AGGR_MODIFY_POLICY) { + status = dladm_get_conf_field(conf, FPOLICY, &u64, + sizeof (u64)); if (status != DLADM_STATUS_OK) return (status); - } else { - dladm_aggr_up_t up; + attrp->ld_policy = (uint32_t)u64; + } - up.lu_key = key; - up.lu_found = B_FALSE; - up.lu_fd = open(DLADM_AGGR_DEV, O_RDWR); - if (up.lu_fd < 0) - return (dladm_errno2status(errno)); + if (mask & DLADM_AGGR_MODIFY_MAC) { + status = dladm_get_conf_field(conf, FFIXMACADDR, + &attrp->ld_mac_fixed, sizeof (boolean_t)); + if (status != DLADM_STATUS_OK) + return (status); - status = i_dladm_aggr_up((void *)&up, &attr); - (void) close(up.lu_fd); - return (status); + if (attrp->ld_mac_fixed) { + boolean_t fixed; + + status = dladm_get_conf_field(conf, FMACADDR, + macstr, sizeof (macstr)); + if (status != DLADM_STATUS_OK) + return (status); + + if (!dladm_aggr_str2macaddr(macstr, &fixed, + attrp->ld_mac)) { + return (DLADM_STATUS_REPOSITORYINVAL); + } + } } - /* bring up the link aggregation group */ - status = dladm_aggr_up(key, root); - /* - * If the operation fails because the aggregation already exists, - * then only update the persistent configuration repository and - * return success. - */ - if (status == DLADM_STATUS_EXIST) - status = DLADM_STATUS_OK; + if (mask & DLADM_AGGR_MODIFY_LACP_MODE) { + status = dladm_get_conf_field(conf, FLACPMODE, &u64, + sizeof (u64)); + if (status != DLADM_STATUS_OK) + return (status); + attrp->ld_lacp_mode = (aggr_lacp_mode_t)u64; + } + + if (mask & DLADM_AGGR_MODIFY_LACP_TIMER) { + status = dladm_get_conf_field(conf, FLACPTIMER, &u64, + sizeof (u64)); + if (status != DLADM_STATUS_OK) + return (status); + attrp->ld_lacp_timer = (aggr_lacp_timer_t)u64; + } + + return (status); +} + +static dladm_status_t +i_dladm_aggr_set_aggr_attr(dladm_conf_t conf, uint32_t mask, + dladm_aggr_modify_attr_t *attrp) +{ + dladm_status_t status = DLADM_STATUS_OK; + char macstr[ETHERADDRL * 3]; + uint64_t u64; + + if (mask & DLADM_AGGR_MODIFY_POLICY) { + u64 = attrp->ld_policy; + status = dladm_set_conf_field(conf, FPOLICY, DLADM_TYPE_UINT64, + &u64); + if (status != DLADM_STATUS_OK) + return (status); + } + + if (mask & DLADM_AGGR_MODIFY_MAC) { + status = dladm_set_conf_field(conf, FFIXMACADDR, + DLADM_TYPE_BOOLEAN, &attrp->ld_mac_fixed); + if (status != DLADM_STATUS_OK) + return (status); + + if (attrp->ld_mac_fixed) { + (void) dladm_aggr_macaddr2str(attrp->ld_mac, macstr); + status = dladm_set_conf_field(conf, FMACADDR, + DLADM_TYPE_STR, macstr); + if (status != DLADM_STATUS_OK) + return (status); + } + } + + if (mask & DLADM_AGGR_MODIFY_LACP_MODE) { + u64 = attrp->ld_lacp_mode; + status = dladm_set_conf_field(conf, FLACPMODE, + DLADM_TYPE_UINT64, &u64); + if (status != DLADM_STATUS_OK) + return (status); + } - if (status != DLADM_STATUS_OK && !tempop) - (void) i_dladm_aggr_del_db(&attr, root); + if (mask & DLADM_AGGR_MODIFY_LACP_TIMER) { + u64 = attrp->ld_lacp_timer; + status = dladm_set_conf_field(conf, FLACPTIMER, + DLADM_TYPE_UINT64, &u64); + if (status != DLADM_STATUS_OK) + return (status); + } return (status); } @@ -1567,146 +1265,211 @@ dladm_aggr_create(uint32_t key, uint32_t nports, * the configuration file and pass the changes to the kernel. */ dladm_status_t -dladm_aggr_modify(uint32_t key, uint32_t modify_mask, uint32_t policy, - boolean_t mac_fixed, uchar_t *mac_addr, aggr_lacp_mode_t lacp_mode, - aggr_lacp_timer_t lacp_timer, boolean_t tempop, const char *root) +dladm_aggr_modify(datalink_id_t linkid, uint32_t modify_mask, uint32_t policy, + boolean_t mac_fixed, const uchar_t *mac_addr, aggr_lacp_mode_t lacp_mode, + aggr_lacp_timer_t lacp_timer, uint32_t flags) { dladm_aggr_modify_attr_t new_attr, old_attr; + dladm_conf_t conf; dladm_status_t status; - if (key == 0) - return (DLADM_STATUS_KEYINVAL); + new_attr.ld_policy = policy; + new_attr.ld_mac_fixed = mac_fixed; + new_attr.ld_lacp_mode = lacp_mode; + new_attr.ld_lacp_timer = lacp_timer; + bcopy(mac_addr, new_attr.ld_mac, ETHERADDRL); - if (modify_mask & DLADM_AGGR_MODIFY_POLICY) - new_attr.ld_policy = policy; + if (flags & DLADM_OPT_PERSIST) { + status = dladm_read_conf(linkid, &conf); + if (status != DLADM_STATUS_OK) + return (status); - if (modify_mask & DLADM_AGGR_MODIFY_MAC) { - new_attr.ld_mac_fixed = mac_fixed; - bcopy(mac_addr, new_attr.ld_mac, ETHERADDRL); - } + if ((status = i_dladm_aggr_get_aggr_attr(conf, modify_mask, + &old_attr)) != DLADM_STATUS_OK) { + goto done; + } - if (modify_mask & DLADM_AGGR_MODIFY_LACP_MODE) - new_attr.ld_lacp_mode = lacp_mode; + if ((status = i_dladm_aggr_set_aggr_attr(conf, modify_mask, + &new_attr)) != DLADM_STATUS_OK) { + goto done; + } - if (modify_mask & DLADM_AGGR_MODIFY_LACP_TIMER) - new_attr.ld_lacp_timer = lacp_timer; + status = dladm_write_conf(conf); - /* update the DB */ - if (!tempop && ((status = i_dladm_aggr_modify_db(key, modify_mask, - &new_attr, &old_attr, root)) != DLADM_STATUS_OK)) { - return (status); +done: + dladm_destroy_conf(conf); + if (status != DLADM_STATUS_OK) + return (status); } - status = i_dladm_aggr_modify_sys(key, modify_mask, &new_attr); - if (status != DLADM_STATUS_OK && !tempop) { - (void) i_dladm_aggr_modify_db(key, modify_mask, &old_attr, - NULL, root); + if (!(flags & DLADM_OPT_ACTIVE)) + return (DLADM_STATUS_OK); + + status = i_dladm_aggr_modify_sys(linkid, modify_mask, &new_attr); + if ((status != DLADM_STATUS_OK) && (flags & DLADM_OPT_PERSIST)) { + if (dladm_read_conf(linkid, &conf) == DLADM_STATUS_OK) { + if (i_dladm_aggr_set_aggr_attr(conf, modify_mask, + &old_attr) == DLADM_STATUS_OK) { + (void) dladm_write_conf(conf); + } + dladm_destroy_conf(conf); + } } return (status); } +typedef struct aggr_held_arg_s { + datalink_id_t aggrid; + boolean_t isheld; +} aggr_held_arg_t; + +static int +i_dladm_aggr_is_held(datalink_id_t linkid, void *arg) +{ + aggr_held_arg_t *aggr_held_arg = arg; + dladm_vlan_attr_t dva; + + if (dladm_vlan_info(linkid, &dva, DLADM_OPT_PERSIST) != DLADM_STATUS_OK) + return (DLADM_WALK_CONTINUE); + + if (dva.dv_linkid == aggr_held_arg->aggrid) { + /* + * This VLAN is created over the given aggregation. + */ + aggr_held_arg->isheld = B_TRUE; + return (DLADM_WALK_TERMINATE); + } + return (DLADM_WALK_CONTINUE); +} + /* - * Delete a previously created link aggregation group. + * Delete a previously created link aggregation group. Either the name "aggr" + * or the "key" is specified. */ dladm_status_t -dladm_aggr_delete(uint32_t key, boolean_t tempop, const char *root) +dladm_aggr_delete(datalink_id_t linkid, uint32_t flags) { - dladm_aggr_grp_attr_db_t db_attr; + laioc_delete_t ioc; + datalink_class_t class; dladm_status_t status; - if (key == 0) - return (DLADM_STATUS_KEYINVAL); - - if (tempop) { - dladm_aggr_down_t down; - dladm_aggr_grp_attr_t sys_attr; + if ((dladm_datalink_id2info(linkid, NULL, &class, NULL, NULL, 0) != + DLADM_STATUS_OK) || (class != DATALINK_CLASS_AGGR)) { + return (DLADM_STATUS_BADARG); + } - down.ld_key = key; - down.ld_found = B_FALSE; - sys_attr.lg_key = key; - if (i_dladm_aggr_down((void *)&down, &sys_attr) < 0) - return (dladm_errno2status(errno)); - else - return (DLADM_STATUS_OK); - } else { - status = dladm_aggr_down(key); + if (flags & DLADM_OPT_ACTIVE) { + ioc.ld_linkid = linkid; + if ((i_dladm_aggr_strioctl(LAIOC_DELETE, &ioc, + sizeof (ioc)) < 0) && + ((errno != ENOENT) || !(flags & DLADM_OPT_PERSIST))) { + status = dladm_errno2status(errno); + return (status); + } /* - * Only continue to delete the configuration repository - * either if we successfully delete the active aggregation - * or if the aggregation is not found. + * Delete ACTIVE linkprop first. */ - if (status != DLADM_STATUS_OK && - status != DLADM_STATUS_NOTFOUND) { - return (status); - } + (void) dladm_set_linkprop(linkid, NULL, NULL, 0, + DLADM_OPT_ACTIVE); + (void) dladm_destroy_datalink_id(linkid, DLADM_OPT_ACTIVE); } - if (tempop) - return (DLADM_STATUS_OK); + /* + * If we reach here, it means that the active aggregation has already + * been deleted, and there is no active VLANs holding this aggregation. + * Now we see whether there is any persistent VLANs holding this + * aggregation. If so, we fail the operation. + */ + if (flags & DLADM_OPT_PERSIST) { + aggr_held_arg_t arg; + + arg.aggrid = linkid; + arg.isheld = B_FALSE; + + (void) dladm_walk_datalink_id(i_dladm_aggr_is_held, + &arg, DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, + DLADM_OPT_PERSIST); + if (arg.isheld) + return (DLADM_STATUS_LINKBUSY); + + (void) dladm_destroy_datalink_id(linkid, DLADM_OPT_PERSIST); + (void) dladm_remove_conf(linkid); + } - db_attr.lt_key = key; - return (i_dladm_aggr_del_db(&db_attr, root)); + return (DLADM_STATUS_OK); } /* * Add one or more ports to an existing link aggregation. */ dladm_status_t -dladm_aggr_add(uint32_t key, uint32_t nports, dladm_aggr_port_attr_db_t *ports, - boolean_t tempop, const char *root) +dladm_aggr_add(datalink_id_t linkid, uint32_t nports, + dladm_aggr_port_attr_db_t *ports, uint32_t flags) { - dladm_aggr_grp_attr_db_t attr; - dladm_status_t status; - - if (key == 0) - return (DLADM_STATUS_KEYINVAL); - - bzero(&attr, sizeof (attr)); - attr.lt_key = key; - attr.lt_nports = nports; - attr.lt_ports = ports; - - if (!tempop && - ((status = i_dladm_aggr_add_db(&attr, root)) != DLADM_STATUS_OK)) { - return (status); - } - - status = i_dladm_aggr_add_rem_sys(&attr, LAIOC_ADD); - if (status != DLADM_STATUS_OK && !tempop) - (void) i_dladm_aggr_remove_db(&attr, root); - - return (status); + return (i_dladm_aggr_add_rmv(linkid, nports, ports, flags, LAIOC_ADD)); } /* * Remove one or more ports from an existing link aggregation. */ dladm_status_t -dladm_aggr_remove(uint32_t key, uint32_t nports, - dladm_aggr_port_attr_db_t *ports, boolean_t tempop, const char *root) +dladm_aggr_remove(datalink_id_t linkid, uint32_t nports, + dladm_aggr_port_attr_db_t *ports, uint32_t flags) +{ + return (i_dladm_aggr_add_rmv(linkid, nports, ports, flags, + LAIOC_REMOVE)); +} + +typedef struct i_walk_key_state_s { + uint16_t key; + datalink_id_t linkid; + boolean_t found; +} i_walk_key_state_t; + +static int +i_dladm_walk_key2linkid(datalink_id_t linkid, void *arg) { - dladm_aggr_grp_attr_db_t attr; + dladm_conf_t conf; + uint16_t key; dladm_status_t status; + i_walk_key_state_t *statep = (i_walk_key_state_t *)arg; + uint64_t u64; - if (key == 0) - return (DLADM_STATUS_KEYINVAL); + if (dladm_read_conf(linkid, &conf) != 0) + return (DLADM_WALK_CONTINUE); - bzero(&attr, sizeof (attr)); - attr.lt_key = key; - attr.lt_nports = nports; - attr.lt_ports = ports; + status = dladm_get_conf_field(conf, FKEY, &u64, sizeof (u64)); + key = (uint16_t)u64; + dladm_destroy_conf(conf); - if (!tempop && - ((status = i_dladm_aggr_remove_db(&attr, root)) != - DLADM_STATUS_OK)) { - return (status); + if ((status == DLADM_STATUS_OK) && (key == statep->key)) { + statep->found = B_TRUE; + statep->linkid = linkid; + return (DLADM_WALK_TERMINATE); } - status = i_dladm_aggr_add_rem_sys(&attr, LAIOC_REMOVE); - if (status != DLADM_STATUS_OK && !tempop) - (void) i_dladm_aggr_add_db(&attr, root); + return (DLADM_WALK_CONTINUE); +} - return (status); +dladm_status_t +dladm_key2linkid(uint16_t key, datalink_id_t *linkidp, uint32_t flags) +{ + i_walk_key_state_t state; + + if (key > AGGR_MAX_KEY) + return (DLADM_STATUS_NOTFOUND); + + state.found = B_FALSE; + state.key = key; + + (void) dladm_walk_datalink_id(i_dladm_walk_key2linkid, &state, + DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, flags); + if (state.found == B_TRUE) { + *linkidp = state.linkid; + return (DLADM_STATUS_OK); + } else { + return (DLADM_STATUS_NOTFOUND); + } } diff --git a/usr/src/lib/libdladm/common/libdlaggr.h b/usr/src/lib/libdladm/common/libdlaggr.h index 40b8c72eeb..1b5df523c4 100644 --- a/usr/src/lib/libdladm/common/libdlaggr.h +++ b/usr/src/lib/libdladm/common/libdlaggr.h @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -44,67 +44,65 @@ extern "C" { /* * Modification flags sent with the LAIOC_MODIFY ioctl */ -#define DLADM_AGGR_MODIFY_POLICY 0x01 -#define DLADM_AGGR_MODIFY_MAC 0x02 -#define DLADM_AGGR_MODIFY_LACP_MODE 0x04 -#define DLADM_AGGR_MODIFY_LACP_TIMER 0x08 +#define DLADM_AGGR_MODIFY_POLICY 0x01 +#define DLADM_AGGR_MODIFY_MAC 0x02 +#define DLADM_AGGR_MODIFY_LACP_MODE 0x04 +#define DLADM_AGGR_MODIFY_LACP_TIMER 0x08 typedef struct dladm_aggr_port_attr_db { - char lp_devname[MAXNAMELEN + 1]; + datalink_id_t lp_linkid; } dladm_aggr_port_attr_db_t; typedef struct dladm_aggr_port_attr { - char lp_devname[MAXNAMELEN + 1]; + datalink_id_t lp_linkid; uchar_t lp_mac[ETHERADDRL]; aggr_port_state_t lp_state; aggr_lacp_state_t lp_lacp_state; } dladm_aggr_port_attr_t; typedef struct dladm_aggr_grp_attr { + datalink_id_t lg_linkid; uint32_t lg_key; uint32_t lg_nports; dladm_aggr_port_attr_t *lg_ports; uint32_t lg_policy; uchar_t lg_mac[ETHERADDRL]; boolean_t lg_mac_fixed; + boolean_t lg_force; aggr_lacp_mode_t lg_lacp_mode; aggr_lacp_timer_t lg_lacp_timer; } dladm_aggr_grp_attr_t; -extern dladm_status_t dladm_aggr_create(uint32_t, uint32_t, +extern dladm_status_t dladm_aggr_create(const char *, uint16_t, uint32_t, dladm_aggr_port_attr_db_t *, uint32_t, boolean_t, - uchar_t *, aggr_lacp_mode_t, aggr_lacp_timer_t, - boolean_t, const char *); -extern dladm_status_t dladm_aggr_delete(uint32_t, boolean_t, const char *); -extern dladm_status_t dladm_aggr_add(uint32_t, uint32_t, - dladm_aggr_port_attr_db_t *, boolean_t, - const char *); -extern dladm_status_t dladm_aggr_remove(uint32_t, uint32_t, - dladm_aggr_port_attr_db_t *, boolean_t, - const char *); -extern dladm_status_t dladm_aggr_modify(uint32_t, uint32_t, uint32_t, - boolean_t, uchar_t *, aggr_lacp_mode_t, - aggr_lacp_timer_t, boolean_t, const char *); -extern dladm_status_t dladm_aggr_up(uint32_t, const char *); -extern dladm_status_t dladm_aggr_down(uint32_t); + const uchar_t *, aggr_lacp_mode_t, + aggr_lacp_timer_t, uint32_t); +extern dladm_status_t dladm_aggr_delete(datalink_id_t, uint32_t); +extern dladm_status_t dladm_aggr_add(datalink_id_t, uint32_t, + dladm_aggr_port_attr_db_t *, uint32_t); +extern dladm_status_t dladm_aggr_remove(datalink_id_t, uint32_t, + dladm_aggr_port_attr_db_t *, uint32_t); +extern dladm_status_t dladm_aggr_modify(datalink_id_t, uint32_t, uint32_t, + boolean_t, const uchar_t *, aggr_lacp_mode_t, + aggr_lacp_timer_t, uint32_t); +extern dladm_status_t dladm_aggr_up(datalink_id_t); +extern dladm_status_t dladm_aggr_info(datalink_id_t, dladm_aggr_grp_attr_t *, + uint32_t); extern boolean_t dladm_aggr_str2policy(const char *, uint32_t *); extern char *dladm_aggr_policy2str(uint32_t, char *); extern boolean_t dladm_aggr_str2macaddr(const char *, boolean_t *, uchar_t *); -extern const char *dladm_aggr_macaddr2str(unsigned char *, char *); - +extern const char *dladm_aggr_macaddr2str(const unsigned char *, char *); extern boolean_t dladm_aggr_str2lacpmode(const char *, aggr_lacp_mode_t *); extern const char *dladm_aggr_lacpmode2str(aggr_lacp_mode_t, char *); extern boolean_t dladm_aggr_str2lacptimer(const char *, aggr_lacp_timer_t *); extern const char *dladm_aggr_lacptimer2str(aggr_lacp_timer_t, char *); - extern const char *dladm_aggr_portstate2str(aggr_port_state_t, char *); - -extern int dladm_aggr_walk(int (*)(void *, - dladm_aggr_grp_attr_t *), void *); +extern dladm_status_t dladm_key2linkid(uint16_t, datalink_id_t *, + uint32_t); #ifdef __cplusplus } diff --git a/usr/src/lib/libdladm/common/libdllink.c b/usr/src/lib/libdladm/common/libdllink.c index 45f4641588..bd046acda9 100644 --- a/usr/src/lib/libdladm/common/libdllink.c +++ b/usr/src/lib/libdladm/common/libdllink.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -29,213 +29,85 @@ #include <unistd.h> #include <errno.h> #include <fcntl.h> +#include <assert.h> +#include <ctype.h> #include <strings.h> #include <sys/stat.h> #include <sys/dld.h> +#include <sys/vlan.h> +#include <librcm.h> #include <libdlpi.h> #include <libdevinfo.h> +#include <libdlaggr.h> +#include <libdlvlan.h> #include <libdllink.h> +#include <libdlmgmt.h> #include <libdladm_impl.h> -typedef struct dladm_dev { - char dd_name[IFNAMSIZ]; - struct dladm_dev *dd_next; -} dladm_dev_t; - -typedef struct dladm_walk { - dladm_dev_t *dw_dev_list; -} dladm_walk_t; - /* * Return the attributes of the specified datalink from the DLD driver. */ -static int -i_dladm_info(int fd, const char *name, dladm_attr_t *dap) +static dladm_status_t +i_dladm_info(int fd, const datalink_id_t linkid, dladm_attr_t *dap) { dld_ioc_attr_t dia; - if (strlen(name) >= IFNAMSIZ) { - errno = EINVAL; - return (-1); - } - - (void) strlcpy(dia.dia_name, name, IFNAMSIZ); + dia.dia_linkid = linkid; - if (i_dladm_ioctl(fd, DLDIOCATTR, &dia, sizeof (dia)) < 0) - return (-1); + if (i_dladm_ioctl(fd, DLDIOC_ATTR, &dia, sizeof (dia)) < 0) + return (dladm_errno2status(errno)); - (void) strlcpy(dap->da_dev, dia.dia_dev, MAXNAMELEN); dap->da_max_sdu = dia.dia_max_sdu; - dap->da_vid = dia.dia_vid; - return (0); + return (DLADM_STATUS_OK); } -/* - * Adds a datalink to the array corresponding to arg. - */ -static void -i_dladm_nt_net_add(void *arg, char *name) -{ - dladm_walk_t *dwp = arg; - dladm_dev_t *ddp = dwp->dw_dev_list; - dladm_dev_t **lastp = &dwp->dw_dev_list; - - while (ddp) { - /* - * Skip duplicates. - */ - if (strcmp(ddp->dd_name, name) == 0) - return; - - lastp = &ddp->dd_next; - ddp = ddp->dd_next; - } - - if ((ddp = malloc(sizeof (*ddp))) == NULL) - return; - - (void) strlcpy(ddp->dd_name, name, IFNAMSIZ); - ddp->dd_next = NULL; - *lastp = ddp; -} - -/* - * Walker callback invoked for each DDI_NT_NET node. - */ -static int -i_dladm_nt_net_walk(di_node_t node, di_minor_t minor, void *arg) -{ - char linkname[DLPI_LINKNAME_MAX]; - dlpi_handle_t dh; - - if (dlpi_makelink(linkname, di_minor_name(minor), - di_instance(node)) != DLPI_SUCCESS) - return (DI_WALK_CONTINUE); - - if (dlpi_open(linkname, &dh, 0) == DLPI_SUCCESS) { - i_dladm_nt_net_add(arg, linkname); - dlpi_close(dh); - } - return (DI_WALK_CONTINUE); -} - -/* - * Hold a data-link. - */ -static int -i_dladm_hold_link(const char *name, zoneid_t zoneid, boolean_t docheck) -{ - int fd; - dld_hold_vlan_t dhv; - - if (strlen(name) >= IFNAMSIZ) { - errno = EINVAL; - return (-1); - } +struct i_dladm_walk_arg { + dladm_walkcb_t *fn; + void *arg; +}; - if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) - return (-1); - - bzero(&dhv, sizeof (dld_hold_vlan_t)); - (void) strlcpy(dhv.dhv_name, name, IFNAMSIZ); - dhv.dhv_zid = zoneid; - dhv.dhv_docheck = docheck; - - if (i_dladm_ioctl(fd, DLDIOCHOLDVLAN, &dhv, sizeof (dhv)) < 0) { - int olderrno = errno; - - (void) close(fd); - errno = olderrno; - return (-1); - } - - (void) close(fd); - return (0); -} - -/* - * Release a data-link. - */ static int -i_dladm_rele_link(const char *name, zoneid_t zoneid, boolean_t docheck) +i_dladm_walk(datalink_id_t linkid, void *arg) { - int fd; - dld_hold_vlan_t dhv; - - if (strlen(name) >= IFNAMSIZ) { - errno = EINVAL; - return (-1); - } - - if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) - return (-1); - - bzero(&dhv, sizeof (dld_hold_vlan_t)); - (void) strlcpy(dhv.dhv_name, name, IFNAMSIZ); - dhv.dhv_zid = zoneid; - dhv.dhv_docheck = docheck; + struct i_dladm_walk_arg *walk_arg = arg; + char link[MAXLINKNAMELEN]; - if (i_dladm_ioctl(fd, DLDIOCRELEVLAN, &dhv, sizeof (dhv)) < 0) { - int olderrno = errno; - - (void) close(fd); - errno = olderrno; - return (-1); + if (dladm_datalink_id2info(linkid, NULL, NULL, NULL, link, + sizeof (link)) == DLADM_STATUS_OK) { + return (walk_arg->fn(link, walk_arg->arg)); } - (void) close(fd); - return (0); + return (DLADM_WALK_CONTINUE); } /* - * Invoke the specified callback function for each active DDI_NT_NET - * node. + * Walk all datalinks. */ -int -dladm_walk(void (*fn)(void *, const char *), void *arg) +dladm_status_t +dladm_walk(dladm_walkcb_t *fn, void *arg, datalink_class_t class, + datalink_media_t dmedia, uint32_t flags) { - di_node_t root; - dladm_walk_t dw; - dladm_dev_t *ddp, *last_ddp; - - if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL) { - errno = EFAULT; - return (-1); - } - dw.dw_dev_list = NULL; - - (void) di_walk_minor(root, DDI_NT_NET, DI_CHECK_ALIAS, &dw, - i_dladm_nt_net_walk); - - di_fini(root); + struct i_dladm_walk_arg walk_arg; - ddp = dw.dw_dev_list; - while (ddp) { - fn(arg, ddp->dd_name); - last_ddp = ddp; - ddp = ddp->dd_next; - free(last_ddp); - } - - return (0); + walk_arg.fn = fn; + walk_arg.arg = arg; + return (dladm_walk_datalink_id(i_dladm_walk, &walk_arg, + class, dmedia, flags)); } /* - * MAC Administration Library. - * - * This library is used by administration tools such as dladm(1M) to + * These routines are used by administration tools such as dladm(1M) to * iterate through the list of MAC interfaces - * */ typedef struct dladm_mac_dev { char dm_name[MAXNAMELEN]; - struct dladm_mac_dev *dm_next; + struct dladm_mac_dev *dm_next; } dladm_mac_dev_t; typedef struct macadm_walk { - dladm_mac_dev_t *dmd_dev_list; + dladm_mac_dev_t *dmd_dev_list; } dladm_mac_walk_t; /* @@ -259,6 +131,12 @@ i_dladm_mac_walk(di_node_t node, di_minor_t minor, void *arg) if (strcmp("aggr", di_driver_name(node)) == 0) return (DI_WALK_CONTINUE); + /* + * Skip softmacs. + */ + if (strcmp("softmac", di_driver_name(node)) == 0) + return (DI_WALK_CONTINUE); + while (dmdp) { /* * Skip duplicates. @@ -281,17 +159,18 @@ i_dladm_mac_walk(di_node_t node, di_minor_t minor, void *arg) } /* - * Invoke the specified callback for each DDI_NT_MAC node. + * Invoke the specified callback for each DDI_NT_NET node. */ -int -dladm_mac_walk(void (*fn)(void *, const char *), void *arg) +dladm_status_t +dladm_mac_walk(int (*fn)(const char *, void *arg), void *arg) { di_node_t root; dladm_mac_walk_t dmw; dladm_mac_dev_t *dmdp, *next; + boolean_t done = B_FALSE; if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL) - return (-1); + return (dladm_errno2status(errno)); dmw.dmd_dev_list = NULL; @@ -303,33 +182,32 @@ dladm_mac_walk(void (*fn)(void *, const char *), void *arg) dmdp = dmw.dmd_dev_list; for (dmdp = dmw.dmd_dev_list; dmdp != NULL; dmdp = next) { next = dmdp->dm_next; - (*fn)(arg, dmdp->dm_name); + if (!done && + ((*fn)(dmdp->dm_name, arg) == DLADM_WALK_TERMINATE)) { + done = B_TRUE; + } free(dmdp); } - return (0); + return (DLADM_STATUS_OK); } /* - * Returns the current attributes of the specified datalink. + * Get the current attributes of the specified datalink. */ -int -dladm_info(const char *name, dladm_attr_t *dap) +dladm_status_t +dladm_info(datalink_id_t linkid, dladm_attr_t *dap) { int fd; + dladm_status_t status; if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) - return (-1); - - if (i_dladm_info(fd, name, dap) < 0) - goto failed; + return (dladm_errno2status(errno)); - (void) close(fd); - return (0); + status = i_dladm_info(fd, linkid, dap); -failed: (void) close(fd); - return (-1); + return (status); } const char * @@ -373,19 +251,678 @@ dladm_linkduplex2str(link_duplex_t duplex, char *buf) } /* - * Do a "hold" operation to a link. + * Set zoneid of a given link */ -int -dladm_hold_link(const char *name, zoneid_t zoneid, boolean_t docheck) +dladm_status_t +dladm_setzid(const char *link, zoneid_t zoneid) +{ + int fd; + dladm_status_t status = DLADM_STATUS_OK; + dld_ioc_setzid_t dis; + + if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) + return (dladm_errno2status(errno)); + + bzero(&dis, sizeof (dld_ioc_setzid_t)); + (void) strlcpy(dis.dis_link, link, MAXLINKNAMELEN); + dis.dis_zid = zoneid; + + if (i_dladm_ioctl(fd, DLDIOC_SETZID, &dis, sizeof (dis)) < 0) + status = dladm_errno2status(errno); + + (void) close(fd); + return (status); +} + +/* + * Get zoneid of a given link + */ +dladm_status_t +dladm_getzid(datalink_id_t linkid, zoneid_t *zoneidp) +{ + int fd; + dladm_status_t status = DLADM_STATUS_OK; + dld_ioc_getzid_t dig; + + if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) + return (dladm_errno2status(errno)); + + bzero(&dig, sizeof (dld_ioc_getzid_t)); + dig.dig_linkid = linkid; + dig.dig_zid = -1; + + if (i_dladm_ioctl(fd, DLDIOC_GETZID, &dig, sizeof (dig)) < 0) + status = dladm_errno2status(errno); + + (void) close(fd); + + if (status == DLADM_STATUS_OK) + *zoneidp = dig.dig_zid; + + return (status); +} + +/* + * Case 1: rename an existing link1 to a link2 that does not exist. + * Result: <linkid1, link2> + */ +static dladm_status_t +i_dladm_rename_link_c1(datalink_id_t linkid1, const char *link1, + const char *link2, uint32_t flags) { - return (i_dladm_hold_link(name, zoneid, docheck)); + dld_ioc_rename_t dir; + dladm_conf_t conf; + dladm_status_t status = DLADM_STATUS_OK; + int fd; + + /* + * Link is currently available. Check to see whether anything is + * holding this link to prevent a rename operation. + */ + if (flags & DLADM_OPT_ACTIVE) { + dir.dir_linkid1 = linkid1; + dir.dir_linkid2 = DATALINK_INVALID_LINKID; + (void) strlcpy(dir.dir_link, link2, MAXLINKNAMELEN); + if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) + return (dladm_errno2status(errno)); + + if (i_dladm_ioctl(fd, DLDIOC_RENAME, &dir, sizeof (dir)) < 0) { + status = dladm_errno2status(errno); + (void) close(fd); + return (status); + } + } + + status = dladm_remap_datalink_id(linkid1, link2); + if (status != DLADM_STATUS_OK) + goto done; + + /* + * Flush the current mapping to persistent configuration. + */ + if ((flags & DLADM_OPT_PERSIST) && + (((status = dladm_read_conf(linkid1, &conf)) != DLADM_STATUS_OK) || + ((status = dladm_write_conf(conf)) != DLADM_STATUS_OK))) { + (void) dladm_remap_datalink_id(linkid1, link1); + } +done: + if (flags & DLADM_OPT_ACTIVE) { + if (status != DLADM_STATUS_OK) { + (void) strlcpy(dir.dir_link, link1, MAXLINKNAMELEN); + (void) i_dladm_ioctl(fd, DLDIOC_RENAME, &dir, + sizeof (dir)); + } + (void) close(fd); + } + return (status); +} + +typedef struct link_hold_arg_s { + datalink_id_t linkid; + datalink_id_t holder; + uint32_t flags; +} link_hold_arg_t; + +static int +i_dladm_aggr_link_hold(datalink_id_t aggrid, void *arg) +{ + link_hold_arg_t *hold_arg = arg; + dladm_aggr_grp_attr_t ginfo; + dladm_status_t status; + int i; + + status = dladm_aggr_info(aggrid, &ginfo, hold_arg->flags); + if (status != DLADM_STATUS_OK) + return (DLADM_WALK_CONTINUE); + + for (i = 0; i < ginfo.lg_nports; i++) { + if (ginfo.lg_ports[i].lp_linkid == hold_arg->linkid) { + hold_arg->holder = aggrid; + return (DLADM_WALK_TERMINATE); + } + } + return (DLADM_WALK_CONTINUE); +} + +static int +i_dladm_vlan_link_hold(datalink_id_t vlanid, void *arg) +{ + link_hold_arg_t *hold_arg = arg; + dladm_vlan_attr_t vinfo; + dladm_status_t status; + + status = dladm_vlan_info(vlanid, &vinfo, hold_arg->flags); + if (status != DLADM_STATUS_OK) + return (DLADM_WALK_CONTINUE); + + if (vinfo.dv_linkid == hold_arg->linkid) { + hold_arg->holder = vlanid; + return (DLADM_WALK_TERMINATE); + } + return (DLADM_WALK_CONTINUE); } /* - * Do a "release" operation to a link. + * Case 2: rename an available physical link link1 to a REMOVED physical link + * link2. As a result, link1 directly inherits all datalinks configured + * over link2 (linkid2). + * Result: <linkid2, link2, link1_phymaj, link1_phyinst, link1_devname, + * link2_other_attr> */ +static dladm_status_t +i_dladm_rename_link_c2(datalink_id_t linkid1, datalink_id_t linkid2) +{ + rcm_handle_t *rcm_hdl = NULL; + nvlist_t *nvl = NULL; + link_hold_arg_t arg; + dld_ioc_rename_t dir; + int fd; + dladm_conf_t conf1, conf2; + char devname[MAXLINKNAMELEN]; + uint64_t phymaj, phyinst; + dladm_status_t status = DLADM_STATUS_OK; + + /* + * First check if linkid1 is associated with any persistent + * aggregations or VLANs. If yes, return BUSY. + */ + arg.linkid = linkid1; + arg.holder = DATALINK_INVALID_LINKID; + arg.flags = DLADM_OPT_PERSIST; + (void) dladm_walk_datalink_id(i_dladm_aggr_link_hold, &arg, + DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); + if (arg.holder != DATALINK_INVALID_LINKID) + return (DLADM_STATUS_LINKBUSY); + + arg.flags = DLADM_OPT_PERSIST; + (void) dladm_walk_datalink_id(i_dladm_vlan_link_hold, &arg, + DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); + if (arg.holder != DATALINK_INVALID_LINKID) + return (DLADM_STATUS_LINKBUSY); + + /* + * Send DLDIOC_RENAME to request to rename link1's linkid to + * be linkid2. This will check whether link1 is used by any + * aggregations or VLANs, or is held by any application. If yes, + * return failure. + */ + if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) + return (dladm_errno2status(errno)); + + dir.dir_linkid1 = linkid1; + dir.dir_linkid2 = linkid2; + if (i_dladm_ioctl(fd, DLDIOC_RENAME, &dir, sizeof (dir)) < 0) + status = dladm_errno2status(errno); + + if (status != DLADM_STATUS_OK) { + (void) close(fd); + return (status); + } + + /* + * Now change the phymaj, phyinst and devname associated with linkid1 + * to be associated with linkid2. Before doing that, the old active + * linkprop of linkid1 should be deleted. + */ + (void) dladm_set_linkprop(linkid1, NULL, NULL, 0, DLADM_OPT_ACTIVE); + + if (((status = dladm_read_conf(linkid1, &conf1)) != DLADM_STATUS_OK) || + ((status = dladm_get_conf_field(conf1, FDEVNAME, devname, + MAXLINKNAMELEN)) != DLADM_STATUS_OK) || + ((status = dladm_get_conf_field(conf1, FPHYMAJ, &phymaj, + sizeof (uint64_t))) != DLADM_STATUS_OK) || + ((status = dladm_get_conf_field(conf1, FPHYINST, &phyinst, + sizeof (uint64_t))) != DLADM_STATUS_OK) || + ((status = dladm_read_conf(linkid2, &conf2)) != DLADM_STATUS_OK)) { + dir.dir_linkid1 = linkid2; + dir.dir_linkid2 = linkid1; + (void) dladm_init_linkprop(linkid1); + (void) i_dladm_ioctl(fd, DLDIOC_RENAME, &dir, sizeof (dir)); + (void) close(fd); + return (status); + } + (void) close(fd); + + dladm_destroy_conf(conf1); + (void) dladm_set_conf_field(conf2, FDEVNAME, DLADM_TYPE_STR, devname); + (void) dladm_set_conf_field(conf2, FPHYMAJ, DLADM_TYPE_UINT64, &phymaj); + (void) dladm_set_conf_field(conf2, FPHYINST, + DLADM_TYPE_UINT64, &phyinst); + (void) dladm_write_conf(conf2); + dladm_destroy_conf(conf2); + + /* + * Delete link1 and mark link2 up. + */ + (void) dladm_destroy_datalink_id(linkid1, DLADM_OPT_ACTIVE | + DLADM_OPT_PERSIST); + (void) dladm_remove_conf(linkid1); + (void) dladm_up_datalink_id(linkid2); + + /* + * Now generate the RCM_RESOURCE_LINK_NEW sysevent which can be + * consumed by the RCM framework to restore all the datalink and + * IP configuration. + */ + status = DLADM_STATUS_FAILED; + if ((nvlist_alloc(&nvl, 0, 0) != 0) || + (nvlist_add_uint64(nvl, RCM_NV_LINKID, linkid2) != 0)) { + goto done; + } + + if (rcm_alloc_handle(NULL, 0, NULL, &rcm_hdl) != RCM_SUCCESS) + goto done; + + if (rcm_notify_event(rcm_hdl, RCM_RESOURCE_LINK_NEW, 0, nvl, NULL) == + RCM_SUCCESS) { + status = DLADM_STATUS_OK; + } + +done: + if (rcm_hdl != NULL) + (void) rcm_free_handle(rcm_hdl); + if (nvl != NULL) + nvlist_free(nvl); + return (status); +} + +/* + * case 3: rename a non-existent link to a REMOVED physical link. + * Set the removed physical link's device name to link1, so that + * when link1 attaches, it inherits all the link configuration of + * the removed physical link. + */ +static dladm_status_t +i_dladm_rename_link_c3(const char *link1, datalink_id_t linkid2) +{ + dladm_conf_t conf; + dladm_status_t status; + + if (!dladm_valid_linkname(link1)) + return (DLADM_STATUS_LINKINVAL); + + status = dladm_read_conf(linkid2, &conf); + if (status != DLADM_STATUS_OK) + goto done; + + if ((status = dladm_set_conf_field(conf, FDEVNAME, DLADM_TYPE_STR, + link1)) == DLADM_STATUS_OK) { + status = dladm_write_conf(conf); + } + + dladm_destroy_conf(conf); + +done: + return (status); +} + +dladm_status_t +dladm_rename_link(const char *link1, const char *link2) +{ + datalink_id_t linkid1 = DATALINK_INVALID_LINKID; + datalink_id_t linkid2 = DATALINK_INVALID_LINKID; + uint32_t flags1, flags2; + datalink_class_t class1, class2; + uint32_t media1, media2; + boolean_t remphy2 = B_FALSE; + dladm_status_t status; + + (void) dladm_name2info(link1, &linkid1, &flags1, &class1, &media1); + if ((dladm_name2info(link2, &linkid2, &flags2, &class2, &media2) == + DLADM_STATUS_OK) && (class2 == DATALINK_CLASS_PHYS) && + (flags2 == DLADM_OPT_PERSIST)) { + /* + * see whether link2 is a removed physical link. + */ + remphy2 = B_TRUE; + } + + if (linkid1 != DATALINK_INVALID_LINKID) { + if (linkid2 == DATALINK_INVALID_LINKID) { + /* + * case 1: rename an existing link to a link that + * does not exist. + */ + status = i_dladm_rename_link_c1(linkid1, link1, link2, + flags1); + } else if (remphy2) { + /* + * case 2: rename an available link to a REMOVED + * physical link. Return failure if link1 is not + * an active physical link. + */ + if ((class1 != class2) || (media1 != media2) || + !(flags1 & DLADM_OPT_ACTIVE)) { + status = DLADM_STATUS_BADARG; + } else { + status = i_dladm_rename_link_c2(linkid1, + linkid2); + } + } else { + status = DLADM_STATUS_EXIST; + } + } else if (remphy2) { + status = i_dladm_rename_link_c3(link1, linkid2); + } else { + status = DLADM_STATUS_NOTFOUND; + } + return (status); +} + +typedef struct consumer_del_phys_arg_s { + datalink_id_t linkid; +} consumer_del_phys_arg_t; + +static int +i_dladm_vlan_link_del(datalink_id_t vlanid, void *arg) +{ + consumer_del_phys_arg_t *del_arg = arg; + dladm_vlan_attr_t vinfo; + dladm_status_t status; + + status = dladm_vlan_info(vlanid, &vinfo, DLADM_OPT_PERSIST); + if (status != DLADM_STATUS_OK) + return (DLADM_WALK_CONTINUE); + + if (vinfo.dv_linkid == del_arg->linkid) + (void) dladm_vlan_delete(vlanid, DLADM_OPT_PERSIST); + return (DLADM_WALK_CONTINUE); +} + +static int +i_dladm_aggr_link_del(datalink_id_t aggrid, void *arg) +{ + consumer_del_phys_arg_t *del_arg = arg; + dladm_aggr_grp_attr_t ginfo; + dladm_status_t status; + dladm_aggr_port_attr_db_t port[1]; + int i; + + status = dladm_aggr_info(aggrid, &ginfo, DLADM_OPT_PERSIST); + if (status != DLADM_STATUS_OK) + return (DLADM_WALK_CONTINUE); + + for (i = 0; i < ginfo.lg_nports; i++) + if (ginfo.lg_ports[i].lp_linkid == del_arg->linkid) + break; + + if (i != ginfo.lg_nports) { + if (ginfo.lg_nports == 1 && i == 0) { + consumer_del_phys_arg_t aggr_del_arg; + + /* + * First delete all the VLANs on this aggregation, then + * delete the aggregation itself. + */ + aggr_del_arg.linkid = aggrid; + (void) dladm_walk_datalink_id(i_dladm_vlan_link_del, + &aggr_del_arg, DATALINK_CLASS_VLAN, + DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); + (void) dladm_aggr_delete(aggrid, DLADM_OPT_PERSIST); + } else { + port[0].lp_linkid = del_arg->linkid; + (void) dladm_aggr_remove(aggrid, 1, port, + DLADM_OPT_PERSIST); + } + } + return (DLADM_WALK_CONTINUE); +} + +typedef struct del_phys_arg_s { + dladm_status_t rval; +} del_phys_arg_t; + +static int +i_dladm_phys_delete(datalink_id_t linkid, void *arg) +{ + uint32_t flags; + datalink_class_t class; + uint32_t media; + dladm_status_t status = DLADM_STATUS_OK; + del_phys_arg_t *del_phys_arg = arg; + consumer_del_phys_arg_t del_arg; + + if ((status = dladm_datalink_id2info(linkid, &flags, &class, + &media, NULL, 0)) != DLADM_STATUS_OK) { + goto done; + } + + /* + * see whether this link is a removed physical link. + */ + if ((class != DATALINK_CLASS_PHYS) || !(flags & DLADM_OPT_PERSIST) || + (flags & DLADM_OPT_ACTIVE)) { + status = DLADM_STATUS_BADARG; + goto done; + } + + if (media == DL_ETHER) { + del_arg.linkid = linkid; + (void) dladm_walk_datalink_id(i_dladm_aggr_link_del, &del_arg, + DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, + DLADM_OPT_PERSIST); + (void) dladm_walk_datalink_id(i_dladm_vlan_link_del, &del_arg, + DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, + DLADM_OPT_PERSIST); + } + + (void) dladm_destroy_datalink_id(linkid, DLADM_OPT_PERSIST); + (void) dladm_remove_conf(linkid); + +done: + del_phys_arg->rval = status; + return (DLADM_WALK_CONTINUE); +} + +dladm_status_t +dladm_phys_delete(datalink_id_t linkid) +{ + del_phys_arg_t arg = {DLADM_STATUS_OK}; + + if (linkid == DATALINK_ALL_LINKID) { + (void) dladm_walk_datalink_id(i_dladm_phys_delete, &arg, + DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, + DLADM_OPT_PERSIST); + return (DLADM_STATUS_OK); + } else { + (void) i_dladm_phys_delete(linkid, &arg); + return (arg.rval); + } +} + +dladm_status_t +dladm_phys_info(datalink_id_t linkid, dladm_phys_attr_t *dpap, uint32_t flags) +{ + dladm_status_t status; + + assert(flags == DLADM_OPT_ACTIVE || flags == DLADM_OPT_PERSIST); + + switch (flags) { + case DLADM_OPT_PERSIST: { + dladm_conf_t conf; + + status = dladm_read_conf(linkid, &conf); + if (status != DLADM_STATUS_OK) + return (status); + + status = dladm_get_conf_field(conf, FDEVNAME, dpap->dp_dev, + MAXLINKNAMELEN); + dladm_destroy_conf(conf); + return (status); + } + case DLADM_OPT_ACTIVE: { + dld_ioc_phys_attr_t dip; + int fd; + + if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) + return (dladm_errno2status(errno)); + + dip.dip_linkid = linkid; + if (i_dladm_ioctl(fd, DLDIOC_PHYS_ATTR, &dip, sizeof (dip)) + < 0) { + status = dladm_errno2status(errno); + (void) close(fd); + return (status); + } + (void) close(fd); + dpap->dp_novanity = dip.dip_novanity; + (void) strlcpy(dpap->dp_dev, dip.dip_dev, MAXLINKNAMELEN); + return (DLADM_STATUS_OK); + } + default: + return (DLADM_STATUS_BADARG); + } +} + +typedef struct i_walk_dev_state_s { + const char *devname; + datalink_id_t linkid; + boolean_t found; +} i_walk_dev_state_t; + int -dladm_rele_link(const char *name, zoneid_t zoneid, boolean_t docheck) +i_dladm_walk_dev2linkid(datalink_id_t linkid, void *arg) +{ + dladm_phys_attr_t dpa; + dladm_status_t status; + i_walk_dev_state_t *statep = arg; + + status = dladm_phys_info(linkid, &dpa, DLADM_OPT_PERSIST); + if ((status == DLADM_STATUS_OK) && + (strcmp(statep->devname, dpa.dp_dev) == 0)) { + statep->found = B_TRUE; + statep->linkid = linkid; + return (DLADM_WALK_TERMINATE); + } + return (DLADM_WALK_CONTINUE); +} + +/* + * Get the linkid from the physical device name. + */ +dladm_status_t +dladm_dev2linkid(const char *devname, datalink_id_t *linkidp) { - return (i_dladm_rele_link(name, zoneid, docheck)); + i_walk_dev_state_t state; + + state.found = B_FALSE; + state.devname = devname; + + (void) dladm_walk_datalink_id(i_dladm_walk_dev2linkid, &state, + DATALINK_CLASS_PHYS, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); + if (state.found == B_TRUE) { + *linkidp = state.linkid; + return (DLADM_STATUS_OK); + } else { + return (dladm_errno2status(ENOENT)); + } +} + +static int +parse_devname(const char *devname, char *driver, uint_t *ppa, size_t maxlen) +{ + char *cp, *tp; + int len; + + /* + * device name length must not be 0, and it must end with digit. + */ + if (((len = strlen(devname)) == 0) || !isdigit(devname[len - 1])) + return (EINVAL); + + (void) strlcpy(driver, devname, maxlen); + cp = (char *)&driver[len - 1]; + + for (tp = cp; isdigit(*tp); tp--) { + if (tp <= driver) + return (EINVAL); + } + + *ppa = atoi(tp + 1); + *(tp + 1) = '\0'; + return (0); +} + +dladm_status_t +dladm_linkid2legacyname(datalink_id_t linkid, char *dev, size_t len) +{ + char devname[MAXLINKNAMELEN]; + uint16_t vid = VLAN_ID_NONE; + datalink_class_t class; + dladm_status_t status; + + status = dladm_datalink_id2info(linkid, NULL, &class, NULL, NULL, 0); + if (status != DLADM_STATUS_OK) + goto done; + + /* + * If this is a VLAN, we must first determine the class and linkid of + * the link the VLAN has been created over. + */ + if (class == DATALINK_CLASS_VLAN) { + dladm_vlan_attr_t dva; + + status = dladm_vlan_info(linkid, &dva, DLADM_OPT_ACTIVE); + if (status != DLADM_STATUS_OK) + goto done; + linkid = dva.dv_linkid; + vid = dva.dv_vid; + + if ((status = dladm_datalink_id2info(linkid, NULL, &class, NULL, + NULL, 0)) != DLADM_STATUS_OK) { + goto done; + } + } + + switch (class) { + case DATALINK_CLASS_AGGR: { + dladm_aggr_grp_attr_t dga; + + status = dladm_aggr_info(linkid, &dga, DLADM_OPT_ACTIVE); + if (status != DLADM_STATUS_OK) + goto done; + + if (dga.lg_key == 0) { + /* + * If the key was not specified when the aggregation + * is created, we cannot guess its /dev node name. + */ + status = DLADM_STATUS_BADARG; + goto done; + } + (void) snprintf(devname, MAXLINKNAMELEN, "aggr%d", dga.lg_key); + break; + } + case DATALINK_CLASS_PHYS: { + dladm_phys_attr_t dpa; + + status = dladm_phys_info(linkid, &dpa, DLADM_OPT_PERSIST); + if (status != DLADM_STATUS_OK) + goto done; + + (void) strlcpy(devname, dpa.dp_dev, MAXLINKNAMELEN); + break; + } + default: + status = DLADM_STATUS_BADARG; + goto done; + } + + if (vid != VLAN_ID_NONE) { + char drv[MAXNAMELEN]; + uint_t ppa; + + if (parse_devname(devname, drv, &ppa, MAXNAMELEN) != 0) { + status = DLADM_STATUS_BADARG; + goto done; + } + if (snprintf(dev, len, "%s%d", drv, vid * 1000 + ppa) >= len) + status = DLADM_STATUS_TOOSMALL; + } else { + if (strlcpy(dev, devname, len) >= len) + status = DLADM_STATUS_TOOSMALL; + } + +done: + return (status); } diff --git a/usr/src/lib/libdladm/common/libdllink.h b/usr/src/lib/libdladm/common/libdllink.h index 12327456a5..2b762ff6d8 100644 --- a/usr/src/lib/libdladm/common/libdllink.h +++ b/usr/src/lib/libdladm/common/libdllink.h @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -29,14 +29,12 @@ #pragma ident "%Z%%M% %I% %E% SMI" /* - * This file includes strcutures, macros and routines used by general - * link administration, which applies not limited to one specific - * type of link. + * This file includes structures, macros and routines used by general + * link administration (i.e. not limited to one specific type of link). */ #include <sys/types.h> #include <sys/param.h> -#include <sys/mac.h> #include <libdladm.h> #ifdef __cplusplus @@ -44,11 +42,25 @@ extern "C" { #endif typedef struct dladm_attr { - char da_dev[MAXNAMELEN]; uint_t da_max_sdu; - uint16_t da_vid; } dladm_attr_t; +typedef struct dladm_phys_attr { + char dp_dev[MAXLINKNAMELEN]; + /* + * Whether this physical link supports vanity naming (links with media + * types not supported by GLDv3 don't have vanity naming support). + */ + boolean_t dp_novanity; +} dladm_phys_attr_t; + +typedef enum { + DLADM_PROP_VAL_CURRENT = 1, + DLADM_PROP_VAL_DEFAULT, + DLADM_PROP_VAL_MODIFIABLE, + DLADM_PROP_VAL_PERSISTENT +} dladm_prop_type_t; + /* * Maximum size of secobj value. Note that it should not be greater than * DLD_SECOBJ_VAL_MAX. @@ -61,26 +73,31 @@ typedef struct dladm_attr { */ #define DLADM_SECOBJ_NAME_MAX 32 -#define DLADM_PROP_VAL_MAX 25 +#define DLADM_MAX_PROP_VALCNT 32 +#define DLADM_PROP_VAL_MAX 128 #define DLADM_SECOBJ_CLASS_WEP 0 #define DLADM_SECOBJ_CLASS_WPA 1 typedef int dladm_secobj_class_t; -typedef void (dladm_walkcb_t)(void *, const char *); +typedef int (dladm_walkcb_t)(const char *, void *); + +extern dladm_status_t dladm_walk(dladm_walkcb_t *, void *, datalink_class_t, + datalink_media_t, uint32_t); +extern dladm_status_t dladm_mac_walk(dladm_walkcb_t *, void *); +extern dladm_status_t dladm_info(datalink_id_t, dladm_attr_t *); +extern dladm_status_t dladm_setzid(const char *, zoneid_t); +extern dladm_status_t dladm_getzid(datalink_id_t, zoneid_t *); -extern int dladm_walk(dladm_walkcb_t *, void *); -extern int dladm_mac_walk(void (*fn)(void *, const char *), void *); -extern int dladm_info(const char *, dladm_attr_t *); -extern int dladm_hold_link(const char *, zoneid_t, boolean_t); -extern int dladm_rele_link(const char *, zoneid_t, boolean_t); +extern dladm_status_t dladm_rename_link(const char *, const char *); -extern dladm_status_t dladm_set_prop(const char *, const char *, - char **, uint_t, uint_t, char **); -extern dladm_status_t dladm_get_prop(const char *, dladm_prop_type_t, +extern dladm_status_t dladm_set_linkprop(datalink_id_t, const char *, + char **, uint_t, uint_t); +extern dladm_status_t dladm_get_linkprop(datalink_id_t, dladm_prop_type_t, const char *, char **, uint_t *); -extern dladm_status_t dladm_walk_prop(const char *, void *, - boolean_t (*)(void *, const char *)); +extern dladm_status_t dladm_walk_linkprop(datalink_id_t, void *, + int (*)(datalink_id_t, const char *, void *)); + extern dladm_status_t dladm_set_secobj(const char *, dladm_secobj_class_t, uint8_t *, uint_t, uint_t); extern dladm_status_t dladm_get_secobj(const char *, dladm_secobj_class_t *, @@ -95,9 +112,40 @@ extern const char *dladm_secobjclass2str(dladm_secobj_class_t, char *); extern dladm_status_t dladm_str2secobjclass(const char *, dladm_secobj_class_t *); -extern dladm_status_t dladm_init_linkprop(void); +extern dladm_status_t dladm_init_linkprop(datalink_id_t); extern dladm_status_t dladm_init_secobj(void); +extern dladm_status_t dladm_create_datalink_id(const char *, datalink_class_t, + uint_t, uint32_t, datalink_id_t *); +extern dladm_status_t dladm_destroy_datalink_id(datalink_id_t, uint32_t); +extern dladm_status_t dladm_remap_datalink_id(datalink_id_t, const char *); +extern dladm_status_t dladm_up_datalink_id(datalink_id_t); +extern dladm_status_t dladm_name2info(const char *, datalink_id_t *, + uint32_t *, datalink_class_t *, uint32_t *); +extern dladm_status_t dladm_datalink_id2info(datalink_id_t, uint32_t *, + datalink_class_t *, uint32_t *, char *, size_t); +extern dladm_status_t dladm_walk_datalink_id(int (*)(datalink_id_t, void *), + void *, datalink_class_t, datalink_media_t, + uint32_t); +extern dladm_status_t dladm_create_conf(const char *, datalink_id_t, + datalink_class_t, uint32_t, dladm_conf_t *); +extern dladm_status_t dladm_read_conf(datalink_id_t, dladm_conf_t *); +extern dladm_status_t dladm_write_conf(dladm_conf_t); +extern dladm_status_t dladm_remove_conf(datalink_id_t); +extern void dladm_destroy_conf(dladm_conf_t); +extern dladm_status_t dladm_get_conf_field(dladm_conf_t, const char *, + void *, size_t); +extern dladm_status_t dladm_set_conf_field(dladm_conf_t, const char *, + dladm_datatype_t, const void *); +extern dladm_status_t dladm_unset_conf_field(dladm_conf_t, const char *); + +extern dladm_status_t dladm_dev2linkid(const char *, datalink_id_t *); +extern dladm_status_t dladm_linkid2legacyname(datalink_id_t, char *, size_t); +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); + #ifdef __cplusplus } #endif diff --git a/usr/src/lib/libdladm/common/libdlmgmt.c b/usr/src/lib/libdladm/common/libdlmgmt.c new file mode 100644 index 0000000000..1826edf810 --- /dev/null +++ b/usr/src/lib/libdladm/common/libdlmgmt.c @@ -0,0 +1,676 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * 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. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <door.h> +#include <errno.h> +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <strings.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/aggr.h> +#include <fcntl.h> +#include <libdladm.h> +#include <libdladm_impl.h> +#include <libdllink.h> +#include <libdlmgmt.h> + +/* + * Table of data type sizes indexed by dladm_datatype_t. + */ +static size_t dladm_datatype_size[] = { + 0, /* DLADM_TYPE_STR, use strnlen() */ + sizeof (boolean_t), /* DLADM_TYPE_BOOLEAN */ + sizeof (uint64_t) /* DLADM_TYPE_UINT64 */ +}; + +static dladm_status_t +dladm_door_call(void *arg, size_t asize, void *rbuf, size_t *rsizep) +{ + door_arg_t darg; + dlmgmt_retval_t *retvalp = rbuf; + int fd; + dladm_status_t status = DLADM_STATUS_OK; + + if ((fd = open(DLMGMT_DOOR, O_RDONLY)) == -1) + return (dladm_errno2status(errno)); + + darg.data_ptr = arg; + darg.data_size = asize; + darg.desc_ptr = NULL; + darg.desc_num = 0; + darg.rbuf = rbuf; + darg.rsize = *rsizep; + + if (door_call(fd, &darg) == -1) + status = dladm_errno2status(errno); + (void) close(fd); + + if (status != DLADM_STATUS_OK) + return (status); + + if (darg.rbuf != rbuf) { + /* + * The size of the input rbuf is not big enough so that + * the door allocate the rbuf itself. In this case, simply + * think something wrong with the door call. + */ + (void) munmap(darg.rbuf, darg.rsize); + return (DLADM_STATUS_TOOSMALL); + } + if (darg.rsize > *rsizep || darg.rsize < sizeof (uint_t)) + return (DLADM_STATUS_FAILED); + + if (retvalp->lr_err != 0) + status = dladm_errno2status(retvalp->lr_err); + else + *rsizep = darg.rsize; + return (status); +} + +/* + * Allocate a new linkid with the given name. Return the new linkid. + */ +dladm_status_t +dladm_create_datalink_id(const char *link, datalink_class_t class, + uint32_t media, uint32_t flags, datalink_id_t *linkidp) +{ + dlmgmt_door_createid_t createid; + dlmgmt_createid_retval_t retval; + uint32_t dlmgmt_flags; + dladm_status_t status; + size_t rsize; + + if (link == NULL || *link == '\0' || class == DATALINK_CLASS_ALL || + !(flags & (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST)) || + linkidp == NULL) { + return (DLADM_STATUS_BADARG); + } + + dlmgmt_flags = (flags & DLADM_OPT_ACTIVE) ? DLMGMT_ACTIVE : 0; + dlmgmt_flags |= (flags & DLADM_OPT_PERSIST) ? DLMGMT_PERSIST : 0; + + (void) strlcpy(createid.ld_link, link, MAXLINKNAMELEN); + createid.ld_class = class; + createid.ld_media = media; + createid.ld_flags = dlmgmt_flags; + createid.ld_cmd = DLMGMT_CMD_CREATE_LINKID; + createid.ld_prefix = (flags & DLADM_OPT_PREFIX); + rsize = sizeof (retval); + + status = dladm_door_call(&createid, sizeof (createid), &retval, &rsize); + if (status != DLADM_STATUS_OK) + return (status); + + if (rsize != sizeof (retval)) + return (DLADM_STATUS_BADARG); + + *linkidp = retval.lr_linkid; + return (DLADM_STATUS_OK); +} + +/* + * Destroy the given link ID. + */ +dladm_status_t +dladm_destroy_datalink_id(datalink_id_t linkid, uint32_t flags) +{ + dlmgmt_door_destroyid_t destroyid; + dlmgmt_destroyid_retval_t retval; + uint32_t dlmgmt_flags; + size_t rsize; + dladm_status_t status; + + dlmgmt_flags = (flags & DLADM_OPT_ACTIVE) ? DLMGMT_ACTIVE : 0; + dlmgmt_flags |= ((flags & DLADM_OPT_PERSIST) ? DLMGMT_PERSIST : 0); + + destroyid.ld_cmd = DLMGMT_CMD_DESTROY_LINKID; + destroyid.ld_linkid = linkid; + destroyid.ld_flags = dlmgmt_flags; + rsize = sizeof (retval); + + status = dladm_door_call(&destroyid, sizeof (destroyid), &retval, + &rsize); + if (status != DLADM_STATUS_OK) + return (status); + + if (rsize != sizeof (retval)) + return (DLADM_STATUS_BADARG); + + return (DLADM_STATUS_OK); +} + +/* + * Remap a given link ID to a new name. + */ +dladm_status_t +dladm_remap_datalink_id(datalink_id_t linkid, const char *link) +{ + dlmgmt_door_remapid_t remapid; + dlmgmt_remapid_retval_t retval; + size_t rsize; + dladm_status_t status; + + remapid.ld_cmd = DLMGMT_CMD_REMAP_LINKID; + remapid.ld_linkid = linkid; + (void) strlcpy(remapid.ld_link, link, MAXLINKNAMELEN); + rsize = sizeof (retval); + + status = dladm_door_call(&remapid, sizeof (remapid), &retval, &rsize); + if (status != DLADM_STATUS_OK) + return (status); + + if (rsize != sizeof (retval)) + return (DLADM_STATUS_BADARG); + + return (DLADM_STATUS_OK); +} + +/* + * Make a given link ID active. + */ +dladm_status_t +dladm_up_datalink_id(datalink_id_t linkid) +{ + dlmgmt_door_upid_t upid; + dlmgmt_upid_retval_t retval; + size_t rsize; + dladm_status_t status; + + upid.ld_cmd = DLMGMT_CMD_UP_LINKID; + upid.ld_linkid = linkid; + rsize = sizeof (retval); + + status = dladm_door_call(&upid, sizeof (upid), &retval, &rsize); + if (status != DLADM_STATUS_OK) + return (status); + + if (rsize != sizeof (retval)) + return (DLADM_STATUS_BADARG); + + return (DLADM_STATUS_OK); +} + +/* + * Create a new link with the given name. Return the new link's handle + */ +dladm_status_t +dladm_create_conf(const char *link, datalink_id_t linkid, + datalink_class_t class, uint32_t media, dladm_conf_t *confp) +{ + dlmgmt_door_createconf_t createconf; + dlmgmt_createconf_retval_t retval; + dladm_status_t status; + size_t rsize; + + if (link == NULL || *link == '\0' || confp == NULL) + return (DLADM_STATUS_BADARG); + + (void) strlcpy(createconf.ld_link, link, MAXLINKNAMELEN); + createconf.ld_class = class; + createconf.ld_media = media; + createconf.ld_linkid = linkid; + createconf.ld_cmd = DLMGMT_CMD_CREATECONF; + rsize = sizeof (retval); + + status = dladm_door_call(&createconf, sizeof (createconf), &retval, + &rsize); + if (status != DLADM_STATUS_OK) + return (status); + + if (rsize != sizeof (retval)) + return (DLADM_STATUS_BADARG); + + *confp = retval.lr_conf; + return (DLADM_STATUS_OK); +} + +/* + * An active physical link reported by the dlmgmtd daemon might not be active + * anymore as this link might be removed during system shutdown. Check its + * real status by calling dladm_phys_info(). + */ +dladm_status_t +i_dladm_phys_status(datalink_id_t linkid, uint32_t *flagsp) +{ + dladm_phys_attr_t dpa; + dladm_status_t status; + + assert((*flagsp) & DLMGMT_ACTIVE); + + status = dladm_phys_info(linkid, &dpa, DLADM_OPT_ACTIVE); + if (status == DLADM_STATUS_NOTFOUND) { + /* + * No active status, this link was removed. Update its status + * in the daemon and delete all active linkprops. + */ + (void) dladm_destroy_datalink_id(linkid, DLADM_OPT_ACTIVE); + (void) dladm_set_linkprop(linkid, NULL, NULL, 0, + DLADM_OPT_ACTIVE); + + (*flagsp) &= ~DLMGMT_ACTIVE; + status = DLADM_STATUS_OK; + } + return (status); +} + +/* + * Walk each entry in the data link configuration repository and + * call fn on the linkid and arg. + */ +dladm_status_t +dladm_walk_datalink_id(int (*fn)(datalink_id_t, void *), void *argp, + datalink_class_t class, datalink_media_t dmedia, uint32_t flags) +{ + dlmgmt_door_getnext_t getnext; + dlmgmt_getnext_retval_t retval; + uint32_t dlmgmt_flags; + size_t rsize; + datalink_id_t linkid = DATALINK_INVALID_LINKID; + dladm_status_t status = DLADM_STATUS_OK; + + if (fn == NULL) + return (DLADM_STATUS_BADARG); + + dlmgmt_flags = (flags & DLADM_OPT_ACTIVE) ? DLMGMT_ACTIVE : 0; + dlmgmt_flags |= ((flags & DLADM_OPT_PERSIST) ? DLMGMT_PERSIST : 0); + + getnext.ld_cmd = DLMGMT_CMD_GETNEXT; + getnext.ld_class = class; + getnext.ld_dmedia = dmedia; + getnext.ld_flags = dlmgmt_flags; + rsize = sizeof (retval); + + do { + getnext.ld_linkid = linkid; + status = dladm_door_call(&getnext, sizeof (getnext), + &retval, &rsize); + if (status != DLADM_STATUS_OK) { + /* + * done with walking + */ + break; + } + + if (rsize != sizeof (retval)) { + status = DLADM_STATUS_BADARG; + break; + } + + linkid = retval.lr_linkid; + if ((retval.lr_class == DATALINK_CLASS_PHYS) && + (retval.lr_flags & DLMGMT_ACTIVE)) { + /* + * An active physical link reported by the dlmgmtd + * daemon might not be active anymore. Check its + * real status. + */ + if (i_dladm_phys_status(linkid, &retval.lr_flags) != + DLADM_STATUS_OK) { + continue; + } + + if (!(dlmgmt_flags & retval.lr_flags)) + continue; + } + + if (fn(linkid, argp) == DLADM_WALK_TERMINATE) + break; + } while (linkid != DATALINK_INVALID_LINKID); + + return (status); +} + +/* + * Get the link properties structure for the given link. + */ +dladm_status_t +dladm_read_conf(datalink_id_t linkid, dladm_conf_t *confp) +{ + dlmgmt_door_readconf_t readconf; + dlmgmt_readconf_retval_t retval; + dladm_status_t status; + size_t rsize; + + if (linkid == DATALINK_INVALID_LINKID || confp == NULL) + return (DLADM_STATUS_BADARG); + + readconf.ld_linkid = linkid; + readconf.ld_cmd = DLMGMT_CMD_READCONF; + rsize = sizeof (retval); + + status = dladm_door_call(&readconf, sizeof (readconf), &retval, + &rsize); + if (status != DLADM_STATUS_OK) + return (status); + + if (rsize != sizeof (retval)) + return (DLADM_STATUS_BADARG); + + *confp = retval.lr_conf; + return (DLADM_STATUS_OK); +} + +/* + * Commit the given link to the data link configuration repository so + * that it will persist across reboots. + */ +dladm_status_t +dladm_write_conf(dladm_conf_t conf) +{ + dlmgmt_door_writeconf_t writeconf; + dlmgmt_writeconf_retval_t retval; + dladm_status_t status; + size_t rsize; + + if (conf == DLADM_INVALID_CONF) + return (DLADM_STATUS_BADARG); + + writeconf.ld_cmd = DLMGMT_CMD_WRITECONF; + writeconf.ld_conf = conf; + rsize = sizeof (retval); + + status = dladm_door_call(&writeconf, sizeof (writeconf), &retval, + &rsize); + if (status != DLADM_STATUS_OK) + return (status); + + if (rsize != sizeof (retval)) + return (DLADM_STATUS_BADARG); + + return (DLADM_STATUS_OK); +} + +/* + * Given a link ID and a key, get the matching information from + * data link configuration repository. + */ +dladm_status_t +dladm_get_conf_field(dladm_conf_t conf, const char *attr, void *attrval, + size_t attrsz) +{ + dlmgmt_door_getattr_t getattr; + dlmgmt_getattr_retval_t *retvalp; + dladm_status_t status = DLADM_STATUS_OK; + size_t oldsize, size; + + if (conf == DLADM_INVALID_CONF || attrval == NULL || + attrsz == 0 || attr == NULL || *attr == '\0') { + return (DLADM_STATUS_BADARG); + } + + getattr.ld_cmd = DLMGMT_CMD_GETATTR; + getattr.ld_conf = conf; + (void) strlcpy(getattr.ld_attr, attr, MAXLINKATTRLEN); + + oldsize = size = attrsz + sizeof (dlmgmt_getattr_retval_t) - 1; + if ((retvalp = calloc(1, oldsize)) == NULL) + return (DLADM_STATUS_NOMEM); + + status = dladm_door_call(&getattr, sizeof (getattr), retvalp, &size); + if (status != DLADM_STATUS_OK) + goto done; + + assert(size <= oldsize); + size = size + 1 - sizeof (dlmgmt_getattr_retval_t); + bcopy(retvalp->lr_attr, attrval, size); +done: + free(retvalp); + return (status); +} + +/* + * Get the link ID that is associated with the given name. + */ +dladm_status_t +dladm_name2info(const char *link, datalink_id_t *linkidp, uint32_t *flagp, + datalink_class_t *classp, uint32_t *mediap) +{ + dlmgmt_door_getlinkid_t getlinkid; + dlmgmt_getlinkid_retval_t retval; + datalink_id_t linkid; + size_t rsize; + dladm_status_t status; + + getlinkid.ld_cmd = DLMGMT_CMD_GETLINKID; + (void) strlcpy(getlinkid.ld_link, link, MAXLINKNAMELEN); + rsize = sizeof (retval); + + status = dladm_door_call(&getlinkid, sizeof (getlinkid), &retval, + &rsize); + if (status != DLADM_STATUS_OK) + return (status); + + if (rsize != sizeof (retval)) + return (DLADM_STATUS_BADARG); + + linkid = retval.lr_linkid; + if (retval.lr_class == DATALINK_CLASS_PHYS && + retval.lr_flags & DLMGMT_ACTIVE) { + /* + * An active physical link reported by the dlmgmtd daemon + * might not be active anymore. Check and set its real status. + */ + status = i_dladm_phys_status(linkid, &retval.lr_flags); + if (status != DLADM_STATUS_OK) + return (status); + } + + if (linkidp != NULL) + *linkidp = linkid; + if (flagp != NULL) { + *flagp = retval.lr_flags & DLMGMT_ACTIVE ? DLADM_OPT_ACTIVE : 0; + *flagp |= (retval.lr_flags & DLMGMT_PERSIST) ? + DLADM_OPT_PERSIST : 0; + } + if (classp != NULL) + *classp = retval.lr_class; + if (mediap != NULL) + *mediap = retval.lr_media; + + return (DLADM_STATUS_OK); +} + +/* + * Get the link name that is associated with the given id. + */ +dladm_status_t +dladm_datalink_id2info(datalink_id_t linkid, uint32_t *flagp, + datalink_class_t *classp, uint32_t *mediap, char *link, size_t len) +{ + dlmgmt_door_getname_t getname; + dlmgmt_getname_retval_t retval; + size_t rsize; + dladm_status_t status; + + if ((linkid == DATALINK_INVALID_LINKID) || (link != NULL && len == 0) || + (link == NULL && len != 0)) { + return (DLADM_STATUS_BADARG); + } + + getname.ld_cmd = DLMGMT_CMD_GETNAME; + getname.ld_linkid = linkid; + rsize = sizeof (retval); + status = dladm_door_call(&getname, sizeof (getname), &retval, &rsize); + if (status != DLADM_STATUS_OK) + return (status); + + if ((rsize != sizeof (retval)) || + (len != 0 && (strlen(retval.lr_link) + 1 > len))) { + return (DLADM_STATUS_TOOSMALL); + } + + if (retval.lr_class == DATALINK_CLASS_PHYS && + retval.lr_flags & DLMGMT_ACTIVE) { + /* + * An active physical link reported by the dlmgmtd daemon + * might not be active anymore. Check and set its real status. + */ + status = i_dladm_phys_status(linkid, &retval.lr_flags); + if (status != DLADM_STATUS_OK) + return (status); + } + + if (link != NULL) + (void) strlcpy(link, retval.lr_link, len); + if (classp != NULL) + *classp = retval.lr_class; + if (mediap != NULL) + *mediap = retval.lr_media; + if (flagp != NULL) { + *flagp = retval.lr_flags & DLMGMT_ACTIVE ? + DLADM_OPT_ACTIVE : 0; + *flagp |= (retval.lr_flags & DLMGMT_PERSIST) ? + DLADM_OPT_PERSIST : 0; + } + return (DLADM_STATUS_OK); +} + +/* + * Set the given attr with the given attrval for the given link. + */ +dladm_status_t +dladm_set_conf_field(dladm_conf_t conf, const char *attr, + dladm_datatype_t type, const void *attrval) +{ + dlmgmt_door_setattr_t *setattrp; + dlmgmt_setattr_retval_t retval; + dladm_status_t status; + size_t asize, attrsz, rsize; + + if (attr == NULL || attr == '\0' || attrval == NULL) + return (DLADM_STATUS_BADARG); + + if (type == DLADM_TYPE_STR) + attrsz = strlen(attrval) + 1; + else + attrsz = dladm_datatype_size[type]; + + asize = sizeof (dlmgmt_door_setattr_t) + attrsz - 1; + if ((setattrp = calloc(1, asize)) == NULL) + return (DLADM_STATUS_NOMEM); + + setattrp->ld_cmd = DLMGMT_CMD_SETATTR; + setattrp->ld_conf = conf; + (void) strlcpy(setattrp->ld_attr, attr, MAXLINKATTRLEN); + setattrp->ld_attrsz = attrsz; + setattrp->ld_type = type; + bcopy(attrval, &setattrp->ld_attrval, attrsz); + rsize = sizeof (retval); + + status = dladm_door_call(setattrp, asize, &retval, &rsize); + if (status != DLADM_STATUS_OK) + goto done; + + if (rsize != sizeof (retval)) + status = DLADM_STATUS_BADARG; + +done: + free(setattrp); + return (status); +} + +/* + * Unset the given attr the given link. + */ +dladm_status_t +dladm_unset_conf_field(dladm_conf_t conf, const char *attr) +{ + dlmgmt_door_unsetattr_t unsetattr; + dlmgmt_unsetattr_retval_t retval; + dladm_status_t status; + size_t rsize; + + if (attr == NULL || attr == '\0') + return (DLADM_STATUS_BADARG); + + unsetattr.ld_cmd = DLMGMT_CMD_UNSETATTR; + unsetattr.ld_conf = conf; + (void) strlcpy(unsetattr.ld_attr, attr, MAXLINKATTRLEN); + rsize = sizeof (retval); + + status = dladm_door_call(&unsetattr, sizeof (unsetattr), &retval, + &rsize); + if (status != DLADM_STATUS_OK) + return (status); + + if (rsize != sizeof (retval)) + return (DLADM_STATUS_BADARG); + + return (DLADM_STATUS_OK); +} + +/* + * Remove the given link ID and its entry from the data link configuration + * repository. + */ +dladm_status_t +dladm_remove_conf(datalink_id_t linkid) +{ + dlmgmt_door_removeconf_t removeconf; + dlmgmt_removeconf_retval_t retval; + size_t rsize; + dladm_status_t status; + + removeconf.ld_cmd = DLMGMT_CMD_REMOVECONF; + removeconf.ld_linkid = linkid; + rsize = sizeof (retval); + + status = dladm_door_call(&removeconf, sizeof (removeconf), &retval, + &rsize); + if (status != DLADM_STATUS_OK) + return (status); + + if (rsize != sizeof (retval)) + return (DLADM_STATUS_BADARG); + + return (DLADM_STATUS_OK); +} + +/* + * Free the contents of the link structure. + */ +void +dladm_destroy_conf(dladm_conf_t conf) +{ + dlmgmt_door_destroyconf_t destroyconf; + dlmgmt_destroyconf_retval_t retval; + size_t rsize; + + if (conf == DLADM_INVALID_CONF) + return; + + destroyconf.ld_cmd = DLMGMT_CMD_DESTROYCONF; + destroyconf.ld_conf = conf; + rsize = sizeof (retval); + + (void) dladm_door_call(&destroyconf, sizeof (destroyconf), &retval, + &rsize); +} diff --git a/usr/src/lib/libdladm/common/libdlmgmt.h b/usr/src/lib/libdladm/common/libdlmgmt.h new file mode 100644 index 0000000000..0459d7360b --- /dev/null +++ b/usr/src/lib/libdladm/common/libdlmgmt.h @@ -0,0 +1,199 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * 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. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * This file includes structures, macros used to communicate with linkmgmt + * daemon. + */ + +#ifndef _LIBDLMGMT_H +#define _LIBDLMGMT_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <libdladm.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * datalink management related macros, structures. + */ + +/* + * Door call commands. + */ +#define DLMGMT_CMD_CREATE_LINKID (DLMGMT_CMD_BASE + 0) +#define DLMGMT_CMD_DESTROY_LINKID (DLMGMT_CMD_BASE + 1) +#define DLMGMT_CMD_REMAP_LINKID (DLMGMT_CMD_BASE + 2) +#define DLMGMT_CMD_CREATECONF (DLMGMT_CMD_BASE + 3) +#define DLMGMT_CMD_READCONF (DLMGMT_CMD_BASE + 4) +#define DLMGMT_CMD_WRITECONF (DLMGMT_CMD_BASE + 5) +#define DLMGMT_CMD_UP_LINKID (DLMGMT_CMD_BASE + 6) +#define DLMGMT_CMD_SETATTR (DLMGMT_CMD_BASE + 7) +#define DLMGMT_CMD_UNSETATTR (DLMGMT_CMD_BASE + 8) +#define DLMGMT_CMD_REMOVECONF (DLMGMT_CMD_BASE + 9) +#define DLMGMT_CMD_DESTROYCONF (DLMGMT_CMD_BASE + 10) +#define DLMGMT_CMD_GETATTR (DLMGMT_CMD_BASE + 11) + +typedef struct dlmgmt_door_createid_s { + int ld_cmd; + char ld_link[MAXLINKNAMELEN]; + datalink_class_t ld_class; + uint32_t ld_media; + boolean_t ld_prefix; + uint32_t ld_flags; +} dlmgmt_door_createid_t; + +typedef struct dlmgmt_door_destroyid_s { + int ld_cmd; + datalink_id_t ld_linkid; + uint32_t ld_flags; +} dlmgmt_door_destroyid_t; + +typedef struct dlmgmt_door_remapid_s { + int ld_cmd; + datalink_id_t ld_linkid; + char ld_link[MAXLINKNAMELEN]; +} dlmgmt_door_remapid_t; + +typedef struct dlmgmt_door_upid_s { + int ld_cmd; + datalink_id_t ld_linkid; +} dlmgmt_door_upid_t; + +typedef struct dlmgmt_door_createconf_s { + int ld_cmd; + char ld_link[MAXLINKNAMELEN]; + datalink_id_t ld_linkid; + datalink_class_t ld_class; + uint32_t ld_media; +} dlmgmt_door_createconf_t; + +typedef struct dlmgmt_door_setattr_s { + int ld_cmd; + dladm_conf_t ld_conf; + char ld_attr[MAXLINKATTRLEN]; + size_t ld_attrsz; + dladm_datatype_t ld_type; + char ld_attrval[1]; +} dlmgmt_door_setattr_t; + +typedef struct dlmgmt_door_unsetattr_s { + int ld_cmd; + dladm_conf_t ld_conf; + char ld_attr[MAXLINKATTRLEN]; +} dlmgmt_door_unsetattr_t; + +typedef struct dlmgmt_door_writeconf_s { + int ld_cmd; + dladm_conf_t ld_conf; +} dlmgmt_door_writeconf_t; + +typedef struct dlmgmt_door_removeconf_s { + int ld_cmd; + datalink_id_t ld_linkid; +} dlmgmt_door_removeconf_t; + +typedef struct dlmgmt_door_destroyconf_s { + int ld_cmd; + dladm_conf_t ld_conf; +} dlmgmt_door_destroyconf_t; + +typedef struct dlmgmt_door_readconf_s { + int ld_cmd; + datalink_id_t ld_linkid; +} dlmgmt_door_readconf_t; + +typedef struct dlmgmt_door_getattr_s { + int ld_cmd; + dladm_conf_t ld_conf; + char ld_attr[MAXLINKATTRLEN]; +} dlmgmt_door_getattr_t; + +typedef union dlmgmt_door_arg_s { + int ld_cmd; + dlmgmt_upcall_arg_create_t kcreate; + dlmgmt_upcall_arg_destroy_t kdestroy; + dlmgmt_upcall_arg_getattr_t kgetattr; + dlmgmt_door_getlinkid_t getlinkid; + dlmgmt_door_getnext_t getnext; + dlmgmt_door_createid_t createid; + dlmgmt_door_destroyid_t destroyid; + dlmgmt_door_remapid_t remapid; + dlmgmt_door_upid_t upid; + dlmgmt_door_createconf_t createconf; + dlmgmt_door_getname_t getname; + dlmgmt_door_getattr_t getattr; + dlmgmt_door_setattr_t setattr; + dlmgmt_door_writeconf_t writeconf; + dlmgmt_door_removeconf_t removeconf; + dlmgmt_door_destroyconf_t destroyconf; + dlmgmt_door_readconf_t readconf; +} dlmgmt_door_arg_t; + +typedef struct dlmgmt_handle_retval_s { + uint_t lr_err; + dladm_conf_t lr_conf; +} dlmgmt_createconf_retval_t, dlmgmt_readconf_retval_t; + +typedef struct dlmgmt_null_retval_s dlmgmt_remapid_retval_t, + dlmgmt_upid_retval_t, + dlmgmt_destroyid_retval_t, + dlmgmt_setattr_retval_t, + dlmgmt_unsetattr_retval_t, + dlmgmt_writeconf_retval_t, + dlmgmt_removeconf_retval_t, + dlmgmt_destroyconf_retval_t; + +typedef struct dlmgmt_linkid_retval_s dlmgmt_createid_retval_t; + +typedef union dlmgmt_retval { + uint_t lr_err; /* return error code */ + dlmgmt_create_retval_t kcreate; + dlmgmt_destroy_retval_t kdestroy; + dlmgmt_getattr_retval_t getattr; + dlmgmt_getname_retval_t getname; + dlmgmt_getlinkid_retval_t getlinkid; + dlmgmt_getnext_retval_t getnext; + dlmgmt_createid_retval_t createid; + dlmgmt_destroyid_retval_t destroyid; + dlmgmt_remapid_retval_t remapid; + dlmgmt_upid_retval_t upid; + dlmgmt_createconf_retval_t createconf; + dlmgmt_readconf_retval_t readconf; + dlmgmt_setattr_retval_t setattr; + dlmgmt_writeconf_retval_t writeconf; + dlmgmt_removeconf_retval_t removeconf; + dlmgmt_destroyconf_retval_t destroyconf; +} dlmgmt_retval_t; + +#ifdef __cplusplus +} +#endif + +#endif /* _LIBDLMGMT_H */ diff --git a/usr/src/lib/libdladm/common/libdlvlan.c b/usr/src/lib/libdladm/common/libdlvlan.c new file mode 100644 index 0000000000..fb84ad92f6 --- /dev/null +++ b/usr/src/lib/libdladm/common/libdlvlan.c @@ -0,0 +1,345 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * 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. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#include <assert.h> +#include <sys/dld.h> +#include <libdladm_impl.h> +#include <libdllink.h> +#include <libdlvlan.h> + +/* + * VLAN Administration Library. + * + * This library is used by administration tools such as dladm(1M) to + * configure VLANs. + */ + +/* + * Returns the current attributes of the specified VLAN. + */ +static dladm_status_t +i_dladm_vlan_info_active(datalink_id_t vlanid, dladm_vlan_attr_t *dvap) +{ + int fd; + dld_ioc_vlan_attr_t div; + dladm_status_t status = DLADM_STATUS_OK; + + if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) + return (dladm_errno2status(errno)); + + div.div_vlanid = vlanid; + + if (i_dladm_ioctl(fd, DLDIOC_VLAN_ATTR, &div, sizeof (div)) < 0) + status = dladm_errno2status(errno); + + dvap->dv_vid = div.div_vid; + dvap->dv_linkid = div.div_linkid; + dvap->dv_force = div.div_force; + dvap->dv_implicit = div.div_implicit; +done: + (void) close(fd); + return (status); +} + +/* + * Returns the persistent attributes of the specified VLAN. + */ +static dladm_status_t +i_dladm_vlan_info_persist(datalink_id_t vlanid, dladm_vlan_attr_t *dvap) +{ + dladm_conf_t conf = DLADM_INVALID_CONF; + dladm_status_t status; + uint64_t u64; + + if ((status = dladm_read_conf(vlanid, &conf)) != DLADM_STATUS_OK) + return (status); + + status = dladm_get_conf_field(conf, FLINKOVER, &u64, sizeof (u64)); + if (status != DLADM_STATUS_OK) + goto done; + dvap->dv_linkid = (datalink_id_t)u64; + + status = dladm_get_conf_field(conf, FFORCE, &dvap->dv_force, + sizeof (boolean_t)); + if (status != DLADM_STATUS_OK) + goto done; + + dvap->dv_implicit = B_FALSE; + + status = dladm_get_conf_field(conf, FVLANID, &u64, sizeof (u64)); + if (status != DLADM_STATUS_OK) + goto done; + dvap->dv_vid = (uint16_t)u64; + +done: + dladm_destroy_conf(conf); + return (status); +} + +dladm_status_t +dladm_vlan_info(datalink_id_t vlanid, dladm_vlan_attr_t *dvap, uint32_t flags) +{ + assert(flags == DLADM_OPT_ACTIVE || flags == DLADM_OPT_PERSIST); + if (flags == DLADM_OPT_ACTIVE) + return (i_dladm_vlan_info_active(vlanid, dvap)); + else + return (i_dladm_vlan_info_persist(vlanid, dvap)); +} + +static dladm_status_t +dladm_persist_vlan_conf(const char *vlan, datalink_id_t vlanid, + boolean_t force, datalink_id_t linkid, uint16_t vid) +{ + dladm_conf_t conf = DLADM_INVALID_CONF; + dladm_status_t status; + uint64_t u64; + + if ((status = dladm_create_conf(vlan, vlanid, DATALINK_CLASS_VLAN, + DL_ETHER, &conf)) != DLADM_STATUS_OK) { + return (status); + } + + u64 = linkid; + status = dladm_set_conf_field(conf, FLINKOVER, DLADM_TYPE_UINT64, &u64); + if (status != DLADM_STATUS_OK) + goto done; + + status = dladm_set_conf_field(conf, FFORCE, DLADM_TYPE_BOOLEAN, &force); + if (status != DLADM_STATUS_OK) + goto done; + + u64 = vid; + status = dladm_set_conf_field(conf, FVLANID, DLADM_TYPE_UINT64, &u64); + if (status != DLADM_STATUS_OK) + goto done; + + status = dladm_write_conf(conf); + +done: + dladm_destroy_conf(conf); + return (status); +} + +/* + * Create a VLAN on given link. + */ +dladm_status_t +dladm_vlan_create(const char *vlan, datalink_id_t linkid, uint16_t vid, + uint32_t flags) +{ + dld_ioc_create_vlan_t dic; + int fd; + datalink_id_t vlanid = DATALINK_INVALID_LINKID; + uint_t media; + datalink_class_t class; + dladm_status_t status; + + if (vid < 1 || vid > 4094) + return (DLADM_STATUS_VIDINVAL); + + if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) + return (dladm_errno2status(errno)); + + status = dladm_datalink_id2info(linkid, NULL, &class, &media, NULL, 0); + if (status != DLADM_STATUS_OK || media != DL_ETHER || + class == DATALINK_CLASS_VLAN) { + return (DLADM_STATUS_BADARG); + } + + status = dladm_create_datalink_id(vlan, DATALINK_CLASS_VLAN, DL_ETHER, + flags & (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST), &vlanid); + if (status != DLADM_STATUS_OK) + goto fail; + + if (flags & DLADM_OPT_PERSIST) { + status = dladm_persist_vlan_conf(vlan, vlanid, + (flags & DLADM_OPT_FORCE) != 0, linkid, vid); + if (status != DLADM_STATUS_OK) + goto fail; + } + + if (flags & DLADM_OPT_ACTIVE) { + dic.dic_vlanid = vlanid; + dic.dic_linkid = linkid; + dic.dic_vid = vid; + dic.dic_force = (flags & DLADM_OPT_FORCE) != 0; + + if (i_dladm_ioctl(fd, DLDIOC_CREATE_VLAN, &dic, + sizeof (dic)) < 0) { + status = dladm_errno2status(errno); + if (flags & DLADM_OPT_PERSIST) + (void) dladm_remove_conf(vlanid); + goto fail; + } + } + + (void) close(fd); + return (DLADM_STATUS_OK); + +fail: + if (vlanid != DATALINK_INVALID_LINKID) { + (void) dladm_destroy_datalink_id(vlanid, + flags & (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST)); + } + (void) close(fd); + return (status); +} + +/* + * Delete a given VLAN. + */ +dladm_status_t +dladm_vlan_delete(datalink_id_t vlanid, uint32_t flags) +{ + dld_ioc_delete_vlan_t did; + int fd; + datalink_class_t class; + dladm_status_t status = DLADM_STATUS_OK; + + if ((dladm_datalink_id2info(vlanid, NULL, &class, NULL, NULL, 0) != + DLADM_STATUS_OK) || (class != DATALINK_CLASS_VLAN)) { + return (DLADM_STATUS_BADARG); + } + + if (flags & DLADM_OPT_ACTIVE) { + if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) + return (dladm_errno2status(errno)); + + did.did_linkid = vlanid; + if ((i_dladm_ioctl(fd, DLDIOC_DELETE_VLAN, &did, + sizeof (did)) < 0) && + ((errno != ENOENT) || !(flags & DLADM_OPT_PERSIST))) { + (void) close(fd); + return (dladm_errno2status(errno)); + } + (void) close(fd); + + /* + * Delete active linkprop before this active link is deleted. + */ + (void) dladm_set_linkprop(vlanid, NULL, NULL, 0, + DLADM_OPT_ACTIVE); + } + + (void) dladm_destroy_datalink_id(vlanid, + flags & (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST)); + + if (flags & DLADM_OPT_PERSIST) + (void) dladm_remove_conf(vlanid); + + return (status); +} + +/* + * Callback used by dladm_vlan_up() + */ +static int +i_dladm_vlan_up(datalink_id_t vlanid, void *arg) +{ + dladm_vlan_attr_t dva; + dld_ioc_create_vlan_t dic; + dladm_status_t *statusp = arg; + uint32_t flags; + int fd; + dladm_status_t status; + + status = dladm_vlan_info(vlanid, &dva, DLADM_OPT_PERSIST); + if (status != DLADM_STATUS_OK) + goto done; + + /* + * Validate (and delete) the link associated with this VLAN, see if + * the specific hardware has been removed during system shutdown. + */ + if ((status = dladm_datalink_id2info(dva.dv_linkid, &flags, NULL, + NULL, NULL, 0)) != DLADM_STATUS_OK) { + goto done; + } + + if (!(flags & DLADM_OPT_ACTIVE)) { + status = DLADM_STATUS_BADARG; + goto done; + } + + dic.dic_linkid = dva.dv_linkid; + dic.dic_force = dva.dv_force; + dic.dic_vid = dva.dv_vid; + + if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) { + status = dladm_errno2status(errno); + goto done; + } + + dic.dic_vlanid = vlanid; + if (i_dladm_ioctl(fd, DLDIOC_CREATE_VLAN, &dic, sizeof (dic)) < 0) { + status = dladm_errno2status(errno); + goto done; + } + + if ((status = dladm_up_datalink_id(vlanid)) != DLADM_STATUS_OK) { + dld_ioc_delete_vlan_t did; + + did.did_linkid = vlanid; + (void) i_dladm_ioctl(fd, DLDIOC_DELETE_VLAN, &did, + sizeof (did)); + } else { + /* + * Reset the active linkprop of this specific link. + */ + (void) dladm_init_linkprop(vlanid); + } + + (void) close(fd); +done: + *statusp = status; + return (DLADM_WALK_CONTINUE); +} + +/* + * Bring up one VLAN, or all persistent VLANs. In the latter case, the + * walk may terminate early if bringup of a VLAN fails. + */ +dladm_status_t +dladm_vlan_up(datalink_id_t linkid) +{ + dladm_status_t status; + + if (linkid == DATALINK_ALL_LINKID) { + (void) dladm_walk_datalink_id(i_dladm_vlan_up, &status, + DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, + DLADM_OPT_PERSIST); + return (DLADM_STATUS_OK); + } else { + (void) i_dladm_vlan_up(linkid, &status); + return (status); + } +} diff --git a/usr/src/lib/libdladm/common/libdlvlan.h b/usr/src/lib/libdladm/common/libdlvlan.h new file mode 100644 index 0000000000..7a305443df --- /dev/null +++ b/usr/src/lib/libdladm/common/libdlvlan.h @@ -0,0 +1,60 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * 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. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _LIBDLVLAN_H +#define _LIBDLVLAN_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * This file includes structures, macros and routines used by VLAN link + * administration. + */ + +#include <libdladm.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct dladm_vlan_attr { + uint16_t dv_vid; + datalink_id_t dv_linkid; + boolean_t dv_force; + boolean_t dv_implicit; +} dladm_vlan_attr_t; + +extern dladm_status_t dladm_vlan_info(datalink_id_t, dladm_vlan_attr_t *, + uint32_t); +extern dladm_status_t dladm_vlan_create(const char *, datalink_id_t, + uint16_t, uint32_t); +extern dladm_status_t dladm_vlan_delete(datalink_id_t, uint32_t); +extern dladm_status_t dladm_vlan_up(datalink_id_t); + +#ifdef __cplusplus +} +#endif + +#endif /* _LIBDLVLAN_H */ diff --git a/usr/src/lib/libdladm/common/libdlvnic.c b/usr/src/lib/libdladm/common/libdlvnic.c index da9d57cd1b..272763b61d 100644 --- a/usr/src/lib/libdladm/common/libdlvnic.c +++ b/usr/src/lib/libdladm/common/libdlvnic.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -39,6 +39,7 @@ #include <net/if_types.h> #include <net/if_dl.h> #include <libdladm_impl.h> +#include <libdllink.h> #include <libdlvnic.h> /* @@ -47,51 +48,19 @@ #define VNIC_DEV "/devices/pseudo/vnic@0:" VNIC_CTL_NODE_NAME -/* - * Because by default the id is used as the DLPI device PPA and default - * VLAN PPA's are calculated as ((1000 * vid) + PPA), the largest id - * can't be > 999. We reserve the last 100 VNIC ids for automatic - * VNIC id assignment. - */ -#define DLADM_VNIC_MIN_VNIC_ID 1 /* total range */ -#define DLADM_VNIC_MAX_VNIC_ID 999 -#define DLADM_VNIC_MIN_VNIC_SPEC_ID 1 /* specified by user */ -#define DLADM_VNIC_MAX_VNIC_SPEC_ID 899 -#define DLADM_VNIC_MIN_VNIC_AUTO_ID 900 /* picked automatically */ -#define DLADM_VNIC_MAX_VNIC_AUTO_ID 999 - -#define DLADM_VNIC_NUM_VNIC_AUTO_ID (DLADM_VNIC_MAX_VNIC_AUTO_ID - \ - DLADM_VNIC_MIN_VNIC_AUTO_ID + 1) - /* Limits on buffer size for VNIC_IOC_INFO request */ #define MIN_INFO_SIZE (4*1024) #define MAX_INFO_SIZE (128*1024) /* configuration database entry */ typedef struct dladm_vnic_attr_db { - uint_t vt_vnic_id; - char vt_dev_name[MAXNAMELEN]; + datalink_id_t vt_vnic_id; + datalink_id_t vt_link_id; vnic_mac_addr_type_t vt_mac_addr_type; uint_t vt_mac_len; uchar_t vt_mac_addr[MAXMACADDRLEN]; } dladm_vnic_attr_db_t; -typedef struct dladm_vnic_up { - uint_t vu_vnic_id; - boolean_t vu_found; - int vu_fd; -} dladm_vnic_up_t; - -typedef struct dladm_vnic_down { - uint32_t vd_vnic_id; - boolean_t vd_found; -} dladm_vnic_down_t; - -typedef struct dladm_vnic_modify { - uint32_t vm_vnic_id; - boolean_t vm_found; -} dladm_vnic_modify_t; - typedef struct dladm_vnic_modify_attr { vnic_mac_addr_type_t vm_mac_addr_type; int vm_mac_len; @@ -108,7 +77,7 @@ i_dladm_vnic_create_sys(int fd, dladm_vnic_attr_db_t *attr) vnic_ioc_create_t ioc; ioc.vc_vnic_id = attr->vt_vnic_id; - bcopy(attr->vt_dev_name, ioc.vc_dev_name, MAXNAMELEN); + ioc.vc_link_id = attr->vt_link_id; ioc.vc_mac_addr_type = attr->vt_mac_addr_type; ioc.vc_mac_len = attr->vt_mac_len; bcopy(attr->vt_mac_addr, ioc.vc_mac_addr, attr->vt_mac_len); @@ -122,31 +91,10 @@ i_dladm_vnic_create_sys(int fd, dladm_vnic_attr_db_t *attr) } /* - * Invoked to bring up a VNIC. - */ -static dladm_status_t -i_dladm_vnic_up(void *arg, dladm_vnic_attr_db_t *attr) -{ - dladm_vnic_up_t *up = (dladm_vnic_up_t *)arg; - dladm_status_t status; - - if (up->vu_vnic_id != 0 && up->vu_vnic_id != attr->vt_vnic_id) - return (DLADM_STATUS_OK); - - up->vu_found = B_TRUE; - - status = i_dladm_vnic_create_sys(up->vu_fd, attr); - if ((status != DLADM_STATUS_OK) && (up->vu_vnic_id != 0)) - return (status); - - return (DLADM_STATUS_OK); -} - -/* * Send a modify command to the VNIC driver. */ static dladm_status_t -i_dladm_vnic_modify_sys(uint_t vnic_id, uint32_t modify_mask, +i_dladm_vnic_modify_sys(datalink_id_t vnic_id, uint32_t modify_mask, dladm_vnic_modify_attr_t *attr) { int rc; @@ -177,75 +125,49 @@ i_dladm_vnic_modify_sys(uint_t vnic_id, uint32_t modify_mask, } /* - * Walk through the vnics defined on the system and for each vnic <vnic>, - * invoke <fn>(<arg>, <vnic>); + * Get the configuration information of the given VNIC. */ dladm_status_t -dladm_vnic_walk_sys(dladm_status_t (*fn)(void *, dladm_vnic_attr_sys_t *), - void *arg) +dladm_vnic_info(datalink_id_t vnic_id, dladm_vnic_attr_sys_t *attrp, + uint32_t flags) { vnic_ioc_info_t *ioc; vnic_ioc_info_vnic_t *vnic; - dladm_vnic_attr_sys_t attr; - int rc, i, bufsize, fd; - char *where; + int rc, bufsize, fd; dladm_status_t status = DLADM_STATUS_OK; + /* for now, only temporary creations are supported */ + if (flags & DLADM_OPT_PERSIST) + return (dladm_errno2status(ENOTSUP)); + if ((fd = open(VNIC_DEV, O_RDWR)) == -1) return (dladm_errno2status(errno)); - bufsize = MIN_INFO_SIZE; + bufsize = sizeof (vnic_ioc_info_t) + sizeof (vnic_ioc_info_vnic_t); ioc = (vnic_ioc_info_t *)calloc(1, bufsize); if (ioc == NULL) { (void) close(fd); return (dladm_errno2status(ENOMEM)); } -tryagain: - + ioc->vi_vnic_id = vnic_id; rc = i_dladm_ioctl(fd, VNIC_IOC_INFO, ioc, bufsize); - if (rc != 0) { - if (errno == ENOSPC) { - bufsize *= 2; - if (bufsize <= MAX_INFO_SIZE) { - ioc = (vnic_ioc_info_t *)realloc(ioc, bufsize); - if (ioc != NULL) { - bzero(ioc, bufsize); - goto tryagain; - } - } - } status = dladm_errno2status(errno); goto bail; } - /* - * Go through each vnic returned by the vnic driver - */ - where = (char *)(ioc + 1); - - for (i = 0; i < ioc->vi_nvnics; i++) { - /* LINTED E_BAD_PTR_CAST_ALIGN */ - vnic = (vnic_ioc_info_vnic_t *)where; - - attr.va_vnic_id = vnic->vn_vnic_id; - bcopy(vnic->vn_dev_name, attr.va_dev_name, - MAXNAMELEN); - attr.va_mac_addr_type = vnic->vn_mac_addr_type; - bcopy(vnic->vn_mac_addr, attr.va_mac_addr, ETHERADDRL); - attr.va_mac_len = vnic->vn_mac_len; - where = (char *)(vnic + 1); - - status = fn(arg, &attr); - if (status != DLADM_STATUS_OK) - goto bail; - } + vnic = (vnic_ioc_info_vnic_t *)(ioc + 1); + + attrp->va_vnic_id = vnic->vn_vnic_id; + attrp->va_link_id = vnic->vn_link_id; + attrp->va_mac_addr_type = vnic->vn_mac_addr_type; + bcopy(vnic->vn_mac_addr, attrp->va_mac_addr, ETHERADDRL); + attrp->va_mac_len = vnic->vn_mac_len; bail: free(ioc); (void) close(fd); - return (status); } @@ -269,34 +191,6 @@ i_dladm_vnic_delete_sys(int fd, dladm_vnic_attr_sys_t *attr) } /* - * Invoked to bring down a VNIC. - */ -static dladm_status_t -i_dladm_vnic_down(void *arg, dladm_vnic_attr_sys_t *attr) -{ - dladm_vnic_down_t *down = (dladm_vnic_down_t *)arg; - int fd; - dladm_status_t status; - - if (down->vd_vnic_id != 0 && down->vd_vnic_id != attr->va_vnic_id) - return (DLADM_STATUS_OK); - - down->vd_found = B_TRUE; - - if ((fd = open(VNIC_DEV, O_RDWR)) < 0) - return (dladm_errno2status(errno)); - - status = i_dladm_vnic_delete_sys(fd, attr); - if ((status != DLADM_STATUS_OK) && (down->vd_vnic_id != 0)) { - (void) close(fd); - return (status); - } - - (void) close(fd); - return (DLADM_STATUS_OK); -} - -/* * Convert between MAC address types and their string representations. */ @@ -311,9 +205,12 @@ static dladm_vnic_addr_type_t addr_types[] = { #define NADDR_TYPES (sizeof (addr_types) / sizeof (dladm_vnic_addr_type_t)) -/* returns B_TRUE if a matching type was found, B_FALSE otherwise */ -boolean_t -dladm_vnic_mac_addr_str_to_type(const char *str, vnic_mac_addr_type_t *val) +/* + * Return DLADM_STATUS_OK if a matching type was found, + * DLADM_STATUS_BADARG otherwise + */ +dladm_status_t +dladm_vnic_str2macaddrtype(const char *str, vnic_mac_addr_type_t *val) { int i; dladm_vnic_addr_type_t *type; @@ -322,127 +219,34 @@ dladm_vnic_mac_addr_str_to_type(const char *str, vnic_mac_addr_type_t *val) type = &addr_types[i]; if (strncmp(str, type->va_str, strlen(type->va_str)) == 0) { *val = type->va_type; - return (B_TRUE); + return (DLADM_STATUS_OK); } } - return (B_FALSE); -} - -/* - * Select a VNIC id automatically. - */ - -typedef struct dladm_vnic_auto_state_s { - uint_t as_nslots; - uint_t *as_slots; -} dladm_vnic_auto_state_t; - -static dladm_status_t -i_dladm_vnic_create_auto_walker(void *arg, dladm_vnic_attr_sys_t *attr) -{ - dladm_vnic_auto_state_t *state = arg; - - if (attr->va_vnic_id < DLADM_VNIC_MIN_VNIC_AUTO_ID || - attr->va_vnic_id > DLADM_VNIC_MAX_VNIC_AUTO_ID) - return (DLADM_STATUS_OK); - - state->as_slots[state->as_nslots++] = attr->va_vnic_id; - - return (DLADM_STATUS_OK); -} - -static int -i_dladm_vnic_compare(const void *p1, const void *p2) -{ - uint_t i = *((uint_t *)p1); - uint_t j = *((uint_t *)p2); - - if (i > j) - return (1); - if (i < j) - return (-1); - return (0); -} - -/*ARGSUSED*/ -static dladm_status_t -i_dladm_vnic_get_auto_id(dladm_vnic_attr_db_t *attr, uint32_t *vnic_id_out) -{ - dladm_vnic_auto_state_t state; - uint_t vnic_ids[DLADM_VNIC_NUM_VNIC_AUTO_ID]; - int i; - uint_t last_id, vnic_id; - dladm_status_t status; - - /* - * Build a sorted array containing the existing VNIC ids in the range - * allocated for automatic allocation. - */ - state.as_nslots = 0; - state.as_slots = vnic_ids; - - status = dladm_vnic_walk_sys(i_dladm_vnic_create_auto_walker, &state); - if (status != DLADM_STATUS_OK) - return (status); - - qsort(vnic_ids, state.as_nslots, sizeof (uint_t), - i_dladm_vnic_compare); - - /* - * Find a gap in the sequence of existing VNIC ids. - */ - last_id = DLADM_VNIC_MIN_VNIC_AUTO_ID - 1; - vnic_id = 0; - for (i = 0; i < state.as_nslots; i++) { - if (vnic_ids[i] > (last_id + 1)) { - vnic_id = last_id + 1; - break; - } - last_id = vnic_ids[i]; - } - - if (vnic_id == 0) { - /* - * Did not find a gap between existing entries, see if we - * can add one. - */ - if (last_id + 1 > DLADM_VNIC_MAX_VNIC_AUTO_ID) - return (DLADM_STATUS_AUTOIDNOAVAILABLEID); - - /* still have room for one more VNIC */ - vnic_id = last_id + 1; - } - - *vnic_id_out = vnic_id; - - return (DLADM_STATUS_OK); + return (DLADM_STATUS_BADARG); } /* * Create a new VNIC. Update the configuration file and bring it up. */ dladm_status_t -dladm_vnic_create(uint_t vnic_id, char *dev_name, +dladm_vnic_create(const char *vnic, datalink_id_t linkid, vnic_mac_addr_type_t mac_addr_type, uchar_t *mac_addr, int mac_len, - uint_t *vnic_id_out, uint32_t flags) + datalink_id_t *vnic_id_out, uint32_t flags) { dladm_vnic_attr_db_t attr; - int i; - boolean_t tempop = ((flags & DLADM_VNIC_OPT_TEMP) != 0); - boolean_t autoid = ((flags & DLADM_VNIC_OPT_AUTOID) != 0); - dladm_vnic_up_t up; + int i, fd; + datalink_id_t vnic_id; + datalink_class_t class; + uint32_t media; + char *name = (char *)vnic; dladm_status_t status; /* * Sanity test arguments. */ - if (autoid && !tempop) - return (DLADM_STATUS_AUTOIDNOTEMP); - - if (!autoid && ((vnic_id < DLADM_VNIC_MIN_VNIC_SPEC_ID) || - (vnic_id > DLADM_VNIC_MAX_VNIC_SPEC_ID))) - return (DLADM_STATUS_INVALIDID); + if (flags & DLADM_OPT_PERSIST) + return (dladm_errno2status(ENOTSUP)); if (mac_len > MAXMACADDRLEN) return (DLADM_STATUS_INVALIDMACADDRLEN); @@ -454,40 +258,46 @@ dladm_vnic_create(uint_t vnic_id, char *dev_name, if (i == NADDR_TYPES) return (DLADM_STATUS_INVALIDMACADDRTYPE); - /* for now, only temporary creations are supported */ - if (!tempop) - return (dladm_errno2status(ENOTSUP)); + if ((status = dladm_datalink_id2info(linkid, NULL, &class, &media, + NULL, 0)) != DLADM_STATUS_OK) { + return (status); + } -auto_again: - if (autoid) { - /* - * Find an unused VNIC id. - */ - status = i_dladm_vnic_get_auto_id(&attr, vnic_id_out); - if (status != DLADM_STATUS_OK) - return (status); - vnic_id = *vnic_id_out; + if (class == DATALINK_CLASS_VNIC) + return (DLADM_STATUS_BADARG); + + if (vnic == NULL) { + flags |= DLADM_OPT_PREFIX; + name = "vnic"; + } + + if ((status = dladm_create_datalink_id(name, DATALINK_CLASS_VNIC, + media, flags, &vnic_id)) != DLADM_STATUS_OK) { + return (status); } bzero(&attr, sizeof (attr)); attr.vt_vnic_id = vnic_id; - (void) strncpy(attr.vt_dev_name, dev_name, - sizeof (attr.vt_dev_name) - 1); + attr.vt_link_id = linkid; attr.vt_mac_addr_type = mac_addr_type; attr.vt_mac_len = mac_len; bcopy(mac_addr, attr.vt_mac_addr, mac_len); - up.vu_vnic_id = vnic_id; - up.vu_found = B_FALSE; - up.vu_fd = open(VNIC_DEV, O_RDWR); - if (up.vu_fd < 0) - return (dladm_errno2status(errno)); + if ((fd = open(VNIC_DEV, O_RDWR)) < 0) { + status = dladm_errno2status(errno); + goto done; + } - status = i_dladm_vnic_up((void *)&up, &attr); - (void) close(up.vu_fd); + status = i_dladm_vnic_create_sys(fd, &attr); + (void) close(fd); - if ((status == DLADM_STATUS_EXIST) && autoid) - goto auto_again; +done: + if (status != DLADM_STATUS_OK) { + (void) dladm_destroy_datalink_id(vnic_id, + flags & ~DLADM_OPT_PREFIX); + } else { + *vnic_id_out = vnic_id; + } return (status); } @@ -496,19 +306,14 @@ auto_again: * Modify the properties of a VNIC. */ dladm_status_t -dladm_vnic_modify(uint_t vnic_id, uint32_t modify_mask, +dladm_vnic_modify(datalink_id_t vnic_id, uint32_t modify_mask, vnic_mac_addr_type_t mac_addr_type, uint_t mac_len, uchar_t *mac_addr, uint32_t flags) { dladm_vnic_modify_attr_t new_attr; - boolean_t tempop = ((flags & DLADM_VNIC_OPT_TEMP) != 0); - - if ((vnic_id < DLADM_VNIC_MIN_VNIC_ID) || - (vnic_id > DLADM_VNIC_MAX_VNIC_ID)) - return (DLADM_STATUS_INVALIDID); /* for now, only temporary creations are supported */ - if (!tempop) + if (flags & DLADM_OPT_PERSIST) return (dladm_errno2status(ENOTSUP)); bzero(&new_attr, sizeof (new_attr)); @@ -523,27 +328,30 @@ dladm_vnic_modify(uint_t vnic_id, uint32_t modify_mask, return (i_dladm_vnic_modify_sys(vnic_id, modify_mask, &new_attr)); } - /* * Delete a VNIC. */ dladm_status_t -dladm_vnic_delete(uint_t vnic_id, uint32_t flags) +dladm_vnic_delete(datalink_id_t vnic_id, uint32_t flags) { - boolean_t tempop = ((flags & DLADM_VNIC_OPT_TEMP) != 0); - dladm_vnic_down_t down; + dladm_status_t status; dladm_vnic_attr_sys_t sys_attr; - - if ((vnic_id < DLADM_VNIC_MIN_VNIC_ID) || - (vnic_id > DLADM_VNIC_MAX_VNIC_ID)) - return (DLADM_STATUS_INVALIDID); + int fd; /* for now, only temporary deletes are supported */ - if (!tempop) + if (flags & DLADM_OPT_PERSIST) return (dladm_errno2status(ENOTSUP)); - down.vd_vnic_id = vnic_id; - down.vd_found = B_FALSE; + if ((fd = open(VNIC_DEV, O_RDWR)) < 0) + return (dladm_errno2status(errno)); + sys_attr.va_vnic_id = vnic_id; - return (i_dladm_vnic_down((void *)&down, &sys_attr)); + status = i_dladm_vnic_delete_sys(fd, &sys_attr); + (void) close(fd); + + if (status != DLADM_STATUS_OK) + return (status); + + (void) dladm_destroy_datalink_id(vnic_id, flags); + return (status); } diff --git a/usr/src/lib/libdladm/common/libdlvnic.h b/usr/src/lib/libdladm/common/libdlvnic.h index 4f0726746c..79b4b01ba2 100644 --- a/usr/src/lib/libdladm/common/libdlvnic.h +++ b/usr/src/lib/libdladm/common/libdlvnic.h @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -38,32 +38,26 @@ extern "C" { #endif typedef struct dladm_vnic_attr_sys { - uint_t va_vnic_id; - char va_dev_name[MAXNAMELEN + 1]; + datalink_id_t va_vnic_id; + datalink_id_t va_link_id; vnic_mac_addr_type_t va_mac_addr_type; uchar_t va_mac_addr[ETHERADDRL]; uint_t va_mac_len; } dladm_vnic_attr_sys_t; /* - * General operations flags. - */ -#define DLADM_VNIC_OPT_TEMP 0x00000001 -#define DLADM_VNIC_OPT_AUTOID 0x00000002 - -/* * Modification flags for dladm_vnic_modify(). */ #define DLADM_VNIC_MODIFY_ADDR 0x01 -extern dladm_status_t dladm_vnic_create(uint_t, char *, vnic_mac_addr_type_t, - uchar_t *, int, uint_t *, uint32_t); -extern dladm_status_t dladm_vnic_modify(uint_t, uint32_t, vnic_mac_addr_type_t, - uint_t, uchar_t *, uint32_t); -extern dladm_status_t dladm_vnic_delete(uint_t, uint32_t); -extern dladm_status_t dladm_vnic_walk_sys( - dladm_status_t (*)(void *, dladm_vnic_attr_sys_t *), void *); -extern boolean_t dladm_vnic_mac_addr_str_to_type(const char *, +extern dladm_status_t dladm_vnic_create(const char *, datalink_id_t, + vnic_mac_addr_type_t, uchar_t *, int, uint_t *, uint32_t); +extern dladm_status_t dladm_vnic_modify(datalink_id_t, uint32_t, + vnic_mac_addr_type_t, uint_t, uchar_t *, uint32_t); +extern dladm_status_t dladm_vnic_delete(datalink_id_t, uint32_t); +extern dladm_status_t dladm_vnic_info(datalink_id_t, dladm_vnic_attr_sys_t *, + uint32_t); +extern dladm_status_t dladm_vnic_str2macaddrtype(const char *, vnic_mac_addr_type_t *); #ifdef __cplusplus diff --git a/usr/src/lib/libdladm/common/libdlwlan.c b/usr/src/lib/libdladm/common/libdlwlan.c index 3819dd5050..6597b84ce0 100644 --- a/usr/src/lib/libdladm/common/libdlwlan.c +++ b/usr/src/lib/libdladm/common/libdlwlan.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -28,163 +28,96 @@ #include <libintl.h> #include <stdio.h> #include <stdlib.h> -#include <stddef.h> #include <unistd.h> #include <fcntl.h> +#include <stddef.h> #include <string.h> #include <stropts.h> #include <libdevinfo.h> #include <net/if.h> #include <net/if_dl.h> #include <net/if_types.h> +#include <libdlpi.h> +#include <libdllink.h> #include <libscf.h> #include <libdlwlan.h> +#include <libdladm_impl.h> #include <libdlwlan_impl.h> #include <net/wpa.h> -typedef struct val_desc { - char *vd_name; - uint_t vd_val; -} val_desc_t; - -struct prop_desc; - -typedef dladm_status_t wl_pd_getf_t(int, wldp_t *, char **, uint_t *); -typedef dladm_status_t wl_pd_setf_t(int, wldp_t *, val_desc_t *, uint_t); -typedef dladm_status_t wl_pd_checkf_t(int, wldp_t *, struct prop_desc *, - char **, uint_t, val_desc_t **); -typedef struct prop_desc { - char *pd_name; - val_desc_t pd_defval; - val_desc_t *pd_modval; - uint_t pd_nmodval; - wl_pd_setf_t *pd_set; - wl_pd_getf_t *pd_getmod; - wl_pd_getf_t *pd_get; - wl_pd_checkf_t *pd_check; -} prop_desc_t; - -static int wpa_instance_create(const char *, void *); -static int wpa_instance_delete(const char *); - -static int do_get_bsstype(int, wldp_t *); -static int do_get_essid(int, wldp_t *); -static int do_get_bssid(int, wldp_t *); -static int do_get_signal(int, wldp_t *); -static int do_get_encryption(int, wldp_t *); -static int do_get_authmode(int, wldp_t *); -static int do_get_linkstatus(int, wldp_t *); -static int do_get_esslist(int, wldp_t *); -static int do_get_rate(int, wldp_t *); -static int do_get_phyconf(int, wldp_t *); -static int do_get_powermode(int, wldp_t *); -static int do_get_radio(int, wldp_t *); -static int do_get_mode(int, wldp_t *); -static int do_get_capability(int, wldp_t *); -static int do_get_wpamode(int, wldp_t *); - -static int do_set_bsstype(int, wldp_t *, dladm_wlan_bsstype_t *); -static int do_set_authmode(int, wldp_t *, dladm_wlan_auth_t *); -static int do_set_encryption(int, wldp_t *, dladm_wlan_secmode_t *); -static int do_set_essid(int, wldp_t *, dladm_wlan_essid_t *); -static int do_set_createibss(int, wldp_t *, boolean_t *); -static int do_set_key(int, wldp_t *, dladm_wlan_key_t *, uint_t); -static int do_set_rate(int, wldp_t *, dladm_wlan_rates_t *); -static int do_set_powermode(int, wldp_t *, dladm_wlan_powermode_t *); -static int do_set_radio(int, wldp_t *, dladm_wlan_radio_t *); -static int do_set_channel(int, wldp_t *, dladm_wlan_channel_t *); - -static int open_link(const char *); -static int do_scan(int, wldp_t *); -static int do_disconnect(const char *, int, wldp_t *); -static boolean_t find_val_by_name(const char *, val_desc_t *, uint_t, uint_t *); -static boolean_t find_name_by_val(uint_t, val_desc_t *, uint_t, char **); -static void generate_essid(dladm_wlan_essid_t *); +static dladm_status_t wpa_instance_create(datalink_id_t, void *); +static dladm_status_t wpa_instance_delete(datalink_id_t); + +static dladm_status_t do_get_bsstype(datalink_id_t, wldp_t *); +static dladm_status_t do_get_essid(datalink_id_t, wldp_t *); +static dladm_status_t do_get_bssid(datalink_id_t, wldp_t *); +static dladm_status_t do_get_signal(datalink_id_t, wldp_t *); +static dladm_status_t do_get_encryption(datalink_id_t, wldp_t *); +static dladm_status_t do_get_authmode(datalink_id_t, wldp_t *); +static dladm_status_t do_get_linkstatus(datalink_id_t, wldp_t *); +static dladm_status_t do_get_esslist(datalink_id_t, wldp_t *); +static dladm_status_t do_get_rate(datalink_id_t, wldp_t *); +static dladm_status_t do_get_mode(datalink_id_t, wldp_t *); +static dladm_status_t do_get_capability(datalink_id_t, wldp_t *); +static dladm_status_t do_get_wpamode(datalink_id_t, wldp_t *); + +static dladm_status_t do_set_bsstype(datalink_id_t, dladm_wlan_bsstype_t *); +static dladm_status_t do_set_authmode(datalink_id_t, dladm_wlan_auth_t *); +static dladm_status_t do_set_encryption(datalink_id_t, + dladm_wlan_secmode_t *); +static dladm_status_t do_set_essid(datalink_id_t, dladm_wlan_essid_t *); +static dladm_status_t do_set_createibss(datalink_id_t, boolean_t *); +static dladm_status_t do_set_key(datalink_id_t, dladm_wlan_key_t *, uint_t); +static dladm_status_t do_set_channel(datalink_id_t, dladm_wlan_channel_t *); + +static dladm_status_t do_scan(datalink_id_t, wldp_t *); +static dladm_status_t do_connect(datalink_id_t, wldp_t *, dladm_wlan_attr_t *, + boolean_t, void *, uint_t, int); +static dladm_status_t do_disconnect(datalink_id_t, wldp_t *); +static boolean_t find_val_by_name(const char *, val_desc_t *, + uint_t, uint_t *); +static boolean_t find_name_by_val(uint_t, val_desc_t *, uint_t, char **); +static void generate_essid(dladm_wlan_essid_t *); static dladm_status_t dladm_wlan_wlresult2status(wldp_t *); - -static wl_pd_getf_t do_get_rate_mod, do_get_rate_prop, do_get_channel_prop, - do_get_powermode_prop, do_get_radio_prop; -static wl_pd_setf_t do_set_rate_prop, do_set_powermode_prop, - do_set_radio_prop; -static wl_pd_checkf_t do_check_prop, do_check_rate; +static dladm_status_t dladm_wlan_validate(datalink_id_t); static val_desc_t linkstatus_vals[] = { - { "disconnected", DLADM_WLAN_LINKSTATUS_DISCONNECTED }, - { "connected", DLADM_WLAN_LINKSTATUS_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 }, - { "weak", DLADM_WLAN_STRENGTH_WEAK }, - { "good", DLADM_WLAN_STRENGTH_GOOD }, - { "very good", DLADM_WLAN_STRENGTH_VERY_GOOD }, - { "excellent", DLADM_WLAN_STRENGTH_EXCELLENT } + { "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} }; 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 } + { "open", DLADM_WLAN_AUTH_OPEN }, + { "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 } -}; - -static val_desc_t radio_vals[] = { - { "on", DLADM_WLAN_RADIO_ON }, - { "off", DLADM_WLAN_RADIO_OFF } -}; - -static val_desc_t powermode_vals[] = { - { "off", DLADM_WLAN_PM_OFF }, - { "fast", DLADM_WLAN_PM_FAST }, - { "max", DLADM_WLAN_PM_MAX } + { "bss", DLADM_WLAN_BSSTYPE_BSS }, + { "ibss", DLADM_WLAN_BSSTYPE_IBSS }, + { "any", DLADM_WLAN_BSSTYPE_ANY } }; -#define VALCNT(vals) (sizeof ((vals)) / sizeof (val_desc_t)) -static prop_desc_t prop_table[] = { - - { "channel", { NULL, 0 }, NULL, 0, - NULL, NULL, do_get_channel_prop, do_check_prop}, - - { "powermode", { "off", DLADM_WLAN_PM_OFF }, powermode_vals, - VALCNT(powermode_vals), - do_set_powermode_prop, NULL, - do_get_powermode_prop, do_check_prop}, - - { "radio", { "on", DLADM_WLAN_RADIO_ON }, radio_vals, - VALCNT(radio_vals), - do_set_radio_prop, NULL, - do_get_radio_prop, do_check_prop}, - - { "speed", { "", 0 }, NULL, 0, - do_set_rate_prop, do_get_rate_mod, - do_get_rate_prop, do_check_rate} -}; -/* - * Unfortunately, MAX_SCAN_SUPPORT_RATES is too small to allow all - * rates to be retrieved. However, we cannot increase it at this - * time because it will break binary comatibility with unbundled - * WiFi drivers and utilities. So for now we define an additional - * constant, MAX_SUPPORT_RATES, to allow all rates to be retrieved. - */ -#define MAX_SUPPORT_RATES 64 -#define DLADM_WLAN_MAX_PROPS (sizeof (prop_table) / sizeof (prop_desc_t)) #define IS_CONNECTED(gbuf) \ ((*(wl_linkstatus_t *)((gbuf)->wldp_buf) == WL_CONNECTED)) @@ -209,38 +142,6 @@ dladm_wlan_wlresult2status(wldp_t *gbuf) return (DLADM_STATUS_FAILED); } -static int -open_link(const char *link) -{ - char linkname[MAXPATHLEN]; - wldp_t *gbuf; - int fd; - - if (link == NULL) - return (-1); - - (void) snprintf(linkname, MAXPATHLEN, "/dev/%s", link); - if ((fd = open(linkname, O_RDWR)) < 0) - return (-1); - - if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) { - (void) close(fd); - return (-1); - } - - /* - * Check to see if the link is wireless. - */ - if (do_get_bsstype(fd, gbuf) < 0) { - free(gbuf); - (void) close(fd); - return (-1); - } - - free(gbuf); - return (fd); -} - static dladm_wlan_mode_t do_convert_mode(wl_phy_conf_t *phyp) { @@ -259,8 +160,8 @@ do_convert_mode(wl_phy_conf_t *phyp) return (DLADM_WLAN_MODE_NONE); } -static boolean_t -do_convert_chan(wl_phy_conf_t *phyp, uint32_t *channelp) +boolean_t +i_dladm_wlan_convert_chan(wl_phy_conf_t *phyp, uint32_t *channelp) { wl_fhss_t *wlfp = &phyp->wl_phy_fhss_conf; wl_ofdm_t *wlop = &phyp->wl_phy_ofdm_conf; @@ -326,16 +227,16 @@ fill_wlan_attr(wl_ess_conf_t *wlp, dladm_wlan_attr_t *attrp) if (attrp->wa_speed > 0) attrp->wa_valid |= DLADM_WLAN_ATTR_SPEED; - if (do_convert_chan((wl_phy_conf_t *)&wlp->wl_phy_conf, + if (i_dladm_wlan_convert_chan((wl_phy_conf_t *)&wlp->wl_phy_conf, &attrp->wa_channel)) attrp->wa_valid |= DLADM_WLAN_ATTR_CHANNEL; } dladm_status_t -dladm_wlan_scan(const char *link, void *arg, +dladm_wlan_scan(datalink_id_t linkid, void *arg, boolean_t (*func)(void *, dladm_wlan_attr_t *)) { - int fd, i; + int i; uint32_t count; wl_ess_conf_t *wlp; wldp_t *gbuf; @@ -343,34 +244,28 @@ dladm_wlan_scan(const char *link, void *arg, dladm_status_t status; boolean_t connected; - if ((fd = open_link(link)) < 0) - return (DLADM_STATUS_LINKINVAL); + if ((status = dladm_wlan_validate(linkid)) != DLADM_STATUS_OK) + goto done; if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) { status = DLADM_STATUS_NOMEM; goto done; } - if (do_get_linkstatus(fd, gbuf) < 0) { - status = DLADM_STATUS_FAILED; + if ((status = do_get_linkstatus(linkid, gbuf)) != DLADM_STATUS_OK) goto done; - } connected = IS_CONNECTED(gbuf); - if (do_scan(fd, gbuf) < 0) { - status = DLADM_STATUS_FAILED; + if ((status = do_scan(linkid, gbuf)) != DLADM_STATUS_OK) goto done; - } if (func == NULL) { status = DLADM_STATUS_OK; goto done; } - if (do_get_esslist(fd, gbuf) < 0) { - status = DLADM_STATUS_FAILED; + if ((status = do_get_esslist(linkid, gbuf)) != DLADM_STATUS_OK) goto done; - } wlp = ((wl_ess_list_t *)gbuf->wldp_buf)->wl_ess_list_ess; count = ((wl_ess_list_t *)(gbuf->wldp_buf))->wl_ess_list_num; @@ -382,18 +277,16 @@ dladm_wlan_scan(const char *link, void *arg, } if (!connected) { - if (do_get_linkstatus(fd, gbuf) < 0) { - status = DLADM_STATUS_FAILED; + status = do_get_linkstatus(linkid, gbuf); + if (status != DLADM_STATUS_OK) goto done; - } if (IS_CONNECTED(gbuf)) - (void) do_disconnect(link, fd, gbuf); + (void) do_disconnect(linkid, gbuf); } status = DLADM_STATUS_OK; done: free(gbuf); - (void) close(fd); return (status); } @@ -507,51 +400,61 @@ append: #define IEEE80211_C_WPA 0x01800000 static dladm_status_t -do_connect(const char *link, int fd, wldp_t *gbuf, dladm_wlan_attr_t *attrp, +do_connect(datalink_id_t linkid, wldp_t *gbuf, dladm_wlan_attr_t *attrp, boolean_t create_ibss, void *keys, uint_t key_count, int timeout) { - dladm_wlan_secmode_t secmode; - dladm_wlan_auth_t authmode; - dladm_wlan_bsstype_t bsstype; - dladm_wlan_essid_t essid; - boolean_t essid_valid = B_FALSE; - dladm_wlan_channel_t channel; - hrtime_t start; - wl_capability_t *caps; + dladm_wlan_secmode_t secmode; + dladm_wlan_auth_t authmode; + dladm_wlan_bsstype_t bsstype; + dladm_wlan_essid_t essid; + boolean_t essid_valid = B_FALSE; + dladm_status_t status; + dladm_wlan_channel_t channel; + hrtime_t start; + wl_capability_t *caps; if ((attrp->wa_valid & DLADM_WLAN_ATTR_CHANNEL) != 0) { channel = attrp->wa_channel; - if (do_set_channel(fd, gbuf, &channel) < 0) + status = do_set_channel(linkid, &channel); + if (status != DLADM_STATUS_OK) goto fail; } secmode = ((attrp->wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0) ? attrp->wa_secmode : DLADM_WLAN_SECMODE_NONE; - if (do_set_encryption(fd, gbuf, &secmode) < 0) + if ((status = do_set_encryption(linkid, &secmode)) != DLADM_STATUS_OK) goto fail; authmode = ((attrp->wa_valid & DLADM_WLAN_ATTR_AUTH) != 0) ? attrp->wa_auth : DLADM_WLAN_AUTH_OPEN; - if (do_set_authmode(fd, gbuf, &authmode) < 0) + if ((status = do_set_authmode(linkid, &authmode)) != DLADM_STATUS_OK) goto fail; bsstype = ((attrp->wa_valid & DLADM_WLAN_ATTR_BSSTYPE) != 0) ? attrp->wa_bsstype : DLADM_WLAN_BSSTYPE_BSS; - if (do_set_bsstype(fd, gbuf, &bsstype) < 0) + if ((status = do_set_bsstype(linkid, &bsstype)) != DLADM_STATUS_OK) goto fail; if (secmode == DLADM_WLAN_SECMODE_WEP) { - if (keys == NULL || key_count == 0 || key_count > MAX_NWEPKEYS) - return (DLADM_STATUS_BADARG); - if (do_set_key(fd, gbuf, keys, key_count) < 0) + if (keys == NULL || key_count == 0 || + key_count > MAX_NWEPKEYS) { + status = DLADM_STATUS_BADARG; + goto fail; + } + status = do_set_key(linkid, keys, key_count); + if (status != DLADM_STATUS_OK) goto fail; } else if (secmode == DLADM_WLAN_SECMODE_WPA) { - if (keys == NULL || key_count == 0 || key_count > MAX_NWEPKEYS) - return (DLADM_STATUS_BADARG); - if (do_get_capability(fd, gbuf) < 0) + if (keys == NULL || key_count == 0 || + key_count > MAX_NWEPKEYS) { + status = DLADM_STATUS_BADARG; + goto fail; + } + status = do_get_capability(linkid, gbuf); + if (status != DLADM_STATUS_OK) goto fail; caps = (wl_capability_t *)(gbuf->wldp_buf); if ((caps->caps & IEEE80211_C_WPA) == 0) @@ -559,10 +462,12 @@ do_connect(const char *link, int fd, wldp_t *gbuf, dladm_wlan_attr_t *attrp, } if (create_ibss) { - if (do_set_channel(fd, gbuf, &channel) < 0) + status = do_set_channel(linkid, &channel); + if (status != DLADM_STATUS_OK) goto fail; - if (do_set_createibss(fd, gbuf, &create_ibss) < 0) + status = do_set_createibss(linkid, &create_ibss); + if (status != DLADM_STATUS_OK) goto fail; if ((attrp->wa_valid & DLADM_WLAN_ATTR_ESSID) == 0) { @@ -576,9 +481,12 @@ do_connect(const char *link, int fd, wldp_t *gbuf, dladm_wlan_attr_t *attrp, essid_valid = B_TRUE; } - if (!essid_valid) - return (DLADM_STATUS_FAILED); - if (do_set_essid(fd, gbuf, &essid) < 0) + if (!essid_valid) { + status = DLADM_STATUS_FAILED; + goto fail; + } + + if ((status = do_set_essid(linkid, &essid)) != DLADM_STATUS_OK) goto fail; /* @@ -586,11 +494,12 @@ do_connect(const char *link, int fd, wldp_t *gbuf, dladm_wlan_attr_t *attrp, * we need call do_set_essid() first, then call wpa_instance_create(). */ if (secmode == DLADM_WLAN_SECMODE_WPA && keys != NULL) - (void) wpa_instance_create(link, keys); + (void) wpa_instance_create(linkid, keys); start = gethrtime(); for (;;) { - if (do_get_linkstatus(fd, gbuf) < 0) + status = do_get_linkstatus(linkid, gbuf); + if (status != DLADM_STATUS_OK) goto fail; if (IS_CONNECTED(gbuf)) @@ -598,38 +507,38 @@ do_connect(const char *link, int fd, wldp_t *gbuf, dladm_wlan_attr_t *attrp, (void) poll(NULL, 0, DLADM_WLAN_CONNECT_POLLRATE); if ((timeout >= 0) && (gethrtime() - start) / - NANOSEC >= timeout) - return (DLADM_STATUS_TIMEDOUT); + NANOSEC >= timeout) { + status = DLADM_STATUS_TIMEDOUT; + goto fail; + } } - return (DLADM_STATUS_OK); + status = DLADM_STATUS_OK; fail: - return (dladm_wlan_wlresult2status(gbuf)); + return (status); } dladm_status_t -dladm_wlan_connect(const char *link, dladm_wlan_attr_t *attrp, +dladm_wlan_connect(datalink_id_t linkid, dladm_wlan_attr_t *attrp, int timeout, void *keys, uint_t key_count, uint_t flags) { - int fd, i; + int i; wldp_t *gbuf = NULL; connect_state_t state = {0, NULL, NULL}; attr_node_t *nodep = NULL; boolean_t create_ibss, set_authmode; dladm_wlan_attr_t **wl_list = NULL; - dladm_status_t status = DLADM_STATUS_FAILED; + dladm_status_t status; - if ((fd = open_link(link)) < 0) - return (DLADM_STATUS_LINKINVAL); + if ((status = dladm_wlan_validate(linkid)) != DLADM_STATUS_OK) + goto done; if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) { status = DLADM_STATUS_NOMEM; goto done; } - if (do_get_linkstatus(fd, gbuf) < 0) { - status = DLADM_STATUS_FAILED; + if ((status = do_get_linkstatus(linkid, gbuf)) != DLADM_STATUS_OK) goto done; - } if (IS_CONNECTED(gbuf)) { status = DLADM_STATUS_ISCONN; @@ -646,8 +555,8 @@ dladm_wlan_connect(const char *link, dladm_wlan_attr_t *attrp, if ((flags & DLADM_WLAN_CONNECT_NOSCAN) != 0 || (create_ibss && attrp != NULL && (attrp->wa_valid & DLADM_WLAN_ATTR_ESSID) == 0)) { - status = do_connect(link, fd, gbuf, attrp, - create_ibss, keys, key_count, timeout); + status = do_connect(linkid, gbuf, attrp, create_ibss, keys, + key_count, timeout); goto done; } @@ -655,7 +564,7 @@ dladm_wlan_connect(const char *link, dladm_wlan_attr_t *attrp, state.cs_list = NULL; state.cs_count = 0; - status = dladm_wlan_scan(link, &state, connect_cb); + status = dladm_wlan_scan(linkid, &state, connect_cb); if (status != DLADM_STATUS_OK) goto done; @@ -664,8 +573,8 @@ dladm_wlan_connect(const char *link, dladm_wlan_attr_t *attrp, status = DLADM_STATUS_NOTFOUND; goto done; } - status = do_connect(link, fd, gbuf, attrp, create_ibss, - keys, key_count, timeout); + status = do_connect(linkid, gbuf, attrp, create_ibss, keys, + key_count, timeout); goto done; } @@ -686,7 +595,7 @@ dladm_wlan_connect(const char *link, dladm_wlan_attr_t *attrp, for (i = 0; i < state.cs_count; i++) { dladm_wlan_attr_t *ap = wl_list[i]; - status = do_connect(link, fd, gbuf, ap, create_ibss, keys, + status = do_connect(linkid, gbuf, ap, create_ibss, keys, key_count, timeout); if (status == DLADM_STATUS_OK) break; @@ -694,15 +603,15 @@ dladm_wlan_connect(const char *link, dladm_wlan_attr_t *attrp, if (!set_authmode) { ap->wa_auth = DLADM_WLAN_AUTH_SHARED; ap->wa_valid |= DLADM_WLAN_ATTR_AUTH; - status = do_connect(link, fd, gbuf, ap, create_ibss, - keys, key_count, timeout); + status = do_connect(linkid, gbuf, ap, create_ibss, keys, + key_count, timeout); if (status == DLADM_STATUS_OK) break; } } done: if ((status != DLADM_STATUS_OK) && (status != DLADM_STATUS_ISCONN)) - (void) do_disconnect(link, fd, gbuf); + (void) do_disconnect(linkid, gbuf); while (state.cs_list != NULL) { nodep = state.cs_list; @@ -711,44 +620,36 @@ done: } free(gbuf); free(wl_list); - (void) close(fd); return (status); } dladm_status_t -dladm_wlan_disconnect(const char *link) +dladm_wlan_disconnect(datalink_id_t linkid) { - int fd; wldp_t *gbuf; dladm_status_t status; - if ((fd = open_link(link)) < 0) - return (DLADM_STATUS_BADARG); + if ((status = dladm_wlan_validate(linkid)) != DLADM_STATUS_OK) + return (status); if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) { status = DLADM_STATUS_NOMEM; goto done; } - if (do_get_linkstatus(fd, gbuf) < 0) { - status = DLADM_STATUS_FAILED; + if ((status = do_get_linkstatus(linkid, gbuf)) != DLADM_STATUS_OK) goto done; - } if (!IS_CONNECTED(gbuf)) { status = DLADM_STATUS_NOTCONN; goto done; } - if (do_disconnect(link, fd, gbuf) < 0) { - status = DLADM_STATUS_FAILED; + if ((status = do_disconnect(linkid, gbuf)) != DLADM_STATUS_OK) goto done; - } - if (do_get_linkstatus(fd, gbuf) < 0) { - status = DLADM_STATUS_FAILED; + if ((status = do_get_linkstatus(linkid, gbuf)) != DLADM_STATUS_OK) goto done; - } if (IS_CONNECTED(gbuf)) { status = DLADM_STATUS_FAILED; @@ -758,85 +659,12 @@ dladm_wlan_disconnect(const char *link) status = DLADM_STATUS_OK; done: free(gbuf); - (void) close(fd); return (status); } -typedef struct dladm_wlan_linkname { - char wl_name[MAXNAMELEN]; - struct dladm_wlan_linkname *wl_next; -} dladm_wlan_linkname_t; - -typedef struct dladm_wlan_walk { - dladm_wlan_linkname_t *ww_list; - dladm_status_t ww_status; -} dladm_wlan_walk_t; - -/* ARGSUSED */ -static int -append_linkname(di_node_t node, di_minor_t minor, void *arg) -{ - dladm_wlan_walk_t *statep = arg; - dladm_wlan_linkname_t **lastp = &statep->ww_list; - dladm_wlan_linkname_t *wlp = *lastp; - char name[MAXNAMELEN]; - - (void) snprintf(name, MAXNAMELEN, "%s%d", - di_driver_name(node), di_instance(node)); - - while (wlp != NULL) { - if (strcmp(wlp->wl_name, name) == 0) - return (DI_WALK_CONTINUE); - - lastp = &wlp->wl_next; - wlp = wlp->wl_next; - } - if ((wlp = malloc(sizeof (*wlp))) == NULL) { - statep->ww_status = DLADM_STATUS_NOMEM; - return (DI_WALK_CONTINUE); - } - - (void) strlcpy(wlp->wl_name, name, MAXNAMELEN); - wlp->wl_next = NULL; - *lastp = wlp; - - return (DI_WALK_CONTINUE); -} - -dladm_status_t -dladm_wlan_walk(void *arg, boolean_t (*func)(void *, const char *)) -{ - di_node_t root; - dladm_wlan_walk_t state; - dladm_wlan_linkname_t *wlp, *wlp_next; - boolean_t cont = B_TRUE; - - if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL) - return (DLADM_STATUS_FAILED); - - state.ww_list = NULL; - state.ww_status = DLADM_STATUS_OK; - (void) di_walk_minor(root, DDI_NT_NET_WIFI, DI_CHECK_ALIAS, - &state, append_linkname); - di_fini(root); - - for (wlp = state.ww_list; wlp != NULL; wlp = wlp_next) { - /* - * NOTE: even if (*func)() returns B_FALSE, the loop continues - * since all memory must be freed. - */ - if (cont) - cont = (*func)(arg, wlp->wl_name); - wlp_next = wlp->wl_next; - free(wlp); - } - return (state.ww_status); -} - dladm_status_t -dladm_wlan_get_linkattr(const char *link, dladm_wlan_linkattr_t *attrp) +dladm_wlan_get_linkattr(datalink_id_t linkid, dladm_wlan_linkattr_t *attrp) { - int fd; wldp_t *gbuf; wl_rssi_t signal; wl_bss_type_t bsstype; @@ -844,13 +672,13 @@ dladm_wlan_get_linkattr(const char *link, dladm_wlan_linkattr_t *attrp) wl_encryption_t encryption; wl_rates_t *ratesp; dladm_wlan_attr_t *wl_attrp; - dladm_status_t status = DLADM_STATUS_FAILED; + dladm_status_t status; if (attrp == NULL) return (DLADM_STATUS_BADARG); - if ((fd = open_link(link)) < 0) - return (DLADM_STATUS_LINKINVAL); + if ((status = dladm_wlan_validate(linkid)) != DLADM_STATUS_OK) + goto done; if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) { status = DLADM_STATUS_NOMEM; @@ -860,17 +688,16 @@ dladm_wlan_get_linkattr(const char *link, dladm_wlan_linkattr_t *attrp) (void) memset(attrp, 0, sizeof (*attrp)); wl_attrp = &attrp->la_wlan_attr; - if (do_get_linkstatus(fd, gbuf) < 0) + if ((status = do_get_linkstatus(linkid, gbuf)) != DLADM_STATUS_OK) goto done; attrp->la_valid |= DLADM_WLAN_LINKATTR_STATUS; - if (!IS_CONNECTED(gbuf)) { - attrp->la_status = DLADM_WLAN_LINKSTATUS_DISCONNECTED; - } else { - attrp->la_status = DLADM_WLAN_LINKSTATUS_CONNECTED; - } + if (!IS_CONNECTED(gbuf)) + attrp->la_status = DLADM_WLAN_LINK_DISCONNECTED; + else + attrp->la_status = DLADM_WLAN_LINK_CONNECTED; - if (do_get_essid(fd, gbuf) < 0) + if ((status = do_get_essid(linkid, gbuf)) != DLADM_STATUS_OK) goto done; (void) strlcpy(wl_attrp->wa_essid.we_bytes, @@ -879,7 +706,7 @@ dladm_wlan_get_linkattr(const char *link, dladm_wlan_linkattr_t *attrp) wl_attrp->wa_valid |= DLADM_WLAN_ATTR_ESSID; - if (do_get_bssid(fd, gbuf) < 0) + if ((status = do_get_bssid(linkid, gbuf)) != DLADM_STATUS_OK) goto done; (void) memcpy(wl_attrp->wa_bssid.wb_bytes, gbuf->wldp_buf, @@ -887,13 +714,13 @@ dladm_wlan_get_linkattr(const char *link, dladm_wlan_linkattr_t *attrp) wl_attrp->wa_valid |= DLADM_WLAN_ATTR_BSSID; - if (attrp->la_status == DLADM_WLAN_LINKSTATUS_DISCONNECTED) { + if (attrp->la_status == DLADM_WLAN_LINK_DISCONNECTED) { attrp->la_valid |= DLADM_WLAN_LINKATTR_WLAN; status = DLADM_STATUS_OK; goto done; } - if (do_get_encryption(fd, gbuf) < 0) + if ((status = do_get_encryption(linkid, gbuf)) != DLADM_STATUS_OK) goto done; encryption = *(wl_encryption_t *)(gbuf->wldp_buf); @@ -914,14 +741,14 @@ dladm_wlan_get_linkattr(const char *link, dladm_wlan_linkattr_t *attrp) break; } - if (do_get_signal(fd, gbuf) < 0) + if ((status = do_get_signal(linkid, gbuf)) != DLADM_STATUS_OK) goto done; signal = *(wl_rssi_t *)(gbuf->wldp_buf); wl_attrp->wa_valid |= DLADM_WLAN_ATTR_STRENGTH; wl_attrp->wa_strength = DLADM_WLAN_SIGNAL2STRENGTH(signal); - if (do_get_rate(fd, gbuf) < 0) + if ((status = do_get_rate(linkid, gbuf)) != DLADM_STATUS_OK) goto done; ratesp = (wl_rates_t *)(gbuf->wldp_buf); @@ -936,7 +763,7 @@ dladm_wlan_get_linkattr(const char *link, dladm_wlan_linkattr_t *attrp) wl_attrp->wa_valid |= DLADM_WLAN_ATTR_SPEED; } - if (do_get_authmode(fd, gbuf) < 0) + if ((status = do_get_authmode(linkid, gbuf)) != DLADM_STATUS_OK) goto done; authmode = *(wl_authmode_t *)(gbuf->wldp_buf); @@ -954,7 +781,7 @@ dladm_wlan_get_linkattr(const char *link, dladm_wlan_linkattr_t *attrp) break; } - if (do_get_bsstype(fd, gbuf) < 0) + if ((status = do_get_bsstype(linkid, gbuf)) != DLADM_STATUS_OK) goto done; bsstype = *(wl_bss_type_t *)(gbuf->wldp_buf); @@ -975,7 +802,7 @@ dladm_wlan_get_linkattr(const char *link, dladm_wlan_linkattr_t *attrp) break; } - if (do_get_mode(fd, gbuf) < 0) + if ((status = do_get_mode(linkid, gbuf)) != DLADM_STATUS_OK) goto done; wl_attrp->wa_mode = do_convert_mode((wl_phy_conf_t *)(gbuf->wldp_buf)); @@ -988,231 +815,30 @@ dladm_wlan_get_linkattr(const char *link, dladm_wlan_linkattr_t *attrp) done: free(gbuf); - (void) close(fd); return (status); } -boolean_t -dladm_wlan_is_valid(const char *link) -{ - int fd = open_link(link); - - if (fd < 0) - return (B_FALSE); - - (void) close(fd); - return (B_TRUE); -} - -/* ARGSUSED */ -static dladm_status_t -do_check_prop(int fd, wldp_t *guf, prop_desc_t *pdp, char **prop_val, - uint_t val_cnt, val_desc_t **vdpp) -{ - int i; - val_desc_t *vdp; - - if (pdp->pd_nmodval == 0) - return (DLADM_STATUS_PROPRDONLY); - - if (val_cnt != 1) - return (DLADM_STATUS_BADVALCNT); - - for (i = 0; i < pdp->pd_nmodval; i++) - if (strcasecmp(*prop_val, pdp->pd_modval[i].vd_name) == 0) - break; - - if (i == pdp->pd_nmodval) - return (DLADM_STATUS_BADVAL); - - vdp = malloc(sizeof (val_desc_t)); - if (vdp == NULL) - return (DLADM_STATUS_NOMEM); - - (void) memcpy(vdp, &pdp->pd_modval[i], sizeof (val_desc_t)); - *vdpp = vdp; - return (DLADM_STATUS_OK); -} - static dladm_status_t -do_set_prop(int fd, wldp_t *gbuf, prop_desc_t *pdp, - char **prop_val, uint_t val_cnt) +dladm_wlan_validate(datalink_id_t linkid) { + wldp_t *gbuf; dladm_status_t status; - val_desc_t *vdp = NULL; - uint_t cnt; - - if (pdp->pd_set == NULL) - return (DLADM_STATUS_PROPRDONLY); - - if (prop_val != NULL) { - status = pdp->pd_check(fd, gbuf, pdp, prop_val, - val_cnt, &vdp); - - if (status != DLADM_STATUS_OK) - return (status); - - cnt = val_cnt; - } else { - if (pdp->pd_defval.vd_name == NULL) - return (DLADM_STATUS_NOTSUP); - - if ((vdp = malloc(sizeof (val_desc_t))) == NULL) - return (DLADM_STATUS_NOMEM); - - *vdp = pdp->pd_defval; - cnt = 1; - } - status = pdp->pd_set(fd, gbuf, vdp, cnt); - if (status == DLADM_STATUS_OK) { - /* - * Some ioctls return 0 but store error code in - * wldp_result. Need to fix them. - */ - if (gbuf->wldp_result != WL_SUCCESS) - status = dladm_wlan_wlresult2status(gbuf); - } - free(vdp); - return (status); -} - -dladm_status_t -dladm_wlan_set_prop(const char *link, const char *prop_name, - char **prop_val, uint_t val_cnt, char **errprop) -{ - int fd, i; - wldp_t *gbuf = NULL; - boolean_t found = B_FALSE; - dladm_status_t status = DLADM_STATUS_OK; - - if ((prop_name == NULL && prop_val != NULL) || - (prop_val != NULL && val_cnt == 0)) - return (DLADM_STATUS_BADARG); - - if ((fd = open_link(link)) < 0) - return (DLADM_STATUS_LINKINVAL); if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) { status = DLADM_STATUS_NOMEM; goto done; } - for (i = 0; i < DLADM_WLAN_MAX_PROPS; i++) { - prop_desc_t *pdp = &prop_table[i]; - dladm_status_t s; - - if (prop_name != NULL && - (strcasecmp(prop_name, pdp->pd_name) != 0)) - continue; - - found = B_TRUE; - s = do_set_prop(fd, gbuf, pdp, prop_val, val_cnt); - - if (prop_name != NULL) { - status = s; - break; - } else { - if (s != DLADM_STATUS_OK && - s != DLADM_STATUS_NOTSUP) { - if (errprop != NULL) - *errprop = pdp->pd_name; - status = s; - break; - } - } - } - if (!found) - status = DLADM_STATUS_NOTFOUND; -done: - free(gbuf); - (void) close(fd); - return (status); -} - -/* ARGSUSED */ -dladm_status_t -dladm_wlan_walk_prop(const char *link, void *arg, - boolean_t (*func)(void *, const char *)) -{ - int i; - - for (i = 0; i < DLADM_WLAN_MAX_PROPS; i++) { - if (!func(arg, prop_table[i].pd_name)) - break; - } - return (DLADM_STATUS_OK); -} - -dladm_status_t -dladm_wlan_get_prop(const char *link, dladm_prop_type_t type, - const char *prop_name, char **prop_val, uint_t *val_cnt) -{ - int fd; - int i; - wldp_t *gbuf; - dladm_status_t status; - uint_t cnt; - prop_desc_t *pdp; - - if (prop_val == NULL || val_cnt == NULL || *val_cnt == 0) - return (DLADM_STATUS_BADARG); - - for (i = 0; i < DLADM_WLAN_MAX_PROPS; i++) - if (strcasecmp(prop_name, prop_table[i].pd_name) == 0) - break; - - if (i == DLADM_WLAN_MAX_PROPS) - return (DLADM_STATUS_NOTFOUND); - - if ((fd = open_link(link)) < 0) - return (DLADM_STATUS_LINKINVAL); - - if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) { - status = DLADM_STATUS_NOMEM; + /* + * Check to see if the link is wireless. + */ + if ((status = do_get_bsstype(linkid, gbuf)) != DLADM_STATUS_OK) { + status = DLADM_STATUS_LINKINVAL; goto done; } - pdp = &prop_table[i]; - status = DLADM_STATUS_OK; - switch (type) { - case DLADM_PROP_VAL_CURRENT: - status = pdp->pd_get(fd, gbuf, prop_val, val_cnt); - break; - - case DLADM_PROP_VAL_DEFAULT: - if (pdp->pd_defval.vd_name == NULL) { - status = DLADM_STATUS_NOTSUP; - break; - } - (void) strcpy(*prop_val, pdp->pd_defval.vd_name); - *val_cnt = 1; - break; - - case DLADM_PROP_VAL_MODIFIABLE: - if (pdp->pd_getmod != NULL) { - status = pdp->pd_getmod(fd, gbuf, prop_val, val_cnt); - break; - } - cnt = pdp->pd_nmodval; - if (cnt == 0) { - status = DLADM_STATUS_NOTSUP; - } else if (cnt > *val_cnt) { - status = DLADM_STATUS_TOOSMALL; - } else { - for (i = 0; i < cnt; i++) { - (void) strcpy(prop_val[i], - pdp->pd_modval[i].vd_name); - } - *val_cnt = cnt; - } - break; - default: - status = DLADM_STATUS_BADARG; - break; - } done: free(gbuf); - (void) close(fd); return (status); } @@ -1422,19 +1048,45 @@ dladm_wlan_str2linkstatus(const char *str, dladm_wlan_linkstatus_t *linkstatus) { uint_t val; - if (!find_val_by_name(str, linkstatus_vals, VALCNT(linkstatus_vals), - &val)) + if (!find_val_by_name(str, linkstatus_vals, + VALCNT(linkstatus_vals), &val)) { return (DLADM_STATUS_BADARG); + } *linkstatus = (dladm_wlan_linkstatus_t)val; return (DLADM_STATUS_OK); } -static int -do_ioctl(int fd, wldp_t *gbuf, uint_t id, size_t len, uint_t cmd, size_t cmdlen) +dladm_status_t +i_dladm_wlan_ioctl(datalink_id_t linkid, wldp_t *gbuf, uint_t id, size_t len, + uint_t cmd, size_t cmdlen) { - int rc; + char linkname[MAXPATHLEN]; + int fd, rc; struct strioctl stri; + uint32_t flags; + dladm_status_t status; + uint32_t media; + char link[MAXLINKNAMELEN]; + + if ((status = dladm_datalink_id2info(linkid, &flags, NULL, &media, + link, MAXLINKNAMELEN)) != DLADM_STATUS_OK) { + return (status); + } + + if (media != DL_WIFI) + return (DLADM_STATUS_BADARG); + + if (!(flags & DLADM_OPT_ACTIVE)) + return (DLADM_STATUS_TEMPONLY); + + /* + * dlpi_open() is not used here because libdlpi depends on libdladm, + * and we do not want to introduce recursive dependencies. + */ + (void) snprintf(linkname, MAXPATHLEN, "/dev/net/%s", link); + if ((fd = open(linkname, O_RDWR)) < 0) + return (DLADM_STATUS_LINKINVAL); gbuf->wldp_type = NET_802_11; gbuf->wldp_id = id; @@ -1446,250 +1098,140 @@ do_ioctl(int fd, wldp_t *gbuf, uint_t id, size_t len, uint_t cmd, size_t cmdlen) stri.ic_len = cmdlen; if ((rc = ioctl(fd, I_STR, &stri)) != 0) { - if (rc > 0) - errno = rc; - return (-1); + if (rc > 0) { + /* + * Non-negative return value indicates the specific + * operation failed and the reason for the failure + * was stored in gbuf->wldp_result. + */ + status = dladm_wlan_wlresult2status(gbuf); + } else { + /* + * Negative return value indicates the ioctl failed. + */ + status = dladm_errno2status(errno); + } } - return (0); + (void) close(fd); + return (status); } -static int -do_get_ioctl(int fd, wldp_t *gbuf, uint_t id) +dladm_status_t +i_dladm_wlan_get_ioctl(datalink_id_t linkid, wldp_t *gbuf, uint_t id) { (void) memset(gbuf, 0, MAX_BUF_LEN); - return (do_ioctl(fd, gbuf, id, MAX_BUF_LEN, WLAN_GET_PARAM, - MAX_BUF_LEN)); + return (i_dladm_wlan_ioctl(linkid, gbuf, id, MAX_BUF_LEN, + WLAN_GET_PARAM, MAX_BUF_LEN)); } -static int -do_set_ioctl(int fd, wldp_t *gbuf, uint_t id, void *buf, uint_t buflen) +dladm_status_t +i_dladm_wlan_set_ioctl(datalink_id_t linkid, uint_t id, void *buf, + uint_t buflen) { + wldp_t *gbuf; + dladm_status_t status = DLADM_STATUS_OK; + + if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) + return (DLADM_STATUS_NOMEM); + (void) memset(gbuf, 0, MAX_BUF_LEN); (void) memcpy(gbuf->wldp_buf, buf, buflen); buflen += WIFI_BUF_OFFSET; - return (do_ioctl(fd, gbuf, id, buflen, WLAN_SET_PARAM, buflen)); + status = i_dladm_wlan_ioctl(linkid, gbuf, id, buflen, + WLAN_SET_PARAM, buflen); + + free(gbuf); + return (status); } -static int -do_cmd_ioctl(int fd, wldp_t *gbuf, uint_t cmd) +static dladm_status_t +do_cmd_ioctl(datalink_id_t linkid, wldp_t *gbuf, uint_t cmd) { (void) memset(gbuf, 0, MAX_BUF_LEN); - return (do_ioctl(fd, gbuf, cmd, sizeof (wldp_t), WLAN_COMMAND, - sizeof (wldp_t))); + return (i_dladm_wlan_ioctl(linkid, gbuf, cmd, sizeof (wldp_t), + WLAN_COMMAND, sizeof (wldp_t))); } -static int -do_scan(int fd, wldp_t *gbuf) +static dladm_status_t +do_scan(datalink_id_t linkid, wldp_t *gbuf) { - return (do_cmd_ioctl(fd, gbuf, WL_SCAN)); + return (do_cmd_ioctl(linkid, gbuf, WL_SCAN)); } -static int -do_disconnect(const char *link, int fd, wldp_t *gbuf) +static dladm_status_t +do_disconnect(datalink_id_t linkid, wldp_t *gbuf) { - if (do_get_wpamode(fd, gbuf) == 0 && ((wl_wpa_t *)(gbuf-> - wldp_buf))->wpa_flag > 0) - (void) wpa_instance_delete(link); + if (do_get_wpamode(linkid, gbuf) == 0 && + ((wl_wpa_t *)(gbuf->wldp_buf))->wpa_flag > 0) + (void) wpa_instance_delete(linkid); - return (do_cmd_ioctl(fd, gbuf, WL_DISASSOCIATE)); + return (do_cmd_ioctl(linkid, gbuf, WL_DISASSOCIATE)); } -static int -do_get_esslist(int fd, wldp_t *gbuf) +static dladm_status_t +do_get_esslist(datalink_id_t linkid, wldp_t *gbuf) { (void) memset(gbuf, 0, MAX_BUF_LEN); - return (do_ioctl(fd, gbuf, WL_ESS_LIST, MAX_BUF_LEN, + return (i_dladm_wlan_ioctl(linkid, gbuf, WL_ESS_LIST, MAX_BUF_LEN, WLAN_GET_PARAM, sizeof (wldp_t))); } -static int -do_get_bssid(int fd, wldp_t *gbuf) -{ - return (do_get_ioctl(fd, gbuf, WL_BSSID)); -} - -static int -do_get_essid(int fd, wldp_t *gbuf) -{ - return (do_get_ioctl(fd, gbuf, WL_ESSID)); -} - -static int -do_get_bsstype(int fd, wldp_t *gbuf) -{ - return (do_get_ioctl(fd, gbuf, WL_BSS_TYPE)); -} - -static int -do_get_linkstatus(int fd, wldp_t *gbuf) -{ - return (do_get_ioctl(fd, gbuf, WL_LINKSTATUS)); -} - -static int -do_get_rate(int fd, wldp_t *gbuf) -{ - return (do_get_ioctl(fd, gbuf, WL_DESIRED_RATES)); -} - -static int -do_get_phyconf(int fd, wldp_t *gbuf) -{ - return (do_get_ioctl(fd, gbuf, WL_PHY_CONFIG)); -} - -static int -do_get_powermode(int fd, wldp_t *gbuf) -{ - return (do_get_ioctl(fd, gbuf, WL_POWER_MODE)); -} - -static int -do_get_radio(int fd, wldp_t *gbuf) -{ - return (do_get_ioctl(fd, gbuf, WL_RADIO)); -} - -static int -do_get_authmode(int fd, wldp_t *gbuf) -{ - return (do_get_ioctl(fd, gbuf, WL_AUTH_MODE)); -} - -static int -do_get_encryption(int fd, wldp_t *gbuf) +static dladm_status_t +do_get_bssid(datalink_id_t linkid, wldp_t *gbuf) { - return (do_get_ioctl(fd, gbuf, WL_ENCRYPTION)); + return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_BSSID)); } -static int -do_get_signal(int fd, wldp_t *gbuf) +static dladm_status_t +do_get_essid(datalink_id_t linkid, wldp_t *gbuf) { - return (do_get_ioctl(fd, gbuf, WL_RSSI)); + return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_ESSID)); } -static int -do_get_mode(int fd, wldp_t *gbuf) +static dladm_status_t +do_get_bsstype(datalink_id_t linkid, wldp_t *gbuf) { - return (do_get_ioctl(fd, gbuf, WL_PHY_CONFIG)); + return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_BSS_TYPE)); } static dladm_status_t -do_get_rate_common(wldp_t *gbuf, char **prop_val, uint_t *val_cnt) +do_get_linkstatus(datalink_id_t linkid, wldp_t *gbuf) { - wl_rates_t *wrp = (wl_rates_t *)gbuf->wldp_buf; - uint_t cnt = wrp->wl_rates_num; - uint_t i; - - if (cnt > *val_cnt) - return (DLADM_STATUS_TOOSMALL); - if (wrp->wl_rates_rates[0] == 0) { - prop_val[0][0] = '\0'; - *val_cnt = 1; - return (DLADM_STATUS_OK); - } - - for (i = 0; i < cnt; i++) { - (void) snprintf(prop_val[i], DLADM_STRSIZE, "%.*f", - wrp->wl_rates_rates[i] % 2, - (float)wrp->wl_rates_rates[i] / 2); - } - *val_cnt = cnt; - return (DLADM_STATUS_OK); + return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_LINKSTATUS)); } static dladm_status_t -do_get_rate_prop(int fd, wldp_t *gbuf, char **prop_val, uint_t *val_cnt) +do_get_rate(datalink_id_t linkid, wldp_t *gbuf) { - if (do_get_rate(fd, gbuf) < 0) - return (dladm_wlan_wlresult2status(gbuf)); - - return (do_get_rate_common(gbuf, prop_val, val_cnt)); + return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_DESIRED_RATES)); } static dladm_status_t -do_get_rate_mod(int fd, wldp_t *gbuf, char **prop_val, uint_t *val_cnt) +do_get_authmode(datalink_id_t linkid, wldp_t *gbuf) { - if (do_get_ioctl(fd, gbuf, WL_SUPPORTED_RATES) < 0) - return (DLADM_STATUS_FAILED); - - return (do_get_rate_common(gbuf, prop_val, val_cnt)); + return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_AUTH_MODE)); } static dladm_status_t -do_get_channel_prop(int fd, wldp_t *gbuf, char **prop_val, uint_t *val_cnt) +do_get_encryption(datalink_id_t linkid, wldp_t *gbuf) { - uint32_t channel; - - if (do_get_phyconf(fd, gbuf) < 0) - return (dladm_wlan_wlresult2status(gbuf)); - - if (!do_convert_chan((wl_phy_conf_t *)gbuf->wldp_buf, &channel)) - return (DLADM_STATUS_NOTFOUND); - - (void) snprintf(*prop_val, DLADM_STRSIZE, "%u", channel); - *val_cnt = 1; - - return (DLADM_STATUS_OK); + return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_ENCRYPTION)); } static dladm_status_t -do_get_powermode_prop(int fd, wldp_t *gbuf, char **prop_val, uint_t *val_cnt) +do_get_signal(datalink_id_t linkid, wldp_t *gbuf) { - wl_ps_mode_t *mode; - const char *s; - - if (do_get_powermode(fd, gbuf) < 0) - return (dladm_wlan_wlresult2status(gbuf)); - - mode = (wl_ps_mode_t *)(gbuf->wldp_buf); - switch (mode->wl_ps_mode) { - case WL_PM_AM: - s = "off"; - break; - case WL_PM_MPS: - s = "max"; - break; - case WL_PM_FAST: - s = "fast"; - break; - default: - return (DLADM_STATUS_NOTFOUND); - } - (void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s); - *val_cnt = 1; - - return (DLADM_STATUS_OK); + return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_RSSI)); } static dladm_status_t -do_get_radio_prop(int fd, wldp_t *gbuf, char **prop_val, uint_t *val_cnt) +do_get_mode(datalink_id_t linkid, wldp_t *gbuf) { - wl_radio_t radio; - const char *s; - - if (do_get_radio(fd, gbuf) < 0) - return (dladm_wlan_wlresult2status(gbuf)); - - radio = *(wl_radio_t *)(gbuf->wldp_buf); - switch (radio) { - case B_TRUE: - s = "on"; - break; - case B_FALSE: - s = "off"; - break; - default: - return (DLADM_STATUS_NOTFOUND); - } - (void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s); - *val_cnt = 1; - - return (DLADM_STATUS_OK); + return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_PHY_CONFIG)); } -static int -do_set_bsstype(int fd, wldp_t *gbuf, dladm_wlan_bsstype_t *bsstype) +static dladm_status_t +do_set_bsstype(datalink_id_t linkid, dladm_wlan_bsstype_t *bsstype) { wl_bss_type_t ibsstype; @@ -1704,12 +1246,12 @@ do_set_bsstype(int fd, wldp_t *gbuf, dladm_wlan_bsstype_t *bsstype) ibsstype = WL_BSS_ANY; break; } - return (do_set_ioctl(fd, gbuf, WL_BSS_TYPE, &ibsstype, + return (i_dladm_wlan_set_ioctl(linkid, WL_BSS_TYPE, &ibsstype, sizeof (ibsstype))); } -static int -do_set_authmode(int fd, wldp_t *gbuf, dladm_wlan_auth_t *auth) +static dladm_status_t +do_set_authmode(datalink_id_t linkid, dladm_wlan_auth_t *auth) { wl_authmode_t auth_mode; @@ -1721,14 +1263,14 @@ do_set_authmode(int fd, wldp_t *gbuf, dladm_wlan_auth_t *auth) auth_mode = WL_SHAREDKEY; break; default: - return (-1); + return (DLADM_STATUS_NOTSUP); } - return (do_set_ioctl(fd, gbuf, WL_AUTH_MODE, &auth_mode, + return (i_dladm_wlan_set_ioctl(linkid, WL_AUTH_MODE, &auth_mode, sizeof (auth_mode))); } -static int -do_set_encryption(int fd, wldp_t *gbuf, dladm_wlan_secmode_t *secmode) +static dladm_status_t +do_set_encryption(datalink_id_t linkid, dladm_wlan_secmode_t *secmode) { wl_encryption_t encryption; @@ -1742,14 +1284,14 @@ do_set_encryption(int fd, wldp_t *gbuf, dladm_wlan_secmode_t *secmode) case DLADM_WLAN_SECMODE_WPA: return (0); default: - return (-1); + return (DLADM_STATUS_NOTSUP); } - return (do_set_ioctl(fd, gbuf, WL_ENCRYPTION, &encryption, + return (i_dladm_wlan_set_ioctl(linkid, WL_ENCRYPTION, &encryption, sizeof (encryption))); } -static int -do_set_key(int fd, wldp_t *gbuf, dladm_wlan_key_t *keys, +static dladm_status_t +do_set_key(datalink_id_t linkid, dladm_wlan_key_t *keys, uint_t key_count) { int i; @@ -1758,7 +1300,7 @@ do_set_key(int fd, wldp_t *gbuf, dladm_wlan_key_t *keys, dladm_wlan_key_t *kp; if (key_count == 0 || key_count > MAX_NWEPKEYS || keys == NULL) - return (-1); + return (DLADM_STATUS_BADARG); (void) memset(wepkey_tab, 0, sizeof (wepkey_tab)); for (i = 0; i < MAX_NWEPKEYS; i++) @@ -1767,10 +1309,10 @@ do_set_key(int fd, wldp_t *gbuf, dladm_wlan_key_t *keys, for (i = 0; i < key_count; i++) { kp = &keys[i]; if (kp->wk_idx == 0 || kp->wk_idx > MAX_NWEPKEYS) - return (-1); + return (DLADM_STATUS_BADARG); if (kp->wk_len != DLADM_WLAN_WEPKEY64_LEN && kp->wk_len != DLADM_WLAN_WEPKEY128_LEN) - return (-1); + return (DLADM_STATUS_BADARG); wkp = &wepkey_tab[kp->wk_idx - 1]; wkp->wl_wep_operation = WL_ADD; @@ -1778,12 +1320,12 @@ do_set_key(int fd, wldp_t *gbuf, dladm_wlan_key_t *keys, (void) memcpy(wkp->wl_wep_key, kp->wk_val, kp->wk_len); } - return (do_set_ioctl(fd, gbuf, WL_WEP_KEY_TAB, &wepkey_tab, + return (i_dladm_wlan_set_ioctl(linkid, WL_WEP_KEY_TAB, &wepkey_tab, sizeof (wepkey_tab))); } -static int -do_set_essid(int fd, wldp_t *gbuf, dladm_wlan_essid_t *essid) +static dladm_status_t +do_set_essid(datalink_id_t linkid, dladm_wlan_essid_t *essid) { wl_essid_t iessid; @@ -1794,186 +1336,34 @@ do_set_essid(int fd, wldp_t *gbuf, dladm_wlan_essid_t *essid) (void) strlcpy(iessid.wl_essid_essid, essid->we_bytes, sizeof (iessid.wl_essid_essid)); } else { - return (-1); - } - return (do_set_ioctl(fd, gbuf, WL_ESSID, &iessid, sizeof (iessid))); -} - -/* ARGSUSED */ -static dladm_status_t -do_check_rate(int fd, wldp_t *gbuf, prop_desc_t *pdp, char **prop_val, - uint_t val_cnt, val_desc_t **vdpp) -{ - int i; - uint_t modval_cnt = MAX_SUPPORT_RATES; - char *buf, **modval; - dladm_status_t status; - val_desc_t *vdp = NULL; - - if (val_cnt != 1) - return (DLADM_STATUS_BADVALCNT); - - buf = malloc((sizeof (char *) + DLADM_STRSIZE) * MAX_SUPPORT_RATES); - if (buf == NULL) { - status = DLADM_STATUS_NOMEM; - goto done; - } - - modval = (char **)(void *)buf; - for (i = 0; i < MAX_SUPPORT_RATES; i++) { - modval[i] = buf + sizeof (char *) * MAX_SUPPORT_RATES + - i * DLADM_STRSIZE; - } - - status = do_get_rate_mod(fd, gbuf, modval, &modval_cnt); - if (status != DLADM_STATUS_OK) - goto done; - - vdp = malloc(sizeof (val_desc_t)); - if (vdp == NULL) { - status = DLADM_STATUS_NOMEM; - 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); - status = DLADM_STATUS_OK; - *vdpp = vdp; - vdp = NULL; - break; - } - } - if (i == modval_cnt) - status = DLADM_STATUS_BADVAL; -done: - free(buf); - free(vdp); - return (status); -} - -static dladm_status_t -do_set_rate_prop(int fd, wldp_t *gbuf, val_desc_t *vdp, uint_t val_cnt) -{ - dladm_wlan_rates_t rates; - - if (val_cnt != 1) - return (DLADM_STATUS_BADVALCNT); - - rates.wr_cnt = 1; - rates.wr_rates[0] = vdp[0].vd_val; - - if (do_set_rate(fd, gbuf, &rates) < 0) - return (dladm_wlan_wlresult2status(gbuf)); - - return (DLADM_STATUS_OK); -} - -static int -do_set_rate(int fd, wldp_t *gbuf, dladm_wlan_rates_t *rates) -{ - int i; - uint_t len; - wl_rates_t *wrp = (wl_rates_t *)gbuf->wldp_buf; - - (void) memset(gbuf, 0, MAX_BUF_LEN); - - for (i = 0; i < rates->wr_cnt; i++) - wrp->wl_rates_rates[i] = rates->wr_rates[i]; - wrp->wl_rates_num = rates->wr_cnt; - - len = offsetof(wl_rates_t, wl_rates_rates) + - (rates->wr_cnt * sizeof (char)) + WIFI_BUF_OFFSET; - return (do_ioctl(fd, gbuf, WL_DESIRED_RATES, len, WLAN_SET_PARAM, len)); -} - -/* ARGSUSED */ -static dladm_status_t -do_set_powermode_prop(int fd, wldp_t *gbuf, val_desc_t *vdp, uint_t val_cnt) -{ - dladm_wlan_powermode_t powermode = (dladm_wlan_powermode_t)vdp->vd_val; - - if (do_set_powermode(fd, gbuf, &powermode) < 0) - return (dladm_wlan_wlresult2status(gbuf)); - - return (DLADM_STATUS_OK); -} - -static int -do_set_powermode(int fd, wldp_t *gbuf, dladm_wlan_powermode_t *pm) -{ - wl_ps_mode_t ps_mode; - - (void) memset(&ps_mode, 0xff, sizeof (ps_mode)); - - switch (*pm) { - case DLADM_WLAN_PM_OFF: - ps_mode.wl_ps_mode = WL_PM_AM; - break; - case DLADM_WLAN_PM_MAX: - ps_mode.wl_ps_mode = WL_PM_MPS; - break; - case DLADM_WLAN_PM_FAST: - ps_mode.wl_ps_mode = WL_PM_FAST; - break; - default: - return (-1); + return (DLADM_STATUS_BADARG); } - return (do_set_ioctl(fd, gbuf, WL_POWER_MODE, &ps_mode, - sizeof (ps_mode))); + return (i_dladm_wlan_set_ioctl(linkid, WL_ESSID, &iessid, + sizeof (iessid))); } -/* ARGSUSED */ static dladm_status_t -do_set_radio_prop(int fd, wldp_t *gbuf, val_desc_t *vdp, uint_t val_cnt) -{ - dladm_wlan_radio_t radio = (dladm_wlan_radio_t)vdp->vd_val; - - if (do_set_radio(fd, gbuf, &radio) < 0) - return (dladm_wlan_wlresult2status(gbuf)); - - return (DLADM_STATUS_OK); -} - -static int -do_set_radio(int fd, wldp_t *gbuf, dladm_wlan_radio_t *radio) -{ - wl_radio_t r; - - switch (*radio) { - case DLADM_WLAN_RADIO_ON: - r = B_TRUE; - break; - case DLADM_WLAN_RADIO_OFF: - r = B_FALSE; - break; - default: - return (-1); - } - return (do_set_ioctl(fd, gbuf, WL_RADIO, &r, sizeof (r))); -} - -static int -do_set_channel(int fd, wldp_t *gbuf, dladm_wlan_channel_t *channel) +do_set_channel(datalink_id_t linkid, dladm_wlan_channel_t *channel) { wl_phy_conf_t phy_conf; if (*channel > MAX_CHANNEL_NUM) - return (-1); + return (DLADM_STATUS_BADVAL); (void) memset(&phy_conf, 0xff, sizeof (phy_conf)); phy_conf.wl_phy_dsss_conf.wl_dsss_channel = *channel; - return (do_set_ioctl(fd, gbuf, WL_PHY_CONFIG, &phy_conf, + return (i_dladm_wlan_set_ioctl(linkid, WL_PHY_CONFIG, &phy_conf, sizeof (phy_conf))); } -static int -do_set_createibss(int fd, wldp_t *gbuf, boolean_t *create_ibss) +static dladm_status_t +do_set_createibss(datalink_id_t linkid, boolean_t *create_ibss) { wl_create_ibss_t cr = (wl_create_ibss_t)(*create_ibss); - return (do_set_ioctl(fd, gbuf, WL_CREATE_IBSS, &cr, sizeof (cr))); + return (i_dladm_wlan_set_ioctl(linkid, WL_CREATE_IBSS, + &cr, sizeof (cr))); } static void @@ -1984,55 +1374,21 @@ generate_essid(dladm_wlan_essid_t *essid) random()); } -static int -do_get_capability(int fd, wldp_t *gbuf) -{ - return (do_get_ioctl(fd, gbuf, WL_CAPABILITY)); -} - -static int -do_get_wpamode(int fd, wldp_t *gbuf) -{ - return (do_get_ioctl(fd, gbuf, WL_WPA)); -} - static dladm_status_t -ioctl_get(const char *link, int id, void *gbuf) +do_get_capability(datalink_id_t linkid, wldp_t *gbuf) { - int fd; - - if ((fd = open_link(link)) < 0) - return (DLADM_STATUS_LINKINVAL); - (void) do_get_ioctl(fd, gbuf, id); - - (void) close(fd); - return (dladm_wlan_wlresult2status(gbuf)); + return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_CAPABILITY)); } static dladm_status_t -ioctl_set(const char *link, int id, void *buf, uint_t buflen) +do_get_wpamode(datalink_id_t linkid, wldp_t *gbuf) { - int fd; - wldp_t *gbuf; - dladm_status_t status; - - if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) - return (DLADM_STATUS_NOMEM); - - if ((fd = open_link(link)) < 0) - return (DLADM_STATUS_LINKINVAL); - (void) do_set_ioctl(fd, gbuf, id, buf, buflen); - - (void) close(fd); - status = dladm_wlan_wlresult2status(gbuf); - free(gbuf); - - return (status); + return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_WPA)); } dladm_status_t -dladm_wlan_wpa_get_sr(const char *link, dladm_wlan_ess_t *sr, uint_t escnt, - uint_t *estot) +dladm_wlan_wpa_get_sr(datalink_id_t linkid, dladm_wlan_ess_t *sr, + uint_t escnt, uint_t *estot) { int i, n; wldp_t *gbuf; @@ -2042,7 +1398,7 @@ dladm_wlan_wpa_get_sr(const char *link, dladm_wlan_ess_t *sr, uint_t escnt, if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) return (DLADM_STATUS_NOMEM); - status = ioctl_get(link, WL_SCANRESULTS, gbuf); + status = i_dladm_wlan_get_ioctl(linkid, gbuf, WL_SCANRESULTS); if (status == DLADM_STATUS_OK) { es = (wl_wpa_ess_t *)(gbuf->wldp_buf); @@ -2066,8 +1422,7 @@ dladm_wlan_wpa_get_sr(const char *link, dladm_wlan_ess_t *sr, uint_t escnt, } dladm_status_t -dladm_wlan_wpa_set_ie(const char *link, uint8_t *wpa_ie, - uint_t wpa_ie_len) +dladm_wlan_wpa_set_ie(datalink_id_t linkid, uint8_t *wpa_ie, uint_t wpa_ie_len) { wl_wpa_ie_t *ie; uint_t len; @@ -2084,41 +1439,43 @@ dladm_wlan_wpa_set_ie(const char *link, uint8_t *wpa_ie, ie->wpa_ie_len = wpa_ie_len; (void) memcpy(ie->wpa_ie, wpa_ie, wpa_ie_len); - status = ioctl_set(link, WL_SETOPTIE, ie, len); + status = i_dladm_wlan_set_ioctl(linkid, WL_SETOPTIE, ie, len); free(ie); return (status); } dladm_status_t -dladm_wlan_wpa_set_wpa(const char *link, boolean_t flag) +dladm_wlan_wpa_set_wpa(datalink_id_t linkid, boolean_t flag) { - wl_wpa_t wpa; + wl_wpa_t wpa; wpa.wpa_flag = flag; - return (ioctl_set(link, WL_WPA, &wpa, sizeof (wl_wpa_t))); + return (i_dladm_wlan_set_ioctl(linkid, WL_WPA, &wpa, + sizeof (wl_wpa_t))); } dladm_status_t -dladm_wlan_wpa_del_key(const char *link, uint_t key_idx, +dladm_wlan_wpa_del_key(datalink_id_t linkid, uint_t key_idx, const dladm_wlan_bssid_t *addr) { - wl_del_key_t wk; + wl_del_key_t wk; wk.idk_keyix = key_idx; if (addr != NULL) (void) memcpy((char *)wk.idk_macaddr, addr->wb_bytes, DLADM_WLAN_BSSID_LEN); - return (ioctl_set(link, WL_DELKEY, &wk, sizeof (wl_del_key_t))); + return (i_dladm_wlan_set_ioctl(linkid, WL_DELKEY, &wk, + sizeof (wl_del_key_t))); } dladm_status_t -dladm_wlan_wpa_set_key(const char *link, dladm_wlan_cipher_t cipher, +dladm_wlan_wpa_set_key(datalink_id_t linkid, dladm_wlan_cipher_t cipher, const dladm_wlan_bssid_t *addr, boolean_t set_tx, uint64_t seq, uint_t key_idx, uint8_t *key, uint_t key_len) { - wl_key_t wk; + wl_key_t wk; (void) memset(&wk, 0, sizeof (wl_key_t)); switch (cipher) { @@ -2155,11 +1512,11 @@ dladm_wlan_wpa_set_key(const char *link, dladm_wlan_cipher_t cipher, (void) memcpy(&wk.ik_keyrsc, &seq, 6); /* only use 48-bit of seq */ (void) memcpy(wk.ik_keydata, key, key_len); - return (ioctl_set(link, WL_KEY, &wk, sizeof (wl_key_t))); + return (i_dladm_wlan_set_ioctl(linkid, WL_KEY, &wk, sizeof (wl_key_t))); } dladm_status_t -dladm_wlan_wpa_set_mlme(const char *link, dladm_wlan_mlme_op_t op, +dladm_wlan_wpa_set_mlme(datalink_id_t linkid, dladm_wlan_mlme_op_t op, dladm_wlan_reason_t reason, dladm_wlan_bssid_t *bssid) { wl_mlme_t mlme; @@ -2180,7 +1537,8 @@ dladm_wlan_wpa_set_mlme(const char *link, dladm_wlan_mlme_op_t op, (void) memcpy(mlme.im_macaddr, bssid->wb_bytes, DLADM_WLAN_BSSID_LEN); - return (ioctl_set(link, WL_MLME, &mlme, sizeof (wl_mlme_t))); + return (i_dladm_wlan_set_ioctl(linkid, WL_MLME, &mlme, + sizeof (wl_mlme_t))); } /* @@ -2204,7 +1562,7 @@ add_property_group_to_instance(scf_handle_t *handle, scf_instance_t *instance, return (pg); } -static int +static dladm_status_t add_new_property(scf_handle_t *handle, const char *prop_name, scf_type_t type, const char *val, scf_transaction_t *tx) { @@ -2228,7 +1586,7 @@ add_new_property(scf_handle_t *handle, const char *prop_name, if (scf_entry_add_value(entry, value) != 0) goto out; - return (DLADM_WLAN_SVC_SUCCESS); + return (DLADM_STATUS_OK); out: if (value != NULL) @@ -2236,18 +1594,15 @@ out: if (entry != NULL) scf_entry_destroy(entry); - return (DLADM_WLAN_SVC_FAILURE); + return (DLADM_STATUS_FAILED); } -/* - * DLADM_WLAN_SVC_APP_FAILURE means allocate buffer failed. - */ -static int +static dladm_status_t add_pg_method(scf_handle_t *handle, scf_instance_t *instance, const char *pg_name, const char *flags) { int rv, size; - int status = DLADM_WLAN_SVC_FAILURE; + dladm_status_t status = DLADM_STATUS_FAILED; char *command = NULL; scf_transaction_t *tran = NULL; scf_propertygroup_t *pg; @@ -2264,7 +1619,7 @@ add_pg_method(scf_handle_t *handle, scf_instance_t *instance, size = strlen(SVC_METHOD) + strlen(" ") + strlen(flags) + 1; command = malloc(size); if (command == NULL) { - status = DLADM_WLAN_SVC_APP_FAILURE; + status = DLADM_STATUS_NOMEM; goto out; } (void) snprintf(command, size, "%s %s", SVC_METHOD, flags); @@ -2274,15 +1629,14 @@ add_pg_method(scf_handle_t *handle, scf_instance_t *instance, goto out; if (add_new_property(handle, SCF_PROPERTY_EXEC, - SCF_TYPE_ASTRING, command, tran) != - DLADM_WLAN_SVC_SUCCESS) { + SCF_TYPE_ASTRING, command, tran) != DLADM_STATUS_OK) { goto out; } rv = scf_transaction_commit(tran); switch (rv) { case 1: - status = DLADM_WLAN_SVC_SUCCESS; + status = DLADM_STATUS_OK; goto out; case 0: scf_transaction_destroy_children(tran); @@ -2311,11 +1665,11 @@ out: return (status); } -static int +static dladm_status_t do_create_instance(scf_handle_t *handle, scf_service_t *svc, const char *instance_name, const char *command) { - int status = DLADM_WLAN_SVC_FAILURE; + dladm_status_t status = DLADM_STATUS_FAILED; char *buf; ssize_t max_fmri_len; scf_instance_t *instance; @@ -2327,12 +1681,12 @@ do_create_instance(scf_handle_t *handle, scf_service_t *svc, if (scf_service_add_instance(svc, instance_name, instance) != 0) { if (scf_error() == SCF_ERROR_EXISTS) /* Let the caller deal with the duplicate instance */ - status = DLADM_WLAN_SVC_INSTANCE_EXISTS; + status = DLADM_STATUS_EXIST; goto out; } if (add_pg_method(handle, instance, "start", - command) != DLADM_WLAN_SVC_SUCCESS) { + command) != DLADM_STATUS_OK) { goto out; } @@ -2346,7 +1700,7 @@ do_create_instance(scf_handle_t *handle, scf_service_t *svc, (smf_enable_instance(buf, SMF_TEMPORARY) != 0)) { goto out; } - status = DLADM_WLAN_SVC_SUCCESS; + status = DLADM_STATUS_OK; } out: @@ -2355,10 +1709,10 @@ out: return (status); } -static int +static dladm_status_t create_instance(const char *instance_name, const char *command) { - int status = DLADM_WLAN_SVC_FAILURE; + dladm_status_t status = DLADM_STATUS_FAILED; scf_service_t *svc = NULL; scf_handle_t *handle = NULL; @@ -2430,10 +1784,10 @@ wait_until_disabled(scf_handle_t *handle, char *fmri) } } -static int +static dladm_status_t delete_instance(const char *instance_name) { - int status = DLADM_WLAN_SVC_FAILURE; + dladm_status_t status = DLADM_STATUS_FAILED; char *buf; ssize_t max_fmri_len; scf_scope_t *scope = NULL; @@ -2468,7 +1822,7 @@ delete_instance(const char *instance_name) scf_error_t scf_errnum = scf_error(); if (scf_errnum == SCF_ERROR_NOT_FOUND) - status = DLADM_WLAN_SVC_SUCCESS; + status = DLADM_STATUS_OK; scf_instance_destroy(instance); goto out; @@ -2503,7 +1857,7 @@ delete_instance(const char *instance_name) scf_instance_destroy(instance); - status = DLADM_WLAN_SVC_SUCCESS; + status = DLADM_STATUS_OK; out: if (svc != NULL) @@ -2520,33 +1874,39 @@ out: return (status); } -/* - * DLADM_WLAN_SVC_APP_FAILURE means allocate buffer failed. - */ -static int -wpa_instance_create(const char *instance_name, void *key) +static dladm_status_t +wpa_instance_create(datalink_id_t linkid, void *key) { - int status = DLADM_WLAN_SVC_FAILURE; + dladm_status_t status = DLADM_STATUS_FAILED; char *command = NULL; char *wk_name = ((dladm_wlan_key_t *)key)->wk_name; int size; + char instance_name[MAXLINKNAMELEN]; + + /* + * Use the link name as the instance name of the network/wpad service. + */ + status = dladm_datalink_id2info(linkid, NULL, NULL, NULL, instance_name, + sizeof (instance_name)); + if (status != DLADM_STATUS_OK) + goto out; size = strlen(instance_name) + strlen(" -i -k ") + strlen(wk_name) + 1; command = malloc(size); if (command == NULL) { - status = DLADM_WLAN_SVC_APP_FAILURE; + status = DLADM_STATUS_NOMEM; goto out; } (void) snprintf(command, size, "-i %s -k %s", instance_name, wk_name); status = create_instance(instance_name, command); - if (status == DLADM_WLAN_SVC_INSTANCE_EXISTS) { + if (status == DLADM_STATUS_EXIST) { /* * Delete the existing instance and create a new instance * with the supplied arguments. */ if ((status = delete_instance(instance_name)) == - DLADM_WLAN_SVC_SUCCESS) { + DLADM_STATUS_OK) { status = create_instance(instance_name, command); } } @@ -2558,12 +1918,18 @@ out: return (status); } -static int -wpa_instance_delete(const char *instance_name) +static dladm_status_t +wpa_instance_delete(datalink_id_t linkid) { - int status; + char instance_name[MAXLINKNAMELEN]; - status = delete_instance(instance_name); + /* + * Get the instance name of the network/wpad service (the same as + * the link name). + */ + if (dladm_datalink_id2info(linkid, NULL, NULL, NULL, instance_name, + sizeof (instance_name)) != DLADM_STATUS_OK) + return (DLADM_STATUS_FAILED); - return (status); + return (delete_instance(instance_name)); } diff --git a/usr/src/lib/libdladm/common/libdlwlan.h b/usr/src/lib/libdladm/common/libdlwlan.h index b1729ae658..b784ad73ba 100644 --- a/usr/src/lib/libdladm/common/libdlwlan.h +++ b/usr/src/lib/libdladm/common/libdlwlan.h @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -125,20 +125,13 @@ typedef enum { } dladm_wlan_bsstype_t; typedef enum { - DLADM_WLAN_LINKSTATUS_DISCONNECTED = 1, - DLADM_WLAN_LINKSTATUS_CONNECTED + DLADM_WLAN_LINK_DISCONNECTED = 1, + DLADM_WLAN_LINK_CONNECTED } dladm_wlan_linkstatus_t; typedef uint32_t dladm_wlan_speed_t; typedef uint32_t dladm_wlan_channel_t; -typedef enum { - DLADM_WLAN_SVC_SUCCESS, - DLADM_WLAN_SVC_FAILURE, - DLADM_WLAN_SVC_APP_FAILURE, - DLADM_WLAN_SVC_INSTANCE_EXISTS -} dladm_wlan_svc_status_t; - enum { DLADM_WLAN_ATTR_ESSID = 0x00000001, DLADM_WLAN_ATTR_BSSID = 0x00000002, @@ -186,33 +179,24 @@ typedef struct dladm_wlan_key { uint_t wk_class; } dladm_wlan_key_t; -extern dladm_status_t dladm_wlan_scan(const char *, void *, +extern dladm_status_t dladm_wlan_scan(datalink_id_t, void *, boolean_t (*)(void *, dladm_wlan_attr_t *)); -extern dladm_status_t dladm_wlan_connect(const char *, dladm_wlan_attr_t *, +extern dladm_status_t dladm_wlan_connect(datalink_id_t, dladm_wlan_attr_t *, int, void *, uint_t, uint_t); -extern dladm_status_t dladm_wlan_disconnect(const char *); -extern dladm_status_t dladm_wlan_get_linkattr(const char *, +extern dladm_status_t dladm_wlan_disconnect(datalink_id_t); +extern dladm_status_t dladm_wlan_get_linkattr(datalink_id_t, dladm_wlan_linkattr_t *); -extern dladm_status_t dladm_wlan_walk(void *, - boolean_t (*)(void *, const char *)); -extern boolean_t dladm_wlan_is_valid(const char *); -extern dladm_status_t dladm_wlan_set_prop(const char *, const char *, - char **, uint_t, char **); -extern dladm_status_t dladm_wlan_walk_prop(const char *, void *, - boolean_t (*)(void *, const char *)); -extern dladm_status_t dladm_wlan_get_prop(const char *, dladm_prop_type_t, - const char *, char **, uint_t *); /* WPA support routines */ -extern dladm_status_t dladm_wlan_wpa_get_sr(const char *, - dladm_wlan_ess_t *, uint_t, uint_t *); -extern dladm_status_t dladm_wlan_wpa_set_ie(const char *, uint8_t *, uint_t); -extern dladm_status_t dladm_wlan_wpa_set_wpa(const char *, boolean_t); -extern dladm_status_t dladm_wlan_wpa_del_key(const char *, - uint_t, const dladm_wlan_bssid_t *); -extern dladm_status_t dladm_wlan_wpa_set_key(const char *, +extern dladm_status_t dladm_wlan_wpa_get_sr(datalink_id_t, dladm_wlan_ess_t *, + uint_t, uint_t *); +extern dladm_status_t dladm_wlan_wpa_set_ie(datalink_id_t, uint8_t *, uint_t); +extern dladm_status_t dladm_wlan_wpa_set_wpa(datalink_id_t, boolean_t); +extern dladm_status_t dladm_wlan_wpa_del_key(datalink_id_t, uint_t, + const dladm_wlan_bssid_t *); +extern dladm_status_t dladm_wlan_wpa_set_key(datalink_id_t, dladm_wlan_cipher_t, const dladm_wlan_bssid_t *, boolean_t, uint64_t, uint_t, uint8_t *, uint_t); -extern dladm_status_t dladm_wlan_wpa_set_mlme(const char *, +extern dladm_status_t dladm_wlan_wpa_set_mlme(datalink_id_t, dladm_wlan_mlme_op_t, dladm_wlan_reason_t, dladm_wlan_bssid_t *); diff --git a/usr/src/lib/libdladm/common/libdlwlan_impl.h b/usr/src/lib/libdladm/common/libdlwlan_impl.h index 764a951bed..9611b5319b 100644 --- a/usr/src/lib/libdladm/common/libdlwlan_impl.h +++ b/usr/src/lib/libdladm/common/libdlwlan_impl.h @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -57,10 +57,9 @@ extern "C" { #define DLADM_WLAN_OFDM2CHAN(mhz) (((mhz) - 5000) / 5) #define DLADM_WLAN_CONNECT_POLLRATE 200 /* milliseconds */ -#define DLADM_WLAN_CONNECT_DEFAULT_CHANNEL 1 #define DLADM_WLAN_MAX_RATES 4 -typedef struct dladm_wlan_rates { +typedef struct dladm_wlan_rates { uint8_t wr_rates[DLADM_WLAN_MAX_RATES]; int wr_cnt; } dladm_wlan_rates_t; @@ -70,12 +69,20 @@ typedef enum { DLADM_WLAN_RADIO_OFF } dladm_wlan_radio_t; -typedef enum { +typedef enum { DLADM_WLAN_PM_OFF = 1, DLADM_WLAN_PM_MAX, DLADM_WLAN_PM_FAST } dladm_wlan_powermode_t; +extern dladm_status_t i_dladm_wlan_get_ioctl(datalink_id_t, wldp_t *, + uint_t); +extern dladm_status_t i_dladm_wlan_set_ioctl(datalink_id_t, uint_t, + void *, uint_t); +extern dladm_status_t i_dladm_wlan_ioctl(datalink_id_t, wldp_t *, uint_t, + size_t, uint_t, size_t); +extern boolean_t i_dladm_wlan_convert_chan(wl_phy_conf_t *, uint32_t *); + #ifdef __cplusplus } #endif diff --git a/usr/src/lib/libdladm/common/linkprop.c b/usr/src/lib/libdladm/common/linkprop.c index e624cec0ec..a05f6ce877 100644 --- a/usr/src/lib/libdladm/common/linkprop.c +++ b/usr/src/lib/libdladm/common/linkprop.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -29,6 +29,7 @@ #include <strings.h> #include <errno.h> #include <ctype.h> +#include <stddef.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/dld.h> @@ -39,721 +40,533 @@ #include <zone.h> #include <libdllink.h> #include <libdladm_impl.h> +#include <libdlwlan_impl.h> #include <libdlwlan.h> +#include <libdlvlan.h> #include <dlfcn.h> #include <link.h> +#include <inet/wifi_ioctl.h> -static dladm_status_t i_dladm_set_prop_db(const char *, const char *, - char **, uint_t); -static dladm_status_t i_dladm_get_prop_db(const char *, const char *, - char **, uint_t *); -static dladm_status_t i_dladm_get_prop_temp(const char *, dladm_prop_type_t, - const char *, char **, uint_t *); -static dladm_status_t i_dladm_set_prop_temp(const char *, const char *, - char **, uint_t, uint_t, char **); -static boolean_t i_dladm_is_prop_temponly(const char *prop_name, - char **); +/* + * The linkprop get() callback. + * - 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); -typedef struct val_desc { - char *vd_name; - void *vd_val; -} val_desc_t; +/* + * 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. + */ +typedef dladm_status_t pd_setf_t(datalink_id_t, val_desc_t *propval, + uint_t cnt); -struct prop_desc; +#define PD_TEMPONLY 0x1 -typedef dladm_status_t pd_getf_t(const char *, char **, uint_t *); -typedef dladm_status_t pd_setf_t(const char *, val_desc_t *, uint_t); -typedef dladm_status_t pd_checkf_t(struct prop_desc *, char **, - uint_t, val_desc_t **); +/* + * 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. + */ +typedef dladm_status_t pd_checkf_t(datalink_id_t, char **propstrp, + uint_t cnt, val_desc_t *propval, boolean_t *dofree); -static pd_getf_t do_get_zone; -static pd_setf_t do_set_zone; -static pd_checkf_t do_check_zone; +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; +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; typedef struct prop_desc { - char *pd_name; - val_desc_t pd_defval; - val_desc_t *pd_modval; - uint_t pd_nmodval; - boolean_t pd_temponly; - pd_setf_t *pd_set; - pd_getf_t *pd_getmod; - pd_getf_t *pd_get; - pd_checkf_t *pd_check; + /* + * link property name + */ + char *pd_name; + + /* + * default property value, can be set to { "", NULL } + */ + val_desc_t pd_defval; + + /* + * list of optional property values, can be NULL. + * + * This is set to non-NULL if there is a list of possible property + * values. pd_optval would point to the array of possible values. + */ + val_desc_t *pd_optval; + + /* + * count of the above optional property values. 0 if pd_optval is NULL. + */ + uint_t pd_noptval; + + /* + * callback to set link property; + * set to NULL if this property is read-only + */ + pd_setf_t *pd_set; + + /* + * callback to get modifiable link property + */ + pd_getf_t *pd_getmod; + + /* + * callback to get current link property + */ + pd_getf_t *pd_get; + + /* + * callback to validate link property value, set to NULL if pd_optval + * is not NULL. In that case, validate the value by comparing it with + * the pd_optval. Return a val_desc_t array pointer if the value is + * valid. + */ + pd_checkf_t *pd_check; + + /* + * currently only PD_TEMPONLY is valid, which indicates the property + * is temporary only. + */ + uint_t pd_flags; + + /* + * indicate link classes this property applies to. + */ + datalink_class_t pd_class; + + /* + * indicate link media type this property applies to. + */ + datalink_media_t pd_dmedia; } prop_desc_t; +static val_desc_t dladm_wlan_radio_vals[] = { + { "on", DLADM_WLAN_RADIO_ON }, + { "off", DLADM_WLAN_RADIO_OFF } +}; + +static val_desc_t dladm_wlan_powermode_vals[] = { + { "off", DLADM_WLAN_PM_OFF }, + { "fast", DLADM_WLAN_PM_FAST }, + { "max", DLADM_WLAN_PM_MAX } +}; + static prop_desc_t prop_table[] = { - { "zone", { "", NULL }, NULL, 0, B_TRUE, + + { "channel", { NULL, 0 }, NULL, 0, NULL, NULL, + do_get_channel_prop, NULL, 0, + 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}, + + { "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}, + + { "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}, + + { "autopush", { "", NULL }, NULL, 0, + do_set_autopush, NULL, + do_get_autopush, do_check_autopush, 0, + DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE}, + + { "zone", { "", NULL }, NULL, 0, do_set_zone, NULL, - do_get_zone, do_check_zone} + do_get_zone, do_check_zone, PD_TEMPONLY, + DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE} }; -#define MAX_PROPS (sizeof (prop_table) / sizeof (prop_desc_t)) +#define DLADM_MAX_PROPS (sizeof (prop_table) / sizeof (prop_desc_t)) -dladm_status_t -dladm_set_prop(const char *link, const char *prop_name, char **prop_val, - uint_t val_cnt, uint_t flags, char **errprop) -{ - dladm_status_t status = DLADM_STATUS_BADARG; +static dladm_status_t i_dladm_set_linkprop_db(datalink_id_t, const char *, + char **, uint_t); +static dladm_status_t i_dladm_get_linkprop_db(datalink_id_t, const char *, + char **, uint_t *); +static dladm_status_t i_dladm_set_single_prop(datalink_id_t, datalink_class_t, + uint32_t, prop_desc_t *, char **, uint_t, uint_t); +static dladm_status_t i_dladm_set_linkprop(datalink_id_t, const char *, + char **, uint_t, uint_t); - if (link == NULL || (prop_val == NULL && val_cnt > 0) || - (prop_val != NULL && val_cnt == 0) || flags == 0) - return (DLADM_STATUS_BADARG); +/* + * Unfortunately, MAX_SCAN_SUPPORT_RATES is too small to allow all + * rates to be retrieved. However, we cannot increase it at this + * time because it will break binary compatibility with unbundled + * WiFi drivers and utilities. So for now we define an additional + * constant, MAX_SUPPORT_RATES, to allow all rates to be retrieved. + */ +#define MAX_SUPPORT_RATES 64 - if ((flags & DLADM_OPT_TEMP) != 0) { - status = i_dladm_set_prop_temp(link, prop_name, prop_val, - val_cnt, flags, errprop); - if (status == DLADM_STATUS_TEMPONLY && - (flags & DLADM_OPT_PERSIST) != 0) - return (DLADM_STATUS_TEMPONLY); +#define AP_ANCHOR "[anchor]" +#define AP_DELIMITER '.' - if (status == DLADM_STATUS_NOTFOUND) { - status = DLADM_STATUS_BADARG; - if (dladm_wlan_is_valid(link)) { - status = dladm_wlan_set_prop(link, prop_name, - prop_val, val_cnt, errprop); +static dladm_status_t +do_check_prop(prop_desc_t *pdp, char **prop_val, uint_t val_cnt, + val_desc_t *vdp) +{ + int i, j; + dladm_status_t status = DLADM_STATUS_OK; + + for (j = 0; j < val_cnt; j++) { + for (i = 0; i < pdp->pd_noptval; i++) { + if (strcasecmp(*prop_val, + pdp->pd_optval[i].vd_name) == 0) { + break; } } - if (status != DLADM_STATUS_OK) - return (status); + if (i == pdp->pd_noptval) { + status = DLADM_STATUS_BADVAL; + goto done; + } + (void) memcpy(vdp + j, &pdp->pd_optval[i], sizeof (val_desc_t)); } - if ((flags & DLADM_OPT_PERSIST) != 0) { - if (i_dladm_is_prop_temponly(prop_name, errprop)) - return (DLADM_STATUS_TEMPONLY); - status = i_dladm_set_prop_db(link, prop_name, - prop_val, val_cnt); - } +done: return (status); } -dladm_status_t -dladm_walk_prop(const char *link, void *arg, - boolean_t (*func)(void *, const char *)) +static dladm_status_t +i_dladm_set_single_prop(datalink_id_t linkid, datalink_class_t class, + uint32_t media, prop_desc_t *pdp, char **prop_val, uint_t val_cnt, + uint_t flags) { - int i; + dladm_status_t status = DLADM_STATUS_OK; + val_desc_t *vdp = NULL; + boolean_t needfree = B_FALSE; + uint_t cnt, i; - if (link == NULL || func == NULL) + if (!(pdp->pd_class & class)) return (DLADM_STATUS_BADARG); - /* For wifi links, show wifi properties first */ - if (dladm_wlan_is_valid(link)) { - dladm_status_t status; - - status = dladm_wlan_walk_prop(link, arg, func); - if (status != DLADM_STATUS_OK) - return (status); - } - - /* Then show data-link properties if there are any */ - for (i = 0; i < MAX_PROPS; i++) { - if (!func(arg, prop_table[i].pd_name)) - break; - } - return (DLADM_STATUS_OK); -} - -dladm_status_t -dladm_get_prop(const char *link, dladm_prop_type_t type, - const char *prop_name, char **prop_val, uint_t *val_cntp) -{ - dladm_status_t status; - - if (link == NULL || prop_name == NULL || prop_val == NULL || - val_cntp == NULL || *val_cntp == 0) + if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media)) return (DLADM_STATUS_BADARG); - if (type == DLADM_PROP_VAL_PERSISTENT) { - if (i_dladm_is_prop_temponly(prop_name, NULL)) - return (DLADM_STATUS_TEMPONLY); - return (i_dladm_get_prop_db(link, prop_name, - prop_val, val_cntp)); - } + if ((flags & DLADM_OPT_PERSIST) && (pdp->pd_flags & PD_TEMPONLY)) + return (DLADM_STATUS_TEMPONLY); - status = i_dladm_get_prop_temp(link, type, prop_name, - prop_val, val_cntp); - if (status != DLADM_STATUS_NOTFOUND) - return (status); + if (!(flags & DLADM_OPT_ACTIVE)) + return (DLADM_STATUS_OK); - if (dladm_wlan_is_valid(link)) { - return (dladm_wlan_get_prop(link, type, prop_name, - prop_val, val_cntp)); - } - return (DLADM_STATUS_BADARG); -} + if (pdp->pd_set == NULL) + return (DLADM_STATUS_PROPRDONLY); -/* - * Data structures used for implementing persistent link properties - */ -typedef struct linkprop_val { - const char *lv_name; - struct linkprop_val *lv_nextval; -} linkprop_val_t; - -typedef struct linkprop_info { - const char *li_name; - struct linkprop_info *li_nextprop; - struct linkprop_val *li_val; -} linkprop_info_t; - -typedef struct linkprop_db_state linkprop_db_state_t; - -typedef boolean_t (*linkprop_db_op_t)(linkprop_db_state_t *, - char *, linkprop_info_t *, dladm_status_t *); - -struct linkprop_db_state { - linkprop_db_op_t ls_op; - const char *ls_link; - const char *ls_propname; - char **ls_propval; - uint_t *ls_valcntp; -}; + if (prop_val != NULL) { + vdp = malloc(sizeof (val_desc_t) * val_cnt); + if (vdp == NULL) + return (DLADM_STATUS_NOMEM); -static void -free_linkprops(linkprop_info_t *lip) -{ - linkprop_info_t *lip_next; - linkprop_val_t *lvp, *lvp_next; - - for (; lip != NULL; lip = lip_next) { - lip_next = lip->li_nextprop; - for (lvp = lip->li_val; lvp != NULL; lvp = lvp_next) { - lvp_next = lvp->lv_nextval; - free(lvp); + if (pdp->pd_check != NULL) { + status = pdp->pd_check(linkid, prop_val, val_cnt, vdp, + &needfree); + } else if (pdp->pd_optval != NULL) { + status = do_check_prop(pdp, prop_val, val_cnt, vdp); + } else { + status = DLADM_STATUS_BADARG; } - free(lip); - } -} -/* - * Generate an entry in the link property database. - * Each entry has this format: - * <linkname> <prop0>=<val0>,...,<valn>;...;<propn>=<val0>,...,<valn>; - */ -static void -generate_linkprop_line(linkprop_db_state_t *lsp, char *buf, - linkprop_info_t *listp, dladm_status_t *statusp) -{ - char tmpbuf[MAXLINELEN]; - char *ptr, *lim = tmpbuf + MAXLINELEN; - linkprop_info_t *lip = listp; - linkprop_val_t *lvp = NULL; + if (status != DLADM_STATUS_OK) + goto done; - /* - * Delete line if there are no properties left. - */ - if (lip == NULL || - (lip->li_val == NULL && lip->li_nextprop == NULL)) { - buf[0] = '\0'; - return; - } - ptr = tmpbuf; - ptr += snprintf(ptr, BUFLEN(lim, ptr), "%s\t", lsp->ls_link); - for (; lip != NULL; lip = lip->li_nextprop) { - /* - * Skip properties without values. - */ - if (lip->li_val == NULL) - continue; + cnt = val_cnt; + } else { + if (pdp->pd_defval.vd_name == NULL) + return (DLADM_STATUS_NOTSUP); - ptr += snprintf(ptr, BUFLEN(lim, ptr), "%s=", lip->li_name); - for (lvp = lip->li_val; lvp != NULL; lvp = lvp->lv_nextval) { - ptr += snprintf(ptr, BUFLEN(lim, ptr), "%s%c", - lvp->lv_name, - ((lvp->lv_nextval == NULL) ? ';' : ',')); - } + if ((vdp = malloc(sizeof (val_desc_t))) == NULL) + return (DLADM_STATUS_NOMEM); + + (void) memcpy(vdp, &pdp->pd_defval, sizeof (val_desc_t)); + cnt = 1; } - if (ptr > lim) { - *statusp = DLADM_STATUS_TOOSMALL; - return; + status = pdp->pd_set(linkid, vdp, cnt); + if (needfree) { + for (i = 0; i < cnt; i++) + free((void *)(((val_desc_t *)vdp + i)->vd_val)); } - (void) snprintf(buf, MAXLINELEN, "%s\n", tmpbuf); +done: + free(vdp); + return (status); } -/* - * This function is used to update or create an entry in the persistent db. - * process_linkprop_db() will first scan the db for an entry matching the - * specified link. If a match is found, this function is invoked with the - * entry's contents (buf) and its linked-list representation (listp). lsp - * holds the name and values of the property to be added or updated; this - * information will be merged with listp. Subsequently, an updated entry - * will be written to buf, which will in turn be written to disk by - * process_linkprop_db(). If no entry matches the specified link, listp - * will be NULL; a new entry will be generated in this case and it will - * contain only the property information in lsp. - */ -static boolean_t -process_linkprop_set(linkprop_db_state_t *lsp, char *buf, - linkprop_info_t *listp, dladm_status_t *statusp) +static dladm_status_t +i_dladm_set_linkprop(datalink_id_t linkid, const char *prop_name, + char **prop_val, uint_t val_cnt, uint_t flags) { - dladm_status_t status; - linkprop_info_t *lastp = NULL, *lip = listp, *nlip = NULL; - linkprop_val_t **lvpp; - int i; - - if (lsp->ls_propname == NULL) { - buf[0] = '\0'; - return (B_FALSE); - } + int i; + boolean_t found = B_FALSE; + datalink_class_t class; + uint32_t media; + dladm_status_t status = DLADM_STATUS_OK; - /* - * Find the linkprop we want to change. - */ - for (; lip != NULL; lip = lip->li_nextprop) { - if (strcmp(lip->li_name, lsp->ls_propname) == 0) - break; + status = dladm_datalink_id2info(linkid, NULL, &class, &media, NULL, 0); + if (status != DLADM_STATUS_OK) + return (status); - lastp = lip; - } + for (i = 0; i < DLADM_MAX_PROPS; i++) { + prop_desc_t *pdp = &prop_table[i]; + dladm_status_t s; - if (lip == NULL) { - /* - * If the linkprop is not found, append it to the list. - */ - if ((nlip = malloc(sizeof (linkprop_info_t))) == NULL) { - status = DLADM_STATUS_NOMEM; - goto fail; - } - /* - * nlip will need to be freed later if there is no list to - * append to. - */ - if (lastp != NULL) - lastp->li_nextprop = nlip; - nlip->li_name = lsp->ls_propname; - nlip->li_nextprop = NULL; - nlip->li_val = NULL; - lvpp = &nlip->li_val; - } else { - linkprop_val_t *lvp, *lvp_next; + if (prop_name != NULL && + (strcasecmp(prop_name, pdp->pd_name) != 0)) + continue; - /* - * If the linkprop is found, delete the existing values from it. - */ - for (lvp = lip->li_val; lvp != NULL; lvp = lvp_next) { - lvp_next = lvp->lv_nextval; - free(lvp); - } - lip->li_val = NULL; - lvpp = &lip->li_val; - } + found = B_TRUE; + s = i_dladm_set_single_prop(linkid, class, media, pdp, prop_val, + val_cnt, flags); - /* - * Fill our linkprop with the specified values. - */ - for (i = 0; i < *lsp->ls_valcntp; i++) { - if ((*lvpp = malloc(sizeof (linkprop_val_t))) == NULL) { - status = DLADM_STATUS_NOMEM; - goto fail; + if (prop_name != NULL) { + status = s; + break; + } else { + if (s != DLADM_STATUS_OK && + s != DLADM_STATUS_NOTSUP) + status = s; } - (*lvpp)->lv_name = lsp->ls_propval[i]; - (*lvpp)->lv_nextval = NULL; - lvpp = &(*lvpp)->lv_nextval; } + if (!found) + status = DLADM_STATUS_NOTFOUND; - if (listp != NULL) { - generate_linkprop_line(lsp, buf, listp, statusp); - } else { - generate_linkprop_line(lsp, buf, nlip, statusp); - free_linkprops(nlip); - } - return (B_FALSE); - -fail: - *statusp = status; - if (listp == NULL) - free_linkprops(nlip); - - return (B_FALSE); + return (status); } /* - * This function is used for retrieving the values for a specific property. - * It gets called if an entry matching the specified link exists in the db. - * The entry is converted into a linked-list listp. This list is then scanned - * for the specified property name; if a matching property exists, its - * associated values are copied to the array lsp->ls_propval. + * Set/reset link property for specific link */ -/* ARGSUSED */ -static boolean_t -process_linkprop_get(linkprop_db_state_t *lsp, char *buf, - linkprop_info_t *listp, dladm_status_t *statusp) +dladm_status_t +dladm_set_linkprop(datalink_id_t linkid, const char *prop_name, char **prop_val, + uint_t val_cnt, uint_t flags) { - linkprop_info_t *lip = listp; - linkprop_val_t *lvp; - uint_t valcnt = 0; + dladm_status_t status = DLADM_STATUS_OK; - /* - * Find the linkprop we want to get. - */ - for (; lip != NULL; lip = lip->li_nextprop) { - if (strcmp(lip->li_name, lsp->ls_propname) == 0) - break; - } - if (lip == NULL) { - *statusp = DLADM_STATUS_NOTFOUND; - return (B_FALSE); + if ((linkid == DATALINK_INVALID_LINKID) || (flags == 0) || + (prop_val == NULL && val_cnt > 0) || + (prop_val != NULL && val_cnt == 0) || + (prop_name == NULL && prop_val != NULL)) { + return (DLADM_STATUS_BADARG); } - for (lvp = lip->li_val; lvp != NULL; lvp = lvp->lv_nextval) { - (void) strncpy(lsp->ls_propval[valcnt], lvp->lv_name, - DLADM_PROP_VAL_MAX); + status = i_dladm_set_linkprop(linkid, prop_name, prop_val, + val_cnt, flags); + if (status != DLADM_STATUS_OK) + return (status); - if (++valcnt >= *lsp->ls_valcntp && lvp->lv_nextval != NULL) { - *statusp = DLADM_STATUS_TOOSMALL; - return (B_FALSE); - } + if (flags & DLADM_OPT_PERSIST) { + status = i_dladm_set_linkprop_db(linkid, prop_name, + prop_val, val_cnt); } - /* - * This function is meant to be called at most once for each call - * to process_linkprop_db(). For this reason, it's ok to overwrite - * the caller's valcnt array size with the actual number of values - * returned. - */ - *lsp->ls_valcntp = valcnt; - return (B_FALSE); + return (status); } /* - * This is used for initializing link properties. - * Unlike the other routines, this gets called for every entry in the - * database. lsp->ls_link is not user-specified but instead is set to - * the current link being processed. + * Walk link properties of the given specific link. */ -/* ARGSUSED */ -static boolean_t -process_linkprop_init(linkprop_db_state_t *lsp, char *buf, - linkprop_info_t *listp, dladm_status_t *statusp) +dladm_status_t +dladm_walk_linkprop(datalink_id_t linkid, void *arg, + int (*func)(datalink_id_t, const char *, void *)) { - dladm_status_t status = DLADM_STATUS_OK; - linkprop_info_t *lip = listp; - linkprop_val_t *lvp; - uint_t valcnt, i; - char **propval; - - for (; lip != NULL; lip = lip->li_nextprop) { - /* - * Construct the propval array and fill it with - * values from listp. - */ - for (lvp = lip->li_val, valcnt = 0; - lvp != NULL; lvp = lvp->lv_nextval, valcnt++) - ; + dladm_status_t status; + datalink_class_t class; + uint_t media; + int i; - propval = malloc(sizeof (char *) * valcnt); - if (propval == NULL) { - *statusp = DLADM_STATUS_NOMEM; - break; - } - lvp = lip->li_val; - for (i = 0; i < valcnt; i++, lvp = lvp->lv_nextval) - propval[i] = (char *)lvp->lv_name; - - status = dladm_set_prop(lsp->ls_link, lip->li_name, - propval, valcnt, DLADM_OPT_TEMP, NULL); - - /* - * We continue with initializing other properties even - * after encountering an error. This error will be - * propagated to the caller via 'statusp'. - */ - if (status != DLADM_STATUS_OK) - *statusp = status; - - free(propval); - } - return (B_TRUE); -} + if (linkid == DATALINK_INVALID_LINKID || func == NULL) + return (DLADM_STATUS_BADARG); -static int -parse_linkprops(char *buf, linkprop_info_t **lipp) -{ - int i, len; - char *curr; - linkprop_info_t *lip = NULL; - linkprop_info_t **tailp = lipp; - linkprop_val_t *lvp = NULL; - linkprop_val_t **vtailp = NULL; - - curr = buf; - len = strlen(buf); - for (i = 0; i < len; i++) { - char c = buf[i]; - boolean_t match = (c == '=' || c == ',' || c == ';'); + status = dladm_datalink_id2info(linkid, NULL, &class, &media, NULL, 0); + if (status != DLADM_STATUS_OK) + return (status); - /* - * Move to the next character if there is no match and - * if we have not reached the last character. - */ - if (!match && i != len - 1) + for (i = 0; i < DLADM_MAX_PROPS; i++) { + if (!(prop_table[i].pd_class & class)) continue; - if (match) { - /* - * Nul-terminate the string pointed to by 'curr'. - */ - buf[i] = '\0'; - if (*curr == '\0') - goto fail; - } + if (!DATALINK_MEDIA_ACCEPTED(prop_table[i].pd_dmedia, media)) + continue; - if (lip != NULL) { - /* - * We get here after we have processed the "<prop>=" - * pattern. The pattern we are now interested in is - * "<val0>,<val1>,...,<valn>;". For each value we - * find, a linkprop_val_t will be allocated and - * added to the current 'lip'. - */ - if (c == '=') - goto fail; - - lvp = malloc(sizeof (*lvp)); - if (lvp == NULL) - goto fail; - - lvp->lv_name = curr; - lvp->lv_nextval = NULL; - *vtailp = lvp; - vtailp = &lvp->lv_nextval; - - if (c == ';') { - tailp = &lip->li_nextprop; - vtailp = NULL; - lip = NULL; - } - } else { - /* - * lip == NULL indicates that 'curr' must be refering - * to a property name. We allocate a new linkprop_info_t - * append it to the list given by the caller. - */ - if (c != '=') - goto fail; - - lip = malloc(sizeof (*lip)); - if (lip == NULL) - goto fail; - - lip->li_name = curr; - lip->li_val = NULL; - lip->li_nextprop = NULL; - *tailp = lip; - vtailp = &lip->li_val; + if (func(linkid, prop_table[i].pd_name, arg) == + DLADM_WALK_TERMINATE) { + break; } - curr = buf + i + 1; } - /* - * The list must be non-empty and the last character must be ';'. - */ - if (*lipp == NULL || lip != NULL) - goto fail; - - return (0); -fail: - free_linkprops(*lipp); - *lipp = NULL; - return (-1); + return (DLADM_STATUS_OK); } -static boolean_t -process_linkprop_line(linkprop_db_state_t *lsp, char *buf, - dladm_status_t *statusp) +/* + * Get linkprop of the given specific link. + */ +dladm_status_t +dladm_get_linkprop(datalink_id_t linkid, dladm_prop_type_t type, + const char *prop_name, char **prop_val, uint_t *val_cntp) { - linkprop_info_t *lip = NULL; - int i, len, llen; - char *str, *lasts; - boolean_t cont, nolink = B_FALSE; + dladm_status_t status = DLADM_STATUS_OK; + datalink_class_t class; + uint_t media; + prop_desc_t *pdp; + uint_t cnt; + int i; + + if (linkid == DATALINK_INVALID_LINKID || prop_name == NULL || + prop_val == NULL || val_cntp == NULL || *val_cntp == 0) + return (DLADM_STATUS_BADARG); - /* - * Skip leading spaces, blank lines, and comments. - */ - len = strlen(buf); - for (i = 0; i < len; i++) { - if (!isspace(buf[i])) + for (i = 0; i < DLADM_MAX_PROPS; i++) + if (strcasecmp(prop_name, prop_table[i].pd_name) == 0) break; - } - if (i == len || buf[i] == '#') - return (B_TRUE); - str = buf + i; - if (lsp->ls_link != NULL) { - /* - * Skip links we're not interested in. - * Note that strncmp() and isspace() are used here - * instead of strtok() and strcmp() because we don't - * want to modify buf in case it does not contain the - * specified link. - */ - llen = strlen(lsp->ls_link); - if (strncmp(str, lsp->ls_link, llen) != 0 || - !isspace(str[llen])) - return (B_TRUE); - } else { - /* - * If a link is not specified, find the link name - * and assign it to lsp->ls_link. - */ - if (strtok_r(str, " \n\t", &lasts) == NULL) - goto fail; - - llen = strlen(str); - lsp->ls_link = str; - nolink = B_TRUE; - } - str += llen + 1; - if (str >= buf + len) - goto fail; - - /* - * Now find the list of link properties. - */ - if ((str = strtok_r(str, " \n\t", &lasts)) == NULL) - goto fail; + if (i == DLADM_MAX_PROPS) + return (DLADM_STATUS_NOTFOUND); - if (parse_linkprops(str, &lip) < 0) - goto fail; + pdp = &prop_table[i]; - cont = (*lsp->ls_op)(lsp, buf, lip, statusp); - free_linkprops(lip); - if (nolink) - lsp->ls_link = NULL; - return (cont); + status = dladm_datalink_id2info(linkid, NULL, &class, &media, NULL, 0); + if (status != DLADM_STATUS_OK) + return (status); -fail: - free_linkprops(lip); - if (nolink) - lsp->ls_link = NULL; + if (!(pdp->pd_class & class)) + return (DLADM_STATUS_BADARG); - /* - * Delete corrupted line. - */ - buf[0] = '\0'; - return (B_TRUE); -} + if (!DATALINK_MEDIA_ACCEPTED(pdp->pd_dmedia, media)) + return (DLADM_STATUS_BADARG); -static dladm_status_t -process_linkprop_db(void *arg, FILE *fp, FILE *nfp) -{ - linkprop_db_state_t *lsp = arg; - dladm_status_t status = DLADM_STATUS_OK; - char buf[MAXLINELEN]; - boolean_t cont = B_TRUE; + switch (type) { + case DLADM_PROP_VAL_CURRENT: + status = pdp->pd_get(linkid, prop_val, val_cntp); + break; - /* - * This loop processes each line of the configuration file. - * buf can potentially be modified by process_linkprop_line(). - * If this is a write operation and buf is not truncated, buf will - * be written to disk. process_linkprop_line() will no longer be - * called after it returns B_FALSE; at which point the remainder - * of the file will continue to be read and, if necessary, written - * to disk as well. - */ - while (fgets(buf, MAXLINELEN, fp) != NULL) { - if (cont) - cont = process_linkprop_line(lsp, buf, &status); + case DLADM_PROP_VAL_DEFAULT: + if (pdp->pd_defval.vd_name == NULL) { + status = DLADM_STATUS_NOTSUP; + break; + } + (void) strcpy(*prop_val, pdp->pd_defval.vd_name); + *val_cntp = 1; + break; - if (nfp != NULL && buf[0] != '\0' && fputs(buf, nfp) == EOF) { - status = dladm_errno2status(errno); + case DLADM_PROP_VAL_MODIFIABLE: + if (pdp->pd_getmod != NULL) { + status = pdp->pd_getmod(linkid, prop_val, val_cntp); break; } + cnt = pdp->pd_noptval; + if (cnt == 0) { + status = DLADM_STATUS_NOTSUP; + } else if (cnt > *val_cntp) { + status = DLADM_STATUS_TOOSMALL; + } else { + for (i = 0; i < cnt; i++) { + (void) strcpy(prop_val[i], + pdp->pd_optval[i].vd_name); + } + *val_cntp = cnt; + } + break; + case DLADM_PROP_VAL_PERSISTENT: + if (pdp->pd_flags & PD_TEMPONLY) + return (DLADM_STATUS_TEMPONLY); + status = i_dladm_get_linkprop_db(linkid, prop_name, + prop_val, val_cntp); + break; + default: + status = DLADM_STATUS_BADARG; + break; } - if (status != DLADM_STATUS_OK || !cont) - return (status); + return (status); +} - if (lsp->ls_op == process_linkprop_set) { - /* - * If the specified link is not found above, we add the - * link and its properties to the configuration file. - */ - (void) (*lsp->ls_op)(lsp, buf, NULL, &status); - if (status == DLADM_STATUS_OK && fputs(buf, nfp) == EOF) - status = dladm_errno2status(errno); - } +/*ARGSUSED*/ +static int +i_dladm_init_one_prop(datalink_id_t linkid, const char *prop_name, void *arg) +{ + char *buf, **propvals; + uint_t i, valcnt = DLADM_MAX_PROP_VALCNT; - if (lsp->ls_op == process_linkprop_get) - status = DLADM_STATUS_NOTFOUND; + if ((buf = malloc((sizeof (char *) + DLADM_PROP_VAL_MAX) * + DLADM_MAX_PROP_VALCNT)) == NULL) { + return (DLADM_WALK_CONTINUE); + } - return (status); -} + propvals = (char **)(void *)buf; + for (i = 0; i < valcnt; i++) { + propvals[i] = buf + + sizeof (char *) * DLADM_MAX_PROP_VALCNT + + i * DLADM_PROP_VAL_MAX; + } -#define LINKPROP_RW_DB(statep, writeop) \ - (i_dladm_rw_db("/etc/dladm/linkprop.conf", \ - S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH, process_linkprop_db, \ - (statep), (writeop))) + if (dladm_get_linkprop(linkid, DLADM_PROP_VAL_PERSISTENT, prop_name, + propvals, &valcnt) != DLADM_STATUS_OK) { + goto done; + } -static dladm_status_t -i_dladm_set_prop_db(const char *link, const char *prop_name, - char **prop_val, uint_t val_cnt) -{ - linkprop_db_state_t state; + (void) dladm_set_linkprop(linkid, prop_name, propvals, valcnt, + DLADM_OPT_ACTIVE); - state.ls_op = process_linkprop_set; - state.ls_link = link; - state.ls_propname = prop_name; - state.ls_propval = prop_val; - state.ls_valcntp = &val_cnt; +done: + if (buf != NULL) + free(buf); - return (LINKPROP_RW_DB(&state, B_TRUE)); + return (DLADM_WALK_CONTINUE); } -static dladm_status_t -i_dladm_get_prop_db(const char *link, const char *prop_name, - char **prop_val, uint_t *val_cntp) +/*ARGSUSED*/ +static int +i_dladm_init_linkprop(datalink_id_t linkid, void *arg) { - linkprop_db_state_t state; - - state.ls_op = process_linkprop_get; - state.ls_link = link; - state.ls_propname = prop_name; - state.ls_propval = prop_val; - state.ls_valcntp = val_cntp; - - return (LINKPROP_RW_DB(&state, B_FALSE)); + (void) dladm_init_linkprop(linkid); + return (DLADM_WALK_CONTINUE); } dladm_status_t -dladm_init_linkprop(void) +dladm_init_linkprop(datalink_id_t linkid) { - linkprop_db_state_t state; - - state.ls_op = process_linkprop_init; - state.ls_link = NULL; - state.ls_propname = NULL; - state.ls_propval = NULL; - state.ls_valcntp = NULL; - - return (LINKPROP_RW_DB(&state, B_FALSE)); + if (linkid == DATALINK_ALL_LINKID) { + (void) dladm_walk_datalink_id(i_dladm_init_linkprop, NULL, + DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, + DLADM_OPT_PERSIST); + } else { + (void) dladm_walk_linkprop(linkid, NULL, i_dladm_init_one_prop); + } + return (DLADM_STATUS_OK); } static dladm_status_t -i_dladm_get_zoneid(const char *link, zoneid_t *zidp) +do_get_zone(datalink_id_t linkid, char **prop_val, uint_t *val_cnt) { - int fd; - dld_hold_vlan_t dhv; + char zone_name[ZONENAME_MAX]; + zoneid_t zid; + dladm_status_t status; - if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) - return (dladm_errno2status(errno)); + status = dladm_getzid(linkid, &zid); + if (status != DLADM_STATUS_OK) + return (status); - bzero(&dhv, sizeof (dld_hold_vlan_t)); - (void) strlcpy(dhv.dhv_name, link, IFNAMSIZ); - dhv.dhv_zid = -1; + *val_cnt = 1; + if (zid != GLOBAL_ZONEID) { + if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0) + return (dladm_errno2status(errno)); - if (i_dladm_ioctl(fd, DLDIOCZIDGET, &dhv, sizeof (dhv)) < 0) { - if (errno == ENOENT) { - *zidp = GLOBAL_ZONEID; - } else { - dladm_status_t status = dladm_errno2status(errno); - (void) close(fd); - return (status); - } + (void) strncpy(*prop_val, zone_name, DLADM_PROP_VAL_MAX); } else { - *zidp = dhv.dhv_zid; + *prop_val[0] = '\0'; } - (void) close(fd); return (DLADM_STATUS_OK); } @@ -785,12 +598,14 @@ i_dladm_get_zone_dev(char *zone_name, char *dev, size_t devlen) } static dladm_status_t -i_dladm_add_deventry(zoneid_t zid, const char *link) +i_dladm_update_deventry(zoneid_t zid, datalink_id_t linkid, boolean_t add) { char path[MAXPATHLEN]; + char name[MAXLINKNAMELEN]; di_prof_t prof = NULL; char zone_name[ZONENAME_MAX]; dladm_status_t status; + int ret; if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0) return (dladm_errno2status(errno)); @@ -799,40 +614,20 @@ i_dladm_add_deventry(zoneid_t zid, const char *link) if (di_prof_init(path, &prof) != 0) return (dladm_errno2status(errno)); - status = DLADM_STATUS_OK; - if (di_prof_add_dev(prof, link) != 0) { - status = dladm_errno2status(errno); + status = dladm_linkid2legacyname(linkid, name, MAXLINKNAMELEN); + if (status != DLADM_STATUS_OK) goto cleanup; - } - if (di_prof_commit(prof) != 0) - status = dladm_errno2status(errno); -cleanup: - if (prof) - di_prof_fini(prof); - - return (status); -} - -static dladm_status_t -i_dladm_remove_deventry(zoneid_t zid, const char *link) -{ - char path[MAXPATHLEN]; - di_prof_t prof = NULL; - char zone_name[ZONENAME_MAX]; - dladm_status_t status; - if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0) - return (dladm_errno2status(errno)); - if (i_dladm_get_zone_dev(zone_name, path, sizeof (path)) != 0) - return (dladm_errno2status(errno)); - if (di_prof_init(path, &prof) != 0) - return (dladm_errno2status(errno)); + if (add) + ret = di_prof_add_dev(prof, name); + else + ret = di_prof_add_exclude(prof, name); - status = DLADM_STATUS_OK; - if (di_prof_add_exclude(prof, link) != 0) { + if (ret != 0) { status = dladm_errno2status(errno); goto cleanup; } + if (di_prof_commit(prof) != 0) status = dladm_errno2status(errno); cleanup: @@ -843,102 +638,93 @@ cleanup: } static dladm_status_t -do_get_zone(const char *link, char **prop_val, uint_t *val_cnt) -{ - char zone_name[ZONENAME_MAX]; - zoneid_t zid; - dladm_status_t status; - - status = i_dladm_get_zoneid(link, &zid); - if (status != DLADM_STATUS_OK) - return (status); - - *val_cnt = 1; - if (zid != GLOBAL_ZONEID) { - if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0) - return (dladm_errno2status(errno)); - - (void) strncpy(*prop_val, zone_name, DLADM_PROP_VAL_MAX); - } else { - *prop_val[0] = '\0'; - } - - return (DLADM_STATUS_OK); -} - -static dladm_status_t -do_set_zone(const char *link, val_desc_t *vdp, uint_t val_cnt) +do_set_zone(datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt) { dladm_status_t status; zoneid_t zid_old, zid_new; + char link[MAXLINKNAMELEN]; if (val_cnt != 1) return (DLADM_STATUS_BADVALCNT); - status = i_dladm_get_zoneid(link, &zid_old); + status = dladm_getzid(linkid, &zid_old); if (status != DLADM_STATUS_OK) return (status); /* Do nothing if setting to current value */ - zid_new = (intptr_t)(void *)vdp->vd_val; + zid_new = vdp->vd_val; if (zid_new == zid_old) return (DLADM_STATUS_OK); - if (zid_old != GLOBAL_ZONEID) { - if (dladm_rele_link(link, GLOBAL_ZONEID, B_TRUE) < 0) - return (dladm_errno2status(errno)); + if ((status = dladm_datalink_id2info(linkid, NULL, NULL, NULL, + link, MAXLINKNAMELEN)) != DLADM_STATUS_OK) { + return (status); + } - if (zone_remove_datalink(zid_old, (char *)link) != 0 && + if (zid_new != GLOBAL_ZONEID) { + /* + * If the new zoneid is the global zone, we could destroy + * the link (in the case of an implicitly-created VLAN) as a + * result of the dladm_setzid() operation. In that case, + * we defer the operation to the end of this function to avoid + * recreating the VLAN and getting a different linkid during + * the rollback if other operation fails. + * + * Otherwise, dladm_setzid() will hold a reference to the + * link and prevent a link renaming, so we need to do it + * before other operations. + */ + status = dladm_setzid(link, zid_new); + if (status != DLADM_STATUS_OK) + return (status); + } + + if (zid_old != GLOBAL_ZONEID) { + if (zone_remove_datalink(zid_old, link) != 0 && errno != ENXIO) { status = dladm_errno2status(errno); goto rollback1; } - status = i_dladm_remove_deventry(zid_old, link); - if (status != DLADM_STATUS_OK) - goto rollback2; + /* + * It is okay to fail to update the /dev entry (some + * vanity-named links do not have a /dev entry). + */ + (void) i_dladm_update_deventry(zid_old, linkid, B_FALSE); } if (zid_new != GLOBAL_ZONEID) { - if (zone_add_datalink(zid_new, (char *)link) != 0) { - status = dladm_errno2status(errno); - goto rollback3; - } - - if (dladm_hold_link(link, zid_new, B_TRUE) < 0) { - (void) zone_remove_datalink(zid_new, (char *)link); + if (zone_add_datalink(zid_new, link) != 0) { status = dladm_errno2status(errno); - goto rollback3; + goto rollback2; } - status = i_dladm_add_deventry(zid_new, link); - if (status != DLADM_STATUS_OK) { - (void) dladm_rele_link(link, GLOBAL_ZONEID, B_FALSE); - (void) zone_remove_datalink(zid_new, (char *)link); - goto rollback3; - } + (void) i_dladm_update_deventry(zid_new, linkid, B_TRUE); + } else { + status = dladm_setzid(link, zid_new); + if (status != DLADM_STATUS_OK) + goto rollback2; } + return (DLADM_STATUS_OK); -rollback3: - if (zid_old != GLOBAL_ZONEID) - (void) i_dladm_add_deventry(zid_old, link); rollback2: if (zid_old != GLOBAL_ZONEID) - (void) zone_add_datalink(zid_old, (char *)link); + (void) i_dladm_update_deventry(zid_old, linkid, B_TRUE); + if (zid_old != GLOBAL_ZONEID) + (void) zone_add_datalink(zid_old, link); rollback1: - (void) dladm_hold_link(link, zid_old, B_FALSE); -cleanexit: + if (zid_new != GLOBAL_ZONEID) + (void) dladm_setzid(link, zid_old); return (status); } /* ARGSUSED */ static dladm_status_t -do_check_zone(prop_desc_t *pdp, char **prop_val, uint_t val_cnt, - val_desc_t **vdpp) +do_check_zone(datalink_id_t linkid, char **prop_val, uint_t val_cnt, + val_desc_t *vdp, boolean_t *needfreep) { - zoneid_t zid; - val_desc_t *vdp = NULL; + zoneid_t zid; if (val_cnt != 1) return (DLADM_STATUS_BADVALCNT); @@ -959,176 +745,563 @@ do_check_zone(prop_desc_t *pdp, char **prop_val, uint_t val_cnt, } } - vdp = malloc(sizeof (val_desc_t)); - if (vdp == NULL) - return (DLADM_STATUS_NOMEM); - - vdp->vd_val = (void *)(uintptr_t)zid; - *vdpp = vdp; + vdp->vd_val = zid; + *needfreep = B_FALSE; return (DLADM_STATUS_OK); } static dladm_status_t -i_dladm_get_prop_temp(const char *link, dladm_prop_type_t type, - const char *prop_name, char **prop_val, uint_t *val_cntp) +do_get_autopush(datalink_id_t linkid, char **prop_val, uint_t *val_cnt) { - int i; - dladm_status_t status; - uint_t cnt; - prop_desc_t *pdp; + dld_ioc_ap_t dia; + int fd, i, len; - if (link == NULL || prop_name == NULL || prop_val == NULL || - val_cntp == NULL || *val_cntp == 0) - return (DLADM_STATUS_BADARG); + if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) + return (dladm_errno2status(errno)); - for (i = 0; i < MAX_PROPS; i++) - if (strcasecmp(prop_name, prop_table[i].pd_name) == 0) - break; + *val_cnt = 1; + dia.dia_linkid = linkid; + if (i_dladm_ioctl(fd, DLDIOC_GETAUTOPUSH, &dia, sizeof (dia)) < 0) { + (*prop_val)[0] = '\0'; + goto done; + } - if (i == MAX_PROPS) - return (DLADM_STATUS_NOTFOUND); + for (i = 0, len = 0; i < dia.dia_npush; i++) { + if (i != 0) { + (void) snprintf(*prop_val + len, + DLADM_PROP_VAL_MAX - len, "%c", AP_DELIMITER); + len += 1; + } + (void) snprintf(*prop_val + len, DLADM_PROP_VAL_MAX - len, + "%s", dia.dia_aplist[i]); + len += strlen(dia.dia_aplist[i]); + if (dia.dia_anchor - 1 == i) { + (void) snprintf(*prop_val + len, + DLADM_PROP_VAL_MAX - len, "%c%s", AP_DELIMITER, + AP_ANCHOR); + len += (strlen(AP_ANCHOR) + 1); + } + } - pdp = &prop_table[i]; - status = DLADM_STATUS_OK; +done: + (void) close(fd); + return (DLADM_STATUS_OK); +} - switch (type) { - case DLADM_PROP_VAL_CURRENT: - status = pdp->pd_get(link, prop_val, val_cntp); - break; - case DLADM_PROP_VAL_DEFAULT: - if (pdp->pd_defval.vd_name == NULL) { - status = DLADM_STATUS_NOTSUP; - break; - } - (void) strcpy(*prop_val, pdp->pd_defval.vd_name); - *val_cntp = 1; - break; +static dladm_status_t +do_set_autopush(datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt) +{ + dld_ioc_ap_t dia; + struct dlautopush *dlap = (struct dlautopush *)vdp->vd_val; + dladm_status_t status = DLADM_STATUS_OK; + int fd, i; + int ic_cmd; - case DLADM_PROP_VAL_MODIFIABLE: - if (pdp->pd_getmod != NULL) { - status = pdp->pd_getmod(link, prop_val, val_cntp); - break; - } - cnt = pdp->pd_nmodval; - if (cnt == 0) { - status = DLADM_STATUS_NOTSUP; - } else if (cnt > *val_cntp) { - status = DLADM_STATUS_TOOSMALL; - } else { - for (i = 0; i < cnt; i++) { - (void) strcpy(prop_val[i], - pdp->pd_modval[i].vd_name); - } - *val_cntp = cnt; + if (val_cnt != 1) + return (DLADM_STATUS_BADVALCNT); + + if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) + return (dladm_errno2status(errno)); + + dia.dia_linkid = linkid; + if (dlap != NULL) { + dia.dia_anchor = dlap->dap_anchor; + dia.dia_npush = dlap->dap_npush; + for (i = 0; i < dia.dia_npush; i++) { + (void) strlcpy(dia.dia_aplist[i], dlap->dap_aplist[i], + FMNAMESZ+1); } - break; - default: - status = DLADM_STATUS_BADARG; - break; + ic_cmd = DLDIOC_SETAUTOPUSH; + } else { + ic_cmd = DLDIOC_CLRAUTOPUSH; } + if (i_dladm_ioctl(fd, ic_cmd, &dia, sizeof (dia)) < 0) + status = dladm_errno2status(errno); + + (void) close(fd); return (status); } -static dladm_status_t -i_dladm_set_one_prop_temp(const char *link, prop_desc_t *pdp, char **prop_val, - uint_t val_cnt, uint_t flags) +/* + * Add the specified module to the dlautopush structure; returns a + * DLADM_STATUS_* code. + */ +dladm_status_t +i_dladm_add_ap_module(const char *module, struct dlautopush *dlap) { - dladm_status_t status; - val_desc_t *vdp = NULL; - uint_t cnt; + if ((strlen(module) == 0) || (strlen(module) > FMNAMESZ)) + return (DLADM_STATUS_BADVAL); - if (pdp->pd_temponly && (flags & DLADM_OPT_PERSIST) != 0) - return (DLADM_STATUS_TEMPONLY); + if (strncasecmp(module, AP_ANCHOR, strlen(AP_ANCHOR)) == 0) { + /* + * We don't allow multiple anchors, and the anchor must + * be after at least one module. + */ + if (dlap->dap_anchor != 0) + return (DLADM_STATUS_BADVAL); + if (dlap->dap_npush == 0) + return (DLADM_STATUS_BADVAL); - if (pdp->pd_set == NULL) - return (DLADM_STATUS_PROPRDONLY); + dlap->dap_anchor = dlap->dap_npush; + return (DLADM_STATUS_OK); + } + if (dlap->dap_npush > MAXAPUSH) + return (DLADM_STATUS_BADVALCNT); - if (prop_val != NULL) { - if (pdp->pd_check != NULL) - status = pdp->pd_check(pdp, prop_val, val_cnt, &vdp); - else - status = DLADM_STATUS_BADARG; + (void) strlcpy(dlap->dap_aplist[dlap->dap_npush++], module, + FMNAMESZ + 1); + + return (DLADM_STATUS_OK); +} + +/* + * Currently, both '.' and ' '(space) can be used as the delimiters between + * autopush modules. The former is used in dladm set-linkprop, and the + * latter is used in the autopush(1M) file. + */ +/* 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) +{ + char *module; + struct dlautopush *dlap; + dladm_status_t status; + char val[DLADM_PROP_VAL_MAX]; + char delimiters[4]; + + if (val_cnt != 1) + return (DLADM_STATUS_BADVALCNT); + + dlap = malloc(sizeof (struct dlautopush)); + if (dlap == NULL) + return (DLADM_STATUS_NOMEM); + (void) memset(dlap, 0, sizeof (struct dlautopush)); + (void) snprintf(delimiters, 4, " %c\n", AP_DELIMITER); + bcopy(*prop_val, val, DLADM_PROP_VAL_MAX); + module = strtok(val, delimiters); + while (module != NULL) { + status = i_dladm_add_ap_module(module, dlap); if (status != DLADM_STATUS_OK) return (status); + module = strtok(NULL, delimiters); + } - cnt = val_cnt; - } else { - if (pdp->pd_defval.vd_name == NULL) - return (DLADM_STATUS_NOTSUP); + vdp->vd_val = (uintptr_t)dlap; + *needfreep = B_TRUE; + return (DLADM_STATUS_OK); +} - if ((vdp = malloc(sizeof (val_desc_t))) == NULL) - return (DLADM_STATUS_NOMEM); +static dladm_status_t +do_get_rate_common(datalink_id_t linkid, char **prop_val, uint_t *val_cnt, + uint_t id) +{ + wl_rates_t *wrp; + uint_t i; + wldp_t *gbuf = NULL; + dladm_status_t status = DLADM_STATUS_OK; - (void) memcpy(vdp, &pdp->pd_defval, sizeof (val_desc_t)); - cnt = 1; + if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) { + status = DLADM_STATUS_NOMEM; + goto done; } - status = pdp->pd_set(link, vdp, cnt); + status = i_dladm_wlan_get_ioctl(linkid, gbuf, id); + if (status != DLADM_STATUS_OK) + goto done; - free(vdp); + wrp = (wl_rates_t *)gbuf->wldp_buf; + if (wrp->wl_rates_num > *val_cnt) { + status = DLADM_STATUS_TOOSMALL; + goto done; + } + + if (wrp->wl_rates_rates[0] == 0) { + prop_val[0][0] = '\0'; + *val_cnt = 1; + goto done; + } + + for (i = 0; i < wrp->wl_rates_num; i++) { + (void) snprintf(prop_val[i], DLADM_STRSIZE, "%.*f", + wrp->wl_rates_rates[i] % 2, + (float)wrp->wl_rates_rates[i] / 2); + } + *val_cnt = wrp->wl_rates_num; + +done: + free(gbuf); return (status); } static dladm_status_t -i_dladm_set_prop_temp(const char *link, const char *prop_name, char **prop_val, - uint_t val_cnt, uint_t flags, char **errprop) +do_get_rate_prop(datalink_id_t linkid, char **prop_val, uint_t *val_cnt) +{ + return (do_get_rate_common(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) +{ + return (do_get_rate_common(linkid, prop_val, val_cnt, + WL_SUPPORTED_RATES)); +} + +static dladm_status_t +do_set_rate(datalink_id_t linkid, dladm_wlan_rates_t *rates) { - int i; + int i; + uint_t len; + wldp_t *gbuf; + wl_rates_t *wrp; dladm_status_t status = DLADM_STATUS_OK; - boolean_t found = B_FALSE; - for (i = 0; i < MAX_PROPS; i++) { - prop_desc_t *pdp = &prop_table[i]; - dladm_status_t s; + if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) + return (DLADM_STATUS_NOMEM); - if (prop_name != NULL && - (strcasecmp(prop_name, pdp->pd_name) != 0)) - continue; + (void) memset(gbuf, 0, MAX_BUF_LEN); - found = B_TRUE; - s = i_dladm_set_one_prop_temp(link, pdp, prop_val, val_cnt, - flags); + wrp = (wl_rates_t *)gbuf->wldp_buf; + for (i = 0; i < rates->wr_cnt; i++) + wrp->wl_rates_rates[i] = rates->wr_rates[i]; + wrp->wl_rates_num = rates->wr_cnt; - if (prop_name != NULL) { - status = s; + len = offsetof(wl_rates_t, wl_rates_rates) + + (rates->wr_cnt * sizeof (char)) + WIFI_BUF_OFFSET; + status = i_dladm_wlan_ioctl(linkid, gbuf, WL_DESIRED_RATES, len, + WLAN_SET_PARAM, len); + + free(gbuf); + return (status); +} + +static dladm_status_t +do_set_rate_prop(datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt) +{ + dladm_wlan_rates_t rates; + dladm_status_t status; + + if (val_cnt != 1) + return (DLADM_STATUS_BADVALCNT); + + rates.wr_cnt = 1; + rates.wr_rates[0] = vdp[0].vd_val; + + status = do_set_rate(linkid, &rates); + +done: + return (status); +} + +/* 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) +{ + int i; + uint_t modval_cnt = MAX_SUPPORT_RATES; + char *buf, **modval; + dladm_status_t status; + + if (val_cnt != 1) + return (DLADM_STATUS_BADVALCNT); + + buf = malloc((sizeof (char *) + DLADM_STRSIZE) * + MAX_SUPPORT_RATES); + if (buf == NULL) { + status = DLADM_STATUS_NOMEM; + goto done; + } + + modval = (char **)(void *)buf; + for (i = 0; i < MAX_SUPPORT_RATES; i++) { + modval[i] = buf + sizeof (char *) * MAX_SUPPORT_RATES + + i * DLADM_STRSIZE; + } + + status = do_get_rate_mod(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); + status = DLADM_STATUS_OK; + + /* + * Does not need the caller to free the vdp->vd_val + */ + *needfreep = B_FALSE; break; - } else { - if (s != DLADM_STATUS_OK && - s != DLADM_STATUS_NOTSUP) { - if (errprop != NULL) - *errprop = pdp->pd_name; - status = s; - break; - } } } + if (i == modval_cnt) + status = DLADM_STATUS_BADVAL; +done: + free(buf); + return (status); +} - if (!found) +static dladm_status_t +do_get_phyconf(datalink_id_t linkid, wldp_t *gbuf) +{ + return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_PHY_CONFIG)); +} + +static dladm_status_t +do_get_channel_prop(datalink_id_t linkid, char **prop_val, uint_t *val_cnt) +{ + uint32_t channel; + wldp_t *gbuf; + dladm_status_t status = DLADM_STATUS_OK; + + if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) + return (DLADM_STATUS_NOMEM); + + if ((status = do_get_phyconf(linkid, gbuf)) != DLADM_STATUS_OK) + goto done; + + if (!i_dladm_wlan_convert_chan((wl_phy_conf_t *)gbuf->wldp_buf, + &channel)) { status = DLADM_STATUS_NOTFOUND; + goto done; + } + (void) snprintf(*prop_val, DLADM_STRSIZE, "%u", channel); + *val_cnt = 1; + +done: + free(gbuf); return (status); } -static boolean_t -i_dladm_is_prop_temponly(const char *prop_name, char **errprop) +static dladm_status_t +do_get_powermode(datalink_id_t linkid, wldp_t *gbuf) { - int i; + return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_POWER_MODE)); +} - for (i = 0; i < MAX_PROPS; i++) { - prop_desc_t *pdp = &prop_table[i]; +static dladm_status_t +do_get_powermode_prop(datalink_id_t linkid, char **prop_val, uint_t *val_cnt) +{ + wl_ps_mode_t *mode; + const char *s; + wldp_t *gbuf; + dladm_status_t status = DLADM_STATUS_OK; - if (prop_name != NULL && - (strcasecmp(prop_name, pdp->pd_name) != 0)) - continue; + if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) + return (DLADM_STATUS_NOMEM); + + if ((status = do_get_powermode(linkid, gbuf)) != DLADM_STATUS_OK) + goto done; + + mode = (wl_ps_mode_t *)(gbuf->wldp_buf); + switch (mode->wl_ps_mode) { + case WL_PM_AM: + s = "off"; + break; + case WL_PM_MPS: + s = "max"; + break; + case WL_PM_FAST: + s = "fast"; + break; + default: + status = DLADM_STATUS_NOTFOUND; + goto done; + } + (void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s); + *val_cnt = 1; + +done: + free(gbuf); + return (status); +} + +static dladm_status_t +do_set_powermode(datalink_id_t linkid, dladm_wlan_powermode_t *pm) +{ + wl_ps_mode_t ps_mode; - if (errprop != NULL) - *errprop = pdp->pd_name; + (void) memset(&ps_mode, 0xff, sizeof (ps_mode)); - if (pdp->pd_temponly) - return (B_TRUE); + switch (*pm) { + case DLADM_WLAN_PM_OFF: + ps_mode.wl_ps_mode = WL_PM_AM; + break; + case DLADM_WLAN_PM_MAX: + ps_mode.wl_ps_mode = WL_PM_MPS; + break; + case DLADM_WLAN_PM_FAST: + ps_mode.wl_ps_mode = WL_PM_FAST; + break; + default: + return (DLADM_STATUS_NOTSUP); } + return (i_dladm_wlan_set_ioctl(linkid, WL_POWER_MODE, &ps_mode, + sizeof (ps_mode))); +} - return (B_FALSE); +/* ARGSUSED */ +static dladm_status_t +do_set_powermode_prop(datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt) +{ + dladm_wlan_powermode_t powermode = (dladm_wlan_powermode_t)vdp->vd_val; + dladm_status_t status; + + if (val_cnt != 1) + return (DLADM_STATUS_BADVALCNT); + + status = do_set_powermode(linkid, &powermode); + + return (status); +} + +static dladm_status_t +do_get_radio(datalink_id_t linkid, wldp_t *gbuf) +{ + return (i_dladm_wlan_get_ioctl(linkid, gbuf, WL_RADIO)); +} + +static dladm_status_t +do_get_radio_prop(datalink_id_t linkid, char **prop_val, uint_t *val_cnt) +{ + wl_radio_t radio; + const char *s; + wldp_t *gbuf; + dladm_status_t status = DLADM_STATUS_OK; + + if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) + return (DLADM_STATUS_NOMEM); + + if ((status = do_get_radio(linkid, gbuf)) != DLADM_STATUS_OK) + goto done; + + radio = *(wl_radio_t *)(gbuf->wldp_buf); + switch (radio) { + case B_TRUE: + s = "on"; + break; + case B_FALSE: + s = "off"; + break; + default: + status = DLADM_STATUS_NOTFOUND; + goto done; + } + (void) snprintf(*prop_val, DLADM_STRSIZE, "%s", s); + *val_cnt = 1; + +done: + free(gbuf); + return (status); +} + +static dladm_status_t +do_set_radio(datalink_id_t linkid, dladm_wlan_radio_t *radio) +{ + wl_radio_t r; + + switch (*radio) { + case DLADM_WLAN_RADIO_ON: + r = B_TRUE; + break; + case DLADM_WLAN_RADIO_OFF: + r = B_FALSE; + break; + default: + return (DLADM_STATUS_NOTSUP); + } + return (i_dladm_wlan_set_ioctl(linkid, WL_RADIO, &r, sizeof (r))); +} + +/* ARGSUSED */ +static dladm_status_t +do_set_radio_prop(datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt) +{ + dladm_wlan_radio_t radio = (dladm_wlan_radio_t)vdp->vd_val; + dladm_status_t status; + + if (val_cnt != 1) + return (DLADM_STATUS_BADVALCNT); + + status = do_set_radio(linkid, &radio); + + return (status); +} + +static dladm_status_t +i_dladm_set_linkprop_db(datalink_id_t linkid, const char *prop_name, + char **prop_val, uint_t val_cnt) +{ + char buf[MAXLINELEN]; + int i; + dladm_conf_t conf; + dladm_status_t status; + + status = dladm_read_conf(linkid, &conf); + if (status != DLADM_STATUS_OK) + return (status); + + /* + * reset case. + */ + if (val_cnt == 0) { + status = dladm_unset_conf_field(conf, prop_name); + if (status == DLADM_STATUS_OK) + status = dladm_write_conf(conf); + goto done; + } + + buf[0] = '\0'; + for (i = 0; i < val_cnt; i++) { + (void) strlcat(buf, prop_val[i], MAXLINELEN); + if (i != val_cnt - 1) + (void) strlcat(buf, ",", MAXLINELEN); + } + + status = dladm_set_conf_field(conf, prop_name, DLADM_TYPE_STR, buf); + if (status == DLADM_STATUS_OK) + status = dladm_write_conf(conf); + +done: + dladm_destroy_conf(conf); + return (status); +} + +static dladm_status_t +i_dladm_get_linkprop_db(datalink_id_t linkid, const char *prop_name, + char **prop_val, uint_t *val_cntp) +{ + char buf[MAXLINELEN], *str; + uint_t cnt = 0; + dladm_conf_t conf; + dladm_status_t status; + + status = dladm_read_conf(linkid, &conf); + if (status != DLADM_STATUS_OK) + return (status); + + status = dladm_get_conf_field(conf, prop_name, buf, MAXLINELEN); + if (status != DLADM_STATUS_OK) + goto done; + + str = strtok(buf, ","); + while (str != NULL) { + if (cnt == *val_cntp) { + status = DLADM_STATUS_TOOSMALL; + goto done; + } + (void) strlcpy(prop_val[cnt++], str, DLADM_PROP_VAL_MAX); + str = strtok(NULL, ","); + } + + *val_cntp = cnt; + +done: + dladm_destroy_conf(conf); + return (status); } diff --git a/usr/src/lib/libdladm/common/llib-ldladm b/usr/src/lib/libdladm/common/llib-ldladm index 467808e937..a6fc19b517 100644 --- a/usr/src/lib/libdladm/common/llib-ldladm +++ b/usr/src/lib/libdladm/common/llib-ldladm @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -32,3 +32,5 @@ #include <libdlaggr.h> #include <libdlwlan.h> #include <libdlvnic.h> +#include <libdlvlan.h> +#include <libdlmgmt.h> diff --git a/usr/src/lib/libdladm/common/mapfile-vers b/usr/src/lib/libdladm/common/mapfile-vers index 2672efc195..25ab048469 100644 --- a/usr/src/lib/libdladm/common/mapfile-vers +++ b/usr/src/lib/libdladm/common/mapfile-vers @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2007 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" @@ -29,17 +29,18 @@ SUNWprivate_1.1 { global: dladm_info; dladm_walk; - dladm_hold_link; - dladm_rele_link; + dladm_setzid; + dladm_getzid; dladm_status2str; dladm_linkstate2str; dladm_linkduplex2str; dladm_set_rootdir; + dladm_valid_linkname; dladm_mac_walk; dladm_init_linkprop; - dladm_get_prop; - dladm_set_prop; - dladm_walk_prop; + dladm_get_linkprop; + dladm_set_linkprop; + dladm_walk_linkprop; dladm_init_secobj; dladm_get_secobj; dladm_set_secobj; @@ -47,9 +48,7 @@ SUNWprivate_1.1 { dladm_walk_secobj; dladm_secobjclass2str; dladm_str2secobjclass; - dladm_aggr_walk; dladm_aggr_up; - dladm_aggr_down; dladm_aggr_add; dladm_aggr_create; dladm_aggr_delete; @@ -64,15 +63,12 @@ SUNWprivate_1.1 { dladm_aggr_str2lacptimer; dladm_aggr_str2macaddr; dladm_aggr_str2policy; - dladm_wlan_walk; + dladm_aggr_info; + dladm_key2linkid; dladm_wlan_scan; dladm_wlan_connect; dladm_wlan_disconnect; dladm_wlan_get_linkattr; - dladm_wlan_is_valid; - dladm_wlan_set_prop; - dladm_wlan_walk_prop; - dladm_wlan_get_prop; dladm_wlan_essid2str; dladm_wlan_bssid2str; dladm_wlan_secmode2str; @@ -91,6 +87,32 @@ SUNWprivate_1.1 { dladm_wlan_str2auth; dladm_wlan_str2bsstype; dladm_wlan_str2linkstatus; + dladm_vlan_create; + dladm_vlan_delete; + dladm_vlan_up; + dladm_vlan_info; + dladm_class2str; + dladm_media2str; + dladm_rename_link; + dladm_phys_info; + dladm_phys_delete; + dladm_dev2linkid; + dladm_linkid2legacyname; + dladm_create_datalink_id; + dladm_destroy_datalink_id; + dladm_remap_datalink_id; + dladm_up_datalink_id; + dladm_name2info; + dladm_datalink_id2info; + dladm_walk_datalink_id; + dladm_create_conf; + dladm_read_conf; + dladm_write_conf; + dladm_remove_conf; + dladm_destroy_conf; + dladm_get_conf_field; + dladm_set_conf_field; + dladm_unset_conf_field; dladm_wlan_wpa_get_sr; dladm_wlan_wpa_set_ie; dladm_wlan_wpa_set_wpa; @@ -100,8 +122,8 @@ SUNWprivate_1.1 { dladm_vnic_create; dladm_vnic_modify; dladm_vnic_delete; - dladm_vnic_walk_sys; - dladm_vnic_mac_addr_str_to_type; + dladm_vnic_info; + dladm_vnic_str2macaddrtype; local: *; diff --git a/usr/src/lib/libdladm/common/secobj.c b/usr/src/lib/libdladm/common/secobj.c index 61a1cd72e5..7f17a38e4e 100644 --- a/usr/src/lib/libdladm/common/secobj.c +++ b/usr/src/lib/libdladm/common/secobj.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -136,7 +136,7 @@ dladm_set_secobj(const char *obj_name, dladm_secobj_class_t class, obj_val == NULL || obj_len == 0 || obj_len > DLD_SECOBJ_VAL_MAX) return (DLADM_STATUS_BADARG); - if ((flags & DLADM_OPT_TEMP) == 0) + if ((flags & DLADM_OPT_ACTIVE) == 0) goto persist; bzero(&secobj_set, sizeof (secobj_set)); @@ -154,7 +154,7 @@ dladm_set_secobj(const char *obj_name, dladm_secobj_class_t class, if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) return (dladm_errno2status(errno)); - if (i_dladm_ioctl(fd, DLDIOCSECOBJSET, &secobj_set, + if (i_dladm_ioctl(fd, DLDIOC_SECOBJ_SET, &secobj_set, sizeof (secobj_set)) < 0) { status = dladm_errno2status(errno); } @@ -198,7 +198,7 @@ dladm_get_secobj(const char *obj_name, dladm_secobj_class_t *classp, if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) return (dladm_errno2status(errno)); - if (i_dladm_ioctl(fd, DLDIOCSECOBJGET, &secobj_get, + if (i_dladm_ioctl(fd, DLDIOC_SECOBJ_GET, &secobj_get, sizeof (secobj_get)) < 0) status = dladm_errno2status(errno); @@ -225,7 +225,7 @@ dladm_unset_secobj(const char *obj_name, uint_t flags) flags == 0) return (DLADM_STATUS_BADARG); - if ((flags & DLADM_OPT_TEMP) == 0) + if ((flags & DLADM_OPT_ACTIVE) == 0) goto persist; bzero(&secobj_unset, sizeof (secobj_unset)); @@ -233,7 +233,7 @@ dladm_unset_secobj(const char *obj_name, uint_t flags) if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) return (dladm_errno2status(errno)); - if (i_dladm_ioctl(fd, DLDIOCSECOBJUNSET, &secobj_unset, + if (i_dladm_ioctl(fd, DLDIOC_SECOBJ_UNSET, &secobj_unset, sizeof (secobj_unset)) < 0) status = dladm_errno2status(errno); @@ -269,7 +269,7 @@ dladm_walk_secobj(void *arg, boolean_t (*func)(void *, const char *), status = dladm_errno2status(errno); goto done; } - if (i_dladm_ioctl(fd, DLDIOCSECOBJGET, secobj_getp, + if (i_dladm_ioctl(fd, DLDIOC_SECOBJ_GET, secobj_getp, SECOBJ_BUFSZ) < 0) { status = dladm_errno2status(errno); goto done; @@ -400,7 +400,7 @@ process_secobj_init(secobj_db_state_t *ssp, char *buf, secobj_info_t *sip, dladm_status_t *statusp) { *statusp = dladm_set_secobj(sip->si_name, *sip->si_classp, sip->si_val, - *sip->si_lenp, DLADM_OPT_TEMP | DLADM_OPT_CREATE); + *sip->si_lenp, DLADM_OPT_ACTIVE | DLADM_OPT_CREATE); return (B_TRUE); } |