/*
* This is a module which is used for queueing packets and communicating with
- * userspace via nfetlink.
+ * userspace via nfnetlink.
*
* (C) 2005 by Harald Welte <laforge@netfilter.org>
* (C) 2007 by Patrick McHardy <kaber@trash.net>
static struct nfqnl_instance *
instance_create(u_int16_t queue_num, int pid)
{
- struct nfqnl_instance *inst = NULL;
+ struct nfqnl_instance *inst;
unsigned int h;
+ int err;
spin_lock(&instances_lock);
- if (instance_lookup(queue_num))
+ if (instance_lookup(queue_num)) {
+ err = -EEXIST;
goto out_unlock;
+ }
inst = kzalloc(sizeof(*inst), GFP_ATOMIC);
- if (!inst)
+ if (!inst) {
+ err = -ENOMEM;
goto out_unlock;
+ }
inst->queue_num = queue_num;
inst->peer_pid = pid;
INIT_LIST_HEAD(&inst->queue_list);
INIT_RCU_HEAD(&inst->rcu);
- if (!try_module_get(THIS_MODULE))
+ if (!try_module_get(THIS_MODULE)) {
+ err = -EAGAIN;
goto out_free;
+ }
h = instance_hashfn(queue_num);
hlist_add_head_rcu(&inst->hlist, &instance_table[h]);
kfree(inst);
out_unlock:
spin_unlock(&instances_lock);
- return NULL;
+ return ERR_PTR(err);
}
static void nfqnl_flush(struct nfqnl_instance *queue, nfqnl_cmpfn cmpfn,
struct net_device *indev;
struct net_device *outdev;
- size = NLMSG_ALIGN(sizeof(struct nfgenmsg))
+ size = NLMSG_SPACE(sizeof(struct nfgenmsg))
+ nla_total_size(sizeof(struct nfqnl_msg_packet_hdr))
+ nla_total_size(sizeof(u_int32_t)) /* ifindex */
+ nla_total_size(sizeof(u_int32_t)) /* ifindex */
switch ((enum nfqnl_config_mode)queue->copy_mode) {
case NFQNL_COPY_META:
case NFQNL_COPY_NONE:
- data_len = 0;
break;
case NFQNL_COPY_PACKET:
if (data_len) {
struct nlattr *nla;
- int size = nla_attr_size(data_len);
+ int sz = nla_attr_size(data_len);
if (skb_tailroom(skb) < nla_total_size(data_len)) {
printk(KERN_WARNING "nf_queue: no tailroom!\n");
nla = (struct nlattr *)skb_put(skb, nla_total_size(data_len));
nla->nla_type = NFQA_PAYLOAD;
- nla->nla_len = size;
+ nla->nla_len = sz;
if (skb_copy_bits(entskb, 0, nla_data(nla), data_len))
BUG();
}
/* nfnetlink_unicast will either free the nskb or add it to a socket */
- err = nfnetlink_unicast(nskb, queue->peer_pid, MSG_DONTWAIT);
+ err = nfnetlink_unicast(nskb, &init_net, queue->peer_pid, MSG_DONTWAIT);
if (err < 0) {
queue->queue_user_dropped++;
goto err_out_unlock;
static int
nfqnl_mangle(void *data, int data_len, struct nf_queue_entry *e)
{
+ struct sk_buff *nskb;
int diff;
- int err;
diff = data_len - e->skb->len;
if (diff < 0) {
if (data_len > 0xFFFF)
return -EINVAL;
if (diff > skb_tailroom(e->skb)) {
- err = pskb_expand_head(e->skb, 0,
- diff - skb_tailroom(e->skb),
- GFP_ATOMIC);
- if (err) {
+ nskb = skb_copy_expand(e->skb, skb_headroom(e->skb),
+ diff, GFP_ATOMIC);
+ if (!nskb) {
printk(KERN_WARNING "nf_queue: OOM "
"in mangle, dropping packet\n");
- return err;
+ return -ENOMEM;
}
+ kfree_skb(e->skb);
+ e->skb = nskb;
}
skb_put(e->skb, diff);
}
{
struct net_device *dev = ptr;
- if (dev->nd_net != &init_net)
+ if (!net_eq(dev_net(dev), &init_net))
return NOTIFY_DONE;
/* Drop any packets associated with the downed device */
{
struct netlink_notify *n = ptr;
- if (event == NETLINK_URELEASE &&
- n->protocol == NETLINK_NETFILTER && n->pid) {
+ if (event == NETLINK_URELEASE && n->protocol == NETLINK_NETFILTER) {
int i;
/* destroy all instances for this pid */
static int
nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb,
- struct nlmsghdr *nlh, struct nlattr *nfqa[])
+ const struct nlmsghdr *nlh,
+ const struct nlattr * const nfqa[])
{
struct nfgenmsg *nfmsg = NLMSG_DATA(nlh);
u_int16_t queue_num = ntohs(nfmsg->res_id);
static int
nfqnl_recv_unsupp(struct sock *ctnl, struct sk_buff *skb,
- struct nlmsghdr *nlh, struct nlattr *nfqa[])
+ const struct nlmsghdr *nlh,
+ const struct nlattr * const nfqa[])
{
return -ENOTSUPP;
}
static int
nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
- struct nlmsghdr *nlh, struct nlattr *nfqa[])
+ const struct nlmsghdr *nlh,
+ const struct nlattr * const nfqa[])
{
struct nfgenmsg *nfmsg = NLMSG_DATA(nlh);
u_int16_t queue_num = ntohs(nfmsg->res_id);
/* Commands without queue context - might sleep */
switch (cmd->command) {
case NFQNL_CFG_CMD_PF_BIND:
- ret = nf_register_queue_handler(ntohs(cmd->pf),
- &nfqh);
- break;
+ return nf_register_queue_handler(ntohs(cmd->pf),
+ &nfqh);
case NFQNL_CFG_CMD_PF_UNBIND:
- ret = nf_unregister_queue_handler(ntohs(cmd->pf),
- &nfqh);
- break;
- default:
- break;
+ return nf_unregister_queue_handler(ntohs(cmd->pf),
+ &nfqh);
}
-
- if (ret < 0)
- return ret;
}
rcu_read_lock();
goto err_out_unlock;
}
queue = instance_create(queue_num, NETLINK_CB(skb).pid);
- if (!queue) {
- ret = -EINVAL;
+ if (IS_ERR(queue)) {
+ ret = PTR_ERR(queue);
goto err_out_unlock;
}
break;
case NFQNL_CFG_CMD_PF_UNBIND:
break;
default:
- ret = -EINVAL;
+ ret = -ENOTSUPP;
break;
}
}
}
static void *seq_start(struct seq_file *seq, loff_t *pos)
+ __acquires(instances_lock)
{
spin_lock(&instances_lock);
return get_idx(seq, *pos);
}
static void seq_stop(struct seq_file *s, void *v)
+ __releases(instances_lock)
{
spin_unlock(&instances_lock);
}
static int __init nfnetlink_queue_init(void)
{
int i, status = -ENOMEM;
-#ifdef CONFIG_PROC_FS
- struct proc_dir_entry *proc_nfqueue;
-#endif
for (i = 0; i < INSTANCE_BUCKETS; i++)
INIT_HLIST_HEAD(&instance_table[i]);
}
#ifdef CONFIG_PROC_FS
- proc_nfqueue = create_proc_entry("nfnetlink_queue", 0440,
- proc_net_netfilter);
- if (!proc_nfqueue)
+ if (!proc_create("nfnetlink_queue", 0440,
+ proc_net_netfilter, &nfqnl_file_ops))
goto cleanup_subsys;
- proc_nfqueue->proc_fops = &nfqnl_file_ops;
#endif
register_netdevice_notifier(&nfqnl_dev_notifier);
#endif
nfnetlink_subsys_unregister(&nfqnl_subsys);
netlink_unregister_notifier(&nfqnl_rtnl_notifier);
+
+ rcu_barrier(); /* Wait for completion of call_rcu()'s */
}
MODULE_DESCRIPTION("netfilter packet queue handler");