diff mbox series

[wpan/next,v4,5/8] ieee802154: hwsim: Implement address filtering

Message ID 20221007085310.503366-6-miquel.raynal@bootlin.com (mailing list archive)
State Accepted
Headers show
Series net: ieee802154: Improve filtering support | expand

Commit Message

Miquel Raynal Oct. 7, 2022, 8:53 a.m. UTC
We have access to the address filters being theoretically applied, we
also have access to the actual filtering level applied, so let's add a
proper frame validation sequence in hwsim.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/net/ieee802154/mac802154_hwsim.c | 111 ++++++++++++++++++++++-
 include/net/ieee802154_netdev.h          |   8 ++
 2 files changed, 117 insertions(+), 2 deletions(-)

Comments

Alexander Aring Oct. 11, 2022, 1:04 a.m. UTC | #1
Hi,

On Fri, Oct 7, 2022 at 4:53 AM Miquel Raynal <miquel.raynal@bootlin.com> wrote:
>
> We have access to the address filters being theoretically applied, we
> also have access to the actual filtering level applied, so let's add a
> proper frame validation sequence in hwsim.
>
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> ---
>  drivers/net/ieee802154/mac802154_hwsim.c | 111 ++++++++++++++++++++++-
>  include/net/ieee802154_netdev.h          |   8 ++
>  2 files changed, 117 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/net/ieee802154/mac802154_hwsim.c b/drivers/net/ieee802154/mac802154_hwsim.c
> index 458be66b5195..84ee948f35bc 100644
> --- a/drivers/net/ieee802154/mac802154_hwsim.c
> +++ b/drivers/net/ieee802154/mac802154_hwsim.c
> @@ -18,6 +18,7 @@
>  #include <linux/netdevice.h>
>  #include <linux/device.h>
>  #include <linux/spinlock.h>
> +#include <net/ieee802154_netdev.h>
>  #include <net/mac802154.h>
>  #include <net/cfg802154.h>
>  #include <net/genetlink.h>
> @@ -139,6 +140,113 @@ static int hwsim_hw_addr_filt(struct ieee802154_hw *hw,
>         return 0;
>  }
>
> +static void hwsim_hw_receive(struct ieee802154_hw *hw, struct sk_buff *skb,
> +                            u8 lqi)
> +{
> +       struct ieee802154_hdr hdr;
> +       struct hwsim_phy *phy = hw->priv;
> +       struct hwsim_pib *pib;
> +
> +       rcu_read_lock();
> +       pib = rcu_dereference(phy->pib);
> +
> +       if (!pskb_may_pull(skb, 3)) {
> +               dev_dbg(hw->parent, "invalid frame\n");
> +               goto drop;
> +       }
> +
> +       memcpy(&hdr, skb->data, 3);
> +
> +       /* Level 4 filtering: Frame fields validity */
> +       if (hw->phy->filtering == IEEE802154_FILTERING_4_FRAME_FIELDS) {
> +
> +               /* 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(hw->parent, "unrecognized frame type 0x%x\n",
> +                               mac_cb(skb)->type);
> +                       goto drop;
> +               }
> +
> +               /* b) Drop reserved frame versions */
> +               switch (hdr.fc.version) {
> +               case IEEE802154_2003_STD:
> +               case IEEE802154_2006_STD:
> +               case IEEE802154_STD:
> +                       break;
> +               default:
> +                       dev_dbg(hw->parent,
> +                               "unrecognized frame version 0x%x\n",
> +                               hdr.fc.version);
> +                       goto drop;
> +               }
> +
> +               /* 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 != pib->filt.pan_id &&
> +                   mac_cb(skb)->dest.pan_id != cpu_to_le16(IEEE802154_PANID_BROADCAST)) {
> +                       dev_dbg(hw->parent,
> +                               "unrecognized PAN ID %04x\n",
> +                               le16_to_cpu(mac_cb(skb)->dest.pan_id));
> +                       goto drop;
> +               }
> +
> +               /* d1) Short address constraints */
> +               if (mac_cb(skb)->dest.mode == IEEE802154_ADDR_SHORT &&
> +                   mac_cb(skb)->dest.short_addr != pib->filt.short_addr &&
> +                   mac_cb(skb)->dest.short_addr != cpu_to_le16(IEEE802154_ADDR_BROADCAST)) {
> +                       dev_dbg(hw->parent,
> +                               "unrecognized short address %04x\n",
> +                               le16_to_cpu(mac_cb(skb)->dest.short_addr));
> +                       goto drop;
> +               }
> +
> +               /* d2) Extended address constraints */
> +               if (mac_cb(skb)->dest.mode == IEEE802154_ADDR_LONG &&
> +                   mac_cb(skb)->dest.extended_addr != pib->filt.ieee_addr) {
> +                       dev_dbg(hw->parent,
> +                               "unrecognized long address 0x%016llx\n",
> +                               mac_cb(skb)->dest.extended_addr);
> +                       goto drop;
> +               }
> +
> +               /* 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(hw->parent,
> +                               "relaying is not supported\n");
> +                       goto drop;
> +               }
> +
> +               /* e) Beacon frames follow specific PAN ID rules */
> +               if (mac_cb(skb)->type == IEEE802154_FC_TYPE_BEACON &&
> +                   pib->filt.pan_id != cpu_to_le16(IEEE802154_PANID_BROADCAST) &&
> +                   mac_cb(skb)->dest.pan_id != pib->filt.pan_id) {
> +                       dev_dbg(hw->parent,
> +                               "invalid beacon PAN ID %04x\n",
> +                               le16_to_cpu(mac_cb(skb)->dest.pan_id));
> +                       goto drop;
> +               }
> +        }
> +
> +       rcu_read_unlock();
> +
> +       ieee802154_rx_irqsafe(hw, skb, lqi);

what is about if hwsim goes into promiscuous mode, then this software
filtering should be skipped?

- Alex
Alexander Aring Oct. 11, 2022, 1:13 a.m. UTC | #2
Hi,

On Mon, Oct 10, 2022 at 9:04 PM Alexander Aring <aahringo@redhat.com> wrote:
>
> Hi,
>
> On Fri, Oct 7, 2022 at 4:53 AM Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> >
> > We have access to the address filters being theoretically applied, we
> > also have access to the actual filtering level applied, so let's add a
> > proper frame validation sequence in hwsim.
> >
> > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> > ---
> >  drivers/net/ieee802154/mac802154_hwsim.c | 111 ++++++++++++++++++++++-
> >  include/net/ieee802154_netdev.h          |   8 ++
> >  2 files changed, 117 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/net/ieee802154/mac802154_hwsim.c b/drivers/net/ieee802154/mac802154_hwsim.c
> > index 458be66b5195..84ee948f35bc 100644
> > --- a/drivers/net/ieee802154/mac802154_hwsim.c
> > +++ b/drivers/net/ieee802154/mac802154_hwsim.c
> > @@ -18,6 +18,7 @@
> >  #include <linux/netdevice.h>
> >  #include <linux/device.h>
> >  #include <linux/spinlock.h>
> > +#include <net/ieee802154_netdev.h>
> >  #include <net/mac802154.h>
> >  #include <net/cfg802154.h>
> >  #include <net/genetlink.h>
> > @@ -139,6 +140,113 @@ static int hwsim_hw_addr_filt(struct ieee802154_hw *hw,
> >         return 0;
> >  }
> >
> > +static void hwsim_hw_receive(struct ieee802154_hw *hw, struct sk_buff *skb,
> > +                            u8 lqi)
> > +{
> > +       struct ieee802154_hdr hdr;
> > +       struct hwsim_phy *phy = hw->priv;
> > +       struct hwsim_pib *pib;
> > +
> > +       rcu_read_lock();
> > +       pib = rcu_dereference(phy->pib);
> > +
> > +       if (!pskb_may_pull(skb, 3)) {
> > +               dev_dbg(hw->parent, "invalid frame\n");
> > +               goto drop;
> > +       }
> > +
> > +       memcpy(&hdr, skb->data, 3);
> > +
> > +       /* Level 4 filtering: Frame fields validity */
> > +       if (hw->phy->filtering == IEEE802154_FILTERING_4_FRAME_FIELDS) {

I see, there is this big if handling. But it accesses the
hw->phy->filtering value. It should be part of the hwsim pib setting
set by the driver callback. It is a question here of mac802154 layer
setting vs driver layer setting. We should do what the mac802154 tells
the driver to do, this way we do what the mac802154 layer is set to.

However it's a minor thing and it's okay to do it so...

- Alex
Alexander Aring Oct. 11, 2022, 1:21 a.m. UTC | #3
Hi,

On Mon, Oct 10, 2022 at 9:13 PM Alexander Aring <aahringo@redhat.com> wrote:
>
> Hi,
>
> On Mon, Oct 10, 2022 at 9:04 PM Alexander Aring <aahringo@redhat.com> wrote:
> >
> > Hi,
> >
> > On Fri, Oct 7, 2022 at 4:53 AM Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> > >
> > > We have access to the address filters being theoretically applied, we
> > > also have access to the actual filtering level applied, so let's add a
> > > proper frame validation sequence in hwsim.
> > >
> > > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> > > ---
> > >  drivers/net/ieee802154/mac802154_hwsim.c | 111 ++++++++++++++++++++++-
> > >  include/net/ieee802154_netdev.h          |   8 ++
> > >  2 files changed, 117 insertions(+), 2 deletions(-)
> > >
> > > diff --git a/drivers/net/ieee802154/mac802154_hwsim.c b/drivers/net/ieee802154/mac802154_hwsim.c
> > > index 458be66b5195..84ee948f35bc 100644
> > > --- a/drivers/net/ieee802154/mac802154_hwsim.c
> > > +++ b/drivers/net/ieee802154/mac802154_hwsim.c
> > > @@ -18,6 +18,7 @@
> > >  #include <linux/netdevice.h>
> > >  #include <linux/device.h>
> > >  #include <linux/spinlock.h>
> > > +#include <net/ieee802154_netdev.h>
> > >  #include <net/mac802154.h>
> > >  #include <net/cfg802154.h>
> > >  #include <net/genetlink.h>
> > > @@ -139,6 +140,113 @@ static int hwsim_hw_addr_filt(struct ieee802154_hw *hw,
> > >         return 0;
> > >  }
> > >
> > > +static void hwsim_hw_receive(struct ieee802154_hw *hw, struct sk_buff *skb,
> > > +                            u8 lqi)
> > > +{
> > > +       struct ieee802154_hdr hdr;
> > > +       struct hwsim_phy *phy = hw->priv;
> > > +       struct hwsim_pib *pib;
> > > +
> > > +       rcu_read_lock();
> > > +       pib = rcu_dereference(phy->pib);
> > > +
> > > +       if (!pskb_may_pull(skb, 3)) {
> > > +               dev_dbg(hw->parent, "invalid frame\n");
> > > +               goto drop;
> > > +       }
> > > +
> > > +       memcpy(&hdr, skb->data, 3);
> > > +
> > > +       /* Level 4 filtering: Frame fields validity */
> > > +       if (hw->phy->filtering == IEEE802154_FILTERING_4_FRAME_FIELDS) {
>
> I see, there is this big if handling. But it accesses the
> hw->phy->filtering value. It should be part of the hwsim pib setting
> set by the driver callback. It is a question here of mac802154 layer
> setting vs driver layer setting. We should do what the mac802154 tells
> the driver to do, this way we do what the mac802154 layer is set to.
>
> However it's a minor thing and it's okay to do it so...

* whereas we never let the driver know at any time of what different
filter levels exist _currently_ we have only the promiscuous mode
on/off switch which is do nothing or 4_FRAME_FIELDS.
It will work for now, changing anything in the mac802154 filtering
fields or something will end in probably breakage in this handling. In
my point of view as the current state is it should not do that, as
remember that hwsim will "simulate" hardware it should not be able to
access mac802154 fields (especially when doing receiving of frames) as
other hardware will only set register bits (as hwsim pib values is
there for)...

Still I think it's fine for now.

- Alex
Stefan Schmidt Oct. 12, 2022, 10:48 a.m. UTC | #4
Hello Miquel.

This patch has given me some checkpatch wawrnings and errors.

Commit d9abecc4a0fc ("ieee802154: hwsim: Implement address filtering")
----------------------------------------------------------------------
CHECK: Blank lines aren't necessary after an open brace '{'
#53: FILE: drivers/net/ieee802154/mac802154_hwsim.c:162:
+	if (hw->phy->filtering == IEEE802154_FILTERING_4_FRAME_FIELDS) {
+

ERROR: code indent should use tabs where possible
#128: FILE: drivers/net/ieee802154/mac802154_hwsim.c:237:
+        }$

WARNING: please, no spaces at the start of a line
#128: FILE: drivers/net/ieee802154/mac802154_hwsim.c:237:
+        }$

total: 1 errors, 1 warnings, 1 checks, 143 lines checked

I fixed this up in palce for you tp proceed with applying this patches. 
Just so you are aware.

regards
Stefan Schmidt
Miquel Raynal Oct. 15, 2022, 8:59 a.m. UTC | #5
Hi Alexander,

aahringo@redhat.com wrote on Mon, 10 Oct 2022 21:21:17 -0400:

> Hi,
> 
> On Mon, Oct 10, 2022 at 9:13 PM Alexander Aring <aahringo@redhat.com> wrote:
> >
> > Hi,
> >
> > On Mon, Oct 10, 2022 at 9:04 PM Alexander Aring <aahringo@redhat.com> wrote:  
> > >
> > > Hi,
> > >
> > > On Fri, Oct 7, 2022 at 4:53 AM Miquel Raynal <miquel.raynal@bootlin.com> wrote:  
> > > >
> > > > We have access to the address filters being theoretically applied, we
> > > > also have access to the actual filtering level applied, so let's add a
> > > > proper frame validation sequence in hwsim.
> > > >
> > > > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> > > > ---
> > > >  drivers/net/ieee802154/mac802154_hwsim.c | 111 ++++++++++++++++++++++-
> > > >  include/net/ieee802154_netdev.h          |   8 ++
> > > >  2 files changed, 117 insertions(+), 2 deletions(-)
> > > >
> > > > diff --git a/drivers/net/ieee802154/mac802154_hwsim.c b/drivers/net/ieee802154/mac802154_hwsim.c
> > > > index 458be66b5195..84ee948f35bc 100644
> > > > --- a/drivers/net/ieee802154/mac802154_hwsim.c
> > > > +++ b/drivers/net/ieee802154/mac802154_hwsim.c
> > > > @@ -18,6 +18,7 @@
> > > >  #include <linux/netdevice.h>
> > > >  #include <linux/device.h>
> > > >  #include <linux/spinlock.h>
> > > > +#include <net/ieee802154_netdev.h>
> > > >  #include <net/mac802154.h>
> > > >  #include <net/cfg802154.h>
> > > >  #include <net/genetlink.h>
> > > > @@ -139,6 +140,113 @@ static int hwsim_hw_addr_filt(struct ieee802154_hw *hw,
> > > >         return 0;
> > > >  }
> > > >
> > > > +static void hwsim_hw_receive(struct ieee802154_hw *hw, struct sk_buff *skb,
> > > > +                            u8 lqi)
> > > > +{
> > > > +       struct ieee802154_hdr hdr;
> > > > +       struct hwsim_phy *phy = hw->priv;
> > > > +       struct hwsim_pib *pib;
> > > > +
> > > > +       rcu_read_lock();
> > > > +       pib = rcu_dereference(phy->pib);
> > > > +
> > > > +       if (!pskb_may_pull(skb, 3)) {
> > > > +               dev_dbg(hw->parent, "invalid frame\n");
> > > > +               goto drop;
> > > > +       }
> > > > +
> > > > +       memcpy(&hdr, skb->data, 3);
> > > > +
> > > > +       /* Level 4 filtering: Frame fields validity */
> > > > +       if (hw->phy->filtering == IEEE802154_FILTERING_4_FRAME_FIELDS) {  
> >
> > I see, there is this big if handling. But it accesses the
> > hw->phy->filtering value. It should be part of the hwsim pib setting
> > set by the driver callback. It is a question here of mac802154 layer
> > setting vs driver layer setting. We should do what the mac802154 tells
> > the driver to do, this way we do what the mac802154 layer is set to.
> >
> > However it's a minor thing and it's okay to do it so...  
> 
> * whereas we never let the driver know at any time of what different
> filter levels exist _currently_ we have only the promiscuous mode
> on/off switch which is do nothing or 4_FRAME_FIELDS.
> It will work for now, changing anything in the mac802154 filtering
> fields or something will end in probably breakage in this handling. In
> my point of view as the current state is it should not do that, as
> remember that hwsim will "simulate" hardware it should not be able to
> access mac802154 fields (especially when doing receiving of frames) as
> other hardware will only set register bits (as hwsim pib values is
> there for)...
> 
> Still I think it's fine for now.

I see your point, indeed I could have added another PIB attribute
instead of accessing the PHY state.

I am fine doing it in a followup patch if this what you prefer. Shall I
do it?

Thanks,
Miquèl
Miquel Raynal Oct. 15, 2022, 8:59 a.m. UTC | #6
Hi Stefan,

stefan@datenfreihafen.org wrote on Wed, 12 Oct 2022 12:48:06 +0200:

> Hello Miquel.
> 
> This patch has given me some checkpatch wawrnings and errors.
> 
> Commit d9abecc4a0fc ("ieee802154: hwsim: Implement address filtering")
> ----------------------------------------------------------------------
> CHECK: Blank lines aren't necessary after an open brace '{'
> #53: FILE: drivers/net/ieee802154/mac802154_hwsim.c:162:
> +	if (hw->phy->filtering == IEEE802154_FILTERING_4_FRAME_FIELDS) {
> +
> 
> ERROR: code indent should use tabs where possible
> #128: FILE: drivers/net/ieee802154/mac802154_hwsim.c:237:
> +        }$
> 
> WARNING: please, no spaces at the start of a line
> #128: FILE: drivers/net/ieee802154/mac802154_hwsim.c:237:
> +        }$
> 
> total: 1 errors, 1 warnings, 1 checks, 143 lines checked
> 
> I fixed this up in palce for you tp proceed with applying this patches. Just so you are aware.

I'm sorry for these, I focused on getting the feature more than on the
presentation and I forgot to re-run checkpatch after all the copy-paste
handling towards hwsim. Next time I'll fix it myself, don't hesitate to
tell me when this happens ;-)

Thanks,
Miquèl
Alexander Aring Oct. 16, 2022, 12:59 a.m. UTC | #7
Hi,

On Sat, Oct 15, 2022 at 4:59 AM Miquel Raynal <miquel.raynal@bootlin.com> wrote:
>
> Hi Alexander,
>
> aahringo@redhat.com wrote on Mon, 10 Oct 2022 21:21:17 -0400:
>
> > Hi,
> >
> > On Mon, Oct 10, 2022 at 9:13 PM Alexander Aring <aahringo@redhat.com> wrote:
> > >
> > > Hi,
> > >
> > > On Mon, Oct 10, 2022 at 9:04 PM Alexander Aring <aahringo@redhat.com> wrote:
> > > >
> > > > Hi,
> > > >
> > > > On Fri, Oct 7, 2022 at 4:53 AM Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> > > > >
> > > > > We have access to the address filters being theoretically applied, we
> > > > > also have access to the actual filtering level applied, so let's add a
> > > > > proper frame validation sequence in hwsim.
> > > > >
> > > > > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> > > > > ---
> > > > >  drivers/net/ieee802154/mac802154_hwsim.c | 111 ++++++++++++++++++++++-
> > > > >  include/net/ieee802154_netdev.h          |   8 ++
> > > > >  2 files changed, 117 insertions(+), 2 deletions(-)
> > > > >
> > > > > diff --git a/drivers/net/ieee802154/mac802154_hwsim.c b/drivers/net/ieee802154/mac802154_hwsim.c
> > > > > index 458be66b5195..84ee948f35bc 100644
> > > > > --- a/drivers/net/ieee802154/mac802154_hwsim.c
> > > > > +++ b/drivers/net/ieee802154/mac802154_hwsim.c
> > > > > @@ -18,6 +18,7 @@
> > > > >  #include <linux/netdevice.h>
> > > > >  #include <linux/device.h>
> > > > >  #include <linux/spinlock.h>
> > > > > +#include <net/ieee802154_netdev.h>
> > > > >  #include <net/mac802154.h>
> > > > >  #include <net/cfg802154.h>
> > > > >  #include <net/genetlink.h>
> > > > > @@ -139,6 +140,113 @@ static int hwsim_hw_addr_filt(struct ieee802154_hw *hw,
> > > > >         return 0;
> > > > >  }
> > > > >
> > > > > +static void hwsim_hw_receive(struct ieee802154_hw *hw, struct sk_buff *skb,
> > > > > +                            u8 lqi)
> > > > > +{
> > > > > +       struct ieee802154_hdr hdr;
> > > > > +       struct hwsim_phy *phy = hw->priv;
> > > > > +       struct hwsim_pib *pib;
> > > > > +
> > > > > +       rcu_read_lock();
> > > > > +       pib = rcu_dereference(phy->pib);
> > > > > +
> > > > > +       if (!pskb_may_pull(skb, 3)) {
> > > > > +               dev_dbg(hw->parent, "invalid frame\n");
> > > > > +               goto drop;
> > > > > +       }
> > > > > +
> > > > > +       memcpy(&hdr, skb->data, 3);
> > > > > +
> > > > > +       /* Level 4 filtering: Frame fields validity */
> > > > > +       if (hw->phy->filtering == IEEE802154_FILTERING_4_FRAME_FIELDS) {
> > >
> > > I see, there is this big if handling. But it accesses the
> > > hw->phy->filtering value. It should be part of the hwsim pib setting
> > > set by the driver callback. It is a question here of mac802154 layer
> > > setting vs driver layer setting. We should do what the mac802154 tells
> > > the driver to do, this way we do what the mac802154 layer is set to.
> > >
> > > However it's a minor thing and it's okay to do it so...
> >
> > * whereas we never let the driver know at any time of what different
> > filter levels exist _currently_ we have only the promiscuous mode
> > on/off switch which is do nothing or 4_FRAME_FIELDS.
> > It will work for now, changing anything in the mac802154 filtering
> > fields or something will end in probably breakage in this handling. In
> > my point of view as the current state is it should not do that, as
> > remember that hwsim will "simulate" hardware it should not be able to
> > access mac802154 fields (especially when doing receiving of frames) as
> > other hardware will only set register bits (as hwsim pib values is
> > there for)...
> >
> > Still I think it's fine for now.
>
> I see your point, indeed I could have added another PIB attribute
> instead of accessing the PHY state.
>
> I am fine doing it in a followup patch if this what you prefer. Shall I
> do it?

okay, note that you did it right with the address filter patches by
copying them from the drivers-ops.

- Alex
diff mbox series

Patch

diff --git a/drivers/net/ieee802154/mac802154_hwsim.c b/drivers/net/ieee802154/mac802154_hwsim.c
index 458be66b5195..84ee948f35bc 100644
--- a/drivers/net/ieee802154/mac802154_hwsim.c
+++ b/drivers/net/ieee802154/mac802154_hwsim.c
@@ -18,6 +18,7 @@ 
 #include <linux/netdevice.h>
 #include <linux/device.h>
 #include <linux/spinlock.h>
+#include <net/ieee802154_netdev.h>
 #include <net/mac802154.h>
 #include <net/cfg802154.h>
 #include <net/genetlink.h>
@@ -139,6 +140,113 @@  static int hwsim_hw_addr_filt(struct ieee802154_hw *hw,
 	return 0;
 }
 
+static void hwsim_hw_receive(struct ieee802154_hw *hw, struct sk_buff *skb,
+			     u8 lqi)
+{
+	struct ieee802154_hdr hdr;
+	struct hwsim_phy *phy = hw->priv;
+	struct hwsim_pib *pib;
+
+	rcu_read_lock();
+	pib = rcu_dereference(phy->pib);
+
+	if (!pskb_may_pull(skb, 3)) {
+		dev_dbg(hw->parent, "invalid frame\n");
+		goto drop;
+	}
+
+	memcpy(&hdr, skb->data, 3);
+
+	/* Level 4 filtering: Frame fields validity */
+	if (hw->phy->filtering == IEEE802154_FILTERING_4_FRAME_FIELDS) {
+
+		/* 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(hw->parent, "unrecognized frame type 0x%x\n",
+				mac_cb(skb)->type);
+			goto drop;
+		}
+
+		/* b) Drop reserved frame versions */
+		switch (hdr.fc.version) {
+		case IEEE802154_2003_STD:
+		case IEEE802154_2006_STD:
+		case IEEE802154_STD:
+			break;
+		default:
+			dev_dbg(hw->parent,
+				"unrecognized frame version 0x%x\n",
+				hdr.fc.version);
+			goto drop;
+		}
+
+		/* 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 != pib->filt.pan_id &&
+		    mac_cb(skb)->dest.pan_id != cpu_to_le16(IEEE802154_PANID_BROADCAST)) {
+			dev_dbg(hw->parent,
+				"unrecognized PAN ID %04x\n",
+				le16_to_cpu(mac_cb(skb)->dest.pan_id));
+			goto drop;
+		}
+
+		/* d1) Short address constraints */
+		if (mac_cb(skb)->dest.mode == IEEE802154_ADDR_SHORT &&
+		    mac_cb(skb)->dest.short_addr != pib->filt.short_addr &&
+		    mac_cb(skb)->dest.short_addr != cpu_to_le16(IEEE802154_ADDR_BROADCAST)) {
+			dev_dbg(hw->parent,
+				"unrecognized short address %04x\n",
+				le16_to_cpu(mac_cb(skb)->dest.short_addr));
+			goto drop;
+		}
+
+		/* d2) Extended address constraints */
+		if (mac_cb(skb)->dest.mode == IEEE802154_ADDR_LONG &&
+		    mac_cb(skb)->dest.extended_addr != pib->filt.ieee_addr) {
+			dev_dbg(hw->parent,
+				"unrecognized long address 0x%016llx\n",
+				mac_cb(skb)->dest.extended_addr);
+			goto drop;
+		}
+
+		/* 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(hw->parent,
+				"relaying is not supported\n");
+			goto drop;
+		}
+
+		/* e) Beacon frames follow specific PAN ID rules */
+		if (mac_cb(skb)->type == IEEE802154_FC_TYPE_BEACON &&
+		    pib->filt.pan_id != cpu_to_le16(IEEE802154_PANID_BROADCAST) &&
+		    mac_cb(skb)->dest.pan_id != pib->filt.pan_id) {
+			dev_dbg(hw->parent,
+				"invalid beacon PAN ID %04x\n",
+				le16_to_cpu(mac_cb(skb)->dest.pan_id));
+			goto drop;
+		}
+        }
+
+	rcu_read_unlock();
+
+	ieee802154_rx_irqsafe(hw, skb, lqi);
+
+	return;
+
+drop:
+	rcu_read_unlock();
+	kfree_skb(skb);
+}
+
 static int hwsim_hw_xmit(struct ieee802154_hw *hw, struct sk_buff *skb)
 {
 	struct hwsim_phy *current_phy = hw->priv;
@@ -166,8 +274,7 @@  static int hwsim_hw_xmit(struct ieee802154_hw *hw, struct sk_buff *skb)
 
 			einfo = rcu_dereference(e->info);
 			if (newskb)
-				ieee802154_rx_irqsafe(e->endpoint->hw, newskb,
-						      einfo->lqi);
+				hwsim_hw_receive(e->endpoint->hw, newskb, einfo->lqi);
 		}
 	}
 	rcu_read_unlock();
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;