diff options
Diffstat (limited to 'net/ipv6')
-rw-r--r-- | net/ipv6/addrconf.c | 82 | ||||
-rw-r--r-- | net/ipv6/addrlabel.c | 5 | ||||
-rw-r--r-- | net/ipv6/datagram.c | 13 | ||||
-rw-r--r-- | net/ipv6/icmp.c | 2 | ||||
-rw-r--r-- | net/ipv6/ip6_fib.c | 112 | ||||
-rw-r--r-- | net/ipv6/ip6_gre.c | 6 | ||||
-rw-r--r-- | net/ipv6/ip6_output.c | 374 | ||||
-rw-r--r-- | net/ipv6/ip6_tunnel.c | 9 | ||||
-rw-r--r-- | net/ipv6/ip6_udp_tunnel.c | 12 | ||||
-rw-r--r-- | net/ipv6/ip6_vti.c | 1 | ||||
-rw-r--r-- | net/ipv6/ip6mr.c | 3 | ||||
-rw-r--r-- | net/ipv6/ipv6_sockglue.c | 8 | ||||
-rw-r--r-- | net/ipv6/ndisc.c | 6 | ||||
-rw-r--r-- | net/ipv6/output_core.c | 40 | ||||
-rw-r--r-- | net/ipv6/ping.c | 3 | ||||
-rw-r--r-- | net/ipv6/raw.c | 7 | ||||
-rw-r--r-- | net/ipv6/route.c | 90 | ||||
-rw-r--r-- | net/ipv6/sit.c | 9 | ||||
-rw-r--r-- | net/ipv6/tcp_ipv6.c | 2 | ||||
-rw-r--r-- | net/ipv6/udp.c | 93 | ||||
-rw-r--r-- | net/ipv6/udp_offload.c | 10 | ||||
-rw-r--r-- | net/ipv6/xfrm6_policy.c | 10 |
22 files changed, 597 insertions, 300 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index f7c8bbeb27b7..98e4a63d72bb 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -201,6 +201,7 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = { | |||
201 | .disable_ipv6 = 0, | 201 | .disable_ipv6 = 0, |
202 | .accept_dad = 1, | 202 | .accept_dad = 1, |
203 | .suppress_frag_ndisc = 1, | 203 | .suppress_frag_ndisc = 1, |
204 | .accept_ra_mtu = 1, | ||
204 | }; | 205 | }; |
205 | 206 | ||
206 | static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { | 207 | static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { |
@@ -238,6 +239,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { | |||
238 | .disable_ipv6 = 0, | 239 | .disable_ipv6 = 0, |
239 | .accept_dad = 1, | 240 | .accept_dad = 1, |
240 | .suppress_frag_ndisc = 1, | 241 | .suppress_frag_ndisc = 1, |
242 | .accept_ra_mtu = 1, | ||
241 | }; | 243 | }; |
242 | 244 | ||
243 | /* Check if a valid qdisc is available */ | 245 | /* Check if a valid qdisc is available */ |
@@ -489,7 +491,8 @@ static int inet6_netconf_fill_devconf(struct sk_buff *skb, int ifindex, | |||
489 | nla_put_s32(skb, NETCONFA_PROXY_NEIGH, devconf->proxy_ndp) < 0) | 491 | nla_put_s32(skb, NETCONFA_PROXY_NEIGH, devconf->proxy_ndp) < 0) |
490 | goto nla_put_failure; | 492 | goto nla_put_failure; |
491 | 493 | ||
492 | return nlmsg_end(skb, nlh); | 494 | nlmsg_end(skb, nlh); |
495 | return 0; | ||
493 | 496 | ||
494 | nla_put_failure: | 497 | nla_put_failure: |
495 | nlmsg_cancel(skb, nlh); | 498 | nlmsg_cancel(skb, nlh); |
@@ -619,7 +622,7 @@ static int inet6_netconf_dump_devconf(struct sk_buff *skb, | |||
619 | cb->nlh->nlmsg_seq, | 622 | cb->nlh->nlmsg_seq, |
620 | RTM_NEWNETCONF, | 623 | RTM_NEWNETCONF, |
621 | NLM_F_MULTI, | 624 | NLM_F_MULTI, |
622 | -1) <= 0) { | 625 | -1) < 0) { |
623 | rcu_read_unlock(); | 626 | rcu_read_unlock(); |
624 | goto done; | 627 | goto done; |
625 | } | 628 | } |
@@ -635,7 +638,7 @@ cont: | |||
635 | NETLINK_CB(cb->skb).portid, | 638 | NETLINK_CB(cb->skb).portid, |
636 | cb->nlh->nlmsg_seq, | 639 | cb->nlh->nlmsg_seq, |
637 | RTM_NEWNETCONF, NLM_F_MULTI, | 640 | RTM_NEWNETCONF, NLM_F_MULTI, |
638 | -1) <= 0) | 641 | -1) < 0) |
639 | goto done; | 642 | goto done; |
640 | else | 643 | else |
641 | h++; | 644 | h++; |
@@ -646,7 +649,7 @@ cont: | |||
646 | NETLINK_CB(cb->skb).portid, | 649 | NETLINK_CB(cb->skb).portid, |
647 | cb->nlh->nlmsg_seq, | 650 | cb->nlh->nlmsg_seq, |
648 | RTM_NEWNETCONF, NLM_F_MULTI, | 651 | RTM_NEWNETCONF, NLM_F_MULTI, |
649 | -1) <= 0) | 652 | -1) < 0) |
650 | goto done; | 653 | goto done; |
651 | else | 654 | else |
652 | h++; | 655 | h++; |
@@ -1519,15 +1522,30 @@ static int ipv6_count_addresses(struct inet6_dev *idev) | |||
1519 | int ipv6_chk_addr(struct net *net, const struct in6_addr *addr, | 1522 | int ipv6_chk_addr(struct net *net, const struct in6_addr *addr, |
1520 | const struct net_device *dev, int strict) | 1523 | const struct net_device *dev, int strict) |
1521 | { | 1524 | { |
1525 | return ipv6_chk_addr_and_flags(net, addr, dev, strict, IFA_F_TENTATIVE); | ||
1526 | } | ||
1527 | EXPORT_SYMBOL(ipv6_chk_addr); | ||
1528 | |||
1529 | int ipv6_chk_addr_and_flags(struct net *net, const struct in6_addr *addr, | ||
1530 | const struct net_device *dev, int strict, | ||
1531 | u32 banned_flags) | ||
1532 | { | ||
1522 | struct inet6_ifaddr *ifp; | 1533 | struct inet6_ifaddr *ifp; |
1523 | unsigned int hash = inet6_addr_hash(addr); | 1534 | unsigned int hash = inet6_addr_hash(addr); |
1535 | u32 ifp_flags; | ||
1524 | 1536 | ||
1525 | rcu_read_lock_bh(); | 1537 | rcu_read_lock_bh(); |
1526 | hlist_for_each_entry_rcu(ifp, &inet6_addr_lst[hash], addr_lst) { | 1538 | hlist_for_each_entry_rcu(ifp, &inet6_addr_lst[hash], addr_lst) { |
1527 | if (!net_eq(dev_net(ifp->idev->dev), net)) | 1539 | if (!net_eq(dev_net(ifp->idev->dev), net)) |
1528 | continue; | 1540 | continue; |
1541 | /* Decouple optimistic from tentative for evaluation here. | ||
1542 | * Ban optimistic addresses explicitly, when required. | ||
1543 | */ | ||
1544 | ifp_flags = (ifp->flags&IFA_F_OPTIMISTIC) | ||
1545 | ? (ifp->flags&~IFA_F_TENTATIVE) | ||
1546 | : ifp->flags; | ||
1529 | if (ipv6_addr_equal(&ifp->addr, addr) && | 1547 | if (ipv6_addr_equal(&ifp->addr, addr) && |
1530 | !(ifp->flags&IFA_F_TENTATIVE) && | 1548 | !(ifp_flags&banned_flags) && |
1531 | (dev == NULL || ifp->idev->dev == dev || | 1549 | (dev == NULL || ifp->idev->dev == dev || |
1532 | !(ifp->scope&(IFA_LINK|IFA_HOST) || strict))) { | 1550 | !(ifp->scope&(IFA_LINK|IFA_HOST) || strict))) { |
1533 | rcu_read_unlock_bh(); | 1551 | rcu_read_unlock_bh(); |
@@ -1538,7 +1556,7 @@ int ipv6_chk_addr(struct net *net, const struct in6_addr *addr, | |||
1538 | rcu_read_unlock_bh(); | 1556 | rcu_read_unlock_bh(); |
1539 | return 0; | 1557 | return 0; |
1540 | } | 1558 | } |
1541 | EXPORT_SYMBOL(ipv6_chk_addr); | 1559 | EXPORT_SYMBOL(ipv6_chk_addr_and_flags); |
1542 | 1560 | ||
1543 | static bool ipv6_chk_same_addr(struct net *net, const struct in6_addr *addr, | 1561 | static bool ipv6_chk_same_addr(struct net *net, const struct in6_addr *addr, |
1544 | struct net_device *dev) | 1562 | struct net_device *dev) |
@@ -4047,7 +4065,8 @@ static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa, | |||
4047 | if (nla_put_u32(skb, IFA_FLAGS, ifa->flags) < 0) | 4065 | if (nla_put_u32(skb, IFA_FLAGS, ifa->flags) < 0) |
4048 | goto error; | 4066 | goto error; |
4049 | 4067 | ||
4050 | return nlmsg_end(skb, nlh); | 4068 | nlmsg_end(skb, nlh); |
4069 | return 0; | ||
4051 | 4070 | ||
4052 | error: | 4071 | error: |
4053 | nlmsg_cancel(skb, nlh); | 4072 | nlmsg_cancel(skb, nlh); |
@@ -4076,7 +4095,8 @@ static int inet6_fill_ifmcaddr(struct sk_buff *skb, struct ifmcaddr6 *ifmca, | |||
4076 | return -EMSGSIZE; | 4095 | return -EMSGSIZE; |
4077 | } | 4096 | } |
4078 | 4097 | ||
4079 | return nlmsg_end(skb, nlh); | 4098 | nlmsg_end(skb, nlh); |
4099 | return 0; | ||
4080 | } | 4100 | } |
4081 | 4101 | ||
4082 | static int inet6_fill_ifacaddr(struct sk_buff *skb, struct ifacaddr6 *ifaca, | 4102 | static int inet6_fill_ifacaddr(struct sk_buff *skb, struct ifacaddr6 *ifaca, |
@@ -4101,7 +4121,8 @@ static int inet6_fill_ifacaddr(struct sk_buff *skb, struct ifacaddr6 *ifaca, | |||
4101 | return -EMSGSIZE; | 4121 | return -EMSGSIZE; |
4102 | } | 4122 | } |
4103 | 4123 | ||
4104 | return nlmsg_end(skb, nlh); | 4124 | nlmsg_end(skb, nlh); |
4125 | return 0; | ||
4105 | } | 4126 | } |
4106 | 4127 | ||
4107 | enum addr_type_t { | 4128 | enum addr_type_t { |
@@ -4134,7 +4155,7 @@ static int in6_dump_addrs(struct inet6_dev *idev, struct sk_buff *skb, | |||
4134 | cb->nlh->nlmsg_seq, | 4155 | cb->nlh->nlmsg_seq, |
4135 | RTM_NEWADDR, | 4156 | RTM_NEWADDR, |
4136 | NLM_F_MULTI); | 4157 | NLM_F_MULTI); |
4137 | if (err <= 0) | 4158 | if (err < 0) |
4138 | break; | 4159 | break; |
4139 | nl_dump_check_consistent(cb, nlmsg_hdr(skb)); | 4160 | nl_dump_check_consistent(cb, nlmsg_hdr(skb)); |
4140 | } | 4161 | } |
@@ -4151,7 +4172,7 @@ static int in6_dump_addrs(struct inet6_dev *idev, struct sk_buff *skb, | |||
4151 | cb->nlh->nlmsg_seq, | 4172 | cb->nlh->nlmsg_seq, |
4152 | RTM_GETMULTICAST, | 4173 | RTM_GETMULTICAST, |
4153 | NLM_F_MULTI); | 4174 | NLM_F_MULTI); |
4154 | if (err <= 0) | 4175 | if (err < 0) |
4155 | break; | 4176 | break; |
4156 | } | 4177 | } |
4157 | break; | 4178 | break; |
@@ -4166,7 +4187,7 @@ static int in6_dump_addrs(struct inet6_dev *idev, struct sk_buff *skb, | |||
4166 | cb->nlh->nlmsg_seq, | 4187 | cb->nlh->nlmsg_seq, |
4167 | RTM_GETANYCAST, | 4188 | RTM_GETANYCAST, |
4168 | NLM_F_MULTI); | 4189 | NLM_F_MULTI); |
4169 | if (err <= 0) | 4190 | if (err < 0) |
4170 | break; | 4191 | break; |
4171 | } | 4192 | } |
4172 | break; | 4193 | break; |
@@ -4209,7 +4230,7 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb, | |||
4209 | goto cont; | 4230 | goto cont; |
4210 | 4231 | ||
4211 | if (in6_dump_addrs(idev, skb, cb, type, | 4232 | if (in6_dump_addrs(idev, skb, cb, type, |
4212 | s_ip_idx, &ip_idx) <= 0) | 4233 | s_ip_idx, &ip_idx) < 0) |
4213 | goto done; | 4234 | goto done; |
4214 | cont: | 4235 | cont: |
4215 | idx++; | 4236 | idx++; |
@@ -4376,6 +4397,7 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf, | |||
4376 | array[DEVCONF_NDISC_NOTIFY] = cnf->ndisc_notify; | 4397 | array[DEVCONF_NDISC_NOTIFY] = cnf->ndisc_notify; |
4377 | array[DEVCONF_SUPPRESS_FRAG_NDISC] = cnf->suppress_frag_ndisc; | 4398 | array[DEVCONF_SUPPRESS_FRAG_NDISC] = cnf->suppress_frag_ndisc; |
4378 | array[DEVCONF_ACCEPT_RA_FROM_LOCAL] = cnf->accept_ra_from_local; | 4399 | array[DEVCONF_ACCEPT_RA_FROM_LOCAL] = cnf->accept_ra_from_local; |
4400 | array[DEVCONF_ACCEPT_RA_MTU] = cnf->accept_ra_mtu; | ||
4379 | } | 4401 | } |
4380 | 4402 | ||
4381 | static inline size_t inet6_ifla6_size(void) | 4403 | static inline size_t inet6_ifla6_size(void) |
@@ -4572,6 +4594,22 @@ static int inet6_set_iftoken(struct inet6_dev *idev, struct in6_addr *token) | |||
4572 | return 0; | 4594 | return 0; |
4573 | } | 4595 | } |
4574 | 4596 | ||
4597 | static const struct nla_policy inet6_af_policy[IFLA_INET6_MAX + 1] = { | ||
4598 | [IFLA_INET6_ADDR_GEN_MODE] = { .type = NLA_U8 }, | ||
4599 | [IFLA_INET6_TOKEN] = { .len = sizeof(struct in6_addr) }, | ||
4600 | }; | ||
4601 | |||
4602 | static int inet6_validate_link_af(const struct net_device *dev, | ||
4603 | const struct nlattr *nla) | ||
4604 | { | ||
4605 | struct nlattr *tb[IFLA_INET6_MAX + 1]; | ||
4606 | |||
4607 | if (dev && !__in6_dev_get(dev)) | ||
4608 | return -EAFNOSUPPORT; | ||
4609 | |||
4610 | return nla_parse_nested(tb, IFLA_INET6_MAX, nla, inet6_af_policy); | ||
4611 | } | ||
4612 | |||
4575 | static int inet6_set_link_af(struct net_device *dev, const struct nlattr *nla) | 4613 | static int inet6_set_link_af(struct net_device *dev, const struct nlattr *nla) |
4576 | { | 4614 | { |
4577 | int err = -EINVAL; | 4615 | int err = -EINVAL; |
@@ -4638,7 +4676,8 @@ static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev, | |||
4638 | goto nla_put_failure; | 4676 | goto nla_put_failure; |
4639 | 4677 | ||
4640 | nla_nest_end(skb, protoinfo); | 4678 | nla_nest_end(skb, protoinfo); |
4641 | return nlmsg_end(skb, nlh); | 4679 | nlmsg_end(skb, nlh); |
4680 | return 0; | ||
4642 | 4681 | ||
4643 | nla_put_failure: | 4682 | nla_put_failure: |
4644 | nlmsg_cancel(skb, nlh); | 4683 | nlmsg_cancel(skb, nlh); |
@@ -4670,7 +4709,7 @@ static int inet6_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) | |||
4670 | if (inet6_fill_ifinfo(skb, idev, | 4709 | if (inet6_fill_ifinfo(skb, idev, |
4671 | NETLINK_CB(cb->skb).portid, | 4710 | NETLINK_CB(cb->skb).portid, |
4672 | cb->nlh->nlmsg_seq, | 4711 | cb->nlh->nlmsg_seq, |
4673 | RTM_NEWLINK, NLM_F_MULTI) <= 0) | 4712 | RTM_NEWLINK, NLM_F_MULTI) < 0) |
4674 | goto out; | 4713 | goto out; |
4675 | cont: | 4714 | cont: |
4676 | idx++; | 4715 | idx++; |
@@ -4747,7 +4786,8 @@ static int inet6_fill_prefix(struct sk_buff *skb, struct inet6_dev *idev, | |||
4747 | ci.valid_time = ntohl(pinfo->valid); | 4786 | ci.valid_time = ntohl(pinfo->valid); |
4748 | if (nla_put(skb, PREFIX_CACHEINFO, sizeof(ci), &ci)) | 4787 | if (nla_put(skb, PREFIX_CACHEINFO, sizeof(ci), &ci)) |
4749 | goto nla_put_failure; | 4788 | goto nla_put_failure; |
4750 | return nlmsg_end(skb, nlh); | 4789 | nlmsg_end(skb, nlh); |
4790 | return 0; | ||
4751 | 4791 | ||
4752 | nla_put_failure: | 4792 | nla_put_failure: |
4753 | nlmsg_cancel(skb, nlh); | 4793 | nlmsg_cancel(skb, nlh); |
@@ -5253,6 +5293,13 @@ static struct addrconf_sysctl_table | |||
5253 | .proc_handler = proc_dointvec, | 5293 | .proc_handler = proc_dointvec, |
5254 | }, | 5294 | }, |
5255 | { | 5295 | { |
5296 | .procname = "accept_ra_mtu", | ||
5297 | .data = &ipv6_devconf.accept_ra_mtu, | ||
5298 | .maxlen = sizeof(int), | ||
5299 | .mode = 0644, | ||
5300 | .proc_handler = proc_dointvec, | ||
5301 | }, | ||
5302 | { | ||
5256 | /* sentinel */ | 5303 | /* sentinel */ |
5257 | } | 5304 | } |
5258 | }, | 5305 | }, |
@@ -5389,10 +5436,11 @@ static struct pernet_operations addrconf_ops = { | |||
5389 | .exit = addrconf_exit_net, | 5436 | .exit = addrconf_exit_net, |
5390 | }; | 5437 | }; |
5391 | 5438 | ||
5392 | static struct rtnl_af_ops inet6_ops = { | 5439 | static struct rtnl_af_ops inet6_ops __read_mostly = { |
5393 | .family = AF_INET6, | 5440 | .family = AF_INET6, |
5394 | .fill_link_af = inet6_fill_link_af, | 5441 | .fill_link_af = inet6_fill_link_af, |
5395 | .get_link_af_size = inet6_get_link_af_size, | 5442 | .get_link_af_size = inet6_get_link_af_size, |
5443 | .validate_link_af = inet6_validate_link_af, | ||
5396 | .set_link_af = inet6_set_link_af, | 5444 | .set_link_af = inet6_set_link_af, |
5397 | }; | 5445 | }; |
5398 | 5446 | ||
diff --git a/net/ipv6/addrlabel.c b/net/ipv6/addrlabel.c index fd0dc47f471d..e43e79d0a612 100644 --- a/net/ipv6/addrlabel.c +++ b/net/ipv6/addrlabel.c | |||
@@ -490,7 +490,8 @@ static int ip6addrlbl_fill(struct sk_buff *skb, | |||
490 | return -EMSGSIZE; | 490 | return -EMSGSIZE; |
491 | } | 491 | } |
492 | 492 | ||
493 | return nlmsg_end(skb, nlh); | 493 | nlmsg_end(skb, nlh); |
494 | return 0; | ||
494 | } | 495 | } |
495 | 496 | ||
496 | static int ip6addrlbl_dump(struct sk_buff *skb, struct netlink_callback *cb) | 497 | static int ip6addrlbl_dump(struct sk_buff *skb, struct netlink_callback *cb) |
@@ -510,7 +511,7 @@ static int ip6addrlbl_dump(struct sk_buff *skb, struct netlink_callback *cb) | |||
510 | cb->nlh->nlmsg_seq, | 511 | cb->nlh->nlmsg_seq, |
511 | RTM_NEWADDRLABEL, | 512 | RTM_NEWADDRLABEL, |
512 | NLM_F_MULTI); | 513 | NLM_F_MULTI); |
513 | if (err <= 0) | 514 | if (err < 0) |
514 | break; | 515 | break; |
515 | } | 516 | } |
516 | idx++; | 517 | idx++; |
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index 100c589a2a6c..c215be70cac0 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c | |||
@@ -369,7 +369,7 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len) | |||
369 | 369 | ||
370 | serr = SKB_EXT_ERR(skb); | 370 | serr = SKB_EXT_ERR(skb); |
371 | 371 | ||
372 | if (sin) { | 372 | if (sin && skb->len) { |
373 | const unsigned char *nh = skb_network_header(skb); | 373 | const unsigned char *nh = skb_network_header(skb); |
374 | sin->sin6_family = AF_INET6; | 374 | sin->sin6_family = AF_INET6; |
375 | sin->sin6_flowinfo = 0; | 375 | sin->sin6_flowinfo = 0; |
@@ -393,11 +393,9 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len) | |||
393 | 393 | ||
394 | memcpy(&errhdr.ee, &serr->ee, sizeof(struct sock_extended_err)); | 394 | memcpy(&errhdr.ee, &serr->ee, sizeof(struct sock_extended_err)); |
395 | sin = &errhdr.offender; | 395 | sin = &errhdr.offender; |
396 | sin->sin6_family = AF_UNSPEC; | 396 | memset(sin, 0, sizeof(*sin)); |
397 | if (serr->ee.ee_origin != SO_EE_ORIGIN_LOCAL) { | 397 | if (serr->ee.ee_origin != SO_EE_ORIGIN_LOCAL && skb->len) { |
398 | sin->sin6_family = AF_INET6; | 398 | sin->sin6_family = AF_INET6; |
399 | sin->sin6_flowinfo = 0; | ||
400 | sin->sin6_port = 0; | ||
401 | if (np->rxopt.all) { | 399 | if (np->rxopt.all) { |
402 | if (serr->ee.ee_origin != SO_EE_ORIGIN_ICMP && | 400 | if (serr->ee.ee_origin != SO_EE_ORIGIN_ICMP && |
403 | serr->ee.ee_origin != SO_EE_ORIGIN_ICMP6) | 401 | serr->ee.ee_origin != SO_EE_ORIGIN_ICMP6) |
@@ -412,12 +410,9 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len) | |||
412 | ipv6_iface_scope_id(&sin->sin6_addr, | 410 | ipv6_iface_scope_id(&sin->sin6_addr, |
413 | IP6CB(skb)->iif); | 411 | IP6CB(skb)->iif); |
414 | } else { | 412 | } else { |
415 | struct inet_sock *inet = inet_sk(sk); | ||
416 | |||
417 | ipv6_addr_set_v4mapped(ip_hdr(skb)->saddr, | 413 | ipv6_addr_set_v4mapped(ip_hdr(skb)->saddr, |
418 | &sin->sin6_addr); | 414 | &sin->sin6_addr); |
419 | sin->sin6_scope_id = 0; | 415 | if (inet_sk(sk)->cmsg_flags) |
420 | if (inet->cmsg_flags) | ||
421 | ip_cmsg_recv(msg, skb); | 416 | ip_cmsg_recv(msg, skb); |
422 | } | 417 | } |
423 | } | 418 | } |
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index d674152b6ede..a5e95199585e 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c | |||
@@ -427,7 +427,7 @@ static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info) | |||
427 | * Dest addr check | 427 | * Dest addr check |
428 | */ | 428 | */ |
429 | 429 | ||
430 | if ((addr_type & IPV6_ADDR_MULTICAST || skb->pkt_type != PACKET_HOST)) { | 430 | if (addr_type & IPV6_ADDR_MULTICAST || skb->pkt_type != PACKET_HOST) { |
431 | if (type != ICMPV6_PKT_TOOBIG && | 431 | if (type != ICMPV6_PKT_TOOBIG && |
432 | !(type == ICMPV6_PARAMPROB && | 432 | !(type == ICMPV6_PARAMPROB && |
433 | code == ICMPV6_UNK_OPTION && | 433 | code == ICMPV6_UNK_OPTION && |
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index b2d1838897c9..263ef4143bff 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c | |||
@@ -277,7 +277,6 @@ static int fib6_dump_node(struct fib6_walker *w) | |||
277 | w->leaf = rt; | 277 | w->leaf = rt; |
278 | return 1; | 278 | return 1; |
279 | } | 279 | } |
280 | WARN_ON(res == 0); | ||
281 | } | 280 | } |
282 | w->leaf = NULL; | 281 | w->leaf = NULL; |
283 | return 0; | 282 | return 0; |
@@ -630,33 +629,59 @@ static bool rt6_qualify_for_ecmp(struct rt6_info *rt) | |||
630 | RTF_GATEWAY; | 629 | RTF_GATEWAY; |
631 | } | 630 | } |
632 | 631 | ||
633 | static int fib6_commit_metrics(struct dst_entry *dst, | 632 | static void fib6_copy_metrics(u32 *mp, const struct mx6_config *mxc) |
634 | struct nlattr *mx, int mx_len) | ||
635 | { | 633 | { |
636 | struct nlattr *nla; | 634 | int i; |
637 | int remaining; | 635 | |
638 | u32 *mp; | 636 | for (i = 0; i < RTAX_MAX; i++) { |
637 | if (test_bit(i, mxc->mx_valid)) | ||
638 | mp[i] = mxc->mx[i]; | ||
639 | } | ||
640 | } | ||
641 | |||
642 | static int fib6_commit_metrics(struct dst_entry *dst, struct mx6_config *mxc) | ||
643 | { | ||
644 | if (!mxc->mx) | ||
645 | return 0; | ||
639 | 646 | ||
640 | if (dst->flags & DST_HOST) { | 647 | if (dst->flags & DST_HOST) { |
641 | mp = dst_metrics_write_ptr(dst); | 648 | u32 *mp = dst_metrics_write_ptr(dst); |
642 | } else { | 649 | |
643 | mp = kzalloc(sizeof(u32) * RTAX_MAX, GFP_ATOMIC); | 650 | if (unlikely(!mp)) |
644 | if (!mp) | ||
645 | return -ENOMEM; | 651 | return -ENOMEM; |
646 | dst_init_metrics(dst, mp, 0); | ||
647 | } | ||
648 | 652 | ||
649 | nla_for_each_attr(nla, mx, mx_len, remaining) { | 653 | fib6_copy_metrics(mp, mxc); |
650 | int type = nla_type(nla); | 654 | } else { |
655 | dst_init_metrics(dst, mxc->mx, false); | ||
651 | 656 | ||
652 | if (type) { | 657 | /* We've stolen mx now. */ |
653 | if (type > RTAX_MAX) | 658 | mxc->mx = NULL; |
654 | return -EINVAL; | 659 | } |
655 | 660 | ||
656 | mp[type - 1] = nla_get_u32(nla); | 661 | return 0; |
662 | } | ||
663 | |||
664 | static void fib6_purge_rt(struct rt6_info *rt, struct fib6_node *fn, | ||
665 | struct net *net) | ||
666 | { | ||
667 | if (atomic_read(&rt->rt6i_ref) != 1) { | ||
668 | /* This route is used as dummy address holder in some split | ||
669 | * nodes. It is not leaked, but it still holds other resources, | ||
670 | * which must be released in time. So, scan ascendant nodes | ||
671 | * and replace dummy references to this route with references | ||
672 | * to still alive ones. | ||
673 | */ | ||
674 | while (fn) { | ||
675 | if (!(fn->fn_flags & RTN_RTINFO) && fn->leaf == rt) { | ||
676 | fn->leaf = fib6_find_prefix(net, fn); | ||
677 | atomic_inc(&fn->leaf->rt6i_ref); | ||
678 | rt6_release(rt); | ||
679 | } | ||
680 | fn = fn->parent; | ||
657 | } | 681 | } |
682 | /* No more references are possible at this point. */ | ||
683 | BUG_ON(atomic_read(&rt->rt6i_ref) != 1); | ||
658 | } | 684 | } |
659 | return 0; | ||
660 | } | 685 | } |
661 | 686 | ||
662 | /* | 687 | /* |
@@ -664,7 +689,7 @@ static int fib6_commit_metrics(struct dst_entry *dst, | |||
664 | */ | 689 | */ |
665 | 690 | ||
666 | static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt, | 691 | static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt, |
667 | struct nl_info *info, struct nlattr *mx, int mx_len) | 692 | struct nl_info *info, struct mx6_config *mxc) |
668 | { | 693 | { |
669 | struct rt6_info *iter = NULL; | 694 | struct rt6_info *iter = NULL; |
670 | struct rt6_info **ins; | 695 | struct rt6_info **ins; |
@@ -773,11 +798,10 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt, | |||
773 | pr_warn("NLM_F_CREATE should be set when creating new route\n"); | 798 | pr_warn("NLM_F_CREATE should be set when creating new route\n"); |
774 | 799 | ||
775 | add: | 800 | add: |
776 | if (mx) { | 801 | err = fib6_commit_metrics(&rt->dst, mxc); |
777 | err = fib6_commit_metrics(&rt->dst, mx, mx_len); | 802 | if (err) |
778 | if (err) | 803 | return err; |
779 | return err; | 804 | |
780 | } | ||
781 | rt->dst.rt6_next = iter; | 805 | rt->dst.rt6_next = iter; |
782 | *ins = rt; | 806 | *ins = rt; |
783 | rt->rt6i_node = fn; | 807 | rt->rt6i_node = fn; |
@@ -797,21 +821,22 @@ add: | |||
797 | pr_warn("NLM_F_REPLACE set, but no existing node found!\n"); | 821 | pr_warn("NLM_F_REPLACE set, but no existing node found!\n"); |
798 | return -ENOENT; | 822 | return -ENOENT; |
799 | } | 823 | } |
800 | if (mx) { | 824 | |
801 | err = fib6_commit_metrics(&rt->dst, mx, mx_len); | 825 | err = fib6_commit_metrics(&rt->dst, mxc); |
802 | if (err) | 826 | if (err) |
803 | return err; | 827 | return err; |
804 | } | 828 | |
805 | *ins = rt; | 829 | *ins = rt; |
806 | rt->rt6i_node = fn; | 830 | rt->rt6i_node = fn; |
807 | rt->dst.rt6_next = iter->dst.rt6_next; | 831 | rt->dst.rt6_next = iter->dst.rt6_next; |
808 | atomic_inc(&rt->rt6i_ref); | 832 | atomic_inc(&rt->rt6i_ref); |
809 | inet6_rt_notify(RTM_NEWROUTE, rt, info); | 833 | inet6_rt_notify(RTM_NEWROUTE, rt, info); |
810 | rt6_release(iter); | ||
811 | if (!(fn->fn_flags & RTN_RTINFO)) { | 834 | if (!(fn->fn_flags & RTN_RTINFO)) { |
812 | info->nl_net->ipv6.rt6_stats->fib_route_nodes++; | 835 | info->nl_net->ipv6.rt6_stats->fib_route_nodes++; |
813 | fn->fn_flags |= RTN_RTINFO; | 836 | fn->fn_flags |= RTN_RTINFO; |
814 | } | 837 | } |
838 | fib6_purge_rt(iter, fn, info->nl_net); | ||
839 | rt6_release(iter); | ||
815 | } | 840 | } |
816 | 841 | ||
817 | return 0; | 842 | return 0; |
@@ -838,8 +863,8 @@ void fib6_force_start_gc(struct net *net) | |||
838 | * with source addr info in sub-trees | 863 | * with source addr info in sub-trees |
839 | */ | 864 | */ |
840 | 865 | ||
841 | int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info, | 866 | int fib6_add(struct fib6_node *root, struct rt6_info *rt, |
842 | struct nlattr *mx, int mx_len) | 867 | struct nl_info *info, struct mx6_config *mxc) |
843 | { | 868 | { |
844 | struct fib6_node *fn, *pn = NULL; | 869 | struct fib6_node *fn, *pn = NULL; |
845 | int err = -ENOMEM; | 870 | int err = -ENOMEM; |
@@ -934,7 +959,7 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info, | |||
934 | } | 959 | } |
935 | #endif | 960 | #endif |
936 | 961 | ||
937 | err = fib6_add_rt2node(fn, rt, info, mx, mx_len); | 962 | err = fib6_add_rt2node(fn, rt, info, mxc); |
938 | if (!err) { | 963 | if (!err) { |
939 | fib6_start_gc(info->nl_net, rt); | 964 | fib6_start_gc(info->nl_net, rt); |
940 | if (!(rt->rt6i_flags & RTF_CACHE)) | 965 | if (!(rt->rt6i_flags & RTF_CACHE)) |
@@ -1322,24 +1347,7 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp, | |||
1322 | fn = fib6_repair_tree(net, fn); | 1347 | fn = fib6_repair_tree(net, fn); |
1323 | } | 1348 | } |
1324 | 1349 | ||
1325 | if (atomic_read(&rt->rt6i_ref) != 1) { | 1350 | fib6_purge_rt(rt, fn, net); |
1326 | /* This route is used as dummy address holder in some split | ||
1327 | * nodes. It is not leaked, but it still holds other resources, | ||
1328 | * which must be released in time. So, scan ascendant nodes | ||
1329 | * and replace dummy references to this route with references | ||
1330 | * to still alive ones. | ||
1331 | */ | ||
1332 | while (fn) { | ||
1333 | if (!(fn->fn_flags & RTN_RTINFO) && fn->leaf == rt) { | ||
1334 | fn->leaf = fib6_find_prefix(net, fn); | ||
1335 | atomic_inc(&fn->leaf->rt6i_ref); | ||
1336 | rt6_release(rt); | ||
1337 | } | ||
1338 | fn = fn->parent; | ||
1339 | } | ||
1340 | /* No more references are possible at this point. */ | ||
1341 | BUG_ON(atomic_read(&rt->rt6i_ref) != 1); | ||
1342 | } | ||
1343 | 1351 | ||
1344 | inet6_rt_notify(RTM_DELROUTE, rt, info); | 1352 | inet6_rt_notify(RTM_DELROUTE, rt, info); |
1345 | rt6_release(rt); | 1353 | rt6_release(rt); |
diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index 13cda4c6313b..bc28b7d42a6d 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c | |||
@@ -417,7 +417,7 @@ static void ip6gre_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
417 | if (code == ICMPV6_HDR_FIELD) | 417 | if (code == ICMPV6_HDR_FIELD) |
418 | teli = ip6_tnl_parse_tlv_enc_lim(skb, skb->data); | 418 | teli = ip6_tnl_parse_tlv_enc_lim(skb, skb->data); |
419 | 419 | ||
420 | if (teli && teli == info - 2) { | 420 | if (teli && teli == be32_to_cpu(info) - 2) { |
421 | tel = (struct ipv6_tlv_tnl_enc_lim *) &skb->data[teli]; | 421 | tel = (struct ipv6_tlv_tnl_enc_lim *) &skb->data[teli]; |
422 | if (tel->encap_limit == 0) { | 422 | if (tel->encap_limit == 0) { |
423 | net_warn_ratelimited("%s: Too small encapsulation limit or routing loop in tunnel!\n", | 423 | net_warn_ratelimited("%s: Too small encapsulation limit or routing loop in tunnel!\n", |
@@ -429,7 +429,7 @@ static void ip6gre_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
429 | } | 429 | } |
430 | break; | 430 | break; |
431 | case ICMPV6_PKT_TOOBIG: | 431 | case ICMPV6_PKT_TOOBIG: |
432 | mtu = info - offset; | 432 | mtu = be32_to_cpu(info) - offset; |
433 | if (mtu < IPV6_MIN_MTU) | 433 | if (mtu < IPV6_MIN_MTU) |
434 | mtu = IPV6_MIN_MTU; | 434 | mtu = IPV6_MIN_MTU; |
435 | t->dev->mtu = mtu; | 435 | t->dev->mtu = mtu; |
@@ -1662,6 +1662,7 @@ static struct rtnl_link_ops ip6gre_link_ops __read_mostly = { | |||
1662 | .dellink = ip6gre_dellink, | 1662 | .dellink = ip6gre_dellink, |
1663 | .get_size = ip6gre_get_size, | 1663 | .get_size = ip6gre_get_size, |
1664 | .fill_info = ip6gre_fill_info, | 1664 | .fill_info = ip6gre_fill_info, |
1665 | .get_link_net = ip6_tnl_get_link_net, | ||
1665 | }; | 1666 | }; |
1666 | 1667 | ||
1667 | static struct rtnl_link_ops ip6gre_tap_ops __read_mostly = { | 1668 | static struct rtnl_link_ops ip6gre_tap_ops __read_mostly = { |
@@ -1675,6 +1676,7 @@ static struct rtnl_link_ops ip6gre_tap_ops __read_mostly = { | |||
1675 | .changelink = ip6gre_changelink, | 1676 | .changelink = ip6gre_changelink, |
1676 | .get_size = ip6gre_get_size, | 1677 | .get_size = ip6gre_get_size, |
1677 | .fill_info = ip6gre_fill_info, | 1678 | .fill_info = ip6gre_fill_info, |
1679 | .get_link_net = ip6_tnl_get_link_net, | ||
1678 | }; | 1680 | }; |
1679 | 1681 | ||
1680 | /* | 1682 | /* |
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index ce69a12ae48c..d33df4cbd872 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c | |||
@@ -537,20 +537,6 @@ static void ip6_copy_metadata(struct sk_buff *to, struct sk_buff *from) | |||
537 | skb_copy_secmark(to, from); | 537 | skb_copy_secmark(to, from); |
538 | } | 538 | } |
539 | 539 | ||
540 | static void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt) | ||
541 | { | ||
542 | static u32 ip6_idents_hashrnd __read_mostly; | ||
543 | u32 hash, id; | ||
544 | |||
545 | net_get_random_once(&ip6_idents_hashrnd, sizeof(ip6_idents_hashrnd)); | ||
546 | |||
547 | hash = __ipv6_addr_jhash(&rt->rt6i_dst.addr, ip6_idents_hashrnd); | ||
548 | hash = __ipv6_addr_jhash(&rt->rt6i_src.addr, hash); | ||
549 | |||
550 | id = ip_idents_reserve(hash, 1); | ||
551 | fhdr->identification = htonl(id); | ||
552 | } | ||
553 | |||
554 | int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) | 540 | int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) |
555 | { | 541 | { |
556 | struct sk_buff *frag; | 542 | struct sk_buff *frag; |
@@ -1041,6 +1027,7 @@ struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6, | |||
1041 | EXPORT_SYMBOL_GPL(ip6_sk_dst_lookup_flow); | 1027 | EXPORT_SYMBOL_GPL(ip6_sk_dst_lookup_flow); |
1042 | 1028 | ||
1043 | static inline int ip6_ufo_append_data(struct sock *sk, | 1029 | static inline int ip6_ufo_append_data(struct sock *sk, |
1030 | struct sk_buff_head *queue, | ||
1044 | int getfrag(void *from, char *to, int offset, int len, | 1031 | int getfrag(void *from, char *to, int offset, int len, |
1045 | int odd, struct sk_buff *skb), | 1032 | int odd, struct sk_buff *skb), |
1046 | void *from, int length, int hh_len, int fragheaderlen, | 1033 | void *from, int length, int hh_len, int fragheaderlen, |
@@ -1056,7 +1043,7 @@ static inline int ip6_ufo_append_data(struct sock *sk, | |||
1056 | * device, so create one single skb packet containing complete | 1043 | * device, so create one single skb packet containing complete |
1057 | * udp datagram | 1044 | * udp datagram |
1058 | */ | 1045 | */ |
1059 | skb = skb_peek_tail(&sk->sk_write_queue); | 1046 | skb = skb_peek_tail(queue); |
1060 | if (skb == NULL) { | 1047 | if (skb == NULL) { |
1061 | skb = sock_alloc_send_skb(sk, | 1048 | skb = sock_alloc_send_skb(sk, |
1062 | hh_len + fragheaderlen + transhdrlen + 20, | 1049 | hh_len + fragheaderlen + transhdrlen + 20, |
@@ -1079,7 +1066,7 @@ static inline int ip6_ufo_append_data(struct sock *sk, | |||
1079 | skb->protocol = htons(ETH_P_IPV6); | 1066 | skb->protocol = htons(ETH_P_IPV6); |
1080 | skb->csum = 0; | 1067 | skb->csum = 0; |
1081 | 1068 | ||
1082 | __skb_queue_tail(&sk->sk_write_queue, skb); | 1069 | __skb_queue_tail(queue, skb); |
1083 | } else if (skb_is_gso(skb)) { | 1070 | } else if (skb_is_gso(skb)) { |
1084 | goto append; | 1071 | goto append; |
1085 | } | 1072 | } |
@@ -1135,99 +1122,106 @@ static void ip6_append_data_mtu(unsigned int *mtu, | |||
1135 | } | 1122 | } |
1136 | } | 1123 | } |
1137 | 1124 | ||
1138 | int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, | 1125 | static int ip6_setup_cork(struct sock *sk, struct inet_cork_full *cork, |
1139 | int offset, int len, int odd, struct sk_buff *skb), | 1126 | struct inet6_cork *v6_cork, |
1140 | void *from, int length, int transhdrlen, | 1127 | int hlimit, int tclass, struct ipv6_txoptions *opt, |
1141 | int hlimit, int tclass, struct ipv6_txoptions *opt, struct flowi6 *fl6, | 1128 | struct rt6_info *rt, struct flowi6 *fl6) |
1142 | struct rt6_info *rt, unsigned int flags, int dontfrag) | ||
1143 | { | 1129 | { |
1144 | struct inet_sock *inet = inet_sk(sk); | ||
1145 | struct ipv6_pinfo *np = inet6_sk(sk); | 1130 | struct ipv6_pinfo *np = inet6_sk(sk); |
1146 | struct inet_cork *cork; | 1131 | unsigned int mtu; |
1132 | |||
1133 | /* | ||
1134 | * setup for corking | ||
1135 | */ | ||
1136 | if (opt) { | ||
1137 | if (WARN_ON(v6_cork->opt)) | ||
1138 | return -EINVAL; | ||
1139 | |||
1140 | v6_cork->opt = kzalloc(opt->tot_len, sk->sk_allocation); | ||
1141 | if (unlikely(v6_cork->opt == NULL)) | ||
1142 | return -ENOBUFS; | ||
1143 | |||
1144 | v6_cork->opt->tot_len = opt->tot_len; | ||
1145 | v6_cork->opt->opt_flen = opt->opt_flen; | ||
1146 | v6_cork->opt->opt_nflen = opt->opt_nflen; | ||
1147 | |||
1148 | v6_cork->opt->dst0opt = ip6_opt_dup(opt->dst0opt, | ||
1149 | sk->sk_allocation); | ||
1150 | if (opt->dst0opt && !v6_cork->opt->dst0opt) | ||
1151 | return -ENOBUFS; | ||
1152 | |||
1153 | v6_cork->opt->dst1opt = ip6_opt_dup(opt->dst1opt, | ||
1154 | sk->sk_allocation); | ||
1155 | if (opt->dst1opt && !v6_cork->opt->dst1opt) | ||
1156 | return -ENOBUFS; | ||
1157 | |||
1158 | v6_cork->opt->hopopt = ip6_opt_dup(opt->hopopt, | ||
1159 | sk->sk_allocation); | ||
1160 | if (opt->hopopt && !v6_cork->opt->hopopt) | ||
1161 | return -ENOBUFS; | ||
1162 | |||
1163 | v6_cork->opt->srcrt = ip6_rthdr_dup(opt->srcrt, | ||
1164 | sk->sk_allocation); | ||
1165 | if (opt->srcrt && !v6_cork->opt->srcrt) | ||
1166 | return -ENOBUFS; | ||
1167 | |||
1168 | /* need source address above miyazawa*/ | ||
1169 | } | ||
1170 | dst_hold(&rt->dst); | ||
1171 | cork->base.dst = &rt->dst; | ||
1172 | cork->fl.u.ip6 = *fl6; | ||
1173 | v6_cork->hop_limit = hlimit; | ||
1174 | v6_cork->tclass = tclass; | ||
1175 | if (rt->dst.flags & DST_XFRM_TUNNEL) | ||
1176 | mtu = np->pmtudisc >= IPV6_PMTUDISC_PROBE ? | ||
1177 | rt->dst.dev->mtu : dst_mtu(&rt->dst); | ||
1178 | else | ||
1179 | mtu = np->pmtudisc >= IPV6_PMTUDISC_PROBE ? | ||
1180 | rt->dst.dev->mtu : dst_mtu(rt->dst.path); | ||
1181 | if (np->frag_size < mtu) { | ||
1182 | if (np->frag_size) | ||
1183 | mtu = np->frag_size; | ||
1184 | } | ||
1185 | cork->base.fragsize = mtu; | ||
1186 | if (dst_allfrag(rt->dst.path)) | ||
1187 | cork->base.flags |= IPCORK_ALLFRAG; | ||
1188 | cork->base.length = 0; | ||
1189 | |||
1190 | return 0; | ||
1191 | } | ||
1192 | |||
1193 | static int __ip6_append_data(struct sock *sk, | ||
1194 | struct flowi6 *fl6, | ||
1195 | struct sk_buff_head *queue, | ||
1196 | struct inet_cork *cork, | ||
1197 | struct inet6_cork *v6_cork, | ||
1198 | struct page_frag *pfrag, | ||
1199 | int getfrag(void *from, char *to, int offset, | ||
1200 | int len, int odd, struct sk_buff *skb), | ||
1201 | void *from, int length, int transhdrlen, | ||
1202 | unsigned int flags, int dontfrag) | ||
1203 | { | ||
1147 | struct sk_buff *skb, *skb_prev = NULL; | 1204 | struct sk_buff *skb, *skb_prev = NULL; |
1148 | unsigned int maxfraglen, fragheaderlen, mtu, orig_mtu; | 1205 | unsigned int maxfraglen, fragheaderlen, mtu, orig_mtu; |
1149 | int exthdrlen; | 1206 | int exthdrlen = 0; |
1150 | int dst_exthdrlen; | 1207 | int dst_exthdrlen = 0; |
1151 | int hh_len; | 1208 | int hh_len; |
1152 | int copy; | 1209 | int copy; |
1153 | int err; | 1210 | int err; |
1154 | int offset = 0; | 1211 | int offset = 0; |
1155 | __u8 tx_flags = 0; | 1212 | __u8 tx_flags = 0; |
1156 | u32 tskey = 0; | 1213 | u32 tskey = 0; |
1214 | struct rt6_info *rt = (struct rt6_info *)cork->dst; | ||
1215 | struct ipv6_txoptions *opt = v6_cork->opt; | ||
1216 | int csummode = CHECKSUM_NONE; | ||
1157 | 1217 | ||
1158 | if (flags&MSG_PROBE) | 1218 | skb = skb_peek_tail(queue); |
1159 | return 0; | 1219 | if (!skb) { |
1160 | cork = &inet->cork.base; | 1220 | exthdrlen = opt ? opt->opt_flen : 0; |
1161 | if (skb_queue_empty(&sk->sk_write_queue)) { | ||
1162 | /* | ||
1163 | * setup for corking | ||
1164 | */ | ||
1165 | if (opt) { | ||
1166 | if (WARN_ON(np->cork.opt)) | ||
1167 | return -EINVAL; | ||
1168 | |||
1169 | np->cork.opt = kzalloc(opt->tot_len, sk->sk_allocation); | ||
1170 | if (unlikely(np->cork.opt == NULL)) | ||
1171 | return -ENOBUFS; | ||
1172 | |||
1173 | np->cork.opt->tot_len = opt->tot_len; | ||
1174 | np->cork.opt->opt_flen = opt->opt_flen; | ||
1175 | np->cork.opt->opt_nflen = opt->opt_nflen; | ||
1176 | |||
1177 | np->cork.opt->dst0opt = ip6_opt_dup(opt->dst0opt, | ||
1178 | sk->sk_allocation); | ||
1179 | if (opt->dst0opt && !np->cork.opt->dst0opt) | ||
1180 | return -ENOBUFS; | ||
1181 | |||
1182 | np->cork.opt->dst1opt = ip6_opt_dup(opt->dst1opt, | ||
1183 | sk->sk_allocation); | ||
1184 | if (opt->dst1opt && !np->cork.opt->dst1opt) | ||
1185 | return -ENOBUFS; | ||
1186 | |||
1187 | np->cork.opt->hopopt = ip6_opt_dup(opt->hopopt, | ||
1188 | sk->sk_allocation); | ||
1189 | if (opt->hopopt && !np->cork.opt->hopopt) | ||
1190 | return -ENOBUFS; | ||
1191 | |||
1192 | np->cork.opt->srcrt = ip6_rthdr_dup(opt->srcrt, | ||
1193 | sk->sk_allocation); | ||
1194 | if (opt->srcrt && !np->cork.opt->srcrt) | ||
1195 | return -ENOBUFS; | ||
1196 | |||
1197 | /* need source address above miyazawa*/ | ||
1198 | } | ||
1199 | dst_hold(&rt->dst); | ||
1200 | cork->dst = &rt->dst; | ||
1201 | inet->cork.fl.u.ip6 = *fl6; | ||
1202 | np->cork.hop_limit = hlimit; | ||
1203 | np->cork.tclass = tclass; | ||
1204 | if (rt->dst.flags & DST_XFRM_TUNNEL) | ||
1205 | mtu = np->pmtudisc >= IPV6_PMTUDISC_PROBE ? | ||
1206 | rt->dst.dev->mtu : dst_mtu(&rt->dst); | ||
1207 | else | ||
1208 | mtu = np->pmtudisc >= IPV6_PMTUDISC_PROBE ? | ||
1209 | rt->dst.dev->mtu : dst_mtu(rt->dst.path); | ||
1210 | if (np->frag_size < mtu) { | ||
1211 | if (np->frag_size) | ||
1212 | mtu = np->frag_size; | ||
1213 | } | ||
1214 | cork->fragsize = mtu; | ||
1215 | if (dst_allfrag(rt->dst.path)) | ||
1216 | cork->flags |= IPCORK_ALLFRAG; | ||
1217 | cork->length = 0; | ||
1218 | exthdrlen = (opt ? opt->opt_flen : 0); | ||
1219 | length += exthdrlen; | ||
1220 | transhdrlen += exthdrlen; | ||
1221 | dst_exthdrlen = rt->dst.header_len - rt->rt6i_nfheader_len; | 1221 | dst_exthdrlen = rt->dst.header_len - rt->rt6i_nfheader_len; |
1222 | } else { | ||
1223 | rt = (struct rt6_info *)cork->dst; | ||
1224 | fl6 = &inet->cork.fl.u.ip6; | ||
1225 | opt = np->cork.opt; | ||
1226 | transhdrlen = 0; | ||
1227 | exthdrlen = 0; | ||
1228 | dst_exthdrlen = 0; | ||
1229 | mtu = cork->fragsize; | ||
1230 | } | 1222 | } |
1223 | |||
1224 | mtu = cork->fragsize; | ||
1231 | orig_mtu = mtu; | 1225 | orig_mtu = mtu; |
1232 | 1226 | ||
1233 | hh_len = LL_RESERVED_SPACE(rt->dst.dev); | 1227 | hh_len = LL_RESERVED_SPACE(rt->dst.dev); |
@@ -1276,6 +1270,14 @@ emsgsize: | |||
1276 | tskey = sk->sk_tskey++; | 1270 | tskey = sk->sk_tskey++; |
1277 | } | 1271 | } |
1278 | 1272 | ||
1273 | /* If this is the first and only packet and device | ||
1274 | * supports checksum offloading, let's use it. | ||
1275 | */ | ||
1276 | if (!skb && | ||
1277 | length + fragheaderlen < mtu && | ||
1278 | rt->dst.dev->features & NETIF_F_V6_CSUM && | ||
1279 | !exthdrlen) | ||
1280 | csummode = CHECKSUM_PARTIAL; | ||
1279 | /* | 1281 | /* |
1280 | * Let's try using as much space as possible. | 1282 | * Let's try using as much space as possible. |
1281 | * Use MTU if total length of the message fits into the MTU. | 1283 | * Use MTU if total length of the message fits into the MTU. |
@@ -1292,13 +1294,12 @@ emsgsize: | |||
1292 | * --yoshfuji | 1294 | * --yoshfuji |
1293 | */ | 1295 | */ |
1294 | 1296 | ||
1295 | skb = skb_peek_tail(&sk->sk_write_queue); | ||
1296 | cork->length += length; | 1297 | cork->length += length; |
1297 | if (((length > mtu) || | 1298 | if (((length > mtu) || |
1298 | (skb && skb_is_gso(skb))) && | 1299 | (skb && skb_is_gso(skb))) && |
1299 | (sk->sk_protocol == IPPROTO_UDP) && | 1300 | (sk->sk_protocol == IPPROTO_UDP) && |
1300 | (rt->dst.dev->features & NETIF_F_UFO)) { | 1301 | (rt->dst.dev->features & NETIF_F_UFO)) { |
1301 | err = ip6_ufo_append_data(sk, getfrag, from, length, | 1302 | err = ip6_ufo_append_data(sk, queue, getfrag, from, length, |
1302 | hh_len, fragheaderlen, | 1303 | hh_len, fragheaderlen, |
1303 | transhdrlen, mtu, flags, rt); | 1304 | transhdrlen, mtu, flags, rt); |
1304 | if (err) | 1305 | if (err) |
@@ -1389,7 +1390,7 @@ alloc_new_skb: | |||
1389 | * Fill in the control structures | 1390 | * Fill in the control structures |
1390 | */ | 1391 | */ |
1391 | skb->protocol = htons(ETH_P_IPV6); | 1392 | skb->protocol = htons(ETH_P_IPV6); |
1392 | skb->ip_summed = CHECKSUM_NONE; | 1393 | skb->ip_summed = csummode; |
1393 | skb->csum = 0; | 1394 | skb->csum = 0; |
1394 | /* reserve for fragmentation and ipsec header */ | 1395 | /* reserve for fragmentation and ipsec header */ |
1395 | skb_reserve(skb, hh_len + sizeof(struct frag_hdr) + | 1396 | skb_reserve(skb, hh_len + sizeof(struct frag_hdr) + |
@@ -1439,7 +1440,7 @@ alloc_new_skb: | |||
1439 | /* | 1440 | /* |
1440 | * Put the packet on the pending queue | 1441 | * Put the packet on the pending queue |
1441 | */ | 1442 | */ |
1442 | __skb_queue_tail(&sk->sk_write_queue, skb); | 1443 | __skb_queue_tail(queue, skb); |
1443 | continue; | 1444 | continue; |
1444 | } | 1445 | } |
1445 | 1446 | ||
@@ -1458,7 +1459,6 @@ alloc_new_skb: | |||
1458 | } | 1459 | } |
1459 | } else { | 1460 | } else { |
1460 | int i = skb_shinfo(skb)->nr_frags; | 1461 | int i = skb_shinfo(skb)->nr_frags; |
1461 | struct page_frag *pfrag = sk_page_frag(sk); | ||
1462 | 1462 | ||
1463 | err = -ENOMEM; | 1463 | err = -ENOMEM; |
1464 | if (!sk_page_frag_refill(sk, pfrag)) | 1464 | if (!sk_page_frag_refill(sk, pfrag)) |
@@ -1501,43 +1501,81 @@ error: | |||
1501 | IP6_INC_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS); | 1501 | IP6_INC_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS); |
1502 | return err; | 1502 | return err; |
1503 | } | 1503 | } |
1504 | |||
1505 | int ip6_append_data(struct sock *sk, | ||
1506 | int getfrag(void *from, char *to, int offset, int len, | ||
1507 | int odd, struct sk_buff *skb), | ||
1508 | void *from, int length, int transhdrlen, int hlimit, | ||
1509 | int tclass, struct ipv6_txoptions *opt, struct flowi6 *fl6, | ||
1510 | struct rt6_info *rt, unsigned int flags, int dontfrag) | ||
1511 | { | ||
1512 | struct inet_sock *inet = inet_sk(sk); | ||
1513 | struct ipv6_pinfo *np = inet6_sk(sk); | ||
1514 | int exthdrlen; | ||
1515 | int err; | ||
1516 | |||
1517 | if (flags&MSG_PROBE) | ||
1518 | return 0; | ||
1519 | if (skb_queue_empty(&sk->sk_write_queue)) { | ||
1520 | /* | ||
1521 | * setup for corking | ||
1522 | */ | ||
1523 | err = ip6_setup_cork(sk, &inet->cork, &np->cork, hlimit, | ||
1524 | tclass, opt, rt, fl6); | ||
1525 | if (err) | ||
1526 | return err; | ||
1527 | |||
1528 | exthdrlen = (opt ? opt->opt_flen : 0); | ||
1529 | length += exthdrlen; | ||
1530 | transhdrlen += exthdrlen; | ||
1531 | } else { | ||
1532 | fl6 = &inet->cork.fl.u.ip6; | ||
1533 | transhdrlen = 0; | ||
1534 | } | ||
1535 | |||
1536 | return __ip6_append_data(sk, fl6, &sk->sk_write_queue, &inet->cork.base, | ||
1537 | &np->cork, sk_page_frag(sk), getfrag, | ||
1538 | from, length, transhdrlen, flags, dontfrag); | ||
1539 | } | ||
1504 | EXPORT_SYMBOL_GPL(ip6_append_data); | 1540 | EXPORT_SYMBOL_GPL(ip6_append_data); |
1505 | 1541 | ||
1506 | static void ip6_cork_release(struct inet_sock *inet, struct ipv6_pinfo *np) | 1542 | static void ip6_cork_release(struct inet_cork_full *cork, |
1543 | struct inet6_cork *v6_cork) | ||
1507 | { | 1544 | { |
1508 | if (np->cork.opt) { | 1545 | if (v6_cork->opt) { |
1509 | kfree(np->cork.opt->dst0opt); | 1546 | kfree(v6_cork->opt->dst0opt); |
1510 | kfree(np->cork.opt->dst1opt); | 1547 | kfree(v6_cork->opt->dst1opt); |
1511 | kfree(np->cork.opt->hopopt); | 1548 | kfree(v6_cork->opt->hopopt); |
1512 | kfree(np->cork.opt->srcrt); | 1549 | kfree(v6_cork->opt->srcrt); |
1513 | kfree(np->cork.opt); | 1550 | kfree(v6_cork->opt); |
1514 | np->cork.opt = NULL; | 1551 | v6_cork->opt = NULL; |
1515 | } | 1552 | } |
1516 | 1553 | ||
1517 | if (inet->cork.base.dst) { | 1554 | if (cork->base.dst) { |
1518 | dst_release(inet->cork.base.dst); | 1555 | dst_release(cork->base.dst); |
1519 | inet->cork.base.dst = NULL; | 1556 | cork->base.dst = NULL; |
1520 | inet->cork.base.flags &= ~IPCORK_ALLFRAG; | 1557 | cork->base.flags &= ~IPCORK_ALLFRAG; |
1521 | } | 1558 | } |
1522 | memset(&inet->cork.fl, 0, sizeof(inet->cork.fl)); | 1559 | memset(&cork->fl, 0, sizeof(cork->fl)); |
1523 | } | 1560 | } |
1524 | 1561 | ||
1525 | int ip6_push_pending_frames(struct sock *sk) | 1562 | struct sk_buff *__ip6_make_skb(struct sock *sk, |
1563 | struct sk_buff_head *queue, | ||
1564 | struct inet_cork_full *cork, | ||
1565 | struct inet6_cork *v6_cork) | ||
1526 | { | 1566 | { |
1527 | struct sk_buff *skb, *tmp_skb; | 1567 | struct sk_buff *skb, *tmp_skb; |
1528 | struct sk_buff **tail_skb; | 1568 | struct sk_buff **tail_skb; |
1529 | struct in6_addr final_dst_buf, *final_dst = &final_dst_buf; | 1569 | struct in6_addr final_dst_buf, *final_dst = &final_dst_buf; |
1530 | struct inet_sock *inet = inet_sk(sk); | ||
1531 | struct ipv6_pinfo *np = inet6_sk(sk); | 1570 | struct ipv6_pinfo *np = inet6_sk(sk); |
1532 | struct net *net = sock_net(sk); | 1571 | struct net *net = sock_net(sk); |
1533 | struct ipv6hdr *hdr; | 1572 | struct ipv6hdr *hdr; |
1534 | struct ipv6_txoptions *opt = np->cork.opt; | 1573 | struct ipv6_txoptions *opt = v6_cork->opt; |
1535 | struct rt6_info *rt = (struct rt6_info *)inet->cork.base.dst; | 1574 | struct rt6_info *rt = (struct rt6_info *)cork->base.dst; |
1536 | struct flowi6 *fl6 = &inet->cork.fl.u.ip6; | 1575 | struct flowi6 *fl6 = &cork->fl.u.ip6; |
1537 | unsigned char proto = fl6->flowi6_proto; | 1576 | unsigned char proto = fl6->flowi6_proto; |
1538 | int err = 0; | ||
1539 | 1577 | ||
1540 | skb = __skb_dequeue(&sk->sk_write_queue); | 1578 | skb = __skb_dequeue(queue); |
1541 | if (skb == NULL) | 1579 | if (skb == NULL) |
1542 | goto out; | 1580 | goto out; |
1543 | tail_skb = &(skb_shinfo(skb)->frag_list); | 1581 | tail_skb = &(skb_shinfo(skb)->frag_list); |
@@ -1545,7 +1583,7 @@ int ip6_push_pending_frames(struct sock *sk) | |||
1545 | /* move skb->data to ip header from ext header */ | 1583 | /* move skb->data to ip header from ext header */ |
1546 | if (skb->data < skb_network_header(skb)) | 1584 | if (skb->data < skb_network_header(skb)) |
1547 | __skb_pull(skb, skb_network_offset(skb)); | 1585 | __skb_pull(skb, skb_network_offset(skb)); |
1548 | while ((tmp_skb = __skb_dequeue(&sk->sk_write_queue)) != NULL) { | 1586 | while ((tmp_skb = __skb_dequeue(queue)) != NULL) { |
1549 | __skb_pull(tmp_skb, skb_network_header_len(skb)); | 1587 | __skb_pull(tmp_skb, skb_network_header_len(skb)); |
1550 | *tail_skb = tmp_skb; | 1588 | *tail_skb = tmp_skb; |
1551 | tail_skb = &(tmp_skb->next); | 1589 | tail_skb = &(tmp_skb->next); |
@@ -1570,10 +1608,10 @@ int ip6_push_pending_frames(struct sock *sk) | |||
1570 | skb_reset_network_header(skb); | 1608 | skb_reset_network_header(skb); |
1571 | hdr = ipv6_hdr(skb); | 1609 | hdr = ipv6_hdr(skb); |
1572 | 1610 | ||
1573 | ip6_flow_hdr(hdr, np->cork.tclass, | 1611 | ip6_flow_hdr(hdr, v6_cork->tclass, |
1574 | ip6_make_flowlabel(net, skb, fl6->flowlabel, | 1612 | ip6_make_flowlabel(net, skb, fl6->flowlabel, |
1575 | np->autoflowlabel)); | 1613 | np->autoflowlabel)); |
1576 | hdr->hop_limit = np->cork.hop_limit; | 1614 | hdr->hop_limit = v6_cork->hop_limit; |
1577 | hdr->nexthdr = proto; | 1615 | hdr->nexthdr = proto; |
1578 | hdr->saddr = fl6->saddr; | 1616 | hdr->saddr = fl6->saddr; |
1579 | hdr->daddr = *final_dst; | 1617 | hdr->daddr = *final_dst; |
@@ -1590,34 +1628,104 @@ int ip6_push_pending_frames(struct sock *sk) | |||
1590 | ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS); | 1628 | ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS); |
1591 | } | 1629 | } |
1592 | 1630 | ||
1631 | ip6_cork_release(cork, v6_cork); | ||
1632 | out: | ||
1633 | return skb; | ||
1634 | } | ||
1635 | |||
1636 | int ip6_send_skb(struct sk_buff *skb) | ||
1637 | { | ||
1638 | struct net *net = sock_net(skb->sk); | ||
1639 | struct rt6_info *rt = (struct rt6_info *)skb_dst(skb); | ||
1640 | int err; | ||
1641 | |||
1593 | err = ip6_local_out(skb); | 1642 | err = ip6_local_out(skb); |
1594 | if (err) { | 1643 | if (err) { |
1595 | if (err > 0) | 1644 | if (err > 0) |
1596 | err = net_xmit_errno(err); | 1645 | err = net_xmit_errno(err); |
1597 | if (err) | 1646 | if (err) |
1598 | goto error; | 1647 | IP6_INC_STATS(net, rt->rt6i_idev, |
1648 | IPSTATS_MIB_OUTDISCARDS); | ||
1599 | } | 1649 | } |
1600 | 1650 | ||
1601 | out: | ||
1602 | ip6_cork_release(inet, np); | ||
1603 | return err; | 1651 | return err; |
1604 | error: | 1652 | } |
1605 | IP6_INC_STATS(net, rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS); | 1653 | |
1606 | goto out; | 1654 | int ip6_push_pending_frames(struct sock *sk) |
1655 | { | ||
1656 | struct sk_buff *skb; | ||
1657 | |||
1658 | skb = ip6_finish_skb(sk); | ||
1659 | if (!skb) | ||
1660 | return 0; | ||
1661 | |||
1662 | return ip6_send_skb(skb); | ||
1607 | } | 1663 | } |
1608 | EXPORT_SYMBOL_GPL(ip6_push_pending_frames); | 1664 | EXPORT_SYMBOL_GPL(ip6_push_pending_frames); |
1609 | 1665 | ||
1610 | void ip6_flush_pending_frames(struct sock *sk) | 1666 | static void __ip6_flush_pending_frames(struct sock *sk, |
1667 | struct sk_buff_head *queue, | ||
1668 | struct inet_cork_full *cork, | ||
1669 | struct inet6_cork *v6_cork) | ||
1611 | { | 1670 | { |
1612 | struct sk_buff *skb; | 1671 | struct sk_buff *skb; |
1613 | 1672 | ||
1614 | while ((skb = __skb_dequeue_tail(&sk->sk_write_queue)) != NULL) { | 1673 | while ((skb = __skb_dequeue_tail(queue)) != NULL) { |
1615 | if (skb_dst(skb)) | 1674 | if (skb_dst(skb)) |
1616 | IP6_INC_STATS(sock_net(sk), ip6_dst_idev(skb_dst(skb)), | 1675 | IP6_INC_STATS(sock_net(sk), ip6_dst_idev(skb_dst(skb)), |
1617 | IPSTATS_MIB_OUTDISCARDS); | 1676 | IPSTATS_MIB_OUTDISCARDS); |
1618 | kfree_skb(skb); | 1677 | kfree_skb(skb); |
1619 | } | 1678 | } |
1620 | 1679 | ||
1621 | ip6_cork_release(inet_sk(sk), inet6_sk(sk)); | 1680 | ip6_cork_release(cork, v6_cork); |
1681 | } | ||
1682 | |||
1683 | void ip6_flush_pending_frames(struct sock *sk) | ||
1684 | { | ||
1685 | __ip6_flush_pending_frames(sk, &sk->sk_write_queue, | ||
1686 | &inet_sk(sk)->cork, &inet6_sk(sk)->cork); | ||
1622 | } | 1687 | } |
1623 | EXPORT_SYMBOL_GPL(ip6_flush_pending_frames); | 1688 | EXPORT_SYMBOL_GPL(ip6_flush_pending_frames); |
1689 | |||
1690 | struct sk_buff *ip6_make_skb(struct sock *sk, | ||
1691 | int getfrag(void *from, char *to, int offset, | ||
1692 | int len, int odd, struct sk_buff *skb), | ||
1693 | void *from, int length, int transhdrlen, | ||
1694 | int hlimit, int tclass, | ||
1695 | struct ipv6_txoptions *opt, struct flowi6 *fl6, | ||
1696 | struct rt6_info *rt, unsigned int flags, | ||
1697 | int dontfrag) | ||
1698 | { | ||
1699 | struct inet_cork_full cork; | ||
1700 | struct inet6_cork v6_cork; | ||
1701 | struct sk_buff_head queue; | ||
1702 | int exthdrlen = (opt ? opt->opt_flen : 0); | ||
1703 | int err; | ||
1704 | |||
1705 | if (flags & MSG_PROBE) | ||
1706 | return NULL; | ||
1707 | |||
1708 | __skb_queue_head_init(&queue); | ||
1709 | |||
1710 | cork.base.flags = 0; | ||
1711 | cork.base.addr = 0; | ||
1712 | cork.base.opt = NULL; | ||
1713 | v6_cork.opt = NULL; | ||
1714 | err = ip6_setup_cork(sk, &cork, &v6_cork, hlimit, tclass, opt, rt, fl6); | ||
1715 | if (err) | ||
1716 | return ERR_PTR(err); | ||
1717 | |||
1718 | if (dontfrag < 0) | ||
1719 | dontfrag = inet6_sk(sk)->dontfrag; | ||
1720 | |||
1721 | err = __ip6_append_data(sk, fl6, &queue, &cork.base, &v6_cork, | ||
1722 | ¤t->task_frag, getfrag, from, | ||
1723 | length + exthdrlen, transhdrlen + exthdrlen, | ||
1724 | flags, dontfrag); | ||
1725 | if (err) { | ||
1726 | __ip6_flush_pending_frames(sk, &queue, &cork, &v6_cork); | ||
1727 | return ERR_PTR(err); | ||
1728 | } | ||
1729 | |||
1730 | return __ip6_make_skb(sk, &queue, &cork, &v6_cork); | ||
1731 | } | ||
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 92b3da571980..266a264ec212 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c | |||
@@ -1760,6 +1760,14 @@ nla_put_failure: | |||
1760 | return -EMSGSIZE; | 1760 | return -EMSGSIZE; |
1761 | } | 1761 | } |
1762 | 1762 | ||
1763 | struct net *ip6_tnl_get_link_net(const struct net_device *dev) | ||
1764 | { | ||
1765 | struct ip6_tnl *tunnel = netdev_priv(dev); | ||
1766 | |||
1767 | return tunnel->net; | ||
1768 | } | ||
1769 | EXPORT_SYMBOL(ip6_tnl_get_link_net); | ||
1770 | |||
1763 | static const struct nla_policy ip6_tnl_policy[IFLA_IPTUN_MAX + 1] = { | 1771 | static const struct nla_policy ip6_tnl_policy[IFLA_IPTUN_MAX + 1] = { |
1764 | [IFLA_IPTUN_LINK] = { .type = NLA_U32 }, | 1772 | [IFLA_IPTUN_LINK] = { .type = NLA_U32 }, |
1765 | [IFLA_IPTUN_LOCAL] = { .len = sizeof(struct in6_addr) }, | 1773 | [IFLA_IPTUN_LOCAL] = { .len = sizeof(struct in6_addr) }, |
@@ -1783,6 +1791,7 @@ static struct rtnl_link_ops ip6_link_ops __read_mostly = { | |||
1783 | .dellink = ip6_tnl_dellink, | 1791 | .dellink = ip6_tnl_dellink, |
1784 | .get_size = ip6_tnl_get_size, | 1792 | .get_size = ip6_tnl_get_size, |
1785 | .fill_info = ip6_tnl_fill_info, | 1793 | .fill_info = ip6_tnl_fill_info, |
1794 | .get_link_net = ip6_tnl_get_link_net, | ||
1786 | }; | 1795 | }; |
1787 | 1796 | ||
1788 | static struct xfrm6_tunnel ip4ip6_handler __read_mostly = { | 1797 | static struct xfrm6_tunnel ip4ip6_handler __read_mostly = { |
diff --git a/net/ipv6/ip6_udp_tunnel.c b/net/ipv6/ip6_udp_tunnel.c index 8db6c98fe218..32d9b268e7d8 100644 --- a/net/ipv6/ip6_udp_tunnel.c +++ b/net/ipv6/ip6_udp_tunnel.c | |||
@@ -62,14 +62,14 @@ error: | |||
62 | } | 62 | } |
63 | EXPORT_SYMBOL_GPL(udp_sock_create6); | 63 | EXPORT_SYMBOL_GPL(udp_sock_create6); |
64 | 64 | ||
65 | int udp_tunnel6_xmit_skb(struct socket *sock, struct dst_entry *dst, | 65 | int udp_tunnel6_xmit_skb(struct dst_entry *dst, struct sk_buff *skb, |
66 | struct sk_buff *skb, struct net_device *dev, | 66 | struct net_device *dev, struct in6_addr *saddr, |
67 | struct in6_addr *saddr, struct in6_addr *daddr, | 67 | struct in6_addr *daddr, |
68 | __u8 prio, __u8 ttl, __be16 src_port, __be16 dst_port) | 68 | __u8 prio, __u8 ttl, __be16 src_port, |
69 | __be16 dst_port, bool nocheck) | ||
69 | { | 70 | { |
70 | struct udphdr *uh; | 71 | struct udphdr *uh; |
71 | struct ipv6hdr *ip6h; | 72 | struct ipv6hdr *ip6h; |
72 | struct sock *sk = sock->sk; | ||
73 | 73 | ||
74 | __skb_push(skb, sizeof(*uh)); | 74 | __skb_push(skb, sizeof(*uh)); |
75 | skb_reset_transport_header(skb); | 75 | skb_reset_transport_header(skb); |
@@ -85,7 +85,7 @@ int udp_tunnel6_xmit_skb(struct socket *sock, struct dst_entry *dst, | |||
85 | | IPSKB_REROUTED); | 85 | | IPSKB_REROUTED); |
86 | skb_dst_set(skb, dst); | 86 | skb_dst_set(skb, dst); |
87 | 87 | ||
88 | udp6_set_csum(udp_get_no_check6_tx(sk), skb, saddr, daddr, skb->len); | 88 | udp6_set_csum(nocheck, skb, saddr, daddr, skb->len); |
89 | 89 | ||
90 | __skb_push(skb, sizeof(*ip6h)); | 90 | __skb_push(skb, sizeof(*ip6h)); |
91 | skb_reset_network_header(skb); | 91 | skb_reset_network_header(skb); |
diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c index ace10d0b3aac..5fb9e212eca8 100644 --- a/net/ipv6/ip6_vti.c +++ b/net/ipv6/ip6_vti.c | |||
@@ -1016,6 +1016,7 @@ static struct rtnl_link_ops vti6_link_ops __read_mostly = { | |||
1016 | .changelink = vti6_changelink, | 1016 | .changelink = vti6_changelink, |
1017 | .get_size = vti6_get_size, | 1017 | .get_size = vti6_get_size, |
1018 | .fill_info = vti6_fill_info, | 1018 | .fill_info = vti6_fill_info, |
1019 | .get_link_net = ip6_tnl_get_link_net, | ||
1019 | }; | 1020 | }; |
1020 | 1021 | ||
1021 | static void __net_exit vti6_destroy_tunnels(struct vti6_net *ip6n) | 1022 | static void __net_exit vti6_destroy_tunnels(struct vti6_net *ip6n) |
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 722669754bbf..34b682617f50 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c | |||
@@ -2388,7 +2388,8 @@ static int ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb, | |||
2388 | if (err < 0 && err != -ENOENT) | 2388 | if (err < 0 && err != -ENOENT) |
2389 | goto nla_put_failure; | 2389 | goto nla_put_failure; |
2390 | 2390 | ||
2391 | return nlmsg_end(skb, nlh); | 2391 | nlmsg_end(skb, nlh); |
2392 | return 0; | ||
2392 | 2393 | ||
2393 | nla_put_failure: | 2394 | nla_put_failure: |
2394 | nlmsg_cancel(skb, nlh); | 2395 | nlmsg_cancel(skb, nlh); |
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 66980d8d98d1..8d766d9100cb 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c | |||
@@ -996,13 +996,9 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, | |||
996 | lock_sock(sk); | 996 | lock_sock(sk); |
997 | skb = np->pktoptions; | 997 | skb = np->pktoptions; |
998 | if (skb) | 998 | if (skb) |
999 | atomic_inc(&skb->users); | ||
1000 | release_sock(sk); | ||
1001 | |||
1002 | if (skb) { | ||
1003 | ip6_datagram_recv_ctl(sk, &msg, skb); | 999 | ip6_datagram_recv_ctl(sk, &msg, skb); |
1004 | kfree_skb(skb); | 1000 | release_sock(sk); |
1005 | } else { | 1001 | if (!skb) { |
1006 | if (np->rxopt.bits.rxinfo) { | 1002 | if (np->rxopt.bits.rxinfo) { |
1007 | struct in6_pktinfo src_info; | 1003 | struct in6_pktinfo src_info; |
1008 | src_info.ipi6_ifindex = np->mcast_oif ? np->mcast_oif : | 1004 | src_info.ipi6_ifindex = np->mcast_oif ? np->mcast_oif : |
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 682866777d53..471ed24aabae 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c | |||
@@ -655,7 +655,9 @@ static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb) | |||
655 | struct in6_addr *target = (struct in6_addr *)&neigh->primary_key; | 655 | struct in6_addr *target = (struct in6_addr *)&neigh->primary_key; |
656 | int probes = atomic_read(&neigh->probes); | 656 | int probes = atomic_read(&neigh->probes); |
657 | 657 | ||
658 | if (skb && ipv6_chk_addr(dev_net(dev), &ipv6_hdr(skb)->saddr, dev, 1)) | 658 | if (skb && ipv6_chk_addr_and_flags(dev_net(dev), &ipv6_hdr(skb)->saddr, |
659 | dev, 1, | ||
660 | IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)) | ||
659 | saddr = &ipv6_hdr(skb)->saddr; | 661 | saddr = &ipv6_hdr(skb)->saddr; |
660 | probes -= NEIGH_VAR(neigh->parms, UCAST_PROBES); | 662 | probes -= NEIGH_VAR(neigh->parms, UCAST_PROBES); |
661 | if (probes < 0) { | 663 | if (probes < 0) { |
@@ -1348,7 +1350,7 @@ skip_routeinfo: | |||
1348 | } | 1350 | } |
1349 | } | 1351 | } |
1350 | 1352 | ||
1351 | if (ndopts.nd_opts_mtu) { | 1353 | if (ndopts.nd_opts_mtu && in6_dev->cnf.accept_ra_mtu) { |
1352 | __be32 n; | 1354 | __be32 n; |
1353 | u32 mtu; | 1355 | u32 mtu; |
1354 | 1356 | ||
diff --git a/net/ipv6/output_core.c b/net/ipv6/output_core.c index 97f41a3e68d9..74581f706c4d 100644 --- a/net/ipv6/output_core.c +++ b/net/ipv6/output_core.c | |||
@@ -9,6 +9,25 @@ | |||
9 | #include <net/addrconf.h> | 9 | #include <net/addrconf.h> |
10 | #include <net/secure_seq.h> | 10 | #include <net/secure_seq.h> |
11 | 11 | ||
12 | static u32 __ipv6_select_ident(u32 hashrnd, struct in6_addr *dst, | ||
13 | struct in6_addr *src) | ||
14 | { | ||
15 | u32 hash, id; | ||
16 | |||
17 | hash = __ipv6_addr_jhash(dst, hashrnd); | ||
18 | hash = __ipv6_addr_jhash(src, hash); | ||
19 | |||
20 | /* Treat id of 0 as unset and if we get 0 back from ip_idents_reserve, | ||
21 | * set the hight order instead thus minimizing possible future | ||
22 | * collisions. | ||
23 | */ | ||
24 | id = ip_idents_reserve(hash, 1); | ||
25 | if (unlikely(!id)) | ||
26 | id = 1 << 31; | ||
27 | |||
28 | return id; | ||
29 | } | ||
30 | |||
12 | /* This function exists only for tap drivers that must support broken | 31 | /* This function exists only for tap drivers that must support broken |
13 | * clients requesting UFO without specifying an IPv6 fragment ID. | 32 | * clients requesting UFO without specifying an IPv6 fragment ID. |
14 | * | 33 | * |
@@ -22,7 +41,7 @@ void ipv6_proxy_select_ident(struct sk_buff *skb) | |||
22 | static u32 ip6_proxy_idents_hashrnd __read_mostly; | 41 | static u32 ip6_proxy_idents_hashrnd __read_mostly; |
23 | struct in6_addr buf[2]; | 42 | struct in6_addr buf[2]; |
24 | struct in6_addr *addrs; | 43 | struct in6_addr *addrs; |
25 | u32 hash, id; | 44 | u32 id; |
26 | 45 | ||
27 | addrs = skb_header_pointer(skb, | 46 | addrs = skb_header_pointer(skb, |
28 | skb_network_offset(skb) + | 47 | skb_network_offset(skb) + |
@@ -34,14 +53,25 @@ void ipv6_proxy_select_ident(struct sk_buff *skb) | |||
34 | net_get_random_once(&ip6_proxy_idents_hashrnd, | 53 | net_get_random_once(&ip6_proxy_idents_hashrnd, |
35 | sizeof(ip6_proxy_idents_hashrnd)); | 54 | sizeof(ip6_proxy_idents_hashrnd)); |
36 | 55 | ||
37 | hash = __ipv6_addr_jhash(&addrs[1], ip6_proxy_idents_hashrnd); | 56 | id = __ipv6_select_ident(ip6_proxy_idents_hashrnd, |
38 | hash = __ipv6_addr_jhash(&addrs[0], hash); | 57 | &addrs[1], &addrs[0]); |
39 | |||
40 | id = ip_idents_reserve(hash, 1); | ||
41 | skb_shinfo(skb)->ip6_frag_id = htonl(id); | 58 | skb_shinfo(skb)->ip6_frag_id = htonl(id); |
42 | } | 59 | } |
43 | EXPORT_SYMBOL_GPL(ipv6_proxy_select_ident); | 60 | EXPORT_SYMBOL_GPL(ipv6_proxy_select_ident); |
44 | 61 | ||
62 | void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt) | ||
63 | { | ||
64 | static u32 ip6_idents_hashrnd __read_mostly; | ||
65 | u32 id; | ||
66 | |||
67 | net_get_random_once(&ip6_idents_hashrnd, sizeof(ip6_idents_hashrnd)); | ||
68 | |||
69 | id = __ipv6_select_ident(ip6_idents_hashrnd, &rt->rt6i_dst.addr, | ||
70 | &rt->rt6i_src.addr); | ||
71 | fhdr->identification = htonl(id); | ||
72 | } | ||
73 | EXPORT_SYMBOL(ipv6_select_ident); | ||
74 | |||
45 | int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr) | 75 | int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr) |
46 | { | 76 | { |
47 | u16 offset = sizeof(struct ipv6hdr); | 77 | u16 offset = sizeof(struct ipv6hdr); |
diff --git a/net/ipv6/ping.c b/net/ipv6/ping.c index 2d3148378a1f..bd46f736f61d 100644 --- a/net/ipv6/ping.c +++ b/net/ipv6/ping.c | |||
@@ -163,8 +163,7 @@ int ping_v6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
163 | pfh.icmph.checksum = 0; | 163 | pfh.icmph.checksum = 0; |
164 | pfh.icmph.un.echo.id = inet->inet_sport; | 164 | pfh.icmph.un.echo.id = inet->inet_sport; |
165 | pfh.icmph.un.echo.sequence = user_icmph.icmp6_sequence; | 165 | pfh.icmph.un.echo.sequence = user_icmph.icmp6_sequence; |
166 | /* XXX: stripping const */ | 166 | pfh.msg = msg; |
167 | pfh.iov = (struct iovec *)msg->msg_iter.iov; | ||
168 | pfh.wcheck = 0; | 167 | pfh.wcheck = 0; |
169 | pfh.family = AF_INET6; | 168 | pfh.family = AF_INET6; |
170 | 169 | ||
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index ee25631f8c29..dae7f1a1e464 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c | |||
@@ -609,7 +609,7 @@ out: | |||
609 | return err; | 609 | return err; |
610 | } | 610 | } |
611 | 611 | ||
612 | static int rawv6_send_hdrinc(struct sock *sk, void *from, int length, | 612 | static int rawv6_send_hdrinc(struct sock *sk, struct msghdr *msg, int length, |
613 | struct flowi6 *fl6, struct dst_entry **dstp, | 613 | struct flowi6 *fl6, struct dst_entry **dstp, |
614 | unsigned int flags) | 614 | unsigned int flags) |
615 | { | 615 | { |
@@ -648,7 +648,7 @@ static int rawv6_send_hdrinc(struct sock *sk, void *from, int length, | |||
648 | skb->ip_summed = CHECKSUM_NONE; | 648 | skb->ip_summed = CHECKSUM_NONE; |
649 | 649 | ||
650 | skb->transport_header = skb->network_header; | 650 | skb->transport_header = skb->network_header; |
651 | err = memcpy_fromiovecend((void *)iph, from, 0, length); | 651 | err = memcpy_from_msg(iph, msg, length); |
652 | if (err) | 652 | if (err) |
653 | goto error_fault; | 653 | goto error_fault; |
654 | 654 | ||
@@ -886,8 +886,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
886 | 886 | ||
887 | back_from_confirm: | 887 | back_from_confirm: |
888 | if (inet->hdrincl) | 888 | if (inet->hdrincl) |
889 | /* XXX: stripping const */ | 889 | err = rawv6_send_hdrinc(sk, msg, len, &fl6, &dst, msg->msg_flags); |
890 | err = rawv6_send_hdrinc(sk, (struct iovec *)msg->msg_iter.iov, len, &fl6, &dst, msg->msg_flags); | ||
891 | else { | 890 | else { |
892 | lock_sock(sk); | 891 | lock_sock(sk); |
893 | err = ip6_append_data(sk, raw6_getfrag, &rfv, | 892 | err = ip6_append_data(sk, raw6_getfrag, &rfv, |
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index c91083156edb..98565ce0ebcd 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -499,7 +499,7 @@ static void rt6_probe_deferred(struct work_struct *w) | |||
499 | addrconf_addr_solict_mult(&work->target, &mcaddr); | 499 | addrconf_addr_solict_mult(&work->target, &mcaddr); |
500 | ndisc_send_ns(work->dev, NULL, &work->target, &mcaddr, NULL); | 500 | ndisc_send_ns(work->dev, NULL, &work->target, &mcaddr, NULL); |
501 | dev_put(work->dev); | 501 | dev_put(work->dev); |
502 | kfree(w); | 502 | kfree(work); |
503 | } | 503 | } |
504 | 504 | ||
505 | static void rt6_probe(struct rt6_info *rt) | 505 | static void rt6_probe(struct rt6_info *rt) |
@@ -853,14 +853,14 @@ EXPORT_SYMBOL(rt6_lookup); | |||
853 | */ | 853 | */ |
854 | 854 | ||
855 | static int __ip6_ins_rt(struct rt6_info *rt, struct nl_info *info, | 855 | static int __ip6_ins_rt(struct rt6_info *rt, struct nl_info *info, |
856 | struct nlattr *mx, int mx_len) | 856 | struct mx6_config *mxc) |
857 | { | 857 | { |
858 | int err; | 858 | int err; |
859 | struct fib6_table *table; | 859 | struct fib6_table *table; |
860 | 860 | ||
861 | table = rt->rt6i_table; | 861 | table = rt->rt6i_table; |
862 | write_lock_bh(&table->tb6_lock); | 862 | write_lock_bh(&table->tb6_lock); |
863 | err = fib6_add(&table->tb6_root, rt, info, mx, mx_len); | 863 | err = fib6_add(&table->tb6_root, rt, info, mxc); |
864 | write_unlock_bh(&table->tb6_lock); | 864 | write_unlock_bh(&table->tb6_lock); |
865 | 865 | ||
866 | return err; | 866 | return err; |
@@ -868,10 +868,10 @@ static int __ip6_ins_rt(struct rt6_info *rt, struct nl_info *info, | |||
868 | 868 | ||
869 | int ip6_ins_rt(struct rt6_info *rt) | 869 | int ip6_ins_rt(struct rt6_info *rt) |
870 | { | 870 | { |
871 | struct nl_info info = { | 871 | struct nl_info info = { .nl_net = dev_net(rt->dst.dev), }; |
872 | .nl_net = dev_net(rt->dst.dev), | 872 | struct mx6_config mxc = { .mx = NULL, }; |
873 | }; | 873 | |
874 | return __ip6_ins_rt(rt, &info, NULL, 0); | 874 | return __ip6_ins_rt(rt, &info, &mxc); |
875 | } | 875 | } |
876 | 876 | ||
877 | static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, | 877 | static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, |
@@ -1160,12 +1160,9 @@ static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk, | |||
1160 | struct net *net = dev_net(dst->dev); | 1160 | struct net *net = dev_net(dst->dev); |
1161 | 1161 | ||
1162 | rt6->rt6i_flags |= RTF_MODIFIED; | 1162 | rt6->rt6i_flags |= RTF_MODIFIED; |
1163 | if (mtu < IPV6_MIN_MTU) { | 1163 | if (mtu < IPV6_MIN_MTU) |
1164 | u32 features = dst_metric(dst, RTAX_FEATURES); | ||
1165 | mtu = IPV6_MIN_MTU; | 1164 | mtu = IPV6_MIN_MTU; |
1166 | features |= RTAX_FEATURE_ALLFRAG; | 1165 | |
1167 | dst_metric_set(dst, RTAX_FEATURES, features); | ||
1168 | } | ||
1169 | dst_metric_set(dst, RTAX_MTU, mtu); | 1166 | dst_metric_set(dst, RTAX_MTU, mtu); |
1170 | rt6_update_expires(rt6, net->ipv6.sysctl.ip6_rt_mtu_expires); | 1167 | rt6_update_expires(rt6, net->ipv6.sysctl.ip6_rt_mtu_expires); |
1171 | } | 1168 | } |
@@ -1245,12 +1242,16 @@ restart: | |||
1245 | rt = net->ipv6.ip6_null_entry; | 1242 | rt = net->ipv6.ip6_null_entry; |
1246 | else if (rt->dst.error) { | 1243 | else if (rt->dst.error) { |
1247 | rt = net->ipv6.ip6_null_entry; | 1244 | rt = net->ipv6.ip6_null_entry; |
1248 | } else if (rt == net->ipv6.ip6_null_entry) { | 1245 | goto out; |
1246 | } | ||
1247 | |||
1248 | if (rt == net->ipv6.ip6_null_entry) { | ||
1249 | fn = fib6_backtrack(fn, &fl6->saddr); | 1249 | fn = fib6_backtrack(fn, &fl6->saddr); |
1250 | if (fn) | 1250 | if (fn) |
1251 | goto restart; | 1251 | goto restart; |
1252 | } | 1252 | } |
1253 | 1253 | ||
1254 | out: | ||
1254 | dst_hold(&rt->dst); | 1255 | dst_hold(&rt->dst); |
1255 | 1256 | ||
1256 | read_unlock_bh(&table->tb6_lock); | 1257 | read_unlock_bh(&table->tb6_lock); |
@@ -1470,9 +1471,51 @@ out: | |||
1470 | return entries > rt_max_size; | 1471 | return entries > rt_max_size; |
1471 | } | 1472 | } |
1472 | 1473 | ||
1473 | /* | 1474 | static int ip6_convert_metrics(struct mx6_config *mxc, |
1474 | * | 1475 | const struct fib6_config *cfg) |
1475 | */ | 1476 | { |
1477 | struct nlattr *nla; | ||
1478 | int remaining; | ||
1479 | u32 *mp; | ||
1480 | |||
1481 | if (cfg->fc_mx == NULL) | ||
1482 | return 0; | ||
1483 | |||
1484 | mp = kzalloc(sizeof(u32) * RTAX_MAX, GFP_KERNEL); | ||
1485 | if (unlikely(!mp)) | ||
1486 | return -ENOMEM; | ||
1487 | |||
1488 | nla_for_each_attr(nla, cfg->fc_mx, cfg->fc_mx_len, remaining) { | ||
1489 | int type = nla_type(nla); | ||
1490 | |||
1491 | if (type) { | ||
1492 | u32 val; | ||
1493 | |||
1494 | if (unlikely(type > RTAX_MAX)) | ||
1495 | goto err; | ||
1496 | if (type == RTAX_CC_ALGO) { | ||
1497 | char tmp[TCP_CA_NAME_MAX]; | ||
1498 | |||
1499 | nla_strlcpy(tmp, nla, sizeof(tmp)); | ||
1500 | val = tcp_ca_get_key_by_name(tmp); | ||
1501 | if (val == TCP_CA_UNSPEC) | ||
1502 | goto err; | ||
1503 | } else { | ||
1504 | val = nla_get_u32(nla); | ||
1505 | } | ||
1506 | |||
1507 | mp[type - 1] = val; | ||
1508 | __set_bit(type - 1, mxc->mx_valid); | ||
1509 | } | ||
1510 | } | ||
1511 | |||
1512 | mxc->mx = mp; | ||
1513 | |||
1514 | return 0; | ||
1515 | err: | ||
1516 | kfree(mp); | ||
1517 | return -EINVAL; | ||
1518 | } | ||
1476 | 1519 | ||
1477 | int ip6_route_add(struct fib6_config *cfg) | 1520 | int ip6_route_add(struct fib6_config *cfg) |
1478 | { | 1521 | { |
@@ -1482,6 +1525,7 @@ int ip6_route_add(struct fib6_config *cfg) | |||
1482 | struct net_device *dev = NULL; | 1525 | struct net_device *dev = NULL; |
1483 | struct inet6_dev *idev = NULL; | 1526 | struct inet6_dev *idev = NULL; |
1484 | struct fib6_table *table; | 1527 | struct fib6_table *table; |
1528 | struct mx6_config mxc = { .mx = NULL, }; | ||
1485 | int addr_type; | 1529 | int addr_type; |
1486 | 1530 | ||
1487 | if (cfg->fc_dst_len > 128 || cfg->fc_src_len > 128) | 1531 | if (cfg->fc_dst_len > 128 || cfg->fc_src_len > 128) |
@@ -1677,8 +1721,14 @@ install_route: | |||
1677 | 1721 | ||
1678 | cfg->fc_nlinfo.nl_net = dev_net(dev); | 1722 | cfg->fc_nlinfo.nl_net = dev_net(dev); |
1679 | 1723 | ||
1680 | return __ip6_ins_rt(rt, &cfg->fc_nlinfo, cfg->fc_mx, cfg->fc_mx_len); | 1724 | err = ip6_convert_metrics(&mxc, cfg); |
1725 | if (err) | ||
1726 | goto out; | ||
1727 | |||
1728 | err = __ip6_ins_rt(rt, &cfg->fc_nlinfo, &mxc); | ||
1681 | 1729 | ||
1730 | kfree(mxc.mx); | ||
1731 | return err; | ||
1682 | out: | 1732 | out: |
1683 | if (dev) | 1733 | if (dev) |
1684 | dev_put(dev); | 1734 | dev_put(dev); |
@@ -2534,7 +2584,8 @@ static inline size_t rt6_nlmsg_size(void) | |||
2534 | + nla_total_size(4) /* RTA_OIF */ | 2584 | + nla_total_size(4) /* RTA_OIF */ |
2535 | + nla_total_size(4) /* RTA_PRIORITY */ | 2585 | + nla_total_size(4) /* RTA_PRIORITY */ |
2536 | + RTAX_MAX * nla_total_size(4) /* RTA_METRICS */ | 2586 | + RTAX_MAX * nla_total_size(4) /* RTA_METRICS */ |
2537 | + nla_total_size(sizeof(struct rta_cacheinfo)); | 2587 | + nla_total_size(sizeof(struct rta_cacheinfo)) |
2588 | + nla_total_size(TCP_CA_NAME_MAX); /* RTAX_CC_ALGO */ | ||
2538 | } | 2589 | } |
2539 | 2590 | ||
2540 | static int rt6_fill_node(struct net *net, | 2591 | static int rt6_fill_node(struct net *net, |
@@ -2675,7 +2726,8 @@ static int rt6_fill_node(struct net *net, | |||
2675 | if (rtnl_put_cacheinfo(skb, &rt->dst, 0, expires, rt->dst.error) < 0) | 2726 | if (rtnl_put_cacheinfo(skb, &rt->dst, 0, expires, rt->dst.error) < 0) |
2676 | goto nla_put_failure; | 2727 | goto nla_put_failure; |
2677 | 2728 | ||
2678 | return nlmsg_end(skb, nlh); | 2729 | nlmsg_end(skb, nlh); |
2730 | return 0; | ||
2679 | 2731 | ||
2680 | nla_put_failure: | 2732 | nla_put_failure: |
2681 | nlmsg_cancel(skb, nlh); | 2733 | nlmsg_cancel(skb, nlh); |
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 213546bd6d5d..e4cbd5798eba 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c | |||
@@ -1506,12 +1506,12 @@ static bool ipip6_netlink_encap_parms(struct nlattr *data[], | |||
1506 | 1506 | ||
1507 | if (data[IFLA_IPTUN_ENCAP_SPORT]) { | 1507 | if (data[IFLA_IPTUN_ENCAP_SPORT]) { |
1508 | ret = true; | 1508 | ret = true; |
1509 | ipencap->sport = nla_get_u16(data[IFLA_IPTUN_ENCAP_SPORT]); | 1509 | ipencap->sport = nla_get_be16(data[IFLA_IPTUN_ENCAP_SPORT]); |
1510 | } | 1510 | } |
1511 | 1511 | ||
1512 | if (data[IFLA_IPTUN_ENCAP_DPORT]) { | 1512 | if (data[IFLA_IPTUN_ENCAP_DPORT]) { |
1513 | ret = true; | 1513 | ret = true; |
1514 | ipencap->dport = nla_get_u16(data[IFLA_IPTUN_ENCAP_DPORT]); | 1514 | ipencap->dport = nla_get_be16(data[IFLA_IPTUN_ENCAP_DPORT]); |
1515 | } | 1515 | } |
1516 | 1516 | ||
1517 | return ret; | 1517 | return ret; |
@@ -1707,9 +1707,9 @@ static int ipip6_fill_info(struct sk_buff *skb, const struct net_device *dev) | |||
1707 | 1707 | ||
1708 | if (nla_put_u16(skb, IFLA_IPTUN_ENCAP_TYPE, | 1708 | if (nla_put_u16(skb, IFLA_IPTUN_ENCAP_TYPE, |
1709 | tunnel->encap.type) || | 1709 | tunnel->encap.type) || |
1710 | nla_put_u16(skb, IFLA_IPTUN_ENCAP_SPORT, | 1710 | nla_put_be16(skb, IFLA_IPTUN_ENCAP_SPORT, |
1711 | tunnel->encap.sport) || | 1711 | tunnel->encap.sport) || |
1712 | nla_put_u16(skb, IFLA_IPTUN_ENCAP_DPORT, | 1712 | nla_put_be16(skb, IFLA_IPTUN_ENCAP_DPORT, |
1713 | tunnel->encap.dport) || | 1713 | tunnel->encap.dport) || |
1714 | nla_put_u16(skb, IFLA_IPTUN_ENCAP_FLAGS, | 1714 | nla_put_u16(skb, IFLA_IPTUN_ENCAP_FLAGS, |
1715 | tunnel->encap.flags)) | 1715 | tunnel->encap.flags)) |
@@ -1763,6 +1763,7 @@ static struct rtnl_link_ops sit_link_ops __read_mostly = { | |||
1763 | .get_size = ipip6_get_size, | 1763 | .get_size = ipip6_get_size, |
1764 | .fill_info = ipip6_fill_info, | 1764 | .fill_info = ipip6_fill_info, |
1765 | .dellink = ipip6_dellink, | 1765 | .dellink = ipip6_dellink, |
1766 | .get_link_net = ip_tunnel_get_link_net, | ||
1766 | }; | 1767 | }; |
1767 | 1768 | ||
1768 | static struct xfrm_tunnel sit_handler __read_mostly = { | 1769 | static struct xfrm_tunnel sit_handler __read_mostly = { |
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 9c0b54e87b47..5d46832c6f72 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
@@ -1199,6 +1199,8 @@ static struct sock *tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
1199 | inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen + | 1199 | inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen + |
1200 | newnp->opt->opt_flen); | 1200 | newnp->opt->opt_flen); |
1201 | 1201 | ||
1202 | tcp_ca_openreq_child(newsk, dst); | ||
1203 | |||
1202 | tcp_sync_mss(newsk, dst_mtu(dst)); | 1204 | tcp_sync_mss(newsk, dst_mtu(dst)); |
1203 | newtp->advmss = dst_metric_advmss(dst); | 1205 | newtp->advmss = dst_metric_advmss(dst); |
1204 | if (tcp_sk(sk)->rx_opt.user_mss && | 1206 | if (tcp_sk(sk)->rx_opt.user_mss && |
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 189dc4ae3eca..d048d46779fc 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
@@ -909,7 +909,7 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, | |||
909 | goto csum_error; | 909 | goto csum_error; |
910 | } | 910 | } |
911 | 911 | ||
912 | if (udp_sk(sk)->convert_csum && uh->check && !IS_UDPLITE(sk)) | 912 | if (inet_get_convert_csum(sk) && uh->check && !IS_UDPLITE(sk)) |
913 | skb_checksum_try_convert(skb, IPPROTO_UDP, uh->check, | 913 | skb_checksum_try_convert(skb, IPPROTO_UDP, uh->check, |
914 | ip6_compute_pseudo); | 914 | ip6_compute_pseudo); |
915 | 915 | ||
@@ -990,9 +990,10 @@ static void udp6_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb, | |||
990 | { | 990 | { |
991 | unsigned int offset; | 991 | unsigned int offset; |
992 | struct udphdr *uh = udp_hdr(skb); | 992 | struct udphdr *uh = udp_hdr(skb); |
993 | struct sk_buff *frags = skb_shinfo(skb)->frag_list; | ||
993 | __wsum csum = 0; | 994 | __wsum csum = 0; |
994 | 995 | ||
995 | if (skb_queue_len(&sk->sk_write_queue) == 1) { | 996 | if (!frags) { |
996 | /* Only one fragment on the socket. */ | 997 | /* Only one fragment on the socket. */ |
997 | skb->csum_start = skb_transport_header(skb) - skb->head; | 998 | skb->csum_start = skb_transport_header(skb) - skb->head; |
998 | skb->csum_offset = offsetof(struct udphdr, check); | 999 | skb->csum_offset = offsetof(struct udphdr, check); |
@@ -1008,9 +1009,9 @@ static void udp6_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb, | |||
1008 | 1009 | ||
1009 | skb->ip_summed = CHECKSUM_NONE; | 1010 | skb->ip_summed = CHECKSUM_NONE; |
1010 | 1011 | ||
1011 | skb_queue_walk(&sk->sk_write_queue, skb) { | 1012 | do { |
1012 | csum = csum_add(csum, skb->csum); | 1013 | csum = csum_add(csum, frags->csum); |
1013 | } | 1014 | } while ((frags = frags->next)); |
1014 | 1015 | ||
1015 | uh->check = csum_ipv6_magic(saddr, daddr, len, IPPROTO_UDP, | 1016 | uh->check = csum_ipv6_magic(saddr, daddr, len, IPPROTO_UDP, |
1016 | csum); | 1017 | csum); |
@@ -1023,26 +1024,15 @@ static void udp6_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb, | |||
1023 | * Sending | 1024 | * Sending |
1024 | */ | 1025 | */ |
1025 | 1026 | ||
1026 | static int udp_v6_push_pending_frames(struct sock *sk) | 1027 | static int udp_v6_send_skb(struct sk_buff *skb, struct flowi6 *fl6) |
1027 | { | 1028 | { |
1028 | struct sk_buff *skb; | 1029 | struct sock *sk = skb->sk; |
1029 | struct udphdr *uh; | 1030 | struct udphdr *uh; |
1030 | struct udp_sock *up = udp_sk(sk); | ||
1031 | struct inet_sock *inet = inet_sk(sk); | ||
1032 | struct flowi6 *fl6; | ||
1033 | int err = 0; | 1031 | int err = 0; |
1034 | int is_udplite = IS_UDPLITE(sk); | 1032 | int is_udplite = IS_UDPLITE(sk); |
1035 | __wsum csum = 0; | 1033 | __wsum csum = 0; |
1036 | 1034 | int offset = skb_transport_offset(skb); | |
1037 | if (up->pending == AF_INET) | 1035 | int len = skb->len - offset; |
1038 | return udp_push_pending_frames(sk); | ||
1039 | |||
1040 | fl6 = &inet->cork.fl.u.ip6; | ||
1041 | |||
1042 | /* Grab the skbuff where UDP header space exists. */ | ||
1043 | skb = skb_peek(&sk->sk_write_queue); | ||
1044 | if (skb == NULL) | ||
1045 | goto out; | ||
1046 | 1036 | ||
1047 | /* | 1037 | /* |
1048 | * Create a UDP header | 1038 | * Create a UDP header |
@@ -1050,29 +1040,28 @@ static int udp_v6_push_pending_frames(struct sock *sk) | |||
1050 | uh = udp_hdr(skb); | 1040 | uh = udp_hdr(skb); |
1051 | uh->source = fl6->fl6_sport; | 1041 | uh->source = fl6->fl6_sport; |
1052 | uh->dest = fl6->fl6_dport; | 1042 | uh->dest = fl6->fl6_dport; |
1053 | uh->len = htons(up->len); | 1043 | uh->len = htons(len); |
1054 | uh->check = 0; | 1044 | uh->check = 0; |
1055 | 1045 | ||
1056 | if (is_udplite) | 1046 | if (is_udplite) |
1057 | csum = udplite_csum_outgoing(sk, skb); | 1047 | csum = udplite_csum(skb); |
1058 | else if (up->no_check6_tx) { /* UDP csum disabled */ | 1048 | else if (udp_sk(sk)->no_check6_tx) { /* UDP csum disabled */ |
1059 | skb->ip_summed = CHECKSUM_NONE; | 1049 | skb->ip_summed = CHECKSUM_NONE; |
1060 | goto send; | 1050 | goto send; |
1061 | } else if (skb->ip_summed == CHECKSUM_PARTIAL) { /* UDP hardware csum */ | 1051 | } else if (skb->ip_summed == CHECKSUM_PARTIAL) { /* UDP hardware csum */ |
1062 | udp6_hwcsum_outgoing(sk, skb, &fl6->saddr, &fl6->daddr, | 1052 | udp6_hwcsum_outgoing(sk, skb, &fl6->saddr, &fl6->daddr, len); |
1063 | up->len); | ||
1064 | goto send; | 1053 | goto send; |
1065 | } else | 1054 | } else |
1066 | csum = udp_csum_outgoing(sk, skb); | 1055 | csum = udp_csum(skb); |
1067 | 1056 | ||
1068 | /* add protocol-dependent pseudo-header */ | 1057 | /* add protocol-dependent pseudo-header */ |
1069 | uh->check = csum_ipv6_magic(&fl6->saddr, &fl6->daddr, | 1058 | uh->check = csum_ipv6_magic(&fl6->saddr, &fl6->daddr, |
1070 | up->len, fl6->flowi6_proto, csum); | 1059 | len, fl6->flowi6_proto, csum); |
1071 | if (uh->check == 0) | 1060 | if (uh->check == 0) |
1072 | uh->check = CSUM_MANGLED_0; | 1061 | uh->check = CSUM_MANGLED_0; |
1073 | 1062 | ||
1074 | send: | 1063 | send: |
1075 | err = ip6_push_pending_frames(sk); | 1064 | err = ip6_send_skb(skb); |
1076 | if (err) { | 1065 | if (err) { |
1077 | if (err == -ENOBUFS && !inet6_sk(sk)->recverr) { | 1066 | if (err == -ENOBUFS && !inet6_sk(sk)->recverr) { |
1078 | UDP6_INC_STATS_USER(sock_net(sk), | 1067 | UDP6_INC_STATS_USER(sock_net(sk), |
@@ -1082,6 +1071,30 @@ send: | |||
1082 | } else | 1071 | } else |
1083 | UDP6_INC_STATS_USER(sock_net(sk), | 1072 | UDP6_INC_STATS_USER(sock_net(sk), |
1084 | UDP_MIB_OUTDATAGRAMS, is_udplite); | 1073 | UDP_MIB_OUTDATAGRAMS, is_udplite); |
1074 | return err; | ||
1075 | } | ||
1076 | |||
1077 | static int udp_v6_push_pending_frames(struct sock *sk) | ||
1078 | { | ||
1079 | struct sk_buff *skb; | ||
1080 | struct udp_sock *up = udp_sk(sk); | ||
1081 | struct flowi6 fl6; | ||
1082 | int err = 0; | ||
1083 | |||
1084 | if (up->pending == AF_INET) | ||
1085 | return udp_push_pending_frames(sk); | ||
1086 | |||
1087 | /* ip6_finish_skb will release the cork, so make a copy of | ||
1088 | * fl6 here. | ||
1089 | */ | ||
1090 | fl6 = inet_sk(sk)->cork.fl.u.ip6; | ||
1091 | |||
1092 | skb = ip6_finish_skb(sk); | ||
1093 | if (!skb) | ||
1094 | goto out; | ||
1095 | |||
1096 | err = udp_v6_send_skb(skb, &fl6); | ||
1097 | |||
1085 | out: | 1098 | out: |
1086 | up->len = 0; | 1099 | up->len = 0; |
1087 | up->pending = 0; | 1100 | up->pending = 0; |
@@ -1164,6 +1177,7 @@ do_udp_sendmsg: | |||
1164 | if (len > INT_MAX - sizeof(struct udphdr)) | 1177 | if (len > INT_MAX - sizeof(struct udphdr)) |
1165 | return -EMSGSIZE; | 1178 | return -EMSGSIZE; |
1166 | 1179 | ||
1180 | getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag; | ||
1167 | if (up->pending) { | 1181 | if (up->pending) { |
1168 | /* | 1182 | /* |
1169 | * There are pending frames. | 1183 | * There are pending frames. |
@@ -1294,6 +1308,20 @@ do_udp_sendmsg: | |||
1294 | goto do_confirm; | 1308 | goto do_confirm; |
1295 | back_from_confirm: | 1309 | back_from_confirm: |
1296 | 1310 | ||
1311 | /* Lockless fast path for the non-corking case */ | ||
1312 | if (!corkreq) { | ||
1313 | struct sk_buff *skb; | ||
1314 | |||
1315 | skb = ip6_make_skb(sk, getfrag, msg, ulen, | ||
1316 | sizeof(struct udphdr), hlimit, tclass, opt, | ||
1317 | &fl6, (struct rt6_info *)dst, | ||
1318 | msg->msg_flags, dontfrag); | ||
1319 | err = PTR_ERR(skb); | ||
1320 | if (!IS_ERR_OR_NULL(skb)) | ||
1321 | err = udp_v6_send_skb(skb, &fl6); | ||
1322 | goto release_dst; | ||
1323 | } | ||
1324 | |||
1297 | lock_sock(sk); | 1325 | lock_sock(sk); |
1298 | if (unlikely(up->pending)) { | 1326 | if (unlikely(up->pending)) { |
1299 | /* The socket is already corked while preparing it. */ | 1327 | /* The socket is already corked while preparing it. */ |
@@ -1311,7 +1339,6 @@ do_append_data: | |||
1311 | if (dontfrag < 0) | 1339 | if (dontfrag < 0) |
1312 | dontfrag = np->dontfrag; | 1340 | dontfrag = np->dontfrag; |
1313 | up->len += ulen; | 1341 | up->len += ulen; |
1314 | getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag; | ||
1315 | err = ip6_append_data(sk, getfrag, msg, ulen, | 1342 | err = ip6_append_data(sk, getfrag, msg, ulen, |
1316 | sizeof(struct udphdr), hlimit, tclass, opt, &fl6, | 1343 | sizeof(struct udphdr), hlimit, tclass, opt, &fl6, |
1317 | (struct rt6_info *)dst, | 1344 | (struct rt6_info *)dst, |
@@ -1323,6 +1350,11 @@ do_append_data: | |||
1323 | else if (unlikely(skb_queue_empty(&sk->sk_write_queue))) | 1350 | else if (unlikely(skb_queue_empty(&sk->sk_write_queue))) |
1324 | up->pending = 0; | 1351 | up->pending = 0; |
1325 | 1352 | ||
1353 | if (err > 0) | ||
1354 | err = np->recverr ? net_xmit_errno(err) : 0; | ||
1355 | release_sock(sk); | ||
1356 | |||
1357 | release_dst: | ||
1326 | if (dst) { | 1358 | if (dst) { |
1327 | if (connected) { | 1359 | if (connected) { |
1328 | ip6_dst_store(sk, dst, | 1360 | ip6_dst_store(sk, dst, |
@@ -1339,9 +1371,6 @@ do_append_data: | |||
1339 | dst = NULL; | 1371 | dst = NULL; |
1340 | } | 1372 | } |
1341 | 1373 | ||
1342 | if (err > 0) | ||
1343 | err = np->recverr ? net_xmit_errno(err) : 0; | ||
1344 | release_sock(sk); | ||
1345 | out: | 1374 | out: |
1346 | dst_release(dst); | 1375 | dst_release(dst); |
1347 | fl6_sock_release(flowlabel); | 1376 | fl6_sock_release(flowlabel); |
diff --git a/net/ipv6/udp_offload.c b/net/ipv6/udp_offload.c index b6aa8ed18257..a56276996b72 100644 --- a/net/ipv6/udp_offload.c +++ b/net/ipv6/udp_offload.c | |||
@@ -52,6 +52,10 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb, | |||
52 | 52 | ||
53 | skb_shinfo(skb)->gso_segs = DIV_ROUND_UP(skb->len, mss); | 53 | skb_shinfo(skb)->gso_segs = DIV_ROUND_UP(skb->len, mss); |
54 | 54 | ||
55 | /* Set the IPv6 fragment id if not set yet */ | ||
56 | if (!skb_shinfo(skb)->ip6_frag_id) | ||
57 | ipv6_proxy_select_ident(skb); | ||
58 | |||
55 | segs = NULL; | 59 | segs = NULL; |
56 | goto out; | 60 | goto out; |
57 | } | 61 | } |
@@ -108,7 +112,11 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb, | |||
108 | fptr = (struct frag_hdr *)(skb_network_header(skb) + unfrag_ip6hlen); | 112 | fptr = (struct frag_hdr *)(skb_network_header(skb) + unfrag_ip6hlen); |
109 | fptr->nexthdr = nexthdr; | 113 | fptr->nexthdr = nexthdr; |
110 | fptr->reserved = 0; | 114 | fptr->reserved = 0; |
111 | fptr->identification = skb_shinfo(skb)->ip6_frag_id; | 115 | if (skb_shinfo(skb)->ip6_frag_id) |
116 | fptr->identification = skb_shinfo(skb)->ip6_frag_id; | ||
117 | else | ||
118 | ipv6_select_ident(fptr, | ||
119 | (struct rt6_info *)skb_dst(skb)); | ||
112 | 120 | ||
113 | /* Fragment the skb. ipv6 header and the remaining fields of the | 121 | /* Fragment the skb. ipv6 header and the remaining fields of the |
114 | * fragment header are updated in ipv6_gso_segment() | 122 | * fragment header are updated in ipv6_gso_segment() |
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index 5f983644373a..48bf5a06847b 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c | |||
@@ -130,12 +130,18 @@ _decode_session6(struct sk_buff *skb, struct flowi *fl, int reverse) | |||
130 | { | 130 | { |
131 | struct flowi6 *fl6 = &fl->u.ip6; | 131 | struct flowi6 *fl6 = &fl->u.ip6; |
132 | int onlyproto = 0; | 132 | int onlyproto = 0; |
133 | u16 offset = skb_network_header_len(skb); | ||
134 | const struct ipv6hdr *hdr = ipv6_hdr(skb); | 133 | const struct ipv6hdr *hdr = ipv6_hdr(skb); |
134 | u16 offset = sizeof(*hdr); | ||
135 | struct ipv6_opt_hdr *exthdr; | 135 | struct ipv6_opt_hdr *exthdr; |
136 | const unsigned char *nh = skb_network_header(skb); | 136 | const unsigned char *nh = skb_network_header(skb); |
137 | u8 nexthdr = nh[IP6CB(skb)->nhoff]; | 137 | u16 nhoff = IP6CB(skb)->nhoff; |
138 | int oif = 0; | 138 | int oif = 0; |
139 | u8 nexthdr; | ||
140 | |||
141 | if (!nhoff) | ||
142 | nhoff = offsetof(struct ipv6hdr, nexthdr); | ||
143 | |||
144 | nexthdr = nh[nhoff]; | ||
139 | 145 | ||
140 | if (skb_dst(skb)) | 146 | if (skb_dst(skb)) |
141 | oif = skb_dst(skb)->dev->ifindex; | 147 | oif = skb_dst(skb)->dev->ifindex; |