etc/services - sync with NetBSD-8
[minix.git] / minix / lib / libc / sys / ioctl.c
blob26e02066d73151d35a1b32a9ff002ebc509a49d1
1 #include <sys/cdefs.h>
2 #include "namespace.h"
3 #include <lib.h>
4 #include <stdarg.h>
6 #include <sys/ioctl.h>
7 #include <minix/i2c.h>
8 #include <string.h>
9 #include <sys/ioccom.h>
10 #include <stdarg.h>
11 #include <fcntl.h>
12 #include <stdlib.h>
13 #include <minix/if.h>
14 #include <minix/bpf.h>
15 #include <assert.h>
17 static void rewrite_i2c_netbsd_to_minix(minix_i2c_ioctl_exec_t *out,
18 i2c_ioctl_exec_t *in);
19 static void rewrite_i2c_minix_to_netbsd(i2c_ioctl_exec_t *out,
20 minix_i2c_ioctl_exec_t *in);
22 static void rewrite_i2c_netbsd_to_minix(minix_i2c_ioctl_exec_t *out,
23 i2c_ioctl_exec_t *in)
25 memset(out, '\0', sizeof(minix_i2c_ioctl_exec_t));
27 out->iie_op = in->iie_op;
28 out->iie_addr = in->iie_addr;
29 out->iie_cmdlen = I2C_EXEC_MAX_CMDLEN < in->iie_cmdlen ?
30 I2C_EXEC_MAX_CMDLEN : in->iie_cmdlen;
31 out->iie_buflen = I2C_EXEC_MAX_BUFLEN < in->iie_buflen ?
32 I2C_EXEC_MAX_BUFLEN : in->iie_buflen;
34 if (in->iie_cmdlen > 0 && in->iie_cmd != NULL) {
35 memcpy(out->iie_cmd, in->iie_cmd, in->iie_cmdlen);
38 if (in->iie_buflen > 0 && in->iie_buf != NULL) {
39 memcpy(out->iie_buf, in->iie_buf, in->iie_buflen);
43 static void rewrite_i2c_minix_to_netbsd(i2c_ioctl_exec_t *out,
44 minix_i2c_ioctl_exec_t *in)
46 /* the only field that changes is iie_buf, everything else is the same */
47 if (in->iie_buflen > 0 ) {
48 memcpy(out->iie_buf, in->iie_buf, in->iie_buflen);
53 * Convert a network interface related IOCTL with pointers to a flat format
54 * suitable for MINIX3. Return a pointer to the new data on success, or zero
55 * (with errno set) on failure. The original request code is given in
56 * 'request' and must be replaced by the new request code to be used.
58 static vir_bytes
59 ioctl_convert_if_to_minix(void * data, unsigned long * request)
61 struct minix_ifmediareq *mifm;
62 struct ifmediareq *ifm;
63 struct minix_if_clonereq *mifcr;
64 struct if_clonereq *ifcr;
66 switch (*request) {
67 case SIOCGIFMEDIA:
68 ifm = (struct ifmediareq *)data;
70 mifm = (struct minix_ifmediareq *)malloc(sizeof(*mifm));
71 if (mifm != NULL) {
73 * The count may exceed MINIX_IF_MAXMEDIA, and should
74 * be truncated as needed by the IF implementation.
76 memcpy(&mifm->mifm_ifm, ifm, sizeof(*ifm));
78 *request = MINIX_SIOCGIFMEDIA;
79 } else
80 errno = ENOMEM;
82 return (vir_bytes)mifm;
84 case SIOCIFGCLONERS:
85 ifcr = (struct if_clonereq *)data;
87 mifcr = (struct minix_if_clonereq *)malloc(sizeof(*mifcr));
88 if (mifcr != NULL) {
90 * The count may exceed MINIX_IF_MAXCLONERS, and should
91 * be truncated as needed by the IF implementation.
93 memcpy(&mifcr->mifcr_ifcr, ifcr, sizeof(*ifcr));
95 *request = MINIX_SIOCIFGCLONERS;
96 } else
97 errno = ENOMEM;
99 return (vir_bytes)mifcr;
101 default:
102 assert(0);
104 errno = ENOTTY;
105 return 0;
110 * Convert a the result of a network interface related IOCTL with pointers from
111 * the flat format used to make the call to MINIX3. Called on success only.
112 * The given request code is that of the (NetBSD-type) original.
114 static void
115 ioctl_convert_if_from_minix(vir_bytes addr, void * data, unsigned long request)
117 struct minix_ifmediareq *mifm;
118 struct ifmediareq *ifm;
119 struct minix_if_clonereq *mifcr;
120 struct if_clonereq *ifcr;
121 int count;
123 switch (request) {
124 case SIOCGIFMEDIA:
125 mifm = (struct minix_ifmediareq *)addr;
126 ifm = (struct ifmediareq *)data;
128 memcpy(ifm, &mifm->mifm_ifm, sizeof(*ifm));
130 if (ifm->ifm_ulist != NULL && ifm->ifm_count > 0)
131 memcpy(ifm->ifm_ulist, mifm->mifm_list,
132 ifm->ifm_count * sizeof(ifm->ifm_ulist[0]));
134 break;
136 case SIOCIFGCLONERS:
137 mifcr = (struct minix_if_clonereq *)addr;
138 ifcr = (struct if_clonereq *)data;
140 memcpy(ifcr, &mifcr->mifcr_ifcr, sizeof(*ifcr));
142 count = (ifcr->ifcr_count < ifcr->ifcr_total) ?
143 ifcr->ifcr_count : ifcr->ifcr_total;
144 if (ifcr->ifcr_buffer != NULL && count > 0)
145 memcpy(ifcr->ifcr_buffer, mifcr->mifcr_buffer,
146 count * IFNAMSIZ);
148 break;
150 default:
151 assert(0);
156 * Convert a BPF (Berkeley Packet Filter) related IOCTL with pointers to a flat
157 * format suitable for MINIX3. Return a pointer to the new data on success, or
158 * zero (with errno set) on failure. The original request code is given in
159 * 'request' and must be replaced by the new request code to be used.
161 static vir_bytes
162 ioctl_convert_bpf_to_minix(void * data, unsigned long * request)
164 struct minix_bpf_program *mbf;
165 struct bpf_program *bf;
166 struct minix_bpf_dltlist *mbfl;
167 struct bpf_dltlist *bfl;
169 switch (*request) {
170 case BIOCSETF:
171 bf = (struct bpf_program *)data;
173 if (bf->bf_len > __arraycount(mbf->mbf_insns)) {
174 errno = EINVAL;
175 return 0;
178 mbf = (struct minix_bpf_program *)malloc(sizeof(*mbf));
179 if (mbf != NULL) {
180 mbf->mbf_len = bf->bf_len;
181 memcpy(mbf->mbf_insns, bf->bf_insns,
182 bf->bf_len * sizeof(mbf->mbf_insns[0]));
184 *request = MINIX_BIOCSETF;
185 } else
186 errno = ENOMEM;
188 return (vir_bytes)mbf;
190 case BIOCGDLTLIST:
191 bfl = (struct bpf_dltlist *)data;
193 mbfl = (struct minix_bpf_dltlist *)malloc(sizeof(*mbfl));
194 if (mbfl != NULL) {
196 * The length may exceed MINIX_BPF_MAXDLT, and should
197 * be truncated as needed by the BPF implementation.
199 memcpy(&mbfl->mbfl_dltlist, bfl, sizeof(*bfl));
201 *request = MINIX_BIOCGDLTLIST;
202 } else
203 errno = ENOMEM;
205 return (vir_bytes)mbfl;
207 default:
208 assert(0);
210 errno = ENOTTY;
211 return 0;
216 * Convert a the result of BPF (Berkeley Packet Filter) related IOCTL with
217 * pointers from the flat format used to make the call to MINIX3. Called on
218 * success only. The given request code is that of the (NetBSD-type) original.
220 static void
221 ioctl_convert_bpf_from_minix(vir_bytes addr, void * data,
222 unsigned long request)
224 struct minix_bpf_dltlist *mbfl;
225 struct bpf_dltlist *bfl;
227 switch (request) {
228 case BIOCGDLTLIST:
229 mbfl = (struct minix_bpf_dltlist *)addr;
230 bfl = (struct bpf_dltlist *)data;
232 memcpy(bfl, &mbfl->mbfl_dltlist, sizeof(*bfl));
234 if (bfl->bfl_list != NULL && bfl->bfl_len > 0)
235 memcpy(bfl->bfl_list, mbfl->mbfl_list,
236 bfl->bfl_len * sizeof(bfl->bfl_list[0]));
238 break;
240 default:
241 assert(0);
246 * Library implementation of FIOCLEX and FIONCLEX.
248 static int
249 ioctl_to_setfd(int fd, int mask, int val)
251 int fl;
253 if ((fl = fcntl(fd, F_GETFD)) == -1)
254 return -1;
256 fl = (fl & ~mask) | val;
258 return fcntl(fd, F_SETFD, fl);
262 * Library implementation of FIONBIO and FIOASYNC.
264 static int
265 ioctl_to_setfl(int fd, void * data, int sfl)
267 int arg, fl;
269 arg = *(int *)data;
271 if ((fl = fcntl(fd, F_GETFL)) == -1)
272 return -1;
274 if (arg)
275 fl |= sfl;
276 else
277 fl &= ~sfl;
279 return fcntl(fd, F_SETFL, fl & ~O_ACCMODE);
283 * Library implementation of various deprecated IOCTLs. These particular IOCTL
284 * calls change how the file descriptors behave, and have nothing to do with
285 * the actual open file. They should therefore be handled by VFS rather than
286 * individual device drivers. We rewrite them to use fcntl(2) instead here.
288 static int
289 ioctl_to_fcntl(int fd, unsigned long request, void * data)
291 switch (request) {
292 case FIOCLEX:
293 return ioctl_to_setfd(fd, FD_CLOEXEC, FD_CLOEXEC);
294 case FIONCLEX:
295 return ioctl_to_setfd(fd, FD_CLOEXEC, 0);
296 case FIONBIO:
297 return ioctl_to_setfl(fd, data, O_NONBLOCK);
298 case FIOASYNC:
299 return ioctl_to_setfl(fd, data, O_ASYNC);
300 case FIOSETOWN: /* XXX TODO */
301 case FIOGETOWN: /* XXX TODO */
302 default:
303 errno = ENOTTY;
304 return -1;
308 int ioctl(int fd, unsigned long request, ...)
310 minix_i2c_ioctl_exec_t i2c;
311 int r, request_save;
312 message m;
313 vir_bytes addr;
314 void *data;
315 va_list ap;
317 va_start(ap, request);
318 data = va_arg(ap, void *);
319 va_end(ap);
322 * To support compatibility with interfaces on other systems, certain
323 * requests are re-written to flat structures (i.e. without pointers).
325 request_save = request;
327 switch (request) {
328 case FIOCLEX:
329 case FIONCLEX:
330 case FIONBIO:
331 case FIOASYNC:
332 case FIOSETOWN:
333 case FIOGETOWN:
334 return ioctl_to_fcntl(fd, request, data);
336 case I2C_IOCTL_EXEC:
337 rewrite_i2c_netbsd_to_minix(&i2c, data);
338 addr = (vir_bytes) &i2c;
339 request = MINIX_I2C_IOCTL_EXEC;
340 break;
342 case SIOCGIFMEDIA:
343 case SIOCIFGCLONERS:
344 if ((addr = ioctl_convert_if_to_minix(data, &request)) == 0)
345 return -1; /* errno has already been set */
346 break;
348 case BIOCSETF:
349 case BIOCGDLTLIST:
350 if ((addr = ioctl_convert_bpf_to_minix(data, &request)) == 0)
351 return -1; /* errno has already been set */
352 break;
354 default:
355 /* Keep original as-is */
356 addr = (vir_bytes)data;
357 break;
360 memset(&m, 0, sizeof(m));
361 m.m_lc_vfs_ioctl.fd = fd;
362 m.m_lc_vfs_ioctl.req = request;
363 m.m_lc_vfs_ioctl.arg = addr;
365 r = _syscall(VFS_PROC_NR, VFS_IOCTL, &m);
368 * Translate back to original form. Do this on failure as well, as
369 * temporarily allocated resources may have to be freed up again.
371 switch (request_save) {
372 case I2C_IOCTL_EXEC:
373 rewrite_i2c_minix_to_netbsd(data, &i2c);
374 break;
376 case SIOCGIFMEDIA:
377 case SIOCIFGCLONERS:
378 if (r == 0)
379 ioctl_convert_if_from_minix(addr, data, request_save);
380 free((void *)addr);
381 break;
383 case BIOCGDLTLIST:
384 if (r == 0)
385 ioctl_convert_bpf_from_minix(addr, data, request_save);
386 /* FALLTHROUGH */
387 case BIOCSETF:
388 free((void *)addr);
389 break;
391 default:
392 /* Nothing to do */
393 break;
396 return r;