- Linus: more PageDirty / swapcache handling
[davej-history.git] / net / ipv6 / udp.c
blobfbf0c31f657706c1b367e58833daded980a39cbf
1 /*
2 * UDP over IPv6
3 * Linux INET6 implementation
5 * Authors:
6 * Pedro Roque <roque@di.fc.ul.pt>
8 * Based on linux/ipv4/udp.c
10 * $Id: udp.c,v 1.59 2000/11/28 13:38:38 davem Exp $
12 * Fixes:
13 * Hideaki YOSHIFUJI : sin6_scope_id support
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version
18 * 2 of the License, or (at your option) any later version.
21 #include <linux/config.h>
22 #include <linux/errno.h>
23 #include <linux/types.h>
24 #include <linux/socket.h>
25 #include <linux/sockios.h>
26 #include <linux/sched.h>
27 #include <linux/net.h>
28 #include <linux/in6.h>
29 #include <linux/netdevice.h>
30 #include <linux/if_arp.h>
31 #include <linux/ipv6.h>
32 #include <linux/icmpv6.h>
33 #include <linux/init.h>
34 #include <asm/uaccess.h>
36 #include <net/sock.h>
37 #include <net/snmp.h>
39 #include <net/ipv6.h>
40 #include <net/ndisc.h>
41 #include <net/protocol.h>
42 #include <net/transp_v6.h>
43 #include <net/ip6_route.h>
44 #include <net/addrconf.h>
45 #include <net/ip.h>
46 #include <net/udp.h>
47 #include <net/inet_common.h>
49 #include <net/checksum.h>
51 struct udp_mib udp_stats_in6[NR_CPUS*2];
53 /* Grrr, addr_type already calculated by caller, but I don't want
54 * to add some silly "cookie" argument to this method just for that.
56 static int udp_v6_get_port(struct sock *sk, unsigned short snum)
58 write_lock_bh(&udp_hash_lock);
59 if (snum == 0) {
60 int best_size_so_far, best, result, i;
62 if (udp_port_rover > sysctl_local_port_range[1] ||
63 udp_port_rover < sysctl_local_port_range[0])
64 udp_port_rover = sysctl_local_port_range[0];
65 best_size_so_far = 32767;
66 best = result = udp_port_rover;
67 for (i = 0; i < UDP_HTABLE_SIZE; i++, result++) {
68 struct sock *sk;
69 int size;
71 sk = udp_hash[result & (UDP_HTABLE_SIZE - 1)];
72 if (!sk) {
73 if (result > sysctl_local_port_range[1])
74 result = sysctl_local_port_range[0] +
75 ((result - sysctl_local_port_range[0]) &
76 (UDP_HTABLE_SIZE - 1));
77 goto gotit;
79 size = 0;
80 do {
81 if (++size >= best_size_so_far)
82 goto next;
83 } while ((sk = sk->next) != NULL);
84 best_size_so_far = size;
85 best = result;
86 next:
88 result = best;
89 for(;; result += UDP_HTABLE_SIZE) {
90 if (result > sysctl_local_port_range[1])
91 result = sysctl_local_port_range[0]
92 + ((result - sysctl_local_port_range[0]) &
93 (UDP_HTABLE_SIZE - 1));
94 if (!udp_lport_inuse(result))
95 break;
97 gotit:
98 udp_port_rover = snum = result;
99 } else {
100 struct sock *sk2;
101 int addr_type = ipv6_addr_type(&sk->net_pinfo.af_inet6.rcv_saddr);
103 for (sk2 = udp_hash[snum & (UDP_HTABLE_SIZE - 1)];
104 sk2 != NULL;
105 sk2 = sk2->next) {
106 if (sk2->num == snum &&
107 sk2 != sk &&
108 sk2->bound_dev_if == sk->bound_dev_if &&
109 (!sk2->rcv_saddr ||
110 addr_type == IPV6_ADDR_ANY ||
111 !ipv6_addr_cmp(&sk->net_pinfo.af_inet6.rcv_saddr,
112 &sk2->net_pinfo.af_inet6.rcv_saddr) ||
113 (addr_type == IPV6_ADDR_MAPPED &&
114 sk2->family == AF_INET &&
115 sk->rcv_saddr == sk2->rcv_saddr)) &&
116 (!sk2->reuse || !sk->reuse))
117 goto fail;
121 sk->num = snum;
122 if (sk->pprev == NULL) {
123 struct sock **skp = &udp_hash[snum & (UDP_HTABLE_SIZE - 1)];
124 if ((sk->next = *skp) != NULL)
125 (*skp)->pprev = &sk->next;
126 *skp = sk;
127 sk->pprev = skp;
128 sock_prot_inc_use(sk->prot);
129 sock_hold(sk);
131 write_unlock_bh(&udp_hash_lock);
132 return 0;
134 fail:
135 write_unlock_bh(&udp_hash_lock);
136 return 1;
139 static void udp_v6_hash(struct sock *sk)
141 BUG();
144 static void udp_v6_unhash(struct sock *sk)
146 write_lock_bh(&udp_hash_lock);
147 if (sk->pprev) {
148 if (sk->next)
149 sk->next->pprev = sk->pprev;
150 *sk->pprev = sk->next;
151 sk->pprev = NULL;
152 sk->num = 0;
153 sock_prot_dec_use(sk->prot);
154 __sock_put(sk);
156 write_unlock_bh(&udp_hash_lock);
159 static struct sock *udp_v6_lookup(struct in6_addr *saddr, u16 sport,
160 struct in6_addr *daddr, u16 dport, int dif)
162 struct sock *sk, *result = NULL;
163 unsigned short hnum = ntohs(dport);
164 int badness = -1;
166 read_lock(&udp_hash_lock);
167 for(sk = udp_hash[hnum & (UDP_HTABLE_SIZE - 1)]; sk != NULL; sk = sk->next) {
168 if((sk->num == hnum) &&
169 (sk->family == PF_INET6)) {
170 struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
171 int score = 0;
172 if(sk->dport) {
173 if(sk->dport != sport)
174 continue;
175 score++;
177 if(!ipv6_addr_any(&np->rcv_saddr)) {
178 if(ipv6_addr_cmp(&np->rcv_saddr, daddr))
179 continue;
180 score++;
182 if(!ipv6_addr_any(&np->daddr)) {
183 if(ipv6_addr_cmp(&np->daddr, saddr))
184 continue;
185 score++;
187 if(sk->bound_dev_if) {
188 if(sk->bound_dev_if != dif)
189 continue;
190 score++;
192 if(score == 4) {
193 result = sk;
194 break;
195 } else if(score > badness) {
196 result = sk;
197 badness = score;
201 if (result)
202 sock_hold(result);
203 read_unlock(&udp_hash_lock);
204 return result;
211 int udpv6_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
213 struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr;
214 struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
215 struct in6_addr *daddr;
216 struct in6_addr saddr;
217 struct dst_entry *dst;
218 struct flowi fl;
219 struct ip6_flowlabel *flowlabel = NULL;
220 int addr_type;
221 int err;
223 if (usin->sin6_family == AF_INET) {
224 err = udp_connect(sk, uaddr, addr_len);
225 goto ipv4_connected;
228 if (addr_len < SIN6_LEN_RFC2133)
229 return -EINVAL;
231 if (usin->sin6_family != AF_INET6)
232 return -EAFNOSUPPORT;
234 fl.fl6_flowlabel = 0;
235 if (np->sndflow) {
236 fl.fl6_flowlabel = usin->sin6_flowinfo&IPV6_FLOWINFO_MASK;
237 if (fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) {
238 flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel);
239 if (flowlabel == NULL)
240 return -EINVAL;
241 ipv6_addr_copy(&usin->sin6_addr, &flowlabel->dst);
245 addr_type = ipv6_addr_type(&usin->sin6_addr);
247 if (addr_type == IPV6_ADDR_ANY) {
249 * connect to self
251 usin->sin6_addr.s6_addr[15] = 0x01;
254 daddr = &usin->sin6_addr;
256 if (addr_type == IPV6_ADDR_MAPPED) {
257 struct sockaddr_in sin;
259 sin.sin_family = AF_INET;
260 sin.sin_addr.s_addr = daddr->s6_addr32[3];
261 sin.sin_port = usin->sin6_port;
263 err = udp_connect(sk, (struct sockaddr*) &sin, sizeof(sin));
265 ipv4_connected:
266 if (err < 0)
267 return err;
269 ipv6_addr_set(&np->daddr, 0, 0,
270 __constant_htonl(0x0000ffff),
271 sk->daddr);
273 if(ipv6_addr_any(&np->saddr)) {
274 ipv6_addr_set(&np->saddr, 0, 0,
275 __constant_htonl(0x0000ffff),
276 sk->saddr);
279 if(ipv6_addr_any(&np->rcv_saddr)) {
280 ipv6_addr_set(&np->rcv_saddr, 0, 0,
281 __constant_htonl(0x0000ffff),
282 sk->rcv_saddr);
284 return 0;
287 if (addr_type&IPV6_ADDR_LINKLOCAL) {
288 if (addr_len >= sizeof(struct sockaddr_in6) &&
289 usin->sin6_scope_id) {
290 if (sk->bound_dev_if && sk->bound_dev_if != usin->sin6_scope_id) {
291 fl6_sock_release(flowlabel);
292 return -EINVAL;
294 sk->bound_dev_if = usin->sin6_scope_id;
297 /* Connect to link-local address requires an interface */
298 if (sk->bound_dev_if == 0)
299 return -EINVAL;
302 ipv6_addr_copy(&np->daddr, daddr);
303 np->flow_label = fl.fl6_flowlabel;
305 sk->dport = usin->sin6_port;
308 * Check for a route to destination an obtain the
309 * destination cache for it.
312 fl.proto = IPPROTO_UDP;
313 fl.fl6_dst = &np->daddr;
314 fl.fl6_src = &saddr;
315 fl.oif = sk->bound_dev_if;
316 fl.uli_u.ports.dport = sk->dport;
317 fl.uli_u.ports.sport = sk->sport;
319 if (flowlabel) {
320 if (flowlabel->opt && flowlabel->opt->srcrt) {
321 struct rt0_hdr *rt0 = (struct rt0_hdr *) flowlabel->opt->srcrt;
322 fl.fl6_dst = rt0->addr;
324 } else if (np->opt && np->opt->srcrt) {
325 struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt;
326 fl.fl6_dst = rt0->addr;
329 dst = ip6_route_output(sk, &fl);
331 if ((err = dst->error) != 0) {
332 dst_release(dst);
333 fl6_sock_release(flowlabel);
334 return err;
337 ip6_dst_store(sk, dst, fl.fl6_dst);
339 /* get the source adddress used in the apropriate device */
341 err = ipv6_get_saddr(dst, daddr, &saddr);
343 if (err == 0) {
344 if(ipv6_addr_any(&np->saddr))
345 ipv6_addr_copy(&np->saddr, &saddr);
347 if(ipv6_addr_any(&np->rcv_saddr)) {
348 ipv6_addr_copy(&np->rcv_saddr, &saddr);
349 sk->rcv_saddr = LOOPBACK4_IPV6;
351 sk->state = TCP_ESTABLISHED;
353 fl6_sock_release(flowlabel);
355 return err;
358 static void udpv6_close(struct sock *sk, long timeout)
360 inet_sock_release(sk);
364 * This should be easy, if there is something there we
365 * return it, otherwise we block.
368 int udpv6_recvmsg(struct sock *sk, struct msghdr *msg, int len,
369 int noblock, int flags, int *addr_len)
371 struct sk_buff *skb;
372 int copied, err;
374 if (addr_len)
375 *addr_len=sizeof(struct sockaddr_in6);
377 if (flags & MSG_ERRQUEUE)
378 return ipv6_recv_error(sk, msg, len);
380 skb = skb_recv_datagram(sk, flags, noblock, &err);
381 if (!skb)
382 goto out;
384 copied = skb->len - sizeof(struct udphdr);
385 if (copied > len) {
386 copied = len;
387 msg->msg_flags |= MSG_TRUNC;
390 if (skb->ip_summed==CHECKSUM_UNNECESSARY) {
391 err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov,
392 copied);
393 } else if (msg->msg_flags&MSG_TRUNC) {
394 if ((unsigned short)csum_fold(csum_partial(skb->h.raw, skb->len, skb->csum)))
395 goto csum_copy_err;
396 err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov,
397 copied);
398 } else {
399 err = copy_and_csum_toiovec(msg->msg_iov, skb, sizeof(struct udphdr));
400 if (err)
401 goto csum_copy_err;
403 if (err)
404 goto out_free;
406 sock_recv_timestamp(msg, sk, skb);
408 /* Copy the address. */
409 if (msg->msg_name) {
410 struct sockaddr_in6 *sin6;
412 sin6 = (struct sockaddr_in6 *) msg->msg_name;
413 sin6->sin6_family = AF_INET6;
414 sin6->sin6_port = skb->h.uh->source;
415 sin6->sin6_flowinfo = 0;
416 sin6->sin6_scope_id = 0;
418 if (skb->protocol == __constant_htons(ETH_P_IP)) {
419 ipv6_addr_set(&sin6->sin6_addr, 0, 0,
420 __constant_htonl(0xffff), skb->nh.iph->saddr);
421 if (sk->protinfo.af_inet.cmsg_flags)
422 ip_cmsg_recv(msg, skb);
423 } else {
424 memcpy(&sin6->sin6_addr, &skb->nh.ipv6h->saddr,
425 sizeof(struct in6_addr));
427 if (sk->net_pinfo.af_inet6.rxopt.all)
428 datagram_recv_ctl(sk, msg, skb);
429 if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) {
430 struct inet6_skb_parm *opt = (struct inet6_skb_parm *) skb->cb;
431 sin6->sin6_scope_id = opt->iif;
435 err = copied;
437 out_free:
438 skb_free_datagram(sk, skb);
439 out:
440 return err;
442 csum_copy_err:
443 /* Clear queue. */
444 if (flags&MSG_PEEK) {
445 int clear = 0;
446 spin_lock_irq(&sk->receive_queue.lock);
447 if (skb == skb_peek(&sk->receive_queue)) {
448 __skb_unlink(skb, &sk->receive_queue);
449 clear = 1;
451 spin_unlock_irq(&sk->receive_queue.lock);
452 if (clear)
453 kfree_skb(skb);
456 /* Error for blocking case is chosen to masquerade
457 as some normal condition.
459 err = (flags&MSG_DONTWAIT) ? -EAGAIN : -EHOSTUNREACH;
460 UDP6_INC_STATS_USER(UdpInErrors);
461 goto out_free;
464 void udpv6_err(struct sk_buff *skb, struct ipv6hdr *hdr,
465 struct inet6_skb_parm *opt,
466 int type, int code, unsigned char *buff, __u32 info)
468 struct net_device *dev = skb->dev;
469 struct in6_addr *saddr = &hdr->saddr;
470 struct in6_addr *daddr = &hdr->daddr;
471 struct sock *sk;
472 struct udphdr *uh;
473 int err;
475 if (buff + sizeof(struct udphdr) > skb->tail)
476 return;
478 uh = (struct udphdr *) buff;
480 sk = udp_v6_lookup(daddr, uh->dest, saddr, uh->source, dev->ifindex);
482 if (sk == NULL)
483 return;
485 if (!icmpv6_err_convert(type, code, &err) &&
486 !sk->net_pinfo.af_inet6.recverr)
487 goto out;
489 if (sk->state!=TCP_ESTABLISHED &&
490 !sk->net_pinfo.af_inet6.recverr)
491 goto out;
493 if (sk->net_pinfo.af_inet6.recverr)
494 ipv6_icmp_error(sk, skb, err, uh->dest, ntohl(info), (u8 *)(uh+1));
496 sk->err = err;
497 sk->error_report(sk);
498 out:
499 sock_put(sk);
502 static inline int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
504 #if defined(CONFIG_FILTER)
505 if (sk->filter && skb->ip_summed != CHECKSUM_UNNECESSARY) {
506 if ((unsigned short)csum_fold(csum_partial(skb->h.raw, skb->len, skb->csum))) {
507 UDP6_INC_STATS_BH(UdpInErrors);
508 IP6_INC_STATS_BH(Ip6InDiscards);
509 kfree_skb(skb);
510 return 0;
512 skb->ip_summed = CHECKSUM_UNNECESSARY;
514 #endif
515 if (sock_queue_rcv_skb(sk,skb)<0) {
516 UDP6_INC_STATS_BH(UdpInErrors);
517 IP6_INC_STATS_BH(Ip6InDiscards);
518 kfree_skb(skb);
519 return 0;
521 IP6_INC_STATS_BH(Ip6InDelivers);
522 UDP6_INC_STATS_BH(UdpInDatagrams);
523 return 0;
526 static struct sock *udp_v6_mcast_next(struct sock *sk,
527 u16 loc_port, struct in6_addr *loc_addr,
528 u16 rmt_port, struct in6_addr *rmt_addr,
529 int dif)
531 struct sock *s = sk;
532 unsigned short num = ntohs(loc_port);
533 for(; s; s = s->next) {
534 if(s->num == num) {
535 struct ipv6_pinfo *np = &s->net_pinfo.af_inet6;
536 if(s->dport) {
537 if(s->dport != rmt_port)
538 continue;
540 if(!ipv6_addr_any(&np->daddr) &&
541 ipv6_addr_cmp(&np->daddr, rmt_addr))
542 continue;
544 if (s->bound_dev_if && s->bound_dev_if != dif)
545 continue;
547 if(!ipv6_addr_any(&np->rcv_saddr)) {
548 if(ipv6_addr_cmp(&np->rcv_saddr, loc_addr) == 0)
549 return s;
551 if(!inet6_mc_check(s, loc_addr))
552 continue;
553 return s;
556 return NULL;
560 * Note: called only from the BH handler context,
561 * so we don't need to lock the hashes.
563 static void udpv6_mcast_deliver(struct udphdr *uh,
564 struct in6_addr *saddr, struct in6_addr *daddr,
565 struct sk_buff *skb)
567 struct sock *sk, *sk2;
568 struct sk_buff *buff;
569 int dif;
571 read_lock(&udp_hash_lock);
572 sk = udp_hash[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)];
573 dif = skb->dev->ifindex;
574 sk = udp_v6_mcast_next(sk, uh->dest, daddr, uh->source, saddr, dif);
575 if (!sk)
576 goto free_skb;
578 buff = NULL;
579 sk2 = sk;
580 while((sk2 = udp_v6_mcast_next(sk2->next, uh->dest, saddr,
581 uh->source, daddr, dif))) {
582 if (!buff) {
583 buff = skb_clone(skb, GFP_ATOMIC);
584 if (!buff)
585 continue;
587 if (sock_queue_rcv_skb(sk2, buff) >= 0)
588 buff = NULL;
590 if (buff)
591 kfree_skb(buff);
592 if (sock_queue_rcv_skb(sk, skb) < 0) {
593 free_skb:
594 kfree_skb(skb);
596 read_unlock(&udp_hash_lock);
599 int udpv6_rcv(struct sk_buff *skb, unsigned long len)
601 struct sock *sk;
602 struct udphdr *uh;
603 struct net_device *dev = skb->dev;
604 struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
605 struct in6_addr *daddr = &skb->nh.ipv6h->daddr;
606 u32 ulen;
608 uh = skb->h.uh;
609 __skb_pull(skb, skb->h.raw - skb->data);
611 ulen = ntohs(uh->len);
613 /* Check for jumbo payload */
614 if (ulen == 0 && skb->nh.ipv6h->payload_len == 0)
615 ulen = len;
617 if (ulen > len || len < sizeof(*uh)) {
618 if (net_ratelimit())
619 printk(KERN_DEBUG "UDP: short packet: %d/%ld\n", ulen, len);
620 UDP6_INC_STATS_BH(UdpInErrors);
621 kfree_skb(skb);
622 return(0);
625 if (uh->check == 0) {
626 /* IPv6 draft-v2 section 8.1 says that we SHOULD log
627 this error. Well, it is reasonable.
629 if (net_ratelimit())
630 printk(KERN_INFO "IPv6: udp checksum is 0\n");
631 goto discard;
634 skb_trim(skb, ulen);
636 if (skb->ip_summed==CHECKSUM_HW) {
637 if (csum_ipv6_magic(saddr, daddr, ulen, IPPROTO_UDP, skb->csum))
638 goto discard;
639 skb->ip_summed = CHECKSUM_UNNECESSARY;
640 } else if (skb->ip_summed != CHECKSUM_UNNECESSARY)
641 skb->csum = ~csum_ipv6_magic(saddr, daddr, ulen, IPPROTO_UDP, 0);
643 len = ulen;
646 * Multicast receive code
648 if (ipv6_addr_type(daddr) & IPV6_ADDR_MULTICAST) {
649 udpv6_mcast_deliver(uh, saddr, daddr, skb);
650 return 0;
653 /* Unicast */
656 * check socket cache ... must talk to Alan about his plans
657 * for sock caches... i'll skip this for now.
660 sk = udp_v6_lookup(saddr, uh->source, daddr, uh->dest, dev->ifindex);
662 if (sk == NULL) {
663 if (skb->ip_summed != CHECKSUM_UNNECESSARY &&
664 (unsigned short)csum_fold(csum_partial((char*)uh, len, skb->csum)))
665 goto discard;
666 UDP6_INC_STATS_BH(UdpNoPorts);
668 icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, dev);
670 kfree_skb(skb);
671 return(0);
674 /* deliver */
676 udpv6_queue_rcv_skb(sk, skb);
677 sock_put(sk);
678 return(0);
680 discard:
681 UDP6_INC_STATS_BH(UdpInErrors);
682 kfree_skb(skb);
683 return(0);
687 * Sending
690 struct udpv6fakehdr
692 struct udphdr uh;
693 struct iovec *iov;
694 __u32 wcheck;
695 __u32 pl_len;
696 struct in6_addr *daddr;
700 * with checksum
703 static int udpv6_getfrag(const void *data, struct in6_addr *addr,
704 char *buff, unsigned int offset, unsigned int len)
706 struct udpv6fakehdr *udh = (struct udpv6fakehdr *) data;
707 char *dst;
708 int final = 0;
709 int clen = len;
711 dst = buff;
713 if (offset) {
714 offset -= sizeof(struct udphdr);
715 } else {
716 dst += sizeof(struct udphdr);
717 final = 1;
718 clen -= sizeof(struct udphdr);
721 if (csum_partial_copy_fromiovecend(dst, udh->iov, offset,
722 clen, &udh->wcheck))
723 return -EFAULT;
725 if (final) {
726 struct in6_addr *daddr;
728 udh->wcheck = csum_partial((char *)udh, sizeof(struct udphdr),
729 udh->wcheck);
731 if (udh->daddr) {
732 daddr = udh->daddr;
733 } else {
735 * use packet destination address
736 * this should improve cache locality
738 daddr = addr + 1;
740 udh->uh.check = csum_ipv6_magic(addr, daddr,
741 udh->pl_len, IPPROTO_UDP,
742 udh->wcheck);
743 if (udh->uh.check == 0)
744 udh->uh.check = -1;
746 memcpy(buff, udh, sizeof(struct udphdr));
748 return 0;
751 static int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, int ulen)
753 struct ipv6_txoptions opt_space;
754 struct udpv6fakehdr udh;
755 struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
756 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) msg->msg_name;
757 struct ipv6_txoptions *opt = NULL;
758 struct ip6_flowlabel *flowlabel = NULL;
759 struct flowi fl;
760 int addr_len = msg->msg_namelen;
761 struct in6_addr *daddr;
762 int len = ulen + sizeof(struct udphdr);
763 int addr_type;
764 int hlimit = -1;
766 int err;
768 /* Rough check on arithmetic overflow,
769 better check is made in ip6_build_xmit
771 if (ulen < 0 || ulen > INT_MAX - sizeof(struct udphdr))
772 return -EMSGSIZE;
774 fl.fl6_flowlabel = 0;
775 fl.oif = 0;
777 if (sin6) {
778 if (sin6->sin6_family == AF_INET)
779 return udp_sendmsg(sk, msg, ulen);
781 if (addr_len < SIN6_LEN_RFC2133)
782 return -EINVAL;
784 if (sin6->sin6_family && sin6->sin6_family != AF_INET6)
785 return -EINVAL;
787 if (sin6->sin6_port == 0)
788 return -EINVAL;
790 udh.uh.dest = sin6->sin6_port;
791 daddr = &sin6->sin6_addr;
793 if (np->sndflow) {
794 fl.fl6_flowlabel = sin6->sin6_flowinfo&IPV6_FLOWINFO_MASK;
795 if (fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) {
796 flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel);
797 if (flowlabel == NULL)
798 return -EINVAL;
799 daddr = &flowlabel->dst;
803 /* Otherwise it will be difficult to maintain sk->dst_cache. */
804 if (sk->state == TCP_ESTABLISHED &&
805 !ipv6_addr_cmp(daddr, &sk->net_pinfo.af_inet6.daddr))
806 daddr = &sk->net_pinfo.af_inet6.daddr;
808 if (addr_len >= sizeof(struct sockaddr_in6) &&
809 sin6->sin6_scope_id &&
810 ipv6_addr_type(daddr)&IPV6_ADDR_LINKLOCAL)
811 fl.oif = sin6->sin6_scope_id;
812 } else {
813 if (sk->state != TCP_ESTABLISHED)
814 return -ENOTCONN;
816 udh.uh.dest = sk->dport;
817 daddr = &sk->net_pinfo.af_inet6.daddr;
818 fl.fl6_flowlabel = np->flow_label;
821 addr_type = ipv6_addr_type(daddr);
823 if (addr_type == IPV6_ADDR_MAPPED) {
824 struct sockaddr_in sin;
826 sin.sin_family = AF_INET;
827 sin.sin_addr.s_addr = daddr->s6_addr32[3];
828 sin.sin_port = udh.uh.dest;
829 msg->msg_name = (struct sockaddr *)(&sin);
830 msg->msg_namelen = sizeof(sin);
831 fl6_sock_release(flowlabel);
833 return udp_sendmsg(sk, msg, ulen);
836 udh.daddr = NULL;
837 if (!fl.oif)
838 fl.oif = sk->bound_dev_if;
839 fl.fl6_src = NULL;
841 if (msg->msg_controllen) {
842 opt = &opt_space;
843 memset(opt, 0, sizeof(struct ipv6_txoptions));
845 err = datagram_send_ctl(msg, &fl, opt, &hlimit);
846 if (err < 0) {
847 fl6_sock_release(flowlabel);
848 return err;
850 if ((fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) && !flowlabel) {
851 flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel);
852 if (flowlabel == NULL)
853 return -EINVAL;
855 if (!(opt->opt_nflen|opt->opt_flen))
856 opt = NULL;
858 if (opt == NULL)
859 opt = np->opt;
860 if (flowlabel)
861 opt = fl6_merge_options(&opt_space, flowlabel, opt);
862 if (opt && opt->srcrt)
863 udh.daddr = daddr;
865 udh.uh.source = sk->sport;
866 udh.uh.len = len < 0x10000 ? htons(len) : 0;
867 udh.uh.check = 0;
868 udh.iov = msg->msg_iov;
869 udh.wcheck = 0;
870 udh.pl_len = len;
872 fl.proto = IPPROTO_UDP;
873 fl.fl6_dst = daddr;
874 if (fl.fl6_src == NULL && !ipv6_addr_any(&np->saddr))
875 fl.fl6_src = &np->saddr;
876 fl.uli_u.ports.dport = udh.uh.dest;
877 fl.uli_u.ports.sport = udh.uh.source;
879 err = ip6_build_xmit(sk, udpv6_getfrag, &udh, &fl, len, opt, hlimit,
880 msg->msg_flags);
882 fl6_sock_release(flowlabel);
884 if (err < 0)
885 return err;
887 UDP6_INC_STATS_USER(UdpOutDatagrams);
888 return ulen;
891 static struct inet6_protocol udpv6_protocol =
893 udpv6_rcv, /* UDP handler */
894 udpv6_err, /* UDP error control */
895 NULL, /* next */
896 IPPROTO_UDP, /* protocol ID */
897 0, /* copy */
898 NULL, /* data */
899 "UDPv6" /* name */
902 #define LINE_LEN 190
903 #define LINE_FMT "%-190s\n"
905 static void get_udp6_sock(struct sock *sp, char *tmpbuf, int i)
907 struct in6_addr *dest, *src;
908 __u16 destp, srcp;
910 dest = &sp->net_pinfo.af_inet6.daddr;
911 src = &sp->net_pinfo.af_inet6.rcv_saddr;
912 destp = ntohs(sp->dport);
913 srcp = ntohs(sp->sport);
914 sprintf(tmpbuf,
915 "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
916 "%02X %08X:%08X %02X:%08lX %08X %5d %8d %ld %d %p",
918 src->s6_addr32[0], src->s6_addr32[1],
919 src->s6_addr32[2], src->s6_addr32[3], srcp,
920 dest->s6_addr32[0], dest->s6_addr32[1],
921 dest->s6_addr32[2], dest->s6_addr32[3], destp,
922 sp->state,
923 atomic_read(&sp->wmem_alloc), atomic_read(&sp->rmem_alloc),
924 0, 0L, 0,
925 sock_i_uid(sp), 0,
926 sock_i_ino(sp),
927 atomic_read(&sp->refcnt), sp);
930 int udp6_get_info(char *buffer, char **start, off_t offset, int length)
932 int len = 0, num = 0, i;
933 off_t pos = 0;
934 off_t begin;
935 char tmpbuf[LINE_LEN+2];
937 if (offset < LINE_LEN+1)
938 len += sprintf(buffer, LINE_FMT,
939 " sl " /* 6 */
940 "local_address " /* 38 */
941 "remote_address " /* 38 */
942 "st tx_queue rx_queue tr tm->when retrnsmt" /* 41 */
943 " uid timeout inode"); /* 21 */
944 /*----*/
945 /*144 */
946 pos = LINE_LEN+1;
947 read_lock(&udp_hash_lock);
948 for (i = 0; i < UDP_HTABLE_SIZE; i++) {
949 struct sock *sk;
951 for (sk = udp_hash[i]; sk; sk = sk->next, num++) {
952 if (sk->family != PF_INET6)
953 continue;
954 pos += LINE_LEN+1;
955 if (pos <= offset)
956 continue;
957 get_udp6_sock(sk, tmpbuf, i);
958 len += sprintf(buffer+len, LINE_FMT, tmpbuf);
959 if(len >= length)
960 goto out;
963 out:
964 read_unlock(&udp_hash_lock);
965 begin = len - (pos - offset);
966 *start = buffer + begin;
967 len -= begin;
968 if(len > length)
969 len = length;
970 if (len < 0)
971 len = 0;
972 return len;
975 struct proto udpv6_prot = {
976 name: "UDP",
977 close: udpv6_close,
978 connect: udpv6_connect,
979 disconnect: udp_disconnect,
980 ioctl: udp_ioctl,
981 destroy: inet6_destroy_sock,
982 setsockopt: ipv6_setsockopt,
983 getsockopt: ipv6_getsockopt,
984 sendmsg: udpv6_sendmsg,
985 recvmsg: udpv6_recvmsg,
986 backlog_rcv: udpv6_queue_rcv_skb,
987 hash: udp_v6_hash,
988 unhash: udp_v6_unhash,
989 get_port: udp_v6_get_port,
992 void __init udpv6_init(void)
994 inet6_add_protocol(&udpv6_protocol);