1 /* $NetBSD: tty_43.c,v 1.37 2020/08/08 19:04:58 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 2008 The NetBSD Foundation, Inc. 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 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /*- 30 * Copyright (c) 1982, 1986, 1991, 1993 31 * The Regents of the University of California. All rights reserved. 32 * 33 * Redistribution and use in source and binary forms, with or without 34 * modification, are permitted provided that the following conditions 35 * are met: 36 * 1. Redistributions of source code must retain the above copyright 37 * notice, this list of conditions and the following disclaimer. 38 * 2. Redistributions in binary form must reproduce the above copyright 39 * notice, this list of conditions and the following disclaimer in the 40 * documentation and/or other materials provided with the distribution. 41 * 3. Neither the name of the University nor the names of its contributors 42 * may be used to endorse or promote products derived from this software 43 * without specific prior written permission. 44 * 45 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 48 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 55 * SUCH DAMAGE. 56 * 57 * @(#)tty_compat.c 8.2 (Berkeley) 1/9/95 58 */ 59 60 /* 61 * mapping routines for old line discipline (yuck) 62 */ 63 64 #include <sys/cdefs.h> 65 __KERNEL_RCSID(0, "$NetBSD: tty_43.c,v 1.37 2020/08/08 19:04:58 christos Exp $"); 66 67 #if defined(_KERNEL_OPT) 68 #include "opt_compat_netbsd.h" 69 #endif 70 71 #include <sys/param.h> 72 #include <sys/systm.h> 73 #include <sys/ioctl.h> 74 #include <sys/proc.h> 75 #include <sys/conf.h> 76 #include <sys/tty.h> 77 #include <sys/termios.h> 78 #include <sys/file.h> 79 #include <sys/kernel.h> 80 #include <sys/syslog.h> 81 #include <sys/compat_stub.h> 82 #include <sys/module_hook.h> 83 #include <sys/ioctl_compat.h> 84 85 #include <compat/common/compat_mod.h> 86 #include <compat/sys/ttycom.h> 87 88 int ttydebug = 0; 89 90 static const struct speedtab compatspeeds[] = { 91 #define MAX_SPEED 17 92 { 115200, 17 }, 93 { 57600, 16 }, 94 { 38400, 15 }, 95 { 19200, 14 }, 96 { 9600, 13 }, 97 { 4800, 12 }, 98 { 2400, 11 }, 99 { 1800, 10 }, 100 { 1200, 9 }, 101 { 600, 8 }, 102 { 300, 7 }, 103 { 200, 6 }, 104 { 150, 5 }, 105 { 134, 4 }, 106 { 110, 3 }, 107 { 75, 2 }, 108 { 50, 1 }, 109 { 0, 0 }, 110 { -1, -1 }, 111 }; 112 static const int compatspcodes[] = { 113 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 114 1800, 2400, 4800, 9600, 19200, 38400, 57600, 115200 115 }; 116 117 static int ttcompatgetflags(struct tty *); 118 static void ttcompatsetflags(struct tty *, struct termios *); 119 static void ttcompatsetlflags(struct tty *, struct termios *); 120 121 /*ARGSUSED*/ 122 int 123 compat_43_ttioctl(struct tty *tp, u_long com, void *data, int flag, 124 struct lwp *l) 125 { 126 127 switch (com) { 128 case TIOCGETP: { 129 struct sgttyb *sg = (struct sgttyb *)data; 130 int speed; 131 132 mutex_spin_enter(&tty_lock); 133 speed = ttspeedtab(tp->t_ospeed, compatspeeds); 134 sg->sg_ospeed = (speed == -1) ? MAX_SPEED : speed; 135 if (tp->t_ispeed == 0) 136 sg->sg_ispeed = sg->sg_ospeed; 137 else { 138 speed = ttspeedtab(tp->t_ispeed, compatspeeds); 139 sg->sg_ispeed = (speed == -1) ? MAX_SPEED : speed; 140 } 141 sg->sg_erase = tty_getctrlchar(tp, VERASE); 142 sg->sg_kill = tty_getctrlchar(tp, VKILL); 143 sg->sg_flags = ttcompatgetflags(tp); 144 mutex_spin_exit(&tty_lock); 145 break; 146 } 147 148 case TIOCSETP: 149 case TIOCSETN: { 150 struct sgttyb *sg = (struct sgttyb *)data; 151 struct termios term; 152 int speed; 153 154 mutex_spin_enter(&tty_lock); 155 term = tp->t_termios; 156 if ((speed = sg->sg_ispeed) > MAX_SPEED || speed < 0) 157 term.c_ispeed = speed; 158 else 159 term.c_ispeed = compatspcodes[speed]; 160 if ((speed = sg->sg_ospeed) > MAX_SPEED || speed < 0) 161 term.c_ospeed = speed; 162 else 163 term.c_ospeed = compatspcodes[speed]; 164 term.c_cc[VERASE] = sg->sg_erase; 165 term.c_cc[VKILL] = sg->sg_kill; 166 tp->t_flags = (ttcompatgetflags(tp)&0xffff0000) | (sg->sg_flags&0xffff); 167 ttcompatsetflags(tp, &term); 168 mutex_spin_exit(&tty_lock); 169 return (ttioctl(tp, com == TIOCSETP ? TIOCSETAF : TIOCSETA, 170 (void *)&term, flag, l)); 171 } 172 173 case TIOCGETC: { 174 struct tchars *tc = (struct tchars *)data; 175 176 tc->t_intrc = tty_getctrlchar(tp, VINTR); 177 tc->t_quitc = tty_getctrlchar(tp, VQUIT); 178 tc->t_startc = tty_getctrlchar(tp, VSTART); 179 tc->t_stopc = tty_getctrlchar(tp, VSTOP); 180 tc->t_eofc = tty_getctrlchar(tp, VEOF); 181 tc->t_brkc = tty_getctrlchar(tp, VEOL); 182 break; 183 } 184 case TIOCSETC: { 185 struct tchars *tc = (struct tchars *)data; 186 187 tty_setctrlchar(tp, VINTR, tc->t_intrc); 188 tty_setctrlchar(tp, VQUIT, tc->t_quitc); 189 tty_setctrlchar(tp, VSTART, tc->t_startc); 190 tty_setctrlchar(tp, VSTOP, tc->t_stopc); 191 tty_setctrlchar(tp, VEOF, tc->t_eofc); 192 tty_setctrlchar(tp, VEOL, tc->t_brkc); 193 if (tc->t_brkc == (char)-1) 194 tty_setctrlchar(tp, VEOL2, _POSIX_VDISABLE); 195 break; 196 } 197 case TIOCSLTC: { 198 struct ltchars *ltc = (struct ltchars *)data; 199 200 tty_setctrlchar(tp, VSUSP, ltc->t_suspc); 201 tty_setctrlchar(tp, VDSUSP, ltc->t_dsuspc); 202 tty_setctrlchar(tp, VREPRINT, ltc->t_rprntc); 203 tty_setctrlchar(tp, VDISCARD, ltc->t_flushc); 204 tty_setctrlchar(tp, VWERASE, ltc->t_werasc); 205 tty_setctrlchar(tp, VLNEXT, ltc->t_lnextc); 206 break; 207 } 208 case TIOCGLTC: { 209 struct ltchars *ltc = (struct ltchars *)data; 210 211 ltc->t_suspc = tty_getctrlchar(tp, VSUSP); 212 ltc->t_dsuspc = tty_getctrlchar(tp, VDSUSP); 213 ltc->t_rprntc = tty_getctrlchar(tp, VREPRINT); 214 ltc->t_flushc = tty_getctrlchar(tp, VDISCARD); 215 ltc->t_werasc = tty_getctrlchar(tp, VWERASE); 216 ltc->t_lnextc = tty_getctrlchar(tp, VLNEXT); 217 break; 218 } 219 case TIOCLBIS: 220 case TIOCLBIC: 221 case TIOCLSET: { 222 struct termios term; 223 int flags; 224 225 mutex_spin_enter(&tty_lock); 226 term = tp->t_termios; 227 flags = ttcompatgetflags(tp); 228 switch (com) { 229 case TIOCLSET: 230 tp->t_flags = (flags&0xffff) | (*(int *)data<<16); 231 break; 232 case TIOCLBIS: 233 tp->t_flags = flags | (*(int *)data<<16); 234 break; 235 case TIOCLBIC: 236 tp->t_flags = flags & ~(*(int *)data<<16); 237 break; 238 } 239 ttcompatsetlflags(tp, &term); 240 mutex_spin_exit(&tty_lock); 241 return (ttioctl(tp, TIOCSETA, (void *)&term, flag, l)); 242 } 243 case TIOCLGET: 244 mutex_spin_enter(&tty_lock); 245 *(int *)data = ttcompatgetflags(tp)>>16; 246 mutex_spin_exit(&tty_lock); 247 if (ttydebug) 248 printf("CLGET: returning %x\n", *(int *)data); 249 break; 250 251 case OTIOCGETD: 252 mutex_spin_enter(&tty_lock); 253 *(int *)data = (tp->t_linesw == NULL || tp->t_linesw->l_no == 0) 254 ? 2 /* XXX old NTTYDISC */ : tp->t_linesw->l_no; 255 mutex_spin_exit(&tty_lock); 256 break; 257 258 case OTIOCSETD: { 259 int ldisczero = 0; 260 261 return (ttioctl(tp, TIOCSETD, 262 *(int *)data == 2 ? (void *)&ldisczero : data, flag, 263 l)); 264 } 265 266 case OTIOCCONS: 267 *(int *)data = 1; 268 return (ttioctl(tp, TIOCCONS, data, flag, l)); 269 270 case TIOCHPCL: 271 mutex_spin_enter(&tty_lock); 272 SET(tp->t_cflag, HUPCL); 273 mutex_spin_exit(&tty_lock); 274 break; 275 276 case TIOCGSID: 277 mutex_enter(&proc_lock); 278 if (tp->t_session == NULL) { 279 mutex_exit(&proc_lock); 280 return ENOTTY; 281 } 282 if (tp->t_session->s_leader == NULL) { 283 mutex_exit(&proc_lock); 284 return ENOTTY; 285 } 286 *(int *) data = tp->t_session->s_leader->p_pid; 287 mutex_exit(&proc_lock); 288 break; 289 290 default: 291 return (EPASSTHROUGH); 292 } 293 return (0); 294 } 295 296 static int 297 ttcompatgetflags(struct tty *tp) 298 { 299 tcflag_t iflag = tp->t_iflag; 300 tcflag_t lflag = tp->t_lflag; 301 tcflag_t oflag = tp->t_oflag; 302 tcflag_t cflag = tp->t_cflag; 303 int flags = 0; 304 305 KASSERT(mutex_owned(&tty_lock)); 306 307 if (ISSET(iflag, IXOFF)) 308 SET(flags, TANDEM); 309 if (ISSET(iflag, ICRNL) || ISSET(oflag, ONLCR)) 310 SET(flags, CRMOD); 311 if (ISSET(cflag, PARENB)) { 312 if (ISSET(iflag, INPCK)) { 313 if (ISSET(cflag, PARODD)) 314 SET(flags, ODDP); 315 else 316 SET(flags, EVENP); 317 } else 318 SET(flags, ANYP); 319 } 320 321 if (!ISSET(lflag, ICANON)) { 322 /* fudge */ 323 if (ISSET(iflag, IXON) || ISSET(lflag, ISIG|IEXTEN) || 324 ISSET(cflag, PARENB)) 325 SET(flags, CBREAK); 326 else 327 SET(flags, RAW); 328 } 329 330 if (ISSET(flags, RAW)) 331 SET(flags, ISSET(tp->t_flags, LITOUT|PASS8)); 332 else if (ISSET(cflag, CSIZE) == CS8) { 333 if (!ISSET(oflag, OPOST)) 334 SET(flags, LITOUT); 335 if (!ISSET(iflag, ISTRIP)) 336 SET(flags, PASS8); 337 } 338 339 if (ISSET(cflag, MDMBUF)) 340 SET(flags, MDMBUF); 341 if (!ISSET(cflag, HUPCL)) 342 SET(flags, NOHANG); 343 if (ISSET(oflag, OXTABS)) 344 SET(flags, XTABS); 345 if (ISSET(lflag, ECHOE)) 346 SET(flags, CRTERA|CRTBS); 347 if (ISSET(lflag, ECHOKE)) 348 SET(flags, CRTKIL|CRTBS); 349 if (ISSET(lflag, ECHOPRT)) 350 SET(flags, PRTERA); 351 if (ISSET(lflag, ECHOCTL)) 352 SET(flags, CTLECH); 353 if (!ISSET(iflag, IXANY)) 354 SET(flags, DECCTQ); 355 SET(flags, ISSET(lflag, ECHO|TOSTOP|FLUSHO|PENDIN|NOFLSH)); 356 if (ttydebug) 357 printf("getflags: %x\n", flags); 358 return (flags); 359 } 360 361 static void 362 ttcompatsetflags(struct tty *tp, struct termios *t) 363 { 364 int flags = tp->t_flags; 365 366 KASSERT(mutex_owned(&tty_lock)); 367 368 tcflag_t iflag = t->c_iflag; 369 tcflag_t oflag = t->c_oflag; 370 tcflag_t lflag = t->c_lflag; 371 tcflag_t cflag = t->c_cflag; 372 373 if (ISSET(flags, TANDEM)) 374 SET(iflag, IXOFF); 375 else 376 CLR(iflag, IXOFF); 377 if (ISSET(flags, ECHO)) 378 SET(lflag, ECHO); 379 else 380 CLR(lflag, ECHO); 381 if (ISSET(flags, CRMOD)) { 382 SET(iflag, ICRNL); 383 SET(oflag, ONLCR); 384 } else { 385 CLR(iflag, ICRNL); 386 CLR(oflag, ONLCR); 387 } 388 if (ISSET(flags, XTABS)) 389 SET(oflag, OXTABS); 390 else 391 CLR(oflag, OXTABS); 392 393 394 if (ISSET(flags, RAW)) { 395 iflag &= IXOFF; 396 CLR(lflag, ISIG|ICANON|IEXTEN); 397 CLR(cflag, PARENB); 398 } else { 399 SET(iflag, BRKINT|IXON|IMAXBEL); 400 SET(lflag, ISIG|IEXTEN); 401 if (ISSET(flags, CBREAK)) 402 CLR(lflag, ICANON); 403 else 404 SET(lflag, ICANON); 405 switch (ISSET(flags, ANYP)) { 406 case 0: 407 CLR(cflag, PARENB); 408 break; 409 case ANYP: 410 SET(cflag, PARENB); 411 CLR(iflag, INPCK); 412 break; 413 case EVENP: 414 SET(cflag, PARENB); 415 SET(iflag, INPCK); 416 CLR(cflag, PARODD); 417 break; 418 case ODDP: 419 SET(cflag, PARENB); 420 SET(iflag, INPCK); 421 SET(cflag, PARODD); 422 break; 423 } 424 } 425 426 if (ISSET(flags, RAW|LITOUT|PASS8)) { 427 CLR(cflag, CSIZE); 428 SET(cflag, CS8); 429 if (!ISSET(flags, RAW|PASS8)) 430 SET(iflag, ISTRIP); 431 else 432 CLR(iflag, ISTRIP); 433 if (!ISSET(flags, RAW|LITOUT)) 434 SET(oflag, OPOST); 435 else 436 CLR(oflag, OPOST); 437 } else { 438 CLR(cflag, CSIZE); 439 SET(cflag, CS7); 440 SET(iflag, ISTRIP); 441 SET(oflag, OPOST); 442 } 443 444 t->c_iflag = iflag; 445 t->c_oflag = oflag; 446 t->c_lflag = lflag; 447 t->c_cflag = cflag; 448 } 449 450 static void 451 ttcompatsetlflags(struct tty *tp, struct termios *t) 452 { 453 int flags = tp->t_flags; 454 tcflag_t iflag = t->c_iflag; 455 tcflag_t oflag = t->c_oflag; 456 tcflag_t lflag = t->c_lflag; 457 tcflag_t cflag = t->c_cflag; 458 459 KASSERT(mutex_owned(&tty_lock)); 460 461 /* Nothing we can do with CRTBS. */ 462 if (ISSET(flags, PRTERA)) 463 SET(lflag, ECHOPRT); 464 else 465 CLR(lflag, ECHOPRT); 466 if (ISSET(flags, CRTERA)) 467 SET(lflag, ECHOE); 468 else 469 CLR(lflag, ECHOE); 470 /* Nothing we can do with TILDE. */ 471 if (ISSET(flags, MDMBUF)) 472 SET(cflag, MDMBUF); 473 else 474 CLR(cflag, MDMBUF); 475 if (ISSET(flags, NOHANG)) 476 CLR(cflag, HUPCL); 477 else 478 SET(cflag, HUPCL); 479 if (ISSET(flags, CRTKIL)) 480 SET(lflag, ECHOKE); 481 else 482 CLR(lflag, ECHOKE); 483 if (ISSET(flags, CTLECH)) 484 SET(lflag, ECHOCTL); 485 else 486 CLR(lflag, ECHOCTL); 487 if (!ISSET(flags, DECCTQ)) 488 SET(iflag, IXANY); 489 else 490 CLR(iflag, IXANY); 491 CLR(lflag, TOSTOP|FLUSHO|PENDIN|NOFLSH); 492 SET(lflag, ISSET(flags, TOSTOP|FLUSHO|PENDIN|NOFLSH)); 493 494 if (ISSET(flags, RAW|LITOUT|PASS8)) { 495 CLR(cflag, CSIZE); 496 SET(cflag, CS8); 497 if (!ISSET(flags, RAW|PASS8)) 498 SET(iflag, ISTRIP); 499 else 500 CLR(iflag, ISTRIP); 501 if (!ISSET(flags, RAW|LITOUT)) 502 SET(oflag, OPOST); 503 else 504 CLR(oflag, OPOST); 505 } else { 506 CLR(cflag, CSIZE); 507 SET(cflag, CS7); 508 SET(iflag, ISTRIP); 509 SET(oflag, OPOST); 510 } 511 512 t->c_iflag = iflag; 513 t->c_oflag = oflag; 514 t->c_lflag = lflag; 515 t->c_cflag = cflag; 516 } 517 518 int 519 kern_tty_43_init(void) 520 { 521 MODULE_HOOK_SET(tty_ttioctl_43_hook, compat_43_ttioctl); 522 return 0; 523 } 524 525 int 526 kern_tty_43_fini(void) 527 { 528 MODULE_HOOK_UNSET(tty_ttioctl_43_hook); 529 return 0; 530 } 531