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 | |
| 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')
| -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 | ||
