~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/net/ipv6/udp.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  *      UDP over IPv6
  3  *      Linux INET6 implementation 
  4  *
  5  *      Authors:
  6  *      Pedro Roque             <roque@di.fc.ul.pt>     
  7  *
  8  *      Based on linux/ipv4/udp.c
  9  *
 10  *      $Id: udp.c,v 1.59 2000/11/28 13:38:38 davem Exp $
 11  *
 12  *      Fixes:
 13  *      Hideaki YOSHIFUJI       :       sin6_scope_id support
 14  *
 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.
 19  */
 20 
 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>
 35 
 36 #include <net/sock.h>
 37 #include <net/snmp.h>
 38 
 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>
 48 
 49 #include <net/checksum.h>
 50 
 51 struct udp_mib udp_stats_in6[NR_CPUS*2];
 52 
 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.
 55  */
 56 static int udp_v6_get_port(struct sock *sk, unsigned short snum)
 57 {
 58         write_lock_bh(&udp_hash_lock);
 59         if (snum == 0) {
 60                 int best_size_so_far, best, result, i;
 61 
 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;
 70 
 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;
 78                         }
 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:;
 87                 }
 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;
 96                 }
 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);
102 
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;
118                 }
119         }
120 
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);
130         }
131         write_unlock_bh(&udp_hash_lock);
132         return 0;
133 
134 fail:
135         write_unlock_bh(&udp_hash_lock);
136         return 1;
137 }
138 
139 static void udp_v6_hash(struct sock *sk)
140 {
141         BUG();
142 }
143 
144 static void udp_v6_unhash(struct sock *sk)
145 {
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);
155         }
156         write_unlock_bh(&udp_hash_lock);
157 }
158 
159 static struct sock *udp_v6_lookup(struct in6_addr *saddr, u16 sport,
160                                   struct in6_addr *daddr, u16 dport, int dif)
161 {
162         struct sock *sk, *result = NULL;
163         unsigned short hnum = ntohs(dport);
164         int badness = -1;
165 
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++;
176                         }
177                         if(!ipv6_addr_any(&np->rcv_saddr)) {
178                                 if(ipv6_addr_cmp(&np->rcv_saddr, daddr))
179                                         continue;
180                                 score++;
181                         }
182                         if(!ipv6_addr_any(&np->daddr)) {
183                                 if(ipv6_addr_cmp(&np->daddr, saddr))
184                                         continue;
185                                 score++;
186                         }
187                         if(sk->bound_dev_if) {
188                                 if(sk->bound_dev_if != dif)
189                                         continue;
190                                 score++;
191                         }
192                         if(score == 4) {
193                                 result = sk;
194                                 break;
195                         } else if(score > badness) {
196                                 result = sk;
197                                 badness = score;
198                         }
199                 }
200         }
201         if (result)
202                 sock_hold(result);
203         read_unlock(&udp_hash_lock);
204         return result;
205 }
206 
207 /*
208  *
209  */
210 
211 int udpv6_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
212 {
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;
222 
223         if (usin->sin6_family == AF_INET) {
224                 err = udp_connect(sk, uaddr, addr_len);
225                 goto ipv4_connected;
226         }
227 
228         if (addr_len < SIN6_LEN_RFC2133)
229                 return -EINVAL;
230 
231         if (usin->sin6_family != AF_INET6) 
232                 return -EAFNOSUPPORT;
233 
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);
242                 }
243         }
244 
245         addr_type = ipv6_addr_type(&usin->sin6_addr);
246 
247         if (addr_type == IPV6_ADDR_ANY) {
248                 /*
249                  *      connect to self
250                  */
251                 usin->sin6_addr.s6_addr[15] = 0x01;
252         }
253 
254         daddr = &usin->sin6_addr;
255 
256         if (addr_type == IPV6_ADDR_MAPPED) {
257                 struct sockaddr_in sin;
258 
259                 sin.sin_family = AF_INET;
260                 sin.sin_addr.s_addr = daddr->s6_addr32[3];
261                 sin.sin_port = usin->sin6_port;
262 
263                 err = udp_connect(sk, (struct sockaddr*) &sin, sizeof(sin));
264 
265 ipv4_connected:
266                 if (err < 0)
267                         return err;
268                 
269                 ipv6_addr_set(&np->daddr, 0, 0, 
270                               __constant_htonl(0x0000ffff),
271                               sk->daddr);
272 
273                 if(ipv6_addr_any(&np->saddr)) {
274                         ipv6_addr_set(&np->saddr, 0, 0, 
275                                       __constant_htonl(0x0000ffff),
276                                       sk->saddr);
277                 }
278 
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);
283                 }
284                 return 0;
285         }
286 
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;
293                         }
294                         sk->bound_dev_if = usin->sin6_scope_id;
295                 }
296 
297                 /* Connect to link-local address requires an interface */
298                 if (sk->bound_dev_if == 0)
299                         return -EINVAL;
300         }
301 
302         ipv6_addr_copy(&np->daddr, daddr);
303         np->flow_label = fl.fl6_flowlabel;
304 
305         sk->dport = usin->sin6_port;
306 
307         /*
308          *      Check for a route to destination an obtain the
309          *      destination cache for it.
310          */
311 
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;
318 
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;
323                 }
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;
327         }
328 
329         dst = ip6_route_output(sk, &fl);
330 
331         if ((err = dst->error) != 0) {
332                 dst_release(dst);
333                 fl6_sock_release(flowlabel);
334                 return err;
335         }
336 
337         ip6_dst_store(sk, dst, fl.fl6_dst);
338 
339         /* get the source adddress used in the apropriate device */
340 
341         err = ipv6_get_saddr(dst, daddr, &saddr);
342 
343         if (err == 0) {
344                 if(ipv6_addr_any(&np->saddr))
345                         ipv6_addr_copy(&np->saddr, &saddr);
346 
347                 if(ipv6_addr_any(&np->rcv_saddr)) {
348                         ipv6_addr_copy(&np->rcv_saddr, &saddr);
349                         sk->rcv_saddr = LOOPBACK4_IPV6;
350                 }
351                 sk->state = TCP_ESTABLISHED;
352         }
353         fl6_sock_release(flowlabel);
354 
355         return err;
356 }
357 
358 static void udpv6_close(struct sock *sk, long timeout)
359 {
360         inet_sock_release(sk);
361 }
362 
363 /*
364  *      This should be easy, if there is something there we
365  *      return it, otherwise we block.
366  */
367 
368 int udpv6_recvmsg(struct sock *sk, struct msghdr *msg, int len,
369                   int noblock, int flags, int *addr_len)
370 {
371         struct sk_buff *skb;
372         int copied, err;
373 
374         if (addr_len)
375                 *addr_len=sizeof(struct sockaddr_in6);
376   
377         if (flags & MSG_ERRQUEUE)
378                 return ipv6_recv_error(sk, msg, len);
379 
380         skb = skb_recv_datagram(sk, flags, noblock, &err);
381         if (!skb)
382                 goto out;
383 
384         copied = skb->len - sizeof(struct udphdr);
385         if (copied > len) {
386                 copied = len;
387                 msg->msg_flags |= MSG_TRUNC;
388         }
389 
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;
402         }
403         if (err)
404                 goto out_free;
405 
406         sock_recv_timestamp(msg, sk, skb);
407 
408         /* Copy the address. */
409         if (msg->msg_name) {
410                 struct sockaddr_in6 *sin6;
411           
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;
417 
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));
426 
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;
432                         }
433                 }
434         }
435         err = copied;
436 
437 out_free:
438         skb_free_datagram(sk, skb);
439 out:
440         return err;
441 
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;
450                 }
451                 spin_unlock_irq(&sk->receive_queue.lock);
452                 if (clear)
453                         kfree_skb(skb);
454         }
455 
456         /* Error for blocking case is chosen to masquerade
457            as some normal condition.
458          */
459         err = (flags&MSG_DONTWAIT) ? -EAGAIN : -EHOSTUNREACH;
460         UDP6_INC_STATS_USER(UdpInErrors);
461         goto out_free;
462 }
463 
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)
467 {
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;
474 
475         if (buff + sizeof(struct udphdr) > skb->tail)
476                 return;
477 
478         uh = (struct udphdr *) buff;
479 
480         sk = udp_v6_lookup(daddr, uh->dest, saddr, uh->source, dev->ifindex);
481    
482         if (sk == NULL)
483                 return;
484 
485         if (!icmpv6_err_convert(type, code, &err) &&
486             !sk->net_pinfo.af_inet6.recverr)
487                 goto out;
488 
489         if (sk->state!=TCP_ESTABLISHED &&
490             !sk->net_pinfo.af_inet6.recverr)
491                 goto out;
492 
493         if (sk->net_pinfo.af_inet6.recverr)
494                 ipv6_icmp_error(sk, skb, err, uh->dest, ntohl(info), (u8 *)(uh+1));
495 
496         sk->err = err;
497         sk->error_report(sk);
498 out:
499         sock_put(sk);
500 }
501 
502 static inline int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
503 {
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;
511                 }
512                 skb->ip_summed = CHECKSUM_UNNECESSARY;
513         }
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;
520         }
521         IP6_INC_STATS_BH(Ip6InDelivers);
522         UDP6_INC_STATS_BH(UdpInDatagrams);
523         return 0;
524 }
525 
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)
530 {
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;
539                         }
540                         if(!ipv6_addr_any(&np->daddr) &&
541                            ipv6_addr_cmp(&np->daddr, rmt_addr))
542                                 continue;
543 
544                         if (s->bound_dev_if && s->bound_dev_if != dif)
545                                 continue;
546 
547                         if(!ipv6_addr_any(&np->rcv_saddr)) {
548                                 if(ipv6_addr_cmp(&np->rcv_saddr, loc_addr) == 0)
549                                         return s;
550                         }
551                         if(!inet6_mc_check(s, loc_addr))
552                                 continue;
553                         return s;
554                 }
555         }
556         return NULL;
557 }
558 
559 /*
560  * Note: called only from the BH handler context,
561  * so we don't need to lock the hashes.
562  */
563 static void udpv6_mcast_deliver(struct udphdr *uh,
564                                 struct in6_addr *saddr, struct in6_addr *daddr,
565                                 struct sk_buff *skb)
566 {
567         struct sock *sk, *sk2;
568         struct sk_buff *buff;
569         int dif;
570 
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;
577 
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;
586                 }
587                 if (sock_queue_rcv_skb(sk2, buff) >= 0)
588                         buff = NULL;
589         }
590         if (buff)
591                 kfree_skb(buff);
592         if (sock_queue_rcv_skb(sk, skb) < 0) {
593 free_skb:
594                 kfree_skb(skb);
595         }
596         read_unlock(&udp_hash_lock);
597 }
598 
599 int udpv6_rcv(struct sk_buff *skb, unsigned long len)
600 {
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;
607 
608         uh = skb->h.uh;
609         __skb_pull(skb, skb->h.raw - skb->data);
610 
611         ulen = ntohs(uh->len);
612 
613         /* Check for jumbo payload */
614         if (ulen == 0 && skb->nh.ipv6h->payload_len == 0)
615                 ulen = len;
616 
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);
623         }
624 
625         if (uh->check == 0) {
626                 /* IPv6 draft-v2 section 8.1 says that we SHOULD log
627                    this error. Well, it is reasonable.
628                  */
629                 if (net_ratelimit())
630                         printk(KERN_INFO "IPv6: udp checksum is 0\n");
631                 goto discard;
632         }
633 
634         skb_trim(skb, ulen);
635 
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);
642 
643         len = ulen;
644 
645         /* 
646          *      Multicast receive code 
647          */
648         if (ipv6_addr_type(daddr) & IPV6_ADDR_MULTICAST) {
649                 udpv6_mcast_deliver(uh, saddr, daddr, skb);
650                 return 0;
651         }
652 
653         /* Unicast */
654 
655         /* 
656          * check socket cache ... must talk to Alan about his plans
657          * for sock caches... i'll skip this for now.
658          */
659         
660         sk = udp_v6_lookup(saddr, uh->source, daddr, uh->dest, dev->ifindex);
661         
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);
667 
668                 icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, dev);
669 
670                 kfree_skb(skb);
671                 return(0);
672         }
673         
674         /* deliver */
675         
676         udpv6_queue_rcv_skb(sk, skb);
677         sock_put(sk);
678         return(0);
679         
680 discard:
681         UDP6_INC_STATS_BH(UdpInErrors);
682         kfree_skb(skb);
683         return(0);      
684 }
685 
686 /*
687  *      Sending
688  */
689 
690 struct udpv6fakehdr 
691 {
692         struct udphdr   uh;
693         struct iovec    *iov;
694         __u32           wcheck;
695         __u32           pl_len;
696         struct in6_addr *daddr;
697 };
698 
699 /*
700  *      with checksum
701  */
702 
703 static int udpv6_getfrag(const void *data, struct in6_addr *addr,
704                          char *buff, unsigned int offset, unsigned int len)
705 {
706         struct udpv6fakehdr *udh = (struct udpv6fakehdr *) data;
707         char *dst;
708         int final = 0;
709         int clen = len;
710 
711         dst = buff;
712 
713         if (offset) {
714                 offset -= sizeof(struct udphdr);
715         } else {
716                 dst += sizeof(struct udphdr);
717                 final = 1;
718                 clen -= sizeof(struct udphdr);
719         }
720 
721         if (csum_partial_copy_fromiovecend(dst, udh->iov, offset,
722                                            clen, &udh->wcheck))
723                 return -EFAULT;
724 
725         if (final) {
726                 struct in6_addr *daddr;
727                 
728                 udh->wcheck = csum_partial((char *)udh, sizeof(struct udphdr),
729                                            udh->wcheck);
730 
731                 if (udh->daddr) {
732                         daddr = udh->daddr;
733                 } else {
734                         /*
735                          *      use packet destination address
736                          *      this should improve cache locality
737                          */
738                         daddr = addr + 1;
739                 }
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;
745 
746                 memcpy(buff, udh, sizeof(struct udphdr));
747         }
748         return 0;
749 }
750 
751 static int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, int ulen)
752 {
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;
765         
766         int err;
767         
768         /* Rough check on arithmetic overflow,
769            better check is made in ip6_build_xmit
770            */
771         if (ulen < 0 || ulen > INT_MAX - sizeof(struct udphdr))
772                 return -EMSGSIZE;
773         
774         fl.fl6_flowlabel = 0;
775         fl.oif = 0;
776 
777         if (sin6) {
778                 if (sin6->sin6_family == AF_INET)
779                         return udp_sendmsg(sk, msg, ulen);
780 
781                 if (addr_len < SIN6_LEN_RFC2133)
782                         return -EINVAL;
783 
784                 if (sin6->sin6_family && sin6->sin6_family != AF_INET6)
785                         return -EINVAL;
786 
787                 if (sin6->sin6_port == 0)
788                         return -EINVAL;
789 
790                 udh.uh.dest = sin6->sin6_port;
791                 daddr = &sin6->sin6_addr;
792 
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;
800                         }
801                 }
802 
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;
807 
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;
815 
816                 udh.uh.dest = sk->dport;
817                 daddr = &sk->net_pinfo.af_inet6.daddr;
818                 fl.fl6_flowlabel = np->flow_label;
819         }
820 
821         addr_type = ipv6_addr_type(daddr);
822 
823         if (addr_type == IPV6_ADDR_MAPPED) {
824                 struct sockaddr_in sin;
825 
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);
832 
833                 return udp_sendmsg(sk, msg, ulen);
834         }
835 
836         udh.daddr = NULL;
837         if (!fl.oif)
838                 fl.oif = sk->bound_dev_if;
839         fl.fl6_src = NULL;
840 
841         if (msg->msg_controllen) {
842                 opt = &opt_space;
843                 memset(opt, 0, sizeof(struct ipv6_txoptions));
844 
845                 err = datagram_send_ctl(msg, &fl, opt, &hlimit);
846                 if (err < 0) {
847                         fl6_sock_release(flowlabel);
848                         return err;
849                 }
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;
854                 }
855                 if (!(opt->opt_nflen|opt->opt_flen))
856                         opt = NULL;
857         }
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;
864 
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;
871 
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;
878 
879         err = ip6_build_xmit(sk, udpv6_getfrag, &udh, &fl, len, opt, hlimit,
880                              msg->msg_flags);
881 
882         fl6_sock_release(flowlabel);
883 
884         if (err < 0)
885                 return err;
886 
887         UDP6_INC_STATS_USER(UdpOutDatagrams);
888         return ulen;
889 }
890 
891 static struct inet6_protocol udpv6_protocol = 
892 {
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                 */
900 };
901 
902 #define LINE_LEN 190
903 #define LINE_FMT "%-190s\n"
904 
905 static void get_udp6_sock(struct sock *sp, char *tmpbuf, int i)
906 {
907         struct in6_addr *dest, *src;
908         __u16 destp, srcp;
909 
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",
917                 i,
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);
928 }
929 
930 int udp6_get_info(char *buffer, char **start, off_t offset, int length)
931 {
932         int len = 0, num = 0, i;
933         off_t pos = 0;
934         off_t begin;
935         char tmpbuf[LINE_LEN+2];
936 
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;
950 
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;
961                 }
962         }
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;
973 }
974 
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,
990 };
991 
992 void __init udpv6_init(void)
993 {
994         inet6_add_protocol(&udpv6_protocol);
995 }
996 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.