linux-wpan.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH wpan-next 00/11] ieee802154: Associations between devices
@ 2023-06-01 15:48 Miquel Raynal
  2023-06-01 15:48 ` [PATCH wpan-next 01/11] ieee802154: Let PAN IDs be reset Miquel Raynal
                   ` (10 more replies)
  0 siblings, 11 replies; 24+ messages in thread
From: Miquel Raynal @ 2023-06-01 15:48 UTC (permalink / raw)
  To: Alexander Aring, Stefan Schmidt, linux-wpan
  Cc: David S. Miller, Jakub Kicinski, Paolo Abeni, Eric Dumazet,
	netdev, David Girault, Romuald Despres, Frederic Blain,
	Nicolas Schodet, Guilhem Imberton, Thomas Petazzoni,
	Miquel Raynal

Hello,

Sorry for sending this so late I was a bit busy, but here is the next
step. I know there are a lot of patches in this series compared to the
previous ones but it was hard to make smaller. I actually split as much
as I could the commits so the review process should not be too
difficult, thanks to the relative shortness of each diff.

Now that we can discover our peer coordinators or make ourselves
dynamically discoverable, we may use the information about surrounding
devices to create PANs dynamically. This involves of course:
* Requesting an association to a coordinator, waiting for the response
* Sending a disassociation notification to a coordinator
* Receiving an association request when we are coordinator, answering
  the request (for now all devices are accepted up to a limit, to be
  refined)
* Sending a disassociation notification to a child
* Users may request the list of associated devices (the parent and the
  children).

Here are a few example of userspace calls that can be made:
iwpan dev <dev> associate pan_id 2 coord $COORD
iwpan dev <dev> list_associations
iwpan dev <dev> disassociate ext_addr $COORD

I used a small using hwsim to scan for a coordinator, associate with
it, look at the associations on both sides, disassociate from it and
check the associations again:
./assoc-demo
*** Scan ***
PAN 0x0002 (on wpan1)
	coordinator 0x060f3b35169a498f
	page 0
	channel 13
	preamble code 0
	mean prf 0
	superframe spec. 0xcf11
	LQI ff
*** End of scan ***
Associating wpan1 with coord0 0x060f3b35169a498f...
Dumping coord0 assoc:
child : 0x0b6f / 0xba7633ae47ccfb21
Dumping wpan1 assoc:
parent: 0xffff / 0x060f3b35169a498f
Disassociating from wpan1
Dumping coord0 assoc:
Dumping wpan1 assoc:

I could also successfully interact with a smaller device running Zephir,
using its command line interface to associate and then disassociate from
the Linux coordinator.

Thanks!
Miquèl

Miquel Raynal (11):
  ieee802154: Let PAN IDs be reset
  ieee802154: Internal PAN management
  ieee802154: Add support for user association requests
  mac802154: Handle associating
  ieee802154: Add support for user disassociation requests
  mac802154: Handle disassociations
  mac802154: Handle association requests from peers
  ieee802154: Add support for limiting the number of associated devices
  mac802154: Follow the number of associated devices
  mac802154: Handle disassociation notifications from peers
  ieee802154: Give the user the association list

 include/linux/ieee802154.h      |   1 +
 include/net/cfg802154.h         |  70 ++++++
 include/net/ieee802154_netdev.h |  60 +++++
 include/net/nl802154.h          |  22 +-
 net/ieee802154/Makefile         |   2 +-
 net/ieee802154/core.c           |  25 ++
 net/ieee802154/nl802154.c       | 229 +++++++++++++++++-
 net/ieee802154/pan.c            | 103 ++++++++
 net/ieee802154/rdev-ops.h       |  30 +++
 net/ieee802154/trace.h          |  38 +++
 net/mac802154/cfg.c             | 175 ++++++++++++++
 net/mac802154/ieee802154_i.h    |  27 +++
 net/mac802154/main.c            |   2 +
 net/mac802154/rx.c              |  25 ++
 net/mac802154/scan.c            | 400 ++++++++++++++++++++++++++++++++
 15 files changed, 1196 insertions(+), 13 deletions(-)
 create mode 100644 net/ieee802154/pan.c

-- 
2.34.1


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH wpan-next 01/11] ieee802154: Let PAN IDs be reset
  2023-06-01 15:48 [PATCH wpan-next 00/11] ieee802154: Associations between devices Miquel Raynal
@ 2023-06-01 15:48 ` Miquel Raynal
  2023-06-01 15:48 ` [PATCH wpan-next 02/11] ieee802154: Internal PAN management Miquel Raynal
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 24+ messages in thread
From: Miquel Raynal @ 2023-06-01 15:48 UTC (permalink / raw)
  To: Alexander Aring, Stefan Schmidt, linux-wpan
  Cc: David S. Miller, Jakub Kicinski, Paolo Abeni, Eric Dumazet,
	netdev, David Girault, Romuald Despres, Frederic Blain,
	Nicolas Schodet, Guilhem Imberton, Thomas Petazzoni,
	Miquel Raynal

Soon association and disassociation will be implemented, which will
require to be able to either change the PAN ID from 0xFFFF to a real
value when association succeeded, or to reset the PAN ID to 0xFFFF upon
disassociation. Let's allow to do that manually for now.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 net/ieee802154/nl802154.c | 10 ----------
 1 file changed, 10 deletions(-)

diff --git a/net/ieee802154/nl802154.c b/net/ieee802154/nl802154.c
index d610c1886160..46ac6f599fe1 100644
--- a/net/ieee802154/nl802154.c
+++ b/net/ieee802154/nl802154.c
@@ -1087,16 +1087,6 @@ static int nl802154_set_pan_id(struct sk_buff *skb, struct genl_info *info)
 
 	pan_id = nla_get_le16(info->attrs[NL802154_ATTR_PAN_ID]);
 
-	/* TODO
-	 * I am not sure about to check here on broadcast pan_id.
-	 * Broadcast is a valid setting, comment from 802.15.4:
-	 * If this value is 0xffff, the device is not associated.
-	 *
-	 * This could useful to simple deassociate an device.
-	 */
-	if (pan_id == cpu_to_le16(IEEE802154_PAN_ID_BROADCAST))
-		return -EINVAL;
-
 	return rdev_set_pan_id(rdev, wpan_dev, pan_id);
 }
 
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH wpan-next 02/11] ieee802154: Internal PAN management
  2023-06-01 15:48 [PATCH wpan-next 00/11] ieee802154: Associations between devices Miquel Raynal
  2023-06-01 15:48 ` [PATCH wpan-next 01/11] ieee802154: Let PAN IDs be reset Miquel Raynal
@ 2023-06-01 15:48 ` Miquel Raynal
  2023-06-01 15:48 ` [PATCH wpan-next 03/11] ieee802154: Add support for user association requests Miquel Raynal
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 24+ messages in thread
From: Miquel Raynal @ 2023-06-01 15:48 UTC (permalink / raw)
  To: Alexander Aring, Stefan Schmidt, linux-wpan
  Cc: David S. Miller, Jakub Kicinski, Paolo Abeni, Eric Dumazet,
	netdev, David Girault, Romuald Despres, Frederic Blain,
	Nicolas Schodet, Guilhem Imberton, Thomas Petazzoni,
	Miquel Raynal

Introduce structures to describe peer devices in a PAN as well as a few
related helpers. We basically care about:
- Our unique parent after associating with a coordinator.
- Peer devices, children, which successfully associated with us.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 include/net/cfg802154.h | 46 ++++++++++++++++++++++++++++
 net/ieee802154/Makefile |  2 +-
 net/ieee802154/core.c   |  2 ++
 net/ieee802154/pan.c    | 66 +++++++++++++++++++++++++++++++++++++++++
 4 files changed, 115 insertions(+), 1 deletion(-)
 create mode 100644 net/ieee802154/pan.c

diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h
index e00057984489..c67adf584672 100644
--- a/include/net/cfg802154.h
+++ b/include/net/cfg802154.h
@@ -302,6 +302,22 @@ struct ieee802154_coord_desc {
 	bool gts_permit;
 };
 
+/**
+ * struct ieee802154_pan_device - PAN device information
+ * @pan_id: the PAN ID of this device
+ * @mode: the preferred mode to reach the device
+ * @short_addr: the short address of this device
+ * @extended_addr: the extended address of this device
+ * @node: the list node
+ */
+struct ieee802154_pan_device {
+	__le16 pan_id;
+	u8 mode;
+	__le16 short_addr;
+	__le64 extended_addr;
+	struct list_head node;
+};
+
 /**
  * struct cfg802154_scan_request - Scan request
  *
@@ -477,6 +493,11 @@ struct wpan_dev {
 
 	/* fallback for acknowledgment bit setting */
 	bool ackreq;
+
+	/* Associations */
+	struct mutex association_lock;
+	struct ieee802154_pan_device *parent;
+	struct list_head children;
 };
 
 #define to_phy(_dev)	container_of(_dev, struct wpan_phy, dev)
@@ -528,4 +549,29 @@ static inline const char *wpan_phy_name(struct wpan_phy *phy)
 void ieee802154_configure_durations(struct wpan_phy *phy,
 				    unsigned int page, unsigned int channel);
 
+/**
+ * cfg802154_device_is_associated - Checks whether we are associated to any device
+ * @wpan_dev: the wpan device
+ */
+bool cfg802154_device_is_associated(struct wpan_dev *wpan_dev);
+
+/**
+ * cfg802154_device_is_parent - Checks if a device is our coordinator
+ * @wpan_dev: the wpan device
+ * @target: the expected parent
+ * @return: true if @target is our coordinator
+ */
+bool cfg802154_device_is_parent(struct wpan_dev *wpan_dev,
+				struct ieee802154_addr *target);
+
+/**
+ * cfg802154_device_is_child - Checks whether a device is associated to us
+ * @wpan_dev: the wpan device
+ * @target: the expected child
+ * @return: the PAN device
+ */
+struct ieee802154_pan_device *
+cfg802154_device_is_child(struct wpan_dev *wpan_dev,
+			  struct ieee802154_addr *target);
+
 #endif /* __NET_CFG802154_H */
diff --git a/net/ieee802154/Makefile b/net/ieee802154/Makefile
index f05b7bdae2aa..7bce67673e83 100644
--- a/net/ieee802154/Makefile
+++ b/net/ieee802154/Makefile
@@ -4,7 +4,7 @@ obj-$(CONFIG_IEEE802154_SOCKET) += ieee802154_socket.o
 obj-y += 6lowpan/
 
 ieee802154-y := netlink.o nl-mac.o nl-phy.o nl_policy.o core.o \
-                header_ops.o sysfs.o nl802154.o trace.o
+                header_ops.o sysfs.o nl802154.o trace.o pan.o
 ieee802154_socket-y := socket.o
 
 CFLAGS_trace.o := -I$(src)
diff --git a/net/ieee802154/core.c b/net/ieee802154/core.c
index 57546e07e06a..cd69bdbfd59f 100644
--- a/net/ieee802154/core.c
+++ b/net/ieee802154/core.c
@@ -276,6 +276,8 @@ static int cfg802154_netdev_notifier_call(struct notifier_block *nb,
 		wpan_dev->identifier = ++rdev->wpan_dev_id;
 		list_add_rcu(&wpan_dev->list, &rdev->wpan_dev_list);
 		rdev->devlist_generation++;
+		mutex_init(&wpan_dev->association_lock);
+		INIT_LIST_HEAD(&wpan_dev->children);
 
 		wpan_dev->netdev = dev;
 		break;
diff --git a/net/ieee802154/pan.c b/net/ieee802154/pan.c
new file mode 100644
index 000000000000..e2a12a42ba2b
--- /dev/null
+++ b/net/ieee802154/pan.c
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * IEEE 802.15.4 PAN management
+ *
+ * Copyright (C) 2021 Qorvo US, Inc
+ * Authors:
+ *   - David Girault <david.girault@qorvo.com>
+ *   - Miquel Raynal <miquel.raynal@bootlin.com>
+ */
+
+#include <linux/kernel.h>
+#include <net/cfg802154.h>
+#include <net/af_ieee802154.h>
+
+static bool cfg802154_same_addr(struct ieee802154_pan_device *a,
+				struct ieee802154_addr *b)
+{
+	if (!a || !b)
+		return false;
+
+	switch (b->mode) {
+	case IEEE802154_ADDR_SHORT:
+		return a->short_addr == b->short_addr;
+	case IEEE802154_ADDR_LONG:
+		return a->extended_addr == b->extended_addr;
+	default:
+		return false;
+	}
+}
+
+bool cfg802154_device_is_associated(struct wpan_dev *wpan_dev)
+{
+	bool is_assoc;
+
+	mutex_lock(&wpan_dev->association_lock);
+	is_assoc = !list_empty(&wpan_dev->children) || wpan_dev->parent;
+	mutex_unlock(&wpan_dev->association_lock);
+
+	return is_assoc;
+}
+
+bool cfg802154_device_is_parent(struct wpan_dev *wpan_dev,
+				struct ieee802154_addr *target)
+{
+	lockdep_assert_held(&wpan_dev->association_lock);
+
+	if (cfg802154_same_addr(wpan_dev->parent, target))
+		return true;
+
+	return false;
+}
+
+struct ieee802154_pan_device *
+cfg802154_device_is_child(struct wpan_dev *wpan_dev,
+			  struct ieee802154_addr *target)
+{
+	struct ieee802154_pan_device *child;
+
+	lockdep_assert_held(&wpan_dev->association_lock);
+
+	list_for_each_entry(child, &wpan_dev->children, node)
+		if (cfg802154_same_addr(child, target))
+			return child;
+
+	return NULL;
+}
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH wpan-next 03/11] ieee802154: Add support for user association requests
  2023-06-01 15:48 [PATCH wpan-next 00/11] ieee802154: Associations between devices Miquel Raynal
  2023-06-01 15:48 ` [PATCH wpan-next 01/11] ieee802154: Let PAN IDs be reset Miquel Raynal
  2023-06-01 15:48 ` [PATCH wpan-next 02/11] ieee802154: Internal PAN management Miquel Raynal
@ 2023-06-01 15:48 ` Miquel Raynal
  2023-06-01 15:48 ` [PATCH wpan-next 04/11] mac802154: Handle associating Miquel Raynal
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 24+ messages in thread
From: Miquel Raynal @ 2023-06-01 15:48 UTC (permalink / raw)
  To: Alexander Aring, Stefan Schmidt, linux-wpan
  Cc: David S. Miller, Jakub Kicinski, Paolo Abeni, Eric Dumazet,
	netdev, David Girault, Romuald Despres, Frederic Blain,
	Nicolas Schodet, Guilhem Imberton, Thomas Petazzoni,
	Miquel Raynal

Users may decide to associate with a peer, which becomes our parent
coordinator. Let's add the necessary netlink support for this.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 include/net/cfg802154.h         |  4 +++
 include/net/ieee802154_netdev.h | 38 +++++++++++++++++++++++++++++
 include/net/nl802154.h          |  1 +
 net/ieee802154/nl802154.c       | 43 +++++++++++++++++++++++++++++++++
 net/ieee802154/rdev-ops.h       | 15 ++++++++++++
 net/ieee802154/trace.h          | 19 +++++++++++++++
 6 files changed, 120 insertions(+)

diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h
index c67adf584672..3b9d65455b9a 100644
--- a/include/net/cfg802154.h
+++ b/include/net/cfg802154.h
@@ -20,6 +20,7 @@ struct wpan_phy;
 struct wpan_phy_cca;
 struct cfg802154_scan_request;
 struct cfg802154_beacon_request;
+struct ieee802154_addr;
 
 #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
 struct ieee802154_llsec_device_key;
@@ -77,6 +78,9 @@ struct cfg802154_ops {
 				struct cfg802154_beacon_request *request);
 	int	(*stop_beacons)(struct wpan_phy *wpan_phy,
 				struct wpan_dev *wpan_dev);
+	int	(*associate)(struct wpan_phy *wpan_phy,
+			     struct wpan_dev *wpan_dev,
+			     struct ieee802154_addr *coord);
 #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
 	void	(*get_llsec_table)(struct wpan_phy *wpan_phy,
 				   struct wpan_dev *wpan_dev,
diff --git a/include/net/ieee802154_netdev.h b/include/net/ieee802154_netdev.h
index 063313df447d..ca8c827d0d7f 100644
--- a/include/net/ieee802154_netdev.h
+++ b/include/net/ieee802154_netdev.h
@@ -125,6 +125,30 @@ struct ieee802154_hdr_fc {
 #endif
 };
 
+struct ieee802154_assoc_req_pl {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+	u8 reserved1:1,
+	   device_type:1,
+	   power_source:1,
+	   rx_on_when_idle:1,
+	   assoc_type:1,
+	   reserved2:1,
+	   security_cap:1,
+	   alloc_addr:1;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+	u8 alloc_addr:1,
+	   security_cap:1,
+	   reserved2:1,
+	   assoc_type:1,
+	   rx_on_when_idle:1,
+	   power_source:1,
+	   device_type:1,
+	   reserved1:1;
+#else
+#error	"Please fix <asm/byteorder.h>"
+#endif
+} __packed;
+
 enum ieee802154_frame_version {
 	IEEE802154_2003_STD,
 	IEEE802154_2006_STD,
@@ -140,6 +164,14 @@ enum ieee802154_addressing_mode {
 	IEEE802154_EXTENDED_ADDRESSING,
 };
 
+enum ieee802154_association_status {
+	IEEE802154_ASSOCIATION_SUCCESSFUL = 0x00,
+	IEEE802154_PAN_AT_CAPACITY = 0x01,
+	IEEE802154_PAN_ACCESS_DENIED = 0x02,
+	IEEE802154_HOPPING_SEQUENCE_OFFSET_DUP = 0x03,
+	IEEE802154_FAST_ASSOCIATION_SUCCESSFUL = 0x80,
+};
+
 struct ieee802154_hdr {
 	struct ieee802154_hdr_fc fc;
 	u8 seq;
@@ -163,6 +195,12 @@ struct ieee802154_beacon_req_frame {
 	struct ieee802154_mac_cmd_pl mac_pl;
 };
 
+struct ieee802154_association_req_frame {
+	struct ieee802154_hdr mhr;
+	struct ieee802154_mac_cmd_pl mac_pl;
+	struct ieee802154_assoc_req_pl assoc_req_pl;
+};
+
 /* pushes hdr onto the skb. fields of hdr->fc that can be calculated from
  * the contents of hdr will be, and the actual value of those bits in
  * hdr->fc will be ignored. this includes the INTRA_PAN bit and the frame
diff --git a/include/net/nl802154.h b/include/net/nl802154.h
index 8cd9d141f5af..830e1c51d3df 100644
--- a/include/net/nl802154.h
+++ b/include/net/nl802154.h
@@ -78,6 +78,7 @@ enum nl802154_commands {
 	NL802154_CMD_SCAN_DONE,
 	NL802154_CMD_SEND_BEACONS,
 	NL802154_CMD_STOP_BEACONS,
+	NL802154_CMD_ASSOCIATE,
 
 	/* add new commands above here */
 
diff --git a/net/ieee802154/nl802154.c b/net/ieee802154/nl802154.c
index 46ac6f599fe1..2c28e0e9fdda 100644
--- a/net/ieee802154/nl802154.c
+++ b/net/ieee802154/nl802154.c
@@ -1628,6 +1628,41 @@ nl802154_stop_beacons(struct sk_buff *skb, struct genl_info *info)
 	return rdev_stop_beacons(rdev, wpan_dev);
 }
 
+static int nl802154_associate(struct sk_buff *skb, struct genl_info *info)
+{
+	struct cfg802154_registered_device *rdev = info->user_ptr[0];
+	struct net_device *dev = info->user_ptr[1];
+	struct wpan_dev *wpan_dev;
+	struct wpan_phy *wpan_phy;
+	struct ieee802154_addr coord;
+	int err;
+
+	wpan_dev = dev->ieee802154_ptr;
+	wpan_phy = &rdev->wpan_phy;
+
+	if (wpan_phy->flags & WPAN_PHY_FLAG_DATAGRAMS_ONLY) {
+		NL_SET_ERR_MSG(info->extack, "PHY only supports datagrams");
+		return -EOPNOTSUPP;
+	}
+
+	if (!info->attrs[NL802154_ATTR_PAN_ID] ||
+	    !info->attrs[NL802154_ATTR_EXTENDED_ADDR])
+		return -EINVAL;
+
+	coord.pan_id = nla_get_le16(info->attrs[NL802154_ATTR_PAN_ID]);
+	coord.mode = IEEE802154_ADDR_LONG;
+	coord.extended_addr = nla_get_le64(info->attrs[NL802154_ATTR_EXTENDED_ADDR]);
+
+	mutex_lock(&wpan_dev->association_lock);
+	err = rdev_associate(rdev, wpan_dev, &coord);
+	mutex_unlock(&wpan_dev->association_lock);
+	if (err)
+		pr_err("Association with PAN ID 0x%x failed (%d)\n",
+		       le16_to_cpu(coord.pan_id), err);
+
+	return err;
+}
+
 #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
 static const struct nla_policy nl802154_dev_addr_policy[NL802154_DEV_ADDR_ATTR_MAX + 1] = {
 	[NL802154_DEV_ADDR_ATTR_PAN_ID] = { .type = NLA_U16 },
@@ -2749,6 +2784,14 @@ static const struct genl_ops nl802154_ops[] = {
 				  NL802154_FLAG_CHECK_NETDEV_UP |
 				  NL802154_FLAG_NEED_RTNL,
 	},
+	{
+		.cmd = NL802154_CMD_ASSOCIATE,
+		.doit = nl802154_associate,
+		.flags = GENL_ADMIN_PERM,
+		.internal_flags = NL802154_FLAG_NEED_NETDEV |
+				  NL802154_FLAG_CHECK_NETDEV_UP |
+				  NL802154_FLAG_NEED_RTNL,
+	},
 #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
 	{
 		.cmd = NL802154_CMD_SET_SEC_PARAMS,
diff --git a/net/ieee802154/rdev-ops.h b/net/ieee802154/rdev-ops.h
index 5eaae15c610e..4843d52f1ee0 100644
--- a/net/ieee802154/rdev-ops.h
+++ b/net/ieee802154/rdev-ops.h
@@ -265,6 +265,21 @@ static inline int rdev_stop_beacons(struct cfg802154_registered_device *rdev,
 	return ret;
 }
 
+static inline int rdev_associate(struct cfg802154_registered_device *rdev,
+				 struct wpan_dev *wpan_dev,
+				 struct ieee802154_addr *coord)
+{
+	int ret;
+
+	if (!rdev->ops->associate)
+		return -EOPNOTSUPP;
+
+	trace_802154_rdev_associate(&rdev->wpan_phy, wpan_dev, coord);
+	ret = rdev->ops->associate(&rdev->wpan_phy, wpan_dev, coord);
+	trace_802154_rdev_return_int(&rdev->wpan_phy, ret);
+	return ret;
+}
+
 #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
 /* TODO this is already a nl802154, so move into ieee802154 */
 static inline void
diff --git a/net/ieee802154/trace.h b/net/ieee802154/trace.h
index e5d8439b9e45..fb24be6bfb03 100644
--- a/net/ieee802154/trace.h
+++ b/net/ieee802154/trace.h
@@ -356,6 +356,25 @@ DEFINE_EVENT(802154_wdev_template, 802154_rdev_stop_beacons,
 	TP_ARGS(wpan_phy, wpan_dev)
 );
 
+TRACE_EVENT(802154_rdev_associate,
+	TP_PROTO(struct wpan_phy *wpan_phy,
+		 struct wpan_dev *wpan_dev,
+		 struct ieee802154_addr *coord),
+	TP_ARGS(wpan_phy, wpan_dev, coord),
+	TP_STRUCT__entry(
+		WPAN_PHY_ENTRY
+		WPAN_DEV_ENTRY
+		__field(__le64, addr)
+	),
+	TP_fast_assign(
+		WPAN_PHY_ASSIGN;
+		WPAN_DEV_ASSIGN;
+		__entry->addr = coord->extended_addr;
+	),
+	TP_printk(WPAN_PHY_PR_FMT ", " WPAN_DEV_PR_FMT ", associating with: 0x%llx",
+		  WPAN_PHY_PR_ARG, WPAN_DEV_PR_ARG, __entry->addr)
+);
+
 TRACE_EVENT(802154_rdev_return_int,
 	TP_PROTO(struct wpan_phy *wpan_phy, int ret),
 	TP_ARGS(wpan_phy, ret),
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH wpan-next 04/11] mac802154: Handle associating
  2023-06-01 15:48 [PATCH wpan-next 00/11] ieee802154: Associations between devices Miquel Raynal
                   ` (2 preceding siblings ...)
  2023-06-01 15:48 ` [PATCH wpan-next 03/11] ieee802154: Add support for user association requests Miquel Raynal
@ 2023-06-01 15:48 ` Miquel Raynal
  2023-06-02 15:54   ` Simon Horman
  2023-06-03 10:09   ` Alexander Aring
  2023-06-01 15:48 ` [PATCH wpan-next 05/11] ieee802154: Add support for user disassociation requests Miquel Raynal
                   ` (6 subsequent siblings)
  10 siblings, 2 replies; 24+ messages in thread
