summaryrefslogtreecommitdiff
path: root/net/mac802154
diff options
context:
space:
mode:
authorMiquel Raynal <miquel.raynal@bootlin.com>2023-09-27 20:12:13 +0200
committerMiquel Raynal <miquel.raynal@bootlin.com>2023-11-20 11:43:33 +0100
commit1e2a45f1f854ce63c114b42298ea686dce9ae4fd (patch)
tree5acc58a704ba9487ed022a5350aee5e3524e7ccd /net/mac802154
parent80f8bf9a2a7f603662e08f7663643a58087a2cd4 (diff)
mac802154: Handle disassociation notifications from peers
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> Acked-by: Stefan Schmidt <stefan@datenfreihafen.org> Acked-by: Alexander Aring <aahringo@redhat.com> Link: https://lore.kernel.org/linux-wpan/20230927181214.129346-11-miquel.raynal@bootlin.com
Diffstat (limited to 'net/mac802154')
-rw-r--r--net/mac802154/ieee802154_i.h2
-rw-r--r--net/mac802154/rx.c8
-rw-r--r--net/mac802154/scan.c55
3 files changed, 65 insertions, 0 deletions
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 81d2c2bb1f09..7597072aed57 100644
--- a/net/mac802154/scan.c
+++ b/net/mac802154/scan.c
@@ -852,3 +852,58 @@ unlock:
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;
+
+ if (dest->pan_id != wpan_dev->pan_id)
+ 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--;
+ }
+
+ mutex_unlock(&wpan_dev->association_lock);
+
+ return 0;
+}