diff options
author | Gustavo F. Padovan <padovan@profusion.mobi> | 2010-05-20 15:21:53 -0400 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2010-07-21 13:39:07 -0400 |
commit | 9b108fc0cf4e79c34a7d5626f5c2c4c529ef6d3f (patch) | |
tree | 4c5822c30372a735569bce8e2fdf08a148795972 /net/bluetooth/l2cap.c | |
parent | 4ea727ef9d507413f15da0de401d8a50b125649a (diff) |
Bluetooth: Fix ERTM error reporting to the userspace
If any error occurs during transfers we have to tell userspace that
something wrong happened.
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Reviewed-by: João Paulo Rechi Vita <jprvita@profusion.mobi>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/bluetooth/l2cap.c')
-rw-r--r-- | net/bluetooth/l2cap.c | 39 |
1 files changed, 22 insertions, 17 deletions
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 7c2273732909..1e39d72b80af 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c | |||
@@ -456,7 +456,7 @@ static void l2cap_do_start(struct sock *sk) | |||
456 | } | 456 | } |
457 | } | 457 | } |
458 | 458 | ||
459 | static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct sock *sk) | 459 | static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct sock *sk, int err) |
460 | { | 460 | { |
461 | struct l2cap_disconn_req req; | 461 | struct l2cap_disconn_req req; |
462 | 462 | ||
@@ -477,6 +477,7 @@ static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct sock *sk) | |||
477 | L2CAP_DISCONN_REQ, sizeof(req), &req); | 477 | L2CAP_DISCONN_REQ, sizeof(req), &req); |
478 | 478 | ||
479 | sk->sk_state = BT_DISCONN; | 479 | sk->sk_state = BT_DISCONN; |
480 | sk->sk_err = err; | ||
480 | } | 481 | } |
481 | 482 | ||
482 | /* ---- L2CAP connections ---- */ | 483 | /* ---- L2CAP connections ---- */ |
@@ -770,7 +771,7 @@ static void __l2cap_sock_close(struct sock *sk, int reason) | |||
770 | struct l2cap_conn *conn = l2cap_pi(sk)->conn; | 771 | struct l2cap_conn *conn = l2cap_pi(sk)->conn; |
771 | 772 | ||
772 | l2cap_sock_set_timer(sk, sk->sk_sndtimeo); | 773 | l2cap_sock_set_timer(sk, sk->sk_sndtimeo); |
773 | l2cap_send_disconn_req(conn, sk); | 774 | l2cap_send_disconn_req(conn, sk, reason); |
774 | } else | 775 | } else |
775 | l2cap_chan_del(sk, reason); | 776 | l2cap_chan_del(sk, reason); |
776 | break; | 777 | break; |
@@ -1315,7 +1316,7 @@ static void l2cap_monitor_timeout(unsigned long arg) | |||
1315 | 1316 | ||
1316 | bh_lock_sock(sk); | 1317 | bh_lock_sock(sk); |
1317 | if (l2cap_pi(sk)->retry_count >= l2cap_pi(sk)->remote_max_tx) { | 1318 | if (l2cap_pi(sk)->retry_count >= l2cap_pi(sk)->remote_max_tx) { |
1318 | l2cap_send_disconn_req(l2cap_pi(sk)->conn, sk); | 1319 | l2cap_send_disconn_req(l2cap_pi(sk)->conn, sk, ECONNABORTED); |
1319 | bh_unlock_sock(sk); | 1320 | bh_unlock_sock(sk); |
1320 | return; | 1321 | return; |
1321 | } | 1322 | } |
@@ -1423,7 +1424,7 @@ static void l2cap_retransmit_one_frame(struct sock *sk, u8 tx_seq) | |||
1423 | 1424 | ||
1424 | if (pi->remote_max_tx && | 1425 | if (pi->remote_max_tx && |
1425 | bt_cb(skb)->retries == pi->remote_max_tx) { | 1426 | bt_cb(skb)->retries == pi->remote_max_tx) { |
1426 | l2cap_send_disconn_req(pi->conn, sk); | 1427 | l2cap_send_disconn_req(pi->conn, sk, ECONNABORTED); |
1427 | return; | 1428 | return; |
1428 | } | 1429 | } |
1429 | 1430 | ||
@@ -1463,7 +1464,7 @@ static int l2cap_ertm_send(struct sock *sk) | |||
1463 | 1464 | ||
1464 | if (pi->remote_max_tx && | 1465 | if (pi->remote_max_tx && |
1465 | bt_cb(skb)->retries == pi->remote_max_tx) { | 1466 | bt_cb(skb)->retries == pi->remote_max_tx) { |
1466 | l2cap_send_disconn_req(pi->conn, sk); | 1467 | l2cap_send_disconn_req(pi->conn, sk, ECONNABORTED); |
1467 | break; | 1468 | break; |
1468 | } | 1469 | } |
1469 | 1470 | ||
@@ -2191,6 +2192,10 @@ static int l2cap_sock_shutdown(struct socket *sock, int how) | |||
2191 | err = bt_sock_wait_state(sk, BT_CLOSED, | 2192 | err = bt_sock_wait_state(sk, BT_CLOSED, |
2192 | sk->sk_lingertime); | 2193 | sk->sk_lingertime); |
2193 | } | 2194 | } |
2195 | |||
2196 | if (!err && sk->sk_err) | ||
2197 | err = -sk->sk_err; | ||
2198 | |||
2194 | release_sock(sk); | 2199 | release_sock(sk); |
2195 | return err; | 2200 | return err; |
2196 | } | 2201 | } |
@@ -2462,7 +2467,7 @@ static int l2cap_build_conf_req(struct sock *sk, void *data) | |||
2462 | case L2CAP_MODE_ERTM: | 2467 | case L2CAP_MODE_ERTM: |
2463 | pi->conf_state |= L2CAP_CONF_STATE2_DEVICE; | 2468 | pi->conf_state |= L2CAP_CONF_STATE2_DEVICE; |
2464 | if (!l2cap_mode_supported(pi->mode, pi->conn->feat_mask)) | 2469 | if (!l2cap_mode_supported(pi->mode, pi->conn->feat_mask)) |
2465 | l2cap_send_disconn_req(pi->conn, sk); | 2470 | l2cap_send_disconn_req(pi->conn, sk, ECONNRESET); |
2466 | break; | 2471 | break; |
2467 | default: | 2472 | default: |
2468 | pi->mode = l2cap_select_mode(rfc.mode, pi->conn->feat_mask); | 2473 | pi->mode = l2cap_select_mode(rfc.mode, pi->conn->feat_mask); |
@@ -3030,7 +3035,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr | |||
3030 | /* Complete config. */ | 3035 | /* Complete config. */ |
3031 | len = l2cap_parse_conf_req(sk, rsp); | 3036 | len = l2cap_parse_conf_req(sk, rsp); |
3032 | if (len < 0) { | 3037 | if (len < 0) { |
3033 | l2cap_send_disconn_req(conn, sk); | 3038 | l2cap_send_disconn_req(conn, sk, ECONNRESET); |
3034 | goto unlock; | 3039 | goto unlock; |
3035 | } | 3040 | } |
3036 | 3041 | ||
@@ -3100,7 +3105,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr | |||
3100 | char req[64]; | 3105 | char req[64]; |
3101 | 3106 | ||
3102 | if (len > sizeof(req) - sizeof(struct l2cap_conf_req)) { | 3107 | if (len > sizeof(req) - sizeof(struct l2cap_conf_req)) { |
3103 | l2cap_send_disconn_req(conn, sk); | 3108 | l2cap_send_disconn_req(conn, sk, ECONNRESET); |
3104 | goto done; | 3109 | goto done; |
3105 | } | 3110 | } |
3106 | 3111 | ||
@@ -3109,7 +3114,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr | |||
3109 | len = l2cap_parse_conf_rsp(sk, rsp->data, | 3114 | len = l2cap_parse_conf_rsp(sk, rsp->data, |
3110 | len, req, &result); | 3115 | len, req, &result); |
3111 | if (len < 0) { | 3116 | if (len < 0) { |
3112 | l2cap_send_disconn_req(conn, sk); | 3117 | l2cap_send_disconn_req(conn, sk, ECONNRESET); |
3113 | goto done; | 3118 | goto done; |
3114 | } | 3119 | } |
3115 | 3120 | ||
@@ -3124,7 +3129,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr | |||
3124 | default: | 3129 | default: |
3125 | sk->sk_err = ECONNRESET; | 3130 | sk->sk_err = ECONNRESET; |
3126 | l2cap_sock_set_timer(sk, HZ * 5); | 3131 | l2cap_sock_set_timer(sk, HZ * 5); |
3127 | l2cap_send_disconn_req(conn, sk); | 3132 | l2cap_send_disconn_req(conn, sk, ECONNRESET); |
3128 | goto done; | 3133 | goto done; |
3129 | } | 3134 | } |
3130 | 3135 | ||
@@ -3565,7 +3570,7 @@ drop: | |||
3565 | pi->sdu = NULL; | 3570 | pi->sdu = NULL; |
3566 | 3571 | ||
3567 | disconnect: | 3572 | disconnect: |
3568 | l2cap_send_disconn_req(pi->conn, sk); | 3573 | l2cap_send_disconn_req(pi->conn, sk, ECONNRESET); |
3569 | kfree_skb(skb); | 3574 | kfree_skb(skb); |
3570 | return 0; | 3575 | return 0; |
3571 | } | 3576 | } |
@@ -3588,7 +3593,7 @@ static void l2cap_busy_work(struct work_struct *work) | |||
3588 | 3593 | ||
3589 | if (n_tries++ > L2CAP_LOCAL_BUSY_TRIES) { | 3594 | if (n_tries++ > L2CAP_LOCAL_BUSY_TRIES) { |
3590 | err = -EBUSY; | 3595 | err = -EBUSY; |
3591 | l2cap_send_disconn_req(pi->conn, sk); | 3596 | l2cap_send_disconn_req(pi->conn, sk, EBUSY); |
3592 | goto done; | 3597 | goto done; |
3593 | } | 3598 | } |
3594 | 3599 | ||
@@ -3864,7 +3869,7 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str | |||
3864 | 3869 | ||
3865 | /* invalid tx_seq */ | 3870 | /* invalid tx_seq */ |
3866 | if (tx_seq_offset >= pi->tx_win) { | 3871 | if (tx_seq_offset >= pi->tx_win) { |
3867 | l2cap_send_disconn_req(pi->conn, sk); | 3872 | l2cap_send_disconn_req(pi->conn, sk, ECONNRESET); |
3868 | goto drop; | 3873 | goto drop; |
3869 | } | 3874 | } |
3870 | 3875 | ||
@@ -4181,7 +4186,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk | |||
4181 | len -= 2; | 4186 | len -= 2; |
4182 | 4187 | ||
4183 | if (len > pi->mps) { | 4188 | if (len > pi->mps) { |
4184 | l2cap_send_disconn_req(pi->conn, sk); | 4189 | l2cap_send_disconn_req(pi->conn, sk, ECONNRESET); |
4185 | goto drop; | 4190 | goto drop; |
4186 | } | 4191 | } |
4187 | 4192 | ||
@@ -4197,20 +4202,20 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk | |||
4197 | 4202 | ||
4198 | /* check for invalid req-seq */ | 4203 | /* check for invalid req-seq */ |
4199 | if (req_seq_offset > next_tx_seq_offset) { | 4204 | if (req_seq_offset > next_tx_seq_offset) { |
4200 | l2cap_send_disconn_req(pi->conn, sk); | 4205 | l2cap_send_disconn_req(pi->conn, sk, ECONNRESET); |
4201 | goto drop; | 4206 | goto drop; |
4202 | } | 4207 | } |
4203 | 4208 | ||
4204 | if (__is_iframe(control)) { | 4209 | if (__is_iframe(control)) { |
4205 | if (len < 0) { | 4210 | if (len < 0) { |
4206 | l2cap_send_disconn_req(pi->conn, sk); | 4211 | l2cap_send_disconn_req(pi->conn, sk, ECONNRESET); |
4207 | goto drop; | 4212 | goto drop; |
4208 | } | 4213 | } |
4209 | 4214 | ||
4210 | l2cap_data_channel_iframe(sk, control, skb); | 4215 | l2cap_data_channel_iframe(sk, control, skb); |
4211 | } else { | 4216 | } else { |
4212 | if (len != 0) { | 4217 | if (len != 0) { |
4213 | l2cap_send_disconn_req(pi->conn, sk); | 4218 | l2cap_send_disconn_req(pi->conn, sk, ECONNRESET); |
4214 | goto drop; | 4219 | goto drop; |
4215 | } | 4220 | } |
4216 | 4221 | ||