2012-05-16 00:50:22 +04:00
/*
* Copyright 2007 - 2012 Siemens AG
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* Written by :
* Dmitry Eremin - Solenikov < dbaryshkov @ gmail . com >
* Sergey Lapin < slapin @ ossfans . org >
* Maxim Gorbachyov < maxim . gorbachev @ siemens . com >
* Alexander Smirnov < alex . bluesman . smirnov @ gmail . com >
*/
# include <linux/netdevice.h>
# include <linux/if_arp.h>
# include <linux/crc-ccitt.h>
2014-10-27 19:13:28 +03:00
# include <asm/unaligned.h>
2012-05-16 00:50:22 +04:00
2014-10-26 11:37:09 +03:00
# include <net/rtnetlink.h>
2013-04-03 08:00:56 +04:00
# include <net/ieee802154_netdev.h>
2012-05-16 00:50:22 +04:00
# include <net/mac802154.h>
2014-10-25 11:41:02 +04:00
# include <net/cfg802154.h>
2012-05-16 00:50:22 +04:00
2014-10-25 11:41:00 +04:00
# include "ieee802154_i.h"
2014-10-28 20:21:21 +03:00
# include "driver-ops.h"
2012-05-16 00:50:22 +04:00
/* IEEE 802.15.4 transceivers can sleep during the xmit session, so process
* packets through the workqueue .
*/
2014-10-26 11:37:13 +03:00
struct ieee802154_xmit_cb {
2012-05-16 00:50:22 +04:00
struct sk_buff * skb ;
struct work_struct work ;
2014-10-25 19:16:35 +04:00
struct ieee802154_local * local ;
2012-05-16 00:50:22 +04:00
} ;
2014-10-26 20:15:34 +03:00
static struct ieee802154_xmit_cb ieee802154_xmit_cb ;
2014-10-26 11:37:02 +03:00
2014-10-26 11:37:13 +03:00
static void ieee802154_xmit_worker ( struct work_struct * work )
2012-05-16 00:50:22 +04:00
{
2014-10-26 11:37:13 +03:00
struct ieee802154_xmit_cb * cb =
container_of ( work , struct ieee802154_xmit_cb , work ) ;
2014-10-26 11:37:03 +03:00
struct ieee802154_local * local = cb - > local ;
struct sk_buff * skb = cb - > skb ;
2014-10-26 11:37:12 +03:00
struct net_device * dev = skb - > dev ;
2012-05-16 00:50:22 +04:00
int res ;
2014-10-26 11:37:09 +03:00
rtnl_lock ( ) ;
/* check if ifdown occurred while schedule */
2014-10-26 11:37:12 +03:00
if ( ! netif_running ( dev ) )
2014-10-26 11:37:09 +03:00
goto err_tx ;
2014-10-28 20:21:21 +03:00
res = drv_xmit_sync ( local , skb ) ;
2014-10-26 11:37:09 +03:00
if ( res )
goto err_tx ;
ieee802154_xmit_complete ( & local - > hw , skb ) ;
2014-10-26 11:37:12 +03:00
dev - > stats . tx_packets + + ;
dev - > stats . tx_bytes + = skb - > len ;
2014-10-26 11:37:09 +03:00
rtnl_unlock ( ) ;
return ;
err_tx :
/* Restart the netif queue on each sub_if_data object. */
ieee802154_wake_queue ( & local - > hw ) ;
rtnl_unlock ( ) ;
kfree_skb ( skb ) ;
2014-10-26 11:37:12 +03:00
netdev_dbg ( dev , " transmission failed \n " ) ;
2012-05-16 00:50:22 +04:00
}
2014-10-26 11:37:04 +03:00
static netdev_tx_t
2014-10-26 11:37:13 +03:00
ieee802154_tx ( struct ieee802154_local * local , struct sk_buff * skb )
2012-05-16 00:50:22 +04:00
{
2014-10-26 11:37:12 +03:00
struct net_device * dev = skb - > dev ;
2014-10-26 11:37:08 +03:00
int ret ;
2012-05-16 00:50:22 +04:00
2014-10-25 19:16:35 +04:00
if ( ! ( local - > hw . flags & IEEE802154_HW_OMIT_CKSUM ) ) {
2014-10-27 19:13:28 +03:00
u16 crc = crc_ccitt ( 0 , skb - > data , skb - > len ) ;
2014-07-02 07:31:09 +04:00
2014-10-27 19:13:28 +03:00
put_unaligned_le16 ( crc , skb_put ( skb , 2 ) ) ;
2012-05-16 00:50:22 +04:00
}
2014-10-25 19:16:35 +04:00
if ( skb_cow_head ( skb , local - > hw . extra_tx_headroom ) )
2014-08-11 15:25:10 +04:00
goto err_tx ;
2012-05-16 00:50:22 +04:00
2013-04-03 08:00:56 +04:00
/* Stop the netif queue on each sub_if_data object. */
2014-10-26 11:37:06 +03:00
ieee802154_stop_queue ( & local - > hw ) ;
2013-04-03 08:00:56 +04:00
2014-10-26 11:37:08 +03:00
/* async is priority, otherwise sync is fallback */
if ( local - > ops - > xmit_async ) {
2014-10-28 20:21:21 +03:00
ret = drv_xmit_async ( local , skb ) ;
2014-10-26 11:37:08 +03:00
if ( ret ) {
ieee802154_wake_queue ( & local - > hw ) ;
goto err_tx ;
}
2014-10-26 11:37:12 +03:00
dev - > stats . tx_packets + + ;
dev - > stats . tx_bytes + = skb - > len ;
2014-10-26 11:37:08 +03:00
} else {
2014-10-26 20:15:34 +03:00
INIT_WORK ( & ieee802154_xmit_cb . work , ieee802154_xmit_worker ) ;
ieee802154_xmit_cb . skb = skb ;
ieee802154_xmit_cb . local = local ;
2012-05-16 00:50:22 +04:00
2014-10-26 20:15:34 +03:00
queue_work ( local - > workqueue , & ieee802154_xmit_cb . work ) ;
2014-10-26 11:37:08 +03:00
}
2012-05-16 00:50:22 +04:00
return NETDEV_TX_OK ;
2014-08-11 15:25:10 +04:00
err_tx :
kfree_skb ( skb ) ;
return NETDEV_TX_OK ;
2012-05-16 00:50:22 +04:00
}
2014-10-26 11:37:01 +03:00
2014-10-26 11:37:13 +03:00
netdev_tx_t
ieee802154_monitor_start_xmit ( struct sk_buff * skb , struct net_device * dev )
2014-10-26 11:37:01 +03:00
{
struct ieee802154_sub_if_data * sdata = IEEE802154_DEV_TO_SUB_IF ( dev ) ;
skb - > skb_iif = dev - > ifindex ;
2014-10-26 11:37:13 +03:00
return ieee802154_tx ( sdata - > local , skb ) ;
2014-10-26 11:37:01 +03:00
}
2014-10-26 11:37:13 +03:00
netdev_tx_t
ieee802154_subif_start_xmit ( struct sk_buff * skb , struct net_device * dev )
2014-10-26 11:37:01 +03:00
{
struct ieee802154_sub_if_data * sdata = IEEE802154_DEV_TO_SUB_IF ( dev ) ;
int rc ;
rc = mac802154_llsec_encrypt ( & sdata - > sec , skb ) ;
if ( rc ) {
2014-10-26 11:37:10 +03:00
netdev_warn ( dev , " encryption failed: %i \n " , rc ) ;
2014-10-26 11:37:01 +03:00
kfree_skb ( skb ) ;
return NETDEV_TX_OK ;
}
skb - > skb_iif = dev - > ifindex ;
2014-10-26 11:37:13 +03:00
return ieee802154_tx ( sdata - > local , skb ) ;
2014-10-26 11:37:01 +03:00
}