|
@@ -3607,11 +3607,13 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
|
|
{
|
|
{
|
|
struct net *net = sock_net(in_skb->sk);
|
|
struct net *net = sock_net(in_skb->sk);
|
|
struct nlattr *tb[RTA_MAX+1];
|
|
struct nlattr *tb[RTA_MAX+1];
|
|
|
|
+ int err, iif = 0, oif = 0;
|
|
|
|
+ struct dst_entry *dst;
|
|
struct rt6_info *rt;
|
|
struct rt6_info *rt;
|
|
struct sk_buff *skb;
|
|
struct sk_buff *skb;
|
|
struct rtmsg *rtm;
|
|
struct rtmsg *rtm;
|
|
struct flowi6 fl6;
|
|
struct flowi6 fl6;
|
|
- int err, iif = 0, oif = 0;
|
|
|
|
|
|
+ bool fibmatch;
|
|
|
|
|
|
err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy,
|
|
err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy,
|
|
extack);
|
|
extack);
|
|
@@ -3622,6 +3624,7 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
|
|
memset(&fl6, 0, sizeof(fl6));
|
|
memset(&fl6, 0, sizeof(fl6));
|
|
rtm = nlmsg_data(nlh);
|
|
rtm = nlmsg_data(nlh);
|
|
fl6.flowlabel = ip6_make_flowinfo(rtm->rtm_tos, 0);
|
|
fl6.flowlabel = ip6_make_flowinfo(rtm->rtm_tos, 0);
|
|
|
|
+ fibmatch = !!(rtm->rtm_flags & RTM_F_FIB_MATCH);
|
|
|
|
|
|
if (tb[RTA_SRC]) {
|
|
if (tb[RTA_SRC]) {
|
|
if (nla_len(tb[RTA_SRC]) < sizeof(struct in6_addr))
|
|
if (nla_len(tb[RTA_SRC]) < sizeof(struct in6_addr))
|
|
@@ -3667,12 +3670,23 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
|
|
if (!ipv6_addr_any(&fl6.saddr))
|
|
if (!ipv6_addr_any(&fl6.saddr))
|
|
flags |= RT6_LOOKUP_F_HAS_SADDR;
|
|
flags |= RT6_LOOKUP_F_HAS_SADDR;
|
|
|
|
|
|
- rt = (struct rt6_info *)ip6_route_input_lookup(net, dev, &fl6,
|
|
|
|
- flags);
|
|
|
|
|
|
+ if (!fibmatch)
|
|
|
|
+ dst = ip6_route_input_lookup(net, dev, &fl6, flags);
|
|
} else {
|
|
} else {
|
|
fl6.flowi6_oif = oif;
|
|
fl6.flowi6_oif = oif;
|
|
|
|
|
|
- rt = (struct rt6_info *)ip6_route_output(net, NULL, &fl6);
|
|
|
|
|
|
+ if (!fibmatch)
|
|
|
|
+ dst = ip6_route_output(net, NULL, &fl6);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (fibmatch)
|
|
|
|
+ dst = ip6_route_lookup(net, &fl6, 0);
|
|
|
|
+
|
|
|
|
+ rt = container_of(dst, struct rt6_info, dst);
|
|
|
|
+ if (rt->dst.error) {
|
|
|
|
+ err = rt->dst.error;
|
|
|
|
+ ip6_rt_put(rt);
|
|
|
|
+ goto errout;
|
|
}
|
|
}
|
|
|
|
|
|
if (rt == net->ipv6.ip6_null_entry) {
|
|
if (rt == net->ipv6.ip6_null_entry) {
|
|
@@ -3689,10 +3703,14 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
|
|
}
|
|
}
|
|
|
|
|
|
skb_dst_set(skb, &rt->dst);
|
|
skb_dst_set(skb, &rt->dst);
|
|
-
|
|
|
|
- err = rt6_fill_node(net, skb, rt, &fl6.daddr, &fl6.saddr, iif,
|
|
|
|
- RTM_NEWROUTE, NETLINK_CB(in_skb).portid,
|
|
|
|
- nlh->nlmsg_seq, 0);
|
|
|
|
|
|
+ if (fibmatch)
|
|
|
|
+ err = rt6_fill_node(net, skb, rt, NULL, NULL, iif,
|
|
|
|
+ RTM_NEWROUTE, NETLINK_CB(in_skb).portid,
|
|
|
|
+ nlh->nlmsg_seq, 0);
|
|
|
|
+ else
|
|
|
|
+ err = rt6_fill_node(net, skb, rt, &fl6.daddr, &fl6.saddr, iif,
|
|
|
|
+ RTM_NEWROUTE, NETLINK_CB(in_skb).portid,
|
|
|
|
+ nlh->nlmsg_seq, 0);
|
|
if (err < 0) {
|
|
if (err < 0) {
|
|
kfree_skb(skb);
|
|
kfree_skb(skb);
|
|
goto errout;
|
|
goto errout;
|