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