blob: bc6ef68fcea5b277cbde4c7984fd9cf5bf7ce7eb [file] [log] [blame]
/*
* linux/drivers/net/comcerto/fp_netfilter.c
*
* Copyright (C) 2010 Mindspeed Technologies, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/module.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <linux/netfilter.h>
#include <net/netfilter/nf_conntrack.h>
static unsigned int fp_netfilter_pre_routing(int family, unsigned int hooknum, struct sk_buff *skb)
{
struct nf_conn *ct;
u_int8_t protonum;
enum ip_conntrack_info ctinfo;
struct comcerto_fp_info *fp_info;
int dir;
ct = nf_ct_get(skb, &ctinfo);
if (!ct)
goto done;
protonum = nf_ct_protonum(ct);
if ((protonum != IPPROTO_TCP) && (protonum != IPPROTO_UDP) && (protonum != IPPROTO_IPIP))
goto done;
dir = CTINFO2DIR(ctinfo);
// if (printk_ratelimit())
// printk(KERN_INFO "ct: %lx, dir: %x, mark: %x, ifindex: %d iif: %d\n", (unsigned long)ct, dir, skb->mark, skb->dev->ifindex, skb->skb_iif);
/* We could also check for changes and notify userspace (or print message) */
if (dir == IP_CT_DIR_ORIGINAL) {
fp_info = &ct->fp_info[IP_CT_DIR_ORIGINAL];
} else {
fp_info = &ct->fp_info[IP_CT_DIR_REPLY];
}
if (fp_info->mark && (fp_info->mark != skb->mark))
if (printk_ratelimit())
printk(KERN_INFO "ct: mark changed %x, %x\n", fp_info->mark, skb->mark);
if (fp_info->ifindex && (fp_info->ifindex != skb->dev->ifindex))
if (printk_ratelimit())
printk(KERN_INFO "ct: ifindex changed %d, %d\n", fp_info->ifindex, skb->dev->ifindex);
if (fp_info->iif && (fp_info->iif != skb->skb_iif))
if (printk_ratelimit())
printk(KERN_INFO "ct: iif changed %d, %d\n", fp_info->iif, skb->skb_iif);
fp_info->mark = skb->mark;
fp_info->ifindex = skb->dev->ifindex;
fp_info->iif = skb->skb_iif;
done:
return NF_ACCEPT;
}
static unsigned int fp_ipv4_netfilter_pre_routing(unsigned int hooknum,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
return fp_netfilter_pre_routing(PF_INET, hooknum, skb);
}
static unsigned int fp_ipv6_netfilter_pre_routing(unsigned int hooknum,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
return fp_netfilter_pre_routing(PF_INET6, hooknum, skb);
}
static struct nf_hook_ops fp_netfilter_ops[] __read_mostly = {
{
.hook = fp_ipv4_netfilter_pre_routing,
.owner = THIS_MODULE,
.pf = NFPROTO_IPV4,
.hooknum = NF_INET_PRE_ROUTING,
.priority = NF_IP_PRI_LAST,
},
{
.hook = fp_ipv6_netfilter_pre_routing,
.owner = THIS_MODULE,
.pf = NFPROTO_IPV6,
.hooknum = NF_INET_PRE_ROUTING,
.priority = NF_IP_PRI_LAST,
},
};
static int __init fp_netfilter_init(void)
{
int rc;
rc = nf_register_hooks(fp_netfilter_ops, ARRAY_SIZE(fp_netfilter_ops));
if (rc < 0) {
printk(KERN_ERR "fp_netfilter_ops: can't register hooks.\n");
goto err0;
}
return 0;
err0:
return rc;
}
static void __exit fp_netfilter_exit(void)
{
nf_unregister_hooks(fp_netfilter_ops, ARRAY_SIZE(fp_netfilter_ops));
}
module_init(fp_netfilter_init);
module_exit(fp_netfilter_exit);