aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorGustavo F. Padovan <padovan@profusion.mobi>2011-12-09 01:48:17 -0500
committerGustavo F. Padovan <padovan@profusion.mobi>2011-12-18 14:07:57 -0500
commit03a001948166d966d0d580cddb8ae3a23f8b795b (patch)
tree341ca43e5feca84870e874eecfc03881e60179d5 /net
parentf878fcad1760247c054a9c80964d0b7450d2379b (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.c58
-rw-r--r--net/bluetooth/l2cap_sock.c61
2 files changed, 59 insertions, 60 deletions
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index a78cdf7236d..d6165199fc8 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
1147int l2cap_chan_connect(struct l2cap_chan *chan) 1147inline 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 fbdc8b38d9e..6c7d4323e79 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
183wait:
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));
186done: 130done:
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