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
Kirill Smelkov
linux
Commits
9c6bc165
Commit
9c6bc165
authored
Apr 17, 2011
by
David S. Miller
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'batman-adv/next' of
git://git.open-mesh.org/ecsv/linux-merge
parents
03746b0a
af20b710
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
537 additions
and
393 deletions
+537
-393
net/batman-adv/gateway_client.c
net/batman-adv/gateway_client.c
+151
-108
net/batman-adv/gateway_client.h
net/batman-adv/gateway_client.h
+1
-1
net/batman-adv/icmp_socket.c
net/batman-adv/icmp_socket.c
+3
-15
net/batman-adv/originator.c
net/batman-adv/originator.c
+29
-9
net/batman-adv/originator.h
net/batman-adv/originator.h
+1
-0
net/batman-adv/routing.c
net/batman-adv/routing.c
+202
-176
net/batman-adv/send.c
net/batman-adv/send.c
+12
-7
net/batman-adv/soft-interface.c
net/batman-adv/soft-interface.c
+88
-27
net/batman-adv/types.h
net/batman-adv/types.h
+4
-3
net/batman-adv/unicast.c
net/batman-adv/unicast.c
+1
-1
net/batman-adv/vis.c
net/batman-adv/vis.c
+45
-46
No files found.
net/batman-adv/gateway_client.c
View file @
9c6bc165
...
@@ -23,6 +23,7 @@
...
@@ -23,6 +23,7 @@
#include "gateway_client.h"
#include "gateway_client.h"
#include "gateway_common.h"
#include "gateway_common.h"
#include "hard-interface.h"
#include "hard-interface.h"
#include "originator.h"
#include <linux/ip.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/ipv6.h>
#include <linux/udp.h>
#include <linux/udp.h>
...
@@ -42,61 +43,76 @@ static void gw_node_free_ref(struct gw_node *gw_node)
...
@@ -42,61 +43,76 @@ static void gw_node_free_ref(struct gw_node *gw_node)
call_rcu
(
&
gw_node
->
rcu
,
gw_node_free_rcu
);
call_rcu
(
&
gw_node
->
rcu
,
gw_node_free_rcu
);
}
}
void
*
gw_get_selected
(
struct
bat_priv
*
bat_priv
)
static
struct
gw_node
*
gw_get_selected_gw_node
(
struct
bat_priv
*
bat_priv
)
{
{
struct
gw_node
*
curr_gateway_tmp
;
struct
gw_node
*
gw_node
;
struct
orig_node
*
orig_node
=
NULL
;
rcu_read_lock
();
rcu_read_lock
();
curr_gateway_tmp
=
rcu_dereference
(
bat_priv
->
curr_gw
);
gw_node
=
rcu_dereference
(
bat_priv
->
curr_gw
);
if
(
!
curr_gateway_tmp
)
if
(
!
gw_node
)
goto
out
;
orig_node
=
curr_gateway_tmp
->
orig_node
;
if
(
!
orig_node
)
goto
out
;
goto
out
;
if
(
!
atomic_inc_not_zero
(
&
orig
_node
->
refcount
))
if
(
!
atomic_inc_not_zero
(
&
gw
_node
->
refcount
))
orig
_node
=
NULL
;
gw
_node
=
NULL
;
out:
out:
rcu_read_unlock
();
rcu_read_unlock
();
return
orig
_node
;
return
gw
_node
;
}
}
void
gw_deselect
(
struct
bat_priv
*
bat_priv
)
struct
orig_node
*
gw_get_selected_orig
(
struct
bat_priv
*
bat_priv
)
{
{
struct
gw_node
*
gw_node
;
struct
gw_node
*
gw_node
;
struct
orig_node
*
orig_node
=
NULL
;
spin_lock_bh
(
&
bat_priv
->
gw_list_lock
);
gw_node
=
gw_get_selected_gw_node
(
bat_priv
);
gw_node
=
rcu_dereference
(
bat_priv
->
curr_gw
);
if
(
!
gw_node
)
rcu_assign_pointer
(
bat_priv
->
curr_gw
,
NULL
);
goto
out
;
spin_unlock_bh
(
&
bat_priv
->
gw_list_lock
);
rcu_read_lock
();
orig_node
=
gw_node
->
orig_node
;
if
(
!
orig_node
)
goto
unlock
;
if
(
!
atomic_inc_not_zero
(
&
orig_node
->
refcount
))
orig_node
=
NULL
;
unlock:
rcu_read_unlock
();
out:
if
(
gw_node
)
if
(
gw_node
)
gw_node_free_ref
(
gw_node
);
gw_node_free_ref
(
gw_node
);
return
orig_node
;
}
}
static
void
gw_select
(
struct
bat_priv
*
bat_priv
,
struct
gw_node
*
new_gw_node
)
static
void
gw_select
(
struct
bat_priv
*
bat_priv
,
struct
gw_node
*
new_gw_node
)
{
{
struct
gw_node
*
curr_gw_node
;
struct
gw_node
*
curr_gw_node
;
spin_lock_bh
(
&
bat_priv
->
gw_list_lock
);
if
(
new_gw_node
&&
!
atomic_inc_not_zero
(
&
new_gw_node
->
refcount
))
if
(
new_gw_node
&&
!
atomic_inc_not_zero
(
&
new_gw_node
->
refcount
))
new_gw_node
=
NULL
;
new_gw_node
=
NULL
;
spin_lock_bh
(
&
bat_priv
->
gw_list_lock
);
curr_gw_node
=
bat_priv
->
curr_gw
;
curr_gw_node
=
rcu_dereference
(
bat_priv
->
curr_gw
);
rcu_assign_pointer
(
bat_priv
->
curr_gw
,
new_gw_node
);
rcu_assign_pointer
(
bat_priv
->
curr_gw
,
new_gw_node
);
spin_unlock_bh
(
&
bat_priv
->
gw_list_lock
);
if
(
curr_gw_node
)
if
(
curr_gw_node
)
gw_node_free_ref
(
curr_gw_node
);
gw_node_free_ref
(
curr_gw_node
);
spin_unlock_bh
(
&
bat_priv
->
gw_list_lock
);
}
void
gw_deselect
(
struct
bat_priv
*
bat_priv
)
{
gw_select
(
bat_priv
,
NULL
);
}
}
void
gw_election
(
struct
bat_priv
*
bat_priv
)
void
gw_election
(
struct
bat_priv
*
bat_priv
)
{
{
struct
hlist_node
*
node
;
struct
hlist_node
*
node
;
struct
gw_node
*
gw_node
,
*
curr_gw
,
*
curr_gw_tmp
=
NULL
;
struct
gw_node
*
gw_node
,
*
curr_gw
=
NULL
,
*
curr_gw_tmp
=
NULL
;
struct
neigh_node
*
router
;
uint8_t
max_tq
=
0
;
uint8_t
max_tq
=
0
;
uint32_t
max_gw_factor
=
0
,
tmp_gw_factor
=
0
;
uint32_t
max_gw_factor
=
0
,
tmp_gw_factor
=
0
;
int
down
,
up
;
int
down
,
up
;
...
@@ -110,32 +126,25 @@ void gw_election(struct bat_priv *bat_priv)
...
@@ -110,32 +126,25 @@ void gw_election(struct bat_priv *bat_priv)
if
(
atomic_read
(
&
bat_priv
->
gw_mode
)
!=
GW_MODE_CLIENT
)
if
(
atomic_read
(
&
bat_priv
->
gw_mode
)
!=
GW_MODE_CLIENT
)
return
;
return
;
rcu_read_lock
();
curr_gw
=
gw_get_selected_gw_node
(
bat_priv
);
curr_gw
=
rcu_dereference
(
bat_priv
->
curr_gw
);
if
(
!
curr_gw
)
if
(
curr_gw
)
{
goto
out
;
rcu_read_unlock
();
return
;
}
rcu_read_lock
();
if
(
hlist_empty
(
&
bat_priv
->
gw_list
))
{
if
(
hlist_empty
(
&
bat_priv
->
gw_list
))
{
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
if
(
curr_gw
)
{
"Removing selected gateway - "
rcu_read_unlock
();
"no gateway in range
\n
"
);
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
gw_deselect
(
bat_priv
);
"Removing selected gateway - "
goto
unlock
;
"no gateway in range
\n
"
);
gw_deselect
(
bat_priv
);
}
else
rcu_read_unlock
();
return
;
}
}
hlist_for_each_entry_rcu
(
gw_node
,
node
,
&
bat_priv
->
gw_list
,
list
)
{
hlist_for_each_entry_rcu
(
gw_node
,
node
,
&
bat_priv
->
gw_list
,
list
)
{
if
(
!
gw_node
->
orig_node
->
router
)
if
(
gw_node
->
deleted
)
continue
;
continue
;
if
(
gw_node
->
deleted
)
router
=
orig_node_get_router
(
gw_node
->
orig_node
);
if
(
!
router
)
continue
;
continue
;
switch
(
atomic_read
(
&
bat_priv
->
gw_sel_class
))
{
switch
(
atomic_read
(
&
bat_priv
->
gw_sel_class
))
{
...
@@ -143,15 +152,14 @@ void gw_election(struct bat_priv *bat_priv)
...
@@ -143,15 +152,14 @@ void gw_election(struct bat_priv *bat_priv)
gw_bandwidth_to_kbit
(
gw_node
->
orig_node
->
gw_flags
,
gw_bandwidth_to_kbit
(
gw_node
->
orig_node
->
gw_flags
,
&
down
,
&
up
);
&
down
,
&
up
);
tmp_gw_factor
=
(
gw_node
->
orig_node
->
router
->
tq_avg
*
tmp_gw_factor
=
(
router
->
tq_avg
*
router
->
tq_avg
*
gw_node
->
orig_node
->
router
->
tq_avg
*
down
*
100
*
100
)
/
down
*
100
*
100
)
/
(
TQ_LOCAL_WINDOW_SIZE
*
(
TQ_LOCAL_WINDOW_SIZE
*
TQ_LOCAL_WINDOW_SIZE
*
64
);
TQ_LOCAL_WINDOW_SIZE
*
64
);
if
((
tmp_gw_factor
>
max_gw_factor
)
||
if
((
tmp_gw_factor
>
max_gw_factor
)
||
((
tmp_gw_factor
==
max_gw_factor
)
&&
((
tmp_gw_factor
==
max_gw_factor
)
&&
(
gw_node
->
orig_node
->
router
->
tq_avg
>
max_tq
)))
(
router
->
tq_avg
>
max_tq
)))
curr_gw_tmp
=
gw_node
;
curr_gw_tmp
=
gw_node
;
break
;
break
;
...
@@ -163,19 +171,25 @@ void gw_election(struct bat_priv *bat_priv)
...
@@ -163,19 +171,25 @@ void gw_election(struct bat_priv *bat_priv)
* soon as a better gateway appears which has
* soon as a better gateway appears which has
* $routing_class more tq points)
* $routing_class more tq points)
**/
**/
if
(
gw_node
->
orig_node
->
router
->
tq_avg
>
max_tq
)
if
(
router
->
tq_avg
>
max_tq
)
curr_gw_tmp
=
gw_node
;
curr_gw_tmp
=
gw_node
;
break
;
break
;
}
}
if
(
gw_node
->
orig_node
->
router
->
tq_avg
>
max_tq
)
if
(
router
->
tq_avg
>
max_tq
)
max_tq
=
gw_node
->
orig_node
->
router
->
tq_avg
;
max_tq
=
router
->
tq_avg
;
if
(
tmp_gw_factor
>
max_gw_factor
)
if
(
tmp_gw_factor
>
max_gw_factor
)
max_gw_factor
=
tmp_gw_factor
;
max_gw_factor
=
tmp_gw_factor
;
neigh_node_free_ref
(
router
);
}
}
if
(
curr_gw
!=
curr_gw_tmp
)
{
if
(
curr_gw
!=
curr_gw_tmp
)
{
router
=
orig_node_get_router
(
curr_gw_tmp
->
orig_node
);
if
(
!
router
)
goto
unlock
;
if
((
curr_gw
)
&&
(
!
curr_gw_tmp
))
if
((
curr_gw
)
&&
(
!
curr_gw_tmp
))
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"Removing selected gateway - "
"Removing selected gateway - "
...
@@ -186,48 +200,50 @@ void gw_election(struct bat_priv *bat_priv)
...
@@ -186,48 +200,50 @@ void gw_election(struct bat_priv *bat_priv)
"(gw_flags: %i, tq: %i)
\n
"
,
"(gw_flags: %i, tq: %i)
\n
"
,
curr_gw_tmp
->
orig_node
->
orig
,
curr_gw_tmp
->
orig_node
->
orig
,
curr_gw_tmp
->
orig_node
->
gw_flags
,
curr_gw_tmp
->
orig_node
->
gw_flags
,
curr_gw_tmp
->
orig_node
->
router
->
tq_avg
);
router
->
tq_avg
);
else
else
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"Changing route to gateway %pM "
"Changing route to gateway %pM "
"(gw_flags: %i, tq: %i)
\n
"
,
"(gw_flags: %i, tq: %i)
\n
"
,
curr_gw_tmp
->
orig_node
->
orig
,
curr_gw_tmp
->
orig_node
->
orig
,
curr_gw_tmp
->
orig_node
->
gw_flags
,
curr_gw_tmp
->
orig_node
->
gw_flags
,
curr_gw_tmp
->
orig_node
->
router
->
tq_avg
);
router
->
tq_avg
);
neigh_node_free_ref
(
router
);
gw_select
(
bat_priv
,
curr_gw_tmp
);
gw_select
(
bat_priv
,
curr_gw_tmp
);
}
}
unlock:
rcu_read_unlock
();
rcu_read_unlock
();
out:
if
(
curr_gw
)
gw_node_free_ref
(
curr_gw
);
}
}
void
gw_check_election
(
struct
bat_priv
*
bat_priv
,
struct
orig_node
*
orig_node
)
void
gw_check_election
(
struct
bat_priv
*
bat_priv
,
struct
orig_node
*
orig_node
)
{
{
struct
gw_node
*
curr_gateway_tmp
;
struct
orig_node
*
curr_gw_orig
;
struct
neigh_node
*
router_gw
=
NULL
,
*
router_orig
=
NULL
;
uint8_t
gw_tq_avg
,
orig_tq_avg
;
uint8_t
gw_tq_avg
,
orig_tq_avg
;
rcu_read_lock
();
curr_gw_orig
=
gw_get_selected_orig
(
bat_priv
);
curr_gateway_tmp
=
rcu_dereference
(
bat_priv
->
curr_gw
);
if
(
!
curr_gw_orig
)
if
(
!
curr_gateway_tmp
)
goto
deselect
;
goto
out_rcu
;
if
(
!
curr_gateway_tmp
->
orig_node
)
router_gw
=
orig_node_get_router
(
curr_gw_orig
);
goto
deselect_rcu
;
if
(
!
router_gw
)
goto
deselect
;
if
(
!
curr_gateway_tmp
->
orig_node
->
router
)
goto
deselect_rcu
;
/* this node already is the gateway */
/* this node already is the gateway */
if
(
curr_gateway_tmp
->
orig_node
==
orig_node
)
if
(
curr_gw_orig
==
orig_node
)
goto
out_rcu
;
goto
out
;
if
(
!
orig_node
->
router
)
goto
out_rcu
;
gw_tq_avg
=
curr_gateway_tmp
->
orig_node
->
router
->
tq_avg
;
router_orig
=
orig_node_get_router
(
orig_node
);
rcu_read_unlock
();
if
(
!
router_orig
)
goto
out
;
orig_tq_avg
=
orig_node
->
router
->
tq_avg
;
gw_tq_avg
=
router_gw
->
tq_avg
;
orig_tq_avg
=
router_orig
->
tq_avg
;
/* the TQ value has to be better */
/* the TQ value has to be better */
if
(
orig_tq_avg
<
gw_tq_avg
)
if
(
orig_tq_avg
<
gw_tq_avg
)
...
@@ -245,16 +261,17 @@ void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node)
...
@@ -245,16 +261,17 @@ void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node)
"Restarting gateway selection: better gateway found (tq curr: "
"Restarting gateway selection: better gateway found (tq curr: "
"%i, tq new: %i)
\n
"
,
"%i, tq new: %i)
\n
"
,
gw_tq_avg
,
orig_tq_avg
);
gw_tq_avg
,
orig_tq_avg
);
goto
deselect
;
out_rcu:
rcu_read_unlock
();
goto
out
;
deselect_rcu:
rcu_read_unlock
();
deselect:
deselect:
gw_deselect
(
bat_priv
);
gw_deselect
(
bat_priv
);
out:
out:
if
(
curr_gw_orig
)
orig_node_free_ref
(
curr_gw_orig
);
if
(
router_gw
)
neigh_node_free_ref
(
router_gw
);
if
(
router_orig
)
neigh_node_free_ref
(
router_orig
);
return
;
return
;
}
}
...
@@ -291,7 +308,11 @@ void gw_node_update(struct bat_priv *bat_priv,
...
@@ -291,7 +308,11 @@ void gw_node_update(struct bat_priv *bat_priv,
struct
orig_node
*
orig_node
,
uint8_t
new_gwflags
)
struct
orig_node
*
orig_node
,
uint8_t
new_gwflags
)
{
{
struct
hlist_node
*
node
;
struct
hlist_node
*
node
;
struct
gw_node
*
gw_node
;
struct
gw_node
*
gw_node
,
*
curr_gw
;
curr_gw
=
gw_get_selected_gw_node
(
bat_priv
);
if
(
!
curr_gw
)
goto
out
;
rcu_read_lock
();
rcu_read_lock
();
hlist_for_each_entry_rcu
(
gw_node
,
node
,
&
bat_priv
->
gw_list
,
list
)
{
hlist_for_each_entry_rcu
(
gw_node
,
node
,
&
bat_priv
->
gw_list
,
list
)
{
...
@@ -312,22 +333,26 @@ void gw_node_update(struct bat_priv *bat_priv,
...
@@ -312,22 +333,26 @@ void gw_node_update(struct bat_priv *bat_priv,
"Gateway %pM removed from gateway list
\n
"
,
"Gateway %pM removed from gateway list
\n
"
,
orig_node
->
orig
);
orig_node
->
orig
);
if
(
gw_node
==
rcu_dereference
(
bat_priv
->
curr_gw
))
{
if
(
gw_node
==
curr_gw
)
rcu_read_unlock
();
goto
deselect
;
gw_deselect
(
bat_priv
);
return
;
}
}
}
rcu_read_unlock
();
goto
unlock
;
return
;
}
}
rcu_read_unlock
();
if
(
new_gwflags
==
0
)
if
(
new_gwflags
==
0
)
return
;
goto
unlock
;
gw_node_add
(
bat_priv
,
orig_node
,
new_gwflags
);
gw_node_add
(
bat_priv
,
orig_node
,
new_gwflags
);
goto
unlock
;
deselect:
gw_deselect
(
bat_priv
);
unlock:
rcu_read_unlock
();
out:
if
(
curr_gw
)
gw_node_free_ref
(
curr_gw
);
}
}
void
gw_node_delete
(
struct
bat_priv
*
bat_priv
,
struct
orig_node
*
orig_node
)
void
gw_node_delete
(
struct
bat_priv
*
bat_priv
,
struct
orig_node
*
orig_node
)
...
@@ -337,9 +362,12 @@ void gw_node_delete(struct bat_priv *bat_priv, struct orig_node *orig_node)
...
@@ -337,9 +362,12 @@ void gw_node_delete(struct bat_priv *bat_priv, struct orig_node *orig_node)
void
gw_node_purge
(
struct
bat_priv
*
bat_priv
)
void
gw_node_purge
(
struct
bat_priv
*
bat_priv
)
{
{
struct
gw_node
*
gw_node
;
struct
gw_node
*
gw_node
,
*
curr_gw
;
struct
hlist_node
*
node
,
*
node_tmp
;
struct
hlist_node
*
node
,
*
node_tmp
;
unsigned
long
timeout
=
2
*
PURGE_TIMEOUT
*
HZ
;
unsigned
long
timeout
=
2
*
PURGE_TIMEOUT
*
HZ
;
char
do_deselect
=
0
;
curr_gw
=
gw_get_selected_gw_node
(
bat_priv
);
spin_lock_bh
(
&
bat_priv
->
gw_list_lock
);
spin_lock_bh
(
&
bat_priv
->
gw_list_lock
);
...
@@ -350,41 +378,56 @@ void gw_node_purge(struct bat_priv *bat_priv)
...
@@ -350,41 +378,56 @@ void gw_node_purge(struct bat_priv *bat_priv)
atomic_read
(
&
bat_priv
->
mesh_state
)
==
MESH_ACTIVE
)
atomic_read
(
&
bat_priv
->
mesh_state
)
==
MESH_ACTIVE
)
continue
;
continue
;
if
(
rcu_dereference
(
bat_priv
->
curr_gw
)
==
gw_node
)
if
(
curr_gw
==
gw_node
)
gw_deselect
(
bat_priv
)
;
do_deselect
=
1
;
hlist_del_rcu
(
&
gw_node
->
list
);
hlist_del_rcu
(
&
gw_node
->
list
);
gw_node_free_ref
(
gw_node
);
gw_node_free_ref
(
gw_node
);
}
}
spin_unlock_bh
(
&
bat_priv
->
gw_list_lock
);
spin_unlock_bh
(
&
bat_priv
->
gw_list_lock
);
/* gw_deselect() needs to acquire the gw_list_lock */
if
(
do_deselect
)
gw_deselect
(
bat_priv
);
if
(
curr_gw
)
gw_node_free_ref
(
curr_gw
);
}
}
/**
* fails if orig_node has no router
*/
static
int
_write_buffer_text
(
struct
bat_priv
*
bat_priv
,
static
int
_write_buffer_text
(
struct
bat_priv
*
bat_priv
,
struct
seq_file
*
seq
,
struct
gw_node
*
gw_node
)
struct
seq_file
*
seq
,
struct
gw_node
*
gw_node
)
{
{
struct
gw_node
*
curr_gw
;
struct
gw_node
*
curr_gw
;
int
down
,
up
,
ret
;
struct
neigh_node
*
router
;
int
down
,
up
,
ret
=
-
1
;
gw_bandwidth_to_kbit
(
gw_node
->
orig_node
->
gw_flags
,
&
down
,
&
up
);
gw_bandwidth_to_kbit
(
gw_node
->
orig_node
->
gw_flags
,
&
down
,
&
up
);
rcu_read_lock
();
router
=
orig_node_get_router
(
gw_node
->
orig_node
);
curr_gw
=
rcu_dereference
(
bat_priv
->
curr_gw
);
if
(
!
router
)
goto
out
;
ret
=
seq_printf
(
seq
,
"%s %pM (%3i) %pM [%10s]: %3i - %i%s/%i%s
\n
"
,
curr_gw
=
gw_get_selected_gw_node
(
bat_priv
);
(
curr_gw
==
gw_node
?
"=>"
:
" "
),
gw_node
->
orig_node
->
orig
,
gw_node
->
orig_node
->
router
->
tq_avg
,
gw_node
->
orig_node
->
router
->
addr
,
gw_node
->
orig_node
->
router
->
if_incoming
->
net_dev
->
name
,
gw_node
->
orig_node
->
gw_flags
,
(
down
>
2048
?
down
/
1024
:
down
),
(
down
>
2048
?
"MBit"
:
"KBit"
),
(
up
>
2048
?
up
/
1024
:
up
),
(
up
>
2048
?
"MBit"
:
"KBit"
));
rcu_read_unlock
();
ret
=
seq_printf
(
seq
,
"%s %pM (%3i) %pM [%10s]: %3i - %i%s/%i%s
\n
"
,
(
curr_gw
==
gw_node
?
"=>"
:
" "
),
gw_node
->
orig_node
->
orig
,
router
->
tq_avg
,
router
->
addr
,
router
->
if_incoming
->
net_dev
->
name
,
gw_node
->
orig_node
->
gw_flags
,
(
down
>
2048
?
down
/
1024
:
down
),
(
down
>
2048
?
"MBit"
:
"KBit"
),
(
up
>
2048
?
up
/
1024
:
up
),
(
up
>
2048
?
"MBit"
:
"KBit"
));
neigh_node_free_ref
(
router
);
if
(
curr_gw
)
gw_node_free_ref
(
curr_gw
);
out:
return
ret
;
return
ret
;
}
}
...
@@ -422,10 +465,10 @@ int gw_client_seq_print_text(struct seq_file *seq, void *offset)
...
@@ -422,10 +465,10 @@ int gw_client_seq_print_text(struct seq_file *seq, void *offset)
if
(
gw_node
->
deleted
)
if
(
gw_node
->
deleted
)
continue
;
continue
;
if
(
!
gw_node
->
orig_node
->
router
)
/* fails if orig_node has no router */
if
(
_write_buffer_text
(
bat_priv
,
seq
,
gw_node
)
<
0
)
continue
;
continue
;
_write_buffer_text
(
bat_priv
,
seq
,
gw_node
);
gw_count
++
;
gw_count
++
;
}
}
rcu_read_unlock
();
rcu_read_unlock
();
...
@@ -442,6 +485,7 @@ int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb)
...
@@ -442,6 +485,7 @@ int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb)
struct
iphdr
*
iphdr
;
struct
iphdr
*
iphdr
;
struct
ipv6hdr
*
ipv6hdr
;
struct
ipv6hdr
*
ipv6hdr
;
struct
udphdr
*
udphdr
;
struct
udphdr
*
udphdr
;
struct
gw_node
*
curr_gw
;
unsigned
int
header_len
=
0
;
unsigned
int
header_len
=
0
;
if
(
atomic_read
(
&
bat_priv
->
gw_mode
)
==
GW_MODE_OFF
)
if
(
atomic_read
(
&
bat_priv
->
gw_mode
)
==
GW_MODE_OFF
)
...
@@ -506,12 +550,11 @@ int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb)
...
@@ -506,12 +550,11 @@ int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb)
if
(
atomic_read
(
&
bat_priv
->
gw_mode
)
==
GW_MODE_SERVER
)
if
(
atomic_read
(
&
bat_priv
->
gw_mode
)
==
GW_MODE_SERVER
)
return
-
1
;
return
-
1
;
rcu_read_lock
();
curr_gw
=
gw_get_selected_gw_node
(
bat_priv
);
if
(
!
rcu_dereference
(
bat_priv
->
curr_gw
))
{
if
(
!
curr_gw
)
rcu_read_unlock
();
return
0
;
return
0
;
}
rcu_read_unlock
();
if
(
curr_gw
)
gw_node_free_ref
(
curr_gw
);
return
1
;
return
1
;
}
}
net/batman-adv/gateway_client.h
View file @
9c6bc165
...
@@ -24,7 +24,7 @@
...
@@ -24,7 +24,7 @@
void
gw_deselect
(
struct
bat_priv
*
bat_priv
);
void
gw_deselect
(
struct
bat_priv
*
bat_priv
);
void
gw_election
(
struct
bat_priv
*
bat_priv
);
void
gw_election
(
struct
bat_priv
*
bat_priv
);
void
*
gw_get_selected
(
struct
bat_priv
*
bat_priv
);
struct
orig_node
*
gw_get_selected_orig
(
struct
bat_priv
*
bat_priv
);
void
gw_check_election
(
struct
bat_priv
*
bat_priv
,
struct
orig_node
*
orig_node
);
void
gw_check_election
(
struct
bat_priv
*
bat_priv
,
struct
orig_node
*
orig_node
);
void
gw_node_update
(
struct
bat_priv
*
bat_priv
,
void
gw_node_update
(
struct
bat_priv
*
bat_priv
,
struct
orig_node
*
orig_node
,
uint8_t
new_gwflags
);
struct
orig_node
*
orig_node
,
uint8_t
new_gwflags
);
...
...
net/batman-adv/icmp_socket.c
View file @
9c6bc165
...
@@ -218,23 +218,13 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff,
...
@@ -218,23 +218,13 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff,
if
(
atomic_read
(
&
bat_priv
->
mesh_state
)
!=
MESH_ACTIVE
)
if
(
atomic_read
(
&
bat_priv
->
mesh_state
)
!=
MESH_ACTIVE
)
goto
dst_unreach
;
goto
dst_unreach
;
rcu_read_lock
();
orig_node
=
orig_hash_find
(
bat_priv
,
icmp_packet
->
dst
);
orig_node
=
orig_hash_find
(
bat_priv
,
icmp_packet
->
dst
);
if
(
!
orig_node
)
if
(
!
orig_node
)
goto
unlock
;
goto
dst_unreach
;
neigh_node
=
orig_node
->
router
;
neigh_node
=
orig_node_get_router
(
orig_node
);
if
(
!
neigh_node
)
if
(
!
neigh_node
)
goto
unlock
;
goto
dst_unreach
;
if
(
!
atomic_inc_not_zero
(
&
neigh_node
->
refcount
))
{
neigh_node
=
NULL
;
goto
unlock
;
}
rcu_read_unlock
();
if
(
!
neigh_node
->
if_incoming
)
if
(
!
neigh_node
->
if_incoming
)
goto
dst_unreach
;
goto
dst_unreach
;
...
@@ -252,8 +242,6 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff,
...
@@ -252,8 +242,6 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff,
send_skb_packet
(
skb
,
neigh_node
->
if_incoming
,
neigh_node
->
addr
);
send_skb_packet
(
skb
,
neigh_node
->
if_incoming
,
neigh_node
->
addr
);
goto
out
;
goto
out
;
unlock:
rcu_read_unlock
();
dst_unreach:
dst_unreach:
icmp_packet
->
msg_type
=
DESTINATION_UNREACHABLE
;
icmp_packet
->
msg_type
=
DESTINATION_UNREACHABLE
;
bat_socket_add_packet
(
socket_client
,
icmp_packet
,
packet_len
);
bat_socket_add_packet
(
socket_client
,
icmp_packet
,
packet_len
);
...
...
net/batman-adv/originator.c
View file @
9c6bc165
...
@@ -70,6 +70,21 @@ void neigh_node_free_ref(struct neigh_node *neigh_node)
...
@@ -70,6 +70,21 @@ void neigh_node_free_ref(struct neigh_node *neigh_node)
call_rcu
(
&
neigh_node
->
rcu
,
neigh_node_free_rcu
);
call_rcu
(
&
neigh_node
->
rcu
,
neigh_node_free_rcu
);
}
}
/* increases the refcounter of a found router */
struct
neigh_node
*
orig_node_get_router
(
struct
orig_node
*
orig_node
)
{
struct
neigh_node
*
router
;
rcu_read_lock
();
router
=
rcu_dereference
(
orig_node
->
router
);
if
(
router
&&
!
atomic_inc_not_zero
(
&
router
->
refcount
))
router
=
NULL
;
rcu_read_unlock
();
return
router
;
}
struct
neigh_node
*
create_neighbor
(
struct
orig_node
*
orig_node
,
struct
neigh_node
*
create_neighbor
(
struct
orig_node
*
orig_node
,
struct
orig_node
*
orig_neigh_node
,
struct
orig_node
*
orig_neigh_node
,
uint8_t
*
neigh
,
uint8_t
*
neigh
,
...
@@ -87,6 +102,7 @@ struct neigh_node *create_neighbor(struct orig_node *orig_node,
...
@@ -87,6 +102,7 @@ struct neigh_node *create_neighbor(struct orig_node *orig_node,
INIT_HLIST_NODE
(
&
neigh_node
->
list
);
INIT_HLIST_NODE
(
&
neigh_node
->
list
);
INIT_LIST_HEAD
(
&
neigh_node
->
bonding_list
);
INIT_LIST_HEAD
(
&
neigh_node
->
bonding_list
);
spin_lock_init
(
&
neigh_node
->
tq_lock
);
memcpy
(
neigh_node
->
addr
,
neigh
,
ETH_ALEN
);
memcpy
(
neigh_node
->
addr
,
neigh
,
ETH_ALEN
);
neigh_node
->
orig_node
=
orig_neigh_node
;
neigh_node
->
orig_node
=
orig_neigh_node
;
...
@@ -390,7 +406,7 @@ int orig_seq_print_text(struct seq_file *seq, void *offset)
...
@@ -390,7 +406,7 @@ int orig_seq_print_text(struct seq_file *seq, void *offset)
struct
hlist_node
*
node
,
*
node_tmp
;
struct
hlist_node
*
node
,
*
node_tmp
;
struct
hlist_head
*
head
;
struct
hlist_head
*
head
;
struct
orig_node
*
orig_node
;
struct
orig_node
*
orig_node
;
struct
neigh_node
*
neigh_node
;
struct
neigh_node
*
neigh_node
,
*
neigh_node_tmp
;
int
batman_count
=
0
;
int
batman_count
=
0
;
int
last_seen_secs
;
int
last_seen_secs
;
int
last_seen_msecs
;
int
last_seen_msecs
;
...
@@ -421,37 +437,41 @@ int orig_seq_print_text(struct seq_file *seq, void *offset)
...
@@ -421,37 +437,41 @@ int orig_seq_print_text(struct seq_file *seq, void *offset)
rcu_read_lock
();
rcu_read_lock
();
hlist_for_each_entry_rcu
(
orig_node
,
node
,
head
,
hash_entry
)
{
hlist_for_each_entry_rcu
(
orig_node
,
node
,
head
,
hash_entry
)
{
if
(
!
orig_node
->
router
)
neigh_node
=
orig_node_get_router
(
orig_node
);
if
(
!
neigh_node
)
continue
;
continue
;
if
(
orig_node
->
router
->
tq_avg
==
0
)
if
(
neigh_node
->
tq_avg
==
0
)
continue
;
goto
next
;
last_seen_secs
=
jiffies_to_msecs
(
jiffies
-
last_seen_secs
=
jiffies_to_msecs
(
jiffies
-
orig_node
->
last_valid
)
/
1000
;
orig_node
->
last_valid
)
/
1000
;
last_seen_msecs
=
jiffies_to_msecs
(
jiffies
-
last_seen_msecs
=
jiffies_to_msecs
(
jiffies
-
orig_node
->
last_valid
)
%
1000
;
orig_node
->
last_valid
)
%
1000
;
neigh_node
=
orig_node
->
router
;
seq_printf
(
seq
,
"%pM %4i.%03is (%3i) %pM [%10s]:"
,
seq_printf
(
seq
,
"%pM %4i.%03is (%3i) %pM [%10s]:"
,
orig_node
->
orig
,
last_seen_secs
,
orig_node
->
orig
,
last_seen_secs
,
last_seen_msecs
,
neigh_node
->
tq_avg
,
last_seen_msecs
,
neigh_node
->
tq_avg
,
neigh_node
->
addr
,
neigh_node
->
addr
,
neigh_node
->
if_incoming
->
net_dev
->
name
);
neigh_node
->
if_incoming
->
net_dev
->
name
);
hlist_for_each_entry_rcu
(
neigh_node
,
node_tmp
,
hlist_for_each_entry_rcu
(
neigh_node
_tmp
,
node_tmp
,
&
orig_node
->
neigh_list
,
list
)
{
&
orig_node
->
neigh_list
,
list
)
{
seq_printf
(
seq
,
" %pM (%3i)"
,
neigh_node
->
addr
,
seq_printf
(
seq
,
" %pM (%3i)"
,
neigh_node
->
tq_avg
);
neigh_node_tmp
->
addr
,
neigh_node_tmp
->
tq_avg
);
}
}
seq_printf
(
seq
,
"
\n
"
);
seq_printf
(
seq
,
"
\n
"
);
batman_count
++
;
batman_count
++
;
next:
neigh_node_free_ref
(
neigh_node
);
}
}
rcu_read_unlock
();
rcu_read_unlock
();
}
}
if
(
(
batman_count
==
0
)
)
if
(
batman_count
==
0
)
seq_printf
(
seq
,
"No batman nodes in range ...
\n
"
);
seq_printf
(
seq
,
"No batman nodes in range ...
\n
"
);
return
0
;
return
0
;
...
...
net/batman-adv/originator.h
View file @
9c6bc165
...
@@ -34,6 +34,7 @@ struct neigh_node *create_neighbor(struct orig_node *orig_node,
...
@@ -34,6 +34,7 @@ struct neigh_node *create_neighbor(struct orig_node *orig_node,
uint8_t
*
neigh
,
uint8_t
*
neigh
,
struct
hard_iface
*
if_incoming
);
struct
hard_iface
*
if_incoming
);
void
neigh_node_free_ref
(
struct
neigh_node
*
neigh_node
);
void
neigh_node_free_ref
(
struct
neigh_node
*
neigh_node
);
struct
neigh_node
*
orig_node_get_router
(
struct
orig_node
*
orig_node
);
int
orig_seq_print_text
(
struct
seq_file
*
seq
,
void
*
offset
);
int
orig_seq_print_text
(
struct
seq_file
*
seq
,
void
*
offset
);
int
orig_hash_add_if
(
struct
hard_iface
*
hard_iface
,
int
max_if_num
);
int
orig_hash_add_if
(
struct
hard_iface
*
hard_iface
,
int
max_if_num
);
int
orig_hash_del_if
(
struct
hard_iface
*
hard_iface
,
int
max_if_num
);
int
orig_hash_del_if
(
struct
hard_iface
*
hard_iface
,
int
max_if_num
);
...
...
net/batman-adv/routing.c
View file @
9c6bc165
...
@@ -87,18 +87,20 @@ static void update_route(struct bat_priv *bat_priv,
...
@@ -87,18 +87,20 @@ static void update_route(struct bat_priv *bat_priv,
struct
neigh_node
*
neigh_node
,
struct
neigh_node
*
neigh_node
,
unsigned
char
*
hna_buff
,
int
hna_buff_len
)
unsigned
char
*
hna_buff
,
int
hna_buff_len
)
{
{
struct
neigh_node
*
neigh_node_tmp
;
struct
neigh_node
*
curr_router
;
curr_router
=
orig_node_get_router
(
orig_node
);
/* route deleted */
/* route deleted */
if
((
orig_node
->
router
)
&&
(
!
neigh_node
))
{
if
((
curr_
router
)
&&
(
!
neigh_node
))
{
bat_dbg
(
DBG_ROUTES
,
bat_priv
,
"Deleting route towards: %pM
\n
"
,
bat_dbg
(
DBG_ROUTES
,
bat_priv
,
"Deleting route towards: %pM
\n
"
,
orig_node
->
orig
);
orig_node
->
orig
);
hna_global_del_orig
(
bat_priv
,
orig_node
,
hna_global_del_orig
(
bat_priv
,
orig_node
,
"originator timed out"
);
"originator timed out"
);
/* route added */
/* route added */
}
else
if
((
!
orig_node
->
router
)
&&
(
neigh_node
))
{
}
else
if
((
!
curr_
router
)
&&
(
neigh_node
))
{
bat_dbg
(
DBG_ROUTES
,
bat_priv
,
bat_dbg
(
DBG_ROUTES
,
bat_priv
,
"Adding route towards: %pM (via %pM)
\n
"
,
"Adding route towards: %pM (via %pM)
\n
"
,
...
@@ -106,21 +108,29 @@ static void update_route(struct bat_priv *bat_priv,
...
@@ -106,21 +108,29 @@ static void update_route(struct bat_priv *bat_priv,
hna_global_add_orig
(
bat_priv
,
orig_node
,
hna_global_add_orig
(
bat_priv
,
orig_node
,
hna_buff
,
hna_buff_len
);
hna_buff
,
hna_buff_len
);
/* route changed */
/* route changed */
}
else
{
}
else
{
bat_dbg
(
DBG_ROUTES
,
bat_priv
,
bat_dbg
(
DBG_ROUTES
,
bat_priv
,
"Changing route towards: %pM "
"Changing route towards: %pM "
"(now via %pM - was via %pM)
\n
"
,
"(now via %pM - was via %pM)
\n
"
,
orig_node
->
orig
,
neigh_node
->
addr
,
orig_node
->
orig
,
neigh_node
->
addr
,
orig_node
->
router
->
addr
);
curr_
router
->
addr
);
}
}
if
(
curr_router
)
neigh_node_free_ref
(
curr_router
);
/* increase refcount of new best neighbor */
if
(
neigh_node
&&
!
atomic_inc_not_zero
(
&
neigh_node
->
refcount
))
if
(
neigh_node
&&
!
atomic_inc_not_zero
(
&
neigh_node
->
refcount
))
neigh_node
=
NULL
;
neigh_node
=
NULL
;
neigh_node_tmp
=
orig_node
->
router
;
orig_node
->
router
=
neigh_node
;
spin_lock_bh
(
&
orig_node
->
neigh_list_lock
);
if
(
neigh_node_tmp
)
rcu_assign_pointer
(
orig_node
->
router
,
neigh_node
);
neigh_node_free_ref
(
neigh_node_tmp
);
spin_unlock_bh
(
&
orig_node
->
neigh_list_lock
);
/* decrease refcount of previous best neighbor */
if
(
curr_router
)
neigh_node_free_ref
(
curr_router
);
}
}
...
@@ -128,16 +138,23 @@ void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_node,
...
@@ -128,16 +138,23 @@ void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_node,
struct
neigh_node
*
neigh_node
,
unsigned
char
*
hna_buff
,
struct
neigh_node
*
neigh_node
,
unsigned
char
*
hna_buff
,
int
hna_buff_len
)
int
hna_buff_len
)
{
{
struct
neigh_node
*
router
=
NULL
;
if
(
!
orig_node
)
if
(
!
orig_node
)
return
;
goto
out
;
router
=
orig_node_get_router
(
orig_node
);
if
(
orig_node
->
router
!=
neigh_node
)
if
(
router
!=
neigh_node
)
update_route
(
bat_priv
,
orig_node
,
neigh_node
,
update_route
(
bat_priv
,
orig_node
,
neigh_node
,
hna_buff
,
hna_buff_len
);
hna_buff
,
hna_buff_len
);
/* may be just HNA changed */
/* may be just HNA changed */
else
else
update_HNA
(
bat_priv
,
orig_node
,
hna_buff
,
hna_buff_len
);
update_HNA
(
bat_priv
,
orig_node
,
hna_buff
,
hna_buff_len
);
out:
if
(
router
)
neigh_node_free_ref
(
router
);
}
}
static
int
is_bidirectional_neigh
(
struct
orig_node
*
orig_node
,
static
int
is_bidirectional_neigh
(
struct
orig_node
*
orig_node
,
...
@@ -288,8 +305,8 @@ static void bonding_candidate_add(struct orig_node *orig_node,
...
@@ -288,8 +305,8 @@ static void bonding_candidate_add(struct orig_node *orig_node,
struct
neigh_node
*
neigh_node
)
struct
neigh_node
*
neigh_node
)
{
{
struct
hlist_node
*
node
;
struct
hlist_node
*
node
;
struct
neigh_node
*
tmp_neigh_node
;
struct
neigh_node
*
tmp_neigh_node
,
*
router
=
NULL
;
uint8_t
best_tq
,
interference_candidate
=
0
;
uint8_t
interference_candidate
=
0
;
spin_lock_bh
(
&
orig_node
->
neigh_list_lock
);
spin_lock_bh
(
&
orig_node
->
neigh_list_lock
);
...
@@ -298,13 +315,12 @@ static void bonding_candidate_add(struct orig_node *orig_node,
...
@@ -298,13 +315,12 @@ static void bonding_candidate_add(struct orig_node *orig_node,
neigh_node
->
orig_node
->
primary_addr
))
neigh_node
->
orig_node
->
primary_addr
))
goto
candidate_del
;
goto
candidate_del
;
if
(
!
orig_node
->
router
)
router
=
orig_node_get_router
(
orig_node
);
if
(
!
router
)
goto
candidate_del
;
goto
candidate_del
;
best_tq
=
orig_node
->
router
->
tq_avg
;
/* ... and is good enough to be considered */
/* ... and is good enough to be considered */
if
(
neigh_node
->
tq_avg
<
best_tq
-
BONDING_TQ_THRESHOLD
)
if
(
neigh_node
->
tq_avg
<
router
->
tq_avg
-
BONDING_TQ_THRESHOLD
)
goto
candidate_del
;
goto
candidate_del
;
/**
/**
...
@@ -350,7 +366,9 @@ static void bonding_candidate_add(struct orig_node *orig_node,
...
@@ -350,7 +366,9 @@ static void bonding_candidate_add(struct orig_node *orig_node,
out:
out:
spin_unlock_bh
(
&
orig_node
->
neigh_list_lock
);
spin_unlock_bh
(
&
orig_node
->
neigh_list_lock
);
return
;
if
(
router
)
neigh_node_free_ref
(
router
);
}
}
/* copy primary address for bonding */
/* copy primary address for bonding */
...
@@ -373,6 +391,7 @@ static void update_orig(struct bat_priv *bat_priv,
...
@@ -373,6 +391,7 @@ static void update_orig(struct bat_priv *bat_priv,
char
is_duplicate
)
char
is_duplicate
)
{
{
struct
neigh_node
*
neigh_node
=
NULL
,
*
tmp_neigh_node
=
NULL
;
struct
neigh_node
*
neigh_node
=
NULL
,
*
tmp_neigh_node
=
NULL
;
struct
neigh_node
*
router
=
NULL
;
struct
orig_node
*
orig_node_tmp
;
struct
orig_node
*
orig_node_tmp
;
struct
hlist_node
*
node
;
struct
hlist_node
*
node
;
int
tmp_hna_buff_len
;
int
tmp_hna_buff_len
;
...
@@ -396,10 +415,12 @@ static void update_orig(struct bat_priv *bat_priv,
...
@@ -396,10 +415,12 @@ static void update_orig(struct bat_priv *bat_priv,
if
(
is_duplicate
)
if
(
is_duplicate
)
continue
;
continue
;
spin_lock_bh
(
&
tmp_neigh_node
->
tq_lock
);
ring_buffer_set
(
tmp_neigh_node
->
tq_recv
,
ring_buffer_set
(
tmp_neigh_node
->
tq_recv
,
&
tmp_neigh_node
->
tq_index
,
0
);
&
tmp_neigh_node
->
tq_index
,
0
);
tmp_neigh_node
->
tq_avg
=
tmp_neigh_node
->
tq_avg
=
ring_buffer_avg
(
tmp_neigh_node
->
tq_recv
);
ring_buffer_avg
(
tmp_neigh_node
->
tq_recv
);
spin_unlock_bh
(
&
tmp_neigh_node
->
tq_lock
);
}
}
if
(
!
neigh_node
)
{
if
(
!
neigh_node
)
{
...
@@ -424,10 +445,12 @@ static void update_orig(struct bat_priv *bat_priv,
...
@@ -424,10 +445,12 @@ static void update_orig(struct bat_priv *bat_priv,
orig_node
->
flags
=
batman_packet
->
flags
;
orig_node
->
flags
=
batman_packet
->
flags
;
neigh_node
->
last_valid
=
jiffies
;
neigh_node
->
last_valid
=
jiffies
;
spin_lock_bh
(
&
neigh_node
->
tq_lock
);
ring_buffer_set
(
neigh_node
->
tq_recv
,
ring_buffer_set
(
neigh_node
->
tq_recv
,
&
neigh_node
->
tq_index
,
&
neigh_node
->
tq_index
,
batman_packet
->
tq
);
batman_packet
->
tq
);
neigh_node
->
tq_avg
=
ring_buffer_avg
(
neigh_node
->
tq_recv
);
neigh_node
->
tq_avg
=
ring_buffer_avg
(
neigh_node
->
tq_recv
);
spin_unlock_bh
(
&
neigh_node
->
tq_lock
);
if
(
!
is_duplicate
)
{
if
(
!
is_duplicate
)
{
orig_node
->
last_ttl
=
batman_packet
->
ttl
;
orig_node
->
last_ttl
=
batman_packet
->
ttl
;
...
@@ -441,19 +464,18 @@ static void update_orig(struct bat_priv *bat_priv,
...
@@ -441,19 +464,18 @@ static void update_orig(struct bat_priv *bat_priv,
/* if this neighbor already is our next hop there is nothing
/* if this neighbor already is our next hop there is nothing
* to change */
* to change */
if
(
orig_node
->
router
==
neigh_node
)
router
=
orig_node_get_router
(
orig_node
);
if
(
router
==
neigh_node
)
goto
update_hna
;
goto
update_hna
;
/* if this neighbor does not offer a better TQ we won't consider it */
/* if this neighbor does not offer a better TQ we won't consider it */
if
((
orig_node
->
router
)
&&
if
(
router
&&
(
router
->
tq_avg
>
neigh_node
->
tq_avg
))
(
orig_node
->
router
->
tq_avg
>
neigh_node
->
tq_avg
))
goto
update_hna
;
goto
update_hna
;
/* if the TQ is the same and the link not more symetric we
/* if the TQ is the same and the link not more symetric we
* won't consider it either */
* won't consider it either */
if
((
orig_node
->
router
)
&&
if
(
router
&&
(
neigh_node
->
tq_avg
==
router
->
tq_avg
))
{
(
neigh_node
->
tq_avg
==
orig_node
->
router
->
tq_avg
))
{
orig_node_tmp
=
router
->
orig_node
;
orig_node_tmp
=
orig_node
->
router
->
orig_node
;
spin_lock_bh
(
&
orig_node_tmp
->
ogm_cnt_lock
);
spin_lock_bh
(
&
orig_node_tmp
->
ogm_cnt_lock
);
bcast_own_sum_orig
=
bcast_own_sum_orig
=
orig_node_tmp
->
bcast_own_sum
[
if_incoming
->
if_num
];
orig_node_tmp
->
bcast_own_sum
[
if_incoming
->
if_num
];
...
@@ -474,7 +496,7 @@ static void update_orig(struct bat_priv *bat_priv,
...
@@ -474,7 +496,7 @@ static void update_orig(struct bat_priv *bat_priv,
goto
update_gw
;
goto
update_gw
;
update_hna:
update_hna:
update_routes
(
bat_priv
,
orig_node
,
orig_node
->
router
,
update_routes
(
bat_priv
,
orig_node
,
router
,
hna_buff
,
tmp_hna_buff_len
);
hna_buff
,
tmp_hna_buff_len
);
update_gw:
update_gw:
...
@@ -496,6 +518,8 @@ static void update_orig(struct bat_priv *bat_priv,
...
@@ -496,6 +518,8 @@ static void update_orig(struct bat_priv *bat_priv,
out:
out:
if
(
neigh_node
)
if
(
neigh_node
)
neigh_node_free_ref
(
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.
/* checks whether the host restarted and is in the protection time.
...
@@ -603,6 +627,8 @@ void receive_bat_packet(struct ethhdr *ethhdr,
...
@@ -603,6 +627,8 @@ void receive_bat_packet(struct ethhdr *ethhdr,
struct
bat_priv
*
bat_priv
=
netdev_priv
(
if_incoming
->
soft_iface
);
struct
bat_priv
*
bat_priv
=
netdev_priv
(
if_incoming
->
soft_iface
);
struct
hard_iface
*
hard_iface
;
struct
hard_iface
*
hard_iface
;
struct
orig_node
*
orig_neigh_node
,
*
orig_node
;
struct
orig_node
*
orig_neigh_node
,
*
orig_node
;
struct
neigh_node
*
router
=
NULL
,
*
router_router
=
NULL
;
struct
neigh_node
*
orig_neigh_router
=
NULL
;
char
has_directlink_flag
;
char
has_directlink_flag
;
char
is_my_addr
=
0
,
is_my_orig
=
0
,
is_my_oldorig
=
0
;
char
is_my_addr
=
0
,
is_my_orig
=
0
,
is_my_oldorig
=
0
;
char
is_broadcast
=
0
,
is_bidirectional
,
is_single_hop_neigh
;
char
is_broadcast
=
0
,
is_bidirectional
,
is_single_hop_neigh
;
...
@@ -747,14 +773,15 @@ void receive_bat_packet(struct ethhdr *ethhdr,
...
@@ -747,14 +773,15 @@ void receive_bat_packet(struct ethhdr *ethhdr,
goto
out
;
goto
out
;
}
}
router
=
orig_node_get_router
(
orig_node
);
if
(
router
)
router_router
=
orig_node_get_router
(
router
->
orig_node
);
/* avoid temporary routing loops */
/* avoid temporary routing loops */
if
((
orig_node
->
router
)
&&
if
(
router
&&
router_router
&&
(
orig_node
->
router
->
orig_node
->
router
)
&&
(
compare_eth
(
router
->
addr
,
batman_packet
->
prev_sender
))
&&
(
compare_eth
(
orig_node
->
router
->
addr
,
batman_packet
->
prev_sender
))
&&
!
(
compare_eth
(
batman_packet
->
orig
,
batman_packet
->
prev_sender
))
&&
!
(
compare_eth
(
batman_packet
->
orig
,
batman_packet
->
prev_sender
))
&&
(
compare_eth
(
orig_node
->
router
->
addr
,
(
compare_eth
(
router
->
addr
,
router_router
->
addr
)))
{
orig_node
->
router
->
orig_node
->
router
->
addr
)))
{
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"Drop packet: ignoring all rebroadcast packets that "
"Drop packet: ignoring all rebroadcast packets that "
"may make me loop (sender: %pM)
\n
"
,
ethhdr
->
h_source
);
"may make me loop (sender: %pM)
\n
"
,
ethhdr
->
h_source
);
...
@@ -769,9 +796,11 @@ void receive_bat_packet(struct ethhdr *ethhdr,
...
@@ -769,9 +796,11 @@ void receive_bat_packet(struct ethhdr *ethhdr,
if
(
!
orig_neigh_node
)
if
(
!
orig_neigh_node
)
goto
out
;
goto
out
;
orig_neigh_router
=
orig_node_get_router
(
orig_neigh_node
);
/* drop packet if sender is not a direct neighbor and if we
/* drop packet if sender is not a direct neighbor and if we
* don't route towards it */
* don't route towards it */
if
(
!
is_single_hop_neigh
&&
(
!
orig_neigh_
node
->
router
))
{
if
(
!
is_single_hop_neigh
&&
(
!
orig_neigh_router
))
{
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"Drop packet: OGM via unknown neighbor!
\n
"
);
"Drop packet: OGM via unknown neighbor!
\n
"
);
goto
out_neigh
;
goto
out_neigh
;
...
@@ -825,6 +854,13 @@ void receive_bat_packet(struct ethhdr *ethhdr,
...
@@ -825,6 +854,13 @@ void receive_bat_packet(struct ethhdr *ethhdr,
if
((
orig_neigh_node
)
&&
(
!
is_single_hop_neigh
))
if
((
orig_neigh_node
)
&&
(
!
is_single_hop_neigh
))
orig_node_free_ref
(
orig_neigh_node
);
orig_node_free_ref
(
orig_neigh_node
);
out:
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
);
orig_node_free_ref
(
orig_node
);
}
}
...
@@ -869,7 +905,7 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv,
...
@@ -869,7 +905,7 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv,
struct
sk_buff
*
skb
,
size_t
icmp_len
)
struct
sk_buff
*
skb
,
size_t
icmp_len
)
{
{
struct
orig_node
*
orig_node
=
NULL
;
struct
orig_node
*
orig_node
=
NULL
;
struct
neigh_node
*
neigh_node
=
NULL
;
struct
neigh_node
*
router
=
NULL
;
struct
icmp_packet_rr
*
icmp_packet
;
struct
icmp_packet_rr
*
icmp_packet
;
int
ret
=
NET_RX_DROP
;
int
ret
=
NET_RX_DROP
;
...
@@ -886,23 +922,13 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv,
...
@@ -886,23 +922,13 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv,
/* answer echo request (ping) */
/* answer echo request (ping) */
/* get routing information */
/* get routing information */
rcu_read_lock
();
orig_node
=
orig_hash_find
(
bat_priv
,
icmp_packet
->
orig
);
orig_node
=
orig_hash_find
(
bat_priv
,
icmp_packet
->
orig
);
if
(
!
orig_node
)
if
(
!
orig_node
)
goto
unlock
;
goto
out
;
neigh_node
=
orig_node
->
router
;
if
(
!
neigh_node
)
goto
unlock
;
if
(
!
atomic_inc_not_zero
(
&
neigh_node
->
refcount
))
{
neigh_node
=
NULL
;
goto
unlock
;
}
rcu_read_unlock
();
router
=
orig_node_get_router
(
orig_node
);
if
(
!
router
)
goto
out
;
/* create a copy of the skb, if needed, to modify it. */
/* create a copy of the skb, if needed, to modify it. */
if
(
skb_cow
(
skb
,
sizeof
(
struct
ethhdr
))
<
0
)
if
(
skb_cow
(
skb
,
sizeof
(
struct
ethhdr
))
<
0
)
...
@@ -916,15 +942,12 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv,
...
@@ -916,15 +942,12 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv,
icmp_packet
->
msg_type
=
ECHO_REPLY
;
icmp_packet
->
msg_type
=
ECHO_REPLY
;
icmp_packet
->
ttl
=
TTL
;
icmp_packet
->
ttl
=
TTL
;
send_skb_packet
(
skb
,
neigh_node
->
if_incoming
,
neigh_node
->
addr
);
send_skb_packet
(
skb
,
router
->
if_incoming
,
router
->
addr
);
ret
=
NET_RX_SUCCESS
;
ret
=
NET_RX_SUCCESS
;
goto
out
;
unlock:
rcu_read_unlock
();
out:
out:
if
(
neigh_node
)
if
(
router
)
neigh_node_free_ref
(
neigh_node
);
neigh_node_free_ref
(
router
);
if
(
orig_node
)
if
(
orig_node
)
orig_node_free_ref
(
orig_node
);
orig_node_free_ref
(
orig_node
);
return
ret
;
return
ret
;
...
@@ -934,7 +957,7 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv,
...
@@ -934,7 +957,7 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv,
struct
sk_buff
*
skb
)
struct
sk_buff
*
skb
)
{
{
struct
orig_node
*
orig_node
=
NULL
;
struct
orig_node
*
orig_node
=
NULL
;
struct
neigh_node
*
neigh_node
=
NULL
;
struct
neigh_node
*
router
=
NULL
;
struct
icmp_packet
*
icmp_packet
;
struct
icmp_packet
*
icmp_packet
;
int
ret
=
NET_RX_DROP
;
int
ret
=
NET_RX_DROP
;
...
@@ -952,23 +975,13 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv,
...
@@ -952,23 +975,13 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv,
goto
out
;
goto
out
;
/* get routing information */
/* get routing information */
rcu_read_lock
();
orig_node
=
orig_hash_find
(
bat_priv
,
icmp_packet
->
orig
);
orig_node
=
orig_hash_find
(
bat_priv
,
icmp_packet
->
orig
);
if
(
!
orig_node
)
if
(
!
orig_node
)
goto
unlock
;
goto
out
;
neigh_node
=
orig_node
->
router
;
if
(
!
neigh_node
)
goto
unlock
;
if
(
!
atomic_inc_not_zero
(
&
neigh_node
->
refcount
))
{
neigh_node
=
NULL
;
goto
unlock
;
}
rcu_read_unlock
();
router
=
orig_node_get_router
(
orig_node
);
if
(
!
router
)
goto
out
;
/* create a copy of the skb, if needed, to modify it. */
/* create a copy of the skb, if needed, to modify it. */
if
(
skb_cow
(
skb
,
sizeof
(
struct
ethhdr
))
<
0
)
if
(
skb_cow
(
skb
,
sizeof
(
struct
ethhdr
))
<
0
)
...
@@ -982,15 +995,12 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv,
...
@@ -982,15 +995,12 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv,
icmp_packet
->
msg_type
=
TTL_EXCEEDED
;
icmp_packet
->
msg_type
=
TTL_EXCEEDED
;
icmp_packet
->
ttl
=
TTL
;
icmp_packet
->
ttl
=
TTL
;
send_skb_packet
(
skb
,
neigh_node
->
if_incoming
,
neigh_node
->
addr
);
send_skb_packet
(
skb
,
router
->
if_incoming
,
router
->
addr
);
ret
=
NET_RX_SUCCESS
;
ret
=
NET_RX_SUCCESS
;
goto
out
;
unlock:
rcu_read_unlock
();
out:
out:
if
(
neigh_node
)
if
(
router
)
neigh_node_free_ref
(
neigh_node
);
neigh_node_free_ref
(
router
);
if
(
orig_node
)
if
(
orig_node
)
orig_node_free_ref
(
orig_node
);
orig_node_free_ref
(
orig_node
);
return
ret
;
return
ret
;
...
@@ -1003,7 +1013,7 @@ int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *recv_if)
...
@@ -1003,7 +1013,7 @@ int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *recv_if)
struct
icmp_packet_rr
*
icmp_packet
;
struct
icmp_packet_rr
*
icmp_packet
;
struct
ethhdr
*
ethhdr
;
struct
ethhdr
*
ethhdr
;
struct
orig_node
*
orig_node
=
NULL
;
struct
orig_node
*
orig_node
=
NULL
;
struct
neigh_node
*
neigh_node
=
NULL
;
struct
neigh_node
*
router
=
NULL
;
int
hdr_size
=
sizeof
(
struct
icmp_packet
);
int
hdr_size
=
sizeof
(
struct
icmp_packet
);
int
ret
=
NET_RX_DROP
;
int
ret
=
NET_RX_DROP
;
...
@@ -1050,23 +1060,13 @@ int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *recv_if)
...
@@ -1050,23 +1060,13 @@ int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *recv_if)
return
recv_icmp_ttl_exceeded
(
bat_priv
,
skb
);
return
recv_icmp_ttl_exceeded
(
bat_priv
,
skb
);
/* get routing information */
/* get routing information */
rcu_read_lock
();
orig_node
=
orig_hash_find
(
bat_priv
,
icmp_packet
->
dst
);
orig_node
=
orig_hash_find
(
bat_priv
,
icmp_packet
->
dst
);
if
(
!
orig_node
)
if
(
!
orig_node
)
goto
unlock
;
goto
out
;
neigh_node
=
orig_node
->
router
;
if
(
!
neigh_node
)
goto
unlock
;
if
(
!
atomic_inc_not_zero
(
&
neigh_node
->
refcount
))
{
neigh_node
=
NULL
;
goto
unlock
;
}
rcu_read_unlock
();
router
=
orig_node_get_router
(
orig_node
);
if
(
!
router
)
goto
out
;
/* create a copy of the skb, if needed, to modify it. */
/* create a copy of the skb, if needed, to modify it. */
if
(
skb_cow
(
skb
,
sizeof
(
struct
ethhdr
))
<
0
)
if
(
skb_cow
(
skb
,
sizeof
(
struct
ethhdr
))
<
0
)
...
@@ -1078,20 +1078,117 @@ int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *recv_if)
...
@@ -1078,20 +1078,117 @@ int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *recv_if)
icmp_packet
->
ttl
--
;
icmp_packet
->
ttl
--
;
/* route it */
/* route it */
send_skb_packet
(
skb
,
neigh_node
->
if_incoming
,
neigh_node
->
addr
);
send_skb_packet
(
skb
,
router
->
if_incoming
,
router
->
addr
);
ret
=
NET_RX_SUCCESS
;
ret
=
NET_RX_SUCCESS
;
goto
out
;
unlock:
rcu_read_unlock
();
out:
out:
if
(
neigh_node
)
if
(
router
)
neigh_node_free_ref
(
neigh_node
);
neigh_node_free_ref
(
router
);
if
(
orig_node
)
if
(
orig_node
)
orig_node_free_ref
(
orig_node
);
orig_node_free_ref
(
orig_node
);
return
ret
;
return
ret
;
}
}
/* In the bonding case, send the packets in a round
* robin fashion over the remaining interfaces.
*
* This method rotates the bonding list and increases the
* returned router's refcount. */
static
struct
neigh_node
*
find_bond_router
(
struct
orig_node
*
primary_orig
,
struct
hard_iface
*
recv_if
)
{
struct
neigh_node
*
tmp_neigh_node
;
struct
neigh_node
*
router
=
NULL
,
*
first_candidate
=
NULL
;
rcu_read_lock
();
list_for_each_entry_rcu
(
tmp_neigh_node
,
&
primary_orig
->
bond_list
,
bonding_list
)
{
if
(
!
first_candidate
)
first_candidate
=
tmp_neigh_node
;
/* recv_if == NULL on the first node. */
if
(
tmp_neigh_node
->
if_incoming
==
recv_if
)
continue
;
if
(
!
atomic_inc_not_zero
(
&
tmp_neigh_node
->
refcount
))
continue
;
router
=
tmp_neigh_node
;
break
;
}
/* use the first candidate if nothing was found. */
if
(
!
router
&&
first_candidate
&&
atomic_inc_not_zero
(
&
first_candidate
->
refcount
))
router
=
first_candidate
;
if
(
!
router
)
goto
out
;
/* selected should point to the next element
* after the current router */
spin_lock_bh
(
&
primary_orig
->
neigh_list_lock
);
/* this is a list_move(), which unfortunately
* does not exist as rcu version */
list_del_rcu
(
&
primary_orig
->
bond_list
);
list_add_rcu
(
&
primary_orig
->
bond_list
,
&
router
->
bonding_list
);
spin_unlock_bh
(
&
primary_orig
->
neigh_list_lock
);
out:
rcu_read_unlock
();
return
router
;
}
/* Interface Alternating: Use the best of the
* remaining candidates which are not using
* this interface.
*
* Increases the returned router's refcount */
static
struct
neigh_node
*
find_ifalter_router
(
struct
orig_node
*
primary_orig
,
struct
hard_iface
*
recv_if
)
{
struct
neigh_node
*
tmp_neigh_node
;
struct
neigh_node
*
router
=
NULL
,
*
first_candidate
=
NULL
;
rcu_read_lock
();
list_for_each_entry_rcu
(
tmp_neigh_node
,
&
primary_orig
->
bond_list
,
bonding_list
)
{
if
(
!
first_candidate
)
first_candidate
=
tmp_neigh_node
;
/* recv_if == NULL on the first node. */
if
(
tmp_neigh_node
->
if_incoming
==
recv_if
)
continue
;
if
(
!
atomic_inc_not_zero
(
&
tmp_neigh_node
->
refcount
))
continue
;
/* if we don't have a router yet
* or this one is better, choose it. */
if
((
!
router
)
||
(
tmp_neigh_node
->
tq_avg
>
router
->
tq_avg
))
{
/* decrement refcount of
* previously selected router */
if
(
router
)
neigh_node_free_ref
(
router
);
router
=
tmp_neigh_node
;
atomic_inc_not_zero
(
&
router
->
refcount
);
}
neigh_node_free_ref
(
tmp_neigh_node
);
}
/* use the first candidate if nothing was found. */
if
(
!
router
&&
first_candidate
&&
atomic_inc_not_zero
(
&
first_candidate
->
refcount
))
router
=
first_candidate
;
rcu_read_unlock
();
return
router
;
}
/* find a suitable router for this originator, and use
/* find a suitable router for this originator, and use
* bonding if possible. increases the found neighbors
* bonding if possible. increases the found neighbors
* refcount.*/
* refcount.*/
...
@@ -1101,14 +1198,15 @@ struct neigh_node *find_router(struct bat_priv *bat_priv,
...
@@ -1101,14 +1198,15 @@ struct neigh_node *find_router(struct bat_priv *bat_priv,
{
{
struct
orig_node
*
primary_orig_node
;
struct
orig_node
*
primary_orig_node
;
struct
orig_node
*
router_orig
;
struct
orig_node
*
router_orig
;
struct
neigh_node
*
router
,
*
first_candidate
,
*
tmp_neigh_node
;
struct
neigh_node
*
router
;
static
uint8_t
zero_mac
[
ETH_ALEN
]
=
{
0
,
0
,
0
,
0
,
0
,
0
};
static
uint8_t
zero_mac
[
ETH_ALEN
]
=
{
0
,
0
,
0
,
0
,
0
,
0
};
int
bonding_enabled
;
int
bonding_enabled
;
if
(
!
orig_node
)
if
(
!
orig_node
)
return
NULL
;
return
NULL
;
if
(
!
orig_node
->
router
)
router
=
orig_node_get_router
(
orig_node
);
if
(
!
router
)
return
NULL
;
return
NULL
;
/* without bonding, the first node should
/* without bonding, the first node should
...
@@ -1117,9 +1215,8 @@ struct neigh_node *find_router(struct bat_priv *bat_priv,
...
@@ -1117,9 +1215,8 @@ struct neigh_node *find_router(struct bat_priv *bat_priv,
rcu_read_lock
();
rcu_read_lock
();
/* select default router to output */
/* select default router to output */
router
=
orig_node
->
router
;
router_orig
=
router
->
orig_node
;
router_orig
=
orig_node
->
router
->
orig_node
;
if
(
!
router_orig
)
{
if
(
!
router_orig
||
!
atomic_inc_not_zero
(
&
router
->
refcount
))
{
rcu_read_unlock
();
rcu_read_unlock
();
return
NULL
;
return
NULL
;
}
}
...
@@ -1151,88 +1248,17 @@ struct neigh_node *find_router(struct bat_priv *bat_priv,
...
@@ -1151,88 +1248,17 @@ struct neigh_node *find_router(struct bat_priv *bat_priv,
if
(
atomic_read
(
&
primary_orig_node
->
bond_candidates
)
<
2
)
if
(
atomic_read
(
&
primary_orig_node
->
bond_candidates
)
<
2
)
goto
return_router
;
goto
return_router
;
/* all nodes between should choose a candidate which
/* all nodes between should choose a candidate which
* is is not on the interface where the packet came
* is is not on the interface where the packet came
* in. */
* in. */
neigh_node_free_ref
(
router
);
neigh_node_free_ref
(
router
);
first_candidate
=
NULL
;
router
=
NULL
;
if
(
bonding_enabled
)
{
/* in the bonding case, send the packets in a round
* robin fashion over the remaining interfaces. */
list_for_each_entry_rcu
(
tmp_neigh_node
,
&
primary_orig_node
->
bond_list
,
bonding_list
)
{
if
(
!
first_candidate
)
first_candidate
=
tmp_neigh_node
;
/* recv_if == NULL on the first node. */
if
(
tmp_neigh_node
->
if_incoming
!=
recv_if
&&
atomic_inc_not_zero
(
&
tmp_neigh_node
->
refcount
))
{
router
=
tmp_neigh_node
;
break
;
}
}
/* use the first candidate if nothing was found. */
if
(
!
router
&&
first_candidate
&&
atomic_inc_not_zero
(
&
first_candidate
->
refcount
))
router
=
first_candidate
;
if
(
!
router
)
{
rcu_read_unlock
();
return
NULL
;
}
/* selected should point to the next element
* after the current router */
spin_lock_bh
(
&
primary_orig_node
->
neigh_list_lock
);
/* this is a list_move(), which unfortunately
* does not exist as rcu version */
list_del_rcu
(
&
primary_orig_node
->
bond_list
);
list_add_rcu
(
&
primary_orig_node
->
bond_list
,
&
router
->
bonding_list
);
spin_unlock_bh
(
&
primary_orig_node
->
neigh_list_lock
);
}
else
{
/* if bonding is disabled, use the best of the
* remaining candidates which are not using
* this interface. */
list_for_each_entry_rcu
(
tmp_neigh_node
,
&
primary_orig_node
->
bond_list
,
bonding_list
)
{
if
(
!
first_candidate
)
first_candidate
=
tmp_neigh_node
;
/* recv_if == NULL on the first node. */
if
(
tmp_neigh_node
->
if_incoming
==
recv_if
)
continue
;
if
(
!
atomic_inc_not_zero
(
&
tmp_neigh_node
->
refcount
))
if
(
bonding_enabled
)
continue
;
router
=
find_bond_router
(
primary_orig_node
,
recv_if
);
else
/* if we don't have a router yet
router
=
find_ifalter_router
(
primary_orig_node
,
recv_if
);
* or this one is better, choose it. */
if
((
!
router
)
||
(
tmp_neigh_node
->
tq_avg
>
router
->
tq_avg
))
{
/* decrement refcount of
* previously selected router */
if
(
router
)
neigh_node_free_ref
(
router
);
router
=
tmp_neigh_node
;
atomic_inc_not_zero
(
&
router
->
refcount
);
}
neigh_node_free_ref
(
tmp_neigh_node
);
}
/* use the first candidate if nothing was found. */
if
(
!
router
&&
first_candidate
&&
atomic_inc_not_zero
(
&
first_candidate
->
refcount
))
router
=
first_candidate
;
}
return_router:
return_router:
rcu_read_unlock
();
rcu_read_unlock
();
return
router
;
return
router
;
...
...
net/batman-adv/send.c
View file @
9c6bc165
...
@@ -308,6 +308,7 @@ void schedule_forward_packet(struct orig_node *orig_node,
...
@@ -308,6 +308,7 @@ void schedule_forward_packet(struct orig_node *orig_node,
struct
hard_iface
*
if_incoming
)
struct
hard_iface
*
if_incoming
)
{
{
struct
bat_priv
*
bat_priv
=
netdev_priv
(
if_incoming
->
soft_iface
);
struct
bat_priv
*
bat_priv
=
netdev_priv
(
if_incoming
->
soft_iface
);
struct
neigh_node
*
router
;
unsigned
char
in_tq
,
in_ttl
,
tq_avg
=
0
;
unsigned
char
in_tq
,
in_ttl
,
tq_avg
=
0
;
unsigned
long
send_time
;
unsigned
long
send_time
;
...
@@ -316,6 +317,8 @@ void schedule_forward_packet(struct orig_node *orig_node,
...
@@ -316,6 +317,8 @@ void schedule_forward_packet(struct orig_node *orig_node,
return
;
return
;
}
}
router
=
orig_node_get_router
(
orig_node
);
in_tq
=
batman_packet
->
tq
;
in_tq
=
batman_packet
->
tq
;
in_ttl
=
batman_packet
->
ttl
;
in_ttl
=
batman_packet
->
ttl
;
...
@@ -324,20 +327,22 @@ void schedule_forward_packet(struct orig_node *orig_node,
...
@@ -324,20 +327,22 @@ void schedule_forward_packet(struct orig_node *orig_node,
/* rebroadcast tq of our best ranking neighbor to ensure the rebroadcast
/* rebroadcast tq of our best ranking neighbor to ensure the rebroadcast
* of our best tq value */
* of our best tq value */
if
(
(
orig_node
->
router
)
&&
(
orig_node
->
router
->
tq_avg
!=
0
)
)
{
if
(
router
&&
router
->
tq_avg
!=
0
)
{
/* rebroadcast ogm of best ranking neighbor as is */
/* rebroadcast ogm of best ranking neighbor as is */
if
(
!
compare_eth
(
orig_node
->
router
->
addr
,
ethhdr
->
h_source
))
{
if
(
!
compare_eth
(
router
->
addr
,
ethhdr
->
h_source
))
{
batman_packet
->
tq
=
orig_node
->
router
->
tq_avg
;
batman_packet
->
tq
=
router
->
tq_avg
;
if
(
orig_node
->
router
->
last_ttl
)
if
(
router
->
last_ttl
)
batman_packet
->
ttl
=
orig_node
->
router
->
last_ttl
batman_packet
->
ttl
=
router
->
last_ttl
-
1
;
-
1
;
}
}
tq_avg
=
orig_node
->
router
->
tq_avg
;
tq_avg
=
router
->
tq_avg
;
}
}
if
(
router
)
neigh_node_free_ref
(
router
);
/* apply hop penalty */
/* apply hop penalty */
batman_packet
->
tq
=
hop_penalty
(
batman_packet
->
tq
,
bat_priv
);
batman_packet
->
tq
=
hop_penalty
(
batman_packet
->
tq
,
bat_priv
);
...
...
net/batman-adv/soft-interface.c
View file @
9c6bc165
...
@@ -90,10 +90,51 @@ static void softif_neigh_free_ref(struct softif_neigh *softif_neigh)
...
@@ -90,10 +90,51 @@ static void softif_neigh_free_ref(struct softif_neigh *softif_neigh)
call_rcu
(
&
softif_neigh
->
rcu
,
softif_neigh_free_rcu
);
call_rcu
(
&
softif_neigh
->
rcu
,
softif_neigh_free_rcu
);
}
}
static
struct
softif_neigh
*
softif_neigh_get_selected
(
struct
bat_priv
*
bat_priv
)
{
struct
softif_neigh
*
neigh
;
rcu_read_lock
();
neigh
=
rcu_dereference
(
bat_priv
->
softif_neigh
);
if
(
neigh
&&
!
atomic_inc_not_zero
(
&
neigh
->
refcount
))
neigh
=
NULL
;
rcu_read_unlock
();
return
neigh
;
}
static
void
softif_neigh_select
(
struct
bat_priv
*
bat_priv
,
struct
softif_neigh
*
new_neigh
)
{
struct
softif_neigh
*
curr_neigh
;
spin_lock_bh
(
&
bat_priv
->
softif_neigh_lock
);
if
(
new_neigh
&&
!
atomic_inc_not_zero
(
&
new_neigh
->
refcount
))
new_neigh
=
NULL
;
curr_neigh
=
bat_priv
->
softif_neigh
;
rcu_assign_pointer
(
bat_priv
->
softif_neigh
,
new_neigh
);
if
(
curr_neigh
)
softif_neigh_free_ref
(
curr_neigh
);
spin_unlock_bh
(
&
bat_priv
->
softif_neigh_lock
);
}
static
void
softif_neigh_deselect
(
struct
bat_priv
*
bat_priv
)
{
softif_neigh_select
(
bat_priv
,
NULL
);
}
void
softif_neigh_purge
(
struct
bat_priv
*
bat_priv
)
void
softif_neigh_purge
(
struct
bat_priv
*
bat_priv
)
{
{
struct
softif_neigh
*
softif_neigh
,
*
softif_neigh_tmp
;
struct
softif_neigh
*
softif_neigh
,
*
curr_softif_neigh
;
struct
hlist_node
*
node
,
*
node_tmp
;
struct
hlist_node
*
node
,
*
node_tmp
;
char
do_deselect
=
0
;
curr_softif_neigh
=
softif_neigh_get_selected
(
bat_priv
);
spin_lock_bh
(
&
bat_priv
->
softif_neigh_lock
);
spin_lock_bh
(
&
bat_priv
->
softif_neigh_lock
);
...
@@ -105,22 +146,26 @@ void softif_neigh_purge(struct bat_priv *bat_priv)
...
@@ -105,22 +146,26 @@ void softif_neigh_purge(struct bat_priv *bat_priv)
(
atomic_read
(
&
bat_priv
->
mesh_state
)
==
MESH_ACTIVE
))
(
atomic_read
(
&
bat_priv
->
mesh_state
)
==
MESH_ACTIVE
))
continue
;
continue
;
hlist_del_rcu
(
&
softif_neigh
->
list
);
if
(
curr_softif_neigh
==
softif_neigh
)
{
if
(
bat_priv
->
softif_neigh
==
softif_neigh
)
{
bat_dbg
(
DBG_ROUTES
,
bat_priv
,
bat_dbg
(
DBG_ROUTES
,
bat_priv
,
"Current mesh exit point '%pM' vanished "
"Current mesh exit point '%pM' vanished "
"(vid: %d).
\n
"
,
"(vid: %d).
\n
"
,
softif_neigh
->
addr
,
softif_neigh
->
vid
);
softif_neigh
->
addr
,
softif_neigh
->
vid
);
softif_neigh_tmp
=
bat_priv
->
softif_neigh
;
do_deselect
=
1
;
bat_priv
->
softif_neigh
=
NULL
;
softif_neigh_free_ref
(
softif_neigh_tmp
);
}
}
hlist_del_rcu
(
&
softif_neigh
->
list
);
softif_neigh_free_ref
(
softif_neigh
);
softif_neigh_free_ref
(
softif_neigh
);
}
}
spin_unlock_bh
(
&
bat_priv
->
softif_neigh_lock
);
spin_unlock_bh
(
&
bat_priv
->
softif_neigh_lock
);
/* soft_neigh_deselect() needs to acquire the softif_neigh_lock */
if
(
do_deselect
)
softif_neigh_deselect
(
bat_priv
);
if
(
curr_softif_neigh
)
softif_neigh_free_ref
(
curr_softif_neigh
);
}
}
static
struct
softif_neigh
*
softif_neigh_get
(
struct
bat_priv
*
bat_priv
,
static
struct
softif_neigh
*
softif_neigh_get
(
struct
bat_priv
*
bat_priv
,
...
@@ -171,6 +216,7 @@ int softif_neigh_seq_print_text(struct seq_file *seq, void *offset)
...
@@ -171,6 +216,7 @@ int softif_neigh_seq_print_text(struct seq_file *seq, void *offset)
struct
bat_priv
*
bat_priv
=
netdev_priv
(
net_dev
);
struct
bat_priv
*
bat_priv
=
netdev_priv
(
net_dev
);
struct
softif_neigh
*
softif_neigh
;
struct
softif_neigh
*
softif_neigh
;
struct
hlist_node
*
node
;
struct
hlist_node
*
node
;
struct
softif_neigh
*
curr_softif_neigh
;
if
(
!
bat_priv
->
primary_if
)
{
if
(
!
bat_priv
->
primary_if
)
{
return
seq_printf
(
seq
,
"BATMAN mesh %s disabled - "
return
seq_printf
(
seq
,
"BATMAN mesh %s disabled - "
...
@@ -180,14 +226,17 @@ int softif_neigh_seq_print_text(struct seq_file *seq, void *offset)
...
@@ -180,14 +226,17 @@ int softif_neigh_seq_print_text(struct seq_file *seq, void *offset)
seq_printf
(
seq
,
"Softif neighbor list (%s)
\n
"
,
net_dev
->
name
);
seq_printf
(
seq
,
"Softif neighbor list (%s)
\n
"
,
net_dev
->
name
);
curr_softif_neigh
=
softif_neigh_get_selected
(
bat_priv
);
rcu_read_lock
();
rcu_read_lock
();
hlist_for_each_entry_rcu
(
softif_neigh
,
node
,
hlist_for_each_entry_rcu
(
softif_neigh
,
node
,
&
bat_priv
->
softif_neigh_list
,
list
)
&
bat_priv
->
softif_neigh_list
,
list
)
seq_printf
(
seq
,
"%s %pM (vid: %d)
\n
"
,
seq_printf
(
seq
,
"%s %pM (vid: %d)
\n
"
,
bat_priv
->
softif_neigh
==
softif_neigh
curr_
softif_neigh
==
softif_neigh
?
"=>"
:
" "
,
softif_neigh
->
addr
,
?
"=>"
:
" "
,
softif_neigh
->
addr
,
softif_neigh
->
vid
);
softif_neigh
->
vid
);
rcu_read_unlock
();
rcu_read_unlock
();
if
(
curr_softif_neigh
)
softif_neigh_free_ref
(
curr_softif_neigh
);
return
0
;
return
0
;
}
}
...
@@ -198,7 +247,8 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev,
...
@@ -198,7 +247,8 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev,
struct
bat_priv
*
bat_priv
=
netdev_priv
(
dev
);
struct
bat_priv
*
bat_priv
=
netdev_priv
(
dev
);
struct
ethhdr
*
ethhdr
=
(
struct
ethhdr
*
)
skb
->
data
;
struct
ethhdr
*
ethhdr
=
(
struct
ethhdr
*
)
skb
->
data
;
struct
batman_packet
*
batman_packet
;
struct
batman_packet
*
batman_packet
;
struct
softif_neigh
*
softif_neigh
,
*
softif_neigh_tmp
;
struct
softif_neigh
*
softif_neigh
;
struct
softif_neigh
*
curr_softif_neigh
=
NULL
;
if
(
ntohs
(
ethhdr
->
h_proto
)
==
ETH_P_8021Q
)
if
(
ntohs
(
ethhdr
->
h_proto
)
==
ETH_P_8021Q
)
batman_packet
=
(
struct
batman_packet
*
)
batman_packet
=
(
struct
batman_packet
*
)
...
@@ -223,7 +273,8 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev,
...
@@ -223,7 +273,8 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev,
if
(
!
softif_neigh
)
if
(
!
softif_neigh
)
goto
err
;
goto
err
;
if
(
bat_priv
->
softif_neigh
==
softif_neigh
)
curr_softif_neigh
=
softif_neigh_get_selected
(
bat_priv
);
if
(
curr_softif_neigh
==
softif_neigh
)
goto
out
;
goto
out
;
/* we got a neighbor but its mac is 'bigger' than ours */
/* we got a neighbor but its mac is 'bigger' than ours */
...
@@ -232,38 +283,39 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev,
...
@@ -232,38 +283,39 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev,
goto
out
;
goto
out
;
/* switch to new 'smallest neighbor' */
/* switch to new 'smallest neighbor' */
if
((
bat_priv
->
softif_neigh
)
&&
if
((
curr_
softif_neigh
)
&&
(
memcmp
(
softif_neigh
->
addr
,
bat_priv
->
softif_neigh
->
addr
,
(
memcmp
(
softif_neigh
->
addr
,
curr_
softif_neigh
->
addr
,
ETH_ALEN
)
<
0
))
{
ETH_ALEN
)
<
0
))
{
bat_dbg
(
DBG_ROUTES
,
bat_priv
,
bat_dbg
(
DBG_ROUTES
,
bat_priv
,
"Changing mesh exit point from %pM (vid: %d) "
"Changing mesh exit point from %pM (vid: %d) "
"to %pM (vid: %d).
\n
"
,
"to %pM (vid: %d).
\n
"
,
bat_priv
->
softif_neigh
->
addr
,
curr_
softif_neigh
->
addr
,
bat_priv
->
softif_neigh
->
vid
,
curr_
softif_neigh
->
vid
,
softif_neigh
->
addr
,
softif_neigh
->
vid
);
softif_neigh
->
addr
,
softif_neigh
->
vid
);
softif_neigh_tmp
=
bat_priv
->
softif_neigh
;
bat_priv
->
softif_neigh
=
softif_neigh
;
softif_neigh_select
(
bat_priv
,
softif_neigh
);
softif_neigh_free_ref
(
softif_neigh_tmp
);
goto
out
;
/* we need to hold the additional reference */
goto
err
;
}
}
/* close own batX device and use softif_neigh as exit node */
/* close own batX device and use softif_neigh as exit node */
if
((
!
bat_priv
->
softif_neigh
)
&&
if
((
!
curr_
softif_neigh
)
&&
(
memcmp
(
softif_neigh
->
addr
,
(
memcmp
(
softif_neigh
->
addr
,
bat_priv
->
primary_if
->
net_dev
->
dev_addr
,
ETH_ALEN
)
<
0
))
{
bat_priv
->
primary_if
->
net_dev
->
dev_addr
,
ETH_ALEN
)
<
0
))
{
bat_dbg
(
DBG_ROUTES
,
bat_priv
,
bat_dbg
(
DBG_ROUTES
,
bat_priv
,
"Setting mesh exit point to %pM (vid: %d).
\n
"
,
"Setting mesh exit point to %pM (vid: %d).
\n
"
,
softif_neigh
->
addr
,
softif_neigh
->
vid
);
softif_neigh
->
addr
,
softif_neigh
->
vid
);
bat_priv
->
softif_neigh
=
softif_neigh
;
/* we need to hold the additional reference */
softif_neigh_select
(
bat_priv
,
softif_neigh
);
goto
err
;
goto
out
;
}
}
out:
out:
softif_neigh_free_ref
(
softif_neigh
);
softif_neigh_free_ref
(
softif_neigh
);
err:
err:
kfree_skb
(
skb
);
kfree_skb
(
skb
);
if
(
curr_softif_neigh
)
softif_neigh_free_ref
(
curr_softif_neigh
);
return
;
return
;
}
}
...
@@ -321,6 +373,7 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
...
@@ -321,6 +373,7 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
struct
bat_priv
*
bat_priv
=
netdev_priv
(
soft_iface
);
struct
bat_priv
*
bat_priv
=
netdev_priv
(
soft_iface
);
struct
bcast_packet
*
bcast_packet
;
struct
bcast_packet
*
bcast_packet
;
struct
vlan_ethhdr
*
vhdr
;
struct
vlan_ethhdr
*
vhdr
;
struct
softif_neigh
*
curr_softif_neigh
=
NULL
;
int
data_len
=
skb
->
len
,
ret
;
int
data_len
=
skb
->
len
,
ret
;
short
vid
=
-
1
;
short
vid
=
-
1
;
bool
do_bcast
=
false
;
bool
do_bcast
=
false
;
...
@@ -348,7 +401,8 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
...
@@ -348,7 +401,8 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
* if we have a another chosen mesh exit node in range
* if we have a another chosen mesh exit node in range
* it will transport the packets to the mesh
* it will transport the packets to the mesh
*/
*/
if
((
bat_priv
->
softif_neigh
)
&&
(
bat_priv
->
softif_neigh
->
vid
==
vid
))
curr_softif_neigh
=
softif_neigh_get_selected
(
bat_priv
);
if
((
curr_softif_neigh
)
&&
(
curr_softif_neigh
->
vid
==
vid
))
goto
dropped
;
goto
dropped
;
/* TODO: check this for locks */
/* TODO: check this for locks */
...
@@ -410,6 +464,8 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
...
@@ -410,6 +464,8 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
dropped_freed:
dropped_freed:
bat_priv
->
stats
.
tx_dropped
++
;
bat_priv
->
stats
.
tx_dropped
++
;
end:
end:
if
(
curr_softif_neigh
)
softif_neigh_free_ref
(
curr_softif_neigh
);
return
NETDEV_TX_OK
;
return
NETDEV_TX_OK
;
}
}
...
@@ -421,6 +477,7 @@ void interface_rx(struct net_device *soft_iface,
...
@@ -421,6 +477,7 @@ void interface_rx(struct net_device *soft_iface,
struct
unicast_packet
*
unicast_packet
;
struct
unicast_packet
*
unicast_packet
;
struct
ethhdr
*
ethhdr
;
struct
ethhdr
*
ethhdr
;
struct
vlan_ethhdr
*
vhdr
;
struct
vlan_ethhdr
*
vhdr
;
struct
softif_neigh
*
curr_softif_neigh
=
NULL
;
short
vid
=
-
1
;
short
vid
=
-
1
;
int
ret
;
int
ret
;
...
@@ -450,7 +507,8 @@ void interface_rx(struct net_device *soft_iface,
...
@@ -450,7 +507,8 @@ void interface_rx(struct net_device *soft_iface,
* if we have a another chosen mesh exit node in range
* if we have a another chosen mesh exit node in range
* it will transport the packets to the non-mesh network
* it will transport the packets to the non-mesh network
*/
*/
if
((
bat_priv
->
softif_neigh
)
&&
(
bat_priv
->
softif_neigh
->
vid
==
vid
))
{
curr_softif_neigh
=
softif_neigh_get_selected
(
bat_priv
);
if
(
curr_softif_neigh
&&
(
curr_softif_neigh
->
vid
==
vid
))
{
skb_push
(
skb
,
hdr_size
);
skb_push
(
skb
,
hdr_size
);
unicast_packet
=
(
struct
unicast_packet
*
)
skb
->
data
;
unicast_packet
=
(
struct
unicast_packet
*
)
skb
->
data
;
...
@@ -461,7 +519,7 @@ void interface_rx(struct net_device *soft_iface,
...
@@ -461,7 +519,7 @@ void interface_rx(struct net_device *soft_iface,
skb_reset_mac_header
(
skb
);
skb_reset_mac_header
(
skb
);
memcpy
(
unicast_packet
->
dest
,
memcpy
(
unicast_packet
->
dest
,
bat_priv
->
softif_neigh
->
addr
,
ETH_ALEN
);
curr_
softif_neigh
->
addr
,
ETH_ALEN
);
ret
=
route_unicast_packet
(
skb
,
recv_if
);
ret
=
route_unicast_packet
(
skb
,
recv_if
);
if
(
ret
==
NET_RX_DROP
)
if
(
ret
==
NET_RX_DROP
)
goto
dropped
;
goto
dropped
;
...
@@ -486,11 +544,13 @@ void interface_rx(struct net_device *soft_iface,
...
@@ -486,11 +544,13 @@ void interface_rx(struct net_device *soft_iface,
soft_iface
->
last_rx
=
jiffies
;
soft_iface
->
last_rx
=
jiffies
;
netif_rx
(
skb
);
netif_rx
(
skb
);
return
;
goto
out
;
dropped:
dropped:
kfree_skb
(
skb
);
kfree_skb
(
skb
);
out:
out:
if
(
curr_softif_neigh
)
softif_neigh_free_ref
(
curr_softif_neigh
);
return
;
return
;
}
}
...
@@ -524,6 +584,7 @@ static void interface_setup(struct net_device *dev)
...
@@ -524,6 +584,7 @@ static void interface_setup(struct net_device *dev)
dev
->
hard_start_xmit
=
interface_tx
;
dev
->
hard_start_xmit
=
interface_tx
;
#endif
#endif
dev
->
destructor
=
free_netdev
;
dev
->
destructor
=
free_netdev
;
dev
->
tx_queue_len
=
0
;
/**
/**
* can't call min_mtu, because the needed variables
* can't call min_mtu, because the needed variables
...
...
net/batman-adv/types.h
View file @
9c6bc165
...
@@ -67,7 +67,7 @@ struct hard_iface {
...
@@ -67,7 +67,7 @@ struct hard_iface {
struct
orig_node
{
struct
orig_node
{
uint8_t
orig
[
ETH_ALEN
];
uint8_t
orig
[
ETH_ALEN
];
uint8_t
primary_addr
[
ETH_ALEN
];
uint8_t
primary_addr
[
ETH_ALEN
];
struct
neigh_node
*
router
;
struct
neigh_node
__rcu
*
router
;
/* rcu protected pointer */
unsigned
long
*
bcast_own
;
unsigned
long
*
bcast_own
;
uint8_t
*
bcast_own_sum
;
uint8_t
*
bcast_own_sum
;
unsigned
long
last_valid
;
unsigned
long
last_valid
;
...
@@ -83,7 +83,7 @@ struct orig_node {
...
@@ -83,7 +83,7 @@ struct orig_node {
uint32_t
last_bcast_seqno
;
uint32_t
last_bcast_seqno
;
struct
hlist_head
neigh_list
;
struct
hlist_head
neigh_list
;
struct
list_head
frag_list
;
struct
list_head
frag_list
;
spinlock_t
neigh_list_lock
;
/* protects neigh
bor list
*/
spinlock_t
neigh_list_lock
;
/* protects neigh
_list and router
*/
atomic_t
refcount
;
atomic_t
refcount
;
struct
rcu_head
rcu
;
struct
rcu_head
rcu
;
struct
hlist_node
hash_entry
;
struct
hlist_node
hash_entry
;
...
@@ -125,6 +125,7 @@ struct neigh_node {
...
@@ -125,6 +125,7 @@ struct neigh_node {
struct
rcu_head
rcu
;
struct
rcu_head
rcu
;
struct
orig_node
*
orig_node
;
struct
orig_node
*
orig_node
;
struct
hard_iface
*
if_incoming
;
struct
hard_iface
*
if_incoming
;
spinlock_t
tq_lock
;
/* protects: tq_recv, tq_index */
};
};
...
@@ -146,7 +147,7 @@ struct bat_priv {
...
@@ -146,7 +147,7 @@ struct bat_priv {
atomic_t
batman_queue_left
;
atomic_t
batman_queue_left
;
char
num_ifaces
;
char
num_ifaces
;
struct
hlist_head
softif_neigh_list
;
struct
hlist_head
softif_neigh_list
;
struct
softif_neigh
*
softif_neigh
;
struct
softif_neigh
__rcu
*
softif_neigh
;
struct
debug_log
*
debug_log
;
struct
debug_log
*
debug_log
;
struct
hard_iface
*
primary_if
;
struct
hard_iface
*
primary_if
;
struct
kobject
*
mesh_obj
;
struct
kobject
*
mesh_obj
;
...
...
net/batman-adv/unicast.c
View file @
9c6bc165
...
@@ -289,7 +289,7 @@ int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv)
...
@@ -289,7 +289,7 @@ int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv)
/* get routing information */
/* get routing information */
if
(
is_multicast_ether_addr
(
ethhdr
->
h_dest
))
{
if
(
is_multicast_ether_addr
(
ethhdr
->
h_dest
))
{
orig_node
=
(
struct
orig_node
*
)
gw_get_selected
(
bat_priv
);
orig_node
=
(
struct
orig_node
*
)
gw_get_selected
_orig
(
bat_priv
);
if
(
orig_node
)
if
(
orig_node
)
goto
find_router
;
goto
find_router
;
}
}
...
...
net/batman-adv/vis.c
View file @
9c6bc165
...
@@ -558,6 +558,7 @@ static int find_best_vis_server(struct bat_priv *bat_priv,
...
@@ -558,6 +558,7 @@ static int find_best_vis_server(struct bat_priv *bat_priv,
struct
vis_info
*
info
)
struct
vis_info
*
info
)
{
{
struct
hashtable_t
*
hash
=
bat_priv
->
orig_hash
;
struct
hashtable_t
*
hash
=
bat_priv
->
orig_hash
;
struct
neigh_node
*
router
;
struct
hlist_node
*
node
;
struct
hlist_node
*
node
;
struct
hlist_head
*
head
;
struct
hlist_head
*
head
;
struct
orig_node
*
orig_node
;
struct
orig_node
*
orig_node
;
...
@@ -571,13 +572,17 @@ static int find_best_vis_server(struct bat_priv *bat_priv,
...
@@ -571,13 +572,17 @@ static int find_best_vis_server(struct bat_priv *bat_priv,
rcu_read_lock
();
rcu_read_lock
();
hlist_for_each_entry_rcu
(
orig_node
,
node
,
head
,
hash_entry
)
{
hlist_for_each_entry_rcu
(
orig_node
,
node
,
head
,
hash_entry
)
{
if
((
orig_node
)
&&
(
orig_node
->
router
)
&&
router
=
orig_node_get_router
(
orig_node
);
(
orig_node
->
flags
&
VIS_SERVER
)
&&
if
(
!
router
)
(
orig_node
->
router
->
tq_avg
>
best_tq
))
{
continue
;
best_tq
=
orig_node
->
router
->
tq_avg
;
if
((
orig_node
->
flags
&
VIS_SERVER
)
&&
(
router
->
tq_avg
>
best_tq
))
{
best_tq
=
router
->
tq_avg
;
memcpy
(
packet
->
target_orig
,
orig_node
->
orig
,
memcpy
(
packet
->
target_orig
,
orig_node
->
orig
,
ETH_ALEN
);
ETH_ALEN
);
}
}
neigh_node_free_ref
(
router
);
}
}
rcu_read_unlock
();
rcu_read_unlock
();
}
}
...
@@ -605,7 +610,7 @@ static int generate_vis_packet(struct bat_priv *bat_priv)
...
@@ -605,7 +610,7 @@ static int generate_vis_packet(struct bat_priv *bat_priv)
struct
hlist_node
*
node
;
struct
hlist_node
*
node
;
struct
hlist_head
*
head
;
struct
hlist_head
*
head
;
struct
orig_node
*
orig_node
;
struct
orig_node
*
orig_node
;
struct
neigh_node
*
neigh_node
;
struct
neigh_node
*
router
;
struct
vis_info
*
info
=
(
struct
vis_info
*
)
bat_priv
->
my_vis_info
;
struct
vis_info
*
info
=
(
struct
vis_info
*
)
bat_priv
->
my_vis_info
;
struct
vis_packet
*
packet
=
(
struct
vis_packet
*
)
info
->
skb_packet
->
data
;
struct
vis_packet
*
packet
=
(
struct
vis_packet
*
)
info
->
skb_packet
->
data
;
struct
vis_info_entry
*
entry
;
struct
vis_info_entry
*
entry
;
...
@@ -633,30 +638,32 @@ static int generate_vis_packet(struct bat_priv *bat_priv)
...
@@ -633,30 +638,32 @@ static int generate_vis_packet(struct bat_priv *bat_priv)
rcu_read_lock
();
rcu_read_lock
();
hlist_for_each_entry_rcu
(
orig_node
,
node
,
head
,
hash_entry
)
{
hlist_for_each_entry_rcu
(
orig_node
,
node
,
head
,
hash_entry
)
{
neigh_node
=
orig_node
->
router
;
router
=
orig_node_get_router
(
orig_node
);
if
(
!
router
)
if
(
!
neigh_node
)
continue
;
continue
;
if
(
!
compare_eth
(
neigh_node
->
addr
,
orig_node
->
orig
))
if
(
!
compare_eth
(
router
->
addr
,
orig_node
->
orig
))
continue
;
goto
next
;
if
(
neigh_node
->
if_incoming
->
if_status
!=
IF_ACTIVE
)
if
(
router
->
if_incoming
->
if_status
!=
IF_ACTIVE
)
continue
;
goto
next
;
if
(
neigh_node
->
tq_avg
<
1
)
if
(
router
->
tq_avg
<
1
)
continue
;
goto
next
;
/* fill one entry into buffer. */
/* fill one entry into buffer. */
entry
=
(
struct
vis_info_entry
*
)
entry
=
(
struct
vis_info_entry
*
)
skb_put
(
info
->
skb_packet
,
sizeof
(
*
entry
));
skb_put
(
info
->
skb_packet
,
sizeof
(
*
entry
));
memcpy
(
entry
->
src
,
memcpy
(
entry
->
src
,
neigh_node
->
if_incoming
->
net_dev
->
dev_addr
,
router
->
if_incoming
->
net_dev
->
dev_addr
,
ETH_ALEN
);
ETH_ALEN
);
memcpy
(
entry
->
dest
,
orig_node
->
orig
,
ETH_ALEN
);
memcpy
(
entry
->
dest
,
orig_node
->
orig
,
ETH_ALEN
);
entry
->
quality
=
neigh_node
->
tq_avg
;
entry
->
quality
=
router
->
tq_avg
;
packet
->
entries
++
;
packet
->
entries
++
;
next:
neigh_node_free_ref
(
router
);
if
(
vis_packet_full
(
info
))
if
(
vis_packet_full
(
info
))
goto
unlock
;
goto
unlock
;
}
}
...
@@ -725,6 +732,7 @@ static void purge_vis_packets(struct bat_priv *bat_priv)
...
@@ -725,6 +732,7 @@ static void purge_vis_packets(struct bat_priv *bat_priv)
static
void
broadcast_vis_packet
(
struct
bat_priv
*
bat_priv
,
static
void
broadcast_vis_packet
(
struct
bat_priv
*
bat_priv
,
struct
vis_info
*
info
)
struct
vis_info
*
info
)
{
{
struct
neigh_node
*
router
;
struct
hashtable_t
*
hash
=
bat_priv
->
orig_hash
;
struct
hashtable_t
*
hash
=
bat_priv
->
orig_hash
;
struct
hlist_node
*
node
;
struct
hlist_node
*
node
;
struct
hlist_head
*
head
;
struct
hlist_head
*
head
;
...
@@ -745,19 +753,26 @@ static void broadcast_vis_packet(struct bat_priv *bat_priv,
...
@@ -745,19 +753,26 @@ static void broadcast_vis_packet(struct bat_priv *bat_priv,
rcu_read_lock
();
rcu_read_lock
();
hlist_for_each_entry_rcu
(
orig_node
,
node
,
head
,
hash_entry
)
{
hlist_for_each_entry_rcu
(
orig_node
,
node
,
head
,
hash_entry
)
{
/* if it's a vis server and reachable, send it. */
/* if it's a vis server and reachable, send it. */
if
((
!
orig_node
)
||
(
!
orig_node
->
router
))
continue
;
if
(
!
(
orig_node
->
flags
&
VIS_SERVER
))
if
(
!
(
orig_node
->
flags
&
VIS_SERVER
))
continue
;
continue
;
router
=
orig_node_get_router
(
orig_node
);
if
(
!
router
)
continue
;
/* don't send it if we already received the packet from
/* don't send it if we already received the packet from
* this node. */
* this node. */
if
(
recv_list_is_in
(
bat_priv
,
&
info
->
recv_list
,
if
(
recv_list_is_in
(
bat_priv
,
&
info
->
recv_list
,
orig_node
->
orig
))
orig_node
->
orig
))
{
neigh_node_free_ref
(
router
);
continue
;
continue
;
}
memcpy
(
packet
->
target_orig
,
orig_node
->
orig
,
ETH_ALEN
);
memcpy
(
packet
->
target_orig
,
orig_node
->
orig
,
ETH_ALEN
);
hard_iface
=
orig_node
->
router
->
if_incoming
;
hard_iface
=
router
->
if_incoming
;
memcpy
(
dstaddr
,
orig_node
->
router
->
addr
,
ETH_ALEN
);
memcpy
(
dstaddr
,
router
->
addr
,
ETH_ALEN
);
neigh_node_free_ref
(
router
);
skb
=
skb_clone
(
info
->
skb_packet
,
GFP_ATOMIC
);
skb
=
skb_clone
(
info
->
skb_packet
,
GFP_ATOMIC
);
if
(
skb
)
if
(
skb
)
...
@@ -772,45 +787,29 @@ static void unicast_vis_packet(struct bat_priv *bat_priv,
...
@@ -772,45 +787,29 @@ static void unicast_vis_packet(struct bat_priv *bat_priv,
struct
vis_info
*
info
)
struct
vis_info
*
info
)
{
{
struct
orig_node
*
orig_node
;
struct
orig_node
*
orig_node
;
struct
neigh_node
*
neigh_node
=
NULL
;
struct
neigh_node
*
router
=
NULL
;
struct
sk_buff
*
skb
;
struct
sk_buff
*
skb
;
struct
vis_packet
*
packet
;
struct
vis_packet
*
packet
;
packet
=
(
struct
vis_packet
*
)
info
->
skb_packet
->
data
;
packet
=
(
struct
vis_packet
*
)
info
->
skb_packet
->
data
;
rcu_read_lock
();
orig_node
=
orig_hash_find
(
bat_priv
,
packet
->
target_orig
);
orig_node
=
orig_hash_find
(
bat_priv
,
packet
->
target_orig
);
if
(
!
orig_node
)
if
(
!
orig_node
)
goto
unlock
;
goto
out
;
neigh_node
=
orig_node
->
router
;
router
=
orig_node_get_router
(
orig_node
);
if
(
!
router
)
if
(
!
neigh_node
)
goto
out
;
goto
unlock
;
if
(
!
atomic_inc_not_zero
(
&
neigh_node
->
refcount
))
{
neigh_node
=
NULL
;
goto
unlock
;
}
rcu_read_unlock
();
skb
=
skb_clone
(
info
->
skb_packet
,
GFP_ATOMIC
);
skb
=
skb_clone
(
info
->
skb_packet
,
GFP_ATOMIC
);
if
(
skb
)
if
(
skb
)
send_skb_packet
(
skb
,
neigh_node
->
if_incoming
,
send_skb_packet
(
skb
,
router
->
if_incoming
,
router
->
addr
);
neigh_node
->
addr
);
goto
out
;
unlock:
rcu_read_unlock
();
out:
out:
if
(
neigh_node
)
if
(
router
)
neigh_node_free_ref
(
neigh_node
);
neigh_node_free_ref
(
router
);
if
(
orig_node
)
if
(
orig_node
)
orig_node_free_ref
(
orig_node
);
orig_node_free_ref
(
orig_node
);
return
;
}
}
/* only send one vis packet. called from send_vis_packets() */
/* only send one vis packet. called from send_vis_packets() */
...
...
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