2012-05-12 02:09:43 +02:00
/* Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
2011-07-30 12:04:12 +02: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 "translation-table.h"
# include "ring_buffer.h"
# include "originator.h"
# include "routing.h"
# include "gateway_common.h"
# include "gateway_client.h"
# include "hard-interface.h"
# include "send.h"
2011-11-28 17:40:17 +08:00
# include "bat_algo.h"
2011-07-30 12:04:12 +02:00
2012-05-12 18:33:51 +02:00
static struct neigh_node * batadv_iv_ogm_neigh_new ( struct hard_iface * hard_iface ,
const uint8_t * neigh_addr ,
struct orig_node * orig_node ,
struct orig_node * orig_neigh ,
__be32 seqno )
2012-03-01 15:35:21 +08:00
{
struct neigh_node * neigh_node ;
2012-04-22 07:46:29 +01:00
neigh_node = batadv_neigh_node_new ( hard_iface , neigh_addr ,
ntohl ( seqno ) ) ;
2012-03-01 15:35:21 +08:00
if ( ! neigh_node )
goto out ;
INIT_LIST_HEAD ( & neigh_node - > bonding_list ) ;
neigh_node - > orig_node = orig_neigh ;
neigh_node - > if_incoming = hard_iface ;
spin_lock_bh ( & orig_node - > neigh_list_lock ) ;
hlist_add_head_rcu ( & neigh_node - > list , & orig_node - > neigh_list ) ;
spin_unlock_bh ( & orig_node - > neigh_list_lock ) ;
out :
return neigh_node ;
}
2012-05-12 18:33:51 +02:00
static int batadv_iv_ogm_iface_enable ( struct hard_iface * hard_iface )
2011-07-30 12:33:33 +02:00
{
struct batman_ogm_packet * batman_ogm_packet ;
2012-02-07 17:20:46 +08:00
uint32_t random_seqno ;
2012-05-05 13:27:28 +02:00
int res = - ENOMEM ;
2012-02-07 17:20:46 +08:00
/* randomize initial seqno to avoid collision */
get_random_bytes ( & random_seqno , sizeof ( random_seqno ) ) ;
atomic_set ( & hard_iface - > seqno , random_seqno ) ;
2011-07-30 12:33:33 +02:00
2012-06-03 22:19:13 +02:00
hard_iface - > packet_len = BATADV_OGM_HLEN ;
2011-07-30 12:33:33 +02:00
hard_iface - > packet_buff = kmalloc ( hard_iface - > packet_len , GFP_ATOMIC ) ;
2012-02-07 17:20:48 +08:00
if ( ! hard_iface - > packet_buff )
goto out ;
2011-07-30 12:33:33 +02:00
batman_ogm_packet = ( struct batman_ogm_packet * ) hard_iface - > packet_buff ;
2012-02-07 17:20:51 +08:00
batman_ogm_packet - > header . packet_type = BAT_IV_OGM ;
2012-06-03 22:19:13 +02:00
batman_ogm_packet - > header . version = BATADV_COMPAT_VERSION ;
2011-11-20 15:47:38 +01:00
batman_ogm_packet - > header . ttl = 2 ;
2012-06-03 22:19:17 +02:00
batman_ogm_packet - > flags = BATADV_NO_FLAGS ;
batman_ogm_packet - > tq = BATADV_TQ_MAX_VALUE ;
2011-07-30 12:33:33 +02:00
batman_ogm_packet - > tt_num_changes = 0 ;
batman_ogm_packet - > ttvn = 0 ;
2012-02-07 17:20:48 +08:00
res = 0 ;
out :
return res ;
2011-07-30 12:33:33 +02:00
}
2012-05-12 18:33:51 +02:00
static void batadv_iv_ogm_iface_disable ( struct hard_iface * hard_iface )
2012-02-07 17:20:47 +08:00
{
kfree ( hard_iface - > packet_buff ) ;
hard_iface - > packet_buff = NULL ;
}
2012-05-12 18:33:51 +02:00
static void batadv_iv_ogm_iface_update_mac ( struct hard_iface * hard_iface )
2011-07-30 12:33:33 +02:00
{
struct batman_ogm_packet * batman_ogm_packet ;
batman_ogm_packet = ( struct batman_ogm_packet * ) hard_iface - > packet_buff ;
2012-03-11 06:17:50 +08:00
memcpy ( batman_ogm_packet - > orig ,
hard_iface - > net_dev - > dev_addr , ETH_ALEN ) ;
memcpy ( batman_ogm_packet - > prev_sender ,
hard_iface - > net_dev - > dev_addr , ETH_ALEN ) ;
2011-07-30 12:33:33 +02:00
}
2012-05-12 18:33:51 +02:00
static void batadv_iv_ogm_primary_iface_set ( struct hard_iface * hard_iface )
2011-07-30 12:33:33 +02:00
{
struct batman_ogm_packet * batman_ogm_packet ;
batman_ogm_packet = ( struct batman_ogm_packet * ) hard_iface - > packet_buff ;
2012-03-11 06:17:50 +08:00
batman_ogm_packet - > flags = PRIMARIES_FIRST_HOP ;
2012-06-03 22:19:17 +02:00
batman_ogm_packet - > header . ttl = BATADV_TTL ;
2011-07-30 12:33:33 +02:00
}
2011-08-03 09:09:30 +02:00
/* when do we schedule our own ogm to be sent */
2012-05-12 18:33:51 +02:00
static unsigned long
batadv_iv_ogm_emit_send_time ( const struct bat_priv * bat_priv )
2011-08-03 09:09:30 +02:00
{
2012-06-03 22:19:17 +02:00
unsigned int msecs ;
msecs = atomic_read ( & bat_priv - > orig_interval ) - BATADV_JITTER ;
msecs + = ( random32 ( ) % 2 * BATADV_JITTER ) ;
return jiffies + msecs_to_jiffies ( msecs ) ;
2011-08-03 09:09:30 +02:00
}
/* when do we schedule a ogm packet to be sent */
2012-05-12 18:33:51 +02:00
static unsigned long batadv_iv_ogm_fwd_send_time ( void )
2011-08-03 09:09:30 +02:00
{
2012-06-03 22:19:17 +02:00
return jiffies + msecs_to_jiffies ( random32 ( ) % ( BATADV_JITTER / 2 ) ) ;
2011-08-03 09:09:30 +02:00
}
/* apply hop penalty for a normal link */
2012-05-12 18:33:51 +02:00
static uint8_t batadv_hop_penalty ( uint8_t tq , const struct bat_priv * bat_priv )
2011-08-03 09:09:30 +02:00
{
int hop_penalty = atomic_read ( & bat_priv - > hop_penalty ) ;
2012-06-03 22:19:17 +02:00
int new_tq ;
new_tq = tq * ( BATADV_TQ_MAX_VALUE - hop_penalty ) ;
new_tq / = BATADV_TQ_MAX_VALUE ;
return new_tq ;
2011-08-03 09:09:30 +02:00
}
2011-07-30 12:04:12 +02:00
/* is there another aggregated packet here? */
2012-05-12 18:33:51 +02:00
static int batadv_iv_ogm_aggr_packet ( int buff_pos , int packet_len ,
int tt_num_changes )
2011-07-30 12:04:12 +02:00
{
2012-05-12 02:09:39 +02:00
int next_buff_pos = 0 ;
2012-06-03 22:19:13 +02:00
next_buff_pos + = buff_pos + BATADV_OGM_HLEN ;
2012-05-12 02:09:39 +02:00
next_buff_pos + = batadv_tt_len ( tt_num_changes ) ;
2011-07-30 12:04:12 +02:00
return ( next_buff_pos < = packet_len ) & &
2012-06-03 22:19:17 +02:00
( next_buff_pos < = BATADV_MAX_AGGREGATION_BYTES ) ;
2011-07-30 12:04:12 +02:00
}
2011-08-03 09:09:30 +02:00
/* send a batman ogm to a given interface */
2012-05-12 18:33:51 +02:00
static void batadv_iv_ogm_send_to_if ( struct forw_packet * forw_packet ,
2011-11-28 21:31:55 +08:00
struct hard_iface * hard_iface )
2011-08-03 09:09:30 +02:00
{
struct bat_priv * bat_priv = netdev_priv ( hard_iface - > soft_iface ) ;
char * fwd_str ;
uint8_t packet_num ;
int16_t buff_pos ;
struct batman_ogm_packet * batman_ogm_packet ;
struct sk_buff * skb ;
if ( hard_iface - > if_status ! = IF_ACTIVE )
return ;
packet_num = 0 ;
buff_pos = 0 ;
batman_ogm_packet = ( struct batman_ogm_packet * ) forw_packet - > skb - > data ;
/* adjust all flags and log packets */
2012-05-12 18:33:51 +02:00
while ( batadv_iv_ogm_aggr_packet ( buff_pos , forw_packet - > packet_len ,
batman_ogm_packet - > tt_num_changes ) ) {
2011-08-03 09:09:30 +02:00
/* we might have aggregated direct link packets with an
2012-05-12 02:09:43 +02:00
* ordinary base packet
*/
2011-08-03 09:09:30 +02:00
if ( ( forw_packet - > direct_link_flags & ( 1 < < packet_num ) ) & &
( forw_packet - > if_incoming = = hard_iface ) )
batman_ogm_packet - > flags | = DIRECTLINK ;
else
batman_ogm_packet - > flags & = ~ DIRECTLINK ;
fwd_str = ( packet_num > 0 ? " Forwarding " : ( forw_packet - > own ?
" Sending own " :
" Forwarding " ) ) ;
2012-05-12 13:48:58 +02:00
batadv_dbg ( DBG_BATMAN , bat_priv ,
" %s %spacket (originator %pM, seqno %u, TQ %d, TTL %d, IDF %s, ttvn %d) on interface %s [%pM] \n " ,
fwd_str , ( packet_num > 0 ? " aggregated " : " " ) ,
batman_ogm_packet - > orig ,
ntohl ( batman_ogm_packet - > seqno ) ,
batman_ogm_packet - > tq , batman_ogm_packet - > header . ttl ,
( batman_ogm_packet - > flags & DIRECTLINK ?
" on " : " off " ) ,
batman_ogm_packet - > ttvn , hard_iface - > net_dev - > name ,
hard_iface - > net_dev - > dev_addr ) ;
2011-08-03 09:09:30 +02:00
2012-06-03 22:19:13 +02:00
buff_pos + = BATADV_OGM_HLEN ;
2012-05-12 02:09:39 +02:00
buff_pos + = batadv_tt_len ( batman_ogm_packet - > tt_num_changes ) ;
2011-08-03 09:09:30 +02:00
packet_num + + ;
batman_ogm_packet = ( struct batman_ogm_packet * )
( forw_packet - > skb - > data + buff_pos ) ;
}
/* create clone because function is called more than once */
skb = skb_clone ( forw_packet - > skb , GFP_ATOMIC ) ;
2012-04-20 17:02:45 +02:00
if ( skb ) {
batadv_inc_counter ( bat_priv , BAT_CNT_MGMT_TX ) ;
batadv_add_counter ( bat_priv , BAT_CNT_MGMT_TX_BYTES ,
skb - > len + ETH_HLEN ) ;
2012-05-12 02:09:42 +02:00
batadv_send_skb_packet ( skb , hard_iface , batadv_broadcast_addr ) ;
2012-04-20 17:02:45 +02:00
}
2011-08-03 09:09:30 +02:00
}
/* send a batman ogm packet */
2012-05-12 18:33:51 +02:00
static void batadv_iv_ogm_emit ( struct forw_packet * forw_packet )
2011-08-03 09:09:30 +02:00
{
struct hard_iface * hard_iface ;
struct net_device * soft_iface ;
struct bat_priv * bat_priv ;
struct hard_iface * primary_if = NULL ;
struct batman_ogm_packet * batman_ogm_packet ;
unsigned char directlink ;
batman_ogm_packet = ( struct batman_ogm_packet * )
( forw_packet - > skb - > data ) ;
directlink = ( batman_ogm_packet - > flags & DIRECTLINK ? 1 : 0 ) ;
if ( ! forw_packet - > if_incoming ) {
2012-03-07 09:07:45 +01:00
pr_err ( " Error - can't forward packet: incoming iface not specified \n " ) ;
2011-08-03 09:09:30 +02:00
goto out ;
}
soft_iface = forw_packet - > if_incoming - > soft_iface ;
bat_priv = netdev_priv ( soft_iface ) ;
if ( forw_packet - > if_incoming - > if_status ! = IF_ACTIVE )
goto out ;
2012-05-12 13:48:54 +02:00
primary_if = batadv_primary_if_get_selected ( bat_priv ) ;
2011-08-03 09:09:30 +02:00
if ( ! primary_if )
goto out ;
2012-05-12 02:09:43 +02:00
/* multihomed peer assumed
* non - primary OGMs are only broadcasted on their interface
*/
2011-11-20 15:47:38 +01:00
if ( ( directlink & & ( batman_ogm_packet - > header . ttl = = 1 ) ) | |
2011-08-03 09:09:30 +02:00
( forw_packet - > own & & ( forw_packet - > if_incoming ! = primary_if ) ) ) {
/* FIXME: what about aggregated packets ? */
2012-05-12 13:48:58 +02:00
batadv_dbg ( DBG_BATMAN , bat_priv ,
" %s packet (originator %pM, seqno %u, TTL %d) on interface %s [%pM] \n " ,
( forw_packet - > own ? " Sending own " : " Forwarding " ) ,
batman_ogm_packet - > orig ,
ntohl ( batman_ogm_packet - > seqno ) ,
batman_ogm_packet - > header . ttl ,
forw_packet - > if_incoming - > net_dev - > name ,
forw_packet - > if_incoming - > net_dev - > dev_addr ) ;
2011-08-03 09:09:30 +02:00
/* skb is only used once and than forw_packet is free'd */
2012-05-12 02:09:37 +02:00
batadv_send_skb_packet ( forw_packet - > skb ,
forw_packet - > if_incoming ,
2012-05-12 02:09:42 +02:00
batadv_broadcast_addr ) ;
2011-08-03 09:09:30 +02:00
forw_packet - > skb = NULL ;
goto out ;
}
/* broadcast on every interface */
rcu_read_lock ( ) ;
2012-05-12 02:09:42 +02:00
list_for_each_entry_rcu ( hard_iface , & batadv_hardif_list , list ) {
2011-08-03 09:09:30 +02:00
if ( hard_iface - > soft_iface ! = soft_iface )
continue ;
2012-05-12 18:33:51 +02:00
batadv_iv_ogm_send_to_if ( forw_packet , hard_iface ) ;
2011-08-03 09:09:30 +02:00
}
rcu_read_unlock ( ) ;
out :
if ( primary_if )
2012-05-12 13:48:54 +02:00
batadv_hardif_free_ref ( primary_if ) ;
2011-08-03 09:09:30 +02:00
}
/* return true if new_packet can be aggregated with forw_packet */
2012-05-12 18:33:51 +02:00
static bool
batadv_iv_ogm_can_aggregate ( const struct batman_ogm_packet * new_bat_ogm_packet ,
struct bat_priv * bat_priv ,
int packet_len , unsigned long send_time ,
bool directlink ,
const struct hard_iface * if_incoming ,
const struct forw_packet * forw_packet )
2011-08-03 09:09:30 +02:00
{
struct batman_ogm_packet * batman_ogm_packet ;
int aggregated_bytes = forw_packet - > packet_len + packet_len ;
struct hard_iface * primary_if = NULL ;
bool res = false ;
2012-06-03 22:19:17 +02:00
unsigned long aggregation_end_time ;
2011-08-03 09:09:30 +02:00
batman_ogm_packet = ( struct batman_ogm_packet * ) forw_packet - > skb - > data ;
2012-06-03 22:19:17 +02:00
aggregation_end_time = send_time ;
aggregation_end_time + = msecs_to_jiffies ( BATADV_MAX_AGGREGATION_MS ) ;
2011-08-03 09:09:30 +02:00
2012-05-12 02:09:43 +02:00
/* we can aggregate the current packet to this aggregated packet
2011-08-03 09:09:30 +02:00
* if :
*
* - the send time is within our MAX_AGGREGATION_MS time
* - the resulting packet wont be bigger than
* MAX_AGGREGATION_BYTES
*/
if ( time_before ( send_time , forw_packet - > send_time ) & &
2012-06-03 22:19:17 +02:00
time_after_eq ( aggregation_end_time , forw_packet - > send_time ) & &
( aggregated_bytes < = BATADV_MAX_AGGREGATION_BYTES ) ) {
2011-08-03 09:09:30 +02:00
2012-05-12 02:09:43 +02:00
/* check aggregation compatibility
2011-08-03 09:09:30 +02:00
* - > direct link packets are broadcasted on
* their interface only
* - > aggregate packet if the current packet is
* a " global " packet as well as the base
* packet
*/
2012-05-12 13:48:54 +02:00
primary_if = batadv_primary_if_get_selected ( bat_priv ) ;
2011-08-03 09:09:30 +02:00
if ( ! primary_if )
goto out ;
/* packets without direct link flag and high TTL
2012-05-12 02:09:43 +02:00
* are flooded through the net
*/
2011-08-03 09:09:30 +02:00
if ( ( ! directlink ) & &
( ! ( batman_ogm_packet - > flags & DIRECTLINK ) ) & &
2011-11-20 15:47:38 +01:00
( batman_ogm_packet - > header . ttl ! = 1 ) & &
2011-08-03 09:09:30 +02:00
/* own packets originating non-primary
2012-05-12 02:09:43 +02:00
* interfaces leave only that interface
*/
2011-08-03 09:09:30 +02:00
( ( ! forw_packet - > own ) | |
( forw_packet - > if_incoming = = primary_if ) ) ) {
res = true ;
goto out ;
}
/* if the incoming packet is sent via this one
2012-05-12 02:09:43 +02:00
* interface only - we still can aggregate
*/
2011-08-03 09:09:30 +02:00
if ( ( directlink ) & &
2012-05-12 18:33:51 +02:00
( new_bat_ogm_packet - > header . ttl = = 1 ) & &
2011-08-03 09:09:30 +02:00
( forw_packet - > if_incoming = = if_incoming ) & &
/* packets from direct neighbors or
* own secondary interface packets
2012-05-12 02:09:43 +02:00
* ( = secondary interface packets in general )
*/
2011-08-03 09:09:30 +02:00
( batman_ogm_packet - > flags & DIRECTLINK | |
( forw_packet - > own & &
forw_packet - > if_incoming ! = primary_if ) ) ) {
res = true ;
goto out ;
}
}
out :
if ( primary_if )
2012-05-12 13:48:54 +02:00
batadv_hardif_free_ref ( primary_if ) ;
2011-08-03 09:09:30 +02:00
return res ;
}
/* create a new aggregated packet and add this packet to it */
2012-05-12 18:33:51 +02:00
static void batadv_iv_ogm_aggregate_new ( const unsigned char * packet_buff ,
int packet_len , unsigned long send_time ,
bool direct_link ,
struct hard_iface * if_incoming ,
int own_packet )
2011-08-03 09:09:30 +02:00
{
struct bat_priv * bat_priv = netdev_priv ( if_incoming - > soft_iface ) ;
struct forw_packet * forw_packet_aggr ;
unsigned char * skb_buff ;
2012-06-03 22:19:17 +02:00
unsigned int skb_size ;
2011-08-03 09:09:30 +02:00
if ( ! atomic_inc_not_zero ( & if_incoming - > refcount ) )
return ;
/* own packet should always be scheduled */
if ( ! own_packet ) {
2012-05-16 20:23:22 +02:00
if ( ! batadv_atomic_dec_not_zero ( & bat_priv - > batman_queue_left ) ) {
2012-05-12 13:48:58 +02:00
batadv_dbg ( DBG_BATMAN , bat_priv ,
" batman packet queue full \n " ) ;
2011-08-03 09:09:30 +02:00
goto out ;
}
}
forw_packet_aggr = kmalloc ( sizeof ( * forw_packet_aggr ) , GFP_ATOMIC ) ;
if ( ! forw_packet_aggr ) {
if ( ! own_packet )
atomic_inc ( & bat_priv - > batman_queue_left ) ;
goto out ;
}
if ( ( atomic_read ( & bat_priv - > aggregated_ogms ) ) & &
2012-06-03 22:19:17 +02:00
( packet_len < BATADV_MAX_AGGREGATION_BYTES ) )
skb_size = BATADV_MAX_AGGREGATION_BYTES + ETH_HLEN ;
2011-08-03 09:09:30 +02:00
else
2012-06-03 22:19:17 +02:00
skb_size = packet_len + ETH_HLEN ;
2011-08-03 09:09:30 +02:00
2012-06-03 22:19:17 +02:00
forw_packet_aggr - > skb = dev_alloc_skb ( skb_size ) ;
2011-08-03 09:09:30 +02:00
if ( ! forw_packet_aggr - > skb ) {
if ( ! own_packet )
atomic_inc ( & bat_priv - > batman_queue_left ) ;
kfree ( forw_packet_aggr ) ;
goto out ;
}
2012-02-18 11:27:34 +01:00
skb_reserve ( forw_packet_aggr - > skb , ETH_HLEN ) ;
2011-08-03 09:09:30 +02:00
INIT_HLIST_NODE ( & forw_packet_aggr - > list ) ;
skb_buff = skb_put ( forw_packet_aggr - > skb , packet_len ) ;
forw_packet_aggr - > packet_len = packet_len ;
memcpy ( skb_buff , packet_buff , packet_len ) ;
forw_packet_aggr - > own = own_packet ;
forw_packet_aggr - > if_incoming = if_incoming ;
forw_packet_aggr - > num_packets = 0 ;
2012-06-03 22:19:17 +02:00
forw_packet_aggr - > direct_link_flags = BATADV_NO_FLAGS ;
2011-08-03 09:09:30 +02:00
forw_packet_aggr - > send_time = send_time ;
/* save packet direct link flag status */
if ( direct_link )
forw_packet_aggr - > direct_link_flags | = 1 ;
/* add new packet to packet list */
spin_lock_bh ( & bat_priv - > forw_bat_list_lock ) ;
hlist_add_head ( & forw_packet_aggr - > list , & bat_priv - > forw_bat_list ) ;
spin_unlock_bh ( & bat_priv - > forw_bat_list_lock ) ;
/* start timer for this packet */
INIT_DELAYED_WORK ( & forw_packet_aggr - > delayed_work ,
2012-05-12 02:09:37 +02:00
batadv_send_outstanding_bat_ogm_packet ) ;
2012-05-12 02:09:42 +02:00
queue_delayed_work ( batadv_event_workqueue ,
2011-08-03 09:09:30 +02:00
& forw_packet_aggr - > delayed_work ,
send_time - jiffies ) ;
return ;
out :
2012-05-12 13:48:54 +02:00
batadv_hardif_free_ref ( if_incoming ) ;
2011-08-03 09:09:30 +02:00
}
/* aggregate a new packet into the existing ogm packet */
2012-05-12 18:33:51 +02:00
static void batadv_iv_ogm_aggregate ( struct forw_packet * forw_packet_aggr ,
const unsigned char * packet_buff ,
int packet_len , bool direct_link )
2011-08-03 09:09:30 +02:00
{
unsigned char * skb_buff ;
skb_buff = skb_put ( forw_packet_aggr - > skb , packet_len ) ;
memcpy ( skb_buff , packet_buff , packet_len ) ;
forw_packet_aggr - > packet_len + = packet_len ;
forw_packet_aggr - > num_packets + + ;
/* save packet direct link flag status */
if ( direct_link )
forw_packet_aggr - > direct_link_flags | =
( 1 < < forw_packet_aggr - > num_packets ) ;
}
2012-05-12 18:33:51 +02:00
static void batadv_iv_ogm_queue_add ( struct bat_priv * bat_priv ,
unsigned char * packet_buff ,
int packet_len ,
struct hard_iface * if_incoming ,
int own_packet , unsigned long send_time )
2011-08-03 09:09:30 +02:00
{
2012-05-12 02:09:43 +02:00
/* _aggr -> pointer to the packet we want to aggregate with
2011-08-03 09:09:30 +02:00
* _pos - > pointer to the position in the queue
*/
struct forw_packet * forw_packet_aggr = NULL , * forw_packet_pos = NULL ;
struct hlist_node * tmp_node ;
struct batman_ogm_packet * batman_ogm_packet ;
bool direct_link ;
2012-06-03 22:19:17 +02:00
unsigned long max_aggregation_jiffies ;
2011-08-03 09:09:30 +02:00
batman_ogm_packet = ( struct batman_ogm_packet * ) packet_buff ;
direct_link = batman_ogm_packet - > flags & DIRECTLINK ? 1 : 0 ;
2012-06-03 22:19:17 +02:00
max_aggregation_jiffies = msecs_to_jiffies ( BATADV_MAX_AGGREGATION_MS ) ;
2011-08-03 09:09:30 +02:00
/* find position for the packet in the forward queue */
spin_lock_bh ( & bat_priv - > forw_bat_list_lock ) ;
/* own packets are not to be aggregated */
if ( ( atomic_read ( & bat_priv - > aggregated_ogms ) ) & & ( ! own_packet ) ) {
hlist_for_each_entry ( forw_packet_pos , tmp_node ,
& bat_priv - > forw_bat_list , list ) {
2012-05-12 18:33:51 +02:00
if ( batadv_iv_ogm_can_aggregate ( batman_ogm_packet ,
bat_priv , packet_len ,
send_time , direct_link ,
if_incoming ,
forw_packet_pos ) ) {
2011-08-03 09:09:30 +02:00
forw_packet_aggr = forw_packet_pos ;
break ;
}
}
}
/* nothing to aggregate with - either aggregation disabled or no
2012-05-12 02:09:43 +02:00
* suitable aggregation packet found
*/
2011-08-03 09:09:30 +02:00
if ( ! forw_packet_aggr ) {
/* the following section can run without the lock */
spin_unlock_bh ( & bat_priv - > forw_bat_list_lock ) ;
2012-05-12 02:09:43 +02:00
/* if we could not aggregate this packet with one of the others
2011-08-03 09:09:30 +02:00
* we hold it back for a while , so that it might be aggregated
* later on
*/
2012-06-03 22:19:17 +02:00
if ( ! own_packet & & atomic_read ( & bat_priv - > aggregated_ogms ) )
send_time + = max_aggregation_jiffies ;
2011-08-03 09:09:30 +02:00
2012-05-12 18:33:51 +02:00
batadv_iv_ogm_aggregate_new ( packet_buff , packet_len ,
send_time , direct_link ,
if_incoming , own_packet ) ;
2011-08-03 09:09:30 +02:00
} else {
2012-05-12 18:33:51 +02:00
batadv_iv_ogm_aggregate ( forw_packet_aggr , packet_buff ,
packet_len , direct_link ) ;
2011-08-03 09:09:30 +02:00
spin_unlock_bh ( & bat_priv - > forw_bat_list_lock ) ;
}
}
2012-05-12 18:33:51 +02:00
static void batadv_iv_ogm_forward ( struct orig_node * orig_node ,
const struct ethhdr * ethhdr ,
struct batman_ogm_packet * batman_ogm_packet ,
bool is_single_hop_neigh ,
bool is_from_best_next_hop ,
struct hard_iface * if_incoming )
2011-08-03 09:09:30 +02:00
{
struct bat_priv * bat_priv = netdev_priv ( if_incoming - > soft_iface ) ;
uint8_t tt_num_changes ;
2011-11-20 15:47:38 +01:00
if ( batman_ogm_packet - > header . ttl < = 1 ) {
2012-05-12 13:48:58 +02:00
batadv_dbg ( DBG_BATMAN , bat_priv , " ttl exceeded \n " ) ;
2011-08-03 09:09:30 +02:00
return ;
}
2012-03-11 06:17:53 +08:00
if ( ! is_from_best_next_hop ) {
/* Mark the forwarded packet when it is not coming from our
* best next hop . We still need to forward the packet for our
* neighbor link quality detection to work in case the packet
* originated from a single hop neighbor . Otherwise we can
* simply drop the ogm .
*/
if ( is_single_hop_neigh )
batman_ogm_packet - > flags | = NOT_BEST_NEXT_HOP ;
else
return ;
}
2011-08-03 09:09:30 +02:00
tt_num_changes = batman_ogm_packet - > tt_num_changes ;
2011-11-20 15:47:38 +01:00
batman_ogm_packet - > header . ttl - - ;
2011-08-03 09:09:30 +02:00
memcpy ( batman_ogm_packet - > prev_sender , ethhdr - > h_source , ETH_ALEN ) ;
/* apply hop penalty */
2012-05-12 18:33:51 +02:00
batman_ogm_packet - > tq = batadv_hop_penalty ( batman_ogm_packet - > tq ,
bat_priv ) ;
2011-08-03 09:09:30 +02:00
2012-05-12 13:48:58 +02:00
batadv_dbg ( DBG_BATMAN , bat_priv ,
" Forwarding packet: tq: %i, ttl: %i \n " ,
batman_ogm_packet - > tq , batman_ogm_packet - > header . ttl ) ;
2011-08-03 09:09:30 +02:00
/* switch of primaries first hop flag when forwarding */
batman_ogm_packet - > flags & = ~ PRIMARIES_FIRST_HOP ;
2012-03-01 15:35:16 +08:00
if ( is_single_hop_neigh )
2011-08-03 09:09:30 +02:00
batman_ogm_packet - > flags | = DIRECTLINK ;
else
batman_ogm_packet - > flags & = ~ DIRECTLINK ;
2012-05-12 18:33:51 +02:00
batadv_iv_ogm_queue_add ( bat_priv , ( unsigned char * ) batman_ogm_packet ,
2012-06-03 22:19:13 +02:00
BATADV_OGM_HLEN + batadv_tt_len ( tt_num_changes ) ,
2012-05-12 18:33:51 +02:00
if_incoming , 0 , batadv_iv_ogm_fwd_send_time ( ) ) ;
2011-08-03 09:09:30 +02:00
}
2012-05-12 18:33:51 +02:00
static void batadv_iv_ogm_schedule ( struct hard_iface * hard_iface )
2011-08-03 09:09:30 +02:00
{
struct bat_priv * bat_priv = netdev_priv ( hard_iface - > soft_iface ) ;
struct batman_ogm_packet * batman_ogm_packet ;
struct hard_iface * primary_if ;
2012-05-07 04:22:05 +08:00
int vis_server , tt_num_changes = 0 ;
2011-08-03 09:09:30 +02:00
vis_server = atomic_read ( & bat_priv - > vis_mode ) ;
2012-05-12 13:48:54 +02:00
primary_if = batadv_primary_if_get_selected ( bat_priv ) ;
2011-08-03 09:09:30 +02:00
2012-05-07 04:22:05 +08:00
if ( hard_iface = = primary_if )
tt_num_changes = batadv_tt_append_diff ( bat_priv ,
& hard_iface - > packet_buff ,
& hard_iface - > packet_len ,
2012-06-03 22:19:13 +02:00
BATADV_OGM_HLEN ) ;
2012-05-07 04:22:05 +08:00
2011-08-03 09:09:30 +02:00
batman_ogm_packet = ( struct batman_ogm_packet * ) hard_iface - > packet_buff ;
/* change sequence number to network order */
batman_ogm_packet - > seqno =
htonl ( ( uint32_t ) atomic_read ( & hard_iface - > seqno ) ) ;
2012-05-07 04:22:05 +08:00
atomic_inc ( & hard_iface - > seqno ) ;
2011-08-03 09:09:30 +02:00
batman_ogm_packet - > ttvn = atomic_read ( & bat_priv - > ttvn ) ;
2012-04-14 13:15:26 +02:00
batman_ogm_packet - > tt_crc = htons ( bat_priv - > tt_crc ) ;
2011-08-03 09:09:30 +02:00
if ( tt_num_changes > = 0 )
batman_ogm_packet - > tt_num_changes = tt_num_changes ;
if ( vis_server = = VIS_TYPE_SERVER_SYNC )
batman_ogm_packet - > flags | = VIS_SERVER ;
else
batman_ogm_packet - > flags & = ~ VIS_SERVER ;
if ( ( hard_iface = = primary_if ) & &
( atomic_read ( & bat_priv - > gw_mode ) = = GW_MODE_SERVER ) )
batman_ogm_packet - > gw_flags =
( uint8_t ) atomic_read ( & bat_priv - > gw_bandwidth ) ;
else
2012-06-03 22:19:17 +02:00
batman_ogm_packet - > gw_flags = BATADV_NO_FLAGS ;
2011-08-03 09:09:30 +02:00
2012-05-12 02:09:36 +02:00
batadv_slide_own_bcast_window ( hard_iface ) ;
2012-05-12 18:33:51 +02:00
batadv_iv_ogm_queue_add ( bat_priv , hard_iface - > packet_buff ,
hard_iface - > packet_len , hard_iface , 1 ,
batadv_iv_ogm_emit_send_time ( bat_priv ) ) ;
2011-08-03 09:09:30 +02:00
if ( primary_if )
2012-05-12 13:48:54 +02:00
batadv_hardif_free_ref ( primary_if ) ;
2011-08-03 09:09:30 +02:00
}
2012-05-12 18:33:51 +02:00
static void
batadv_iv_ogm_orig_update ( struct bat_priv * bat_priv ,
struct orig_node * orig_node ,
const struct ethhdr * ethhdr ,
const struct batman_ogm_packet * batman_ogm_packet ,
struct hard_iface * if_incoming ,
const unsigned char * tt_buff ,
int is_duplicate )
2011-07-30 12:04:12 +02:00
{
struct neigh_node * neigh_node = NULL , * tmp_neigh_node = NULL ;
struct neigh_node * router = NULL ;
struct orig_node * orig_node_tmp ;
struct hlist_node * node ;
uint8_t bcast_own_sum_orig , bcast_own_sum_neigh ;
2012-05-12 13:48:58 +02:00
uint8_t * neigh_addr ;
2011-07-30 12:04:12 +02:00
2012-05-12 13:48:58 +02:00
batadv_dbg ( DBG_BATMAN , bat_priv ,
" update_originator(): Searching and updating originator entry of received packet \n " ) ;
2011-07-30 12:04:12 +02:00
rcu_read_lock ( ) ;
hlist_for_each_entry_rcu ( tmp_neigh_node , node ,
& orig_node - > neigh_list , list ) {
2012-05-12 13:48:58 +02:00
neigh_addr = tmp_neigh_node - > addr ;
if ( batadv_compare_eth ( neigh_addr , ethhdr - > h_source ) & &
tmp_neigh_node - > if_incoming = = if_incoming & &
atomic_inc_not_zero ( & tmp_neigh_node - > refcount ) ) {
2011-07-30 12:04:12 +02:00
if ( neigh_node )
2012-05-12 02:09:34 +02:00
batadv_neigh_node_free_ref ( neigh_node ) ;
2011-07-30 12:04:12 +02:00
neigh_node = tmp_neigh_node ;
continue ;
}
if ( is_duplicate )
continue ;
2012-03-17 15:28:32 +08:00
spin_lock_bh ( & tmp_neigh_node - > lq_update_lock ) ;
2012-05-12 02:09:35 +02:00
batadv_ring_buffer_set ( tmp_neigh_node - > tq_recv ,
& tmp_neigh_node - > tq_index , 0 ) ;
2011-07-30 12:04:12 +02:00
tmp_neigh_node - > tq_avg =
2012-05-12 02:09:35 +02:00
batadv_ring_buffer_avg ( tmp_neigh_node - > tq_recv ) ;
2012-03-17 15:28:32 +08:00
spin_unlock_bh ( & tmp_neigh_node - > lq_update_lock ) ;
2011-07-30 12:04:12 +02:00
}
if ( ! neigh_node ) {
struct orig_node * orig_tmp ;
2012-05-12 02:09:34 +02:00
orig_tmp = batadv_get_orig_node ( bat_priv , ethhdr - > h_source ) ;
2011-07-30 12:04:12 +02:00
if ( ! orig_tmp )
goto unlock ;
2012-05-12 18:33:51 +02:00
neigh_node = batadv_iv_ogm_neigh_new ( if_incoming ,
ethhdr - > h_source ,
orig_node , orig_tmp ,
batman_ogm_packet - > seqno ) ;
2011-07-30 12:04:12 +02:00
2012-05-12 02:09:34 +02:00
batadv_orig_node_free_ref ( orig_tmp ) ;
2011-07-30 12:04:12 +02:00
if ( ! neigh_node )
goto unlock ;
} else
2012-05-12 13:48:58 +02:00
batadv_dbg ( DBG_BATMAN , bat_priv ,
" Updating existing last-hop neighbor of originator \n " ) ;
2011-07-30 12:04:12 +02:00
rcu_read_unlock ( ) ;
orig_node - > flags = batman_ogm_packet - > flags ;
2012-03-01 15:35:19 +08:00
neigh_node - > last_seen = jiffies ;
2011-07-30 12:04:12 +02:00
2012-03-17 15:28:32 +08:00
spin_lock_bh ( & neigh_node - > lq_update_lock ) ;
2012-05-12 02:09:35 +02:00
batadv_ring_buffer_set ( neigh_node - > tq_recv ,
& neigh_node - > tq_index ,
batman_ogm_packet - > tq ) ;
neigh_node - > tq_avg = batadv_ring_buffer_avg ( neigh_node - > tq_recv ) ;
2012-03-17 15:28:32 +08:00
spin_unlock_bh ( & neigh_node - > lq_update_lock ) ;
2011-07-30 12:04:12 +02:00
if ( ! is_duplicate ) {
2011-11-20 15:47:38 +01:00
orig_node - > last_ttl = batman_ogm_packet - > header . ttl ;
neigh_node - > last_ttl = batman_ogm_packet - > header . ttl ;
2011-07-30 12:04:12 +02:00
}
2012-05-12 02:09:36 +02:00
batadv_bonding_candidate_add ( orig_node , neigh_node ) ;
2011-07-30 12:04:12 +02:00
/* if this neighbor already is our next hop there is nothing
2012-05-12 02:09:43 +02:00
* to change
*/
2012-05-12 02:09:34 +02:00
router = batadv_orig_node_get_router ( orig_node ) ;
2011-07-30 12:04:12 +02:00
if ( router = = neigh_node )
goto update_tt ;
/* if this neighbor does not offer a better TQ we won't consider it */
if ( router & & ( router - > tq_avg > neigh_node - > tq_avg ) )
goto update_tt ;
/* if the TQ is the same and the link not more symmetric we
2012-05-12 02:09:43 +02:00
* won ' t consider it either
*/
2011-07-30 12:04:12 +02:00
if ( router & & ( neigh_node - > tq_avg = = router - > tq_avg ) ) {
orig_node_tmp = router - > orig_node ;
spin_lock_bh ( & orig_node_tmp - > ogm_cnt_lock ) ;
bcast_own_sum_orig =
orig_node_tmp - > bcast_own_sum [ if_incoming - > if_num ] ;
spin_unlock_bh ( & orig_node_tmp - > ogm_cnt_lock ) ;
orig_node_tmp = neigh_node - > orig_node ;
spin_lock_bh ( & orig_node_tmp - > ogm_cnt_lock ) ;
bcast_own_sum_neigh =
orig_node_tmp - > bcast_own_sum [ if_incoming - > if_num ] ;
spin_unlock_bh ( & orig_node_tmp - > ogm_cnt_lock ) ;
if ( bcast_own_sum_orig > = bcast_own_sum_neigh )
goto update_tt ;
}
2012-05-12 02:09:36 +02:00
batadv_update_route ( bat_priv , orig_node , neigh_node ) ;
2011-07-30 12:04:12 +02:00
update_tt :
/* I have to check for transtable changes only if the OGM has been
2012-05-12 02:09:43 +02:00
* sent through a primary interface
*/
2011-07-30 12:04:12 +02:00
if ( ( ( batman_ogm_packet - > orig ! = ethhdr - > h_source ) & &
2011-11-20 15:47:38 +01:00
( batman_ogm_packet - > header . ttl > 2 ) ) | |
2011-07-30 12:04:12 +02:00
( batman_ogm_packet - > flags & PRIMARIES_FIRST_HOP ) )
2012-05-12 02:09:39 +02:00
batadv_tt_update_orig ( bat_priv , orig_node , tt_buff ,
batman_ogm_packet - > tt_num_changes ,
batman_ogm_packet - > ttvn ,
ntohs ( batman_ogm_packet - > tt_crc ) ) ;
2011-07-30 12:04:12 +02:00
if ( orig_node - > gw_flags ! = batman_ogm_packet - > gw_flags )
2012-05-12 02:09:29 +02:00
batadv_gw_node_update ( bat_priv , orig_node ,
batman_ogm_packet - > gw_flags ) ;
2011-07-30 12:04:12 +02:00
orig_node - > gw_flags = batman_ogm_packet - > gw_flags ;
/* restart gateway selection if fast or late switching was enabled */
if ( ( orig_node - > gw_flags ) & &
( atomic_read ( & bat_priv - > gw_mode ) = = GW_MODE_CLIENT ) & &
( atomic_read ( & bat_priv - > gw_sel_class ) > 2 ) )
2012-05-12 02:09:29 +02:00
batadv_gw_check_election ( bat_priv , orig_node ) ;
2011-07-30 12:04:12 +02:00
goto out ;
unlock :
rcu_read_unlock ( ) ;
out :
if ( neigh_node )
2012-05-12 02:09:34 +02:00
batadv_neigh_node_free_ref ( neigh_node ) ;
2011-07-30 12:04:12 +02:00
if ( router )
2012-05-12 02:09:34 +02:00
batadv_neigh_node_free_ref ( router ) ;
2011-07-30 12:04:12 +02:00
}
2012-05-12 18:33:51 +02:00
static int batadv_iv_ogm_calc_tq ( struct orig_node * orig_node ,
struct orig_node * orig_neigh_node ,
struct batman_ogm_packet * batman_ogm_packet ,
struct hard_iface * if_incoming )
2011-07-30 12:04:12 +02:00
{
struct bat_priv * bat_priv = netdev_priv ( if_incoming - > soft_iface ) ;
struct neigh_node * neigh_node = NULL , * tmp_neigh_node ;
struct hlist_node * node ;
uint8_t total_count ;
2012-06-03 22:19:17 +02:00
uint8_t orig_eq_count , neigh_rq_count , neigh_rq_inv , tq_own ;
unsigned int neigh_rq_inv_cube , neigh_rq_max_cube ;
int tq_asym_penalty , inv_asym_penalty , ret = 0 ;
unsigned int combined_tq ;
2011-07-30 12:04:12 +02:00
/* find corresponding one hop neighbor */
rcu_read_lock ( ) ;
hlist_for_each_entry_rcu ( tmp_neigh_node , node ,
& orig_neigh_node - > neigh_list , list ) {
2012-05-12 13:48:58 +02:00
if ( ! batadv_compare_eth ( tmp_neigh_node - > addr ,
orig_neigh_node - > orig ) )
2011-07-30 12:04:12 +02:00
continue ;
if ( tmp_neigh_node - > if_incoming ! = if_incoming )
continue ;
if ( ! atomic_inc_not_zero ( & tmp_neigh_node - > refcount ) )
continue ;
neigh_node = tmp_neigh_node ;
break ;
}
rcu_read_unlock ( ) ;
if ( ! neigh_node )
2012-05-12 18:33:51 +02:00
neigh_node = batadv_iv_ogm_neigh_new ( if_incoming ,
orig_neigh_node - > orig ,
orig_neigh_node ,
orig_neigh_node ,
batman_ogm_packet - > seqno ) ;
2011-07-30 12:04:12 +02:00
if ( ! neigh_node )
goto out ;
2012-03-01 15:35:19 +08:00
/* if orig_node is direct neighbor update neigh_node last_seen */
2011-07-30 12:04:12 +02:00
if ( orig_node = = orig_neigh_node )
2012-03-01 15:35:19 +08:00
neigh_node - > last_seen = jiffies ;
2011-07-30 12:04:12 +02:00
2012-03-01 15:35:19 +08:00
orig_node - > last_seen = jiffies ;
2011-07-30 12:04:12 +02:00
/* find packet count of corresponding one hop neighbor */
spin_lock_bh ( & orig_node - > ogm_cnt_lock ) ;
orig_eq_count = orig_neigh_node - > bcast_own_sum [ if_incoming - > if_num ] ;
neigh_rq_count = neigh_node - > real_packet_count ;
spin_unlock_bh ( & orig_node - > ogm_cnt_lock ) ;
/* pay attention to not get a value bigger than 100 % */
total_count = ( orig_eq_count > neigh_rq_count ?
neigh_rq_count : orig_eq_count ) ;
2012-05-12 02:09:43 +02:00
/* if we have too few packets (too less data) we set tq_own to zero
* if we receive too few packets it is not considered bidirectional
*/
2012-06-03 22:19:17 +02:00
if ( total_count < BATADV_TQ_LOCAL_BIDRECT_SEND_MINIMUM | |
neigh_rq_count < BATADV_TQ_LOCAL_BIDRECT_RECV_MINIMUM )
2011-07-30 12:04:12 +02:00
tq_own = 0 ;
else
/* neigh_node->real_packet_count is never zero as we
* only purge old information when getting new
2012-05-12 02:09:43 +02:00
* information
*/
2012-06-03 22:19:17 +02:00
tq_own = ( BATADV_TQ_MAX_VALUE * total_count ) / neigh_rq_count ;
2011-07-30 12:04:12 +02:00
2012-03-07 09:07:46 +01:00
/* 1 - ((1-x) ** 3), normalized to TQ_MAX_VALUE this does
2011-07-30 12:04:12 +02:00
* affect the nearly - symmetric links only a little , but
* punishes asymmetric links more . This will give a value
* between 0 and TQ_MAX_VALUE
*/
2012-06-03 22:19:17 +02:00
neigh_rq_inv = BATADV_TQ_LOCAL_WINDOW_SIZE - neigh_rq_count ;
neigh_rq_inv_cube = neigh_rq_inv * neigh_rq_inv * neigh_rq_inv ;
neigh_rq_max_cube = BATADV_TQ_LOCAL_WINDOW_SIZE *
BATADV_TQ_LOCAL_WINDOW_SIZE *
BATADV_TQ_LOCAL_WINDOW_SIZE ;
inv_asym_penalty = BATADV_TQ_MAX_VALUE * neigh_rq_inv_cube ;
inv_asym_penalty / = neigh_rq_max_cube ;
tq_asym_penalty = BATADV_TQ_MAX_VALUE - inv_asym_penalty ;
combined_tq = batman_ogm_packet - > tq * tq_own * tq_asym_penalty ;
combined_tq / = BATADV_TQ_MAX_VALUE * BATADV_TQ_MAX_VALUE ;
batman_ogm_packet - > tq = combined_tq ;
2011-07-30 12:04:12 +02:00
2012-05-12 13:48:58 +02:00
batadv_dbg ( DBG_BATMAN , bat_priv ,
" bidirectional: orig = %-15pM neigh = %-15pM => own_bcast = %2i, real recv = %2i, local tq: %3i, asym_penalty: %3i, total tq: %3i \n " ,
orig_node - > orig , orig_neigh_node - > orig , total_count ,
neigh_rq_count , tq_own ,
tq_asym_penalty , batman_ogm_packet - > tq ) ;
2011-07-30 12:04:12 +02:00
/* if link has the minimum required transmission quality
2012-05-12 02:09:43 +02:00
* consider it bidirectional
*/
2012-06-03 22:19:17 +02:00
if ( batman_ogm_packet - > tq > = BATADV_TQ_TOTAL_BIDRECT_LIMIT )
2011-07-30 12:04:12 +02:00
ret = 1 ;
out :
if ( neigh_node )
2012-05-12 02:09:34 +02:00
batadv_neigh_node_free_ref ( neigh_node ) ;
2011-07-30 12:04:12 +02:00
return ret ;
}
/* processes a batman packet for all interfaces, adjusts the sequence number and
* finds out whether it is a duplicate .
* returns :
* 1 the packet is a duplicate
* 0 the packet has not yet been received
* - 1 the packet is old and has been received while the seqno window
* was protected . Caller should drop it .
*/
2012-05-12 18:33:51 +02:00
static int
batadv_iv_ogm_update_seqnos ( const struct ethhdr * ethhdr ,
const struct batman_ogm_packet * batman_ogm_packet ,
const struct hard_iface * if_incoming )
2011-07-30 12:04:12 +02:00
{
struct bat_priv * bat_priv = netdev_priv ( if_incoming - > soft_iface ) ;
struct orig_node * orig_node ;
struct neigh_node * tmp_neigh_node ;
struct hlist_node * node ;
int is_duplicate = 0 ;
int32_t seq_diff ;
int need_update = 0 ;
int set_mark , ret = - 1 ;
2012-04-22 07:46:29 +01:00
uint32_t seqno = ntohl ( batman_ogm_packet - > seqno ) ;
2012-05-12 13:48:58 +02:00
uint8_t * neigh_addr ;
2011-07-30 12:04:12 +02:00
2012-05-12 02:09:34 +02:00
orig_node = batadv_get_orig_node ( bat_priv , batman_ogm_packet - > orig ) ;
2011-07-30 12:04:12 +02:00
if ( ! orig_node )
return 0 ;
spin_lock_bh ( & orig_node - > ogm_cnt_lock ) ;
2012-04-22 07:46:29 +01:00
seq_diff = seqno - orig_node - > last_real_seqno ;
2011-07-30 12:04:12 +02:00
/* signalize caller that the packet is to be dropped. */
2012-02-26 15:39:42 +01:00
if ( ! hlist_empty ( & orig_node - > neigh_list ) & &
2012-05-12 02:09:36 +02:00
batadv_window_protected ( bat_priv , seq_diff ,
& orig_node - > batman_seqno_reset ) )
2011-07-30 12:04:12 +02:00
goto out ;
rcu_read_lock ( ) ;
hlist_for_each_entry_rcu ( tmp_neigh_node , node ,
& orig_node - > neigh_list , list ) {
2012-05-12 13:48:53 +02:00
is_duplicate | = batadv_test_bit ( tmp_neigh_node - > real_bits ,
orig_node - > last_real_seqno ,
seqno ) ;
2011-07-30 12:04:12 +02:00
2012-05-12 13:48:58 +02:00
neigh_addr = tmp_neigh_node - > addr ;
if ( batadv_compare_eth ( neigh_addr , ethhdr - > h_source ) & &
tmp_neigh_node - > if_incoming = = if_incoming )
2011-07-30 12:04:12 +02:00
set_mark = 1 ;
else
set_mark = 0 ;
/* if the window moved, set the update flag. */
2012-05-12 02:09:25 +02:00
need_update | = batadv_bit_get_packet ( bat_priv ,
tmp_neigh_node - > real_bits ,
seq_diff , set_mark ) ;
2011-07-30 12:04:12 +02:00
tmp_neigh_node - > real_packet_count =
2012-02-04 17:34:52 +01:00
bitmap_weight ( tmp_neigh_node - > real_bits ,
2012-06-03 22:19:17 +02:00
BATADV_TQ_LOCAL_WINDOW_SIZE ) ;
2011-07-30 12:04:12 +02:00
}
rcu_read_unlock ( ) ;
if ( need_update ) {
2012-05-12 13:48:58 +02:00
batadv_dbg ( DBG_BATMAN , bat_priv ,
" updating last_seqno: old %u, new %u \n " ,
orig_node - > last_real_seqno , seqno ) ;
2012-04-22 07:46:29 +01:00
orig_node - > last_real_seqno = seqno ;
2011-07-30 12:04:12 +02:00
}
ret = is_duplicate ;
out :
spin_unlock_bh ( & orig_node - > ogm_cnt_lock ) ;
2012-05-12 02:09:34 +02:00
batadv_orig_node_free_ref ( orig_node ) ;
2011-07-30 12:04:12 +02:00
return ret ;
}
2012-05-12 18:33:51 +02:00
static void batadv_iv_ogm_process ( const struct ethhdr * ethhdr ,
struct batman_ogm_packet * batman_ogm_packet ,
const unsigned char * tt_buff ,
struct hard_iface * if_incoming )
2011-07-30 12:04:12 +02:00
{
struct bat_priv * bat_priv = netdev_priv ( if_incoming - > soft_iface ) ;
struct hard_iface * hard_iface ;
struct orig_node * orig_neigh_node , * orig_node ;
struct neigh_node * router = NULL , * router_router = NULL ;
struct neigh_node * orig_neigh_router = NULL ;
int has_directlink_flag ;
int is_my_addr = 0 , is_my_orig = 0 , is_my_oldorig = 0 ;
2012-05-12 18:33:51 +02:00
int is_broadcast = 0 , is_bidirect ;
2012-03-01 15:35:16 +08:00
bool is_single_hop_neigh = false ;
2012-03-11 06:17:53 +08:00
bool is_from_best_next_hop = false ;
2012-05-12 18:33:51 +02:00
int is_duplicate , sameseq , simlar_ttl ;
2011-07-30 12:04:12 +02:00
uint32_t if_incoming_seqno ;
2012-05-12 13:48:58 +02:00
uint8_t * prev_sender ;
2011-07-30 12:04:12 +02:00
/* Silently drop when the batman packet is actually not a
* correct packet .
*
* This might happen if a packet is padded ( e . g . Ethernet has a
* minimum frame length of 64 byte ) and the aggregation interprets
* it as an additional length .
*
* TODO : A more sane solution would be to have a bit in the
* batman_ogm_packet to detect whether the packet is the last
* packet in an aggregation . Here we expect that the padding
* is always zero ( or not 0x01 )
*/
2012-02-07 17:20:51 +08:00
if ( batman_ogm_packet - > header . packet_type ! = BAT_IV_OGM )
2011-07-30 12:04:12 +02:00
return ;
/* could be changed by schedule_own_packet() */
if_incoming_seqno = atomic_read ( & if_incoming - > seqno ) ;
has_directlink_flag = ( batman_ogm_packet - > flags & DIRECTLINK ? 1 : 0 ) ;
2012-05-12 13:48:58 +02:00
if ( batadv_compare_eth ( ethhdr - > h_source , batman_ogm_packet - > orig ) )
2012-03-01 15:35:16 +08:00
is_single_hop_neigh = true ;
2011-07-30 12:04:12 +02:00
2012-05-12 13:48:58 +02:00
batadv_dbg ( DBG_BATMAN , bat_priv ,
" Received BATMAN packet via NB: %pM, IF: %s [%pM] (from OG: %pM, via prev OG: %pM, seqno %u, ttvn %u, crc %u, changes %u, td %d, TTL %d, V %d, IDF %d) \n " ,
ethhdr - > h_source , if_incoming - > net_dev - > name ,
if_incoming - > net_dev - > dev_addr , batman_ogm_packet - > orig ,
batman_ogm_packet - > prev_sender ,
ntohl ( batman_ogm_packet - > seqno ) , batman_ogm_packet - > ttvn ,
ntohs ( batman_ogm_packet - > tt_crc ) ,
batman_ogm_packet - > tt_num_changes , batman_ogm_packet - > tq ,
batman_ogm_packet - > header . ttl ,
batman_ogm_packet - > header . version , has_directlink_flag ) ;
2011-07-30 12:04:12 +02:00
rcu_read_lock ( ) ;
2012-05-12 02:09:42 +02:00
list_for_each_entry_rcu ( hard_iface , & batadv_hardif_list , list ) {
2011-07-30 12:04:12 +02:00
if ( hard_iface - > if_status ! = IF_ACTIVE )
continue ;
if ( hard_iface - > soft_iface ! = if_incoming - > soft_iface )
continue ;
2012-05-12 13:48:58 +02:00
if ( batadv_compare_eth ( ethhdr - > h_source ,
hard_iface - > net_dev - > dev_addr ) )
2011-07-30 12:04:12 +02:00
is_my_addr = 1 ;
2012-05-12 13:48:58 +02:00
if ( batadv_compare_eth ( batman_ogm_packet - > orig ,
hard_iface - > net_dev - > dev_addr ) )
2011-07-30 12:04:12 +02:00
is_my_orig = 1 ;
2012-05-12 13:48:58 +02:00
if ( batadv_compare_eth ( batman_ogm_packet - > prev_sender ,
hard_iface - > net_dev - > dev_addr ) )
2011-07-30 12:04:12 +02:00
is_my_oldorig = 1 ;
if ( is_broadcast_ether_addr ( ethhdr - > h_source ) )
is_broadcast = 1 ;
}
rcu_read_unlock ( ) ;
2012-06-03 22:19:13 +02:00
if ( batman_ogm_packet - > header . version ! = BATADV_COMPAT_VERSION ) {
2012-05-12 13:48:58 +02:00
batadv_dbg ( DBG_BATMAN , bat_priv ,
" Drop packet: incompatible batman version (%i) \n " ,
batman_ogm_packet - > header . version ) ;
2011-07-30 12:04:12 +02:00
return ;
}
if ( is_my_addr ) {
2012-05-12 13:48:58 +02:00
batadv_dbg ( DBG_BATMAN , bat_priv ,
" Drop packet: received my own broadcast (sender: %pM) \n " ,
ethhdr - > h_source ) ;
2011-07-30 12:04:12 +02:00
return ;
}
if ( is_broadcast ) {
2012-05-12 13:48:58 +02:00
batadv_dbg ( DBG_BATMAN , bat_priv ,
" Drop packet: ignoring all packets with broadcast source addr (sender: %pM) \n " ,
ethhdr - > h_source ) ;
2011-07-30 12:04:12 +02:00
return ;
}
if ( is_my_orig ) {
unsigned long * word ;
int offset ;
2012-05-12 13:48:53 +02:00
int32_t bit_pos ;
2012-06-03 22:19:17 +02:00
int16_t if_num ;
uint8_t * weight ;
2011-07-30 12:04:12 +02:00
2012-05-12 02:09:34 +02:00
orig_neigh_node = batadv_get_orig_node ( bat_priv ,
ethhdr - > h_source ) ;
2011-07-30 12:04:12 +02:00
if ( ! orig_neigh_node )
return ;
/* neighbor has to indicate direct link and it has to
2012-05-12 02:09:43 +02:00
* come via the corresponding interface
* save packet seqno for bidirectional check
*/
2011-07-30 12:04:12 +02:00
if ( has_directlink_flag & &
2012-05-12 13:48:58 +02:00
batadv_compare_eth ( if_incoming - > net_dev - > dev_addr ,
batman_ogm_packet - > orig ) ) {
2012-06-03 22:19:17 +02:00
if_num = if_incoming - > if_num ;
offset = if_num * BATADV_NUM_WORDS ;
2011-07-30 12:04:12 +02:00
spin_lock_bh ( & orig_neigh_node - > ogm_cnt_lock ) ;
word = & ( orig_neigh_node - > bcast_own [ offset ] ) ;
2012-05-12 13:48:53 +02:00
bit_pos = if_incoming_seqno - 2 ;
bit_pos - = ntohl ( batman_ogm_packet - > seqno ) ;
batadv_set_bit ( word , bit_pos ) ;
2012-06-03 22:19:17 +02:00
weight = & orig_neigh_node - > bcast_own_sum [ if_num ] ;
* weight = bitmap_weight ( word ,
BATADV_TQ_LOCAL_WINDOW_SIZE ) ;
2011-07-30 12:04:12 +02:00
spin_unlock_bh ( & orig_neigh_node - > ogm_cnt_lock ) ;
}
2012-05-12 13:48:58 +02:00
batadv_dbg ( DBG_BATMAN , bat_priv ,
" Drop packet: originator packet from myself (via neighbor) \n " ) ;
2012-05-12 02:09:34 +02:00
batadv_orig_node_free_ref ( orig_neigh_node ) ;
2011-07-30 12:04:12 +02:00
return ;
}
if ( is_my_oldorig ) {
2012-05-12 13:48:58 +02:00
batadv_dbg ( DBG_BATMAN , bat_priv ,
" Drop packet: ignoring all rebroadcast echos (sender: %pM) \n " ,
ethhdr - > h_source ) ;
2011-07-30 12:04:12 +02:00
return ;
}
2012-03-11 06:17:53 +08:00
if ( batman_ogm_packet - > flags & NOT_BEST_NEXT_HOP ) {
2012-05-12 13:48:58 +02:00
batadv_dbg ( DBG_BATMAN , bat_priv ,
" Drop packet: ignoring all packets not forwarded from the best next hop (sender: %pM) \n " ,
ethhdr - > h_source ) ;
2012-03-11 06:17:53 +08:00
return ;
}
2012-05-12 02:09:34 +02:00
orig_node = batadv_get_orig_node ( bat_priv , batman_ogm_packet - > orig ) ;
2011-07-30 12:04:12 +02:00
if ( ! orig_node )
return ;
2012-05-12 18:33:51 +02:00
is_duplicate = batadv_iv_ogm_update_seqnos ( ethhdr , batman_ogm_packet ,
if_incoming ) ;
2011-07-30 12:04:12 +02:00
if ( is_duplicate = = - 1 ) {
2012-05-12 13:48:58 +02:00
batadv_dbg ( DBG_BATMAN , bat_priv ,
" Drop packet: packet within seqno protection time (sender: %pM) \n " ,
ethhdr - > h_source ) ;
2011-07-30 12:04:12 +02:00
goto out ;
}
if ( batman_ogm_packet - > tq = = 0 ) {
2012-05-12 13:48:58 +02:00
batadv_dbg ( DBG_BATMAN , bat_priv ,
" Drop packet: originator packet with tq equal 0 \n " ) ;
2011-07-30 12:04:12 +02:00
goto out ;
}
2012-05-12 02:09:34 +02:00
router = batadv_orig_node_get_router ( orig_node ) ;
2011-07-30 12:04:12 +02:00
if ( router )
2012-05-12 02:09:34 +02:00
router_router = batadv_orig_node_get_router ( router - > orig_node ) ;
2011-07-30 12:04:12 +02:00
2012-03-11 06:17:53 +08:00
if ( ( router & & router - > tq_avg ! = 0 ) & &
2012-05-12 13:48:58 +02:00
( batadv_compare_eth ( router - > addr , ethhdr - > h_source ) ) )
2012-03-11 06:17:53 +08:00
is_from_best_next_hop = true ;
2012-05-12 13:48:58 +02:00
prev_sender = batman_ogm_packet - > prev_sender ;
2011-07-30 12:04:12 +02:00
/* avoid temporary routing loops */
if ( router & & router_router & &
2012-05-12 13:48:58 +02:00
( batadv_compare_eth ( router - > addr , prev_sender ) ) & &
! ( batadv_compare_eth ( batman_ogm_packet - > orig , prev_sender ) ) & &
( batadv_compare_eth ( router - > addr , router_router - > addr ) ) ) {
batadv_dbg ( DBG_BATMAN , bat_priv ,
" Drop packet: ignoring all rebroadcast packets that may make me loop (sender: %pM) \n " ,
ethhdr - > h_source ) ;
2011-07-30 12:04:12 +02:00
goto out ;
}
/* if sender is a direct neighbor the sender mac equals
2012-05-12 02:09:43 +02:00
* originator mac
*/
2011-07-30 12:04:12 +02:00
orig_neigh_node = ( is_single_hop_neigh ?
orig_node :
2012-05-12 02:09:34 +02:00
batadv_get_orig_node ( bat_priv , ethhdr - > h_source ) ) ;
2011-07-30 12:04:12 +02:00
if ( ! orig_neigh_node )
goto out ;
2012-05-12 02:09:34 +02:00
orig_neigh_router = batadv_orig_node_get_router ( orig_neigh_node ) ;
2011-07-30 12:04:12 +02:00
/* drop packet if sender is not a direct neighbor and if we
2012-05-12 02:09:43 +02:00
* don ' t route towards it
*/
2011-07-30 12:04:12 +02:00
if ( ! is_single_hop_neigh & & ( ! orig_neigh_router ) ) {
2012-05-12 13:48:58 +02:00
batadv_dbg ( DBG_BATMAN , bat_priv ,
" Drop packet: OGM via unknown neighbor! \n " ) ;
2011-07-30 12:04:12 +02:00
goto out_neigh ;
}
2012-05-12 18:33:51 +02:00
is_bidirect = batadv_iv_ogm_calc_tq ( orig_node , orig_neigh_node ,
batman_ogm_packet , if_incoming ) ;
2011-07-30 12:04:12 +02:00
2012-05-12 02:09:36 +02:00
batadv_bonding_save_primary ( orig_node , orig_neigh_node ,
batman_ogm_packet ) ;
2011-07-30 12:04:12 +02:00
/* update ranking if it is not a duplicate or has the same
2012-05-12 02:09:43 +02:00
* seqno and similar ttl as the non - duplicate
*/
2012-05-12 18:33:51 +02:00
sameseq = orig_node - > last_real_seqno = = ntohl ( batman_ogm_packet - > seqno ) ;
simlar_ttl = orig_node - > last_ttl - 3 < = batman_ogm_packet - > header . ttl ;
if ( is_bidirect & & ( ! is_duplicate | | ( sameseq & & simlar_ttl ) ) )
batadv_iv_ogm_orig_update ( bat_priv , orig_node , ethhdr ,
batman_ogm_packet , if_incoming ,
tt_buff , is_duplicate ) ;
2011-07-30 12:04:12 +02:00
/* is single hop (direct) neighbor */
if ( is_single_hop_neigh ) {
/* mark direct link on incoming interface */
2012-05-12 18:33:51 +02:00
batadv_iv_ogm_forward ( orig_node , ethhdr , batman_ogm_packet ,
is_single_hop_neigh ,
is_from_best_next_hop , if_incoming ) ;
2011-07-30 12:04:12 +02:00
2012-05-12 13:48:58 +02:00
batadv_dbg ( DBG_BATMAN , bat_priv ,
" Forwarding packet: rebroadcast neighbor packet with direct link flag \n " ) ;
2011-07-30 12:04:12 +02:00
goto out_neigh ;
}
/* multihop originator */
2012-05-12 18:33:51 +02:00
if ( ! is_bidirect ) {
2012-05-12 13:48:58 +02:00
batadv_dbg ( DBG_BATMAN , bat_priv ,
" Drop packet: not received via bidirectional link \n " ) ;
2011-07-30 12:04:12 +02:00
goto out_neigh ;
}
if ( is_duplicate ) {
2012-05-12 13:48:58 +02:00
batadv_dbg ( DBG_BATMAN , bat_priv ,
" Drop packet: duplicate packet received \n " ) ;
2011-07-30 12:04:12 +02:00
goto out_neigh ;
}
2012-05-12 13:48:58 +02:00
batadv_dbg ( DBG_BATMAN , bat_priv ,
" Forwarding packet: rebroadcast originator packet \n " ) ;
2012-05-12 18:33:51 +02:00
batadv_iv_ogm_forward ( orig_node , ethhdr , batman_ogm_packet ,
is_single_hop_neigh , is_from_best_next_hop ,
if_incoming ) ;
2011-07-30 12:04:12 +02:00
out_neigh :
if ( ( orig_neigh_node ) & & ( ! is_single_hop_neigh ) )
2012-05-12 02:09:34 +02:00
batadv_orig_node_free_ref ( orig_neigh_node ) ;
2011-07-30 12:04:12 +02:00
out :
if ( router )
2012-05-12 02:09:34 +02:00
batadv_neigh_node_free_ref ( router ) ;
2011-07-30 12:04:12 +02:00
if ( router_router )
2012-05-12 02:09:34 +02:00
batadv_neigh_node_free_ref ( router_router ) ;
2011-07-30 12:04:12 +02:00
if ( orig_neigh_router )
2012-05-12 02:09:34 +02:00
batadv_neigh_node_free_ref ( orig_neigh_router ) ;
2011-07-30 12:04:12 +02:00
2012-05-12 02:09:34 +02:00
batadv_orig_node_free_ref ( orig_node ) ;
2011-07-30 12:04:12 +02:00
}
2012-05-12 18:33:51 +02:00
static int batadv_iv_ogm_receive ( struct sk_buff * skb ,
struct hard_iface * if_incoming )
2011-07-30 12:04:12 +02:00
{
2012-03-11 06:17:49 +08:00
struct bat_priv * bat_priv = netdev_priv ( if_incoming - > soft_iface ) ;
2011-07-30 12:04:12 +02:00
struct batman_ogm_packet * batman_ogm_packet ;
2011-12-05 04:01:51 +08:00
struct ethhdr * ethhdr ;
int buff_pos = 0 , packet_len ;
unsigned char * tt_buff , * packet_buff ;
2012-03-04 16:56:25 +08:00
bool ret ;
2012-06-03 22:19:13 +02:00
ret = batadv_check_management_packet ( skb , if_incoming , BATADV_OGM_HLEN ) ;
2012-03-04 16:56:25 +08:00
if ( ! ret )
return NET_RX_DROP ;
2011-07-30 12:04:12 +02:00
2012-03-11 06:17:49 +08:00
/* did we receive a B.A.T.M.A.N. IV OGM packet on an interface
* that does not have B . A . T . M . A . N . IV enabled ?
*/
2012-05-12 18:33:51 +02:00
if ( bat_priv - > bat_algo_ops - > bat_ogm_emit ! = batadv_iv_ogm_emit )
2012-03-11 06:17:49 +08:00
return NET_RX_DROP ;
2012-04-20 17:02:45 +02:00
batadv_inc_counter ( bat_priv , BAT_CNT_MGMT_RX ) ;
batadv_add_counter ( bat_priv , BAT_CNT_MGMT_RX_BYTES ,
skb - > len + ETH_HLEN ) ;
2011-12-05 04:01:51 +08:00
packet_len = skb_headlen ( skb ) ;
ethhdr = ( struct ethhdr * ) skb_mac_header ( skb ) ;
packet_buff = skb - > data ;
2011-07-30 12:04:12 +02:00
batman_ogm_packet = ( struct batman_ogm_packet * ) packet_buff ;
/* unpack the aggregated packets and process them one by one */
do {
2012-06-03 22:19:13 +02:00
tt_buff = packet_buff + buff_pos + BATADV_OGM_HLEN ;
2011-07-30 12:04:12 +02:00
2012-05-12 18:33:51 +02:00
batadv_iv_ogm_process ( ethhdr , batman_ogm_packet , tt_buff ,
if_incoming ) ;
2011-07-30 12:04:12 +02:00
2012-06-03 22:19:13 +02:00
buff_pos + = BATADV_OGM_HLEN ;
2012-05-12 02:09:39 +02:00
buff_pos + = batadv_tt_len ( batman_ogm_packet - > tt_num_changes ) ;
2011-07-30 12:04:12 +02:00
batman_ogm_packet = ( struct batman_ogm_packet * )
( packet_buff + buff_pos ) ;
2012-05-12 18:33:51 +02:00
} while ( batadv_iv_ogm_aggr_packet ( buff_pos , packet_len ,
batman_ogm_packet - > tt_num_changes ) ) ;
2012-03-04 16:56:25 +08:00
kfree_skb ( skb ) ;
return NET_RX_SUCCESS ;
2011-07-30 12:04:12 +02:00
}
2011-11-28 17:40:17 +08:00
2012-05-12 18:33:51 +02:00
static struct bat_algo_ops batadv_batman_iv __read_mostly = {
2012-04-18 17:15:57 +08:00
. name = " BATMAN_IV " ,
2012-05-12 18:33:51 +02:00
. bat_iface_enable = batadv_iv_ogm_iface_enable ,
. bat_iface_disable = batadv_iv_ogm_iface_disable ,
. bat_iface_update_mac = batadv_iv_ogm_iface_update_mac ,
. bat_primary_iface_set = batadv_iv_ogm_primary_iface_set ,
. bat_ogm_schedule = batadv_iv_ogm_schedule ,
. bat_ogm_emit = batadv_iv_ogm_emit ,
2011-11-28 17:40:17 +08:00
} ;
2012-05-12 02:09:22 +02:00
int __init batadv_iv_init ( void )
2011-11-28 17:40:17 +08:00
{
2012-03-04 16:56:25 +08:00
int ret ;
/* batman originator packet */
2012-05-12 18:33:51 +02:00
ret = batadv_recv_handler_register ( BAT_IV_OGM , batadv_iv_ogm_receive ) ;
2012-03-04 16:56:25 +08:00
if ( ret < 0 )
goto out ;
2012-05-12 18:33:51 +02:00
ret = batadv_algo_register ( & batadv_batman_iv ) ;
2012-03-04 16:56:25 +08:00
if ( ret < 0 )
goto handler_unregister ;
goto out ;
handler_unregister :
2012-05-12 02:09:42 +02:00
batadv_recv_handler_unregister ( BAT_IV_OGM ) ;
2012-03-04 16:56:25 +08:00
out :
return ret ;
2011-11-28 17:40:17 +08:00
}