2012-05-12 02:09:43 +02:00
/* Copyright (C) 2011-2012 B.A.T.M.A.N. contributors:
2012-01-22 20:00:19 +01:00
*
* 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 "hash.h"
# include "hard-interface.h"
# include "originator.h"
# include "bridge_loop_avoidance.h"
2012-01-22 20:00:23 +01:00
# include "translation-table.h"
2012-01-22 20:00:19 +01:00
# include "send.h"
# include <linux/etherdevice.h>
# include <linux/crc16.h>
# include <linux/if_arp.h>
# include <net/arp.h>
# include <linux/if_vlan.h>
2012-05-12 18:33:53 +02:00
static const uint8_t batadv_announce_mac [ 4 ] = { 0x43 , 0x05 , 0x43 , 0x05 } ;
2012-01-22 20:00:19 +01:00
2012-05-12 18:33:53 +02:00
static void batadv_bla_periodic_work ( struct work_struct * work ) ;
2012-12-25 17:03:24 +08:00
static void
batadv_bla_send_announce ( struct batadv_priv * bat_priv ,
struct batadv_bla_backbone_gw * backbone_gw ) ;
2012-01-22 20:00:19 +01:00
/* return the index of the claim */
2012-05-12 18:33:53 +02:00
static inline uint32_t batadv_choose_claim ( const void * data , uint32_t size )
2012-01-22 20:00:19 +01:00
{
2012-12-25 17:03:25 +08:00
struct batadv_bla_claim * claim = ( struct batadv_bla_claim * ) data ;
2012-01-22 20:00:19 +01:00
uint32_t hash = 0 ;
2012-08-30 18:22:27 +02:00
hash = batadv_hash_bytes ( hash , & claim - > addr , sizeof ( claim - > addr ) ) ;
hash = batadv_hash_bytes ( hash , & claim - > vid , sizeof ( claim - > vid ) ) ;
2012-01-22 20:00:19 +01:00
hash + = ( hash < < 3 ) ;
hash ^ = ( hash > > 11 ) ;
hash + = ( hash < < 15 ) ;
return hash % size ;
}
/* return the index of the backbone gateway */
2012-05-12 18:33:53 +02:00
static inline uint32_t batadv_choose_backbone_gw ( const void * data ,
uint32_t size )
2012-01-22 20:00:19 +01:00
{
2012-12-25 17:03:25 +08:00
const struct batadv_bla_claim * claim = ( struct batadv_bla_claim * ) data ;
2012-01-22 20:00:19 +01:00
uint32_t hash = 0 ;
2012-08-30 18:22:27 +02:00
hash = batadv_hash_bytes ( hash , & claim - > addr , sizeof ( claim - > addr ) ) ;
hash = batadv_hash_bytes ( hash , & claim - > vid , sizeof ( claim - > vid ) ) ;
2012-01-22 20:00:19 +01:00
hash + = ( hash < < 3 ) ;
hash ^ = ( hash > > 11 ) ;
hash + = ( hash < < 15 ) ;
return hash % size ;
}
/* compares address and vid of two backbone gws */
2012-05-12 18:33:53 +02:00
static int batadv_compare_backbone_gw ( const struct hlist_node * node ,
const void * data2 )
2012-01-22 20:00:19 +01:00
{
2012-12-25 17:03:24 +08:00
const void * data1 = container_of ( node , struct batadv_bla_backbone_gw ,
2012-01-22 20:00:19 +01:00
hash_entry ) ;
2012-12-25 17:03:24 +08:00
const struct batadv_bla_backbone_gw * gw1 = data1 , * gw2 = data2 ;
2012-01-22 20:00:19 +01:00
2012-10-15 22:38:04 +02:00
if ( ! batadv_compare_eth ( gw1 - > orig , gw2 - > orig ) )
return 0 ;
if ( gw1 - > vid ! = gw2 - > vid )
return 0 ;
return 1 ;
2012-01-22 20:00:19 +01:00
}
/* compares address and vid of two claims */
2012-05-12 18:33:53 +02:00
static int batadv_compare_claim ( const struct hlist_node * node ,
const void * data2 )
2012-01-22 20:00:19 +01:00
{
2012-12-25 17:03:25 +08:00
const void * data1 = container_of ( node , struct batadv_bla_claim ,
2012-01-22 20:00:19 +01:00
hash_entry ) ;
2012-12-25 17:03:25 +08:00
const struct batadv_bla_claim * cl1 = data1 , * cl2 = data2 ;
2012-10-15 22:38:04 +02:00
if ( ! batadv_compare_eth ( cl1 - > addr , cl2 - > addr ) )
return 0 ;
if ( cl1 - > vid ! = cl2 - > vid )
return 0 ;
2012-01-22 20:00:19 +01:00
2012-10-15 22:38:04 +02:00
return 1 ;
2012-01-22 20:00:19 +01:00
}
/* free a backbone gw */
2012-12-25 17:03:24 +08:00
static void
batadv_backbone_gw_free_ref ( struct batadv_bla_backbone_gw * backbone_gw )
2012-01-22 20:00:19 +01:00
{
if ( atomic_dec_and_test ( & backbone_gw - > refcount ) )
kfree_rcu ( backbone_gw , rcu ) ;
}
/* finally deinitialize the claim */
2012-05-12 18:33:53 +02:00
static void batadv_claim_free_rcu ( struct rcu_head * rcu )
2012-01-22 20:00:19 +01:00
{
2012-12-25 17:03:25 +08:00
struct batadv_bla_claim * claim ;
2012-01-22 20:00:19 +01:00
2012-12-25 17:03:25 +08:00
claim = container_of ( rcu , struct batadv_bla_claim , rcu ) ;
2012-01-22 20:00:19 +01:00
2012-05-12 18:33:53 +02:00
batadv_backbone_gw_free_ref ( claim - > backbone_gw ) ;
2012-01-22 20:00:19 +01:00
kfree ( claim ) ;
}
/* free a claim, call claim_free_rcu if its the last reference */
2012-12-25 17:03:25 +08:00
static void batadv_claim_free_ref ( struct batadv_bla_claim * claim )
2012-01-22 20:00:19 +01:00
{
if ( atomic_dec_and_test ( & claim - > refcount ) )
2012-05-12 18:33:53 +02:00
call_rcu ( & claim - > rcu , batadv_claim_free_rcu ) ;
2012-01-22 20:00:19 +01:00
}
2012-05-12 02:09:43 +02:00
/* @bat_priv: the bat priv with all the soft interface information
2012-01-22 20:00:19 +01:00
* @ data : search data ( may be local / static data )
*
* looks for a claim in the hash , and returns it if found
* or NULL otherwise .
*/
2012-12-25 17:03:25 +08:00
static struct batadv_bla_claim
* batadv_claim_hash_find ( struct batadv_priv * bat_priv ,
struct batadv_bla_claim * data )
2012-01-22 20:00:19 +01:00
{
2012-07-15 22:26:51 +02:00
struct batadv_hashtable * hash = bat_priv - > bla . claim_hash ;
2012-01-22 20:00:19 +01:00
struct hlist_head * head ;
struct hlist_node * node ;
2012-12-25 17:03:25 +08:00
struct batadv_bla_claim * claim ;
struct batadv_bla_claim * claim_tmp = NULL ;
2012-01-22 20:00:19 +01:00
int index ;
if ( ! hash )
return NULL ;
2012-05-12 18:33:53 +02:00
index = batadv_choose_claim ( data , hash - > size ) ;
2012-01-22 20:00:19 +01:00
head = & hash - > table [ index ] ;
rcu_read_lock ( ) ;
hlist_for_each_entry_rcu ( claim , node , head , hash_entry ) {
2012-05-12 18:33:53 +02:00
if ( ! batadv_compare_claim ( & claim - > hash_entry , data ) )
2012-01-22 20:00:19 +01:00
continue ;
if ( ! atomic_inc_not_zero ( & claim - > refcount ) )
continue ;
claim_tmp = claim ;
break ;
}
rcu_read_unlock ( ) ;
return claim_tmp ;
}
2012-07-10 10:55:09 +00:00
/**
* batadv_backbone_hash_find - looks for a claim in the hash
* @ bat_priv : the bat priv with all the soft interface information
2012-01-22 20:00:19 +01:00
* @ addr : the address of the originator
* @ vid : the VLAN ID
*
2012-07-10 10:55:09 +00:00
* Returns claim if found or NULL otherwise .
2012-01-22 20:00:19 +01:00
*/
2012-12-25 17:03:24 +08:00
static struct batadv_bla_backbone_gw *
2012-06-05 22:31:31 +02:00
batadv_backbone_hash_find ( struct batadv_priv * bat_priv ,
uint8_t * addr , short vid )
2012-01-22 20:00:19 +01:00
{
2012-07-15 22:26:51 +02:00
struct batadv_hashtable * hash = bat_priv - > bla . backbone_hash ;
2012-01-22 20:00:19 +01:00
struct hlist_head * head ;
struct hlist_node * node ;
2012-12-25 17:03:24 +08:00
struct batadv_bla_backbone_gw search_entry , * backbone_gw ;
struct batadv_bla_backbone_gw * backbone_gw_tmp = NULL ;
2012-01-22 20:00:19 +01:00
int index ;
if ( ! hash )
return NULL ;
memcpy ( search_entry . orig , addr , ETH_ALEN ) ;
search_entry . vid = vid ;
2012-05-12 18:33:53 +02:00
index = batadv_choose_backbone_gw ( & search_entry , hash - > size ) ;
2012-01-22 20:00:19 +01:00
head = & hash - > table [ index ] ;
rcu_read_lock ( ) ;
hlist_for_each_entry_rcu ( backbone_gw , node , head , hash_entry ) {
2012-05-12 18:33:53 +02:00
if ( ! batadv_compare_backbone_gw ( & backbone_gw - > hash_entry ,
& search_entry ) )
2012-01-22 20:00:19 +01:00
continue ;
if ( ! atomic_inc_not_zero ( & backbone_gw - > refcount ) )
continue ;
backbone_gw_tmp = backbone_gw ;
break ;
}
rcu_read_unlock ( ) ;
return backbone_gw_tmp ;
}
/* delete all claims for a backbone */
2012-06-05 22:31:31 +02:00
static void
2012-12-25 17:03:24 +08:00
batadv_bla_del_backbone_claims ( struct batadv_bla_backbone_gw * backbone_gw )
2012-01-22 20:00:19 +01:00
{
2012-06-05 22:31:28 +02:00
struct batadv_hashtable * hash ;
2012-01-22 20:00:19 +01:00
struct hlist_node * node , * node_tmp ;
struct hlist_head * head ;
2012-12-25 17:03:25 +08:00
struct batadv_bla_claim * claim ;
2012-01-22 20:00:19 +01:00
int i ;
spinlock_t * list_lock ; /* protects write access to the hash lists */
2012-07-15 22:26:51 +02:00
hash = backbone_gw - > bat_priv - > bla . claim_hash ;
2012-01-22 20:00:19 +01:00
if ( ! hash )
return ;
for ( i = 0 ; i < hash - > size ; i + + ) {
head = & hash - > table [ i ] ;
list_lock = & hash - > list_locks [ i ] ;
spin_lock_bh ( list_lock ) ;
hlist_for_each_entry_safe ( claim , node , node_tmp ,
head , hash_entry ) {
if ( claim - > backbone_gw ! = backbone_gw )
continue ;
2012-05-12 18:33:53 +02:00
batadv_claim_free_ref ( claim ) ;
2012-01-22 20:00:19 +01:00
hlist_del_rcu ( node ) ;
}
spin_unlock_bh ( list_lock ) ;
}
/* all claims gone, intialize CRC */
2012-06-03 22:19:10 +02:00
backbone_gw - > crc = BATADV_BLA_CRC_INIT ;
2012-01-22 20:00:19 +01:00
}
2012-07-10 10:55:09 +00:00
/**
* batadv_bla_send_claim - sends a claim frame according to the provided info
* @ bat_priv : the bat priv with all the soft interface information
2012-01-22 20:00:19 +01:00
* @ orig : the mac address to be announced within the claim
* @ vid : the VLAN ID
* @ claimtype : the type of the claim ( CLAIM , UNCLAIM , ANNOUNCE , . . . )
*/
2012-06-05 22:31:31 +02:00
static void batadv_bla_send_claim ( struct batadv_priv * bat_priv , uint8_t * mac ,
2012-05-12 18:33:53 +02:00
short vid , int claimtype )
2012-01-22 20:00:19 +01:00
{
struct sk_buff * skb ;
struct ethhdr * ethhdr ;
2012-06-05 22:31:31 +02:00
struct batadv_hard_iface * primary_if ;
2012-01-22 20:00:19 +01:00
struct net_device * soft_iface ;
uint8_t * hw_src ;
2012-06-05 22:31:30 +02:00
struct batadv_bla_claim_dst local_claim_dest ;
2012-04-22 07:47:50 +01:00
__be32 zeroip = 0 ;
2012-01-22 20:00:19 +01:00
2012-05-12 13:48:54 +02:00
primary_if = batadv_primary_if_get_selected ( bat_priv ) ;
2012-01-22 20:00:19 +01:00
if ( ! primary_if )
return ;
2012-07-15 22:26:51 +02:00
memcpy ( & local_claim_dest , & bat_priv - > bla . claim_dest ,
2012-01-22 20:00:26 +01:00
sizeof ( local_claim_dest ) ) ;
2012-01-22 20:00:19 +01:00
local_claim_dest . type = claimtype ;
soft_iface = primary_if - > soft_iface ;
skb = arp_create ( ARPOP_REPLY , ETH_P_ARP ,
/* IP DST: 0.0.0.0 */
zeroip ,
primary_if - > soft_iface ,
/* IP SRC: 0.0.0.0 */
zeroip ,
/* Ethernet DST: Broadcast */
NULL ,
/* Ethernet SRC/HW SRC: originator mac */
primary_if - > net_dev - > dev_addr ,
2012-06-23 12:34:17 +02:00
/* HW DST: FF:43:05:XX:YY:YY
2012-01-22 20:00:19 +01:00
* with XX = claim type
2012-01-22 20:00:26 +01:00
* and YY : YY = group id
2012-01-22 20:00:19 +01:00
*/
( uint8_t * ) & local_claim_dest ) ;
if ( ! skb )
goto out ;
ethhdr = ( struct ethhdr * ) skb - > data ;
2012-02-18 11:27:34 +01:00
hw_src = ( uint8_t * ) ethhdr + ETH_HLEN + sizeof ( struct arphdr ) ;
2012-01-22 20:00:19 +01:00
/* now we pretend that the client would have sent this ... */
switch ( claimtype ) {
2012-06-23 12:34:18 +02:00
case BATADV_CLAIM_TYPE_CLAIM :
2012-01-22 20:00:19 +01:00
/* normal claim frame
* set Ethernet SRC to the clients mac
*/
memcpy ( ethhdr - > h_source , mac , ETH_ALEN ) ;
2012-06-03 22:19:22 +02:00
batadv_dbg ( BATADV_DBG_BLA , bat_priv ,
2012-05-12 13:48:58 +02:00
" bla_send_claim(): CLAIM %pM on vid %d \n " , mac , vid ) ;
2012-01-22 20:00:19 +01:00
break ;
2012-06-23 12:34:18 +02:00
case BATADV_CLAIM_TYPE_UNCLAIM :
2012-01-22 20:00:19 +01:00
/* unclaim frame
* set HW SRC to the clients mac
*/
memcpy ( hw_src , mac , ETH_ALEN ) ;
2012-06-03 22:19:22 +02:00
batadv_dbg ( BATADV_DBG_BLA , bat_priv ,
2012-05-12 13:48:58 +02:00
" bla_send_claim(): UNCLAIM %pM on vid %d \n " , mac ,
vid ) ;
2012-01-22 20:00:19 +01:00
break ;
2012-06-03 22:19:21 +02:00
case BATADV_CLAIM_TYPE_ANNOUNCE :
2012-01-22 20:00:19 +01:00
/* announcement frame
* set HW SRC to the special mac containg the crc
*/
memcpy ( hw_src , mac , ETH_ALEN ) ;
2012-06-03 22:19:22 +02:00
batadv_dbg ( BATADV_DBG_BLA , bat_priv ,
2012-05-12 13:48:58 +02:00
" bla_send_claim(): ANNOUNCE of %pM on vid %d \n " ,
ethhdr - > h_source , vid ) ;
2012-01-22 20:00:19 +01:00
break ;
2012-06-03 22:19:21 +02:00
case BATADV_CLAIM_TYPE_REQUEST :
2012-01-22 20:00:19 +01:00
/* request frame
2012-06-23 12:34:17 +02:00
* set HW SRC and header destination to the receiving backbone
* gws mac
2012-01-22 20:00:19 +01:00
*/
memcpy ( hw_src , mac , ETH_ALEN ) ;
memcpy ( ethhdr - > h_dest , mac , ETH_ALEN ) ;
2012-06-03 22:19:22 +02:00
batadv_dbg ( BATADV_DBG_BLA , bat_priv ,
2012-05-12 13:48:58 +02:00
" bla_send_claim(): REQUEST of %pM to %pMon vid %d \n " ,
ethhdr - > h_source , ethhdr - > h_dest , vid ) ;
2012-01-22 20:00:19 +01:00
break ;
}
if ( vid ! = - 1 )
skb = vlan_insert_tag ( skb , vid ) ;
skb_reset_mac_header ( skb ) ;
skb - > protocol = eth_type_trans ( skb , soft_iface ) ;
2012-06-23 11:47:53 +02:00
batadv_inc_counter ( bat_priv , BATADV_CNT_RX ) ;
batadv_add_counter ( bat_priv , BATADV_CNT_RX_BYTES ,
skb - > len + ETH_HLEN ) ;
2012-01-22 20:00:19 +01:00
soft_iface - > last_rx = jiffies ;
netif_rx ( skb ) ;
out :
if ( primary_if )
2012-05-12 13:48:54 +02:00
batadv_hardif_free_ref ( primary_if ) ;
2012-01-22 20:00:19 +01:00
}
2012-07-10 10:55:09 +00:00
/**
* batadv_bla_get_backbone_gw
* @ bat_priv : the bat priv with all the soft interface information
2012-01-22 20:00:19 +01:00
* @ orig : the mac address of the originator
* @ vid : the VLAN ID
*
* searches for the backbone gw or creates a new one if it could not
* be found .
*/
2012-12-25 17:03:24 +08:00
static struct batadv_bla_backbone_gw *
2012-06-05 22:31:31 +02:00
batadv_bla_get_backbone_gw ( struct batadv_priv * bat_priv , uint8_t * orig ,
2012-09-08 18:02:53 +02:00
short vid , bool own_backbone )
2012-01-22 20:00:19 +01:00
{
2012-12-25 17:03:24 +08:00
struct batadv_bla_backbone_gw * entry ;
2012-06-05 22:31:31 +02:00
struct batadv_orig_node * orig_node ;
2012-01-22 20:00:19 +01:00
int hash_added ;
2012-05-12 18:33:53 +02:00
entry = batadv_backbone_hash_find ( bat_priv , orig , vid ) ;
2012-01-22 20:00:19 +01:00
if ( entry )
return entry ;
2012-06-03 22:19:22 +02:00
batadv_dbg ( BATADV_DBG_BLA , bat_priv ,
2012-05-12 13:48:58 +02:00
" bla_get_backbone_gw(): not found (%pM, %d), creating new entry \n " ,
orig , vid ) ;
2012-01-22 20:00:19 +01:00
entry = kzalloc ( sizeof ( * entry ) , GFP_ATOMIC ) ;
if ( ! entry )
return NULL ;
entry - > vid = vid ;
entry - > lasttime = jiffies ;
2012-06-03 22:19:10 +02:00
entry - > crc = BATADV_BLA_CRC_INIT ;
2012-01-22 20:00:19 +01:00
entry - > bat_priv = bat_priv ;
atomic_set ( & entry - > request_sent , 0 ) ;
2012-09-13 18:18:46 +02:00
atomic_set ( & entry - > wait_periods , 0 ) ;
2012-01-22 20:00:19 +01:00
memcpy ( entry - > orig , orig , ETH_ALEN ) ;
/* one for the hash, one for returning */
atomic_set ( & entry - > refcount , 2 ) ;
2012-07-15 22:26:51 +02:00
hash_added = batadv_hash_add ( bat_priv - > bla . backbone_hash ,
2012-05-12 18:33:53 +02:00
batadv_compare_backbone_gw ,
batadv_choose_backbone_gw , entry ,
& entry - > hash_entry ) ;
2012-01-22 20:00:19 +01:00
if ( unlikely ( hash_added ! = 0 ) ) {
/* hash failed, free the structure */
kfree ( entry ) ;
return NULL ;
}
2012-01-22 20:00:23 +01:00
/* this is a gateway now, remove any tt entries */
2012-05-12 13:48:56 +02:00
orig_node = batadv_orig_hash_find ( bat_priv , orig ) ;
2012-01-22 20:00:23 +01:00
if ( orig_node ) {
2012-05-12 02:09:39 +02:00
batadv_tt_global_del_orig ( bat_priv , orig_node ,
" became a backbone gateway " ) ;
2012-05-12 02:09:34 +02:00
batadv_orig_node_free_ref ( orig_node ) ;
2012-01-22 20:00:23 +01:00
}
2012-09-08 18:02:53 +02:00
2012-09-09 22:27:57 +02:00
if ( own_backbone ) {
2012-09-08 18:02:53 +02:00
batadv_bla_send_announce ( bat_priv , entry ) ;
2012-09-09 22:27:57 +02:00
/* this will be decreased in the worker thread */
atomic_inc ( & entry - > request_sent ) ;
2012-09-13 18:18:46 +02:00
atomic_set ( & entry - > wait_periods , BATADV_BLA_WAIT_PERIODS ) ;
2012-09-09 22:27:57 +02:00
atomic_inc ( & bat_priv - > bla . num_requests ) ;
}
2012-01-22 20:00:19 +01:00
return entry ;
}
/* update or add the own backbone gw to make sure we announce
* where we receive other backbone gws
*/
2012-06-05 22:31:31 +02:00
static void
batadv_bla_update_own_backbone_gw ( struct batadv_priv * bat_priv ,
struct batadv_hard_iface * primary_if ,
short vid )
2012-01-22 20:00:19 +01:00
{
2012-12-25 17:03:24 +08:00
struct batadv_bla_backbone_gw * backbone_gw ;
2012-01-22 20:00:19 +01:00
2012-05-12 18:33:53 +02:00
backbone_gw = batadv_bla_get_backbone_gw ( bat_priv ,
primary_if - > net_dev - > dev_addr ,
2012-09-08 18:02:53 +02:00
vid , true ) ;
2012-01-22 20:00:19 +01:00
if ( unlikely ( ! backbone_gw ) )
return ;
backbone_gw - > lasttime = jiffies ;
2012-05-12 18:33:53 +02:00
batadv_backbone_gw_free_ref ( backbone_gw ) ;
2012-01-22 20:00:19 +01:00
}
2012-05-12 02:09:43 +02:00
/* @bat_priv: the bat priv with all the soft interface information
2012-01-22 20:00:19 +01:00
* @ vid : the vid where the request came on
*
* Repeat all of our own claims , and finally send an ANNOUNCE frame
* to allow the requester another check if the CRC is correct now .
*/
2012-06-05 22:31:31 +02:00
static void batadv_bla_answer_request ( struct batadv_priv * bat_priv ,
struct batadv_hard_iface * primary_if ,
short vid )
2012-01-22 20:00:19 +01:00
{
struct hlist_node * node ;
struct hlist_head * head ;
2012-06-05 22:31:28 +02:00
struct batadv_hashtable * hash ;
2012-12-25 17:03:25 +08:00
struct batadv_bla_claim * claim ;
2012-12-25 17:03:24 +08:00
struct batadv_bla_backbone_gw * backbone_gw ;
2012-01-22 20:00:19 +01:00
int i ;
2012-06-03 22:19:22 +02:00
batadv_dbg ( BATADV_DBG_BLA , bat_priv ,
2012-05-12 13:48:58 +02:00
" bla_answer_request(): received a claim request, send all of our own claims again \n " ) ;
2012-01-22 20:00:19 +01:00
2012-05-12 18:33:53 +02:00
backbone_gw = batadv_backbone_hash_find ( bat_priv ,
primary_if - > net_dev - > dev_addr ,
vid ) ;
2012-01-22 20:00:19 +01:00
if ( ! backbone_gw )
return ;
2012-07-15 22:26:51 +02:00
hash = bat_priv - > bla . claim_hash ;
2012-01-22 20:00:19 +01:00
for ( i = 0 ; i < hash - > size ; i + + ) {
head = & hash - > table [ i ] ;
rcu_read_lock ( ) ;
hlist_for_each_entry_rcu ( claim , node , head , hash_entry ) {
/* only own claims are interesting */
if ( claim - > backbone_gw ! = backbone_gw )
continue ;
2012-05-12 18:33:53 +02:00
batadv_bla_send_claim ( bat_priv , claim - > addr , claim - > vid ,
2012-06-23 12:34:18 +02:00
BATADV_CLAIM_TYPE_CLAIM ) ;
2012-01-22 20:00:19 +01:00
}
rcu_read_unlock ( ) ;
}
/* finally, send an announcement frame */
2012-05-12 18:33:53 +02:00
batadv_bla_send_announce ( bat_priv , backbone_gw ) ;
batadv_backbone_gw_free_ref ( backbone_gw ) ;
2012-01-22 20:00:19 +01:00
}
2012-05-12 02:09:43 +02:00
/* @backbone_gw: the backbone gateway from whom we are out of sync
2012-01-22 20:00:19 +01:00
*
* When the crc is wrong , ask the backbone gateway for a full table update .
* After the request , it will repeat all of his own claims and finally
* send an announcement claim with which we can check again .
*/
2012-12-25 17:03:24 +08:00
static void batadv_bla_send_request ( struct batadv_bla_backbone_gw * backbone_gw )
2012-01-22 20:00:19 +01:00
{
/* first, remove all old entries */
2012-05-12 18:33:53 +02:00
batadv_bla_del_backbone_claims ( backbone_gw ) ;
2012-01-22 20:00:19 +01:00
2012-06-03 22:19:22 +02:00
batadv_dbg ( BATADV_DBG_BLA , backbone_gw - > bat_priv ,
" Sending REQUEST to %pM \n " , backbone_gw - > orig ) ;
2012-01-22 20:00:19 +01:00
/* send request */
2012-05-12 18:33:53 +02:00
batadv_bla_send_claim ( backbone_gw - > bat_priv , backbone_gw - > orig ,
2012-06-03 22:19:21 +02:00
backbone_gw - > vid , BATADV_CLAIM_TYPE_REQUEST ) ;
2012-01-22 20:00:19 +01:00
/* no local broadcasts should be sent or received, for now. */
if ( ! atomic_read ( & backbone_gw - > request_sent ) ) {
2012-07-15 22:26:51 +02:00
atomic_inc ( & backbone_gw - > bat_priv - > bla . num_requests ) ;
2012-01-22 20:00:19 +01:00
atomic_set ( & backbone_gw - > request_sent , 1 ) ;
}
}
2012-05-12 02:09:43 +02:00
/* @bat_priv: the bat priv with all the soft interface information
2012-01-22 20:00:19 +01:00
* @ backbone_gw : our backbone gateway which should be announced
*
* This function sends an announcement . It is called from multiple
* places .
*/
2012-06-05 22:31:31 +02:00
static void batadv_bla_send_announce ( struct batadv_priv * bat_priv ,
2012-12-25 17:03:24 +08:00
struct batadv_bla_backbone_gw * backbone_gw )
2012-01-22 20:00:19 +01:00
{
uint8_t mac [ ETH_ALEN ] ;
2012-04-22 07:47:50 +01:00
__be16 crc ;
2012-01-22 20:00:19 +01:00
2012-05-12 18:33:53 +02:00
memcpy ( mac , batadv_announce_mac , 4 ) ;
2012-01-22 20:00:19 +01:00
crc = htons ( backbone_gw - > crc ) ;
2012-04-22 07:50:29 +01:00
memcpy ( & mac [ 4 ] , & crc , 2 ) ;
2012-01-22 20:00:19 +01:00
2012-05-12 18:33:53 +02:00
batadv_bla_send_claim ( bat_priv , mac , backbone_gw - > vid ,
2012-06-03 22:19:21 +02:00
BATADV_CLAIM_TYPE_ANNOUNCE ) ;
2012-01-22 20:00:19 +01:00
}
2012-07-10 10:55:09 +00:00
/**
* batadv_bla_add_claim - Adds a claim in the claim hash
* @ bat_priv : the bat priv with all the soft interface information
2012-01-22 20:00:19 +01:00
* @ mac : the mac address of the claim
* @ vid : the VLAN ID of the frame
* @ backbone_gw : the backbone gateway which claims it
*/
2012-06-05 22:31:31 +02:00
static void batadv_bla_add_claim ( struct batadv_priv * bat_priv ,
const uint8_t * mac , const short vid ,
2012-12-25 17:03:24 +08:00
struct batadv_bla_backbone_gw * backbone_gw )
2012-01-22 20:00:19 +01:00
{
2012-12-25 17:03:25 +08:00
struct batadv_bla_claim * claim ;
struct batadv_bla_claim search_claim ;
2012-01-22 20:00:19 +01:00
int hash_added ;
memcpy ( search_claim . addr , mac , ETH_ALEN ) ;
search_claim . vid = vid ;
2012-05-12 18:33:53 +02:00
claim = batadv_claim_hash_find ( bat_priv , & search_claim ) ;
2012-01-22 20:00:19 +01:00
/* create a new claim entry if it does not exist yet. */
if ( ! claim ) {
claim = kzalloc ( sizeof ( * claim ) , GFP_ATOMIC ) ;
if ( ! claim )
return ;
memcpy ( claim - > addr , mac , ETH_ALEN ) ;
claim - > vid = vid ;
claim - > lasttime = jiffies ;
claim - > backbone_gw = backbone_gw ;
atomic_set ( & claim - > refcount , 2 ) ;
2012-06-03 22:19:22 +02:00
batadv_dbg ( BATADV_DBG_BLA , bat_priv ,
2012-05-12 13:48:58 +02:00
" bla_add_claim(): adding new entry %pM, vid %d to hash ... \n " ,
mac , vid ) ;
2012-07-15 22:26:51 +02:00
hash_added = batadv_hash_add ( bat_priv - > bla . claim_hash ,
2012-05-12 18:33:53 +02:00
batadv_compare_claim ,
batadv_choose_claim , claim ,
& claim - > hash_entry ) ;
2012-01-22 20:00:19 +01:00
if ( unlikely ( hash_added ! = 0 ) ) {
/* only local changes happened. */
kfree ( claim ) ;
return ;
}
} else {
claim - > lasttime = jiffies ;
if ( claim - > backbone_gw = = backbone_gw )
/* no need to register a new backbone */
goto claim_free_ref ;
2012-06-03 22:19:22 +02:00
batadv_dbg ( BATADV_DBG_BLA , bat_priv ,
2012-05-12 13:48:58 +02:00
" bla_add_claim(): changing ownership for %pM, vid %d \n " ,
mac , vid ) ;
2012-01-22 20:00:19 +01:00
2012-07-08 17:13:15 +02:00
claim - > backbone_gw - > crc ^ = crc16 ( 0 , claim - > addr , ETH_ALEN ) ;
2012-05-12 18:33:53 +02:00
batadv_backbone_gw_free_ref ( claim - > backbone_gw ) ;
2012-01-22 20:00:19 +01:00
}
/* set (new) backbone gw */
atomic_inc ( & backbone_gw - > refcount ) ;
claim - > backbone_gw = backbone_gw ;
backbone_gw - > crc ^ = crc16 ( 0 , claim - > addr , ETH_ALEN ) ;
backbone_gw - > lasttime = jiffies ;
claim_free_ref :
2012-05-12 18:33:53 +02:00
batadv_claim_free_ref ( claim ) ;
2012-01-22 20:00:19 +01:00
}
/* Delete a claim from the claim hash which has the
* given mac address and vid .
*/
2012-06-05 22:31:31 +02:00
static void batadv_bla_del_claim ( struct batadv_priv * bat_priv ,
const uint8_t * mac , const short vid )
2012-01-22 20:00:19 +01:00
{
2012-12-25 17:03:25 +08:00
struct batadv_bla_claim search_claim , * claim ;
2012-01-22 20:00:19 +01:00
memcpy ( search_claim . addr , mac , ETH_ALEN ) ;
search_claim . vid = vid ;
2012-05-12 18:33:53 +02:00
claim = batadv_claim_hash_find ( bat_priv , & search_claim ) ;
2012-01-22 20:00:19 +01:00
if ( ! claim )
return ;
2012-06-03 22:19:22 +02:00
batadv_dbg ( BATADV_DBG_BLA , bat_priv , " bla_del_claim(): %pM, vid %d \n " ,
mac , vid ) ;
2012-01-22 20:00:19 +01:00
2012-07-15 22:26:51 +02:00
batadv_hash_remove ( bat_priv - > bla . claim_hash , batadv_compare_claim ,
2012-05-12 18:33:53 +02:00
batadv_choose_claim , claim ) ;
batadv_claim_free_ref ( claim ) ; /* reference from the hash is gone */
2012-01-22 20:00:19 +01:00
claim - > backbone_gw - > crc ^ = crc16 ( 0 , claim - > addr , ETH_ALEN ) ;
/* don't need the reference from hash_find() anymore */
2012-05-12 18:33:53 +02:00
batadv_claim_free_ref ( claim ) ;
2012-01-22 20:00:19 +01:00
}
/* check for ANNOUNCE frame, return 1 if handled */
2012-06-05 22:31:31 +02:00
static int batadv_handle_announce ( struct batadv_priv * bat_priv ,
2012-05-12 18:33:53 +02:00
uint8_t * an_addr , uint8_t * backbone_addr ,
short vid )
2012-01-22 20:00:19 +01:00
{
2012-12-25 17:03:24 +08:00
struct batadv_bla_backbone_gw * backbone_gw ;
2012-01-22 20:00:19 +01:00
uint16_t crc ;
2012-05-12 18:33:53 +02:00
if ( memcmp ( an_addr , batadv_announce_mac , 4 ) ! = 0 )
2012-01-22 20:00:19 +01:00
return 0 ;
2012-09-08 18:02:53 +02:00
backbone_gw = batadv_bla_get_backbone_gw ( bat_priv , backbone_addr , vid ,
false ) ;
2012-01-22 20:00:19 +01:00
if ( unlikely ( ! backbone_gw ) )
return 1 ;
/* handle as ANNOUNCE frame */
backbone_gw - > lasttime = jiffies ;
2012-04-22 07:47:50 +01:00
crc = ntohs ( * ( ( __be16 * ) ( & an_addr [ 4 ] ) ) ) ;
2012-01-22 20:00:19 +01:00
2012-06-03 22:19:22 +02:00
batadv_dbg ( BATADV_DBG_BLA , bat_priv ,
2012-11-19 09:01:43 +01:00
" handle_announce(): ANNOUNCE vid %d (sent by %pM)... CRC = %#.4x \n " ,
2012-05-12 13:48:58 +02:00
vid , backbone_gw - > orig , crc ) ;
2012-01-22 20:00:19 +01:00
if ( backbone_gw - > crc ! = crc ) {
2012-06-03 22:19:22 +02:00
batadv_dbg ( BATADV_DBG_BLA , backbone_gw - > bat_priv ,
2012-11-19 09:01:43 +01:00
" handle_announce(): CRC FAILED for %pM/%d (my = %#.4x, sent = %#.4x) \n " ,
2012-05-12 13:48:58 +02:00
backbone_gw - > orig , backbone_gw - > vid ,
backbone_gw - > crc , crc ) ;
2012-01-22 20:00:19 +01:00
2012-05-12 18:33:53 +02:00
batadv_bla_send_request ( backbone_gw ) ;
2012-01-22 20:00:19 +01:00
} else {
/* if we have sent a request and the crc was OK,
* we can allow traffic again .
*/
if ( atomic_read ( & backbone_gw - > request_sent ) ) {
2012-07-15 22:26:51 +02:00
atomic_dec ( & backbone_gw - > bat_priv - > bla . num_requests ) ;
2012-01-22 20:00:19 +01:00
atomic_set ( & backbone_gw - > request_sent , 0 ) ;
}
}
2012-05-12 18:33:53 +02:00
batadv_backbone_gw_free_ref ( backbone_gw ) ;
2012-01-22 20:00:19 +01:00
return 1 ;
}
/* check for REQUEST frame, return 1 if handled */
2012-06-05 22:31:31 +02:00
static int batadv_handle_request ( struct batadv_priv * bat_priv ,
struct batadv_hard_iface * primary_if ,
2012-05-12 18:33:53 +02:00
uint8_t * backbone_addr ,
struct ethhdr * ethhdr , short vid )
2012-01-22 20:00:19 +01:00
{
/* check for REQUEST frame */
2012-05-12 13:48:58 +02:00
if ( ! batadv_compare_eth ( backbone_addr , ethhdr - > h_dest ) )
2012-01-22 20:00:19 +01:00
return 0 ;
/* sanity check, this should not happen on a normal switch,
* we ignore it in this case .
*/
2012-05-12 13:48:58 +02:00
if ( ! batadv_compare_eth ( ethhdr - > h_dest , primary_if - > net_dev - > dev_addr ) )
2012-01-22 20:00:19 +01:00
return 1 ;
2012-06-03 22:19:22 +02:00
batadv_dbg ( BATADV_DBG_BLA , bat_priv ,
2012-05-12 13:48:58 +02:00
" handle_request(): REQUEST vid %d (sent by %pM)... \n " ,
vid , ethhdr - > h_source ) ;
2012-01-22 20:00:19 +01:00
2012-05-12 18:33:53 +02:00
batadv_bla_answer_request ( bat_priv , primary_if , vid ) ;
2012-01-22 20:00:19 +01:00
return 1 ;
}
/* check for UNCLAIM frame, return 1 if handled */
2012-06-05 22:31:31 +02:00
static int batadv_handle_unclaim ( struct batadv_priv * bat_priv ,
struct batadv_hard_iface * primary_if ,
2012-05-12 18:33:53 +02:00
uint8_t * backbone_addr ,
uint8_t * claim_addr , short vid )
2012-01-22 20:00:19 +01:00
{
2012-12-25 17:03:24 +08:00
struct batadv_bla_backbone_gw * backbone_gw ;
2012-01-22 20:00:19 +01:00
/* unclaim in any case if it is our own */
2012-05-12 13:48:58 +02:00
if ( primary_if & & batadv_compare_eth ( backbone_addr ,
primary_if - > net_dev - > dev_addr ) )
2012-05-12 18:33:53 +02:00
batadv_bla_send_claim ( bat_priv , claim_addr , vid ,
2012-06-23 12:34:18 +02:00
BATADV_CLAIM_TYPE_UNCLAIM ) ;
2012-01-22 20:00:19 +01:00
2012-05-12 18:33:53 +02:00
backbone_gw = batadv_backbone_hash_find ( bat_priv , backbone_addr , vid ) ;
2012-01-22 20:00:19 +01:00
if ( ! backbone_gw )
return 1 ;
/* this must be an UNCLAIM frame */
2012-06-03 22:19:22 +02:00
batadv_dbg ( BATADV_DBG_BLA , bat_priv ,
2012-05-12 13:48:58 +02:00
" handle_unclaim(): UNCLAIM %pM on vid %d (sent by %pM)... \n " ,
claim_addr , vid , backbone_gw - > orig ) ;
2012-01-22 20:00:19 +01:00
2012-05-12 18:33:53 +02:00
batadv_bla_del_claim ( bat_priv , claim_addr , vid ) ;
batadv_backbone_gw_free_ref ( backbone_gw ) ;
2012-01-22 20:00:19 +01:00
return 1 ;
}
/* check for CLAIM frame, return 1 if handled */
2012-06-05 22:31:31 +02:00
static int batadv_handle_claim ( struct batadv_priv * bat_priv ,
struct batadv_hard_iface * primary_if ,
2012-05-12 18:33:53 +02:00
uint8_t * backbone_addr , uint8_t * claim_addr ,
short vid )
2012-01-22 20:00:19 +01:00
{
2012-12-25 17:03:24 +08:00
struct batadv_bla_backbone_gw * backbone_gw ;
2012-01-22 20:00:19 +01:00
/* register the gateway if not yet available, and add the claim. */
2012-09-08 18:02:53 +02:00
backbone_gw = batadv_bla_get_backbone_gw ( bat_priv , backbone_addr , vid ,
false ) ;
2012-01-22 20:00:19 +01:00
if ( unlikely ( ! backbone_gw ) )
return 1 ;
/* this must be a CLAIM frame */
2012-05-12 18:33:53 +02:00
batadv_bla_add_claim ( bat_priv , claim_addr , vid , backbone_gw ) ;
2012-05-12 13:48:58 +02:00
if ( batadv_compare_eth ( backbone_addr , primary_if - > net_dev - > dev_addr ) )
2012-05-12 18:33:53 +02:00
batadv_bla_send_claim ( bat_priv , claim_addr , vid ,
2012-06-23 12:34:18 +02:00
BATADV_CLAIM_TYPE_CLAIM ) ;
2012-01-22 20:00:19 +01:00
/* TODO: we could call something like tt_local_del() here. */
2012-05-12 18:33:53 +02:00
batadv_backbone_gw_free_ref ( backbone_gw ) ;
2012-01-22 20:00:19 +01:00
return 1 ;
}
2012-07-10 10:55:09 +00:00
/**
* batadv_check_claim_group
* @ bat_priv : the bat priv with all the soft interface information
2012-01-22 20:00:26 +01:00
* @ hw_src : the Hardware source in the ARP Header
* @ hw_dst : the Hardware destination in the ARP Header
* @ ethhdr : pointer to the Ethernet header of the claim frame
*
* checks if it is a claim packet and if its on the same group .
* This function also applies the group ID of the sender
* if it is in the same mesh .
*
* returns :
* 2 - if it is a claim packet and on the same group
* 1 - if is a claim packet from another group
* 0 - if it is not a claim packet
*/
2012-06-05 22:31:31 +02:00
static int batadv_check_claim_group ( struct batadv_priv * bat_priv ,
struct batadv_hard_iface * primary_if ,
2012-05-12 18:33:53 +02:00
uint8_t * hw_src , uint8_t * hw_dst ,
struct ethhdr * ethhdr )
2012-01-22 20:00:26 +01:00
{
uint8_t * backbone_addr ;
2012-06-05 22:31:31 +02:00
struct batadv_orig_node * orig_node ;
2012-06-05 22:31:30 +02:00
struct batadv_bla_claim_dst * bla_dst , * bla_dst_own ;
2012-01-22 20:00:26 +01:00
2012-06-05 22:31:30 +02:00
bla_dst = ( struct batadv_bla_claim_dst * ) hw_dst ;
2012-07-15 22:26:51 +02:00
bla_dst_own = & bat_priv - > bla . claim_dest ;
2012-01-22 20:00:26 +01:00
/* check if it is a claim packet in general */
if ( memcmp ( bla_dst - > magic , bla_dst_own - > magic ,
sizeof ( bla_dst - > magic ) ) ! = 0 )
return 0 ;
/* if announcement packet, use the source,
* otherwise assume it is in the hw_src
*/
switch ( bla_dst - > type ) {
2012-06-23 12:34:18 +02:00
case BATADV_CLAIM_TYPE_CLAIM :
2012-01-22 20:00:26 +01:00
backbone_addr = hw_src ;
break ;
2012-06-03 22:19:21 +02:00
case BATADV_CLAIM_TYPE_REQUEST :
case BATADV_CLAIM_TYPE_ANNOUNCE :
2012-06-23 12:34:18 +02:00
case BATADV_CLAIM_TYPE_UNCLAIM :
2012-01-22 20:00:26 +01:00
backbone_addr = ethhdr - > h_source ;
break ;
default :
return 0 ;
}
/* don't accept claim frames from ourselves */
2012-05-12 13:48:58 +02:00
if ( batadv_compare_eth ( backbone_addr , primary_if - > net_dev - > dev_addr ) )
2012-01-22 20:00:26 +01:00
return 0 ;
/* if its already the same group, it is fine. */
if ( bla_dst - > group = = bla_dst_own - > group )
return 2 ;
/* lets see if this originator is in our mesh */
2012-05-12 13:48:56 +02:00
orig_node = batadv_orig_hash_find ( bat_priv , backbone_addr ) ;
2012-01-22 20:00:26 +01:00
/* dont accept claims from gateways which are not in
* the same mesh or group .
*/
if ( ! orig_node )
return 1 ;
/* if our mesh friends mac is bigger, use it for ourselves. */
if ( ntohs ( bla_dst - > group ) > ntohs ( bla_dst_own - > group ) ) {
2012-06-03 22:19:22 +02:00
batadv_dbg ( BATADV_DBG_BLA , bat_priv ,
2012-11-19 09:01:43 +01:00
" taking other backbones claim group: %#.4x \n " ,
2012-05-12 13:48:58 +02:00
ntohs ( bla_dst - > group ) ) ;
2012-01-22 20:00:26 +01:00
bla_dst_own - > group = bla_dst - > group ;
}
2012-05-12 02:09:34 +02:00
batadv_orig_node_free_ref ( orig_node ) ;
2012-01-22 20:00:26 +01:00
return 2 ;
}
2012-05-12 02:09:43 +02:00
/* @bat_priv: the bat priv with all the soft interface information
2012-01-22 20:00:19 +01:00
* @ skb : the frame to be checked
*
* Check if this is a claim frame , and process it accordingly .
*
* returns 1 if it was a claim frame , otherwise return 0 to
* tell the callee that it can use the frame on its own .
*/
2012-06-05 22:31:31 +02:00
static int batadv_bla_process_claim ( struct batadv_priv * bat_priv ,
struct batadv_hard_iface * primary_if ,
2012-05-12 18:33:53 +02:00
struct sk_buff * skb )
2012-01-22 20:00:19 +01:00
{
struct ethhdr * ethhdr ;
struct vlan_ethhdr * vhdr ;
struct arphdr * arphdr ;
uint8_t * hw_src , * hw_dst ;
2012-06-05 22:31:30 +02:00
struct batadv_bla_claim_dst * bla_dst ;
2012-01-22 20:00:19 +01:00
uint16_t proto ;
int headlen ;
short vid = - 1 ;
2012-01-22 20:00:26 +01:00
int ret ;
2012-01-22 20:00:19 +01:00
ethhdr = ( struct ethhdr * ) skb_mac_header ( skb ) ;
if ( ntohs ( ethhdr - > h_proto ) = = ETH_P_8021Q ) {
vhdr = ( struct vlan_ethhdr * ) ethhdr ;
vid = ntohs ( vhdr - > h_vlan_TCI ) & VLAN_VID_MASK ;
proto = ntohs ( vhdr - > h_vlan_encapsulated_proto ) ;
headlen = sizeof ( * vhdr ) ;
} else {
proto = ntohs ( ethhdr - > h_proto ) ;
2012-02-18 11:27:34 +01:00
headlen = ETH_HLEN ;
2012-01-22 20:00:19 +01:00
}
if ( proto ! = ETH_P_ARP )
return 0 ; /* not a claim frame */
/* this must be a ARP frame. check if it is a claim. */
if ( unlikely ( ! pskb_may_pull ( skb , headlen + arp_hdr_len ( skb - > dev ) ) ) )
return 0 ;
/* pskb_may_pull() may have modified the pointers, get ethhdr again */
ethhdr = ( struct ethhdr * ) skb_mac_header ( skb ) ;
arphdr = ( struct arphdr * ) ( ( uint8_t * ) ethhdr + headlen ) ;
/* Check whether the ARP frame carries a valid
* IP information
*/
if ( arphdr - > ar_hrd ! = htons ( ARPHRD_ETHER ) )
return 0 ;
if ( arphdr - > ar_pro ! = htons ( ETH_P_IP ) )
return 0 ;
if ( arphdr - > ar_hln ! = ETH_ALEN )
return 0 ;
if ( arphdr - > ar_pln ! = 4 )
return 0 ;
hw_src = ( uint8_t * ) arphdr + sizeof ( struct arphdr ) ;
hw_dst = hw_src + ETH_ALEN + 4 ;
2012-06-05 22:31:30 +02:00
bla_dst = ( struct batadv_bla_claim_dst * ) hw_dst ;
2012-01-22 20:00:19 +01:00
/* check if it is a claim frame. */
2012-05-12 18:33:53 +02:00
ret = batadv_check_claim_group ( bat_priv , primary_if , hw_src , hw_dst ,
ethhdr ) ;
2012-01-22 20:00:26 +01:00
if ( ret = = 1 )
2012-06-03 22:19:22 +02:00
batadv_dbg ( BATADV_DBG_BLA , bat_priv ,
2012-05-12 13:48:58 +02:00
" bla_process_claim(): received a claim frame from another group. From: %pM on vid %d ...(hw_src %pM, hw_dst %pM) \n " ,
ethhdr - > h_source , vid , hw_src , hw_dst ) ;
2012-01-22 20:00:26 +01:00
if ( ret < 2 )
return ret ;
2012-01-22 20:00:19 +01:00
/* become a backbone gw ourselves on this vlan if not happened yet */
2012-05-12 18:33:53 +02:00
batadv_bla_update_own_backbone_gw ( bat_priv , primary_if , vid ) ;
2012-01-22 20:00:19 +01:00
/* check for the different types of claim frames ... */
switch ( bla_dst - > type ) {
2012-06-23 12:34:18 +02:00
case BATADV_CLAIM_TYPE_CLAIM :
2012-05-12 18:33:53 +02:00
if ( batadv_handle_claim ( bat_priv , primary_if , hw_src ,
ethhdr - > h_source , vid ) )
2012-01-22 20:00:19 +01:00
return 1 ;
break ;
2012-06-23 12:34:18 +02:00
case BATADV_CLAIM_TYPE_UNCLAIM :
2012-05-12 18:33:53 +02:00
if ( batadv_handle_unclaim ( bat_priv , primary_if ,
ethhdr - > h_source , hw_src , vid ) )
2012-01-22 20:00:19 +01:00
return 1 ;
break ;
2012-06-03 22:19:21 +02:00
case BATADV_CLAIM_TYPE_ANNOUNCE :
2012-05-12 18:33:53 +02:00
if ( batadv_handle_announce ( bat_priv , hw_src , ethhdr - > h_source ,
vid ) )
2012-01-22 20:00:19 +01:00
return 1 ;
break ;
2012-06-03 22:19:21 +02:00
case BATADV_CLAIM_TYPE_REQUEST :
2012-05-12 18:33:53 +02:00
if ( batadv_handle_request ( bat_priv , primary_if , hw_src , ethhdr ,
vid ) )
2012-01-22 20:00:19 +01:00
return 1 ;
break ;
}
2012-06-03 22:19:22 +02:00
batadv_dbg ( BATADV_DBG_BLA , bat_priv ,
2012-05-12 13:48:58 +02:00
" bla_process_claim(): ERROR - this looks like a claim frame, but is useless. eth src %pM on vid %d ...(hw_src %pM, hw_dst %pM) \n " ,
ethhdr - > h_source , vid , hw_src , hw_dst ) ;
2012-01-22 20:00:19 +01:00
return 1 ;
}
/* Check when we last heard from other nodes, and remove them in case of
* a time out , or clean all backbone gws if now is set .
*/
2012-06-05 22:31:31 +02:00
static void batadv_bla_purge_backbone_gw ( struct batadv_priv * bat_priv , int now )
2012-01-22 20:00:19 +01:00
{
2012-12-25 17:03:24 +08:00
struct batadv_bla_backbone_gw * backbone_gw ;
2012-01-22 20:00:19 +01:00
struct hlist_node * node , * node_tmp ;
struct hlist_head * head ;
2012-06-05 22:31:28 +02:00
struct batadv_hashtable * hash ;
2012-01-22 20:00:19 +01:00
spinlock_t * list_lock ; /* protects write access to the hash lists */
int i ;
2012-07-15 22:26:51 +02:00
hash = bat_priv - > bla . backbone_hash ;
2012-01-22 20:00:19 +01:00
if ( ! hash )
return ;
for ( i = 0 ; i < hash - > size ; i + + ) {
head = & hash - > table [ i ] ;
list_lock = & hash - > list_locks [ i ] ;
spin_lock_bh ( list_lock ) ;
hlist_for_each_entry_safe ( backbone_gw , node , node_tmp ,
head , hash_entry ) {
if ( now )
goto purge_now ;
2012-05-12 13:48:58 +02:00
if ( ! batadv_has_timed_out ( backbone_gw - > lasttime ,
2012-06-03 22:19:17 +02:00
BATADV_BLA_BACKBONE_TIMEOUT ) )
2012-01-22 20:00:19 +01:00
continue ;
2012-06-03 22:19:22 +02:00
batadv_dbg ( BATADV_DBG_BLA , backbone_gw - > bat_priv ,
2012-05-12 13:48:58 +02:00
" bla_purge_backbone_gw(): backbone gw %pM timed out \n " ,
backbone_gw - > orig ) ;
2012-01-22 20:00:19 +01:00
purge_now :
/* don't wait for the pending request anymore */
if ( atomic_read ( & backbone_gw - > request_sent ) )
2012-07-15 22:26:51 +02:00
atomic_dec ( & bat_priv - > bla . num_requests ) ;
2012-01-22 20:00:19 +01:00
2012-05-12 18:33:53 +02:00
batadv_bla_del_backbone_claims ( backbone_gw ) ;
2012-01-22 20:00:19 +01:00
hlist_del_rcu ( node ) ;
2012-05-12 18:33:53 +02:00
batadv_backbone_gw_free_ref ( backbone_gw ) ;
2012-01-22 20:00:19 +01:00
}
spin_unlock_bh ( list_lock ) ;
}
}
2012-07-10 10:55:09 +00:00
/**
* batadv_bla_purge_claims
* @ bat_priv : the bat priv with all the soft interface information
2012-01-22 20:00:19 +01:00
* @ primary_if : the selected primary interface , may be NULL if now is set
* @ now : whether the whole hash shall be wiped now
*
* Check when we heard last time from our own claims , and remove them in case of
* a time out , or clean all claims if now is set
*/
2012-06-05 22:31:31 +02:00
static void batadv_bla_purge_claims ( struct batadv_priv * bat_priv ,
struct batadv_hard_iface * primary_if ,
int now )
2012-01-22 20:00:19 +01:00
{
2012-12-25 17:03:25 +08:00
struct batadv_bla_claim * claim ;
2012-01-22 20:00:19 +01:00
struct hlist_node * node ;
struct hlist_head * head ;
2012-06-05 22:31:28 +02:00
struct batadv_hashtable * hash ;
2012-01-22 20:00:19 +01:00
int i ;
2012-07-15 22:26:51 +02:00
hash = bat_priv - > bla . claim_hash ;
2012-01-22 20:00:19 +01:00
if ( ! hash )
return ;
for ( i = 0 ; i < hash - > size ; i + + ) {
head = & hash - > table [ i ] ;
rcu_read_lock ( ) ;
hlist_for_each_entry_rcu ( claim , node , head , hash_entry ) {
if ( now )
goto purge_now ;
2012-05-12 13:48:58 +02:00
if ( ! batadv_compare_eth ( claim - > backbone_gw - > orig ,
primary_if - > net_dev - > dev_addr ) )
2012-01-22 20:00:19 +01:00
continue ;
2012-05-12 13:48:58 +02:00
if ( ! batadv_has_timed_out ( claim - > lasttime ,
2012-06-03 22:19:17 +02:00
BATADV_BLA_CLAIM_TIMEOUT ) )
2012-01-22 20:00:19 +01:00
continue ;
2012-06-03 22:19:22 +02:00
batadv_dbg ( BATADV_DBG_BLA , bat_priv ,
2012-05-12 13:48:58 +02:00
" bla_purge_claims(): %pM, vid %d, time out \n " ,
claim - > addr , claim - > vid ) ;
2012-01-22 20:00:19 +01:00
purge_now :
2012-05-12 18:33:53 +02:00
batadv_handle_unclaim ( bat_priv , primary_if ,
claim - > backbone_gw - > orig ,
claim - > addr , claim - > vid ) ;
2012-01-22 20:00:19 +01:00
}
rcu_read_unlock ( ) ;
}
}
2012-07-10 10:55:09 +00:00
/**
* batadv_bla_update_orig_address
* @ bat_priv : the bat priv with all the soft interface information
2012-01-22 20:00:19 +01:00
* @ primary_if : the new selected primary_if
* @ oldif : the old primary interface , may be NULL
*
* Update the backbone gateways when the own orig address changes .
*/
2012-06-05 22:31:31 +02:00
void batadv_bla_update_orig_address ( struct batadv_priv * bat_priv ,
struct batadv_hard_iface * primary_if ,
struct batadv_hard_iface * oldif )
2012-01-22 20:00:19 +01:00
{
2012-12-25 17:03:24 +08:00
struct batadv_bla_backbone_gw * backbone_gw ;
2012-01-22 20:00:19 +01:00
struct hlist_node * node ;
struct hlist_head * head ;
2012-06-05 22:31:28 +02:00
struct batadv_hashtable * hash ;
2012-07-15 22:26:51 +02:00
__be16 group ;
2012-01-22 20:00:19 +01:00
int i ;
2012-01-22 20:00:26 +01:00
/* reset bridge loop avoidance group id */
2012-07-15 22:26:51 +02:00
group = htons ( crc16 ( 0 , primary_if - > net_dev - > dev_addr , ETH_ALEN ) ) ;
bat_priv - > bla . claim_dest . group = group ;
2012-01-22 20:00:26 +01:00
2012-01-22 20:00:19 +01:00
if ( ! oldif ) {
2012-05-12 18:33:53 +02:00
batadv_bla_purge_claims ( bat_priv , NULL , 1 ) ;
batadv_bla_purge_backbone_gw ( bat_priv , 1 ) ;
2012-01-22 20:00:19 +01:00
return ;
}
2012-07-15 22:26:51 +02:00
hash = bat_priv - > bla . backbone_hash ;
2012-01-22 20:00:19 +01:00
if ( ! hash )
return ;
for ( i = 0 ; i < hash - > size ; i + + ) {
head = & hash - > table [ i ] ;
rcu_read_lock ( ) ;
hlist_for_each_entry_rcu ( backbone_gw , node , head , hash_entry ) {
/* own orig still holds the old value. */
2012-05-12 13:48:58 +02:00
if ( ! batadv_compare_eth ( backbone_gw - > orig ,
oldif - > net_dev - > dev_addr ) )
2012-01-22 20:00:19 +01:00
continue ;
memcpy ( backbone_gw - > orig ,
primary_if - > net_dev - > dev_addr , ETH_ALEN ) ;
/* send an announce frame so others will ask for our
* claims and update their tables .
*/
2012-05-12 18:33:53 +02:00
batadv_bla_send_announce ( bat_priv , backbone_gw ) ;
2012-01-22 20:00:19 +01:00
}
rcu_read_unlock ( ) ;
}
}
/* periodic work to do:
* * purge structures when they are too old
* * send announcements
*/
2012-05-12 18:33:53 +02:00
static void batadv_bla_periodic_work ( struct work_struct * work )
2012-01-22 20:00:19 +01:00
{
2012-07-08 17:13:15 +02:00
struct delayed_work * delayed_work ;
2012-06-05 22:31:31 +02:00
struct batadv_priv * bat_priv ;
2012-07-15 22:26:51 +02:00
struct batadv_priv_bla * priv_bla ;
2012-01-22 20:00:19 +01:00
struct hlist_node * node ;
struct hlist_head * head ;
2012-12-25 17:03:24 +08:00
struct batadv_bla_backbone_gw * backbone_gw ;
2012-06-05 22:31:28 +02:00
struct batadv_hashtable * hash ;
2012-06-05 22:31:31 +02:00
struct batadv_hard_iface * primary_if ;
2012-01-22 20:00:19 +01:00
int i ;
2012-07-08 17:13:15 +02:00
delayed_work = container_of ( work , struct delayed_work , work ) ;
2012-07-15 22:26:51 +02:00
priv_bla = container_of ( delayed_work , struct batadv_priv_bla , work ) ;
bat_priv = container_of ( priv_bla , struct batadv_priv , bla ) ;
2012-05-12 13:48:54 +02:00
primary_if = batadv_primary_if_get_selected ( bat_priv ) ;
2012-01-22 20:00:19 +01:00
if ( ! primary_if )
goto out ;
2012-05-12 18:33:53 +02:00
batadv_bla_purge_claims ( bat_priv , primary_if , 0 ) ;
batadv_bla_purge_backbone_gw ( bat_priv , 0 ) ;
2012-01-22 20:00:19 +01:00
if ( ! atomic_read ( & bat_priv - > bridge_loop_avoidance ) )
goto out ;
2012-07-15 22:26:51 +02:00
hash = bat_priv - > bla . backbone_hash ;
2012-01-22 20:00:19 +01:00
if ( ! hash )
goto out ;
for ( i = 0 ; i < hash - > size ; i + + ) {
head = & hash - > table [ i ] ;
rcu_read_lock ( ) ;
hlist_for_each_entry_rcu ( backbone_gw , node , head , hash_entry ) {
2012-05-12 13:48:58 +02:00
if ( ! batadv_compare_eth ( backbone_gw - > orig ,
primary_if - > net_dev - > dev_addr ) )
2012-01-22 20:00:19 +01:00
continue ;
backbone_gw - > lasttime = jiffies ;
2012-05-12 18:33:53 +02:00
batadv_bla_send_announce ( bat_priv , backbone_gw ) ;
2012-09-09 22:27:57 +02:00
/* request_sent is only set after creation to avoid
* problems when we are not yet known as backbone gw
* in the backbone .
*
2012-09-13 18:18:46 +02:00
* We can reset this now after we waited some periods
* to give bridge forward delays and bla group forming
* some grace time .
2012-09-09 22:27:57 +02:00
*/
if ( atomic_read ( & backbone_gw - > request_sent ) = = 0 )
continue ;
2012-09-13 18:18:46 +02:00
if ( ! atomic_dec_and_test ( & backbone_gw - > wait_periods ) )
continue ;
2012-09-09 22:27:57 +02:00
atomic_dec ( & backbone_gw - > bat_priv - > bla . num_requests ) ;
atomic_set ( & backbone_gw - > request_sent , 0 ) ;
2012-01-22 20:00:19 +01:00
}
rcu_read_unlock ( ) ;
}
out :
if ( primary_if )
2012-05-12 13:48:54 +02:00
batadv_hardif_free_ref ( primary_if ) ;
2012-01-22 20:00:19 +01:00
2012-12-25 13:14:37 +01:00
queue_delayed_work ( batadv_event_workqueue , & bat_priv - > bla . work ,
msecs_to_jiffies ( BATADV_BLA_PERIOD_LENGTH ) ) ;
2012-01-22 20:00:19 +01:00
}
2012-03-29 12:38:20 +02:00
/* The hash for claim and backbone hash receive the same key because they
* are getting initialized by hash_new with the same key . Reinitializing
* them with to different keys to allow nested locking without generating
* lockdep warnings
*/
2012-05-12 18:33:53 +02:00
static struct lock_class_key batadv_claim_hash_lock_class_key ;
static struct lock_class_key batadv_backbone_hash_lock_class_key ;
2012-03-29 12:38:20 +02:00
2012-01-22 20:00:19 +01:00
/* initialize all bla structures */
2012-06-05 22:31:31 +02:00
int batadv_bla_init ( struct batadv_priv * bat_priv )
2012-01-22 20:00:19 +01:00
{
2012-01-22 20:00:24 +01:00
int i ;
2012-01-22 20:00:26 +01:00
uint8_t claim_dest [ ETH_ALEN ] = { 0xff , 0x43 , 0x05 , 0x00 , 0x00 , 0x00 } ;
2012-06-05 22:31:31 +02:00
struct batadv_hard_iface * primary_if ;
2012-07-15 22:26:51 +02:00
uint16_t crc ;
unsigned long entrytime ;
2012-01-22 20:00:24 +01:00
2012-10-17 14:53:05 +02:00
spin_lock_init ( & bat_priv - > bla . bcast_duplist_lock ) ;
2012-06-03 22:19:22 +02:00
batadv_dbg ( BATADV_DBG_BLA , bat_priv , " bla hash registering \n " ) ;
2012-01-22 20:00:19 +01:00
2012-01-22 20:00:26 +01:00
/* setting claim destination address */
2012-07-15 22:26:51 +02:00
memcpy ( & bat_priv - > bla . claim_dest . magic , claim_dest , 3 ) ;
bat_priv - > bla . claim_dest . type = 0 ;
2012-05-12 13:48:54 +02:00
primary_if = batadv_primary_if_get_selected ( bat_priv ) ;
2012-01-22 20:00:26 +01:00
if ( primary_if ) {
2012-07-15 22:26:51 +02:00
crc = crc16 ( 0 , primary_if - > net_dev - > dev_addr , ETH_ALEN ) ;
bat_priv - > bla . claim_dest . group = htons ( crc ) ;
2012-05-12 13:48:54 +02:00
batadv_hardif_free_ref ( primary_if ) ;
2012-01-22 20:00:26 +01:00
} else {
2012-07-15 22:26:51 +02:00
bat_priv - > bla . claim_dest . group = 0 ; /* will be set later */
2012-01-22 20:00:26 +01:00
}
2012-01-22 20:00:24 +01:00
/* initialize the duplicate list */
2012-07-15 22:26:51 +02:00
entrytime = jiffies - msecs_to_jiffies ( BATADV_DUPLIST_TIMEOUT ) ;
2012-06-03 22:19:17 +02:00
for ( i = 0 ; i < BATADV_DUPLIST_SIZE ; i + + )
2012-07-15 22:26:51 +02:00
bat_priv - > bla . bcast_duplist [ i ] . entrytime = entrytime ;
bat_priv - > bla . bcast_duplist_curr = 0 ;
2012-01-22 20:00:24 +01:00
2012-07-15 22:26:51 +02:00
if ( bat_priv - > bla . claim_hash )
2012-05-05 13:27:28 +02:00
return 0 ;
2012-01-22 20:00:19 +01:00
2012-07-15 22:26:51 +02:00
bat_priv - > bla . claim_hash = batadv_hash_new ( 128 ) ;
bat_priv - > bla . backbone_hash = batadv_hash_new ( 32 ) ;
2012-01-22 20:00:19 +01:00
2012-07-15 22:26:51 +02:00
if ( ! bat_priv - > bla . claim_hash | | ! bat_priv - > bla . backbone_hash )
2012-05-05 13:27:28 +02:00
return - ENOMEM ;
2012-01-22 20:00:19 +01:00
2012-07-15 22:26:51 +02:00
batadv_hash_set_lock_class ( bat_priv - > bla . claim_hash ,
2012-05-12 18:33:53 +02:00
& batadv_claim_hash_lock_class_key ) ;
2012-07-15 22:26:51 +02:00
batadv_hash_set_lock_class ( bat_priv - > bla . backbone_hash ,
2012-05-12 18:33:53 +02:00
& batadv_backbone_hash_lock_class_key ) ;
2012-03-29 12:38:20 +02:00
2012-06-03 22:19:22 +02:00
batadv_dbg ( BATADV_DBG_BLA , bat_priv , " bla hashes initialized \n " ) ;
2012-01-22 20:00:19 +01:00
2012-12-25 13:14:37 +01:00
INIT_DELAYED_WORK ( & bat_priv - > bla . work , batadv_bla_periodic_work ) ;
queue_delayed_work ( batadv_event_workqueue , & bat_priv - > bla . work ,
msecs_to_jiffies ( BATADV_BLA_PERIOD_LENGTH ) ) ;
2012-05-05 13:27:28 +02:00
return 0 ;
2012-01-22 20:00:19 +01:00
}
2012-07-10 10:55:09 +00:00
/**
* batadv_bla_check_bcast_duplist
* @ bat_priv : the bat priv with all the soft interface information
2012-10-18 13:47:42 +02:00
* @ skb : contains the bcast_packet to be checked
2012-01-22 20:00:24 +01:00
*
* check if it is on our broadcast list . Another gateway might
* have sent the same packet because it is connected to the same backbone ,
* so we have to remove this duplicate .
*
* This is performed by checking the CRC , which will tell us
* with a good chance that it is the same packet . If it is furthermore
* sent by another host , drop it . We allow equal packets from
* the same host however as this might be intended .
2012-05-12 02:09:43 +02:00
*/
2012-06-05 22:31:31 +02:00
int batadv_bla_check_bcast_duplist ( struct batadv_priv * bat_priv ,
2012-10-18 13:47:42 +02:00
struct sk_buff * skb )
2012-01-22 20:00:24 +01:00
{
2012-10-18 13:47:42 +02:00
int i , curr , ret = 0 ;
__be32 crc ;
struct batadv_bcast_packet * bcast_packet ;
2012-06-05 22:31:31 +02:00
struct batadv_bcast_duplist_entry * entry ;
2012-01-22 20:00:24 +01:00
2012-10-18 13:47:42 +02:00
bcast_packet = ( struct batadv_bcast_packet * ) skb - > data ;
2012-01-22 20:00:24 +01:00
/* calculate the crc ... */
2012-10-18 13:47:42 +02:00
crc = batadv_skb_crc32 ( skb , ( u8 * ) ( bcast_packet + 1 ) ) ;
2012-01-22 20:00:24 +01:00
2012-10-17 14:53:05 +02:00
spin_lock_bh ( & bat_priv - > bla . bcast_duplist_lock ) ;
2012-06-03 22:19:17 +02:00
for ( i = 0 ; i < BATADV_DUPLIST_SIZE ; i + + ) {
2012-07-15 22:26:51 +02:00
curr = ( bat_priv - > bla . bcast_duplist_curr + i ) ;
curr % = BATADV_DUPLIST_SIZE ;
entry = & bat_priv - > bla . bcast_duplist [ curr ] ;
2012-01-22 20:00:24 +01:00
/* we can stop searching if the entry is too old ;
* later entries will be even older
*/
2012-06-03 22:19:17 +02:00
if ( batadv_has_timed_out ( entry - > entrytime ,
BATADV_DUPLIST_TIMEOUT ) )
2012-01-22 20:00:24 +01:00
break ;
if ( entry - > crc ! = crc )
continue ;
2012-05-12 13:48:58 +02:00
if ( batadv_compare_eth ( entry - > orig , bcast_packet - > orig ) )
2012-01-22 20:00:24 +01:00
continue ;
/* this entry seems to match: same crc, not too old,
* and from another gw . therefore return 1 to forbid it .
*/
2012-10-17 14:53:05 +02:00
ret = 1 ;
goto out ;
2012-01-22 20:00:24 +01:00
}
2012-10-17 14:53:05 +02:00
/* not found, add a new entry (overwrite the oldest entry)
* and allow it , its the first occurence .
*/
2012-07-15 22:26:51 +02:00
curr = ( bat_priv - > bla . bcast_duplist_curr + BATADV_DUPLIST_SIZE - 1 ) ;
2012-06-03 22:19:17 +02:00
curr % = BATADV_DUPLIST_SIZE ;
2012-07-15 22:26:51 +02:00
entry = & bat_priv - > bla . bcast_duplist [ curr ] ;
2012-01-22 20:00:24 +01:00
entry - > crc = crc ;
entry - > entrytime = jiffies ;
memcpy ( entry - > orig , bcast_packet - > orig , ETH_ALEN ) ;
2012-07-15 22:26:51 +02:00
bat_priv - > bla . bcast_duplist_curr = curr ;
2012-01-22 20:00:24 +01:00
2012-10-17 14:53:05 +02:00
out :
spin_unlock_bh ( & bat_priv - > bla . bcast_duplist_lock ) ;
return ret ;
2012-01-22 20:00:24 +01:00
}
2012-05-12 02:09:43 +02:00
/* @bat_priv: the bat priv with all the soft interface information
2012-01-22 20:00:23 +01:00
* @ orig : originator mac address
*
* check if the originator is a gateway for any VLAN ID .
*
* returns 1 if it is found , 0 otherwise
*/
2012-06-05 22:31:31 +02:00
int batadv_bla_is_backbone_gw_orig ( struct batadv_priv * bat_priv , uint8_t * orig )
2012-01-22 20:00:23 +01:00
{
2012-07-15 22:26:51 +02:00
struct batadv_hashtable * hash = bat_priv - > bla . backbone_hash ;
2012-01-22 20:00:23 +01:00
struct hlist_head * head ;
struct hlist_node * node ;
2012-12-25 17:03:24 +08:00
struct batadv_bla_backbone_gw * backbone_gw ;
2012-01-22 20:00:23 +01:00
int i ;
if ( ! atomic_read ( & bat_priv - > bridge_loop_avoidance ) )
return 0 ;
if ( ! hash )
return 0 ;
for ( i = 0 ; i < hash - > size ; i + + ) {
head = & hash - > table [ i ] ;
rcu_read_lock ( ) ;
hlist_for_each_entry_rcu ( backbone_gw , node , head , hash_entry ) {
2012-05-12 13:48:58 +02:00
if ( batadv_compare_eth ( backbone_gw - > orig , orig ) ) {
2012-01-22 20:00:23 +01:00
rcu_read_unlock ( ) ;
return 1 ;
}
}
rcu_read_unlock ( ) ;
}
return 0 ;
}
2012-07-10 10:55:09 +00:00
/**
* batadv_bla_is_backbone_gw
* @ skb : the frame to be checked
2012-01-22 20:00:19 +01:00
* @ orig_node : the orig_node of the frame
* @ hdr_size : maximum length of the frame
*
* bla_is_backbone_gw inspects the skb for the VLAN ID and returns 1
* if the orig_node is also a gateway on the soft interface , otherwise it
* returns 0.
*/
2012-05-12 13:38:47 +02:00
int batadv_bla_is_backbone_gw ( struct sk_buff * skb ,
2012-06-05 22:31:31 +02:00
struct batadv_orig_node * orig_node , int hdr_size )
2012-01-22 20:00:19 +01:00
{
struct ethhdr * ethhdr ;
struct vlan_ethhdr * vhdr ;
2012-12-25 17:03:24 +08:00
struct batadv_bla_backbone_gw * backbone_gw ;
2012-01-22 20:00:19 +01:00
short vid = - 1 ;
if ( ! atomic_read ( & orig_node - > bat_priv - > bridge_loop_avoidance ) )
return 0 ;
/* first, find out the vid. */
2012-02-18 11:27:34 +01:00
if ( ! pskb_may_pull ( skb , hdr_size + ETH_HLEN ) )
2012-01-22 20:00:19 +01:00
return 0 ;
ethhdr = ( struct ethhdr * ) ( ( ( uint8_t * ) skb - > data ) + hdr_size ) ;
if ( ntohs ( ethhdr - > h_proto ) = = ETH_P_8021Q ) {
if ( ! pskb_may_pull ( skb , hdr_size + sizeof ( struct vlan_ethhdr ) ) )
return 0 ;
2012-07-08 18:33:51 +02:00
vhdr = ( struct vlan_ethhdr * ) ( skb - > data + hdr_size ) ;
2012-01-22 20:00:19 +01:00
vid = ntohs ( vhdr - > h_vlan_TCI ) & VLAN_VID_MASK ;
}
/* see if this originator is a backbone gw for this VLAN */
2012-05-12 18:33:53 +02:00
backbone_gw = batadv_backbone_hash_find ( orig_node - > bat_priv ,
orig_node - > orig , vid ) ;
2012-01-22 20:00:19 +01:00
if ( ! backbone_gw )
return 0 ;
2012-05-12 18:33:53 +02:00
batadv_backbone_gw_free_ref ( backbone_gw ) ;
2012-01-22 20:00:19 +01:00
return 1 ;
}
/* free all bla structures (for softinterface free or module unload) */
2012-06-05 22:31:31 +02:00
void batadv_bla_free ( struct batadv_priv * bat_priv )
2012-01-22 20:00:19 +01:00
{
2012-06-05 22:31:31 +02:00
struct batadv_hard_iface * primary_if ;
2012-01-22 20:00:19 +01:00
2012-07-15 22:26:51 +02:00
cancel_delayed_work_sync ( & bat_priv - > bla . work ) ;
2012-05-12 13:48:54 +02:00
primary_if = batadv_primary_if_get_selected ( bat_priv ) ;
2012-01-22 20:00:19 +01:00
2012-07-15 22:26:51 +02:00
if ( bat_priv - > bla . claim_hash ) {
2012-05-12 18:33:53 +02:00
batadv_bla_purge_claims ( bat_priv , primary_if , 1 ) ;
2012-07-15 22:26:51 +02:00
batadv_hash_destroy ( bat_priv - > bla . claim_hash ) ;
bat_priv - > bla . claim_hash = NULL ;
2012-01-22 20:00:19 +01:00
}
2012-07-15 22:26:51 +02:00
if ( bat_priv - > bla . backbone_hash ) {
2012-05-12 18:33:53 +02:00
batadv_bla_purge_backbone_gw ( bat_priv , 1 ) ;
2012-07-15 22:26:51 +02:00
batadv_hash_destroy ( bat_priv - > bla . backbone_hash ) ;
bat_priv - > bla . backbone_hash = NULL ;
2012-01-22 20:00:19 +01:00
}
if ( primary_if )
2012-05-12 13:48:54 +02:00
batadv_hardif_free_ref ( primary_if ) ;
2012-01-22 20:00:19 +01:00
}
2012-07-10 10:55:09 +00:00
/**
* batadv_bla_rx
* @ bat_priv : the bat priv with all the soft interface information
2012-01-22 20:00:19 +01:00
* @ skb : the frame to be checked
* @ vid : the VLAN ID of the frame
2012-07-04 20:38:19 +02:00
* @ is_bcast : the packet came in a broadcast packet type .
2012-01-22 20:00:19 +01:00
*
* bla_rx avoidance checks if :
* * we have to race for a claim
* * if the frame is allowed on the LAN
*
* in these cases , the skb is further handled by this function and
* returns 1 , otherwise it returns 0 and the caller shall further
* process the skb .
*/
2012-07-10 23:56:33 -07:00
int batadv_bla_rx ( struct batadv_priv * bat_priv , struct sk_buff * skb , short vid ,
bool is_bcast )
2012-01-22 20:00:19 +01:00
{
struct ethhdr * ethhdr ;
2012-12-25 17:03:25 +08:00
struct batadv_bla_claim search_claim , * claim = NULL ;
2012-06-05 22:31:31 +02:00
struct batadv_hard_iface * primary_if ;
2012-01-22 20:00:19 +01:00
int ret ;
ethhdr = ( struct ethhdr * ) skb_mac_header ( skb ) ;
2012-05-12 13:48:54 +02:00
primary_if = batadv_primary_if_get_selected ( bat_priv ) ;
2012-01-22 20:00:19 +01:00
if ( ! primary_if )
goto handled ;
if ( ! atomic_read ( & bat_priv - > bridge_loop_avoidance ) )
goto allow ;
2012-07-15 22:26:51 +02:00
if ( unlikely ( atomic_read ( & bat_priv - > bla . num_requests ) ) )
2012-01-22 20:00:19 +01:00
/* don't allow broadcasts while requests are in flight */
2012-07-04 20:38:19 +02:00
if ( is_multicast_ether_addr ( ethhdr - > h_dest ) & & is_bcast )
2012-01-22 20:00:19 +01:00
goto handled ;
memcpy ( search_claim . addr , ethhdr - > h_source , ETH_ALEN ) ;
search_claim . vid = vid ;
2012-05-12 18:33:53 +02:00
claim = batadv_claim_hash_find ( bat_priv , & search_claim ) ;
2012-01-22 20:00:19 +01:00
if ( ! claim ) {
/* possible optimization: race for a claim */
/* No claim exists yet, claim it for us!
*/
2012-05-12 18:33:53 +02:00
batadv_handle_claim ( bat_priv , primary_if ,
primary_if - > net_dev - > dev_addr ,
ethhdr - > h_source , vid ) ;
2012-01-22 20:00:19 +01:00
goto allow ;
}
/* if it is our own claim ... */
2012-05-12 13:48:58 +02:00
if ( batadv_compare_eth ( claim - > backbone_gw - > orig ,
primary_if - > net_dev - > dev_addr ) ) {
2012-01-22 20:00:19 +01:00
/* ... allow it in any case */
claim - > lasttime = jiffies ;
goto allow ;
}
/* if it is a broadcast ... */
2012-07-04 20:38:19 +02:00
if ( is_multicast_ether_addr ( ethhdr - > h_dest ) & & is_bcast ) {
/* ... drop it. the responsible gateway is in charge.
*
* We need to check is_bcast because with the gateway
* feature , broadcasts ( like DHCP requests ) may be sent
* using a unicast packet type .
*/
2012-01-22 20:00:19 +01:00
goto handled ;
} else {
/* seems the client considers us as its best gateway.
* send a claim and update the claim table
* immediately .
*/
2012-05-12 18:33:53 +02:00
batadv_handle_claim ( bat_priv , primary_if ,
primary_if - > net_dev - > dev_addr ,
ethhdr - > h_source , vid ) ;
2012-01-22 20:00:19 +01:00
goto allow ;
}
allow :
2012-05-12 18:33:53 +02:00
batadv_bla_update_own_backbone_gw ( bat_priv , primary_if , vid ) ;
2012-01-22 20:00:19 +01:00
ret = 0 ;
goto out ;
handled :
kfree_skb ( skb ) ;
ret = 1 ;
out :
if ( primary_if )
2012-05-12 13:48:54 +02:00
batadv_hardif_free_ref ( primary_if ) ;
2012-01-22 20:00:19 +01:00
if ( claim )
2012-05-12 18:33:53 +02:00
batadv_claim_free_ref ( claim ) ;
2012-01-22 20:00:19 +01:00
return ret ;
}
2012-07-10 10:55:09 +00:00
/**
* batadv_bla_tx
* @ bat_priv : the bat priv with all the soft interface information
2012-01-22 20:00:19 +01:00
* @ skb : the frame to be checked
* @ vid : the VLAN ID of the frame
*
* bla_tx checks if :
* * a claim was received which has to be processed
* * the frame is allowed on the mesh
*
* in these cases , the skb is further handled by this function and
* returns 1 , otherwise it returns 0 and the caller shall further
* process the skb .
*/
2012-06-05 22:31:31 +02:00
int batadv_bla_tx ( struct batadv_priv * bat_priv , struct sk_buff * skb , short vid )
2012-01-22 20:00:19 +01:00
{
struct ethhdr * ethhdr ;
2012-12-25 17:03:25 +08:00
struct batadv_bla_claim search_claim , * claim = NULL ;
2012-06-05 22:31:31 +02:00
struct batadv_hard_iface * primary_if ;
2012-01-22 20:00:19 +01:00
int ret = 0 ;
2012-05-12 13:48:54 +02:00
primary_if = batadv_primary_if_get_selected ( bat_priv ) ;
2012-01-22 20:00:19 +01:00
if ( ! primary_if )
goto out ;
if ( ! atomic_read ( & bat_priv - > bridge_loop_avoidance ) )
goto allow ;
/* in VLAN case, the mac header might not be set. */
skb_reset_mac_header ( skb ) ;
2012-05-12 18:33:53 +02:00
if ( batadv_bla_process_claim ( bat_priv , primary_if , skb ) )
2012-01-22 20:00:19 +01:00
goto handled ;
ethhdr = ( struct ethhdr * ) skb_mac_header ( skb ) ;
2012-07-15 22:26:51 +02:00
if ( unlikely ( atomic_read ( & bat_priv - > bla . num_requests ) ) )
2012-01-22 20:00:19 +01:00
/* don't allow broadcasts while requests are in flight */
if ( is_multicast_ether_addr ( ethhdr - > h_dest ) )
goto handled ;
memcpy ( search_claim . addr , ethhdr - > h_source , ETH_ALEN ) ;
search_claim . vid = vid ;
2012-05-12 18:33:53 +02:00
claim = batadv_claim_hash_find ( bat_priv , & search_claim ) ;
2012-01-22 20:00:19 +01:00
/* if no claim exists, allow it. */
if ( ! claim )
goto allow ;
/* check if we are responsible. */
2012-05-12 13:48:58 +02:00
if ( batadv_compare_eth ( claim - > backbone_gw - > orig ,
primary_if - > net_dev - > dev_addr ) ) {
2012-01-22 20:00:19 +01:00
/* if yes, the client has roamed and we have
* to unclaim it .
*/
2012-05-12 18:33:53 +02:00
batadv_handle_unclaim ( bat_priv , primary_if ,
primary_if - > net_dev - > dev_addr ,
ethhdr - > h_source , vid ) ;
2012-01-22 20:00:19 +01:00
goto allow ;
}
/* check if it is a multicast/broadcast frame */
if ( is_multicast_ether_addr ( ethhdr - > h_dest ) ) {
/* drop it. the responsible gateway has forwarded it into
* the backbone network .
*/
goto handled ;
} else {
/* we must allow it. at least if we are
* responsible for the DESTINATION .
*/
goto allow ;
}
allow :
2012-05-12 18:33:53 +02:00
batadv_bla_update_own_backbone_gw ( bat_priv , primary_if , vid ) ;
2012-01-22 20:00:19 +01:00
ret = 0 ;
goto out ;
handled :
ret = 1 ;
out :
if ( primary_if )
2012-05-12 13:48:54 +02:00
batadv_hardif_free_ref ( primary_if ) ;
2012-01-22 20:00:19 +01:00
if ( claim )
2012-05-12 18:33:53 +02:00
batadv_claim_free_ref ( claim ) ;
2012-01-22 20:00:19 +01:00
return ret ;
}
2012-01-22 20:00:21 +01:00
2012-05-12 13:38:47 +02:00
int batadv_bla_claim_table_seq_print_text ( struct seq_file * seq , void * offset )
2012-01-22 20:00:21 +01:00
{
struct net_device * net_dev = ( struct net_device * ) seq - > private ;
2012-06-05 22:31:31 +02:00
struct batadv_priv * bat_priv = netdev_priv ( net_dev ) ;
2012-07-15 22:26:51 +02:00
struct batadv_hashtable * hash = bat_priv - > bla . claim_hash ;
2012-12-25 17:03:25 +08:00
struct batadv_bla_claim * claim ;
2012-06-05 22:31:31 +02:00
struct batadv_hard_iface * primary_if ;
2012-01-22 20:00:21 +01:00
struct hlist_node * node ;
struct hlist_head * head ;
uint32_t i ;
bool is_own ;
2012-05-12 13:48:58 +02:00
uint8_t * primary_addr ;
2012-01-22 20:00:21 +01:00
2012-08-03 17:15:46 +02:00
primary_if = batadv_seq_print_text_primary_if_get ( seq ) ;
if ( ! primary_if )
2012-01-22 20:00:21 +01:00
goto out ;
2012-05-12 13:48:58 +02:00
primary_addr = primary_if - > net_dev - > dev_addr ;
2012-01-22 20:00:26 +01:00
seq_printf ( seq ,
2012-11-19 09:01:43 +01:00
" Claims announced for the mesh %s (orig %pM, group id %#.4x) \n " ,
2012-05-12 13:48:58 +02:00
net_dev - > name , primary_addr ,
2012-07-15 22:26:51 +02:00
ntohs ( bat_priv - > bla . claim_dest . group ) ) ;
2012-11-19 09:01:43 +01:00
seq_printf ( seq , " %-17s %-5s %-17s [o] (%-6s) \n " ,
2012-01-22 20:00:21 +01:00
" Client " , " VID " , " Originator " , " CRC " ) ;
for ( i = 0 ; i < hash - > size ; i + + ) {
head = & hash - > table [ i ] ;
rcu_read_lock ( ) ;
hlist_for_each_entry_rcu ( claim , node , head , hash_entry ) {
2012-05-12 13:48:58 +02:00
is_own = batadv_compare_eth ( claim - > backbone_gw - > orig ,
primary_addr ) ;
2012-11-19 09:01:43 +01:00
seq_printf ( seq , " * %pM on % 5d by %pM [%c] (%#.4x) \n " ,
2012-01-22 20:00:21 +01:00
claim - > addr , claim - > vid ,
claim - > backbone_gw - > orig ,
( is_own ? ' x ' : ' ' ) ,
claim - > backbone_gw - > crc ) ;
}
rcu_read_unlock ( ) ;
}
out :
if ( primary_if )
2012-05-12 13:48:54 +02:00
batadv_hardif_free_ref ( primary_if ) ;
2012-08-03 17:15:46 +02:00
return 0 ;
2012-01-22 20:00:21 +01:00
}
2012-06-18 18:39:26 +02:00
int batadv_bla_backbone_table_seq_print_text ( struct seq_file * seq , void * offset )
{
struct net_device * net_dev = ( struct net_device * ) seq - > private ;
struct batadv_priv * bat_priv = netdev_priv ( net_dev ) ;
2012-07-15 22:26:51 +02:00
struct batadv_hashtable * hash = bat_priv - > bla . backbone_hash ;
2012-12-25 17:03:24 +08:00
struct batadv_bla_backbone_gw * backbone_gw ;
2012-06-18 18:39:26 +02:00
struct batadv_hard_iface * primary_if ;
struct hlist_node * node ;
struct hlist_head * head ;
int secs , msecs ;
uint32_t i ;
bool is_own ;
uint8_t * primary_addr ;
2012-08-03 17:15:46 +02:00
primary_if = batadv_seq_print_text_primary_if_get ( seq ) ;
if ( ! primary_if )
2012-06-18 18:39:26 +02:00
goto out ;
primary_addr = primary_if - > net_dev - > dev_addr ;
seq_printf ( seq ,
2012-11-19 09:01:43 +01:00
" Backbones announced for the mesh %s (orig %pM, group id %#.4x) \n " ,
2012-06-18 18:39:26 +02:00
net_dev - > name , primary_addr ,
2012-07-15 22:26:51 +02:00
ntohs ( bat_priv - > bla . claim_dest . group ) ) ;
2012-11-19 09:01:43 +01:00
seq_printf ( seq , " %-17s %-5s %-9s (%-6s) \n " ,
2012-06-18 18:39:26 +02:00
" Originator " , " VID " , " last seen " , " CRC " ) ;
for ( i = 0 ; i < hash - > size ; i + + ) {
head = & hash - > table [ i ] ;
rcu_read_lock ( ) ;
hlist_for_each_entry_rcu ( backbone_gw , node , head , hash_entry ) {
msecs = jiffies_to_msecs ( jiffies -
backbone_gw - > lasttime ) ;
secs = msecs / 1000 ;
msecs = msecs % 1000 ;
is_own = batadv_compare_eth ( backbone_gw - > orig ,
primary_addr ) ;
if ( is_own )
continue ;
seq_printf ( seq ,
2012-11-19 09:01:43 +01:00
" * %pM on % 5d % 4i.%03is (%#.4x) \n " ,
2012-06-18 18:39:26 +02:00
backbone_gw - > orig , backbone_gw - > vid ,
secs , msecs , backbone_gw - > crc ) ;
}
rcu_read_unlock ( ) ;
}
out :
if ( primary_if )
batadv_hardif_free_ref ( primary_if ) ;
2012-08-03 17:15:46 +02:00
return 0 ;
2012-06-18 18:39:26 +02:00
}