1 /* 2 * Copyright 2007-2012 Siemens AG 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License version 2 6 * as published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 * 13 * You should have received a copy of the GNU General Public License along 14 * with this program; if not, write to the Free Software Foundation, Inc., 15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 16 * 17 * Written by: 18 * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> 19 * Sergey Lapin <slapin@ossfans.org> 20 * Maxim Gorbachyov <maxim.gorbachev@siemens.com> 21 * Alexander Smirnov <alex.bluesman.smirnov@gmail.com> 22 */ 23 24 #include <linux/if_arp.h> 25 26 #include <net/mac802154.h> 27 #include <net/ieee802154_netdev.h> 28 #include <net/wpan-phy.h> 29 30 #include "mac802154.h" 31 32 struct phy_chan_notify_work { 33 struct work_struct work; 34 struct net_device *dev; 35 }; 36 37 struct hw_addr_filt_notify_work { 38 struct work_struct work; 39 struct net_device *dev; 40 unsigned long changed; 41 }; 42 43 static struct mac802154_priv *mac802154_slave_get_priv(struct net_device *dev) 44 { 45 struct mac802154_sub_if_data *priv = netdev_priv(dev); 46 47 BUG_ON(dev->type != ARPHRD_IEEE802154); 48 49 return priv->hw; 50 } 51 52 static void hw_addr_notify(struct work_struct *work) 53 { 54 struct hw_addr_filt_notify_work *nw = container_of(work, 55 struct hw_addr_filt_notify_work, work); 56 struct mac802154_priv *hw = mac802154_slave_get_priv(nw->dev); 57 int res; 58 59 res = hw->ops->set_hw_addr_filt(&hw->hw, 60 &hw->hw.hw_filt, 61 nw->changed); 62 if (res) 63 pr_debug("failed changed mask %lx\n", nw->changed); 64 65 kfree(nw); 66 } 67 68 static void set_hw_addr_filt(struct net_device *dev, unsigned long changed) 69 { 70 struct mac802154_sub_if_data *priv = netdev_priv(dev); 71 struct hw_addr_filt_notify_work *work; 72 73 work = kzalloc(sizeof(*work), GFP_ATOMIC); 74 if (!work) 75 return; 76 77 INIT_WORK(&work->work, hw_addr_notify); 78 work->dev = dev; 79 work->changed = changed; 80 queue_work(priv->hw->dev_workqueue, &work->work); 81 } 82 83 void mac802154_dev_set_short_addr(struct net_device *dev, __le16 val) 84 { 85 struct mac802154_sub_if_data *priv = netdev_priv(dev); 86 87 BUG_ON(dev->type != ARPHRD_IEEE802154); 88 89 spin_lock_bh(&priv->mib_lock); 90 priv->short_addr = val; 91 spin_unlock_bh(&priv->mib_lock); 92 93 if ((priv->hw->ops->set_hw_addr_filt) && 94 (priv->hw->hw.hw_filt.short_addr != priv->short_addr)) { 95 priv->hw->hw.hw_filt.short_addr = priv->short_addr; 96 set_hw_addr_filt(dev, IEEE802515_AFILT_SADDR_CHANGED); 97 } 98 } 99 100 __le16 mac802154_dev_get_short_addr(const struct net_device *dev) 101 { 102 struct mac802154_sub_if_data *priv = netdev_priv(dev); 103 __le16 ret; 104 105 BUG_ON(dev->type != ARPHRD_IEEE802154); 106 107 spin_lock_bh(&priv->mib_lock); 108 ret = priv->short_addr; 109 spin_unlock_bh(&priv->mib_lock); 110 111 return ret; 112 } 113 114 void mac802154_dev_set_ieee_addr(struct net_device *dev) 115 { 116 struct mac802154_sub_if_data *priv = netdev_priv(dev); 117 struct mac802154_priv *mac = priv->hw; 118 119 priv->extended_addr = ieee802154_devaddr_from_raw(dev->dev_addr); 120 121 if (mac->ops->set_hw_addr_filt && 122 mac->hw.hw_filt.ieee_addr != priv->extended_addr) { 123 mac->hw.hw_filt.ieee_addr = priv->extended_addr; 124 set_hw_addr_filt(dev, IEEE802515_AFILT_IEEEADDR_CHANGED); 125 } 126 } 127 128 __le16 mac802154_dev_get_pan_id(const struct net_device *dev) 129 { 130 struct mac802154_sub_if_data *priv = netdev_priv(dev); 131 __le16 ret; 132 133 BUG_ON(dev->type != ARPHRD_IEEE802154); 134 135 spin_lock_bh(&priv->mib_lock); 136 ret = priv->pan_id; 137 spin_unlock_bh(&priv->mib_lock); 138 139 return ret; 140 } 141 142 void mac802154_dev_set_pan_id(struct net_device *dev, __le16 val) 143 { 144 struct mac802154_sub_if_data *priv = netdev_priv(dev); 145 146 BUG_ON(dev->type != ARPHRD_IEEE802154); 147 148 spin_lock_bh(&priv->mib_lock); 149 priv->pan_id = val; 150 spin_unlock_bh(&priv->mib_lock); 151 152 if ((priv->hw->ops->set_hw_addr_filt) && 153 (priv->hw->hw.hw_filt.pan_id != priv->pan_id)) { 154 priv->hw->hw.hw_filt.pan_id = priv->pan_id; 155 set_hw_addr_filt(dev, IEEE802515_AFILT_PANID_CHANGED); 156 } 157 } 158 159 u8 mac802154_dev_get_dsn(const struct net_device *dev) 160 { 161 struct mac802154_sub_if_data *priv = netdev_priv(dev); 162 163 BUG_ON(dev->type != ARPHRD_IEEE802154); 164 165 return priv->dsn++; 166 } 167 168 static void phy_chan_notify(struct work_struct *work) 169 { 170 struct phy_chan_notify_work *nw = container_of(work, 171 struct phy_chan_notify_work, work); 172 struct mac802154_priv *hw = mac802154_slave_get_priv(nw->dev); 173 struct mac802154_sub_if_data *priv = netdev_priv(nw->dev); 174 int res; 175 176 mutex_lock(&priv->hw->phy->pib_lock); 177 res = hw->ops->set_channel(&hw->hw, priv->page, priv->chan); 178 if (res) 179 pr_debug("set_channel failed\n"); 180 else { 181 priv->hw->phy->current_channel = priv->chan; 182 priv->hw->phy->current_page = priv->page; 183 } 184 mutex_unlock(&priv->hw->phy->pib_lock); 185 186 kfree(nw); 187 } 188 189 void mac802154_dev_set_page_channel(struct net_device *dev, u8 page, u8 chan) 190 { 191 struct mac802154_sub_if_data *priv = netdev_priv(dev); 192 struct phy_chan_notify_work *work; 193 194 BUG_ON(dev->type != ARPHRD_IEEE802154); 195 196 spin_lock_bh(&priv->mib_lock); 197 priv->page = page; 198 priv->chan = chan; 199 spin_unlock_bh(&priv->mib_lock); 200 201 mutex_lock(&priv->hw->phy->pib_lock); 202 if (priv->hw->phy->current_channel != priv->chan || 203 priv->hw->phy->current_page != priv->page) { 204 mutex_unlock(&priv->hw->phy->pib_lock); 205 206 work = kzalloc(sizeof(*work), GFP_ATOMIC); 207 if (!work) 208 return; 209 210 INIT_WORK(&work->work, phy_chan_notify); 211 work->dev = dev; 212 queue_work(priv->hw->dev_workqueue, &work->work); 213 } else 214 mutex_unlock(&priv->hw->phy->pib_lock); 215 } 216