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 .
*
* 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>
2014-10-25 09:41:04 +02:00
# include <linux/ieee802154.h>
2012-06-25 23:24:48 +00:00
2014-11-17 08:20:49 +01:00
# include <net/nl802154.h>
2012-06-25 23:24:48 +00:00
# include <net/mac802154.h>
# include <net/ieee802154_netdev.h>
2014-10-25 09:41:02 +02:00
# include <net/cfg802154.h>
2012-06-25 23:24:48 +00:00
2014-10-25 09:41:00 +02:00
# include "ieee802154_i.h"
2014-10-28 18:21:21 +01:00
# include "driver-ops.h"
2012-06-25 23:24:48 +00:00
2015-06-21 16:45:20 +02:00
int mac802154_wpan_update_llsec ( struct net_device * dev )
2014-05-16 17:46:43 +02:00
{
2014-10-25 17:16:40 +02:00
struct ieee802154_sub_if_data * sdata = IEEE802154_DEV_TO_SUB_IF ( dev ) ;
2014-05-16 17:46:43 +02:00
struct ieee802154_mlme_ops * ops = ieee802154_mlme_ops ( dev ) ;
2014-11-09 08:36:45 +01:00
struct wpan_dev * wpan_dev = & sdata - > wpan_dev ;
2014-05-16 17:46:43 +02:00
int rc = 0 ;
if ( ops - > llsec ) {
struct ieee802154_llsec_params params ;
int changed = 0 ;
2014-11-09 08:36:45 +01:00
params . pan_id = wpan_dev - > pan_id ;
2014-05-16 17:46:43 +02:00
changed | = IEEE802154_LLSEC_PARAM_PAN_ID ;
2014-11-09 08:36:45 +01:00
params . hwaddr = wpan_dev - > extended_addr ;
2014-05-16 17:46:43 +02:00
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 )
{
2014-10-25 17:16:40 +02:00
struct ieee802154_sub_if_data * sdata = IEEE802154_DEV_TO_SUB_IF ( dev ) ;
2014-11-09 08:36:45 +01:00
struct wpan_dev * wpan_dev = & sdata - > wpan_dev ;
2012-06-25 23:24:48 +00:00
struct sockaddr_ieee802154 * sa =
( struct sockaddr_ieee802154 * ) & ifr - > ifr_addr ;
int err = - ENOIOCTLCMD ;
2015-05-26 15:06:10 +03:00
if ( cmd ! = SIOCGIFADDR & & cmd ! = SIOCSIFADDR )
return err ;
2015-05-22 17:43:51 +02:00
rtnl_lock ( ) ;
2012-06-25 23:24:48 +00:00
switch ( cmd ) {
case SIOCGIFADDR :
2014-03-14 21:23:59 +01:00
{
u16 pan_id , short_addr ;
2014-11-09 08:36:45 +01:00
pan_id = le16_to_cpu ( wpan_dev - > pan_id ) ;
short_addr = le16_to_cpu ( wpan_dev - > short_addr ) ;
2014-03-14 21:23:59 +01:00
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 :
2014-11-09 08:36:59 +01:00
if ( netif_running ( dev ) ) {
2015-05-22 17:43:51 +02:00
rtnl_unlock ( ) ;
2014-11-09 08:36:59 +01:00
return - EBUSY ;
}
2012-06-25 23:24:48 +00:00
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-11-09 08:36:45 +01:00
wpan_dev - > pan_id = cpu_to_le16 ( sa - > addr . pan_id ) ;
wpan_dev - > 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 ;
}
2015-05-22 17:43:51 +02:00
rtnl_unlock ( ) ;
2012-06-25 23:24:48 +00:00
return err ;
}
static int mac802154_wpan_mac_addr ( struct net_device * dev , void * p )
{
2014-11-02 04:18:41 +01:00
struct ieee802154_sub_if_data * sdata = IEEE802154_DEV_TO_SUB_IF ( dev ) ;
2012-06-25 23:24:48 +00:00
struct sockaddr * addr = p ;
2014-11-02 04:18:46 +01:00
__le64 extended_addr ;
2012-06-25 23:24:48 +00:00
if ( netif_running ( dev ) )
return - EBUSY ;
2015-08-10 21:15:54 +02:00
/* lowpan need to be down for update
* SLAAC address after ifup
*/
if ( sdata - > wpan_dev . lowpan_dev ) {
if ( netif_running ( sdata - > wpan_dev . lowpan_dev ) )
return - EBUSY ;
}
2014-11-05 20:51:24 +01:00
ieee802154_be64_to_le64 ( & extended_addr , addr - > sa_data ) ;
2015-05-28 15:38:43 +03:00
if ( ! ieee802154_is_valid_extended_unicast_addr ( extended_addr ) )
2014-11-02 04:18:46 +01:00
return - EINVAL ;
2012-06-25 23:24:48 +00:00
memcpy ( dev - > dev_addr , addr - > sa_data , dev - > addr_len ) ;
2014-11-09 08:36:45 +01:00
sdata - > wpan_dev . extended_addr = extended_addr ;
2014-11-02 04:18:41 +01:00
2015-08-10 21:15:54 +02:00
/* update lowpan interface mac address when
* wpan mac has been changed
*/
if ( sdata - > wpan_dev . lowpan_dev )
memcpy ( sdata - > wpan_dev . lowpan_dev - > dev_addr , dev - > dev_addr ,
dev - > addr_len ) ;
2014-05-16 17:46:43 +02:00
return mac802154_wpan_update_llsec ( dev ) ;
2012-06-25 23:24:48 +00:00
}
2015-06-17 15:35:17 +02:00
static int ieee802154_setup_hw ( struct ieee802154_sub_if_data * sdata )
{
struct ieee802154_local * local = sdata - > local ;
struct wpan_dev * wpan_dev = & sdata - > wpan_dev ;
int ret ;
if ( local - > hw . flags & IEEE802154_HW_PROMISCUOUS ) {
ret = drv_set_promiscuous_mode ( local ,
wpan_dev - > promiscuous_mode ) ;
if ( ret < 0 )
return ret ;
}
if ( local - > hw . flags & IEEE802154_HW_AFILT ) {
ret = drv_set_pan_id ( local , wpan_dev - > pan_id ) ;
if ( ret < 0 )
return ret ;
ret = drv_set_extended_addr ( local , wpan_dev - > extended_addr ) ;
if ( ret < 0 )
return ret ;
ret = drv_set_short_addr ( local , wpan_dev - > short_addr ) ;
if ( ret < 0 )
return ret ;
}
if ( local - > hw . flags & IEEE802154_HW_LBT ) {
ret = drv_set_lbt_mode ( local , wpan_dev - > lbt ) ;
if ( ret < 0 )
return ret ;
}
if ( local - > hw . flags & IEEE802154_HW_CSMA_PARAMS ) {
ret = drv_set_csma_params ( local , wpan_dev - > min_be ,
wpan_dev - > max_be ,
wpan_dev - > csma_retries ) ;
if ( ret < 0 )
return ret ;
}
if ( local - > hw . flags & IEEE802154_HW_FRAME_RETRIES ) {
ret = drv_set_max_frame_retries ( local , wpan_dev - > frame_retries ) ;
if ( ret < 0 )
return ret ;
}
return 0 ;
}
2014-10-28 18:21:17 +01:00
static int mac802154_slave_open ( struct net_device * dev )
{
struct ieee802154_sub_if_data * sdata = IEEE802154_DEV_TO_SUB_IF ( dev ) ;
struct ieee802154_local * local = sdata - > local ;
2015-06-17 15:35:18 +02:00
int res ;
2014-10-28 18:21:17 +01:00
ASSERT_RTNL ( ) ;
2014-10-28 18:21:24 +01:00
set_bit ( SDATA_STATE_RUNNING , & sdata - > state ) ;
2014-10-28 18:21:17 +01:00
2014-10-28 18:21:31 +01:00
if ( ! local - > open_count ) {
2015-06-17 15:35:17 +02:00
res = ieee802154_setup_hw ( sdata ) ;
if ( res )
goto err ;
2014-10-28 18:21:21 +01:00
res = drv_start ( local ) ;
2014-10-28 18:21:17 +01:00
if ( res )
goto err ;
}
2014-10-28 18:21:31 +01:00
local - > open_count + + ;
2014-10-28 18:21:17 +01:00
netif_start_queue ( dev ) ;
return 0 ;
err :
2014-10-28 18:21:24 +01:00
/* might already be clear but that doesn't matter */
clear_bit ( SDATA_STATE_RUNNING , & sdata - > state ) ;
2014-10-28 18:21:17 +01:00
return res ;
}
2014-12-19 23:45:58 +01:00
static int
ieee802154_check_mac_settings ( struct ieee802154_local * local ,
struct wpan_dev * wpan_dev ,
struct wpan_dev * nwpan_dev )
{
ASSERT_RTNL ( ) ;
if ( local - > hw . flags & IEEE802154_HW_PROMISCUOUS ) {
if ( wpan_dev - > promiscuous_mode ! = nwpan_dev - > promiscuous_mode )
return - EBUSY ;
}
if ( local - > hw . flags & IEEE802154_HW_AFILT ) {
2015-03-26 12:46:28 +01:00
if ( wpan_dev - > pan_id ! = nwpan_dev - > pan_id | |
wpan_dev - > short_addr ! = nwpan_dev - > short_addr | |
wpan_dev - > extended_addr ! = nwpan_dev - > extended_addr )
2014-12-19 23:45:58 +01:00
return - EBUSY ;
}
if ( local - > hw . flags & IEEE802154_HW_CSMA_PARAMS ) {
2015-03-26 12:46:28 +01:00
if ( wpan_dev - > min_be ! = nwpan_dev - > min_be | |
wpan_dev - > max_be ! = nwpan_dev - > max_be | |
wpan_dev - > csma_retries ! = nwpan_dev - > csma_retries )
2014-12-19 23:45:58 +01:00
return - EBUSY ;
}
if ( local - > hw . flags & IEEE802154_HW_FRAME_RETRIES ) {
if ( wpan_dev - > frame_retries ! = nwpan_dev - > frame_retries )
return - EBUSY ;
}
if ( local - > hw . flags & IEEE802154_HW_LBT ) {
if ( wpan_dev - > lbt ! = nwpan_dev - > lbt )
return - EBUSY ;
}
return 0 ;
}
static int
ieee802154_check_concurrent_iface ( struct ieee802154_sub_if_data * sdata ,
enum nl802154_iftype iftype )
{
struct ieee802154_local * local = sdata - > local ;
struct wpan_dev * wpan_dev = & sdata - > wpan_dev ;
struct ieee802154_sub_if_data * nsdata ;
/* we hold the RTNL here so can safely walk the list */
list_for_each_entry ( nsdata , & local - > interfaces , list ) {
if ( nsdata ! = sdata & & ieee802154_sdata_running ( nsdata ) ) {
int ret ;
2014-12-19 23:45:59 +01:00
/* TODO currently we don't support multiple node types
* we need to run skb_clone at rx path . Check if there
* exist really an use case if we need to support
* multiple node types at the same time .
*/
2015-06-06 17:30:46 +02:00
if ( wpan_dev - > iftype = = NL802154_IFTYPE_NODE & &
nsdata - > wpan_dev . iftype = = NL802154_IFTYPE_NODE )
2014-12-19 23:45:59 +01:00
return - EBUSY ;
2014-12-19 23:45:58 +01:00
/* check all phy mac sublayer settings are the same.
* We have only one phy , different values makes trouble .
*/
ret = ieee802154_check_mac_settings ( local , wpan_dev ,
& nsdata - > wpan_dev ) ;
if ( ret < 0 )
return ret ;
}
}
return 0 ;
}
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 ;
2014-10-25 17:16:40 +02:00
struct ieee802154_sub_if_data * sdata = IEEE802154_DEV_TO_SUB_IF ( dev ) ;
2014-11-09 08:36:45 +01:00
struct wpan_dev * wpan_dev = & sdata - > wpan_dev ;
2014-03-31 21:37:46 +02:00
2015-06-06 17:30:46 +02:00
rc = ieee802154_check_concurrent_iface ( sdata , wpan_dev - > iftype ) ;
2014-12-19 23:45:58 +01:00
if ( rc < 0 )
return rc ;
2015-06-17 15:35:17 +02:00
return mac802154_slave_open ( dev ) ;
2014-03-31 21:37:46 +02:00
}
2014-10-28 18:21:17 +01:00
static int mac802154_slave_close ( struct net_device * dev )
{
struct ieee802154_sub_if_data * sdata = IEEE802154_DEV_TO_SUB_IF ( dev ) ;
struct ieee802154_local * local = sdata - > local ;
ASSERT_RTNL ( ) ;
netif_stop_queue ( dev ) ;
2014-10-28 18:21:31 +01:00
local - > open_count - - ;
2014-10-28 18:21:17 +01:00
2014-10-28 18:21:24 +01:00
clear_bit ( SDATA_STATE_RUNNING , & sdata - > state ) ;
2014-10-28 18:21:17 +01:00
2015-06-24 11:36:34 +02:00
if ( ! local - > open_count )
ieee802154_stop_device ( local ) ;
2014-10-28 18:21:17 +01:00
return 0 ;
}
2014-10-25 17:16:36 +02:00
static int mac802154_set_header_security ( struct ieee802154_sub_if_data * sdata ,
2014-05-16 17:46:40 +02:00
struct ieee802154_hdr * hdr ,
const struct ieee802154_mac_cb * cb )
{
struct ieee802154_llsec_params params ;
u8 level ;
2014-10-25 17:16:36 +02:00
mac802154_llsec_get_params ( & sdata - > sec , & params ) ;
2014-05-16 17:46:40 +02:00
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 ;
2014-10-25 17:16:40 +02:00
struct ieee802154_sub_if_data * sdata = IEEE802154_DEV_TO_SUB_IF ( dev ) ;
2014-11-09 08:36:45 +01:00
struct wpan_dev * wpan_dev = & sdata - > wpan_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 ;
2015-05-22 17:43:53 +02:00
hdr . seq = atomic_inc_return ( & dev - > ieee802154_ptr - > dsn ) & 0xFF ;
2012-06-25 23:24:48 +00:00
2014-10-25 17:16:36 +02:00
if ( mac802154_set_header_security ( sdata , & hdr , cb ) < 0 )
2014-05-16 17:46:40 +02:00
return - EINVAL ;
2012-06-25 23:24:48 +00:00
if ( ! saddr ) {
2014-11-09 08:36:45 +01:00
if ( wpan_dev - > short_addr = = cpu_to_le16 ( IEEE802154_ADDR_BROADCAST ) | |
wpan_dev - > short_addr = = cpu_to_le16 ( IEEE802154_ADDR_UNDEF ) | |
wpan_dev - > pan_id = = cpu_to_le16 ( IEEE802154_PANID_BROADCAST ) ) {
2014-03-14 21:24:01 +01:00
hdr . source . mode = IEEE802154_ADDR_LONG ;
2014-11-09 08:36:45 +01:00
hdr . source . extended_addr = wpan_dev - > 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 ;
2014-11-09 08:36:45 +01:00
hdr . source . short_addr = wpan_dev - > short_addr ;
2012-06-25 23:24:48 +00:00
}
2014-11-09 08:36:45 +01:00
hdr . source . pan_id = wpan_dev - > pan_id ;
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 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 ,
2014-10-26 09:37:13 +01:00
. ndo_start_xmit = ieee802154_subif_start_xmit ,
2012-06-25 23:24:48 +00:00
. ndo_do_ioctl = mac802154_wpan_ioctl ,
. ndo_set_mac_address = mac802154_wpan_mac_addr ,
} ;
2014-10-28 18:21:16 +01:00
static const struct net_device_ops mac802154_monitor_ops = {
2014-10-29 21:34:44 +01:00
. ndo_open = mac802154_wpan_open ,
2014-10-28 18:21:16 +01:00
. ndo_stop = mac802154_slave_close ,
. ndo_start_xmit = ieee802154_monitor_start_xmit ,
} ;
2014-05-16 17:46:40 +02:00
static void mac802154_wpan_free ( struct net_device * dev )
{
2014-10-25 17:16:40 +02:00
struct ieee802154_sub_if_data * sdata = IEEE802154_DEV_TO_SUB_IF ( dev ) ;
2014-05-16 17:46:40 +02:00
2014-10-25 17:16:36 +02:00
mac802154_llsec_destroy ( & sdata - > sec ) ;
2014-05-16 17:46:40 +02:00
free_netdev ( dev ) ;
}
2014-11-05 20:51:17 +01:00
static void ieee802154_if_setup ( struct net_device * dev )
2012-06-25 23:24:48 +00:00
{
2014-11-05 20:51:28 +01:00
dev - > addr_len = IEEE802154_EXTENDED_ADDR_LEN ;
memset ( dev - > broadcast , 0xff , IEEE802154_EXTENDED_ADDR_LEN ) ;
2012-06-25 23:24:48 +00:00
dev - > hard_header_len = MAC802154_FRAME_HARD_HEADER_LEN ;
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 - > flags = IFF_NOARP | IFF_BROADCAST ;
2014-11-05 20:51:17 +01:00
}
2012-06-25 23:24:48 +00:00
2014-11-05 20:51:17 +01:00
static int
2014-11-17 08:20:49 +01:00
ieee802154_setup_sdata ( struct ieee802154_sub_if_data * sdata ,
enum nl802154_iftype type )
2014-11-05 20:51:17 +01:00
{
2014-11-09 08:36:45 +01:00
struct wpan_dev * wpan_dev = & sdata - > wpan_dev ;
2015-06-21 16:45:20 +02:00
int ret ;
2015-05-22 17:43:53 +02:00
u8 tmp ;
2014-11-09 08:36:45 +01:00
2014-11-05 20:51:17 +01:00
/* set some type-dependent values */
2014-11-09 08:36:49 +01:00
sdata - > wpan_dev . iftype = type ;
2012-06-25 23:24:48 +00:00
2015-05-22 17:43:53 +02:00
get_random_bytes ( & tmp , sizeof ( tmp ) ) ;
atomic_set ( & wpan_dev - > bsn , tmp ) ;
get_random_bytes ( & tmp , sizeof ( tmp ) ) ;
atomic_set ( & wpan_dev - > dsn , tmp ) ;
2012-06-25 23:24:48 +00:00
2014-03-31 21:37:46 +02:00
/* defaults per 802.15.4-2011 */
2014-11-09 08:36:46 +01:00
wpan_dev - > min_be = 3 ;
wpan_dev - > max_be = 5 ;
wpan_dev - > csma_retries = 4 ;
2015-08-10 21:15:56 +02:00
wpan_dev - > frame_retries = 3 ;
2014-03-31 21:37:46 +02:00
2014-11-09 08:36:45 +01:00
wpan_dev - > pan_id = cpu_to_le16 ( IEEE802154_PANID_BROADCAST ) ;
wpan_dev - > short_addr = cpu_to_le16 ( IEEE802154_ADDR_BROADCAST ) ;
2014-05-16 17:46:40 +02:00
2014-11-05 20:51:17 +01:00
switch ( type ) {
2014-11-17 08:20:49 +01:00
case NL802154_IFTYPE_NODE :
2014-11-09 08:36:56 +01:00
ieee802154_be64_to_le64 ( & wpan_dev - > extended_addr ,
sdata - > dev - > dev_addr ) ;
2014-11-05 20:51:17 +01:00
sdata - > dev - > header_ops = & mac802154_header_ops ;
sdata - > dev - > destructor = mac802154_wpan_free ;
sdata - > dev - > netdev_ops = & mac802154_wpan_ops ;
sdata - > dev - > ml_priv = & mac802154_mlme_wpan ;
2014-11-09 08:36:45 +01:00
wpan_dev - > promiscuous_mode = false ;
2014-11-05 20:51:15 +01:00
2014-11-05 20:51:17 +01:00
mutex_init ( & sdata - > sec_mtx ) ;
2014-11-05 20:51:15 +01:00
2014-11-05 20:51:17 +01:00
mac802154_llsec_init ( & sdata - > sec ) ;
2015-06-21 16:45:20 +02:00
ret = mac802154_wpan_update_llsec ( sdata - > dev ) ;
if ( ret < 0 )
return ret ;
2014-11-05 20:51:17 +01:00
break ;
2014-11-17 08:20:49 +01:00
case NL802154_IFTYPE_MONITOR :
2014-11-05 20:51:17 +01:00
sdata - > dev - > destructor = free_netdev ;
sdata - > dev - > netdev_ops = & mac802154_monitor_ops ;
2014-11-09 08:36:45 +01:00
wpan_dev - > promiscuous_mode = true ;
2014-11-05 20:51:17 +01:00
break ;
default :
BUG ( ) ;
}
2014-11-05 20:51:15 +01:00
return 0 ;
}
struct net_device *
ieee802154_if_add ( struct ieee802154_local * local , const char * name ,
2015-04-30 17:44:57 +02:00
unsigned char name_assign_type , enum nl802154_iftype type ,
__le64 extended_addr )
2014-11-05 20:51:15 +01:00
{
2014-11-05 20:51:17 +01:00
struct net_device * ndev = NULL ;
struct ieee802154_sub_if_data * sdata = NULL ;
int ret = - ENOMEM ;
ASSERT_RTNL ( ) ;
2015-06-06 17:30:46 +02:00
ndev = alloc_netdev ( sizeof ( * sdata ) , name ,
2015-04-30 17:44:57 +02:00
name_assign_type , ieee802154_if_setup ) ;
2014-11-05 20:51:17 +01:00
if ( ! ndev )
return ERR_PTR ( - ENOMEM ) ;
ndev - > needed_headroom = local - > hw . extra_tx_headroom ;
ret = dev_alloc_name ( ndev , ndev - > name ) ;
if ( ret < 0 )
goto err ;
2014-11-05 20:51:15 +01:00
2014-11-17 08:20:52 +01:00
ieee802154_le64_to_be64 ( ndev - > perm_addr ,
& local - > hw . phy - > perm_extended_addr ) ;
2014-11-05 20:51:15 +01:00
switch ( type ) {
2014-11-17 08:20:49 +01:00
case NL802154_IFTYPE_NODE :
2014-11-05 20:51:17 +01:00
ndev - > type = ARPHRD_IEEE802154 ;
2015-05-28 15:38:43 +03:00
if ( ieee802154_is_valid_extended_unicast_addr ( extended_addr ) )
2014-11-17 08:20:52 +01:00
ieee802154_le64_to_be64 ( ndev - > dev_addr , & extended_addr ) ;
else
memcpy ( ndev - > dev_addr , ndev - > perm_addr ,
IEEE802154_EXTENDED_ADDR_LEN ) ;
2014-11-05 20:51:15 +01:00
break ;
2014-11-17 08:20:49 +01:00
case NL802154_IFTYPE_MONITOR :
2014-11-05 20:51:17 +01:00
ndev - > type = ARPHRD_IEEE802154_MONITOR ;
2014-11-05 20:51:15 +01:00
break ;
2014-11-05 20:51:17 +01:00
default :
ret = - EINVAL ;
goto err ;
2014-11-05 20:51:15 +01:00
}
2014-11-05 20:51:17 +01:00
/* TODO check this */
SET_NETDEV_DEV ( ndev , & local - > phy - > dev ) ;
sdata = netdev_priv ( ndev ) ;
ndev - > ieee802154_ptr = & sdata - > wpan_dev ;
memcpy ( sdata - > name , ndev - > name , IFNAMSIZ ) ;
sdata - > dev = ndev ;
sdata - > wpan_dev . wpan_phy = local - > hw . phy ;
sdata - > local = local ;
/* setup type-dependent data */
ret = ieee802154_setup_sdata ( sdata , type ) ;
if ( ret )
2014-11-05 20:51:15 +01:00
goto err ;
2014-11-25 16:34:43 +05:30
ret = register_netdevice ( ndev ) ;
if ( ret < 0 )
goto err ;
2014-11-05 20:51:17 +01:00
mutex_lock ( & local - > iflist_mtx ) ;
list_add_tail_rcu ( & sdata - > list , & local - > interfaces ) ;
mutex_unlock ( & local - > iflist_mtx ) ;
2014-11-05 20:51:15 +01:00
2014-11-05 20:51:17 +01:00
return ndev ;
2014-11-05 20:51:15 +01:00
err :
2014-11-05 20:51:17 +01:00
free_netdev ( ndev ) ;
return ERR_PTR ( ret ) ;
2014-11-05 20:51:15 +01:00
}
2014-11-05 20:51:14 +01:00
void ieee802154_if_remove ( struct ieee802154_sub_if_data * sdata )
{
ASSERT_RTNL ( ) ;
mutex_lock ( & sdata - > local - > iflist_mtx ) ;
list_del_rcu ( & sdata - > list ) ;
mutex_unlock ( & sdata - > local - > iflist_mtx ) ;
synchronize_rcu ( ) ;
unregister_netdevice ( sdata - > dev ) ;
}
2014-11-12 03:36:48 +01:00
void ieee802154_remove_interfaces ( struct ieee802154_local * local )
{
2014-11-12 03:36:49 +01:00
struct ieee802154_sub_if_data * sdata , * tmp ;
2014-11-12 03:36:48 +01:00
2014-11-12 03:36:50 +01:00
mutex_lock ( & local - > iflist_mtx ) ;
2014-11-12 03:36:49 +01:00
list_for_each_entry_safe ( sdata , tmp , & local - > interfaces , list ) {
2014-11-12 03:36:48 +01:00
list_del ( & sdata - > list ) ;
unregister_netdevice ( sdata - > dev ) ;
}
2014-11-12 03:36:50 +01:00
mutex_unlock ( & local - > iflist_mtx ) ;
2014-11-12 03:36:48 +01:00
}
2014-11-12 03:36:53 +01:00
static int netdev_notify ( struct notifier_block * nb ,
unsigned long state , void * ptr )
{
struct net_device * dev = netdev_notifier_info_to_dev ( ptr ) ;
struct ieee802154_sub_if_data * sdata ;
if ( state ! = NETDEV_CHANGENAME )
return NOTIFY_DONE ;
if ( ! dev - > ieee802154_ptr | | ! dev - > ieee802154_ptr - > wpan_phy )
return NOTIFY_DONE ;
if ( dev - > ieee802154_ptr - > wpan_phy - > privid ! = mac802154_wpan_phy_privid )
return NOTIFY_DONE ;
sdata = IEEE802154_DEV_TO_SUB_IF ( dev ) ;
memcpy ( sdata - > name , dev - > name , IFNAMSIZ ) ;
return NOTIFY_OK ;
}
static struct notifier_block mac802154_netdev_notifier = {
. notifier_call = netdev_notify ,
} ;
int ieee802154_iface_init ( void )
{
return register_netdevice_notifier ( & mac802154_netdev_notifier ) ;
}
void ieee802154_iface_exit ( void )
{
unregister_netdevice_notifier ( & mac802154_netdev_notifier ) ;
}