Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
0c070900
Commit
0c070900
authored
Sep 21, 2011
by
David S. Miller
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'batman-adv/next' of
git://git.open-mesh.org/linux-merge
parents
f26cd41a
320f422f
Changes
16
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
1281 additions
and
1275 deletions
+1281
-1275
Documentation/networking/batman-adv.txt
Documentation/networking/batman-adv.txt
+4
-4
net/batman-adv/Makefile
net/batman-adv/Makefile
+1
-1
net/batman-adv/aggregation.c
net/batman-adv/aggregation.c
+0
-293
net/batman-adv/bat_iv_ogm.c
net/batman-adv/bat_iv_ogm.c
+1170
-0
net/batman-adv/bat_ogm.h
net/batman-adv/bat_ogm.h
+10
-20
net/batman-adv/hard-interface.c
net/batman-adv/hard-interface.c
+15
-39
net/batman-adv/main.c
net/batman-adv/main.c
+0
-2
net/batman-adv/main.h
net/batman-adv/main.h
+1
-1
net/batman-adv/originator.c
net/batman-adv/originator.c
+5
-14
net/batman-adv/packet.h
net/batman-adv/packet.h
+9
-9
net/batman-adv/routing.c
net/batman-adv/routing.c
+18
-584
net/batman-adv/routing.h
net/batman-adv/routing.h
+10
-7
net/batman-adv/send.c
net/batman-adv/send.c
+25
-280
net/batman-adv/send.h
net/batman-adv/send.h
+2
-7
net/batman-adv/soft-interface.c
net/batman-adv/soft-interface.c
+10
-11
net/batman-adv/vis.c
net/batman-adv/vis.c
+1
-3
No files found.
Documentation/networking/batman-adv.txt
View file @
0c070900
[state:
17-04
-2011]
[state:
21-08
-2011]
BATMAN-ADV
----------
...
...
@@ -68,9 +68,9 @@ All mesh wide settings can be found in batman's own interface
folder:
# ls /sys/class/net/bat0/mesh/
#
aggregated_ogms gw_bandwidth hop_penalty
#
bonding gw_mode orig_interval
#
fragmentation gw_sel_class vis_mode
#
aggregated_ogms fragmentation gw_sel_class vis_mode
#
ap_isolation gw_bandwidth hop_penalty
#
bonding gw_mode orig_interval
There is a special folder for debugging information:
...
...
net/batman-adv/Makefile
View file @
0c070900
...
...
@@ -19,8 +19,8 @@
#
obj-$(CONFIG_BATMAN_ADV)
+=
batman-adv.o
batman-adv-y
+=
aggregation.o
batman-adv-y
+=
bat_debugfs.o
batman-adv-y
+=
bat_iv_ogm.o
batman-adv-y
+=
bat_sysfs.o
batman-adv-y
+=
bitarray.o
batman-adv-y
+=
gateway_client.o
...
...
net/batman-adv/aggregation.c
deleted
100644 → 0
View file @
f26cd41a
/*
* Copyright (C) 2007-2011 B.A.T.M.A.N. contributors:
*
* 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 "aggregation.h"
#include "send.h"
#include "routing.h"
#include "hard-interface.h"
/* return true if new_packet can be aggregated with forw_packet */
static
bool
can_aggregate_with
(
const
struct
batman_packet
*
new_batman_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
)
{
struct
batman_packet
*
batman_packet
=
(
struct
batman_packet
*
)
forw_packet
->
skb
->
data
;
int
aggregated_bytes
=
forw_packet
->
packet_len
+
packet_len
;
struct
hard_iface
*
primary_if
=
NULL
;
bool
res
=
false
;
/**
* we can aggregate the current packet to this aggregated packet
* 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
)
&&
time_after_eq
(
send_time
+
msecs_to_jiffies
(
MAX_AGGREGATION_MS
),
forw_packet
->
send_time
)
&&
(
aggregated_bytes
<=
MAX_AGGREGATION_BYTES
))
{
/**
* check aggregation compatibility
* -> 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
*/
primary_if
=
primary_if_get_selected
(
bat_priv
);
if
(
!
primary_if
)
goto
out
;
/* packets without direct link flag and high TTL
* are flooded through the net */
if
((
!
directlink
)
&&
(
!
(
batman_packet
->
flags
&
DIRECTLINK
))
&&
(
batman_packet
->
ttl
!=
1
)
&&
/* own packets originating non-primary
* interfaces leave only that interface */
((
!
forw_packet
->
own
)
||
(
forw_packet
->
if_incoming
==
primary_if
)))
{
res
=
true
;
goto
out
;
}
/* if the incoming packet is sent via this one
* interface only - we still can aggregate */
if
((
directlink
)
&&
(
new_batman_packet
->
ttl
==
1
)
&&
(
forw_packet
->
if_incoming
==
if_incoming
)
&&
/* packets from direct neighbors or
* own secondary interface packets
* (= secondary interface packets in general) */
(
batman_packet
->
flags
&
DIRECTLINK
||
(
forw_packet
->
own
&&
forw_packet
->
if_incoming
!=
primary_if
)))
{
res
=
true
;
goto
out
;
}
}
out:
if
(
primary_if
)
hardif_free_ref
(
primary_if
);
return
res
;
}
/* create a new aggregated packet and add this packet to it */
static
void
new_aggregated_packet
(
const
unsigned
char
*
packet_buff
,
int
packet_len
,
unsigned
long
send_time
,
bool
direct_link
,
struct
hard_iface
*
if_incoming
,
int
own_packet
)
{
struct
bat_priv
*
bat_priv
=
netdev_priv
(
if_incoming
->
soft_iface
);
struct
forw_packet
*
forw_packet_aggr
;
unsigned
char
*
skb_buff
;
if
(
!
atomic_inc_not_zero
(
&
if_incoming
->
refcount
))
return
;
/* own packet should always be scheduled */
if
(
!
own_packet
)
{
if
(
!
atomic_dec_not_zero
(
&
bat_priv
->
batman_queue_left
))
{
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"batman packet queue full
\n
"
);
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
))
&&
(
packet_len
<
MAX_AGGREGATION_BYTES
))
forw_packet_aggr
->
skb
=
dev_alloc_skb
(
MAX_AGGREGATION_BYTES
+
sizeof
(
struct
ethhdr
));
else
forw_packet_aggr
->
skb
=
dev_alloc_skb
(
packet_len
+
sizeof
(
struct
ethhdr
));
if
(
!
forw_packet_aggr
->
skb
)
{
if
(
!
own_packet
)
atomic_inc
(
&
bat_priv
->
batman_queue_left
);
kfree
(
forw_packet_aggr
);
goto
out
;
}
skb_reserve
(
forw_packet_aggr
->
skb
,
sizeof
(
struct
ethhdr
));
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
;
forw_packet_aggr
->
direct_link_flags
=
NO_FLAGS
;
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
,
send_outstanding_bat_packet
);
queue_delayed_work
(
bat_event_workqueue
,
&
forw_packet_aggr
->
delayed_work
,
send_time
-
jiffies
);
return
;
out:
hardif_free_ref
(
if_incoming
);
}
/* aggregate a new packet into the existing aggregation */
static
void
aggregate
(
struct
forw_packet
*
forw_packet_aggr
,
const
unsigned
char
*
packet_buff
,
int
packet_len
,
bool
direct_link
)
{
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
);
}
void
add_bat_packet_to_list
(
struct
bat_priv
*
bat_priv
,
unsigned
char
*
packet_buff
,
int
packet_len
,
struct
hard_iface
*
if_incoming
,
int
own_packet
,
unsigned
long
send_time
)
{
/**
* _aggr -> pointer to the packet we want to aggregate with
* _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_packet
*
batman_packet
=
(
struct
batman_packet
*
)
packet_buff
;
bool
direct_link
=
batman_packet
->
flags
&
DIRECTLINK
?
1
:
0
;
/* 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
)
{
if
(
can_aggregate_with
(
batman_packet
,
bat_priv
,
packet_len
,
send_time
,
direct_link
,
if_incoming
,
forw_packet_pos
))
{
forw_packet_aggr
=
forw_packet_pos
;
break
;
}
}
}
/* nothing to aggregate with - either aggregation disabled or no
* suitable aggregation packet found */
if
(
!
forw_packet_aggr
)
{
/* the following section can run without the lock */
spin_unlock_bh
(
&
bat_priv
->
forw_bat_list_lock
);
/**
* if we could not aggregate this packet with one of the others
* we hold it back for a while, so that it might be aggregated
* later on
*/
if
((
!
own_packet
)
&&
(
atomic_read
(
&
bat_priv
->
aggregated_ogms
)))
send_time
+=
msecs_to_jiffies
(
MAX_AGGREGATION_MS
);
new_aggregated_packet
(
packet_buff
,
packet_len
,
send_time
,
direct_link
,
if_incoming
,
own_packet
);
}
else
{
aggregate
(
forw_packet_aggr
,
packet_buff
,
packet_len
,
direct_link
);
spin_unlock_bh
(
&
bat_priv
->
forw_bat_list_lock
);
}
}
/* unpack the aggregated packets and process them one by one */
void
receive_aggr_bat_packet
(
const
struct
ethhdr
*
ethhdr
,
unsigned
char
*
packet_buff
,
int
packet_len
,
struct
hard_iface
*
if_incoming
)
{
struct
batman_packet
*
batman_packet
;
int
buff_pos
=
0
;
unsigned
char
*
tt_buff
;
batman_packet
=
(
struct
batman_packet
*
)
packet_buff
;
do
{
/* network to host order for our 32bit seqno and the
orig_interval */
batman_packet
->
seqno
=
ntohl
(
batman_packet
->
seqno
);
batman_packet
->
tt_crc
=
ntohs
(
batman_packet
->
tt_crc
);
tt_buff
=
packet_buff
+
buff_pos
+
BAT_PACKET_LEN
;
receive_bat_packet
(
ethhdr
,
batman_packet
,
tt_buff
,
if_incoming
);
buff_pos
+=
BAT_PACKET_LEN
+
tt_len
(
batman_packet
->
tt_num_changes
);
batman_packet
=
(
struct
batman_packet
*
)
(
packet_buff
+
buff_pos
);
}
while
(
aggregated_packet
(
buff_pos
,
packet_len
,
batman_packet
->
tt_num_changes
));
}
net/batman-adv/bat_iv_ogm.c
0 → 100644
View file @
0c070900
/*
* Copyright (C) 2007-2011 B.A.T.M.A.N. contributors:
*
* 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 "bat_ogm.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"
void
bat_ogm_init
(
struct
hard_iface
*
hard_iface
)
{
struct
batman_ogm_packet
*
batman_ogm_packet
;
hard_iface
->
packet_len
=
BATMAN_OGM_LEN
;
hard_iface
->
packet_buff
=
kmalloc
(
hard_iface
->
packet_len
,
GFP_ATOMIC
);
batman_ogm_packet
=
(
struct
batman_ogm_packet
*
)
hard_iface
->
packet_buff
;
batman_ogm_packet
->
packet_type
=
BAT_OGM
;
batman_ogm_packet
->
version
=
COMPAT_VERSION
;
batman_ogm_packet
->
flags
=
NO_FLAGS
;
batman_ogm_packet
->
ttl
=
2
;
batman_ogm_packet
->
tq
=
TQ_MAX_VALUE
;
batman_ogm_packet
->
tt_num_changes
=
0
;
batman_ogm_packet
->
ttvn
=
0
;
}
void
bat_ogm_init_primary
(
struct
hard_iface
*
hard_iface
)
{
struct
batman_ogm_packet
*
batman_ogm_packet
;
batman_ogm_packet
=
(
struct
batman_ogm_packet
*
)
hard_iface
->
packet_buff
;
batman_ogm_packet
->
flags
=
PRIMARIES_FIRST_HOP
;
batman_ogm_packet
->
ttl
=
TTL
;
}
void
bat_ogm_update_mac
(
struct
hard_iface
*
hard_iface
)
{
struct
batman_ogm_packet
*
batman_ogm_packet
;
batman_ogm_packet
=
(
struct
batman_ogm_packet
*
)
hard_iface
->
packet_buff
;
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
);
}
/* when do we schedule our own ogm to be sent */
static
unsigned
long
bat_ogm_emit_send_time
(
const
struct
bat_priv
*
bat_priv
)
{
return
jiffies
+
msecs_to_jiffies
(
atomic_read
(
&
bat_priv
->
orig_interval
)
-
JITTER
+
(
random32
()
%
2
*
JITTER
));
}
/* when do we schedule a ogm packet to be sent */
static
unsigned
long
bat_ogm_fwd_send_time
(
void
)
{
return
jiffies
+
msecs_to_jiffies
(
random32
()
%
(
JITTER
/
2
));
}
/* apply hop penalty for a normal link */
static
uint8_t
hop_penalty
(
uint8_t
tq
,
const
struct
bat_priv
*
bat_priv
)
{
int
hop_penalty
=
atomic_read
(
&
bat_priv
->
hop_penalty
);
return
(
tq
*
(
TQ_MAX_VALUE
-
hop_penalty
))
/
(
TQ_MAX_VALUE
);
}
/* is there another aggregated packet here? */
static
int
bat_ogm_aggr_packet
(
int
buff_pos
,
int
packet_len
,
int
tt_num_changes
)
{
int
next_buff_pos
=
buff_pos
+
BATMAN_OGM_LEN
+
tt_len
(
tt_num_changes
);
return
(
next_buff_pos
<=
packet_len
)
&&
(
next_buff_pos
<=
MAX_AGGREGATION_BYTES
);
}
/* send a batman ogm to a given interface */
static
void
bat_ogm_send_to_if
(
struct
forw_packet
*
forw_packet
,
struct
hard_iface
*
hard_iface
)
{
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 */
while
(
bat_ogm_aggr_packet
(
buff_pos
,
forw_packet
->
packet_len
,
batman_ogm_packet
->
tt_num_changes
))
{
/* we might have aggregated direct link packets with an
* ordinary base packet */
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"
));
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"%s %spacket (originator %pM, seqno %d, 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
->
ttl
,
(
batman_ogm_packet
->
flags
&
DIRECTLINK
?
"on"
:
"off"
),
batman_ogm_packet
->
ttvn
,
hard_iface
->
net_dev
->
name
,
hard_iface
->
net_dev
->
dev_addr
);
buff_pos
+=
BATMAN_OGM_LEN
+
tt_len
(
batman_ogm_packet
->
tt_num_changes
);
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
);
if
(
skb
)
send_skb_packet
(
skb
,
hard_iface
,
broadcast_addr
);
}
/* send a batman ogm packet */
void
bat_ogm_emit
(
struct
forw_packet
*
forw_packet
)
{
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
)
{
pr_err
(
"Error - can't forward packet: incoming iface not "
"specified
\n
"
);
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
;
primary_if
=
primary_if_get_selected
(
bat_priv
);
if
(
!
primary_if
)
goto
out
;
/* multihomed peer assumed */
/* non-primary OGMs are only broadcasted on their interface */
if
((
directlink
&&
(
batman_ogm_packet
->
ttl
==
1
))
||
(
forw_packet
->
own
&&
(
forw_packet
->
if_incoming
!=
primary_if
)))
{
/* FIXME: what about aggregated packets ? */
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"%s packet (originator %pM, seqno %d, 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
->
ttl
,
forw_packet
->
if_incoming
->
net_dev
->
name
,
forw_packet
->
if_incoming
->
net_dev
->
dev_addr
);
/* skb is only used once and than forw_packet is free'd */
send_skb_packet
(
forw_packet
->
skb
,
forw_packet
->
if_incoming
,
broadcast_addr
);
forw_packet
->
skb
=
NULL
;
goto
out
;
}
/* broadcast on every interface */
rcu_read_lock
();
list_for_each_entry_rcu
(
hard_iface
,
&
hardif_list
,
list
)
{
if
(
hard_iface
->
soft_iface
!=
soft_iface
)
continue
;
bat_ogm_send_to_if
(
forw_packet
,
hard_iface
);
}
rcu_read_unlock
();
out:
if
(
primary_if
)
hardif_free_ref
(
primary_if
);
}
/* return true if new_packet can be aggregated with forw_packet */
static
bool
bat_ogm_can_aggregate
(
const
struct
batman_ogm_packet
*
new_batman_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
)
{
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
;
batman_ogm_packet
=
(
struct
batman_ogm_packet
*
)
forw_packet
->
skb
->
data
;
/**
* we can aggregate the current packet to this aggregated packet
* 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
)
&&
time_after_eq
(
send_time
+
msecs_to_jiffies
(
MAX_AGGREGATION_MS
),
forw_packet
->
send_time
)
&&
(
aggregated_bytes
<=
MAX_AGGREGATION_BYTES
))
{
/**
* check aggregation compatibility
* -> 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
*/
primary_if
=
primary_if_get_selected
(
bat_priv
);
if
(
!
primary_if
)
goto
out
;
/* packets without direct link flag and high TTL
* are flooded through the net */
if
((
!
directlink
)
&&
(
!
(
batman_ogm_packet
->
flags
&
DIRECTLINK
))
&&
(
batman_ogm_packet
->
ttl
!=
1
)
&&
/* own packets originating non-primary
* interfaces leave only that interface */
((
!
forw_packet
->
own
)
||
(
forw_packet
->
if_incoming
==
primary_if
)))
{
res
=
true
;
goto
out
;
}
/* if the incoming packet is sent via this one
* interface only - we still can aggregate */
if
((
directlink
)
&&
(
new_batman_ogm_packet
->
ttl
==
1
)
&&
(
forw_packet
->
if_incoming
==
if_incoming
)
&&
/* packets from direct neighbors or
* own secondary interface packets
* (= secondary interface packets in general) */
(
batman_ogm_packet
->
flags
&
DIRECTLINK
||
(
forw_packet
->
own
&&
forw_packet
->
if_incoming
!=
primary_if
)))
{
res
=
true
;
goto
out
;
}
}
out:
if
(
primary_if
)
hardif_free_ref
(
primary_if
);
return
res
;
}
/* create a new aggregated packet and add this packet to it */
static
void
bat_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
)
{
struct
bat_priv
*
bat_priv
=
netdev_priv
(
if_incoming
->
soft_iface
);
struct
forw_packet
*
forw_packet_aggr
;
unsigned
char
*
skb_buff
;
if
(
!
atomic_inc_not_zero
(
&
if_incoming
->
refcount
))
return
;
/* own packet should always be scheduled */
if
(
!
own_packet
)
{
if
(
!
atomic_dec_not_zero
(
&
bat_priv
->
batman_queue_left
))
{
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"batman packet queue full
\n
"
);
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
))
&&
(
packet_len
<
MAX_AGGREGATION_BYTES
))
forw_packet_aggr
->
skb
=
dev_alloc_skb
(
MAX_AGGREGATION_BYTES
+
sizeof
(
struct
ethhdr
));
else
forw_packet_aggr
->
skb
=
dev_alloc_skb
(
packet_len
+
sizeof
(
struct
ethhdr
));
if
(
!
forw_packet_aggr
->
skb
)
{
if
(
!
own_packet
)
atomic_inc
(
&
bat_priv
->
batman_queue_left
);
kfree
(
forw_packet_aggr
);
goto
out
;
}
skb_reserve
(
forw_packet_aggr
->
skb
,
sizeof
(
struct
ethhdr
));
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
;
forw_packet_aggr
->
direct_link_flags
=
NO_FLAGS
;
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
,
send_outstanding_bat_ogm_packet
);
queue_delayed_work
(
bat_event_workqueue
,
&
forw_packet_aggr
->
delayed_work
,
send_time
-
jiffies
);
return
;
out:
hardif_free_ref
(
if_incoming
);
}
/* aggregate a new packet into the existing ogm packet */
static
void
bat_ogm_aggregate
(
struct
forw_packet
*
forw_packet_aggr
,
const
unsigned
char
*
packet_buff
,
int
packet_len
,
bool
direct_link
)
{
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
);
}
static
void
bat_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
)
{
/**
* _aggr -> pointer to the packet we want to aggregate with
* _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
;
batman_ogm_packet
=
(
struct
batman_ogm_packet
*
)
packet_buff
;
direct_link
=
batman_ogm_packet
->
flags
&
DIRECTLINK
?
1
:
0
;
/* 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
)
{
if
(
bat_ogm_can_aggregate
(
batman_ogm_packet
,
bat_priv
,
packet_len
,
send_time
,
direct_link
,
if_incoming
,
forw_packet_pos
))
{
forw_packet_aggr
=
forw_packet_pos
;
break
;
}
}
}
/* nothing to aggregate with - either aggregation disabled or no
* suitable aggregation packet found */
if
(
!
forw_packet_aggr
)
{
/* the following section can run without the lock */
spin_unlock_bh
(
&
bat_priv
->
forw_bat_list_lock
);
/**
* if we could not aggregate this packet with one of the others
* we hold it back for a while, so that it might be aggregated
* later on
*/
if
((
!
own_packet
)
&&
(
atomic_read
(
&
bat_priv
->
aggregated_ogms
)))
send_time
+=
msecs_to_jiffies
(
MAX_AGGREGATION_MS
);
bat_ogm_aggregate_new
(
packet_buff
,
packet_len
,
send_time
,
direct_link
,
if_incoming
,
own_packet
);
}
else
{
bat_ogm_aggregate
(
forw_packet_aggr
,
packet_buff
,
packet_len
,
direct_link
);
spin_unlock_bh
(
&
bat_priv
->
forw_bat_list_lock
);
}
}
static
void
bat_ogm_forward
(
struct
orig_node
*
orig_node
,
const
struct
ethhdr
*
ethhdr
,
struct
batman_ogm_packet
*
batman_ogm_packet
,
int
directlink
,
struct
hard_iface
*
if_incoming
)
{
struct
bat_priv
*
bat_priv
=
netdev_priv
(
if_incoming
->
soft_iface
);
struct
neigh_node
*
router
;
uint8_t
in_tq
,
in_ttl
,
tq_avg
=
0
;
uint8_t
tt_num_changes
;
if
(
batman_ogm_packet
->
ttl
<=
1
)
{
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"ttl exceeded
\n
"
);
return
;
}
router
=
orig_node_get_router
(
orig_node
);
in_tq
=
batman_ogm_packet
->
tq
;
in_ttl
=
batman_ogm_packet
->
ttl
;
tt_num_changes
=
batman_ogm_packet
->
tt_num_changes
;
batman_ogm_packet
->
ttl
--
;
memcpy
(
batman_ogm_packet
->
prev_sender
,
ethhdr
->
h_source
,
ETH_ALEN
);
/* rebroadcast tq of our best ranking neighbor to ensure the rebroadcast
* of our best tq value */
if
(
router
&&
router
->
tq_avg
!=
0
)
{
/* rebroadcast ogm of best ranking neighbor as is */
if
(
!
compare_eth
(
router
->
addr
,
ethhdr
->
h_source
))
{
batman_ogm_packet
->
tq
=
router
->
tq_avg
;
if
(
router
->
last_ttl
)
batman_ogm_packet
->
ttl
=
router
->
last_ttl
-
1
;
}
tq_avg
=
router
->
tq_avg
;
}
if
(
router
)
neigh_node_free_ref
(
router
);
/* apply hop penalty */
batman_ogm_packet
->
tq
=
hop_penalty
(
batman_ogm_packet
->
tq
,
bat_priv
);
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"Forwarding packet: tq_orig: %i, tq_avg: %i, "
"tq_forw: %i, ttl_orig: %i, ttl_forw: %i
\n
"
,
in_tq
,
tq_avg
,
batman_ogm_packet
->
tq
,
in_ttl
-
1
,
batman_ogm_packet
->
ttl
);
batman_ogm_packet
->
seqno
=
htonl
(
batman_ogm_packet
->
seqno
);
batman_ogm_packet
->
tt_crc
=
htons
(
batman_ogm_packet
->
tt_crc
);
/* switch of primaries first hop flag when forwarding */
batman_ogm_packet
->
flags
&=
~
PRIMARIES_FIRST_HOP
;
if
(
directlink
)
batman_ogm_packet
->
flags
|=
DIRECTLINK
;
else
batman_ogm_packet
->
flags
&=
~
DIRECTLINK
;
bat_ogm_queue_add
(
bat_priv
,
(
unsigned
char
*
)
batman_ogm_packet
,
BATMAN_OGM_LEN
+
tt_len
(
tt_num_changes
),
if_incoming
,
0
,
bat_ogm_fwd_send_time
());
}
void
bat_ogm_schedule
(
struct
hard_iface
*
hard_iface
,
int
tt_num_changes
)
{
struct
bat_priv
*
bat_priv
=
netdev_priv
(
hard_iface
->
soft_iface
);
struct
batman_ogm_packet
*
batman_ogm_packet
;
struct
hard_iface
*
primary_if
;
int
vis_server
;
vis_server
=
atomic_read
(
&
bat_priv
->
vis_mode
);
primary_if
=
primary_if_get_selected
(
bat_priv
);
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
));
batman_ogm_packet
->
ttvn
=
atomic_read
(
&
bat_priv
->
ttvn
);
batman_ogm_packet
->
tt_crc
=
htons
((
uint16_t
)
atomic_read
(
&
bat_priv
->
tt_crc
));
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
batman_ogm_packet
->
gw_flags
=
NO_FLAGS
;
atomic_inc
(
&
hard_iface
->
seqno
);
slide_own_bcast_window
(
hard_iface
);
bat_ogm_queue_add
(
bat_priv
,
hard_iface
->
packet_buff
,
hard_iface
->
packet_len
,
hard_iface
,
1
,
bat_ogm_emit_send_time
(
bat_priv
));
if
(
primary_if
)
hardif_free_ref
(
primary_if
);
}
static
void
bat_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
)
{
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
;
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"update_originator(): "
"Searching and updating originator entry of received packet
\n
"
);
rcu_read_lock
();
hlist_for_each_entry_rcu
(
tmp_neigh_node
,
node
,
&
orig_node
->
neigh_list
,
list
)
{
if
(
compare_eth
(
tmp_neigh_node
->
addr
,
ethhdr
->
h_source
)
&&
(
tmp_neigh_node
->
if_incoming
==
if_incoming
)
&&
atomic_inc_not_zero
(
&
tmp_neigh_node
->
refcount
))
{
if
(
neigh_node
)
neigh_node_free_ref
(
neigh_node
);
neigh_node
=
tmp_neigh_node
;
continue
;
}
if
(
is_duplicate
)
continue
;
spin_lock_bh
(
&
tmp_neigh_node
->
tq_lock
);
ring_buffer_set
(
tmp_neigh_node
->
tq_recv
,
&
tmp_neigh_node
->
tq_index
,
0
);
tmp_neigh_node
->
tq_avg
=
ring_buffer_avg
(
tmp_neigh_node
->
tq_recv
);
spin_unlock_bh
(
&
tmp_neigh_node
->
tq_lock
);
}
if
(
!
neigh_node
)
{
struct
orig_node
*
orig_tmp
;
orig_tmp
=
get_orig_node
(
bat_priv
,
ethhdr
->
h_source
);
if
(
!
orig_tmp
)
goto
unlock
;
neigh_node
=
create_neighbor
(
orig_node
,
orig_tmp
,
ethhdr
->
h_source
,
if_incoming
);
orig_node_free_ref
(
orig_tmp
);
if
(
!
neigh_node
)
goto
unlock
;
}
else
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"Updating existing last-hop neighbor of originator
\n
"
);
rcu_read_unlock
();
orig_node
->
flags
=
batman_ogm_packet
->
flags
;
neigh_node
->
last_valid
=
jiffies
;
spin_lock_bh
(
&
neigh_node
->
tq_lock
);
ring_buffer_set
(
neigh_node
->
tq_recv
,
&
neigh_node
->
tq_index
,
batman_ogm_packet
->
tq
);
neigh_node
->
tq_avg
=
ring_buffer_avg
(
neigh_node
->
tq_recv
);
spin_unlock_bh
(
&
neigh_node
->
tq_lock
);
if
(
!
is_duplicate
)
{
orig_node
->
last_ttl
=
batman_ogm_packet
->
ttl
;
neigh_node
->
last_ttl
=
batman_ogm_packet
->
ttl
;
}
bonding_candidate_add
(
orig_node
,
neigh_node
);
/* if this neighbor already is our next hop there is nothing
* to change */
router
=
orig_node_get_router
(
orig_node
);
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
* won't consider it either */
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
;
}
update_route
(
bat_priv
,
orig_node
,
neigh_node
);
update_tt:
/* I have to check for transtable changes only if the OGM has been
* sent through a primary interface */
if
(((
batman_ogm_packet
->
orig
!=
ethhdr
->
h_source
)
&&
(
batman_ogm_packet
->
ttl
>
2
))
||
(
batman_ogm_packet
->
flags
&
PRIMARIES_FIRST_HOP
))
tt_update_orig
(
bat_priv
,
orig_node
,
tt_buff
,
batman_ogm_packet
->
tt_num_changes
,
batman_ogm_packet
->
ttvn
,
batman_ogm_packet
->
tt_crc
);
if
(
orig_node
->
gw_flags
!=
batman_ogm_packet
->
gw_flags
)
gw_node_update
(
bat_priv
,
orig_node
,
batman_ogm_packet
->
gw_flags
);
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
))
gw_check_election
(
bat_priv
,
orig_node
);
goto
out
;
unlock:
rcu_read_unlock
();
out:
if
(
neigh_node
)
neigh_node_free_ref
(
neigh_node
);
if
(
router
)
neigh_node_free_ref
(
router
);
}
static
int
bat_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
)
{
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
;
uint8_t
orig_eq_count
,
neigh_rq_count
,
tq_own
;
int
tq_asym_penalty
,
ret
=
0
;
/* find corresponding one hop neighbor */
rcu_read_lock
();
hlist_for_each_entry_rcu
(
tmp_neigh_node
,
node
,
&
orig_neigh_node
->
neigh_list
,
list
)
{
if
(
!
compare_eth
(
tmp_neigh_node
->
addr
,
orig_neigh_node
->
orig
))
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
)
neigh_node
=
create_neighbor
(
orig_neigh_node
,
orig_neigh_node
,
orig_neigh_node
->
orig
,
if_incoming
);
if
(
!
neigh_node
)
goto
out
;
/* if orig_node is direct neighbor update neigh_node last_valid */
if
(
orig_node
==
orig_neigh_node
)
neigh_node
->
last_valid
=
jiffies
;
orig_node
->
last_valid
=
jiffies
;
/* 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
);
/* 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 */
if
((
total_count
<
TQ_LOCAL_BIDRECT_SEND_MINIMUM
)
||
(
neigh_rq_count
<
TQ_LOCAL_BIDRECT_RECV_MINIMUM
))
tq_own
=
0
;
else
/* neigh_node->real_packet_count is never zero as we
* only purge old information when getting new
* information */
tq_own
=
(
TQ_MAX_VALUE
*
total_count
)
/
neigh_rq_count
;
/*
* 1 - ((1-x) ** 3), normalized to TQ_MAX_VALUE this does
* affect the nearly-symmetric links only a little, but
* punishes asymmetric links more. This will give a value
* between 0 and TQ_MAX_VALUE
*/
tq_asym_penalty
=
TQ_MAX_VALUE
-
(
TQ_MAX_VALUE
*
(
TQ_LOCAL_WINDOW_SIZE
-
neigh_rq_count
)
*
(
TQ_LOCAL_WINDOW_SIZE
-
neigh_rq_count
)
*
(
TQ_LOCAL_WINDOW_SIZE
-
neigh_rq_count
))
/
(
TQ_LOCAL_WINDOW_SIZE
*
TQ_LOCAL_WINDOW_SIZE
*
TQ_LOCAL_WINDOW_SIZE
);
batman_ogm_packet
->
tq
=
((
batman_ogm_packet
->
tq
*
tq_own
*
tq_asym_penalty
)
/
(
TQ_MAX_VALUE
*
TQ_MAX_VALUE
));
bat_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
);
/* if link has the minimum required transmission quality
* consider it bidirectional */
if
(
batman_ogm_packet
->
tq
>=
TQ_TOTAL_BIDRECT_LIMIT
)
ret
=
1
;
out:
if
(
neigh_node
)
neigh_node_free_ref
(
neigh_node
);
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.
*/
static
int
bat_ogm_update_seqnos
(
const
struct
ethhdr
*
ethhdr
,
const
struct
batman_ogm_packet
*
batman_ogm_packet
,
const
struct
hard_iface
*
if_incoming
)
{
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
;
orig_node
=
get_orig_node
(
bat_priv
,
batman_ogm_packet
->
orig
);
if
(
!
orig_node
)
return
0
;
spin_lock_bh
(
&
orig_node
->
ogm_cnt_lock
);
seq_diff
=
batman_ogm_packet
->
seqno
-
orig_node
->
last_real_seqno
;
/* signalize caller that the packet is to be dropped. */
if
(
window_protected
(
bat_priv
,
seq_diff
,
&
orig_node
->
batman_seqno_reset
))
goto
out
;
rcu_read_lock
();
hlist_for_each_entry_rcu
(
tmp_neigh_node
,
node
,
&
orig_node
->
neigh_list
,
list
)
{
is_duplicate
|=
get_bit_status
(
tmp_neigh_node
->
real_bits
,
orig_node
->
last_real_seqno
,
batman_ogm_packet
->
seqno
);
if
(
compare_eth
(
tmp_neigh_node
->
addr
,
ethhdr
->
h_source
)
&&
(
tmp_neigh_node
->
if_incoming
==
if_incoming
))
set_mark
=
1
;
else
set_mark
=
0
;
/* if the window moved, set the update flag. */
need_update
|=
bit_get_packet
(
bat_priv
,
tmp_neigh_node
->
real_bits
,
seq_diff
,
set_mark
);
tmp_neigh_node
->
real_packet_count
=
bit_packet_count
(
tmp_neigh_node
->
real_bits
);
}
rcu_read_unlock
();
if
(
need_update
)
{
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"updating last_seqno: old %d, new %d
\n
"
,
orig_node
->
last_real_seqno
,
batman_ogm_packet
->
seqno
);
orig_node
->
last_real_seqno
=
batman_ogm_packet
->
seqno
;
}
ret
=
is_duplicate
;
out:
spin_unlock_bh
(
&
orig_node
->
ogm_cnt_lock
);
orig_node_free_ref
(
orig_node
);
return
ret
;
}
static
void
bat_ogm_process
(
const
struct
ethhdr
*
ethhdr
,
struct
batman_ogm_packet
*
batman_ogm_packet
,
const
unsigned
char
*
tt_buff
,
struct
hard_iface
*
if_incoming
)
{
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
;
int
is_broadcast
=
0
,
is_bidirectional
,
is_single_hop_neigh
;
int
is_duplicate
;
uint32_t
if_incoming_seqno
;
/* 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)
*/
if
(
batman_ogm_packet
->
packet_type
!=
BAT_OGM
)
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
);
is_single_hop_neigh
=
(
compare_eth
(
ethhdr
->
h_source
,
batman_ogm_packet
->
orig
)
?
1
:
0
);
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"Received BATMAN packet via NB: %pM, IF: %s [%pM] "
"(from OG: %pM, via prev OG: %pM, seqno %d, 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
,
batman_ogm_packet
->
seqno
,
batman_ogm_packet
->
ttvn
,
batman_ogm_packet
->
tt_crc
,
batman_ogm_packet
->
tt_num_changes
,
batman_ogm_packet
->
tq
,
batman_ogm_packet
->
ttl
,
batman_ogm_packet
->
version
,
has_directlink_flag
);
rcu_read_lock
();
list_for_each_entry_rcu
(
hard_iface
,
&
hardif_list
,
list
)
{
if
(
hard_iface
->
if_status
!=
IF_ACTIVE
)
continue
;
if
(
hard_iface
->
soft_iface
!=
if_incoming
->
soft_iface
)
continue
;
if
(
compare_eth
(
ethhdr
->
h_source
,
hard_iface
->
net_dev
->
dev_addr
))
is_my_addr
=
1
;
if
(
compare_eth
(
batman_ogm_packet
->
orig
,
hard_iface
->
net_dev
->
dev_addr
))
is_my_orig
=
1
;
if
(
compare_eth
(
batman_ogm_packet
->
prev_sender
,
hard_iface
->
net_dev
->
dev_addr
))
is_my_oldorig
=
1
;
if
(
is_broadcast_ether_addr
(
ethhdr
->
h_source
))
is_broadcast
=
1
;
}
rcu_read_unlock
();
if
(
batman_ogm_packet
->
version
!=
COMPAT_VERSION
)
{
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"Drop packet: incompatible batman version (%i)
\n
"
,
batman_ogm_packet
->
version
);
return
;
}
if
(
is_my_addr
)
{
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"Drop packet: received my own broadcast (sender: %pM"
")
\n
"
,
ethhdr
->
h_source
);
return
;
}
if
(
is_broadcast
)
{
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"Drop packet: "
"ignoring all packets with broadcast source addr (sender: %pM"
")
\n
"
,
ethhdr
->
h_source
);
return
;
}
if
(
is_my_orig
)
{
unsigned
long
*
word
;
int
offset
;
orig_neigh_node
=
get_orig_node
(
bat_priv
,
ethhdr
->
h_source
);
if
(
!
orig_neigh_node
)
return
;
/* neighbor has to indicate direct link and it has to
* come via the corresponding interface */
/* save packet seqno for bidirectional check */
if
(
has_directlink_flag
&&
compare_eth
(
if_incoming
->
net_dev
->
dev_addr
,
batman_ogm_packet
->
orig
))
{
offset
=
if_incoming
->
if_num
*
NUM_WORDS
;
spin_lock_bh
(
&
orig_neigh_node
->
ogm_cnt_lock
);
word
=
&
(
orig_neigh_node
->
bcast_own
[
offset
]);
bit_mark
(
word
,
if_incoming_seqno
-
batman_ogm_packet
->
seqno
-
2
);
orig_neigh_node
->
bcast_own_sum
[
if_incoming
->
if_num
]
=
bit_packet_count
(
word
);
spin_unlock_bh
(
&
orig_neigh_node
->
ogm_cnt_lock
);
}
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"Drop packet: "
"originator packet from myself (via neighbor)
\n
"
);
orig_node_free_ref
(
orig_neigh_node
);
return
;
}
if
(
is_my_oldorig
)
{
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"Drop packet: ignoring all rebroadcast echos (sender: "
"%pM)
\n
"
,
ethhdr
->
h_source
);
return
;
}
orig_node
=
get_orig_node
(
bat_priv
,
batman_ogm_packet
->
orig
);
if
(
!
orig_node
)
return
;
is_duplicate
=
bat_ogm_update_seqnos
(
ethhdr
,
batman_ogm_packet
,
if_incoming
);
if
(
is_duplicate
==
-
1
)
{
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"Drop packet: packet within seqno protection time "
"(sender: %pM)
\n
"
,
ethhdr
->
h_source
);
goto
out
;
}
if
(
batman_ogm_packet
->
tq
==
0
)
{
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"Drop packet: originator packet with tq equal 0
\n
"
);
goto
out
;
}
router
=
orig_node_get_router
(
orig_node
);
if
(
router
)
router_router
=
orig_node_get_router
(
router
->
orig_node
);
/* avoid temporary routing loops */
if
(
router
&&
router_router
&&
(
compare_eth
(
router
->
addr
,
batman_ogm_packet
->
prev_sender
))
&&
!
(
compare_eth
(
batman_ogm_packet
->
orig
,
batman_ogm_packet
->
prev_sender
))
&&
(
compare_eth
(
router
->
addr
,
router_router
->
addr
)))
{
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"Drop packet: ignoring all rebroadcast packets that "
"may make me loop (sender: %pM)
\n
"
,
ethhdr
->
h_source
);
goto
out
;
}
/* if sender is a direct neighbor the sender mac equals
* originator mac */
orig_neigh_node
=
(
is_single_hop_neigh
?
orig_node
:
get_orig_node
(
bat_priv
,
ethhdr
->
h_source
));
if
(
!
orig_neigh_node
)
goto
out
;
orig_neigh_router
=
orig_node_get_router
(
orig_neigh_node
);
/* drop packet if sender is not a direct neighbor and if we
* don't route towards it */
if
(
!
is_single_hop_neigh
&&
(
!
orig_neigh_router
))
{
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"Drop packet: OGM via unknown neighbor!
\n
"
);
goto
out_neigh
;
}
is_bidirectional
=
bat_ogm_calc_tq
(
orig_node
,
orig_neigh_node
,
batman_ogm_packet
,
if_incoming
);
bonding_save_primary
(
orig_node
,
orig_neigh_node
,
batman_ogm_packet
);
/* update ranking if it is not a duplicate or has the same
* seqno and similar ttl as the non-duplicate */
if
(
is_bidirectional
&&
(
!
is_duplicate
||
((
orig_node
->
last_real_seqno
==
batman_ogm_packet
->
seqno
)
&&
(
orig_node
->
last_ttl
-
3
<=
batman_ogm_packet
->
ttl
))))
bat_ogm_orig_update
(
bat_priv
,
orig_node
,
ethhdr
,
batman_ogm_packet
,
if_incoming
,
tt_buff
,
is_duplicate
);
/* is single hop (direct) neighbor */
if
(
is_single_hop_neigh
)
{
/* mark direct link on incoming interface */
bat_ogm_forward
(
orig_node
,
ethhdr
,
batman_ogm_packet
,
1
,
if_incoming
);
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"Forwarding packet: "
"rebroadcast neighbor packet with direct link flag
\n
"
);
goto
out_neigh
;
}
/* multihop originator */
if
(
!
is_bidirectional
)
{
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"Drop packet: not received via bidirectional link
\n
"
);
goto
out_neigh
;
}
if
(
is_duplicate
)
{
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"Drop packet: duplicate packet received
\n
"
);
goto
out_neigh
;
}
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"Forwarding packet: rebroadcast originator packet
\n
"
);
bat_ogm_forward
(
orig_node
,
ethhdr
,
batman_ogm_packet
,
0
,
if_incoming
);
out_neigh:
if
((
orig_neigh_node
)
&&
(
!
is_single_hop_neigh
))
orig_node_free_ref
(
orig_neigh_node
);
out:
if
(
router
)
neigh_node_free_ref
(
router
);
if
(
router_router
)
neigh_node_free_ref
(
router_router
);
if
(
orig_neigh_router
)
neigh_node_free_ref
(
orig_neigh_router
);
orig_node_free_ref
(
orig_node
);
}
void
bat_ogm_receive
(
const
struct
ethhdr
*
ethhdr
,
unsigned
char
*
packet_buff
,
int
packet_len
,
struct
hard_iface
*
if_incoming
)
{
struct
batman_ogm_packet
*
batman_ogm_packet
;
int
buff_pos
=
0
;
unsigned
char
*
tt_buff
;
batman_ogm_packet
=
(
struct
batman_ogm_packet
*
)
packet_buff
;
/* unpack the aggregated packets and process them one by one */
do
{
/* network to host order for our 32bit seqno and the
orig_interval */
batman_ogm_packet
->
seqno
=
ntohl
(
batman_ogm_packet
->
seqno
);
batman_ogm_packet
->
tt_crc
=
ntohs
(
batman_ogm_packet
->
tt_crc
);
tt_buff
=
packet_buff
+
buff_pos
+
BATMAN_OGM_LEN
;
bat_ogm_process
(
ethhdr
,
batman_ogm_packet
,
tt_buff
,
if_incoming
);
buff_pos
+=
BATMAN_OGM_LEN
+
tt_len
(
batman_ogm_packet
->
tt_num_changes
);
batman_ogm_packet
=
(
struct
batman_ogm_packet
*
)
(
packet_buff
+
buff_pos
);
}
while
(
bat_ogm_aggr_packet
(
buff_pos
,
packet_len
,
batman_ogm_packet
->
tt_num_changes
));
}
net/batman-adv/
aggregation
.h
→
net/batman-adv/
bat_ogm
.h
View file @
0c070900
...
...
@@ -19,27 +19,17 @@
*
*/
#ifndef _NET_BATMAN_ADV_
AGGREGATION
_H_
#define _NET_BATMAN_ADV_
AGGREGATION
_H_
#ifndef _NET_BATMAN_ADV_
OGM
_H_
#define _NET_BATMAN_ADV_
OGM
_H_
#include "main.h"
/* is there another aggregated packet here? */
static
inline
int
aggregated_packet
(
int
buff_pos
,
int
packet_len
,
int
tt_num_changes
)
{
int
next_buff_pos
=
buff_pos
+
BAT_PACKET_LEN
+
tt_len
(
tt_num_changes
);
void
bat_ogm_init
(
struct
hard_iface
*
hard_iface
);
void
bat_ogm_init_primary
(
struct
hard_iface
*
hard_iface
);
void
bat_ogm_update_mac
(
struct
hard_iface
*
hard_iface
);
void
bat_ogm_schedule
(
struct
hard_iface
*
hard_iface
,
int
tt_num_changes
);
void
bat_ogm_emit
(
struct
forw_packet
*
forw_packet
);
void
bat_ogm_receive
(
const
struct
ethhdr
*
ethhdr
,
unsigned
char
*
packet_buff
,
int
packet_len
,
struct
hard_iface
*
if_incoming
);
return
(
next_buff_pos
<=
packet_len
)
&&
(
next_buff_pos
<=
MAX_AGGREGATION_BYTES
);
}
void
add_bat_packet_to_list
(
struct
bat_priv
*
bat_priv
,
unsigned
char
*
packet_buff
,
int
packet_len
,
struct
hard_iface
*
if_incoming
,
int
own_packet
,
unsigned
long
send_time
);
void
receive_aggr_bat_packet
(
const
struct
ethhdr
*
ethhdr
,
unsigned
char
*
packet_buff
,
int
packet_len
,
struct
hard_iface
*
if_incoming
);
#endif
/* _NET_BATMAN_ADV_AGGREGATION_H_ */
#endif
/* _NET_BATMAN_ADV_OGM_H_ */
net/batman-adv/hard-interface.c
View file @
0c070900
...
...
@@ -28,6 +28,7 @@
#include "bat_sysfs.h"
#include "originator.h"
#include "hash.h"
#include "bat_ogm.h"
#include <linux/if_arp.h>
...
...
@@ -131,7 +132,6 @@ static void primary_if_select(struct bat_priv *bat_priv,
struct
hard_iface
*
new_hard_iface
)
{
struct
hard_iface
*
curr_hard_iface
;
struct
batman_packet
*
batman_packet
;
ASSERT_RTNL
();
...
...
@@ -147,10 +147,7 @@ static void primary_if_select(struct bat_priv *bat_priv,
if
(
!
new_hard_iface
)
return
;
batman_packet
=
(
struct
batman_packet
*
)(
new_hard_iface
->
packet_buff
);
batman_packet
->
flags
=
PRIMARIES_FIRST_HOP
;
batman_packet
->
ttl
=
TTL
;
bat_ogm_init_primary
(
new_hard_iface
);
primary_if_update_addr
(
bat_priv
);
}
...
...
@@ -162,14 +159,6 @@ static bool hardif_is_iface_up(const struct hard_iface *hard_iface)
return
false
;
}
static
void
update_mac_addresses
(
struct
hard_iface
*
hard_iface
)
{
memcpy
(((
struct
batman_packet
*
)(
hard_iface
->
packet_buff
))
->
orig
,
hard_iface
->
net_dev
->
dev_addr
,
ETH_ALEN
);
memcpy
(((
struct
batman_packet
*
)(
hard_iface
->
packet_buff
))
->
prev_sender
,
hard_iface
->
net_dev
->
dev_addr
,
ETH_ALEN
);
}
static
void
check_known_mac_addr
(
const
struct
net_device
*
net_dev
)
{
const
struct
hard_iface
*
hard_iface
;
...
...
@@ -244,7 +233,7 @@ static void hardif_activate_interface(struct hard_iface *hard_iface)
bat_priv
=
netdev_priv
(
hard_iface
->
soft_iface
);
update_mac_addresses
(
hard_iface
);
bat_ogm_update_mac
(
hard_iface
);
hard_iface
->
if_status
=
IF_TO_BE_ACTIVATED
;
/**
...
...
@@ -283,7 +272,6 @@ int hardif_enable_interface(struct hard_iface *hard_iface,
const
char
*
iface_name
)
{
struct
bat_priv
*
bat_priv
;
struct
batman_packet
*
batman_packet
;
struct
net_device
*
soft_iface
;
int
ret
;
...
...
@@ -318,8 +306,8 @@ int hardif_enable_interface(struct hard_iface *hard_iface,
hard_iface
->
soft_iface
=
soft_iface
;
bat_priv
=
netdev_priv
(
hard_iface
->
soft_iface
);
hard_iface
->
packet_len
=
BAT_PACKET_LEN
;
hard_iface
->
packet_buff
=
kmalloc
(
hard_iface
->
packet_len
,
GFP_ATOMIC
);
bat_ogm_init
(
hard_iface
);
if
(
!
hard_iface
->
packet_buff
)
{
bat_err
(
hard_iface
->
soft_iface
,
"Can't add interface packet "
...
...
@@ -328,15 +316,6 @@ int hardif_enable_interface(struct hard_iface *hard_iface,
goto
err
;
}
batman_packet
=
(
struct
batman_packet
*
)(
hard_iface
->
packet_buff
);
batman_packet
->
packet_type
=
BAT_PACKET
;
batman_packet
->
version
=
COMPAT_VERSION
;
batman_packet
->
flags
=
NO_FLAGS
;
batman_packet
->
ttl
=
2
;
batman_packet
->
tq
=
TQ_MAX_VALUE
;
batman_packet
->
tt_num_changes
=
0
;
batman_packet
->
ttvn
=
0
;
hard_iface
->
if_num
=
bat_priv
->
num_ifaces
;
bat_priv
->
num_ifaces
++
;
hard_iface
->
if_status
=
IF_INACTIVE
;
...
...
@@ -381,7 +360,7 @@ int hardif_enable_interface(struct hard_iface *hard_iface,
hard_iface
->
net_dev
->
name
);
/* begin scheduling originator messages on that interface */
schedule_
own_packet
(
hard_iface
);
schedule_
bat_ogm
(
hard_iface
);
out:
return
0
;
...
...
@@ -455,11 +434,8 @@ static struct hard_iface *hardif_add_interface(struct net_device *net_dev)
dev_hold
(
net_dev
);
hard_iface
=
kmalloc
(
sizeof
(
*
hard_iface
),
GFP_ATOMIC
);
if
(
!
hard_iface
)
{
pr_err
(
"Can't add interface (%s): out of memory
\n
"
,
net_dev
->
name
);
if
(
!
hard_iface
)
goto
release_dev
;
}
ret
=
sysfs_add_hardif
(
&
hard_iface
->
hardif_obj
,
net_dev
);
if
(
ret
)
...
...
@@ -551,7 +527,7 @@ static int hard_if_event(struct notifier_block *this,
goto
hardif_put
;
check_known_mac_addr
(
hard_iface
->
net_dev
);
update_mac_addresses
(
hard_iface
);
bat_ogm_update_mac
(
hard_iface
);
bat_priv
=
netdev_priv
(
hard_iface
->
soft_iface
);
primary_if
=
primary_if_get_selected
(
bat_priv
);
...
...
@@ -580,7 +556,7 @@ static int batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
struct
net_device
*
orig_dev
)
{
struct
bat_priv
*
bat_priv
;
struct
batman_
packet
*
batman
_packet
;
struct
batman_
ogm_packet
*
batman_ogm
_packet
;
struct
hard_iface
*
hard_iface
;
int
ret
;
...
...
@@ -612,22 +588,22 @@ static int batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
if
(
hard_iface
->
if_status
!=
IF_ACTIVE
)
goto
err_free
;
batman_
packet
=
(
struct
batman
_packet
*
)
skb
->
data
;
batman_
ogm_packet
=
(
struct
batman_ogm
_packet
*
)
skb
->
data
;
if
(
batman_packet
->
version
!=
COMPAT_VERSION
)
{
if
(
batman_
ogm_
packet
->
version
!=
COMPAT_VERSION
)
{
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"Drop packet: incompatible batman version (%i)
\n
"
,
batman_packet
->
version
);
batman_
ogm_
packet
->
version
);
goto
err_free
;
}
/* all receive handlers return whether they received or reused
* the supplied skb. if not, we have to free the skb. */
switch
(
batman_packet
->
packet_type
)
{
switch
(
batman_
ogm_
packet
->
packet_type
)
{
/* batman originator packet */
case
BAT_
PACKET
:
ret
=
recv_bat_packet
(
skb
,
hard_iface
);
case
BAT_
OGM
:
ret
=
recv_bat_
ogm_
packet
(
skb
,
hard_iface
);
break
;
/* batman icmp packet */
...
...
net/batman-adv/main.c
View file @
0c070900
...
...
@@ -117,8 +117,6 @@ int mesh_init(struct net_device *soft_iface)
goto
end
;
err:
pr_err
(
"Unable to allocate memory for mesh information structures: "
"out of mem ?
\n
"
);
mesh_free
(
soft_iface
);
return
-
1
;
...
...
net/batman-adv/main.h
View file @
0c070900
...
...
@@ -28,7 +28,7 @@
#define DRIVER_DEVICE "batman-adv"
#ifndef SOURCE_VERSION
#define SOURCE_VERSION "2011.
3
.0"
#define SOURCE_VERSION "2011.
4
.0"
#endif
/* B.A.T.M.A.N. parameters */
...
...
net/batman-adv/originator.c
View file @
0c070900
...
...
@@ -336,8 +336,7 @@ static bool purge_orig_node(struct bat_priv *bat_priv,
}
else
{
if
(
purge_orig_neighbors
(
bat_priv
,
orig_node
,
&
best_neigh_node
))
{
update_routes
(
bat_priv
,
orig_node
,
best_neigh_node
);
update_route
(
bat_priv
,
orig_node
,
best_neigh_node
);
}
}
...
...
@@ -493,10 +492,8 @@ static int orig_node_add_if(struct orig_node *orig_node, int max_if_num)
data_ptr
=
kmalloc
(
max_if_num
*
sizeof
(
unsigned
long
)
*
NUM_WORDS
,
GFP_ATOMIC
);
if
(
!
data_ptr
)
{
pr_err
(
"Can't resize orig: out of memory
\n
"
);
if
(
!
data_ptr
)
return
-
1
;
}
memcpy
(
data_ptr
,
orig_node
->
bcast_own
,
(
max_if_num
-
1
)
*
sizeof
(
unsigned
long
)
*
NUM_WORDS
);
...
...
@@ -504,10 +501,8 @@ static int orig_node_add_if(struct orig_node *orig_node, int max_if_num)
orig_node
->
bcast_own
=
data_ptr
;
data_ptr
=
kmalloc
(
max_if_num
*
sizeof
(
uint8_t
),
GFP_ATOMIC
);
if
(
!
data_ptr
)
{
pr_err
(
"Can't resize orig: out of memory
\n
"
);
if
(
!
data_ptr
)
return
-
1
;
}
memcpy
(
data_ptr
,
orig_node
->
bcast_own_sum
,
(
max_if_num
-
1
)
*
sizeof
(
uint8_t
));
...
...
@@ -562,10 +557,8 @@ static int orig_node_del_if(struct orig_node *orig_node,
chunk_size
=
sizeof
(
unsigned
long
)
*
NUM_WORDS
;
data_ptr
=
kmalloc
(
max_if_num
*
chunk_size
,
GFP_ATOMIC
);
if
(
!
data_ptr
)
{
pr_err
(
"Can't resize orig: out of memory
\n
"
);
if
(
!
data_ptr
)
return
-
1
;
}
/* copy first part */
memcpy
(
data_ptr
,
orig_node
->
bcast_own
,
del_if_num
*
chunk_size
);
...
...
@@ -583,10 +576,8 @@ static int orig_node_del_if(struct orig_node *orig_node,
goto
free_own_sum
;
data_ptr
=
kmalloc
(
max_if_num
*
sizeof
(
uint8_t
),
GFP_ATOMIC
);
if
(
!
data_ptr
)
{
pr_err
(
"Can't resize orig: out of memory
\n
"
);
if
(
!
data_ptr
)
return
-
1
;
}
memcpy
(
data_ptr
,
orig_node
->
bcast_own_sum
,
del_if_num
*
sizeof
(
uint8_t
));
...
...
net/batman-adv/packet.h
View file @
0c070900
...
...
@@ -25,14 +25,14 @@
#define ETH_P_BATMAN 0x4305
/* unofficial/not registered Ethertype */
enum
bat_packettype
{
BAT_
PACKET
=
0x01
,
BAT_ICMP
=
0x02
,
BAT_UNICAST
=
0x03
,
BAT_BCAST
=
0x04
,
BAT_VIS
=
0x05
,
BAT_
OGM
=
0x01
,
BAT_ICMP
=
0x02
,
BAT_UNICAST
=
0x03
,
BAT_BCAST
=
0x04
,
BAT_VIS
=
0x05
,
BAT_UNICAST_FRAG
=
0x06
,
BAT_TT_QUERY
=
0x07
,
BAT_ROAM_ADV
=
0x08
BAT_TT_QUERY
=
0x07
,
BAT_ROAM_ADV
=
0x08
};
/* this file is included by batctl which needs these defines */
...
...
@@ -90,7 +90,7 @@ enum tt_client_flags {
TT_CLIENT_PENDING
=
1
<<
10
};
struct
batman_packet
{
struct
batman_
ogm_
packet
{
uint8_t
packet_type
;
uint8_t
version
;
/* batman version field */
uint8_t
ttl
;
...
...
@@ -105,7 +105,7 @@ struct batman_packet {
uint16_t
tt_crc
;
}
__packed
;
#define BAT
_PACKET_LEN sizeof(struct batman
_packet)
#define BAT
MAN_OGM_LEN sizeof(struct batman_ogm
_packet)
struct
icmp_packet
{
uint8_t
packet_type
;
...
...
net/batman-adv/routing.c
View file @
0c070900
...
...
@@ -22,18 +22,14 @@
#include "main.h"
#include "routing.h"
#include "send.h"
#include "hash.h"
#include "soft-interface.h"
#include "hard-interface.h"
#include "icmp_socket.h"
#include "translation-table.h"
#include "originator.h"
#include "ring_buffer.h"
#include "vis.h"
#include "aggregation.h"
#include "gateway_common.h"
#include "gateway_client.h"
#include "unicast.h"
#include "bat_ogm.h"
void
slide_own_bcast_window
(
struct
hard_iface
*
hard_iface
)
{
...
...
@@ -64,9 +60,9 @@ void slide_own_bcast_window(struct hard_iface *hard_iface)
}
}
static
void
update_route
(
struct
bat_priv
*
bat_priv
,
struct
orig_node
*
orig_node
,
struct
neigh_node
*
neigh_node
)
static
void
_
update_route
(
struct
bat_priv
*
bat_priv
,
struct
orig_node
*
orig_node
,
struct
neigh_node
*
neigh_node
)
{
struct
neigh_node
*
curr_router
;
...
...
@@ -110,8 +106,8 @@ static void update_route(struct bat_priv *bat_priv,
neigh_node_free_ref
(
curr_router
);
}
void
update_route
s
(
struct
bat_priv
*
bat_priv
,
struct
orig_node
*
orig_node
,
struct
neigh_node
*
neigh_node
)
void
update_route
(
struct
bat_priv
*
bat_priv
,
struct
orig_node
*
orig_node
,
struct
neigh_node
*
neigh_node
)
{
struct
neigh_node
*
router
=
NULL
;
...
...
@@ -121,116 +117,13 @@ void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_node,
router
=
orig_node_get_router
(
orig_node
);
if
(
router
!=
neigh_node
)
update_route
(
bat_priv
,
orig_node
,
neigh_node
);
_
update_route
(
bat_priv
,
orig_node
,
neigh_node
);
out:
if
(
router
)
neigh_node_free_ref
(
router
);
}
static
int
is_bidirectional_neigh
(
struct
orig_node
*
orig_node
,
struct
orig_node
*
orig_neigh_node
,
struct
batman_packet
*
batman_packet
,
struct
hard_iface
*
if_incoming
)
{
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
;
uint8_t
orig_eq_count
,
neigh_rq_count
,
tq_own
;
int
tq_asym_penalty
,
ret
=
0
;
/* find corresponding one hop neighbor */
rcu_read_lock
();
hlist_for_each_entry_rcu
(
tmp_neigh_node
,
node
,
&
orig_neigh_node
->
neigh_list
,
list
)
{
if
(
!
compare_eth
(
tmp_neigh_node
->
addr
,
orig_neigh_node
->
orig
))
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
)
neigh_node
=
create_neighbor
(
orig_neigh_node
,
orig_neigh_node
,
orig_neigh_node
->
orig
,
if_incoming
);
if
(
!
neigh_node
)
goto
out
;
/* if orig_node is direct neighbor update neigh_node last_valid */
if
(
orig_node
==
orig_neigh_node
)
neigh_node
->
last_valid
=
jiffies
;
orig_node
->
last_valid
=
jiffies
;
/* 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
);
/* 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 */
if
((
total_count
<
TQ_LOCAL_BIDRECT_SEND_MINIMUM
)
||
(
neigh_rq_count
<
TQ_LOCAL_BIDRECT_RECV_MINIMUM
))
tq_own
=
0
;
else
/* neigh_node->real_packet_count is never zero as we
* only purge old information when getting new
* information */
tq_own
=
(
TQ_MAX_VALUE
*
total_count
)
/
neigh_rq_count
;
/*
* 1 - ((1-x) ** 3), normalized to TQ_MAX_VALUE this does
* affect the nearly-symmetric links only a little, but
* punishes asymmetric links more. This will give a value
* between 0 and TQ_MAX_VALUE
*/
tq_asym_penalty
=
TQ_MAX_VALUE
-
(
TQ_MAX_VALUE
*
(
TQ_LOCAL_WINDOW_SIZE
-
neigh_rq_count
)
*
(
TQ_LOCAL_WINDOW_SIZE
-
neigh_rq_count
)
*
(
TQ_LOCAL_WINDOW_SIZE
-
neigh_rq_count
))
/
(
TQ_LOCAL_WINDOW_SIZE
*
TQ_LOCAL_WINDOW_SIZE
*
TQ_LOCAL_WINDOW_SIZE
);
batman_packet
->
tq
=
((
batman_packet
->
tq
*
tq_own
*
tq_asym_penalty
)
/
(
TQ_MAX_VALUE
*
TQ_MAX_VALUE
));
bat_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_packet
->
tq
);
/* if link has the minimum required transmission quality
* consider it bidirectional */
if
(
batman_packet
->
tq
>=
TQ_TOTAL_BIDRECT_LIMIT
)
ret
=
1
;
out:
if
(
neigh_node
)
neigh_node_free_ref
(
neigh_node
);
return
ret
;
}
/* caller must hold the neigh_list_lock */
void
bonding_candidate_del
(
struct
orig_node
*
orig_node
,
struct
neigh_node
*
neigh_node
)
...
...
@@ -248,8 +141,8 @@ void bonding_candidate_del(struct orig_node *orig_node,
return
;
}
static
void
bonding_candidate_add
(
struct
orig_node
*
orig_node
,
struct
neigh_node
*
neigh_node
)
void
bonding_candidate_add
(
struct
orig_node
*
orig_node
,
struct
neigh_node
*
neigh_node
)
{
struct
hlist_node
*
node
;
struct
neigh_node
*
tmp_neigh_node
,
*
router
=
NULL
;
...
...
@@ -319,161 +212,23 @@ static void bonding_candidate_add(struct orig_node *orig_node,
}
/* copy primary address for bonding */
static
void
bonding_save_primary
(
const
struct
orig_node
*
orig_node
,
struct
orig_node
*
orig_neigh_node
,
const
struct
batman_packet
*
batman
_packet
)
void
bonding_save_primary
(
const
struct
orig_node
*
orig_node
,
struct
orig_node
*
orig_neigh_node
,
const
struct
batman_ogm_packet
*
batman_ogm
_packet
)
{
if
(
!
(
batman_packet
->
flags
&
PRIMARIES_FIRST_HOP
))
if
(
!
(
batman_
ogm_
packet
->
flags
&
PRIMARIES_FIRST_HOP
))
return
;
memcpy
(
orig_neigh_node
->
primary_addr
,
orig_node
->
orig
,
ETH_ALEN
);
}
static
void
update_orig
(
struct
bat_priv
*
bat_priv
,
struct
orig_node
*
orig_node
,
const
struct
ethhdr
*
ethhdr
,
const
struct
batman_packet
*
batman_packet
,
struct
hard_iface
*
if_incoming
,
const
unsigned
char
*
tt_buff
,
int
is_duplicate
)
{
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
;
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"update_originator(): "
"Searching and updating originator entry of received packet
\n
"
);
rcu_read_lock
();
hlist_for_each_entry_rcu
(
tmp_neigh_node
,
node
,
&
orig_node
->
neigh_list
,
list
)
{
if
(
compare_eth
(
tmp_neigh_node
->
addr
,
ethhdr
->
h_source
)
&&
(
tmp_neigh_node
->
if_incoming
==
if_incoming
)
&&
atomic_inc_not_zero
(
&
tmp_neigh_node
->
refcount
))
{
if
(
neigh_node
)
neigh_node_free_ref
(
neigh_node
);
neigh_node
=
tmp_neigh_node
;
continue
;
}
if
(
is_duplicate
)
continue
;
spin_lock_bh
(
&
tmp_neigh_node
->
tq_lock
);
ring_buffer_set
(
tmp_neigh_node
->
tq_recv
,
&
tmp_neigh_node
->
tq_index
,
0
);
tmp_neigh_node
->
tq_avg
=
ring_buffer_avg
(
tmp_neigh_node
->
tq_recv
);
spin_unlock_bh
(
&
tmp_neigh_node
->
tq_lock
);
}
if
(
!
neigh_node
)
{
struct
orig_node
*
orig_tmp
;
orig_tmp
=
get_orig_node
(
bat_priv
,
ethhdr
->
h_source
);
if
(
!
orig_tmp
)
goto
unlock
;
neigh_node
=
create_neighbor
(
orig_node
,
orig_tmp
,
ethhdr
->
h_source
,
if_incoming
);
orig_node_free_ref
(
orig_tmp
);
if
(
!
neigh_node
)
goto
unlock
;
}
else
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"Updating existing last-hop neighbor of originator
\n
"
);
rcu_read_unlock
();
orig_node
->
flags
=
batman_packet
->
flags
;
neigh_node
->
last_valid
=
jiffies
;
spin_lock_bh
(
&
neigh_node
->
tq_lock
);
ring_buffer_set
(
neigh_node
->
tq_recv
,
&
neigh_node
->
tq_index
,
batman_packet
->
tq
);
neigh_node
->
tq_avg
=
ring_buffer_avg
(
neigh_node
->
tq_recv
);
spin_unlock_bh
(
&
neigh_node
->
tq_lock
);
if
(
!
is_duplicate
)
{
orig_node
->
last_ttl
=
batman_packet
->
ttl
;
neigh_node
->
last_ttl
=
batman_packet
->
ttl
;
}
bonding_candidate_add
(
orig_node
,
neigh_node
);
/* if this neighbor already is our next hop there is nothing
* to change */
router
=
orig_node_get_router
(
orig_node
);
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
* won't consider it either */
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
;
}
update_routes
(
bat_priv
,
orig_node
,
neigh_node
);
update_tt:
/* I have to check for transtable changes only if the OGM has been
* sent through a primary interface */
if
(((
batman_packet
->
orig
!=
ethhdr
->
h_source
)
&&
(
batman_packet
->
ttl
>
2
))
||
(
batman_packet
->
flags
&
PRIMARIES_FIRST_HOP
))
tt_update_orig
(
bat_priv
,
orig_node
,
tt_buff
,
batman_packet
->
tt_num_changes
,
batman_packet
->
ttvn
,
batman_packet
->
tt_crc
);
if
(
orig_node
->
gw_flags
!=
batman_packet
->
gw_flags
)
gw_node_update
(
bat_priv
,
orig_node
,
batman_packet
->
gw_flags
);
orig_node
->
gw_flags
=
batman_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
))
gw_check_election
(
bat_priv
,
orig_node
);
goto
out
;
unlock:
rcu_read_unlock
();
out:
if
(
neigh_node
)
neigh_node_free_ref
(
neigh_node
);
if
(
router
)
neigh_node_free_ref
(
router
);
}
/* checks whether the host restarted and is in the protection time.
* returns:
* 0 if the packet is to be accepted
* 1 if the packet is to be ignored.
*/
static
int
window_protected
(
struct
bat_priv
*
bat_priv
,
int32_t
seq_num_diff
,
unsigned
long
*
last_reset
)
int
window_protected
(
struct
bat_priv
*
bat_priv
,
int32_t
seq_num_diff
,
unsigned
long
*
last_reset
)
{
if
((
seq_num_diff
<=
-
TQ_LOCAL_WINDOW_SIZE
)
||
(
seq_num_diff
>=
EXPECTED_SEQNO_RANGE
))
{
...
...
@@ -491,330 +246,12 @@ static int window_protected(struct bat_priv *bat_priv,
return
0
;
}
/* 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.
*/
static
int
count_real_packets
(
const
struct
ethhdr
*
ethhdr
,
const
struct
batman_packet
*
batman_packet
,
const
struct
hard_iface
*
if_incoming
)
{
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
;
orig_node
=
get_orig_node
(
bat_priv
,
batman_packet
->
orig
);
if
(
!
orig_node
)
return
0
;
spin_lock_bh
(
&
orig_node
->
ogm_cnt_lock
);
seq_diff
=
batman_packet
->
seqno
-
orig_node
->
last_real_seqno
;
/* signalize caller that the packet is to be dropped. */
if
(
window_protected
(
bat_priv
,
seq_diff
,
&
orig_node
->
batman_seqno_reset
))
goto
out
;
rcu_read_lock
();
hlist_for_each_entry_rcu
(
tmp_neigh_node
,
node
,
&
orig_node
->
neigh_list
,
list
)
{
is_duplicate
|=
get_bit_status
(
tmp_neigh_node
->
real_bits
,
orig_node
->
last_real_seqno
,
batman_packet
->
seqno
);
if
(
compare_eth
(
tmp_neigh_node
->
addr
,
ethhdr
->
h_source
)
&&
(
tmp_neigh_node
->
if_incoming
==
if_incoming
))
set_mark
=
1
;
else
set_mark
=
0
;
/* if the window moved, set the update flag. */
need_update
|=
bit_get_packet
(
bat_priv
,
tmp_neigh_node
->
real_bits
,
seq_diff
,
set_mark
);
tmp_neigh_node
->
real_packet_count
=
bit_packet_count
(
tmp_neigh_node
->
real_bits
);
}
rcu_read_unlock
();
if
(
need_update
)
{
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"updating last_seqno: old %d, new %d
\n
"
,
orig_node
->
last_real_seqno
,
batman_packet
->
seqno
);
orig_node
->
last_real_seqno
=
batman_packet
->
seqno
;
}
ret
=
is_duplicate
;
out:
spin_unlock_bh
(
&
orig_node
->
ogm_cnt_lock
);
orig_node_free_ref
(
orig_node
);
return
ret
;
}
void
receive_bat_packet
(
const
struct
ethhdr
*
ethhdr
,
struct
batman_packet
*
batman_packet
,
const
unsigned
char
*
tt_buff
,
struct
hard_iface
*
if_incoming
)
{
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
;
int
is_broadcast
=
0
,
is_bidirectional
,
is_single_hop_neigh
;
int
is_duplicate
;
uint32_t
if_incoming_seqno
;
/* 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_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)
*/
if
(
batman_packet
->
packet_type
!=
BAT_PACKET
)
return
;
/* could be changed by schedule_own_packet() */
if_incoming_seqno
=
atomic_read
(
&
if_incoming
->
seqno
);
has_directlink_flag
=
(
batman_packet
->
flags
&
DIRECTLINK
?
1
:
0
);
is_single_hop_neigh
=
(
compare_eth
(
ethhdr
->
h_source
,
batman_packet
->
orig
)
?
1
:
0
);
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"Received BATMAN packet via NB: %pM, IF: %s [%pM] "
"(from OG: %pM, via prev OG: %pM, seqno %d, 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_packet
->
orig
,
batman_packet
->
prev_sender
,
batman_packet
->
seqno
,
batman_packet
->
ttvn
,
batman_packet
->
tt_crc
,
batman_packet
->
tt_num_changes
,
batman_packet
->
tq
,
batman_packet
->
ttl
,
batman_packet
->
version
,
has_directlink_flag
);
rcu_read_lock
();
list_for_each_entry_rcu
(
hard_iface
,
&
hardif_list
,
list
)
{
if
(
hard_iface
->
if_status
!=
IF_ACTIVE
)
continue
;
if
(
hard_iface
->
soft_iface
!=
if_incoming
->
soft_iface
)
continue
;
if
(
compare_eth
(
ethhdr
->
h_source
,
hard_iface
->
net_dev
->
dev_addr
))
is_my_addr
=
1
;
if
(
compare_eth
(
batman_packet
->
orig
,
hard_iface
->
net_dev
->
dev_addr
))
is_my_orig
=
1
;
if
(
compare_eth
(
batman_packet
->
prev_sender
,
hard_iface
->
net_dev
->
dev_addr
))
is_my_oldorig
=
1
;
if
(
is_broadcast_ether_addr
(
ethhdr
->
h_source
))
is_broadcast
=
1
;
}
rcu_read_unlock
();
if
(
batman_packet
->
version
!=
COMPAT_VERSION
)
{
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"Drop packet: incompatible batman version (%i)
\n
"
,
batman_packet
->
version
);
return
;
}
if
(
is_my_addr
)
{
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"Drop packet: received my own broadcast (sender: %pM"
")
\n
"
,
ethhdr
->
h_source
);
return
;
}
if
(
is_broadcast
)
{
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"Drop packet: "
"ignoring all packets with broadcast source addr (sender: %pM"
")
\n
"
,
ethhdr
->
h_source
);
return
;
}
if
(
is_my_orig
)
{
unsigned
long
*
word
;
int
offset
;
orig_neigh_node
=
get_orig_node
(
bat_priv
,
ethhdr
->
h_source
);
if
(
!
orig_neigh_node
)
return
;
/* neighbor has to indicate direct link and it has to
* come via the corresponding interface */
/* save packet seqno for bidirectional check */
if
(
has_directlink_flag
&&
compare_eth
(
if_incoming
->
net_dev
->
dev_addr
,
batman_packet
->
orig
))
{
offset
=
if_incoming
->
if_num
*
NUM_WORDS
;
spin_lock_bh
(
&
orig_neigh_node
->
ogm_cnt_lock
);
word
=
&
(
orig_neigh_node
->
bcast_own
[
offset
]);
bit_mark
(
word
,
if_incoming_seqno
-
batman_packet
->
seqno
-
2
);
orig_neigh_node
->
bcast_own_sum
[
if_incoming
->
if_num
]
=
bit_packet_count
(
word
);
spin_unlock_bh
(
&
orig_neigh_node
->
ogm_cnt_lock
);
}
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"Drop packet: "
"originator packet from myself (via neighbor)
\n
"
);
orig_node_free_ref
(
orig_neigh_node
);
return
;
}
if
(
is_my_oldorig
)
{
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"Drop packet: ignoring all rebroadcast echos (sender: "
"%pM)
\n
"
,
ethhdr
->
h_source
);
return
;
}
orig_node
=
get_orig_node
(
bat_priv
,
batman_packet
->
orig
);
if
(
!
orig_node
)
return
;
is_duplicate
=
count_real_packets
(
ethhdr
,
batman_packet
,
if_incoming
);
if
(
is_duplicate
==
-
1
)
{
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"Drop packet: packet within seqno protection time "
"(sender: %pM)
\n
"
,
ethhdr
->
h_source
);
goto
out
;
}
if
(
batman_packet
->
tq
==
0
)
{
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"Drop packet: originator packet with tq equal 0
\n
"
);
goto
out
;
}
router
=
orig_node_get_router
(
orig_node
);
if
(
router
)
router_router
=
orig_node_get_router
(
router
->
orig_node
);
/* avoid temporary routing loops */
if
(
router
&&
router_router
&&
(
compare_eth
(
router
->
addr
,
batman_packet
->
prev_sender
))
&&
!
(
compare_eth
(
batman_packet
->
orig
,
batman_packet
->
prev_sender
))
&&
(
compare_eth
(
router
->
addr
,
router_router
->
addr
)))
{
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"Drop packet: ignoring all rebroadcast packets that "
"may make me loop (sender: %pM)
\n
"
,
ethhdr
->
h_source
);
goto
out
;
}
/* if sender is a direct neighbor the sender mac equals
* originator mac */
orig_neigh_node
=
(
is_single_hop_neigh
?
orig_node
:
get_orig_node
(
bat_priv
,
ethhdr
->
h_source
));
if
(
!
orig_neigh_node
)
goto
out
;
orig_neigh_router
=
orig_node_get_router
(
orig_neigh_node
);
/* drop packet if sender is not a direct neighbor and if we
* don't route towards it */
if
(
!
is_single_hop_neigh
&&
(
!
orig_neigh_router
))
{
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"Drop packet: OGM via unknown neighbor!
\n
"
);
goto
out_neigh
;
}
is_bidirectional
=
is_bidirectional_neigh
(
orig_node
,
orig_neigh_node
,
batman_packet
,
if_incoming
);
bonding_save_primary
(
orig_node
,
orig_neigh_node
,
batman_packet
);
/* update ranking if it is not a duplicate or has the same
* seqno and similar ttl as the non-duplicate */
if
(
is_bidirectional
&&
(
!
is_duplicate
||
((
orig_node
->
last_real_seqno
==
batman_packet
->
seqno
)
&&
(
orig_node
->
last_ttl
-
3
<=
batman_packet
->
ttl
))))
update_orig
(
bat_priv
,
orig_node
,
ethhdr
,
batman_packet
,
if_incoming
,
tt_buff
,
is_duplicate
);
/* is single hop (direct) neighbor */
if
(
is_single_hop_neigh
)
{
/* mark direct link on incoming interface */
schedule_forward_packet
(
orig_node
,
ethhdr
,
batman_packet
,
1
,
if_incoming
);
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"Forwarding packet: "
"rebroadcast neighbor packet with direct link flag
\n
"
);
goto
out_neigh
;
}
/* multihop originator */
if
(
!
is_bidirectional
)
{
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"Drop packet: not received via bidirectional link
\n
"
);
goto
out_neigh
;
}
if
(
is_duplicate
)
{
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"Drop packet: duplicate packet received
\n
"
);
goto
out_neigh
;
}
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"Forwarding packet: rebroadcast originator packet
\n
"
);
schedule_forward_packet
(
orig_node
,
ethhdr
,
batman_packet
,
0
,
if_incoming
);
out_neigh:
if
((
orig_neigh_node
)
&&
(
!
is_single_hop_neigh
))
orig_node_free_ref
(
orig_neigh_node
);
out:
if
(
router
)
neigh_node_free_ref
(
router
);
if
(
router_router
)
neigh_node_free_ref
(
router_router
);
if
(
orig_neigh_router
)
neigh_node_free_ref
(
orig_neigh_router
);
orig_node_free_ref
(
orig_node
);
}
int
recv_bat_packet
(
struct
sk_buff
*
skb
,
struct
hard_iface
*
hard_iface
)
int
recv_bat_ogm_packet
(
struct
sk_buff
*
skb
,
struct
hard_iface
*
hard_iface
)
{
struct
ethhdr
*
ethhdr
;
/* drop packet if it has not necessary minimum size */
if
(
unlikely
(
!
pskb_may_pull
(
skb
,
sizeof
(
struct
batman_packet
)
)))
if
(
unlikely
(
!
pskb_may_pull
(
skb
,
BATMAN_OGM_LEN
)))
return
NET_RX_DROP
;
ethhdr
=
(
struct
ethhdr
*
)
skb_mac_header
(
skb
);
...
...
@@ -837,10 +274,7 @@ int recv_bat_packet(struct sk_buff *skb, struct hard_iface *hard_iface)
ethhdr
=
(
struct
ethhdr
*
)
skb_mac_header
(
skb
);
receive_aggr_bat_packet
(
ethhdr
,
skb
->
data
,
skb_headlen
(
skb
),
hard_iface
);
bat_ogm_receive
(
ethhdr
,
skb
->
data
,
skb_headlen
(
skb
),
hard_iface
);
kfree_skb
(
skb
);
return
NET_RX_SUCCESS
;
...
...
net/batman-adv/routing.h
View file @
0c070900
...
...
@@ -23,19 +23,15 @@
#define _NET_BATMAN_ADV_ROUTING_H_
void
slide_own_bcast_window
(
struct
hard_iface
*
hard_iface
);
void
receive_bat_packet
(
const
struct
ethhdr
*
ethhdr
,
struct
batman_packet
*
batman_packet
,
const
unsigned
char
*
tt_buff
,
struct
hard_iface
*
if_incoming
);
void
update_routes
(
struct
bat_priv
*
bat_priv
,
struct
orig_node
*
orig_node
,
struct
neigh_node
*
neigh_node
);
void
update_route
(
struct
bat_priv
*
bat_priv
,
struct
orig_node
*
orig_node
,
struct
neigh_node
*
neigh_node
);
int
route_unicast_packet
(
struct
sk_buff
*
skb
,
struct
hard_iface
*
recv_if
);
int
recv_icmp_packet
(
struct
sk_buff
*
skb
,
struct
hard_iface
*
recv_if
);
int
recv_unicast_packet
(
struct
sk_buff
*
skb
,
struct
hard_iface
*
recv_if
);
int
recv_ucast_frag_packet
(
struct
sk_buff
*
skb
,
struct
hard_iface
*
recv_if
);
int
recv_bcast_packet
(
struct
sk_buff
*
skb
,
struct
hard_iface
*
recv_if
);
int
recv_vis_packet
(
struct
sk_buff
*
skb
,
struct
hard_iface
*
recv_if
);
int
recv_bat_packet
(
struct
sk_buff
*
skb
,
struct
hard_iface
*
recv_if
);
int
recv_bat_
ogm_
packet
(
struct
sk_buff
*
skb
,
struct
hard_iface
*
recv_if
);
int
recv_tt_query
(
struct
sk_buff
*
skb
,
struct
hard_iface
*
recv_if
);
int
recv_roam_adv
(
struct
sk_buff
*
skb
,
struct
hard_iface
*
recv_if
);
struct
neigh_node
*
find_router
(
struct
bat_priv
*
bat_priv
,
...
...
@@ -43,5 +39,12 @@ struct neigh_node *find_router(struct bat_priv *bat_priv,
const
struct
hard_iface
*
recv_if
);
void
bonding_candidate_del
(
struct
orig_node
*
orig_node
,
struct
neigh_node
*
neigh_node
);
void
bonding_candidate_add
(
struct
orig_node
*
orig_node
,
struct
neigh_node
*
neigh_node
);
void
bonding_save_primary
(
const
struct
orig_node
*
orig_node
,
struct
orig_node
*
orig_neigh_node
,
const
struct
batman_ogm_packet
*
batman_ogm_packet
);
int
window_protected
(
struct
bat_priv
*
bat_priv
,
int32_t
seq_num_diff
,
unsigned
long
*
last_reset
);
#endif
/* _NET_BATMAN_ADV_ROUTING_H_ */
net/batman-adv/send.c
View file @
0c070900
...
...
@@ -26,33 +26,12 @@
#include "soft-interface.h"
#include "hard-interface.h"
#include "vis.h"
#include "aggregation.h"
#include "gateway_common.h"
#include "originator.h"
#include "bat_ogm.h"
static
void
send_outstanding_bcast_packet
(
struct
work_struct
*
work
);
/* apply hop penalty for a normal link */
static
uint8_t
hop_penalty
(
uint8_t
tq
,
const
struct
bat_priv
*
bat_priv
)
{
int
hop_penalty
=
atomic_read
(
&
bat_priv
->
hop_penalty
);
return
(
tq
*
(
TQ_MAX_VALUE
-
hop_penalty
))
/
(
TQ_MAX_VALUE
);
}
/* when do we schedule our own packet to be sent */
static
unsigned
long
own_send_time
(
const
struct
bat_priv
*
bat_priv
)
{
return
jiffies
+
msecs_to_jiffies
(
atomic_read
(
&
bat_priv
->
orig_interval
)
-
JITTER
+
(
random32
()
%
2
*
JITTER
));
}
/* when do we schedule a forwarded packet to be sent */
static
unsigned
long
forward_send_time
(
void
)
{
return
jiffies
+
msecs_to_jiffies
(
random32
()
%
(
JITTER
/
2
));
}
/* send out an already prepared packet to the given address via the
* specified batman interface */
int
send_skb_packet
(
struct
sk_buff
*
skb
,
struct
hard_iface
*
hard_iface
,
...
...
@@ -99,141 +78,17 @@ int send_skb_packet(struct sk_buff *skb, struct hard_iface *hard_iface,
return
NET_XMIT_DROP
;
}
/* Send a packet to a given interface */
static
void
send_packet_to_if
(
struct
forw_packet
*
forw_packet
,
struct
hard_iface
*
hard_iface
)
{
struct
bat_priv
*
bat_priv
=
netdev_priv
(
hard_iface
->
soft_iface
);
char
*
fwd_str
;
uint8_t
packet_num
;
int16_t
buff_pos
;
struct
batman_packet
*
batman_packet
;
struct
sk_buff
*
skb
;
if
(
hard_iface
->
if_status
!=
IF_ACTIVE
)
return
;
packet_num
=
0
;
buff_pos
=
0
;
batman_packet
=
(
struct
batman_packet
*
)
forw_packet
->
skb
->
data
;
/* adjust all flags and log packets */
while
(
aggregated_packet
(
buff_pos
,
forw_packet
->
packet_len
,
batman_packet
->
tt_num_changes
))
{
/* we might have aggregated direct link packets with an
* ordinary base packet */
if
((
forw_packet
->
direct_link_flags
&
(
1
<<
packet_num
))
&&
(
forw_packet
->
if_incoming
==
hard_iface
))
batman_packet
->
flags
|=
DIRECTLINK
;
else
batman_packet
->
flags
&=
~
DIRECTLINK
;
fwd_str
=
(
packet_num
>
0
?
"Forwarding"
:
(
forw_packet
->
own
?
"Sending own"
:
"Forwarding"
));
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"%s %spacket (originator %pM, seqno %d, TQ %d, TTL %d,"
" IDF %s, ttvn %d) on interface %s [%pM]
\n
"
,
fwd_str
,
(
packet_num
>
0
?
"aggregated "
:
""
),
batman_packet
->
orig
,
ntohl
(
batman_packet
->
seqno
),
batman_packet
->
tq
,
batman_packet
->
ttl
,
(
batman_packet
->
flags
&
DIRECTLINK
?
"on"
:
"off"
),
batman_packet
->
ttvn
,
hard_iface
->
net_dev
->
name
,
hard_iface
->
net_dev
->
dev_addr
);
buff_pos
+=
sizeof
(
*
batman_packet
)
+
tt_len
(
batman_packet
->
tt_num_changes
);
packet_num
++
;
batman_packet
=
(
struct
batman_packet
*
)
(
forw_packet
->
skb
->
data
+
buff_pos
);
}
/* create clone because function is called more than once */
skb
=
skb_clone
(
forw_packet
->
skb
,
GFP_ATOMIC
);
if
(
skb
)
send_skb_packet
(
skb
,
hard_iface
,
broadcast_addr
);
}
/* send a batman packet */
static
void
send_packet
(
struct
forw_packet
*
forw_packet
)
{
struct
hard_iface
*
hard_iface
;
struct
net_device
*
soft_iface
;
struct
bat_priv
*
bat_priv
;
struct
hard_iface
*
primary_if
=
NULL
;
struct
batman_packet
*
batman_packet
=
(
struct
batman_packet
*
)(
forw_packet
->
skb
->
data
);
int
directlink
=
(
batman_packet
->
flags
&
DIRECTLINK
?
1
:
0
);
if
(
!
forw_packet
->
if_incoming
)
{
pr_err
(
"Error - can't forward packet: incoming iface not "
"specified
\n
"
);
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
;
primary_if
=
primary_if_get_selected
(
bat_priv
);
if
(
!
primary_if
)
goto
out
;
/* multihomed peer assumed */
/* non-primary OGMs are only broadcasted on their interface */
if
((
directlink
&&
(
batman_packet
->
ttl
==
1
))
||
(
forw_packet
->
own
&&
(
forw_packet
->
if_incoming
!=
primary_if
)))
{
/* FIXME: what about aggregated packets ? */
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"%s packet (originator %pM, seqno %d, TTL %d) "
"on interface %s [%pM]
\n
"
,
(
forw_packet
->
own
?
"Sending own"
:
"Forwarding"
),
batman_packet
->
orig
,
ntohl
(
batman_packet
->
seqno
),
batman_packet
->
ttl
,
forw_packet
->
if_incoming
->
net_dev
->
name
,
forw_packet
->
if_incoming
->
net_dev
->
dev_addr
);
/* skb is only used once and than forw_packet is free'd */
send_skb_packet
(
forw_packet
->
skb
,
forw_packet
->
if_incoming
,
broadcast_addr
);
forw_packet
->
skb
=
NULL
;
goto
out
;
}
/* broadcast on every interface */
rcu_read_lock
();
list_for_each_entry_rcu
(
hard_iface
,
&
hardif_list
,
list
)
{
if
(
hard_iface
->
soft_iface
!=
soft_iface
)
continue
;
send_packet_to_if
(
forw_packet
,
hard_iface
);
}
rcu_read_unlock
();
out:
if
(
primary_if
)
hardif_free_ref
(
primary_if
);
}
static
void
realloc_packet_buffer
(
struct
hard_iface
*
hard_iface
,
int
new_len
)
int
new_len
)
{
unsigned
char
*
new_buff
;
struct
batman_packet
*
batman_packet
;
new_buff
=
kmalloc
(
new_len
,
GFP_ATOMIC
);
/* keep old buffer if kmalloc should fail */
if
(
new_buff
)
{
memcpy
(
new_buff
,
hard_iface
->
packet_buff
,
sizeof
(
*
batman_packet
)
);
BATMAN_OGM_LEN
);
kfree
(
hard_iface
->
packet_buff
);
hard_iface
->
packet_buff
=
new_buff
;
...
...
@@ -242,60 +97,48 @@ static void realloc_packet_buffer(struct hard_iface *hard_iface,
}
/* when calling this function (hard_iface == primary_if) has to be true */
static
void
prepare_packet_buffer
(
struct
bat_priv
*
bat_priv
,
static
int
prepare_packet_buffer
(
struct
bat_priv
*
bat_priv
,
struct
hard_iface
*
hard_iface
)
{
int
new_len
;
struct
batman_packet
*
batman_packet
;
new_len
=
BAT
_PACKET
_LEN
+
new_len
=
BAT
MAN_OGM
_LEN
+
tt_len
((
uint8_t
)
atomic_read
(
&
bat_priv
->
tt_local_changes
));
/* if we have too many changes for one packet don't send any
* and wait for the tt table request which will be fragmented */
if
(
new_len
>
hard_iface
->
soft_iface
->
mtu
)
new_len
=
BAT
_PACKET
_LEN
;
new_len
=
BAT
MAN_OGM
_LEN
;
realloc_packet_buffer
(
hard_iface
,
new_len
);
batman_packet
=
(
struct
batman_packet
*
)
hard_iface
->
packet_buff
;
atomic_set
(
&
bat_priv
->
tt_crc
,
tt_local_crc
(
bat_priv
));
/* reset the sending counter */
atomic_set
(
&
bat_priv
->
tt_ogm_append_cnt
,
TT_OGM_APPEND_MAX
);
batman_packet
->
tt_num_changes
=
tt_changes_fill_buffer
(
bat_priv
,
hard_iface
->
packet_buff
+
BAT_PACKET_LEN
,
hard_iface
->
packet_len
-
BAT_PACKET_LEN
);
return
tt_changes_fill_buffer
(
bat_priv
,
hard_iface
->
packet_buff
+
BATMAN_OGM_LEN
,
hard_iface
->
packet_len
-
BATMAN_OGM_LEN
);
}
static
void
reset_packet_buffer
(
struct
bat_priv
*
bat_priv
,
struct
hard_iface
*
hard_iface
)
static
int
reset_packet_buffer
(
struct
bat_priv
*
bat_priv
,
struct
hard_iface
*
hard_iface
)
{
struct
batman_packet
*
batman_packet
;
realloc_packet_buffer
(
hard_iface
,
BAT_PACKET_LEN
);
batman_packet
=
(
struct
batman_packet
*
)
hard_iface
->
packet_buff
;
batman_packet
->
tt_num_changes
=
0
;
realloc_packet_buffer
(
hard_iface
,
BATMAN_OGM_LEN
);
return
0
;
}
void
schedule_
own_packet
(
struct
hard_iface
*
hard_iface
)
void
schedule_
bat_ogm
(
struct
hard_iface
*
hard_iface
)
{
struct
bat_priv
*
bat_priv
=
netdev_priv
(
hard_iface
->
soft_iface
);
struct
hard_iface
*
primary_if
;
unsigned
long
send_time
;
struct
batman_packet
*
batman_packet
;
int
vis_server
;
int
tt_num_changes
=
-
1
;
if
((
hard_iface
->
if_status
==
IF_NOT_IN_USE
)
||
(
hard_iface
->
if_status
==
IF_TO_BE_REMOVED
))
return
;
vis_server
=
atomic_read
(
&
bat_priv
->
vis_mode
);
primary_if
=
primary_if_get_selected
(
bat_priv
);
/**
* the interface gets activated here to avoid race conditions between
* the moment of activating the interface in
...
...
@@ -306,124 +149,26 @@ void schedule_own_packet(struct hard_iface *hard_iface)
if
(
hard_iface
->
if_status
==
IF_TO_BE_ACTIVATED
)
hard_iface
->
if_status
=
IF_ACTIVE
;
primary_if
=
primary_if_get_selected
(
bat_priv
);
if
(
hard_iface
==
primary_if
)
{
/* if at least one change happened */
if
(
atomic_read
(
&
bat_priv
->
tt_local_changes
)
>
0
)
{
tt_commit_changes
(
bat_priv
);
prepare_packet_buffer
(
bat_priv
,
hard_iface
);
tt_num_changes
=
prepare_packet_buffer
(
bat_priv
,
hard_iface
);
}
/* if the changes have been sent often enough */
if
(
!
atomic_dec_not_zero
(
&
bat_priv
->
tt_ogm_append_cnt
))
reset_packet_buffer
(
bat_priv
,
hard_iface
);
tt_num_changes
=
reset_packet_buffer
(
bat_priv
,
hard_iface
);
}
/**
* NOTE: packet_buff might just have been re-allocated in
* prepare_packet_buffer() or in reset_packet_buffer()
*/
batman_packet
=
(
struct
batman_packet
*
)
hard_iface
->
packet_buff
;
/* change sequence number to network order */
batman_packet
->
seqno
=
htonl
((
uint32_t
)
atomic_read
(
&
hard_iface
->
seqno
));
batman_packet
->
ttvn
=
atomic_read
(
&
bat_priv
->
ttvn
);
batman_packet
->
tt_crc
=
htons
((
uint16_t
)
atomic_read
(
&
bat_priv
->
tt_crc
));
if
(
vis_server
==
VIS_TYPE_SERVER_SYNC
)
batman_packet
->
flags
|=
VIS_SERVER
;
else
batman_packet
->
flags
&=
~
VIS_SERVER
;
if
((
hard_iface
==
primary_if
)
&&
(
atomic_read
(
&
bat_priv
->
gw_mode
)
==
GW_MODE_SERVER
))
batman_packet
->
gw_flags
=
(
uint8_t
)
atomic_read
(
&
bat_priv
->
gw_bandwidth
);
else
batman_packet
->
gw_flags
=
NO_FLAGS
;
atomic_inc
(
&
hard_iface
->
seqno
);
slide_own_bcast_window
(
hard_iface
);
send_time
=
own_send_time
(
bat_priv
);
add_bat_packet_to_list
(
bat_priv
,
hard_iface
->
packet_buff
,
hard_iface
->
packet_len
,
hard_iface
,
1
,
send_time
);
if
(
primary_if
)
hardif_free_ref
(
primary_if
);
}
void
schedule_forward_packet
(
struct
orig_node
*
orig_node
,
const
struct
ethhdr
*
ethhdr
,
struct
batman_packet
*
batman_packet
,
int
directlink
,
struct
hard_iface
*
if_incoming
)
{
struct
bat_priv
*
bat_priv
=
netdev_priv
(
if_incoming
->
soft_iface
);
struct
neigh_node
*
router
;
uint8_t
in_tq
,
in_ttl
,
tq_avg
=
0
;
unsigned
long
send_time
;
uint8_t
tt_num_changes
;
if
(
batman_packet
->
ttl
<=
1
)
{
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"ttl exceeded
\n
"
);
return
;
}
router
=
orig_node_get_router
(
orig_node
);
in_tq
=
batman_packet
->
tq
;
in_ttl
=
batman_packet
->
ttl
;
tt_num_changes
=
batman_packet
->
tt_num_changes
;
batman_packet
->
ttl
--
;
memcpy
(
batman_packet
->
prev_sender
,
ethhdr
->
h_source
,
ETH_ALEN
);
/* rebroadcast tq of our best ranking neighbor to ensure the rebroadcast
* of our best tq value */
if
(
router
&&
router
->
tq_avg
!=
0
)
{
/* rebroadcast ogm of best ranking neighbor as is */
if
(
!
compare_eth
(
router
->
addr
,
ethhdr
->
h_source
))
{
batman_packet
->
tq
=
router
->
tq_avg
;
if
(
router
->
last_ttl
)
batman_packet
->
ttl
=
router
->
last_ttl
-
1
;
}
tq_avg
=
router
->
tq_avg
;
}
if
(
router
)
neigh_node_free_ref
(
router
);
/* apply hop penalty */
batman_packet
->
tq
=
hop_penalty
(
batman_packet
->
tq
,
bat_priv
);
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"Forwarding packet: tq_orig: %i, tq_avg: %i, "
"tq_forw: %i, ttl_orig: %i, ttl_forw: %i
\n
"
,
in_tq
,
tq_avg
,
batman_packet
->
tq
,
in_ttl
-
1
,
batman_packet
->
ttl
);
batman_packet
->
seqno
=
htonl
(
batman_packet
->
seqno
);
batman_packet
->
tt_crc
=
htons
(
batman_packet
->
tt_crc
);
/* switch of primaries first hop flag when forwarding */
batman_packet
->
flags
&=
~
PRIMARIES_FIRST_HOP
;
if
(
directlink
)
batman_packet
->
flags
|=
DIRECTLINK
;
else
batman_packet
->
flags
&=
~
DIRECTLINK
;
send_time
=
forward_send_time
();
add_bat_packet_to_list
(
bat_priv
,
(
unsigned
char
*
)
batman_packet
,
sizeof
(
*
batman_packet
)
+
tt_len
(
tt_num_changes
),
if_incoming
,
0
,
send_time
);
bat_ogm_schedule
(
hard_iface
,
tt_num_changes
);
}
static
void
forw_packet_free
(
struct
forw_packet
*
forw_packet
)
...
...
@@ -557,7 +302,7 @@ static void send_outstanding_bcast_packet(struct work_struct *work)
atomic_inc
(
&
bat_priv
->
bcast_queue_left
);
}
void
send_outstanding_bat_packet
(
struct
work_struct
*
work
)
void
send_outstanding_bat_
ogm_
packet
(
struct
work_struct
*
work
)
{
struct
delayed_work
*
delayed_work
=
container_of
(
work
,
struct
delayed_work
,
work
);
...
...
@@ -573,7 +318,7 @@ void send_outstanding_bat_packet(struct work_struct *work)
if
(
atomic_read
(
&
bat_priv
->
mesh_state
)
==
MESH_DEACTIVATING
)
goto
out
;
send_packe
t
(
forw_packet
);
bat_ogm_emi
t
(
forw_packet
);
/**
* we have to have at least one packet in the queue
...
...
@@ -581,7 +326,7 @@ void send_outstanding_bat_packet(struct work_struct *work)
* shutting down
*/
if
(
forw_packet
->
own
)
schedule_
own_packet
(
forw_packet
->
if_incoming
);
schedule_
bat_ogm
(
forw_packet
->
if_incoming
);
out:
/* don't count own packet */
...
...
net/batman-adv/send.h
View file @
0c070900
...
...
@@ -24,15 +24,10 @@
int
send_skb_packet
(
struct
sk_buff
*
skb
,
struct
hard_iface
*
hard_iface
,
const
uint8_t
*
dst_addr
);
void
schedule_own_packet
(
struct
hard_iface
*
hard_iface
);
void
schedule_forward_packet
(
struct
orig_node
*
orig_node
,
const
struct
ethhdr
*
ethhdr
,
struct
batman_packet
*
batman_packet
,
int
directlink
,
struct
hard_iface
*
if_outgoing
);
void
schedule_bat_ogm
(
struct
hard_iface
*
hard_iface
);
int
add_bcast_packet_to_list
(
struct
bat_priv
*
bat_priv
,
const
struct
sk_buff
*
skb
,
unsigned
long
delay
);
void
send_outstanding_bat_packet
(
struct
work_struct
*
work
);
void
send_outstanding_bat_
ogm_
packet
(
struct
work_struct
*
work
);
void
purge_outstanding_packets
(
struct
bat_priv
*
bat_priv
,
const
struct
hard_iface
*
hard_iface
);
...
...
net/batman-adv/soft-interface.c
View file @
0c070900
...
...
@@ -445,30 +445,31 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev,
{
struct
bat_priv
*
bat_priv
=
netdev_priv
(
dev
);
struct
ethhdr
*
ethhdr
=
(
struct
ethhdr
*
)
skb
->
data
;
struct
batman_
packet
*
batman
_packet
;
struct
batman_
ogm_packet
*
batman_ogm
_packet
;
struct
softif_neigh
*
softif_neigh
=
NULL
;
struct
hard_iface
*
primary_if
=
NULL
;
struct
softif_neigh
*
curr_softif_neigh
=
NULL
;
if
(
ntohs
(
ethhdr
->
h_proto
)
==
ETH_P_8021Q
)
batman_
packet
=
(
struct
batman
_packet
*
)
batman_
ogm_packet
=
(
struct
batman_ogm
_packet
*
)
(
skb
->
data
+
ETH_HLEN
+
VLAN_HLEN
);
else
batman_packet
=
(
struct
batman_packet
*
)(
skb
->
data
+
ETH_HLEN
);
batman_ogm_packet
=
(
struct
batman_ogm_packet
*
)
(
skb
->
data
+
ETH_HLEN
);
if
(
batman_packet
->
version
!=
COMPAT_VERSION
)
if
(
batman_
ogm_
packet
->
version
!=
COMPAT_VERSION
)
goto
out
;
if
(
batman_
packet
->
packet_type
!=
BAT_PACKET
)
if
(
batman_
ogm_packet
->
packet_type
!=
BAT_OGM
)
goto
out
;
if
(
!
(
batman_packet
->
flags
&
PRIMARIES_FIRST_HOP
))
if
(
!
(
batman_
ogm_
packet
->
flags
&
PRIMARIES_FIRST_HOP
))
goto
out
;
if
(
is_my_mac
(
batman_packet
->
orig
))
if
(
is_my_mac
(
batman_
ogm_
packet
->
orig
))
goto
out
;
softif_neigh
=
softif_neigh_get
(
bat_priv
,
batman_packet
->
orig
,
vid
);
softif_neigh
=
softif_neigh_get
(
bat_priv
,
batman_
ogm_
packet
->
orig
,
vid
);
if
(
!
softif_neigh
)
goto
out
;
...
...
@@ -800,10 +801,8 @@ struct net_device *softif_create(const char *name)
soft_iface
=
alloc_netdev
(
sizeof
(
*
bat_priv
),
name
,
interface_setup
);
if
(
!
soft_iface
)
{
pr_err
(
"Unable to allocate the batman interface: %s
\n
"
,
name
);
if
(
!
soft_iface
)
goto
out
;
}
ret
=
register_netdevice
(
soft_iface
);
if
(
ret
<
0
)
{
...
...
net/batman-adv/vis.c
View file @
0c070900
...
...
@@ -887,10 +887,8 @@ int vis_init(struct bat_priv *bat_priv)
}
bat_priv
->
my_vis_info
=
kmalloc
(
MAX_VIS_PACKET_SIZE
,
GFP_ATOMIC
);
if
(
!
bat_priv
->
my_vis_info
)
{
pr_err
(
"Can't initialize vis packet
\n
"
);
if
(
!
bat_priv
->
my_vis_info
)
goto
err
;
}
bat_priv
->
my_vis_info
->
skb_packet
=
dev_alloc_skb
(
sizeof
(
*
packet
)
+
MAX_VIS_PACKET_SIZE
+
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment