bio.c revision 1.1.4.2 1 /* $NetBSD: bio.c,v 1.1.4.2 2007/05/08 10:45:04 pavel 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.1.4.2 2007/05/08 10:45:04 pavel Exp $");
32
33 #include <sys/param.h>
34 #include <sys/conf.h>
35 #include <sys/device.h>
36 #include <sys/event.h>
37 #include <sys/ioctl.h>
38 #include <sys/malloc.h>
39 #include <sys/queue.h>
40 #include <sys/systm.h>
41 #include <sys/proc.h>
42 #include <sys/kauth.h>
43
44 #include <dev/biovar.h>
45
46 struct bio_mapping {
47 LIST_ENTRY(bio_mapping) bm_link;
48 struct device *bm_dev;
49 int (*bm_ioctl)(struct device *, u_long, caddr_t);
50 };
51
52 LIST_HEAD(, bio_mapping) bios = LIST_HEAD_INITIALIZER(bios);
53
54 void bioattach(int);
55 int bioclose(dev_t, int, int, struct lwp *);
56 int bioioctl(dev_t, u_long, caddr_t, int, struct lwp *);
57 int bioopen(dev_t, int, int, struct lwp *);
58
59 int bio_delegate_ioctl(struct bio_mapping *, u_long, void *);
60 struct bio_mapping *bio_lookup(char *);
61 int bio_validate(void *);
62
63 const struct cdevsw bio_cdevsw = {
64 bioopen, bioclose, noread, nowrite, bioioctl,
65 nostop, notty, nopoll, nommap, nokqfilter, 0
66 };
67
68
69 void
70 bioattach(int nunits)
71 {
72 }
73
74 int
75 bioopen(dev_t dev, int flags, int mode, struct lwp *l)
76 {
77 return (0);
78 }
79
80 int
81 bioclose(dev_t dev, int flags, int mode, struct lwp *l)
82 {
83 return (0);
84 }
85
86 int
87 bioioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct lwp *l)
88 {
89 struct bio_locate *locate;
90 struct bio_common *common;
91 char name[16];
92 int error, s;
93
94 switch(cmd) {
95 case BIOCLOCATE:
96 case BIOCINQ:
97 case BIOCDISK:
98 case BIOCVOL:
99 error = kauth_authorize_device_passthru(l->l_cred, dev,
100 KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_READCONF, addr);
101 if (error)
102 return (error);
103 break;
104 case BIOCBLINK:
105 case BIOCSETSTATE:
106 error = kauth_authorize_device_passthru(l->l_cred, dev,
107 KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_WRITECONF, addr);
108 if (error)
109 return (error);
110 break;
111 case BIOCALARM: {
112 struct bioc_alarm *alarm = (struct bioc_alarm *)addr;
113 switch (alarm->ba_opcode) {
114 case BIOC_SADISABLE:
115 case BIOC_SAENABLE:
116 case BIOC_SASILENCE:
117 case BIOC_SATEST:
118 error = kauth_authorize_device_passthru(l->l_cred, dev,
119 KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_WRITECONF, addr);
120 if (error)
121 return (error);
122 break;
123 case BIOC_GASTATUS:
124 error = kauth_authorize_device_passthru(l->l_cred, dev,
125 KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_READCONF, addr);
126 if (error)
127 return (error);
128 break;
129 default:
130 return EINVAL;
131 }
132 break;
133 }
134 default:
135 return ENOTTY;
136 }
137
138 switch (cmd) {
139 case BIOCLOCATE:
140 locate = (struct bio_locate *)addr;
141 error = copyinstr(locate->bl_name, name, 16, NULL);
142 if (error != 0)
143 return (error);
144 locate->bl_cookie = bio_lookup(name);
145 if (locate->bl_cookie == NULL)
146 return (ENOENT);
147 break;
148
149 default:
150 common = (struct bio_common *)addr;
151 s = splbio();
152 if (!bio_validate(common->bc_cookie)) {
153 splx(s);
154 return (ENOENT);
155 }
156 error = bio_delegate_ioctl(
157 (struct bio_mapping *)common->bc_cookie, cmd, addr);
158 splx(s);
159 return (error);
160 }
161 return (0);
162 }
163
164 int
165 bio_register(struct device *dev, int (*ioctl)(struct device *, u_long, caddr_t))
166 {
167 struct bio_mapping *bm;
168 int s;
169
170 MALLOC(bm, struct bio_mapping *, sizeof *bm, M_DEVBUF, M_NOWAIT);
171 if (bm == NULL)
172 return (ENOMEM);
173 bm->bm_dev = dev;
174 bm->bm_ioctl = ioctl;
175 s = splbio();
176 LIST_INSERT_HEAD(&bios, bm, bm_link);
177 splx(s);
178 return (0);
179 }
180
181 void
182 bio_unregister(struct device *dev)
183 {
184 struct bio_mapping *bm, *next;
185 int s;
186
187 s = splbio();
188 for (bm = LIST_FIRST(&bios); bm != NULL; bm = next) {
189 next = LIST_NEXT(bm, bm_link);
190
191 if (dev == bm->bm_dev) {
192 LIST_REMOVE(bm, bm_link);
193 free(bm, M_DEVBUF);
194 }
195 }
196 splx(s);
197 }
198
199 struct bio_mapping *
200 bio_lookup(char *name)
201 {
202 struct bio_mapping *bm;
203 int s;
204
205 s = splbio();
206 LIST_FOREACH(bm, &bios, bm_link) {
207 if (strcmp(name, bm->bm_dev->dv_xname) == 0) {
208 splx(s);
209 return (bm);
210 }
211 }
212 splx(s);
213 return (NULL);
214 }
215
216 int
217 bio_validate(void *cookie)
218 {
219 struct bio_mapping *bm;
220
221 LIST_FOREACH(bm, &bios, bm_link) {
222 if (bm == cookie) {
223 return (1);
224 }
225 }
226 return (0);
227 }
228
229 int
230 bio_delegate_ioctl(struct bio_mapping *bm, u_long cmd, void *addr)
231 {
232
233 return (bm->bm_ioctl(bm->bm_dev, cmd, addr));
234 }
235