Merge tag 'batman-adv-for-davem' of git://git.open-mesh.org/linux-merge
authorDavid S. Miller <davem@davemloft.net>
Wed, 11 May 2016 03:36:14 +0000 (23:36 -0400)
committerDavid S. Miller <davem@davemloft.net>
Wed, 11 May 2016 03:36:14 +0000 (23:36 -0400)
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: David S. Miller <davem@davemloft.net>
26 files changed:
net/batman-adv/bat_iv_ogm.c
net/batman-adv/bat_v_ogm.c
net/batman-adv/bitarray.c
net/batman-adv/bitarray.h
net/batman-adv/bridge_loop_avoidance.c
net/batman-adv/bridge_loop_avoidance.h
net/batman-adv/debugfs.c
net/batman-adv/distributed-arp-table.c
net/batman-adv/gateway_client.c
net/batman-adv/hard-interface.c
net/batman-adv/hard-interface.h
net/batman-adv/hash.h
net/batman-adv/main.c
net/batman-adv/main.h
net/batman-adv/network-coding.c
net/batman-adv/originator.c
net/batman-adv/originator.h
net/batman-adv/packet.h
net/batman-adv/routing.c
net/batman-adv/routing.h
net/batman-adv/send.c
net/batman-adv/soft-interface.c
net/batman-adv/soft-interface.h
net/batman-adv/sysfs.c
net/batman-adv/translation-table.c
net/batman-adv/types.h

index 8c1710bba803f3d5c1ecfea4418681fca99e5294..7f98a9d39883029e427d132f670373e78f0a982d 100644 (file)
@@ -681,18 +681,12 @@ static void batadv_iv_ogm_aggregate_new(const unsigned char *packet_buff,
        unsigned char *skb_buff;
        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 */
        if (!own_packet) {
                if (!batadv_atomic_dec_not_zero(&bat_priv->batman_queue_left)) {
                        batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
                                   "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,
        forw_packet_aggr->packet_len = 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->if_incoming = if_incoming;
        forw_packet_aggr->if_outgoing = if_outgoing;
@@ -747,10 +743,6 @@ out_free_forw_packet:
 out_nomem:
        if (!own_packet)
                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 */
@@ -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) {
                if (tmp_hard_iface->soft_iface != hard_iface->soft_iface)
                        continue;
+
+               if (!kref_get_unless_zero(&tmp_hard_iface->refcount))
+                       continue;
+
                batadv_iv_ogm_queue_add(bat_priv, *ogm_buff,
                                        *ogm_buff_len, hard_iface,
                                        tmp_hard_iface, 1, send_time);
+
+               batadv_hardif_put(tmp_hard_iface);
        }
        rcu_read_unlock();
 
@@ -1170,13 +1168,13 @@ out:
  * @if_incoming: interface where the packet was received
  * @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,
-                                struct batadv_orig_node *orig_neigh_node,
-                                struct batadv_ogm_packet *batadv_ogm_packet,
-                                struct batadv_hard_iface *if_incoming,
-                                struct batadv_hard_iface *if_outgoing)
+static bool batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node,
+                                 struct batadv_orig_node *orig_neigh_node,
+                                 struct batadv_ogm_packet *batadv_ogm_packet,
+                                 struct batadv_hard_iface *if_incoming,
+                                 struct batadv_hard_iface *if_outgoing)
 {
        struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
        struct batadv_neigh_node *neigh_node = NULL, *tmp_neigh_node;
@@ -1184,9 +1182,10 @@ static int batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node,
        u8 total_count;
        u8 orig_eq_count, neigh_rq_count, neigh_rq_inv, tq_own;
        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;
        int tq_iface_penalty;
+       bool ret = false;
 
        /* find corresponding one hop neighbor */
        rcu_read_lock();
@@ -1298,7 +1297,7 @@ static int batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node,
         * consider it bidirectional
         */
        if (batadv_ogm_packet->tq >= BATADV_TQ_TOTAL_BIDRECT_LIMIT)
-               ret = 1;
+               ret = true;
 
 out:
        if (neigh_node)
@@ -1327,9 +1326,9 @@ batadv_iv_ogm_update_seqnos(const struct ethhdr *ethhdr,
        struct batadv_orig_ifinfo *orig_ifinfo = NULL;
        struct batadv_neigh_node *neigh_node;
        struct batadv_neigh_ifinfo *neigh_ifinfo;
-       int is_dup;
+       bool is_dup;
        s32 seq_diff;
-       int need_update = 0;
+       bool need_update = false;
        int set_mark;
        enum batadv_dup_status ret = BATADV_NO_DUP;
        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,
        struct sk_buff *skb_priv;
        struct ethhdr *ethhdr;
        u8 *prev_sender;
-       int is_bidirect;
+       bool is_bidirect;
 
        /* create a private copy of the skb, as some functions change tq value
         * and/or flags.
@@ -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)
                        continue;
 
+               if (!kref_get_unless_zero(&hard_iface->refcount))
+                       continue;
+
                batadv_iv_ogm_process_per_outif(skb, ogm_offset, orig_node,
                                                if_incoming, hard_iface);
+
+               batadv_hardif_put(hard_iface);
        }
        rcu_read_unlock();
 
index 4155fa57cf6da5ff1c4d46f3c71d7c5bc349351f..473ebb9a0e737a23c29c7293cfe193959f1aec07 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/if_ether.h>
 #include <linux/jiffies.h>
 #include <linux/kernel.h>
+#include <linux/kref.h>
 #include <linux/list.h>
 #include <linux/netdevice.h>
 #include <linux/random.h>
@@ -176,6 +177,9 @@ static void batadv_v_ogm_send(struct work_struct *work)
                if (hard_iface->soft_iface != bat_priv->soft_iface)
                        continue;
 
+               if (!kref_get_unless_zero(&hard_iface->refcount))
+                       continue;
+
                batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
                           "Sending own OGM2 packet (originator %pM, seqno %u, throughput %u, TTL %d) on interface %s [%pM]\n",
                           ogm_packet->orig, ntohl(ogm_packet->seqno),
@@ -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() */
                skb_tmp = skb_clone(skb, GFP_ATOMIC);
-               if (!skb_tmp)
+               if (!skb_tmp) {
+                       batadv_hardif_put(hard_iface);
                        break;
+               }
 
                batadv_v_ogm_send_to_if(skb_tmp, hard_iface);
+               batadv_hardif_put(hard_iface);
        }
        rcu_read_unlock();
 
@@ -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)
                        continue;
 
+               if (!kref_get_unless_zero(&hard_iface->refcount))
+                       continue;
+
                batadv_v_ogm_process_per_outif(bat_priv, ethhdr, ogm_packet,
                                               orig_node, neigh_node,
                                               if_incoming, hard_iface);
+
+               batadv_hardif_put(hard_iface);
        }
        rcu_read_unlock();
 out:
index b56bb000a0abcbb2fe547612d12009a18e69d530..a0c7913837a58af3a293c98720fa8f5480c6450a 100644 (file)
@@ -38,11 +38,11 @@ static void batadv_bitmap_shift_left(unsigned long *seq_bits, s32 n)
  *  the last sequence number
  * @set_mark: whether this packet should be marked in seq_bits
  *
- * Return: 1 if the window was moved (either new or very old),
- *  0 if the window was not moved/shifted.
+ * Return: true if the window was moved (either new or very old),
+ *  false if the window was not moved/shifted.
  */
