2013-01-04 06:05:31 +04:00
/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
2010-12-13 14:19:28 +03:00
*
* Marek Lindner , Simon Wunderlich
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of version 2 of the GNU General Public
* License 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
*/
# include "main.h"
# include "soft-interface.h"
# include "hard-interface.h"
2011-06-26 05:37:18 +04:00
# include "distributed-arp-table.h"
2010-12-13 14:19:28 +03:00
# include "routing.h"
# include "send.h"
2012-06-11 01:58:51 +04:00
# include "debugfs.h"
2010-12-13 14:19:28 +03:00
# include "translation-table.h"
# include "hash.h"
# include "gateway_common.h"
# include "gateway_client.h"
2012-06-11 01:58:51 +04:00
# include "sysfs.h"
2011-04-26 23:31:45 +04:00
# include "originator.h"
2010-12-13 14:19:28 +03:00
# include <linux/slab.h>
# include <linux/ethtool.h>
# include <linux/etherdevice.h>
# include <linux/if_vlan.h>
2012-01-22 23:00:19 +04:00
# include "bridge_loop_avoidance.h"
2013-01-25 14:12:38 +04:00
# include "network-coding.h"
2010-12-13 14:19:28 +03:00
2012-05-16 22:23:15 +04:00
static int batadv_get_settings ( struct net_device * dev , struct ethtool_cmd * cmd ) ;
static void batadv_get_drvinfo ( struct net_device * dev ,
struct ethtool_drvinfo * info ) ;
static u32 batadv_get_msglevel ( struct net_device * dev ) ;
static void batadv_set_msglevel ( struct net_device * dev , u32 value ) ;
static u32 batadv_get_link ( struct net_device * dev ) ;
2012-04-20 19:02:45 +04:00
static void batadv_get_strings ( struct net_device * dev , u32 stringset , u8 * data ) ;
static void batadv_get_ethtool_stats ( struct net_device * dev ,
struct ethtool_stats * stats , u64 * data ) ;
static int batadv_get_sset_count ( struct net_device * dev , int stringset ) ;
2010-12-13 14:19:28 +03:00
2012-05-16 22:23:15 +04:00
static const struct ethtool_ops batadv_ethtool_ops = {
. get_settings = batadv_get_settings ,
. get_drvinfo = batadv_get_drvinfo ,
. get_msglevel = batadv_get_msglevel ,
. set_msglevel = batadv_set_msglevel ,
. get_link = batadv_get_link ,
2012-04-20 19:02:45 +04:00
. get_strings = batadv_get_strings ,
. get_ethtool_stats = batadv_get_ethtool_stats ,
. get_sset_count = batadv_get_sset_count ,
2010-12-13 14:19:28 +03:00
} ;
2012-05-12 04:09:38 +04:00
int batadv_skb_head_push ( struct sk_buff * skb , unsigned int len )
2010-12-13 14:19:28 +03:00
{
int result ;
2012-05-12 04:09:43 +04:00
/* TODO: We must check if we can release all references to non-payload
2010-12-13 14:19:28 +03:00
* data using skb_header_release in our skbs to allow skb_cow_header to
* work optimally . This means that those skbs are not allowed to read
* or write any data which is before the current position of skb - > data
* after that call and thus allow other skbs with the same data buffer
* to write freely in that area .
*/
result = skb_cow_head ( skb , len ) ;
if ( result < 0 )
return result ;
skb_push ( skb , len ) ;
return 0 ;
}
2012-05-16 22:23:15 +04:00
static int batadv_interface_open ( struct net_device * dev )
2010-12-13 14:19:28 +03:00
{
netif_start_queue ( dev ) ;
return 0 ;
}
2012-05-16 22:23:15 +04:00
static int batadv_interface_release ( struct net_device * dev )
2010-12-13 14:19:28 +03:00
{
netif_stop_queue ( dev ) ;
return 0 ;
}
2012-05-16 22:23:15 +04:00
static struct net_device_stats * batadv_interface_stats ( struct net_device * dev )
2010-12-13 14:19:28 +03:00
{
2012-06-06 00:31:31 +04:00
struct batadv_priv * bat_priv = netdev_priv ( dev ) ;
2012-06-23 13:47:53 +04:00
struct net_device_stats * stats = & bat_priv - > stats ;
stats - > tx_packets = batadv_sum_counter ( bat_priv , BATADV_CNT_TX ) ;
stats - > tx_bytes = batadv_sum_counter ( bat_priv , BATADV_CNT_TX_BYTES ) ;
stats - > tx_dropped = batadv_sum_counter ( bat_priv , BATADV_CNT_TX_DROPPED ) ;
stats - > rx_packets = batadv_sum_counter ( bat_priv , BATADV_CNT_RX ) ;
stats - > rx_bytes = batadv_sum_counter ( bat_priv , BATADV_CNT_RX_BYTES ) ;
return stats ;
2010-12-13 14:19:28 +03:00
}
2012-05-16 22:23:15 +04:00
static int batadv_interface_set_mac_addr ( struct net_device * dev , void * p )
2010-12-13 14:19:28 +03:00
{
2012-06-06 00:31:31 +04:00
struct batadv_priv * bat_priv = netdev_priv ( dev ) ;
2010-12-13 14:19:28 +03:00
struct sockaddr * addr = p ;
2012-09-20 16:56:13 +04:00
uint8_t old_addr [ ETH_ALEN ] ;
2010-12-13 14:19:28 +03:00
if ( ! is_valid_ether_addr ( addr - > sa_data ) )
return - EADDRNOTAVAIL ;
2012-09-20 16:56:13 +04:00
memcpy ( old_addr , dev - > dev_addr , ETH_ALEN ) ;
memcpy ( dev - > dev_addr , addr - > sa_data , ETH_ALEN ) ;
2011-07-09 19:52:13 +04:00
/* only modify transtable if it has been initialized before */
2012-06-04 00:19:22 +04:00
if ( atomic_read ( & bat_priv - > mesh_state ) = = BATADV_MESH_ACTIVE ) {
2013-06-04 14:11:39 +04:00
batadv_tt_local_remove ( bat_priv , old_addr , BATADV_NO_FLAGS ,
2012-05-12 04:09:39 +04:00
" mac address changed " , false ) ;
2013-06-04 14:11:39 +04:00
batadv_tt_local_add ( dev , addr - > sa_data , BATADV_NO_FLAGS ,
BATADV_NULL_IFINDEX ) ;
2010-12-13 14:19:28 +03:00
}
return 0 ;
}
2012-05-16 22:23:15 +04:00
static int batadv_interface_change_mtu ( struct net_device * dev , int new_mtu )
2010-12-13 14:19:28 +03:00
{
/* check ranges */
2012-05-12 04:09:31 +04:00
if ( ( new_mtu < 68 ) | | ( new_mtu > batadv_hardif_min_mtu ( dev ) ) )
2010-12-13 14:19:28 +03:00
return - EINVAL ;
dev - > mtu = new_mtu ;
return 0 ;
}
2013-05-26 19:56:07 +04:00
/**
* batadv_interface_set_rx_mode - set the rx mode of a device
* @ dev : registered network device to modify
*
* We do not actually need to set any rx filters for the virtual batman
* soft interface . However a dummy handler enables a user to set static
* multicast listeners for instance .
*/
static void batadv_interface_set_rx_mode ( struct net_device * dev )
{
}
2012-05-16 22:23:15 +04:00
static int batadv_interface_tx ( struct sk_buff * skb ,
struct net_device * soft_iface )
2010-12-13 14:19:28 +03:00
{
2013-06-04 14:11:39 +04:00
struct ethhdr * ethhdr ;
2012-06-06 00:31:31 +04:00
struct batadv_priv * bat_priv = netdev_priv ( soft_iface ) ;
struct batadv_hard_iface * primary_if = NULL ;
2012-06-06 00:31:30 +04:00
struct batadv_bcast_packet * bcast_packet ;
2013-05-19 14:55:16 +04:00
__be16 ethertype = htons ( ETH_P_BATMAN ) ;
2012-08-19 22:10:09 +04:00
static const uint8_t stp_addr [ ETH_ALEN ] = { 0x01 , 0x80 , 0xC2 , 0x00 ,
0x00 , 0x00 } ;
static const uint8_t ectp_addr [ ETH_ALEN ] = { 0xCF , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 } ;
2013-06-04 14:11:39 +04:00
struct vlan_ethhdr * vhdr ;
2011-09-08 15:12:53 +04:00
unsigned int header_len = 0 ;
2010-12-13 14:19:28 +03:00
int data_len = skb - > len , ret ;
2013-06-04 14:11:39 +04:00
unsigned long brd_delay = 1 ;
2011-09-08 15:12:53 +04:00
bool do_bcast = false ;
2013-06-04 14:11:39 +04:00
unsigned short vid ;
2012-07-08 19:13:15 +04:00
uint32_t seqno ;
2010-12-13 14:19:28 +03:00
2012-06-04 00:19:22 +04:00
if ( atomic_read ( & bat_priv - > mesh_state ) ! = BATADV_MESH_ACTIVE )
2010-12-13 14:19:28 +03:00
goto dropped ;
soft_iface - > trans_start = jiffies ;
2013-06-04 14:11:39 +04:00
vid = batadv_get_vid ( skb , 0 ) ;
ethhdr = ( struct ethhdr * ) skb - > data ;
2010-12-13 14:19:28 +03:00
switch ( ntohs ( ethhdr - > h_proto ) ) {
case ETH_P_8021Q :
vhdr = ( struct vlan_ethhdr * ) skb - > data ;
2012-06-04 00:19:13 +04:00
if ( vhdr - > h_vlan_encapsulated_proto ! = ethertype )
2010-12-13 14:19:28 +03:00
break ;
/* fall through */
2012-11-26 03:38:50 +04:00
case ETH_P_BATMAN :
2010-12-13 14:19:28 +03:00
goto dropped ;
2012-01-22 23:00:18 +04:00
}
2010-12-13 14:19:28 +03:00
2012-05-12 15:38:47 +04:00
if ( batadv_bla_tx ( bat_priv , skb , vid ) )
2012-01-22 23:00:19 +04:00
goto dropped ;
2013-08-06 22:21:15 +04:00
/* skb->data might have been reallocated by batadv_bla_tx() */
ethhdr = ( struct ethhdr * ) skb - > data ;
2011-04-27 16:27:44 +04:00
/* Register the client MAC in the transtable */
2012-10-17 17:07:35 +04:00
if ( ! is_multicast_ether_addr ( ethhdr - > h_source ) )
2013-06-04 14:11:39 +04:00
batadv_tt_local_add ( soft_iface , ethhdr - > h_source , vid ,
skb - > skb_iif ) ;
2010-12-13 14:19:28 +03:00
2012-01-22 23:00:25 +04:00
/* don't accept stp packets. STP does not help in meshes.
* better use the bridge loop avoidance . . .
2012-08-19 22:10:09 +04:00
*
* The same goes for ECTP sent at least by some Cisco Switches ,
* it might confuse the mesh when used with bridge loop avoidance .
2012-01-22 23:00:25 +04:00
*/
2012-05-12 15:48:58 +04:00
if ( batadv_compare_eth ( ethhdr - > h_dest , stp_addr ) )
2012-01-22 23:00:25 +04:00
goto dropped ;
2012-08-19 22:10:09 +04:00
if ( batadv_compare_eth ( ethhdr - > h_dest , ectp_addr ) )
goto dropped ;
2011-09-08 15:12:53 +04:00
if ( is_multicast_ether_addr ( ethhdr - > h_dest ) ) {
do_bcast = true ;
2010-12-13 14:19:28 +03:00
2011-09-08 15:12:53 +04:00
switch ( atomic_read ( & bat_priv - > gw_mode ) ) {
2012-06-04 00:19:18 +04:00
case BATADV_GW_MODE_SERVER :
2011-09-08 15:12:53 +04:00
/* gateway servers should not send dhcp
2012-05-12 04:09:43 +04:00
* requests into the mesh
*/
2012-05-12 04:09:29 +04:00
ret = batadv_gw_is_dhcp_target ( skb , & header_len ) ;
2011-09-08 15:12:53 +04:00
if ( ret )
goto dropped ;
break ;
2012-06-04 00:19:18 +04:00
case BATADV_GW_MODE_CLIENT :
2011-09-08 15:12:53 +04:00
/* gateway clients should send dhcp requests
2012-05-12 04:09:43 +04:00
* via unicast to their gateway
*/
2012-05-12 04:09:29 +04:00
ret = batadv_gw_is_dhcp_target ( skb , & header_len ) ;
2011-09-08 15:12:53 +04:00
if ( ret )
do_bcast = false ;
break ;
2012-06-04 00:19:18 +04:00
case BATADV_GW_MODE_OFF :
2011-09-08 15:12:53 +04:00
default :
break ;
}
2013-08-06 22:21:15 +04:00
/* reminder: ethhdr might have become unusable from here on
* ( batadv_gw_is_dhcp_target ( ) might have reallocated skb data )
*/
2010-12-13 14:19:28 +03:00
}
2013-07-29 19:56:44 +04:00
batadv_skb_set_priority ( skb , 0 ) ;
2010-12-13 14:19:28 +03:00
/* ethernet packet should be broadcasted */
if ( do_bcast ) {
2012-05-12 15:48:54 +04:00
primary_if = batadv_primary_if_get_selected ( bat_priv ) ;
2011-04-20 17:40:58 +04:00
if ( ! primary_if )
2010-12-13 14:19:28 +03:00
goto dropped ;
2011-06-26 05:37:18 +04:00
/* in case of ARP request, we do not immediately broadcasti the
* packet , instead we first wait for DAT to try to retrieve the
* correct ARP entry
*/
if ( batadv_dat_snoop_outgoing_arp_request ( bat_priv , skb ) )
brd_delay = msecs_to_jiffies ( ARP_REQ_DELAY ) ;
2012-05-12 04:09:38 +04:00
if ( batadv_skb_head_push ( skb , sizeof ( * bcast_packet ) ) < 0 )
2010-12-13 14:19:28 +03:00
goto dropped ;
2012-06-06 00:31:30 +04:00
bcast_packet = ( struct batadv_bcast_packet * ) skb - > data ;
2012-06-04 00:19:13 +04:00
bcast_packet - > header . version = BATADV_COMPAT_VERSION ;
2012-06-04 00:19:17 +04:00
bcast_packet - > header . ttl = BATADV_TTL ;
2010-12-13 14:19:28 +03:00
/* batman packet type: broadcast */
2012-06-04 00:19:21 +04:00
bcast_packet - > header . packet_type = BATADV_BCAST ;
2012-06-28 13:56:52 +04:00
bcast_packet - > reserved = 0 ;
2010-12-13 14:19:28 +03:00
/* hw address of first interface is the orig mac because only
2012-05-12 04:09:43 +04:00
* this mac is known throughout the mesh
*/
2010-12-13 14:19:28 +03:00
memcpy ( bcast_packet - > orig ,
2011-04-20 17:40:58 +04:00
primary_if - > net_dev - > dev_addr , ETH_ALEN ) ;
2010-12-13 14:19:28 +03:00
/* set broadcast sequence number */
2012-07-08 19:13:15 +04:00
seqno = atomic_inc_return ( & bat_priv - > bcast_seqno ) ;
bcast_packet - > seqno = htonl ( seqno ) ;
2010-12-13 14:19:28 +03:00
2011-06-26 05:37:18 +04:00
batadv_add_bcast_packet_to_list ( bat_priv , skb , brd_delay ) ;
2010-12-13 14:19:28 +03:00
/* a copy is stored in the bcast list, therefore removing
2012-05-12 04:09:43 +04:00
* the original skb .
*/
2010-12-13 14:19:28 +03:00
kfree_skb ( skb ) ;
/* unicast packet */
} else {
2012-06-04 00:19:18 +04:00
if ( atomic_read ( & bat_priv - > gw_mode ) ! = BATADV_GW_MODE_OFF ) {
2013-08-06 22:21:15 +04:00
ret = batadv_gw_out_of_range ( bat_priv , skb ) ;
2011-09-08 15:12:53 +04:00
if ( ret )
goto dropped ;
}
2011-06-26 05:37:18 +04:00
if ( batadv_dat_snoop_outgoing_arp_request ( bat_priv , skb ) )
goto dropped ;
batadv_dat_snoop_outgoing_arp_reply ( bat_priv , skb ) ;
2013-06-04 14:11:39 +04:00
ret = batadv_send_skb_unicast ( bat_priv , skb , vid ) ;
2010-12-13 14:19:28 +03:00
if ( ret ! = 0 )
goto dropped_freed ;
}
2012-06-23 13:47:53 +04:00
batadv_inc_counter ( bat_priv , BATADV_CNT_TX ) ;
batadv_add_counter ( bat_priv , BATADV_CNT_TX_BYTES , data_len ) ;
2010-12-13 14:19:28 +03:00
goto end ;
dropped :
kfree_skb ( skb ) ;
dropped_freed :
2012-06-23 13:47:53 +04:00
batadv_inc_counter ( bat_priv , BATADV_CNT_TX_DROPPED ) ;
2010-12-13 14:19:28 +03:00
end :
2011-04-20 17:40:58 +04:00
if ( primary_if )
2012-05-12 15:48:54 +04:00
batadv_hardif_free_ref ( primary_if ) ;
2010-12-13 14:19:28 +03:00
return NETDEV_TX_OK ;
}
2012-05-12 04:09:38 +04:00
void batadv_interface_rx ( struct net_device * soft_iface ,
2012-06-06 00:31:31 +04:00
struct sk_buff * skb , struct batadv_hard_iface * recv_if ,
2012-07-06 01:38:30 +04:00
int hdr_size , struct batadv_orig_node * orig_node )
2010-12-13 14:19:28 +03:00
{
2012-07-11 10:56:33 +04:00
struct batadv_header * batadv_header = ( struct batadv_header * ) skb - > data ;
2013-06-04 14:11:39 +04:00
struct batadv_priv * bat_priv = netdev_priv ( soft_iface ) ;
2013-05-19 14:55:16 +04:00
__be16 ethertype = htons ( ETH_P_BATMAN ) ;
2013-06-04 14:11:39 +04:00
struct vlan_ethhdr * vhdr ;
struct ethhdr * ethhdr ;
unsigned short vid ;
2012-07-04 22:38:19 +04:00
bool is_bcast ;
2012-07-11 10:56:33 +04:00
is_bcast = ( batadv_header - > packet_type = = BATADV_BCAST ) ;
2010-12-13 14:19:28 +03:00
/* check if enough space is available for pulling, and pull */
if ( ! pskb_may_pull ( skb , hdr_size ) )
goto dropped ;
skb_pull_rcsum ( skb , hdr_size ) ;
skb_reset_mac_header ( skb ) ;
2013-06-04 14:11:39 +04:00
vid = batadv_get_vid ( skb , hdr_size ) ;
2013-04-08 17:08:18 +04:00
ethhdr = eth_hdr ( skb ) ;
2010-12-13 14:19:28 +03:00
switch ( ntohs ( ethhdr - > h_proto ) ) {
case ETH_P_8021Q :
vhdr = ( struct vlan_ethhdr * ) skb - > data ;
2012-06-04 00:19:13 +04:00
if ( vhdr - > h_vlan_encapsulated_proto ! = ethertype )
2010-12-13 14:19:28 +03:00
break ;
/* fall through */
2012-11-26 03:38:50 +04:00
case ETH_P_BATMAN :
2010-12-13 14:19:28 +03:00
goto dropped ;
}
/* skb->dev & skb->pkt_type are set here */
if ( unlikely ( ! pskb_may_pull ( skb , ETH_HLEN ) ) )
goto dropped ;
skb - > protocol = eth_type_trans ( skb , soft_iface ) ;
2011-03-31 05:57:33 +04:00
/* should not be necessary anymore as we use skb_pull_rcsum()
2010-12-13 14:19:28 +03:00
* TODO : please verify this and remove this TODO
2012-05-12 04:09:43 +04:00
* - - Dec 21 st 2009 , Simon Wunderlich
*/
2010-12-13 14:19:28 +03:00
2012-05-12 04:09:43 +04:00
/* skb->ip_summed = CHECKSUM_UNNECESSARY; */
2010-12-13 14:19:28 +03:00
2012-06-23 13:47:53 +04:00
batadv_inc_counter ( bat_priv , BATADV_CNT_RX ) ;
batadv_add_counter ( bat_priv , BATADV_CNT_RX_BYTES ,
skb - > len + ETH_HLEN ) ;
2010-12-13 14:19:28 +03:00
soft_iface - > last_rx = jiffies ;
2012-11-09 00:55:30 +04:00
/* Let the bridge loop avoidance check the packet. If will
* not handle it , we can safely push it up .
*/
if ( batadv_bla_rx ( bat_priv , skb , vid , is_bcast ) )
goto out ;
2012-07-06 01:38:30 +04:00
if ( orig_node )
batadv_tt_add_temporary_global_entry ( bat_priv , orig_node ,
2013-06-04 14:11:39 +04:00
ethhdr - > h_source , vid ) ;
2012-07-06 01:38:30 +04:00
2012-05-12 04:09:39 +04:00
if ( batadv_is_ap_isolated ( bat_priv , ethhdr - > h_source , ethhdr - > h_dest ) )
2011-07-07 17:35:36 +04:00
goto dropped ;
2010-12-13 14:19:28 +03:00
netif_rx ( skb ) ;
2011-04-17 22:34:27 +04:00
goto out ;
2010-12-13 14:19:28 +03:00
dropped :
kfree_skb ( skb ) ;
out :
return ;
}
2012-08-20 11:03:59 +04:00
/* batman-adv network devices have devices nesting below it and are a special
* " super class " of normal network devices ; split their locks off into a
* separate class since they always nest .
*/
static struct lock_class_key batadv_netdev_xmit_lock_key ;
static struct lock_class_key batadv_netdev_addr_lock_key ;
/**
* batadv_set_lockdep_class_one - Set lockdep class for a single tx queue
* @ dev : device which owns the tx queue
* @ txq : tx queue to modify
* @ _unused : always NULL
*/
static void batadv_set_lockdep_class_one ( struct net_device * dev ,
struct netdev_queue * txq ,
void * _unused )
{
lockdep_set_class ( & txq - > _xmit_lock , & batadv_netdev_xmit_lock_key ) ;
}
/**
* batadv_set_lockdep_class - Set txq and addr_list lockdep class
* @ dev : network device to modify
*/
static void batadv_set_lockdep_class ( struct net_device * dev )
{
lockdep_set_class ( & dev - > addr_list_lock , & batadv_netdev_addr_lock_key ) ;
netdev_for_each_tx_queue ( dev , batadv_set_lockdep_class_one , NULL ) ;
}
2013-01-11 13:19:51 +04:00
/**
* batadv_softif_destroy_finish - cleans up the remains of a softif
* @ work : work queue item
*
* Free the parts of the soft interface which can not be removed under
* rtnl lock ( to prevent deadlock situations ) .
*/
static void batadv_softif_destroy_finish ( struct work_struct * work )
{
struct batadv_priv * bat_priv ;
struct net_device * soft_iface ;
bat_priv = container_of ( work , struct batadv_priv ,
cleanup_work ) ;
soft_iface = bat_priv - > soft_iface ;
batadv_sysfs_del_meshif ( soft_iface ) ;
rtnl_lock ( ) ;
unregister_netdevice ( soft_iface ) ;
rtnl_unlock ( ) ;
}
2013-02-11 13:10:22 +04:00
/**
* batadv_softif_init_late - late stage initialization of soft interface
* @ dev : registered network device to modify
*
* Returns error code on failures
*/
static int batadv_softif_init_late ( struct net_device * dev )
2010-12-13 14:19:28 +03:00
{
2012-06-06 00:31:31 +04:00
struct batadv_priv * bat_priv ;
2013-05-23 18:53:03 +04:00
uint32_t random_seqno ;
2010-12-13 14:19:28 +03:00
int ret ;
2012-06-04 00:19:20 +04:00
size_t cnt_len = sizeof ( uint64_t ) * BATADV_CNT_NUM ;
2010-12-13 14:19:28 +03:00
2013-02-11 13:10:22 +04:00
batadv_set_lockdep_class ( dev ) ;
2010-12-13 14:19:28 +03:00
2013-02-11 13:10:22 +04:00
bat_priv = netdev_priv ( dev ) ;
bat_priv - > soft_iface = dev ;
2013-01-11 13:19:51 +04:00
INIT_WORK ( & bat_priv - > cleanup_work , batadv_softif_destroy_finish ) ;
2012-06-23 13:47:53 +04:00
/* batadv_interface_stats() needs to be available as soon as
* register_netdevice ( ) has been called
*/
bat_priv - > bat_counters = __alloc_percpu ( cnt_len , __alignof__ ( uint64_t ) ) ;
if ( ! bat_priv - > bat_counters )
2013-02-11 13:10:22 +04:00
return - ENOMEM ;
2010-12-13 14:19:28 +03:00
atomic_set ( & bat_priv - > aggregated_ogms , 1 ) ;
atomic_set ( & bat_priv - > bonding , 0 ) ;
2012-11-26 04:27:29 +04:00
# ifdef CONFIG_BATMAN_ADV_BLA
2012-01-22 23:00:19 +04:00
atomic_set ( & bat_priv - > bridge_loop_avoidance , 0 ) ;
2012-11-26 04:27:29 +04:00
# endif
2012-08-08 20:50:57 +04:00
# ifdef CONFIG_BATMAN_ADV_DAT
atomic_set ( & bat_priv - > distributed_arp_table , 1 ) ;
# endif
2011-07-07 17:35:36 +04:00
atomic_set ( & bat_priv - > ap_isolation , 0 ) ;
2012-06-04 00:19:18 +04:00
atomic_set ( & bat_priv - > gw_mode , BATADV_GW_MODE_OFF ) ;
2010-12-13 14:19:28 +03:00
atomic_set ( & bat_priv - > gw_sel_class , 20 ) ;
2013-04-23 17:39:58 +04:00
atomic_set ( & bat_priv - > gw . bandwidth_down , 100 ) ;
atomic_set ( & bat_priv - > gw . bandwidth_up , 20 ) ;
2010-12-13 14:19:28 +03:00
atomic_set ( & bat_priv - > orig_interval , 1000 ) ;
2012-01-27 19:11:55 +04:00
atomic_set ( & bat_priv - > hop_penalty , 30 ) ;
2012-12-16 09:53:15 +04:00
# ifdef CONFIG_BATMAN_ADV_DEBUG
2010-12-13 14:19:28 +03:00
atomic_set ( & bat_priv - > log_level , 0 ) ;
2012-12-16 09:53:15 +04:00
# endif
2010-12-13 14:19:28 +03:00
atomic_set ( & bat_priv - > fragmentation , 1 ) ;
2012-06-04 00:19:17 +04:00
atomic_set ( & bat_priv - > bcast_queue_left , BATADV_BCAST_QUEUE_LEN ) ;
atomic_set ( & bat_priv - > batman_queue_left , BATADV_BATMAN_QUEUE_LEN ) ;
2010-12-13 14:19:28 +03:00
2012-06-04 00:19:22 +04:00
atomic_set ( & bat_priv - > mesh_state , BATADV_MESH_INACTIVE ) ;
2010-12-13 14:19:28 +03:00
atomic_set ( & bat_priv - > bcast_seqno , 1 ) ;
2012-07-16 00:26:51 +04:00
atomic_set ( & bat_priv - > tt . vn , 0 ) ;
atomic_set ( & bat_priv - > tt . local_changes , 0 ) ;
atomic_set ( & bat_priv - > tt . ogm_append_cnt , 0 ) ;
# ifdef CONFIG_BATMAN_ADV_BLA
atomic_set ( & bat_priv - > bla . num_requests , 0 ) ;
# endif
bat_priv - > tt . last_changeset = NULL ;
bat_priv - > tt . last_changeset_len = 0 ;
2010-12-13 14:19:28 +03:00
2013-05-23 18:53:03 +04:00
/* randomize initial seqno to avoid collision */
get_random_bytes ( & random_seqno , sizeof ( random_seqno ) ) ;
atomic_set ( & bat_priv - > frag_seqno , random_seqno ) ;
2010-12-13 14:19:28 +03:00
bat_priv - > primary_if = NULL ;
bat_priv - > num_ifaces = 0 ;
2013-01-25 14:12:38 +04:00
batadv_nc_init_bat_priv ( bat_priv ) ;
2013-02-11 13:10:22 +04:00
ret = batadv_algo_select ( bat_priv , batadv_routing_algo ) ;
2010-12-13 14:19:28 +03:00
if ( ret < 0 )
2013-02-11 13:10:22 +04:00
goto free_bat_counters ;
2010-12-13 14:19:28 +03:00
2013-02-11 13:10:22 +04:00
ret = batadv_debugfs_add_meshif ( dev ) ;
2010-12-13 14:19:28 +03:00
if ( ret < 0 )
2013-02-11 13:10:22 +04:00
goto free_bat_counters ;
2010-12-13 14:19:28 +03:00
2013-02-11 13:10:22 +04:00
ret = batadv_mesh_init ( dev ) ;
2010-12-13 14:19:28 +03:00
if ( ret < 0 )
goto unreg_debugfs ;
2013-02-11 13:10:22 +04:00
return 0 ;
2010-12-13 14:19:28 +03:00
unreg_debugfs :
2013-02-11 13:10:22 +04:00
batadv_debugfs_del_meshif ( dev ) ;
2012-06-23 13:47:53 +04:00
free_bat_counters :
free_percpu ( bat_priv - > bat_counters ) ;
2013-04-17 23:13:16 +04:00
bat_priv - > bat_counters = NULL ;
2013-02-11 13:10:22 +04:00
return ret ;
}
2013-02-11 13:10:27 +04:00
/**
* batadv_softif_slave_add - Add a slave interface to a batadv_soft_interface
* @ dev : batadv_soft_interface used as master interface
* @ slave_dev : net_device which should become the slave interface
*
* Return 0 if successful or error otherwise .
*/
static int batadv_softif_slave_add ( struct net_device * dev ,
struct net_device * slave_dev )
{
struct batadv_hard_iface * hard_iface ;
int ret = - EINVAL ;
hard_iface = batadv_hardif_get_by_netdev ( slave_dev ) ;
if ( ! hard_iface | | hard_iface - > soft_iface ! = NULL )
goto out ;
ret = batadv_hardif_enable_interface ( hard_iface , dev - > name ) ;
out :
if ( hard_iface )
batadv_hardif_free_ref ( hard_iface ) ;
return ret ;
}
/**
* batadv_softif_slave_del - Delete a slave iface from a batadv_soft_interface
* @ dev : batadv_soft_interface used as master interface
* @ slave_dev : net_device which should be removed from the master interface
*
* Return 0 if successful or error otherwise .
*/
static int batadv_softif_slave_del ( struct net_device * dev ,
struct net_device * slave_dev )
{
struct batadv_hard_iface * hard_iface ;
int ret = - EINVAL ;
hard_iface = batadv_hardif_get_by_netdev ( slave_dev ) ;
if ( ! hard_iface | | hard_iface - > soft_iface ! = dev )
goto out ;
batadv_hardif_disable_interface ( hard_iface , BATADV_IF_CLEANUP_KEEP ) ;
ret = 0 ;
out :
if ( hard_iface )
batadv_hardif_free_ref ( hard_iface ) ;
return ret ;
}
2013-02-11 13:10:22 +04:00
static const struct net_device_ops batadv_netdev_ops = {
. ndo_init = batadv_softif_init_late ,
. ndo_open = batadv_interface_open ,
. ndo_stop = batadv_interface_release ,
. ndo_get_stats = batadv_interface_stats ,
. ndo_set_mac_address = batadv_interface_set_mac_addr ,
. ndo_change_mtu = batadv_interface_change_mtu ,
2013-05-26 19:56:07 +04:00
. ndo_set_rx_mode = batadv_interface_set_rx_mode ,
2013-02-11 13:10:22 +04:00
. ndo_start_xmit = batadv_interface_tx ,
2013-02-11 13:10:27 +04:00
. ndo_validate_addr = eth_validate_addr ,
. ndo_add_slave = batadv_softif_slave_add ,
. ndo_del_slave = batadv_softif_slave_del ,
2013-02-11 13:10:22 +04:00
} ;
2013-02-11 13:10:23 +04:00
/**
* batadv_softif_free - Deconstructor of batadv_soft_interface
* @ dev : Device to cleanup and remove
*/
static void batadv_softif_free ( struct net_device * dev )
{
batadv_debugfs_del_meshif ( dev ) ;
batadv_mesh_free ( dev ) ;
2013-04-19 13:04:52 +04:00
/* some scheduled RCU callbacks need the bat_priv struct to accomplish
* their tasks . Wait for them all to be finished before freeing the
* netdev and its private data ( bat_priv )
*/
rcu_barrier ( ) ;
2013-02-11 13:10:23 +04:00
free_netdev ( dev ) ;
}
2013-02-11 13:10:22 +04:00
/**
* batadv_softif_init_early - early stage initialization of soft interface
* @ dev : registered network device to modify
*/
static void batadv_softif_init_early ( struct net_device * dev )
{
struct batadv_priv * priv = netdev_priv ( dev ) ;
ether_setup ( dev ) ;
dev - > netdev_ops = & batadv_netdev_ops ;
2013-02-11 13:10:23 +04:00
dev - > destructor = batadv_softif_free ;
2013-02-11 13:10:22 +04:00
dev - > tx_queue_len = 0 ;
/* can't call min_mtu, because the needed variables
* have not been initialized yet
*/
dev - > mtu = ETH_DATA_LEN ;
/* reserve more space in the skbuff for our header */
2013-05-08 09:31:59 +04:00
dev - > hard_header_len = batadv_max_header_len ( ) ;
2013-02-11 13:10:22 +04:00
/* generate random address */
eth_hw_addr_random ( dev ) ;
SET_ETHTOOL_OPS ( dev , & batadv_ethtool_ops ) ;
memset ( priv , 0 , sizeof ( * priv ) ) ;
}
struct net_device * batadv_softif_create ( const char * name )
{
struct net_device * soft_iface ;
int ret ;
soft_iface = alloc_netdev ( sizeof ( struct batadv_priv ) , name ,
batadv_softif_init_early ) ;
if ( ! soft_iface )
return NULL ;
2013-02-11 13:10:26 +04:00
soft_iface - > rtnl_link_ops = & batadv_link_ops ;
2013-02-11 13:10:22 +04:00
ret = register_netdevice ( soft_iface ) ;
if ( ret < 0 ) {
pr_err ( " Unable to register the batman interface '%s': %i \n " ,
name , ret ) ;
free_netdev ( soft_iface ) ;
return NULL ;
}
return soft_iface ;
2010-12-13 14:19:28 +03:00
}
2013-02-11 13:10:25 +04:00
/**
* batadv_softif_destroy_sysfs - deletion of batadv_soft_interface via sysfs
* @ soft_iface : the to - be - removed batman - adv interface
*/
void batadv_softif_destroy_sysfs ( struct net_device * soft_iface )
2010-12-13 14:19:28 +03:00
{
2013-01-11 13:19:51 +04:00
struct batadv_priv * bat_priv = netdev_priv ( soft_iface ) ;
queue_work ( batadv_event_workqueue , & bat_priv - > cleanup_work ) ;
2010-12-13 14:19:28 +03:00
}
2013-02-11 13:10:26 +04:00
/**
* batadv_softif_destroy_netlink - deletion of batadv_soft_interface via netlink
* @ soft_iface : the to - be - removed batman - adv interface
* @ head : list pointer
*/
static void batadv_softif_destroy_netlink ( struct net_device * soft_iface ,
struct list_head * head )
{
struct batadv_hard_iface * hard_iface ;
list_for_each_entry ( hard_iface , & batadv_hardif_list , list ) {
if ( hard_iface - > soft_iface = = soft_iface )
batadv_hardif_disable_interface ( hard_iface ,
BATADV_IF_CLEANUP_KEEP ) ;
}
batadv_sysfs_del_meshif ( soft_iface ) ;
unregister_netdevice_queue ( soft_iface , head ) ;
}
2012-05-12 04:09:38 +04:00
int batadv_softif_is_valid ( const struct net_device * net_dev )
2011-03-05 00:36:41 +03:00
{
2012-05-16 22:23:15 +04:00
if ( net_dev - > netdev_ops - > ndo_start_xmit = = batadv_interface_tx )
2011-03-05 00:36:41 +03:00
return 1 ;
return 0 ;
}
2013-02-11 13:10:26 +04:00
struct rtnl_link_ops batadv_link_ops __read_mostly = {
. kind = " batadv " ,
. priv_size = sizeof ( struct batadv_priv ) ,
. setup = batadv_softif_init_early ,
. dellink = batadv_softif_destroy_netlink ,
} ;
2010-12-13 14:19:28 +03:00
/* ethtool */
2012-05-16 22:23:15 +04:00
static int batadv_get_settings ( struct net_device * dev , struct ethtool_cmd * cmd )
2010-12-13 14:19:28 +03:00
{
cmd - > supported = 0 ;
cmd - > advertising = 0 ;
2011-04-27 22:32:40 +04:00
ethtool_cmd_speed_set ( cmd , SPEED_10 ) ;
2010-12-13 14:19:28 +03:00
cmd - > duplex = DUPLEX_FULL ;
cmd - > port = PORT_TP ;
cmd - > phy_address = 0 ;
cmd - > transceiver = XCVR_INTERNAL ;
cmd - > autoneg = AUTONEG_DISABLE ;
cmd - > maxtxpkt = 0 ;
cmd - > maxrxpkt = 0 ;
return 0 ;
}
2012-05-16 22:23:15 +04:00
static void batadv_get_drvinfo ( struct net_device * dev ,
struct ethtool_drvinfo * info )
2010-12-13 14:19:28 +03:00
{
2013-01-06 04:44:26 +04:00
strlcpy ( info - > driver , " B.A.T.M.A.N. advanced " , sizeof ( info - > driver ) ) ;
strlcpy ( info - > version , BATADV_SOURCE_VERSION , sizeof ( info - > version ) ) ;
strlcpy ( info - > fw_version , " N/A " , sizeof ( info - > fw_version ) ) ;
strlcpy ( info - > bus_info , " batman " , sizeof ( info - > bus_info ) ) ;
2010-12-13 14:19:28 +03:00
}
2012-05-16 22:23:15 +04:00
static u32 batadv_get_msglevel ( struct net_device * dev )
2010-12-13 14:19:28 +03:00
{
return - EOPNOTSUPP ;
}
2012-05-16 22:23:15 +04:00
static void batadv_set_msglevel ( struct net_device * dev , u32 value )
2010-12-13 14:19:28 +03:00
{
}
2012-05-16 22:23:15 +04:00
static u32 batadv_get_link ( struct net_device * dev )
2010-12-13 14:19:28 +03:00
{
return 1 ;
}
2012-04-20 19:02:45 +04:00
/* Inspired by drivers/net/ethernet/dlink/sundance.c:1702
* Declare each description string in struct . name [ ] to get fixed sized buffer
* and compile time checking for strings longer than ETH_GSTRING_LEN .
*/
static const struct {
const char name [ ETH_GSTRING_LEN ] ;
2012-05-16 22:23:15 +04:00
} batadv_counters_strings [ ] = {
2012-06-23 13:47:53 +04:00
{ " tx " } ,
{ " tx_bytes " } ,
{ " tx_dropped " } ,
{ " rx " } ,
{ " rx_bytes " } ,
2012-04-20 19:02:45 +04:00
{ " forward " } ,
{ " forward_bytes " } ,
{ " mgmt_tx " } ,
{ " mgmt_tx_bytes " } ,
{ " mgmt_rx " } ,
{ " mgmt_rx_bytes " } ,
2013-05-23 18:53:03 +04:00
{ " frag_tx " } ,
{ " frag_tx_bytes " } ,
2013-05-23 18:53:02 +04:00
{ " frag_rx " } ,
{ " frag_rx_bytes " } ,
{ " frag_fwd " } ,
{ " frag_fwd_bytes " } ,
2012-04-20 19:02:45 +04:00
{ " tt_request_tx " } ,
{ " tt_request_rx " } ,
{ " tt_response_tx " } ,
{ " tt_response_rx " } ,
{ " tt_roam_adv_tx " } ,
{ " tt_roam_adv_rx " } ,
2012-04-20 19:02:45 +04:00
# ifdef CONFIG_BATMAN_ADV_DAT
{ " dat_get_tx " } ,
{ " dat_get_rx " } ,
{ " dat_put_tx " } ,
{ " dat_put_rx " } ,
{ " dat_cached_reply_tx " } ,
# endif
2013-01-25 14:12:41 +04:00
# ifdef CONFIG_BATMAN_ADV_NC
{ " nc_code " } ,
{ " nc_code_bytes " } ,
{ " nc_recode " } ,
{ " nc_recode_bytes " } ,
2013-01-25 14:12:42 +04:00
{ " nc_buffer " } ,
2013-01-25 14:12:43 +04:00
{ " nc_decode " } ,
{ " nc_decode_bytes " } ,
{ " nc_decode_failed " } ,
{ " nc_sniffed " } ,
2013-01-25 14:12:41 +04:00
# endif
2012-04-20 19:02:45 +04:00
} ;
static void batadv_get_strings ( struct net_device * dev , uint32_t stringset ,
uint8_t * data )
{
if ( stringset = = ETH_SS_STATS )
2012-05-16 22:23:15 +04:00
memcpy ( data , batadv_counters_strings ,
sizeof ( batadv_counters_strings ) ) ;
2012-04-20 19:02:45 +04:00
}
static void batadv_get_ethtool_stats ( struct net_device * dev ,
struct ethtool_stats * stats ,
uint64_t * data )
{
2012-06-06 00:31:31 +04:00
struct batadv_priv * bat_priv = netdev_priv ( dev ) ;
2012-04-20 19:02:45 +04:00
int i ;
2012-06-04 00:19:20 +04:00
for ( i = 0 ; i < BATADV_CNT_NUM ; i + + )
2012-04-20 19:02:45 +04:00
data [ i ] = batadv_sum_counter ( bat_priv , i ) ;
}
static int batadv_get_sset_count ( struct net_device * dev , int stringset )
{
if ( stringset = = ETH_SS_STATS )
2012-06-04 00:19:20 +04:00
return BATADV_CNT_NUM ;
2012-04-20 19:02:45 +04:00
return - EOPNOTSUPP ;
}