Home | History | Annotate | Line # | Download | only in dev
bio.c revision 1.5
      1 /*	$NetBSD: bio.c,v 1.5 2008/01/02 23:45:03 xtraeme Exp $ */
      2 /*	$OpenBSD: bio.c,v 1.9 2007/03/20 02:35:55 marco Exp $	*/
      3 
      4 /*
      5  * Copyright (c) 2002 Niklas Hallqvist.  All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26  */
     27 
     28 /* A device controller ioctl tunnelling device.  */
     29 
     30 #include <sys/cdefs.h>
     31 __KERNEL_RCSID(0, "$NetBSD: bio.c,v 1.5 2008/01/02 23:45:03 xtraeme Exp $");
     32 
     33 #include "opt_compat_netbsd.h"
     34 
     35 #include <sys/param.h>
     36 #include <sys/conf.h>
     37 #include <sys/device.h>
     38 #include <sys/event.h>
     39 #include <sys/ioctl.h>
     40 #include <sys/malloc.h>
     41 #include <sys/queue.h>
     42 #include <sys/systm.h>
     43 #include <sys/mutex.h>
     44 #include <sys/proc.h>
     45 #include <sys/kauth.h>
     46 
     47 #include <dev/biovar.h>
     48 
     49 struct bio_mapping {
     50 	LIST_ENTRY(bio_mapping) bm_link;
     51 	struct device *bm_dev;
     52 	int (*bm_ioctl)(struct device *, u_long, void *);
     53 };
     54 
     55 LIST_HEAD(, bio_mapping) bios = LIST_HEAD_INITIALIZER(bios);
     56 static kmutex_t bio_lock;
     57 static bool bio_lock_initialized = false;
     58 
     59 static void bio_initialize(void);
     60 void	bioattach(int);
     61 int	bioclose(dev_t, int, int, struct lwp *);
     62 int	bioioctl(dev_t, u_long, void *, int, struct lwp *);
     63 int	bioopen(dev_t, int, int, struct lwp *);
     64 
     65 int	bio_delegate_ioctl(struct bio_mapping *, u_long, void *);
     66 struct	bio_mapping *bio_lookup(char *);
     67 int	bio_validate(void *);
     68 
     69 const struct cdevsw bio_cdevsw = {
     70         bioopen, bioclose, noread, nowrite, bioioctl,
     71         nostop, notty, nopoll, nommap, nokqfilter, 0
     72 };
     73 
     74 
     75 void
     76 bio_initialize(void)
     77 {
     78 	if (bio_lock_initialized)
     79 		return;
     80 
     81 	mutex_init(&bio_lock, MUTEX_DEFAULT, IPL_VM);
     82 	bio_lock_initialized = true;
     83 }
     84 
     85 void
     86 bioattach(int nunits)
     87 {
     88 	if (!bio_lock_initialized)
     89 		bio_initialize();
     90 }
     91 
     92 int
     93 bioopen(dev_t dev, int flags, int mode, struct lwp *l)
     94 {
     95 	return 0;
     96 }
     97 
     98 int
     99 bioclose(dev_t dev, int flags, int mode, struct lwp *l)
    100 {
    101 	return 0;
    102 }
    103 
    104 int
    105 bioioctl(dev_t dev, u_long cmd, void *addr, int flag, struct  lwp *l)
    106 {
    107 	struct bio_locate *locate;
    108 	struct bio_common *common;
    109 #ifdef COMPAT_30
    110 	struct bioc_disk *bd;
    111 	struct bioc_vol *bv;
    112 #endif
    113 	char name[16];
    114 	int error;
    115 
    116 	switch(cmd) {
    117 	case BIOCLOCATE:
    118 	case BIOCINQ:
    119 	case BIOCDISK:
    120 	case BIOCDISK_NOVOL:
    121 	case BIOCVOL:
    122 #ifdef COMPAT_30
    123 	case OBIOCDISK:
    124 	case OBIOCVOL:
    125 #endif
    126 		error = kauth_authorize_device_passthru(l->l_cred, dev,
    127 		    KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_READCONF, addr);
    128 		if (error)
    129 			return error;
    130 		break;
    131 	case BIOCBLINK:
    132 	case BIOCSETSTATE:
    133 	case BIOCVOLOPS:
    134 		error = kauth_authorize_device_passthru(l->l_cred, dev,
    135 		    KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_WRITECONF, addr);
    136 		if (error)
    137 			return error;
    138 		break;
    139 	case BIOCALARM: {
    140 		struct bioc_alarm *alarm = (struct bioc_alarm *)addr;
    141 		switch (alarm->ba_opcode) {
    142 		case BIOC_SADISABLE:
    143 		case BIOC_SAENABLE:
    144 		case BIOC_SASILENCE:
    145 		case BIOC_SATEST:
    146 			error = kauth_authorize_device_passthru(l->l_cred, dev,
    147 			    KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_WRITECONF, addr);
    148 			if (error)
    149 				return error;
    150 			break;
    151 		case BIOC_GASTATUS:
    152 			error = kauth_authorize_device_passthru(l->l_cred, dev,
    153 			    KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_READCONF, addr);
    154 			if (error)
    155 				return error;
    156 			break;
    157 		default:
    158 			return EINVAL;
    159 		}
    160 		break;
    161 	}
    162 	default:
    163 		return ENOTTY;
    164 	}
    165 
    166 	switch (cmd) {
    167 	case BIOCLOCATE:
    168 		locate = (struct bio_locate *)addr;
    169 		error = copyinstr(locate->bl_name, name, sizeof(name), NULL);
    170 		if (error != 0)
    171 			return error;
    172 		locate->bl_cookie = bio_lookup(name);
    173 		if (locate->bl_cookie == NULL)
    174 			return ENOENT;
    175 		break;
    176 
    177 	default:
    178 		common = (struct bio_common *)addr;
    179 		mutex_enter(&bio_lock);
    180 		if (!bio_validate(common->bc_cookie)) {
    181 			mutex_exit(&bio_lock);
    182 			return ENOENT;
    183 		}
    184 		mutex_exit(&bio_lock);
    185 #ifdef COMPAT_30
    186 		switch (cmd) {
    187 		case OBIOCDISK:
    188 		    {
    189 			bd = malloc(sizeof(*bd), M_DEVBUF, M_WAITOK|M_ZERO);
    190 
    191 			memcpy(bd, addr, sizeof(struct obioc_disk));
    192 			error = bio_delegate_ioctl(
    193 			    (struct bio_mapping *)common->bc_cookie,
    194 			    BIOCDISK, bd);
    195 			if (error) {
    196 				free(bd, M_DEVBUF);
    197 				return error;
    198 			}
    199 
    200 			memcpy(addr, bd, sizeof(struct obioc_disk));
    201 			free(bd, M_DEVBUF);
    202 			return 0;
    203 		    }
    204 		case OBIOCVOL:
    205 		    {
    206 			bv = malloc(sizeof(*bv), M_DEVBUF, M_WAITOK|M_ZERO);
    207 
    208 			memcpy(bv, addr, sizeof(struct obioc_vol));
    209 			error = bio_delegate_ioctl(
    210 			    (struct bio_mapping *)common->bc_cookie,
    211 			    BIOCVOL, bv);
    212 			if (error) {
    213 				free(bv, M_DEVBUF);
    214 				return error;
    215 			}
    216 
    217 			memcpy(addr, bv, sizeof(struct obioc_vol));
    218 			free(bv, M_DEVBUF);
    219 			return 0;
    220 		    }
    221 		}
    222 #endif
    223 		error = bio_delegate_ioctl(
    224 		    (struct bio_mapping *)common->bc_cookie, cmd, addr);
    225 		return error;
    226 	}
    227 	return 0;
    228 }
    229 
    230 int
    231 bio_register(struct device *dev, int (*ioctl)(struct device *, u_long, void *))
    232 {
    233 	struct bio_mapping *bm;
    234 
    235 	if (!bio_lock_initialized)
    236 		bio_initialize();
    237 
    238 	bm = malloc(sizeof(*bm), M_DEVBUF, M_NOWAIT|M_ZERO);
    239 	if (bm == NULL)
    240 		return ENOMEM;
    241 	bm->bm_dev = dev;
    242 	bm->bm_ioctl = ioctl;
    243 	mutex_enter(&bio_lock);
    244 	LIST_INSERT_HEAD(&bios, bm, bm_link);
    245 	mutex_exit(&bio_lock);
    246 	return 0;
    247 }
    248 
    249 void
    250 bio_unregister(struct device *dev)
    251 {
    252 	struct bio_mapping *bm, *next;
    253 
    254 	mutex_enter(&bio_lock);
    255 	for (bm = LIST_FIRST(&bios); bm != NULL; bm = next) {
    256 		next = LIST_NEXT(bm, bm_link);
    257 
    258 		if (dev == bm->bm_dev) {
    259 			LIST_REMOVE(bm, bm_link);
    260 			free(bm, M_DEVBUF);
    261 		}
    262 	}
    263 	mutex_exit(&bio_lock);
    264 }
    265 
    266 struct bio_mapping *
    267 bio_lookup(char *name)
    268 {
    269 	struct bio_mapping *bm;
    270 
    271 	mutex_enter(&bio_lock);
    272 	LIST_FOREACH(bm, &bios, bm_link) {
    273 		if (strcmp(name, bm->bm_dev->dv_xname) == 0) {
    274 			mutex_exit(&bio_lock);
    275 			return bm;
    276 		}
    277 	}
    278 	mutex_exit(&bio_lock);
    279 	return NULL;
    280 }
    281 
    282 int
    283 bio_validate(void *cookie)
    284 {
    285 	struct bio_mapping *bm;
    286 
    287 	LIST_FOREACH(bm, &bios, bm_link)
    288 		if (bm == cookie)
    289 			return 1;
    290 
    291 	return 0;
    292 }
    293 
    294 int
    295 bio_delegate_ioctl(struct bio_mapping *bm, u_long cmd, void *addr)
    296 {
    297 
    298 	return bm->bm_ioctl(bm->bm_dev, cmd, addr);
    299 }
    300