-int batadv_bit_get_packet(void *priv, unsigned long *seq_bits, s32 seq_num_diff,
-                         int set_mark)
+bool batadv_bit_get_packet(void *priv, unsigned long *seq_bits,
+                          s32 seq_num_diff, int set_mark)
 {
        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,
        if (seq_num_diff <= 0 && seq_num_diff > -BATADV_TQ_LOCAL_WINDOW_SIZE) {
                if (set_mark)
                        batadv_set_bit(seq_bits, -seq_num_diff);
-               return 0;
+               return false;
        }
 
        /* 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,
 
                if (set_mark)
                        batadv_set_bit(seq_bits, 0);
-               return 1;
+               return true;
        }
 
        /* 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,
                bitmap_zero(seq_bits, BATADV_TQ_LOCAL_WINDOW_SIZE);
                if (set_mark)
                        batadv_set_bit(seq_bits, 0);
-               return 1;
+               return true;
        }
 
        /* 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,
        if (set_mark)
                batadv_set_bit(seq_bits, 0);
 
-       return 1;
+       return true;
 }
index 3e41bb80eb81ac34dce4c3c34fa33a3643b19bdc..0e6e9d09078cf176e7b426615666e5f51def5fbd 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <linux/bitops.h>
 #include <linux/compiler.h>
+#include <linux/stddef.h>
 #include <linux/types.h>
 
 /**
  * @last_seqno: latest sequence number in seq_bits
  * @curr_seqno: sequence number to test for
  *
- * Return: 1 if the corresponding bit in the given seq_bits indicates true
- * and curr_seqno is within range of last_seqno. Otherwise returns 0.
+ * Return: true if the corresponding bit in the given seq_bits indicates true
+ * and curr_seqno is within range of last_seqno. Otherwise returns false.
  */
-static inline int batadv_test_bit(const unsigned long *seq_bits,
-                                 u32 last_seqno, u32 curr_seqno)
+static inline bool batadv_test_bit(const unsigned long *seq_bits,
+                                  u32 last_seqno, u32 curr_seqno)
 {
        s32 diff;
 
        diff = last_seqno - curr_seqno;
        if (diff < 0 || diff >= BATADV_TQ_LOCAL_WINDOW_SIZE)
-               return 0;
+               return false;
        return test_bit(diff, seq_bits) != 0;
 }
 
@@ -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 */
 }
 
-int batadv_bit_get_packet(void *priv, unsigned long *seq_bits, s32 seq_num_diff,
-                         int set_mark);
+bool batadv_bit_get_packet(void *priv, unsigned long *seq_bits,
+                          s32 seq_num_diff, int set_mark);
 
 #endif /* _NET_BATMAN_ADV_BITARRAY_H_ */
index 2c9aa671a49b18abb786f6a3f3c3106d1774d302..748a9ead7ce50fd65a0a09f2b19eaa035a566327 100644 (file)
@@ -50,6 +50,7 @@
 #include "hash.h"
 #include "originator.h"
 #include "packet.h"
+#include "sysfs.h"
 #include "translation-table.h"
 
 static const u8 batadv_announce_mac[4] = {0x43, 0x05, 0x43, 0x05};
@@ -100,10 +101,10 @@ static inline u32 batadv_choose_backbone_gw(const void *data, u32 size)
  * @node: list node of the first entry to compare
  * @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,
-                                     const void *data2)
+static bool batadv_compare_backbone_gw(const struct hlist_node *node,
+                                      const void *data2)
 {
        const void *data1 = container_of(node, struct batadv_bla_backbone_gw,
                                         hash_entry);
@@ -111,12 +112,12 @@ static int batadv_compare_backbone_gw(const struct hlist_node *node,
        const struct batadv_bla_backbone_gw *gw2 = data2;
 
        if (!batadv_compare_eth(gw1->orig, gw2->orig))
-               return 0;
+               return false;
 
        if (gw1->vid != gw2->vid)
-               return 0;
+               return false;
 
-       return 1;
+       return true;
 }
 
 /**
@@ -124,10 +125,10 @@ static int batadv_compare_backbone_gw(const struct hlist_node *node,
  * @node: list node of the first entry to compare
  * @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,
-                               const void *data2)
+static bool batadv_compare_claim(const struct hlist_node *node,
+                                const void *data2)
 {
        const void *data1 = container_of(node, struct batadv_bla_claim,
                                         hash_entry);
@@ -135,12 +136,12 @@ static int batadv_compare_claim(const struct hlist_node *node,
        const struct batadv_bla_claim *cl2 = data2;
 
        if (!batadv_compare_eth(cl1->addr, cl2->addr))
-               return 0;
+               return false;
 
        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,
                           ethhdr->h_source, ethhdr->h_dest,
                           BATADV_PRINT_VID(vid));
                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)
@@ -426,6 +435,36 @@ out:
                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
  * @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,
        atomic_set(&entry->request_sent, 0);
        atomic_set(&entry->wait_periods, 0);
        ether_addr_copy(entry->orig, orig);
+       INIT_WORK(&entry->report_work, batadv_bla_loopdetect_report);
 
        /* one for the hash, one for returning */
        kref_init(&entry->refcount);
@@ -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)
  * @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,
-                                 u8 *backbone_addr, unsigned short vid)
+static bool batadv_handle_announce(struct batadv_priv *bat_priv, u8 *an_addr,
+                                  u8 *backbone_addr, unsigned short vid)
 {
        struct batadv_bla_backbone_gw *backbone_gw;
        u16 backbone_crc, crc;
 
        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,
                                                 false);
 
        if (unlikely(!backbone_gw))
-               return 1;
+               return true;
 
        /* handle as ANNOUNCE frame */
        backbone_gw->lasttime = jiffies;
@@ -783,7 +823,7 @@ static int batadv_handle_announce(struct batadv_priv *bat_priv, u8 *an_addr,
        }
 
        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,
  * @ethhdr: ethernet header of a packet
  * @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,
-                                struct batadv_hard_iface *primary_if,
-                                u8 *backbone_addr, struct ethhdr *ethhdr,
-                                unsigned short vid)
+static bool batadv_handle_request(struct batadv_priv *bat_priv,
+                                 struct batadv_hard_iface *primary_if,
+                                 u8 *backbone_addr, struct ethhdr *ethhdr,
+                                 unsigned short vid)
 {
        /* check for REQUEST frame */
        if (!batadv_compare_eth(backbone_addr, ethhdr->h_dest))
-               return 0;
+               return false;
 
        /* sanity check, this should not happen on a normal switch,
         * we ignore it in this case.
         */
        if (!batadv_compare_eth(ethhdr->h_dest, primary_if->net_dev->dev_addr))
-               return 1;
+               return true;
 
        batadv_dbg(BATADV_DBG_BLA, bat_priv,
                   "handle_request(): REQUEST vid %d (sent by %pM)...\n",
                   BATADV_PRINT_VID(vid), ethhdr->h_source);
 
        batadv_bla_answer_request(bat_priv, primary_if, vid);
-       return 1;
+       return true;
 }
 
 /**
@@ -827,12 +867,12 @@ static int batadv_handle_request(struct batadv_priv *bat_priv,
  * @claim_addr: Client to be unclaimed (ARP sender HW MAC)
  * @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,
-                                struct batadv_hard_iface *primary_if,
-                                u8 *backbone_addr, u8 *claim_addr,
-                                unsigned short vid)
+static bool batadv_handle_unclaim(struct batadv_priv *bat_priv,
+                                 struct batadv_hard_iface *primary_if,
+                                 u8 *backbone_addr, u8 *claim_addr,
+                                 unsigned short vid)
 {
        struct batadv_bla_backbone_gw *backbone_gw;
 
@@ -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);
 
        if (!backbone_gw)
-               return 1;
+               return true;
 
        /* this must be an UNCLAIM frame */
        batadv_dbg(BATADV_DBG_BLA, 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_backbone_gw_put(backbone_gw);
-       return 1;
+       return true;
 }
 
 /**
@@ -865,12 +905,12 @@ static int batadv_handle_unclaim(struct batadv_priv *bat_priv,
  * @claim_addr: client mac address to be claimed (ARP sender HW MAC)
  * @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,
-                              struct batadv_hard_iface *primary_if,
-                              u8 *backbone_addr, u8 *claim_addr,
-                              unsigned short vid)
+static bool batadv_handle_claim(struct batadv_priv *bat_priv,
+                               struct batadv_hard_iface *primary_if,
+                               u8 *backbone_addr, u8 *claim_addr,
+                               unsigned short vid)
 {
        struct batadv_bla_backbone_gw *backbone_gw;
 
@@ -880,7 +920,7 @@ static int batadv_handle_claim(struct batadv_priv *bat_priv,
                                                 false);
 
        if (unlikely(!backbone_gw))
-               return 1;
+               return true;
 
        /* this must be a CLAIM frame */
        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,
        /* TODO: we could call something like tt_local_del() here. */
 
        batadv_backbone_gw_put(backbone_gw);
