summaryrefslogtreecommitdiff
path: root/usr/src/lib
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib')
-rw-r--r--usr/src/lib/Makefile5
-rw-r--r--usr/src/lib/libbsm/audit_class.txt1
-rw-r--r--usr/src/lib/libbsm/audit_event.txt2
-rw-r--r--usr/src/lib/libbsm/common/adt_event.h18
-rw-r--r--usr/src/lib/libbsm/common/adt_xlate.c44
-rw-r--r--usr/src/lib/libbsm/common/adt_xml.txt33
-rw-r--r--usr/src/lib/libdladm/Makefile2
-rw-r--r--usr/src/lib/libdladm/Makefile.com5
-rw-r--r--usr/src/lib/libdladm/common/libdladm.c274
-rw-r--r--usr/src/lib/libdladm/common/libdladm.h72
-rw-r--r--usr/src/lib/libdladm/common/libdladm_impl.h51
-rw-r--r--usr/src/lib/libdladm/common/linkprop.c700
-rw-r--r--usr/src/lib/libdladm/common/mapfile-vers14
-rw-r--r--usr/src/lib/libdladm/common/secobj.c634
-rw-r--r--usr/src/lib/liblaadm/common/liblaadm.c26
-rw-r--r--usr/src/lib/libsecdb/auth_attr.txt1
-rw-r--r--usr/src/lib/libsecdb/exec_attr.txt5
-rw-r--r--usr/src/lib/libsecdb/help/auths/LinkSecurity.html45
-rw-r--r--usr/src/lib/libsecdb/help/auths/Makefile3
-rw-r--r--usr/src/lib/libsecdb/help/profiles/Makefile8
-rw-r--r--usr/src/lib/libsecdb/help/profiles/RtNetLinkSecure.html39
-rw-r--r--usr/src/lib/libsecdb/prof_attr.txt3
-rw-r--r--usr/src/lib/libwladm/Makefile62
-rw-r--r--usr/src/lib/libwladm/Makefile.com51
-rw-r--r--usr/src/lib/libwladm/common/libwladm.c1957
-rw-r--r--usr/src/lib/libwladm/common/libwladm.h209
-rw-r--r--usr/src/lib/libwladm/common/libwladm_impl.h82
-rw-r--r--usr/src/lib/libwladm/common/llib-lwladm31
-rw-r--r--usr/src/lib/libwladm/common/mapfile-vers60
-rw-r--r--usr/src/lib/libwladm/i386/Makefile30
-rw-r--r--usr/src/lib/libwladm/sparc/Makefile30
31 files changed, 4454 insertions, 43 deletions
diff --git a/usr/src/lib/Makefile b/usr/src/lib/Makefile
index d507548e2b..6effccf08b 100644
--- a/usr/src/lib/Makefile
+++ b/usr/src/lib/Makefile
@@ -185,6 +185,7 @@ SUBDIRS += \
madv \
mpss \
libdisasm \
+ libwladm \
libwrap \
libxcurses \
libxcurses2 \
@@ -374,6 +375,7 @@ HDRSUBDIRS= \
libvolmgt \
libumem \
libuutil \
+ libwladm \
libwrap \
libxcurses2 \
libzfs \
@@ -461,7 +463,7 @@ libdevinfo: libnvpair libsec
libdhcpagent: libdhcputil libnsl libsocket
libdhcpsvc: libinetutil
libdhcputil: libinetutil
-libdladm: libdlpi libdevinfo
+libdladm: libdlpi libdevinfo libwladm libinetutil
libdtrace: libproc libgen libctf
libdtrace_jni: libuutil libdtrace
libefi: libuuid
@@ -493,6 +495,7 @@ libwrap: libnsl libsocket
libwanboot: libnvpair libresolv libnsl libsocket libdevinfo libinetutil \
libdhcputil openssl
libwanbootutil: libnsl
+libwladm: libdevinfo libsocket
pam_modules: libproject passwdutil $(SMARTCARD)
libscf: libuutil libmd
libinetsvc: libscf
diff --git a/usr/src/lib/libbsm/audit_class.txt b/usr/src/lib/libbsm/audit_class.txt
index d8e2c6ee42..ae51e5fb53 100644
--- a/usr/src/lib/libbsm/audit_class.txt
+++ b/usr/src/lib/libbsm/audit_class.txt
@@ -52,6 +52,7 @@
0x00000400:na:non-attribute
0x00001000:lo:login or logout
0x00004000:ap:application
+0x00008000:cy:cryptographic
0x00010000:ss:change system state
0x00020000:as:system-wide administration
0x00040000:ua:user administration
diff --git a/usr/src/lib/libbsm/audit_event.txt b/usr/src/lib/libbsm/audit_event.txt
index da1ab9aabe..784b79eab5 100644
--- a/usr/src/lib/libbsm/audit_event.txt
+++ b/usr/src/lib/libbsm/audit_event.txt
@@ -428,6 +428,8 @@
6232:AUE_remove:remove/eject device:ot
6233:AUE_pool_import:import device into pool:ot
6234:AUE_pool_export:export device from pool:ot
+6235:AUE_dladm_create_secobj:create network security object:as,cy
+6236:AUE_dladm_delete_secobj:delete network security object:as,cy
#
# Trusted Extensions events:
#
diff --git a/usr/src/lib/libbsm/common/adt_event.h b/usr/src/lib/libbsm/common/adt_event.h
index f55e446097..f9e2c06ab8 100644
--- a/usr/src/lib/libbsm/common/adt_event.h
+++ b/usr/src/lib/libbsm/common/adt_event.h
@@ -95,6 +95,8 @@ enum adt_login_text {
#define ADT_admin_authenticate 3
#define ADT_attach 42
#define ADT_detach 43
+#define ADT_dladm_create_secobj 47
+#define ADT_dladm_delete_secobj 48
#define ADT_filesystem_add 4
#define ADT_filesystem_delete 5
#define ADT_filesystem_modify 6
@@ -161,6 +163,20 @@ struct adt_detach { /* ADT_detach */
};
typedef struct adt_detach adt_detach_t;
+struct adt_dladm_create_secobj { /* ADT_dladm_create_secobj */
+ char *auth_used; /* required */
+ char *obj_class; /* required */
+ char *obj_name; /* required */
+};
+typedef struct adt_dladm_create_secobj adt_dladm_create_secobj_t;
+
+struct adt_dladm_delete_secobj { /* ADT_dladm_delete_secobj */
+ char *auth_used; /* required */
+ char *obj_class; /* required */
+ char *obj_name; /* required */
+};
+typedef struct adt_dladm_delete_secobj adt_dladm_delete_secobj_t;
+
struct adt_filesystem_add { /* ADT_filesystem_add */
char *object_name; /* required */
char *domain; /* optional */
@@ -483,6 +499,8 @@ union adt_event_data {
adt_admin_authenticate_t adt_admin_authenticate;
adt_attach_t adt_attach;
adt_detach_t adt_detach;
+ adt_dladm_create_secobj_t adt_dladm_create_secobj;
+ adt_dladm_delete_secobj_t adt_dladm_delete_secobj;
adt_filesystem_add_t adt_filesystem_add;
adt_filesystem_delete_t adt_filesystem_delete;
adt_filesystem_modify_t adt_filesystem_modify;
diff --git a/usr/src/lib/libbsm/common/adt_xlate.c b/usr/src/lib/libbsm/common/adt_xlate.c
index 1da827d5f7..a24aa10439 100644
--- a/usr/src/lib/libbsm/common/adt_xlate.c
+++ b/usr/src/lib/libbsm/common/adt_xlate.c
@@ -117,6 +117,46 @@ static struct translation X_detach = {
&XX_detach[0],
&XX_detach[0]
};
+static struct entry XX_dladm_create_secobj[5] = {
+ {AUT_SUBJECT, 1, NULL, &(XX_dladm_create_secobj[1]),
+ 0, 0, 0, NULL},
+ {AUT_UAUTH, 1, &adr1[0], &(XX_dladm_create_secobj[2]),
+ 0, 1, 0, NULL},
+ {AUT_TEXT, 1, &adr1[0], &(XX_dladm_create_secobj[3]),
+ 0, 1, 0, NULL},
+ {AUT_TEXT, 1, &adr1[0], &(XX_dladm_create_secobj[4]),
+ 0, 1, 0, NULL},
+ {AUT_RETURN, 1, NULL, NULL,
+ 0, 0, 0, NULL}
+};
+static struct translation X_dladm_create_secobj = {
+ 0,
+ ADT_dladm_create_secobj,
+ AUE_dladm_create_secobj,
+ 5,
+ &XX_dladm_create_secobj[0],
+ &XX_dladm_create_secobj[0]
+};
+static struct entry XX_dladm_delete_secobj[5] = {
+ {AUT_SUBJECT, 1, NULL, &(XX_dladm_delete_secobj[1]),
+ 0, 0, 0, NULL},
+ {AUT_UAUTH, 1, &adr1[0], &(XX_dladm_delete_secobj[2]),
+ 0, 1, 0, NULL},
+ {AUT_TEXT, 1, &adr1[0], &(XX_dladm_delete_secobj[3]),
+ 0, 1, 0, NULL},
+ {AUT_TEXT, 1, &adr1[0], &(XX_dladm_delete_secobj[4]),
+ 0, 1, 0, NULL},
+ {AUT_RETURN, 1, NULL, NULL,
+ 0, 0, 0, NULL}
+};
+static struct translation X_dladm_delete_secobj = {
+ 0,
+ ADT_dladm_delete_secobj,
+ AUE_dladm_delete_secobj,
+ 5,
+ &XX_dladm_delete_secobj[0],
+ &XX_dladm_delete_secobj[0]
+};
static struct entry XX_filesystem_add[7] = {
{AUT_SUBJECT, 1, NULL, &(XX_filesystem_add[1]),
0, 0, 0, NULL},
@@ -979,10 +1019,12 @@ static struct translation X_zone_state = {
&XX_zone_state[0],
&XX_zone_state[0]
};
-struct translation *xlate_table[47] = {
+struct translation *xlate_table[49] = {
&X_admin_authenticate,
&X_attach,
&X_detach,
+ &X_dladm_create_secobj,
+ &X_dladm_delete_secobj,
&X_filesystem_add,
&X_filesystem_delete,
&X_filesystem_modify,
diff --git a/usr/src/lib/libbsm/common/adt_xml.txt b/usr/src/lib/libbsm/common/adt_xml.txt
index 222dfaf59c..16999ce633 100644
--- a/usr/src/lib/libbsm/common/adt_xml.txt
+++ b/usr/src/lib/libbsm/common/adt_xml.txt
@@ -843,8 +843,39 @@ Use is subject to license terms.
</entry>
</event>
+<!-- dladm security objected events -->
+ <event id="AUE_dladm_generic" type="generic" omit="always">
+ <entry id="subject">
+ <internal token="subject"/>
+ <external opt="none"/>
+ </entry>
+ <entry id="auth_used">
+ <internal token="uauth"/>
+ <external opt="required" type="char *"/>
+ </entry>
+ <entry id="obj_class">
+ <internal token="text"/>
+ <external opt="required" type="char *"/>
+ </entry>
+ <entry id="obj_name">
+ <internal token="text"/>
+ <external opt="required" type="char *"/>
+ </entry>
+ <entry id="return">
+ <internal token="return"/>
+ <external opt="none"/>
+ </entry>
+ </event>
+
+ <event id="AUE_dladm_create_secobj" instance_of="AUE_dladm_generic"
+ header="0" idNo="47" omit="JNI">
+ </event>
+ <event id="AUE_dladm_delete_secobj" instance_of="AUE_dladm_generic"
+ header="0" idNo="48" omit="JNI">
+ </event>
+
<!-- add new everts here with the next higher idNo -->
-<!-- Highest idNo is 46, so next is 47, then fix this comment -->
+<!-- Highest idNo is 48, so next is 49, then fix this comment -->
<!-- end of C Only events -->
diff --git a/usr/src/lib/libdladm/Makefile b/usr/src/lib/libdladm/Makefile
index 6fdcdf8a88..8794785ba1 100644
--- a/usr/src/lib/libdladm/Makefile
+++ b/usr/src/lib/libdladm/Makefile
@@ -27,7 +27,7 @@
include $(SRC)/lib/Makefile.lib
-HDRS = libdladm.h
+HDRS = libdladm.h libdladm_impl.h
HDRDIR = common
SUBDIRS = $(MACH)
diff --git a/usr/src/lib/libdladm/Makefile.com b/usr/src/lib/libdladm/Makefile.com
index 23396f1091..83b423a83b 100644
--- a/usr/src/lib/libdladm/Makefile.com
+++ b/usr/src/lib/libdladm/Makefile.com
@@ -27,7 +27,7 @@
LIBRARY = libdladm.a
VERS = .1
-OBJECTS = libdladm.o
+OBJECTS = libdladm.o secobj.o linkprop.o
include ../../Makefile.lib
@@ -35,8 +35,7 @@ include ../../Makefile.lib
include ../../Makefile.rootfs
LIBS = $(DYNLIB) $(LINTLIB)
-
-LDLIBS += -ldevinfo -ldlpi -lc
+LDLIBS += -ldevinfo -ldlpi -lc -lwladm -linetutil
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 679368a9ae..f7f9c1755a 100644
--- a/usr/src/lib/libdladm/common/libdladm.c
+++ b/usr/src/lib/libdladm/common/libdladm.c
@@ -25,19 +25,18 @@
#pragma ident "%Z%%M% %I% %E% SMI"
-#include <stdio.h>
-#include <sys/types.h>
-#include <string.h>
-#include <fcntl.h>
#include <unistd.h>
#include <stropts.h>
-#include <stdlib.h>
#include <errno.h>
-#include <libdevinfo.h>
-#include <libdlpi.h>
-#include <libdladm.h>
-#include <sys/dld.h>
+#include <fcntl.h>
+#include <strings.h>
+#include <dirent.h>
#include <net/if.h>
+#include <sys/stat.h>
+#include <sys/dld.h>
+#include <libdlpi.h>
+#include <libdevinfo.h>
+#include <libdladm_impl.h>
typedef struct dladm_dev {
char dd_name[IFNAMSIZ];
@@ -48,11 +47,13 @@ typedef struct dladm_walk {
dladm_dev_t *dw_dev_list;
} dladm_walk_t;
+static char dladm_rootdir[MAXPATHLEN] = "/";
+
/*
* Issue an ioctl to the specified file descriptor attached to the
* DLD control driver interface.
*/
-static int
+int
i_dladm_ioctl(int fd, int ic_cmd, void *ic_dp, int ic_len)
{
struct strioctl iocb;
@@ -250,3 +251,256 @@ failed:
(void) close(fd);
return (-1);
}
+
+const char *
+dladm_status2str(dladm_status_t status, char *buf)
+{
+ const char *s;
+
+ switch (status) {
+ case DLADM_STATUS_OK:
+ s = "ok";
+ break;
+ case DLADM_STATUS_BADARG:
+ s = "invalid argument";
+ break;
+ case DLADM_STATUS_FAILED:
+ s = "operation failed";
+ break;
+ case DLADM_STATUS_TOOSMALL:
+ s = "buffer size too small";
+ break;
+ case DLADM_STATUS_NOTSUP:
+ s = "operation not supported";
+ break;
+ case DLADM_STATUS_NOTFOUND:
+ s = "object not found";
+ break;
+ case DLADM_STATUS_BADVAL:
+ s = "invalid value";
+ break;
+ case DLADM_STATUS_NOMEM:
+ s = "insufficient memory";
+ break;
+ case DLADM_STATUS_EXIST:
+ s = "object already exists";
+ break;
+ case DLADM_STATUS_LINKINVAL:
+ s = "invalid link";
+ break;
+ case DLADM_STATUS_PROPRDONLY:
+ s = "read-only property";
+ break;
+ case DLADM_STATUS_BADVALCNT:
+ s = "invalid number of values";
+ break;
+ case DLADM_STATUS_DBNOTFOUND:
+ s = "database not found";
+ break;
+ case DLADM_STATUS_DENIED:
+ s = "permission denied";
+ break;
+ case DLADM_STATUS_IOERR:
+ s = "I/O error";
+ break;
+ default:
+ s = "";
+ }
+ (void) snprintf(buf, DLADM_STRSIZE, "%s", s);
+ return (buf);
+}
+
+/*
+ * Convert a unix errno to a dladm_status_t.
+ * We only convert errnos that are likely to be encountered. All others
+ * are mapped to DLADM_STATUS_FAILED.
+ */
+dladm_status_t
+dladm_errno2status(int err)
+{
+ switch (err) {
+ case EINVAL:
+ return (DLADM_STATUS_BADARG);
+ case EEXIST:
+ return (DLADM_STATUS_EXIST);
+ case ENOENT:
+ return (DLADM_STATUS_NOTFOUND);
+ case ENOSPC:
+ return (DLADM_STATUS_TOOSMALL);
+ case ENOMEM:
+ return (DLADM_STATUS_NOMEM);
+ case ENOTSUP:
+ return (DLADM_STATUS_NOTSUP);
+ case EACCES:
+ return (DLADM_STATUS_DENIED);
+ case EIO:
+ return (DLADM_STATUS_IOERR);
+ default:
+ return (DLADM_STATUS_FAILED);
+ }
+}
+
+/*
+ * 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
+
+static int
+i_dladm_lock_db(const char *lock_file, short type)
+{
+ int lock_fd;
+ struct flock lock;
+
+ if ((lock_fd = open(lock_file, O_RDWR | O_CREAT | O_TRUNC,
+ LOCK_DB_PERMS)) < 0)
+ return (-1);
+
+ lock.l_type = type;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = 0;
+ lock.l_len = 0;
+
+ if (fcntl(lock_fd, F_SETLKW, &lock) < 0) {
+ int err = errno;
+
+ (void) close(lock_fd);
+ (void) unlink(lock_file);
+ errno = err;
+ return (-1);
+ }
+ return (lock_fd);
+}
+
+static void
+i_dladm_unlock_db(const char *lock_file, int fd)
+{
+ struct flock lock;
+
+ if (fd < 0)
+ return;
+
+ lock.l_type = F_UNLCK;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = 0;
+ lock.l_len = 0;
+
+ (void) fcntl(fd, F_SETLKW, &lock);
+ (void) close(fd);
+ (void) unlink(lock_file);
+}
+
+dladm_status_t
+i_dladm_rw_db(const char *db_file, mode_t db_perms,
+ dladm_status_t (*process_db)(void *, FILE *, FILE *),
+ void *arg, boolean_t writeop)
+{
+ dladm_status_t status = DLADM_STATUS_OK;
+ FILE *fp, *nfp = NULL;
+ char lock[MAXPATHLEN];
+ char file[MAXPATHLEN];
+ char newfile[MAXPATHLEN];
+ char *db_basename;
+ int nfd, lock_fd;
+
+ /*
+ * If we are called from a boot script such as net-physical,
+ * it's quite likely that the root fs is still not writable.
+ * For this case, it's ok for the lock creation to fail since
+ * no one else could be accessing our configuration file.
+ */
+ db_basename = strrchr(db_file, '/');
+ if (db_basename == NULL || db_basename[1] == '\0')
+ return (dladm_errno2status(EINVAL));
+ db_basename++;
+ (void) snprintf(lock, MAXPATHLEN, "/tmp/%s.lock", db_basename);
+ if ((lock_fd = i_dladm_lock_db
+ (lock, (writeop ? F_WRLCK : F_RDLCK))) < 0 && errno != EROFS)
+ return (dladm_errno2status(errno));
+
+ (void) snprintf(file, MAXPATHLEN, "%s/%s", dladm_rootdir, db_file);
+ if ((fp = fopen(file, (writeop ? "r+" : "r"))) == NULL) {
+ int err = errno;
+
+ i_dladm_unlock_db(lock, lock_fd);
+ if (err == ENOENT)
+ return (DLADM_STATUS_DBNOTFOUND);
+
+ return (dladm_errno2status(err));
+ }
+
+ if (writeop) {
+ (void) snprintf(newfile, MAXPATHLEN, "%s/%s.new",
+ dladm_rootdir, db_file);
+ if ((nfd = open(newfile, O_WRONLY | O_CREAT | O_TRUNC,
+ db_perms)) < 0) {
+ (void) fclose(fp);
+ i_dladm_unlock_db(lock, lock_fd);
+ return (dladm_errno2status(errno));
+ }
+
+ if ((nfp = fdopen(nfd, "w")) == NULL) {
+ (void) close(nfd);
+ (void) fclose(fp);
+ (void) unlink(newfile);
+ i_dladm_unlock_db(lock, lock_fd);
+ return (dladm_errno2status(errno));
+ }
+ }
+ status = (*process_db)(arg, fp, nfp);
+ if (!writeop || status != DLADM_STATUS_OK)
+ goto done;
+
+ /*
+ * Configuration files need to be owned by the 'dladm' user.
+ * If we are invoked by root, the file ownership needs to be fixed.
+ */
+ if (getuid() == 0 || geteuid() == 0) {
+ if (fchown(nfd, DLADM_DB_OWNER, DLADM_DB_GROUP) < 0) {
+ status = dladm_errno2status(errno);
+ goto done;
+ }
+ }
+
+ if (fflush(nfp) == EOF) {
+ status = dladm_errno2status(errno);
+ goto done;
+ }
+ (void) fclose(fp);
+ (void) fclose(nfp);
+
+ if (rename(newfile, file) < 0) {
+ (void) unlink(newfile);
+ i_dladm_unlock_db(lock, lock_fd);
+ return (dladm_errno2status(errno));
+ }
+
+ i_dladm_unlock_db(lock, lock_fd);
+ return (DLADM_STATUS_OK);
+
+done:
+ if (nfp != NULL) {
+ (void) fclose(nfp);
+ if (status != DLADM_STATUS_OK)
+ (void) unlink(newfile);
+ }
+ (void) fclose(fp);
+ i_dladm_unlock_db(lock, lock_fd);
+ return (status);
+}
+
+dladm_status_t
+dladm_set_rootdir(const char *rootdir)
+{
+ DIR *dp;
+
+ if (rootdir == NULL || *rootdir != '/' ||
+ (dp = opendir(rootdir)) == NULL)
+ return (DLADM_STATUS_BADARG);
+
+ (void) strncpy(dladm_rootdir, rootdir, MAXPATHLEN);
+ (void) closedir(dp);
+ return (DLADM_STATUS_OK);
+}
diff --git a/usr/src/lib/libdladm/common/libdladm.h b/usr/src/lib/libdladm/common/libdladm.h
index 64315da820..1cf3700fc6 100644
--- a/usr/src/lib/libdladm/common/libdladm.h
+++ b/usr/src/lib/libdladm/common/libdladm.h
@@ -36,19 +36,77 @@
extern "C" {
#endif
-typedef struct dladm_attr dladm_attr_t;
-
-struct dladm_attr {
+typedef struct dladm_attr {
char da_dev[MAXNAMELEN];
uint_t da_max_sdu;
uint16_t da_vid;
-};
+} dladm_attr_t;
+
+#define DLADM_STRSIZE 256
+#define DLADM_SECOBJ_VAL_MAX 256
+#define DLADM_PROP_VAL_MAX 256
+#define DLADM_OPT_TEMP 0x00000001
+#define DLADM_OPT_CREATE 0x00000002
+#define DLADM_OPT_PERSIST 0x00000004
+
+typedef enum {
+ DLADM_STATUS_OK = 0,
+ DLADM_STATUS_BADARG,
+ DLADM_STATUS_FAILED,
+ DLADM_STATUS_TOOSMALL,
+ DLADM_STATUS_NOTSUP,
+ DLADM_STATUS_NOTFOUND,
+ DLADM_STATUS_BADVAL,
+ DLADM_STATUS_NOMEM,
+ DLADM_STATUS_EXIST,
+ DLADM_STATUS_LINKINVAL,
+ DLADM_STATUS_PROPRDONLY,
+ DLADM_STATUS_BADVALCNT,
+ DLADM_STATUS_DBNOTFOUND,
+ DLADM_STATUS_DENIED,
+ DLADM_STATUS_IOERR
+} 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;
+
+#define DLADM_SECOBJ_CLASS_WEP 0
+typedef int dladm_secobj_class_t;
-extern int dladm_walk(void (*)(void *, const char *), void *);
-extern int dladm_walk_vlan(void (*)(void *,
- const char *), void *, const char *);
+typedef void (dladm_walkcb_t)(void *, const char *);
+
+extern int dladm_walk(dladm_walkcb_t *, void *);
+extern int dladm_walk_vlan(dladm_walkcb_t *, void *, const char *);
extern int dladm_info(const char *, dladm_attr_t *);
+extern dladm_status_t dladm_set_prop(const char *, const char *,
+ char **, uint_t, uint_t);
+extern dladm_status_t dladm_get_prop(const char *, 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_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 *,
+ uint8_t *, uint_t *, uint_t);
+extern dladm_status_t dladm_unset_secobj(const char *, uint_t);
+extern dladm_status_t dladm_walk_secobj(void *,
+ boolean_t (*)(void *, const char *), uint_t);
+
+extern const char *dladm_status2str(dladm_status_t, char *);
+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_secobj(void);
+extern dladm_status_t dladm_set_rootdir(const char *rootdir);
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/lib/libdladm/common/libdladm_impl.h b/usr/src/lib/libdladm/common/libdladm_impl.h
new file mode 100644
index 0000000000..c949219a5b
--- /dev/null
+++ b/usr/src/lib/libdladm/common/libdladm_impl.h
@@ -0,0 +1,51 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _LIBDLADM_IMPL_H
+#define _LIBDLADM_IMPL_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <libdladm.h>
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MAXLINELEN 1024
+#define BUFLEN(lim, ptr) (((lim) > (ptr)) ? ((lim) - (ptr)) : 0)
+
+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,
+ dladm_status_t (*)(void *, FILE *, FILE *),
+ void *, boolean_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBDLADM_IMPL_H */
diff --git a/usr/src/lib/libdladm/common/linkprop.c b/usr/src/lib/libdladm/common/linkprop.c
new file mode 100644
index 0000000000..8e1ef849e9
--- /dev/null
+++ b/usr/src/lib/libdladm/common/linkprop.c
@@ -0,0 +1,700 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdlib.h>
+#include <strings.h>
+#include <errno.h>
+#include <ctype.h>
+#include <sys/stat.h>
+#include <libwladm.h>
+#include <libdladm_impl.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 *);
+
+/*
+ * Convert a wladm_status_t to a dladm_status_t. This is used by wrappers
+ * to libwladm routines (e.g. dladm_set_prop()). Note that the mapping is
+ * not 1-1; whenever possible we try to look for an error code with a
+ * similar meaning. Error codes with no suitable counterpart in libdladm
+ * will be mapped to DLADM_STATUS_FAILED. Clients who require clearer error
+ * reporting should use libwladm directly.
+ */
+static dladm_status_t
+dladm_wladmstatus2status(wladm_status_t wstatus)
+{
+ switch (wstatus) {
+ case WLADM_STATUS_OK:
+ return (DLADM_STATUS_OK);
+ case WLADM_STATUS_FAILED:
+ return (DLADM_STATUS_FAILED);
+ case WLADM_STATUS_NOTSUP:
+ return (DLADM_STATUS_NOTSUP);
+ case WLADM_STATUS_BADARG:
+ return (DLADM_STATUS_BADARG);
+ case WLADM_STATUS_NOTFOUND:
+ return (DLADM_STATUS_NOTFOUND);
+ case WLADM_STATUS_BADVAL:
+ return (DLADM_STATUS_BADVAL);
+ case WLADM_STATUS_LINKINVAL:
+ return (DLADM_STATUS_LINKINVAL);
+ case WLADM_STATUS_NOMEM:
+ return (DLADM_STATUS_NOMEM);
+ case WLADM_STATUS_PROPRDONLY:
+ return (DLADM_STATUS_PROPRDONLY);
+ case WLADM_STATUS_TOOSMALL:
+ return (DLADM_STATUS_TOOSMALL);
+ case WLADM_STATUS_BADVALCNT:
+ return (DLADM_STATUS_BADVALCNT);
+ default:
+ return (DLADM_STATUS_FAILED);
+ }
+}
+
+dladm_status_t
+dladm_set_prop(const char *link, const char *prop_name, char **prop_val,
+ uint_t val_cnt, uint_t flags)
+{
+ dladm_status_t status = DLADM_STATUS_BADARG;
+
+ if (link == NULL || (prop_val == NULL && val_cnt > 0) ||
+ (prop_val != NULL && val_cnt == 0) || flags == 0)
+ return (DLADM_STATUS_BADARG);
+
+ if ((flags & DLADM_OPT_TEMP) != 0) {
+ if (wladm_is_valid(link)) {
+ status = dladm_wladmstatus2status(
+ wladm_set_prop(link, prop_name,
+ prop_val, val_cnt));
+ }
+ if (status != DLADM_STATUS_OK)
+ return (status);
+ }
+ if ((flags & DLADM_OPT_PERSIST) != 0) {
+ status = i_dladm_set_prop_db(link, prop_name,
+ prop_val, val_cnt);
+ }
+ return (status);
+}
+
+dladm_status_t
+dladm_walk_prop(const char *link, void *arg,
+ boolean_t (*func)(void *, const char *))
+{
+ if (link == NULL || func == NULL)
+ return (DLADM_STATUS_BADARG);
+
+ if (wladm_is_valid(link)) {
+ return (dladm_wladmstatus2status(
+ wladm_walk_prop(link, arg, func)));
+ }
+ return (DLADM_STATUS_BADARG);
+}
+
+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)
+{
+ if (link == NULL || prop_name == NULL || prop_val == NULL ||
+ val_cntp == NULL || *val_cntp == 0)
+ return (DLADM_STATUS_BADARG);
+
+ if (type == DLADM_PROP_VAL_PERSISTENT) {
+ return (i_dladm_get_prop_db(link, prop_name,
+ prop_val, val_cntp));
+ }
+
+ if (wladm_is_valid(link)) {
+ wladm_prop_type_t wtype;
+
+ switch (type) {
+ case DLADM_PROP_VAL_CURRENT:
+ wtype = WLADM_PROP_VAL_CURRENT;
+ break;
+ case DLADM_PROP_VAL_DEFAULT:
+ wtype = WLADM_PROP_VAL_DEFAULT;
+ break;
+ case DLADM_PROP_VAL_MODIFIABLE:
+ wtype = WLADM_PROP_VAL_MODIFIABLE;
+ break;
+ default:
+ return (DLADM_STATUS_BADARG);
+ }
+
+ return (dladm_wladmstatus2status(
+ wladm_get_prop(link, wtype, prop_name,
+ prop_val, val_cntp)));
+ }
+ return (DLADM_STATUS_BADARG);
+}
+
+/*
+ * 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;
+};
+
+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);
+ }
+ 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;
+
+ /*
+ * 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;
+
+ 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 (ptr > lim) {
+ *statusp = DLADM_STATUS_TOOSMALL;
+ return;
+ }
+ (void) snprintf(buf, MAXLINELEN, "%s\n", tmpbuf);
+}
+
+/*
+ * 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)
+{
+ 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);
+ }
+
+ /*
+ * Find the linkprop we want to change.
+ */
+ for (; lip != NULL; lip = lip->li_nextprop) {
+ if (strcmp(lip->li_name, lsp->ls_propname) == 0)
+ break;
+
+ lastp = lip;
+ }
+
+ 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 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;
+ }
+
+ /*
+ * 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;
+ }
+ (*lvpp)->lv_name = lsp->ls_propval[i];
+ (*lvpp)->lv_nextval = NULL;
+ lvpp = &(*lvpp)->lv_nextval;
+ }
+
+ 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);
+}
+
+/*
+ * 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.
+ */
+/* ARGSUSED */
+static boolean_t
+process_linkprop_get(linkprop_db_state_t *lsp, char *buf,
+ linkprop_info_t *listp, dladm_status_t *statusp)
+{
+ linkprop_info_t *lip = listp;
+ linkprop_val_t *lvp;
+ uint_t valcnt = 0;
+
+ /*
+ * 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);
+ }
+
+ for (lvp = lip->li_val; lvp != NULL; lvp = lvp->lv_nextval) {
+ (void) strncpy(lsp->ls_propval[valcnt], lvp->lv_name,
+ DLADM_PROP_VAL_MAX);
+
+ if (++valcnt >= *lsp->ls_valcntp && lvp->lv_nextval != NULL) {
+ *statusp = DLADM_STATUS_TOOSMALL;
+ return (B_FALSE);
+ }
+ }
+ /*
+ * 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);
+}
+
+/*
+ * 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.
+ */
+/* 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 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++);
+
+ 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);
+
+ /*
+ * 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);
+}
+
+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 == ';');
+
+ /*
+ * Move to the next character if there is no match and
+ * if we have not reached the last character.
+ */
+ if (!match && i != len - 1)
+ continue;
+
+ if (match) {
+ /*
+ * Nul-terminate the string pointed to by 'curr'.
+ */
+ buf[i] = '\0';
+ if (*curr == '\0')
+ goto fail;
+ }
+
+ 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;
+ }
+ 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);
+}
+
+static boolean_t
+process_linkprop_line(linkprop_db_state_t *lsp, char *buf,
+ dladm_status_t *statusp)
+{
+ linkprop_info_t *lip = NULL;
+ int i, len, llen;
+ char *str, *lasts;
+ boolean_t cont, nolink = B_FALSE;
+
+ /*
+ * Skip leading spaces, blank lines, and comments.
+ */
+ len = strlen(buf);
+ for (i = 0; i < len; i++) {
+ if (!isspace(buf[i]))
+ 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 (parse_linkprops(str, &lip) < 0)
+ goto fail;
+
+ cont = (*lsp->ls_op)(lsp, buf, lip, statusp);
+ free_linkprops(lip);
+ if (nolink)
+ lsp->ls_link = NULL;
+ return (cont);
+
+fail:
+ free_linkprops(lip);
+ if (nolink)
+ lsp->ls_link = NULL;
+
+ /*
+ * Delete corrupted line.
+ */
+ buf[0] = '\0';
+ return (B_TRUE);
+}
+
+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;
+
+ /*
+ * 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);
+
+ if (nfp != NULL && buf[0] != '\0' && fputs(buf, nfp) == EOF) {
+ status = dladm_errno2status(errno);
+ break;
+ }
+ }
+
+ if (status != DLADM_STATUS_OK || !cont)
+ 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);
+ }
+
+ if (lsp->ls_op == process_linkprop_get)
+ status = DLADM_STATUS_NOTFOUND;
+
+ return (status);
+}
+
+#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)))
+
+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;
+
+ 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;
+
+ return (LINKPROP_RW_DB(&state, B_TRUE));
+}
+
+static dladm_status_t
+i_dladm_get_prop_db(const char *link, const char *prop_name,
+ char **prop_val, uint_t *val_cntp)
+{
+ 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));
+}
+
+dladm_status_t
+dladm_init_linkprop(void)
+{
+ 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));
+}
diff --git a/usr/src/lib/libdladm/common/mapfile-vers b/usr/src/lib/libdladm/common/mapfile-vers
index 5e0f599741..2af8201536 100644
--- a/usr/src/lib/libdladm/common/mapfile-vers
+++ b/usr/src/lib/libdladm/common/mapfile-vers
@@ -30,6 +30,20 @@ SUNWprivate_1.1 {
dladm_info;
dladm_walk;
dladm_walk_vlan;
+ dladm_get_prop;
+ dladm_set_prop;
+ dladm_walk_prop;
+ dladm_get_secobj;
+ dladm_set_secobj;
+ dladm_unset_secobj;
+ dladm_walk_secobj;
+ dladm_status2str;
+ dladm_secobjclass2str;
+ dladm_str2secobjclass;
+ dladm_init_linkprop;
+ dladm_init_secobj;
+ dladm_set_rootdir;
+
local:
*;
};
diff --git a/usr/src/lib/libdladm/common/secobj.c b/usr/src/lib/libdladm/common/secobj.c
new file mode 100644
index 0000000000..3f122ca347
--- /dev/null
+++ b/usr/src/lib/libdladm/common/secobj.c
@@ -0,0 +1,634 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <errno.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/dld.h>
+#include <libinetutil.h>
+#include <libdladm_impl.h>
+
+static dladm_status_t i_dladm_set_secobj_db(const char *,
+ dladm_secobj_class_t, uint8_t *, uint_t);
+static dladm_status_t i_dladm_get_secobj_db(const char *,
+ dladm_secobj_class_t *, uint8_t *, uint_t *);
+static dladm_status_t i_dladm_unset_secobj_db(const char *);
+static dladm_status_t i_dladm_walk_secobj_db(void *,
+ boolean_t (*)(void *, const char *));
+
+typedef struct secobj_class_info {
+ const char *sc_name;
+ dld_secobj_class_t sc_dldclass;
+} secobj_class_info_t;
+
+static secobj_class_info_t secobj_class_table[] = {
+ {"wep", DLD_SECOBJ_CLASS_WEP}
+};
+
+#define NSECOBJCLASS \
+ (sizeof (secobj_class_table) / sizeof (secobj_class_info_t))
+
+static boolean_t
+dladm_check_secobjclass(dladm_secobj_class_t class)
+{
+ return (class >= 0 && class < NSECOBJCLASS);
+}
+
+dladm_status_t
+dladm_str2secobjclass(const char *str, dladm_secobj_class_t *class)
+{
+ int i;
+ secobj_class_info_t *sp;
+
+ for (i = 0; i < NSECOBJCLASS; i++) {
+ sp = &secobj_class_table[i];
+ if (strcasecmp(str, sp->sc_name) == 0) {
+ *class = i;
+ return (DLADM_STATUS_OK);
+ }
+ }
+ return (DLADM_STATUS_BADARG);
+}
+
+const char *
+dladm_secobjclass2str(dladm_secobj_class_t class, char *buf)
+{
+ const char *s;
+
+ if (!dladm_check_secobjclass(class))
+ s = "";
+ else
+ s = secobj_class_table[class].sc_name;
+
+ (void) snprintf(buf, DLADM_STRSIZE, "%s", s);
+ return (buf);
+}
+
+static boolean_t
+dladm_convert_secobjclass(dladm_secobj_class_t class,
+ dld_secobj_class_t *dldclass)
+{
+ if (!dladm_check_secobjclass(class))
+ return (B_FALSE);
+
+ *dldclass = secobj_class_table[class].sc_dldclass;
+ return (B_TRUE);
+}
+
+static boolean_t
+dladm_convert_dldsecobjclass(dld_secobj_class_t dldclass,
+ dladm_secobj_class_t *class)
+{
+ int i;
+ secobj_class_info_t *sp;
+
+ for (i = 0; i < NSECOBJCLASS; i++) {
+ sp = &secobj_class_table[i];
+ if (dldclass == sp->sc_dldclass) {
+ *class = i;
+ return (B_TRUE);
+ }
+ }
+ return (B_FALSE);
+}
+
+dladm_status_t
+dladm_set_secobj(const char *obj_name, dladm_secobj_class_t class,
+ uint8_t *obj_val, uint_t obj_len, uint_t flags)
+{
+ int fd;
+ dladm_status_t status = DLADM_STATUS_OK;
+ dld_ioc_secobj_set_t secobj_set;
+ dld_secobj_t *objp;
+
+ if (!dladm_check_secobjclass(class) || flags == 0 ||
+ obj_name == NULL || strlen(obj_name) > DLD_SECOBJ_NAME_MAX ||
+ obj_val == NULL || obj_len == 0 || obj_len > DLD_SECOBJ_VAL_MAX)
+ return (DLADM_STATUS_BADARG);
+
+ if ((flags & DLADM_OPT_TEMP) == 0)
+ goto persist;
+
+ bzero(&secobj_set, sizeof (secobj_set));
+ objp = &secobj_set.ss_obj;
+ if (!dladm_convert_secobjclass(class, &objp->so_class))
+ return (DLADM_STATUS_BADARG);
+
+ (void) strlcpy(objp->so_name, obj_name, DLD_SECOBJ_NAME_MAX);
+ bcopy(obj_val, objp->so_val, obj_len);
+ objp->so_len = obj_len;
+
+ if ((flags & DLADM_OPT_CREATE) != 0)
+ secobj_set.ss_flags = DLD_SECOBJ_OPT_CREATE;
+
+ if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
+ return (dladm_errno2status(errno));
+
+ if (i_dladm_ioctl(fd, DLDIOCSECOBJSET, &secobj_set,
+ sizeof (secobj_set)) < 0)
+ status = dladm_errno2status(errno);
+
+ (void) close(fd);
+ if (status != DLADM_STATUS_OK)
+ return (status);
+
+persist:
+ if ((flags & DLADM_OPT_PERSIST) != 0) {
+ status = i_dladm_set_secobj_db(obj_name, class,
+ obj_val, obj_len);
+ }
+ return (status);
+}
+
+dladm_status_t
+dladm_get_secobj(const char *obj_name, dladm_secobj_class_t *classp,
+ uint8_t *obj_val, uint_t *obj_lenp, uint_t flags)
+{
+ int fd;
+ dladm_status_t status = DLADM_STATUS_OK;
+ dld_ioc_secobj_get_t secobj_get;
+ dld_secobj_t *objp;
+
+ if (obj_name == NULL || strlen(obj_name) > DLD_SECOBJ_NAME_MAX ||
+ obj_val == NULL || obj_lenp == NULL || *obj_lenp == 0 ||
+ *obj_lenp > DLD_SECOBJ_VAL_MAX)
+ return (DLADM_STATUS_BADARG);
+
+ if ((flags & DLADM_OPT_PERSIST) != 0) {
+ return (i_dladm_get_secobj_db(obj_name, classp,
+ obj_val, obj_lenp));
+ }
+
+ bzero(&secobj_get, sizeof (secobj_get));
+ objp = &secobj_get.sg_obj;
+ (void) strlcpy(objp->so_name, obj_name, DLD_SECOBJ_NAME_MAX);
+
+ if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
+ return (dladm_errno2status(errno));
+
+ if (i_dladm_ioctl(fd, DLDIOCSECOBJGET, &secobj_get,
+ sizeof (secobj_get)) < 0)
+ status = dladm_errno2status(errno);
+
+ (void) close(fd);
+ if (objp->so_len > *obj_lenp)
+ return (DLADM_STATUS_TOOSMALL);
+
+ if (!dladm_convert_dldsecobjclass(objp->so_class, classp))
+ return (DLADM_STATUS_FAILED);
+
+ *obj_lenp = objp->so_len;
+ bcopy(objp->so_val, obj_val, *obj_lenp);
+ return (status);
+}
+
+dladm_status_t
+dladm_unset_secobj(const char *obj_name, uint_t flags)
+{
+ int fd;
+ dladm_status_t status = DLADM_STATUS_OK;
+ dld_ioc_secobj_unset_t secobj_unset;
+
+ if (obj_name == NULL || strlen(obj_name) > DLD_SECOBJ_NAME_MAX ||
+ flags == 0)
+ return (DLADM_STATUS_BADARG);
+
+ if ((flags & DLADM_OPT_TEMP) == 0)
+ goto persist;
+
+ bzero(&secobj_unset, sizeof (secobj_unset));
+ (void) strlcpy(secobj_unset.su_name, obj_name, DLD_SECOBJ_NAME_MAX);
+ if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
+ return (dladm_errno2status(errno));
+
+ if (i_dladm_ioctl(fd, DLDIOCSECOBJUNSET, &secobj_unset,
+ sizeof (secobj_unset)) < 0)
+ status = dladm_errno2status(errno);
+
+ (void) close(fd);
+ if (status != DLADM_STATUS_OK)
+ return (status);
+
+persist:
+ if ((flags & DLADM_OPT_PERSIST) != 0)
+ status = i_dladm_unset_secobj_db(obj_name);
+
+ return (status);
+}
+
+#define SECOBJ_BUFSZ 65536
+dladm_status_t
+dladm_walk_secobj(void *arg, boolean_t (*func)(void *, const char *),
+ uint_t flags)
+{
+ int fd = -1;
+ dladm_status_t status = DLADM_STATUS_OK;
+ dld_ioc_secobj_get_t *secobj_getp;
+ dld_secobj_t *objp;
+
+ if ((flags & DLADM_OPT_PERSIST) != 0)
+ return (i_dladm_walk_secobj_db(arg, func));
+
+ secobj_getp = calloc(1, SECOBJ_BUFSZ);
+ if (secobj_getp == NULL)
+ return (DLADM_STATUS_NOMEM);
+
+ if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) {
+ status = dladm_errno2status(errno);
+ goto done;
+ }
+ if (i_dladm_ioctl(fd, DLDIOCSECOBJGET, secobj_getp,
+ SECOBJ_BUFSZ) < 0) {
+ status = dladm_errno2status(errno);
+ goto done;
+ }
+
+ objp = (dld_secobj_t *)(secobj_getp + 1);
+ while (secobj_getp->sg_count > 0) {
+ if (!func(arg, objp->so_name))
+ goto done;
+ secobj_getp->sg_count--;
+ objp++;
+ }
+done:
+ (void) close(fd);
+ free(secobj_getp);
+ return (status);
+}
+
+/*
+ * Data structures used for implementing persistent secure objects
+ */
+typedef struct secobj_info {
+ const char *si_name;
+ dladm_secobj_class_t *si_classp;
+ uint8_t *si_val;
+ uint_t *si_lenp;
+} secobj_info_t;
+
+typedef struct secobj_name {
+ char *sn_name;
+ struct secobj_name *sn_next;
+} secobj_name_t;
+
+typedef struct secobj_db_state secobj_db_state_t;
+
+typedef boolean_t (*secobj_db_op_t)(struct secobj_db_state *, char *,
+ secobj_info_t *, dladm_status_t *);
+
+struct secobj_db_state {
+ secobj_db_op_t ss_op;
+ secobj_info_t ss_info;
+ secobj_name_t **ss_namelist;
+};
+
+/*
+ * Update or generate a secobj entry using the info in ssp->ss_info.
+ */
+/* ARGSUSED */
+static boolean_t
+process_secobj_set(secobj_db_state_t *ssp, char *buf, secobj_info_t *sip,
+ dladm_status_t *statusp)
+{
+ char tmpbuf[MAXLINELEN];
+ char classbuf[DLADM_STRSIZE];
+ char *ptr = tmpbuf, *lim = tmpbuf + MAXLINELEN;
+ int i;
+
+ sip = &ssp->ss_info;
+
+ ptr += snprintf(ptr, BUFLEN(lim, ptr), "%s\t", sip->si_name);
+ ptr += snprintf(ptr, BUFLEN(lim, ptr), "%s\t",
+ dladm_secobjclass2str(*sip->si_classp, classbuf));
+
+ ptr += snprintf(ptr, BUFLEN(lim, ptr), "0x");
+ for (i = 0; i < *sip->si_lenp; i++) {
+ ptr += snprintf(ptr, BUFLEN(lim, ptr), "%02x",
+ sip->si_val[i] & 0xff);
+ }
+ if (ptr > lim) {
+ *statusp = DLADM_STATUS_TOOSMALL;
+ return (B_FALSE);
+ }
+ (void) snprintf(buf, MAXLINELEN, "%s\n", tmpbuf);
+ return (B_FALSE);
+}
+
+/* ARGSUSED */
+static boolean_t
+process_secobj_get(secobj_db_state_t *ssp, char *buf, secobj_info_t *sip,
+ dladm_status_t *statusp)
+{
+ if (*sip->si_lenp > *ssp->ss_info.si_lenp) {
+ *statusp = DLADM_STATUS_TOOSMALL;
+ return (B_FALSE);
+ }
+ bcopy(sip->si_val, ssp->ss_info.si_val, *sip->si_lenp);
+ *ssp->ss_info.si_lenp = *sip->si_lenp;
+ *ssp->ss_info.si_classp = *sip->si_classp;
+ return (B_FALSE);
+}
+
+/* ARGSUSED */
+static boolean_t
+process_secobj_unset(secobj_db_state_t *ssp, char *buf, secobj_info_t *sip,
+ dladm_status_t *statusp)
+{
+ /*
+ * Delete line.
+ */
+ buf[0] = '\0';
+ return (B_FALSE);
+}
+
+/* ARGSUSED */
+static boolean_t
+process_secobj_walk(secobj_db_state_t *ssp, char *buf, secobj_info_t *sip,
+ dladm_status_t *statusp)
+{
+ secobj_name_t *snp;
+
+ if ((snp = malloc(sizeof (*snp))) == NULL)
+ return (B_TRUE);
+
+ if ((snp->sn_name = strdup(sip->si_name)) == NULL) {
+ free(snp);
+ return (B_TRUE);
+ }
+
+ snp->sn_next = NULL;
+ *ssp->ss_namelist = snp;
+ ssp->ss_namelist = &snp->sn_next;
+ return (B_TRUE);
+}
+
+/* ARGSUSED */
+static boolean_t
+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);
+ return (B_TRUE);
+}
+
+static int
+parse_secobj_val(char *buf, secobj_info_t *sip)
+{
+ if (strncmp(buf, "0x", 2) != 0)
+ return (EINVAL);
+
+ return (hexascii_to_octet(buf + 2, strlen(buf) - 2,
+ sip->si_val, sip->si_lenp));
+}
+
+static boolean_t
+process_secobj_line(secobj_db_state_t *ssp, char *buf,
+ dladm_status_t *statusp)
+{
+ secobj_info_t sinfo;
+ dladm_secobj_class_t class;
+ uint8_t val[DLADM_SECOBJ_VAL_MAX];
+ uint_t vlen;
+ int i, len, nlen;
+ char *str, *lasts;
+
+ /*
+ * Skip leading spaces, blank lines, and comments.
+ */
+ len = strlen(buf);
+ for (i = 0; i < len; i++) {
+ if (!isspace(buf[i]))
+ break;
+ }
+ if (i == len || buf[i] == '#')
+ return (B_TRUE);
+
+ str = buf + i;
+ if (ssp->ss_info.si_name != NULL) {
+ /*
+ * Skip objects we're not interested in.
+ */
+ nlen = strlen(ssp->ss_info.si_name);
+ if (strncmp(str, ssp->ss_info.si_name, nlen) != 0 ||
+ !isspace(str[nlen]))
+ return (B_TRUE);
+
+ sinfo.si_name = ssp->ss_info.si_name;
+ } else {
+ /*
+ * If an object is not specified, find the object name
+ * and assign it to sinfo.si_name.
+ */
+ if (strtok_r(str, " \n\t", &lasts) == NULL)
+ goto fail;
+
+ nlen = strlen(str);
+ sinfo.si_name = str;
+ }
+ str += nlen + 1;
+ if (str >= buf + len)
+ goto fail;
+
+ /*
+ * Find the class name.
+ */
+ if ((str = strtok_r(str, " \n\t", &lasts)) == NULL)
+ goto fail;
+
+ *statusp = dladm_str2secobjclass(str, &class);
+ if (*statusp != DLADM_STATUS_OK)
+ goto fail;
+
+ /*
+ * Find the object value.
+ */
+ if ((str = strtok_r(NULL, " \n\t", &lasts)) == NULL)
+ goto fail;
+
+ vlen = DLADM_SECOBJ_VAL_MAX;
+ sinfo.si_classp = &class;
+ sinfo.si_val = val;
+ sinfo.si_lenp = &vlen;
+ if (parse_secobj_val(str, &sinfo) != 0)
+ goto fail;
+
+ return ((*ssp->ss_op)(ssp, buf, &sinfo, statusp));
+
+fail:
+ /*
+ * Delete corrupted line.
+ */
+ buf[0] = '\0';
+ return (B_TRUE);
+}
+
+static dladm_status_t
+process_secobj_db(void *arg, FILE *fp, FILE *nfp)
+{
+ secobj_db_state_t *ssp = arg;
+ dladm_status_t status = DLADM_STATUS_OK;
+ char buf[MAXLINELEN];
+ boolean_t cont = B_TRUE;
+
+ /*
+ * This loop processes each line of the configuration file.
+ * buf can potentially be modified by process_secobj_line().
+ * If this is a write operation and buf is not truncated, buf will
+ * be written to disk. process_secobj_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_secobj_line(ssp, buf, &status);
+
+ if (nfp != NULL && buf[0] != '\0' && fputs(buf, nfp) == EOF) {
+ status = dladm_errno2status(errno);
+ break;
+ }
+ }
+ if (status != DLADM_STATUS_OK || !cont)
+ return (status);
+
+ if (ssp->ss_op == process_secobj_set) {
+ /*
+ * If the specified object is not found above, we add the
+ * object to the configuration file.
+ */
+ (void) (*ssp->ss_op)(ssp, buf, NULL, &status);
+ if (status == DLADM_STATUS_OK && fputs(buf, nfp) == EOF)
+ status = dladm_errno2status(errno);
+ }
+
+ if (ssp->ss_op == process_secobj_unset ||
+ ssp->ss_op == process_secobj_get)
+ status = DLADM_STATUS_NOTFOUND;
+
+ return (status);
+}
+
+#define SECOBJ_RW_DB(statep, writeop) \
+ (i_dladm_rw_db("/etc/dladm/secobj.conf", S_IRUSR | S_IWUSR, \
+ process_secobj_db, (statep), (writeop)))
+
+static dladm_status_t
+i_dladm_set_secobj_db(const char *obj_name, dladm_secobj_class_t class,
+ uint8_t *obj_val, uint_t obj_len)
+{
+ secobj_db_state_t state;
+
+ state.ss_op = process_secobj_set;
+ state.ss_info.si_name = obj_name;
+ state.ss_info.si_classp = &class;
+ state.ss_info.si_val = obj_val;
+ state.ss_info.si_lenp = &obj_len;
+ state.ss_namelist = NULL;
+
+ return (SECOBJ_RW_DB(&state, B_TRUE));
+}
+
+static dladm_status_t
+i_dladm_get_secobj_db(const char *obj_name, dladm_secobj_class_t *classp,
+ uint8_t *obj_val, uint_t *obj_lenp)
+{
+ secobj_db_state_t state;
+
+ state.ss_op = process_secobj_get;
+ state.ss_info.si_name = obj_name;
+ state.ss_info.si_classp = classp;
+ state.ss_info.si_val = obj_val;
+ state.ss_info.si_lenp = obj_lenp;
+ state.ss_namelist = NULL;
+
+ return (SECOBJ_RW_DB(&state, B_FALSE));
+}
+
+static dladm_status_t
+i_dladm_unset_secobj_db(const char *obj_name)
+{
+ secobj_db_state_t state;
+
+ state.ss_op = process_secobj_unset;
+ state.ss_info.si_name = obj_name;
+ state.ss_info.si_classp = NULL;
+ state.ss_info.si_val = NULL;
+ state.ss_info.si_lenp = NULL;
+ state.ss_namelist = NULL;
+
+ return (SECOBJ_RW_DB(&state, B_TRUE));
+}
+
+static dladm_status_t
+i_dladm_walk_secobj_db(void *arg, boolean_t (*func)(void *, const char *))
+{
+ secobj_db_state_t state;
+ secobj_name_t *snp = NULL, *fsnp;
+ dladm_status_t status;
+ boolean_t cont = B_TRUE;
+
+ state.ss_op = process_secobj_walk;
+ state.ss_info.si_name = NULL;
+ state.ss_info.si_classp = NULL;
+ state.ss_info.si_val = NULL;
+ state.ss_info.si_lenp = NULL;
+ state.ss_namelist = &snp;
+
+ status = SECOBJ_RW_DB(&state, B_FALSE);
+ if (status != DLADM_STATUS_OK)
+ return (status);
+
+ while (snp != NULL) {
+ fsnp = snp;
+ snp = snp->sn_next;
+ if (cont)
+ cont = func(arg, fsnp->sn_name);
+ free(fsnp->sn_name);
+ free(fsnp);
+ }
+ return (status);
+}
+
+dladm_status_t
+dladm_init_secobj(void)
+{
+ secobj_db_state_t state;
+
+ state.ss_op = process_secobj_init;
+ state.ss_info.si_name = NULL;
+ state.ss_info.si_classp = NULL;
+ state.ss_info.si_val = NULL;
+ state.ss_info.si_lenp = NULL;
+ state.ss_namelist = NULL;
+
+ return (SECOBJ_RW_DB(&state, B_FALSE));
+}
diff --git a/usr/src/lib/liblaadm/common/liblaadm.c b/usr/src/lib/liblaadm/common/liblaadm.c
index 0beeee27da..3b23a5999d 100644
--- a/usr/src/lib/liblaadm/common/liblaadm.c
+++ b/usr/src/lib/liblaadm/common/liblaadm.c
@@ -52,31 +52,31 @@
* <db-file> ::= <groups>*
* <group> ::= <key> <sep> <policy> <sep> <nports> <sep> <ports> <sep>
* <mac> <sep> <lacp-mode> <sep> <lacp-timer>
- * <sep> ::= ' ' | '\t'
- * <key> ::= <number>
+ * <sep> ::= ' ' | '\t'
+ * <key> ::= <number>
* <nports> ::= <number>
* <ports> ::= <port> <m-port>*
* <m-port> ::= ',' <port>
- * <port> ::= <devname>
+ * <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> ::= 'auto' | <mac-addr>
* <mac-addr> ::= <hex> ':' <hex> ':' <hex> ':' <hex> ':' <hex> ':' <hex>
* <lacp-mode> ::= 'off' | 'active' | 'passive'
* <lacp-timer> ::= 'short' | 'long'
*/
#define LAADM_DEV "/devices/pseudo/aggr@0:" AGGR_DEVNAME_CTL
-#define LAADM_DB "/etc/aggregation.conf"
-#define LAADM_DB_TMP "/etc/aggregation.conf.new"
+#define LAADM_DB "/etc/dladm/aggregation.conf"
+#define LAADM_DB_TMP "/etc/dladm/aggregation.conf.new"
#define LAADM_DB_LOCK "/tmp/aggregation.conf.lock"
#define LAADM_DB_PERMS S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
-#define LAADM_DB_OWNER 0
-#define LAADM_DB_GROUP 1
+#define LAADM_DB_OWNER 15 /* "dladm" UID */
+#define LAADM_DB_GROUP 3 /* "sys" GID */
/*
* The largest configurable aggregation key. Because by default the key is
@@ -866,11 +866,13 @@ i_laadm_walk_rw_db(int (*fn)(void *, laadm_grp_attr_db_t *),
attr.lt_ports = NULL;
}
- if (fchmod(nfd, LAADM_DB_PERMS) == -1)
- goto failed;
+ if (getuid() == 0 || geteuid() == 0) {
+ if (fchmod(nfd, LAADM_DB_PERMS) == -1)
+ goto failed;
- if (fchown(nfd, LAADM_DB_OWNER, LAADM_DB_GROUP) == -1)
- goto failed;
+ if (fchown(nfd, LAADM_DB_OWNER, LAADM_DB_GROUP) == -1)
+ goto failed;
+ }
if (fflush(nfp) == EOF)
goto failed;
diff --git a/usr/src/lib/libsecdb/auth_attr.txt b/usr/src/lib/libsecdb/auth_attr.txt
index 085d3eb463..fd6d0219ce 100644
--- a/usr/src/lib/libsecdb/auth_attr.txt
+++ b/usr/src/lib/libsecdb/auth_attr.txt
@@ -62,6 +62,7 @@ solaris.mail.:::Mail::help=MailHeader.html
solaris.mail.mailq:::Mail Queue::help=MailQueue.html
#
solaris.network.:::Network::help=NetworkHeader.html
+solaris.network.link.security:::Link Security::help=LinkSecurity.html
solaris.network.wifi.config:::Wifi Config::help=WifiConfig.html
solaris.network.wifi.wep:::Wifi Wep::help=WifiWep.html
#
diff --git a/usr/src/lib/libsecdb/exec_attr.txt b/usr/src/lib/libsecdb/exec_attr.txt
index a1165b85d9..8a037f4bd8 100644
--- a/usr/src/lib/libsecdb/exec_attr.txt
+++ b/usr/src/lib/libsecdb/exec_attr.txt
@@ -178,7 +178,8 @@ Network Management:solaris:cmd:::/sbin/ifconfig:uid=0
Network Management:solaris:cmd:::/sbin/route:privs=sys_net_config
Network Management:solaris:cmd:::/sbin/routeadm:euid=0;\
privs=proc_chroot,proc_owner,sys_net_config
-Network Management:solaris:cmd:::/sbin/dladm:privs=sys_net_config
+Network Management:solaris:cmd:::/sbin/dladm:euid=dladm;egid=sys;\
+ privs=sys_net_config,net_rawaccess
Network Management:suser:cmd:::/usr/bin/netstat:uid=0
Network Management:suser:cmd:::/usr/bin/rup:euid=0
Network Management:suser:cmd:::/usr/bin/ruptime:euid=0
@@ -191,6 +192,8 @@ Network Management:suser:cmd:::/usr/sbin/rndc:privs=file_dac_read
Network Management:suser:cmd:::/usr/sbin/route:uid=0
Network Management:suser:cmd:::/usr/sbin/snoop:uid=0
Network Management:suser:cmd:::/usr/sbin/spray:euid=0
+Network Link Security:solaris:cmd:::/sbin/dladm:euid=dladm;egid=sys;\
+ privs=sys_net_config,net_rawaccess
Network Security:solaris:cmd:::/usr/lib/inet/certdb:privs=sys_net_config
Network Security:solaris:cmd:::/usr/lib/inet/certlocal:privs=sys_net_config
Network Security:solaris:cmd:::/usr/lib/inet/certrldb:privs=sys_net_config
diff --git a/usr/src/lib/libsecdb/help/auths/LinkSecurity.html b/usr/src/lib/libsecdb/help/auths/LinkSecurity.html
new file mode 100644
index 0000000000..161a38d799
--- /dev/null
+++ b/usr/src/lib/libsecdb/help/auths/LinkSecurity.html
@@ -0,0 +1,45 @@
+<HTML>
+
+<!--
+ Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ Use is subject to license terms.
+
+ 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
+-->
+<!-- SCCS keyword
+#pragma ident "%Z%%M% %I% %E% SMI"
+-->
+
+<HEAD>
+<!--
+META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"
+-->
+<!--
+META NAME="GENERATOR" CONTENT="Mozilla/4.02 [en] (X11; U; SunOS 5.6 sun4u) [Netscape]"
+-->
+</HEAD>
+<BODY>
+When Link Security is in the Authorizations Included column, it grants the authorization
+to create or remove secure objects using dladm.
+<p>
+If Link Security is grayed, then you are not entitled to Add or Remove this authorization.
+<BR>&nbsp;
+</BODY>
+</HTML>
diff --git a/usr/src/lib/libsecdb/help/auths/Makefile b/usr/src/lib/libsecdb/help/auths/Makefile
index 70e85c8426..3f063bc0d3 100644
--- a/usr/src/lib/libsecdb/help/auths/Makefile
+++ b/usr/src/lib/libsecdb/help/auths/Makefile
@@ -84,7 +84,8 @@ HTMLENTS = \
SmfValueRouting.html \
NetworkHeader.html \
WifiConfig.html \
- WifiWep.html
+ WifiWep.html \
+ LinkSecurity.html
HELPDIR=$(ROOT)/usr/lib/help
AUTHDIR=$(HELPDIR)/auths
diff --git a/usr/src/lib/libsecdb/help/profiles/Makefile b/usr/src/lib/libsecdb/help/profiles/Makefile
index 2b1313a4af..fb9b645a7b 100644
--- a/usr/src/lib/libsecdb/help/profiles/Makefile
+++ b/usr/src/lib/libsecdb/help/profiles/Makefile
@@ -2,9 +2,8 @@
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License"). You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or http://www.opensolaris.org/os/licensing.
@@ -19,7 +18,7 @@
#
# CDDL HEADER END
#
-# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
#ident "%Z%%M% %I% %E% SMI"
@@ -56,6 +55,7 @@ HTMLENTS = \
RtNetSecure.html \
RtNetWifiMngmnt.html \
RtNetWifiSecure.html \
+ RtNetLinkSecure.html \
RtObAccessMngmnt.html \
RtPrntAdmin.html \
RtProcManagement.html \
diff --git a/usr/src/lib/libsecdb/help/profiles/RtNetLinkSecure.html b/usr/src/lib/libsecdb/help/profiles/RtNetLinkSecure.html
new file mode 100644
index 0000000000..7fcad1df97
--- /dev/null
+++ b/usr/src/lib/libsecdb/help/profiles/RtNetLinkSecure.html
@@ -0,0 +1,39 @@
+<HTML>
+<!--
+ 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 2006 Sun Microsystems, Inc. All rights reserved.
+-- Use is subject to license terms.
+-->
+<HEAD>
+ <TITLE> </TITLE>
+
+
+</HEAD>
+<BODY>
+<!-- ident "%Z%%M% %I% %E% SMI" -->
+
+When Network Link Security is in the Rights Included column, it grants the right to
+manage network link security.
+<p>
+If Network Link Security is grayed, then you are not entitled to Add or Remove this right.
+<p>
+</BODY>
+</HTML>
diff --git a/usr/src/lib/libsecdb/prof_attr.txt b/usr/src/lib/libsecdb/prof_attr.txt
index 70016e8cd2..6901a2b673 100644
--- a/usr/src/lib/libsecdb/prof_attr.txt
+++ b/usr/src/lib/libsecdb/prof_attr.txt
@@ -50,9 +50,10 @@ Maintenance and Repair:::Maintain and repair a system:auths=solaris.smf.manage.s
Media Backup:::Backup files and file systems:help=RtMediaBkup.html
Media Restore:::Restore files and file systems from backups:help=RtMediaRestore.html
Network Management:::Manage the host and network configuration:auths=solaris.smf.manage.name-service-cache,solaris.smf.manage.bind,solaris.smf.value.routing,solaris.smf.manage.routing;profiles=Network Wifi Management;help=RtNetMngmnt.html
-Network Security:::Manage network and host security:auths=solaris.smf.manage.ssh;profiles=Network Wifi Security;help=RtNetSecure.html
+Network Security:::Manage network and host security:auths=solaris.smf.manage.ssh;profiles=Network Wifi Security,Network Link Security;help=RtNetSecure.html
Network Wifi Management:::Manage wifi network configuration:auths=solaris.network.wifi.config;help=RtNetWifiMngmnt.html
Network Wifi Security:::Manage wifi network security:auths=solaris.network.wifi.wep;help=RtNetWifiSecure.html
+Network Link Security:::Manage network link security:auths=solaris.network.link.security;help=RtNetLinkSecure.html
Name Service Management:::Non-security name service scripts/commands:help=RtNameServiceAdmin.html
Name Service Security:::Security related name service scripts/commands:help=RtNameServiceSecure.html
Object Access Management:::Change ownership and permission on files:help=RtObAccessMngmnt.html
diff --git a/usr/src/lib/libwladm/Makefile b/usr/src/lib/libwladm/Makefile
new file mode 100644
index 0000000000..f537457d54
--- /dev/null
+++ b/usr/src/lib/libwladm/Makefile
@@ -0,0 +1,62 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include $(SRC)/lib/Makefile.lib
+
+HDRS = libwladm.h libwladm_impl.h
+HDRDIR = common
+
+SUBDIRS = $(MACH)
+
+POFILE = libwladm.po
+MSGFILES = common/libwladm.c
+
+all := TARGET = all
+clean := TARGET = clean
+clobber := TARGET = clobber
+install := TARGET = install
+lint := TARGET = lint
+
+.KEEP_STATE:
+
+all clean clobber install lint: $(SUBDIRS)
+
+install_h: $(ROOTHDRS)
+
+check: $(CHECKHDRS)
+
+$(POFILE): pofile_MSGFILES
+
+_msg: $(MSGDOMAINPOFILE)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include $(SRC)/Makefile.msg.targ
+include $(SRC)/lib/Makefile.targ
diff --git a/usr/src/lib/libwladm/Makefile.com b/usr/src/lib/libwladm/Makefile.com
new file mode 100644
index 0000000000..1f8c9760df
--- /dev/null
+++ b/usr/src/lib/libwladm/Makefile.com
@@ -0,0 +1,51 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+LIBRARY = libwladm.a
+VERS = .1
+OBJECTS = libwladm.o
+
+include ../../Makefile.lib
+# install this library in the root filesystem
+include ../../Makefile.rootfs
+
+LIBS = $(DYNLIB) $(LINTLIB)
+LDLIBS += -ldevinfo -lsocket -lc
+
+SRCDIR = ../common
+$(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC)
+
+CFLAGS += $(CCVERBOSE)
+CPPFLAGS += -I$(SRCDIR) -D_REENTRANT
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+lint: lintcheck
+
+include $(SRC)/lib/Makefile.targ
diff --git a/usr/src/lib/libwladm/common/libwladm.c b/usr/src/lib/libwladm/common/libwladm.c
new file mode 100644
index 0000000000..4c3c8e918b
--- /dev/null
+++ b/usr/src/lib/libwladm/common/libwladm.c
@@ -0,0 +1,1957 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <fcntl.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 <libwladm.h>
+#include <libwladm_impl.h>
+#include <inet/wifi_ioctl.h>
+
+typedef struct val_desc {
+ char *vd_name;
+ uint_t vd_val;
+} val_desc_t;
+
+struct prop_desc;
+
+typedef wladm_status_t pd_getf_t(int, wldp_t *, char **, uint_t *);
+typedef wladm_status_t pd_setf_t(int, wldp_t *, val_desc_t *, uint_t);
+typedef wladm_status_t 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;
+ pd_setf_t *pd_set;
+ pd_getf_t *pd_getmod;
+ pd_getf_t *pd_get;
+ pd_checkf_t *pd_check;
+} prop_desc_t;
+
+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_set_bsstype(int, wldp_t *, wladm_bsstype_t *);
+static int do_set_authmode(int, wldp_t *, wladm_auth_t *);
+static int do_set_encryption(int, wldp_t *, wladm_secmode_t *);
+static int do_set_essid(int, wldp_t *, wladm_essid_t *);
+static int do_set_createibss(int, wldp_t *, boolean_t *);
+static int do_set_wepkey(int, wldp_t *, wladm_wep_key_t *, uint_t);
+static int do_set_rate(int, wldp_t *, wladm_rates_t *);
+static int do_set_powermode(int, wldp_t *, wladm_powermode_t *);
+static int do_set_radio(int, wldp_t *, wladm_radio_t *);
+static int do_set_channel(int, wldp_t *, wladm_channel_t *);
+
+static int open_link(const char *);
+static int do_scan(int, wldp_t *);
+static int do_disconnect(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(wladm_essid_t *);
+
+static wladm_status_t wladm_wlresult2status(wldp_t *);
+
+static pd_getf_t 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_rate_prop, do_set_powermode_prop,
+ do_set_radio_prop;
+static pd_checkf_t do_check_prop, do_check_rate;
+
+static val_desc_t status_vals[] = {
+ { "ok", WLADM_STATUS_OK },
+ { "invalid argument", WLADM_STATUS_BADARG },
+ { "operation failed", WLADM_STATUS_FAILED },
+ { "operation not supported", WLADM_STATUS_NOTSUP },
+ { "already connected", WLADM_STATUS_ISCONN },
+ { "not connected", WLADM_STATUS_NOTCONN },
+ { "not found", WLADM_STATUS_NOTFOUND },
+ { "value not found", WLADM_STATUS_BADVAL },
+ { "invalid link", WLADM_STATUS_LINKINVAL },
+ { "insufficient memory", WLADM_STATUS_NOMEM },
+ { "operation timed out", WLADM_STATUS_TIMEDOUT },
+ { "read-only property", WLADM_STATUS_PROPRDONLY },
+ { "not enough space", WLADM_STATUS_TOOSMALL },
+ { "invalid number of values", WLADM_STATUS_BADVALCNT }
+};
+
+static val_desc_t linkstatus_vals[] = {
+ { "disconnected", WLADM_LINK_STATUS_DISCONNECTED },
+ { "connected", WLADM_LINK_STATUS_CONNECTED }
+};
+
+static val_desc_t secmode_vals[] = {
+ { "none", WLADM_SECMODE_NONE },
+ { "wep", WLADM_SECMODE_WEP }
+};
+
+static val_desc_t strength_vals[] = {
+ { "very weak", WLADM_STRENGTH_VERY_WEAK },
+ { "weak", WLADM_STRENGTH_WEAK },
+ { "good", WLADM_STRENGTH_GOOD },
+ { "very good", WLADM_STRENGTH_VERY_GOOD },
+ { "excellent", WLADM_STRENGTH_EXCELLENT }
+};
+
+static val_desc_t mode_vals[] = {
+ { "a", WLADM_MODE_80211A },
+ { "b", WLADM_MODE_80211B },
+ { "g", WLADM_MODE_80211G },
+};
+
+static val_desc_t auth_vals[] = {
+ { "open", WLADM_AUTH_OPEN },
+ { "shared", WLADM_AUTH_SHARED }
+};
+
+static val_desc_t bsstype_vals[] = {
+ { "bss", WLADM_BSSTYPE_BSS },
+ { "ibss", WLADM_BSSTYPE_IBSS },
+ { "any", WLADM_BSSTYPE_ANY }
+};
+
+static val_desc_t radio_vals[] = {
+ { "on", WLADM_RADIO_ON },
+ { "off", WLADM_RADIO_OFF }
+};
+
+static val_desc_t powermode_vals[] = {
+ { "off", WLADM_PM_OFF },
+ { "fast", WLADM_PM_FAST },
+ { "max", WLADM_PM_MAX }
+};
+
+#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", WLADM_PM_OFF }, powermode_vals,
+ VALCNT(powermode_vals),
+ do_set_powermode_prop, NULL,
+ do_get_powermode_prop, do_check_prop},
+
+ { "radio", { "on", WLADM_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 WLADM_MAX_PROPS (sizeof (prop_table) / sizeof (prop_desc_t))
+#define IS_CONNECTED(gbuf) \
+ ((*(wl_linkstatus_t *)((gbuf)->wldp_buf) == WL_CONNECTED))
+
+static wladm_status_t
+wladm_wlresult2status(wldp_t *gbuf)
+{
+ switch (gbuf->wldp_result) {
+ case WL_SUCCESS:
+ return (WLADM_STATUS_OK);
+
+ case WL_NOTSUPPORTED:
+ case WL_LACK_FEATURE:
+ return (WLADM_STATUS_NOTSUP);
+
+ case WL_READONLY:
+ return (WLADM_STATUS_PROPRDONLY);
+
+ default:
+ break;
+ }
+
+ return (WLADM_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 wladm_mode_t
+do_convert_mode(wl_phy_conf_t *phyp)
+{
+ switch (phyp->wl_phy_fhss_conf.wl_fhss_subtype) {
+ case WL_ERP:
+ return (WLADM_MODE_80211G);
+ case WL_OFDM:
+ return (WLADM_MODE_80211A);
+ case WL_DSSS:
+ case WL_FHSS:
+ return (WLADM_MODE_80211B);
+ default:
+ break;
+ }
+
+ return (WLADM_MODE_NONE);
+}
+
+static boolean_t
+do_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;
+
+ switch (wlfp->wl_fhss_subtype) {
+ case WL_FHSS:
+ case WL_DSSS:
+ case WL_IRBASE:
+ case WL_HRDS:
+ case WL_ERP:
+ *channelp = wlfp->wl_fhss_channel;
+ break;
+ case WL_OFDM:
+ *channelp = WLADM_OFDM2CHAN(wlop->wl_ofdm_frequency);
+ break;
+ default:
+ return (B_FALSE);
+ }
+ return (B_TRUE);
+}
+
+#define IEEE80211_RATE 0x7f
+static void
+fill_wlan_attr(wl_ess_conf_t *wlp, wladm_wlan_attr_t *attrp)
+{
+ int i;
+
+ (void) memset(attrp, 0, sizeof (*attrp));
+
+ (void) snprintf(attrp->wa_essid.we_bytes, WLADM_MAX_ESSID_LEN, "%s",
+ wlp->wl_ess_conf_essid.wl_essid_essid);
+ attrp->wa_valid |= WLADM_WLAN_ATTR_ESSID;
+
+ (void) memcpy(attrp->wa_bssid.wb_bytes, wlp->wl_ess_conf_bssid,
+ WLADM_BSSID_LEN);
+ attrp->wa_valid |= WLADM_WLAN_ATTR_BSSID;
+
+ attrp->wa_secmode = (wlp->wl_ess_conf_wepenabled ==
+ WL_ENC_WEP ? WLADM_SECMODE_WEP : WLADM_SECMODE_NONE);
+ attrp->wa_valid |= WLADM_WLAN_ATTR_SECMODE;
+
+ attrp->wa_bsstype = (wlp->wl_ess_conf_bsstype == WL_BSS_BSS ?
+ WLADM_BSSTYPE_BSS : WLADM_BSSTYPE_IBSS);
+ attrp->wa_valid |= WLADM_WLAN_ATTR_BSSTYPE;
+
+ attrp->wa_auth = (wlp->wl_ess_conf_authmode == 0 ?
+ WLADM_AUTH_OPEN : WLADM_AUTH_SHARED);
+ attrp->wa_valid |= WLADM_WLAN_ATTR_AUTH;
+
+ attrp->wa_strength = WLADM_SIGNAL2STRENGTH(wlp->wl_ess_conf_sl);
+ attrp->wa_valid |= WLADM_WLAN_ATTR_STRENGTH;
+
+ attrp->wa_mode = do_convert_mode((wl_phy_conf_t *)&wlp->wl_phy_conf);
+ attrp->wa_valid |= WLADM_WLAN_ATTR_MODE;
+
+ for (i = 0; i < MAX_SCAN_SUPPORT_RATES; i++) {
+ wlp->wl_supported_rates[i] &= IEEE80211_RATE;
+ if (wlp->wl_supported_rates[i] > attrp->wa_speed)
+ attrp->wa_speed = wlp->wl_supported_rates[i];
+ }
+ if (attrp->wa_speed > 0)
+ attrp->wa_valid |= WLADM_WLAN_ATTR_SPEED;
+
+ if (do_convert_chan((wl_phy_conf_t *)&wlp->wl_phy_conf,
+ &attrp->wa_channel))
+ attrp->wa_valid |= WLADM_WLAN_ATTR_CHANNEL;
+}
+
+wladm_status_t
+wladm_scan(const char *link, void *arg,
+ boolean_t (*func)(void *, wladm_wlan_attr_t *))
+{
+ int fd, i;
+ uint32_t count;
+ wl_ess_conf_t *wlp;
+ wldp_t *gbuf;
+ wladm_wlan_attr_t wlattr;
+ wladm_status_t status;
+ boolean_t connected;
+
+ if ((fd = open_link(link)) < 0)
+ return (WLADM_STATUS_LINKINVAL);
+
+ if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) {
+ status = WLADM_STATUS_NOMEM;
+ goto done;
+ }
+
+ if (do_get_linkstatus(fd, gbuf) < 0) {
+ status = WLADM_STATUS_FAILED;
+ goto done;
+ }
+ connected = IS_CONNECTED(gbuf);
+
+ if (do_scan(fd, gbuf) < 0) {
+ status = WLADM_STATUS_FAILED;
+ goto done;
+ }
+
+ if (do_get_esslist(fd, gbuf) < 0) {
+ status = WLADM_STATUS_FAILED;
+ 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;
+
+ for (i = 0; i < count; i++, wlp++) {
+ fill_wlan_attr(wlp, &wlattr);
+ if (!func(arg, &wlattr))
+ break;
+ }
+
+ if (!connected) {
+ if (do_get_linkstatus(fd, gbuf) < 0) {
+ status = WLADM_STATUS_FAILED;
+ goto done;
+ }
+ if (IS_CONNECTED(gbuf))
+ (void) do_disconnect(fd, gbuf);
+ }
+
+ status = WLADM_STATUS_OK;
+done:
+ free(gbuf);
+ (void) close(fd);
+ return (status);
+}
+
+/*
+ * Structures used in building the list of eligible WLANs to connect to.
+ * Specifically, `connect_state' has the WLAN attributes that must be matched
+ * (in `cs_attr') and a growing list of WLANs that matched those attributes
+ * chained through `cs_list'. Each element in the list is of type `attr_node'
+ * and has the matching WLAN's attributes and a pointer to the next element.
+ * For convenience, `cs_count' tracks the number of elements in the list.
+ */
+typedef struct attr_node {
+ wladm_wlan_attr_t an_attr;
+ struct attr_node *an_next;
+} attr_node_t;
+
+typedef struct connect_state {
+ wladm_wlan_attr_t *cs_attr;
+ uint_t cs_count;
+ attr_node_t *cs_list;
+} connect_state_t;
+
+/*
+ * Compare two sets of WLAN attributes. For now, we only consider strength
+ * and speed (in that order), which matches the documented default policy for
+ * wladm_connect().
+ */
+static int
+attr_compare(const void *p1, const void *p2)
+{
+ wladm_wlan_attr_t *attrp1, *attrp2;
+
+ attrp1 = (*(wladm_wlan_attr_t **)p1);
+ attrp2 = (*(wladm_wlan_attr_t **)p2);
+
+ if (attrp1->wa_strength < attrp2->wa_strength)
+ return (1);
+
+ if (attrp1->wa_strength > attrp2->wa_strength)
+ return (-1);
+
+ return (attrp2->wa_speed - attrp1->wa_speed);
+}
+
+/*
+ * Callback function used by wladm_connect() to filter out unwanted WLANs when
+ * scanning for available WLANs. Always returns B_TRUE to continue the scan.
+ */
+static boolean_t
+connect_cb(void *arg, wladm_wlan_attr_t *attrp)
+{
+ attr_node_t *nodep;
+ wladm_wlan_attr_t *fattrp;
+ connect_state_t *statep = (connect_state_t *)arg;
+
+ fattrp = statep->cs_attr;
+ if (fattrp == NULL)
+ goto append;
+
+ if ((fattrp->wa_valid & attrp->wa_valid) != fattrp->wa_valid)
+ return (B_TRUE);
+
+ if ((fattrp->wa_valid & WLADM_WLAN_ATTR_ESSID) != 0 &&
+ strncmp(fattrp->wa_essid.we_bytes, attrp->wa_essid.we_bytes,
+ WLADM_MAX_ESSID_LEN) != 0)
+ return (B_TRUE);
+
+ if ((fattrp->wa_valid & WLADM_WLAN_ATTR_SECMODE) != 0 &&
+ fattrp->wa_secmode != attrp->wa_secmode)
+ return (B_TRUE);
+
+ if ((fattrp->wa_valid & WLADM_WLAN_ATTR_MODE) != 0 &&
+ fattrp->wa_mode != attrp->wa_mode)
+ return (B_TRUE);
+
+ if ((fattrp->wa_valid & WLADM_WLAN_ATTR_STRENGTH) != 0 &&
+ fattrp->wa_strength != attrp->wa_strength)
+ return (B_TRUE);
+
+ if ((fattrp->wa_valid & WLADM_WLAN_ATTR_SPEED) != 0 &&
+ fattrp->wa_speed != attrp->wa_speed)
+ return (B_TRUE);
+
+ if ((fattrp->wa_valid & WLADM_WLAN_ATTR_AUTH) != 0) {
+ attrp->wa_auth = fattrp->wa_auth;
+ attrp->wa_valid |= WLADM_WLAN_ATTR_AUTH;
+ }
+
+ if ((fattrp->wa_valid & WLADM_WLAN_ATTR_BSSTYPE) != 0 &&
+ fattrp->wa_bsstype != attrp->wa_bsstype)
+ return (B_TRUE);
+
+ if ((fattrp->wa_valid & WLADM_WLAN_ATTR_BSSID) != 0 &&
+ memcmp(fattrp->wa_bssid.wb_bytes, attrp->wa_bssid.wb_bytes,
+ WLADM_BSSID_LEN) != 0)
+ return (B_TRUE);
+append:
+ nodep = malloc(sizeof (attr_node_t));
+ if (nodep == NULL)
+ return (B_TRUE);
+
+ (void) memcpy(&nodep->an_attr, attrp, sizeof (wladm_wlan_attr_t));
+ nodep->an_next = statep->cs_list;
+ statep->cs_list = nodep;
+ statep->cs_count++;
+
+ return (B_TRUE);
+}
+
+static wladm_status_t
+do_connect(int fd, wldp_t *gbuf, wladm_wlan_attr_t *attrp,
+ boolean_t create_ibss, void *keys, uint_t key_count, int timeout)
+{
+ wladm_secmode_t secmode;
+ wladm_auth_t authmode;
+ wladm_bsstype_t bsstype;
+ wladm_essid_t essid;
+ boolean_t essid_valid = B_FALSE;
+ wladm_status_t status = WLADM_STATUS_FAILED;
+ wladm_channel_t channel;
+ hrtime_t start;
+ struct timespec ts;
+
+ if ((attrp->wa_valid & WLADM_WLAN_ATTR_CHANNEL) != 0) {
+ channel = attrp->wa_channel;
+ if (do_set_channel(fd, gbuf, &channel) < 0)
+ goto done;
+ }
+
+ secmode = ((attrp->wa_valid & WLADM_WLAN_ATTR_SECMODE) != 0) ?
+ attrp->wa_secmode : WLADM_SECMODE_NONE;
+
+ if (do_set_encryption(fd, gbuf, &secmode) < 0)
+ goto done;
+
+ authmode = ((attrp->wa_valid & WLADM_WLAN_ATTR_AUTH) != 0) ?
+ attrp->wa_auth : WLADM_AUTH_OPEN;
+
+ if (do_set_authmode(fd, gbuf, &authmode) < 0)
+ goto done;
+
+ bsstype = ((attrp->wa_valid & WLADM_WLAN_ATTR_BSSTYPE) != 0) ?
+ attrp->wa_bsstype : WLADM_BSSTYPE_BSS;
+
+ if (do_set_bsstype(fd, gbuf, &bsstype) < 0)
+ goto done;
+
+ if (secmode == WLADM_SECMODE_WEP &&
+ (keys == NULL || key_count == 0 || key_count > MAX_NWEPKEYS ||
+ do_set_wepkey(fd, gbuf, keys, key_count) < 0))
+ goto done;
+
+ if (create_ibss) {
+ if (do_set_channel(fd, gbuf, &channel) < 0)
+ goto done;
+
+ if (do_set_createibss(fd, gbuf, &create_ibss) < 0)
+ goto done;
+
+ if ((attrp->wa_valid & WLADM_WLAN_ATTR_ESSID) == 0) {
+ generate_essid(&essid);
+ essid_valid = B_TRUE;
+ }
+ }
+
+ if ((attrp->wa_valid & WLADM_WLAN_ATTR_ESSID) != 0) {
+ essid = attrp->wa_essid;
+ essid_valid = B_TRUE;
+ }
+
+ if (!essid_valid || do_set_essid(fd, gbuf, &essid) < 0)
+ goto done;
+
+ ts.tv_sec = 0;
+ ts.tv_nsec = WLADM_CONNECT_POLLRATE;
+ start = gethrtime();
+ for (;;) {
+ if (do_get_linkstatus(fd, gbuf) < 0) {
+ status = WLADM_STATUS_FAILED;
+ goto done;
+ }
+
+ if (IS_CONNECTED(gbuf))
+ break;
+
+ (void) nanosleep(&ts, NULL);
+ if ((timeout >= 0) && (gethrtime() - start) /
+ NANOSEC >= timeout) {
+ status = WLADM_STATUS_TIMEDOUT;
+ goto done;
+ }
+ }
+ status = WLADM_STATUS_OK;
+done:
+ return (status);
+}
+
+wladm_status_t
+wladm_connect(const char *link, wladm_wlan_attr_t *attrp,
+ int timeout, void *keys, uint_t key_count, uint_t flags)
+{
+ int fd, i;
+ wldp_t *gbuf = NULL;
+ connect_state_t state = {0, NULL, NULL};
+ attr_node_t *nodep = NULL;
+ boolean_t create_ibss, set_authmode;
+ wladm_wlan_attr_t **wl_list = NULL;
+ wladm_status_t status = WLADM_STATUS_FAILED;
+
+ if ((fd = open_link(link)) < 0)
+ return (WLADM_STATUS_LINKINVAL);
+
+ if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) {
+ status = WLADM_STATUS_NOMEM;
+ goto done;
+ }
+
+ if (do_get_linkstatus(fd, gbuf) < 0) {
+ status = WLADM_STATUS_FAILED;
+ goto done;
+ }
+
+ if (IS_CONNECTED(gbuf)) {
+ status = WLADM_STATUS_ISCONN;
+ goto done;
+ }
+
+ set_authmode = ((attrp != NULL) &&
+ (attrp->wa_valid & WLADM_WLAN_ATTR_MODE) != 0);
+ create_ibss = ((flags & WLADM_OPT_CREATEIBSS) != 0 &&
+ attrp != NULL &&
+ (attrp->wa_valid & WLADM_WLAN_ATTR_BSSTYPE) != 0 &&
+ attrp->wa_bsstype == WLADM_BSSTYPE_IBSS);
+
+ if ((flags & WLADM_OPT_NOSCAN) != 0 ||
+ (create_ibss && attrp != NULL &&
+ (attrp->wa_valid & WLADM_WLAN_ATTR_ESSID) == 0)) {
+ status = do_connect(fd, gbuf, attrp,
+ create_ibss, keys, key_count, timeout);
+ goto done;
+ }
+
+ state.cs_attr = attrp;
+ state.cs_list = NULL;
+ state.cs_count = 0;
+
+ status = wladm_scan(link, &state, connect_cb);
+ if (status != WLADM_STATUS_OK)
+ goto done;
+
+ if (state.cs_count == 0) {
+ if (!create_ibss) {
+ status = WLADM_STATUS_NOTFOUND;
+ goto done;
+ }
+ status = do_connect(fd, gbuf, attrp, create_ibss,
+ keys, key_count, timeout);
+ goto done;
+ }
+
+ wl_list = malloc(state.cs_count * sizeof (wladm_wlan_attr_t *));
+ if (wl_list == NULL) {
+ status = WLADM_STATUS_NOMEM;
+ goto done;
+ }
+
+ nodep = state.cs_list;
+ for (i = 0; i < state.cs_count; i++) {
+ wl_list[i] = &nodep->an_attr;
+ nodep = nodep->an_next;
+ }
+ qsort(wl_list, state.cs_count, sizeof (wladm_wlan_attr_t *),
+ attr_compare);
+
+ for (i = 0; i < state.cs_count; i++) {
+ wladm_wlan_attr_t *ap = wl_list[i];
+
+ status = do_connect(fd, gbuf, ap, create_ibss, keys,
+ key_count, timeout);
+ if (status == WLADM_STATUS_OK)
+ break;
+
+ if (!set_authmode) {
+ ap->wa_auth = WLADM_AUTH_SHARED;
+ ap->wa_valid |= WLADM_WLAN_ATTR_AUTH;
+ status = do_connect(fd, gbuf, ap, create_ibss, keys,
+ key_count, timeout);
+ if (status == WLADM_STATUS_OK)
+ break;
+ }
+ }
+done:
+ if ((status != WLADM_STATUS_OK) && (status != WLADM_STATUS_ISCONN))
+ (void) do_disconnect(fd, gbuf);
+
+ while (state.cs_list != NULL) {
+ nodep = state.cs_list;
+ state.cs_list = nodep->an_next;
+ free(nodep);
+ }
+ free(gbuf);
+ free(wl_list);
+ (void) close(fd);
+ return (status);
+}
+
+wladm_status_t
+wladm_disconnect(const char *link)
+{
+ int fd;
+ wldp_t *gbuf;
+ wladm_status_t status;
+
+ if ((fd = open_link(link)) < 0)
+ return (WLADM_STATUS_BADARG);
+
+ if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) {
+ status = WLADM_STATUS_NOMEM;
+ goto done;
+ }
+
+ if (do_get_linkstatus(fd, gbuf) < 0) {
+ status = WLADM_STATUS_FAILED;
+ goto done;
+ }
+
+ if (!IS_CONNECTED(gbuf)) {
+ status = WLADM_STATUS_NOTCONN;
+ goto done;
+ }
+
+ if (do_disconnect(fd, gbuf) < 0) {
+ status = WLADM_STATUS_FAILED;
+ goto done;
+ }
+
+ if (do_get_linkstatus(fd, gbuf) < 0) {
+ status = WLADM_STATUS_FAILED;
+ goto done;
+ }
+
+ if (IS_CONNECTED(gbuf)) {
+ status = WLADM_STATUS_FAILED;
+ goto done;
+ }
+
+ status = WLADM_STATUS_OK;
+done:
+ free(gbuf);
+ (void) close(fd);
+ return (status);
+}
+
+typedef struct wladm_linkname {
+ char wl_name[MAXNAMELEN];
+ struct wladm_linkname *wl_next;
+} wladm_linkname_t;
+
+typedef struct wladm_walk {
+ wladm_linkname_t *ww_list;
+ wladm_status_t ww_status;
+} wladm_walk_t;
+
+/* ARGSUSED */
+static int
+append_linkname(di_node_t node, di_minor_t minor, void *arg)
+{
+ wladm_walk_t *statep = arg;
+ wladm_linkname_t **lastp = &statep->ww_list;
+ wladm_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 = WLADM_STATUS_NOMEM;
+ return (DI_WALK_CONTINUE);
+ }
+
+ (void) strlcpy(wlp->wl_name, name, MAXNAMELEN);
+ wlp->wl_next = NULL;
+ *lastp = wlp;
+
+ return (DI_WALK_CONTINUE);
+}
+
+wladm_status_t
+wladm_walk(void *arg, boolean_t (*func)(void *, const char *))
+{
+ di_node_t root;
+ wladm_walk_t state;
+ wladm_linkname_t *wlp, *wlp_next;
+ boolean_t cont = B_TRUE;
+
+ if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL)
+ return (WLADM_STATUS_FAILED);
+
+ state.ww_list = NULL;
+ state.ww_status = WLADM_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);
+}
+
+wladm_status_t
+wladm_get_link_attr(const char *link, wladm_link_attr_t *attrp)
+{
+ int fd;
+ wldp_t *gbuf;
+ wl_rssi_t signal;
+ wl_bss_type_t bsstype;
+ wl_authmode_t authmode;
+ wl_encryption_t encryption;
+ wl_rates_t *ratesp;
+ wladm_wlan_attr_t *wl_attrp;
+ wladm_status_t status = WLADM_STATUS_FAILED;
+
+ if (attrp == NULL)
+ return (WLADM_STATUS_BADARG);
+
+ if ((fd = open_link(link)) < 0)
+ return (WLADM_STATUS_LINKINVAL);
+
+ if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) {
+ status = WLADM_STATUS_NOMEM;
+ goto done;
+ }
+
+ (void) memset(attrp, 0, sizeof (*attrp));
+ wl_attrp = &attrp->la_wlan_attr;
+
+ if (do_get_linkstatus(fd, gbuf) < 0)
+ goto done;
+
+ attrp->la_valid |= WLADM_LINK_ATTR_STATUS;
+ if (!IS_CONNECTED(gbuf)) {
+ attrp->la_status = WLADM_LINK_STATUS_DISCONNECTED;
+ status = WLADM_STATUS_OK;
+ goto done;
+ }
+ attrp->la_status = WLADM_LINK_STATUS_CONNECTED;
+
+ if (do_get_essid(fd, gbuf) < 0)
+ goto done;
+
+ (void) strlcpy(wl_attrp->wa_essid.we_bytes,
+ ((wl_essid_t *)(gbuf->wldp_buf))->wl_essid_essid,
+ WLADM_MAX_ESSID_LEN);
+
+ wl_attrp->wa_valid |= WLADM_WLAN_ATTR_ESSID;
+
+ if (do_get_bssid(fd, gbuf) < 0)
+ goto done;
+
+ (void) memcpy(wl_attrp->wa_bssid.wb_bytes, gbuf->wldp_buf,
+ WLADM_BSSID_LEN);
+
+ wl_attrp->wa_valid |= WLADM_WLAN_ATTR_BSSID;
+
+ if (do_get_encryption(fd, gbuf) < 0)
+ goto done;
+
+ encryption = *(wl_encryption_t *)(gbuf->wldp_buf);
+ wl_attrp->wa_valid |= WLADM_WLAN_ATTR_SECMODE;
+
+ switch (encryption) {
+ case WL_NOENCRYPTION:
+ wl_attrp->wa_secmode = WLADM_SECMODE_NONE;
+ break;
+ case WL_ENC_WEP:
+ wl_attrp->wa_secmode = WLADM_SECMODE_WEP;
+ break;
+ default:
+ wl_attrp->wa_valid &= ~WLADM_WLAN_ATTR_SECMODE;
+ break;
+ }
+
+ if (do_get_signal(fd, gbuf) < 0)
+ goto done;
+
+ signal = *(wl_rssi_t *)(gbuf->wldp_buf);
+ wl_attrp->wa_valid |= WLADM_WLAN_ATTR_STRENGTH;
+ wl_attrp->wa_strength = WLADM_SIGNAL2STRENGTH(signal);
+
+ if (do_get_rate(fd, gbuf) < 0)
+ goto done;
+
+ ratesp = (wl_rates_t *)(gbuf->wldp_buf);
+ if (ratesp->wl_rates_num > 0) {
+ uint_t i, r = 0;
+
+ for (i = 0; i < ratesp->wl_rates_num; i++) {
+ if (ratesp->wl_rates_rates[i] > r)
+ r = ratesp->wl_rates_rates[i];
+ }
+ wl_attrp->wa_speed = r;
+ wl_attrp->wa_valid |= WLADM_WLAN_ATTR_SPEED;
+ }
+
+ if (do_get_authmode(fd, gbuf) < 0)
+ goto done;
+
+ authmode = *(wl_authmode_t *)(gbuf->wldp_buf);
+ wl_attrp->wa_valid |= WLADM_WLAN_ATTR_AUTH;
+
+ switch (authmode) {
+ case WL_OPENSYSTEM:
+ wl_attrp->wa_auth = WLADM_AUTH_OPEN;
+ break;
+ case WL_SHAREDKEY:
+ wl_attrp->wa_auth = WLADM_AUTH_SHARED;
+ break;
+ default:
+ wl_attrp->wa_valid &= ~WLADM_WLAN_ATTR_AUTH;
+ break;
+ }
+
+ if (do_get_bsstype(fd, gbuf) < 0)
+ goto done;
+
+ bsstype = *(wl_bss_type_t *)(gbuf->wldp_buf);
+ wl_attrp->wa_valid |= WLADM_WLAN_ATTR_BSSTYPE;
+
+ switch (bsstype) {
+ case WL_BSS_BSS:
+ wl_attrp->wa_bsstype = WLADM_BSSTYPE_BSS;
+ break;
+ case WL_BSS_IBSS:
+ wl_attrp->wa_bsstype = WLADM_BSSTYPE_IBSS;
+ break;
+ case WL_BSS_ANY:
+ wl_attrp->wa_bsstype = WLADM_BSSTYPE_ANY;
+ break;
+ default:
+ wl_attrp->wa_valid &= ~WLADM_WLAN_ATTR_BSSTYPE;
+ break;
+ }
+
+ if (do_get_mode(fd, gbuf) < 0)
+ goto done;
+
+ wl_attrp->wa_mode = do_convert_mode((wl_phy_conf_t *)(gbuf->wldp_buf));
+ wl_attrp->wa_valid |= WLADM_WLAN_ATTR_MODE;
+ if (wl_attrp->wa_mode != WLADM_MODE_NONE)
+ wl_attrp->wa_valid |= WLADM_WLAN_ATTR_MODE;
+
+ attrp->la_valid |= WLADM_LINK_ATTR_WLAN;
+ status = WLADM_STATUS_OK;
+
+done:
+ free(gbuf);
+ (void) close(fd);
+ return (status);
+}
+
+boolean_t
+wladm_is_valid(const char *link)
+{
+ int fd = open_link(link);
+
+ if (fd < 0)
+ return (B_FALSE);
+
+ (void) close(fd);
+ return (B_TRUE);
+}
+
+/* ARGSUSED */
+static wladm_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 (WLADM_STATUS_PROPRDONLY);
+
+ if (val_cnt != 1)
+ return (WLADM_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 (WLADM_STATUS_BADVAL);
+
+ vdp = malloc(sizeof (val_desc_t));
+ if (vdp == NULL)
+ return (WLADM_STATUS_NOMEM);
+
+ (void) memcpy(vdp, &pdp->pd_modval[i], sizeof (val_desc_t));
+ *vdpp = vdp;
+ return (WLADM_STATUS_OK);
+}
+
+static wladm_status_t
+do_set_prop(int fd, wldp_t *gbuf, prop_desc_t *pdp,
+ char **prop_val, uint_t val_cnt)
+{
+ wladm_status_t status;
+ val_desc_t *vdp = NULL;
+ uint_t cnt;
+
+ if (pdp->pd_set == NULL)
+ return (WLADM_STATUS_PROPRDONLY);
+
+ if (prop_val != NULL) {
+ status = pdp->pd_check(fd, gbuf, pdp, prop_val,
+ val_cnt, &vdp);
+
+ if (status != WLADM_STATUS_OK)
+ return (status);
+
+ cnt = val_cnt;
+ } else {
+ if (pdp->pd_defval.vd_name == NULL)
+ return (WLADM_STATUS_NOTSUP);
+
+ if ((vdp = malloc(sizeof (val_desc_t))) == NULL)
+ return (WLADM_STATUS_NOMEM);
+
+ *vdp = pdp->pd_defval;
+ cnt = 1;
+ }
+ status = pdp->pd_set(fd, gbuf, vdp, cnt);
+ if (status == WLADM_STATUS_OK) {
+ /*
+ * Some ioctls return 0 but store error code in
+ * wldp_result. Need to fix them.
+ */
+ if (gbuf->wldp_result != WL_SUCCESS)
+ status = wladm_wlresult2status(gbuf);
+ }
+ free(vdp);
+ return (status);
+}
+
+wladm_status_t
+wladm_set_prop(const char *link, const char *prop_name,
+ char **prop_val, uint_t val_cnt)
+{
+ int fd, i;
+ wldp_t *gbuf = NULL;
+ boolean_t found = B_FALSE;
+ wladm_status_t status = WLADM_STATUS_OK;
+
+ if ((prop_name == NULL && prop_val != NULL) ||
+ (prop_val != NULL && val_cnt == 0))
+ return (WLADM_STATUS_BADARG);
+
+ if ((fd = open_link(link)) < 0)
+ return (WLADM_STATUS_LINKINVAL);
+
+ if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) {
+ status = WLADM_STATUS_NOMEM;
+ goto done;
+ }
+
+ for (i = 0; i < WLADM_MAX_PROPS; i++) {
+ prop_desc_t *pdp = &prop_table[i];
+ wladm_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 != WLADM_STATUS_OK &&
+ s != WLADM_STATUS_NOTSUP)
+ status = s;
+ }
+ }
+ if (!found)
+ status = WLADM_STATUS_NOTFOUND;
+done:
+ free(gbuf);
+ (void) close(fd);
+ return (status);
+}
+
+/* ARGSUSED */
+wladm_status_t
+wladm_walk_prop(const char *link, void *arg,
+ boolean_t (*func)(void *, const char *))
+{
+ int i;
+
+ for (i = 0; i < WLADM_MAX_PROPS; i++) {
+ if (!func(arg, prop_table[i].pd_name))
+ break;
+ }
+ return (WLADM_STATUS_OK);
+}
+
+wladm_status_t
+wladm_get_prop(const char *link, wladm_prop_type_t type, const char *prop_name,
+ char **prop_val, uint_t *val_cnt)
+{
+ int fd;
+ int i;
+ wldp_t *gbuf;
+ wladm_status_t status;
+ uint_t cnt;
+ prop_desc_t *pdp;
+
+ if (prop_val == NULL || val_cnt == NULL || *val_cnt == 0)
+ return (WLADM_STATUS_BADARG);
+
+ for (i = 0; i < WLADM_MAX_PROPS; i++)
+ if (strcasecmp(prop_name, prop_table[i].pd_name) == 0)
+ break;
+
+ if (i == WLADM_MAX_PROPS)
+ return (WLADM_STATUS_NOTFOUND);
+
+ if ((fd = open_link(link)) < 0)
+ return (WLADM_STATUS_LINKINVAL);
+
+ if ((gbuf = malloc(MAX_BUF_LEN)) == NULL) {
+ status = WLADM_STATUS_NOMEM;
+ goto done;
+ }
+ pdp = &prop_table[i];
+ status = WLADM_STATUS_OK;
+
+ switch (type) {
+ case WLADM_PROP_VAL_CURRENT:
+ status = pdp->pd_get(fd, gbuf, prop_val, val_cnt);
+ break;
+
+ case WLADM_PROP_VAL_DEFAULT:
+ if (pdp->pd_defval.vd_name == NULL) {
+ status = WLADM_STATUS_NOTSUP;
+ break;
+ }
+ (void) strcpy(*prop_val, pdp->pd_defval.vd_name);
+ *val_cnt = 1;
+ break;
+
+ case WLADM_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 = WLADM_STATUS_NOTSUP;
+ } else if (cnt > *val_cnt) {
+ status = WLADM_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 = WLADM_STATUS_BADARG;
+ break;
+ }
+done:
+ free(gbuf);
+ (void) close(fd);
+ return (status);
+}
+
+static boolean_t
+find_val_by_name(const char *str, val_desc_t *vdp, uint_t cnt, uint_t *valp)
+{
+ int i;
+
+ for (i = 0; i < cnt; i++) {
+ if (strcasecmp(str, vdp[i].vd_name) == 0) {
+ *valp = vdp[i].vd_val;
+ return (B_TRUE);
+ }
+ }
+ return (B_FALSE);
+}
+
+static boolean_t
+find_name_by_val(uint_t val, val_desc_t *vdp, uint_t cnt, char **strp)
+{
+ int i;
+
+ for (i = 0; i < cnt; i++) {
+ if (val == vdp[i].vd_val) {
+ *strp = vdp[i].vd_name;
+ return (B_TRUE);
+ }
+ }
+ return (B_FALSE);
+}
+
+const char *
+wladm_essid2str(wladm_essid_t *essid, char *buf)
+{
+ (void) snprintf(buf, WLADM_STRSIZE, "%s", essid->we_bytes);
+ return (buf);
+}
+
+const char *
+wladm_bssid2str(wladm_bssid_t *bssid, char *buf)
+{
+ return (_link_ntoa(bssid->wb_bytes, buf, WLADM_BSSID_LEN, IFT_OTHER));
+}
+
+static const char *
+wladm_val2str(uint_t val, val_desc_t *vdp, uint_t cnt, char *buf)
+{
+ char *s;
+
+ if (!find_name_by_val(val, vdp, cnt, &s))
+ s = "";
+
+ (void) snprintf(buf, WLADM_STRSIZE, "%s", s);
+ return (buf);
+}
+
+const char *
+wladm_secmode2str(wladm_secmode_t *secmode, char *buf)
+{
+ return (wladm_val2str((uint_t)*secmode, secmode_vals,
+ VALCNT(secmode_vals), buf));
+}
+
+const char *
+wladm_strength2str(wladm_strength_t *strength, char *buf)
+{
+ return (wladm_val2str((uint_t)*strength, strength_vals,
+ VALCNT(strength_vals), buf));
+}
+
+const char *
+wladm_mode2str(wladm_mode_t *mode, char *buf)
+{
+ return (wladm_val2str((uint_t)*mode, mode_vals,
+ VALCNT(mode_vals), buf));
+}
+
+const char *
+wladm_speed2str(wladm_speed_t *speed, char *buf)
+{
+ (void) snprintf(buf, WLADM_STRSIZE, "%.*f", *speed % 2,
+ (float)(*speed) / 2);
+ return (buf);
+}
+
+const char *
+wladm_auth2str(wladm_auth_t *auth, char *buf)
+{
+ return (wladm_val2str((uint_t)*auth, auth_vals,
+ VALCNT(auth_vals), buf));
+}
+
+const char *
+wladm_bsstype2str(wladm_bsstype_t *bsstype, char *buf)
+{
+ return (wladm_val2str((uint_t)*bsstype, bsstype_vals,
+ VALCNT(bsstype_vals), buf));
+}
+
+const char *
+wladm_linkstatus2str(wladm_linkstatus_t *linkstatus, char *buf)
+{
+ return (wladm_val2str((uint_t)*linkstatus, linkstatus_vals,
+ VALCNT(linkstatus_vals), buf));
+}
+
+const char *
+wladm_status2str(wladm_status_t status, char *buf)
+{
+ return (wladm_val2str((uint_t)status, status_vals,
+ VALCNT(status_vals), buf));
+}
+
+wladm_status_t
+wladm_str2essid(const char *str, wladm_essid_t *essid)
+{
+ if (str[0] == '\0')
+ return (WLADM_STATUS_BADARG);
+
+ (void) strlcpy(essid->we_bytes, str, WLADM_MAX_ESSID_LEN);
+ return (WLADM_STATUS_OK);
+}
+
+wladm_status_t
+wladm_str2bssid(const char *str, wladm_bssid_t *bssid)
+{
+ int len;
+ uchar_t *buf;
+
+ buf = _link_aton(str, &len);
+ if (buf == NULL)
+ return (WLADM_STATUS_BADARG);
+
+ if (len != WLADM_BSSID_LEN) {
+ free(buf);
+ return (WLADM_STATUS_BADARG);
+ }
+
+ (void) memcpy(bssid->wb_bytes, buf, len);
+ free(buf);
+ return (WLADM_STATUS_OK);
+}
+
+wladm_status_t
+wladm_str2secmode(const char *str, wladm_secmode_t *secmode)
+{
+ uint_t val;
+
+ if (!find_val_by_name(str, secmode_vals, VALCNT(secmode_vals), &val))
+ return (WLADM_STATUS_BADARG);
+
+ *secmode = (wladm_secmode_t)val;
+ return (WLADM_STATUS_OK);
+}
+
+wladm_status_t
+wladm_str2strength(const char *str, wladm_strength_t *strength)
+{
+ uint_t val;
+
+ if (!find_val_by_name(str, strength_vals, VALCNT(strength_vals), &val))
+ return (WLADM_STATUS_BADARG);
+
+ *strength = (wladm_strength_t)val;
+ return (WLADM_STATUS_OK);
+}
+
+wladm_status_t
+wladm_str2mode(const char *str, wladm_mode_t *mode)
+{
+ uint_t val;
+
+ if (!find_val_by_name(str, mode_vals, VALCNT(mode_vals), &val))
+ return (WLADM_STATUS_BADARG);
+
+ *mode = (wladm_mode_t)val;
+ return (WLADM_STATUS_OK);
+}
+
+wladm_status_t
+wladm_str2speed(const char *str, wladm_speed_t *speed)
+{
+ *speed = (wladm_speed_t)(atof(str) * 2);
+ return (WLADM_STATUS_OK);
+}
+
+wladm_status_t
+wladm_str2auth(const char *str, wladm_auth_t *auth)
+{
+ uint_t val;
+
+ if (!find_val_by_name(str, auth_vals, VALCNT(auth_vals), &val))
+ return (WLADM_STATUS_BADARG);
+
+ *auth = (wladm_auth_t)val;
+ return (WLADM_STATUS_OK);
+}
+
+wladm_status_t
+wladm_str2bsstype(const char *str, wladm_bsstype_t *bsstype)
+{
+ uint_t val;
+
+ if (!find_val_by_name(str, bsstype_vals, VALCNT(bsstype_vals), &val))
+ return (WLADM_STATUS_BADARG);
+
+ *bsstype = (wladm_bsstype_t)val;
+ return (WLADM_STATUS_OK);
+}
+
+wladm_status_t
+wladm_str2linkstatus(const char *str, wladm_linkstatus_t *linkstatus)
+{
+ uint_t val;
+
+ if (!find_val_by_name(str, linkstatus_vals, VALCNT(linkstatus_vals),
+ &val))
+ return (WLADM_STATUS_BADARG);
+
+ *linkstatus = (wladm_linkstatus_t)val;
+ return (WLADM_STATUS_OK);
+}
+
+static int
+do_ioctl(int fd, wldp_t *gbuf, uint_t id, size_t len, uint_t cmd, size_t cmdlen)
+{
+ int rc;
+ struct strioctl stri;
+
+ gbuf->wldp_type = NET_802_11;
+ gbuf->wldp_id = id;
+ gbuf->wldp_length = len;
+
+ stri.ic_timout = 0;
+ stri.ic_dp = (char *)gbuf;
+ stri.ic_cmd = cmd;
+ stri.ic_len = cmdlen;
+
+ if ((rc = ioctl(fd, I_STR, &stri)) != 0) {
+ if (rc > 0)
+ errno = rc;
+ return (-1);
+ }
+ return (0);
+}
+
+static int
+do_get_ioctl(int fd, 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));
+}
+
+static int
+do_set_ioctl(int fd, wldp_t *gbuf, uint_t id, void *buf, uint_t buflen)
+{
+ (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));
+}
+
+static int
+do_cmd_ioctl(int fd, 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)));
+}
+
+static int
+do_scan(int fd, wldp_t *gbuf)
+{
+ return (do_cmd_ioctl(fd, gbuf, WL_SCAN));
+}
+
+static int
+do_disconnect(int fd, wldp_t *gbuf)
+{
+ return (do_cmd_ioctl(fd, gbuf, WL_DISASSOCIATE));
+}
+
+static int
+do_get_esslist(int fd, wldp_t *gbuf)
+{
+ (void) memset(gbuf, 0, MAX_BUF_LEN);
+ return (do_ioctl(fd, 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)
+{
+ return (do_get_ioctl(fd, gbuf, WL_ENCRYPTION));
+}
+
+static int
+do_get_signal(int fd, wldp_t *gbuf)
+{
+ return (do_get_ioctl(fd, gbuf, WL_RSSI));
+}
+
+static int
+do_get_mode(int fd, wldp_t *gbuf)
+{
+ return (do_get_ioctl(fd, gbuf, WL_PHY_CONFIG));
+}
+
+static wladm_status_t
+do_get_rate_common(wldp_t *gbuf, char **prop_val, uint_t *val_cnt)
+{
+ 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 (WLADM_STATUS_TOOSMALL);
+ if (wrp->wl_rates_rates[0] == 0) {
+ prop_val[0][0] = '\0';
+ *val_cnt = 1;
+ return (WLADM_STATUS_OK);
+ }
+
+ for (i = 0; i < cnt; i++) {
+ (void) snprintf(prop_val[i], WLADM_STRSIZE, "%.*f",
+ wrp->wl_rates_rates[i] % 2,
+ (float)wrp->wl_rates_rates[i] / 2);
+ }
+ *val_cnt = cnt;
+ return (WLADM_STATUS_OK);
+}
+
+static wladm_status_t
+do_get_rate_prop(int fd, wldp_t *gbuf, char **prop_val, uint_t *val_cnt)
+{
+ if (do_get_rate(fd, gbuf) < 0)
+ return (wladm_wlresult2status(gbuf));
+
+ return (do_get_rate_common(gbuf, prop_val, val_cnt));
+}
+
+static wladm_status_t
+do_get_rate_mod(int fd, wldp_t *gbuf, char **prop_val, uint_t *val_cnt)
+{
+ if (do_get_ioctl(fd, gbuf, WL_SUPPORTED_RATES) < 0)
+ return (WLADM_STATUS_FAILED);
+
+ return (do_get_rate_common(gbuf, prop_val, val_cnt));
+}
+
+static wladm_status_t
+do_get_channel_prop(int fd, wldp_t *gbuf, char **prop_val, uint_t *val_cnt)
+{
+ uint32_t channel;
+
+ if (do_get_phyconf(fd, gbuf) < 0)
+ return (wladm_wlresult2status(gbuf));
+
+ if (!do_convert_chan((wl_phy_conf_t *)gbuf->wldp_buf, &channel))
+ return (WLADM_STATUS_NOTFOUND);
+
+ (void) snprintf(*prop_val, WLADM_STRSIZE, "%u", channel);
+ *val_cnt = 1;
+
+ return (WLADM_STATUS_OK);
+}
+
+static wladm_status_t
+do_get_powermode_prop(int fd, wldp_t *gbuf, char **prop_val, uint_t *val_cnt)
+{
+ wl_ps_mode_t *mode;
+ const char *s;
+
+ if (do_get_powermode(fd, gbuf) < 0)
+ return (wladm_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 (WLADM_STATUS_NOTFOUND);
+ }
+ (void) snprintf(*prop_val, WLADM_STRSIZE, "%s", s);
+ *val_cnt = 1;
+
+ return (WLADM_STATUS_OK);
+}
+
+static wladm_status_t
+do_get_radio_prop(int fd, wldp_t *gbuf, char **prop_val, uint_t *val_cnt)
+{
+ wl_radio_t radio;
+ const char *s;
+
+ if (do_get_radio(fd, gbuf) < 0)
+ return (wladm_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 (WLADM_STATUS_NOTFOUND);
+ }
+ (void) snprintf(*prop_val, WLADM_STRSIZE, "%s", s);
+ *val_cnt = 1;
+
+ return (WLADM_STATUS_OK);
+}
+
+static int
+do_set_bsstype(int fd, wldp_t *gbuf, wladm_bsstype_t *bsstype)
+{
+ wl_bss_type_t ibsstype;
+
+ switch (*bsstype) {
+ case WLADM_BSSTYPE_BSS:
+ ibsstype = WL_BSS_BSS;
+ break;
+ case WLADM_BSSTYPE_IBSS:
+ ibsstype = WL_BSS_IBSS;
+ break;
+ default:
+ ibsstype = WL_BSS_ANY;
+ break;
+ }
+ return (do_set_ioctl(fd, gbuf, WL_BSS_TYPE, &ibsstype,
+ sizeof (ibsstype)));
+}
+
+static int
+do_set_authmode(int fd, wldp_t *gbuf, wladm_auth_t *auth)
+{
+ wl_authmode_t auth_mode;
+
+ switch (*auth) {
+ case WLADM_AUTH_OPEN:
+ auth_mode = WL_OPENSYSTEM;
+ break;
+ case WLADM_AUTH_SHARED:
+ auth_mode = WL_SHAREDKEY;
+ break;
+ default:
+ return (-1);
+ }
+ return (do_set_ioctl(fd, gbuf, WL_AUTH_MODE, &auth_mode,
+ sizeof (auth_mode)));
+}
+
+static int
+do_set_encryption(int fd, wldp_t *gbuf, wladm_secmode_t *secmode)
+{
+ wl_encryption_t encryption;
+
+ switch (*secmode) {
+ case WLADM_SECMODE_NONE:
+ encryption = WL_NOENCRYPTION;
+ break;
+ case WLADM_SECMODE_WEP:
+ encryption = WL_ENC_WEP;
+ break;
+ default:
+ return (-1);
+ }
+ return (do_set_ioctl(fd, gbuf, WL_ENCRYPTION, &encryption,
+ sizeof (encryption)));
+}
+
+static int
+do_set_wepkey(int fd, wldp_t *gbuf, wladm_wep_key_t *keys, uint_t key_count)
+{
+ int i;
+ wl_wep_key_t *wkp;
+ wl_wep_key_tab_t wepkey_tab;
+ wladm_wep_key_t *kp;
+
+ if (key_count == 0 || key_count > MAX_NWEPKEYS || keys == NULL)
+ return (-1);
+
+ (void) memset(wepkey_tab, 0, sizeof (wepkey_tab));
+ for (i = 0; i < MAX_NWEPKEYS; i++)
+ wepkey_tab[i].wl_wep_operation = WL_NUL;
+
+ for (i = 0; i < key_count; i++) {
+ kp = &keys[i];
+ if (kp->wk_idx == 0 || kp->wk_idx > MAX_NWEPKEYS)
+ return (-1);
+ if (kp->wk_len != WLADM_WEPKEY64_LEN &&
+ kp->wk_len != WLADM_WEPKEY128_LEN)
+ return (-1);
+
+ wkp = &wepkey_tab[kp->wk_idx - 1];
+ wkp->wl_wep_operation = WL_ADD;
+ wkp->wl_wep_length = kp->wk_len;
+ (void) memcpy(wkp->wl_wep_key, kp->wk_val, kp->wk_len);
+ }
+
+ return (do_set_ioctl(fd, gbuf, WL_WEP_KEY_TAB, &wepkey_tab,
+ sizeof (wepkey_tab)));
+}
+
+static int
+do_set_essid(int fd, wldp_t *gbuf, wladm_essid_t *essid)
+{
+ wl_essid_t iessid;
+
+ (void) memset(&iessid, 0, sizeof (essid));
+
+ if (essid != NULL && essid->we_bytes[0] != '\0') {
+ iessid.wl_essid_length = strlen(essid->we_bytes);
+ (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 wladm_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;
+ wladm_status_t status;
+ val_desc_t *vdp = NULL;
+
+ if (val_cnt != 1)
+ return (WLADM_STATUS_BADVALCNT);
+
+ buf = malloc((sizeof (char *) + WLADM_STRSIZE) *
+ MAX_SUPPORT_RATES);
+ if (buf == NULL)
+ goto done;
+
+ modval = (char **)(void *)buf;
+ for (i = 0; i < MAX_SUPPORT_RATES; i++) {
+ modval[i] = buf + sizeof (char *) * MAX_SUPPORT_RATES +
+ i * WLADM_STRSIZE;
+ }
+
+ status = do_get_rate_mod(fd, gbuf, modval, &modval_cnt);
+ if (status != WLADM_STATUS_OK)
+ goto done;
+
+ vdp = malloc(sizeof (val_desc_t));
+ if (vdp == NULL) {
+ status = WLADM_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 = WLADM_STATUS_OK;
+ *vdpp = vdp;
+ vdp = NULL;
+ break;
+ }
+ }
+ if (i == modval_cnt)
+ status = WLADM_STATUS_BADVAL;
+done:
+ free(buf);
+ free(vdp);
+ return (status);
+}
+
+static wladm_status_t
+do_set_rate_prop(int fd, wldp_t *gbuf, val_desc_t *vdp, uint_t val_cnt)
+{
+ wladm_rates_t rates;
+
+ if (val_cnt != 1)
+ return (WLADM_STATUS_BADVALCNT);
+
+ rates.wr_cnt = 1;
+ rates.wr_rates[0] = vdp[0].vd_val;
+
+ if (do_set_rate(fd, gbuf, &rates) < 0)
+ return (wladm_wlresult2status(gbuf));
+
+ return (WLADM_STATUS_OK);
+}
+
+static int
+do_set_rate(int fd, wldp_t *gbuf, wladm_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 wladm_status_t
+do_set_powermode_prop(int fd, wldp_t *gbuf, val_desc_t *vdp, uint_t val_cnt)
+{
+ wladm_powermode_t powermode = (wladm_powermode_t)vdp->vd_val;
+
+ if (do_set_powermode(fd, gbuf, &powermode) < 0)
+ return (wladm_wlresult2status(gbuf));
+
+ return (WLADM_STATUS_OK);
+}
+
+static int
+do_set_powermode(int fd, wldp_t *gbuf, wladm_powermode_t *pm)
+{
+ wl_ps_mode_t ps_mode;
+
+ (void) memset(&ps_mode, 0xff, sizeof (ps_mode));
+
+ switch (*pm) {
+ case WLADM_PM_OFF:
+ ps_mode.wl_ps_mode = WL_PM_AM;
+ break;
+ case WLADM_PM_MAX:
+ ps_mode.wl_ps_mode = WL_PM_MPS;
+ break;
+ case WLADM_PM_FAST:
+ ps_mode.wl_ps_mode = WL_PM_FAST;
+ break;
+ default:
+ return (-1);
+ }
+ return (do_set_ioctl(fd, gbuf, WL_POWER_MODE, &ps_mode,
+ sizeof (ps_mode)));
+}
+
+/* ARGSUSED */
+static wladm_status_t
+do_set_radio_prop(int fd, wldp_t *gbuf, val_desc_t *vdp, uint_t val_cnt)
+{
+ wladm_radio_t radio = (wladm_radio_t)vdp->vd_val;
+
+ if (do_set_radio(fd, gbuf, &radio) < 0)
+ return (wladm_wlresult2status(gbuf));
+
+ return (WLADM_STATUS_OK);
+}
+
+static int
+do_set_radio(int fd, wldp_t *gbuf, wladm_radio_t *radio)
+{
+ wl_radio_t r;
+
+ switch (*radio) {
+ case WLADM_RADIO_ON:
+ r = B_TRUE;
+ break;
+ case WLADM_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, wladm_channel_t *channel)
+{
+ wl_phy_conf_t phy_conf;
+
+ if (*channel > MAX_CHANNEL_NUM)
+ return (-1);
+
+ (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,
+ sizeof (phy_conf)));
+}
+
+static int
+do_set_createibss(int fd, wldp_t *gbuf, 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)));
+}
+
+static void
+generate_essid(wladm_essid_t *essid)
+{
+ srandom(gethrtime());
+ (void) snprintf(essid->we_bytes, WLADM_MAX_ESSID_LEN, "%d", random());
+}
diff --git a/usr/src/lib/libwladm/common/libwladm.h b/usr/src/lib/libwladm/common/libwladm.h
new file mode 100644
index 0000000000..0a5d24df9e
--- /dev/null
+++ b/usr/src/lib/libwladm/common/libwladm.h
@@ -0,0 +1,209 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _LIBWLADM_H
+#define _LIBWLADM_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+
+/*
+ * General libwladm definitions and functions.
+ *
+ * These interfaces are ON consolidation-private.
+ * For documentation, refer to PSARC/2006/623.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define WLADM_MAX_ESSID_LEN 32 /* per 802.11 spec */
+#define WLADM_BSSID_LEN 6 /* per 802.11 spec */
+#define WLADM_STRSIZE 256
+
+#define WLADM_CONNECT_TIMEOUT_DEFAULT 10
+#define WLADM_OPT_CREATEIBSS 0x00000001
+#define WLADM_OPT_NOSCAN 0x00000002
+
+typedef struct wladm_essid {
+ char we_bytes[WLADM_MAX_ESSID_LEN];
+} wladm_essid_t;
+
+typedef struct wladm_bssid {
+ uint8_t wb_bytes[WLADM_BSSID_LEN];
+} wladm_bssid_t;
+
+typedef enum {
+ WLADM_SECMODE_NONE = 1,
+ WLADM_SECMODE_WEP
+} wladm_secmode_t;
+
+typedef enum {
+ WLADM_STRENGTH_VERY_WEAK = 1,
+ WLADM_STRENGTH_WEAK,
+ WLADM_STRENGTH_GOOD,
+ WLADM_STRENGTH_VERY_GOOD,
+ WLADM_STRENGTH_EXCELLENT
+} wladm_strength_t;
+
+typedef enum {
+ WLADM_MODE_NONE = 0,
+ WLADM_MODE_80211A,
+ WLADM_MODE_80211B,
+ WLADM_MODE_80211G
+} wladm_mode_t;
+
+typedef enum {
+ WLADM_AUTH_OPEN = 1,
+ WLADM_AUTH_SHARED
+} wladm_auth_t;
+
+typedef enum {
+ WLADM_BSSTYPE_BSS = 1,
+ WLADM_BSSTYPE_IBSS,
+ WLADM_BSSTYPE_ANY
+} wladm_bsstype_t;
+
+typedef enum {
+ WLADM_LINK_STATUS_DISCONNECTED = 1,
+ WLADM_LINK_STATUS_CONNECTED
+} wladm_linkstatus_t;
+
+typedef enum {
+ WLADM_STATUS_OK = 0,
+ WLADM_STATUS_BADARG,
+ WLADM_STATUS_FAILED,
+ WLADM_STATUS_NOTSUP,
+ WLADM_STATUS_ISCONN,
+ WLADM_STATUS_NOTCONN,
+ WLADM_STATUS_NOTFOUND,
+ WLADM_STATUS_BADVAL,
+ WLADM_STATUS_LINKINVAL,
+ WLADM_STATUS_NOMEM,
+ WLADM_STATUS_TIMEDOUT,
+ WLADM_STATUS_PROPRDONLY,
+ WLADM_STATUS_TOOSMALL,
+ WLADM_STATUS_BADVALCNT
+} wladm_status_t;
+
+typedef uint32_t wladm_speed_t;
+typedef uint32_t wladm_channel_t;
+
+enum {
+ WLADM_WLAN_ATTR_ESSID = 0x00000001,
+ WLADM_WLAN_ATTR_BSSID = 0x00000002,
+ WLADM_WLAN_ATTR_SECMODE = 0x00000004,
+ WLADM_WLAN_ATTR_STRENGTH = 0x00000008,
+ WLADM_WLAN_ATTR_MODE = 0x00000010,
+ WLADM_WLAN_ATTR_SPEED = 0x00000020,
+ WLADM_WLAN_ATTR_AUTH = 0x00000040,
+ WLADM_WLAN_ATTR_BSSTYPE = 0x00000080,
+ WLADM_WLAN_ATTR_CHANNEL = 0x00000100
+};
+typedef struct wladm_wlan_attr {
+ uint_t wa_valid;
+ wladm_essid_t wa_essid;
+ wladm_bssid_t wa_bssid;
+ wladm_secmode_t wa_secmode;
+ wladm_strength_t wa_strength;
+ wladm_mode_t wa_mode;
+ wladm_speed_t wa_speed;
+ wladm_auth_t wa_auth;
+ wladm_bsstype_t wa_bsstype;
+ wladm_channel_t wa_channel;
+} wladm_wlan_attr_t;
+
+enum {
+ WLADM_LINK_ATTR_STATUS = 0x00000001,
+ WLADM_LINK_ATTR_WLAN = 0x00000002
+};
+typedef struct wladm_link_attr {
+ uint_t la_valid;
+ wladm_linkstatus_t la_status;
+ wladm_wlan_attr_t la_wlan_attr;
+} wladm_link_attr_t;
+
+#define WLADM_WEPKEY64_LEN 5 /* per WEP spec */
+#define WLADM_WEPKEY128_LEN 13 /* per WEP spec */
+#define WLADM_MAX_WEPKEY_LEN 13 /* per WEP spec */
+#define WLADM_MAX_WEPKEYS 4 /* MAX_NWEPKEYS */
+#define WLADM_MAX_WEPKEYNAME_LEN 64
+typedef struct wladm_wep_key {
+ uint_t wk_idx;
+ uint_t wk_len;
+ uint8_t wk_val[WLADM_MAX_WEPKEY_LEN];
+ char wk_name[WLADM_MAX_WEPKEYNAME_LEN];
+} wladm_wep_key_t;
+
+typedef enum {
+ WLADM_PROP_VAL_CURRENT = 1,
+ WLADM_PROP_VAL_DEFAULT,
+ WLADM_PROP_VAL_MODIFIABLE
+} wladm_prop_type_t;
+
+extern wladm_status_t wladm_scan(const char *, void *,
+ boolean_t (*)(void *, wladm_wlan_attr_t *));
+extern wladm_status_t wladm_connect(const char *, wladm_wlan_attr_t *,
+ int, void *, uint_t, uint_t);
+extern wladm_status_t wladm_disconnect(const char *);
+extern wladm_status_t wladm_get_link_attr(const char *, wladm_link_attr_t *);
+extern wladm_status_t wladm_walk(void *, boolean_t (*)(void *, const char *));
+extern boolean_t wladm_is_valid(const char *);
+extern wladm_status_t wladm_set_prop(const char *, const char *, char **,
+ uint_t);
+extern wladm_status_t wladm_walk_prop(const char *, void *,
+ boolean_t (*)(void *, const char *));
+extern wladm_status_t wladm_get_prop(const char *, wladm_prop_type_t,
+ const char *, char **, uint_t *);
+
+extern const char *wladm_essid2str(wladm_essid_t *, char *);
+extern const char *wladm_bssid2str(wladm_bssid_t *, char *);
+extern const char *wladm_secmode2str(wladm_secmode_t *, char *);
+extern const char *wladm_strength2str(wladm_strength_t *, char *);
+extern const char *wladm_mode2str(wladm_mode_t *, char *);
+extern const char *wladm_speed2str(wladm_speed_t *, char *);
+extern const char *wladm_auth2str(wladm_auth_t *, char *);
+extern const char *wladm_bsstype2str(wladm_bsstype_t *, char *);
+extern const char *wladm_linkstatus2str(wladm_linkstatus_t *, char *);
+extern const char *wladm_status2str(wladm_status_t, char *);
+
+extern wladm_status_t wladm_str2essid(const char *, wladm_essid_t *);
+extern wladm_status_t wladm_str2bssid(const char *, wladm_bssid_t *);
+extern wladm_status_t wladm_str2secmode(const char *, wladm_secmode_t *);
+extern wladm_status_t wladm_str2strength(const char *, wladm_strength_t *);
+extern wladm_status_t wladm_str2mode(const char *, wladm_mode_t *);
+extern wladm_status_t wladm_str2speed(const char *, wladm_speed_t *);
+extern wladm_status_t wladm_str2auth(const char *, wladm_auth_t *);
+extern wladm_status_t wladm_str2bsstype(const char *, wladm_bsstype_t *);
+extern wladm_status_t wladm_str2linkstatus(const char *,
+ wladm_linkstatus_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBWLADM_H */
diff --git a/usr/src/lib/libwladm/common/libwladm_impl.h b/usr/src/lib/libwladm/common/libwladm_impl.h
new file mode 100644
index 0000000000..e3dfbd7ea0
--- /dev/null
+++ b/usr/src/lib/libwladm/common/libwladm_impl.h
@@ -0,0 +1,82 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _LIBWLADM_IMPL_H
+#define _LIBWLADM_IMPL_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <inet/wifi_ioctl.h>
+
+/*
+ * Implementation-private data structures, macros, and constants.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Map a signal value from 0-15 into an enumerated strength. Since there are
+ * 5 strengths but 16 values, by convention the "middle" strength gets the
+ * extra value. Thus, the buckets are 0-2, 3-5, 6-9, 10-12, and 13-15.
+ */
+#define WLADM_SIGNAL2STRENGTH(signal) \
+ (((signal) > 12 ? WLADM_STRENGTH_EXCELLENT : \
+ ((signal) > 9 ? WLADM_STRENGTH_VERY_GOOD : \
+ ((signal) > 5 ? WLADM_STRENGTH_GOOD : \
+ ((signal) > 2 ? WLADM_STRENGTH_WEAK : WLADM_STRENGTH_VERY_WEAK)))))
+
+/*
+ * Convert between an OFDM MHz and a channel number.
+ */
+#define WLADM_OFDM2CHAN(mhz) (((mhz) - 5000) / 5)
+
+#define WLADM_CONNECT_POLLRATE 200000000 /* nanoseconds */
+#define WLADM_CONNECT_DEFAULT_CHANNEL 1
+
+#define WLADM_MAX_RATES 4
+typedef struct wladm_rates {
+ uint8_t wr_rates[WLADM_MAX_RATES];
+ int wr_cnt;
+} wladm_rates_t;
+
+typedef enum {
+ WLADM_RADIO_ON = 1,
+ WLADM_RADIO_OFF
+} wladm_radio_t;
+
+typedef enum {
+ WLADM_PM_OFF = 1,
+ WLADM_PM_MAX,
+ WLADM_PM_FAST
+} wladm_powermode_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBWLADM_IMPL_H */
diff --git a/usr/src/lib/libwladm/common/llib-lwladm b/usr/src/lib/libwladm/common/llib-lwladm
new file mode 100644
index 0000000000..1f233e14ec
--- /dev/null
+++ b/usr/src/lib/libwladm/common/llib-lwladm
@@ -0,0 +1,31 @@
+/*
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*LINTLIBRARY*/
+/*PROTOLIB1*/
+
+#include <libwladm.h>
diff --git a/usr/src/lib/libwladm/common/mapfile-vers b/usr/src/lib/libwladm/common/mapfile-vers
new file mode 100644
index 0000000000..c5f00d22b4
--- /dev/null
+++ b/usr/src/lib/libwladm/common/mapfile-vers
@@ -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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+SUNWprivate_1.1 {
+ global:
+ wladm_scan;
+ wladm_connect;
+ wladm_disconnect;
+ wladm_get_link_attr;
+ wladm_walk;
+ wladm_is_valid;
+ wladm_set_prop;
+ wladm_walk_prop;
+ wladm_get_prop;
+ wladm_essid2str;
+ wladm_bssid2str;
+ wladm_secmode2str;
+ wladm_strength2str;
+ wladm_mode2str;
+ wladm_speed2str;
+ wladm_auth2str;
+ wladm_bsstype2str;
+ wladm_linkstatus2str;
+ wladm_status2str;
+ wladm_str2essid;
+ wladm_str2bssid;
+ wladm_str2secmode;
+ wladm_str2strength;
+ wladm_str2mode;
+ wladm_str2speed;
+ wladm_str2auth;
+ wladm_str2bsstype;
+ wladm_str2linkstatus;
+ local:
+ *;
+};
diff --git a/usr/src/lib/libwladm/i386/Makefile b/usr/src/lib/libwladm/i386/Makefile
new file mode 100644
index 0000000000..a333224278
--- /dev/null
+++ b/usr/src/lib/libwladm/i386/Makefile
@@ -0,0 +1,30 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/libwladm/sparc/Makefile b/usr/src/lib/libwladm/sparc/Makefile
new file mode 100644
index 0000000000..a333224278
--- /dev/null
+++ b/usr/src/lib/libwladm/sparc/Makefile
@@ -0,0 +1,30 @@
+#
+# 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 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)