aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/bluetooth/l2cap.c132
1 files changed, 79 insertions, 53 deletions
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index dc8601fc2404..cf4481f7f566 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -77,6 +77,8 @@ static void l2cap_sock_kill(struct sock *sk);
77static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, 77static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
78 u8 code, u8 ident, u16 dlen, void *data); 78 u8 code, u8 ident, u16 dlen, void *data);
79 79
80static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb);
81
80/* ---- L2CAP timers ---- */ 82/* ---- L2CAP timers ---- */
81static void l2cap_sock_timeout(unsigned long arg) 83static void l2cap_sock_timeout(unsigned long arg)
82{ 84{
@@ -2447,6 +2449,8 @@ static inline void l2cap_ertm_init(struct sock *sk)
2447 __skb_queue_head_init(BUSY_QUEUE(sk)); 2449 __skb_queue_head_init(BUSY_QUEUE(sk));
2448 2450
2449 INIT_WORK(&l2cap_pi(sk)->busy_work, l2cap_busy_work); 2451 INIT_WORK(&l2cap_pi(sk)->busy_work, l2cap_busy_work);
2452
2453 sk->sk_backlog_rcv = l2cap_ertm_data_rcv;
2450} 2454}
2451 2455
2452static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask) 2456static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask)
@@ -4171,13 +4175,83 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str
4171 return 0; 4175 return 0;
4172} 4176}
4173 4177
4178static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb)
4179{
4180 struct l2cap_pinfo *pi = l2cap_pi(sk);
4181 u16 control;
4182 u8 req_seq;
4183 int len, next_tx_seq_offset, req_seq_offset;
4184
4185 control = get_unaligned_le16(skb->data);
4186 skb_pull(skb, 2);
4187 len = skb->len;
4188
4189 /*
4190 * We can just drop the corrupted I-frame here.
4191 * Receiver will miss it and start proper recovery
4192 * procedures and ask retransmission.
4193 */
4194 if (l2cap_check_fcs(pi, skb))
4195 goto drop;
4196
4197 if (__is_sar_start(control) && __is_iframe(control))
4198 len -= 2;
4199
4200 if (pi->fcs == L2CAP_FCS_CRC16)
4201 len -= 2;
4202
4203 if (len > pi->mps) {
4204 l2cap_send_disconn_req(pi->conn, sk, ECONNRESET);
4205 goto drop;
4206 }
4207
4208 req_seq = __get_reqseq(control);
4209 req_seq_offset = (req_seq - pi->expected_ack_seq) % 64;
4210 if (req_seq_offset < 0)
4211 req_seq_offset += 64;
4212
4213 next_tx_seq_offset =
4214 (pi->next_tx_seq - pi->expected_ack_seq) % 64;
4215 if (next_tx_seq_offset < 0)
4216 next_tx_seq_offset += 64;
4217
4218 /* check for invalid req-seq */
4219 if (req_seq_offset > next_tx_seq_offset) {
4220 l2cap_send_disconn_req(pi->conn, sk, ECONNRESET);
4221 goto drop;
4222 }
4223
4224 if (__is_iframe(control)) {
4225 if (len < 0) {
4226 l2cap_send_disconn_req(pi->conn, sk, ECONNRESET);
4227 goto drop;
4228 }
4229
4230 l2cap_data_channel_iframe(sk, control, skb);
4231 } else {
4232 if (len != 0) {
4233 BT_ERR("%d", len);
4234 l2cap_send_disconn_req(pi->conn, sk, ECONNRESET);
4235 goto drop;
4236 }
4237
4238 l2cap_data_channel_sframe(sk, control, skb);
4239 }
4240
4241 return 0;
4242
4243drop:
4244 kfree_skb(skb);
4245 return 0;
4246}
4247
4174static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb) 4248static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb)
4175{ 4249{
4176 struct sock *sk; 4250 struct sock *sk;
4177 struct l2cap_pinfo *pi; 4251 struct l2cap_pinfo *pi;
4178 u16 control; 4252 u16 control;
4179 u8 tx_seq, req_seq; 4253 u8 tx_seq;
4180 int len, next_tx_seq_offset, req_seq_offset; 4254 int len;
4181 4255
4182 sk = l2cap_get_chan_by_scid(&conn->chan_list, cid); 4256 sk = l2cap_get_chan_by_scid(&conn->chan_list, cid);
4183 if (!sk) { 4257 if (!sk) {
@@ -4207,59 +4281,11 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
4207 break; 4281 break;
4208 4282
4209 case L2CAP_MODE_ERTM: 4283 case L2CAP_MODE_ERTM:
4210 control = get_unaligned_le16(skb->data); 4284 if (!sock_owned_by_user(sk)) {
4211 skb_pull(skb, 2); 4285 l2cap_ertm_data_rcv(sk, skb);
4212 len = skb->len;
4213
4214 /*
4215 * We can just drop the corrupted I-frame here.
4216 * Receiver will miss it and start proper recovery
4217 * procedures and ask retransmission.
4218 */
4219 if (l2cap_check_fcs(pi, skb))
4220 goto drop;
4221
4222 if (__is_sar_start(control) && __is_iframe(control))
4223 len -= 2;
4224
4225 if (pi->fcs == L2CAP_FCS_CRC16)
4226 len -= 2;
4227
4228 if (len > pi->mps) {
4229 l2cap_send_disconn_req(pi->conn, sk, ECONNRESET);
4230 goto drop;
4231 }
4232
4233 req_seq = __get_reqseq(control);
4234 req_seq_offset = (req_seq - pi->expected_ack_seq) % 64;
4235 if (req_seq_offset < 0)
4236 req_seq_offset += 64;
4237
4238 next_tx_seq_offset =
4239 (pi->next_tx_seq - pi->expected_ack_seq) % 64;
4240 if (next_tx_seq_offset < 0)
4241 next_tx_seq_offset += 64;
4242
4243 /* check for invalid req-seq */
4244 if (req_seq_offset > next_tx_seq_offset) {
4245 l2cap_send_disconn_req(pi->conn, sk, ECONNRESET);
4246 goto drop;
4247 }
4248
4249 if (__is_iframe(control)) {
4250 if (len < 0) {
4251 l2cap_send_disconn_req(pi->conn, sk, ECONNRESET);
4252 goto drop;
4253 }
4254
4255 l2cap_data_channel_iframe(sk, control, skb);
4256 } else { 4286 } else {
4257 if (len != 0) { 4287 if (sk_add_backlog(sk, skb))
4258 l2cap_send_disconn_req(pi->conn, sk, ECONNRESET);
4259 goto drop; 4288 goto drop;
4260 }
4261
4262 l2cap_data_channel_sframe(sk, control, skb);
4263 } 4289 }
4264 4290
4265 goto done; 4291 goto done;