Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'ieee802154-for-net-next-2023-12-20' of gitolite.kernel.org:pub/scm/linux/kernel/git/wpan/wpan-next

Miquel Raynal says:

====================
This pull request mainly brings support for dynamic associations in
the WPAN world. Thanks to the recent improvements it was possible to
discover nearby devices, it is now also possible to associate with them
to form a sub-network using a specific PAN ID. The support includes
several functions, such as:

* 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

There are as well two patches from Uwe turning remove callbacks into
void functions.

* tag 'ieee802154-for-net-next-2023-12-20' of gitolite.kernel.org:pub/scm/linux/kernel/git/wpan/wpan-next:
mac802154: Avoid new associations while disassociating
ieee802154: Avoid confusing changes after associating
mac802154: Only allow PAN controllers to process association requests
mac802154: Use the PAN coordinator parameter when stamping packets
mac80254: Provide real PAN coordinator info in beacons
ieee802154: Give the user the association list
mac802154: Handle disassociation notifications from peers
mac802154: Follow the number of associated devices
ieee802154: Add support for limiting the number of associated devices
mac802154: Handle association requests from peers
mac802154: Handle disassociations
ieee802154: Add support for user disassociation requests
mac802154: Handle associating
ieee802154: Add support for user association requests
ieee802154: Internal PAN management
ieee802154: Let PAN IDs be reset
ieee802154: hwsim: Convert to platform remove callback returning void
ieee802154: fakelb: Convert to platform remove callback returning void
====================

