diff options
Diffstat (limited to 'net/ipv4/route.c')
-rw-r--r-- | net/ipv4/route.c | 166 |
1 files changed, 83 insertions, 83 deletions
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index b873cbcdd0b8..20ffe8e88c0f 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c | |||
@@ -2639,51 +2639,54 @@ static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event, | |||
2639 | { | 2639 | { |
2640 | struct rtable *rt = (struct rtable*)skb->dst; | 2640 | struct rtable *rt = (struct rtable*)skb->dst; |
2641 | struct rtmsg *r; | 2641 | struct rtmsg *r; |
2642 | struct nlmsghdr *nlh; | 2642 | struct nlmsghdr *nlh; |
2643 | unsigned char *b = skb->tail; | ||
2644 | struct rta_cacheinfo ci; | 2643 | struct rta_cacheinfo ci; |
2645 | #ifdef CONFIG_IP_MROUTE | 2644 | |
2646 | struct rtattr *eptr; | 2645 | nlh = nlmsg_put(skb, pid, seq, event, sizeof(*r), flags); |
2647 | #endif | 2646 | if (nlh == NULL) |
2648 | nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*r), flags); | 2647 | return -ENOBUFS; |
2649 | r = NLMSG_DATA(nlh); | 2648 | |
2649 | r = nlmsg_data(nlh); | ||
2650 | r->rtm_family = AF_INET; | 2650 | r->rtm_family = AF_INET; |
2651 | r->rtm_dst_len = 32; | 2651 | r->rtm_dst_len = 32; |
2652 | r->rtm_src_len = 0; | 2652 | r->rtm_src_len = 0; |
2653 | r->rtm_tos = rt->fl.fl4_tos; | 2653 | r->rtm_tos = rt->fl.fl4_tos; |
2654 | r->rtm_table = RT_TABLE_MAIN; | 2654 | r->rtm_table = RT_TABLE_MAIN; |
2655 | NLA_PUT_U32(skb, RTA_TABLE, RT_TABLE_MAIN); | ||
2655 | r->rtm_type = rt->rt_type; | 2656 | r->rtm_type = rt->rt_type; |
2656 | r->rtm_scope = RT_SCOPE_UNIVERSE; | 2657 | r->rtm_scope = RT_SCOPE_UNIVERSE; |
2657 | r->rtm_protocol = RTPROT_UNSPEC; | 2658 | r->rtm_protocol = RTPROT_UNSPEC; |
2658 | r->rtm_flags = (rt->rt_flags & ~0xFFFF) | RTM_F_CLONED; | 2659 | r->rtm_flags = (rt->rt_flags & ~0xFFFF) | RTM_F_CLONED; |
2659 | if (rt->rt_flags & RTCF_NOTIFY) | 2660 | if (rt->rt_flags & RTCF_NOTIFY) |
2660 | r->rtm_flags |= RTM_F_NOTIFY; | 2661 | r->rtm_flags |= RTM_F_NOTIFY; |
2661 | RTA_PUT(skb, RTA_DST, 4, &rt->rt_dst); | 2662 | |
2663 | NLA_PUT_U32(skb, RTA_DST, rt->rt_dst); | ||
2664 | |||
2662 | if (rt->fl.fl4_src) { | 2665 | if (rt->fl.fl4_src) { |
2663 | r->rtm_src_len = 32; | 2666 | r->rtm_src_len = 32; |
2664 | RTA_PUT(skb, RTA_SRC, 4, &rt->fl.fl4_src); | 2667 | NLA_PUT_U32(skb, RTA_SRC, rt->fl.fl4_src); |
2665 | } | 2668 | } |
2666 | if (rt->u.dst.dev) | 2669 | if (rt->u.dst.dev) |
2667 | RTA_PUT(skb, RTA_OIF, sizeof(int), &rt->u.dst.dev->ifindex); | 2670 | NLA_PUT_U32(skb, RTA_OIF, rt->u.dst.dev->ifindex); |
2668 | #ifdef CONFIG_NET_CLS_ROUTE | 2671 | #ifdef CONFIG_NET_CLS_ROUTE |
2669 | if (rt->u.dst.tclassid) | 2672 | if (rt->u.dst.tclassid) |
2670 | RTA_PUT(skb, RTA_FLOW, 4, &rt->u.dst.tclassid); | 2673 | NLA_PUT_U32(skb, RTA_FLOW, rt->u.dst.tclassid); |
2671 | #endif | 2674 | #endif |
2672 | #ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED | 2675 | #ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED |
2673 | if (rt->rt_multipath_alg != IP_MP_ALG_NONE) { | 2676 | if (rt->rt_multipath_alg != IP_MP_ALG_NONE) |
2674 | __u32 alg = rt->rt_multipath_alg; | 2677 | NLA_PUT_U32(skb, RTA_MP_ALGO, rt->rt_multipath_alg); |
2675 | |||
2676 | RTA_PUT(skb, RTA_MP_ALGO, 4, &alg); | ||
2677 | } | ||
2678 | #endif | 2678 | #endif |
2679 | if (rt->fl.iif) | 2679 | if (rt->fl.iif) |
2680 | RTA_PUT(skb, RTA_PREFSRC, 4, &rt->rt_spec_dst); | 2680 | NLA_PUT_U32(skb, RTA_PREFSRC, rt->rt_spec_dst); |
2681 | else if (rt->rt_src != rt->fl.fl4_src) | 2681 | else if (rt->rt_src != rt->fl.fl4_src) |
2682 | RTA_PUT(skb, RTA_PREFSRC, 4, &rt->rt_src); | 2682 | NLA_PUT_U32(skb, RTA_PREFSRC, rt->rt_src); |
2683 | |||
2683 | if (rt->rt_dst != rt->rt_gateway) | 2684 | if (rt->rt_dst != rt->rt_gateway) |
2684 | RTA_PUT(skb, RTA_GATEWAY, 4, &rt->rt_gateway); | 2685 | NLA_PUT_U32(skb, RTA_GATEWAY, rt->rt_gateway); |
2686 | |||
2685 | if (rtnetlink_put_metrics(skb, rt->u.dst.metrics) < 0) | 2687 | if (rtnetlink_put_metrics(skb, rt->u.dst.metrics) < 0) |
2686 | goto rtattr_failure; | 2688 | goto nla_put_failure; |
2689 | |||
2687 | ci.rta_lastuse = jiffies_to_clock_t(jiffies - rt->u.dst.lastuse); | 2690 | ci.rta_lastuse = jiffies_to_clock_t(jiffies - rt->u.dst.lastuse); |
2688 | ci.rta_used = rt->u.dst.__use; | 2691 | ci.rta_used = rt->u.dst.__use; |
2689 | ci.rta_clntref = atomic_read(&rt->u.dst.__refcnt); | 2692 | ci.rta_clntref = atomic_read(&rt->u.dst.__refcnt); |
@@ -2700,10 +2703,7 @@ static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event, | |||
2700 | ci.rta_tsage = xtime.tv_sec - rt->peer->tcp_ts_stamp; | 2703 | ci.rta_tsage = xtime.tv_sec - rt->peer->tcp_ts_stamp; |
2701 | } | 2704 | } |
2702 | } | 2705 | } |
2703 | #ifdef CONFIG_IP_MROUTE | 2706 | |
2704 | eptr = (struct rtattr*)skb->tail; | ||
2705 | #endif | ||
2706 | RTA_PUT(skb, RTA_CACHEINFO, sizeof(ci), &ci); | ||
2707 | if (rt->fl.iif) { | 2707 | if (rt->fl.iif) { |
2708 | #ifdef CONFIG_IP_MROUTE | 2708 | #ifdef CONFIG_IP_MROUTE |
2709 | u32 dst = rt->rt_dst; | 2709 | u32 dst = rt->rt_dst; |
@@ -2715,41 +2715,46 @@ static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event, | |||
2715 | if (!nowait) { | 2715 | if (!nowait) { |
2716 | if (err == 0) | 2716 | if (err == 0) |
2717 | return 0; | 2717 | return 0; |
2718 | goto nlmsg_failure; | 2718 | goto nla_put_failure; |
2719 | } else { | 2719 | } else { |
2720 | if (err == -EMSGSIZE) | 2720 | if (err == -EMSGSIZE) |
2721 | goto nlmsg_failure; | 2721 | goto nla_put_failure; |
2722 | ((struct rta_cacheinfo*)RTA_DATA(eptr))->rta_error = err; | 2722 | ci.rta_error = err; |
2723 | } | 2723 | } |
2724 | } | 2724 | } |
2725 | } else | 2725 | } else |
2726 | #endif | 2726 | #endif |
2727 | RTA_PUT(skb, RTA_IIF, sizeof(int), &rt->fl.iif); | 2727 | NLA_PUT_U32(skb, RTA_IIF, rt->fl.iif); |
2728 | } | 2728 | } |
2729 | 2729 | ||
2730 | nlh->nlmsg_len = skb->tail - b; | 2730 | NLA_PUT(skb, RTA_CACHEINFO, sizeof(ci), &ci); |
2731 | return skb->len; | 2731 | |
2732 | return nlmsg_end(skb, nlh); | ||
2732 | 2733 | ||
2733 | nlmsg_failure: | 2734 | nla_put_failure: |
2734 | rtattr_failure: | 2735 | return nlmsg_cancel(skb, nlh); |
2735 | skb_trim(skb, b - skb->data); | ||
2736 | return -1; | ||
2737 | } | 2736 | } |
2738 | 2737 | ||
2739 | int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg) | 2738 | int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg) |
2740 | { | 2739 | { |
2741 | struct rtattr **rta = arg; | 2740 | struct rtmsg *rtm; |
2742 | struct rtmsg *rtm = NLMSG_DATA(nlh); | 2741 | struct nlattr *tb[RTA_MAX+1]; |
2743 | struct rtable *rt = NULL; | 2742 | struct rtable *rt = NULL; |
2744 | u32 dst = 0; | 2743 | u32 dst, src, iif; |
2745 | u32 src = 0; | 2744 | int err; |
2746 | int iif = 0; | ||
2747 | int err = -ENOBUFS; | ||
2748 | struct sk_buff *skb; | 2745 | struct sk_buff *skb; |
2749 | 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 | |||
2750 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); | 2753 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); |
2751 | if (!skb) | 2754 | if (skb == NULL) { |
2752 | goto out; | 2755 | err = -ENOBUFS; |
2756 | goto errout; | ||
2757 | } | ||
2753 | 2758 | ||
2754 | /* Reserve room for dummy headers, this skb can pass | 2759 | /* Reserve room for dummy headers, this skb can pass |
2755 | through good chunk of routing engine. | 2760 | through good chunk of routing engine. |
@@ -2760,62 +2765,61 @@ int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg) | |||
2760 | skb->nh.iph->protocol = IPPROTO_ICMP; | 2765 | skb->nh.iph->protocol = IPPROTO_ICMP; |
2761 | skb_reserve(skb, MAX_HEADER + sizeof(struct iphdr)); | 2766 | skb_reserve(skb, MAX_HEADER + sizeof(struct iphdr)); |
2762 | 2767 | ||
2763 | if (rta[RTA_SRC - 1]) | 2768 | src = tb[RTA_SRC] ? nla_get_u32(tb[RTA_SRC]) : 0; |
2764 | memcpy(&src, RTA_DATA(rta[RTA_SRC - 1]), 4); | 2769 | dst = tb[RTA_DST] ? nla_get_u32(tb[RTA_DST]) : 0; |
2765 | if (rta[RTA_DST - 1]) | 2770 | iif = tb[RTA_IIF] ? nla_get_u32(tb[RTA_IIF]) : 0; |
2766 | memcpy(&dst, RTA_DATA(rta[RTA_DST - 1]), 4); | ||
2767 | if (rta[RTA_IIF - 1]) | ||
2768 | memcpy(&iif, RTA_DATA(rta[RTA_IIF - 1]), sizeof(int)); | ||
2769 | 2771 | ||
2770 | if (iif) { | 2772 | if (iif) { |
2771 | struct net_device *dev = __dev_get_by_index(iif); | 2773 | struct net_device *dev; |
2772 | err = -ENODEV; | 2774 | |
2773 | if (!dev) | 2775 | dev = __dev_get_by_index(iif); |
2774 | goto out_free; | 2776 | if (dev == NULL) { |
2777 | err = -ENODEV; | ||
2778 | goto errout_free; | ||
2779 | } | ||
2780 | |||
2775 | skb->protocol = htons(ETH_P_IP); | 2781 | skb->protocol = htons(ETH_P_IP); |
2776 | skb->dev = dev; | 2782 | skb->dev = dev; |
2777 | local_bh_disable(); | 2783 | local_bh_disable(); |
2778 | err = ip_route_input(skb, dst, src, rtm->rtm_tos, dev); | 2784 | err = ip_route_input(skb, dst, src, rtm->rtm_tos, dev); |
2779 | local_bh_enable(); | 2785 | local_bh_enable(); |
2780 | rt = (struct rtable*)skb->dst; | 2786 | |
2781 | if (!err && rt->u.dst.error) | 2787 | rt = (struct rtable*) skb->dst; |
2788 | if (err == 0 && rt->u.dst.error) | ||
2782 | err = -rt->u.dst.error; | 2789 | err = -rt->u.dst.error; |
2783 | } else { | 2790 | } else { |
2784 | struct flowi fl = { .nl_u = { .ip4_u = { .daddr = dst, | 2791 | struct flowi fl = { |
2785 | .saddr = src, | 2792 | .nl_u = { |
2786 | .tos = rtm->rtm_tos } } }; | 2793 | .ip4_u = { |
2787 | int oif = 0; | 2794 | .daddr = dst, |
2788 | if (rta[RTA_OIF - 1]) | 2795 | .saddr = src, |
2789 | memcpy(&oif, RTA_DATA(rta[RTA_OIF - 1]), sizeof(int)); | 2796 | .tos = rtm->rtm_tos, |
2790 | fl.oif = oif; | 2797 | }, |
2798 | }, | ||
2799 | .oif = tb[RTA_OIF] ? nla_get_u32(tb[RTA_OIF]) : 0, | ||
2800 | }; | ||
2791 | err = ip_route_output_key(&rt, &fl); | 2801 | err = ip_route_output_key(&rt, &fl); |
2792 | } | 2802 | } |
2803 | |||
2793 | if (err) | 2804 | if (err) |
2794 | goto out_free; | 2805 | goto errout_free; |
2795 | 2806 | ||
2796 | skb->dst = &rt->u.dst; | 2807 | skb->dst = &rt->u.dst; |
2797 | if (rtm->rtm_flags & RTM_F_NOTIFY) | 2808 | if (rtm->rtm_flags & RTM_F_NOTIFY) |
2798 | rt->rt_flags |= RTCF_NOTIFY; | 2809 | rt->rt_flags |= RTCF_NOTIFY; |
2799 | 2810 | ||
2800 | NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid; | ||
2801 | |||
2802 | 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, |
2803 | RTM_NEWROUTE, 0, 0); | 2812 | RTM_NEWROUTE, 0, 0); |
2804 | if (!err) | 2813 | if (err <= 0) |
2805 | goto out_free; | 2814 | goto errout_free; |
2806 | if (err < 0) { | ||
2807 | err = -EMSGSIZE; | ||
2808 | goto out_free; | ||
2809 | } | ||
2810 | 2815 | ||
2811 | err = netlink_unicast(rtnl, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT); | 2816 | err = rtnl_unicast(skb, NETLINK_CB(in_skb).pid); |
2812 | if (err > 0) | 2817 | errout: |
2813 | err = 0; | 2818 | return err; |
2814 | out: return err; | ||
2815 | 2819 | ||
2816 | out_free: | 2820 | errout_free: |
2817 | kfree_skb(skb); | 2821 | kfree_skb(skb); |
2818 | goto out; | 2822 | goto errout; |
2819 | } | 2823 | } |
2820 | 2824 | ||
2821 | int ip_rt_dump(struct sk_buff *skb, struct netlink_callback *cb) | 2825 | int ip_rt_dump(struct sk_buff *skb, struct netlink_callback *cb) |
@@ -3143,13 +3147,9 @@ int __init ip_rt_init(void) | |||
3143 | } | 3147 | } |
3144 | #endif | 3148 | #endif |
3145 | 3149 | ||
3146 | ipv4_dst_ops.kmem_cachep = kmem_cache_create("ip_dst_cache", | 3150 | ipv4_dst_ops.kmem_cachep = |
3147 | sizeof(struct rtable), | 3151 | kmem_cache_create("ip_dst_cache", sizeof(struct rtable), 0, |
3148 | 0, SLAB_HWCACHE_ALIGN, | 3152 | SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL); |
3149 | NULL, NULL); | ||
3150 | |||
3151 | if (!ipv4_dst_ops.kmem_cachep) | ||
3152 | panic("IP: failed to allocate ip_dst_cache\n"); | ||
3153 | 3153 | ||
3154 | rt_hash_table = (struct rt_hash_bucket *) | 3154 | rt_hash_table = (struct rt_hash_bucket *) |
3155 | alloc_large_system_hash("IP route cache", | 3155 | alloc_large_system_hash("IP route cache", |