-       return 1;
+       return true;
 }
 
 /**
@@ -975,12 +1015,12 @@ static int batadv_check_claim_group(struct batadv_priv *bat_priv,
  * @primary_if: the primary hard interface of this batman soft interface
  * @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.
  */
-static int batadv_bla_process_claim(struct batadv_priv *bat_priv,
-                                   struct batadv_hard_iface *primary_if,
-                                   struct sk_buff *skb)
+static bool batadv_bla_process_claim(struct batadv_priv *bat_priv,
+                                    struct batadv_hard_iface *primary_if,
+                                    struct sk_buff *skb)
 {
        struct batadv_bla_claim_dst *bla_dst, *bla_dst_own;
        u8 *hw_src, *hw_dst;
@@ -1011,7 +1051,7 @@ static int batadv_bla_process_claim(struct batadv_priv *bat_priv,
                        vhdr = skb_header_pointer(skb, headlen, VLAN_HLEN,
                                                  &vhdr_buf);
                        if (!vhdr)
-                               return 0;
+                               return false;
 
                        proto = vhdr->h_vlan_encapsulated_proto;
                        headlen += VLAN_HLEN;
@@ -1020,12 +1060,12 @@ static int batadv_bla_process_claim(struct batadv_priv *bat_priv,
        }
 
        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. */
 
        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 */
        ethhdr = eth_hdr(skb);
@@ -1035,13 +1075,13 @@ static int batadv_bla_process_claim(struct batadv_priv *bat_priv,
         * IP information
         */
        if (arphdr->ar_hrd != htons(ARPHRD_ETHER))
-               return 0;
+               return false;
        if (arphdr->ar_pro != htons(ETH_P_IP))
-               return 0;
+               return false;
        if (arphdr->ar_hln != ETH_ALEN)
-               return 0;
+               return false;
        if (arphdr->ar_pln != 4)
-               return 0;
+               return false;
 
        hw_src = (u8 *)arphdr + sizeof(struct arphdr);
        hw_dst = hw_src + ETH_ALEN + 4;
@@ -1051,14 +1091,18 @@ static int batadv_bla_process_claim(struct batadv_priv *bat_priv,
        /* check if it is a claim frame in general */
        if (memcmp(bla_dst->magic, bla_dst_own->magic,
                   sizeof(bla_dst->magic)) != 0)
-               return 0;
+               return false;
 
        /* 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
         * sent via the mesh.
         */
        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. */
        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,
                           hw_dst);
 
        if (ret < 2)
-               return ret;
+               return !!ret;
 
        /* become a backbone gw ourselves on this vlan if not happened yet */
        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,
        case BATADV_CLAIM_TYPE_CLAIM:
                if (batadv_handle_claim(bat_priv, primary_if, hw_src,
                                        ethhdr->h_source, vid))
-                       return 1;
+                       return true;
                break;
        case BATADV_CLAIM_TYPE_UNCLAIM:
                if (batadv_handle_unclaim(bat_priv, primary_if,
                                          ethhdr->h_source, hw_src, vid))
-                       return 1;
+                       return true;
                break;
 
        case BATADV_CLAIM_TYPE_ANNOUNCE:
                if (batadv_handle_announce(bat_priv, hw_src, ethhdr->h_source,
                                           vid))
-                       return 1;
+                       return true;
                break;
        case BATADV_CLAIM_TYPE_REQUEST:
                if (batadv_handle_request(bat_priv, primary_if, hw_src, ethhdr,
                                          vid))
-                       return 1;
+                       return true;
                break;
        }
 
        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",
                   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,
        }
 }
 
+/**
+ * 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
  * @net_dev: the soft interface net device
@@ -1301,6 +1365,7 @@ static void batadv_bla_periodic_work(struct work_struct *work)
        struct batadv_bla_backbone_gw *backbone_gw;
        struct batadv_hashtable *hash;
        struct batadv_hard_iface *primary_if;
+       bool send_loopdetect = false;
        int i;
 
        delayed_work = to_delayed_work(work);
@@ -1316,6 +1381,22 @@ static void batadv_bla_periodic_work(struct work_struct *work)
        if (!atomic_read(&bat_priv->bridge_loop_avoidance))
                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;
        if (!hash)
                goto out;
@@ -1332,6 +1413,9 @@ static void batadv_bla_periodic_work(struct work_struct *work)
                        backbone_gw->lasttime = jiffies;
 
                        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
                         * problems when we are not yet known as backbone gw
@@ -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_curr = 0;
 
+       atomic_set(&bat_priv->bla.loopdetect_next,
+                  BATADV_BLA_LOOPDETECT_PERIODS);
+
        if (bat_priv->bla.claim_hash)
                return 0;
 
@@ -1442,15 +1529,16 @@ int batadv_bla_init(struct batadv_priv *bat_priv)
  * sent by another host, drop it. We allow equal packets from
  * 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,
-                                  struct sk_buff *skb)
+bool batadv_bla_check_bcast_duplist(struct batadv_priv *bat_priv,
+                                   struct sk_buff *skb)
 {
-       int i, curr, ret = 0;
+       int i, curr;
        __be32 crc;
        struct batadv_bcast_packet *bcast_packet;
        struct batadv_bcast_duplist_entry *entry;
+       bool ret = false;
 
        bcast_packet = (struct batadv_bcast_packet *)skb->data;
 
@@ -1478,9 +1566,9 @@ int batadv_bla_check_bcast_duplist(struct batadv_priv *bat_priv,
                        continue;
 
                /* 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;
        }
        /* 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,
  * @orig_node: the orig_node 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
- * it returns 0.
+ * Return: true if the orig_node is also a gateway on the soft interface,
+ * otherwise it returns false.
  */
