diff mbox

[wpan] net: ieee802154: 6lowpan: fix frag reassembly

Message ID 20180420185413.8818-1-aring@mojatatu.com (mailing list archive)
State Accepted
Headers show

Commit Message

Alexander Aring April 20, 2018, 6:54 p.m. UTC
This patch initialize stack variables which are used in
frag_lowpan_compare_key to zero. In my case there are padding bytes in the
structures ieee802154_addr as well in frag_lowpan_compare_key. Otherwise
the key variable contains random bytes. The result is that a compare of
two keys by memcmp works incorrect.

Fixes: 648700f76b03 ("inet: frags: use rhashtables for reassembly units")
Signed-off-by: Alexander Aring <aring@mojatatu.com>
Reported-by: Stefan Schmidt <stefan@osg.samsung.com>
---
So far I see it's a case of 32 alignment in frag_v4_compare_key and
frag_v6_compare_key and I am not sure about if this works on all arch
correctly.

 net/ieee802154/6lowpan/6lowpan_i.h  |  4 ++--
 net/ieee802154/6lowpan/reassembly.c | 14 +++++++-------
 2 files changed, 9 insertions(+), 9 deletions(-)

Comments

Stefan Schmidt April 20, 2018, 9:07 p.m. UTC | #1
Hello.


On 04/20/2018 08:54 PM, Alexander Aring wrote:
> This patch initialize stack variables which are used in
> frag_lowpan_compare_key to zero. In my case there are padding bytes in the
> structures ieee802154_addr as well in frag_lowpan_compare_key. Otherwise
> the key variable contains random bytes. The result is that a compare of
> two keys by memcmp works incorrect.
>
> Fixes: 648700f76b03 ("inet: frags: use rhashtables for reassembly units")
> Signed-off-by: Alexander Aring <aring@mojatatu.com>
> Reported-by: Stefan Schmidt <stefan@osg.samsung.com>

Thanks for having another attempt on this. I dropped the __packed patch you sent earlier.

Giving this some more testing with SSH and large ping packets and it is as stable again as before.

Eric, you did the original change so let me know if you have a problem with this.


