2015-08-11 22:44:08 +03:00
/* 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 .
*
* Authors :
* ( C ) 2015 Pengutronix , Alexander Aring < aar @ pengutronix . de >
*/
2015-08-11 22:44:09 +03:00
# include <linux/module.h>
2015-08-11 22:44:08 +03:00
# include <net/6lowpan.h>
2016-06-15 22:20:17 +03:00
# include <net/addrconf.h>
2015-08-11 22:44:08 +03:00
2015-12-10 00:46:30 +03:00
# include "6lowpan_i.h"
2015-12-10 00:46:29 +03:00
int lowpan_register_netdevice ( struct net_device * dev ,
enum lowpan_lltypes lltype )
2015-08-11 22:44:08 +03:00
{
2016-02-22 11:13:54 +03:00
int i , ret ;
2015-12-10 00:46:30 +03:00
2017-03-12 11:19:34 +03:00
switch ( lltype ) {
case LOWPAN_LLTYPE_IEEE802154 :
dev - > addr_len = EUI64_ADDR_LEN ;
break ;
case LOWPAN_LLTYPE_BTLE :
dev - > addr_len = ETH_ALEN ;
break ;
}
2015-10-02 21:28:04 +03:00
dev - > type = ARPHRD_6LOWPAN ;
dev - > mtu = IPV6_MIN_MTU ;
2016-04-11 12:04:18 +03:00
lowpan_dev ( dev ) - > lltype = lltype ;
2015-12-10 00:46:29 +03:00
2016-04-11 12:04:18 +03:00
spin_lock_init ( & lowpan_dev ( dev ) - > ctx . lock ) ;
2016-02-22 11:13:54 +03:00
for ( i = 0 ; i < LOWPAN_IPHC_CTX_TABLE_SIZE ; i + + )
2016-04-11 12:04:18 +03:00
lowpan_dev ( dev ) - > ctx . table [ i ] . id = i ;
2016-02-22 11:13:54 +03:00
2016-06-15 22:20:25 +03:00
dev - > ndisc_ops = & lowpan_ndisc_ops ;
2015-12-15 14:25:35 +03:00
ret = register_netdevice ( dev ) ;
2015-12-10 00:46:30 +03:00
if ( ret < 0 )
return ret ;
2015-12-15 14:25:35 +03:00
ret = lowpan_dev_debugfs_init ( dev ) ;
2015-12-10 00:46:30 +03:00
if ( ret < 0 )
2015-12-15 14:25:35 +03:00
unregister_netdevice ( dev ) ;
2015-12-10 00:46:30 +03:00
return ret ;
2015-12-10 00:46:29 +03:00
}
EXPORT_SYMBOL ( lowpan_register_netdevice ) ;
int lowpan_register_netdev ( struct net_device * dev ,
enum lowpan_lltypes lltype )
{
int ret ;
rtnl_lock ( ) ;
ret = lowpan_register_netdevice ( dev , lltype ) ;
rtnl_unlock ( ) ;
return ret ;
}
EXPORT_SYMBOL ( lowpan_register_netdev ) ;
void lowpan_unregister_netdevice ( struct net_device * dev )
{
unregister_netdevice ( dev ) ;
2015-12-10 00:46:30 +03:00
lowpan_dev_debugfs_exit ( dev ) ;
2015-12-10 00:46:29 +03:00
}
EXPORT_SYMBOL ( lowpan_unregister_netdevice ) ;
void lowpan_unregister_netdev ( struct net_device * dev )
{
rtnl_lock ( ) ;
lowpan_unregister_netdevice ( dev ) ;
rtnl_unlock ( ) ;
2015-08-11 22:44:08 +03:00
}
2015-12-10 00:46:29 +03:00
EXPORT_SYMBOL ( lowpan_unregister_netdev ) ;
2015-08-11 22:44:09 +03:00
2016-06-15 22:20:25 +03:00
int addrconf_ifid_802154_6lowpan ( u8 * eui , struct net_device * dev )
2016-06-15 22:20:17 +03:00
{
struct wpan_dev * wpan_dev = lowpan_802154_dev ( dev ) - > wdev - > ieee802154_ptr ;
/* Set short_addr autoconfiguration if short_addr is present only */
if ( ! lowpan_802154_is_valid_src_short_addr ( wpan_dev - > short_addr ) )
return - 1 ;
/* For either address format, all zero addresses MUST NOT be used */
if ( wpan_dev - > pan_id = = cpu_to_le16 ( 0x0000 ) & &
wpan_dev - > short_addr = = cpu_to_le16 ( 0x0000 ) )
return - 1 ;
/* Alternatively, if no PAN ID is known, 16 zero bits may be used */
if ( wpan_dev - > pan_id = = cpu_to_le16 ( IEEE802154_PAN_ID_BROADCAST ) )
memset ( eui , 0 , 2 ) ;
else
ieee802154_le16_to_be16 ( eui , & wpan_dev - > pan_id ) ;
/* The "Universal/Local" (U/L) bit shall be set to zero */
eui [ 0 ] & = ~ 2 ;
eui [ 2 ] = 0 ;
eui [ 3 ] = 0xFF ;
eui [ 4 ] = 0xFE ;
eui [ 5 ] = 0 ;
ieee802154_le16_to_be16 ( & eui [ 6 ] , & wpan_dev - > short_addr ) ;
return 0 ;
}
2016-02-22 11:13:54 +03:00
static int lowpan_event ( struct notifier_block * unused ,
unsigned long event , void * ptr )
{
struct net_device * dev = netdev_notifier_info_to_dev ( ptr ) ;
2016-06-15 22:20:17 +03:00
struct inet6_dev * idev ;
struct in6_addr addr ;
2016-02-22 11:13:54 +03:00
int i ;
if ( dev - > type ! = ARPHRD_6LOWPAN )
return NOTIFY_DONE ;
2016-06-15 22:20:17 +03:00
idev = __in6_dev_get ( dev ) ;
if ( ! idev )
return NOTIFY_DONE ;
2016-02-22 11:13:54 +03:00
switch ( event ) {
2016-06-15 22:20:17 +03:00
case NETDEV_UP :
case NETDEV_CHANGE :
/* (802.15.4 6LoWPAN short address slaac handling */
if ( lowpan_is_ll ( dev , LOWPAN_LLTYPE_IEEE802154 ) & &
addrconf_ifid_802154_6lowpan ( addr . s6_addr + 8 , dev ) = = 0 ) {
__ipv6_addr_set_half ( & addr . s6_addr32 [ 0 ] ,
htonl ( 0xFE800000 ) , 0 ) ;
addrconf_add_linklocal ( idev , & addr , 0 ) ;
}
break ;
2016-02-22 11:13:54 +03:00
case NETDEV_DOWN :
for ( i = 0 ; i < LOWPAN_IPHC_CTX_TABLE_SIZE ; i + + )
clear_bit ( LOWPAN_IPHC_CTX_FLAG_ACTIVE ,
2016-04-11 12:04:18 +03:00
& lowpan_dev ( dev ) - > ctx . table [ i ] . flags ) ;
2016-02-22 11:13:54 +03:00
break ;
default :
return NOTIFY_DONE ;
}
return NOTIFY_OK ;
}
static struct notifier_block lowpan_notifier = {
. notifier_call = lowpan_event ,
} ;
2015-08-11 22:44:09 +03:00
static int __init lowpan_module_init ( void )
{
2015-12-10 00:46:30 +03:00
int ret ;
ret = lowpan_debugfs_init ( ) ;
if ( ret < 0 )
return ret ;
2016-02-22 11:13:54 +03:00
ret = register_netdevice_notifier ( & lowpan_notifier ) ;
if ( ret < 0 ) {
lowpan_debugfs_exit ( ) ;
return ret ;
}
2015-08-11 22:44:09 +03:00
request_module_nowait ( " nhc_dest " ) ;
request_module_nowait ( " nhc_fragment " ) ;
request_module_nowait ( " nhc_hop " ) ;
request_module_nowait ( " nhc_ipv6 " ) ;
request_module_nowait ( " nhc_mobility " ) ;
request_module_nowait ( " nhc_routing " ) ;
request_module_nowait ( " nhc_udp " ) ;
return 0 ;
}
2015-12-10 00:46:30 +03:00
static void __exit lowpan_module_exit ( void )
{
lowpan_debugfs_exit ( ) ;
2016-02-22 11:13:54 +03:00
unregister_netdevice_notifier ( & lowpan_notifier ) ;
2015-12-10 00:46:30 +03:00
}
2015-08-11 22:44:09 +03:00
module_init ( lowpan_module_init ) ;
2015-12-10 00:46:30 +03:00
module_exit ( lowpan_module_exit ) ;
2015-08-11 22:44:09 +03:00
MODULE_LICENSE ( " GPL " ) ;