15b641ebeSalex.bluesman.smirnov@gmail.com /* 25b641ebeSalex.bluesman.smirnov@gmail.com * Copyright 2007-2012 Siemens AG 35b641ebeSalex.bluesman.smirnov@gmail.com * 45b641ebeSalex.bluesman.smirnov@gmail.com * This program is free software; you can redistribute it and/or modify 55b641ebeSalex.bluesman.smirnov@gmail.com * it under the terms of the GNU General Public License version 2 65b641ebeSalex.bluesman.smirnov@gmail.com * as published by the Free Software Foundation. 75b641ebeSalex.bluesman.smirnov@gmail.com * 85b641ebeSalex.bluesman.smirnov@gmail.com * This program is distributed in the hope that it will be useful, 95b641ebeSalex.bluesman.smirnov@gmail.com * but WITHOUT ANY WARRANTY; without even the implied warranty of 105b641ebeSalex.bluesman.smirnov@gmail.com * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 115b641ebeSalex.bluesman.smirnov@gmail.com * GNU General Public License for more details. 125b641ebeSalex.bluesman.smirnov@gmail.com * 135b641ebeSalex.bluesman.smirnov@gmail.com * You should have received a copy of the GNU General Public License along 145b641ebeSalex.bluesman.smirnov@gmail.com * with this program; if not, write to the Free Software Foundation, Inc., 155b641ebeSalex.bluesman.smirnov@gmail.com * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 165b641ebeSalex.bluesman.smirnov@gmail.com * 175b641ebeSalex.bluesman.smirnov@gmail.com * Written by: 185b641ebeSalex.bluesman.smirnov@gmail.com * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> 195b641ebeSalex.bluesman.smirnov@gmail.com * Sergey Lapin <slapin@ossfans.org> 205b641ebeSalex.bluesman.smirnov@gmail.com * Maxim Gorbachyov <maxim.gorbachev@siemens.com> 215b641ebeSalex.bluesman.smirnov@gmail.com * Alexander Smirnov <alex.bluesman.smirnov@gmail.com> 225b641ebeSalex.bluesman.smirnov@gmail.com */ 235b641ebeSalex.bluesman.smirnov@gmail.com 245b641ebeSalex.bluesman.smirnov@gmail.com #include <linux/netdevice.h> 255b641ebeSalex.bluesman.smirnov@gmail.com #include <linux/if_arp.h> 265b641ebeSalex.bluesman.smirnov@gmail.com #include <linux/crc-ccitt.h> 275b641ebeSalex.bluesman.smirnov@gmail.com 28*b5992fe9SAlan Ott #include <net/ieee802154_netdev.h> 295b641ebeSalex.bluesman.smirnov@gmail.com #include <net/mac802154.h> 305b641ebeSalex.bluesman.smirnov@gmail.com #include <net/wpan-phy.h> 315b641ebeSalex.bluesman.smirnov@gmail.com 325b641ebeSalex.bluesman.smirnov@gmail.com #include "mac802154.h" 335b641ebeSalex.bluesman.smirnov@gmail.com 345b641ebeSalex.bluesman.smirnov@gmail.com /* IEEE 802.15.4 transceivers can sleep during the xmit session, so process 355b641ebeSalex.bluesman.smirnov@gmail.com * packets through the workqueue. 365b641ebeSalex.bluesman.smirnov@gmail.com */ 375b641ebeSalex.bluesman.smirnov@gmail.com struct xmit_work { 385b641ebeSalex.bluesman.smirnov@gmail.com struct sk_buff *skb; 395b641ebeSalex.bluesman.smirnov@gmail.com struct work_struct work; 405b641ebeSalex.bluesman.smirnov@gmail.com struct mac802154_priv *priv; 415b641ebeSalex.bluesman.smirnov@gmail.com u8 chan; 425b641ebeSalex.bluesman.smirnov@gmail.com u8 page; 435b641ebeSalex.bluesman.smirnov@gmail.com }; 445b641ebeSalex.bluesman.smirnov@gmail.com 455b641ebeSalex.bluesman.smirnov@gmail.com static void mac802154_xmit_worker(struct work_struct *work) 465b641ebeSalex.bluesman.smirnov@gmail.com { 475b641ebeSalex.bluesman.smirnov@gmail.com struct xmit_work *xw = container_of(work, struct xmit_work, work); 48*b5992fe9SAlan Ott struct mac802154_sub_if_data *sdata; 495b641ebeSalex.bluesman.smirnov@gmail.com int res; 505b641ebeSalex.bluesman.smirnov@gmail.com 515b641ebeSalex.bluesman.smirnov@gmail.com mutex_lock(&xw->priv->phy->pib_lock); 525b641ebeSalex.bluesman.smirnov@gmail.com if (xw->priv->phy->current_channel != xw->chan || 535b641ebeSalex.bluesman.smirnov@gmail.com xw->priv->phy->current_page != xw->page) { 545b641ebeSalex.bluesman.smirnov@gmail.com res = xw->priv->ops->set_channel(&xw->priv->hw, 555b641ebeSalex.bluesman.smirnov@gmail.com xw->page, 565b641ebeSalex.bluesman.smirnov@gmail.com xw->chan); 575b641ebeSalex.bluesman.smirnov@gmail.com if (res) { 585b641ebeSalex.bluesman.smirnov@gmail.com pr_debug("set_channel failed\n"); 595b641ebeSalex.bluesman.smirnov@gmail.com goto out; 605b641ebeSalex.bluesman.smirnov@gmail.com } 615b641ebeSalex.bluesman.smirnov@gmail.com } 625b641ebeSalex.bluesman.smirnov@gmail.com 635b641ebeSalex.bluesman.smirnov@gmail.com res = xw->priv->ops->xmit(&xw->priv->hw, xw->skb); 647dd43d35SAlan Ott if (res) 657dd43d35SAlan Ott pr_debug("transmission failed\n"); 665b641ebeSalex.bluesman.smirnov@gmail.com 675b641ebeSalex.bluesman.smirnov@gmail.com out: 685b641ebeSalex.bluesman.smirnov@gmail.com mutex_unlock(&xw->priv->phy->pib_lock); 695b641ebeSalex.bluesman.smirnov@gmail.com 70*b5992fe9SAlan Ott /* Restart the netif queue on each sub_if_data object. */ 71*b5992fe9SAlan Ott rcu_read_lock(); 72*b5992fe9SAlan Ott list_for_each_entry_rcu(sdata, &xw->priv->slaves, list) 73*b5992fe9SAlan Ott netif_wake_queue(sdata->dev); 74*b5992fe9SAlan Ott rcu_read_unlock(); 755b641ebeSalex.bluesman.smirnov@gmail.com 765b641ebeSalex.bluesman.smirnov@gmail.com dev_kfree_skb(xw->skb); 775b641ebeSalex.bluesman.smirnov@gmail.com 785b641ebeSalex.bluesman.smirnov@gmail.com kfree(xw); 795b641ebeSalex.bluesman.smirnov@gmail.com } 805b641ebeSalex.bluesman.smirnov@gmail.com 815b641ebeSalex.bluesman.smirnov@gmail.com netdev_tx_t mac802154_tx(struct mac802154_priv *priv, struct sk_buff *skb, 825b641ebeSalex.bluesman.smirnov@gmail.com u8 page, u8 chan) 835b641ebeSalex.bluesman.smirnov@gmail.com { 845b641ebeSalex.bluesman.smirnov@gmail.com struct xmit_work *work; 85*b5992fe9SAlan Ott struct mac802154_sub_if_data *sdata; 865b641ebeSalex.bluesman.smirnov@gmail.com 878a8e28b8Salex.bluesman.smirnov@gmail.com if (!(priv->phy->channels_supported[page] & (1 << chan))) { 885b641ebeSalex.bluesman.smirnov@gmail.com WARN_ON(1); 89fcefbe9fSAlan Ott kfree_skb(skb); 905b641ebeSalex.bluesman.smirnov@gmail.com return NETDEV_TX_OK; 918a8e28b8Salex.bluesman.smirnov@gmail.com } 925b641ebeSalex.bluesman.smirnov@gmail.com 9372fd5a8bSalex.bluesman.smirnov@gmail.com mac802154_monitors_rx(mac802154_to_priv(&priv->hw), skb); 9472fd5a8bSalex.bluesman.smirnov@gmail.com 955b641ebeSalex.bluesman.smirnov@gmail.com if (!(priv->hw.flags & IEEE802154_HW_OMIT_CKSUM)) { 965b641ebeSalex.bluesman.smirnov@gmail.com u16 crc = crc_ccitt(0, skb->data, skb->len); 975b641ebeSalex.bluesman.smirnov@gmail.com u8 *data = skb_put(skb, 2); 985b641ebeSalex.bluesman.smirnov@gmail.com data[0] = crc & 0xff; 995b641ebeSalex.bluesman.smirnov@gmail.com data[1] = crc >> 8; 1005b641ebeSalex.bluesman.smirnov@gmail.com } 1015b641ebeSalex.bluesman.smirnov@gmail.com 1025b641ebeSalex.bluesman.smirnov@gmail.com if (skb_cow_head(skb, priv->hw.extra_tx_headroom)) { 10392a2ec72SAlan Ott kfree_skb(skb); 1045b641ebeSalex.bluesman.smirnov@gmail.com return NETDEV_TX_OK; 1055b641ebeSalex.bluesman.smirnov@gmail.com } 1065b641ebeSalex.bluesman.smirnov@gmail.com 1075b641ebeSalex.bluesman.smirnov@gmail.com work = kzalloc(sizeof(struct xmit_work), GFP_ATOMIC); 108fcefbe9fSAlan Ott if (!work) { 109fcefbe9fSAlan Ott kfree_skb(skb); 1105b641ebeSalex.bluesman.smirnov@gmail.com return NETDEV_TX_BUSY; 111fcefbe9fSAlan Ott } 1125b641ebeSalex.bluesman.smirnov@gmail.com 113*b5992fe9SAlan Ott /* Stop the netif queue on each sub_if_data object. */ 114*b5992fe9SAlan Ott rcu_read_lock(); 115*b5992fe9SAlan Ott list_for_each_entry_rcu(sdata, &priv->slaves, list) 116*b5992fe9SAlan Ott netif_stop_queue(sdata->dev); 117*b5992fe9SAlan Ott rcu_read_unlock(); 118*b5992fe9SAlan Ott 1195b641ebeSalex.bluesman.smirnov@gmail.com INIT_WORK(&work->work, mac802154_xmit_worker); 1205b641ebeSalex.bluesman.smirnov@gmail.com work->skb = skb; 1215b641ebeSalex.bluesman.smirnov@gmail.com work->priv = priv; 1225b641ebeSalex.bluesman.smirnov@gmail.com work->page = page; 1235b641ebeSalex.bluesman.smirnov@gmail.com work->chan = chan; 1245b641ebeSalex.bluesman.smirnov@gmail.com 1255b641ebeSalex.bluesman.smirnov@gmail.com queue_work(priv->dev_workqueue, &work->work); 1265b641ebeSalex.bluesman.smirnov@gmail.com 1275b641ebeSalex.bluesman.smirnov@gmail.com return NETDEV_TX_OK; 1285b641ebeSalex.bluesman.smirnov@gmail.com } 129