1148456Spjd/*-
2220922Spjd * Copyright (c) 2005-2011 Pawel Jakub Dawidek <pawel@dawidek.net>
3148456Spjd * All rights reserved.
4148456Spjd *
5148456Spjd * Redistribution and use in source and binary forms, with or without
6148456Spjd * modification, are permitted provided that the following conditions
7148456Spjd * are met:
8148456Spjd * 1. Redistributions of source code must retain the above copyright
9148456Spjd *    notice, this list of conditions and the following disclaimer.
10148456Spjd * 2. Redistributions in binary form must reproduce the above copyright
11148456Spjd *    notice, this list of conditions and the following disclaimer in the
12148456Spjd *    documentation and/or other materials provided with the distribution.
13155174Spjd *
14148456Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15148456Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16148456Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17148456Spjd * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18148456Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19148456Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20148456Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21148456Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22148456Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23148456Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24148456Spjd * SUCH DAMAGE.
25148456Spjd */
26148456Spjd
27148456Spjd#include <sys/cdefs.h>
28148456Spjd__FBSDID("$FreeBSD$");
29148456Spjd
30148456Spjd#include <sys/param.h>
31148456Spjd#include <sys/systm.h>
32148456Spjd#include <sys/kernel.h>
33148456Spjd#include <sys/module.h>
34148456Spjd#include <sys/lock.h>
35148456Spjd#include <sys/mutex.h>
36148456Spjd#include <sys/bio.h>
37148456Spjd#include <sys/sysctl.h>
38148456Spjd#include <sys/malloc.h>
39148456Spjd#include <sys/kthread.h>
40148456Spjd#include <sys/proc.h>
41148456Spjd#include <sys/sched.h>
42148456Spjd#include <sys/uio.h>
43148456Spjd
44148456Spjd#include <vm/uma.h>
45148456Spjd
46148456Spjd#include <geom/geom.h>
47148456Spjd#include <geom/eli/g_eli.h>
48148456Spjd
49148456Spjd
50148456SpjdMALLOC_DECLARE(M_ELI);
51148456Spjd
52148456Spjd
53148456Spjdstatic void
54148456Spjdg_eli_ctl_attach(struct gctl_req *req, struct g_class *mp)
55148456Spjd{
56148456Spjd	struct g_eli_metadata md;
57148456Spjd	struct g_provider *pp;
58148456Spjd	const char *name;
59148456Spjd	u_char *key, mkey[G_ELI_DATAIVKEYLEN];
60161127Spjd	int *nargs, *detach, *readonly;
61148456Spjd	int keysize, error;
62148456Spjd	u_int nkey;
63148456Spjd
64148456Spjd	g_topology_assert();
65148456Spjd
66148456Spjd	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
67148456Spjd	if (nargs == NULL) {
68148456Spjd		gctl_error(req, "No '%s' argument.", "nargs");
69148456Spjd		return;
70148456Spjd	}
71148456Spjd	if (*nargs != 1) {
72148456Spjd		gctl_error(req, "Invalid number of arguments.");
73148456Spjd		return;
74148456Spjd	}
75148456Spjd
76148456Spjd	detach = gctl_get_paraml(req, "detach", sizeof(*detach));
77148456Spjd	if (detach == NULL) {
78148456Spjd		gctl_error(req, "No '%s' argument.", "detach");
79148456Spjd		return;
80148456Spjd	}
81148456Spjd
82161127Spjd	readonly = gctl_get_paraml(req, "readonly", sizeof(*readonly));
83161127Spjd	if (readonly == NULL) {
84161127Spjd		gctl_error(req, "No '%s' argument.", "readonly");
85161127Spjd		return;
86161127Spjd	}
87161127Spjd
88148456Spjd	name = gctl_get_asciiparam(req, "arg0");
89148456Spjd	if (name == NULL) {
90148456Spjd		gctl_error(req, "No 'arg%u' argument.", 0);
91148456Spjd		return;
92148456Spjd	}
93148456Spjd	if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
94148456Spjd		name += strlen("/dev/");
95148456Spjd	pp = g_provider_by_name(name);
96148456Spjd	if (pp == NULL) {
97148456Spjd		gctl_error(req, "Provider %s is invalid.", name);
98148456Spjd		return;
99148456Spjd	}
100148456Spjd	error = g_eli_read_metadata(mp, pp, &md);
101148456Spjd	if (error != 0) {
102148456Spjd		gctl_error(req, "Cannot read metadata from %s (error=%d).",
103148456Spjd		    name, error);
104148456Spjd		return;
105148456Spjd	}
106148456Spjd	if (md.md_keys == 0x00) {
107148456Spjd		bzero(&md, sizeof(md));
108148456Spjd		gctl_error(req, "No valid keys on %s.", pp->name);
109148456Spjd		return;
110148456Spjd	}
111148456Spjd
112148456Spjd	key = gctl_get_param(req, "key", &keysize);
113148456Spjd	if (key == NULL || keysize != G_ELI_USERKEYLEN) {
114148456Spjd		bzero(&md, sizeof(md));
115148456Spjd		gctl_error(req, "No '%s' argument.", "key");
116148456Spjd		return;
117148456Spjd	}
118148456Spjd
119148456Spjd	error = g_eli_mkey_decrypt(&md, key, mkey, &nkey);
120148456Spjd	bzero(key, keysize);
121148456Spjd	if (error == -1) {
122148456Spjd		bzero(&md, sizeof(md));
123148456Spjd		gctl_error(req, "Wrong key for %s.", pp->name);
124148456Spjd		return;
125148456Spjd	} else if (error > 0) {
126148456Spjd		bzero(&md, sizeof(md));
127148456Spjd		gctl_error(req, "Cannot decrypt Master Key for %s (error=%d).",
128148456Spjd		    pp->name, error);
129148456Spjd		return;
130148456Spjd	}
131148456Spjd	G_ELI_DEBUG(1, "Using Master Key %u for %s.", nkey, pp->name);
132148456Spjd
133161127Spjd	if (*detach && *readonly) {
134161127Spjd		bzero(&md, sizeof(md));
135162345Spjd		gctl_error(req, "Options -d and -r are mutually exclusive.");
136161127Spjd		return;
137161127Spjd	}
138148456Spjd	if (*detach)
139148456Spjd		md.md_flags |= G_ELI_FLAG_WO_DETACH;
140161127Spjd	if (*readonly)
141161127Spjd		md.md_flags |= G_ELI_FLAG_RO;
142148456Spjd	g_eli_create(req, mp, pp, &md, mkey, nkey);
143148456Spjd	bzero(mkey, sizeof(mkey));
144148456Spjd	bzero(&md, sizeof(md));
145148456Spjd}
146148456Spjd
147148456Spjdstatic struct g_eli_softc *
148148456Spjdg_eli_find_device(struct g_class *mp, const char *prov)
149148456Spjd{
150148456Spjd	struct g_eli_softc *sc;
151148456Spjd	struct g_geom *gp;
152148456Spjd	struct g_provider *pp;
153148456Spjd	struct g_consumer *cp;
154148456Spjd
155148456Spjd	if (strncmp(prov, "/dev/", strlen("/dev/")) == 0)
156148456Spjd		prov += strlen("/dev/");
157148456Spjd	LIST_FOREACH(gp, &mp->geom, geom) {
158148456Spjd		sc = gp->softc;
159148456Spjd		if (sc == NULL)
160148456Spjd			continue;
161148456Spjd		pp = LIST_FIRST(&gp->provider);
162148456Spjd		if (pp != NULL && strcmp(pp->name, prov) == 0)
163148456Spjd			return (sc);
164148456Spjd		cp = LIST_FIRST(&gp->consumer);
165148456Spjd		if (cp != NULL && cp->provider != NULL &&
166148456Spjd		    strcmp(cp->provider->name, prov) == 0) {
167148456Spjd			return (sc);
168148456Spjd		}
169148456Spjd	}
170148456Spjd	return (NULL);
171148456Spjd}
172148456Spjd
173148456Spjdstatic void
174148456Spjdg_eli_ctl_detach(struct gctl_req *req, struct g_class *mp)
175148456Spjd{
176148456Spjd	struct g_eli_softc *sc;
177148456Spjd	int *force, *last, *nargs, error;
178148456Spjd	const char *prov;
179148456Spjd	char param[16];
180154463Spjd	int i;
181148456Spjd
182148456Spjd	g_topology_assert();
183148456Spjd
184148456Spjd	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
185148456Spjd	if (nargs == NULL) {
186148456Spjd		gctl_error(req, "No '%s' argument.", "nargs");
187148456Spjd		return;
188148456Spjd	}
189148456Spjd	if (*nargs <= 0) {
190148456Spjd		gctl_error(req, "Missing device(s).");
191148456Spjd		return;
192148456Spjd	}
193148456Spjd	force = gctl_get_paraml(req, "force", sizeof(*force));
194148456Spjd	if (force == NULL) {
195148456Spjd		gctl_error(req, "No '%s' argument.", "force");
196148456Spjd		return;
197148456Spjd	}
198148456Spjd	last = gctl_get_paraml(req, "last", sizeof(*last));
199148456Spjd	if (last == NULL) {
200148456Spjd		gctl_error(req, "No '%s' argument.", "last");
201148456Spjd		return;
202148456Spjd	}
203148456Spjd
204154463Spjd	for (i = 0; i < *nargs; i++) {
205154463Spjd		snprintf(param, sizeof(param), "arg%d", i);
206148456Spjd		prov = gctl_get_asciiparam(req, param);
207148456Spjd		if (prov == NULL) {
208154463Spjd			gctl_error(req, "No 'arg%d' argument.", i);
209148456Spjd			return;
210148456Spjd		}
211148456Spjd		sc = g_eli_find_device(mp, prov);
212148456Spjd		if (sc == NULL) {
213148456Spjd			gctl_error(req, "No such device: %s.", prov);
214148456Spjd			return;
215148456Spjd		}
216148456Spjd		if (*last) {
217148456Spjd			sc->sc_flags |= G_ELI_FLAG_RW_DETACH;
218148456Spjd			sc->sc_geom->access = g_eli_access;
219148456Spjd		} else {
220214118Spjd			error = g_eli_destroy(sc, *force ? TRUE : FALSE);
221148456Spjd			if (error != 0) {
222148456Spjd				gctl_error(req,
223148456Spjd				    "Cannot destroy device %s (error=%d).",
224148456Spjd				    sc->sc_name, error);
225148456Spjd				return;
226148456Spjd			}
227148456Spjd		}
228148456Spjd	}
229148456Spjd}
230148456Spjd
231148456Spjdstatic void
232148456Spjdg_eli_ctl_onetime(struct gctl_req *req, struct g_class *mp)
233148456Spjd{
234148456Spjd	struct g_eli_metadata md;
235148456Spjd	struct g_provider *pp;
236148456Spjd	const char *name;
237148456Spjd	intmax_t *keylen, *sectorsize;
238148456Spjd	u_char mkey[G_ELI_DATAIVKEYLEN];
239148456Spjd	int *nargs, *detach;
240148456Spjd
241148456Spjd	g_topology_assert();
242148456Spjd	bzero(&md, sizeof(md));
243148456Spjd
244148456Spjd	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
245148456Spjd	if (nargs == NULL) {
246148456Spjd		gctl_error(req, "No '%s' argument.", "nargs");
247148456Spjd		return;
248148456Spjd	}
249148456Spjd	if (*nargs != 1) {
250148456Spjd		gctl_error(req, "Invalid number of arguments.");
251148456Spjd		return;
252148456Spjd	}
253148456Spjd
254148456Spjd	detach = gctl_get_paraml(req, "detach", sizeof(*detach));
255148456Spjd	if (detach == NULL) {
256148456Spjd		gctl_error(req, "No '%s' argument.", "detach");
257148456Spjd		return;
258148456Spjd	}
259148456Spjd
260148456Spjd	strlcpy(md.md_magic, G_ELI_MAGIC, sizeof(md.md_magic));
261148456Spjd	md.md_version = G_ELI_VERSION;
262148456Spjd	md.md_flags |= G_ELI_FLAG_ONETIME;
263148456Spjd	if (*detach)
264148456Spjd		md.md_flags |= G_ELI_FLAG_WO_DETACH;
265148456Spjd
266159361Spjd	md.md_ealgo = CRYPTO_ALGORITHM_MIN - 1;
267159307Spjd	name = gctl_get_asciiparam(req, "aalgo");
268148456Spjd	if (name == NULL) {
269159307Spjd		gctl_error(req, "No '%s' argument.", "aalgo");
270148456Spjd		return;
271148456Spjd	}
272212547Spjd	if (*name != '\0') {
273159307Spjd		md.md_aalgo = g_eli_str2aalgo(name);
274159361Spjd		if (md.md_aalgo >= CRYPTO_ALGORITHM_MIN &&
275159361Spjd		    md.md_aalgo <= CRYPTO_ALGORITHM_MAX) {
276159361Spjd			md.md_flags |= G_ELI_FLAG_AUTH;
277159361Spjd		} else {
278159361Spjd			/*
279159361Spjd			 * For backward compatibility, check if the -a option
280159361Spjd			 * was used to provide encryption algorithm.
281159361Spjd			 */
282159361Spjd			md.md_ealgo = g_eli_str2ealgo(name);
283159361Spjd			if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
284159361Spjd			    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
285159361Spjd				gctl_error(req,
286159361Spjd				    "Invalid authentication algorithm.");
287159361Spjd				return;
288159361Spjd			} else {
289159361Spjd				gctl_error(req, "warning: The -e option, not "
290159361Spjd				    "the -a option is now used to specify "
291159361Spjd				    "encryption algorithm to use.");
292159361Spjd			}
293159307Spjd		}
294159307Spjd	}
295159307Spjd
296159307Spjd	if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
297159307Spjd	    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
298159361Spjd		name = gctl_get_asciiparam(req, "ealgo");
299159361Spjd		if (name == NULL) {
300159361Spjd			gctl_error(req, "No '%s' argument.", "ealgo");
301159361Spjd			return;
302159361Spjd		}
303159361Spjd		md.md_ealgo = g_eli_str2ealgo(name);
304159361Spjd		if (md.md_ealgo < CRYPTO_ALGORITHM_MIN ||
305159361Spjd		    md.md_ealgo > CRYPTO_ALGORITHM_MAX) {
306159361Spjd			gctl_error(req, "Invalid encryption algorithm.");
307159361Spjd			return;
308159361Spjd		}
309159307Spjd	}
310148456Spjd
311148456Spjd	keylen = gctl_get_paraml(req, "keylen", sizeof(*keylen));
312148456Spjd	if (keylen == NULL) {
313148456Spjd		gctl_error(req, "No '%s' argument.", "keylen");
314148456Spjd		return;
315148456Spjd	}
316159307Spjd	md.md_keylen = g_eli_keylen(md.md_ealgo, *keylen);
317148456Spjd	if (md.md_keylen == 0) {
318148456Spjd		gctl_error(req, "Invalid '%s' argument.", "keylen");
319148456Spjd		return;
320148456Spjd	}
321148456Spjd
322148456Spjd	/* Not important here. */
323148456Spjd	md.md_provsize = 0;
324148456Spjd	/* Not important here. */
325148456Spjd	bzero(md.md_salt, sizeof(md.md_salt));
326148456Spjd
327148456Spjd	md.md_keys = 0x01;
328148456Spjd	arc4rand(mkey, sizeof(mkey), 0);
329148456Spjd
330148456Spjd	/* Not important here. */
331148456Spjd	bzero(md.md_hash, sizeof(md.md_hash));
332148456Spjd
333148456Spjd	name = gctl_get_asciiparam(req, "arg0");
334148456Spjd	if (name == NULL) {
335148456Spjd		gctl_error(req, "No 'arg%u' argument.", 0);
336148456Spjd		return;
337148456Spjd	}
338148456Spjd	if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
339148456Spjd		name += strlen("/dev/");
340148456Spjd	pp = g_provider_by_name(name);
341148456Spjd	if (pp == NULL) {
342148456Spjd		gctl_error(req, "Provider %s is invalid.", name);
343148456Spjd		return;
344148456Spjd	}
345148456Spjd
346148456Spjd	sectorsize = gctl_get_paraml(req, "sectorsize", sizeof(*sectorsize));
347148456Spjd	if (sectorsize == NULL) {
348148456Spjd		gctl_error(req, "No '%s' argument.", "sectorsize");
349148456Spjd		return;
350148456Spjd	}
351148456Spjd	if (*sectorsize == 0)
352148456Spjd		md.md_sectorsize = pp->sectorsize;
353148456Spjd	else {
354148456Spjd		if (*sectorsize < 0 || (*sectorsize % pp->sectorsize) != 0) {
355148456Spjd			gctl_error(req, "Invalid sector size.");
356148456Spjd			return;
357148456Spjd		}
358167229Spjd		if (*sectorsize > PAGE_SIZE) {
359167229Spjd			gctl_error(req, "warning: Using sectorsize bigger than "
360167229Spjd			    "the page size!");
361167229Spjd		}
362148456Spjd		md.md_sectorsize = *sectorsize;
363148456Spjd	}
364148456Spjd
365148456Spjd	g_eli_create(req, mp, pp, &md, mkey, -1);
366148456Spjd	bzero(mkey, sizeof(mkey));
367148456Spjd	bzero(&md, sizeof(md));
368148456Spjd}
369148456Spjd
370148456Spjdstatic void
371162353Spjdg_eli_ctl_configure(struct gctl_req *req, struct g_class *mp)
372162353Spjd{
373162353Spjd	struct g_eli_softc *sc;
374162353Spjd	struct g_eli_metadata md;
375162353Spjd	struct g_provider *pp;
376162353Spjd	struct g_consumer *cp;
377162353Spjd	char param[16];
378162353Spjd	const char *prov;
379162353Spjd	u_char *sector;
380162353Spjd	int *nargs, *boot, *noboot;
381162353Spjd	int error;
382162353Spjd	u_int i;
383162353Spjd
384162353Spjd	g_topology_assert();
385162353Spjd
386162353Spjd	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
387162353Spjd	if (nargs == NULL) {
388162353Spjd		gctl_error(req, "No '%s' argument.", "nargs");
389162353Spjd		return;
390162353Spjd	}
391162353Spjd	if (*nargs <= 0) {
392162353Spjd		gctl_error(req, "Missing device(s).");
393162353Spjd		return;
394162353Spjd	}
395162353Spjd
396162353Spjd	boot = gctl_get_paraml(req, "boot", sizeof(*boot));
397162353Spjd	if (boot == NULL) {
398162353Spjd		gctl_error(req, "No '%s' argument.", "boot");
399162353Spjd		return;
400162353Spjd	}
401162353Spjd	noboot = gctl_get_paraml(req, "noboot", sizeof(*noboot));
402162353Spjd	if (noboot == NULL) {
403162353Spjd		gctl_error(req, "No '%s' argument.", "noboot");
404162353Spjd		return;
405162353Spjd	}
406162353Spjd	if (*boot && *noboot) {
407162353Spjd		gctl_error(req, "Options -b and -B are mutually exclusive.");
408162353Spjd		return;
409162353Spjd	}
410162353Spjd	if (!*boot && !*noboot) {
411162353Spjd		gctl_error(req, "No option given.");
412162353Spjd		return;
413162353Spjd	}
414162353Spjd
415162353Spjd	for (i = 0; i < *nargs; i++) {
416162353Spjd		snprintf(param, sizeof(param), "arg%d", i);
417162353Spjd		prov = gctl_get_asciiparam(req, param);
418162353Spjd		if (prov == NULL) {
419162353Spjd			gctl_error(req, "No 'arg%d' argument.", i);
420162353Spjd			return;
421162353Spjd		}
422162353Spjd		sc = g_eli_find_device(mp, prov);
423162353Spjd		if (sc == NULL) {
424162353Spjd			/*
425162353Spjd			 * We ignore not attached providers, userland part will
426162353Spjd			 * take care of them.
427162353Spjd			 */
428162353Spjd			G_ELI_DEBUG(1, "Skipping configuration of not attached "
429162353Spjd			    "provider %s.", prov);
430162353Spjd			continue;
431162353Spjd		}
432162353Spjd		if (*boot && (sc->sc_flags & G_ELI_FLAG_BOOT)) {
433162353Spjd			G_ELI_DEBUG(1, "BOOT flag already configured for %s.",
434162353Spjd			    prov);
435162353Spjd			continue;
436162353Spjd		} else if (!*boot && !(sc->sc_flags & G_ELI_FLAG_BOOT)) {
437162353Spjd			G_ELI_DEBUG(1, "BOOT flag not configured for %s.",
438162353Spjd			    prov);
439162353Spjd			continue;
440162353Spjd		}
441162353Spjd		if (sc->sc_flags & G_ELI_FLAG_RO) {
442162353Spjd			gctl_error(req, "Cannot change configuration of "
443162353Spjd			    "read-only provider %s.", prov);
444162353Spjd			continue;
445162353Spjd		}
446162353Spjd		cp = LIST_FIRST(&sc->sc_geom->consumer);
447162353Spjd		pp = cp->provider;
448162353Spjd		error = g_eli_read_metadata(mp, pp, &md);
449162353Spjd		if (error != 0) {
450162353Spjd			gctl_error(req,
451162353Spjd			    "Cannot read metadata from %s (error=%d).",
452162353Spjd			    prov, error);
453162353Spjd			continue;
454162353Spjd		}
455162353Spjd
456162353Spjd		if (*boot) {
457162353Spjd			md.md_flags |= G_ELI_FLAG_BOOT;
458162353Spjd			sc->sc_flags |= G_ELI_FLAG_BOOT;
459162353Spjd		} else {
460162353Spjd			md.md_flags &= ~G_ELI_FLAG_BOOT;
461162353Spjd			sc->sc_flags &= ~G_ELI_FLAG_BOOT;
462162353Spjd		}
463162353Spjd
464162353Spjd		sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
465162353Spjd		eli_metadata_encode(&md, sector);
466162353Spjd		error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
467162353Spjd		    pp->sectorsize);
468162353Spjd		if (error != 0) {
469162353Spjd			gctl_error(req,
470162353Spjd			    "Cannot store metadata on %s (error=%d).",
471162353Spjd			    prov, error);
472162353Spjd		}
473162353Spjd		bzero(&md, sizeof(md));
474257718Sdelphij		bzero(sector, pp->sectorsize);
475162353Spjd		free(sector, M_ELI);
476162353Spjd	}
477162353Spjd}
478162353Spjd
479162353Spjdstatic void
480148456Spjdg_eli_ctl_setkey(struct gctl_req *req, struct g_class *mp)
481148456Spjd{
482148456Spjd	struct g_eli_softc *sc;
483148456Spjd	struct g_eli_metadata md;
484148456Spjd	struct g_provider *pp;
485148456Spjd	struct g_consumer *cp;
486148456Spjd	const char *name;
487148456Spjd	u_char *key, *mkeydst, *sector;
488148456Spjd	intmax_t *valp;
489149304Spjd	int keysize, nkey, error;
490148456Spjd
491148456Spjd	g_topology_assert();
492148456Spjd
493148456Spjd	name = gctl_get_asciiparam(req, "arg0");
494148456Spjd	if (name == NULL) {
495148456Spjd		gctl_error(req, "No 'arg%u' argument.", 0);
496148456Spjd		return;
497148456Spjd	}
498148456Spjd	sc = g_eli_find_device(mp, name);
499148456Spjd	if (sc == NULL) {
500148456Spjd		gctl_error(req, "Provider %s is invalid.", name);
501148456Spjd		return;
502148456Spjd	}
503161127Spjd	if (sc->sc_flags & G_ELI_FLAG_RO) {
504161127Spjd		gctl_error(req, "Cannot change keys for read-only provider.");
505161127Spjd		return;
506161127Spjd	}
507148456Spjd	cp = LIST_FIRST(&sc->sc_geom->consumer);
508148456Spjd	pp = cp->provider;
509148456Spjd
510148456Spjd	error = g_eli_read_metadata(mp, pp, &md);
511148456Spjd	if (error != 0) {
512148456Spjd		gctl_error(req, "Cannot read metadata from %s (error=%d).",
513148456Spjd		    name, error);
514148456Spjd		return;
515148456Spjd	}
516148456Spjd
517148456Spjd	valp = gctl_get_paraml(req, "keyno", sizeof(*valp));
518148456Spjd	if (valp == NULL) {
519148456Spjd		gctl_error(req, "No '%s' argument.", "keyno");
520148456Spjd		return;
521148456Spjd	}
522148456Spjd	if (*valp != -1)
523148456Spjd		nkey = *valp;
524148456Spjd	else
525148456Spjd		nkey = sc->sc_nkey;
526148456Spjd	if (nkey < 0 || nkey >= G_ELI_MAXMKEYS) {
527148456Spjd		gctl_error(req, "Invalid '%s' argument.", "keyno");
528148456Spjd		return;
529148456Spjd	}
530148456Spjd
531149304Spjd	valp = gctl_get_paraml(req, "iterations", sizeof(*valp));
532149304Spjd	if (valp == NULL) {
533149304Spjd		gctl_error(req, "No '%s' argument.", "iterations");
534149304Spjd		return;
535149304Spjd	}
536149304Spjd	/* Check if iterations number should and can be changed. */
537149304Spjd	if (*valp != -1) {
538149304Spjd		if (bitcount32(md.md_keys) != 1) {
539149304Spjd			gctl_error(req, "To be able to use '-i' option, only "
540149304Spjd			    "one key can be defined.");
541149304Spjd			return;
542149304Spjd		}
543149304Spjd		if (md.md_keys != (1 << nkey)) {
544149304Spjd			gctl_error(req, "Only already defined key can be "
545149304Spjd			    "changed when '-i' option is used.");
546149304Spjd			return;
547149304Spjd		}
548149304Spjd		md.md_iterations = *valp;
549149304Spjd	}
550149304Spjd
551148456Spjd	key = gctl_get_param(req, "key", &keysize);
552148456Spjd	if (key == NULL || keysize != G_ELI_USERKEYLEN) {
553148456Spjd		bzero(&md, sizeof(md));
554148456Spjd		gctl_error(req, "No '%s' argument.", "key");
555148456Spjd		return;
556148456Spjd	}
557148456Spjd
558148456Spjd	mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
559148456Spjd	md.md_keys |= (1 << nkey);
560148456Spjd
561159307Spjd	bcopy(sc->sc_mkey, mkeydst, sizeof(sc->sc_mkey));
562148456Spjd
563148456Spjd	/* Encrypt Master Key with the new key. */
564159307Spjd	error = g_eli_mkey_encrypt(md.md_ealgo, key, md.md_keylen, mkeydst);
565257718Sdelphij	bzero(key, keysize);
566148456Spjd	if (error != 0) {
567148456Spjd		bzero(&md, sizeof(md));
568148456Spjd		gctl_error(req, "Cannot encrypt Master Key (error=%d).", error);
569148456Spjd		return;
570148456Spjd	}
571148456Spjd
572148456Spjd	sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
573148456Spjd	/* Store metadata with fresh key. */
574148456Spjd	eli_metadata_encode(&md, sector);
575148456Spjd	bzero(&md, sizeof(md));
576148456Spjd	error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
577148456Spjd	    pp->sectorsize);
578257718Sdelphij	bzero(sector, pp->sectorsize);
579148456Spjd	free(sector, M_ELI);
580148456Spjd	if (error != 0) {
581148456Spjd		gctl_error(req, "Cannot store metadata on %s (error=%d).",
582148456Spjd		    pp->name, error);
583148456Spjd		return;
584148456Spjd	}
585148456Spjd	G_ELI_DEBUG(1, "Key %u changed on %s.", nkey, pp->name);
586148456Spjd}
587148456Spjd
588148456Spjdstatic void
589148456Spjdg_eli_ctl_delkey(struct gctl_req *req, struct g_class *mp)
590148456Spjd{
591148456Spjd	struct g_eli_softc *sc;
592148456Spjd	struct g_eli_metadata md;
593148456Spjd	struct g_provider *pp;
594148456Spjd	struct g_consumer *cp;
595148456Spjd	const char *name;
596148456Spjd	u_char *mkeydst, *sector;
597148456Spjd	intmax_t *valp;
598148456Spjd	size_t keysize;
599148456Spjd	int error, nkey, *all, *force;
600148456Spjd	u_int i;
601148456Spjd
602148456Spjd	g_topology_assert();
603148456Spjd
604148456Spjd	nkey = 0;	/* fixes causeless gcc warning */
605148456Spjd
606148456Spjd	name = gctl_get_asciiparam(req, "arg0");
607148456Spjd	if (name == NULL) {
608148456Spjd		gctl_error(req, "No 'arg%u' argument.", 0);
609148456Spjd		return;
610148456Spjd	}
611148456Spjd	sc = g_eli_find_device(mp, name);
612148456Spjd	if (sc == NULL) {
613148456Spjd		gctl_error(req, "Provider %s is invalid.", name);
614148456Spjd		return;
615148456Spjd	}
616161127Spjd	if (sc->sc_flags & G_ELI_FLAG_RO) {
617161127Spjd		gctl_error(req, "Cannot delete keys for read-only provider.");
618161127Spjd		return;
619161127Spjd	}
620148456Spjd	cp = LIST_FIRST(&sc->sc_geom->consumer);
621148456Spjd	pp = cp->provider;
622148456Spjd
623148456Spjd	error = g_eli_read_metadata(mp, pp, &md);
624148456Spjd	if (error != 0) {
625148456Spjd		gctl_error(req, "Cannot read metadata from %s (error=%d).",
626148456Spjd		    name, error);
627148456Spjd		return;
628148456Spjd	}
629148456Spjd
630148456Spjd	all = gctl_get_paraml(req, "all", sizeof(*all));
631148456Spjd	if (all == NULL) {
632148456Spjd		gctl_error(req, "No '%s' argument.", "all");
633148456Spjd		return;
634148456Spjd	}
635148456Spjd
636148456Spjd	if (*all) {
637148456Spjd		mkeydst = md.md_mkeys;
638148456Spjd		keysize = sizeof(md.md_mkeys);
639148456Spjd	} else {
640148456Spjd		force = gctl_get_paraml(req, "force", sizeof(*force));
641148456Spjd		if (force == NULL) {
642148456Spjd			gctl_error(req, "No '%s' argument.", "force");
643148456Spjd			return;
644148456Spjd		}
645162834Spjd
646148456Spjd		valp = gctl_get_paraml(req, "keyno", sizeof(*valp));
647148456Spjd		if (valp == NULL) {
648148456Spjd			gctl_error(req, "No '%s' argument.", "keyno");
649148456Spjd			return;
650148456Spjd		}
651148456Spjd		if (*valp != -1)
652148456Spjd			nkey = *valp;
653148456Spjd		else
654148456Spjd			nkey = sc->sc_nkey;
655148456Spjd		if (nkey < 0 || nkey >= G_ELI_MAXMKEYS) {
656148456Spjd			gctl_error(req, "Invalid '%s' argument.", "keyno");
657148456Spjd			return;
658148456Spjd		}
659148456Spjd		if (!(md.md_keys & (1 << nkey)) && !*force) {
660148456Spjd			gctl_error(req, "Master Key %u is not set.", nkey);
661148456Spjd			return;
662148456Spjd		}
663148456Spjd		md.md_keys &= ~(1 << nkey);
664148456Spjd		if (md.md_keys == 0 && !*force) {
665148456Spjd			gctl_error(req, "This is the last Master Key. Use '-f' "
666148456Spjd			    "flag if you really want to remove it.");
667148456Spjd			return;
668148456Spjd		}
669148456Spjd		mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
670148456Spjd		keysize = G_ELI_MKEYLEN;
671148456Spjd	}
672148456Spjd
673148456Spjd	sector = malloc(pp->sectorsize, M_ELI, M_WAITOK | M_ZERO);
674148456Spjd	for (i = 0; i <= g_eli_overwrites; i++) {
675148456Spjd		if (i == g_eli_overwrites)
676148456Spjd			bzero(mkeydst, keysize);
677148456Spjd		else
678148456Spjd			arc4rand(mkeydst, keysize, 0);
679148456Spjd		/* Store metadata with destroyed key. */
680148456Spjd		eli_metadata_encode(&md, sector);
681148456Spjd		error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
682148456Spjd		    pp->sectorsize);
683148456Spjd		if (error != 0) {
684148456Spjd			G_ELI_DEBUG(0, "Cannot store metadata on %s "
685148456Spjd			    "(error=%d).", pp->name, error);
686148456Spjd		}
687169313Spjd		/*
688169313Spjd		 * Flush write cache so we don't overwrite data N times in cache
689169313Spjd		 * and only once on disk.
690169313Spjd		 */
691213164Spjd		(void)g_io_flush(cp);
692148456Spjd	}
693148456Spjd	bzero(&md, sizeof(md));
694257718Sdelphij	bzero(sector, pp->sectorsize);
695148456Spjd	free(sector, M_ELI);
696148456Spjd	if (*all)
697148456Spjd		G_ELI_DEBUG(1, "All keys removed from %s.", pp->name);
698148456Spjd	else
699148456Spjd		G_ELI_DEBUG(1, "Key %d removed from %s.", nkey, pp->name);
700148456Spjd}
701148456Spjd
702214229Spjdstatic void
703214229Spjdg_eli_suspend_one(struct g_eli_softc *sc, struct gctl_req *req)
704214118Spjd{
705214118Spjd	struct g_eli_worker *wr;
706214118Spjd
707214118Spjd	g_topology_assert();
708214118Spjd
709214229Spjd	KASSERT(sc != NULL, ("NULL sc"));
710214118Spjd
711214229Spjd	if (sc->sc_flags & G_ELI_FLAG_ONETIME) {
712214229Spjd		gctl_error(req,
713214229Spjd		    "Device %s is using one-time key, suspend not supported.",
714214229Spjd		    sc->sc_name);
715214229Spjd		return;
716214229Spjd	}
717214229Spjd
718214118Spjd	mtx_lock(&sc->sc_queue_mtx);
719214118Spjd	if (sc->sc_flags & G_ELI_FLAG_SUSPEND) {
720214118Spjd		mtx_unlock(&sc->sc_queue_mtx);
721214229Spjd		gctl_error(req, "Device %s already suspended.",
722214229Spjd		    sc->sc_name);
723214229Spjd		return;
724214118Spjd	}
725214118Spjd	sc->sc_flags |= G_ELI_FLAG_SUSPEND;
726214118Spjd	wakeup(sc);
727214118Spjd	for (;;) {
728214118Spjd		LIST_FOREACH(wr, &sc->sc_workers, w_next) {
729214118Spjd			if (wr->w_active)
730214118Spjd				break;
731214118Spjd		}
732214118Spjd		if (wr == NULL)
733214118Spjd			break;
734214118Spjd		/* Not all threads suspended. */
735214118Spjd		msleep(&sc->sc_workers, &sc->sc_queue_mtx, PRIBIO,
736214118Spjd		    "geli:suspend", 0);
737214118Spjd	}
738214118Spjd	/*
739214118Spjd	 * Clear sensitive data on suspend, they will be recovered on resume.
740214118Spjd	 */
741214118Spjd	bzero(sc->sc_mkey, sizeof(sc->sc_mkey));
742220922Spjd	g_eli_key_destroy(sc);
743214118Spjd	bzero(sc->sc_akey, sizeof(sc->sc_akey));
744214118Spjd	bzero(&sc->sc_akeyctx, sizeof(sc->sc_akeyctx));
745214118Spjd	bzero(sc->sc_ivkey, sizeof(sc->sc_ivkey));
746214118Spjd	bzero(&sc->sc_ivctx, sizeof(sc->sc_ivctx));
747214118Spjd	mtx_unlock(&sc->sc_queue_mtx);
748214229Spjd	G_ELI_DEBUG(0, "Device %s has been suspended.", sc->sc_name);
749214118Spjd}
750214118Spjd
751214118Spjdstatic void
752214118Spjdg_eli_ctl_suspend(struct gctl_req *req, struct g_class *mp)
753214118Spjd{
754214118Spjd	struct g_eli_softc *sc;
755214118Spjd	int *all, *nargs;
756214118Spjd
757214118Spjd	g_topology_assert();
758214118Spjd
759214118Spjd	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
760214118Spjd	if (nargs == NULL) {
761214118Spjd		gctl_error(req, "No '%s' argument.", "nargs");
762214118Spjd		return;
763214118Spjd	}
764214118Spjd	all = gctl_get_paraml(req, "all", sizeof(*all));
765214118Spjd	if (all == NULL) {
766214118Spjd		gctl_error(req, "No '%s' argument.", "all");
767214118Spjd		return;
768214118Spjd	}
769214118Spjd	if (!*all && *nargs == 0) {
770214118Spjd		gctl_error(req, "Too few arguments.");
771214118Spjd		return;
772214118Spjd	}
773214118Spjd
774214118Spjd	if (*all) {
775214118Spjd		struct g_geom *gp, *gp2;
776214118Spjd
777214118Spjd		LIST_FOREACH_SAFE(gp, &mp->geom, geom, gp2) {
778214118Spjd			sc = gp->softc;
779214229Spjd			if (sc->sc_flags & G_ELI_FLAG_ONETIME) {
780214229Spjd				G_ELI_DEBUG(0,
781214229Spjd				    "Device %s is using one-time key, suspend not supported, skipping.",
782214229Spjd				    sc->sc_name);
783214118Spjd				continue;
784214229Spjd			}
785214229Spjd			g_eli_suspend_one(sc, req);
786214118Spjd		}
787214118Spjd	} else {
788214118Spjd		const char *prov;
789214118Spjd		char param[16];
790214118Spjd		int i;
791214118Spjd
792214118Spjd		for (i = 0; i < *nargs; i++) {
793214118Spjd			snprintf(param, sizeof(param), "arg%d", i);
794214118Spjd			prov = gctl_get_asciiparam(req, param);
795214118Spjd			if (prov == NULL) {
796214118Spjd				G_ELI_DEBUG(0, "No 'arg%d' argument.", i);
797214118Spjd				continue;
798214118Spjd			}
799214118Spjd
800214118Spjd			sc = g_eli_find_device(mp, prov);
801214118Spjd			if (sc == NULL) {
802214118Spjd				G_ELI_DEBUG(0, "No such provider: %s.", prov);
803214118Spjd				continue;
804214118Spjd			}
805214229Spjd			g_eli_suspend_one(sc, req);
806214118Spjd		}
807214118Spjd	}
808214118Spjd}
809214118Spjd
810214118Spjdstatic void
811214118Spjdg_eli_ctl_resume(struct gctl_req *req, struct g_class *mp)
812214118Spjd{
813214118Spjd	struct g_eli_metadata md;
814214118Spjd	struct g_eli_softc *sc;
815214118Spjd	struct g_provider *pp;
816214118Spjd	struct g_consumer *cp;
817214118Spjd	const char *name;
818214118Spjd	u_char *key, mkey[G_ELI_DATAIVKEYLEN];
819214118Spjd	int *nargs, keysize, error;
820214118Spjd	u_int nkey;
821214118Spjd
822214118Spjd	g_topology_assert();
823214118Spjd
824214118Spjd	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
825214118Spjd	if (nargs == NULL) {
826214118Spjd		gctl_error(req, "No '%s' argument.", "nargs");
827214118Spjd		return;
828214118Spjd	}
829214118Spjd	if (*nargs != 1) {
830214118Spjd		gctl_error(req, "Invalid number of arguments.");
831214118Spjd		return;
832214118Spjd	}
833214118Spjd
834214118Spjd	name = gctl_get_asciiparam(req, "arg0");
835214118Spjd	if (name == NULL) {
836214118Spjd		gctl_error(req, "No 'arg%u' argument.", 0);
837214118Spjd		return;
838214118Spjd	}
839214118Spjd	sc = g_eli_find_device(mp, name);
840214118Spjd	if (sc == NULL) {
841214118Spjd		gctl_error(req, "Provider %s is invalid.", name);
842214118Spjd		return;
843214118Spjd	}
844214118Spjd	cp = LIST_FIRST(&sc->sc_geom->consumer);
845214118Spjd	pp = cp->provider;
846214118Spjd	error = g_eli_read_metadata(mp, pp, &md);
847214118Spjd	if (error != 0) {
848214118Spjd		gctl_error(req, "Cannot read metadata from %s (error=%d).",
849214118Spjd		    name, error);
850214118Spjd		return;
851214118Spjd	}
852214118Spjd	if (md.md_keys == 0x00) {
853214118Spjd		bzero(&md, sizeof(md));
854214118Spjd		gctl_error(req, "No valid keys on %s.", pp->name);
855214118Spjd		return;
856214118Spjd	}
857214118Spjd
858214118Spjd	key = gctl_get_param(req, "key", &keysize);
859214118Spjd	if (key == NULL || keysize != G_ELI_USERKEYLEN) {
860214118Spjd		bzero(&md, sizeof(md));
861214118Spjd		gctl_error(req, "No '%s' argument.", "key");
862214118Spjd		return;
863214118Spjd	}
864214118Spjd
865214118Spjd	error = g_eli_mkey_decrypt(&md, key, mkey, &nkey);
866214118Spjd	bzero(key, keysize);
867214118Spjd	if (error == -1) {
868214118Spjd		bzero(&md, sizeof(md));
869214118Spjd		gctl_error(req, "Wrong key for %s.", pp->name);
870214118Spjd		return;
871214118Spjd	} else if (error > 0) {
872214118Spjd		bzero(&md, sizeof(md));
873214118Spjd		gctl_error(req, "Cannot decrypt Master Key for %s (error=%d).",
874214118Spjd		    pp->name, error);
875214118Spjd		return;
876214118Spjd	}
877214118Spjd	G_ELI_DEBUG(1, "Using Master Key %u for %s.", nkey, pp->name);
878214118Spjd
879214118Spjd	mtx_lock(&sc->sc_queue_mtx);
880214228Spjd	if (!(sc->sc_flags & G_ELI_FLAG_SUSPEND))
881214228Spjd		gctl_error(req, "Device %s is not suspended.", name);
882214228Spjd	else {
883214228Spjd		/* Restore sc_mkey, sc_ekeys, sc_akey and sc_ivkey. */
884214228Spjd		g_eli_mkey_propagate(sc, mkey);
885214228Spjd		sc->sc_flags &= ~G_ELI_FLAG_SUSPEND;
886214228Spjd		G_ELI_DEBUG(1, "Resumed %s.", pp->name);
887214228Spjd		wakeup(sc);
888214228Spjd	}
889214225Spjd	mtx_unlock(&sc->sc_queue_mtx);
890214118Spjd	bzero(mkey, sizeof(mkey));
891214118Spjd	bzero(&md, sizeof(md));
892214118Spjd}
893214118Spjd
894214118Spjdstatic int
895148456Spjdg_eli_kill_one(struct g_eli_softc *sc)
896148456Spjd{
897148456Spjd	struct g_provider *pp;
898148456Spjd	struct g_consumer *cp;
899161127Spjd	int error = 0;
900148456Spjd
901148456Spjd	g_topology_assert();
902148456Spjd
903148456Spjd	if (sc == NULL)
904148456Spjd		return (ENOENT);
905148456Spjd
906148456Spjd	pp = LIST_FIRST(&sc->sc_geom->provider);
907148456Spjd	g_error_provider(pp, ENXIO);
908148456Spjd
909148456Spjd	cp = LIST_FIRST(&sc->sc_geom->consumer);
910148456Spjd	pp = cp->provider;
911148456Spjd
912161127Spjd	if (sc->sc_flags & G_ELI_FLAG_RO) {
913161127Spjd		G_ELI_DEBUG(0, "WARNING: Metadata won't be erased on read-only "
914161127Spjd		    "provider: %s.", pp->name);
915161127Spjd	} else {
916161127Spjd		u_char *sector;
917161127Spjd		u_int i;
918161127Spjd		int err;
919161127Spjd
920161127Spjd		sector = malloc(pp->sectorsize, M_ELI, M_WAITOK);
921161127Spjd		for (i = 0; i <= g_eli_overwrites; i++) {
922161127Spjd			if (i == g_eli_overwrites)
923161127Spjd				bzero(sector, pp->sectorsize);
924161127Spjd			else
925161127Spjd				arc4rand(sector, pp->sectorsize, 0);
926161127Spjd			err = g_write_data(cp, pp->mediasize - pp->sectorsize,
927161127Spjd			    sector, pp->sectorsize);
928161127Spjd			if (err != 0) {
929161127Spjd				G_ELI_DEBUG(0, "Cannot erase metadata on %s "
930161127Spjd				    "(error=%d).", pp->name, err);
931161127Spjd				if (error == 0)
932161127Spjd					error = err;
933161127Spjd			}
934213164Spjd			/*
935213164Spjd			 * Flush write cache so we don't overwrite data N times
936213164Spjd			 * in cache and only once on disk.
937213164Spjd			 */
938213164Spjd			(void)g_io_flush(cp);
939148456Spjd		}
940161127Spjd		free(sector, M_ELI);
941148456Spjd	}
942148456Spjd	if (error == 0)
943148456Spjd		G_ELI_DEBUG(0, "%s has been killed.", pp->name);
944214118Spjd	g_eli_destroy(sc, TRUE);
945148456Spjd	return (error);
946148456Spjd}
947148456Spjd
948148456Spjdstatic void
949148456Spjdg_eli_ctl_kill(struct gctl_req *req, struct g_class *mp)
950148456Spjd{
951148456Spjd	int *all, *nargs;
952148456Spjd	int error;
953148456Spjd
954148456Spjd	g_topology_assert();
955148456Spjd
956148456Spjd	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
957148456Spjd	if (nargs == NULL) {
958148456Spjd		gctl_error(req, "No '%s' argument.", "nargs");
959148456Spjd		return;
960148456Spjd	}
961148456Spjd	all = gctl_get_paraml(req, "all", sizeof(*all));
962148456Spjd	if (all == NULL) {
963148456Spjd		gctl_error(req, "No '%s' argument.", "all");
964148456Spjd		return;
965148456Spjd	}
966148456Spjd	if (!*all && *nargs == 0) {
967148456Spjd		gctl_error(req, "Too few arguments.");
968148456Spjd		return;
969148456Spjd	}
970148456Spjd
971148456Spjd	if (*all) {
972148456Spjd		struct g_geom *gp, *gp2;
973148456Spjd
974148456Spjd		LIST_FOREACH_SAFE(gp, &mp->geom, geom, gp2) {
975148456Spjd			error = g_eli_kill_one(gp->softc);
976148456Spjd			if (error != 0)
977148456Spjd				gctl_error(req, "Not fully done.");
978148456Spjd		}
979148456Spjd	} else {
980148456Spjd		struct g_eli_softc *sc;
981148456Spjd		const char *prov;
982148456Spjd		char param[16];
983148456Spjd		int i;
984148456Spjd
985148456Spjd		for (i = 0; i < *nargs; i++) {
986154463Spjd			snprintf(param, sizeof(param), "arg%d", i);
987148456Spjd			prov = gctl_get_asciiparam(req, param);
988154462Spjd			if (prov == NULL) {
989154462Spjd				G_ELI_DEBUG(0, "No 'arg%d' argument.", i);
990154462Spjd				continue;
991154462Spjd			}
992148456Spjd
993148456Spjd			sc = g_eli_find_device(mp, prov);
994148456Spjd			if (sc == NULL) {
995154463Spjd				G_ELI_DEBUG(0, "No such provider: %s.", prov);
996148456Spjd				continue;
997148456Spjd			}
998148456Spjd			error = g_eli_kill_one(sc);
999148456Spjd			if (error != 0)
1000148456Spjd				gctl_error(req, "Not fully done.");
1001148456Spjd		}
1002148456Spjd	}
1003148456Spjd}
1004148456Spjd
1005148456Spjdvoid
1006148456Spjdg_eli_config(struct gctl_req *req, struct g_class *mp, const char *verb)
1007148456Spjd{
1008148456Spjd	uint32_t *version;
1009148456Spjd
1010148456Spjd	g_topology_assert();
1011148456Spjd
1012148456Spjd	version = gctl_get_paraml(req, "version", sizeof(*version));
1013148456Spjd	if (version == NULL) {
1014148456Spjd		gctl_error(req, "No '%s' argument.", "version");
1015148456Spjd		return;
1016148456Spjd	}
1017221630Spjd	while (*version != G_ELI_VERSION) {
1018221630Spjd		if (G_ELI_VERSION == G_ELI_VERSION_06 &&
1019221630Spjd		    *version == G_ELI_VERSION_05) {
1020221630Spjd			/* Compatible. */
1021221630Spjd			break;
1022221630Spjd		}
1023238116Spjd		if (G_ELI_VERSION == G_ELI_VERSION_07 &&
1024238116Spjd		    (*version == G_ELI_VERSION_05 ||
1025238116Spjd		     *version == G_ELI_VERSION_06)) {
1026238116Spjd			/* Compatible. */
1027238116Spjd			break;
1028238116Spjd		}
1029148456Spjd		gctl_error(req, "Userland and kernel parts are out of sync.");
1030148456Spjd		return;
1031148456Spjd	}
1032148456Spjd
1033148456Spjd	if (strcmp(verb, "attach") == 0)
1034148456Spjd		g_eli_ctl_attach(req, mp);
1035148456Spjd	else if (strcmp(verb, "detach") == 0 || strcmp(verb, "stop") == 0)
1036148456Spjd		g_eli_ctl_detach(req, mp);
1037148456Spjd	else if (strcmp(verb, "onetime") == 0)
1038148456Spjd		g_eli_ctl_onetime(req, mp);
1039162353Spjd	else if (strcmp(verb, "configure") == 0)
1040162353Spjd		g_eli_ctl_configure(req, mp);
1041148456Spjd	else if (strcmp(verb, "setkey") == 0)
1042148456Spjd		g_eli_ctl_setkey(req, mp);
1043148456Spjd	else if (strcmp(verb, "delkey") == 0)
1044148456Spjd		g_eli_ctl_delkey(req, mp);
1045214118Spjd	else if (strcmp(verb, "suspend") == 0)
1046214118Spjd		g_eli_ctl_suspend(req, mp);
1047214118Spjd	else if (strcmp(verb, "resume") == 0)
1048214118Spjd		g_eli_ctl_resume(req, mp);
1049148456Spjd	else if (strcmp(verb, "kill") == 0)
1050148456Spjd		g_eli_ctl_kill(req, mp);
1051148456Spjd	else
1052148456Spjd		gctl_error(req, "Unknown verb.");
1053148456Spjd}
1054