Link: https://lore.kernel.org/r/20231220095556.4d9cef91@xps-13
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+1227 -37
+2 -3
drivers/net/ieee802154/fakelb.c
··· 221 221 return err; 222 222 } 223 223 224 - static int fakelb_remove(struct platform_device *pdev) 224 + static void fakelb_remove(struct platform_device *pdev) 225 225 { 226 226 struct fakelb_phy *phy, *tmp; 227 227 ··· 229 229 list_for_each_entry_safe(phy, tmp, &fakelb_phys, list) 230 230 fakelb_del(phy); 231 231 mutex_unlock(&fakelb_phys_lock); 232 - return 0; 233 232 } 234 233 235 234 static struct platform_device *ieee802154fake_dev; 236 235 237 236 static struct platform_driver ieee802154fake_driver = { 238 237 .probe = fakelb_probe, 239 - .remove = fakelb_remove, 238 + .remove_new = fakelb_remove, 240 239 .driver = { 241 240 .name = "ieee802154fakelb", 242 241 },
+2 -4
drivers/net/ieee802154/mac802154_hwsim.c
··· 1035 1035 return err; 1036 1036 } 1037 1037 1038 - static int hwsim_remove(struct platform_device *pdev) 1038 + static void hwsim_remove(struct platform_device *pdev) 1039 1039 { 1040 1040 struct hwsim_phy *phy, *tmp; 1041 1041 ··· 1043 1043 list_for_each_entry_safe(phy, tmp, &hwsim_phys, list) 1044 1044 hwsim_del(phy); 1045 1045 mutex_unlock(&hwsim_phys_lock); 1046 - 1047 - return 0; 1048 1046 } 1049 1047 1050 1048 static struct platform_driver mac802154hwsim_driver = { 1051 1049 .probe = hwsim_probe, 1052 - .remove = hwsim_remove, 1050 + .remove_new = hwsim_remove, 1053 1051 .driver = { 1054 1052 .name = "mac802154_hwsim", 1055 1053 },
+72
include/net/cfg802154.h
··· 20 20 struct wpan_phy_cca; 21 21 struct cfg802154_scan_request; 22 22 struct cfg802154_beacon_request; 23 + struct ieee802154_addr; 23 24 24 25 #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL 25 26 struct ieee802154_llsec_device_key; ··· 78 77 struct cfg802154_beacon_request *request); 79 78 int (*stop_beacons)(struct wpan_phy *wpan_phy, 80 79 struct wpan_dev *wpan_dev); 80 + int (*associate)(struct wpan_phy *wpan_phy, 81 + struct wpan_dev *wpan_dev, 82 + struct ieee802154_addr *coord); 83 + int (*disassociate)(struct wpan_phy *wpan_phy, 84 + struct wpan_dev *wpan_dev, 85 + struct ieee802154_addr *target); 81 86 #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL 82 87 void (*get_llsec_table)(struct wpan_phy *wpan_phy, 83 88 struct wpan_dev *wpan_dev, ··· 311 304 }; 312 305 313 306 /** 307 + * struct ieee802154_pan_device - PAN device information 308 + * @pan_id: the PAN ID of this device 309 + * @mode: the preferred mode to reach the device 310 + * @short_addr: the short address of this device 311 + * @extended_addr: the extended address of this device 312 + * @node: the list node 313 + */ 314 + struct ieee802154_pan_device { 315 + __le16 pan_id; 316 + u8 mode; 317 + __le16 short_addr; 318 + __le64 extended_addr; 319 + struct list_head node; 320 + }; 321 + 322 + /** 314 323 * struct cfg802154_scan_request - Scan request 315 324 * 316 325 * @type: type of scan to be performed ··· 501 478 502 479 /* fallback for acknowledgment bit setting */ 503 480 bool ackreq; 481 + 482 + /* Associations */ 483 + struct mutex association_lock; 484 + struct ieee802154_pan_device *parent; 485 + struct list_head children; 486 + unsigned int max_associations; 487 + unsigned int nchildren; 504 488 }; 505 489 506 490 #define to_phy(_dev) container_of(_dev, struct wpan_phy, dev) ··· 558 528 559 529 void ieee802154_configure_durations(struct wpan_phy *phy, 560 530 unsigned int page, unsigned int channel); 531 + 532 + /** 533 + * cfg802154_device_is_associated - Checks whether we are associated to any device 534 + * @wpan_dev: the wpan device 535 + * @return: true if we are associated 536 + */ 537 + bool cfg802154_device_is_associated(struct wpan_dev *wpan_dev); 538 + 539 + /** 540 + * cfg802154_device_is_parent - Checks if a device is our coordinator 541 + * @wpan_dev: the wpan device 542 + * @target: the expected parent 543 + * @return: true if @target is our coordinator 544 + */ 545 + bool cfg802154_device_is_parent(struct wpan_dev *wpan_dev, 546 + struct ieee802154_addr *target); 547 + 548 + /** 549 + * cfg802154_device_is_child - Checks whether a device is associated to us 550 + * @wpan_dev: the wpan device 551 + * @target: the expected child 552 + * @return: the PAN device 553 + */ 554 + struct ieee802154_pan_device * 555 + cfg802154_device_is_child(struct wpan_dev *wpan_dev, 556 + struct ieee802154_addr *target); 557 + 558 + /** 559 + * cfg802154_set_max_associations - Limit the number of future associations 560 + * @wpan_dev: the wpan device 561 + * @max: the maximum number of devices we accept to associate 562 + * @return: the old maximum value 563 + */ 564 + unsigned int cfg802154_set_max_associations(struct wpan_dev *wpan_dev, 565 + unsigned int max); 566 + 567 + /** 568 + * cfg802154_get_free_short_addr - Get a free address among the known devices 569 + * @wpan_dev: the wpan device 570 + * @return: a random short address expectedly unused on our PAN 571 + */ 572 + __le16 cfg802154_get_free_short_addr(struct wpan_dev *wpan_dev); 561 573 562 574 #endif /* __NET_CFG802154_H */
+60
include/net/ieee802154_netdev.h
··· 125 125 #endif 126 126 }; 127 127 128 + struct ieee802154_assoc_req_pl { 129 + #if defined(__LITTLE_ENDIAN_BITFIELD) 130 + u8 reserved1:1, 131 + device_type:1, 132 + power_source:1, 133 + rx_on_when_idle:1, 134 + assoc_type:1, 135 + reserved2:1, 136 + security_cap:1, 137 + alloc_addr:1; 138 + #elif defined(__BIG_ENDIAN_BITFIELD) 139 + u8 alloc_addr:1, 140 + security_cap:1, 141 + reserved2:1, 142 + assoc_type:1, 143 + rx_on_when_idle:1, 144 + power_source:1, 145 + device_type:1, 146 + reserved1:1; 147 + #else 148 + #error "Please fix <asm/byteorder.h>" 149 + #endif 150 + } __packed; 151 + 152 + struct ieee802154_assoc_resp_pl { 153 + __le16 short_addr; 154 + u8 status; 155 + } __packed; 156 + 128 157 enum ieee802154_frame_version { 129 158 IEEE802154_2003_STD, 130 159 IEEE802154_2006_STD, ··· 167 138 IEEE802154_RESERVED, 168 139 IEEE802154_SHORT_ADDRESSING, 169 140 IEEE802154_EXTENDED_ADDRESSING, 141 + }; 142 + 143 + enum ieee802154_association_status { 144 + IEEE802154_ASSOCIATION_SUCCESSFUL = 0x00, 145 + IEEE802154_PAN_AT_CAPACITY = 0x01, 146 + IEEE802154_PAN_ACCESS_DENIED = 0x02, 147 + IEEE802154_HOPPING_SEQUENCE_OFFSET_DUP = 0x03, 148 + IEEE802154_FAST_ASSOCIATION_SUCCESSFUL = 0x80, 149 + }; 150 + 151 + enum ieee802154_disassociation_reason { 152 + IEEE802154_COORD_WISHES_DEVICE_TO_LEAVE = 0x1, 153 + IEEE802154_DEVICE_WISHES_TO_LEAVE = 0x2, 170 154 }; 171 155 172 156 struct ieee802154_hdr { ··· 203 161 struct ieee802154_beacon_req_frame { 204 162 struct ieee802154_hdr mhr; 205 163 struct ieee802154_mac_cmd_pl mac_pl; 164 + }; 165 + 166 + struct ieee802154_association_req_frame { 167 + struct ieee802154_hdr mhr; 168 + struct ieee802154_mac_cmd_pl mac_pl; 169 + struct ieee802154_assoc_req_pl assoc_req_pl; 170 + }; 171 + 172 + struct ieee802154_association_resp_frame { 173 + struct ieee802154_hdr mhr; 174 + struct ieee802154_mac_cmd_pl mac_pl; 175 + struct ieee802154_assoc_resp_pl assoc_resp_pl; 176 + }; 177 + 178 + struct ieee802154_disassociation_notif_frame { 179 + struct ieee802154_hdr mhr; 180 + struct ieee802154_mac_cmd_pl mac_pl; 181 + u8 disassoc_pl; 206 182 }; 207 183 208 184 /* pushes hdr onto the skb. fields of hdr->fc that can be calculated from
+20 -2
include/net/nl802154.h
··· 78 78 NL802154_CMD_SCAN_DONE, 79 79 NL802154_CMD_SEND_BEACONS, 80 80 NL802154_CMD_STOP_BEACONS, 81 + NL802154_CMD_ASSOCIATE, 82 + NL802154_CMD_DISASSOCIATE, 83 + NL802154_CMD_SET_MAX_ASSOCIATIONS, 84 + NL802154_CMD_LIST_ASSOCIATIONS, 81 85 82 86 /* add new commands above here */ 83 87 ··· 151 147 NL802154_ATTR_SCAN_DURATION, 152 148 NL802154_ATTR_SCAN_DONE_REASON, 153 149 NL802154_ATTR_BEACON_INTERVAL, 150 + NL802154_ATTR_MAX_ASSOCIATIONS, 151 + NL802154_ATTR_PEER, 154 152 155 153 /* add attributes here, update the policy in nl802154.c */ 156 154 ··· 391 385 NL802154_SUPPORTED_BOOL_MAX = __NL802154_SUPPORTED_BOOL_AFTER_LAST - 1 392 386 }; 393 387 394 - #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL 395 - 396 388 enum nl802154_dev_addr_modes { 397 389 NL802154_DEV_ADDR_NONE, 398 390 __NL802154_DEV_ADDR_INVALID, ··· 410 406 NL802154_DEV_ADDR_ATTR_SHORT, 411 407 NL802154_DEV_ADDR_ATTR_EXTENDED, 412 408 NL802154_DEV_ADDR_ATTR_PAD, 409 + NL802154_DEV_ADDR_ATTR_PEER_TYPE, 413 410 414 411 /* keep last */ 415 412 __NL802154_DEV_ADDR_ATTR_AFTER_LAST, 416 413 NL802154_DEV_ADDR_ATTR_MAX = __NL802154_DEV_ADDR_ATTR_AFTER_LAST - 1 417 414 }; 415 + 416 + enum nl802154_peer_type { 417 + NL802154_PEER_TYPE_UNSPEC, 418 + 419 + NL802154_PEER_TYPE_PARENT, 420 + NL802154_PEER_TYPE_CHILD, 421 + 422 + /* keep last */ 423 + __NL802154_PEER_TYPE_AFTER_LAST, 424 + NL802154_PEER_TYPE_MAX = __NL802154_PEER_TYPE_AFTER_LAST - 1 425 + }; 426 + 427 + #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL 418 428 419 429 enum nl802154_key_id_modes { 420 430 NL802154_KEY_ID_MODE_IMPLICIT,
+1 -1
net/ieee802154/Makefile
··· 4 4 obj-y += 6lowpan/ 5 5 6 6 ieee802154-y := netlink.o nl-mac.o nl-phy.o nl_policy.o core.o \ 7 - header_ops.o sysfs.o nl802154.o trace.o 7 + header_ops.o sysfs.o nl802154.o trace.o pan.o 8 8 ieee802154_socket-y := socket.o 9 9 10 10 CFLAGS_trace.o := -I$(src)
+24
net/ieee802154/core.c
··· 198 198 } 199 199 EXPORT_SYMBOL(wpan_phy_free); 200 200 201 + static void cfg802154_free_peer_structures(struct wpan_dev *wpan_dev) 202 + { 203 + struct ieee802154_pan_device *child, *tmp; 204 + 205 + mutex_lock(&wpan_dev->association_lock); 206 + 207 + kfree(wpan_dev->parent); 208 + wpan_dev->parent = NULL; 209 + 210 + list_for_each_entry_safe(child, tmp, &wpan_dev->children, node) { 211 + list_del(&child->node); 212 + kfree(child); 213 + } 214 + 215 + wpan_dev->nchildren = 0; 216 + 217 + mutex_unlock(&wpan_dev->association_lock); 218 + } 219 + 201 220 int cfg802154_switch_netns(struct cfg802154_registered_device *rdev, 202 221 struct net *net) 203 222 { ··· 295 276 wpan_dev->identifier = ++rdev->wpan_dev_id; 296 277 list_add_rcu(&wpan_dev->list, &rdev->wpan_dev_list); 297 278 rdev->devlist_generation++; 279 + mutex_init(&wpan_dev->association_lock); 280 + INIT_LIST_HEAD(&wpan_dev->children); 281 + wpan_dev->max_associations = SZ_16K; 298 282 299 283 wpan_dev->netdev = dev; 300 284 break; ··· 313 291 rdev->opencount++; 314 292 break; 315 293 case NETDEV_UNREGISTER: 294 + cfg802154_free_peer_structures(wpan_dev); 295 + 316 296 /* It is possible to get NETDEV_UNREGISTER 317 297 * multiple times. To detect that, check 318 298 * that the interface is still on the list
+228 -21
net/ieee802154/nl802154.c
··· 234 234 NL802154_SCAN_DONE_REASON_ABORTED), 235 235 [NL802154_ATTR_BEACON_INTERVAL] = 236 236 NLA_POLICY_MAX(NLA_U8, IEEE802154_ACTIVE_SCAN_DURATION), 237 + [NL802154_ATTR_MAX_ASSOCIATIONS] = { .type = NLA_U32 }, 238 + [NL802154_ATTR_PEER] = { .type = NLA_NESTED }, 237 239 238 240 #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL 239 241 [NL802154_ATTR_SEC_ENABLED] = { .type = NLA_U8, }, ··· 250 248 #endif /* CONFIG_IEEE802154_NL802154_EXPERIMENTAL */ 251 249 }; 252 250 253 - #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL 254 251 static int 255 252 nl802154_prepare_wpan_dev_dump(struct sk_buff *skb, 256 253 struct netlink_callback *cb, ··· 308 307 { 309 308 rtnl_unlock(); 310 309 } 311 - #endif /* CONFIG_IEEE802154_NL802154_EXPERIMENTAL */ 312 310 313 311 /* message building helper */ 314 312 static inline void *nl802154hdr_put(struct sk_buff *skb, u32 portid, u32 seq, ··· 1087 1087 1088 1088 pan_id = nla_get_le16(info->attrs[NL802154_ATTR_PAN_ID]); 1089 1089 1090 - /* TODO 1091 - * I am not sure about to check here on broadcast pan_id. 1092 - * Broadcast is a valid setting, comment from 802.15.4: 1093 - * If this value is 0xffff, the device is not associated. 1094 - * 1095 - * This could useful to simple deassociate an device. 1090 + /* Only allow changing the PAN ID when the device has no more 1091 + * associations ongoing to avoid confusing peers. 1096 1092 */ 1097 - if (pan_id == cpu_to_le16(IEEE802154_PAN_ID_BROADCAST)) 1093 + if (cfg802154_device_is_associated(wpan_dev)) { 1094 + NL_SET_ERR_MSG(info->extack, 1095 + "Existing associations, changing PAN ID forbidden"); 1098 1096 return -EINVAL; 1097 + } 1099 1098 1100 1099 return rdev_set_pan_id(rdev, wpan_dev, pan_id); 1101 1100 } ··· 1122 1123 1123 1124 short_addr = nla_get_le16(info->attrs[NL802154_ATTR_SHORT_ADDR]); 1124 1125 1125 - /* TODO 1126 - * I am not sure about to check here on broadcast short_addr. 1127 - * Broadcast is a valid setting, comment from 802.15.4: 1128 - * A value of 0xfffe indicates that the device has 1129 - * associated but has not been allocated an address. A 1130 - * value of 0xffff indicates that the device does not 1131 - * have a short address. 1132 - * 1133 - * I think we should allow to set these settings but 1134 - * don't allow to allow socket communication with it. 1126 + /* The short address only has a meaning when part of a PAN, after a 1127 + * proper association procedure. However, we want to still offer the 1128 + * possibility to create static networks so changing the short address 1129 + * is only allowed when not already associated to other devices with 1130 + * the official handshake. 1135 1131 */ 1136 - if (short_addr == cpu_to_le16(IEEE802154_ADDR_SHORT_UNSPEC) || 1137 - short_addr == cpu_to_le16(IEEE802154_ADDR_SHORT_BROADCAST)) 1132 + if (cfg802154_device_is_associated(wpan_dev)) { 1133 + NL_SET_ERR_MSG(info->extack, 1134 + "Existing associations, changing short address forbidden"); 1138 1135 return -EINVAL; 1136 + } 1139 1137 1140 1138 return rdev_set_short_addr(rdev, wpan_dev, short_addr); 1141 1139 } ··· 1632 1636 1633 1637 /* Resources are released in the notification helper above */ 1634 1638 return rdev_stop_beacons(rdev, wpan_dev); 1639 + } 1640 + 1641 + static int nl802154_associate(struct sk_buff *skb, struct genl_info *info) 1642 + { 1643 + struct cfg802154_registered_device *rdev = info->user_ptr[0]; 1644 + struct net_device *dev = info->user_ptr[1]; 1645 + struct wpan_dev *wpan_dev; 1646 + struct wpan_phy *wpan_phy; 1647 + struct ieee802154_addr coord; 1648 + int err; 1649 + 1650 + wpan_dev = dev->ieee802154_ptr; 1651 + wpan_phy = &rdev->wpan_phy; 1652 + 1653 + if (wpan_phy->flags & WPAN_PHY_FLAG_DATAGRAMS_ONLY) { 1654 + NL_SET_ERR_MSG(info->extack, "PHY only supports datagrams"); 1655 + return -EOPNOTSUPP; 1656 + } 1657 + 1658 + if (!info->attrs[NL802154_ATTR_PAN_ID] || 1659 + !info->attrs[NL802154_ATTR_EXTENDED_ADDR]) 1660 + return -EINVAL; 1661 + 1662 + coord.pan_id = nla_get_le16(info->attrs[NL802154_ATTR_PAN_ID]); 1663 + coord.mode = IEEE802154_ADDR_LONG; 1664 + coord.extended_addr = nla_get_le64(info->attrs[NL802154_ATTR_EXTENDED_ADDR]); 1665 + 1666 + mutex_lock(&wpan_dev->association_lock); 1667 + err = rdev_associate(rdev, wpan_dev, &coord); 1668 + mutex_unlock(&wpan_dev->association_lock); 1669 + if (err) 1670 + pr_err("Association with PAN ID 0x%x failed (%d)\n", 1671 + le16_to_cpu(coord.pan_id), err); 1672 + 1673 + return err; 1674 + } 1675 + 1676 + static int nl802154_disassociate(struct sk_buff *skb, struct genl_info *info) 1677 + { 1678 + struct cfg802154_registered_device *rdev = info->user_ptr[0]; 1679 + struct net_device *dev = info->user_ptr[1]; 1680 + struct wpan_dev *wpan_dev = dev->ieee802154_ptr; 1681 + struct wpan_phy *wpan_phy = &rdev->wpan_phy; 1682 + struct ieee802154_addr target; 1683 + 1684 + if (wpan_phy->flags & WPAN_PHY_FLAG_DATAGRAMS_ONLY) { 1685 + NL_SET_ERR_MSG(info->extack, "PHY only supports datagrams"); 1686 + return -EOPNOTSUPP; 1687 + } 1688 + 1689 + target.pan_id = wpan_dev->pan_id; 1690 + 1691 + if (info->attrs[NL802154_ATTR_EXTENDED_ADDR]) { 1692 + target.mode = IEEE802154_ADDR_LONG; 1693 + target.extended_addr = nla_get_le64(info->attrs[NL802154_ATTR_EXTENDED_ADDR]); 1694 + } else if (info->attrs[NL802154_ATTR_SHORT_ADDR]) { 1695 + target.mode = IEEE802154_ADDR_SHORT; 1696 + target.short_addr = nla_get_le16(info->attrs[NL802154_ATTR_SHORT_ADDR]); 1697 + } else { 1698 + NL_SET_ERR_MSG(info->extack, "Device address is missing"); 1699 + return -EINVAL; 1700 + } 1701 + 1702 + mutex_lock(&wpan_dev->association_lock); 1703 + rdev_disassociate(rdev, wpan_dev, &target); 1704 + mutex_unlock(&wpan_dev->association_lock); 1705 + 1706 + return 0; 1707 + } 1708 + 1709 + static int nl802154_set_max_associations(struct sk_buff *skb, struct genl_info *info) 1710 + { 1711 + struct net_device *dev = info->user_ptr[1]; 1712 + struct wpan_dev *wpan_dev = dev->ieee802154_ptr; 1713 + unsigned int max_assoc; 1714 + 1715 + if (!info->attrs[NL802154_ATTR_MAX_ASSOCIATIONS]) { 1716 + NL_SET_ERR_MSG(info->extack, "No maximum number of association given"); 1717 + return -EINVAL; 1718 + } 1719 + 1720 + max_assoc = nla_get_u32(info->attrs[NL802154_ATTR_MAX_ASSOCIATIONS]); 1721 + 1722 + mutex_lock(&wpan_dev->association_lock); 1723 + cfg802154_set_max_associations(wpan_dev, max_assoc); 1724 + mutex_unlock(&wpan_dev->association_lock); 1725 + 1726 + return 0; 1727 + } 1728 + 1729 + static int nl802154_send_peer_info(struct sk_buff *msg, 1730 + struct netlink_callback *cb, 1731 + u32 seq, int flags, 1732 + struct cfg802154_registered_device *rdev, 1733 + struct wpan_dev *wpan_dev, 1734 + struct ieee802154_pan_device *peer, 1735 + enum nl802154_peer_type type) 1736 + { 1737 + struct nlattr *nla; 1738 + void *hdr; 1739 + 1740 + ASSERT_RTNL(); 1741 + 1742 + hdr = nl802154hdr_put(msg, NETLINK_CB(cb->skb).portid, seq, flags, 1743 + NL802154_CMD_LIST_ASSOCIATIONS); 1744 + if (!hdr) 1745 + return -ENOBUFS; 1746 + 1747 + genl_dump_check_consistent(cb, hdr); 1748 + 1749 + nla = nla_nest_start_noflag(msg, NL802154_ATTR_PEER); 1750 + if (!nla) 1751 + goto nla_put_failure; 1752 + 1753 + if (nla_put_u8(msg, NL802154_DEV_ADDR_ATTR_PEER_TYPE, type)) 1754 + goto nla_put_failure; 1755 + 1756 + if (nla_put_u8(msg, NL802154_DEV_ADDR_ATTR_MODE, peer->mode)) 1757 + goto nla_put_failure; 1758 + 1759 + if (nla_put(msg, NL802154_DEV_ADDR_ATTR_SHORT, 1760 + IEEE802154_SHORT_ADDR_LEN, &peer->short_addr)) 1761 + goto nla_put_failure; 1762 + 1763 + if (nla_put(msg, NL802154_DEV_ADDR_ATTR_EXTENDED, 1764 + IEEE802154_EXTENDED_ADDR_LEN, &peer->extended_addr)) 1765 + goto nla_put_failure; 1766 + 1767 + nla_nest_end(msg, nla); 1768 + 1769 + genlmsg_end(msg, hdr); 1770 + 1771 + return 0; 1772 + 1773 + nla_put_failure: 1774 + genlmsg_cancel(msg, hdr); 1775 + return -EMSGSIZE; 1776 + } 1777 + 1778 + static int nl802154_list_associations(struct sk_buff *skb, 1779 + struct netlink_callback *cb) 1780 + { 1781 + struct cfg802154_registered_device *rdev; 1782 + struct ieee802154_pan_device *child; 1783 + struct wpan_dev *wpan_dev; 1784 + int err; 1785 + 1786 + err = nl802154_prepare_wpan_dev_dump(skb, cb, &rdev, &wpan_dev); 1787 + if (err) 1788 + return err; 1789 + 1790 + mutex_lock(&wpan_dev->association_lock); 1791 + 1792 + if (cb->args[2]) 1793 + goto out; 1794 + 1795 + if (wpan_dev->parent) { 1796 + err = nl802154_send_peer_info(skb, cb, cb->nlh->nlmsg_seq, 1797 + NLM_F_MULTI, rdev, wpan_dev, 1798 + wpan_dev->parent, 1799 + NL802154_PEER_TYPE_PARENT); 1800 + if (err < 0) 1801 + goto out_err; 1802 + } 1803 + 1804 + list_for_each_entry(child, &wpan_dev->children, node) { 1805 + err = nl802154_send_peer_info(skb, cb, cb->nlh->nlmsg_seq, 1806 + NLM_F_MULTI, rdev, wpan_dev, 1807 + child, 1808 + NL802154_PEER_TYPE_CHILD); 1809 + if (err < 0) 1810 + goto out_err; 1811 + } 1812 + 1813 + cb->args[2] = 1; 1814 + out: 1815 + err = skb->len; 1816 + out_err: 1817 + mutex_unlock(&wpan_dev->association_lock); 1818 + 1819 + nl802154_finish_wpan_dev_dump(rdev); 1820 + 1821 + return err; 1635 1822 } 1636 1823 1637 1824 #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL ··· 2937 2758 .internal_flags = NL802154_FLAG_NEED_NETDEV | 2938 2759 NL802154_FLAG_CHECK_NETDEV_UP | 2939 2760 NL802154_FLAG_NEED_RTNL, 2761 + }, 2762 + { 2763 + .cmd = NL802154_CMD_ASSOCIATE, 2764 + .doit = nl802154_associate, 2765 + .flags = GENL_ADMIN_PERM, 2766 + .internal_flags = NL802154_FLAG_NEED_NETDEV | 2767 + NL802154_FLAG_CHECK_NETDEV_UP | 2768 + NL802154_FLAG_NEED_RTNL, 2769 + }, 2770 + { 2771 + .cmd = NL802154_CMD_DISASSOCIATE, 2772 + .doit = nl802154_disassociate, 2773 + .flags = GENL_ADMIN_PERM, 2774 + .internal_flags = NL802154_FLAG_NEED_NETDEV | 2775 + NL802154_FLAG_CHECK_NETDEV_UP | 2776 + NL802154_FLAG_NEED_RTNL, 2777 + }, 2778 + { 2779 + .cmd = NL802154_CMD_SET_MAX_ASSOCIATIONS, 2780 + .doit = nl802154_set_max_associations, 2781 + .flags = GENL_ADMIN_PERM, 2782 + .internal_flags = NL802154_FLAG_NEED_NETDEV | 2783 + NL802154_FLAG_NEED_RTNL, 2784 + }, 2785 + { 2786 + .cmd = NL802154_CMD_LIST_ASSOCIATIONS, 2787 + .dumpit = nl802154_list_associations, 2788 + /* can be retrieved by unprivileged users */ 2940 2789 }, 2941 2790 #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL 2942 2791 {
+109
net/ieee802154/pan.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * IEEE 802.15.4 PAN management 4 + * 5 + * Copyright (C) 2023 Qorvo US, Inc 6 + * Authors: 7 + * - David Girault <david.girault@qorvo.com> 8 + * - Miquel Raynal <miquel.raynal@bootlin.com> 9 + */ 10 + 11 + #include <linux/kernel.h> 12 + #include <net/cfg802154.h> 13 + #include <net/af_ieee802154.h> 14 + 15 + /* Checks whether a device address matches one from the PAN list. 16 + * This helper is meant to be used only during PAN management, when we expect 17 + * extended addresses to be used. 18 + */ 19 + static bool cfg802154_pan_device_is_matching(struct ieee802154_pan_device *pan_dev, 20 + struct ieee802154_addr *ext_dev) 21 + { 22 + if (!pan_dev || !ext_dev) 23 + return false; 24 + 25 + if (ext_dev->mode == IEEE802154_ADDR_SHORT) 26 + return false; 27 + 28 + return pan_dev->extended_addr == ext_dev->extended_addr; 29 + } 30 + 31 + bool cfg802154_device_is_associated(struct wpan_dev *wpan_dev) 32 + { 33 + bool is_assoc; 34 + 35 + mutex_lock(&wpan_dev->association_lock); 36 + is_assoc = !list_empty(&wpan_dev->children) || wpan_dev->parent; 37 + mutex_unlock(&wpan_dev->association_lock); 38 + 39 + return is_assoc; 40 + } 41 + 42 + bool cfg802154_device_is_parent(struct wpan_dev *wpan_dev, 43 + struct ieee802154_addr *target) 44 + { 45 + lockdep_assert_held(&wpan_dev->association_lock); 46 + 47 + return cfg802154_pan_device_is_matching(wpan_dev->parent, target); 48 + } 49 + EXPORT_SYMBOL_GPL(cfg802154_device_is_parent); 50 + 51 + struct ieee802154_pan_device * 52 + cfg802154_device_is_child(struct wpan_dev *wpan_dev, 53 + struct ieee802154_addr *target) 54 + { 55 + struct ieee802154_pan_device *child; 56 + 57 + lockdep_assert_held(&wpan_dev->association_lock); 58 + 59 + list_for_each_entry(child, &wpan_dev->children, node) 60 + if (cfg802154_pan_device_is_matching(child, target)) 61 + return child; 62 + 63 + return NULL; 64 + } 65 + EXPORT_SYMBOL_GPL(cfg802154_device_is_child); 66 + 67 + __le16 cfg802154_get_free_short_addr(struct wpan_dev *wpan_dev) 68 + { 69 + struct ieee802154_pan_device *child; 70 + __le16 addr; 71 + 72 + lockdep_assert_held(&wpan_dev->association_lock); 73 + 74 + do { 75 + get_random_bytes(&addr, 2); 76 + if (addr == cpu_to_le16(IEEE802154_ADDR_SHORT_BROADCAST) || 77 + addr == cpu_to_le16(IEEE802154_ADDR_SHORT_UNSPEC)) 78 + continue; 79 + 80 + if (wpan_dev->short_addr == addr) 81 + continue; 82 + 83 + if (wpan_dev->parent && wpan_dev->parent->short_addr == addr) 84 + continue; 85 + 86 + list_for_each_entry(child, &wpan_dev->children, node) 87 + if (child->short_addr == addr) 88 + continue; 89 + 90 + break; 91 + } while (1); 92 + 93 + return addr; 94 + } 95 + EXPORT_SYMBOL_GPL(cfg802154_get_free_short_addr); 96 + 97 + unsigned int cfg802154_set_max_associations(struct wpan_dev *wpan_dev, 98 + unsigned int max) 99 + { 100 + unsigned int old_max; 101 + 102 + lockdep_assert_held(&wpan_dev->association_lock); 103 + 104 + old_max = wpan_dev->max_associations; 105 + wpan_dev->max_associations = max; 106 + 107 + return old_max; 108 + } 109 + EXPORT_SYMBOL_GPL(cfg802154_set_max_associations);
+30
net/ieee802154/rdev-ops.h
··· 265 265 return ret; 266 266 } 267 267 268 + static inline int rdev_associate(struct cfg802154_registered_device *rdev, 269 + struct wpan_dev *wpan_dev, 270 + struct ieee802154_addr *coord) 271 + { 272 + int ret; 273 + 274 + if (!rdev->ops->associate) 275 + return -EOPNOTSUPP; 276 + 277 + trace_802154_rdev_associate(&rdev->wpan_phy, wpan_dev, coord); 278 + ret = rdev->ops->associate(&rdev->wpan_phy, wpan_dev, coord); 279 + trace_802154_rdev_return_int(&rdev->wpan_phy, ret); 280 + return ret; 281 + } 282 + 283 + static inline int rdev_disassociate(struct cfg802154_registered_device *rdev, 284 + struct wpan_dev *wpan_dev, 285 + struct ieee802154_addr *target) 286 + { 287 + int ret; 288 + 289 + if (!rdev->ops->disassociate) 290 + return -EOPNOTSUPP; 291 + 292 + trace_802154_rdev_disassociate(&rdev->wpan_phy, wpan_dev, target); 293 + ret = rdev->ops->disassociate(&rdev->wpan_phy, wpan_dev, target); 294 + trace_802154_rdev_return_int(&rdev->wpan_phy, ret); 295 + return ret; 296 + } 297 + 268 298 #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL 269 299 /* TODO this is already a nl802154, so move into ieee802154 */ 270 300 static inline void
+38
net/ieee802154/trace.h
··· 356 356 TP_ARGS(wpan_phy, wpan_dev) 357 357 ); 358 358 359 + TRACE_EVENT(802154_rdev_associate, 360 + TP_PROTO(struct wpan_phy *wpan_phy, 361 + struct wpan_dev *wpan_dev, 362 + struct ieee802154_addr *coord), 363 + TP_ARGS(wpan_phy, wpan_dev, coord), 364 + TP_STRUCT__entry( 365 + WPAN_PHY_ENTRY 366 + WPAN_DEV_ENTRY 367 + __field(__le64, addr) 368 + ), 369 + TP_fast_assign( 370 + WPAN_PHY_ASSIGN; 371 + WPAN_DEV_ASSIGN; 372 + __entry->addr = coord->extended_addr; 373 + ), 374 + TP_printk(WPAN_PHY_PR_FMT ", " WPAN_DEV_PR_FMT ", associating with: 0x%llx", 375 + WPAN_PHY_PR_ARG, WPAN_DEV_PR_ARG, __entry->addr) 376 + ); 377 + 378 + TRACE_EVENT(802154_rdev_disassociate, 379 + TP_PROTO(struct wpan_phy *wpan_phy, 380 + struct wpan_dev *wpan_dev, 381 + struct ieee802154_addr *target), 382 + TP_ARGS(wpan_phy, wpan_dev, target), 383 + TP_STRUCT__entry( 384 + WPAN_PHY_ENTRY 385 + WPAN_DEV_ENTRY 386 + __field(__le64, addr) 387 + ), 388 + TP_fast_assign( 389 + WPAN_PHY_ASSIGN; 390 + WPAN_DEV_ASSIGN; 391 + __entry->addr = target->extended_addr; 392 + ), 393 + TP_printk(WPAN_PHY_PR_FMT ", " WPAN_DEV_PR_FMT ", disassociating with: 0x%llx", 394 + WPAN_PHY_PR_ARG, WPAN_DEV_PR_ARG, __entry->addr) 395 + ); 396 + 359 397 TRACE_EVENT(802154_rdev_return_int, 360 398 TP_PROTO(struct wpan_phy *wpan_phy, int ret), 361 399 TP_ARGS(wpan_phy, ret),
+175
net/mac802154/cfg.c
··· 315 315 return mac802154_stop_beacons_locked(local, sdata); 316 316 } 317 317 318 + static int mac802154_associate(struct wpan_phy *wpan_phy, 319 + struct wpan_dev *wpan_dev, 320 + struct ieee802154_addr *coord) 321 + { 322 + struct ieee802154_local *local = wpan_phy_priv(wpan_phy); 323 + u64 ceaddr = swab64((__force u64)coord->extended_addr); 324 + struct ieee802154_sub_if_data *sdata; 325 + struct ieee802154_pan_device *parent; 326 + __le16 short_addr; 327 + int ret; 328 + 329 + ASSERT_RTNL(); 330 + 331 + sdata = IEEE802154_WPAN_DEV_TO_SUB_IF(wpan_dev); 332 + 333 + if (wpan_dev->parent) { 334 + dev_err(&sdata->dev->dev, 335 + "Device %8phC is already associated\n", &ceaddr); 336 + return -EPERM; 337 + } 338 + 339 + if (coord->mode == IEEE802154_SHORT_ADDRESSING) 340 + return -EINVAL; 341 + 342 + parent = kzalloc(sizeof(*parent), GFP_KERNEL); 343 + if (!parent) 344 + return -ENOMEM; 345 + 346 + parent->pan_id = coord->pan_id; 347 + parent->mode = coord->mode; 348 + parent->extended_addr = coord->extended_addr; 349 + parent->short_addr = cpu_to_le16(IEEE802154_ADDR_SHORT_BROADCAST); 350 + 351 + /* Set the PAN ID hardware address filter beforehand to avoid dropping 352 + * the association response with a destination PAN ID field set to the 353 + * "new" PAN ID. 354 + */ 355 + if (local->hw.flags & IEEE802154_HW_AFILT) { 356 + ret = drv_set_pan_id(local, coord->pan_id); 357 + if (ret < 0) 358 + goto free_parent; 359 + } 360 + 361 + ret = mac802154_perform_association(sdata, parent, &short_addr); 362 + if (ret) 363 + goto reset_panid; 364 + 365 + if (local->hw.flags & IEEE802154_HW_AFILT) { 366 + ret = drv_set_short_addr(local, short_addr); 367 + if (ret < 0) 368 + goto reset_panid; 369 + } 370 + 371 + wpan_dev->pan_id = coord->pan_id; 372 + wpan_dev->short_addr = short_addr; 373 + wpan_dev->parent = parent; 374 + 375 + return 0; 376 + 377 + reset_panid: 378 + if (local->hw.flags & IEEE802154_HW_AFILT) 379 + drv_set_pan_id(local, cpu_to_le16(IEEE802154_PAN_ID_BROADCAST)); 380 + 381 + free_parent: 382 + kfree(parent); 383 + return ret; 384 + } 385 + 386 + static int mac802154_disassociate_from_parent(struct wpan_phy *wpan_phy, 387 + struct wpan_dev *wpan_dev) 388 + { 389 + struct ieee802154_local *local = wpan_phy_priv(wpan_phy); 390 + struct ieee802154_pan_device *child, *tmp; 391 + struct ieee802154_sub_if_data *sdata; 392 + unsigned int max_assoc; 393 + u64 eaddr; 394 + int ret; 395 + 396 + sdata = IEEE802154_WPAN_DEV_TO_SUB_IF(wpan_dev); 397 + 398 + /* Start by disassociating all the children and preventing new ones to 399 + * attempt associations. 400 + */ 401 + max_assoc = cfg802154_set_max_associations(wpan_dev, 0); 402 + list_for_each_entry_safe(child, tmp, &wpan_dev->children, node) { 403 + ret = mac802154_send_disassociation_notif(sdata, child, 404 + IEEE802154_COORD_WISHES_DEVICE_TO_LEAVE); 405 + if (ret) { 406 + eaddr = swab64((__force u64)child->extended_addr); 407 + dev_err(&sdata->dev->dev, 408 + "Disassociation with %8phC may have failed (%d)\n", 409 + &eaddr, ret); 410 + } 411 + 412 + list_del(&child->node); 413 + } 414 + 415 + ret = mac802154_send_disassociation_notif(sdata, wpan_dev->parent, 416 + IEEE802154_DEVICE_WISHES_TO_LEAVE); 417 + if (ret) { 418 + eaddr = swab64((__force u64)wpan_dev->parent->extended_addr); 419 + dev_err(&sdata->dev->dev, 420 + "Disassociation from %8phC may have failed (%d)\n", 421 + &eaddr, ret); 422 + } 423 + 424 + ret = 0; 425 + 426 + kfree(wpan_dev->parent); 427 + wpan_dev->parent = NULL; 428 + wpan_dev->pan_id = cpu_to_le16(IEEE802154_PAN_ID_BROADCAST); 429 + wpan_dev->short_addr = cpu_to_le16(IEEE802154_ADDR_SHORT_BROADCAST); 430 + 431 + if (local->hw.flags & IEEE802154_HW_AFILT) { 432 + ret = drv_set_pan_id(local, wpan_dev->pan_id); 433 + if (ret < 0) 434 + goto reset_mac_assoc; 435 + 436 + ret = drv_set_short_addr(local, wpan_dev->short_addr); 437 + if (ret < 0) 438 + goto reset_mac_assoc; 439 + } 440 + 441 + reset_mac_assoc: 442 + cfg802154_set_max_associations(wpan_dev, max_assoc); 443 + 444 + return ret; 445 + } 446 + 447 + static int mac802154_disassociate_child(struct wpan_phy *wpan_phy, 448 + struct wpan_dev *wpan_dev, 449 + struct ieee802154_pan_device *child) 450 + { 451 + struct ieee802154_sub_if_data *sdata; 452 + int ret; 453 + 454 + sdata = IEEE802154_WPAN_DEV_TO_SUB_IF(wpan_dev); 455 + 456 + ret = mac802154_send_disassociation_notif(sdata, child, 457 + IEEE802154_COORD_WISHES_DEVICE_TO_LEAVE); 458 + if (ret) 459 + return ret; 460 + 461 + list_del(&child->node); 462 + wpan_dev->nchildren--; 463 + kfree(child); 464 + 465 + return 0; 466 + } 467 + 468 + static int mac802154_disassociate(struct wpan_phy *wpan_phy, 469 + struct wpan_dev *wpan_dev, 470 + struct ieee802154_addr *target) 471 + { 472 + u64 teaddr = swab64((__force u64)target->extended_addr); 473 + struct ieee802154_pan_device *pan_device; 474 + 475 + ASSERT_RTNL(); 476 + 477 + if (cfg802154_device_is_parent(wpan_dev, target)) 478 + return mac802154_disassociate_from_parent(wpan_phy, wpan_dev); 479 + 480 + pan_device = cfg802154_device_is_child(wpan_dev, target); 481 + if (pan_device) 482 + return mac802154_disassociate_child(wpan_phy, wpan_dev, 483 + pan_device); 484 + 485 + dev_err(&wpan_dev->netdev->dev, 486 + "Device %8phC is not associated with us\n", &teaddr); 487 + 488 + return -EINVAL; 489 + } 490 + 318 491 #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL 319 492 static void 320 493 ieee802154_get_llsec_table(struct wpan_phy *wpan_phy, ··· 699 526 .abort_scan = mac802154_abort_scan, 700 527 .send_beacons = mac802154_send_beacons, 701 528 .stop_beacons = mac802154_stop_beacons, 529 + .associate = mac802154_associate, 530 + .disassociate = mac802154_disassociate, 702 531 #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL 703 532 .get_llsec_table = ieee802154_get_llsec_table, 704 533 .lock_llsec_table = ieee802154_lock_llsec_table,
+27
net/mac802154/ieee802154_i.h
··· 24 24 enum ieee802154_ongoing { 25 25 IEEE802154_IS_SCANNING = BIT(0), 26 26 IEEE802154_IS_BEACONING = BIT(1), 27 + IEEE802154_IS_ASSOCIATING = BIT(2), 27 28 }; 28 29 29 30 /* mac802154 device private data */ ··· 74 73 struct work_struct rx_beacon_work; 75 74 struct list_head rx_mac_cmd_list; 76 75 struct work_struct rx_mac_cmd_work; 76 + 77 + /* Association */ 78 + struct ieee802154_pan_device *assoc_dev; 79 + struct completion assoc_done; 80 + __le16 assoc_addr; 81 + u8 assoc_status; 82 + struct work_struct assoc_work; 77 83 78 84 bool started; 79 85 bool suspended; ··· 303 295 } 304 296 305 297 void mac802154_rx_mac_cmd_worker(struct work_struct *work); 298 + 299 + int mac802154_perform_association(struct ieee802154_sub_if_data *sdata, 300 + struct ieee802154_pan_device *coord, 301 + __le16 *short_addr); 302 + int mac802154_process_association_resp(struct ieee802154_sub_if_data *sdata, 303 + struct sk_buff *skb); 304 + 305 + static inline bool mac802154_is_associating(struct ieee802154_local *local) 306 + { 307 + return test_bit(IEEE802154_IS_ASSOCIATING, &local->ongoing); 308 + } 309 + 310 + int mac802154_send_disassociation_notif(struct ieee802154_sub_if_data *sdata, 311 + struct ieee802154_pan_device *target, 312 + u8 reason); 313 + int mac802154_process_disassociation_notif(struct ieee802154_sub_if_data *sdata, 314 + struct sk_buff *skb); 315 + int mac802154_process_association_req(struct ieee802154_sub_if_data *sdata, 316 + struct sk_buff *skb); 306 317 307 318 /* interface handling */ 308 319 int ieee802154_iface_init(void);
+2
net/mac802154/main.c
··· 103 103 INIT_DELAYED_WORK(&local->beacon_work, mac802154_beacon_worker); 104 104 INIT_WORK(&local->rx_mac_cmd_work, mac802154_rx_mac_cmd_worker); 105 105 106 + init_completion(&local->assoc_done); 107 + 106 108 /* init supported flags with 802.15.4 default ranges */ 107 109 phy->supported.max_minbe = 8; 108 110 phy->supported.min_maxbe = 3;
+32 -4
net/mac802154/rx.c
··· 93 93 94 94 queue_delayed_work(local->mac_wq, &local->beacon_work, 0); 95 95 break; 96 + 97 + case IEEE802154_CMD_ASSOCIATION_RESP: 98 + dev_dbg(&mac_pkt->sdata->dev->dev, "processing ASSOC RESP\n"); 99 + if (!mac802154_is_associating(local)) 100 + break; 101 + 102 + mac802154_process_association_resp(mac_pkt->sdata, mac_pkt->skb); 103 + break; 104 + 105 + case IEEE802154_CMD_ASSOCIATION_REQ: 106 + dev_dbg(&mac_pkt->sdata->dev->dev, "processing ASSOC REQ\n"); 107 + if (mac_pkt->sdata->wpan_dev.iftype != NL802154_IFTYPE_COORD) 108 + break; 109 + 110 + mac802154_process_association_req(mac_pkt->sdata, mac_pkt->skb); 111 + break; 112 + 113 + case IEEE802154_CMD_DISASSOCIATION_NOTIFY: 114 + dev_dbg(&mac_pkt->sdata->dev->dev, "processing DISASSOC NOTIF\n"); 115 + if (mac_pkt->sdata->wpan_dev.iftype != NL802154_IFTYPE_COORD) 116 + break; 117 + 118 + mac802154_process_disassociation_notif(mac_pkt->sdata, mac_pkt->skb); 119 + break; 120 + 96 121 default: 97 122 break; 98 123 } ··· 156 131 157 132 switch (mac_cb(skb)->dest.mode) { 158 133 case IEEE802154_ADDR_NONE: 159 - if (hdr->source.mode != IEEE802154_ADDR_NONE) 160 - /* FIXME: check if we are PAN coordinator */ 161 - skb->pkt_type = PACKET_OTHERHOST; 162 - else 134 + if (hdr->source.mode == IEEE802154_ADDR_NONE) 163 135 /* ACK comes with both addresses empty */ 164 136 skb->pkt_type = PACKET_HOST; 137 + else if (!wpan_dev->parent) 138 + /* No dest means PAN coordinator is the recipient */ 139 + skb->pkt_type = PACKET_HOST; 140 + else 141 + /* We are not the PAN coordinator, just relaying */ 142 + skb->pkt_type = PACKET_OTHERHOST; 165 143 break; 166 144 case IEEE802154_ADDR_LONG: 167 145 if (mac_cb(skb)->dest.pan_id != span &&
+405 -2
net/mac802154/scan.c
··· 466 466 struct cfg802154_beacon_request *request) 467 467 { 468 468 struct ieee802154_local *local = sdata->local; 469 + struct wpan_dev *wpan_dev = &sdata->wpan_dev; 469 470 470 471 ASSERT_RTNL(); 471 472 ··· 496 495 local->beacon.mac_pl.superframe_order = request->interval; 497 496 local->beacon.mac_pl.final_cap_slot = 0xf; 498 497 local->beacon.mac_pl.battery_life_ext = 0; 499 - /* TODO: Fill this field with the coordinator situation in the network */ 500 - local->beacon.mac_pl.pan_coordinator = 1; 498 + local->beacon.mac_pl.pan_coordinator = !wpan_dev->parent; 501 499 local->beacon.mac_pl.assoc_permit = 1; 502 500 503 501 if (request->interval == IEEE802154_ACTIVE_SCAN_DURATION) ··· 507 507 mac802154_scan_get_channel_time(request->interval, 508 508 request->wpan_phy->symbol_duration); 509 509 queue_delayed_work(local->mac_wq, &local->beacon_work, 0); 510 + 511 + return 0; 512 + } 513 + 514 + int mac802154_perform_association(struct ieee802154_sub_if_data *sdata, 515 + struct ieee802154_pan_device *coord, 516 + __le16 *short_addr) 517 + { 518 + u64 ceaddr = swab64((__force u64)coord->extended_addr); 519 + struct ieee802154_association_req_frame frame = {}; 520 + struct ieee802154_local *local = sdata->local; 521 + struct wpan_dev *wpan_dev = &sdata->wpan_dev; 522 + struct sk_buff *skb; 523 + int ret; 524 + 525 + frame.mhr.fc.type = IEEE802154_FC_TYPE_MAC_CMD; 526 + frame.mhr.fc.security_enabled = 0; 527 + frame.mhr.fc.frame_pending = 0; 528 + frame.mhr.fc.ack_request = 1; /* We always expect an ack here */ 529 + frame.mhr.fc.intra_pan = 0; 530 + frame.mhr.fc.dest_addr_mode = (coord->mode == IEEE802154_ADDR_LONG) ? 531 + IEEE802154_EXTENDED_ADDRESSING : IEEE802154_SHORT_ADDRESSING; 532 + frame.mhr.fc.version = IEEE802154_2003_STD; 533 + frame.mhr.fc.source_addr_mode = IEEE802154_EXTENDED_ADDRESSING; 534 + frame.mhr.source.mode = IEEE802154_ADDR_LONG; 535 + frame.mhr.source.pan_id = cpu_to_le16(IEEE802154_PANID_BROADCAST); 536 + frame.mhr.source.extended_addr = wpan_dev->extended_addr; 537 + frame.mhr.dest.mode = coord->mode; 538 + frame.mhr.dest.pan_id = coord->pan_id; 539 + if (coord->mode == IEEE802154_ADDR_LONG) 540 + frame.mhr.dest.extended_addr = coord->extended_addr; 541 + else 542 + frame.mhr.dest.short_addr = coord->short_addr; 543 + frame.mhr.seq = atomic_inc_return(&wpan_dev->dsn) & 0xFF; 544 + frame.mac_pl.cmd_id = IEEE802154_CMD_ASSOCIATION_REQ; 545 + frame.assoc_req_pl.device_type = 1; 546 + frame.assoc_req_pl.power_source = 1; 547 + frame.assoc_req_pl.rx_on_when_idle = 1; 548 + frame.assoc_req_pl.alloc_addr = 1; 549 + 550 + skb = alloc_skb(IEEE802154_MAC_CMD_SKB_SZ + sizeof(frame.assoc_req_pl), 551 + GFP_KERNEL); 552 + if (!skb) 553 + return -ENOBUFS; 554 + 555 + skb->dev = sdata->dev; 556 + 557 + ret = ieee802154_mac_cmd_push(skb, &frame, &frame.assoc_req_pl, 558 + sizeof(frame.assoc_req_pl)); 559 + if (ret) { 560 + kfree_skb(skb); 561 + return ret; 562 + } 563 + 564 + local->assoc_dev = coord; 565 + reinit_completion(&local->assoc_done); 566 + set_bit(IEEE802154_IS_ASSOCIATING, &local->ongoing); 567 + 568 + ret = ieee802154_mlme_tx_one_locked(local, sdata, skb); 569 + if (ret) { 570 + if (ret > 0) 571 + ret = (ret == IEEE802154_NO_ACK) ? -EREMOTEIO : -EIO; 572 + dev_warn(&sdata->dev->dev, 573 + "No ASSOC REQ ACK received from %8phC\n", &ceaddr); 574 + goto clear_assoc; 575 + } 576 + 577 + ret = wait_for_completion_killable_timeout(&local->assoc_done, 10 * HZ); 578 + if (ret <= 0) { 579 + dev_warn(&sdata->dev->dev, 580 + "No ASSOC RESP received from %8phC\n", &ceaddr); 581 + ret = -ETIMEDOUT; 582 + goto clear_assoc; 583 + } 584 + 585 + if (local->assoc_status != IEEE802154_ASSOCIATION_SUCCESSFUL) { 586 + if (local->assoc_status == IEEE802154_PAN_AT_CAPACITY) 587 + ret = -ERANGE; 588 + else 589 + ret = -EPERM; 590 + 591 + dev_warn(&sdata->dev->dev, 592 + "Negative ASSOC RESP received from %8phC: %s\n", &ceaddr, 593 + local->assoc_status == IEEE802154_PAN_AT_CAPACITY ? 594 + "PAN at capacity" : "access denied"); 595 + } 596 + 597 + ret = 0; 598 + *short_addr = local->assoc_addr; 599 + 600 + clear_assoc: 601 + clear_bit(IEEE802154_IS_ASSOCIATING, &local->ongoing); 602 + local->assoc_dev = NULL; 603 + 604 + return ret; 605 + } 606 + 607 + int mac802154_process_association_resp(struct ieee802154_sub_if_data *sdata, 608 + struct sk_buff *skb) 609 + { 610 + struct ieee802154_addr *src = &mac_cb(skb)->source; 611 + struct ieee802154_addr *dest = &mac_cb(skb)->dest; 612 + u64 deaddr = swab64((__force u64)dest->extended_addr); 613 + struct ieee802154_local *local = sdata->local; 614 + struct wpan_dev *wpan_dev = &sdata->wpan_dev; 615 + struct ieee802154_assoc_resp_pl resp_pl = {}; 616 + 617 + if (skb->len != sizeof(resp_pl)) 618 + return -EINVAL; 619 + 620 + if (unlikely(src->mode != IEEE802154_EXTENDED_ADDRESSING || 621 + dest->mode != IEEE802154_EXTENDED_ADDRESSING)) 622 + return -EINVAL; 623 + 624 + if (unlikely(dest->extended_addr != wpan_dev->extended_addr || 625 + src->extended_addr != local->assoc_dev->extended_addr)) 626 + return -ENODEV; 627 + 628 + memcpy(&resp_pl, skb->data, sizeof(resp_pl)); 629 + local->assoc_addr = resp_pl.short_addr; 630 + local->assoc_status = resp_pl.status; 631 + 632 + dev_dbg(&skb->dev->dev, 633 + "ASSOC RESP 0x%x received from %8phC, getting short address %04x\n", 634 + local->assoc_status, &deaddr, local->assoc_addr); 635 + 636 + complete(&local->assoc_done); 637 + 638 + return 0; 639 + } 640 + 641 + int mac802154_send_disassociation_notif(struct ieee802154_sub_if_data *sdata, 642 + struct ieee802154_pan_device *target, 643 + u8 reason) 644 + { 645 + struct ieee802154_disassociation_notif_frame frame = {}; 646 + u64 teaddr = swab64((__force u64)target->extended_addr); 647 + struct ieee802154_local *local = sdata->local; 648 + struct wpan_dev *wpan_dev = &sdata->wpan_dev; 649 + struct sk_buff *skb; 650 + int ret; 651 + 652 + frame.mhr.fc.type = IEEE802154_FC_TYPE_MAC_CMD; 653 + frame.mhr.fc.security_enabled = 0; 654 + frame.mhr.fc.frame_pending = 0; 655 + frame.mhr.fc.ack_request = 1; 656 + frame.mhr.fc.intra_pan = 1; 657 + frame.mhr.fc.dest_addr_mode = (target->mode == IEEE802154_ADDR_LONG) ? 658 + IEEE802154_EXTENDED_ADDRESSING : IEEE802154_SHORT_ADDRESSING; 659 + frame.mhr.fc.version = IEEE802154_2003_STD; 660 + frame.mhr.fc.source_addr_mode = IEEE802154_EXTENDED_ADDRESSING; 661 + frame.mhr.source.mode = IEEE802154_ADDR_LONG; 662 + frame.mhr.source.pan_id = wpan_dev->pan_id; 663 + frame.mhr.source.extended_addr = wpan_dev->extended_addr; 664 + frame.mhr.dest.mode = target->mode; 665 + frame.mhr.dest.pan_id = wpan_dev->pan_id; 666 + if (target->mode == IEEE802154_ADDR_LONG) 667 + frame.mhr.dest.extended_addr = target->extended_addr; 668 + else 669 + frame.mhr.dest.short_addr = target->short_addr; 670 + frame.mhr.seq = atomic_inc_return(&wpan_dev->dsn) & 0xFF; 671 + frame.mac_pl.cmd_id = IEEE802154_CMD_DISASSOCIATION_NOTIFY; 672 + frame.disassoc_pl = reason; 673 + 674 + skb = alloc_skb(IEEE802154_MAC_CMD_SKB_SZ + sizeof(frame.disassoc_pl), 675 + GFP_KERNEL); 676 + if (!skb) 677 + return -ENOBUFS; 678 + 679 + skb->dev = sdata->dev; 680 + 681 + ret = ieee802154_mac_cmd_push(skb, &frame, &frame.disassoc_pl, 682 + sizeof(frame.disassoc_pl)); 683 + if (ret) { 684 + kfree_skb(skb); 685 + return ret; 686 + } 687 + 688 + ret = ieee802154_mlme_tx_one_locked(local, sdata, skb); 689 + if (ret) { 690 + dev_warn(&sdata->dev->dev, 691 + "No DISASSOC ACK received from %8phC\n", &teaddr); 692 + if (ret > 0) 693 + ret = (ret == IEEE802154_NO_ACK) ? -EREMOTEIO : -EIO; 694 + return ret; 695 + } 696 + 697 + dev_dbg(&sdata->dev->dev, "DISASSOC ACK received from %8phC\n", &teaddr); 698 + return 0; 699 + } 700 + 701 + static int 702 + mac802154_send_association_resp_locked(struct ieee802154_sub_if_data *sdata, 703 + struct ieee802154_pan_device *target, 704 + struct ieee802154_assoc_resp_pl *assoc_resp_pl) 705 + { 706 + u64 teaddr = swab64((__force u64)target->extended_addr); 707 + struct ieee802154_association_resp_frame frame = {}; 708 + struct ieee802154_local *local = sdata->local; 709 + struct wpan_dev *wpan_dev = &sdata->wpan_dev; 710 + struct sk_buff *skb; 711 + int ret; 712 + 713 + frame.mhr.fc.type = IEEE802154_FC_TYPE_MAC_CMD; 714 + frame.mhr.fc.security_enabled = 0; 715 + frame.mhr.fc.frame_pending = 0; 716 + frame.mhr.fc.ack_request = 1; /* We always expect an ack here */ 717 + frame.mhr.fc.intra_pan = 1; 718 + frame.mhr.fc.dest_addr_mode = IEEE802154_EXTENDED_ADDRESSING; 719 + frame.mhr.fc.version = IEEE802154_2003_STD; 720 + frame.mhr.fc.source_addr_mode = IEEE802154_EXTENDED_ADDRESSING; 721 + frame.mhr.source.mode = IEEE802154_ADDR_LONG; 722 + frame.mhr.source.extended_addr = wpan_dev->extended_addr; 723 + frame.mhr.dest.mode = IEEE802154_ADDR_LONG; 724 + frame.mhr.dest.pan_id = wpan_dev->pan_id; 725 + frame.mhr.dest.extended_addr = target->extended_addr; 726 + frame.mhr.seq = atomic_inc_return(&wpan_dev->dsn) & 0xFF; 727 + frame.mac_pl.cmd_id = IEEE802154_CMD_ASSOCIATION_RESP; 728 + 729 + skb = alloc_skb(IEEE802154_MAC_CMD_SKB_SZ + sizeof(*assoc_resp_pl), 730 + GFP_KERNEL); 731 + if (!skb) 732 + return -ENOBUFS; 733 + 734 + skb->dev = sdata->dev; 735 + 736 + ret = ieee802154_mac_cmd_push(skb, &frame, assoc_resp_pl, 737 + sizeof(*assoc_resp_pl)); 738 + if (ret) { 739 + kfree_skb(skb); 740 + return ret; 741 + } 742 + 743 + ret = ieee802154_mlme_tx_locked(local, sdata, skb); 744 + if (ret) { 745 + dev_warn(&sdata->dev->dev, 746 + "No ASSOC RESP ACK received from %8phC\n", &teaddr); 747 + if (ret > 0) 748 + ret = (ret == IEEE802154_NO_ACK) ? -EREMOTEIO : -EIO; 749 + return ret; 750 + } 751 + 752 + return 0; 753 + } 754 + 755 + int mac802154_process_association_req(struct ieee802154_sub_if_data *sdata, 756 + struct sk_buff *skb) 757 + { 758 + struct wpan_dev *wpan_dev = &sdata->wpan_dev; 759 + struct ieee802154_addr *src = &mac_cb(skb)->source; 760 + struct ieee802154_addr *dest = &mac_cb(skb)->dest; 761 + struct ieee802154_assoc_resp_pl assoc_resp_pl = {}; 762 + struct ieee802154_assoc_req_pl assoc_req_pl; 763 + struct ieee802154_pan_device *child, *exchild; 764 + struct ieee802154_addr tmp = {}; 765 + u64 ceaddr; 766 + int ret; 767 + 768 + if (skb->len != sizeof(assoc_req_pl)) 769 + return -EINVAL; 770 + 771 + if (unlikely(src->mode != IEEE802154_EXTENDED_ADDRESSING)) 772 + return -EINVAL; 773 + 774 + if (unlikely(dest->pan_id != wpan_dev->pan_id)) 775 + return -ENODEV; 776 + 777 + if (dest->mode == IEEE802154_EXTENDED_ADDRESSING && 778 + unlikely(dest->extended_addr != wpan_dev->extended_addr)) 779 + return -ENODEV; 780 + else if (dest->mode == IEEE802154_SHORT_ADDRESSING && 781 + unlikely(dest->short_addr != wpan_dev->short_addr)) 782 + return -ENODEV; 783 + 784 + if (wpan_dev->parent) { 785 + dev_dbg(&sdata->dev->dev, 786 + "Ignoring ASSOC REQ, not the PAN coordinator\n"); 787 + return -ENODEV; 788 + } 789 + 790 + mutex_lock(&wpan_dev->association_lock); 791 + 792 + memcpy(&assoc_req_pl, skb->data, sizeof(assoc_req_pl)); 793 + if (assoc_req_pl.assoc_type) { 794 + dev_err(&skb->dev->dev, "Fast associations not supported yet\n"); 795 + ret = -EOPNOTSUPP; 796 + goto unlock; 797 + } 798 + 799 + child = kzalloc(sizeof(*child), GFP_KERNEL); 800 + if (!child) { 801 + ret = -ENOMEM; 802 + goto unlock; 803 + } 804 + 805 + child->extended_addr = src->extended_addr; 806 + child->mode = IEEE802154_EXTENDED_ADDRESSING; 807 + ceaddr = swab64((__force u64)child->extended_addr); 808 + 809 + if (wpan_dev->nchildren >= wpan_dev->max_associations) { 810 + if (!wpan_dev->max_associations) 811 + assoc_resp_pl.status = IEEE802154_PAN_ACCESS_DENIED; 812 + else 813 + assoc_resp_pl.status = IEEE802154_PAN_AT_CAPACITY; 814 + assoc_resp_pl.short_addr = cpu_to_le16(IEEE802154_ADDR_SHORT_BROADCAST); 815 + dev_dbg(&sdata->dev->dev, 816 + "Refusing ASSOC REQ from child %8phC, %s\n", &ceaddr, 817 + assoc_resp_pl.status == IEEE802154_PAN_ACCESS_DENIED ? 818 + "access denied" : "too many children"); 819 + } else { 820 + assoc_resp_pl.status = IEEE802154_ASSOCIATION_SUCCESSFUL; 821 + if (assoc_req_pl.alloc_addr) { 822 + assoc_resp_pl.short_addr = cfg802154_get_free_short_addr(wpan_dev); 823 + child->mode = IEEE802154_SHORT_ADDRESSING; 824 + } else { 825 + assoc_resp_pl.short_addr = cpu_to_le16(IEEE802154_ADDR_SHORT_UNSPEC); 826 + } 827 + child->short_addr = assoc_resp_pl.short_addr; 828 + dev_dbg(&sdata->dev->dev, 829 + "Accepting ASSOC REQ from child %8phC, providing short address 0x%04x\n", 830 + &ceaddr, le16_to_cpu(child->short_addr)); 831 + } 832 + 833 + ret = mac802154_send_association_resp_locked(sdata, child, &assoc_resp_pl); 834 + if (ret || assoc_resp_pl.status != IEEE802154_ASSOCIATION_SUCCESSFUL) { 835 + kfree(child); 836 + goto unlock; 837 + } 838 + 839 + dev_dbg(&sdata->dev->dev, 840 + "Successful association with new child %8phC\n", &ceaddr); 841 + 842 + /* Ensure this child is not already associated (might happen due to 843 + * retransmissions), in this case drop the ex structure. 844 + */ 845 + tmp.mode = child->mode; 846 + tmp.extended_addr = child->extended_addr; 847 + exchild = cfg802154_device_is_child(wpan_dev, &tmp); 848 + if (exchild) { 849 + dev_dbg(&sdata->dev->dev, 850 + "Child %8phC was already known\n", &ceaddr); 851 + list_del(&exchild->node); 852 + } 853 + 854 + list_add(&child->node, &wpan_dev->children); 855 + wpan_dev->nchildren++; 856 + 857 + unlock: 858 + mutex_unlock(&wpan_dev->association_lock); 859 + return ret; 860 + } 861 + 862 + int mac802154_process_disassociation_notif(struct ieee802154_sub_if_data *sdata, 863 + struct sk_buff *skb) 864 + { 865 + struct ieee802154_addr *src = &mac_cb(skb)->source; 866 + struct ieee802154_addr *dest = &mac_cb(skb)->dest; 867 + struct wpan_dev *wpan_dev = &sdata->wpan_dev; 868 + struct ieee802154_pan_device *child; 869 + struct ieee802154_addr target; 870 + bool parent; 871 + u64 teaddr; 872 + 873 + if (skb->len != sizeof(u8)) 874 + return -EINVAL; 875 + 876 + if (unlikely(src->mode != IEEE802154_EXTENDED_ADDRESSING)) 877 + return -EINVAL; 878 + 879 + if (dest->mode == IEEE802154_EXTENDED_ADDRESSING && 880 + unlikely(dest->extended_addr != wpan_dev->extended_addr)) 881 + return -ENODEV; 882 + else if (dest->mode == IEEE802154_SHORT_ADDRESSING && 883 + unlikely(dest->short_addr != wpan_dev->short_addr)) 884 + return -ENODEV; 885 + 886 + if (dest->pan_id != wpan_dev->pan_id) 887 + return -ENODEV; 888 + 889 + target.mode = IEEE802154_EXTENDED_ADDRESSING; 890 + target.extended_addr = src->extended_addr; 891 + teaddr = swab64((__force u64)target.extended_addr); 892 + dev_dbg(&skb->dev->dev, "Processing DISASSOC NOTIF from %8phC\n", &teaddr); 893 + 894 + mutex_lock(&wpan_dev->association_lock); 895 + parent = cfg802154_device_is_parent(wpan_dev, &target); 896 + if (!parent) 897 + child = cfg802154_device_is_child(wpan_dev, &target); 898 + if (!parent && !child) { 899 + mutex_unlock(&wpan_dev->association_lock); 900 + return -EINVAL; 901 + } 902 + 903 + if (parent) { 904 + kfree(wpan_dev->parent); 905 + wpan_dev->parent = NULL; 906 + } else { 907 + list_del(&child->node); 908 + kfree(child); 909 + wpan_dev->nchildren--; 910 + } 911 + 912 + mutex_unlock(&wpan_dev->association_lock); 510 913 511 914 return 0; 512 915 }