> ---
> So far I see it's a case of 32 alignment in frag_v4_compare_key and
> frag_v6_compare_key and I am not sure about if this works on all arch
> correctly.
>
>  net/ieee802154/6lowpan/6lowpan_i.h  |  4 ++--
>  net/ieee802154/6lowpan/reassembly.c | 14 +++++++-------
>  2 files changed, 9 insertions(+), 9 deletions(-)
>
> diff --git a/net/ieee802154/6lowpan/6lowpan_i.h b/net/ieee802154/6lowpan/6lowpan_i.h
> index b8d95cb71c25..44a7e16bf3b5 100644
> --- a/net/ieee802154/6lowpan/6lowpan_i.h
> +++ b/net/ieee802154/6lowpan/6lowpan_i.h
> @@ -20,8 +20,8 @@ typedef unsigned __bitwise lowpan_rx_result;
>  struct frag_lowpan_compare_key {
>  	u16 tag;
>  	u16 d_size;
> -	const struct ieee802154_addr src;
> -	const struct ieee802154_addr dst;
> +	struct ieee802154_addr src;
> +	struct ieee802154_addr dst;
>  };
>  
>  /* Equivalent of ipv4 struct ipq
> diff --git a/net/ieee802154/6lowpan/reassembly.c b/net/ieee802154/6lowpan/reassembly.c
> index 1790b65944b3..2cc224106b69 100644
> --- a/net/ieee802154/6lowpan/reassembly.c
> +++ b/net/ieee802154/6lowpan/reassembly.c
> @@ -75,14 +75,14 @@ fq_find(struct net *net, const struct lowpan_802154_cb *cb,
>  {
>  	struct netns_ieee802154_lowpan *ieee802154_lowpan =
>  		net_ieee802154_lowpan(net);
> -	struct frag_lowpan_compare_key key = {
> -		.tag = cb->d_tag,
> -		.d_size = cb->d_size,
> -		.src = *src,
> -		.dst = *dst,
> -	};
> +	struct frag_lowpan_compare_key key = {};
>  	struct inet_frag_queue *q;
>  
> +	key.tag = cb->d_tag;
> +	key.d_size = cb->d_size;
> +	key.src = *src;
> +	key.dst = *dst;
> +
>  	q = inet_frag_find(&ieee802154_lowpan->frags, &key);
>  	if (!q)
>  		return NULL;
> @@ -372,7 +372,7 @@ int lowpan_frag_rcv(struct sk_buff *skb, u8 frag_type)
>  	struct lowpan_frag_queue *fq;
>  	struct net *net = dev_net(skb->dev);
>  	struct lowpan_802154_cb *cb = lowpan_802154_cb(skb);
> -	struct ieee802154_hdr hdr;
> +	struct ieee802154_hdr hdr = {};
>  	int err;
>  
>  	if (ieee802154_hdr_peek_addrs(skb, &hdr) < 0)

regards
Stefan Schmidt

--
To unsubscribe from this list: send the line "unsubscribe linux-wpan" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Stefan Schmidt April 23, 2018, 7:07 p.m. UTC | #2
Hello.


On 04/20/2018 08:54 PM, Alexander Aring wrote:
> This patch initialize stack variables which are used in
> frag_lowpan_compare_key to zero. In my case there are padding bytes in the
> structures ieee802154_addr as well in frag_lowpan_compare_key. Otherwise
> the key variable contains random bytes. The result is that a compare of
> two keys by memcmp works incorrect.
>
> Fixes: 648700f76b03 ("inet: frags: use rhashtables for reassembly units")
> Signed-off-by: Alexander Aring <aring@mojatatu.com>
> Reported-by: Stefan Schmidt <stefan@osg.samsung.com>
> ---
> So far I see it's a case of 32 alignment in frag_v4_compare_key and
> frag_v6_compare_key and I am not sure about if this works on all arch
> correctly.
>
>  net/ieee802154/6lowpan/6lowpan_i.h  |  4 ++--
>  net/ieee802154/6lowpan/reassembly.c | 14 +++++++-------
>  2 files changed, 9 insertions(+), 9 deletions(-)
>
> diff --git a/net/ieee802154/6lowpan/6lowpan_i.h b/net/ieee802154/6lowpan/6lowpan_i.h
> index b8d95cb71c25..44a7e16bf3b5 100644
> --- a/net/ieee802154/6lowpan/6lowpan_i.h
> +++ b/net/ieee802154/6lowpan/6lowpan_i.h
> @@ -20,8 +20,8 @@ typedef unsigned __bitwise lowpan_rx_result;
>  struct frag_lowpan_compare_key {
>  	u16 tag;
>  	u16 d_size;
> -	const struct ieee802154_addr src;
> -	const struct ieee802154_addr dst;
> +	struct ieee802154_addr src;
> +	struct ieee802154_addr dst;
>  };
>  
>  /* Equivalent of ipv4 struct ipq
> diff --git a/net/ieee802154/6lowpan/reassembly.c b/net/ieee802154/6lowpan/reassembly.c
> index 1790b65944b3..2cc224106b69 100644
> --- a/net/ieee802154/6lowpan/reassembly.c
> +++ b/net/ieee802154/6lowpan/reassembly.c
> @@ -75,14 +75,14 @@ fq_find(struct net *net, const struct lowpan_802154_cb *cb,
>  {
>  	struct netns_ieee802154_lowpan *ieee802154_lowpan =
>  		net_ieee802154_lowpan(net);
> -	struct frag_lowpan_compare_key key = {
> -		.tag = cb->d_tag,
> -		.d_size = cb->d_size,
> -		.src = *src,
> -		.dst = *dst,
> -	};
> +	struct frag_lowpan_compare_key key = {};
>  	struct inet_frag_queue *q;
>  
> +	key.tag = cb->d_tag;
> +	key.d_size = cb->d_size;
> +	key.src = *src;
> +	key.dst = *dst;
> +
>  	q = inet_frag_find(&ieee802154_lowpan->frags, &key);
>  	if (!q)
>  		return NULL;
> @@ -372,7 +372,7 @@ int lowpan_frag_rcv(struct sk_buff *skb, u8 frag_type)
>  	struct lowpan_frag_queue *fq;
>  	struct net *net = dev_net(skb->dev);
>  	struct lowpan_802154_cb *cb = lowpan_802154_cb(skb);
> -	struct ieee802154_hdr hdr;
> +	struct ieee802154_hdr hdr = {};
>  	int err;
>  
>  	if (ieee802154_hdr_peek_addrs(skb, &hdr) < 0)

This patch has been applied to the wpan tree and will be
part of the next pull request to net. Thanks!

regards
Stefan Schmidt
--
To unsubscribe from this list: send the line "unsubscribe linux-wpan" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Eric Dumazet April 24, 2018, 12:11 a.m. UTC | #3
On 04/20/2018 11:54 AM, Alexander Aring wrote:
> This patch initialize stack variables which are used in
> frag_lowpan_compare_key to zero. In my case there are padding bytes in the
> structures ieee802154_addr as well in frag_lowpan_compare_key. Otherwise
> the key variable contains random bytes. The result is that a compare of
> two keys by memcmp works incorrect.
> 
> Fixes: 648700f76b03 ("inet: frags: use rhashtables for reassembly units")
> Signed-off-by: Alexander Aring <aring@mojatatu.com>
> Reported-by: Stefan Schmidt <stefan@osg.samsung.com>
> ---
> So far I see it's a case of 32 alignment in frag_v4_compare_key and
> frag_v6_compare_key and I am not sure about if this works on all arch
> correctly.
> 
>  net/ieee802154/6lowpan/6lowpan_i.h  |  4 ++--
>  net/ieee802154/6lowpan/reassembly.c | 14 +++++++-------
>  2 files changed, 9 insertions(+), 9 deletions(-)
> 
> diff --git a/net/ieee802154/6lowpan/6lowpan_i.h b/net/ieee802154/6lowpan/6lowpan_i.h
> index b8d95cb71c25..44a7e16bf3b5 100644
> --- a/net/ieee802154/6lowpan/6lowpan_i.h
> +++ b/net/ieee802154/6lowpan/6lowpan_i.h
> @@ -20,8 +20,8 @@ typedef unsigned __bitwise lowpan_rx_result;
>  struct frag_lowpan_compare_key {
>  	u16 tag;
>  	u16 d_size;
> -	const struct ieee802154_addr src;
> -	const struct ieee802154_addr dst;
> +	struct ieee802154_addr src;
> +	struct ieee802154_addr dst;
>  };
>  
>  /* Equivalent of ipv4 struct ipq
> diff --git a/net/ieee802154/6lowpan/reassembly.c b/net/ieee802154/6lowpan/reassembly.c
> index 1790b65944b3..2cc224106b69 100644
> --- a/net/ieee802154/6lowpan/reassembly.c
> +++ b/net/ieee802154/6lowpan/reassembly.c
> @@ -75,14 +75,14 @@ fq_find(struct net *net, const struct lowpan_802154_cb *cb,
>  {
>  	struct netns_ieee802154_lowpan *ieee802154_lowpan =
>  		net_ieee802154_lowpan(net);
> -	struct frag_lowpan_compare_key key = {
> -		.tag = cb->d_tag,
> -		.d_size = cb->d_size,
> -		.src = *src,
> -		.dst = *dst,
> -	};
> +	struct frag_lowpan_compare_key key = {};
>  	struct inet_frag_queue *q;
>  
> +	key.tag = cb->d_tag;
> +	key.d_size = cb->d_size;
> +	key.src = *src;
> +	key.dst = *dst;
> +
>  	q = inet_frag_find(&ieee802154_lowpan->frags, &key);
>  	if (!q)
>  		return NULL;
> @@ -372,7 +372,7 @@ int lowpan_frag_rcv(struct sk_buff *skb, u8 frag_type)
>  	struct lowpan_frag_queue *fq;
>  	struct net *net = dev_net(skb->dev);
>  	struct lowpan_802154_cb *cb = lowpan_802154_cb(skb);
> -	struct ieee802154_hdr hdr;
> +	struct ieee802154_hdr hdr = {};
>  	int err;
>  
>  	if (ieee802154_hdr_peek_addrs(skb, &hdr) < 0)
> 

Hi Alexander.

Thanks for working on this !

It looks like only the last chunk was really needed to fix this bug, right ?

Compiler should really init everything, and not leave garbage bytes in :

	struct frag_lowpan_compare_key key = {
		.tag = cb->d_tag,
		.d_size = cb->d_size,
		.src = *src,
		.dst = *dst,
	};


--
To unsubscribe from this list: send the line "unsubscribe linux-wpan" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Alexander Aring April 25, 2018, 9:19 p.m. UTC | #4
Hi,

On Mon, Apr 23, 2018 at 05:11:39PM -0700, Eric Dumazet wrote:
> 
> 
> On 04/20/2018 11:54 AM, Alexander Aring wrote:
> > This patch initialize stack variables which are used in
> > frag_lowpan_compare_key to zero. In my case there are padding bytes in the
> > structures ieee802154_addr as well in frag_lowpan_compare_key. Otherwise
> > the key variable contains random bytes. The result is that a compare of
> > two keys by memcmp works incorrect.
> > 
> > Fixes: 648700f76b03 ("inet: frags: use rhashtables for reassembly units")
> > Signed-off-by: Alexander Aring <aring@mojatatu.com>
> > Reported-by: Stefan Schmidt <stefan@osg.samsung.com>
> > ---
> > So far I see it's a case of 32 alignment in frag_v4_compare_key and
> > frag_v6_compare_key and I am not sure about if this works on all arch
> > correctly.
> > 
> >  net/ieee802154/6lowpan/6lowpan_i.h  |  4 ++--
> >  net/ieee802154/6lowpan/reassembly.c | 14 +++++++-------
> >  2 files changed, 9 insertions(+), 9 deletions(-)
> > 
> > diff --git a/net/ieee802154/6lowpan/6lowpan_i.h b/net/ieee802154/6lowpan/6lowpan_i.h
> > index b8d95cb71c25..44a7e16bf3b5 100644
> > --- a/net/ieee802154/6lowpan/6lowpan_i.h
> > +++ b/net/ieee802154/6lowpan/6lowpan_i.h
> > @@ -20,8 +20,8 @@ typedef unsigned __bitwise lowpan_rx_result;
> >  struct frag_lowpan_compare_key {
> >  	u16 tag;
> >  	u16 d_size;
> > -	const struct ieee802154_addr src;
> > -	const struct ieee802154_addr dst;
> > +	struct ieee802154_addr src;
> > +	struct ieee802154_addr dst;
> >  };
> >  
> >  /* Equivalent of ipv4 struct ipq
> > diff --git a/net/ieee802154/6lowpan/reassembly.c b/net/ieee802154/6lowpan/reassembly.c
> > index 1790b65944b3..2cc224106b69 100644
> > --- a/net/ieee802154/6lowpan/reassembly.c
> > +++ b/net/ieee802154/6lowpan/reassembly.c
> > @@ -75,14 +75,14 @@ fq_find(struct net *net, const struct lowpan_802154_cb *cb,
> >  {
> >  	struct netns_ieee802154_lowpan *ieee802154_lowpan =
> >  		net_ieee802154_lowpan(net);
> > -	struct frag_lowpan_compare_key key = {
> > -		.tag = cb->d_tag,
> > -		.d_size = cb->d_size,
> > -		.src = *src,
> > -		.dst = *dst,
> > -	};
> > +	struct frag_lowpan_compare_key key = {};
> >  	struct inet_frag_queue *q;
> >  
> > +	key.tag = cb->d_tag;
> > +	key.d_size = cb->d_size;
> > +	key.src = *src;
> > +	key.dst = *dst;
> > +
> >  	q = inet_frag_find(&ieee802154_lowpan->frags, &key);
> >  	if (!q)
> >  		return NULL;
> > @@ -372,7 +372,7 @@ int lowpan_frag_rcv(struct sk_buff *skb, u8 frag_type)
> >  	struct lowpan_frag_queue *fq;
> >  	struct net *net = dev_net(skb->dev);
> >  	struct lowpan_802154_cb *cb = lowpan_802154_cb(skb);
> > -	struct ieee802154_hdr hdr;
> > +	struct ieee802154_hdr hdr = {};
> >  	int err;
> >  
> >  	if (ieee802154_hdr_peek_addrs(skb, &hdr) < 0)
> > 
> 
> Hi Alexander.
> 
> Thanks for working on this !
> 
> It looks like only the last chunk was really needed to fix this bug, right ?
> 

Yes, the last chunk is needed because:

 .src = *src,

but it will not fix everything, see below. The reason why I was not
sure is that I get packet drops with many fragments and _virtual_
hardware which doesn't should have any drops because I don't use
something to make drops.

> Compiler should really init everything, and not leave garbage bytes in :
> 
> 	struct frag_lowpan_compare_key key = {
> 		.tag = cb->d_tag,
> 		.d_size = cb->d_size,
> 		.src = *src,
> 		.dst = *dst,
> 	};

I talked privately with Stefan and we both use (but I have the same
issue with my host compiler 6.3.0 debian stretch):

gcc version 7.3.1

in my case I use a x86_64 qemu emulation.

my test is:

$ ping fe80::38c7:dc15:6089:4cc8%lowpan0 -s 1024 -c 10000 -i 0.025

which ends in about ~10 fragments (I don't remember the exact value, we
have ~80 bytes payload per frame only)

and I get back:

10000 packets transmitted, 6192 received, 38% packet loss, time 326431ms

ping implementation is:

ping utility, iputils-s20161105

I did the following changes:

---
@@ -590,8 +593,30 @@ static int lowpan_obj_cmpfn(struct rhashtable_compare_arg *arg, const void *ptr)
 {
        const struct frag_lowpan_compare_key *key = arg->key;
        const struct inet_frag_queue *fq = ptr;
+       const struct frag_lowpan_compare_key *key2 = (const struct frag_lowpan_compare_key *)&fq->key;
+       int rc, rc2;
+
+       rc2 = !!memcmp(&fq->key, key, sizeof(*key));
+
+       if (sizeof(*key) > sizeof(fq->key))
+               BUG();
+
+       rc = ((key2->tag == key->tag) &&
+             (key2->d_size == key->d_size) &&
+             ieee802154_addr_equal(&key2->src, &key->src) &&
+             ieee802154_addr_equal(&key2->dst, &key->dst));
+
+       if (rc) {
+               if (rc2 != 0) {
+                       pr_info("XXXXXXXXXXXXXXXXXXXX BINGO %d\n", rc2);
+                       print_hex_dump(KERN_INFO, "key data: ", DUMP_PREFIX_ADDRESS,
+                                      16, 1, key, sizeof(*key), true);
+                       print_hex_dump(KERN_INFO, "key2 data: ", DUMP_PREFIX_ADDRESS,
+                                      16, 1, key2, sizeof(*key2), true);
+               }
+       }
---

This change will check between memcmp() and fields compare and report a
BINGO inclusive hexdump() when they report different results which they
should not.

While debugging that I saw that fq->key is a union which doesn't has the
"frag_lowpan_compare_key" inside. Which is still fine because we are not
bigger than frag_v6_compare_key. I did some BUG() if this occurs.
Just as side note.

Please also note I _only_ get this code triggered when I am lucky and
the hashfn report the same hash for some mismatch keys (I saw this is
already the case and seems enough to debug).

I get this on my dmesg output:

---
6LoWPAN: XXXXXXXXXXXXXXXXXXXX BINGO 1
key data: 000000004c4f1290: 55 0b 30 04 ff ff ff ff 02 00 ef be 00 00 00 00  U.0.............
key data: 00000000f28c6d16: cd 0b 00 00 00 00 00 00 03 00 ef be 00 00 00 00  ................
key data: 00000000c3564bd8: c8 4c 89 60 15 dc c7 3a                          .L.`...:
key2 data: 000000000469f467: 55 0b 30 04 02 88 ff ff 02 00 ef be 00 00 00 00  U.0.............
key2 data: 00000000c3bc7aca: cd 0b 00 00 00 00 00 00 03 00 ef be 00 00 00 00  ................
key2 data: 00000000d2a3a530: c8 4c 89 60 15 dc c7 3a                          .L.`...:
---

pahole reports about frag_lowpan_compare_key the following (we should move
the padding "bits" to the end. Now I know how to deal with pahole):

---
struct frag_lowpan_compare_key {
    u16                        tag;                  /*     0     2 */
    u16                        d_size;               /*     2     2 */

    /* XXX 4 bytes hole, try to pack */

    struct ieee802154_addr     src;                  /*     8    16 */
    struct ieee802154_addr     dst;                  /*    24    16 */

    /* size: 40, cachelines: 1, members: 4 */
    /* sum members: 36, holes: 1, sum holes: 4 */
    /* last cacheline: 40 bytes */
};
---

