Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0
2 : : /*
3 : : * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds
4 : : *
5 : : * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines
6 : : * which can be dynamically activated and de-activated by the line
7 : : * discipline handling modules (like SLIP).
8 : : */
9 : :
10 : : #include <linux/types.h>
11 : : #include <linux/termios.h>
12 : : #include <linux/errno.h>
13 : : #include <linux/sched/signal.h>
14 : : #include <linux/kernel.h>
15 : : #include <linux/major.h>
16 : : #include <linux/tty.h>
17 : : #include <linux/fcntl.h>
18 : : #include <linux/string.h>
19 : : #include <linux/mm.h>
20 : : #include <linux/module.h>
21 : : #include <linux/bitops.h>
22 : : #include <linux/mutex.h>
23 : : #include <linux/compat.h>
24 : :
25 : : #include <asm/io.h>
26 : : #include <linux/uaccess.h>
27 : :
28 : : #undef TTY_DEBUG_WAIT_UNTIL_SENT
29 : :
30 : : #ifdef TTY_DEBUG_WAIT_UNTIL_SENT
31 : : # define tty_debug_wait_until_sent(tty, f, args...) tty_debug(tty, f, ##args)
32 : : #else
33 : : # define tty_debug_wait_until_sent(tty, f, args...) do {} while (0)
34 : : #endif
35 : :
36 : : #undef DEBUG
37 : :
38 : : /*
39 : : * Internal flag options for termios setting behavior
40 : : */
41 : : #define TERMIOS_FLUSH 1
42 : : #define TERMIOS_WAIT 2
43 : : #define TERMIOS_TERMIO 4
44 : : #define TERMIOS_OLD 8
45 : :
46 : :
47 : : /**
48 : : * tty_chars_in_buffer - characters pending
49 : : * @tty: terminal
50 : : *
51 : : * Return the number of bytes of data in the device private
52 : : * output queue. If no private method is supplied there is assumed
53 : : * to be no queue on the device.
54 : : */
55 : :
56 : 979 : int tty_chars_in_buffer(struct tty_struct *tty)
57 : : {
58 [ # # ]: 0 : if (tty->ops->chars_in_buffer)
59 : 979 : return tty->ops->chars_in_buffer(tty);
60 : : else
61 : : return 0;
62 : : }
63 : : EXPORT_SYMBOL(tty_chars_in_buffer);
64 : :
65 : : /**
66 : : * tty_write_room - write queue space
67 : : * @tty: terminal
68 : : *
69 : : * Return the number of bytes that can be queued to this device
70 : : * at the present time. The result should be treated as a guarantee
71 : : * and the driver cannot offer a value it later shrinks by more than
72 : : * the number of bytes written. If no method is provided 2K is always
73 : : * returned and data may be lost as there will be no flow control.
74 : : */
75 : :
76 : 5148 : int tty_write_room(struct tty_struct *tty)
77 : : {
78 [ + - ]: 5148 : if (tty->ops->write_room)
79 : 5148 : return tty->ops->write_room(tty);
80 : : return 2048;
81 : : }
82 : : EXPORT_SYMBOL(tty_write_room);
83 : :
84 : : /**
85 : : * tty_driver_flush_buffer - discard internal buffer
86 : : * @tty: terminal
87 : : *
88 : : * Discard the internal output buffer for this device. If no method
89 : : * is provided then either the buffer cannot be hardware flushed or
90 : : * there is no buffer driver side.
91 : : */
92 : 11 : void tty_driver_flush_buffer(struct tty_struct *tty)
93 : : {
94 [ # # ]: 0 : if (tty->ops->flush_buffer)
95 : 11 : tty->ops->flush_buffer(tty);
96 : 0 : }
97 : : EXPORT_SYMBOL(tty_driver_flush_buffer);
98 : :
99 : : /**
100 : : * tty_throttle - flow control
101 : : * @tty: terminal
102 : : *
103 : : * Indicate that a tty should stop transmitting data down the stack.
104 : : * Takes the termios rwsem to protect against parallel throttle/unthrottle
105 : : * and also to ensure the driver can consistently reference its own
106 : : * termios data at this point when implementing software flow control.
107 : : */
108 : :
109 : 0 : void tty_throttle(struct tty_struct *tty)
110 : : {
111 : 0 : down_write(&tty->termios_rwsem);
112 : : /* check TTY_THROTTLED first so it indicates our state */
113 [ # # ]: 0 : if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) &&
114 [ # # ]: 0 : tty->ops->throttle)
115 : 0 : tty->ops->throttle(tty);
116 : 0 : tty->flow_change = 0;
117 : 0 : up_write(&tty->termios_rwsem);
118 : 0 : }
119 : : EXPORT_SYMBOL(tty_throttle);
120 : :
121 : : /**
122 : : * tty_unthrottle - flow control
123 : : * @tty: terminal
124 : : *
125 : : * Indicate that a tty may continue transmitting data down the stack.
126 : : * Takes the termios rwsem to protect against parallel throttle/unthrottle
127 : : * and also to ensure the driver can consistently reference its own
128 : : * termios data at this point when implementing software flow control.
129 : : *
130 : : * Drivers should however remember that the stack can issue a throttle,
131 : : * then change flow control method, then unthrottle.
132 : : */
133 : :
134 : 1001 : void tty_unthrottle(struct tty_struct *tty)
135 : : {
136 : 1001 : down_write(&tty->termios_rwsem);
137 [ - + ]: 1001 : if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
138 [ # # ]: 0 : tty->ops->unthrottle)
139 : 0 : tty->ops->unthrottle(tty);
140 : 1001 : tty->flow_change = 0;
141 : 1001 : up_write(&tty->termios_rwsem);
142 : 1001 : }
143 : : EXPORT_SYMBOL(tty_unthrottle);
144 : :
145 : : /**
146 : : * tty_throttle_safe - flow control
147 : : * @tty: terminal
148 : : *
149 : : * Similar to tty_throttle() but will only attempt throttle
150 : : * if tty->flow_change is TTY_THROTTLE_SAFE. Prevents an accidental
151 : : * throttle due to race conditions when throttling is conditional
152 : : * on factors evaluated prior to throttling.
153 : : *
154 : : * Returns 0 if tty is throttled (or was already throttled)
155 : : */
156 : :
157 : 0 : int tty_throttle_safe(struct tty_struct *tty)
158 : : {
159 : 0 : int ret = 0;
160 : :
161 : 0 : mutex_lock(&tty->throttle_mutex);
162 [ # # ]: 0 : if (!tty_throttled(tty)) {
163 [ # # ]: 0 : if (tty->flow_change != TTY_THROTTLE_SAFE)
164 : : ret = 1;
165 : : else {
166 : 0 : set_bit(TTY_THROTTLED, &tty->flags);
167 [ # # ]: 0 : if (tty->ops->throttle)
168 : 0 : tty->ops->throttle(tty);
169 : : }
170 : : }
171 : 0 : mutex_unlock(&tty->throttle_mutex);
172 : :
173 : 0 : return ret;
174 : : }
175 : :
176 : : /**
177 : : * tty_unthrottle_safe - flow control
178 : : * @tty: terminal
179 : : *
180 : : * Similar to tty_unthrottle() but will only attempt unthrottle
181 : : * if tty->flow_change is TTY_UNTHROTTLE_SAFE. Prevents an accidental
182 : : * unthrottle due to race conditions when unthrottling is conditional
183 : : * on factors evaluated prior to unthrottling.
184 : : *
185 : : * Returns 0 if tty is unthrottled (or was already unthrottled)
186 : : */
187 : :
188 : 0 : int tty_unthrottle_safe(struct tty_struct *tty)
189 : : {
190 : 0 : int ret = 0;
191 : :
192 : 0 : mutex_lock(&tty->throttle_mutex);
193 [ # # ]: 0 : if (tty_throttled(tty)) {
194 [ # # ]: 0 : if (tty->flow_change != TTY_UNTHROTTLE_SAFE)
195 : : ret = 1;
196 : : else {
197 : 0 : clear_bit(TTY_THROTTLED, &tty->flags);
198 [ # # ]: 0 : if (tty->ops->unthrottle)
199 : 0 : tty->ops->unthrottle(tty);
200 : : }
201 : : }
202 : 0 : mutex_unlock(&tty->throttle_mutex);
203 : :
204 : 0 : return ret;
205 : : }
206 : :
207 : : /**
208 : : * tty_wait_until_sent - wait for I/O to finish
209 : : * @tty: tty we are waiting for
210 : : * @timeout: how long we will wait
211 : : *
212 : : * Wait for characters pending in a tty driver to hit the wire, or
213 : : * for a timeout to occur (eg due to flow control)
214 : : *
215 : : * Locking: none
216 : : */
217 : :
218 : 979 : void tty_wait_until_sent(struct tty_struct *tty, long timeout)
219 : : {
220 : 979 : tty_debug_wait_until_sent(tty, "wait until sent, timeout=%ld\n", timeout);
221 : :
222 [ - + ]: 979 : if (!timeout)
223 : 0 : timeout = MAX_SCHEDULE_TIMEOUT;
224 : :
225 [ + - - + : 1958 : timeout = wait_event_interruptible_timeout(tty->write_wait,
- + - - -
- - - -
- ]
226 : : !tty_chars_in_buffer(tty), timeout);
227 [ + - ]: 979 : if (timeout <= 0)
228 : : return;
229 : :
230 [ - + ]: 979 : if (timeout == MAX_SCHEDULE_TIMEOUT)
231 : 0 : timeout = 0;
232 : :
233 [ + - ]: 979 : if (tty->ops->wait_until_sent)
234 : 979 : tty->ops->wait_until_sent(tty, timeout);
235 : : }
236 : : EXPORT_SYMBOL(tty_wait_until_sent);
237 : :
238 : :
239 : : /*
240 : : * Termios Helper Methods
241 : : */
242 : :
243 : 11 : static void unset_locked_termios(struct tty_struct *tty, struct ktermios *old)
244 : : {
245 : 11 : struct ktermios *termios = &tty->termios;
246 : 11 : struct ktermios *locked = &tty->termios_locked;
247 : 11 : int i;
248 : :
249 : : #define NOSET_MASK(x, y, z) (x = ((x) & ~(z)) | ((y) & (z)))
250 : :
251 : 11 : NOSET_MASK(termios->c_iflag, old->c_iflag, locked->c_iflag);
252 : 11 : NOSET_MASK(termios->c_oflag, old->c_oflag, locked->c_oflag);
253 : 11 : NOSET_MASK(termios->c_cflag, old->c_cflag, locked->c_cflag);
254 : 11 : NOSET_MASK(termios->c_lflag, old->c_lflag, locked->c_lflag);
255 [ - + ]: 11 : termios->c_line = locked->c_line ? old->c_line : termios->c_line;
256 [ + + ]: 220 : for (i = 0; i < NCCS; i++)
257 [ - + ]: 209 : termios->c_cc[i] = locked->c_cc[i] ?
258 : : old->c_cc[i] : termios->c_cc[i];
259 : : /* FIXME: What should we do for i/ospeed */
260 : 11 : }
261 : :
262 : : /**
263 : : * tty_termios_copy_hw - copy hardware settings
264 : : * @new: New termios
265 : : * @old: Old termios
266 : : *
267 : : * Propagate the hardware specific terminal setting bits from
268 : : * the old termios structure to the new one. This is used in cases
269 : : * where the hardware does not support reconfiguration or as a helper
270 : : * in some cases where only minimal reconfiguration is supported
271 : : */
272 : :
273 : 0 : void tty_termios_copy_hw(struct ktermios *new, struct ktermios *old)
274 : : {
275 : : /* The bits a dumb device handles in software. Smart devices need
276 : : to always provide a set_termios method */
277 : 0 : new->c_cflag &= HUPCL | CREAD | CLOCAL;
278 : 0 : new->c_cflag |= old->c_cflag & ~(HUPCL | CREAD | CLOCAL);
279 : 0 : new->c_ispeed = old->c_ispeed;
280 : 0 : new->c_ospeed = old->c_ospeed;
281 : 0 : }
282 : : EXPORT_SYMBOL(tty_termios_copy_hw);
283 : :
284 : : /**
285 : : * tty_termios_hw_change - check for setting change
286 : : * @a: termios
287 : : * @b: termios to compare
288 : : *
289 : : * Check if any of the bits that affect a dumb device have changed
290 : : * between the two termios structures, or a speed change is needed.
291 : : */
292 : :
293 : 0 : int tty_termios_hw_change(const struct ktermios *a, const struct ktermios *b)
294 : : {
295 [ # # # # ]: 0 : if (a->c_ispeed != b->c_ispeed || a->c_ospeed != b->c_ospeed)
296 : : return 1;
297 [ # # ]: 0 : if ((a->c_cflag ^ b->c_cflag) & ~(HUPCL | CREAD | CLOCAL))
298 : 0 : return 1;
299 : : return 0;
300 : : }
301 : : EXPORT_SYMBOL(tty_termios_hw_change);
302 : :
303 : : /**
304 : : * tty_set_termios - update termios values
305 : : * @tty: tty to update
306 : : * @new_termios: desired new value
307 : : *
308 : : * Perform updates to the termios values set on this terminal.
309 : : * A master pty's termios should never be set.
310 : : *
311 : : * Locking: termios_rwsem
312 : : */
313 : :
314 : 11 : int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios)
315 : : {
316 : 11 : struct ktermios old_termios;
317 : 11 : struct tty_ldisc *ld;
318 : :
319 [ - + ]: 11 : WARN_ON(tty->driver->type == TTY_DRIVER_TYPE_PTY &&
320 : : tty->driver->subtype == PTY_TYPE_MASTER);
321 : : /*
322 : : * Perform the actual termios internal changes under lock.
323 : : */
324 : :
325 : :
326 : : /* FIXME: we need to decide on some locking/ordering semantics
327 : : for the set_termios notification eventually */
328 : 11 : down_write(&tty->termios_rwsem);
329 : 11 : old_termios = tty->termios;
330 : 11 : tty->termios = *new_termios;
331 : 11 : unset_locked_termios(tty, &old_termios);
332 : :
333 [ + - ]: 11 : if (tty->ops->set_termios)
334 : 11 : tty->ops->set_termios(tty, &old_termios);
335 : : else
336 : 0 : tty_termios_copy_hw(&tty->termios, &old_termios);
337 : :
338 : 11 : ld = tty_ldisc_ref(tty);
339 [ + - ]: 11 : if (ld != NULL) {
340 [ + - ]: 11 : if (ld->ops->set_termios)
341 : 11 : ld->ops->set_termios(tty, &old_termios);
342 : 11 : tty_ldisc_deref(ld);
343 : : }
344 : 11 : up_write(&tty->termios_rwsem);
345 : 11 : return 0;
346 : : }
347 : : EXPORT_SYMBOL_GPL(tty_set_termios);
348 : :
349 : : /**
350 : : * set_termios - set termios values for a tty
351 : : * @tty: terminal device
352 : : * @arg: user data
353 : : * @opt: option information
354 : : *
355 : : * Helper function to prepare termios data and run necessary other
356 : : * functions before using tty_set_termios to do the actual changes.
357 : : *
358 : : * Locking:
359 : : * Called functions take ldisc and termios_rwsem locks
360 : : */
361 : :
362 : 11 : static int set_termios(struct tty_struct *tty, void __user *arg, int opt)
363 : : {
364 : 11 : struct ktermios tmp_termios;
365 : 11 : struct tty_ldisc *ld;
366 : 11 : int retval = tty_check_change(tty);
367 : :
368 [ + - ]: 11 : if (retval)
369 : : return retval;
370 : :
371 : 11 : down_read(&tty->termios_rwsem);
372 : 11 : tmp_termios = tty->termios;
373 : 11 : up_read(&tty->termios_rwsem);
374 : :
375 [ - + ]: 11 : if (opt & TERMIOS_TERMIO) {
376 [ # # ]: 0 : if (user_termio_to_kernel_termios(&tmp_termios,
377 : : (struct termio __user *)arg))
378 : : return -EFAULT;
379 : : #ifdef TCGETS2
380 [ + - ]: 11 : } else if (opt & TERMIOS_OLD) {
381 [ + - ]: 11 : if (user_termios_to_kernel_termios_1(&tmp_termios,
382 : : (struct termios __user *)arg))
383 : : return -EFAULT;
384 : : } else {
385 [ # # ]: 0 : if (user_termios_to_kernel_termios(&tmp_termios,
386 : : (struct termios2 __user *)arg))
387 : : return -EFAULT;
388 : : }
389 : : #else
390 : : } else if (user_termios_to_kernel_termios(&tmp_termios,
391 : : (struct termios __user *)arg))
392 : : return -EFAULT;
393 : : #endif
394 : :
395 : : /* If old style Bfoo values are used then load c_ispeed/c_ospeed
396 : : * with the real speed so its unconditionally usable */
397 : 11 : tmp_termios.c_ispeed = tty_termios_input_baud_rate(&tmp_termios);
398 : 11 : tmp_termios.c_ospeed = tty_termios_baud_rate(&tmp_termios);
399 : :
400 : 11 : ld = tty_ldisc_ref(tty);
401 : :
402 [ + - ]: 11 : if (ld != NULL) {
403 [ - + - - ]: 11 : if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer)
404 : 0 : ld->ops->flush_buffer(tty);
405 : 11 : tty_ldisc_deref(ld);
406 : : }
407 : :
408 [ - + ]: 11 : if (opt & TERMIOS_WAIT) {
409 : 0 : tty_wait_until_sent(tty, 0);
410 [ # # ]: 0 : if (signal_pending(current))
411 : : return -ERESTARTSYS;
412 : : }
413 : :
414 : 11 : tty_set_termios(tty, &tmp_termios);
415 : :
416 : : /* FIXME: Arguably if tmp_termios == tty->termios AND the
417 : : actual requested termios was not tmp_termios then we may
418 : : want to return an error as no user requested change has
419 : : succeeded */
420 : 11 : return 0;
421 : : }
422 : :
423 : 1012 : static void copy_termios(struct tty_struct *tty, struct ktermios *kterm)
424 : : {
425 : 1012 : down_read(&tty->termios_rwsem);
426 : 1012 : *kterm = tty->termios;
427 : 1012 : up_read(&tty->termios_rwsem);
428 : 1012 : }
429 : :
430 : 0 : static void copy_termios_locked(struct tty_struct *tty, struct ktermios *kterm)
431 : : {
432 : 0 : down_read(&tty->termios_rwsem);
433 : 0 : *kterm = tty->termios_locked;
434 : 0 : up_read(&tty->termios_rwsem);
435 : 0 : }
436 : :
437 : 0 : static int get_termio(struct tty_struct *tty, struct termio __user *termio)
438 : : {
439 : 0 : struct ktermios kterm;
440 : 0 : copy_termios(tty, &kterm);
441 [ # # ]: 0 : if (kernel_termios_to_user_termio(termio, &kterm))
442 : 0 : return -EFAULT;
443 : : return 0;
444 : : }
445 : :
446 : :
447 : : #ifdef TCGETX
448 : :
449 : : /**
450 : : * set_termiox - set termiox fields if possible
451 : : * @tty: terminal
452 : : * @arg: termiox structure from user
453 : : * @opt: option flags for ioctl type
454 : : *
455 : : * Implement the device calling points for the SYS5 termiox ioctl
456 : : * interface in Linux
457 : : */
458 : :
459 : 0 : static int set_termiox(struct tty_struct *tty, void __user *arg, int opt)
460 : : {
461 : 0 : struct termiox tnew;
462 : 0 : struct tty_ldisc *ld;
463 : :
464 [ # # ]: 0 : if (tty->termiox == NULL)
465 : : return -EINVAL;
466 [ # # ]: 0 : if (copy_from_user(&tnew, arg, sizeof(struct termiox)))
467 : : return -EFAULT;
468 : :
469 : 0 : ld = tty_ldisc_ref(tty);
470 [ # # ]: 0 : if (ld != NULL) {
471 [ # # # # ]: 0 : if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer)
472 : 0 : ld->ops->flush_buffer(tty);
473 : 0 : tty_ldisc_deref(ld);
474 : : }
475 [ # # ]: 0 : if (opt & TERMIOS_WAIT) {
476 : 0 : tty_wait_until_sent(tty, 0);
477 [ # # ]: 0 : if (signal_pending(current))
478 : : return -ERESTARTSYS;
479 : : }
480 : :
481 : 0 : down_write(&tty->termios_rwsem);
482 [ # # ]: 0 : if (tty->ops->set_termiox)
483 : 0 : tty->ops->set_termiox(tty, &tnew);
484 : 0 : up_write(&tty->termios_rwsem);
485 : 0 : return 0;
486 : : }
487 : :
488 : : #endif
489 : :
490 : :
491 : : #ifdef TIOCGETP
492 : : /*
493 : : * These are deprecated, but there is limited support..
494 : : *
495 : : * The "sg_flags" translation is a joke..
496 : : */
497 : : static int get_sgflags(struct tty_struct *tty)
498 : : {
499 : : int flags = 0;
500 : :
501 : : if (!L_ICANON(tty)) {
502 : : if (L_ISIG(tty))
503 : : flags |= 0x02; /* cbreak */
504 : : else
505 : : flags |= 0x20; /* raw */
506 : : }
507 : : if (L_ECHO(tty))
508 : : flags |= 0x08; /* echo */
509 : : if (O_OPOST(tty))
510 : : if (O_ONLCR(tty))
511 : : flags |= 0x10; /* crmod */
512 : : return flags;
513 : : }
514 : :
515 : : static int get_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
516 : : {
517 : : struct sgttyb tmp;
518 : :
519 : : down_read(&tty->termios_rwsem);
520 : : tmp.sg_ispeed = tty->termios.c_ispeed;
521 : : tmp.sg_ospeed = tty->termios.c_ospeed;
522 : : tmp.sg_erase = tty->termios.c_cc[VERASE];
523 : : tmp.sg_kill = tty->termios.c_cc[VKILL];
524 : : tmp.sg_flags = get_sgflags(tty);
525 : : up_read(&tty->termios_rwsem);
526 : :
527 : : return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0;
528 : : }
529 : :
530 : : static void set_sgflags(struct ktermios *termios, int flags)
531 : : {
532 : : termios->c_iflag = ICRNL | IXON;
533 : : termios->c_oflag = 0;
534 : : termios->c_lflag = ISIG | ICANON;
535 : : if (flags & 0x02) { /* cbreak */
536 : : termios->c_iflag = 0;
537 : : termios->c_lflag &= ~ICANON;
538 : : }
539 : : if (flags & 0x08) { /* echo */
540 : : termios->c_lflag |= ECHO | ECHOE | ECHOK |
541 : : ECHOCTL | ECHOKE | IEXTEN;
542 : : }
543 : : if (flags & 0x10) { /* crmod */
544 : : termios->c_oflag |= OPOST | ONLCR;
545 : : }
546 : : if (flags & 0x20) { /* raw */
547 : : termios->c_iflag = 0;
548 : : termios->c_lflag &= ~(ISIG | ICANON);
549 : : }
550 : : if (!(termios->c_lflag & ICANON)) {
551 : : termios->c_cc[VMIN] = 1;
552 : : termios->c_cc[VTIME] = 0;
553 : : }
554 : : }
555 : :
556 : : /**
557 : : * set_sgttyb - set legacy terminal values
558 : : * @tty: tty structure
559 : : * @sgttyb: pointer to old style terminal structure
560 : : *
561 : : * Updates a terminal from the legacy BSD style terminal information
562 : : * structure.
563 : : *
564 : : * Locking: termios_rwsem
565 : : */
566 : :
567 : : static int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
568 : : {
569 : : int retval;
570 : : struct sgttyb tmp;
571 : : struct ktermios termios;
572 : :
573 : : retval = tty_check_change(tty);
574 : : if (retval)
575 : : return retval;
576 : :
577 : : if (copy_from_user(&tmp, sgttyb, sizeof(tmp)))
578 : : return -EFAULT;
579 : :
580 : : down_write(&tty->termios_rwsem);
581 : : termios = tty->termios;
582 : : termios.c_cc[VERASE] = tmp.sg_erase;
583 : : termios.c_cc[VKILL] = tmp.sg_kill;
584 : : set_sgflags(&termios, tmp.sg_flags);
585 : : /* Try and encode into Bfoo format */
586 : : #ifdef BOTHER
587 : : tty_termios_encode_baud_rate(&termios, termios.c_ispeed,
588 : : termios.c_ospeed);
589 : : #endif
590 : : up_write(&tty->termios_rwsem);
591 : : tty_set_termios(tty, &termios);
592 : : return 0;
593 : : }
594 : : #endif
595 : :
596 : : #ifdef TIOCGETC
597 : : static int get_tchars(struct tty_struct *tty, struct tchars __user *tchars)
598 : : {
599 : : struct tchars tmp;
600 : :
601 : : down_read(&tty->termios_rwsem);
602 : : tmp.t_intrc = tty->termios.c_cc[VINTR];
603 : : tmp.t_quitc = tty->termios.c_cc[VQUIT];
604 : : tmp.t_startc = tty->termios.c_cc[VSTART];
605 : : tmp.t_stopc = tty->termios.c_cc[VSTOP];
606 : : tmp.t_eofc = tty->termios.c_cc[VEOF];
607 : : tmp.t_brkc = tty->termios.c_cc[VEOL2]; /* what is brkc anyway? */
608 : : up_read(&tty->termios_rwsem);
609 : : return copy_to_user(tchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
610 : : }
611 : :
612 : : static int set_tchars(struct tty_struct *tty, struct tchars __user *tchars)
613 : : {
614 : : struct tchars tmp;
615 : :
616 : : if (copy_from_user(&tmp, tchars, sizeof(tmp)))
617 : : return -EFAULT;
618 : : down_write(&tty->termios_rwsem);
619 : : tty->termios.c_cc[VINTR] = tmp.t_intrc;
620 : : tty->termios.c_cc[VQUIT] = tmp.t_quitc;
621 : : tty->termios.c_cc[VSTART] = tmp.t_startc;
622 : : tty->termios.c_cc[VSTOP] = tmp.t_stopc;
623 : : tty->termios.c_cc[VEOF] = tmp.t_eofc;
624 : : tty->termios.c_cc[VEOL2] = tmp.t_brkc; /* what is brkc anyway? */
625 : : up_write(&tty->termios_rwsem);
626 : : return 0;
627 : : }
628 : : #endif
629 : :
630 : : #ifdef TIOCGLTC
631 : : static int get_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
632 : : {
633 : : struct ltchars tmp;
634 : :
635 : : down_read(&tty->termios_rwsem);
636 : : tmp.t_suspc = tty->termios.c_cc[VSUSP];
637 : : /* what is dsuspc anyway? */
638 : : tmp.t_dsuspc = tty->termios.c_cc[VSUSP];
639 : : tmp.t_rprntc = tty->termios.c_cc[VREPRINT];
640 : : /* what is flushc anyway? */
641 : : tmp.t_flushc = tty->termios.c_cc[VEOL2];
642 : : tmp.t_werasc = tty->termios.c_cc[VWERASE];
643 : : tmp.t_lnextc = tty->termios.c_cc[VLNEXT];
644 : : up_read(&tty->termios_rwsem);
645 : : return copy_to_user(ltchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
646 : : }
647 : :
648 : : static int set_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
649 : : {
650 : : struct ltchars tmp;
651 : :
652 : : if (copy_from_user(&tmp, ltchars, sizeof(tmp)))
653 : : return -EFAULT;
654 : :
655 : : down_write(&tty->termios_rwsem);
656 : : tty->termios.c_cc[VSUSP] = tmp.t_suspc;
657 : : /* what is dsuspc anyway? */
658 : : tty->termios.c_cc[VEOL2] = tmp.t_dsuspc;
659 : : tty->termios.c_cc[VREPRINT] = tmp.t_rprntc;
660 : : /* what is flushc anyway? */
661 : : tty->termios.c_cc[VEOL2] = tmp.t_flushc;
662 : : tty->termios.c_cc[VWERASE] = tmp.t_werasc;
663 : : tty->termios.c_cc[VLNEXT] = tmp.t_lnextc;
664 : : up_write(&tty->termios_rwsem);
665 : : return 0;
666 : : }
667 : : #endif
668 : :
669 : : /**
670 : : * tty_change_softcar - carrier change ioctl helper
671 : : * @tty: tty to update
672 : : * @arg: enable/disable CLOCAL
673 : : *
674 : : * Perform a change to the CLOCAL state and call into the driver
675 : : * layer to make it visible. All done with the termios rwsem
676 : : */
677 : :
678 : 0 : static int tty_change_softcar(struct tty_struct *tty, int arg)
679 : : {
680 : 0 : int ret = 0;
681 [ # # ]: 0 : int bit = arg ? CLOCAL : 0;
682 : 0 : struct ktermios old;
683 : :
684 : 0 : down_write(&tty->termios_rwsem);
685 : 0 : old = tty->termios;
686 : 0 : tty->termios.c_cflag &= ~CLOCAL;
687 : 0 : tty->termios.c_cflag |= bit;
688 [ # # ]: 0 : if (tty->ops->set_termios)
689 : 0 : tty->ops->set_termios(tty, &old);
690 [ # # ]: 0 : if (C_CLOCAL(tty) != bit)
691 : 0 : ret = -EINVAL;
692 : 0 : up_write(&tty->termios_rwsem);
693 : 0 : return ret;
694 : : }
695 : :
696 : : /**
697 : : * tty_mode_ioctl - mode related ioctls
698 : : * @tty: tty for the ioctl
699 : : * @file: file pointer for the tty
700 : : * @cmd: command
701 : : * @arg: ioctl argument
702 : : *
703 : : * Perform non line discipline specific mode control ioctls. This
704 : : * is designed to be called by line disciplines to ensure they provide
705 : : * consistent mode setting.
706 : : */
707 : :
708 : 1034 : int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
709 : : unsigned int cmd, unsigned long arg)
710 : : {
711 : 1034 : struct tty_struct *real_tty;
712 : 1034 : void __user *p = (void __user *)arg;
713 : 1034 : int ret = 0;
714 : 1034 : struct ktermios kterm;
715 : :
716 [ - + ]: 1034 : BUG_ON(file == NULL);
717 : :
718 [ - + ]: 1034 : if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
719 : : tty->driver->subtype == PTY_TYPE_MASTER)
720 : 0 : real_tty = tty->link;
721 : : else
722 : : real_tty = tty;
723 : :
724 [ - - + + : 1034 : switch (cmd) {
- - - - -
- - - - -
- - - - -
- + ]
725 : : #ifdef TIOCGETP
726 : : case TIOCGETP:
727 : : return get_sgttyb(real_tty, (struct sgttyb __user *) arg);
728 : : case TIOCSETP:
729 : : case TIOCSETN:
730 : : return set_sgttyb(real_tty, (struct sgttyb __user *) arg);
731 : : #endif
732 : : #ifdef TIOCGETC
733 : : case TIOCGETC:
734 : : return get_tchars(real_tty, p);
735 : : case TIOCSETC:
736 : : return set_tchars(real_tty, p);
737 : : #endif
738 : : #ifdef TIOCGLTC
739 : : case TIOCGLTC:
740 : : return get_ltchars(real_tty, p);
741 : : case TIOCSLTC:
742 : : return set_ltchars(real_tty, p);
743 : : #endif
744 : 0 : case TCSETSF:
745 : 0 : return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_OLD);
746 : 0 : case TCSETSW:
747 : 0 : return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_OLD);
748 : 11 : case TCSETS:
749 : 11 : return set_termios(real_tty, p, TERMIOS_OLD);
750 : : #ifndef TCGETS2
751 : : case TCGETS:
752 : : copy_termios(real_tty, &kterm);
753 : : if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm))
754 : : ret = -EFAULT;
755 : : return ret;
756 : : #else
757 : 1012 : case TCGETS:
758 : 1012 : copy_termios(real_tty, &kterm);
759 [ - + ]: 1012 : if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm))
760 : 0 : ret = -EFAULT;
761 : : return ret;
762 : 0 : case TCGETS2:
763 : 0 : copy_termios(real_tty, &kterm);
764 [ # # ]: 0 : if (kernel_termios_to_user_termios((struct termios2 __user *)arg, &kterm))
765 : 0 : ret = -EFAULT;
766 : : return ret;
767 : 0 : case TCSETSF2:
768 : 0 : return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT);
769 : 0 : case TCSETSW2:
770 : 0 : return set_termios(real_tty, p, TERMIOS_WAIT);
771 : 0 : case TCSETS2:
772 : 0 : return set_termios(real_tty, p, 0);
773 : : #endif
774 : 0 : case TCGETA:
775 : 0 : return get_termio(real_tty, p);
776 : 0 : case TCSETAF:
777 : 0 : return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_TERMIO);
778 : 0 : case TCSETAW:
779 : 0 : return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_TERMIO);
780 : 0 : case TCSETA:
781 : 0 : return set_termios(real_tty, p, TERMIOS_TERMIO);
782 : : #ifndef TCGETS2
783 : : case TIOCGLCKTRMIOS:
784 : : copy_termios_locked(real_tty, &kterm);
785 : : if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm))
786 : : ret = -EFAULT;
787 : : return ret;
788 : : case TIOCSLCKTRMIOS:
789 : : if (!capable(CAP_SYS_ADMIN))
790 : : return -EPERM;
791 : : copy_termios_locked(real_tty, &kterm);
792 : : if (user_termios_to_kernel_termios(&kterm,
793 : : (struct termios __user *) arg))
794 : : return -EFAULT;
795 : : down_write(&real_tty->termios_rwsem);
796 : : real_tty->termios_locked = kterm;
797 : : up_write(&real_tty->termios_rwsem);
798 : : return 0;
799 : : #else
800 : 0 : case TIOCGLCKTRMIOS:
801 : 0 : copy_termios_locked(real_tty, &kterm);
802 [ # # ]: 0 : if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm))
803 : 0 : ret = -EFAULT;
804 : : return ret;
805 : 0 : case TIOCSLCKTRMIOS:
806 [ # # ]: 0 : if (!capable(CAP_SYS_ADMIN))
807 : : return -EPERM;
808 : 0 : copy_termios_locked(real_tty, &kterm);
809 [ # # ]: 0 : if (user_termios_to_kernel_termios_1(&kterm,
810 : : (struct termios __user *) arg))
811 : : return -EFAULT;
812 : 0 : down_write(&real_tty->termios_rwsem);
813 : 0 : real_tty->termios_locked = kterm;
814 : 0 : up_write(&real_tty->termios_rwsem);
815 : 0 : return ret;
816 : : #endif
817 : : #ifdef TCGETX
818 : 0 : case TCGETX: {
819 : 0 : struct termiox ktermx;
820 [ # # ]: 0 : if (real_tty->termiox == NULL)
821 : : return -EINVAL;
822 : 0 : down_read(&real_tty->termios_rwsem);
823 : 0 : memcpy(&ktermx, real_tty->termiox, sizeof(struct termiox));
824 : 0 : up_read(&real_tty->termios_rwsem);
825 [ # # ]: 0 : if (copy_to_user(p, &ktermx, sizeof(struct termiox)))
826 : 0 : ret = -EFAULT;
827 : : return ret;
828 : : }
829 : 0 : case TCSETX:
830 : 0 : return set_termiox(real_tty, p, 0);
831 : 0 : case TCSETXW:
832 : 0 : return set_termiox(real_tty, p, TERMIOS_WAIT);
833 : 0 : case TCSETXF:
834 : 0 : return set_termiox(real_tty, p, TERMIOS_FLUSH);
835 : : #endif
836 : 0 : case TIOCGSOFTCAR:
837 : 0 : copy_termios(real_tty, &kterm);
838 : 0 : ret = put_user((kterm.c_cflag & CLOCAL) ? 1 : 0,
839 : : (int __user *)arg);
840 : 0 : return ret;
841 : : case TIOCSSOFTCAR:
842 [ # # ]: 0 : if (get_user(arg, (unsigned int __user *) arg))
843 : : return -EFAULT;
844 : 0 : return tty_change_softcar(real_tty, arg);
845 : : default:
846 : : return -ENOIOCTLCMD;
847 : : }
848 : : }
849 : : EXPORT_SYMBOL_GPL(tty_mode_ioctl);
850 : :
851 : :
852 : : /* Caller guarantees ldisc reference is held */
853 : 11 : static int __tty_perform_flush(struct tty_struct *tty, unsigned long arg)
854 : : {
855 : 11 : struct tty_ldisc *ld = tty->ldisc;
856 : :
857 [ - + - - ]: 11 : switch (arg) {
858 : 0 : case TCIFLUSH:
859 [ # # # # ]: 0 : if (ld && ld->ops->flush_buffer) {
860 : 0 : ld->ops->flush_buffer(tty);
861 : 0 : tty_unthrottle(tty);
862 : : }
863 : : break;
864 : 11 : case TCIOFLUSH:
865 [ + - + - ]: 11 : if (ld && ld->ops->flush_buffer) {
866 : 11 : ld->ops->flush_buffer(tty);
867 : 11 : tty_unthrottle(tty);
868 : : }
869 : : /* fall through */
870 : : case TCOFLUSH:
871 [ + - ]: 11 : tty_driver_flush_buffer(tty);
872 : : break;
873 : : default:
874 : : return -EINVAL;
875 : : }
876 : : return 0;
877 : : }
878 : :
879 : 0 : int tty_perform_flush(struct tty_struct *tty, unsigned long arg)
880 : : {
881 : 0 : struct tty_ldisc *ld;
882 : 0 : int retval = tty_check_change(tty);
883 [ # # ]: 0 : if (retval)
884 : : return retval;
885 : :
886 : 0 : ld = tty_ldisc_ref_wait(tty);
887 : 0 : retval = __tty_perform_flush(tty, arg);
888 [ # # ]: 0 : if (ld)
889 : 0 : tty_ldisc_deref(ld);
890 : : return retval;
891 : : }
892 : : EXPORT_SYMBOL_GPL(tty_perform_flush);
893 : :
894 : 1045 : int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
895 : : unsigned int cmd, unsigned long arg)
896 : : {
897 : 1045 : int retval;
898 : :
899 [ - + + ]: 1045 : switch (cmd) {
900 : 0 : case TCXONC:
901 : 0 : retval = tty_check_change(tty);
902 [ # # ]: 0 : if (retval)
903 : : return retval;
904 [ # # # # : 0 : switch (arg) {
# ]
905 : 0 : case TCOOFF:
906 : 0 : spin_lock_irq(&tty->flow_lock);
907 [ # # ]: 0 : if (!tty->flow_stopped) {
908 : 0 : tty->flow_stopped = 1;
909 : 0 : __stop_tty(tty);
910 : : }
911 : 0 : spin_unlock_irq(&tty->flow_lock);
912 : : break;
913 : 0 : case TCOON:
914 : 0 : spin_lock_irq(&tty->flow_lock);
915 [ # # ]: 0 : if (tty->flow_stopped) {
916 : 0 : tty->flow_stopped = 0;
917 : 0 : __start_tty(tty);
918 : : }
919 : 0 : spin_unlock_irq(&tty->flow_lock);
920 : : break;
921 : 0 : case TCIOFF:
922 [ # # ]: 0 : if (STOP_CHAR(tty) != __DISABLED_CHAR)
923 : 0 : retval = tty_send_xchar(tty, STOP_CHAR(tty));
924 : : break;
925 : 0 : case TCION:
926 [ # # ]: 0 : if (START_CHAR(tty) != __DISABLED_CHAR)
927 : 0 : retval = tty_send_xchar(tty, START_CHAR(tty));
928 : : break;
929 : : default:
930 : : return -EINVAL;
931 : : }
932 : : return retval;
933 : 11 : case TCFLSH:
934 : 11 : retval = tty_check_change(tty);
935 [ + - ]: 11 : if (retval)
936 : : return retval;
937 : 11 : return __tty_perform_flush(tty, arg);
938 : 1034 : default:
939 : : /* Try the mode commands */
940 : 1034 : return tty_mode_ioctl(tty, file, cmd, arg);
941 : : }
942 : : }
943 : : EXPORT_SYMBOL(n_tty_ioctl_helper);
|