pppoe_proto(skb) == htons(PPP_IPV6) && \
brnf_filter_pppoe_tagged)
-/* We need these fake structures to make netfilter happy --
- * lots of places assume that skb->dst != NULL, which isn't
- * all that unreasonable.
- *
+/*
+ * Initialize bogus route table used to keep netfilter happy.
* Currently, we fill in the PMTU entry because netfilter
* refragmentation needs it, and the rt_flags entry because
* ipt_REJECT needs it. Future netfilter modules might
- * require us to fill additional fields. */
-static struct net_device __fake_net_device = {
- .hard_header_len = ETH_HLEN
-};
+ * require us to fill additional fields.
+ */
+void br_netfilter_rtable_init(struct net_bridge *br)
+{
+ struct rtable *rt = &br->fake_rtable;
-static struct rtable __fake_rtable = {
- .u = {
- .dst = {
- .__refcnt = ATOMIC_INIT(1),
- .dev = &__fake_net_device,
- .path = &__fake_rtable.u.dst,
- .metrics = {[RTAX_MTU - 1] = 1500},
- .flags = DST_NOXFRM,
- }
- },
- .rt_flags = 0,
-};
+ atomic_set(&rt->u.dst.__refcnt, 1);
+ rt->u.dst.dev = br->dev;
+ rt->u.dst.path = &rt->u.dst;
+ rt->u.dst.metrics[RTAX_MTU - 1] = 1500;
+ rt->u.dst.flags = DST_NOXFRM;
+}
+
+static inline struct rtable *bridge_parent_rtable(const struct net_device *dev)
+{
+ struct net_bridge_port *port = rcu_dereference(dev->br_port);
+
+ return port ? &port->br->fake_rtable : NULL;
+}
static inline struct net_device *bridge_parent(const struct net_device *dev)
{
}
nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING;
- skb->dst = (struct dst_entry *)&__fake_rtable;
- dst_hold(skb->dst);
+ skb->rtable = bridge_parent_rtable(nf_bridge->physindev);
+ if (!skb->rtable) {
+ kfree_skb(skb);
+ return 0;
+ }
+ dst_hold(&skb->rtable->u.dst);
skb->dev = nf_bridge->physindev;
nf_bridge_push_encap_header(skb);
if (err != -EHOSTUNREACH || !in_dev || IN_DEV_FORWARD(in_dev))
goto free_skb;
- if (!ip_route_output_key(&rt, &fl)) {
+ if (!ip_route_output_key(&init_net, &rt, &fl)) {
/* - Bridged-and-DNAT'ed traffic doesn't
* require ip_forwarding. */
if (((struct dst_entry *)rt)->dev == dev) {
skb->pkt_type = PACKET_HOST;
}
} else {
- skb->dst = (struct dst_entry *)&__fake_rtable;
- dst_hold(skb->dst);
+ skb->rtable = bridge_parent_rtable(nf_bridge->physindev);
+ if (!skb->rtable) {
+ kfree_skb(skb);
+ return 0;
+ }
+ dst_hold(&skb->rtable->u.dst);
}
skb->dev = nf_bridge->physindev;
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
- if (skb->dst == (struct dst_entry *)&__fake_rtable) {
- dst_release(skb->dst);
- skb->dst = NULL;
+ if (skb->rtable && skb->rtable == bridge_parent_rtable(in)) {
+ dst_release(&skb->rtable->u.dst);
+ skb->rtable = NULL;
}
return NF_ACCEPT;
{
struct nf_bridge_info *nf_bridge;
struct net_device *parent;
- int pf;
+ u_int8_t pf;
if (!skb->nf_bridge)
return NF_ACCEPT;
{
struct nf_bridge_info *nf_bridge = skb->nf_bridge;
struct net_device *realoutdev = bridge_parent(skb->dev);
- int pf;
+ u_int8_t pf;
#ifdef CONFIG_NETFILTER_DEBUG
/* Be very paranoid. This probably won't happen anymore, but let's
nf_bridge_pull_encap_header(skb);
nf_bridge_save_header(skb);
-#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
- if (nf_bridge->netoutdev)
- realoutdev = nf_bridge->netoutdev;
-#endif
NF_HOOK(pf, NF_INET_POST_ROUTING, skb, NULL, realoutdev,
br_nf_dev_queue_xmit);
* PF_BRIDGE/NF_BR_LOCAL_OUT functions don't get bridged traffic as input.
* For br_nf_post_routing, we need (prio = NF_BR_PRI_LAST), because
* ip_refrag() can return NF_STOLEN. */
-static struct nf_hook_ops br_nf_ops[] = {
+static struct nf_hook_ops br_nf_ops[] __read_mostly = {
{ .hook = br_nf_pre_routing,
.owner = THIS_MODULE,
.pf = PF_BRIDGE,
{ .ctl_name = 0 }
};
-static ctl_table brnf_bridge_table[] = {
- {
- .ctl_name = NET_BRIDGE,
- .procname = "bridge",
- .mode = 0555,
- .child = brnf_table,
- },
- { .ctl_name = 0 }
-};
-
-static ctl_table brnf_net_table[] = {
- {
- .ctl_name = CTL_NET,
- .procname = "net",
- .mode = 0555,
- .child = brnf_bridge_table,
- },
- { .ctl_name = 0 }
+static struct ctl_path brnf_path[] = {
+ { .procname = "net", .ctl_name = CTL_NET, },
+ { .procname = "bridge", .ctl_name = NET_BRIDGE, },
+ { }
};
#endif
if (ret < 0)
return ret;
#ifdef CONFIG_SYSCTL
- brnf_sysctl_header = register_sysctl_table(brnf_net_table);
+ brnf_sysctl_header = register_sysctl_paths(brnf_path, brnf_table);
if (brnf_sysctl_header == NULL) {
printk(KERN_WARNING
"br_netfilter: can't register to sysctl.\n");