1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26#include <stdio.h>
27#include <fcntl.h>
28#include <unistd.h>
29#include <stdlib.h>
30#include <strings.h>
31#include <errno.h>
32#include <sys/types.h>
33#include <sys/sysevent.h>
34#include <libsysevent.h>
35#include <sys/vlds.h>
36#include "libds.h"
37
38#define	PTRTOUINT64(ptr)	((uint64_t)((uintptr_t)(ptr)))
39static char vlds_device[] =
40	"/devices/virtual-devices@100/channel-devices@200/"
41	"virtual-domain-service@0:vlds";
42
43typedef struct dslibentry {
44	ds_hdl_t dsl_hdl;
45	uint32_t dsl_flags;
46	uint32_t dsl_tflags;
47	char *dsl_service;
48	ds_ops_t dsl_ops;
49} dslibentry_t;
50
51/* dsl_tflags */
52#define	DSL_ENTRY_INUSE		0x0001	/* handle is currently active */
53
54#define	MIN_DSLIB_ENTRIES	64
55static dslibentry_t *dslibtab;
56static int ndslib;
57
58/*
59 * Lock to protect the dslibtab table.  We only need to protect this
60 * table for those functions which actually look at or modify the table:
61 * service registration (ds_svc_reg/ds_clnt_reg), service unregistration
62 * (ds_hdl_unreg) or during callbacks (ds_recv)
63 */
64static mutex_t dslib_lock;
65
66static int ds_fd = -1;
67
68static char *ds_sid_name = "vlds";
69
70static evchan_t *ds_evchan;
71
72/*
73 * Static functions internal to dslib.
74 */
75static dslibentry_t *ds_hdl_to_dslibentry(ds_hdl_t hdl);
76static dslibentry_t *ds_new_dslibentry(void);
77static uint_t ds_service_count(char *service, boolean_t is_client);
78static dslibentry_t *ds_lookup_dslibentry(char *service, boolean_t is_client);
79static dslibentry_t *ds_register_dslibentry(ds_hdl_t hdl, char *service,
80    boolean_t is_client);
81static void ds_free_dslibentry(dslibentry_t *dsp, int force_unreg);
82static int ds_recv(sysevent_t *sep, void *arg);
83static void ds_string_arg(vlds_string_t *dsp, char *str);
84static int ds_register(ds_capability_t *cap, ds_ops_t *ops, uint_t flags);
85
86static dslibentry_t *
87ds_hdl_to_dslibentry(ds_hdl_t hdl)
88{
89	int i;
90	dslibentry_t *dsp;
91
92	for (i = 0, dsp = dslibtab; i < ndslib; i++, dsp++) {
93		if (hdl == dsp->dsl_hdl)
94			return (dsp);
95	}
96	return (NULL);
97}
98
99static dslibentry_t *
100ds_new_dslibentry(void)
101{
102	int newndslib;
103	dslibentry_t *dsp;
104
105	if ((dsp = ds_hdl_to_dslibentry(NULL)) != NULL)
106		return (dsp);
107
108	/* double the size */
109	newndslib = ndslib << 1;
110	if ((dslibtab = realloc(dslibtab, newndslib * sizeof (dslibentry_t)))
111	    == NULL)
112		return (NULL);
113	dsp = &dslibtab[ndslib];
114	(void) memset(dsp, 0, (newndslib - ndslib) * sizeof (dslibentry_t));
115	ndslib = newndslib;
116	return (dsp);
117}
118
119static uint_t
120ds_service_count(char *service, boolean_t is_client)
121{
122	int i;
123	dslibentry_t *dsp;
124	uint_t is_client_flag = is_client ? VLDS_REG_CLIENT : 0;
125	uint_t count = 0;
126
127	for (i = 0, dsp = dslibtab; i < ndslib; i++, dsp++) {
128		if (dsp->dsl_hdl != NULL &&
129		    strcmp(dsp->dsl_service, service) == 0 &&
130		    (dsp->dsl_flags & VLDS_REG_CLIENT) == is_client_flag) {
131			count++;
132		}
133	}
134	return (count);
135}
136
137static dslibentry_t *
138ds_lookup_dslibentry(char *service, boolean_t is_client)
139{
140	int i;
141	dslibentry_t *dsp;
142	uint_t is_client_flag = is_client ? VLDS_REG_CLIENT : 0;
143
144	for (i = 0, dsp = dslibtab; i < ndslib; i++, dsp++) {
145		if (dsp->dsl_hdl != NULL &&
146		    strcmp(dsp->dsl_service, service) == 0 &&
147		    (dsp->dsl_flags & VLDS_REG_CLIENT) == is_client_flag) {
148			return (dsp);
149		}
150	}
151	return (NULL);
152}
153
154static dslibentry_t *
155ds_register_dslibentry(ds_hdl_t hdl, char *service, boolean_t is_client)
156{
157	dslibentry_t *dsp, *orig_dsp;
158
159	if ((dsp = ds_hdl_to_dslibentry(hdl)) != NULL) {
160		dsp->dsl_tflags |= DSL_ENTRY_INUSE;
161		return (dsp);
162	}
163
164	if ((orig_dsp = ds_lookup_dslibentry(service, is_client)) == NULL) {
165		return (NULL);
166	}
167
168	if ((orig_dsp->dsl_tflags & DSL_ENTRY_INUSE) == 0) {
169		/* use the original structure entry */
170		orig_dsp->dsl_tflags |= DSL_ENTRY_INUSE;
171		orig_dsp->dsl_hdl = hdl;
172		return (orig_dsp);
173	}
174
175	/* allocate a new structure entry */
176	if ((dsp = ds_new_dslibentry()) == NULL)
177		return (NULL);
178
179	*dsp = *orig_dsp;
180	dsp->dsl_service = strdup(orig_dsp->dsl_service);
181	dsp->dsl_hdl = hdl;
182	return (dsp);
183}
184
185/*
186 * Want to leave an entry in the dslib table even though all the
187 * handles may have been unregistered for it.
188 */
189static void
190ds_free_dslibentry(dslibentry_t *dsp, int force_unreg)
191{
192	uint_t nhdls;
193
194	/*
195	 * Find out if we have 1 or 2 or more handles for the given
196	 * service.  Having one implies that we want to leave the entry
197	 * intact but marked as not in use unless this is a ds_unreg_hdl
198	 * (force_unreg is true).
199	 */
200	nhdls = ds_service_count(dsp->dsl_service,
201	    (dsp->dsl_flags & VLDS_REG_CLIENT) != 0);
202
203	if ((nhdls == 1 && force_unreg) || nhdls >= 2) {
204		dsp->dsl_hdl = NULL;
205		if (dsp->dsl_service) {
206			free(dsp->dsl_service);
207		}
208		(void) memset(dsp, 0, sizeof (dslibentry_t));
209	} else if (nhdls == 1) {
210		dsp->dsl_tflags &= ~DSL_ENTRY_INUSE;
211	}
212}
213
214/*ARGSUSED*/
215static int
216ds_recv(sysevent_t *sep, void *arg)
217{
218	nvlist_t *nvl;
219	uint64_t hdl;
220	ds_ver_t ver;
221	ds_domain_hdl_t dhdl;
222	uchar_t *bufp;
223	boolean_t is_client;
224	uint_t buflen;
225	char *subclass;
226	char *servicep;
227	dslibentry_t *dsp;
228	ds_cb_arg_t cb_arg;
229
230	subclass = sysevent_get_subclass_name(sep);
231	if (sysevent_get_attr_list(sep, &nvl) != 0) {
232		return (0);
233	}
234
235	if (nvlist_lookup_uint64(nvl, VLDS_HDL, &hdl) == 0) {
236		if (strcmp(subclass, ESC_VLDS_REGISTER) == 0) {
237			void (*reg_cb)(ds_hdl_t, ds_cb_arg_t, ds_ver_t *,
238			    ds_domain_hdl_t) = NULL;
239
240			if (nvlist_lookup_string(nvl, VLDS_SERVICE_ID,
241			    &servicep) == 0 &&
242			    nvlist_lookup_boolean_value(nvl, VLDS_ISCLIENT,
243			    &is_client) == 0) {
244				(void) mutex_lock(&dslib_lock);
245				if ((dsp = ds_register_dslibentry(hdl,
246				    servicep, is_client)) != NULL) {
247					reg_cb = dsp->dsl_ops.ds_reg_cb;
248					cb_arg = dsp->dsl_ops.cb_arg;
249				}
250				(void) mutex_unlock(&dslib_lock);
251				if (reg_cb != NULL &&
252				    nvlist_lookup_uint64(nvl, VLDS_DOMAIN_HDL,
253				    &dhdl) == 0 &&
254				    nvlist_lookup_uint16(nvl, VLDS_VER_MAJOR,
255				    &ver.major) == 0 &&
256				    nvlist_lookup_uint16(nvl, VLDS_VER_MINOR,
257				    &ver.minor) == 0) {
258					(reg_cb)((ds_hdl_t)hdl, cb_arg, &ver,
259					    dhdl);
260				}
261			}
262		} else if (strcmp(subclass, ESC_VLDS_UNREGISTER) == 0) {
263			void (*unreg_cb)(ds_hdl_t, ds_cb_arg_t) = NULL;
264
265			(void) mutex_lock(&dslib_lock);
266			if ((dsp = ds_hdl_to_dslibentry(hdl)) != NULL) {
267				unreg_cb = dsp->dsl_ops.ds_unreg_cb;
268				cb_arg = dsp->dsl_ops.cb_arg;
269				ds_free_dslibentry(dsp, 0);
270			}
271			(void) mutex_unlock(&dslib_lock);
272			if (unreg_cb != NULL) {
273				(unreg_cb)((ds_hdl_t)hdl, cb_arg);
274			}
275		} else if (strcmp(subclass, ESC_VLDS_DATA) == 0) {
276			void (*data_cb)(ds_hdl_t, ds_cb_arg_t, void *,
277			    size_t) = NULL;
278
279			(void) mutex_lock(&dslib_lock);
280			if ((dsp = ds_hdl_to_dslibentry(hdl)) != NULL) {
281				data_cb = dsp->dsl_ops.ds_data_cb;
282				cb_arg = dsp->dsl_ops.cb_arg;
283			}
284			(void) mutex_unlock(&dslib_lock);
285			if (data_cb != NULL &&
286			    nvlist_lookup_byte_array(nvl, VLDS_DATA, &bufp,
287			    &buflen) == 0) {
288				(data_cb)((ds_hdl_t)hdl, cb_arg, bufp, buflen);
289			}
290		}
291	}
292	nvlist_free(nvl);
293	return (0);
294}
295
296static void
297ds_string_arg(vlds_string_t *dsp, char *str)
298{
299	if (str == NULL) {
300		dsp->vlds_strp = NULL;
301		dsp->vlds_strlen = 0;
302	} else {
303		dsp->vlds_strp = PTRTOUINT64(str);
304		dsp->vlds_strlen = strlen(str) + 1;
305	}
306}
307
308static int
309ds_init_sysev(void)
310{
311	char evchan_name[MAX_CHNAME_LEN];
312
313	(void) sprintf(evchan_name, VLDS_SYSEV_CHAN_FMT, (int)getpid());
314	if (sysevent_evc_bind(evchan_name, &ds_evchan, 0) != 0) {
315		return (errno);
316	}
317	if (sysevent_evc_subscribe(ds_evchan, ds_sid_name, EC_VLDS,
318	    ds_recv, NULL, 0) != 0) {
319		(void) sysevent_evc_unbind(ds_evchan);
320		ds_evchan = NULL;
321		return (errno);
322	}
323	return (0);
324}
325
326int
327ds_init(void)
328{
329	if (ds_fd >= 0)
330		return (0);
331
332	if ((ds_fd = open(vlds_device, 0)) < 0)
333		return (errno);
334
335	if (dslibtab == NULL) {
336		dslibtab = malloc(sizeof (dslibentry_t) * MIN_DSLIB_ENTRIES);
337		if (dslibtab == NULL)
338			return (errno = ENOMEM);
339		ndslib = MIN_DSLIB_ENTRIES;
340		(void) memset(dslibtab, 0, sizeof (dslibentry_t) * ndslib);
341	}
342
343	(void) mutex_init(&dslib_lock, USYNC_THREAD, NULL);
344	return (0);
345}
346
347static int
348ds_register(ds_capability_t *cap, ds_ops_t *ops, uint_t flags)
349{
350	dslibentry_t *dsp;
351	vlds_svc_reg_arg_t vlds_arg;
352	vlds_cap_t vlds_cap;
353	vlds_ver_t vlds_vers[VLDS_MAX_VERS];
354	uint64_t hdl_arg;
355	ds_hdl_t hdl;
356	uint_t nhdls;
357	int i;
358
359	if (cap == NULL || ops == NULL || cap->svc_id == NULL ||
360	    cap->vers == NULL || (flags & (~VLDS_REG_CLIENT)) != 0) {
361		return (errno = EINVAL);
362	}
363
364	if (cap->nvers > VLDS_MAX_VERS) {
365		return (errno = EINVAL);
366	}
367
368	if (ds_fd < 0 && (errno = ds_init()) != 0) {
369		return (errno);
370	}
371
372	if (ds_hdl_lookup(cap->svc_id, (flags & VLDS_REG_CLIENT), NULL, 1,
373	    &nhdls) == 0 && nhdls == 1) {
374		return (errno = EALREADY);
375	}
376
377	(void) mutex_lock(&dslib_lock);
378	if ((dsp = ds_new_dslibentry()) == NULL) {
379		(void) mutex_unlock(&dslib_lock);
380		return (errno = ENOMEM);
381	}
382
383	/* Setup device driver capability structure. */
384
385	/* service string */
386	ds_string_arg(&vlds_cap.vlds_service, cap->svc_id);
387
388	/* version array */
389	for (i = 0; i < cap->nvers; i++) {
390		vlds_vers[i].vlds_major = cap->vers[i].major;
391		vlds_vers[i].vlds_minor = cap->vers[i].minor;
392	}
393	vlds_cap.vlds_versp = PTRTOUINT64(vlds_vers);
394	vlds_cap.vlds_nver = cap->nvers;
395
396	/*
397	 * Format args for VLDS_SVC_REG ioctl.
398	 */
399
400	vlds_arg.vlds_capp = PTRTOUINT64(&vlds_cap);
401
402	/* op flags */
403	if (ops->ds_reg_cb != NULL)
404		flags |= VLDS_REGCB_VALID;
405	if (ops->ds_unreg_cb != NULL)
406		flags |= VLDS_UNREGCB_VALID;
407	if (ops->ds_data_cb != NULL)
408		flags |= VLDS_DATACB_VALID;
409	vlds_arg.vlds_reg_flags = flags;
410
411	/* returned handle */
412	vlds_arg.vlds_hdlp = PTRTOUINT64(&hdl_arg);
413
414	if (ioctl(ds_fd, VLDS_SVC_REG, &vlds_arg) < 0) {
415		(void) mutex_unlock(&dslib_lock);
416		return (errno);
417	}
418
419	/*
420	 * Setup user callback sysevent channel.
421	 */
422	if ((flags & VLDS_ANYCB_VALID) != 0 && ds_evchan == NULL &&
423	    ds_init_sysev() != 0) {
424		(void) mutex_unlock(&dslib_lock);
425		(void) ioctl(ds_fd, VLDS_UNREG_HDL, &vlds_arg);
426		return (errno);
427	}
428
429	hdl = hdl_arg;
430
431	/*
432	 * Set entry values in dslibtab.
433	 */
434	dsp->dsl_hdl = hdl;
435	dsp->dsl_flags = flags;
436	dsp->dsl_tflags = 0;
437	dsp->dsl_service = strdup(cap->svc_id);
438	dsp->dsl_ops = *ops;
439	(void) mutex_unlock(&dslib_lock);
440	return (0);
441}
442
443/*
444 * Registers a service provider.  Kicks off the handshake with other
445 * domain(s) to announce servce.  Callback events are as described above.
446 */
447int
448ds_svc_reg(ds_capability_t *cap, ds_ops_t *ops)
449{
450	return (ds_register(cap, ops, 0));
451}
452
453/*
454 * Registers interest in a service from a specific domain.  When that
455 * service is registered, the register callback is invoked.  When that
456 * service is unregistered, the unregister callback is invoked.  When
457 * data is received, the receive data callback is invoked.
458 */
459int
460ds_clnt_reg(ds_capability_t *cap, ds_ops_t *ops)
461{
462	return (ds_register(cap, ops, VLDS_REG_CLIENT));
463}
464
465/*
466 * Given a service name and type, returns the existing handle(s), if
467 * one or more exist.  This could be used to poll for the connection being
468 * registered or unregistered, rather than using the register/unregister
469 * callbacks.
470 */
471int
472ds_hdl_lookup(char *service, boolean_t is_client, ds_hdl_t *hdlsp,
473    uint_t maxhdls, uint_t *nhdlsp)
474{
475	vlds_hdl_lookup_arg_t vlds_arg;
476	uint64_t nhdls_arg;
477
478	errno = 0;
479	if (ds_fd < 0) {
480		return (errno = EBADF);
481	}
482
483	if (service == NULL) {
484		return (errno = EINVAL);
485	}
486
487	ds_string_arg(&vlds_arg.vlds_service, service);
488	vlds_arg.vlds_isclient = is_client ? VLDS_REG_CLIENT : 0;
489	vlds_arg.vlds_hdlsp = PTRTOUINT64(hdlsp);
490	vlds_arg.vlds_maxhdls = maxhdls;
491	vlds_arg.vlds_nhdlsp = PTRTOUINT64(&nhdls_arg);
492
493	if (ioctl(ds_fd, VLDS_HDL_LOOKUP, &vlds_arg) < 0) {
494		return (errno);
495	}
496
497	*nhdlsp = nhdls_arg;
498	return (0);
499}
500
501/*
502 * Given a handle, return its associated domain.
503 */
504int
505ds_domain_lookup(ds_hdl_t hdl, ds_domain_hdl_t *dhdlp)
506{
507	vlds_dmn_lookup_arg_t vlds_arg;
508	uint64_t dhdl_arg;
509
510	if (ds_fd < 0) {
511		return (errno = EBADF);
512	}
513
514	vlds_arg.vlds_hdl = hdl;
515	vlds_arg.vlds_dhdlp = PTRTOUINT64(&dhdl_arg);
516
517	if (ioctl(ds_fd, VLDS_DMN_LOOKUP, &vlds_arg) < 0) {
518		return (errno);
519	}
520
521	if (dhdlp) {
522		*dhdlp = dhdl_arg;
523	}
524
525	return (0);
526}
527
528/*
529 * Unregisters either a service or an interest in that service
530 * indicated by the supplied handle.
531 */
532int
533ds_unreg_hdl(ds_hdl_t hdl)
534{
535	dslibentry_t *dsp;
536	vlds_unreg_hdl_arg_t vlds_arg;
537
538	(void) mutex_lock(&dslib_lock);
539	if ((dsp = ds_hdl_to_dslibentry(hdl)) != NULL) {
540		ds_free_dslibentry(dsp, 1);
541	}
542	(void) mutex_unlock(&dslib_lock);
543
544	if (ds_fd >= 0) {
545		vlds_arg.vlds_hdl = hdl;
546		(void) ioctl(ds_fd, VLDS_UNREG_HDL, &vlds_arg);
547	}
548
549	return (0);
550}
551
552/*
553 * Send data to the appropriate service provider or client
554 * indicated by the provided handle.  The sender will block
555 * until the message has been sent.  There is no guarantee
556 * that multiple calls to ds_send_msg by the same thread
557 * will result in the data showing up at the receiver in
558 * the same order as sent.  If multiple messages are required,
559 * it will be up to the sender and receiver to implement a
560 * protocol.
561 */
562int
563ds_send_msg(ds_hdl_t hdl, void *buf, size_t buflen)
564{
565	vlds_send_msg_arg_t vlds_arg;
566
567	if (ds_fd < 0) {
568		return (errno = EBADF);
569	}
570
571	vlds_arg.vlds_hdl = hdl;
572	vlds_arg.vlds_bufp = PTRTOUINT64(buf);
573	vlds_arg.vlds_buflen = buflen;
574
575	if (ioctl(ds_fd, VLDS_SEND_MSG, &vlds_arg) < 0) {
576		return (errno);
577	}
578
579	return (0);
580}
581
582/*
583 * Receive data from the appropriate service provider or client
584 * indicated by the provided handle.  The sender will block
585 * until a message has been received.
586 */
587int
588ds_recv_msg(ds_hdl_t hdl, void *buf, size_t buflen, size_t *msglen)
589{
590	vlds_recv_msg_arg_t vlds_arg;
591	uint64_t msglen_arg;
592
593	if (ds_fd < 0) {
594		return (errno = EBADF);
595	}
596
597	vlds_arg.vlds_hdl = hdl;
598	vlds_arg.vlds_bufp = PTRTOUINT64(buf);
599	vlds_arg.vlds_buflen = buflen;
600	vlds_arg.vlds_msglenp = PTRTOUINT64(&msglen_arg);
601
602	if (ioctl(ds_fd, VLDS_RECV_MSG, &vlds_arg) < 0) {
603		if (errno == EFBIG && msglen) {
604			*msglen = msglen_arg;
605		}
606		return (errno);
607	}
608
609	if (msglen) {
610		*msglen = msglen_arg;
611	}
612
613	return (0);
614}
615
616int
617ds_isready(ds_hdl_t hdl, boolean_t *is_ready)
618{
619	vlds_hdl_isready_arg_t vlds_arg;
620	uint64_t is_ready_arg;
621
622	if (ds_fd < 0) {
623		return (errno = EBADF);
624	}
625
626	vlds_arg.vlds_hdl = hdl;
627	vlds_arg.vlds_isreadyp = PTRTOUINT64(&is_ready_arg);
628
629	if (ioctl(ds_fd, VLDS_HDL_ISREADY, &vlds_arg) < 0) {
630		return (errno);
631	}
632
633	*is_ready = (is_ready_arg != 0);
634	return (0);
635}
636
637/*
638 * Given a domain name, return its associated domain handle.
639 */
640int
641ds_dom_name_to_hdl(char *domain_name, ds_domain_hdl_t *dhdlp)
642{
643	vlds_dom_nam2hdl_arg_t vlds_arg;
644	uint64_t dhdl_arg;
645
646	if (ds_fd < 0) {
647		return (errno = EBADF);
648	}
649
650	ds_string_arg(&vlds_arg.vlds_domain_name, domain_name);
651	vlds_arg.vlds_dhdlp = PTRTOUINT64(&dhdl_arg);
652
653	if (ioctl(ds_fd, VLDS_DOM_NAM2HDL, &vlds_arg) < 0) {
654		return (errno);
655	}
656
657	if (dhdlp) {
658		*dhdlp = dhdl_arg;
659	}
660
661	return (0);
662}
663
664/*
665 * Given a domain handle, return its associated domain name.
666 */
667int
668ds_dom_hdl_to_name(ds_domain_hdl_t dhdl, char *domain_name, uint_t maxnamlen)
669{
670	vlds_dom_hdl2nam_arg_t vlds_arg;
671
672	if (ds_fd < 0) {
673		return (errno = EBADF);
674	}
675
676	vlds_arg.vlds_dhdl = dhdl;
677	vlds_arg.vlds_domain_name.vlds_strp = PTRTOUINT64(domain_name);
678	vlds_arg.vlds_domain_name.vlds_strlen = maxnamlen;
679
680	if (ioctl(ds_fd, VLDS_DOM_HDL2NAM, &vlds_arg) < 0) {
681		return (errno);
682	}
683
684	return (0);
685}
686
687void
688ds_unreg_svc(char *service, boolean_t is_client)
689{
690	ds_hdl_t hdl;
691	uint_t nhdls;
692
693	while (ds_hdl_lookup(service, is_client, &hdl, 1, &nhdls) == 0 &&
694	    nhdls == 1) {
695		(void) ds_unreg_hdl(hdl);
696	}
697}
698
699void
700ds_fini(void)
701{
702	int i;
703	dslibentry_t *dsp;
704
705	if (ds_fd >= 0) {
706		(void) close(ds_fd);
707		ds_fd = -1;
708	}
709	if (ds_evchan) {
710		(void) sysevent_evc_unsubscribe(ds_evchan, ds_sid_name);
711		(void) sysevent_evc_unbind(ds_evchan);
712		ds_evchan = NULL;
713	}
714	if (ndslib > 0) {
715		(void) mutex_lock(&dslib_lock);
716		for (i = 0, dsp = dslibtab; i < ndslib; i++, dsp++) {
717			if (dsp->dsl_hdl == NULL)
718				continue;
719			if (dsp->dsl_service) {
720				free(dsp->dsl_service);
721			}
722		}
723		free(dslibtab);
724		ndslib = 0;
725		dslibtab = NULL;
726		(void) mutex_unlock(&dslib_lock);
727		(void) mutex_destroy(&dslib_lock);
728	}
729}
730