Commit 34e0b945 authored by David S. Miller's avatar David S. Miller
Browse files

Merge tag 'ieee802154-for-net-next-2022-10-25' of...

Merge tag 'ieee802154-for-net-next-2022-10-25' of git://git.kernel.org/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: default avatarDavid S. Miller <davem@davemloft.net>
parents 9c8dddab 4161634b
Loading
Loading
Loading
Loading
+28 −5
Original line number Diff line number Diff line
@@ -191,7 +191,7 @@ 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;
@@ -199,7 +199,10 @@ static void atusb_tx_done(struct atusb *atusb, u8 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 */
		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
@@ -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");
@@ -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;
	}

+172 −7
Original line number Diff line number Diff line
@@ -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>
@@ -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;
};
@@ -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;
@@ -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();
@@ -148,6 +294,7 @@ static int hwsim_hw_start(struct ieee802154_hw *hw)
	struct hwsim_phy *phy = hw->priv;

	phy->suspended = false;

	return 0;
}

@@ -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 = {
@@ -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)
@@ -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);
+3 −6
Original line number Diff line number Diff line
@@ -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);
+24 −0
Original line number Diff line number Diff line
@@ -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
+16 −4
Original line number Diff line number Diff line
@@ -11,7 +11,7 @@

#include <linux/ieee802154.h>
#include <linux/netdevice.h>
#include <linux/mutex.h>
#include <linux/spinlock.h>
#include <linux/bug.h>

#include <net/nl802154.h>
@@ -166,11 +166,14 @@ wpan_phy_cca_cmp(const struct wpan_phy_cca *a, const struct wpan_phy_cca *b)
 *	level setting.
 * @WPAN_PHY_FLAG_CCA_MODE: Indicates that transceiver will support cca mode
 *	setting.
 * @WPAN_PHY_FLAG_STATE_QUEUE_STOPPED: Indicates that the transmit queue was
 *	temporarily stopped.
 */
enum wpan_phy_flags {
	WPAN_PHY_FLAG_TXPOWER		= BIT(1),
	WPAN_PHY_FLAG_CCA_ED_LEVEL	= BIT(2),
	WPAN_PHY_FLAG_CCA_MODE		= BIT(3),
	WPAN_PHY_FLAG_STATE_QUEUE_STOPPED = BIT(4),
};

struct wpan_phy {
@@ -182,7 +185,7 @@ struct wpan_phy {
	 */
	const void *privid;

	u32 flags;
	unsigned long flags;

	/*
	 * This is a PIB according to 802.15.4-2011.
@@ -214,6 +217,17 @@ struct wpan_phy {
	/* the network namespace this phy lives in currently */
	possible_net_t _net;

	/* Transmission monitoring and control */
	spinlock_t queue_lock;
	atomic_t ongoing_txs;
	atomic_t hold_txs;
	wait_queue_head_t sync_txq;

	/* Current filtering level on reception.
	 * Only allowed to be changed if phy is not operational.
	 */
	enum ieee802154_filtering_level filtering;

	char priv[] __aligned(NETDEV_ALIGN);
};

@@ -365,8 +379,6 @@ struct wpan_dev {

	bool lbt;

	bool promiscuous_mode;

	/* fallback for acknowledgment bit setting */
	bool ackreq;
};
Loading