1 /*- 2 * Copyright (c) 2015 Dmitry Chagin 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include <sys/param.h> 31 #include <sys/systm.h> 32 #include <sys/ctype.h> 33 #include <sys/jail.h> 34 #include <sys/lock.h> 35 #include <sys/signalvar.h> 36 #include <sys/socket.h> 37 38 #include <net/if.h> 39 #include <net/if_var.h> 40 #include <net/if_dl.h> 41 #include <net/if_types.h> 42 43 #include <compat/linux/linux.h> 44 #include <compat/linux/linux_common.h> 45 46 CTASSERT(LINUX_IFNAMSIZ == IFNAMSIZ); 47 48 static int bsd_to_linux_sigtbl[LINUX_SIGTBLSZ] = { 49 LINUX_SIGHUP, /* SIGHUP */ 50 LINUX_SIGINT, /* SIGINT */ 51 LINUX_SIGQUIT, /* SIGQUIT */ 52 LINUX_SIGILL, /* SIGILL */ 53 LINUX_SIGTRAP, /* SIGTRAP */ 54 LINUX_SIGABRT, /* SIGABRT */ 55 0, /* SIGEMT */ 56 LINUX_SIGFPE, /* SIGFPE */ 57 LINUX_SIGKILL, /* SIGKILL */ 58 LINUX_SIGBUS, /* SIGBUS */ 59 LINUX_SIGSEGV, /* SIGSEGV */ 60 LINUX_SIGSYS, /* SIGSYS */ 61 LINUX_SIGPIPE, /* SIGPIPE */ 62 LINUX_SIGALRM, /* SIGALRM */ 63 LINUX_SIGTERM, /* SIGTERM */ 64 LINUX_SIGURG, /* SIGURG */ 65 LINUX_SIGSTOP, /* SIGSTOP */ 66 LINUX_SIGTSTP, /* SIGTSTP */ 67 LINUX_SIGCONT, /* SIGCONT */ 68 LINUX_SIGCHLD, /* SIGCHLD */ 69 LINUX_SIGTTIN, /* SIGTTIN */ 70 LINUX_SIGTTOU, /* SIGTTOU */ 71 LINUX_SIGIO, /* SIGIO */ 72 LINUX_SIGXCPU, /* SIGXCPU */ 73 LINUX_SIGXFSZ, /* SIGXFSZ */ 74 LINUX_SIGVTALRM,/* SIGVTALRM */ 75 LINUX_SIGPROF, /* SIGPROF */ 76 LINUX_SIGWINCH, /* SIGWINCH */ 77 0, /* SIGINFO */ 78 LINUX_SIGUSR1, /* SIGUSR1 */ 79 LINUX_SIGUSR2 /* SIGUSR2 */ 80 }; 81 82 static int linux_to_bsd_sigtbl[LINUX_SIGTBLSZ] = { 83 SIGHUP, /* LINUX_SIGHUP */ 84 SIGINT, /* LINUX_SIGINT */ 85 SIGQUIT, /* LINUX_SIGQUIT */ 86 SIGILL, /* LINUX_SIGILL */ 87 SIGTRAP, /* LINUX_SIGTRAP */ 88 SIGABRT, /* LINUX_SIGABRT */ 89 SIGBUS, /* LINUX_SIGBUS */ 90 SIGFPE, /* LINUX_SIGFPE */ 91 SIGKILL, /* LINUX_SIGKILL */ 92 SIGUSR1, /* LINUX_SIGUSR1 */ 93 SIGSEGV, /* LINUX_SIGSEGV */ 94 SIGUSR2, /* LINUX_SIGUSR2 */ 95 SIGPIPE, /* LINUX_SIGPIPE */ 96 SIGALRM, /* LINUX_SIGALRM */ 97 SIGTERM, /* LINUX_SIGTERM */ 98 SIGBUS, /* LINUX_SIGSTKFLT */ 99 SIGCHLD, /* LINUX_SIGCHLD */ 100 SIGCONT, /* LINUX_SIGCONT */ 101 SIGSTOP, /* LINUX_SIGSTOP */ 102 SIGTSTP, /* LINUX_SIGTSTP */ 103 SIGTTIN, /* LINUX_SIGTTIN */ 104 SIGTTOU, /* LINUX_SIGTTOU */ 105 SIGURG, /* LINUX_SIGURG */ 106 SIGXCPU, /* LINUX_SIGXCPU */ 107 SIGXFSZ, /* LINUX_SIGXFSZ */ 108 SIGVTALRM, /* LINUX_SIGVTALARM */ 109 SIGPROF, /* LINUX_SIGPROF */ 110 SIGWINCH, /* LINUX_SIGWINCH */ 111 SIGIO, /* LINUX_SIGIO */ 112 /* 113 * FreeBSD does not have SIGPWR signal, map Linux SIGPWR signal 114 * to the first unused FreeBSD signal number. Since Linux supports 115 * signals from 1 to 64 we are ok here as our SIGRTMIN = 65. 116 */ 117 SIGRTMIN, /* LINUX_SIGPWR */ 118 SIGSYS /* LINUX_SIGSYS */ 119 }; 120 121 /* 122 * Map Linux RT signals to the FreeBSD RT signals. 123 */ 124 static inline int 125 linux_to_bsd_rt_signal(int sig) 126 { 127 128 return (SIGRTMIN + 1 + sig - LINUX_SIGRTMIN); 129 } 130 131 static inline int 132 bsd_to_linux_rt_signal(int sig) 133 { 134 135 return (sig - SIGRTMIN - 1 + LINUX_SIGRTMIN); 136 } 137 138 int 139 linux_to_bsd_signal(int sig) 140 { 141 142 KASSERT(sig > 0 && sig <= LINUX_SIGRTMAX, ("invalid Linux signal %d\n", sig)); 143 144 if (sig < LINUX_SIGRTMIN) 145 return (linux_to_bsd_sigtbl[_SIG_IDX(sig)]); 146 147 return (linux_to_bsd_rt_signal(sig)); 148 } 149 150 int 151 bsd_to_linux_signal(int sig) 152 { 153 154 if (sig <= LINUX_SIGTBLSZ) 155 return (bsd_to_linux_sigtbl[_SIG_IDX(sig)]); 156 if (sig == SIGRTMIN) 157 return (LINUX_SIGPWR); 158 159 return (bsd_to_linux_rt_signal(sig)); 160 } 161 162 int 163 linux_to_bsd_sigaltstack(int lsa) 164 { 165 int bsa = 0; 166 167 if (lsa & LINUX_SS_DISABLE) 168 bsa |= SS_DISABLE; 169 /* 170 * Linux ignores SS_ONSTACK flag for ss 171 * parameter while FreeBSD prohibits it. 172 */ 173 return (bsa); 174 } 175 176 int 177 bsd_to_linux_sigaltstack(int bsa) 178 { 179 int lsa = 0; 180 181 if (bsa & SS_DISABLE) 182 lsa |= LINUX_SS_DISABLE; 183 if (bsa & SS_ONSTACK) 184 lsa |= LINUX_SS_ONSTACK; 185 return (lsa); 186 } 187 188 void 189 linux_to_bsd_sigset(l_sigset_t *lss, sigset_t *bss) 190 { 191 int b, l; 192 193 SIGEMPTYSET(*bss); 194 for (l = 1; l <= LINUX_SIGRTMAX; l++) { 195 if (LINUX_SIGISMEMBER(*lss, l)) { 196 b = linux_to_bsd_signal(l); 197 if (b) 198 SIGADDSET(*bss, b); 199 } 200 } 201 } 202 203 void 204 bsd_to_linux_sigset(sigset_t *bss, l_sigset_t *lss) 205 { 206 int b, l; 207 208 LINUX_SIGEMPTYSET(*lss); 209 for (b = 1; b <= SIGRTMAX; b++) { 210 if (SIGISMEMBER(*bss, b)) { 211 l = bsd_to_linux_signal(b); 212 if (l) 213 LINUX_SIGADDSET(*lss, l); 214 } 215 } 216 } 217 218 /* 219 * Translate a Linux interface name to a FreeBSD interface name, 220 * and return the associated ifnet structure 221 * bsdname and lxname need to be least IFNAMSIZ bytes long, but 222 * can point to the same buffer. 223 */ 224 struct ifnet * 225 ifname_linux_to_bsd(struct thread *td, const char *lxname, char *bsdname) 226 { 227 struct ifnet *ifp; 228 int len, unit; 229 char *ep; 230 int index; 231 bool is_eth, is_lo; 232 233 for (len = 0; len < LINUX_IFNAMSIZ; ++len) 234 if (!isalpha(lxname[len]) || lxname[len] == '\0') 235 break; 236 if (len == 0 || len == LINUX_IFNAMSIZ) 237 return (NULL); 238 /* Linux loopback interface name is lo (not lo0) */ 239 is_lo = (len == 2 && strncmp(lxname, "lo", len) == 0); 240 unit = (int)strtoul(lxname + len, &ep, 10); 241 if ((ep == NULL || ep == lxname + len || ep >= lxname + LINUX_IFNAMSIZ) && 242 is_lo == 0) 243 return (NULL); 244 index = 0; 245 is_eth = (len == 3 && strncmp(lxname, "eth", len) == 0); 246 247 CURVNET_SET(TD_TO_VNET(td)); 248 IFNET_RLOCK(); 249 CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) { 250 /* 251 * Allow Linux programs to use FreeBSD names. Don't presume 252 * we never have an interface named "eth", so don't make 253 * the test optional based on is_eth. 254 */ 255 if (strncmp(ifp->if_xname, lxname, LINUX_IFNAMSIZ) == 0) 256 break; 257 if (is_eth && IFP_IS_ETH(ifp) && unit == index++) 258 break; 259 if (is_lo && IFP_IS_LOOP(ifp)) 260 break; 261 } 262 IFNET_RUNLOCK(); 263 CURVNET_RESTORE(); 264 if (ifp != NULL && bsdname != NULL) 265 strlcpy(bsdname, ifp->if_xname, IFNAMSIZ); 266 return (ifp); 267 } 268 269 void 270 linux_ifflags(struct ifnet *ifp, short *flags) 271 { 272 unsigned short fl; 273 274 fl = (ifp->if_flags | ifp->if_drv_flags) & 0xffff; 275 *flags = 0; 276 if (fl & IFF_UP) 277 *flags |= LINUX_IFF_UP; 278 if (fl & IFF_BROADCAST) 279 *flags |= LINUX_IFF_BROADCAST; 280 if (fl & IFF_DEBUG) 281 *flags |= LINUX_IFF_DEBUG; 282 if (fl & IFF_LOOPBACK) 283 *flags |= LINUX_IFF_LOOPBACK; 284 if (fl & IFF_POINTOPOINT) 285 *flags |= LINUX_IFF_POINTOPOINT; 286 if (fl & IFF_DRV_RUNNING) 287 *flags |= LINUX_IFF_RUNNING; 288 if (fl & IFF_NOARP) 289 *flags |= LINUX_IFF_NOARP; 290 if (fl & IFF_PROMISC) 291 *flags |= LINUX_IFF_PROMISC; 292 if (fl & IFF_ALLMULTI) 293 *flags |= LINUX_IFF_ALLMULTI; 294 if (fl & IFF_MULTICAST) 295 *flags |= LINUX_IFF_MULTICAST; 296 } 297 298 int 299 linux_ifhwaddr(struct ifnet *ifp, struct l_sockaddr *lsa) 300 { 301 struct ifaddr *ifa; 302 struct sockaddr_dl *sdl; 303 304 if (IFP_IS_LOOP(ifp)) { 305 bzero(lsa, sizeof(*lsa)); 306 lsa->sa_family = LINUX_ARPHRD_LOOPBACK; 307 return (0); 308 } 309 310 if (!IFP_IS_ETH(ifp)) 311 return (ENOENT); 312 313 CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 314 sdl = (struct sockaddr_dl*)ifa->ifa_addr; 315 if (sdl != NULL && (sdl->sdl_family == AF_LINK) && 316 (sdl->sdl_type == IFT_ETHER)) { 317 bzero(lsa, sizeof(*lsa)); 318 lsa->sa_family = LINUX_ARPHRD_ETHER; 319 bcopy(LLADDR(sdl), lsa->sa_data, LINUX_IFHWADDRLEN); 320 return (0); 321 } 322 } 323 324 return (ENOENT); 325 } 326