* Ville Nuorvala <vnuorval@tcs.hut.fi>
*/
-#include <linux/config.h>
#include <linux/netdevice.h>
#include <net/fib_rules.h>
if (arg.rule)
fib_rule_put(arg.rule);
- return (struct dst_entry *) arg.result;
+ if (arg.result)
+ return arg.result;
+
+ dst_hold(&ip6_null_entry.u.dst);
+ return &ip6_null_entry.u.dst;
}
-int fib6_rule_action(struct fib_rule *rule, struct flowi *flp,
- int flags, struct fib_lookup_arg *arg)
+static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp,
+ int flags, struct fib_lookup_arg *arg)
{
struct rt6_info *rt = NULL;
struct fib6_table *table;
if (rt != &ip6_null_entry)
goto out;
-
dst_release(&rt->u.dst);
+ rt = NULL;
+ goto out;
+
discard_pkt:
dst_hold(&rt->u.dst);
out:
{
struct fib6_rule *r = (struct fib6_rule *) rule;
- if (!ipv6_prefix_equal(&fl->fl6_dst, &r->dst.addr, r->dst.plen))
+ if (r->dst.plen &&
+ !ipv6_prefix_equal(&fl->fl6_dst, &r->dst.addr, r->dst.plen))
return 0;
- if ((flags & RT6_F_HAS_SADDR) &&
- !ipv6_prefix_equal(&fl->fl6_src, &r->src.addr, r->src.plen))
+ if (r->src.plen) {
+ if (!(flags & RT6_LOOKUP_F_HAS_SADDR) ||
+ !ipv6_prefix_equal(&fl->fl6_src, &r->src.addr, r->src.plen))
+ return 0;
+ }
+
+ if (r->tclass && r->tclass != ((ntohl(fl->fl6_flowlabel) >> 20) & 0xff))
return 0;
return 1;
}
-static struct nla_policy fib6_rule_policy[RTA_MAX+1] __read_mostly = {
- [FRA_IFNAME] = { .type = NLA_STRING },
- [FRA_PRIORITY] = { .type = NLA_U32 },
- [FRA_SRC] = { .minlen = sizeof(struct in6_addr) },
- [FRA_DST] = { .minlen = sizeof(struct in6_addr) },
+static struct nla_policy fib6_rule_policy[FRA_MAX+1] __read_mostly = {
+ FRA_GENERIC_POLICY,
};
static int fib6_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
int err = -EINVAL;
struct fib6_rule *rule6 = (struct fib6_rule *) rule;
- if (frh->src_len > 128 || frh->dst_len > 128 ||
- (frh->tos & ~IPV6_FLOWINFO_MASK))
- goto errout;
-
if (rule->action == FR_ACT_TO_TBL) {
if (rule->table == RT6_TABLE_UNSPEC)
goto errout;
}
}
- if (tb[FRA_SRC])
+ if (frh->src_len)
nla_memcpy(&rule6->src.addr, tb[FRA_SRC],
sizeof(struct in6_addr));
- if (tb[FRA_DST])
+ if (frh->dst_len)
nla_memcpy(&rule6->dst.addr, tb[FRA_DST],
sizeof(struct in6_addr));
if (frh->tos && (rule6->tclass != frh->tos))
return 0;
- if (tb[FRA_SRC] &&
+ if (frh->src_len &&
nla_memcmp(tb[FRA_SRC], &rule6->src.addr, sizeof(struct in6_addr)))
return 0;
- if (tb[FRA_DST] &&
+ if (frh->dst_len &&
nla_memcmp(tb[FRA_DST], &rule6->dst.addr, sizeof(struct in6_addr)))
return 0;
return 0x3FFF;
}
+static size_t fib6_rule_nlmsg_payload(struct fib_rule *rule)
+{
+ return nla_total_size(16) /* dst */
+ + nla_total_size(16); /* src */
+}
+
static struct fib_rules_ops fib6_rules_ops = {
.family = AF_INET6,
.rule_size = sizeof(struct fib6_rule),
+ .addr_size = sizeof(struct in6_addr),
.action = fib6_rule_action,
.match = fib6_rule_match,
.configure = fib6_rule_configure,
.compare = fib6_rule_compare,
.fill = fib6_rule_fill,
.default_pref = fib6_rule_default_pref,
+ .nlmsg_payload = fib6_rule_nlmsg_payload,
.nlgroup = RTNLGRP_IPV6_RULE,
.policy = fib6_rule_policy,
.rules_list = &fib6_rules,