]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/staging/batman-adv/originator.c
Merge branch 'master' into csb1725
[mv-sheeva.git] / drivers / staging / batman-adv / originator.c
index de5a8c1a810462da1d2f7e8779afd582eb779784..55270080a44bf3de5caffad4eb433267bc0d7e96 100644 (file)
 #include "translation-table.h"
 #include "routing.h"
 #include "hard-interface.h"
+#include "unicast.h"
 
-static DECLARE_DELAYED_WORK(purge_orig_wq, purge_orig);
+static void purge_orig(struct work_struct *work);
 
-static void start_purge_timer(void)
+static void start_purge_timer(struct bat_priv *bat_priv)
 {
-       queue_delayed_work(bat_event_workqueue, &purge_orig_wq, 1 * HZ);
+       INIT_DELAYED_WORK(&bat_priv->orig_work, purge_orig);
+       queue_delayed_work(bat_event_workqueue, &bat_priv->orig_work, 1 * HZ);
 }
 
-int originator_init(void)
+int originator_init(struct bat_priv *bat_priv)
 {
        unsigned long flags;
-       if (orig_hash)
+       if (bat_priv->orig_hash)
                return 1;
 
-       spin_lock_irqsave(&orig_hash_lock, flags);
-       orig_hash = hash_new(128, compare_orig, choose_orig);
+       spin_lock_irqsave(&bat_priv->orig_hash_lock, flags);
+       bat_priv->orig_hash = hash_new(128, compare_orig, choose_orig);
 
-       if (!orig_hash)
+       if (!bat_priv->orig_hash)
                goto err;
 
-       spin_unlock_irqrestore(&orig_hash_lock, flags);
-       start_purge_timer();
+       spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
+       start_purge_timer(bat_priv);
        return 1;
 
 err:
-       spin_unlock_irqrestore(&orig_hash_lock, flags);
+       spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
        return 0;
 }
 
@@ -60,8 +62,7 @@ struct neigh_node *
 create_neighbor(struct orig_node *orig_node, struct orig_node *orig_neigh_node,
                uint8_t *neigh, struct batman_if *if_incoming)
 {
-       /* FIXME: each orig_node->batman_if will be attached to a softif */
-       struct bat_priv *bat_priv = netdev_priv(soft_device);
+       struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
        struct neigh_node *neigh_node;
 
        bat_dbg(DBG_BATMAN, bat_priv,
@@ -81,11 +82,12 @@ create_neighbor(struct orig_node *orig_node, struct orig_node *orig_neigh_node,
        return neigh_node;
 }
 
-static void free_orig_node(void *data)
+static void free_orig_node(void *data, void *arg)
 {
        struct list_head *list_pos, *list_pos_tmp;
        struct neigh_node *neigh_node;
        struct orig_node *orig_node = (struct orig_node *)data;
+       struct bat_priv *bat_priv = (struct bat_priv *)arg;
 
        /* for all neighbors towards this originator ... */
        list_for_each_safe(list_pos, list_pos_tmp, &orig_node->neigh_list) {
@@ -95,41 +97,40 @@ static void free_orig_node(void *data)
                kfree(neigh_node);
        }
 
-       hna_global_del_orig(orig_node, "originator timed out");
+       frag_list_free(&orig_node->frag_list);
+       hna_global_del_orig(bat_priv, orig_node, "originator timed out");
 
        kfree(orig_node->bcast_own);
        kfree(orig_node->bcast_own_sum);
        kfree(orig_node);
 }
 
-void originator_free(void)
+void originator_free(struct bat_priv *bat_priv)
 {
        unsigned long flags;
 
-       if (!orig_hash)
+       if (!bat_priv->orig_hash)
                return;
 
-       cancel_delayed_work_sync(&purge_orig_wq);
+       cancel_delayed_work_sync(&bat_priv->orig_work);
 
-       spin_lock_irqsave(&orig_hash_lock, flags);
-       hash_delete(orig_hash, free_orig_node);
-       orig_hash = NULL;
-       spin_unlock_irqrestore(&orig_hash_lock, flags);
+       spin_lock_irqsave(&bat_priv->orig_hash_lock, flags);
+       hash_delete(bat_priv->orig_hash, free_orig_node, bat_priv);
+       bat_priv->orig_hash = NULL;
+       spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
 }
 
 /* this function finds or creates an originator entry for the given
  * address if it does not exits */
-struct orig_node *get_orig_node(uint8_t *addr)
+struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr)
 {
-       /* FIXME: each batman_if will be attached to a softif */
-       struct bat_priv *bat_priv = netdev_priv(soft_device);
        struct orig_node *orig_node;
        struct hashtable_t *swaphash;
        int size;
 
-       orig_node = ((struct orig_node *)hash_find(orig_hash, addr));
+       orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, addr));
 
