diff options
author | Gustavo F. Padovan <padovan@profusion.mobi> | 2011-12-09 01:48:17 -0500 |
---|---|---|
committer | Gustavo F. Padovan <padovan@profusion.mobi> | 2011-12-18 14:07:57 -0500 |
commit | 03a001948166d966d0d580cddb8ae3a23f8b795b (patch) | |
tree | 341ca43e5feca84870e874eecfc03881e60179d5 /net | |
parent | f878fcad1760247c054a9c80964d0b7450d2379b (diff) |
Bluetooth: invert locking order in connect path
This move some checking code that was in l2cap_sock_connect() to
l2cap_chan_connect(). Thus we can invert the lock calls, i.e., call
lock_sock() before hci_dev_lock() to avoid a deadlock scenario.
Acked-by: Marcel Holtmann <marcel@holtmann.org>
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Diffstat (limited to 'net')
-rw-r--r-- | net/bluetooth/l2cap_core.c | 58 | ||||
-rw-r--r-- | net/bluetooth/l2cap_sock.c | 61 |
2 files changed, 59 insertions, 60 deletions
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index a78cdf7236db..d6165199fc8b 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c | |||
@@ -1144,11 +1144,10 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr | |||
1144 | return c1; | 1144 | return c1; |
1145 | } | 1145 | } |
1146 | 1146 | ||
1147 | int l2cap_chan_connect(struct l2cap_chan *chan) | 1147 | inline int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *dst) |
1148 | { | 1148 | { |
1149 | struct sock *sk = chan->sk; | 1149 | struct sock *sk = chan->sk; |
1150 | bdaddr_t *src = &bt_sk(sk)->src; | 1150 | bdaddr_t *src = &bt_sk(sk)->src; |
1151 | bdaddr_t *dst = &bt_sk(sk)->dst; | ||
1152 | struct l2cap_conn *conn; | 1151 | struct l2cap_conn *conn; |
1153 | struct hci_conn *hcon; | 1152 | struct hci_conn *hcon; |
1154 | struct hci_dev *hdev; | 1153 | struct hci_dev *hdev; |
@@ -1164,6 +1163,61 @@ int l2cap_chan_connect(struct l2cap_chan *chan) | |||
1164 | 1163 | ||
1165 | hci_dev_lock(hdev); | 1164 | hci_dev_lock(hdev); |
1166 | 1165 | ||
1166 | lock_sock(sk); | ||
1167 | |||
1168 | /* PSM must be odd and lsb of upper byte must be 0 */ | ||
1169 | if ((__le16_to_cpu(psm) & 0x0101) != 0x0001 && !cid && | ||
1170 | chan->chan_type != L2CAP_CHAN_RAW) { | ||
1171 | err = -EINVAL; | ||
1172 | goto done; | ||
1173 | } | ||
1174 | |||
1175 | if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED && !(psm || cid)) { | ||
1176 | err = -EINVAL; | ||
1177 | goto done; | ||
1178 | } | ||
1179 | |||
1180 | switch (chan->mode) { | ||
1181 | case L2CAP_MODE_BASIC: | ||
1182 | break; | ||
1183 | case L2CAP_MODE_ERTM: | ||
1184 | case L2CAP_MODE_STREAMING: | ||
1185 | if (!disable_ertm) | ||
1186 | break; | ||
1187 | /* fall through */ | ||
1188 | default: | ||
1189 | err = -ENOTSUPP; | ||
1190 | goto done; | ||
1191 | } | ||
1192 | |||
1193 | switch (sk->sk_state) { | ||
1194 | case BT_CONNECT: | ||
1195 | case BT_CONNECT2: | ||
1196 | case BT_CONFIG: | ||
1197 | /* Already connecting */ | ||
1198 | err = 0; | ||
1199 | goto done; | ||
1200 | |||
1201 | case BT_CONNECTED: | ||
1202 | /* Already connected */ | ||
1203 | err = -EISCONN; | ||
1204 | goto done; | ||
1205 | |||
1206 | case BT_OPEN: | ||
1207 | case BT_BOUND: | ||
1208 | /* Can connect */ | ||
1209 | break; | ||
1210 | |||
1211 | default: | ||
1212 | err = -EBADFD; | ||
1213 | goto done; | ||
1214 | } | ||
1215 | |||
1216 | /* Set destination address and psm */ | ||
1217 | bacpy(&bt_sk(sk)->dst, src); | ||
1218 | chan->psm = psm; | ||
1219 | chan->dcid = cid; | ||
1220 | |||
1167 | auth_type = l2cap_get_auth_type(chan); | 1221 | auth_type = l2cap_get_auth_type(chan); |
1168 | 1222 | ||
1169 | if (chan->dcid == L2CAP_CID_LE_DATA) | 1223 | if (chan->dcid == L2CAP_CID_LE_DATA) |
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index fbdc8b38d9ee..6c7d4323e797 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c | |||
@@ -121,70 +121,15 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al | |||
121 | if (la.l2_cid && la.l2_psm) | 121 | if (la.l2_cid && la.l2_psm) |
122 | return -EINVAL; | 122 | return -EINVAL; |
123 | 123 | ||
124 | lock_sock(sk); | 124 | err = l2cap_chan_connect(chan, la.l2_psm, la.l2_cid, &la.l2_bdaddr); |
125 | |||
126 | if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED | ||
127 | && !(la.l2_psm || la.l2_cid)) { | ||
128 | err = -EINVAL; | ||
129 | goto done; | ||
130 | } | ||
131 | |||
132 | switch (chan->mode) { | ||
133 | case L2CAP_MODE_BASIC: | ||
134 | break; | ||
135 | case L2CAP_MODE_ERTM: | ||
136 | case L2CAP_MODE_STREAMING: | ||
137 | if (!disable_ertm) | ||
138 | break; | ||
139 | /* fall through */ | ||
140 | default: | ||
141 | err = -ENOTSUPP; | ||
142 | goto done; | ||
143 | } | ||
144 | |||
145 | switch (sk->sk_state) { | ||
146 | case BT_CONNECT: | ||
147 | case BT_CONNECT2: | ||
148 | case BT_CONFIG: | ||
149 | /* Already connecting */ | ||
150 | goto wait; | ||
151 | |||
152 | case BT_CONNECTED: | ||
153 | /* Already connected */ | ||
154 | err = -EISCONN; | ||
155 | goto done; | ||
156 | |||
157 | case BT_OPEN: | ||
158 | case BT_BOUND: | ||
159 | /* Can connect */ | ||
160 | break; | ||
161 | |||
162 | default: | ||
163 | err = -EBADFD; | ||
164 | goto done; | ||
165 | } | ||
166 | |||
167 | /* PSM must be odd and lsb of upper byte must be 0 */ | ||
168 | if ((__le16_to_cpu(la.l2_psm) & 0x0101) != 0x0001 && !la.l2_cid && | ||
169 | chan->chan_type != L2CAP_CHAN_RAW) { | ||
170 | err = -EINVAL; | ||
171 | goto done; | ||
172 | } | ||
173 | |||
174 | /* Set destination address and psm */ | ||
175 | bacpy(&bt_sk(sk)->dst, &la.l2_bdaddr); | ||
176 | chan->psm = la.l2_psm; | ||
177 | chan->dcid = la.l2_cid; | ||
178 | |||
179 | err = l2cap_chan_connect(chan); | ||
180 | if (err) | 125 | if (err) |
181 | goto done; | 126 | goto done; |
182 | 127 | ||
183 | wait: | ||
184 | err = bt_sock_wait_state(sk, BT_CONNECTED, | 128 | err = bt_sock_wait_state(sk, BT_CONNECTED, |
185 | sock_sndtimeo(sk, flags & O_NONBLOCK)); | 129 | sock_sndtimeo(sk, flags & O_NONBLOCK)); |
186 | done: | 130 | done: |
187 | release_sock(sk); | 131 | if (sock_owned_by_user(sk)) |
132 | release_sock(sk); | ||
188 | return err; | 133 | return err; |
189 | } | 134 | } |
190 | 135 | ||