diff options
Diffstat (limited to 'net/ipv6/ip6_output.c')
-rw-r--r-- | net/ipv6/ip6_output.c | 81 |
1 files changed, 31 insertions, 50 deletions
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 5552d13ae92f..155eccfa7760 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c | |||
@@ -56,8 +56,6 @@ | |||
56 | #include <net/checksum.h> | 56 | #include <net/checksum.h> |
57 | #include <linux/mroute6.h> | 57 | #include <linux/mroute6.h> |
58 | 58 | ||
59 | int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)); | ||
60 | |||
61 | int __ip6_local_out(struct sk_buff *skb) | 59 | int __ip6_local_out(struct sk_buff *skb) |
62 | { | 60 | { |
63 | int len; | 61 | int len; |
@@ -88,7 +86,8 @@ static int ip6_finish_output2(struct sk_buff *skb) | |||
88 | struct dst_entry *dst = skb_dst(skb); | 86 | struct dst_entry *dst = skb_dst(skb); |
89 | struct net_device *dev = dst->dev; | 87 | struct net_device *dev = dst->dev; |
90 | struct neighbour *neigh; | 88 | struct neighbour *neigh; |
91 | struct rt6_info *rt; | 89 | struct in6_addr *nexthop; |
90 | int ret; | ||
92 | 91 | ||
93 | skb->protocol = htons(ETH_P_IPV6); | 92 | skb->protocol = htons(ETH_P_IPV6); |
94 | skb->dev = dev; | 93 | skb->dev = dev; |
@@ -121,12 +120,26 @@ static int ip6_finish_output2(struct sk_buff *skb) | |||
121 | 120 | ||
122 | IP6_UPD_PO_STATS(dev_net(dev), idev, IPSTATS_MIB_OUTMCAST, | 121 | IP6_UPD_PO_STATS(dev_net(dev), idev, IPSTATS_MIB_OUTMCAST, |
123 | skb->len); | 122 | skb->len); |
123 | |||
124 | if (IPV6_ADDR_MC_SCOPE(&ipv6_hdr(skb)->daddr) <= | ||
125 | IPV6_ADDR_SCOPE_NODELOCAL && | ||
126 | !(dev->flags & IFF_LOOPBACK)) { | ||
127 | kfree_skb(skb); | ||
128 | return 0; | ||
129 | } | ||
124 | } | 130 | } |
125 | 131 | ||
126 | rt = (struct rt6_info *) dst; | 132 | rcu_read_lock_bh(); |
127 | neigh = rt->n; | 133 | nexthop = rt6_nexthop((struct rt6_info *)dst, &ipv6_hdr(skb)->daddr); |
128 | if (neigh) | 134 | neigh = __ipv6_neigh_lookup_noref(dst->dev, nexthop); |
129 | return dst_neigh_output(dst, neigh, skb); | 135 | if (unlikely(!neigh)) |
136 | neigh = __neigh_create(&nd_tbl, nexthop, dst->dev, false); | ||
137 | if (!IS_ERR(neigh)) { | ||
138 | ret = dst_neigh_output(dst, neigh, skb); | ||
139 | rcu_read_unlock_bh(); | ||
140 | return ret; | ||
141 | } | ||
142 | rcu_read_unlock_bh(); | ||
130 | 143 | ||
131 | IP6_INC_STATS_BH(dev_net(dst->dev), | 144 | IP6_INC_STATS_BH(dev_net(dst->dev), |
132 | ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES); | 145 | ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES); |
@@ -216,7 +229,7 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6, | |||
216 | if (hlimit < 0) | 229 | if (hlimit < 0) |
217 | hlimit = ip6_dst_hoplimit(dst); | 230 | hlimit = ip6_dst_hoplimit(dst); |
218 | 231 | ||
219 | *(__be32 *)hdr = htonl(0x60000000 | (tclass << 20)) | fl6->flowlabel; | 232 | ip6_flow_hdr(hdr, tclass, fl6->flowlabel); |
220 | 233 | ||
221 | hdr->payload_len = htons(seg_len); | 234 | hdr->payload_len = htons(seg_len); |
222 | hdr->nexthdr = proto; | 235 | hdr->nexthdr = proto; |
@@ -236,9 +249,8 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6, | |||
236 | dst->dev, dst_output); | 249 | dst->dev, dst_output); |
237 | } | 250 | } |
238 | 251 | ||
239 | net_dbg_ratelimited("IPv6: sending pkt_too_big to self\n"); | ||
240 | skb->dev = dst->dev; | 252 | skb->dev = dst->dev; |
241 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); | 253 | ipv6_local_error(sk, EMSGSIZE, fl6, mtu); |
242 | IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_FRAGFAILS); | 254 | IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_FRAGFAILS); |
243 | kfree_skb(skb); | 255 | kfree_skb(skb); |
244 | return -EMSGSIZE; | 256 | return -EMSGSIZE; |
@@ -246,39 +258,6 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6, | |||
246 | 258 | ||
247 | EXPORT_SYMBOL(ip6_xmit); | 259 | EXPORT_SYMBOL(ip6_xmit); |
248 | 260 | ||
249 | /* | ||
250 | * To avoid extra problems ND packets are send through this | ||
251 | * routine. It's code duplication but I really want to avoid | ||
252 | * extra checks since ipv6_build_header is used by TCP (which | ||
253 | * is for us performance critical) | ||
254 | */ | ||
255 | |||
256 | int ip6_nd_hdr(struct sock *sk, struct sk_buff *skb, struct net_device *dev, | ||
257 | const struct in6_addr *saddr, const struct in6_addr *daddr, | ||
258 | int proto, int len) | ||
259 | { | ||
260 | struct ipv6_pinfo *np = inet6_sk(sk); | ||
261 | struct ipv6hdr *hdr; | ||
262 | |||
263 | skb->protocol = htons(ETH_P_IPV6); | ||
264 | skb->dev = dev; | ||
265 | |||
266 | skb_reset_network_header(skb); | ||
267 | skb_put(skb, sizeof(struct ipv6hdr)); | ||
268 | hdr = ipv6_hdr(skb); | ||
269 | |||
270 | *(__be32*)hdr = htonl(0x60000000); | ||
271 | |||
272 | hdr->payload_len = htons(len); | ||
273 | hdr->nexthdr = proto; | ||
274 | hdr->hop_limit = np->hop_limit; | ||
275 | |||
276 | hdr->saddr = *saddr; | ||
277 | hdr->daddr = *daddr; | ||
278 | |||
279 | return 0; | ||
280 | } | ||
281 | |||
282 | static int ip6_call_ra_chain(struct sk_buff *skb, int sel) | 261 | static int ip6_call_ra_chain(struct sk_buff *skb, int sel) |
283 | { | 262 | { |
284 | struct ip6_ra_chain *ra; | 263 | struct ip6_ra_chain *ra; |
@@ -913,8 +892,12 @@ static int ip6_dst_lookup_tail(struct sock *sk, | |||
913 | * dst entry of the nexthop router | 892 | * dst entry of the nexthop router |
914 | */ | 893 | */ |
915 | rt = (struct rt6_info *) *dst; | 894 | rt = (struct rt6_info *) *dst; |
916 | n = rt->n; | 895 | rcu_read_lock_bh(); |
917 | if (n && !(n->nud_state & NUD_VALID)) { | 896 | n = __ipv6_neigh_lookup_noref(rt->dst.dev, rt6_nexthop(rt, &fl6->daddr)); |
897 | err = n && !(n->nud_state & NUD_VALID) ? -EINVAL : 0; | ||
898 | rcu_read_unlock_bh(); | ||
899 | |||
900 | if (err) { | ||
918 | struct inet6_ifaddr *ifp; | 901 | struct inet6_ifaddr *ifp; |
919 | struct flowi6 fl_gw6; | 902 | struct flowi6 fl_gw6; |
920 | int redirect; | 903 | int redirect; |
@@ -1213,10 +1196,10 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, | |||
1213 | if (dst_allfrag(rt->dst.path)) | 1196 | if (dst_allfrag(rt->dst.path)) |
1214 | cork->flags |= IPCORK_ALLFRAG; | 1197 | cork->flags |= IPCORK_ALLFRAG; |
1215 | cork->length = 0; | 1198 | cork->length = 0; |
1216 | exthdrlen = (opt ? opt->opt_flen : 0) - rt->rt6i_nfheader_len; | 1199 | exthdrlen = (opt ? opt->opt_flen : 0); |
1217 | length += exthdrlen; | 1200 | length += exthdrlen; |
1218 | transhdrlen += exthdrlen; | 1201 | transhdrlen += exthdrlen; |
1219 | dst_exthdrlen = rt->dst.header_len; | 1202 | dst_exthdrlen = rt->dst.header_len - rt->rt6i_nfheader_len; |
1220 | } else { | 1203 | } else { |
1221 | rt = (struct rt6_info *)cork->dst; | 1204 | rt = (struct rt6_info *)cork->dst; |
1222 | fl6 = &inet->cork.fl.u.ip6; | 1205 | fl6 = &inet->cork.fl.u.ip6; |
@@ -1548,9 +1531,7 @@ int ip6_push_pending_frames(struct sock *sk) | |||
1548 | skb_reset_network_header(skb); | 1531 | skb_reset_network_header(skb); |
1549 | hdr = ipv6_hdr(skb); | 1532 | hdr = ipv6_hdr(skb); |
1550 | 1533 | ||
1551 | *(__be32*)hdr = fl6->flowlabel | | 1534 | ip6_flow_hdr(hdr, np->cork.tclass, fl6->flowlabel); |
1552 | htonl(0x60000000 | ((int)np->cork.tclass << 20)); | ||
1553 | |||
1554 | hdr->hop_limit = np->cork.hop_limit; | 1535 | hdr->hop_limit = np->cork.hop_limit; |
1555 | hdr->nexthdr = proto; | 1536 | hdr->nexthdr = proto; |
1556 | hdr->saddr = fl6->saddr; | 1537 | hdr->saddr = fl6->saddr; |