-       if (orig_node != NULL)
+       if (orig_node)
                return orig_node;
 
        bat_dbg(DBG_BATMAN, bat_priv,
@@ -157,20 +158,25 @@ struct orig_node *get_orig_node(uint8_t *addr)
 
        size = bat_priv->num_ifaces * sizeof(uint8_t);
        orig_node->bcast_own_sum = kzalloc(size, GFP_ATOMIC);
+
+       INIT_LIST_HEAD(&orig_node->frag_list);
+       orig_node->last_frag_packet = 0;
+
        if (!orig_node->bcast_own_sum)
                goto free_bcast_own;
 
-       if (hash_add(orig_hash, orig_node) < 0)
+       if (hash_add(bat_priv->orig_hash, orig_node) < 0)
                goto free_bcast_own_sum;
 
-       if (orig_hash->elements * 4 > orig_hash->size) {
-               swaphash = hash_resize(orig_hash, orig_hash->size * 2);
+       if (bat_priv->orig_hash->elements * 4 > bat_priv->orig_hash->size) {
+               swaphash = hash_resize(bat_priv->orig_hash,
+                                      bat_priv->orig_hash->size * 2);
 
-               if (swaphash == NULL)
-                       bat_err(soft_device,
+               if (!swaphash)
+                       bat_dbg(DBG_BATMAN, bat_priv,
                                "Couldn't resize orig hash table\n");
                else
-                       orig_hash = swaphash;
+                       bat_priv->orig_hash = swaphash;
        }
 
        return orig_node;
@@ -183,11 +189,10 @@ free_orig_node:
        return NULL;
 }
 
-static bool purge_orig_neighbors(struct orig_node *orig_node,
+static bool purge_orig_neighbors(struct bat_priv *bat_priv,
+                                struct orig_node *orig_node,
                                 struct neigh_node **best_neigh_node)
 {
-       /* FIXME: each orig_node->batman_if will be attached to a softif */
-       struct bat_priv *bat_priv = netdev_priv(soft_device);
        struct list_head *list_pos, *list_pos_tmp;
        struct neigh_node *neigh_node;
        bool neigh_purged = false;
@@ -200,8 +205,8 @@ static bool purge_orig_neighbors(struct orig_node *orig_node,
 
                if ((time_after(jiffies,
                        neigh_node->last_valid + PURGE_TIMEOUT * HZ)) ||
-                   (neigh_node->if_incoming->if_status ==
-                                               IF_TO_BE_REMOVED)) {
+                   (neigh_node->if_incoming->if_status == IF_INACTIVE) ||
+                   (neigh_node->if_incoming->if_status == IF_TO_BE_REMOVED)) {
 
                        if (neigh_node->if_incoming->if_status ==
                                                        IF_TO_BE_REMOVED)
@@ -209,7 +214,7 @@ static bool purge_orig_neighbors(struct orig_node *orig_node,
                                        "neighbor purge: originator %pM, "
                                        "neighbor: %pM, iface: %s\n",
                                        orig_node->orig, neigh_node->addr,
-                                       neigh_node->if_incoming->dev);
+                                       neigh_node->if_incoming->net_dev->name);
                        else
                                bat_dbg(DBG_BATMAN, bat_priv,
                                        "neighbor timeout: originator %pM, "
@@ -229,10 +234,9 @@ static bool purge_orig_neighbors(struct orig_node *orig_node,
        return neigh_purged;
 }
 
-static bool purge_orig_node(struct orig_node *orig_node)
+static bool purge_orig_node(struct bat_priv *bat_priv,
+                           struct orig_node *orig_node)
 {
-       /* FIXME: each batman_if will be attached to a softif */
-       struct bat_priv *bat_priv = netdev_priv(soft_device);
        struct neigh_node *best_neigh_node;
 
        if (time_after(jiffies,
@@ -243,8 +247,10 @@ static bool purge_orig_node(struct orig_node *orig_node)
                        orig_node->orig, (orig_node->last_valid / HZ));
                return true;
        } else {
-               if (purge_orig_neighbors(orig_node, &best_neigh_node)) {
-                       update_routes(orig_node, best_neigh_node,
+               if (purge_orig_neighbors(bat_priv, orig_node,
+                                                       &best_neigh_node)) {
+                       update_routes(bat_priv, orig_node,
+                                     best_neigh_node,
                                      orig_node->hna_buff,
                                      orig_node->hna_buff_len);
                        /* update bonding candidates, we could have lost
@@ -256,29 +262,46 @@ static bool purge_orig_node(struct orig_node *orig_node)
        return false;
 }
 
-void purge_orig(struct work_struct *work)
+static void _purge_orig(struct bat_priv *bat_priv)
 {
        HASHIT(hashit);
        struct orig_node *orig_node;
        unsigned long flags;
 
-       spin_lock_irqsave(&orig_hash_lock, flags);
+       spin_lock_irqsave(&bat_priv->orig_hash_lock, flags);
 
        /* for all origins... */
-       while (hash_iterate(orig_hash, &hashit)) {
+       while (hash_iterate(bat_priv->orig_hash, &hashit)) {
                orig_node = hashit.bucket->data;
-               if (purge_orig_node(orig_node)) {
-                       hash_remove_bucket(orig_hash, &hashit);
-                       free_orig_node(orig_node);
+
+               if (purge_orig_node(bat_priv, orig_node)) {
+                       hash_remove_bucket(bat_priv->orig_hash, &hashit);
+                       free_orig_node(orig_node, bat_priv);
                }
+
+               if (time_after(jiffies, (orig_node->last_frag_packet +
+                                       msecs_to_jiffies(FRAG_TIMEOUT))))
+                       frag_list_free(&orig_node->frag_list);
        }
 
-       spin_unlock_irqrestore(&orig_hash_lock, flags);
+       spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
+
+}
+
+static void purge_orig(struct work_struct *work)
+{
+       struct delayed_work *delayed_work =
+               container_of(work, struct delayed_work, work);
+       struct bat_priv *bat_priv =
+               container_of(delayed_work, struct bat_priv, orig_work);
 
-       /* if work == NULL we were not called by the timer
-        * and thus do not need to re-arm the timer */
-       if (work)
-               start_purge_timer();
+       _purge_orig(bat_priv);
+       start_purge_timer(bat_priv);
+}
+
+void purge_orig_ref(struct bat_priv *bat_priv)
+{
+       _purge_orig(bat_priv);
 }
 
 int orig_seq_print_text(struct seq_file *seq, void *offset)
@@ -292,7 +315,6 @@ int orig_seq_print_text(struct seq_file *seq, void *offset)
        int last_seen_secs;
        int last_seen_msecs;
        unsigned long flags;
-       char orig_str[ETH_STR_LEN], router_str[ETH_STR_LEN];
 
        if ((!bat_priv->primary_if) ||
            (bat_priv->primary_if->if_status != IF_ACTIVE)) {
@@ -306,19 +328,17 @@ int orig_seq_print_text(struct seq_file *seq, void *offset)
                                  net_dev->name);
        }
 
-       rcu_read_lock();
-       seq_printf(seq, "[B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%s (%s)]\n",
+       seq_printf(seq, "[B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%pM (%s)]\n",
                   SOURCE_VERSION, REVISION_VERSION_STR,
-                  bat_priv->primary_if->dev, bat_priv->primary_if->addr_str,
-                  net_dev->name);
+                  bat_priv->primary_if->net_dev->name,
+                  bat_priv->primary_if->net_dev->dev_addr, net_dev->name);
        seq_printf(seq, "  %-15s %s (%s/%i) %17s [%10s]: %20s ...\n",
                   "Originator", "last-seen", "#", TQ_MAX_VALUE, "Nexthop",
                   "outgoingIF", "Potential nexthops");
-       rcu_read_unlock();
 
-       spin_lock_irqsave(&orig_hash_lock, flags);
+       spin_lock_irqsave(&bat_priv->orig_hash_lock, flags);
 
-       while (hash_iterate(orig_hash, &hashit)) {
+       while (hash_iterate(bat_priv->orig_hash, &hashit)) {
 
                orig_node = hashit.bucket->data;
 
@@ -328,21 +348,18 @@ int orig_seq_print_text(struct seq_file *seq, void *offset)
                if (orig_node->router->tq_avg == 0)
                        continue;
 
-               addr_to_string(orig_str, orig_node->orig);
-               addr_to_string(router_str, orig_node->router->addr);
                last_seen_secs = jiffies_to_msecs(jiffies -
                                                orig_node->last_valid) / 1000;
                last_seen_msecs = jiffies_to_msecs(jiffies -
                                                orig_node->last_valid) % 1000;
 
-               seq_printf(seq, "%-17s %4i.%03is   (%3i) %17s [%10s]:",
-                          orig_str, last_seen_secs, last_seen_msecs,
-                          orig_node->router->tq_avg, router_str,
-                          orig_node->router->if_incoming->dev);
+               seq_printf(seq, "%pM %4i.%03is   (%3i) %pM [%10s]:",
+                          orig_node->orig, last_seen_secs, last_seen_msecs,
+                          orig_node->router->tq_avg, orig_node->router->addr,
+                          orig_node->router->if_incoming->net_dev->name);
 
                list_for_each_entry(neigh_node, &orig_node->neigh_list, list) {
-                       addr_to_string(orig_str, neigh_node->addr);
-                       seq_printf(seq, " %17s (%3i)", orig_str,
+                       seq_printf(seq, " %pM (%3i)", neigh_node->addr,
                                           neigh_node->tq_avg);
                }
 
@@ -350,7 +367,7 @@ int orig_seq_print_text(struct seq_file *seq, void *offset)
                batman_count++;
        }
 
-       spin_unlock_irqrestore(&orig_hash_lock, flags);
+       spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
 
        if ((batman_count == 0))
                seq_printf(seq, "No batman nodes in range ...\n");
@@ -390,26 +407,27 @@ static int orig_node_add_if(struct orig_node *orig_node, int max_if_num)
 
 int orig_hash_add_if(struct batman_if *batman_if, int max_if_num)
 {
+       struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface);
        struct orig_node *orig_node;
        unsigned long flags;
        HASHIT(hashit);
 
        /* resize all orig nodes because orig_node->bcast_own(_sum) depend on
         * if_num */
-       spin_lock_irqsave(&orig_hash_lock, flags);
+       spin_lock_irqsave(&bat_priv->orig_hash_lock, flags);
 
-       while (hash_iterate(orig_hash, &hashit)) {
+       while (hash_iterate(bat_priv->orig_hash, &hashit)) {
                orig_node = hashit.bucket->data;
 
                if (orig_node_add_if(orig_node, max_if_num) == -1)
                        goto err;
        }
 
-       spin_unlock_irqrestore(&orig_hash_lock, flags);
+       spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
        return 0;
 
 err:
-       spin_unlock_irqrestore(&orig_hash_lock, flags);
+       spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
        return -ENOMEM;
 }
 
@@ -434,7 +452,7 @@ static int orig_node_del_if(struct orig_node *orig_node,
        memcpy(data_ptr, orig_node->bcast_own, del_if_num * chunk_size);
 
        /* copy second part */
-       memcpy(data_ptr,
+       memcpy(data_ptr + del_if_num * chunk_size,
               orig_node->bcast_own + ((del_if_num + 1) * chunk_size),
               (max_if_num - del_if_num) * chunk_size);
 
@@ -454,7 +472,7 @@ free_bcast_own:
        memcpy(data_ptr, orig_node->bcast_own_sum,
               del_if_num * sizeof(uint8_t));
 
-       memcpy(data_ptr,
+       memcpy(data_ptr + del_if_num * sizeof(uint8_t),
               orig_node->bcast_own_sum + ((del_if_num + 1) * sizeof(uint8_t)),
               (max_if_num - del_if_num) * sizeof(uint8_t));
 
@@ -467,6 +485,7 @@ free_own_sum:
 
 int orig_hash_del_if(struct batman_if *batman_if, int max_if_num)
 {
+       struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface);
        struct batman_if *batman_if_tmp;
        struct orig_node *orig_node;
        unsigned long flags;
@@ -475,9 +494,9 @@ int orig_hash_del_if(struct batman_if *batman_if, int max_if_num)
 
        /* resize all orig nodes because orig_node->bcast_own(_sum) depend on
         * if_num */
-       spin_lock_irqsave(&orig_hash_lock, flags);
+       spin_lock_irqsave(&bat_priv->orig_hash_lock, flags);
 
-       while (hash_iterate(orig_hash, &hashit)) {
+       while (hash_iterate(bat_priv->orig_hash, &hashit)) {
                orig_node = hashit.bucket->data;
 
                ret = orig_node_del_if(orig_node, max_if_num,
@@ -496,16 +515,19 @@ int orig_hash_del_if(struct batman_if *batman_if, int max_if_num)
                if (batman_if == batman_if_tmp)
                        continue;
 
+               if (batman_if->soft_iface != batman_if_tmp->soft_iface)
+                       continue;
+
                if (batman_if_tmp->if_num > batman_if->if_num)
                        batman_if_tmp->if_num--;
        }
        rcu_read_unlock();
 
        batman_if->if_num = -1;
-       spin_unlock_irqrestore(&orig_hash_lock, flags);
+       spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
        return 0;
 
 err:
-       spin_unlock_irqrestore(&orig_hash_lock, flags);
+       spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
        return -ENOMEM;
 }