diff options
Diffstat (limited to 'net/bluetooth/l2cap_sock.c')
-rw-r--r-- | net/bluetooth/l2cap_sock.c | 61 |
1 files changed, 61 insertions, 0 deletions
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index db787f67c52a..3f5946351fb9 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c | |||
@@ -872,6 +872,25 @@ static int l2cap_sock_release(struct socket *sock) | |||
872 | return err; | 872 | return err; |
873 | } | 873 | } |
874 | 874 | ||
875 | static void l2cap_sock_cleanup_listen(struct sock *parent) | ||
876 | { | ||
877 | struct sock *sk; | ||
878 | |||
879 | BT_DBG("parent %p", parent); | ||
880 | |||
881 | /* Close not yet accepted channels */ | ||
882 | while ((sk = bt_accept_dequeue(parent, NULL))) { | ||
883 | struct l2cap_chan *chan = l2cap_pi(sk)->chan; | ||
884 | |||
885 | l2cap_chan_lock(chan); | ||
886 | __clear_chan_timer(chan); | ||
887 | l2cap_chan_close(chan, ECONNRESET); | ||
888 | l2cap_chan_unlock(chan); | ||
889 | |||
890 | l2cap_sock_kill(sk); | ||
891 | } | ||
892 | } | ||
893 | |||
875 | static struct l2cap_chan *l2cap_sock_new_connection_cb(struct l2cap_chan *chan) | 894 | static struct l2cap_chan *l2cap_sock_new_connection_cb(struct l2cap_chan *chan) |
876 | { | 895 | { |
877 | struct sock *sk, *parent = chan->data; | 896 | struct sock *sk, *parent = chan->data; |
@@ -931,6 +950,47 @@ static void l2cap_sock_close_cb(struct l2cap_chan *chan) | |||
931 | l2cap_sock_kill(sk); | 950 | l2cap_sock_kill(sk); |
932 | } | 951 | } |
933 | 952 | ||
953 | static void l2cap_sock_teardown_cb(struct l2cap_chan *chan, int err) | ||
954 | { | ||
955 | struct sock *sk = chan->data; | ||
956 | struct sock *parent; | ||
957 | |||
958 | lock_sock(sk); | ||
959 | |||
960 | parent = bt_sk(sk)->parent; | ||
961 | |||
962 | sock_set_flag(sk, SOCK_ZAPPED); | ||
963 | |||
964 | switch (chan->state) { | ||
965 | case BT_OPEN: | ||
966 | case BT_BOUND: | ||
967 | case BT_CLOSED: | ||
968 | break; | ||
969 | case BT_LISTEN: | ||
970 | l2cap_sock_cleanup_listen(sk); | ||
971 | sk->sk_state = BT_CLOSED; | ||
972 | chan->state = BT_CLOSED; | ||
973 | |||
974 | break; | ||
975 | default: | ||
976 | sk->sk_state = BT_CLOSED; | ||
977 | chan->state = BT_CLOSED; | ||
978 | |||
979 | sk->sk_err = err; | ||
980 | |||
981 | if (parent) { | ||
982 | bt_accept_unlink(sk); | ||
983 | parent->sk_data_ready(parent, 0); | ||
984 | } else { | ||
985 | sk->sk_state_change(sk); | ||
986 | } | ||
987 | |||
988 | break; | ||
989 | } | ||
990 | |||
991 | release_sock(sk); | ||
992 | } | ||
993 | |||
934 | static void l2cap_sock_state_change_cb(struct l2cap_chan *chan, int state) | 994 | static void l2cap_sock_state_change_cb(struct l2cap_chan *chan, int state) |
935 | { | 995 | { |
936 | struct sock *sk = chan->data; | 996 | struct sock *sk = chan->data; |
@@ -959,6 +1019,7 @@ static struct l2cap_ops l2cap_chan_ops = { | |||
959 | .new_connection = l2cap_sock_new_connection_cb, | 1019 | .new_connection = l2cap_sock_new_connection_cb, |
960 | .recv = l2cap_sock_recv_cb, | 1020 | .recv = l2cap_sock_recv_cb, |
961 | .close = l2cap_sock_close_cb, | 1021 | .close = l2cap_sock_close_cb, |
1022 | .teardown = l2cap_sock_teardown_cb, | ||
962 | .state_change = l2cap_sock_state_change_cb, | 1023 | .state_change = l2cap_sock_state_change_cb, |
963 | .alloc_skb = l2cap_sock_alloc_skb_cb, | 1024 | .alloc_skb = l2cap_sock_alloc_skb_cb, |
964 | }; | 1025 | }; |