xref: /onnv-gate/usr/src/lib/libipmp/common/ipmp_query.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 2002 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
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  * IPMP query interfaces (PSARC/2002/615).
31*0Sstevel@tonic-gate  */
32*0Sstevel@tonic-gate 
33*0Sstevel@tonic-gate #include <assert.h>
34*0Sstevel@tonic-gate #include <errno.h>
35*0Sstevel@tonic-gate #include <string.h>
36*0Sstevel@tonic-gate #include <stdlib.h>
37*0Sstevel@tonic-gate #include <unistd.h>
38*0Sstevel@tonic-gate #include <sys/types.h>
39*0Sstevel@tonic-gate 
40*0Sstevel@tonic-gate #include "ipmp_impl.h"
41*0Sstevel@tonic-gate #include "ipmp_mpathd.h"
42*0Sstevel@tonic-gate #include "ipmp_query_impl.h"
43*0Sstevel@tonic-gate 
44*0Sstevel@tonic-gate #define	IPMP_REQTIMEOUT	5	/* seconds */
45*0Sstevel@tonic-gate 
46*0Sstevel@tonic-gate static ipmp_ifinfo_t	*ipmp_ifinfo_clone(ipmp_ifinfo_t *);
47*0Sstevel@tonic-gate static ipmp_grouplist_t	*ipmp_grouplist_clone(ipmp_grouplist_t *);
48*0Sstevel@tonic-gate static ipmp_groupinfo_t	*ipmp_groupinfo_clone(ipmp_groupinfo_t *);
49*0Sstevel@tonic-gate static ipmp_groupinfo_t *ipmp_snap_getgroupinfo(ipmp_snap_t *, const char *);
50*0Sstevel@tonic-gate static ipmp_ifinfo_t	*ipmp_snap_getifinfo(ipmp_snap_t *, const char *);
51*0Sstevel@tonic-gate static int		ipmp_snap_take(ipmp_state_t *, ipmp_snap_t **);
52*0Sstevel@tonic-gate static boolean_t	ipmp_checktlv(ipmp_infotype_t, size_t, void *);
53*0Sstevel@tonic-gate static int		ipmp_querydone(ipmp_state_t *, int);
54*0Sstevel@tonic-gate 
55*0Sstevel@tonic-gate /*
56*0Sstevel@tonic-gate  * Using `statep', send a query request for `type' to in.mpathd, and if
57*0Sstevel@tonic-gate  * necessary wait until at least `endtp' for a response.  Returns an IPMP
58*0Sstevel@tonic-gate  * error code.  If successful, the caller may then read additional query
59*0Sstevel@tonic-gate  * information through ipmp_readinfo(), and must eventually call
60*0Sstevel@tonic-gate  * ipmp_querydone() to complete the query operation.  Only one query may be
61*0Sstevel@tonic-gate  * outstanding on a given `statep' at a time.
62*0Sstevel@tonic-gate  */
63*0Sstevel@tonic-gate static int
64*0Sstevel@tonic-gate ipmp_sendquery(ipmp_state_t *statep, ipmp_infotype_t type, const char *name,
65*0Sstevel@tonic-gate     struct timeval *endtp)
66*0Sstevel@tonic-gate {
67*0Sstevel@tonic-gate 	mi_query_t	query;
68*0Sstevel@tonic-gate 	mi_result_t	result;
69*0Sstevel@tonic-gate 	int		retval;
70*0Sstevel@tonic-gate 
71*0Sstevel@tonic-gate 	query.miq_command = MI_QUERY;
72*0Sstevel@tonic-gate 	query.miq_inforeq = type;
73*0Sstevel@tonic-gate 
74*0Sstevel@tonic-gate 	switch (type) {
75*0Sstevel@tonic-gate 	case IPMP_GROUPINFO:
76*0Sstevel@tonic-gate 		(void) strlcpy(query.miq_grname, name, LIFGRNAMSIZ);
77*0Sstevel@tonic-gate 		break;
78*0Sstevel@tonic-gate 
79*0Sstevel@tonic-gate 	case IPMP_IFINFO:
80*0Sstevel@tonic-gate 		(void) strlcpy(query.miq_ifname, name, LIFNAMSIZ);
81*0Sstevel@tonic-gate 		break;
82*0Sstevel@tonic-gate 
83*0Sstevel@tonic-gate 	case IPMP_GROUPLIST:
84*0Sstevel@tonic-gate 	case IPMP_SNAP:
85*0Sstevel@tonic-gate 		break;
86*0Sstevel@tonic-gate 
87*0Sstevel@tonic-gate 	default:
88*0Sstevel@tonic-gate 		assert(0);
89*0Sstevel@tonic-gate 	}
90*0Sstevel@tonic-gate 
91*0Sstevel@tonic-gate 	if (gettimeofday(endtp, NULL) == -1)
92*0Sstevel@tonic-gate 		return (IPMP_FAILURE);
93*0Sstevel@tonic-gate 
94*0Sstevel@tonic-gate 	endtp->tv_sec += IPMP_REQTIMEOUT;
95*0Sstevel@tonic-gate 
96*0Sstevel@tonic-gate 	assert(statep->st_fd == -1);
97*0Sstevel@tonic-gate 	retval = ipmp_connect(&statep->st_fd);
98*0Sstevel@tonic-gate 	if (retval != IPMP_SUCCESS)
99*0Sstevel@tonic-gate 		return (retval);
100*0Sstevel@tonic-gate 
101*0Sstevel@tonic-gate 	retval = ipmp_write(statep->st_fd, &query, sizeof (query));
102*0Sstevel@tonic-gate 	if (retval != IPMP_SUCCESS)
103*0Sstevel@tonic-gate 		return (ipmp_querydone(statep, retval));
104*0Sstevel@tonic-gate 
105*0Sstevel@tonic-gate 	retval = ipmp_read(statep->st_fd, &result, sizeof (result), endtp);
106*0Sstevel@tonic-gate 	if (retval != IPMP_SUCCESS)
107*0Sstevel@tonic-gate 		return (ipmp_querydone(statep, retval));
108*0Sstevel@tonic-gate 
109*0Sstevel@tonic-gate 	if (result.me_mpathd_error != IPMP_SUCCESS)
110*0Sstevel@tonic-gate 		return (ipmp_querydone(statep, result.me_mpathd_error));
111*0Sstevel@tonic-gate 
112*0Sstevel@tonic-gate 	return (IPMP_SUCCESS);
113*0Sstevel@tonic-gate }
114*0Sstevel@tonic-gate 
115*0Sstevel@tonic-gate /*
116*0Sstevel@tonic-gate  * Using `statep', read a query response of type `infotype' into a dynamically
117*0Sstevel@tonic-gate  * allocated buffer pointed to by `*infop', before the current time becomes
118*0Sstevel@tonic-gate  * `endtp'.  Returns an IPMP error code.
119*0Sstevel@tonic-gate  */
120*0Sstevel@tonic-gate static int
121*0Sstevel@tonic-gate ipmp_readinfo(ipmp_state_t *statep, ipmp_infotype_t infotype, void **infop,
122*0Sstevel@tonic-gate     const struct timeval *endtp)
123*0Sstevel@tonic-gate {
124*0Sstevel@tonic-gate 	int		retval;
125*0Sstevel@tonic-gate 	size_t		len;
126*0Sstevel@tonic-gate 	ipmp_infotype_t	type;
127*0Sstevel@tonic-gate 
128*0Sstevel@tonic-gate 	retval = ipmp_readtlv(statep->st_fd, &type, &len, infop, endtp);
129*0Sstevel@tonic-gate 	if (retval != IPMP_SUCCESS)
130*0Sstevel@tonic-gate 		return (retval);
131*0Sstevel@tonic-gate 
132*0Sstevel@tonic-gate 	if (type != infotype || !ipmp_checktlv(type, len, *infop)) {
133*0Sstevel@tonic-gate 		free(*infop);
134*0Sstevel@tonic-gate 		return (IPMP_EPROTO);
135*0Sstevel@tonic-gate 	}
136*0Sstevel@tonic-gate 
137*0Sstevel@tonic-gate 	return (IPMP_SUCCESS);
138*0Sstevel@tonic-gate }
139*0Sstevel@tonic-gate 
140*0Sstevel@tonic-gate /*
141*0Sstevel@tonic-gate  * Complete the query operation started in ipmp_sendquery().  The interface is
142*0Sstevel@tonic-gate  * designed to be easy to use in the `return' statement of a function, and
143*0Sstevel@tonic-gate  * thus returns the passed in `retval' and preserves `errno'.
144*0Sstevel@tonic-gate  */
145*0Sstevel@tonic-gate static int
146*0Sstevel@tonic-gate ipmp_querydone(ipmp_state_t *statep, int retval)
147*0Sstevel@tonic-gate {
148*0Sstevel@tonic-gate 	int error = errno;
149*0Sstevel@tonic-gate 
150*0Sstevel@tonic-gate 	(void) close(statep->st_fd);
151*0Sstevel@tonic-gate 	statep->st_fd = -1;
152*0Sstevel@tonic-gate 	errno = error;
153*0Sstevel@tonic-gate 	return (retval);
154*0Sstevel@tonic-gate }
155*0Sstevel@tonic-gate 
156*0Sstevel@tonic-gate /*
157*0Sstevel@tonic-gate  * Using `handle', get the group list and store the results in a dynamically
158*0Sstevel@tonic-gate  * allocated buffer pointed to by `*grlistpp'.  Returns an IPMP error code.
159*0Sstevel@tonic-gate  */
160*0Sstevel@tonic-gate int
161*0Sstevel@tonic-gate ipmp_getgrouplist(ipmp_handle_t handle, ipmp_grouplist_t **grlistpp)
162*0Sstevel@tonic-gate {
163*0Sstevel@tonic-gate 	ipmp_state_t	*statep = handle;
164*0Sstevel@tonic-gate 	struct timeval	end;
165*0Sstevel@tonic-gate 	int		retval;
166*0Sstevel@tonic-gate 
167*0Sstevel@tonic-gate 	if (statep->st_snap != NULL) {
168*0Sstevel@tonic-gate 		*grlistpp = ipmp_grouplist_clone(statep->st_snap->sn_grlistp);
169*0Sstevel@tonic-gate 		return (*grlistpp != NULL ? IPMP_SUCCESS : IPMP_ENOMEM);
170*0Sstevel@tonic-gate 	}
171*0Sstevel@tonic-gate 
172*0Sstevel@tonic-gate 	retval = ipmp_sendquery(statep, IPMP_GROUPLIST, NULL, &end);
173*0Sstevel@tonic-gate 	if (retval != IPMP_SUCCESS)
174*0Sstevel@tonic-gate 		return (retval);
175*0Sstevel@tonic-gate 
176*0Sstevel@tonic-gate 	retval = ipmp_readinfo(statep, IPMP_GROUPLIST, (void **)grlistpp, &end);
177*0Sstevel@tonic-gate 	return (ipmp_querydone(statep, retval));
178*0Sstevel@tonic-gate }
179*0Sstevel@tonic-gate 
180*0Sstevel@tonic-gate /*
181*0Sstevel@tonic-gate  * Free the group list pointed to by `grlistp'.
182*0Sstevel@tonic-gate  */
183*0Sstevel@tonic-gate void
184*0Sstevel@tonic-gate ipmp_freegrouplist(ipmp_grouplist_t *grlistp)
185*0Sstevel@tonic-gate {
186*0Sstevel@tonic-gate 	free(grlistp);
187*0Sstevel@tonic-gate }
188*0Sstevel@tonic-gate 
189*0Sstevel@tonic-gate /*
190*0Sstevel@tonic-gate  * Using `handle', get the group information associated with group `name' and
191*0Sstevel@tonic-gate  * store the results in a dynamically allocated buffer pointed to by
192*0Sstevel@tonic-gate  * `*grinfopp'.  Returns an IPMP error code.
193*0Sstevel@tonic-gate  */
194*0Sstevel@tonic-gate int
195*0Sstevel@tonic-gate ipmp_getgroupinfo(ipmp_handle_t handle, const char *name,
196*0Sstevel@tonic-gate     ipmp_groupinfo_t **grinfopp)
197*0Sstevel@tonic-gate {
198*0Sstevel@tonic-gate 	ipmp_state_t	*statep = handle;
199*0Sstevel@tonic-gate 	ipmp_iflist_t	*iflistp;
200*0Sstevel@tonic-gate 	int		retval;
201*0Sstevel@tonic-gate 	struct timeval	end;
202*0Sstevel@tonic-gate 	ipmp_groupinfo_t *grinfop;
203*0Sstevel@tonic-gate 
204*0Sstevel@tonic-gate 	if (statep->st_snap != NULL) {
205*0Sstevel@tonic-gate 		grinfop = ipmp_snap_getgroupinfo(statep->st_snap, name);
206*0Sstevel@tonic-gate 		if (grinfop == NULL)
207*0Sstevel@tonic-gate 			return (IPMP_EUNKGROUP);
208*0Sstevel@tonic-gate 
209*0Sstevel@tonic-gate 		*grinfopp = ipmp_groupinfo_clone(grinfop);
210*0Sstevel@tonic-gate 		return (*grinfopp != NULL ? IPMP_SUCCESS : IPMP_ENOMEM);
211*0Sstevel@tonic-gate 	}
212*0Sstevel@tonic-gate 
213*0Sstevel@tonic-gate 	retval = ipmp_sendquery(statep, IPMP_GROUPINFO, name, &end);
214*0Sstevel@tonic-gate 	if (retval != IPMP_SUCCESS)
215*0Sstevel@tonic-gate 		return (retval);
216*0Sstevel@tonic-gate 
217*0Sstevel@tonic-gate 	retval = ipmp_readinfo(statep, IPMP_GROUPINFO, (void **)grinfopp, &end);
218*0Sstevel@tonic-gate 	if (retval != IPMP_SUCCESS)
219*0Sstevel@tonic-gate 		return (ipmp_querydone(statep, retval));
220*0Sstevel@tonic-gate 
221*0Sstevel@tonic-gate 	retval = ipmp_readinfo(statep, IPMP_IFLIST, (void **)&iflistp, &end);
222*0Sstevel@tonic-gate 	if (retval != IPMP_SUCCESS)
223*0Sstevel@tonic-gate 		free(*grinfopp);
224*0Sstevel@tonic-gate 	else
225*0Sstevel@tonic-gate 		(*grinfopp)->gr_iflistp = iflistp;
226*0Sstevel@tonic-gate 
227*0Sstevel@tonic-gate 	return (ipmp_querydone(statep, retval));
228*0Sstevel@tonic-gate }
229*0Sstevel@tonic-gate 
230*0Sstevel@tonic-gate /*
231*0Sstevel@tonic-gate  * Free the group information pointed to by `grinfop'.
232*0Sstevel@tonic-gate  */
233*0Sstevel@tonic-gate void
234*0Sstevel@tonic-gate ipmp_freegroupinfo(ipmp_groupinfo_t *grinfop)
235*0Sstevel@tonic-gate {
236*0Sstevel@tonic-gate 	free(grinfop->gr_iflistp);
237*0Sstevel@tonic-gate 	free(grinfop);
238*0Sstevel@tonic-gate }
239*0Sstevel@tonic-gate 
240*0Sstevel@tonic-gate /*
241*0Sstevel@tonic-gate  * Using `handle', get the interface information associated with interface
242*0Sstevel@tonic-gate  * `name' and store the results in a dynamically allocated buffer pointed to
243*0Sstevel@tonic-gate  * by `*ifinfopp'.  Returns an IPMP error code.
244*0Sstevel@tonic-gate  */
245*0Sstevel@tonic-gate int
246*0Sstevel@tonic-gate ipmp_getifinfo(ipmp_handle_t handle, const char *name, ipmp_ifinfo_t **ifinfopp)
247*0Sstevel@tonic-gate {
248*0Sstevel@tonic-gate 	ipmp_state_t	*statep = handle;
249*0Sstevel@tonic-gate 	ipmp_ifinfo_t	*ifinfop;
250*0Sstevel@tonic-gate 	int		retval;
251*0Sstevel@tonic-gate 	struct timeval	end;
252*0Sstevel@tonic-gate 
253*0Sstevel@tonic-gate 	if (statep->st_snap != NULL) {
254*0Sstevel@tonic-gate 		ifinfop = ipmp_snap_getifinfo(statep->st_snap, name);
255*0Sstevel@tonic-gate 		if (ifinfop == NULL)
256*0Sstevel@tonic-gate 			return (IPMP_EUNKIF);
257*0Sstevel@tonic-gate 
258*0Sstevel@tonic-gate 		*ifinfopp = ipmp_ifinfo_clone(ifinfop);
259*0Sstevel@tonic-gate 		return (*ifinfopp != NULL ? IPMP_SUCCESS : IPMP_ENOMEM);
260*0Sstevel@tonic-gate 	}
261*0Sstevel@tonic-gate 
262*0Sstevel@tonic-gate 	retval = ipmp_sendquery(statep, IPMP_IFINFO, name, &end);
263*0Sstevel@tonic-gate 	if (retval != IPMP_SUCCESS)
264*0Sstevel@tonic-gate 		return (retval);
265*0Sstevel@tonic-gate 
266*0Sstevel@tonic-gate 	retval = ipmp_readinfo(statep, IPMP_IFINFO, (void **)ifinfopp, &end);
267*0Sstevel@tonic-gate 	return (ipmp_querydone(statep, retval));
268*0Sstevel@tonic-gate }
269*0Sstevel@tonic-gate 
270*0Sstevel@tonic-gate /*
271*0Sstevel@tonic-gate  * Free the interface information pointed to by `ifinfop'.
272*0Sstevel@tonic-gate  */
273*0Sstevel@tonic-gate void
274*0Sstevel@tonic-gate ipmp_freeifinfo(ipmp_ifinfo_t *ifinfop)
275*0Sstevel@tonic-gate {
276*0Sstevel@tonic-gate 	free(ifinfop);
277*0Sstevel@tonic-gate }
278*0Sstevel@tonic-gate 
279*0Sstevel@tonic-gate /*
280*0Sstevel@tonic-gate  * Check if `buf' has a NUL byte in its first `bufsize' bytes.
281*0Sstevel@tonic-gate  */
282*0Sstevel@tonic-gate static boolean_t
283*0Sstevel@tonic-gate hasnulbyte(const char *buf, size_t bufsize)
284*0Sstevel@tonic-gate {
285*0Sstevel@tonic-gate 	while (bufsize-- > 0) {
286*0Sstevel@tonic-gate 		if (buf[bufsize] == '\0')
287*0Sstevel@tonic-gate 			return (B_TRUE);
288*0Sstevel@tonic-gate 	}
289*0Sstevel@tonic-gate 	return (B_FALSE);
290*0Sstevel@tonic-gate }
291*0Sstevel@tonic-gate 
292*0Sstevel@tonic-gate /*
293*0Sstevel@tonic-gate  * Check that the TLV triplet named by `type', `len' and `value' is correctly
294*0Sstevel@tonic-gate  * formed.
295*0Sstevel@tonic-gate  */
296*0Sstevel@tonic-gate static boolean_t
297*0Sstevel@tonic-gate ipmp_checktlv(ipmp_infotype_t type, size_t len, void *value)
298*0Sstevel@tonic-gate {
299*0Sstevel@tonic-gate 	ipmp_iflist_t		*iflistp;
300*0Sstevel@tonic-gate 	ipmp_ifinfo_t		*ifinfop;
301*0Sstevel@tonic-gate 	ipmp_grouplist_t	*grlistp;
302*0Sstevel@tonic-gate 	ipmp_groupinfo_t	*grinfop;
303*0Sstevel@tonic-gate 	unsigned int		i;
304*0Sstevel@tonic-gate 
305*0Sstevel@tonic-gate 	switch (type) {
306*0Sstevel@tonic-gate 	case IPMP_IFLIST:
307*0Sstevel@tonic-gate 		iflistp = (ipmp_iflist_t *)value;
308*0Sstevel@tonic-gate 		if (len < IPMP_IFLIST_MINSIZE ||
309*0Sstevel@tonic-gate 		    len < IPMP_IFLIST_SIZE(iflistp->il_nif))
310*0Sstevel@tonic-gate 			return (B_FALSE);
311*0Sstevel@tonic-gate 
312*0Sstevel@tonic-gate 		for (i = 0; i < iflistp->il_nif; i++)
313*0Sstevel@tonic-gate 			if (!hasnulbyte(iflistp->il_ifs[i], LIFNAMSIZ))
314*0Sstevel@tonic-gate 				return (B_FALSE);
315*0Sstevel@tonic-gate 		break;
316*0Sstevel@tonic-gate 
317*0Sstevel@tonic-gate 	case IPMP_IFINFO:
318*0Sstevel@tonic-gate 		ifinfop = (ipmp_ifinfo_t *)value;
319*0Sstevel@tonic-gate 		if (len != sizeof (ipmp_ifinfo_t))
320*0Sstevel@tonic-gate 			return (B_FALSE);
321*0Sstevel@tonic-gate 
322*0Sstevel@tonic-gate 		if (!hasnulbyte(ifinfop->if_name, LIFNAMSIZ) ||
323*0Sstevel@tonic-gate 		    !hasnulbyte(ifinfop->if_group, LIFGRNAMSIZ))
324*0Sstevel@tonic-gate 			return (B_FALSE);
325*0Sstevel@tonic-gate 		break;
326*0Sstevel@tonic-gate 
327*0Sstevel@tonic-gate 	case IPMP_GROUPLIST:
328*0Sstevel@tonic-gate 		grlistp = (ipmp_grouplist_t *)value;
329*0Sstevel@tonic-gate 		if (len < IPMP_GROUPLIST_MINSIZE ||
330*0Sstevel@tonic-gate 		    len < IPMP_GROUPLIST_SIZE(grlistp->gl_ngroup))
331*0Sstevel@tonic-gate 			return (B_FALSE);
332*0Sstevel@tonic-gate 
333*0Sstevel@tonic-gate 		for (i = 0; i < grlistp->gl_ngroup; i++)
334*0Sstevel@tonic-gate 			if (!hasnulbyte(grlistp->gl_groups[i], LIFGRNAMSIZ))
335*0Sstevel@tonic-gate 				return (B_FALSE);
336*0Sstevel@tonic-gate 		break;
337*0Sstevel@tonic-gate 
338*0Sstevel@tonic-gate 	case IPMP_GROUPINFO:
339*0Sstevel@tonic-gate 		grinfop = (ipmp_groupinfo_t *)value;
340*0Sstevel@tonic-gate 		if (len != sizeof (ipmp_groupinfo_t))
341*0Sstevel@tonic-gate 			return (B_FALSE);
342*0Sstevel@tonic-gate 
343*0Sstevel@tonic-gate 		if (!hasnulbyte(grinfop->gr_name, LIFGRNAMSIZ))
344*0Sstevel@tonic-gate 			return (B_FALSE);
345*0Sstevel@tonic-gate 		break;
346*0Sstevel@tonic-gate 
347*0Sstevel@tonic-gate 	case IPMP_SNAP:
348*0Sstevel@tonic-gate 		if (len != sizeof (ipmp_snap_t))
349*0Sstevel@tonic-gate 			return (B_FALSE);
350*0Sstevel@tonic-gate 		break;
351*0Sstevel@tonic-gate 
352*0Sstevel@tonic-gate 	default:
353*0Sstevel@tonic-gate 		return (B_FALSE);
354*0Sstevel@tonic-gate 	}
355*0Sstevel@tonic-gate 
356*0Sstevel@tonic-gate 	return (B_TRUE);
357*0Sstevel@tonic-gate }
358*0Sstevel@tonic-gate 
359*0Sstevel@tonic-gate /*
360*0Sstevel@tonic-gate  * Create a group list with signature `sig' containing `ngroup' groups named
361*0Sstevel@tonic-gate  * by `groups'.  Returns a pointer to the new group list on success, or NULL
362*0Sstevel@tonic-gate  * on failure.
363*0Sstevel@tonic-gate  */
364*0Sstevel@tonic-gate ipmp_grouplist_t *
365*0Sstevel@tonic-gate ipmp_grouplist_create(uint64_t sig, unsigned int ngroup,
366*0Sstevel@tonic-gate     char (*groups)[LIFGRNAMSIZ])
367*0Sstevel@tonic-gate {
368*0Sstevel@tonic-gate 	unsigned int i;
369*0Sstevel@tonic-gate 	ipmp_grouplist_t *grlistp;
370*0Sstevel@tonic-gate 
371*0Sstevel@tonic-gate 	grlistp = malloc(IPMP_GROUPLIST_SIZE(ngroup));
372*0Sstevel@tonic-gate 	if (grlistp == NULL)
373*0Sstevel@tonic-gate 		return (NULL);
374*0Sstevel@tonic-gate 
375*0Sstevel@tonic-gate 	grlistp->gl_sig = sig;
376*0Sstevel@tonic-gate 	grlistp->gl_ngroup = ngroup;
377*0Sstevel@tonic-gate 	for (i = 0; i < ngroup; i++)
378*0Sstevel@tonic-gate 		(void) strlcpy(grlistp->gl_groups[i], groups[i], LIFGRNAMSIZ);
379*0Sstevel@tonic-gate 
380*0Sstevel@tonic-gate 	return (grlistp);
381*0Sstevel@tonic-gate }
382*0Sstevel@tonic-gate 
383*0Sstevel@tonic-gate /*
384*0Sstevel@tonic-gate  * Clone the group list named by `grlistp'.  Returns a pointer to the clone on
385*0Sstevel@tonic-gate  * success, or NULL on failure.
386*0Sstevel@tonic-gate  */
387*0Sstevel@tonic-gate ipmp_grouplist_t *
388*0Sstevel@tonic-gate ipmp_grouplist_clone(ipmp_grouplist_t *grlistp)
389*0Sstevel@tonic-gate {
390*0Sstevel@tonic-gate 	return (ipmp_grouplist_create(grlistp->gl_sig, grlistp->gl_ngroup,
391*0Sstevel@tonic-gate 	    grlistp->gl_groups));
392*0Sstevel@tonic-gate }
393*0Sstevel@tonic-gate 
394*0Sstevel@tonic-gate /*
395*0Sstevel@tonic-gate  * Create an interface information structure for interface `name' and
396*0Sstevel@tonic-gate  * associate `group', `state' and `type' with it.  Returns a pointer to the
397*0Sstevel@tonic-gate  * interface information on success, or NULL on failure.
398*0Sstevel@tonic-gate  */
399*0Sstevel@tonic-gate ipmp_ifinfo_t *
400*0Sstevel@tonic-gate ipmp_ifinfo_create(const char *name, const char *group, ipmp_if_state_t state,
401*0Sstevel@tonic-gate     ipmp_if_type_t type)
402*0Sstevel@tonic-gate {
403*0Sstevel@tonic-gate 	ipmp_ifinfo_t *ifinfop;
404*0Sstevel@tonic-gate 
405*0Sstevel@tonic-gate 	ifinfop = malloc(sizeof (ipmp_ifinfo_t));
406*0Sstevel@tonic-gate 	if (ifinfop == NULL)
407*0Sstevel@tonic-gate 		return (NULL);
408*0Sstevel@tonic-gate 
409*0Sstevel@tonic-gate 	(void) strlcpy(ifinfop->if_name, name, LIFNAMSIZ);
410*0Sstevel@tonic-gate 	(void) strlcpy(ifinfop->if_group, group, LIFGRNAMSIZ);
411*0Sstevel@tonic-gate 	ifinfop->if_state = state;
412*0Sstevel@tonic-gate 	ifinfop->if_type = type;
413*0Sstevel@tonic-gate 
414*0Sstevel@tonic-gate 	return (ifinfop);
415*0Sstevel@tonic-gate }
416*0Sstevel@tonic-gate 
417*0Sstevel@tonic-gate /*
418*0Sstevel@tonic-gate  * Clone the interface information named by `ifinfop'.  Returns a pointer to
419*0Sstevel@tonic-gate  * the clone on success, or NULL on failure.
420*0Sstevel@tonic-gate  */
421*0Sstevel@tonic-gate ipmp_ifinfo_t *
422*0Sstevel@tonic-gate ipmp_ifinfo_clone(ipmp_ifinfo_t *ifinfop)
423*0Sstevel@tonic-gate {
424*0Sstevel@tonic-gate 	return (ipmp_ifinfo_create(ifinfop->if_name, ifinfop->if_group,
425*0Sstevel@tonic-gate 	    ifinfop->if_state, ifinfop->if_type));
426*0Sstevel@tonic-gate }
427*0Sstevel@tonic-gate 
428*0Sstevel@tonic-gate /*
429*0Sstevel@tonic-gate  * Create a group named `name' with signature `sig', in state `state', and
430*0Sstevel@tonic-gate  * with the `nif' interfaces named by `ifs' as members.  Returns a pointer
431*0Sstevel@tonic-gate  * to the new group on success, or NULL on failure.
432*0Sstevel@tonic-gate  */
433*0Sstevel@tonic-gate ipmp_groupinfo_t *
434*0Sstevel@tonic-gate ipmp_groupinfo_create(const char *name, uint64_t sig, ipmp_group_state_t state,
435*0Sstevel@tonic-gate     unsigned int nif, char (*ifs)[LIFNAMSIZ])
436*0Sstevel@tonic-gate {
437*0Sstevel@tonic-gate 	ipmp_groupinfo_t *grinfop;
438*0Sstevel@tonic-gate 	ipmp_iflist_t	*iflistp;
439*0Sstevel@tonic-gate 	unsigned int	i;
440*0Sstevel@tonic-gate 
441*0Sstevel@tonic-gate 	grinfop = malloc(sizeof (ipmp_groupinfo_t));
442*0Sstevel@tonic-gate 	if (grinfop == NULL)
443*0Sstevel@tonic-gate 		return (NULL);
444*0Sstevel@tonic-gate 
445*0Sstevel@tonic-gate 	iflistp = malloc(IPMP_IFLIST_SIZE(nif));
446*0Sstevel@tonic-gate 	if (iflistp == NULL) {
447*0Sstevel@tonic-gate 		free(grinfop);
448*0Sstevel@tonic-gate 		return (NULL);
449*0Sstevel@tonic-gate 	}
450*0Sstevel@tonic-gate 
451*0Sstevel@tonic-gate 	grinfop->gr_sig = sig;
452*0Sstevel@tonic-gate 	grinfop->gr_state = state;
453*0Sstevel@tonic-gate 	grinfop->gr_iflistp = iflistp;
454*0Sstevel@tonic-gate 	(void) strlcpy(grinfop->gr_name, name, LIFGRNAMSIZ);
455*0Sstevel@tonic-gate 
456*0Sstevel@tonic-gate 	iflistp->il_nif = nif;
457*0Sstevel@tonic-gate 	for (i = 0; i < nif; i++)
458*0Sstevel@tonic-gate 		(void) strlcpy(iflistp->il_ifs[i], ifs[i], LIFNAMSIZ);
459*0Sstevel@tonic-gate 
460*0Sstevel@tonic-gate 	return (grinfop);
461*0Sstevel@tonic-gate }
462*0Sstevel@tonic-gate 
463*0Sstevel@tonic-gate /*
464*0Sstevel@tonic-gate  * Clone the group information named by `grinfop'.  Returns a pointer to
465*0Sstevel@tonic-gate  * the clone on success, or NULL on failure.
466*0Sstevel@tonic-gate  */
467*0Sstevel@tonic-gate ipmp_groupinfo_t *
468*0Sstevel@tonic-gate ipmp_groupinfo_clone(ipmp_groupinfo_t *grinfop)
469*0Sstevel@tonic-gate {
470*0Sstevel@tonic-gate 	return (ipmp_groupinfo_create(grinfop->gr_name, grinfop->gr_sig,
471*0Sstevel@tonic-gate 	    grinfop->gr_state, grinfop->gr_iflistp->il_nif,
472*0Sstevel@tonic-gate 	    grinfop->gr_iflistp->il_ifs));
473*0Sstevel@tonic-gate }
474*0Sstevel@tonic-gate 
475*0Sstevel@tonic-gate /*
476*0Sstevel@tonic-gate  * Set the query context associated with `handle' to `qcontext', which must be
477*0Sstevel@tonic-gate  * either IPMP_QCONTEXT_LIVE or IPMP_QCONTEXT_SNAP.  Upon success, any
478*0Sstevel@tonic-gate  * previous snapshot associated with `handle' is discarded.  Returns an IPMP
479*0Sstevel@tonic-gate  * error code.
480*0Sstevel@tonic-gate  */
481*0Sstevel@tonic-gate int
482*0Sstevel@tonic-gate ipmp_setqcontext(ipmp_handle_t handle, ipmp_qcontext_t qcontext)
483*0Sstevel@tonic-gate {
484*0Sstevel@tonic-gate 	ipmp_state_t	*statep = handle;
485*0Sstevel@tonic-gate 	ipmp_snap_t	*snap;
486*0Sstevel@tonic-gate 	int		retval;
487*0Sstevel@tonic-gate 
488*0Sstevel@tonic-gate 	switch (qcontext) {
489*0Sstevel@tonic-gate 	case IPMP_QCONTEXT_LIVE:
490*0Sstevel@tonic-gate 		snap = NULL;
491*0Sstevel@tonic-gate 		break;
492*0Sstevel@tonic-gate 
493*0Sstevel@tonic-gate 	case IPMP_QCONTEXT_SNAP:
494*0Sstevel@tonic-gate 		retval = ipmp_snap_take(statep, &snap);
495*0Sstevel@tonic-gate 		if (retval != IPMP_SUCCESS)
496*0Sstevel@tonic-gate 			return (retval);
497*0Sstevel@tonic-gate 		break;
498*0Sstevel@tonic-gate 
499*0Sstevel@tonic-gate 	default:
500*0Sstevel@tonic-gate 		return (IPMP_EINVAL);
501*0Sstevel@tonic-gate 	}
502*0Sstevel@tonic-gate 
503*0Sstevel@tonic-gate 	if (statep->st_snap != NULL)
504*0Sstevel@tonic-gate 		ipmp_snap_free(statep->st_snap);
505*0Sstevel@tonic-gate 	statep->st_snap = snap;
506*0Sstevel@tonic-gate 
507*0Sstevel@tonic-gate 	return (IPMP_SUCCESS);
508*0Sstevel@tonic-gate }
509*0Sstevel@tonic-gate 
510*0Sstevel@tonic-gate /*
511*0Sstevel@tonic-gate  * Create an empty snapshot.  Returns a pointer to the snapshot on success,
512*0Sstevel@tonic-gate  * or NULL on failure.
513*0Sstevel@tonic-gate  */
514*0Sstevel@tonic-gate ipmp_snap_t *
515*0Sstevel@tonic-gate ipmp_snap_create(void)
516*0Sstevel@tonic-gate {
517*0Sstevel@tonic-gate 	ipmp_snap_t *snap;
518*0Sstevel@tonic-gate 
519*0Sstevel@tonic-gate 	snap = malloc(sizeof (ipmp_snap_t));
520*0Sstevel@tonic-gate 	if (snap == NULL)
521*0Sstevel@tonic-gate 		return (NULL);
522*0Sstevel@tonic-gate 
523*0Sstevel@tonic-gate 	snap->sn_grlistp = NULL;
524*0Sstevel@tonic-gate 	snap->sn_grinfolistp = NULL;
525*0Sstevel@tonic-gate 	snap->sn_ifinfolistp = NULL;
526*0Sstevel@tonic-gate 	snap->sn_ngroup = 0;
527*0Sstevel@tonic-gate 	snap->sn_nif = 0;
528*0Sstevel@tonic-gate 
529*0Sstevel@tonic-gate 	return (snap);
530*0Sstevel@tonic-gate }
531*0Sstevel@tonic-gate 
532*0Sstevel@tonic-gate /*
533*0Sstevel@tonic-gate  * Free all of the resources associated with snapshot `snap'.
534*0Sstevel@tonic-gate  */
535*0Sstevel@tonic-gate void
536*0Sstevel@tonic-gate ipmp_snap_free(ipmp_snap_t *snap)
537*0Sstevel@tonic-gate {
538*0Sstevel@tonic-gate 	ipmp_ifinfolist_t	*iflp, *ifnext;
539*0Sstevel@tonic-gate 	ipmp_groupinfolist_t	*grlp, *grnext;
540*0Sstevel@tonic-gate 
541*0Sstevel@tonic-gate 	ipmp_freegrouplist(snap->sn_grlistp);
542*0Sstevel@tonic-gate 
543*0Sstevel@tonic-gate 	for (grlp = snap->sn_grinfolistp; grlp != NULL; grlp = grnext) {
544*0Sstevel@tonic-gate 		grnext = grlp->grl_next;
545*0Sstevel@tonic-gate 		ipmp_freegroupinfo(grlp->grl_grinfop);
546*0Sstevel@tonic-gate 		free(grlp);
547*0Sstevel@tonic-gate 	}
548*0Sstevel@tonic-gate 
549*0Sstevel@tonic-gate 	for (iflp = snap->sn_ifinfolistp; iflp != NULL; iflp = ifnext) {
550*0Sstevel@tonic-gate 		ifnext = iflp->ifl_next;
551*0Sstevel@tonic-gate 		ipmp_freeifinfo(iflp->ifl_ifinfop);
552*0Sstevel@tonic-gate 		free(iflp);
553*0Sstevel@tonic-gate 	}
554*0Sstevel@tonic-gate 
555*0Sstevel@tonic-gate 	free(snap);
556*0Sstevel@tonic-gate }
557*0Sstevel@tonic-gate 
558*0Sstevel@tonic-gate /*
559*0Sstevel@tonic-gate  * Add the group information in `grinfop' to the snapshot named by `snap'.
560*0Sstevel@tonic-gate  * Returns an IPMP error code.
561*0Sstevel@tonic-gate  */
562*0Sstevel@tonic-gate int
563*0Sstevel@tonic-gate ipmp_snap_addgroupinfo(ipmp_snap_t *snap, ipmp_groupinfo_t *grinfop)
564*0Sstevel@tonic-gate {
565*0Sstevel@tonic-gate 	ipmp_groupinfolist_t *grlp;
566*0Sstevel@tonic-gate 
567*0Sstevel@tonic-gate 	/*
568*0Sstevel@tonic-gate 	 * If the information for this group is already in the snapshot,
569*0Sstevel@tonic-gate 	 * in.mpathd is broken.
570*0Sstevel@tonic-gate 	 */
571*0Sstevel@tonic-gate 	if (ipmp_snap_getgroupinfo(snap, grinfop->gr_name) != NULL)
572*0Sstevel@tonic-gate 		return (IPMP_EPROTO);
573*0Sstevel@tonic-gate 
574*0Sstevel@tonic-gate 	grlp = malloc(sizeof (ipmp_groupinfolist_t));
575*0Sstevel@tonic-gate 	if (grlp == NULL)
576*0Sstevel@tonic-gate 		return (IPMP_ENOMEM);
577*0Sstevel@tonic-gate 
578*0Sstevel@tonic-gate 	grlp->grl_grinfop = grinfop;
579*0Sstevel@tonic-gate 	grlp->grl_next = snap->sn_grinfolistp;
580*0Sstevel@tonic-gate 	snap->sn_grinfolistp = grlp;
581*0Sstevel@tonic-gate 	snap->sn_ngroup++;
582*0Sstevel@tonic-gate 
583*0Sstevel@tonic-gate 	return (IPMP_SUCCESS);
584*0Sstevel@tonic-gate }
585*0Sstevel@tonic-gate 
586*0Sstevel@tonic-gate /*
587*0Sstevel@tonic-gate  * Add the interface information in `ifinfop' to the snapshot named by `snap'.
588*0Sstevel@tonic-gate  * Returns an IPMP error code.
589*0Sstevel@tonic-gate  */
590*0Sstevel@tonic-gate int
591*0Sstevel@tonic-gate ipmp_snap_addifinfo(ipmp_snap_t *snap, ipmp_ifinfo_t *ifinfop)
592*0Sstevel@tonic-gate {
593*0Sstevel@tonic-gate 	ipmp_ifinfolist_t *iflp;
594*0Sstevel@tonic-gate 
595*0Sstevel@tonic-gate 	/*
596*0Sstevel@tonic-gate 	 * If the information for this interface is already in the snapshot,
597*0Sstevel@tonic-gate 	 * in.mpathd is broken.
598*0Sstevel@tonic-gate 	 */
599*0Sstevel@tonic-gate 	if (ipmp_snap_getifinfo(snap, ifinfop->if_name) != NULL)
600*0Sstevel@tonic-gate 		return (IPMP_EPROTO);
601*0Sstevel@tonic-gate 
602*0Sstevel@tonic-gate 	iflp = malloc(sizeof (ipmp_ifinfolist_t));
603*0Sstevel@tonic-gate 	if (iflp == NULL)
604*0Sstevel@tonic-gate 		return (IPMP_ENOMEM);
605*0Sstevel@tonic-gate 
606*0Sstevel@tonic-gate 	iflp->ifl_ifinfop = ifinfop;
607*0Sstevel@tonic-gate 	iflp->ifl_next = snap->sn_ifinfolistp;
608*0Sstevel@tonic-gate 	snap->sn_ifinfolistp = iflp;
609*0Sstevel@tonic-gate 	snap->sn_nif++;
610*0Sstevel@tonic-gate 
611*0Sstevel@tonic-gate 	return (IPMP_SUCCESS);
612*0Sstevel@tonic-gate }
613*0Sstevel@tonic-gate 
614*0Sstevel@tonic-gate /*
615*0Sstevel@tonic-gate  * Retrieve the information for the group `name' in snapshot `snap'.
616*0Sstevel@tonic-gate  * Returns a pointer to the group information on success, or NULL on failure.
617*0Sstevel@tonic-gate  */
618*0Sstevel@tonic-gate static ipmp_groupinfo_t *
619*0Sstevel@tonic-gate ipmp_snap_getgroupinfo(ipmp_snap_t *snap, const char *name)
620*0Sstevel@tonic-gate {
621*0Sstevel@tonic-gate 	ipmp_groupinfolist_t *grlp;
622*0Sstevel@tonic-gate 
623*0Sstevel@tonic-gate 	for (grlp = snap->sn_grinfolistp; grlp != NULL; grlp = grlp->grl_next) {
624*0Sstevel@tonic-gate 		if (strcmp(grlp->grl_grinfop->gr_name, name) == 0)
625*0Sstevel@tonic-gate 			break;
626*0Sstevel@tonic-gate 	}
627*0Sstevel@tonic-gate 
628*0Sstevel@tonic-gate 	return (grlp != NULL ? grlp->grl_grinfop : NULL);
629*0Sstevel@tonic-gate }
630*0Sstevel@tonic-gate 
631*0Sstevel@tonic-gate /*
632*0Sstevel@tonic-gate  * Retrieve the information for the interface `name' in snapshot `snap'.
633*0Sstevel@tonic-gate  * Returns a pointer to the interface information on success, or NULL on
634*0Sstevel@tonic-gate  * failure.
635*0Sstevel@tonic-gate  */
636*0Sstevel@tonic-gate static ipmp_ifinfo_t *
637*0Sstevel@tonic-gate ipmp_snap_getifinfo(ipmp_snap_t *snap, const char *name)
638*0Sstevel@tonic-gate {
639*0Sstevel@tonic-gate 	ipmp_ifinfolist_t *iflp;
640*0Sstevel@tonic-gate 
641*0Sstevel@tonic-gate 	for (iflp = snap->sn_ifinfolistp; iflp != NULL; iflp = iflp->ifl_next) {
642*0Sstevel@tonic-gate 		if (strcmp(iflp->ifl_ifinfop->if_name, name) == 0)
643*0Sstevel@tonic-gate 			break;
644*0Sstevel@tonic-gate 	}
645*0Sstevel@tonic-gate 
646*0Sstevel@tonic-gate 	return (iflp != NULL ? iflp->ifl_ifinfop : NULL);
647*0Sstevel@tonic-gate }
648*0Sstevel@tonic-gate 
649*0Sstevel@tonic-gate /*
650*0Sstevel@tonic-gate  * Using `statep', take a snapshot of the IPMP subsystem and if successful
651*0Sstevel@tonic-gate  * return it in a dynamically allocated snapshot pointed to by `*snapp'.
652*0Sstevel@tonic-gate  * Returns an IPMP error code.
653*0Sstevel@tonic-gate  */
654*0Sstevel@tonic-gate static int
655*0Sstevel@tonic-gate ipmp_snap_take(ipmp_state_t *statep, ipmp_snap_t **snapp)
656*0Sstevel@tonic-gate {
657*0Sstevel@tonic-gate 	ipmp_snap_t	*snap, *osnap;
658*0Sstevel@tonic-gate 	ipmp_infotype_t	type;
659*0Sstevel@tonic-gate 	ipmp_iflist_t	*iflistp;
660*0Sstevel@tonic-gate 	int		retval;
661*0Sstevel@tonic-gate 	size_t		len;
662*0Sstevel@tonic-gate 	void		*infop;
663*0Sstevel@tonic-gate 	struct timeval	end;
664*0Sstevel@tonic-gate 
665*0Sstevel@tonic-gate 	snap = ipmp_snap_create();
666*0Sstevel@tonic-gate 	if (snap == NULL)
667*0Sstevel@tonic-gate 		return (IPMP_ENOMEM);
668*0Sstevel@tonic-gate 
669*0Sstevel@tonic-gate 	retval = ipmp_sendquery(statep, IPMP_SNAP, NULL, &end);
670*0Sstevel@tonic-gate 	if (retval != IPMP_SUCCESS) {
671*0Sstevel@tonic-gate 		ipmp_snap_free(snap);
672*0Sstevel@tonic-gate 		return (retval);
673*0Sstevel@tonic-gate 	}
674*0Sstevel@tonic-gate 
675*0Sstevel@tonic-gate 	retval = ipmp_readinfo(statep, IPMP_SNAP, (void **)&osnap, &end);
676*0Sstevel@tonic-gate 	if (retval != IPMP_SUCCESS) {
677*0Sstevel@tonic-gate 		ipmp_snap_free(snap);
678*0Sstevel@tonic-gate 		return (ipmp_querydone(statep, retval));
679*0Sstevel@tonic-gate 	}
680*0Sstevel@tonic-gate 
681*0Sstevel@tonic-gate 	/*
682*0Sstevel@tonic-gate 	 * Using the information in the passed `osnap' snapshot, build up our
683*0Sstevel@tonic-gate 	 * own snapshot.  If we receive more than one grouplist, or more than
684*0Sstevel@tonic-gate 	 * the expected number of interfaces or groups, then bail out.  Note
685*0Sstevel@tonic-gate 	 * that there's only so much we can do to check that the information
686*0Sstevel@tonic-gate 	 * sent by in.mpathd makes sense.  We know there will always be at
687*0Sstevel@tonic-gate 	 * least one TLV (IPMP_GROUPLIST).
688*0Sstevel@tonic-gate 	 */
689*0Sstevel@tonic-gate 	do {
690*0Sstevel@tonic-gate 		infop = NULL;
691*0Sstevel@tonic-gate 		retval = ipmp_readtlv(statep->st_fd, &type, &len, &infop, &end);
692*0Sstevel@tonic-gate 		if (retval != IPMP_SUCCESS)
693*0Sstevel@tonic-gate 			goto fail;
694*0Sstevel@tonic-gate 
695*0Sstevel@tonic-gate 		if (!ipmp_checktlv(type, len, infop)) {
696*0Sstevel@tonic-gate 			retval = IPMP_EPROTO;
697*0Sstevel@tonic-gate 			goto fail;
698*0Sstevel@tonic-gate 		}
699*0Sstevel@tonic-gate 
700*0Sstevel@tonic-gate 		switch (type) {
701*0Sstevel@tonic-gate 		case IPMP_GROUPLIST:
702*0Sstevel@tonic-gate 			if (snap->sn_grlistp != NULL) {
703*0Sstevel@tonic-gate 				retval = IPMP_EPROTO;
704*0Sstevel@tonic-gate 				break;
705*0Sstevel@tonic-gate 			}
706*0Sstevel@tonic-gate 			snap->sn_grlistp = infop;
707*0Sstevel@tonic-gate 			break;
708*0Sstevel@tonic-gate 
709*0Sstevel@tonic-gate 		case IPMP_IFINFO:
710*0Sstevel@tonic-gate 			if (snap->sn_nif == osnap->sn_nif) {
711*0Sstevel@tonic-gate 				retval = IPMP_EPROTO;
712*0Sstevel@tonic-gate 				break;
713*0Sstevel@tonic-gate 			}
714*0Sstevel@tonic-gate 			retval = ipmp_snap_addifinfo(snap, infop);
715*0Sstevel@tonic-gate 			break;
716*0Sstevel@tonic-gate 
717*0Sstevel@tonic-gate 		case IPMP_GROUPINFO:
718*0Sstevel@tonic-gate 			if (snap->sn_ngroup == osnap->sn_ngroup) {
719*0Sstevel@tonic-gate 				retval = IPMP_EPROTO;
720*0Sstevel@tonic-gate 				break;
721*0Sstevel@tonic-gate 			}
722*0Sstevel@tonic-gate 
723*0Sstevel@tonic-gate 			/*
724*0Sstevel@tonic-gate 			 * An IPMP_IFLIST TLV always follows the
725*0Sstevel@tonic-gate 			 * IPMP_GROUPINFO TLV; read it in.
726*0Sstevel@tonic-gate 			 */
727*0Sstevel@tonic-gate 			retval = ipmp_readinfo(statep, IPMP_IFLIST,
728*0Sstevel@tonic-gate 			    (void **)&iflistp, &end);
729*0Sstevel@tonic-gate 			if (retval != IPMP_SUCCESS)
730*0Sstevel@tonic-gate 				break;
731*0Sstevel@tonic-gate 
732*0Sstevel@tonic-gate 			((ipmp_groupinfo_t *)infop)->gr_iflistp = iflistp;
733*0Sstevel@tonic-gate 			retval = ipmp_snap_addgroupinfo(snap, infop);
734*0Sstevel@tonic-gate 			if (retval != IPMP_SUCCESS)
735*0Sstevel@tonic-gate 				free(iflistp);
736*0Sstevel@tonic-gate 			break;
737*0Sstevel@tonic-gate 
738*0Sstevel@tonic-gate 		default:
739*0Sstevel@tonic-gate 			retval = IPMP_EPROTO;
740*0Sstevel@tonic-gate 			break;
741*0Sstevel@tonic-gate 		}
742*0Sstevel@tonic-gate fail:
743*0Sstevel@tonic-gate 		if (retval != IPMP_SUCCESS) {
744*0Sstevel@tonic-gate 			free(infop);
745*0Sstevel@tonic-gate 			free(osnap);
746*0Sstevel@tonic-gate 			ipmp_snap_free(snap);
747*0Sstevel@tonic-gate 			return (ipmp_querydone(statep, retval));
748*0Sstevel@tonic-gate 		}
749*0Sstevel@tonic-gate 	} while (snap->sn_grlistp == NULL || snap->sn_nif < osnap->sn_nif ||
750*0Sstevel@tonic-gate 	    snap->sn_ngroup < osnap->sn_ngroup);
751*0Sstevel@tonic-gate 
752*0Sstevel@tonic-gate 	free(osnap);
753*0Sstevel@tonic-gate 	*snapp = snap;
754*0Sstevel@tonic-gate 	return (ipmp_querydone(statep, IPMP_SUCCESS));
755*0Sstevel@tonic-gate }
756