From: Miquel Raynal @ 2023-06-01 15:48 UTC (permalink / raw)
  To: Alexander Aring, Stefan Schmidt, linux-wpan
  Cc: David S. Miller, Jakub Kicinski, Paolo Abeni, Eric Dumazet,
	netdev, David Girault, Romuald Despres, Frederic Blain,
	Nicolas Schodet, Guilhem Imberton, Thomas Petazzoni,
	Miquel Raynal

Joining a PAN officially goes by associating with a coordinator. This
coordinator may have been discovered thanks to the beacons it sent in
the past. Add support to the MAC layer for these associations, which
require:
- Sending an association request
- Receiving an association response

The association response contains the association status, eventually a
reason if the association was unsuccessful, and finally a short address
that we should use for intra-PAN communication from now on, if we
required one (which is the default, and not yet configurable).

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 include/linux/ieee802154.h      |   1 +
 include/net/cfg802154.h         |   1 +
 include/net/ieee802154_netdev.h |   5 ++
 net/ieee802154/core.c           |  14 ++++
 net/mac802154/cfg.c             |  72 ++++++++++++++++++
 net/mac802154/ieee802154_i.h    |  19 +++++
 net/mac802154/main.c            |   2 +
 net/mac802154/rx.c              |   9 +++
 net/mac802154/scan.c            | 127 ++++++++++++++++++++++++++++++++
 9 files changed, 250 insertions(+)

diff --git a/include/linux/ieee802154.h b/include/linux/ieee802154.h
index 140f61ec0f5f..c72bd76cac1b 100644
--- a/include/linux/ieee802154.h
+++ b/include/linux/ieee802154.h
@@ -37,6 +37,7 @@
 					 IEEE802154_FCS_LEN)
 
 #define IEEE802154_PAN_ID_BROADCAST	0xffff
+#define IEEE802154_ADDR_LONG_BROADCAST	0xffffffffffffffffULL
 #define IEEE802154_ADDR_SHORT_BROADCAST	0xffff
 #define IEEE802154_ADDR_SHORT_UNSPEC	0xfffe
 
diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h
index 3b9d65455b9a..dd0964d351cd 100644
--- a/include/net/cfg802154.h
+++ b/include/net/cfg802154.h
@@ -502,6 +502,7 @@ struct wpan_dev {
 	struct mutex association_lock;
 	struct ieee802154_pan_device *parent;
 	struct list_head children;
+	unsigned int association_generation;
 };
 
 #define to_phy(_dev)	container_of(_dev, struct wpan_phy, dev)
diff --git a/include/net/ieee802154_netdev.h b/include/net/ieee802154_netdev.h
index ca8c827d0d7f..e26ffd079556 100644
--- a/include/net/ieee802154_netdev.h
+++ b/include/net/ieee802154_netdev.h
@@ -149,6 +149,11 @@ struct ieee802154_assoc_req_pl {
 #endif
 } __packed;
 
+struct ieee802154_assoc_resp_pl {
+	__le16 short_addr;
+	u8 status;
+} __packed;
+
 enum ieee802154_frame_version {
 	IEEE802154_2003_STD,
 	IEEE802154_2006_STD,
diff --git a/net/ieee802154/core.c b/net/ieee802154/core.c
index cd69bdbfd59f..8bf01bb7e858 100644
--- a/net/ieee802154/core.c
+++ b/net/ieee802154/core.c
@@ -198,6 +198,18 @@ void wpan_phy_free(struct wpan_phy *phy)
 }
 EXPORT_SYMBOL(wpan_phy_free);
 
