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

Merge tag 'batman-adv-for-davem' of git://git.open-mesh.org/linux-merge

Antonio Quartulli says:

====================
Included changes:
- remove useless skb size check in batadv_interface_rx
- basic netns support introduced by Andrew Lunn:
    - prevent virtual interface from changing netns by setting
      NETIF_F_NETNS_LOCAL
    - create virtual interface within the netns of the first
      hard-interface
- introduce detection of complex bridge loops and report event
  to the user (via udev) when the Bridge Loop Avoidance mechanism
  can't prevent them
- minor reference counting bugfixes for the hard_iface object that
  couldn't make it via the net tree
- use kref_get() instead of kref_get_unless_zero() to make reference
  counting bug more visible
- use batadv_compare_eth() all over the code when possible instead of
  plain memcmp()
- minor code cleanup and style adjustments
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 953abb38 676970e5
...@@ -681,18 +681,12 @@ static void batadv_iv_ogm_aggregate_new(const unsigned char *packet_buff, ...@@ -681,18 +681,12 @@ static void batadv_iv_ogm_aggregate_new(const unsigned char *packet_buff,
unsigned char *skb_buff; unsigned char *skb_buff;
unsigned int skb_size; unsigned int skb_size;
if (!kref_get_unless_zero(&if_incoming->refcount))
return;
if (!kref_get_unless_zero(&if_outgoing->refcount))
goto out_free_incoming;
/* own packet should always be scheduled */ /* own packet should always be scheduled */
if (!own_packet) { if (!own_packet) {
if (!batadv_atomic_dec_not_zero(&bat_priv->batman_queue_left)) { if (!batadv_atomic_dec_not_zero(&bat_priv->batman_queue_left)) {
batadv_dbg(BATADV_DBG_BATMAN, bat_priv, batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"batman packet queue full\n"); "batman packet queue full\n");
goto out_free_outgoing; return;
} }
} }
...@@ -718,6 +712,8 @@ static void batadv_iv_ogm_aggregate_new(const unsigned char *packet_buff, ...@@ -718,6 +712,8 @@ static void batadv_iv_ogm_aggregate_new(const unsigned char *packet_buff,
forw_packet_aggr->packet_len = packet_len; forw_packet_aggr->packet_len = packet_len;
memcpy(skb_buff, packet_buff, packet_len); memcpy(skb_buff, packet_buff, packet_len);
kref_get(&if_incoming->refcount);
kref_get(&if_outgoing->refcount);
forw_packet_aggr->own = own_packet; forw_packet_aggr->own = own_packet;
forw_packet_aggr->if_incoming = if_incoming; forw_packet_aggr->if_incoming = if_incoming;
forw_packet_aggr->if_outgoing = if_outgoing; forw_packet_aggr->if_outgoing = if_outgoing;
...@@ -747,10 +743,6 @@ static void batadv_iv_ogm_aggregate_new(const unsigned char *packet_buff, ...@@ -747,10 +743,6 @@ static void batadv_iv_ogm_aggregate_new(const unsigned char *packet_buff,
out_nomem: out_nomem:
if (!own_packet) if (!own_packet)
atomic_inc(&bat_priv->batman_queue_left); atomic_inc(&bat_priv->batman_queue_left);
out_free_outgoing:
batadv_hardif_put(if_outgoing);
out_free_incoming:
batadv_hardif_put(if_incoming);
} }
/* aggregate a new packet into the existing ogm packet */ /* aggregate a new packet into the existing ogm packet */
...@@ -987,9 +979,15 @@ static void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface) ...@@ -987,9 +979,15 @@ static void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface)
list_for_each_entry_rcu(tmp_hard_iface, &batadv_hardif_list, list) { list_for_each_entry_rcu(tmp_hard_iface, &batadv_hardif_list, list) {
if (tmp_hard_iface->soft_iface != hard_iface->soft_iface) if (tmp_hard_iface->soft_iface != hard_iface->soft_iface)
continue; continue;
if (!kref_get_unless_zero(&tmp_hard_iface->refcount))
continue;
batadv_iv_ogm_queue_add(bat_priv, *ogm_buff, batadv_iv_ogm_queue_add(bat_priv, *ogm_buff,
*ogm_buff_len, hard_iface, *ogm_buff_len, hard_iface,
tmp_hard_iface, 1, send_time); tmp_hard_iface, 1, send_time);
batadv_hardif_put(tmp_hard_iface);
} }
rcu_read_unlock(); rcu_read_unlock();
...@@ -1170,9 +1168,9 @@ batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv, ...@@ -1170,9 +1168,9 @@ batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv,
* @if_incoming: interface where the packet was received * @if_incoming: interface where the packet was received
* @if_outgoing: interface for which the retransmission should be considered * @if_outgoing: interface for which the retransmission should be considered
* *
* Return: 1 if the link can be considered bidirectional, 0 otherwise * Return: true if the link can be considered bidirectional, false otherwise
*/ */
static int batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node, static bool batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node,
struct batadv_orig_node *orig_neigh_node, struct batadv_orig_node *orig_neigh_node,
struct batadv_ogm_packet *batadv_ogm_packet, struct batadv_ogm_packet *batadv_ogm_packet,
struct batadv_hard_iface *if_incoming, struct batadv_hard_iface *if_incoming,
...@@ -1184,9 +1182,10 @@ static int batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node, ...@@ -1184,9 +1182,10 @@ static int batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node,
u8 total_count; u8 total_count;
u8 orig_eq_count, neigh_rq_count, neigh_rq_inv, tq_own; u8 orig_eq_count, neigh_rq_count, neigh_rq_inv, tq_own;
unsigned int neigh_rq_inv_cube, neigh_rq_max_cube; unsigned int neigh_rq_inv_cube, neigh_rq_max_cube;
int tq_asym_penalty, inv_asym_penalty, if_num, ret = 0; int tq_asym_penalty, inv_asym_penalty, if_num;
unsigned int combined_tq; unsigned int combined_tq;
int tq_iface_penalty; int tq_iface_penalty;
bool ret = false;
/* find corresponding one hop neighbor */ /* find corresponding one hop neighbor */
rcu_read_lock(); rcu_read_lock();
...@@ -1298,7 +1297,7 @@ static int batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node, ...@@ -1298,7 +1297,7 @@ static int batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node,
* consider it bidirectional * consider it bidirectional
*/ */
if (batadv_ogm_packet->tq >= BATADV_TQ_TOTAL_BIDRECT_LIMIT) if (batadv_ogm_packet->tq >= BATADV_TQ_TOTAL_BIDRECT_LIMIT)
ret = 1; ret = true;
out: out:
if (neigh_node) if (neigh_node)
...@@ -1327,9 +1326,9 @@ batadv_iv_ogm_update_seqnos(const struct ethhdr *ethhdr, ...@@ -1327,9 +1326,9 @@ batadv_iv_ogm_update_seqnos(const struct ethhdr *ethhdr,
struct batadv_orig_ifinfo *orig_ifinfo = NULL; struct batadv_orig_ifinfo *orig_ifinfo = NULL;
struct batadv_neigh_node *neigh_node; struct batadv_neigh_node *neigh_node;
struct batadv_neigh_ifinfo *neigh_ifinfo; struct batadv_neigh_ifinfo *neigh_ifinfo;
int is_dup; bool is_dup;
s32 seq_diff; s32 seq_diff;
int need_update = 0; bool need_update = false;
int set_mark; int set_mark;
enum batadv_dup_status ret = BATADV_NO_DUP; enum batadv_dup_status ret = BATADV_NO_DUP;
u32 seqno = ntohl(batadv_ogm_packet->seqno); u32 seqno = ntohl(batadv_ogm_packet->seqno);
...@@ -1439,7 +1438,7 @@ batadv_iv_ogm_process_per_outif(const struct sk_buff *skb, int ogm_offset, ...@@ -1439,7 +1438,7 @@ batadv_iv_ogm_process_per_outif(const struct sk_buff *skb, int ogm_offset,
struct sk_buff *skb_priv; struct sk_buff *skb_priv;
struct ethhdr *ethhdr; struct ethhdr *ethhdr;
u8 *prev_sender; u8 *prev_sender;
int is_bidirect; bool is_bidirect;
/* create a private copy of the skb, as some functions change tq value /* create a private copy of the skb, as some functions change tq value
* and/or flags. * and/or flags.
...@@ -1767,8 +1766,13 @@ static void batadv_iv_ogm_process(const struct sk_buff *skb, int ogm_offset, ...@@ -1767,8 +1766,13 @@ static void batadv_iv_ogm_process(const struct sk_buff *skb, int ogm_offset,
if (hard_iface->soft_iface != bat_priv->soft_iface) if (hard_iface->soft_iface != bat_priv->soft_iface)
continue; continue;
if (!kref_get_unless_zero(&hard_iface->refcount))
continue;
batadv_iv_ogm_process_per_outif(skb, ogm_offset, orig_node, batadv_iv_ogm_process_per_outif(skb, ogm_offset, orig_node,
if_incoming, hard_iface); if_incoming, hard_iface);
batadv_hardif_put(hard_iface);
} }
rcu_read_unlock(); rcu_read_unlock();
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <linux/if_ether.h> #include <linux/if_ether.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/kref.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/random.h> #include <linux/random.h>
...@@ -176,6 +177,9 @@ static void batadv_v_ogm_send(struct work_struct *work) ...@@ -176,6 +177,9 @@ static void batadv_v_ogm_send(struct work_struct *work)
if (hard_iface->soft_iface != bat_priv->soft_iface) if (hard_iface->soft_iface != bat_priv->soft_iface)
continue; continue;
if (!kref_get_unless_zero(&hard_iface->refcount))
continue;
batadv_dbg(BATADV_DBG_BATMAN, bat_priv, batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Sending own OGM2 packet (originator %pM, seqno %u, throughput %u, TTL %d) on interface %s [%pM]\n", "Sending own OGM2 packet (originator %pM, seqno %u, throughput %u, TTL %d) on interface %s [%pM]\n",
ogm_packet->orig, ntohl(ogm_packet->seqno), ogm_packet->orig, ntohl(ogm_packet->seqno),
...@@ -185,10 +189,13 @@ static void batadv_v_ogm_send(struct work_struct *work) ...@@ -185,10 +189,13 @@ static void batadv_v_ogm_send(struct work_struct *work)
/* this skb gets consumed by batadv_v_ogm_send_to_if() */ /* this skb gets consumed by batadv_v_ogm_send_to_if() */
skb_tmp = skb_clone(skb, GFP_ATOMIC); skb_tmp = skb_clone(skb, GFP_ATOMIC);
if (!skb_tmp) if (!skb_tmp) {
batadv_hardif_put(hard_iface);
break; break;
}
batadv_v_ogm_send_to_if(skb_tmp, hard_iface); batadv_v_ogm_send_to_if(skb_tmp, hard_iface);
batadv_hardif_put(hard_iface);
} }
rcu_read_unlock(); rcu_read_unlock();
...@@ -704,9 +711,14 @@ static void batadv_v_ogm_process(const struct sk_buff *skb, int ogm_offset, ...@@ -704,9 +711,14 @@ static void batadv_v_ogm_process(const struct sk_buff *skb, int ogm_offset,
if (hard_iface->soft_iface != bat_priv->soft_iface) if (hard_iface->soft_iface != bat_priv->soft_iface)
continue; continue;
if (!kref_get_unless_zero(&hard_iface->refcount))
continue;
batadv_v_ogm_process_per_outif(bat_priv, ethhdr, ogm_packet, batadv_v_ogm_process_per_outif(bat_priv, ethhdr, ogm_packet,
orig_node, neigh_node, orig_node, neigh_node,
if_incoming, hard_iface); if_incoming, hard_iface);
batadv_hardif_put(hard_iface);
} }
rcu_read_unlock(); rcu_read_unlock();
out: out:
......
...@@ -38,11 +38,11 @@ static void batadv_bitmap_shift_left(unsigned long *seq_bits, s32 n) ...@@ -38,11 +38,11 @@ static void batadv_bitmap_shift_left(unsigned long *seq_bits, s32 n)
* the last sequence number * the last sequence number
* @set_mark: whether this packet should be marked in seq_bits * @set_mark: whether this packet should be marked in seq_bits
* *
* Return: 1 if the window was moved (either new or very old), * Return: true if the window was moved (either new or very old),
* 0 if the window was not moved/shifted. * false if the window was not moved/shifted.
*/ */
int batadv_bit_get_packet(void *priv, unsigned long *seq_bits, s32 seq_num_diff, bool batadv_bit_get_packet(void *priv, unsigned long *seq_bits,
int set_mark) s32 seq_num_diff, int set_mark)
{ {
struct batadv_priv *bat_priv = priv; struct batadv_priv *bat_priv = priv;
...@@ -52,7 +52,7 @@ int batadv_bit_get_packet(void *priv, unsigned long *seq_bits, s32 seq_num_diff, ...@@ -52,7 +52,7 @@ int batadv_bit_get_packet(void *priv, unsigned long *seq_bits, s32 seq_num_diff,
if (seq_num_diff <= 0 && seq_num_diff > -BATADV_TQ_LOCAL_WINDOW_SIZE) { if (seq_num_diff <= 0 && seq_num_diff > -BATADV_TQ_LOCAL_WINDOW_SIZE) {
if (set_mark) if (set_mark)
batadv_set_bit(seq_bits, -seq_num_diff); batadv_set_bit(seq_bits, -seq_num_diff);
return 0; return false;
} }
/* sequence number is slightly newer, so we shift the window and /* sequence number is slightly newer, so we shift the window and
...@@ -63,7 +63,7 @@ int batadv_bit_get_packet(void *priv, unsigned long *seq_bits, s32 seq_num_diff, ...@@ -63,7 +63,7 @@ int batadv_bit_get_packet(void *priv, unsigned long *seq_bits, s32 seq_num_diff,
if (set_mark) if (set_mark)
batadv_set_bit(seq_bits, 0); batadv_set_bit(seq_bits, 0);
return 1; return true;
} }
/* sequence number is much newer, probably missed a lot of packets */ /* sequence number is much newer, probably missed a lot of packets */
...@@ -75,7 +75,7 @@ int batadv_bit_get_packet(void *priv, unsigned long *seq_bits, s32 seq_num_diff, ...@@ -75,7 +75,7 @@ int batadv_bit_get_packet(void *priv, unsigned long *seq_bits, s32 seq_num_diff,
bitmap_zero(seq_bits, BATADV_TQ_LOCAL_WINDOW_SIZE); bitmap_zero(seq_bits, BATADV_TQ_LOCAL_WINDOW_SIZE);
if (set_mark) if (set_mark)
batadv_set_bit(seq_bits, 0); batadv_set_bit(seq_bits, 0);
return 1; return true;
} }
/* received a much older packet. The other host either restarted /* received a much older packet. The other host either restarted
...@@ -94,5 +94,5 @@ int batadv_bit_get_packet(void *priv, unsigned long *seq_bits, s32 seq_num_diff, ...@@ -94,5 +94,5 @@ int batadv_bit_get_packet(void *priv, unsigned long *seq_bits, s32 seq_num_diff,
if (set_mark) if (set_mark)
batadv_set_bit(seq_bits, 0); batadv_set_bit(seq_bits, 0);
return 1; return true;
} }
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/compiler.h> #include <linux/compiler.h>
#include <linux/stddef.h>
#include <linux/types.h> #include <linux/types.h>
/** /**
...@@ -31,17 +32,17 @@ ...@@ -31,17 +32,17 @@
* @last_seqno: latest sequence number in seq_bits * @last_seqno: latest sequence number in seq_bits
* @curr_seqno: sequence number to test for * @curr_seqno: sequence number to test for
* *
* Return: 1 if the corresponding bit in the given seq_bits indicates true * Return: true if the corresponding bit in the given seq_bits indicates true
* and curr_seqno is within range of last_seqno. Otherwise returns 0. * and curr_seqno is within range of last_seqno. Otherwise returns false.
*/ */
static inline int batadv_test_bit(const unsigned long *seq_bits, static inline bool batadv_test_bit(const unsigned long *seq_bits,
u32 last_seqno, u32 curr_seqno) u32 last_seqno, u32 curr_seqno)
{ {
s32 diff; s32 diff;
diff = last_seqno - curr_seqno; diff = last_seqno - curr_seqno;
if (diff < 0 || diff >= BATADV_TQ_LOCAL_WINDOW_SIZE) if (diff < 0 || diff >= BATADV_TQ_LOCAL_WINDOW_SIZE)
return 0; return false;
return test_bit(diff, seq_bits) != 0; return test_bit(diff, seq_bits) != 0;
} }
...@@ -55,7 +56,7 @@ static inline void batadv_set_bit(unsigned long *seq_bits, s32 n) ...@@ -55,7 +56,7 @@ static inline void batadv_set_bit(unsigned long *seq_bits, s32 n)
set_bit(n, seq_bits); /* turn the position on */ set_bit(n, seq_bits); /* turn the position on */
} }
int batadv_bit_get_packet(void *priv, unsigned long *seq_bits, s32 seq_num_diff, bool batadv_bit_get_packet(void *priv, unsigned long *seq_bits,
int set_mark); s32 seq_num_diff, int set_mark);
#endif /* _NET_BATMAN_ADV_BITARRAY_H_ */ #endif /* _NET_BATMAN_ADV_BITARRAY_H_ */
...@@ -50,6 +50,7 @@ ...@@ -50,6 +50,7 @@
#include "hash.h" #include "hash.h"
#include "originator.h" #include "originator.h"
#include "packet.h" #include "packet.h"
#include "sysfs.h"
#include "translation-table.h" #include "translation-table.h"
static const u8 batadv_announce_mac[4] = {0x43, 0x05, 0x43, 0x05}; static const u8 batadv_announce_mac[4] = {0x43, 0x05, 0x43, 0x05};
...@@ -100,9 +101,9 @@ static inline u32 batadv_choose_backbone_gw(const void *data, u32 size) ...@@ -100,9 +101,9 @@ static inline u32 batadv_choose_backbone_gw(const void *data, u32 size)
* @node: list node of the first entry to compare * @node: list node of the first entry to compare
* @data2: pointer to the second backbone gateway * @data2: pointer to the second backbone gateway
* *
* Return: 1 if the backbones have the same data, 0 otherwise * Return: true if the backbones have the same data, false otherwise
*/ */
static int batadv_compare_backbone_gw(const struct hlist_node *node, static bool batadv_compare_backbone_gw(const struct hlist_node *node,
const void *data2) const void *data2)
{ {
const void *data1 = container_of(node, struct batadv_bla_backbone_gw, const void *data1 = container_of(node, struct batadv_bla_backbone_gw,
...@@ -111,12 +112,12 @@ static int batadv_compare_backbone_gw(const struct hlist_node *node, ...@@ -111,12 +112,12 @@ static int batadv_compare_backbone_gw(const struct hlist_node *node,
const struct batadv_bla_backbone_gw *gw2 = data2; const struct batadv_bla_backbone_gw *gw2 = data2;
if (!batadv_compare_eth(gw1->orig, gw2->orig)) if (!batadv_compare_eth(gw1->orig, gw2->orig))
return 0; return false;
if (gw1->vid != gw2->vid) if (gw1->vid != gw2->vid)
return 0; return false;
return 1; return true;
} }
/** /**
...@@ -124,9 +125,9 @@ static int batadv_compare_backbone_gw(const struct hlist_node *node, ...@@ -124,9 +125,9 @@ static int batadv_compare_backbone_gw(const struct hlist_node *node,
* @node: list node of the first entry to compare * @node: list node of the first entry to compare
* @data2: pointer to the second claims * @data2: pointer to the second claims
* *
* Return: 1 if the claim have the same data, 0 otherwise * Return: true if the claim have the same data, 0 otherwise
*/ */
static int batadv_compare_claim(const struct hlist_node *node, static bool batadv_compare_claim(const struct hlist_node *node,
const void *data2) const void *data2)
{ {
const void *data1 = container_of(node, struct batadv_bla_claim, const void *data1 = container_of(node, struct batadv_bla_claim,
...@@ -135,12 +136,12 @@ static int batadv_compare_claim(const struct hlist_node *node, ...@@ -135,12 +136,12 @@ static int batadv_compare_claim(const struct hlist_node *node,
const struct batadv_bla_claim *cl2 = data2; const struct batadv_bla_claim *cl2 = data2;
if (!batadv_compare_eth(cl1->addr, cl2->addr)) if (!batadv_compare_eth(cl1->addr, cl2->addr))
return 0; return false;
if (cl1->vid != cl2->vid) if (cl1->vid != cl2->vid)
return 0; return false;
return 1; return true;
} }
/** /**
...@@ -407,6 +408,14 @@ static void batadv_bla_send_claim(struct batadv_priv *bat_priv, u8 *mac, ...@@ -407,6 +408,14 @@ static void batadv_bla_send_claim(struct batadv_priv *bat_priv, u8 *mac,
ethhdr->h_source, ethhdr->h_dest, ethhdr->h_source, ethhdr->h_dest,
BATADV_PRINT_VID(vid)); BATADV_PRINT_VID(vid));
break; break;
case BATADV_CLAIM_TYPE_LOOPDETECT:
ether_addr_copy(ethhdr->h_source, mac);
batadv_dbg(BATADV_DBG_BLA, bat_priv,
"bla_send_claim(): LOOPDETECT of %pM to %pM on vid %d\n",
ethhdr->h_source, ethhdr->h_dest,
BATADV_PRINT_VID(vid));
break;
} }
if (vid & BATADV_VLAN_HAS_TAG) if (vid & BATADV_VLAN_HAS_TAG)
...@@ -426,6 +435,36 @@ static void batadv_bla_send_claim(struct batadv_priv *bat_priv, u8 *mac, ...@@ -426,6 +435,36 @@ static void batadv_bla_send_claim(struct batadv_priv *bat_priv, u8 *mac,
batadv_hardif_put(primary_if); batadv_hardif_put(primary_if);
} }
/**
* batadv_bla_loopdetect_report - worker for reporting the loop
* @work: work queue item
*
* Throws an uevent, as the loopdetect check function can't do that itself
* since the kernel may sleep while throwing uevents.
*/
static void batadv_bla_loopdetect_report(struct work_struct *work)
{
struct batadv_bla_backbone_gw *backbone_gw;
struct batadv_priv *bat_priv;
char vid_str[6] = { '\0' };
backbone_gw = container_of(work, struct batadv_bla_backbone_gw,
report_work);
bat_priv = backbone_gw->bat_priv;
batadv_info(bat_priv->soft_iface,
"Possible loop on VLAN %d detected which can't be handled by BLA - please check your network setup!\n",
BATADV_PRINT_VID(backbone_gw->vid));
snprintf(vid_str, sizeof(vid_str), "%d",
BATADV_PRINT_VID(backbone_gw->vid));
vid_str[sizeof(vid_str) - 1] = 0;
batadv_throw_uevent(bat_priv, BATADV_UEV_BLA, BATADV_UEV_LOOPDETECT,
vid_str);
batadv_backbone_gw_put(backbone_gw);
}
/** /**
* batadv_bla_get_backbone_gw - finds or creates a backbone gateway * batadv_bla_get_backbone_gw - finds or creates a backbone gateway
* @bat_priv: the bat priv with all the soft interface information * @bat_priv: the bat priv with all the soft interface information
...@@ -464,6 +503,7 @@ batadv_bla_get_backbone_gw(struct batadv_priv *bat_priv, u8 *orig, ...@@ -464,6 +503,7 @@ batadv_bla_get_backbone_gw(struct batadv_priv *bat_priv, u8 *orig,
atomic_set(&entry->request_sent, 0); atomic_set(&entry->request_sent, 0);
atomic_set(&entry->wait_periods, 0); atomic_set(&entry->wait_periods, 0);
ether_addr_copy(entry->orig, orig); ether_addr_copy(entry->orig, orig);
INIT_WORK(&entry->report_work, batadv_bla_loopdetect_report);
/* one for the hash, one for returning */ /* one for the hash, one for returning */
kref_init(&entry->refcount); kref_init(&entry->refcount);
...@@ -735,22 +775,22 @@ static void batadv_bla_del_claim(struct batadv_priv *bat_priv, ...@@ -735,22 +775,22 @@ static void batadv_bla_del_claim(struct batadv_priv *bat_priv,
* @backbone_addr: originator address of the sender (Ethernet source MAC) * @backbone_addr: originator address of the sender (Ethernet source MAC)
* @vid: the VLAN ID of the frame * @vid: the VLAN ID of the frame
* *
* Return: 1 if handled * Return: true if handled
*/ */
static int batadv_handle_announce(struct batadv_priv *bat_priv, u8 *an_addr, static bool batadv_handle_announce(struct batadv_priv *bat_priv, u8 *an_addr,
u8 *backbone_addr, unsigned short vid) u8 *backbone_addr, unsigned short vid)
{ {
struct batadv_bla_backbone_gw *backbone_gw; struct batadv_bla_backbone_gw *backbone_gw;
u16 backbone_crc, crc; u16 backbone_crc, crc;
if (memcmp(an_addr, batadv_announce_mac, 4) != 0) if (memcmp(an_addr, batadv_announce_mac, 4) != 0)
return 0; return false;
backbone_gw = batadv_bla_get_backbone_gw(bat_priv, backbone_addr, vid, backbone_gw = batadv_bla_get_backbone_gw(bat_priv, backbone_addr, vid,
false); false);
if (unlikely(!backbone_gw)) if (unlikely(!backbone_gw))
return 1; return true;
/* handle as ANNOUNCE frame */ /* handle as ANNOUNCE frame */
backbone_gw->lasttime = jiffies; backbone_gw->lasttime = jiffies;
...@@ -783,7 +823,7 @@ static int batadv_handle_announce(struct batadv_priv *bat_priv, u8 *an_addr, ...@@ -783,7 +823,7 @@ static int batadv_handle_announce(struct batadv_priv *bat_priv, u8 *an_addr,
} }
batadv_backbone_gw_put(backbone_gw); batadv_backbone_gw_put(backbone_gw);
return 1; return true;
} }
/** /**
...@@ -794,29 +834,29 @@ static int batadv_handle_announce(struct batadv_priv *bat_priv, u8 *an_addr, ...@@ -794,29 +834,29 @@ static int batadv_handle_announce(struct batadv_priv *bat_priv, u8 *an_addr,
* @ethhdr: ethernet header of a packet * @ethhdr: ethernet header of a packet
* @vid: the VLAN ID of the frame * @vid: the VLAN ID of the frame
* *
* Return: 1 if handled * Return: true if handled
*/ */
static int batadv_handle_request(struct batadv_priv *bat_priv, static bool batadv_handle_request(struct batadv_priv *bat_priv,
struct batadv_hard_iface *primary_if, struct batadv_hard_iface *primary_if,
u8 *backbone_addr, struct ethhdr *ethhdr, u8 *backbone_addr, struct ethhdr *ethhdr,
unsigned short vid) unsigned short vid)
{ {
/* check for REQUEST frame */ /* check for REQUEST frame */
if (!batadv_compare_eth(backbone_addr, ethhdr->h_dest)) if (!batadv_compare_eth(backbone_addr, ethhdr->h_dest))
return 0; return false;
/* sanity check, this should not happen on a normal switch, /* sanity check, this should not happen on a normal switch,
* we ignore it in this case. * we ignore it in this case.
*/ */
if (!batadv_compare_eth(ethhdr->h_dest, primary_if->net_dev->dev_addr)) if (!batadv_compare_eth(ethhdr->h_dest, primary_if->net_dev->dev_addr))
return 1; return true;
batadv_dbg(BATADV_DBG_BLA, bat_priv, batadv_dbg(BATADV_DBG_BLA, bat_priv,
"handle_request(): REQUEST vid %d (sent by %pM)...\n", "handle_request(): REQUEST vid %d (sent by %pM)...\n",
BATADV_PRINT_VID(vid), ethhdr->h_source); BATADV_PRINT_VID(vid), ethhdr->h_source);
batadv_bla_answer_request(bat_priv, primary_if, vid); batadv_bla_answer_request(bat_priv, primary_if, vid);
return 1; return true;
} }
/** /**
...@@ -827,9 +867,9 @@ static int batadv_handle_request(struct batadv_priv *bat_priv, ...@@ -827,9 +867,9 @@ static int batadv_handle_request(struct batadv_priv *bat_priv,
* @claim_addr: Client to be unclaimed (ARP sender HW MAC) * @claim_addr: Client to be unclaimed (ARP sender HW MAC)
* @vid: the VLAN ID of the frame * @vid: the VLAN ID of the frame
* *
* Return: 1 if handled * Return: true if handled
*/ */
static int batadv_handle_unclaim(struct batadv_priv *bat_priv, static bool batadv_handle_unclaim(struct batadv_priv *bat_priv,
struct batadv_hard_iface *primary_if, struct batadv_hard_iface *primary_if,
u8 *backbone_addr, u8 *claim_addr, u8 *backbone_addr, u8 *claim_addr,
unsigned short vid) unsigned short vid)
...@@ -845,7 +885,7 @@ static int batadv_handle_unclaim(struct batadv_priv *bat_priv, ...@@ -845,7 +885,7 @@ static int batadv_handle_unclaim(struct batadv_priv *bat_priv,
backbone_gw = batadv_backbone_hash_find(bat_priv, backbone_addr, vid); backbone_gw = batadv_backbone_hash_find(bat_priv, backbone_addr, vid);
if (!backbone_gw) if (!backbone_gw)
return 1; return true;
/* this must be an UNCLAIM frame */ /* this must be an UNCLAIM frame */
batadv_dbg(BATADV_DBG_BLA, bat_priv, batadv_dbg(BATADV_DBG_BLA, bat_priv,
...@@ -854,7 +894,7 @@ static int batadv_handle_unclaim(struct batadv_priv *bat_priv, ...@@ -854,7 +894,7 @@ static int batadv_handle_unclaim(struct batadv_priv *bat_priv,
batadv_bla_del_claim(bat_priv, claim_addr, vid); batadv_bla_del_claim(bat_priv, claim_addr, vid);
batadv_backbone_gw_put(backbone_gw); batadv_backbone_gw_put(backbone_gw);
return 1; return true;
} }
/** /**
...@@ -865,9 +905,9 @@ static int batadv_handle_unclaim(struct batadv_priv *bat_priv, ...@@ -865,9 +905,9 @@ static int batadv_handle_unclaim(struct batadv_priv *bat_priv,
* @claim_addr: client mac address to be claimed (ARP sender HW MAC) * @claim_addr: client mac address to be claimed (ARP sender HW MAC)
* @vid: the VLAN ID of the frame * @vid: the VLAN ID of the frame
* *
* Return: 1 if handled * Return: true if handled
*/ */
static int batadv_handle_claim(struct batadv_priv *bat_priv, static bool batadv_handle_claim(struct batadv_priv *bat_priv,
struct batadv_hard_iface *primary_if, struct batadv_hard_iface *primary_if,
u8 *backbone_addr, u8 *claim_addr, u8 *backbone_addr, u8 *claim_addr,
unsigned short vid) unsigned short vid)
...@@ -880,7 +920,7 @@ static int batadv_handle_claim(struct batadv_priv *bat_priv, ...@@ -880,7 +920,7 @@ static int batadv_handle_claim(struct batadv_priv *bat_priv,
false); false);
if (unlikely(!backbone_gw)) if (unlikely(!backbone_gw))
return 1; return true;
/* this must be a CLAIM frame */ /* this must be a CLAIM frame */
batadv_bla_add_claim(bat_priv, claim_addr, vid, backbone_gw); batadv_bla_add_claim(bat_priv, claim_addr, vid, backbone_gw);
...@@ -891,7 +931,7 @@ static int batadv_handle_claim(struct batadv_priv *bat_priv, ...@@ -891,7 +931,7 @@ static int batadv_handle_claim(struct batadv_priv *bat_priv,
/* TODO: we could call something like tt_local_del() here. */ /* TODO: we could call something like tt_local_del() here. */
batadv_backbone_gw_put(backbone_gw); batadv_backbone_gw_put(backbone_gw);
return 1; return true;
} }
/** /**
...@@ -975,10 +1015,10 @@ static int batadv_check_claim_group(struct batadv_priv *bat_priv, ...@@ -975,10 +1015,10 @@ static int batadv_check_claim_group(struct batadv_priv *bat_priv,
* @primary_if: the primary hard interface of this batman soft interface * @primary_if: the primary hard interface of this batman soft interface
* @skb: the frame to be checked * @skb: the frame to be checked
* *
* Return: 1 if it was a claim frame, otherwise return 0 to * Return: true if it was a claim frame, otherwise return false to
* tell the callee that it can use the frame on its own. * tell the callee that it can use the frame on its own.
*/ */
static int batadv_bla_process_claim(struct batadv_priv *bat_priv, static bool batadv_bla_process_claim(struct batadv_priv *bat_priv,
struct batadv_hard_iface *primary_if, struct batadv_hard_iface *primary_if,
struct sk_buff *skb) struct sk_buff *skb)
{ {
...@@ -1011,7 +1051,7 @@ static int batadv_bla_process_claim(struct batadv_priv *bat_priv, ...@@ -1011,7 +1051,7 @@ static int batadv_bla_process_claim(struct batadv_priv *bat_priv,
vhdr = skb_header_pointer(skb, headlen, VLAN_HLEN, vhdr = skb_header_pointer(skb, headlen, VLAN_HLEN,
&vhdr_buf); &vhdr_buf);
if (!vhdr) if (!vhdr)
return 0; return false;
proto = vhdr->h_vlan_encapsulated_proto; proto = vhdr->h_vlan_encapsulated_proto;
headlen += VLAN_HLEN; headlen += VLAN_HLEN;
...@@ -1020,12 +1060,12 @@ static int batadv_bla_process_claim(struct batadv_priv *bat_priv, ...@@ -1020,12 +1060,12 @@ static int batadv_bla_process_claim(struct batadv_priv *bat_priv,
} }
if (proto != htons(ETH_P_ARP)) if (proto != htons(ETH_P_ARP))
return 0; /* not a claim frame */ return false; /* not a claim frame */
/* this must be a ARP frame. check if it is a claim. */ /* this must be a ARP frame. check if it is a claim. */
if (unlikely(!pskb_may_pull(skb, headlen + arp_hdr_len(skb->dev)))) if (unlikely(!pskb_may_pull(skb, headlen + arp_hdr_len(skb->dev))))
return 0; return false;
/* pskb_may_pull() may have modified the pointers, get ethhdr again */ /* pskb_may_pull() may have modified the pointers, get ethhdr again */
ethhdr = eth_hdr(skb); ethhdr = eth_hdr(skb);
...@@ -1035,13 +1075,13 @@ static int batadv_bla_process_claim(struct batadv_priv *bat_priv, ...@@ -1035,13 +1075,13 @@ static int batadv_bla_process_claim(struct batadv_priv *bat_priv,
* IP information * IP information
*/ */
if (arphdr->ar_hrd != htons(ARPHRD_ETHER)) if (arphdr->ar_hrd != htons(ARPHRD_ETHER))
return 0; return false;
if (arphdr->ar_pro != htons(ETH_P_IP)) if (arphdr->ar_pro != htons(ETH_P_IP))
return 0; return false;
if (arphdr->ar_hln != ETH_ALEN) if (arphdr->ar_hln != ETH_ALEN)
return 0; return false;
if (arphdr->ar_pln != 4) if (arphdr->ar_pln != 4)
return 0; return false;
hw_src = (u8 *)arphdr + sizeof(struct arphdr); hw_src = (u8 *)arphdr + sizeof(struct arphdr);
hw_dst = hw_src + ETH_ALEN + 4; hw_dst = hw_src + ETH_ALEN + 4;
...@@ -1051,14 +1091,18 @@ static int batadv_bla_process_claim(struct batadv_priv *bat_priv, ...@@ -1051,14 +1091,18 @@ static int batadv_bla_process_claim(struct batadv_priv *bat_priv,
/* check if it is a claim frame in general */ /* check if it is a claim frame in general */
if (memcmp(bla_dst->magic, bla_dst_own->magic, if (memcmp(bla_dst->magic, bla_dst_own->magic,
sizeof(bla_dst->magic)) != 0) sizeof(bla_dst->magic)) != 0)
return 0; return false;
/* check if there is a claim frame encapsulated deeper in (QinQ) and /* check if there is a claim frame encapsulated deeper in (QinQ) and
* drop that, as this is not supported by BLA but should also not be * drop that, as this is not supported by BLA but should also not be
* sent via the mesh. * sent via the mesh.
*/ */
if (vlan_depth > 1) if (vlan_depth > 1)
return 1; return true;
/* Let the loopdetect frames on the mesh in any case. */
if (bla_dst->type == BATADV_CLAIM_TYPE_LOOPDETECT)
return 0;
/* check if it is a claim frame. */ /* check if it is a claim frame. */
ret = batadv_check_claim_group(bat_priv, primary_if, hw_src, hw_dst, ret = batadv_check_claim_group(bat_priv, primary_if, hw_src, hw_dst,
...@@ -1070,7 +1114,7 @@ static int batadv_bla_process_claim(struct batadv_priv *bat_priv, ...@@ -1070,7 +1114,7 @@ static int batadv_bla_process_claim(struct batadv_priv *bat_priv,
hw_dst); hw_dst);
if (ret < 2) if (ret < 2)
return ret; return !!ret;
/* become a backbone gw ourselves on this vlan if not happened yet */ /* become a backbone gw ourselves on this vlan if not happened yet */
batadv_bla_update_own_backbone_gw(bat_priv, primary_if, vid); batadv_bla_update_own_backbone_gw(bat_priv, primary_if, vid);
...@@ -1080,30 +1124,30 @@ static int batadv_bla_process_claim(struct batadv_priv *bat_priv, ...@@ -1080,30 +1124,30 @@ static int batadv_bla_process_claim(struct batadv_priv *bat_priv,
case BATADV_CLAIM_TYPE_CLAIM: case BATADV_CLAIM_TYPE_CLAIM:
if (batadv_handle_claim(bat_priv, primary_if, hw_src, if (batadv_handle_claim(bat_priv, primary_if, hw_src,
ethhdr->h_source, vid)) ethhdr->h_source, vid))
return 1; return true;
break; break;
case BATADV_CLAIM_TYPE_UNCLAIM: case BATADV_CLAIM_TYPE_UNCLAIM:
if (batadv_handle_unclaim(bat_priv, primary_if, if (batadv_handle_unclaim(bat_priv, primary_if,
ethhdr->h_source, hw_src, vid)) ethhdr->h_source, hw_src, vid))
return 1; return true;
break; break;
case BATADV_CLAIM_TYPE_ANNOUNCE: case BATADV_CLAIM_TYPE_ANNOUNCE:
if (batadv_handle_announce(bat_priv, hw_src, ethhdr->h_source, if (batadv_handle_announce(bat_priv, hw_src, ethhdr->h_source,
vid)) vid))
return 1; return true;
break; break;
case BATADV_CLAIM_TYPE_REQUEST: case BATADV_CLAIM_TYPE_REQUEST:
if (batadv_handle_request(bat_priv, primary_if, hw_src, ethhdr, if (batadv_handle_request(bat_priv, primary_if, hw_src, ethhdr,
vid)) vid))
return 1; return true;
break; break;
} }
batadv_dbg(BATADV_DBG_BLA, bat_priv, batadv_dbg(BATADV_DBG_BLA, bat_priv,
"bla_process_claim(): ERROR - this looks like a claim frame, but is useless. eth src %pM on vid %d ...(hw_src %pM, hw_dst %pM)\n", "bla_process_claim(): ERROR - this looks like a claim frame, but is useless. eth src %pM on vid %d ...(hw_src %pM, hw_dst %pM)\n",
ethhdr->h_source, BATADV_PRINT_VID(vid), hw_src, hw_dst); ethhdr->h_source, BATADV_PRINT_VID(vid), hw_src, hw_dst);
return 1; return true;
} }
/** /**
...@@ -1264,6 +1308,26 @@ void batadv_bla_update_orig_address(struct batadv_priv *bat_priv, ...@@ -1264,6 +1308,26 @@ void batadv_bla_update_orig_address(struct batadv_priv *bat_priv,
} }
} }
/**
* batadv_bla_send_loopdetect - send a loopdetect frame
* @bat_priv: the bat priv with all the soft interface information
* @backbone_gw: the backbone gateway for which a loop should be detected
*
* To detect loops that the bridge loop avoidance can't handle, send a loop
* detection packet on the backbone. Unlike other BLA frames, this frame will
* be allowed on the mesh by other nodes. If it is received on the mesh, this
* indicates that there is a loop.
*/
static void
batadv_bla_send_loopdetect(struct batadv_priv *bat_priv,
struct batadv_bla_backbone_gw *backbone_gw)
{
batadv_dbg(BATADV_DBG_BLA, bat_priv, "Send loopdetect frame for vid %d\n",
backbone_gw->vid);
batadv_bla_send_claim(bat_priv, bat_priv->bla.loopdetect_addr,
backbone_gw->vid, BATADV_CLAIM_TYPE_LOOPDETECT);
}
/** /**
* batadv_bla_status_update - purge bla interfaces if necessary * batadv_bla_status_update - purge bla interfaces if necessary
* @net_dev: the soft interface net device * @net_dev: the soft interface net device
...@@ -1301,6 +1365,7 @@ static void batadv_bla_periodic_work(struct work_struct *work) ...@@ -1301,6 +1365,7 @@ static void batadv_bla_periodic_work(struct work_struct *work)
struct batadv_bla_backbone_gw *backbone_gw; struct batadv_bla_backbone_gw *backbone_gw;
struct batadv_hashtable *hash; struct batadv_hashtable *hash;
struct batadv_hard_iface *primary_if; struct batadv_hard_iface *primary_if;
bool send_loopdetect = false;
int i; int i;
delayed_work = to_delayed_work(work); delayed_work = to_delayed_work(work);
...@@ -1316,6 +1381,22 @@ static void batadv_bla_periodic_work(struct work_struct *work) ...@@ -1316,6 +1381,22 @@ static void batadv_bla_periodic_work(struct work_struct *work)
if (!atomic_read(&bat_priv->bridge_loop_avoidance)) if (!atomic_read(&bat_priv->bridge_loop_avoidance))
goto out; goto out;
if (atomic_dec_and_test(&bat_priv->bla.loopdetect_next)) {
/* set a new random mac address for the next bridge loop
* detection frames. Set the locally administered bit to avoid
* collisions with users mac addresses.
*/
random_ether_addr(bat_priv->bla.loopdetect_addr);
bat_priv->bla.loopdetect_addr[0] = 0xba;
bat_priv->bla.loopdetect_addr[1] = 0xbe;
bat_priv->bla.loopdetect_lasttime = jiffies;
atomic_set(&bat_priv->bla.loopdetect_next,
BATADV_BLA_LOOPDETECT_PERIODS);
/* mark for sending loop detect on all VLANs */
send_loopdetect = true;
}
hash = bat_priv->bla.backbone_hash; hash = bat_priv->bla.backbone_hash;
if (!hash) if (!hash)
goto out; goto out;
...@@ -1332,6 +1413,9 @@ static void batadv_bla_periodic_work(struct work_struct *work) ...@@ -1332,6 +1413,9 @@ static void batadv_bla_periodic_work(struct work_struct *work)
backbone_gw->lasttime = jiffies; backbone_gw->lasttime = jiffies;
batadv_bla_send_announce(bat_priv, backbone_gw); batadv_bla_send_announce(bat_priv, backbone_gw);
if (send_loopdetect)
batadv_bla_send_loopdetect(bat_priv,
backbone_gw);
/* request_sent is only set after creation to avoid /* request_sent is only set after creation to avoid
* problems when we are not yet known as backbone gw * problems when we are not yet known as backbone gw
...@@ -1405,6 +1489,9 @@ int batadv_bla_init(struct batadv_priv *bat_priv) ...@@ -1405,6 +1489,9 @@ int batadv_bla_init(struct batadv_priv *bat_priv)
bat_priv->bla.bcast_duplist[i].entrytime = entrytime; bat_priv->bla.bcast_duplist[i].entrytime = entrytime;
bat_priv->bla.bcast_duplist_curr = 0; bat_priv->bla.bcast_duplist_curr = 0;
atomic_set(&bat_priv->bla.loopdetect_next,
BATADV_BLA_LOOPDETECT_PERIODS);
if (bat_priv->bla.claim_hash) if (bat_priv->bla.claim_hash)
return 0; return 0;
...@@ -1442,15 +1529,16 @@ int batadv_bla_init(struct batadv_priv *bat_priv) ...@@ -1442,15 +1529,16 @@ int batadv_bla_init(struct batadv_priv *bat_priv)
* sent by another host, drop it. We allow equal packets from * sent by another host, drop it. We allow equal packets from
* the same host however as this might be intended. * the same host however as this might be intended.
* *
* Return: 1 if a packet is in the duplicate list, 0 otherwise. * Return: true if a packet is in the duplicate list, false otherwise.
*/ */
int batadv_bla_check_bcast_duplist(struct batadv_priv *bat_priv, bool batadv_bla_check_bcast_duplist(struct batadv_priv *bat_priv,
struct sk_buff *skb) struct sk_buff *skb)
{ {
int i, curr, ret = 0; int i, curr;
__be32 crc; __be32 crc;
struct batadv_bcast_packet *bcast_packet; struct batadv_bcast_packet *bcast_packet;
struct batadv_bcast_duplist_entry *entry; struct batadv_bcast_duplist_entry *entry;
bool ret = false;
bcast_packet = (struct batadv_bcast_packet *)skb->data; bcast_packet = (struct batadv_bcast_packet *)skb->data;
...@@ -1478,9 +1566,9 @@ int batadv_bla_check_bcast_duplist(struct batadv_priv *bat_priv, ...@@ -1478,9 +1566,9 @@ int batadv_bla_check_bcast_duplist(struct batadv_priv *bat_priv,
continue; continue;
/* this entry seems to match: same crc, not too old, /* this entry seems to match: same crc, not too old,
* and from another gw. therefore return 1 to forbid it. * and from another gw. therefore return true to forbid it.
*/ */
ret = 1; ret = true;
goto out; goto out;
} }
/* not found, add a new entry (overwrite the oldest entry) /* not found, add a new entry (overwrite the oldest entry)
...@@ -1546,21 +1634,21 @@ bool batadv_bla_is_backbone_gw_orig(struct batadv_priv *bat_priv, u8 *orig, ...@@ -1546,21 +1634,21 @@ bool batadv_bla_is_backbone_gw_orig(struct batadv_priv *bat_priv, u8 *orig,
* @orig_node: the orig_node of the frame * @orig_node: the orig_node of the frame
* @hdr_size: maximum length of the frame * @hdr_size: maximum length of the frame
* *
* Return: 1 if the orig_node is also a gateway on the soft interface, otherwise * Return: true if the orig_node is also a gateway on the soft interface,
* it returns 0. * otherwise it returns false.
*/ */
int batadv_bla_is_backbone_gw(struct sk_buff *skb, bool batadv_bla_is_backbone_gw(struct sk_buff *skb,
struct batadv_orig_node *orig_node, int hdr_size) struct batadv_orig_node *orig_node, int hdr_size)
{ {
struct batadv_bla_backbone_gw *backbone_gw; struct batadv_bla_backbone_gw *backbone_gw;
unsigned short vid; unsigned short vid;
if (!atomic_read(&orig_node->bat_priv->bridge_loop_avoidance)) if (!atomic_read(&orig_node->bat_priv->bridge_loop_avoidance))
return 0; return false;
/* first, find out the vid. */ /* first, find out the vid. */
if (!pskb_may_pull(skb, hdr_size + ETH_HLEN)) if (!pskb_may_pull(skb, hdr_size + ETH_HLEN))
return 0; return false;
vid = batadv_get_vid(skb, hdr_size); vid = batadv_get_vid(skb, hdr_size);
...@@ -1568,10 +1656,10 @@ int batadv_bla_is_backbone_gw(struct sk_buff *skb, ...@@ -1568,10 +1656,10 @@ int batadv_bla_is_backbone_gw(struct sk_buff *skb,
backbone_gw = batadv_backbone_hash_find(orig_node->bat_priv, backbone_gw = batadv_backbone_hash_find(orig_node->bat_priv,
orig_node->orig, vid); orig_node->orig, vid);
if (!backbone_gw) if (!backbone_gw)
return 0; return false;
batadv_backbone_gw_put(backbone_gw); batadv_backbone_gw_put(backbone_gw);
return 1; return true;
} }
/** /**
...@@ -1601,6 +1689,55 @@ void batadv_bla_free(struct batadv_priv *bat_priv) ...@@ -1601,6 +1689,55 @@ void batadv_bla_free(struct batadv_priv *bat_priv)
batadv_hardif_put(primary_if); batadv_hardif_put(primary_if);
} }
/**
* batadv_bla_loopdetect_check - check and handle a detected loop
* @bat_priv: the bat priv with all the soft interface information
* @skb: the packet to check
* @primary_if: interface where the request came on
* @vid: the VLAN ID of the frame
*
* Checks if this packet is a loop detect frame which has been sent by us,
* throw an uevent and log the event if that is the case.
*
* Return: true if it is a loop detect frame which is to be dropped, false
* otherwise.
*/
static bool
batadv_bla_loopdetect_check(struct batadv_priv *bat_priv, struct sk_buff *skb,
struct batadv_hard_iface *primary_if,
unsigned short vid)
{
struct batadv_bla_backbone_gw *backbone_gw;
struct ethhdr *ethhdr;
ethhdr = eth_hdr(skb);
/* Only check for the MAC address and skip more checks here for
* performance reasons - this function is on the hotpath, after all.
*/
if (!batadv_compare_eth(ethhdr->h_source,
bat_priv->bla.loopdetect_addr))
return false;
/* If the packet came too late, don't forward it on the mesh
* but don't consider that as loop. It might be a coincidence.
*/
if (batadv_has_timed_out(bat_priv->bla.loopdetect_lasttime,
BATADV_BLA_LOOPDETECT_TIMEOUT))
return true;
backbone_gw = batadv_bla_get_backbone_gw(bat_priv,
primary_if->net_dev->dev_addr,
vid, true);
if (unlikely(!backbone_gw))
return true;
queue_work(batadv_event_workqueue, &backbone_gw->report_work);
/* backbone_gw is unreferenced in the report work function function */
return true;
}
/** /**
* batadv_bla_rx - check packets coming from the mesh. * batadv_bla_rx - check packets coming from the mesh.
* @bat_priv: the bat priv with all the soft interface information * @bat_priv: the bat priv with all the soft interface information
...@@ -1614,16 +1751,16 @@ void batadv_bla_free(struct batadv_priv *bat_priv) ...@@ -1614,16 +1751,16 @@ void batadv_bla_free(struct batadv_priv *bat_priv)
* *
* in these cases, the skb is further handled by this function * in these cases, the skb is further handled by this function
* *
* Return: 1 if handled, otherwise it returns 0 and the caller shall further * Return: true if handled, otherwise it returns false and the caller shall
* process the skb. * further process the skb.
*/ */
int batadv_bla_rx(struct batadv_priv *bat_priv, struct sk_buff *skb, bool batadv_bla_rx(struct batadv_priv *bat_priv, struct sk_buff *skb,
unsigned short vid, bool is_bcast) unsigned short vid, bool is_bcast)
{ {
struct ethhdr *ethhdr; struct ethhdr *ethhdr;
struct batadv_bla_claim search_claim, *claim = NULL; struct batadv_bla_claim search_claim, *claim = NULL;
struct batadv_hard_iface *primary_if; struct batadv_hard_iface *primary_if;
int ret; bool ret;
ethhdr = eth_hdr(skb); ethhdr = eth_hdr(skb);
...@@ -1634,6 +1771,9 @@ int batadv_bla_rx(struct batadv_priv *bat_priv, struct sk_buff *skb, ...@@ -1634,6 +1771,9 @@ int batadv_bla_rx(struct batadv_priv *bat_priv, struct sk_buff *skb,
if (!atomic_read(&bat_priv->bridge_loop_avoidance)) if (!atomic_read(&bat_priv->bridge_loop_avoidance))
goto allow; goto allow;
if (batadv_bla_loopdetect_check(bat_priv, skb, primary_if, vid))
goto handled;
if (unlikely(atomic_read(&bat_priv->bla.num_requests))) if (unlikely(atomic_read(&bat_priv->bla.num_requests)))
/* don't allow broadcasts while requests are in flight */ /* don't allow broadcasts while requests are in flight */
if (is_multicast_ether_addr(ethhdr->h_dest) && is_bcast) if (is_multicast_ether_addr(ethhdr->h_dest) && is_bcast)
...@@ -1682,12 +1822,12 @@ int batadv_bla_rx(struct batadv_priv *bat_priv, struct sk_buff *skb, ...@@ -1682,12 +1822,12 @@ int batadv_bla_rx(struct batadv_priv *bat_priv, struct sk_buff *skb,
} }
allow: allow:
batadv_bla_update_own_backbone_gw(bat_priv, primary_if, vid); batadv_bla_update_own_backbone_gw(bat_priv, primary_if, vid);
ret = 0; ret = false;
goto out; goto out;
handled: handled:
kfree_skb(skb); kfree_skb(skb);
ret = 1; ret = true;
out: out:
if (primary_if) if (primary_if)
...@@ -1711,16 +1851,16 @@ int batadv_bla_rx(struct batadv_priv *bat_priv, struct sk_buff *skb, ...@@ -1711,16 +1851,16 @@ int batadv_bla_rx(struct batadv_priv *bat_priv, struct sk_buff *skb,
* *
* This call might reallocate skb data. * This call might reallocate skb data.
* *
* Return: 1 if handled, otherwise it returns 0 and the caller shall further * Return: true if handled, otherwise it returns false and the caller shall
* process the skb. * further process the skb.
*/ */
int batadv_bla_tx(struct batadv_priv *bat_priv, struct sk_buff *skb, bool batadv_bla_tx(struct batadv_priv *bat_priv, struct sk_buff *skb,
unsigned short vid) unsigned short vid)
{ {
struct ethhdr *ethhdr; struct ethhdr *ethhdr;
struct batadv_bla_claim search_claim, *claim = NULL; struct batadv_bla_claim search_claim, *claim = NULL;
struct batadv_hard_iface *primary_if; struct batadv_hard_iface *primary_if;
int ret = 0; bool ret = false;
primary_if = batadv_primary_if_get_selected(bat_priv); primary_if = batadv_primary_if_get_selected(bat_priv);
if (!primary_if) if (!primary_if)
...@@ -1774,10 +1914,10 @@ int batadv_bla_tx(struct batadv_priv *bat_priv, struct sk_buff *skb, ...@@ -1774,10 +1914,10 @@ int batadv_bla_tx(struct batadv_priv *bat_priv, struct sk_buff *skb,
} }
allow: allow:
batadv_bla_update_own_backbone_gw(bat_priv, primary_if, vid); batadv_bla_update_own_backbone_gw(bat_priv, primary_if, vid);
ret = 0; ret = false;
goto out; goto out;
handled: handled:
ret = 1; ret = true;
out: out:
if (primary_if) if (primary_if)
batadv_hardif_put(primary_if); batadv_hardif_put(primary_if);
......
...@@ -27,18 +27,19 @@ struct seq_file; ...@@ -27,18 +27,19 @@ struct seq_file;
struct sk_buff; struct sk_buff;
#ifdef CONFIG_BATMAN_ADV_BLA #ifdef CONFIG_BATMAN_ADV_BLA
int batadv_bla_rx(struct batadv_priv *bat_priv, struct sk_buff *skb, bool batadv_bla_rx(struct batadv_priv *bat_priv, struct sk_buff *skb,
unsigned short vid, bool is_bcast); unsigned short vid, bool is_bcast);
int batadv_bla_tx(struct batadv_priv *bat_priv, struct sk_buff *skb, bool batadv_bla_tx(struct batadv_priv *bat_priv, struct sk_buff *skb,
unsigned short vid); unsigned short vid);
int batadv_bla_is_backbone_gw(struct sk_buff *skb, bool batadv_bla_is_backbone_gw(struct sk_buff *skb,
struct batadv_orig_node *orig_node, int hdr_size); struct batadv_orig_node *orig_node,
int hdr_size);
int batadv_bla_claim_table_seq_print_text(struct seq_file *seq, void *offset); int batadv_bla_claim_table_seq_print_text(struct seq_file *seq, void *offset);
int batadv_bla_backbone_table_seq_print_text(struct seq_file *seq, int batadv_bla_backbone_table_seq_print_text(struct seq_file *seq,
void *offset); void *offset);
bool batadv_bla_is_backbone_gw_orig(struct batadv_priv *bat_priv, u8 *orig, bool batadv_bla_is_backbone_gw_orig(struct batadv_priv *bat_priv, u8 *orig,
unsigned short vid); unsigned short vid);
int batadv_bla_check_bcast_duplist(struct batadv_priv *bat_priv, bool batadv_bla_check_bcast_duplist(struct batadv_priv *bat_priv,
struct sk_buff *skb); struct sk_buff *skb);
void batadv_bla_update_orig_address(struct batadv_priv *bat_priv, void batadv_bla_update_orig_address(struct batadv_priv *bat_priv,
struct batadv_hard_iface *primary_if, struct batadv_hard_iface *primary_if,
...@@ -50,24 +51,24 @@ void batadv_bla_free(struct batadv_priv *bat_priv); ...@@ -50,24 +51,24 @@ void batadv_bla_free(struct batadv_priv *bat_priv);
#define BATADV_BLA_CRC_INIT 0 #define BATADV_BLA_CRC_INIT 0
#else /* ifdef CONFIG_BATMAN_ADV_BLA */ #else /* ifdef CONFIG_BATMAN_ADV_BLA */
static inline int batadv_bla_rx(struct batadv_priv *bat_priv, static inline bool batadv_bla_rx(struct batadv_priv *bat_priv,
struct sk_buff *skb, unsigned short vid, struct sk_buff *skb, unsigned short vid,
bool is_bcast) bool is_bcast)
{ {
return 0; return false;
} }
static inline int batadv_bla_tx(struct batadv_priv *bat_priv, static inline bool batadv_bla_tx(struct batadv_priv *bat_priv,
struct sk_buff *skb, unsigned short vid) struct sk_buff *skb, unsigned short vid)
{ {
return 0; return false;
} }
static inline int batadv_bla_is_backbone_gw(struct sk_buff *skb, static inline bool batadv_bla_is_backbone_gw(struct sk_buff *skb,
struct batadv_orig_node *orig_node, struct batadv_orig_node *orig_node,
int hdr_size) int hdr_size)
{ {
return 0; return false;
} }
static inline int batadv_bla_claim_table_seq_print_text(struct seq_file *seq, static inline int batadv_bla_claim_table_seq_print_text(struct seq_file *seq,
...@@ -88,11 +89,11 @@ static inline bool batadv_bla_is_backbone_gw_orig(struct batadv_priv *bat_priv, ...@@ -88,11 +89,11 @@ static inline bool batadv_bla_is_backbone_gw_orig(struct batadv_priv *bat_priv,
return false; return false;
} }
static inline int static inline bool
batadv_bla_check_bcast_duplist(struct batadv_priv *bat_priv, batadv_bla_check_bcast_duplist(struct batadv_priv *bat_priv,
struct sk_buff *skb) struct sk_buff *skb)
{ {
return 0; return false;
} }
static inline void static inline void
......
...@@ -134,7 +134,7 @@ static int batadv_log_release(struct inode *inode, struct file *file) ...@@ -134,7 +134,7 @@ static int batadv_log_release(struct inode *inode, struct file *file)
return 0; return 0;
} }
static int batadv_log_empty(struct batadv_priv_debug_log *debug_log) static bool batadv_log_empty(struct batadv_priv_debug_log *debug_log)
{ {
return !(debug_log->log_start - debug_log->log_end); return !(debug_log->log_start - debug_log->log_end);
} }
......
...@@ -165,14 +165,14 @@ static void batadv_dat_purge(struct work_struct *work) ...@@ -165,14 +165,14 @@ static void batadv_dat_purge(struct work_struct *work)
* @node: node in the local table * @node: node in the local table
* @data2: second object to compare the node to * @data2: second object to compare the node to
* *
* Return: 1 if the two entries are the same, 0 otherwise. * Return: true if the two entries are the same, false otherwise.
*/ */
static int batadv_compare_dat(const struct hlist_node *node, const void *data2) static bool batadv_compare_dat(const struct hlist_node *node, const void *data2)
{ {
const void *data1 = container_of(node, struct batadv_dat_entry, const void *data1 = container_of(node, struct batadv_dat_entry,
hash_entry); hash_entry);
return memcmp(data1, data2, sizeof(__be32)) == 0 ? 1 : 0; return memcmp(data1, data2, sizeof(__be32)) == 0;
} }
/** /**
......
...@@ -135,8 +135,8 @@ static void batadv_gw_select(struct batadv_priv *bat_priv, ...@@ -135,8 +135,8 @@ static void batadv_gw_select(struct batadv_priv *bat_priv,
spin_lock_bh(&bat_priv->gw.list_lock); spin_lock_bh(&bat_priv->gw.list_lock);
if (new_gw_node && !kref_get_unless_zero(&new_gw_node->refcount)) if (new_gw_node)
new_gw_node = NULL; kref_get(&new_gw_node->refcount);
curr_gw_node = rcu_dereference_protected(bat_priv->gw.curr_gw, 1); curr_gw_node = rcu_dereference_protected(bat_priv->gw.curr_gw, 1);
rcu_assign_pointer(bat_priv->gw.curr_gw, new_gw_node); rcu_assign_pointer(bat_priv->gw.curr_gw, new_gw_node);
...@@ -440,15 +440,11 @@ static void batadv_gw_node_add(struct batadv_priv *bat_priv, ...@@ -440,15 +440,11 @@ static void batadv_gw_node_add(struct batadv_priv *bat_priv,
if (gateway->bandwidth_down == 0) if (gateway->bandwidth_down == 0)
return; return;
if (!kref_get_unless_zero(&orig_node->refcount))
return;
gw_node = kzalloc(sizeof(*gw_node), GFP_ATOMIC); gw_node = kzalloc(sizeof(*gw_node), GFP_ATOMIC);
if (!gw_node) { if (!gw_node)
batadv_orig_node_put(orig_node);
return; return;
}
kref_get(&orig_node->refcount);
INIT_HLIST_NODE(&gw_node->list); INIT_HLIST_NODE(&gw_node->list);
gw_node->orig_node = orig_node; gw_node->orig_node = orig_node;
gw_node->bandwidth_down = ntohl(gateway->bandwidth_down); gw_node->bandwidth_down = ntohl(gateway->bandwidth_down);
......
...@@ -36,7 +36,6 @@ ...@@ -36,7 +36,6 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <net/net_namespace.h>
#include "bridge_loop_avoidance.h" #include "bridge_loop_avoidance.h"
#include "debugfs.h" #include "debugfs.h"
...@@ -121,6 +120,7 @@ static bool batadv_mutual_parents(const struct net_device *dev1, ...@@ -121,6 +120,7 @@ static bool batadv_mutual_parents(const struct net_device *dev1,
static bool batadv_is_on_batman_iface(const struct net_device *net_dev) static bool batadv_is_on_batman_iface(const struct net_device *net_dev)
{ {
struct net_device *parent_dev; struct net_device *parent_dev;
struct net *net = dev_net(net_dev);
bool ret; bool ret;
/* check if this is a batman-adv mesh interface */ /* check if this is a batman-adv mesh interface */
...@@ -133,7 +133,7 @@ static bool batadv_is_on_batman_iface(const struct net_device *net_dev) ...@@ -133,7 +133,7 @@ static bool batadv_is_on_batman_iface(const struct net_device *net_dev)
return false; return false;
/* recurse over the parent device */ /* recurse over the parent device */
parent_dev = __dev_get_by_index(&init_net, dev_get_iflink(net_dev)); parent_dev = __dev_get_by_index(net, dev_get_iflink(net_dev));
/* if we got a NULL parent_dev there is something broken.. */ /* if we got a NULL parent_dev there is something broken.. */
if (WARN(!parent_dev, "Cannot find parent device")) if (WARN(!parent_dev, "Cannot find parent device"))
return false; return false;
...@@ -146,22 +146,22 @@ static bool batadv_is_on_batman_iface(const struct net_device *net_dev) ...@@ -146,22 +146,22 @@ static bool batadv_is_on_batman_iface(const struct net_device *net_dev)
return ret; return ret;
} }
static int batadv_is_valid_iface(const struct net_device *net_dev) static bool batadv_is_valid_iface(const struct net_device *net_dev)
{ {
if (net_dev->flags & IFF_LOOPBACK) if (net_dev->flags & IFF_LOOPBACK)
return 0; return false;
if (net_dev->type != ARPHRD_ETHER) if (net_dev->type != ARPHRD_ETHER)
return 0; return false;
if (net_dev->addr_len != ETH_ALEN) if (net_dev->addr_len != ETH_ALEN)
return 0; return false;
/* no batman over batman */ /* no batman over batman */
if (batadv_is_on_batman_iface(net_dev)) if (batadv_is_on_batman_iface(net_dev))
return 0; return false;
return 1; return true;
} }
/** /**
...@@ -236,8 +236,8 @@ static void batadv_primary_if_select(struct batadv_priv *bat_priv, ...@@ -236,8 +236,8 @@ static void batadv_primary_if_select(struct batadv_priv *bat_priv,
ASSERT_RTNL(); ASSERT_RTNL();
if (new_hard_iface && !kref_get_unless_zero(&new_hard_iface->refcount)) if (new_hard_iface)
new_hard_iface = NULL; kref_get(&new_hard_iface->refcount);
curr_hard_iface = rcu_dereference_protected(bat_priv->primary_if, 1); curr_hard_iface = rcu_dereference_protected(bat_priv->primary_if, 1);
rcu_assign_pointer(bat_priv->primary_if, new_hard_iface); rcu_assign_pointer(bat_priv->primary_if, new_hard_iface);
...@@ -456,7 +456,7 @@ static int batadv_master_del_slave(struct batadv_hard_iface *slave, ...@@ -456,7 +456,7 @@ static int batadv_master_del_slave(struct batadv_hard_iface *slave,
} }
int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface, int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface,
const char *iface_name) struct net *net, const char *iface_name)
{ {
struct batadv_priv *bat_priv; struct batadv_priv *bat_priv;
struct net_device *soft_iface, *master; struct net_device *soft_iface, *master;
...@@ -467,13 +467,12 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface, ...@@ -467,13 +467,12 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface,
if (hard_iface->if_status != BATADV_IF_NOT_IN_USE) if (hard_iface->if_status != BATADV_IF_NOT_IN_USE)
goto out; goto out;
if (!kref_get_unless_zero(&hard_iface->refcount)) kref_get(&hard_iface->refcount);
goto out;
soft_iface = dev_get_by_name(&init_net, iface_name); soft_iface = dev_get_by_name(net, iface_name);
if (!soft_iface) { if (!soft_iface) {
soft_iface = batadv_softif_create(iface_name); soft_iface = batadv_softif_create(net, iface_name);
if (!soft_iface) { if (!soft_iface) {
ret = -ENOMEM; ret = -ENOMEM;
...@@ -522,6 +521,7 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface, ...@@ -522,6 +521,7 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface,
goto err_upper; goto err_upper;
} }
kref_get(&hard_iface->refcount);
hard_iface->batman_adv_ptype.type = ethertype; hard_iface->batman_adv_ptype.type = ethertype;
hard_iface->batman_adv_ptype.func = batadv_batman_skb_recv; hard_iface->batman_adv_ptype.func = batadv_batman_skb_recv;
hard_iface->batman_adv_ptype.dev = hard_iface->net_dev; hard_iface->batman_adv_ptype.dev = hard_iface->net_dev;
...@@ -583,6 +583,7 @@ void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface, ...@@ -583,6 +583,7 @@ void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface,
batadv_info(hard_iface->soft_iface, "Removing interface: %s\n", batadv_info(hard_iface->soft_iface, "Removing interface: %s\n",
hard_iface->net_dev->name); hard_iface->net_dev->name);
dev_remove_pack(&hard_iface->batman_adv_ptype); dev_remove_pack(&hard_iface->batman_adv_ptype);
batadv_hardif_put(hard_iface);
bat_priv->num_ifaces--; bat_priv->num_ifaces--;
batadv_orig_hash_del_if(hard_iface, bat_priv->num_ifaces); batadv_orig_hash_del_if(hard_iface, bat_priv->num_ifaces);
...@@ -652,8 +653,7 @@ batadv_hardif_add_interface(struct net_device *net_dev) ...@@ -652,8 +653,7 @@ batadv_hardif_add_interface(struct net_device *net_dev)
ASSERT_RTNL(); ASSERT_RTNL();
ret = batadv_is_valid_iface(net_dev); if (!batadv_is_valid_iface(net_dev))
if (ret != 1)
goto out; goto out;
dev_hold(net_dev); dev_hold(net_dev);
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <linux/types.h> #include <linux/types.h>
struct net_device; struct net_device;
struct net;
enum batadv_hard_if_state { enum batadv_hard_if_state {
BATADV_IF_NOT_IN_USE, BATADV_IF_NOT_IN_USE,
...@@ -55,7 +56,7 @@ bool batadv_is_wifi_iface(int ifindex); ...@@ -55,7 +56,7 @@ bool batadv_is_wifi_iface(int ifindex);
struct batadv_hard_iface* struct batadv_hard_iface*
batadv_hardif_get_by_netdev(const struct net_device *net_dev); batadv_hardif_get_by_netdev(const struct net_device *net_dev);
int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface, int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface,
const char *iface_name); struct net *net, const char *iface_name);
void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface, void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface,
enum batadv_hard_if_cleanup autodel); enum batadv_hard_if_cleanup autodel);
void batadv_hardif_remove_interfaces(void); void batadv_hardif_remove_interfaces(void);
......
...@@ -32,9 +32,9 @@ struct lock_class_key; ...@@ -32,9 +32,9 @@ struct lock_class_key;
/* callback to a compare function. should compare 2 element datas for their /* callback to a compare function. should compare 2 element datas for their
* keys * keys
* *
* Return: 0 if same and not 0 if not same * Return: true if same and false if not same
*/ */
typedef int (*batadv_hashdata_compare_cb)(const struct hlist_node *, typedef bool (*batadv_hashdata_compare_cb)(const struct hlist_node *,
const void *); const void *);
/* the hashfunction /* the hashfunction
......
...@@ -401,11 +401,19 @@ int batadv_batman_skb_recv(struct sk_buff *skb, struct net_device *dev, ...@@ -401,11 +401,19 @@ int batadv_batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
hard_iface = container_of(ptype, struct batadv_hard_iface, hard_iface = container_of(ptype, struct batadv_hard_iface,
batman_adv_ptype); batman_adv_ptype);
/* Prevent processing a packet received on an interface which is getting
* shut down otherwise the packet may trigger de-reference errors
* further down in the receive path.
*/
if (!kref_get_unless_zero(&hard_iface->refcount))
goto err_out;
skb = skb_share_check(skb, GFP_ATOMIC); skb = skb_share_check(skb, GFP_ATOMIC);
/* skb was released by skb_share_check() */ /* skb was released by skb_share_check() */
if (!skb) if (!skb)
goto err_out; goto err_put;
/* packet should hold at least type and version */ /* packet should hold at least type and version */
if (unlikely(!pskb_may_pull(skb, 2))) if (unlikely(!pskb_may_pull(skb, 2)))
...@@ -448,6 +456,8 @@ int batadv_batman_skb_recv(struct sk_buff *skb, struct net_device *dev, ...@@ -448,6 +456,8 @@ int batadv_batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
if (ret == NET_RX_DROP) if (ret == NET_RX_DROP)
kfree_skb(skb); kfree_skb(skb);
batadv_hardif_put(hard_iface);
/* return NET_RX_SUCCESS in any case as we /* return NET_RX_SUCCESS in any case as we
* most probably dropped the packet for * most probably dropped the packet for
* routing-logical reasons. * routing-logical reasons.
...@@ -456,6 +466,8 @@ int batadv_batman_skb_recv(struct sk_buff *skb, struct net_device *dev, ...@@ -456,6 +466,8 @@ int batadv_batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
err_free: err_free:
kfree_skb(skb); kfree_skb(skb);
err_put:
batadv_hardif_put(hard_iface);
err_out: err_out:
return NET_RX_DROP; return NET_RX_DROP;
} }
...@@ -736,9 +748,7 @@ batadv_tvlv_container_get(struct batadv_priv *bat_priv, u8 type, u8 version) ...@@ -736,9 +748,7 @@ batadv_tvlv_container_get(struct batadv_priv *bat_priv, u8 type, u8 version)
if (tvlv_tmp->tvlv_hdr.version != version) if (tvlv_tmp->tvlv_hdr.version != version)
continue; continue;
if (!kref_get_unless_zero(&tvlv_tmp->refcount)) kref_get(&tvlv_tmp->refcount);
continue;
tvlv = tvlv_tmp; tvlv = tvlv_tmp;
break; break;
} }
......
...@@ -120,6 +120,8 @@ ...@@ -120,6 +120,8 @@
#define BATADV_BLA_BACKBONE_TIMEOUT (BATADV_BLA_PERIOD_LENGTH * 6) #define BATADV_BLA_BACKBONE_TIMEOUT (BATADV_BLA_PERIOD_LENGTH * 6)
#define BATADV_BLA_CLAIM_TIMEOUT (BATADV_BLA_PERIOD_LENGTH * 10) #define BATADV_BLA_CLAIM_TIMEOUT (BATADV_BLA_PERIOD_LENGTH * 10)
#define BATADV_BLA_WAIT_PERIODS 3 #define BATADV_BLA_WAIT_PERIODS 3
#define BATADV_BLA_LOOPDETECT_PERIODS 6
#define BATADV_BLA_LOOPDETECT_TIMEOUT 3000 /* 3 seconds */
#define BATADV_DUPLIST_SIZE 16 #define BATADV_DUPLIST_SIZE 16
#define BATADV_DUPLIST_TIMEOUT 500 /* 500 ms */ #define BATADV_DUPLIST_TIMEOUT 500 /* 500 ms */
...@@ -142,10 +144,12 @@ enum batadv_uev_action { ...@@ -142,10 +144,12 @@ enum batadv_uev_action {
BATADV_UEV_ADD = 0, BATADV_UEV_ADD = 0,
BATADV_UEV_DEL, BATADV_UEV_DEL,
BATADV_UEV_CHANGE, BATADV_UEV_CHANGE,
BATADV_UEV_LOOPDETECT,
}; };
enum batadv_uev_type { enum batadv_uev_type {
BATADV_UEV_GW = 0, BATADV_UEV_GW = 0,
BATADV_UEV_BLA,
}; };
#define BATADV_GW_THRESHOLD 50 #define BATADV_GW_THRESHOLD 50
...@@ -288,7 +292,7 @@ static inline void _batadv_dbg(int type __always_unused, ...@@ -288,7 +292,7 @@ static inline void _batadv_dbg(int type __always_unused,
* *
* note: can't use ether_addr_equal() as it requires aligned memory * note: can't use ether_addr_equal() as it requires aligned memory
* *
* Return: 1 if they are the same ethernet addr * Return: true if they are the same ethernet addr
*/ */
static inline bool batadv_compare_eth(const void *data1, const void *data2) static inline bool batadv_compare_eth(const void *data1, const void *data2)
{ {
......
...@@ -510,9 +510,9 @@ static u32 batadv_nc_hash_choose(const void *data, u32 size) ...@@ -510,9 +510,9 @@ static u32 batadv_nc_hash_choose(const void *data, u32 size)
* @node: node in the local table * @node: node in the local table
* @data2: second object to compare the node to * @data2: second object to compare the node to
* *
* Return: 1 if the two entry are the same, 0 otherwise * Return: true if the two entry are the same, false otherwise
*/ */
static int batadv_nc_hash_compare(const struct hlist_node *node, static bool batadv_nc_hash_compare(const struct hlist_node *node,
const void *data2) const void *data2)
{ {
const struct batadv_nc_path *nc_path1, *nc_path2; const struct batadv_nc_path *nc_path1, *nc_path2;
...@@ -521,15 +521,13 @@ static int batadv_nc_hash_compare(const struct hlist_node *node, ...@@ -521,15 +521,13 @@ static int batadv_nc_hash_compare(const struct hlist_node *node,
nc_path2 = data2; nc_path2 = data2;
/* Return 1 if the two keys are identical */ /* Return 1 if the two keys are identical */
if (memcmp(nc_path1->prev_hop, nc_path2->prev_hop, if (!batadv_compare_eth(nc_path1->prev_hop, nc_path2->prev_hop))
sizeof(nc_path1->prev_hop)) != 0) return false;
return 0;
if (memcmp(nc_path1->next_hop, nc_path2->next_hop, if (!batadv_compare_eth(nc_path1->next_hop, nc_path2->next_hop))
sizeof(nc_path1->next_hop)) != 0) return false;
return 0;
return 1; return true;
} }
/** /**
...@@ -856,8 +854,7 @@ batadv_nc_get_nc_node(struct batadv_priv *bat_priv, ...@@ -856,8 +854,7 @@ batadv_nc_get_nc_node(struct batadv_priv *bat_priv,
if (!nc_node) if (!nc_node)
return NULL; return NULL;
if (!kref_get_unless_zero(&orig_neigh_node->refcount)) kref_get(&orig_neigh_node->refcount);
goto free;
/* Initialize nc_node */ /* Initialize nc_node */
INIT_LIST_HEAD(&nc_node->list); INIT_LIST_HEAD(&nc_node->list);
...@@ -884,10 +881,6 @@ batadv_nc_get_nc_node(struct batadv_priv *bat_priv, ...@@ -884,10 +881,6 @@ batadv_nc_get_nc_node(struct batadv_priv *bat_priv,
spin_unlock_bh(lock); spin_unlock_bh(lock);
return nc_node; return nc_node;
free:
kfree(nc_node);
return NULL;
} }
/** /**
......
...@@ -54,9 +54,9 @@ static void batadv_purge_orig(struct work_struct *work); ...@@ -54,9 +54,9 @@ static void batadv_purge_orig(struct work_struct *work);
* @node: node in the local table * @node: node in the local table
* @data2: second object to compare the node to * @data2: second object to compare the node to
* *
* Return: 1 if they are the same originator * Return: true if they are the same originator
*/ */
int batadv_compare_orig(const struct hlist_node *node, const void *data2) bool batadv_compare_orig(const struct hlist_node *node, const void *data2)
{ {
const void *data1 = container_of(node, struct batadv_orig_node, const void *data1 = container_of(node, struct batadv_orig_node,
hash_entry); hash_entry);
...@@ -374,12 +374,8 @@ batadv_orig_ifinfo_new(struct batadv_orig_node *orig_node, ...@@ -374,12 +374,8 @@ batadv_orig_ifinfo_new(struct batadv_orig_node *orig_node,
if (!orig_ifinfo) if (!orig_ifinfo)
goto out; goto out;
if (if_outgoing != BATADV_IF_DEFAULT && if (if_outgoing != BATADV_IF_DEFAULT)
!kref_get_unless_zero(&if_outgoing->refcount)) { kref_get(&if_outgoing->refcount);
kfree(orig_ifinfo);
orig_ifinfo = NULL;
goto out;
}
reset_time = jiffies - 1; reset_time = jiffies - 1;
reset_time -= msecs_to_jiffies(BATADV_RESET_PROTECTION_MS); reset_time -= msecs_to_jiffies(BATADV_RESET_PROTECTION_MS);
...@@ -455,11 +451,8 @@ batadv_neigh_ifinfo_new(struct batadv_neigh_node *neigh, ...@@ -455,11 +451,8 @@ batadv_neigh_ifinfo_new(struct batadv_neigh_node *neigh,
if (!neigh_ifinfo) if (!neigh_ifinfo)
goto out; goto out;
if (if_outgoing && !kref_get_unless_zero(&if_outgoing->refcount)) { if (if_outgoing)
kfree(neigh_ifinfo); kref_get(&if_outgoing->refcount);
neigh_ifinfo = NULL;
goto out;
}
INIT_HLIST_NODE(&neigh_ifinfo->list); INIT_HLIST_NODE(&neigh_ifinfo->list);
kref_init(&neigh_ifinfo->refcount); kref_init(&neigh_ifinfo->refcount);
...@@ -532,15 +525,11 @@ batadv_hardif_neigh_create(struct batadv_hard_iface *hard_iface, ...@@ -532,15 +525,11 @@ batadv_hardif_neigh_create(struct batadv_hard_iface *hard_iface,
if (hardif_neigh) if (hardif_neigh)
goto out; goto out;
if (!kref_get_unless_zero(&hard_iface->refcount))
goto out;
hardif_neigh = kzalloc(sizeof(*hardif_neigh), GFP_ATOMIC); hardif_neigh = kzalloc(sizeof(*hardif_neigh), GFP_ATOMIC);
if (!hardif_neigh) { if (!hardif_neigh)
batadv_hardif_put(hard_iface);
goto out; goto out;
}
kref_get(&hard_iface->refcount);
INIT_HLIST_NODE(&hardif_neigh->list); INIT_HLIST_NODE(&hardif_neigh->list);
ether_addr_copy(hardif_neigh->addr, neigh_addr); ether_addr_copy(hardif_neigh->addr, neigh_addr);
hardif_neigh->if_incoming = hard_iface; hardif_neigh->if_incoming = hard_iface;
...@@ -643,16 +632,11 @@ batadv_neigh_node_new(struct batadv_orig_node *orig_node, ...@@ -643,16 +632,11 @@ batadv_neigh_node_new(struct batadv_orig_node *orig_node,
if (!neigh_node) if (!neigh_node)
goto out; goto out;
if (!kref_get_unless_zero(&hard_iface->refcount)) {
kfree(neigh_node);
neigh_node = NULL;
goto out;
}
INIT_HLIST_NODE(&neigh_node->list); INIT_HLIST_NODE(&neigh_node->list);
INIT_HLIST_HEAD(&neigh_node->ifinfo_list); INIT_HLIST_HEAD(&neigh_node->ifinfo_list);
spin_lock_init(&neigh_node->ifinfo_lock); spin_lock_init(&neigh_node->ifinfo_lock);
kref_get(&hard_iface->refcount);
ether_addr_copy(neigh_node->addr, neigh_addr); ether_addr_copy(neigh_node->addr, neigh_addr);
neigh_node->if_incoming = hard_iface; neigh_node->if_incoming = hard_iface;
neigh_node->orig_node = orig_node; neigh_node->orig_node = orig_node;
...@@ -1160,6 +1144,9 @@ static bool batadv_purge_orig_node(struct batadv_priv *bat_priv, ...@@ -1160,6 +1144,9 @@ static bool batadv_purge_orig_node(struct batadv_priv *bat_priv,
if (hard_iface->soft_iface != bat_priv->soft_iface) if (hard_iface->soft_iface != bat_priv->soft_iface)
continue; continue;
if (!kref_get_unless_zero(&hard_iface->refcount))
continue;
best_neigh_node = batadv_find_best_neighbor(bat_priv, best_neigh_node = batadv_find_best_neighbor(bat_priv,
orig_node, orig_node,
hard_iface); hard_iface);
...@@ -1167,6 +1154,8 @@ static bool batadv_purge_orig_node(struct batadv_priv *bat_priv, ...@@ -1167,6 +1154,8 @@ static bool batadv_purge_orig_node(struct batadv_priv *bat_priv,
best_neigh_node); best_neigh_node);
if (best_neigh_node) if (best_neigh_node)
batadv_neigh_node_put(best_neigh_node); batadv_neigh_node_put(best_neigh_node);
batadv_hardif_put(hard_iface);
} }
rcu_read_unlock(); rcu_read_unlock();
......
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,7 @@
struct seq_file; struct seq_file;
int batadv_compare_orig(const struct hlist_node *node, const void *data2); bool batadv_compare_orig(const struct hlist_node *node, const void *data2);
int batadv_originator_init(struct batadv_priv *bat_priv); int batadv_originator_init(struct batadv_priv *bat_priv);
void batadv_originator_free(struct batadv_priv *bat_priv); void batadv_originator_free(struct batadv_priv *bat_priv);
void batadv_purge_orig_ref(struct batadv_priv *bat_priv); void batadv_purge_orig_ref(struct batadv_priv *bat_priv);
......
...@@ -175,6 +175,7 @@ enum batadv_bla_claimframe { ...@@ -175,6 +175,7 @@ enum batadv_bla_claimframe {
BATADV_CLAIM_TYPE_UNCLAIM = 0x01, BATADV_CLAIM_TYPE_UNCLAIM = 0x01,
BATADV_CLAIM_TYPE_ANNOUNCE = 0x02, BATADV_CLAIM_TYPE_ANNOUNCE = 0x02,
BATADV_CLAIM_TYPE_REQUEST = 0x03, BATADV_CLAIM_TYPE_REQUEST = 0x03,
BATADV_CLAIM_TYPE_LOOPDETECT = 0x04,
}; };
/** /**
......
...@@ -100,10 +100,6 @@ static void _batadv_update_route(struct batadv_priv *bat_priv, ...@@ -100,10 +100,6 @@ static void _batadv_update_route(struct batadv_priv *bat_priv,
if (curr_router) if (curr_router)
batadv_neigh_node_put(curr_router); batadv_neigh_node_put(curr_router);
/* increase refcount of new best neighbor */
if (neigh_node && !kref_get_unless_zero(&neigh_node->refcount))
neigh_node = NULL;
spin_lock_bh(&orig_node->neigh_list_lock); spin_lock_bh(&orig_node->neigh_list_lock);
/* curr_router used earlier may not be the current orig_ifinfo->router /* curr_router used earlier may not be the current orig_ifinfo->router
* anymore because it was dereferenced outside of the neigh_list_lock * anymore because it was dereferenced outside of the neigh_list_lock
...@@ -114,6 +110,10 @@ static void _batadv_update_route(struct batadv_priv *bat_priv, ...@@ -114,6 +110,10 @@ static void _batadv_update_route(struct batadv_priv *bat_priv,
*/ */
curr_router = rcu_dereference_protected(orig_ifinfo->router, true); curr_router = rcu_dereference_protected(orig_ifinfo->router, true);
/* increase refcount of new best neighbor */
if (neigh_node)
kref_get(&neigh_node->refcount);
rcu_assign_pointer(orig_ifinfo->router, neigh_node); rcu_assign_pointer(orig_ifinfo->router, neigh_node);
spin_unlock_bh(&orig_node->neigh_list_lock); spin_unlock_bh(&orig_node->neigh_list_lock);
batadv_orig_ifinfo_put(orig_ifinfo); batadv_orig_ifinfo_put(orig_ifinfo);
...@@ -163,10 +163,10 @@ void batadv_update_route(struct batadv_priv *bat_priv, ...@@ -163,10 +163,10 @@ void batadv_update_route(struct batadv_priv *bat_priv,
* doesn't change otherwise. * doesn't change otherwise.
* *
* Return: * Return:
* 0 if the packet is to be accepted. * false if the packet is to be accepted.
* 1 if the packet is to be ignored. * true if the packet is to be ignored.
*/ */
int batadv_window_protected(struct batadv_priv *bat_priv, s32 seq_num_diff, bool batadv_window_protected(struct batadv_priv *bat_priv, s32 seq_num_diff,
s32 seq_old_max_diff, unsigned long *last_reset, s32 seq_old_max_diff, unsigned long *last_reset,
bool *protection_started) bool *protection_started)
{ {
...@@ -174,7 +174,7 @@ int batadv_window_protected(struct batadv_priv *bat_priv, s32 seq_num_diff, ...@@ -174,7 +174,7 @@ int batadv_window_protected(struct batadv_priv *bat_priv, s32 seq_num_diff,
seq_num_diff >= BATADV_EXPECTED_SEQNO_RANGE) { seq_num_diff >= BATADV_EXPECTED_SEQNO_RANGE) {
if (!batadv_has_timed_out(*last_reset, if (!batadv_has_timed_out(*last_reset,
BATADV_RESET_PROTECTION_MS)) BATADV_RESET_PROTECTION_MS))
return 1; return true;
*last_reset = jiffies; *last_reset = jiffies;
if (protection_started) if (protection_started)
...@@ -183,7 +183,7 @@ int batadv_window_protected(struct batadv_priv *bat_priv, s32 seq_num_diff, ...@@ -183,7 +183,7 @@ int batadv_window_protected(struct batadv_priv *bat_priv, s32 seq_num_diff,
"old packet received, start protection\n"); "old packet received, start protection\n");
} }
return 0; return false;
} }
bool batadv_check_management_packet(struct sk_buff *skb, bool batadv_check_management_packet(struct sk_buff *skb,
...@@ -718,8 +718,9 @@ batadv_reroute_unicast_packet(struct batadv_priv *bat_priv, ...@@ -718,8 +718,9 @@ batadv_reroute_unicast_packet(struct batadv_priv *bat_priv,
return ret; return ret;
} }
static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv, static bool batadv_check_unicast_ttvn(struct batadv_priv *bat_priv,
struct sk_buff *skb, int hdr_len) { struct sk_buff *skb, int hdr_len)
{
struct batadv_unicast_packet *unicast_packet; struct batadv_unicast_packet *unicast_packet;
struct batadv_hard_iface *primary_if; struct batadv_hard_iface *primary_if;
struct batadv_orig_node *orig_node; struct batadv_orig_node *orig_node;
...@@ -730,11 +731,11 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv, ...@@ -730,11 +731,11 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv,
/* check if there is enough data before accessing it */ /* check if there is enough data before accessing it */
if (!pskb_may_pull(skb, hdr_len + ETH_HLEN)) if (!pskb_may_pull(skb, hdr_len + ETH_HLEN))
return 0; return false;
/* create a copy of the skb (in case of for re-routing) to modify it. */ /* create a copy of the skb (in case of for re-routing) to modify it. */
if (skb_cow(skb, sizeof(*unicast_packet)) < 0) if (skb_cow(skb, sizeof(*unicast_packet)) < 0)
return 0; return false;
unicast_packet = (struct batadv_unicast_packet *)skb->data; unicast_packet = (struct batadv_unicast_packet *)skb->data;
vid = batadv_get_vid(skb, hdr_len); vid = batadv_get_vid(skb, hdr_len);
...@@ -758,7 +759,7 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv, ...@@ -758,7 +759,7 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv,
* table. If not, let the packet go untouched anyway because * table. If not, let the packet go untouched anyway because
* there is nothing the node can do * there is nothing the node can do
*/ */
return 1; return true;
} }
/* retrieve the TTVN known by this node for the packet destination. This /* retrieve the TTVN known by this node for the packet destination. This
...@@ -774,7 +775,7 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv, ...@@ -774,7 +775,7 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv,
* not be possible to deliver it * not be possible to deliver it
*/ */
if (!orig_node) if (!orig_node)
return 0; return false;
curr_ttvn = (u8)atomic_read(&orig_node->last_ttvn); curr_ttvn = (u8)atomic_read(&orig_node->last_ttvn);
batadv_orig_node_put(orig_node); batadv_orig_node_put(orig_node);
...@@ -785,7 +786,7 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv, ...@@ -785,7 +786,7 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv,
*/ */
is_old_ttvn = batadv_seq_before(unicast_packet->ttvn, curr_ttvn); is_old_ttvn = batadv_seq_before(unicast_packet->ttvn, curr_ttvn);
if (!is_old_ttvn) if (!is_old_ttvn)
return 1; return true;
old_ttvn = unicast_packet->ttvn; old_ttvn = unicast_packet->ttvn;
/* the packet was forged based on outdated network information. Its /* the packet was forged based on outdated network information. Its
...@@ -798,7 +799,7 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv, ...@@ -798,7 +799,7 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv,
"Rerouting unicast packet to %pM (dst=%pM): TTVN mismatch old_ttvn=%u new_ttvn=%u\n", "Rerouting unicast packet to %pM (dst=%pM): TTVN mismatch old_ttvn=%u new_ttvn=%u\n",
unicast_packet->dest, ethhdr->h_dest, unicast_packet->dest, ethhdr->h_dest,
old_ttvn, curr_ttvn); old_ttvn, curr_ttvn);
return 1; return true;
} }
/* the packet has not been re-routed: either the destination is /* the packet has not been re-routed: either the destination is
...@@ -806,14 +807,14 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv, ...@@ -806,14 +807,14 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv,
* it is possible to drop the packet * it is possible to drop the packet
*/ */
if (!batadv_is_my_client(bat_priv, ethhdr->h_dest, vid)) if (!batadv_is_my_client(bat_priv, ethhdr->h_dest, vid))
return 0; return false;
/* update the header in order to let the packet be delivered to this /* update the header in order to let the packet be delivered to this
* node's soft interface * node's soft interface
*/ */
primary_if = batadv_primary_if_get_selected(bat_priv); primary_if = batadv_primary_if_get_selected(bat_priv);
if (!primary_if) if (!primary_if)
return 0; return false;
ether_addr_copy(unicast_packet->dest, primary_if->net_dev->dev_addr); ether_addr_copy(unicast_packet->dest, primary_if->net_dev->dev_addr);
...@@ -821,7 +822,7 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv, ...@@ -821,7 +822,7 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv,
unicast_packet->ttvn = curr_ttvn; unicast_packet->ttvn = curr_ttvn;
return 1; return true;
} }
/** /**
...@@ -912,7 +913,7 @@ int batadv_recv_unicast_packet(struct sk_buff *skb, ...@@ -912,7 +913,7 @@ int batadv_recv_unicast_packet(struct sk_buff *skb,
hdr_size)) hdr_size))
goto rx_success; goto rx_success;
batadv_interface_rx(recv_if->soft_iface, skb, recv_if, hdr_size, batadv_interface_rx(recv_if->soft_iface, skb, hdr_size,
orig_node); orig_node);
rx_success: rx_success:
...@@ -1122,8 +1123,7 @@ int batadv_recv_bcast_packet(struct sk_buff *skb, ...@@ -1122,8 +1123,7 @@ int batadv_recv_bcast_packet(struct sk_buff *skb,
goto rx_success; goto rx_success;
/* broadcast for me */ /* broadcast for me */
batadv_interface_rx(recv_if->soft_iface, skb, recv_if, hdr_size, batadv_interface_rx(recv_if->soft_iface, skb, hdr_size, orig_node);
orig_node);
rx_success: rx_success:
ret = NET_RX_SUCCESS; ret = NET_RX_SUCCESS;
......
...@@ -51,7 +51,7 @@ struct batadv_neigh_node * ...@@ -51,7 +51,7 @@ struct batadv_neigh_node *
batadv_find_router(struct batadv_priv *bat_priv, batadv_find_router(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig_node, struct batadv_orig_node *orig_node,
struct batadv_hard_iface *recv_if); struct batadv_hard_iface *recv_if);
int batadv_window_protected(struct batadv_priv *bat_priv, s32 seq_num_diff, bool batadv_window_protected(struct batadv_priv *bat_priv, s32 seq_num_diff,
s32 seq_old_max_diff, unsigned long *last_reset, s32 seq_old_max_diff, unsigned long *last_reset,
bool *protection_started); bool *protection_started);
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <linux/if.h> #include <linux/if.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/kref.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/printk.h> #include <linux/printk.h>
...@@ -577,10 +578,15 @@ static void batadv_send_outstanding_bcast_packet(struct work_struct *work) ...@@ -577,10 +578,15 @@ static void batadv_send_outstanding_bcast_packet(struct work_struct *work)
if (forw_packet->num_packets >= hard_iface->num_bcasts) if (forw_packet->num_packets >= hard_iface->num_bcasts)
continue; continue;
if (!kref_get_unless_zero(&hard_iface->refcount))
continue;
/* send a copy of the saved skb */ /* send a copy of the saved skb */
skb1 = skb_clone(forw_packet->skb, GFP_ATOMIC); skb1 = skb_clone(forw_packet->skb, GFP_ATOMIC);
if (skb1) if (skb1)
batadv_send_broadcast_skb(skb1, hard_iface); batadv_send_broadcast_skb(skb1, hard_iface);
batadv_hardif_put(hard_iface);
} }
rcu_read_unlock(); rcu_read_unlock();
......
...@@ -186,7 +186,6 @@ static int batadv_interface_tx(struct sk_buff *skb, ...@@ -186,7 +186,6 @@ static int batadv_interface_tx(struct sk_buff *skb,
struct batadv_priv *bat_priv = netdev_priv(soft_iface); struct batadv_priv *bat_priv = netdev_priv(soft_iface);
struct batadv_hard_iface *primary_if = NULL; struct batadv_hard_iface *primary_if = NULL;
struct batadv_bcast_packet *bcast_packet; struct batadv_bcast_packet *bcast_packet;
__be16 ethertype = htons(ETH_P_BATMAN);
static const u8 stp_addr[ETH_ALEN] = {0x01, 0x80, 0xC2, 0x00, static const u8 stp_addr[ETH_ALEN] = {0x01, 0x80, 0xC2, 0x00,
0x00, 0x00}; 0x00, 0x00};
static const u8 ectp_addr[ETH_ALEN] = {0xCF, 0x00, 0x00, 0x00, static const u8 ectp_addr[ETH_ALEN] = {0xCF, 0x00, 0x00, 0x00,
...@@ -216,7 +215,8 @@ static int batadv_interface_tx(struct sk_buff *skb, ...@@ -216,7 +215,8 @@ static int batadv_interface_tx(struct sk_buff *skb,
case ETH_P_8021Q: case ETH_P_8021Q:
vhdr = vlan_eth_hdr(skb); vhdr = vlan_eth_hdr(skb);
if (vhdr->h_vlan_encapsulated_proto != ethertype) { /* drop batman-in-batman packets to prevent loops */
if (vhdr->h_vlan_encapsulated_proto != htons(ETH_P_BATMAN)) {
network_offset += VLAN_HLEN; network_offset += VLAN_HLEN;
break; break;
} }
...@@ -385,7 +385,6 @@ static int batadv_interface_tx(struct sk_buff *skb, ...@@ -385,7 +385,6 @@ static int batadv_interface_tx(struct sk_buff *skb,
* batadv_interface_rx - receive ethernet frame on local batman-adv interface * batadv_interface_rx - receive ethernet frame on local batman-adv interface
* @soft_iface: local interface which will receive the ethernet frame * @soft_iface: local interface which will receive the ethernet frame
* @skb: ethernet frame for @soft_iface * @skb: ethernet frame for @soft_iface
* @recv_if: interface on which the batman-adv packet was received
* @hdr_size: size of already parsed batman-adv header * @hdr_size: size of already parsed batman-adv header
* @orig_node: originator from which the batman-adv packet was sent * @orig_node: originator from which the batman-adv packet was sent
* *
...@@ -400,12 +399,11 @@ static int batadv_interface_tx(struct sk_buff *skb, ...@@ -400,12 +399,11 @@ static int batadv_interface_tx(struct sk_buff *skb,
* isolated clients. * isolated clients.
*/ */
void batadv_interface_rx(struct net_device *soft_iface, void batadv_interface_rx(struct net_device *soft_iface,
struct sk_buff *skb, struct batadv_hard_iface *recv_if, struct sk_buff *skb, int hdr_size,
int hdr_size, struct batadv_orig_node *orig_node) struct batadv_orig_node *orig_node)
{ {
struct batadv_bcast_packet *batadv_bcast_packet; struct batadv_bcast_packet *batadv_bcast_packet;
struct batadv_priv *bat_priv = netdev_priv(soft_iface); struct batadv_priv *bat_priv = netdev_priv(soft_iface);
__be16 ethertype = htons(ETH_P_BATMAN);
struct vlan_ethhdr *vhdr; struct vlan_ethhdr *vhdr;
struct ethhdr *ethhdr; struct ethhdr *ethhdr;
unsigned short vid; unsigned short vid;
...@@ -414,10 +412,6 @@ void batadv_interface_rx(struct net_device *soft_iface, ...@@ -414,10 +412,6 @@ void batadv_interface_rx(struct net_device *soft_iface,
batadv_bcast_packet = (struct batadv_bcast_packet *)skb->data; batadv_bcast_packet = (struct batadv_bcast_packet *)skb->data;
is_bcast = (batadv_bcast_packet->packet_type == BATADV_BCAST); is_bcast = (batadv_bcast_packet->packet_type == BATADV_BCAST);
/* check if enough space is available for pulling, and pull */
if (!pskb_may_pull(skb, hdr_size))
goto dropped;
skb_pull_rcsum(skb, hdr_size); skb_pull_rcsum(skb, hdr_size);
skb_reset_mac_header(skb); skb_reset_mac_header(skb);
...@@ -439,7 +433,8 @@ void batadv_interface_rx(struct net_device *soft_iface, ...@@ -439,7 +433,8 @@ void batadv_interface_rx(struct net_device *soft_iface,
vhdr = (struct vlan_ethhdr *)skb->data; vhdr = (struct vlan_ethhdr *)skb->data;
if (vhdr->h_vlan_encapsulated_proto != ethertype) /* drop batman-in-batman packets to prevent loops */
if (vhdr->h_vlan_encapsulated_proto != htons(ETH_P_BATMAN))
break; break;
/* fall through */ /* fall through */
...@@ -890,13 +885,14 @@ static int batadv_softif_slave_add(struct net_device *dev, ...@@ -890,13 +885,14 @@ static int batadv_softif_slave_add(struct net_device *dev,
struct net_device *slave_dev) struct net_device *slave_dev)
{ {
struct batadv_hard_iface *hard_iface; struct batadv_hard_iface *hard_iface;
struct net *net = dev_net(dev);
int ret = -EINVAL; int ret = -EINVAL;
hard_iface = batadv_hardif_get_by_netdev(slave_dev); hard_iface = batadv_hardif_get_by_netdev(slave_dev);
if (!hard_iface || hard_iface->soft_iface) if (!hard_iface || hard_iface->soft_iface)
goto out; goto out;
ret = batadv_hardif_enable_interface(hard_iface, dev->name); ret = batadv_hardif_enable_interface(hard_iface, net, dev->name);
out: out:
if (hard_iface) if (hard_iface)
...@@ -977,7 +973,7 @@ static void batadv_softif_init_early(struct net_device *dev) ...@@ -977,7 +973,7 @@ static void batadv_softif_init_early(struct net_device *dev)
dev->netdev_ops = &batadv_netdev_ops; dev->netdev_ops = &batadv_netdev_ops;
dev->destructor = batadv_softif_free; dev->destructor = batadv_softif_free;
dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER; dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_NETNS_LOCAL;
dev->priv_flags |= IFF_NO_QUEUE; dev->priv_flags |= IFF_NO_QUEUE;
/* can't call min_mtu, because the needed variables /* can't call min_mtu, because the needed variables
...@@ -993,7 +989,7 @@ static void batadv_softif_init_early(struct net_device *dev) ...@@ -993,7 +989,7 @@ static void batadv_softif_init_early(struct net_device *dev)
memset(priv, 0, sizeof(*priv)); memset(priv, 0, sizeof(*priv));
} }
struct net_device *batadv_softif_create(const char *name) struct net_device *batadv_softif_create(struct net *net, const char *name)
{ {
struct net_device *soft_iface; struct net_device *soft_iface;
int ret; int ret;
...@@ -1003,6 +999,8 @@ struct net_device *batadv_softif_create(const char *name) ...@@ -1003,6 +999,8 @@ struct net_device *batadv_softif_create(const char *name)
if (!soft_iface) if (!soft_iface)
return NULL; return NULL;
dev_net_set(soft_iface, net);
soft_iface->rtnl_link_ops = &batadv_link_ops; soft_iface->rtnl_link_ops = &batadv_link_ops;
ret = register_netdevice(soft_iface); ret = register_netdevice(soft_iface);
...@@ -1047,12 +1045,12 @@ static void batadv_softif_destroy_netlink(struct net_device *soft_iface, ...@@ -1047,12 +1045,12 @@ static void batadv_softif_destroy_netlink(struct net_device *soft_iface,
unregister_netdevice_queue(soft_iface, head); unregister_netdevice_queue(soft_iface, head);
} }
int batadv_softif_is_valid(const struct net_device *net_dev) bool batadv_softif_is_valid(const struct net_device *net_dev)
{ {
if (net_dev->netdev_ops->ndo_start_xmit == batadv_interface_tx) if (net_dev->netdev_ops->ndo_start_xmit == batadv_interface_tx)
return 1; return true;
return 0; return false;
} }
struct rtnl_link_ops batadv_link_ops __read_mostly = { struct rtnl_link_ops batadv_link_ops __read_mostly = {
......
...@@ -20,18 +20,20 @@ ...@@ -20,18 +20,20 @@
#include "main.h" #include "main.h"
#include <linux/types.h>
#include <net/rtnetlink.h> #include <net/rtnetlink.h>
struct net_device; struct net_device;
struct net;
struct sk_buff; struct sk_buff;
int batadv_skb_head_push(struct sk_buff *skb, unsigned int len); int batadv_skb_head_push(struct sk_buff *skb, unsigned int len);
void batadv_interface_rx(struct net_device *soft_iface, void batadv_interface_rx(struct net_device *soft_iface,
struct sk_buff *skb, struct batadv_hard_iface *recv_if, struct sk_buff *skb, int hdr_size,
int hdr_size, struct batadv_orig_node *orig_node); struct batadv_orig_node *orig_node);
struct net_device *batadv_softif_create(const char *name); struct net_device *batadv_softif_create(struct net *net, const char *name);
void batadv_softif_destroy_sysfs(struct net_device *soft_iface); void batadv_softif_destroy_sysfs(struct net_device *soft_iface);
int batadv_softif_is_valid(const struct net_device *net_dev); bool batadv_softif_is_valid(const struct net_device *net_dev);
extern struct rtnl_link_ops batadv_link_ops; extern struct rtnl_link_ops batadv_link_ops;
int batadv_softif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid); int batadv_softif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid);
void batadv_softif_vlan_put(struct batadv_softif_vlan *softif_vlan); void batadv_softif_vlan_put(struct batadv_softif_vlan *softif_vlan);
......
...@@ -116,11 +116,13 @@ batadv_kobj_to_vlan(struct batadv_priv *bat_priv, struct kobject *obj) ...@@ -116,11 +116,13 @@ batadv_kobj_to_vlan(struct batadv_priv *bat_priv, struct kobject *obj)
static char *batadv_uev_action_str[] = { static char *batadv_uev_action_str[] = {
"add", "add",
"del", "del",
"change" "change",
"loopdetect",
}; };
static char *batadv_uev_type_str[] = { static char *batadv_uev_type_str[] = {
"gw" "gw",
"bla",
}; };
/* Use this, if you have customized show and store functions for vlan attrs */ /* Use this, if you have customized show and store functions for vlan attrs */
...@@ -830,6 +832,7 @@ static ssize_t batadv_store_mesh_iface(struct kobject *kobj, ...@@ -830,6 +832,7 @@ static ssize_t batadv_store_mesh_iface(struct kobject *kobj,
size_t count) size_t count)
{ {
struct net_device *net_dev = batadv_kobj_to_netdev(kobj); struct net_device *net_dev = batadv_kobj_to_netdev(kobj);
struct net *net = dev_net(net_dev);
struct batadv_hard_iface *hard_iface; struct batadv_hard_iface *hard_iface;
int status_tmp = -1; int status_tmp = -1;
int ret = count; int ret = count;
...@@ -873,7 +876,7 @@ static ssize_t batadv_store_mesh_iface(struct kobject *kobj, ...@@ -873,7 +876,7 @@ static ssize_t batadv_store_mesh_iface(struct kobject *kobj,
batadv_hardif_disable_interface(hard_iface, batadv_hardif_disable_interface(hard_iface,
BATADV_IF_CLEANUP_AUTO); BATADV_IF_CLEANUP_AUTO);
ret = batadv_hardif_enable_interface(hard_iface, buff); ret = batadv_hardif_enable_interface(hard_iface, net, buff);
unlock: unlock:
rtnl_unlock(); rtnl_unlock();
......
...@@ -43,7 +43,6 @@ ...@@ -43,7 +43,6 @@
#include <linux/stddef.h> #include <linux/stddef.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <net/net_namespace.h>
#include "bridge_loop_avoidance.h" #include "bridge_loop_avoidance.h"
#include "hard-interface.h" #include "hard-interface.h"
...@@ -76,9 +75,9 @@ static void batadv_tt_global_del(struct batadv_priv *bat_priv, ...@@ -76,9 +75,9 @@ static void batadv_tt_global_del(struct batadv_priv *bat_priv,
* *
* Compare the MAC address and the VLAN ID of the two TT entries and check if * Compare the MAC address and the VLAN ID of the two TT entries and check if
* they are the same TT client. * they are the same TT client.
* Return: 1 if the two TT clients are the same, 0 otherwise * Return: true if the two TT clients are the same, false otherwise
*/ */
static int batadv_compare_tt(const struct hlist_node *node, const void *data2) static bool batadv_compare_tt(const struct hlist_node *node, const void *data2)
{ {
const void *data1 = container_of(node, struct batadv_tt_common_entry, const void *data1 = container_of(node, struct batadv_tt_common_entry,
hash_entry); hash_entry);
...@@ -585,6 +584,7 @@ bool batadv_tt_local_add(struct net_device *soft_iface, const u8 *addr, ...@@ -585,6 +584,7 @@ bool batadv_tt_local_add(struct net_device *soft_iface, const u8 *addr,
struct batadv_priv *bat_priv = netdev_priv(soft_iface); struct batadv_priv *bat_priv = netdev_priv(soft_iface);
struct batadv_tt_local_entry *tt_local; struct batadv_tt_local_entry *tt_local;
struct batadv_tt_global_entry *tt_global = NULL; struct batadv_tt_global_entry *tt_global = NULL;
struct net *net = dev_net(soft_iface);
struct batadv_softif_vlan *vlan; struct batadv_softif_vlan *vlan;
struct net_device *in_dev = NULL; struct net_device *in_dev = NULL;
struct hlist_head *head; struct hlist_head *head;
...@@ -596,7 +596,7 @@ bool batadv_tt_local_add(struct net_device *soft_iface, const u8 *addr, ...@@ -596,7 +596,7 @@ bool batadv_tt_local_add(struct net_device *soft_iface, const u8 *addr,
u32 match_mark; u32 match_mark;
if (ifindex != BATADV_NULL_IFINDEX) if (ifindex != BATADV_NULL_IFINDEX)
in_dev = dev_get_by_index(&init_net, ifindex); in_dev = dev_get_by_index(net, ifindex);
tt_local = batadv_tt_local_hash_find(bat_priv, addr, vid); tt_local = batadv_tt_local_hash_find(bat_priv, addr, vid);
...@@ -2361,18 +2361,18 @@ batadv_tt_req_node_new(struct batadv_priv *bat_priv, ...@@ -2361,18 +2361,18 @@ batadv_tt_req_node_new(struct batadv_priv *bat_priv,
* @entry_ptr: to be checked local tt entry * @entry_ptr: to be checked local tt entry
* @data_ptr: not used but definition required to satisfy the callback prototype * @data_ptr: not used but definition required to satisfy the callback prototype
* *
* Return: 1 if the entry is a valid, 0 otherwise. * Return: true if the entry is a valid, false otherwise.
*/ */
static int batadv_tt_local_valid(const void *entry_ptr, const void *data_ptr) static bool batadv_tt_local_valid(const void *entry_ptr, const void *data_ptr)
{ {
const struct batadv_tt_common_entry *tt_common_entry = entry_ptr; const struct batadv_tt_common_entry *tt_common_entry = entry_ptr;
if (tt_common_entry->flags & BATADV_TT_CLIENT_NEW) if (tt_common_entry->flags & BATADV_TT_CLIENT_NEW)
return 0; return false;
return 1; return true;
} }
static int batadv_tt_global_valid(const void *entry_ptr, static bool batadv_tt_global_valid(const void *entry_ptr,
const void *data_ptr) const void *data_ptr)
{ {
const struct batadv_tt_common_entry *tt_common_entry = entry_ptr; const struct batadv_tt_common_entry *tt_common_entry = entry_ptr;
...@@ -2381,7 +2381,7 @@ static int batadv_tt_global_valid(const void *entry_ptr, ...@@ -2381,7 +2381,7 @@ static int batadv_tt_global_valid(const void *entry_ptr,
if (tt_common_entry->flags & BATADV_TT_CLIENT_ROAM || if (tt_common_entry->flags & BATADV_TT_CLIENT_ROAM ||
tt_common_entry->flags & BATADV_TT_CLIENT_TEMP) tt_common_entry->flags & BATADV_TT_CLIENT_TEMP)
return 0; return false;
tt_global_entry = container_of(tt_common_entry, tt_global_entry = container_of(tt_common_entry,
struct batadv_tt_global_entry, struct batadv_tt_global_entry,
...@@ -2403,7 +2403,8 @@ static int batadv_tt_global_valid(const void *entry_ptr, ...@@ -2403,7 +2403,8 @@ static int batadv_tt_global_valid(const void *entry_ptr,
static void batadv_tt_tvlv_generate(struct batadv_priv *bat_priv, static void batadv_tt_tvlv_generate(struct batadv_priv *bat_priv,
struct batadv_hashtable *hash, struct batadv_hashtable *hash,
void *tvlv_buff, u16 tt_len, void *tvlv_buff, u16 tt_len,
int (*valid_cb)(const void *, const void *), bool (*valid_cb)(const void *,
const void *),
void *cb_data) void *cb_data)
{ {
struct batadv_tt_common_entry *tt_common_entry; struct batadv_tt_common_entry *tt_common_entry;
...@@ -2552,7 +2553,7 @@ static void batadv_tt_global_update_crc(struct batadv_priv *bat_priv, ...@@ -2552,7 +2553,7 @@ static void batadv_tt_global_update_crc(struct batadv_priv *bat_priv,
* *
* Return: true if the TT Request was sent, false otherwise * Return: true if the TT Request was sent, false otherwise
*/ */
static int batadv_send_tt_request(struct batadv_priv *bat_priv, static bool batadv_send_tt_request(struct batadv_priv *bat_priv,
struct batadv_orig_node *dst_orig_node, struct batadv_orig_node *dst_orig_node,
u8 ttvn, u8 ttvn,
struct batadv_tvlv_tt_vlan_data *tt_vlan, struct batadv_tvlv_tt_vlan_data *tt_vlan,
......
...@@ -657,6 +657,9 @@ struct batadv_priv_tt { ...@@ -657,6 +657,9 @@ struct batadv_priv_tt {
* @num_requests: number of bla requests in flight * @num_requests: number of bla requests in flight
* @claim_hash: hash table containing mesh nodes this host has claimed * @claim_hash: hash table containing mesh nodes this host has claimed
* @backbone_hash: hash table containing all detected backbone gateways * @backbone_hash: hash table containing all detected backbone gateways
* @loopdetect_addr: MAC address used for own loopdetection frames
* @loopdetect_lasttime: time when the loopdetection frames were sent
* @loopdetect_next: how many periods to wait for the next loopdetect process
* @bcast_duplist: recently received broadcast packets array (for broadcast * @bcast_duplist: recently received broadcast packets array (for broadcast
* duplicate suppression) * duplicate suppression)
* @bcast_duplist_curr: index of last broadcast packet added to bcast_duplist * @bcast_duplist_curr: index of last broadcast packet added to bcast_duplist
...@@ -668,6 +671,9 @@ struct batadv_priv_bla { ...@@ -668,6 +671,9 @@ struct batadv_priv_bla {
atomic_t num_requests; atomic_t num_requests;
struct batadv_hashtable *claim_hash; struct batadv_hashtable *claim_hash;
struct batadv_hashtable *backbone_hash; struct batadv_hashtable *backbone_hash;
u8 loopdetect_addr[ETH_ALEN];
unsigned long loopdetect_lasttime;
atomic_t loopdetect_next;
struct batadv_bcast_duplist_entry bcast_duplist[BATADV_DUPLIST_SIZE]; struct batadv_bcast_duplist_entry bcast_duplist[BATADV_DUPLIST_SIZE];
int bcast_duplist_curr; int bcast_duplist_curr;
/* protects bcast_duplist & bcast_duplist_curr */ /* protects bcast_duplist & bcast_duplist_curr */
...@@ -1012,6 +1018,7 @@ struct batadv_socket_packet { ...@@ -1012,6 +1018,7 @@ struct batadv_socket_packet {
* resolved * resolved
* @crc: crc16 checksum over all claims * @crc: crc16 checksum over all claims
* @crc_lock: lock protecting crc * @crc_lock: lock protecting crc
* @report_work: work struct for reporting detected loops
* @refcount: number of contexts the object is used * @refcount: number of contexts the object is used
* @rcu: struct used for freeing in an RCU-safe manner * @rcu: struct used for freeing in an RCU-safe manner
*/ */
...@@ -1025,6 +1032,7 @@ struct batadv_bla_backbone_gw { ...@@ -1025,6 +1032,7 @@ struct batadv_bla_backbone_gw {
atomic_t request_sent; atomic_t request_sent;
u16 crc; u16 crc;
spinlock_t crc_lock; /* protects crc */ spinlock_t crc_lock; /* protects crc */
struct work_struct report_work;
struct kref refcount; struct kref refcount;
struct rcu_head rcu; struct rcu_head rcu;
}; };
......
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