]> rtime.felk.cvut.cz Git - socketcan-devel.git/blobdiff - kernel/2.6/net/can/gw.c
Added funtionality to flush all GW jobs in one netlink message.
[socketcan-devel.git] / kernel / 2.6 / net / can / gw.c
index 7b999c70d78dedd0e23d2e6e10dff0ec716c7390..42f7fe7a0ec91f48e7a320af50d5e904589be213 100644 (file)
@@ -48,6 +48,7 @@
 #include <linux/list.h>
 #include <linux/spinlock.h>
 #include <linux/rcupdate.h>
+#include <linux/rculist.h>
 #include <linux/net.h>
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
@@ -567,6 +568,22 @@ fail:
        return err;
 }
 
+static void gw_remove_all_jobs(void)
+{
+       struct gw_job *gwj = NULL;
+       struct hlist_node *n, *nx;
+
+       spin_lock(&can_gw_list_lock);
+
+       hlist_for_each_entry_safe(gwj, n, nx, &can_gw_list, list) {
+               hlist_del(&gwj->list);
+               can_gw_unregister_filter(gwj);
+               kfree(gwj);
+       }
+
+       spin_unlock(&can_gw_list_lock);
+}
+
 static int gw_remove_job(struct sk_buff *skb,  struct nlmsghdr *nlh, void *arg)
 {
        struct gw_job *gwj = NULL;
@@ -583,6 +600,12 @@ static int gw_remove_job(struct sk_buff *skb,  struct nlmsghdr *nlh, void *arg)
         if (r->can_family != AF_CAN)
                 return -EPFNOSUPPORT;
 
+       /* if_index set to 0 => remove all entries */
+       if (!r->src_ifindex && !r->dst_ifindex) {
+               gw_remove_all_jobs();
+               return 0;
+       }
+
        if (r->can_txflags & CAN_GW_TXFLAGS_ECHO)
                flags |= CAN_TX_ECHO;
 
@@ -653,22 +676,11 @@ static __init int gw_module_init(void)
 
 static __exit void gw_module_exit(void)
 {
-       struct gw_job *gwj = NULL;
-       struct hlist_node *n, *nx;
-
        rtnl_unregister_all(PF_CAN);
 
        unregister_netdevice_notifier(&notifier);
 
-       spin_lock(&can_gw_list_lock);
-
-       hlist_for_each_entry_safe(gwj, n, nx, &can_gw_list, list) {
-               hlist_del(&gwj->list);
-               can_gw_unregister_filter(gwj);
-               kfree(gwj);
-       }
-
-       spin_unlock(&can_gw_list_lock);
+       gw_remove_all_jobs();
 
        rcu_barrier(); /* Wait for completion of call_rcu()'s */