mqprio: Avoid panic if no options are provided
[linux-2.6.git] / net / netfilter / nfnetlink_log.c
index 8ec23ec..2d8158a 100644 (file)
@@ -33,7 +33,7 @@
 #include <net/netfilter/nf_log.h>
 #include <net/netfilter/nfnetlink_log.h>
 
-#include <asm/atomic.h>
+#include <linux/atomic.h>
 
 #ifdef CONFIG_BRIDGE_NETFILTER
 #include "../bridge/br_private.h"
@@ -109,8 +109,8 @@ instance_lookup_get(u_int16_t group_num)
 
        rcu_read_lock_bh();
        inst = __instance_lookup(group_num);
-       if (inst)
-               instance_get(inst);
+       if (inst && !atomic_inc_not_zero(&inst->use))
+               inst = NULL;
        rcu_read_unlock_bh();
 
        return inst;
@@ -171,7 +171,7 @@ instance_create(u_int16_t group_num, int pid)
        inst->copy_mode         = NFULNL_COPY_PACKET;
        inst->copy_range        = NFULNL_COPY_RANGE_MAX;
 
-       hlist_add_head(&inst->hlist,
+       hlist_add_head_rcu(&inst->hlist,
                       &instance_table[instance_hashfn(group_num)]);
 
        spin_unlock_bh(&instances_lock);
@@ -185,18 +185,23 @@ out_unlock:
 
 static void __nfulnl_flush(struct nfulnl_instance *inst);
 
+/* called with BH disabled */
 static void
 __instance_destroy(struct nfulnl_instance *inst)
 {
        /* first pull it out of the global list */
-       hlist_del(&inst->hlist);
+       hlist_del_rcu(&inst->hlist);
 
        /* then flush all pending packets from skb */
 
-       spin_lock_bh(&inst->lock);
+       spin_lock(&inst->lock);
+
+       /* lockless readers wont be able to use us */
+       inst->copy_mode = NFULNL_COPY_DISABLED;
+
        if (inst->skb)
                __nfulnl_flush(inst);
-       spin_unlock_bh(&inst->lock);
+       spin_unlock(&inst->lock);
 
        /* and finally put the refcount */
        instance_put(inst);
@@ -371,13 +376,11 @@ __build_packet_message(struct nfulnl_instance *inst,
                        unsigned int hooknum,
                        const struct net_device *indev,
                        const struct net_device *outdev,
-                       const struct nf_loginfo *li,
                        const char *prefix, unsigned int plen)
 {
        struct nfulnl_msg_packet_hdr pmsg;
        struct nlmsghdr *nlh;
        struct nfgenmsg *nfmsg;
-       __be32 tmp_uint;
        sk_buff_data_t old_tail = inst->skb->tail;
 
        nlh = NLMSG_PUT(inst->skb, 0, 0,
@@ -408,8 +411,9 @@ __build_packet_message(struct nfulnl_instance *inst,
                        NLA_PUT_BE32(inst->skb, NFULA_IFINDEX_PHYSINDEV,
                                     htonl(indev->ifindex));
                        /* this is the bridge group "brX" */
+                       /* rcu_read_lock()ed by nf_hook_slow or nf_log_packet */
                        NLA_PUT_BE32(inst->skb, NFULA_IFINDEX_INDEV,
-                                    htonl(indev->br_port->br->dev->ifindex));
+                                    htonl(br_port_get_rcu(indev)->br->dev->ifindex));
                } else {
                        /* Case 2: indev is bridge group, we need to look for
                         * physical device (when called from ipv4) */
@@ -423,7 +427,6 @@ __build_packet_message(struct nfulnl_instance *inst,
        }
 
        if (outdev) {
-               tmp_uint = htonl(outdev->ifindex);
 #ifndef CONFIG_BRIDGE_NETFILTER
                NLA_PUT_BE32(inst->skb, NFULA_IFINDEX_OUTDEV,
                             htonl(outdev->ifindex));
@@ -435,8 +438,9 @@ __build_packet_message(struct nfulnl_instance *inst,
                        NLA_PUT_BE32(inst->skb, NFULA_IFINDEX_PHYSOUTDEV,
                                     htonl(outdev->ifindex));
                        /* this is the bridge group "brX" */
+                       /* rcu_read_lock()ed by nf_hook_slow or nf_log_packet */
                        NLA_PUT_BE32(inst->skb, NFULA_IFINDEX_OUTDEV,
-                                    htonl(outdev->br_port->br->dev->ifindex));
+                                    htonl(br_port_get_rcu(outdev)->br->dev->ifindex));
                } else {
                        /* Case 2: indev is a bridge group, we need to look
                         * for physical device (when called from ipv4) */
@@ -452,7 +456,8 @@ __build_packet_message(struct nfulnl_instance *inst,
        if (skb->mark)
                NLA_PUT_BE32(inst->skb, NFULA_MARK, htonl(skb->mark));
 
-       if (indev && skb->dev) {
+       if (indev && skb->dev &&
+           skb->mac_header != skb->network_header) {
                struct nfulnl_msg_packet_hw phw;
                int len = dev_parse_header(skb, phw.hw_addr);
                if (len > 0) {
@@ -624,6 +629,7 @@ nfulnl_log_packet(u_int8_t pf,
                size += nla_total_size(data_len);
                break;
 
+       case NFULNL_COPY_DISABLED:
        default:
                goto unlock_and_release;
        }
@@ -644,7 +650,7 @@ nfulnl_log_packet(u_int8_t pf,
        inst->qlen++;
 
        __build_packet_message(inst, skb, data_len, pf,
-                               hooknum, in, out, li, prefix, plen);
+                               hooknum, in, out, prefix, plen);
 
        if (inst->qlen >= qthreshold)
                __nfulnl_flush(inst);
@@ -866,19 +872,19 @@ static struct hlist_node *get_first(struct iter_state *st)
 
        for (st->bucket = 0; st->bucket < INSTANCE_BUCKETS; st->bucket++) {
                if (!hlist_empty(&instance_table[st->bucket]))
-                       return rcu_dereference_bh(instance_table[st->bucket].first);
+                       return rcu_dereference_bh(hlist_first_rcu(&instance_table[st->bucket]));
        }
        return NULL;
 }
 
 static struct hlist_node *get_next(struct iter_state *st, struct hlist_node *h)
 {
-       h = rcu_dereference_bh(h->next);
+       h = rcu_dereference_bh(hlist_next_rcu(h));
        while (!h) {
                if (++st->bucket >= INSTANCE_BUCKETS)
                        return NULL;
 
-               h = rcu_dereference_bh(instance_table[st->bucket].first);
+               h = rcu_dereference_bh(hlist_first_rcu(&instance_table[st->bucket]));
        }
        return h;
 }