diff options
Diffstat (limited to 'usr/src/lib')
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> +</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) |