1d62bc4baSyz /*
2d62bc4baSyz  * CDDL HEADER START
3d62bc4baSyz  *
4d62bc4baSyz  * The contents of this file are subject to the terms of the
5d62bc4baSyz  * Common Development and Distribution License (the "License").
6d62bc4baSyz  * You may not use this file except in compliance with the License.
7d62bc4baSyz  *
8d62bc4baSyz  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9d62bc4baSyz  * or http://www.opensolaris.org/os/licensing.
10d62bc4baSyz  * See the License for the specific language governing permissions
11d62bc4baSyz  * and limitations under the License.
12d62bc4baSyz  *
13d62bc4baSyz  * When distributing Covered Code, include this CDDL HEADER in each
14d62bc4baSyz  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15d62bc4baSyz  * If applicable, add the following below this CDDL HEADER, with the
16d62bc4baSyz  * fields enclosed by brackets "[]" replaced with your own identifying
17d62bc4baSyz  * information: Portions Copyright [yyyy] [name of copyright owner]
18d62bc4baSyz  *
19d62bc4baSyz  * CDDL HEADER END
20d62bc4baSyz  */
21d62bc4baSyz /*
2232715170SCathy Zhou  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23d62bc4baSyz  */
24d62bc4baSyz 
25d62bc4baSyz #include <door.h>
26d62bc4baSyz #include <errno.h>
27d62bc4baSyz #include <assert.h>
28d62bc4baSyz #include <stdio.h>
29d62bc4baSyz #include <stdlib.h>
30d62bc4baSyz #include <unistd.h>
31d62bc4baSyz #include <string.h>
32d62bc4baSyz #include <strings.h>
332b24ab6bSSebastien Roy #include <zone.h>
34d62bc4baSyz #include <sys/types.h>
35d62bc4baSyz #include <sys/stat.h>
36d62bc4baSyz #include <sys/aggr.h>
3782a2fc47SJames Carlson #include <sys/mman.h>
38d62bc4baSyz #include <fcntl.h>
39d62bc4baSyz #include <libdladm.h>
40d62bc4baSyz #include <libdladm_impl.h>
41d62bc4baSyz #include <libdllink.h>
42d62bc4baSyz #include <libdlmgmt.h>
43d62bc4baSyz 
44d62bc4baSyz /*
45d62bc4baSyz  * Table of data type sizes indexed by dladm_datatype_t.
46d62bc4baSyz  */
47d62bc4baSyz static size_t dladm_datatype_size[] = {
48d62bc4baSyz 	0,				/* DLADM_TYPE_STR, use strnlen() */
49d62bc4baSyz 	sizeof (boolean_t),		/* DLADM_TYPE_BOOLEAN */
50d62bc4baSyz 	sizeof (uint64_t)		/* DLADM_TYPE_UINT64 */
51d62bc4baSyz };
52d62bc4baSyz 
53d62bc4baSyz static dladm_status_t
544ac67f02SAnurag S. Maskey dladm_door_call(dladm_handle_t handle, void *arg, size_t asize, void *rbuf,
5532715170SCathy Zhou     size_t *rsizep)
56d62bc4baSyz {
57d62bc4baSyz 	door_arg_t	darg;
584ac67f02SAnurag S. Maskey 	int		door_fd;
59f689bed1SRishi Srivatsavai 	dladm_status_t	status;
60f689bed1SRishi Srivatsavai 	boolean_t	reopen = B_FALSE;
61d62bc4baSyz 
62d62bc4baSyz 	darg.data_ptr	= arg;
63d62bc4baSyz 	darg.data_size	= asize;
64d62bc4baSyz 	darg.desc_ptr	= NULL;
65d62bc4baSyz 	darg.desc_num	= 0;
66d62bc4baSyz 	darg.rbuf	= rbuf;
6732715170SCathy Zhou 	darg.rsize	= *rsizep;
68d62bc4baSyz 
69f689bed1SRishi Srivatsavai reopen:
704ac67f02SAnurag S. Maskey 	/* The door descriptor is opened if it isn't already */
714ac67f02SAnurag S. Maskey 	if ((status = dladm_door_fd(handle, &door_fd)) != DLADM_STATUS_OK)
724ac67f02SAnurag S. Maskey 		return (status);
73f689bed1SRishi Srivatsavai 	if (door_call(door_fd, &darg) == -1) {
74f689bed1SRishi Srivatsavai 		/*
75f689bed1SRishi Srivatsavai 		 * Stale door descriptor is possible if dlmgmtd was re-started
76f689bed1SRishi Srivatsavai 		 * since last door_fd open so try re-opening door file.
77f689bed1SRishi Srivatsavai 		 */
78f689bed1SRishi Srivatsavai 		if (!reopen && errno == EBADF) {
79f689bed1SRishi Srivatsavai 			(void) close(handle->door_fd);
80f689bed1SRishi Srivatsavai 			handle->door_fd = -1;
81f689bed1SRishi Srivatsavai 			reopen = B_TRUE;
82f689bed1SRishi Srivatsavai 			goto reopen;
83f689bed1SRishi Srivatsavai 		}
84d62bc4baSyz 		status = dladm_errno2status(errno);
85f689bed1SRishi Srivatsavai 	}
86d62bc4baSyz 	if (status != DLADM_STATUS_OK)
87d62bc4baSyz 		return (status);
88d62bc4baSyz 
89d62bc4baSyz 	if (darg.rbuf != rbuf) {
90d62bc4baSyz 		/*
91d62bc4baSyz 		 * The size of the input rbuf is not big enough so that
9232715170SCathy Zhou 		 * the door allocate the rbuf itself. In this case, return
9332715170SCathy Zhou 		 * the required size to the caller.
94d62bc4baSyz 		 */
95d62bc4baSyz 		(void) munmap(darg.rbuf, darg.rsize);
9632715170SCathy Zhou 		*rsizep = darg.rsize;
97d62bc4baSyz 		return (DLADM_STATUS_TOOSMALL);
9832715170SCathy Zhou 	} else if (darg.rsize != *rsizep) {
99d62bc4baSyz 		return (DLADM_STATUS_FAILED);
10032715170SCathy Zhou 	}
101d62bc4baSyz 
102024b0a25Sseb 	return (dladm_errno2status(((dlmgmt_retval_t *)rbuf)->lr_err));
103d62bc4baSyz }
104d62bc4baSyz 
105d62bc4baSyz /*
106d62bc4baSyz  * Allocate a new linkid with the given name. Return the new linkid.
107d62bc4baSyz  */
108d62bc4baSyz dladm_status_t
1094ac67f02SAnurag S. Maskey dladm_create_datalink_id(dladm_handle_t handle, const char *link,
1104ac67f02SAnurag S. Maskey     datalink_class_t class, uint32_t media, uint32_t flags,
1114ac67f02SAnurag S. Maskey     datalink_id_t *linkidp)
112d62bc4baSyz {
113024b0a25Sseb 	dlmgmt_door_createid_t	createid;
114d62bc4baSyz 	dlmgmt_createid_retval_t retval;
115024b0a25Sseb 	uint32_t		dlmgmt_flags;
116024b0a25Sseb 	dladm_status_t		status;
11732715170SCathy Zhou 	size_t			sz = sizeof (retval);
118d62bc4baSyz 
119024b0a25Sseb 	if (link == NULL || class == DATALINK_CLASS_ALL ||
120d62bc4baSyz 	    !(flags & (DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST)) ||
121d62bc4baSyz 	    linkidp == NULL) {
122d62bc4baSyz 		return (DLADM_STATUS_BADARG);
123d62bc4baSyz 	}
124d62bc4baSyz 
125d62bc4baSyz 	dlmgmt_flags = (flags & DLADM_OPT_ACTIVE) ? DLMGMT_ACTIVE : 0;
126d62bc4baSyz 	dlmgmt_flags |= (flags & DLADM_OPT_PERSIST) ? DLMGMT_PERSIST : 0;
127d62bc4baSyz 
128d62bc4baSyz 	(void) strlcpy(createid.ld_link, link, MAXLINKNAMELEN);
129d62bc4baSyz 	createid.ld_class = class;
130d62bc4baSyz 	createid.ld_media = media;
131d62bc4baSyz 	createid.ld_flags = dlmgmt_flags;
132d62bc4baSyz 	createid.ld_cmd = DLMGMT_CMD_CREATE_LINKID;
133d62bc4baSyz 	createid.ld_prefix = (flags & DLADM_OPT_PREFIX);
134d62bc4baSyz 
1354ac67f02SAnurag S. Maskey 	if ((status = dladm_door_call(handle, &createid, sizeof (createid),
13632715170SCathy Zhou 	    &retval, &sz)) == DLADM_STATUS_OK) {
137024b0a25Sseb 		*linkidp = retval.lr_linkid;
138024b0a25Sseb 	}
139024b0a25Sseb 	return (status);
140d62bc4baSyz }
141d62bc4baSyz 
142d62bc4baSyz /*
143d62bc4baSyz  * Destroy the given link ID.
144d62bc4baSyz  */
145d62bc4baSyz dladm_status_t
1464ac67f02SAnurag S. Maskey dladm_destroy_datalink_id(dladm_handle_t handle, datalink_id_t linkid,
1474ac67f02SAnurag S. Maskey     uint32_t flags)
148d62bc4baSyz {
149d62bc4baSyz 	dlmgmt_door_destroyid_t		destroyid;
150d62bc4baSyz 	dlmgmt_destroyid_retval_t	retval;
151d62bc4baSyz 	uint32_t			dlmgmt_flags;
15232715170SCathy Zhou 	size_t				sz = sizeof (retval);
153d62bc4baSyz 
154d62bc4baSyz 	dlmgmt_flags = (flags & DLADM_OPT_ACTIVE) ? DLMGMT_ACTIVE : 0;
155d62bc4baSyz 	dlmgmt_flags |= ((flags & DLADM_OPT_PERSIST) ? DLMGMT_PERSIST : 0);
156d62bc4baSyz 
157d62bc4baSyz 	destroyid.ld_cmd = DLMGMT_CMD_DESTROY_LINKID;
158d62bc4baSyz 	destroyid.ld_linkid = linkid;
159d62bc4baSyz 	destroyid.ld_flags = dlmgmt_flags;
160d62bc4baSyz 
16132715170SCathy Zhou 	return (dladm_door_call(handle, &destroyid, sizeof (destroyid),
16232715170SCathy Zhou 	    &retval, &sz));
163d62bc4baSyz }
164d62bc4baSyz 
165d62bc4baSyz /*
166d62bc4baSyz  * Remap a given link ID to a new name.
167d62bc4baSyz  */
168d62bc4baSyz dladm_status_t
1694ac67f02SAnurag S. Maskey dladm_remap_datalink_id(dladm_handle_t handle, datalink_id_t linkid,
1704ac67f02SAnurag S. Maskey     const char *link)
171d62bc4baSyz {
172d62bc4baSyz 	dlmgmt_door_remapid_t	remapid;
173d62bc4baSyz 	dlmgmt_remapid_retval_t	retval;
17432715170SCathy Zhou 	size_t			sz = sizeof (retval);
175d62bc4baSyz 
176d62bc4baSyz 	remapid.ld_cmd = DLMGMT_CMD_REMAP_LINKID;
177d62bc4baSyz 	remapid.ld_linkid = linkid;
178d62bc4baSyz 	(void) strlcpy(remapid.ld_link, link, MAXLINKNAMELEN);
179d62bc4baSyz 
18032715170SCathy Zhou 	return (dladm_door_call(handle, &remapid, sizeof (remapid),
18132715170SCathy Zhou 	    &retval, &sz));
182d62bc4baSyz }
183d62bc4baSyz 
184d62bc4baSyz /*
185d62bc4baSyz  * Make a given link ID active.
186d62bc4baSyz  */
187d62bc4baSyz dladm_status_t
1884ac67f02SAnurag S. Maskey dladm_up_datalink_id(dladm_handle_t handle, datalink_id_t linkid)
189d62bc4baSyz {
190024b0a25Sseb 	dlmgmt_door_upid_t	upid;
191024b0a25Sseb 	dlmgmt_upid_retval_t	retval;
19232715170SCathy Zhou 	size_t			sz = sizeof (retval);
193d62bc4baSyz 
194d62bc4baSyz 	upid.ld_cmd = DLMGMT_CMD_UP_LINKID;
195d62bc4baSyz 	upid.ld_linkid = linkid;
196d62bc4baSyz 
19732715170SCathy Zhou 	return (dladm_door_call(handle, &upid, sizeof (upid), &retval, &sz));
198d62bc4baSyz }
199d62bc4baSyz 
200d62bc4baSyz /*
201d62bc4baSyz  * Create a new link with the given name.  Return the new link's handle
202d62bc4baSyz  */
203d62bc4baSyz dladm_status_t
2044ac67f02SAnurag S. Maskey dladm_create_conf(dladm_handle_t handle, const char *link, datalink_id_t linkid,
205d62bc4baSyz     datalink_class_t class, uint32_t media, dladm_conf_t *confp)
206d62bc4baSyz {
207024b0a25Sseb 	dlmgmt_door_createconf_t	createconf;
208024b0a25Sseb 	dlmgmt_createconf_retval_t	retval;
209024b0a25Sseb 	dladm_status_t			status;
21032715170SCathy Zhou 	size_t				sz = sizeof (retval);
211d62bc4baSyz 
212024b0a25Sseb 	if (link == NULL || confp == NULL)
213d62bc4baSyz 		return (DLADM_STATUS_BADARG);
214d62bc4baSyz 
215d62bc4baSyz 	(void) strlcpy(createconf.ld_link, link, MAXLINKNAMELEN);
216d62bc4baSyz 	createconf.ld_class = class;
217d62bc4baSyz 	createconf.ld_media = media;
218d62bc4baSyz 	createconf.ld_linkid = linkid;
219d62bc4baSyz 	createconf.ld_cmd = DLMGMT_CMD_CREATECONF;
22032715170SCathy Zhou 	confp->ds_confid = DLADM_INVALID_CONF;
221d62bc4baSyz 
2224ac67f02SAnurag S. Maskey 	if ((status = dladm_door_call(handle, &createconf, sizeof (createconf),
22332715170SCathy Zhou 	    &retval, &sz)) == DLADM_STATUS_OK) {
22432715170SCathy Zhou 		confp->ds_readonly = B_FALSE;
22532715170SCathy Zhou 		confp->ds_confid = retval.lr_confid;
226024b0a25Sseb 	}
227024b0a25Sseb 	return (status);
228d62bc4baSyz }
229d62bc4baSyz 
230d62bc4baSyz /*
231d62bc4baSyz  * An active physical link reported by the dlmgmtd daemon might not be active
232d62bc4baSyz  * anymore as this link might be removed during system shutdown. Check its
233d62bc4baSyz  * real status by calling dladm_phys_info().
234d62bc4baSyz  */
235d62bc4baSyz dladm_status_t
2364ac67f02SAnurag S. Maskey i_dladm_phys_status(dladm_handle_t handle, datalink_id_t linkid,
2374ac67f02SAnurag S. Maskey     uint32_t *flagsp)
238d62bc4baSyz {
239d62bc4baSyz 	dladm_phys_attr_t	dpa;
240d62bc4baSyz 	dladm_status_t		status;
241d62bc4baSyz 
242d62bc4baSyz 	assert((*flagsp) & DLMGMT_ACTIVE);
243d62bc4baSyz 
2444ac67f02SAnurag S. Maskey 	status = dladm_phys_info(handle, linkid, &dpa, DLADM_OPT_ACTIVE);
245d62bc4baSyz 	if (status == DLADM_STATUS_NOTFOUND) {
246d62bc4baSyz 		/*
247d62bc4baSyz 		 * No active status, this link was removed. Update its status
248d62bc4baSyz 		 * in the daemon and delete all active linkprops.
2492d4eecfaSCathy Zhou 		 *
2502d4eecfaSCathy Zhou 		 * Note that the operation could fail. If it does, return
2512d4eecfaSCathy Zhou 		 * failure now since otherwise dladm_set_linkprop() might
2522d4eecfaSCathy Zhou 		 * call back to i_dladm_phys_status() recursively.
253d62bc4baSyz 		 */
2544ac67f02SAnurag S. Maskey 		if ((status = dladm_destroy_datalink_id(handle, linkid,
2554ac67f02SAnurag S. Maskey 		    DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK)
2562d4eecfaSCathy Zhou 			return (status);
2572d4eecfaSCathy Zhou 
2584ac67f02SAnurag S. Maskey 		(void) dladm_set_linkprop(handle, linkid, NULL, NULL, 0,
259d62bc4baSyz 		    DLADM_OPT_ACTIVE);
260d62bc4baSyz 
261d62bc4baSyz 		(*flagsp) &= ~DLMGMT_ACTIVE;
262d62bc4baSyz 		status = DLADM_STATUS_OK;
263d62bc4baSyz 	}
264d62bc4baSyz 	return (status);
265d62bc4baSyz }
266d62bc4baSyz 
267d62bc4baSyz /*
268d62bc4baSyz  * Walk each entry in the data link configuration repository and
269d62bc4baSyz  * call fn on the linkid and arg.
270d62bc4baSyz  */
271d62bc4baSyz dladm_status_t
2724ac67f02SAnurag S. Maskey dladm_walk_datalink_id(int (*fn)(dladm_handle_t, datalink_id_t, void *),
2734ac67f02SAnurag S. Maskey     dladm_handle_t handle, void *argp, datalink_class_t class,
2744ac67f02SAnurag S. Maskey     datalink_media_t dmedia, uint32_t flags)
275d62bc4baSyz {
276d62bc4baSyz 	dlmgmt_door_getnext_t	getnext;
277d62bc4baSyz 	dlmgmt_getnext_retval_t	retval;
278c0e21d6aSToomas Soome 	uint32_t		dlmgmt_flags;
279d62bc4baSyz 	datalink_id_t		linkid = DATALINK_INVALID_LINKID;
280d62bc4baSyz 	dladm_status_t		status = DLADM_STATUS_OK;
28132715170SCathy Zhou 	size_t			sz = sizeof (retval);
282d62bc4baSyz 
283d62bc4baSyz 	if (fn == NULL)
284d62bc4baSyz 		return (DLADM_STATUS_BADARG);
285d62bc4baSyz 
286d62bc4baSyz 	dlmgmt_flags = (flags & DLADM_OPT_ACTIVE) ? DLMGMT_ACTIVE : 0;
287d62bc4baSyz 	dlmgmt_flags |= ((flags & DLADM_OPT_PERSIST) ? DLMGMT_PERSIST : 0);
288d62bc4baSyz 
289d62bc4baSyz 	getnext.ld_cmd = DLMGMT_CMD_GETNEXT;
290d62bc4baSyz 	getnext.ld_class = class;
291d62bc4baSyz 	getnext.ld_dmedia = dmedia;
292d62bc4baSyz 	getnext.ld_flags = dlmgmt_flags;
293d62bc4baSyz 
294d62bc4baSyz 	do {
295d62bc4baSyz 		getnext.ld_linkid = linkid;
2964ac67f02SAnurag S. Maskey 		if ((status = dladm_door_call(handle, &getnext,
29732715170SCathy Zhou 		    sizeof (getnext), &retval, &sz)) != DLADM_STATUS_OK) {
298d62bc4baSyz 			/*
2997363c184SCathy Zhou 			 * Done with walking. If no next datalink is found,
3007363c184SCathy Zhou 			 * return success.
301d62bc4baSyz 			 */
3027363c184SCathy Zhou 			if (status == DLADM_STATUS_NOTFOUND)
3037363c184SCathy Zhou 				status = DLADM_STATUS_OK;
304d62bc4baSyz 			break;
305d62bc4baSyz 		}
306d62bc4baSyz 
307d62bc4baSyz 		linkid = retval.lr_linkid;
308d62bc4baSyz 		if ((retval.lr_class == DATALINK_CLASS_PHYS) &&
309d62bc4baSyz 		    (retval.lr_flags & DLMGMT_ACTIVE)) {
310d62bc4baSyz 			/*
311d62bc4baSyz 			 * An active physical link reported by the dlmgmtd
312d62bc4baSyz 			 * daemon might not be active anymore. Check its
313d62bc4baSyz 			 * real status.
314d62bc4baSyz 			 */
3154ac67f02SAnurag S. Maskey 			if (i_dladm_phys_status(handle, linkid,
3164ac67f02SAnurag S. Maskey 			    &retval.lr_flags) != DLADM_STATUS_OK) {
317d62bc4baSyz 				continue;
318d62bc4baSyz 			}
319d62bc4baSyz 
320d62bc4baSyz 			if (!(dlmgmt_flags & retval.lr_flags))
321d62bc4baSyz 				continue;
322d62bc4baSyz 		}
323d62bc4baSyz 
3244ac67f02SAnurag S. Maskey 		if (fn(handle, linkid, argp) == DLADM_WALK_TERMINATE)
325d62bc4baSyz 			break;
326d62bc4baSyz 	} while (linkid != DATALINK_INVALID_LINKID);
327d62bc4baSyz 
328d62bc4baSyz 	return (status);
329d62bc4baSyz }
330d62bc4baSyz 
331d62bc4baSyz /*
33232715170SCathy Zhou  * Get a handle of a copy of the link configuration (kept in the daemon)
33332715170SCathy Zhou  * for the given link so it can be updated later by dladm_write_conf().
33432715170SCathy Zhou  */
33532715170SCathy Zhou dladm_status_t
33632715170SCathy Zhou dladm_open_conf(dladm_handle_t handle, datalink_id_t linkid,
33732715170SCathy Zhou     dladm_conf_t *confp)
33832715170SCathy Zhou {
33932715170SCathy Zhou 	dlmgmt_door_openconf_t		openconf;
34032715170SCathy Zhou 	dlmgmt_openconf_retval_t	retval;
34132715170SCathy Zhou 	dladm_status_t			status;
34232715170SCathy Zhou 	size_t				sz;
34332715170SCathy Zhou 
34432715170SCathy Zhou 	if (linkid == DATALINK_INVALID_LINKID || confp == NULL)
34532715170SCathy Zhou 		return (DLADM_STATUS_BADARG);
34632715170SCathy Zhou 
34732715170SCathy Zhou 	sz = sizeof (retval);
34832715170SCathy Zhou 	openconf.ld_linkid = linkid;
34932715170SCathy Zhou 	openconf.ld_cmd = DLMGMT_CMD_OPENCONF;
35032715170SCathy Zhou 	confp->ds_confid = DLADM_INVALID_CONF;
35132715170SCathy Zhou 	if ((status = dladm_door_call(handle, &openconf,
35232715170SCathy Zhou 	    sizeof (openconf), &retval, &sz)) == DLADM_STATUS_OK) {
35332715170SCathy Zhou 		confp->ds_readonly = B_FALSE;
35432715170SCathy Zhou 		confp->ds_confid = retval.lr_confid;
35532715170SCathy Zhou 	}
35632715170SCathy Zhou 
35732715170SCathy Zhou 	return (status);
35832715170SCathy Zhou }
35932715170SCathy Zhou 
36032715170SCathy Zhou /*
36132715170SCathy Zhou  * Get the handle of a local snapshot of the link configuration. Note that
36232715170SCathy Zhou  * any operations with this handle are read-only, i.e., one can not update
36332715170SCathy Zhou  * the configuration with this handle.
364d62bc4baSyz  */
365d62bc4baSyz dladm_status_t
36632715170SCathy Zhou dladm_getsnap_conf(dladm_handle_t handle, datalink_id_t linkid,
3674ac67f02SAnurag S. Maskey     dladm_conf_t *confp)
368d62bc4baSyz {
36932715170SCathy Zhou 	dlmgmt_door_getconfsnapshot_t	snapshot;
37032715170SCathy Zhou 	dlmgmt_getconfsnapshot_retval_t	*retvalp;
37132715170SCathy Zhou 	char				*nvlbuf;
372d62bc4baSyz 	dladm_status_t			status;
37332715170SCathy Zhou 	int				err;
37432715170SCathy Zhou 	size_t				sz;
375d62bc4baSyz 
376d62bc4baSyz 	if (linkid == DATALINK_INVALID_LINKID || confp == NULL)
377d62bc4baSyz 		return (DLADM_STATUS_BADARG);
378d62bc4baSyz 
37932715170SCathy Zhou 	sz = sizeof (dlmgmt_getconfsnapshot_retval_t);
38032715170SCathy Zhou 	snapshot.ld_linkid = linkid;
38132715170SCathy Zhou 	snapshot.ld_cmd = DLMGMT_CMD_GETCONFSNAPSHOT;
38232715170SCathy Zhou again:
38332715170SCathy Zhou 	if ((retvalp = malloc(sz)) == NULL)
38432715170SCathy Zhou 		return (DLADM_STATUS_NOMEM);
38532715170SCathy Zhou 
38632715170SCathy Zhou 	if ((status = dladm_door_call(handle, &snapshot, sizeof (snapshot),
38732715170SCathy Zhou 	    retvalp, &sz)) == DLADM_STATUS_TOOSMALL) {
38832715170SCathy Zhou 		free(retvalp);
38932715170SCathy Zhou 		goto again;
39032715170SCathy Zhou 	}
39132715170SCathy Zhou 
39232715170SCathy Zhou 	if (status != DLADM_STATUS_OK) {
39332715170SCathy Zhou 		free(retvalp);
39432715170SCathy Zhou 		return (status);
39532715170SCathy Zhou 	}
396d62bc4baSyz 
39732715170SCathy Zhou 	confp->ds_readonly = B_TRUE;
39832715170SCathy Zhou 	nvlbuf = (char *)retvalp + sizeof (dlmgmt_getconfsnapshot_retval_t);
39932715170SCathy Zhou 	if ((err = nvlist_unpack(nvlbuf, retvalp->lr_nvlsz,
4000d1087e8SHans Rosenfeld 	    &(confp->ds_nvl), 0)) != 0) {
40132715170SCathy Zhou 		status = dladm_errno2status(err);
402024b0a25Sseb 	}
40332715170SCathy Zhou 	free(retvalp);
404024b0a25Sseb 	return (status);
405d62bc4baSyz }
406d62bc4baSyz 
407d62bc4baSyz /*
408d62bc4baSyz  * Commit the given link to the data link configuration repository so
409d62bc4baSyz  * that it will persist across reboots.
410d62bc4baSyz  */
411d62bc4baSyz dladm_status_t
4124ac67f02SAnurag S. Maskey dladm_write_conf(dladm_handle_t handle, dladm_conf_t conf)
413d62bc4baSyz {
414d62bc4baSyz 	dlmgmt_door_writeconf_t		writeconf;
415d62bc4baSyz 	dlmgmt_writeconf_retval_t	retval;
41632715170SCathy Zhou 	size_t				sz = sizeof (retval);
417d62bc4baSyz 
41832715170SCathy Zhou 	if (conf.ds_confid == DLADM_INVALID_CONF)
419d62bc4baSyz 		return (DLADM_STATUS_BADARG);
420d62bc4baSyz 
42132715170SCathy Zhou 	if (conf.ds_readonly)
42232715170SCathy Zhou 		return (DLADM_STATUS_DENIED);
42332715170SCathy Zhou 
424d62bc4baSyz 	writeconf.ld_cmd = DLMGMT_CMD_WRITECONF;
42532715170SCathy Zhou 	writeconf.ld_confid = conf.ds_confid;
426d62bc4baSyz 
42732715170SCathy Zhou 	return (dladm_door_call(handle, &writeconf, sizeof (writeconf),
42832715170SCathy Zhou 	    &retval, &sz));
429d62bc4baSyz }
430d62bc4baSyz 
431d62bc4baSyz /*
43232715170SCathy Zhou  * Given a dladm_conf_t, get the specific configuration field
43332715170SCathy Zhou  *
43432715170SCathy Zhou  * If the specified dladm_conf_t is a read-only snapshot of the configuration,
43532715170SCathy Zhou  * get a specific link propertie from that snapshot (nvl), otherwise, get
43632715170SCathy Zhou  * the link protperty from the dlmgmtd daemon using the given confid.
437d62bc4baSyz  */
438d62bc4baSyz dladm_status_t
4394ac67f02SAnurag S. Maskey dladm_get_conf_field(dladm_handle_t handle, dladm_conf_t conf, const char *attr,
4404ac67f02SAnurag S. Maskey     void *attrval, size_t attrsz)
441d62bc4baSyz {
44232715170SCathy Zhou 	dladm_status_t		status = DLADM_STATUS_OK;
443d62bc4baSyz 
44432715170SCathy Zhou 	if (attrval == NULL || attrsz == 0 || attr == NULL)
445d62bc4baSyz 		return (DLADM_STATUS_BADARG);
446d62bc4baSyz 
44732715170SCathy Zhou 	if (conf.ds_readonly) {
44832715170SCathy Zhou 		uchar_t		*oattrval;
44932715170SCathy Zhou 		uint32_t	oattrsz;
45032715170SCathy Zhou 		int		err;
451d62bc4baSyz 
45232715170SCathy Zhou 		if ((err = nvlist_lookup_byte_array(conf.ds_nvl, (char *)attr,
45332715170SCathy Zhou 		    &oattrval, &oattrsz)) != 0) {
45432715170SCathy Zhou 			return (dladm_errno2status(err));
45532715170SCathy Zhou 		}
45632715170SCathy Zhou 		if (oattrsz > attrsz)
45732715170SCathy Zhou 			return (DLADM_STATUS_TOOSMALL);
458d62bc4baSyz 
45932715170SCathy Zhou 		bcopy(oattrval, attrval, oattrsz);
46032715170SCathy Zhou 	} else {
46132715170SCathy Zhou 		dlmgmt_door_getattr_t	getattr;
46232715170SCathy Zhou 		dlmgmt_getattr_retval_t	retval;
46332715170SCathy Zhou 		size_t			sz = sizeof (retval);
464d62bc4baSyz 
46532715170SCathy Zhou 		if (conf.ds_confid == DLADM_INVALID_CONF)
46632715170SCathy Zhou 			return (DLADM_STATUS_BADARG);
46732715170SCathy Zhou 
46832715170SCathy Zhou 		getattr.ld_cmd = DLMGMT_CMD_GETATTR;
46932715170SCathy Zhou 		getattr.ld_confid = conf.ds_confid;
47032715170SCathy Zhou 		(void) strlcpy(getattr.ld_attr, attr, MAXLINKATTRLEN);
47132715170SCathy Zhou 
47232715170SCathy Zhou 		if ((status = dladm_door_call(handle, &getattr,
47332715170SCathy Zhou 		    sizeof (getattr), &retval, &sz)) != DLADM_STATUS_OK) {
47432715170SCathy Zhou 			return (status);
47532715170SCathy Zhou 		}
47632715170SCathy Zhou 
47732715170SCathy Zhou 		if (retval.lr_attrsz > attrsz)
47832715170SCathy Zhou 			return (DLADM_STATUS_TOOSMALL);
47932715170SCathy Zhou 
48032715170SCathy Zhou 		bcopy(retval.lr_attrval, attrval, retval.lr_attrsz);
48132715170SCathy Zhou 	}
48232715170SCathy Zhou 	return (status);
48362ee1d25SArtem Kachitchkine }
48462ee1d25SArtem Kachitchkine 
48562ee1d25SArtem Kachitchkine /*
48662ee1d25SArtem Kachitchkine  * Get next property attribute from data link configuration repository.
48732715170SCathy Zhou  * If last_attr is "", return the first property.
48862ee1d25SArtem Kachitchkine  */
48932715170SCathy Zhou /* ARGSUSED */
49062ee1d25SArtem Kachitchkine dladm_status_t
49162ee1d25SArtem Kachitchkine dladm_getnext_conf_linkprop(dladm_handle_t handle, dladm_conf_t conf,
49262ee1d25SArtem Kachitchkine     const char *last_attr, char *attr, void *attrval, size_t attrsz,
49362ee1d25SArtem Kachitchkine     size_t *attrszp)
49462ee1d25SArtem Kachitchkine {
49532715170SCathy Zhou 	nvlist_t	*nvl = conf.ds_nvl;
49632715170SCathy Zhou 	nvpair_t	*last = NULL, *nvp;
49732715170SCathy Zhou 	uchar_t		*oattrval;
49832715170SCathy Zhou 	uint32_t	oattrsz;
49932715170SCathy Zhou 	int		err;
50032715170SCathy Zhou 
50132715170SCathy Zhou 	if (nvl == NULL || attrval == NULL || attrsz == 0 || attr == NULL ||
50232715170SCathy Zhou 	    !conf.ds_readonly)
50362ee1d25SArtem Kachitchkine 		return (DLADM_STATUS_BADARG);
50432715170SCathy Zhou 
50532715170SCathy Zhou 	while ((nvp = nvlist_next_nvpair(nvl, last)) != NULL) {
50632715170SCathy Zhou 		if (last_attr[0] == '\0')
50732715170SCathy Zhou 			break;
50832715170SCathy Zhou 		if (last != NULL && strcmp(last_attr, nvpair_name(last)) == 0)
50932715170SCathy Zhou 			break;
51032715170SCathy Zhou 		last = nvp;
51162ee1d25SArtem Kachitchkine 	}
51262ee1d25SArtem Kachitchkine 
51332715170SCathy Zhou 	if (nvp == NULL)
51432715170SCathy Zhou 		return (DLADM_STATUS_NOTFOUND);
51562ee1d25SArtem Kachitchkine 
51632715170SCathy Zhou 	if ((err = nvpair_value_byte_array(nvp, (uchar_t **)&oattrval,
517c0e21d6aSToomas Soome 	    &oattrsz)) != 0) {
51832715170SCathy Zhou 		return (dladm_errno2status(err));
51962ee1d25SArtem Kachitchkine 	}
52062ee1d25SArtem Kachitchkine 
52132715170SCathy Zhou 	*attrszp = oattrsz;
52232715170SCathy Zhou 	if (oattrsz > attrsz)
52362ee1d25SArtem Kachitchkine 		return (DLADM_STATUS_TOOSMALL);
52462ee1d25SArtem Kachitchkine 
52532715170SCathy Zhou 	(void) strlcpy(attr, nvpair_name(nvp), MAXLINKATTRLEN);
52632715170SCathy Zhou 	bcopy(oattrval, attrval, oattrsz);
527024b0a25Sseb 	return (DLADM_STATUS_OK);
528d62bc4baSyz }
529d62bc4baSyz 
530d62bc4baSyz /*
531d62bc4baSyz  * Get the link ID that is associated with the given name.
532d62bc4baSyz  */
533d62bc4baSyz dladm_status_t
5344ac67f02SAnurag S. Maskey dladm_name2info(dladm_handle_t handle, const char *link, datalink_id_t *linkidp,
5354ac67f02SAnurag S. Maskey     uint32_t *flagp, datalink_class_t *classp, uint32_t *mediap)
536d62bc4baSyz {
537d62bc4baSyz 	dlmgmt_door_getlinkid_t		getlinkid;
538d62bc4baSyz 	dlmgmt_getlinkid_retval_t	retval;
539d62bc4baSyz 	datalink_id_t			linkid;
540d62bc4baSyz 	dladm_status_t			status;
54132715170SCathy Zhou 	size_t				sz = sizeof (retval);
542d62bc4baSyz 
543d62bc4baSyz 	getlinkid.ld_cmd = DLMGMT_CMD_GETLINKID;
544d62bc4baSyz 	(void) strlcpy(getlinkid.ld_link, link, MAXLINKNAMELEN);
545d62bc4baSyz 
5464ac67f02SAnurag S. Maskey 	if ((status = dladm_door_call(handle, &getlinkid, sizeof (getlinkid),
54732715170SCathy Zhou 	    &retval, &sz)) != DLADM_STATUS_OK) {
548d62bc4baSyz 		return (status);
549024b0a25Sseb 	}
550d62bc4baSyz 
551d62bc4baSyz 	linkid = retval.lr_linkid;
552d62bc4baSyz 	if (retval.lr_class == DATALINK_CLASS_PHYS &&
553d62bc4baSyz 	    retval.lr_flags & DLMGMT_ACTIVE) {
554d62bc4baSyz 		/*
555d62bc4baSyz 		 * An active physical link reported by the dlmgmtd daemon
556d62bc4baSyz 		 * might not be active anymore. Check and set its real status.
557d62bc4baSyz 		 */
5584ac67f02SAnurag S. Maskey 		status = i_dladm_phys_status(handle, linkid, &retval.lr_flags);
559d62bc4baSyz 		if (status != DLADM_STATUS_OK)
560d62bc4baSyz 			return (status);
561d62bc4baSyz 	}
562d62bc4baSyz 
563d62bc4baSyz 	if (linkidp != NULL)
564d62bc4baSyz 		*linkidp = linkid;
565d62bc4baSyz 	if (flagp != NULL) {
566d62bc4baSyz 		*flagp = retval.lr_flags & DLMGMT_ACTIVE ? DLADM_OPT_ACTIVE : 0;
567d62bc4baSyz 		*flagp |= (retval.lr_flags & DLMGMT_PERSIST) ?
568d62bc4baSyz 		    DLADM_OPT_PERSIST : 0;
569d62bc4baSyz 	}
570d62bc4baSyz 	if (classp != NULL)
571d62bc4baSyz 		*classp = retval.lr_class;
572d62bc4baSyz 	if (mediap != NULL)
573d62bc4baSyz 		*mediap = retval.lr_media;
574d62bc4baSyz 
575d62bc4baSyz 	return (DLADM_STATUS_OK);
576d62bc4baSyz }
577d62bc4baSyz 
578d62bc4baSyz /*
579d62bc4baSyz  * Get the link name that is associated with the given id.
580d62bc4baSyz  */
581d62bc4baSyz dladm_status_t
5824ac67f02SAnurag S. Maskey dladm_datalink_id2info(dladm_handle_t handle, datalink_id_t linkid,
5834ac67f02SAnurag S. Maskey     uint32_t *flagp, datalink_class_t *classp, uint32_t *mediap, char *link,
5844ac67f02SAnurag S. Maskey     size_t len)
585d62bc4baSyz {
586024b0a25Sseb 	dlmgmt_door_getname_t	getname;
587024b0a25Sseb 	dlmgmt_getname_retval_t	retval;
588024b0a25Sseb 	dladm_status_t		status;
58932715170SCathy Zhou 	size_t			sz = sizeof (retval);
590d62bc4baSyz 
591d62bc4baSyz 	if ((linkid == DATALINK_INVALID_LINKID) || (link != NULL && len == 0) ||
592d62bc4baSyz 	    (link == NULL && len != 0)) {
593d62bc4baSyz 		return (DLADM_STATUS_BADARG);
594d62bc4baSyz 	}
595d62bc4baSyz 
596d62bc4baSyz 	getname.ld_cmd = DLMGMT_CMD_GETNAME;
597d62bc4baSyz 	getname.ld_linkid = linkid;
5984ac67f02SAnurag S. Maskey 	if ((status = dladm_door_call(handle, &getname, sizeof (getname),
59932715170SCathy Zhou 	    &retval, &sz)) != DLADM_STATUS_OK) {
600d62bc4baSyz 		return (status);
601024b0a25Sseb 	}
602d62bc4baSyz 
603024b0a25Sseb 	if (len != 0 && (strlen(retval.lr_link) + 1 > len))
604d62bc4baSyz 		return (DLADM_STATUS_TOOSMALL);
605d62bc4baSyz 
606d62bc4baSyz 	if (retval.lr_class == DATALINK_CLASS_PHYS &&
607d62bc4baSyz 	    retval.lr_flags & DLMGMT_ACTIVE) {
608d62bc4baSyz 		/*
609d62bc4baSyz 		 * An active physical link reported by the dlmgmtd daemon
610d62bc4baSyz 		 * might not be active anymore. Check and set its real status.
611d62bc4baSyz 		 */
6124ac67f02SAnurag S. Maskey 		status = i_dladm_phys_status(handle, linkid, &retval.lr_flags);
613d62bc4baSyz 		if (status != DLADM_STATUS_OK)
614d62bc4baSyz 			return (status);
615d62bc4baSyz 	}
616d62bc4baSyz 
617d62bc4baSyz 	if (link != NULL)
618d62bc4baSyz 		(void) strlcpy(link, retval.lr_link, len);
619d62bc4baSyz 	if (classp != NULL)
620d62bc4baSyz 		*classp = retval.lr_class;
621d62bc4baSyz 	if (mediap != NULL)
622d62bc4baSyz 		*mediap = retval.lr_media;
623d62bc4baSyz 	if (flagp != NULL) {
624d62bc4baSyz 		*flagp = retval.lr_flags & DLMGMT_ACTIVE ?
625d62bc4baSyz 		    DLADM_OPT_ACTIVE : 0;
626d62bc4baSyz 		*flagp |= (retval.lr_flags & DLMGMT_PERSIST) ?
627d62bc4baSyz 		    DLADM_OPT_PERSIST : 0;
628d62bc4baSyz 	}
629d62bc4baSyz 	return (DLADM_STATUS_OK);
630d62bc4baSyz }
631d62bc4baSyz 
632d62bc4baSyz /*
633d62bc4baSyz  * Set the given attr with the given attrval for the given link.
634d62bc4baSyz  */
635d62bc4baSyz dladm_status_t
6364ac67f02SAnurag S. Maskey dladm_set_conf_field(dladm_handle_t handle, dladm_conf_t conf, const char *attr,
637d62bc4baSyz     dladm_datatype_t type, const void *attrval)
638d62bc4baSyz {
639024b0a25Sseb 	dlmgmt_door_setattr_t	setattr;
640024b0a25Sseb 	dlmgmt_setattr_retval_t	retval;
641024b0a25Sseb 	size_t			attrsz;
64232715170SCathy Zhou 	size_t			sz = sizeof (retval);
643d62bc4baSyz 
644024b0a25Sseb 	if (attr == NULL || attrval == NULL)
645d62bc4baSyz 		return (DLADM_STATUS_BADARG);
646d62bc4baSyz 
64732715170SCathy Zhou 	if (conf.ds_readonly)
64832715170SCathy Zhou 		return (DLADM_STATUS_DENIED);
64932715170SCathy Zhou 
650d62bc4baSyz 	if (type == DLADM_TYPE_STR)
651d62bc4baSyz 		attrsz = strlen(attrval) + 1;
652d62bc4baSyz 	else
653d62bc4baSyz 		attrsz = dladm_datatype_size[type];
654d62bc4baSyz 
655024b0a25Sseb 	if (attrsz > MAXLINKATTRVALLEN)
656024b0a25Sseb 		return (DLADM_STATUS_TOOSMALL);
657d62bc4baSyz 
658024b0a25Sseb 	setattr.ld_cmd = DLMGMT_CMD_SETATTR;
65932715170SCathy Zhou 	setattr.ld_confid = conf.ds_confid;
660024b0a25Sseb 	(void) strlcpy(setattr.ld_attr, attr, MAXLINKATTRLEN);
661*640aa5d6SRyan Goodfellow 	setattr.ld_attrsz = (uint32_t)attrsz;
662024b0a25Sseb 	setattr.ld_type = type;
663024b0a25Sseb 	bcopy(attrval, &setattr.ld_attrval, attrsz);
664d62bc4baSyz 
66532715170SCathy Zhou 	return (dladm_door_call(handle, &setattr, sizeof (setattr),
66632715170SCathy Zhou 	    &retval, &sz));
667d62bc4baSyz }
668d62bc4baSyz 
669d62bc4baSyz /*
670d62bc4baSyz  * Unset the given attr the given link.
671d62bc4baSyz  */
672d62bc4baSyz dladm_status_t
6734ac67f02SAnurag S. Maskey dladm_unset_conf_field(dladm_handle_t handle, dladm_conf_t conf,
6744ac67f02SAnurag S. Maskey     const char *attr)
675d62bc4baSyz {
676d62bc4baSyz 	dlmgmt_door_unsetattr_t		unsetattr;
677d62bc4baSyz 	dlmgmt_unsetattr_retval_t	retval;
67832715170SCathy Zhou 	size_t				sz = sizeof (retval);
679d62bc4baSyz 
680024b0a25Sseb 	if (attr == NULL)
681d62bc4baSyz 		return (DLADM_STATUS_BADARG);
682d62bc4baSyz 
68332715170SCathy Zhou 	if (conf.ds_readonly)
68432715170SCathy Zhou 		return (DLADM_STATUS_DENIED);
68532715170SCathy Zhou 
686d62bc4baSyz 	unsetattr.ld_cmd = DLMGMT_CMD_UNSETATTR;
68732715170SCathy Zhou 	unsetattr.ld_confid = conf.ds_confid;
688d62bc4baSyz 	(void) strlcpy(unsetattr.ld_attr, attr, MAXLINKATTRLEN);
689d62bc4baSyz 
69032715170SCathy Zhou 	return (dladm_door_call(handle, &unsetattr, sizeof (unsetattr),
69132715170SCathy Zhou 	    &retval, &sz));
692d62bc4baSyz }
693d62bc4baSyz 
694d62bc4baSyz /*
695d62bc4baSyz  * Remove the given link ID and its entry from the data link configuration
696d62bc4baSyz  * repository.
697d62bc4baSyz  */
698d62bc4baSyz dladm_status_t
6994ac67f02SAnurag S. Maskey dladm_remove_conf(dladm_handle_t handle, datalink_id_t linkid)
700d62bc4baSyz {
701d62bc4baSyz 	dlmgmt_door_removeconf_t	removeconf;
702d62bc4baSyz 	dlmgmt_removeconf_retval_t	retval;
70332715170SCathy Zhou 	size_t				sz = sizeof (retval);
704d62bc4baSyz 
705d62bc4baSyz 	removeconf.ld_cmd = DLMGMT_CMD_REMOVECONF;
706d62bc4baSyz 	removeconf.ld_linkid = linkid;
707d62bc4baSyz 
7084ac67f02SAnurag S. Maskey 	return (dladm_door_call(handle, &removeconf, sizeof (removeconf),
70932715170SCathy Zhou 	    &retval, &sz));
710d62bc4baSyz }
711d62bc4baSyz 
712d62bc4baSyz /*
713d62bc4baSyz  * Free the contents of the link structure.
714d62bc4baSyz  */
715d62bc4baSyz void
7164ac67f02SAnurag S. Maskey dladm_destroy_conf(dladm_handle_t handle, dladm_conf_t conf)
717d62bc4baSyz {
71832715170SCathy Zhou 	dlmgmt_door_destroyconf_t	dconf;
719d62bc4baSyz 	dlmgmt_destroyconf_retval_t	retval;
72032715170SCathy Zhou 	size_t				sz = sizeof (retval);
721d62bc4baSyz 
72232715170SCathy Zhou 	if (conf.ds_readonly) {
72332715170SCathy Zhou 		nvlist_free(conf.ds_nvl);
72432715170SCathy Zhou 	} else {
72532715170SCathy Zhou 		if (conf.ds_confid == DLADM_INVALID_CONF)
72632715170SCathy Zhou 			return;
727d62bc4baSyz 
72832715170SCathy Zhou 		dconf.ld_cmd = DLMGMT_CMD_DESTROYCONF;
72932715170SCathy Zhou 		dconf.ld_confid = conf.ds_confid;
730d62bc4baSyz 
73132715170SCathy Zhou 		(void) dladm_door_call(handle, &dconf, sizeof (dconf),
73232715170SCathy Zhou 		    &retval, &sz);
73332715170SCathy Zhou 	}
734d62bc4baSyz }
7352b24ab6bSSebastien Roy 
7362b24ab6bSSebastien Roy dladm_status_t
7372b24ab6bSSebastien Roy dladm_zone_boot(dladm_handle_t handle, zoneid_t zoneid)
7382b24ab6bSSebastien Roy {
7392b24ab6bSSebastien Roy 	dlmgmt_door_zoneboot_t		zoneboot;
7402b24ab6bSSebastien Roy 	dlmgmt_zoneboot_retval_t	retval;
74132715170SCathy Zhou 	size_t				sz = sizeof (retval);
7422b24ab6bSSebastien Roy 
7432b24ab6bSSebastien Roy 	zoneboot.ld_cmd = DLMGMT_CMD_ZONEBOOT;
7442b24ab6bSSebastien Roy 	zoneboot.ld_zoneid = zoneid;
74532715170SCathy Zhou 	return (dladm_door_call(handle, &zoneboot, sizeof (zoneboot),
74632715170SCathy Zhou 	    &retval, &sz));
7472b24ab6bSSebastien Roy }
7482b24ab6bSSebastien Roy 
7492b24ab6bSSebastien Roy dladm_status_t
7502b24ab6bSSebastien Roy dladm_zone_halt(dladm_handle_t handle, zoneid_t zoneid)
7512b24ab6bSSebastien Roy {
7522b24ab6bSSebastien Roy 	dlmgmt_door_zonehalt_t		zonehalt;
7532b24ab6bSSebastien Roy 	dlmgmt_zonehalt_retval_t	retval;
75432715170SCathy Zhou 	size_t				sz = sizeof (retval);
7552b24ab6bSSebastien Roy 
7562b24ab6bSSebastien Roy 	zonehalt.ld_cmd = DLMGMT_CMD_ZONEHALT;
7572b24ab6bSSebastien Roy 	zonehalt.ld_zoneid = zoneid;
75832715170SCathy Zhou 	return (dladm_door_call(handle, &zonehalt, sizeof (zonehalt),
75932715170SCathy Zhou 	    &retval, &sz));
7602b24ab6bSSebastien Roy }
761