2012-05-12 04:09:43 +04:00
/* Copyright (C) 2007-2012 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 "routing.h"
# include "send.h"
# include "soft-interface.h"
# include "hard-interface.h"
# include "icmp_socket.h"
# include "translation-table.h"
# include "originator.h"
# include "vis.h"
# include "unicast.h"
2012-01-22 23:00:19 +04:00
# include "bridge_loop_avoidance.h"
2010-12-13 14:19:28 +03:00
2012-05-16 22:23:13 +04:00
static int batadv_route_unicast_packet ( struct sk_buff * skb ,
struct hard_iface * recv_if ) ;
2012-01-22 23:00:18 +04:00
2012-05-12 04:09:36 +04:00
void batadv_slide_own_bcast_window ( struct hard_iface * hard_iface )
2010-12-13 14:19:28 +03:00
{
2011-02-18 15:33:20 +03:00
struct bat_priv * bat_priv = netdev_priv ( hard_iface - > soft_iface ) ;
2010-12-13 14:19:28 +03:00
struct hashtable_t * hash = bat_priv - > orig_hash ;
2011-02-18 15:28:09 +03:00
struct hlist_node * node ;
2010-12-13 14:19:28 +03:00
struct hlist_head * head ;
struct orig_node * orig_node ;
unsigned long * word ;
2011-10-05 19:05:25 +04:00
uint32_t i ;
2010-12-13 14:19:28 +03:00
size_t word_index ;
2012-06-04 00:19:17 +04:00
uint8_t * w ;
2010-12-13 14:19:28 +03:00
for ( i = 0 ; i < hash - > size ; i + + ) {
head = & hash - > table [ i ] ;
2011-01-19 23:01:40 +03:00
rcu_read_lock ( ) ;
2011-02-18 15:28:09 +03:00
hlist_for_each_entry_rcu ( orig_node , node , head , hash_entry ) {
2011-01-19 23:01:42 +03:00
spin_lock_bh ( & orig_node - > ogm_cnt_lock ) ;
2012-06-04 00:19:17 +04:00
word_index = hard_iface - > if_num * BATADV_NUM_WORDS ;
2010-12-13 14:19:28 +03:00
word = & ( orig_node - > bcast_own [ word_index ] ) ;
2012-05-12 04:09:25 +04:00
batadv_bit_get_packet ( bat_priv , word , 1 , 0 ) ;
2012-06-04 00:19:17 +04:00
w = & orig_node - > bcast_own_sum [ hard_iface - > if_num ] ;
* w = bitmap_weight ( word , BATADV_TQ_LOCAL_WINDOW_SIZE ) ;
2011-01-19 23:01:42 +03:00
spin_unlock_bh ( & orig_node - > ogm_cnt_lock ) ;
2010-12-13 14:19:28 +03:00
}
2011-01-19 23:01:40 +03:00
rcu_read_unlock ( ) ;
2010-12-13 14:19:28 +03:00
}
}
2012-05-16 22:23:13 +04:00
static void _batadv_update_route ( struct bat_priv * bat_priv ,
struct orig_node * orig_node ,
struct neigh_node * neigh_node )
2010-12-13 14:19:28 +03:00
{
2011-03-15 01:43:37 +03:00
struct neigh_node * curr_router ;
2012-05-12 04:09:34 +04:00
curr_router = batadv_orig_node_get_router ( orig_node ) ;
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 ) ;
2012-05-12 04:09:39 +04:00
batadv_tt_global_del_orig ( bat_priv , orig_node ,
" 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 ) ) {
2010-12-13 14:19:28 +03:00
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 ) ;
rcu_assign_pointer ( orig_node - > router , neigh_node ) ;
spin_unlock_bh ( & orig_node - > neigh_list_lock ) ;
/* 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
}
2012-05-12 04:09:36 +04:00
void batadv_update_route ( struct bat_priv * bat_priv , struct orig_node * orig_node ,
struct neigh_node * neigh_node )
2010-12-13 14:19:28 +03:00
{
2011-03-15 01:43:37 +03:00
struct 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 ;
2012-05-12 04:09:34 +04:00
router = batadv_orig_node_get_router ( orig_node ) ;
2010-12-13 14:19:28 +03:00
2011-03-15 01:43:37 +03:00
if ( router ! = neigh_node )
2012-05-16 22:23:13 +04:00
_batadv_update_route ( bat_priv , orig_node , 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
}
2011-01-19 23:01:43 +03:00
/* caller must hold the neigh_list_lock */
2012-05-12 04:09:36 +04:00
void batadv_bonding_candidate_del ( struct orig_node * orig_node ,
struct neigh_node * neigh_node )
2011-01-19 23:01:43 +03:00
{
/* this neighbor is not part of our candidate list */
if ( list_empty ( & neigh_node - > bonding_list ) )
goto out ;
list_del_rcu ( & neigh_node - > bonding_list ) ;
INIT_LIST_HEAD ( & neigh_node - > bonding_list ) ;
2012-05-12 04:09:34 +04:00
batadv_neigh_node_free_ref ( neigh_node ) ;
2011-01-19 23:01:43 +03:00
atomic_dec ( & orig_node - > bond_candidates ) ;
out :
return ;
}
2012-05-12 04:09:36 +04:00
void batadv_bonding_candidate_add ( struct orig_node * orig_node ,
struct neigh_node * neigh_node )
2011-01-19 23:01:43 +03:00
{
struct hlist_node * node ;
2011-03-15 01:43:37 +03:00
struct neigh_node * tmp_neigh_node , * router = NULL ;
uint8_t interference_candidate = 0 ;
2011-01-19 23:01:43 +03:00
spin_lock_bh ( & orig_node - > neigh_list_lock ) ;
/* only consider if it has the same primary address ... */
2012-05-12 15:48:58 +04:00
if ( ! batadv_compare_eth ( orig_node - > orig ,
neigh_node - > orig_node - > primary_addr ) )
2011-01-19 23:01:43 +03:00
goto candidate_del ;
2012-05-12 04:09:34 +04:00
router = batadv_orig_node_get_router ( orig_node ) ;
2011-03-15 01:43:37 +03:00
if ( ! router )
2011-01-19 23:01:43 +03:00
goto candidate_del ;
/* ... and is good enough to be considered */
2012-06-04 00:19:17 +04:00
if ( neigh_node - > tq_avg < router - > tq_avg - BATADV_BONDING_TQ_THRESHOLD )
2011-01-19 23:01:43 +03:00
goto candidate_del ;
2012-05-12 04:09:43 +04:00
/* check if we have another candidate with the same mac address or
2011-01-19 23:01:43 +03:00
* interface . If we do , we won ' t select this candidate because of
* possible interference .
*/
hlist_for_each_entry_rcu ( tmp_neigh_node , node ,
& orig_node - > neigh_list , list ) {
if ( tmp_neigh_node = = neigh_node )
continue ;
/* we only care if the other candidate is even
2012-05-12 04:09:43 +04:00
* considered as candidate .
*/
2011-01-19 23:01:43 +03:00
if ( list_empty ( & tmp_neigh_node - > bonding_list ) )
continue ;
if ( ( neigh_node - > if_incoming = = tmp_neigh_node - > if_incoming ) | |
2012-05-12 15:48:58 +04:00
( batadv_compare_eth ( neigh_node - > addr ,
tmp_neigh_node - > addr ) ) ) {
2011-01-19 23:01:43 +03:00
interference_candidate = 1 ;
break ;
}
}
/* don't care further if it is an interference candidate */
if ( interference_candidate )
goto candidate_del ;
/* this neighbor already is part of our candidate list */
if ( ! list_empty ( & neigh_node - > bonding_list ) )
goto out ;
2011-02-10 17:33:53 +03:00
if ( ! atomic_inc_not_zero ( & neigh_node - > refcount ) )
goto out ;
2011-01-19 23:01:43 +03:00
list_add_rcu ( & neigh_node - > bonding_list , & orig_node - > bond_list ) ;
atomic_inc ( & orig_node - > bond_candidates ) ;
goto out ;
candidate_del :
2012-05-12 04:09:36 +04:00
batadv_bonding_candidate_del ( orig_node , neigh_node ) ;
2011-01-19 23:01:43 +03:00
out :
spin_unlock_bh ( & orig_node - > neigh_list_lock ) ;
2011-03-15 01:43:37 +03:00
if ( router )
2012-05-12 04:09:34 +04:00
batadv_neigh_node_free_ref ( router ) ;
2011-01-19 23:01:43 +03:00
}
/* copy primary address for bonding */
2012-05-12 04:09:36 +04:00
void
batadv_bonding_save_primary ( const struct orig_node * orig_node ,
struct orig_node * orig_neigh_node ,
const struct batman_ogm_packet * batman_ogm_packet )
2011-01-19 23:01:43 +03:00
{
2012-06-04 00:19:21 +04:00
if ( ! ( batman_ogm_packet - > flags & BATADV_PRIMARIES_FIRST_HOP ) )
2011-01-19 23:01:43 +03:00
return ;
memcpy ( orig_neigh_node - > primary_addr , orig_node - > orig , ETH_ALEN ) ;
}
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-05-12 04:09:36 +04:00
int batadv_window_protected ( struct bat_priv * bat_priv , int32_t seq_num_diff ,
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 ,
struct hard_iface * hard_iface ,
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
ethhdr = ( struct ethhdr * ) skb_mac_header ( skb ) ;
/* 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
}
2012-05-16 22:23:13 +04:00
static int batadv_recv_my_icmp_packet ( struct bat_priv * bat_priv ,
struct sk_buff * skb , size_t icmp_len )
2010-12-13 14:19:28 +03:00
{
2011-04-20 17:40:58 +04:00
struct hard_iface * primary_if = NULL ;
2011-02-10 17:33:53 +03:00
struct orig_node * orig_node = NULL ;
2011-03-15 01:43:37 +03:00
struct neigh_node * router = NULL ;
2010-12-13 14:19:28 +03:00
struct icmp_packet_rr * icmp_packet ;
2011-02-10 17:33:53 +03:00
int ret = NET_RX_DROP ;
2010-12-13 14:19:28 +03:00
icmp_packet = ( struct icmp_packet_rr * ) skb - > data ;
/* add data to device queue */
2012-06-04 00:19:21 +04:00
if ( icmp_packet - > msg_type ! = BATADV_ECHO_REQUEST ) {
2012-05-12 04:09:33 +04:00
batadv_socket_receive_packet ( icmp_packet , icmp_len ) ;
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
/* answer echo request (ping) */
/* get routing information */
2012-05-12 15:48:56 +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
2012-05-12 04:09:34 +04:00
router = batadv_orig_node_get_router ( orig_node ) ;
2011-03-15 01:43:37 +03:00
if ( ! router )
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 ;
icmp_packet = ( struct icmp_packet_rr * ) skb - > data ;
memcpy ( icmp_packet - > dst , icmp_packet - > orig , ETH_ALEN ) ;
2011-04-20 17:40:58 +04:00
memcpy ( icmp_packet - > orig , primary_if - > net_dev - > dev_addr , ETH_ALEN ) ;
2012-06-04 00:19:21 +04:00
icmp_packet - > msg_type = BATADV_ECHO_REPLY ;
2012-06-04 00:19:17 +04:00
icmp_packet - > header . ttl = BATADV_TTL ;
2011-02-10 17:33:53 +03:00
2012-05-12 04:09:37 +04:00
batadv_send_skb_packet ( skb , router - > if_incoming , router - > addr ) ;
2011-02-10 17:33:53 +03: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-03-15 01:43:37 +03:00
if ( router )
2012-05-12 04:09:34 +04:00
batadv_neigh_node_free_ref ( router ) ;
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-05-16 22:23:13 +04:00
static int batadv_recv_icmp_ttl_exceeded ( struct bat_priv * bat_priv ,
struct sk_buff * skb )
2010-12-13 14:19:28 +03:00
{
2011-04-20 17:40:58 +04:00
struct hard_iface * primary_if = NULL ;
2011-02-10 17:33:53 +03:00
struct orig_node * orig_node = NULL ;
2011-03-15 01:43:37 +03:00
struct neigh_node * router = NULL ;
2010-12-13 14:19:28 +03:00
struct 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
icmp_packet = ( struct icmp_packet * ) skb - > data ;
/* send TTL exceeded if packet is an echo request (traceroute) */
2012-06-04 00:19:21 +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 " ,
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 */
2012-05-12 15:48:56 +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
2012-05-12 04:09:34 +04:00
router = batadv_orig_node_get_router ( orig_node ) ;
2011-03-15 01:43:37 +03:00
if ( ! router )
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
2011-02-10 17:33:53 +03:00
icmp_packet = ( struct icmp_packet * ) skb - > data ;
2010-12-13 14:19:28 +03:00
2011-02-10 17:33:53 +03:00
memcpy ( icmp_packet - > dst , icmp_packet - > orig , ETH_ALEN ) ;
2011-04-20 17:40:58 +04:00
memcpy ( icmp_packet - > orig , primary_if - > net_dev - > dev_addr , ETH_ALEN ) ;
2012-06-04 00:19:21 +04:00
icmp_packet - > msg_type = BATADV_TTL_EXCEEDED ;
2012-06-04 00:19:17 +04:00
icmp_packet - > header . ttl = BATADV_TTL ;
2011-02-10 17:33:53 +03:00
2012-05-12 04:09:37 +04:00
batadv_send_skb_packet ( skb , router - > if_incoming , router - > addr ) ;
2011-02-10 17:33:53 +03: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-03-15 01:43:37 +03:00
if ( router )
2012-05-12 04:09:34 +04:00
batadv_neigh_node_free_ref ( router ) ;
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-05-12 04:09:36 +04:00
int batadv_recv_icmp_packet ( struct sk_buff * skb , struct hard_iface * recv_if )
2010-12-13 14:19:28 +03:00
{
struct bat_priv * bat_priv = netdev_priv ( recv_if - > soft_iface ) ;
struct icmp_packet_rr * icmp_packet ;
struct ethhdr * ethhdr ;
2011-02-10 17:33:53 +03:00
struct orig_node * orig_node = NULL ;
2011-03-15 01:43:37 +03:00
struct neigh_node * router = NULL ;
2010-12-13 14:19:28 +03:00
int hdr_size = sizeof ( struct icmp_packet ) ;
2011-02-10 17:33:53 +03:00
int ret = NET_RX_DROP ;
2010-12-13 14:19:28 +03:00
2012-05-12 04:09:43 +04:00
/* we truncate all incoming icmp packets if they don't match our size */
2010-12-13 14:19:28 +03:00
if ( skb - > len > = sizeof ( struct icmp_packet_rr ) )
hdr_size = sizeof ( struct icmp_packet_rr ) ;
/* 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
ethhdr = ( struct ethhdr * ) skb_mac_header ( skb ) ;
/* 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 */
2012-05-12 04:09:42 +04:00
if ( ! batadv_is_my_mac ( ethhdr - > h_dest ) )
2011-02-10 17:33:53 +03:00
goto out ;
2010-12-13 14:19:28 +03:00
icmp_packet = ( struct icmp_packet_rr * ) skb - > data ;
/* add record route information if not full */
if ( ( hdr_size = = sizeof ( struct icmp_packet_rr ) ) & &
2012-06-04 00:19:13 +04:00
( icmp_packet - > rr_cur < BATADV_RR_LEN ) ) {
2010-12-13 14:19:28 +03:00
memcpy ( & ( icmp_packet - > rr [ icmp_packet - > rr_cur ] ) ,
2012-02-28 13:55:36 +04:00
ethhdr - > h_dest , ETH_ALEN ) ;
2010-12-13 14:19:28 +03:00
icmp_packet - > rr_cur + + ;
}
/* packet for me */
2012-05-12 04:09:42 +04:00
if ( batadv_is_my_mac ( icmp_packet - > dst ) )
2012-05-16 22:23:13 +04:00
return batadv_recv_my_icmp_packet ( bat_priv , skb , hdr_size ) ;
2010-12-13 14:19:28 +03:00
/* TTL exceeded */
2011-11-20 18:47:38 +04:00
if ( icmp_packet - > header . 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 */
2012-05-12 15:48:56 +04:00
orig_node = batadv_orig_hash_find ( bat_priv , icmp_packet - > 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
2012-05-12 04:09:34 +04:00
router = batadv_orig_node_get_router ( orig_node ) ;
2011-03-15 01:43:37 +03:00
if ( ! router )
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
2011-02-10 17:33:53 +03:00
icmp_packet = ( struct icmp_packet_rr * ) skb - > data ;
2010-12-13 14:19:28 +03:00
2011-02-10 17:33:53 +03:00
/* decrement ttl */
2011-11-20 18:47:38 +04:00
icmp_packet - > header . ttl - - ;
2011-02-10 17:33:53 +03:00
/* route it */
2012-05-12 04:09:37 +04:00
batadv_send_skb_packet ( skb , router - > if_incoming , router - > addr ) ;
2011-02-10 17:33:53 +03:00
ret = NET_RX_SUCCESS ;
2010-12-13 14:19:28 +03:00
2011-02-10 17:33:53 +03:00
out :
2011-03-15 01:43:37 +03:00
if ( router )
2012-05-12 04:09:34 +04:00
batadv_neigh_node_free_ref ( router ) ;
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 ;
}
2011-03-15 01:43:27 +03:00
/* In the bonding case, send the packets in a round
* robin fashion over the remaining interfaces .
*
* This method rotates the bonding list and increases the
2012-05-12 04:09:43 +04:00
* returned router ' s refcount .
*/
2012-05-16 22:23:13 +04:00
static struct neigh_node *
batadv_find_bond_router ( struct orig_node * primary_orig ,
const struct hard_iface * recv_if )
2011-03-15 01:43:27 +03:00
{
struct neigh_node * tmp_neigh_node ;
struct neigh_node * router = NULL , * first_candidate = NULL ;
rcu_read_lock ( ) ;
list_for_each_entry_rcu ( tmp_neigh_node , & primary_orig - > bond_list ,
bonding_list ) {
if ( ! first_candidate )
first_candidate = tmp_neigh_node ;
/* recv_if == NULL on the first node. */
if ( tmp_neigh_node - > if_incoming = = recv_if )
continue ;
if ( ! atomic_inc_not_zero ( & tmp_neigh_node - > refcount ) )
continue ;
router = tmp_neigh_node ;
break ;
}
/* use the first candidate if nothing was found. */
if ( ! router & & first_candidate & &
atomic_inc_not_zero ( & first_candidate - > refcount ) )
router = first_candidate ;
if ( ! router )
goto out ;
/* selected should point to the next element
2012-05-12 04:09:43 +04:00
* after the current router
*/
2011-03-15 01:43:27 +03:00
spin_lock_bh ( & primary_orig - > neigh_list_lock ) ;
/* this is a list_move(), which unfortunately
2012-05-12 04:09:43 +04:00
* does not exist as rcu version
*/
2011-03-15 01:43:27 +03:00
list_del_rcu ( & primary_orig - > bond_list ) ;
list_add_rcu ( & primary_orig - > bond_list ,
& router - > bonding_list ) ;
spin_unlock_bh ( & primary_orig - > neigh_list_lock ) ;
out :
rcu_read_unlock ( ) ;
return router ;
}
/* Interface Alternating: Use the best of the
* remaining candidates which are not using
* this interface .
*
2012-05-12 04:09:43 +04:00
* Increases the returned router ' s refcount
*/
2012-05-16 22:23:13 +04:00
static struct neigh_node *
batadv_find_ifalter_router ( struct orig_node * primary_orig ,
const struct hard_iface * recv_if )
2011-03-15 01:43:27 +03:00
{
struct neigh_node * tmp_neigh_node ;
struct neigh_node * router = NULL , * first_candidate = NULL ;
rcu_read_lock ( ) ;
list_for_each_entry_rcu ( tmp_neigh_node , & primary_orig - > bond_list ,
bonding_list ) {
if ( ! first_candidate )
first_candidate = tmp_neigh_node ;
/* recv_if == NULL on the first node. */
if ( tmp_neigh_node - > if_incoming = = recv_if )
continue ;
if ( ! atomic_inc_not_zero ( & tmp_neigh_node - > refcount ) )
continue ;
/* if we don't have a router yet
2012-05-12 04:09:43 +04:00
* or this one is better , choose it .
*/
2011-03-15 01:43:27 +03:00
if ( ( ! router ) | |
( tmp_neigh_node - > tq_avg > router - > tq_avg ) ) {
/* decrement refcount of
2012-05-12 04:09:43 +04:00
* previously selected router
*/
2011-03-15 01:43:27 +03:00
if ( router )
2012-05-12 04:09:34 +04:00
batadv_neigh_node_free_ref ( router ) ;
2011-03-15 01:43:27 +03:00
router = tmp_neigh_node ;
atomic_inc_not_zero ( & router - > refcount ) ;
}
2012-05-12 04:09:34 +04:00
batadv_neigh_node_free_ref ( tmp_neigh_node ) ;
2011-03-15 01:43:27 +03:00
}
/* use the first candidate if nothing was found. */
if ( ! router & & first_candidate & &
atomic_inc_not_zero ( & first_candidate - > refcount ) )
router = first_candidate ;
rcu_read_unlock ( ) ;
return router ;
}
2012-05-12 04:09:36 +04:00
int batadv_recv_tt_query ( struct sk_buff * skb , struct hard_iface * recv_if )
2011-04-27 16:27:44 +04:00
{
struct bat_priv * bat_priv = netdev_priv ( recv_if - > soft_iface ) ;
struct tt_query_packet * tt_query ;
2012-04-22 10:44:27 +04:00
uint16_t tt_size ;
2011-04-27 16:27:44 +04:00
struct ethhdr * ethhdr ;
2012-05-12 15:48:58 +04:00
char tt_flag ;
2011-04-27 16:27:44 +04:00
/* drop packet if it has not necessary minimum size */
if ( unlikely ( ! pskb_may_pull ( skb , sizeof ( struct tt_query_packet ) ) ) )
goto out ;
/* I could need to modify it */
if ( skb_cow ( skb , sizeof ( struct tt_query_packet ) ) < 0 )
goto out ;
ethhdr = ( struct ethhdr * ) skb_mac_header ( skb ) ;
/* packet with unicast indication but broadcast recipient */
if ( is_broadcast_ether_addr ( ethhdr - > h_dest ) )
goto out ;
/* packet with broadcast sender address */
if ( is_broadcast_ether_addr ( ethhdr - > h_source ) )
goto out ;
tt_query = ( struct tt_query_packet * ) skb - > data ;
2012-06-04 00:19:13 +04:00
switch ( tt_query - > flags & BATADV_TT_QUERY_TYPE_MASK ) {
2012-06-04 00:19:21 +04:00
case BATADV_TT_REQUEST :
2012-06-04 00:19:20 +04:00
batadv_inc_counter ( bat_priv , BATADV_CNT_TT_REQUEST_RX ) ;
2012-04-20 19:02:45 +04:00
2011-04-27 16:27:44 +04:00
/* If we cannot provide an answer the tt_request is
2012-05-12 04:09:43 +04:00
* forwarded
*/
2012-05-12 04:09:39 +04:00
if ( ! batadv_send_tt_response ( bat_priv , tt_query ) ) {
2012-06-04 00:19:21 +04:00
if ( tt_query - > flags & BATADV_TT_FULL_TABLE )
tt_flag = ' F ' ;
else
tt_flag = ' . ' ;
2012-06-04 00:19:22 +04:00
batadv_dbg ( BATADV_DBG_TT , bat_priv ,
2012-05-12 15:48:58 +04:00
" Routing TT_REQUEST to %pM [%c] \n " ,
tt_query - > dst ,
tt_flag ) ;
2012-05-16 22:23:13 +04:00
return batadv_route_unicast_packet ( skb , recv_if ) ;
2011-04-27 16:27:44 +04:00
}
break ;
2012-06-04 00:19:21 +04:00
case BATADV_TT_RESPONSE :
2012-06-04 00:19:20 +04:00
batadv_inc_counter ( bat_priv , BATADV_CNT_TT_RESPONSE_RX ) ;
2012-04-20 19:02:45 +04:00
2012-05-12 04:09:42 +04:00
if ( batadv_is_my_mac ( tt_query - > dst ) ) {
2011-10-16 22:32:02 +04:00
/* packet needs to be linearized to access the TT
2012-05-12 04:09:43 +04:00
* changes
*/
2011-10-16 22:32:02 +04:00
if ( skb_linearize ( skb ) < 0 )
goto out ;
2012-06-15 00:21:28 +04:00
/* skb_linearize() possibly changed skb->data */
tt_query = ( struct tt_query_packet * ) skb - > data ;
2011-04-27 16:27:44 +04:00
2012-05-12 04:09:39 +04:00
tt_size = batadv_tt_len ( ntohs ( tt_query - > tt_data ) ) ;
2011-10-16 22:32:03 +04:00
/* Ensure we have all the claimed data */
if ( unlikely ( skb_headlen ( skb ) <
2012-04-22 10:44:27 +04:00
sizeof ( struct tt_query_packet ) + tt_size ) )
2011-10-16 22:32:03 +04:00
goto out ;
2012-05-12 04:09:39 +04:00
batadv_handle_tt_response ( bat_priv , tt_query ) ;
2011-10-16 22:32:02 +04:00
} else {
2012-06-04 00:19:21 +04:00
if ( tt_query - > flags & BATADV_TT_FULL_TABLE )
tt_flag = ' F ' ;
else
tt_flag = ' . ' ;
2012-06-04 00:19:22 +04:00
batadv_dbg ( BATADV_DBG_TT , bat_priv ,
2012-05-12 15:48:58 +04:00
" Routing TT_RESPONSE to %pM [%c] \n " ,
tt_query - > dst ,
tt_flag ) ;
2012-05-16 22:23:13 +04:00
return batadv_route_unicast_packet ( skb , recv_if ) ;
2011-04-27 16:27:44 +04:00
}
break ;
}
out :
/* returning NET_RX_DROP will make the caller function kfree the skb */
return NET_RX_DROP ;
}
2012-05-12 04:09:36 +04:00
int batadv_recv_roam_adv ( struct sk_buff * skb , struct hard_iface * recv_if )
2011-04-27 16:27:57 +04:00
{
struct bat_priv * bat_priv = netdev_priv ( recv_if - > soft_iface ) ;
struct roam_adv_packet * roam_adv_packet ;
struct orig_node * orig_node ;
struct ethhdr * ethhdr ;
/* drop packet if it has not necessary minimum size */
if ( unlikely ( ! pskb_may_pull ( skb , sizeof ( struct roam_adv_packet ) ) ) )
goto out ;
ethhdr = ( struct ethhdr * ) skb_mac_header ( skb ) ;
/* packet with unicast indication but broadcast recipient */
if ( is_broadcast_ether_addr ( ethhdr - > h_dest ) )
goto out ;
/* packet with broadcast sender address */
if ( is_broadcast_ether_addr ( ethhdr - > h_source ) )
goto out ;
2012-06-04 00:19:20 +04:00
batadv_inc_counter ( bat_priv , BATADV_CNT_TT_ROAM_ADV_RX ) ;
2012-04-20 19:02:45 +04:00
2011-04-27 16:27:57 +04:00
roam_adv_packet = ( struct roam_adv_packet * ) skb - > data ;
2012-05-12 04:09:42 +04:00
if ( ! batadv_is_my_mac ( roam_adv_packet - > dst ) )
2012-05-16 22:23:13 +04:00
return batadv_route_unicast_packet ( skb , recv_if ) ;
2011-04-27 16:27:57 +04:00
2012-01-22 23:00:23 +04:00
/* check if it is a backbone gateway. we don't accept
* roaming advertisement from it , as it has the same
* entries as we have .
*/
2012-05-12 15:38:47 +04:00
if ( batadv_bla_is_backbone_gw_orig ( bat_priv , roam_adv_packet - > src ) )
2012-01-22 23:00:23 +04:00
goto out ;
2012-05-12 15:48:56 +04:00
orig_node = batadv_orig_hash_find ( bat_priv , roam_adv_packet - > src ) ;
2011-04-27 16:27:57 +04:00
if ( ! orig_node )
goto out ;
2012-06-04 00:19:22 +04:00
batadv_dbg ( BATADV_DBG_TT , bat_priv ,
2012-05-12 15:48:58 +04:00
" Received ROAMING_ADV from %pM (client %pM) \n " ,
roam_adv_packet - > src , roam_adv_packet - > client ) ;
2011-04-27 16:27:57 +04:00
2012-05-12 04:09:39 +04:00
batadv_tt_global_add ( bat_priv , orig_node , roam_adv_packet - > client ,
2012-06-04 00:19:21 +04:00
BATADV_TT_CLIENT_ROAM ,
2012-05-25 02:00:54 +04:00
atomic_read ( & orig_node - > last_ttvn ) + 1 ) ;
2011-04-27 16:27:57 +04:00
/* Roaming phase starts: I have new information but the ttvn has not
* been incremented yet . This flag will make me check all the incoming
2012-05-12 04:09:43 +04:00
* packets for the correct destination .
*/
2011-04-27 16:27:57 +04:00
bat_priv - > tt_poss_change = true ;
2012-05-12 04:09:34 +04:00
batadv_orig_node_free_ref ( orig_node ) ;
2011-04-27 16:27:57 +04:00
out :
/* returning NET_RX_DROP will make the caller function kfree the skb */
return NET_RX_DROP ;
}
2010-12-13 14:19:28 +03:00
/* find a suitable router for this originator, and use
2011-01-19 23:01:43 +03:00
* bonding if possible . increases the found neighbors
2012-05-12 04:09:43 +04:00
* refcount .
*/
2012-05-12 04:09:36 +04:00
struct neigh_node * batadv_find_router ( struct bat_priv * bat_priv ,
struct orig_node * orig_node ,
const struct hard_iface * recv_if )
2010-12-13 14:19:28 +03:00
{
struct orig_node * primary_orig_node ;
struct orig_node * router_orig ;
2011-03-15 01:43:27 +03:00
struct neigh_node * router ;
2010-12-13 14:19:28 +03:00
static uint8_t zero_mac [ ETH_ALEN ] = { 0 , 0 , 0 , 0 , 0 , 0 } ;
int bonding_enabled ;
2012-05-12 15:48:56 +04:00
uint8_t * primary_addr ;
2010-12-13 14:19:28 +03:00
if ( ! orig_node )
return NULL ;
2012-05-12 04:09:34 +04:00
router = batadv_orig_node_get_router ( orig_node ) ;
2011-03-15 01:43:37 +03:00
if ( ! router )
2011-05-05 16:14:46 +04:00
goto err ;
2010-12-13 14:19:28 +03:00
/* without bonding, the first node should
2012-05-12 04:09:43 +04:00
* always choose the default router .
*/
2010-12-13 14:19:28 +03:00
bonding_enabled = atomic_read ( & bat_priv - > bonding ) ;
2011-01-19 23:01:43 +03:00
rcu_read_lock ( ) ;
/* select default router to output */
2011-03-15 01:43:37 +03:00
router_orig = router - > orig_node ;
2011-05-05 16:14:46 +04:00
if ( ! router_orig )
goto err_unlock ;
2011-01-19 23:01:43 +03:00
if ( ( ! recv_if ) & & ( ! bonding_enabled ) )
goto return_router ;
2010-12-13 14:19:28 +03:00
2012-05-12 15:48:56 +04:00
primary_addr = router_orig - > primary_addr ;
2010-12-13 14:19:28 +03:00
/* if we have something in the primary_addr, we can search
2012-05-12 04:09:43 +04:00
* for a potential bonding candidate .
*/
2012-05-12 15:48:58 +04:00
if ( batadv_compare_eth ( primary_addr , zero_mac ) )
2011-01-19 23:01:43 +03:00
goto return_router ;
2010-12-13 14:19:28 +03:00
/* find the orig_node which has the primary interface. might
2012-05-12 04:09:43 +04:00
* even be the same as our router_orig in many cases
*/
2012-05-12 15:48:58 +04:00
if ( batadv_compare_eth ( primary_addr , router_orig - > orig ) ) {
2010-12-13 14:19:28 +03:00
primary_orig_node = router_orig ;
} else {
2012-05-12 15:48:56 +04:00
primary_orig_node = batadv_orig_hash_find ( bat_priv ,
primary_addr ) ;
2010-12-13 14:19:28 +03:00
if ( ! primary_orig_node )
2011-01-19 23:01:43 +03:00
goto return_router ;
2011-02-18 15:28:09 +03:00
2012-05-12 04:09:34 +04:00
batadv_orig_node_free_ref ( primary_orig_node ) ;
2010-12-13 14:19:28 +03:00
}
/* with less than 2 candidates, we can't do any
2012-05-12 04:09:43 +04:00
* bonding and prefer the original router .
*/
2011-01-19 23:01:43 +03:00
if ( atomic_read ( & primary_orig_node - > bond_candidates ) < 2 )
goto return_router ;
2010-12-13 14:19:28 +03:00
/* all nodes between should choose a candidate which
* is is not on the interface where the packet came
2012-05-12 04:09:43 +04:00
* in .
*/
2012-05-12 04:09:34 +04:00
batadv_neigh_node_free_ref ( router ) ;
2010-12-13 14:19:28 +03:00
2011-03-15 01:43:27 +03:00
if ( bonding_enabled )
2012-05-16 22:23:13 +04:00
router = batadv_find_bond_router ( primary_orig_node , recv_if ) ;
2011-03-15 01:43:27 +03:00
else
2012-05-16 22:23:13 +04:00
router = batadv_find_ifalter_router ( primary_orig_node , recv_if ) ;
2010-12-13 14:19:28 +03:00
2011-01-19 23:01:43 +03:00
return_router :
2012-06-04 00:19:19 +04:00
if ( router & & router - > if_incoming - > if_status ! = BATADV_IF_ACTIVE )
2011-05-08 22:52:57 +04:00
goto err_unlock ;
2011-01-19 23:01:43 +03:00
rcu_read_unlock ( ) ;
2010-12-13 14:19:28 +03:00
return router ;
2011-05-05 16:14:46 +04:00
err_unlock :
rcu_read_unlock ( ) ;
err :
if ( router )
2012-05-12 04:09:34 +04:00
batadv_neigh_node_free_ref ( router ) ;
2011-05-05 16:14:46 +04:00
return NULL ;
2010-12-13 14:19:28 +03:00
}
2012-05-16 22:23:13 +04:00
static int batadv_check_unicast_packet ( struct sk_buff * skb , int hdr_size )
2010-12-13 14:19:28 +03:00
{
struct ethhdr * ethhdr ;
/* drop packet if it has not necessary minimum size */
if ( unlikely ( ! pskb_may_pull ( skb , hdr_size ) ) )
return - 1 ;
ethhdr = ( struct ethhdr * ) skb_mac_header ( skb ) ;
/* packet with unicast indication but broadcast recipient */
if ( is_broadcast_ether_addr ( ethhdr - > h_dest ) )
return - 1 ;
/* packet with broadcast sender address */
if ( is_broadcast_ether_addr ( ethhdr - > h_source ) )
return - 1 ;
/* not for me */
2012-05-12 04:09:42 +04:00
if ( ! batadv_is_my_mac ( ethhdr - > h_dest ) )
2010-12-13 14:19:28 +03:00
return - 1 ;
return 0 ;
}
2012-05-16 22:23:13 +04:00
static int batadv_route_unicast_packet ( struct sk_buff * skb ,
struct hard_iface * recv_if )
2010-12-13 14:19:28 +03:00
{
struct bat_priv * bat_priv = netdev_priv ( recv_if - > soft_iface ) ;
2011-02-10 17:33:53 +03:00
struct orig_node * orig_node = NULL ;
struct neigh_node * neigh_node = NULL ;
2010-12-13 14:19:28 +03:00
struct unicast_packet * unicast_packet ;
struct ethhdr * ethhdr = ( struct ethhdr * ) skb_mac_header ( skb ) ;
2011-02-10 17:33:53 +03:00
int ret = NET_RX_DROP ;
2010-12-13 14:19:28 +03:00
struct sk_buff * new_skb ;
unicast_packet = ( struct unicast_packet * ) skb - > data ;
/* TTL exceeded */
2011-11-20 18:47:38 +04:00
if ( unicast_packet - > header . 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
2011-01-19 23:01:43 +03:00
/* find_router() increases neigh_nodes refcount if found. */
2012-05-12 04:09:36 +04:00
neigh_node = batadv_find_router ( bat_priv , orig_node , recv_if ) ;
2010-12-13 14:19:28 +03:00
2011-01-19 23:01:44 +03:00
if ( ! neigh_node )
2011-02-10 17:33:53 +03: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
unicast_packet = ( struct unicast_packet * ) skb - > data ;
2012-06-04 00:19:21 +04:00
if ( unicast_packet - > header . packet_type = = BATADV_UNICAST & &
2010-12-13 14:19:28 +03:00
atomic_read ( & bat_priv - > fragmentation ) & &
2011-01-19 23:01:44 +03:00
skb - > len > neigh_node - > if_incoming - > net_dev - > mtu ) {
2012-05-12 04:09:40 +04:00
ret = batadv_frag_send_skb ( skb , bat_priv ,
neigh_node - > if_incoming ,
neigh_node - > addr ) ;
2011-01-19 23:01:44 +03:00
goto out ;
}
2010-12-13 14:19:28 +03:00
2012-06-04 00:19:21 +04:00
if ( unicast_packet - > header . packet_type = = BATADV_UNICAST_FRAG & &
2012-05-12 15:48:57 +04:00
batadv_frag_can_reassemble ( skb ,
neigh_node - > if_incoming - > net_dev - > mtu ) ) {
2010-12-13 14:19:28 +03:00
2012-05-12 04:09:40 +04:00
ret = batadv_frag_reassemble_skb ( skb , bat_priv , & new_skb ) ;
2010-12-13 14:19:28 +03:00
if ( ret = = NET_RX_DROP )
2011-02-10 17:33:53 +03:00
goto out ;
2010-12-13 14:19:28 +03:00
/* packet was buffered for late merge */
2011-02-10 17:33:53 +03:00
if ( ! new_skb ) {
ret = NET_RX_SUCCESS ;
goto out ;
}
2010-12-13 14:19:28 +03:00
skb = new_skb ;
unicast_packet = ( struct unicast_packet * ) skb - > data ;
}
/* decrement ttl */
2011-11-20 18:47:38 +04:00
unicast_packet - > header . ttl - - ;
2010-12-13 14:19:28 +03:00
2012-04-20 19:02:45 +04:00
/* Update stats counter */
2012-06-04 00:19:20 +04:00
batadv_inc_counter ( bat_priv , BATADV_CNT_FORWARD ) ;
batadv_add_counter ( bat_priv , BATADV_CNT_FORWARD_BYTES ,
2012-04-20 19:02:45 +04:00
skb - > len + ETH_HLEN ) ;
2010-12-13 14:19:28 +03:00
/* route it */
2012-05-12 04:09:37 +04:00
batadv_send_skb_packet ( skb , neigh_node - > if_incoming , neigh_node - > addr ) ;
2011-02-10 17:33:53 +03:00
ret = NET_RX_SUCCESS ;
2010-12-13 14:19:28 +03:00
2011-02-10 17:33:53 +03:00
out :
if ( neigh_node )
2012-05-12 04:09:34 +04:00
batadv_neigh_node_free_ref ( neigh_node ) ;
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 ) ;
2011-02-10 17:33:53 +03:00
return ret ;
2010-12-13 14:19:28 +03:00
}
2012-05-16 22:23:13 +04:00
static int batadv_check_unicast_ttvn ( struct bat_priv * bat_priv ,
struct sk_buff * skb ) {
2011-04-27 16:27:44 +04:00
uint8_t curr_ttvn ;
struct orig_node * orig_node ;
struct ethhdr * ethhdr ;
struct hard_iface * primary_if ;
struct unicast_packet * unicast_packet ;
2011-04-27 16:27:57 +04:00
bool tt_poss_change ;
2012-05-16 22:23:22 +04:00
int is_old_ttvn ;
2011-04-27 16:27:44 +04:00
/* I could need to modify it */
if ( skb_cow ( skb , sizeof ( struct unicast_packet ) ) < 0 )
return 0 ;
unicast_packet = ( struct unicast_packet * ) skb - > data ;
2012-05-12 04:09:42 +04:00
if ( batadv_is_my_mac ( unicast_packet - > dest ) ) {
2011-04-27 16:27:57 +04:00
tt_poss_change = bat_priv - > tt_poss_change ;
2011-04-27 16:27:44 +04:00
curr_ttvn = ( uint8_t ) atomic_read ( & bat_priv - > ttvn ) ;
2011-04-27 16:27:57 +04:00
} else {
2012-05-12 15:48:56 +04:00
orig_node = batadv_orig_hash_find ( bat_priv ,
unicast_packet - > dest ) ;
2011-04-27 16:27:44 +04:00
if ( ! orig_node )
return 0 ;
curr_ttvn = ( uint8_t ) atomic_read ( & orig_node - > last_ttvn ) ;
2011-04-27 16:27:57 +04:00
tt_poss_change = orig_node - > tt_poss_change ;
2012-05-12 04:09:34 +04:00
batadv_orig_node_free_ref ( orig_node ) ;
2011-04-27 16:27:44 +04:00
}
/* Check whether I have to reroute the packet */
2012-05-16 22:23:22 +04:00
is_old_ttvn = batadv_seq_before ( unicast_packet - > ttvn , curr_ttvn ) ;
if ( is_old_ttvn | | tt_poss_change ) {
2012-03-16 14:52:31 +04:00
/* check if there is enough data before accessing it */
if ( pskb_may_pull ( skb , sizeof ( struct unicast_packet ) +
ETH_HLEN ) < 0 )
2011-04-27 16:27:44 +04:00
return 0 ;
ethhdr = ( struct ethhdr * ) ( skb - > data +
sizeof ( struct unicast_packet ) ) ;
2012-03-16 21:03:28 +04:00
/* we don't have an updated route for this client, so we should
* not try to reroute the packet ! !
*/
2012-05-12 04:09:39 +04:00
if ( batadv_tt_global_client_is_roaming ( bat_priv ,
ethhdr - > h_dest ) )
2012-03-16 21:03:28 +04:00
return 1 ;
2012-05-12 04:09:39 +04:00
orig_node = batadv_transtable_search ( bat_priv , NULL ,
ethhdr - > h_dest ) ;
2011-04-27 16:27:44 +04:00
if ( ! orig_node ) {
2012-05-12 04:09:39 +04:00
if ( ! batadv_is_my_client ( bat_priv , ethhdr - > h_dest ) )
2011-04-27 16:27:44 +04:00
return 0 ;
2012-05-12 15:48:54 +04:00
primary_if = batadv_primary_if_get_selected ( bat_priv ) ;
2011-04-27 16:27:44 +04:00
if ( ! primary_if )
return 0 ;
memcpy ( unicast_packet - > dest ,
primary_if - > net_dev - > dev_addr , ETH_ALEN ) ;
2012-05-12 15:48:54 +04:00
batadv_hardif_free_ref ( primary_if ) ;
2011-04-27 16:27:44 +04:00
} else {
memcpy ( unicast_packet - > dest , orig_node - > orig ,
ETH_ALEN ) ;
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-06-04 00:19:22 +04:00
batadv_dbg ( BATADV_DBG_ROUTES , bat_priv ,
2012-05-12 15:48:58 +04:00
" TTVN mismatch (old_ttvn %u new_ttvn %u)! Rerouting unicast packet (for %pM) to %pM \n " ,
unicast_packet - > ttvn , curr_ttvn , ethhdr - > h_dest ,
unicast_packet - > dest ) ;
2011-04-27 16:27:44 +04:00
unicast_packet - > ttvn = curr_ttvn ;
}
return 1 ;
}
2012-05-12 04:09:36 +04:00
int batadv_recv_unicast_packet ( struct sk_buff * skb , struct hard_iface * recv_if )
2010-12-13 14:19:28 +03:00
{
2011-04-27 16:27:44 +04:00
struct bat_priv * bat_priv = netdev_priv ( recv_if - > soft_iface ) ;
2010-12-13 14:19:28 +03:00
struct unicast_packet * unicast_packet ;
2011-05-15 01:14:54 +04:00
int hdr_size = sizeof ( * unicast_packet ) ;
2010-12-13 14:19:28 +03:00
2012-05-16 22:23:13 +04:00
if ( batadv_check_unicast_packet ( skb , hdr_size ) < 0 )
2010-12-13 14:19:28 +03:00
return NET_RX_DROP ;
2012-05-16 22:23:13 +04:00
if ( ! batadv_check_unicast_ttvn ( bat_priv , skb ) )
2011-04-27 16:27:44 +04:00
return NET_RX_DROP ;
2010-12-13 14:19:28 +03:00
unicast_packet = ( struct unicast_packet * ) skb - > data ;
/* packet for me */
2012-05-12 04:09:42 +04:00
if ( batadv_is_my_mac ( unicast_packet - > dest ) ) {
2012-05-12 04:09:38 +04:00
batadv_interface_rx ( recv_if - > soft_iface , skb , recv_if ,
hdr_size ) ;
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
}
2012-05-12 04:09:36 +04:00
int batadv_recv_ucast_frag_packet ( struct sk_buff * skb ,
struct hard_iface * recv_if )
2010-12-13 14:19:28 +03:00
{
struct bat_priv * bat_priv = netdev_priv ( recv_if - > soft_iface ) ;
struct unicast_frag_packet * unicast_packet ;
2011-05-15 01:14:54 +04:00
int hdr_size = sizeof ( * unicast_packet ) ;
2010-12-13 14:19:28 +03:00
struct sk_buff * new_skb = NULL ;
int ret ;
2012-05-16 22:23:13 +04:00
if ( batadv_check_unicast_packet ( skb , hdr_size ) < 0 )
2010-12-13 14:19:28 +03:00
return NET_RX_DROP ;
2012-05-16 22:23:13 +04:00
if ( ! batadv_check_unicast_ttvn ( bat_priv , skb ) )
2011-04-27 16:27:44 +04:00
return NET_RX_DROP ;
2010-12-13 14:19:28 +03:00
unicast_packet = ( struct unicast_frag_packet * ) skb - > data ;
/* packet for me */
2012-05-12 04:09:42 +04:00
if ( batadv_is_my_mac ( unicast_packet - > dest ) ) {
2010-12-13 14:19:28 +03:00
2012-05-12 04:09:40 +04:00
ret = batadv_frag_reassemble_skb ( skb , bat_priv , & new_skb ) ;
2010-12-13 14:19:28 +03:00
if ( ret = = NET_RX_DROP )
return NET_RX_DROP ;
/* packet was buffered for late merge */
if ( ! new_skb )
return NET_RX_SUCCESS ;
2012-05-12 04:09:38 +04:00
batadv_interface_rx ( recv_if - > soft_iface , new_skb , recv_if ,
sizeof ( struct unicast_packet ) ) ;
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
}
2012-05-12 04:09:36 +04:00
int batadv_recv_bcast_packet ( struct sk_buff * skb , struct hard_iface * recv_if )
2010-12-13 14:19:28 +03:00
{
struct bat_priv * bat_priv = netdev_priv ( recv_if - > soft_iface ) ;
2011-01-26 00:52:11 +03:00
struct orig_node * orig_node = NULL ;
2010-12-13 14:19:28 +03:00
struct bcast_packet * bcast_packet ;
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 ;
/* 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
ethhdr = ( struct ethhdr * ) skb_mac_header ( skb ) ;
/* 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 */
2012-05-12 04:09:42 +04:00
if ( batadv_is_my_mac ( ethhdr - > h_source ) )
2011-01-26 00:52:11 +03:00
goto out ;
2010-12-13 14:19:28 +03:00
bcast_packet = ( struct bcast_packet * ) skb - > data ;
/* ignore broadcasts originated by myself */
2012-05-12 04:09:42 +04:00
if ( batadv_is_my_mac ( bcast_packet - > orig ) )
2011-01-26 00:52:11 +03:00
goto out ;
2010-12-13 14:19:28 +03:00
2011-11-20 18:47:38 +04:00
if ( bcast_packet - > header . 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
/* 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 ,
ntohl ( bcast_packet - > seqno ) ) )
2011-01-26 00:52:11 +03:00
goto spin_unlock ;
2010-12-13 14:19:28 +03:00
seq_diff = ntohl ( bcast_packet - > seqno ) - orig_node - > last_bcast_seqno ;
/* 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 ) )
2010-12-13 14:19:28 +03:00
orig_node - > last_bcast_seqno = ntohl ( bcast_packet - > seqno ) ;
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-05-12 15:38:47 +04:00
if ( batadv_bla_check_bcast_duplist ( bat_priv , bcast_packet , hdr_size ) )
2012-01-22 23:00:24 +04:00
goto out ;
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 ;
2010-12-13 14:19:28 +03:00
/* broadcast for me */
2012-05-12 04:09:38 +04:00
batadv_interface_rx ( recv_if - > soft_iface , skb , recv_if , hdr_size ) ;
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
}
2012-05-12 04:09:36 +04:00
int batadv_recv_vis_packet ( struct sk_buff * skb , struct hard_iface * recv_if )
2010-12-13 14:19:28 +03:00
{
struct vis_packet * vis_packet ;
struct ethhdr * ethhdr ;
struct bat_priv * bat_priv = netdev_priv ( recv_if - > soft_iface ) ;
2011-05-15 01:14:54 +04:00
int hdr_size = sizeof ( * vis_packet ) ;
2010-12-13 14:19:28 +03:00
/* keep skb linear */
if ( skb_linearize ( skb ) < 0 )
return NET_RX_DROP ;
if ( unlikely ( ! pskb_may_pull ( skb , hdr_size ) ) )
return NET_RX_DROP ;
vis_packet = ( struct vis_packet * ) skb - > data ;
ethhdr = ( struct ethhdr * ) skb_mac_header ( skb ) ;
/* not for me */
2012-05-12 04:09:42 +04:00
if ( ! batadv_is_my_mac ( ethhdr - > h_dest ) )
2010-12-13 14:19:28 +03:00
return NET_RX_DROP ;
/* ignore own packets */
2012-05-12 04:09:42 +04:00
if ( batadv_is_my_mac ( vis_packet - > vis_orig ) )
2010-12-13 14:19:28 +03:00
return NET_RX_DROP ;
2012-05-12 04:09:42 +04:00
if ( batadv_is_my_mac ( vis_packet - > sender_orig ) )
2010-12-13 14:19:28 +03:00
return NET_RX_DROP ;
switch ( vis_packet - > vis_type ) {
2012-06-04 00:19:21 +04:00
case BATADV_VIS_TYPE_SERVER_SYNC :
2012-05-12 04:09:41 +04:00
batadv_receive_server_sync_packet ( bat_priv , vis_packet ,
skb_headlen ( skb ) ) ;
2010-12-13 14:19:28 +03:00
break ;
2012-06-04 00:19:21 +04:00
case BATADV_VIS_TYPE_CLIENT_UPDATE :
2012-05-12 04:09:41 +04:00
batadv_receive_client_update_packet ( bat_priv , vis_packet ,
skb_headlen ( skb ) ) ;
2010-12-13 14:19:28 +03:00
break ;
default : /* ignore unknown packet */
break ;
}
/* We take a copy of the data in the packet, so we should
2012-05-12 04:09:43 +04:00
* always free the skbuf .
*/
2010-12-13 14:19:28 +03:00
return NET_RX_DROP ;
}