Home | History | Annotate | Line # | Download | only in kern
      1 /*	$NetBSD: tty_conf.c,v 1.57 2021/08/09 20:49:10 andvar Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2005, 2007 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Jason R. Thorpe.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 /*-
     33  * Copyright (c) 1982, 1986, 1991, 1993
     34  *	The Regents of the University of California.  All rights reserved.
     35  * (c) UNIX System Laboratories, Inc.
     36  * All or some portions of this file are derived from material licensed
     37  * to the University of California by American Telephone and Telegraph
     38  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
     39  * the permission of UNIX System Laboratories, Inc.
     40  *
     41  * Redistribution and use in source and binary forms, with or without
     42  * modification, are permitted provided that the following conditions
     43  * are met:
     44  * 1. Redistributions of source code must retain the above copyright
     45  *    notice, this list of conditions and the following disclaimer.
     46  * 2. Redistributions in binary form must reproduce the above copyright
     47  *    notice, this list of conditions and the following disclaimer in the
     48  *    documentation and/or other materials provided with the distribution.
     49  * 3. Neither the name of the University nor the names of its contributors
     50  *    may be used to endorse or promote products derived from this software
     51  *    without specific prior written permission.
     52  *
     53  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     54  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     55  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     56  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     57  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     58  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     59  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     60  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     61  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     62  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     63  * SUCH DAMAGE.
     64  *
     65  *	@(#)tty_conf.c	8.5 (Berkeley) 1/9/95
     66  */
     67 
     68 #include <sys/cdefs.h>
     69 __KERNEL_RCSID(0, "$NetBSD: tty_conf.c,v 1.57 2021/08/09 20:49:10 andvar Exp $");
     70 
     71 #define TTY_ALLOW_PRIVATE
     72 
     73 #include <sys/param.h>
     74 #include <sys/systm.h>
     75 #include <sys/poll.h>
     76 #include <sys/proc.h>
     77 #include <sys/tty.h>
     78 #include <sys/ttycom.h>
     79 #include <sys/conf.h>
     80 #include <sys/mutex.h>
     81 #include <sys/queue.h>
     82 
     83 static struct linesw termios_disc = {
     84 	.l_name = "termios",
     85 	.l_open = ttylopen,
     86 	.l_close = ttylclose,
     87 	.l_read = ttread,
     88 	.l_write = ttwrite,
     89 	.l_ioctl = ttynullioctl,
     90 	.l_rint = ttyinput,
     91 	.l_start = ttstart,
     92 	.l_modem = ttymodem,
     93 	.l_poll = ttpoll
     94 };
     95 
     96 /*
     97  * This is for the benefit of old BSD TTY compatibility, but since it is
     98  * identical to termios (except for the name), don't bother conditionalizing
     99  * it.
    100  */
    101 static struct linesw ntty_disc = {	/* old NTTYDISC */
    102 	.l_name = "ntty",
    103 	.l_open = ttylopen,
    104 	.l_close = ttylclose,
    105 	.l_read = ttread,
    106 	.l_write = ttwrite,
    107 	.l_ioctl = ttynullioctl,
    108 	.l_rint = ttyinput,
    109 	.l_start = ttstart,
    110 	.l_modem = ttymodem,
    111 	.l_poll = ttpoll
    112 };
    113 
    114 static LIST_HEAD(, linesw) ttyldisc_list = LIST_HEAD_INITIALIZER(ttyldisc_head);
    115 
    116 /*
    117  * Note: We don't bother refcounting termios_disc and ntty_disc; they can't
    118  * be removed from the list, and termios_disc is likely to have very many
    119  * references (could we overflow the count?).
    120  */
    121 #define	TTYLDISC_ISSTATIC(disc)					\
    122 	((disc) == &termios_disc || (disc) == &ntty_disc)
    123 
    124 #define	TTYLDISC_HOLD(disc)					\
    125 do {								\
    126 	if (! TTYLDISC_ISSTATIC(disc)) {			\
    127 		KASSERT((disc)->l_refcnt != UINT_MAX);		\
    128 		(disc)->l_refcnt++;				\
    129 	}							\
    130 } while (/*CONSTCOND*/0)
    131 
    132 #define	TTYLDISC_RELE(disc)					\
    133 do {								\
    134 	if (! TTYLDISC_ISSTATIC(disc)) {			\
    135 		KASSERT((disc)->l_refcnt != 0);			\
    136 		(disc)->l_refcnt--;				\
    137 	}							\
    138 } while (/*CONSTCOND*/0)
    139 
    140 #define	TTYLDISC_ISINUSE(disc)					\
    141 	(TTYLDISC_ISSTATIC(disc) || (disc)->l_refcnt != 0)
    142 
    143 /*
    144  * Do nothing specific version of line
    145  * discipline specific ioctl command.
    146  */
    147 /*ARGSUSED*/
    148 int
    149 ttynullioctl(struct tty *tp, u_long cmd, void *data, int flags, struct lwp *l)
    150 {
    151 
    152 	return (EPASSTHROUGH);
    153 }
    154 
    155 /*
    156  * Return error to line discipline
    157  * specific poll call.
    158  */
    159 /*ARGSUSED*/
    160 int
    161 ttyerrpoll(struct tty *tp, int events, struct lwp *l)
    162 {
    163 
    164 	return (POLLERR);
    165 }
    166 
    167 void
    168 ttyldisc_init(void)
    169 {
    170 
    171 	if (ttyldisc_attach(&termios_disc) != 0)
    172 		panic("ttyldisc_init: termios_disc");
    173 	if (ttyldisc_attach(&ntty_disc) != 0)
    174 		panic("ttyldisc_init: ntty_disc");
    175 }
    176 
    177 static struct linesw *
    178 ttyldisc_lookup_locked(const char *name)
    179 {
    180 	struct linesw *disc;
    181 
    182 	LIST_FOREACH(disc, &ttyldisc_list, l_list) {
    183 		if (strcmp(name, disc->l_name) == 0)
    184 			return (disc);
    185 	}
    186 
    187 	return (NULL);
    188 }
    189 
    190 /*
    191  * Look up a line discipline by its name.  Caller holds a reference on
    192  * the returned line discipline.
    193  */
    194 struct linesw *
    195 ttyldisc_lookup(const char *name)
    196 {
    197 	struct linesw *disc;
    198 
    199 	mutex_spin_enter(&tty_lock);
    200 	disc = ttyldisc_lookup_locked(name);
    201 	if (disc != NULL)
    202 		TTYLDISC_HOLD(disc);
    203 	mutex_spin_exit(&tty_lock);
    204 
    205 	return (disc);
    206 }
    207 
    208 /*
    209  * Look up a line discipline by its legacy number.  Caller holds a
    210  * reference on the returned line discipline.
    211  */
    212 struct linesw *
    213 ttyldisc_lookup_bynum(int num)
    214 {
    215 	struct linesw *disc;
    216 
    217 	mutex_spin_enter(&tty_lock);
    218 
    219 	LIST_FOREACH(disc, &ttyldisc_list, l_list) {
    220 		if (disc->l_no == num) {
    221 			TTYLDISC_HOLD(disc);
    222 			mutex_spin_exit(&tty_lock);
    223 			return (disc);
    224 		}
    225 	}
    226 
    227 	mutex_spin_exit(&tty_lock);
    228 	return (NULL);
    229 }
    230 
    231 /*
    232  * Release a reference on a line discipline previously added by
    233  * ttyldisc_lookup() or ttyldisc_lookup_bynum().
    234  */
    235 void
    236 ttyldisc_release(struct linesw *disc)
    237 {
    238 
    239 	if (disc == NULL)
    240 		return;
    241 
    242 	mutex_spin_enter(&tty_lock);
    243 	TTYLDISC_RELE(disc);
    244 	mutex_spin_exit(&tty_lock);
    245 }
    246 
    247 #define	TTYLDISC_LEGACY_NUMBER_MIN	10
    248 #define	TTYLDISC_LEGACY_NUMBER_MAX	INT_MAX
    249 
    250 static void
    251 ttyldisc_assign_legacy_number(struct linesw *disc)
    252 {
    253 	static const struct {
    254 		const char *name;
    255 		int num;
    256 	} table[] = {
    257 		{ "termios",		TTYDISC },
    258 		{ "ntty",		2 /* XXX old NTTYDISC */ },
    259 		{ "tablet",		TABLDISC },
    260 		{ "slip",		SLIPDISC },
    261 		{ "ppp",		PPPDISC },
    262 		{ "strip",		STRIPDISC },
    263 		{ "hdlc",		HDLCDISC },
    264 		{ NULL,			0 }
    265 	};
    266 	struct linesw *ldisc;
    267 	int i;
    268 
    269 	for (i = 0; table[i].name != NULL; i++) {
    270 		if (strcmp(disc->l_name, table[i].name) == 0) {
    271 			disc->l_no = table[i].num;
    272 			return;
    273 		}
    274 	}
    275 
    276 	disc->l_no = TTYLDISC_LEGACY_NUMBER_MIN;
    277 
    278 	LIST_FOREACH(ldisc, &ttyldisc_list, l_list) {
    279 		if (disc->l_no == ldisc->l_no) {
    280 			KASSERT(disc->l_no < TTYLDISC_LEGACY_NUMBER_MAX);
    281 			disc->l_no++;
    282 		}
    283 	}
    284 }
    285 
    286 /*
    287  * Register a line discipline.
    288  */
    289 int
    290 ttyldisc_attach(struct linesw *disc)
    291 {
    292 
    293 	KASSERT(disc->l_name != NULL);
    294 	KASSERT(disc->l_open != NULL);
    295 	KASSERT(disc->l_close != NULL);
    296 	KASSERT(disc->l_read != NULL);
    297 	KASSERT(disc->l_write != NULL);
    298 	KASSERT(disc->l_ioctl != NULL);
    299 	KASSERT(disc->l_rint != NULL);
    300 	KASSERT(disc->l_start != NULL);
    301 	KASSERT(disc->l_modem != NULL);
    302 	KASSERT(disc->l_poll != NULL);
    303 
    304 	/* You are not allowed to exceed TTLINEDNAMELEN */
    305 	if (strlen(disc->l_name) >= TTLINEDNAMELEN)
    306 		return (ENAMETOOLONG);
    307 
    308 	mutex_spin_enter(&tty_lock);
    309 
    310 	if (ttyldisc_lookup_locked(disc->l_name) != NULL) {
    311 		mutex_spin_exit(&tty_lock);
    312 		return (EEXIST);
    313 	}
    314 
    315 	ttyldisc_assign_legacy_number(disc);
    316 	LIST_INSERT_HEAD(&ttyldisc_list, disc, l_list);
    317 
    318 	mutex_spin_exit(&tty_lock);
    319 
    320 	return (0);
    321 }
    322 
    323 /*
    324  * Remove a line discipline.
    325  */
    326 int
    327 ttyldisc_detach(struct linesw *disc)
    328 {
    329 #ifdef DIAGNOSTIC
    330 	struct linesw *ldisc = ttyldisc_lookup(disc->l_name);
    331 
    332 	KASSERT(ldisc != NULL);
    333 	KASSERT(ldisc == disc);
    334 	ttyldisc_release(ldisc);
    335 #endif
    336 
    337 	mutex_spin_enter(&tty_lock);
    338 
    339 	if (TTYLDISC_ISINUSE(disc)) {
    340 		mutex_spin_exit(&tty_lock);
    341 		return (EBUSY);
    342 	}
    343 
    344 	LIST_REMOVE(disc, l_list);
    345 
    346 	mutex_spin_exit(&tty_lock);
    347 
    348 	return (0);
    349 }
    350 
    351 /*
    352  * Return the default line discipline.
    353  */
    354 struct linesw *
    355 ttyldisc_default(void)
    356 {
    357 
    358 	return (&termios_disc);
    359 }
    360