130588217SMike Christensen /*
230588217SMike Christensen * CDDL HEADER START
330588217SMike Christensen *
430588217SMike Christensen * The contents of this file are subject to the terms of the
530588217SMike Christensen * Common Development and Distribution License (the "License").
630588217SMike Christensen * You may not use this file except in compliance with the License.
730588217SMike Christensen *
830588217SMike Christensen * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
930588217SMike Christensen * or http://www.opensolaris.org/os/licensing.
1030588217SMike Christensen * See the License for the specific language governing permissions
1130588217SMike Christensen * and limitations under the License.
1230588217SMike Christensen *
1330588217SMike Christensen * When distributing Covered Code, include this CDDL HEADER in each
1430588217SMike Christensen * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1530588217SMike Christensen * If applicable, add the following below this CDDL HEADER, with the
1630588217SMike Christensen * fields enclosed by brackets "[]" replaced with your own identifying
1730588217SMike Christensen * information: Portions Copyright [yyyy] [name of copyright owner]
1830588217SMike Christensen *
1930588217SMike Christensen * CDDL HEADER END
2030588217SMike Christensen */
2130588217SMike Christensen /*
22*49b225e1SGavin Maltby * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
2330588217SMike Christensen * Use is subject to license terms.
2430588217SMike Christensen */
2530588217SMike Christensen
2630588217SMike Christensen #include <stdio.h>
2730588217SMike Christensen #include <fcntl.h>
2830588217SMike Christensen #include <unistd.h>
2930588217SMike Christensen #include <stdlib.h>
3030588217SMike Christensen #include <strings.h>
3130588217SMike Christensen #include <errno.h>
3230588217SMike Christensen #include <sys/types.h>
3330588217SMike Christensen #include <sys/sysevent.h>
3430588217SMike Christensen #include <libsysevent.h>
3530588217SMike Christensen #include <sys/vlds.h>
3630588217SMike Christensen #include "libds.h"
3730588217SMike Christensen
3830588217SMike Christensen #define PTRTOUINT64(ptr) ((uint64_t)((uintptr_t)(ptr)))
3930588217SMike Christensen static char vlds_device[] =
4030588217SMike Christensen "/devices/virtual-devices@100/channel-devices@200/"
4130588217SMike Christensen "virtual-domain-service@0:vlds";
4230588217SMike Christensen
4330588217SMike Christensen typedef struct dslibentry {
4430588217SMike Christensen ds_hdl_t dsl_hdl;
4530588217SMike Christensen uint32_t dsl_flags;
46ba9236fbSMike Christensen uint32_t dsl_tflags;
4730588217SMike Christensen char *dsl_service;
4830588217SMike Christensen ds_ops_t dsl_ops;
4930588217SMike Christensen } dslibentry_t;
5030588217SMike Christensen
51ba9236fbSMike Christensen /* dsl_tflags */
52ba9236fbSMike Christensen #define DSL_ENTRY_INUSE 0x0001 /* handle is currently active */
53ba9236fbSMike Christensen
5430588217SMike Christensen #define MIN_DSLIB_ENTRIES 64
5530588217SMike Christensen static dslibentry_t *dslibtab;
5630588217SMike Christensen static int ndslib;
5730588217SMike Christensen
5830588217SMike Christensen /*
5930588217SMike Christensen * Lock to protect the dslibtab table. We only need to protect this
6030588217SMike Christensen * table for those functions which actually look at or modify the table:
6130588217SMike Christensen * service registration (ds_svc_reg/ds_clnt_reg), service unregistration
6230588217SMike Christensen * (ds_hdl_unreg) or during callbacks (ds_recv)
6330588217SMike Christensen */
6430588217SMike Christensen static mutex_t dslib_lock;
6530588217SMike Christensen
6630588217SMike Christensen static int ds_fd = -1;
6730588217SMike Christensen
6830588217SMike Christensen static char *ds_sid_name = "vlds";
6930588217SMike Christensen
7030588217SMike Christensen static evchan_t *ds_evchan;
7130588217SMike Christensen
7230588217SMike Christensen /*
7330588217SMike Christensen * Static functions internal to dslib.
7430588217SMike Christensen */
7530588217SMike Christensen static dslibentry_t *ds_hdl_to_dslibentry(ds_hdl_t hdl);
76ba9236fbSMike Christensen static dslibentry_t *ds_new_dslibentry(void);
77ba9236fbSMike Christensen static uint_t ds_service_count(char *service, boolean_t is_client);
7830588217SMike Christensen static dslibentry_t *ds_lookup_dslibentry(char *service, boolean_t is_client);
7930588217SMike Christensen static dslibentry_t *ds_register_dslibentry(ds_hdl_t hdl, char *service,
8030588217SMike Christensen boolean_t is_client);
8130588217SMike Christensen static void ds_free_dslibentry(dslibentry_t *dsp, int force_unreg);
8230588217SMike Christensen static int ds_recv(sysevent_t *sep, void *arg);
8330588217SMike Christensen static void ds_string_arg(vlds_string_t *dsp, char *str);
8430588217SMike Christensen static int ds_register(ds_capability_t *cap, ds_ops_t *ops, uint_t flags);
8530588217SMike Christensen
8630588217SMike Christensen static dslibentry_t *
ds_hdl_to_dslibentry(ds_hdl_t hdl)8730588217SMike Christensen ds_hdl_to_dslibentry(ds_hdl_t hdl)
8830588217SMike Christensen {
8930588217SMike Christensen int i;
9030588217SMike Christensen dslibentry_t *dsp;
9130588217SMike Christensen
9230588217SMike Christensen for (i = 0, dsp = dslibtab; i < ndslib; i++, dsp++) {
9330588217SMike Christensen if (hdl == dsp->dsl_hdl)
9430588217SMike Christensen return (dsp);
9530588217SMike Christensen }
9630588217SMike Christensen return (NULL);
9730588217SMike Christensen }
9830588217SMike Christensen
9930588217SMike Christensen static dslibentry_t *
ds_new_dslibentry(void)10030588217SMike Christensen ds_new_dslibentry(void)
10130588217SMike Christensen {
10230588217SMike Christensen int newndslib;
10330588217SMike Christensen dslibentry_t *dsp;
10430588217SMike Christensen
10530588217SMike Christensen if ((dsp = ds_hdl_to_dslibentry(NULL)) != NULL)
10630588217SMike Christensen return (dsp);
10730588217SMike Christensen
10830588217SMike Christensen /* double the size */
10930588217SMike Christensen newndslib = ndslib << 1;
11030588217SMike Christensen if ((dslibtab = realloc(dslibtab, newndslib * sizeof (dslibentry_t)))
11130588217SMike Christensen == NULL)
11230588217SMike Christensen return (NULL);
11330588217SMike Christensen dsp = &dslibtab[ndslib];
11430588217SMike Christensen (void) memset(dsp, 0, (newndslib - ndslib) * sizeof (dslibentry_t));
11530588217SMike Christensen ndslib = newndslib;
11630588217SMike Christensen return (dsp);
11730588217SMike Christensen }
11830588217SMike Christensen
119ba9236fbSMike Christensen static uint_t
ds_service_count(char * service,boolean_t is_client)120ba9236fbSMike Christensen ds_service_count(char *service, boolean_t is_client)
121ba9236fbSMike Christensen {
122ba9236fbSMike Christensen int i;
123ba9236fbSMike Christensen dslibentry_t *dsp;
124ba9236fbSMike Christensen uint_t is_client_flag = is_client ? VLDS_REG_CLIENT : 0;
125ba9236fbSMike Christensen uint_t count = 0;
126ba9236fbSMike Christensen
127ba9236fbSMike Christensen for (i = 0, dsp = dslibtab; i < ndslib; i++, dsp++) {
128ba9236fbSMike Christensen if (dsp->dsl_hdl != NULL &&
129ba9236fbSMike Christensen strcmp(dsp->dsl_service, service) == 0 &&
130ba9236fbSMike Christensen (dsp->dsl_flags & VLDS_REG_CLIENT) == is_client_flag) {
131ba9236fbSMike Christensen count++;
132ba9236fbSMike Christensen }
133ba9236fbSMike Christensen }
134ba9236fbSMike Christensen return (count);
135ba9236fbSMike Christensen }
136ba9236fbSMike Christensen
13730588217SMike Christensen static dslibentry_t *
ds_lookup_dslibentry(char * service,boolean_t is_client)13830588217SMike Christensen ds_lookup_dslibentry(char *service, boolean_t is_client)
13930588217SMike Christensen {
14030588217SMike Christensen int i;
14130588217SMike Christensen dslibentry_t *dsp;
14230588217SMike Christensen uint_t is_client_flag = is_client ? VLDS_REG_CLIENT : 0;
14330588217SMike Christensen
14430588217SMike Christensen for (i = 0, dsp = dslibtab; i < ndslib; i++, dsp++) {
14530588217SMike Christensen if (dsp->dsl_hdl != NULL &&
14630588217SMike Christensen strcmp(dsp->dsl_service, service) == 0 &&
14730588217SMike Christensen (dsp->dsl_flags & VLDS_REG_CLIENT) == is_client_flag) {
14830588217SMike Christensen return (dsp);
14930588217SMike Christensen }
15030588217SMike Christensen }
15130588217SMike Christensen return (NULL);
15230588217SMike Christensen }
15330588217SMike Christensen
15430588217SMike Christensen static dslibentry_t *
ds_register_dslibentry(ds_hdl_t hdl,char * service,boolean_t is_client)15530588217SMike Christensen ds_register_dslibentry(ds_hdl_t hdl, char *service, boolean_t is_client)
15630588217SMike Christensen {
15730588217SMike Christensen dslibentry_t *dsp, *orig_dsp;
15830588217SMike Christensen
159ba9236fbSMike Christensen if ((dsp = ds_hdl_to_dslibentry(hdl)) != NULL) {
160ba9236fbSMike Christensen dsp->dsl_tflags |= DSL_ENTRY_INUSE;
16130588217SMike Christensen return (dsp);
162ba9236fbSMike Christensen }
16330588217SMike Christensen
16430588217SMike Christensen if ((orig_dsp = ds_lookup_dslibentry(service, is_client)) == NULL) {
16530588217SMike Christensen return (NULL);
16630588217SMike Christensen }
16730588217SMike Christensen
168ba9236fbSMike Christensen if ((orig_dsp->dsl_tflags & DSL_ENTRY_INUSE) == 0) {
169ba9236fbSMike Christensen /* use the original structure entry */
170ba9236fbSMike Christensen orig_dsp->dsl_tflags |= DSL_ENTRY_INUSE;
171ba9236fbSMike Christensen orig_dsp->dsl_hdl = hdl;
172ba9236fbSMike Christensen return (orig_dsp);
173ba9236fbSMike Christensen }
17430588217SMike Christensen
17530588217SMike Christensen /* allocate a new structure entry */
17630588217SMike Christensen if ((dsp = ds_new_dslibentry()) == NULL)
17730588217SMike Christensen return (NULL);
178ba9236fbSMike Christensen
17930588217SMike Christensen *dsp = *orig_dsp;
18030588217SMike Christensen dsp->dsl_service = strdup(orig_dsp->dsl_service);
18130588217SMike Christensen dsp->dsl_hdl = hdl;
18230588217SMike Christensen return (dsp);
18330588217SMike Christensen }
18430588217SMike Christensen
18530588217SMike Christensen /*
18630588217SMike Christensen * Want to leave an entry in the dslib table even though all the
18730588217SMike Christensen * handles may have been unregistered for it.
18830588217SMike Christensen */
18930588217SMike Christensen static void
ds_free_dslibentry(dslibentry_t * dsp,int force_unreg)19030588217SMike Christensen ds_free_dslibentry(dslibentry_t *dsp, int force_unreg)
19130588217SMike Christensen {
19230588217SMike Christensen uint_t nhdls;
19330588217SMike Christensen
19430588217SMike Christensen /*
195ba9236fbSMike Christensen * Find out if we have 1 or 2 or more handles for the given
196ba9236fbSMike Christensen * service. Having one implies that we want to leave the entry
197ba9236fbSMike Christensen * intact but marked as not in use unless this is a ds_unreg_hdl
19830588217SMike Christensen * (force_unreg is true).
19930588217SMike Christensen */
200ba9236fbSMike Christensen nhdls = ds_service_count(dsp->dsl_service,
201ba9236fbSMike Christensen (dsp->dsl_flags & VLDS_REG_CLIENT) != 0);
20230588217SMike Christensen
203ba9236fbSMike Christensen if ((nhdls == 1 && force_unreg) || nhdls >= 2) {
20430588217SMike Christensen dsp->dsl_hdl = NULL;
20530588217SMike Christensen if (dsp->dsl_service) {
20630588217SMike Christensen free(dsp->dsl_service);
20730588217SMike Christensen }
20830588217SMike Christensen (void) memset(dsp, 0, sizeof (dslibentry_t));
209ba9236fbSMike Christensen } else if (nhdls == 1) {
210ba9236fbSMike Christensen dsp->dsl_tflags &= ~DSL_ENTRY_INUSE;
21130588217SMike Christensen }
21230588217SMike Christensen }
21330588217SMike Christensen
21430588217SMike Christensen /*ARGSUSED*/
21530588217SMike Christensen static int
ds_recv(sysevent_t * sep,void * arg)21630588217SMike Christensen ds_recv(sysevent_t *sep, void *arg)
21730588217SMike Christensen {
21830588217SMike Christensen nvlist_t *nvl;
21930588217SMike Christensen uint64_t hdl;
22030588217SMike Christensen ds_ver_t ver;
22130588217SMike Christensen ds_domain_hdl_t dhdl;
22230588217SMike Christensen uchar_t *bufp;
22330588217SMike Christensen boolean_t is_client;
22430588217SMike Christensen uint_t buflen;
22530588217SMike Christensen char *subclass;
22630588217SMike Christensen char *servicep;
22730588217SMike Christensen dslibentry_t *dsp;
22830588217SMike Christensen ds_cb_arg_t cb_arg;
22930588217SMike Christensen
23030588217SMike Christensen subclass = sysevent_get_subclass_name(sep);
23130588217SMike Christensen if (sysevent_get_attr_list(sep, &nvl) != 0) {
23230588217SMike Christensen return (0);
23330588217SMike Christensen }
23430588217SMike Christensen
23530588217SMike Christensen if (nvlist_lookup_uint64(nvl, VLDS_HDL, &hdl) == 0) {
23630588217SMike Christensen if (strcmp(subclass, ESC_VLDS_REGISTER) == 0) {
23730588217SMike Christensen void (*reg_cb)(ds_hdl_t, ds_cb_arg_t, ds_ver_t *,
23830588217SMike Christensen ds_domain_hdl_t) = NULL;
23930588217SMike Christensen
24030588217SMike Christensen if (nvlist_lookup_string(nvl, VLDS_SERVICE_ID,
24130588217SMike Christensen &servicep) == 0 &&
24230588217SMike Christensen nvlist_lookup_boolean_value(nvl, VLDS_ISCLIENT,
24330588217SMike Christensen &is_client) == 0) {
24430588217SMike Christensen (void) mutex_lock(&dslib_lock);
24530588217SMike Christensen if ((dsp = ds_register_dslibentry(hdl,
24630588217SMike Christensen servicep, is_client)) != NULL) {
24730588217SMike Christensen reg_cb = dsp->dsl_ops.ds_reg_cb;
24830588217SMike Christensen cb_arg = dsp->dsl_ops.cb_arg;
24930588217SMike Christensen }
25030588217SMike Christensen (void) mutex_unlock(&dslib_lock);
25130588217SMike Christensen if (reg_cb != NULL &&
25230588217SMike Christensen nvlist_lookup_uint64(nvl, VLDS_DOMAIN_HDL,
25330588217SMike Christensen &dhdl) == 0 &&
25430588217SMike Christensen nvlist_lookup_uint16(nvl, VLDS_VER_MAJOR,
25530588217SMike Christensen &ver.major) == 0 &&
25630588217SMike Christensen nvlist_lookup_uint16(nvl, VLDS_VER_MINOR,
25730588217SMike Christensen &ver.minor) == 0) {
25830588217SMike Christensen (reg_cb)((ds_hdl_t)hdl, cb_arg, &ver,
25930588217SMike Christensen dhdl);
26030588217SMike Christensen }
26130588217SMike Christensen }
26230588217SMike Christensen } else if (strcmp(subclass, ESC_VLDS_UNREGISTER) == 0) {
26330588217SMike Christensen void (*unreg_cb)(ds_hdl_t, ds_cb_arg_t) = NULL;
26430588217SMike Christensen
26530588217SMike Christensen (void) mutex_lock(&dslib_lock);
26630588217SMike Christensen if ((dsp = ds_hdl_to_dslibentry(hdl)) != NULL) {
26730588217SMike Christensen unreg_cb = dsp->dsl_ops.ds_unreg_cb;
26830588217SMike Christensen cb_arg = dsp->dsl_ops.cb_arg;
26930588217SMike Christensen ds_free_dslibentry(dsp, 0);
27030588217SMike Christensen }
27130588217SMike Christensen (void) mutex_unlock(&dslib_lock);
27230588217SMike Christensen if (unreg_cb != NULL) {
27330588217SMike Christensen (unreg_cb)((ds_hdl_t)hdl, cb_arg);
27430588217SMike Christensen }
27530588217SMike Christensen } else if (strcmp(subclass, ESC_VLDS_DATA) == 0) {
27630588217SMike Christensen void (*data_cb)(ds_hdl_t, ds_cb_arg_t, void *,
27730588217SMike Christensen size_t) = NULL;
27830588217SMike Christensen
27930588217SMike Christensen (void) mutex_lock(&dslib_lock);
28030588217SMike Christensen if ((dsp = ds_hdl_to_dslibentry(hdl)) != NULL) {
28130588217SMike Christensen data_cb = dsp->dsl_ops.ds_data_cb;
28230588217SMike Christensen cb_arg = dsp->dsl_ops.cb_arg;
28330588217SMike Christensen }
28430588217SMike Christensen (void) mutex_unlock(&dslib_lock);
28530588217SMike Christensen if (data_cb != NULL &&
28630588217SMike Christensen nvlist_lookup_byte_array(nvl, VLDS_DATA, &bufp,
28730588217SMike Christensen &buflen) == 0) {
28830588217SMike Christensen (data_cb)((ds_hdl_t)hdl, cb_arg, bufp, buflen);
28930588217SMike Christensen }
29030588217SMike Christensen }
29130588217SMike Christensen }
29230588217SMike Christensen nvlist_free(nvl);
29330588217SMike Christensen return (0);
29430588217SMike Christensen }
29530588217SMike Christensen
29630588217SMike Christensen static void
ds_string_arg(vlds_string_t * dsp,char * str)29730588217SMike Christensen ds_string_arg(vlds_string_t *dsp, char *str)
29830588217SMike Christensen {
29930588217SMike Christensen if (str == NULL) {
30030588217SMike Christensen dsp->vlds_strp = NULL;
30130588217SMike Christensen dsp->vlds_strlen = 0;
30230588217SMike Christensen } else {
30330588217SMike Christensen dsp->vlds_strp = PTRTOUINT64(str);
30430588217SMike Christensen dsp->vlds_strlen = strlen(str) + 1;
30530588217SMike Christensen }
30630588217SMike Christensen }
30730588217SMike Christensen
30830588217SMike Christensen static int
ds_init_sysev(void)30930588217SMike Christensen ds_init_sysev(void)
31030588217SMike Christensen {
31130588217SMike Christensen char evchan_name[MAX_CHNAME_LEN];
31230588217SMike Christensen
31330588217SMike Christensen (void) sprintf(evchan_name, VLDS_SYSEV_CHAN_FMT, (int)getpid());
31430588217SMike Christensen if (sysevent_evc_bind(evchan_name, &ds_evchan, 0) != 0) {
31530588217SMike Christensen return (errno);
31630588217SMike Christensen }
31730588217SMike Christensen if (sysevent_evc_subscribe(ds_evchan, ds_sid_name, EC_VLDS,
31830588217SMike Christensen ds_recv, NULL, 0) != 0) {
319*49b225e1SGavin Maltby (void) sysevent_evc_unbind(ds_evchan);
32030588217SMike Christensen ds_evchan = NULL;
32130588217SMike Christensen return (errno);
32230588217SMike Christensen }
32330588217SMike Christensen return (0);
32430588217SMike Christensen }
32530588217SMike Christensen
32630588217SMike Christensen int
ds_init(void)32730588217SMike Christensen ds_init(void)
32830588217SMike Christensen {
32930588217SMike Christensen if (ds_fd >= 0)
33030588217SMike Christensen return (0);
33130588217SMike Christensen
33230588217SMike Christensen if ((ds_fd = open(vlds_device, 0)) < 0)
33330588217SMike Christensen return (errno);
33430588217SMike Christensen
33530588217SMike Christensen if (dslibtab == NULL) {
336ba9236fbSMike Christensen dslibtab = malloc(sizeof (dslibentry_t) * MIN_DSLIB_ENTRIES);
337ba9236fbSMike Christensen if (dslibtab == NULL)
33830588217SMike Christensen return (errno = ENOMEM);
33930588217SMike Christensen ndslib = MIN_DSLIB_ENTRIES;
34030588217SMike Christensen (void) memset(dslibtab, 0, sizeof (dslibentry_t) * ndslib);
34130588217SMike Christensen }
34230588217SMike Christensen
34330588217SMike Christensen (void) mutex_init(&dslib_lock, USYNC_THREAD, NULL);
34430588217SMike Christensen return (0);
34530588217SMike Christensen }
34630588217SMike Christensen
34730588217SMike Christensen static int
ds_register(ds_capability_t * cap,ds_ops_t * ops,uint_t flags)34830588217SMike Christensen ds_register(ds_capability_t *cap, ds_ops_t *ops, uint_t flags)
34930588217SMike Christensen {
35030588217SMike Christensen dslibentry_t *dsp;
35130588217SMike Christensen vlds_svc_reg_arg_t vlds_arg;
35230588217SMike Christensen vlds_cap_t vlds_cap;
35330588217SMike Christensen vlds_ver_t vlds_vers[VLDS_MAX_VERS];
35430588217SMike Christensen uint64_t hdl_arg;
35530588217SMike Christensen ds_hdl_t hdl;
35630588217SMike Christensen uint_t nhdls;
35730588217SMike Christensen int i;
35830588217SMike Christensen
35930588217SMike Christensen if (cap == NULL || ops == NULL || cap->svc_id == NULL ||
36030588217SMike Christensen cap->vers == NULL || (flags & (~VLDS_REG_CLIENT)) != 0) {
36130588217SMike Christensen return (errno = EINVAL);
36230588217SMike Christensen }
36330588217SMike Christensen
36430588217SMike Christensen if (cap->nvers > VLDS_MAX_VERS) {
36530588217SMike Christensen return (errno = EINVAL);
36630588217SMike Christensen }
36730588217SMike Christensen
36830588217SMike Christensen if (ds_fd < 0 && (errno = ds_init()) != 0) {
36930588217SMike Christensen return (errno);
37030588217SMike Christensen }
37130588217SMike Christensen
37230588217SMike Christensen if (ds_hdl_lookup(cap->svc_id, (flags & VLDS_REG_CLIENT), NULL, 1,
37330588217SMike Christensen &nhdls) == 0 && nhdls == 1) {
37430588217SMike Christensen return (errno = EALREADY);
37530588217SMike Christensen }
37630588217SMike Christensen
37730588217SMike Christensen (void) mutex_lock(&dslib_lock);
37830588217SMike Christensen if ((dsp = ds_new_dslibentry()) == NULL) {
37930588217SMike Christensen (void) mutex_unlock(&dslib_lock);
38030588217SMike Christensen return (errno = ENOMEM);
38130588217SMike Christensen }
38230588217SMike Christensen
38330588217SMike Christensen /* Setup device driver capability structure. */
38430588217SMike Christensen
38530588217SMike Christensen /* service string */
38630588217SMike Christensen ds_string_arg(&vlds_cap.vlds_service, cap->svc_id);
38730588217SMike Christensen
38830588217SMike Christensen /* version array */
38930588217SMike Christensen for (i = 0; i < cap->nvers; i++) {
39030588217SMike Christensen vlds_vers[i].vlds_major = cap->vers[i].major;
39130588217SMike Christensen vlds_vers[i].vlds_minor = cap->vers[i].minor;
39230588217SMike Christensen }
39330588217SMike Christensen vlds_cap.vlds_versp = PTRTOUINT64(vlds_vers);
39430588217SMike Christensen vlds_cap.vlds_nver = cap->nvers;
39530588217SMike Christensen
39630588217SMike Christensen /*
39730588217SMike Christensen * Format args for VLDS_SVC_REG ioctl.
39830588217SMike Christensen */
39930588217SMike Christensen
40030588217SMike Christensen vlds_arg.vlds_capp = PTRTOUINT64(&vlds_cap);
40130588217SMike Christensen
40230588217SMike Christensen /* op flags */
40330588217SMike Christensen if (ops->ds_reg_cb != NULL)
40430588217SMike Christensen flags |= VLDS_REGCB_VALID;
40530588217SMike Christensen if (ops->ds_unreg_cb != NULL)
40630588217SMike Christensen flags |= VLDS_UNREGCB_VALID;
40730588217SMike Christensen if (ops->ds_data_cb != NULL)
40830588217SMike Christensen flags |= VLDS_DATACB_VALID;
40930588217SMike Christensen vlds_arg.vlds_reg_flags = flags;
41030588217SMike Christensen
41130588217SMike Christensen /* returned handle */
41230588217SMike Christensen vlds_arg.vlds_hdlp = PTRTOUINT64(&hdl_arg);
41330588217SMike Christensen
41430588217SMike Christensen if (ioctl(ds_fd, VLDS_SVC_REG, &vlds_arg) < 0) {
41530588217SMike Christensen (void) mutex_unlock(&dslib_lock);
41630588217SMike Christensen return (errno);
41730588217SMike Christensen }
41830588217SMike Christensen
41930588217SMike Christensen /*
42030588217SMike Christensen * Setup user callback sysevent channel.
42130588217SMike Christensen */
42230588217SMike Christensen if ((flags & VLDS_ANYCB_VALID) != 0 && ds_evchan == NULL &&
42330588217SMike Christensen ds_init_sysev() != 0) {
42430588217SMike Christensen (void) mutex_unlock(&dslib_lock);
42530588217SMike Christensen (void) ioctl(ds_fd, VLDS_UNREG_HDL, &vlds_arg);
42630588217SMike Christensen return (errno);
42730588217SMike Christensen }
42830588217SMike Christensen
42930588217SMike Christensen hdl = hdl_arg;
43030588217SMike Christensen
43130588217SMike Christensen /*
43230588217SMike Christensen * Set entry values in dslibtab.
43330588217SMike Christensen */
43430588217SMike Christensen dsp->dsl_hdl = hdl;
43530588217SMike Christensen dsp->dsl_flags = flags;
436ba9236fbSMike Christensen dsp->dsl_tflags = 0;
43730588217SMike Christensen dsp->dsl_service = strdup(cap->svc_id);
43830588217SMike Christensen dsp->dsl_ops = *ops;
43930588217SMike Christensen (void) mutex_unlock(&dslib_lock);
44030588217SMike Christensen return (0);
44130588217SMike Christensen }
44230588217SMike Christensen
44330588217SMike Christensen /*
44430588217SMike Christensen * Registers a service provider. Kicks off the handshake with other
44530588217SMike Christensen * domain(s) to announce servce. Callback events are as described above.
44630588217SMike Christensen */
44730588217SMike Christensen int
ds_svc_reg(ds_capability_t * cap,ds_ops_t * ops)44830588217SMike Christensen ds_svc_reg(ds_capability_t *cap, ds_ops_t *ops)
44930588217SMike Christensen {
45030588217SMike Christensen return (ds_register(cap, ops, 0));
45130588217SMike Christensen }
45230588217SMike Christensen
45330588217SMike Christensen /*
45430588217SMike Christensen * Registers interest in a service from a specific domain. When that
45530588217SMike Christensen * service is registered, the register callback is invoked. When that
45630588217SMike Christensen * service is unregistered, the unregister callback is invoked. When
45730588217SMike Christensen * data is received, the receive data callback is invoked.
45830588217SMike Christensen */
45930588217SMike Christensen int
ds_clnt_reg(ds_capability_t * cap,ds_ops_t * ops)46030588217SMike Christensen ds_clnt_reg(ds_capability_t *cap, ds_ops_t *ops)
46130588217SMike Christensen {
46230588217SMike Christensen return (ds_register(cap, ops, VLDS_REG_CLIENT));
46330588217SMike Christensen }
46430588217SMike Christensen
46530588217SMike Christensen /*
46630588217SMike Christensen * Given a service name and type, returns the existing handle(s), if
46730588217SMike Christensen * one or more exist. This could be used to poll for the connection being
46830588217SMike Christensen * registered or unregistered, rather than using the register/unregister
46930588217SMike Christensen * callbacks.
47030588217SMike Christensen */
47130588217SMike Christensen int
ds_hdl_lookup(char * service,boolean_t is_client,ds_hdl_t * hdlsp,uint_t maxhdls,uint_t * nhdlsp)47230588217SMike Christensen ds_hdl_lookup(char *service, boolean_t is_client, ds_hdl_t *hdlsp,
47330588217SMike Christensen uint_t maxhdls, uint_t *nhdlsp)
47430588217SMike Christensen {
47530588217SMike Christensen vlds_hdl_lookup_arg_t vlds_arg;
47630588217SMike Christensen uint64_t nhdls_arg;
47730588217SMike Christensen
47830588217SMike Christensen errno = 0;
47930588217SMike Christensen if (ds_fd < 0) {
48030588217SMike Christensen return (errno = EBADF);
48130588217SMike Christensen }
48230588217SMike Christensen
48330588217SMike Christensen if (service == NULL) {
48430588217SMike Christensen return (errno = EINVAL);
48530588217SMike Christensen }
48630588217SMike Christensen
48730588217SMike Christensen ds_string_arg(&vlds_arg.vlds_service, service);
48830588217SMike Christensen vlds_arg.vlds_isclient = is_client ? VLDS_REG_CLIENT : 0;
48930588217SMike Christensen vlds_arg.vlds_hdlsp = PTRTOUINT64(hdlsp);
49030588217SMike Christensen vlds_arg.vlds_maxhdls = maxhdls;
49130588217SMike Christensen vlds_arg.vlds_nhdlsp = PTRTOUINT64(&nhdls_arg);
49230588217SMike Christensen
49330588217SMike Christensen if (ioctl(ds_fd, VLDS_HDL_LOOKUP, &vlds_arg) < 0) {
49430588217SMike Christensen return (errno);
49530588217SMike Christensen }
49630588217SMike Christensen
49730588217SMike Christensen *nhdlsp = nhdls_arg;
49830588217SMike Christensen return (0);
49930588217SMike Christensen }
50030588217SMike Christensen
50130588217SMike Christensen /*
50230588217SMike Christensen * Given a handle, return its associated domain.
50330588217SMike Christensen */
50430588217SMike Christensen int
ds_domain_lookup(ds_hdl_t hdl,ds_domain_hdl_t * dhdlp)50530588217SMike Christensen ds_domain_lookup(ds_hdl_t hdl, ds_domain_hdl_t *dhdlp)
50630588217SMike Christensen {
50730588217SMike Christensen vlds_dmn_lookup_arg_t vlds_arg;
50830588217SMike Christensen uint64_t dhdl_arg;
50930588217SMike Christensen
51030588217SMike Christensen if (ds_fd < 0) {
51130588217SMike Christensen return (errno = EBADF);
51230588217SMike Christensen }
51330588217SMike Christensen
51430588217SMike Christensen vlds_arg.vlds_hdl = hdl;
51530588217SMike Christensen vlds_arg.vlds_dhdlp = PTRTOUINT64(&dhdl_arg);
51630588217SMike Christensen
51730588217SMike Christensen if (ioctl(ds_fd, VLDS_DMN_LOOKUP, &vlds_arg) < 0) {
51830588217SMike Christensen return (errno);
51930588217SMike Christensen }
52030588217SMike Christensen
52130588217SMike Christensen if (dhdlp) {
52230588217SMike Christensen *dhdlp = dhdl_arg;
52330588217SMike Christensen }
52430588217SMike Christensen
52530588217SMike Christensen return (0);
52630588217SMike Christensen }
52730588217SMike Christensen
52830588217SMike Christensen /*
52930588217SMike Christensen * Unregisters either a service or an interest in that service
53030588217SMike Christensen * indicated by the supplied handle.
53130588217SMike Christensen */
53230588217SMike Christensen int
ds_unreg_hdl(ds_hdl_t hdl)53330588217SMike Christensen ds_unreg_hdl(ds_hdl_t hdl)
53430588217SMike Christensen {
53530588217SMike Christensen dslibentry_t *dsp;
53630588217SMike Christensen vlds_unreg_hdl_arg_t vlds_arg;
53730588217SMike Christensen
53830588217SMike Christensen (void) mutex_lock(&dslib_lock);
53930588217SMike Christensen if ((dsp = ds_hdl_to_dslibentry(hdl)) != NULL) {
54030588217SMike Christensen ds_free_dslibentry(dsp, 1);
54130588217SMike Christensen }
54230588217SMike Christensen (void) mutex_unlock(&dslib_lock);
54330588217SMike Christensen
54430588217SMike Christensen if (ds_fd >= 0) {
54530588217SMike Christensen vlds_arg.vlds_hdl = hdl;
54630588217SMike Christensen (void) ioctl(ds_fd, VLDS_UNREG_HDL, &vlds_arg);
54730588217SMike Christensen }
54830588217SMike Christensen
54930588217SMike Christensen return (0);
55030588217SMike Christensen }
55130588217SMike Christensen
55230588217SMike Christensen /*
55330588217SMike Christensen * Send data to the appropriate service provider or client
55430588217SMike Christensen * indicated by the provided handle. The sender will block
55530588217SMike Christensen * until the message has been sent. There is no guarantee
55630588217SMike Christensen * that multiple calls to ds_send_msg by the same thread
55730588217SMike Christensen * will result in the data showing up at the receiver in
55830588217SMike Christensen * the same order as sent. If multiple messages are required,
55930588217SMike Christensen * it will be up to the sender and receiver to implement a
56030588217SMike Christensen * protocol.
56130588217SMike Christensen */
56230588217SMike Christensen int
ds_send_msg(ds_hdl_t hdl,void * buf,size_t buflen)56330588217SMike Christensen ds_send_msg(ds_hdl_t hdl, void *buf, size_t buflen)
56430588217SMike Christensen {
56530588217SMike Christensen vlds_send_msg_arg_t vlds_arg;
56630588217SMike Christensen
56730588217SMike Christensen if (ds_fd < 0) {
56830588217SMike Christensen return (errno = EBADF);
56930588217SMike Christensen }
57030588217SMike Christensen
57130588217SMike Christensen vlds_arg.vlds_hdl = hdl;
57230588217SMike Christensen vlds_arg.vlds_bufp = PTRTOUINT64(buf);
57330588217SMike Christensen vlds_arg.vlds_buflen = buflen;
57430588217SMike Christensen
57530588217SMike Christensen if (ioctl(ds_fd, VLDS_SEND_MSG, &vlds_arg) < 0) {
57630588217SMike Christensen return (errno);
57730588217SMike Christensen }
57830588217SMike Christensen
57930588217SMike Christensen return (0);
58030588217SMike Christensen }
58130588217SMike Christensen
58230588217SMike Christensen /*
58330588217SMike Christensen * Receive data from the appropriate service provider or client
58430588217SMike Christensen * indicated by the provided handle. The sender will block
58530588217SMike Christensen * until a message has been received.
58630588217SMike Christensen */
58730588217SMike Christensen int
ds_recv_msg(ds_hdl_t hdl,void * buf,size_t buflen,size_t * msglen)58830588217SMike Christensen ds_recv_msg(ds_hdl_t hdl, void *buf, size_t buflen, size_t *msglen)
58930588217SMike Christensen {
59030588217SMike Christensen vlds_recv_msg_arg_t vlds_arg;
59130588217SMike Christensen uint64_t msglen_arg;
59230588217SMike Christensen
59330588217SMike Christensen if (ds_fd < 0) {
59430588217SMike Christensen return (errno = EBADF);
59530588217SMike Christensen }
59630588217SMike Christensen
59730588217SMike Christensen vlds_arg.vlds_hdl = hdl;
59830588217SMike Christensen vlds_arg.vlds_bufp = PTRTOUINT64(buf);
59930588217SMike Christensen vlds_arg.vlds_buflen = buflen;
60030588217SMike Christensen vlds_arg.vlds_msglenp = PTRTOUINT64(&msglen_arg);
60130588217SMike Christensen
60230588217SMike Christensen if (ioctl(ds_fd, VLDS_RECV_MSG, &vlds_arg) < 0) {
60330588217SMike Christensen if (errno == EFBIG && msglen) {
60430588217SMike Christensen *msglen = msglen_arg;
60530588217SMike Christensen }
60630588217SMike Christensen return (errno);
60730588217SMike Christensen }
60830588217SMike Christensen
60930588217SMike Christensen if (msglen) {
61030588217SMike Christensen *msglen = msglen_arg;
61130588217SMike Christensen }
61230588217SMike Christensen
61330588217SMike Christensen return (0);
61430588217SMike Christensen }
61530588217SMike Christensen
61630588217SMike Christensen int
ds_isready(ds_hdl_t hdl,boolean_t * is_ready)61730588217SMike Christensen ds_isready(ds_hdl_t hdl, boolean_t *is_ready)
61830588217SMike Christensen {
61930588217SMike Christensen vlds_hdl_isready_arg_t vlds_arg;
62030588217SMike Christensen uint64_t is_ready_arg;
62130588217SMike Christensen
62230588217SMike Christensen if (ds_fd < 0) {
62330588217SMike Christensen return (errno = EBADF);
62430588217SMike Christensen }
62530588217SMike Christensen
62630588217SMike Christensen vlds_arg.vlds_hdl = hdl;
62730588217SMike Christensen vlds_arg.vlds_isreadyp = PTRTOUINT64(&is_ready_arg);
62830588217SMike Christensen
62930588217SMike Christensen if (ioctl(ds_fd, VLDS_HDL_ISREADY, &vlds_arg) < 0) {
63030588217SMike Christensen return (errno);
63130588217SMike Christensen }
63230588217SMike Christensen
63330588217SMike Christensen *is_ready = (is_ready_arg != 0);
63430588217SMike Christensen return (0);
63530588217SMike Christensen }
63630588217SMike Christensen
63730588217SMike Christensen /*
63830588217SMike Christensen * Given a domain name, return its associated domain handle.
63930588217SMike Christensen */
64030588217SMike Christensen int
ds_dom_name_to_hdl(char * domain_name,ds_domain_hdl_t * dhdlp)64130588217SMike Christensen ds_dom_name_to_hdl(char *domain_name, ds_domain_hdl_t *dhdlp)
64230588217SMike Christensen {
64330588217SMike Christensen vlds_dom_nam2hdl_arg_t vlds_arg;
64430588217SMike Christensen uint64_t dhdl_arg;
64530588217SMike Christensen
64630588217SMike Christensen if (ds_fd < 0) {
64730588217SMike Christensen return (errno = EBADF);
64830588217SMike Christensen }
64930588217SMike Christensen
65030588217SMike Christensen ds_string_arg(&vlds_arg.vlds_domain_name, domain_name);
65130588217SMike Christensen vlds_arg.vlds_dhdlp = PTRTOUINT64(&dhdl_arg);
65230588217SMike Christensen
65330588217SMike Christensen if (ioctl(ds_fd, VLDS_DOM_NAM2HDL, &vlds_arg) < 0) {
65430588217SMike Christensen return (errno);
65530588217SMike Christensen }
65630588217SMike Christensen
65730588217SMike Christensen if (dhdlp) {
65830588217SMike Christensen *dhdlp = dhdl_arg;
65930588217SMike Christensen }
66030588217SMike Christensen
66130588217SMike Christensen return (0);
66230588217SMike Christensen }
66330588217SMike Christensen
66430588217SMike Christensen /*
66530588217SMike Christensen * Given a domain handle, return its associated domain name.
66630588217SMike Christensen */
66730588217SMike Christensen int
ds_dom_hdl_to_name(ds_domain_hdl_t dhdl,char * domain_name,uint_t maxnamlen)66830588217SMike Christensen ds_dom_hdl_to_name(ds_domain_hdl_t dhdl, char *domain_name, uint_t maxnamlen)
66930588217SMike Christensen {
67030588217SMike Christensen vlds_dom_hdl2nam_arg_t vlds_arg;
67130588217SMike Christensen
67230588217SMike Christensen if (ds_fd < 0) {
67330588217SMike Christensen return (errno = EBADF);
67430588217SMike Christensen }
67530588217SMike Christensen
67630588217SMike Christensen vlds_arg.vlds_dhdl = dhdl;
67730588217SMike Christensen vlds_arg.vlds_domain_name.vlds_strp = PTRTOUINT64(domain_name);
67830588217SMike Christensen vlds_arg.vlds_domain_name.vlds_strlen = maxnamlen;
67930588217SMike Christensen
68030588217SMike Christensen if (ioctl(ds_fd, VLDS_DOM_HDL2NAM, &vlds_arg) < 0) {
68130588217SMike Christensen return (errno);
68230588217SMike Christensen }
68330588217SMike Christensen
68430588217SMike Christensen return (0);
68530588217SMike Christensen }
68630588217SMike Christensen
68730588217SMike Christensen void
ds_unreg_svc(char * service,boolean_t is_client)68830588217SMike Christensen ds_unreg_svc(char *service, boolean_t is_client)
68930588217SMike Christensen {
69030588217SMike Christensen ds_hdl_t hdl;
69130588217SMike Christensen uint_t nhdls;
69230588217SMike Christensen
69330588217SMike Christensen while (ds_hdl_lookup(service, is_client, &hdl, 1, &nhdls) == 0 &&
69430588217SMike Christensen nhdls == 1) {
69530588217SMike Christensen (void) ds_unreg_hdl(hdl);
69630588217SMike Christensen }
69730588217SMike Christensen }
69830588217SMike Christensen
69930588217SMike Christensen void
ds_fini(void)70030588217SMike Christensen ds_fini(void)
70130588217SMike Christensen {
70230588217SMike Christensen int i;
70330588217SMike Christensen dslibentry_t *dsp;
70430588217SMike Christensen
70530588217SMike Christensen if (ds_fd >= 0) {
70630588217SMike Christensen (void) close(ds_fd);
70730588217SMike Christensen ds_fd = -1;
70830588217SMike Christensen }
70930588217SMike Christensen if (ds_evchan) {
71030588217SMike Christensen (void) sysevent_evc_unsubscribe(ds_evchan, ds_sid_name);
71130588217SMike Christensen (void) sysevent_evc_unbind(ds_evchan);
71230588217SMike Christensen ds_evchan = NULL;
71330588217SMike Christensen }
71430588217SMike Christensen if (ndslib > 0) {
71530588217SMike Christensen (void) mutex_lock(&dslib_lock);
71630588217SMike Christensen for (i = 0, dsp = dslibtab; i < ndslib; i++, dsp++) {
71730588217SMike Christensen if (dsp->dsl_hdl == NULL)
71830588217SMike Christensen continue;
71930588217SMike Christensen if (dsp->dsl_service) {
72030588217SMike Christensen free(dsp->dsl_service);
72130588217SMike Christensen }
72230588217SMike Christensen }
72330588217SMike Christensen free(dslibtab);
72430588217SMike Christensen ndslib = 0;
72530588217SMike Christensen dslibtab = NULL;
72630588217SMike Christensen (void) mutex_unlock(&dslib_lock);
72730588217SMike Christensen (void) mutex_destroy(&dslib_lock);
72830588217SMike Christensen }
72930588217SMike Christensen }
730