xref: /minix3/minix/lib/libc/sys/ioctl.c (revision ef8d499e2d2af900e9b2ab297171d7b088652482)
1433d6423SLionel Sambuc #include <sys/cdefs.h>
2433d6423SLionel Sambuc #include "namespace.h"
3433d6423SLionel Sambuc #include <lib.h>
4433d6423SLionel Sambuc #include <stdarg.h>
5433d6423SLionel Sambuc 
6433d6423SLionel Sambuc #include <sys/ioctl.h>
7433d6423SLionel Sambuc #include <minix/i2c.h>
8433d6423SLionel Sambuc #include <string.h>
9433d6423SLionel Sambuc #include <sys/ioccom.h>
10433d6423SLionel Sambuc #include <stdarg.h>
11ed223591SDavid van Moolenbroek #include <fcntl.h>
12*ef8d499eSDavid van Moolenbroek #include <stdlib.h>
13*ef8d499eSDavid van Moolenbroek #include <minix/if.h>
14*ef8d499eSDavid van Moolenbroek #include <minix/bpf.h>
15*ef8d499eSDavid van Moolenbroek #include <assert.h>
16433d6423SLionel Sambuc 
17433d6423SLionel Sambuc static void rewrite_i2c_netbsd_to_minix(minix_i2c_ioctl_exec_t *out,
18433d6423SLionel Sambuc     i2c_ioctl_exec_t *in);
19433d6423SLionel Sambuc static void rewrite_i2c_minix_to_netbsd(i2c_ioctl_exec_t *out,
20433d6423SLionel Sambuc     minix_i2c_ioctl_exec_t *in);
21433d6423SLionel Sambuc 
rewrite_i2c_netbsd_to_minix(minix_i2c_ioctl_exec_t * out,i2c_ioctl_exec_t * in)22433d6423SLionel Sambuc static void rewrite_i2c_netbsd_to_minix(minix_i2c_ioctl_exec_t *out,
23433d6423SLionel Sambuc 	i2c_ioctl_exec_t *in)
24433d6423SLionel Sambuc {
25433d6423SLionel Sambuc   memset(out, '\0', sizeof(minix_i2c_ioctl_exec_t));
26433d6423SLionel Sambuc 
27433d6423SLionel Sambuc   out->iie_op = in->iie_op;
28433d6423SLionel Sambuc   out->iie_addr = in->iie_addr;
29433d6423SLionel Sambuc   out->iie_cmdlen = I2C_EXEC_MAX_CMDLEN < in->iie_cmdlen ?
30433d6423SLionel Sambuc   	I2C_EXEC_MAX_CMDLEN : in->iie_cmdlen;
31433d6423SLionel Sambuc   out->iie_buflen = I2C_EXEC_MAX_BUFLEN < in->iie_buflen ?
32433d6423SLionel Sambuc   	I2C_EXEC_MAX_BUFLEN : in->iie_buflen;
33433d6423SLionel Sambuc 
34433d6423SLionel Sambuc   if (in->iie_cmdlen > 0 && in->iie_cmd != NULL) {
35433d6423SLionel Sambuc 	memcpy(out->iie_cmd, in->iie_cmd, in->iie_cmdlen);
36433d6423SLionel Sambuc   }
37433d6423SLionel Sambuc 
38433d6423SLionel Sambuc   if (in->iie_buflen > 0 && in->iie_buf != NULL) {
39433d6423SLionel Sambuc 	memcpy(out->iie_buf, in->iie_buf, in->iie_buflen);
40433d6423SLionel Sambuc   }
41433d6423SLionel Sambuc }
42433d6423SLionel Sambuc 
rewrite_i2c_minix_to_netbsd(i2c_ioctl_exec_t * out,minix_i2c_ioctl_exec_t * in)43433d6423SLionel Sambuc static void rewrite_i2c_minix_to_netbsd(i2c_ioctl_exec_t *out,
44433d6423SLionel Sambuc 	minix_i2c_ioctl_exec_t *in)
45433d6423SLionel Sambuc {
46433d6423SLionel Sambuc   /* the only field that changes is iie_buf, everything else is the same */
4754841c01SEmmanuel Blot   if (in->iie_buflen > 0 ) {
48433d6423SLionel Sambuc 	memcpy(out->iie_buf, in->iie_buf, in->iie_buflen);
49433d6423SLionel Sambuc   }
50433d6423SLionel Sambuc }
51433d6423SLionel Sambuc 
52ed223591SDavid van Moolenbroek /*
53*ef8d499eSDavid van Moolenbroek  * Convert a network interface related IOCTL with pointers to a flat format
54*ef8d499eSDavid van Moolenbroek  * suitable for MINIX3.  Return a pointer to the new data on success, or zero
55*ef8d499eSDavid van Moolenbroek  * (with errno set) on failure.  The original request code is given in
56*ef8d499eSDavid van Moolenbroek  * 'request' and must be replaced by the new request code to be used.
57*ef8d499eSDavid van Moolenbroek  */
58*ef8d499eSDavid van Moolenbroek static vir_bytes
ioctl_convert_if_to_minix(void * data,unsigned long * request)59*ef8d499eSDavid van Moolenbroek ioctl_convert_if_to_minix(void * data, unsigned long * request)
60*ef8d499eSDavid van Moolenbroek {
61*ef8d499eSDavid van Moolenbroek 	struct minix_ifmediareq *mifm;
62*ef8d499eSDavid van Moolenbroek 	struct ifmediareq *ifm;
63*ef8d499eSDavid van Moolenbroek 	struct minix_if_clonereq *mifcr;
64*ef8d499eSDavid van Moolenbroek 	struct if_clonereq *ifcr;
65*ef8d499eSDavid van Moolenbroek 
66*ef8d499eSDavid van Moolenbroek 	switch (*request) {
67*ef8d499eSDavid van Moolenbroek 	case SIOCGIFMEDIA:
68*ef8d499eSDavid van Moolenbroek 		ifm = (struct ifmediareq *)data;
69*ef8d499eSDavid van Moolenbroek 
70*ef8d499eSDavid van Moolenbroek 		mifm = (struct minix_ifmediareq *)malloc(sizeof(*mifm));
71*ef8d499eSDavid van Moolenbroek 		if (mifm != NULL) {
72*ef8d499eSDavid van Moolenbroek 			/*
73*ef8d499eSDavid van Moolenbroek 			 * The count may exceed MINIX_IF_MAXMEDIA, and should
74*ef8d499eSDavid van Moolenbroek 			 * be truncated as needed by the IF implementation.
75*ef8d499eSDavid van Moolenbroek 			 */
76*ef8d499eSDavid van Moolenbroek 			memcpy(&mifm->mifm_ifm, ifm, sizeof(*ifm));
77*ef8d499eSDavid van Moolenbroek 
78*ef8d499eSDavid van Moolenbroek 			*request = MINIX_SIOCGIFMEDIA;
79*ef8d499eSDavid van Moolenbroek 		} else
80*ef8d499eSDavid van Moolenbroek 			errno = ENOMEM;
81*ef8d499eSDavid van Moolenbroek 
82*ef8d499eSDavid van Moolenbroek 		return (vir_bytes)mifm;
83*ef8d499eSDavid van Moolenbroek 
84*ef8d499eSDavid van Moolenbroek 	case SIOCIFGCLONERS:
85*ef8d499eSDavid van Moolenbroek 		ifcr = (struct if_clonereq *)data;
86*ef8d499eSDavid van Moolenbroek 
87*ef8d499eSDavid van Moolenbroek 		mifcr = (struct minix_if_clonereq *)malloc(sizeof(*mifcr));
88*ef8d499eSDavid van Moolenbroek 		if (mifcr != NULL) {
89*ef8d499eSDavid van Moolenbroek 			/*
90*ef8d499eSDavid van Moolenbroek 			 * The count may exceed MINIX_IF_MAXCLONERS, and should
91*ef8d499eSDavid van Moolenbroek 			 * be truncated as needed by the IF implementation.
92*ef8d499eSDavid van Moolenbroek 			 */
93*ef8d499eSDavid van Moolenbroek 			memcpy(&mifcr->mifcr_ifcr, ifcr, sizeof(*ifcr));
94*ef8d499eSDavid van Moolenbroek 
95*ef8d499eSDavid van Moolenbroek 			*request = MINIX_SIOCIFGCLONERS;
96*ef8d499eSDavid van Moolenbroek 		} else
97*ef8d499eSDavid van Moolenbroek 			errno = ENOMEM;
98*ef8d499eSDavid van Moolenbroek 
99*ef8d499eSDavid van Moolenbroek 		return (vir_bytes)mifcr;
100*ef8d499eSDavid van Moolenbroek 
101*ef8d499eSDavid van Moolenbroek 	default:
102*ef8d499eSDavid van Moolenbroek 		assert(0);
103*ef8d499eSDavid van Moolenbroek 
104*ef8d499eSDavid van Moolenbroek 		errno = ENOTTY;
105*ef8d499eSDavid van Moolenbroek 		return 0;
106*ef8d499eSDavid van Moolenbroek 	}
107*ef8d499eSDavid van Moolenbroek }
108*ef8d499eSDavid van Moolenbroek 
109*ef8d499eSDavid van Moolenbroek /*
110*ef8d499eSDavid van Moolenbroek  * Convert a the result of a network interface related IOCTL with pointers from
111*ef8d499eSDavid van Moolenbroek  * the flat format used to make the call to MINIX3.  Called on success only.
112*ef8d499eSDavid van Moolenbroek  * The given request code is that of the (NetBSD-type) original.
113*ef8d499eSDavid van Moolenbroek  */
114*ef8d499eSDavid van Moolenbroek static void
ioctl_convert_if_from_minix(vir_bytes addr,void * data,unsigned long request)115*ef8d499eSDavid van Moolenbroek ioctl_convert_if_from_minix(vir_bytes addr, void * data, unsigned long request)
116*ef8d499eSDavid van Moolenbroek {
117*ef8d499eSDavid van Moolenbroek 	struct minix_ifmediareq *mifm;
118*ef8d499eSDavid van Moolenbroek 	struct ifmediareq *ifm;
119*ef8d499eSDavid van Moolenbroek 	struct minix_if_clonereq *mifcr;
120*ef8d499eSDavid van Moolenbroek 	struct if_clonereq *ifcr;
121*ef8d499eSDavid van Moolenbroek 	int count;
122*ef8d499eSDavid van Moolenbroek 
123*ef8d499eSDavid van Moolenbroek 	switch (request) {
124*ef8d499eSDavid van Moolenbroek 	case SIOCGIFMEDIA:
125*ef8d499eSDavid van Moolenbroek 		mifm = (struct minix_ifmediareq *)addr;
126*ef8d499eSDavid van Moolenbroek 		ifm = (struct ifmediareq *)data;
127*ef8d499eSDavid van Moolenbroek 
128*ef8d499eSDavid van Moolenbroek 		memcpy(ifm, &mifm->mifm_ifm, sizeof(*ifm));
129*ef8d499eSDavid van Moolenbroek 
130*ef8d499eSDavid van Moolenbroek 		if (ifm->ifm_ulist != NULL && ifm->ifm_count > 0)
131*ef8d499eSDavid van Moolenbroek 			memcpy(ifm->ifm_ulist, mifm->mifm_list,
132*ef8d499eSDavid van Moolenbroek 			    ifm->ifm_count * sizeof(ifm->ifm_ulist[0]));
133*ef8d499eSDavid van Moolenbroek 
134*ef8d499eSDavid van Moolenbroek 		break;
135*ef8d499eSDavid van Moolenbroek 
136*ef8d499eSDavid van Moolenbroek 	case SIOCIFGCLONERS:
137*ef8d499eSDavid van Moolenbroek 		mifcr = (struct minix_if_clonereq *)addr;
138*ef8d499eSDavid van Moolenbroek 		ifcr = (struct if_clonereq *)data;
139*ef8d499eSDavid van Moolenbroek 
140*ef8d499eSDavid van Moolenbroek 		memcpy(ifcr, &mifcr->mifcr_ifcr, sizeof(*ifcr));
141*ef8d499eSDavid van Moolenbroek 
142*ef8d499eSDavid van Moolenbroek 		count = (ifcr->ifcr_count < ifcr->ifcr_total) ?
143*ef8d499eSDavid van Moolenbroek 		    ifcr->ifcr_count : ifcr->ifcr_total;
144*ef8d499eSDavid van Moolenbroek 		if (ifcr->ifcr_buffer != NULL && count > 0)
145*ef8d499eSDavid van Moolenbroek 			memcpy(ifcr->ifcr_buffer, mifcr->mifcr_buffer,
146*ef8d499eSDavid van Moolenbroek 			    count * IFNAMSIZ);
147*ef8d499eSDavid van Moolenbroek 
148*ef8d499eSDavid van Moolenbroek 		break;
149*ef8d499eSDavid van Moolenbroek 
150*ef8d499eSDavid van Moolenbroek 	default:
151*ef8d499eSDavid van Moolenbroek 		assert(0);
152*ef8d499eSDavid van Moolenbroek 	}
153*ef8d499eSDavid van Moolenbroek }
154*ef8d499eSDavid van Moolenbroek 
155*ef8d499eSDavid van Moolenbroek /*
156*ef8d499eSDavid van Moolenbroek  * Convert a BPF (Berkeley Packet Filter) related IOCTL with pointers to a flat
157*ef8d499eSDavid van Moolenbroek  * format suitable for MINIX3.  Return a pointer to the new data on success, or
158*ef8d499eSDavid van Moolenbroek  * zero (with errno set) on failure.  The original request code is given in
159*ef8d499eSDavid van Moolenbroek  * 'request' and must be replaced by the new request code to be used.
160*ef8d499eSDavid van Moolenbroek  */
161*ef8d499eSDavid van Moolenbroek static vir_bytes
ioctl_convert_bpf_to_minix(void * data,unsigned long * request)162*ef8d499eSDavid van Moolenbroek ioctl_convert_bpf_to_minix(void * data, unsigned long * request)
163*ef8d499eSDavid van Moolenbroek {
164*ef8d499eSDavid van Moolenbroek 	struct minix_bpf_program *mbf;
165*ef8d499eSDavid van Moolenbroek 	struct bpf_program *bf;
166*ef8d499eSDavid van Moolenbroek 	struct minix_bpf_dltlist *mbfl;
167*ef8d499eSDavid van Moolenbroek 	struct bpf_dltlist *bfl;
168*ef8d499eSDavid van Moolenbroek 
169*ef8d499eSDavid van Moolenbroek 	switch (*request) {
170*ef8d499eSDavid van Moolenbroek 	case BIOCSETF:
171*ef8d499eSDavid van Moolenbroek 		bf = (struct bpf_program *)data;
172*ef8d499eSDavid van Moolenbroek 
173*ef8d499eSDavid van Moolenbroek 		if (bf->bf_len > __arraycount(mbf->mbf_insns)) {
174*ef8d499eSDavid van Moolenbroek 			errno = EINVAL;
175*ef8d499eSDavid van Moolenbroek 			return 0;
176*ef8d499eSDavid van Moolenbroek 		}
177*ef8d499eSDavid van Moolenbroek 
178*ef8d499eSDavid van Moolenbroek 		mbf = (struct minix_bpf_program *)malloc(sizeof(*mbf));
179*ef8d499eSDavid van Moolenbroek 		if (mbf != NULL) {
180*ef8d499eSDavid van Moolenbroek 			mbf->mbf_len = bf->bf_len;
181*ef8d499eSDavid van Moolenbroek 			memcpy(mbf->mbf_insns, bf->bf_insns,
182*ef8d499eSDavid van Moolenbroek 			    bf->bf_len * sizeof(mbf->mbf_insns[0]));
183*ef8d499eSDavid van Moolenbroek 
184*ef8d499eSDavid van Moolenbroek 			*request = MINIX_BIOCSETF;
185*ef8d499eSDavid van Moolenbroek 		} else
186*ef8d499eSDavid van Moolenbroek 			errno = ENOMEM;
187*ef8d499eSDavid van Moolenbroek 
188*ef8d499eSDavid van Moolenbroek 		return (vir_bytes)mbf;
189*ef8d499eSDavid van Moolenbroek 
190*ef8d499eSDavid van Moolenbroek 	case BIOCGDLTLIST:
191*ef8d499eSDavid van Moolenbroek 		bfl = (struct bpf_dltlist *)data;
192*ef8d499eSDavid van Moolenbroek 
193*ef8d499eSDavid van Moolenbroek 		mbfl = (struct minix_bpf_dltlist *)malloc(sizeof(*mbfl));
194*ef8d499eSDavid van Moolenbroek 		if (mbfl != NULL) {
195*ef8d499eSDavid van Moolenbroek 			/*
196*ef8d499eSDavid van Moolenbroek 			 * The length may exceed MINIX_BPF_MAXDLT, and should
197*ef8d499eSDavid van Moolenbroek 			 * be truncated as needed by the BPF implementation.
198*ef8d499eSDavid van Moolenbroek 			 */
199*ef8d499eSDavid van Moolenbroek 			memcpy(&mbfl->mbfl_dltlist, bfl, sizeof(*bfl));
200*ef8d499eSDavid van Moolenbroek 
201*ef8d499eSDavid van Moolenbroek 			*request = MINIX_BIOCGDLTLIST;
202*ef8d499eSDavid van Moolenbroek 		} else
203*ef8d499eSDavid van Moolenbroek 			errno = ENOMEM;
204*ef8d499eSDavid van Moolenbroek 
205*ef8d499eSDavid van Moolenbroek 		return (vir_bytes)mbfl;
206*ef8d499eSDavid van Moolenbroek 
207*ef8d499eSDavid van Moolenbroek 	default:
208*ef8d499eSDavid van Moolenbroek 		assert(0);
209*ef8d499eSDavid van Moolenbroek 
210*ef8d499eSDavid van Moolenbroek 		errno = ENOTTY;
211*ef8d499eSDavid van Moolenbroek 		return 0;
212*ef8d499eSDavid van Moolenbroek 	}
213*ef8d499eSDavid van Moolenbroek }
214*ef8d499eSDavid van Moolenbroek 
215*ef8d499eSDavid van Moolenbroek /*
216*ef8d499eSDavid van Moolenbroek  * Convert a the result of BPF (Berkeley Packet Filter) related IOCTL with
217*ef8d499eSDavid van Moolenbroek  * pointers from the flat format used to make the call to MINIX3.  Called on
218*ef8d499eSDavid van Moolenbroek  * success only.  The given request code is that of the (NetBSD-type) original.
219*ef8d499eSDavid van Moolenbroek  */
220*ef8d499eSDavid van Moolenbroek static void
ioctl_convert_bpf_from_minix(vir_bytes addr,void * data,unsigned long request)221*ef8d499eSDavid van Moolenbroek ioctl_convert_bpf_from_minix(vir_bytes addr, void * data,
222*ef8d499eSDavid van Moolenbroek 	unsigned long request)
223*ef8d499eSDavid van Moolenbroek {
224*ef8d499eSDavid van Moolenbroek 	struct minix_bpf_dltlist *mbfl;
225*ef8d499eSDavid van Moolenbroek 	struct bpf_dltlist *bfl;
226*ef8d499eSDavid van Moolenbroek 
227*ef8d499eSDavid van Moolenbroek 	switch (request) {
228*ef8d499eSDavid van Moolenbroek 	case BIOCGDLTLIST:
229*ef8d499eSDavid van Moolenbroek 		mbfl = (struct minix_bpf_dltlist *)addr;
230*ef8d499eSDavid van Moolenbroek 		bfl = (struct bpf_dltlist *)data;
231*ef8d499eSDavid van Moolenbroek 
232*ef8d499eSDavid van Moolenbroek 		memcpy(bfl, &mbfl->mbfl_dltlist, sizeof(*bfl));
233*ef8d499eSDavid van Moolenbroek 
234*ef8d499eSDavid van Moolenbroek 		if (bfl->bfl_list != NULL && bfl->bfl_len > 0)
235*ef8d499eSDavid van Moolenbroek 			memcpy(bfl->bfl_list, mbfl->mbfl_list,
236*ef8d499eSDavid van Moolenbroek 			    bfl->bfl_len * sizeof(bfl->bfl_list[0]));
237*ef8d499eSDavid van Moolenbroek 
238*ef8d499eSDavid van Moolenbroek 		break;
239*ef8d499eSDavid van Moolenbroek 
240*ef8d499eSDavid van Moolenbroek 	default:
241*ef8d499eSDavid van Moolenbroek 		assert(0);
242*ef8d499eSDavid van Moolenbroek 	}
243*ef8d499eSDavid van Moolenbroek }
244*ef8d499eSDavid van Moolenbroek 
245*ef8d499eSDavid van Moolenbroek /*
246ed223591SDavid van Moolenbroek  * Library implementation of FIOCLEX and FIONCLEX.
247ed223591SDavid van Moolenbroek  */
248ed223591SDavid van Moolenbroek static int
ioctl_to_setfd(int fd,int mask,int val)249ed223591SDavid van Moolenbroek ioctl_to_setfd(int fd, int mask, int val)
250ed223591SDavid van Moolenbroek {
251ed223591SDavid van Moolenbroek 	int fl;
252ed223591SDavid van Moolenbroek 
253ed223591SDavid van Moolenbroek 	if ((fl = fcntl(fd, F_GETFD)) == -1)
254ed223591SDavid van Moolenbroek 		return -1;
255ed223591SDavid van Moolenbroek 
256ed223591SDavid van Moolenbroek 	fl = (fl & ~mask) | val;
257ed223591SDavid van Moolenbroek 
258ed223591SDavid van Moolenbroek 	return fcntl(fd, F_SETFD, fl);
259ed223591SDavid van Moolenbroek }
260ed223591SDavid van Moolenbroek 
261ed223591SDavid van Moolenbroek /*
262ed223591SDavid van Moolenbroek  * Library implementation of FIONBIO and FIOASYNC.
263ed223591SDavid van Moolenbroek  */
264ed223591SDavid van Moolenbroek static int
ioctl_to_setfl(int fd,void * data,int sfl)265ed223591SDavid van Moolenbroek ioctl_to_setfl(int fd, void * data, int sfl)
266ed223591SDavid van Moolenbroek {
267ed223591SDavid van Moolenbroek 	int arg, fl;
268ed223591SDavid van Moolenbroek 
269ed223591SDavid van Moolenbroek 	arg = *(int *)data;
270ed223591SDavid van Moolenbroek 
271ed223591SDavid van Moolenbroek 	if ((fl = fcntl(fd, F_GETFL)) == -1)
272ed223591SDavid van Moolenbroek 		return -1;
273ed223591SDavid van Moolenbroek 
274ed223591SDavid van Moolenbroek 	if (arg)
275ed223591SDavid van Moolenbroek 		fl |= sfl;
276ed223591SDavid van Moolenbroek 	else
277ed223591SDavid van Moolenbroek 		fl &= ~sfl;
278ed223591SDavid van Moolenbroek 
279ed223591SDavid van Moolenbroek 	return fcntl(fd, F_SETFL, fl & ~O_ACCMODE);
280ed223591SDavid van Moolenbroek }
281ed223591SDavid van Moolenbroek 
282ed223591SDavid van Moolenbroek /*
283ed223591SDavid van Moolenbroek  * Library implementation of various deprecated IOCTLs.  These particular IOCTL
284ed223591SDavid van Moolenbroek  * calls change how the file descriptors behave, and have nothing to do with
285ed223591SDavid van Moolenbroek  * the actual open file.  They should therefore be handled by VFS rather than
286ed223591SDavid van Moolenbroek  * individual device drivers.  We rewrite them to use fcntl(2) instead here.
287ed223591SDavid van Moolenbroek  */
288ed223591SDavid van Moolenbroek static int
ioctl_to_fcntl(int fd,unsigned long request,void * data)289ed223591SDavid van Moolenbroek ioctl_to_fcntl(int fd, unsigned long request, void * data)
290ed223591SDavid van Moolenbroek {
291ed223591SDavid van Moolenbroek 	switch (request) {
292ed223591SDavid van Moolenbroek 	case FIOCLEX:
293ed223591SDavid van Moolenbroek 		return ioctl_to_setfd(fd, FD_CLOEXEC, FD_CLOEXEC);
294ed223591SDavid van Moolenbroek 	case FIONCLEX:
295ed223591SDavid van Moolenbroek 		return ioctl_to_setfd(fd, FD_CLOEXEC, 0);
296ed223591SDavid van Moolenbroek 	case FIONBIO:
297ed223591SDavid van Moolenbroek 		return ioctl_to_setfl(fd, data, O_NONBLOCK);
298ed223591SDavid van Moolenbroek 	case FIOASYNC:
299ed223591SDavid van Moolenbroek 		return ioctl_to_setfl(fd, data, O_ASYNC);
300ed223591SDavid van Moolenbroek 	case FIOSETOWN: /* XXX TODO */
301ed223591SDavid van Moolenbroek 	case FIOGETOWN: /* XXX TODO */
302ed223591SDavid van Moolenbroek 	default:
303ed223591SDavid van Moolenbroek 		errno = ENOTTY;
304ed223591SDavid van Moolenbroek 		return -1;
305ed223591SDavid van Moolenbroek 	}
306ed223591SDavid van Moolenbroek }
307ed223591SDavid van Moolenbroek 
ioctl(int fd,unsigned long request,...)308433d6423SLionel Sambuc int     ioctl(int fd, unsigned long request, ...)
309433d6423SLionel Sambuc {
310*ef8d499eSDavid van Moolenbroek   minix_i2c_ioctl_exec_t i2c;
311433d6423SLionel Sambuc   int r, request_save;
312433d6423SLionel Sambuc   message m;
313433d6423SLionel Sambuc   vir_bytes addr;
314433d6423SLionel Sambuc   void *data;
315433d6423SLionel Sambuc   va_list ap;
316433d6423SLionel Sambuc 
317433d6423SLionel Sambuc   va_start(ap, request);
318433d6423SLionel Sambuc   data = va_arg(ap, void *);
319ed223591SDavid van Moolenbroek   va_end(ap);
320433d6423SLionel Sambuc 
321433d6423SLionel Sambuc   /*
322433d6423SLionel Sambuc    * To support compatibility with interfaces on other systems, certain
323433d6423SLionel Sambuc    * requests are re-written to flat structures (i.e. without pointers).
324433d6423SLionel Sambuc    */
325433d6423SLionel Sambuc   request_save = request;
326433d6423SLionel Sambuc 
327433d6423SLionel Sambuc   switch (request) {
328ed223591SDavid van Moolenbroek 	case FIOCLEX:
329ed223591SDavid van Moolenbroek 	case FIONCLEX:
330ed223591SDavid van Moolenbroek 	case FIONBIO:
331ed223591SDavid van Moolenbroek 	case FIOASYNC:
332ed223591SDavid van Moolenbroek 	case FIOSETOWN:
333ed223591SDavid van Moolenbroek 	case FIOGETOWN:
334ed223591SDavid van Moolenbroek 		return ioctl_to_fcntl(fd, request, data);
335ed223591SDavid van Moolenbroek 
336433d6423SLionel Sambuc 	case I2C_IOCTL_EXEC:
337433d6423SLionel Sambuc 		rewrite_i2c_netbsd_to_minix(&i2c, data);
338433d6423SLionel Sambuc 		addr = (vir_bytes) &i2c;
339433d6423SLionel Sambuc 		request = MINIX_I2C_IOCTL_EXEC;
340433d6423SLionel Sambuc 		break;
341*ef8d499eSDavid van Moolenbroek 
342*ef8d499eSDavid van Moolenbroek 	case SIOCGIFMEDIA:
343*ef8d499eSDavid van Moolenbroek 	case SIOCIFGCLONERS:
344*ef8d499eSDavid van Moolenbroek 		if ((addr = ioctl_convert_if_to_minix(data, &request)) == 0)
345*ef8d499eSDavid van Moolenbroek 			return -1;	/* errno has already been set */
346*ef8d499eSDavid van Moolenbroek 		break;
347*ef8d499eSDavid van Moolenbroek 
348*ef8d499eSDavid van Moolenbroek 	case BIOCSETF:
349*ef8d499eSDavid van Moolenbroek 	case BIOCGDLTLIST:
350*ef8d499eSDavid van Moolenbroek 		if ((addr = ioctl_convert_bpf_to_minix(data, &request)) == 0)
351*ef8d499eSDavid van Moolenbroek 			return -1;	/* errno has already been set */
352*ef8d499eSDavid van Moolenbroek 		break;
353*ef8d499eSDavid van Moolenbroek 
354433d6423SLionel Sambuc 	default:
355433d6423SLionel Sambuc 		/* Keep original as-is */
3565dd8da10SDavid van Moolenbroek 		addr = (vir_bytes)data;
357433d6423SLionel Sambuc 		break;
358433d6423SLionel Sambuc   }
359433d6423SLionel Sambuc 
360433d6423SLionel Sambuc   memset(&m, 0, sizeof(m));
361433d6423SLionel Sambuc   m.m_lc_vfs_ioctl.fd = fd;
362433d6423SLionel Sambuc   m.m_lc_vfs_ioctl.req = request;
363433d6423SLionel Sambuc   m.m_lc_vfs_ioctl.arg = addr;
364433d6423SLionel Sambuc 
365433d6423SLionel Sambuc   r = _syscall(VFS_PROC_NR, VFS_IOCTL, &m);
366433d6423SLionel Sambuc 
367*ef8d499eSDavid van Moolenbroek   /*
368*ef8d499eSDavid van Moolenbroek    * Translate back to original form.  Do this on failure as well, as
369*ef8d499eSDavid van Moolenbroek    * temporarily allocated resources may have to be freed up again.
370*ef8d499eSDavid van Moolenbroek    */
371433d6423SLionel Sambuc   switch (request_save) {
372433d6423SLionel Sambuc 	case I2C_IOCTL_EXEC:
373433d6423SLionel Sambuc 		rewrite_i2c_minix_to_netbsd(data, &i2c);
374433d6423SLionel Sambuc 		break;
375*ef8d499eSDavid van Moolenbroek 
376*ef8d499eSDavid van Moolenbroek 	case SIOCGIFMEDIA:
377*ef8d499eSDavid van Moolenbroek 	case SIOCIFGCLONERS:
378*ef8d499eSDavid van Moolenbroek 		if (r == 0)
379*ef8d499eSDavid van Moolenbroek 			ioctl_convert_if_from_minix(addr, data, request_save);
380*ef8d499eSDavid van Moolenbroek 		free((void *)addr);
381*ef8d499eSDavid van Moolenbroek 		break;
382*ef8d499eSDavid van Moolenbroek 
383*ef8d499eSDavid van Moolenbroek 	case BIOCGDLTLIST:
384*ef8d499eSDavid van Moolenbroek 		if (r == 0)
385*ef8d499eSDavid van Moolenbroek 			ioctl_convert_bpf_from_minix(addr, data, request_save);
386*ef8d499eSDavid van Moolenbroek 		/* FALLTHROUGH */
387*ef8d499eSDavid van Moolenbroek 	case BIOCSETF:
388*ef8d499eSDavid van Moolenbroek 		free((void *)addr);
389*ef8d499eSDavid van Moolenbroek 		break;
390*ef8d499eSDavid van Moolenbroek 
391433d6423SLionel Sambuc 	default:
392433d6423SLionel Sambuc 		/* Nothing to do */
393433d6423SLionel Sambuc 		break;
394433d6423SLionel Sambuc   }
395433d6423SLionel Sambuc 
396433d6423SLionel Sambuc   return r;
397433d6423SLionel Sambuc }
398