^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * HWSIM IEEE 802.15.4 interface
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * (C) 2018 Mojatau, Alexander Aring <aring@mojatau.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright 2007-2012 Siemens AG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Based on fakelb, original Written by:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Sergey Lapin <slapin@ossfans.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/timer.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/rtnetlink.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/netdevice.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/spinlock.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <net/mac802154.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <net/cfg802154.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <net/genetlink.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include "mac802154_hwsim.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) MODULE_DESCRIPTION("Software simulator of IEEE 802.15.4 radio(s) for mac802154");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) static LIST_HEAD(hwsim_phys);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) static DEFINE_MUTEX(hwsim_phys_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) static struct platform_device *mac802154hwsim_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) /* MAC802154_HWSIM netlink family */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) static struct genl_family hwsim_genl_family;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) static int hwsim_radio_idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) enum hwsim_multicast_groups {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) HWSIM_MCGRP_CONFIG,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) static const struct genl_multicast_group hwsim_mcgrps[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) [HWSIM_MCGRP_CONFIG] = { .name = "config", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) struct hwsim_pib {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) u8 page;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) u8 channel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) struct rcu_head rcu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) struct hwsim_edge_info {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) u8 lqi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) struct rcu_head rcu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) struct hwsim_edge {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) struct hwsim_phy *endpoint;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) struct hwsim_edge_info __rcu *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) struct list_head list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) struct rcu_head rcu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) struct hwsim_phy {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) struct ieee802154_hw *hw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) u32 idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) struct hwsim_pib __rcu *pib;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) bool suspended;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) struct list_head edges;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) struct list_head list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) static int hwsim_add_one(struct genl_info *info, struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) bool init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) static void hwsim_del(struct hwsim_phy *phy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) static int hwsim_hw_ed(struct ieee802154_hw *hw, u8 *level)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) *level = 0xbe;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) static int hwsim_hw_channel(struct ieee802154_hw *hw, u8 page, u8 channel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) struct hwsim_phy *phy = hw->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) struct hwsim_pib *pib, *pib_old;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) pib = kzalloc(sizeof(*pib), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) if (!pib)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) pib->page = page;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) pib->channel = channel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) pib_old = rtnl_dereference(phy->pib);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) rcu_assign_pointer(phy->pib, pib);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) kfree_rcu(pib_old, rcu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) static int hwsim_hw_xmit(struct ieee802154_hw *hw, struct sk_buff *skb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) struct hwsim_phy *current_phy = hw->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) struct hwsim_pib *current_pib, *endpoint_pib;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) struct hwsim_edge_info *einfo;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) struct hwsim_edge *e;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) WARN_ON(current_phy->suspended);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) rcu_read_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) current_pib = rcu_dereference(current_phy->pib);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) list_for_each_entry_rcu(e, ¤t_phy->edges, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) /* Can be changed later in rx_irqsafe, but this is only a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) * performance tweak. Received radio should drop the frame
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) * in mac802154 stack anyway... so we don't need to be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) * 100% of locking here to check on suspended
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) if (e->endpoint->suspended)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) endpoint_pib = rcu_dereference(e->endpoint->pib);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) if (current_pib->page == endpoint_pib->page &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) current_pib->channel == endpoint_pib->channel) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) struct sk_buff *newskb = pskb_copy(skb, GFP_ATOMIC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) einfo = rcu_dereference(e->info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) if (newskb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) ieee802154_rx_irqsafe(e->endpoint->hw, newskb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) einfo->lqi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) rcu_read_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) ieee802154_xmit_complete(hw, skb, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) static int hwsim_hw_start(struct ieee802154_hw *hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) struct hwsim_phy *phy = hw->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) phy->suspended = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) static void hwsim_hw_stop(struct ieee802154_hw *hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) struct hwsim_phy *phy = hw->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) phy->suspended = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) hwsim_set_promiscuous_mode(struct ieee802154_hw *hw, const bool on)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) static const struct ieee802154_ops hwsim_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) .xmit_async = hwsim_hw_xmit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) .ed = hwsim_hw_ed,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) .set_channel = hwsim_hw_channel,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) .start = hwsim_hw_start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) .stop = hwsim_hw_stop,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) .set_promiscuous_mode = hwsim_set_promiscuous_mode,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) static int hwsim_new_radio_nl(struct sk_buff *msg, struct genl_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) return hwsim_add_one(info, &mac802154hwsim_dev->dev, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) static int hwsim_del_radio_nl(struct sk_buff *msg, struct genl_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) struct hwsim_phy *phy, *tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) s64 idx = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) if (!info->attrs[MAC802154_HWSIM_ATTR_RADIO_ID])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) idx = nla_get_u32(info->attrs[MAC802154_HWSIM_ATTR_RADIO_ID]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) mutex_lock(&hwsim_phys_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) list_for_each_entry_safe(phy, tmp, &hwsim_phys, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) if (idx == phy->idx) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) hwsim_del(phy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) mutex_unlock(&hwsim_phys_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) mutex_unlock(&hwsim_phys_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) static int append_radio_msg(struct sk_buff *skb, struct hwsim_phy *phy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) struct nlattr *nl_edges, *nl_edge;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) struct hwsim_edge_info *einfo;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) struct hwsim_edge *e;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) ret = nla_put_u32(skb, MAC802154_HWSIM_ATTR_RADIO_ID, phy->idx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) rcu_read_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) if (list_empty(&phy->edges)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) rcu_read_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) nl_edges = nla_nest_start_noflag(skb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) MAC802154_HWSIM_ATTR_RADIO_EDGES);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) if (!nl_edges) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) rcu_read_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) return -ENOBUFS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) list_for_each_entry_rcu(e, &phy->edges, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) nl_edge = nla_nest_start_noflag(skb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) MAC802154_HWSIM_ATTR_RADIO_EDGE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) if (!nl_edge) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) rcu_read_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) nla_nest_cancel(skb, nl_edges);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) return -ENOBUFS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) ret = nla_put_u32(skb, MAC802154_HWSIM_EDGE_ATTR_ENDPOINT_ID,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) e->endpoint->idx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) rcu_read_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) nla_nest_cancel(skb, nl_edge);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) nla_nest_cancel(skb, nl_edges);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) einfo = rcu_dereference(e->info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) ret = nla_put_u8(skb, MAC802154_HWSIM_EDGE_ATTR_LQI,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) einfo->lqi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) rcu_read_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) nla_nest_cancel(skb, nl_edge);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) nla_nest_cancel(skb, nl_edges);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) nla_nest_end(skb, nl_edge);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) rcu_read_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) nla_nest_end(skb, nl_edges);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) static int hwsim_get_radio(struct sk_buff *skb, struct hwsim_phy *phy,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) u32 portid, u32 seq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) struct netlink_callback *cb, int flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) void *hdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) int res = -EMSGSIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) hdr = genlmsg_put(skb, portid, seq, &hwsim_genl_family, flags,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) MAC802154_HWSIM_CMD_GET_RADIO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) if (!hdr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) return -EMSGSIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) if (cb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) genl_dump_check_consistent(cb, hdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) res = append_radio_msg(skb, phy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) if (res < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) goto out_err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) genlmsg_end(skb, hdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) out_err:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) genlmsg_cancel(skb, hdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) return res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) static int hwsim_get_radio_nl(struct sk_buff *msg, struct genl_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) struct hwsim_phy *phy;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) struct sk_buff *skb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) int idx, res = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) if (!info->attrs[MAC802154_HWSIM_ATTR_RADIO_ID])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) idx = nla_get_u32(info->attrs[MAC802154_HWSIM_ATTR_RADIO_ID]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) mutex_lock(&hwsim_phys_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) list_for_each_entry(phy, &hwsim_phys, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) if (phy->idx != idx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) if (!skb) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) res = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) goto out_err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) res = hwsim_get_radio(skb, phy, info->snd_portid,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) info->snd_seq, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) if (res < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) nlmsg_free(skb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) goto out_err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) res = genlmsg_reply(skb, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) out_err:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) mutex_unlock(&hwsim_phys_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) return res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) static int hwsim_dump_radio_nl(struct sk_buff *skb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) struct netlink_callback *cb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) int idx = cb->args[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) struct hwsim_phy *phy;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) int res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) mutex_lock(&hwsim_phys_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) if (idx == hwsim_radio_idx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) goto done;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) list_for_each_entry(phy, &hwsim_phys, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) if (phy->idx < idx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) res = hwsim_get_radio(skb, phy, NETLINK_CB(cb->skb).portid,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) cb->nlh->nlmsg_seq, cb, NLM_F_MULTI);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) if (res < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) idx = phy->idx + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) cb->args[0] = idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) done:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) mutex_unlock(&hwsim_phys_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) return skb->len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) /* caller need to held hwsim_phys_lock */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) static struct hwsim_phy *hwsim_get_radio_by_id(uint32_t idx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) struct hwsim_phy *phy;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) list_for_each_entry(phy, &hwsim_phys, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) if (phy->idx == idx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) return phy;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) static const struct nla_policy hwsim_edge_policy[MAC802154_HWSIM_EDGE_ATTR_MAX + 1] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) [MAC802154_HWSIM_EDGE_ATTR_ENDPOINT_ID] = { .type = NLA_U32 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) [MAC802154_HWSIM_EDGE_ATTR_LQI] = { .type = NLA_U8 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) static struct hwsim_edge *hwsim_alloc_edge(struct hwsim_phy *endpoint, u8 lqi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) struct hwsim_edge_info *einfo;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) struct hwsim_edge *e;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) e = kzalloc(sizeof(*e), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) if (!e)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) einfo = kzalloc(sizeof(*einfo), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) if (!einfo) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) kfree(e);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) einfo->lqi = 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) rcu_assign_pointer(e->info, einfo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) e->endpoint = endpoint;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) return e;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) static void hwsim_free_edge(struct hwsim_edge *e)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) struct hwsim_edge_info *einfo;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) rcu_read_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) einfo = rcu_dereference(e->info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) rcu_read_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) kfree_rcu(einfo, rcu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) kfree_rcu(e, rcu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) static int hwsim_new_edge_nl(struct sk_buff *msg, struct genl_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) struct nlattr *edge_attrs[MAC802154_HWSIM_EDGE_ATTR_MAX + 1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) struct hwsim_phy *phy_v0, *phy_v1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) struct hwsim_edge *e;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) u32 v0, v1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) if (!info->attrs[MAC802154_HWSIM_ATTR_RADIO_ID] ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) !info->attrs[MAC802154_HWSIM_ATTR_RADIO_EDGE])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) if (nla_parse_nested_deprecated(edge_attrs, MAC802154_HWSIM_EDGE_ATTR_MAX, info->attrs[MAC802154_HWSIM_ATTR_RADIO_EDGE], hwsim_edge_policy, NULL))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) if (!edge_attrs[MAC802154_HWSIM_EDGE_ATTR_ENDPOINT_ID])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) v0 = nla_get_u32(info->attrs[MAC802154_HWSIM_ATTR_RADIO_ID]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) v1 = nla_get_u32(edge_attrs[MAC802154_HWSIM_EDGE_ATTR_ENDPOINT_ID]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) if (v0 == v1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) mutex_lock(&hwsim_phys_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) phy_v0 = hwsim_get_radio_by_id(v0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) if (!phy_v0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) mutex_unlock(&hwsim_phys_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) phy_v1 = hwsim_get_radio_by_id(v1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) if (!phy_v1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) mutex_unlock(&hwsim_phys_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) rcu_read_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) list_for_each_entry_rcu(e, &phy_v0->edges, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) if (e->endpoint->idx == v1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) mutex_unlock(&hwsim_phys_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) rcu_read_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) return -EEXIST;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) rcu_read_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) e = hwsim_alloc_edge(phy_v1, 0xff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) if (!e) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) mutex_unlock(&hwsim_phys_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) list_add_rcu(&e->list, &phy_v0->edges);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) /* wait until changes are done under hwsim_phys_lock lock
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) * should prevent of calling this function twice while
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) * edges list has not the changes yet.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) synchronize_rcu();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) mutex_unlock(&hwsim_phys_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) static int hwsim_del_edge_nl(struct sk_buff *msg, struct genl_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) struct nlattr *edge_attrs[MAC802154_HWSIM_EDGE_ATTR_MAX + 1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) struct hwsim_phy *phy_v0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) struct hwsim_edge *e;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) u32 v0, v1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) if (!info->attrs[MAC802154_HWSIM_ATTR_RADIO_ID] ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) !info->attrs[MAC802154_HWSIM_ATTR_RADIO_EDGE])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) if (nla_parse_nested_deprecated(edge_attrs, MAC802154_HWSIM_EDGE_ATTR_MAX, info->attrs[MAC802154_HWSIM_ATTR_RADIO_EDGE], hwsim_edge_policy, NULL))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) if (!edge_attrs[MAC802154_HWSIM_EDGE_ATTR_ENDPOINT_ID])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) v0 = nla_get_u32(info->attrs[MAC802154_HWSIM_ATTR_RADIO_ID]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) v1 = nla_get_u32(edge_attrs[MAC802154_HWSIM_EDGE_ATTR_ENDPOINT_ID]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) mutex_lock(&hwsim_phys_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) phy_v0 = hwsim_get_radio_by_id(v0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) if (!phy_v0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) mutex_unlock(&hwsim_phys_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) rcu_read_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) list_for_each_entry_rcu(e, &phy_v0->edges, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) if (e->endpoint->idx == v1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) rcu_read_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) list_del_rcu(&e->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) hwsim_free_edge(e);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) /* same again - wait until list changes are done */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) synchronize_rcu();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) mutex_unlock(&hwsim_phys_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) rcu_read_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) mutex_unlock(&hwsim_phys_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) static int hwsim_set_edge_lqi(struct sk_buff *msg, struct genl_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) struct nlattr *edge_attrs[MAC802154_HWSIM_EDGE_ATTR_MAX + 1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) struct hwsim_edge_info *einfo;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) struct hwsim_phy *phy_v0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) struct hwsim_edge *e;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) u32 v0, v1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) u8 lqi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) if (!info->attrs[MAC802154_HWSIM_ATTR_RADIO_ID] ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) !info->attrs[MAC802154_HWSIM_ATTR_RADIO_EDGE])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) if (nla_parse_nested_deprecated(edge_attrs, MAC802154_HWSIM_EDGE_ATTR_MAX, info->attrs[MAC802154_HWSIM_ATTR_RADIO_EDGE], hwsim_edge_policy, NULL))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) if (!edge_attrs[MAC802154_HWSIM_EDGE_ATTR_ENDPOINT_ID] ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) !edge_attrs[MAC802154_HWSIM_EDGE_ATTR_LQI])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) v0 = nla_get_u32(info->attrs[MAC802154_HWSIM_ATTR_RADIO_ID]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) v1 = nla_get_u32(edge_attrs[MAC802154_HWSIM_EDGE_ATTR_ENDPOINT_ID]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) lqi = nla_get_u8(edge_attrs[MAC802154_HWSIM_EDGE_ATTR_LQI]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) mutex_lock(&hwsim_phys_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) phy_v0 = hwsim_get_radio_by_id(v0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) if (!phy_v0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) mutex_unlock(&hwsim_phys_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) einfo = kzalloc(sizeof(*einfo), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) if (!einfo) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) mutex_unlock(&hwsim_phys_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) rcu_read_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) list_for_each_entry_rcu(e, &phy_v0->edges, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) if (e->endpoint->idx == v1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) einfo->lqi = lqi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) rcu_assign_pointer(e->info, einfo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) rcu_read_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) mutex_unlock(&hwsim_phys_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) rcu_read_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) kfree(einfo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) mutex_unlock(&hwsim_phys_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) /* MAC802154_HWSIM netlink policy */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) static const struct nla_policy hwsim_genl_policy[MAC802154_HWSIM_ATTR_MAX + 1] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) [MAC802154_HWSIM_ATTR_RADIO_ID] = { .type = NLA_U32 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) [MAC802154_HWSIM_ATTR_RADIO_EDGE] = { .type = NLA_NESTED },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) [MAC802154_HWSIM_ATTR_RADIO_EDGES] = { .type = NLA_NESTED },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) /* Generic Netlink operations array */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) static const struct genl_small_ops hwsim_nl_ops[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) .cmd = MAC802154_HWSIM_CMD_NEW_RADIO,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) .doit = hwsim_new_radio_nl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) .flags = GENL_UNS_ADMIN_PERM,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) .cmd = MAC802154_HWSIM_CMD_DEL_RADIO,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) .doit = hwsim_del_radio_nl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) .flags = GENL_UNS_ADMIN_PERM,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) .cmd = MAC802154_HWSIM_CMD_GET_RADIO,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) .doit = hwsim_get_radio_nl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) .dumpit = hwsim_dump_radio_nl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) .cmd = MAC802154_HWSIM_CMD_NEW_EDGE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) .doit = hwsim_new_edge_nl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) .flags = GENL_UNS_ADMIN_PERM,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) .cmd = MAC802154_HWSIM_CMD_DEL_EDGE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) .doit = hwsim_del_edge_nl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) .flags = GENL_UNS_ADMIN_PERM,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) .cmd = MAC802154_HWSIM_CMD_SET_EDGE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) .doit = hwsim_set_edge_lqi,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) .flags = GENL_UNS_ADMIN_PERM,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) static struct genl_family hwsim_genl_family __ro_after_init = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) .name = "MAC802154_HWSIM",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) .version = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) .maxattr = MAC802154_HWSIM_ATTR_MAX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) .policy = hwsim_genl_policy,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) .module = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) .small_ops = hwsim_nl_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) .n_small_ops = ARRAY_SIZE(hwsim_nl_ops),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) .mcgrps = hwsim_mcgrps,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) .n_mcgrps = ARRAY_SIZE(hwsim_mcgrps),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) static void hwsim_mcast_config_msg(struct sk_buff *mcast_skb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) struct genl_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) if (info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) genl_notify(&hwsim_genl_family, mcast_skb, info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) HWSIM_MCGRP_CONFIG, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) genlmsg_multicast(&hwsim_genl_family, mcast_skb, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) HWSIM_MCGRP_CONFIG, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) static void hwsim_mcast_new_radio(struct genl_info *info, struct hwsim_phy *phy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) struct sk_buff *mcast_skb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) void *data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) mcast_skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) if (!mcast_skb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) data = genlmsg_put(mcast_skb, 0, 0, &hwsim_genl_family, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) MAC802154_HWSIM_CMD_NEW_RADIO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) if (!data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) goto out_err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) if (append_radio_msg(mcast_skb, phy) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) goto out_err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) genlmsg_end(mcast_skb, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) hwsim_mcast_config_msg(mcast_skb, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) out_err:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) genlmsg_cancel(mcast_skb, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) nlmsg_free(mcast_skb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) static void hwsim_edge_unsubscribe_me(struct hwsim_phy *phy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) struct hwsim_phy *tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) struct hwsim_edge *e;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) rcu_read_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) /* going to all phy edges and remove phy from it */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) list_for_each_entry(tmp, &hwsim_phys, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) list_for_each_entry_rcu(e, &tmp->edges, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) if (e->endpoint->idx == phy->idx) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) list_del_rcu(&e->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) hwsim_free_edge(e);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) rcu_read_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) synchronize_rcu();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) static int hwsim_subscribe_all_others(struct hwsim_phy *phy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) struct hwsim_phy *sub;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) struct hwsim_edge *e;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) list_for_each_entry(sub, &hwsim_phys, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) e = hwsim_alloc_edge(sub, 0xff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) if (!e)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) goto me_fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) list_add_rcu(&e->list, &phy->edges);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) list_for_each_entry(sub, &hwsim_phys, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) e = hwsim_alloc_edge(phy, 0xff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) if (!e)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) goto sub_fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) list_add_rcu(&e->list, &sub->edges);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) sub_fail:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) hwsim_edge_unsubscribe_me(phy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) me_fail:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) rcu_read_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) list_for_each_entry_rcu(e, &phy->edges, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) list_del_rcu(&e->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) hwsim_free_edge(e);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) rcu_read_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) static int hwsim_add_one(struct genl_info *info, struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) bool init)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) struct ieee802154_hw *hw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) struct hwsim_phy *phy;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) struct hwsim_pib *pib;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) int idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) idx = hwsim_radio_idx++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) hw = ieee802154_alloc_hw(sizeof(*phy), &hwsim_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) if (!hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) phy = hw->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) phy->hw = hw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) /* 868 MHz BPSK 802.15.4-2003 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) hw->phy->supported.channels[0] |= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) /* 915 MHz BPSK 802.15.4-2003 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) hw->phy->supported.channels[0] |= 0x7fe;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) /* 2.4 GHz O-QPSK 802.15.4-2003 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) hw->phy->supported.channels[0] |= 0x7FFF800;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) /* 868 MHz ASK 802.15.4-2006 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) hw->phy->supported.channels[1] |= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) /* 915 MHz ASK 802.15.4-2006 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) hw->phy->supported.channels[1] |= 0x7fe;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) /* 868 MHz O-QPSK 802.15.4-2006 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) hw->phy->supported.channels[2] |= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) /* 915 MHz O-QPSK 802.15.4-2006 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) hw->phy->supported.channels[2] |= 0x7fe;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) /* 2.4 GHz CSS 802.15.4a-2007 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) hw->phy->supported.channels[3] |= 0x3fff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) /* UWB Sub-gigahertz 802.15.4a-2007 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) hw->phy->supported.channels[4] |= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) /* UWB Low band 802.15.4a-2007 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) hw->phy->supported.channels[4] |= 0x1e;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) /* UWB High band 802.15.4a-2007 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) hw->phy->supported.channels[4] |= 0xffe0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) /* 750 MHz O-QPSK 802.15.4c-2009 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) hw->phy->supported.channels[5] |= 0xf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) /* 750 MHz MPSK 802.15.4c-2009 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) hw->phy->supported.channels[5] |= 0xf0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) /* 950 MHz BPSK 802.15.4d-2009 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) hw->phy->supported.channels[6] |= 0x3ff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) /* 950 MHz GFSK 802.15.4d-2009 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) hw->phy->supported.channels[6] |= 0x3ffc00;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) ieee802154_random_extended_addr(&hw->phy->perm_extended_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) /* hwsim phy channel 13 as default */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) hw->phy->current_channel = 13;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) pib = kzalloc(sizeof(*pib), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) if (!pib) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) err = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) goto err_pib;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) pib->channel = 13;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) rcu_assign_pointer(phy->pib, pib);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) phy->idx = idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) INIT_LIST_HEAD(&phy->edges);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) hw->flags = IEEE802154_HW_PROMISCUOUS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) hw->parent = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) err = ieee802154_register_hw(hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) goto err_reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) mutex_lock(&hwsim_phys_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) if (init) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) err = hwsim_subscribe_all_others(phy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) if (err < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) mutex_unlock(&hwsim_phys_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) goto err_subscribe;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) list_add_tail(&phy->list, &hwsim_phys);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) mutex_unlock(&hwsim_phys_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) hwsim_mcast_new_radio(info, phy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) return idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) err_subscribe:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) ieee802154_unregister_hw(phy->hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) err_reg:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) kfree(pib);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) err_pib:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) ieee802154_free_hw(phy->hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) static void hwsim_del(struct hwsim_phy *phy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) struct hwsim_pib *pib;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) struct hwsim_edge *e;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) hwsim_edge_unsubscribe_me(phy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) list_del(&phy->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) rcu_read_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) list_for_each_entry_rcu(e, &phy->edges, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) list_del_rcu(&e->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) hwsim_free_edge(e);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) pib = rcu_dereference(phy->pib);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) rcu_read_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) kfree_rcu(pib, rcu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) ieee802154_unregister_hw(phy->hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) ieee802154_free_hw(phy->hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) static int hwsim_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) struct hwsim_phy *phy, *tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) int err, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) for (i = 0; i < 2; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) err = hwsim_add_one(NULL, &pdev->dev, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) goto err_slave;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) dev_info(&pdev->dev, "Added 2 mac802154 hwsim hardware radios\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) err_slave:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) mutex_lock(&hwsim_phys_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) list_for_each_entry_safe(phy, tmp, &hwsim_phys, list)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) hwsim_del(phy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) mutex_unlock(&hwsim_phys_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) static int hwsim_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) struct hwsim_phy *phy, *tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) mutex_lock(&hwsim_phys_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) list_for_each_entry_safe(phy, tmp, &hwsim_phys, list)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) hwsim_del(phy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) mutex_unlock(&hwsim_phys_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) static struct platform_driver mac802154hwsim_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) .probe = hwsim_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) .remove = hwsim_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) .name = "mac802154_hwsim",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) static __init int hwsim_init_module(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) rc = genl_register_family(&hwsim_genl_family);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) mac802154hwsim_dev = platform_device_register_simple("mac802154_hwsim",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) -1, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) if (IS_ERR(mac802154hwsim_dev)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) rc = PTR_ERR(mac802154hwsim_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) goto platform_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) rc = platform_driver_register(&mac802154hwsim_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) if (rc < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) goto platform_drv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) platform_drv:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) platform_device_unregister(mac802154hwsim_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) platform_dev:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) genl_unregister_family(&hwsim_genl_family);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) static __exit void hwsim_remove_module(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) genl_unregister_family(&hwsim_genl_family);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) platform_driver_unregister(&mac802154hwsim_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) platform_device_unregister(mac802154hwsim_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) module_init(hwsim_init_module);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) module_exit(hwsim_remove_module);