00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include <linux/errno.h>
00027 #include <linux/types.h>
00028 #include <linux/socket.h>
00029 #include <linux/net.h>
00030 #include <linux/netdevice.h>
00031 #include <linux/if_arp.h>
00032 #include <linux/in6.h>
00033 #include <linux/route.h>
00034
00035 #include <net/sock.h>
00036 #include <net/snmp.h>
00037
00038 #include <net/ipv6.h>
00039 #include <net/ndisc.h>
00040 #include <net/protocol.h>
00041 #include <net/ip6_route.h>
00042 #include <net/addrconf.h>
00043 #include <net/rawv6.h>
00044 #include <net/icmp.h>
00045
00046 static u32 ipv6_fragmentation_id = 1;
00047
00048 int ip6_output(struct sk_buff *skb)
00049 {
00050 struct dst_entry *dst = skb->dst;
00051 struct device *dev = dst->dev;
00052 struct hh_cache *hh = dst->hh;
00053
00054 skb->protocol = __constant_htons(ETH_P_IPV6);
00055 skb->dev = dev;
00056
00057 if (ipv6_addr_is_multicast(&skb->nh.ipv6h->daddr)) {
00058 if (!(dev->flags&IFF_LOOPBACK) &&
00059 (skb->sk == NULL || skb->sk->net_pinfo.af_inet6.mc_loop) &&
00060 ipv6_chk_mcast_addr(dev, &skb->nh.ipv6h->daddr)) {
00061
00062
00063
00064 dev_loopback_xmit(skb);
00065
00066 if (skb->nh.ipv6h->hop_limit == 0) {
00067 kfree_skb(skb);
00068 return 0;
00069 }
00070 }
00071
00072 ipv6_statistics.Ip6OutMcastPkts++;
00073 }
00074
00075 if (hh) {
00076 #ifdef __alpha__
00077
00078 u64 *aligned_hdr = (u64*)(skb->data - 16);
00079 u64 *aligned_hdr0 = hh->hh_data;
00080 read_lock_irq(&hh->hh_lock);
00081 aligned_hdr[0] = aligned_hdr0[0];
00082 aligned_hdr[1] = aligned_hdr0[1];
00083 #else
00084 read_lock_irq(&hh->hh_lock);
00085 memcpy(skb->data - 16, hh->hh_data, 16);
00086 #endif
00087 read_unlock_irq(&hh->hh_lock);
00088 skb_push(skb, dev->hard_header_len);
00089 return hh->hh_output(skb);
00090 } else if (dst->neighbour)
00091 return dst->neighbour->output(skb);
00092
00093 kfree_skb(skb);
00094 return -EINVAL;
00095 }
00096
00097
00098
00099
00100
00101 int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl,
00102 struct ipv6_txoptions *opt)
00103 {
00104 struct ipv6_pinfo * np = sk ? &sk->net_pinfo.af_inet6 : NULL;
00105 struct in6_addr *first_hop = fl->nl_u.ip6_u.daddr;
00106 struct dst_entry *dst = skb->dst;
00107 struct ipv6hdr *hdr;
00108 u8 proto = fl->proto;
00109 int seg_len = skb->len;
00110 int hlimit;
00111
00112 if (opt) {
00113 int head_room;
00114
00115
00116
00117
00118 head_room = opt->opt_nflen + opt->opt_flen;
00119 seg_len += head_room;
00120 head_room += sizeof(struct ipv6hdr) + ((dst->dev->hard_header_len + 15)&~15);
00121
00122 if (skb_headroom(skb) < head_room) {
00123 struct sk_buff *skb2 = skb_realloc_headroom(skb, head_room);
00124 kfree_skb(skb);
00125 skb = skb2;
00126 if (skb == NULL)
00127 return -ENOBUFS;
00128 if (sk)
00129 skb_set_owner_w(skb, sk);
00130 }
00131 if (opt->opt_flen)
00132 ipv6_push_frag_opts(skb, opt, &proto);
00133 if (opt->opt_nflen)
00134 ipv6_push_nfrag_opts(skb, opt, &proto, &first_hop);
00135 }
00136
00137 hdr = skb->nh.ipv6h = (struct ipv6hdr*)skb_push(skb, sizeof(struct ipv6hdr));
00138
00139
00140
00141
00142
00143 *(u32*)hdr = __constant_htonl(0x60000000) | fl->fl6_flowlabel;
00144 hlimit = -1;
00145 if (np)
00146 hlimit = np->hop_limit;
00147 if (hlimit < 0)
00148 hlimit = ((struct rt6_info*)dst)->rt6i_hoplimit;
00149
00150 hdr->payload_len = htons(seg_len);
00151 hdr->nexthdr = proto;
00152 hdr->hop_limit = hlimit;
00153
00154 ipv6_addr_copy(&hdr->saddr, fl->nl_u.ip6_u.saddr);
00155 ipv6_addr_copy(&hdr->daddr, first_hop);
00156
00157 if (skb->len <= dst->pmtu) {
00158 ipv6_statistics.Ip6OutRequests++;
00159 dst->output(skb);
00160 return 0;
00161 }
00162
00163 printk(KERN_DEBUG "IPv6: sending pkt_too_big to self\n");
00164 start_bh_atomic();
00165 icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, dst->pmtu, skb->dev);
00166 end_bh_atomic();
00167 kfree_skb(skb);
00168 return -EMSGSIZE;
00169 }
00170
00171
00172
00173
00174
00175
00176
00177
00178 int ip6_nd_hdr(struct sock *sk, struct sk_buff *skb, struct device *dev,
00179 struct in6_addr *saddr, struct in6_addr *daddr,
00180 int proto, int len)
00181 {
00182 struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
00183 struct ipv6hdr *hdr;
00184 int totlen;
00185
00186 skb->protocol = __constant_htons(ETH_P_IPV6);
00187 skb->dev = dev;
00188
00189 totlen = len + sizeof(struct ipv6hdr);
00190
00191 hdr = (struct ipv6hdr *) skb_put(skb, sizeof(struct ipv6hdr));
00192 skb->nh.ipv6h = hdr;
00193
00194 *(u32*)hdr = htonl(0x60000000);
00195
00196 hdr->payload_len = htons(len);
00197 hdr->nexthdr = proto;
00198 hdr->hop_limit = np->hop_limit;
00199
00200 ipv6_addr_copy(&hdr->saddr, saddr);
00201 ipv6_addr_copy(&hdr->daddr, daddr);
00202
00203 return 0;
00204 }
00205
00206 static struct ipv6hdr * ip6_bld_1(struct sock *sk, struct sk_buff *skb, struct flowi *fl,
00207 int hlimit, unsigned pktlength)
00208 {
00209 struct ipv6hdr *hdr;
00210
00211 skb->nh.raw = skb_put(skb, sizeof(struct ipv6hdr));
00212 hdr = skb->nh.ipv6h;
00213
00214 *(u32*)hdr = fl->fl6_flowlabel | htonl(0x60000000);
00215
00216 hdr->payload_len = htons(pktlength - sizeof(struct ipv6hdr));
00217 hdr->hop_limit = hlimit;
00218 hdr->nexthdr = fl->proto;
00219
00220 ipv6_addr_copy(&hdr->saddr, fl->nl_u.ip6_u.saddr);
00221 ipv6_addr_copy(&hdr->daddr, fl->nl_u.ip6_u.daddr);
00222 return hdr;
00223 }
00224
00225 static __inline__ u8 * ipv6_build_fraghdr(struct sk_buff *skb, u8* prev_hdr, unsigned offset)
00226 {
00227 struct frag_hdr *fhdr;
00228
00229 fhdr = (struct frag_hdr *) skb_put(skb, sizeof(struct frag_hdr));
00230
00231 fhdr->nexthdr = *prev_hdr;
00232 *prev_hdr = NEXTHDR_FRAGMENT;
00233 prev_hdr = &fhdr->nexthdr;
00234
00235 fhdr->reserved = 0;
00236 fhdr->frag_off = htons(offset);
00237 fhdr->identification = ipv6_fragmentation_id++;
00238 return &fhdr->nexthdr;
00239 }
00240
00241 static int ip6_frag_xmit(struct sock *sk, inet_getfrag_t getfrag,
00242 const void *data, struct dst_entry *dst,
00243 struct flowi *fl, struct ipv6_txoptions *opt,
00244 struct in6_addr *final_dst,
00245 int hlimit, int flags, unsigned length, int mtu)
00246 {
00247 struct ipv6hdr *hdr;
00248 struct sk_buff *last_skb;
00249 u8 *prev_hdr;
00250 int unfrag_len;
00251 int frag_len;
00252 int last_len;
00253 int nfrags;
00254 int fhdr_dist;
00255 int frag_off;
00256 int data_off;
00257 int err;
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271 unfrag_len = sizeof(struct ipv6hdr) + sizeof(struct frag_hdr);
00272 last_len = length;
00273
00274 if (opt) {
00275 unfrag_len += opt->opt_nflen;
00276 last_len += opt->opt_flen;
00277 }
00278
00279
00280
00281
00282
00283
00284
00285 frag_len = (mtu - unfrag_len) & ~0x7;
00286
00287
00288 if (frag_len <= 0) {
00289 ipv6_local_error(sk, EMSGSIZE, fl, mtu);
00290 return -EMSGSIZE;
00291 }
00292
00293 nfrags = last_len / frag_len;
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306 frag_off = nfrags * frag_len;
00307 last_len -= frag_off;
00308
00309 if (last_len == 0) {
00310 last_len = frag_len;
00311 frag_off -= frag_len;
00312 nfrags--;
00313 }
00314 data_off = frag_off;
00315
00316
00317
00318
00319 if (opt) {
00320 if (frag_len < opt->opt_flen) {
00321 ipv6_local_error(sk, EMSGSIZE, fl, mtu);
00322 return -EMSGSIZE;
00323 }
00324 data_off = frag_off - opt->opt_flen;
00325 }
00326
00327 last_skb = sock_alloc_send_skb(sk, unfrag_len + frag_len +
00328 dst->dev->hard_header_len + 15,
00329 0, flags & MSG_DONTWAIT, &err);
00330
00331 if (last_skb == NULL)
00332 return err;
00333
00334 last_skb->dst = dst_clone(dst);
00335
00336 skb_reserve(last_skb, (dst->dev->hard_header_len + 15) & ~15);
00337
00338 hdr = ip6_bld_1(sk, last_skb, fl, hlimit, frag_len+unfrag_len);
00339 prev_hdr = &hdr->nexthdr;
00340
00341 if (opt && opt->opt_nflen)
00342 prev_hdr = ipv6_build_nfrag_opts(last_skb, prev_hdr, opt, final_dst, 0);
00343
00344 prev_hdr = ipv6_build_fraghdr(last_skb, prev_hdr, frag_off);
00345 fhdr_dist = prev_hdr - last_skb->data;
00346
00347 err = getfrag(data, &hdr->saddr, last_skb->tail, data_off, last_len);
00348
00349 if (!err) {
00350 while (nfrags--) {
00351 struct sk_buff *skb;
00352
00353 struct frag_hdr *fhdr2;
00354
00355 skb = skb_copy(last_skb, sk->allocation);
00356
00357 if (skb == NULL) {
00358 ipv6_statistics.Ip6FragFails++;
00359 kfree_skb(last_skb);
00360 return -ENOMEM;
00361 }
00362
00363 frag_off -= frag_len;
00364 data_off -= frag_len;
00365
00366 fhdr2 = (struct frag_hdr *) (skb->data + fhdr_dist);
00367
00368
00369 fhdr2->frag_off = htons(frag_off | 1);
00370
00371
00372 if (nfrags == 0 && opt && opt->opt_flen) {
00373 ipv6_build_frag_opts(skb, &fhdr2->nexthdr, opt);
00374 frag_len -= opt->opt_flen;
00375 data_off = 0;
00376 }
00377
00378 err = getfrag(data, &hdr->saddr,skb_put(skb, frag_len),
00379 data_off, frag_len);
00380
00381 if (err) {
00382 kfree_skb(skb);
00383 break;
00384 }
00385
00386 ipv6_statistics.Ip6FragCreates++;
00387 ipv6_statistics.Ip6OutRequests++;
00388 dst->output(skb);
00389 }
00390 }
00391
00392 if (err) {
00393 ipv6_statistics.Ip6FragFails++;
00394 kfree_skb(last_skb);
00395 return -EFAULT;
00396 }
00397
00398 hdr->payload_len = htons(unfrag_len + last_len - sizeof(struct ipv6hdr));
00399
00400
00401
00402
00403
00404
00405 skb_put(last_skb, last_len);
00406
00407 ipv6_statistics.Ip6FragCreates++;
00408 ipv6_statistics.Ip6FragOKs++;
00409 ipv6_statistics.Ip6OutRequests++;
00410 dst->output(last_skb);
00411
00412 return 0;
00413 }
00414
00415 int ip6_build_xmit(struct sock *sk, inet_getfrag_t getfrag, const void *data,
00416 struct flowi *fl, unsigned length,
00417 struct ipv6_txoptions *opt, int hlimit, int flags)
00418 {
00419 struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
00420 struct in6_addr *final_dst = NULL;
00421 struct dst_entry *dst;
00422 int err = 0;
00423 unsigned int pktlength, jumbolen, mtu;
00424 struct in6_addr saddr;
00425
00426 if (opt && opt->srcrt) {
00427 struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
00428 final_dst = fl->fl6_dst;
00429 fl->fl6_dst = rt0->addr;
00430 }
00431
00432 if (!fl->oif && ipv6_addr_is_multicast(fl->nl_u.ip6_u.daddr))
00433 fl->oif = np->mcast_oif;
00434
00435 dst = NULL;
00436 if (sk->dst_cache) {
00437 dst = dst_check(&sk->dst_cache, np->dst_cookie);
00438 if (dst) {
00439 struct rt6_info *rt = (struct rt6_info*)dst_clone(dst);
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458 if (((rt->rt6i_dst.plen != 128 ||
00459 ipv6_addr_cmp(fl->fl6_dst, &rt->rt6i_dst.addr))
00460 && (np->daddr_cache == NULL ||
00461 ipv6_addr_cmp(fl->fl6_dst, np->daddr_cache)))
00462 || (fl->oif && fl->oif != dst->dev->ifindex)) {
00463 dst_release(dst);
00464 dst = NULL;
00465 }
00466 }
00467 }
00468
00469 if (dst == NULL)
00470 dst = ip6_route_output(sk, fl);
00471
00472 if (dst->error) {
00473 ipv6_statistics.Ip6OutNoRoutes++;
00474 dst_release(dst);
00475 return -ENETUNREACH;
00476 }
00477
00478 if (fl->fl6_src == NULL) {
00479 err = ipv6_get_saddr(dst, fl->fl6_dst, &saddr);
00480
00481 if (err) {
00482 #if IP6_DEBUG >= 2
00483 printk(KERN_DEBUG "ip6_build_xmit: "
00484 "no availiable source address\n");
00485 #endif
00486 goto out;
00487 }
00488 fl->fl6_src = &saddr;
00489 }
00490 pktlength = length;
00491
00492 if (hlimit < 0) {
00493 if (ipv6_addr_is_multicast(fl->fl6_dst))
00494 hlimit = np->mcast_hops;
00495 else
00496 hlimit = np->hop_limit;
00497 if (hlimit < 0)
00498 hlimit = ((struct rt6_info*)dst)->rt6i_hoplimit;
00499 }
00500
00501 jumbolen = 0;
00502
00503 if (!sk->ip_hdrincl) {
00504 pktlength += sizeof(struct ipv6hdr);
00505 if (opt)
00506 pktlength += opt->opt_flen + opt->opt_nflen;
00507
00508 if (pktlength > 0xFFFF + sizeof(struct ipv6hdr)) {
00509
00510
00511
00512
00513 pktlength += 8;
00514 jumbolen = pktlength - sizeof(struct ipv6hdr);
00515 }
00516 }
00517
00518 mtu = dst->pmtu;
00519 if (np->frag_size < mtu) {
00520 if (np->frag_size)
00521 mtu = np->frag_size;
00522 else if (np->pmtudisc == IPV6_PMTUDISC_DONT)
00523 mtu = IPV6_MIN_MTU;
00524 }
00525
00526
00527
00528
00529 if (pktlength < length) {
00530 ipv6_local_error(sk, EMSGSIZE, fl, mtu);
00531 err = -EMSGSIZE;
00532 goto out;
00533 }
00534
00535 if (pktlength <= mtu) {
00536 struct sk_buff *skb;
00537 struct ipv6hdr *hdr;
00538 struct device *dev = dst->dev;
00539
00540 skb = sock_alloc_send_skb(sk, pktlength + 15 +
00541 dev->hard_header_len, 0,
00542 flags & MSG_DONTWAIT, &err);
00543
00544 if (skb == NULL) {
00545 ipv6_statistics.Ip6OutDiscards++;
00546 goto out;
00547 }
00548
00549 skb->dst = dst_clone(dst);
00550
00551 skb_reserve(skb, (dev->hard_header_len + 15) & ~15);
00552
00553 hdr = (struct ipv6hdr *) skb->tail;
00554 skb->nh.ipv6h = hdr;
00555
00556 if (!sk->ip_hdrincl) {
00557 ip6_bld_1(sk, skb, fl, hlimit,
00558 jumbolen ? sizeof(struct ipv6hdr) : pktlength);
00559
00560 if (opt || jumbolen) {
00561 u8 *prev_hdr = &hdr->nexthdr;
00562 prev_hdr = ipv6_build_nfrag_opts(skb, prev_hdr, opt, final_dst, jumbolen);
00563 if (opt && opt->opt_flen)
00564 ipv6_build_frag_opts(skb, prev_hdr, opt);
00565 }
00566 }
00567
00568 skb_put(skb, length);
00569 err = getfrag(data, &hdr->saddr,
00570 ((char *) hdr) + (pktlength - length),
00571 0, length);
00572
00573 if (!err) {
00574 ipv6_statistics.Ip6OutRequests++;
00575 dst->output(skb);
00576 } else {
00577 err = -EFAULT;
00578 kfree_skb(skb);
00579 }
00580 } else {
00581 if (sk->ip_hdrincl || jumbolen ||
00582 np->pmtudisc == IPV6_PMTUDISC_DO) {
00583 ipv6_local_error(sk, EMSGSIZE, fl, mtu);
00584 err = -EMSGSIZE;
00585 goto out;
00586 }
00587
00588 err = ip6_frag_xmit(sk, getfrag, data, dst, fl, opt, final_dst, hlimit,
00589 flags, length, mtu);
00590 }
00591
00592
00593
00594
00595 out:
00596 ip6_dst_store(sk, dst, fl->nl_u.ip6_u.daddr == &np->daddr ? &np->daddr : NULL);
00597 return err;
00598 }
00599
00600 int ip6_call_ra_chain(struct sk_buff *skb, int sel)
00601 {
00602 struct ip6_ra_chain *ra;
00603 struct sock *last = NULL;
00604
00605 for (ra = ip6_ra_chain; ra; ra = ra->next) {
00606 struct sock *sk = ra->sk;
00607 if (sk && ra->sel == sel) {
00608 if (last) {
00609 struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
00610 if (skb2)
00611 rawv6_rcv(last, skb2, skb2->len);
00612 }
00613 last = sk;
00614 }
00615 }
00616
00617 if (last) {
00618 rawv6_rcv(last, skb, skb->len);
00619 return 1;
00620 }
00621 return 0;
00622 }
00623
00624 int ip6_forward(struct sk_buff *skb)
00625 {
00626 struct dst_entry *dst = skb->dst;
00627 struct ipv6hdr *hdr = skb->nh.ipv6h;
00628 struct inet6_skb_parm *opt =(struct inet6_skb_parm*)skb->cb;
00629
00630 if (ipv6_devconf.forwarding == 0 && opt->srcrt == 0)
00631 goto drop;
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646 if (opt->ra) {
00647 u8 *ptr = skb->nh.raw + opt->ra;
00648 if (ip6_call_ra_chain(skb, (ptr[2]<<8) + ptr[3]))
00649 return 0;
00650 }
00651
00652
00653
00654
00655 if (hdr->hop_limit <= 1) {
00656
00657 skb->dev = dst->dev;
00658 icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT,
00659 0, skb->dev);
00660
00661 kfree_skb(skb);
00662 return -ETIMEDOUT;
00663 }
00664
00665
00666
00667
00668 if (skb->dev == dst->dev && dst->neighbour && opt->srcrt == 0) {
00669 struct in6_addr *target = NULL;
00670 struct rt6_info *rt;
00671 struct neighbour *n = dst->neighbour;
00672
00673
00674
00675
00676
00677
00678 rt = (struct rt6_info *) dst;
00679 if ((rt->rt6i_flags & RTF_GATEWAY))
00680 target = (struct in6_addr*)&n->primary_key;
00681 else
00682 target = &hdr->daddr;
00683
00684
00685
00686
00687 if (xrlim_allow(dst, 1*HZ))
00688 ndisc_send_redirect(skb, n, target);
00689 } else if (ipv6_addr_type(&hdr->saddr)&(IPV6_ADDR_MULTICAST|IPV6_ADDR_LOOPBACK
00690 |IPV6_ADDR_LINKLOCAL)) {
00691
00692 goto drop;
00693 }
00694
00695 if (skb->len > dst->pmtu) {
00696
00697 skb->dev = dst->dev;
00698 icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, dst->pmtu, skb->dev);
00699 ipv6_statistics.Ip6InTooBigErrors++;
00700 kfree_skb(skb);
00701 return -EMSGSIZE;
00702 }
00703
00704 if ((skb = skb_cow(skb, dst->dev->hard_header_len)) == NULL)
00705 return 0;
00706
00707 hdr = skb->nh.ipv6h;
00708
00709
00710
00711 hdr->hop_limit--;
00712
00713 ipv6_statistics.Ip6OutForwDatagrams++;
00714 return dst->output(skb);
00715
00716 drop:
00717 ipv6_statistics.Ip6InAddrErrors++;
00718 kfree_skb(skb);
00719 return -EINVAL;
00720 }