Skip to content

Commit

Permalink
Merge tag 'ieee802154-for-net-next-2022-10-25' of git://git.kernel.or…
Browse files Browse the repository at this point in the history
…g/pub/scm/linux/kernel/git/sschmidt/wpan-next

Stefan Schmidt says:

====================

==
One of the biggest cycles for ieee802154 in a long time. We are landing the
first pieces of a big enhancements in managing PAN's. We might have another pull
request ready for this cycle later on, but I want to get this one out first.

Miquel Raynal added support for sending frames synchronously as a dependency
to handle MLME commands. Also introducing more filtering levels to match with
the needs of a device when scanning or operating as a pan coordinator.
To support development and testing the hwsim driver for ieee802154 was also
enhanced for the new filtering levels and to update the PIB attributes.

Alexander Aring fixed quite a few bugs spotted during reviewing changes. He
also added support for TRAC in the atusb driver to have better failure
handling if the firmware provides the needed information.

Jilin Yuan fixed a comment with a repeated word in it.
==================

Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
davem330 committed Oct 26, 2022
2 parents 9c8ddda + 4161634 commit 34e0b94
Show file tree
Hide file tree
Showing 16 changed files with 695 additions and 205 deletions.
33 changes: 28 additions & 5 deletions drivers/net/ieee802154/atusb.c
Original file line number Diff line number Diff line change
Expand Up @@ -191,15 +191,18 @@ static void atusb_work_urbs(struct work_struct *work)

/* ----- Asynchronous USB -------------------------------------------------- */

static void atusb_tx_done(struct atusb *atusb, u8 seq)
static void atusb_tx_done(struct atusb *atusb, u8 seq, int reason)
{
struct usb_device *usb_dev = atusb->usb_dev;
u8 expect = atusb->tx_ack_seq;

dev_dbg(&usb_dev->dev, "%s (0x%02x/0x%02x)\n", __func__, seq, expect);
if (seq == expect) {
/* TODO check for ifs handling in firmware */
ieee802154_xmit_complete(atusb->hw, atusb->tx_skb, false);
if (reason == IEEE802154_SUCCESS)
ieee802154_xmit_complete(atusb->hw, atusb->tx_skb, false);
else
ieee802154_xmit_error(atusb->hw, atusb->tx_skb, reason);
} else {
/* TODO I experience this case when atusb has a tx complete
* irq before probing, we should fix the firmware it's an
Expand All @@ -215,7 +218,8 @@ static void atusb_in_good(struct urb *urb)
struct usb_device *usb_dev = urb->dev;
struct sk_buff *skb = urb->context;
struct atusb *atusb = SKB_ATUSB(skb);
u8 len, lqi;
int result = IEEE802154_SUCCESS;
u8 len, lqi, trac;

if (!urb->actual_length) {
dev_dbg(&usb_dev->dev, "atusb_in: zero-sized URB ?\n");
Expand All @@ -224,8 +228,27 @@ static void atusb_in_good(struct urb *urb)

len = *skb->data;

if (urb->actual_length == 1) {
atusb_tx_done(atusb, len);
switch (urb->actual_length) {
case 2:
trac = TRAC_MASK(*(skb->data + 1));
switch (trac) {
case TRAC_SUCCESS:
case TRAC_SUCCESS_DATA_PENDING:
/* already IEEE802154_SUCCESS */
break;
case TRAC_CHANNEL_ACCESS_FAILURE:
result = IEEE802154_CHANNEL_ACCESS_FAILURE;
break;
case TRAC_NO_ACK:
result = IEEE802154_NO_ACK;
break;
default:
result = IEEE802154_SYSTEM_ERROR;
}

fallthrough;
case 1:
atusb_tx_done(atusb, len, result);
return;
}

Expand Down
179 changes: 172 additions & 7 deletions drivers/net/ieee802154/mac802154_hwsim.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -47,6 +48,8 @@ static const struct genl_multicast_group hwsim_mcgrps[] = {
struct hwsim_pib {
u8 page;
u8 channel;
struct ieee802154_hw_addr_filt filt;
enum ieee802154_filtering_level filt_level;

struct rcu_head rcu;
};
Expand Down Expand Up @@ -88,24 +91,168 @@ static int hwsim_hw_ed(struct ieee802154_hw *hw, u8 *level)
return 0;
}

static int hwsim_hw_channel(struct ieee802154_hw *hw, u8 page, u8 channel)
static int hwsim_update_pib(struct ieee802154_hw *hw, u8 page, u8 channel,
struct ieee802154_hw_addr_filt *filt,
enum ieee802154_filtering_level filt_level)
{
struct hwsim_phy *phy = hw->priv;
struct hwsim_pib *pib, *pib_old;

pib = kzalloc(sizeof(*pib), GFP_KERNEL);
pib = kzalloc(sizeof(*pib), GFP_ATOMIC);
if (!pib)
return -ENOMEM;

pib_old = rtnl_dereference(phy->pib);

pib->page = page;
pib->channel = channel;
pib->filt.short_addr = filt->short_addr;
pib->filt.pan_id = filt->pan_id;
pib->filt.ieee_addr = filt->ieee_addr;
pib->filt.pan_coord = filt->pan_coord;
pib->filt_level = filt_level;

pib_old = rtnl_dereference(phy->pib);
rcu_assign_pointer(phy->pib, pib);
kfree_rcu(pib_old, rcu);
return 0;
}