-int batadv_bla_is_backbone_gw(struct sk_buff *skb,
-                             struct batadv_orig_node *orig_node, int hdr_size)
+bool batadv_bla_is_backbone_gw(struct sk_buff *skb,
+                              struct batadv_orig_node *orig_node, int hdr_size)
 {
        struct batadv_bla_backbone_gw *backbone_gw;
        unsigned short vid;
 
        if (!atomic_read(&orig_node->bat_priv->bridge_loop_avoidance))
-               return 0;
+               return false;
 
        /* first, find out the vid. */
        if (!pskb_may_pull(skb, hdr_size + ETH_HLEN))
-               return 0;
+               return false;
 
        vid = batadv_get_vid(skb, hdr_size);
 
@@ -1568,10 +1656,10 @@ int batadv_bla_is_backbone_gw(struct sk_buff *skb,
        backbone_gw = batadv_backbone_hash_find(orig_node->bat_priv,
                                                orig_node->orig, vid);
        if (!backbone_gw)
-               return 0;
+               return false;
 
        batadv_backbone_gw_put(backbone_gw);
-       return 1;
+       return true;
 }
 
 /**
@@ -1601,6 +1689,55 @@ void batadv_bla_free(struct batadv_priv *bat_priv)
                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.
  * @bat_priv: the bat priv with all the soft interface information
@@ -1614,16 +1751,16 @@ void batadv_bla_free(struct batadv_priv *bat_priv)
  *
  * in these cases, the skb is further handled by this function
  *
- * Return: 1 if handled, otherwise it returns 0 and the caller shall further
- * process the skb.
+ * Return: true if handled, otherwise it returns false and the caller shall
+ * further process the skb.
  */
-int batadv_bla_rx(struct batadv_priv *bat_priv, struct sk_buff *skb,
-                 unsigned short vid, bool is_bcast)
+bool batadv_bla_rx(struct batadv_priv *bat_priv, struct sk_buff *skb,
+                  unsigned short vid, bool is_bcast)
 {
        struct ethhdr *ethhdr;
        struct batadv_bla_claim search_claim, *claim = NULL;
        struct batadv_hard_iface *primary_if;
-       int ret;
+       bool ret;
 
        ethhdr = eth_hdr(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))
                goto allow;
 
+       if (batadv_bla_loopdetect_check(bat_priv, skb, primary_if, vid))
+               goto handled;
+
        if (unlikely(atomic_read(&bat_priv->bla.num_requests)))
                /* don't allow broadcasts while requests are in flight */
                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,
        }
 allow:
        batadv_bla_update_own_backbone_gw(bat_priv, primary_if, vid);
-       ret = 0;
+       ret = false;
        goto out;
 
 handled:
        kfree_skb(skb);
-       ret = 1;
+       ret = true;
 
 out:
        if (primary_if)
@@ -1711,16 +1851,16 @@ out:
  *
  * This call might reallocate skb data.
  *
- * Return: 1 if handled, otherwise it returns 0 and the caller shall further
- * process the skb.
+ * Return: true if handled, otherwise it returns false and the caller shall
+ * further process the skb.
  */
-int batadv_bla_tx(struct batadv_priv *bat_priv, struct sk_buff *skb,
-                 unsigned short vid)
+bool batadv_bla_tx(struct batadv_priv *bat_priv, struct sk_buff *skb,
+                  unsigned short vid)
 {
        struct ethhdr *ethhdr;
        struct batadv_bla_claim search_claim, *claim = NULL;
        struct batadv_hard_iface *primary_if;
-       int ret = 0;
+       bool ret = false;
 
        primary_if = batadv_primary_if_get_selected(bat_priv);
        if (!primary_if)
@@ -1774,10 +1914,10 @@ int batadv_bla_tx(struct batadv_priv *bat_priv, struct sk_buff *skb,
        }
 allow:
        batadv_bla_update_own_backbone_gw(bat_priv, primary_if, vid);
-       ret = 0;
+       ret = false;
        goto out;
 handled:
-       ret = 1;
+       ret = true;
 out:
        if (primary_if)
                batadv_hardif_put(primary_if);
index 579f0fa6fe6a47c7fd1c7bba73dd4496cec24ca7..0f01daeb359e74ae2f69ae678e97a4c09c767511 100644 (file)
@@ -27,19 +27,20 @@ struct seq_file;
 struct sk_buff;
 
 #ifdef CONFIG_BATMAN_ADV_BLA
-int batadv_bla_rx(struct batadv_priv *bat_priv, struct sk_buff *skb,
-                 unsigned short vid, bool is_bcast);
-int batadv_bla_tx(struct batadv_priv *bat_priv, struct sk_buff *skb,
-                 unsigned short vid);
-int batadv_bla_is_backbone_gw(struct sk_buff *skb,
-                             struct batadv_orig_node *orig_node, int hdr_size);
+bool batadv_bla_rx(struct batadv_priv *bat_priv, struct sk_buff *skb,
+                  unsigned short vid, bool is_bcast);
+bool batadv_bla_tx(struct batadv_priv *bat_priv, struct sk_buff *skb,
+                  unsigned short vid);
+bool batadv_bla_is_backbone_gw(struct sk_buff *skb,
+                              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_backbone_table_seq_print_text(struct seq_file *seq,
                                             void *offset);
 bool batadv_bla_is_backbone_gw_orig(struct batadv_priv *bat_priv, u8 *orig,
                                    unsigned short vid);
-int batadv_bla_check_bcast_duplist(struct batadv_priv *bat_priv,
-                                  struct sk_buff *skb);
+bool batadv_bla_check_bcast_duplist(struct batadv_priv *bat_priv,
+                                   struct sk_buff *skb);
 void batadv_bla_update_orig_address(struct batadv_priv *bat_priv,
                                    struct batadv_hard_iface *primary_if,
                                    struct batadv_hard_iface *oldif);
@@ -50,24 +51,24 @@ void batadv_bla_free(struct batadv_priv *bat_priv);
 #define BATADV_BLA_CRC_INIT    0
 #else /* ifdef CONFIG_BATMAN_ADV_BLA */
 
-static inline int batadv_bla_rx(struct batadv_priv *bat_priv,
-                               struct sk_buff *skb, unsigned short vid,
-                               bool is_bcast)
+static inline bool batadv_bla_rx(struct batadv_priv *bat_priv,
+                                struct sk_buff *skb, unsigned short vid,
+                                bool is_bcast)
 {
-       return 0;
+       return false;
 }
 
-static inline int batadv_bla_tx(struct batadv_priv *bat_priv,
-                               struct sk_buff *skb, unsigned short vid)
+static inline bool batadv_bla_tx(struct batadv_priv *bat_priv,
+                                struct sk_buff *skb, unsigned short vid)
 {
-       return 0;
+       return false;
 }
 
-static inline int batadv_bla_is_backbone_gw(struct sk_buff *skb,
-                                           struct batadv_orig_node *orig_node,
-                                           int hdr_size)
+static inline bool batadv_bla_is_backbone_gw(struct sk_buff *skb,
+                                            struct batadv_orig_node *orig_node,
+                                            int hdr_size)
 {
-       return 0;
+       return false;
 }
 
 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,
        return false;
 }
 
-static inline int
+static inline bool
 batadv_bla_check_bcast_duplist(struct batadv_priv *bat_priv,
                               struct sk_buff *skb)
 {
-       return 0;
+       return false;
 }
 
 static inline void
index aa315da83429f51e612c2f992c58c4db8e5b4a05..952900466d8829bc158357ea06caf9432718c0c9 100644 (file)
@@ -134,7 +134,7 @@ static int batadv_log_release(struct inode *inode, struct file *file)
        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);
 }
index 67f44f5d630b0d4e59034995ca260a91422e1443..278800a99c69458c083da635bd39bcd19e788842 100644 (file)
@@ -165,14 +165,14 @@ static void batadv_dat_purge(struct work_struct *work)
  * @node: node in the local table
  * @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,
                                         hash_entry);
 
