diff options
Diffstat (limited to 'net/bluetooth')
-rw-r--r-- | net/bluetooth/l2cap.c | 357 |
1 files changed, 177 insertions, 180 deletions
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index f6501fa0d59f..eaaad658d11d 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c | |||
@@ -63,11 +63,6 @@ static struct bt_sock_list l2cap_sk_list = { | |||
63 | .lock = RW_LOCK_UNLOCKED | 63 | .lock = RW_LOCK_UNLOCKED |
64 | }; | 64 | }; |
65 | 65 | ||
66 | static int l2cap_conn_del(struct hci_conn *conn, int err); | ||
67 | |||
68 | static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent); | ||
69 | static void l2cap_chan_del(struct sock *sk, int err); | ||
70 | |||
71 | static void __l2cap_sock_close(struct sock *sk, int reason); | 66 | static void __l2cap_sock_close(struct sock *sk, int reason); |
72 | static void l2cap_sock_close(struct sock *sk); | 67 | static void l2cap_sock_close(struct sock *sk); |
73 | static void l2cap_sock_kill(struct sock *sk); | 68 | static void l2cap_sock_kill(struct sock *sk); |
@@ -109,24 +104,177 @@ static void l2cap_sock_init_timer(struct sock *sk) | |||
109 | sk->sk_timer.data = (unsigned long)sk; | 104 | sk->sk_timer.data = (unsigned long)sk; |
110 | } | 105 | } |
111 | 106 | ||
107 | /* ---- L2CAP channels ---- */ | ||
108 | static struct sock *__l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, u16 cid) | ||
109 | { | ||
110 | struct sock *s; | ||
111 | for (s = l->head; s; s = l2cap_pi(s)->next_c) { | ||
112 | if (l2cap_pi(s)->dcid == cid) | ||
113 | break; | ||
114 | } | ||
115 | return s; | ||
116 | } | ||
117 | |||
118 | static struct sock *__l2cap_get_chan_by_scid(struct l2cap_chan_list *l, u16 cid) | ||
119 | { | ||
120 | struct sock *s; | ||
121 | for (s = l->head; s; s = l2cap_pi(s)->next_c) { | ||
122 | if (l2cap_pi(s)->scid == cid) | ||
123 | break; | ||
124 | } | ||
125 | return s; | ||
126 | } | ||
127 | |||
128 | /* Find channel with given SCID. | ||
129 | * Returns locked socket */ | ||
130 | static inline struct sock *l2cap_get_chan_by_scid(struct l2cap_chan_list *l, u16 cid) | ||
131 | { | ||
132 | struct sock *s; | ||
133 | read_lock(&l->lock); | ||
134 | s = __l2cap_get_chan_by_scid(l, cid); | ||
135 | if (s) bh_lock_sock(s); | ||
136 | read_unlock(&l->lock); | ||
137 | return s; | ||
138 | } | ||
139 | |||
140 | static struct sock *__l2cap_get_chan_by_ident(struct l2cap_chan_list *l, u8 ident) | ||
141 | { | ||
142 | struct sock *s; | ||
143 | for (s = l->head; s; s = l2cap_pi(s)->next_c) { | ||
144 | if (l2cap_pi(s)->ident == ident) | ||
145 | break; | ||
146 | } | ||
147 | return s; | ||
148 | } | ||
149 | |||
150 | static inline struct sock *l2cap_get_chan_by_ident(struct l2cap_chan_list *l, u8 ident) | ||
151 | { | ||
152 | struct sock *s; | ||
153 | read_lock(&l->lock); | ||
154 | s = __l2cap_get_chan_by_ident(l, ident); | ||
155 | if (s) bh_lock_sock(s); | ||
156 | read_unlock(&l->lock); | ||
157 | return s; | ||
158 | } | ||
159 | |||
160 | static u16 l2cap_alloc_cid(struct l2cap_chan_list *l) | ||
161 | { | ||
162 | u16 cid = 0x0040; | ||
163 | |||
164 | for (; cid < 0xffff; cid++) { | ||
165 | if(!__l2cap_get_chan_by_scid(l, cid)) | ||
166 | return cid; | ||
167 | } | ||
168 | |||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | static inline void __l2cap_chan_link(struct l2cap_chan_list *l, struct sock *sk) | ||
173 | { | ||
174 | sock_hold(sk); | ||
175 | |||
176 | if (l->head) | ||
177 | l2cap_pi(l->head)->prev_c = sk; | ||
178 | |||
179 | l2cap_pi(sk)->next_c = l->head; | ||
180 | l2cap_pi(sk)->prev_c = NULL; | ||
181 | l->head = sk; | ||
182 | } | ||
183 | |||
184 | static inline void l2cap_chan_unlink(struct l2cap_chan_list *l, struct sock *sk) | ||
185 | { | ||
186 | struct sock *next = l2cap_pi(sk)->next_c, *prev = l2cap_pi(sk)->prev_c; | ||
187 | |||
188 | write_lock(&l->lock); | ||
189 | if (sk == l->head) | ||
190 | l->head = next; | ||
191 | |||
192 | if (next) | ||
193 | l2cap_pi(next)->prev_c = prev; | ||
194 | if (prev) | ||
195 | l2cap_pi(prev)->next_c = next; | ||
196 | write_unlock(&l->lock); | ||
197 | |||
198 | __sock_put(sk); | ||
199 | } | ||
200 | |||
201 | static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent) | ||
202 | { | ||
203 | struct l2cap_chan_list *l = &conn->chan_list; | ||
204 | |||
205 | BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, l2cap_pi(sk)->psm, l2cap_pi(sk)->dcid); | ||
206 | |||
207 | l2cap_pi(sk)->conn = conn; | ||
208 | |||
209 | if (sk->sk_type == SOCK_SEQPACKET) { | ||
210 | /* Alloc CID for connection-oriented socket */ | ||
211 | l2cap_pi(sk)->scid = l2cap_alloc_cid(l); | ||
212 | } else if (sk->sk_type == SOCK_DGRAM) { | ||
213 | /* Connectionless socket */ | ||
214 | l2cap_pi(sk)->scid = 0x0002; | ||
215 | l2cap_pi(sk)->dcid = 0x0002; | ||
216 | l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU; | ||
217 | } else { | ||
218 | /* Raw socket can send/recv signalling messages only */ | ||
219 | l2cap_pi(sk)->scid = 0x0001; | ||
220 | l2cap_pi(sk)->dcid = 0x0001; | ||
221 | l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU; | ||
222 | } | ||
223 | |||
224 | __l2cap_chan_link(l, sk); | ||
225 | |||
226 | if (parent) | ||
227 | bt_accept_enqueue(parent, sk); | ||
228 | } | ||
229 | |||
230 | /* Delete channel. | ||
231 | * Must be called on the locked socket. */ | ||
232 | static void l2cap_chan_del(struct sock *sk, int err) | ||
233 | { | ||
234 | struct l2cap_conn *conn = l2cap_pi(sk)->conn; | ||
235 | struct sock *parent = bt_sk(sk)->parent; | ||
236 | |||
237 | l2cap_sock_clear_timer(sk); | ||
238 | |||
239 | BT_DBG("sk %p, conn %p, err %d", sk, conn, err); | ||
240 | |||
241 | if (conn) { | ||
242 | /* Unlink from channel list */ | ||
243 | l2cap_chan_unlink(&conn->chan_list, sk); | ||
244 | l2cap_pi(sk)->conn = NULL; | ||
245 | hci_conn_put(conn->hcon); | ||
246 | } | ||
247 | |||
248 | sk->sk_state = BT_CLOSED; | ||
249 | sock_set_flag(sk, SOCK_ZAPPED); | ||
250 | |||
251 | if (err) | ||
252 | sk->sk_err = err; | ||
253 | |||
254 | if (parent) { | ||
255 | bt_accept_unlink(sk); | ||
256 | parent->sk_data_ready(parent, 0); | ||
257 | } else | ||
258 | sk->sk_state_change(sk); | ||
259 | } | ||
260 | |||
112 | /* ---- L2CAP connections ---- */ | 261 | /* ---- L2CAP connections ---- */ |
113 | static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status) | 262 | static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status) |
114 | { | 263 | { |
115 | struct l2cap_conn *conn; | 264 | struct l2cap_conn *conn = hcon->l2cap_data; |
116 | |||
117 | if ((conn = hcon->l2cap_data)) | ||
118 | return conn; | ||
119 | 265 | ||
120 | if (status) | 266 | if (conn || status) |
121 | return conn; | 267 | return conn; |
122 | 268 | ||
123 | if (!(conn = kmalloc(sizeof(struct l2cap_conn), GFP_ATOMIC))) | 269 | conn = kzalloc(sizeof(struct l2cap_conn), GFP_ATOMIC); |
270 | if (!conn) | ||
124 | return NULL; | 271 | return NULL; |
125 | memset(conn, 0, sizeof(struct l2cap_conn)); | ||
126 | 272 | ||
127 | hcon->l2cap_data = conn; | 273 | hcon->l2cap_data = conn; |
128 | conn->hcon = hcon; | 274 | conn->hcon = hcon; |
129 | 275 | ||
276 | BT_DBG("hcon %p conn %p", hcon, conn); | ||
277 | |||
130 | conn->mtu = hcon->hdev->acl_mtu; | 278 | conn->mtu = hcon->hdev->acl_mtu; |
131 | conn->src = &hcon->hdev->bdaddr; | 279 | conn->src = &hcon->hdev->bdaddr; |
132 | conn->dst = &hcon->dst; | 280 | conn->dst = &hcon->dst; |
@@ -134,17 +282,16 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status) | |||
134 | spin_lock_init(&conn->lock); | 282 | spin_lock_init(&conn->lock); |
135 | rwlock_init(&conn->chan_list.lock); | 283 | rwlock_init(&conn->chan_list.lock); |
136 | 284 | ||
137 | BT_DBG("hcon %p conn %p", hcon, conn); | ||
138 | return conn; | 285 | return conn; |
139 | } | 286 | } |
140 | 287 | ||
141 | static int l2cap_conn_del(struct hci_conn *hcon, int err) | 288 | static void l2cap_conn_del(struct hci_conn *hcon, int err) |
142 | { | 289 | { |
143 | struct l2cap_conn *conn; | 290 | struct l2cap_conn *conn = hcon->l2cap_data; |
144 | struct sock *sk; | 291 | struct sock *sk; |
145 | 292 | ||
146 | if (!(conn = hcon->l2cap_data)) | 293 | if (!conn) |
147 | return 0; | 294 | return; |
148 | 295 | ||
149 | BT_DBG("hcon %p conn %p, err %d", hcon, conn, err); | 296 | BT_DBG("hcon %p conn %p, err %d", hcon, conn, err); |
150 | 297 | ||
@@ -161,7 +308,6 @@ static int l2cap_conn_del(struct hci_conn *hcon, int err) | |||
161 | 308 | ||
162 | hcon->l2cap_data = NULL; | 309 | hcon->l2cap_data = NULL; |
163 | kfree(conn); | 310 | kfree(conn); |
164 | return 0; | ||
165 | } | 311 | } |
166 | 312 | ||
167 | static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent) | 313 | static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent) |
@@ -925,160 +1071,6 @@ static int l2cap_sock_release(struct socket *sock) | |||
925 | return err; | 1071 | return err; |
926 | } | 1072 | } |
927 | 1073 | ||
928 | /* ---- L2CAP channels ---- */ | ||
929 | static struct sock *__l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, u16 cid) | ||
930 | { | ||
931 | struct sock *s; | ||
932 | for (s = l->head; s; s = l2cap_pi(s)->next_c) { | ||
933 | if (l2cap_pi(s)->dcid == cid) | ||
934 | break; | ||
935 | } | ||
936 | return s; | ||
937 | } | ||
938 | |||
939 | static struct sock *__l2cap_get_chan_by_scid(struct l2cap_chan_list *l, u16 cid) | ||
940 | { | ||
941 | struct sock *s; | ||
942 | for (s = l->head; s; s = l2cap_pi(s)->next_c) { | ||
943 | if (l2cap_pi(s)->scid == cid) | ||
944 | break; | ||
945 | } | ||
946 | return s; | ||
947 | } | ||
948 | |||
949 | /* Find channel with given SCID. | ||
950 | * Returns locked socket */ | ||
951 | static inline struct sock *l2cap_get_chan_by_scid(struct l2cap_chan_list *l, u16 cid) | ||
952 | { | ||
953 | struct sock *s; | ||
954 | read_lock(&l->lock); | ||
955 | s = __l2cap_get_chan_by_scid(l, cid); | ||
956 | if (s) bh_lock_sock(s); | ||
957 | read_unlock(&l->lock); | ||
958 | return s; | ||
959 | } | ||
960 | |||
961 | static struct sock *__l2cap_get_chan_by_ident(struct l2cap_chan_list *l, u8 ident) | ||
962 | { | ||
963 | struct sock *s; | ||
964 | for (s = l->head; s; s = l2cap_pi(s)->next_c) { | ||
965 | if (l2cap_pi(s)->ident == ident) | ||
966 | break; | ||
967 | } | ||
968 | return s; | ||
969 | } | ||
970 | |||
971 | static inline struct sock *l2cap_get_chan_by_ident(struct l2cap_chan_list *l, u8 ident) | ||
972 | { | ||
973 | struct sock *s; | ||
974 | read_lock(&l->lock); | ||
975 | s = __l2cap_get_chan_by_ident(l, ident); | ||
976 | if (s) bh_lock_sock(s); | ||
977 | read_unlock(&l->lock); | ||
978 | return s; | ||
979 | } | ||
980 | |||
981 | static u16 l2cap_alloc_cid(struct l2cap_chan_list *l) | ||
982 | { | ||
983 | u16 cid = 0x0040; | ||
984 | |||
985 | for (; cid < 0xffff; cid++) { | ||
986 | if(!__l2cap_get_chan_by_scid(l, cid)) | ||
987 | return cid; | ||
988 | } | ||
989 | |||
990 | return 0; | ||
991 | } | ||
992 | |||
993 | static inline void __l2cap_chan_link(struct l2cap_chan_list *l, struct sock *sk) | ||
994 | { | ||
995 | sock_hold(sk); | ||
996 | |||
997 | if (l->head) | ||
998 | l2cap_pi(l->head)->prev_c = sk; | ||
999 | |||
1000 | l2cap_pi(sk)->next_c = l->head; | ||
1001 | l2cap_pi(sk)->prev_c = NULL; | ||
1002 | l->head = sk; | ||
1003 | } | ||
1004 | |||
1005 | static inline void l2cap_chan_unlink(struct l2cap_chan_list *l, struct sock *sk) | ||
1006 | { | ||
1007 | struct sock *next = l2cap_pi(sk)->next_c, *prev = l2cap_pi(sk)->prev_c; | ||
1008 | |||
1009 | write_lock(&l->lock); | ||
1010 | if (sk == l->head) | ||
1011 | l->head = next; | ||
1012 | |||
1013 | if (next) | ||
1014 | l2cap_pi(next)->prev_c = prev; | ||
1015 | if (prev) | ||
1016 | l2cap_pi(prev)->next_c = next; | ||
1017 | write_unlock(&l->lock); | ||
1018 | |||
1019 | __sock_put(sk); | ||
1020 | } | ||
1021 | |||
1022 | static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent) | ||
1023 | { | ||
1024 | struct l2cap_chan_list *l = &conn->chan_list; | ||
1025 | |||
1026 | BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, l2cap_pi(sk)->psm, l2cap_pi(sk)->dcid); | ||
1027 | |||
1028 | l2cap_pi(sk)->conn = conn; | ||
1029 | |||
1030 | if (sk->sk_type == SOCK_SEQPACKET) { | ||
1031 | /* Alloc CID for connection-oriented socket */ | ||
1032 | l2cap_pi(sk)->scid = l2cap_alloc_cid(l); | ||
1033 | } else if (sk->sk_type == SOCK_DGRAM) { | ||
1034 | /* Connectionless socket */ | ||
1035 | l2cap_pi(sk)->scid = 0x0002; | ||
1036 | l2cap_pi(sk)->dcid = 0x0002; | ||
1037 | l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU; | ||
1038 | } else { | ||
1039 | /* Raw socket can send/recv signalling messages only */ | ||
1040 | l2cap_pi(sk)->scid = 0x0001; | ||
1041 | l2cap_pi(sk)->dcid = 0x0001; | ||
1042 | l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU; | ||
1043 | } | ||
1044 | |||
1045 | __l2cap_chan_link(l, sk); | ||
1046 | |||
1047 | if (parent) | ||
1048 | bt_accept_enqueue(parent, sk); | ||
1049 | } | ||
1050 | |||
1051 | /* Delete channel. | ||
1052 | * Must be called on the locked socket. */ | ||
1053 | static void l2cap_chan_del(struct sock *sk, int err) | ||
1054 | { | ||
1055 | struct l2cap_conn *conn = l2cap_pi(sk)->conn; | ||
1056 | struct sock *parent = bt_sk(sk)->parent; | ||
1057 | |||
1058 | l2cap_sock_clear_timer(sk); | ||
1059 | |||
1060 | BT_DBG("sk %p, conn %p, err %d", sk, conn, err); | ||
1061 | |||
1062 | if (conn) { | ||
1063 | /* Unlink from channel list */ | ||
1064 | l2cap_chan_unlink(&conn->chan_list, sk); | ||
1065 | l2cap_pi(sk)->conn = NULL; | ||
1066 | hci_conn_put(conn->hcon); | ||
1067 | } | ||
1068 | |||
1069 | sk->sk_state = BT_CLOSED; | ||
1070 | sock_set_flag(sk, SOCK_ZAPPED); | ||
1071 | |||
1072 | if (err) | ||
1073 | sk->sk_err = err; | ||
1074 | |||
1075 | if (parent) { | ||
1076 | bt_accept_unlink(sk); | ||
1077 | parent->sk_data_ready(parent, 0); | ||
1078 | } else | ||
1079 | sk->sk_state_change(sk); | ||
1080 | } | ||
1081 | |||
1082 | static void l2cap_conn_ready(struct l2cap_conn *conn) | 1074 | static void l2cap_conn_ready(struct l2cap_conn *conn) |
1083 | { | 1075 | { |
1084 | struct l2cap_chan_list *l = &conn->chan_list; | 1076 | struct l2cap_chan_list *l = &conn->chan_list; |
@@ -1834,7 +1826,9 @@ drop: | |||
1834 | kfree_skb(skb); | 1826 | kfree_skb(skb); |
1835 | 1827 | ||
1836 | done: | 1828 | done: |
1837 | if (sk) bh_unlock_sock(sk); | 1829 | if (sk) |
1830 | bh_unlock_sock(sk); | ||
1831 | |||
1838 | return 0; | 1832 | return 0; |
1839 | } | 1833 | } |
1840 | 1834 | ||
@@ -1925,18 +1919,18 @@ static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) | |||
1925 | 1919 | ||
1926 | static int l2cap_connect_cfm(struct hci_conn *hcon, u8 status) | 1920 | static int l2cap_connect_cfm(struct hci_conn *hcon, u8 status) |
1927 | { | 1921 | { |
1922 | struct l2cap_conn *conn; | ||
1923 | |||
1928 | BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status); | 1924 | BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status); |
1929 | 1925 | ||
1930 | if (hcon->type != ACL_LINK) | 1926 | if (hcon->type != ACL_LINK) |
1931 | return 0; | 1927 | return 0; |
1932 | 1928 | ||
1933 | if (!status) { | 1929 | if (!status) { |
1934 | struct l2cap_conn *conn; | ||
1935 | |||
1936 | conn = l2cap_conn_add(hcon, status); | 1930 | conn = l2cap_conn_add(hcon, status); |
1937 | if (conn) | 1931 | if (conn) |
1938 | l2cap_conn_ready(conn); | 1932 | l2cap_conn_ready(conn); |
1939 | } else | 1933 | } else |
1940 | l2cap_conn_del(hcon, bt_err(status)); | 1934 | l2cap_conn_del(hcon, bt_err(status)); |
1941 | 1935 | ||
1942 | return 0; | 1936 | return 0; |
@@ -1950,19 +1944,21 @@ static int l2cap_disconn_ind(struct hci_conn *hcon, u8 reason) | |||
1950 | return 0; | 1944 | return 0; |
1951 | 1945 | ||
1952 | l2cap_conn_del(hcon, bt_err(reason)); | 1946 | l2cap_conn_del(hcon, bt_err(reason)); |
1947 | |||
1953 | return 0; | 1948 | return 0; |
1954 | } | 1949 | } |
1955 | 1950 | ||
1956 | static int l2cap_auth_cfm(struct hci_conn *hcon, u8 status) | 1951 | static int l2cap_auth_cfm(struct hci_conn *hcon, u8 status) |
1957 | { | 1952 | { |
1958 | struct l2cap_chan_list *l; | 1953 | struct l2cap_chan_list *l; |
1959 | struct l2cap_conn *conn; | 1954 | struct l2cap_conn *conn = conn = hcon->l2cap_data; |
1960 | struct l2cap_conn_rsp rsp; | 1955 | struct l2cap_conn_rsp rsp; |
1961 | struct sock *sk; | 1956 | struct sock *sk; |
1962 | int result; | 1957 | int result; |
1963 | 1958 | ||
1964 | if (!(conn = hcon->l2cap_data)) | 1959 | if (!conn) |
1965 | return 0; | 1960 | return 0; |
1961 | |||
1966 | l = &conn->chan_list; | 1962 | l = &conn->chan_list; |
1967 | 1963 | ||
1968 | BT_DBG("conn %p", conn); | 1964 | BT_DBG("conn %p", conn); |
@@ -2005,13 +2001,14 @@ static int l2cap_auth_cfm(struct hci_conn *hcon, u8 status) | |||
2005 | static int l2cap_encrypt_cfm(struct hci_conn *hcon, u8 status) | 2001 | static int l2cap_encrypt_cfm(struct hci_conn *hcon, u8 status) |
2006 | { | 2002 | { |
2007 | struct l2cap_chan_list *l; | 2003 | struct l2cap_chan_list *l; |
2008 | struct l2cap_conn *conn; | 2004 | struct l2cap_conn *conn = hcon->l2cap_data; |
2009 | struct l2cap_conn_rsp rsp; | 2005 | struct l2cap_conn_rsp rsp; |
2010 | struct sock *sk; | 2006 | struct sock *sk; |
2011 | int result; | 2007 | int result; |
2012 | 2008 | ||
2013 | if (!(conn = hcon->l2cap_data)) | 2009 | if (!conn) |
2014 | return 0; | 2010 | return 0; |
2011 | |||
2015 | l = &conn->chan_list; | 2012 | l = &conn->chan_list; |
2016 | 2013 | ||
2017 | BT_DBG("conn %p", conn); | 2014 | BT_DBG("conn %p", conn); |