+static void cfg802154_free_peer_structures(struct wpan_dev *wpan_dev)
+{
+	mutex_lock(&wpan_dev->association_lock);
+
+	if (wpan_dev->parent)
+		kfree(wpan_dev->parent);
+
+	wpan_dev->association_generation++;
+
+	mutex_unlock(&wpan_dev->association_lock);
+}
+
 int cfg802154_switch_netns(struct cfg802154_registered_device *rdev,
 			   struct net *net)
 {
@@ -293,6 +305,8 @@ static int cfg802154_netdev_notifier_call(struct notifier_block *nb,
 		rdev->opencount++;
 		break;
 	case NETDEV_UNREGISTER:
+		cfg802154_free_peer_structures(wpan_dev);
+
 		/* It is possible to get NETDEV_UNREGISTER
 		 * multiple times. To detect that, check
 		 * that the interface is still on the list
diff --git a/net/mac802154/cfg.c b/net/mac802154/cfg.c
index 5c3cb019f751..89112d2bcee7 100644
--- a/net/mac802154/cfg.c
+++ b/net/mac802154/cfg.c
@@ -315,6 +315,77 @@ static int mac802154_stop_beacons(struct wpan_phy *wpan_phy,
 	return mac802154_stop_beacons_locked(local, sdata);
 }
 
+static int mac802154_associate(struct wpan_phy *wpan_phy,
+			       struct wpan_dev *wpan_dev,
+			       struct ieee802154_addr *coord)
+{
+	struct ieee802154_local *local = wpan_phy_priv(wpan_phy);
+	u64 ceaddr = swab64((__force u64)coord->extended_addr);
+	struct ieee802154_sub_if_data *sdata;
+	struct ieee802154_pan_device *parent;
+	__le16 short_addr;
+	int ret;
+
+	ASSERT_RTNL();
+
+	sdata = IEEE802154_WPAN_DEV_TO_SUB_IF(wpan_dev);
+
+	if (wpan_dev->parent) {
+		dev_err(&sdata->dev->dev,
+			"Device %8phC is already associated\n", &ceaddr);
+		return -EPERM;
+	}
+
+	parent = kzalloc(sizeof(*parent), GFP_KERNEL);
+	if (!parent)
+		return -ENOMEM;
+
+	parent->pan_id = coord->pan_id;
+	parent->mode = coord->mode;
+	if (parent->mode == IEEE802154_SHORT_ADDRESSING) {
+		parent->short_addr = coord->short_addr;
+		parent->extended_addr = cpu_to_le64(IEEE802154_ADDR_LONG_BROADCAST);
+	} else {
+		parent->extended_addr = coord->extended_addr;
+		parent->short_addr = cpu_to_le16(IEEE802154_ADDR_SHORT_BROADCAST);
+	}
+
+	/* Set the PAN ID hardware address filter beforehand to avoid dropping
+	 * the association response with a destination PAN ID field set to the
+	 * "new" PAN ID.
+	 */
+	if (local->hw.flags & IEEE802154_HW_AFILT) {
+		ret = drv_set_pan_id(local, coord->pan_id);
+		if (ret < 0)
+			goto free_parent;
+	}
+
+	ret = mac802154_perform_association(sdata, parent, &short_addr);
+	if (ret)
+		goto reset_panid;
+
+	if (local->hw.flags & IEEE802154_HW_AFILT) {
+		ret = drv_set_short_addr(local, short_addr);
+		if (ret < 0)
+			goto reset_panid;
+	}
+
+	wpan_dev->pan_id = coord->pan_id;
+	wpan_dev->short_addr = short_addr;
+	wpan_dev->parent = parent;
+	wpan_dev->association_generation++;
+
+	return 0;
+
+reset_panid:
+	if (local->hw.flags & IEEE802154_HW_AFILT)
+		drv_set_pan_id(local, IEEE802154_PAN_ID_BROADCAST);
+
+free_parent:
+	kfree(parent);
+	return ret;
+}
+
 #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
 static void
 ieee802154_get_llsec_table(struct wpan_phy *wpan_phy,
@@ -526,6 +597,7 @@ const struct cfg802154_ops mac802154_config_ops = {
 	.abort_scan = mac802154_abort_scan,
 	.send_beacons = mac802154_send_beacons,
 	.stop_beacons = mac802154_stop_beacons,
+	.associate = mac802154_associate,
 #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
 	.get_llsec_table = ieee802154_get_llsec_table,
 	.lock_llsec_table = ieee802154_lock_llsec_table,
diff --git a/net/mac802154/ieee802154_i.h b/net/mac802154/ieee802154_i.h
index c347ec9ff8c9..fff67676b400 100644
--- a/net/mac802154/ieee802154_i.h
+++ b/net/mac802154/ieee802154_i.h
@@ -24,6 +24,7 @@
 enum ieee802154_ongoing {
 	IEEE802154_IS_SCANNING = BIT(0),
 	IEEE802154_IS_BEACONING = BIT(1),
+	IEEE802154_IS_ASSOCIATING = BIT(2),
 };
 
 /* mac802154 device private data */
@@ -74,6 +75,13 @@ struct ieee802154_local {
 	struct list_head rx_mac_cmd_list;
 	struct work_struct rx_mac_cmd_work;
 
+	/* Association */
+	struct ieee802154_pan_device *assoc_dev;
+	struct completion assoc_done;
+	__le16 assoc_addr;
+	u8 assoc_status;
+	struct work_struct assoc_work;
+
 	bool started;
 	bool suspended;
 	unsigned long ongoing;
@@ -296,6 +304,17 @@ static inline bool mac802154_is_beaconing(struct ieee802154_local *local)
 
 void mac802154_rx_mac_cmd_worker(struct work_struct *work);
 
+int mac802154_perform_association(struct ieee802154_sub_if_data *sdata,
+				  struct ieee802154_pan_device *coord,
+				  __le16 *short_addr);
+int mac802154_process_association_resp(struct ieee802154_sub_if_data *sdata,
+				       struct sk_buff *skb);
+
+static inline bool mac802154_is_associating(struct ieee802154_local *local)
+{
+	return test_bit(IEEE802154_IS_ASSOCIATING, &local->ongoing);
+}
+
 /* interface handling */
 int ieee802154_iface_init(void);
 void ieee802154_iface_exit(void);
diff --git a/net/mac802154/main.c b/net/mac802154/main.c
index 357ece67432b..9ab7396668d2 100644
--- a/net/mac802154/main.c
+++ b/net/mac802154/main.c
@@ -103,6 +103,8 @@ ieee802154_alloc_hw(size_t priv_data_len, const struct ieee802154_ops *ops)
 	INIT_DELAYED_WORK(&local->beacon_work, mac802154_beacon_worker);
 	INIT_WORK(&local->rx_mac_cmd_work, mac802154_rx_mac_cmd_worker);
 
+	init_completion(&local->assoc_done);
+
 	/* init supported flags with 802.15.4 default ranges */
 	phy->supported.max_minbe = 8;
 	phy->supported.min_maxbe = 3;
diff --git a/net/mac802154/rx.c b/net/mac802154/rx.c
index e2434b4fe514..d0e08613a36b 100644
--- a/net/mac802154/rx.c
+++ b/net/mac802154/rx.c
@@ -93,6 +93,15 @@ void mac802154_rx_mac_cmd_worker(struct work_struct *work)
 
 		queue_delayed_work(local->mac_wq, &local->beacon_work, 0);
 		break;
+
+	case IEEE802154_CMD_ASSOCIATION_RESP:
+		dev_dbg(&mac_pkt->sdata->dev->dev, "processing ASSOC RESP\n");
+		if (!mac802154_is_associating(local))
+			break;
+
+		mac802154_process_association_resp(mac_pkt->sdata, mac_pkt->skb);
+		break;
+
 	default:
 		break;
 	}
diff --git a/net/mac802154/scan.c b/net/mac802154/scan.c
index d9658f2c4ae6..5dd50e1ce329 100644
--- a/net/mac802154/scan.c
+++ b/net/mac802154/scan.c
@@ -510,3 +510,130 @@ int mac802154_send_beacons_locked(struct ieee802154_sub_if_data *sdata,
 
 	return 0;
 }
+
+int mac802154_perform_association(struct ieee802154_sub_if_data *sdata,
+				  struct ieee802154_pan_device *coord,
+				  __le16 *short_addr)
+{
+	u64 ceaddr = swab64((__force u64)coord->extended_addr);
+	struct ieee802154_association_req_frame frame = {};
+	struct ieee802154_local *local = sdata->local;
+	struct wpan_dev *wpan_dev = &sdata->wpan_dev;
+	struct sk_buff *skb;
+	int ret;
+
+	frame.mhr.fc.type = IEEE802154_FC_TYPE_MAC_CMD;
+	frame.mhr.fc.security_enabled = 0;
+	frame.mhr.fc.frame_pending = 0;
+	frame.mhr.fc.ack_request = 1; /* We always expect an ack here */
+	frame.mhr.fc.intra_pan = 0;
+	frame.mhr.fc.dest_addr_mode = (coord->mode == IEEE802154_ADDR_LONG) ?
+		IEEE802154_EXTENDED_ADDRESSING : IEEE802154_SHORT_ADDRESSING;
+	frame.mhr.fc.version = IEEE802154_2003_STD;
+	frame.mhr.fc.source_addr_mode = IEEE802154_EXTENDED_ADDRESSING;
+	frame.mhr.source.mode = IEEE802154_ADDR_LONG;
+	frame.mhr.source.pan_id = cpu_to_le16(IEEE802154_PANID_BROADCAST);
+	frame.mhr.source.extended_addr = wpan_dev->extended_addr;
+	frame.mhr.dest.mode = coord->mode;
+	frame.mhr.dest.pan_id = coord->pan_id;
+	if (coord->mode == IEEE802154_ADDR_LONG)
+		frame.mhr.dest.extended_addr = coord->extended_addr;
+	else
+		frame.mhr.dest.short_addr = coord->short_addr;
+	frame.mhr.seq = atomic_inc_return(&wpan_dev->dsn) & 0xFF;
+	frame.mac_pl.cmd_id = IEEE802154_CMD_ASSOCIATION_REQ;
+	frame.assoc_req_pl.device_type = 1;
+	frame.assoc_req_pl.power_source = 1;
+	frame.assoc_req_pl.rx_on_when_idle = 1;
+	frame.assoc_req_pl.alloc_addr = 1;
+
+	skb = alloc_skb(IEEE802154_MAC_CMD_SKB_SZ + sizeof(frame.assoc_req_pl),
+			GFP_KERNEL);
+	if (!skb)
+		return -ENOBUFS;
+
+	skb->dev = sdata->dev;
+
+	ret = ieee802154_mac_cmd_push(skb, &frame, &frame.assoc_req_pl,
+				      sizeof(frame.assoc_req_pl));
+	if (ret) {
+		kfree_skb(skb);
+		return ret;
+	}
+
+	local->assoc_dev = coord;
+	reinit_completion(&local->assoc_done);
+	set_bit(IEEE802154_IS_ASSOCIATING, &local->ongoing);
+
+	ret = ieee802154_mlme_tx_one_locked(local, sdata, skb);
+	if (ret) {
+		if (ret > 0)
+			ret = (ret == IEEE802154_NO_ACK) ? -EREMOTEIO : -EIO;
+		dev_warn(&sdata->dev->dev,
+			 "No ASSOC REQ ACK received from %8phC\n", &ceaddr);
+		goto clear_assoc;
+	}
+
+	ret = wait_for_completion_killable_timeout(&local->assoc_done, 10 * HZ);
+	if (ret <= 0) {
+		dev_warn(&sdata->dev->dev,
+			 "No ASSOC RESP received from %8phC\n", &ceaddr);
+		ret = -ETIMEDOUT;
+		goto clear_assoc;
+	}
+
+	if (local->assoc_status != IEEE802154_ASSOCIATION_SUCCESSFUL) {
+		if (local->assoc_status == IEEE802154_PAN_AT_CAPACITY)
+			ret = -ERANGE;
+		else
+			ret = -EPERM;
+
+		dev_warn(&sdata->dev->dev,
+			 "Negative ASSOC RESP received from %8phC: %s\n", &ceaddr,
+			 local->assoc_status == IEEE802154_PAN_AT_CAPACITY ?
+			 "PAN at capacity" : "access denied");
+	}
+
+	ret = 0;
+	*short_addr = local->assoc_addr;
+
+clear_assoc:
+	clear_bit(IEEE802154_IS_ASSOCIATING, &local->ongoing);
+	local->assoc_dev = NULL;
+
+	return ret;
+}
+
+int mac802154_process_association_resp(struct ieee802154_sub_if_data *sdata,
+				       struct sk_buff *skb)
+{
+	struct ieee802154_addr *src = &mac_cb(skb)->source;
+	struct ieee802154_addr *dest = &mac_cb(skb)->dest;
+	u64 deaddr = swab64((__force u64)dest->extended_addr);
+	struct ieee802154_local *local = sdata->local;
+	struct wpan_dev *wpan_dev = &sdata->wpan_dev;
+	struct ieee802154_assoc_resp_pl resp_pl = {};
+
+	if (skb->len != sizeof(resp_pl))
+		return -EINVAL;
+
+	if (unlikely(src->mode != IEEE802154_EXTENDED_ADDRESSING ||
+		     dest->mode != IEEE802154_EXTENDED_ADDRESSING))
+		return -EINVAL;
+
+	if (unlikely(dest->extended_addr != wpan_dev->extended_addr ||
+		     src->extended_addr != local->assoc_dev->extended_addr))
+		return -ENODEV;
+
+	memcpy(&resp_pl, skb->data, sizeof(resp_pl));
+	local->assoc_addr = resp_pl.short_addr;
+	local->assoc_status = resp_pl.status;
+
+	dev_dbg(&skb->dev->dev,
+		"ASSOC RESP 0x%x received from %8phC, getting short address %04x\n",
+		local->assoc_status, &deaddr, local->assoc_addr);
+
+	complete(&local->assoc_done);
+
+	return 0;
+}
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH wpan-next 05/11] ieee802154: Add support for user disassociation requests
  2023-06-01 15:48 [PATCH wpan-next 00/11] ieee802154: Associations between devices Miquel Raynal
                   ` (3 preceding siblings ...)
  2023-06-01 15:48 ` [PATCH wpan-next 04/11] mac802154: Handle associating Miquel Raynal
@ 2023-06-01 15:48 ` Miquel Raynal
  2023-06-01 15:48 ` [PATCH wpan-next 06/11] mac802154: Handle disassociations Miquel Raynal
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 24+ messages in thread
From: Miquel Raynal @ 2023-06-01 15:48 UTC (permalink / raw)
  To: Alexander Aring, Stefan Schmidt, linux-wpan
  Cc: David S. Miller, Jakub Kicinski, Paolo Abeni, Eric Dumazet,
	netdev, David Girault, Romuald Despres, Frederic Blain,
	Nicolas Schodet, Guilhem Imberton, Thomas Petazzoni,
	Miquel Raynal

A device may decide at some point to disassociate from a PAN, let's
introduce a netlink command for this purpose.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 include/net/cfg802154.h         |  3 +++
 include/net/ieee802154_netdev.h | 11 +++++++++
 include/net/nl802154.h          |  1 +
 net/ieee802154/nl802154.c       | 41 +++++++++++++++++++++++++++++++++
 net/ieee802154/rdev-ops.h       | 15 ++++++++++++
 net/ieee802154/trace.h          | 19 +++++++++++++++
 6 files changed, 90 insertions(+)

diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h
index dd0964d351cd..01bc6c2da7b9 100644
--- a/include/net/cfg802154.h
+++ b/include/net/cfg802154.h
@@ -81,6 +81,9 @@ struct cfg802154_ops {
 	int	(*associate)(struct wpan_phy *wpan_phy,
 			     struct wpan_dev *wpan_dev,
 			     struct ieee802154_addr *coord);
+	int	(*disassociate)(struct wpan_phy *wpan_phy,
+				struct wpan_dev *wpan_dev,
+				struct ieee802154_addr *target);
 #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
 	void	(*get_llsec_table)(struct wpan_phy *wpan_phy,
 				   struct wpan_dev *wpan_dev,
diff --git a/include/net/ieee802154_netdev.h b/include/net/ieee802154_netdev.h
index e26ffd079556..16194356cfe7 100644
--- a/include/net/ieee802154_netdev.h
+++ b/include/net/ieee802154_netdev.h
@@ -177,6 +177,11 @@ enum ieee802154_association_status {
 	IEEE802154_FAST_ASSOCIATION_SUCCESSFUL = 0x80,
 };
 
+enum ieee802154_disassociation_reason {
+	IEEE802154_COORD_WISHES_DEVICE_TO_LEAVE = 0x1,
+	IEEE802154_DEVICE_WISHES_TO_LEAVE = 0x2,
+};
+
 struct ieee802154_hdr {
 	struct ieee802154_hdr_fc fc;
 	u8 seq;
@@ -206,6 +211,12 @@ struct ieee802154_association_req_frame {
 	struct ieee802154_assoc_req_pl assoc_req_pl;
 };
 
+struct ieee802154_disassociation_notif_frame {
+	struct ieee802154_hdr mhr;
+	struct ieee802154_mac_cmd_pl mac_pl;
+	u8 disassoc_pl;
+};
+
 /* pushes hdr onto the skb. fields of hdr->fc that can be calculated from
  * the contents of hdr will be, and the actual value of those bits in
  * hdr->fc will be ignored. this includes the INTRA_PAN bit and the frame
diff --git a/include/net/nl802154.h b/include/net/nl802154.h
index 830e1c51d3df..8a47c14c72f0 100644
--- a/include/net/nl802154.h
+++ b/include/net/nl802154.h
@@ -79,6 +79,7 @@ enum nl802154_commands {
 	NL802154_CMD_SEND_BEACONS,
 	NL802154_CMD_STOP_BEACONS,
 	NL802154_CMD_ASSOCIATE,
+	NL802154_CMD_DISASSOCIATE,
 
 	/* add new commands above here */
 
diff --git a/net/ieee802154/nl802154.c b/net/ieee802154/nl802154.c
index 2c28e0e9fdda..5820fe425ddd 100644
--- a/net/ieee802154/nl802154.c
+++ b/net/ieee802154/nl802154.c
@@ -1663,6 +1663,39 @@ static int nl802154_associate(struct sk_buff *skb, struct genl_info *info)
 	return err;
 }
 
+static int nl802154_disassociate(struct sk_buff *skb, struct genl_info *info)
+{
+	struct cfg802154_registered_device *rdev = info->user_ptr[0];
+	struct net_device *dev = info->user_ptr[1];
+	struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
+	struct wpan_phy *wpan_phy = &rdev->wpan_phy;
+	struct ieee802154_addr target;
+
+	if (wpan_phy->flags & WPAN_PHY_FLAG_DATAGRAMS_ONLY) {
+		NL_SET_ERR_MSG(info->extack, "PHY only supports datagrams");
+		return -EOPNOTSUPP;
+	}
+
+	target.pan_id = wpan_dev->pan_id;
+
+	if (info->attrs[NL802154_ATTR_EXTENDED_ADDR]) {
+		target.mode = IEEE802154_ADDR_LONG;
+		target.extended_addr = nla_get_le64(info->attrs[NL802154_ATTR_EXTENDED_ADDR]);
+	} else if (info->attrs[NL802154_ATTR_SHORT_ADDR]) {
+		target.mode = IEEE802154_ADDR_SHORT;
+		target.short_addr = nla_get_le16(info->attrs[NL802154_ATTR_SHORT_ADDR]);
+	} else {
+		NL_SET_ERR_MSG(info->extack, "Device address is missing");
+		return -EINVAL;
+	}
+
+	mutex_lock(&wpan_dev->association_lock);
+	rdev_disassociate(rdev, wpan_dev, &target);
+	mutex_unlock(&wpan_dev->association_lock);
+
+	return 0;
+}
+
 #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
 static const struct nla_policy nl802154_dev_addr_policy[NL802154_DEV_ADDR_ATTR_MAX + 1] = {
 	[NL802154_DEV_ADDR_ATTR_PAN_ID] = { .type = NLA_U16 },
@@ -2792,6 +2825,14 @@ static const struct genl_ops nl802154_ops[] = {
 				  NL802154_FLAG_CHECK_NETDEV_UP |
 				  NL802154_FLAG_NEED_RTNL,
 	},
+	{
+		.cmd = NL802154_CMD_DISASSOCIATE,
+		.doit = nl802154_disassociate,
+		.flags = GENL_ADMIN_PERM,
+		.internal_flags = NL802154_FLAG_NEED_NETDEV |
+				  NL802154_FLAG_CHECK_NETDEV_UP |
+				  NL802154_FLAG_NEED_RTNL,
+	},
 #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
 	{
 		.cmd = NL802154_CMD_SET_SEC_PARAMS,
diff --git a/net/ieee802154/rdev-ops.h b/net/ieee802154/rdev-ops.h
index 4843d52f1ee0..64071ef6f57b 100644
--- a/net/ieee802154/rdev-ops.h
+++ b/net/ieee802154/rdev-ops.h
@@ -280,6 +280,21 @@ static inline int rdev_associate(struct cfg802154_registered_device *rdev,
 	return ret;
 }
 
+static inline int rdev_disassociate(struct cfg802154_registered_device *rdev,
+				    struct wpan_dev *wpan_dev,
+				    struct ieee802154_addr *target)
+{
+	int ret;
+
+	if (!rdev->ops->disassociate)
+		return -EOPNOTSUPP;
+
+	trace_802154_rdev_disassociate(&rdev->wpan_phy, wpan_dev, target);
+	ret = rdev->ops->disassociate(&rdev->wpan_phy, wpan_dev, target);
+	trace_802154_rdev_return_int(&rdev->wpan_phy, ret);
+	return ret;
+}
+
 #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
 /* TODO this is already a nl802154, so move into ieee802154 */
 static inline void
diff --git a/net/ieee802154/trace.h b/net/ieee802154/trace.h
index fb24be6bfb03..cd1e4a0ff275 100644
--- a/net/ieee802154/trace.h
+++ b/net/ieee802154/trace.h
@@ -375,6 +375,25 @@ TRACE_EVENT(802154_rdev_associate,
 		  WPAN_PHY_PR_ARG, WPAN_DEV_PR_ARG, __entry->addr)
 );
 
+TRACE_EVENT(802154_rdev_disassociate,
+	TP_PROTO(struct wpan_phy *wpan_phy,
+		 struct wpan_dev *wpan_dev,
+		 struct ieee802154_addr *target),
+	TP_ARGS(wpan_phy, wpan_dev, target),
+	TP_STRUCT__entry(
+		WPAN_PHY_ENTRY
+		WPAN_DEV_ENTRY
+		__field(__le64, addr)
+	),
+	TP_fast_assign(
+		WPAN_PHY_ASSIGN;
+		WPAN_DEV_ASSIGN;
+		__entry->addr = target->extended_addr;
+	),
+	TP_printk(WPAN_PHY_PR_FMT ", " WPAN_DEV_PR_FMT ", disassociating with: 0x%llx",
+		  WPAN_PHY_PR_ARG, WPAN_DEV_PR_ARG, __entry->addr)
+);
+
 TRACE_EVENT(802154_rdev_return_int,
 	TP_PROTO(struct wpan_phy *wpan_phy, int ret),
 	TP_ARGS(wpan_phy, ret),
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH wpan-next 06/11] mac802154: Handle disassociations
  2023-06-01 15:48 [PATCH wpan-next 00/11] ieee802154: Associations between devices Miquel Raynal
                   ` (4 preceding siblings ...)
  2023-06-01 15:48 ` [PATCH wpan-next 05/11] ieee802154: Add support for user disassociation requests Miquel Raynal
@ 2023-06-01 15:48 ` Miquel Raynal
  2023-06-03 11:30   ` Alexander Aring
  2023-06-01 15:48 ` [PATCH wpan-next 07/11] mac802154: Handle association requests from peers Miquel Raynal
                   ` (4 subsequent siblings)
  10 siblings, 1 reply; 24+ messages in thread
From: Miquel Raynal @ 2023-06-01 15:48 UTC (permalink / raw)
  To: Alexander Aring, Stefan Schmidt, linux-wpan
  Cc: David S. Miller, Jakub Kicinski, Paolo Abeni, Eric Dumazet,
	netdev, David Girault, Romuald Despres, Frederic Blain,
	Nicolas Schodet, Guilhem Imberton, Thomas Petazzoni,
	Miquel Raynal

Devices may decide to disassociate from their coordinator for different
reasons (device turning off, coordinator signal strength too low, etc),
the MAC layer just has to send a disassociation notification.

If the ack of the disassociation notification is not received, the
device may consider itself disassociated anyway.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 net/ieee802154/pan.c         |   2 +
 net/mac802154/cfg.c          | 102 +++++++++++++++++++++++++++++++++++
 net/mac802154/ieee802154_i.h |   4 ++
 net/mac802154/scan.c         |  60 +++++++++++++++++++++
 4 files changed, 168 insertions(+)

diff --git a/net/ieee802154/pan.c b/net/ieee802154/pan.c
index e2a12a42ba2b..477e8dad0cf0 100644
--- a/net/ieee802154/pan.c
+++ b/net/ieee802154/pan.c
@@ -49,6 +49,7 @@ bool cfg802154_device_is_parent(struct wpan_dev *wpan_dev,
 
 	return false;
 }
+EXPORT_SYMBOL_GPL(cfg802154_device_is_parent);
 
 struct ieee802154_pan_device *
 cfg802154_device_is_child(struct wpan_dev *wpan_dev,
@@ -64,3 +65,4 @@ cfg802154_device_is_child(struct wpan_dev *wpan_dev,
 
 	return NULL;
 }
+EXPORT_SYMBOL_GPL(cfg802154_device_is_child);
diff --git a/net/mac802154/cfg.c b/net/mac802154/cfg.c
index 89112d2bcee7..c27c05e825ff 100644
--- a/net/mac802154/cfg.c
+++ b/net/mac802154/cfg.c
@@ -386,6 +386,107 @@ static int mac802154_associate(struct wpan_phy *wpan_phy,
 	return ret;
 }
 
+static int mac802154_disassociate_from_parent(struct wpan_phy *wpan_phy,
+					      struct wpan_dev *wpan_dev)
+{
+	struct ieee802154_local *local = wpan_phy_priv(wpan_phy);
+	struct ieee802154_pan_device *child, *tmp;
+	struct ieee802154_sub_if_data *sdata;
+	u64 eaddr;
+	int ret;
+
+	sdata = IEEE802154_WPAN_DEV_TO_SUB_IF(wpan_dev);
+
+	/* Start by disassociating all the children and preventing new ones to
+	 * attempt associations.
+	 */
+	list_for_each_entry_safe(child, tmp, &wpan_dev->children, node) {
+		ret = mac802154_send_disassociation_notif(sdata, child,
+							  IEEE802154_COORD_WISHES_DEVICE_TO_LEAVE);
+		if (ret) {
+			eaddr = swab64((__force u64)child->extended_addr);
+			dev_err(&sdata->dev->dev,
+				"Disassociation with %8phC may have failed (%d)\n",
+				&eaddr, ret);
+		}
+
+		list_del(&child->node);
+	}
+
+	ret = mac802154_send_disassociation_notif(sdata, wpan_dev->parent,
+						  IEEE802154_DEVICE_WISHES_TO_LEAVE);
+	if (ret) {
+		eaddr = swab64((__force u64)wpan_dev->parent->extended_addr);
+		dev_err(&sdata->dev->dev,
+			"Disassociation from %8phC may have failed (%d)\n",
+			&eaddr, ret);
+	}
+
+	ret = 0;
+
+	kfree(wpan_dev->parent);
+	wpan_dev->parent = NULL;
+	wpan_dev->association_generation++;
+	wpan_dev->pan_id = cpu_to_le16(IEEE802154_PAN_ID_BROADCAST);
+	wpan_dev->short_addr = cpu_to_le16(IEEE802154_ADDR_SHORT_BROADCAST);
+
+	if (local->hw.flags & IEEE802154_HW_AFILT) {
+		ret = drv_set_pan_id(local, wpan_dev->pan_id);
+		if (ret < 0)
+			return ret;
+
+		ret = drv_set_short_addr(local, wpan_dev->short_addr);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int mac802154_disassociate_child(struct wpan_phy *wpan_phy,
+					struct wpan_dev *wpan_dev,
+					struct ieee802154_pan_device *child)
+{
+	struct ieee802154_sub_if_data *sdata;
+	int ret;
+
+	sdata = IEEE802154_WPAN_DEV_TO_SUB_IF(wpan_dev);
+
+	ret = mac802154_send_disassociation_notif(sdata, child,
+						  IEEE802154_COORD_WISHES_DEVICE_TO_LEAVE);
+	if (ret)
+		return ret;
+
+	list_del(&child->node);
+	wpan_dev->association_generation++;
+	kfree(child);
+
+	return 0;
+}
+
+static int mac802154_disassociate(struct wpan_phy *wpan_phy,
+				  struct wpan_dev *wpan_dev,
+				  struct ieee802154_addr *target)
+{
+	u64 teaddr = swab64((__force u64)target->extended_addr);
+	struct ieee802154_pan_device *pan_device;
+
+	ASSERT_RTNL();
+
+	if (cfg802154_device_is_parent(wpan_dev, target))
+		return mac802154_disassociate_from_parent(wpan_phy, wpan_dev);
+
+	pan_device = cfg802154_device_is_child(wpan_dev, target);
+	if (pan_device)
+		return mac802154_disassociate_child(wpan_phy, wpan_dev,
+						    pan_device);
+
+	dev_err(&wpan_dev->netdev->dev,
+		"Device %8phC is not associated with us\n", &teaddr);
+
+	return -EINVAL;
+}
+
 #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
 static void
 ieee802154_get_llsec_table(struct wpan_phy *wpan_phy,
@@ -598,6 +699,7 @@ const struct cfg802154_ops mac802154_config_ops = {
 	.send_beacons = mac802154_send_beacons,
 	.stop_beacons = mac802154_stop_beacons,
 	.associate = mac802154_associate,
+	.disassociate = mac802154_disassociate,
 #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
 	.get_llsec_table = ieee802154_get_llsec_table,
 	.lock_llsec_table = ieee802154_lock_llsec_table,
diff --git a/net/mac802154/ieee802154_i.h b/net/mac802154/ieee802154_i.h
index fff67676b400..92252f86c69c 100644
--- a/net/mac802154/ieee802154_i.h
+++ b/net/mac802154/ieee802154_i.h
@@ -315,6 +315,10 @@ static inline bool mac802154_is_associating(struct ieee802154_local *local)
 	return test_bit(IEEE802154_IS_ASSOCIATING, &local->ongoing);
 }
 
+int mac802154_send_disassociation_notif(struct ieee802154_sub_if_data *sdata,
+					struct ieee802154_pan_device *target,
+					u8 reason);
+
 /* interface handling */
 int ieee802154_iface_init(void);
 void ieee802154_iface_exit(void);
diff --git a/net/mac802154/scan.c b/net/mac802154/scan.c
index 5dd50e1ce329..e2f2e1235ec6 100644
--- a/net/mac802154/scan.c
+++ b/net/mac802154/scan.c
@@ -637,3 +637,63 @@ int mac802154_process_association_resp(struct ieee802154_sub_if_data *sdata,
 
 	return 0;
 }
+
+int mac802154_send_disassociation_notif(struct ieee802154_sub_if_data *sdata,
+					struct ieee802154_pan_device *target,
+					u8 reason)
+{
+	struct ieee802154_disassociation_notif_frame frame = {};
+	u64 teaddr = swab64((__force u64)target->extended_addr);
+	struct ieee802154_local *local = sdata->local;
+	struct wpan_dev *wpan_dev = &sdata->wpan_dev;
+	struct sk_buff *skb;
+	int ret;
+
+	frame.mhr.fc.type = IEEE802154_FC_TYPE_MAC_CMD;
+	frame.mhr.fc.security_enabled = 0;
+	frame.mhr.fc.frame_pending = 0;
+	frame.mhr.fc.ack_request = 1;
+	frame.mhr.fc.intra_pan = 1;
+	frame.mhr.fc.dest_addr_mode = (target->mode == IEEE802154_ADDR_LONG) ?
+		IEEE802154_EXTENDED_ADDRESSING : IEEE802154_SHORT_ADDRESSING;
+	frame.mhr.fc.version = IEEE802154_2003_STD;
+	frame.mhr.fc.source_addr_mode = IEEE802154_EXTENDED_ADDRESSING;
+	frame.mhr.source.mode = IEEE802154_ADDR_LONG;
+	frame.mhr.source.pan_id = wpan_dev->pan_id;
+	frame.mhr.source.extended_addr = wpan_dev->extended_addr;
+	frame.mhr.dest.mode = target->mode;
+	frame.mhr.dest.pan_id = wpan_dev->pan_id;
+	if (target->mode == IEEE802154_ADDR_LONG)
+		frame.mhr.dest.extended_addr = target->extended_addr;
+	else
+		frame.mhr.dest.short_addr = target->short_addr;
+	frame.mhr.seq = atomic_inc_return(&wpan_dev->dsn) & 0xFF;
+	frame.mac_pl.cmd_id = IEEE802154_CMD_DISASSOCIATION_NOTIFY;
+	frame.disassoc_pl = reason;
+
+	skb = alloc_skb(IEEE802154_MAC_CMD_SKB_SZ + sizeof(frame.disassoc_pl),
+			GFP_KERNEL);
+	if (!skb)
+		return -ENOBUFS;
+
+	skb->dev = sdata->dev;
+
+	ret = ieee802154_mac_cmd_push(skb, &frame, &frame.disassoc_pl,
+				      sizeof(frame.disassoc_pl));
+	if (ret) {
+		kfree_skb(skb);
+		return ret;
+	}
+
+	ret = ieee802154_mlme_tx_one_locked(local, sdata, skb);
+	if (ret) {
+		dev_warn(&sdata->dev->dev,
+			 "No DISASSOC ACK received from %8phC\n", &teaddr);
+		if (ret > 0)
+			ret = (ret == IEEE802154_NO_ACK) ? -EREMOTEIO : -EIO;
+		return ret;
+	}
+
+	dev_dbg(&sdata->dev->dev, "DISASSOC ACK received from %8phC\n", &teaddr);
+	return 0;
+}
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH wpan-next 07/11] mac802154: Handle association requests from peers
  2023-06-01 15:48 [PATCH wpan-next 00/11] ieee802154: Associations between devices Miquel Raynal
                   ` (5 preceding siblings ...)
  2023-06-01 15:48 ` [PATCH wpan-next 06/11] mac802154: Handle disassociations Miquel Raynal
@ 2023-06-01 15:48 ` Miquel Raynal
  2023-06-03 11:28   ` Alexander Aring
  2023-06-01 15:48 ` [PATCH wpan-next 08/11] ieee802154: Add support for limiting the number of associated devices Miquel Raynal
                   ` (3 subsequent siblings)
  10 siblings, 1 reply; 24+ messages in thread
From: Miquel Raynal @ 2023-06-01 15:48 UTC (permalink / raw)
  To: Alexander Aring, Stefan Schmidt, linux-wpan
  Cc: David S. Miller, Jakub Kicinski, Paolo Abeni, Eric Dumazet,
	netdev, David Girault, Romuald Despres, Frederic Blain,
	Nicolas Schodet, Guilhem Imberton, Thomas Petazzoni,
	Miquel Raynal

Coordinators may have to handle association requests from peers which
want to join the PAN. The logic involves:
- Acknowledging the request (done by hardware)
- If requested, a random short address that is free on this PAN should
  be chosen for the device.
- Sending an association response with the short address allocated for
  the peer and expecting it to be ack'ed.

If anything fails during this procedure, the peer is considered not
associated.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 include/net/cfg802154.h         |   7 ++
 include/net/ieee802154_netdev.h |   6 ++
 net/ieee802154/core.c           |   7 ++
 net/ieee802154/pan.c            |  27 ++++++
 net/mac802154/ieee802154_i.h    |   2 +
 net/mac802154/rx.c              |   8 ++
 net/mac802154/scan.c            | 147 ++++++++++++++++++++++++++++++++
 7 files changed, 204 insertions(+)

diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h
index 01bc6c2da7b9..4404072365e7 100644
--- a/include/net/cfg802154.h
+++ b/include/net/cfg802154.h
@@ -582,4 +582,11 @@ struct ieee802154_pan_device *
 cfg802154_device_is_child(struct wpan_dev *wpan_dev,
 			  struct ieee802154_addr *target);
 
+/**
+ * cfg802154_get_free_short_addr - Get a free address among the known devices
+ * @wpan_dev: the wpan device
+ * @return: a random short address expectedly unused on our PAN
+ */
+__le16 cfg802154_get_free_short_addr(struct wpan_dev *wpan_dev);
+
 #endif /* __NET_CFG802154_H */
diff --git a/include/net/ieee802154_netdev.h b/include/net/ieee802154_netdev.h
index 16194356cfe7..4de858f9929e 100644
--- a/include/net/ieee802154_netdev.h
+++ b/include/net/ieee802154_netdev.h
@@ -211,6 +211,12 @@ struct ieee802154_association_req_frame {
 	struct ieee802154_assoc_req_pl assoc_req_pl;
 };
 
+struct ieee802154_association_resp_frame {
+	struct ieee802154_hdr mhr;
+	struct ieee802154_mac_cmd_pl mac_pl;
+	struct ieee802154_assoc_resp_pl assoc_resp_pl;
+};
+
 struct ieee802154_disassociation_notif_frame {
 	struct ieee802154_hdr mhr;
 	struct ieee802154_mac_cmd_pl mac_pl;
diff --git a/net/ieee802154/core.c b/net/ieee802154/core.c
index 8bf01bb7e858..39674db64336 100644
--- a/net/ieee802154/core.c
+++ b/net/ieee802154/core.c
@@ -200,11 +200,18 @@ EXPORT_SYMBOL(wpan_phy_free);
 
 static void cfg802154_free_peer_structures(struct wpan_dev *wpan_dev)
 {
+	struct ieee802154_pan_device *child, *tmp;
+
 	mutex_lock(&wpan_dev->association_lock);
 
 	if (wpan_dev->parent)
 		kfree(wpan_dev->parent);
 
+	list_for_each_entry_safe(child, tmp, &wpan_dev->children, node) {
+		list_del(&child->node);
+		kfree(child);
+	}
+
 	wpan_dev->association_generation++;
 
 	mutex_unlock(&wpan_dev->association_lock);
diff --git a/net/ieee802154/pan.c b/net/ieee802154/pan.c
index 477e8dad0cf0..7756906c201d 100644
--- a/net/ieee802154/pan.c
+++ b/net/ieee802154/pan.c
@@ -66,3 +66,30 @@ cfg802154_device_is_child(struct wpan_dev *wpan_dev,
 	return NULL;
 }
 EXPORT_SYMBOL_GPL(cfg802154_device_is_child);
+
+__le16 cfg802154_get_free_short_addr(struct wpan_dev *wpan_dev)
+{
+	struct ieee802154_pan_device *child;
+	__le16 addr;
+
+	lockdep_assert_held(&wpan_dev->association_lock);
+
+	do {
+		get_random_bytes(&addr, 2);
+		if (addr == cpu_to_le16(IEEE802154_ADDR_SHORT_BROADCAST) ||
+		    addr == cpu_to_le16(IEEE802154_ADDR_SHORT_UNSPEC))
+			continue;
+
+		if (wpan_dev->parent && wpan_dev->parent->short_addr == addr)
+			continue;
+
+		list_for_each_entry(child, &wpan_dev->children, node)
+			if (child->short_addr == addr)
+				continue;
+
+		break;
+	} while (1);
+
+	return addr;
+}
+EXPORT_SYMBOL_GPL(cfg802154_get_free_short_addr);
diff --git a/net/mac802154/ieee802154_i.h b/net/mac802154/ieee802154_i.h
index 92252f86c69c..432bfa87249e 100644
--- a/net/mac802154/ieee802154_i.h
+++ b/net/mac802154/ieee802154_i.h
@@ -318,6 +318,8 @@ static inline bool mac802154_is_associating(struct ieee802154_local *local)
 int mac802154_send_disassociation_notif(struct ieee802154_sub_if_data *sdata,
 					struct ieee802154_pan_device *target,
 					u8 reason);
+int mac802154_process_association_req(struct ieee802154_sub_if_data *sdata,
+				      struct sk_buff *skb);
 
 /* interface handling */
 int ieee802154_iface_init(void);
diff --git a/net/mac802154/rx.c b/net/mac802154/rx.c
index d0e08613a36b..96040b63a4fc 100644
--- a/net/mac802154/rx.c
+++ b/net/mac802154/rx.c
@@ -102,6 +102,14 @@ void mac802154_rx_mac_cmd_worker(struct work_struct *work)
 		mac802154_process_association_resp(mac_pkt->sdata, mac_pkt->skb);
 		break;
 
+	case IEEE802154_CMD_ASSOCIATION_REQ:
+		dev_dbg(&mac_pkt->sdata->dev->dev, "processing ASSOC REQ\n");
+		if (mac_pkt->sdata->wpan_dev.iftype != NL802154_IFTYPE_COORD)
+			break;
+
+		mac802154_process_association_req(mac_pkt->sdata, mac_pkt->skb);
+		break;
+
 	default:
 		break;
 	}
diff --git a/net/mac802154/scan.c b/net/mac802154/scan.c
index e2f2e1235ec6..9f55b2314fe5 100644
--- a/net/mac802154/scan.c
+++ b/net/mac802154/scan.c
@@ -697,3 +697,150 @@ int mac802154_send_disassociation_notif(struct ieee802154_sub_if_data *sdata,
 	dev_dbg(&sdata->dev->dev, "DISASSOC ACK received from %8phC\n", &teaddr);
 	return 0;
 }
+
+static int
+mac802154_send_association_resp_locked(struct ieee802154_sub_if_data *sdata,
+				       struct ieee802154_pan_device *target,
+				       struct ieee802154_assoc_resp_pl *assoc_resp_pl)
+{
+	u64 teaddr = swab64((__force u64)target->extended_addr);
+	struct ieee802154_association_resp_frame frame = {};
+	struct ieee802154_local *local = sdata->local;
+	struct wpan_dev *wpan_dev = &sdata->wpan_dev;
+	struct sk_buff *skb;
+	int ret;
+
+	frame.mhr.fc.type = IEEE802154_FC_TYPE_MAC_CMD;
+	frame.mhr.fc.security_enabled = 0;
+	frame.mhr.fc.frame_pending = 0;
+	frame.mhr.fc.ack_request = 1; /* We always expect an ack here */
+	frame.mhr.fc.intra_pan = 1;
+	frame.mhr.fc.dest_addr_mode = IEEE802154_EXTENDED_ADDRESSING;
+	frame.mhr.fc.version = IEEE802154_2003_STD;
+	frame.mhr.fc.source_addr_mode = IEEE802154_EXTENDED_ADDRESSING;
+	frame.mhr.seq = 10;
+	frame.mhr.source.mode = IEEE802154_ADDR_LONG;
+	frame.mhr.source.extended_addr = wpan_dev->extended_addr;
+	frame.mhr.dest.mode = IEEE802154_ADDR_LONG;
+	frame.mhr.dest.pan_id = wpan_dev->pan_id;
+	frame.mhr.dest.extended_addr = target->extended_addr;
+	frame.mhr.seq = atomic_inc_return(&wpan_dev->dsn) & 0xFF;
+	frame.mac_pl.cmd_id = IEEE802154_CMD_ASSOCIATION_RESP;
+
+	skb = alloc_skb(IEEE802154_MAC_CMD_SKB_SZ + sizeof(*assoc_resp_pl),
+			GFP_KERNEL);
+	if (!skb)
+		return -ENOBUFS;
+
+	skb->dev = sdata->dev;
+
+	ret = ieee802154_mac_cmd_push(skb, &frame, assoc_resp_pl,
+				      sizeof(*assoc_resp_pl));
+	if (ret) {
+		kfree_skb(skb);
+		return ret;
+	}
+
+	ret = ieee802154_mlme_tx_locked(local, sdata, skb);
+	if (ret) {
+		dev_warn(&sdata->dev->dev,
+			 "No ASSOC RESP ACK received from %8phC\n", &teaddr);
+		if (ret > 0)
+			ret = (ret == IEEE802154_NO_ACK) ? -EREMOTEIO : -EIO;
+		return ret;
+	}
+
+	return 0;
+}
+
+int mac802154_process_association_req(struct ieee802154_sub_if_data *sdata,
+				      struct sk_buff *skb)
+{
+	struct wpan_dev *wpan_dev = &sdata->wpan_dev;
+	struct ieee802154_addr *src = &mac_cb(skb)->source;
+	struct ieee802154_addr *dest = &mac_cb(skb)->dest;
+	struct ieee802154_assoc_resp_pl assoc_resp_pl = {};
+	struct ieee802154_assoc_req_pl assoc_req_pl;
+	struct ieee802154_pan_device *child, *exchild;
+	struct ieee802154_addr tmp = {};
+	u64 ceaddr;
+	int ret;
+
+	if (skb->len != sizeof(assoc_req_pl))
+		return -EINVAL;
+
+	if (unlikely(src->mode != IEEE802154_EXTENDED_ADDRESSING))
+		return -EINVAL;
+
+	if (unlikely(dest->pan_id != wpan_dev->pan_id))
+		return -ENODEV;
+
+	if (dest->mode == IEEE802154_EXTENDED_ADDRESSING &&
+	    unlikely(dest->extended_addr != wpan_dev->extended_addr))
+		return -ENODEV;
+	else if (dest->mode == IEEE802154_SHORT_ADDRESSING &&
+		 unlikely(dest->short_addr != wpan_dev->short_addr))
+		return -ENODEV;
+
+	mutex_lock(&wpan_dev->association_lock);
+
+	memcpy(&assoc_req_pl, skb->data, sizeof(assoc_req_pl));
+	if (assoc_req_pl.assoc_type) {
+		dev_err(&skb->dev->dev, "Fast associations not supported yet\n");
+		ret = -EOPNOTSUPP;
+		goto unlock;
+	}
+
+	child = kzalloc(sizeof(*child), GFP_KERNEL);
+	if (!child) {
+		ret = -ENOMEM;
+		goto unlock;
+	}
+
+	child->extended_addr = src->extended_addr;
+	child->mode = IEEE802154_EXTENDED_ADDRESSING;
+	ceaddr = swab64((__force u64)child->extended_addr);
+
+	assoc_resp_pl.status = IEEE802154_ASSOCIATION_SUCCESSFUL;
+	if (assoc_req_pl.alloc_addr) {
+		assoc_resp_pl.short_addr = cfg802154_get_free_short_addr(wpan_dev);
+		child->mode = IEEE802154_SHORT_ADDRESSING;
+	} else {
+		assoc_resp_pl.short_addr = cpu_to_le16(IEEE802154_ADDR_SHORT_UNSPEC);
+	}
+	child->short_addr = assoc_resp_pl.short_addr;
+	dev_dbg(&sdata->dev->dev,
+		"Accepting ASSOC REQ from child %8phC, providing short address 0x%04x\n",
+		&ceaddr, le16_to_cpu(child->short_addr));
+
+	ret = mac802154_send_association_resp_locked(sdata, child, &assoc_resp_pl);
+	if (ret) {
+		kfree(child);
+		goto unlock;
+	}
+
+	dev_dbg(&sdata->dev->dev,
+		"Successful association with new child %8phC\n", &ceaddr);
+
+	/* Ensure this child is not already associated (might happen due to
+	 * retransmissions), in this case drop the ex structure.
+	 */
+	tmp.mode = child->mode;
+	if (tmp.mode == IEEE802154_SHORT_ADDRESSING)
+		tmp.short_addr = child->short_addr;
+	else
+		tmp.extended_addr = child->extended_addr;
+	exchild = cfg802154_device_is_child(wpan_dev, &tmp);
+	if (exchild) {
+		dev_dbg(&sdata->dev->dev,
+			"Child %8phC was already known\n", &ceaddr);
+		list_del(&exchild->node);
+	}
+
+	list_add(&child->node, &wpan_dev->children);
+	wpan_dev->association_generation++;
+
+unlock:
+	mutex_unlock(&wpan_dev->association_lock);
+	return ret;
+}
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH wpan-next 08/11] ieee802154: Add support for limiting the number of associated devices
  2023-06-01 15:48 [PATCH wpan-next 00/11] ieee802154: Associations between devices Miquel Raynal
                   ` (6 preceding siblings ...)
  2023-06-01 15:48 ` [PATCH wpan-next 07/11] mac802154: Handle association requests from peers Miquel Raynal
@ 2023-06-01 15:48 ` Miquel Raynal
  2023-06-01 15:48 ` [PATCH wpan-next 09/11] mac802154: Follow " Miquel Raynal
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 24+ messages in thread
From: Miquel Raynal @ 2023-06-01 15:48 UTC (permalink / raw)
  To: Alexander Aring, Stefan Schmidt, linux-wpan
  Cc: David S. Miller, Jakub Kicinski, Paolo Abeni, Eric Dumazet,
	netdev, David Girault, Romuald Despres, Frederic Blain,
	Nicolas Schodet, Guilhem Imberton, Thomas Petazzoni,
	Miquel Raynal

Coordinators may refuse associations. We need a user input for
that. Let's add a new netlink command which can provide a maximum number
of devices we accept to associate with as a first step. Later, we could
also forward the request to userspace and check whether the association
should be accepted or not.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 include/net/cfg802154.h   |  8 ++++++++
 include/net/nl802154.h    |  2 ++
 net/ieee802154/core.c     |  1 +
 net/ieee802154/nl802154.c | 28 ++++++++++++++++++++++++++++
 net/ieee802154/pan.c      |  8 ++++++++
 5 files changed, 47 insertions(+)

diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h
index 4404072365e7..d7583598b290 100644
--- a/include/net/cfg802154.h
+++ b/include/net/cfg802154.h
@@ -506,6 +506,7 @@ struct wpan_dev {
 	struct ieee802154_pan_device *parent;
 	struct list_head children;
 	unsigned int association_generation;
+	unsigned int max_associations;
 };
 
 #define to_phy(_dev)	container_of(_dev, struct wpan_phy, dev)
@@ -582,6 +583,13 @@ struct ieee802154_pan_device *
 cfg802154_device_is_child(struct wpan_dev *wpan_dev,
 			  struct ieee802154_addr *target);
 
+/**
+ * cfg802154_set_max_associations - Limit the number of future associations
+ * @wpan_dev: the wpan device
+ * @max: the maximum number of devices we accept to associate
+ */
+void cfg802154_set_max_associations(struct wpan_dev *wpan_dev, unsigned int max);
+
 /**
  * cfg802154_get_free_short_addr - Get a free address among the known devices
  * @wpan_dev: the wpan device
diff --git a/include/net/nl802154.h b/include/net/nl802154.h
index 8a47c14c72f0..8b26faae49e8 100644
--- a/include/net/nl802154.h
+++ b/include/net/nl802154.h
@@ -80,6 +80,7 @@ enum nl802154_commands {
 	NL802154_CMD_STOP_BEACONS,
 	NL802154_CMD_ASSOCIATE,
 	NL802154_CMD_DISASSOCIATE,
+	NL802154_CMD_SET_MAX_ASSOCIATIONS,
 
 	/* add new commands above here */
 
@@ -149,6 +150,7 @@ enum nl802154_attrs {
 	NL802154_ATTR_SCAN_DURATION,
 	NL802154_ATTR_SCAN_DONE_REASON,
 	NL802154_ATTR_BEACON_INTERVAL,
+	NL802154_ATTR_MAX_ASSOCIATIONS,
 
 	/* add attributes here, update the policy in nl802154.c */
 
diff --git a/net/ieee802154/core.c b/net/ieee802154/core.c
index 39674db64336..65bb656db9b4 100644
--- a/net/ieee802154/core.c
+++ b/net/ieee802154/core.c
@@ -297,6 +297,7 @@ static int cfg802154_netdev_notifier_call(struct notifier_block *nb,
 		rdev->devlist_generation++;
 		mutex_init(&wpan_dev->association_lock);
 		INIT_LIST_HEAD(&wpan_dev->children);
+		wpan_dev->max_associations = SZ_16K;
 
 		wpan_dev->netdev = dev;
 		break;
diff --git a/net/ieee802154/nl802154.c b/net/ieee802154/nl802154.c
index 5820fe425ddd..e16e57fc34d0 100644
--- a/net/ieee802154/nl802154.c
+++ b/net/ieee802154/nl802154.c
@@ -234,6 +234,7 @@ static const struct nla_policy nl802154_policy[NL802154_ATTR_MAX+1] = {
 				 NL802154_SCAN_DONE_REASON_ABORTED),
 	[NL802154_ATTR_BEACON_INTERVAL] =
 		NLA_POLICY_MAX(NLA_U8, IEEE802154_ACTIVE_SCAN_DURATION),
+	[NL802154_ATTR_MAX_ASSOCIATIONS] = { .type = NLA_U32 },
 
 #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
 	[NL802154_ATTR_SEC_ENABLED] = { .type = NLA_U8, },
@@ -1696,6 +1697,26 @@ static int nl802154_disassociate(struct sk_buff *skb, struct genl_info *info)
 	return 0;
 }
 
+static int nl802154_set_max_associations(struct sk_buff *skb, struct genl_info *info)
+{
+	struct net_device *dev = info->user_ptr[1];
+	struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
+	unsigned int max_assoc;
+
+	if (!info->attrs[NL802154_ATTR_MAX_ASSOCIATIONS]) {
+		NL_SET_ERR_MSG(info->extack, "No maximum number of association given");
+		return -EINVAL;
+	}
+
+	max_assoc = nla_get_u32(info->attrs[NL802154_ATTR_MAX_ASSOCIATIONS]);
+
+	mutex_lock(&wpan_dev->association_lock);
+	cfg802154_set_max_associations(wpan_dev, max_assoc);
+	mutex_unlock(&wpan_dev->association_lock);
+
+	return 0;
+}
+
 #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
 static const struct nla_policy nl802154_dev_addr_policy[NL802154_DEV_ADDR_ATTR_MAX + 1] = {
 	[NL802154_DEV_ADDR_ATTR_PAN_ID] = { .type = NLA_U16 },
@@ -2833,6 +2854,13 @@ static const struct genl_ops nl802154_ops[] = {
 				  NL802154_FLAG_CHECK_NETDEV_UP |
 				  NL802154_FLAG_NEED_RTNL,
 	},
+	{
+		.cmd = NL802154_CMD_SET_MAX_ASSOCIATIONS,
+		.doit = nl802154_set_max_associations,
+		.flags = GENL_ADMIN_PERM,
+		.internal_flags = NL802154_FLAG_NEED_NETDEV |
+				  NL802154_FLAG_NEED_RTNL,
+	},
 #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
 	{
 		.cmd = NL802154_CMD_SET_SEC_PARAMS,
diff --git a/net/ieee802154/pan.c b/net/ieee802154/pan.c
index 7756906c201d..138a55847d78 100644
--- a/net/ieee802154/pan.c
+++ b/net/ieee802154/pan.c
@@ -93,3 +93,11 @@ __le16 cfg802154_get_free_short_addr(struct wpan_dev *wpan_dev)
 	return addr;
 }
 EXPORT_SYMBOL_GPL(cfg802154_get_free_short_addr);
+
+void cfg802154_set_max_associations(struct wpan_dev *wpan_dev, unsigned int max)
+{
+	lockdep_assert_held(&wpan_dev->association_lock);
+
+	wpan_dev->max_associations = max;
+}
+EXPORT_SYMBOL_GPL(cfg802154_set_max_associations);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH wpan-next 09/11] mac802154: Follow the number of associated devices
  2023-06-01 15:48 [PATCH wpan-next 00/11] ieee802154: Associations between devices Miquel Raynal
                   ` (7 preceding siblings ...)
  2023-06-01 15:48 ` [PATCH wpan-next 08/11] ieee802154: Add support for limiting the number of associated devices Miquel Raynal
@ 2023-06-01 15:48 ` Miquel Raynal
  2023-06-01 15:48 ` [PATCH wpan-next 10/11] mac802154: Handle disassociation notifications from peers Miquel Raynal
  2023-06-01 15:48 ` [PATCH wpan-next 11/11] ieee802154: Give the user the association list Miquel Raynal
  10 siblings, 0 replies; 24+ messages in thread
From: Miquel Raynal @ 2023-06-01 15:48 UTC (permalink / raw)
  To: Alexander Aring, Stefan Schmidt, linux-wpan
  Cc: David S. Miller, Jakub Kicinski, Paolo Abeni, Eric Dumazet,
	netdev, David Girault, Romuald Despres, Frederic Blain,
	Nicolas Schodet, Guilhem Imberton, Thomas Petazzoni,
	Miquel Raynal

Track the count of associated devices. Limit the number of associations
using the value provided by the user if any. If we reach the maximum
number of associations, we tell the device we are at capacity. If the
user do not want to accept any more associations, it may specify the
value 0 to the maximum number of associations, which will lead to an
access denied error status returned to the peers trying to associate.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 include/net/cfg802154.h |  1 +
 net/ieee802154/core.c   |  1 +
 net/mac802154/cfg.c     |  1 +
 net/mac802154/scan.c    | 33 +++++++++++++++++++++++----------
 4 files changed, 26 insertions(+), 10 deletions(-)

diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h
index d7583598b290..f18b93f9684f 100644
--- a/include/net/cfg802154.h
+++ b/include/net/cfg802154.h
@@ -507,6 +507,7 @@ struct wpan_dev {
 	struct list_head children;
 	unsigned int association_generation;
 	unsigned int max_associations;
+	unsigned int nchildren;
 };
 
 #define to_phy(_dev)	container_of(_dev, struct wpan_phy, dev)
diff --git a/net/ieee802154/core.c b/net/ieee802154/core.c
index 65bb656db9b4..6f7eecdc4067 100644
--- a/net/ieee802154/core.c
+++ b/net/ieee802154/core.c
@@ -212,6 +212,7 @@ static void cfg802154_free_peer_structures(struct wpan_dev *wpan_dev)
 		kfree(child);
 	}
 
+	wpan_dev->nchildren = 0;
 	wpan_dev->association_generation++;
 
 	mutex_unlock(&wpan_dev->association_lock);
diff --git a/net/mac802154/cfg.c b/net/mac802154/cfg.c
index c27c05e825ff..65a8806f9ddb 100644
--- a/net/mac802154/cfg.c
+++ b/net/mac802154/cfg.c
@@ -458,6 +458,7 @@ static int mac802154_disassociate_child(struct wpan_phy *wpan_phy,
 		return ret;
 
 	list_del(&child->node);
+	wpan_dev->nchildren--;
 	wpan_dev->association_generation++;
 	kfree(child);
 
diff --git a/net/mac802154/scan.c b/net/mac802154/scan.c
index 9f55b2314fe5..fbbae7586ab1 100644
--- a/net/mac802154/scan.c
+++ b/net/mac802154/scan.c
@@ -801,20 +801,32 @@ int mac802154_process_association_req(struct ieee802154_sub_if_data *sdata,
 	child->mode = IEEE802154_EXTENDED_ADDRESSING;
 	ceaddr = swab64((__force u64)child->extended_addr);
 
-	assoc_resp_pl.status = IEEE802154_ASSOCIATION_SUCCESSFUL;
-	if (assoc_req_pl.alloc_addr) {
-		assoc_resp_pl.short_addr = cfg802154_get_free_short_addr(wpan_dev);
-		child->mode = IEEE802154_SHORT_ADDRESSING;
+	if (wpan_dev->nchildren >= wpan_dev->max_associations) {
+		if (!wpan_dev->max_associations)
+			assoc_resp_pl.status = IEEE802154_PAN_ACCESS_DENIED;
+		else
+			assoc_resp_pl.status = IEEE802154_PAN_AT_CAPACITY;
+		assoc_resp_pl.short_addr = cpu_to_le16(IEEE802154_ADDR_SHORT_BROADCAST);
+		dev_dbg(&sdata->dev->dev,
+			"Refusing ASSOC REQ from child %8phC, %s\n", &ceaddr,
+			assoc_resp_pl.status == IEEE802154_PAN_ACCESS_DENIED ?
+			"access denied" : "too many children");
 	} else {
-		assoc_resp_pl.short_addr = cpu_to_le16(IEEE802154_ADDR_SHORT_UNSPEC);
+		assoc_resp_pl.status = IEEE802154_ASSOCIATION_SUCCESSFUL;
+		if (assoc_req_pl.alloc_addr) {
+			assoc_resp_pl.short_addr = cfg802154_get_free_short_addr(wpan_dev);
+			child->mode = IEEE802154_SHORT_ADDRESSING;
+		} else {
+			assoc_resp_pl.short_addr = cpu_to_le16(IEEE802154_ADDR_SHORT_UNSPEC);
+		}
+		child->short_addr = assoc_resp_pl.short_addr;
+		dev_dbg(&sdata->dev->dev,
+			"Accepting ASSOC REQ from child %8phC, providing short address 0x%04x\n",
+			&ceaddr, le16_to_cpu(child->short_addr));
 	}
-	child->short_addr = assoc_resp_pl.short_addr;
-	dev_dbg(&sdata->dev->dev,
-		"Accepting ASSOC REQ from child %8phC, providing short address 0x%04x\n",
-		&ceaddr, le16_to_cpu(child->short_addr));
 
 	ret = mac802154_send_association_resp_locked(sdata, child, &assoc_resp_pl);
-	if (ret) {
+	if (ret || assoc_resp_pl.status != IEEE802154_ASSOCIATION_SUCCESSFUL) {
 		kfree(child);
 		goto unlock;
 	}
@@ -838,6 +850,7 @@ int mac802154_process_association_req(struct ieee802154_sub_if_data *sdata,
 	}
 
 	list_add(&child->node, &wpan_dev->children);
+	wpan_dev->nchildren++;
 	wpan_dev->association_generation++;
 
 unlock:
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH wpan-next 10/11] mac802154: Handle disassociation notifications from peers
  2023-06-01 15:48 [PATCH wpan-next 00/11] ieee802154: Associations between devices Miquel Raynal
                   ` (8 preceding siblings ...)
  2023-06-01 15:48 ` [PATCH wpan-next 09/11] mac802154: Follow " Miquel Raynal
@ 2023-06-01 15:48 ` Miquel Raynal
  2023-06-01 15:48 ` [PATCH wpan-next 11/11] ieee802154: Give the user the association list Miquel Raynal
  10 siblings, 0 replies; 24+ messages in thread
From: Miquel Raynal @ 2023-06-01 15:48 UTC (permalink / raw)
  To: Alexander Aring, Stefan Schmidt, linux-wpan
  Cc: David S. Miller, Jakub Kicinski, Paolo Abeni, Eric Dumazet,
	netdev, David Girault, Romuald Despres, Frederic Blain,
	Nicolas Schodet, Guilhem Imberton, Thomas Petazzoni,
	Miquel Raynal

Peers may decided to disassociate from us, their coordinator, in this
case they will send a disassociation notification which we must
acknowledge. If we don't, the peer device considers itself disassociated
anyway. We also need to drop the reference to this child from our
internal structures.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 net/mac802154/ieee802154_i.h |  2 ++
 net/mac802154/rx.c           |  8 ++++++
 net/mac802154/scan.c         | 53 ++++++++++++++++++++++++++++++++++++
 3 files changed, 63 insertions(+)

diff --git a/net/mac802154/ieee802154_i.h b/net/mac802154/ieee802154_i.h
index 432bfa87249e..08dd521a51a5 100644
--- a/net/mac802154/ieee802154_i.h
+++ b/net/mac802154/ieee802154_i.h
@@ -318,6 +318,8 @@ static inline bool mac802154_is_associating(struct ieee802154_local *local)
 int mac802154_send_disassociation_notif(struct ieee802154_sub_if_data *sdata,
 					struct ieee802154_pan_device *target,
 					u8 reason);
+int mac802154_process_disassociation_notif(struct ieee802154_sub_if_data *sdata,
+					   struct sk_buff *skb);
 int mac802154_process_association_req(struct ieee802154_sub_if_data *sdata,
 				      struct sk_buff *skb);
 
diff --git a/net/mac802154/rx.c b/net/mac802154/rx.c
index 96040b63a4fc..0024341ef9c5 100644
--- a/net/mac802154/rx.c
+++ b/net/mac802154/rx.c
@@ -110,6 +110,14 @@ void mac802154_rx_mac_cmd_worker(struct work_struct *work)
 		mac802154_process_association_req(mac_pkt->sdata, mac_pkt->skb);
 		break;
 
+	case IEEE802154_CMD_DISASSOCIATION_NOTIFY:
+		dev_dbg(&mac_pkt->sdata->dev->dev, "processing DISASSOC NOTIF\n");
+		if (mac_pkt->sdata->wpan_dev.iftype != NL802154_IFTYPE_COORD)
+			break;
+
+		mac802154_process_disassociation_notif(mac_pkt->sdata, mac_pkt->skb);
+		break;
+
 	default:
 		break;
 	}
diff --git a/net/mac802154/scan.c b/net/mac802154/scan.c
index fbbae7586ab1..ffd793c22ad3 100644
--- a/net/mac802154/scan.c
+++ b/net/mac802154/scan.c
@@ -857,3 +857,56 @@ int mac802154_process_association_req(struct ieee802154_sub_if_data *sdata,
 	mutex_unlock(&wpan_dev->association_lock);
 	return ret;
 }
+
+int mac802154_process_disassociation_notif(struct ieee802154_sub_if_data *sdata,
+					   struct sk_buff *skb)
+{
+	struct ieee802154_addr *src = &mac_cb(skb)->source;
+	struct ieee802154_addr *dest = &mac_cb(skb)->dest;
+	struct wpan_dev *wpan_dev = &sdata->wpan_dev;
+	struct ieee802154_pan_device *child;
+	struct ieee802154_addr target;
+	bool parent;
+	u64 teaddr;
+
+	if (skb->len != sizeof(u8))
+		return -EINVAL;
+
+	if (unlikely(src->mode != IEEE802154_EXTENDED_ADDRESSING))
+		return -EINVAL;
+
+	if (dest->mode == IEEE802154_EXTENDED_ADDRESSING &&
+	    unlikely(dest->extended_addr != wpan_dev->extended_addr))
+		return -ENODEV;
+	else if (dest->mode == IEEE802154_SHORT_ADDRESSING &&
+		 unlikely(dest->short_addr != wpan_dev->short_addr))
+		return -ENODEV;
+
+	target.mode = IEEE802154_EXTENDED_ADDRESSING;
+	target.extended_addr = src->extended_addr;
+	teaddr = swab64((__force u64)target.extended_addr);
+	dev_dbg(&skb->dev->dev, "Processing DISASSOC NOTIF from %8phC\n", &teaddr);
+
+	mutex_lock(&wpan_dev->association_lock);
+	parent = cfg802154_device_is_parent(wpan_dev, &target);
+	if (!parent)
+		child = cfg802154_device_is_child(wpan_dev, &target);
+	if (!parent && !child) {
+		mutex_unlock(&wpan_dev->association_lock);
+		return -EINVAL;
+	}
+
+	if (parent) {
+		kfree(wpan_dev->parent);
+		wpan_dev->parent = NULL;
+	} else {
+		list_del(&child->node);
+		kfree(child);
+		wpan_dev->nchildren--;
+	}
+	wpan_dev->association_generation++;
+
+	mutex_unlock(&wpan_dev->association_lock);
+
+	return 0;
+}
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH wpan-next 11/11] ieee802154: Give the user the association list
  2023-06-01 15:48 [PATCH wpan-next 00/11] ieee802154: Associations between devices Miquel Raynal
                   ` (9 preceding siblings ...)
  2023-06-01 15:48 ` [PATCH wpan-next 10/11] mac802154: Handle disassociation notifications from peers Miquel Raynal
@ 2023-06-01 15:48 ` Miquel Raynal
  10 siblings, 0 replies; 24+ messages in thread
From: Miquel Raynal @ 2023-06-01 15:48 UTC (permalink / raw)
  To: Alexander Aring, Stefan Schmidt, linux-wpan
  Cc: David S. Miller, Jakub Kicinski, Paolo Abeni, Eric Dumazet,
	netdev, David Girault, Romuald Despres, Frederic Blain,
	Nicolas Schodet, Guilhem Imberton, Thomas Petazzoni,
	Miquel Raynal

Upon request, we must be able to provide to the user the list of
associations currently in place. Let's add a new netlink command and
attribute for this purpose.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 include/net/nl802154.h    |  18 ++++++-
 net/ieee802154/nl802154.c | 107 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 123 insertions(+), 2 deletions(-)

diff --git a/include/net/nl802154.h b/include/net/nl802154.h
index 8b26faae49e8..4c752f799957 100644
--- a/include/net/nl802154.h
+++ b/include/net/nl802154.h
@@ -81,6 +81,7 @@ enum nl802154_commands {
 	NL802154_CMD_ASSOCIATE,
 	NL802154_CMD_DISASSOCIATE,
 	NL802154_CMD_SET_MAX_ASSOCIATIONS,
+	NL802154_CMD_LIST_ASSOCIATIONS,
 
 	/* add new commands above here */
 
@@ -151,6 +152,7 @@ enum nl802154_attrs {
 	NL802154_ATTR_SCAN_DONE_REASON,
 	NL802154_ATTR_BEACON_INTERVAL,
 	NL802154_ATTR_MAX_ASSOCIATIONS,
+	NL802154_ATTR_PEER,
 
 	/* add attributes here, update the policy in nl802154.c */
 
@@ -389,8 +391,6 @@ enum nl802154_supported_bool_states {
 	NL802154_SUPPORTED_BOOL_MAX = __NL802154_SUPPORTED_BOOL_AFTER_LAST - 1
 };
 
-#ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
-
 enum nl802154_dev_addr_modes {
 	NL802154_DEV_ADDR_NONE,
 	__NL802154_DEV_ADDR_INVALID,
@@ -410,12 +410,26 @@ enum nl802154_dev_addr_attrs {
 	NL802154_DEV_ADDR_ATTR_SHORT,
 	NL802154_DEV_ADDR_ATTR_EXTENDED,
 	NL802154_DEV_ADDR_ATTR_PAD,
+	NL802154_DEV_ADDR_ATTR_PEER_TYPE,
 
 	/* keep last */
 	__NL802154_DEV_ADDR_ATTR_AFTER_LAST,
 	NL802154_DEV_ADDR_ATTR_MAX = __NL802154_DEV_ADDR_ATTR_AFTER_LAST - 1
 };
 
+enum nl802154_peer_type {
+	NL802154_PEER_TYPE_UNSPEC,
+
+	NL802154_PEER_TYPE_PARENT,
+	NL802154_PEER_TYPE_CHILD,
+
+	/* keep last */
+	__NL802154_PEER_TYPE_AFTER_LAST,
+	NL802154_PEER_TYPE_MAX = __NL802154_PEER_TYPE_AFTER_LAST - 1
+};
+
+#ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
+
 enum nl802154_key_id_modes {
 	NL802154_KEY_ID_MODE_IMPLICIT,
 	NL802154_KEY_ID_MODE_INDEX,
diff --git a/net/ieee802154/nl802154.c b/net/ieee802154/nl802154.c
index e16e57fc34d0..e26d7cec02ce 100644
--- a/net/ieee802154/nl802154.c
+++ b/net/ieee802154/nl802154.c
@@ -235,6 +235,7 @@ static const struct nla_policy nl802154_policy[NL802154_ATTR_MAX+1] = {
 	[NL802154_ATTR_BEACON_INTERVAL] =
 		NLA_POLICY_MAX(NLA_U8, IEEE802154_ACTIVE_SCAN_DURATION),
 	[NL802154_ATTR_MAX_ASSOCIATIONS] = { .type = NLA_U32 },
+	[NL802154_ATTR_PEER] = { .type = NLA_NESTED },
 
 #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
 	[NL802154_ATTR_SEC_ENABLED] = { .type = NLA_U8, },
@@ -1717,6 +1718,107 @@ static int nl802154_set_max_associations(struct sk_buff *skb, struct genl_info *
 	return 0;
 }
 
+static int nl802154_send_peer_info(struct sk_buff *msg,
+				   struct netlink_callback *cb,
+				   u32 seq, int flags,
+				   struct cfg802154_registered_device *rdev,
+				   struct wpan_dev *wpan_dev,
+				   struct ieee802154_pan_device *peer,
+				   enum nl802154_peer_type type)
+{
+	struct nlattr *nla;
+	void *hdr;
+
+	ASSERT_RTNL();
+
+	hdr = nl802154hdr_put(msg, NETLINK_CB(cb->skb).portid, seq, flags,
+			      NL802154_CMD_LIST_ASSOCIATIONS);
+	if (!hdr)
+		return -ENOBUFS;
+
+	genl_dump_check_consistent(cb, hdr);
+
+	if (nla_put_u32(msg, NL802154_ATTR_GENERATION,
+			wpan_dev->association_generation))
+		goto nla_put_failure;
+
+	nla = nla_nest_start_noflag(msg, NL802154_ATTR_PEER);
+	if (!nla)
+		goto nla_put_failure;
+
+	if (nla_put_u8(msg, NL802154_DEV_ADDR_ATTR_PEER_TYPE, type))
+		goto nla_put_failure;
+
+	if (nla_put_u8(msg, NL802154_DEV_ADDR_ATTR_MODE, peer->mode))
+		goto nla_put_failure;
+
+	if (nla_put(msg, NL802154_DEV_ADDR_ATTR_SHORT,
+		    IEEE802154_SHORT_ADDR_LEN, &peer->short_addr))
+		goto nla_put_failure;
+
+	if (nla_put(msg, NL802154_DEV_ADDR_ATTR_EXTENDED,
+		    IEEE802154_EXTENDED_ADDR_LEN, &peer->extended_addr))
+		goto nla_put_failure;
+
+	nla_nest_end(msg, nla);
+
+	genlmsg_end(msg, hdr);
+
+	return 0;
+
+ nla_put_failure:
+	genlmsg_cancel(msg, hdr);
+	return -EMSGSIZE;
+}
+
+static int nl802154_list_associations(struct sk_buff *skb,
+				      struct netlink_callback *cb)
+{
+	struct cfg802154_registered_device *rdev;
+	struct ieee802154_pan_device *child;
+	struct wpan_dev *wpan_dev;
+	int err;
+
+	err = nl802154_prepare_wpan_dev_dump(skb, cb, &rdev, &wpan_dev);
+	if (err)
+		return err;
+
+	mutex_lock(&wpan_dev->association_lock);
+
+	if (cb->args[2])
+		goto out;
+
+	cb->seq = wpan_dev->association_generation;
+
+	if (wpan_dev->parent) {
+		err = nl802154_send_peer_info(skb, cb, cb->nlh->nlmsg_seq,
+					      NLM_F_MULTI, rdev, wpan_dev,
+					      wpan_dev->parent,
+					      NL802154_PEER_TYPE_PARENT);
+		if (err < 0)
+			goto out_err;
+	}
+
+	list_for_each_entry(child, &wpan_dev->children, node) {
+		err = nl802154_send_peer_info(skb, cb, cb->nlh->nlmsg_seq,
+					      NLM_F_MULTI, rdev, wpan_dev,
+					      child,
+					      NL802154_PEER_TYPE_CHILD);
+		if (err < 0)
+			goto out_err;
+	}
+
+	cb->args[2] = 1;
+out:
+	err = skb->len;
+out_err:
+	mutex_unlock(&wpan_dev->association_lock);
+
+	nl802154_finish_wpan_dev_dump(rdev);
+
+	return err;
+}
+
 #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
 static const struct nla_policy nl802154_dev_addr_policy[NL802154_DEV_ADDR_ATTR_MAX + 1] = {
 	[NL802154_DEV_ADDR_ATTR_PAN_ID] = { .type = NLA_U16 },
@@ -2861,6 +2963,11 @@ static const struct genl_ops nl802154_ops[] = {
 		.internal_flags = NL802154_FLAG_NEED_NETDEV |
 				  NL802154_FLAG_NEED_RTNL,
 	},
+	{
+		.cmd = NL802154_CMD_LIST_ASSOCIATIONS,
+		.dumpit = nl802154_list_associations,
+		/* can be retrieved by unprivileged users */
+	},
 #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
 	{
 		.cmd = NL802154_CMD_SET_SEC_PARAMS,
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* Re: [PATCH wpan-next 04/11] mac802154: Handle associating
  2023-06-01 15:48 ` [PATCH wpan-next 04/11] mac802154: Handle associating Miquel Raynal
@ 2023-06-02 15:54   ` Simon Horman
  2023-08-18 14:17     ` Miquel Raynal
  2023-06-03 10:09   ` Alexander Aring
  1 sibling, 1 reply; 24+ messages in thread
From: Simon Horman @ 2023-06-02 15:54 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Alexander Aring, Stefan Schmidt, linux-wpan, David S. Miller,
	Jakub Kicinski, Paolo Abeni, Eric Dumazet, netdev, David Girault,
	Romuald Despres, Frederic Blain, Nicolas Schodet,
	Guilhem Imberton, Thomas Petazzoni

On Thu, Jun 01, 2023 at 05:48:10PM +0200, Miquel Raynal wrote:
> Joining a PAN officially goes by associating with a coordinator. This
> coordinator may have been discovered thanks to the beacons it sent in
> the past. Add support to the MAC layer for these associations, which
> require:
> - Sending an association request
> - Receiving an association response
> 
> The association response contains the association status, eventually a
> reason if the association was unsuccessful, and finally a short address
> that we should use for intra-PAN communication from now on, if we
> required one (which is the default, and not yet configurable).
> 
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>

...

> diff --git a/net/ieee802154/core.c b/net/ieee802154/core.c
> index cd69bdbfd59f..8bf01bb7e858 100644
> --- a/net/ieee802154/core.c
> +++ b/net/ieee802154/core.c
> @@ -198,6 +198,18 @@ void wpan_phy_free(struct wpan_phy *phy)
>  }
>  EXPORT_SYMBOL(wpan_phy_free);
>  
> +static void cfg802154_free_peer_structures(struct wpan_dev *wpan_dev)
> +{
> +	mutex_lock(&wpan_dev->association_lock);
> +
> +	if (wpan_dev->parent)
> +		kfree(wpan_dev->parent);

Hi Miquel,

a minor nit from my side: There no need to check for NULL before calling
kfree, because kfree will do nothing with a NULL argument.

> +
> +	wpan_dev->association_generation++;
> +
> +	mutex_unlock(&wpan_dev->association_lock);
> +}
> +
>  int cfg802154_switch_netns(struct cfg802154_registered_device *rdev,
>  			   struct net *net)
>  {

...

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH wpan-next 04/11] mac802154: Handle associating
  2023-06-01 15:48 ` [PATCH wpan-next 04/11] mac802154: Handle associating Miquel Raynal
  2023-06-02 15:54   ` Simon Horman
@ 2023-06-03 10:09   ` Alexander Aring
  2023-07-04 11:34     ` Alexander Aring
                       ` (2 more replies)
  1 sibling, 3 replies; 24+ messages in thread
From: Alexander Aring @ 2023-06-03 10:09 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Alexander Aring, Stefan Schmidt, linux-wpan, David S. Miller,
	Jakub Kicinski, Paolo Abeni, Eric Dumazet, netdev, David Girault,
	Romuald Despres, Frederic Blain, Nicolas Schodet,
	Guilhem Imberton, Thomas Petazzoni

Hi,

On Thu, Jun 1, 2023 at 11:50 AM Miquel Raynal <miquel.raynal@bootlin.com> wrote:
>
> Joining a PAN officially goes by associating with a coordinator. This
> coordinator may have been discovered thanks to the beacons it sent in
> the past. Add support to the MAC layer for these associations, which
> require:
> - Sending an association request
> - Receiving an association response
>
> The association response contains the association status, eventually a
> reason if the association was unsuccessful, and finally a short address
> that we should use for intra-PAN communication from now on, if we
> required one (which is the default, and not yet configurable).
>
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> ---
>  include/linux/ieee802154.h      |   1 +
>  include/net/cfg802154.h         |   1 +
>  include/net/ieee802154_netdev.h |   5 ++
>  net/ieee802154/core.c           |  14 ++++
>  net/mac802154/cfg.c             |  72 ++++++++++++++++++
>  net/mac802154/ieee802154_i.h    |  19 +++++
>  net/mac802154/main.c            |   2 +
>  net/mac802154/rx.c              |   9 +++
>  net/mac802154/scan.c            | 127 ++++++++++++++++++++++++++++++++
>  9 files changed, 250 insertions(+)
>
> diff --git a/include/linux/ieee802154.h b/include/linux/ieee802154.h
> index 140f61ec0f5f..c72bd76cac1b 100644
> --- a/include/linux/ieee802154.h
> +++ b/include/linux/ieee802154.h
> @@ -37,6 +37,7 @@
>                                          IEEE802154_FCS_LEN)
>
>  #define IEEE802154_PAN_ID_BROADCAST    0xffff
> +#define IEEE802154_ADDR_LONG_BROADCAST 0xffffffffffffffffULL
>  #define IEEE802154_ADDR_SHORT_BROADCAST        0xffff
>  #define IEEE802154_ADDR_SHORT_UNSPEC   0xfffe
>
> diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h
> index 3b9d65455b9a..dd0964d351cd 100644
> --- a/include/net/cfg802154.h
> +++ b/include/net/cfg802154.h
> @@ -502,6 +502,7 @@ struct wpan_dev {
>         struct mutex association_lock;
>         struct ieee802154_pan_device *parent;
>         struct list_head children;
> +       unsigned int association_generation;
>  };
>
>  #define to_phy(_dev)   container_of(_dev, struct wpan_phy, dev)
> diff --git a/include/net/ieee802154_netdev.h b/include/net/ieee802154_netdev.h
> index ca8c827d0d7f..e26ffd079556 100644
> --- a/include/net/ieee802154_netdev.h
> +++ b/include/net/ieee802154_netdev.h
> @@ -149,6 +149,11 @@ struct ieee802154_assoc_req_pl {
>  #endif
>  } __packed;
>
> +struct ieee802154_assoc_resp_pl {
> +       __le16 short_addr;
> +       u8 status;
> +} __packed;
> +
>  enum ieee802154_frame_version {
>         IEEE802154_2003_STD,
>         IEEE802154_2006_STD,
> diff --git a/net/ieee802154/core.c b/net/ieee802154/core.c
> index cd69bdbfd59f..8bf01bb7e858 100644
> --- a/net/ieee802154/core.c
> +++ b/net/ieee802154/core.c
> @@ -198,6 +198,18 @@ void wpan_phy_free(struct wpan_phy *phy)
>  }
>  EXPORT_SYMBOL(wpan_phy_free);
>
> +static void cfg802154_free_peer_structures(struct wpan_dev *wpan_dev)
> +{
> +       mutex_lock(&wpan_dev->association_lock);
> +
> +       if (wpan_dev->parent)
> +               kfree(wpan_dev->parent);
> +
> +       wpan_dev->association_generation++;
> +
> +       mutex_unlock(&wpan_dev->association_lock);
> +}
> +
>  int cfg802154_switch_netns(struct cfg802154_registered_device *rdev,
>                            struct net *net)
>  {
> @@ -293,6 +305,8 @@ static int cfg802154_netdev_notifier_call(struct notifier_block *nb,
>                 rdev->opencount++;
>                 break;
>         case NETDEV_UNREGISTER:
> +               cfg802154_free_peer_structures(wpan_dev);
> +

I think the comment below is not relevant here, but I have also no
idea if this is still the case.

>                 /* It is possible to get NETDEV_UNREGISTER
>                  * multiple times. To detect that, check
>                  * that the interface is still on the list
> diff --git a/net/mac802154/cfg.c b/net/mac802154/cfg.c
> index 5c3cb019f751..89112d2bcee7 100644
> --- a/net/mac802154/cfg.c
> +++ b/net/mac802154/cfg.c
> @@ -315,6 +315,77 @@ static int mac802154_stop_beacons(struct wpan_phy *wpan_phy,
>         return mac802154_stop_beacons_locked(local, sdata);
>  }
>
> +static int mac802154_associate(struct wpan_phy *wpan_phy,
> +                              struct wpan_dev *wpan_dev,
> +                              struct ieee802154_addr *coord)
> +{
> +       struct ieee802154_local *local = wpan_phy_priv(wpan_phy);
> +       u64 ceaddr = swab64((__force u64)coord->extended_addr);
> +       struct ieee802154_sub_if_data *sdata;
> +       struct ieee802154_pan_device *parent;
> +       __le16 short_addr;
> +       int ret;
> +
> +       ASSERT_RTNL();
> +
> +       sdata = IEEE802154_WPAN_DEV_TO_SUB_IF(wpan_dev);
> +
> +       if (wpan_dev->parent) {
> +               dev_err(&sdata->dev->dev,
> +                       "Device %8phC is already associated\n", &ceaddr);
> +               return -EPERM;
> +       }
> +
> +       parent = kzalloc(sizeof(*parent), GFP_KERNEL);
> +       if (!parent)
> +               return -ENOMEM;
> +
> +       parent->pan_id = coord->pan_id;
> +       parent->mode = coord->mode;
> +       if (parent->mode == IEEE802154_SHORT_ADDRESSING) {
> +               parent->short_addr = coord->short_addr;
> +               parent->extended_addr = cpu_to_le64(IEEE802154_ADDR_LONG_BROADCAST);

There is no IEEE802154_ADDR_LONG_BROADCAST (extended address) address.
The broadcast address is always a short address 0xffff. (Talkin about
destination addresses).

Just to clarify we can have here two different types/length of mac
addresses being used, whereas the extended address is always present.
We have the monitor interface set to an invalid extended address
0x0...0 (talking about source address) which is a reserved EUI64 (what
long/extended address is) address, 0xffff...ffff is also being
reserved. Monitors get their address from the socket interface.

If there is a parent, an extended address is always present and known.
A short address can be set, but is not required as a node to have.
Sure if a node has a short address, you want to use a short address
because it saves payload.
Also remember when an address is unique in the network, an extended
address (LONG) is always being unique, a short address is unique in
combination of pan id + short address.

If you save some neighbors you want to store the extended and if
present panid/shortaddress.

Or I do not understand something here?

btw: as you probably noticed, the netdev interface dev_addr is an
extended address (because it's always present). Now there comes the
ugly part, netdevs cannot deal with other dev_addrs with different
length, that's why it's stored in the wpan specific dev structure and
things don't get easy and solutions need to be found how to make it
working... get prepared to get crazy...

- Alex


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH wpan-next 07/11] mac802154: Handle association requests from peers
  2023-06-01 15:48 ` [PATCH wpan-next 07/11] mac802154: Handle association requests from peers Miquel Raynal
@ 2023-06-03 11:28   ` Alexander Aring
  2023-08-21  8:52     ` Miquel Raynal
  0 siblings, 1 reply; 24+ messages in thread
From: Alexander Aring @ 2023-06-03 11:28 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Alexander Aring, Stefan Schmidt, linux-wpan, David S. Miller,
	Jakub Kicinski, Paolo Abeni, Eric Dumazet, netdev, David Girault,
	Romuald Despres, Frederic Blain, Nicolas Schodet,
	Guilhem Imberton, Thomas Petazzoni

Hi,

On Thu, Jun 1, 2023 at 11:50 AM Miquel Raynal <miquel.raynal@bootlin.com> wrote:
>
> Coordinators may have to handle association requests from peers which
> want to join the PAN. The logic involves:
> - Acknowledging the request (done by hardware)
> - If requested, a random short address that is free on this PAN should
>   be chosen for the device.
> - Sending an association response with the short address allocated for
>   the peer and expecting it to be ack'ed.
>
> If anything fails during this procedure, the peer is considered not
> associated.
>
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> ---
>  include/net/cfg802154.h         |   7 ++
>  include/net/ieee802154_netdev.h |   6 ++
>  net/ieee802154/core.c           |   7 ++
>  net/ieee802154/pan.c            |  27 ++++++
>  net/mac802154/ieee802154_i.h    |   2 +
>  net/mac802154/rx.c              |   8 ++
>  net/mac802154/scan.c            | 147 ++++++++++++++++++++++++++++++++
>  7 files changed, 204 insertions(+)
>
> diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h
> index 01bc6c2da7b9..4404072365e7 100644
> --- a/include/net/cfg802154.h
> +++ b/include/net/cfg802154.h
> @@ -582,4 +582,11 @@ struct ieee802154_pan_device *
>  cfg802154_device_is_child(struct wpan_dev *wpan_dev,
>                           struct ieee802154_addr *target);
>
> +/**
> + * cfg802154_get_free_short_addr - Get a free address among the known devices
> + * @wpan_dev: the wpan device
> + * @return: a random short address expectedly unused on our PAN
> + */
> +__le16 cfg802154_get_free_short_addr(struct wpan_dev *wpan_dev);
> +
>  #endif /* __NET_CFG802154_H */
> diff --git a/include/net/ieee802154_netdev.h b/include/net/ieee802154_netdev.h
> index 16194356cfe7..4de858f9929e 100644
> --- a/include/net/ieee802154_netdev.h
> +++ b/include/net/ieee802154_netdev.h
> @@ -211,6 +211,12 @@ struct ieee802154_association_req_frame {
>         struct ieee802154_assoc_req_pl assoc_req_pl;
>  };
>
> +struct ieee802154_association_resp_frame {
> +       struct ieee802154_hdr mhr;
> +       struct ieee802154_mac_cmd_pl mac_pl;
> +       struct ieee802154_assoc_resp_pl assoc_resp_pl;
> +};
> +
>  struct ieee802154_disassociation_notif_frame {
>         struct ieee802154_hdr mhr;
>         struct ieee802154_mac_cmd_pl mac_pl;
> diff --git a/net/ieee802154/core.c b/net/ieee802154/core.c
> index 8bf01bb7e858..39674db64336 100644
> --- a/net/ieee802154/core.c
> +++ b/net/ieee802154/core.c
> @@ -200,11 +200,18 @@ EXPORT_SYMBOL(wpan_phy_free);
>
>  static void cfg802154_free_peer_structures(struct wpan_dev *wpan_dev)
>  {
> +       struct ieee802154_pan_device *child, *tmp;
> +
>         mutex_lock(&wpan_dev->association_lock);
>
>         if (wpan_dev->parent)
>                 kfree(wpan_dev->parent);
>
> +       list_for_each_entry_safe(child, tmp, &wpan_dev->children, node) {
> +               list_del(&child->node);
> +               kfree(child);
> +       }
> +
>         wpan_dev->association_generation++;
>
>         mutex_unlock(&wpan_dev->association_lock);
> diff --git a/net/ieee802154/pan.c b/net/ieee802154/pan.c
> index 477e8dad0cf0..7756906c201d 100644
> --- a/net/ieee802154/pan.c
> +++ b/net/ieee802154/pan.c
> @@ -66,3 +66,30 @@ cfg802154_device_is_child(struct wpan_dev *wpan_dev,
>         return NULL;
>  }
>  EXPORT_SYMBOL_GPL(cfg802154_device_is_child);
> +
> +__le16 cfg802154_get_free_short_addr(struct wpan_dev *wpan_dev)
> +{
> +       struct ieee802154_pan_device *child;
> +       __le16 addr;
> +
> +       lockdep_assert_held(&wpan_dev->association_lock);
> +
> +       do {
> +               get_random_bytes(&addr, 2);

This is combined with the max associations setting? I am not sure if
this is the best way to get free values from a u16 value where we have
some data structure of "given" addresses to a node. I recently was
looking into idr/xarray data structure... maybe we can use something
from there.

- Alex


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH wpan-next 06/11] mac802154: Handle disassociations
  2023-06-01 15:48 ` [PATCH wpan-next 06/11] mac802154: Handle disassociations Miquel Raynal
@ 2023-06-03 11:30   ` Alexander Aring
  2023-08-21  9:02     ` Miquel Raynal
  0 siblings, 1 reply; 24+ messages in thread
From: Alexander Aring @ 2023-06-03 11:30 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Alexander Aring, Stefan Schmidt, linux-wpan, David S. Miller,
	Jakub Kicinski, Paolo Abeni, Eric Dumazet, netdev, David Girault,
	Romuald Despres, Frederic Blain, Nicolas Schodet,
	Guilhem Imberton, Thomas Petazzoni

Hi,

On Thu, Jun 1, 2023 at 11:50 AM Miquel Raynal <miquel.raynal@bootlin.com> wrote:
>
> Devices may decide to disassociate from their coordinator for different
> reasons (device turning off, coordinator signal strength too low, etc),
> the MAC layer just has to send a disassociation notification.
>
> If the ack of the disassociation notification is not received, the
> device may consider itself disassociated anyway.
>
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> ---
>  net/ieee802154/pan.c         |   2 +
>  net/mac802154/cfg.c          | 102 +++++++++++++++++++++++++++++++++++
>  net/mac802154/ieee802154_i.h |   4 ++
>  net/mac802154/scan.c         |  60 +++++++++++++++++++++
>  4 files changed, 168 insertions(+)
>
> diff --git a/net/ieee802154/pan.c b/net/ieee802154/pan.c
> index e2a12a42ba2b..477e8dad0cf0 100644
> --- a/net/ieee802154/pan.c
> +++ b/net/ieee802154/pan.c
> @@ -49,6 +49,7 @@ bool cfg802154_device_is_parent(struct wpan_dev *wpan_dev,
>
>         return false;
>  }
> +EXPORT_SYMBOL_GPL(cfg802154_device_is_parent);
>
>  struct ieee802154_pan_device *
>  cfg802154_device_is_child(struct wpan_dev *wpan_dev,
> @@ -64,3 +65,4 @@ cfg802154_device_is_child(struct wpan_dev *wpan_dev,
>
>         return NULL;
>  }
> +EXPORT_SYMBOL_GPL(cfg802154_device_is_child);
> diff --git a/net/mac802154/cfg.c b/net/mac802154/cfg.c
> index 89112d2bcee7..c27c05e825ff 100644
> --- a/net/mac802154/cfg.c
> +++ b/net/mac802154/cfg.c
> @@ -386,6 +386,107 @@ static int mac802154_associate(struct wpan_phy *wpan_phy,
>         return ret;
>  }
>
> +static int mac802154_disassociate_from_parent(struct wpan_phy *wpan_phy,
> +                                             struct wpan_dev *wpan_dev)
> +{
> +       struct ieee802154_local *local = wpan_phy_priv(wpan_phy);
> +       struct ieee802154_pan_device *child, *tmp;
> +       struct ieee802154_sub_if_data *sdata;
> +       u64 eaddr;
> +       int ret;
> +
> +       sdata = IEEE802154_WPAN_DEV_TO_SUB_IF(wpan_dev);
> +
> +       /* Start by disassociating all the children and preventing new ones to
> +        * attempt associations.
> +        */
> +       list_for_each_entry_safe(child, tmp, &wpan_dev->children, node) {
> +               ret = mac802154_send_disassociation_notif(sdata, child,
> +                                                         IEEE802154_COORD_WISHES_DEVICE_TO_LEAVE);
> +               if (ret) {
> +                       eaddr = swab64((__force u64)child->extended_addr);

Does this pass sparse? I think this needs to be le64_to_cpu()?

- Alex


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH wpan-next 04/11] mac802154: Handle associating
  2023-06-03 10:09   ` Alexander Aring
@ 2023-07-04 11:34     ` Alexander Aring
  2023-09-01 15:01     ` Miquel Raynal
  2023-09-01 15:31     ` Miquel Raynal
  2 siblings, 0 replies; 24+ messages in thread
From: Alexander Aring @ 2023-07-04 11:34 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Alexander Aring, Stefan Schmidt, linux-wpan, David S. Miller,
	Jakub Kicinski, Paolo Abeni, Eric Dumazet, netdev, David Girault,
	Romuald Despres, Frederic Blain, Nicolas Schodet,
	Guilhem Imberton, Thomas Petazzoni

Hi,

On Sat, Jun 3, 2023 at 6:09 AM Alexander Aring <aahringo@redhat.com> wrote:
>
> Hi,
>
> On Thu, Jun 1, 2023 at 11:50 AM Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> >
> > Joining a PAN officially goes by associating with a coordinator. This
> > coordinator may have been discovered thanks to the beacons it sent in
> > the past. Add support to the MAC layer for these associations, which
> > require:
> > - Sending an association request
> > - Receiving an association response
> >
> > The association response contains the association status, eventually a
> > reason if the association was unsuccessful, and finally a short address
> > that we should use for intra-PAN communication from now on, if we
> > required one (which is the default, and not yet configurable).
> >
> > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> > ---
> >  include/linux/ieee802154.h      |   1 +
> >  include/net/cfg802154.h         |   1 +
> >  include/net/ieee802154_netdev.h |   5 ++
> >  net/ieee802154/core.c           |  14 ++++
> >  net/mac802154/cfg.c             |  72 ++++++++++++++++++
> >  net/mac802154/ieee802154_i.h    |  19 +++++
> >  net/mac802154/main.c            |   2 +
> >  net/mac802154/rx.c              |   9 +++
> >  net/mac802154/scan.c            | 127 ++++++++++++++++++++++++++++++++
> >  9 files changed, 250 insertions(+)
> >
> > diff --git a/include/linux/ieee802154.h b/include/linux/ieee802154.h
> > index 140f61ec0f5f..c72bd76cac1b 100644
> > --- a/include/linux/ieee802154.h
> > +++ b/include/linux/ieee802154.h
> > @@ -37,6 +37,7 @@
> >                                          IEEE802154_FCS_LEN)
> >
> >  #define IEEE802154_PAN_ID_BROADCAST    0xffff
> > +#define IEEE802154_ADDR_LONG_BROADCAST 0xffffffffffffffffULL
> >  #define IEEE802154_ADDR_SHORT_BROADCAST        0xffff
> >  #define IEEE802154_ADDR_SHORT_UNSPEC   0xfffe
> >
> > diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h
> > index 3b9d65455b9a..dd0964d351cd 100644
> > --- a/include/net/cfg802154.h
> > +++ b/include/net/cfg802154.h
> > @@ -502,6 +502,7 @@ struct wpan_dev {
> >         struct mutex association_lock;
> >         struct ieee802154_pan_device *parent;
> >         struct list_head children;
> > +       unsigned int association_generation;
> >  };
> >
> >  #define to_phy(_dev)   container_of(_dev, struct wpan_phy, dev)
> > diff --git a/include/net/ieee802154_netdev.h b/include/net/ieee802154_netdev.h
> > index ca8c827d0d7f..e26ffd079556 100644
> > --- a/include/net/ieee802154_netdev.h
> > +++ b/include/net/ieee802154_netdev.h
> > @@ -149,6 +149,11 @@ struct ieee802154_assoc_req_pl {
> >  #endif
> >  } __packed;
> >
> > +struct ieee802154_assoc_resp_pl {
> > +       __le16 short_addr;
> > +       u8 status;
> > +} __packed;
> > +
> >  enum ieee802154_frame_version {
> >         IEEE802154_2003_STD,
> >         IEEE802154_2006_STD,
> > diff --git a/net/ieee802154/core.c b/net/ieee802154/core.c
> > index cd69bdbfd59f..8bf01bb7e858 100644
> > --- a/net/ieee802154/core.c
> > +++ b/net/ieee802154/core.c
> > @@ -198,6 +198,18 @@ void wpan_phy_free(struct wpan_phy *phy)
> >  }
> >  EXPORT_SYMBOL(wpan_phy_free);
> >
> > +static void cfg802154_free_peer_structures(struct wpan_dev *wpan_dev)
> > +{
> > +       mutex_lock(&wpan_dev->association_lock);
> > +
> > +       if (wpan_dev->parent)
> > +               kfree(wpan_dev->parent);
> > +
> > +       wpan_dev->association_generation++;
> > +
> > +       mutex_unlock(&wpan_dev->association_lock);
> > +}
> > +
> >  int cfg802154_switch_netns(struct cfg802154_registered_device *rdev,
> >                            struct net *net)
> >  {
> > @@ -293,6 +305,8 @@ static int cfg802154_netdev_notifier_call(struct notifier_block *nb,
> >                 rdev->opencount++;
> >                 break;
> >         case NETDEV_UNREGISTER:
> > +               cfg802154_free_peer_structures(wpan_dev);
> > +
>
> I think the comment below is not relevant here, but I have also no
> idea if this is still the case.
>
> >                 /* It is possible to get NETDEV_UNREGISTER
> >                  * multiple times. To detect that, check
> >                  * that the interface is still on the list
> > diff --git a/net/mac802154/cfg.c b/net/mac802154/cfg.c
> > index 5c3cb019f751..89112d2bcee7 100644
> > --- a/net/mac802154/cfg.c
> > +++ b/net/mac802154/cfg.c
> > @@ -315,6 +315,77 @@ static int mac802154_stop_beacons(struct wpan_phy *wpan_phy,
> >         return mac802154_stop_beacons_locked(local, sdata);
> >  }
> >
> > +static int mac802154_associate(struct wpan_phy *wpan_phy,
> > +                              struct wpan_dev *wpan_dev,
> > +                              struct ieee802154_addr *coord)
> > +{
> > +       struct ieee802154_local *local = wpan_phy_priv(wpan_phy);
> > +       u64 ceaddr = swab64((__force u64)coord->extended_addr);
> > +       struct ieee802154_sub_if_data *sdata;
> > +       struct ieee802154_pan_device *parent;
> > +       __le16 short_addr;
> > +       int ret;
> > +
> > +       ASSERT_RTNL();
> > +
> > +       sdata = IEEE802154_WPAN_DEV_TO_SUB_IF(wpan_dev);
> > +
> > +       if (wpan_dev->parent) {
> > +               dev_err(&sdata->dev->dev,
> > +                       "Device %8phC is already associated\n", &ceaddr);
> > +               return -EPERM;
> > +       }
> > +
> > +       parent = kzalloc(sizeof(*parent), GFP_KERNEL);
> > +       if (!parent)
> > +               return -ENOMEM;
> > +
> > +       parent->pan_id = coord->pan_id;
> > +       parent->mode = coord->mode;
> > +       if (parent->mode == IEEE802154_SHORT_ADDRESSING) {
> > +               parent->short_addr = coord->short_addr;
> > +               parent->extended_addr = cpu_to_le64(IEEE802154_ADDR_LONG_BROADCAST);
>
> There is no IEEE802154_ADDR_LONG_BROADCAST (extended address) address.
> The broadcast address is always a short address 0xffff. (Talkin about
> destination addresses).
>
> Just to clarify we can have here two different types/length of mac
> addresses being used, whereas the extended address is always present.
> We have the monitor interface set to an invalid extended address
> 0x0...0 (talking about source address) which is a reserved EUI64 (what
> long/extended address is) address, 0xffff...ffff is also being
> reserved. Monitors get their address from the socket interface.
>
> If there is a parent, an extended address is always present and known.

I want to weaken this, we can also have only the short address of the
neighbor. But it depends on assoc/deassoc, I would think the extended
address should be known. If you look on air and make per neighbor
stats... you can see a neighbor with either a short or extended
address being used. Map them to one neighbor if using a short address
is only possible if you know the mapping... (but this is so far I see
not the case here).

We need some kind of policy here, but with assoc/deassoc we should
always know this mapping.

- Alex


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH wpan-next 04/11] mac802154: Handle associating
  2023-06-02 15:54   ` Simon Horman
@ 2023-08-18 14:17     ` Miquel Raynal
  0 siblings, 0 replies; 24+ messages in thread
From: Miquel Raynal @ 2023-08-18 14:17 UTC (permalink / raw)
  To: Simon Horman
  Cc: Alexander Aring, Stefan Schmidt, linux-wpan, David S. Miller,
	Jakub Kicinski, Paolo Abeni, Eric Dumazet, netdev, David Girault,
	Romuald Despres, Frederic Blain, Nicolas Schodet,
	Guilhem Imberton, Thomas Petazzoni

Hi Simon,

simon.horman@corigine.com wrote on Fri, 2 Jun 2023 17:54:40 +0200:

> On Thu, Jun 01, 2023 at 05:48:10PM +0200, Miquel Raynal wrote:
> > Joining a PAN officially goes by associating with a coordinator. This
> > coordinator may have been discovered thanks to the beacons it sent in
> > the past. Add support to the MAC layer for these associations, which
> > require:
> > - Sending an association request
> > - Receiving an association response
> > 
> > The association response contains the association status, eventually a
> > reason if the association was unsuccessful, and finally a short address
> > that we should use for intra-PAN communication from now on, if we
> > required one (which is the default, and not yet configurable).
> > 
> > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>  
> 
> ...
> 
> > diff --git a/net/ieee802154/core.c b/net/ieee802154/core.c
> > index cd69bdbfd59f..8bf01bb7e858 100644
> > --- a/net/ieee802154/core.c
> > +++ b/net/ieee802154/core.c
> > @@ -198,6 +198,18 @@ void wpan_phy_free(struct wpan_phy *phy)
> >  }
> >  EXPORT_SYMBOL(wpan_phy_free);
> >  
> > +static void cfg802154_free_peer_structures(struct wpan_dev *wpan_dev)
> > +{
> > +	mutex_lock(&wpan_dev->association_lock);
> > +
> > +	if (wpan_dev->parent)
> > +		kfree(wpan_dev->parent);  
> 
> Hi Miquel,
> 
> a minor nit from my side: There no need to check for NULL before calling
> kfree, because kfree will do nothing with a NULL argument.

Sorry for the delay, yes of course, I will drop the extra check.

Thanks,
Miquèl

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH wpan-next 07/11] mac802154: Handle association requests from peers
  2023-06-03 11:28   ` Alexander Aring
@ 2023-08-21  8:52     ` Miquel Raynal
  2023-09-01 15:45       ` Miquel Raynal
  0 siblings, 1 reply; 24+ messages in thread
From: Miquel Raynal @ 2023-08-21  8:52 UTC (permalink / raw)
  To: Alexander Aring
  Cc: Alexander Aring, Stefan Schmidt, linux-wpan, David S. Miller,
	Jakub Kicinski, Paolo Abeni, Eric Dumazet, netdev, David Girault,
	Romuald Despres, Frederic Blain, Nicolas Schodet,
	Guilhem Imberton, Thomas Petazzoni

Hi Alexander,

aahringo@redhat.com wrote on Sat, 3 Jun 2023 07:28:25 -0400:

> Hi,
> 
> On Thu, Jun 1, 2023 at 11:50 AM Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> >
> > Coordinators may have to handle association requests from peers which
> > want to join the PAN. The logic involves:
> > - Acknowledging the request (done by hardware)
> > - If requested, a random short address that is free on this PAN should
> >   be chosen for the device.
> > - Sending an association response with the short address allocated for
> >   the peer and expecting it to be ack'ed.
> >
> > If anything fails during this procedure, the peer is considered not
> > associated.
> >
> > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> > ---
> >  include/net/cfg802154.h         |   7 ++
> >  include/net/ieee802154_netdev.h |   6 ++
> >  net/ieee802154/core.c           |   7 ++
> >  net/ieee802154/pan.c            |  27 ++++++
> >  net/mac802154/ieee802154_i.h    |   2 +
> >  net/mac802154/rx.c              |   8 ++
> >  net/mac802154/scan.c            | 147 ++++++++++++++++++++++++++++++++
> >  7 files changed, 204 insertions(+)
> >
> > diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h
> > index 01bc6c2da7b9..4404072365e7 100644
> > --- a/include/net/cfg802154.h
> > +++ b/include/net/cfg802154.h
> > @@ -582,4 +582,11 @@ struct ieee802154_pan_device *
> >  cfg802154_device_is_child(struct wpan_dev *wpan_dev,
> >                           struct ieee802154_addr *target);
> >
> > +/**
> > + * cfg802154_get_free_short_addr - Get a free address among the known devices
> > + * @wpan_dev: the wpan device
> > + * @return: a random short address expectedly unused on our PAN
> > + */
> > +__le16 cfg802154_get_free_short_addr(struct wpan_dev *wpan_dev);
> > +
> >  #endif /* __NET_CFG802154_H */
> > diff --git a/include/net/ieee802154_netdev.h b/include/net/ieee802154_netdev.h
> > index 16194356cfe7..4de858f9929e 100644
> > --- a/include/net/ieee802154_netdev.h
> > +++ b/include/net/ieee802154_netdev.h
> > @@ -211,6 +211,12 @@ struct ieee802154_association_req_frame {
> >         struct ieee802154_assoc_req_pl assoc_req_pl;
> >  };
> >
> > +struct ieee802154_association_resp_frame {
> > +       struct ieee802154_hdr mhr;
> > +       struct ieee802154_mac_cmd_pl mac_pl;
> > +       struct ieee802154_assoc_resp_pl assoc_resp_pl;
> > +};
> > +
> >  struct ieee802154_disassociation_notif_frame {
> >         struct ieee802154_hdr mhr;
> >         struct ieee802154_mac_cmd_pl mac_pl;
> > diff --git a/net/ieee802154/core.c b/net/ieee802154/core.c
> > index 8bf01bb7e858..39674db64336 100644
> > --- a/net/ieee802154/core.c
> > +++ b/net/ieee802154/core.c
> > @@ -200,11 +200,18 @@ EXPORT_SYMBOL(wpan_phy_free);
> >
> >  static void cfg802154_free_peer_structures(struct wpan_dev *wpan_dev)
> >  {
> > +       struct ieee802154_pan_device *child, *tmp;
> > +
> >         mutex_lock(&wpan_dev->association_lock);
> >
> >         if (wpan_dev->parent)
> >                 kfree(wpan_dev->parent);
> >
> > +       list_for_each_entry_safe(child, tmp, &wpan_dev->children, node) {
> > +               list_del(&child->node);
> > +               kfree(child);
> > +       }
> > +
> >         wpan_dev->association_generation++;
> >
> >         mutex_unlock(&wpan_dev->association_lock);
> > diff --git a/net/ieee802154/pan.c b/net/ieee802154/pan.c
> > index 477e8dad0cf0..7756906c201d 100644
> > --- a/net/ieee802154/pan.c
> > +++ b/net/ieee802154/pan.c
> > @@ -66,3 +66,30 @@ cfg802154_device_is_child(struct wpan_dev *wpan_dev,
> >         return NULL;
> >  }
> >  EXPORT_SYMBOL_GPL(cfg802154_device_is_child);
> > +
> > +__le16 cfg802154_get_free_short_addr(struct wpan_dev *wpan_dev)
> > +{
> > +       struct ieee802154_pan_device *child;
> > +       __le16 addr;
> > +
> > +       lockdep_assert_held(&wpan_dev->association_lock);
> > +
> > +       do {
> > +               get_random_bytes(&addr, 2);  
> 
> This is combined with the max associations setting? I am not sure if
> this is the best way to get free values from a u16 value where we have
> some data structure of "given" addresses to a node. I recently was
> looking into idr/xarray data structure... maybe we can use something
> from there.

I actually thought about using an increasing index, but the pseudo
random generator seemed appropriate because of its "unpredictability",
but there is not real use for that (besides maybe testing purposes). I
can definitely switch to another solution.

Thanks,
Miquèl

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH wpan-next 06/11] mac802154: Handle disassociations
  2023-06-03 11:30   ` Alexander Aring
@ 2023-08-21  9:02     ` Miquel Raynal
  0 siblings, 0 replies; 24+ messages in thread
From: Miquel Raynal @ 2023-08-21  9:02 UTC (permalink / raw)
  To: Alexander Aring
  Cc: Alexander Aring, Stefan Schmidt, linux-wpan, David S. Miller,
	Jakub Kicinski, Paolo Abeni, Eric Dumazet, netdev, David Girault,
	Romuald Despres, Frederic Blain, Nicolas Schodet,
	Guilhem Imberton, Thomas Petazzoni

Hi Alexander,

aahringo@redhat.com wrote on Sat, 3 Jun 2023 07:30:05 -0400:

> Hi,
> 
> On Thu, Jun 1, 2023 at 11:50 AM Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> >
> > Devices may decide to disassociate from their coordinator for different
> > reasons (device turning off, coordinator signal strength too low, etc),
> > the MAC layer just has to send a disassociation notification.
> >
> > If the ack of the disassociation notification is not received, the
> > device may consider itself disassociated anyway.
> >
> > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> > ---
> >  net/ieee802154/pan.c         |   2 +
> >  net/mac802154/cfg.c          | 102 +++++++++++++++++++++++++++++++++++
> >  net/mac802154/ieee802154_i.h |   4 ++
> >  net/mac802154/scan.c         |  60 +++++++++++++++++++++
> >  4 files changed, 168 insertions(+)
> >
> > diff --git a/net/ieee802154/pan.c b/net/ieee802154/pan.c
> > index e2a12a42ba2b..477e8dad0cf0 100644
> > --- a/net/ieee802154/pan.c
> > +++ b/net/ieee802154/pan.c
> > @@ -49,6 +49,7 @@ bool cfg802154_device_is_parent(struct wpan_dev *wpan_dev,
> >
> >         return false;
> >  }
> > +EXPORT_SYMBOL_GPL(cfg802154_device_is_parent);
> >
> >  struct ieee802154_pan_device *
> >  cfg802154_device_is_child(struct wpan_dev *wpan_dev,
> > @@ -64,3 +65,4 @@ cfg802154_device_is_child(struct wpan_dev *wpan_dev,
> >
> >         return NULL;
> >  }
> > +EXPORT_SYMBOL_GPL(cfg802154_device_is_child);
> > diff --git a/net/mac802154/cfg.c b/net/mac802154/cfg.c
> > index 89112d2bcee7..c27c05e825ff 100644
> > --- a/net/mac802154/cfg.c
> > +++ b/net/mac802154/cfg.c
> > @@ -386,6 +386,107 @@ static int mac802154_associate(struct wpan_phy *wpan_phy,
> >         return ret;
> >  }
> >
> > +static int mac802154_disassociate_from_parent(struct wpan_phy *wpan_phy,
> > +                                             struct wpan_dev *wpan_dev)
> > +{
> > +       struct ieee802154_local *local = wpan_phy_priv(wpan_phy);
> > +       struct ieee802154_pan_device *child, *tmp;
> > +       struct ieee802154_sub_if_data *sdata;
> > +       u64 eaddr;
> > +       int ret;
> > +
> > +       sdata = IEEE802154_WPAN_DEV_TO_SUB_IF(wpan_dev);
> > +
> > +       /* Start by disassociating all the children and preventing new ones to
> > +        * attempt associations.
> > +        */
> > +       list_for_each_entry_safe(child, tmp, &wpan_dev->children, node) {
> > +               ret = mac802154_send_disassociation_notif(sdata, child,
> > +                                                         IEEE802154_COORD_WISHES_DEVICE_TO_LEAVE);
> > +               if (ret) {
> > +                       eaddr = swab64((__force u64)child->extended_addr);  
> 
> Does this pass sparse? I think this needs to be le64_to_cpu()?

I never feel comfortable with sparse given the dozens (hundreds) of
lines it outputs, but I think yes, parse does not seem to complain. To
be honest I think we should keep it this way just because I copy-pasted
it from other locations in the core:

$ git grep -c "swab64((__force u64)" -- net/ieee802154/ net/mac802154/
net/ieee802154/nl-mac.c:1
net/mac802154/cfg.c:4
net/mac802154/llsec.c:1
net/mac802154/rx.c:2
net/mac802154/scan.c:6

So if we ever want to change that, we could easily find them all and
replace them all in one go?

Thanks,
Miquèl

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH wpan-next 04/11] mac802154: Handle associating
  2023-06-03 10:09   ` Alexander Aring
  2023-07-04 11:34     ` Alexander Aring
@ 2023-09-01 15:01     ` Miquel Raynal
  2023-09-01 15:31     ` Miquel Raynal
  2 siblings, 0 replies; 24+ messages in thread
From: Miquel Raynal @ 2023-09-01 15:01 UTC (permalink / raw)
  To: Alexander Aring
  Cc: Alexander Aring, Stefan Schmidt, linux-wpan, David S. Miller,
	Jakub Kicinski, Paolo Abeni, Eric Dumazet, netdev, David Girault,
	Romuald Despres, Frederic Blain, Nicolas Schodet,
	Guilhem Imberton, Thomas Petazzoni

Hi Alexander,

> > @@ -293,6 +305,8 @@ static int cfg802154_netdev_notifier_call(struct notifier_block *nb,
> >                 rdev->opencount++;
> >                 break;
> >         case NETDEV_UNREGISTER:
> > +               cfg802154_free_peer_structures(wpan_dev);
> > +  
> 
> I think the comment below is not relevant here, but I have also no
> idea if this is still the case.

Yeah, I did not bother with it as it was off topic. I believe the call
above would anyway not be affected.

> >                 /* It is possible to get NETDEV_UNREGISTER
> >                  * multiple times. To detect that, check
> >                  * that the interface is still on the list
> > diff --git a/net/mac802154/cfg.c b/net/mac802154/cfg.c
> > index 5c3cb019f751..89112d2bcee7 100644
> > --- a/net/mac802154/cfg.c
> > +++ b/net/mac802154/cfg.c
> > @@ -315,6 +315,77 @@ static int mac802154_stop_beacons(struct wpan_phy *wpan_phy,
> >         return mac802154_stop_beacons_locked(local, sdata);
> >  }
> >
> > +static int mac802154_associate(struct wpan_phy *wpan_phy,
> > +                              struct wpan_dev *wpan_dev,
> > +                              struct ieee802154_addr *coord)
> > +{
> > +       struct ieee802154_local *local = wpan_phy_priv(wpan_phy);
> > +       u64 ceaddr = swab64((__force u64)coord->extended_addr);
> > +       struct ieee802154_sub_if_data *sdata;
> > +       struct ieee802154_pan_device *parent;
> > +       __le16 short_addr;
> > +       int ret;
> > +
> > +       ASSERT_RTNL();
> > +
> > +       sdata = IEEE802154_WPAN_DEV_TO_SUB_IF(wpan_dev);
> > +
> > +       if (wpan_dev->parent) {
> > +               dev_err(&sdata->dev->dev,
> > +                       "Device %8phC is already associated\n", &ceaddr);
> > +               return -EPERM;
> > +       }
> > +
> > +       parent = kzalloc(sizeof(*parent), GFP_KERNEL);
> > +       if (!parent)
> > +               return -ENOMEM;
> > +
> > +       parent->pan_id = coord->pan_id;
> > +       parent->mode = coord->mode;
> > +       if (parent->mode == IEEE802154_SHORT_ADDRESSING) {
> > +               parent->short_addr = coord->short_addr;
> > +               parent->extended_addr = cpu_to_le64(IEEE802154_ADDR_LONG_BROADCAST);  
> 
> There is no IEEE802154_ADDR_LONG_BROADCAST (extended address) address.
> The broadcast address is always a short address 0xffff. (Talkin about
> destination addresses).

You're totally right, this is misleading. I will just drop this
definition and its use, see below.

> Just to clarify we can have here two different types/length of mac
> addresses being used, whereas the extended address is always present.
> We have the monitor interface set to an invalid extended address
> 0x0...0 (talking about source address) which is a reserved EUI64 (what
> long/extended address is) address, 0xffff...ffff is also being
> reserved. Monitors get their address from the socket interface.
> 
> If there is a parent, an extended address is always present and known.
> A short address can be set, but is not required as a node to have.
> Sure if a node has a short address, you want to use a short address
> because it saves payload.
> Also remember when an address is unique in the network, an extended
> address (LONG) is always being unique, a short address is unique in
> combination of pan id + short address.

Absolutely.

> If you save some neighbors you want to store the extended and if
> present panid/shortaddress.

The code above was misleading, I will clarify it to only accept NL
association commands with an extended address. In fact the coord
structure is created in the nl802154 layer and it already only accepts
extended addresses (we don't expect the short address through the nl
command) so to answer your request: yes, the extended address will
always be there because we must know it.

Regarding the possibility to provide a short address, as we no longer
keep details about the surrounding devices inside the kernel (we only
keep the associated devices, either the parent or the children) keeping
this information would be useless. I don't see a need for it. The
NL interface can evolve later without breaking the compatibility if we
ever want to provide a short address as well and make something with it
(actually even today one could send the short address, it would simply
be ingored).

One thing however regarding the fact that we might want to store both a
short *and* an extended address in some cases: I created a "PAN device"
structure which allows this (because otherwise we had a union) as we
need to do it when we are parent as we are in charge of allocating the
short addresses:

+/**
+ * struct ieee802154_pan_device - PAN device information
+ * @pan_id: the PAN ID of this device
+ * @mode: the preferred mode to reach the device
+ * @short_addr: the short address of this device
+ * @extended_addr: the extended address of this device
+ * @node: the list node
+ */
+struct ieee802154_pan_device {
+       __le16 pan_id;
+       u8 mode;
+       __le16 short_addr;
+       __le64 extended_addr;
+       struct list_head node;
+};

> Or I do not understand something here?

No no, I think we are fully aligned :-)

> btw: as you probably noticed, the netdev interface dev_addr is an
> extended address (because it's always present). Now there comes the
> ugly part, netdevs cannot deal with other dev_addrs with different
> length, that's why it's stored in the wpan specific dev structure and
> things don't get easy and solutions need to be found how to make it
> working... get prepared to get crazy...

Yeah but I believe once we have proper PAN IDs/short address vs
extended address mappings we could have the translation internally at
least. I haven't investigated this for now.

Thanks,
Miquèl

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH wpan-next 04/11] mac802154: Handle associating
  2023-06-03 10:09   ` Alexander Aring
  2023-07-04 11:34     ` Alexander Aring
  2023-09-01 15:01     ` Miquel Raynal
@ 2023-09-01 15:31     ` Miquel Raynal
  2 siblings, 0 replies; 24+ messages in thread
From: Miquel Raynal @ 2023-09-01 15:31 UTC (permalink / raw)
  To: Alexander Aring
  Cc: Alexander Aring, Stefan Schmidt, linux-wpan, David S. Miller,
	Jakub Kicinski, Paolo Abeni, Eric Dumazet, netdev, David Girault,
	Romuald Despres, Frederic Blain, Nicolas Schodet,
	Guilhem Imberton, Thomas Petazzoni

Hi Alexander,

> > @@ -293,6 +305,8 @@ static int cfg802154_netdev_notifier_call(struct notifier_block *nb,
> >                 rdev->opencount++;
> >                 break;
> >         case NETDEV_UNREGISTER:
> > +               cfg802154_free_peer_structures(wpan_dev);
> > +  
> 
> I think the comment below is not relevant here, but I have also no
> idea if this is still the case.

Yeah, I did not bother with it as it was off topic. I believe the call
above would anyway not be affected.

> >                 /* It is possible to get NETDEV_UNREGISTER
> >                  * multiple times. To detect that, check
> >                  * that the interface is still on the list
> > diff --git a/net/mac802154/cfg.c b/net/mac802154/cfg.c
> > index 5c3cb019f751..89112d2bcee7 100644
> > --- a/net/mac802154/cfg.c
> > +++ b/net/mac802154/cfg.c
> > @@ -315,6 +315,77 @@ static int mac802154_stop_beacons(struct wpan_phy *wpan_phy,
> >         return mac802154_stop_beacons_locked(local, sdata);
> >  }
> >
> > +static int mac802154_associate(struct wpan_phy *wpan_phy,
> > +                              struct wpan_dev *wpan_dev,
> > +                              struct ieee802154_addr *coord)
> > +{
> > +       struct ieee802154_local *local = wpan_phy_priv(wpan_phy);
> > +       u64 ceaddr = swab64((__force u64)coord->extended_addr);
> > +       struct ieee802154_sub_if_data *sdata;
> > +       struct ieee802154_pan_device *parent;
> > +       __le16 short_addr;
> > +       int ret;
> > +
> > +       ASSERT_RTNL();
> > +
> > +       sdata = IEEE802154_WPAN_DEV_TO_SUB_IF(wpan_dev);
> > +
> > +       if (wpan_dev->parent) {
> > +               dev_err(&sdata->dev->dev,
> > +                       "Device %8phC is already associated\n", &ceaddr);
> > +               return -EPERM;
> > +       }
> > +
> > +       parent = kzalloc(sizeof(*parent), GFP_KERNEL);
> > +       if (!parent)
> > +               return -ENOMEM;
> > +
> > +       parent->pan_id = coord->pan_id;
> > +       parent->mode = coord->mode;
> > +       if (parent->mode == IEEE802154_SHORT_ADDRESSING) {
> > +               parent->short_addr = coord->short_addr;
> > +               parent->extended_addr = cpu_to_le64(IEEE802154_ADDR_LONG_BROADCAST);  
> 
> There is no IEEE802154_ADDR_LONG_BROADCAST (extended address) address.
> The broadcast address is always a short address 0xffff. (Talkin about
> destination addresses).

You're totally right, this is misleading. I will just drop this
definition and its use, see below.

> Just to clarify we can have here two different types/length of mac
> addresses being used, whereas the extended address is always present.
> We have the monitor interface set to an invalid extended address
> 0x0...0 (talking about source address) which is a reserved EUI64 (what
> long/extended address is) address, 0xffff...ffff is also being
> reserved. Monitors get their address from the socket interface.
> 
> If there is a parent, an extended address is always present and known.
> A short address can be set, but is not required as a node to have.
> Sure if a node has a short address, you want to use a short address
> because it saves payload.
> Also remember when an address is unique in the network, an extended
> address (LONG) is always being unique, a short address is unique in
> combination of pan id + short address.

Absolutely.

> If you save some neighbors you want to store the extended and if
> present panid/shortaddress.

The code above was misleading, I will clarify it to only accept NL
association commands with an extended address. In fact the coord
structure is created in the nl802154 layer and it already only accepts
extended addresses (we don't expect the short address through the nl
command) so to answer your request: yes, the extended address will
always be there because we must know it.

Regarding the possibility to provide a short address, as we no longer
keep details about the surrounding devices inside the kernel (we only
keep the associated devices, either the parent or the children) keeping
this information would be useless. I don't see a need for it. The
NL interface can evolve later without breaking the compatibility if we
ever want to provide a short address as well and make something with it
(actually even today one could send the short address, it would simply
be ingored).

One thing however regarding the fact that we might want to store both a
short *and* an extended address in some cases: I created a "PAN device"
structure which allows this (because otherwise we had a union) as we
need to do it when we are parent as we are in charge of allocating the
short addresses:

+/**
+ * struct ieee802154_pan_device - PAN device information
+ * @pan_id: the PAN ID of this device
+ * @mode: the preferred mode to reach the device
+ * @short_addr: the short address of this device
+ * @extended_addr: the extended address of this device
+ * @node: the list node
+ */
+struct ieee802154_pan_device {
+       __le16 pan_id;
+       u8 mode;
+       __le16 short_addr;
+       __le64 extended_addr;
+       struct list_head node;
+};

> Or I do not understand something here?

No no, I think we are fully aligned :-)

> btw: as you probably noticed, the netdev interface dev_addr is an
> extended address (because it's always present). Now there comes the
> ugly part, netdevs cannot deal with other dev_addrs with different
> length, that's why it's stored in the wpan specific dev structure and
> things don't get easy and solutions need to be found how to make it
> working... get prepared to get crazy...

Yeah but I believe once we have proper PAN IDs/short address vs
extended address mappings we could have the translation internally at
least. I haven't investigated this for now.

Thanks,
Miquèl

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH wpan-next 07/11] mac802154: Handle association requests from peers
  2023-08-21  8:52     ` Miquel Raynal
@ 2023-09-01 15:45       ` Miquel Raynal
  2023-09-01 16:25         ` Miquel Raynal
  0 siblings, 1 reply; 24+ messages in thread
From: Miquel Raynal @ 2023-09-01 15:45 UTC (permalink / raw)
  To: Alexander Aring
  Cc: Alexander Aring, Stefan Schmidt, linux-wpan, David S. Miller,
	Jakub Kicinski, Paolo Abeni, Eric Dumazet, netdev, David Girault,
	Romuald Despres, Frederic Blain, Nicolas Schodet,
	Guilhem Imberton, Thomas Petazzoni

Hi Alexander,

> > > --- a/net/ieee802154/pan.c
> > > +++ b/net/ieee802154/pan.c
> > > @@ -66,3 +66,30 @@ cfg802154_device_is_child(struct wpan_dev *wpan_dev,
> > >         return NULL;
> > >  }
> > >  EXPORT_SYMBOL_GPL(cfg802154_device_is_child);
> > > +
> > > +__le16 cfg802154_get_free_short_addr(struct wpan_dev *wpan_dev)
> > > +{
> > > +       struct ieee802154_pan_device *child;
> > > +       __le16 addr;
> > > +
> > > +       lockdep_assert_held(&wpan_dev->association_lock);
> > > +
> > > +       do {
> > > +               get_random_bytes(&addr, 2);    
> > 
> > This is combined with the max associations setting? I am not sure if
> > this is the best way to get free values from a u16 value where we have
> > some data structure of "given" addresses to a node. I recently was
> > looking into idr/xarray data structure... maybe we can use something
> > from there.  
> 
> I actually thought about using an increasing index, but the pseudo
> random generator seemed appropriate because of its "unpredictability",
> but there is not real use for that (besides maybe testing purposes). I
> can definitely switch to another solution.

I looked into this deeper. I didn't felt like idr would be so much
useful, but I started converting the code to use ida instead (so the
simplest approach, with no associated pointer). There are actually two
use cases which clearly match better the random address mechanism.

a/ One can freely decide the short address of the coordinator (it is
freely selectable by the user) but ida has no mechanism to handle this
with an API which would prevent such "number to be used".

In practice, this could be workarounded "easily", even though the
implementation would be dirty IMHO: getting an IDA, if it matches ours,
just try again without freeing it. TBH I don't like much this idea.

b/ In case we ever want to support master handover, the ida solution
does not work well...

For now I've kept the current approach (actually adding a missing
check), but if you know how to solve that I can either update the
implementation or make a followup patch, especially since the current
approach is not bounded (in the theoretical case where we have 65k
devices in the same PAN).

I believe the allocation strategies are not set in stone anyway and can
easily evolve.

Thanks,
Miquèl

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH wpan-next 07/11] mac802154: Handle association requests from peers
  2023-09-01 15:45       ` Miquel Raynal
@ 2023-09-01 16:25         ` Miquel Raynal
  0 siblings, 0 replies; 24+ messages in thread
From: Miquel Raynal @ 2023-09-01 16:25 UTC (permalink / raw)
  To: Alexander Aring
  Cc: Alexander Aring, Stefan Schmidt, linux-wpan, David S. Miller,
	Jakub Kicinski, Paolo Abeni, Eric Dumazet, netdev, David Girault,
	Romuald Despres, Frederic Blain, Nicolas Schodet,
	Guilhem Imberton, Thomas Petazzoni


miquel.raynal@bootlin.com wrote on Fri, 1 Sep 2023 17:45:37 +0200:

> Hi Alexander,
> 
> > > > --- a/net/ieee802154/pan.c
> > > > +++ b/net/ieee802154/pan.c
> > > > @@ -66,3 +66,30 @@ cfg802154_device_is_child(struct wpan_dev *wpan_dev,
> > > >         return NULL;
> > > >  }
> > > >  EXPORT_SYMBOL_GPL(cfg802154_device_is_child);
> > > > +
> > > > +__le16 cfg802154_get_free_short_addr(struct wpan_dev *wpan_dev)
> > > > +{
> > > > +       struct ieee802154_pan_device *child;
> > > > +       __le16 addr;
> > > > +
> > > > +       lockdep_assert_held(&wpan_dev->association_lock);
> > > > +
> > > > +       do {
> > > > +               get_random_bytes(&addr, 2);      
> > > 
> > > This is combined with the max associations setting? I am not sure if
> > > this is the best way to get free values from a u16 value where we have
> > > some data structure of "given" addresses to a node. I recently was
> > > looking into idr/xarray data structure... maybe we can use something
> > > from there.    
> > 
> > I actually thought about using an increasing index, but the pseudo
> > random generator seemed appropriate because of its "unpredictability",
> > but there is not real use for that (besides maybe testing purposes). I
> > can definitely switch to another solution.  
> 
> I looked into this deeper. I didn't felt like idr would be so much
> useful, but I started converting the code to use ida instead (so the
> simplest approach, with no associated pointer). There are actually two
> use cases which clearly match better the random address mechanism.
> 
> a/ One can freely decide the short address of the coordinator (it is
> freely selectable by the user) but ida has no mechanism to handle this
> with an API which would prevent such "number to be used".
> 
> In practice, this could be workarounded "easily", even though the
> implementation would be dirty IMHO: getting an IDA, if it matches ours,
> just try again without freeing it. TBH I don't like much this idea.
> 
> b/ In case we ever want to support master handover, the ida solution
> does not work well...

c/ Technically speaking, leaf devices can connect to a PAN coordinator
which is not the top-level coordinator in case it is out of reach.
So the coordinator receiving the association request needs to allocate
a random address for this leaf device, without knowing all the
addresses the top-level coordinator already allocated. In case the
devices move or a coordinator detects two different devices within the
same PAN with the same short addres, it must trigger a realignment
procedure (not implemented yet). Therefore, following a linear scheme
when allocating children short addresses sounds like an endless source
of conflicts and realignments, whereas random addressing would prevent
most of these situations on regular sized networks?

> For now I've kept the current approach (actually adding a missing
> check), but if you know how to solve that I can either update the
> implementation or make a followup patch, especially since the current
> approach is not bounded (in the theoretical case where we have 65k
> devices in the same PAN).
> 
> I believe the allocation strategies are not set in stone anyway and can
> easily evolve.
> 
> Thanks,
> Miquèl

^ permalink raw reply	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2023-09-01 16:25 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-06-01 15:48 [PATCH wpan-next 00/11] ieee802154: Associations between devices Miquel Raynal
2023-06-01 15:48 ` [PATCH wpan-next 01/11] ieee802154: Let PAN IDs be reset Miquel Raynal
2023-06-01 15:48 ` [PATCH wpan-next 02/11] ieee802154: Internal PAN management Miquel Raynal
2023-06-01 15:48 ` [PATCH wpan-next 03/11] ieee802154: Add support for user association requests Miquel Raynal
2023-06-01 15:48 ` [PATCH wpan-next 04/11] mac802154: Handle associating Miquel Raynal
2023-06-02 15:54   ` Simon Horman
2023-08-18 14:17     ` Miquel Raynal
2023-06-03 10:09   ` Alexander Aring
2023-07-04 11:34     ` Alexander Aring
2023-09-01 15:01     ` Miquel Raynal
2023-09-01 15:31     ` Miquel Raynal
2023-06-01 15:48 ` [PATCH wpan-next 05/11] ieee802154: Add support for user disassociation requests Miquel Raynal
2023-06-01 15:48 ` [PATCH wpan-next 06/11] mac802154: Handle disassociations Miquel Raynal
2023-06-03 11:30   ` Alexander Aring
2023-08-21  9:02     ` Miquel Raynal
2023-06-01 15:48 ` [PATCH wpan-next 07/11] mac802154: Handle association requests from peers Miquel Raynal
2023-06-03 11:28   ` Alexander Aring
2023-08-21  8:52     ` Miquel Raynal
2023-09-01 15:45       ` Miquel Raynal
2023-09-01 16:25         ` Miquel Raynal
2023-06-01 15:48 ` [PATCH wpan-next 08/11] ieee802154: Add support for limiting the number of associated devices Miquel Raynal
2023-06-01 15:48 ` [PATCH wpan-next 09/11] mac802154: Follow " Miquel Raynal
2023-06-01 15:48 ` [PATCH wpan-next 10/11] mac802154: Handle disassociation notifications from peers Miquel Raynal
2023-06-01 15:48 ` [PATCH wpan-next 11/11] ieee802154: Give the user the association list Miquel Raynal

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).