-       return memcmp(data1, data2, sizeof(__be32)) == 0 ? 1 : 0;
+       return memcmp(data1, data2, sizeof(__be32)) == 0;
 }
 
 /**
index c59aff5ccac8a63f191a669eafcfdba7a270fd75..5839c569f769ef7137fca9b92915799b78e21123 100644 (file)
@@ -135,8 +135,8 @@ static void batadv_gw_select(struct batadv_priv *bat_priv,
 
        spin_lock_bh(&bat_priv->gw.list_lock);
 
-       if (new_gw_node && !kref_get_unless_zero(&new_gw_node->refcount))
-               new_gw_node = NULL;
+       if (new_gw_node)
+               kref_get(&new_gw_node->refcount);
 
        curr_gw_node = rcu_dereference_protected(bat_priv->gw.curr_gw, 1);
        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,
        if (gateway->bandwidth_down == 0)
                return;
 
-       if (!kref_get_unless_zero(&orig_node->refcount))
-               return;
-
        gw_node = kzalloc(sizeof(*gw_node), GFP_ATOMIC);
-       if (!gw_node) {
-               batadv_orig_node_put(orig_node);
+       if (!gw_node)
                return;
-       }
 
+       kref_get(&orig_node->refcount);
        INIT_HLIST_NODE(&gw_node->list);
        gw_node->orig_node = orig_node;
        gw_node->bandwidth_down = ntohl(gateway->bandwidth_down);
index 0a7deaf2670a981078d0c5c3de1805f69c265796..8c2f39962fa591ab02afacb2338feaefd698779f 100644 (file)
@@ -36,7 +36,6 @@
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/workqueue.h>
-#include <net/net_namespace.h>
 
 #include "bridge_loop_avoidance.h"
 #include "debugfs.h"
@@ -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)
 {
        struct net_device *parent_dev;
+       struct net *net = dev_net(net_dev);
        bool ret;
 
        /* 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)
                return false;
 
        /* 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 (WARN(!parent_dev, "Cannot find parent device"))
                return false;
@@ -146,22 +146,22 @@ static bool batadv_is_on_batman_iface(const struct net_device *net_dev)
        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)
-               return 0;
+               return false;
 
        if (net_dev->type != ARPHRD_ETHER)
-               return 0;
+               return false;
 
        if (net_dev->addr_len != ETH_ALEN)
-               return 0;
+               return false;
 
        /* no batman over batman */
        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,
 
        ASSERT_RTNL();
 
-       if (new_hard_iface && !kref_get_unless_zero(&new_hard_iface->refcount))
-               new_hard_iface = NULL;
+       if (new_hard_iface)
+               kref_get(&new_hard_iface->refcount);
 
        curr_hard_iface = rcu_dereference_protected(bat_priv->primary_if, 1);
        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,
 }
 
 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 net_device *soft_iface, *master;
@@ -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)
                goto out;
 
-       if (!kref_get_unless_zero(&hard_iface->refcount))
-               goto out;
+       kref_get(&hard_iface->refcount);
 
