|
@@ -724,87 +724,6 @@ static void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
|
|
hci_send_acl(chan->conn->hchan, skb, flags);
|
|
hci_send_acl(chan->conn->hchan, skb, flags);
|
|
}
|
|
}
|
|
|
|
|
|
-static inline void l2cap_send_sframe(struct l2cap_chan *chan, u32 control)
|
|
|
|
-{
|
|
|
|
- struct sk_buff *skb;
|
|
|
|
- struct l2cap_hdr *lh;
|
|
|
|
- struct l2cap_conn *conn = chan->conn;
|
|
|
|
- int count, hlen;
|
|
|
|
-
|
|
|
|
- if (chan->state != BT_CONNECTED)
|
|
|
|
- return;
|
|
|
|
-
|
|
|
|
- if (test_bit(FLAG_EXT_CTRL, &chan->flags))
|
|
|
|
- hlen = L2CAP_EXT_HDR_SIZE;
|
|
|
|
- else
|
|
|
|
- hlen = L2CAP_ENH_HDR_SIZE;
|
|
|
|
-
|
|
|
|
- if (chan->fcs == L2CAP_FCS_CRC16)
|
|
|
|
- hlen += L2CAP_FCS_SIZE;
|
|
|
|
-
|
|
|
|
- BT_DBG("chan %p, control 0x%8.8x", chan, control);
|
|
|
|
-
|
|
|
|
- count = min_t(unsigned int, conn->mtu, hlen);
|
|
|
|
-
|
|
|
|
- control |= __set_sframe(chan);
|
|
|
|
-
|
|
|
|
- if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
|
|
|
|
- control |= __set_ctrl_final(chan);
|
|
|
|
-
|
|
|
|
- if (test_and_clear_bit(CONN_SEND_PBIT, &chan->conn_state))
|
|
|
|
- control |= __set_ctrl_poll(chan);
|
|
|
|
-
|
|
|
|
- skb = bt_skb_alloc(count, GFP_ATOMIC);
|
|
|
|
- if (!skb)
|
|
|
|
- return;
|
|
|
|
-
|
|
|
|
- lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
|
|
|
|
- lh->len = cpu_to_le16(hlen - L2CAP_HDR_SIZE);
|
|
|
|
- lh->cid = cpu_to_le16(chan->dcid);
|
|
|
|
-
|
|
|
|
- __put_control(chan, control, skb_put(skb, __ctrl_size(chan)));
|
|
|
|
-
|
|
|
|
- if (chan->fcs == L2CAP_FCS_CRC16) {
|
|
|
|
- u16 fcs = crc16(0, (u8 *)lh, count - L2CAP_FCS_SIZE);
|
|
|
|
- put_unaligned_le16(fcs, skb_put(skb, L2CAP_FCS_SIZE));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- skb->priority = HCI_PRIO_MAX;
|
|
|
|
- l2cap_do_send(chan, skb);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u32 control)
|
|
|
|
-{
|
|
|
|
- if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
|
|
|
|
- control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
|
|
|
|
- set_bit(CONN_RNR_SENT, &chan->conn_state);
|
|
|
|
- } else
|
|
|
|
- control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
|
|
|
|
-
|
|
|
|
- control |= __set_reqseq(chan, chan->buffer_seq);
|
|
|
|
-
|
|
|
|
- l2cap_send_sframe(chan, control);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static u16 __pack_enhanced_control(struct l2cap_ctrl *control)
|
|
|
|
-{
|
|
|
|
- u16 packed;
|
|
|
|
-
|
|
|
|
- packed = control->reqseq << L2CAP_CTRL_REQSEQ_SHIFT;
|
|
|
|
- packed |= control->final << L2CAP_CTRL_FINAL_SHIFT;
|
|
|
|
-
|
|
|
|
- if (control->sframe) {
|
|
|
|
- packed |= control->poll << L2CAP_CTRL_POLL_SHIFT;
|
|
|
|
- packed |= control->super << L2CAP_CTRL_SUPER_SHIFT;
|
|
|
|
- packed |= L2CAP_CTRL_FRAME_TYPE;
|
|
|
|
- } else {
|
|
|
|
- packed |= control->sar << L2CAP_CTRL_SAR_SHIFT;
|
|
|
|
- packed |= control->txseq << L2CAP_CTRL_TXSEQ_SHIFT;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return packed;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
static void __unpack_enhanced_control(u16 enh, struct l2cap_ctrl *control)
|
|
static void __unpack_enhanced_control(u16 enh, struct l2cap_ctrl *control)
|
|
{
|
|
{
|
|
control->reqseq = (enh & L2CAP_CTRL_REQSEQ) >> L2CAP_CTRL_REQSEQ_SHIFT;
|
|
control->reqseq = (enh & L2CAP_CTRL_REQSEQ) >> L2CAP_CTRL_REQSEQ_SHIFT;
|
|
@@ -829,25 +748,6 @@ static void __unpack_enhanced_control(u16 enh, struct l2cap_ctrl *control)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-static u32 __pack_extended_control(struct l2cap_ctrl *control)
|
|
|
|
-{
|
|
|
|
- u32 packed;
|
|
|
|
-
|
|
|
|
- packed = control->reqseq << L2CAP_EXT_CTRL_REQSEQ_SHIFT;
|
|
|
|
- packed |= control->final << L2CAP_EXT_CTRL_FINAL_SHIFT;
|
|
|
|
-
|
|
|
|
- if (control->sframe) {
|
|
|
|
- packed |= control->poll << L2CAP_EXT_CTRL_POLL_SHIFT;
|
|
|
|
- packed |= control->super << L2CAP_EXT_CTRL_SUPER_SHIFT;
|
|
|
|
- packed |= L2CAP_EXT_CTRL_FRAME_TYPE;
|
|
|
|
- } else {
|
|
|
|
- packed |= control->sar << L2CAP_EXT_CTRL_SAR_SHIFT;
|
|
|
|
- packed |= control->txseq << L2CAP_EXT_CTRL_TXSEQ_SHIFT;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return packed;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
static void __unpack_extended_control(u32 ext, struct l2cap_ctrl *control)
|
|
static void __unpack_extended_control(u32 ext, struct l2cap_ctrl *control)
|
|
{
|
|
{
|
|
control->reqseq = (ext & L2CAP_EXT_CTRL_REQSEQ) >> L2CAP_EXT_CTRL_REQSEQ_SHIFT;
|
|
control->reqseq = (ext & L2CAP_EXT_CTRL_REQSEQ) >> L2CAP_EXT_CTRL_REQSEQ_SHIFT;
|
|
@@ -884,6 +784,44 @@ static inline void __unpack_control(struct l2cap_chan *chan,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static u32 __pack_extended_control(struct l2cap_ctrl *control)
|
|
|
|
+{
|
|
|
|
+ u32 packed;
|
|
|
|
+
|
|
|
|
+ packed = control->reqseq << L2CAP_EXT_CTRL_REQSEQ_SHIFT;
|
|
|
|
+ packed |= control->final << L2CAP_EXT_CTRL_FINAL_SHIFT;
|
|
|
|
+
|
|
|
|
+ if (control->sframe) {
|
|
|
|
+ packed |= control->poll << L2CAP_EXT_CTRL_POLL_SHIFT;
|
|
|
|
+ packed |= control->super << L2CAP_EXT_CTRL_SUPER_SHIFT;
|
|
|
|
+ packed |= L2CAP_EXT_CTRL_FRAME_TYPE;
|
|
|
|
+ } else {
|
|
|
|
+ packed |= control->sar << L2CAP_EXT_CTRL_SAR_SHIFT;
|
|
|
|
+ packed |= control->txseq << L2CAP_EXT_CTRL_TXSEQ_SHIFT;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return packed;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static u16 __pack_enhanced_control(struct l2cap_ctrl *control)
|
|
|
|
+{
|
|
|
|
+ u16 packed;
|
|
|
|
+
|
|
|
|
+ packed = control->reqseq << L2CAP_CTRL_REQSEQ_SHIFT;
|
|
|
|
+ packed |= control->final << L2CAP_CTRL_FINAL_SHIFT;
|
|
|
|
+
|
|
|
|
+ if (control->sframe) {
|
|
|
|
+ packed |= control->poll << L2CAP_CTRL_POLL_SHIFT;
|
|
|
|
+ packed |= control->super << L2CAP_CTRL_SUPER_SHIFT;
|
|
|
|
+ packed |= L2CAP_CTRL_FRAME_TYPE;
|
|
|
|
+ } else {
|
|
|
|
+ packed |= control->sar << L2CAP_CTRL_SAR_SHIFT;
|
|
|
|
+ packed |= control->txseq << L2CAP_CTRL_TXSEQ_SHIFT;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return packed;
|
|
|
|
+}
|
|
|
|
+
|
|
static inline void __pack_control(struct l2cap_chan *chan,
|
|
static inline void __pack_control(struct l2cap_chan *chan,
|
|
struct l2cap_ctrl *control,
|
|
struct l2cap_ctrl *control,
|
|
struct sk_buff *skb)
|
|
struct sk_buff *skb)
|
|
@@ -897,6 +835,68 @@ static inline void __pack_control(struct l2cap_chan *chan,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static inline void l2cap_send_sframe(struct l2cap_chan *chan, u32 control)
|
|
|
|
+{
|
|
|
|
+ struct sk_buff *skb;
|
|
|
|
+ struct l2cap_hdr *lh;
|
|
|
|
+ struct l2cap_conn *conn = chan->conn;
|
|
|
|
+ int count, hlen;
|
|
|
|
+
|
|
|
|
+ if (chan->state != BT_CONNECTED)
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ if (test_bit(FLAG_EXT_CTRL, &chan->flags))
|
|
|
|
+ hlen = L2CAP_EXT_HDR_SIZE;
|
|
|
|
+ else
|
|
|
|
+ hlen = L2CAP_ENH_HDR_SIZE;
|
|
|
|
+
|
|
|
|
+ if (chan->fcs == L2CAP_FCS_CRC16)
|
|
|
|
+ hlen += L2CAP_FCS_SIZE;
|
|
|
|
+
|
|
|
|
+ BT_DBG("chan %p, control 0x%8.8x", chan, control);
|
|
|
|
+
|
|
|
|
+ count = min_t(unsigned int, conn->mtu, hlen);
|
|
|
|
+
|
|
|
|
+ control |= __set_sframe(chan);
|
|
|
|
+
|
|
|
|
+ if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
|
|
|
|
+ control |= __set_ctrl_final(chan);
|
|
|
|
+
|
|
|
|
+ if (test_and_clear_bit(CONN_SEND_PBIT, &chan->conn_state))
|
|
|
|
+ control |= __set_ctrl_poll(chan);
|
|
|
|
+
|
|
|
|
+ skb = bt_skb_alloc(count, GFP_ATOMIC);
|
|
|
|
+ if (!skb)
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
|
|
|
|
+ lh->len = cpu_to_le16(hlen - L2CAP_HDR_SIZE);
|
|
|
|
+ lh->cid = cpu_to_le16(chan->dcid);
|
|
|
|
+
|
|
|
|
+ __put_control(chan, control, skb_put(skb, __ctrl_size(chan)));
|
|
|
|
+
|
|
|
|
+ if (chan->fcs == L2CAP_FCS_CRC16) {
|
|
|
|
+ u16 fcs = crc16(0, (u8 *)lh, count - L2CAP_FCS_SIZE);
|
|
|
|
+ put_unaligned_le16(fcs, skb_put(skb, L2CAP_FCS_SIZE));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ skb->priority = HCI_PRIO_MAX;
|
|
|
|
+ l2cap_do_send(chan, skb);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u32 control)
|
|
|
|
+{
|
|
|
|
+ if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
|
|
|
|
+ control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
|
|
|
|
+ set_bit(CONN_RNR_SENT, &chan->conn_state);
|
|
|
|
+ } else
|
|
|
|
+ control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
|
|
|
|
+
|
|
|
|
+ control |= __set_reqseq(chan, chan->buffer_seq);
|
|
|
|
+
|
|
|
|
+ l2cap_send_sframe(chan, control);
|
|
|
|
+}
|
|
|
|
+
|
|
static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan)
|
|
static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan)
|
|
{
|
|
{
|
|
return !test_bit(CONF_CONNECT_PEND, &chan->conf_state);
|
|
return !test_bit(CONF_CONNECT_PEND, &chan->conf_state);
|