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