diff options
Diffstat (limited to 'drivers/net/slip.c')
-rw-r--r-- | drivers/net/slip.c | 96 |
1 files changed, 23 insertions, 73 deletions
diff --git a/drivers/net/slip.c b/drivers/net/slip.c index 26f6ee93a064..e17c535a577e 100644 --- a/drivers/net/slip.c +++ b/drivers/net/slip.c | |||
@@ -616,6 +616,14 @@ static void sl_uninit(struct net_device *dev) | |||
616 | sl_free_bufs(sl); | 616 | sl_free_bufs(sl); |
617 | } | 617 | } |
618 | 618 | ||
619 | /* Hook the destructor so we can free slip devices at the right point in time */ | ||
620 | static void sl_free_netdev(struct net_device *dev) | ||
621 | { | ||
622 | int i = dev->base_addr; | ||
623 | free_netdev(dev); | ||
624 | slip_devs[i] = NULL; | ||
625 | } | ||
626 | |||
619 | static const struct net_device_ops sl_netdev_ops = { | 627 | static const struct net_device_ops sl_netdev_ops = { |
620 | .ndo_init = sl_init, | 628 | .ndo_init = sl_init, |
621 | .ndo_uninit = sl_uninit, | 629 | .ndo_uninit = sl_uninit, |
@@ -634,7 +642,7 @@ static const struct net_device_ops sl_netdev_ops = { | |||
634 | static void sl_setup(struct net_device *dev) | 642 | static void sl_setup(struct net_device *dev) |
635 | { | 643 | { |
636 | dev->netdev_ops = &sl_netdev_ops; | 644 | dev->netdev_ops = &sl_netdev_ops; |
637 | dev->destructor = free_netdev; | 645 | dev->destructor = sl_free_netdev; |
638 | 646 | ||
639 | dev->hard_header_len = 0; | 647 | dev->hard_header_len = 0; |
640 | dev->addr_len = 0; | 648 | dev->addr_len = 0; |
@@ -712,8 +720,6 @@ static void sl_sync(void) | |||
712 | static struct slip *sl_alloc(dev_t line) | 720 | static struct slip *sl_alloc(dev_t line) |
713 | { | 721 | { |
714 | int i; | 722 | int i; |
715 | int sel = -1; | ||
716 | int score = -1; | ||
717 | struct net_device *dev = NULL; | 723 | struct net_device *dev = NULL; |
718 | struct slip *sl; | 724 | struct slip *sl; |
719 | 725 | ||
@@ -724,55 +730,7 @@ static struct slip *sl_alloc(dev_t line) | |||
724 | dev = slip_devs[i]; | 730 | dev = slip_devs[i]; |
725 | if (dev == NULL) | 731 | if (dev == NULL) |
726 | break; | 732 | break; |
727 | |||
728 | sl = netdev_priv(dev); | ||
729 | if (sl->leased) { | ||
730 | if (sl->line != line) | ||
731 | continue; | ||
732 | if (sl->tty) | ||
733 | return NULL; | ||
734 | |||
735 | /* Clear ESCAPE & ERROR flags */ | ||
736 | sl->flags &= (1 << SLF_INUSE); | ||
737 | return sl; | ||
738 | } | ||
739 | |||
740 | if (sl->tty) | ||
741 | continue; | ||
742 | |||
743 | if (current->pid == sl->pid) { | ||
744 | if (sl->line == line && score < 3) { | ||
745 | sel = i; | ||
746 | score = 3; | ||
747 | continue; | ||
748 | } | ||
749 | if (score < 2) { | ||
750 | sel = i; | ||
751 | score = 2; | ||
752 | } | ||
753 | continue; | ||
754 | } | ||
755 | if (sl->line == line && score < 1) { | ||
756 | sel = i; | ||
757 | score = 1; | ||
758 | continue; | ||
759 | } | ||
760 | if (score < 0) { | ||
761 | sel = i; | ||
762 | score = 0; | ||
763 | } | ||
764 | } | ||
765 | |||
766 | if (sel >= 0) { | ||
767 | i = sel; | ||
768 | dev = slip_devs[i]; | ||
769 | if (score > 1) { | ||
770 | sl = netdev_priv(dev); | ||
771 | sl->flags &= (1 << SLF_INUSE); | ||
772 | return sl; | ||
773 | } | ||
774 | } | 733 | } |
775 | |||
776 | /* Sorry, too many, all slots in use */ | 734 | /* Sorry, too many, all slots in use */ |
777 | if (i >= slip_maxdev) | 735 | if (i >= slip_maxdev) |
778 | return NULL; | 736 | return NULL; |
@@ -909,30 +867,13 @@ err_exit: | |||
909 | } | 867 | } |
910 | 868 | ||
911 | /* | 869 | /* |
912 | |||
913 | FIXME: 1,2 are fixed 3 was never true anyway. | ||
914 | |||
915 | Let me to blame a bit. | ||
916 | 1. TTY module calls this funstion on soft interrupt. | ||
917 | 2. TTY module calls this function WITH MASKED INTERRUPTS! | ||
918 | 3. TTY module does not notify us about line discipline | ||
919 | shutdown, | ||
920 | |||
921 | Seems, now it is clean. The solution is to consider netdevice and | ||
922 | line discipline sides as two independent threads. | ||
923 | |||
924 | By-product (not desired): sl? does not feel hangups and remains open. | ||
925 | It is supposed, that user level program (dip, diald, slattach...) | ||
926 | will catch SIGHUP and make the rest of work. | ||
927 | |||
928 | I see no way to make more with current tty code. --ANK | ||
929 | */ | ||
930 | |||
931 | /* | ||
932 | * Close down a SLIP channel. | 870 | * Close down a SLIP channel. |
933 | * This means flushing out any pending queues, and then returning. This | 871 | * This means flushing out any pending queues, and then returning. This |
934 | * call is serialized against other ldisc functions. | 872 | * call is serialized against other ldisc functions. |
873 | * | ||
874 | * We also use this method fo a hangup event | ||
935 | */ | 875 | */ |
876 | |||
936 | static void slip_close(struct tty_struct *tty) | 877 | static void slip_close(struct tty_struct *tty) |
937 | { | 878 | { |
938 | struct slip *sl = tty->disc_data; | 879 | struct slip *sl = tty->disc_data; |
@@ -951,10 +892,16 @@ static void slip_close(struct tty_struct *tty) | |||
951 | del_timer_sync(&sl->keepalive_timer); | 892 | del_timer_sync(&sl->keepalive_timer); |
952 | del_timer_sync(&sl->outfill_timer); | 893 | del_timer_sync(&sl->outfill_timer); |
953 | #endif | 894 | #endif |
954 | 895 | /* Flush network side */ | |
955 | /* Count references from TTY module */ | 896 | unregister_netdev(sl->dev); |
897 | /* This will complete via sl_free_netdev */ | ||
956 | } | 898 | } |
957 | 899 | ||
900 | static int slip_hangup(struct tty_struct *tty) | ||
901 | { | ||
902 | slip_close(tty); | ||
903 | return 0; | ||
904 | } | ||
958 | /************************************************************************ | 905 | /************************************************************************ |
959 | * STANDARD SLIP ENCAPSULATION * | 906 | * STANDARD SLIP ENCAPSULATION * |
960 | ************************************************************************/ | 907 | ************************************************************************/ |
@@ -1311,6 +1258,7 @@ static struct tty_ldisc_ops sl_ldisc = { | |||
1311 | .name = "slip", | 1258 | .name = "slip", |
1312 | .open = slip_open, | 1259 | .open = slip_open, |
1313 | .close = slip_close, | 1260 | .close = slip_close, |
1261 | .hangup = slip_hangup, | ||
1314 | .ioctl = slip_ioctl, | 1262 | .ioctl = slip_ioctl, |
1315 | .receive_buf = slip_receive_buf, | 1263 | .receive_buf = slip_receive_buf, |
1316 | .write_wakeup = slip_write_wakeup, | 1264 | .write_wakeup = slip_write_wakeup, |
@@ -1384,6 +1332,8 @@ static void __exit slip_exit(void) | |||
1384 | } | 1332 | } |
1385 | } while (busy && time_before(jiffies, timeout)); | 1333 | } while (busy && time_before(jiffies, timeout)); |
1386 | 1334 | ||
1335 | /* FIXME: hangup is async so we should wait when doing this second | ||
1336 | phase */ | ||
1387 | 1337 | ||
1388 | for (i = 0; i < slip_maxdev; i++) { | 1338 | for (i = 0; i < slip_maxdev; i++) { |
1389 | dev = slip_devs[i]; | 1339 | dev = slip_devs[i]; |