skb->len is the wrong var to tell the size of a packet, skb->len keeps the
size of the overall skb, including its head and fragments, then when
sending the head the wrong size is passed if the we have a framented skb.
We fix this by using skb_datalen(skb) which is the total skb size minus
the fragments size, i.e., the actual head size.
This bug appeared when implementing MSG_MORE support for L2CAP sockets, it
never showed up before because l2cap_skbuff_fromiovec() never accounted skb
size correctly. A following patch will fix this.
Signed-off-by: Gustavo Padovan <[email protected]>
---
drivers/bluetooth/bluecard_cs.c | 5 +++--
drivers/bluetooth/bpa10x.c | 4 ++--
drivers/bluetooth/bt3c_cs.c | 4 ++--
drivers/bluetooth/btusb.c | 4 ++--
drivers/bluetooth/btwilink.c | 2 +-
drivers/bluetooth/dtl1_cs.c | 13 +++++++------
drivers/bluetooth/hci_bcsp.c | 8 ++++++--
drivers/bluetooth/hci_ldisc.c | 7 ++++---
drivers/bluetooth/hci_vhci.c | 2 +-
net/bluetooth/hci_core.c | 2 +-
10 files changed, 29 insertions(+), 22 deletions(-)
diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c
index 1fcd923..c64ee02 100644
--- a/drivers/bluetooth/bluecard_cs.c
+++ b/drivers/bluetooth/bluecard_cs.c
@@ -270,7 +270,8 @@ static void bluecard_write_wakeup(bluecard_info_t *info)
bluecard_enable_activity_led(info);
/* Send frame */
- len = bluecard_write(iobase, offset, skb->data, skb->len);
+ len = bluecard_write(iobase, offset, skb->data,
+ skb_headlen(skb));
/* Tell the FPGA to send the data */
outb_p(command, iobase + REG_COMMAND);
@@ -321,7 +322,7 @@ static void bluecard_write_wakeup(bluecard_info_t *info)
finish_wait(&wq, &wait);
}
- if (len == skb->len) {
+ if (len == skb_headlen(skb)) {
kfree_skb(skb);
} else {
skb_pull(skb, len);
diff --git a/drivers/bluetooth/bpa10x.c b/drivers/bluetooth/bpa10x.c
index d894340..c09f29f 100644
--- a/drivers/bluetooth/bpa10x.c
+++ b/drivers/bluetooth/bpa10x.c
@@ -398,8 +398,8 @@ static int bpa10x_send_frame(struct sk_buff *skb)
case HCI_ACLDATA_PKT:
pipe = usb_sndbulkpipe(data->udev, 0x02);
- usb_fill_bulk_urb(urb, data->udev, pipe,
- skb->data, skb->len, bpa10x_tx_complete, skb);
+ usb_fill_bulk_urb(urb, data->udev, pipe, skb->data,
+ skb_headlen(skb), bpa10x_tx_complete, skb);
hdev->stat.acl_tx++;
break;
diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c
index 308c859..b19d134 100644
--- a/drivers/bluetooth/bt3c_cs.c
+++ b/drivers/bluetooth/bt3c_cs.c
@@ -200,9 +200,9 @@ static void bt3c_write_wakeup(bt3c_info_t *info)
}
/* Send frame */
- len = bt3c_write(iobase, 256, skb->data, skb->len);
+ len = bt3c_write(iobase, 256, skb->data, skb_headlen(skb));
- if (len != skb->len) {
+ if (len != skb_headlen(skb)) {
BT_ERR("Very strange");
}
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index cb480f1..0e3ec17 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -739,8 +739,8 @@ static int btusb_send_frame(struct sk_buff *skb)
pipe = usb_sndbulkpipe(data->udev,
data->bulk_tx_ep->bEndpointAddress);
- usb_fill_bulk_urb(urb, data->udev, pipe,
- skb->data, skb->len, btusb_tx_complete, skb);
+ usb_fill_bulk_urb(urb, data->udev, pipe, skb->data,
+ skb_headlen(skb), btusb_tx_complete, skb);
hdev->stat.acl_tx++;
break;
diff --git a/drivers/bluetooth/btwilink.c b/drivers/bluetooth/btwilink.c
index 8869469..3929eff 100644
--- a/drivers/bluetooth/btwilink.c
+++ b/drivers/bluetooth/btwilink.c
@@ -270,7 +270,7 @@ static int ti_st_send_frame(struct sk_buff *skb)
memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
BT_DBG("%s: type %d len %d", hdev->name, bt_cb(skb)->pkt_type,
- skb->len);
+ skb_headlen(skb));
/* Insert skb to shared transport layer's transmit queue.
* Freeing skb memory is taken care in shared transport layer,
diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c
index 6e8d961..92e520c 100644
--- a/drivers/bluetooth/dtl1_cs.c
+++ b/drivers/bluetooth/dtl1_cs.c
@@ -157,9 +157,9 @@ static void dtl1_write_wakeup(dtl1_info_t *info)
break;
/* Send frame */
- len = dtl1_write(iobase, 32, skb->data, skb->len);
+ len = dtl1_write(iobase, 32, skb->data, skb_headlen(skb));
- if (len == skb->len) {
+ if (len == skb_headlen(skb)) {
set_bit(XMIT_WAITING, &(info->tx_state));
kfree_skb(skb);
} else {
@@ -389,6 +389,7 @@ static int dtl1_hci_send_frame(struct sk_buff *skb)
struct hci_dev *hdev = (struct hci_dev *)(skb->dev);
struct sk_buff *s;
nsh_t nsh;
+ int len = skb_headlen(skb);
if (!hdev) {
BT_ERR("Frame for unknown HCI device (hdev=NULL)");
@@ -415,15 +416,15 @@ static int dtl1_hci_send_frame(struct sk_buff *skb)
};
nsh.zero = 0;
- nsh.len = skb->len;
+ nsh.len = len;
- s = bt_skb_alloc(NSHL + skb->len + 1, GFP_ATOMIC);
+ s = bt_skb_alloc(NSHL + len + 1, GFP_ATOMIC);
if (!s)
return -ENOMEM;
skb_reserve(s, NSHL);
- skb_copy_from_linear_data(skb, skb_put(s, skb->len), skb->len);
- if (skb->len & 0x0001)
+ skb_copy_from_linear_data(skb, skb_put(s, len), len);
+ if (len & 0x0001)
*skb_put(s, 1) = 0; /* PAD */
/* Prepend skb with Nokia frame header and queue */
diff --git a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c
index 661a8dc..64a69fa 100644
--- a/drivers/bluetooth/hci_bcsp.c
+++ b/drivers/bluetooth/hci_bcsp.c
@@ -292,7 +292,9 @@ static struct sk_buff *bcsp_dequeue(struct hci_uart *hu)
since they have priority */
if ((skb = skb_dequeue(&bcsp->unrel)) != NULL) {
- struct sk_buff *nskb = bcsp_prepare_pkt(bcsp, skb->data, skb->len, bt_cb(skb)->pkt_type);
+ struct sk_buff *nskb = bcsp_prepare_pkt(bcsp, skb->data,
+ skb_headlen(skb),
+ bt_cb(skb)->pkt_type);
if (nskb) {
kfree_skb(skb);
return nskb;
@@ -309,7 +311,9 @@ static struct sk_buff *bcsp_dequeue(struct hci_uart *hu)
spin_lock_irqsave_nested(&bcsp->unack.lock, flags, SINGLE_DEPTH_NESTING);
if (bcsp->unack.qlen < BCSP_TXWINSIZE && (skb = skb_dequeue(&bcsp->rel)) != NULL) {
- struct sk_buff *nskb = bcsp_prepare_pkt(bcsp, skb->data, skb->len, bt_cb(skb)->pkt_type);
+ struct sk_buff *nskb = bcsp_prepare_pkt(bcsp, skb->data,
+ skb_headlen(skb),
+ bt_cb(skb)->pkt_type);
if (nskb) {
__skb_queue_tail(&bcsp->unack, skb);
mod_timer(&bcsp->tbcsp, jiffies + HZ / 4);
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index e564579..f6d551d 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -136,11 +136,11 @@ restart:
int len;
set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
- len = tty->ops->write(tty, skb->data, skb->len);
+ len = tty->ops->write(tty, skb->data, skb_headlen(skb));
hdev->stat.byte_tx += len;
skb_pull(skb, len);
- if (skb->len) {
+ if (skb_headlen(skb)) {
hu->tx_skb = skb;
break;
}
@@ -220,7 +220,8 @@ static int hci_uart_send_frame(struct sk_buff *skb)
hu = hci_get_drvdata(hdev);
- BT_DBG("%s: type %d len %d", hdev->name, bt_cb(skb)->pkt_type, skb->len);
+ BT_DBG("%s: type %d len %d", hdev->name, bt_cb(skb)->pkt_type,
+ skb_headlen(skb));
hu->proto->enqueue(hu, skb);
diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c
index 3f72595..1381511 100644
--- a/drivers/bluetooth/hci_vhci.c
+++ b/drivers/bluetooth/hci_vhci.c
@@ -135,7 +135,7 @@ static inline ssize_t vhci_put_user(struct vhci_data *data,
char __user *ptr = buf;
int len, total = 0;
- len = min_t(unsigned int, skb->len, count);
+ len = min_t(unsigned int, skb_headlen(skb), count);
if (copy_to_user(ptr, skb->data, len))
return -EFAULT;
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index a492b374..f8d5b8d 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -2147,7 +2147,7 @@ void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode)
static void hci_add_acl_hdr(struct sk_buff *skb, __u16 handle, __u16 flags)
{
struct hci_acl_hdr *hdr;
- int len = skb->len;
+ int len = skb_headlen(skb);
skb_push(skb, HCI_ACL_HDR_SIZE);
skb_reset_transport_header(skb);
--
1.7.10.1
Gustavo -
On Wed, 9 May 2012, Gustavo Padovan wrote:
> Hi Mat,
>
> * Mat Martineau <[email protected]> [2012-05-09 09:27:18 -0700]:
>
>>
>> Hi Gustavo -
>>
>> On Wed, 9 May 2012, Gustavo Padovan wrote:
>>
>>> When we add a fragment to a skb, len, data_len and truesize fields needs
>>> to be updated.
>>>
>>> Signed-off-by: Gustavo Padovan <[email protected]>
>>> ---
>>> net/bluetooth/l2cap_core.c | 4 ++++
>>> 1 file changed, 4 insertions(+)
>>>
>>> diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
>>> index 66a1a55..8d7c6ba 100644
>>> --- a/net/bluetooth/l2cap_core.c
>>> +++ b/net/bluetooth/l2cap_core.c
>>> @@ -1851,6 +1851,10 @@ static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan,
>>> sent += count;
>>> len -= count;
>>>
>>> + skb->len += (*frag)->len;
>>> + skb->data_len += (*frag)->len;
>>> + skb->truesize += (*frag)->truesize;
>>> +
>>> frag = &(*frag)->next;
>>> }
>>>
>>> --
>>> 1.7.10.1
>>
>> Good to hear that MSG_MORE support is in progress! Is this change
>> necessary to support MSG_MORE, or is it only something you noticed
>> while working on that feature?
>
> Yes, it is needed for MSG_MORE, I need to do proper accounting of
> the total skb size(skb->len) and its framents(skb->data_len)
Right - so you can check the outgoing MTU size with skb->len while you
incrementally build the SDU.
>>
>> I think this patch breaks SO_SNDBUF accounting, which uses
>> skb->truesize in the sock_wfree() destructor.
>
> If set truesize here is problem when we call the destructor I can
> get ride of the truesize calculation here, only len and data_len is
> enough for me.
It seems like that would work, and also is better in error cases where
the skb is freed before it gets to hci_queue_acl().
>>
>> For outgoing packets, L2CAP and HCI currently use skb fragments in a
>> non-standard way. The &skb_shinfo(skb)->frag_list and skb->next
>> pointers are used to group HCI fragments so they are placed in the
>> HCI send queue all at once. But they are *not* intended to
>> represent a "normal" fragmented skb.
>
> Yes and I don't have this intention, I just want to report the
> proper skb length to controller and acl headers.
>
>>
>> Once the list of skbs is passed to hci_send_acl(), hci_queue_acl()
>> separates all of the linked skbs before being placing them in the
>> HCI chan->data_q. Since the driver sees packets coming out of
>> chan->data_q, it only sees unfragmented skbs. If you change
>> skb->truesize on the first HCI fragment, sk->sk_wmem_alloc will be
>> adjusted for the bytes used by that first fragment plus the bytes
>> used by all of the continuation fragments. However, all of the
>> later continuation fragments will adjust sk->sk_wmem_alloc too!
>>
>>
>> There are other problems due to the non-standard use of skb
>> fragments by HCI and L2CAP. One is that it is confusing, and makes
>> changes that *should* work (like this one) instead cause breakage.
>>
>> The big problem is that the skb->next pointer is used for both skb
>> queuing and skb fragment lists. On top of that, skb clones share
>> the &skb_shinfo(skb)->frag_list pointer - so the continuation
>> fragments and their 'next' pointers are also shared between clones!
>> When hci_queue_acl() puts each fragment in the chan->data_q, the
>> skb->next pointers of the fragments are overwritten. If there is a
>> clone of the head skb in another queue (like the ERTM tx queue), its
>> fragments get corrupted. This is why ERTM PDUs must fit in a single
>> HCI fragment, so that no fragment lists are included in the ERTM tx
>> queue. Some devices (especially USB) have very short HCI MTUs,
>> which makes ERTM much less efficient on those devices.
>>
>>
>> I see these options:
>>
>> * Add comments to explain non-standard use of skb fragments
>>
>> * Keep your change above, but also modify hci_queue_acl() to
>> rewrite the len, data_len, and truesize values of the head skb
>> before queueing it.
>
> I think len and data_len is enough, we don't need to touch truesize
> here. Then on hci_queue_acl() we just set skb->len to skb_headlen()
> and skb->data_len to 0. That fixes everything and no modification on
> drivers will be needed.
Ok. A few comments where skb->len and skb->data_len are adjusted
would also be great so we don't all forget what is going on!
--
Mat Martineau
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum
Hi Mat,
* Mat Martineau <[email protected]> [2012-05-09 09:27:18 -0700]:
>
> Hi Gustavo -
>
> On Wed, 9 May 2012, Gustavo Padovan wrote:
>
> >When we add a fragment to a skb, len, data_len and truesize fields needs
> >to be updated.
> >
> >Signed-off-by: Gustavo Padovan <[email protected]>
> >---
> >net/bluetooth/l2cap_core.c | 4 ++++
> >1 file changed, 4 insertions(+)
> >
> >diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
> >index 66a1a55..8d7c6ba 100644
> >--- a/net/bluetooth/l2cap_core.c
> >+++ b/net/bluetooth/l2cap_core.c
> >@@ -1851,6 +1851,10 @@ static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan,
> > sent += count;
> > len -= count;
> >
> >+ skb->len += (*frag)->len;
> >+ skb->data_len += (*frag)->len;
> >+ skb->truesize += (*frag)->truesize;
> >+
> > frag = &(*frag)->next;
> > }
> >
> >--
> >1.7.10.1
>
> Good to hear that MSG_MORE support is in progress! Is this change
> necessary to support MSG_MORE, or is it only something you noticed
> while working on that feature?
Yes, it is needed for MSG_MORE, I need to do proper accounting of the total
skb size(skb->len) and its framents(skb->data_len)
>
> I think this patch breaks SO_SNDBUF accounting, which uses
> skb->truesize in the sock_wfree() destructor.
If set truesize here is problem when we call the destructor I can get ride of
the truesize calculation here, only len and data_len is enough for me.
>
> For outgoing packets, L2CAP and HCI currently use skb fragments in a
> non-standard way. The &skb_shinfo(skb)->frag_list and skb->next
> pointers are used to group HCI fragments so they are placed in the
> HCI send queue all at once. But they are *not* intended to
> represent a "normal" fragmented skb.
Yes and I don't have this intention, I just want to report the proper skb
length to controller and acl headers.
>
> Once the list of skbs is passed to hci_send_acl(), hci_queue_acl()
> separates all of the linked skbs before being placing them in the
> HCI chan->data_q. Since the driver sees packets coming out of
> chan->data_q, it only sees unfragmented skbs. If you change
> skb->truesize on the first HCI fragment, sk->sk_wmem_alloc will be
> adjusted for the bytes used by that first fragment plus the bytes
> used by all of the continuation fragments. However, all of the
> later continuation fragments will adjust sk->sk_wmem_alloc too!
>
>
> There are other problems due to the non-standard use of skb
> fragments by HCI and L2CAP. One is that it is confusing, and makes
> changes that *should* work (like this one) instead cause breakage.
>
> The big problem is that the skb->next pointer is used for both skb
> queuing and skb fragment lists. On top of that, skb clones share
> the &skb_shinfo(skb)->frag_list pointer - so the continuation
> fragments and their 'next' pointers are also shared between clones!
> When hci_queue_acl() puts each fragment in the chan->data_q, the
> skb->next pointers of the fragments are overwritten. If there is a
> clone of the head skb in another queue (like the ERTM tx queue), its
> fragments get corrupted. This is why ERTM PDUs must fit in a single
> HCI fragment, so that no fragment lists are included in the ERTM tx
> queue. Some devices (especially USB) have very short HCI MTUs,
> which makes ERTM much less efficient on those devices.
>
>
> I see these options:
>
> * Add comments to explain non-standard use of skb fragments
>
> * Keep your change above, but also modify hci_queue_acl() to
> rewrite the len, data_len, and truesize values of the head skb
> before queueing it.
I think len and data_len is enough, we don't need to touch truesize here. Then
on hci_queue_acl() we just set skb->len to skb_headlen() and skb->data_len to
0. That fixes everything and no modification on drivers will be needed.
Gustavo
Hi Gustavo -
On Wed, 9 May 2012, Gustavo Padovan wrote:
> When we add a fragment to a skb, len, data_len and truesize fields needs
> to be updated.
>
> Signed-off-by: Gustavo Padovan <[email protected]>
> ---
> net/bluetooth/l2cap_core.c | 4 ++++
> 1 file changed, 4 insertions(+)
>
> diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
> index 66a1a55..8d7c6ba 100644
> --- a/net/bluetooth/l2cap_core.c
> +++ b/net/bluetooth/l2cap_core.c
> @@ -1851,6 +1851,10 @@ static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan,
> sent += count;
> len -= count;
>
> + skb->len += (*frag)->len;
> + skb->data_len += (*frag)->len;
> + skb->truesize += (*frag)->truesize;
> +
> frag = &(*frag)->next;
> }
>
> --
> 1.7.10.1
Good to hear that MSG_MORE support is in progress! Is this change
necessary to support MSG_MORE, or is it only something you noticed
while working on that feature?
I think this patch breaks SO_SNDBUF accounting, which uses
skb->truesize in the sock_wfree() destructor.
For outgoing packets, L2CAP and HCI currently use skb fragments in a
non-standard way. The &skb_shinfo(skb)->frag_list and skb->next
pointers are used to group HCI fragments so they are placed in the HCI
send queue all at once. But they are *not* intended to represent a
"normal" fragmented skb.
Once the list of skbs is passed to hci_send_acl(), hci_queue_acl()
separates all of the linked skbs before being placing them in the HCI
chan->data_q. Since the driver sees packets coming out of
chan->data_q, it only sees unfragmented skbs. If you change
skb->truesize on the first HCI fragment, sk->sk_wmem_alloc will be
adjusted for the bytes used by that first fragment plus the bytes used
by all of the continuation fragments. However, all of the later
continuation fragments will adjust sk->sk_wmem_alloc too!
There are other problems due to the non-standard use of skb fragments
by HCI and L2CAP. One is that it is confusing, and makes changes that
*should* work (like this one) instead cause breakage.
The big problem is that the skb->next pointer is used for both skb
queuing and skb fragment lists. On top of that, skb clones share the
&skb_shinfo(skb)->frag_list pointer - so the continuation fragments
and their 'next' pointers are also shared between clones! When
hci_queue_acl() puts each fragment in the chan->data_q, the skb->next
pointers of the fragments are overwritten. If there is a clone of the
head skb in another queue (like the ERTM tx queue), its fragments get
corrupted. This is why ERTM PDUs must fit in a single HCI fragment,
so that no fragment lists are included in the ERTM tx queue. Some
devices (especially USB) have very short HCI MTUs, which makes ERTM
much less efficient on those devices.
I see these options:
* Add comments to explain non-standard use of skb fragments
* Keep your change above, but also modify hci_queue_acl() to rewrite
the len, data_len, and truesize values of the head skb before queueing
it.
* Try to find a different way to represent HCI fragments that fits
with standard skb usage and interacts better with ERTM tx queues.
What sounds good to you?
--
Mat Martineau
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum
Gustavo -
On Wed, 9 May 2012, Gustavo Padovan wrote:
> skb->len is the wrong var to tell the size of a packet, skb->len keeps the
> size of the overall skb, including its head and fragments, then when
> sending the head the wrong size is passed if the we have a framented skb.
> We fix this by using skb_datalen(skb) which is the total skb size minus
> the fragments size, i.e., the actual head size.
>
> This bug appeared when implementing MSG_MORE support for L2CAP sockets, it
> never showed up before because l2cap_skbuff_fromiovec() never accounted skb
> size correctly. A following patch will fix this.
>
> Signed-off-by: Gustavo Padovan <[email protected]>
> ---
> drivers/bluetooth/bluecard_cs.c | 5 +++--
> drivers/bluetooth/bpa10x.c | 4 ++--
> drivers/bluetooth/bt3c_cs.c | 4 ++--
> drivers/bluetooth/btusb.c | 4 ++--
> drivers/bluetooth/btwilink.c | 2 +-
> drivers/bluetooth/dtl1_cs.c | 13 +++++++------
> drivers/bluetooth/hci_bcsp.c | 8 ++++++--
> drivers/bluetooth/hci_ldisc.c | 7 ++++---
> drivers/bluetooth/hci_vhci.c | 2 +-
> net/bluetooth/hci_core.c | 2 +-
> 10 files changed, 29 insertions(+), 22 deletions(-)
The drivers should never see fragmented skbs, so this change should
not be necessary. See my reply to the next patch for the full
background information.
--
Mat Martineau
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum
When we add a fragment to a skb, len, data_len and truesize fields needs
to be updated.
Signed-off-by: Gustavo Padovan <[email protected]>
---
net/bluetooth/l2cap_core.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 66a1a55..8d7c6ba 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -1851,6 +1851,10 @@ static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan,
sent += count;
len -= count;
+ skb->len += (*frag)->len;
+ skb->data_len += (*frag)->len;
+ skb->truesize += (*frag)->truesize;
+
frag = &(*frag)->next;
}
--
1.7.10.1