]> Pileus Git - ~andy/linux/blobdiff - net/batman-adv/main.c
Merge branch 'drm-intel-fixes' of git://people.freedesktop.org/~danvet/drm-intel...
[~andy/linux] / net / batman-adv / main.c
index 6d51caaf8cecb782fcb9c4da2b50000f1546f865..083a2993efe43802c25d8be483e11470731227a5 100644 (file)
@@ -30,6 +30,7 @@
 #include "translation-table.h"
 #include "hard-interface.h"
 #include "gateway_client.h"
+#include "bridge_loop_avoidance.h"
 #include "vis.h"
 #include "hash.h"
 #include "bat_algo.h"
@@ -38,6 +39,7 @@
 /* List manipulations on hardif_list have to be rtnl_lock()'ed,
  * list traversals just rcu-locked */
 struct list_head hardif_list;
+static int (*recv_packet_handler[256])(struct sk_buff *, struct hard_iface *);
 char bat_routing_algo[20] = "BATMAN IV";
 static struct hlist_head bat_algo_list;
 
@@ -45,11 +47,15 @@ unsigned char broadcast_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
 
 struct workqueue_struct *bat_event_workqueue;
 
+static void recv_handler_init(void);
+
 static int __init batman_init(void)
 {
        INIT_LIST_HEAD(&hardif_list);
        INIT_HLIST_HEAD(&bat_algo_list);
 
+       recv_handler_init();
+
        bat_iv_init();
 
        /* the name should not be longer than 10 chars - see
@@ -96,13 +102,10 @@ int mesh_init(struct net_device *soft_iface)
        spin_lock_init(&bat_priv->gw_list_lock);
        spin_lock_init(&bat_priv->vis_hash_lock);
        spin_lock_init(&bat_priv->vis_list_lock);
-       spin_lock_init(&bat_priv->softif_neigh_lock);
-       spin_lock_init(&bat_priv->softif_neigh_vid_lock);
 
        INIT_HLIST_HEAD(&bat_priv->forw_bat_list);
        INIT_HLIST_HEAD(&bat_priv->forw_bcast_list);
        INIT_HLIST_HEAD(&bat_priv->gw_list);
-       INIT_HLIST_HEAD(&bat_priv->softif_neigh_vids);
        INIT_LIST_HEAD(&bat_priv->tt_changes_list);
        INIT_LIST_HEAD(&bat_priv->tt_req_list);
        INIT_LIST_HEAD(&bat_priv->tt_roam_list);
@@ -118,6 +121,9 @@ int mesh_init(struct net_device *soft_iface)
        if (vis_init(bat_priv) < 1)
                goto err;
 
+       if (bla_init(bat_priv) < 1)
+               goto err;
+
        atomic_set(&bat_priv->gw_reselect, 0);
        atomic_set(&bat_priv->mesh_state, MESH_ACTIVE);
        goto end;
@@ -145,7 +151,7 @@ void mesh_free(struct net_device *soft_iface)
 
        tt_free(bat_priv);
 
-       softif_neigh_purge(bat_priv);
+       bla_free(bat_priv);
 
        atomic_set(&bat_priv->mesh_state, MESH_INACTIVE);
 }
@@ -178,6 +184,120 @@ int is_my_mac(const uint8_t *addr)
        return 0;
 }
 
+static int recv_unhandled_packet(struct sk_buff *skb,
+                                struct hard_iface *recv_if)
+{
+       return NET_RX_DROP;
+}
+
+/* incoming packets with the batman ethertype received on any active hard
+ * interface
+ */
+int batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
+                   struct packet_type *ptype, struct net_device *orig_dev)
+{
+       struct bat_priv *bat_priv;
+       struct batman_ogm_packet *batman_ogm_packet;
+       struct hard_iface *hard_iface;
+       uint8_t idx;
+       int ret;
+
+       hard_iface = container_of(ptype, struct hard_iface, batman_adv_ptype);
+       skb = skb_share_check(skb, GFP_ATOMIC);
+
+       /* skb was released by skb_share_check() */
+       if (!skb)
+               goto err_out;
+
+       /* packet should hold at least type and version */
+       if (unlikely(!pskb_may_pull(skb, 2)))
+               goto err_free;
+
+       /* expect a valid ethernet header here. */
+       if (unlikely(skb->mac_len != ETH_HLEN || !skb_mac_header(skb)))
+               goto err_free;
+
+       if (!hard_iface->soft_iface)
+               goto err_free;
+
+       bat_priv = netdev_priv(hard_iface->soft_iface);
+
+       if (atomic_read(&bat_priv->mesh_state) != MESH_ACTIVE)
+               goto err_free;
+
+       /* discard frames on not active interfaces */
+       if (hard_iface->if_status != IF_ACTIVE)
+               goto err_free;
+
+       batman_ogm_packet = (struct batman_ogm_packet *)skb->data;
+
+       if (batman_ogm_packet->header.version != COMPAT_VERSION) {
+               bat_dbg(DBG_BATMAN, bat_priv,
+                       "Drop packet: incompatible batman version (%i)\n",
+                       batman_ogm_packet->header.version);
+               goto err_free;
+       }
+
+       /* all receive handlers return whether they received or reused
+        * the supplied skb. if not, we have to free the skb.
+        */
+       idx = batman_ogm_packet->header.packet_type;
+       ret = (*recv_packet_handler[idx])(skb, hard_iface);
+
+       if (ret == NET_RX_DROP)
+               kfree_skb(skb);
+
+       /* return NET_RX_SUCCESS in any case as we
+        * most probably dropped the packet for
+        * routing-logical reasons.
+        */
+       return NET_RX_SUCCESS;
+
+err_free:
+       kfree_skb(skb);
+err_out:
+       return NET_RX_DROP;
+}
+
+static void recv_handler_init(void)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(recv_packet_handler); i++)
+               recv_packet_handler[i] = recv_unhandled_packet;
+
+       /* batman icmp packet */
+       recv_packet_handler[BAT_ICMP] = recv_icmp_packet;
+       /* unicast packet */
+       recv_packet_handler[BAT_UNICAST] = recv_unicast_packet;
+       /* fragmented unicast packet */
+       recv_packet_handler[BAT_UNICAST_FRAG] = recv_ucast_frag_packet;
+       /* broadcast packet */
+       recv_packet_handler[BAT_BCAST] = recv_bcast_packet;
+       /* vis packet */
+       recv_packet_handler[BAT_VIS] = recv_vis_packet;
+       /* Translation table query (request or response) */
+       recv_packet_handler[BAT_TT_QUERY] = recv_tt_query;
+       /* Roaming advertisement */
+       recv_packet_handler[BAT_ROAM_ADV] = recv_roam_adv;
+}
+
+int recv_handler_register(uint8_t packet_type,
+                         int (*recv_handler)(struct sk_buff *,
+                                             struct hard_iface *))
+{
+       if (recv_packet_handler[packet_type] != &recv_unhandled_packet)
+               return -EBUSY;
+
+       recv_packet_handler[packet_type] = recv_handler;
+       return 0;
+}
+
+void recv_handler_unregister(uint8_t packet_type)
+{
+       recv_packet_handler[packet_type] = recv_unhandled_packet;
+}
+
 static struct bat_algo_ops *bat_algo_get(char *name)
 {
        struct bat_algo_ops *bat_algo_ops = NULL, *bat_algo_ops_tmp;
@@ -207,12 +327,12 @@ int bat_algo_register(struct bat_algo_ops *bat_algo_ops)
        }
 
        /* all algorithms must implement all ops (for now) */
-       if (!bat_algo_ops->bat_ogm_init ||
-           !bat_algo_ops->bat_ogm_init_primary ||
-           !bat_algo_ops->bat_ogm_update_mac ||
+       if (!bat_algo_ops->bat_iface_enable ||
+           !bat_algo_ops->bat_iface_disable ||
+           !bat_algo_ops->bat_iface_update_mac ||
+           !bat_algo_ops->bat_primary_iface_set ||
            !bat_algo_ops->bat_ogm_schedule ||
-           !bat_algo_ops->bat_ogm_emit ||
-           !bat_algo_ops->bat_ogm_receive) {
+           !bat_algo_ops->bat_ogm_emit) {
                pr_info("Routing algo '%s' does not implement required ops\n",
                        bat_algo_ops->name);
                goto out;