Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs
[linux-2.6-block.git] / net / batman-adv / main.c
index 4b5d61fbadb1fb77b2f8484f74abd231dd789346..d64ddb961979ae083ba99907b07fc090a3dfe775 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
  *
@@ -29,6 +29,7 @@
 #include <linux/ip.h>
 #include <linux/ipv6.h>
 #include <linux/kernel.h>
+#include <linux/kref.h>
 #include <linux/list.h>
 #include <linux/lockdep.h>
 #include <linux/module.h>
@@ -86,6 +87,7 @@ static int __init batadv_init(void)
 
        batadv_recv_handler_init();
 
+       batadv_v_init();
        batadv_iv_init();
        batadv_nc_init();
 
@@ -158,6 +160,10 @@ int batadv_mesh_init(struct net_device *soft_iface)
        INIT_HLIST_HEAD(&bat_priv->tvlv.handler_list);
        INIT_HLIST_HEAD(&bat_priv->softif_vlan_list);
 
+       ret = batadv_v_mesh_init(bat_priv);
+       if (ret < 0)
+               goto err;
+
        ret = batadv_originator_init(bat_priv);
        if (ret < 0)
                goto err;
@@ -200,6 +206,8 @@ void batadv_mesh_free(struct net_device *soft_iface)
        batadv_purge_outstanding_packets(bat_priv, NULL);
 
        batadv_gw_node_free(bat_priv);
+
+       batadv_v_mesh_free(bat_priv);
        batadv_nc_mesh_free(bat_priv);
        batadv_dat_free(bat_priv);
        batadv_bla_free(bat_priv);
@@ -233,7 +241,7 @@ void batadv_mesh_free(struct net_device *soft_iface)
  * @bat_priv: the bat priv with all the soft interface information
  * @addr: the address to check
  *
