diff options
| author | John W. Linville <linville@tuxdriver.com> | 2006-08-04 14:24:15 -0400 |
|---|---|---|
| committer | John W. Linville <linville@tuxdriver.com> | 2006-08-04 14:24:15 -0400 |
| commit | 71bfe47f023c55c322607939b786ce0a44627dfc (patch) | |
| tree | f59c37feb00f1df2e0f4ec282ae9c80ad6bb0cdc /net/ipv6 | |
| parent | 73c1ac1e3b6c989b9b5f7b2313ac590a1c3b6d6a (diff) | |
| parent | efe78cda3596f8a6d1c2d4a6b1a221bafa3e1a48 (diff) | |
Merge branch 'from-linus' into upstream
Diffstat (limited to 'net/ipv6')
| -rw-r--r-- | net/ipv6/addrconf.c | 174 | ||||
| -rw-r--r-- | net/ipv6/af_inet6.c | 2 | ||||
| -rw-r--r-- | net/ipv6/inet6_connection_sock.c | 2 | ||||
| -rw-r--r-- | net/ipv6/ip6_output.c | 129 | ||||
| -rw-r--r-- | net/ipv6/route.c | 7 | ||||
| -rw-r--r-- | net/ipv6/tcp_ipv6.c | 6 | ||||
| -rw-r--r-- | net/ipv6/udp.c | 2 | ||||
| -rw-r--r-- | net/ipv6/xfrm6_output.c | 2 |
8 files changed, 266 insertions, 58 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 2316a4315a18..8ea1e36bf8eb 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
| @@ -1869,15 +1869,21 @@ err_exit: | |||
| 1869 | /* | 1869 | /* |
| 1870 | * Manual configuration of address on an interface | 1870 | * Manual configuration of address on an interface |
| 1871 | */ | 1871 | */ |
| 1872 | static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen) | 1872 | static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen, |
| 1873 | __u32 prefered_lft, __u32 valid_lft) | ||
| 1873 | { | 1874 | { |
| 1874 | struct inet6_ifaddr *ifp; | 1875 | struct inet6_ifaddr *ifp; |
| 1875 | struct inet6_dev *idev; | 1876 | struct inet6_dev *idev; |
| 1876 | struct net_device *dev; | 1877 | struct net_device *dev; |
| 1878 | __u8 ifa_flags = 0; | ||
| 1877 | int scope; | 1879 | int scope; |
| 1878 | 1880 | ||
| 1879 | ASSERT_RTNL(); | 1881 | ASSERT_RTNL(); |
| 1880 | 1882 | ||
| 1883 | /* check the lifetime */ | ||
| 1884 | if (!valid_lft || prefered_lft > valid_lft) | ||
| 1885 | return -EINVAL; | ||
| 1886 | |||
| 1881 | if ((dev = __dev_get_by_index(ifindex)) == NULL) | 1887 | if ((dev = __dev_get_by_index(ifindex)) == NULL) |
| 1882 | return -ENODEV; | 1888 | return -ENODEV; |
| 1883 | 1889 | ||
| @@ -1889,10 +1895,29 @@ static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen) | |||
| 1889 | 1895 | ||
| 1890 | scope = ipv6_addr_scope(pfx); | 1896 | scope = ipv6_addr_scope(pfx); |
| 1891 | 1897 | ||
| 1892 | ifp = ipv6_add_addr(idev, pfx, plen, scope, IFA_F_PERMANENT); | 1898 | if (valid_lft == INFINITY_LIFE_TIME) |
| 1899 | ifa_flags |= IFA_F_PERMANENT; | ||
| 1900 | else if (valid_lft >= 0x7FFFFFFF/HZ) | ||
| 1901 | valid_lft = 0x7FFFFFFF/HZ; | ||
| 1902 | |||
| 1903 | if (prefered_lft == 0) | ||
| 1904 | ifa_flags |= IFA_F_DEPRECATED; | ||
| 1905 | else if ((prefered_lft >= 0x7FFFFFFF/HZ) && | ||
| 1906 | (prefered_lft != INFINITY_LIFE_TIME)) | ||
| 1907 | prefered_lft = 0x7FFFFFFF/HZ; | ||
| 1908 | |||
| 1909 | ifp = ipv6_add_addr(idev, pfx, plen, scope, ifa_flags); | ||
| 1910 | |||
| 1893 | if (!IS_ERR(ifp)) { | 1911 | if (!IS_ERR(ifp)) { |
| 1912 | spin_lock(&ifp->lock); | ||
| 1913 | ifp->valid_lft = valid_lft; | ||
| 1914 | ifp->prefered_lft = prefered_lft; | ||
| 1915 | ifp->tstamp = jiffies; | ||
| 1916 | spin_unlock(&ifp->lock); | ||
| 1917 | |||
| 1894 | addrconf_dad_start(ifp, 0); | 1918 | addrconf_dad_start(ifp, 0); |
| 1895 | in6_ifa_put(ifp); | 1919 | in6_ifa_put(ifp); |
| 1920 | addrconf_verify(0); | ||
| 1896 | return 0; | 1921 | return 0; |
| 1897 | } | 1922 | } |
| 1898 | 1923 | ||
| @@ -1945,7 +1970,8 @@ int addrconf_add_ifaddr(void __user *arg) | |||
| 1945 | return -EFAULT; | 1970 | return -EFAULT; |
| 1946 | 1971 | ||
| 1947 | rtnl_lock(); | 1972 | rtnl_lock(); |
| 1948 | err = inet6_addr_add(ireq.ifr6_ifindex, &ireq.ifr6_addr, ireq.ifr6_prefixlen); | 1973 | err = inet6_addr_add(ireq.ifr6_ifindex, &ireq.ifr6_addr, ireq.ifr6_prefixlen, |
| 1974 | INFINITY_LIFE_TIME, INFINITY_LIFE_TIME); | ||
| 1949 | rtnl_unlock(); | 1975 | rtnl_unlock(); |
| 1950 | return err; | 1976 | return err; |
| 1951 | } | 1977 | } |
| @@ -2771,12 +2797,16 @@ restart: | |||
| 2771 | ifp->idev->nd_parms->retrans_time / HZ; | 2797 | ifp->idev->nd_parms->retrans_time / HZ; |
| 2772 | #endif | 2798 | #endif |
| 2773 | 2799 | ||
| 2774 | if (age >= ifp->valid_lft) { | 2800 | if (ifp->valid_lft != INFINITY_LIFE_TIME && |
| 2801 | age >= ifp->valid_lft) { | ||
| 2775 | spin_unlock(&ifp->lock); | 2802 | spin_unlock(&ifp->lock); |
| 2776 | in6_ifa_hold(ifp); | 2803 | in6_ifa_hold(ifp); |
| 2777 | read_unlock(&addrconf_hash_lock); | 2804 | read_unlock(&addrconf_hash_lock); |
| 2778 | ipv6_del_addr(ifp); | 2805 | ipv6_del_addr(ifp); |
| 2779 | goto restart; | 2806 | goto restart; |
| 2807 | } else if (ifp->prefered_lft == INFINITY_LIFE_TIME) { | ||
| 2808 | spin_unlock(&ifp->lock); | ||
| 2809 | continue; | ||
| 2780 | } else if (age >= ifp->prefered_lft) { | 2810 | } else if (age >= ifp->prefered_lft) { |
| 2781 | /* jiffies - ifp->tsamp > age >= ifp->prefered_lft */ | 2811 | /* jiffies - ifp->tsamp > age >= ifp->prefered_lft */ |
| 2782 | int deprecate = 0; | 2812 | int deprecate = 0; |
| @@ -2853,7 +2883,8 @@ inet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
| 2853 | pfx = RTA_DATA(rta[IFA_ADDRESS-1]); | 2883 | pfx = RTA_DATA(rta[IFA_ADDRESS-1]); |
| 2854 | } | 2884 | } |
| 2855 | if (rta[IFA_LOCAL-1]) { | 2885 | if (rta[IFA_LOCAL-1]) { |
| 2856 | if (pfx && memcmp(pfx, RTA_DATA(rta[IFA_LOCAL-1]), sizeof(*pfx))) | 2886 | if (RTA_PAYLOAD(rta[IFA_LOCAL-1]) < sizeof(*pfx) || |
| 2887 | (pfx && memcmp(pfx, RTA_DATA(rta[IFA_LOCAL-1]), sizeof(*pfx)))) | ||
| 2857 | return -EINVAL; | 2888 | return -EINVAL; |
| 2858 | pfx = RTA_DATA(rta[IFA_LOCAL-1]); | 2889 | pfx = RTA_DATA(rta[IFA_LOCAL-1]); |
| 2859 | } | 2890 | } |
| @@ -2864,11 +2895,61 @@ inet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
| 2864 | } | 2895 | } |
| 2865 | 2896 | ||
| 2866 | static int | 2897 | static int |
| 2898 | inet6_addr_modify(int ifindex, struct in6_addr *pfx, | ||
| 2899 | __u32 prefered_lft, __u32 valid_lft) | ||
| 2900 | { | ||
| 2901 | struct inet6_ifaddr *ifp = NULL; | ||
| 2902 | struct net_device *dev; | ||
| 2903 | int ifa_flags = 0; | ||
| 2904 | |||
| 2905 | if ((dev = __dev_get_by_index(ifindex)) == NULL) | ||
| 2906 | return -ENODEV; | ||
| 2907 | |||
| 2908 | if (!(dev->flags&IFF_UP)) | ||
| 2909 | return -ENETDOWN; | ||
| 2910 | |||
| 2911 | if (!valid_lft || (prefered_lft > valid_lft)) | ||
| 2912 | return -EINVAL; | ||
| 2913 | |||
| 2914 | ifp = ipv6_get_ifaddr(pfx, dev, 1); | ||
| 2915 | if (ifp == NULL) | ||
| 2916 | return -ENOENT; | ||
| 2917 | |||
| 2918 | if (valid_lft == INFINITY_LIFE_TIME) | ||
| 2919 | ifa_flags = IFA_F_PERMANENT; | ||
| 2920 | else if (valid_lft >= 0x7FFFFFFF/HZ) | ||
| 2921 | valid_lft = 0x7FFFFFFF/HZ; | ||
| 2922 | |||
| 2923 | if (prefered_lft == 0) | ||
| 2924 | ifa_flags = IFA_F_DEPRECATED; | ||
| 2925 | else if ((prefered_lft >= 0x7FFFFFFF/HZ) && | ||
| 2926 | (prefered_lft != INFINITY_LIFE_TIME)) | ||
| 2927 | prefered_lft = 0x7FFFFFFF/HZ; | ||
| 2928 | |||
| 2929 | spin_lock_bh(&ifp->lock); | ||
| 2930 | ifp->flags = (ifp->flags & ~(IFA_F_DEPRECATED|IFA_F_PERMANENT)) | ifa_flags; | ||
| 2931 | |||
| 2932 | ifp->tstamp = jiffies; | ||
| 2933 | ifp->valid_lft = valid_lft; | ||
| 2934 | ifp->prefered_lft = prefered_lft; | ||
| 2935 | |||
| 2936 | spin_unlock_bh(&ifp->lock); | ||
| 2937 | if (!(ifp->flags&IFA_F_TENTATIVE)) | ||
| 2938 | ipv6_ifa_notify(0, ifp); | ||
| 2939 | in6_ifa_put(ifp); | ||
| 2940 | |||
| 2941 | addrconf_verify(0); | ||
| 2942 | |||
| 2943 | return 0; | ||
| 2944 | } | ||
| 2945 | |||
| 2946 | static int | ||
| 2867 | inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | 2947 | inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) |
| 2868 | { | 2948 | { |
| 2869 | struct rtattr **rta = arg; | 2949 | struct rtattr **rta = arg; |
| 2870 | struct ifaddrmsg *ifm = NLMSG_DATA(nlh); | 2950 | struct ifaddrmsg *ifm = NLMSG_DATA(nlh); |
| 2871 | struct in6_addr *pfx; | 2951 | struct in6_addr *pfx; |
| 2952 | __u32 valid_lft = INFINITY_LIFE_TIME, prefered_lft = INFINITY_LIFE_TIME; | ||
| 2872 | 2953 | ||
| 2873 | pfx = NULL; | 2954 | pfx = NULL; |
| 2874 | if (rta[IFA_ADDRESS-1]) { | 2955 | if (rta[IFA_ADDRESS-1]) { |
| @@ -2877,14 +2958,34 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
| 2877 | pfx = RTA_DATA(rta[IFA_ADDRESS-1]); | 2958 | pfx = RTA_DATA(rta[IFA_ADDRESS-1]); |
| 2878 | } | 2959 | } |
| 2879 | if (rta[IFA_LOCAL-1]) { | 2960 | if (rta[IFA_LOCAL-1]) { |
| 2880 | if (pfx && memcmp(pfx, RTA_DATA(rta[IFA_LOCAL-1]), sizeof(*pfx))) | 2961 | if (RTA_PAYLOAD(rta[IFA_LOCAL-1]) < sizeof(*pfx) || |
| 2962 | (pfx && memcmp(pfx, RTA_DATA(rta[IFA_LOCAL-1]), sizeof(*pfx)))) | ||
| 2881 | return -EINVAL; | 2963 | return -EINVAL; |
| 2882 | pfx = RTA_DATA(rta[IFA_LOCAL-1]); | 2964 | pfx = RTA_DATA(rta[IFA_LOCAL-1]); |
| 2883 | } | 2965 | } |
| 2884 | if (pfx == NULL) | 2966 | if (pfx == NULL) |
| 2885 | return -EINVAL; | 2967 | return -EINVAL; |
| 2886 | 2968 | ||
| 2887 | return inet6_addr_add(ifm->ifa_index, pfx, ifm->ifa_prefixlen); | 2969 | if (rta[IFA_CACHEINFO-1]) { |
| 2970 | struct ifa_cacheinfo *ci; | ||
| 2971 | if (RTA_PAYLOAD(rta[IFA_CACHEINFO-1]) < sizeof(*ci)) | ||
| 2972 | return -EINVAL; | ||
| 2973 | ci = RTA_DATA(rta[IFA_CACHEINFO-1]); | ||
| 2974 | valid_lft = ci->ifa_valid; | ||
| 2975 | prefered_lft = ci->ifa_prefered; | ||
| 2976 | } | ||
| 2977 | |||
| 2978 | if (nlh->nlmsg_flags & NLM_F_REPLACE) { | ||
| 2979 | int ret; | ||
| 2980 | ret = inet6_addr_modify(ifm->ifa_index, pfx, | ||
| 2981 | prefered_lft, valid_lft); | ||
| 2982 | if (ret == 0 || !(nlh->nlmsg_flags & NLM_F_CREATE)) | ||
| 2983 | return ret; | ||
| 2984 | } | ||
| 2985 | |||
| 2986 | return inet6_addr_add(ifm->ifa_index, pfx, ifm->ifa_prefixlen, | ||
| 2987 | prefered_lft, valid_lft); | ||
| 2988 | |||
| 2888 | } | 2989 | } |
| 2889 | 2990 | ||
| 2890 | /* Maximum length of ifa_cacheinfo attributes */ | 2991 | /* Maximum length of ifa_cacheinfo attributes */ |
| @@ -3121,6 +3222,62 @@ static int inet6_dump_ifacaddr(struct sk_buff *skb, struct netlink_callback *cb) | |||
| 3121 | return inet6_dump_addr(skb, cb, type); | 3222 | return inet6_dump_addr(skb, cb, type); |
| 3122 | } | 3223 | } |
| 3123 | 3224 | ||
| 3225 | static int inet6_rtm_getaddr(struct sk_buff *in_skb, | ||
| 3226 | struct nlmsghdr* nlh, void *arg) | ||
| 3227 | { | ||
| 3228 | struct rtattr **rta = arg; | ||
| 3229 | struct ifaddrmsg *ifm = NLMSG_DATA(nlh); | ||
| 3230 | struct in6_addr *addr = NULL; | ||
| 3231 | struct net_device *dev = NULL; | ||
| 3232 | struct inet6_ifaddr *ifa; | ||
| 3233 | struct sk_buff *skb; | ||
| 3234 | int size = NLMSG_SPACE(sizeof(struct ifaddrmsg) + INET6_IFADDR_RTA_SPACE); | ||
| 3235 | int err; | ||
| 3236 | |||
| 3237 | if (rta[IFA_ADDRESS-1]) { | ||
| 3238 | if (RTA_PAYLOAD(rta[IFA_ADDRESS-1]) < sizeof(*addr)) | ||
| 3239 | return -EINVAL; | ||
| 3240 | addr = RTA_DATA(rta[IFA_ADDRESS-1]); | ||
| 3241 | } | ||
| 3242 | if (rta[IFA_LOCAL-1]) { | ||
| 3243 | if (RTA_PAYLOAD(rta[IFA_LOCAL-1]) < sizeof(*addr) || | ||
| 3244 | (addr && memcmp(addr, RTA_DATA(rta[IFA_LOCAL-1]), sizeof(*addr)))) | ||
| 3245 | return -EINVAL; | ||
| 3246 | addr = RTA_DATA(rta[IFA_LOCAL-1]); | ||
| 3247 | } | ||
| 3248 | if (addr == NULL) | ||
| 3249 | return -EINVAL; | ||
| 3250 | |||
| 3251 | if (ifm->ifa_index) | ||
| 3252 | dev = __dev_get_by_index(ifm->ifa_index); | ||
| 3253 | |||
| 3254 | if ((ifa = ipv6_get_ifaddr(addr, dev, 1)) == NULL) | ||
| 3255 | return -EADDRNOTAVAIL; | ||
| 3256 | |||
| 3257 | if ((skb = alloc_skb(size, GFP_KERNEL)) == NULL) { | ||
| 3258 | err = -ENOBUFS; | ||
| 3259 | goto out; | ||
| 3260 | } | ||
| 3261 | |||
| 3262 | NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid; | ||
| 3263 | err = inet6_fill_ifaddr(skb, ifa, NETLINK_CB(in_skb).pid, | ||
| 3264 | nlh->nlmsg_seq, RTM_NEWADDR, 0); | ||
| 3265 | if (err < 0) { | ||
| 3266 | err = -EMSGSIZE; | ||
| 3267 | goto out_free; | ||
| 3268 | } | ||
| 3269 | |||
| 3270 | err = netlink_unicast(rtnl, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT); | ||
| 3271 | if (err > 0) | ||
| 3272 | err = 0; | ||
| 3273 | out: | ||
| 3274 | in6_ifa_put(ifa); | ||
| 3275 | return err; | ||
| 3276 | out_free: | ||
| 3277 | kfree_skb(skb); | ||
| 3278 | goto out; | ||
| 3279 | } | ||
| 3280 | |||
| 3124 | static void inet6_ifa_notify(int event, struct inet6_ifaddr *ifa) | 3281 | static void inet6_ifa_notify(int event, struct inet6_ifaddr *ifa) |
| 3125 | { | 3282 | { |
| 3126 | struct sk_buff *skb; | 3283 | struct sk_buff *skb; |
| @@ -3363,7 +3520,8 @@ static struct rtnetlink_link inet6_rtnetlink_table[RTM_NR_MSGTYPES] = { | |||
| 3363 | [RTM_GETLINK - RTM_BASE] = { .dumpit = inet6_dump_ifinfo, }, | 3520 | [RTM_GETLINK - RTM_BASE] = { .dumpit = inet6_dump_ifinfo, }, |
| 3364 | [RTM_NEWADDR - RTM_BASE] = { .doit = inet6_rtm_newaddr, }, | 3521 | [RTM_NEWADDR - RTM_BASE] = { .doit = inet6_rtm_newaddr, }, |
| 3365 | [RTM_DELADDR - RTM_BASE] = { .doit = inet6_rtm_deladdr, }, | 3522 | [RTM_DELADDR - RTM_BASE] = { .doit = inet6_rtm_deladdr, }, |
| 3366 | [RTM_GETADDR - RTM_BASE] = { .dumpit = inet6_dump_ifaddr, }, | 3523 | [RTM_GETADDR - RTM_BASE] = { .doit = inet6_rtm_getaddr, |
| 3524 | .dumpit = inet6_dump_ifaddr, }, | ||
| 3367 | [RTM_GETMULTICAST - RTM_BASE] = { .dumpit = inet6_dump_ifmcaddr, }, | 3525 | [RTM_GETMULTICAST - RTM_BASE] = { .dumpit = inet6_dump_ifmcaddr, }, |
| 3368 | [RTM_GETANYCAST - RTM_BASE] = { .dumpit = inet6_dump_ifacaddr, }, | 3526 | [RTM_GETANYCAST - RTM_BASE] = { .dumpit = inet6_dump_ifacaddr, }, |
| 3369 | [RTM_NEWROUTE - RTM_BASE] = { .doit = inet6_rtm_newroute, }, | 3527 | [RTM_NEWROUTE - RTM_BASE] = { .doit = inet6_rtm_newroute, }, |
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 5a0ba58b86cc..ac85e9c532c2 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c | |||
| @@ -658,7 +658,7 @@ int inet6_sk_rebuild_header(struct sock *sk) | |||
| 658 | return err; | 658 | return err; |
| 659 | } | 659 | } |
| 660 | 660 | ||
| 661 | ip6_dst_store(sk, dst, NULL); | 661 | __ip6_dst_store(sk, dst, NULL); |
| 662 | } | 662 | } |
| 663 | 663 | ||
| 664 | return 0; | 664 | return 0; |
diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c index 5c950cc79d80..bf491077b822 100644 --- a/net/ipv6/inet6_connection_sock.c +++ b/net/ipv6/inet6_connection_sock.c | |||
| @@ -185,7 +185,7 @@ int inet6_csk_xmit(struct sk_buff *skb, int ipfragok) | |||
| 185 | return err; | 185 | return err; |
| 186 | } | 186 | } |
| 187 | 187 | ||
| 188 | ip6_dst_store(sk, dst, NULL); | 188 | __ip6_dst_store(sk, dst, NULL); |
| 189 | } | 189 | } |
| 190 | 190 | ||
| 191 | skb->dst = dst_clone(dst); | 191 | skb->dst = dst_clone(dst); |
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 3bc74ce78800..69451af6abe7 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c | |||
| @@ -356,6 +356,7 @@ int ip6_forward(struct sk_buff *skb) | |||
| 356 | skb->dev = dst->dev; | 356 | skb->dev = dst->dev; |
| 357 | icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, | 357 | icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, |
| 358 | 0, skb->dev); | 358 | 0, skb->dev); |
| 359 | IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); | ||
| 359 | 360 | ||
| 360 | kfree_skb(skb); | 361 | kfree_skb(skb); |
| 361 | return -ETIMEDOUT; | 362 | return -ETIMEDOUT; |
| @@ -595,6 +596,9 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) | |||
| 595 | } | 596 | } |
| 596 | 597 | ||
| 597 | err = output(skb); | 598 | err = output(skb); |
| 599 | if(!err) | ||
| 600 | IP6_INC_STATS(IPSTATS_MIB_FRAGCREATES); | ||
| 601 | |||
| 598 | if (err || !frag) | 602 | if (err || !frag) |
| 599 | break; | 603 | break; |
| 600 | 604 | ||
| @@ -706,12 +710,11 @@ slow_path: | |||
| 706 | /* | 710 | /* |
| 707 | * Put this fragment into the sending queue. | 711 | * Put this fragment into the sending queue. |
| 708 | */ | 712 | */ |
| 709 | |||
| 710 | IP6_INC_STATS(IPSTATS_MIB_FRAGCREATES); | ||
| 711 | |||
| 712 | err = output(frag); | 713 | err = output(frag); |
| 713 | if (err) | 714 | if (err) |
| 714 | goto fail; | 715 | goto fail; |
| 716 | |||
| 717 | IP6_INC_STATS(IPSTATS_MIB_FRAGCREATES); | ||
| 715 | } | 718 | } |
| 716 | kfree_skb(skb); | 719 | kfree_skb(skb); |
| 717 | IP6_INC_STATS(IPSTATS_MIB_FRAGOKS); | 720 | IP6_INC_STATS(IPSTATS_MIB_FRAGOKS); |
| @@ -723,48 +726,51 @@ fail: | |||
| 723 | return err; | 726 | return err; |
| 724 | } | 727 | } |
| 725 | 728 | ||
| 726 | int ip6_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi *fl) | 729 | static struct dst_entry *ip6_sk_dst_check(struct sock *sk, |
| 730 | struct dst_entry *dst, | ||
| 731 | struct flowi *fl) | ||
| 727 | { | 732 | { |
| 728 | int err = 0; | 733 | struct ipv6_pinfo *np = inet6_sk(sk); |
| 734 | struct rt6_info *rt = (struct rt6_info *)dst; | ||
| 729 | 735 | ||
| 730 | *dst = NULL; | 736 | if (!dst) |
| 731 | if (sk) { | 737 | goto out; |
| 732 | struct ipv6_pinfo *np = inet6_sk(sk); | 738 | |
| 733 | 739 | /* Yes, checking route validity in not connected | |
| 734 | *dst = sk_dst_check(sk, np->dst_cookie); | 740 | * case is not very simple. Take into account, |
| 735 | if (*dst) { | 741 | * that we do not support routing by source, TOS, |
| 736 | struct rt6_info *rt = (struct rt6_info*)*dst; | 742 | * and MSG_DONTROUTE --ANK (980726) |
| 737 | 743 | * | |
| 738 | /* Yes, checking route validity in not connected | 744 | * 1. If route was host route, check that |
| 739 | * case is not very simple. Take into account, | 745 | * cached destination is current. |
| 740 | * that we do not support routing by source, TOS, | 746 | * If it is network route, we still may |
| 741 | * and MSG_DONTROUTE --ANK (980726) | 747 | * check its validity using saved pointer |
| 742 | * | 748 | * to the last used address: daddr_cache. |
| 743 | * 1. If route was host route, check that | 749 | * We do not want to save whole address now, |
| 744 | * cached destination is current. | 750 | * (because main consumer of this service |
| 745 | * If it is network route, we still may | 751 | * is tcp, which has not this problem), |
| 746 | * check its validity using saved pointer | 752 | * so that the last trick works only on connected |
| 747 | * to the last used address: daddr_cache. | 753 | * sockets. |
| 748 | * We do not want to save whole address now, | 754 | * 2. oif also should be the same. |
| 749 | * (because main consumer of this service | 755 | */ |
| 750 | * is tcp, which has not this problem), | 756 | if (((rt->rt6i_dst.plen != 128 || |
| 751 | * so that the last trick works only on connected | 757 | !ipv6_addr_equal(&fl->fl6_dst, &rt->rt6i_dst.addr)) |
| 752 | * sockets. | 758 | && (np->daddr_cache == NULL || |
| 753 | * 2. oif also should be the same. | 759 | !ipv6_addr_equal(&fl->fl6_dst, np->daddr_cache))) |
| 754 | */ | 760 | || (fl->oif && fl->oif != dst->dev->ifindex)) { |
| 755 | if (((rt->rt6i_dst.plen != 128 || | 761 | dst_release(dst); |
| 756 | !ipv6_addr_equal(&fl->fl6_dst, | 762 | dst = NULL; |
| 757 | &rt->rt6i_dst.addr)) | ||
| 758 | && (np->daddr_cache == NULL || | ||
| 759 | !ipv6_addr_equal(&fl->fl6_dst, | ||
| 760 | np->daddr_cache))) | ||
| 761 | || (fl->oif && fl->oif != (*dst)->dev->ifindex)) { | ||
| 762 | dst_release(*dst); | ||
| 763 | *dst = NULL; | ||
| 764 | } | ||
| 765 | } | ||
| 766 | } | 763 | } |
| 767 | 764 | ||
| 765 | out: | ||
| 766 | return dst; | ||
| 767 | } | ||
| 768 | |||
| 769 | static int ip6_dst_lookup_tail(struct sock *sk, | ||
| 770 | struct dst_entry **dst, struct flowi *fl) | ||
| 771 | { | ||
| 772 | int err; | ||
| 773 | |||
| 768 | if (*dst == NULL) | 774 | if (*dst == NULL) |
| 769 | *dst = ip6_route_output(sk, fl); | 775 | *dst = ip6_route_output(sk, fl); |
| 770 | 776 | ||
| @@ -773,7 +779,6 @@ int ip6_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi *fl) | |||
| 773 | 779 | ||
| 774 | if (ipv6_addr_any(&fl->fl6_src)) { | 780 | if (ipv6_addr_any(&fl->fl6_src)) { |
| 775 | err = ipv6_get_saddr(*dst, &fl->fl6_dst, &fl->fl6_src); | 781 | err = ipv6_get_saddr(*dst, &fl->fl6_dst, &fl->fl6_src); |
| 776 | |||
| 777 | if (err) | 782 | if (err) |
| 778 | goto out_err_release; | 783 | goto out_err_release; |
| 779 | } | 784 | } |
| @@ -786,8 +791,48 @@ out_err_release: | |||
| 786 | return err; | 791 | return err; |
| 787 | } | 792 | } |
| 788 | 793 | ||
| 794 | /** | ||
| 795 | * ip6_dst_lookup - perform route lookup on flow | ||
| 796 | * @sk: socket which provides route info | ||
| 797 | * @dst: pointer to dst_entry * for result | ||
| 798 | * @fl: flow to lookup | ||
| 799 | * | ||
| 800 | * This function performs a route lookup on the given flow. | ||
| 801 | * | ||
| 802 | * It returns zero on success, or a standard errno code on error. | ||
| 803 | */ | ||
| 804 | int ip6_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi *fl) | ||
| 805 | { | ||
| 806 | *dst = NULL; | ||
| 807 | return ip6_dst_lookup_tail(sk, dst, fl); | ||
| 808 | } | ||
| 789 | EXPORT_SYMBOL_GPL(ip6_dst_lookup); | 809 | EXPORT_SYMBOL_GPL(ip6_dst_lookup); |
| 790 | 810 | ||
| 811 | /** | ||
| 812 | * ip6_sk_dst_lookup - perform socket cached route lookup on flow | ||
| 813 | * @sk: socket which provides the dst cache and route info | ||
| 814 | * @dst: pointer to dst_entry * for result | ||
| 815 | * @fl: flow to lookup | ||
| 816 | * | ||
| 817 | * This function performs a route lookup on the given flow with the | ||
| 818 | * possibility of using the cached route in the socket if it is valid. | ||
| 819 | * It will take the socket dst lock when operating on the dst cache. | ||
| 820 | * As a result, this function can only be used in process context. | ||
| 821 | * | ||
| 822 | * It returns zero on success, or a standard errno code on error. | ||
| 823 | */ | ||
| 824 | int ip6_sk_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi *fl) | ||
| 825 | { | ||
| 826 | *dst = NULL; | ||
| 827 | if (sk) { | ||
| 828 | *dst = sk_dst_check(sk, inet6_sk(sk)->dst_cookie); | ||
| 829 | *dst = ip6_sk_dst_check(sk, *dst, fl); | ||
| 830 | } | ||
| 831 | |||
| 832 | return ip6_dst_lookup_tail(sk, dst, fl); | ||
| 833 | } | ||
| 834 | EXPORT_SYMBOL_GPL(ip6_sk_dst_lookup); | ||
| 835 | |||
| 791 | static inline int ip6_ufo_append_data(struct sock *sk, | 836 | static inline int ip6_ufo_append_data(struct sock *sk, |
| 792 | int getfrag(void *from, char *to, int offset, int len, | 837 | int getfrag(void *from, char *to, int offset, int len, |
| 793 | int odd, struct sk_buff *skb), | 838 | int odd, struct sk_buff *skb), |
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 87c39c978cd0..4b163711f3a8 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
| @@ -53,6 +53,7 @@ | |||
| 53 | #include <linux/rtnetlink.h> | 53 | #include <linux/rtnetlink.h> |
| 54 | #include <net/dst.h> | 54 | #include <net/dst.h> |
| 55 | #include <net/xfrm.h> | 55 | #include <net/xfrm.h> |
| 56 | #include <net/netevent.h> | ||
| 56 | 57 | ||
| 57 | #include <asm/uaccess.h> | 58 | #include <asm/uaccess.h> |
| 58 | 59 | ||
| @@ -742,6 +743,7 @@ static void ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu) | |||
| 742 | dst->metrics[RTAX_FEATURES-1] |= RTAX_FEATURE_ALLFRAG; | 743 | dst->metrics[RTAX_FEATURES-1] |= RTAX_FEATURE_ALLFRAG; |
| 743 | } | 744 | } |
| 744 | dst->metrics[RTAX_MTU-1] = mtu; | 745 | dst->metrics[RTAX_MTU-1] = mtu; |
| 746 | call_netevent_notifiers(NETEVENT_PMTU_UPDATE, dst); | ||
| 745 | } | 747 | } |
| 746 | } | 748 | } |
| 747 | 749 | ||
| @@ -1155,6 +1157,7 @@ void rt6_redirect(struct in6_addr *dest, struct in6_addr *saddr, | |||
| 1155 | struct rt6_info *rt, *nrt = NULL; | 1157 | struct rt6_info *rt, *nrt = NULL; |
| 1156 | int strict; | 1158 | int strict; |
| 1157 | struct fib6_node *fn; | 1159 | struct fib6_node *fn; |
| 1160 | struct netevent_redirect netevent; | ||
| 1158 | 1161 | ||
| 1159 | /* | 1162 | /* |
| 1160 | * Get the "current" route for this destination and | 1163 | * Get the "current" route for this destination and |
| @@ -1252,6 +1255,10 @@ restart: | |||
| 1252 | if (ip6_ins_rt(nrt, NULL, NULL, NULL)) | 1255 | if (ip6_ins_rt(nrt, NULL, NULL, NULL)) |
| 1253 | goto out; | 1256 | goto out; |
| 1254 | 1257 | ||
| 1258 | netevent.old = &rt->u.dst; | ||
| 1259 | netevent.new = &nrt->u.dst; | ||
| 1260 | call_netevent_notifiers(NETEVENT_REDIRECT, &netevent); | ||
| 1261 | |||
| 1255 | if (rt->rt6i_flags&RTF_CACHE) { | 1262 | if (rt->rt6i_flags&RTF_CACHE) { |
| 1256 | ip6_del_rt(rt, NULL, NULL, NULL); | 1263 | ip6_del_rt(rt, NULL, NULL, NULL); |
| 1257 | return; | 1264 | return; |
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 923989d0520d..b843a650be71 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
| @@ -270,7 +270,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
| 270 | inet->rcv_saddr = LOOPBACK4_IPV6; | 270 | inet->rcv_saddr = LOOPBACK4_IPV6; |
| 271 | 271 | ||
| 272 | sk->sk_gso_type = SKB_GSO_TCPV6; | 272 | sk->sk_gso_type = SKB_GSO_TCPV6; |
| 273 | ip6_dst_store(sk, dst, NULL); | 273 | __ip6_dst_store(sk, dst, NULL); |
| 274 | 274 | ||
| 275 | icsk->icsk_ext_hdr_len = 0; | 275 | icsk->icsk_ext_hdr_len = 0; |
| 276 | if (np->opt) | 276 | if (np->opt) |
| @@ -427,7 +427,6 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
| 427 | case TCP_SYN_RECV: /* Cannot happen. | 427 | case TCP_SYN_RECV: /* Cannot happen. |
| 428 | It can, it SYNs are crossed. --ANK */ | 428 | It can, it SYNs are crossed. --ANK */ |
| 429 | if (!sock_owned_by_user(sk)) { | 429 | if (!sock_owned_by_user(sk)) { |
| 430 | TCP_INC_STATS_BH(TCP_MIB_ATTEMPTFAILS); | ||
| 431 | sk->sk_err = err; | 430 | sk->sk_err = err; |
| 432 | sk->sk_error_report(sk); /* Wake people up to see the error (see connect in sock.c) */ | 431 | sk->sk_error_report(sk); /* Wake people up to see the error (see connect in sock.c) */ |
| 433 | 432 | ||
| @@ -831,7 +830,6 @@ drop: | |||
| 831 | if (req) | 830 | if (req) |
| 832 | reqsk_free(req); | 831 | reqsk_free(req); |
| 833 | 832 | ||
| 834 | TCP_INC_STATS_BH(TCP_MIB_ATTEMPTFAILS); | ||
| 835 | return 0; /* don't send reset */ | 833 | return 0; /* don't send reset */ |
| 836 | } | 834 | } |
| 837 | 835 | ||
| @@ -947,7 +945,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
| 947 | */ | 945 | */ |
| 948 | 946 | ||
| 949 | sk->sk_gso_type = SKB_GSO_TCPV6; | 947 | sk->sk_gso_type = SKB_GSO_TCPV6; |
| 950 | ip6_dst_store(newsk, dst, NULL); | 948 | __ip6_dst_store(newsk, dst, NULL); |
| 951 | 949 | ||
| 952 | newtcp6sk = (struct tcp6_sock *)newsk; | 950 | newtcp6sk = (struct tcp6_sock *)newsk; |
| 953 | inet_sk(newsk)->pinet6 = &newtcp6sk->inet6; | 951 | inet_sk(newsk)->pinet6 = &newtcp6sk->inet6; |
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index ccc57f434cd3..3d54f246411e 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
| @@ -782,7 +782,7 @@ do_udp_sendmsg: | |||
| 782 | connected = 0; | 782 | connected = 0; |
| 783 | } | 783 | } |
| 784 | 784 | ||
| 785 | err = ip6_dst_lookup(sk, &dst, fl); | 785 | err = ip6_sk_dst_lookup(sk, &dst, fl); |
| 786 | if (err) | 786 | if (err) |
| 787 | goto out; | 787 | goto out; |
| 788 | if (final_p) | 788 | if (final_p) |
diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c index 0eea60ea9ebc..c8c8b44a0f58 100644 --- a/net/ipv6/xfrm6_output.c +++ b/net/ipv6/xfrm6_output.c | |||
| @@ -125,7 +125,7 @@ static int xfrm6_output_finish(struct sk_buff *skb) | |||
| 125 | if (!skb_is_gso(skb)) | 125 | if (!skb_is_gso(skb)) |
| 126 | return xfrm6_output_finish2(skb); | 126 | return xfrm6_output_finish2(skb); |
| 127 | 127 | ||
| 128 | skb->protocol = htons(ETH_P_IP); | 128 | skb->protocol = htons(ETH_P_IPV6); |
| 129 | segs = skb_gso_segment(skb, 0); | 129 | segs = skb_gso_segment(skb, 0); |
| 130 | kfree_skb(skb); | 130 | kfree_skb(skb); |
| 131 | if (unlikely(IS_ERR(segs))) | 131 | if (unlikely(IS_ERR(segs))) |
