summaryrefslogtreecommitdiff
path: root/usr/src/lib/libdladm/common
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libdladm/common')
-rw-r--r--usr/src/lib/libdladm/common/libdladm.c274
-rw-r--r--usr/src/lib/libdladm/common/libdladm.h72
-rw-r--r--usr/src/lib/libdladm/common/libdladm_impl.h51
-rw-r--r--usr/src/lib/libdladm/common/linkprop.c700
-rw-r--r--usr/src/lib/libdladm/common/mapfile-vers14
-rw-r--r--usr/src/lib/libdladm/common/secobj.c634
6 files changed, 1728 insertions, 17 deletions
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));
+}