diff options
Diffstat (limited to 'net/ipv6')
| -rw-r--r-- | net/ipv6/addrconf.c | 20 | ||||
| -rw-r--r-- | net/ipv6/exthdrs.c | 40 | ||||
| -rw-r--r-- | net/ipv6/fib6_rules.c | 14 | ||||
| -rw-r--r-- | net/ipv6/ip6_fib.c | 8 | ||||
| -rw-r--r-- | net/ipv6/ip6_input.c | 8 | ||||
| -rw-r--r-- | net/ipv6/raw.c | 4 | ||||
| -rw-r--r-- | net/ipv6/route.c | 149 | ||||
| -rw-r--r-- | net/ipv6/tcp_ipv6.c | 1 | ||||
| -rw-r--r-- | net/ipv6/udp.c | 2 | ||||
| -rw-r--r-- | net/ipv6/xfrm6_tunnel.c | 4 |
10 files changed, 159 insertions, 91 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index a7fee6b27320..452a82ce4796 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
| @@ -172,6 +172,7 @@ struct ipv6_devconf ipv6_devconf __read_mostly = { | |||
| 172 | #endif | 172 | #endif |
| 173 | #endif | 173 | #endif |
| 174 | .proxy_ndp = 0, | 174 | .proxy_ndp = 0, |
| 175 | .accept_source_route = 0, /* we do not accept RH0 by default. */ | ||
| 175 | }; | 176 | }; |
| 176 | 177 | ||
| 177 | static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { | 178 | static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { |
| @@ -203,6 +204,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { | |||
| 203 | #endif | 204 | #endif |
| 204 | #endif | 205 | #endif |
| 205 | .proxy_ndp = 0, | 206 | .proxy_ndp = 0, |
| 207 | .accept_source_route = 0, /* we do not accept RH0 by default. */ | ||
| 206 | }; | 208 | }; |
| 207 | 209 | ||
| 208 | /* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */ | 210 | /* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */ |
| @@ -342,6 +344,9 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev) | |||
| 342 | } | 344 | } |
| 343 | #endif | 345 | #endif |
| 344 | 346 | ||
| 347 | if (netif_running(dev) && netif_carrier_ok(dev)) | ||
| 348 | ndev->if_flags |= IF_READY; | ||
| 349 | |||
| 345 | ipv6_mc_init_dev(ndev); | 350 | ipv6_mc_init_dev(ndev); |
| 346 | ndev->tstamp = jiffies; | 351 | ndev->tstamp = jiffies; |
| 347 | #ifdef CONFIG_SYSCTL | 352 | #ifdef CONFIG_SYSCTL |
| @@ -804,7 +809,7 @@ struct ipv6_saddr_score { | |||
| 804 | #define IPV6_SADDR_SCORE_LABEL 0x0020 | 809 | #define IPV6_SADDR_SCORE_LABEL 0x0020 |
| 805 | #define IPV6_SADDR_SCORE_PRIVACY 0x0040 | 810 | #define IPV6_SADDR_SCORE_PRIVACY 0x0040 |
| 806 | 811 | ||
| 807 | static int inline ipv6_saddr_preferred(int type) | 812 | static inline int ipv6_saddr_preferred(int type) |
| 808 | { | 813 | { |
| 809 | if (type & (IPV6_ADDR_MAPPED|IPV6_ADDR_COMPATv4| | 814 | if (type & (IPV6_ADDR_MAPPED|IPV6_ADDR_COMPATv4| |
| 810 | IPV6_ADDR_LOOPBACK|IPV6_ADDR_RESERVED)) | 815 | IPV6_ADDR_LOOPBACK|IPV6_ADDR_RESERVED)) |
| @@ -813,7 +818,7 @@ static int inline ipv6_saddr_preferred(int type) | |||
| 813 | } | 818 | } |
| 814 | 819 | ||
| 815 | /* static matching label */ | 820 | /* static matching label */ |
| 816 | static int inline ipv6_saddr_label(const struct in6_addr *addr, int type) | 821 | static inline int ipv6_saddr_label(const struct in6_addr *addr, int type) |
| 817 | { | 822 | { |
| 818 | /* | 823 | /* |
| 819 | * prefix (longest match) label | 824 | * prefix (longest match) label |
| @@ -3318,7 +3323,7 @@ errout: | |||
| 3318 | rtnl_set_sk_err(RTNLGRP_IPV6_IFADDR, err); | 3323 | rtnl_set_sk_err(RTNLGRP_IPV6_IFADDR, err); |
| 3319 | } | 3324 | } |
| 3320 | 3325 | ||
| 3321 | static void inline ipv6_store_devconf(struct ipv6_devconf *cnf, | 3326 | static inline void ipv6_store_devconf(struct ipv6_devconf *cnf, |
| 3322 | __s32 *array, int bytes) | 3327 | __s32 *array, int bytes) |
| 3323 | { | 3328 | { |
| 3324 | BUG_ON(bytes < (DEVCONF_MAX * 4)); | 3329 | BUG_ON(bytes < (DEVCONF_MAX * 4)); |
| @@ -3353,6 +3358,7 @@ static void inline ipv6_store_devconf(struct ipv6_devconf *cnf, | |||
| 3353 | #endif | 3358 | #endif |
| 3354 | #endif | 3359 | #endif |
| 3355 | array[DEVCONF_PROXY_NDP] = cnf->proxy_ndp; | 3360 | array[DEVCONF_PROXY_NDP] = cnf->proxy_ndp; |
| 3361 | array[DEVCONF_ACCEPT_SOURCE_ROUTE] = cnf->accept_source_route; | ||
| 3356 | } | 3362 | } |
| 3357 | 3363 | ||
| 3358 | static inline size_t inet6_if_nlmsg_size(void) | 3364 | static inline size_t inet6_if_nlmsg_size(void) |
| @@ -3881,6 +3887,14 @@ static struct addrconf_sysctl_table | |||
| 3881 | .proc_handler = &proc_dointvec, | 3887 | .proc_handler = &proc_dointvec, |
| 3882 | }, | 3888 | }, |
| 3883 | { | 3889 | { |
| 3890 | .ctl_name = NET_IPV6_ACCEPT_SOURCE_ROUTE, | ||
| 3891 | .procname = "accept_source_route", | ||
| 3892 | .data = &ipv6_devconf.accept_source_route, | ||
| 3893 | .maxlen = sizeof(int), | ||
| 3894 | .mode = 0644, | ||
| 3895 | .proc_handler = &proc_dointvec, | ||
| 3896 | }, | ||
| 3897 | { | ||
| 3884 | .ctl_name = 0, /* sentinel */ | 3898 | .ctl_name = 0, /* sentinel */ |
| 3885 | } | 3899 | } |
| 3886 | }, | 3900 | }, |
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c index 28e0c6568272..fb39604c3d09 100644 --- a/net/ipv6/exthdrs.c +++ b/net/ipv6/exthdrs.c | |||
| @@ -362,10 +362,27 @@ static int ipv6_rthdr_rcv(struct sk_buff **skbp) | |||
| 362 | struct inet6_skb_parm *opt = IP6CB(skb); | 362 | struct inet6_skb_parm *opt = IP6CB(skb); |
| 363 | struct in6_addr *addr = NULL; | 363 | struct in6_addr *addr = NULL; |
| 364 | struct in6_addr daddr; | 364 | struct in6_addr daddr; |
| 365 | struct inet6_dev *idev; | ||
| 365 | int n, i; | 366 | int n, i; |
| 366 | |||
| 367 | struct ipv6_rt_hdr *hdr; | 367 | struct ipv6_rt_hdr *hdr; |
| 368 | struct rt0_hdr *rthdr; | 368 | struct rt0_hdr *rthdr; |
| 369 | int accept_source_route = ipv6_devconf.accept_source_route; | ||
| 370 | |||
| 371 | if (accept_source_route < 0 || | ||
| 372 | ((idev = in6_dev_get(skb->dev)) == NULL)) { | ||
| 373 | kfree_skb(skb); | ||
| 374 | return -1; | ||
| 375 | } | ||
| 376 | if (idev->cnf.accept_source_route < 0) { | ||
| 377 | in6_dev_put(idev); | ||
| 378 | kfree_skb(skb); | ||
| 379 | return -1; | ||
| 380 | } | ||
| 381 | |||
| 382 | if (accept_source_route > idev->cnf.accept_source_route) | ||
| 383 | accept_source_route = idev->cnf.accept_source_route; | ||
| 384 | |||
| 385 | in6_dev_put(idev); | ||
| 369 | 386 | ||
| 370 | if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) || | 387 | if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) || |
| 371 | !pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) { | 388 | !pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) { |
| @@ -377,6 +394,22 @@ static int ipv6_rthdr_rcv(struct sk_buff **skbp) | |||
| 377 | 394 | ||
| 378 | hdr = (struct ipv6_rt_hdr *) skb->h.raw; | 395 | hdr = (struct ipv6_rt_hdr *) skb->h.raw; |
| 379 | 396 | ||
| 397 | switch (hdr->type) { | ||
| 398 | #ifdef CONFIG_IPV6_MIP6 | ||
| 399 | break; | ||
| 400 | #endif | ||
| 401 | case IPV6_SRCRT_TYPE_0: | ||
| 402 | if (accept_source_route > 0) | ||
| 403 | break; | ||
| 404 | kfree_skb(skb); | ||
| 405 | return -1; | ||
| 406 | default: | ||
| 407 | IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), | ||
| 408 | IPSTATS_MIB_INHDRERRORS); | ||
| 409 | icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->type) - skb->nh.raw); | ||
| 410 | return -1; | ||
| 411 | } | ||
| 412 | |||
| 380 | if (ipv6_addr_is_multicast(&skb->nh.ipv6h->daddr) || | 413 | if (ipv6_addr_is_multicast(&skb->nh.ipv6h->daddr) || |
| 381 | skb->pkt_type != PACKET_HOST) { | 414 | skb->pkt_type != PACKET_HOST) { |
| 382 | IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), | 415 | IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), |
| @@ -434,11 +467,6 @@ looped_back: | |||
| 434 | } | 467 | } |
| 435 | break; | 468 | break; |
| 436 | #endif | 469 | #endif |
| 437 | default: | ||
| 438 | IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), | ||
| 439 | IPSTATS_MIB_INHDRERRORS); | ||
| 440 | icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->type) - skb->nh.raw); | ||
| 441 | return -1; | ||
| 442 | } | 470 | } |
| 443 | 471 | ||
| 444 | /* | 472 | /* |
diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c index 0862809ffcf7..ea3035b4e3e8 100644 --- a/net/ipv6/fib6_rules.c +++ b/net/ipv6/fib6_rules.c | |||
| @@ -131,8 +131,6 @@ static int fib6_rule_match(struct fib_rule *rule, struct flowi *fl, int flags) | |||
| 131 | 131 | ||
| 132 | static struct nla_policy fib6_rule_policy[FRA_MAX+1] __read_mostly = { | 132 | static struct nla_policy fib6_rule_policy[FRA_MAX+1] __read_mostly = { |
| 133 | FRA_GENERIC_POLICY, | 133 | FRA_GENERIC_POLICY, |
| 134 | [FRA_SRC] = { .len = sizeof(struct in6_addr) }, | ||
| 135 | [FRA_DST] = { .len = sizeof(struct in6_addr) }, | ||
| 136 | }; | 134 | }; |
| 137 | 135 | ||
| 138 | static int fib6_rule_configure(struct fib_rule *rule, struct sk_buff *skb, | 136 | static int fib6_rule_configure(struct fib_rule *rule, struct sk_buff *skb, |
| @@ -142,9 +140,6 @@ static int fib6_rule_configure(struct fib_rule *rule, struct sk_buff *skb, | |||
| 142 | int err = -EINVAL; | 140 | int err = -EINVAL; |
| 143 | struct fib6_rule *rule6 = (struct fib6_rule *) rule; | 141 | struct fib6_rule *rule6 = (struct fib6_rule *) rule; |
| 144 | 142 | ||
| 145 | if (frh->src_len > 128 || frh->dst_len > 128) | ||
| 146 | goto errout; | ||
| 147 | |||
| 148 | if (rule->action == FR_ACT_TO_TBL) { | 143 | if (rule->action == FR_ACT_TO_TBL) { |
| 149 | if (rule->table == RT6_TABLE_UNSPEC) | 144 | if (rule->table == RT6_TABLE_UNSPEC) |
| 150 | goto errout; | 145 | goto errout; |
| @@ -155,11 +150,11 @@ static int fib6_rule_configure(struct fib_rule *rule, struct sk_buff *skb, | |||
| 155 | } | 150 | } |
| 156 | } | 151 | } |
| 157 | 152 | ||
| 158 | if (tb[FRA_SRC]) | 153 | if (frh->src_len) |
| 159 | nla_memcpy(&rule6->src.addr, tb[FRA_SRC], | 154 | nla_memcpy(&rule6->src.addr, tb[FRA_SRC], |
| 160 | sizeof(struct in6_addr)); | 155 | sizeof(struct in6_addr)); |
| 161 | 156 | ||
| 162 | if (tb[FRA_DST]) | 157 | if (frh->dst_len) |
| 163 | nla_memcpy(&rule6->dst.addr, tb[FRA_DST], | 158 | nla_memcpy(&rule6->dst.addr, tb[FRA_DST], |
| 164 | sizeof(struct in6_addr)); | 159 | sizeof(struct in6_addr)); |
| 165 | 160 | ||
| @@ -186,11 +181,11 @@ static int fib6_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh, | |||
| 186 | if (frh->tos && (rule6->tclass != frh->tos)) | 181 | if (frh->tos && (rule6->tclass != frh->tos)) |
| 187 | return 0; | 182 | return 0; |
| 188 | 183 | ||
| 189 | if (tb[FRA_SRC] && | 184 | if (frh->src_len && |
| 190 | nla_memcmp(tb[FRA_SRC], &rule6->src.addr, sizeof(struct in6_addr))) | 185 | nla_memcmp(tb[FRA_SRC], &rule6->src.addr, sizeof(struct in6_addr))) |
| 191 | return 0; | 186 | return 0; |
| 192 | 187 | ||
| 193 | if (tb[FRA_DST] && | 188 | if (frh->dst_len && |
| 194 | nla_memcmp(tb[FRA_DST], &rule6->dst.addr, sizeof(struct in6_addr))) | 189 | nla_memcmp(tb[FRA_DST], &rule6->dst.addr, sizeof(struct in6_addr))) |
| 195 | return 0; | 190 | return 0; |
| 196 | 191 | ||
| @@ -240,6 +235,7 @@ static size_t fib6_rule_nlmsg_payload(struct fib_rule *rule) | |||
| 240 | static struct fib_rules_ops fib6_rules_ops = { | 235 | static struct fib_rules_ops fib6_rules_ops = { |
| 241 | .family = AF_INET6, | 236 | .family = AF_INET6, |
| 242 | .rule_size = sizeof(struct fib6_rule), | 237 | .rule_size = sizeof(struct fib6_rule), |
| 238 | .addr_size = sizeof(struct in6_addr), | ||
| 243 | .action = fib6_rule_action, | 239 | .action = fib6_rule_action, |
| 244 | .match = fib6_rule_match, | 240 | .match = fib6_rule_match, |
| 245 | .configure = fib6_rule_configure, | 241 | .configure = fib6_rule_configure, |
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index f4d7be77eb0f..268f476ef3db 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c | |||
| @@ -658,6 +658,10 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt, | |||
| 658 | ins = &iter->u.dst.rt6_next; | 658 | ins = &iter->u.dst.rt6_next; |
| 659 | } | 659 | } |
| 660 | 660 | ||
| 661 | /* Reset round-robin state, if necessary */ | ||
| 662 | if (ins == &fn->leaf) | ||
| 663 | fn->rr_ptr = NULL; | ||
| 664 | |||
| 661 | /* | 665 | /* |
| 662 | * insert node | 666 | * insert node |
| 663 | */ | 667 | */ |
| @@ -1109,6 +1113,10 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp, | |||
| 1109 | rt6_stats.fib_rt_entries--; | 1113 | rt6_stats.fib_rt_entries--; |
| 1110 | rt6_stats.fib_discarded_routes++; | 1114 | rt6_stats.fib_discarded_routes++; |
| 1111 | 1115 | ||
| 1116 | /* Reset round-robin state, if necessary */ | ||
| 1117 | if (fn->rr_ptr == rt) | ||
| 1118 | fn->rr_ptr = NULL; | ||
| 1119 | |||
| 1112 | /* Adjust walkers */ | 1120 | /* Adjust walkers */ |
| 1113 | read_lock(&fib6_walker_lock); | 1121 | read_lock(&fib6_walker_lock); |
| 1114 | FOR_WALKERS(w) { | 1122 | FOR_WALKERS(w) { |
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index 11bfc7c43182..61e7a6c8141d 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c | |||
| @@ -108,8 +108,10 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt | |||
| 108 | 108 | ||
| 109 | /* pkt_len may be zero if Jumbo payload option is present */ | 109 | /* pkt_len may be zero if Jumbo payload option is present */ |
| 110 | if (pkt_len || hdr->nexthdr != NEXTHDR_HOP) { | 110 | if (pkt_len || hdr->nexthdr != NEXTHDR_HOP) { |
| 111 | if (pkt_len + sizeof(struct ipv6hdr) > skb->len) | 111 | if (pkt_len + sizeof(struct ipv6hdr) > skb->len) { |
| 112 | goto truncated; | 112 | IP6_INC_STATS_BH(idev, IPSTATS_MIB_INTRUNCATEDPKTS); |
| 113 | goto drop; | ||
| 114 | } | ||
| 113 | if (pskb_trim_rcsum(skb, pkt_len + sizeof(struct ipv6hdr))) { | 115 | if (pskb_trim_rcsum(skb, pkt_len + sizeof(struct ipv6hdr))) { |
| 114 | IP6_INC_STATS_BH(idev, IPSTATS_MIB_INHDRERRORS); | 116 | IP6_INC_STATS_BH(idev, IPSTATS_MIB_INHDRERRORS); |
| 115 | goto drop; | 117 | goto drop; |
| @@ -128,8 +130,6 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt | |||
| 128 | rcu_read_unlock(); | 130 | rcu_read_unlock(); |
| 129 | 131 | ||
| 130 | return NF_HOOK(PF_INET6,NF_IP6_PRE_ROUTING, skb, dev, NULL, ip6_rcv_finish); | 132 | return NF_HOOK(PF_INET6,NF_IP6_PRE_ROUTING, skb, dev, NULL, ip6_rcv_finish); |
| 131 | truncated: | ||
| 132 | IP6_INC_STATS_BH(idev, IPSTATS_MIB_INTRUNCATEDPKTS); | ||
| 133 | err: | 133 | err: |
| 134 | IP6_INC_STATS_BH(idev, IPSTATS_MIB_INHDRERRORS); | 134 | IP6_INC_STATS_BH(idev, IPSTATS_MIB_INHDRERRORS); |
| 135 | drop: | 135 | drop: |
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 306d5d83c068..203e069e7fe9 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c | |||
| @@ -687,9 +687,9 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
| 687 | int err; | 687 | int err; |
| 688 | 688 | ||
| 689 | /* Rough check on arithmetic overflow, | 689 | /* Rough check on arithmetic overflow, |
| 690 | better check is made in ip6_build_xmit | 690 | better check is made in ip6_append_data(). |
| 691 | */ | 691 | */ |
| 692 | if (len < 0) | 692 | if (len > INT_MAX) |
| 693 | return -EMSGSIZE; | 693 | return -EMSGSIZE; |
| 694 | 694 | ||
| 695 | /* Mirror BSD error message compatibility */ | 695 | /* Mirror BSD error message compatibility */ |
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 0e1f4b2cd3dd..aebb4e2d5ae3 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
| @@ -308,27 +308,18 @@ static inline void rt6_probe(struct rt6_info *rt) | |||
| 308 | /* | 308 | /* |
| 309 | * Default Router Selection (RFC 2461 6.3.6) | 309 | * Default Router Selection (RFC 2461 6.3.6) |
| 310 | */ | 310 | */ |
| 311 | static int inline rt6_check_dev(struct rt6_info *rt, int oif) | 311 | static inline int rt6_check_dev(struct rt6_info *rt, int oif) |
| 312 | { | 312 | { |
| 313 | struct net_device *dev = rt->rt6i_dev; | 313 | struct net_device *dev = rt->rt6i_dev; |
| 314 | int ret = 0; | 314 | if (!oif || dev->ifindex == oif) |
| 315 | |||
| 316 | if (!oif) | ||
| 317 | return 2; | ||
| 318 | if (dev->flags & IFF_LOOPBACK) { | ||
| 319 | if (!WARN_ON(rt->rt6i_idev == NULL) && | ||
| 320 | rt->rt6i_idev->dev->ifindex == oif) | ||
| 321 | ret = 1; | ||
| 322 | else | ||
| 323 | return 0; | ||
| 324 | } | ||
| 325 | if (dev->ifindex == oif) | ||
| 326 | return 2; | 315 | return 2; |
| 327 | 316 | if ((dev->flags & IFF_LOOPBACK) && | |
| 328 | return ret; | 317 | rt->rt6i_idev && rt->rt6i_idev->dev->ifindex == oif) |
| 318 | return 1; | ||
| 319 | return 0; | ||
| 329 | } | 320 | } |
| 330 | 321 | ||
| 331 | static int inline rt6_check_neigh(struct rt6_info *rt) | 322 | static inline int rt6_check_neigh(struct rt6_info *rt) |
| 332 | { | 323 | { |
| 333 | struct neighbour *neigh = rt->rt6i_nexthop; | 324 | struct neighbour *neigh = rt->rt6i_nexthop; |
| 334 | int m = 0; | 325 | int m = 0; |
| @@ -363,55 +354,76 @@ static int rt6_score_route(struct rt6_info *rt, int oif, | |||
| 363 | return m; | 354 | return m; |
| 364 | } | 355 | } |
| 365 | 356 | ||
| 366 | static struct rt6_info *rt6_select(struct rt6_info **head, int oif, | 357 | static struct rt6_info *find_match(struct rt6_info *rt, int oif, int strict, |
| 367 | int strict) | 358 | int *mpri, struct rt6_info *match) |
| 368 | { | 359 | { |
| 369 | struct rt6_info *match = NULL, *last = NULL; | 360 | int m; |
| 370 | struct rt6_info *rt, *rt0 = *head; | 361 | |
| 371 | u32 metric; | 362 | if (rt6_check_expired(rt)) |
| 363 | goto out; | ||
| 364 | |||
| 365 | m = rt6_score_route(rt, oif, strict); | ||
| 366 | if (m < 0) | ||
| 367 | goto out; | ||
| 368 | |||
| 369 | if (m > *mpri) { | ||
| 370 | if (strict & RT6_LOOKUP_F_REACHABLE) | ||
| 371 | rt6_probe(match); | ||
| 372 | *mpri = m; | ||
| 373 | match = rt; | ||
| 374 | } else if (strict & RT6_LOOKUP_F_REACHABLE) { | ||
| 375 | rt6_probe(rt); | ||
| 376 | } | ||
| 377 | |||
| 378 | out: | ||
| 379 | return match; | ||
| 380 | } | ||
| 381 | |||
| 382 | static struct rt6_info *find_rr_leaf(struct fib6_node *fn, | ||
| 383 | struct rt6_info *rr_head, | ||
| 384 | u32 metric, int oif, int strict) | ||
| 385 | { | ||
| 386 | struct rt6_info *rt, *match; | ||
| 372 | int mpri = -1; | 387 | int mpri = -1; |
| 373 | 388 | ||
| 374 | RT6_TRACE("%s(head=%p(*head=%p), oif=%d)\n", | 389 | match = NULL; |
| 375 | __FUNCTION__, head, head ? *head : NULL, oif); | 390 | for (rt = rr_head; rt && rt->rt6i_metric == metric; |
| 391 | rt = rt->u.dst.rt6_next) | ||
| 392 | match = find_match(rt, oif, strict, &mpri, match); | ||
| 393 | for (rt = fn->leaf; rt && rt != rr_head && rt->rt6i_metric == metric; | ||
| 394 | rt = rt->u.dst.rt6_next) | ||
| 395 | match = find_match(rt, oif, strict, &mpri, match); | ||
| 376 | 396 | ||
| 377 | for (rt = rt0, metric = rt0->rt6i_metric; | 397 | return match; |
| 378 | rt && rt->rt6i_metric == metric && (!last || rt != rt0); | 398 | } |
| 379 | rt = rt->u.dst.rt6_next) { | ||
| 380 | int m; | ||
| 381 | 399 | ||
| 382 | if (rt6_check_expired(rt)) | 400 | static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict) |
| 383 | continue; | 401 | { |
| 402 | struct rt6_info *match, *rt0; | ||
| 384 | 403 | ||
| 385 | last = rt; | 404 | RT6_TRACE("%s(fn->leaf=%p, oif=%d)\n", |
| 405 | __FUNCTION__, fn->leaf, oif); | ||
| 386 | 406 | ||
| 387 | m = rt6_score_route(rt, oif, strict); | 407 | rt0 = fn->rr_ptr; |
| 388 | if (m < 0) | 408 | if (!rt0) |
| 389 | continue; | 409 | fn->rr_ptr = rt0 = fn->leaf; |
| 390 | 410 | ||
| 391 | if (m > mpri) { | 411 | match = find_rr_leaf(fn, rt0, rt0->rt6i_metric, oif, strict); |
| 392 | if (strict & RT6_LOOKUP_F_REACHABLE) | ||
| 393 | rt6_probe(match); | ||
| 394 | match = rt; | ||
| 395 | mpri = m; | ||
| 396 | } else if (strict & RT6_LOOKUP_F_REACHABLE) { | ||
| 397 | rt6_probe(rt); | ||
| 398 | } | ||
| 399 | } | ||
| 400 | 412 | ||
| 401 | if (!match && | 413 | if (!match && |
| 402 | (strict & RT6_LOOKUP_F_REACHABLE) && | 414 | (strict & RT6_LOOKUP_F_REACHABLE)) { |
| 403 | last && last != rt0) { | 415 | struct rt6_info *next = rt0->u.dst.rt6_next; |
| 416 | |||
| 404 | /* no entries matched; do round-robin */ | 417 | /* no entries matched; do round-robin */ |
| 405 | static DEFINE_SPINLOCK(lock); | 418 | if (!next || next->rt6i_metric != rt0->rt6i_metric) |
| 406 | spin_lock(&lock); | 419 | next = fn->leaf; |
| 407 | *head = rt0->u.dst.rt6_next; | 420 | |
| 408 | rt0->u.dst.rt6_next = last->u.dst.rt6_next; | 421 | if (next != rt0) |
| 409 | last->u.dst.rt6_next = rt0; | 422 | fn->rr_ptr = next; |
| 410 | spin_unlock(&lock); | ||
| 411 | } | 423 | } |
| 412 | 424 | ||
| 413 | RT6_TRACE("%s() => %p, score=%d\n", | 425 | RT6_TRACE("%s() => %p\n", |
| 414 | __FUNCTION__, match, mpri); | 426 | __FUNCTION__, match); |
| 415 | 427 | ||
| 416 | return (match ? match : &ip6_null_entry); | 428 | return (match ? match : &ip6_null_entry); |
| 417 | } | 429 | } |
| @@ -657,7 +669,7 @@ restart_2: | |||
| 657 | fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src); | 669 | fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src); |
| 658 | 670 | ||
| 659 | restart: | 671 | restart: |
| 660 | rt = rt6_select(&fn->leaf, fl->iif, strict | reachable); | 672 | rt = rt6_select(fn, fl->iif, strict | reachable); |
| 661 | BACKTRACK(&fl->fl6_src); | 673 | BACKTRACK(&fl->fl6_src); |
| 662 | if (rt == &ip6_null_entry || | 674 | if (rt == &ip6_null_entry || |
| 663 | rt->rt6i_flags & RTF_CACHE) | 675 | rt->rt6i_flags & RTF_CACHE) |
| @@ -752,7 +764,7 @@ restart_2: | |||
| 752 | fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src); | 764 | fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src); |
| 753 | 765 | ||
| 754 | restart: | 766 | restart: |
| 755 | rt = rt6_select(&fn->leaf, fl->oif, strict | reachable); | 767 | rt = rt6_select(fn, fl->oif, strict | reachable); |
| 756 | BACKTRACK(&fl->fl6_src); | 768 | BACKTRACK(&fl->fl6_src); |
| 757 | if (rt == &ip6_null_entry || | 769 | if (rt == &ip6_null_entry || |
| 758 | rt->rt6i_flags & RTF_CACHE) | 770 | rt->rt6i_flags & RTF_CACHE) |
| @@ -1754,13 +1766,22 @@ int ipv6_route_ioctl(unsigned int cmd, void __user *arg) | |||
| 1754 | * Drop the packet on the floor | 1766 | * Drop the packet on the floor |
| 1755 | */ | 1767 | */ |
| 1756 | 1768 | ||
| 1757 | static inline int ip6_pkt_drop(struct sk_buff *skb, int code) | 1769 | static inline int ip6_pkt_drop(struct sk_buff *skb, int code, |
| 1770 | int ipstats_mib_noroutes) | ||
| 1758 | { | 1771 | { |
| 1759 | int type = ipv6_addr_type(&skb->nh.ipv6h->daddr); | 1772 | int type; |
| 1760 | if (type == IPV6_ADDR_ANY || type == IPV6_ADDR_RESERVED) | 1773 | switch (ipstats_mib_noroutes) { |
| 1761 | IP6_INC_STATS(ip6_dst_idev(skb->dst), IPSTATS_MIB_INADDRERRORS); | 1774 | case IPSTATS_MIB_INNOROUTES: |
| 1762 | 1775 | type = ipv6_addr_type(&skb->nh.ipv6h->daddr); | |
| 1763 | IP6_INC_STATS(ip6_dst_idev(skb->dst), IPSTATS_MIB_OUTNOROUTES); | 1776 | if (type == IPV6_ADDR_ANY || type == IPV6_ADDR_RESERVED) { |
| 1777 | IP6_INC_STATS(ip6_dst_idev(skb->dst), IPSTATS_MIB_INADDRERRORS); | ||
| 1778 | break; | ||
| 1779 | } | ||
| 1780 | /* FALLTHROUGH */ | ||
| 1781 | case IPSTATS_MIB_OUTNOROUTES: | ||
| 1782 | IP6_INC_STATS(ip6_dst_idev(skb->dst), ipstats_mib_noroutes); | ||
| 1783 | break; | ||
| 1784 | } | ||
| 1764 | icmpv6_send(skb, ICMPV6_DEST_UNREACH, code, 0, skb->dev); | 1785 | icmpv6_send(skb, ICMPV6_DEST_UNREACH, code, 0, skb->dev); |
| 1765 | kfree_skb(skb); | 1786 | kfree_skb(skb); |
| 1766 | return 0; | 1787 | return 0; |
| @@ -1768,26 +1789,26 @@ static inline int ip6_pkt_drop(struct sk_buff *skb, int code) | |||
| 1768 | 1789 | ||
| 1769 | static int ip6_pkt_discard(struct sk_buff *skb) | 1790 | static int ip6_pkt_discard(struct sk_buff *skb) |
| 1770 | { | 1791 | { |
| 1771 | return ip6_pkt_drop(skb, ICMPV6_NOROUTE); | 1792 | return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_INNOROUTES); |
| 1772 | } | 1793 | } |
| 1773 | 1794 | ||
| 1774 | static int ip6_pkt_discard_out(struct sk_buff *skb) | 1795 | static int ip6_pkt_discard_out(struct sk_buff *skb) |
| 1775 | { | 1796 | { |
| 1776 | skb->dev = skb->dst->dev; | 1797 | skb->dev = skb->dst->dev; |
| 1777 | return ip6_pkt_discard(skb); | 1798 | return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_OUTNOROUTES); |
| 1778 | } | 1799 | } |
| 1779 | 1800 | ||
| 1780 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES | 1801 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES |
| 1781 | 1802 | ||
| 1782 | static int ip6_pkt_prohibit(struct sk_buff *skb) | 1803 | static int ip6_pkt_prohibit(struct sk_buff *skb) |
| 1783 | { | 1804 | { |
| 1784 | return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED); | 1805 | return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_INNOROUTES); |
| 1785 | } | 1806 | } |
| 1786 | 1807 | ||
| 1787 | static int ip6_pkt_prohibit_out(struct sk_buff *skb) | 1808 | static int ip6_pkt_prohibit_out(struct sk_buff *skb) |
| 1788 | { | 1809 | { |
| 1789 | skb->dev = skb->dst->dev; | 1810 | skb->dev = skb->dst->dev; |
| 1790 | return ip6_pkt_prohibit(skb); | 1811 | return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES); |
| 1791 | } | 1812 | } |
| 1792 | 1813 | ||
| 1793 | static int ip6_pkt_blk_hole(struct sk_buff *skb) | 1814 | static int ip6_pkt_blk_hole(struct sk_buff *skb) |
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index f57a9baa6b27..92f99927d12d 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
| @@ -1453,6 +1453,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
| 1453 | First: no IPv4 options. | 1453 | First: no IPv4 options. |
| 1454 | */ | 1454 | */ |
| 1455 | newinet->opt = NULL; | 1455 | newinet->opt = NULL; |
| 1456 | newnp->ipv6_fl_list = NULL; | ||
| 1456 | 1457 | ||
| 1457 | /* Clone RX bits */ | 1458 | /* Clone RX bits */ |
| 1458 | newnp->rxopt.all = np->rxopt.all; | 1459 | newnp->rxopt.all = np->rxopt.all; |
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 0ad471909881..f590db57a7c9 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
| @@ -615,7 +615,7 @@ do_udp_sendmsg: | |||
| 615 | return udp_sendmsg(iocb, sk, msg, len); | 615 | return udp_sendmsg(iocb, sk, msg, len); |
| 616 | 616 | ||
| 617 | /* Rough check on arithmetic overflow, | 617 | /* Rough check on arithmetic overflow, |
| 618 | better check is made in ip6_build_xmit | 618 | better check is made in ip6_append_data(). |
| 619 | */ | 619 | */ |
| 620 | if (len > INT_MAX - sizeof(struct udphdr)) | 620 | if (len > INT_MAX - sizeof(struct udphdr)) |
| 621 | return -EMSGSIZE; | 621 | return -EMSGSIZE; |
diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c index ee4b84a33ff4..93c42232aa39 100644 --- a/net/ipv6/xfrm6_tunnel.c +++ b/net/ipv6/xfrm6_tunnel.c | |||
| @@ -58,7 +58,7 @@ static struct kmem_cache *xfrm6_tunnel_spi_kmem __read_mostly; | |||
| 58 | static struct hlist_head xfrm6_tunnel_spi_byaddr[XFRM6_TUNNEL_SPI_BYADDR_HSIZE]; | 58 | static struct hlist_head xfrm6_tunnel_spi_byaddr[XFRM6_TUNNEL_SPI_BYADDR_HSIZE]; |
| 59 | static struct hlist_head xfrm6_tunnel_spi_byspi[XFRM6_TUNNEL_SPI_BYSPI_HSIZE]; | 59 | static struct hlist_head xfrm6_tunnel_spi_byspi[XFRM6_TUNNEL_SPI_BYSPI_HSIZE]; |
| 60 | 60 | ||
| 61 | static unsigned inline xfrm6_tunnel_spi_hash_byaddr(xfrm_address_t *addr) | 61 | static inline unsigned xfrm6_tunnel_spi_hash_byaddr(xfrm_address_t *addr) |
| 62 | { | 62 | { |
| 63 | unsigned h; | 63 | unsigned h; |
| 64 | 64 | ||
| @@ -70,7 +70,7 @@ static unsigned inline xfrm6_tunnel_spi_hash_byaddr(xfrm_address_t *addr) | |||
| 70 | return h; | 70 | return h; |
| 71 | } | 71 | } |
| 72 | 72 | ||
| 73 | static unsigned inline xfrm6_tunnel_spi_hash_byspi(u32 spi) | 73 | static inline unsigned xfrm6_tunnel_spi_hash_byspi(u32 spi) |
| 74 | { | 74 | { |
| 75 | return spi % XFRM6_TUNNEL_SPI_BYSPI_HSIZE; | 75 | return spi % XFRM6_TUNNEL_SPI_BYSPI_HSIZE; |
| 76 | } | 76 | } |
