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
2015-07-21 17:44:47 +03:00
void ieee802154_xmit_worker ( struct work_struct * work )
2012-05-16 00:50:22 +04:00
{
2015-07-21 17:44:47 +03:00
struct ieee802154_local * local =
container_of ( work , struct ieee802154_local , tx_work ) ;
struct sk_buff * skb = local - > tx_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 ;
2014-11-12 21:51:56 +03:00
ieee802154_xmit_complete ( & local - > hw , skb , false ) ;
2014-10-26 11:37:09 +03:00
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
2015-09-18 12:30:44 +03:00
/* This check is for AF_PACKET RAW socket only, which doesn't
* know about the FCS which is set here or by hardware . otherwise
* it should not occur in any case !
*
* TODO : This should be handled in AF_PACKET and return - EMSGSIZE .
*/
if ( skb - > len > IEEE802154_MTU - IEEE802154_FCS_LEN ) {
netdev_warn ( dev , " Frame len above MTU limit. Dropped. \n " ) ;
goto err_tx ;
}
2014-10-29 23:34:34 +03:00
if ( ! ( local - > hw . flags & IEEE802154_HW_TX_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
}
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 {
2015-07-21 17:44:47 +03:00
local - > tx_skb = skb ;
queue_work ( local - > workqueue , & local - > tx_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
}