Merge tag 'asm-generic-4.6' of git://git.kernel.org/pub/scm/linux/kernel/git/arnd...
[deliverable/linux.git] / net / batman-adv / routing.c
index e4f2646d92463a915b3a52a43b46c6f0736b5e52..b781bf75325061a5157c54bc976d1df1a522e0bd 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2015 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-201 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner, Simon Wunderlich
  *
@@ -25,6 +25,7 @@
 #include <linux/etherdevice.h>
 #include <linux/if_ether.h>
 #include <linux/jiffies.h>
+#include <linux/kref.h>
 #include <linux/netdevice.h>
 #include <linux/printk.h>
 #include <linux/rculist.h>
@@ -72,7 +73,7 @@ static void _batadv_update_route(struct batadv_priv *bat_priv,
 
        rcu_read_lock();
        curr_router = rcu_dereference(orig_ifinfo->router);
-       if (curr_router && !atomic_inc_not_zero(&curr_router->refcount))
+       if (curr_router && !kref_get_unless_zero(&curr_router->refcount))
                curr_router = NULL;
        rcu_read_unlock();
 
@@ -97,20 +98,29 @@ static void _batadv_update_route(struct batadv_priv *bat_priv,
        }
 
        if (curr_router)
-               batadv_neigh_node_free_ref(curr_router);
+               batadv_neigh_node_put(curr_router);
 
        /* increase refcount of new best neighbor */
-       if (neigh_node && !atomic_inc_not_zero(&neigh_node->refcount))
+       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
+        * protected region. After the new best neighbor has replace the current
+        * best neighbor the reference counter needs to decrease. Consequently,
+        * the code needs to ensure the curr_router variable contains a pointer
+        * to the replaced best neighbor.
+        */
+       curr_router = rcu_dereference_protected(orig_ifinfo->router, true);
+
        rcu_assign_pointer(orig_ifinfo->router, neigh_node);
        spin_unlock_bh(&orig_node->neigh_list_lock);
-       batadv_orig_ifinfo_free_ref(orig_ifinfo);
+       batadv_orig_ifinfo_put(orig_ifinfo);
 
        /* decrease refcount of previous best neighbor */
        if (curr_router)
-               batadv_neigh_node_free_ref(curr_router);
+               batadv_neigh_node_put(curr_router);
 }
 
 /**
@@ -137,24 +147,38 @@ void batadv_update_route(struct batadv_priv *bat_priv,
 
 out:
        if (router)
-               batadv_neigh_node_free_ref(router);
+               batadv_neigh_node_put(router);
 }
 
-/* checks whether the host restarted and is in the protection time.
- * returns:
- *  0 if the packet is to be accepted
+/**
+ * batadv_window_protected - checks whether the host restarted and is in the
+ *  protection time.
+ * @bat_priv: the bat priv with all the soft interface information
+ * @seq_num_diff: difference between the current/received sequence number and
+ *  the last sequence number
+ * @seq_old_max_diff: maximum age of sequence number not considered as restart
+ * @last_reset: jiffies timestamp of the last reset, will be updated when reset
+ *  is detected
+ * @protection_started: is set to true if the protection window was started,
+ *   doesn't change otherwise.
+ *
+ * Return:
+ *  0 if the packet is to be accepted.
  *  1 if the packet is to be ignored.
  */
 int batadv_window_protected(struct batadv_priv *bat_priv, s32 seq_num_diff,
-                           unsigned long *last_reset)
+                           s32 seq_old_max_diff, unsigned long *last_reset,
+                           bool *protection_started)
 {
-       if (seq_num_diff <= -BATADV_TQ_LOCAL_WINDOW_SIZE ||
+       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;
 
                *last_reset = jiffies;
+               if (protection_started)
+                       *protection_started = true;
                batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
                           "old packet received, start protection\n");
        }
