aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/ip6_output.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/ip6_output.c')
-rw-r--r--net/ipv6/ip6_output.c84
1 files changed, 47 insertions, 37 deletions
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 66716911962e..e05ecbb1412d 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -88,7 +88,7 @@ static inline int ip6_output_finish(struct sk_buff *skb)
88 } else if (dst->neighbour) 88 } else if (dst->neighbour)
89 return dst->neighbour->output(skb); 89 return dst->neighbour->output(skb);
90 90
91 IP6_INC_STATS_BH(IPSTATS_MIB_OUTNOROUTES); 91 IP6_INC_STATS_BH(ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES);
92 kfree_skb(skb); 92 kfree_skb(skb);
93 return -EINVAL; 93 return -EINVAL;
94 94
@@ -118,6 +118,7 @@ static int ip6_output2(struct sk_buff *skb)
118 118
119 if (ipv6_addr_is_multicast(&skb->nh.ipv6h->daddr)) { 119 if (ipv6_addr_is_multicast(&skb->nh.ipv6h->daddr)) {
120 struct ipv6_pinfo* np = skb->sk ? inet6_sk(skb->sk) : NULL; 120 struct ipv6_pinfo* np = skb->sk ? inet6_sk(skb->sk) : NULL;
121 struct inet6_dev *idev = ip6_dst_idev(skb->dst);
121 122
122 if (!(dev->flags & IFF_LOOPBACK) && (!np || np->mc_loop) && 123 if (!(dev->flags & IFF_LOOPBACK) && (!np || np->mc_loop) &&
123 ipv6_chk_mcast_addr(dev, &skb->nh.ipv6h->daddr, 124 ipv6_chk_mcast_addr(dev, &skb->nh.ipv6h->daddr,
@@ -133,13 +134,13 @@ static int ip6_output2(struct sk_buff *skb)
133 ip6_dev_loopback_xmit); 134 ip6_dev_loopback_xmit);
134 135
135 if (skb->nh.ipv6h->hop_limit == 0) { 136 if (skb->nh.ipv6h->hop_limit == 0) {
136 IP6_INC_STATS(IPSTATS_MIB_OUTDISCARDS); 137 IP6_INC_STATS(idev, IPSTATS_MIB_OUTDISCARDS);
137 kfree_skb(skb); 138 kfree_skb(skb);
138 return 0; 139 return 0;
139 } 140 }
140 } 141 }
141 142
142 IP6_INC_STATS(IPSTATS_MIB_OUTMCASTPKTS); 143 IP6_INC_STATS(idev, IPSTATS_MIB_OUTMCASTPKTS);
143 } 144 }
144 145
145 return NF_HOOK(PF_INET6, NF_IP6_POST_ROUTING, skb,NULL, skb->dev,ip6_output_finish); 146 return NF_HOOK(PF_INET6, NF_IP6_POST_ROUTING, skb,NULL, skb->dev,ip6_output_finish);
@@ -182,12 +183,14 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl,
182 183
183 if (skb_headroom(skb) < head_room) { 184 if (skb_headroom(skb) < head_room) {
184 struct sk_buff *skb2 = skb_realloc_headroom(skb, head_room); 185 struct sk_buff *skb2 = skb_realloc_headroom(skb, head_room);
185 kfree_skb(skb); 186 if (skb2 == NULL) {
186 skb = skb2; 187 IP6_INC_STATS(ip6_dst_idev(skb->dst),
187 if (skb == NULL) { 188 IPSTATS_MIB_OUTDISCARDS);
188 IP6_INC_STATS(IPSTATS_MIB_OUTDISCARDS); 189 kfree_skb(skb);
189 return -ENOBUFS; 190 return -ENOBUFS;
190 } 191 }
192 kfree_skb(skb);
193 skb = skb2;
191 if (sk) 194 if (sk)
192 skb_set_owner_w(skb, sk); 195 skb_set_owner_w(skb, sk);
193 } 196 }
@@ -217,7 +220,7 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl,
217 if (tclass < 0) 220 if (tclass < 0)
218 tclass = 0; 221 tclass = 0;
219 222
220 *(u32 *)hdr = htonl(0x60000000 | (tclass << 20)) | fl->fl6_flowlabel; 223 *(__be32 *)hdr = htonl(0x60000000 | (tclass << 20)) | fl->fl6_flowlabel;
221 224
222 hdr->payload_len = htons(seg_len); 225 hdr->payload_len = htons(seg_len);
223 hdr->nexthdr = proto; 226 hdr->nexthdr = proto;
@@ -230,7 +233,8 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl,
230 233
231 mtu = dst_mtu(dst); 234 mtu = dst_mtu(dst);
232 if ((skb->len <= mtu) || ipfragok || skb_is_gso(skb)) { 235 if ((skb->len <= mtu) || ipfragok || skb_is_gso(skb)) {
233 IP6_INC_STATS(IPSTATS_MIB_OUTREQUESTS); 236 IP6_INC_STATS(ip6_dst_idev(skb->dst),
237 IPSTATS_MIB_OUTREQUESTS);
234 return NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, 238 return NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev,
235 dst_output); 239 dst_output);
236 } 240 }
@@ -239,7 +243,7 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl,
239 printk(KERN_DEBUG "IPv6: sending pkt_too_big to self\n"); 243 printk(KERN_DEBUG "IPv6: sending pkt_too_big to self\n");
240 skb->dev = dst->dev; 244 skb->dev = dst->dev;
241 icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev); 245 icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev);
242 IP6_INC_STATS(IPSTATS_MIB_FRAGFAILS); 246 IP6_INC_STATS(ip6_dst_idev(skb->dst), IPSTATS_MIB_FRAGFAILS);
243 kfree_skb(skb); 247 kfree_skb(skb);
244 return -EMSGSIZE; 248 return -EMSGSIZE;
245} 249}
@@ -267,7 +271,7 @@ int ip6_nd_hdr(struct sock *sk, struct sk_buff *skb, struct net_device *dev,
267 hdr = (struct ipv6hdr *) skb_put(skb, sizeof(struct ipv6hdr)); 271 hdr = (struct ipv6hdr *) skb_put(skb, sizeof(struct ipv6hdr));
268 skb->nh.ipv6h = hdr; 272 skb->nh.ipv6h = hdr;
269 273
270 *(u32*)hdr = htonl(0x60000000); 274 *(__be32*)hdr = htonl(0x60000000);
271 275
272 hdr->payload_len = htons(len); 276 hdr->payload_len = htons(len);
273 hdr->nexthdr = proto; 277 hdr->nexthdr = proto;
@@ -373,7 +377,7 @@ int ip6_forward(struct sk_buff *skb)
373 goto error; 377 goto error;
374 378
375 if (!xfrm6_policy_check(NULL, XFRM_POLICY_FWD, skb)) { 379 if (!xfrm6_policy_check(NULL, XFRM_POLICY_FWD, skb)) {
376 IP6_INC_STATS(IPSTATS_MIB_INDISCARDS); 380 IP6_INC_STATS(ip6_dst_idev(dst), IPSTATS_MIB_INDISCARDS);
377 goto drop; 381 goto drop;
378 } 382 }
379 383
@@ -406,7 +410,7 @@ int ip6_forward(struct sk_buff *skb)
406 skb->dev = dst->dev; 410 skb->dev = dst->dev;
407 icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, 411 icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT,
408 0, skb->dev); 412 0, skb->dev);
409 IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); 413 IP6_INC_STATS_BH(ip6_dst_idev(dst), IPSTATS_MIB_INHDRERRORS);
410 414
411 kfree_skb(skb); 415 kfree_skb(skb);
412 return -ETIMEDOUT; 416 return -ETIMEDOUT;
@@ -419,13 +423,13 @@ int ip6_forward(struct sk_buff *skb)
419 if (proxied > 0) 423 if (proxied > 0)
420 return ip6_input(skb); 424 return ip6_input(skb);
421 else if (proxied < 0) { 425 else if (proxied < 0) {
422 IP6_INC_STATS(IPSTATS_MIB_INDISCARDS); 426 IP6_INC_STATS(ip6_dst_idev(dst), IPSTATS_MIB_INDISCARDS);
423 goto drop; 427 goto drop;
424 } 428 }
425 } 429 }
426 430
427 if (!xfrm6_route_forward(skb)) { 431 if (!xfrm6_route_forward(skb)) {
428 IP6_INC_STATS(IPSTATS_MIB_INDISCARDS); 432 IP6_INC_STATS(ip6_dst_idev(dst), IPSTATS_MIB_INDISCARDS);
429 goto drop; 433 goto drop;
430 } 434 }
431 dst = skb->dst; 435 dst = skb->dst;
@@ -464,14 +468,14 @@ int ip6_forward(struct sk_buff *skb)
464 /* Again, force OUTPUT device used as source address */ 468 /* Again, force OUTPUT device used as source address */
465 skb->dev = dst->dev; 469 skb->dev = dst->dev;
466 icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, dst_mtu(dst), skb->dev); 470 icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, dst_mtu(dst), skb->dev);
467 IP6_INC_STATS_BH(IPSTATS_MIB_INTOOBIGERRORS); 471 IP6_INC_STATS_BH(ip6_dst_idev(dst), IPSTATS_MIB_INTOOBIGERRORS);
468 IP6_INC_STATS_BH(IPSTATS_MIB_FRAGFAILS); 472 IP6_INC_STATS_BH(ip6_dst_idev(dst), IPSTATS_MIB_FRAGFAILS);
469 kfree_skb(skb); 473 kfree_skb(skb);
470 return -EMSGSIZE; 474 return -EMSGSIZE;
471 } 475 }
472 476
473 if (skb_cow(skb, dst->dev->hard_header_len)) { 477 if (skb_cow(skb, dst->dev->hard_header_len)) {
474 IP6_INC_STATS(IPSTATS_MIB_OUTDISCARDS); 478 IP6_INC_STATS(ip6_dst_idev(dst), IPSTATS_MIB_OUTDISCARDS);
475 goto drop; 479 goto drop;
476 } 480 }
477 481
@@ -481,11 +485,11 @@ int ip6_forward(struct sk_buff *skb)
481 485
482 hdr->hop_limit--; 486 hdr->hop_limit--;
483 487
484 IP6_INC_STATS_BH(IPSTATS_MIB_OUTFORWDATAGRAMS); 488 IP6_INC_STATS_BH(ip6_dst_idev(dst), IPSTATS_MIB_OUTFORWDATAGRAMS);
485 return NF_HOOK(PF_INET6,NF_IP6_FORWARD, skb, skb->dev, dst->dev, ip6_forward_finish); 489 return NF_HOOK(PF_INET6,NF_IP6_FORWARD, skb, skb->dev, dst->dev, ip6_forward_finish);
486 490
487error: 491error:
488 IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS); 492 IP6_INC_STATS_BH(ip6_dst_idev(dst), IPSTATS_MIB_INADDRERRORS);
489drop: 493drop:
490 kfree_skb(skb); 494 kfree_skb(skb);
491 return -EINVAL; 495 return -EINVAL;
@@ -499,12 +503,12 @@ static void ip6_copy_metadata(struct sk_buff *to, struct sk_buff *from)
499 dst_release(to->dst); 503 dst_release(to->dst);
500 to->dst = dst_clone(from->dst); 504 to->dst = dst_clone(from->dst);
501 to->dev = from->dev; 505 to->dev = from->dev;
506 to->mark = from->mark;
502 507
503#ifdef CONFIG_NET_SCHED 508#ifdef CONFIG_NET_SCHED
504 to->tc_index = from->tc_index; 509 to->tc_index = from->tc_index;
505#endif 510#endif
506#ifdef CONFIG_NETFILTER 511#ifdef CONFIG_NETFILTER
507 to->nfmark = from->nfmark;
508 /* Connection association is same as pre-frag packet */ 512 /* Connection association is same as pre-frag packet */
509 nf_conntrack_put(to->nfct); 513 nf_conntrack_put(to->nfct);
510 to->nfct = from->nfct; 514 to->nfct = from->nfct;
@@ -571,7 +575,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
571 struct ipv6hdr *tmp_hdr; 575 struct ipv6hdr *tmp_hdr;
572 struct frag_hdr *fh; 576 struct frag_hdr *fh;
573 unsigned int mtu, hlen, left, len; 577 unsigned int mtu, hlen, left, len;
574 u32 frag_id = 0; 578 __be32 frag_id = 0;
575 int ptr, offset = 0, err=0; 579 int ptr, offset = 0, err=0;
576 u8 *prevhdr, nexthdr = 0; 580 u8 *prevhdr, nexthdr = 0;
577 581
@@ -620,14 +624,13 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
620 skb_shinfo(skb)->frag_list = NULL; 624 skb_shinfo(skb)->frag_list = NULL;
621 /* BUILD HEADER */ 625 /* BUILD HEADER */
622 626
623 tmp_hdr = kmalloc(hlen, GFP_ATOMIC); 627 tmp_hdr = kmemdup(skb->nh.raw, hlen, GFP_ATOMIC);
624 if (!tmp_hdr) { 628 if (!tmp_hdr) {
625 IP6_INC_STATS(IPSTATS_MIB_FRAGFAILS); 629 IP6_INC_STATS(ip6_dst_idev(skb->dst), IPSTATS_MIB_FRAGFAILS);
626 return -ENOMEM; 630 return -ENOMEM;
627 } 631 }
628 632
629 *prevhdr = NEXTHDR_FRAGMENT; 633 *prevhdr = NEXTHDR_FRAGMENT;
630 memcpy(tmp_hdr, skb->nh.raw, hlen);
631 __skb_pull(skb, hlen); 634 __skb_pull(skb, hlen);
632 fh = (struct frag_hdr*)__skb_push(skb, sizeof(struct frag_hdr)); 635 fh = (struct frag_hdr*)__skb_push(skb, sizeof(struct frag_hdr));
633 skb->nh.raw = __skb_push(skb, hlen); 636 skb->nh.raw = __skb_push(skb, hlen);
@@ -643,7 +646,8 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
643 skb->data_len = first_len - skb_headlen(skb); 646 skb->data_len = first_len - skb_headlen(skb);
644 skb->len = first_len; 647 skb->len = first_len;
645 skb->nh.ipv6h->payload_len = htons(first_len - sizeof(struct ipv6hdr)); 648 skb->nh.ipv6h->payload_len = htons(first_len - sizeof(struct ipv6hdr));
646 649
650 dst_hold(&rt->u.dst);
647 651
648 for (;;) { 652 for (;;) {
649 /* Prepare header of the next frame, 653 /* Prepare header of the next frame,
@@ -667,7 +671,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
667 671
668 err = output(skb); 672 err = output(skb);
669 if(!err) 673 if(!err)
670 IP6_INC_STATS(IPSTATS_MIB_FRAGCREATES); 674 IP6_INC_STATS(ip6_dst_idev(&rt->u.dst), IPSTATS_MIB_FRAGCREATES);
671 675
672 if (err || !frag) 676 if (err || !frag)
673 break; 677 break;
@@ -680,7 +684,8 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
680 kfree(tmp_hdr); 684 kfree(tmp_hdr);
681 685
682 if (err == 0) { 686 if (err == 0) {
683 IP6_INC_STATS(IPSTATS_MIB_FRAGOKS); 687 IP6_INC_STATS(ip6_dst_idev(&rt->u.dst), IPSTATS_MIB_FRAGOKS);
688 dst_release(&rt->u.dst);
684 return 0; 689 return 0;
685 } 690 }
686 691
@@ -690,7 +695,8 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
690 frag = skb; 695 frag = skb;
691 } 696 }
692 697
693 IP6_INC_STATS(IPSTATS_MIB_FRAGFAILS); 698 IP6_INC_STATS(ip6_dst_idev(&rt->u.dst), IPSTATS_MIB_FRAGFAILS);
699 dst_release(&rt->u.dst);
694 return err; 700 return err;
695 } 701 }
696 702
@@ -723,7 +729,8 @@ slow_path:
723 729
724 if ((frag = alloc_skb(len+hlen+sizeof(struct frag_hdr)+LL_RESERVED_SPACE(rt->u.dst.dev), GFP_ATOMIC)) == NULL) { 730 if ((frag = alloc_skb(len+hlen+sizeof(struct frag_hdr)+LL_RESERVED_SPACE(rt->u.dst.dev), GFP_ATOMIC)) == NULL) {
725 NETDEBUG(KERN_INFO "IPv6: frag: no memory for new fragment!\n"); 731 NETDEBUG(KERN_INFO "IPv6: frag: no memory for new fragment!\n");
726 IP6_INC_STATS(IPSTATS_MIB_FRAGFAILS); 732 IP6_INC_STATS(ip6_dst_idev(skb->dst),
733 IPSTATS_MIB_FRAGFAILS);
727 err = -ENOMEM; 734 err = -ENOMEM;
728 goto fail; 735 goto fail;
729 } 736 }
@@ -784,15 +791,17 @@ slow_path:
784 if (err) 791 if (err)
785 goto fail; 792 goto fail;
786 793
787 IP6_INC_STATS(IPSTATS_MIB_FRAGCREATES); 794 IP6_INC_STATS(ip6_dst_idev(skb->dst), IPSTATS_MIB_FRAGCREATES);
788 } 795 }
796 IP6_INC_STATS(ip6_dst_idev(skb->dst),
797 IPSTATS_MIB_FRAGOKS);
789 kfree_skb(skb); 798 kfree_skb(skb);
790 IP6_INC_STATS(IPSTATS_MIB_FRAGOKS);
791 return err; 799 return err;
792 800
793fail: 801fail:
802 IP6_INC_STATS(ip6_dst_idev(skb->dst),
803 IPSTATS_MIB_FRAGFAILS);
794 kfree_skb(skb); 804 kfree_skb(skb);
795 IP6_INC_STATS(IPSTATS_MIB_FRAGFAILS);
796 return err; 805 return err;
797} 806}
798 807
@@ -1265,7 +1274,7 @@ alloc_new_skb:
1265 return 0; 1274 return 0;
1266error: 1275error:
1267 inet->cork.length -= length; 1276 inet->cork.length -= length;
1268 IP6_INC_STATS(IPSTATS_MIB_OUTDISCARDS); 1277 IP6_INC_STATS(rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS);
1269 return err; 1278 return err;
1270} 1279}
1271 1280
@@ -1311,7 +1320,7 @@ int ip6_push_pending_frames(struct sock *sk)
1311 1320
1312 skb->nh.ipv6h = hdr = (struct ipv6hdr*) skb_push(skb, sizeof(struct ipv6hdr)); 1321 skb->nh.ipv6h = hdr = (struct ipv6hdr*) skb_push(skb, sizeof(struct ipv6hdr));
1313 1322
1314 *(u32*)hdr = fl->fl6_flowlabel | 1323 *(__be32*)hdr = fl->fl6_flowlabel |
1315 htonl(0x60000000 | ((int)np->cork.tclass << 20)); 1324 htonl(0x60000000 | ((int)np->cork.tclass << 20));
1316 1325
1317 if (skb->len <= sizeof(struct ipv6hdr) + IPV6_MAXPLEN) 1326 if (skb->len <= sizeof(struct ipv6hdr) + IPV6_MAXPLEN)
@@ -1326,7 +1335,7 @@ int ip6_push_pending_frames(struct sock *sk)
1326 skb->priority = sk->sk_priority; 1335 skb->priority = sk->sk_priority;
1327 1336
1328 skb->dst = dst_clone(&rt->u.dst); 1337 skb->dst = dst_clone(&rt->u.dst);
1329 IP6_INC_STATS(IPSTATS_MIB_OUTREQUESTS); 1338 IP6_INC_STATS(rt->rt6i_idev, IPSTATS_MIB_OUTREQUESTS);
1330 err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, skb->dst->dev, dst_output); 1339 err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, skb->dst->dev, dst_output);
1331 if (err) { 1340 if (err) {
1332 if (err > 0) 1341 if (err > 0)
@@ -1357,7 +1366,8 @@ void ip6_flush_pending_frames(struct sock *sk)
1357 struct sk_buff *skb; 1366 struct sk_buff *skb;
1358 1367
1359 while ((skb = __skb_dequeue_tail(&sk->sk_write_queue)) != NULL) { 1368 while ((skb = __skb_dequeue_tail(&sk->sk_write_queue)) != NULL) {
1360 IP6_INC_STATS(IPSTATS_MIB_OUTDISCARDS); 1369 IP6_INC_STATS(ip6_dst_idev(skb->dst),
1370 IPSTATS_MIB_OUTDISCARDS);
1361 kfree_skb(skb); 1371 kfree_skb(skb);
1362 } 1372 }
1363 1373