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/wpan-phy.h> 28 29 #include "mac802154.h" 30 31 struct phy_chan_notify_work { 32 struct work_struct work; 33 struct net_device *dev; 34 }; 35 36 struct hw_addr_filt_notify_work { 37 struct work_struct work; 38 struct net_device *dev; 39 unsigned long changed; 40 }; 41 42 static struct mac802154_priv *mac802154_slave_get_priv(struct net_device *dev) 43 { 44 struct mac802154_sub_if_data *priv = netdev_priv(dev); 45 46 BUG_ON(dev->type != ARPHRD_IEEE802154); 47 48 return priv->hw; 49 } 50 51 static void hw_addr_notify(struct work_struct *work) 52 { 53 struct hw_addr_filt_notify_work *nw = container_of(work, 54 struct hw_addr_filt_notify_work, work); 55 struct mac802154_priv *hw = mac802154_slave_get_priv(nw->dev); 56 int res; 57 58 res = hw->ops->set_hw_addr_filt(&hw->hw, 59 &hw->hw.hw_filt, 60 nw->changed); 61 if (res) 62 pr_debug("failed changed mask %lx\n", nw->changed); 63 64 kfree(nw); 65 66 return; 67 } 68 69 static void set_hw_addr_filt(struct net_device *dev, unsigned long changed) 70 { 71 struct mac802154_sub_if_data *priv = netdev_priv(dev); 72 struct hw_addr_filt_notify_work *work; 73 74 work = kzalloc(sizeof(*work), GFP_ATOMIC); 75 if (!work) 76 return; 77 78 INIT_WORK(&work->work, hw_addr_notify); 79 work->dev = dev; 80 work->changed = changed; 81 queue_work(priv->hw->dev_workqueue, &work->work); 82 83 return; 84 } 85 86 void mac802154_dev_set_short_addr(struct net_device *dev, u16 val) 87 { 88 struct mac802154_sub_if_data *priv = netdev_priv(dev); 89 90 BUG_ON(dev->type != ARPHRD_IEEE802154); 91 92 spin_lock_bh(&priv->mib_lock); 93 priv->short_addr = val; 94 spin_unlock_bh(&priv->mib_lock); 95 96 if ((priv->hw->ops->set_hw_addr_filt) && 97 (priv->hw->hw.hw_filt.short_addr != priv->short_addr)) { 98 priv->hw->hw.hw_filt.short_addr = priv->short_addr; 99 set_hw_addr_filt(dev, IEEE802515_AFILT_SADDR_CHANGED); 100 } 101 } 102 103 u16 mac802154_dev_get_short_addr(const struct net_device *dev) 104 { 105 struct mac802154_sub_if_data *priv = netdev_priv(dev); 106 u16 ret; 107 108 BUG_ON(dev->type != ARPHRD_IEEE802154); 109 110 spin_lock_bh(&priv->mib_lock); 111 ret = priv->short_addr; 112 spin_unlock_bh(&priv->mib_lock); 113 114 return ret; 115 } 116 117 void mac802154_dev_set_ieee_addr(struct net_device *dev) 118 { 119 struct mac802154_sub_if_data *priv = netdev_priv(dev); 120 struct mac802154_priv *mac = priv->hw; 121 122 if (mac->ops->set_hw_addr_filt && 123 memcmp(mac->hw.hw_filt.ieee_addr, 124 dev->dev_addr, IEEE802154_ADDR_LEN)) { 125 memcpy(mac->hw.hw_filt.ieee_addr, 126 dev->dev_addr, IEEE802154_ADDR_LEN); 127 set_hw_addr_filt(dev, IEEE802515_AFILT_IEEEADDR_CHANGED); 128 } 129 } 130 131 u16 mac802154_dev_get_pan_id(const struct net_device *dev) 132 { 133 struct mac802154_sub_if_data *priv = netdev_priv(dev); 134 u16 ret; 135 136 BUG_ON(dev->type != ARPHRD_IEEE802154); 137 138 spin_lock_bh(&priv->mib_lock); 139 ret = priv->pan_id; 140 spin_unlock_bh(&priv->mib_lock); 141 142 return ret; 143 } 144 145 void mac802154_dev_set_pan_id(struct net_device *dev, u16 val) 146 { 147 struct mac802154_sub_if_data *priv = netdev_priv(dev); 148 149 BUG_ON(dev->type != ARPHRD_IEEE802154); 150 151 spin_lock_bh(&priv->mib_lock); 152 priv->pan_id = val; 153 spin_unlock_bh(&priv->mib_lock); 154 155 if ((priv->hw->ops->set_hw_addr_filt) && 156 (priv->hw->hw.hw_filt.pan_id != priv->pan_id)) { 157 priv->hw->hw.hw_filt.pan_id = priv->pan_id; 158 set_hw_addr_filt(dev, IEEE802515_AFILT_PANID_CHANGED); 159 } 160 } 161 162 u8 mac802154_dev_get_dsn(const struct net_device *dev) 163 { 164 struct mac802154_sub_if_data *priv = netdev_priv(dev); 165 166 BUG_ON(dev->type != ARPHRD_IEEE802154); 167 168 return priv->dsn++; 169 } 170 171 static void phy_chan_notify(struct work_struct *work) 172 { 173 struct phy_chan_notify_work *nw = container_of(work, 174 struct phy_chan_notify_work, work); 175 struct mac802154_priv *hw = mac802154_slave_get_priv(nw->dev); 176 struct mac802154_sub_if_data *priv = netdev_priv(nw->dev); 177 int res; 178 179 mutex_lock(&priv->hw->phy->pib_lock); 180 res = hw->ops->set_channel(&hw->hw, priv->page, priv->chan); 181 if (res) 182 pr_debug("set_channel failed\n"); 183 else { 184 priv->hw->phy->current_channel = priv->chan; 185 priv->hw->phy->current_page = priv->page; 186 } 187 mutex_unlock(&priv->hw->phy->pib_lock); 188 189 kfree(nw); 190 } 191 192 void mac802154_dev_set_page_channel(struct net_device *dev, u8 page, u8 chan) 193 { 194 struct mac802154_sub_if_data *priv = netdev_priv(dev); 195 struct phy_chan_notify_work *work; 196 197 BUG_ON(dev->type != ARPHRD_IEEE802154); 198 199 spin_lock_bh(&priv->mib_lock); 200 priv->page = page; 201 priv->chan = chan; 202 spin_unlock_bh(&priv->mib_lock); 203 204 mutex_lock(&priv->hw->phy->pib_lock); 205 if (priv->hw->phy->current_channel != priv->chan || 206 priv->hw->phy->current_page != priv->page) { 207 mutex_unlock(&priv->hw->phy->pib_lock); 208 209 work = kzalloc(sizeof(*work), GFP_ATOMIC); 210 if (!work) 211 return; 212 213 INIT_WORK(&work->work, phy_chan_notify); 214 work->dev = dev; 215 queue_work(priv->hw->dev_workqueue, &work->work); 216 } else 217 mutex_unlock(&priv->hw->phy->pib_lock); 218 } 219