-       soft_iface = dev_get_by_name(&init_net, iface_name);
+       soft_iface = dev_get_by_name(net, iface_name);
 
        if (!soft_iface) {
-               soft_iface = batadv_softif_create(iface_name);
+               soft_iface = batadv_softif_create(net, iface_name);
 
                if (!soft_iface) {
                        ret = -ENOMEM;
@@ -522,6 +521,7 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface,
                goto err_upper;
        }
 
+       kref_get(&hard_iface->refcount);
        hard_iface->batman_adv_ptype.type = ethertype;
        hard_iface->batman_adv_ptype.func = batadv_batman_skb_recv;
        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,
        batadv_info(hard_iface->soft_iface, "Removing interface: %s\n",
                    hard_iface->net_dev->name);
        dev_remove_pack(&hard_iface->batman_adv_ptype);
+       batadv_hardif_put(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)
 
        ASSERT_RTNL();
 
-       ret = batadv_is_valid_iface(net_dev);
-       if (ret != 1)
+       if (!batadv_is_valid_iface(net_dev))
                goto out;
 
        dev_hold(net_dev);
index d74f1983f33e1d430dbc332da510f6d24247aab7..a76724d369bfda14a772b56af2bff2b9cb836e80 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/types.h>
 
 struct net_device;
+struct net;
 
 enum batadv_hard_if_state {
        BATADV_IF_NOT_IN_USE,
@@ -55,7 +56,7 @@ bool batadv_is_wifi_iface(int ifindex);
 struct batadv_hard_iface*
 batadv_hardif_get_by_netdev(const struct net_device *net_dev);
 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,
                                     enum batadv_hard_if_cleanup autodel);
 void batadv_hardif_remove_interfaces(void);
index 9bb57b87447cc0ca43c8c9bf31625c3a1f00303c..cbbf87075f06fc7c68103a9a65147748b706e40b 100644 (file)
@@ -32,10 +32,10 @@ struct lock_class_key;
 /* callback to a compare function.  should compare 2 element datas for their
  * 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 *,
-                                         const void *);
+typedef bool (*batadv_hashdata_compare_cb)(const struct hlist_node *,
+                                          const void *);
 
 /* the hashfunction
  *
index 78c05a91ae6fa62a0d898b5316c2312aabfb4044..5f2974bd1227f32301dc607039d3271add649281 100644 (file)
@@ -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,
                                  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 was released by skb_share_check() */
        if (!skb)
-               goto err_out;
+               goto err_put;
 
        /* packet should hold at least type and version */
        if (unlikely(!pskb_may_pull(skb, 2)))
@@ -448,6 +456,8 @@ int batadv_batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
        if (ret == NET_RX_DROP)
                kfree_skb(skb);
 
+       batadv_hardif_put(hard_iface);
+
        /* return NET_RX_SUCCESS in any case as we
         * most probably dropped the packet for
         * routing-logical reasons.
@@ -456,6 +466,8 @@ int batadv_batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
 
 err_free:
        kfree_skb(skb);
+err_put:
+       batadv_hardif_put(hard_iface);
 err_out:
        return NET_RX_DROP;
 }
@@ -736,9 +748,7 @@ batadv_tvlv_container_get(struct batadv_priv *bat_priv, u8 type, u8 version)
                if (tvlv_tmp->tvlv_hdr.version != version)
                        continue;
 
-               if (!kref_get_unless_zero(&tvlv_tmp->refcount))
-                       continue;
-
+               kref_get(&tvlv_tmp->refcount);
                tvlv = tvlv_tmp;
                break;
        }
index 07a6042d0ad6f64b835cc50e01ad0e08c0b4c61f..76925266deed1b572e1afd796b3df9cdef56d8a1 100644 (file)
 #define BATADV_BLA_BACKBONE_TIMEOUT    (BATADV_BLA_PERIOD_LENGTH * 6)
 #define BATADV_BLA_CLAIM_TIMEOUT       (BATADV_BLA_PERIOD_LENGTH * 10)
 #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_TIMEOUT         500     /* 500 ms */
@@ -142,10 +144,12 @@ enum batadv_uev_action {
        BATADV_UEV_ADD = 0,
        BATADV_UEV_DEL,
        BATADV_UEV_CHANGE,
+       BATADV_UEV_LOOPDETECT,
 };
 
 enum batadv_uev_type {
        BATADV_UEV_GW = 0,
+       BATADV_UEV_BLA,
 };
 
 #define BATADV_GW_THRESHOLD    50
@@ -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
  *
- * 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)
 {
index 1da8e0e1b18fd8c324494b7f1468534d8c2c9c6d..678f0686531254ba057490c479e9f6e1ad74c7b1 100644 (file)
@@ -510,10 +510,10 @@ static u32 batadv_nc_hash_choose(const void *data, u32 size)
  * @node: node in the local table
  * @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,
-                                 const void *data2)
+static bool batadv_nc_hash_compare(const struct hlist_node *node,
+                                  const void *data2)
 {
        const struct batadv_nc_path *nc_path1, *nc_path2;
 
@@ -521,15 +521,13 @@ static int batadv_nc_hash_compare(const struct hlist_node *node,
        nc_path2 = data2;
 
        /* Return 1 if the two keys are identical */
-       if (memcmp(nc_path1->prev_hop, nc_path2->prev_hop,
-                  sizeof(nc_path1->prev_hop)) != 0)
-               return 0;
+       if (!batadv_compare_eth(nc_path1->prev_hop, nc_path2->prev_hop))
+               return false;
 
-       if (memcmp(nc_path1->next_hop, nc_path2->next_hop,
-                  sizeof(nc_path1->next_hop)) != 0)
-               return 0;
+       if (!batadv_compare_eth(nc_path1->next_hop, nc_path2->next_hop))
+               return false;
 
-       return 1;
+       return true;
 }
 
 /**
@@ -856,8 +854,7 @@ batadv_nc_get_nc_node(struct batadv_priv *bat_priv,
        if (!nc_node)
                return NULL;
 
-       if (!kref_get_unless_zero(&orig_neigh_node->refcount))
-               goto free;
+       kref_get(&orig_neigh_node->refcount);
 
        /* Initialize nc_node */
        INIT_LIST_HEAD(&nc_node->list);
@@ -884,10 +881,6 @@ batadv_nc_get_nc_node(struct batadv_priv *bat_priv,
        spin_unlock_bh(lock);
 
        return nc_node;
-
-free:
-       kfree(nc_node);
-       return NULL;
 }
 
 /**
index f885a41d06d53c290387dd8bf43316322ecf8d5d..1ff4ee473966d23328ee0dbb926cbb72945e6a99 100644 (file)
@@ -54,9 +54,9 @@ static void batadv_purge_orig(struct work_struct *work);
  * @node: node in the local table
  * @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,
                                         hash_entry);
@@ -374,12 +374,8 @@ batadv_orig_ifinfo_new(struct batadv_orig_node *orig_node,
        if (!orig_ifinfo)
                goto out;
 
-       if (if_outgoing != BATADV_IF_DEFAULT &&
-           !kref_get_unless_zero(&if_outgoing->refcount)) {
-               kfree(orig_ifinfo);
-               orig_ifinfo = NULL;
-               goto out;
-       }
+       if (if_outgoing != BATADV_IF_DEFAULT)
+               kref_get(&if_outgoing->refcount);
 
        reset_time = jiffies - 1;
        reset_time -= msecs_to_jiffies(BATADV_RESET_PROTECTION_MS);
@@ -455,11 +451,8 @@ batadv_neigh_ifinfo_new(struct batadv_neigh_node *neigh,
        if (!neigh_ifinfo)
                goto out;
 
-       if (if_outgoing && !kref_get_unless_zero(&if_outgoing->refcount)) {
-               kfree(neigh_ifinfo);
-               neigh_ifinfo = NULL;
-               goto out;
-       }
+       if (if_outgoing)
+               kref_get(&if_outgoing->refcount);
 
        INIT_HLIST_NODE(&neigh_ifinfo->list);
        kref_init(&neigh_ifinfo->refcount);
@@ -532,15 +525,11 @@ batadv_hardif_neigh_create(struct batadv_hard_iface *hard_iface,
        if (hardif_neigh)
                goto out;
 
-       if (!kref_get_unless_zero(&hard_iface->refcount))
-               goto out;
-
        hardif_neigh = kzalloc(sizeof(*hardif_neigh), GFP_ATOMIC);
-       if (!hardif_neigh) {
-               batadv_hardif_put(hard_iface);
+       if (!hardif_neigh)
                goto out;
-       }
 
+       kref_get(&hard_iface->refcount);
        INIT_HLIST_NODE(&hardif_neigh->list);
        ether_addr_copy(hardif_neigh->addr, neigh_addr);
        hardif_neigh->if_incoming = hard_iface;
@@ -643,16 +632,11 @@ batadv_neigh_node_new(struct batadv_orig_node *orig_node,
        if (!neigh_node)
                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_HEAD(&neigh_node->ifinfo_list);
        spin_lock_init(&neigh_node->ifinfo_lock);
 
+       kref_get(&hard_iface->refcount);
        ether_addr_copy(neigh_node->addr, neigh_addr);
        neigh_node->if_incoming = hard_iface;
        neigh_node->orig_node = orig_node;
@@ -1160,6 +1144,9 @@ static bool batadv_purge_orig_node(struct batadv_priv *bat_priv,
                if (hard_iface->soft_iface != bat_priv->soft_iface)
                        continue;
 
+               if (!kref_get_unless_zero(&hard_iface->refcount))
+                       continue;
+
                best_neigh_node = batadv_find_best_neighbor(bat_priv,
                                                            orig_node,
                                                            hard_iface);
@@ -1167,6 +1154,8 @@ static bool batadv_purge_orig_node(struct batadv_priv *bat_priv,
                                    best_neigh_node);
                if (best_neigh_node)
                        batadv_neigh_node_put(best_neigh_node);
+
+               batadv_hardif_put(hard_iface);
        }
        rcu_read_unlock();
 
index 4e8b67f110511302b42add7d5aa517510b6f7380..64a8951e58446fc11974622ab59b3b6a2d78dc34 100644 (file)
@@ -33,7 +33,7 @@
 
 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);
 void batadv_originator_free(struct batadv_priv *bat_priv);
 void batadv_purge_orig_ref(struct batadv_priv *bat_priv);
index 0796dfdfbb60d7715373db79d69f78b1b300289a..372128ddb474de09b8e60538f499a8bf5d463c9c 100644 (file)
@@ -175,6 +175,7 @@ enum batadv_bla_claimframe {
        BATADV_CLAIM_TYPE_UNCLAIM       = 0x01,
        BATADV_CLAIM_TYPE_ANNOUNCE      = 0x02,
        BATADV_CLAIM_TYPE_REQUEST       = 0x03,
+       BATADV_CLAIM_TYPE_LOOPDETECT    = 0x04,
 };
 
 /**
index b781bf75325061a5157c54bc976d1df1a522e0bd..ae850f2d11cba30230a2d6ed881c3b2ab3c245f1 100644 (file)
@@ -100,10 +100,6 @@ static void _batadv_update_route(struct batadv_priv *bat_priv,
        if (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);
        /* curr_router used earlier may not be the current orig_ifinfo->router
         * 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,
         */
        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);
        spin_unlock_bh(&orig_node->neigh_list_lock);
        batadv_orig_ifinfo_put(orig_ifinfo);
@@ -163,18 +163,18 @@ out:
  *   doesn't change otherwise.
  *
  * Return:
- *  0 if the packet is to be accepted.
- *  1 if the packet is to be ignored.
+ *  false if the packet is to be accepted.
+ *  true if the packet is to be ignored.
  */
-int batadv_window_protected(struct batadv_priv *bat_priv, s32 seq_num_diff,
-                           s32 seq_old_max_diff, unsigned long *last_reset,
-                           bool *protection_started)
+bool batadv_window_protected(struct batadv_priv *bat_priv, s32 seq_num_diff,
+                            s32 seq_old_max_diff, unsigned long *last_reset,
+                            bool *protection_started)
 {
        if (seq_num_diff <= -seq_old_max_diff ||
            seq_num_diff >= BATADV_EXPECTED_SEQNO_RANGE) {
                if (!batadv_has_timed_out(*last_reset,
                                          BATADV_RESET_PROTECTION_MS))
-                       return 1;
+                       return true;
 
                *last_reset = jiffies;
                if (protection_started)
@@ -183,7 +183,7 @@ int batadv_window_protected(struct batadv_priv *bat_priv, s32 seq_num_diff,
                           "old packet received, start protection\n");
        }
 
-       return 0;
+       return false;
 }
 
 bool batadv_check_management_packet(struct sk_buff *skb,
@@ -718,8 +718,9 @@ out:
        return ret;
 }
 
