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 static void phy_chan_notify(struct work_struct *work) 163 { 164 struct phy_chan_notify_work *nw = container_of(work, 165 struct phy_chan_notify_work, work); 166 struct mac802154_priv *hw = mac802154_slave_get_priv(nw->dev); 167 struct mac802154_sub_if_data *priv = netdev_priv(nw->dev); 168 int res; 169 170 res = hw->ops->set_channel(&hw->hw, priv->page, priv->chan); 171 if (res) 172 pr_debug("set_channel failed\n"); 173 174 kfree(nw); 175 } 176 177 void mac802154_dev_set_page_channel(struct net_device *dev, u8 page, u8 chan) 178 { 179 struct mac802154_sub_if_data *priv = netdev_priv(dev); 180 struct phy_chan_notify_work *work; 181 182 BUG_ON(dev->type != ARPHRD_IEEE802154); 183 184 spin_lock_bh(&priv->mib_lock); 185 priv->page = page; 186 priv->chan = chan; 187 spin_unlock_bh(&priv->mib_lock); 188 189 if (priv->hw->phy->current_channel != priv->chan || 190 priv->hw->phy->current_page != priv->page) { 191 work = kzalloc(sizeof(*work), GFP_ATOMIC); 192 if (!work) 193 return; 194 195 INIT_WORK(&work->work, phy_chan_notify); 196 work->dev = dev; 197 queue_work(priv->hw->dev_workqueue, &work->work); 198 } 199 } 200