2012-06-25 23:24:48 +00: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 .
*
* You should have received a copy of the GNU General Public License along
* with this program ; if not , write to the Free Software Foundation , Inc . ,
* 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA .
*
* 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/module.h>
# include <linux/if_arp.h>
# include <net/rtnetlink.h>
# include <linux/nl802154.h>
# include <net/af_ieee802154.h>
# include <net/mac802154.h>
# include <net/ieee802154_netdev.h>
# include <net/ieee802154.h>
# include <net/wpan-phy.h>
# include "mac802154.h"
2014-05-16 17:46:43 +02:00
static int mac802154_wpan_update_llsec ( struct net_device * dev )
{
struct mac802154_sub_if_data * priv = netdev_priv ( dev ) ;
struct ieee802154_mlme_ops * ops = ieee802154_mlme_ops ( dev ) ;
int rc = 0 ;
if ( ops - > llsec ) {
struct ieee802154_llsec_params params ;
int changed = 0 ;
params . pan_id = priv - > pan_id ;
changed | = IEEE802154_LLSEC_PARAM_PAN_ID ;
params . hwaddr = priv - > extended_addr ;
changed | = IEEE802154_LLSEC_PARAM_HWADDR ;
rc = ops - > llsec - > set_params ( dev , & params , changed ) ;
}
return rc ;
}
2012-06-25 23:24:48 +00:00
static int
mac802154_wpan_ioctl ( struct net_device * dev , struct ifreq * ifr , int cmd )
{
struct mac802154_sub_if_data * priv = netdev_priv ( dev ) ;
struct sockaddr_ieee802154 * sa =
( struct sockaddr_ieee802154 * ) & ifr - > ifr_addr ;
int err = - ENOIOCTLCMD ;
spin_lock_bh ( & priv - > mib_lock ) ;
switch ( cmd ) {
case SIOCGIFADDR :
2014-03-14 21:23:59 +01:00
{
u16 pan_id , short_addr ;
pan_id = le16_to_cpu ( priv - > pan_id ) ;
short_addr = le16_to_cpu ( priv - > short_addr ) ;
if ( pan_id = = IEEE802154_PANID_BROADCAST | |
short_addr = = IEEE802154_ADDR_BROADCAST ) {
2012-06-25 23:24:48 +00:00
err = - EADDRNOTAVAIL ;
break ;
}
sa - > family = AF_IEEE802154 ;
sa - > addr . addr_type = IEEE802154_ADDR_SHORT ;
2014-03-14 21:23:59 +01:00
sa - > addr . pan_id = pan_id ;
sa - > addr . short_addr = short_addr ;
2012-06-25 23:24:48 +00:00
err = 0 ;
break ;
2014-03-14 21:23:59 +01:00
}
2012-06-25 23:24:48 +00:00
case SIOCSIFADDR :
dev_warn ( & dev - > dev ,
2014-08-06 22:31:28 +09:00
" Using DEBUGing ioctl SIOCSIFADDR isn't recommended! \n " ) ;
2012-06-25 23:24:48 +00:00
if ( sa - > family ! = AF_IEEE802154 | |
sa - > addr . addr_type ! = IEEE802154_ADDR_SHORT | |
sa - > addr . pan_id = = IEEE802154_PANID_BROADCAST | |
sa - > addr . short_addr = = IEEE802154_ADDR_BROADCAST | |
sa - > addr . short_addr = = IEEE802154_ADDR_UNDEF ) {
err = - EINVAL ;
break ;
}
2014-03-14 21:23:59 +01:00
priv - > pan_id = cpu_to_le16 ( sa - > addr . pan_id ) ;
priv - > short_addr = cpu_to_le16 ( sa - > addr . short_addr ) ;
2012-06-25 23:24:48 +00:00
2014-05-16 17:46:43 +02:00
err = mac802154_wpan_update_llsec ( dev ) ;
2012-06-25 23:24:48 +00:00
break ;
}
spin_unlock_bh ( & priv - > mib_lock ) ;
return err ;
}
static int mac802154_wpan_mac_addr ( struct net_device * dev , void * p )
{
struct sockaddr * addr = p ;
if ( netif_running ( dev ) )
return - EBUSY ;
/* FIXME: validate addr */
memcpy ( dev - > dev_addr , addr - > sa_data , dev - > addr_len ) ;
mac802154_dev_set_ieee_addr ( dev ) ;
2014-05-16 17:46:43 +02:00
return mac802154_wpan_update_llsec ( dev ) ;
2012-06-25 23:24:48 +00:00
}
2014-03-31 21:37:46 +02:00
int mac802154_set_mac_params ( struct net_device * dev ,
const struct ieee802154_mac_params * params )
{
struct mac802154_sub_if_data * priv = netdev_priv ( dev ) ;
mutex_lock ( & priv - > hw - > slaves_mtx ) ;
priv - > mac_params = * params ;
mutex_unlock ( & priv - > hw - > slaves_mtx ) ;
return 0 ;
}
void mac802154_get_mac_params ( struct net_device * dev ,
struct ieee802154_mac_params * params )
{
struct mac802154_sub_if_data * priv = netdev_priv ( dev ) ;
mutex_lock ( & priv - > hw - > slaves_mtx ) ;
* params = priv - > mac_params ;
mutex_unlock ( & priv - > hw - > slaves_mtx ) ;
}
2014-05-14 17:43:11 +02:00
static int mac802154_wpan_open ( struct net_device * dev )
2014-03-31 21:37:46 +02:00
{
int rc ;
struct mac802154_sub_if_data * priv = netdev_priv ( dev ) ;
struct wpan_phy * phy = priv - > hw - > phy ;
rc = mac802154_slave_open ( dev ) ;
if ( rc < 0 )
return rc ;
mutex_lock ( & phy - > pib_lock ) ;
if ( phy - > set_txpower ) {
rc = phy - > set_txpower ( phy , priv - > mac_params . transmit_power ) ;
if ( rc < 0 )
goto out ;
}
if ( phy - > set_lbt ) {
rc = phy - > set_lbt ( phy , priv - > mac_params . lbt ) ;
if ( rc < 0 )
goto out ;
}
if ( phy - > set_cca_mode ) {
rc = phy - > set_cca_mode ( phy , priv - > mac_params . cca_mode ) ;
if ( rc < 0 )
goto out ;
}
if ( phy - > set_cca_ed_level ) {
rc = phy - > set_cca_ed_level ( phy , priv - > mac_params . cca_ed_level ) ;
if ( rc < 0 )
goto out ;
}
if ( phy - > set_csma_params ) {
rc = phy - > set_csma_params ( phy , priv - > mac_params . min_be ,
priv - > mac_params . max_be ,
priv - > mac_params . csma_retries ) ;
if ( rc < 0 )
goto out ;
}
if ( phy - > set_frame_retries ) {
rc = phy - > set_frame_retries ( phy ,
priv - > mac_params . frame_retries ) ;
if ( rc < 0 )
goto out ;
}
mutex_unlock ( & phy - > pib_lock ) ;
return 0 ;
out :
mutex_unlock ( & phy - > pib_lock ) ;
return rc ;
}
2014-05-16 17:46:40 +02:00
static int mac802154_set_header_security ( struct mac802154_sub_if_data * priv ,
struct ieee802154_hdr * hdr ,
const struct ieee802154_mac_cb * cb )
{
struct ieee802154_llsec_params params ;
u8 level ;
mac802154_llsec_get_params ( & priv - > sec , & params ) ;
if ( ! params . enabled & & cb - > secen_override & & cb - > secen )
return - EINVAL ;
if ( ! params . enabled | |
( cb - > secen_override & & ! cb - > secen ) | |
! params . out_level )
return 0 ;
if ( cb - > seclevel_override & & ! cb - > seclevel )
return - EINVAL ;
level = cb - > seclevel_override ? cb - > seclevel : params . out_level ;
hdr - > fc . security_enabled = 1 ;
hdr - > sec . level = level ;
hdr - > sec . key_id_mode = params . out_key . mode ;
if ( params . out_key . mode = = IEEE802154_SCF_KEY_SHORT_INDEX )
hdr - > sec . short_src = params . out_key . short_source ;
else if ( params . out_key . mode = = IEEE802154_SCF_KEY_HW_INDEX )
hdr - > sec . extended_src = params . out_key . extended_source ;
hdr - > sec . key_id = params . out_key . id ;
return 0 ;
}
2012-06-25 23:24:48 +00:00
static int mac802154_header_create ( struct sk_buff * skb ,
struct net_device * dev ,
unsigned short type ,
2014-03-14 21:24:01 +01:00
const void * daddr ,
const void * saddr ,
2012-06-25 23:24:48 +00:00
unsigned len )
{
2014-03-14 21:24:01 +01:00
struct ieee802154_hdr hdr ;
2012-06-25 23:24:48 +00:00
struct mac802154_sub_if_data * priv = netdev_priv ( dev ) ;
2014-05-14 17:43:08 +02:00
struct ieee802154_mac_cb * cb = mac_cb ( skb ) ;
2014-03-14 21:24:01 +01:00
int hlen ;
2012-06-25 23:24:48 +00:00
if ( ! daddr )
return - EINVAL ;
2014-03-14 21:24:01 +01:00
memset ( & hdr . fc , 0 , sizeof ( hdr . fc ) ) ;
2014-05-14 17:43:08 +02:00
hdr . fc . type = cb - > type ;
hdr . fc . security_enabled = cb - > secen ;
hdr . fc . ack_request = cb - > ackreq ;
hdr . seq = ieee802154_mlme_ops ( dev ) - > get_dsn ( dev ) ;
2012-06-25 23:24:48 +00:00
2014-05-16 17:46:40 +02:00
if ( mac802154_set_header_security ( priv , & hdr , cb ) < 0 )
return - EINVAL ;
2012-06-25 23:24:48 +00:00
if ( ! saddr ) {
spin_lock_bh ( & priv - > mib_lock ) ;
2014-03-14 21:23:59 +01:00
if ( priv - > short_addr = = cpu_to_le16 ( IEEE802154_ADDR_BROADCAST ) | |
priv - > short_addr = = cpu_to_le16 ( IEEE802154_ADDR_UNDEF ) | |
priv - > pan_id = = cpu_to_le16 ( IEEE802154_PANID_BROADCAST ) ) {
2014-03-14 21:24:01 +01:00
hdr . source . mode = IEEE802154_ADDR_LONG ;
hdr . source . extended_addr = priv - > extended_addr ;
2012-06-25 23:24:48 +00:00
} else {
2014-03-14 21:24:01 +01:00
hdr . source . mode = IEEE802154_ADDR_SHORT ;
hdr . source . short_addr = priv - > short_addr ;
2012-06-25 23:24:48 +00:00
}
2014-03-14 21:24:01 +01:00
hdr . source . pan_id = priv - > pan_id ;
2012-06-25 23:24:48 +00:00
spin_unlock_bh ( & priv - > mib_lock ) ;
2014-03-14 21:24:01 +01:00
} else {
hdr . source = * ( const struct ieee802154_addr * ) saddr ;
2012-06-25 23:24:48 +00:00
}
2014-03-14 21:24:01 +01:00
hdr . dest = * ( const struct ieee802154_addr * ) daddr ;
2012-06-25 23:24:48 +00:00
2014-03-14 21:24:01 +01:00
hlen = ieee802154_hdr_push ( skb , & hdr ) ;
if ( hlen < 0 )
return - EINVAL ;
2012-06-25 23:24:48 +00:00
2013-10-30 09:18:22 +01:00
skb_reset_mac_header ( skb ) ;
2014-03-14 21:24:01 +01:00
skb - > mac_len = hlen ;
2012-06-25 23:24:48 +00:00
2014-05-14 17:43:07 +02:00
if ( len > ieee802154_max_payload ( & hdr ) )
2014-03-14 21:24:04 +01:00
return - EMSGSIZE ;
2014-03-14 21:24:01 +01:00
return hlen ;
2012-06-25 23:24:48 +00:00
}
static int
mac802154_header_parse ( const struct sk_buff * skb , unsigned char * haddr )
{
2014-03-14 21:24:01 +01:00
struct ieee802154_hdr hdr ;
struct ieee802154_addr * addr = ( struct ieee802154_addr * ) haddr ;
2012-06-25 23:24:48 +00:00
2014-03-14 21:24:01 +01:00
if ( ieee802154_hdr_peek_addrs ( skb , & hdr ) < 0 ) {
pr_debug ( " malformed packet \n " ) ;
return 0 ;
2012-06-25 23:24:48 +00:00
}
2014-03-14 21:24:01 +01:00
* addr = hdr . source ;
return sizeof ( * addr ) ;
2012-06-25 23:24:48 +00:00
}
static netdev_tx_t
mac802154_wpan_xmit ( struct sk_buff * skb , struct net_device * dev )
{
struct mac802154_sub_if_data * priv ;
u8 chan , page ;
2014-05-16 17:46:40 +02:00
int rc ;
2012-06-25 23:24:48 +00:00
priv = netdev_priv ( dev ) ;
spin_lock_bh ( & priv - > mib_lock ) ;
chan = priv - > chan ;
page = priv - > page ;
spin_unlock_bh ( & priv - > mib_lock ) ;
if ( chan = = MAC802154_CHAN_NONE | |
page > = WPAN_NUM_PAGES | |
2012-11-29 18:25:10 +00:00
chan > = WPAN_NUM_CHANNELS ) {
kfree_skb ( skb ) ;
2012-06-25 23:24:48 +00:00
return NETDEV_TX_OK ;
2012-11-29 18:25:10 +00:00
}
2012-06-25 23:24:48 +00:00
2014-05-16 17:46:40 +02:00
rc = mac802154_llsec_encrypt ( & priv - > sec , skb ) ;
if ( rc ) {
pr_warn ( " encryption failed: %i \n " , rc ) ;
kfree_skb ( skb ) ;
return NETDEV_TX_OK ;
}
2012-06-25 23:24:48 +00:00
skb - > skb_iif = dev - > ifindex ;
dev - > stats . tx_packets + + ;
dev - > stats . tx_bytes + = skb - > len ;
return mac802154_tx ( priv - > hw , skb , page , chan ) ;
}
static struct header_ops mac802154_header_ops = {
. create = mac802154_header_create ,
. parse = mac802154_header_parse ,
} ;
static const struct net_device_ops mac802154_wpan_ops = {
2014-03-31 21:37:46 +02:00
. ndo_open = mac802154_wpan_open ,
2012-06-25 23:24:48 +00:00
. ndo_stop = mac802154_slave_close ,
. ndo_start_xmit = mac802154_wpan_xmit ,
. ndo_do_ioctl = mac802154_wpan_ioctl ,
. ndo_set_mac_address = mac802154_wpan_mac_addr ,
} ;
2014-05-16 17:46:40 +02:00
static void mac802154_wpan_free ( struct net_device * dev )
{
struct mac802154_sub_if_data * priv = netdev_priv ( dev ) ;
mac802154_llsec_destroy ( & priv - > sec ) ;
free_netdev ( dev ) ;
}
2012-06-25 23:24:48 +00:00
void mac802154_wpan_setup ( struct net_device * dev )
{
struct mac802154_sub_if_data * priv ;
dev - > addr_len = IEEE802154_ADDR_LEN ;
memset ( dev - > broadcast , 0xff , IEEE802154_ADDR_LEN ) ;
dev - > hard_header_len = MAC802154_FRAME_HARD_HEADER_LEN ;
dev - > header_ops = & mac802154_header_ops ;
2014-05-16 17:46:40 +02:00
dev - > needed_tailroom = 2 + 16 ; /* FCS + MIC */
2012-06-25 23:24:48 +00:00
dev - > mtu = IEEE802154_MTU ;
2013-04-03 04:00:57 +00:00
dev - > tx_queue_len = 300 ;
2012-06-25 23:24:48 +00:00
dev - > type = ARPHRD_IEEE802154 ;
dev - > flags = IFF_NOARP | IFF_BROADCAST ;
dev - > watchdog_timeo = 0 ;
2014-05-16 17:46:40 +02:00
dev - > destructor = mac802154_wpan_free ;
2012-06-25 23:24:48 +00:00
dev - > netdev_ops = & mac802154_wpan_ops ;
dev - > ml_priv = & mac802154_mlme_wpan ;
priv = netdev_priv ( dev ) ;
priv - > type = IEEE802154_DEV_WPAN ;
priv - > chan = MAC802154_CHAN_NONE ;
priv - > page = 0 ;
spin_lock_init ( & priv - > mib_lock ) ;
2014-05-16 17:46:40 +02:00
mutex_init ( & priv - > sec_mtx ) ;
2012-06-25 23:24:48 +00:00
get_random_bytes ( & priv - > bsn , 1 ) ;
get_random_bytes ( & priv - > dsn , 1 ) ;
2014-03-31 21:37:46 +02:00
/* defaults per 802.15.4-2011 */
priv - > mac_params . min_be = 3 ;
priv - > mac_params . max_be = 5 ;
priv - > mac_params . csma_retries = 4 ;
priv - > mac_params . frame_retries = - 1 ; /* for compatibility, actual default is 3 */
2014-03-14 21:23:59 +01:00
priv - > pan_id = cpu_to_le16 ( IEEE802154_PANID_BROADCAST ) ;
priv - > short_addr = cpu_to_le16 ( IEEE802154_ADDR_BROADCAST ) ;
2014-05-16 17:46:40 +02:00
mac802154_llsec_init ( & priv - > sec ) ;
2012-06-25 23:24:48 +00:00
}
static int mac802154_process_data ( struct net_device * dev , struct sk_buff * skb )
{
2013-01-02 01:01:10 +00:00
return netif_rx_ni ( skb ) ;
2012-06-25 23:24:48 +00:00
}
static int
2014-05-16 17:46:40 +02:00
mac802154_subif_frame ( struct mac802154_sub_if_data * sdata , struct sk_buff * skb ,
const struct ieee802154_hdr * hdr )
2012-06-25 23:24:48 +00:00
{
2014-03-14 21:24:02 +01:00
__le16 span , sshort ;
2014-05-16 17:46:40 +02:00
int rc ;
2014-03-14 21:23:59 +01:00
2012-06-25 23:24:48 +00:00
pr_debug ( " getting packet via slave interface %s \n " , sdata - > dev - > name ) ;
spin_lock_bh ( & sdata - > mib_lock ) ;
2014-03-14 21:24:02 +01:00
span = sdata - > pan_id ;
sshort = sdata - > short_addr ;
2014-03-14 21:23:59 +01:00
2014-03-14 21:24:02 +01:00
switch ( mac_cb ( skb ) - > dest . mode ) {
2012-06-25 23:24:48 +00:00
case IEEE802154_ADDR_NONE :
2014-03-14 21:24:02 +01:00
if ( mac_cb ( skb ) - > dest . mode ! = IEEE802154_ADDR_NONE )
2012-06-25 23:24:48 +00:00
/* FIXME: check if we are PAN coordinator */
skb - > pkt_type = PACKET_OTHERHOST ;
else
/* ACK comes with both addresses empty */
skb - > pkt_type = PACKET_HOST ;
break ;
case IEEE802154_ADDR_LONG :
2014-03-14 21:24:02 +01:00
if ( mac_cb ( skb ) - > dest . pan_id ! = span & &
mac_cb ( skb ) - > dest . pan_id ! = cpu_to_le16 ( IEEE802154_PANID_BROADCAST ) )
2012-06-25 23:24:48 +00:00
skb - > pkt_type = PACKET_OTHERHOST ;
2014-03-14 21:24:02 +01:00
else if ( mac_cb ( skb ) - > dest . extended_addr = = sdata - > extended_addr )
2012-06-25 23:24:48 +00:00
skb - > pkt_type = PACKET_HOST ;
else
skb - > pkt_type = PACKET_OTHERHOST ;
break ;
case IEEE802154_ADDR_SHORT :
2014-03-14 21:24:02 +01:00
if ( mac_cb ( skb ) - > dest . pan_id ! = span & &
mac_cb ( skb ) - > dest . pan_id ! = cpu_to_le16 ( IEEE802154_PANID_BROADCAST ) )
2012-06-25 23:24:48 +00:00
skb - > pkt_type = PACKET_OTHERHOST ;
2014-03-14 21:24:02 +01:00
else if ( mac_cb ( skb ) - > dest . short_addr = = sshort )
2012-06-25 23:24:48 +00:00
skb - > pkt_type = PACKET_HOST ;
2014-03-14 21:24:02 +01:00
else if ( mac_cb ( skb ) - > dest . short_addr = =
cpu_to_le16 ( IEEE802154_ADDR_BROADCAST ) )
2012-06-25 23:24:48 +00:00
skb - > pkt_type = PACKET_BROADCAST ;
else
skb - > pkt_type = PACKET_OTHERHOST ;
break ;
default :
2014-08-19 19:03:30 +02:00
spin_unlock_bh ( & sdata - > mib_lock ) ;
pr_debug ( " invalid dest mode \n " ) ;
kfree_skb ( skb ) ;
return NET_RX_DROP ;
2012-06-25 23:24:48 +00:00
}
spin_unlock_bh ( & sdata - > mib_lock ) ;
skb - > dev = sdata - > dev ;
2014-05-16 17:46:40 +02:00
rc = mac802154_llsec_decrypt ( & sdata - > sec , skb ) ;
if ( rc ) {
pr_debug ( " decryption failed: %i \n " , rc ) ;
2014-08-11 13:25:08 +02:00
goto fail ;
2014-05-16 17:46:40 +02:00
}
2012-06-25 23:24:48 +00:00
sdata - > dev - > stats . rx_packets + + ;
sdata - > dev - > stats . rx_bytes + = skb - > len ;
2014-05-14 17:43:08 +02:00
switch ( mac_cb ( skb ) - > type ) {
2012-06-25 23:24:48 +00:00
case IEEE802154_FC_TYPE_DATA :
return mac802154_process_data ( sdata - > dev , skb ) ;
default :
2013-12-19 09:22:26 +08:00
pr_warn ( " ieee802154: bad frame received (type = %d) \n " ,
2014-05-14 17:43:08 +02:00
mac_cb ( skb ) - > type ) ;
2014-08-11 13:25:08 +02:00
goto fail ;
2012-06-25 23:24:48 +00:00
}
2014-08-11 13:25:08 +02:00
fail :
kfree_skb ( skb ) ;
return NET_RX_DROP ;
2012-06-25 23:24:48 +00:00
}
2014-03-14 21:24:01 +01:00
static void mac802154_print_addr ( const char * name ,
const struct ieee802154_addr * addr )
2012-06-25 23:24:48 +00:00
{
2014-03-14 21:24:01 +01:00
if ( addr - > mode = = IEEE802154_ADDR_NONE )
pr_debug ( " %s not present \n " , name ) ;
2012-06-25 23:24:48 +00:00
2014-03-14 21:24:01 +01:00
pr_debug ( " %s PAN ID: %04x \n " , name , le16_to_cpu ( addr - > pan_id ) ) ;
if ( addr - > mode = = IEEE802154_ADDR_SHORT ) {
pr_debug ( " %s is short: %04x \n " , name ,
le16_to_cpu ( addr - > short_addr ) ) ;
} else {
u64 hw = swab64 ( ( __force u64 ) addr - > extended_addr ) ;
2012-06-25 23:24:48 +00:00
2014-03-14 21:24:01 +01:00
pr_debug ( " %s is hardware: %8phC \n " , name , & hw ) ;
}
}
2012-06-25 23:24:48 +00:00
2014-05-16 17:46:40 +02:00
static int mac802154_parse_frame_start ( struct sk_buff * skb ,
struct ieee802154_hdr * hdr )
2014-03-14 21:24:01 +01:00
{
int hlen ;
2014-05-14 17:43:08 +02:00
struct ieee802154_mac_cb * cb = mac_cb_init ( skb ) ;
2012-06-25 23:24:48 +00:00
2014-05-16 17:46:40 +02:00
hlen = ieee802154_hdr_pull ( skb , hdr ) ;
2014-03-14 21:24:01 +01:00
if ( hlen < 0 )
return - EINVAL ;
2012-06-25 23:24:48 +00:00
2014-03-14 21:24:01 +01:00
skb - > mac_len = hlen ;
2012-06-25 23:24:48 +00:00
2014-05-16 17:46:40 +02:00
pr_debug ( " fc: %04x dsn: %02x \n " , le16_to_cpup ( ( __le16 * ) & hdr - > fc ) ,
hdr - > seq ) ;
2012-06-25 23:24:48 +00:00
2014-05-16 17:46:40 +02:00
cb - > type = hdr - > fc . type ;
cb - > ackreq = hdr - > fc . ack_request ;
cb - > secen = hdr - > fc . security_enabled ;
2012-06-25 23:24:48 +00:00
2014-05-16 17:46:40 +02:00
mac802154_print_addr ( " destination " , & hdr - > dest ) ;
mac802154_print_addr ( " source " , & hdr - > source ) ;
2012-06-25 23:24:48 +00:00
2014-05-16 17:46:40 +02:00
cb - > source = hdr - > source ;
cb - > dest = hdr - > dest ;
2014-03-14 21:24:02 +01:00
2014-05-16 17:46:40 +02:00
if ( hdr - > fc . security_enabled ) {
2014-03-14 21:24:01 +01:00
u64 key ;
2012-06-25 23:24:48 +00:00
2014-05-16 17:46:40 +02:00
pr_debug ( " seclevel %i \n " , hdr - > sec . level ) ;
2012-06-25 23:24:48 +00:00
2014-05-16 17:46:40 +02:00
switch ( hdr - > sec . key_id_mode ) {
2014-03-14 21:24:01 +01:00
case IEEE802154_SCF_KEY_IMPLICIT :
pr_debug ( " implicit key \n " ) ;
break ;
2012-06-25 23:24:48 +00:00
2014-03-14 21:24:01 +01:00
case IEEE802154_SCF_KEY_INDEX :
2014-05-16 17:46:40 +02:00
pr_debug ( " key %02x \n " , hdr - > sec . key_id ) ;
2014-03-14 21:24:01 +01:00
break ;
2012-06-25 23:24:48 +00:00
2014-03-14 21:24:01 +01:00
case IEEE802154_SCF_KEY_SHORT_INDEX :
pr_debug ( " key %04x:%04x %02x \n " ,
2014-05-16 17:46:40 +02:00
le32_to_cpu ( hdr - > sec . short_src ) > > 16 ,
le32_to_cpu ( hdr - > sec . short_src ) & 0xffff ,
hdr - > sec . key_id ) ;
2014-03-14 21:24:01 +01:00
break ;
2012-06-25 23:24:48 +00:00
2014-03-14 21:24:01 +01:00
case IEEE802154_SCF_KEY_HW_INDEX :
2014-05-16 17:46:40 +02:00
key = swab64 ( ( __force u64 ) hdr - > sec . extended_src ) ;
2014-03-14 21:24:01 +01:00
pr_debug ( " key source %8phC %02x \n " , & key ,
2014-05-16 17:46:40 +02:00
hdr - > sec . key_id ) ;
2014-03-14 21:24:01 +01:00
break ;
2012-06-25 23:24:48 +00:00
}
}
return 0 ;
}
void mac802154_wpans_rx ( struct mac802154_priv * priv , struct sk_buff * skb )
{
int ret ;
struct mac802154_sub_if_data * sdata ;
2014-05-16 17:46:40 +02:00
struct ieee802154_hdr hdr ;
2012-06-25 23:24:48 +00:00
2014-05-16 17:46:40 +02:00
ret = mac802154_parse_frame_start ( skb , & hdr ) ;
2012-06-25 23:24:48 +00:00
if ( ret ) {
pr_debug ( " got invalid frame \n " ) ;
2014-08-19 19:03:28 +02:00
kfree_skb ( skb ) ;
2012-06-25 23:24:48 +00:00
return ;
}
rcu_read_lock ( ) ;
list_for_each_entry_rcu ( sdata , & priv - > slaves , list ) {
2014-06-11 12:03:07 +02:00
if ( sdata - > type ! = IEEE802154_DEV_WPAN | |
! netif_running ( sdata - > dev ) )
2012-06-25 23:24:48 +00:00
continue ;
2014-06-11 12:03:07 +02:00
mac802154_subif_frame ( sdata , skb , & hdr ) ;
skb = NULL ;
break ;
2012-06-25 23:24:48 +00:00
}
rcu_read_unlock ( ) ;
2014-06-11 12:03:07 +02:00
if ( skb )
kfree_skb ( skb ) ;
2012-06-25 23:24:48 +00:00
}