-static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv,
-                                    struct sk_buff *skb, int hdr_len) {
+static bool batadv_check_unicast_ttvn(struct batadv_priv *bat_priv,
+                                     struct sk_buff *skb, int hdr_len)
+{
        struct batadv_unicast_packet *unicast_packet;
        struct batadv_hard_iface *primary_if;
        struct batadv_orig_node *orig_node;
@@ -730,11 +731,11 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv,
 
        /* check if there is enough data before accessing it */
        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. */
        if (skb_cow(skb, sizeof(*unicast_packet)) < 0)
-               return 0;
+               return false;
 
        unicast_packet = (struct batadv_unicast_packet *)skb->data;
        vid = batadv_get_vid(skb, hdr_len);
@@ -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
                 * there is nothing the node can do
                 */
-               return 1;
+               return true;
        }
 
        /* 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,
                 * not be possible to deliver it
                 */
                if (!orig_node)
-                       return 0;
+                       return false;
 
                curr_ttvn = (u8)atomic_read(&orig_node->last_ttvn);
                batadv_orig_node_put(orig_node);
@@ -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);
        if (!is_old_ttvn)
-               return 1;
+               return true;
 
        old_ttvn = unicast_packet->ttvn;
        /* 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,
                                       "Rerouting unicast packet to %pM (dst=%pM): TTVN mismatch old_ttvn=%u new_ttvn=%u\n",
                                       unicast_packet->dest, ethhdr->h_dest,
                                       old_ttvn, curr_ttvn);
-               return 1;
+               return true;
        }
 
        /* 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,
         * it is possible to drop the packet
         */
        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
         * node's soft interface
         */
        primary_if = batadv_primary_if_get_selected(bat_priv);
        if (!primary_if)
-               return 0;
+               return false;
 
        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,
 
        unicast_packet->ttvn = curr_ttvn;
 
-       return 1;
+       return true;
 }
 
 /**
@@ -912,7 +913,7 @@ int batadv_recv_unicast_packet(struct sk_buff *skb,
                                                        hdr_size))
                        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);
 
 rx_success:
@@ -1122,8 +1123,7 @@ int batadv_recv_bcast_packet(struct sk_buff *skb,
                goto rx_success;
 
        /* broadcast for me */
-       batadv_interface_rx(recv_if->soft_iface, skb, recv_if, hdr_size,
-                           orig_node);
+       batadv_interface_rx(recv_if->soft_iface, skb, hdr_size, orig_node);
 
 rx_success:
        ret = NET_RX_SUCCESS;
index 02a5caa84127e4dc2ffb4b675cb76486bda075b0..05c3ff42e1816743989ad0c6ed4bc6eea943e448 100644 (file)
@@ -51,8 +51,8 @@ struct batadv_neigh_node *
 batadv_find_router(struct batadv_priv *bat_priv,
                   struct batadv_orig_node *orig_node,
                   struct batadv_hard_iface *recv_if);
-int batadv_window_protected(struct batadv_priv *bat_priv, s32 seq_num_diff,
-                           s32 seq_old_max_diff, unsigned long *last_reset,
-                           bool *protection_started);
+bool batadv_window_protected(struct batadv_priv *bat_priv, s32 seq_num_diff,
+                            s32 seq_old_max_diff, unsigned long *last_reset,
+                            bool *protection_started);
 
 #endif /* _NET_BATMAN_ADV_ROUTING_H_ */
index 99ea9001cf8aa8aac34b9503df7e489ab4fbc005..f2f125684ed9c199e1c4f7f7b3b6109b3b9a51c2 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/if.h>
 #include <linux/jiffies.h>
 #include <linux/kernel.h>
+#include <linux/kref.h>
 #include <linux/list.h>
 #include <linux/netdevice.h>
 #include <linux/printk.h>
@@ -577,10 +578,15 @@ static void batadv_send_outstanding_bcast_packet(struct work_struct *work)
                if (forw_packet->num_packets >= hard_iface->num_bcasts)
                        continue;
 
+               if (!kref_get_unless_zero(&hard_iface->refcount))
+                       continue;
+
                /* send a copy of the saved skb */
                skb1 = skb_clone(forw_packet->skb, GFP_ATOMIC);
                if (skb1)
                        batadv_send_broadcast_skb(skb1, hard_iface);
+
+               batadv_hardif_put(hard_iface);
        }
        rcu_read_unlock();
 
