xref: /onnv-gate/usr/src/lib/libdhcpsvc/private/private.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright (c) 2001 by Sun Microsystems, Inc.
24*0Sstevel@tonic-gate  * All rights reserved.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate  * This module contains the private layer API.
31*0Sstevel@tonic-gate  */
32*0Sstevel@tonic-gate 
33*0Sstevel@tonic-gate #include <stdio.h>
34*0Sstevel@tonic-gate #include <assert.h>
35*0Sstevel@tonic-gate #include <stdlib.h>
36*0Sstevel@tonic-gate #include <unistd.h>
37*0Sstevel@tonic-gate #include <string.h>
38*0Sstevel@tonic-gate #include <sys/param.h>
39*0Sstevel@tonic-gate #include <libelf.h>
40*0Sstevel@tonic-gate #include <gelf.h>
41*0Sstevel@tonic-gate #include <sys/types.h>
42*0Sstevel@tonic-gate #include <sys/socket.h>
43*0Sstevel@tonic-gate #include <netinet/in.h>
44*0Sstevel@tonic-gate #include <arpa/inet.h>
45*0Sstevel@tonic-gate #include <dlfcn.h>
46*0Sstevel@tonic-gate #include <glob.h>
47*0Sstevel@tonic-gate #include <fcntl.h>
48*0Sstevel@tonic-gate #include <libinetutil.h>
49*0Sstevel@tonic-gate #include <dhcp_svc_public.h>
50*0Sstevel@tonic-gate #include <dhcp_svc_private.h>
51*0Sstevel@tonic-gate 
52*0Sstevel@tonic-gate /*
53*0Sstevel@tonic-gate  * Threading notes for private layer consumers:
54*0Sstevel@tonic-gate  *
55*0Sstevel@tonic-gate  * The handles returned from open_dd() may be shared across multiple
56*0Sstevel@tonic-gate  * threads with no adverse side effects.  However, it's up to that consumer
57*0Sstevel@tonic-gate  * to ensure that all threads have finished using an instance before
58*0Sstevel@tonic-gate  * closing the instance or removing the container it's referencing.
59*0Sstevel@tonic-gate  * Phrased differently:
60*0Sstevel@tonic-gate  *
61*0Sstevel@tonic-gate  *	* Consumers must ensure all threads sharing a handle are
62*0Sstevel@tonic-gate  *	  finished before calling close_dd().
63*0Sstevel@tonic-gate  *
64*0Sstevel@tonic-gate  *	* Consumers must ensure all threads referencing a container are
65*0Sstevel@tonic-gate  *	  closed before calling remove_dd().
66*0Sstevel@tonic-gate  */
67*0Sstevel@tonic-gate 
68*0Sstevel@tonic-gate static boolean_t validate_dd_entry(dsvc_handle_t, const void *, boolean_t);
69*0Sstevel@tonic-gate static int  synch_init(dsvc_handle_t, const char *, uint_t);
70*0Sstevel@tonic-gate static void synch_fini(dsvc_handle_t);
71*0Sstevel@tonic-gate 
72*0Sstevel@tonic-gate /*
73*0Sstevel@tonic-gate  * Order here should match the function array in <dhcp_svc_private.h>
74*0Sstevel@tonic-gate  */
75*0Sstevel@tonic-gate static char	*funcnames[] = {
76*0Sstevel@tonic-gate 	"status",	"version",	"mklocation",
77*0Sstevel@tonic-gate 	"list_dt",	"open_dt",	"close_dt",	"remove_dt",
78*0Sstevel@tonic-gate 	"lookup_dt",	"add_dt",	"modify_dt",	"delete_dt",
79*0Sstevel@tonic-gate 	"list_dn",	"open_dn",	"close_dn",	"remove_dn",
80*0Sstevel@tonic-gate 	"lookup_dn",	"add_dn",	"modify_dn",	"delete_dn"
81*0Sstevel@tonic-gate };
82*0Sstevel@tonic-gate 
83*0Sstevel@tonic-gate extern dsvc_synch_ops_t dsvcd_synch_ops;
84*0Sstevel@tonic-gate 
85*0Sstevel@tonic-gate /*
86*0Sstevel@tonic-gate  * Retrieve the current version associated with the datastore named by
87*0Sstevel@tonic-gate  * `resource' and store in `converp'.  One might think we could do this via
88*0Sstevel@tonic-gate  * a simple readlink(2), but on internal release builds $(ROOTLINKS)
89*0Sstevel@tonic-gate  * installs using hardlinks, not symlinks.  For this reason and to make it
90*0Sstevel@tonic-gate  * harder for us to be fooled, we'll dredge up the actual soname through
91*0Sstevel@tonic-gate  * ELF.  Close your eyes, it's gonna get ugly.
92*0Sstevel@tonic-gate  */
93*0Sstevel@tonic-gate static int
get_conver(const char * resource,int * converp)94*0Sstevel@tonic-gate get_conver(const char *resource, int *converp)
95*0Sstevel@tonic-gate {
96*0Sstevel@tonic-gate 	int		elf_fd;
97*0Sstevel@tonic-gate 	int		i;
98*0Sstevel@tonic-gate 	GElf_Shdr	gelf_shdr;
99*0Sstevel@tonic-gate 	GElf_Dyn	gelf_dyn;
100*0Sstevel@tonic-gate 	Elf_Scn		*elf_scn = NULL;
101*0Sstevel@tonic-gate 	Elf		*elf_file;
102*0Sstevel@tonic-gate 	Elf_Data	*elf_data;
103*0Sstevel@tonic-gate 	char		*soname = NULL;
104*0Sstevel@tonic-gate 	char		path[MAXPATHLEN];
105*0Sstevel@tonic-gate 
106*0Sstevel@tonic-gate 	(void) snprintf(path, sizeof (path), "%s%s/%s_%s.so", DHCP_CONFOPT_ROOT,
107*0Sstevel@tonic-gate 	    DSVC_MODULE_DIR, DSVC_PUBLIC_PREFIX, resource);
108*0Sstevel@tonic-gate 
109*0Sstevel@tonic-gate 	elf_fd = open(path, O_RDONLY);
110*0Sstevel@tonic-gate 	if (elf_fd == -1)
111*0Sstevel@tonic-gate 		return (DSVC_MODULE_ERR);
112*0Sstevel@tonic-gate 
113*0Sstevel@tonic-gate 	if (elf_version(EV_CURRENT) == EV_NONE) {
114*0Sstevel@tonic-gate 		(void) close(elf_fd);
115*0Sstevel@tonic-gate 		return (DSVC_INTERNAL);
116*0Sstevel@tonic-gate 	}
117*0Sstevel@tonic-gate 
118*0Sstevel@tonic-gate 	elf_file = elf_begin(elf_fd, ELF_C_READ, NULL);
119*0Sstevel@tonic-gate 	if (elf_file == NULL || elf_kind(elf_file) != ELF_K_ELF) {
120*0Sstevel@tonic-gate 		(void) close(elf_fd);
121*0Sstevel@tonic-gate 		return (DSVC_INTERNAL);
122*0Sstevel@tonic-gate 	}
123*0Sstevel@tonic-gate 
124*0Sstevel@tonic-gate 	while ((elf_scn = elf_nextscn(elf_file, elf_scn)) != NULL) {
125*0Sstevel@tonic-gate 		if (gelf_getshdr(elf_scn, &gelf_shdr) == 0)
126*0Sstevel@tonic-gate 			continue;
127*0Sstevel@tonic-gate 
128*0Sstevel@tonic-gate 		if (gelf_shdr.sh_type != SHT_DYNAMIC)
129*0Sstevel@tonic-gate 			continue;
130*0Sstevel@tonic-gate 
131*0Sstevel@tonic-gate 		elf_data = elf_getdata(elf_scn, NULL);
132*0Sstevel@tonic-gate 		if (elf_data == NULL)
133*0Sstevel@tonic-gate 			continue;
134*0Sstevel@tonic-gate 
135*0Sstevel@tonic-gate 		i = 0;
136*0Sstevel@tonic-gate 		do {
137*0Sstevel@tonic-gate 			(void) gelf_getdyn(elf_data, i++, &gelf_dyn);
138*0Sstevel@tonic-gate 			if (gelf_dyn.d_tag == DT_SONAME)
139*0Sstevel@tonic-gate 				soname = elf_strptr(elf_file, gelf_shdr.sh_link,
140*0Sstevel@tonic-gate 				    gelf_dyn.d_un.d_ptr);
141*0Sstevel@tonic-gate 		} while (gelf_dyn.d_tag != DT_NULL && soname == NULL);
142*0Sstevel@tonic-gate 	}
143*0Sstevel@tonic-gate 	if (soname == NULL || sscanf(soname, "%*[^.].so.%d", converp) != 1) {
144*0Sstevel@tonic-gate 		(void) elf_end(elf_file);
145*0Sstevel@tonic-gate 		(void) close(elf_fd);
146*0Sstevel@tonic-gate 		return (DSVC_MODULE_ERR);
147*0Sstevel@tonic-gate 	}
148*0Sstevel@tonic-gate 	(void) elf_end(elf_file);
149*0Sstevel@tonic-gate 	(void) close(elf_fd);
150*0Sstevel@tonic-gate 
151*0Sstevel@tonic-gate 	return (DSVC_SUCCESS);
152*0Sstevel@tonic-gate }
153*0Sstevel@tonic-gate 
154*0Sstevel@tonic-gate /*
155*0Sstevel@tonic-gate  * Unload a public datastore module.
156*0Sstevel@tonic-gate  */
157*0Sstevel@tonic-gate static int
unload_public_module(void ** instance,dsvc_splapi_t * api)158*0Sstevel@tonic-gate unload_public_module(void **instance, dsvc_splapi_t *api)
159*0Sstevel@tonic-gate {
160*0Sstevel@tonic-gate 	static dsvc_splapi_t	null_api;
161*0Sstevel@tonic-gate 
162*0Sstevel@tonic-gate 	if (dlclose(*instance) != 0)
163*0Sstevel@tonic-gate 		return (DSVC_MODULE_UNLOAD_ERR);
164*0Sstevel@tonic-gate 
165*0Sstevel@tonic-gate 	*instance = NULL;
166*0Sstevel@tonic-gate 	*api = null_api;
167*0Sstevel@tonic-gate 
168*0Sstevel@tonic-gate 	return (DSVC_SUCCESS);
169*0Sstevel@tonic-gate }
170*0Sstevel@tonic-gate 
171*0Sstevel@tonic-gate /*
172*0Sstevel@tonic-gate  * Load public datastore module.  Validates version of module.  Returns
173*0Sstevel@tonic-gate  * instance of opened module, and populates the api argument with the
174*0Sstevel@tonic-gate  * function addresses exporting the API.
175*0Sstevel@tonic-gate  */
176*0Sstevel@tonic-gate static int
load_public_module(dsvc_datastore_t * ddp,void ** instance,dsvc_splapi_t * api)177*0Sstevel@tonic-gate load_public_module(dsvc_datastore_t *ddp, void **instance, dsvc_splapi_t *api)
178*0Sstevel@tonic-gate {
179*0Sstevel@tonic-gate 	int		i, v;
180*0Sstevel@tonic-gate 	dsvc_splfuncp_t	configure;
181*0Sstevel@tonic-gate 	char		path[MAXPATHLEN];
182*0Sstevel@tonic-gate 
183*0Sstevel@tonic-gate 	(void) snprintf(path, sizeof (path), "%s%s/%s_%s.so", DHCP_CONFOPT_ROOT,
184*0Sstevel@tonic-gate 	    DSVC_MODULE_DIR, DSVC_PUBLIC_PREFIX, ddp->d_resource);
185*0Sstevel@tonic-gate 
186*0Sstevel@tonic-gate 	if (ddp->d_conver != DSVC_CUR_CONVER)
187*0Sstevel@tonic-gate 		(void) snprintf(path, sizeof (path), "%s.%d", path,
188*0Sstevel@tonic-gate 		    ddp->d_conver);
189*0Sstevel@tonic-gate 
190*0Sstevel@tonic-gate 	*instance = dlopen(path, RTLD_LAZY|RTLD_GROUP|RTLD_WORLD);
191*0Sstevel@tonic-gate 	if (*instance == NULL)
192*0Sstevel@tonic-gate 		return (DSVC_MODULE_LOAD_ERR);
193*0Sstevel@tonic-gate 
194*0Sstevel@tonic-gate 	/*
195*0Sstevel@tonic-gate 	 * No requirement to duplicate the names - we can always reference
196*0Sstevel@tonic-gate 	 * the same set.
197*0Sstevel@tonic-gate 	 */
198*0Sstevel@tonic-gate 	api->version = (dsvc_splfuncp_t)dlsym(*instance, "version");
199*0Sstevel@tonic-gate 	if (api->version == NULL || api->version(&v) != DSVC_SUCCESS ||
200*0Sstevel@tonic-gate 	    v != DSVC_PUBLIC_VERSION) {
201*0Sstevel@tonic-gate 		(void) unload_public_module(instance, api);
202*0Sstevel@tonic-gate 		return (DSVC_MODULE_VERSION);
203*0Sstevel@tonic-gate 	}
204*0Sstevel@tonic-gate 
205*0Sstevel@tonic-gate 	configure = (dsvc_splfuncp_t)dlsym(*instance, "configure");
206*0Sstevel@tonic-gate 	if (configure != NULL) {
207*0Sstevel@tonic-gate 		if (configure(ddp->d_config) != DSVC_SUCCESS) {
208*0Sstevel@tonic-gate 			(void) unload_public_module(instance, api);
209*0Sstevel@tonic-gate 			return (DSVC_MODULE_CFG_ERR);
210*0Sstevel@tonic-gate 		}
211*0Sstevel@tonic-gate 	}
212*0Sstevel@tonic-gate 
213*0Sstevel@tonic-gate 	for (i = 0; i < DSVC_NSPLFUNCS; i++) {
214*0Sstevel@tonic-gate 		if ((((dsvc_splfuncp_t *)api)[i] =
215*0Sstevel@tonic-gate 		    (dsvc_splfuncp_t)dlsym(*instance, funcnames[i])) == NULL) {
216*0Sstevel@tonic-gate 			(void) unload_public_module(instance, api);
217*0Sstevel@tonic-gate 			return (DSVC_MODULE_ERR);
218*0Sstevel@tonic-gate 		}
219*0Sstevel@tonic-gate 	}
220*0Sstevel@tonic-gate 
221*0Sstevel@tonic-gate 	/*
222*0Sstevel@tonic-gate 	 * Caller requested the current version; fill in what that current
223*0Sstevel@tonic-gate 	 * version is.
224*0Sstevel@tonic-gate 	 */
225*0Sstevel@tonic-gate 	if (ddp->d_conver == DSVC_CUR_CONVER) {
226*0Sstevel@tonic-gate 		int	error;
227*0Sstevel@tonic-gate 		error = get_conver(ddp->d_resource, &ddp->d_conver);
228*0Sstevel@tonic-gate 		if (error != DSVC_SUCCESS) {
229*0Sstevel@tonic-gate 			(void) unload_public_module(instance, api);
230*0Sstevel@tonic-gate 			return (error);
231*0Sstevel@tonic-gate 		}
232*0Sstevel@tonic-gate 	}
233*0Sstevel@tonic-gate 
234*0Sstevel@tonic-gate 	return (DSVC_SUCCESS);
235*0Sstevel@tonic-gate }
236*0Sstevel@tonic-gate 
237*0Sstevel@tonic-gate /*
238*0Sstevel@tonic-gate  * Return a dynamically-allocated null-terminated list of the available
239*0Sstevel@tonic-gate  * modules stored in the module directory.  A count of the available
240*0Sstevel@tonic-gate  * modules is stored in the num argument.  Caller is responsible for
241*0Sstevel@tonic-gate  * freeing the list.
242*0Sstevel@tonic-gate  */
243*0Sstevel@tonic-gate int
enumerate_dd(char *** modules,int * nump)244*0Sstevel@tonic-gate enumerate_dd(char ***modules, int *nump)
245*0Sstevel@tonic-gate {
246*0Sstevel@tonic-gate 	int	i, retval;
247*0Sstevel@tonic-gate 	char	*ptr;
248*0Sstevel@tonic-gate 	glob_t	globbuf;
249*0Sstevel@tonic-gate 	char	globpat[MAXPATHLEN];
250*0Sstevel@tonic-gate 
251*0Sstevel@tonic-gate 	if (modules == NULL || nump == NULL)
252*0Sstevel@tonic-gate 		return (DSVC_INVAL);
253*0Sstevel@tonic-gate 
254*0Sstevel@tonic-gate 	(void) snprintf(globpat, sizeof (globpat), "%s%s/%s_*\\.so",
255*0Sstevel@tonic-gate 	    DHCP_CONFOPT_ROOT, DSVC_MODULE_DIR, DSVC_PUBLIC_PREFIX);
256*0Sstevel@tonic-gate 
257*0Sstevel@tonic-gate 	retval = glob(globpat, GLOB_NOSORT, NULL, &globbuf);
258*0Sstevel@tonic-gate 	if (retval != 0) {
259*0Sstevel@tonic-gate 		globfree(&globbuf);
260*0Sstevel@tonic-gate 		switch (retval) {
261*0Sstevel@tonic-gate 		case GLOB_NOMATCH:
262*0Sstevel@tonic-gate 			*nump = 0;
263*0Sstevel@tonic-gate 			*modules = NULL;
264*0Sstevel@tonic-gate 			return (DSVC_SUCCESS);
265*0Sstevel@tonic-gate 		case GLOB_NOSPACE:
266*0Sstevel@tonic-gate 			return (DSVC_NO_MEMORY);
267*0Sstevel@tonic-gate 		default:
268*0Sstevel@tonic-gate 			return (DSVC_INTERNAL);
269*0Sstevel@tonic-gate 		}
270*0Sstevel@tonic-gate 	}
271*0Sstevel@tonic-gate 
272*0Sstevel@tonic-gate 	*modules = calloc(globbuf.gl_pathc, sizeof (char **));
273*0Sstevel@tonic-gate 	if (*modules == NULL) {
274*0Sstevel@tonic-gate 		globfree(&globbuf);
275*0Sstevel@tonic-gate 		return (DSVC_NO_MEMORY);
276*0Sstevel@tonic-gate 	}
277*0Sstevel@tonic-gate 
278*0Sstevel@tonic-gate 	for (i = 0; i < globbuf.gl_pathc; i++) {
279*0Sstevel@tonic-gate 		ptr = strrchr(globbuf.gl_pathv[i], '/');
280*0Sstevel@tonic-gate 		if (ptr == NULL)
281*0Sstevel@tonic-gate 			ptr = globbuf.gl_pathv[i];
282*0Sstevel@tonic-gate 		else
283*0Sstevel@tonic-gate 			ptr++;
284*0Sstevel@tonic-gate 		(*modules)[i] = malloc(strlen(ptr) + 1);
285*0Sstevel@tonic-gate 		if ((*modules)[i] == NULL) {
286*0Sstevel@tonic-gate 			while (i--)
287*0Sstevel@tonic-gate 				free((*modules)[i]);
288*0Sstevel@tonic-gate 			free(modules);
289*0Sstevel@tonic-gate 			globfree(&globbuf);
290*0Sstevel@tonic-gate 			return (DSVC_NO_MEMORY);
291*0Sstevel@tonic-gate 		}
292*0Sstevel@tonic-gate 
293*0Sstevel@tonic-gate 		(void) sscanf(ptr, "%*[^_]_%[^.]", (*modules)[i]);
294*0Sstevel@tonic-gate 	}
295*0Sstevel@tonic-gate 
296*0Sstevel@tonic-gate 	globfree(&globbuf);
297*0Sstevel@tonic-gate 	*nump = i;
298*0Sstevel@tonic-gate 	return (DSVC_SUCCESS);
299*0Sstevel@tonic-gate }
300*0Sstevel@tonic-gate 
301*0Sstevel@tonic-gate /*
302*0Sstevel@tonic-gate  * Check the status of the underlying service supporting the data store.
303*0Sstevel@tonic-gate  * Caller is responsible for freeing any dynamically allocated arguments.
304*0Sstevel@tonic-gate  */
305*0Sstevel@tonic-gate int
status_dd(dsvc_datastore_t * ddp)306*0Sstevel@tonic-gate status_dd(dsvc_datastore_t *ddp)
307*0Sstevel@tonic-gate {
308*0Sstevel@tonic-gate 	void		*instance;
309*0Sstevel@tonic-gate 	dsvc_splapi_t	api;
310*0Sstevel@tonic-gate 	int		error;
311*0Sstevel@tonic-gate 
312*0Sstevel@tonic-gate 	error = load_public_module(ddp, &instance, &api);
313*0Sstevel@tonic-gate 	if (error != DSVC_SUCCESS)
314*0Sstevel@tonic-gate 		return (error);
315*0Sstevel@tonic-gate 
316*0Sstevel@tonic-gate 	error = api.status(ddp->d_location);
317*0Sstevel@tonic-gate 
318*0Sstevel@tonic-gate 	(void) unload_public_module(&instance, &api);
319*0Sstevel@tonic-gate 
320*0Sstevel@tonic-gate 	return (error);
321*0Sstevel@tonic-gate }
322*0Sstevel@tonic-gate 
323*0Sstevel@tonic-gate /*
324*0Sstevel@tonic-gate  * Create within the data store the "location" where containers will be
325*0Sstevel@tonic-gate  * stored.
326*0Sstevel@tonic-gate  */
327*0Sstevel@tonic-gate int
mklocation_dd(dsvc_datastore_t * ddp)328*0Sstevel@tonic-gate mklocation_dd(dsvc_datastore_t *ddp)
329*0Sstevel@tonic-gate {
330*0Sstevel@tonic-gate 	void		*instance;
331*0Sstevel@tonic-gate 	dsvc_splapi_t	api;
332*0Sstevel@tonic-gate 	int		error;
333*0Sstevel@tonic-gate 
334*0Sstevel@tonic-gate 	error = load_public_module(ddp, &instance, &api);
335*0Sstevel@tonic-gate 	if (error != DSVC_SUCCESS)
336*0Sstevel@tonic-gate 		return (error);
337*0Sstevel@tonic-gate 
338*0Sstevel@tonic-gate 	error = api.mklocation(ddp->d_location);
339*0Sstevel@tonic-gate 
340*0Sstevel@tonic-gate 	(void) unload_public_module(&instance, &api);
341*0Sstevel@tonic-gate 
342*0Sstevel@tonic-gate 	return (error);
343*0Sstevel@tonic-gate }
344*0Sstevel@tonic-gate 
345*0Sstevel@tonic-gate /*
346*0Sstevel@tonic-gate  * Return a list of the current container objects of type 'type' located at
347*0Sstevel@tonic-gate  * 'location' in listppp.  Return the number of list elements in 'count'.
348*0Sstevel@tonic-gate  */
349*0Sstevel@tonic-gate int
list_dd(dsvc_datastore_t * ddp,dsvc_contype_t type,char *** listppp,uint_t * count)350*0Sstevel@tonic-gate list_dd(dsvc_datastore_t *ddp, dsvc_contype_t type, char ***listppp,
351*0Sstevel@tonic-gate     uint_t *count)
352*0Sstevel@tonic-gate {
353*0Sstevel@tonic-gate 	void		*instance;
354*0Sstevel@tonic-gate 	dsvc_splapi_t	api;
355*0Sstevel@tonic-gate 	int		error;
356*0Sstevel@tonic-gate 
357*0Sstevel@tonic-gate 	error = load_public_module(ddp, &instance, &api);
358*0Sstevel@tonic-gate 	if (error != DSVC_SUCCESS)
359*0Sstevel@tonic-gate 		return (error);
360*0Sstevel@tonic-gate 
361*0Sstevel@tonic-gate 	if (type == DSVC_DHCPTAB)
362*0Sstevel@tonic-gate 		error = api.list_dt(ddp->d_location, listppp, count);
363*0Sstevel@tonic-gate 	else
364*0Sstevel@tonic-gate 		error = api.list_dn(ddp->d_location, listppp, count);
365*0Sstevel@tonic-gate 
366*0Sstevel@tonic-gate 	(void) unload_public_module(&instance, &api);
367*0Sstevel@tonic-gate 
368*0Sstevel@tonic-gate 	return (error);
369*0Sstevel@tonic-gate }
370*0Sstevel@tonic-gate 
371*0Sstevel@tonic-gate /*
372*0Sstevel@tonic-gate  * Creates or opens the DHCP container of type called name within the
373*0Sstevel@tonic-gate  * specific datastore referenced by ddp, and returns a handle to this
374*0Sstevel@tonic-gate  * container in the handp argument.  New containers are created with
375*0Sstevel@tonic-gate  * the identity of the caller.  Caller is responsible for freeing any
376*0Sstevel@tonic-gate  * dynamically allocated arguments.  The returned handle instance must
377*0Sstevel@tonic-gate  * be released by calling close_dd().
378*0Sstevel@tonic-gate  */
379*0Sstevel@tonic-gate int
open_dd(dsvc_handle_t * handp,dsvc_datastore_t * ddp,dsvc_contype_t type,const char * name,uint_t flags)380*0Sstevel@tonic-gate open_dd(dsvc_handle_t *handp, dsvc_datastore_t *ddp, dsvc_contype_t type,
381*0Sstevel@tonic-gate     const char *name, uint_t flags)
382*0Sstevel@tonic-gate {
383*0Sstevel@tonic-gate 	int			error;
384*0Sstevel@tonic-gate 	dsvc_handle_t		hp;
385*0Sstevel@tonic-gate 
386*0Sstevel@tonic-gate 	*handp = NULL;
387*0Sstevel@tonic-gate 
388*0Sstevel@tonic-gate 	if (type == DSVC_DHCPNETWORK && name == NULL)
389*0Sstevel@tonic-gate 		return (DSVC_INVAL);
390*0Sstevel@tonic-gate 
391*0Sstevel@tonic-gate 	if (flags & DSVC_CREATE && (flags & DSVC_WRITE) == 0)
392*0Sstevel@tonic-gate 		return (DSVC_INVAL);
393*0Sstevel@tonic-gate 
394*0Sstevel@tonic-gate 	if ((hp = calloc(1, sizeof (struct dsvc_handle))) == NULL)
395*0Sstevel@tonic-gate 		return (DSVC_NO_MEMORY);
396*0Sstevel@tonic-gate 
397*0Sstevel@tonic-gate 	if (type == DSVC_DHCPNETWORK) {
398*0Sstevel@tonic-gate 		hp->d_conid.c_net.s_addr = ntohl(inet_addr(name));
399*0Sstevel@tonic-gate 		if (hp->d_conid.c_net.s_addr == INADDR_BROADCAST) {
400*0Sstevel@tonic-gate 			free(hp);
401*0Sstevel@tonic-gate 			return (DSVC_INVAL);
402*0Sstevel@tonic-gate 		}
403*0Sstevel@tonic-gate 		get_netmask4(&hp->d_conid.c_net, &hp->d_conid.c_mask);
404*0Sstevel@tonic-gate 	}
405*0Sstevel@tonic-gate 
406*0Sstevel@tonic-gate 	error = load_public_module(ddp, &hp->d_instance, &hp->d_api);
407*0Sstevel@tonic-gate 	if (error != DSVC_SUCCESS) {
408*0Sstevel@tonic-gate 		free(hp);
409*0Sstevel@tonic-gate 		return (error);
410*0Sstevel@tonic-gate 	}
411*0Sstevel@tonic-gate 
412*0Sstevel@tonic-gate 	hp->d_type = type;
413*0Sstevel@tonic-gate 	hp->d_desc.d_conver = ddp->d_conver;
414*0Sstevel@tonic-gate 	hp->d_desc.d_resource = strdup(ddp->d_resource);
415*0Sstevel@tonic-gate 	hp->d_desc.d_location = strdup(ddp->d_location);
416*0Sstevel@tonic-gate 	if (hp->d_desc.d_resource == NULL || hp->d_desc.d_location == NULL) {
417*0Sstevel@tonic-gate 		error = DSVC_NO_MEMORY;
418*0Sstevel@tonic-gate 		goto error;
419*0Sstevel@tonic-gate 	}
420*0Sstevel@tonic-gate 
421*0Sstevel@tonic-gate 	/*
422*0Sstevel@tonic-gate 	 * Initialize the synchronization strategy (may not be any).
423*0Sstevel@tonic-gate 	 */
424*0Sstevel@tonic-gate 	error = synch_init(hp, name, flags);
425*0Sstevel@tonic-gate 	if (error != DSVC_SUCCESS)
426*0Sstevel@tonic-gate 		goto error;
427*0Sstevel@tonic-gate 
428*0Sstevel@tonic-gate 	if (type == DSVC_DHCPTAB)
429*0Sstevel@tonic-gate 		error = hp->d_api.open_dt(&hp->d_hand, ddp->d_location, flags);
430*0Sstevel@tonic-gate 	else
431*0Sstevel@tonic-gate 		error = hp->d_api.open_dn(&hp->d_hand, ddp->d_location, flags,
432*0Sstevel@tonic-gate 		    &hp->d_conid.c_net, &hp->d_conid.c_mask);
433*0Sstevel@tonic-gate 
434*0Sstevel@tonic-gate 	if (error != DSVC_SUCCESS) {
435*0Sstevel@tonic-gate 		if (hp->d_synch != NULL)
436*0Sstevel@tonic-gate 			synch_fini(hp);
437*0Sstevel@tonic-gate 		goto error;
438*0Sstevel@tonic-gate 	}
439*0Sstevel@tonic-gate 
440*0Sstevel@tonic-gate 	*handp = hp;
441*0Sstevel@tonic-gate 	return (DSVC_SUCCESS);
442*0Sstevel@tonic-gate error:
443*0Sstevel@tonic-gate 	(void) unload_public_module(&hp->d_instance, &hp->d_api);
444*0Sstevel@tonic-gate 	free(hp->d_desc.d_resource);
445*0Sstevel@tonic-gate 	free(hp->d_desc.d_location);
446*0Sstevel@tonic-gate 	free(hp);
447*0Sstevel@tonic-gate 	return (error);
448*0Sstevel@tonic-gate }
449*0Sstevel@tonic-gate 
450*0Sstevel@tonic-gate /*
451*0Sstevel@tonic-gate  * Remove DHCP container called name of type within the specific datastore
452*0Sstevel@tonic-gate  * referenced by ddp.  Caller is responsible for freeing any dynamically
453*0Sstevel@tonic-gate  * allocated arguments.
454*0Sstevel@tonic-gate  */
455*0Sstevel@tonic-gate int
remove_dd(dsvc_datastore_t * ddp,dsvc_contype_t type,const char * name)456*0Sstevel@tonic-gate remove_dd(dsvc_datastore_t *ddp, dsvc_contype_t type, const char *name)
457*0Sstevel@tonic-gate {
458*0Sstevel@tonic-gate 	void		*instance;
459*0Sstevel@tonic-gate 	int		error;
460*0Sstevel@tonic-gate 	dsvc_splapi_t	api;
461*0Sstevel@tonic-gate 	struct in_addr	ip, mask;
462*0Sstevel@tonic-gate 
463*0Sstevel@tonic-gate 	if (type != DSVC_DHCPTAB) {
464*0Sstevel@tonic-gate 		if ((ip.s_addr = inet_addr(name)) == INADDR_BROADCAST)
465*0Sstevel@tonic-gate 			return (DSVC_INVAL);
466*0Sstevel@tonic-gate 		ip.s_addr = ntohl(ip.s_addr);
467*0Sstevel@tonic-gate 		get_netmask4(&ip, &mask);
468*0Sstevel@tonic-gate 	}
469*0Sstevel@tonic-gate 
470*0Sstevel@tonic-gate 	error = load_public_module(ddp, &instance, &api);
471*0Sstevel@tonic-gate 	if (error != DSVC_SUCCESS)
472*0Sstevel@tonic-gate 		return (error);
473*0Sstevel@tonic-gate 
474*0Sstevel@tonic-gate 	/* remove the DHCP container */
475*0Sstevel@tonic-gate 	if (type == DSVC_DHCPTAB)
476*0Sstevel@tonic-gate 		error = api.remove_dt(ddp->d_location);
477*0Sstevel@tonic-gate 	else
478*0Sstevel@tonic-gate 		error = api.remove_dn(ddp->d_location, &ip, &mask);
479*0Sstevel@tonic-gate 
480*0Sstevel@tonic-gate 	(void) unload_public_module(&instance, &api);
481*0Sstevel@tonic-gate 
482*0Sstevel@tonic-gate 	return (error);
483*0Sstevel@tonic-gate }
484*0Sstevel@tonic-gate 
485*0Sstevel@tonic-gate /*
486*0Sstevel@tonic-gate  * Delete the handle instance referenced by hand. Frees hand if the close
487*0Sstevel@tonic-gate  * operation was successful.  NOTE: Caller is responsible for synchronizing
488*0Sstevel@tonic-gate  * multiple threads such that close_dd() is called when all consuming
489*0Sstevel@tonic-gate  * threads have exited.
490*0Sstevel@tonic-gate  */
491*0Sstevel@tonic-gate int
close_dd(dsvc_handle_t * handp)492*0Sstevel@tonic-gate close_dd(dsvc_handle_t *handp)
493*0Sstevel@tonic-gate {
494*0Sstevel@tonic-gate 	int	error;
495*0Sstevel@tonic-gate 
496*0Sstevel@tonic-gate 	if (handp == NULL || DSVC_HANDLE_INVAL(*handp))
497*0Sstevel@tonic-gate 		return (DSVC_INVAL);
498*0Sstevel@tonic-gate 
499*0Sstevel@tonic-gate 	if ((*handp)->d_type == DSVC_DHCPTAB)
500*0Sstevel@tonic-gate 		error = (*handp)->d_api.close_dt(&((*handp)->d_hand));
501*0Sstevel@tonic-gate 	else
502*0Sstevel@tonic-gate 		error = (*handp)->d_api.close_dn(&((*handp)->d_hand));
503*0Sstevel@tonic-gate 
504*0Sstevel@tonic-gate 	if (error == DSVC_SUCCESS) {
505*0Sstevel@tonic-gate 		error = unload_public_module(&(*handp)->d_instance,
506*0Sstevel@tonic-gate 		    &(*handp)->d_api);
507*0Sstevel@tonic-gate 		if ((*handp)->d_synch != NULL)
508*0Sstevel@tonic-gate 			synch_fini(*handp);
509*0Sstevel@tonic-gate 		free((*handp)->d_desc.d_resource);
510*0Sstevel@tonic-gate 		free((*handp)->d_desc.d_location);
511*0Sstevel@tonic-gate 		free(*handp);
512*0Sstevel@tonic-gate 		*handp = NULL;
513*0Sstevel@tonic-gate 	}
514*0Sstevel@tonic-gate 
515*0Sstevel@tonic-gate 	return (error);
516*0Sstevel@tonic-gate }
517*0Sstevel@tonic-gate 
518*0Sstevel@tonic-gate /*
519*0Sstevel@tonic-gate  * Searches hand container for records that match the query described by
520*0Sstevel@tonic-gate  * the combination of query and targetp. If the partial field is true, then
521*0Sstevel@tonic-gate  * lookup operations that have located some records but are unable to
522*0Sstevel@tonic-gate  * complete entirely are allowed.  The query argument consists of 2 fields,
523*0Sstevel@tonic-gate  * each 16 bits long. The lower 16 bits selects which fields in the targetp
524*0Sstevel@tonic-gate  * record are to be considered in the query. The upper 16 bits identifies
525*0Sstevel@tonic-gate  * whether a particular field value must match (bit set) or not match (bit
526*0Sstevel@tonic-gate  * clear). Unused bits in both 16 bit fields must be 0. The count argument
527*0Sstevel@tonic-gate  * specifies the maximum number of matching records to return. A count
528*0Sstevel@tonic-gate  * value of -1 requests that all matching records be returned. recordsp is
529*0Sstevel@tonic-gate  * set to point to the resulting list of records; if recordsp is NULL then
530*0Sstevel@tonic-gate  * no records are actually returned. Note that these records are
531*0Sstevel@tonic-gate  * dynamically allocated, thus the caller is responsible for freeing them.
532*0Sstevel@tonic-gate  * The number of records found is returned in nrecordsp; a value of 0 means
533*0Sstevel@tonic-gate  * that no records matched the query.
534*0Sstevel@tonic-gate  */
535*0Sstevel@tonic-gate int
lookup_dd(dsvc_handle_t hand,boolean_t partial,uint_t query,int count,const void * targetp,void ** recordsp,uint_t * nrecordsp)536*0Sstevel@tonic-gate lookup_dd(dsvc_handle_t hand, boolean_t partial, uint_t query,
537*0Sstevel@tonic-gate     int count, const void *targetp, void **recordsp, uint_t *nrecordsp)
538*0Sstevel@tonic-gate {
539*0Sstevel@tonic-gate 	uint_t	mask = 0;
540*0Sstevel@tonic-gate 	int	error;
541*0Sstevel@tonic-gate 	void	*unlock_cookie;
542*0Sstevel@tonic-gate 	int	(*lookup)();
543*0Sstevel@tonic-gate 
544*0Sstevel@tonic-gate 	if (targetp == NULL || nrecordsp == NULL || DSVC_HANDLE_INVAL(hand))
545*0Sstevel@tonic-gate 		return (DSVC_INVAL);
546*0Sstevel@tonic-gate 
547*0Sstevel@tonic-gate 	if (hand->d_type == DSVC_DHCPTAB) {
548*0Sstevel@tonic-gate 		mask = (uint_t)~DT_QALL;
549*0Sstevel@tonic-gate 		lookup = hand->d_api.lookup_dt;
550*0Sstevel@tonic-gate 	} else {
551*0Sstevel@tonic-gate 		mask = (uint_t)~DN_QALL;
552*0Sstevel@tonic-gate 		lookup = hand->d_api.lookup_dn;
553*0Sstevel@tonic-gate 	}
554*0Sstevel@tonic-gate 
555*0Sstevel@tonic-gate 	/* validate query */
556*0Sstevel@tonic-gate 	if (((query & 0xffff) & mask) || ((query >> 16) & mask))
557*0Sstevel@tonic-gate 		return (DSVC_INVAL);
558*0Sstevel@tonic-gate 
559*0Sstevel@tonic-gate 	/*
560*0Sstevel@tonic-gate 	 * XXX: need to validate the `targetp' -- what a mess cuz only the
561*0Sstevel@tonic-gate 	 *	fields lit in `query' need to be valid.
562*0Sstevel@tonic-gate 	 */
563*0Sstevel@tonic-gate 
564*0Sstevel@tonic-gate 	if (hand->d_synch != NULL) {
565*0Sstevel@tonic-gate 		error = DSVC_SYNCH_RDLOCK(hand->d_synch, &unlock_cookie);
566*0Sstevel@tonic-gate 		if (error != DSVC_SUCCESS)
567*0Sstevel@tonic-gate 			return (error);
568*0Sstevel@tonic-gate 	}
569*0Sstevel@tonic-gate 
570*0Sstevel@tonic-gate 	error = lookup(hand->d_hand, partial, query, count, targetp, recordsp,
571*0Sstevel@tonic-gate 	    nrecordsp);
572*0Sstevel@tonic-gate 
573*0Sstevel@tonic-gate 	if (hand->d_synch != NULL)
574*0Sstevel@tonic-gate 		(void) DSVC_SYNCH_UNLOCK(hand->d_synch, unlock_cookie);
575*0Sstevel@tonic-gate 
576*0Sstevel@tonic-gate 	return (error);
577*0Sstevel@tonic-gate }
578*0Sstevel@tonic-gate 
579*0Sstevel@tonic-gate /*
580*0Sstevel@tonic-gate  * Frees the record pointed to by entryp.
581*0Sstevel@tonic-gate  */
582*0Sstevel@tonic-gate void
free_dd(dsvc_handle_t hand,void * entryp)583*0Sstevel@tonic-gate free_dd(dsvc_handle_t hand, void *entryp)
584*0Sstevel@tonic-gate {
585*0Sstevel@tonic-gate 	if (DSVC_HANDLE_INVAL(hand) || entryp == NULL)
586*0Sstevel@tonic-gate 		return;
587*0Sstevel@tonic-gate 
588*0Sstevel@tonic-gate 	if (hand->d_type == DSVC_DHCPTAB)
589*0Sstevel@tonic-gate 		free_dtrec((dt_rec_t *)entryp);
590*0Sstevel@tonic-gate 	else
591*0Sstevel@tonic-gate 		free_dnrec((dn_rec_t *)entryp);
592*0Sstevel@tonic-gate }
593*0Sstevel@tonic-gate 
594*0Sstevel@tonic-gate /*
595*0Sstevel@tonic-gate  * Frees the list of records pointed to by listp.
596*0Sstevel@tonic-gate  */
597*0Sstevel@tonic-gate void
free_dd_list(dsvc_handle_t hand,void * listp)598*0Sstevel@tonic-gate free_dd_list(dsvc_handle_t hand, void *listp)
599*0Sstevel@tonic-gate {
600*0Sstevel@tonic-gate 	if (DSVC_HANDLE_INVAL(hand) || listp == NULL)
601*0Sstevel@tonic-gate 		return;
602*0Sstevel@tonic-gate 
603*0Sstevel@tonic-gate 	if (hand->d_type == DSVC_DHCPTAB)
604*0Sstevel@tonic-gate 		free_dtrec_list((dt_rec_list_t *)listp);
605*0Sstevel@tonic-gate 	else
606*0Sstevel@tonic-gate 		free_dnrec_list((dn_rec_list_t *)listp);
607*0Sstevel@tonic-gate }
608*0Sstevel@tonic-gate 
609*0Sstevel@tonic-gate /*
610*0Sstevel@tonic-gate  * Add the record newp to the DHCP container hand. newp's update signature
611*0Sstevel@tonic-gate  * will be updated by the public layer module doing the update. Caller is
612*0Sstevel@tonic-gate  * responsible for freeing newp if it was dynamically allocated.
613*0Sstevel@tonic-gate  */
614*0Sstevel@tonic-gate int
add_dd_entry(dsvc_handle_t hand,void * newp)615*0Sstevel@tonic-gate add_dd_entry(dsvc_handle_t hand, void *newp)
616*0Sstevel@tonic-gate {
617*0Sstevel@tonic-gate 	int	error;
618*0Sstevel@tonic-gate 	void	*unlock_cookie;
619*0Sstevel@tonic-gate 
620*0Sstevel@tonic-gate 	if (DSVC_HANDLE_INVAL(hand))
621*0Sstevel@tonic-gate 		return (DSVC_INVAL);
622*0Sstevel@tonic-gate 
623*0Sstevel@tonic-gate 	if (!validate_dd_entry(hand, newp, B_FALSE))
624*0Sstevel@tonic-gate 		return (DSVC_INVAL);
625*0Sstevel@tonic-gate 
626*0Sstevel@tonic-gate 	if (hand->d_synch != NULL) {
627*0Sstevel@tonic-gate 		error = DSVC_SYNCH_WRLOCK(hand->d_synch, &unlock_cookie);
628*0Sstevel@tonic-gate 		if (error != DSVC_SUCCESS)
629*0Sstevel@tonic-gate 			return (error);
630*0Sstevel@tonic-gate 	}
631*0Sstevel@tonic-gate 
632*0Sstevel@tonic-gate 	if (hand->d_type == DSVC_DHCPTAB)
633*0Sstevel@tonic-gate 		error = hand->d_api.add_dt(hand->d_hand, newp);
634*0Sstevel@tonic-gate 	else
635*0Sstevel@tonic-gate 		error = hand->d_api.add_dn(hand->d_hand, newp);
636*0Sstevel@tonic-gate 
637*0Sstevel@tonic-gate 	if (hand->d_synch != NULL)
638*0Sstevel@tonic-gate 		(void) DSVC_SYNCH_UNLOCK(hand->d_synch, unlock_cookie);
639*0Sstevel@tonic-gate 
640*0Sstevel@tonic-gate 	return (error);
641*0Sstevel@tonic-gate }
642*0Sstevel@tonic-gate 
643*0Sstevel@tonic-gate /*
644*0Sstevel@tonic-gate  * Modify the record origp with the record newp in the DHCP container hand.
645*0Sstevel@tonic-gate  * newp's update signature will be updated by the public layer module doing
646*0Sstevel@tonic-gate  * the update. Caller is responsible for freeing origp and/or newp if they
647*0Sstevel@tonic-gate  * were dynamically allocated.
648*0Sstevel@tonic-gate  */
649*0Sstevel@tonic-gate int
modify_dd_entry(dsvc_handle_t hand,const void * origp,void * newp)650*0Sstevel@tonic-gate modify_dd_entry(dsvc_handle_t hand, const void *origp, void *newp)
651*0Sstevel@tonic-gate {
652*0Sstevel@tonic-gate 	int	error;
653*0Sstevel@tonic-gate 	void 	*unlock_cookie;
654*0Sstevel@tonic-gate 
655*0Sstevel@tonic-gate 	if (DSVC_HANDLE_INVAL(hand))
656*0Sstevel@tonic-gate 		return (DSVC_INVAL);
657*0Sstevel@tonic-gate 
658*0Sstevel@tonic-gate 	if (!validate_dd_entry(hand, origp, B_TRUE))
659*0Sstevel@tonic-gate 		return (DSVC_INVAL);
660*0Sstevel@tonic-gate 
661*0Sstevel@tonic-gate 	if (!validate_dd_entry(hand, newp, B_FALSE))
662*0Sstevel@tonic-gate 		return (DSVC_INVAL);
663*0Sstevel@tonic-gate 
664*0Sstevel@tonic-gate 	if (hand->d_synch != NULL) {
665*0Sstevel@tonic-gate 		error = DSVC_SYNCH_WRLOCK(hand->d_synch, &unlock_cookie);
666*0Sstevel@tonic-gate 		if (error != DSVC_SUCCESS)
667*0Sstevel@tonic-gate 			return (error);
668*0Sstevel@tonic-gate 	}
669*0Sstevel@tonic-gate 
670*0Sstevel@tonic-gate 	if (hand->d_type == DSVC_DHCPTAB)
671*0Sstevel@tonic-gate 		error = hand->d_api.modify_dt(hand->d_hand, origp, newp);
672*0Sstevel@tonic-gate 	else
673*0Sstevel@tonic-gate 		error = hand->d_api.modify_dn(hand->d_hand, origp, newp);
674*0Sstevel@tonic-gate 
675*0Sstevel@tonic-gate 	if (hand->d_synch != NULL)
676*0Sstevel@tonic-gate 		(void) DSVC_SYNCH_UNLOCK(hand->d_synch, unlock_cookie);
677*0Sstevel@tonic-gate 
678*0Sstevel@tonic-gate 	return (error);
679*0Sstevel@tonic-gate }
680*0Sstevel@tonic-gate 
681*0Sstevel@tonic-gate /*
682*0Sstevel@tonic-gate  * Deletes the record referred to by entryp from the DHCP container hand.
683*0Sstevel@tonic-gate  * Caller is responsible for freeing entryp if it was dynamically
684*0Sstevel@tonic-gate  * allocated.
685*0Sstevel@tonic-gate  */
686*0Sstevel@tonic-gate int
delete_dd_entry(dsvc_handle_t hand,void * entryp)687*0Sstevel@tonic-gate delete_dd_entry(dsvc_handle_t hand, void *entryp)
688*0Sstevel@tonic-gate {
689*0Sstevel@tonic-gate 	int	error;
690*0Sstevel@tonic-gate 	void	*unlock_cookie;
691*0Sstevel@tonic-gate 
692*0Sstevel@tonic-gate 	if (DSVC_HANDLE_INVAL(hand))
693*0Sstevel@tonic-gate 		return (DSVC_INVAL);
694*0Sstevel@tonic-gate 
695*0Sstevel@tonic-gate 	if (!validate_dd_entry(hand, entryp, B_TRUE))
696*0Sstevel@tonic-gate 		return (DSVC_INVAL);
697*0Sstevel@tonic-gate 
698*0Sstevel@tonic-gate 	if (hand->d_synch != NULL) {
699*0Sstevel@tonic-gate 		error = DSVC_SYNCH_WRLOCK(hand->d_synch, &unlock_cookie);
700*0Sstevel@tonic-gate 		if (error != DSVC_SUCCESS)
701*0Sstevel@tonic-gate 			return (error);
702*0Sstevel@tonic-gate 	}
703*0Sstevel@tonic-gate 
704*0Sstevel@tonic-gate 	if (hand->d_type == DSVC_DHCPTAB)
705*0Sstevel@tonic-gate 		error = hand->d_api.delete_dt(hand->d_hand, entryp);
706*0Sstevel@tonic-gate 	else
707*0Sstevel@tonic-gate 		error = hand->d_api.delete_dn(hand->d_hand, entryp);
708*0Sstevel@tonic-gate 
709*0Sstevel@tonic-gate 	if (hand->d_synch != NULL)
710*0Sstevel@tonic-gate 		(void) DSVC_SYNCH_UNLOCK(hand->d_synch, unlock_cookie);
711*0Sstevel@tonic-gate 
712*0Sstevel@tonic-gate 	return (error);
713*0Sstevel@tonic-gate }
714*0Sstevel@tonic-gate 
715*0Sstevel@tonic-gate /*
716*0Sstevel@tonic-gate  * Validate that the DHCP network record `dn' is correctly formed; returns
717*0Sstevel@tonic-gate  * B_TRUE if it is, B_FALSE if it's not.  If `justkey' is set, then only
718*0Sstevel@tonic-gate  * validate the key.
719*0Sstevel@tonic-gate  */
720*0Sstevel@tonic-gate static boolean_t
validate_dnrec(dsvc_handle_t hand,const dn_rec_t * dn,boolean_t justkey)721*0Sstevel@tonic-gate validate_dnrec(dsvc_handle_t hand, const dn_rec_t *dn, boolean_t justkey)
722*0Sstevel@tonic-gate {
723*0Sstevel@tonic-gate 	/* CIP must be on container's network */
724*0Sstevel@tonic-gate 	if (hand->d_conid.c_net.s_addr !=
725*0Sstevel@tonic-gate 	    (dn->dn_cip.s_addr & hand->d_conid.c_mask.s_addr))
726*0Sstevel@tonic-gate 		return (B_FALSE);
727*0Sstevel@tonic-gate 
728*0Sstevel@tonic-gate 	if (justkey)
729*0Sstevel@tonic-gate 		return (B_TRUE);
730*0Sstevel@tonic-gate 
731*0Sstevel@tonic-gate 	if (dn->dn_cid_len < 1 || dn->dn_cid_len > DN_MAX_CID_LEN)
732*0Sstevel@tonic-gate 		return (B_FALSE);
733*0Sstevel@tonic-gate 
734*0Sstevel@tonic-gate 	if ((dn->dn_flags & ~DN_FALL) != 0)
735*0Sstevel@tonic-gate 		return (B_FALSE);
736*0Sstevel@tonic-gate 
737*0Sstevel@tonic-gate 	return (B_TRUE);
738*0Sstevel@tonic-gate }
739*0Sstevel@tonic-gate 
740*0Sstevel@tonic-gate /*
741*0Sstevel@tonic-gate  * Validate that the dhcptab record `dt' is correctly formed; returns
742*0Sstevel@tonic-gate  * B_TRUE if it is, B_FALSE if it's not.  If `justkey' is set, then only
743*0Sstevel@tonic-gate  * validate the key.
744*0Sstevel@tonic-gate  */
745*0Sstevel@tonic-gate /* ARGSUSED */
746*0Sstevel@tonic-gate static boolean_t
validate_dtrec(dsvc_handle_t hand,const dt_rec_t * dt,boolean_t justkey)747*0Sstevel@tonic-gate validate_dtrec(dsvc_handle_t hand, const dt_rec_t *dt, boolean_t justkey)
748*0Sstevel@tonic-gate {
749*0Sstevel@tonic-gate 	return (dt->dt_type == DT_SYMBOL || dt->dt_type == DT_MACRO);
750*0Sstevel@tonic-gate }
751*0Sstevel@tonic-gate 
752*0Sstevel@tonic-gate /*
753*0Sstevel@tonic-gate  * Validate that a DHCP record of type `hand->d_type' is correctly formed;
754*0Sstevel@tonic-gate  * returns B_TRUE if it is, B_FALSE if it's not.  If `justkey' is set, then
755*0Sstevel@tonic-gate  * only validate the key.
756*0Sstevel@tonic-gate  */
757*0Sstevel@tonic-gate static boolean_t
validate_dd_entry(dsvc_handle_t hand,const void * entryp,boolean_t justkey)758*0Sstevel@tonic-gate validate_dd_entry(dsvc_handle_t hand, const void *entryp, boolean_t justkey)
759*0Sstevel@tonic-gate {
760*0Sstevel@tonic-gate 	if (entryp == NULL)
761*0Sstevel@tonic-gate 		return (B_FALSE);
762*0Sstevel@tonic-gate 
763*0Sstevel@tonic-gate 	if (hand->d_type == DSVC_DHCPTAB)
764*0Sstevel@tonic-gate 		return (validate_dtrec(hand, (dt_rec_t *)entryp, justkey));
765*0Sstevel@tonic-gate 	else if (hand->d_type == DSVC_DHCPNETWORK)
766*0Sstevel@tonic-gate 		return (validate_dnrec(hand, (dn_rec_t *)entryp, justkey));
767*0Sstevel@tonic-gate 
768*0Sstevel@tonic-gate 	return (B_FALSE);
769*0Sstevel@tonic-gate }
770*0Sstevel@tonic-gate 
771*0Sstevel@tonic-gate /*
772*0Sstevel@tonic-gate  * Get the type of synchronization needed for this module and store in
773*0Sstevel@tonic-gate  * `synchtypep'.  Returns a DSVC_* code.  This function is exported so that
774*0Sstevel@tonic-gate  * dsvclockd(1M) can use it.
775*0Sstevel@tonic-gate  */
776*0Sstevel@tonic-gate int
module_synchtype(dsvc_datastore_t * ddp,dsvc_synchtype_t * synchtypep)777*0Sstevel@tonic-gate module_synchtype(dsvc_datastore_t *ddp, dsvc_synchtype_t *synchtypep)
778*0Sstevel@tonic-gate {
779*0Sstevel@tonic-gate 	void			*instance;
780*0Sstevel@tonic-gate 	dsvc_splapi_t		api;
781*0Sstevel@tonic-gate 	dsvc_synchtype_t	*dsvc_synchtypep;
782*0Sstevel@tonic-gate 
783*0Sstevel@tonic-gate 	if (load_public_module(ddp, &instance, &api) != DSVC_SUCCESS)
784*0Sstevel@tonic-gate 		return (DSVC_INTERNAL);
785*0Sstevel@tonic-gate 
786*0Sstevel@tonic-gate 	dsvc_synchtypep = dlsym(instance, "dsvc_synchtype");
787*0Sstevel@tonic-gate 	if (dsvc_synchtypep != NULL)
788*0Sstevel@tonic-gate 		*synchtypep = *dsvc_synchtypep;
789*0Sstevel@tonic-gate 	else
790*0Sstevel@tonic-gate 		*synchtypep = DSVC_SYNCH_NONE;
791*0Sstevel@tonic-gate 
792*0Sstevel@tonic-gate 	(void) unload_public_module(&instance, &api);
793*0Sstevel@tonic-gate 
794*0Sstevel@tonic-gate 	return (DSVC_SUCCESS);
795*0Sstevel@tonic-gate }
796*0Sstevel@tonic-gate 
797*0Sstevel@tonic-gate /*
798*0Sstevel@tonic-gate  * Initialize private-layer synchronization on handle `hand' for container
799*0Sstevel@tonic-gate  * `conname'; `flags' is the same flags passed into open_dd().  If there's
800*0Sstevel@tonic-gate  * no synchronization needed, always succeeds.  Returns a DSVC_* code.
801*0Sstevel@tonic-gate  */
802*0Sstevel@tonic-gate int
synch_init(dsvc_handle_t hand,const char * conname,uint_t flags)803*0Sstevel@tonic-gate synch_init(dsvc_handle_t hand, const char *conname, uint_t flags)
804*0Sstevel@tonic-gate {
805*0Sstevel@tonic-gate 	dsvc_synchtype_t	synchtype;
806*0Sstevel@tonic-gate 	dsvc_synch_t		*sp;
807*0Sstevel@tonic-gate 	int 			error;
808*0Sstevel@tonic-gate 	int			(*mkloctoken)(const char *, char *, size_t);
809*0Sstevel@tonic-gate 
810*0Sstevel@tonic-gate 	error = module_synchtype(&hand->d_desc, &synchtype);
811*0Sstevel@tonic-gate 	if (error != DSVC_SUCCESS)
812*0Sstevel@tonic-gate 		return (error);
813*0Sstevel@tonic-gate 
814*0Sstevel@tonic-gate 	if (synchtype == DSVC_SYNCH_NONE)
815*0Sstevel@tonic-gate 		return (DSVC_SUCCESS);
816*0Sstevel@tonic-gate 
817*0Sstevel@tonic-gate 	sp = malloc(sizeof (dsvc_synch_t));
818*0Sstevel@tonic-gate 	if (sp == NULL)
819*0Sstevel@tonic-gate 		return (DSVC_NO_MEMORY);
820*0Sstevel@tonic-gate 
821*0Sstevel@tonic-gate 	sp->s_conname = strdup(conname);
822*0Sstevel@tonic-gate 	if (sp->s_conname == NULL) {
823*0Sstevel@tonic-gate 		free(sp);
824*0Sstevel@tonic-gate 		return (DSVC_NO_MEMORY);
825*0Sstevel@tonic-gate 	}
826*0Sstevel@tonic-gate 	sp->s_nonblock	= flags & DSVC_NONBLOCK;
827*0Sstevel@tonic-gate 	sp->s_datastore = &hand->d_desc;
828*0Sstevel@tonic-gate 
829*0Sstevel@tonic-gate 	mkloctoken = (int (*)())dlsym(hand->d_instance, "mkloctoken");
830*0Sstevel@tonic-gate 	if (mkloctoken == NULL) {
831*0Sstevel@tonic-gate 		(void) strlcpy(sp->s_loctoken, sp->s_datastore->d_location,
832*0Sstevel@tonic-gate 		    sizeof (sp->s_loctoken));
833*0Sstevel@tonic-gate 	} else {
834*0Sstevel@tonic-gate 		error = mkloctoken(sp->s_datastore->d_location, sp->s_loctoken,
835*0Sstevel@tonic-gate 		    sizeof (sp->s_loctoken));
836*0Sstevel@tonic-gate 		if (error != DSVC_SUCCESS) {
837*0Sstevel@tonic-gate 			free(sp->s_conname);
838*0Sstevel@tonic-gate 			free(sp);
839*0Sstevel@tonic-gate 			return (error);
840*0Sstevel@tonic-gate 		}
841*0Sstevel@tonic-gate 	}
842*0Sstevel@tonic-gate 
843*0Sstevel@tonic-gate 	/*
844*0Sstevel@tonic-gate 	 * The only synchtype supported is DSVC_SYNCH_DSVCD; if this
845*0Sstevel@tonic-gate 	 * changes, we'll need to enhance this.
846*0Sstevel@tonic-gate 	 */
847*0Sstevel@tonic-gate 	assert((synchtype & DSVC_SYNCH_STRATMASK) == DSVC_SYNCH_DSVCD);
848*0Sstevel@tonic-gate 	sp->s_ops = &dsvcd_synch_ops;
849*0Sstevel@tonic-gate 
850*0Sstevel@tonic-gate 	error = DSVC_SYNCH_INIT(sp, synchtype & DSVC_SYNCH_FLAGMASK);
851*0Sstevel@tonic-gate 	if (error != DSVC_SUCCESS) {
852*0Sstevel@tonic-gate 		free(sp->s_conname);
853*0Sstevel@tonic-gate 		free(sp);
854*0Sstevel@tonic-gate 		return (error);
855*0Sstevel@tonic-gate 	}
856*0Sstevel@tonic-gate 
857*0Sstevel@tonic-gate 	hand->d_synch = sp;
858*0Sstevel@tonic-gate 	return (DSVC_SUCCESS);
859*0Sstevel@tonic-gate }
860*0Sstevel@tonic-gate 
861*0Sstevel@tonic-gate /*
862*0Sstevel@tonic-gate  * Finish using private-layer synchronization on handle `hand'.
863*0Sstevel@tonic-gate  */
864*0Sstevel@tonic-gate void
synch_fini(dsvc_handle_t hand)865*0Sstevel@tonic-gate synch_fini(dsvc_handle_t hand)
866*0Sstevel@tonic-gate {
867*0Sstevel@tonic-gate 	DSVC_SYNCH_FINI(hand->d_synch);
868*0Sstevel@tonic-gate 	free(hand->d_synch->s_conname);
869*0Sstevel@tonic-gate 	free(hand->d_synch);
870*0Sstevel@tonic-gate 	hand->d_synch = NULL;
871*0Sstevel@tonic-gate }
872