Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
raspberrypi-kernel
提交
eac56465
R
raspberrypi-kernel
项目概览
openeuler
/
raspberrypi-kernel
通知
13
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
raspberrypi-kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
eac56465
编写于
6月 20, 2011
作者:
D
David S. Miller
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'batman-adv/next' of
git://git.open-mesh.org/ecsv/linux-merge
上级
1b9c4134
43676ab5
变更
27
展开全部
隐藏空白更改
内联
并排
Showing
27 changed file
with
2080 addition
and
462 deletion
+2080
-462
net/batman-adv/Kconfig
net/batman-adv/Kconfig
+1
-0
net/batman-adv/aggregation.c
net/batman-adv/aggregation.c
+11
-14
net/batman-adv/aggregation.h
net/batman-adv/aggregation.h
+5
-3
net/batman-adv/bat_sysfs.c
net/batman-adv/bat_sysfs.c
+72
-1
net/batman-adv/bat_sysfs.h
net/batman-adv/bat_sysfs.h
+2
-0
net/batman-adv/bitarray.c
net/batman-adv/bitarray.c
+4
-4
net/batman-adv/bitarray.h
net/batman-adv/bitarray.h
+4
-4
net/batman-adv/gateway_client.c
net/batman-adv/gateway_client.c
+179
-59
net/batman-adv/gateway_client.h
net/batman-adv/gateway_client.h
+2
-1
net/batman-adv/gateway_common.c
net/batman-adv/gateway_common.c
+3
-3
net/batman-adv/hard-interface.c
net/batman-adv/hard-interface.c
+10
-7
net/batman-adv/main.c
net/batman-adv/main.c
+10
-8
net/batman-adv/main.h
net/batman-adv/main.h
+24
-3
net/batman-adv/originator.c
net/batman-adv/originator.c
+14
-3
net/batman-adv/originator.h
net/batman-adv/originator.h
+0
-8
net/batman-adv/packet.h
net/batman-adv/packet.h
+79
-13
net/batman-adv/routing.c
net/batman-adv/routing.c
+262
-55
net/batman-adv/routing.h
net/batman-adv/routing.h
+4
-3
net/batman-adv/send.c
net/batman-adv/send.c
+70
-22
net/batman-adv/send.h
net/batman-adv/send.h
+1
-1
net/batman-adv/soft-interface.c
net/batman-adv/soft-interface.c
+19
-7
net/batman-adv/soft-interface.h
net/batman-adv/soft-interface.h
+0
-1
net/batman-adv/translation-table.c
net/batman-adv/translation-table.c
+1206
-222
net/batman-adv/translation-table.h
net/batman-adv/translation-table.h
+30
-8
net/batman-adv/types.h
net/batman-adv/types.h
+59
-5
net/batman-adv/unicast.c
net/batman-adv/unicast.c
+3
-0
net/batman-adv/vis.c
net/batman-adv/vis.c
+6
-7
未找到文件。
net/batman-adv/Kconfig
浏览文件 @
eac56465
...
...
@@ -5,6 +5,7 @@
config BATMAN_ADV
tristate "B.A.T.M.A.N. Advanced Meshing Protocol"
depends on NET
select CRC16
default n
---help---
...
...
net/batman-adv/aggregation.c
浏览文件 @
eac56465
...
...
@@ -20,17 +20,12 @@
*/
#include "main.h"
#include "translation-table.h"
#include "aggregation.h"
#include "send.h"
#include "routing.h"
#include "hard-interface.h"
/* calculate the size of the tt information for a given packet */
static
int
tt_len
(
const
struct
batman_packet
*
batman_packet
)
{
return
batman_packet
->
num_tt
*
ETH_ALEN
;
}
/* return true if new_packet can be aggregated with forw_packet */
static
bool
can_aggregate_with
(
const
struct
batman_packet
*
new_batman_packet
,
int
packet_len
,
...
...
@@ -195,7 +190,7 @@ static void aggregate(struct forw_packet *forw_packet_aggr,
void
add_bat_packet_to_list
(
struct
bat_priv
*
bat_priv
,
unsigned
char
*
packet_buff
,
int
packet_len
,
struct
hard_iface
*
if_incoming
,
char
own_packet
,
struct
hard_iface
*
if_incoming
,
int
own_packet
,
unsigned
long
send_time
)
{
/**
...
...
@@ -264,18 +259,20 @@ void receive_aggr_bat_packet(const struct ethhdr *ethhdr,
batman_packet
=
(
struct
batman_packet
*
)
packet_buff
;
do
{
/* network to host order for our 32bit seqno
,
and the
orig_interval
.
*/
/* 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
,
tt_len
(
batman_packet
),
if_incoming
);
buff_pos
+=
BAT_PACKET_LEN
+
tt_len
(
batman_packet
);
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
->
num_tt
));
batman_packet
->
tt_num_changes
));
}
net/batman-adv/aggregation.h
浏览文件 @
eac56465
...
...
@@ -25,9 +25,11 @@
#include "main.h"
/* is there another aggregated packet here? */
static
inline
int
aggregated_packet
(
int
buff_pos
,
int
packet_len
,
int
num_tt
)
static
inline
int
aggregated_packet
(
int
buff_pos
,
int
packet_len
,
int
tt_num_changes
)
{
int
next_buff_pos
=
buff_pos
+
BAT_PACKET_LEN
+
(
num_tt
*
ETH_ALEN
);
int
next_buff_pos
=
buff_pos
+
BAT_PACKET_LEN
+
(
tt_num_changes
*
sizeof
(
struct
tt_change
));
return
(
next_buff_pos
<=
packet_len
)
&&
(
next_buff_pos
<=
MAX_AGGREGATION_BYTES
);
...
...
@@ -35,7 +37,7 @@ static inline int aggregated_packet(int buff_pos, int packet_len, int num_tt)
void
add_bat_packet_to_list
(
struct
bat_priv
*
bat_priv
,
unsigned
char
*
packet_buff
,
int
packet_len
,
struct
hard_iface
*
if_incoming
,
char
own_packet
,
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
,
...
...
net/batman-adv/bat_sysfs.c
浏览文件 @
eac56465
...
...
@@ -40,6 +40,20 @@ static struct bat_priv *kobj_to_batpriv(struct kobject *obj)
return
netdev_priv
(
net_dev
);
}
#define UEV_TYPE_VAR "BATTYPE="
#define UEV_ACTION_VAR "BATACTION="
#define UEV_DATA_VAR "BATDATA="
static
char
*
uev_action_str
[]
=
{
"add"
,
"del"
,
"change"
};
static
char
*
uev_type_str
[]
=
{
"gw"
};
/* Use this, if you have customized show and store functions */
#define BAT_ATTR(_name, _mode, _show, _store) \
struct bat_attribute bat_attr_##_name = { \
...
...
@@ -375,7 +389,7 @@ BAT_ATTR_UINT(gw_sel_class, S_IRUGO | S_IWUSR, 1, TQ_MAX_VALUE,
static
BAT_ATTR
(
gw_bandwidth
,
S_IRUGO
|
S_IWUSR
,
show_gw_bwidth
,
store_gw_bwidth
);
#ifdef CONFIG_BATMAN_ADV_DEBUG
BAT_ATTR_UINT
(
log_level
,
S_IRUGO
|
S_IWUSR
,
0
,
3
,
NULL
);
BAT_ATTR_UINT
(
log_level
,
S_IRUGO
|
S_IWUSR
,
0
,
7
,
NULL
);
#endif
static
struct
bat_attribute
*
mesh_attrs
[]
=
{
...
...
@@ -601,3 +615,60 @@ void sysfs_del_hardif(struct kobject **hardif_obj)
kobject_put
(
*
hardif_obj
);
*
hardif_obj
=
NULL
;
}
int
throw_uevent
(
struct
bat_priv
*
bat_priv
,
enum
uev_type
type
,
enum
uev_action
action
,
const
char
*
data
)
{
int
ret
=
-
1
;
struct
hard_iface
*
primary_if
=
NULL
;
struct
kobject
*
bat_kobj
;
char
*
uevent_env
[
4
]
=
{
NULL
,
NULL
,
NULL
,
NULL
};
primary_if
=
primary_if_get_selected
(
bat_priv
);
if
(
!
primary_if
)
goto
out
;
bat_kobj
=
&
primary_if
->
soft_iface
->
dev
.
kobj
;
uevent_env
[
0
]
=
kmalloc
(
strlen
(
UEV_TYPE_VAR
)
+
strlen
(
uev_type_str
[
type
])
+
1
,
GFP_ATOMIC
);
if
(
!
uevent_env
[
0
])
goto
out
;
sprintf
(
uevent_env
[
0
],
"%s%s"
,
UEV_TYPE_VAR
,
uev_type_str
[
type
]);
uevent_env
[
1
]
=
kmalloc
(
strlen
(
UEV_ACTION_VAR
)
+
strlen
(
uev_action_str
[
action
])
+
1
,
GFP_ATOMIC
);
if
(
!
uevent_env
[
1
])
goto
out
;
sprintf
(
uevent_env
[
1
],
"%s%s"
,
UEV_ACTION_VAR
,
uev_action_str
[
action
]);
/* If the event is DEL, ignore the data field */
if
(
action
!=
UEV_DEL
)
{
uevent_env
[
2
]
=
kmalloc
(
strlen
(
UEV_DATA_VAR
)
+
strlen
(
data
)
+
1
,
GFP_ATOMIC
);
if
(
!
uevent_env
[
2
])
goto
out
;
sprintf
(
uevent_env
[
2
],
"%s%s"
,
UEV_DATA_VAR
,
data
);
}
ret
=
kobject_uevent_env
(
bat_kobj
,
KOBJ_CHANGE
,
uevent_env
);
out:
kfree
(
uevent_env
[
0
]);
kfree
(
uevent_env
[
1
]);
kfree
(
uevent_env
[
2
]);
if
(
primary_if
)
hardif_free_ref
(
primary_if
);
if
(
ret
)
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"Impossible to send "
"uevent for (%s,%s,%s) event (err: %d)
\n
"
,
uev_type_str
[
type
],
uev_action_str
[
action
],
(
action
==
UEV_DEL
?
"NULL"
:
data
),
ret
);
return
ret
;
}
net/batman-adv/bat_sysfs.h
浏览文件 @
eac56465
...
...
@@ -38,5 +38,7 @@ int sysfs_add_meshif(struct net_device *dev);
void
sysfs_del_meshif
(
struct
net_device
*
dev
);
int
sysfs_add_hardif
(
struct
kobject
**
hardif_obj
,
struct
net_device
*
dev
);
void
sysfs_del_hardif
(
struct
kobject
**
hardif_obj
);
int
throw_uevent
(
struct
bat_priv
*
bat_priv
,
enum
uev_type
type
,
enum
uev_action
action
,
const
char
*
data
);
#endif
/* _NET_BATMAN_ADV_SYSFS_H_ */
net/batman-adv/bitarray.c
浏览文件 @
eac56465
...
...
@@ -26,8 +26,8 @@
/* returns true if the corresponding bit in the given seq_bits indicates true
* and curr_seqno is within range of last_seqno */
uint8_
t
get_bit_status
(
const
unsigned
long
*
seq_bits
,
uint32_t
last_seqno
,
uint32_t
curr_seqno
)
in
t
get_bit_status
(
const
unsigned
long
*
seq_bits
,
uint32_t
last_seqno
,
uint32_t
curr_seqno
)
{
int32_t
diff
,
word_offset
,
word_num
;
...
...
@@ -127,8 +127,8 @@ static void bit_reset_window(unsigned long *seq_bits)
* 1 if the window was moved (either new or very old)
* 0 if the window was not moved/shifted.
*/
char
bit_get_packet
(
void
*
priv
,
unsigned
long
*
seq_bits
,
int32_t
seq_num_diff
,
int
8_t
set_mark
)
int
bit_get_packet
(
void
*
priv
,
unsigned
long
*
seq_bits
,
int32_t
seq_num_diff
,
int
set_mark
)
{
struct
bat_priv
*
bat_priv
=
priv
;
...
...
net/batman-adv/bitarray.h
浏览文件 @
eac56465
...
...
@@ -26,8 +26,8 @@
/* returns true if the corresponding bit in the given seq_bits indicates true
* and curr_seqno is within range of last_seqno */
uint8_
t
get_bit_status
(
const
unsigned
long
*
seq_bits
,
uint32_t
last_seqno
,
uint32_t
curr_seqno
);
in
t
get_bit_status
(
const
unsigned
long
*
seq_bits
,
uint32_t
last_seqno
,
uint32_t
curr_seqno
);
/* turn corresponding bit on, so we can remember that we got the packet */
void
bit_mark
(
unsigned
long
*
seq_bits
,
int32_t
n
);
...
...
@@ -35,8 +35,8 @@ void bit_mark(unsigned long *seq_bits, int32_t n);
/* receive and process one packet, returns 1 if received seq_num is considered
* new, 0 if old */
char
bit_get_packet
(
void
*
priv
,
unsigned
long
*
seq_bits
,
int32_t
seq_num_diff
,
int8_
t
set_mark
);
int
bit_get_packet
(
void
*
priv
,
unsigned
long
*
seq_bits
,
int32_t
seq_num_diff
,
in
t
set_mark
);
/* count the hamming weight, how many good packets did we receive? */
int
bit_packet_count
(
const
unsigned
long
*
seq_bits
);
...
...
net/batman-adv/gateway_client.c
浏览文件 @
eac56465
...
...
@@ -20,15 +20,22 @@
*/
#include "main.h"
#include "bat_sysfs.h"
#include "gateway_client.h"
#include "gateway_common.h"
#include "hard-interface.h"
#include "originator.h"
#include "routing.h"
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/udp.h>
#include <linux/if_vlan.h>
/* This is the offset of the options field in a dhcp packet starting at
* the beginning of the dhcp header */
#define DHCP_OPTIONS_OFFSET 240
#define DHCP_REQUEST 3
static
void
gw_node_free_ref
(
struct
gw_node
*
gw_node
)
{
if
(
atomic_dec_and_test
(
&
gw_node
->
refcount
))
...
...
@@ -97,40 +104,19 @@ static void gw_select(struct bat_priv *bat_priv, struct gw_node *new_gw_node)
void
gw_deselect
(
struct
bat_priv
*
bat_priv
)
{
gw_select
(
bat_priv
,
NULL
);
atomic_set
(
&
bat_priv
->
gw_reselect
,
1
);
}
void
gw_election
(
struct
bat_priv
*
bat_priv
)
static
struct
gw_node
*
gw_get_best_gw_node
(
struct
bat_priv
*
bat_priv
)
{
struct
hlist_node
*
node
;
struct
gw_node
*
gw_node
,
*
curr_gw
=
NULL
,
*
curr_gw_tmp
=
NULL
;
struct
neigh_node
*
router
;
uint8_t
max_tq
=
0
;
struct
hlist_node
*
node
;
struct
gw_node
*
gw_node
,
*
curr_gw
=
NULL
;
uint32_t
max_gw_factor
=
0
,
tmp_gw_factor
=
0
;
uint8_t
max_tq
=
0
;
int
down
,
up
;
/**
* The batman daemon checks here if we already passed a full originator
* cycle in order to make sure we don't choose the first gateway we
* hear about. This check is based on the daemon's uptime which we
* don't have.
**/
if
(
atomic_read
(
&
bat_priv
->
gw_mode
)
!=
GW_MODE_CLIENT
)
return
;
curr_gw
=
gw_get_selected_gw_node
(
bat_priv
);
if
(
curr_gw
)
goto
out
;
rcu_read_lock
();
if
(
hlist_empty
(
&
bat_priv
->
gw_list
))
{
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"Removing selected gateway - "
"no gateway in range
\n
"
);
gw_deselect
(
bat_priv
);
goto
unlock
;
}
hlist_for_each_entry_rcu
(
gw_node
,
node
,
&
bat_priv
->
gw_list
,
list
)
{
if
(
gw_node
->
deleted
)
continue
;
...
...
@@ -139,6 +125,9 @@ void gw_election(struct bat_priv *bat_priv)
if
(
!
router
)
continue
;
if
(
!
atomic_inc_not_zero
(
&
gw_node
->
refcount
))
goto
next
;
switch
(
atomic_read
(
&
bat_priv
->
gw_sel_class
))
{
case
1
:
/* fast connection */
gw_bandwidth_to_kbit
(
gw_node
->
orig_node
->
gw_flags
,
...
...
@@ -151,8 +140,12 @@ void gw_election(struct bat_priv *bat_priv)
if
((
tmp_gw_factor
>
max_gw_factor
)
||
((
tmp_gw_factor
==
max_gw_factor
)
&&
(
router
->
tq_avg
>
max_tq
)))
curr_gw_tmp
=
gw_node
;
(
router
->
tq_avg
>
max_tq
)))
{
if
(
curr_gw
)
gw_node_free_ref
(
curr_gw
);
curr_gw
=
gw_node
;
atomic_inc
(
&
curr_gw
->
refcount
);
}
break
;
default:
/**
...
...
@@ -163,8 +156,12 @@ void gw_election(struct bat_priv *bat_priv)
* soon as a better gateway appears which has
* $routing_class more tq points)
**/
if
(
router
->
tq_avg
>
max_tq
)
curr_gw_tmp
=
gw_node
;
if
(
router
->
tq_avg
>
max_tq
)
{
if
(
curr_gw
)
gw_node_free_ref
(
curr_gw
);
curr_gw
=
gw_node
;
atomic_inc
(
&
curr_gw
->
refcount
);
}
break
;
}
...
...
@@ -174,42 +171,81 @@ void gw_election(struct bat_priv *bat_priv)
if
(
tmp_gw_factor
>
max_gw_factor
)
max_gw_factor
=
tmp_gw_factor
;
gw_node_free_ref
(
gw_node
);
next:
neigh_node_free_ref
(
router
);
}
rcu_read_unlock
();
if
(
curr_gw
!=
curr_gw_tmp
)
{
router
=
orig_node_get_router
(
curr_gw_tmp
->
orig_node
);
if
(
!
router
)
goto
unlock
;
return
curr_gw
;
}
if
((
curr_gw
)
&&
(
!
curr_gw_tmp
))
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"Removing selected gateway - "
"no gateway in range
\n
"
);
else
if
((
!
curr_gw
)
&&
(
curr_gw_tmp
))
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"Adding route to gateway %pM "
"(gw_flags: %i, tq: %i)
\n
"
,
curr_gw_tmp
->
orig_node
->
orig
,
curr_gw_tmp
->
orig_node
->
gw_flags
,
router
->
tq_avg
);
else
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"Changing route to gateway %pM "
"(gw_flags: %i, tq: %i)
\n
"
,
curr_gw_tmp
->
orig_node
->
orig
,
curr_gw_tmp
->
orig_node
->
gw_flags
,
router
->
tq_avg
);
void
gw_election
(
struct
bat_priv
*
bat_priv
)
{
struct
gw_node
*
curr_gw
=
NULL
,
*
next_gw
=
NULL
;
struct
neigh_node
*
router
=
NULL
;
char
gw_addr
[
18
]
=
{
'\0'
};
neigh_node_free_ref
(
router
);
gw_select
(
bat_priv
,
curr_gw_tmp
);
/**
* The batman daemon checks here if we already passed a full originator
* cycle in order to make sure we don't choose the first gateway we
* hear about. This check is based on the daemon's uptime which we
* don't have.
**/
if
(
atomic_read
(
&
bat_priv
->
gw_mode
)
!=
GW_MODE_CLIENT
)
goto
out
;
if
(
!
atomic_dec_not_zero
(
&
bat_priv
->
gw_reselect
))
goto
out
;
curr_gw
=
gw_get_selected_gw_node
(
bat_priv
);
next_gw
=
gw_get_best_gw_node
(
bat_priv
);
if
(
curr_gw
==
next_gw
)
goto
out
;
if
(
next_gw
)
{
sprintf
(
gw_addr
,
"%pM"
,
next_gw
->
orig_node
->
orig
);
router
=
orig_node_get_router
(
next_gw
->
orig_node
);
if
(
!
router
)
{
gw_deselect
(
bat_priv
);
goto
out
;
}
}
unlock:
rcu_read_unlock
();
if
((
curr_gw
)
&&
(
!
next_gw
))
{
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"Removing selected gateway - no gateway in range
\n
"
);
throw_uevent
(
bat_priv
,
UEV_GW
,
UEV_DEL
,
NULL
);
}
else
if
((
!
curr_gw
)
&&
(
next_gw
))
{
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"Adding route to gateway %pM (gw_flags: %i, tq: %i)
\n
"
,
next_gw
->
orig_node
->
orig
,
next_gw
->
orig_node
->
gw_flags
,
router
->
tq_avg
);
throw_uevent
(
bat_priv
,
UEV_GW
,
UEV_ADD
,
gw_addr
);
}
else
{
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"Changing route to gateway %pM "
"(gw_flags: %i, tq: %i)
\n
"
,
next_gw
->
orig_node
->
orig
,
next_gw
->
orig_node
->
gw_flags
,
router
->
tq_avg
);
throw_uevent
(
bat_priv
,
UEV_GW
,
UEV_CHANGE
,
gw_addr
);
}
gw_select
(
bat_priv
,
next_gw
);
out:
if
(
curr_gw
)
gw_node_free_ref
(
curr_gw
);
if
(
next_gw
)
gw_node_free_ref
(
next_gw
);
if
(
router
)
neigh_node_free_ref
(
router
);
}
void
gw_check_election
(
struct
bat_priv
*
bat_priv
,
struct
orig_node
*
orig_node
)
...
...
@@ -360,7 +396,7 @@ void gw_node_purge(struct bat_priv *bat_priv)
struct
gw_node
*
gw_node
,
*
curr_gw
;
struct
hlist_node
*
node
,
*
node_tmp
;
unsigned
long
timeout
=
2
*
PURGE_TIMEOUT
*
HZ
;
char
do_deselect
=
0
;
int
do_deselect
=
0
;
curr_gw
=
gw_get_selected_gw_node
(
bat_priv
);
...
...
@@ -479,14 +515,75 @@ int gw_client_seq_print_text(struct seq_file *seq, void *offset)
return
ret
;
}
int
gw_is_target
(
struct
bat_priv
*
bat_priv
,
struct
sk_buff
*
skb
)
static
bool
is_type_dhcprequest
(
struct
sk_buff
*
skb
,
int
header_len
)
{
int
ret
=
false
;
unsigned
char
*
p
;
int
pkt_len
;
if
(
skb_linearize
(
skb
)
<
0
)
goto
out
;
pkt_len
=
skb_headlen
(
skb
);
if
(
pkt_len
<
header_len
+
DHCP_OPTIONS_OFFSET
+
1
)
goto
out
;
p
=
skb
->
data
+
header_len
+
DHCP_OPTIONS_OFFSET
;
pkt_len
-=
header_len
+
DHCP_OPTIONS_OFFSET
+
1
;
/* Access the dhcp option lists. Each entry is made up by:
* - octect 1: option type
* - octect 2: option data len (only if type != 255 and 0)
* - octect 3: option data */
while
(
*
p
!=
255
&&
!
ret
)
{
/* p now points to the first octect: option type */
if
(
*
p
==
53
)
{
/* type 53 is the message type option.
* Jump the len octect and go to the data octect */
if
(
pkt_len
<
2
)
goto
out
;
p
+=
2
;
/* check if the message type is what we need */
if
(
*
p
==
DHCP_REQUEST
)
ret
=
true
;
break
;
}
else
if
(
*
p
==
0
)
{
/* option type 0 (padding), just go forward */
if
(
pkt_len
<
1
)
goto
out
;
pkt_len
--
;
p
++
;
}
else
{
/* This is any other option. So we get the length... */
if
(
pkt_len
<
1
)
goto
out
;
pkt_len
--
;
p
++
;
/* ...and then we jump over the data */
if
(
pkt_len
<
*
p
)
goto
out
;
pkt_len
-=
*
p
;
p
+=
(
*
p
);
}
}
out:
return
ret
;
}
int
gw_is_target
(
struct
bat_priv
*
bat_priv
,
struct
sk_buff
*
skb
,
struct
orig_node
*
old_gw
)
{
struct
ethhdr
*
ethhdr
;
struct
iphdr
*
iphdr
;
struct
ipv6hdr
*
ipv6hdr
;
struct
udphdr
*
udphdr
;
struct
gw_node
*
curr_gw
;
struct
neigh_node
*
neigh_curr
=
NULL
,
*
neigh_old
=
NULL
;
unsigned
int
header_len
=
0
;
int
ret
=
1
;
if
(
atomic_read
(
&
bat_priv
->
gw_mode
)
==
GW_MODE_OFF
)
return
0
;
...
...
@@ -554,7 +651,30 @@ int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb)
if
(
!
curr_gw
)
return
0
;
/* If old_gw != NULL then this packet is unicast.
* So, at this point we have to check the message type: if it is a
* DHCPREQUEST we have to decide whether to drop it or not */
if
(
old_gw
&&
curr_gw
->
orig_node
!=
old_gw
)
{
if
(
is_type_dhcprequest
(
skb
,
header_len
))
{
/* If the dhcp packet has been sent to a different gw,
* we have to evaluate whether the old gw is still
* reliable enough */
neigh_curr
=
find_router
(
bat_priv
,
curr_gw
->
orig_node
,
NULL
);
neigh_old
=
find_router
(
bat_priv
,
old_gw
,
NULL
);
if
(
!
neigh_curr
||
!
neigh_old
)
goto
free_neigh
;
if
(
neigh_curr
->
tq_avg
-
neigh_old
->
tq_avg
<
GW_THRESHOLD
)
ret
=
-
1
;
}
}
free_neigh:
if
(
neigh_old
)
neigh_node_free_ref
(
neigh_old
);
if
(
neigh_curr
)
neigh_node_free_ref
(
neigh_curr
);
if
(
curr_gw
)
gw_node_free_ref
(
curr_gw
);
return
1
;
return
ret
;
}
net/batman-adv/gateway_client.h
浏览文件 @
eac56465
...
...
@@ -31,6 +31,7 @@ void gw_node_update(struct bat_priv *bat_priv,
void
gw_node_delete
(
struct
bat_priv
*
bat_priv
,
struct
orig_node
*
orig_node
);
void
gw_node_purge
(
struct
bat_priv
*
bat_priv
);
int
gw_client_seq_print_text
(
struct
seq_file
*
seq
,
void
*
offset
);
int
gw_is_target
(
struct
bat_priv
*
bat_priv
,
struct
sk_buff
*
skb
);
int
gw_is_target
(
struct
bat_priv
*
bat_priv
,
struct
sk_buff
*
skb
,
struct
orig_node
*
old_gw
);
#endif
/* _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ */
net/batman-adv/gateway_common.c
浏览文件 @
eac56465
...
...
@@ -61,9 +61,9 @@ static void kbit_to_gw_bandwidth(int down, int up, long *gw_srv_class)
/* returns the up and downspeeds in kbit, calculated from the class */
void
gw_bandwidth_to_kbit
(
uint8_t
gw_srv_class
,
int
*
down
,
int
*
up
)
{
char
sbit
=
(
gw_srv_class
&
0x80
)
>>
7
;
char
dpart
=
(
gw_srv_class
&
0x78
)
>>
3
;
char
upart
=
(
gw_srv_class
&
0x07
);
int
sbit
=
(
gw_srv_class
&
0x80
)
>>
7
;
int
dpart
=
(
gw_srv_class
&
0x78
)
>>
3
;
int
upart
=
(
gw_srv_class
&
0x07
);
if
(
!
gw_srv_class
)
{
*
down
=
0
;
...
...
net/batman-adv/hard-interface.c
浏览文件 @
eac56465
...
...
@@ -152,12 +152,6 @@ static void primary_if_select(struct bat_priv *bat_priv,
batman_packet
->
ttl
=
TTL
;
primary_if_update_addr
(
bat_priv
);
/***
* hacky trick to make sure that we send the TT information via
* our new primary interface
*/
atomic_set
(
&
bat_priv
->
tt_local_changed
,
1
);
}
static
bool
hardif_is_iface_up
(
const
struct
hard_iface
*
hard_iface
)
...
...
@@ -340,7 +334,8 @@ int hardif_enable_interface(struct hard_iface *hard_iface,
batman_packet
->
flags
=
NO_FLAGS
;
batman_packet
->
ttl
=
2
;
batman_packet
->
tq
=
TQ_MAX_VALUE
;
batman_packet
->
num_tt
=
0
;
batman_packet
->
tt_num_changes
=
0
;
batman_packet
->
ttvn
=
0
;
hard_iface
->
if_num
=
bat_priv
->
num_ifaces
;
bat_priv
->
num_ifaces
++
;
...
...
@@ -659,6 +654,14 @@ static int batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
case
BAT_VIS
:
ret
=
recv_vis_packet
(
skb
,
hard_iface
);
break
;
/* Translation table query (request or response) */
case
BAT_TT_QUERY
:
ret
=
recv_tt_query
(
skb
,
hard_iface
);
break
;
/* Roaming advertisement */
case
BAT_ROAM_ADV
:
ret
=
recv_roam_adv
(
skb
,
hard_iface
);
break
;
default:
ret
=
NET_RX_DROP
;
}
...
...
net/batman-adv/main.c
浏览文件 @
eac56465
...
...
@@ -84,8 +84,10 @@ int mesh_init(struct net_device *soft_iface)
spin_lock_init
(
&
bat_priv
->
forw_bat_list_lock
);
spin_lock_init
(
&
bat_priv
->
forw_bcast_list_lock
);
spin_lock_init
(
&
bat_priv
->
tt_lhash_lock
);
spin_lock_init
(
&
bat_priv
->
tt_ghash_lock
);
spin_lock_init
(
&
bat_priv
->
tt_changes_list_lock
);
spin_lock_init
(
&
bat_priv
->
tt_req_list_lock
);
spin_lock_init
(
&
bat_priv
->
tt_roam_list_lock
);
spin_lock_init
(
&
bat_priv
->
tt_buff_lock
);
spin_lock_init
(
&
bat_priv
->
gw_list_lock
);
spin_lock_init
(
&
bat_priv
->
vis_hash_lock
);
spin_lock_init
(
&
bat_priv
->
vis_list_lock
);
...
...
@@ -96,14 +98,14 @@ int mesh_init(struct net_device *soft_iface)
INIT_HLIST_HEAD
(
&
bat_priv
->
forw_bcast_list
);
INIT_HLIST_HEAD
(
&
bat_priv
->
gw_list
);
INIT_HLIST_HEAD
(
&
bat_priv
->
softif_neigh_vids
);
INIT_LIST_HEAD
(
&
bat_priv
->
tt_changes_list
);
INIT_LIST_HEAD
(
&
bat_priv
->
tt_req_list
);
INIT_LIST_HEAD
(
&
bat_priv
->
tt_roam_list
);
if
(
originator_init
(
bat_priv
)
<
1
)
goto
err
;
if
(
tt_local_init
(
bat_priv
)
<
1
)
goto
err
;
if
(
tt_global_init
(
bat_priv
)
<
1
)
if
(
tt_init
(
bat_priv
)
<
1
)
goto
err
;
tt_local_add
(
soft_iface
,
soft_iface
->
dev_addr
);
...
...
@@ -111,6 +113,7 @@ int mesh_init(struct net_device *soft_iface)
if
(
vis_init
(
bat_priv
)
<
1
)
goto
err
;
atomic_set
(
&
bat_priv
->
gw_reselect
,
0
);
atomic_set
(
&
bat_priv
->
mesh_state
,
MESH_ACTIVE
);
goto
end
;
...
...
@@ -137,8 +140,7 @@ void mesh_free(struct net_device *soft_iface)
gw_node_purge
(
bat_priv
);
originator_free
(
bat_priv
);
tt_local_free
(
bat_priv
);
tt_global_free
(
bat_priv
);
tt_free
(
bat_priv
);
softif_neigh_purge
(
bat_priv
);
...
...
net/batman-adv/main.h
浏览文件 @
eac56465
...
...
@@ -42,15 +42,23 @@
* -> TODO: check influence on TQ_LOCAL_WINDOW_SIZE */
#define PURGE_TIMEOUT 200
#define TT_LOCAL_TIMEOUT 3600
/* in seconds */
#define TT_CLIENT_ROAM_TIMEOUT 600
/* sliding packet range of received originator messages in squence numbers
* (should be a multiple of our word size) */
#define TQ_LOCAL_WINDOW_SIZE 64
#define TT_REQUEST_TIMEOUT 3
/* seconds we have to keep pending tt_req */
#define TQ_GLOBAL_WINDOW_SIZE 5
#define TQ_LOCAL_BIDRECT_SEND_MINIMUM 1
#define TQ_LOCAL_BIDRECT_RECV_MINIMUM 1
#define TQ_TOTAL_BIDRECT_LIMIT 1
#define TT_OGM_APPEND_MAX 3
/* number of OGMs sent with the last tt diff */
#define ROAMING_MAX_TIME 20
/* Time in which a client can roam at most
* ROAMING_MAX_COUNT times */
#define ROAMING_MAX_COUNT 5
#define NO_FLAGS 0
#define NUM_WORDS (TQ_LOCAL_WINDOW_SIZE / WORD_BIT_SIZE)
...
...
@@ -83,6 +91,18 @@ enum mesh_state {
#define BCAST_QUEUE_LEN 256
#define BATMAN_QUEUE_LEN 256
enum
uev_action
{
UEV_ADD
=
0
,
UEV_DEL
,
UEV_CHANGE
};
enum
uev_type
{
UEV_GW
=
0
};
#define GW_THRESHOLD 50
/*
* Debug Messages
*/
...
...
@@ -96,7 +116,8 @@ enum mesh_state {
enum
dbg_level
{
DBG_BATMAN
=
1
<<
0
,
DBG_ROUTES
=
1
<<
1
,
/* route added / changed / deleted */
DBG_ALL
=
3
DBG_TT
=
1
<<
2
,
/* translation table operations */
DBG_ALL
=
7
};
...
...
@@ -151,7 +172,7 @@ int debug_log(struct bat_priv *bat_priv, const char *fmt, ...) __printf(2, 3);
while (0)
#else
/* !CONFIG_BATMAN_ADV_DEBUG */
__printf
(
3
,
4
)
static
inline
void
bat_dbg
(
char
type
__always_unused
,
static
inline
void
bat_dbg
(
int
type
__always_unused
,
struct
bat_priv
*
bat_priv
__always_unused
,
const
char
*
fmt
__always_unused
,
...)
{
...
...
net/batman-adv/originator.c
浏览文件 @
eac56465
...
...
@@ -37,6 +37,14 @@ static void start_purge_timer(struct bat_priv *bat_priv)
queue_delayed_work
(
bat_event_workqueue
,
&
bat_priv
->
orig_work
,
1
*
HZ
);
}
/* returns 1 if they are the same originator */
static
int
compare_orig
(
const
struct
hlist_node
*
node
,
const
void
*
data2
)
{
const
void
*
data1
=
container_of
(
node
,
struct
orig_node
,
hash_entry
);
return
(
memcmp
(
data1
,
data2
,
ETH_ALEN
)
==
0
?
1
:
0
);
}
int
originator_init
(
struct
bat_priv
*
bat_priv
)
{
if
(
bat_priv
->
orig_hash
)
...
...
@@ -137,6 +145,7 @@ static void orig_node_free_rcu(struct rcu_head *rcu)
tt_global_del_orig
(
orig_node
->
bat_priv
,
orig_node
,
"originator timed out"
);
kfree
(
orig_node
->
tt_buff
);
kfree
(
orig_node
->
bcast_own
);
kfree
(
orig_node
->
bcast_own_sum
);
kfree
(
orig_node
);
...
...
@@ -205,14 +214,18 @@ struct orig_node *get_orig_node(struct bat_priv *bat_priv, const uint8_t *addr)
spin_lock_init
(
&
orig_node
->
ogm_cnt_lock
);
spin_lock_init
(
&
orig_node
->
bcast_seqno_lock
);
spin_lock_init
(
&
orig_node
->
neigh_list_lock
);
spin_lock_init
(
&
orig_node
->
tt_buff_lock
);
/* extra reference for return */
atomic_set
(
&
orig_node
->
refcount
,
2
);
orig_node
->
tt_poss_change
=
false
;
orig_node
->
bat_priv
=
bat_priv
;
memcpy
(
orig_node
->
orig
,
addr
,
ETH_ALEN
);
orig_node
->
router
=
NULL
;
orig_node
->
tt_buff
=
NULL
;
orig_node
->
tt_buff_len
=
0
;
atomic_set
(
&
orig_node
->
tt_size
,
0
);
orig_node
->
bcast_seqno_reset
=
jiffies
-
1
-
msecs_to_jiffies
(
RESET_PROTECTION_MS
);
orig_node
->
batman_seqno_reset
=
jiffies
-
1
...
...
@@ -322,9 +335,7 @@ static bool purge_orig_node(struct bat_priv *bat_priv,
if
(
purge_orig_neighbors
(
bat_priv
,
orig_node
,
&
best_neigh_node
))
{
update_routes
(
bat_priv
,
orig_node
,
best_neigh_node
,
orig_node
->
tt_buff
,
orig_node
->
tt_buff_len
);
best_neigh_node
);
}
}
...
...
net/batman-adv/originator.h
浏览文件 @
eac56465
...
...
@@ -40,14 +40,6 @@ 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
);
/* returns 1 if they are the same originator */
static
inline
int
compare_orig
(
const
struct
hlist_node
*
node
,
const
void
*
data2
)
{
const
void
*
data1
=
container_of
(
node
,
struct
orig_node
,
hash_entry
);
return
(
memcmp
(
data1
,
data2
,
ETH_ALEN
)
==
0
?
1
:
0
);
}
/* hashfunction to choose an entry in a hash table of given size */
/* hash algorithm from http://en.wikipedia.org/wiki/Hash_table */
static
inline
int
choose_orig
(
const
void
*
data
,
int32_t
size
)
...
...
net/batman-adv/packet.h
浏览文件 @
eac56465
...
...
@@ -30,11 +30,13 @@ enum bat_packettype {
BAT_UNICAST
=
0x03
,
BAT_BCAST
=
0x04
,
BAT_VIS
=
0x05
,
BAT_UNICAST_FRAG
=
0x06
BAT_UNICAST_FRAG
=
0x06
,
BAT_TT_QUERY
=
0x07
,
BAT_ROAM_ADV
=
0x08
};
/* this file is included by batctl which needs these defines */
#define COMPAT_VERSION 1
2
#define COMPAT_VERSION 1
4
enum
batman_flags
{
PRIMARIES_FIRST_HOP
=
1
<<
4
,
...
...
@@ -63,18 +65,38 @@ enum unicast_frag_flags {
UNI_FRAG_LARGETAIL
=
1
<<
1
};
/* TT_QUERY subtypes */
#define TT_QUERY_TYPE_MASK 0x3
enum
tt_query_packettype
{
TT_REQUEST
=
0
,
TT_RESPONSE
=
1
};
/* TT_QUERY flags */
enum
tt_query_flags
{
TT_FULL_TABLE
=
1
<<
2
};
/* TT_CHANGE flags */
enum
tt_change_flags
{
TT_CHANGE_DEL
=
0x01
,
TT_CLIENT_ROAM
=
0x02
};
struct
batman_packet
{
uint8_t
packet_type
;
uint8_t
version
;
/* batman version field */
uint8_t
ttl
;
uint8_t
flags
;
/* 0x40: DIRECTLINK flag, 0x20 VIS_SERVER flag... */
uint8_t
tq
;
uint32_t
seqno
;
uint8_t
orig
[
6
];
uint8_t
prev_sender
[
6
];
uint8_t
ttl
;
uint8_t
num_tt
;
uint8_t
gw_flags
;
/* flags related to gateway class */
uint8_t
align
;
uint8_t
tq
;
uint8_t
tt_num_changes
;
uint8_t
ttvn
;
/* translation table version number */
uint16_t
tt_crc
;
}
__packed
;
#define BAT_PACKET_LEN sizeof(struct batman_packet)
...
...
@@ -82,12 +104,13 @@ struct batman_packet {
struct
icmp_packet
{
uint8_t
packet_type
;
uint8_t
version
;
/* batman version field */
uint8_t
msg_type
;
/* see ICMP message types above */
uint8_t
ttl
;
uint8_t
msg_type
;
/* see ICMP message types above */
uint8_t
dst
[
6
];
uint8_t
orig
[
6
];
uint16_t
seqno
;
uint8_t
uid
;
uint8_t
reserved
;
}
__packed
;
#define BAT_RR_LEN 16
...
...
@@ -97,8 +120,8 @@ struct icmp_packet {
struct
icmp_packet_rr
{
uint8_t
packet_type
;
uint8_t
version
;
/* batman version field */
uint8_t
msg_type
;
/* see ICMP message types above */
uint8_t
ttl
;
uint8_t
msg_type
;
/* see ICMP message types above */
uint8_t
dst
[
6
];
uint8_t
orig
[
6
];
uint16_t
seqno
;
...
...
@@ -110,16 +133,19 @@ struct icmp_packet_rr {
struct
unicast_packet
{
uint8_t
packet_type
;
uint8_t
version
;
/* batman version field */
uint8_t
dest
[
6
];
uint8_t
ttl
;
uint8_t
ttvn
;
/* destination translation table version number */
uint8_t
dest
[
6
];
}
__packed
;
struct
unicast_frag_packet
{
uint8_t
packet_type
;
uint8_t
version
;
/* batman version field */
uint8_t
dest
[
6
];
uint8_t
ttl
;
uint8_t
ttvn
;
/* destination translation table version number */
uint8_t
dest
[
6
];
uint8_t
flags
;
uint8_t
align
;
uint8_t
orig
[
6
];
uint16_t
seqno
;
}
__packed
;
...
...
@@ -127,21 +153,61 @@ struct unicast_frag_packet {
struct
bcast_packet
{
uint8_t
packet_type
;
uint8_t
version
;
/* batman version field */
uint8_t
orig
[
6
];
uint8_t
ttl
;
uint8_t
reserved
;
uint32_t
seqno
;
uint8_t
orig
[
6
];
}
__packed
;
struct
vis_packet
{
uint8_t
packet_type
;
uint8_t
version
;
/* batman version field */
uint8_t
ttl
;
/* TTL */
uint8_t
vis_type
;
/* which type of vis-participant sent this? */
uint8_t
entries
;
/* number of entries behind this struct */
uint32_t
seqno
;
/* sequence number */
uint8_t
ttl
;
/* TTL */
uint8_t
entries
;
/* number of entries behind this struct */
uint8_t
reserved
;
uint8_t
vis_orig
[
6
];
/* originator that announces its neighbors */
uint8_t
target_orig
[
6
];
/* who should receive this packet */
uint8_t
sender_orig
[
6
];
/* who sent or rebroadcasted this packet */
}
__packed
;
struct
tt_query_packet
{
uint8_t
packet_type
;
uint8_t
version
;
/* batman version field */
uint8_t
ttl
;
/* the flag field is a combination of:
* - TT_REQUEST or TT_RESPONSE
* - TT_FULL_TABLE */
uint8_t
flags
;
uint8_t
dst
[
ETH_ALEN
];
uint8_t
src
[
ETH_ALEN
];
/* the ttvn field is:
* if TT_REQUEST: ttvn that triggered the
* request
* if TT_RESPONSE: new ttvn for the src
* orig_node */
uint8_t
ttvn
;
/* tt_data field is:
* if TT_REQUEST: crc associated with the
* ttvn
* if TT_RESPONSE: table_size */
uint16_t
tt_data
;
}
__packed
;
struct
roam_adv_packet
{
uint8_t
packet_type
;
uint8_t
version
;
uint8_t
ttl
;
uint8_t
reserved
;
uint8_t
dst
[
ETH_ALEN
];
uint8_t
src
[
ETH_ALEN
];
uint8_t
client
[
ETH_ALEN
];
}
__packed
;
struct
tt_change
{
uint8_t
flags
;
uint8_t
addr
[
ETH_ALEN
];
}
__packed
;
#endif
/* _NET_BATMAN_ADV_PACKET_H_ */
net/batman-adv/routing.c
浏览文件 @
eac56465
...
...
@@ -64,27 +64,57 @@ void slide_own_bcast_window(struct hard_iface *hard_iface)
}
}
static
void
update_TT
(
struct
bat_priv
*
bat_priv
,
struct
orig_node
*
orig_node
,
const
unsigned
char
*
tt_buff
,
int
tt_buff_len
)
static
void
update_transtable
(
struct
bat_priv
*
bat_priv
,
struct
orig_node
*
orig_node
,
const
unsigned
char
*
tt_buff
,
uint8_t
tt_num_changes
,
uint8_t
ttvn
,
uint16_t
tt_crc
)
{
if
((
tt_buff_len
!=
orig_node
->
tt_buff_len
)
||
((
tt_buff_len
>
0
)
&&
(
orig_node
->
tt_buff_len
>
0
)
&&
(
memcmp
(
orig_node
->
tt_buff
,
tt_buff
,
tt_buff_len
)
!=
0
)))
{
if
(
orig_node
->
tt_buff_len
>
0
)
tt_global_del_orig
(
bat_priv
,
orig_node
,
"originator changed tt"
);
if
((
tt_buff_len
>
0
)
&&
(
tt_buff
))
tt_global_add_orig
(
bat_priv
,
orig_node
,
tt_buff
,
tt_buff_len
);
uint8_t
orig_ttvn
=
(
uint8_t
)
atomic_read
(
&
orig_node
->
last_ttvn
);
bool
full_table
=
true
;
/* the ttvn increased by one -> we can apply the attached changes */
if
(
ttvn
-
orig_ttvn
==
1
)
{
/* the OGM could not contain the changes because they were too
* many to fit in one frame or because they have already been
* sent TT_OGM_APPEND_MAX times. In this case send a tt
* request */
if
(
!
tt_num_changes
)
{
full_table
=
false
;
goto
request_table
;
}
tt_update_changes
(
bat_priv
,
orig_node
,
tt_num_changes
,
ttvn
,
(
struct
tt_change
*
)
tt_buff
);
/* Even if we received the crc into the OGM, we prefer
* to recompute it to spot any possible inconsistency
* in the global table */
orig_node
->
tt_crc
=
tt_global_crc
(
bat_priv
,
orig_node
);
/* Roaming phase is over: tables are in sync again. I can
* unset the flag */
orig_node
->
tt_poss_change
=
false
;
}
else
{
/* if we missed more than one change or our tables are not
* in sync anymore -> request fresh tt data */
if
(
ttvn
!=
orig_ttvn
||
orig_node
->
tt_crc
!=
tt_crc
)
{
request_table:
bat_dbg
(
DBG_TT
,
bat_priv
,
"TT inconsistency for %pM. "
"Need to retrieve the correct information "
"(ttvn: %u last_ttvn: %u crc: %u last_crc: "
"%u num_changes: %u)
\n
"
,
orig_node
->
orig
,
ttvn
,
orig_ttvn
,
tt_crc
,
orig_node
->
tt_crc
,
tt_num_changes
);
send_tt_request
(
bat_priv
,
orig_node
,
ttvn
,
tt_crc
,
full_table
);
return
;
}
}
}
static
void
update_route
(
struct
bat_priv
*
bat_priv
,
struct
orig_node
*
orig_node
,
struct
neigh_node
*
neigh
_node
,
const
unsigned
char
*
tt_buff
,
int
tt_buff_len
)
static
void
update_route
(
struct
bat_priv
*
bat_priv
,
struct
orig_node
*
orig
_node
,
struct
neigh_node
*
neigh_node
)
{
struct
neigh_node
*
curr_router
;
...
...
@@ -92,11 +122,10 @@ static void update_route(struct bat_priv *bat_priv, struct orig_node *orig_node,
/* route deleted */
if
((
curr_router
)
&&
(
!
neigh_node
))
{
bat_dbg
(
DBG_ROUTES
,
bat_priv
,
"Deleting route towards: %pM
\n
"
,
orig_node
->
orig
);
tt_global_del_orig
(
bat_priv
,
orig_node
,
"
originator timed out
"
);
"
Deleted route towards originator
"
);
/* route added */
}
else
if
((
!
curr_router
)
&&
(
neigh_node
))
{
...
...
@@ -104,9 +133,6 @@ static void update_route(struct bat_priv *bat_priv, struct orig_node *orig_node,
bat_dbg
(
DBG_ROUTES
,
bat_priv
,
"Adding route towards: %pM (via %pM)
\n
"
,
orig_node
->
orig
,
neigh_node
->
addr
);
tt_global_add_orig
(
bat_priv
,
orig_node
,
tt_buff
,
tt_buff_len
);
/* route changed */
}
else
if
(
neigh_node
&&
curr_router
)
{
bat_dbg
(
DBG_ROUTES
,
bat_priv
,
...
...
@@ -133,8 +159,7 @@ static void update_route(struct bat_priv *bat_priv, struct orig_node *orig_node,
}
void
update_routes
(
struct
bat_priv
*
bat_priv
,
struct
orig_node
*
orig_node
,
struct
neigh_node
*
neigh_node
,
const
unsigned
char
*
tt_buff
,
int
tt_buff_len
)
struct
neigh_node
*
neigh_node
)
{
struct
neigh_node
*
router
=
NULL
;
...
...
@@ -144,11 +169,7 @@ 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
,
tt_buff
,
tt_buff_len
);
/* may be just TT changed */
else
update_TT
(
bat_priv
,
orig_node
,
tt_buff
,
tt_buff_len
);
update_route
(
bat_priv
,
orig_node
,
neigh_node
);
out:
if
(
router
)
...
...
@@ -163,7 +184,7 @@ static int is_bidirectional_neigh(struct orig_node *orig_node,
struct
bat_priv
*
bat_priv
=
netdev_priv
(
if_incoming
->
soft_iface
);
struct
neigh_node
*
neigh_node
=
NULL
,
*
tmp_neigh_node
;
struct
hlist_node
*
node
;
u
nsigned
char
total_count
;
u
int8_t
total_count
;
uint8_t
orig_eq_count
,
neigh_rq_count
,
tq_own
;
int
tq_asym_penalty
,
ret
=
0
;
...
...
@@ -360,14 +381,12 @@ 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
tt_buff_len
,
char
is_duplicate
)
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
;
int
tmp_tt_buff_len
;
uint8_t
bcast_own_sum_orig
,
bcast_own_sum_neigh
;
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"update_originator(): "
...
...
@@ -432,9 +451,6 @@ static void update_orig(struct bat_priv *bat_priv, struct orig_node *orig_node,
bonding_candidate_add
(
orig_node
,
neigh_node
);
tmp_tt_buff_len
=
(
tt_buff_len
>
batman_packet
->
num_tt
*
ETH_ALEN
?
batman_packet
->
num_tt
*
ETH_ALEN
:
tt_buff_len
);
/* if this neighbor already is our next hop there is nothing
* to change */
router
=
orig_node_get_router
(
orig_node
);
...
...
@@ -464,15 +480,19 @@ static void update_orig(struct bat_priv *bat_priv, struct orig_node *orig_node,
goto
update_tt
;
}
update_routes
(
bat_priv
,
orig_node
,
neigh_node
,
tt_buff
,
tmp_tt_buff_len
);
goto
update_gw
;
update_routes
(
bat_priv
,
orig_node
,
neigh_node
);
update_tt:
update_routes
(
bat_priv
,
orig_node
,
router
,
tt_buff
,
tmp_tt_buff_len
);
/* 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
))
update_transtable
(
bat_priv
,
orig_node
,
tt_buff
,
batman_packet
->
tt_num_changes
,
batman_packet
->
ttvn
,
batman_packet
->
tt_crc
);
update_gw:
if
(
orig_node
->
gw_flags
!=
batman_packet
->
gw_flags
)
gw_node_update
(
bat_priv
,
orig_node
,
batman_packet
->
gw_flags
);
...
...
@@ -528,7 +548,7 @@ static int window_protected(struct bat_priv *bat_priv,
* -1 the packet is old and has been received while the seqno window
* was protected. Caller should drop it.
*/
static
char
count_real_packets
(
const
struct
ethhdr
*
ethhdr
,
static
int
count_real_packets
(
const
struct
ethhdr
*
ethhdr
,
const
struct
batman_packet
*
batman_packet
,
const
struct
hard_iface
*
if_incoming
)
{
...
...
@@ -536,7 +556,7 @@ static char count_real_packets(const struct ethhdr *ethhdr,
struct
orig_node
*
orig_node
;
struct
neigh_node
*
tmp_neigh_node
;
struct
hlist_node
*
node
;
char
is_duplicate
=
0
;
int
is_duplicate
=
0
;
int32_t
seq_diff
;
int
need_update
=
0
;
int
set_mark
,
ret
=
-
1
;
...
...
@@ -594,7 +614,7 @@ static char count_real_packets(const struct ethhdr *ethhdr,
void
receive_bat_packet
(
const
struct
ethhdr
*
ethhdr
,
struct
batman_packet
*
batman_packet
,
const
unsigned
char
*
tt_buff
,
int
tt_buff_len
,
const
unsigned
char
*
tt_buff
,
struct
hard_iface
*
if_incoming
)
{
struct
bat_priv
*
bat_priv
=
netdev_priv
(
if_incoming
->
soft_iface
);
...
...
@@ -602,10 +622,10 @@ void receive_bat_packet(const struct ethhdr *ethhdr,
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
is_my_addr
=
0
,
is_my_orig
=
0
,
is_my_oldorig
=
0
;
char
is_broadcast
=
0
,
is_bidirectional
,
is_single_hop_neigh
;
char
is_duplicate
;
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
...
...
@@ -633,12 +653,14 @@ void receive_bat_packet(const struct ethhdr *ethhdr,
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"Received BATMAN packet via NB: %pM, IF: %s [%pM] "
"(from OG: %pM, via prev OG: %pM, seqno %d, t
q %d
, "
"TTL %d, V %d, IDF %d)
\n
"
,
"(from OG: %pM, via prev OG: %pM, seqno %d, t
tvn %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
->
tq
,
batman_packet
->
ttl
,
batman_packet
->
version
,
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
();
...
...
@@ -790,14 +812,14 @@ void receive_bat_packet(const struct ethhdr *ethhdr,
((
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
,
tt_buff_len
,
is_duplicate
);
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
,
tt_buff_len
,
if_incoming
);
1
,
if_incoming
);
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"Forwarding packet: "
"rebroadcast neighbor packet with direct link flag
\n
"
);
...
...
@@ -820,7 +842,7 @@ void receive_bat_packet(const struct ethhdr *ethhdr,
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"Forwarding packet: rebroadcast originator packet
\n
"
);
schedule_forward_packet
(
orig_node
,
ethhdr
,
batman_packet
,
0
,
tt_buff_len
,
if_incoming
);
0
,
if_incoming
);
out_neigh:
if
((
orig_neigh_node
)
&&
(
!
is_single_hop_neigh
))
...
...
@@ -1167,6 +1189,118 @@ static struct neigh_node *find_ifalter_router(struct orig_node *primary_orig,
return
router
;
}
int
recv_tt_query
(
struct
sk_buff
*
skb
,
struct
hard_iface
*
recv_if
)
{
struct
bat_priv
*
bat_priv
=
netdev_priv
(
recv_if
->
soft_iface
);
struct
tt_query_packet
*
tt_query
;
struct
ethhdr
*
ethhdr
;
/* drop packet if it has not necessary minimum size */
if
(
unlikely
(
!
pskb_may_pull
(
skb
,
sizeof
(
struct
tt_query_packet
))))
goto
out
;
/* I could need to modify it */
if
(
skb_cow
(
skb
,
sizeof
(
struct
tt_query_packet
))
<
0
)
goto
out
;
ethhdr
=
(
struct
ethhdr
*
)
skb_mac_header
(
skb
);
/* packet with unicast indication but broadcast recipient */
if
(
is_broadcast_ether_addr
(
ethhdr
->
h_dest
))
goto
out
;
/* packet with broadcast sender address */
if
(
is_broadcast_ether_addr
(
ethhdr
->
h_source
))
goto
out
;
tt_query
=
(
struct
tt_query_packet
*
)
skb
->
data
;
tt_query
->
tt_data
=
ntohs
(
tt_query
->
tt_data
);
switch
(
tt_query
->
flags
&
TT_QUERY_TYPE_MASK
)
{
case
TT_REQUEST
:
/* If we cannot provide an answer the tt_request is
* forwarded */
if
(
!
send_tt_response
(
bat_priv
,
tt_query
))
{
bat_dbg
(
DBG_TT
,
bat_priv
,
"Routing TT_REQUEST to %pM [%c]
\n
"
,
tt_query
->
dst
,
(
tt_query
->
flags
&
TT_FULL_TABLE
?
'F'
:
'.'
));
tt_query
->
tt_data
=
htons
(
tt_query
->
tt_data
);
return
route_unicast_packet
(
skb
,
recv_if
);
}
break
;
case
TT_RESPONSE
:
/* packet needs to be linearised to access the TT changes */
if
(
skb_linearize
(
skb
)
<
0
)
goto
out
;
if
(
is_my_mac
(
tt_query
->
dst
))
handle_tt_response
(
bat_priv
,
tt_query
);
else
{
bat_dbg
(
DBG_TT
,
bat_priv
,
"Routing TT_RESPONSE to %pM [%c]
\n
"
,
tt_query
->
dst
,
(
tt_query
->
flags
&
TT_FULL_TABLE
?
'F'
:
'.'
));
tt_query
->
tt_data
=
htons
(
tt_query
->
tt_data
);
return
route_unicast_packet
(
skb
,
recv_if
);
}
break
;
}
out:
/* returning NET_RX_DROP will make the caller function kfree the skb */
return
NET_RX_DROP
;
}
int
recv_roam_adv
(
struct
sk_buff
*
skb
,
struct
hard_iface
*
recv_if
)
{
struct
bat_priv
*
bat_priv
=
netdev_priv
(
recv_if
->
soft_iface
);
struct
roam_adv_packet
*
roam_adv_packet
;
struct
orig_node
*
orig_node
;
struct
ethhdr
*
ethhdr
;
/* drop packet if it has not necessary minimum size */
if
(
unlikely
(
!
pskb_may_pull
(
skb
,
sizeof
(
struct
roam_adv_packet
))))
goto
out
;
ethhdr
=
(
struct
ethhdr
*
)
skb_mac_header
(
skb
);
/* packet with unicast indication but broadcast recipient */
if
(
is_broadcast_ether_addr
(
ethhdr
->
h_dest
))
goto
out
;
/* packet with broadcast sender address */
if
(
is_broadcast_ether_addr
(
ethhdr
->
h_source
))
goto
out
;
roam_adv_packet
=
(
struct
roam_adv_packet
*
)
skb
->
data
;
if
(
!
is_my_mac
(
roam_adv_packet
->
dst
))
return
route_unicast_packet
(
skb
,
recv_if
);
orig_node
=
orig_hash_find
(
bat_priv
,
roam_adv_packet
->
src
);
if
(
!
orig_node
)
goto
out
;
bat_dbg
(
DBG_TT
,
bat_priv
,
"Received ROAMING_ADV from %pM "
"(client %pM)
\n
"
,
roam_adv_packet
->
src
,
roam_adv_packet
->
client
);
tt_global_add
(
bat_priv
,
orig_node
,
roam_adv_packet
->
client
,
atomic_read
(
&
orig_node
->
last_ttvn
)
+
1
,
true
);
/* Roaming phase starts: I have new information but the ttvn has not
* been incremented yet. This flag will make me check all the incoming
* packets for the correct destination. */
bat_priv
->
tt_poss_change
=
true
;
orig_node_free_ref
(
orig_node
);
out:
/* returning NET_RX_DROP will make the caller function kfree the skb */
return
NET_RX_DROP
;
}
/* find a suitable router for this originator, and use
* bonding if possible. increases the found neighbors
* refcount.*/
...
...
@@ -1353,14 +1487,84 @@ int route_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if)
return
ret
;
}
static
int
check_unicast_ttvn
(
struct
bat_priv
*
bat_priv
,
struct
sk_buff
*
skb
)
{
uint8_t
curr_ttvn
;
struct
orig_node
*
orig_node
;
struct
ethhdr
*
ethhdr
;
struct
hard_iface
*
primary_if
;
struct
unicast_packet
*
unicast_packet
;
bool
tt_poss_change
;
/* I could need to modify it */
if
(
skb_cow
(
skb
,
sizeof
(
struct
unicast_packet
))
<
0
)
return
0
;
unicast_packet
=
(
struct
unicast_packet
*
)
skb
->
data
;
if
(
is_my_mac
(
unicast_packet
->
dest
))
{
tt_poss_change
=
bat_priv
->
tt_poss_change
;
curr_ttvn
=
(
uint8_t
)
atomic_read
(
&
bat_priv
->
ttvn
);
}
else
{
orig_node
=
orig_hash_find
(
bat_priv
,
unicast_packet
->
dest
);
if
(
!
orig_node
)
return
0
;
curr_ttvn
=
(
uint8_t
)
atomic_read
(
&
orig_node
->
last_ttvn
);
tt_poss_change
=
orig_node
->
tt_poss_change
;
orig_node_free_ref
(
orig_node
);
}
/* Check whether I have to reroute the packet */
if
(
seq_before
(
unicast_packet
->
ttvn
,
curr_ttvn
)
||
tt_poss_change
)
{
/* Linearize the skb before accessing it */
if
(
skb_linearize
(
skb
)
<
0
)
return
0
;
ethhdr
=
(
struct
ethhdr
*
)(
skb
->
data
+
sizeof
(
struct
unicast_packet
));
orig_node
=
transtable_search
(
bat_priv
,
ethhdr
->
h_dest
);
if
(
!
orig_node
)
{
if
(
!
is_my_client
(
bat_priv
,
ethhdr
->
h_dest
))
return
0
;
primary_if
=
primary_if_get_selected
(
bat_priv
);
if
(
!
primary_if
)
return
0
;
memcpy
(
unicast_packet
->
dest
,
primary_if
->
net_dev
->
dev_addr
,
ETH_ALEN
);
hardif_free_ref
(
primary_if
);
}
else
{
memcpy
(
unicast_packet
->
dest
,
orig_node
->
orig
,
ETH_ALEN
);
curr_ttvn
=
(
uint8_t
)
atomic_read
(
&
orig_node
->
last_ttvn
);
orig_node_free_ref
(
orig_node
);
}
bat_dbg
(
DBG_ROUTES
,
bat_priv
,
"TTVN mismatch (old_ttvn %u "
"new_ttvn %u)! Rerouting unicast packet (for %pM) to "
"%pM
\n
"
,
unicast_packet
->
ttvn
,
curr_ttvn
,
ethhdr
->
h_dest
,
unicast_packet
->
dest
);
unicast_packet
->
ttvn
=
curr_ttvn
;
}
return
1
;
}
int
recv_unicast_packet
(
struct
sk_buff
*
skb
,
struct
hard_iface
*
recv_if
)
{
struct
bat_priv
*
bat_priv
=
netdev_priv
(
recv_if
->
soft_iface
);
struct
unicast_packet
*
unicast_packet
;
int
hdr_size
=
sizeof
(
*
unicast_packet
);
if
(
check_unicast_packet
(
skb
,
hdr_size
)
<
0
)
return
NET_RX_DROP
;
if
(
!
check_unicast_ttvn
(
bat_priv
,
skb
))
return
NET_RX_DROP
;
unicast_packet
=
(
struct
unicast_packet
*
)
skb
->
data
;
/* packet for me */
...
...
@@ -1383,6 +1587,9 @@ int recv_ucast_frag_packet(struct sk_buff *skb, struct hard_iface *recv_if)
if
(
check_unicast_packet
(
skb
,
hdr_size
)
<
0
)
return
NET_RX_DROP
;
if
(
!
check_unicast_ttvn
(
bat_priv
,
skb
))
return
NET_RX_DROP
;
unicast_packet
=
(
struct
unicast_frag_packet
*
)
skb
->
data
;
/* packet for me */
...
...
net/batman-adv/routing.h
浏览文件 @
eac56465
...
...
@@ -25,11 +25,10 @@
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
,
int
tt_buff_len
,
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
,
const
unsigned
char
*
tt_buff
,
int
tt_buff_len
);
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
);
...
...
@@ -37,6 +36,8 @@ 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_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
,
struct
orig_node
*
orig_node
,
const
struct
hard_iface
*
recv_if
);
...
...
net/batman-adv/send.c
浏览文件 @
eac56465
...
...
@@ -120,7 +120,7 @@ static void send_packet_to_if(struct forw_packet *forw_packet,
/* adjust all flags and log packets */
while
(
aggregated_packet
(
buff_pos
,
forw_packet
->
packet_len
,
batman_packet
->
num_tt
))
{
batman_packet
->
tt_num_changes
))
{
/* we might have aggregated direct link packets with an
* ordinary base packet */
...
...
@@ -135,17 +135,17 @@ static void send_packet_to_if(struct forw_packet *forw_packet,
"Forwarding"
));
bat_dbg
(
DBG_BATMAN
,
bat_priv
,
"%s %spacket (originator %pM, seqno %d, TQ %d, TTL %d,"
" IDF %s) on interface %s [%pM]
\n
"
,
" IDF %s
, hvn %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"
),
hard_iface
->
net_dev
->
name
,
batman_packet
->
ttvn
,
hard_iface
->
net_dev
->
name
,
hard_iface
->
net_dev
->
dev_addr
);
buff_pos
+=
sizeof
(
*
batman_packet
)
+
(
batman_packet
->
num_tt
*
ETH_ALEN
);
tt_len
(
batman_packet
->
tt_num_changes
);
packet_num
++
;
batman_packet
=
(
struct
batman_packet
*
)
(
forw_packet
->
skb
->
data
+
buff_pos
);
...
...
@@ -165,7 +165,7 @@ static void send_packet(struct forw_packet *forw_packet)
struct
bat_priv
*
bat_priv
;
struct
batman_packet
*
batman_packet
=
(
struct
batman_packet
*
)(
forw_packet
->
skb
->
data
);
unsigned
char
directlink
=
(
batman_packet
->
flags
&
DIRECTLINK
?
1
:
0
);
int
directlink
=
(
batman_packet
->
flags
&
DIRECTLINK
?
1
:
0
);
if
(
!
forw_packet
->
if_incoming
)
{
pr_err
(
"Error - can't forward packet: incoming iface not "
...
...
@@ -213,25 +213,18 @@ static void send_packet(struct forw_packet *forw_packet)
rcu_read_unlock
();
}
static
void
re
build_batman_packet
(
struct
bat_priv
*
bat_priv
,
struct
hard_iface
*
hard_iface
)
static
void
re
alloc_packet_buffer
(
struct
hard_iface
*
hard_iface
,
int
new_len
)
{
int
new_len
;
unsigned
char
*
new_buff
;
struct
batman_packet
*
batman_packet
;
new_len
=
sizeof
(
*
batman_packet
)
+
(
bat_priv
->
num_local_tt
*
ETH_ALEN
);
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_packet
=
(
struct
batman_packet
*
)
new_buff
;
batman_packet
->
num_tt
=
tt_local_fill_buffer
(
bat_priv
,
new_buff
+
sizeof
(
*
batman_packet
),
new_len
-
sizeof
(
*
batman_packet
));
kfree
(
hard_iface
->
packet_buff
);
hard_iface
->
packet_buff
=
new_buff
;
...
...
@@ -239,6 +232,46 @@ static void rebuild_batman_packet(struct bat_priv *bat_priv,
}
}
/* when calling this function (hard_iface == primary_if) has to be true */
static
void
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
+
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
;
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
);
}
static
void
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
;
}
void
schedule_own_packet
(
struct
hard_iface
*
hard_iface
)
{
struct
bat_priv
*
bat_priv
=
netdev_priv
(
hard_iface
->
soft_iface
);
...
...
@@ -264,14 +297,23 @@ void schedule_own_packet(struct hard_iface *hard_iface)
if
(
hard_iface
->
if_status
==
IF_TO_BE_ACTIVATED
)
hard_iface
->
if_status
=
IF_ACTIVE
;
/* if local tt has changed and interface is a primary interface */
if
((
atomic_read
(
&
bat_priv
->
tt_local_changed
))
&&
(
hard_iface
==
primary_if
))
rebuild_batman_packet
(
bat_priv
,
hard_iface
);
if
(
hard_iface
==
primary_if
)
{
/* if at least one change happened */
if
(
atomic_read
(
&
bat_priv
->
tt_local_changes
)
>
0
)
{
prepare_packet_buffer
(
bat_priv
,
hard_iface
);
/* Increment the TTVN only once per OGM interval */
atomic_inc
(
&
bat_priv
->
ttvn
);
bat_priv
->
tt_poss_change
=
false
;
}
/* if the changes have been sent enough times */
if
(
!
atomic_dec_not_zero
(
&
bat_priv
->
tt_ogm_append_cnt
))
reset_packet_buffer
(
bat_priv
,
hard_iface
);
}
/**
* NOTE: packet_buff might just have been re-allocated in
*
rebuild_batman_packet
()
*
prepare_packet_buffer() or in reset_packet_buffer
()
*/
batman_packet
=
(
struct
batman_packet
*
)
hard_iface
->
packet_buff
;
...
...
@@ -279,6 +321,9 @@ void schedule_own_packet(struct hard_iface *hard_iface)
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
...
...
@@ -307,13 +352,14 @@ 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
,
uint8_t
directlink
,
int
tt_buff_len
,
int
directlink
,
struct
hard_iface
*
if_incoming
)
{
struct
bat_priv
*
bat_priv
=
netdev_priv
(
if_incoming
->
soft_iface
);
struct
neigh_node
*
router
;
u
nsigned
char
in_tq
,
in_ttl
,
tq_avg
=
0
;
u
int8_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
"
);
...
...
@@ -324,6 +370,7 @@ void schedule_forward_packet(struct orig_node *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
);
...
...
@@ -356,6 +403,7 @@ void schedule_forward_packet(struct orig_node *orig_node,
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
;
...
...
@@ -367,7 +415,7 @@ void schedule_forward_packet(struct orig_node *orig_node,
send_time
=
forward_send_time
();
add_bat_packet_to_list
(
bat_priv
,
(
unsigned
char
*
)
batman_packet
,
sizeof
(
*
batman_packet
)
+
tt_
buff_len
,
sizeof
(
*
batman_packet
)
+
tt_
len
(
tt_num_changes
)
,
if_incoming
,
0
,
send_time
);
}
...
...
net/batman-adv/send.h
浏览文件 @
eac56465
...
...
@@ -28,7 +28,7 @@ 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
,
uint8_t
directlink
,
int
tt_buff_len
,
int
directlink
,
struct
hard_iface
*
if_outgoing
);
int
add_bcast_packet_to_list
(
struct
bat_priv
*
bat_priv
,
const
struct
sk_buff
*
skb
);
...
...
net/batman-adv/soft-interface.c
浏览文件 @
eac56465
...
...
@@ -30,6 +30,7 @@
#include "gateway_common.h"
#include "gateway_client.h"
#include "bat_sysfs.h"
#include "originator.h"
#include <linux/slab.h>
#include <linux/ethtool.h>
#include <linux/etherdevice.h>
...
...
@@ -380,7 +381,7 @@ void softif_neigh_purge(struct bat_priv *bat_priv)
struct
softif_neigh
*
softif_neigh
,
*
curr_softif_neigh
;
struct
softif_neigh_vid
*
softif_neigh_vid
;
struct
hlist_node
*
node
,
*
node_tmp
,
*
node_tmp2
;
char
do_deselect
;
int
do_deselect
;
rcu_read_lock
();
hlist_for_each_entry_rcu
(
softif_neigh_vid
,
node
,
...
...
@@ -534,7 +535,7 @@ static int interface_set_mac_addr(struct net_device *dev, void *p)
/* only modify transtable if it has been initialised before */
if
(
atomic_read
(
&
bat_priv
->
mesh_state
)
==
MESH_ACTIVE
)
{
tt_local_remove
(
bat_priv
,
dev
->
dev_addr
,
"mac address changed"
);
"mac address changed"
,
false
);
tt_local_add
(
dev
,
addr
->
sa_data
);
}
...
...
@@ -553,7 +554,7 @@ static int interface_change_mtu(struct net_device *dev, int new_mtu)
return
0
;
}
int
interface_tx
(
struct
sk_buff
*
skb
,
struct
net_device
*
soft_iface
)
static
int
interface_tx
(
struct
sk_buff
*
skb
,
struct
net_device
*
soft_iface
)
{
struct
ethhdr
*
ethhdr
=
(
struct
ethhdr
*
)
skb
->
data
;
struct
bat_priv
*
bat_priv
=
netdev_priv
(
soft_iface
);
...
...
@@ -561,6 +562,7 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
struct
bcast_packet
*
bcast_packet
;
struct
vlan_ethhdr
*
vhdr
;
struct
softif_neigh
*
curr_softif_neigh
=
NULL
;
struct
orig_node
*
orig_node
=
NULL
;
int
data_len
=
skb
->
len
,
ret
;
short
vid
=
-
1
;
bool
do_bcast
=
false
;
...
...
@@ -592,11 +594,13 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
if
(
curr_softif_neigh
)
goto
dropped
;
/*
TODO: check this for locks
*/
/*
Register the client MAC in the transtable
*/
tt_local_add
(
soft_iface
,
ethhdr
->
h_source
);
if
(
is_multicast_ether_addr
(
ethhdr
->
h_dest
))
{
ret
=
gw_is_target
(
bat_priv
,
skb
);
orig_node
=
transtable_search
(
bat_priv
,
ethhdr
->
h_dest
);
if
(
is_multicast_ether_addr
(
ethhdr
->
h_dest
)
||
(
orig_node
&&
orig_node
->
gw_flags
))
{
ret
=
gw_is_target
(
bat_priv
,
skb
,
orig_node
);
if
(
ret
<
0
)
goto
dropped
;
...
...
@@ -656,6 +660,8 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
softif_neigh_free_ref
(
curr_softif_neigh
);
if
(
primary_if
)
hardif_free_ref
(
primary_if
);
if
(
orig_node
)
orig_node_free_ref
(
orig_node
);
return
NETDEV_TX_OK
;
}
...
...
@@ -830,7 +836,13 @@ struct net_device *softif_create(const char *name)
atomic_set
(
&
bat_priv
->
mesh_state
,
MESH_INACTIVE
);
atomic_set
(
&
bat_priv
->
bcast_seqno
,
1
);
atomic_set
(
&
bat_priv
->
tt_local_changed
,
0
);
atomic_set
(
&
bat_priv
->
ttvn
,
0
);
atomic_set
(
&
bat_priv
->
tt_local_changes
,
0
);
atomic_set
(
&
bat_priv
->
tt_ogm_append_cnt
,
0
);
bat_priv
->
tt_buff
=
NULL
;
bat_priv
->
tt_buff_len
=
0
;
bat_priv
->
tt_poss_change
=
false
;
bat_priv
->
primary_if
=
NULL
;
bat_priv
->
num_ifaces
=
0
;
...
...
net/batman-adv/soft-interface.h
浏览文件 @
eac56465
...
...
@@ -25,7 +25,6 @@
int
my_skb_head_push
(
struct
sk_buff
*
skb
,
unsigned
int
len
);
int
softif_neigh_seq_print_text
(
struct
seq_file
*
seq
,
void
*
offset
);
void
softif_neigh_purge
(
struct
bat_priv
*
bat_priv
);
int
interface_tx
(
struct
sk_buff
*
skb
,
struct
net_device
*
soft_iface
);
void
interface_rx
(
struct
net_device
*
soft_iface
,
struct
sk_buff
*
skb
,
struct
hard_iface
*
recv_if
,
int
hdr_size
);
...
...
net/batman-adv/translation-table.c
浏览文件 @
eac56465
此差异已折叠。
点击以展开。
net/batman-adv/translation-table.h
浏览文件 @
eac56465
...
...
@@ -22,23 +22,45 @@
#ifndef _NET_BATMAN_ADV_TRANSLATION_TABLE_H_
#define _NET_BATMAN_ADV_TRANSLATION_TABLE_H_
int
tt_local_init
(
struct
bat_priv
*
bat_priv
);
int
tt_len
(
int
changes_num
);
int
tt_changes_fill_buffer
(
struct
bat_priv
*
bat_priv
,
unsigned
char
*
buff
,
int
buff_len
);
int
tt_init
(
struct
bat_priv
*
bat_priv
);
void
tt_local_add
(
struct
net_device
*
soft_iface
,
const
uint8_t
*
addr
);
void
tt_local_remove
(
struct
bat_priv
*
bat_priv
,
const
uint8_t
*
addr
,
const
char
*
message
);
int
tt_local_fill_buffer
(
struct
bat_priv
*
bat_priv
,
unsigned
char
*
buff
,
int
buff_len
);
const
uint8_t
*
addr
,
const
char
*
message
,
bool
roaming
);
int
tt_local_seq_print_text
(
struct
seq_file
*
seq
,
void
*
offset
);
void
tt_local_free
(
struct
bat_priv
*
bat_priv
);
int
tt_global_init
(
struct
bat_priv
*
bat_priv
);
void
tt_global_add_orig
(
struct
bat_priv
*
bat_priv
,
struct
orig_node
*
orig_node
,
const
unsigned
char
*
tt_buff
,
int
tt_buff_len
);
int
tt_global_add
(
struct
bat_priv
*
bat_priv
,
struct
orig_node
*
orig_node
,
const
unsigned
char
*
addr
,
uint8_t
ttvn
,
bool
roaming
);
int
tt_global_seq_print_text
(
struct
seq_file
*
seq
,
void
*
offset
);
void
tt_global_del_orig
(
struct
bat_priv
*
bat_priv
,
struct
orig_node
*
orig_node
,
const
char
*
message
);
void
tt_global_free
(
struct
bat_priv
*
bat_priv
);
struct
orig_node
*
orig_node
,
const
char
*
message
);
void
tt_global_del
(
struct
bat_priv
*
bat_priv
,
struct
orig_node
*
orig_node
,
const
unsigned
char
*
addr
,
const
char
*
message
,
bool
roaming
);
struct
orig_node
*
transtable_search
(
struct
bat_priv
*
bat_priv
,
const
uint8_t
*
addr
);
void
tt_save_orig_buffer
(
struct
bat_priv
*
bat_priv
,
struct
orig_node
*
orig_node
,
const
unsigned
char
*
tt_buff
,
uint8_t
tt_num_changes
);
uint16_t
tt_local_crc
(
struct
bat_priv
*
bat_priv
);
uint16_t
tt_global_crc
(
struct
bat_priv
*
bat_priv
,
struct
orig_node
*
orig_node
);
void
tt_free
(
struct
bat_priv
*
bat_priv
);
int
send_tt_request
(
struct
bat_priv
*
bat_priv
,
struct
orig_node
*
dst_orig_node
,
uint8_t
hvn
,
uint16_t
tt_crc
,
bool
full_table
);
bool
send_tt_response
(
struct
bat_priv
*
bat_priv
,
struct
tt_query_packet
*
tt_request
);
void
tt_update_changes
(
struct
bat_priv
*
bat_priv
,
struct
orig_node
*
orig_node
,
uint16_t
tt_num_changes
,
uint8_t
ttvn
,
struct
tt_change
*
tt_change
);
bool
is_my_client
(
struct
bat_priv
*
bat_priv
,
const
uint8_t
*
addr
);
void
handle_tt_response
(
struct
bat_priv
*
bat_priv
,
struct
tt_query_packet
*
tt_response
);
void
send_roam_adv
(
struct
bat_priv
*
bat_priv
,
uint8_t
*
client
,
struct
orig_node
*
orig_node
);
#endif
/* _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ */
net/batman-adv/types.h
浏览文件 @
eac56465
...
...
@@ -75,8 +75,18 @@ struct orig_node {
unsigned
long
batman_seqno_reset
;
uint8_t
gw_flags
;
uint8_t
flags
;
atomic_t
last_ttvn
;
/* last seen translation table version number */
uint16_t
tt_crc
;
unsigned
char
*
tt_buff
;
int16_t
tt_buff_len
;
spinlock_t
tt_buff_lock
;
/* protects tt_buff */
atomic_t
tt_size
;
/* The tt_poss_change flag is used to detect an ongoing roaming phase.
* If true, then I sent a Roaming_adv to this orig_node and I have to
* inspect every packet directed to it to check whether it is still
* the true destination or not. This flag will be reset to false as
* soon as I receive a new TTVN from this orig_node */
bool
tt_poss_change
;
uint32_t
last_real_seqno
;
uint8_t
last_ttl
;
unsigned
long
bcast_bits
[
NUM_WORDS
];
...
...
@@ -94,6 +104,7 @@ struct orig_node {
spinlock_t
ogm_cnt_lock
;
/* bcast_seqno_lock protects bcast_bits, last_bcast_seqno */
spinlock_t
bcast_seqno_lock
;
spinlock_t
tt_list_lock
;
/* protects tt_list */
atomic_t
bond_candidates
;
struct
list_head
bond_list
;
};
...
...
@@ -145,6 +156,15 @@ struct bat_priv {
atomic_t
bcast_seqno
;
atomic_t
bcast_queue_left
;
atomic_t
batman_queue_left
;
atomic_t
ttvn
;
/* tranlation table version number */
atomic_t
tt_ogm_append_cnt
;
atomic_t
tt_local_changes
;
/* changes registered in a OGM interval */
/* The tt_poss_change flag is used to detect an ongoing roaming phase.
* If true, then I received a Roaming_adv and I have to inspect every
* packet directed to me to check whether I am still the true
* destination or not. This flag will be reset to false as soon as I
* increase my TTVN */
bool
tt_poss_change
;
char
num_ifaces
;
struct
debug_log
*
debug_log
;
struct
kobject
*
mesh_obj
;
...
...
@@ -153,26 +173,35 @@ struct bat_priv {
struct
hlist_head
forw_bcast_list
;
struct
hlist_head
gw_list
;
struct
hlist_head
softif_neigh_vids
;
struct
list_head
tt_changes_list
;
/* tracks changes in a OGM int */
struct
list_head
vis_send_list
;
struct
hashtable_t
*
orig_hash
;
struct
hashtable_t
*
tt_local_hash
;
struct
hashtable_t
*
tt_global_hash
;
struct
list_head
tt_req_list
;
/* list of pending tt_requests */
struct
list_head
tt_roam_list
;
struct
hashtable_t
*
vis_hash
;
spinlock_t
forw_bat_list_lock
;
/* protects forw_bat_list */
spinlock_t
forw_bcast_list_lock
;
/* protects */
spinlock_t
tt_lhash_lock
;
/* protects tt_local_hash */
spinlock_t
tt_ghash_lock
;
/* protects tt_global_hash */
spinlock_t
tt_changes_list_lock
;
/* protects tt_changes */
spinlock_t
tt_req_list_lock
;
/* protects tt_req_list */
spinlock_t
tt_roam_list_lock
;
/* protects tt_roam_list */
spinlock_t
gw_list_lock
;
/* protects gw_list and curr_gw */
spinlock_t
vis_hash_lock
;
/* protects vis_hash */
spinlock_t
vis_list_lock
;
/* protects vis_info::recv_list */
spinlock_t
softif_neigh_lock
;
/* protects soft-interface neigh list */
spinlock_t
softif_neigh_vid_lock
;
/* protects soft-interface vid list */
int16_t
num_local_tt
;
atomic_t
tt_local_changed
;
atomic_t
num_local_tt
;
/* Checksum of the local table, recomputed before sending a new OGM */
atomic_t
tt_crc
;
unsigned
char
*
tt_buff
;
int16_t
tt_buff_len
;
spinlock_t
tt_buff_lock
;
/* protects tt_buff */
struct
delayed_work
tt_work
;
struct
delayed_work
orig_work
;
struct
delayed_work
vis_work
;
struct
gw_node
__rcu
*
curr_gw
;
/* rcu protected pointer */
atomic_t
gw_reselect
;
struct
hard_iface
__rcu
*
primary_if
;
/* rcu protected pointer */
struct
vis_info
*
my_vis_info
;
};
...
...
@@ -196,13 +225,38 @@ struct tt_local_entry {
uint8_t
addr
[
ETH_ALEN
];
unsigned
long
last_seen
;
char
never_purge
;
atomic_t
refcount
;
struct
rcu_head
rcu
;
struct
hlist_node
hash_entry
;
};
struct
tt_global_entry
{
uint8_t
addr
[
ETH_ALEN
];
struct
orig_node
*
orig_node
;
struct
hlist_node
hash_entry
;
uint8_t
ttvn
;
uint8_t
flags
;
/* only TT_GLOBAL_ROAM is used */
unsigned
long
roam_at
;
/* time at which TT_GLOBAL_ROAM was set */
atomic_t
refcount
;
struct
rcu_head
rcu
;
struct
hlist_node
hash_entry
;
/* entry in the global table */
};
struct
tt_change_node
{
struct
list_head
list
;
struct
tt_change
change
;
};
struct
tt_req_node
{
uint8_t
addr
[
ETH_ALEN
];
unsigned
long
issued_at
;
struct
list_head
list
;
};
struct
tt_roam_node
{
uint8_t
addr
[
ETH_ALEN
];
atomic_t
counter
;
unsigned
long
first_time
;
struct
list_head
list
;
};
/**
...
...
net/batman-adv/unicast.c
浏览文件 @
eac56465
...
...
@@ -325,6 +325,9 @@ int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv)
unicast_packet
->
ttl
=
TTL
;
/* copy the destination for faster routing */
memcpy
(
unicast_packet
->
dest
,
orig_node
->
orig
,
ETH_ALEN
);
/* set the destination tt version number */
unicast_packet
->
ttvn
=
(
uint8_t
)
atomic_read
(
&
orig_node
->
last_ttvn
);
if
(
atomic_read
(
&
bat_priv
->
fragmentation
)
&&
data_len
+
sizeof
(
*
unicast_packet
)
>
...
...
net/batman-adv/vis.c
浏览文件 @
eac56465
...
...
@@ -665,11 +665,12 @@ static int generate_vis_packet(struct bat_priv *bat_priv)
hash
=
bat_priv
->
tt_local_hash
;
spin_lock_bh
(
&
bat_priv
->
tt_lhash_lock
);
for
(
i
=
0
;
i
<
hash
->
size
;
i
++
)
{
head
=
&
hash
->
table
[
i
];
hlist_for_each_entry
(
tt_local_entry
,
node
,
head
,
hash_entry
)
{
rcu_read_lock
();
hlist_for_each_entry_rcu
(
tt_local_entry
,
node
,
head
,
hash_entry
)
{
entry
=
(
struct
vis_info_entry
*
)
skb_put
(
info
->
skb_packet
,
sizeof
(
*
entry
));
...
...
@@ -678,14 +679,12 @@ static int generate_vis_packet(struct bat_priv *bat_priv)
entry
->
quality
=
0
;
/* 0 means TT */
packet
->
entries
++
;
if
(
vis_packet_full
(
info
))
{
spin_unlock_bh
(
&
bat_priv
->
tt_lhash_lock
);
return
0
;
}
if
(
vis_packet_full
(
info
))
goto
unlock
;
}
rcu_read_unlock
();
}
spin_unlock_bh
(
&
bat_priv
->
tt_lhash_lock
);
return
0
;
unlock:
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录