As you can see starting at offset 4 size 4 I have a 4 bytes hole.
Compare to the hexdump: (I marked the bytes with ^^)

---
key data: 000000004c4f1290: 55 0b 30 04 ff ff ff ff 02 00 ef be 00 00 00 00  U.0.............
                                        ^^ ^^ ^^ ^^
key data: 00000000f28c6d16: cd 0b 00 00 00 00 00 00 03 00 ef be 00 00 00 00  ................
key data: 00000000c3564bd8: c8 4c 89 60 15 dc c7 3a                          .L.`...:
key2 data: 000000000469f467: 55 0b 30 04 02 88 ff ff 02 00 ef be 00 00 00 00  U.0.............
                                         ^^ ^^ ^^ ^^
key2 data: 00000000c3bc7aca: cd 0b 00 00 00 00 00 00 03 00 ef be 00 00 00 00  ................
key2 data: 00000000d2a3a530: c8 4c 89 60 15 dc c7 3a                          .L.`...:
---

So the padding bits are different. The compare via memcmp didn't
reported 0, but compare by fields it reports that it's equal. That's
when my BINGO hits.

I received a lot of BINGO messages, but remember I had only luck that
the hashfn reports the same hash for it which seems to confirm there is
something not working with the padding bits.

I added afterwards this:

