#include <linux/netfilter/nfnetlink.h>
MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
+MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_NETFILTER);
static char __initdata nfversion[] = "0.30";
#if 0
-#define DEBUGP printk
+#define DEBUGP(format, args...) \
+ printk(KERN_DEBUG "%s(%d):%s(): " format, __FILE__, \
+ __LINE__, __FUNCTION__, ## args)
#else
#define DEBUGP(format, args...)
#endif
{
DEBUGP("registering subsystem ID %u\n", n->subsys_id);
- /* If the netlink socket wasn't created, then fail */
- if (!nfnl)
- return -1;
-
nfnl_lock();
+ if (subsys_table[n->subsys_id]) {
+ nfnl_unlock();
+ return -EBUSY;
+ }
subsys_table[n->subsys_id] = n;
nfnl_unlock();
struct nlmsghdr *nlh, struct nfattr *cda[])
{
int min_len;
+ u_int16_t attr_count;
+ u_int8_t cb_id = NFNL_MSG_TYPE(nlh->nlmsg_type);
- memset(cda, 0, sizeof(struct nfattr *) * subsys->attr_count);
+ if (unlikely(cb_id >= subsys->cb_count)) {
+ DEBUGP("msgtype %u >= %u, returning\n",
+ cb_id, subsys->cb_count);
+ return -EINVAL;
+ }
- /* check attribute lengths. */
min_len = NLMSG_ALIGN(sizeof(struct nfgenmsg));
- if (nlh->nlmsg_len < min_len)
+ if (unlikely(nlh->nlmsg_len < min_len))
return -EINVAL;
- if (nlh->nlmsg_len > min_len) {
+ attr_count = subsys->cb[cb_id].attr_count;
+ memset(cda, 0, sizeof(struct nfattr *) * attr_count);
+
+ /* check attribute lengths. */
+ if (likely(nlh->nlmsg_len > min_len)) {
struct nfattr *attr = NFM_NFA(NLMSG_DATA(nlh));
int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len);
while (NFA_OK(attr, attrlen)) {
unsigned flavor = attr->nfa_type;
if (flavor) {
- if (flavor > subsys->attr_count)
+ if (flavor > attr_count)
return -EINVAL;
cda[flavor - 1] = attr;
}
attr = NFA_NEXT(attr, attrlen);
}
- } else
- return -EINVAL;
+ }
+
+ /* implicit: if nlmsg_len == min_len, we return 0, and an empty
+ * (zeroed) cda[] array. The message is valid, but empty. */
return 0;
}
int nfnetlink_send(struct sk_buff *skb, u32 pid, unsigned group, int echo)
{
- int allocation = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL;
+ unsigned int __nocast allocation =
+ in_interrupt() ? GFP_ATOMIC : GFP_KERNEL;
int err = 0;
- NETLINK_CB(skb).dst_groups = group;
+ NETLINK_CB(skb).dst_group = group;
if (echo)
atomic_inc(&skb->users);
netlink_broadcast(nfnl, skb, pid, group, allocation);
type = nlh->nlmsg_type;
ss = nfnetlink_get_subsys(type);
- if (!ss)
+ if (!ss) {
+#ifdef CONFIG_KMOD
+ /* don't call nfnl_shunlock, since it would reenter
+ * with further packet processing */
+ up(&nfnl_sem);
+ request_module("nfnetlink-subsys-%d", NFNL_SUBSYS_ID(type));
+ nfnl_shlock();
+ ss = nfnetlink_get_subsys(type);
+ if (!ss)
+#endif
goto err_inval;
+ }
nc = nfnetlink_find_client(type, ss);
if (!nc) {
}
{
- struct nfattr *cda[ss->attr_count];
+ u_int16_t attr_count =
+ ss->cb[NFNL_MSG_TYPE(nlh->nlmsg_type)].attr_count;
+ struct nfattr *cda[attr_count];
- memset(cda, 0, ss->attr_count*sizeof(struct nfattr *));
+ memset(cda, 0, sizeof(struct nfattr *) * attr_count);
err = nfnetlink_check_attributes(ss, nlh, cda);
if (err < 0)
goto err_inval;
+ DEBUGP("calling handler\n");
err = nc->call(nfnl, skb, nlh, cda, errp);
*errp = err;
return err;
}
err_inval:
+ DEBUGP("returning -EINVAL\n");
*errp = -EINVAL;
return -1;
}
kfree_skb(skb);
}
+ /* don't call nfnl_shunlock, since it would reenter
+ * with further packet processing */
up(&nfnl_sem);
} while(nfnl && nfnl->sk_receive_queue.qlen);
}
-void __exit nfnetlink_exit(void)
+static void __exit nfnetlink_exit(void)
{
printk("Removing netfilter NETLINK layer.\n");
sock_release(nfnl->sk_socket);
return;
}
-int __init nfnetlink_init(void)
+static int __init nfnetlink_init(void)
{
printk("Netfilter messages via NETLINK v%s.\n", nfversion);
- nfnl = netlink_kernel_create(NETLINK_NETFILTER, nfnetlink_rcv);
+ nfnl = netlink_kernel_create(NETLINK_NETFILTER, NFNLGRP_MAX,
+ nfnetlink_rcv, THIS_MODULE);
if (!nfnl) {
printk(KERN_ERR "cannot initialize nfnetlink!\n");
return -1;