diff options
Diffstat (limited to 'net/bluetooth/l2cap_core.c')
-rw-r--r-- | net/bluetooth/l2cap_core.c | 151 |
1 files changed, 83 insertions, 68 deletions
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index d42dfdc83ebb..a8964db04bfb 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -431,6 +431,7 @@ void l2cap_chan_set_defaults(struct l2cap_chan *chan) chan->max_tx = L2CAP_DEFAULT_MAX_TX; chan->tx_win = L2CAP_DEFAULT_TX_WINDOW; chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW; + chan->ack_win = L2CAP_DEFAULT_TX_WINDOW; chan->sec_level = BT_SECURITY_LOW; set_bit(FLAG_FORCE_ACTIVE, &chan->flags); @@ -1657,7 +1658,7 @@ static void l2cap_streaming_send(struct l2cap_chan *chan, l2cap_do_send(chan, skb); - BT_DBG("Sent txseq %d", (int)control->txseq); + BT_DBG("Sent txseq %u", control->txseq); chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq); chan->frames_sent++; @@ -1722,11 +1723,11 @@ static int l2cap_ertm_send(struct l2cap_chan *chan) chan->tx_send_head = skb_queue_next(&chan->tx_q, skb); l2cap_do_send(chan, tx_skb); - BT_DBG("Sent txseq %d", (int)control->txseq); + BT_DBG("Sent txseq %u", control->txseq); } - BT_DBG("Sent %d, %d unacked, %d in ERTM queue", sent, - (int) chan->unacked_frames, skb_queue_len(&chan->tx_q)); + BT_DBG("Sent %d, %u unacked, %u in ERTM queue", sent, + chan->unacked_frames, skb_queue_len(&chan->tx_q)); return sent; } @@ -1877,14 +1878,14 @@ static void l2cap_send_ack(struct l2cap_chan *chan) frames_to_ack = 0; } - /* Ack now if the tx window is 3/4ths full. + /* Ack now if the window is 3/4ths full. * Calculate without mul or div */ - threshold = chan->tx_win; + threshold = chan->ack_win; threshold += threshold << 1; threshold >>= 2; - BT_DBG("frames_to_ack %d, threshold %d", (int)frames_to_ack, + BT_DBG("frames_to_ack %u, threshold %d", frames_to_ack, threshold); if (frames_to_ack >= threshold) { @@ -1946,15 +1947,15 @@ static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan, } static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, - struct msghdr *msg, size_t len, - u32 priority) + struct msghdr *msg, size_t len, + u32 priority) { struct l2cap_conn *conn = chan->conn; struct sk_buff *skb; int err, count, hlen = L2CAP_HDR_SIZE + L2CAP_PSMLEN_SIZE; struct l2cap_hdr *lh; - BT_DBG("chan %p len %d priority %u", chan, (int)len, priority); + BT_DBG("chan %p len %zu priority %u", chan, len, priority); count = min_t(unsigned int, (conn->mtu - hlen), len); @@ -1980,15 +1981,15 @@ static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, } static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, - struct msghdr *msg, size_t len, - u32 priority) + struct msghdr *msg, size_t len, + u32 priority) { struct l2cap_conn *conn = chan->conn; struct sk_buff *skb; int err, count; struct l2cap_hdr *lh; - BT_DBG("chan %p len %d", chan, (int)len); + BT_DBG("chan %p len %zu", chan, len); count = min_t(unsigned int, (conn->mtu - L2CAP_HDR_SIZE), len); @@ -2013,15 +2014,15 @@ static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, } static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, - struct msghdr *msg, size_t len, - u16 sdulen) + struct msghdr *msg, size_t len, + u16 sdulen) { struct l2cap_conn *conn = chan->conn; struct sk_buff *skb; int err, count, hlen; struct l2cap_hdr *lh; - BT_DBG("chan %p len %d", chan, (int)len); + BT_DBG("chan %p len %zu", chan, len); if (!conn) return ERR_PTR(-ENOTCONN); @@ -2075,7 +2076,7 @@ static int l2cap_segment_sdu(struct l2cap_chan *chan, size_t pdu_len; u8 sar; - BT_DBG("chan %p, msg %p, len %d", chan, msg, (int)len); + BT_DBG("chan %p, msg %p, len %zu", chan, msg, len); /* It is critical that ERTM PDUs fit in a single HCI fragment, * so fragmented skbs are not used. The HCI layer's handling @@ -2219,7 +2220,7 @@ static void l2cap_send_srej(struct l2cap_chan *chan, u16 txseq) struct l2cap_ctrl control; u16 seq; - BT_DBG("chan %p, txseq %d", chan, txseq); + BT_DBG("chan %p, txseq %u", chan, txseq); memset(&control, 0, sizeof(control)); control.sframe = 1; @@ -2259,7 +2260,7 @@ static void l2cap_send_srej_list(struct l2cap_chan *chan, u16 txseq) u16 initial_head; u16 seq; - BT_DBG("chan %p, txseq %d", chan, txseq); + BT_DBG("chan %p, txseq %u", chan, txseq); memset(&control, 0, sizeof(control)); control.sframe = 1; @@ -2284,12 +2285,12 @@ static void l2cap_process_reqseq(struct l2cap_chan *chan, u16 reqseq) struct sk_buff *acked_skb; u16 ackseq; - BT_DBG("chan %p, reqseq %d", chan, reqseq); + BT_DBG("chan %p, reqseq %u", chan, reqseq); if (chan->unacked_frames == 0 || reqseq == chan->expected_ack_seq) return; - BT_DBG("expected_ack_seq %d, unacked_frames %d", + BT_DBG("expected_ack_seq %u, unacked_frames %u", chan->expected_ack_seq, chan->unacked_frames); for (ackseq = chan->expected_ack_seq; ackseq != reqseq; @@ -2308,7 +2309,7 @@ static void l2cap_process_reqseq(struct l2cap_chan *chan, u16 reqseq) if (chan->unacked_frames == 0) __clear_retrans_timer(chan); - BT_DBG("unacked_frames %d", (int) chan->unacked_frames); + BT_DBG("unacked_frames %u", chan->unacked_frames); } static void l2cap_abort_rx_srej_sent(struct l2cap_chan *chan) @@ -2534,16 +2535,16 @@ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb) } /* ---- L2CAP signalling commands ---- */ -static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, - u8 code, u8 ident, u16 dlen, void *data) +static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, u8 code, + u8 ident, u16 dlen, void *data) { struct sk_buff *skb, **frag; struct l2cap_cmd_hdr *cmd; struct l2cap_hdr *lh; int len, count; - BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %d", - conn, code, ident, dlen); + BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %u", + conn, code, ident, dlen); len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen; count = min_t(unsigned int, conn->mtu, len); @@ -2626,7 +2627,7 @@ static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen, unsigned break; } - BT_DBG("type 0x%2.2x len %d val 0x%lx", *type, opt->len, *val); + BT_DBG("type 0x%2.2x len %u val 0x%lx", *type, opt->len, *val); return len; } @@ -2634,7 +2635,7 @@ static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val) { struct l2cap_conf_opt *opt = *ptr; - BT_DBG("type 0x%2.2x len %d val 0x%lx", type, len, val); + BT_DBG("type 0x%2.2x len %u val 0x%lx", type, len, val); opt->type = type; opt->len = len; @@ -2786,6 +2787,7 @@ static inline void l2cap_txwin_setup(struct l2cap_chan *chan) L2CAP_DEFAULT_TX_WINDOW); chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW; } + chan->ack_win = chan->tx_win; } static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data) @@ -3175,10 +3177,9 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi break; case L2CAP_CONF_EWS: - chan->tx_win = min_t(u16, val, - L2CAP_DEFAULT_EXT_WINDOW); + chan->ack_win = min_t(u16, val, chan->ack_win); l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2, - chan->tx_win); + chan->tx_win); break; case L2CAP_CONF_EFS: @@ -3207,6 +3208,9 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout); chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout); chan->mps = le16_to_cpu(rfc.max_pdu_size); + if (!test_bit(FLAG_EXT_CTRL, &chan->flags)) + chan->ack_win = min_t(u16, chan->ack_win, + rfc.txwin_size); if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) { chan->local_msdu = le16_to_cpu(efs.msdu); @@ -3268,7 +3272,17 @@ static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len) { int type, olen; unsigned long val; - struct l2cap_conf_rfc rfc; + /* Use sane default values in case a misbehaving remote device + * did not send an RFC or extended window size option. + */ + u16 txwin_ext = chan->ack_win; + struct l2cap_conf_rfc rfc = { + .mode = chan->mode, + .retrans_timeout = __constant_cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO), + .monitor_timeout = __constant_cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO), + .max_pdu_size = cpu_to_le16(chan->imtu), + .txwin_size = min_t(u16, chan->ack_win, L2CAP_DEFAULT_TX_WINDOW), + }; BT_DBG("chan %p, rsp %p, len %d", chan, rsp, len); @@ -3278,32 +3292,27 @@ static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len) while (len >= L2CAP_CONF_OPT_SIZE) { len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val); - if (type != L2CAP_CONF_RFC) - continue; - - if (olen != sizeof(rfc)) + switch (type) { + case L2CAP_CONF_RFC: + if (olen == sizeof(rfc)) + memcpy(&rfc, (void *)val, olen); break; - - memcpy(&rfc, (void *)val, olen); - goto done; + case L2CAP_CONF_EWS: + txwin_ext = val; + break; + } } - /* Use sane default values in case a misbehaving remote device - * did not send an RFC option. - */ - rfc.mode = chan->mode; - rfc.retrans_timeout = __constant_cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO); - rfc.monitor_timeout = __constant_cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO); - rfc.max_pdu_size = cpu_to_le16(chan->imtu); - - BT_ERR("Expected RFC option was not found, using defaults"); - -done: switch (rfc.mode) { case L2CAP_MODE_ERTM: chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout); chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout); - chan->mps = le16_to_cpu(rfc.max_pdu_size); + chan->mps = le16_to_cpu(rfc.max_pdu_size); + if (test_bit(FLAG_EXT_CTRL, &chan->flags)) + chan->ack_win = min_t(u16, chan->ack_win, txwin_ext); + else + chan->ack_win = min_t(u16, chan->ack_win, + rfc.txwin_size); break; case L2CAP_MODE_STREAMING: chan->mps = le16_to_cpu(rfc.max_pdu_size); @@ -3949,7 +3958,7 @@ static inline int l2cap_create_channel_req(struct l2cap_conn *conn, psm = le16_to_cpu(req->psm); scid = le16_to_cpu(req->scid); - BT_DBG("psm %d, scid %d, amp_id %d", psm, scid, req->amp_id); + BT_DBG("psm 0x%2.2x, scid 0x%4.4x, amp_id %d", psm, scid, req->amp_id); /* Placeholder: Always reject */ rsp.dcid = 0; @@ -3972,11 +3981,11 @@ static inline int l2cap_create_channel_rsp(struct l2cap_conn *conn, } static void l2cap_send_move_chan_rsp(struct l2cap_conn *conn, u8 ident, - u16 icid, u16 result) + u16 icid, u16 result) { struct l2cap_move_chan_rsp rsp; - BT_DBG("icid %d, result %d", icid, result); + BT_DBG("icid 0x%4.4x, result 0x%4.4x", icid, result); rsp.icid = cpu_to_le16(icid); rsp.result = cpu_to_le16(result); @@ -3985,12 +3994,13 @@ static void l2cap_send_move_chan_rsp(struct l2cap_conn *conn, u8 ident, } static void l2cap_send_move_chan_cfm(struct l2cap_conn *conn, - struct l2cap_chan *chan, u16 icid, u16 result) + struct l2cap_chan *chan, + u16 icid, u16 result) { struct l2cap_move_chan_cfm cfm; u8 ident; - BT_DBG("icid %d, result %d", icid, result); + BT_DBG("icid 0x%4.4x, result 0x%4.4x", icid, result); ident = l2cap_get_ident(conn); if (chan) @@ -4003,18 +4013,19 @@ static void l2cap_send_move_chan_cfm(struct l2cap_conn *conn, } static void l2cap_send_move_chan_cfm_rsp(struct l2cap_conn *conn, u8 ident, - u16 icid) + u16 icid) { struct l2cap_move_chan_cfm_rsp rsp; - BT_DBG("icid %d", icid); + BT_DBG("icid 0x%4.4x", icid); rsp.icid = cpu_to_le16(icid); l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM_RSP, sizeof(rsp), &rsp); } static inline int l2cap_move_channel_req(struct l2cap_conn *conn, - struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data) + struct l2cap_cmd_hdr *cmd, + u16 cmd_len, void *data) { struct l2cap_move_chan_req *req = data; u16 icid = 0; @@ -4025,7 +4036,7 @@ static inline int l2cap_move_channel_req(struct l2cap_conn *conn, icid = le16_to_cpu(req->icid); - BT_DBG("icid %d, dest_amp_id %d", icid, req->dest_amp_id); + BT_DBG("icid 0x%4.4x, dest_amp_id %d", icid, req->dest_amp_id); if (!enable_hs) return -EINVAL; @@ -4037,7 +4048,8 @@ static inline int l2cap_move_channel_req(struct l2cap_conn *conn, } static inline int l2cap_move_channel_rsp(struct l2cap_conn *conn, - struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data) + struct l2cap_cmd_hdr *cmd, + u16 cmd_len, void *data) { struct l2cap_move_chan_rsp *rsp = data; u16 icid, result; @@ -4048,7 +4060,7 @@ static inline int l2cap_move_channel_rsp(struct l2cap_conn *conn, icid = le16_to_cpu(rsp->icid); result = le16_to_cpu(rsp->result); - BT_DBG("icid %d, result %d", icid, result); + BT_DBG("icid 0x%4.4x, result 0x%4.4x", icid, result); /* Placeholder: Always unconfirmed */ l2cap_send_move_chan_cfm(conn, NULL, icid, L2CAP_MC_UNCONFIRMED); @@ -4057,7 +4069,8 @@ static inline int l2cap_move_channel_rsp(struct l2cap_conn *conn, } static inline int l2cap_move_channel_confirm(struct l2cap_conn *conn, - struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data) + struct l2cap_cmd_hdr *cmd, + u16 cmd_len, void *data) { struct l2cap_move_chan_cfm *cfm = data; u16 icid, result; @@ -4068,7 +4081,7 @@ static inline int l2cap_move_channel_confirm(struct l2cap_conn *conn, icid = le16_to_cpu(cfm->icid); result = le16_to_cpu(cfm->result); - BT_DBG("icid %d, result %d", icid, result); + BT_DBG("icid 0x%4.4x, result 0x%4.4x", icid, result); l2cap_send_move_chan_cfm_rsp(conn, cmd->ident, icid); @@ -4076,7 +4089,8 @@ static inline int l2cap_move_channel_confirm(struct l2cap_conn *conn, } static inline int l2cap_move_channel_confirm_rsp(struct l2cap_conn *conn, - struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data) + struct l2cap_cmd_hdr *cmd, + u16 cmd_len, void *data) { struct l2cap_move_chan_cfm_rsp *rsp = data; u16 icid; @@ -4086,7 +4100,7 @@ static inline int l2cap_move_channel_confirm_rsp(struct l2cap_conn *conn, icid = le16_to_cpu(rsp->icid); - BT_DBG("icid %d", icid); + BT_DBG("icid 0x%4.4x", icid); return 0; } @@ -5374,7 +5388,7 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) if (!conn) return 0; - BT_DBG("conn %p", conn); + BT_DBG("conn %p status 0x%2.2x encrypt %u", conn, status, encrypt); if (hcon->type == LE_LINK) { if (!status && encrypt) @@ -5387,7 +5401,8 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) list_for_each_entry(chan, &conn->chan_l, list) { l2cap_chan_lock(chan); - BT_DBG("chan->scid %d", chan->scid); + BT_DBG("chan %p scid 0x%4.4x state %s", chan, chan->scid, + state_to_string(chan->state)); if (chan->scid == L2CAP_CID_LE_DATA) { if (!status && encrypt) { |