#include <asm/atomic.h>
+#ifdef CONFIG_BRIDGE_NETFILTER
+#include "../bridge/br_private.h"
+#endif
+
#define NFQNL_QMAX_DEFAULT 1024
#if 0
static DEFINE_RWLOCK(instances_lock);
-u_int64_t htonll(u_int64_t in)
-{
- u_int64_t out;
- int i;
-
- for (i = 0; i < sizeof(u_int64_t); i++)
- ((u_int8_t *)&out)[sizeof(u_int64_t)-1] = ((u_int8_t *)&in)[i];
-
- return out;
-}
-
#define INSTANCE_BUCKETS 16
static struct hlist_head instance_table[INSTANCE_BUCKETS];
size = NLMSG_SPACE(sizeof(struct nfqnl_msg_packet_hdr))
+ NLMSG_SPACE(sizeof(u_int32_t)) /* ifindex */
+ NLMSG_SPACE(sizeof(u_int32_t)) /* ifindex */
+#ifdef CONFIG_BRIDGE_NETFILTER
+ + NLMSG_SPACE(sizeof(u_int32_t)) /* ifindex */
+ + NLMSG_SPACE(sizeof(u_int32_t)) /* ifindex */
+#endif
+ NLMSG_SPACE(sizeof(u_int32_t)) /* mark */
+ NLMSG_SPACE(sizeof(struct nfqnl_msg_packet_hw))
+ NLMSG_SPACE(sizeof(struct nfqnl_msg_packet_timestamp));
break;
case NFQNL_COPY_PACKET:
+ if (entry->skb->ip_summed == CHECKSUM_HW &&
+ (*errp = skb_checksum_help(entry->skb,
+ entry->info->outdev == NULL))) {
+ spin_unlock_bh(&queue->lock);
+ return NULL;
+ }
if (queue->copy_range == 0
|| queue->copy_range > entry->skb->len)
data_len = entry->skb->len;
if (entry->info->indev) {
tmp_uint = htonl(entry->info->indev->ifindex);
+#ifndef CONFIG_BRIDGE_NETFILTER
NFA_PUT(skb, NFQA_IFINDEX_INDEV, sizeof(tmp_uint), &tmp_uint);
+#else
+ if (entry->info->pf == PF_BRIDGE) {
+ /* Case 1: indev is physical input device, we need to
+ * look for bridge group (when called from
+ * netfilter_bridge) */
+ NFA_PUT(skb, NFQA_IFINDEX_PHYSINDEV, sizeof(tmp_uint),
+ &tmp_uint);
+ /* this is the bridge group "brX" */
+ tmp_uint = htonl(entry->info->indev->br_port->br->dev->ifindex);
+ NFA_PUT(skb, NFQA_IFINDEX_INDEV, sizeof(tmp_uint),
+ &tmp_uint);
+ } else {
+ /* Case 2: indev is bridge group, we need to look for
+ * physical device (when called from ipv4) */
+ NFA_PUT(skb, NFQA_IFINDEX_INDEV, sizeof(tmp_uint),
+ &tmp_uint);
+ if (entry->skb->nf_bridge
+ && entry->skb->nf_bridge->physindev) {
+ tmp_uint = htonl(entry->skb->nf_bridge->physindev->ifindex);
+ NFA_PUT(skb, NFQA_IFINDEX_PHYSINDEV,
+ sizeof(tmp_uint), &tmp_uint);
+ }
+ }
+#endif
}
if (entry->info->outdev) {
tmp_uint = htonl(entry->info->outdev->ifindex);
+#ifndef CONFIG_BRIDGE_NETFILTER
NFA_PUT(skb, NFQA_IFINDEX_OUTDEV, sizeof(tmp_uint), &tmp_uint);
+#else
+ if (entry->info->pf == PF_BRIDGE) {
+ /* Case 1: outdev is physical output device, we need to
+ * look for bridge group (when called from
+ * netfilter_bridge) */
+ NFA_PUT(skb, NFQA_IFINDEX_PHYSOUTDEV, sizeof(tmp_uint),
+ &tmp_uint);
+ /* this is the bridge group "brX" */
+ tmp_uint = htonl(entry->info->outdev->br_port->br->dev->ifindex);
+ NFA_PUT(skb, NFQA_IFINDEX_OUTDEV, sizeof(tmp_uint),
+ &tmp_uint);
+ } else {
+ /* Case 2: outdev is bridge group, we need to look for
+ * physical output device (when called from ipv4) */
+ NFA_PUT(skb, NFQA_IFINDEX_OUTDEV, sizeof(tmp_uint),
+ &tmp_uint);
+ if (entry->skb->nf_bridge
+ && entry->skb->nf_bridge->physoutdev) {
+ tmp_uint = htonl(entry->skb->nf_bridge->physoutdev->ifindex);
+ NFA_PUT(skb, NFQA_IFINDEX_PHYSOUTDEV,
+ sizeof(tmp_uint), &tmp_uint);
+ }
+ }
+#endif
}
if (entry->skb->nfmark) {
NFA_PUT(skb, NFQA_HWADDR, sizeof(phw), &phw);
}
- if (entry->skb->stamp.tv_sec) {
+ if (entry->skb->tstamp.off_sec) {
struct nfqnl_msg_packet_timestamp ts;
- ts.sec = htonll(entry->skb->stamp.tv_sec);
- ts.usec = htonll(entry->skb->stamp.tv_usec);
+ ts.sec = cpu_to_be64(skb_tv_base.tv_sec + entry->skb->tstamp.off_sec);
+ ts.usec = cpu_to_be64(skb_tv_base.tv_usec + entry->skb->tstamp.off_usec);
NFA_PUT(skb, NFQA_TIMESTAMP, sizeof(ts), &ts);
}
if (!skb_make_writable(&e->skb, data_len))
return -ENOMEM;
memcpy(e->skb->data, data, data_len);
-
+ e->skb->ip_summed = CHECKSUM_NONE;
return 0;
}
[NFQA_CFG_PARAMS-1] = sizeof(struct nfqnl_msg_config_params),
};
+static struct nf_queue_handler nfqh = {
+ .name = "nf_queue",
+ .outfn = &nfqnl_enqueue_packet,
+};
+
static int
nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
struct nlmsghdr *nlh, struct nfattr *nfqa[], int *errp)
case NFQNL_CFG_CMD_PF_BIND:
QDEBUG("registering queue handler for pf=%u\n",
ntohs(cmd->pf));
- ret = nf_register_queue_handler(ntohs(cmd->pf),
- nfqnl_enqueue_packet,
- NULL);
-
+ ret = nf_register_queue_handler(ntohs(cmd->pf), &nfqh);
break;
case NFQNL_CFG_CMD_PF_UNBIND:
QDEBUG("unregistering queue handler for pf=%u\n",
static struct nfnl_callback nfqnl_cb[NFQNL_MSG_MAX] = {
[NFQNL_MSG_PACKET] = { .call = nfqnl_recv_unsupp,
+ .attr_count = NFQA_MAX,
.cap_required = CAP_NET_ADMIN },
[NFQNL_MSG_VERDICT] = { .call = nfqnl_recv_verdict,
+ .attr_count = NFQA_MAX,
.cap_required = CAP_NET_ADMIN },
[NFQNL_MSG_CONFIG] = { .call = nfqnl_recv_config,
+ .attr_count = NFQA_CFG_MAX,
.cap_required = CAP_NET_ADMIN },
};
.name = "nf_queue",
.subsys_id = NFNL_SUBSYS_QUEUE,
.cb_count = NFQNL_MSG_MAX,
- .attr_count = NFQA_MAX,
.cb = nfqnl_cb,
};
return status;
cleanup:
- nf_unregister_queue_handlers(nfqnl_enqueue_packet);
+ nf_unregister_queue_handlers(&nfqh);
unregister_netdevice_notifier(&nfqnl_dev_notifier);
#ifdef CONFIG_PROC_FS
remove_proc_entry("nfnetlink_queue", proc_net_netfilter);