---
+       print_hex_dump(KERN_INFO, "key data before inet_frag_find: ", DUMP_PREFIX_ADDRESS,
+                      16, 1, &key, sizeof(key), true);
---

right before calling inet_frag_find and check for the padding bits.
I did the same command again but with a -s 100, which should end in two fragments:

---
key data before inet_frag_find: 0000000056195e0f: 06 00 94 00 00 00 00 00 03 00 ef be 00 00 00 00  ................
                                                              ^^ ^^ ^^ ^^ 
key data before inet_frag_find: 00000000bc3eefd4: 57 bc 05 52 e9 ea 9b be 02 00 ef be 00 00 00 00  W..R............
key data before inet_frag_find: 00000000a1c4ed4e: cd 0b 00 00 00 00 00 00                          ........
key data before inet_frag_find: 0000000056195e0f: 06 00 94 00 02 88 ff ff 03 00 ef be 00 00 00 00  ................
                                                              ^^ ^^ ^^ ^^
key data before inet_frag_find: 00000000bc3eefd4: 57 bc 05 52 e9 ea 9b be 02 00 ef be 00 00 00 00  W..R............
key data before inet_frag_find: 00000000a1c4ed4e: cd 0b 00 00 00 00 00 00  
---

It seems at the first fragment the stack will be zero  and then for the
next fragment there are some random bits inside the padding bits.
Maybe this behavior is compiler related... above the first fragment
seems to have ff..ff inside the padding bits, that's so far what fq->key
tells me and so far I understood is the first fragment.
(I only suppose here that the fragments will arrive synchronized order).

