xref: /freebsd/sys/compat/freebsd32/freebsd32_ioctl.c (revision 6469bdcdb6a5968dc7edfcfb495d427b4bfdb3dd)
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 2008 David E. O'Brien
5  * 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  * 3. Neither the name of the author nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34 
35 #include <sys/param.h>
36 #include <sys/capsicum.h>
37 #include <sys/cdio.h>
38 #include <sys/fcntl.h>
39 #include <sys/filio.h>
40 #include <sys/file.h>
41 #include <sys/ioccom.h>
42 #include <sys/malloc.h>
43 #include <sys/memrange.h>
44 #include <sys/pciio.h>
45 #include <sys/proc.h>
46 #include <sys/syscall.h>
47 #include <sys/syscallsubr.h>
48 #include <sys/sysctl.h>
49 #include <sys/sysent.h>
50 #include <sys/sysproto.h>
51 #include <sys/systm.h>
52 #include <sys/uio.h>
53 
54 #include <compat/freebsd32/freebsd32.h>
55 #include <compat/freebsd32/freebsd32_ioctl.h>
56 #include <compat/freebsd32/freebsd32_proto.h>
57 
58 CTASSERT(sizeof(struct ioc_read_toc_entry32) == 8);
59 CTASSERT(sizeof(struct mem_range_op32) == 12);
60 CTASSERT(sizeof(struct pci_conf_io32) == 36);
61 CTASSERT(sizeof(struct pci_match_conf32) == 44);
62 CTASSERT(sizeof(struct pci_conf32) == 44);
63 
64 static int
65 freebsd32_ioctl_ioc_read_toc(struct thread *td,
66     struct freebsd32_ioctl_args *uap, struct file *fp)
67 {
68 	struct ioc_read_toc_entry toce;
69 	struct ioc_read_toc_entry32 toce32;
70 	int error;
71 
72 	if ((error = copyin(uap->data, &toce32, sizeof(toce32))))
73 		return (error);
74 	CP(toce32, toce, address_format);
75 	CP(toce32, toce, starting_track);
76 	CP(toce32, toce, data_len);
77 	PTRIN_CP(toce32, toce, data);
78 
79 	if ((error = fo_ioctl(fp, CDIOREADTOCENTRYS, (caddr_t)&toce,
80 	    td->td_ucred, td))) {
81 		CP(toce, toce32, address_format);
82 		CP(toce, toce32, starting_track);
83 		CP(toce, toce32, data_len);
84 		PTROUT_CP(toce, toce32, data);
85 		error = copyout(&toce32, uap->data, sizeof(toce32));
86 	}
87 	return error;
88 }
89 
90 static int
91 freebsd32_ioctl_fiodgname(struct thread *td,
92     struct freebsd32_ioctl_args *uap, struct file *fp)
93 {
94 	struct fiodgname_arg fgn;
95 	struct fiodgname_arg32 fgn32;
96 	int error;
97 
98 	if ((error = copyin(uap->data, &fgn32, sizeof fgn32)) != 0)
99 		return (error);
100 	CP(fgn32, fgn, len);
101 	PTRIN_CP(fgn32, fgn, buf);
102 	error = fo_ioctl(fp, FIODGNAME, (caddr_t)&fgn, td->td_ucred, td);
103 	return (error);
104 }
105 
106 static int
107 freebsd32_ioctl_memrange(struct thread *td,
108     struct freebsd32_ioctl_args *uap, struct file *fp)
109 {
110 	struct mem_range_op mro;
111 	struct mem_range_op32 mro32;
112 	int error;
113 	u_long com;
114 
115 	if ((error = copyin(uap->data, &mro32, sizeof(mro32))) != 0)
116 		return (error);
117 
118 	PTRIN_CP(mro32, mro, mo_desc);
119 	CP(mro32, mro, mo_arg[0]);
120 	CP(mro32, mro, mo_arg[1]);
121 
122 	com = 0;
123 	switch (uap->com) {
124 	case MEMRANGE_GET32:
125 		com = MEMRANGE_GET;
126 		break;
127 
128 	case MEMRANGE_SET32:
129 		com = MEMRANGE_SET;
130 		break;
131 
132 	default:
133 		panic("%s: unknown MEMRANGE %#x", __func__, uap->com);
134 	}
135 
136 	if ((error = fo_ioctl(fp, com, (caddr_t)&mro, td->td_ucred, td)) != 0)
137 		return (error);
138 
139 	if ( (com & IOC_OUT) ) {
140 		CP(mro, mro32, mo_arg[0]);
141 		CP(mro, mro32, mo_arg[1]);
142 
143 		error = copyout(&mro32, uap->data, sizeof(mro32));
144 	}
145 
146 	return (error);
147 }
148 
149 static int
150 freebsd32_ioctl_pciocgetconf(struct thread *td,
151     struct freebsd32_ioctl_args *uap, struct file *fp)
152 {
153 	struct pci_conf_io pci;
154 	struct pci_conf_io32 pci32;
155 	struct pci_match_conf32 pmc32;
156 	struct pci_match_conf32 *pmc32p;
157 	struct pci_match_conf pmc;
158 	struct pci_match_conf *pmcp;
159 	struct pci_conf32 pc32;
160 	struct pci_conf32 *pc32p;
161 	struct pci_conf pc;
162 	struct pci_conf *pcp;
163 	u_int32_t i;
164 	u_int32_t npat_to_convert;
165 	u_int32_t nmatch_to_convert;
166 	vm_offset_t addr;
167 	int error;
168 
169 	if ((error = copyin(uap->data, &pci32, sizeof(pci32))) != 0)
170 		return (error);
171 
172 	CP(pci32, pci, num_patterns);
173 	CP(pci32, pci, offset);
174 	CP(pci32, pci, generation);
175 
176 	npat_to_convert = pci32.pat_buf_len / sizeof(struct pci_match_conf32);
177 	pci.pat_buf_len = npat_to_convert * sizeof(struct pci_match_conf);
178 	pci.patterns = NULL;
179 	nmatch_to_convert = pci32.match_buf_len / sizeof(struct pci_conf32);
180 	pci.match_buf_len = nmatch_to_convert * sizeof(struct pci_conf);
181 	pci.matches = NULL;
182 
183 	if ((error = copyout_map(td, &addr, pci.pat_buf_len)) != 0)
184 		goto cleanup;
185 	pci.patterns = (struct pci_match_conf *)addr;
186 	if ((error = copyout_map(td, &addr, pci.match_buf_len)) != 0)
187 		goto cleanup;
188 	pci.matches = (struct pci_conf *)addr;
189 
190 	npat_to_convert = min(npat_to_convert, pci.num_patterns);
191 
192 	for (i = 0, pmc32p = (struct pci_match_conf32 *)PTRIN(pci32.patterns),
193 	     pmcp = pci.patterns;
194 	     i < npat_to_convert; i++, pmc32p++, pmcp++) {
195 		if ((error = copyin(pmc32p, &pmc32, sizeof(pmc32))) != 0)
196 			goto cleanup;
197 		CP(pmc32,pmc,pc_sel);
198 		strlcpy(pmc.pd_name, pmc32.pd_name, sizeof(pmc.pd_name));
199 		CP(pmc32,pmc,pd_unit);
200 		CP(pmc32,pmc,pc_vendor);
201 		CP(pmc32,pmc,pc_device);
202 		CP(pmc32,pmc,pc_class);
203 		CP(pmc32,pmc,flags);
204 		if ((error = copyout(&pmc, pmcp, sizeof(pmc))) != 0)
205 			goto cleanup;
206 	}
207 
208 	if ((error = fo_ioctl(fp, PCIOCGETCONF, (caddr_t)&pci,
209 			      td->td_ucred, td)) != 0)
210 		goto cleanup;
211 
212 	nmatch_to_convert = min(nmatch_to_convert, pci.num_matches);
213 
214 	for (i = 0, pcp = pci.matches,
215 	     pc32p = (struct pci_conf32 *)PTRIN(pci32.matches);
216 	     i < nmatch_to_convert; i++, pcp++, pc32p++) {
217 		if ((error = copyin(pcp, &pc, sizeof(pc))) != 0)
218 			goto cleanup;
219 		CP(pc,pc32,pc_sel);
220 		CP(pc,pc32,pc_hdr);
221 		CP(pc,pc32,pc_subvendor);
222 		CP(pc,pc32,pc_subdevice);
223 		CP(pc,pc32,pc_vendor);
224 		CP(pc,pc32,pc_device);
225 		CP(pc,pc32,pc_class);
226 		CP(pc,pc32,pc_subclass);
227 		CP(pc,pc32,pc_progif);
228 		CP(pc,pc32,pc_revid);
229 		strlcpy(pc32.pd_name, pc.pd_name, sizeof(pc32.pd_name));
230 		CP(pc,pc32,pd_unit);
231 		if ((error = copyout(&pc32, pc32p, sizeof(pc32))) != 0)
232 			goto cleanup;
233 	}
234 
235 	CP(pci, pci32, num_matches);
236 	CP(pci, pci32, offset);
237 	CP(pci, pci32, generation);
238 	CP(pci, pci32, status);
239 
240 	error = copyout(&pci32, uap->data, sizeof(pci32));
241 
242 cleanup:
243 	if (pci.patterns)
244 		copyout_unmap(td, (vm_offset_t)pci.patterns, pci.pat_buf_len);
245 	if (pci.matches)
246 		copyout_unmap(td, (vm_offset_t)pci.matches, pci.match_buf_len);
247 
248 	return (error);
249 }
250 
251 static int
252 freebsd32_ioctl_sg(struct thread *td,
253     struct freebsd32_ioctl_args *uap, struct file *fp)
254 {
255 	struct sg_io_hdr io;
256 	struct sg_io_hdr32 io32;
257 	int error;
258 
259 	if ((error = copyin(uap->data, &io32, sizeof(io32))) != 0)
260 		return (error);
261 
262 	CP(io32, io, interface_id);
263 	CP(io32, io, dxfer_direction);
264 	CP(io32, io, cmd_len);
265 	CP(io32, io, mx_sb_len);
266 	CP(io32, io, iovec_count);
267 	CP(io32, io, dxfer_len);
268 	PTRIN_CP(io32, io, dxferp);
269 	PTRIN_CP(io32, io, cmdp);
270 	PTRIN_CP(io32, io, sbp);
271 	CP(io32, io, timeout);
272 	CP(io32, io, flags);
273 	CP(io32, io, pack_id);
274 	PTRIN_CP(io32, io, usr_ptr);
275 	CP(io32, io, status);
276 	CP(io32, io, masked_status);
277 	CP(io32, io, msg_status);
278 	CP(io32, io, sb_len_wr);
279 	CP(io32, io, host_status);
280 	CP(io32, io, driver_status);
281 	CP(io32, io, resid);
282 	CP(io32, io, duration);
283 	CP(io32, io, info);
284 
285 	if ((error = fo_ioctl(fp, SG_IO, (caddr_t)&io, td->td_ucred, td)) != 0)
286 		return (error);
287 
288 	CP(io, io32, interface_id);
289 	CP(io, io32, dxfer_direction);
290 	CP(io, io32, cmd_len);
291 	CP(io, io32, mx_sb_len);
292 	CP(io, io32, iovec_count);
293 	CP(io, io32, dxfer_len);
294 	PTROUT_CP(io, io32, dxferp);
295 	PTROUT_CP(io, io32, cmdp);
296 	PTROUT_CP(io, io32, sbp);
297 	CP(io, io32, timeout);
298 	CP(io, io32, flags);
299 	CP(io, io32, pack_id);
300 	PTROUT_CP(io, io32, usr_ptr);
301 	CP(io, io32, status);
302 	CP(io, io32, masked_status);
303 	CP(io, io32, msg_status);
304 	CP(io, io32, sb_len_wr);
305 	CP(io, io32, host_status);
306 	CP(io, io32, driver_status);
307 	CP(io, io32, resid);
308 	CP(io, io32, duration);
309 	CP(io, io32, info);
310 
311 	error = copyout(&io32, uap->data, sizeof(io32));
312 
313 	return (error);
314 }
315 
316 int
317 freebsd32_ioctl(struct thread *td, struct freebsd32_ioctl_args *uap)
318 {
319 	struct ioctl_args ap /*{
320 		int	fd;
321 		u_long	com;
322 		caddr_t	data;
323 	}*/ ;
324 	struct file *fp;
325 	cap_rights_t rights;
326 	int error;
327 
328 	error = fget(td, uap->fd, cap_rights_init(&rights, CAP_IOCTL), &fp);
329 	if (error != 0)
330 		return (error);
331 	if ((fp->f_flag & (FREAD | FWRITE)) == 0) {
332 		fdrop(fp, td);
333 		return (EBADF);
334 	}
335 
336 	switch (uap->com) {
337 	case CDIOREADTOCENTRYS_32:
338 		error = freebsd32_ioctl_ioc_read_toc(td, uap, fp);
339 		break;
340 
341 	case FIODGNAME_32:
342 		error = freebsd32_ioctl_fiodgname(td, uap, fp);
343 		break;
344 
345 	case MEMRANGE_GET32:	/* FALLTHROUGH */
346 	case MEMRANGE_SET32:
347 		error = freebsd32_ioctl_memrange(td, uap, fp);
348 		break;
349 
350 	case PCIOCGETCONF_32:
351 		error = freebsd32_ioctl_pciocgetconf(td, uap, fp);
352 		break;
353 
354 	case SG_IO_32:
355 		error = freebsd32_ioctl_sg(td, uap, fp);
356 		break;
357 
358 	default:
359 		fdrop(fp, td);
360 		ap.fd = uap->fd;
361 		ap.com = uap->com;
362 		PTRIN_CP(*uap, ap, data);
363 		return sys_ioctl(td, &ap);
364 	}
365 
366 	fdrop(fp, td);
367 	return error;
368 }
369