diff options
| author | Ralf Baechle <ralf@linux-mips.org> | 2007-03-12 18:53:33 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2007-03-12 18:53:33 -0400 |
| commit | 2536b94a2d2e37dd6c14171d6251f63bbda47293 (patch) | |
| tree | 963a1b750e0844bbd90b42b7e55c728b3abb3629 | |
| parent | 6cee77dbf29e3c4c2cf2ce16621759accc76891e (diff) | |
[ROSE]: Socket locking is a great invention.
Especially if you actually try to do it ;-)
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | net/rose/af_rose.c | 78 |
1 files changed, 50 insertions, 28 deletions
diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c index 596b302d0e47..f92d5310847b 100644 --- a/net/rose/af_rose.c +++ b/net/rose/af_rose.c | |||
| @@ -700,23 +700,7 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le | |||
| 700 | unsigned char cause, diagnostic; | 700 | unsigned char cause, diagnostic; |
| 701 | struct net_device *dev; | 701 | struct net_device *dev; |
| 702 | ax25_uid_assoc *user; | 702 | ax25_uid_assoc *user; |
| 703 | int n; | 703 | int n, err = 0; |
| 704 | |||
| 705 | if (sk->sk_state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) { | ||
| 706 | sock->state = SS_CONNECTED; | ||
| 707 | return 0; /* Connect completed during a ERESTARTSYS event */ | ||
| 708 | } | ||
| 709 | |||
| 710 | if (sk->sk_state == TCP_CLOSE && sock->state == SS_CONNECTING) { | ||
| 711 | sock->state = SS_UNCONNECTED; | ||
| 712 | return -ECONNREFUSED; | ||
| 713 | } | ||
| 714 | |||
| 715 | if (sk->sk_state == TCP_ESTABLISHED) | ||
| 716 | return -EISCONN; /* No reconnect on a seqpacket socket */ | ||
| 717 | |||
| 718 | sk->sk_state = TCP_CLOSE; | ||
| 719 | sock->state = SS_UNCONNECTED; | ||
| 720 | 704 | ||
| 721 | if (addr_len != sizeof(struct sockaddr_rose) && addr_len != sizeof(struct full_sockaddr_rose)) | 705 | if (addr_len != sizeof(struct sockaddr_rose) && addr_len != sizeof(struct full_sockaddr_rose)) |
| 722 | return -EINVAL; | 706 | return -EINVAL; |
| @@ -734,24 +718,53 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le | |||
| 734 | if ((rose->source_ndigis + addr->srose_ndigis) > ROSE_MAX_DIGIS) | 718 | if ((rose->source_ndigis + addr->srose_ndigis) > ROSE_MAX_DIGIS) |
| 735 | return -EINVAL; | 719 | return -EINVAL; |
| 736 | 720 | ||
| 721 | lock_sock(sk); | ||
| 722 | |||
| 723 | if (sk->sk_state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) { | ||
| 724 | /* Connect completed during a ERESTARTSYS event */ | ||
| 725 | sock->state = SS_CONNECTED; | ||
| 726 | goto out_release; | ||
| 727 | } | ||
| 728 | |||
| 729 | if (sk->sk_state == TCP_CLOSE && sock->state == SS_CONNECTING) { | ||
| 730 | sock->state = SS_UNCONNECTED; | ||
| 731 | err = -ECONNREFUSED; | ||
| 732 | goto out_release; | ||
| 733 | } | ||
| 734 | |||
| 735 | if (sk->sk_state == TCP_ESTABLISHED) { | ||
| 736 | /* No reconnect on a seqpacket socket */ | ||
| 737 | err = -EISCONN; | ||
| 738 | goto out_release; | ||
| 739 | } | ||
| 740 | |||
| 741 | sk->sk_state = TCP_CLOSE; | ||
| 742 | sock->state = SS_UNCONNECTED; | ||
| 743 | |||
| 737 | rose->neighbour = rose_get_neigh(&addr->srose_addr, &cause, | 744 | rose->neighbour = rose_get_neigh(&addr->srose_addr, &cause, |
| 738 | &diagnostic); | 745 | &diagnostic); |
| 739 | if (!rose->neighbour) | 746 | if (!rose->neighbour) |
| 740 | return -ENETUNREACH; | 747 | return -ENETUNREACH; |
| 741 | 748 | ||
| 742 | rose->lci = rose_new_lci(rose->neighbour); | 749 | rose->lci = rose_new_lci(rose->neighbour); |
| 743 | if (!rose->lci) | 750 | if (!rose->lci) { |
| 744 | return -ENETUNREACH; | 751 | err = -ENETUNREACH; |
| 752 | goto out_release; | ||
| 753 | } | ||
| 745 | 754 | ||
| 746 | if (sock_flag(sk, SOCK_ZAPPED)) { /* Must bind first - autobinding in this may or may not work */ | 755 | if (sock_flag(sk, SOCK_ZAPPED)) { /* Must bind first - autobinding in this may or may not work */ |
| 747 | sock_reset_flag(sk, SOCK_ZAPPED); | 756 | sock_reset_flag(sk, SOCK_ZAPPED); |
| 748 | 757 | ||
| 749 | if ((dev = rose_dev_first()) == NULL) | 758 | if ((dev = rose_dev_first()) == NULL) { |
| 750 | return -ENETUNREACH; | 759 | err = -ENETUNREACH; |
| 760 | goto out_release; | ||
| 761 | } | ||
| 751 | 762 | ||
| 752 | user = ax25_findbyuid(current->euid); | 763 | user = ax25_findbyuid(current->euid); |
| 753 | if (!user) | 764 | if (!user) { |
| 754 | return -EINVAL; | 765 | err = -EINVAL; |
| 766 | goto out_release; | ||
| 767 | } | ||
| 755 | 768 | ||
| 756 | memcpy(&rose->source_addr, dev->dev_addr, ROSE_ADDR_LEN); | 769 | memcpy(&rose->source_addr, dev->dev_addr, ROSE_ADDR_LEN); |
| 757 | rose->source_call = user->call; | 770 | rose->source_call = user->call; |
| @@ -789,8 +802,10 @@ rose_try_next_neigh: | |||
| 789 | rose_start_t1timer(sk); | 802 | rose_start_t1timer(sk); |
| 790 | 803 | ||
| 791 | /* Now the loop */ | 804 | /* Now the loop */ |
| 792 | if (sk->sk_state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) | 805 | if (sk->sk_state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) { |
| 793 | return -EINPROGRESS; | 806 | err = -EINPROGRESS; |
| 807 | goto out_release; | ||
| 808 | } | ||
| 794 | 809 | ||
| 795 | /* | 810 | /* |
| 796 | * A Connect Ack with Choke or timeout or failed routing will go to | 811 | * A Connect Ack with Choke or timeout or failed routing will go to |
| @@ -805,8 +820,10 @@ rose_try_next_neigh: | |||
| 805 | set_current_state(TASK_INTERRUPTIBLE); | 820 | set_current_state(TASK_INTERRUPTIBLE); |
| 806 | if (sk->sk_state != TCP_SYN_SENT) | 821 | if (sk->sk_state != TCP_SYN_SENT) |
| 807 | break; | 822 | break; |
| 823 | release_sock(sk); | ||
| 808 | if (!signal_pending(tsk)) { | 824 | if (!signal_pending(tsk)) { |
| 809 | schedule(); | 825 | schedule(); |
| 826 | lock_sock(sk); | ||
| 810 | continue; | 827 | continue; |
| 811 | } | 828 | } |
| 812 | current->state = TASK_RUNNING; | 829 | current->state = TASK_RUNNING; |
| @@ -822,14 +839,19 @@ rose_try_next_neigh: | |||
| 822 | rose->neighbour = rose_get_neigh(&addr->srose_addr, &cause, &diagnostic); | 839 | rose->neighbour = rose_get_neigh(&addr->srose_addr, &cause, &diagnostic); |
| 823 | if (rose->neighbour) | 840 | if (rose->neighbour) |
| 824 | goto rose_try_next_neigh; | 841 | goto rose_try_next_neigh; |
| 825 | /* No more neighbour */ | 842 | |
| 843 | /* No more neighbours */ | ||
| 826 | sock->state = SS_UNCONNECTED; | 844 | sock->state = SS_UNCONNECTED; |
| 827 | return sock_error(sk); /* Always set at this point */ | 845 | err = sock_error(sk); /* Always set at this point */ |
| 846 | goto out_release; | ||
| 828 | } | 847 | } |
| 829 | 848 | ||
| 830 | sock->state = SS_CONNECTED; | 849 | sock->state = SS_CONNECTED; |
| 831 | 850 | ||
| 832 | return 0; | 851 | out_release: |
| 852 | release_sock(sk); | ||
| 853 | |||
| 854 | return err; | ||
| 833 | } | 855 | } |
| 834 | 856 | ||
| 835 | static int rose_accept(struct socket *sock, struct socket *newsock, int flags) | 857 | static int rose_accept(struct socket *sock, struct socket *newsock, int flags) |
