2016-01-01 02:01:03 +03:00
/* Copyright (C) 2007-2016 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
2013-11-03 23:40:48 +04:00
* along with this program ; if not , see < http : //www.gnu.org/licenses/>.
2010-12-13 14:19:28 +03:00
*/
# include "soft-interface.h"
2015-04-17 20:40:28 +03:00
# include "main.h"
# include <linux/atomic.h>
# include <linux/byteorder/generic.h>
# include <linux/cache.h>
# include <linux/compiler.h>
# include <linux/errno.h>
2010-12-13 14:19:28 +03:00
# include <linux/etherdevice.h>
2015-04-17 20:40:28 +03:00
# include <linux/ethtool.h>
# include <linux/fs.h>
# include <linux/if_ether.h>
2010-12-13 14:19:28 +03:00
# include <linux/if_vlan.h>
2015-04-17 20:40:28 +03:00
# include <linux/jiffies.h>
# include <linux/kernel.h>
2016-01-16 12:29:42 +03:00
# include <linux/kref.h>
2015-04-17 20:40:28 +03:00
# include <linux/list.h>
# include <linux/lockdep.h>
# include <linux/netdevice.h>
# include <linux/percpu.h>
# include <linux/printk.h>
# include <linux/random.h>
# include <linux/rculist.h>
# include <linux/rcupdate.h>
# include <linux/skbuff.h>
# include <linux/slab.h>
# include <linux/socket.h>
# include <linux/spinlock.h>
# include <linux/stddef.h>
# include <linux/string.h>
# include <linux/types.h>
# include <linux/workqueue.h>
2012-01-22 23:00:19 +04:00
# include "bridge_loop_avoidance.h"
2015-04-17 20:40:28 +03:00
# include "debugfs.h"
# include "distributed-arp-table.h"
# include "gateway_client.h"
# include "gateway_common.h"
# include "hard-interface.h"
# include "multicast.h"
2013-01-25 14:12:38 +04:00
# include "network-coding.h"
2015-04-17 20:40:28 +03:00
# include "packet.h"
# include "send.h"
# include "sysfs.h"
# include "translation-table.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 ) ;
2014-03-31 15:48:10 +04:00
struct batadv_softif_vlan * vlan ;
2010-12-13 14:19:28 +03:00
struct sockaddr * addr = p ;
2015-05-26 19:34:26 +03:00
u8 old_addr [ ETH_ALEN ] ;
2010-12-13 14:19:28 +03:00
if ( ! is_valid_ether_addr ( addr - > sa_data ) )
return - EADDRNOTAVAIL ;
2014-01-22 03:42:11 +04:00
ether_addr_copy ( old_addr , dev - > dev_addr ) ;
ether_addr_copy ( dev - > dev_addr , addr - > sa_data ) ;
2012-09-20 16:56:13 +04:00
2011-07-09 19:52:13 +04:00
/* only modify transtable if it has been initialized before */
2014-03-31 15:48:10 +04:00
if ( atomic_read ( & bat_priv - > mesh_state ) ! = BATADV_MESH_ACTIVE )
return 0 ;
rcu_read_lock ( ) ;
hlist_for_each_entry_rcu ( vlan , & bat_priv - > softif_vlan_list , list ) {
batadv_tt_local_remove ( bat_priv , old_addr , vlan - > vid ,
2012-05-12 04:09:39 +04:00
" mac address changed " , false ) ;
2014-03-31 15:48:10 +04:00
batadv_tt_local_add ( dev , addr - > sa_data , vlan - > vid ,
2013-11-16 15:03:48 +04:00
BATADV_NULL_IFINDEX , BATADV_NO_MARK ) ;
2010-12-13 14:19:28 +03:00
}
2014-03-31 15:48:10 +04:00
rcu_read_unlock ( ) ;
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 ) ;
2015-05-26 19:34:26 +03:00
static const u8 stp_addr [ ETH_ALEN ] = { 0x01 , 0x80 , 0xC2 , 0x00 ,
0x00 , 0x00 } ;
static const u8 ectp_addr [ ETH_ALEN ] = { 0xCF , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 } ;
2013-11-05 22:31:08 +04:00
enum batadv_dhcp_recipient dhcp_rcp = BATADV_DHCP_NO ;
2015-05-26 19:34:26 +03:00
u8 * dst_hint = NULL , chaddr [ ETH_ALEN ] ;
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 ;
2013-05-27 11:33:25 +04:00
bool do_bcast = false , client_added ;
2013-06-04 14:11:39 +04:00
unsigned short vid ;
2015-05-26 19:34:26 +03:00
u32 seqno ;
2013-11-05 22:31:08 +04:00
int gw_mode ;
2014-02-15 20:47:52 +04:00
enum batadv_forw_mode forw_mode ;
struct batadv_orig_node * mcast_single_orig = NULL ;
2015-07-01 00:45:26 +03:00
int network_offset = ETH_HLEN ;
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 ;
2016-05-03 17:33:13 +03:00
netif_trans_update ( soft_iface ) ;
2013-06-04 14:11:39 +04:00
vid = batadv_get_vid ( skb , 0 ) ;
2014-01-20 01:22:45 +04:00
ethhdr = eth_hdr ( skb ) ;
2010-12-13 14:19:28 +03:00
switch ( ntohs ( ethhdr - > h_proto ) ) {
case ETH_P_8021Q :
2014-01-20 01:22:45 +04:00
vhdr = vlan_eth_hdr ( skb ) ;
2010-12-13 14:19:28 +03:00
2015-07-01 00:45:26 +03:00
if ( vhdr - > h_vlan_encapsulated_proto ! = ethertype ) {
network_offset + = VLAN_HLEN ;
2010-12-13 14:19:28 +03:00
break ;
2015-07-01 00:45:26 +03:00
}
2010-12-13 14:19:28 +03:00
/* 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
2015-07-01 00:45:26 +03:00
skb_set_network_header ( skb , network_offset ) ;
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() */
2014-01-20 01:22:45 +04:00
ethhdr = eth_hdr ( skb ) ;
2013-08-06 22:21:15 +04:00
2011-04-27 16:27:44 +04:00
/* Register the client MAC in the transtable */
2013-05-27 11:33:25 +04:00
if ( ! is_multicast_ether_addr ( ethhdr - > h_source ) ) {
client_added = batadv_tt_local_add ( soft_iface , ethhdr - > h_source ,
2013-11-16 15:03:48 +04:00
vid , skb - > skb_iif ,
skb - > mark ) ;
2013-05-27 11:33:25 +04:00
if ( ! client_added )
goto dropped ;
}
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 ;
2013-11-05 22:31:08 +04:00
gw_mode = atomic_read ( & bat_priv - > gw_mode ) ;
2011-09-08 15:12:53 +04:00
if ( is_multicast_ether_addr ( ethhdr - > h_dest ) ) {
2013-11-05 22:31:08 +04:00
/* if gw mode is off, broadcast every packet */
if ( gw_mode = = BATADV_GW_MODE_OFF ) {
do_bcast = true ;
goto send ;
2011-09-08 15:12:53 +04:00
}
2013-08-06 22:21:15 +04:00
2013-11-05 22:31:08 +04:00
dhcp_rcp = batadv_gw_dhcp_recipient_get ( skb , & header_len ,
chaddr ) ;
/* skb->data may have been modified by
* batadv_gw_dhcp_recipient_get ( )
2013-08-06 22:21:15 +04:00
*/
2014-01-20 01:22:45 +04:00
ethhdr = eth_hdr ( skb ) ;
2013-11-05 22:31:08 +04:00
/* if gw_mode is on, broadcast any non-DHCP message.
* All the DHCP packets are going to be sent as unicast
*/
if ( dhcp_rcp = = BATADV_DHCP_NO ) {
do_bcast = true ;
goto send ;
}
if ( dhcp_rcp = = BATADV_DHCP_TO_CLIENT )
dst_hint = chaddr ;
else if ( ( gw_mode = = BATADV_GW_MODE_SERVER ) & &
( dhcp_rcp = = BATADV_DHCP_TO_SERVER ) )
/* gateways should not forward any DHCP message if
* directed to a DHCP server
*/
goto dropped ;
2010-12-13 14:19:28 +03:00
2013-11-05 22:31:08 +04:00
send :
2014-02-15 20:47:52 +04:00
if ( do_bcast & & ! is_broadcast_ether_addr ( ethhdr - > h_dest ) ) {
forw_mode = batadv_mcast_forw_mode ( bat_priv , skb ,
& mcast_single_orig ) ;
if ( forw_mode = = BATADV_FORW_NONE )
goto dropped ;
if ( forw_mode = = BATADV_FORW_SINGLE )
do_bcast = false ;
}
}
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 ;
2013-12-02 23:38:31 +04:00
bcast_packet - > version = BATADV_COMPAT_VERSION ;
bcast_packet - > ttl = BATADV_TTL ;
2010-12-13 14:19:28 +03:00
/* batman packet type: broadcast */
2013-12-02 23:38:31 +04:00
bcast_packet - > 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
*/
2014-01-22 03:42:11 +04:00
ether_addr_copy ( bcast_packet - > orig ,
primary_if - > net_dev - > dev_addr ) ;
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 {
2013-11-05 22:31:08 +04:00
/* DHCP packets going to a server will use the GW feature */
if ( dhcp_rcp = = BATADV_DHCP_TO_SERVER ) {
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 ;
2013-07-03 12:40:00 +04:00
ret = batadv_send_skb_via_gw ( bat_priv , skb , vid ) ;
2014-02-15 20:47:52 +04:00
} else if ( mcast_single_orig ) {
ret = batadv_send_skb_unicast ( bat_priv , skb ,
BATADV_UNICAST , 0 ,
mcast_single_orig , vid ) ;
2013-11-05 22:31:08 +04:00
} else {
if ( batadv_dat_snoop_outgoing_arp_request ( bat_priv ,
skb ) )
goto dropped ;
2013-07-03 12:40:00 +04:00
2013-11-05 22:31:08 +04:00
batadv_dat_snoop_outgoing_arp_reply ( bat_priv , skb ) ;
ret = batadv_send_skb_via_tt ( bat_priv , skb , dst_hint ,
vid ) ;
}
2013-07-03 12:40:00 +04:00
if ( ret = = NET_XMIT_DROP )
2010-12-13 14:19:28 +03:00
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 )
2016-01-17 13:01:10 +03:00
batadv_hardif_put ( primary_if ) ;
2010-12-13 14:19:28 +03:00
return NETDEV_TX_OK ;
}
2016-02-28 13:38:50 +03:00
/**
* batadv_interface_rx - receive ethernet frame on local batman - adv interface
* @ soft_iface : local interface which will receive the ethernet frame
* @ skb : ethernet frame for @ soft_iface
* @ hdr_size : size of already parsed batman - adv header
* @ orig_node : originator from which the batman - adv packet was sent
*
* Sends a ethernet frame to the receive path of the local @ soft_iface .
* skb - > data has still point to the batman - adv header with the size @ hdr_size .
* The caller has to have parsed this header already and made sure that at least
* @ hdr_size bytes are still available for pull in @ skb .
*
* The packet may still get dropped . This can happen when the encapsulated
* ethernet frame is invalid or contains again an batman - adv packet . Also
* unicast packets will be dropped directly when it was sent between two
* isolated clients .
*/
2012-05-12 04:09:38 +04:00
void batadv_interface_rx ( struct net_device * soft_iface ,
2016-02-28 13:38:51 +03:00
struct sk_buff * skb , int hdr_size ,
struct batadv_orig_node * orig_node )
2010-12-13 14:19:28 +03:00
{
2013-12-02 23:38:31 +04:00
struct batadv_bcast_packet * batadv_bcast_packet ;
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 ;
2013-12-02 23:38:31 +04:00
batadv_bcast_packet = ( struct batadv_bcast_packet * ) skb - > data ;
is_bcast = ( batadv_bcast_packet - > packet_type = = BATADV_BCAST ) ;
2010-12-13 14:19:28 +03:00
skb_pull_rcsum ( skb , hdr_size ) ;
skb_reset_mac_header ( skb ) ;
2013-12-23 04:28:05 +04:00
/* clean the netfilter state now that the batman-adv header has been
* removed
*/
nf_reset ( skb ) ;
2016-02-26 19:56:13 +03:00
if ( unlikely ( ! pskb_may_pull ( skb , ETH_HLEN ) ) )
goto dropped ;
2013-12-24 00:43:39 +04:00
vid = batadv_get_vid ( skb , 0 ) ;
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 :
2016-02-26 19:56:13 +03:00
if ( ! pskb_may_pull ( skb , VLAN_ETH_HLEN ) )
goto dropped ;
2010-12-13 14:19:28 +03:00
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 */
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
2013-11-16 15:03:52 +04:00
if ( is_multicast_ether_addr ( ethhdr - > h_dest ) ) {
/* set the mark on broadcast packets if AP isolation is ON and
* the packet is coming from an " isolated " client
*/
if ( batadv_vlan_ap_isola_get ( bat_priv , vid ) & &
batadv_tt_global_is_isolated ( bat_priv , ethhdr - > h_source ,
vid ) ) {
/* save bits in skb->mark not covered by the mask and
* apply the mark on the rest
*/
skb - > mark & = ~ bat_priv - > isolation_mark_mask ;
skb - > mark | = bat_priv - > isolation_mark ;
}
} else if ( batadv_is_ap_isolated ( bat_priv , ethhdr - > h_source ,
ethhdr - > h_dest , vid ) ) {
2011-07-07 17:35:36 +04:00
goto dropped ;
2013-11-16 15:03:52 +04:00
}
2011-07-07 17:35:36 +04:00
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 ;
}
2016-01-16 12:29:42 +03:00
/**
* batadv_softif_vlan_release - release vlan from lists and queue for free after
* rcu grace period
* @ ref : kref pointer of the vlan object
*/
static void batadv_softif_vlan_release ( struct kref * ref )
{
struct batadv_softif_vlan * vlan ;
vlan = container_of ( ref , struct batadv_softif_vlan , refcount ) ;
spin_lock_bh ( & vlan - > bat_priv - > softif_vlan_list_lock ) ;
hlist_del_rcu ( & vlan - > list ) ;
spin_unlock_bh ( & vlan - > bat_priv - > softif_vlan_list_lock ) ;
kfree_rcu ( vlan , rcu ) ;
}
2013-07-02 13:04:34 +04:00
/**
2016-01-17 13:01:21 +03:00
* batadv_softif_vlan_put - decrease the vlan object refcounter and
2016-01-16 12:29:42 +03:00
* possibly release it
2015-09-06 22:38:51 +03:00
* @ vlan : the vlan object to release
2013-07-02 13:04:34 +04:00
*/
2016-01-17 13:01:21 +03:00
void batadv_softif_vlan_put ( struct batadv_softif_vlan * vlan )
2013-07-02 13:04:34 +04:00
{
2015-06-09 16:24:36 +03:00
if ( ! vlan )
return ;
2016-01-16 12:29:42 +03:00
kref_put ( & vlan - > refcount , batadv_softif_vlan_release ) ;
2013-07-02 13:04:34 +04:00
}
/**
* batadv_softif_vlan_get - get the vlan object for a specific vid
* @ bat_priv : the bat priv with all the soft interface information
* @ vid : the identifier of the vlan object to retrieve
*
2015-09-15 20:00:48 +03:00
* Return : the private data of the vlan matching the vid passed as argument or
2013-07-02 13:04:34 +04:00
* NULL otherwise . The refcounter of the returned object is incremented by 1.
*/
2013-07-02 13:04:35 +04:00
struct batadv_softif_vlan * batadv_softif_vlan_get ( struct batadv_priv * bat_priv ,
unsigned short vid )
2013-07-02 13:04:34 +04:00
{
struct batadv_softif_vlan * vlan_tmp , * vlan = NULL ;
rcu_read_lock ( ) ;
hlist_for_each_entry_rcu ( vlan_tmp , & bat_priv - > softif_vlan_list , list ) {
if ( vlan_tmp - > vid ! = vid )
continue ;
2016-01-16 12:29:42 +03:00
if ( ! kref_get_unless_zero ( & vlan_tmp - > refcount ) )
2013-07-02 13:04:34 +04:00
continue ;
vlan = vlan_tmp ;
break ;
}
rcu_read_unlock ( ) ;
return vlan ;
}
/**
2016-03-11 18:36:19 +03:00
* batadv_softif_create_vlan - allocate the needed resources for a new vlan
2013-07-02 13:04:34 +04:00
* @ bat_priv : the bat priv with all the soft interface information
* @ vid : the VLAN identifier
*
2015-09-15 20:00:48 +03:00
* Return : 0 on success , a negative error otherwise .
2013-07-02 13:04:34 +04:00
*/
int batadv_softif_create_vlan ( struct batadv_priv * bat_priv , unsigned short vid )
{
struct batadv_softif_vlan * vlan ;
2013-07-02 13:04:35 +04:00
int err ;
2013-07-02 13:04:34 +04:00
vlan = batadv_softif_vlan_get ( bat_priv , vid ) ;
if ( vlan ) {
2016-01-17 13:01:21 +03:00
batadv_softif_vlan_put ( vlan ) ;
2013-07-02 13:04:34 +04:00
return - EEXIST ;
}
vlan = kzalloc ( sizeof ( * vlan ) , GFP_ATOMIC ) ;
if ( ! vlan )
return - ENOMEM ;
2014-05-08 19:13:15 +04:00
vlan - > bat_priv = bat_priv ;
2013-07-02 13:04:34 +04:00
vlan - > vid = vid ;
2016-01-16 12:29:42 +03:00
kref_init ( & vlan - > refcount ) ;
2013-07-02 13:04:34 +04:00
2013-07-02 13:04:36 +04:00
atomic_set ( & vlan - > ap_isolation , 0 ) ;
2013-07-02 13:04:35 +04:00
err = batadv_sysfs_add_vlan ( bat_priv - > soft_iface , vlan ) ;
if ( err ) {
kfree ( vlan ) ;
return err ;
}
2014-05-08 19:13:15 +04:00
spin_lock_bh ( & bat_priv - > softif_vlan_list_lock ) ;
hlist_add_head_rcu ( & vlan - > list , & bat_priv - > softif_vlan_list ) ;
spin_unlock_bh ( & bat_priv - > softif_vlan_list_lock ) ;
2013-07-02 13:04:34 +04:00
/* add a new TT local entry. This one will be marked with the NOPURGE
* flag
*/
batadv_tt_local_add ( bat_priv - > soft_iface ,
bat_priv - > soft_iface - > dev_addr , vid ,
2013-11-16 15:03:48 +04:00
BATADV_NULL_IFINDEX , BATADV_NO_MARK ) ;
2013-07-02 13:04:34 +04:00
return 0 ;
}
/**
* batadv_softif_destroy_vlan - remove and destroy a softif_vlan object
* @ bat_priv : the bat priv with all the soft interface information
* @ vlan : the object to remove
*/
static void batadv_softif_destroy_vlan ( struct batadv_priv * bat_priv ,
struct batadv_softif_vlan * vlan )
{
/* explicitly remove the associated TT local entry because it is marked
* with the NOPURGE flag
*/
batadv_tt_local_remove ( bat_priv , bat_priv - > soft_iface - > dev_addr ,
vlan - > vid , " vlan interface destroyed " , false ) ;
2014-05-08 19:13:15 +04:00
batadv_sysfs_del_vlan ( bat_priv , vlan ) ;
2016-01-17 13:01:21 +03:00
batadv_softif_vlan_put ( vlan ) ;
2013-07-02 13:04:34 +04:00
}
/**
* batadv_interface_add_vid - ndo_add_vid API implementation
* @ dev : the netdev of the mesh interface
2015-10-31 14:29:29 +03:00
* @ proto : protocol of the the vlan id
2013-07-02 13:04:34 +04:00
* @ vid : identifier of the new vlan
*
* Set up all the internal structures for handling the new vlan on top of the
* mesh interface
*
2015-09-15 20:00:48 +03:00
* Return : 0 on success or a negative error code in case of failure .
2013-07-02 13:04:34 +04:00
*/
static int batadv_interface_add_vid ( struct net_device * dev , __be16 proto ,
unsigned short vid )
{
struct batadv_priv * bat_priv = netdev_priv ( dev ) ;
2014-05-08 19:13:15 +04:00
struct batadv_softif_vlan * vlan ;
int ret ;
2013-07-02 13:04:34 +04:00
/* only 802.1Q vlans are supported.
* batman - adv does not know how to handle other types
*/
if ( proto ! = htons ( ETH_P_8021Q ) )
return - EINVAL ;
vid | = BATADV_VLAN_HAS_TAG ;
2014-05-08 19:13:15 +04:00
/* if a new vlan is getting created and it already exists, it means that
* it was not deleted yet . batadv_softif_vlan_get ( ) increases the
* refcount in order to revive the object .
*
* if it does not exist then create it .
*/
vlan = batadv_softif_vlan_get ( bat_priv , vid ) ;
if ( ! vlan )
return batadv_softif_create_vlan ( bat_priv , vid ) ;
/* recreate the sysfs object if it was already destroyed (and it should
* be since we received a kill_vid ( ) for this vlan
*/
if ( ! vlan - > kobj ) {
ret = batadv_sysfs_add_vlan ( bat_priv - > soft_iface , vlan ) ;
if ( ret ) {
2016-01-17 13:01:21 +03:00
batadv_softif_vlan_put ( vlan ) ;
2014-05-08 19:13:15 +04:00
return ret ;
}
}
/* add a new TT local entry. This one will be marked with the NOPURGE
* flag . This must be added again , even if the vlan object already
* exists , because the entry was deleted by kill_vid ( )
*/
batadv_tt_local_add ( bat_priv - > soft_iface ,
bat_priv - > soft_iface - > dev_addr , vid ,
BATADV_NULL_IFINDEX , BATADV_NO_MARK ) ;
return 0 ;
2013-07-02 13:04:34 +04:00
}
/**
* batadv_interface_kill_vid - ndo_kill_vid API implementation
* @ dev : the netdev of the mesh interface
2015-10-31 14:29:29 +03:00
* @ proto : protocol of the the vlan id
2013-07-02 13:04:34 +04:00
* @ vid : identifier of the deleted vlan
*
* Destroy all the internal structures used to handle the vlan identified by vid
* on top of the mesh interface
*
2015-09-15 20:00:48 +03:00
* Return : 0 on success , - EINVAL if the specified prototype is not ETH_P_8021Q
2013-07-02 13:04:34 +04:00
* or - ENOENT if the specified vlan id wasn ' t registered .
*/
static int batadv_interface_kill_vid ( struct net_device * dev , __be16 proto ,
unsigned short vid )
{
struct batadv_priv * bat_priv = netdev_priv ( dev ) ;
struct batadv_softif_vlan * vlan ;
/* only 802.1Q vlans are supported. batman-adv does not know how to
* handle other types
*/
if ( proto ! = htons ( ETH_P_8021Q ) )
return - EINVAL ;
vlan = batadv_softif_vlan_get ( bat_priv , vid | BATADV_VLAN_HAS_TAG ) ;
if ( ! vlan )
return - ENOENT ;
batadv_softif_destroy_vlan ( bat_priv , vlan ) ;
/* finally free the vlan object */
2016-01-17 13:01:21 +03:00
batadv_softif_vlan_put ( vlan ) ;
2013-07-02 13:04:34 +04:00
return 0 ;
}
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 )
{
2013-07-02 13:04:34 +04:00
struct batadv_softif_vlan * vlan ;
2013-01-11 13:19:51 +04:00
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 ;
2013-07-02 13:04:34 +04:00
/* destroy the "untagged" VLAN */
vlan = batadv_softif_vlan_get ( bat_priv , BATADV_NO_FLAGS ) ;
if ( vlan ) {
batadv_softif_destroy_vlan ( bat_priv , vlan ) ;
2016-01-17 13:01:21 +03:00
batadv_softif_vlan_put ( vlan ) ;
2013-07-02 13:04:34 +04:00
}
2013-01-11 13:19:51 +04:00
batadv_sysfs_del_meshif ( soft_iface ) ;
2014-02-08 19:28:18 +04:00
unregister_netdev ( soft_iface ) ;
2013-01-11 13:19:51 +04:00
}
2013-02-11 13:10:22 +04:00
/**
* batadv_softif_init_late - late stage initialization of soft interface
* @ dev : registered network device to modify
*
2015-09-15 20:00:48 +03:00
* Return : error code on failures
2013-02-11 13:10:22 +04:00
*/
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 ;
2015-05-26 19:34:26 +03:00
u32 random_seqno ;
2010-12-13 14:19:28 +03:00
int ret ;
2015-05-26 19:34:26 +03:00
size_t cnt_len = sizeof ( u64 ) * 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
*/
2015-05-26 19:34:26 +03:00
bat_priv - > bat_counters = __alloc_percpu ( cnt_len , __alignof__ ( u64 ) ) ;
2012-06-23 13:47:53 +04:00
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
2015-02-18 20:20:24 +03:00
atomic_set ( & bat_priv - > bridge_loop_avoidance , 1 ) ;
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 ) ;
2014-02-15 20:47:51 +04:00
# endif
# ifdef CONFIG_BATMAN_ADV_MCAST
bat_priv - > mcast . flags = BATADV_NO_FLAGS ;
2014-02-15 20:47:52 +04:00
atomic_set ( & bat_priv - > multicast_mode , 1 ) ;
2014-02-15 20:47:51 +04:00
atomic_set ( & bat_priv - > mcast . num_disabled , 0 ) ;
2014-02-15 20:47:53 +04:00
atomic_set ( & bat_priv - > mcast . num_want_all_unsnoopables , 0 ) ;
2014-02-15 20:47:54 +04:00
atomic_set ( & bat_priv - > mcast . num_want_all_ipv4 , 0 ) ;
atomic_set ( & bat_priv - > mcast . num_want_all_ipv6 , 0 ) ;
2012-08-08 20:50:57 +04:00
# endif
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 ) ;
2014-06-17 14:16:03 +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 ) ;
2013-05-27 11:33:25 +04:00
atomic_set ( & bat_priv - > packet_size_max , ETH_DATA_LEN ) ;
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 ;
2013-11-16 15:03:47 +04:00
bat_priv - > isolation_mark = 0 ;
bat_priv - > isolation_mark_mask = 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
*
2015-09-15 20:00:48 +03:00
* Return : 0 if successful or error otherwise .
2013-02-11 13:10:27 +04:00
*/
static int batadv_softif_slave_add ( struct net_device * dev ,
struct net_device * slave_dev )
{
struct batadv_hard_iface * hard_iface ;
2016-04-21 13:57:27 +03:00
struct net * net = dev_net ( dev ) ;
2013-02-11 13:10:27 +04:00
int ret = - EINVAL ;
hard_iface = batadv_hardif_get_by_netdev ( slave_dev ) ;
2015-02-18 17:17:30 +03:00
if ( ! hard_iface | | hard_iface - > soft_iface )
2013-02-11 13:10:27 +04:00
goto out ;
2016-04-21 13:57:27 +03:00
ret = batadv_hardif_enable_interface ( hard_iface , net , dev - > name ) ;
2013-02-11 13:10:27 +04:00
out :
if ( hard_iface )
2016-01-17 13:01:10 +03:00
batadv_hardif_put ( hard_iface ) ;
2013-02-11 13:10:27 +04:00
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
*
2015-09-15 20:00:48 +03:00
* Return : 0 if successful or error otherwise .
2013-02-11 13:10:27 +04:00
*/
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 )
2016-01-17 13:01:10 +03:00
batadv_hardif_put ( hard_iface ) ;
2013-02-11 13:10:27 +04:00
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 ,
2013-07-02 13:04:34 +04:00
. ndo_vlan_rx_add_vid = batadv_interface_add_vid ,
. ndo_vlan_rx_kill_vid = batadv_interface_kill_vid ,
2013-02-11 13:10:22 +04:00
. 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 ;
2016-03-02 00:19:05 +03:00
dev - > features | = NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_NETNS_LOCAL ;
2015-08-18 11:30:44 +03:00
dev - > priv_flags | = IFF_NO_QUEUE ;
2013-02-11 13:10:22 +04:00
/* can't call min_mtu, because the needed variables
* have not been initialized yet
*/
dev - > mtu = ETH_DATA_LEN ;
/* generate random address */
eth_hw_addr_random ( dev ) ;
2014-05-11 04:12:32 +04:00
dev - > ethtool_ops = & batadv_ethtool_ops ;
2013-02-11 13:10:22 +04:00
memset ( priv , 0 , sizeof ( * priv ) ) ;
}
2016-04-21 13:57:27 +03:00
struct net_device * batadv_softif_create ( struct net * net , const char * name )
2013-02-11 13:10:22 +04:00
{
struct net_device * soft_iface ;
int ret ;
soft_iface = alloc_netdev ( sizeof ( struct batadv_priv ) , name ,
net: set name_assign_type in alloc_netdev()
Extend alloc_netdev{,_mq{,s}}() to take name_assign_type as argument, and convert
all users to pass NET_NAME_UNKNOWN.
Coccinelle patch:
@@
expression sizeof_priv, name, setup, txqs, rxqs, count;
@@
(
-alloc_netdev_mqs(sizeof_priv, name, setup, txqs, rxqs)
+alloc_netdev_mqs(sizeof_priv, name, NET_NAME_UNKNOWN, setup, txqs, rxqs)
|
-alloc_netdev_mq(sizeof_priv, name, setup, count)
+alloc_netdev_mq(sizeof_priv, name, NET_NAME_UNKNOWN, setup, count)
|
-alloc_netdev(sizeof_priv, name, setup)
+alloc_netdev(sizeof_priv, name, NET_NAME_UNKNOWN, setup)
)
v9: move comments here from the wrong commit
Signed-off-by: Tom Gundersen <teg@jklm.no>
Reviewed-by: David Herrmann <dh.herrmann@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2014-07-14 18:37:24 +04:00
NET_NAME_UNKNOWN , batadv_softif_init_early ) ;
2013-02-11 13:10:22 +04:00
if ( ! soft_iface )
return NULL ;
2016-04-21 13:57:27 +03:00
dev_net_set ( soft_iface , net ) ;
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 ) ;
}
2016-02-22 23:02:39 +03:00
bool 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 )
2016-02-22 23:02:39 +03:00
return true ;
2011-03-05 00:36:41 +03:00
2016-02-22 23:02:39 +03:00
return false ;
2011-03-05 00:36:41 +03:00
}
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
} ;
2015-05-26 19:34:26 +03:00
static void batadv_get_strings ( struct net_device * dev , u32 stringset , u8 * data )
2012-04-20 19:02:45 +04:00
{
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 ,
2015-05-26 19:34:26 +03:00
struct ethtool_stats * stats , u64 * data )
2012-04-20 19:02:45 +04:00
{
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 ;
}