diff options
Diffstat (limited to 'net/bluetooth/sco.c')
-rw-r--r-- | net/bluetooth/sco.c | 125 |
1 files changed, 75 insertions, 50 deletions
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index c06dbd3938e8..7ee9e4ab00f8 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c | |||
@@ -40,13 +40,38 @@ static struct bt_sock_list sco_sk_list = { | |||
40 | .lock = __RW_LOCK_UNLOCKED(sco_sk_list.lock) | 40 | .lock = __RW_LOCK_UNLOCKED(sco_sk_list.lock) |
41 | }; | 41 | }; |
42 | 42 | ||
43 | static void __sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent); | 43 | /* ---- SCO connections ---- */ |
44 | static void sco_chan_del(struct sock *sk, int err); | 44 | struct sco_conn { |
45 | struct hci_conn *hcon; | ||
46 | |||
47 | spinlock_t lock; | ||
48 | struct sock *sk; | ||
49 | |||
50 | unsigned int mtu; | ||
51 | }; | ||
52 | |||
53 | #define sco_conn_lock(c) spin_lock(&c->lock); | ||
54 | #define sco_conn_unlock(c) spin_unlock(&c->lock); | ||
45 | 55 | ||
46 | static void sco_sock_close(struct sock *sk); | 56 | static void sco_sock_close(struct sock *sk); |
47 | static void sco_sock_kill(struct sock *sk); | 57 | static void sco_sock_kill(struct sock *sk); |
48 | 58 | ||
59 | /* ----- SCO socket info ----- */ | ||
60 | #define sco_pi(sk) ((struct sco_pinfo *) sk) | ||
61 | |||
62 | struct sco_pinfo { | ||
63 | struct bt_sock bt; | ||
64 | bdaddr_t src; | ||
65 | bdaddr_t dst; | ||
66 | __u32 flags; | ||
67 | __u16 setting; | ||
68 | struct sco_conn *conn; | ||
69 | }; | ||
70 | |||
49 | /* ---- SCO timers ---- */ | 71 | /* ---- SCO timers ---- */ |
72 | #define SCO_CONN_TIMEOUT (HZ * 40) | ||
73 | #define SCO_DISCONN_TIMEOUT (HZ * 2) | ||
74 | |||
50 | static void sco_sock_timeout(unsigned long arg) | 75 | static void sco_sock_timeout(unsigned long arg) |
51 | { | 76 | { |
52 | struct sock *sk = (struct sock *) arg; | 77 | struct sock *sk = (struct sock *) arg; |
@@ -102,13 +127,31 @@ static struct sco_conn *sco_conn_add(struct hci_conn *hcon) | |||
102 | return conn; | 127 | return conn; |
103 | } | 128 | } |
104 | 129 | ||
105 | static struct sock *sco_chan_get(struct sco_conn *conn) | 130 | /* Delete channel. |
131 | * Must be called on the locked socket. */ | ||
132 | static void sco_chan_del(struct sock *sk, int err) | ||
106 | { | 133 | { |
107 | struct sock *sk = NULL; | 134 | struct sco_conn *conn; |
108 | sco_conn_lock(conn); | 135 | |
109 | sk = conn->sk; | 136 | conn = sco_pi(sk)->conn; |
110 | sco_conn_unlock(conn); | 137 | |
111 | return sk; | 138 | BT_DBG("sk %p, conn %p, err %d", sk, conn, err); |
139 | |||
140 | if (conn) { | ||
141 | sco_conn_lock(conn); | ||
142 | conn->sk = NULL; | ||
143 | sco_pi(sk)->conn = NULL; | ||
144 | sco_conn_unlock(conn); | ||
145 | |||
146 | if (conn->hcon) | ||
147 | hci_conn_drop(conn->hcon); | ||
148 | } | ||
149 | |||
150 | sk->sk_state = BT_CLOSED; | ||
151 | sk->sk_err = err; | ||
152 | sk->sk_state_change(sk); | ||
153 | |||
154 | sock_set_flag(sk, SOCK_ZAPPED); | ||
112 | } | 155 | } |
113 | 156 | ||
114 | static int sco_conn_del(struct hci_conn *hcon, int err) | 157 | static int sco_conn_del(struct hci_conn *hcon, int err) |
@@ -122,7 +165,10 @@ static int sco_conn_del(struct hci_conn *hcon, int err) | |||
122 | BT_DBG("hcon %p conn %p, err %d", hcon, conn, err); | 165 | BT_DBG("hcon %p conn %p, err %d", hcon, conn, err); |
123 | 166 | ||
124 | /* Kill socket */ | 167 | /* Kill socket */ |
125 | sk = sco_chan_get(conn); | 168 | sco_conn_lock(conn); |
169 | sk = conn->sk; | ||
170 | sco_conn_unlock(conn); | ||
171 | |||
126 | if (sk) { | 172 | if (sk) { |
127 | bh_lock_sock(sk); | 173 | bh_lock_sock(sk); |
128 | sco_sock_clear_timer(sk); | 174 | sco_sock_clear_timer(sk); |
@@ -136,6 +182,17 @@ static int sco_conn_del(struct hci_conn *hcon, int err) | |||
136 | return 0; | 182 | return 0; |
137 | } | 183 | } |
138 | 184 | ||
185 | static void __sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent) | ||
186 | { | ||
187 | BT_DBG("conn %p", conn); | ||
188 | |||
189 | sco_pi(sk)->conn = conn; | ||
190 | conn->sk = sk; | ||
191 | |||
192 | if (parent) | ||
193 | bt_accept_enqueue(parent, sk); | ||
194 | } | ||
195 | |||
139 | static int sco_chan_add(struct sco_conn *conn, struct sock *sk, | 196 | static int sco_chan_add(struct sco_conn *conn, struct sock *sk, |
140 | struct sock *parent) | 197 | struct sock *parent) |
141 | { | 198 | { |
@@ -240,7 +297,11 @@ static int sco_send_frame(struct sock *sk, struct msghdr *msg, int len) | |||
240 | 297 | ||
241 | static void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb) | 298 | static void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb) |
242 | { | 299 | { |
243 | struct sock *sk = sco_chan_get(conn); | 300 | struct sock *sk; |
301 | |||
302 | sco_conn_lock(conn); | ||
303 | sk = conn->sk; | ||
304 | sco_conn_unlock(conn); | ||
244 | 305 | ||
245 | if (!sk) | 306 | if (!sk) |
246 | goto drop; | 307 | goto drop; |
@@ -909,7 +970,8 @@ static int sco_sock_shutdown(struct socket *sock, int how) | |||
909 | sco_sock_clear_timer(sk); | 970 | sco_sock_clear_timer(sk); |
910 | __sco_sock_close(sk); | 971 | __sco_sock_close(sk); |
911 | 972 | ||
912 | if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime) | 973 | if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime && |
974 | !(current->flags & PF_EXITING)) | ||
913 | err = bt_sock_wait_state(sk, BT_CLOSED, | 975 | err = bt_sock_wait_state(sk, BT_CLOSED, |
914 | sk->sk_lingertime); | 976 | sk->sk_lingertime); |
915 | } | 977 | } |
@@ -929,7 +991,8 @@ static int sco_sock_release(struct socket *sock) | |||
929 | 991 | ||
930 | sco_sock_close(sk); | 992 | sco_sock_close(sk); |
931 | 993 | ||
932 | if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime) { | 994 | if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime && |
995 | !(current->flags & PF_EXITING)) { | ||
933 | lock_sock(sk); | 996 | lock_sock(sk); |
934 | err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime); | 997 | err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime); |
935 | release_sock(sk); | 998 | release_sock(sk); |
@@ -940,44 +1003,6 @@ static int sco_sock_release(struct socket *sock) | |||
940 | return err; | 1003 | return err; |
941 | } | 1004 | } |
942 | 1005 | ||
943 | static void __sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent) | ||
944 | { | ||
945 | BT_DBG("conn %p", conn); | ||
946 | |||
947 | sco_pi(sk)->conn = conn; | ||
948 | conn->sk = sk; | ||
949 | |||
950 | if (parent) | ||
951 | bt_accept_enqueue(parent, sk); | ||
952 | } | ||
953 | |||
954 | /* Delete channel. | ||
955 | * Must be called on the locked socket. */ | ||
956 | static void sco_chan_del(struct sock *sk, int err) | ||
957 | { | ||
958 | struct sco_conn *conn; | ||
959 | |||
960 | conn = sco_pi(sk)->conn; | ||
961 | |||
962 | BT_DBG("sk %p, conn %p, err %d", sk, conn, err); | ||
963 | |||
964 | if (conn) { | ||
965 | sco_conn_lock(conn); | ||
966 | conn->sk = NULL; | ||
967 | sco_pi(sk)->conn = NULL; | ||
968 | sco_conn_unlock(conn); | ||
969 | |||
970 | if (conn->hcon) | ||
971 | hci_conn_drop(conn->hcon); | ||
972 | } | ||
973 | |||
974 | sk->sk_state = BT_CLOSED; | ||
975 | sk->sk_err = err; | ||
976 | sk->sk_state_change(sk); | ||
977 | |||
978 | sock_set_flag(sk, SOCK_ZAPPED); | ||
979 | } | ||
980 | |||
981 | static void sco_conn_ready(struct sco_conn *conn) | 1006 | static void sco_conn_ready(struct sco_conn *conn) |
982 | { | 1007 | { |
983 | struct sock *parent; | 1008 | struct sock *parent; |