diff options
author | Alan Cox <alan@redhat.com> | 2007-11-07 04:24:56 -0500 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-11-07 07:14:19 -0500 |
commit | 0fc00e2440b717e19bab1ae0015f03936bdf7967 (patch) | |
tree | 4ae26ce4c71511fad3bad97384dce22a69c16bb6 | |
parent | 543821c6f5dea5221426eaf1eac98b100249c7ac (diff) |
[TTY]: Fix network driver interactions with TCGET/SET calls.
Dave Miller noted various cases where line disciplines for things like
ppp go poking around in termios themselves in ways that broke with the
new termios code. Rather than have them all learning about termios
internals provide proper methods for this
- tty_mode_ioctl()
This handles all the terminal mode handling for speed/carrier
etc and none of the methods are ldisc dependant so they can be called
by any user
- tty_perform_flush()
This extracts the flush functionality and enables pppd the ppp
layer to share it cleanly.
The existing n_tty_ioctl code is refactored in this patch to provide
the new functions and to call them itself appropriately. This patch
has no (intended) behaviour changes and simply prepares for the other
fixes.
Signed-off-by: Alan Cox <alan@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/char/tty_ioctl.c | 170 | ||||
-rw-r--r-- | include/linux/tty.h | 4 |
2 files changed, 107 insertions, 67 deletions
diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c index 7a003504c265..1bdd2bf4f37d 100644 --- a/drivers/char/tty_ioctl.c +++ b/drivers/char/tty_ioctl.c | |||
@@ -730,13 +730,23 @@ static int send_prio_char(struct tty_struct *tty, char ch) | |||
730 | return 0; | 730 | return 0; |
731 | } | 731 | } |
732 | 732 | ||
733 | int n_tty_ioctl(struct tty_struct * tty, struct file * file, | 733 | /** |
734 | unsigned int cmd, unsigned long arg) | 734 | * tty_mode_ioctl - mode related ioctls |
735 | * @tty: tty for the ioctl | ||
736 | * @file: file pointer for the tty | ||
737 | * @cmd: command | ||
738 | * @arg: ioctl argument | ||
739 | * | ||
740 | * Perform non line discipline specific mode control ioctls. This | ||
741 | * is designed to be called by line disciplines to ensure they provide | ||
742 | * consistent mode setting. | ||
743 | */ | ||
744 | |||
745 | int tty_mode_ioctl(struct tty_struct * tty, struct file *file, | ||
746 | unsigned int cmd, unsigned long arg) | ||
735 | { | 747 | { |
736 | struct tty_struct * real_tty; | 748 | struct tty_struct * real_tty; |
737 | void __user *p = (void __user *)arg; | 749 | void __user *p = (void __user *)arg; |
738 | int retval; | ||
739 | struct tty_ldisc *ld; | ||
740 | 750 | ||
741 | if (tty->driver->type == TTY_DRIVER_TYPE_PTY && | 751 | if (tty->driver->type == TTY_DRIVER_TYPE_PTY && |
742 | tty->driver->subtype == PTY_TYPE_MASTER) | 752 | tty->driver->subtype == PTY_TYPE_MASTER) |
@@ -799,6 +809,93 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file, | |||
799 | return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_TERMIO); | 809 | return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_TERMIO); |
800 | case TCSETA: | 810 | case TCSETA: |
801 | return set_termios(real_tty, p, TERMIOS_TERMIO); | 811 | return set_termios(real_tty, p, TERMIOS_TERMIO); |
812 | #ifndef TCGETS2 | ||
813 | case TIOCGLCKTRMIOS: | ||
814 | if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios_locked)) | ||
815 | return -EFAULT; | ||
816 | return 0; | ||
817 | |||
818 | case TIOCSLCKTRMIOS: | ||
819 | if (!capable(CAP_SYS_ADMIN)) | ||
820 | return -EPERM; | ||
821 | if (user_termios_to_kernel_termios(real_tty->termios_locked, (struct termios __user *) arg)) | ||
822 | return -EFAULT; | ||
823 | return 0; | ||
824 | #else | ||
825 | case TIOCGLCKTRMIOS: | ||
826 | if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios_locked)) | ||
827 | return -EFAULT; | ||
828 | return 0; | ||
829 | |||
830 | case TIOCSLCKTRMIOS: | ||
831 | if (!capable(CAP_SYS_ADMIN)) | ||
832 | return -EPERM; | ||
833 | if (user_termios_to_kernel_termios_1(real_tty->termios_locked, (struct termios __user *) arg)) | ||
834 | return -EFAULT; | ||
835 | return 0; | ||
836 | #endif | ||
837 | case TIOCGSOFTCAR: | ||
838 | return put_user(C_CLOCAL(tty) ? 1 : 0, (int __user *)arg); | ||
839 | case TIOCSSOFTCAR: | ||
840 | if (get_user(arg, (unsigned int __user *) arg)) | ||
841 | return -EFAULT; | ||
842 | mutex_lock(&tty->termios_mutex); | ||
843 | tty->termios->c_cflag = | ||
844 | ((tty->termios->c_cflag & ~CLOCAL) | | ||
845 | (arg ? CLOCAL : 0)); | ||
846 | mutex_unlock(&tty->termios_mutex); | ||
847 | return 0; | ||
848 | default: | ||
849 | return -ENOIOCTLCMD; | ||
850 | } | ||
851 | } | ||
852 | |||
853 | EXPORT_SYMBOL_GPL(tty_mode_ioctl); | ||
854 | |||
855 | int tty_perform_flush(struct tty_struct *tty, unsigned long arg) | ||
856 | { | ||
857 | struct tty_ldisc *ld; | ||
858 | int retval = tty_check_change(tty); | ||
859 | if (retval) | ||
860 | return retval; | ||
861 | |||
862 | ld = tty_ldisc_ref(tty); | ||
863 | switch (arg) { | ||
864 | case TCIFLUSH: | ||
865 | if (ld && ld->flush_buffer) | ||
866 | ld->flush_buffer(tty); | ||
867 | break; | ||
868 | case TCIOFLUSH: | ||
869 | if (ld && ld->flush_buffer) | ||
870 | ld->flush_buffer(tty); | ||
871 | /* fall through */ | ||
872 | case TCOFLUSH: | ||
873 | if (tty->driver->flush_buffer) | ||
874 | tty->driver->flush_buffer(tty); | ||
875 | break; | ||
876 | default: | ||
877 | tty_ldisc_deref(ld); | ||
878 | return -EINVAL; | ||
879 | } | ||
880 | tty_ldisc_deref(ld); | ||
881 | return 0; | ||
882 | } | ||
883 | |||
884 | EXPORT_SYMBOL_GPL(tty_perform_flush); | ||
885 | |||
886 | int n_tty_ioctl(struct tty_struct * tty, struct file * file, | ||
887 | unsigned int cmd, unsigned long arg) | ||
888 | { | ||
889 | struct tty_struct * real_tty; | ||
890 | int retval; | ||
891 | |||
892 | if (tty->driver->type == TTY_DRIVER_TYPE_PTY && | ||
893 | tty->driver->subtype == PTY_TYPE_MASTER) | ||
894 | real_tty = tty->link; | ||
895 | else | ||
896 | real_tty = tty; | ||
897 | |||
898 | switch (cmd) { | ||
802 | case TCXONC: | 899 | case TCXONC: |
803 | retval = tty_check_change(tty); | 900 | retval = tty_check_change(tty); |
804 | if (retval) | 901 | if (retval) |
@@ -829,30 +926,7 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file, | |||
829 | } | 926 | } |
830 | return 0; | 927 | return 0; |
831 | case TCFLSH: | 928 | case TCFLSH: |
832 | retval = tty_check_change(tty); | 929 | return tty_perform_flush(tty, arg); |
833 | if (retval) | ||
834 | return retval; | ||
835 | |||
836 | ld = tty_ldisc_ref(tty); | ||
837 | switch (arg) { | ||
838 | case TCIFLUSH: | ||
839 | if (ld && ld->flush_buffer) | ||
840 | ld->flush_buffer(tty); | ||
841 | break; | ||
842 | case TCIOFLUSH: | ||
843 | if (ld && ld->flush_buffer) | ||
844 | ld->flush_buffer(tty); | ||
845 | /* fall through */ | ||
846 | case TCOFLUSH: | ||
847 | if (tty->driver->flush_buffer) | ||
848 | tty->driver->flush_buffer(tty); | ||
849 | break; | ||
850 | default: | ||
851 | tty_ldisc_deref(ld); | ||
852 | return -EINVAL; | ||
853 | } | ||
854 | tty_ldisc_deref(ld); | ||
855 | return 0; | ||
856 | case TIOCOUTQ: | 930 | case TIOCOUTQ: |
857 | return put_user(tty->driver->chars_in_buffer ? | 931 | return put_user(tty->driver->chars_in_buffer ? |
858 | tty->driver->chars_in_buffer(tty) : 0, | 932 | tty->driver->chars_in_buffer(tty) : 0, |
@@ -862,32 +936,6 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file, | |||
862 | if (L_ICANON(tty)) | 936 | if (L_ICANON(tty)) |
863 | retval = inq_canon(tty); | 937 | retval = inq_canon(tty); |
864 | return put_user(retval, (unsigned int __user *) arg); | 938 | return put_user(retval, (unsigned int __user *) arg); |
865 | #ifndef TCGETS2 | ||
866 | case TIOCGLCKTRMIOS: | ||
867 | if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios_locked)) | ||
868 | return -EFAULT; | ||
869 | return 0; | ||
870 | |||
871 | case TIOCSLCKTRMIOS: | ||
872 | if (!capable(CAP_SYS_ADMIN)) | ||
873 | return -EPERM; | ||
874 | if (user_termios_to_kernel_termios(real_tty->termios_locked, (struct termios __user *) arg)) | ||
875 | return -EFAULT; | ||
876 | return 0; | ||
877 | #else | ||
878 | case TIOCGLCKTRMIOS: | ||
879 | if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios_locked)) | ||
880 | return -EFAULT; | ||
881 | return 0; | ||
882 | |||
883 | case TIOCSLCKTRMIOS: | ||
884 | if (!capable(CAP_SYS_ADMIN)) | ||
885 | return -EPERM; | ||
886 | if (user_termios_to_kernel_termios_1(real_tty->termios_locked, (struct termios __user *) arg)) | ||
887 | return -EFAULT; | ||
888 | return 0; | ||
889 | #endif | ||
890 | |||
891 | case TIOCPKT: | 939 | case TIOCPKT: |
892 | { | 940 | { |
893 | int pktmode; | 941 | int pktmode; |
@@ -906,19 +954,9 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file, | |||
906 | tty->packet = 0; | 954 | tty->packet = 0; |
907 | return 0; | 955 | return 0; |
908 | } | 956 | } |
909 | case TIOCGSOFTCAR: | ||
910 | return put_user(C_CLOCAL(tty) ? 1 : 0, (int __user *)arg); | ||
911 | case TIOCSSOFTCAR: | ||
912 | if (get_user(arg, (unsigned int __user *) arg)) | ||
913 | return -EFAULT; | ||
914 | mutex_lock(&tty->termios_mutex); | ||
915 | tty->termios->c_cflag = | ||
916 | ((tty->termios->c_cflag & ~CLOCAL) | | ||
917 | (arg ? CLOCAL : 0)); | ||
918 | mutex_unlock(&tty->termios_mutex); | ||
919 | return 0; | ||
920 | default: | 957 | default: |
921 | return -ENOIOCTLCMD; | 958 | /* Try the mode commands */ |
959 | return tty_mode_ioctl(tty, file, cmd, arg); | ||
922 | } | 960 | } |
923 | } | 961 | } |
924 | 962 | ||
diff --git a/include/linux/tty.h b/include/linux/tty.h index 56164d7ba0ad..c555f5442bd7 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h | |||
@@ -332,7 +332,9 @@ extern void tty_ldisc_flush(struct tty_struct *tty); | |||
332 | 332 | ||
333 | extern int tty_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | 333 | extern int tty_ioctl(struct inode *inode, struct file *file, unsigned int cmd, |
334 | unsigned long arg); | 334 | unsigned long arg); |
335 | 335 | extern int tty_mode_ioctl(struct tty_struct *tty, struct file *file, | |
336 | unsigned int cmd, unsigned long arg); | ||
337 | extern int tty_perform_flush(struct tty_struct *tty, unsigned long arg); | ||
336 | extern dev_t tty_devnum(struct tty_struct *tty); | 338 | extern dev_t tty_devnum(struct tty_struct *tty); |
337 | extern void proc_clear_tty(struct task_struct *p); | 339 | extern void proc_clear_tty(struct task_struct *p); |
338 | extern struct tty_struct *get_current_tty(void); | 340 | extern struct tty_struct *get_current_tty(void); |