xref: /freebsd/sys/geom/eli/g_eli_ctl.c (revision 8f1c45c20ab6167e767ac994ff156e3edb3d3c45)
1c58794deSPawel Jakub Dawidek /*-
23728855aSPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
33728855aSPedro F. Giffuni  *
41e09ff3dSPawel Jakub Dawidek  * Copyright (c) 2005-2011 Pawel Jakub Dawidek <pawel@dawidek.net>
5c58794deSPawel Jakub Dawidek  * All rights reserved.
6c58794deSPawel Jakub Dawidek  *
7c58794deSPawel Jakub Dawidek  * Redistribution and use in source and binary forms, with or without
8c58794deSPawel Jakub Dawidek  * modification, are permitted provided that the following conditions
9c58794deSPawel Jakub Dawidek  * are met:
10c58794deSPawel Jakub Dawidek  * 1. Redistributions of source code must retain the above copyright
11c58794deSPawel Jakub Dawidek  *    notice, this list of conditions and the following disclaimer.
12c58794deSPawel Jakub Dawidek  * 2. Redistributions in binary form must reproduce the above copyright
13c58794deSPawel Jakub Dawidek  *    notice, this list of conditions and the following disclaimer in the
14c58794deSPawel Jakub Dawidek  *    documentation and/or other materials provided with the distribution.
15c58794deSPawel Jakub Dawidek  *
16c58794deSPawel Jakub Dawidek  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
17c58794deSPawel Jakub Dawidek  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18c58794deSPawel Jakub Dawidek  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19c58794deSPawel Jakub Dawidek  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
20c58794deSPawel Jakub Dawidek  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21c58794deSPawel Jakub Dawidek  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22c58794deSPawel Jakub Dawidek  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23c58794deSPawel Jakub Dawidek  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24c58794deSPawel Jakub Dawidek  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25c58794deSPawel Jakub Dawidek  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26c58794deSPawel Jakub Dawidek  * SUCH DAMAGE.
27c58794deSPawel Jakub Dawidek  */
28c58794deSPawel Jakub Dawidek 
29c58794deSPawel Jakub Dawidek #include <sys/cdefs.h>
30c58794deSPawel Jakub Dawidek __FBSDID("$FreeBSD$");
31c58794deSPawel Jakub Dawidek 
32c58794deSPawel Jakub Dawidek #include <sys/param.h>
33c58794deSPawel Jakub Dawidek #include <sys/systm.h>
34c58794deSPawel Jakub Dawidek #include <sys/kernel.h>
35c58794deSPawel Jakub Dawidek #include <sys/module.h>
36c58794deSPawel Jakub Dawidek #include <sys/lock.h>
37c58794deSPawel Jakub Dawidek #include <sys/mutex.h>
38c58794deSPawel Jakub Dawidek #include <sys/bio.h>
39c58794deSPawel Jakub Dawidek #include <sys/sysctl.h>
40c58794deSPawel Jakub Dawidek #include <sys/malloc.h>
41c58794deSPawel Jakub Dawidek #include <sys/kthread.h>
42c58794deSPawel Jakub Dawidek #include <sys/proc.h>
43c58794deSPawel Jakub Dawidek #include <sys/sched.h>
44c58794deSPawel Jakub Dawidek #include <sys/uio.h>
45c58794deSPawel Jakub Dawidek 
46c58794deSPawel Jakub Dawidek #include <vm/uma.h>
47c58794deSPawel Jakub Dawidek 
48c58794deSPawel Jakub Dawidek #include <geom/geom.h>
49c58794deSPawel Jakub Dawidek #include <geom/eli/g_eli.h>
50c58794deSPawel Jakub Dawidek 
51c58794deSPawel Jakub Dawidek 
52c58794deSPawel Jakub Dawidek MALLOC_DECLARE(M_ELI);
53c58794deSPawel Jakub Dawidek 
54c58794deSPawel Jakub Dawidek 
55c58794deSPawel Jakub Dawidek static void
56c58794deSPawel Jakub Dawidek g_eli_ctl_attach(struct gctl_req *req, struct g_class *mp)
57c58794deSPawel Jakub Dawidek {
58c58794deSPawel Jakub Dawidek 	struct g_eli_metadata md;
59c58794deSPawel Jakub Dawidek 	struct g_provider *pp;
60c58794deSPawel Jakub Dawidek 	const char *name;
61c58794deSPawel Jakub Dawidek 	u_char *key, mkey[G_ELI_DATAIVKEYLEN];
62*8f1c45c2SMariusz Zaborski 	int *nargs, *detach, *readonly, *dryrun;
63c58794deSPawel Jakub Dawidek 	int keysize, error;
64c58794deSPawel Jakub Dawidek 	u_int nkey;
65c58794deSPawel Jakub Dawidek 
66c58794deSPawel Jakub Dawidek 	g_topology_assert();
67c58794deSPawel Jakub Dawidek 
68c58794deSPawel Jakub Dawidek 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
69c58794deSPawel Jakub Dawidek 	if (nargs == NULL) {
70c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "nargs");
71c58794deSPawel Jakub Dawidek 		return;
72c58794deSPawel Jakub Dawidek 	}
73c58794deSPawel Jakub Dawidek 	if (*nargs != 1) {
74c58794deSPawel Jakub Dawidek 		gctl_error(req, "Invalid number of arguments.");
75c58794deSPawel Jakub Dawidek 		return;
76c58794deSPawel Jakub Dawidek 	}
77c58794deSPawel Jakub Dawidek 
78c58794deSPawel Jakub Dawidek 	detach = gctl_get_paraml(req, "detach", sizeof(*detach));
79c58794deSPawel Jakub Dawidek 	if (detach == NULL) {
80c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "detach");
81c58794deSPawel Jakub Dawidek 		return;
82c58794deSPawel Jakub Dawidek 	}
83c58794deSPawel Jakub Dawidek 
8485059016SPawel Jakub Dawidek 	readonly = gctl_get_paraml(req, "readonly", sizeof(*readonly));
8585059016SPawel Jakub Dawidek 	if (readonly == NULL) {
8685059016SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "readonly");
8785059016SPawel Jakub Dawidek 		return;
8885059016SPawel Jakub Dawidek 	}
8985059016SPawel Jakub Dawidek 
90*8f1c45c2SMariusz Zaborski 	dryrun = gctl_get_paraml(req, "dryrun", sizeof(*dryrun));
91*8f1c45c2SMariusz Zaborski 	if (dryrun == NULL) {
92*8f1c45c2SMariusz Zaborski 		gctl_error(req, "No '%s' argument.", "dryrun");
93*8f1c45c2SMariusz Zaborski 		return;
94*8f1c45c2SMariusz Zaborski 	}
95*8f1c45c2SMariusz Zaborski 
9639b7ca45SAllan Jude 	if (*detach && *readonly) {
9739b7ca45SAllan Jude 		gctl_error(req, "Options -d and -r are mutually exclusive.");
9839b7ca45SAllan Jude 		return;
9939b7ca45SAllan Jude 	}
10039b7ca45SAllan Jude 
101c58794deSPawel Jakub Dawidek 	name = gctl_get_asciiparam(req, "arg0");
102c58794deSPawel Jakub Dawidek 	if (name == NULL) {
103c58794deSPawel Jakub Dawidek 		gctl_error(req, "No 'arg%u' argument.", 0);
104c58794deSPawel Jakub Dawidek 		return;
105c58794deSPawel Jakub Dawidek 	}
106c58794deSPawel Jakub Dawidek 	if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
107c58794deSPawel Jakub Dawidek 		name += strlen("/dev/");
108c58794deSPawel Jakub Dawidek 	pp = g_provider_by_name(name);
109c58794deSPawel Jakub Dawidek 	if (pp == NULL) {
110c58794deSPawel Jakub Dawidek 		gctl_error(req, "Provider %s is invalid.", name);
111c58794deSPawel Jakub Dawidek 		return;
112c58794deSPawel Jakub Dawidek 	}
113c58794deSPawel Jakub Dawidek 	error = g_eli_read_metadata(mp, pp, &md);
114c58794deSPawel Jakub Dawidek 	if (error != 0) {
115c58794deSPawel Jakub Dawidek 		gctl_error(req, "Cannot read metadata from %s (error=%d).",
116c58794deSPawel Jakub Dawidek 		    name, error);
117c58794deSPawel Jakub Dawidek 		return;
118c58794deSPawel Jakub Dawidek 	}
119c58794deSPawel Jakub Dawidek 	if (md.md_keys == 0x00) {
12039b7ca45SAllan Jude 		explicit_bzero(&md, sizeof(md));
121c58794deSPawel Jakub Dawidek 		gctl_error(req, "No valid keys on %s.", pp->name);
122c58794deSPawel Jakub Dawidek 		return;
123c58794deSPawel Jakub Dawidek 	}
124c58794deSPawel Jakub Dawidek 
125c58794deSPawel Jakub Dawidek 	key = gctl_get_param(req, "key", &keysize);
126c58794deSPawel Jakub Dawidek 	if (key == NULL || keysize != G_ELI_USERKEYLEN) {
12739b7ca45SAllan Jude 		explicit_bzero(&md, sizeof(md));
128c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "key");
129c58794deSPawel Jakub Dawidek 		return;
130c58794deSPawel Jakub Dawidek 	}
131c58794deSPawel Jakub Dawidek 
132c58794deSPawel Jakub Dawidek 	error = g_eli_mkey_decrypt(&md, key, mkey, &nkey);
13339b7ca45SAllan Jude 	explicit_bzero(key, keysize);
134c58794deSPawel Jakub Dawidek 	if (error == -1) {
13539b7ca45SAllan Jude 		explicit_bzero(&md, sizeof(md));
136c58794deSPawel Jakub Dawidek 		gctl_error(req, "Wrong key for %s.", pp->name);
137c58794deSPawel Jakub Dawidek 		return;
138c58794deSPawel Jakub Dawidek 	} else if (error > 0) {
13939b7ca45SAllan Jude 		explicit_bzero(&md, sizeof(md));
140c58794deSPawel Jakub Dawidek 		gctl_error(req, "Cannot decrypt Master Key for %s (error=%d).",
141c58794deSPawel Jakub Dawidek 		    pp->name, error);
142c58794deSPawel Jakub Dawidek 		return;
143c58794deSPawel Jakub Dawidek 	}
144c58794deSPawel Jakub Dawidek 	G_ELI_DEBUG(1, "Using Master Key %u for %s.", nkey, pp->name);
145c58794deSPawel Jakub Dawidek 
146c58794deSPawel Jakub Dawidek 	if (*detach)
147c58794deSPawel Jakub Dawidek 		md.md_flags |= G_ELI_FLAG_WO_DETACH;
14885059016SPawel Jakub Dawidek 	if (*readonly)
14985059016SPawel Jakub Dawidek 		md.md_flags |= G_ELI_FLAG_RO;
150*8f1c45c2SMariusz Zaborski 	if (!*dryrun)
151c58794deSPawel Jakub Dawidek 		g_eli_create(req, mp, pp, &md, mkey, nkey);
15239b7ca45SAllan Jude 	explicit_bzero(mkey, sizeof(mkey));
15339b7ca45SAllan Jude 	explicit_bzero(&md, sizeof(md));
154c58794deSPawel Jakub Dawidek }
155c58794deSPawel Jakub Dawidek 
156c58794deSPawel Jakub Dawidek static struct g_eli_softc *
157c58794deSPawel Jakub Dawidek g_eli_find_device(struct g_class *mp, const char *prov)
158c58794deSPawel Jakub Dawidek {
159c58794deSPawel Jakub Dawidek 	struct g_eli_softc *sc;
160c58794deSPawel Jakub Dawidek 	struct g_geom *gp;
161c58794deSPawel Jakub Dawidek 	struct g_provider *pp;
162c58794deSPawel Jakub Dawidek 	struct g_consumer *cp;
163c58794deSPawel Jakub Dawidek 
164c58794deSPawel Jakub Dawidek 	if (strncmp(prov, "/dev/", strlen("/dev/")) == 0)
165c58794deSPawel Jakub Dawidek 		prov += strlen("/dev/");
166c58794deSPawel Jakub Dawidek 	LIST_FOREACH(gp, &mp->geom, geom) {
167c58794deSPawel Jakub Dawidek 		sc = gp->softc;
168c58794deSPawel Jakub Dawidek 		if (sc == NULL)
169c58794deSPawel Jakub Dawidek 			continue;
170c58794deSPawel Jakub Dawidek 		pp = LIST_FIRST(&gp->provider);
171c58794deSPawel Jakub Dawidek 		if (pp != NULL && strcmp(pp->name, prov) == 0)
172c58794deSPawel Jakub Dawidek 			return (sc);
173c58794deSPawel Jakub Dawidek 		cp = LIST_FIRST(&gp->consumer);
174c58794deSPawel Jakub Dawidek 		if (cp != NULL && cp->provider != NULL &&
175c58794deSPawel Jakub Dawidek 		    strcmp(cp->provider->name, prov) == 0) {
176c58794deSPawel Jakub Dawidek 			return (sc);
177c58794deSPawel Jakub Dawidek 		}
178c58794deSPawel Jakub Dawidek 	}
179c58794deSPawel Jakub Dawidek 	return (NULL);
180c58794deSPawel Jakub Dawidek }
181c58794deSPawel Jakub Dawidek 
182c58794deSPawel Jakub Dawidek static void
183c58794deSPawel Jakub Dawidek g_eli_ctl_detach(struct gctl_req *req, struct g_class *mp)
184c58794deSPawel Jakub Dawidek {
185c58794deSPawel Jakub Dawidek 	struct g_eli_softc *sc;
186c58794deSPawel Jakub Dawidek 	int *force, *last, *nargs, error;
187c58794deSPawel Jakub Dawidek 	const char *prov;
188c58794deSPawel Jakub Dawidek 	char param[16];
1897d54b385SPawel Jakub Dawidek 	int i;
190c58794deSPawel Jakub Dawidek 
191c58794deSPawel Jakub Dawidek 	g_topology_assert();
192c58794deSPawel Jakub Dawidek 
193c58794deSPawel Jakub Dawidek 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
194c58794deSPawel Jakub Dawidek 	if (nargs == NULL) {
195c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "nargs");
196c58794deSPawel Jakub Dawidek 		return;
197c58794deSPawel Jakub Dawidek 	}
198c58794deSPawel Jakub Dawidek 	if (*nargs <= 0) {
199c58794deSPawel Jakub Dawidek 		gctl_error(req, "Missing device(s).");
200c58794deSPawel Jakub Dawidek 		return;
201c58794deSPawel Jakub Dawidek 	}
202c58794deSPawel Jakub Dawidek 	force = gctl_get_paraml(req, "force", sizeof(*force));
203c58794deSPawel Jakub Dawidek 	if (force == NULL) {
204c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "force");
205c58794deSPawel Jakub Dawidek 		return;
206c58794deSPawel Jakub Dawidek 	}
207c58794deSPawel Jakub Dawidek 	last = gctl_get_paraml(req, "last", sizeof(*last));
208c58794deSPawel Jakub Dawidek 	if (last == NULL) {
209c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "last");
210c58794deSPawel Jakub Dawidek 		return;
211c58794deSPawel Jakub Dawidek 	}
212c58794deSPawel Jakub Dawidek 
2137d54b385SPawel Jakub Dawidek 	for (i = 0; i < *nargs; i++) {
2147d54b385SPawel Jakub Dawidek 		snprintf(param, sizeof(param), "arg%d", i);
215c58794deSPawel Jakub Dawidek 		prov = gctl_get_asciiparam(req, param);
216c58794deSPawel Jakub Dawidek 		if (prov == NULL) {
2177d54b385SPawel Jakub Dawidek 			gctl_error(req, "No 'arg%d' argument.", i);
218c58794deSPawel Jakub Dawidek 			return;
219c58794deSPawel Jakub Dawidek 		}
220c58794deSPawel Jakub Dawidek 		sc = g_eli_find_device(mp, prov);
221c58794deSPawel Jakub Dawidek 		if (sc == NULL) {
222c58794deSPawel Jakub Dawidek 			gctl_error(req, "No such device: %s.", prov);
223c58794deSPawel Jakub Dawidek 			return;
224c58794deSPawel Jakub Dawidek 		}
225c58794deSPawel Jakub Dawidek 		if (*last) {
226c58794deSPawel Jakub Dawidek 			sc->sc_flags |= G_ELI_FLAG_RW_DETACH;
227c58794deSPawel Jakub Dawidek 			sc->sc_geom->access = g_eli_access;
228c58794deSPawel Jakub Dawidek 		} else {
2295ad4a7c7SPawel Jakub Dawidek 			error = g_eli_destroy(sc, *force ? TRUE : FALSE);
230c58794deSPawel Jakub Dawidek 			if (error != 0) {
231c58794deSPawel Jakub Dawidek 				gctl_error(req,
232c58794deSPawel Jakub Dawidek 				    "Cannot destroy device %s (error=%d).",
233c58794deSPawel Jakub Dawidek 				    sc->sc_name, error);
234c58794deSPawel Jakub Dawidek 				return;
235c58794deSPawel Jakub Dawidek 			}
236c58794deSPawel Jakub Dawidek 		}
237c58794deSPawel Jakub Dawidek 	}
238c58794deSPawel Jakub Dawidek }
239c58794deSPawel Jakub Dawidek 
240c58794deSPawel Jakub Dawidek static void
241c58794deSPawel Jakub Dawidek g_eli_ctl_onetime(struct gctl_req *req, struct g_class *mp)
242c58794deSPawel Jakub Dawidek {
243c58794deSPawel Jakub Dawidek 	struct g_eli_metadata md;
244c58794deSPawel Jakub Dawidek 	struct g_provider *pp;
245c58794deSPawel Jakub Dawidek 	const char *name;
246c58794deSPawel Jakub Dawidek 	intmax_t *keylen, *sectorsize;
247c58794deSPawel Jakub Dawidek 	u_char mkey[G_ELI_DATAIVKEYLEN];
24846e34470SPawel Jakub Dawidek 	int *nargs, *detach, *notrim;
249c58794deSPawel Jakub Dawidek 
250c58794deSPawel Jakub Dawidek 	g_topology_assert();
251c58794deSPawel Jakub Dawidek 	bzero(&md, sizeof(md));
252c58794deSPawel Jakub Dawidek 
253c58794deSPawel Jakub Dawidek 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
254c58794deSPawel Jakub Dawidek 	if (nargs == NULL) {
255c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "nargs");
256c58794deSPawel Jakub Dawidek 		return;
257c58794deSPawel Jakub Dawidek 	}
258c58794deSPawel Jakub Dawidek 	if (*nargs != 1) {
259c58794deSPawel Jakub Dawidek 		gctl_error(req, "Invalid number of arguments.");
260c58794deSPawel Jakub Dawidek 		return;
261c58794deSPawel Jakub Dawidek 	}
262c58794deSPawel Jakub Dawidek 
263c58794deSPawel Jakub Dawidek 	strlcpy(md.md_magic, G_ELI_MAGIC, sizeof(md.md_magic));
264c58794deSPawel Jakub Dawidek 	md.md_version = G_ELI_VERSION;
265c58794deSPawel Jakub Dawidek 	md.md_flags |= G_ELI_FLAG_ONETIME;
26646e34470SPawel Jakub Dawidek 
26746e34470SPawel Jakub Dawidek 	detach = gctl_get_paraml(req, "detach", sizeof(*detach));
26846e34470SPawel Jakub Dawidek 	if (detach != NULL && *detach)
269c58794deSPawel Jakub Dawidek 		md.md_flags |= G_ELI_FLAG_WO_DETACH;
27046e34470SPawel Jakub Dawidek 	notrim = gctl_get_paraml(req, "notrim", sizeof(*notrim));
27146e34470SPawel Jakub Dawidek 	if (notrim != NULL && *notrim)
27246e34470SPawel Jakub Dawidek 		md.md_flags |= G_ELI_FLAG_NODELETE;
273c58794deSPawel Jakub Dawidek 
274c84efdcaSPawel Jakub Dawidek 	md.md_ealgo = CRYPTO_ALGORITHM_MIN - 1;
275eaa3b919SPawel Jakub Dawidek 	name = gctl_get_asciiparam(req, "aalgo");
276c58794deSPawel Jakub Dawidek 	if (name == NULL) {
277eaa3b919SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "aalgo");
278c58794deSPawel Jakub Dawidek 		return;
279c58794deSPawel Jakub Dawidek 	}
280a478ea74SPawel Jakub Dawidek 	if (*name != '\0') {
281eaa3b919SPawel Jakub Dawidek 		md.md_aalgo = g_eli_str2aalgo(name);
282c84efdcaSPawel Jakub Dawidek 		if (md.md_aalgo >= CRYPTO_ALGORITHM_MIN &&
283c84efdcaSPawel Jakub Dawidek 		    md.md_aalgo <= CRYPTO_ALGORITHM_MAX) {
284eaa3b919SPawel Jakub Dawidek 			md.md_flags |= G_ELI_FLAG_AUTH;
285c84efdcaSPawel Jakub Dawidek 		} else {
286c84efdcaSPawel Jakub Dawidek 			/*
287c84efdcaSPawel Jakub Dawidek 			 * For backward compatibility, check if the -a option
288c84efdcaSPawel Jakub Dawidek 			 * was used to provide encryption algorithm.
289c84efdcaSPawel Jakub Dawidek 			 */
290c84efdcaSPawel Jakub Dawidek 			md.md_ealgo = g_eli_str2ealgo(name);
291c84efdcaSPawel Jakub Dawidek 			if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
292c84efdcaSPawel Jakub Dawidek 			    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
293c84efdcaSPawel Jakub Dawidek 				gctl_error(req,
294c84efdcaSPawel Jakub Dawidek 				    "Invalid authentication algorithm.");
295c84efdcaSPawel Jakub Dawidek 				return;
296c84efdcaSPawel Jakub Dawidek 			} else {
297c84efdcaSPawel Jakub Dawidek 				gctl_error(req, "warning: The -e option, not "
298c84efdcaSPawel Jakub Dawidek 				    "the -a option is now used to specify "
299c84efdcaSPawel Jakub Dawidek 				    "encryption algorithm to use.");
300c84efdcaSPawel Jakub Dawidek 			}
301c84efdcaSPawel Jakub Dawidek 		}
302eaa3b919SPawel Jakub Dawidek 	}
303eaa3b919SPawel Jakub Dawidek 
304c84efdcaSPawel Jakub Dawidek 	if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
305c84efdcaSPawel Jakub Dawidek 	    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
306eaa3b919SPawel Jakub Dawidek 		name = gctl_get_asciiparam(req, "ealgo");
307eaa3b919SPawel Jakub Dawidek 		if (name == NULL) {
308eaa3b919SPawel Jakub Dawidek 			gctl_error(req, "No '%s' argument.", "ealgo");
309eaa3b919SPawel Jakub Dawidek 			return;
310eaa3b919SPawel Jakub Dawidek 		}
311eaa3b919SPawel Jakub Dawidek 		md.md_ealgo = g_eli_str2ealgo(name);
312eaa3b919SPawel Jakub Dawidek 		if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
313eaa3b919SPawel Jakub Dawidek 		    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
314eaa3b919SPawel Jakub Dawidek 			gctl_error(req, "Invalid encryption algorithm.");
315c58794deSPawel Jakub Dawidek 			return;
316c58794deSPawel Jakub Dawidek 		}
317c84efdcaSPawel Jakub Dawidek 	}
318c58794deSPawel Jakub Dawidek 
319c58794deSPawel Jakub Dawidek 	keylen = gctl_get_paraml(req, "keylen", sizeof(*keylen));
320c58794deSPawel Jakub Dawidek 	if (keylen == NULL) {
321c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "keylen");
322c58794deSPawel Jakub Dawidek 		return;
323c58794deSPawel Jakub Dawidek 	}
324eaa3b919SPawel Jakub Dawidek 	md.md_keylen = g_eli_keylen(md.md_ealgo, *keylen);
325c58794deSPawel Jakub Dawidek 	if (md.md_keylen == 0) {
326c58794deSPawel Jakub Dawidek 		gctl_error(req, "Invalid '%s' argument.", "keylen");
327c58794deSPawel Jakub Dawidek 		return;
328c58794deSPawel Jakub Dawidek 	}
329c58794deSPawel Jakub Dawidek 
330c58794deSPawel Jakub Dawidek 	/* Not important here. */
331c58794deSPawel Jakub Dawidek 	md.md_provsize = 0;
332c58794deSPawel Jakub Dawidek 	/* Not important here. */
333c58794deSPawel Jakub Dawidek 	bzero(md.md_salt, sizeof(md.md_salt));
334c58794deSPawel Jakub Dawidek 
335c58794deSPawel Jakub Dawidek 	md.md_keys = 0x01;
336c58794deSPawel Jakub Dawidek 	arc4rand(mkey, sizeof(mkey), 0);
337c58794deSPawel Jakub Dawidek 
338c58794deSPawel Jakub Dawidek 	/* Not important here. */
339c58794deSPawel Jakub Dawidek 	bzero(md.md_hash, sizeof(md.md_hash));
340c58794deSPawel Jakub Dawidek 
341c58794deSPawel Jakub Dawidek 	name = gctl_get_asciiparam(req, "arg0");
342c58794deSPawel Jakub Dawidek 	if (name == NULL) {
343c58794deSPawel Jakub Dawidek 		gctl_error(req, "No 'arg%u' argument.", 0);
344c58794deSPawel Jakub Dawidek 		return;
345c58794deSPawel Jakub Dawidek 	}
346c58794deSPawel Jakub Dawidek 	if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
347c58794deSPawel Jakub Dawidek 		name += strlen("/dev/");
348c58794deSPawel Jakub Dawidek 	pp = g_provider_by_name(name);
349c58794deSPawel Jakub Dawidek 	if (pp == NULL) {
350c58794deSPawel Jakub Dawidek 		gctl_error(req, "Provider %s is invalid.", name);
351c58794deSPawel Jakub Dawidek 		return;
352c58794deSPawel Jakub Dawidek 	}
353c58794deSPawel Jakub Dawidek 
354c58794deSPawel Jakub Dawidek 	sectorsize = gctl_get_paraml(req, "sectorsize", sizeof(*sectorsize));
355c58794deSPawel Jakub Dawidek 	if (sectorsize == NULL) {
356c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "sectorsize");
357c58794deSPawel Jakub Dawidek 		return;
358c58794deSPawel Jakub Dawidek 	}
359c58794deSPawel Jakub Dawidek 	if (*sectorsize == 0)
360c58794deSPawel Jakub Dawidek 		md.md_sectorsize = pp->sectorsize;
361c58794deSPawel Jakub Dawidek 	else {
362c58794deSPawel Jakub Dawidek 		if (*sectorsize < 0 || (*sectorsize % pp->sectorsize) != 0) {
363c58794deSPawel Jakub Dawidek 			gctl_error(req, "Invalid sector size.");
364c58794deSPawel Jakub Dawidek 			return;
365c58794deSPawel Jakub Dawidek 		}
36697a669a3SPawel Jakub Dawidek 		if (*sectorsize > PAGE_SIZE) {
36797a669a3SPawel Jakub Dawidek 			gctl_error(req, "warning: Using sectorsize bigger than "
36897a669a3SPawel Jakub Dawidek 			    "the page size!");
36997a669a3SPawel Jakub Dawidek 		}
370c58794deSPawel Jakub Dawidek 		md.md_sectorsize = *sectorsize;
371c58794deSPawel Jakub Dawidek 	}
372c58794deSPawel Jakub Dawidek 
373c58794deSPawel Jakub Dawidek 	g_eli_create(req, mp, pp, &md, mkey, -1);
37439b7ca45SAllan Jude 	explicit_bzero(mkey, sizeof(mkey));
37539b7ca45SAllan Jude 	explicit_bzero(&md, sizeof(md));
376c58794deSPawel Jakub Dawidek }
377c58794deSPawel Jakub Dawidek 
378c58794deSPawel Jakub Dawidek static void
3798abd1ad1SPawel Jakub Dawidek g_eli_ctl_configure(struct gctl_req *req, struct g_class *mp)
3808abd1ad1SPawel Jakub Dawidek {
3818abd1ad1SPawel Jakub Dawidek 	struct g_eli_softc *sc;
3828abd1ad1SPawel Jakub Dawidek 	struct g_eli_metadata md;
3838abd1ad1SPawel Jakub Dawidek 	struct g_provider *pp;
3848abd1ad1SPawel Jakub Dawidek 	struct g_consumer *cp;
3858abd1ad1SPawel Jakub Dawidek 	char param[16];
3868abd1ad1SPawel Jakub Dawidek 	const char *prov;
3878abd1ad1SPawel Jakub Dawidek 	u_char *sector;
388d8736625SAllan Jude 	int *nargs, *boot, *noboot, *trim, *notrim, *geliboot, *nogeliboot;
3893453dc72SMariusz Zaborski 	int *displaypass, *nodisplaypass;
39046e34470SPawel Jakub Dawidek 	int zero, error, changed;
3918abd1ad1SPawel Jakub Dawidek 	u_int i;
3928abd1ad1SPawel Jakub Dawidek 
3938abd1ad1SPawel Jakub Dawidek 	g_topology_assert();
3948abd1ad1SPawel Jakub Dawidek 
39546e34470SPawel Jakub Dawidek 	changed = 0;
39646e34470SPawel Jakub Dawidek 	zero = 0;
39746e34470SPawel Jakub Dawidek 
3988abd1ad1SPawel Jakub Dawidek 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
3998abd1ad1SPawel Jakub Dawidek 	if (nargs == NULL) {
4008abd1ad1SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "nargs");
4018abd1ad1SPawel Jakub Dawidek 		return;
4028abd1ad1SPawel Jakub Dawidek 	}
4038abd1ad1SPawel Jakub Dawidek 	if (*nargs <= 0) {
4048abd1ad1SPawel Jakub Dawidek 		gctl_error(req, "Missing device(s).");
4058abd1ad1SPawel Jakub Dawidek 		return;
4068abd1ad1SPawel Jakub Dawidek 	}
4078abd1ad1SPawel Jakub Dawidek 
4088abd1ad1SPawel Jakub Dawidek 	boot = gctl_get_paraml(req, "boot", sizeof(*boot));
40946e34470SPawel Jakub Dawidek 	if (boot == NULL)
41046e34470SPawel Jakub Dawidek 		boot = &zero;
4118abd1ad1SPawel Jakub Dawidek 	noboot = gctl_get_paraml(req, "noboot", sizeof(*noboot));
41246e34470SPawel Jakub Dawidek 	if (noboot == NULL)
41346e34470SPawel Jakub Dawidek 		noboot = &zero;
4148abd1ad1SPawel Jakub Dawidek 	if (*boot && *noboot) {
4158abd1ad1SPawel Jakub Dawidek 		gctl_error(req, "Options -b and -B are mutually exclusive.");
4168abd1ad1SPawel Jakub Dawidek 		return;
4178abd1ad1SPawel Jakub Dawidek 	}
41846e34470SPawel Jakub Dawidek 	if (*boot || *noboot)
41946e34470SPawel Jakub Dawidek 		changed = 1;
42046e34470SPawel Jakub Dawidek 
42146e34470SPawel Jakub Dawidek 	trim = gctl_get_paraml(req, "trim", sizeof(*trim));
42246e34470SPawel Jakub Dawidek 	if (trim == NULL)
42346e34470SPawel Jakub Dawidek 		trim = &zero;
42446e34470SPawel Jakub Dawidek 	notrim = gctl_get_paraml(req, "notrim", sizeof(*notrim));
42546e34470SPawel Jakub Dawidek 	if (notrim == NULL)
42646e34470SPawel Jakub Dawidek 		notrim = &zero;
42746e34470SPawel Jakub Dawidek 	if (*trim && *notrim) {
42846e34470SPawel Jakub Dawidek 		gctl_error(req, "Options -t and -T are mutually exclusive.");
42946e34470SPawel Jakub Dawidek 		return;
43046e34470SPawel Jakub Dawidek 	}
43146e34470SPawel Jakub Dawidek 	if (*trim || *notrim)
43246e34470SPawel Jakub Dawidek 		changed = 1;
43346e34470SPawel Jakub Dawidek 
434d8736625SAllan Jude 	geliboot = gctl_get_paraml(req, "geliboot", sizeof(*geliboot));
435d8736625SAllan Jude 	if (geliboot == NULL)
436d8736625SAllan Jude 		geliboot = &zero;
437d8736625SAllan Jude 	nogeliboot = gctl_get_paraml(req, "nogeliboot", sizeof(*nogeliboot));
438d8736625SAllan Jude 	if (nogeliboot == NULL)
439d8736625SAllan Jude 		nogeliboot = &zero;
440d8736625SAllan Jude 	if (*geliboot && *nogeliboot) {
441d8736625SAllan Jude 		gctl_error(req, "Options -g and -G are mutually exclusive.");
442d8736625SAllan Jude 		return;
443d8736625SAllan Jude 	}
444d8736625SAllan Jude 	if (*geliboot || *nogeliboot)
445d8736625SAllan Jude 		changed = 1;
446d8736625SAllan Jude 
4473453dc72SMariusz Zaborski 	displaypass = gctl_get_paraml(req, "displaypass", sizeof(*displaypass));
4483453dc72SMariusz Zaborski 	if (displaypass == NULL)
4493453dc72SMariusz Zaborski 		displaypass = &zero;
4503453dc72SMariusz Zaborski 	nodisplaypass = gctl_get_paraml(req, "nodisplaypass", sizeof(*nodisplaypass));
4513453dc72SMariusz Zaborski 	if (nodisplaypass == NULL)
4523453dc72SMariusz Zaborski 		nodisplaypass = &zero;
4533453dc72SMariusz Zaborski 	if (*displaypass && *nodisplaypass) {
4543453dc72SMariusz Zaborski 		gctl_error(req, "Options -d and -D are mutually exclusive.");
4553453dc72SMariusz Zaborski 		return;
4563453dc72SMariusz Zaborski 	}
4573453dc72SMariusz Zaborski 	if (*displaypass || *nodisplaypass)
4583453dc72SMariusz Zaborski 		changed = 1;
4593453dc72SMariusz Zaborski 
46046e34470SPawel Jakub Dawidek 	if (!changed) {
4618abd1ad1SPawel Jakub Dawidek 		gctl_error(req, "No option given.");
4628abd1ad1SPawel Jakub Dawidek 		return;
4638abd1ad1SPawel Jakub Dawidek 	}
4648abd1ad1SPawel Jakub Dawidek 
4658abd1ad1SPawel Jakub Dawidek 	for (i = 0; i < *nargs; i++) {
4668abd1ad1SPawel Jakub Dawidek 		snprintf(param, sizeof(param), "arg%d", i);
4678abd1ad1SPawel Jakub Dawidek 		prov = gctl_get_asciiparam(req, param);
4688abd1ad1SPawel Jakub Dawidek 		if (prov == NULL) {
4698abd1ad1SPawel Jakub Dawidek 			gctl_error(req, "No 'arg%d' argument.", i);
4708abd1ad1SPawel Jakub Dawidek 			return;
4718abd1ad1SPawel Jakub Dawidek 		}
4728abd1ad1SPawel Jakub Dawidek 		sc = g_eli_find_device(mp, prov);
4738abd1ad1SPawel Jakub Dawidek 		if (sc == NULL) {
4748abd1ad1SPawel Jakub Dawidek 			/*
4758abd1ad1SPawel Jakub Dawidek 			 * We ignore not attached providers, userland part will
4768abd1ad1SPawel Jakub Dawidek 			 * take care of them.
4778abd1ad1SPawel Jakub Dawidek 			 */
4788abd1ad1SPawel Jakub Dawidek 			G_ELI_DEBUG(1, "Skipping configuration of not attached "
4798abd1ad1SPawel Jakub Dawidek 			    "provider %s.", prov);
4808abd1ad1SPawel Jakub Dawidek 			continue;
4818abd1ad1SPawel Jakub Dawidek 		}
4828abd1ad1SPawel Jakub Dawidek 		if (sc->sc_flags & G_ELI_FLAG_RO) {
4838abd1ad1SPawel Jakub Dawidek 			gctl_error(req, "Cannot change configuration of "
4848abd1ad1SPawel Jakub Dawidek 			    "read-only provider %s.", prov);
4858abd1ad1SPawel Jakub Dawidek 			continue;
4868abd1ad1SPawel Jakub Dawidek 		}
48746e34470SPawel Jakub Dawidek 
48846e34470SPawel Jakub Dawidek 		if (*boot && (sc->sc_flags & G_ELI_FLAG_BOOT)) {
48946e34470SPawel Jakub Dawidek 			G_ELI_DEBUG(1, "BOOT flag already configured for %s.",
49046e34470SPawel Jakub Dawidek 			    prov);
49146e34470SPawel Jakub Dawidek 			continue;
49246e34470SPawel Jakub Dawidek 		} else if (*noboot && !(sc->sc_flags & G_ELI_FLAG_BOOT)) {
49346e34470SPawel Jakub Dawidek 			G_ELI_DEBUG(1, "BOOT flag not configured for %s.",
49446e34470SPawel Jakub Dawidek 			    prov);
49546e34470SPawel Jakub Dawidek 			continue;
49646e34470SPawel Jakub Dawidek 		}
49746e34470SPawel Jakub Dawidek 
49846e34470SPawel Jakub Dawidek 		if (*notrim && (sc->sc_flags & G_ELI_FLAG_NODELETE)) {
49946e34470SPawel Jakub Dawidek 			G_ELI_DEBUG(1, "TRIM disable flag already configured for %s.",
50046e34470SPawel Jakub Dawidek 			    prov);
50146e34470SPawel Jakub Dawidek 			continue;
50246e34470SPawel Jakub Dawidek 		} else if (*trim && !(sc->sc_flags & G_ELI_FLAG_NODELETE)) {
50346e34470SPawel Jakub Dawidek 			G_ELI_DEBUG(1, "TRIM disable flag not configured for %s.",
50446e34470SPawel Jakub Dawidek 			    prov);
50546e34470SPawel Jakub Dawidek 			continue;
50646e34470SPawel Jakub Dawidek 		}
50746e34470SPawel Jakub Dawidek 
508d8736625SAllan Jude 		if (*geliboot && (sc->sc_flags & G_ELI_FLAG_GELIBOOT)) {
509d8736625SAllan Jude 			G_ELI_DEBUG(1, "GELIBOOT flag already configured for %s.",
510d8736625SAllan Jude 			    prov);
511d8736625SAllan Jude 			continue;
512d8736625SAllan Jude 		} else if (*nogeliboot && !(sc->sc_flags & G_ELI_FLAG_GELIBOOT)) {
513d8736625SAllan Jude 			G_ELI_DEBUG(1, "GELIBOOT flag not configured for %s.",
514d8736625SAllan Jude 			    prov);
515d8736625SAllan Jude 			continue;
516d8736625SAllan Jude 		}
517d8736625SAllan Jude 
5183453dc72SMariusz Zaborski 		if (*displaypass && (sc->sc_flags & G_ELI_FLAG_GELIDISPLAYPASS)) {
5193453dc72SMariusz Zaborski 			G_ELI_DEBUG(1, "GELIDISPLAYPASS flag already configured for %s.",
5203453dc72SMariusz Zaborski 			    prov);
5213453dc72SMariusz Zaborski 			continue;
5223453dc72SMariusz Zaborski 		} else if (*nodisplaypass &&
5233453dc72SMariusz Zaborski 		    !(sc->sc_flags & G_ELI_FLAG_GELIDISPLAYPASS)) {
5243453dc72SMariusz Zaborski 			G_ELI_DEBUG(1, "GELIDISPLAYPASS flag not configured for %s.",
5253453dc72SMariusz Zaborski 			    prov);
5263453dc72SMariusz Zaborski 			continue;
5273453dc72SMariusz Zaborski 		}
5283453dc72SMariusz Zaborski 
52946e34470SPawel Jakub Dawidek 		if (!(sc->sc_flags & G_ELI_FLAG_ONETIME)) {
53046e34470SPawel Jakub Dawidek 			/*
53146e34470SPawel Jakub Dawidek 			 * ONETIME providers don't write metadata to
53246e34470SPawel Jakub Dawidek 			 * disk, so don't try reading it.  This means
53346e34470SPawel Jakub Dawidek 			 * we're bit-flipping uninitialized memory in md
53446e34470SPawel Jakub Dawidek 			 * below, but that's OK; we don't do anything
53546e34470SPawel Jakub Dawidek 			 * with it later.
53646e34470SPawel Jakub Dawidek 			 */
5378abd1ad1SPawel Jakub Dawidek 			cp = LIST_FIRST(&sc->sc_geom->consumer);
5388abd1ad1SPawel Jakub Dawidek 			pp = cp->provider;
5398abd1ad1SPawel Jakub Dawidek 			error = g_eli_read_metadata(mp, pp, &md);
5408abd1ad1SPawel Jakub Dawidek 			if (error != 0) {
5418abd1ad1SPawel Jakub Dawidek 			    gctl_error(req,
5428abd1ad1SPawel Jakub Dawidek 				"Cannot read metadata from %s (error=%d).",
5438abd1ad1SPawel Jakub Dawidek 				prov, error);
5448abd1ad1SPawel Jakub Dawidek 			    continue;
5458abd1ad1SPawel Jakub Dawidek 			}
54646e34470SPawel Jakub Dawidek 		}
5478abd1ad1SPawel Jakub Dawidek 
5488abd1ad1SPawel Jakub Dawidek 		if (*boot) {
5498abd1ad1SPawel Jakub Dawidek 			md.md_flags |= G_ELI_FLAG_BOOT;
5508abd1ad1SPawel Jakub Dawidek 			sc->sc_flags |= G_ELI_FLAG_BOOT;
55146e34470SPawel Jakub Dawidek 		} else if (*noboot) {
5528abd1ad1SPawel Jakub Dawidek 			md.md_flags &= ~G_ELI_FLAG_BOOT;
5538abd1ad1SPawel Jakub Dawidek 			sc->sc_flags &= ~G_ELI_FLAG_BOOT;
5548abd1ad1SPawel Jakub Dawidek 		}
5558abd1ad1SPawel Jakub Dawidek 
55646e34470SPawel Jakub Dawidek 		if (*notrim) {
55746e34470SPawel Jakub Dawidek 			md.md_flags |= G_ELI_FLAG_NODELETE;
55846e34470SPawel Jakub Dawidek 			sc->sc_flags |= G_ELI_FLAG_NODELETE;
55946e34470SPawel Jakub Dawidek 		} else if (*trim) {
56046e34470SPawel Jakub Dawidek 			md.md_flags &= ~G_ELI_FLAG_NODELETE;
56146e34470SPawel Jakub Dawidek 			sc->sc_flags &= ~G_ELI_FLAG_NODELETE;
56246e34470SPawel Jakub Dawidek 		}
56346e34470SPawel Jakub Dawidek 
564d8736625SAllan Jude 		if (*geliboot) {
565d8736625SAllan Jude 			md.md_flags |= G_ELI_FLAG_GELIBOOT;
566d8736625SAllan Jude 			sc->sc_flags |= G_ELI_FLAG_GELIBOOT;
567d8736625SAllan Jude 		} else if (*nogeliboot) {
568d8736625SAllan Jude 			md.md_flags &= ~G_ELI_FLAG_GELIBOOT;
569d8736625SAllan Jude 			sc->sc_flags &= ~G_ELI_FLAG_GELIBOOT;
570d8736625SAllan Jude 		}
571d8736625SAllan Jude 
5723453dc72SMariusz Zaborski 		if (*displaypass) {
5733453dc72SMariusz Zaborski 			md.md_flags |= G_ELI_FLAG_GELIDISPLAYPASS;
5743453dc72SMariusz Zaborski 			sc->sc_flags |= G_ELI_FLAG_GELIDISPLAYPASS;
5753453dc72SMariusz Zaborski 		} else if (*nodisplaypass) {
5763453dc72SMariusz Zaborski 			md.md_flags &= ~G_ELI_FLAG_GELIDISPLAYPASS;
5773453dc72SMariusz Zaborski 			sc->sc_flags &= ~G_ELI_FLAG_GELIDISPLAYPASS;
5783453dc72SMariusz Zaborski 		}
5793453dc72SMariusz Zaborski 
58046e34470SPawel Jakub Dawidek 		if (sc->sc_flags & G_ELI_FLAG_ONETIME) {
58146e34470SPawel Jakub Dawidek 			/* There's no metadata on disk so we are done here. */
58246e34470SPawel Jakub Dawidek 			continue;
58346e34470SPawel Jakub Dawidek 		}
58446e34470SPawel Jakub Dawidek 
5858abd1ad1SPawel Jakub Dawidek 		sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
5868abd1ad1SPawel Jakub Dawidek 		eli_metadata_encode(&md, sector);
5878abd1ad1SPawel Jakub Dawidek 		error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
5888abd1ad1SPawel Jakub Dawidek 		    pp->sectorsize);
5898abd1ad1SPawel Jakub Dawidek 		if (error != 0) {
5908abd1ad1SPawel Jakub Dawidek 			gctl_error(req,
5918abd1ad1SPawel Jakub Dawidek 			    "Cannot store metadata on %s (error=%d).",
5928abd1ad1SPawel Jakub Dawidek 			    prov, error);
5938abd1ad1SPawel Jakub Dawidek 		}
59439b7ca45SAllan Jude 		explicit_bzero(&md, sizeof(md));
59539b7ca45SAllan Jude 		explicit_bzero(sector, pp->sectorsize);
5968abd1ad1SPawel Jakub Dawidek 		free(sector, M_ELI);
5978abd1ad1SPawel Jakub Dawidek 	}
5988abd1ad1SPawel Jakub Dawidek }
5998abd1ad1SPawel Jakub Dawidek 
6008abd1ad1SPawel Jakub Dawidek static void
601c58794deSPawel Jakub Dawidek g_eli_ctl_setkey(struct gctl_req *req, struct g_class *mp)
602c58794deSPawel Jakub Dawidek {
603c58794deSPawel Jakub Dawidek 	struct g_eli_softc *sc;
604c58794deSPawel Jakub Dawidek 	struct g_eli_metadata md;
605c58794deSPawel Jakub Dawidek 	struct g_provider *pp;
606c58794deSPawel Jakub Dawidek 	struct g_consumer *cp;
607c58794deSPawel Jakub Dawidek 	const char *name;
608c58794deSPawel Jakub Dawidek 	u_char *key, *mkeydst, *sector;
609c58794deSPawel Jakub Dawidek 	intmax_t *valp;
6107a5c26fcSPawel Jakub Dawidek 	int keysize, nkey, error;
611c58794deSPawel Jakub Dawidek 
612c58794deSPawel Jakub Dawidek 	g_topology_assert();
613c58794deSPawel Jakub Dawidek 
614c58794deSPawel Jakub Dawidek 	name = gctl_get_asciiparam(req, "arg0");
615c58794deSPawel Jakub Dawidek 	if (name == NULL) {
616c58794deSPawel Jakub Dawidek 		gctl_error(req, "No 'arg%u' argument.", 0);
617c58794deSPawel Jakub Dawidek 		return;
618c58794deSPawel Jakub Dawidek 	}
61939b7ca45SAllan Jude 	key = gctl_get_param(req, "key", &keysize);
62039b7ca45SAllan Jude 	if (key == NULL || keysize != G_ELI_USERKEYLEN) {
62139b7ca45SAllan Jude 		gctl_error(req, "No '%s' argument.", "key");
62239b7ca45SAllan Jude 		return;
62339b7ca45SAllan Jude 	}
624c58794deSPawel Jakub Dawidek 	sc = g_eli_find_device(mp, name);
625c58794deSPawel Jakub Dawidek 	if (sc == NULL) {
626c58794deSPawel Jakub Dawidek 		gctl_error(req, "Provider %s is invalid.", name);
627c58794deSPawel Jakub Dawidek 		return;
628c58794deSPawel Jakub Dawidek 	}
62985059016SPawel Jakub Dawidek 	if (sc->sc_flags & G_ELI_FLAG_RO) {
63085059016SPawel Jakub Dawidek 		gctl_error(req, "Cannot change keys for read-only provider.");
63185059016SPawel Jakub Dawidek 		return;
63285059016SPawel Jakub Dawidek 	}
633c58794deSPawel Jakub Dawidek 	cp = LIST_FIRST(&sc->sc_geom->consumer);
634c58794deSPawel Jakub Dawidek 	pp = cp->provider;
635c58794deSPawel Jakub Dawidek 
636c58794deSPawel Jakub Dawidek 	error = g_eli_read_metadata(mp, pp, &md);
637c58794deSPawel Jakub Dawidek 	if (error != 0) {
638c58794deSPawel Jakub Dawidek 		gctl_error(req, "Cannot read metadata from %s (error=%d).",
639c58794deSPawel Jakub Dawidek 		    name, error);
640c58794deSPawel Jakub Dawidek 		return;
641c58794deSPawel Jakub Dawidek 	}
642c58794deSPawel Jakub Dawidek 
643c58794deSPawel Jakub Dawidek 	valp = gctl_get_paraml(req, "keyno", sizeof(*valp));
644c58794deSPawel Jakub Dawidek 	if (valp == NULL) {
645c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "keyno");
646c58794deSPawel Jakub Dawidek 		return;
647c58794deSPawel Jakub Dawidek 	}
648c58794deSPawel Jakub Dawidek 	if (*valp != -1)
649c58794deSPawel Jakub Dawidek 		nkey = *valp;
650c58794deSPawel Jakub Dawidek 	else
651c58794deSPawel Jakub Dawidek 		nkey = sc->sc_nkey;
652c58794deSPawel Jakub Dawidek 	if (nkey < 0 || nkey >= G_ELI_MAXMKEYS) {
653c58794deSPawel Jakub Dawidek 		gctl_error(req, "Invalid '%s' argument.", "keyno");
654c58794deSPawel Jakub Dawidek 		return;
655c58794deSPawel Jakub Dawidek 	}
656c58794deSPawel Jakub Dawidek 
6577a5c26fcSPawel Jakub Dawidek 	valp = gctl_get_paraml(req, "iterations", sizeof(*valp));
6587a5c26fcSPawel Jakub Dawidek 	if (valp == NULL) {
6597a5c26fcSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "iterations");
6607a5c26fcSPawel Jakub Dawidek 		return;
6617a5c26fcSPawel Jakub Dawidek 	}
6627a5c26fcSPawel Jakub Dawidek 	/* Check if iterations number should and can be changed. */
663d8880fd4SAlexander Motin 	if (*valp != -1 && md.md_iterations == -1) {
664d8880fd4SAlexander Motin 		md.md_iterations = *valp;
665d8880fd4SAlexander Motin 	} else if (*valp != -1 && *valp != md.md_iterations) {
6667a5c26fcSPawel Jakub Dawidek 		if (bitcount32(md.md_keys) != 1) {
6677a5c26fcSPawel Jakub Dawidek 			gctl_error(req, "To be able to use '-i' option, only "
6687a5c26fcSPawel Jakub Dawidek 			    "one key can be defined.");
6697a5c26fcSPawel Jakub Dawidek 			return;
6707a5c26fcSPawel Jakub Dawidek 		}
6717a5c26fcSPawel Jakub Dawidek 		if (md.md_keys != (1 << nkey)) {
6727a5c26fcSPawel Jakub Dawidek 			gctl_error(req, "Only already defined key can be "
6737a5c26fcSPawel Jakub Dawidek 			    "changed when '-i' option is used.");
6747a5c26fcSPawel Jakub Dawidek 			return;
6757a5c26fcSPawel Jakub Dawidek 		}
6767a5c26fcSPawel Jakub Dawidek 		md.md_iterations = *valp;
6777a5c26fcSPawel Jakub Dawidek 	}
6787a5c26fcSPawel Jakub Dawidek 
679c58794deSPawel Jakub Dawidek 	mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
680c58794deSPawel Jakub Dawidek 	md.md_keys |= (1 << nkey);
681c58794deSPawel Jakub Dawidek 
682eaa3b919SPawel Jakub Dawidek 	bcopy(sc->sc_mkey, mkeydst, sizeof(sc->sc_mkey));
683c58794deSPawel Jakub Dawidek 
684c58794deSPawel Jakub Dawidek 	/* Encrypt Master Key with the new key. */
685eaa3b919SPawel Jakub Dawidek 	error = g_eli_mkey_encrypt(md.md_ealgo, key, md.md_keylen, mkeydst);
68639b7ca45SAllan Jude 	explicit_bzero(key, keysize);
687c58794deSPawel Jakub Dawidek 	if (error != 0) {
68839b7ca45SAllan Jude 		explicit_bzero(&md, sizeof(md));
689c58794deSPawel Jakub Dawidek 		gctl_error(req, "Cannot encrypt Master Key (error=%d).", error);
690c58794deSPawel Jakub Dawidek 		return;
691c58794deSPawel Jakub Dawidek 	}
692c58794deSPawel Jakub Dawidek 
693c58794deSPawel Jakub Dawidek 	sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
694c58794deSPawel Jakub Dawidek 	/* Store metadata with fresh key. */
695c58794deSPawel Jakub Dawidek 	eli_metadata_encode(&md, sector);
69639b7ca45SAllan Jude 	explicit_bzero(&md, sizeof(md));
697c58794deSPawel Jakub Dawidek 	error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
698c58794deSPawel Jakub Dawidek 	    pp->sectorsize);
69939b7ca45SAllan Jude 	explicit_bzero(sector, pp->sectorsize);
700c58794deSPawel Jakub Dawidek 	free(sector, M_ELI);
701c58794deSPawel Jakub Dawidek 	if (error != 0) {
702c58794deSPawel Jakub Dawidek 		gctl_error(req, "Cannot store metadata on %s (error=%d).",
703c58794deSPawel Jakub Dawidek 		    pp->name, error);
704c58794deSPawel Jakub Dawidek 		return;
705c58794deSPawel Jakub Dawidek 	}
706c58794deSPawel Jakub Dawidek 	G_ELI_DEBUG(1, "Key %u changed on %s.", nkey, pp->name);
707c58794deSPawel Jakub Dawidek }
708c58794deSPawel Jakub Dawidek 
709c58794deSPawel Jakub Dawidek static void
710c58794deSPawel Jakub Dawidek g_eli_ctl_delkey(struct gctl_req *req, struct g_class *mp)
711c58794deSPawel Jakub Dawidek {
712c58794deSPawel Jakub Dawidek 	struct g_eli_softc *sc;
713c58794deSPawel Jakub Dawidek 	struct g_eli_metadata md;
714c58794deSPawel Jakub Dawidek 	struct g_provider *pp;
715c58794deSPawel Jakub Dawidek 	struct g_consumer *cp;
716c58794deSPawel Jakub Dawidek 	const char *name;
717c58794deSPawel Jakub Dawidek 	u_char *mkeydst, *sector;
718c58794deSPawel Jakub Dawidek 	intmax_t *valp;
719c58794deSPawel Jakub Dawidek 	size_t keysize;
720c58794deSPawel Jakub Dawidek 	int error, nkey, *all, *force;
721c58794deSPawel Jakub Dawidek 	u_int i;
722c58794deSPawel Jakub Dawidek 
723c58794deSPawel Jakub Dawidek 	g_topology_assert();
724c58794deSPawel Jakub Dawidek 
725c58794deSPawel Jakub Dawidek 	nkey = 0;	/* fixes causeless gcc warning */
726c58794deSPawel Jakub Dawidek 
727c58794deSPawel Jakub Dawidek 	name = gctl_get_asciiparam(req, "arg0");
728c58794deSPawel Jakub Dawidek 	if (name == NULL) {
729c58794deSPawel Jakub Dawidek 		gctl_error(req, "No 'arg%u' argument.", 0);
730c58794deSPawel Jakub Dawidek 		return;
731c58794deSPawel Jakub Dawidek 	}
732c58794deSPawel Jakub Dawidek 	sc = g_eli_find_device(mp, name);
733c58794deSPawel Jakub Dawidek 	if (sc == NULL) {
734c58794deSPawel Jakub Dawidek 		gctl_error(req, "Provider %s is invalid.", name);
735c58794deSPawel Jakub Dawidek 		return;
736c58794deSPawel Jakub Dawidek 	}
73785059016SPawel Jakub Dawidek 	if (sc->sc_flags & G_ELI_FLAG_RO) {
73885059016SPawel Jakub Dawidek 		gctl_error(req, "Cannot delete keys for read-only provider.");
73985059016SPawel Jakub Dawidek 		return;
74085059016SPawel Jakub Dawidek 	}
741c58794deSPawel Jakub Dawidek 	cp = LIST_FIRST(&sc->sc_geom->consumer);
742c58794deSPawel Jakub Dawidek 	pp = cp->provider;
743c58794deSPawel Jakub Dawidek 
744c58794deSPawel Jakub Dawidek 	error = g_eli_read_metadata(mp, pp, &md);
745c58794deSPawel Jakub Dawidek 	if (error != 0) {
746c58794deSPawel Jakub Dawidek 		gctl_error(req, "Cannot read metadata from %s (error=%d).",
747c58794deSPawel Jakub Dawidek 		    name, error);
748c58794deSPawel Jakub Dawidek 		return;
749c58794deSPawel Jakub Dawidek 	}
750c58794deSPawel Jakub Dawidek 
751c58794deSPawel Jakub Dawidek 	all = gctl_get_paraml(req, "all", sizeof(*all));
752c58794deSPawel Jakub Dawidek 	if (all == NULL) {
753c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "all");
754c58794deSPawel Jakub Dawidek 		return;
755c58794deSPawel Jakub Dawidek 	}
756c58794deSPawel Jakub Dawidek 
757c58794deSPawel Jakub Dawidek 	if (*all) {
758c58794deSPawel Jakub Dawidek 		mkeydst = md.md_mkeys;
759c58794deSPawel Jakub Dawidek 		keysize = sizeof(md.md_mkeys);
760c58794deSPawel Jakub Dawidek 	} else {
761c58794deSPawel Jakub Dawidek 		force = gctl_get_paraml(req, "force", sizeof(*force));
762c58794deSPawel Jakub Dawidek 		if (force == NULL) {
763c58794deSPawel Jakub Dawidek 			gctl_error(req, "No '%s' argument.", "force");
764c58794deSPawel Jakub Dawidek 			return;
765c58794deSPawel Jakub Dawidek 		}
766c58794deSPawel Jakub Dawidek 
767c58794deSPawel Jakub Dawidek 		valp = gctl_get_paraml(req, "keyno", sizeof(*valp));
768c58794deSPawel Jakub Dawidek 		if (valp == NULL) {
769c58794deSPawel Jakub Dawidek 			gctl_error(req, "No '%s' argument.", "keyno");
770c58794deSPawel Jakub Dawidek 			return;
771c58794deSPawel Jakub Dawidek 		}
772c58794deSPawel Jakub Dawidek 		if (*valp != -1)
773c58794deSPawel Jakub Dawidek 			nkey = *valp;
774c58794deSPawel Jakub Dawidek 		else
775c58794deSPawel Jakub Dawidek 			nkey = sc->sc_nkey;
776c58794deSPawel Jakub Dawidek 		if (nkey < 0 || nkey >= G_ELI_MAXMKEYS) {
777c58794deSPawel Jakub Dawidek 			gctl_error(req, "Invalid '%s' argument.", "keyno");
778c58794deSPawel Jakub Dawidek 			return;
779c58794deSPawel Jakub Dawidek 		}
780c58794deSPawel Jakub Dawidek 		if (!(md.md_keys & (1 << nkey)) && !*force) {
781c58794deSPawel Jakub Dawidek 			gctl_error(req, "Master Key %u is not set.", nkey);
782c58794deSPawel Jakub Dawidek 			return;
783c58794deSPawel Jakub Dawidek 		}
784c58794deSPawel Jakub Dawidek 		md.md_keys &= ~(1 << nkey);
785c58794deSPawel Jakub Dawidek 		if (md.md_keys == 0 && !*force) {
786c58794deSPawel Jakub Dawidek 			gctl_error(req, "This is the last Master Key. Use '-f' "
787c58794deSPawel Jakub Dawidek 			    "flag if you really want to remove it.");
788c58794deSPawel Jakub Dawidek 			return;
789c58794deSPawel Jakub Dawidek 		}
790c58794deSPawel Jakub Dawidek 		mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
791c58794deSPawel Jakub Dawidek 		keysize = G_ELI_MKEYLEN;
792c58794deSPawel Jakub Dawidek 	}
793c58794deSPawel Jakub Dawidek 
794c58794deSPawel Jakub Dawidek 	sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
795c58794deSPawel Jakub Dawidek 	for (i = 0; i <= g_eli_overwrites; i++) {
796c58794deSPawel Jakub Dawidek 		if (i == g_eli_overwrites)
79739b7ca45SAllan Jude 			explicit_bzero(mkeydst, keysize);
798c58794deSPawel Jakub Dawidek 		else
799c58794deSPawel Jakub Dawidek 			arc4rand(mkeydst, keysize, 0);
800c58794deSPawel Jakub Dawidek 		/* Store metadata with destroyed key. */
801c58794deSPawel Jakub Dawidek 		eli_metadata_encode(&md, sector);
802c58794deSPawel Jakub Dawidek 		error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
803c58794deSPawel Jakub Dawidek 		    pp->sectorsize);
804c58794deSPawel Jakub Dawidek 		if (error != 0) {
805c58794deSPawel Jakub Dawidek 			G_ELI_DEBUG(0, "Cannot store metadata on %s "
806c58794deSPawel Jakub Dawidek 			    "(error=%d).", pp->name, error);
807c58794deSPawel Jakub Dawidek 		}
808f0256e71SPawel Jakub Dawidek 		/*
809f0256e71SPawel Jakub Dawidek 		 * Flush write cache so we don't overwrite data N times in cache
810f0256e71SPawel Jakub Dawidek 		 * and only once on disk.
811f0256e71SPawel Jakub Dawidek 		 */
812350e8df8SPawel Jakub Dawidek 		(void)g_io_flush(cp);
813c58794deSPawel Jakub Dawidek 	}
81439b7ca45SAllan Jude 	explicit_bzero(&md, sizeof(md));
81539b7ca45SAllan Jude 	explicit_bzero(sector, pp->sectorsize);
816c58794deSPawel Jakub Dawidek 	free(sector, M_ELI);
817c58794deSPawel Jakub Dawidek 	if (*all)
818c58794deSPawel Jakub Dawidek 		G_ELI_DEBUG(1, "All keys removed from %s.", pp->name);
819c58794deSPawel Jakub Dawidek 	else
820c58794deSPawel Jakub Dawidek 		G_ELI_DEBUG(1, "Key %d removed from %s.", nkey, pp->name);
821c58794deSPawel Jakub Dawidek }
822c58794deSPawel Jakub Dawidek 
8230d2f5a4eSPawel Jakub Dawidek static void
8240d2f5a4eSPawel Jakub Dawidek g_eli_suspend_one(struct g_eli_softc *sc, struct gctl_req *req)
8255ad4a7c7SPawel Jakub Dawidek {
8265ad4a7c7SPawel Jakub Dawidek 	struct g_eli_worker *wr;
8275ad4a7c7SPawel Jakub Dawidek 
8285ad4a7c7SPawel Jakub Dawidek 	g_topology_assert();
8295ad4a7c7SPawel Jakub Dawidek 
8300d2f5a4eSPawel Jakub Dawidek 	KASSERT(sc != NULL, ("NULL sc"));
8310d2f5a4eSPawel Jakub Dawidek 
8320d2f5a4eSPawel Jakub Dawidek 	if (sc->sc_flags & G_ELI_FLAG_ONETIME) {
8330d2f5a4eSPawel Jakub Dawidek 		gctl_error(req,
8340d2f5a4eSPawel Jakub Dawidek 		    "Device %s is using one-time key, suspend not supported.",
8350d2f5a4eSPawel Jakub Dawidek 		    sc->sc_name);
8360d2f5a4eSPawel Jakub Dawidek 		return;
8370d2f5a4eSPawel Jakub Dawidek 	}
8385ad4a7c7SPawel Jakub Dawidek 
8395ad4a7c7SPawel Jakub Dawidek 	mtx_lock(&sc->sc_queue_mtx);
8405ad4a7c7SPawel Jakub Dawidek 	if (sc->sc_flags & G_ELI_FLAG_SUSPEND) {
8415ad4a7c7SPawel Jakub Dawidek 		mtx_unlock(&sc->sc_queue_mtx);
8420d2f5a4eSPawel Jakub Dawidek 		gctl_error(req, "Device %s already suspended.",
8430d2f5a4eSPawel Jakub Dawidek 		    sc->sc_name);
8440d2f5a4eSPawel Jakub Dawidek 		return;
8455ad4a7c7SPawel Jakub Dawidek 	}
8465ad4a7c7SPawel Jakub Dawidek 	sc->sc_flags |= G_ELI_FLAG_SUSPEND;
8475ad4a7c7SPawel Jakub Dawidek 	wakeup(sc);
8485ad4a7c7SPawel Jakub Dawidek 	for (;;) {
8495ad4a7c7SPawel Jakub Dawidek 		LIST_FOREACH(wr, &sc->sc_workers, w_next) {
8505ad4a7c7SPawel Jakub Dawidek 			if (wr->w_active)
8515ad4a7c7SPawel Jakub Dawidek 				break;
8525ad4a7c7SPawel Jakub Dawidek 		}
8535ad4a7c7SPawel Jakub Dawidek 		if (wr == NULL)
8545ad4a7c7SPawel Jakub Dawidek 			break;
8555ad4a7c7SPawel Jakub Dawidek 		/* Not all threads suspended. */
8565ad4a7c7SPawel Jakub Dawidek 		msleep(&sc->sc_workers, &sc->sc_queue_mtx, PRIBIO,
8575ad4a7c7SPawel Jakub Dawidek 		    "geli:suspend", 0);
8585ad4a7c7SPawel Jakub Dawidek 	}
8595ad4a7c7SPawel Jakub Dawidek 	/*
8605ad4a7c7SPawel Jakub Dawidek 	 * Clear sensitive data on suspend, they will be recovered on resume.
8615ad4a7c7SPawel Jakub Dawidek 	 */
86239b7ca45SAllan Jude 	explicit_bzero(sc->sc_mkey, sizeof(sc->sc_mkey));
8631e09ff3dSPawel Jakub Dawidek 	g_eli_key_destroy(sc);
86439b7ca45SAllan Jude 	explicit_bzero(sc->sc_akey, sizeof(sc->sc_akey));
86539b7ca45SAllan Jude 	explicit_bzero(&sc->sc_akeyctx, sizeof(sc->sc_akeyctx));
86639b7ca45SAllan Jude 	explicit_bzero(sc->sc_ivkey, sizeof(sc->sc_ivkey));
86739b7ca45SAllan Jude 	explicit_bzero(&sc->sc_ivctx, sizeof(sc->sc_ivctx));
8685ad4a7c7SPawel Jakub Dawidek 	mtx_unlock(&sc->sc_queue_mtx);
8690d2f5a4eSPawel Jakub Dawidek 	G_ELI_DEBUG(0, "Device %s has been suspended.", sc->sc_name);
8705ad4a7c7SPawel Jakub Dawidek }
8715ad4a7c7SPawel Jakub Dawidek 
8725ad4a7c7SPawel Jakub Dawidek static void
8735ad4a7c7SPawel Jakub Dawidek g_eli_ctl_suspend(struct gctl_req *req, struct g_class *mp)
8745ad4a7c7SPawel Jakub Dawidek {
8755ad4a7c7SPawel Jakub Dawidek 	struct g_eli_softc *sc;
8765ad4a7c7SPawel Jakub Dawidek 	int *all, *nargs;
8775ad4a7c7SPawel Jakub Dawidek 
8785ad4a7c7SPawel Jakub Dawidek 	g_topology_assert();
8795ad4a7c7SPawel Jakub Dawidek 
8805ad4a7c7SPawel Jakub Dawidek 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
8815ad4a7c7SPawel Jakub Dawidek 	if (nargs == NULL) {
8825ad4a7c7SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "nargs");
8835ad4a7c7SPawel Jakub Dawidek 		return;
8845ad4a7c7SPawel Jakub Dawidek 	}
8855ad4a7c7SPawel Jakub Dawidek 	all = gctl_get_paraml(req, "all", sizeof(*all));
8865ad4a7c7SPawel Jakub Dawidek 	if (all == NULL) {
8875ad4a7c7SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "all");
8885ad4a7c7SPawel Jakub Dawidek 		return;
8895ad4a7c7SPawel Jakub Dawidek 	}
8905ad4a7c7SPawel Jakub Dawidek 	if (!*all && *nargs == 0) {
8915ad4a7c7SPawel Jakub Dawidek 		gctl_error(req, "Too few arguments.");
8925ad4a7c7SPawel Jakub Dawidek 		return;
8935ad4a7c7SPawel Jakub Dawidek 	}
8945ad4a7c7SPawel Jakub Dawidek 
8955ad4a7c7SPawel Jakub Dawidek 	if (*all) {
8965ad4a7c7SPawel Jakub Dawidek 		struct g_geom *gp, *gp2;
8975ad4a7c7SPawel Jakub Dawidek 
8985ad4a7c7SPawel Jakub Dawidek 		LIST_FOREACH_SAFE(gp, &mp->geom, geom, gp2) {
8995ad4a7c7SPawel Jakub Dawidek 			sc = gp->softc;
9000d2f5a4eSPawel Jakub Dawidek 			if (sc->sc_flags & G_ELI_FLAG_ONETIME) {
9010d2f5a4eSPawel Jakub Dawidek 				G_ELI_DEBUG(0,
9020d2f5a4eSPawel Jakub Dawidek 				    "Device %s is using one-time key, suspend not supported, skipping.",
9030d2f5a4eSPawel Jakub Dawidek 				    sc->sc_name);
9045ad4a7c7SPawel Jakub Dawidek 				continue;
9050d2f5a4eSPawel Jakub Dawidek 			}
9060d2f5a4eSPawel Jakub Dawidek 			g_eli_suspend_one(sc, req);
9075ad4a7c7SPawel Jakub Dawidek 		}
9085ad4a7c7SPawel Jakub Dawidek 	} else {
9095ad4a7c7SPawel Jakub Dawidek 		const char *prov;
9105ad4a7c7SPawel Jakub Dawidek 		char param[16];
9115ad4a7c7SPawel Jakub Dawidek 		int i;
9125ad4a7c7SPawel Jakub Dawidek 
9135ad4a7c7SPawel Jakub Dawidek 		for (i = 0; i < *nargs; i++) {
9145ad4a7c7SPawel Jakub Dawidek 			snprintf(param, sizeof(param), "arg%d", i);
9155ad4a7c7SPawel Jakub Dawidek 			prov = gctl_get_asciiparam(req, param);
9165ad4a7c7SPawel Jakub Dawidek 			if (prov == NULL) {
9175ad4a7c7SPawel Jakub Dawidek 				G_ELI_DEBUG(0, "No 'arg%d' argument.", i);
9185ad4a7c7SPawel Jakub Dawidek 				continue;
9195ad4a7c7SPawel Jakub Dawidek 			}
9205ad4a7c7SPawel Jakub Dawidek 
9215ad4a7c7SPawel Jakub Dawidek 			sc = g_eli_find_device(mp, prov);
9225ad4a7c7SPawel Jakub Dawidek 			if (sc == NULL) {
9235ad4a7c7SPawel Jakub Dawidek 				G_ELI_DEBUG(0, "No such provider: %s.", prov);
9245ad4a7c7SPawel Jakub Dawidek 				continue;
9255ad4a7c7SPawel Jakub Dawidek 			}
9260d2f5a4eSPawel Jakub Dawidek 			g_eli_suspend_one(sc, req);
9275ad4a7c7SPawel Jakub Dawidek 		}
9285ad4a7c7SPawel Jakub Dawidek 	}
9295ad4a7c7SPawel Jakub Dawidek }
9305ad4a7c7SPawel Jakub Dawidek 
9315ad4a7c7SPawel Jakub Dawidek static void
9325ad4a7c7SPawel Jakub Dawidek g_eli_ctl_resume(struct gctl_req *req, struct g_class *mp)
9335ad4a7c7SPawel Jakub Dawidek {
9345ad4a7c7SPawel Jakub Dawidek 	struct g_eli_metadata md;
9355ad4a7c7SPawel Jakub Dawidek 	struct g_eli_softc *sc;
9365ad4a7c7SPawel Jakub Dawidek 	struct g_provider *pp;
9375ad4a7c7SPawel Jakub Dawidek 	struct g_consumer *cp;
9385ad4a7c7SPawel Jakub Dawidek 	const char *name;
9395ad4a7c7SPawel Jakub Dawidek 	u_char *key, mkey[G_ELI_DATAIVKEYLEN];
9405ad4a7c7SPawel Jakub Dawidek 	int *nargs, keysize, error;
9415ad4a7c7SPawel Jakub Dawidek 	u_int nkey;
9425ad4a7c7SPawel Jakub Dawidek 
9435ad4a7c7SPawel Jakub Dawidek 	g_topology_assert();
9445ad4a7c7SPawel Jakub Dawidek 
9455ad4a7c7SPawel Jakub Dawidek 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
9465ad4a7c7SPawel Jakub Dawidek 	if (nargs == NULL) {
9475ad4a7c7SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "nargs");
9485ad4a7c7SPawel Jakub Dawidek 		return;
9495ad4a7c7SPawel Jakub Dawidek 	}
9505ad4a7c7SPawel Jakub Dawidek 	if (*nargs != 1) {
9515ad4a7c7SPawel Jakub Dawidek 		gctl_error(req, "Invalid number of arguments.");
9525ad4a7c7SPawel Jakub Dawidek 		return;
9535ad4a7c7SPawel Jakub Dawidek 	}
9545ad4a7c7SPawel Jakub Dawidek 
9555ad4a7c7SPawel Jakub Dawidek 	name = gctl_get_asciiparam(req, "arg0");
9565ad4a7c7SPawel Jakub Dawidek 	if (name == NULL) {
9575ad4a7c7SPawel Jakub Dawidek 		gctl_error(req, "No 'arg%u' argument.", 0);
9585ad4a7c7SPawel Jakub Dawidek 		return;
9595ad4a7c7SPawel Jakub Dawidek 	}
96039b7ca45SAllan Jude 	key = gctl_get_param(req, "key", &keysize);
96139b7ca45SAllan Jude 	if (key == NULL || keysize != G_ELI_USERKEYLEN) {
96239b7ca45SAllan Jude 		gctl_error(req, "No '%s' argument.", "key");
96339b7ca45SAllan Jude 		return;
96439b7ca45SAllan Jude 	}
9655ad4a7c7SPawel Jakub Dawidek 	sc = g_eli_find_device(mp, name);
9665ad4a7c7SPawel Jakub Dawidek 	if (sc == NULL) {
9675ad4a7c7SPawel Jakub Dawidek 		gctl_error(req, "Provider %s is invalid.", name);
9685ad4a7c7SPawel Jakub Dawidek 		return;
9695ad4a7c7SPawel Jakub Dawidek 	}
9705ad4a7c7SPawel Jakub Dawidek 	cp = LIST_FIRST(&sc->sc_geom->consumer);
9715ad4a7c7SPawel Jakub Dawidek 	pp = cp->provider;
9725ad4a7c7SPawel Jakub Dawidek 	error = g_eli_read_metadata(mp, pp, &md);
9735ad4a7c7SPawel Jakub Dawidek 	if (error != 0) {
9745ad4a7c7SPawel Jakub Dawidek 		gctl_error(req, "Cannot read metadata from %s (error=%d).",
9755ad4a7c7SPawel Jakub Dawidek 		    name, error);
9765ad4a7c7SPawel Jakub Dawidek 		return;
9775ad4a7c7SPawel Jakub Dawidek 	}
9785ad4a7c7SPawel Jakub Dawidek 	if (md.md_keys == 0x00) {
97939b7ca45SAllan Jude 		explicit_bzero(&md, sizeof(md));
9805ad4a7c7SPawel Jakub Dawidek 		gctl_error(req, "No valid keys on %s.", pp->name);
9815ad4a7c7SPawel Jakub Dawidek 		return;
9825ad4a7c7SPawel Jakub Dawidek 	}
9835ad4a7c7SPawel Jakub Dawidek 
9845ad4a7c7SPawel Jakub Dawidek 	error = g_eli_mkey_decrypt(&md, key, mkey, &nkey);
98539b7ca45SAllan Jude 	explicit_bzero(key, keysize);
9865ad4a7c7SPawel Jakub Dawidek 	if (error == -1) {
98739b7ca45SAllan Jude 		explicit_bzero(&md, sizeof(md));
9885ad4a7c7SPawel Jakub Dawidek 		gctl_error(req, "Wrong key for %s.", pp->name);
9895ad4a7c7SPawel Jakub Dawidek 		return;
9905ad4a7c7SPawel Jakub Dawidek 	} else if (error > 0) {
99139b7ca45SAllan Jude 		explicit_bzero(&md, sizeof(md));
9925ad4a7c7SPawel Jakub Dawidek 		gctl_error(req, "Cannot decrypt Master Key for %s (error=%d).",
9935ad4a7c7SPawel Jakub Dawidek 		    pp->name, error);
9945ad4a7c7SPawel Jakub Dawidek 		return;
9955ad4a7c7SPawel Jakub Dawidek 	}
9965ad4a7c7SPawel Jakub Dawidek 	G_ELI_DEBUG(1, "Using Master Key %u for %s.", nkey, pp->name);
9975ad4a7c7SPawel Jakub Dawidek 
9985ad4a7c7SPawel Jakub Dawidek 	mtx_lock(&sc->sc_queue_mtx);
9992f2d7830SPawel Jakub Dawidek 	if (!(sc->sc_flags & G_ELI_FLAG_SUSPEND))
10002f2d7830SPawel Jakub Dawidek 		gctl_error(req, "Device %s is not suspended.", name);
10012f2d7830SPawel Jakub Dawidek 	else {
10025ad4a7c7SPawel Jakub Dawidek 		/* Restore sc_mkey, sc_ekeys, sc_akey and sc_ivkey. */
10035ad4a7c7SPawel Jakub Dawidek 		g_eli_mkey_propagate(sc, mkey);
10045ad4a7c7SPawel Jakub Dawidek 		sc->sc_flags &= ~G_ELI_FLAG_SUSPEND;
10052f2d7830SPawel Jakub Dawidek 		G_ELI_DEBUG(1, "Resumed %s.", pp->name);
10062f2d7830SPawel Jakub Dawidek 		wakeup(sc);
10072f2d7830SPawel Jakub Dawidek 	}
10085ad4a7c7SPawel Jakub Dawidek 	mtx_unlock(&sc->sc_queue_mtx);
100939b7ca45SAllan Jude 	explicit_bzero(mkey, sizeof(mkey));
101039b7ca45SAllan Jude 	explicit_bzero(&md, sizeof(md));
10115ad4a7c7SPawel Jakub Dawidek }
10125ad4a7c7SPawel Jakub Dawidek 
10135ad4a7c7SPawel Jakub Dawidek static int
1014c58794deSPawel Jakub Dawidek g_eli_kill_one(struct g_eli_softc *sc)
1015c58794deSPawel Jakub Dawidek {
1016c58794deSPawel Jakub Dawidek 	struct g_provider *pp;
1017c58794deSPawel Jakub Dawidek 	struct g_consumer *cp;
101885059016SPawel Jakub Dawidek 	int error = 0;
1019c58794deSPawel Jakub Dawidek 
1020c58794deSPawel Jakub Dawidek 	g_topology_assert();
1021c58794deSPawel Jakub Dawidek 
1022c58794deSPawel Jakub Dawidek 	if (sc == NULL)
1023c58794deSPawel Jakub Dawidek 		return (ENOENT);
1024c58794deSPawel Jakub Dawidek 
1025c58794deSPawel Jakub Dawidek 	pp = LIST_FIRST(&sc->sc_geom->provider);
1026c58794deSPawel Jakub Dawidek 	g_error_provider(pp, ENXIO);
1027c58794deSPawel Jakub Dawidek 
1028c58794deSPawel Jakub Dawidek 	cp = LIST_FIRST(&sc->sc_geom->consumer);
1029c58794deSPawel Jakub Dawidek 	pp = cp->provider;
1030c58794deSPawel Jakub Dawidek 
103185059016SPawel Jakub Dawidek 	if (sc->sc_flags & G_ELI_FLAG_RO) {
103285059016SPawel Jakub Dawidek 		G_ELI_DEBUG(0, "WARNING: Metadata won't be erased on read-only "
103385059016SPawel Jakub Dawidek 		    "provider: %s.", pp->name);
103485059016SPawel Jakub Dawidek 	} else {
103585059016SPawel Jakub Dawidek 		u_char *sector;
103685059016SPawel Jakub Dawidek 		u_int i;
103785059016SPawel Jakub Dawidek 		int err;
103885059016SPawel Jakub Dawidek 
1039c58794deSPawel Jakub Dawidek 		sector = malloc(pp->sectorsize, M_ELI, M_WAITOK);
1040c58794deSPawel Jakub Dawidek 		for (i = 0; i <= g_eli_overwrites; i++) {
1041c58794deSPawel Jakub Dawidek 			if (i == g_eli_overwrites)
1042c58794deSPawel Jakub Dawidek 				bzero(sector, pp->sectorsize);
1043c58794deSPawel Jakub Dawidek 			else
1044c58794deSPawel Jakub Dawidek 				arc4rand(sector, pp->sectorsize, 0);
104585059016SPawel Jakub Dawidek 			err = g_write_data(cp, pp->mediasize - pp->sectorsize,
104685059016SPawel Jakub Dawidek 			    sector, pp->sectorsize);
1047c58794deSPawel Jakub Dawidek 			if (err != 0) {
1048c58794deSPawel Jakub Dawidek 				G_ELI_DEBUG(0, "Cannot erase metadata on %s "
1049c58794deSPawel Jakub Dawidek 				    "(error=%d).", pp->name, err);
1050c58794deSPawel Jakub Dawidek 				if (error == 0)
1051c58794deSPawel Jakub Dawidek 					error = err;
1052c58794deSPawel Jakub Dawidek 			}
1053350e8df8SPawel Jakub Dawidek 			/*
1054350e8df8SPawel Jakub Dawidek 			 * Flush write cache so we don't overwrite data N times
1055350e8df8SPawel Jakub Dawidek 			 * in cache and only once on disk.
1056350e8df8SPawel Jakub Dawidek 			 */
1057350e8df8SPawel Jakub Dawidek 			(void)g_io_flush(cp);
1058c58794deSPawel Jakub Dawidek 		}
1059c58794deSPawel Jakub Dawidek 		free(sector, M_ELI);
106085059016SPawel Jakub Dawidek 	}
1061c58794deSPawel Jakub Dawidek 	if (error == 0)
1062c58794deSPawel Jakub Dawidek 		G_ELI_DEBUG(0, "%s has been killed.", pp->name);
10635ad4a7c7SPawel Jakub Dawidek 	g_eli_destroy(sc, TRUE);
1064c58794deSPawel Jakub Dawidek 	return (error);
1065c58794deSPawel Jakub Dawidek }
1066c58794deSPawel Jakub Dawidek 
1067c58794deSPawel Jakub Dawidek static void
1068c58794deSPawel Jakub Dawidek g_eli_ctl_kill(struct gctl_req *req, struct g_class *mp)
1069c58794deSPawel Jakub Dawidek {
1070c58794deSPawel Jakub Dawidek 	int *all, *nargs;
1071c58794deSPawel Jakub Dawidek 	int error;
1072c58794deSPawel Jakub Dawidek 
1073c58794deSPawel Jakub Dawidek 	g_topology_assert();
1074c58794deSPawel Jakub Dawidek 
1075c58794deSPawel Jakub Dawidek 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
1076c58794deSPawel Jakub Dawidek 	if (nargs == NULL) {
1077c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "nargs");
1078c58794deSPawel Jakub Dawidek 		return;
1079c58794deSPawel Jakub Dawidek 	}
1080c58794deSPawel Jakub Dawidek 	all = gctl_get_paraml(req, "all", sizeof(*all));
1081c58794deSPawel Jakub Dawidek 	if (all == NULL) {
1082c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "all");
1083c58794deSPawel Jakub Dawidek 		return;
1084c58794deSPawel Jakub Dawidek 	}
1085c58794deSPawel Jakub Dawidek 	if (!*all && *nargs == 0) {
1086c58794deSPawel Jakub Dawidek 		gctl_error(req, "Too few arguments.");
1087c58794deSPawel Jakub Dawidek 		return;
1088c58794deSPawel Jakub Dawidek 	}
1089c58794deSPawel Jakub Dawidek 
1090c58794deSPawel Jakub Dawidek 	if (*all) {
1091c58794deSPawel Jakub Dawidek 		struct g_geom *gp, *gp2;
1092c58794deSPawel Jakub Dawidek 
1093c58794deSPawel Jakub Dawidek 		LIST_FOREACH_SAFE(gp, &mp->geom, geom, gp2) {
1094c58794deSPawel Jakub Dawidek 			error = g_eli_kill_one(gp->softc);
1095c58794deSPawel Jakub Dawidek 			if (error != 0)
1096c58794deSPawel Jakub Dawidek 				gctl_error(req, "Not fully done.");
1097c58794deSPawel Jakub Dawidek 		}
1098c58794deSPawel Jakub Dawidek 	} else {
1099c58794deSPawel Jakub Dawidek 		struct g_eli_softc *sc;
1100c58794deSPawel Jakub Dawidek 		const char *prov;
1101c58794deSPawel Jakub Dawidek 		char param[16];
1102c58794deSPawel Jakub Dawidek 		int i;
1103c58794deSPawel Jakub Dawidek 
1104c58794deSPawel Jakub Dawidek 		for (i = 0; i < *nargs; i++) {
11057d54b385SPawel Jakub Dawidek 			snprintf(param, sizeof(param), "arg%d", i);
1106c58794deSPawel Jakub Dawidek 			prov = gctl_get_asciiparam(req, param);
1107b5f30223SPawel Jakub Dawidek 			if (prov == NULL) {
1108b5f30223SPawel Jakub Dawidek 				G_ELI_DEBUG(0, "No 'arg%d' argument.", i);
1109b5f30223SPawel Jakub Dawidek 				continue;
1110b5f30223SPawel Jakub Dawidek 			}
1111c58794deSPawel Jakub Dawidek 
1112c58794deSPawel Jakub Dawidek 			sc = g_eli_find_device(mp, prov);
1113c58794deSPawel Jakub Dawidek 			if (sc == NULL) {
11147d54b385SPawel Jakub Dawidek 				G_ELI_DEBUG(0, "No such provider: %s.", prov);
1115c58794deSPawel Jakub Dawidek 				continue;
1116c58794deSPawel Jakub Dawidek 			}
1117c58794deSPawel Jakub Dawidek 			error = g_eli_kill_one(sc);
1118c58794deSPawel Jakub Dawidek 			if (error != 0)
1119c58794deSPawel Jakub Dawidek 				gctl_error(req, "Not fully done.");
1120c58794deSPawel Jakub Dawidek 		}
1121c58794deSPawel Jakub Dawidek 	}
1122c58794deSPawel Jakub Dawidek }
1123c58794deSPawel Jakub Dawidek 
1124c58794deSPawel Jakub Dawidek void
1125c58794deSPawel Jakub Dawidek g_eli_config(struct gctl_req *req, struct g_class *mp, const char *verb)
1126c58794deSPawel Jakub Dawidek {
1127c58794deSPawel Jakub Dawidek 	uint32_t *version;
1128c58794deSPawel Jakub Dawidek 
1129c58794deSPawel Jakub Dawidek 	g_topology_assert();
1130c58794deSPawel Jakub Dawidek 
1131c58794deSPawel Jakub Dawidek 	version = gctl_get_paraml(req, "version", sizeof(*version));
1132c58794deSPawel Jakub Dawidek 	if (version == NULL) {
1133c58794deSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "version");
1134c58794deSPawel Jakub Dawidek 		return;
1135c58794deSPawel Jakub Dawidek 	}
1136731adc86SPawel Jakub Dawidek 	while (*version != G_ELI_VERSION) {
1137731adc86SPawel Jakub Dawidek 		if (G_ELI_VERSION == G_ELI_VERSION_06 &&
1138731adc86SPawel Jakub Dawidek 		    *version == G_ELI_VERSION_05) {
1139731adc86SPawel Jakub Dawidek 			/* Compatible. */
1140731adc86SPawel Jakub Dawidek 			break;
1141731adc86SPawel Jakub Dawidek 		}
1142457bbc4fSPawel Jakub Dawidek 		if (G_ELI_VERSION == G_ELI_VERSION_07 &&
1143457bbc4fSPawel Jakub Dawidek 		    (*version == G_ELI_VERSION_05 ||
1144457bbc4fSPawel Jakub Dawidek 		     *version == G_ELI_VERSION_06)) {
1145457bbc4fSPawel Jakub Dawidek 			/* Compatible. */
1146457bbc4fSPawel Jakub Dawidek 			break;
1147457bbc4fSPawel Jakub Dawidek 		}
1148c58794deSPawel Jakub Dawidek 		gctl_error(req, "Userland and kernel parts are out of sync.");
1149c58794deSPawel Jakub Dawidek 		return;
1150c58794deSPawel Jakub Dawidek 	}
1151c58794deSPawel Jakub Dawidek 
1152c58794deSPawel Jakub Dawidek 	if (strcmp(verb, "attach") == 0)
1153c58794deSPawel Jakub Dawidek 		g_eli_ctl_attach(req, mp);
1154c58794deSPawel Jakub Dawidek 	else if (strcmp(verb, "detach") == 0 || strcmp(verb, "stop") == 0)
1155c58794deSPawel Jakub Dawidek 		g_eli_ctl_detach(req, mp);
1156c58794deSPawel Jakub Dawidek 	else if (strcmp(verb, "onetime") == 0)
1157c58794deSPawel Jakub Dawidek 		g_eli_ctl_onetime(req, mp);
11588abd1ad1SPawel Jakub Dawidek 	else if (strcmp(verb, "configure") == 0)
11598abd1ad1SPawel Jakub Dawidek 		g_eli_ctl_configure(req, mp);
1160c58794deSPawel Jakub Dawidek 	else if (strcmp(verb, "setkey") == 0)
1161c58794deSPawel Jakub Dawidek 		g_eli_ctl_setkey(req, mp);
1162c58794deSPawel Jakub Dawidek 	else if (strcmp(verb, "delkey") == 0)
1163c58794deSPawel Jakub Dawidek 		g_eli_ctl_delkey(req, mp);
11645ad4a7c7SPawel Jakub Dawidek 	else if (strcmp(verb, "suspend") == 0)
11655ad4a7c7SPawel Jakub Dawidek 		g_eli_ctl_suspend(req, mp);
11665ad4a7c7SPawel Jakub Dawidek 	else if (strcmp(verb, "resume") == 0)
11675ad4a7c7SPawel Jakub Dawidek 		g_eli_ctl_resume(req, mp);
1168c58794deSPawel Jakub Dawidek 	else if (strcmp(verb, "kill") == 0)
1169c58794deSPawel Jakub Dawidek 		g_eli_ctl_kill(req, mp);
1170c58794deSPawel Jakub Dawidek 	else
1171c58794deSPawel Jakub Dawidek 		gctl_error(req, "Unknown verb.");
1172c58794deSPawel Jakub Dawidek }
1173