@@ -198,7 +222,7 @@ bool batadv_check_management_packet(struct sk_buff *skb,
  * @bat_priv: the bat priv with all the soft interface information
  * @skb: icmp packet to process
  *
- * Returns NET_RX_SUCCESS if the packet has been consumed or NET_RX_DROP
+ * Return: NET_RX_SUCCESS if the packet has been consumed or NET_RX_DROP
  * otherwise.
  */
 static int batadv_recv_my_icmp_packet(struct batadv_priv *bat_priv,
@@ -254,9 +278,9 @@ static int batadv_recv_my_icmp_packet(struct batadv_priv *bat_priv,
        }
 out:
        if (primary_if)
-               batadv_hardif_free_ref(primary_if);
+               batadv_hardif_put(primary_if);
        if (orig_node)
-               batadv_orig_node_free_ref(orig_node);
+               batadv_orig_node_put(orig_node);
        return ret;
 }
 
@@ -302,9 +326,9 @@ static int batadv_recv_icmp_ttl_exceeded(struct batadv_priv *bat_priv,
 
 out:
        if (primary_if)
-               batadv_hardif_free_ref(primary_if);
+               batadv_hardif_put(primary_if);
        if (orig_node)
-               batadv_orig_node_free_ref(orig_node);
+               batadv_orig_node_put(orig_node);
        return ret;
 }
 
@@ -388,7 +412,7 @@ int batadv_recv_icmp_packet(struct sk_buff *skb,
 
 out:
        if (orig_node)
-               batadv_orig_node_free_ref(orig_node);
+               batadv_orig_node_put(orig_node);
        return ret;
 }
 
@@ -398,10 +422,11 @@ out:
  * @skb: packet to check
  * @hdr_size: size of header to pull
  *
- * Check for short header and bad addresses in given packet. Returns negative
- * value when check fails and 0 otherwise. The negative value depends on the
- * reason: -ENODATA for bad header, -EBADR for broadcast destination or source,
- * and -EREMOTE for non-local (other host) destination.
+ * Check for short header and bad addresses in given packet.
+ *
+ * Return: negative value when check fails and 0 otherwise. The negative value
+ * depends on the reason: -ENODATA for bad header, -EBADR for broadcast
+ * destination or source, and -EREMOTE for non-local (other host) destination.
  */
 static int batadv_check_unicast_packet(struct batadv_priv *bat_priv,
                                       struct sk_buff *skb, int hdr_size)
@@ -435,7 +460,7 @@ static int batadv_check_unicast_packet(struct batadv_priv *bat_priv,
  * @orig_node: the destination node
  * @recv_if: pointer to interface this packet was received on
  *
- * Returns the router which should be used for this orig_node on
+ * Return: the router which should be used for this orig_node on
  * this interface, or NULL if not available.
  */
 struct batadv_neigh_node *
@@ -482,14 +507,14 @@ batadv_find_router(struct batadv_priv *bat_priv,
 
        hlist_for_each_entry_rcu(cand, &orig_node->ifinfo_list, list) {
                /* acquire some structures and references ... */
-               if (!atomic_inc_not_zero(&cand->refcount))
+               if (!kref_get_unless_zero(&cand->refcount))
                        continue;
 
                cand_router = rcu_dereference(cand->router);
                if (!cand_router)
                        goto next;
 
-               if (!atomic_inc_not_zero(&cand_router->refcount)) {
+               if (!kref_get_unless_zero(&cand_router->refcount)) {
                        cand_router = NULL;
                        goto next;
                }
@@ -508,8 +533,8 @@ batadv_find_router(struct batadv_priv *bat_priv,
 
                /* mark the first possible candidate */
                if (!first_candidate) {
-                       atomic_inc(&cand_router->refcount);
-                       atomic_inc(&cand->refcount);
+                       kref_get(&cand_router->refcount);
+                       kref_get(&cand->refcount);
                        first_candidate = cand;
                        first_candidate_router = cand_router;
                }
@@ -529,16 +554,16 @@ batadv_find_router(struct batadv_priv *bat_priv,
 next:
                /* free references */
                if (cand_router) {
-                       batadv_neigh_node_free_ref(cand_router);
+                       batadv_neigh_node_put(cand_router);
                        cand_router = NULL;
                }
-               batadv_orig_ifinfo_free_ref(cand);
+               batadv_orig_ifinfo_put(cand);
        }
        rcu_read_unlock();
 
        /* last_bonding_candidate is reset below, remove the old reference. */
        if (orig_node->last_bonding_candidate)
-               batadv_orig_ifinfo_free_ref(orig_node->last_bonding_candidate);
+               batadv_orig_ifinfo_put(orig_node->last_bonding_candidate);
 
        /* After finding candidates, handle the three cases:
         * 1) there is a next candidate, use that
@@ -546,17 +571,17 @@ next:
         * 3) there is no candidate at all, return the default router
         */
        if (next_candidate) {
-               batadv_neigh_node_free_ref(router);
+               batadv_neigh_node_put(router);
 
                /* remove references to first candidate, we don't need it. */
                if (first_candidate) {
-                       batadv_neigh_node_free_ref(first_candidate_router);
-                       batadv_orig_ifinfo_free_ref(first_candidate);
+                       batadv_neigh_node_put(first_candidate_router);
+                       batadv_orig_ifinfo_put(first_candidate);
                }
                router = next_candidate_router;
                orig_node->last_bonding_candidate = next_candidate;
        } else if (first_candidate) {
-               batadv_neigh_node_free_ref(router);
+               batadv_neigh_node_put(router);
 
                /* refcounting has already been done in the loop above. */
                router = first_candidate_router;
@@ -633,7 +658,7 @@ static int batadv_route_unicast_packet(struct sk_buff *skb,
 
 out:
        if (orig_node)
-               batadv_orig_node_free_ref(orig_node);
+               batadv_orig_node_put(orig_node);
        return ret;
 }
 
@@ -648,7 +673,7 @@ out:
  * the new corresponding information (originator address where the destination
  * client currently is and its known TTVN)
  *
- * Returns true if the packet header has been updated, false otherwise
+ * Return: true if the packet header has been updated, false otherwise
  */
 static bool
 batadv_reroute_unicast_packet(struct batadv_priv *bat_priv,
@@ -686,9 +711,9 @@ batadv_reroute_unicast_packet(struct batadv_priv *bat_priv,
        ret = true;
 out:
        if (primary_if)
-               batadv_hardif_free_ref(primary_if);
+               batadv_hardif_put(primary_if);
        if (orig_node)
-               batadv_orig_node_free_ref(orig_node);
+               batadv_orig_node_put(orig_node);
 
        return ret;
 }
@@ -752,7 +777,7 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv,
                        return 0;
 
                curr_ttvn = (u8)atomic_read(&orig_node->last_ttvn);
-               batadv_orig_node_free_ref(orig_node);
+               batadv_orig_node_put(orig_node);
        }
 
        /* check if the TTVN contained in the packet is fresher than what the
@@ -792,7 +817,7 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv,
 
        ether_addr_copy(unicast_packet->dest, primary_if->net_dev->dev_addr);
 
-       batadv_hardif_free_ref(primary_if);
+       batadv_hardif_put(primary_if);
 
        unicast_packet->ttvn = curr_ttvn;
 
@@ -805,7 +830,7 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv,
  * @skb: unicast tvlv packet to process
  * @recv_if: pointer to interface this packet was received on
  *
- * Returns NET_RX_SUCCESS if the packet has been consumed or NET_RX_DROP
+ * Return: NET_RX_SUCCESS if the packet has been consumed or NET_RX_DROP
  * otherwise.
  */
 int batadv_recv_unhandled_unicast_packet(struct sk_buff *skb,
@@ -892,7 +917,7 @@ int batadv_recv_unicast_packet(struct sk_buff *skb,
 
 rx_success:
                if (orig_node)
-                       batadv_orig_node_free_ref(orig_node);
+                       batadv_orig_node_put(orig_node);
 
                return NET_RX_SUCCESS;
        }
@@ -904,9 +929,8 @@ rx_success:
  * batadv_recv_unicast_tvlv - receive and process unicast tvlv packets
  * @skb: unicast tvlv packet to process
  * @recv_if: pointer to interface this packet was received on
- * @dst_addr: the payload destination
  *
- * Returns NET_RX_SUCCESS if the packet has been consumed or NET_RX_DROP
+ * Return: NET_RX_SUCCESS if the packet has been consumed or NET_RX_DROP
  * otherwise.
  */
 int batadv_recv_unicast_tvlv(struct sk_buff *skb,
@@ -960,7 +984,7 @@ int batadv_recv_unicast_tvlv(struct sk_buff *skb,
  * the assembled packet will exceed our MTU; 2) Buffer fragment, if we till
  * lack further fragments; 3) Merge fragments, if we have all needed parts.
  *
- * Return NET_RX_DROP if the skb is not consumed, NET_RX_SUCCESS otherwise.
+ * Return: NET_RX_DROP if the skb is not consumed, NET_RX_SUCCESS otherwise.
  */
 int batadv_recv_frag_packet(struct sk_buff *skb,
                            struct batadv_hard_iface *recv_if)
@@ -1004,7 +1028,7 @@ int batadv_recv_frag_packet(struct sk_buff *skb,
 
 out:
        if (orig_node_src)
-               batadv_orig_node_free_ref(orig_node_src);
+               batadv_orig_node_put(orig_node_src);
 
        return ret;
 }
@@ -1065,7 +1089,8 @@ int batadv_recv_bcast_packet(struct sk_buff *skb,
 
        /* check whether the packet is old and the host just restarted. */
        if (batadv_window_protected(bat_priv, seq_diff,
-                                   &orig_node->bcast_seqno_reset))
+                                   BATADV_BCAST_MAX_AGE,
+                                   &orig_node->bcast_seqno_reset, NULL))
                goto spin_unlock;
 
        /* mark broadcast in flood history, update window position
@@ -1108,6 +1133,6 @@ spin_unlock:
        spin_unlock_bh(&orig_node->bcast_seqno_lock);
 out:
        if (orig_node)
-               batadv_orig_node_free_ref(orig_node);
+               batadv_orig_node_put(orig_node);
        return ret;
 }
This page took 0.050134 seconds and 5 git commands to generate.