Home | History | Annotate | Line # | Download | only in dev
bio.c revision 1.9.12.1
      1 /*	$NetBSD: bio.c,v 1.9.12.1 2014/05/22 11:40:19 yamt 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.9.12.1 2014/05/22 11:40:19 yamt 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 	device_t bm_dev;
     52 	int (*bm_ioctl)(device_t, u_long, void *);
     53 };
     54 
     55 static 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 static int	bioclose(dev_t, int, int, struct lwp *);
     61 static int	bioioctl(dev_t, u_long, void *, int, struct lwp *);
     62 static int	bioopen(dev_t, int, int, struct lwp *);
     63 
     64 static int	bio_delegate_ioctl(void *, u_long, void *);
     65 static struct	bio_mapping *bio_lookup(char *);
     66 static int	bio_validate(void *);
     67 
     68 void	bioattach(int);
     69 
     70 const struct cdevsw bio_cdevsw = {
     71         .d_open = bioopen,
     72 	.d_close = bioclose,
     73 	.d_read = noread,
     74 	.d_write = nowrite,
     75 	.d_ioctl = bioioctl,
     76         .d_stop = nostop,
     77 	.d_tty = notty,
     78 	.d_poll = nopoll,
     79 	.d_mmap = nommap,
     80 	.d_kqfilter = nokqfilter,
     81 	.d_flag = D_OTHER | D_MPSAFE
     82 };
     83 
     84 
     85 static void
     86 bio_initialize(void)
     87 {
     88 	if (bio_lock_initialized)
     89 		return;
     90 
     91 	mutex_init(&bio_lock, MUTEX_DEFAULT, IPL_VM);
     92 	bio_lock_initialized = true;
     93 }
     94 
     95 void
     96 bioattach(int nunits)
     97 {
     98 	if (!bio_lock_initialized)
     99 		bio_initialize();
    100 }
    101 
    102 static int
    103 bioopen(dev_t dev, int flags, int mode, struct lwp *l)
    104 {
    105 	return 0;
    106 }
    107 
    108 static int
    109 bioclose(dev_t dev, int flags, int mode, struct lwp *l)
    110 {
    111 	return 0;
    112 }
    113 
    114 static int
    115 bioioctl(dev_t dev, u_long cmd, void *addr, int flag, struct  lwp *l)
    116 {
    117 	struct bio_locate *locate;
    118 	struct bio_common *common;
    119 	char name[16];
    120 	int error;
    121 
    122 	switch(cmd) {
    123 	case BIOCLOCATE:
    124 	case BIOCINQ:
    125 	case BIOCDISK:
    126 	case BIOCDISK_NOVOL:
    127 	case BIOCVOL:
    128 #ifdef COMPAT_30
    129 	case OBIOCDISK:
    130 	case OBIOCVOL:
    131 #endif
    132 		error = kauth_authorize_device_passthru(l->l_cred, dev,
    133 		    KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_READCONF, addr);
    134 		if (error)
    135 			return error;
    136 		break;
    137 	case BIOCBLINK:
    138 	case BIOCSETSTATE:
    139 	case BIOCVOLOPS:
    140 		error = kauth_authorize_device_passthru(l->l_cred, dev,
    141 		    KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_WRITECONF, addr);
    142 		if (error)
    143 			return error;
    144 		break;
    145 	case BIOCALARM: {
    146 		struct bioc_alarm *alarm = (struct bioc_alarm *)addr;
    147 		switch (alarm->ba_opcode) {
    148 		case BIOC_SADISABLE:
    149 		case BIOC_SAENABLE:
    150 		case BIOC_SASILENCE:
    151 		case BIOC_SATEST:
    152 			error = kauth_authorize_device_passthru(l->l_cred, dev,
    153 			    KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_WRITECONF, addr);
    154 			if (error)
    155 				return error;
    156 			break;
    157 		case BIOC_GASTATUS:
    158 			error = kauth_authorize_device_passthru(l->l_cred, dev,
    159 			    KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_READCONF, addr);
    160 			if (error)
    161 				return error;
    162 			break;
    163 		default:
    164 			return EINVAL;
    165 		}
    166 		break;
    167 	}
    168 	default:
    169 		return ENOTTY;
    170 	}
    171 
    172 	switch (cmd) {
    173 	case BIOCLOCATE:
    174 		locate = addr;
    175 		error = copyinstr(locate->bl_name, name, sizeof(name), NULL);
    176 		if (error != 0)
    177 			return error;
    178 		locate->bl_cookie = bio_lookup(name);
    179 		if (locate->bl_cookie == NULL)
    180 			return ENOENT;
    181 		break;
    182 
    183 	default:
    184 		common = addr;
    185 		mutex_enter(&bio_lock);
    186 		if (!bio_validate(common->bc_cookie)) {
    187 			mutex_exit(&bio_lock);
    188 			return ENOENT;
    189 		}
    190 		mutex_exit(&bio_lock);
    191 #ifdef COMPAT_30
    192 		switch (cmd) {
    193 		case OBIOCDISK: {
    194 			struct bioc_disk *bd =
    195 			    malloc(sizeof(*bd), M_DEVBUF, M_WAITOK|M_ZERO);
    196 
    197 			(void)memcpy(bd, addr, sizeof(struct obioc_disk));
    198 			error = bio_delegate_ioctl(common->bc_cookie,
    199 			    BIOCDISK, bd);
    200 			if (error) {
    201 				free(bd, M_DEVBUF);
    202 				return error;
    203 			}
    204 
    205 			(void)memcpy(addr, bd, sizeof(struct obioc_disk));
    206 			free(bd, M_DEVBUF);
    207 			return 0;
    208 		}
    209 		case OBIOCVOL: {
    210 			struct bioc_vol *bv =
    211 			    malloc(sizeof(*bv), M_DEVBUF, M_WAITOK|M_ZERO);
    212 
    213 			(void)memcpy(bv, addr, sizeof(struct obioc_vol));
    214 			error = bio_delegate_ioctl(common->bc_cookie,
    215 			    BIOCVOL, bv);
    216 			if (error) {
    217 				free(bv, M_DEVBUF);
    218 				return error;
    219 			}
    220 
    221 			(void)memcpy(addr, bv, sizeof(struct obioc_vol));
    222 			free(bv, M_DEVBUF);
    223 			return 0;
    224 		}
    225 		}
    226 #endif
    227 		error = bio_delegate_ioctl(common->bc_cookie, cmd, addr);
    228 		return error;
    229 	}
    230 	return 0;
    231 }
    232 
    233 int
    234 bio_register(device_t dev, int (*ioctl)(device_t, u_long, void *))
    235 {
    236 	struct bio_mapping *bm;
    237 
    238 	if (!bio_lock_initialized)
    239 		bio_initialize();
    240 
    241 	bm = malloc(sizeof(*bm), M_DEVBUF, M_NOWAIT|M_ZERO);
    242 	if (bm == NULL)
    243 		return ENOMEM;
    244 	bm->bm_dev = dev;
    245 	bm->bm_ioctl = ioctl;
    246 	mutex_enter(&bio_lock);
    247 	LIST_INSERT_HEAD(&bios, bm, bm_link);
    248 	mutex_exit(&bio_lock);
    249 	return 0;
    250 }
    251 
    252 void
    253 bio_unregister(device_t dev)
    254 {
    255 	struct bio_mapping *bm, *next;
    256 
    257 	mutex_enter(&bio_lock);
    258 	for (bm = LIST_FIRST(&bios); bm != NULL; bm = next) {
    259 		next = LIST_NEXT(bm, bm_link);
    260 
    261 		if (dev == bm->bm_dev) {
    262 			LIST_REMOVE(bm, bm_link);
    263 			free(bm, M_DEVBUF);
    264 		}
    265 	}
    266 	mutex_exit(&bio_lock);
    267 }
    268 
    269 static struct bio_mapping *
    270 bio_lookup(char *name)
    271 {
    272 	struct bio_mapping *bm;
    273 
    274 	mutex_enter(&bio_lock);
    275 	LIST_FOREACH(bm, &bios, bm_link) {
    276 		if (strcmp(name, device_xname(bm->bm_dev)) == 0) {
    277 			mutex_exit(&bio_lock);
    278 			return bm;
    279 		}
    280 	}
    281 	mutex_exit(&bio_lock);
    282 	return NULL;
    283 }
    284 
    285 static int
    286 bio_validate(void *cookie)
    287 {
    288 	struct bio_mapping *bm;
    289 
    290 	LIST_FOREACH(bm, &bios, bm_link)
    291 		if (bm == cookie)
    292 			return 1;
    293 
    294 	return 0;
    295 }
    296 
    297 static int
    298 bio_delegate_ioctl(void *cookie, u_long cmd, void *addr)
    299 {
    300 	struct bio_mapping *bm = cookie;
    301 
    302 	return bm->bm_ioctl(bm->bm_dev, cmd, addr);
    303 }
    304