Commit b8cec4a4 authored by David S. Miller's avatar David S. Miller

Merge branch 'batman-adv/next' of git://git.open-mesh.org/ecsv/linux-merge

parents 5e2b61f7 e44d8fe2
...@@ -35,7 +35,7 @@ static bool can_aggregate_with(struct batman_packet *new_batman_packet, ...@@ -35,7 +35,7 @@ static bool can_aggregate_with(struct batman_packet *new_batman_packet,
int packet_len, int packet_len,
unsigned long send_time, unsigned long send_time,
bool directlink, bool directlink,
struct batman_if *if_incoming, struct hard_iface *if_incoming,
struct forw_packet *forw_packet) struct forw_packet *forw_packet)
{ {
struct batman_packet *batman_packet = struct batman_packet *batman_packet =
...@@ -99,7 +99,7 @@ static bool can_aggregate_with(struct batman_packet *new_batman_packet, ...@@ -99,7 +99,7 @@ static bool can_aggregate_with(struct batman_packet *new_batman_packet,
/* create a new aggregated packet and add this packet to it */ /* create a new aggregated packet and add this packet to it */
static void new_aggregated_packet(unsigned char *packet_buff, int packet_len, static void new_aggregated_packet(unsigned char *packet_buff, int packet_len,
unsigned long send_time, bool direct_link, unsigned long send_time, bool direct_link,
struct batman_if *if_incoming, struct hard_iface *if_incoming,
int own_packet) int own_packet)
{ {
struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface); struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
...@@ -188,7 +188,7 @@ static void aggregate(struct forw_packet *forw_packet_aggr, ...@@ -188,7 +188,7 @@ static void aggregate(struct forw_packet *forw_packet_aggr,
void add_bat_packet_to_list(struct bat_priv *bat_priv, void add_bat_packet_to_list(struct bat_priv *bat_priv,
unsigned char *packet_buff, int packet_len, unsigned char *packet_buff, int packet_len,
struct batman_if *if_incoming, char own_packet, struct hard_iface *if_incoming, char own_packet,
unsigned long send_time) unsigned long send_time)
{ {
/** /**
...@@ -247,7 +247,7 @@ void add_bat_packet_to_list(struct bat_priv *bat_priv, ...@@ -247,7 +247,7 @@ void add_bat_packet_to_list(struct bat_priv *bat_priv,
/* unpack the aggregated packets and process them one by one */ /* unpack the aggregated packets and process them one by one */
void receive_aggr_bat_packet(struct ethhdr *ethhdr, unsigned char *packet_buff, void receive_aggr_bat_packet(struct ethhdr *ethhdr, unsigned char *packet_buff,
int packet_len, struct batman_if *if_incoming) int packet_len, struct hard_iface *if_incoming)
{ {
struct batman_packet *batman_packet; struct batman_packet *batman_packet;
int buff_pos = 0; int buff_pos = 0;
......
...@@ -35,9 +35,9 @@ static inline int aggregated_packet(int buff_pos, int packet_len, int num_hna) ...@@ -35,9 +35,9 @@ static inline int aggregated_packet(int buff_pos, int packet_len, int num_hna)
void add_bat_packet_to_list(struct bat_priv *bat_priv, void add_bat_packet_to_list(struct bat_priv *bat_priv,
unsigned char *packet_buff, int packet_len, unsigned char *packet_buff, int packet_len,
struct batman_if *if_incoming, char own_packet, struct hard_iface *if_incoming, char own_packet,
unsigned long send_time); unsigned long send_time);
void receive_aggr_bat_packet(struct ethhdr *ethhdr, unsigned char *packet_buff, void receive_aggr_bat_packet(struct ethhdr *ethhdr, unsigned char *packet_buff,
int packet_len, struct batman_if *if_incoming); int packet_len, struct hard_iface *if_incoming);
#endif /* _NET_BATMAN_ADV_AGGREGATION_H_ */ #endif /* _NET_BATMAN_ADV_AGGREGATION_H_ */
...@@ -441,16 +441,16 @@ static ssize_t show_mesh_iface(struct kobject *kobj, struct attribute *attr, ...@@ -441,16 +441,16 @@ static ssize_t show_mesh_iface(struct kobject *kobj, struct attribute *attr,
char *buff) char *buff)
{ {
struct net_device *net_dev = kobj_to_netdev(kobj); struct net_device *net_dev = kobj_to_netdev(kobj);
struct batman_if *batman_if = get_batman_if_by_netdev(net_dev); struct hard_iface *hard_iface = hardif_get_by_netdev(net_dev);
ssize_t length; ssize_t length;
if (!batman_if) if (!hard_iface)
return 0; return 0;
length = sprintf(buff, "%s\n", batman_if->if_status == IF_NOT_IN_USE ? length = sprintf(buff, "%s\n", hard_iface->if_status == IF_NOT_IN_USE ?
"none" : batman_if->soft_iface->name); "none" : hard_iface->soft_iface->name);
kref_put(&batman_if->refcount, hardif_free_ref); hardif_free_ref(hard_iface);
return length; return length;
} }
...@@ -459,11 +459,11 @@ static ssize_t store_mesh_iface(struct kobject *kobj, struct attribute *attr, ...@@ -459,11 +459,11 @@ static ssize_t store_mesh_iface(struct kobject *kobj, struct attribute *attr,
char *buff, size_t count) char *buff, size_t count)
{ {
struct net_device *net_dev = kobj_to_netdev(kobj); struct net_device *net_dev = kobj_to_netdev(kobj);
struct batman_if *batman_if = get_batman_if_by_netdev(net_dev); struct hard_iface *hard_iface = hardif_get_by_netdev(net_dev);
int status_tmp = -1; int status_tmp = -1;
int ret; int ret = count;
if (!batman_if) if (!hard_iface)
return count; return count;
if (buff[count - 1] == '\n') if (buff[count - 1] == '\n')
...@@ -472,7 +472,7 @@ static ssize_t store_mesh_iface(struct kobject *kobj, struct attribute *attr, ...@@ -472,7 +472,7 @@ static ssize_t store_mesh_iface(struct kobject *kobj, struct attribute *attr,
if (strlen(buff) >= IFNAMSIZ) { if (strlen(buff) >= IFNAMSIZ) {
pr_err("Invalid parameter for 'mesh_iface' setting received: " pr_err("Invalid parameter for 'mesh_iface' setting received: "
"interface name too long '%s'\n", buff); "interface name too long '%s'\n", buff);
kref_put(&batman_if->refcount, hardif_free_ref); hardif_free_ref(hard_iface);
return -EINVAL; return -EINVAL;
} }
...@@ -481,30 +481,31 @@ static ssize_t store_mesh_iface(struct kobject *kobj, struct attribute *attr, ...@@ -481,30 +481,31 @@ static ssize_t store_mesh_iface(struct kobject *kobj, struct attribute *attr,
else else
status_tmp = IF_I_WANT_YOU; status_tmp = IF_I_WANT_YOU;
if ((batman_if->if_status == status_tmp) || ((batman_if->soft_iface) && if (hard_iface->if_status == status_tmp)
(strncmp(batman_if->soft_iface->name, buff, IFNAMSIZ) == 0))) { goto out;
kref_put(&batman_if->refcount, hardif_free_ref);
return count; if ((hard_iface->soft_iface) &&
} (strncmp(hard_iface->soft_iface->name, buff, IFNAMSIZ) == 0))
goto out;
if (status_tmp == IF_NOT_IN_USE) { if (status_tmp == IF_NOT_IN_USE) {
rtnl_lock(); rtnl_lock();
hardif_disable_interface(batman_if); hardif_disable_interface(hard_iface);
rtnl_unlock(); rtnl_unlock();
kref_put(&batman_if->refcount, hardif_free_ref); goto out;
return count;
} }
/* if the interface already is in use */ /* if the interface already is in use */
if (batman_if->if_status != IF_NOT_IN_USE) { if (hard_iface->if_status != IF_NOT_IN_USE) {
rtnl_lock(); rtnl_lock();
hardif_disable_interface(batman_if); hardif_disable_interface(hard_iface);
rtnl_unlock(); rtnl_unlock();
} }
ret = hardif_enable_interface(batman_if, buff); ret = hardif_enable_interface(hard_iface, buff);
kref_put(&batman_if->refcount, hardif_free_ref);
out:
hardif_free_ref(hard_iface);
return ret; return ret;
} }
...@@ -512,13 +513,13 @@ static ssize_t show_iface_status(struct kobject *kobj, struct attribute *attr, ...@@ -512,13 +513,13 @@ static ssize_t show_iface_status(struct kobject *kobj, struct attribute *attr,
char *buff) char *buff)
{ {
struct net_device *net_dev = kobj_to_netdev(kobj); struct net_device *net_dev = kobj_to_netdev(kobj);
struct batman_if *batman_if = get_batman_if_by_netdev(net_dev); struct hard_iface *hard_iface = hardif_get_by_netdev(net_dev);
ssize_t length; ssize_t length;
if (!batman_if) if (!hard_iface)
return 0; return 0;
switch (batman_if->if_status) { switch (hard_iface->if_status) {
case IF_TO_BE_REMOVED: case IF_TO_BE_REMOVED:
length = sprintf(buff, "disabling\n"); length = sprintf(buff, "disabling\n");
break; break;
...@@ -537,7 +538,7 @@ static ssize_t show_iface_status(struct kobject *kobj, struct attribute *attr, ...@@ -537,7 +538,7 @@ static ssize_t show_iface_status(struct kobject *kobj, struct attribute *attr,
break; break;
} }
kref_put(&batman_if->refcount, hardif_free_ref); hardif_free_ref(hard_iface);
return length; return length;
} }
......
...@@ -28,58 +28,75 @@ ...@@ -28,58 +28,75 @@
#include <linux/udp.h> #include <linux/udp.h>
#include <linux/if_vlan.h> #include <linux/if_vlan.h>
static void gw_node_free_ref(struct kref *refcount) static void gw_node_free_rcu(struct rcu_head *rcu)
{ {
struct gw_node *gw_node; struct gw_node *gw_node;
gw_node = container_of(refcount, struct gw_node, refcount); gw_node = container_of(rcu, struct gw_node, rcu);
kfree(gw_node); kfree(gw_node);
} }
static void gw_node_free_rcu(struct rcu_head *rcu) static void gw_node_free_ref(struct gw_node *gw_node)
{ {
struct gw_node *gw_node; if (atomic_dec_and_test(&gw_node->refcount))
call_rcu(&gw_node->rcu, gw_node_free_rcu);
gw_node = container_of(rcu, struct gw_node, rcu);
kref_put(&gw_node->refcount, gw_node_free_ref);
} }
void *gw_get_selected(struct bat_priv *bat_priv) void *gw_get_selected(struct bat_priv *bat_priv)
{ {
struct gw_node *curr_gateway_tmp = bat_priv->curr_gw; struct gw_node *curr_gateway_tmp;
struct orig_node *orig_node = NULL;
rcu_read_lock();
curr_gateway_tmp = rcu_dereference(bat_priv->curr_gw);
if (!curr_gateway_tmp) if (!curr_gateway_tmp)
return NULL; goto out;
orig_node = curr_gateway_tmp->orig_node;
if (!orig_node)
goto out;
return curr_gateway_tmp->orig_node; if (!atomic_inc_not_zero(&orig_node->refcount))
orig_node = NULL;
out:
rcu_read_unlock();
return orig_node;
} }
void gw_deselect(struct bat_priv *bat_priv) void gw_deselect(struct bat_priv *bat_priv)
{ {
struct gw_node *gw_node = bat_priv->curr_gw; struct gw_node *gw_node;
bat_priv->curr_gw = NULL; spin_lock_bh(&bat_priv->gw_list_lock);
gw_node = rcu_dereference(bat_priv->curr_gw);
rcu_assign_pointer(bat_priv->curr_gw, NULL);
spin_unlock_bh(&bat_priv->gw_list_lock);
if (gw_node) if (gw_node)
kref_put(&gw_node->refcount, gw_node_free_ref); gw_node_free_ref(gw_node);
} }
static struct gw_node *gw_select(struct bat_priv *bat_priv, static void gw_select(struct bat_priv *bat_priv, struct gw_node *new_gw_node)
struct gw_node *new_gw_node)
{ {
struct gw_node *curr_gw_node = bat_priv->curr_gw; struct gw_node *curr_gw_node;
if (new_gw_node) if (new_gw_node && !atomic_inc_not_zero(&new_gw_node->refcount))
kref_get(&new_gw_node->refcount); new_gw_node = NULL;
spin_lock_bh(&bat_priv->gw_list_lock);
curr_gw_node = rcu_dereference(bat_priv->curr_gw);
rcu_assign_pointer(bat_priv->curr_gw, new_gw_node);
spin_unlock_bh(&bat_priv->gw_list_lock);
bat_priv->curr_gw = new_gw_node; if (curr_gw_node)
return curr_gw_node; gw_node_free_ref(curr_gw_node);
} }
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_tmp = NULL, *old_gw_node = NULL; struct gw_node *gw_node, *curr_gw, *curr_gw_tmp = NULL;
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;
...@@ -93,19 +110,23 @@ void gw_election(struct bat_priv *bat_priv) ...@@ -93,19 +110,23 @@ 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;
if (bat_priv->curr_gw) rcu_read_lock();
curr_gw = rcu_dereference(bat_priv->curr_gw);
if (curr_gw) {
rcu_read_unlock();
return; return;
}
rcu_read_lock();
if (hlist_empty(&bat_priv->gw_list)) { if (hlist_empty(&bat_priv->gw_list)) {
rcu_read_unlock();
if (bat_priv->curr_gw) { if (curr_gw) {
rcu_read_unlock();
bat_dbg(DBG_BATMAN, bat_priv, bat_dbg(DBG_BATMAN, bat_priv,
"Removing selected gateway - " "Removing selected gateway - "
"no gateway in range\n"); "no gateway in range\n");
gw_deselect(bat_priv); gw_deselect(bat_priv);
} } else
rcu_read_unlock();
return; return;
} }
...@@ -154,12 +175,12 @@ void gw_election(struct bat_priv *bat_priv) ...@@ -154,12 +175,12 @@ void gw_election(struct bat_priv *bat_priv)
max_gw_factor = tmp_gw_factor; max_gw_factor = tmp_gw_factor;
} }
if (bat_priv->curr_gw != curr_gw_tmp) { if (curr_gw != curr_gw_tmp) {
if ((bat_priv->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 - "
"no gateway in range\n"); "no gateway in range\n");
else if ((!bat_priv->curr_gw) && (curr_gw_tmp)) else if ((!curr_gw) && (curr_gw_tmp))
bat_dbg(DBG_BATMAN, bat_priv, bat_dbg(DBG_BATMAN, bat_priv,
"Adding route to gateway %pM " "Adding route to gateway %pM "
"(gw_flags: %i, tq: %i)\n", "(gw_flags: %i, tq: %i)\n",
...@@ -174,43 +195,43 @@ void gw_election(struct bat_priv *bat_priv) ...@@ -174,43 +195,43 @@ void gw_election(struct bat_priv *bat_priv)
curr_gw_tmp->orig_node->gw_flags, curr_gw_tmp->orig_node->gw_flags,
curr_gw_tmp->orig_node->router->tq_avg); curr_gw_tmp->orig_node->router->tq_avg);
old_gw_node = gw_select(bat_priv, curr_gw_tmp); gw_select(bat_priv, curr_gw_tmp);
} }
rcu_read_unlock(); rcu_read_unlock();
/* the kfree() has to be outside of the rcu lock */
if (old_gw_node)
kref_put(&old_gw_node->refcount, gw_node_free_ref);
} }
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 = bat_priv->curr_gw; struct gw_node *curr_gateway_tmp;
uint8_t gw_tq_avg, orig_tq_avg; uint8_t gw_tq_avg, orig_tq_avg;
rcu_read_lock();
curr_gateway_tmp = rcu_dereference(bat_priv->curr_gw);
if (!curr_gateway_tmp) if (!curr_gateway_tmp)
return; goto out_rcu;
if (!curr_gateway_tmp->orig_node) if (!curr_gateway_tmp->orig_node)
goto deselect; goto deselect_rcu;
if (!curr_gateway_tmp->orig_node->router) if (!curr_gateway_tmp->orig_node->router)
goto deselect; 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_gateway_tmp->orig_node == orig_node)
return; goto out_rcu;
if (!orig_node->router) if (!orig_node->router)
return; goto out_rcu;
gw_tq_avg = curr_gateway_tmp->orig_node->router->tq_avg; gw_tq_avg = curr_gateway_tmp->orig_node->router->tq_avg;
rcu_read_unlock();
orig_tq_avg = orig_node->router->tq_avg; orig_tq_avg = orig_node->router->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)
return; goto out;
/** /**
* if the routing class is greater than 3 the value tells us how much * if the routing class is greater than 3 the value tells us how much
...@@ -218,15 +239,23 @@ void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node) ...@@ -218,15 +239,23 @@ void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node)
**/ **/
if ((atomic_read(&bat_priv->gw_sel_class) > 3) && if ((atomic_read(&bat_priv->gw_sel_class) > 3) &&
(orig_tq_avg - gw_tq_avg < atomic_read(&bat_priv->gw_sel_class))) (orig_tq_avg - gw_tq_avg < atomic_read(&bat_priv->gw_sel_class)))
return; goto out;
bat_dbg(DBG_BATMAN, bat_priv, bat_dbg(DBG_BATMAN, bat_priv,
"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:
return;
} }
static void gw_node_add(struct bat_priv *bat_priv, static void gw_node_add(struct bat_priv *bat_priv,
...@@ -242,7 +271,7 @@ static void gw_node_add(struct bat_priv *bat_priv, ...@@ -242,7 +271,7 @@ static void gw_node_add(struct bat_priv *bat_priv,
memset(gw_node, 0, sizeof(struct gw_node)); memset(gw_node, 0, sizeof(struct gw_node));
INIT_HLIST_NODE(&gw_node->list); INIT_HLIST_NODE(&gw_node->list);
gw_node->orig_node = orig_node; gw_node->orig_node = orig_node;
kref_init(&gw_node->refcount); atomic_set(&gw_node->refcount, 1);
spin_lock_bh(&bat_priv->gw_list_lock); spin_lock_bh(&bat_priv->gw_list_lock);
hlist_add_head_rcu(&gw_node->list, &bat_priv->gw_list); hlist_add_head_rcu(&gw_node->list, &bat_priv->gw_list);
...@@ -283,7 +312,7 @@ void gw_node_update(struct bat_priv *bat_priv, ...@@ -283,7 +312,7 @@ 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 == bat_priv->curr_gw) { if (gw_node == rcu_dereference(bat_priv->curr_gw)) {
rcu_read_unlock(); rcu_read_unlock();
gw_deselect(bat_priv); gw_deselect(bat_priv);
return; return;
...@@ -321,11 +350,11 @@ void gw_node_purge(struct bat_priv *bat_priv) ...@@ -321,11 +350,11 @@ 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 (bat_priv->curr_gw == gw_node) if (rcu_dereference(bat_priv->curr_gw) == gw_node)
gw_deselect(bat_priv); gw_deselect(bat_priv);
hlist_del_rcu(&gw_node->list); hlist_del_rcu(&gw_node->list);
call_rcu(&gw_node->rcu, gw_node_free_rcu); gw_node_free_ref(gw_node);
} }
...@@ -335,12 +364,16 @@ void gw_node_purge(struct bat_priv *bat_priv) ...@@ -335,12 +364,16 @@ void gw_node_purge(struct bat_priv *bat_priv)
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)
{ {
int down, up; struct gw_node *curr_gw;
int down, up, ret;
gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags, &down, &up); gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags, &down, &up);
return seq_printf(seq, "%s %pM (%3i) %pM [%10s]: %3i - %i%s/%i%s\n", rcu_read_lock();
(bat_priv->curr_gw == gw_node ? "=>" : " "), curr_gw = rcu_dereference(bat_priv->curr_gw);
ret = seq_printf(seq, "%s %pM (%3i) %pM [%10s]: %3i - %i%s/%i%s\n",
(curr_gw == gw_node ? "=>" : " "),
gw_node->orig_node->orig, gw_node->orig_node->orig,
gw_node->orig_node->router->tq_avg, gw_node->orig_node->router->tq_avg,
gw_node->orig_node->router->addr, gw_node->orig_node->router->addr,
...@@ -350,6 +383,9 @@ static int _write_buffer_text(struct bat_priv *bat_priv, ...@@ -350,6 +383,9 @@ static int _write_buffer_text(struct bat_priv *bat_priv,
(down > 2048 ? "MBit" : "KBit"), (down > 2048 ? "MBit" : "KBit"),
(up > 2048 ? up / 1024 : up), (up > 2048 ? up / 1024 : up),
(up > 2048 ? "MBit" : "KBit")); (up > 2048 ? "MBit" : "KBit"));
rcu_read_unlock();
return ret;
} }
int gw_client_seq_print_text(struct seq_file *seq, void *offset) int gw_client_seq_print_text(struct seq_file *seq, void *offset)
...@@ -470,8 +506,12 @@ int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb) ...@@ -470,8 +506,12 @@ 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;
if (!bat_priv->curr_gw) rcu_read_lock();
if (!rcu_dereference(bat_priv->curr_gw)) {
rcu_read_unlock();
return 0; return 0;
}
rcu_read_unlock();
return 1; return 1;
} }
This diff is collapsed.
...@@ -31,19 +31,18 @@ ...@@ -31,19 +31,18 @@
extern struct notifier_block hard_if_notifier; extern struct notifier_block hard_if_notifier;
struct batman_if *get_batman_if_by_netdev(struct net_device *net_dev); struct hard_iface *hardif_get_by_netdev(struct net_device *net_dev);
int hardif_enable_interface(struct batman_if *batman_if, char *iface_name); int hardif_enable_interface(struct hard_iface *hard_iface, char *iface_name);
void hardif_disable_interface(struct batman_if *batman_if); void hardif_disable_interface(struct hard_iface *hard_iface);
void hardif_remove_interfaces(void); void hardif_remove_interfaces(void);
int hardif_min_mtu(struct net_device *soft_iface); int hardif_min_mtu(struct net_device *soft_iface);
void update_min_mtu(struct net_device *soft_iface); void update_min_mtu(struct net_device *soft_iface);
void hardif_free_rcu(struct rcu_head *rcu);
static inline void hardif_free_ref(struct kref *refcount) static inline void hardif_free_ref(struct hard_iface *hard_iface)
{ {
struct batman_if *batman_if; if (atomic_dec_and_test(&hard_iface->refcount))
call_rcu(&hard_iface->rcu, hardif_free_rcu);
batman_if = container_of(refcount, struct batman_if, refcount);
kfree(batman_if);
} }
#endif /* _NET_BATMAN_ADV_HARD_INTERFACE_H_ */ #endif /* _NET_BATMAN_ADV_HARD_INTERFACE_H_ */
...@@ -27,13 +27,16 @@ static void hash_init(struct hashtable_t *hash) ...@@ -27,13 +27,16 @@ static void hash_init(struct hashtable_t *hash)
{ {
int i; int i;
for (i = 0 ; i < hash->size; i++) for (i = 0 ; i < hash->size; i++) {
INIT_HLIST_HEAD(&hash->table[i]); INIT_HLIST_HEAD(&hash->table[i]);
spin_lock_init(&hash->list_locks[i]);
}
} }
/* free only the hashtable and the hash itself. */ /* free only the hashtable and the hash itself. */
void hash_destroy(struct hashtable_t *hash) void hash_destroy(struct hashtable_t *hash)
{ {
kfree(hash->list_locks);
kfree(hash->table); kfree(hash->table);
kfree(hash); kfree(hash);
} }
...@@ -43,20 +46,25 @@ struct hashtable_t *hash_new(int size) ...@@ -43,20 +46,25 @@ struct hashtable_t *hash_new(int size)
{ {
struct hashtable_t *hash; struct hashtable_t *hash;
hash = kmalloc(sizeof(struct hashtable_t) , GFP_ATOMIC); hash = kmalloc(sizeof(struct hashtable_t), GFP_ATOMIC);
if (!hash) if (!hash)
return NULL; return NULL;
hash->size = size;
hash->table = kmalloc(sizeof(struct element_t *) * size, GFP_ATOMIC); hash->table = kmalloc(sizeof(struct element_t *) * size, GFP_ATOMIC);
if (!hash->table)
goto free_hash;
if (!hash->table) { hash->list_locks = kmalloc(sizeof(spinlock_t) * size, GFP_ATOMIC);
kfree(hash); if (!hash->list_locks)
return NULL; goto free_table;
}
hash->size = size;
hash_init(hash); hash_init(hash);
return hash; return hash;
free_table:
kfree(hash->table);
free_hash:
kfree(hash);
return NULL;
} }
...@@ -28,21 +28,17 @@ ...@@ -28,21 +28,17 @@
* compare 2 element datas for their keys, * compare 2 element datas for their keys,
* return 0 if same and not 0 if not * return 0 if same and not 0 if not
* same */ * same */
typedef int (*hashdata_compare_cb)(void *, void *); typedef int (*hashdata_compare_cb)(struct hlist_node *, void *);
/* the hashfunction, should return an index /* the hashfunction, should return an index
* based on the key in the data of the first * based on the key in the data of the first
* argument and the size the second */ * argument and the size the second */
typedef int (*hashdata_choose_cb)(void *, int); typedef int (*hashdata_choose_cb)(void *, int);
typedef void (*hashdata_free_cb)(void *, void *); typedef void (*hashdata_free_cb)(struct hlist_node *, void *);
struct element_t {
void *data; /* pointer to the data */
struct hlist_node hlist; /* bucket list pointer */
};
struct hashtable_t { struct hashtable_t {
struct hlist_head *table; /* the hashtable itself, with the buckets */ struct hlist_head *table; /* the hashtable itself with the buckets */
spinlock_t *list_locks; /* spinlock for each hash list entry */
int size; /* size of hashtable */ int size; /* size of hashtable */
}; };
...@@ -59,21 +55,22 @@ static inline void hash_delete(struct hashtable_t *hash, ...@@ -59,21 +55,22 @@ static inline void hash_delete(struct hashtable_t *hash,
hashdata_free_cb free_cb, void *arg) hashdata_free_cb free_cb, void *arg)
{ {
struct hlist_head *head; struct hlist_head *head;
struct hlist_node *walk, *safe; struct hlist_node *node, *node_tmp;
struct element_t *bucket; spinlock_t *list_lock; /* spinlock to protect write access */
int i; int i;
for (i = 0; i < hash->size; i++) { for (i = 0; i < hash->size; i++) {
head = &hash->table[i]; head = &hash->table[i];
list_lock = &hash->list_locks[i];
hlist_for_each_safe(walk, safe, head) { spin_lock_bh(list_lock);
bucket = hlist_entry(walk, struct element_t, hlist); hlist_for_each_safe(node, node_tmp, head) {
if (free_cb) hlist_del_rcu(node);
free_cb(bucket->data, arg);
hlist_del(walk); if (free_cb)
kfree(bucket); free_cb(node, arg);
} }
spin_unlock_bh(list_lock);
} }
hash_destroy(hash); hash_destroy(hash);
...@@ -82,35 +79,41 @@ static inline void hash_delete(struct hashtable_t *hash, ...@@ -82,35 +79,41 @@ static inline void hash_delete(struct hashtable_t *hash,
/* adds data to the hashtable. returns 0 on success, -1 on error */ /* adds data to the hashtable. returns 0 on success, -1 on error */
static inline int hash_add(struct hashtable_t *hash, static inline int hash_add(struct hashtable_t *hash,
hashdata_compare_cb compare, hashdata_compare_cb compare,
hashdata_choose_cb choose, void *data) hashdata_choose_cb choose,
void *data, struct hlist_node *data_node)
{ {
int index; int index;
struct hlist_head *head; struct hlist_head *head;
struct hlist_node *walk, *safe; struct hlist_node *node;
struct element_t *bucket; spinlock_t *list_lock; /* spinlock to protect write access */
if (!hash) if (!hash)
return -1; goto err;
index = choose(data, hash->size); index = choose(data, hash->size);
head = &hash->table[index]; head = &hash->table[index];
list_lock = &hash->list_locks[index];
rcu_read_lock();
__hlist_for_each_rcu(node, head) {
if (!compare(node, data))
continue;
hlist_for_each_safe(walk, safe, head) { goto err_unlock;
bucket = hlist_entry(walk, struct element_t, hlist);
if (compare(bucket->data, data))
return -1;
} }
rcu_read_unlock();
/* no duplicate found in list, add new element */ /* no duplicate found in list, add new element */
bucket = kmalloc(sizeof(struct element_t), GFP_ATOMIC); spin_lock_bh(list_lock);
hlist_add_head_rcu(data_node, head);
if (!bucket) spin_unlock_bh(list_lock);
return -1;
bucket->data = data;
hlist_add_head(&bucket->hlist, head);
return 0; return 0;
err_unlock:
rcu_read_unlock();
err:
return -1;
} }
/* removes data from hash, if found. returns pointer do data on success, so you /* removes data from hash, if found. returns pointer do data on success, so you
...@@ -122,50 +125,25 @@ static inline void *hash_remove(struct hashtable_t *hash, ...@@ -122,50 +125,25 @@ static inline void *hash_remove(struct hashtable_t *hash,
hashdata_choose_cb choose, void *data) hashdata_choose_cb choose, void *data)
{ {
size_t index; size_t index;
struct hlist_node *walk; struct hlist_node *node;
struct element_t *bucket;
struct hlist_head *head; struct hlist_head *head;
void *data_save; void *data_save = NULL;
index = choose(data, hash->size); index = choose(data, hash->size);
head = &hash->table[index]; head = &hash->table[index];
hlist_for_each_entry(bucket, walk, head, hlist) { spin_lock_bh(&hash->list_locks[index]);
if (compare(bucket->data, data)) { hlist_for_each(node, head) {
data_save = bucket->data; if (!compare(node, data))
hlist_del(walk); continue;
kfree(bucket);
return data_save;
}
}
return NULL;
}
/* finds data, based on the key in keydata. returns the found data on success,
* or NULL on error */
static inline void *hash_find(struct hashtable_t *hash,
hashdata_compare_cb compare,
hashdata_choose_cb choose, void *keydata)
{
int index;
struct hlist_head *head;
struct hlist_node *walk;
struct element_t *bucket;
if (!hash)
return NULL;
index = choose(keydata , hash->size);
head = &hash->table[index];
hlist_for_each(walk, head) { data_save = node;
bucket = hlist_entry(walk, struct element_t, hlist); hlist_del_rcu(node);
if (compare(bucket->data, keydata)) break;
return bucket->data;
} }
spin_unlock_bh(&hash->list_locks[index]);
return NULL; return data_save;
} }
#endif /* _NET_BATMAN_ADV_HASH_H_ */ #endif /* _NET_BATMAN_ADV_HASH_H_ */
...@@ -156,10 +156,9 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff, ...@@ -156,10 +156,9 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff,
struct sk_buff *skb; struct sk_buff *skb;
struct icmp_packet_rr *icmp_packet; struct icmp_packet_rr *icmp_packet;
struct orig_node *orig_node; struct orig_node *orig_node = NULL;
struct batman_if *batman_if; struct neigh_node *neigh_node = NULL;
size_t packet_len = sizeof(struct icmp_packet); size_t packet_len = sizeof(struct icmp_packet);
uint8_t dstaddr[ETH_ALEN];
if (len < sizeof(struct icmp_packet)) { if (len < sizeof(struct icmp_packet)) {
bat_dbg(DBG_BATMAN, bat_priv, bat_dbg(DBG_BATMAN, bat_priv,
...@@ -219,47 +218,52 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff, ...@@ -219,47 +218,52 @@ 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;
spin_lock_bh(&bat_priv->orig_hash_lock); rcu_read_lock();
orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, orig_node = orig_hash_find(bat_priv, icmp_packet->dst);
compare_orig, choose_orig,
icmp_packet->dst));
if (!orig_node) if (!orig_node)
goto unlock; goto unlock;
if (!orig_node->router) neigh_node = orig_node->router;
if (!neigh_node)
goto unlock; goto unlock;
batman_if = orig_node->router->if_incoming; if (!atomic_inc_not_zero(&neigh_node->refcount)) {
memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); neigh_node = NULL;
goto unlock;
}
spin_unlock_bh(&bat_priv->orig_hash_lock); rcu_read_unlock();
if (!batman_if) if (!neigh_node->if_incoming)
goto dst_unreach; goto dst_unreach;
if (batman_if->if_status != IF_ACTIVE) if (neigh_node->if_incoming->if_status != IF_ACTIVE)
goto dst_unreach; goto dst_unreach;
memcpy(icmp_packet->orig, memcpy(icmp_packet->orig,
bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN);
if (packet_len == sizeof(struct icmp_packet_rr)) if (packet_len == sizeof(struct icmp_packet_rr))
memcpy(icmp_packet->rr, batman_if->net_dev->dev_addr, ETH_ALEN); memcpy(icmp_packet->rr,
neigh_node->if_incoming->net_dev->dev_addr, ETH_ALEN);
send_skb_packet(skb, batman_if, dstaddr);
send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
goto out; goto out;
unlock: unlock:
spin_unlock_bh(&bat_priv->orig_hash_lock); 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);
free_skb: free_skb:
kfree_skb(skb); kfree_skb(skb);
out: out:
if (neigh_node)
neigh_node_free_ref(neigh_node);
if (orig_node)
orig_node_free_ref(orig_node);
return len; return len;
} }
......
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,7 @@
#include "vis.h" #include "vis.h"
#include "hash.h" #include "hash.h"
struct list_head if_list; struct list_head hardif_list;
unsigned char broadcast_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; unsigned char broadcast_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
...@@ -41,7 +41,7 @@ struct workqueue_struct *bat_event_workqueue; ...@@ -41,7 +41,7 @@ struct workqueue_struct *bat_event_workqueue;
static int __init batman_init(void) static int __init batman_init(void)
{ {
INIT_LIST_HEAD(&if_list); INIT_LIST_HEAD(&hardif_list);
/* the name should not be longer than 10 chars - see /* the name should not be longer than 10 chars - see
* http://lwn.net/Articles/23634/ */ * http://lwn.net/Articles/23634/ */
...@@ -79,7 +79,6 @@ int mesh_init(struct net_device *soft_iface) ...@@ -79,7 +79,6 @@ int mesh_init(struct net_device *soft_iface)
{ {
struct bat_priv *bat_priv = netdev_priv(soft_iface); struct bat_priv *bat_priv = netdev_priv(soft_iface);
spin_lock_init(&bat_priv->orig_hash_lock);
spin_lock_init(&bat_priv->forw_bat_list_lock); spin_lock_init(&bat_priv->forw_bat_list_lock);
spin_lock_init(&bat_priv->forw_bcast_list_lock); spin_lock_init(&bat_priv->forw_bcast_list_lock);
spin_lock_init(&bat_priv->hna_lhash_lock); spin_lock_init(&bat_priv->hna_lhash_lock);
...@@ -154,14 +153,14 @@ void dec_module_count(void) ...@@ -154,14 +153,14 @@ void dec_module_count(void)
int is_my_mac(uint8_t *addr) int is_my_mac(uint8_t *addr)
{ {
struct batman_if *batman_if; struct hard_iface *hard_iface;
rcu_read_lock(); rcu_read_lock();
list_for_each_entry_rcu(batman_if, &if_list, list) { list_for_each_entry_rcu(hard_iface, &hardif_list, list) {
if (batman_if->if_status != IF_ACTIVE) if (hard_iface->if_status != IF_ACTIVE)
continue; continue;
if (compare_orig(batman_if->net_dev->dev_addr, addr)) { if (compare_eth(hard_iface->net_dev->dev_addr, addr)) {
rcu_read_unlock(); rcu_read_unlock();
return 1; return 1;
} }
......
...@@ -122,7 +122,7 @@ ...@@ -122,7 +122,7 @@
#define REVISION_VERSION_STR " "REVISION_VERSION #define REVISION_VERSION_STR " "REVISION_VERSION
#endif #endif
extern struct list_head if_list; extern struct list_head hardif_list;
extern unsigned char broadcast_addr[]; extern unsigned char broadcast_addr[];
extern struct workqueue_struct *bat_event_workqueue; extern struct workqueue_struct *bat_event_workqueue;
...@@ -165,4 +165,14 @@ static inline void bat_dbg(char type __always_unused, ...@@ -165,4 +165,14 @@ static inline void bat_dbg(char type __always_unused,
pr_err("%s: " fmt, _netdev->name, ## arg); \ pr_err("%s: " fmt, _netdev->name, ## arg); \
} while (0) } while (0)
/**
* returns 1 if they are the same ethernet addr
*
* note: can't use compare_ether_addr() as it requires aligned memory
*/
static inline int compare_eth(void *data1, void *data2)
{
return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0);
}
#endif /* _NET_BATMAN_ADV_MAIN_H_ */ #endif /* _NET_BATMAN_ADV_MAIN_H_ */
This diff is collapsed.
...@@ -22,21 +22,28 @@ ...@@ -22,21 +22,28 @@
#ifndef _NET_BATMAN_ADV_ORIGINATOR_H_ #ifndef _NET_BATMAN_ADV_ORIGINATOR_H_
#define _NET_BATMAN_ADV_ORIGINATOR_H_ #define _NET_BATMAN_ADV_ORIGINATOR_H_
#include "hash.h"
int originator_init(struct bat_priv *bat_priv); int originator_init(struct bat_priv *bat_priv);
void originator_free(struct bat_priv *bat_priv); void originator_free(struct bat_priv *bat_priv);
void purge_orig_ref(struct bat_priv *bat_priv); void purge_orig_ref(struct bat_priv *bat_priv);
void orig_node_free_ref(struct orig_node *orig_node);
struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr); struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr);
struct neigh_node * struct neigh_node *create_neighbor(struct orig_node *orig_node,
create_neighbor(struct orig_node *orig_node, struct orig_node *orig_neigh_node, struct orig_node *orig_neigh_node,
uint8_t *neigh, struct batman_if *if_incoming); uint8_t *neigh,
struct hard_iface *if_incoming);
void neigh_node_free_ref(struct neigh_node *neigh_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 batman_if *batman_if, int max_if_num); int orig_hash_add_if(struct hard_iface *hard_iface, int max_if_num);
int orig_hash_del_if(struct batman_if *batman_if, 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 */ /* returns 1 if they are the same originator */
static inline int compare_orig(void *data1, void *data2) static inline int compare_orig(struct hlist_node *node, void *data2)
{ {
void *data1 = container_of(node, struct orig_node, hash_entry);
return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0); return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0);
} }
...@@ -61,4 +68,35 @@ static inline int choose_orig(void *data, int32_t size) ...@@ -61,4 +68,35 @@ static inline int choose_orig(void *data, int32_t size)
return hash % size; return hash % size;
} }
static inline struct orig_node *orig_hash_find(struct bat_priv *bat_priv,
void *data)
{
struct hashtable_t *hash = bat_priv->orig_hash;
struct hlist_head *head;
struct hlist_node *node;
struct orig_node *orig_node, *orig_node_tmp = NULL;
int index;
if (!hash)
return NULL;
index = choose_orig(data, hash->size);
head = &hash->table[index];
rcu_read_lock();
hlist_for_each_entry_rcu(orig_node, node, head, hash_entry) {
if (!compare_eth(orig_node, data))
continue;
if (!atomic_inc_not_zero(&orig_node->refcount))
continue;
orig_node_tmp = orig_node;
break;
}
rcu_read_unlock();
return orig_node_tmp;
}
#endif /* _NET_BATMAN_ADV_ORIGINATOR_H_ */ #endif /* _NET_BATMAN_ADV_ORIGINATOR_H_ */
This diff is collapsed.
...@@ -22,24 +22,25 @@ ...@@ -22,24 +22,25 @@
#ifndef _NET_BATMAN_ADV_ROUTING_H_ #ifndef _NET_BATMAN_ADV_ROUTING_H_
#define _NET_BATMAN_ADV_ROUTING_H_ #define _NET_BATMAN_ADV_ROUTING_H_
void slide_own_bcast_window(struct batman_if *batman_if); void slide_own_bcast_window(struct hard_iface *hard_iface);
void receive_bat_packet(struct ethhdr *ethhdr, void receive_bat_packet(struct ethhdr *ethhdr,
struct batman_packet *batman_packet, struct batman_packet *batman_packet,
unsigned char *hna_buff, int hna_buff_len, unsigned char *hna_buff, int hna_buff_len,
struct batman_if *if_incoming); struct hard_iface *if_incoming);
void update_routes(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, unsigned char *hna_buff, struct neigh_node *neigh_node, unsigned char *hna_buff,
int hna_buff_len); int hna_buff_len);
int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if, int route_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if);
int hdr_size); int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *recv_if);
int recv_icmp_packet(struct sk_buff *skb, struct batman_if *recv_if); int recv_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if);
int recv_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if); int recv_ucast_frag_packet(struct sk_buff *skb, struct hard_iface *recv_if);
int recv_ucast_frag_packet(struct sk_buff *skb, struct batman_if *recv_if); int recv_bcast_packet(struct sk_buff *skb, struct hard_iface *recv_if);
int recv_bcast_packet(struct sk_buff *skb, struct batman_if *recv_if); int recv_vis_packet(struct sk_buff *skb, struct hard_iface *recv_if);
int recv_vis_packet(struct sk_buff *skb, struct batman_if *recv_if); int recv_bat_packet(struct sk_buff *skb, struct hard_iface *recv_if);
int recv_bat_packet(struct sk_buff *skb, struct batman_if *recv_if);
struct neigh_node *find_router(struct bat_priv *bat_priv, struct neigh_node *find_router(struct bat_priv *bat_priv,
struct orig_node *orig_node, struct batman_if *recv_if); struct orig_node *orig_node,
void update_bonding_candidates(struct orig_node *orig_node); struct hard_iface *recv_if);
void bonding_candidate_del(struct orig_node *orig_node,
struct neigh_node *neigh_node);
#endif /* _NET_BATMAN_ADV_ROUTING_H_ */ #endif /* _NET_BATMAN_ADV_ROUTING_H_ */
This diff is collapsed.
...@@ -23,17 +23,17 @@ ...@@ -23,17 +23,17 @@
#define _NET_BATMAN_ADV_SEND_H_ #define _NET_BATMAN_ADV_SEND_H_
int send_skb_packet(struct sk_buff *skb, int send_skb_packet(struct sk_buff *skb,
struct batman_if *batman_if, struct hard_iface *hard_iface,
uint8_t *dst_addr); uint8_t *dst_addr);
void schedule_own_packet(struct batman_if *batman_if); void schedule_own_packet(struct hard_iface *hard_iface);
void schedule_forward_packet(struct orig_node *orig_node, void schedule_forward_packet(struct orig_node *orig_node,
struct ethhdr *ethhdr, struct ethhdr *ethhdr,
struct batman_packet *batman_packet, struct batman_packet *batman_packet,
uint8_t directlink, int hna_buff_len, uint8_t directlink, int hna_buff_len,
struct batman_if *if_outgoing); struct hard_iface *if_outgoing);
int add_bcast_packet_to_list(struct bat_priv *bat_priv, struct sk_buff *skb); int add_bcast_packet_to_list(struct bat_priv *bat_priv, struct sk_buff *skb);
void send_outstanding_bat_packet(struct work_struct *work); void send_outstanding_bat_packet(struct work_struct *work);
void purge_outstanding_packets(struct bat_priv *bat_priv, void purge_outstanding_packets(struct bat_priv *bat_priv,
struct batman_if *batman_if); struct hard_iface *hard_iface);
#endif /* _NET_BATMAN_ADV_SEND_H_ */ #endif /* _NET_BATMAN_ADV_SEND_H_ */
...@@ -29,14 +29,12 @@ ...@@ -29,14 +29,12 @@
#include "hash.h" #include "hash.h"
#include "gateway_common.h" #include "gateway_common.h"
#include "gateway_client.h" #include "gateway_client.h"
#include "send.h"
#include "bat_sysfs.h" #include "bat_sysfs.h"
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/ethtool.h> #include <linux/ethtool.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <linux/if_vlan.h> #include <linux/if_vlan.h>
#include "unicast.h" #include "unicast.h"
#include "routing.h"
static int bat_get_settings(struct net_device *dev, struct ethtool_cmd *cmd); static int bat_get_settings(struct net_device *dev, struct ethtool_cmd *cmd);
...@@ -78,20 +76,18 @@ int my_skb_head_push(struct sk_buff *skb, unsigned int len) ...@@ -78,20 +76,18 @@ int my_skb_head_push(struct sk_buff *skb, unsigned int len)
return 0; return 0;
} }
static void softif_neigh_free_ref(struct kref *refcount) static void softif_neigh_free_rcu(struct rcu_head *rcu)
{ {
struct softif_neigh *softif_neigh; struct softif_neigh *softif_neigh;
softif_neigh = container_of(refcount, struct softif_neigh, refcount); softif_neigh = container_of(rcu, struct softif_neigh, rcu);
kfree(softif_neigh); kfree(softif_neigh);
} }
static void softif_neigh_free_rcu(struct rcu_head *rcu) static void softif_neigh_free_ref(struct softif_neigh *softif_neigh)
{ {
struct softif_neigh *softif_neigh; if (atomic_dec_and_test(&softif_neigh->refcount))
call_rcu(&softif_neigh->rcu, softif_neigh_free_rcu);
softif_neigh = container_of(rcu, struct softif_neigh, rcu);
kref_put(&softif_neigh->refcount, softif_neigh_free_ref);
} }
void softif_neigh_purge(struct bat_priv *bat_priv) void softif_neigh_purge(struct bat_priv *bat_priv)
...@@ -118,11 +114,10 @@ void softif_neigh_purge(struct bat_priv *bat_priv) ...@@ -118,11 +114,10 @@ void softif_neigh_purge(struct bat_priv *bat_priv)
softif_neigh->addr, softif_neigh->vid); softif_neigh->addr, softif_neigh->vid);
softif_neigh_tmp = bat_priv->softif_neigh; softif_neigh_tmp = bat_priv->softif_neigh;
bat_priv->softif_neigh = NULL; bat_priv->softif_neigh = NULL;
kref_put(&softif_neigh_tmp->refcount, softif_neigh_free_ref(softif_neigh_tmp);
softif_neigh_free_ref);
} }
call_rcu(&softif_neigh->rcu, softif_neigh_free_rcu); softif_neigh_free_ref(softif_neigh);
} }
spin_unlock_bh(&bat_priv->softif_neigh_lock); spin_unlock_bh(&bat_priv->softif_neigh_lock);
...@@ -137,14 +132,17 @@ static struct softif_neigh *softif_neigh_get(struct bat_priv *bat_priv, ...@@ -137,14 +132,17 @@ static struct softif_neigh *softif_neigh_get(struct bat_priv *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) {
if (memcmp(softif_neigh->addr, addr, ETH_ALEN) != 0) if (!compare_eth(softif_neigh->addr, addr))
continue; continue;
if (softif_neigh->vid != vid) if (softif_neigh->vid != vid)
continue; continue;
if (!atomic_inc_not_zero(&softif_neigh->refcount))
continue;
softif_neigh->last_seen = jiffies; softif_neigh->last_seen = jiffies;
goto found; goto out;
} }
softif_neigh = kzalloc(sizeof(struct softif_neigh), GFP_ATOMIC); softif_neigh = kzalloc(sizeof(struct softif_neigh), GFP_ATOMIC);
...@@ -154,15 +152,14 @@ static struct softif_neigh *softif_neigh_get(struct bat_priv *bat_priv, ...@@ -154,15 +152,14 @@ static struct softif_neigh *softif_neigh_get(struct bat_priv *bat_priv,
memcpy(softif_neigh->addr, addr, ETH_ALEN); memcpy(softif_neigh->addr, addr, ETH_ALEN);
softif_neigh->vid = vid; softif_neigh->vid = vid;
softif_neigh->last_seen = jiffies; softif_neigh->last_seen = jiffies;
kref_init(&softif_neigh->refcount); /* initialize with 2 - caller decrements counter by one */
atomic_set(&softif_neigh->refcount, 2);
INIT_HLIST_NODE(&softif_neigh->list); INIT_HLIST_NODE(&softif_neigh->list);
spin_lock_bh(&bat_priv->softif_neigh_lock); spin_lock_bh(&bat_priv->softif_neigh_lock);
hlist_add_head_rcu(&softif_neigh->list, &bat_priv->softif_neigh_list); hlist_add_head_rcu(&softif_neigh->list, &bat_priv->softif_neigh_list);
spin_unlock_bh(&bat_priv->softif_neigh_lock); spin_unlock_bh(&bat_priv->softif_neigh_lock);
found:
kref_get(&softif_neigh->refcount);
out: out:
rcu_read_unlock(); rcu_read_unlock();
return softif_neigh; return softif_neigh;
...@@ -174,8 +171,6 @@ int softif_neigh_seq_print_text(struct seq_file *seq, void *offset) ...@@ -174,8 +171,6 @@ 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;
size_t buf_size, pos;
char *buff;
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 - "
...@@ -185,33 +180,15 @@ int softif_neigh_seq_print_text(struct seq_file *seq, void *offset) ...@@ -185,33 +180,15 @@ 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);
buf_size = 1;
/* Estimate length for: " xx:xx:xx:xx:xx:xx\n" */
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)
buf_size += 30; seq_printf(seq, "%s %pM (vid: %d)\n",
rcu_read_unlock();
buff = kmalloc(buf_size, GFP_ATOMIC);
if (!buff)
return -ENOMEM;
buff[0] = '\0';
pos = 0;
rcu_read_lock();
hlist_for_each_entry_rcu(softif_neigh, node,
&bat_priv->softif_neigh_list, list) {
pos += snprintf(buff + pos, 31, "%s %pM (vid: %d)\n",
bat_priv->softif_neigh == softif_neigh bat_priv->softif_neigh == softif_neigh
? "=>" : " ", softif_neigh->addr, ? "=>" : " ", softif_neigh->addr,
softif_neigh->vid); softif_neigh->vid);
}
rcu_read_unlock(); rcu_read_unlock();
seq_printf(seq, "%s", buff);
kfree(buff);
return 0; return 0;
} }
...@@ -266,7 +243,7 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, ...@@ -266,7 +243,7 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev,
softif_neigh->addr, softif_neigh->vid); softif_neigh->addr, softif_neigh->vid);
softif_neigh_tmp = bat_priv->softif_neigh; softif_neigh_tmp = bat_priv->softif_neigh;
bat_priv->softif_neigh = softif_neigh; bat_priv->softif_neigh = softif_neigh;
kref_put(&softif_neigh_tmp->refcount, softif_neigh_free_ref); softif_neigh_free_ref(softif_neigh_tmp);
/* we need to hold the additional reference */ /* we need to hold the additional reference */
goto err; goto err;
} }
...@@ -284,7 +261,7 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, ...@@ -284,7 +261,7 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev,
} }
out: out:
kref_put(&softif_neigh->refcount, softif_neigh_free_ref); softif_neigh_free_ref(softif_neigh);
err: err:
kfree_skb(skb); kfree_skb(skb);
return; return;
...@@ -437,7 +414,7 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface) ...@@ -437,7 +414,7 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
} }
void interface_rx(struct net_device *soft_iface, void interface_rx(struct net_device *soft_iface,
struct sk_buff *skb, struct batman_if *recv_if, struct sk_buff *skb, struct hard_iface *recv_if,
int hdr_size) int hdr_size)
{ {
struct bat_priv *bat_priv = netdev_priv(soft_iface); struct bat_priv *bat_priv = netdev_priv(soft_iface);
...@@ -485,7 +462,7 @@ void interface_rx(struct net_device *soft_iface, ...@@ -485,7 +462,7 @@ void interface_rx(struct net_device *soft_iface,
memcpy(unicast_packet->dest, memcpy(unicast_packet->dest,
bat_priv->softif_neigh->addr, ETH_ALEN); bat_priv->softif_neigh->addr, ETH_ALEN);
ret = route_unicast_packet(skb, recv_if, hdr_size); ret = route_unicast_packet(skb, recv_if);
if (ret == NET_RX_DROP) if (ret == NET_RX_DROP)
goto dropped; goto dropped;
...@@ -645,6 +622,19 @@ void softif_destroy(struct net_device *soft_iface) ...@@ -645,6 +622,19 @@ void softif_destroy(struct net_device *soft_iface)
unregister_netdevice(soft_iface); unregister_netdevice(soft_iface);
} }
int softif_is_valid(struct net_device *net_dev)
{
#ifdef HAVE_NET_DEVICE_OPS
if (net_dev->netdev_ops->ndo_start_xmit == interface_tx)
return 1;
#else
if (net_dev->hard_start_xmit == interface_tx)
return 1;
#endif
return 0;
}
/* ethtool */ /* ethtool */
static int bat_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) static int bat_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{ {
......
...@@ -27,9 +27,10 @@ int softif_neigh_seq_print_text(struct seq_file *seq, void *offset); ...@@ -27,9 +27,10 @@ int softif_neigh_seq_print_text(struct seq_file *seq, void *offset);
void softif_neigh_purge(struct bat_priv *bat_priv); void softif_neigh_purge(struct bat_priv *bat_priv);
int interface_tx(struct sk_buff *skb, struct net_device *soft_iface); int interface_tx(struct sk_buff *skb, struct net_device *soft_iface);
void interface_rx(struct net_device *soft_iface, void interface_rx(struct net_device *soft_iface,
struct sk_buff *skb, struct batman_if *recv_if, struct sk_buff *skb, struct hard_iface *recv_if,
int hdr_size); int hdr_size);
struct net_device *softif_create(char *name); struct net_device *softif_create(char *name);
void softif_destroy(struct net_device *soft_iface); void softif_destroy(struct net_device *soft_iface);
int softif_is_valid(struct net_device *net_dev);
#endif /* _NET_BATMAN_ADV_SOFT_INTERFACE_H_ */ #endif /* _NET_BATMAN_ADV_SOFT_INTERFACE_H_ */
This diff is collapsed.
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,7 @@
sizeof(struct bcast_packet)))) sizeof(struct bcast_packet))))
struct batman_if { struct hard_iface {
struct list_head list; struct list_head list;
int16_t if_num; int16_t if_num;
char if_status; char if_status;
...@@ -43,7 +43,7 @@ struct batman_if { ...@@ -43,7 +43,7 @@ struct batman_if {
unsigned char *packet_buff; unsigned char *packet_buff;
int packet_len; int packet_len;
struct kobject *hardif_obj; struct kobject *hardif_obj;
struct kref refcount; atomic_t refcount;
struct packet_type batman_adv_ptype; struct packet_type batman_adv_ptype;
struct net_device *soft_iface; struct net_device *soft_iface;
struct rcu_head rcu; struct rcu_head rcu;
...@@ -70,8 +70,6 @@ struct orig_node { ...@@ -70,8 +70,6 @@ struct orig_node {
struct neigh_node *router; struct neigh_node *router;
unsigned long *bcast_own; unsigned long *bcast_own;
uint8_t *bcast_own_sum; uint8_t *bcast_own_sum;
uint8_t tq_own;
int tq_asym_penalty;
unsigned long last_valid; unsigned long last_valid;
unsigned long bcast_seqno_reset; unsigned long bcast_seqno_reset;
unsigned long batman_seqno_reset; unsigned long batman_seqno_reset;
...@@ -83,20 +81,28 @@ struct orig_node { ...@@ -83,20 +81,28 @@ struct orig_node {
uint8_t last_ttl; uint8_t last_ttl;
unsigned long bcast_bits[NUM_WORDS]; unsigned long bcast_bits[NUM_WORDS];
uint32_t last_bcast_seqno; uint32_t last_bcast_seqno;
struct list_head neigh_list; struct hlist_head neigh_list;
struct list_head frag_list; struct list_head frag_list;
spinlock_t neigh_list_lock; /* protects neighbor list */
atomic_t refcount;
struct rcu_head rcu;
struct hlist_node hash_entry;
struct bat_priv *bat_priv;
unsigned long last_frag_packet; unsigned long last_frag_packet;
struct { spinlock_t ogm_cnt_lock; /* protects: bcast_own, bcast_own_sum,
uint8_t candidates; * neigh_node->real_bits,
struct neigh_node *selected; * neigh_node->real_packet_count */
} bond; spinlock_t bcast_seqno_lock; /* protects bcast_bits,
* last_bcast_seqno */
atomic_t bond_candidates;
struct list_head bond_list;
}; };
struct gw_node { struct gw_node {
struct hlist_node list; struct hlist_node list;
struct orig_node *orig_node; struct orig_node *orig_node;
unsigned long deleted; unsigned long deleted;
struct kref refcount; atomic_t refcount;
struct rcu_head rcu; struct rcu_head rcu;
}; };
...@@ -105,18 +111,20 @@ struct gw_node { ...@@ -105,18 +111,20 @@ struct gw_node {
* @last_valid: when last packet via this neighbor was received * @last_valid: when last packet via this neighbor was received
*/ */
struct neigh_node { struct neigh_node {
struct list_head list; struct hlist_node list;
uint8_t addr[ETH_ALEN]; uint8_t addr[ETH_ALEN];
uint8_t real_packet_count; uint8_t real_packet_count;
uint8_t tq_recv[TQ_GLOBAL_WINDOW_SIZE]; uint8_t tq_recv[TQ_GLOBAL_WINDOW_SIZE];
uint8_t tq_index; uint8_t tq_index;
uint8_t tq_avg; uint8_t tq_avg;
uint8_t last_ttl; uint8_t last_ttl;
struct neigh_node *next_bond_candidate; struct list_head bonding_list;
unsigned long last_valid; unsigned long last_valid;
unsigned long real_bits[NUM_WORDS]; unsigned long real_bits[NUM_WORDS];
atomic_t refcount;
struct rcu_head rcu;
struct orig_node *orig_node; struct orig_node *orig_node;
struct batman_if *if_incoming; struct hard_iface *if_incoming;
}; };
...@@ -140,7 +148,7 @@ struct bat_priv { ...@@ -140,7 +148,7 @@ struct bat_priv {
struct hlist_head softif_neigh_list; struct hlist_head softif_neigh_list;
struct softif_neigh *softif_neigh; struct softif_neigh *softif_neigh;
struct debug_log *debug_log; struct debug_log *debug_log;
struct batman_if *primary_if; struct hard_iface *primary_if;
struct kobject *mesh_obj; struct kobject *mesh_obj;
struct dentry *debug_dir; struct dentry *debug_dir;
struct hlist_head forw_bat_list; struct hlist_head forw_bat_list;
...@@ -151,12 +159,11 @@ struct bat_priv { ...@@ -151,12 +159,11 @@ struct bat_priv {
struct hashtable_t *hna_local_hash; struct hashtable_t *hna_local_hash;
struct hashtable_t *hna_global_hash; struct hashtable_t *hna_global_hash;
struct hashtable_t *vis_hash; struct hashtable_t *vis_hash;
spinlock_t orig_hash_lock; /* protects orig_hash */
spinlock_t forw_bat_list_lock; /* protects forw_bat_list */ spinlock_t forw_bat_list_lock; /* protects forw_bat_list */
spinlock_t forw_bcast_list_lock; /* protects */ spinlock_t forw_bcast_list_lock; /* protects */
spinlock_t hna_lhash_lock; /* protects hna_local_hash */ spinlock_t hna_lhash_lock; /* protects hna_local_hash */
spinlock_t hna_ghash_lock; /* protects hna_global_hash */ spinlock_t hna_ghash_lock; /* protects hna_global_hash */
spinlock_t gw_list_lock; /* protects gw_list */ spinlock_t gw_list_lock; /* protects gw_list and curr_gw */
spinlock_t vis_hash_lock; /* protects vis_hash */ spinlock_t vis_hash_lock; /* protects vis_hash */
spinlock_t vis_list_lock; /* protects vis_info::recv_list */ spinlock_t vis_list_lock; /* protects vis_info::recv_list */
spinlock_t softif_neigh_lock; /* protects soft-interface neigh list */ spinlock_t softif_neigh_lock; /* protects soft-interface neigh list */
...@@ -165,7 +172,7 @@ struct bat_priv { ...@@ -165,7 +172,7 @@ struct bat_priv {
struct delayed_work hna_work; struct delayed_work hna_work;
struct delayed_work orig_work; struct delayed_work orig_work;
struct delayed_work vis_work; struct delayed_work vis_work;
struct gw_node *curr_gw; struct gw_node __rcu *curr_gw; /* rcu protected pointer */
struct vis_info *my_vis_info; struct vis_info *my_vis_info;
}; };
...@@ -188,11 +195,13 @@ struct hna_local_entry { ...@@ -188,11 +195,13 @@ struct hna_local_entry {
uint8_t addr[ETH_ALEN]; uint8_t addr[ETH_ALEN];
unsigned long last_seen; unsigned long last_seen;
char never_purge; char never_purge;
struct hlist_node hash_entry;
}; };
struct hna_global_entry { struct hna_global_entry {
uint8_t addr[ETH_ALEN]; uint8_t addr[ETH_ALEN];
struct orig_node *orig_node; struct orig_node *orig_node;
struct hlist_node hash_entry;
}; };
/** /**
...@@ -208,7 +217,7 @@ struct forw_packet { ...@@ -208,7 +217,7 @@ struct forw_packet {
uint32_t direct_link_flags; uint32_t direct_link_flags;
uint8_t num_packets; uint8_t num_packets;
struct delayed_work delayed_work; struct delayed_work delayed_work;
struct batman_if *if_incoming; struct hard_iface *if_incoming;
}; };
/* While scanning for vis-entries of a particular vis-originator /* While scanning for vis-entries of a particular vis-originator
...@@ -242,6 +251,7 @@ struct vis_info { ...@@ -242,6 +251,7 @@ struct vis_info {
* from. we should not reply to them. */ * from. we should not reply to them. */
struct list_head send_list; struct list_head send_list;
struct kref refcount; struct kref refcount;
struct hlist_node hash_entry;
struct bat_priv *bat_priv; struct bat_priv *bat_priv;
/* this packet might be part of the vis send queue. */ /* this packet might be part of the vis send queue. */
struct sk_buff *skb_packet; struct sk_buff *skb_packet;
...@@ -264,7 +274,7 @@ struct softif_neigh { ...@@ -264,7 +274,7 @@ struct softif_neigh {
uint8_t addr[ETH_ALEN]; uint8_t addr[ETH_ALEN];
unsigned long last_seen; unsigned long last_seen;
short vid; short vid;
struct kref refcount; atomic_t refcount;
struct rcu_head rcu; struct rcu_head rcu;
}; };
......
...@@ -183,15 +183,10 @@ int frag_reassemble_skb(struct sk_buff *skb, struct bat_priv *bat_priv, ...@@ -183,15 +183,10 @@ int frag_reassemble_skb(struct sk_buff *skb, struct bat_priv *bat_priv,
(struct unicast_frag_packet *)skb->data; (struct unicast_frag_packet *)skb->data;
*new_skb = NULL; *new_skb = NULL;
spin_lock_bh(&bat_priv->orig_hash_lock);
orig_node = ((struct orig_node *)
hash_find(bat_priv->orig_hash, compare_orig, choose_orig,
unicast_packet->orig));
if (!orig_node) { orig_node = orig_hash_find(bat_priv, unicast_packet->orig);
pr_debug("couldn't find originator in orig_hash\n"); if (!orig_node)
goto out; goto out;
}
orig_node->last_frag_packet = jiffies; orig_node->last_frag_packet = jiffies;
...@@ -215,14 +210,15 @@ int frag_reassemble_skb(struct sk_buff *skb, struct bat_priv *bat_priv, ...@@ -215,14 +210,15 @@ int frag_reassemble_skb(struct sk_buff *skb, struct bat_priv *bat_priv,
/* if not, merge failed */ /* if not, merge failed */
if (*new_skb) if (*new_skb)
ret = NET_RX_SUCCESS; ret = NET_RX_SUCCESS;
out:
spin_unlock_bh(&bat_priv->orig_hash_lock);
out:
if (orig_node)
orig_node_free_ref(orig_node);
return ret; return ret;
} }
int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv, int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv,
struct batman_if *batman_if, uint8_t dstaddr[]) struct hard_iface *hard_iface, uint8_t dstaddr[])
{ {
struct unicast_packet tmp_uc, *unicast_packet; struct unicast_packet tmp_uc, *unicast_packet;
struct sk_buff *frag_skb; struct sk_buff *frag_skb;
...@@ -267,12 +263,12 @@ int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv, ...@@ -267,12 +263,12 @@ int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv,
frag1->flags = UNI_FRAG_HEAD | large_tail; frag1->flags = UNI_FRAG_HEAD | large_tail;
frag2->flags = large_tail; frag2->flags = large_tail;
seqno = atomic_add_return(2, &batman_if->frag_seqno); seqno = atomic_add_return(2, &hard_iface->frag_seqno);
frag1->seqno = htons(seqno - 1); frag1->seqno = htons(seqno - 1);
frag2->seqno = htons(seqno); frag2->seqno = htons(seqno);
send_skb_packet(skb, batman_if, dstaddr); send_skb_packet(skb, hard_iface, dstaddr);
send_skb_packet(frag_skb, batman_if, dstaddr); send_skb_packet(frag_skb, hard_iface, dstaddr);
return NET_RX_SUCCESS; return NET_RX_SUCCESS;
drop_frag: drop_frag:
...@@ -286,40 +282,37 @@ int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv) ...@@ -286,40 +282,37 @@ int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv)
{ {
struct ethhdr *ethhdr = (struct ethhdr *)skb->data; struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
struct unicast_packet *unicast_packet; struct unicast_packet *unicast_packet;
struct orig_node *orig_node = NULL; struct orig_node *orig_node;
struct batman_if *batman_if; struct neigh_node *neigh_node;
struct neigh_node *router;
int data_len = skb->len; int data_len = skb->len;
uint8_t dstaddr[6]; int ret = 1;
spin_lock_bh(&bat_priv->orig_hash_lock);
/* 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(bat_priv);
if (orig_node)
goto find_router;
}
/* check for hna host */ /* check for hna host - increases orig_node refcount */
if (!orig_node) orig_node = transtable_search(bat_priv, ethhdr->h_dest);
orig_node = transtable_search(bat_priv, ethhdr->h_dest);
router = find_router(bat_priv, orig_node, NULL);
if (!router)
goto unlock;
/* don't lock while sending the packets ... we therefore
* copy the required data before sending */
batman_if = router->if_incoming; find_router:
memcpy(dstaddr, router->addr, ETH_ALEN); /**
* find_router():
* - if orig_node is NULL it returns NULL
* - increases neigh_nodes refcount if found.
*/
neigh_node = find_router(bat_priv, orig_node, NULL);
spin_unlock_bh(&bat_priv->orig_hash_lock); if (!neigh_node)
goto out;
if (batman_if->if_status != IF_ACTIVE) if (neigh_node->if_incoming->if_status != IF_ACTIVE)
goto dropped; goto out;
if (my_skb_head_push(skb, sizeof(struct unicast_packet)) < 0) if (my_skb_head_push(skb, sizeof(struct unicast_packet)) < 0)
goto dropped; goto out;
unicast_packet = (struct unicast_packet *)skb->data; unicast_packet = (struct unicast_packet *)skb->data;
...@@ -333,18 +326,24 @@ int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv) ...@@ -333,18 +326,24 @@ int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv)
if (atomic_read(&bat_priv->fragmentation) && if (atomic_read(&bat_priv->fragmentation) &&
data_len + sizeof(struct unicast_packet) > data_len + sizeof(struct unicast_packet) >
batman_if->net_dev->mtu) { neigh_node->if_incoming->net_dev->mtu) {
/* send frag skb decreases ttl */ /* send frag skb decreases ttl */
unicast_packet->ttl++; unicast_packet->ttl++;
return frag_send_skb(skb, bat_priv, batman_if, ret = frag_send_skb(skb, bat_priv,
dstaddr); neigh_node->if_incoming, neigh_node->addr);
goto out;
} }
send_skb_packet(skb, batman_if, dstaddr);
return 0;
unlock: send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
spin_unlock_bh(&bat_priv->orig_hash_lock); ret = 0;
dropped: goto out;
kfree_skb(skb);
return 1; out:
if (neigh_node)
neigh_node_free_ref(neigh_node);
if (orig_node)
orig_node_free_ref(orig_node);
if (ret == 1)
kfree_skb(skb);
return ret;
} }
...@@ -32,7 +32,7 @@ int frag_reassemble_skb(struct sk_buff *skb, struct bat_priv *bat_priv, ...@@ -32,7 +32,7 @@ int frag_reassemble_skb(struct sk_buff *skb, struct bat_priv *bat_priv,
void frag_list_free(struct list_head *head); void frag_list_free(struct list_head *head);
int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv); int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv);
int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv, int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv,
struct batman_if *batman_if, uint8_t dstaddr[]); struct hard_iface *hard_iface, uint8_t dstaddr[]);
static inline int frag_can_reassemble(struct sk_buff *skb, int mtu) static inline int frag_can_reassemble(struct sk_buff *skb, int mtu)
{ {
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment