]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
mac802154: Handle disassociation notifications from peers
authorMiquel Raynal <miquel.raynal@bootlin.com>
Wed, 27 Sep 2023 18:12:13 +0000 (20:12 +0200)
committerMiquel Raynal <miquel.raynal@bootlin.com>
Mon, 20 Nov 2023 10:43:33 +0000 (11:43 +0100)
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
net/mac802154/ieee802154_i.h
net/mac802154/rx.c
net/mac802154/scan.c

index 432bfa87249ee95abd90f990d2c90b367240c7c3..08dd521a51a5c52b58c251a7b2df165ee340d00c 100644 (file)
@@ -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);
 
index 96040b63a4fc55e014d2882dc5893bb2e9a8b736..0024341ef9c507b8656c2aef011ca787d887a7d1 100644 (file)
@@ -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;
        }
index 81d2c2bb1f09a9213143e81202942e734112464d..7597072aed57b3e40f9cf646a28527df88e5052b 100644 (file)
@@ -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;
+}