static int hwsim_hw_channel(struct ieee802154_hw *hw, u8 page, u8 channel)
{
struct hwsim_phy *phy = hw->priv;
struct hwsim_pib *pib;
int ret;

rcu_read_lock();
pib = rcu_dereference(phy->pib);
ret = hwsim_update_pib(hw, page, channel, &pib->filt, pib->filt_level);
rcu_read_unlock();

return ret;
}

static int hwsim_hw_addr_filt(struct ieee802154_hw *hw,
struct ieee802154_hw_addr_filt *filt,
unsigned long changed)
{
struct hwsim_phy *phy = hw->priv;
struct hwsim_pib *pib;
int ret;

rcu_read_lock();
pib = rcu_dereference(phy->pib);
ret = hwsim_update_pib(hw, pib->page, pib->channel, filt, pib->filt_level);
rcu_read_unlock();

return ret;
}

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 (pib->filt_level == 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;
Expand Down Expand Up @@ -133,8 +280,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();
Expand All @@ -148,6 +294,7 @@ static int hwsim_hw_start(struct ieee802154_hw *hw)
struct hwsim_phy *phy = hw->priv;

phy->suspended = false;

return 0;
}

Expand All @@ -161,7 +308,22 @@ static void hwsim_hw_stop(struct ieee802154_hw *hw)
static int
hwsim_set_promiscuous_mode(struct ieee802154_hw *hw, const bool on)
{
return 0;
enum ieee802154_filtering_level filt_level;
struct hwsim_phy *phy = hw->priv;
struct hwsim_pib *pib;
int ret;

if (on)
filt_level = IEEE802154_FILTERING_NONE;
else
filt_level = IEEE802154_FILTERING_4_FRAME_FIELDS;

rcu_read_lock();
pib = rcu_dereference(phy->pib);
ret = hwsim_update_pib(hw, pib->page, pib->channel, &pib->filt, filt_level);
rcu_read_unlock();

return ret;
}

static const struct ieee802154_ops hwsim_ops = {
Expand All @@ -172,6 +334,7 @@ static const struct ieee802154_ops hwsim_ops = {
.start = hwsim_hw_start,
.stop = hwsim_hw_stop,
.set_promiscuous_mode = hwsim_set_promiscuous_mode,
.set_hw_addr_filt = hwsim_hw_addr_filt,
};

static int hwsim_new_radio_nl(struct sk_buff *msg, struct genl_info *info)
Expand Down Expand Up @@ -788,11 +951,13 @@ static int hwsim_add_one(struct genl_info *info, struct device *dev,
}

pib->channel = 13;
pib->filt.short_addr = cpu_to_le16(IEEE802154_ADDR_BROADCAST);
pib->filt.pan_id = cpu_to_le16(IEEE802154_PANID_BROADCAST);
rcu_assign_pointer(phy->pib, pib);
phy->idx = idx;
INIT_LIST_HEAD(&phy->edges);

hw->flags = IEEE802154_HW_PROMISCUOUS | IEEE802154_HW_RX_DROP_BAD_CKSUM;
hw->flags = IEEE802154_HW_PROMISCUOUS;
hw->parent = dev;

err = ieee802154_register_hw(hw);
Expand Down
9 changes: 3 additions & 6 deletions drivers/net/ieee802154/mcr20a.c
Original file line number Diff line number Diff line change
Expand Up @@ -1233,12 +1233,9 @@ mcr20a_probe(struct spi_device *spi)
}

rst_b = devm_gpiod_get(&spi->dev, "rst_b", GPIOD_OUT_HIGH);
if (IS_ERR(rst_b)) {
ret = PTR_ERR(rst_b);
if (ret != -EPROBE_DEFER)
dev_err(&spi->dev, "Failed to get 'rst_b' gpio: %d", ret);
return ret;
}
if (IS_ERR(rst_b))
return dev_err_probe(&spi->dev, PTR_ERR(rst_b),
"Failed to get 'rst_b' gpio");

/* reset mcr20a */
usleep_range(10, 20);
Expand Down
24 changes: 24 additions & 0 deletions include/linux/ieee802154.h
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,30 @@ enum {
IEEE802154_SYSTEM_ERROR = 0xff,
};

/**
* enum ieee802154_filtering_level - Filtering levels applicable to a PHY
*
* @IEEE802154_FILTERING_NONE: No filtering at all, what is received is
* forwarded to the softMAC
* @IEEE802154_FILTERING_1_FCS: First filtering level, frames with an invalid
* FCS should be dropped
* @IEEE802154_FILTERING_2_PROMISCUOUS: Second filtering level, promiscuous
* mode as described in the spec, identical in terms of filtering to the
* level one on PHY side, but at the MAC level the frame should be
* forwarded to the upper layer directly
* @IEEE802154_FILTERING_3_SCAN: Third filtering level, scan related, where
* only beacons must be processed, all remaining traffic gets dropped
* @IEEE802154_FILTERING_4_FRAME_FIELDS: Fourth filtering level actually
* enforcing the validity of the content of the frame with various checks
*/
enum ieee802154_filtering_level {
IEEE802154_FILTERING_NONE,
IEEE802154_FILTERING_1_FCS,
IEEE802154_FILTERING_2_PROMISCUOUS,
IEEE802154_FILTERING_3_SCAN,
IEEE802154_FILTERING_4_FRAME_FIELDS,
};

/* frame control handling */
#define IEEE802154_FCTL_FTYPE 0x0003
#define IEEE802154_FCTL_ACKREQ 0x0020
Expand Down
Loading

0 comments on commit 34e0b94

Please sign in to comment.