- * Returns 'true' if the mac address was found, false otherwise.
+ * Return: 'true' if the mac address was found, false otherwise.
  */
 bool batadv_is_my_mac(struct batadv_priv *bat_priv, const u8 *addr)
 {
@@ -262,7 +270,7 @@ bool batadv_is_my_mac(struct batadv_priv *bat_priv, const u8 *addr)
  *  function that requires the primary interface
  * @seq: debugfs table seq_file struct
  *
- * Returns primary interface if found or NULL otherwise.
+ * Return: primary interface if found or NULL otherwise.
  */
 struct batadv_hard_iface *
 batadv_seq_print_text_primary_if_get(struct seq_file *seq)
@@ -286,7 +294,7 @@ batadv_seq_print_text_primary_if_get(struct seq_file *seq)
        seq_printf(seq,
                   "BATMAN mesh %s disabled - primary interface not active\n",
                   net_dev->name);
-       batadv_hardif_free_ref(primary_if);
+       batadv_hardif_put(primary_if);
        primary_if = NULL;
 
 out:
@@ -297,7 +305,7 @@ out:
  * batadv_max_header_len - calculate maximum encapsulation overhead for a
  *  payload packet
  *
- * Return the maximum encapsulation overhead in bytes.
+ * Return: the maximum encapsulation overhead in bytes.
  */
 int batadv_max_header_len(void)
 {
@@ -599,6 +607,8 @@ int batadv_algo_seq_print_text(struct seq_file *seq, void *offset)
  *
  * payload_ptr must always point to an address in the skb head buffer and not to
  * a fragment.
+ *
+ * Return: big endian crc32c of the checksummed data
  */
 __be32 batadv_skb_crc32(struct sk_buff *skb, u8 *payload_ptr)
 {
@@ -622,15 +632,26 @@ __be32 batadv_skb_crc32(struct sk_buff *skb, u8 *payload_ptr)
 }
 
 /**
- * batadv_tvlv_handler_free_ref - decrement the tvlv handler refcounter and
- *  possibly free it
+ * batadv_tvlv_handler_release - release tvlv handler from lists and queue for
+ *  free after rcu grace period
+ * @ref: kref pointer of the tvlv
+ */
+static void batadv_tvlv_handler_release(struct kref *ref)
+{
+       struct batadv_tvlv_handler *tvlv_handler;
+
+       tvlv_handler = container_of(ref, struct batadv_tvlv_handler, refcount);
+       kfree_rcu(tvlv_handler, rcu);
+}
+
+/**
+ * batadv_tvlv_handler_put - decrement the tvlv container refcounter and
+ *  possibly release it
  * @tvlv_handler: the tvlv handler to free
  */
-static void
-batadv_tvlv_handler_free_ref(struct batadv_tvlv_handler *tvlv_handler)
+static void batadv_tvlv_handler_put(struct batadv_tvlv_handler *tvlv_handler)
 {
-       if (atomic_dec_and_test(&tvlv_handler->refcount))
-               kfree_rcu(tvlv_handler, rcu);
+       kref_put(&tvlv_handler->refcount, batadv_tvlv_handler_release);
 }
 
 /**
@@ -640,7 +661,7 @@ batadv_tvlv_handler_free_ref(struct batadv_tvlv_handler *tvlv_handler)
  * @type: tvlv handler type to look for
  * @version: tvlv handler version to look for
  *
- * Returns tvlv handler if found or NULL otherwise.
+ * Return: tvlv handler if found or NULL otherwise.
  */
 static struct batadv_tvlv_handler
 *batadv_tvlv_handler_get(struct batadv_priv *bat_priv, u8 type, u8 version)
@@ -656,7 +677,7 @@ static struct batadv_tvlv_handler
                if (tvlv_handler_tmp->version != version)
                        continue;
 
-               if (!atomic_inc_not_zero(&tvlv_handler_tmp->refcount))
+               if (!kref_get_unless_zero(&tvlv_handler_tmp->refcount))
                        continue;
 
                tvlv_handler = tvlv_handler_tmp;
@@ -668,14 +689,25 @@ static struct batadv_tvlv_handler
 }
 
 /**
- * batadv_tvlv_container_free_ref - decrement the tvlv container refcounter and
- *  possibly free it
+ * batadv_tvlv_container_release - release tvlv from lists and free
+ * @ref: kref pointer of the tvlv
+ */
+static void batadv_tvlv_container_release(struct kref *ref)
+{
+       struct batadv_tvlv_container *tvlv;
+
+       tvlv = container_of(ref, struct batadv_tvlv_container, refcount);
+       kfree(tvlv);
+}
+
+/**
+ * batadv_tvlv_container_put - decrement the tvlv container refcounter and
+ *  possibly release it
  * @tvlv: the tvlv container to free
  */
-static void batadv_tvlv_container_free_ref(struct batadv_tvlv_container *tvlv)
+static void batadv_tvlv_container_put(struct batadv_tvlv_container *tvlv)
 {
-       if (atomic_dec_and_test(&tvlv->refcount))
-               kfree(tvlv);
+       kref_put(&tvlv->refcount, batadv_tvlv_container_release);
 }
 
 /**
@@ -688,13 +720,15 @@ static void batadv_tvlv_container_free_ref(struct batadv_tvlv_container *tvlv)
  * Has to be called with the appropriate locks being acquired
  * (tvlv.container_list_lock).
  *
- * Returns tvlv container if found or NULL otherwise.
+ * Return: tvlv container if found or NULL otherwise.
  */
 static struct batadv_tvlv_container
 *batadv_tvlv_container_get(struct batadv_priv *bat_priv, u8 type, u8 version)
 {
        struct batadv_tvlv_container *tvlv_tmp, *tvlv = NULL;
 
+       lockdep_assert_held(&bat_priv->tvlv.container_list_lock);
+
        hlist_for_each_entry(tvlv_tmp, &bat_priv->tvlv.container_list, list) {
                if (tvlv_tmp->tvlv_hdr.type != type)
                        continue;
@@ -702,7 +736,7 @@ static struct batadv_tvlv_container
                if (tvlv_tmp->tvlv_hdr.version != version)
                        continue;
 
-               if (!atomic_inc_not_zero(&tvlv_tmp->refcount))
+               if (!kref_get_unless_zero(&tvlv_tmp->refcount))
                        continue;
 
                tvlv = tvlv_tmp;
@@ -720,13 +754,15 @@ static struct batadv_tvlv_container
  * Has to be called with the appropriate locks being acquired
  * (tvlv.container_list_lock).
  *
- * Returns size of all currently registered tvlv containers in bytes.
+ * Return: size of all currently registered tvlv containers in bytes.
  */
 static u16 batadv_tvlv_container_list_size(struct batadv_priv *bat_priv)
 {
        struct batadv_tvlv_container *tvlv;
        u16 tvlv_len = 0;
 
+       lockdep_assert_held(&bat_priv->tvlv.container_list_lock);
+
        hlist_for_each_entry(tvlv, &bat_priv->tvlv.container_list, list) {
                tvlv_len += sizeof(struct batadv_tvlv_hdr);
                tvlv_len += ntohs(tvlv->tvlv_hdr.len);
@@ -755,8 +791,8 @@ static void batadv_tvlv_container_remove(struct batadv_priv *bat_priv,
        hlist_del(&tvlv->list);
 
        /* first call to decrement the counter, second call to free */
-       batadv_tvlv_container_free_ref(tvlv);
-       batadv_tvlv_container_free_ref(tvlv);
+       batadv_tvlv_container_put(tvlv);
+       batadv_tvlv_container_put(tvlv);
 }
 
 /**
@@ -808,7 +844,7 @@ void batadv_tvlv_container_register(struct batadv_priv *bat_priv,
 
        memcpy(tvlv_new + 1, tvlv_value, ntohs(tvlv_new->tvlv_hdr.len));
        INIT_HLIST_NODE(&tvlv_new->list);
-       atomic_set(&tvlv_new->refcount, 1);
+       kref_init(&tvlv_new->refcount);
 
        spin_lock_bh(&bat_priv->tvlv.container_list_lock);
        tvlv_old = batadv_tvlv_container_get(bat_priv, type, version);
@@ -826,7 +862,7 @@ void batadv_tvlv_container_register(struct batadv_priv *bat_priv,
  * @additional_packet_len: requested additional packet size on top of minimum
  *  size
  *
- * Returns true of the packet buffer could be changed to the requested size,
+ * Return: true of the packet buffer could be changed to the requested size,
  * false otherwise.
  */
 static bool batadv_tvlv_realloc_packet_buff(unsigned char **packet_buff,
@@ -862,7 +898,7 @@ static bool batadv_tvlv_realloc_packet_buff(unsigned char **packet_buff,
  * The ogm packet might be enlarged or shrunk depending on the current size
  * and the size of the to-be-appended tvlv containers.
  *
- * Returns size of all appended tvlv containers in bytes.
+ * Return: size of all appended tvlv containers in bytes.
  */
 u16 batadv_tvlv_container_ogm_append(struct batadv_priv *bat_priv,
                                     unsigned char **packet_buff,
@@ -915,7 +951,7 @@ end:
  * @tvlv_value: tvlv content
  * @tvlv_value_len: tvlv content length
  *
- * Returns success if handler was not found or the return value of the handler
+ * Return: success if handler was not found or the return value of the handler
  * callback.
  */
 static int batadv_tvlv_call_handler(struct batadv_priv *bat_priv,
@@ -968,7 +1004,7 @@ static int batadv_tvlv_call_handler(struct batadv_priv *bat_priv,
  * @tvlv_value: tvlv content
  * @tvlv_value_len: tvlv content length
  *
- * Returns success when processing an OGM or the return value of all called
+ * Return: success when processing an OGM or the return value of all called
  * handler callbacks.
  */
 int batadv_tvlv_containers_process(struct batadv_priv *bat_priv,
@@ -1001,7 +1037,7 @@ int batadv_tvlv_containers_process(struct batadv_priv *bat_priv,
                                                src, dst, tvlv_value,
                                                tvlv_value_cont_len);
                if (tvlv_handler)
-                       batadv_tvlv_handler_free_ref(tvlv_handler);
+                       batadv_tvlv_handler_put(tvlv_handler);
                tvlv_value = (u8 *)tvlv_value + tvlv_value_cont_len;
                tvlv_value_len -= tvlv_value_cont_len;
        }
@@ -1081,7 +1117,7 @@ void batadv_tvlv_handler_register(struct batadv_priv *bat_priv,
 
        tvlv_handler = batadv_tvlv_handler_get(bat_priv, type, version);
        if (tvlv_handler) {
-               batadv_tvlv_handler_free_ref(tvlv_handler);
+               batadv_tvlv_handler_put(tvlv_handler);
                return;
        }
 
@@ -1094,7 +1130,7 @@ void batadv_tvlv_handler_register(struct batadv_priv *bat_priv,
        tvlv_handler->type = type;
        tvlv_handler->version = version;
        tvlv_handler->flags = flags;
-       atomic_set(&tvlv_handler->refcount, 1);
+       kref_init(&tvlv_handler->refcount);
        INIT_HLIST_NODE(&tvlv_handler->list);
 
        spin_lock_bh(&bat_priv->tvlv.handler_list_lock);
@@ -1118,11 +1154,11 @@ void batadv_tvlv_handler_unregister(struct batadv_priv *bat_priv,
        if (!tvlv_handler)
                return;
 
-       batadv_tvlv_handler_free_ref(tvlv_handler);
+       batadv_tvlv_handler_put(tvlv_handler);
        spin_lock_bh(&bat_priv->tvlv.handler_list_lock);
        hlist_del_rcu(&tvlv_handler->list);
        spin_unlock_bh(&bat_priv->tvlv.handler_list_lock);
-       batadv_tvlv_handler_free_ref(tvlv_handler);
+       batadv_tvlv_handler_put(tvlv_handler);
 }
 
 /**
@@ -1182,7 +1218,7 @@ void batadv_tvlv_unicast_send(struct batadv_priv *bat_priv, u8 *src,
        if (batadv_send_skb_to_orig(skb, orig_node, NULL) == NET_XMIT_DROP)
                kfree_skb(skb);
 out:
-       batadv_orig_node_free_ref(orig_node);
+       batadv_orig_node_put(orig_node);
 }
 
 /**
@@ -1190,8 +1226,8 @@ out:
  * @skb: the buffer containing the packet
  * @header_len: length of the batman header preceding the ethernet header
  *
- * If the packet embedded in the skb is vlan tagged this function returns the
- * VID with the BATADV_VLAN_HAS_TAG flag. Otherwise BATADV_NO_FLAGS is returned.
+ * Return: VID with the BATADV_VLAN_HAS_TAG flag when the packet embedded in the
+ * skb is vlan tagged. Otherwise BATADV_NO_FLAGS.
  */
 unsigned short batadv_get_vid(struct sk_buff *skb, size_t header_len)
 {
@@ -1218,7 +1254,7 @@ unsigned short batadv_get_vid(struct sk_buff *skb, size_t header_len)
  * @vid: the VLAN identifier for which the AP isolation attributed as to be
  *  looked up
  *
- * Returns true if AP isolation is on for the VLAN idenfied by vid, false
+ * Return: true if AP isolation is on for the VLAN idenfied by vid, false
  * otherwise
  */
 bool batadv_vlan_ap_isola_get(struct batadv_priv *bat_priv, unsigned short vid)
@@ -1232,7 +1268,7 @@ bool batadv_vlan_ap_isola_get(struct batadv_priv *bat_priv, unsigned short vid)
        vlan = batadv_softif_vlan_get(bat_priv, vid);
        if (vlan) {
                ap_isolation_enabled = atomic_read(&vlan->ap_isolation);
-               batadv_softif_vlan_free_ref(vlan);
+               batadv_softif_vlan_put(vlan);
        }
 
        return ap_isolation_enabled;