Also I get nothing reassembled anymore and the random padding bits are for
all followed frags always the same. 02 88 ff ff, I think it doesn't
matter...

----------

Everything works fine when I init frag_lowpan_compare_key with zero by
doing = {} and assign the values afterwards.

Ping reports:

10000 packets transmitted, 10000 received, 0% packet loss, time 1108587ms

This is what I assume for virtual hardware... but I guess I am only lucky,
that gcc handles = {} as memset(&foo, 0, sizeof(..)) somehow.

That's all what I can tell right now...

What should I do now? I am ready to debug this more...

- Alex
--
To unsubscribe from this list: send the line "unsubscribe linux-wpan" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/net/ieee802154/6lowpan/6lowpan_i.h b/net/ieee802154/6lowpan/6lowpan_i.h
index b8d95cb71c25..44a7e16bf3b5 100644
--- a/net/ieee802154/6lowpan/6lowpan_i.h
+++ b/net/ieee802154/6lowpan/6lowpan_i.h
@@ -20,8 +20,8 @@  typedef unsigned __bitwise lowpan_rx_result;
 struct frag_lowpan_compare_key {
 	u16 tag;
 	u16 d_size;
-	const struct ieee802154_addr src;
-	const struct ieee802154_addr dst;
+	struct ieee802154_addr src;
+	struct ieee802154_addr dst;
 };
 
 /* Equivalent of ipv4 struct ipq
diff --git a/net/ieee802154/6lowpan/reassembly.c b/net/ieee802154/6lowpan/reassembly.c
index 1790b65944b3..2cc224106b69 100644
--- a/net/ieee802154/6lowpan/reassembly.c
+++ b/net/ieee802154/6lowpan/reassembly.c
@@ -75,14 +75,14 @@  fq_find(struct net *net, const struct lowpan_802154_cb *cb,
 {
 	struct netns_ieee802154_lowpan *ieee802154_lowpan =
 		net_ieee802154_lowpan(net);
-	struct frag_lowpan_compare_key key = {
-		.tag = cb->d_tag,
-		.d_size = cb->d_size,
-		.src = *src,
-		.dst = *dst,
-	};
+	struct frag_lowpan_compare_key key = {};
 	struct inet_frag_queue *q;
 
+	key.tag = cb->d_tag;
+	key.d_size = cb->d_size;
+	key.src = *src;
+	key.dst = *dst;
+
 	q = inet_frag_find(&ieee802154_lowpan->frags, &key);
 	if (!q)
 		return NULL;
@@ -372,7 +372,7 @@  int lowpan_frag_rcv(struct sk_buff *skb, u8 frag_type)
 	struct lowpan_frag_queue *fq;
 	struct net *net = dev_net(skb->dev);
 	struct lowpan_802154_cb *cb = lowpan_802154_cb(skb);
-	struct ieee802154_hdr hdr;
+	struct ieee802154_hdr hdr = {};
 	int err;
 
 	if (ieee802154_hdr_peek_addrs(skb, &hdr) < 0)