/* * INET An implementation of the TCP/IP protocol suite for the LINUX * operating system. INET is implemented using the BSD Socket * interface as the means of communication with the user level. * * The User Datagram Protocol (UDP). * * Version: $Id: udp.c,v 1.91 2000/11/28 13:38:38 davem Exp $ * * Authors: Ross Biro, <bir7@leland.Stanford.Edu> * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> * Arnt Gulbrandsen, <agulbra@nvg.unit.no> * Alan Cox, <Alan.Cox@linux.org> * * Fixes: * Alan Cox : verify_area() calls * Alan Cox : stopped close while in use off icmp * messages. Not a fix but a botch that * for udp at least is 'valid'. * Alan Cox : Fixed icmp handling properly * Alan Cox : Correct error for oversized datagrams * Alan Cox : Tidied select() semantics. * Alan Cox : udp_err() fixed properly, also now * select and read wake correctly on errors * Alan Cox : udp_send verify_area moved to avoid mem leak * Alan Cox : UDP can count its memory * Alan Cox : send to an unknown connection causes * an ECONNREFUSED off the icmp, but * does NOT close. * Alan Cox : Switched to new sk_buff handlers. No more backlog! * Alan Cox : Using generic datagram code. Even smaller and the PEEK * bug no longer crashes it. * Fred Van Kempen : Net2e support for sk->broadcast. * Alan Cox : Uses skb_free_datagram * Alan Cox : Added get/set sockopt support. * Alan Cox : Broadcasting without option set returns EACCES. * Alan Cox : No wakeup calls. Instead we now use the callbacks. * Alan Cox : Use ip_tos and ip_ttl * Alan Cox : SNMP Mibs * Alan Cox : MSG_DONTROUTE, and 0.0.0.0 support. * Matt Dillon : UDP length checks. * Alan Cox : Smarter af_inet used properly. * Alan Cox : Use new kernel side addressing. * Alan Cox : Incorrect return on truncated datagram receive. * Arnt Gulbrandsen : New udp_send and stuff * Alan Cox : Cache last socket * Alan Cox : Route cache * Jon Peatfield : Minor efficiency fix to sendto(). * Mike Shaver : RFC1122 checks. * Alan Cox : Nonblocking error fix. * Willy Konynenberg : Transparent proxying support. * Mike McLagan : Routing by source * David S. Miller : New socket lookup architecture. * Last socket cache retained as it * does have a high hit rate. * Olaf Kirch : Don't linearise iovec on sendmsg. * Andi Kleen : Some cleanups, cache destination entry * for connect. * Vitaly E. Lavrov : Transparent proxy revived after year coma. * Melvin Smith : Check msg_name not msg_namelen in sendto(), * return ENOTCONN for unconnected sockets (POSIX) * Janos Farkas : don't deliver multi/broadcasts to a different * bound-to-device socket * * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ /* RFC1122 Status: 4.1.3.1 (Ports): SHOULD send ICMP_PORT_UNREACHABLE in response to datagrams to an un-listened port. (OK) 4.1.3.2 (IP Options) MUST pass IP options from IP -> application (OK) MUST allow application to specify IP options (OK) 4.1.3.3 (ICMP Messages) MUST pass ICMP error messages to application (OK -- except when SO_BSDCOMPAT is set) 4.1.3.4 (UDP Checksums) MUST provide facility for checksumming (OK) MAY allow application to control checksumming (OK) MUST default to checksumming on (OK) MUST discard silently datagrams with bad csums (OK, except during debugging) 4.1.3.5 (UDP Multihoming) MUST allow application to specify source address (OK) SHOULD be able to communicate the chosen src addr up to application when application doesn't choose (DOES - use recvmsg cmsgs) 4.1.3.6 (Invalid Addresses) MUST discard invalid source addresses (OK -- done in the new routing code) MUST only send datagrams with one of our addresses (OK) */ #include <asm/system.h> #include <asm/uaccess.h> #include <linux/types.h> #include <linux/fcntl.h> #include <linux/socket.h> #include <linux/sockios.h> #include <linux/in.h> #include <linux/errno.h> #include <linux/timer.h> #include <linux/mm.h> #include <linux/config.h> #include <linux/inet.h> #include <linux/netdevice.h> #include <net/snmp.h> #include <net/ip.h> #include <net/protocol.h> #include <linux/skbuff.h> #include <net/sock.h> #include <net/udp.h> #include <net/icmp.h> #include <net/route.h> #include <net/inet_common.h> #include <net/checksum.h> /* * Snmp MIB for the UDP layer */ struct udp_mib udp_statistics[NR_CPUS*2]; struct sock *udp_hash[UDP_HTABLE_SIZE]; rwlock_t udp_hash_lock = RW_LOCK_UNLOCKED; /* Shared by v4/v6 udp. */ int udp_port_rover; 131 static int udp_v4_get_port(struct sock *sk, unsigned short snum) { 133 write_lock_bh(&udp_hash_lock); 134 if (snum == 0) { int best_size_so_far, best, result, i; if (udp_port_rover > sysctl_local_port_range[1] || 138 udp_port_rover < sysctl_local_port_range[0]) udp_port_rover = sysctl_local_port_range[0]; best_size_so_far = 32767; best = result = udp_port_rover; 142 for (i = 0; i < UDP_HTABLE_SIZE; i++, result++) { struct sock *sk; int size; sk = udp_hash[result & (UDP_HTABLE_SIZE - 1)]; 147 if (!sk) { 148 if (result > sysctl_local_port_range[1]) result = sysctl_local_port_range[0] + ((result - sysctl_local_port_range[0]) & (UDP_HTABLE_SIZE - 1)); 152 goto gotit; } size = 0; 155 do { 156 if (++size >= best_size_so_far) 157 goto next; 158 } while ((sk = sk->next) != NULL); best_size_so_far = size; best = result; next:; } result = best; 164 for(;; result += UDP_HTABLE_SIZE) { 165 if (result > sysctl_local_port_range[1]) result = sysctl_local_port_range[0] + ((result - sysctl_local_port_range[0]) & (UDP_HTABLE_SIZE - 1)); 169 if (!udp_lport_inuse(result)) 170 break; } gotit: udp_port_rover = snum = result; 174 } else { struct sock *sk2; for (sk2 = udp_hash[snum & (UDP_HTABLE_SIZE - 1)]; 178 sk2 != NULL; sk2 = sk2->next) { if (sk2->num == snum && sk2 != sk && sk2->bound_dev_if == sk->bound_dev_if && (!sk2->rcv_saddr || !sk->rcv_saddr || sk2->rcv_saddr == sk->rcv_saddr) && 186 (!sk2->reuse || !sk->reuse)) 187 goto fail; } } sk->num = snum; 191 if (sk->pprev == NULL) { struct sock **skp = &udp_hash[snum & (UDP_HTABLE_SIZE - 1)]; 193 if ((sk->next = *skp) != NULL) (*skp)->pprev = &sk->next; *skp = sk; sk->pprev = skp; sock_prot_inc_use(sk->prot); sock_hold(sk); } 200 write_unlock_bh(&udp_hash_lock); 201 return 0; fail: 204 write_unlock_bh(&udp_hash_lock); 205 return 1; } 208 static void udp_v4_hash(struct sock *sk) { 210 BUG(); } 213 static void udp_v4_unhash(struct sock *sk) { 215 write_lock_bh(&udp_hash_lock); 216 if (sk->pprev) { 217 if (sk->next) sk->next->pprev = sk->pprev; *sk->pprev = sk->next; sk->pprev = NULL; sk->num = 0; sock_prot_dec_use(sk->prot); __sock_put(sk); } 225 write_unlock_bh(&udp_hash_lock); } /* UDP is nearly always wildcards out the wazoo, it makes no sense to try * harder than this. -DaveM */ 231 struct sock *udp_v4_lookup_longway(u32 saddr, u16 sport, u32 daddr, u16 dport, int dif) { struct sock *sk, *result = NULL; unsigned short hnum = ntohs(dport); int badness = -1; 237 for(sk = udp_hash[hnum & (UDP_HTABLE_SIZE - 1)]; sk != NULL; sk = sk->next) { 238 if(sk->num == hnum) { int score = 0; 240 if(sk->rcv_saddr) { 241 if(sk->rcv_saddr != daddr) 242 continue; score++; } 245 if(sk->daddr) { 246 if(sk->daddr != saddr) 247 continue; score++; } 250 if(sk->dport) { 251 if(sk->dport != sport) 252 continue; score++; } 255 if(sk->bound_dev_if) { 256 if(sk->bound_dev_if != dif) 257 continue; score++; } 260 if(score == 4) { result = sk; 262 break; 263 } else if(score > badness) { result = sk; badness = score; } } } 269 return result; } 272 __inline__ struct sock *udp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport, int dif) { struct sock *sk; read_lock(&udp_hash_lock); sk = udp_v4_lookup_longway(saddr, sport, daddr, dport, dif); 278 if (sk) sock_hold(sk); 280 read_unlock(&udp_hash_lock); 281 return sk; } 284 static inline struct sock *udp_v4_mcast_next(struct sock *sk, u16 loc_port, u32 loc_addr, u16 rmt_port, u32 rmt_addr, int dif) { struct sock *s = sk; unsigned short hnum = ntohs(loc_port); 291 for(; s; s = s->next) { if ((s->num != hnum) || (s->daddr && s->daddr!=rmt_addr) || (s->dport != rmt_port && s->dport != 0) || (s->rcv_saddr && s->rcv_saddr != loc_addr) || 296 (s->bound_dev_if && s->bound_dev_if != dif)) 297 continue; 298 break; } 300 return s; } /* * This routine is called by the ICMP module when it gets some * sort of error condition. If err < 0 then the socket should * be closed and the error returned to the user. If err > 0 * it's just the icmp type << 8 | icmp code. * Header points to the ip header of the error packet. We move * on past this. Then (as it used to claim before adjustment) * header points to the first 8 bytes of the udp header. We need * to find the appropriate port. */ 314 void udp_err(struct sk_buff *skb, unsigned char *dp, int len) { struct iphdr *iph = (struct iphdr*)dp; struct udphdr *uh = (struct udphdr*)(dp+(iph->ihl<<2)); int type = skb->h.icmph->type; int code = skb->h.icmph->code; struct sock *sk; int harderr; u32 info; int err; 325 if (len < (iph->ihl<<2)+sizeof(struct udphdr)) { ICMP_INC_STATS_BH(IcmpInErrors); 327 return; } sk = udp_v4_lookup(iph->daddr, uh->dest, iph->saddr, uh->source, skb->dev->ifindex); 331 if (sk == NULL) { ICMP_INC_STATS_BH(IcmpInErrors); 333 return; /* No socket for error */ } err = 0; info = 0; harderr = 0; 340 switch (type) { 341 default: 342 case ICMP_TIME_EXCEEDED: err = EHOSTUNREACH; 344 break; 345 case ICMP_SOURCE_QUENCH: 346 goto out; 347 case ICMP_PARAMETERPROB: err = EPROTO; info = ntohl(skb->h.icmph->un.gateway)>>24; harderr = 1; 351 break; 352 case ICMP_DEST_UNREACH: 353 if (code == ICMP_FRAG_NEEDED) { /* Path MTU discovery */ 354 if (sk->protinfo.af_inet.pmtudisc != IP_PMTUDISC_DONT) { err = EMSGSIZE; info = ntohs(skb->h.icmph->un.frag.mtu); harderr = 1; 358 break; } 360 goto out; } err = EHOSTUNREACH; 363 if (code <= NR_ICMP_UNREACH) { harderr = icmp_err_convert[code].fatal; err = icmp_err_convert[code].errno; } 367 break; } /* * RFC1122: OK. Passes ICMP errors back to application, as per * 4.1.3.3. */ 374 if (!sk->protinfo.af_inet.recverr) { 375 if (!harderr || sk->state != TCP_ESTABLISHED) 376 goto out; 377 } else { ip_icmp_error(sk, skb, err, uh->dest, info, (u8*)(uh+1)); } sk->err = err; sk->error_report(sk); out: sock_put(sk); } 387 static unsigned short udp_check(struct udphdr *uh, int len, unsigned long saddr, unsigned long daddr, unsigned long base) { 389 return(csum_tcpudp_magic(saddr, daddr, len, IPPROTO_UDP, base)); } struct udpfakehdr { struct udphdr uh; u32 saddr; u32 daddr; struct iovec *iov; u32 wcheck; }; /* * Copy and checksum a UDP packet from user space into a buffer. We still have * to do the planning to get ip_build_xmit to spot direct transfer to network * card and provide an additional callback mode for direct user->board I/O * transfers. That one will be fun. */ 408 static int udp_getfrag(const void *p, char * to, unsigned int offset, unsigned int fraglen) { struct udpfakehdr *ufh = (struct udpfakehdr *)p; 411 if (offset==0) { if (csum_partial_copy_fromiovecend(to+sizeof(struct udphdr), ufh->iov, offset, 413 fraglen-sizeof(struct udphdr), &ufh->wcheck)) 414 return -EFAULT; ufh->wcheck = csum_partial((char *)ufh, sizeof(struct udphdr), ufh->wcheck); ufh->uh.check = csum_tcpudp_magic(ufh->saddr, ufh->daddr, ntohs(ufh->uh.len), IPPROTO_UDP, ufh->wcheck); 420 if (ufh->uh.check == 0) ufh->uh.check = -1; memcpy(to, ufh, sizeof(struct udphdr)); 423 return 0; } if (csum_partial_copy_fromiovecend(to, ufh->iov, offset-sizeof(struct udphdr), 426 fraglen, &ufh->wcheck)) 427 return -EFAULT; 428 return 0; } /* * Unchecksummed UDP is sufficiently critical to stuff like ATM video conferencing * that we use two routines for this for speed. Probably we ought to have a * CONFIG_FAST_NET set for >10Mb/second boards to activate this sort of coding. * Timing needed to verify if this is a valid decision. */ 438 static int udp_getfrag_nosum(const void *p, char * to, unsigned int offset, unsigned int fraglen) { struct udpfakehdr *ufh = (struct udpfakehdr *)p; 442 if (offset==0) { memcpy(to, ufh, sizeof(struct udphdr)); return memcpy_fromiovecend(to+sizeof(struct udphdr), ufh->iov, offset, 445 fraglen-sizeof(struct udphdr)); } return memcpy_fromiovecend(to, ufh->iov, offset-sizeof(struct udphdr), 448 fraglen); } 451 int udp_sendmsg(struct sock *sk, struct msghdr *msg, int len) { int ulen = len + sizeof(struct udphdr); struct ipcm_cookie ipc; struct udpfakehdr ufh; struct rtable *rt = NULL; int free = 0; int connected = 0; u32 daddr; u8 tos; int err; /* This check is ONLY to check for arithmetic overflow on integer(!) len. Not more! Real check will be made in ip_build_xmit --ANK BTW socket.c -> af_*.c -> ... make multiple invalid conversions size_t -> int. We MUST repair it f.e. by replacing all of them with size_t and revise all the places sort of len += sizeof(struct iphdr) If len was ULONG_MAX-10 it would be cathastrophe --ANK */ 474 if (len < 0 || len > 0xFFFF) 475 return -EMSGSIZE; /* * Check the flags. */ 481 if (msg->msg_flags&MSG_OOB) /* Mirror BSD error message compatibility */ 482 return -EOPNOTSUPP; /* * Get and verify the address. */ 488 if (msg->msg_name) { struct sockaddr_in * usin = (struct sockaddr_in*)msg->msg_name; 490 if (msg->msg_namelen < sizeof(*usin)) 491 return -EINVAL; 492 if (usin->sin_family != AF_INET) { 493 if (usin->sin_family != AF_UNSPEC) 494 return -EINVAL; } ufh.daddr = usin->sin_addr.s_addr; ufh.uh.dest = usin->sin_port; 499 if (ufh.uh.dest == 0) 500 return -EINVAL; 501 } else { 502 if (sk->state != TCP_ESTABLISHED) 503 return -ENOTCONN; ufh.daddr = sk->daddr; ufh.uh.dest = sk->dport; /* Open fast path for connected socket. Route will not be used, if at least one option is set. */ connected = 1; } ipc.addr = sk->saddr; ufh.uh.source = sk->sport; ipc.opt = NULL; ipc.oif = sk->bound_dev_if; 516 if (msg->msg_controllen) { err = ip_cmsg_send(msg, &ipc); 518 if (err) 519 return err; 520 if (ipc.opt) free = 1; connected = 0; } 524 if (!ipc.opt) ipc.opt = sk->protinfo.af_inet.opt; ufh.saddr = ipc.addr; ipc.addr = daddr = ufh.daddr; 530 if (ipc.opt && ipc.opt->srr) { 531 if (!daddr) 532 return -EINVAL; daddr = ipc.opt->faddr; connected = 0; } tos = RT_TOS(sk->protinfo.af_inet.tos); if (sk->localroute || (msg->msg_flags&MSG_DONTROUTE) || 538 (ipc.opt && ipc.opt->is_strictroute)) { tos |= RTO_ONLINK; connected = 0; } 543 if (MULTICAST(daddr)) { 544 if (!ipc.oif) ipc.oif = sk->protinfo.af_inet.mc_index; 546 if (!ufh.saddr) ufh.saddr = sk->protinfo.af_inet.mc_addr; connected = 0; } 551 if (connected) rt = (struct rtable*)sk_dst_check(sk, 0); 554 if (rt == NULL) { err = ip_route_output(&rt, daddr, ufh.saddr, tos, ipc.oif); 556 if (err) 557 goto out; err = -EACCES; 560 if (rt->rt_flags&RTCF_BROADCAST && !sk->broadcast) 561 goto out; 562 if (connected) sk_dst_set(sk, dst_clone(&rt->u.dst)); } 566 if (msg->msg_flags&MSG_CONFIRM) 567 goto do_confirm; back_from_confirm: ufh.saddr = rt->rt_src; 571 if (!ipc.addr) ufh.daddr = ipc.addr = rt->rt_dst; ufh.uh.len = htons(ulen); ufh.uh.check = 0; ufh.iov = msg->msg_iov; ufh.wcheck = 0; /* RFC1122: OK. Provides the checksumming facility (MUST) as per */ /* 4.1.3.4. It's configurable by the application via setsockopt() */ /* (MAY) and it defaults to on (MUST). */ err = ip_build_xmit(sk, (sk->no_check == UDP_CSUM_NOXMIT ? udp_getfrag_nosum : udp_getfrag), &ufh, ulen, &ipc, rt, msg->msg_flags); out: ip_rt_put(rt); 590 if (free) kfree(ipc.opt); 592 if (!err) { UDP_INC_STATS_USER(UdpOutDatagrams); 594 return len; } 596 return err; do_confirm: dst_confirm(&rt->u.dst); 600 if (!(msg->msg_flags&MSG_PROBE) || len) 601 goto back_from_confirm; err = 0; 603 goto out; } /* * IOCTL requests applicable to the UDP protocol */ 610 int udp_ioctl(struct sock *sk, int cmd, unsigned long arg) { 612 switch(cmd) { 614 case SIOCOUTQ: { int amount = atomic_read(&sk->wmem_alloc); 617 return put_user(amount, (int *)arg); } 620 case SIOCINQ: { struct sk_buff *skb; unsigned long amount; amount = 0; 626 spin_lock_irq(&sk->receive_queue.lock); skb = skb_peek(&sk->receive_queue); 628 if (skb != NULL) { /* * We will only return the amount * of this packet since that is all * that will be read. */ amount = skb->len - sizeof(struct udphdr); } 636 spin_unlock_irq(&sk->receive_queue.lock); 637 return put_user(amount, (int *)arg); } 640 default: 641 return -ENOIOCTLCMD; } 643 return(0); } 646 static __inline__ int __udp_checksum_complete(struct sk_buff *skb) { 648 return (unsigned short)csum_fold(csum_partial(skb->h.raw, skb->len, skb->csum)); } 651 static __inline__ int udp_checksum_complete(struct sk_buff *skb) { return skb->ip_summed != CHECKSUM_UNNECESSARY && 654 __udp_checksum_complete(skb); } /* * This should be easy, if there is something there we * return it, otherwise we block. */ 662 int udp_recvmsg(struct sock *sk, struct msghdr *msg, int len, int noblock, int flags, int *addr_len) { struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name; struct sk_buff *skb; int copied, err; /* * Check any passed addresses */ 672 if (addr_len) *addr_len=sizeof(*sin); 675 if (flags & MSG_ERRQUEUE) 676 return ip_recv_error(sk, msg, len); /* * From here the generic datagram does a lot of the work. Come * the finished NET3, it will do _ALL_ the work! */ skb = skb_recv_datagram(sk, flags, noblock, &err); 684 if (!skb) 685 goto out; copied = skb->len - sizeof(struct udphdr); 688 if (copied > len) { copied = len; msg->msg_flags |= MSG_TRUNC; } 693 if (skb->ip_summed==CHECKSUM_UNNECESSARY) { err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov, copied); 696 } else if (msg->msg_flags&MSG_TRUNC) { 697 if (__udp_checksum_complete(skb)) 698 goto csum_copy_err; err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov, copied); 701 } else { err = copy_and_csum_toiovec(msg->msg_iov, skb, sizeof(struct udphdr)); 704 if (err) 705 goto csum_copy_err; } 708 if (err) 709 goto out_free; sock_recv_timestamp(msg, sk, skb); /* Copy the address. */ 714 if (sin) { sin->sin_family = AF_INET; sin->sin_port = skb->h.uh->source; sin->sin_addr.s_addr = skb->nh.iph->saddr; memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); } 721 if (sk->protinfo.af_inet.cmsg_flags) ip_cmsg_recv(msg, skb); err = copied; out_free: skb_free_datagram(sk, skb); out: 728 return err; csum_copy_err: UDP_INC_STATS_BH(UdpInErrors); /* Clear queue. */ 734 if (flags&MSG_PEEK) { int clear = 0; 736 spin_lock_irq(&sk->receive_queue.lock); 737 if (skb == skb_peek(&sk->receive_queue)) { __skb_unlink(skb, &sk->receive_queue); clear = 1; } 741 spin_unlock_irq(&sk->receive_queue.lock); 742 if (clear) kfree_skb(skb); } skb_free_datagram(sk, skb); 748 return -EAGAIN; } 751 int udp_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) { struct sockaddr_in *usin = (struct sockaddr_in *) uaddr; struct rtable *rt; int err; 758 if (addr_len < sizeof(*usin)) 759 return -EINVAL; 761 if (usin->sin_family != AF_INET) 762 return -EAFNOSUPPORT; sk_dst_reset(sk); err = ip_route_connect(&rt, usin->sin_addr.s_addr, sk->saddr, sk->protinfo.af_inet.tos|sk->localroute, sk->bound_dev_if); 768 if (err) 769 return err; 770 if ((rt->rt_flags&RTCF_BROADCAST) && !sk->broadcast) { ip_rt_put(rt); 772 return -EACCES; } 774 if(!sk->saddr) sk->saddr = rt->rt_src; /* Update source address */ 776 if(!sk->rcv_saddr) sk->rcv_saddr = rt->rt_src; sk->daddr = rt->rt_dst; sk->dport = usin->sin_port; sk->state = TCP_ESTABLISHED; sk_dst_set(sk, &rt->u.dst); 783 return(0); } 786 int udp_disconnect(struct sock *sk, int flags) { /* * 1003.1g - break association. */ sk->state = TCP_CLOSE; sk->daddr = 0; sk->dport = 0; sk->bound_dev_if = 0; 796 if (!(sk->userlocks&SOCK_BINDADDR_LOCK)) { sk->rcv_saddr = 0; sk->saddr = 0; #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) memset(&sk->net_pinfo.af_inet6.saddr, 0, 16); memset(&sk->net_pinfo.af_inet6.rcv_saddr, 0, 16); #endif } 804 if (!(sk->userlocks&SOCK_BINDPORT_LOCK)) { sk->prot->unhash(sk); sk->sport = 0; } sk_dst_reset(sk); 809 return 0; } 812 static void udp_close(struct sock *sk, long timeout) { inet_sock_release(sk); } 817 static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) { /* * Charge it to the socket, dropping if the queue is full. */ #if defined(CONFIG_FILTER) if (sk->filter && skb->ip_summed != CHECKSUM_UNNECESSARY) { if (__udp_checksum_complete(skb)) { UDP_INC_STATS_BH(UdpInErrors); IP_INC_STATS_BH(IpInDiscards); ip_statistics[smp_processor_id()*2].IpInDelivers--; kfree_skb(skb); return -1; } skb->ip_summed = CHECKSUM_UNNECESSARY; } #endif 836 if (sock_queue_rcv_skb(sk,skb)<0) { UDP_INC_STATS_BH(UdpInErrors); IP_INC_STATS_BH(IpInDiscards); ip_statistics[smp_processor_id()*2].IpInDelivers--; kfree_skb(skb); 841 return -1; } UDP_INC_STATS_BH(UdpInDatagrams); 844 return 0; } /* * Multicasts and broadcasts go to each listener. * * Note: called only from the BH handler context, * so we don't need to lock the hashes. */ 853 static int udp_v4_mcast_deliver(struct sk_buff *skb, struct udphdr *uh, u32 saddr, u32 daddr) { struct sock *sk; int dif; read_lock(&udp_hash_lock); sk = udp_hash[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)]; dif = skb->dev->ifindex; sk = udp_v4_mcast_next(sk, uh->dest, daddr, uh->source, saddr, dif); 863 if (sk) { struct sock *sknext = NULL; 866 do { struct sk_buff *skb1 = skb; sknext = udp_v4_mcast_next(sk->next, uh->dest, daddr, uh->source, saddr, dif); 871 if(sknext) skb1 = skb_clone(skb, GFP_ATOMIC); 874 if(skb1) udp_queue_rcv_skb(sk, skb1); sk = sknext; 877 } while(sknext); 878 } else kfree_skb(skb); 880 read_unlock(&udp_hash_lock); 881 return 0; } /* Initialize UDP checksum. If exited with zero value (success), * CHECKSUM_UNNECESSARY means, that no more checks are required. * Otherwise, csum completion requires chacksumming packet body, * including udp header and folding it to skb->csum. */ 889 static int udp_checksum_init(struct sk_buff *skb, struct udphdr *uh, unsigned short ulen, u32 saddr, u32 daddr) { 892 if (uh->check == 0) { skb->ip_summed = CHECKSUM_UNNECESSARY; 894 } else if (skb->ip_summed == CHECKSUM_HW) { 895 if (udp_check(uh, ulen, saddr, daddr, skb->csum)) 896 return -1; skb->ip_summed = CHECKSUM_UNNECESSARY; 898 } else if (skb->ip_summed != CHECKSUM_UNNECESSARY) skb->csum = csum_tcpudp_nofold(saddr, daddr, ulen, IPPROTO_UDP, 0); /* Probably, we should checksum udp header (it should be in cache * in any case) and data in tiny packets (< rx copybreak). */ 903 return 0; } /* * All we need to do is get the socket, and then do a checksum. */ 910 int udp_rcv(struct sk_buff *skb, unsigned short len) { struct sock *sk; struct udphdr *uh; unsigned short ulen; struct rtable *rt = (struct rtable*)skb->dst; u32 saddr = skb->nh.iph->saddr; u32 daddr = skb->nh.iph->daddr; /* * Get the header. */ uh = skb->h.uh; __skb_pull(skb, skb->h.raw - skb->data); IP_INC_STATS_BH(IpInDelivers); /* * Validate the packet and the UDP length. */ ulen = ntohs(uh->len); 934 if (ulen > len || ulen < sizeof(*uh)) { 935 NETDEBUG(printk(KERN_DEBUG "UDP: short packet: %d/%d\n", ulen, len)); UDP_INC_STATS_BH(UdpInErrors); kfree_skb(skb); 938 return(0); } skb_trim(skb, ulen); 942 if (udp_checksum_init(skb, uh, ulen, saddr, daddr) < 0) 943 goto csum_error; 945 if(rt->rt_flags & (RTCF_BROADCAST|RTCF_MULTICAST)) 946 return udp_v4_mcast_deliver(skb, uh, saddr, daddr); sk = udp_v4_lookup(saddr, uh->source, daddr, uh->dest, skb->dev->ifindex); 950 if (sk != NULL) { udp_queue_rcv_skb(sk, skb); sock_put(sk); 953 return 0; } /* No socket. Drop packet silently, if checksum is wrong */ 957 if (udp_checksum_complete(skb)) 958 goto csum_error; UDP_INC_STATS_BH(UdpNoPorts); icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); /* * Hmm. We got an UDP packet to a port to which we * don't wanna listen. Ignore it. */ kfree_skb(skb); 968 return(0); csum_error: /* * RFC1122: OK. Discards the bad packet silently (as far as * the network is concerned, anyway) as per 4.1.3.4 (MUST). */ 975 NETDEBUG(printk(KERN_DEBUG "UDP: bad checksum. From %d.%d.%d.%d:%d to %d.%d.%d.%d:%d ulen %d\n", NIPQUAD(saddr), ntohs(uh->source), NIPQUAD(daddr), ntohs(uh->dest), 980 ulen)); UDP_INC_STATS_BH(UdpInErrors); kfree_skb(skb); 983 return(0); } 986 static void get_udp_sock(struct sock *sp, char *tmpbuf, int i) { unsigned int dest, src; __u16 destp, srcp; dest = sp->daddr; src = sp->rcv_saddr; destp = ntohs(sp->dport); srcp = ntohs(sp->sport); sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X" " %02X %08X:%08X %02X:%08lX %08X %5d %8d %ld %d %p", i, src, srcp, dest, destp, sp->state, atomic_read(&sp->wmem_alloc), atomic_read(&sp->rmem_alloc), 0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp), atomic_read(&sp->refcnt), sp); } 1005 int udp_get_info(char *buffer, char **start, off_t offset, int length) { int len = 0, num = 0, i; off_t pos = 0; off_t begin; char tmpbuf[129]; 1012 if (offset < 128) len += sprintf(buffer, "%-127s\n", " sl local_address rem_address st tx_queue " "rx_queue tr tm->when retrnsmt uid timeout inode"); pos = 128; read_lock(&udp_hash_lock); 1018 for (i = 0; i < UDP_HTABLE_SIZE; i++) { struct sock *sk; 1021 for (sk = udp_hash[i]; sk; sk = sk->next, num++) { 1022 if (sk->family != PF_INET) 1023 continue; pos += 128; 1025 if (pos <= offset) 1026 continue; get_udp_sock(sk, tmpbuf, i); len += sprintf(buffer+len, "%-127s\n", tmpbuf); 1029 if(len >= length) 1030 goto out; } } out: 1034 read_unlock(&udp_hash_lock); begin = len - (pos - offset); *start = buffer + begin; len -= begin; 1038 if(len > length) len = length; 1040 if (len < 0) len = 0; 1042 return len; } struct proto udp_prot = { name: "UDP", close: udp_close, connect: udp_connect, disconnect: udp_disconnect, ioctl: udp_ioctl, setsockopt: ip_setsockopt, getsockopt: ip_getsockopt, sendmsg: udp_sendmsg, recvmsg: udp_recvmsg, backlog_rcv: udp_queue_rcv_skb, hash: udp_v4_hash, unhash: udp_v4_unhash, get_port: udp_v4_get_port, };