batman-adv: introduce packet type handler array for incoming packets
authorMarek Lindner <lindner_marek@yahoo.de>
Thu, 1 Mar 2012 07:35:17 +0000 (15:35 +0800)
committerAntonio Quartulli <ordex@autistici.org>
Fri, 11 May 2012 08:08:10 +0000 (10:08 +0200)
The packet handler array replaces the growing switch statement, thus
dealing with incoming packets in a more efficient way. It also adds
to possibility to register packet handlers on the fly.

Signed-off-by: Marek Lindner <lindner_marek@yahoo.de>
Acked-by: Simon Wunderlich <siwu@hrz.tu-chemnitz.de>
Signed-off-by: Antonio Quartulli <ordex@autistici.org>
net/batman-adv/hard-interface.c
net/batman-adv/main.c
net/batman-adv/main.h

index 47c79d724ba3286d54699ec891028cb5e6d1a566..95f869c7ca04965212f36be5753f8b756f18daeb 100644 (file)
 
 #include <linux/if_arp.h>
 
-
-static int batman_skb_recv(struct sk_buff *skb,
-                          struct net_device *dev,
-                          struct packet_type *ptype,
-                          struct net_device *orig_dev);
-
 void hardif_free_rcu(struct rcu_head *rcu)
 {
        struct hard_iface *hard_iface;
@@ -551,113 +545,6 @@ out:
        return NOTIFY_DONE;
 }
 
-/* incoming packets with the batman ethertype received on any active hard
- * interface */
-static 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;
-       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. */
-
-       switch (batman_ogm_packet->header.packet_type) {
-               /* batman originator packet */
-       case BAT_IV_OGM:
-               ret = recv_bat_ogm_packet(skb, hard_iface);
-               break;
-
-               /* batman icmp packet */
-       case BAT_ICMP:
-               ret = recv_icmp_packet(skb, hard_iface);
-               break;
-
-               /* unicast packet */
-       case BAT_UNICAST:
-               ret = recv_unicast_packet(skb, hard_iface);
-               break;
-
-               /* fragmented unicast packet */
-       case BAT_UNICAST_FRAG:
-               ret = recv_ucast_frag_packet(skb, hard_iface);
-               break;
-
-               /* broadcast packet */
-       case BAT_BCAST:
-               ret = recv_bcast_packet(skb, hard_iface);
-               break;
-
-               /* vis packet */
-       case BAT_VIS:
-               ret = recv_vis_packet(skb, hard_iface);
-               break;
-               /* Translation table query (request or response) */
-       case BAT_TT_QUERY:
-               ret = recv_tt_query(skb, hard_iface);
-               break;
-               /* Roaming advertisement */
-       case BAT_ROAM_ADV:
-               ret = recv_roam_adv(skb, hard_iface);
-               break;
-       default:
-               ret = NET_RX_DROP;
-       }
-
-       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;
-}
-
 /* This function returns true if the interface represented by ifindex is a
  * 802.11 wireless device */
 bool is_wifi_iface(int ifindex)
index 791327219531c8a907a23cb54e4091401d15a7c2..d19b93575d565296c97a300f8415703d4a6ee2f6 100644 (file)
@@ -39,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;
 
@@ -46,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
@@ -179,6 +184,122 @@ 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 originator packet */
+       recv_packet_handler[BAT_IV_OGM] = recv_bat_ogm_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;
index d9832acf558dc0e2d9cd3ef29cb33c47f0df051c..fd83acd48b2804268620c4a256c3727c43b5e4ee 100644 (file)
@@ -155,6 +155,12 @@ void mesh_free(struct net_device *soft_iface);
 void inc_module_count(void);
 void dec_module_count(void);
 int is_my_mac(const uint8_t *addr);
+int batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
+                   struct packet_type *ptype, struct net_device *orig_dev);
+int recv_handler_register(uint8_t packet_type,
+                         int (*recv_handler)(struct sk_buff *,
+                                             struct hard_iface *));
+void recv_handler_unregister(uint8_t packet_type);
 int bat_algo_register(struct bat_algo_ops *bat_algo_ops);
 int bat_algo_select(struct bat_priv *bat_priv, char *name);
 int bat_algo_seq_print_text(struct seq_file *seq, void *offset);