aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth
diff options
context:
space:
mode:
authorGustavo F. Padovan <padovan@profusion.mobi>2010-05-01 15:15:39 -0400
committerMarcel Holtmann <marcel@holtmann.org>2010-05-10 03:28:48 -0400
commit7b1c0049be3aabc18831ada339dbcf41ba8c81fd (patch)
tree61d3e22c735d3e6e4ae3ad5d702ca6bfff846db0 /net/bluetooth
parent2fb862e215e53630066c677e06d7551fa38bf235 (diff)
Bluetooth: Read RFC conf option on a successful Conf RSP
On Enhanced Retransmission Mode and Streaming Mode a entity can send, on a successful Conf RSP, new values for the RFC fields. For example, the entity can send txWindow and MPS values less than the value received on a Conf REQ. 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.c39
1 files changed, 38 insertions, 1 deletions
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index f604405fe667..c50c05738fb6 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -2602,6 +2602,42 @@ static int l2cap_build_conf_rsp(struct sock *sk, void *data, u16 result, u16 fla
2602 return ptr - data; 2602 return ptr - data;
2603} 2603}
2604 2604
2605static void l2cap_conf_rfc_get(struct sock *sk, void *rsp, int len)
2606{
2607 struct l2cap_pinfo *pi = l2cap_pi(sk);
2608 int type, olen;
2609 unsigned long val;
2610 struct l2cap_conf_rfc rfc;
2611
2612 BT_DBG("sk %p, rsp %p, len %d", sk, rsp, len);
2613
2614 if ((pi->mode != L2CAP_MODE_ERTM) && (pi->mode != L2CAP_MODE_STREAMING))
2615 return;
2616
2617 while (len >= L2CAP_CONF_OPT_SIZE) {
2618 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
2619
2620 switch (type) {
2621 case L2CAP_CONF_RFC:
2622 if (olen == sizeof(rfc))
2623 memcpy(&rfc, (void *)val, olen);
2624 goto done;
2625 }
2626 }
2627
2628done:
2629 switch (rfc.mode) {
2630 case L2CAP_MODE_ERTM:
2631 pi->remote_tx_win = rfc.txwin_size;
2632 pi->retrans_timeout = rfc.retrans_timeout;
2633 pi->monitor_timeout = rfc.monitor_timeout;
2634 pi->mps = le16_to_cpu(rfc.max_pdu_size);
2635 break;
2636 case L2CAP_MODE_STREAMING:
2637 pi->mps = le16_to_cpu(rfc.max_pdu_size);
2638 }
2639}
2640
2605static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data) 2641static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2606{ 2642{
2607 struct l2cap_cmd_rej *rej = (struct l2cap_cmd_rej *) data; 2643 struct l2cap_cmd_rej *rej = (struct l2cap_cmd_rej *) data;
@@ -2881,6 +2917,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
2881 struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data; 2917 struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data;
2882 u16 scid, flags, result; 2918 u16 scid, flags, result;
2883 struct sock *sk; 2919 struct sock *sk;
2920 int len = cmd->len - sizeof(*rsp);
2884 2921
2885 scid = __le16_to_cpu(rsp->scid); 2922 scid = __le16_to_cpu(rsp->scid);
2886 flags = __le16_to_cpu(rsp->flags); 2923 flags = __le16_to_cpu(rsp->flags);
@@ -2895,11 +2932,11 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
2895 2932
2896 switch (result) { 2933 switch (result) {
2897 case L2CAP_CONF_SUCCESS: 2934 case L2CAP_CONF_SUCCESS:
2935 l2cap_conf_rfc_get(sk, rsp->data, len);
2898 break; 2936 break;
2899 2937
2900 case L2CAP_CONF_UNACCEPT: 2938 case L2CAP_CONF_UNACCEPT:
2901 if (l2cap_pi(sk)->num_conf_rsp <= L2CAP_CONF_MAX_CONF_RSP) { 2939 if (l2cap_pi(sk)->num_conf_rsp <= L2CAP_CONF_MAX_CONF_RSP) {
2902 int len = cmd->len - sizeof(*rsp);
2903 char req[64]; 2940 char req[64];
2904 2941
2905 if (len > sizeof(req) - sizeof(struct l2cap_conf_req)) { 2942 if (len > sizeof(req) - sizeof(struct l2cap_conf_req)) {