aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/ip_fib.h1
-rw-r--r--net/ipv4/fib_frontend.c2
-rw-r--r--net/ipv4/route.c84
3 files changed, 47 insertions, 40 deletions
diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h
index 42ed96fab3f..fcc159a4ac1 100644
--- a/include/net/ip_fib.h
+++ b/include/net/ip_fib.h
@@ -216,6 +216,7 @@ extern void fib_select_default(const struct flowi *flp, struct fib_result *res);
216#endif /* CONFIG_IP_MULTIPLE_TABLES */ 216#endif /* CONFIG_IP_MULTIPLE_TABLES */
217 217
218/* Exported by fib_frontend.c */ 218/* Exported by fib_frontend.c */
219extern struct nla_policy rtm_ipv4_policy[];
219extern void ip_fib_init(void); 220extern void ip_fib_init(void);
220extern int inet_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg); 221extern int inet_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg);
221extern int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg); 222extern int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg);
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index d537c933abe..d0abeab16e6 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -453,7 +453,7 @@ int ip_rt_ioctl(unsigned int cmd, void *arg)
453 453
454#endif 454#endif
455 455
456static struct nla_policy rtm_ipv4_policy[RTA_MAX+1] __read_mostly = { 456struct nla_policy rtm_ipv4_policy[RTA_MAX+1] __read_mostly = {
457 [RTA_DST] = { .type = NLA_U32 }, 457 [RTA_DST] = { .type = NLA_U32 },
458 [RTA_SRC] = { .type = NLA_U32 }, 458 [RTA_SRC] = { .type = NLA_U32 },
459 [RTA_IIF] = { .type = NLA_U32 }, 459 [RTA_IIF] = { .type = NLA_U32 },
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 31b67059ac2..a4d4cb85a16 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -2737,18 +2737,24 @@ nla_put_failure:
2737 2737
2738int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg) 2738int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg)
2739{ 2739{
2740 struct rtattr **rta = arg; 2740 struct rtmsg *rtm;
2741 struct rtmsg *rtm = NLMSG_DATA(nlh); 2741 struct nlattr *tb[RTA_MAX+1];
2742 struct rtable *rt = NULL; 2742 struct rtable *rt = NULL;
2743 u32 dst = 0; 2743 u32 dst, src, iif;
2744 u32 src = 0; 2744 int err;
2745 int iif = 0;
2746 int err = -ENOBUFS;
2747 struct sk_buff *skb; 2745 struct sk_buff *skb;
2748 2746
2747 err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv4_policy);
2748 if (err < 0)
2749 goto errout;
2750
2751 rtm = nlmsg_data(nlh);
2752
2749 skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); 2753 skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
2750 if (!skb) 2754 if (skb == NULL) {
2751 goto out; 2755 err = -ENOBUFS;
2756 goto errout;
2757 }
2752 2758
2753 /* Reserve room for dummy headers, this skb can pass 2759 /* Reserve room for dummy headers, this skb can pass
2754 through good chunk of routing engine. 2760 through good chunk of routing engine.
@@ -2759,61 +2765,61 @@ int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg)
2759 skb->nh.iph->protocol = IPPROTO_ICMP; 2765 skb->nh.iph->protocol = IPPROTO_ICMP;
2760 skb_reserve(skb, MAX_HEADER + sizeof(struct iphdr)); 2766 skb_reserve(skb, MAX_HEADER + sizeof(struct iphdr));
2761 2767
2762 if (rta[RTA_SRC - 1]) 2768 src = tb[RTA_SRC] ? nla_get_u32(tb[RTA_SRC]) : 0;
2763 memcpy(&src, RTA_DATA(rta[RTA_SRC - 1]), 4); 2769 dst = tb[RTA_DST] ? nla_get_u32(tb[RTA_DST]) : 0;
2764 if (rta[RTA_DST - 1]) 2770 iif = tb[RTA_IIF] ? nla_get_u32(tb[RTA_IIF]) : 0;
2765 memcpy(&dst, RTA_DATA(rta[RTA_DST - 1]), 4);
2766 if (rta[RTA_IIF - 1])
2767 memcpy(&iif, RTA_DATA(rta[RTA_IIF - 1]), sizeof(int));
2768 2771
2769 if (iif) { 2772 if (iif) {
2770 struct net_device *dev = __dev_get_by_index(iif); 2773 struct net_device *dev;
2771 err = -ENODEV; 2774
2772 if (!dev) 2775 dev = __dev_get_by_index(iif);
2773 goto out_free; 2776 if (dev == NULL) {
2777 err = -ENODEV;
2778 goto errout_free;
2779 }
2780
2774 skb->protocol = htons(ETH_P_IP); 2781 skb->protocol = htons(ETH_P_IP);
2775 skb->dev = dev; 2782 skb->dev = dev;
2776 local_bh_disable(); 2783 local_bh_disable();
2777 err = ip_route_input(skb, dst, src, rtm->rtm_tos, dev); 2784 err = ip_route_input(skb, dst, src, rtm->rtm_tos, dev);
2778 local_bh_enable(); 2785 local_bh_enable();
2779 rt = (struct rtable*)skb->dst; 2786
2780 if (!err && rt->u.dst.error) 2787 rt = (struct rtable*) skb->dst;
2788 if (err == 0 && rt->u.dst.error)
2781 err = -rt->u.dst.error; 2789 err = -rt->u.dst.error;
2782 } else { 2790 } else {
2783 struct flowi fl = { .nl_u = { .ip4_u = { .daddr = dst, 2791 struct flowi fl = {
2784 .saddr = src, 2792 .nl_u = {
2785 .tos = rtm->rtm_tos } } }; 2793 .ip4_u = {
2786 int oif = 0; 2794 .daddr = dst,
2787 if (rta[RTA_OIF - 1]) 2795 .saddr = src,
2788 memcpy(&oif, RTA_DATA(rta[RTA_OIF - 1]), sizeof(int)); 2796 .tos = rtm->rtm_tos,
2789 fl.oif = oif; 2797 },
2798 },
2799 .oif = tb[RTA_OIF] ? nla_get_u32(tb[RTA_OIF]) : 0,
2800 };
2790 err = ip_route_output_key(&rt, &fl); 2801 err = ip_route_output_key(&rt, &fl);
2791 } 2802 }
2803
2792 if (err) 2804 if (err)
2793 goto out_free; 2805 goto errout_free;
2794 2806
2795 skb->dst = &rt->u.dst; 2807 skb->dst = &rt->u.dst;
2796 if (rtm->rtm_flags & RTM_F_NOTIFY) 2808 if (rtm->rtm_flags & RTM_F_NOTIFY)
2797 rt->rt_flags |= RTCF_NOTIFY; 2809 rt->rt_flags |= RTCF_NOTIFY;
2798 2810
2799 NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid;
2800
2801 err = rt_fill_info(skb, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq, 2811 err = rt_fill_info(skb, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq,
2802 RTM_NEWROUTE, 0, 0); 2812 RTM_NEWROUTE, 0, 0);
2803 if (!err) 2813 if (err <= 0)
2804 goto out_free; 2814 goto errout_free;
2805 if (err < 0) {
2806 err = -EMSGSIZE;
2807 goto out_free;
2808 }
2809 2815
2810 err = rtnl_unicast(skb, NETLINK_CB(in_skb).pid); 2816 err = rtnl_unicast(skb, NETLINK_CB(in_skb).pid);
2811out: 2817errout:
2812 return err; 2818 return err;
2813 2819
2814out_free: 2820errout_free:
2815 kfree_skb(skb); 2821 kfree_skb(skb);
2816 goto out; 2822 goto errout;
2817} 2823}
2818 2824
2819int ip_rt_dump(struct sk_buff *skb, struct netlink_callback *cb) 2825int ip_rt_dump(struct sk_buff *skb, struct netlink_callback *cb)