diff mbox series

[wpan/next,v3,8/9] net: mac802154: Ensure proper general purpose frame filtering

Message ID 20220905203412.1322947-9-miquel.raynal@bootlin.com (mailing list archive)
State Awaiting Upstream
Delegated to: Netdev Maintainers
Headers show
Series net: ieee802154: Support scanning/beaconing | expand

Checks

Context Check Description
netdev/tree_selection success Guessing tree name failed - patch did not apply

Commit Message

Miquel Raynal Sept. 5, 2022, 8:34 p.m. UTC
Most of the PHYs seem to cope with the standard filtering rules by
default. Some of them might not, like hwsim which is only software, and
in this case advertises its real filtering level with the new
"filtering" internal value.

The core then needs to check what is expected by looking at the PHY
requested filtering level and possibly apply additional filtering
rules.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 include/net/ieee802154_netdev.h |  8 ++++
 net/mac802154/rx.c              | 78 +++++++++++++++++++++++++++++++++
 2 files changed, 86 insertions(+)

Comments

Alexander Aring Sept. 9, 2022, 1 a.m. UTC | #1
Hi,

On Mon, Sep 5, 2022 at 4:35 PM Miquel Raynal <miquel.raynal@bootlin.com> wrote:
>
> Most of the PHYs seem to cope with the standard filtering rules by
> default. Some of them might not, like hwsim which is only software, and

yes, as I said before hwsim should pretend to be like all other
hardware we have.

