1 /*-
2 * Copyright (c) 2015 Dmitry Chagin <dchagin@FreeBSD.org>
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 */
25
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
28
29 #include <opt_inet6.h>
30
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/conf.h>
34 #include <sys/ctype.h>
35 #include <sys/file.h>
36 #include <sys/filedesc.h>
37 #include <sys/jail.h>
38 #include <sys/lock.h>
39 #include <sys/malloc.h>
40 #include <sys/poll.h>
41 #include <sys/proc.h>
42 #include <sys/signalvar.h>
43 #include <sys/socket.h>
44 #include <sys/socketvar.h>
45
46 #include <net/if.h>
47 #include <net/if_var.h>
48 #include <net/if_dl.h>
49 #include <net/if_types.h>
50 #include <netlink/netlink.h>
51
52 #include <sys/un.h>
53 #include <netinet/in.h>
54
55 #include <compat/linux/linux.h>
56 #include <compat/linux/linux_common.h>
57 #include <compat/linux/linux_mib.h>
58 #include <compat/linux/linux_util.h>
59
60 CTASSERT(LINUX_IFNAMSIZ == IFNAMSIZ);
61
62 static int bsd_to_linux_sigtbl[LINUX_SIGTBLSZ] = {
63 LINUX_SIGHUP, /* SIGHUP */
64 LINUX_SIGINT, /* SIGINT */
65 LINUX_SIGQUIT, /* SIGQUIT */
66 LINUX_SIGILL, /* SIGILL */
67 LINUX_SIGTRAP, /* SIGTRAP */
68 LINUX_SIGABRT, /* SIGABRT */
69 0, /* SIGEMT */
70 LINUX_SIGFPE, /* SIGFPE */
71 LINUX_SIGKILL, /* SIGKILL */
72 LINUX_SIGBUS, /* SIGBUS */
73 LINUX_SIGSEGV, /* SIGSEGV */
74 LINUX_SIGSYS, /* SIGSYS */
75 LINUX_SIGPIPE, /* SIGPIPE */
76 LINUX_SIGALRM, /* SIGALRM */
77 LINUX_SIGTERM, /* SIGTERM */
78 LINUX_SIGURG, /* SIGURG */
79 LINUX_SIGSTOP, /* SIGSTOP */
80 LINUX_SIGTSTP, /* SIGTSTP */
81 LINUX_SIGCONT, /* SIGCONT */
82 LINUX_SIGCHLD, /* SIGCHLD */
83 LINUX_SIGTTIN, /* SIGTTIN */
84 LINUX_SIGTTOU, /* SIGTTOU */
85 LINUX_SIGIO, /* SIGIO */
86 LINUX_SIGXCPU, /* SIGXCPU */
87 LINUX_SIGXFSZ, /* SIGXFSZ */
88 LINUX_SIGVTALRM,/* SIGVTALRM */
89 LINUX_SIGPROF, /* SIGPROF */
90 LINUX_SIGWINCH, /* SIGWINCH */
91 0, /* SIGINFO */
92 LINUX_SIGUSR1, /* SIGUSR1 */
93 LINUX_SIGUSR2 /* SIGUSR2 */
94 };
95
96 #define LINUX_SIGPWREMU (SIGRTMIN + (LINUX_SIGRTMAX - LINUX_SIGRTMIN) + 1)
97
98 static int linux_to_bsd_sigtbl[LINUX_SIGTBLSZ] = {
99 SIGHUP, /* LINUX_SIGHUP */
100 SIGINT, /* LINUX_SIGINT */
101 SIGQUIT, /* LINUX_SIGQUIT */
102 SIGILL, /* LINUX_SIGILL */
103 SIGTRAP, /* LINUX_SIGTRAP */
104 SIGABRT, /* LINUX_SIGABRT */
105 SIGBUS, /* LINUX_SIGBUS */
106 SIGFPE, /* LINUX_SIGFPE */
107 SIGKILL, /* LINUX_SIGKILL */
108 SIGUSR1, /* LINUX_SIGUSR1 */
109 SIGSEGV, /* LINUX_SIGSEGV */
110 SIGUSR2, /* LINUX_SIGUSR2 */
111 SIGPIPE, /* LINUX_SIGPIPE */
112 SIGALRM, /* LINUX_SIGALRM */
113 SIGTERM, /* LINUX_SIGTERM */
114 SIGBUS, /* LINUX_SIGSTKFLT */
115 SIGCHLD, /* LINUX_SIGCHLD */
116 SIGCONT, /* LINUX_SIGCONT */
117 SIGSTOP, /* LINUX_SIGSTOP */
118 SIGTSTP, /* LINUX_SIGTSTP */
119 SIGTTIN, /* LINUX_SIGTTIN */
120 SIGTTOU, /* LINUX_SIGTTOU */
121 SIGURG, /* LINUX_SIGURG */
122 SIGXCPU, /* LINUX_SIGXCPU */
123 SIGXFSZ, /* LINUX_SIGXFSZ */
124 SIGVTALRM, /* LINUX_SIGVTALARM */
125 SIGPROF, /* LINUX_SIGPROF */
126 SIGWINCH, /* LINUX_SIGWINCH */
127 SIGIO, /* LINUX_SIGIO */
128 /*
129 * FreeBSD does not have SIGPWR signal, map Linux SIGPWR signal
130 * to the first unused FreeBSD signal number. Since Linux supports
131 * signals from 1 to 64 we are ok here as our SIGRTMIN = 65.
132 */
133 LINUX_SIGPWREMU,/* LINUX_SIGPWR */
134 SIGSYS /* LINUX_SIGSYS */
135 };
136
137 static struct cdev *dev_shm_cdev;
138 static struct cdevsw dev_shm_cdevsw = {
139 .d_version = D_VERSION,
140 .d_name = "dev_shm",
141 };
142
143 /*
144 * Map Linux RT signals to the FreeBSD RT signals.
145 */
146 static inline int
147 linux_to_bsd_rt_signal(int sig)
148 {
149
150 return (SIGRTMIN + sig - LINUX_SIGRTMIN);
151 }
152
153 static inline int
154 bsd_to_linux_rt_signal(int sig)
155 {
156
157 return (sig - SIGRTMIN + LINUX_SIGRTMIN);
158 }
159
160 int
161 linux_to_bsd_signal(int sig)
162 {
163
164 KASSERT(sig > 0 && sig <= LINUX_SIGRTMAX, ("invalid Linux signal %d\n", sig));
165
166 if (sig < LINUX_SIGRTMIN)
167 return (linux_to_bsd_sigtbl[_SIG_IDX(sig)]);
168
169 return (linux_to_bsd_rt_signal(sig));
170 }
171
172 int
173 bsd_to_linux_signal(int sig)
174 {
175
176 if (sig <= LINUX_SIGTBLSZ)
177 return (bsd_to_linux_sigtbl[_SIG_IDX(sig)]);
178 if (sig == LINUX_SIGPWREMU)
179 return (LINUX_SIGPWR);
180
181 return (bsd_to_linux_rt_signal(sig));
182 }
183
184 int
185 linux_to_bsd_sigaltstack(int lsa)
186 {
187 int bsa = 0;
188
189 if (lsa & LINUX_SS_DISABLE)
190 bsa |= SS_DISABLE;
191 /*
192 * Linux ignores SS_ONSTACK flag for ss
193 * parameter while FreeBSD prohibits it.
194 */
195 return (bsa);
196 }
197
198 int
199 bsd_to_linux_sigaltstack(int bsa)
200 {
201 int lsa = 0;
202
203 if (bsa & SS_DISABLE)
204 lsa |= LINUX_SS_DISABLE;
205 if (bsa & SS_ONSTACK)
206 lsa |= LINUX_SS_ONSTACK;
207 return (lsa);
208 }
209
210 void
211 linux_to_bsd_sigset(l_sigset_t *lss, sigset_t *bss)
212 {
213 int b, l;
214
215 SIGEMPTYSET(*bss);
216 for (l = 1; l <= LINUX_SIGRTMAX; l++) {
217 if (LINUX_SIGISMEMBER(*lss, l)) {
218 b = linux_to_bsd_signal(l);
219 if (b)
220 SIGADDSET(*bss, b);
221 }
222 }
223 }
224
225 void
226 bsd_to_linux_sigset(sigset_t *bss, l_sigset_t *lss)
227 {
228 int b, l;
229
230 LINUX_SIGEMPTYSET(*lss);
231 for (b = 1; b <= SIGRTMAX; b++) {
232 if (SIGISMEMBER(*bss, b)) {
233 l = bsd_to_linux_signal(b);
234 if (l)
235 LINUX_SIGADDSET(*lss, l);
236 }
237 }
238 }
239
240 /*
241 * Translate a Linux interface name to a FreeBSD interface name,
242 * and return the associated ifnet structure
243 * bsdname and lxname need to be least IFNAMSIZ bytes long, but
244 * can point to the same buffer.
245 */
246 struct ifnet *
247 ifname_linux_to_bsd(struct thread *td, const char *lxname, char *bsdname)
248 {
249 struct ifnet *ifp;
250 int len, unit;
251 char *ep;
252 int index;
253 bool is_eth, is_lo;
254
255 for (len = 0; len < LINUX_IFNAMSIZ; ++len)
256 if (!isalpha(lxname[len]) || lxname[len] == '\0')
257 break;
258 if (len == 0 || len == LINUX_IFNAMSIZ)
259 return (NULL);
260 /* Linux loopback interface name is lo (not lo0) */
261 is_lo = (len == 2 && strncmp(lxname, "lo", len) == 0);
262 unit = (int)strtoul(lxname + len, &ep, 10);
263 if ((ep == NULL || ep == lxname + len || ep >= lxname + LINUX_IFNAMSIZ) &&
264 is_lo == 0)
265 return (NULL);
266 index = 0;
267 is_eth = (len == 3 && strncmp(lxname, "eth", len) == 0);
268
269 CURVNET_SET(TD_TO_VNET(td));
270 IFNET_RLOCK();
271 CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
272 /*
273 * Allow Linux programs to use FreeBSD names. Don't presume
274 * we never have an interface named "eth", so don't make
275 * the test optional based on is_eth.
276 */
277 if (strncmp(ifp->if_xname, lxname, LINUX_IFNAMSIZ) == 0)
278 break;
279 if (is_eth && IFP_IS_ETH(ifp) && unit == index++)
280 break;
281 if (is_lo && IFP_IS_LOOP(ifp))
282 break;
283 }
284 IFNET_RUNLOCK();
285 CURVNET_RESTORE();
286 if (ifp != NULL && bsdname != NULL)
287 strlcpy(bsdname, ifp->if_xname, IFNAMSIZ);
288 return (ifp);
289 }
290
291 void
292 linux_ifflags(struct ifnet *ifp, short *flags)
293 {
294 unsigned short fl;
295
296 fl = (ifp->if_flags | ifp->if_drv_flags) & 0xffff;
297 *flags = 0;
298 if (fl & IFF_UP)
299 *flags |= LINUX_IFF_UP;
300 if (fl & IFF_BROADCAST)
301 *flags |= LINUX_IFF_BROADCAST;
302 if (fl & IFF_DEBUG)
303 *flags |= LINUX_IFF_DEBUG;
304 if (fl & IFF_LOOPBACK)
305 *flags |= LINUX_IFF_LOOPBACK;
306 if (fl & IFF_POINTOPOINT)
307 *flags |= LINUX_IFF_POINTOPOINT;
308 if (fl & IFF_DRV_RUNNING)
309 *flags |= LINUX_IFF_RUNNING;
310 if (fl & IFF_NOARP)
311 *flags |= LINUX_IFF_NOARP;
312 if (fl & IFF_PROMISC)
313 *flags |= LINUX_IFF_PROMISC;
314 if (fl & IFF_ALLMULTI)
315 *flags |= LINUX_IFF_ALLMULTI;
316 if (fl & IFF_MULTICAST)
317 *flags |= LINUX_IFF_MULTICAST;
318 }
319
320 int
321 linux_ifhwaddr(struct ifnet *ifp, struct l_sockaddr *lsa)
322 {
323 struct ifaddr *ifa;
324 struct sockaddr_dl *sdl;
325
326 if (IFP_IS_LOOP(ifp)) {
327 bzero(lsa, sizeof(*lsa));
328 lsa->sa_family = LINUX_ARPHRD_LOOPBACK;
329 return (0);
330 }
331
332 if (!IFP_IS_ETH(ifp))
333 return (ENOENT);
334
335 CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
336 sdl = (struct sockaddr_dl*)ifa->ifa_addr;
337 if (sdl != NULL && (sdl->sdl_family == AF_LINK) &&
338 (sdl->sdl_type == IFT_ETHER)) {
339 bzero(lsa, sizeof(*lsa));
340 lsa->sa_family = LINUX_ARPHRD_ETHER;
341 bcopy(LLADDR(sdl), lsa->sa_data, LINUX_IFHWADDRLEN);
342 return (0);
343 }
344 }
345
346 return (ENOENT);
347 }
348
349 int
350 linux_to_bsd_domain(int domain)
351 {
352
353 switch (domain) {
354 case LINUX_AF_UNSPEC:
355 return (AF_UNSPEC);
356 case LINUX_AF_UNIX:
357 return (AF_LOCAL);
358 case LINUX_AF_INET:
359 return (AF_INET);
360 case LINUX_AF_INET6:
361 return (AF_INET6);
362 case LINUX_AF_AX25:
363 return (AF_CCITT);
364 case LINUX_AF_IPX:
365 return (AF_IPX);
366 case LINUX_AF_APPLETALK:
367 return (AF_APPLETALK);
368 case LINUX_AF_NETLINK:
369 return (AF_NETLINK);
370 }
371 return (-1);
372 }
373
374 int
375 bsd_to_linux_domain(int domain)
376 {
377
378 switch (domain) {
379 case AF_UNSPEC:
380 return (LINUX_AF_UNSPEC);
381 case AF_LOCAL:
382 return (LINUX_AF_UNIX);
383 case AF_INET:
384 return (LINUX_AF_INET);
385 case AF_INET6:
386 return (LINUX_AF_INET6);
387 case AF_CCITT:
388 return (LINUX_AF_AX25);
389 case AF_IPX:
390 return (LINUX_AF_IPX);
391 case AF_APPLETALK:
392 return (LINUX_AF_APPLETALK);
393 case AF_NETLINK:
394 return (LINUX_AF_NETLINK);
395 }
396 return (-1);
397 }
398
399 /*
400 * Based on the fact that:
401 * 1. Native and Linux storage of struct sockaddr
402 * and struct sockaddr_in6 are equal.
403 * 2. On Linux sa_family is the first member of all struct sockaddr.
404 */
405 int
406 bsd_to_linux_sockaddr(const struct sockaddr *sa, struct l_sockaddr **lsa,
407 socklen_t len)
408 {
409 struct l_sockaddr *kosa;
410 int bdom;
411
412 *lsa = NULL;
413 if (len < 2 || len > UCHAR_MAX)
414 return (EINVAL);
415 bdom = bsd_to_linux_domain(sa->sa_family);
416 if (bdom == -1)
417 return (EAFNOSUPPORT);
418
419 kosa = malloc(len, M_LINUX, M_WAITOK);
420 bcopy(sa, kosa, len);
421 kosa->sa_family = bdom;
422 *lsa = kosa;
423 return (0);
424 }
425
426 int
427 linux_to_bsd_sockaddr(const struct l_sockaddr *osa, struct sockaddr **sap,
428 socklen_t *len)
429 {
430 struct sockaddr *sa;
431 struct l_sockaddr *kosa;
432 #ifdef INET6
433 struct sockaddr_in6 *sin6;
434 bool oldv6size;
435 #endif
436 char *name;
437 int salen, bdom, error, hdrlen, namelen;
438
439 if (*len < 2 || *len > UCHAR_MAX)
440 return (EINVAL);
441
442 salen = *len;
443
444 #ifdef INET6
445 oldv6size = false;
446 /*
447 * Check for old (pre-RFC2553) sockaddr_in6. We may accept it
448 * if it's a v4-mapped address, so reserve the proper space
449 * for it.
450 */
451 if (salen == sizeof(struct sockaddr_in6) - sizeof(uint32_t)) {
452 salen += sizeof(uint32_t);
453 oldv6size = true;
454 }
455 #endif
456
457 kosa = malloc(salen, M_SONAME, M_WAITOK);
458
459 if ((error = copyin(osa, kosa, *len)))
460 goto out;
461
462 bdom = linux_to_bsd_domain(kosa->sa_family);
463 if (bdom == -1) {
464 error = EAFNOSUPPORT;
465 goto out;
466 }
467
468 #ifdef INET6
469 /*
470 * Older Linux IPv6 code uses obsolete RFC2133 struct sockaddr_in6,
471 * which lacks the scope id compared with RFC2553 one. If we detect
472 * the situation, reject the address and write a message to system log.
473 *
474 * Still accept addresses for which the scope id is not used.
475 */
476 if (oldv6size) {
477 if (bdom == AF_INET6) {
478 sin6 = (struct sockaddr_in6 *)kosa;
479 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) ||
480 (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) &&
481 !IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr) &&
482 !IN6_IS_ADDR_V4COMPAT(&sin6->sin6_addr) &&
483 !IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) &&
484 !IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))) {
485 sin6->sin6_scope_id = 0;
486 } else {
487 linux_msg(curthread,
488 "obsolete pre-RFC2553 sockaddr_in6 rejected");
489 error = EINVAL;
490 goto out;
491 }
492 } else
493 salen -= sizeof(uint32_t);
494 }
495 #endif
496 if (bdom == AF_INET) {
497 if (salen < sizeof(struct sockaddr_in)) {
498 error = EINVAL;
499 goto out;
500 }
501 salen = sizeof(struct sockaddr_in);
502 }
503
504 if (bdom == AF_LOCAL && salen > sizeof(struct sockaddr_un)) {
505 hdrlen = offsetof(struct sockaddr_un, sun_path);
506 name = ((struct sockaddr_un *)kosa)->sun_path;
507 if (*name == '\0') {
508 /*
509 * Linux abstract namespace starts with a NULL byte.
510 * XXX We do not support abstract namespace yet.
511 */
512 namelen = strnlen(name + 1, salen - hdrlen - 1) + 1;
513 } else
514 namelen = strnlen(name, salen - hdrlen);
515 salen = hdrlen + namelen;
516 if (salen > sizeof(struct sockaddr_un)) {
517 error = ENAMETOOLONG;
518 goto out;
519 }
520 }
521
522 if (bdom == AF_NETLINK) {
523 if (salen < sizeof(struct sockaddr_nl)) {
524 error = EINVAL;
525 goto out;
526 }
527 salen = sizeof(struct sockaddr_nl);
528 }
529
530 sa = (struct sockaddr *)kosa;
531 sa->sa_family = bdom;
532 sa->sa_len = salen;
533
534 *sap = sa;
535 *len = salen;
536 return (0);
537
538 out:
539 free(kosa, M_SONAME);
540 return (error);
541 }
542
543 void
544 linux_dev_shm_create(void)
545 {
546 int error;
547
548 error = make_dev_p(MAKEDEV_CHECKNAME | MAKEDEV_WAITOK, &dev_shm_cdev,
549 &dev_shm_cdevsw, NULL, UID_ROOT, GID_WHEEL, 0, "shm/.mountpoint");
550 if (error != 0) {
551 printf("%s: failed to create device node, error %d\n",
552 __func__, error);
553 }
554 }
555
556 void
557 linux_dev_shm_destroy(void)
558 {
559
560 destroy_dev(dev_shm_cdev);
561 }
562
563 int
564 bsd_to_linux_bits_(int value, struct bsd_to_linux_bitmap *bitmap,
565 size_t mapcnt, int no_value)
566 {
567 int bsd_mask, bsd_value, linux_mask, linux_value;
568 int linux_ret;
569 size_t i;
570 bool applied;
571
572 applied = false;
573 linux_ret = 0;
574 for (i = 0; i < mapcnt; ++i) {
575 bsd_mask = bitmap[i].bsd_mask;
576 bsd_value = bitmap[i].bsd_value;
577 if (bsd_mask == 0)
578 bsd_mask = bsd_value;
579
580 linux_mask = bitmap[i].linux_mask;
581 linux_value = bitmap[i].linux_value;
582 if (linux_mask == 0)
583 linux_mask = linux_value;
584
585 /*
586 * If a mask larger than just the value is set, we explicitly
587 * want to make sure that only this bit we mapped within that
588 * mask is set.
589 */
590 if ((value & bsd_mask) == bsd_value) {
591 linux_ret = (linux_ret & ~linux_mask) | linux_value;
592 applied = true;
593 }
594 }
595
596 if (!applied)
597 return (no_value);
598 return (linux_ret);
599 }
600
601 int
602 linux_to_bsd_bits_(int value, struct bsd_to_linux_bitmap *bitmap,
603 size_t mapcnt, int no_value)
604 {
605 int bsd_mask, bsd_value, linux_mask, linux_value;
606 int bsd_ret;
607 size_t i;
608 bool applied;
609
610 applied = false;
611 bsd_ret = 0;
612 for (i = 0; i < mapcnt; ++i) {
613 bsd_mask = bitmap[i].bsd_mask;
614 bsd_value = bitmap[i].bsd_value;
615 if (bsd_mask == 0)
616 bsd_mask = bsd_value;
617
618 linux_mask = bitmap[i].linux_mask;
619 linux_value = bitmap[i].linux_value;
620 if (linux_mask == 0)
621 linux_mask = linux_value;
622
623 /*
624 * If a mask larger than just the value is set, we explicitly
625 * want to make sure that only this bit we mapped within that
626 * mask is set.
627 */
628 if ((value & linux_mask) == linux_value) {
629 bsd_ret = (bsd_ret & ~bsd_mask) | bsd_value;
630 applied = true;
631 }
632 }
633
634 if (!applied)
635 return (no_value);
636 return (bsd_ret);
637 }
638
639 void
640 linux_to_bsd_poll_events(struct thread *td, int fd, short lev,
641 short *bev)
642 {
643 struct file *fp;
644 int error;
645 short bits = 0;
646
647 if (lev & LINUX_POLLIN)
648 bits |= POLLIN;
649 if (lev & LINUX_POLLPRI)
650 bits |= POLLPRI;
651 if (lev & LINUX_POLLOUT)
652 bits |= POLLOUT;
653 if (lev & LINUX_POLLERR)
654 bits |= POLLERR;
655 if (lev & LINUX_POLLHUP)
656 bits |= POLLHUP;
657 if (lev & LINUX_POLLNVAL)
658 bits |= POLLNVAL;
659 if (lev & LINUX_POLLRDNORM)
660 bits |= POLLRDNORM;
661 if (lev & LINUX_POLLRDBAND)
662 bits |= POLLRDBAND;
663 if (lev & LINUX_POLLWRBAND)
664 bits |= POLLWRBAND;
665 if (lev & LINUX_POLLWRNORM)
666 bits |= POLLWRNORM;
667
668 if (lev & LINUX_POLLRDHUP) {
669 /*
670 * It seems that the Linux silencly ignores POLLRDHUP
671 * on non-socket file descriptors unlike FreeBSD, where
672 * events bits is more strictly checked (POLLSTANDARD).
673 */
674 error = fget_unlocked(td, fd, &cap_no_rights, &fp);
675 if (error == 0) {
676 /*
677 * XXX. On FreeBSD POLLRDHUP applies only to
678 * stream sockets.
679 */
680 if (fp->f_type == DTYPE_SOCKET)
681 bits |= POLLRDHUP;
682 fdrop(fp, td);
683 }
684 }
685
686 if (lev & LINUX_POLLMSG)
687 LINUX_RATELIMIT_MSG_OPT1("unsupported POLLMSG, events(%d)", lev);
688 if (lev & LINUX_POLLREMOVE)
689 LINUX_RATELIMIT_MSG_OPT1("unsupported POLLREMOVE, events(%d)", lev);
690
691 *bev = bits;
692 }
693
694 void
695 bsd_to_linux_poll_events(short bev, short *lev)
696 {
697 short bits = 0;
698
699 if (bev & POLLIN)
700 bits |= LINUX_POLLIN;
701 if (bev & POLLPRI)
702 bits |= LINUX_POLLPRI;
703 if (bev & (POLLOUT | POLLWRNORM))
704 /*
705 * POLLWRNORM is equal to POLLOUT on FreeBSD,
706 * but not on Linux
707 */
708 bits |= LINUX_POLLOUT;
709 if (bev & POLLERR)
710 bits |= LINUX_POLLERR;
711 if (bev & POLLHUP)
712 bits |= LINUX_POLLHUP;
713 if (bev & POLLNVAL)
714 bits |= LINUX_POLLNVAL;
715 if (bev & POLLRDNORM)
716 bits |= LINUX_POLLRDNORM;
717 if (bev & POLLRDBAND)
718 bits |= LINUX_POLLRDBAND;
719 if (bev & POLLWRBAND)
720 bits |= LINUX_POLLWRBAND;
721 if (bev & POLLRDHUP)
722 bits |= LINUX_POLLRDHUP;
723
724 *lev = bits;
725 }
Cache object: b180a109a1b4660bd7faa206b3d2c61b
|