LCOV - code coverage report
Current view: top level - drivers/tty - tty_ioctl.c (source / functions) Hit Total Coverage
Test: landlock.info Lines: 144 260 55.4 %
Date: 2021-04-22 12:43:58 Functions: 13 21 61.9 %

          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         430 : int tty_chars_in_buffer(struct tty_struct *tty)
      57             : {
      58           1 :         if (tty->ops->chars_in_buffer)
      59         430 :                 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         283 : int tty_write_room(struct tty_struct *tty)
      77             : {
      78         283 :         if (tty->ops->write_room)
      79         283 :                 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           3 : void tty_driver_flush_buffer(struct tty_struct *tty)
      93             : {
      94           1 :         if (tty->ops->flush_buffer)
      95           1 :                 tty->ops->flush_buffer(tty);
      96           1 : }
      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         166 : void tty_unthrottle(struct tty_struct *tty)
     135             : {
     136         166 :         down_write(&tty->termios_rwsem);
     137         166 :         if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
     138           0 :             tty->ops->unthrottle)
     139           0 :                 tty->ops->unthrottle(tty);
     140         166 :         tty->flow_change = 0;
     141         166 :         up_write(&tty->termios_rwsem);
     142         166 : }
     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         136 : void tty_wait_until_sent(struct tty_struct *tty, long timeout)
     219             : {
     220         136 :         tty_debug_wait_until_sent(tty, "wait until sent, timeout=%ld\n", timeout);
     221             : 
     222         136 :         if (!timeout)
     223           1 :                 timeout = MAX_SCHEDULE_TIMEOUT;
     224             : 
     225         565 :         timeout = wait_event_interruptible_timeout(tty->write_wait,
     226             :                         !tty_chars_in_buffer(tty), timeout);
     227         136 :         if (timeout <= 0)
     228             :                 return;
     229             : 
     230         136 :         if (timeout == MAX_SCHEDULE_TIMEOUT)
     231           1 :                 timeout = 0;
     232             : 
     233         136 :         if (tty->ops->wait_until_sent)
     234         135 :                 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           3 : static void unset_locked_termios(struct tty_struct *tty, struct ktermios *old)
     244             : {
     245           3 :         struct ktermios *termios = &tty->termios;
     246           3 :         struct ktermios *locked  = &tty->termios_locked;
     247           3 :         int     i;
     248             : 
     249             : #define NOSET_MASK(x, y, z) (x = ((x) & ~(z)) | ((y) & (z)))
     250             : 
     251           3 :         NOSET_MASK(termios->c_iflag, old->c_iflag, locked->c_iflag);
     252           3 :         NOSET_MASK(termios->c_oflag, old->c_oflag, locked->c_oflag);
     253           3 :         NOSET_MASK(termios->c_cflag, old->c_cflag, locked->c_cflag);
     254           3 :         NOSET_MASK(termios->c_lflag, old->c_lflag, locked->c_lflag);
     255           3 :         termios->c_line = locked->c_line ? old->c_line : termios->c_line;
     256          60 :         for (i = 0; i < NCCS; i++)
     257          57 :                 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           3 : }
     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           2 : 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           2 :         new->c_cflag &= HUPCL | CREAD | CLOCAL;
     278           2 :         new->c_cflag |= old->c_cflag & ~(HUPCL | CREAD | CLOCAL);
     279           2 :         new->c_ispeed = old->c_ispeed;
     280           2 :         new->c_ospeed = old->c_ospeed;
     281           2 : }
     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           3 : int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios)
     315             : {
     316           3 :         struct ktermios old_termios;
     317           3 :         struct tty_ldisc *ld;
     318             : 
     319           3 :         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           3 :         down_write(&tty->termios_rwsem);
     329           3 :         old_termios = tty->termios;
     330           3 :         tty->termios = *new_termios;
     331           3 :         unset_locked_termios(tty, &old_termios);
     332             : 
     333           3 :         if (tty->ops->set_termios)
     334           1 :                 tty->ops->set_termios(tty, &old_termios);
     335             :         else
     336           2 :                 tty_termios_copy_hw(&tty->termios, &old_termios);
     337             : 
     338           3 :         ld = tty_ldisc_ref(tty);
     339           3 :         if (ld != NULL) {
     340           3 :                 if (ld->ops->set_termios)
     341           3 :                         ld->ops->set_termios(tty, &old_termios);
     342           3 :                 tty_ldisc_deref(ld);
     343             :         }
     344           3 :         up_write(&tty->termios_rwsem);
     345           3 :         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           3 : static int set_termios(struct tty_struct *tty, void __user *arg, int opt)
     363             : {
     364           3 :         struct ktermios tmp_termios;
     365           3 :         struct tty_ldisc *ld;
     366           3 :         int retval = tty_check_change(tty);
     367             : 
     368           3 :         if (retval)
     369             :                 return retval;
     370             : 
     371           3 :         down_read(&tty->termios_rwsem);
     372           3 :         tmp_termios = tty->termios;
     373           3 :         up_read(&tty->termios_rwsem);
     374             : 
     375           3 :         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           3 :         } else if (opt & TERMIOS_OLD) {
     381           3 :                 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           3 :         tmp_termios.c_ispeed = tty_termios_input_baud_rate(&tmp_termios);
     398           3 :         tmp_termios.c_ospeed = tty_termios_baud_rate(&tmp_termios);
     399             : 
     400           3 :         ld = tty_ldisc_ref(tty);
     401             : 
     402           3 :         if (ld != NULL) {
     403           3 :                 if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer)
     404           0 :                         ld->ops->flush_buffer(tty);
     405           3 :                 tty_ldisc_deref(ld);
     406             :         }
     407             : 
     408           3 :         if (opt & TERMIOS_WAIT) {
     409           1 :                 tty_wait_until_sent(tty, 0);
     410           1 :                 if (signal_pending(current))
     411             :                         return -ERESTARTSYS;
     412             :         }
     413             : 
     414           3 :         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           3 :         return 0;
     421             : }
     422             : 
     423         163 : static void copy_termios(struct tty_struct *tty, struct ktermios *kterm)
     424             : {
     425         163 :         down_read(&tty->termios_rwsem);
     426         163 :         *kterm = tty->termios;
     427         163 :         up_read(&tty->termios_rwsem);
     428         163 : }
     429             : 
     430           2 : static void copy_termios_locked(struct tty_struct *tty, struct ktermios *kterm)
     431             : {
     432           2 :         down_read(&tty->termios_rwsem);
     433           2 :         *kterm = tty->termios_locked;
     434           2 :         up_read(&tty->termios_rwsem);
     435           2 : }
     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             : #ifdef TIOCGETP
     447             : /*
     448             :  * These are deprecated, but there is limited support..
     449             :  *
     450             :  * The "sg_flags" translation is a joke..
     451             :  */
     452             : static int get_sgflags(struct tty_struct *tty)
     453             : {
     454             :         int flags = 0;
     455             : 
     456             :         if (!L_ICANON(tty)) {
     457             :                 if (L_ISIG(tty))
     458             :                         flags |= 0x02;          /* cbreak */
     459             :                 else
     460             :                         flags |= 0x20;          /* raw */
     461             :         }
     462             :         if (L_ECHO(tty))
     463             :                 flags |= 0x08;                  /* echo */
     464             :         if (O_OPOST(tty))
     465             :                 if (O_ONLCR(tty))
     466             :                         flags |= 0x10;          /* crmod */
     467             :         return flags;
     468             : }
     469             : 
     470             : static int get_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
     471             : {
     472             :         struct sgttyb tmp;
     473             : 
     474             :         down_read(&tty->termios_rwsem);
     475             :         tmp.sg_ispeed = tty->termios.c_ispeed;
     476             :         tmp.sg_ospeed = tty->termios.c_ospeed;
     477             :         tmp.sg_erase = tty->termios.c_cc[VERASE];
     478             :         tmp.sg_kill = tty->termios.c_cc[VKILL];
     479             :         tmp.sg_flags = get_sgflags(tty);
     480             :         up_read(&tty->termios_rwsem);
     481             : 
     482             :         return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0;
     483             : }
     484             : 
     485             : static void set_sgflags(struct ktermios *termios, int flags)
     486             : {
     487             :         termios->c_iflag = ICRNL | IXON;
     488             :         termios->c_oflag = 0;
     489             :         termios->c_lflag = ISIG | ICANON;
     490             :         if (flags & 0x02) { /* cbreak */
     491             :                 termios->c_iflag = 0;
     492             :                 termios->c_lflag &= ~ICANON;
     493             :         }
     494             :         if (flags & 0x08) {         /* echo */
     495             :                 termios->c_lflag |= ECHO | ECHOE | ECHOK |
     496             :                                     ECHOCTL | ECHOKE | IEXTEN;
     497             :         }
     498             :         if (flags & 0x10) {         /* crmod */
     499             :                 termios->c_oflag |= OPOST | ONLCR;
     500             :         }
     501             :         if (flags & 0x20) { /* raw */
     502             :                 termios->c_iflag = 0;
     503             :                 termios->c_lflag &= ~(ISIG | ICANON);
     504             :         }
     505             :         if (!(termios->c_lflag & ICANON)) {
     506             :                 termios->c_cc[VMIN] = 1;
     507             :                 termios->c_cc[VTIME] = 0;
     508             :         }
     509             : }
     510             : 
     511             : /**
     512             :  *      set_sgttyb              -       set legacy terminal values
     513             :  *      @tty: tty structure
     514             :  *      @sgttyb: pointer to old style terminal structure
     515             :  *
     516             :  *      Updates a terminal from the legacy BSD style terminal information
     517             :  *      structure.
     518             :  *
     519             :  *      Locking: termios_rwsem
     520             :  */
     521             : 
     522             : static int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
     523             : {
     524             :         int retval;
     525             :         struct sgttyb tmp;
     526             :         struct ktermios termios;
     527             : 
     528             :         retval = tty_check_change(tty);
     529             :         if (retval)
     530             :                 return retval;
     531             : 
     532             :         if (copy_from_user(&tmp, sgttyb, sizeof(tmp)))
     533             :                 return -EFAULT;
     534             : 
     535             :         down_write(&tty->termios_rwsem);
     536             :         termios = tty->termios;
     537             :         termios.c_cc[VERASE] = tmp.sg_erase;
     538             :         termios.c_cc[VKILL] = tmp.sg_kill;
     539             :         set_sgflags(&termios, tmp.sg_flags);
     540             :         /* Try and encode into Bfoo format */
     541             : #ifdef BOTHER
     542             :         tty_termios_encode_baud_rate(&termios, termios.c_ispeed,
     543             :                                                 termios.c_ospeed);
     544             : #endif
     545             :         up_write(&tty->termios_rwsem);
     546             :         tty_set_termios(tty, &termios);
     547             :         return 0;
     548             : }
     549             : #endif
     550             : 
     551             : #ifdef TIOCGETC
     552             : static int get_tchars(struct tty_struct *tty, struct tchars __user *tchars)
     553             : {
     554             :         struct tchars tmp;
     555             : 
     556             :         down_read(&tty->termios_rwsem);
     557             :         tmp.t_intrc = tty->termios.c_cc[VINTR];
     558             :         tmp.t_quitc = tty->termios.c_cc[VQUIT];
     559             :         tmp.t_startc = tty->termios.c_cc[VSTART];
     560             :         tmp.t_stopc = tty->termios.c_cc[VSTOP];
     561             :         tmp.t_eofc = tty->termios.c_cc[VEOF];
     562             :         tmp.t_brkc = tty->termios.c_cc[VEOL2];       /* what is brkc anyway? */
     563             :         up_read(&tty->termios_rwsem);
     564             :         return copy_to_user(tchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
     565             : }
     566             : 
     567             : static int set_tchars(struct tty_struct *tty, struct tchars __user *tchars)
     568             : {
     569             :         struct tchars tmp;
     570             : 
     571             :         if (copy_from_user(&tmp, tchars, sizeof(tmp)))
     572             :                 return -EFAULT;
     573             :         down_write(&tty->termios_rwsem);
     574             :         tty->termios.c_cc[VINTR] = tmp.t_intrc;
     575             :         tty->termios.c_cc[VQUIT] = tmp.t_quitc;
     576             :         tty->termios.c_cc[VSTART] = tmp.t_startc;
     577             :         tty->termios.c_cc[VSTOP] = tmp.t_stopc;
     578             :         tty->termios.c_cc[VEOF] = tmp.t_eofc;
     579             :         tty->termios.c_cc[VEOL2] = tmp.t_brkc;       /* what is brkc anyway? */
     580             :         up_write(&tty->termios_rwsem);
     581             :         return 0;
     582             : }
     583             : #endif
     584             : 
     585             : #ifdef TIOCGLTC
     586             : static int get_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
     587             : {
     588             :         struct ltchars tmp;
     589             : 
     590             :         down_read(&tty->termios_rwsem);
     591             :         tmp.t_suspc = tty->termios.c_cc[VSUSP];
     592             :         /* what is dsuspc anyway? */
     593             :         tmp.t_dsuspc = tty->termios.c_cc[VSUSP];
     594             :         tmp.t_rprntc = tty->termios.c_cc[VREPRINT];
     595             :         /* what is flushc anyway? */
     596             :         tmp.t_flushc = tty->termios.c_cc[VEOL2];
     597             :         tmp.t_werasc = tty->termios.c_cc[VWERASE];
     598             :         tmp.t_lnextc = tty->termios.c_cc[VLNEXT];
     599             :         up_read(&tty->termios_rwsem);
     600             :         return copy_to_user(ltchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
     601             : }
     602             : 
     603             : static int set_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
     604             : {
     605             :         struct ltchars tmp;
     606             : 
     607             :         if (copy_from_user(&tmp, ltchars, sizeof(tmp)))
     608             :                 return -EFAULT;
     609             : 
     610             :         down_write(&tty->termios_rwsem);
     611             :         tty->termios.c_cc[VSUSP] = tmp.t_suspc;
     612             :         /* what is dsuspc anyway? */
     613             :         tty->termios.c_cc[VEOL2] = tmp.t_dsuspc;
     614             :         tty->termios.c_cc[VREPRINT] = tmp.t_rprntc;
     615             :         /* what is flushc anyway? */
     616             :         tty->termios.c_cc[VEOL2] = tmp.t_flushc;
     617             :         tty->termios.c_cc[VWERASE] = tmp.t_werasc;
     618             :         tty->termios.c_cc[VLNEXT] = tmp.t_lnextc;
     619             :         up_write(&tty->termios_rwsem);
     620             :         return 0;
     621             : }
     622             : #endif
     623             : 
     624             : /**
     625             :  *      tty_change_softcar      -       carrier change ioctl helper
     626             :  *      @tty: tty to update
     627             :  *      @arg: enable/disable CLOCAL
     628             :  *
     629             :  *      Perform a change to the CLOCAL state and call into the driver
     630             :  *      layer to make it visible. All done with the termios rwsem
     631             :  */
     632             : 
     633           0 : static int tty_change_softcar(struct tty_struct *tty, int arg)
     634             : {
     635           0 :         int ret = 0;
     636           0 :         int bit = arg ? CLOCAL : 0;
     637           0 :         struct ktermios old;
     638             : 
     639           0 :         down_write(&tty->termios_rwsem);
     640           0 :         old = tty->termios;
     641           0 :         tty->termios.c_cflag &= ~CLOCAL;
     642           0 :         tty->termios.c_cflag |= bit;
     643           0 :         if (tty->ops->set_termios)
     644           0 :                 tty->ops->set_termios(tty, &old);
     645           0 :         if (C_CLOCAL(tty) != bit)
     646           0 :                 ret = -EINVAL;
     647           0 :         up_write(&tty->termios_rwsem);
     648           0 :         return ret;
     649             : }
     650             : 
     651             : /**
     652             :  *      tty_mode_ioctl          -       mode related ioctls
     653             :  *      @tty: tty for the ioctl
     654             :  *      @file: file pointer for the tty
     655             :  *      @cmd: command
     656             :  *      @arg: ioctl argument
     657             :  *
     658             :  *      Perform non line discipline specific mode control ioctls. This
     659             :  *      is designed to be called by line disciplines to ensure they provide
     660             :  *      consistent mode setting.
     661             :  */
     662             : 
     663         170 : int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
     664             :                         unsigned int cmd, unsigned long arg)
     665             : {
     666         170 :         struct tty_struct *real_tty;
     667         170 :         void __user *p = (void __user *)arg;
     668         170 :         int ret = 0;
     669         170 :         struct ktermios kterm;
     670             : 
     671         170 :         BUG_ON(file == NULL);
     672             : 
     673         170 :         if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
     674             :             tty->driver->subtype == PTY_TYPE_MASTER)
     675           0 :                 real_tty = tty->link;
     676             :         else
     677             :                 real_tty = tty;
     678             : 
     679         170 :         switch (cmd) {
     680             : #ifdef TIOCGETP
     681             :         case TIOCGETP:
     682             :                 return get_sgttyb(real_tty, (struct sgttyb __user *) arg);
     683             :         case TIOCSETP:
     684             :         case TIOCSETN:
     685             :                 return set_sgttyb(real_tty, (struct sgttyb __user *) arg);
     686             : #endif
     687             : #ifdef TIOCGETC
     688             :         case TIOCGETC:
     689             :                 return get_tchars(real_tty, p);
     690             :         case TIOCSETC:
     691             :                 return set_tchars(real_tty, p);
     692             : #endif
     693             : #ifdef TIOCGLTC
     694             :         case TIOCGLTC:
     695             :                 return get_ltchars(real_tty, p);
     696             :         case TIOCSLTC:
     697             :                 return set_ltchars(real_tty, p);
     698             : #endif
     699           0 :         case TCSETSF:
     700           0 :                 return set_termios(real_tty, p,  TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_OLD);
     701           1 :         case TCSETSW:
     702           1 :                 return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_OLD);
     703           2 :         case TCSETS:
     704           2 :                 return set_termios(real_tty, p, TERMIOS_OLD);
     705             : #ifndef TCGETS2
     706             :         case TCGETS:
     707             :                 copy_termios(real_tty, &kterm);
     708             :                 if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm))
     709             :                         ret = -EFAULT;
     710             :                 return ret;
     711             : #else
     712         163 :         case TCGETS:
     713         163 :                 copy_termios(real_tty, &kterm);
     714         163 :                 if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm))
     715           0 :                         ret = -EFAULT;
     716             :                 return ret;
     717           0 :         case TCGETS2:
     718           0 :                 copy_termios(real_tty, &kterm);
     719           0 :                 if (kernel_termios_to_user_termios((struct termios2 __user *)arg, &kterm))
     720           0 :                         ret = -EFAULT;
     721             :                 return ret;
     722           0 :         case TCSETSF2:
     723           0 :                 return set_termios(real_tty, p,  TERMIOS_FLUSH | TERMIOS_WAIT);
     724           0 :         case TCSETSW2:
     725           0 :                 return set_termios(real_tty, p, TERMIOS_WAIT);
     726           0 :         case TCSETS2:
     727           0 :                 return set_termios(real_tty, p, 0);
     728             : #endif
     729           0 :         case TCGETA:
     730           0 :                 return get_termio(real_tty, p);
     731           0 :         case TCSETAF:
     732           0 :                 return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_TERMIO);
     733           0 :         case TCSETAW:
     734           0 :                 return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_TERMIO);
     735           0 :         case TCSETA:
     736           0 :                 return set_termios(real_tty, p, TERMIOS_TERMIO);
     737             : #ifndef TCGETS2
     738             :         case TIOCGLCKTRMIOS:
     739             :                 copy_termios_locked(real_tty, &kterm);
     740             :                 if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm))
     741             :                         ret = -EFAULT;
     742             :                 return ret;
     743             :         case TIOCSLCKTRMIOS:
     744             :                 if (!capable(CAP_SYS_ADMIN))
     745             :                         return -EPERM;
     746             :                 copy_termios_locked(real_tty, &kterm);
     747             :                 if (user_termios_to_kernel_termios(&kterm,
     748             :                                                (struct termios __user *) arg))
     749             :                         return -EFAULT;
     750             :                 down_write(&real_tty->termios_rwsem);
     751             :                 real_tty->termios_locked = kterm;
     752             :                 up_write(&real_tty->termios_rwsem);
     753             :                 return 0;
     754             : #else
     755           1 :         case TIOCGLCKTRMIOS:
     756           1 :                 copy_termios_locked(real_tty, &kterm);
     757           1 :                 if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm))
     758           0 :                         ret = -EFAULT;
     759             :                 return ret;
     760           1 :         case TIOCSLCKTRMIOS:
     761           1 :                 if (!capable(CAP_SYS_ADMIN))
     762             :                         return -EPERM;
     763           1 :                 copy_termios_locked(real_tty, &kterm);
     764           1 :                 if (user_termios_to_kernel_termios_1(&kterm,
     765             :                                                (struct termios __user *) arg))
     766             :                         return -EFAULT;
     767           1 :                 down_write(&real_tty->termios_rwsem);
     768           1 :                 real_tty->termios_locked = kterm;
     769           1 :                 up_write(&real_tty->termios_rwsem);
     770           1 :                 return ret;
     771             : #endif
     772             : #ifdef TCGETX
     773             :         case TCGETX:
     774             :         case TCSETX:
     775             :         case TCSETXW:
     776             :         case TCSETXF:
     777             :                 return -EINVAL;
     778             : #endif          
     779           0 :         case TIOCGSOFTCAR:
     780           0 :                 copy_termios(real_tty, &kterm);
     781           0 :                 ret = put_user((kterm.c_cflag & CLOCAL) ? 1 : 0,
     782             :                                                 (int __user *)arg);
     783           0 :                 return ret;
     784           0 :         case TIOCSSOFTCAR:
     785           0 :                 if (get_user(arg, (unsigned int __user *) arg))
     786             :                         return -EFAULT;
     787           0 :                 return tty_change_softcar(real_tty, arg);
     788           2 :         default:
     789           2 :                 return -ENOIOCTLCMD;
     790             :         }
     791             : }
     792             : EXPORT_SYMBOL_GPL(tty_mode_ioctl);
     793             : 
     794             : 
     795             : /* Caller guarantees ldisc reference is held */
     796           3 : static int __tty_perform_flush(struct tty_struct *tty, unsigned long arg)
     797             : {
     798           3 :         struct tty_ldisc *ld = tty->ldisc;
     799             : 
     800           3 :         switch (arg) {
     801           1 :         case TCIFLUSH:
     802           1 :                 if (ld && ld->ops->flush_buffer) {
     803           1 :                         ld->ops->flush_buffer(tty);
     804           1 :                         tty_unthrottle(tty);
     805             :                 }
     806             :                 break;
     807           2 :         case TCIOFLUSH:
     808           2 :                 if (ld && ld->ops->flush_buffer) {
     809           2 :                         ld->ops->flush_buffer(tty);
     810           2 :                         tty_unthrottle(tty);
     811             :                 }
     812           2 :                 fallthrough;
     813             :         case TCOFLUSH:
     814           2 :                 tty_driver_flush_buffer(tty);
     815             :                 break;
     816             :         default:
     817             :                 return -EINVAL;
     818             :         }
     819             :         return 0;
     820             : }
     821             : 
     822           0 : int tty_perform_flush(struct tty_struct *tty, unsigned long arg)
     823             : {
     824           0 :         struct tty_ldisc *ld;
     825           0 :         int retval = tty_check_change(tty);
     826           0 :         if (retval)
     827             :                 return retval;
     828             : 
     829           0 :         ld = tty_ldisc_ref_wait(tty);
     830           0 :         retval = __tty_perform_flush(tty, arg);
     831           0 :         if (ld)
     832           0 :                 tty_ldisc_deref(ld);
     833             :         return retval;
     834             : }
     835             : EXPORT_SYMBOL_GPL(tty_perform_flush);
     836             : 
     837         173 : int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
     838             :                        unsigned int cmd, unsigned long arg)
     839             : {
     840         173 :         int retval;
     841             : 
     842         173 :         switch (cmd) {
     843           0 :         case TCXONC:
     844           0 :                 retval = tty_check_change(tty);
     845           0 :                 if (retval)
     846             :                         return retval;
     847           0 :                 switch (arg) {
     848           0 :                 case TCOOFF:
     849           0 :                         spin_lock_irq(&tty->flow_lock);
     850           0 :                         if (!tty->flow_stopped) {
     851           0 :                                 tty->flow_stopped = 1;
     852           0 :                                 __stop_tty(tty);
     853             :                         }
     854           0 :                         spin_unlock_irq(&tty->flow_lock);
     855             :                         break;
     856           0 :                 case TCOON:
     857           0 :                         spin_lock_irq(&tty->flow_lock);
     858           0 :                         if (tty->flow_stopped) {
     859           0 :                                 tty->flow_stopped = 0;
     860           0 :                                 __start_tty(tty);
     861             :                         }
     862           0 :                         spin_unlock_irq(&tty->flow_lock);
     863             :                         break;
     864           0 :                 case TCIOFF:
     865           0 :                         if (STOP_CHAR(tty) != __DISABLED_CHAR)
     866           0 :                                 retval = tty_send_xchar(tty, STOP_CHAR(tty));
     867             :                         break;
     868           0 :                 case TCION:
     869           0 :                         if (START_CHAR(tty) != __DISABLED_CHAR)
     870           0 :                                 retval = tty_send_xchar(tty, START_CHAR(tty));
     871             :                         break;
     872             :                 default:
     873             :                         return -EINVAL;
     874             :                 }
     875             :                 return retval;
     876           3 :         case TCFLSH:
     877           3 :                 retval = tty_check_change(tty);
     878           3 :                 if (retval)
     879             :                         return retval;
     880           3 :                 return __tty_perform_flush(tty, arg);
     881         170 :         default:
     882             :                 /* Try the mode commands */
     883         170 :                 return tty_mode_ioctl(tty, file, cmd, arg);
     884             :         }
     885             : }
     886             : EXPORT_SYMBOL(n_tty_ioctl_helper);

Generated by: LCOV version 1.14