netfilter: nfnetlink_queue: add skb info attribute
Florian Westphal [Fri, 19 Apr 2013 04:58:26 +0000 (04:58 +0000)]
Once we allow userspace to receive gso/gro packets, userspace
needs to be able to determine when checksums appear to be
broken, but are not.

NFQA_SKB_CSUMNOTREADY means 'checksums will be fixed in kernel
later, pretend they are ok'.

NFQA_SKB_GSO could be used for statistics, or to determine when
packet size exceeds mtu.

Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

include/uapi/linux/netfilter/nfnetlink_queue.h
net/netfilter/nfnetlink_queue_core.c

index 70ec8c2..0069da3 100644 (file)
@@ -45,6 +45,7 @@ enum nfqnl_attr_type {
        NFQA_CT,                        /* nf_conntrack_netlink.h */
        NFQA_CT_INFO,                   /* enum ip_conntrack_info */
        NFQA_CAP_LEN,                   /* __u32 length of captured packet */
+       NFQA_SKB_INFO,                  /* __u32 skb meta information */
 
        __NFQA_MAX
 };
@@ -98,4 +99,10 @@ enum nfqnl_attr_config {
 #define NFQA_CFG_F_CONNTRACK                   (1 << 1)
 #define NFQA_CFG_F_MAX                         (1 << 2)
 
+/* flags for NFQA_SKB_INFO */
+/* packet appears to have wrong checksums, but they are ok */
+#define NFQA_SKB_CSUMNOTREADY (1 << 0)
+/* packet is GSO (i.e., exceeds device mtu) */
+#define NFQA_SKB_GSO (1 << 1)
+
 #endif /* _NFNETLINK_QUEUE_H */
index edbae4c..d052cd6 100644 (file)
@@ -272,6 +272,18 @@ nfqnl_zcopy(struct sk_buff *to, const struct sk_buff *from, int len, int hlen)
        skb_shinfo(to)->nr_frags = j;
 }
 
+static int nfqnl_put_packet_info(struct sk_buff *nlskb, struct sk_buff *packet)
+{
+       __u32 flags = 0;
+
+       if (packet->ip_summed == CHECKSUM_PARTIAL)
+               flags = NFQA_SKB_CSUMNOTREADY;
+       if (skb_is_gso(packet))
+               flags |= NFQA_SKB_GSO;
+
+       return flags ? nla_put_be32(nlskb, NFQA_SKB_INFO, htonl(flags)) : 0;
+}
+
 static struct sk_buff *
 nfqnl_build_packet_message(struct nfqnl_instance *queue,
                           struct nf_queue_entry *entry,
@@ -301,6 +313,7 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue,
 #endif
                + nla_total_size(sizeof(u_int32_t))     /* mark */
                + nla_total_size(sizeof(struct nfqnl_msg_packet_hw))
+               + nla_total_size(sizeof(u_int32_t))     /* skbinfo */
                + nla_total_size(sizeof(u_int32_t));    /* cap_len */
 
        if (entskb->tstamp.tv64)
@@ -454,6 +467,9 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue,
        if (cap_len > 0 && nla_put_be32(skb, NFQA_CAP_LEN, htonl(cap_len)))
                goto nla_put_failure;
 
+       if (nfqnl_put_packet_info(skb, entskb))
+               goto nla_put_failure;
+
        if (data_len) {
                struct nlattr *nla;