batman-adv: Make orig_node->router an rcu protected pointer
[pandora-kernel.git] / net / batman-adv / send.c
index b89b9f7..e78670c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors:
+ * Copyright (C) 2007-2011 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner, Simon Wunderlich
  *
@@ -25,7 +25,6 @@
 #include "translation-table.h"
 #include "soft-interface.h"
 #include "hard-interface.h"
-#include "types.h"
 #include "vis.h"
 #include "aggregation.h"
 #include "gateway_common.h"
@@ -49,7 +48,7 @@ static unsigned long own_send_time(struct bat_priv *bat_priv)
 }
 
 /* when do we schedule a forwarded packet to be sent */
-static unsigned long forward_send_time(struct bat_priv *bat_priv)
+static unsigned long forward_send_time(void)
 {
        return jiffies + msecs_to_jiffies(random32() % (JITTER/2));
 }
@@ -57,20 +56,20 @@ static unsigned long forward_send_time(struct bat_priv *bat_priv)
 /* send out an already prepared packet to the given address via the
  * specified batman interface */
 int send_skb_packet(struct sk_buff *skb,
-                               struct batman_if *batman_if,
+                               struct hard_iface *hard_iface,
                                uint8_t *dst_addr)
 {
        struct ethhdr *ethhdr;
 
-       if (batman_if->if_status != IF_ACTIVE)
+       if (hard_iface->if_status != IF_ACTIVE)
                goto send_skb_err;
 
-       if (unlikely(!batman_if->net_dev))
+       if (unlikely(!hard_iface->net_dev))
                goto send_skb_err;
 
-       if (!(batman_if->net_dev->flags & IFF_UP)) {
+       if (!(hard_iface->net_dev->flags & IFF_UP)) {
                pr_warning("Interface %s is not up - can't send packet via "
-                          "that interface!\n", batman_if->net_dev->name);
+                          "that interface!\n", hard_iface->net_dev->name);
                goto send_skb_err;
        }
 
@@ -81,7 +80,7 @@ int send_skb_packet(struct sk_buff *skb,
        skb_reset_mac_header(skb);
 
        ethhdr = (struct ethhdr *) skb_mac_header(skb);
-       memcpy(ethhdr->h_source, batman_if->net_dev->dev_addr, ETH_ALEN);
+       memcpy(ethhdr->h_source, hard_iface->net_dev->dev_addr, ETH_ALEN);
        memcpy(ethhdr->h_dest, dst_addr, ETH_ALEN);
        ethhdr->h_proto = __constant_htons(ETH_P_BATMAN);
 
@@ -89,7 +88,7 @@ int send_skb_packet(struct sk_buff *skb,
        skb->priority = TC_PRIO_CONTROL;
        skb->protocol = __constant_htons(ETH_P_BATMAN);
 
-       skb->dev = batman_if->net_dev;
+       skb->dev = hard_iface->net_dev;
 
        /* dev_queue_xmit() returns a negative result on error.  However on
         * congestion and traffic shaping, it drops and returns NET_XMIT_DROP
@@ -103,16 +102,16 @@ send_skb_err:
 
 /* Send a packet to a given interface */
 static void send_packet_to_if(struct forw_packet *forw_packet,
-                             struct batman_if *batman_if)
+                             struct hard_iface *hard_iface)
 {
-       struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface);
+       struct bat_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
        char *fwd_str;
        uint8_t packet_num;
        int16_t buff_pos;
        struct batman_packet *batman_packet;
        struct sk_buff *skb;
 
-       if (batman_if->if_status != IF_ACTIVE)
+       if (hard_iface->if_status != IF_ACTIVE)
                return;
 
        packet_num = 0;
@@ -127,7 +126,7 @@ static void send_packet_to_if(struct forw_packet *forw_packet,
                /* we might have aggregated direct link packets with an
                 * ordinary base packet */
                if ((forw_packet->direct_link_flags & (1 << packet_num)) &&
-                   (forw_packet->if_incoming == batman_if))
+                   (forw_packet->if_incoming == hard_iface))
                        batman_packet->flags |= DIRECTLINK;
                else
                        batman_packet->flags &= ~DIRECTLINK;
@@ -143,7 +142,8 @@ static void send_packet_to_if(struct forw_packet *forw_packet,
                        batman_packet->tq, batman_packet->ttl,
                        (batman_packet->flags & DIRECTLINK ?
                         "on" : "off"),
-                       batman_if->net_dev->name, batman_if->net_dev->dev_addr);
+                       hard_iface->net_dev->name,
+                       hard_iface->net_dev->dev_addr);
 
                buff_pos += sizeof(struct batman_packet) +
                        (batman_packet->num_hna * ETH_ALEN);
@@ -155,13 +155,13 @@ static void send_packet_to_if(struct forw_packet *forw_packet,
        /* create clone because function is called more than once */
        skb = skb_clone(forw_packet->skb, GFP_ATOMIC);
        if (skb)
-               send_skb_packet(skb, batman_if, broadcast_addr);
+               send_skb_packet(skb, hard_iface, broadcast_addr);
 }
 
 /* send a batman packet */
 static void send_packet(struct forw_packet *forw_packet)
 {
-       struct batman_if *batman_if;
+       struct hard_iface *hard_iface;
        struct net_device *soft_iface;
        struct bat_priv *bat_priv;
        struct batman_packet *batman_packet =
@@ -205,17 +205,17 @@ static void send_packet(struct forw_packet *forw_packet)
 
        /* broadcast on every interface */
        rcu_read_lock();
-       list_for_each_entry_rcu(batman_if, &if_list, list) {
-               if (batman_if->soft_iface != soft_iface)
+       list_for_each_entry_rcu(hard_iface, &hardif_list, list) {
+               if (hard_iface->soft_iface != soft_iface)
                        continue;
 
-               send_packet_to_if(forw_packet, batman_if);
+               send_packet_to_if(forw_packet, hard_iface);
        }
        rcu_read_unlock();
 }
 
 static void rebuild_batman_packet(struct bat_priv *bat_priv,
-                                 struct batman_if *batman_if)
+                                 struct hard_iface *hard_iface)
 {
        int new_len;
        unsigned char *new_buff;
@@ -227,7 +227,7 @@ static void rebuild_batman_packet(struct bat_priv *bat_priv,
 
        /* keep old buffer if kmalloc should fail */
        if (new_buff) {
-               memcpy(new_buff, batman_if->packet_buff,
+               memcpy(new_buff, hard_iface->packet_buff,
                       sizeof(struct batman_packet));
                batman_packet = (struct batman_packet *)new_buff;
 
@@ -235,21 +235,21 @@ static void rebuild_batman_packet(struct bat_priv *bat_priv,
                                new_buff + sizeof(struct batman_packet),
                                new_len - sizeof(struct batman_packet));
 
-               kfree(batman_if->packet_buff);
-               batman_if->packet_buff = new_buff;
-               batman_if->packet_len = new_len;
+               kfree(hard_iface->packet_buff);
+               hard_iface->packet_buff = new_buff;
+               hard_iface->packet_len = new_len;
        }
 }
 
-void schedule_own_packet(struct batman_if *batman_if)
+void schedule_own_packet(struct hard_iface *hard_iface)
 {
-       struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface);
+       struct bat_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
        unsigned long send_time;
        struct batman_packet *batman_packet;
        int vis_server;
 
-       if ((batman_if->if_status == IF_NOT_IN_USE) ||
-           (batman_if->if_status == IF_TO_BE_REMOVED))
+       if ((hard_iface->if_status == IF_NOT_IN_USE) ||
+           (hard_iface->if_status == IF_TO_BE_REMOVED))
                return;
 
        vis_server = atomic_read(&bat_priv->vis_mode);
@@ -261,53 +261,54 @@ void schedule_own_packet(struct batman_if *batman_if)
         * outdated packets (especially uninitialized mac addresses) in the
         * packet queue
         */
-       if (batman_if->if_status == IF_TO_BE_ACTIVATED)
-               batman_if->if_status = IF_ACTIVE;
+       if (hard_iface->if_status == IF_TO_BE_ACTIVATED)
+               hard_iface->if_status = IF_ACTIVE;
 
        /* if local hna has changed and interface is a primary interface */
        if ((atomic_read(&bat_priv->hna_local_changed)) &&
-           (batman_if == bat_priv->primary_if))
-               rebuild_batman_packet(bat_priv, batman_if);
+           (hard_iface == bat_priv->primary_if))
+               rebuild_batman_packet(bat_priv, hard_iface);
 
        /**
         * NOTE: packet_buff might just have been re-allocated in
         * rebuild_batman_packet()
         */
-       batman_packet = (struct batman_packet *)batman_if->packet_buff;
+       batman_packet = (struct batman_packet *)hard_iface->packet_buff;
 
        /* change sequence number to network order */
        batman_packet->seqno =
-               htonl((uint32_t)atomic_read(&batman_if->seqno));
+               htonl((uint32_t)atomic_read(&hard_iface->seqno));
 
        if (vis_server == VIS_TYPE_SERVER_SYNC)
                batman_packet->flags |= VIS_SERVER;
        else
                batman_packet->flags &= ~VIS_SERVER;
 
-       if ((batman_if == bat_priv->primary_if) &&
+       if ((hard_iface == bat_priv->primary_if) &&
            (atomic_read(&bat_priv->gw_mode) == GW_MODE_SERVER))
                batman_packet->gw_flags =
                                (uint8_t)atomic_read(&bat_priv->gw_bandwidth);
        else
                batman_packet->gw_flags = 0;
 
-       atomic_inc(&batman_if->seqno);
+       atomic_inc(&hard_iface->seqno);
 
-       slide_own_bcast_window(batman_if);
+       slide_own_bcast_window(hard_iface);
        send_time = own_send_time(bat_priv);
        add_bat_packet_to_list(bat_priv,
-                              batman_if->packet_buff,
-                              batman_if->packet_len,
-                              batman_if, 1, send_time);
+                              hard_iface->packet_buff,
+                              hard_iface->packet_len,
+                              hard_iface, 1, send_time);
 }
 
 void schedule_forward_packet(struct orig_node *orig_node,
                             struct ethhdr *ethhdr,
                             struct batman_packet *batman_packet,
                             uint8_t directlink, int hna_buff_len,
-                            struct batman_if *if_incoming)
+                            struct hard_iface *if_incoming)
 {
        struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
+       struct neigh_node *router;
        unsigned char in_tq, in_ttl, tq_avg = 0;
        unsigned long send_time;
 
@@ -316,6 +317,8 @@ void schedule_forward_packet(struct orig_node *orig_node,
                return;
        }
 
+       router = orig_node_get_router(orig_node);
+
        in_tq = batman_packet->tq;
        in_ttl = batman_packet->ttl;
 
@@ -324,20 +327,22 @@ void schedule_forward_packet(struct orig_node *orig_node,
 
        /* rebroadcast tq of our best ranking neighbor to ensure the rebroadcast
         * of our best tq value */
-       if ((orig_node->router) && (orig_node->router->tq_avg != 0)) {
+       if (router && router->tq_avg != 0) {
 
                /* rebroadcast ogm of best ranking neighbor as is */
-               if (!compare_orig(orig_node->router->addr, ethhdr->h_source)) {
-                       batman_packet->tq = orig_node->router->tq_avg;
+               if (!compare_eth(router->addr, ethhdr->h_source)) {
+                       batman_packet->tq = router->tq_avg;
 
-                       if (orig_node->router->last_ttl)
-                               batman_packet->ttl = orig_node->router->last_ttl
-                                                       - 1;
+                       if (router->last_ttl)
+                               batman_packet->ttl = router->last_ttl - 1;
                }
 
-               tq_avg = orig_node->router->tq_avg;
+               tq_avg = router->tq_avg;
        }
 
+       if (router)
+               neigh_node_free_ref(router);
+
        /* apply hop penalty */
        batman_packet->tq = hop_penalty(batman_packet->tq, bat_priv);
 
@@ -356,7 +361,7 @@ void schedule_forward_packet(struct orig_node *orig_node,
        else
                batman_packet->flags &= ~DIRECTLINK;
 
-       send_time = forward_send_time(bat_priv);
+       send_time = forward_send_time();
        add_bat_packet_to_list(bat_priv,
                               (unsigned char *)batman_packet,
                               sizeof(struct batman_packet) + hna_buff_len,
@@ -444,7 +449,7 @@ out:
 
 static void send_outstanding_bcast_packet(struct work_struct *work)
 {
-       struct batman_if *batman_if;
+       struct hard_iface *hard_iface;
        struct delayed_work *delayed_work =
                container_of(work, struct delayed_work, work);
        struct forw_packet *forw_packet =
@@ -462,14 +467,14 @@ static void send_outstanding_bcast_packet(struct work_struct *work)
 
        /* rebroadcast packet */
        rcu_read_lock();
-       list_for_each_entry_rcu(batman_if, &if_list, list) {
-               if (batman_if->soft_iface != soft_iface)
+       list_for_each_entry_rcu(hard_iface, &hardif_list, list) {
+               if (hard_iface->soft_iface != soft_iface)
                        continue;
 
                /* send a copy of the saved skb */
                skb1 = skb_clone(forw_packet->skb, GFP_ATOMIC);
                if (skb1)
-                       send_skb_packet(skb1, batman_if, broadcast_addr);
+                       send_skb_packet(skb1, hard_iface, broadcast_addr);
        }
        rcu_read_unlock();
 
@@ -522,15 +527,15 @@ out:
 }
 
 void purge_outstanding_packets(struct bat_priv *bat_priv,
-                              struct batman_if *batman_if)
+                              struct hard_iface *hard_iface)
 {
        struct forw_packet *forw_packet;
        struct hlist_node *tmp_node, *safe_tmp_node;
 
-       if (batman_if)
+       if (hard_iface)
                bat_dbg(DBG_BATMAN, bat_priv,
                        "purge_outstanding_packets(): %s\n",
-                       batman_if->net_dev->name);
+                       hard_iface->net_dev->name);
        else
                bat_dbg(DBG_BATMAN, bat_priv,
                        "purge_outstanding_packets()\n");
@@ -544,8 +549,8 @@ void purge_outstanding_packets(struct bat_priv *bat_priv,
                 * if purge_outstanding_packets() was called with an argmument
                 * we delete only packets belonging to the given interface
                 */
-               if ((batman_if) &&
-                   (forw_packet->if_incoming != batman_if))
+               if ((hard_iface) &&
+                   (forw_packet->if_incoming != hard_iface))
                        continue;
 
                spin_unlock_bh(&bat_priv->forw_bcast_list_lock);
@@ -568,8 +573,8 @@ void purge_outstanding_packets(struct bat_priv *bat_priv,
                 * if purge_outstanding_packets() was called with an argmument
                 * we delete only packets belonging to the given interface
                 */
-               if ((batman_if) &&
-                   (forw_packet->if_incoming != batman_if))
+               if ((hard_iface) &&
+                   (forw_packet->if_incoming != hard_iface))
                        continue;
 
                spin_unlock_bh(&bat_priv->forw_bat_list_lock);