index dfb4d56120b696bffd870aab9b3cdde364cc32f5..343d2c90439928cfd986654de265eeb10ca9a10a 100644 (file)
@@ -186,7 +186,6 @@ static int batadv_interface_tx(struct sk_buff *skb,
        struct batadv_priv *bat_priv = netdev_priv(soft_iface);
        struct batadv_hard_iface *primary_if = NULL;
        struct batadv_bcast_packet *bcast_packet;
-       __be16 ethertype = htons(ETH_P_BATMAN);
        static const u8 stp_addr[ETH_ALEN] = {0x01, 0x80, 0xC2, 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,
        case ETH_P_8021Q:
                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;
                        break;
                }
@@ -385,7 +385,6 @@ end:
  * batadv_interface_rx - receive ethernet frame on local batman-adv interface
  * @soft_iface: local interface which will receive the ethernet frame
  * @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
  * @orig_node: originator from which the batman-adv packet was sent
  *
@@ -400,12 +399,11 @@ end:
  * isolated clients.
  */
 void batadv_interface_rx(struct net_device *soft_iface,
-                        struct sk_buff *skb, struct batadv_hard_iface *recv_if,
-                        int hdr_size, struct batadv_orig_node *orig_node)
+                        struct sk_buff *skb, int hdr_size,
+                        struct batadv_orig_node *orig_node)
 {
        struct batadv_bcast_packet *batadv_bcast_packet;
        struct batadv_priv *bat_priv = netdev_priv(soft_iface);
-       __be16 ethertype = htons(ETH_P_BATMAN);
        struct vlan_ethhdr *vhdr;
        struct ethhdr *ethhdr;
        unsigned short vid;
@@ -414,10 +412,6 @@ void batadv_interface_rx(struct net_device *soft_iface,
        batadv_bcast_packet = (struct batadv_bcast_packet *)skb->data;
        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_reset_mac_header(skb);
 
@@ -439,7 +433,8 @@ void batadv_interface_rx(struct net_device *soft_iface,
 
                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;
 
                /* fall through */
@@ -890,13 +885,14 @@ static int batadv_softif_slave_add(struct net_device *dev,
                                   struct net_device *slave_dev)
 {
        struct batadv_hard_iface *hard_iface;
+       struct net *net = dev_net(dev);
        int ret = -EINVAL;
 
        hard_iface = batadv_hardif_get_by_netdev(slave_dev);
        if (!hard_iface || hard_iface->soft_iface)
                goto out;
 
-       ret = batadv_hardif_enable_interface(hard_iface, dev->name);
+       ret = batadv_hardif_enable_interface(hard_iface, net, dev->name);
 
 out:
        if (hard_iface)
@@ -977,7 +973,7 @@ static void batadv_softif_init_early(struct net_device *dev)
 
        dev->netdev_ops = &batadv_netdev_ops;
        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;
 
        /* can't call min_mtu, because the needed variables
@@ -993,7 +989,7 @@ static void batadv_softif_init_early(struct net_device *dev)
        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;
        int ret;
@@ -1003,6 +999,8 @@ struct net_device *batadv_softif_create(const char *name)
        if (!soft_iface)
                return NULL;
 
+       dev_net_set(soft_iface, net);
+
        soft_iface->rtnl_link_ops = &batadv_link_ops;
 
        ret = register_netdevice(soft_iface);
@@ -1047,12 +1045,12 @@ static void batadv_softif_destroy_netlink(struct net_device *soft_iface,
        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)
-               return 1;
+               return true;
 
-       return 0;
+       return false;
 }
 
 struct rtnl_link_ops batadv_link_ops __read_mostly = {
index 9ae265703d237462541b356b6cacaa47774c27ba..ec303ddbf647828947f8c83c7edde06582735ad6 100644 (file)
 
 #include "main.h"
 
+#include <linux/types.h>
 #include <net/rtnetlink.h>
 
 struct net_device;
+struct net;
 struct sk_buff;
 
 int batadv_skb_head_push(struct sk_buff *skb, unsigned int len);
 void batadv_interface_rx(struct net_device *soft_iface,
-                        struct sk_buff *skb, struct batadv_hard_iface *recv_if,
-                        int hdr_size, struct batadv_orig_node *orig_node);
-struct net_device *batadv_softif_create(const char *name);
+                        struct sk_buff *skb, int hdr_size,
+                        struct batadv_orig_node *orig_node);
+struct net_device *batadv_softif_create(struct net *net, const char *name);
 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;
 int batadv_softif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid);
 void batadv_softif_vlan_put(struct batadv_softif_vlan *softif_vlan);
index e7cf51333a36455b6288f3c1b029eb3a187939d5..414b2074165f3368d1cd307ad72c477b2489c6d7 100644 (file)
@@ -116,11 +116,13 @@ batadv_kobj_to_vlan(struct batadv_priv *bat_priv, struct kobject *obj)
 static char *batadv_uev_action_str[] = {
        "add",
        "del",
-       "change"
+       "change",
+       "loopdetect",
 };
 
 static char *batadv_uev_type_str[] = {
-       "gw"
+       "gw",
+       "bla",
 };
 
 /* 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,
                                       size_t count)
 {
        struct net_device *net_dev = batadv_kobj_to_netdev(kobj);
+       struct net *net = dev_net(net_dev);
        struct batadv_hard_iface *hard_iface;
        int status_tmp = -1;
        int ret = count;
@@ -873,7 +876,7 @@ static ssize_t batadv_store_mesh_iface(struct kobject *kobj,
                batadv_hardif_disable_interface(hard_iface,
                                                BATADV_IF_CLEANUP_AUTO);
 
-       ret = batadv_hardif_enable_interface(hard_iface, buff);
+       ret = batadv_hardif_enable_interface(hard_iface, net, buff);
 
 unlock:
        rtnl_unlock();
index 942b3aa00bedd34c8e7f11954784c4827a7785f7..feaf492b01ca011b221fbfb74bba295da794ac15 100644 (file)
@@ -43,7 +43,6 @@
 #include <linux/stddef.h>
 #include <linux/string.h>
 #include <linux/workqueue.h>
-#include <net/net_namespace.h>
 
 #include "bridge_loop_avoidance.h"
 #include "hard-interface.h"
@@ -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
  * 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,
                                         hash_entry);
@@ -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_tt_local_entry *tt_local;
        struct batadv_tt_global_entry *tt_global = NULL;
+       struct net *net = dev_net(soft_iface);
        struct batadv_softif_vlan *vlan;
        struct net_device *in_dev = NULL;
        struct hlist_head *head;
@@ -596,7 +596,7 @@ bool batadv_tt_local_add(struct net_device *soft_iface, const u8 *addr,
        u32 match_mark;
 
        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);
 
@@ -2361,19 +2361,19 @@ unlock:
  * @entry_ptr: to be checked local tt entry
  * @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;
 
        if (tt_common_entry->flags & BATADV_TT_CLIENT_NEW)
-               return 0;
-       return 1;
+               return false;
+       return true;
 }
 
-static int batadv_tt_global_valid(const void *entry_ptr,
-                                 const void *data_ptr)
+static bool batadv_tt_global_valid(const void *entry_ptr,
+                                  const void *data_ptr)
 {
        const struct batadv_tt_common_entry *tt_common_entry = entry_ptr;
        const struct batadv_tt_global_entry *tt_global_entry;
@@ -2381,7 +2381,7 @@ static int batadv_tt_global_valid(const void *entry_ptr,
 
        if (tt_common_entry->flags & BATADV_TT_CLIENT_ROAM ||
            tt_common_entry->flags & BATADV_TT_CLIENT_TEMP)
-               return 0;
+               return false;
 
        tt_global_entry = container_of(tt_common_entry,
                                       struct batadv_tt_global_entry,
@@ -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,
                                    struct batadv_hashtable *hash,
                                    void *tvlv_buff, u16 tt_len,
-                                   int (*valid_cb)(const void *, const void *),
+                                   bool (*valid_cb)(const void *,
+                                                    const void *),
                                    void *cb_data)
 {
        struct batadv_tt_common_entry *tt_common_entry;
@@ -2552,11 +2553,11 @@ static void batadv_tt_global_update_crc(struct batadv_priv *bat_priv,
  *
  * Return: true if the TT Request was sent, false otherwise
  */
-static int batadv_send_tt_request(struct batadv_priv *bat_priv,
-                                 struct batadv_orig_node *dst_orig_node,
-                                 u8 ttvn,
-                                 struct batadv_tvlv_tt_vlan_data *tt_vlan,
-                                 u16 num_vlan, bool full_table)
+static bool batadv_send_tt_request(struct batadv_priv *bat_priv,
+                                  struct batadv_orig_node *dst_orig_node,
+                                  u8 ttvn,
+                                  struct batadv_tvlv_tt_vlan_data *tt_vlan,
+                                  u16 num_vlan, bool full_table)
 {
        struct batadv_tvlv_tt_data *tvlv_tt_data = NULL;
        struct batadv_tt_req_node *tt_req_node = NULL;
index 1e47fbe8bb7b2e9b3ec79c64ef508d7305b5d1a7..6a577f4f8ba77ce1b2b923c55deada8a050802e8 100644 (file)
@@ -657,6 +657,9 @@ struct batadv_priv_tt {
  * @num_requests: number of bla requests in flight
  * @claim_hash: hash table containing mesh nodes this host has claimed
  * @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
  *  duplicate suppression)
  * @bcast_duplist_curr: index of last broadcast packet added to bcast_duplist
@@ -668,6 +671,9 @@ struct batadv_priv_bla {
        atomic_t num_requests;
        struct batadv_hashtable *claim_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];
        int bcast_duplist_curr;
        /* protects bcast_duplist & bcast_duplist_curr */
@@ -1012,6 +1018,7 @@ struct batadv_socket_packet {
  *  resolved
  * @crc: crc16 checksum over all claims
  * @crc_lock: lock protecting crc
+ * @report_work: work struct for reporting detected loops
  * @refcount: number of contexts the object is used
  * @rcu: struct used for freeing in an RCU-safe manner
  */
@@ -1025,6 +1032,7 @@ struct batadv_bla_backbone_gw {
        atomic_t request_sent;
        u16 crc;
        spinlock_t crc_lock; /* protects crc */
+       struct work_struct report_work;
        struct kref refcount;
        struct rcu_head rcu;
 };
This page took 0.105917 seconds and 5 git commands to generate.