diff options
author | Marcel Holtmann <marcel@holtmann.org> | 2007-10-20 07:39:51 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-10-22 05:59:43 -0400 |
commit | 6464f35f3771f69cd8d107fff166dc29ab392f97 (patch) | |
tree | b737bc19dfd6decc6769a425491e0e0b06687d1b | |
parent | f0709e03ac3552b1b048ee171cb96ecaacc6813c (diff) |
[Bluetooth] Fall back to L2CAP in basic mode
In case the remote entity tries to negogiate retransmission or flow
control mode, reject it and fall back to basic mode.
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
-rw-r--r-- | include/net/bluetooth/l2cap.h | 13 | ||||
-rw-r--r-- | net/bluetooth/l2cap.c | 32 |
2 files changed, 37 insertions, 8 deletions
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index e1ea64085c4f..73e115bc12dd 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h | |||
@@ -149,6 +149,19 @@ struct l2cap_conf_opt { | |||
149 | 149 | ||
150 | #define L2CAP_CONF_MAX_SIZE 22 | 150 | #define L2CAP_CONF_MAX_SIZE 22 |
151 | 151 | ||
152 | struct l2cap_conf_rfc { | ||
153 | __u8 mode; | ||
154 | __u8 txwin_size; | ||
155 | __u8 max_transmit; | ||
156 | __le16 retrans_timeout; | ||
157 | __le16 monitor_timeout; | ||
158 | __le16 max_pdu_size; | ||
159 | } __attribute__ ((packed)); | ||
160 | |||
161 | #define L2CAP_MODE_BASIC 0x00 | ||
162 | #define L2CAP_MODE_RETRANS 0x01 | ||
163 | #define L2CAP_MODE_FLOWCTL 0x02 | ||
164 | |||
152 | struct l2cap_disconn_req { | 165 | struct l2cap_disconn_req { |
153 | __le16 dcid; | 166 | __le16 dcid; |
154 | __le16 scid; | 167 | __le16 scid; |
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 733c95dbd07e..6fbbae78b304 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c | |||
@@ -1048,7 +1048,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch | |||
1048 | opts.imtu = l2cap_pi(sk)->imtu; | 1048 | opts.imtu = l2cap_pi(sk)->imtu; |
1049 | opts.omtu = l2cap_pi(sk)->omtu; | 1049 | opts.omtu = l2cap_pi(sk)->omtu; |
1050 | opts.flush_to = l2cap_pi(sk)->flush_to; | 1050 | opts.flush_to = l2cap_pi(sk)->flush_to; |
1051 | opts.mode = 0x00; | 1051 | opts.mode = L2CAP_MODE_BASIC; |
1052 | 1052 | ||
1053 | len = min_t(unsigned int, sizeof(opts), optlen); | 1053 | len = min_t(unsigned int, sizeof(opts), optlen); |
1054 | if (copy_from_user((char *) &opts, optval, len)) { | 1054 | if (copy_from_user((char *) &opts, optval, len)) { |
@@ -1097,7 +1097,7 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch | |||
1097 | opts.imtu = l2cap_pi(sk)->imtu; | 1097 | opts.imtu = l2cap_pi(sk)->imtu; |
1098 | opts.omtu = l2cap_pi(sk)->omtu; | 1098 | opts.omtu = l2cap_pi(sk)->omtu; |
1099 | opts.flush_to = l2cap_pi(sk)->flush_to; | 1099 | opts.flush_to = l2cap_pi(sk)->flush_to; |
1100 | opts.mode = 0x00; | 1100 | opts.mode = L2CAP_MODE_BASIC; |
1101 | 1101 | ||
1102 | len = min_t(unsigned int, len, sizeof(opts)); | 1102 | len = min_t(unsigned int, len, sizeof(opts)); |
1103 | if (copy_to_user(optval, (char *) &opts, len)) | 1103 | if (copy_to_user(optval, (char *) &opts, len)) |
@@ -1376,6 +1376,7 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data) | |||
1376 | int len = pi->conf_len; | 1376 | int len = pi->conf_len; |
1377 | int type, hint, olen; | 1377 | int type, hint, olen; |
1378 | unsigned long val; | 1378 | unsigned long val; |
1379 | struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC }; | ||
1379 | u16 mtu = L2CAP_DEFAULT_MTU; | 1380 | u16 mtu = L2CAP_DEFAULT_MTU; |
1380 | u16 result = L2CAP_CONF_SUCCESS; | 1381 | u16 result = L2CAP_CONF_SUCCESS; |
1381 | 1382 | ||
@@ -1399,6 +1400,11 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data) | |||
1399 | case L2CAP_CONF_QOS: | 1400 | case L2CAP_CONF_QOS: |
1400 | break; | 1401 | break; |
1401 | 1402 | ||
1403 | case L2CAP_CONF_RFC: | ||
1404 | if (olen == sizeof(rfc)) | ||
1405 | memcpy(&rfc, (void *) val, olen); | ||
1406 | break; | ||
1407 | |||
1402 | default: | 1408 | default: |
1403 | if (hint) | 1409 | if (hint) |
1404 | break; | 1410 | break; |
@@ -1413,14 +1419,24 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data) | |||
1413 | /* Configure output options and let the other side know | 1419 | /* Configure output options and let the other side know |
1414 | * which ones we don't like. */ | 1420 | * which ones we don't like. */ |
1415 | 1421 | ||
1416 | if (mtu < pi->omtu) | 1422 | if (rfc.mode == L2CAP_MODE_BASIC) { |
1423 | if (mtu < pi->omtu) | ||
1424 | result = L2CAP_CONF_UNACCEPT; | ||
1425 | else { | ||
1426 | pi->omtu = mtu; | ||
1427 | pi->conf_state |= L2CAP_CONF_OUTPUT_DONE; | ||
1428 | } | ||
1429 | |||
1430 | l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->omtu); | ||
1431 | } else { | ||
1417 | result = L2CAP_CONF_UNACCEPT; | 1432 | result = L2CAP_CONF_UNACCEPT; |
1418 | else { | ||
1419 | pi->omtu = mtu; | ||
1420 | pi->conf_state |= L2CAP_CONF_OUTPUT_DONE; | ||
1421 | } | ||
1422 | 1433 | ||
1423 | l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->omtu); | 1434 | memset(&rfc, 0, sizeof(rfc)); |
1435 | rfc.mode = L2CAP_MODE_BASIC; | ||
1436 | |||
1437 | l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, | ||
1438 | sizeof(rfc), (unsigned long) &rfc); | ||
1439 | } | ||
1424 | } | 1440 | } |
1425 | 1441 | ||
1426 | rsp->scid = cpu_to_le16(pi->dcid); | 1442 | rsp->scid = cpu_to_le16(pi->dcid); |