]> Pileus Git - ~andy/linux/blobdiff - net/batman-adv/send.c
Merge remote-tracking branches 'spi/fix/ath79', 'spi/fix/atmel', 'spi/fix/coldfire...
[~andy/linux] / net / batman-adv / send.c
index fba4dcfcfac21b6e9c6686c30fc6ca8a1a08f3fa..843febd1e5198914a398215037cd2d926f167738 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner, Simon Wunderlich
  *
@@ -12,9 +12,7 @@
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include "main.h"
@@ -256,9 +254,9 @@ static int batadv_send_skb_unicast(struct batadv_priv *bat_priv,
                                   struct batadv_orig_node *orig_node,
                                   unsigned short vid)
 {
-       struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
+       struct ethhdr *ethhdr;
        struct batadv_unicast_packet *unicast_packet;
-       int ret = NET_XMIT_DROP;
+       int ret = NET_XMIT_DROP, hdr_size;
 
        if (!orig_node)
                goto out;
@@ -267,12 +265,16 @@ static int batadv_send_skb_unicast(struct batadv_priv *bat_priv,
        case BATADV_UNICAST:
                if (!batadv_send_skb_prepare_unicast(skb, orig_node))
                        goto out;
+
+               hdr_size = sizeof(*unicast_packet);
                break;
        case BATADV_UNICAST_4ADDR:
                if (!batadv_send_skb_prepare_unicast_4addr(bat_priv, skb,
                                                           orig_node,
                                                           packet_subtype))
                        goto out;
+
+               hdr_size = sizeof(struct batadv_unicast_4addr_packet);
                break;
        default:
                /* this function supports UNICAST and UNICAST_4ADDR only. It
@@ -281,6 +283,7 @@ static int batadv_send_skb_unicast(struct batadv_priv *bat_priv,
                goto out;
        }
 
+       ethhdr = (struct ethhdr *)(skb->data + hdr_size);
        unicast_packet = (struct batadv_unicast_packet *)skb->data;
 
        /* inform the destination node that we are still missing a correct route
@@ -321,13 +324,23 @@ out:
  */
 int batadv_send_skb_via_tt_generic(struct batadv_priv *bat_priv,
                                   struct sk_buff *skb, int packet_type,
-                                  int packet_subtype, unsigned short vid)
+                                  int packet_subtype, uint8_t *dst_hint,
+                                  unsigned short vid)
 {
        struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
        struct batadv_orig_node *orig_node;
+       uint8_t *src, *dst;
+
+       src = ethhdr->h_source;
+       dst = ethhdr->h_dest;
+
+       /* if we got an hint! let's send the packet to this client (if any) */
+       if (dst_hint) {
+               src = NULL;
+               dst = dst_hint;
+       }
+       orig_node = batadv_transtable_search(bat_priv, src, dst, vid);
 
-       orig_node = batadv_transtable_search(bat_priv, ethhdr->h_source,
-                                            ethhdr->h_dest, vid);
        return batadv_send_skb_unicast(bat_priv, skb, packet_type,
                                       packet_subtype, orig_node, vid);
 }
@@ -379,6 +392,8 @@ static void batadv_forw_packet_free(struct batadv_forw_packet *forw_packet)
                kfree_skb(forw_packet->skb);
        if (forw_packet->if_incoming)
                batadv_hardif_free_ref(forw_packet->if_incoming);
+       if (forw_packet->if_outgoing)
+               batadv_hardif_free_ref(forw_packet->if_outgoing);
        kfree(forw_packet);
 }
 
@@ -442,6 +457,7 @@ int batadv_add_bcast_packet_to_list(struct batadv_priv *bat_priv,
 
        forw_packet->skb = newskb;
        forw_packet->if_incoming = primary_if;
+       forw_packet->if_outgoing = NULL;
 
        /* how often did we send the bcast packet ? */
        forw_packet->num_packets = 0;
@@ -537,11 +553,16 @@ void batadv_send_outstanding_bat_ogm_packet(struct work_struct *work)
 
        bat_priv->bat_algo_ops->bat_ogm_emit(forw_packet);
 
-       /* we have to have at least one packet in the queue
-        * to determine the queues wake up time unless we are
-        * shutting down
+       /* we have to have at least one packet in the queue to determine the
+        * queues wake up time unless we are shutting down.
+        *
+        * only re-schedule if this is the "original" copy, e.g. the OGM of the
+        * primary interface should only be rescheduled once per period, but
+        * this function will be called for the forw_packet instances of the
+        * other secondary interfaces as well.
         */
-       if (forw_packet->own)
+       if (forw_packet->own &&
+           forw_packet->if_incoming == forw_packet->if_outgoing)
                batadv_schedule_bat_ogm(forw_packet->if_incoming);
 
 out:
@@ -602,7 +623,8 @@ batadv_purge_outstanding_packets(struct batadv_priv *bat_priv,
                 * we delete only packets belonging to the given interface
                 */
                if ((hard_iface) &&
-                   (forw_packet->if_incoming != hard_iface))
+                   (forw_packet->if_incoming != hard_iface) &&
+                   (forw_packet->if_outgoing != hard_iface))
                        continue;
 
                spin_unlock_bh(&bat_priv->forw_bat_list_lock);