> in this case advertises its real filtering level with the new
> "filtering" internal value.
>
> The core then needs to check what is expected by looking at the PHY
> requested filtering level and possibly apply additional filtering
> rules.
>
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> ---
>  include/net/ieee802154_netdev.h |  8 ++++
>  net/mac802154/rx.c              | 78 +++++++++++++++++++++++++++++++++
>  2 files changed, 86 insertions(+)
>
> diff --git a/include/net/ieee802154_netdev.h b/include/net/ieee802154_netdev.h
> index d0d188c3294b..1b82bbafe8c7 100644
> --- a/include/net/ieee802154_netdev.h
> +++ b/include/net/ieee802154_netdev.h
> @@ -69,6 +69,14 @@ struct ieee802154_hdr_fc {
>  #endif
>  };
>
> +enum ieee802154_frame_version {
> +       IEEE802154_2003_STD,
> +       IEEE802154_2006_STD,
> +       IEEE802154_STD,
> +       IEEE802154_RESERVED_STD,
> +       IEEE802154_MULTIPURPOSE_STD = IEEE802154_2003_STD,
> +};
> +
>  struct ieee802154_hdr {
>         struct ieee802154_hdr_fc fc;
>         u8 seq;
> diff --git a/net/mac802154/rx.c b/net/mac802154/rx.c
> index c43289c0fdd7..bc46e4a7669d 100644
> --- a/net/mac802154/rx.c
> +++ b/net/mac802154/rx.c
> @@ -52,6 +52,84 @@ ieee802154_subif_frame(struct ieee802154_sub_if_data *sdata,
>                                 mac_cb(skb)->type);
>                         goto fail;
>                 }
> +       } else if (sdata->required_filtering == IEEE802154_FILTERING_4_FRAME_FIELDS &&

We switch here from determine that receive path, means way we are
going from interface type to the required filtering value. Sure there
is currently a 1:1 mapping for them now but I don't know why we are
doing that and this is in my opinion wrong. The receive path should
depend on interface type as it was before and for scanning there is
some early check like:

if (wpan_phy_is_in_scan_mode_state(local)) {
     do_receive_scanning(...)
     /* don't do any other delivery because they provide it to upper layer */
     return;
}

Maybe you should do monitors receive that frame before as well, but
every other interface type should currently not receive it.

- Alex
Alexander Aring Sept. 9, 2022, 1:02 a.m. UTC | #2
Hi,

On Thu, Sep 8, 2022 at 9:00 PM Alexander Aring <aahringo@redhat.com> wrote:
>
> Hi,
>
> On Mon, Sep 5, 2022 at 4:35 PM Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> >
> > Most of the PHYs seem to cope with the standard filtering rules by
> > default. Some of them might not, like hwsim which is only software, and
>
> yes, as I said before hwsim should pretend to be like all other
> hardware we have.
>
> > in this case advertises its real filtering level with the new
> > "filtering" internal value.
> >
> > The core then needs to check what is expected by looking at the PHY
> > requested filtering level and possibly apply additional filtering
> > rules.
> >
> > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> > ---
> >  include/net/ieee802154_netdev.h |  8 ++++
> >  net/mac802154/rx.c              | 78 +++++++++++++++++++++++++++++++++
> >  2 files changed, 86 insertions(+)
> >
> > diff --git a/include/net/ieee802154_netdev.h b/include/net/ieee802154_netdev.h
> > index d0d188c3294b..1b82bbafe8c7 100644
> > --- a/include/net/ieee802154_netdev.h
> > +++ b/include/net/ieee802154_netdev.h
> > @@ -69,6 +69,14 @@ struct ieee802154_hdr_fc {
> >  #endif
> >  };
> >
> > +enum ieee802154_frame_version {
> > +       IEEE802154_2003_STD,
> > +       IEEE802154_2006_STD,
> > +       IEEE802154_STD,
> > +       IEEE802154_RESERVED_STD,
> > +       IEEE802154_MULTIPURPOSE_STD = IEEE802154_2003_STD,
> > +};
> > +
> >  struct ieee802154_hdr {
> >         struct ieee802154_hdr_fc fc;
> >         u8 seq;
> > diff --git a/net/mac802154/rx.c b/net/mac802154/rx.c
> > index c43289c0fdd7..bc46e4a7669d 100644
> > --- a/net/mac802154/rx.c
> > +++ b/net/mac802154/rx.c
> > @@ -52,6 +52,84 @@ ieee802154_subif_frame(struct ieee802154_sub_if_data *sdata,
> >                                 mac_cb(skb)->type);
> >                         goto fail;
> >                 }
> > +       } else if (sdata->required_filtering == IEEE802154_FILTERING_4_FRAME_FIELDS &&
>
> We switch here from determine that receive path, means way we are

- way

> going from interface type to the required filtering value. Sure there
> is currently a 1:1 mapping for them now but I don't know why we are
> doing that and this is in my opinion wrong. The receive path should
> depend on interface type as it was before and for scanning there is
> some early check like:
>
> if (wpan_phy_is_in_scan_mode_state(local)) {
>      do_receive_scanning(...)
>      /* don't do any other delivery because they provide it to upper layer */

In the assumption we know if the condition above is true we have
address filtering disabled.

- Alex
Miquel Raynal Sept. 21, 2022, 3:59 p.m. UTC | #3
Hi Alexander,

aahringo@redhat.com wrote on Thu, 8 Sep 2022 21:00:37 -0400:

> Hi,
> 
> On Mon, Sep 5, 2022 at 4:35 PM Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> >
> > Most of the PHYs seem to cope with the standard filtering rules by
> > default. Some of them might not, like hwsim which is only software, and  
> 
> yes, as I said before hwsim should pretend to be like all other
> hardware we have.
> 
> > in this case advertises its real filtering level with the new
> > "filtering" internal value.
> >
> > The core then needs to check what is expected by looking at the PHY
> > requested filtering level and possibly apply additional filtering
> > rules.
> >
> > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> > ---
> >  include/net/ieee802154_netdev.h |  8 ++++
> >  net/mac802154/rx.c              | 78 +++++++++++++++++++++++++++++++++
> >  2 files changed, 86 insertions(+)
> >
> > diff --git a/include/net/ieee802154_netdev.h b/include/net/ieee802154_netdev.h
> > index d0d188c3294b..1b82bbafe8c7 100644
> > --- a/include/net/ieee802154_netdev.h
> > +++ b/include/net/ieee802154_netdev.h
> > @@ -69,6 +69,14 @@ struct ieee802154_hdr_fc {
> >  #endif
> >  };
> >
> > +enum ieee802154_frame_version {
> > +       IEEE802154_2003_STD,
> > +       IEEE802154_2006_STD,
> > +       IEEE802154_STD,
> > +       IEEE802154_RESERVED_STD,
> > +       IEEE802154_MULTIPURPOSE_STD = IEEE802154_2003_STD,
> > +};
> > +
> >  struct ieee802154_hdr {
> >         struct ieee802154_hdr_fc fc;
> >         u8 seq;
> > diff --git a/net/mac802154/rx.c b/net/mac802154/rx.c
> > index c43289c0fdd7..bc46e4a7669d 100644
> > --- a/net/mac802154/rx.c
> > +++ b/net/mac802154/rx.c
> > @@ -52,6 +52,84 @@ ieee802154_subif_frame(struct ieee802154_sub_if_data *sdata,
> >                                 mac_cb(skb)->type);
> >                         goto fail;
> >                 }
> > +       } else if (sdata->required_filtering == IEEE802154_FILTERING_4_FRAME_FIELDS &&  
> 
> We switch here from determine that receive path, means way we are
> going from interface type to the required filtering value. Sure there
> is currently a 1:1 mapping for them now but I don't know why we are
> doing that and this is in my opinion wrong. The receive path should
> depend on interface type as it was before and for scanning there is
> some early check like:

Maybe on this one I am not fully convinced yet.

In your opinion (I try to rephrase so that we align on what you told
me) the total lack of filtering is only something that is reserved to
monitor interfaces, so you make an implicit link between interface type
and filtering level.

I would argue that this is true today, but as the "no filtering at all"
level is defined in the spec, I assumed it was a possible level that
one would want to achieve some day (not sure for what purpose yet). So
I assumed it would be more relevant to only work with the
expected filtering level in the receive path rather than on the
interface type, it makes more sense IMHO. In practice I agree it should
be the same filtering-wise, but from a conceptual point of view I find
the current logic partially satisfying.

Would you agree with me only using "expected filtering levels" rather
than:
- sometimes the interface type
- sometimes the mac state (scan)
- otherwise, by default, the highest filtering level
?

I think it would clarify the receive path.

I will of course get rid of most of all the other "nasty"
software filtering additions you nacked in the other threads.

> if (wpan_phy_is_in_scan_mode_state(local)) {
>      do_receive_scanning(...)
>      /* don't do any other delivery because they provide it to upper layer */
>      return;
> }
> 
> Maybe you should do monitors receive that frame before as well, but
> every other interface type should currently not receive it.
> 
> - Alex
> 


Thanks,
Miquèl
Alexander Aring Sept. 25, 2022, 10:27 p.m. UTC | #4
Hi,

On Wed, Sep 21, 2022 at 11:59 AM Miquel Raynal
<miquel.raynal@bootlin.com> wrote:
>
> Hi Alexander,
>
> aahringo@redhat.com wrote on Thu, 8 Sep 2022 21:00:37 -0400:
>
> > Hi,
> >
> > On Mon, Sep 5, 2022 at 4:35 PM Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> > >
> > > Most of the PHYs seem to cope with the standard filtering rules by
> > > default. Some of them might not, like hwsim which is only software, and
> >
> > yes, as I said before hwsim should pretend to be like all other
> > hardware we have.
> >
> > > in this case advertises its real filtering level with the new
> > > "filtering" internal value.
> > >
> > > The core then needs to check what is expected by looking at the PHY
> > > requested filtering level and possibly apply additional filtering
> > > rules.
> > >
> > > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> > > ---
> > >  include/net/ieee802154_netdev.h |  8 ++++
> > >  net/mac802154/rx.c              | 78 +++++++++++++++++++++++++++++++++
> > >  2 files changed, 86 insertions(+)
> > >
> > > diff --git a/include/net/ieee802154_netdev.h b/include/net/ieee802154_netdev.h
> > > index d0d188c3294b..1b82bbafe8c7 100644
> > > --- a/include/net/ieee802154_netdev.h
> > > +++ b/include/net/ieee802154_netdev.h
> > > @@ -69,6 +69,14 @@ struct ieee802154_hdr_fc {
> > >  #endif
> > >  };
> > >
> > > +enum ieee802154_frame_version {
> > > +       IEEE802154_2003_STD,
> > > +       IEEE802154_2006_STD,
> > > +       IEEE802154_STD,
> > > +       IEEE802154_RESERVED_STD,
> > > +       IEEE802154_MULTIPURPOSE_STD = IEEE802154_2003_STD,
> > > +};
> > > +
> > >  struct ieee802154_hdr {
> > >         struct ieee802154_hdr_fc fc;
> > >         u8 seq;
> > > diff --git a/net/mac802154/rx.c b/net/mac802154/rx.c
> > > index c43289c0fdd7..bc46e4a7669d 100644
> > > --- a/net/mac802154/rx.c
> > > +++ b/net/mac802154/rx.c
> > > @@ -52,6 +52,84 @@ ieee802154_subif_frame(struct ieee802154_sub_if_data *sdata,
> > >                                 mac_cb(skb)->type);
> > >                         goto fail;
> > >                 }
> > > +       } else if (sdata->required_filtering == IEEE802154_FILTERING_4_FRAME_FIELDS &&
> >
> > We switch here from determine that receive path, means way we are
> > going from interface type to the required filtering value. Sure there
> > is currently a 1:1 mapping for them now but I don't know why we are
> > doing that and this is in my opinion wrong. The receive path should
> > depend on interface type as it was before and for scanning there is
> > some early check like:
>
> Maybe on this one I am not fully convinced yet.
>
> In your opinion (I try to rephrase so that we align on what you told
> me) the total lack of filtering is only something that is reserved to
> monitor interfaces, so you make an implicit link between interface type
> and filtering level.

it always depends on the use case, but in the sense of filtering-level
in "normal" operating mode and calling netif_skb_deliver_foo(), yes.

The use case for e.g. scan is different and mac802154 takes control of it.

>
> I would argue that this is true today, but as the "no filtering at all"
> level is defined in the spec, I assumed it was a possible level that
> one would want to achieve some day (not sure for what purpose yet). So
> I assumed it would be more relevant to only work with the
> expected filtering level in the receive path rather than on the
> interface type, it makes more sense IMHO. In practice I agree it should
> be the same filtering-wise, but from a conceptual point of view I find
> the current logic partially satisfying.
>

I don't quite follow here. I would say we currently only support to
tell the hardware the whole filtering level (with AACK support) or the
non-filtering level. With both we should somehow able to support
interface types which requires

> Would you agree with me only using "expected filtering levels" rather
> than:
> - sometimes the interface type
> - sometimes the mac state (scan)
> - otherwise, by default, the highest filtering level
> ?

I think so, yes? I don't know what "otherwise, by default, the highest
filtering level" means, it is the interface type which declares what
it's actually needs at netif_skb_deliver_foo(), e.g. monitors will
call netif_skb_deliver_foo() even without AACK support... because
that's how they working. They also don't have an address in the
network. It is a kind of experimenting, debugging, or making chaos in
your network interface type.

For other node, or coordinator interfaces? They need at least AACK
support (and they having a valid address filtering going on) they need
it...

however on scan I would say then they are in a kind of "hidden"
non-operating interface and the phy will do some operation on phy
level and do something and restore after it's done. Scan should not
have anything todo with interfaces, BUT there might be the possibility
to specify the interface on iwpan layer to make a scan, _however_ it
will be only a shortcut to specify the phy which the interface is
using...

- Alex
Alexander Aring Sept. 28, 2022, 12:23 a.m. UTC | #5
Hi,

On Sun, Sep 25, 2022 at 6:27 PM Alexander Aring <aahringo@redhat.com> wrote:
>
> Hi,
>
> On Wed, Sep 21, 2022 at 11:59 AM Miquel Raynal
> <miquel.raynal@bootlin.com> wrote:
> >
> > Hi Alexander,
> >
> > aahringo@redhat.com wrote on Thu, 8 Sep 2022 21:00:37 -0400:
> >
> > > Hi,
> > >
> > > On Mon, Sep 5, 2022 at 4:35 PM Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> > > >
> > > > Most of the PHYs seem to cope with the standard filtering rules by
> > > > default. Some of them might not, like hwsim which is only software, and
> > >
> > > yes, as I said before hwsim should pretend to be like all other
> > > hardware we have.
> > >
> > > > in this case advertises its real filtering level with the new
> > > > "filtering" internal value.
> > > >
> > > > The core then needs to check what is expected by looking at the PHY
> > > > requested filtering level and possibly apply additional filtering
> > > > rules.
> > > >
> > > > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> > > > ---
> > > >  include/net/ieee802154_netdev.h |  8 ++++
> > > >  net/mac802154/rx.c              | 78 +++++++++++++++++++++++++++++++++
> > > >  2 files changed, 86 insertions(+)
> > > >
> > > > diff --git a/include/net/ieee802154_netdev.h b/include/net/ieee802154_netdev.h
> > > > index d0d188c3294b..1b82bbafe8c7 100644
> > > > --- a/include/net/ieee802154_netdev.h
> > > > +++ b/include/net/ieee802154_netdev.h
> > > > @@ -69,6 +69,14 @@ struct ieee802154_hdr_fc {
> > > >  #endif
> > > >  };
> > > >
> > > > +enum ieee802154_frame_version {
> > > > +       IEEE802154_2003_STD,
> > > > +       IEEE802154_2006_STD,
> > > > +       IEEE802154_STD,
> > > > +       IEEE802154_RESERVED_STD,
> > > > +       IEEE802154_MULTIPURPOSE_STD = IEEE802154_2003_STD,
> > > > +};
> > > > +
> > > >  struct ieee802154_hdr {
> > > >         struct ieee802154_hdr_fc fc;
> > > >         u8 seq;
> > > > diff --git a/net/mac802154/rx.c b/net/mac802154/rx.c
> > > > index c43289c0fdd7..bc46e4a7669d 100644
> > > > --- a/net/mac802154/rx.c
> > > > +++ b/net/mac802154/rx.c
> > > > @@ -52,6 +52,84 @@ ieee802154_subif_frame(struct ieee802154_sub_if_data *sdata,
> > > >                                 mac_cb(skb)->type);
> > > >                         goto fail;
> > > >                 }
> > > > +       } else if (sdata->required_filtering == IEEE802154_FILTERING_4_FRAME_FIELDS &&
> > >
> > > We switch here from determine that receive path, means way we are
> > > going from interface type to the required filtering value. Sure there
> > > is currently a 1:1 mapping for them now but I don't know why we are
> > > doing that and this is in my opinion wrong. The receive path should
> > > depend on interface type as it was before and for scanning there is
> > > some early check like:
> >
> > Maybe on this one I am not fully convinced yet.
> >
> > In your opinion (I try to rephrase so that we align on what you told
> > me) the total lack of filtering is only something that is reserved to
> > monitor interfaces, so you make an implicit link between interface type
> > and filtering level.
>
> it always depends on the use case, but in the sense of filtering-level
> in "normal" operating mode and calling netif_skb_deliver_foo(), yes.
>
> The use case for e.g. scan is different and mac802154 takes control of it.
>
> >
> > I would argue that this is true today, but as the "no filtering at all"
> > level is defined in the spec, I assumed it was a possible level that
> > one would want to achieve some day (not sure for what purpose yet). So
> > I assumed it would be more relevant to only work with the
> > expected filtering level in the receive path rather than on the
> > interface type, it makes more sense IMHO. In practice I agree it should
> > be the same filtering-wise, but from a conceptual point of view I find
> > the current logic partially satisfying.
> >
>
> I don't quite follow here. I would say we currently only support to
> tell the hardware the whole filtering level (with AACK support) or the
> non-filtering level. With both we should somehow able to support
> interface types which requires
>
> > Would you agree with me only using "expected filtering levels" rather
> > than:
> > - sometimes the interface type
> > - sometimes the mac state (scan)
> > - otherwise, by default, the highest filtering level
> > ?
>
> I think so, yes? I don't know what "otherwise, by default, the highest
> filtering level" means, it is the interface type which declares what
> it's actually needs at netif_skb_deliver_foo(), e.g. monitors will
> call netif_skb_deliver_foo() even without AACK support... because
> that's how they working. They also don't have an address in the

they don't have an address -> the hardware filter is set to invalid
destination address setting and this should always be set when
switching to a mode which disables address filter. In case of your
scan command it should be then switched back.

- Alex
diff mbox series

Patch

diff --git a/include/net/ieee802154_netdev.h b/include/net/ieee802154_netdev.h
index d0d188c3294b..1b82bbafe8c7 100644
--- a/include/net/ieee802154_netdev.h
+++ b/include/net/ieee802154_netdev.h
@@ -69,6 +69,14 @@  struct ieee802154_hdr_fc {
 #endif
 };
 
+enum ieee802154_frame_version {
+	IEEE802154_2003_STD,
+	IEEE802154_2006_STD,
+	IEEE802154_STD,
+	IEEE802154_RESERVED_STD,
+	IEEE802154_MULTIPURPOSE_STD = IEEE802154_2003_STD,
+};
+
 struct ieee802154_hdr {
 	struct ieee802154_hdr_fc fc;
 	u8 seq;
diff --git a/net/mac802154/rx.c b/net/mac802154/rx.c
index c43289c0fdd7..bc46e4a7669d 100644
--- a/net/mac802154/rx.c
+++ b/net/mac802154/rx.c
@@ -52,6 +52,84 @@  ieee802154_subif_frame(struct ieee802154_sub_if_data *sdata,
 				mac_cb(skb)->type);
 			goto fail;
 		}
+	} else if (sdata->required_filtering == IEEE802154_FILTERING_4_FRAME_FIELDS &&
+		   sdata->required_filtering > wpan_phy->filtering) {
+		/* Level 4 filtering: Frame fields validity */
+
+		/* a) Drop reserved frame types */
+		switch (mac_cb(skb)->type) {
+		case IEEE802154_FC_TYPE_BEACON:
+		case IEEE802154_FC_TYPE_DATA:
+		case IEEE802154_FC_TYPE_ACK:
+		case IEEE802154_FC_TYPE_MAC_CMD:
+			break;
+		default:
+			dev_dbg(&sdata->dev->dev, "unrecognized frame type 0x%x\n",
+				mac_cb(skb)->type);
+			goto fail;
+		}
+
+		/* b) Drop reserved frame versions */
+		switch (hdr->fc.version) {
+		case IEEE802154_2003_STD:
+		case IEEE802154_2006_STD:
+		case IEEE802154_STD:
+			break;
+		default:
+			dev_dbg(&sdata->dev->dev,
+				"unrecognized frame version 0x%x\n",
+				hdr->fc.version);
+			goto fail;
+		}
+
+		/* c) PAN ID constraints */
+		if ((mac_cb(skb)->dest.mode == IEEE802154_ADDR_LONG ||
+		     mac_cb(skb)->dest.mode == IEEE802154_ADDR_SHORT) &&
+		    mac_cb(skb)->dest.pan_id != span &&
+		    mac_cb(skb)->dest.pan_id != cpu_to_le16(IEEE802154_PANID_BROADCAST)) {
+			dev_dbg(&sdata->dev->dev,
+				"unrecognized PAN ID %04x\n",
+				le16_to_cpu(mac_cb(skb)->dest.pan_id));
+			goto fail;
+		}
+
+		/* d1) Short address constraints */
+		if (mac_cb(skb)->dest.mode == IEEE802154_ADDR_SHORT &&
+		    mac_cb(skb)->dest.short_addr != sshort &&
+		    mac_cb(skb)->dest.short_addr != cpu_to_le16(IEEE802154_ADDR_BROADCAST)) {
+			dev_dbg(&sdata->dev->dev,
+				"unrecognized short address %04x\n",
+				le16_to_cpu(mac_cb(skb)->dest.short_addr));
+			goto fail;
+		}
+
+		/* d2) Extended address constraints */
+		if (mac_cb(skb)->dest.mode == IEEE802154_ADDR_LONG &&
+		    mac_cb(skb)->dest.extended_addr != wpan_dev->extended_addr) {
+			dev_dbg(&sdata->dev->dev,
+				"unrecognized long address 0x%016llx\n",
+				mac_cb(skb)->dest.extended_addr);
+			goto fail;
+		}
+
+		/* d4) Specific PAN coordinator case (no parent) */
+		if ((mac_cb(skb)->type == IEEE802154_FC_TYPE_DATA ||
+		     mac_cb(skb)->type == IEEE802154_FC_TYPE_MAC_CMD) &&
+		    mac_cb(skb)->dest.mode == IEEE802154_ADDR_NONE) {
+			dev_dbg(&sdata->dev->dev,
+				"relaying is not supported\n");
+			goto fail;
+		}
+	}
+
+	/* e) Beacon frames follow specific PAN ID rules */
+	if (mac_cb(skb)->type == IEEE802154_FC_TYPE_BEACON &&
+	    span != cpu_to_le16(IEEE802154_PANID_BROADCAST) &&
+	    mac_cb(skb)->dest.pan_id != span) {
+		dev_dbg(&sdata->dev->dev,
+			"invalid beacon PAN ID %04x\n",
+			le16_to_cpu(mac_cb(skb)->dest.pan_id));
+		goto fail;
 	}
 
 	switch (mac_cb(skb)->dest.mode) {