2014-01-04 21:04:25 +04:00
/* Copyright (C) 2007-2014 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 "main.h"
# include "routing.h"
# include "send.h"
# include "soft-interface.h"
# include "hard-interface.h"
# include "icmp_socket.h"
# include "translation-table.h"
# include "originator.h"
2012-01-22 23:00:19 +04:00
# include "bridge_loop_avoidance.h"
2011-06-26 05:37:18 +04:00
# include "distributed-arp-table.h"
2013-01-25 14:12:40 +04:00
# include "network-coding.h"
2013-05-23 18:53:02 +04:00
# include "fragmentation.h"
2010-12-13 14:19:28 +03:00
2013-06-04 14:11:39 +04:00
# include <linux/if_vlan.h>
2012-05-16 22:23:13 +04:00
static int batadv_route_unicast_packet ( struct sk_buff * skb ,
2012-06-06 00:31:31 +04:00
struct batadv_hard_iface * recv_if ) ;
2012-01-22 23:00:18 +04:00
2013-11-13 22:14:47 +04:00
/**
* _batadv_update_route - set the router for this originator
* @ bat_priv : the bat priv with all the soft interface information
* @ orig_node : orig node which is to be configured
* @ recv_if : the receive interface for which this route is set
* @ neigh_node : neighbor which should be the next router
*
* This function does not perform any error checks
*/
2012-06-06 00:31:31 +04:00
static void _batadv_update_route ( struct batadv_priv * bat_priv ,
struct batadv_orig_node * orig_node ,
2013-11-13 22:14:47 +04:00
struct batadv_hard_iface * recv_if ,
2012-06-06 00:31:31 +04:00
struct batadv_neigh_node * neigh_node )
2010-12-13 14:19:28 +03:00
{
2013-11-13 22:14:47 +04:00
struct batadv_orig_ifinfo * orig_ifinfo ;
2012-06-06 00:31:31 +04:00
struct batadv_neigh_node * curr_router ;
2011-03-15 01:43:37 +03:00
2013-11-13 22:14:47 +04:00
orig_ifinfo = batadv_orig_ifinfo_get ( orig_node , recv_if ) ;
if ( ! orig_ifinfo )
return ;
rcu_read_lock ( ) ;
curr_router = rcu_dereference ( orig_ifinfo - > router ) ;
if ( curr_router & & ! atomic_inc_not_zero ( & curr_router - > refcount ) )
curr_router = NULL ;
rcu_read_unlock ( ) ;
2010-12-13 00:57:10 +03:00
2010-12-13 14:19:28 +03:00
/* route deleted */
2011-03-15 01:43:37 +03:00
if ( ( curr_router ) & & ( ! neigh_node ) ) {
2012-06-04 00:19:22 +04:00
batadv_dbg ( BATADV_DBG_ROUTES , bat_priv ,
" Deleting route towards: %pM \n " , orig_node - > orig ) ;
2013-08-07 20:28:55 +04:00
batadv_tt_global_del_orig ( bat_priv , orig_node , - 1 ,
2012-05-12 04:09:39 +04:00
" Deleted route towards originator " ) ;
2010-12-13 14:19:28 +03:00
2011-03-15 01:43:37 +03:00
/* route added */
} else if ( ( ! curr_router ) & & ( neigh_node ) ) {
2012-06-04 00:19:22 +04:00
batadv_dbg ( BATADV_DBG_ROUTES , bat_priv ,
2012-05-12 15:48:58 +04:00
" Adding route towards: %pM (via %pM) \n " ,
orig_node - > orig , neigh_node - > addr ) ;
2011-03-15 01:43:37 +03:00
/* route changed */
2011-05-10 13:22:37 +04:00
} else if ( neigh_node & & curr_router ) {
2012-06-04 00:19:22 +04:00
batadv_dbg ( BATADV_DBG_ROUTES , bat_priv ,
2012-05-12 15:48:58 +04:00
" Changing route towards: %pM (now via %pM - was via %pM) \n " ,
orig_node - > orig , neigh_node - > addr ,
curr_router - > addr ) ;
2010-12-13 14:19:28 +03:00
}
2011-03-15 01:43:37 +03:00
if ( curr_router )
2012-05-12 04:09:34 +04:00
batadv_neigh_node_free_ref ( curr_router ) ;
2011-03-15 01:43:37 +03:00
/* increase refcount of new best neighbor */
2011-02-10 17:33:53 +03:00
if ( neigh_node & & ! atomic_inc_not_zero ( & neigh_node - > refcount ) )
neigh_node = NULL ;
2011-03-15 01:43:37 +03:00
spin_lock_bh ( & orig_node - > neigh_list_lock ) ;
2013-11-13 22:14:47 +04:00
rcu_assign_pointer ( orig_ifinfo - > router , neigh_node ) ;
2011-03-15 01:43:37 +03:00
spin_unlock_bh ( & orig_node - > neigh_list_lock ) ;
2013-11-13 22:14:47 +04:00
batadv_orig_ifinfo_free_ref ( orig_ifinfo ) ;
2011-03-15 01:43:37 +03:00
/* decrease refcount of previous best neighbor */
if ( curr_router )
2012-05-12 04:09:34 +04:00
batadv_neigh_node_free_ref ( curr_router ) ;
2010-12-13 14:19:28 +03:00
}
2013-11-13 22:14:47 +04:00
/**
* batadv_update_route - set the router for this originator
* @ bat_priv : the bat priv with all the soft interface information
* @ orig_node : orig node which is to be configured
* @ recv_if : the receive interface for which this route is set
* @ neigh_node : neighbor which should be the next router
*/
2012-06-06 00:31:31 +04:00
void batadv_update_route ( struct batadv_priv * bat_priv ,
struct batadv_orig_node * orig_node ,
2013-11-13 22:14:47 +04:00
struct batadv_hard_iface * recv_if ,
2012-06-06 00:31:31 +04:00
struct batadv_neigh_node * neigh_node )
2010-12-13 14:19:28 +03:00
{
2012-06-06 00:31:31 +04:00
struct batadv_neigh_node * router = NULL ;
2010-12-13 14:19:28 +03:00
if ( ! orig_node )
2011-03-15 01:43:37 +03:00
goto out ;
2013-11-13 22:14:47 +04:00
router = batadv_orig_router_get ( orig_node , recv_if ) ;
2010-12-13 14:19:28 +03:00
2011-03-15 01:43:37 +03:00
if ( router ! = neigh_node )
2013-11-13 22:14:47 +04:00
_batadv_update_route ( bat_priv , orig_node , recv_if , neigh_node ) ;
2011-03-15 01:43:37 +03:00
out :
if ( router )
2012-05-12 04:09:34 +04:00
batadv_neigh_node_free_ref ( router ) ;
2010-12-13 14:19:28 +03:00
}
/* checks whether the host restarted and is in the protection time.
* returns :
* 0 if the packet is to be accepted
* 1 if the packet is to be ignored .
*/
2012-06-06 00:31:31 +04:00
int batadv_window_protected ( struct batadv_priv * bat_priv , int32_t seq_num_diff ,
2012-05-12 04:09:36 +04:00
unsigned long * last_reset )
2010-12-13 14:19:28 +03:00
{
2012-06-04 00:19:17 +04:00
if ( seq_num_diff < = - BATADV_TQ_LOCAL_WINDOW_SIZE | |
seq_num_diff > = BATADV_EXPECTED_SEQNO_RANGE ) {
if ( ! batadv_has_timed_out ( * last_reset ,
BATADV_RESET_PROTECTION_MS ) )
2010-12-13 14:19:28 +03:00
return 1 ;
2012-03-17 11:28:33 +04:00
* last_reset = jiffies ;
2012-06-04 00:19:22 +04:00
batadv_dbg ( BATADV_DBG_BATMAN , bat_priv ,
2012-05-12 15:48:58 +04:00
" old packet received, start protection \n " ) ;
2010-12-13 14:19:28 +03:00
}
2012-03-17 11:28:33 +04:00
2010-12-13 14:19:28 +03:00
return 0 ;
}
2012-05-12 04:09:36 +04:00
bool batadv_check_management_packet ( struct sk_buff * skb ,
2012-06-06 00:31:31 +04:00
struct batadv_hard_iface * hard_iface ,
2012-05-12 04:09:36 +04:00
int header_len )
2010-12-13 14:19:28 +03:00
{
struct ethhdr * ethhdr ;
/* drop packet if it has not necessary minimum size */
2012-03-04 12:56:25 +04:00
if ( unlikely ( ! pskb_may_pull ( skb , header_len ) ) )
return false ;
2010-12-13 14:19:28 +03:00
2013-04-08 17:08:18 +04:00
ethhdr = eth_hdr ( skb ) ;
2010-12-13 14:19:28 +03:00
/* packet with broadcast indication but unicast recipient */
if ( ! is_broadcast_ether_addr ( ethhdr - > h_dest ) )
2012-03-04 12:56:25 +04:00
return false ;
2010-12-13 14:19:28 +03:00
/* packet with broadcast sender address */
if ( is_broadcast_ether_addr ( ethhdr - > h_source ) )
2012-03-04 12:56:25 +04:00
return false ;
2010-12-13 14:19:28 +03:00
/* create a copy of the skb, if needed, to modify it. */
if ( skb_cow ( skb , 0 ) < 0 )
2012-03-04 12:56:25 +04:00
return false ;
2010-12-13 14:19:28 +03:00
/* keep skb linear */
if ( skb_linearize ( skb ) < 0 )
2012-03-04 12:56:25 +04:00
return false ;
2010-12-13 14:19:28 +03:00
2012-03-04 12:56:25 +04:00
return true ;
2010-12-13 14:19:28 +03:00
}
2013-10-23 00:50:09 +04:00
/**
* batadv_recv_my_icmp_packet - receive an icmp packet locally
* @ bat_priv : the bat priv with all the soft interface information
* @ skb : icmp packet to process
*
* Returns NET_RX_SUCCESS if the packet has been consumed or NET_RX_DROP
* otherwise .
*/
2012-06-06 00:31:31 +04:00
static int batadv_recv_my_icmp_packet ( struct batadv_priv * bat_priv ,
2013-10-23 00:50:09 +04:00
struct sk_buff * skb )
2010-12-13 14:19:28 +03:00
{
2012-06-06 00:31:31 +04:00
struct batadv_hard_iface * primary_if = NULL ;
struct batadv_orig_node * orig_node = NULL ;
2013-10-23 00:50:09 +04:00
struct batadv_icmp_header * icmph ;
int res , ret = NET_RX_DROP ;
2010-12-13 14:19:28 +03:00
2013-10-23 00:50:09 +04:00
icmph = ( struct batadv_icmp_header * ) skb - > data ;
2010-12-13 14:19:28 +03:00
2013-10-23 00:50:09 +04:00
switch ( icmph - > msg_type ) {
case BATADV_ECHO_REPLY :
case BATADV_DESTINATION_UNREACHABLE :
case BATADV_TTL_EXCEEDED :
/* receive the packet */
if ( skb_linearize ( skb ) < 0 )
break ;
2010-12-13 14:19:28 +03:00
2013-10-23 00:50:09 +04:00
batadv_socket_receive_packet ( icmph , skb - > len ) ;
break ;
case BATADV_ECHO_REQUEST :
/* answer echo request (ping) */
primary_if = batadv_primary_if_get_selected ( bat_priv ) ;
if ( ! primary_if )
goto out ;
/* get routing information */
orig_node = batadv_orig_hash_find ( bat_priv , icmph - > orig ) ;
if ( ! orig_node )
goto out ;
/* create a copy of the skb, if needed, to modify it. */
if ( skb_cow ( skb , ETH_HLEN ) < 0 )
goto out ;
icmph = ( struct batadv_icmp_header * ) skb - > data ;
2014-01-22 03:42:11 +04:00
ether_addr_copy ( icmph - > dst , icmph - > orig ) ;
ether_addr_copy ( icmph - > orig , primary_if - > net_dev - > dev_addr ) ;
2013-10-23 00:50:09 +04:00
icmph - > msg_type = BATADV_ECHO_REPLY ;
2013-12-02 23:38:31 +04:00
icmph - > ttl = BATADV_TTL ;
2013-10-23 00:50:09 +04:00
res = batadv_send_skb_to_orig ( skb , orig_node , NULL ) ;
if ( res ! = NET_XMIT_DROP )
ret = NET_RX_SUCCESS ;
break ;
default :
/* drop unknown type */
2011-02-10 17:33:53 +03:00
goto out ;
2013-10-23 00:50:09 +04:00
}
2011-02-10 17:33:53 +03:00
out :
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 ) ;
2011-02-10 17:33:53 +03:00
if ( orig_node )
2012-05-12 04:09:34 +04:00
batadv_orig_node_free_ref ( orig_node ) ;
2010-12-13 14:19:28 +03:00
return ret ;
}
2012-06-06 00:31:31 +04:00
static int batadv_recv_icmp_ttl_exceeded ( struct batadv_priv * bat_priv ,
2012-05-16 22:23:13 +04:00
struct sk_buff * skb )
2010-12-13 14:19:28 +03:00
{
2012-06-06 00:31:31 +04:00
struct batadv_hard_iface * primary_if = NULL ;
struct batadv_orig_node * orig_node = NULL ;
2012-06-06 00:31:30 +04:00
struct batadv_icmp_packet * icmp_packet ;
2011-02-10 17:33:53 +03:00
int ret = NET_RX_DROP ;
2010-12-13 14:19:28 +03:00
2012-06-06 00:31:30 +04:00
icmp_packet = ( struct batadv_icmp_packet * ) skb - > data ;
2010-12-13 14:19:28 +03:00
/* send TTL exceeded if packet is an echo request (traceroute) */
2013-12-05 18:33:00 +04:00
if ( icmp_packet - > msg_type ! = BATADV_ECHO_REQUEST ) {
2012-03-07 12:07:45 +04:00
pr_debug ( " Warning - can't forward icmp packet from %pM to %pM: ttl exceeded \n " ,
2013-12-05 18:33:00 +04:00
icmp_packet - > orig , icmp_packet - > dst ) ;
2011-02-10 17:33:53 +03:00
goto out ;
2010-12-13 14:19:28 +03:00
}
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 )
2011-02-10 17:33:53 +03:00
goto out ;
2010-12-13 14:19:28 +03:00
/* get routing information */
2013-12-05 18:33:00 +04:00
orig_node = batadv_orig_hash_find ( bat_priv , icmp_packet - > orig ) ;
2011-02-10 17:33:53 +03:00
if ( ! orig_node )
2011-03-15 01:43:37 +03:00
goto out ;
2010-12-13 14:19:28 +03:00
2011-02-10 17:33:53 +03:00
/* create a copy of the skb, if needed, to modify it. */
2012-02-18 14:27:34 +04:00
if ( skb_cow ( skb , ETH_HLEN ) < 0 )
2011-02-10 17:33:53 +03:00
goto out ;
2010-12-13 14:19:28 +03:00
2012-06-06 00:31:30 +04:00
icmp_packet = ( struct batadv_icmp_packet * ) skb - > data ;
2010-12-13 14:19:28 +03:00
2014-01-22 03:42:11 +04:00
ether_addr_copy ( icmp_packet - > dst , icmp_packet - > orig ) ;
ether_addr_copy ( icmp_packet - > orig , primary_if - > net_dev - > dev_addr ) ;
2013-12-05 18:33:00 +04:00
icmp_packet - > msg_type = BATADV_TTL_EXCEEDED ;
icmp_packet - > ttl = BATADV_TTL ;
2011-02-10 17:33:53 +03:00
2013-04-20 15:54:39 +04:00
if ( batadv_send_skb_to_orig ( skb , orig_node , NULL ) ! = NET_XMIT_DROP )
2012-10-16 18:13:48 +04:00
ret = NET_RX_SUCCESS ;
2010-12-13 14:19:28 +03:00
2011-02-10 17:33:53 +03:00
out :
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 ) ;
2011-02-10 17:33:53 +03:00
if ( orig_node )
2012-05-12 04:09:34 +04:00
batadv_orig_node_free_ref ( orig_node ) ;
2010-12-13 14:19:28 +03:00
return ret ;
}
2012-06-06 00:31:31 +04:00
int batadv_recv_icmp_packet ( struct sk_buff * skb ,
struct batadv_hard_iface * recv_if )
2010-12-13 14:19:28 +03:00
{
2012-06-06 00:31:31 +04:00
struct batadv_priv * bat_priv = netdev_priv ( recv_if - > soft_iface ) ;
2013-10-23 00:50:09 +04:00
struct batadv_icmp_header * icmph ;
struct batadv_icmp_packet_rr * icmp_packet_rr ;
2010-12-13 14:19:28 +03:00
struct ethhdr * ethhdr ;
2012-06-06 00:31:31 +04:00
struct batadv_orig_node * orig_node = NULL ;
2013-10-23 00:50:09 +04:00
int hdr_size = sizeof ( struct batadv_icmp_header ) ;
2011-02-10 17:33:53 +03:00
int ret = NET_RX_DROP ;
2010-12-13 14:19:28 +03:00
/* drop packet if it has not necessary minimum size */
if ( unlikely ( ! pskb_may_pull ( skb , hdr_size ) ) )
2011-02-10 17:33:53 +03:00
goto out ;
2010-12-13 14:19:28 +03:00
2013-04-08 17:08:18 +04:00
ethhdr = eth_hdr ( skb ) ;
2010-12-13 14:19:28 +03:00
/* packet with unicast indication but broadcast recipient */
if ( is_broadcast_ether_addr ( ethhdr - > h_dest ) )
2011-02-10 17:33:53 +03:00
goto out ;
2010-12-13 14:19:28 +03:00
/* packet with broadcast sender address */
if ( is_broadcast_ether_addr ( ethhdr - > h_source ) )
2011-02-10 17:33:53 +03:00
goto out ;
2010-12-13 14:19:28 +03:00
/* not for me */
2013-04-03 21:10:26 +04:00
if ( ! batadv_is_my_mac ( bat_priv , ethhdr - > h_dest ) )
2011-02-10 17:33:53 +03:00
goto out ;
2010-12-13 14:19:28 +03:00
2013-10-23 00:50:09 +04:00
icmph = ( struct batadv_icmp_header * ) skb - > data ;
2010-12-13 14:19:28 +03:00
/* add record route information if not full */
2013-10-23 00:50:09 +04:00
if ( ( icmph - > msg_type = = BATADV_ECHO_REPLY | |
icmph - > msg_type = = BATADV_ECHO_REQUEST ) & &
( skb - > len > = sizeof ( struct batadv_icmp_packet_rr ) ) ) {
if ( skb_linearize ( skb ) < 0 )
goto out ;
/* create a copy of the skb, if needed, to modify it. */
if ( skb_cow ( skb , ETH_HLEN ) < 0 )
goto out ;
icmph = ( struct batadv_icmp_header * ) skb - > data ;
icmp_packet_rr = ( struct batadv_icmp_packet_rr * ) icmph ;
if ( icmp_packet_rr - > rr_cur > = BATADV_RR_LEN )
goto out ;
2014-01-22 03:42:11 +04:00
ether_addr_copy ( icmp_packet_rr - > rr [ icmp_packet_rr - > rr_cur ] ,
ethhdr - > h_dest ) ;
2013-10-23 00:50:09 +04:00
icmp_packet_rr - > rr_cur + + ;
2010-12-13 14:19:28 +03:00
}
/* packet for me */
2013-10-23 00:50:09 +04:00
if ( batadv_is_my_mac ( bat_priv , icmph - > dst ) )
return batadv_recv_my_icmp_packet ( bat_priv , skb ) ;
2010-12-13 14:19:28 +03:00
/* TTL exceeded */
2013-12-02 23:38:31 +04:00
if ( icmph - > ttl < 2 )
2012-05-16 22:23:13 +04:00
return batadv_recv_icmp_ttl_exceeded ( bat_priv , skb ) ;
2010-12-13 14:19:28 +03:00
/* get routing information */
2013-10-23 00:50:09 +04:00
orig_node = batadv_orig_hash_find ( bat_priv , icmph - > dst ) ;
2011-02-10 17:33:53 +03:00
if ( ! orig_node )
2011-03-15 01:43:37 +03:00
goto out ;
2010-12-13 14:19:28 +03:00
2011-02-10 17:33:53 +03:00
/* create a copy of the skb, if needed, to modify it. */
2012-02-18 14:27:34 +04:00
if ( skb_cow ( skb , ETH_HLEN ) < 0 )
2011-02-10 17:33:53 +03:00
goto out ;
2010-12-13 14:19:28 +03:00
2013-10-23 00:50:09 +04:00
icmph = ( struct batadv_icmp_header * ) skb - > data ;
2010-12-13 14:19:28 +03:00
2011-02-10 17:33:53 +03:00
/* decrement ttl */
2013-12-02 23:38:31 +04:00
icmph - > ttl - - ;
2011-02-10 17:33:53 +03:00
/* route it */
2013-04-20 15:54:39 +04:00
if ( batadv_send_skb_to_orig ( skb , orig_node , recv_if ) ! = NET_XMIT_DROP )
2012-10-16 18:13:48 +04:00
ret = NET_RX_SUCCESS ;
2010-12-13 14:19:28 +03:00
2011-02-10 17:33:53 +03:00
out :
if ( orig_node )
2012-05-12 04:09:34 +04:00
batadv_orig_node_free_ref ( orig_node ) ;
2010-12-13 14:19:28 +03:00
return ret ;
}
2013-01-14 03:20:32 +04:00
/**
* batadv_check_unicast_packet - Check for malformed unicast packets
2013-04-23 04:32:51 +04:00
* @ bat_priv : the bat priv with all the soft interface information
2013-01-14 03:20:32 +04:00
* @ skb : packet to check
* @ hdr_size : size of header to pull
*
* Check for short header and bad addresses in given packet . Returns negative
* value when check fails and 0 otherwise . The negative value depends on the
* reason : - ENODATA for bad header , - EBADR for broadcast destination or source ,
* and - EREMOTE for non - local ( other host ) destination .
*/
2013-04-03 21:10:26 +04:00
static int batadv_check_unicast_packet ( struct batadv_priv * bat_priv ,
struct sk_buff * skb , int hdr_size )
2012-07-05 13:34:27 +04:00
{
struct ethhdr * ethhdr ;
/* drop packet if it has not necessary minimum size */
if ( unlikely ( ! pskb_may_pull ( skb , hdr_size ) ) )
2013-01-14 03:20:32 +04:00
return - ENODATA ;
2012-07-05 13:34:27 +04:00
2013-04-08 17:08:18 +04:00
ethhdr = eth_hdr ( skb ) ;
2012-07-05 13:34:27 +04:00
/* packet with unicast indication but broadcast recipient */
if ( is_broadcast_ether_addr ( ethhdr - > h_dest ) )
2013-01-14 03:20:32 +04:00
return - EBADR ;
2012-07-05 13:34:27 +04:00
/* packet with broadcast sender address */
if ( is_broadcast_ether_addr ( ethhdr - > h_source ) )
2013-01-14 03:20:32 +04:00
return - EBADR ;
2012-07-05 13:34:27 +04:00
/* not for me */
2013-04-03 21:10:26 +04:00
if ( ! batadv_is_my_mac ( bat_priv , ethhdr - > h_dest ) )
2013-01-14 03:20:32 +04:00
return - EREMOTE ;
2012-07-05 13:34:27 +04:00
return 0 ;
}
2013-11-13 22:14:45 +04:00
/**
* batadv_find_router - find a suitable router for this originator
* @ bat_priv : the bat priv with all the soft interface information
* @ orig_node : the destination node
* @ recv_if : pointer to interface this packet was received on
*
* Returns the router which should be used for this orig_node on
* this interface , or NULL if not available .
2012-05-12 04:09:43 +04:00
*/
2012-06-06 00:31:31 +04:00
struct batadv_neigh_node *
batadv_find_router ( struct batadv_priv * bat_priv ,
struct batadv_orig_node * orig_node ,
2013-11-13 22:14:50 +04:00
struct batadv_hard_iface * recv_if )
2010-12-13 14:19:28 +03:00
{
2013-11-13 22:14:50 +04:00
struct batadv_algo_ops * bao = bat_priv - > bat_algo_ops ;
struct batadv_neigh_node * first_candidate_router = NULL ;
struct batadv_neigh_node * next_candidate_router = NULL ;
struct batadv_neigh_node * router , * cand_router = NULL ;
struct batadv_neigh_node * last_cand_router = NULL ;
struct batadv_orig_ifinfo * cand , * first_candidate = NULL ;
struct batadv_orig_ifinfo * next_candidate = NULL ;
struct batadv_orig_ifinfo * last_candidate ;
bool last_candidate_found = false ;
2010-12-13 14:19:28 +03:00
if ( ! orig_node )
return NULL ;
2013-11-13 22:14:47 +04:00
router = batadv_orig_router_get ( orig_node , recv_if ) ;
2010-12-13 14:19:28 +03:00
2014-08-13 16:26:56 +04:00
if ( ! router )
return router ;
2013-11-13 22:14:50 +04:00
/* only consider bonding for recv_if == BATADV_IF_DEFAULT (first hop)
* and if activated .
*/
2014-08-13 16:26:56 +04:00
if ( ! ( recv_if = = BATADV_IF_DEFAULT & & atomic_read ( & bat_priv - > bonding ) ) )
2013-11-13 22:14:50 +04:00
return router ;
/* bonding: loop through the list of possible routers found
* for the various outgoing interfaces and find a candidate after
* the last chosen bonding candidate ( next_candidate ) . If no such
* router is found , use the first candidate found ( the previously
* chosen bonding candidate might have been the last one in the list ) .
2014-11-02 13:29:56 +03:00
* If this can ' t be found either , return the previously chosen
2013-11-13 22:14:50 +04:00
* router - obviously there are no other candidates .
*/
rcu_read_lock ( ) ;
last_candidate = orig_node - > last_bonding_candidate ;
if ( last_candidate )
last_cand_router = rcu_dereference ( last_candidate - > router ) ;
hlist_for_each_entry_rcu ( cand , & orig_node - > ifinfo_list , list ) {
/* acquire some structures and references ... */
if ( ! atomic_inc_not_zero ( & cand - > refcount ) )
continue ;
cand_router = rcu_dereference ( cand - > router ) ;
if ( ! cand_router )
goto next ;
if ( ! atomic_inc_not_zero ( & cand_router - > refcount ) ) {
cand_router = NULL ;
goto next ;
}
/* alternative candidate should be good enough to be
* considered
*/
if ( ! bao - > bat_neigh_is_equiv_or_better ( cand_router ,
cand - > if_outgoing ,
router , recv_if ) )
goto next ;
/* don't use the same router twice */
if ( last_cand_router = = cand_router )
goto next ;
/* mark the first possible candidate */
if ( ! first_candidate ) {
atomic_inc ( & cand_router - > refcount ) ;
atomic_inc ( & cand - > refcount ) ;
first_candidate = cand ;
first_candidate_router = cand_router ;
}
/* check if the loop has already passed the previously selected
* candidate . . . this function should select the next candidate
* AFTER the previously used bonding candidate .
*/
if ( ! last_candidate | | last_candidate_found ) {
next_candidate = cand ;
next_candidate_router = cand_router ;
break ;
}
if ( last_candidate = = cand )
last_candidate_found = true ;
next :
/* free references */
if ( cand_router ) {
batadv_neigh_node_free_ref ( cand_router ) ;
cand_router = NULL ;
}
batadv_orig_ifinfo_free_ref ( cand ) ;
}
rcu_read_unlock ( ) ;
/* last_bonding_candidate is reset below, remove the old reference. */
if ( orig_node - > last_bonding_candidate )
batadv_orig_ifinfo_free_ref ( orig_node - > last_bonding_candidate ) ;
/* After finding candidates, handle the three cases:
* 1 ) there is a next candidate , use that
* 2 ) there is no next candidate , use the first of the list
* 3 ) there is no candidate at all , return the default router
*/
if ( next_candidate ) {
batadv_neigh_node_free_ref ( router ) ;
/* remove references to first candidate, we don't need it. */
if ( first_candidate ) {
batadv_neigh_node_free_ref ( first_candidate_router ) ;
batadv_orig_ifinfo_free_ref ( first_candidate ) ;
}
router = next_candidate_router ;
orig_node - > last_bonding_candidate = next_candidate ;
} else if ( first_candidate ) {
batadv_neigh_node_free_ref ( router ) ;
/* refcounting has already been done in the loop above. */
router = first_candidate_router ;
orig_node - > last_bonding_candidate = first_candidate ;
} else {
orig_node - > last_bonding_candidate = NULL ;
}
2013-11-13 22:14:45 +04:00
2010-12-13 14:19:28 +03:00
return router ;
}
2012-05-16 22:23:13 +04:00
static int batadv_route_unicast_packet ( struct sk_buff * skb ,
2012-06-06 00:31:31 +04:00
struct batadv_hard_iface * recv_if )
2010-12-13 14:19:28 +03:00
{
2012-06-06 00:31:31 +04:00
struct batadv_priv * bat_priv = netdev_priv ( recv_if - > soft_iface ) ;
struct batadv_orig_node * orig_node = NULL ;
2012-06-06 00:31:30 +04:00
struct batadv_unicast_packet * unicast_packet ;
2013-04-08 17:08:18 +04:00
struct ethhdr * ethhdr = eth_hdr ( skb ) ;
2013-07-29 19:56:44 +04:00
int res , hdr_len , ret = NET_RX_DROP ;
2010-12-13 14:19:28 +03:00
2012-06-06 00:31:30 +04:00
unicast_packet = ( struct batadv_unicast_packet * ) skb - > data ;
2010-12-13 14:19:28 +03:00
/* TTL exceeded */
2013-12-02 23:38:31 +04:00
if ( unicast_packet - > ttl < 2 ) {
2012-03-07 12:07:45 +04:00
pr_debug ( " Warning - can't forward unicast packet from %pM to %pM: ttl exceeded \n " ,
ethhdr - > h_source , unicast_packet - > dest ) ;
2011-02-10 17:33:53 +03:00
goto out ;
2010-12-13 14:19:28 +03:00
}
/* get routing information */
2012-05-12 15:48:56 +04:00
orig_node = batadv_orig_hash_find ( bat_priv , unicast_packet - > dest ) ;
2011-02-18 15:28:09 +03:00
2011-02-10 17:33:53 +03:00
if ( ! orig_node )
2011-04-16 13:30:57 +04:00
goto out ;
2010-12-13 14:19:28 +03:00
/* create a copy of the skb, if needed, to modify it. */
2012-02-18 14:27:34 +04:00
if ( skb_cow ( skb , ETH_HLEN ) < 0 )
2011-02-10 17:33:53 +03:00
goto out ;
2010-12-13 14:19:28 +03:00
/* decrement ttl */
2013-05-23 18:53:01 +04:00
unicast_packet = ( struct batadv_unicast_packet * ) skb - > data ;
2013-12-02 23:38:31 +04:00
unicast_packet - > ttl - - ;
2010-12-13 14:19:28 +03:00
2013-12-02 23:38:31 +04:00
switch ( unicast_packet - > packet_type ) {
2013-07-29 19:56:44 +04:00
case BATADV_UNICAST_4ADDR :
hdr_len = sizeof ( struct batadv_unicast_4addr_packet ) ;
break ;
case BATADV_UNICAST :
hdr_len = sizeof ( struct batadv_unicast_packet ) ;
break ;
default :
/* other packet types not supported - yet */
hdr_len = - 1 ;
break ;
}
if ( hdr_len > 0 )
batadv_skb_set_priority ( skb , hdr_len ) ;
2013-04-20 15:54:39 +04:00
res = batadv_send_skb_to_orig ( skb , orig_node , recv_if ) ;
2013-01-25 14:12:40 +04:00
2013-04-20 15:54:39 +04:00
/* translate transmit result into receive result */
if ( res = = NET_XMIT_SUCCESS ) {
/* skb was transmitted and consumed */
2013-01-25 14:12:40 +04:00
batadv_inc_counter ( bat_priv , BATADV_CNT_FORWARD ) ;
batadv_add_counter ( bat_priv , BATADV_CNT_FORWARD_BYTES ,
skb - > len + ETH_HLEN ) ;
2013-04-20 15:54:39 +04:00
ret = NET_RX_SUCCESS ;
} else if ( res = = NET_XMIT_POLICED ) {
/* skb was buffered and consumed */
ret = NET_RX_SUCCESS ;
2013-01-25 14:12:40 +04:00
}
2010-12-13 14:19:28 +03:00
2011-02-10 17:33:53 +03:00
out :
if ( orig_node )
2012-05-12 04:09:34 +04:00
batadv_orig_node_free_ref ( orig_node ) ;
2011-02-10 17:33:53 +03:00
return ret ;
2010-12-13 14:19:28 +03:00
}
2012-09-24 00:38:34 +04:00
/**
* batadv_reroute_unicast_packet - update the unicast header for re - routing
* @ bat_priv : the bat priv with all the soft interface information
* @ unicast_packet : the unicast header to be updated
* @ dst_addr : the payload destination
2013-06-04 14:11:39 +04:00
* @ vid : VLAN identifier
2012-09-24 00:38:34 +04:00
*
* Search the translation table for dst_addr and update the unicast header with
* the new corresponding information ( originator address where the destination
* client currently is and its known TTVN )
*
* Returns true if the packet header has been updated , false otherwise
*/
static bool
batadv_reroute_unicast_packet ( struct batadv_priv * bat_priv ,
struct batadv_unicast_packet * unicast_packet ,
2013-06-04 14:11:39 +04:00
uint8_t * dst_addr , unsigned short vid )
2012-09-24 00:38:34 +04:00
{
struct batadv_orig_node * orig_node = NULL ;
struct batadv_hard_iface * primary_if = NULL ;
bool ret = false ;
uint8_t * orig_addr , orig_ttvn ;
2013-06-04 14:11:39 +04:00
if ( batadv_is_my_client ( bat_priv , dst_addr , vid ) ) {
2012-09-24 00:38:34 +04:00
primary_if = batadv_primary_if_get_selected ( bat_priv ) ;
if ( ! primary_if )
goto out ;
orig_addr = primary_if - > net_dev - > dev_addr ;
orig_ttvn = ( uint8_t ) atomic_read ( & bat_priv - > tt . vn ) ;
} else {
2013-06-04 14:11:39 +04:00
orig_node = batadv_transtable_search ( bat_priv , NULL , dst_addr ,
vid ) ;
2012-09-24 00:38:34 +04:00
if ( ! orig_node )
goto out ;
if ( batadv_compare_eth ( orig_node - > orig , unicast_packet - > dest ) )
goto out ;
orig_addr = orig_node - > orig ;
orig_ttvn = ( uint8_t ) atomic_read ( & orig_node - > last_ttvn ) ;
}
/* update the packet header */
2014-01-22 03:42:11 +04:00
ether_addr_copy ( unicast_packet - > dest , orig_addr ) ;
2012-09-24 00:38:34 +04:00
unicast_packet - > ttvn = orig_ttvn ;
ret = true ;
out :
if ( primary_if )
batadv_hardif_free_ref ( primary_if ) ;
if ( orig_node )
batadv_orig_node_free_ref ( orig_node ) ;
return ret ;
}
2012-06-06 00:31:31 +04:00
static int batadv_check_unicast_ttvn ( struct batadv_priv * bat_priv ,
2013-04-03 12:14:20 +04:00
struct sk_buff * skb , int hdr_len ) {
2013-06-04 14:11:39 +04:00
struct batadv_unicast_packet * unicast_packet ;
struct batadv_hard_iface * primary_if ;
2012-06-06 00:31:31 +04:00
struct batadv_orig_node * orig_node ;
2013-06-04 14:11:39 +04:00
uint8_t curr_ttvn , old_ttvn ;
2011-04-27 16:27:44 +04:00
struct ethhdr * ethhdr ;
2013-06-04 14:11:39 +04:00
unsigned short vid ;
2012-05-16 22:23:22 +04:00
int is_old_ttvn ;
2011-04-27 16:27:44 +04:00
2012-08-27 01:25:59 +04:00
/* check if there is enough data before accessing it */
2014-01-30 03:12:24 +04:00
if ( ! pskb_may_pull ( skb , hdr_len + ETH_HLEN ) )
2012-08-27 01:25:59 +04:00
return 0 ;
/* create a copy of the skb (in case of for re-routing) to modify it. */
if ( skb_cow ( skb , sizeof ( * unicast_packet ) ) < 0 )
2011-04-27 16:27:44 +04:00
return 0 ;
2012-06-06 00:31:30 +04:00
unicast_packet = ( struct batadv_unicast_packet * ) skb - > data ;
2013-06-04 14:11:39 +04:00
vid = batadv_get_vid ( skb , hdr_len ) ;
2013-04-03 12:14:20 +04:00
ethhdr = ( struct ethhdr * ) ( skb - > data + hdr_len ) ;
2011-04-27 16:27:44 +04:00
2012-09-24 00:38:34 +04:00
/* check if the destination client was served by this node and it is now
* roaming . In this case , it means that the node has got a ROAM_ADV
* message and that it knows the new destination in the mesh to re - route
* the packet to
*/
2013-06-04 14:11:39 +04:00
if ( batadv_tt_local_client_is_roaming ( bat_priv , ethhdr - > h_dest , vid ) ) {
2012-09-24 00:38:34 +04:00
if ( batadv_reroute_unicast_packet ( bat_priv , unicast_packet ,
2013-06-04 14:11:39 +04:00
ethhdr - > h_dest , vid ) )
2014-06-10 19:50:31 +04:00
batadv_dbg_ratelimited ( BATADV_DBG_TT ,
bat_priv ,
" Rerouting unicast packet to %pM (dst=%pM): Local Roaming \n " ,
unicast_packet - > dest ,
ethhdr - > h_dest ) ;
2012-09-24 00:38:34 +04:00
/* at this point the mesh destination should have been
* substituted with the originator address found in the global
* table . If not , let the packet go untouched anyway because
* there is nothing the node can do
*/
return 1 ;
}
/* retrieve the TTVN known by this node for the packet destination. This
* value is used later to check if the node which sent ( or re - routed
* last time ) the packet had an updated information or not
*/
curr_ttvn = ( uint8_t ) atomic_read ( & bat_priv - > tt . vn ) ;
2013-04-03 21:10:26 +04:00
if ( ! batadv_is_my_mac ( bat_priv , unicast_packet - > dest ) ) {
2012-05-12 15:48:56 +04:00
orig_node = batadv_orig_hash_find ( bat_priv ,
unicast_packet - > dest ) ;
2012-09-24 00:38:34 +04:00
/* if it is not possible to find the orig_node representing the
* destination , the packet can immediately be dropped as it will
* not be possible to deliver it
*/
2011-04-27 16:27:44 +04:00
if ( ! orig_node )
return 0 ;
curr_ttvn = ( uint8_t ) atomic_read ( & orig_node - > last_ttvn ) ;
2012-05-12 04:09:34 +04:00
batadv_orig_node_free_ref ( orig_node ) ;
2011-04-27 16:27:44 +04:00
}
2012-09-24 00:38:34 +04:00
/* check if the TTVN contained in the packet is fresher than what the
* node knows
*/
2012-05-16 22:23:22 +04:00
is_old_ttvn = batadv_seq_before ( unicast_packet - > ttvn , curr_ttvn ) ;
2012-09-24 00:38:34 +04:00
if ( ! is_old_ttvn )
return 1 ;
2011-04-27 16:27:44 +04:00
2012-09-24 00:38:34 +04:00
old_ttvn = unicast_packet - > ttvn ;
/* the packet was forged based on outdated network information. Its
* destination can possibly be updated and forwarded towards the new
* target host
*/
if ( batadv_reroute_unicast_packet ( bat_priv , unicast_packet ,
2013-06-04 14:11:39 +04:00
ethhdr - > h_dest , vid ) ) {
2014-06-10 19:50:31 +04:00
batadv_dbg_ratelimited ( BATADV_DBG_TT , bat_priv ,
" Rerouting unicast packet to %pM (dst=%pM): TTVN mismatch old_ttvn=%u new_ttvn=%u \n " ,
unicast_packet - > dest , ethhdr - > h_dest ,
old_ttvn , curr_ttvn ) ;
2012-09-24 00:38:34 +04:00
return 1 ;
}
2012-03-16 21:03:28 +04:00
2012-09-24 00:38:34 +04:00
/* the packet has not been re-routed: either the destination is
* currently served by this node or there is no destination at all and
* it is possible to drop the packet
*/
2013-06-04 14:11:39 +04:00
if ( ! batadv_is_my_client ( bat_priv , ethhdr - > h_dest , vid ) )
2012-09-24 00:38:34 +04:00
return 0 ;
2012-03-16 21:03:28 +04:00
2012-09-24 00:38:34 +04:00
/* update the header in order to let the packet be delivered to this
* node ' s soft interface
*/
primary_if = batadv_primary_if_get_selected ( bat_priv ) ;
if ( ! primary_if )
return 0 ;
2011-04-27 16:27:44 +04:00
2014-01-22 03:42:11 +04:00
ether_addr_copy ( unicast_packet - > dest , primary_if - > net_dev - > dev_addr ) ;
2012-09-24 00:38:34 +04:00
batadv_hardif_free_ref ( primary_if ) ;
unicast_packet - > ttvn = curr_ttvn ;
2011-04-27 16:27:44 +04:00
return 1 ;
}
2013-04-25 12:37:23 +04:00
/**
* batadv_recv_unhandled_unicast_packet - receive and process packets which
* are in the unicast number space but not yet known to the implementation
* @ skb : unicast tvlv packet to process
* @ recv_if : pointer to interface this packet was received on
*
* Returns NET_RX_SUCCESS if the packet has been consumed or NET_RX_DROP
* otherwise .
*/
int batadv_recv_unhandled_unicast_packet ( struct sk_buff * skb ,
struct batadv_hard_iface * recv_if )
{
struct batadv_unicast_packet * unicast_packet ;
struct batadv_priv * bat_priv = netdev_priv ( recv_if - > soft_iface ) ;
int check , hdr_size = sizeof ( * unicast_packet ) ;
check = batadv_check_unicast_packet ( bat_priv , skb , hdr_size ) ;
if ( check < 0 )
return NET_RX_DROP ;
/* we don't know about this type, drop it. */
unicast_packet = ( struct batadv_unicast_packet * ) skb - > data ;
if ( batadv_is_my_mac ( bat_priv , unicast_packet - > dest ) )
return NET_RX_DROP ;
return batadv_route_unicast_packet ( skb , recv_if ) ;
}
2012-06-06 00:31:31 +04:00
int batadv_recv_unicast_packet ( struct sk_buff * skb ,
struct batadv_hard_iface * recv_if )
2010-12-13 14:19:28 +03:00
{
2012-06-06 00:31:31 +04:00
struct batadv_priv * bat_priv = netdev_priv ( recv_if - > soft_iface ) ;
2012-06-06 00:31:30 +04:00
struct batadv_unicast_packet * unicast_packet ;
2012-04-20 19:02:45 +04:00
struct batadv_unicast_4addr_packet * unicast_4addr_packet ;
2012-10-14 19:19:19 +04:00
uint8_t * orig_addr ;
struct batadv_orig_node * orig_node = NULL ;
2013-01-25 14:12:42 +04:00
int check , hdr_size = sizeof ( * unicast_packet ) ;
2011-06-26 05:37:18 +04:00
bool is4addr ;
2010-12-13 14:19:28 +03:00
2012-10-01 11:57:35 +04:00
unicast_packet = ( struct batadv_unicast_packet * ) skb - > data ;
2012-04-20 19:02:45 +04:00
unicast_4addr_packet = ( struct batadv_unicast_4addr_packet * ) skb - > data ;
2012-10-01 11:57:35 +04:00
2013-12-02 23:38:31 +04:00
is4addr = unicast_packet - > packet_type = = BATADV_UNICAST_4ADDR ;
2012-10-01 11:57:35 +04:00
/* the caller function should have already pulled 2 bytes */
2011-06-26 05:37:18 +04:00
if ( is4addr )
2012-04-20 19:02:45 +04:00
hdr_size = sizeof ( * unicast_4addr_packet ) ;
2012-10-01 11:57:35 +04:00
2013-01-25 14:12:42 +04:00
/* function returns -EREMOTE for promiscuous packets */
2013-04-23 04:32:51 +04:00
check = batadv_check_unicast_packet ( bat_priv , skb , hdr_size ) ;
2013-01-25 14:12:42 +04:00
/* Even though the packet is not for us, we might save it to use for
* decoding a later received coded packet
*/
if ( check = = - EREMOTE )
batadv_nc_skb_store_sniffed_unicast ( bat_priv , skb ) ;
if ( check < 0 )
2010-12-13 14:19:28 +03:00
return NET_RX_DROP ;
2013-04-03 12:14:20 +04:00
if ( ! batadv_check_unicast_ttvn ( bat_priv , skb , hdr_size ) )
2011-04-27 16:27:44 +04:00
return NET_RX_DROP ;
2010-12-13 14:19:28 +03:00
/* packet for me */
2013-04-03 21:10:26 +04:00
if ( batadv_is_my_mac ( bat_priv , unicast_packet - > dest ) ) {
2012-10-14 19:19:19 +04:00
if ( is4addr ) {
2012-04-20 19:02:45 +04:00
batadv_dat_inc_counter ( bat_priv ,
unicast_4addr_packet - > subtype ) ;
2012-10-14 19:19:19 +04:00
orig_addr = unicast_4addr_packet - > src ;
orig_node = batadv_orig_hash_find ( bat_priv , orig_addr ) ;
}
2012-04-20 19:02:45 +04:00
2011-06-26 05:37:18 +04:00
if ( batadv_dat_snoop_incoming_arp_request ( bat_priv , skb ,
hdr_size ) )
goto rx_success ;
if ( batadv_dat_snoop_incoming_arp_reply ( bat_priv , skb ,
hdr_size ) )
goto rx_success ;
2012-07-06 01:38:30 +04:00
batadv_interface_rx ( recv_if - > soft_iface , skb , recv_if , hdr_size ,
2012-10-14 19:19:19 +04:00
orig_node ) ;
2012-07-06 01:38:30 +04:00
2011-06-26 05:37:18 +04:00
rx_success :
2012-10-14 19:19:19 +04:00
if ( orig_node )
batadv_orig_node_free_ref ( orig_node ) ;
2010-12-13 14:19:28 +03:00
return NET_RX_SUCCESS ;
}
2012-05-16 22:23:13 +04:00
return batadv_route_unicast_packet ( skb , recv_if ) ;
2010-12-13 14:19:28 +03:00
}
2013-04-23 17:39:57 +04:00
/**
* batadv_recv_unicast_tvlv - receive and process unicast tvlv packets
* @ skb : unicast tvlv packet to process
* @ recv_if : pointer to interface this packet was received on
* @ dst_addr : the payload destination
*
* Returns NET_RX_SUCCESS if the packet has been consumed or NET_RX_DROP
* otherwise .
*/
int batadv_recv_unicast_tvlv ( struct sk_buff * skb ,
struct batadv_hard_iface * recv_if )
{
struct batadv_priv * bat_priv = netdev_priv ( recv_if - > soft_iface ) ;
struct batadv_unicast_tvlv_packet * unicast_tvlv_packet ;
unsigned char * tvlv_buff ;
uint16_t tvlv_buff_len ;
int hdr_size = sizeof ( * unicast_tvlv_packet ) ;
int ret = NET_RX_DROP ;
if ( batadv_check_unicast_packet ( bat_priv , skb , hdr_size ) < 0 )
return NET_RX_DROP ;
/* the header is likely to be modified while forwarding */
if ( skb_cow ( skb , hdr_size ) < 0 )
return NET_RX_DROP ;
/* packet needs to be linearized to access the tvlv content */
if ( skb_linearize ( skb ) < 0 )
return NET_RX_DROP ;
unicast_tvlv_packet = ( struct batadv_unicast_tvlv_packet * ) skb - > data ;
tvlv_buff = ( unsigned char * ) ( skb - > data + hdr_size ) ;
tvlv_buff_len = ntohs ( unicast_tvlv_packet - > tvlv_len ) ;
if ( tvlv_buff_len > skb - > len - hdr_size )
return NET_RX_DROP ;
ret = batadv_tvlv_containers_process ( bat_priv , false , NULL ,
unicast_tvlv_packet - > src ,
unicast_tvlv_packet - > dst ,
tvlv_buff , tvlv_buff_len ) ;
if ( ret ! = NET_RX_SUCCESS )
ret = batadv_route_unicast_packet ( skb , recv_if ) ;
2014-02-11 20:05:07 +04:00
else
consume_skb ( skb ) ;
2013-04-23 17:39:57 +04:00
return ret ;
}
2010-12-13 14:19:28 +03:00
2013-05-23 18:53:02 +04:00
/**
* batadv_recv_frag_packet - process received fragment
* @ skb : the received fragment
* @ recv_if : interface that the skb is received on
*
* This function does one of the three following things : 1 ) Forward fragment , if
* the assembled packet will exceed our MTU ; 2 ) Buffer fragment , if we till
* lack further fragments ; 3 ) Merge fragments , if we have all needed parts .
*
* Return NET_RX_DROP if the skb is not consumed , NET_RX_SUCCESS otherwise .
*/
int batadv_recv_frag_packet ( struct sk_buff * skb ,
struct batadv_hard_iface * recv_if )
{
struct batadv_priv * bat_priv = netdev_priv ( recv_if - > soft_iface ) ;
struct batadv_orig_node * orig_node_src = NULL ;
struct batadv_frag_packet * frag_packet ;
int ret = NET_RX_DROP ;
if ( batadv_check_unicast_packet ( bat_priv , skb ,
sizeof ( * frag_packet ) ) < 0 )
goto out ;
frag_packet = ( struct batadv_frag_packet * ) skb - > data ;
orig_node_src = batadv_orig_hash_find ( bat_priv , frag_packet - > orig ) ;
if ( ! orig_node_src )
goto out ;
/* Route the fragment if it is not for us and too big to be merged. */
if ( ! batadv_is_my_mac ( bat_priv , frag_packet - > dest ) & &
batadv_frag_skb_fwd ( skb , recv_if , orig_node_src ) ) {
ret = NET_RX_SUCCESS ;
goto out ;
}
batadv_inc_counter ( bat_priv , BATADV_CNT_FRAG_RX ) ;
batadv_add_counter ( bat_priv , BATADV_CNT_FRAG_RX_BYTES , skb - > len ) ;
/* Add fragment to buffer and merge if possible. */
if ( ! batadv_frag_skb_buffer ( & skb , orig_node_src ) )
goto out ;
/* Deliver merged packet to the appropriate handler, if it was
* merged
*/
if ( skb )
batadv_batman_skb_recv ( skb , recv_if - > net_dev ,
& recv_if - > batman_adv_ptype , NULL ) ;
ret = NET_RX_SUCCESS ;
out :
if ( orig_node_src )
batadv_orig_node_free_ref ( orig_node_src ) ;
return ret ;
}
2012-06-06 00:31:31 +04:00
int batadv_recv_bcast_packet ( struct sk_buff * skb ,
struct batadv_hard_iface * recv_if )
2010-12-13 14:19:28 +03:00
{
2012-06-06 00:31:31 +04:00
struct batadv_priv * bat_priv = netdev_priv ( recv_if - > soft_iface ) ;
struct batadv_orig_node * orig_node = NULL ;
2012-06-06 00:31:30 +04:00
struct batadv_bcast_packet * bcast_packet ;
2010-12-13 14:19:28 +03:00
struct ethhdr * ethhdr ;
2011-05-15 01:14:54 +04:00
int hdr_size = sizeof ( * bcast_packet ) ;
2011-01-26 00:52:11 +03:00
int ret = NET_RX_DROP ;
2010-12-13 14:19:28 +03:00
int32_t seq_diff ;
2013-10-13 04:50:17 +04:00
uint32_t seqno ;
2010-12-13 14:19:28 +03:00
/* drop packet if it has not necessary minimum size */
if ( unlikely ( ! pskb_may_pull ( skb , hdr_size ) ) )
2011-01-26 00:52:11 +03:00
goto out ;
2010-12-13 14:19:28 +03:00
2013-04-08 17:08:18 +04:00
ethhdr = eth_hdr ( skb ) ;
2010-12-13 14:19:28 +03:00
/* packet with broadcast indication but unicast recipient */
if ( ! is_broadcast_ether_addr ( ethhdr - > h_dest ) )
2011-01-26 00:52:11 +03:00
goto out ;
2010-12-13 14:19:28 +03:00
/* packet with broadcast sender address */
if ( is_broadcast_ether_addr ( ethhdr - > h_source ) )
2011-01-26 00:52:11 +03:00
goto out ;
2010-12-13 14:19:28 +03:00
/* ignore broadcasts sent by myself */
2013-04-03 21:10:26 +04:00
if ( batadv_is_my_mac ( bat_priv , ethhdr - > h_source ) )
2011-01-26 00:52:11 +03:00
goto out ;
2010-12-13 14:19:28 +03:00
2012-06-06 00:31:30 +04:00
bcast_packet = ( struct batadv_bcast_packet * ) skb - > data ;
2010-12-13 14:19:28 +03:00
/* ignore broadcasts originated by myself */
2013-04-03 21:10:26 +04:00
if ( batadv_is_my_mac ( bat_priv , bcast_packet - > orig ) )
2011-01-26 00:52:11 +03:00
goto out ;
2010-12-13 14:19:28 +03:00
2013-12-02 23:38:31 +04:00
if ( bcast_packet - > ttl < 2 )
2011-01-26 00:52:11 +03:00
goto out ;
2010-12-13 14:19:28 +03:00
2012-05-12 15:48:56 +04:00
orig_node = batadv_orig_hash_find ( bat_priv , bcast_packet - > orig ) ;
2011-01-26 00:52:11 +03:00
if ( ! orig_node )
2011-04-16 13:30:57 +04:00
goto out ;
2010-12-13 14:19:28 +03:00
2011-01-26 00:52:11 +03:00
spin_lock_bh ( & orig_node - > bcast_seqno_lock ) ;
2010-12-13 14:19:28 +03:00
2013-10-13 04:50:17 +04:00
seqno = ntohl ( bcast_packet - > seqno ) ;
2010-12-13 14:19:28 +03:00
/* check whether the packet is a duplicate */
2012-05-12 15:48:53 +04:00
if ( batadv_test_bit ( orig_node - > bcast_bits , orig_node - > last_bcast_seqno ,
2013-10-13 04:50:17 +04:00
seqno ) )
2011-01-26 00:52:11 +03:00
goto spin_unlock ;
2010-12-13 14:19:28 +03:00
2013-10-13 04:50:17 +04:00
seq_diff = seqno - orig_node - > last_bcast_seqno ;
2010-12-13 14:19:28 +03:00
/* check whether the packet is old and the host just restarted. */
2012-05-12 04:09:36 +04:00
if ( batadv_window_protected ( bat_priv , seq_diff ,
& orig_node - > bcast_seqno_reset ) )
2011-01-26 00:52:11 +03:00
goto spin_unlock ;
2010-12-13 14:19:28 +03:00
/* mark broadcast in flood history, update window position
2012-05-12 04:09:43 +04:00
* if required .
*/
2012-05-12 04:09:25 +04:00
if ( batadv_bit_get_packet ( bat_priv , orig_node - > bcast_bits , seq_diff , 1 ) )
2013-10-13 04:50:17 +04:00
orig_node - > last_bcast_seqno = seqno ;
2010-12-13 14:19:28 +03:00
2011-01-26 00:52:11 +03:00
spin_unlock_bh ( & orig_node - > bcast_seqno_lock ) ;
2012-01-22 23:00:24 +04:00
/* check whether this has been sent by another originator before */
2012-10-18 15:47:42 +04:00
if ( batadv_bla_check_bcast_duplist ( bat_priv , skb ) )
2012-01-22 23:00:24 +04:00
goto out ;
2013-07-29 19:56:44 +04:00
batadv_skb_set_priority ( skb , sizeof ( struct batadv_bcast_packet ) ) ;
2010-12-13 14:19:28 +03:00
/* rebroadcast packet */
2012-05-12 04:09:37 +04:00
batadv_add_bcast_packet_to_list ( bat_priv , skb , 1 ) ;
2010-12-13 14:19:28 +03:00
2012-01-22 23:00:19 +04:00
/* don't hand the broadcast up if it is from an originator
* from the same backbone .
*/
2012-05-12 15:38:47 +04:00
if ( batadv_bla_is_backbone_gw ( skb , orig_node , hdr_size ) )
2012-01-22 23:00:19 +04:00
goto out ;
2011-06-26 05:37:18 +04:00
if ( batadv_dat_snoop_incoming_arp_request ( bat_priv , skb , hdr_size ) )
goto rx_success ;
if ( batadv_dat_snoop_incoming_arp_reply ( bat_priv , skb , hdr_size ) )
goto rx_success ;
2010-12-13 14:19:28 +03:00
/* broadcast for me */
2012-07-06 01:38:30 +04:00
batadv_interface_rx ( recv_if - > soft_iface , skb , recv_if , hdr_size ,
orig_node ) ;
2011-06-26 05:37:18 +04:00
rx_success :
2011-01-26 00:52:11 +03:00
ret = NET_RX_SUCCESS ;
goto out ;
2010-12-13 14:19:28 +03:00
2011-01-26 00:52:11 +03:00
spin_unlock :
spin_unlock_bh ( & orig_node - > bcast_seqno_lock ) ;
out :
if ( orig_node )
2012-05-12 04:09:34 +04:00
batadv_orig_node_free_ref ( orig_node ) ;
2011-01-26 00:52:11 +03:00
return ret ;
2010-12-13 14:19:28 +03:00
}