2005-04-17 02:20:36 +04:00
/*
* 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.102 2002 / 02 / 01 22 : 01 : 04 davem Exp $
*
2005-05-06 03:16:16 +04:00
* Authors : Ross Biro
2005-04-17 02:20:36 +04:00
* Fred N . van Kempen , < waltje @ uWalt . NL . Mugnet . ORG >
* Arnt Gulbrandsen , < agulbra @ nvg . unit . no >
* Alan Cox , < Alan . Cox @ linux . org >
* Hirokazu Takahashi , < taka @ valinux . co . jp >
*
* 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
2007-02-09 17:24:47 +03:00
* Alan Cox : Tidied select ( ) semantics .
* Alan Cox : udp_err ( ) fixed properly , also now
2005-04-17 02:20:36 +04:00
* 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
2007-02-09 17:24:47 +03:00
* for connect .
2005-04-17 02:20:36 +04:00
* 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
* Hirokazu Takahashi : HW checksumming for outgoing UDP
* datagrams .
* Hirokazu Takahashi : sendfile ( ) on UDP works now .
* Arnaldo C . Melo : convert / proc / net / udp to seq_file
* YOSHIFUJI Hideaki @ USAGI and : Support IPV6_V6ONLY socket option , which
* Alexey Kuznetsov : allow both IPv4 and IPv6 sockets to bind
* a single port at the same time .
* Derek Atkins < derek @ ihtfp . com > : Add Encapulation Support
*
*
* 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 .
*/
2007-02-09 17:24:47 +03:00
2005-04-17 02:20:36 +04:00
# include <asm/system.h>
# include <asm/uaccess.h>
# include <asm/ioctls.h>
# include <linux/types.h>
# include <linux/fcntl.h>
# include <linux/module.h>
# include <linux/socket.h>
# include <linux/sockios.h>
2005-12-27 07:43:12 +03:00
# include <linux/igmp.h>
2005-04-17 02:20:36 +04:00
# include <linux/in.h>
# include <linux/errno.h>
# include <linux/timer.h>
# include <linux/mm.h>
# include <linux/inet.h>
# include <linux/netdevice.h>
2005-08-10 07:08:28 +04:00
# include <net/tcp_states.h>
2005-04-17 02:20:36 +04:00
# include <linux/skbuff.h>
# include <linux/proc_fs.h>
# include <linux/seq_file.h>
# include <net/icmp.h>
# include <net/route.h>
# include <net/checksum.h>
# include <net/xfrm.h>
2006-11-27 22:10:57 +03:00
# include "udp_impl.h"
2005-04-17 02:20:36 +04:00
/*
* Snmp MIB for the UDP layer
*/
2005-08-26 23:05:31 +04:00
DEFINE_SNMP_STAT ( struct udp_mib , udp_statistics ) __read_mostly ;
2005-04-17 02:20:36 +04:00
struct hlist_head udp_hash [ UDP_HTABLE_SIZE ] ;
DEFINE_RWLOCK ( udp_hash_lock ) ;
2006-08-27 07:06:49 +04:00
static int udp_port_rover ;
2005-04-17 02:20:36 +04:00
2007-04-30 11:26:00 +04:00
/*
* Note about this hash function :
* Typical use is probably daddr = 0 , only dport is going to vary hash
*/
2007-05-10 03:42:20 +04:00
static inline unsigned int udp_hash_port ( __u16 port )
2007-04-30 11:26:00 +04:00
{
2007-05-10 03:42:20 +04:00
return port ;
2007-04-30 11:26:00 +04:00
}
static inline int __udp_lib_port_inuse ( unsigned int hash , int port ,
2007-05-10 03:42:20 +04:00
const struct sock * this_sk ,
struct hlist_head udptable [ ] ,
const struct udp_get_port_ops * ops )
2005-04-17 02:20:36 +04:00
{
2006-08-27 07:06:05 +04:00
struct sock * sk ;
2005-04-17 02:20:36 +04:00
struct hlist_node * node ;
2007-04-30 11:26:00 +04:00
struct inet_sock * inet ;
2006-08-27 07:06:05 +04:00
2007-04-30 11:26:00 +04:00
sk_for_each ( sk , node , & udptable [ hash & ( UDP_HTABLE_SIZE - 1 ) ] ) {
if ( sk - > sk_hash ! = hash )
continue ;
inet = inet_sk ( sk ) ;
if ( inet - > num ! = port )
continue ;
2007-05-10 03:42:20 +04:00
if ( this_sk ) {
if ( ops - > saddr_cmp ( sk , this_sk ) )
return 1 ;
} else if ( ops - > saddr_any ( sk ) )
2006-08-27 07:06:05 +04:00
return 1 ;
2007-04-30 11:26:00 +04:00
}
2006-08-27 07:06:05 +04:00
return 0 ;
}
/**
2006-11-27 22:10:57 +03:00
* __udp_lib_get_port - UDP / - Lite port lookup for IPv4 and IPv6
2006-08-27 07:06:05 +04:00
*
* @ sk : socket struct in question
* @ snum : port number to look up
2006-11-27 22:10:57 +03:00
* @ udptable : hash list table , must be of UDP_HTABLE_SIZE
* @ port_rover : pointer to record of last unallocated port
2007-05-10 03:42:20 +04:00
* @ ops : AF - dependent address operations
2006-08-27 07:06:05 +04:00
*/
2006-11-27 22:10:57 +03:00
int __udp_lib_get_port ( struct sock * sk , unsigned short snum ,
struct hlist_head udptable [ ] , int * port_rover ,
2007-05-10 03:42:20 +04:00
const struct udp_get_port_ops * ops )
2006-08-27 07:06:05 +04:00
{
struct hlist_node * node ;
struct hlist_head * head ;
2005-04-17 02:20:36 +04:00
struct sock * sk2 ;
2007-04-30 11:26:00 +04:00
unsigned int hash ;
2006-08-27 07:06:05 +04:00
int error = 1 ;
2005-04-17 02:20:36 +04:00
write_lock_bh ( & udp_hash_lock ) ;
if ( snum = = 0 ) {
int best_size_so_far , best , result , i ;
2006-11-27 22:10:57 +03:00
if ( * port_rover > sysctl_local_port_range [ 1 ] | |
* port_rover < sysctl_local_port_range [ 0 ] )
* port_rover = sysctl_local_port_range [ 0 ] ;
2005-04-17 02:20:36 +04:00
best_size_so_far = 32767 ;
2006-11-27 22:10:57 +03:00
best = result = * port_rover ;
2005-04-17 02:20:36 +04:00
for ( i = 0 ; i < UDP_HTABLE_SIZE ; i + + , result + + ) {
int size ;
2007-05-10 03:42:20 +04:00
hash = ops - > hash_port_and_rcv_saddr ( result , sk ) ;
2007-04-30 11:26:00 +04:00
head = & udptable [ hash & ( UDP_HTABLE_SIZE - 1 ) ] ;
2006-08-27 07:06:05 +04:00
if ( hlist_empty ( head ) ) {
2005-04-17 02:20:36 +04:00
if ( result > sysctl_local_port_range [ 1 ] )
result = sysctl_local_port_range [ 0 ] +
( ( result - sysctl_local_port_range [ 0 ] ) &
( UDP_HTABLE_SIZE - 1 ) ) ;
goto gotit ;
}
size = 0 ;
2006-12-22 22:42:26 +03:00
sk_for_each ( sk2 , node , head ) {
if ( + + size > = best_size_so_far )
goto next ;
}
best_size_so_far = size ;
best = result ;
next :
;
2005-04-17 02:20:36 +04:00
}
result = best ;
2007-03-09 07:41:55 +03:00
for ( i = 0 ; i < ( 1 < < 16 ) / UDP_HTABLE_SIZE ;
i + + , result + = UDP_HTABLE_SIZE ) {
2005-04-17 02:20:36 +04:00
if ( result > sysctl_local_port_range [ 1 ] )
result = sysctl_local_port_range [ 0 ]
+ ( ( result - sysctl_local_port_range [ 0 ] ) &
( UDP_HTABLE_SIZE - 1 ) ) ;
2007-05-10 03:42:20 +04:00
hash = udp_hash_port ( result ) ;
2007-05-01 01:51:58 +04:00
if ( __udp_lib_port_inuse ( hash , result ,
2007-05-10 03:42:20 +04:00
NULL , udptable , ops ) )
2007-05-01 01:51:58 +04:00
continue ;
2007-05-10 03:42:20 +04:00
if ( ops - > saddr_any ( sk ) )
2007-05-01 01:51:58 +04:00
break ;
2007-05-10 03:42:20 +04:00
hash = ops - > hash_port_and_rcv_saddr ( result , sk ) ;
2007-04-30 11:26:00 +04:00
if ( ! __udp_lib_port_inuse ( hash , result ,
2007-05-10 03:42:20 +04:00
sk , udptable , ops ) )
2005-04-17 02:20:36 +04:00
break ;
}
if ( i > = ( 1 < < 16 ) / UDP_HTABLE_SIZE )
goto fail ;
gotit :
2006-11-27 22:10:57 +03:00
* port_rover = snum = result ;
2005-04-17 02:20:36 +04:00
} else {
2007-05-10 03:42:20 +04:00
hash = udp_hash_port ( snum ) ;
2007-04-30 11:26:00 +04:00
head = & udptable [ hash & ( UDP_HTABLE_SIZE - 1 ) ] ;
2006-08-27 07:06:05 +04:00
sk_for_each ( sk2 , node , head )
2007-05-01 01:51:58 +04:00
if ( sk2 - > sk_hash = = hash & &
sk2 ! = sk & &
inet_sk ( sk2 ) - > num = = snum & &
( ! sk2 - > sk_reuse | | ! sk - > sk_reuse ) & &
( ! sk2 - > sk_bound_dev_if | | ! sk - > sk_bound_dev_if | |
sk2 - > sk_bound_dev_if = = sk - > sk_bound_dev_if ) & &
2007-05-10 03:42:20 +04:00
ops - > saddr_cmp ( sk , sk2 ) )
2005-04-17 02:20:36 +04:00
goto fail ;
2007-05-01 01:51:58 +04:00
2007-05-10 03:42:20 +04:00
if ( ! ops - > saddr_any ( sk ) ) {
hash = ops - > hash_port_and_rcv_saddr ( snum , sk ) ;
2007-05-01 01:51:58 +04:00
head = & udptable [ hash & ( UDP_HTABLE_SIZE - 1 ) ] ;
sk_for_each ( sk2 , node , head )
if ( sk2 - > sk_hash = = hash & &
sk2 ! = sk & &
inet_sk ( sk2 ) - > num = = snum & &
( ! sk2 - > sk_reuse | | ! sk - > sk_reuse ) & &
( ! sk2 - > sk_bound_dev_if | |
! sk - > sk_bound_dev_if | |
sk2 - > sk_bound_dev_if = =
sk - > sk_bound_dev_if ) & &
2007-05-10 03:42:20 +04:00
ops - > saddr_cmp ( sk , sk2 ) )
2007-05-01 01:51:58 +04:00
goto fail ;
}
2005-04-17 02:20:36 +04:00
}
2006-08-27 07:06:05 +04:00
inet_sk ( sk ) - > num = snum ;
2007-04-30 11:26:00 +04:00
sk - > sk_hash = hash ;
2005-04-17 02:20:36 +04:00
if ( sk_unhashed ( sk ) ) {
2007-04-30 11:26:00 +04:00
head = & udptable [ hash & ( UDP_HTABLE_SIZE - 1 ) ] ;
2006-08-27 07:06:05 +04:00
sk_add_node ( sk , head ) ;
2005-04-17 02:20:36 +04:00
sock_prot_inc_use ( sk - > sk_prot ) ;
}
2006-08-27 07:06:05 +04:00
error = 0 ;
2005-04-17 02:20:36 +04:00
fail :
write_unlock_bh ( & udp_hash_lock ) ;
2006-08-27 07:06:05 +04:00
return error ;
}
2007-03-09 07:46:41 +03:00
int udp_get_port ( struct sock * sk , unsigned short snum ,
2007-05-10 03:42:20 +04:00
const struct udp_get_port_ops * ops )
2006-11-27 22:10:57 +03:00
{
2007-05-10 03:42:20 +04:00
return __udp_lib_get_port ( sk , snum , udp_hash , & udp_port_rover , ops ) ;
2006-11-27 22:10:57 +03:00
}
2007-05-10 03:42:20 +04:00
static int ipv4_rcv_saddr_equal ( const struct sock * sk1 , const struct sock * sk2 )
2006-08-27 07:06:05 +04:00
{
struct inet_sock * inet1 = inet_sk ( sk1 ) , * inet2 = inet_sk ( sk2 ) ;
return ( ! ipv6_only_sock ( sk2 ) & &
( ! inet1 - > rcv_saddr | | ! inet2 - > rcv_saddr | |
inet1 - > rcv_saddr = = inet2 - > rcv_saddr ) ) ;
}
2007-05-10 03:42:20 +04:00
static int ipv4_rcv_saddr_any ( const struct sock * sk )
{
return ! inet_sk ( sk ) - > rcv_saddr ;
}
static inline unsigned int ipv4_hash_port_and_addr ( __u16 port , __be32 addr )
{
addr ^ = addr > > 16 ;
addr ^ = addr > > 8 ;
return port ^ addr ;
}
static unsigned int ipv4_hash_port_and_rcv_saddr ( __u16 port ,
const struct sock * sk )
{
return ipv4_hash_port_and_addr ( port , inet_sk ( sk ) - > rcv_saddr ) ;
}
const struct udp_get_port_ops udp_ipv4_ops = {
. saddr_cmp = ipv4_rcv_saddr_equal ,
. saddr_any = ipv4_rcv_saddr_any ,
. hash_port_and_rcv_saddr = ipv4_hash_port_and_rcv_saddr ,
} ;
2006-08-27 07:06:05 +04:00
static inline int udp_v4_get_port ( struct sock * sk , unsigned short snum )
{
2007-05-10 03:42:20 +04:00
return udp_get_port ( sk , snum , & udp_ipv4_ops ) ;
2005-04-17 02:20:36 +04:00
}
/* UDP is nearly always wildcards out the wazoo, it makes no sense to try
* harder than this . - DaveM
*/
2006-11-27 22:10:57 +03:00
static struct sock * __udp4_lib_lookup ( __be32 saddr , __be16 sport ,
__be32 daddr , __be16 dport ,
int dif , struct hlist_head udptable [ ] )
2005-04-17 02:20:36 +04:00
{
struct sock * sk , * result = NULL ;
struct hlist_node * node ;
2007-04-30 11:26:00 +04:00
unsigned int hash , hashwild ;
2007-05-01 00:35:29 +04:00
int score , best = - 1 , hport = ntohs ( dport ) ;
2007-04-30 11:26:00 +04:00
2007-05-10 03:42:20 +04:00
hash = ipv4_hash_port_and_addr ( hport , daddr ) ;
hashwild = udp_hash_port ( hport ) ;
2005-04-17 02:20:36 +04:00
2006-11-27 22:10:57 +03:00
read_lock ( & udp_hash_lock ) ;
2007-04-30 11:26:00 +04:00
lookup :
sk_for_each ( sk , node , & udptable [ hash & ( UDP_HTABLE_SIZE - 1 ) ] ) {
2005-04-17 02:20:36 +04:00
struct inet_sock * inet = inet_sk ( sk ) ;
2007-04-30 11:26:00 +04:00
if ( sk - > sk_hash ! = hash | | ipv6_only_sock ( sk ) | |
2007-05-01 00:35:29 +04:00
inet - > num ! = hport )
2007-04-30 11:26:00 +04:00
continue ;
score = ( sk - > sk_family = = PF_INET ? 1 : 0 ) ;
if ( inet - > rcv_saddr ) {
if ( inet - > rcv_saddr ! = daddr )
continue ;
score + = 2 ;
}
if ( inet - > daddr ) {
if ( inet - > daddr ! = saddr )
continue ;
score + = 2 ;
}
if ( inet - > dport ) {
if ( inet - > dport ! = sport )
continue ;
score + = 2 ;
}
if ( sk - > sk_bound_dev_if ) {
if ( sk - > sk_bound_dev_if ! = dif )
continue ;
score + = 2 ;
}
if ( score = = 9 ) {
result = sk ;
goto found ;
} else if ( score > best ) {
result = sk ;
best = score ;
2005-04-17 02:20:36 +04:00
}
}
2007-04-30 11:26:00 +04:00
if ( hash ! = hashwild ) {
hash = hashwild ;
goto lookup ;
}
found :
2006-11-27 22:10:57 +03:00
if ( result )
sock_hold ( result ) ;
2005-04-17 02:20:36 +04:00
read_unlock ( & udp_hash_lock ) ;
2006-11-27 22:10:57 +03:00
return result ;
2005-04-17 02:20:36 +04:00
}
2007-05-01 00:35:29 +04:00
static inline struct sock * udp_v4_mcast_next ( struct sock * sk , unsigned int hnum ,
int hport , __be32 loc_addr ,
__be16 rmt_port , __be32 rmt_addr ,
int dif )
2005-04-17 02:20:36 +04:00
{
struct hlist_node * node ;
struct sock * s = sk ;
sk_for_each_from ( s , node ) {
struct inet_sock * inet = inet_sk ( s ) ;
2007-02-10 02:44:52 +03:00
if ( s - > sk_hash ! = hnum | |
2007-05-01 00:35:29 +04:00
inet - > num ! = hport | |
2005-04-17 02:20:36 +04:00
( inet - > daddr & & inet - > daddr ! = rmt_addr ) | |
( inet - > dport ! = rmt_port & & inet - > dport ) | |
( inet - > rcv_saddr & & inet - > rcv_saddr ! = loc_addr ) | |
ipv6_only_sock ( s ) | |
( s - > sk_bound_dev_if & & s - > sk_bound_dev_if ! = dif ) )
continue ;
if ( ! ip_mc_sf_allow ( s , loc_addr , rmt_addr , dif ) )
continue ;
goto found ;
2007-02-09 17:24:47 +03:00
}
2005-04-17 02:20:36 +04:00
s = NULL ;
found :
2007-02-09 17:24:47 +03:00
return s ;
2005-04-17 02:20:36 +04:00
}
/*
* 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
2007-02-09 17:24:47 +03:00
* it ' s just the icmp type < < 8 | icmp code .
2005-04-17 02:20:36 +04:00
* 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 .
*/
2006-11-27 22:10:57 +03:00
void __udp4_lib_err ( struct sk_buff * skb , u32 info , struct hlist_head udptable [ ] )
2005-04-17 02:20:36 +04:00
{
struct inet_sock * inet ;
struct iphdr * iph = ( struct iphdr * ) skb - > data ;
struct udphdr * uh = ( struct udphdr * ) ( skb - > data + ( iph - > ihl < < 2 ) ) ;
2007-03-13 20:43:18 +03:00
const int type = icmp_hdr ( skb ) - > type ;
const int code = icmp_hdr ( skb ) - > code ;
2005-04-17 02:20:36 +04:00
struct sock * sk ;
int harderr ;
int err ;
2006-11-27 22:10:57 +03:00
sk = __udp4_lib_lookup ( iph - > daddr , uh - > dest , iph - > saddr , uh - > source ,
skb - > dev - > ifindex , udptable ) ;
2005-04-17 02:20:36 +04:00
if ( sk = = NULL ) {
ICMP_INC_STATS_BH ( ICMP_MIB_INERRORS ) ;
2007-02-09 17:24:47 +03:00
return ; /* No socket for error */
2005-04-17 02:20:36 +04:00
}
err = 0 ;
harderr = 0 ;
inet = inet_sk ( sk ) ;
switch ( type ) {
default :
case ICMP_TIME_EXCEEDED :
err = EHOSTUNREACH ;
break ;
case ICMP_SOURCE_QUENCH :
goto out ;
case ICMP_PARAMETERPROB :
err = EPROTO ;
harderr = 1 ;
break ;
case ICMP_DEST_UNREACH :
if ( code = = ICMP_FRAG_NEEDED ) { /* Path MTU discovery */
if ( inet - > pmtudisc ! = IP_PMTUDISC_DONT ) {
err = EMSGSIZE ;
harderr = 1 ;
break ;
}
goto out ;
}
err = EHOSTUNREACH ;
if ( code < = NR_ICMP_UNREACH ) {
harderr = icmp_err_convert [ code ] . fatal ;
err = icmp_err_convert [ code ] . errno ;
}
break ;
}
/*
2007-02-09 17:24:47 +03:00
* RFC1122 : OK . Passes ICMP errors back to application , as per
2005-04-17 02:20:36 +04:00
* 4.1 .3 .3 .
*/
if ( ! inet - > recverr ) {
if ( ! harderr | | sk - > sk_state ! = TCP_ESTABLISHED )
goto out ;
} else {
ip_icmp_error ( sk , skb , err , uh - > dest , info , ( u8 * ) ( uh + 1 ) ) ;
}
sk - > sk_err = err ;
sk - > sk_error_report ( sk ) ;
out :
sock_put ( sk ) ;
}
2007-03-09 07:46:41 +03:00
void udp_err ( struct sk_buff * skb , u32 info )
2006-11-27 22:10:57 +03:00
{
return __udp4_lib_err ( skb , info , udp_hash ) ;
}
2005-04-17 02:20:36 +04:00
/*
* Throw away all pending data and cancel the corking . Socket is locked .
*/
static void udp_flush_pending_frames ( struct sock * sk )
{
struct udp_sock * up = udp_sk ( sk ) ;
if ( up - > pending ) {
up - > len = 0 ;
up - > pending = 0 ;
ip_flush_pending_frames ( sk ) ;
}
}
2006-11-27 22:10:57 +03:00
/**
* udp4_hwcsum_outgoing - handle outgoing HW checksumming
* @ sk : socket we are sending on
* @ skb : sk_buff containing the filled - in UDP header
* ( checksum field must be zeroed out )
*/
static void udp4_hwcsum_outgoing ( struct sock * sk , struct sk_buff * skb ,
__be32 src , __be32 dst , int len )
{
2006-11-15 08:28:24 +03:00
unsigned int offset ;
2007-03-13 20:28:48 +03:00
struct udphdr * uh = udp_hdr ( skb ) ;
2006-11-15 08:28:24 +03:00
__wsum csum = 0 ;
2006-11-27 22:10:57 +03:00
if ( skb_queue_len ( & sk - > sk_write_queue ) = = 1 ) {
/*
* Only one fragment on the socket .
*/
2007-04-09 22:59:07 +04:00
skb - > csum_start = skb_transport_header ( skb ) - skb - > head ;
2006-11-21 05:07:29 +03:00
skb - > csum_offset = offsetof ( struct udphdr , check ) ;
2006-11-27 22:10:57 +03:00
uh - > check = ~ csum_tcpudp_magic ( src , dst , len , IPPROTO_UDP , 0 ) ;
} else {
/*
* HW - checksum won ' t work as there are two or more
* fragments on the socket so that all csums of sk_buffs
* should be together
*/
2007-04-26 04:55:53 +04:00
offset = skb_transport_offset ( skb ) ;
2006-11-27 22:10:57 +03:00
skb - > csum = skb_checksum ( skb , offset , skb - > len - offset , 0 ) ;
skb - > ip_summed = CHECKSUM_NONE ;
skb_queue_walk ( & sk - > sk_write_queue , skb ) {
csum = csum_add ( csum , skb - > csum ) ;
}
uh - > check = csum_tcpudp_magic ( src , dst , len , IPPROTO_UDP , csum ) ;
if ( uh - > check = = 0 )
2006-11-16 13:36:50 +03:00
uh - > check = CSUM_MANGLED_0 ;
2006-11-27 22:10:57 +03:00
}
}
2005-04-17 02:20:36 +04:00
/*
* Push out all pending data as one UDP datagram . Socket is locked .
*/
2006-11-27 20:29:59 +03:00
static int udp_push_pending_frames ( struct sock * sk )
2005-04-17 02:20:36 +04:00
{
2006-11-27 20:29:59 +03:00
struct udp_sock * up = udp_sk ( sk ) ;
2005-04-17 02:20:36 +04:00
struct inet_sock * inet = inet_sk ( sk ) ;
struct flowi * fl = & inet - > cork . fl ;
struct sk_buff * skb ;
struct udphdr * uh ;
int err = 0 ;
2006-11-21 05:06:37 +03:00
__wsum csum = 0 ;
2005-04-17 02:20:36 +04:00
/* Grab the skbuff where UDP header space exists. */
if ( ( skb = skb_peek ( & sk - > sk_write_queue ) ) = = NULL )
goto out ;
/*
* Create a UDP header
*/
2007-03-13 20:28:48 +03:00
uh = udp_hdr ( skb ) ;
2005-04-17 02:20:36 +04:00
uh - > source = fl - > fl_ip_sport ;
uh - > dest = fl - > fl_ip_dport ;
uh - > len = htons ( up - > len ) ;
uh - > check = 0 ;
2006-11-27 22:10:57 +03:00
if ( up - > pcflag ) /* UDP-Lite */
csum = udplite_csum_outgoing ( sk , skb ) ;
else if ( sk - > sk_no_check = = UDP_CSUM_NOXMIT ) { /* UDP csum disabled */
2005-04-17 02:20:36 +04:00
skb - > ip_summed = CHECKSUM_NONE ;
goto send ;
2006-11-27 22:10:57 +03:00
} else if ( skb - > ip_summed = = CHECKSUM_PARTIAL ) { /* UDP hardware csum */
2005-04-17 02:20:36 +04:00
2006-11-27 22:10:57 +03:00
udp4_hwcsum_outgoing ( sk , skb , fl - > fl4_src , fl - > fl4_dst , up - > len ) ;
goto send ;
} else /* `normal' UDP */
csum = udp_csum_outgoing ( sk , skb ) ;
/* add protocol-dependent pseudo-header */
uh - > check = csum_tcpudp_magic ( fl - > fl4_src , fl - > fl4_dst , up - > len ,
sk - > sk_protocol , csum ) ;
if ( uh - > check = = 0 )
2006-11-16 13:36:50 +03:00
uh - > check = CSUM_MANGLED_0 ;
2005-04-17 02:20:36 +04:00
send :
err = ip_push_pending_frames ( sk ) ;
out :
up - > len = 0 ;
up - > pending = 0 ;
return err ;
}
int udp_sendmsg ( struct kiocb * iocb , struct sock * sk , struct msghdr * msg ,
size_t len )
{
struct inet_sock * inet = inet_sk ( sk ) ;
struct udp_sock * up = udp_sk ( sk ) ;
int ulen = len ;
struct ipcm_cookie ipc ;
struct rtable * rt = NULL ;
int free = 0 ;
int connected = 0 ;
2006-09-28 05:28:07 +04:00
__be32 daddr , faddr , saddr ;
2006-09-28 05:37:41 +04:00
__be16 dport ;
2005-04-17 02:20:36 +04:00
u8 tos ;
2006-11-27 22:10:57 +03:00
int err , is_udplite = up - > pcflag ;
2005-04-17 02:20:36 +04:00
int corkreq = up - > corkflag | | msg - > msg_flags & MSG_MORE ;
2006-11-27 22:10:57 +03:00
int ( * getfrag ) ( void * , char * , int , int , int , struct sk_buff * ) ;
2005-04-17 02:20:36 +04:00
if ( len > 0xFFFF )
return - EMSGSIZE ;
2007-02-09 17:24:47 +03:00
/*
2005-04-17 02:20:36 +04:00
* Check the flags .
*/
if ( msg - > msg_flags & MSG_OOB ) /* Mirror BSD error message compatibility */
return - EOPNOTSUPP ;
ipc . opt = NULL ;
if ( up - > pending ) {
/*
* There are pending frames .
2007-02-09 17:24:47 +03:00
* The socket lock must be held while it ' s corked .
2005-04-17 02:20:36 +04:00
*/
lock_sock ( sk ) ;
if ( likely ( up - > pending ) ) {
if ( unlikely ( up - > pending ! = AF_INET ) ) {
release_sock ( sk ) ;
return - EINVAL ;
}
2007-02-09 17:24:47 +03:00
goto do_append_data ;
2005-04-17 02:20:36 +04:00
}
release_sock ( sk ) ;
}
ulen + = sizeof ( struct udphdr ) ;
/*
2007-02-09 17:24:47 +03:00
* Get and verify the address .
2005-04-17 02:20:36 +04:00
*/
if ( msg - > msg_name ) {
struct sockaddr_in * usin = ( struct sockaddr_in * ) msg - > msg_name ;
if ( msg - > msg_namelen < sizeof ( * usin ) )
return - EINVAL ;
if ( usin - > sin_family ! = AF_INET ) {
if ( usin - > sin_family ! = AF_UNSPEC )
return - EAFNOSUPPORT ;
}
daddr = usin - > sin_addr . s_addr ;
dport = usin - > sin_port ;
if ( dport = = 0 )
return - EINVAL ;
} else {
if ( sk - > sk_state ! = TCP_ESTABLISHED )
return - EDESTADDRREQ ;
daddr = inet - > daddr ;
dport = inet - > dport ;
/* Open fast path for connected socket.
Route will not be used , if at least one option is set .
*/
connected = 1 ;
2007-02-09 17:24:47 +03:00
}
2005-04-17 02:20:36 +04:00
ipc . addr = inet - > saddr ;
ipc . oif = sk - > sk_bound_dev_if ;
if ( msg - > msg_controllen ) {
err = ip_cmsg_send ( msg , & ipc ) ;
if ( err )
return err ;
if ( ipc . opt )
free = 1 ;
connected = 0 ;
}
if ( ! ipc . opt )
ipc . opt = inet - > opt ;
saddr = ipc . addr ;
ipc . addr = faddr = daddr ;
if ( ipc . opt & & ipc . opt - > srr ) {
if ( ! daddr )
return - EINVAL ;
faddr = ipc . opt - > faddr ;
connected = 0 ;
}
tos = RT_TOS ( inet - > tos ) ;
if ( sock_flag ( sk , SOCK_LOCALROUTE ) | |
2007-02-09 17:24:47 +03:00
( msg - > msg_flags & MSG_DONTROUTE ) | |
2005-04-17 02:20:36 +04:00
( ipc . opt & & ipc . opt - > is_strictroute ) ) {
tos | = RTO_ONLINK ;
connected = 0 ;
}
if ( MULTICAST ( daddr ) ) {
if ( ! ipc . oif )
ipc . oif = inet - > mc_index ;
if ( ! saddr )
saddr = inet - > mc_addr ;
connected = 0 ;
}
if ( connected )
rt = ( struct rtable * ) sk_dst_check ( sk , 0 ) ;
if ( rt = = NULL ) {
struct flowi fl = { . oif = ipc . oif ,
. nl_u = { . ip4_u =
{ . daddr = faddr ,
. saddr = saddr ,
. tos = tos } } ,
2006-11-27 22:10:57 +03:00
. proto = sk - > sk_protocol ,
2005-04-17 02:20:36 +04:00
. uli_u = { . ports =
{ . sport = inet - > sport ,
. dport = dport } } } ;
2006-08-05 10:12:42 +04:00
security_sk_classify_flow ( sk , & fl ) ;
2007-02-08 13:09:21 +03:00
err = ip_route_output_flow ( & rt , & fl , sk , 1 ) ;
2005-04-17 02:20:36 +04:00
if ( err )
goto out ;
err = - EACCES ;
if ( ( rt - > rt_flags & RTCF_BROADCAST ) & &
! sock_flag ( sk , SOCK_BROADCAST ) )
goto out ;
if ( connected )
sk_dst_set ( sk , dst_clone ( & rt - > u . dst ) ) ;
}
if ( msg - > msg_flags & MSG_CONFIRM )
goto do_confirm ;
back_from_confirm :
saddr = rt - > rt_src ;
if ( ! ipc . addr )
daddr = ipc . addr = rt - > rt_dst ;
lock_sock ( sk ) ;
if ( unlikely ( up - > pending ) ) {
/* The socket is already corked while preparing it. */
/* ... which is an evident application bug. --ANK */
release_sock ( sk ) ;
2005-08-10 07:50:53 +04:00
LIMIT_NETDEBUG ( KERN_DEBUG " udp cork app bug 2 \n " ) ;
2005-04-17 02:20:36 +04:00
err = - EINVAL ;
goto out ;
}
/*
* Now cork the socket to pend data .
*/
inet - > cork . fl . fl4_dst = daddr ;
inet - > cork . fl . fl_ip_dport = dport ;
inet - > cork . fl . fl4_src = saddr ;
inet - > cork . fl . fl_ip_sport = inet - > sport ;
up - > pending = AF_INET ;
do_append_data :
up - > len + = ulen ;
2006-11-27 22:10:57 +03:00
getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag ;
err = ip_append_data ( sk , getfrag , msg - > msg_iov , ulen ,
sizeof ( struct udphdr ) , & ipc , rt ,
2005-04-17 02:20:36 +04:00
corkreq ? msg - > msg_flags | MSG_MORE : msg - > msg_flags ) ;
if ( err )
udp_flush_pending_frames ( sk ) ;
else if ( ! corkreq )
2006-11-27 20:29:59 +03:00
err = udp_push_pending_frames ( sk ) ;
2006-10-04 01:35:49 +04:00
else if ( unlikely ( skb_queue_empty ( & sk - > sk_write_queue ) ) )
up - > pending = 0 ;
2005-04-17 02:20:36 +04:00
release_sock ( sk ) ;
out :
ip_rt_put ( rt ) ;
if ( free )
kfree ( ipc . opt ) ;
if ( ! err ) {
2006-11-27 22:10:57 +03:00
UDP_INC_STATS_USER ( UDP_MIB_OUTDATAGRAMS , is_udplite ) ;
2005-04-17 02:20:36 +04:00
return len ;
}
2006-08-15 10:57:10 +04:00
/*
* ENOBUFS = no kernel mem , SOCK_NOSPACE = no sndbuf space . Reporting
* ENOBUFS might not be good ( it ' s not tunable per se ) , but otherwise
* we don ' t have a good statistic ( IpOutDiscards but it can be too many
* things ) . We could add another new stat but at least for now that
* seems like overkill .
*/
if ( err = = - ENOBUFS | | test_bit ( SOCK_NOSPACE , & sk - > sk_socket - > flags ) ) {
2006-11-27 22:10:57 +03:00
UDP_INC_STATS_USER ( UDP_MIB_SNDBUFERRORS , is_udplite ) ;
2006-08-15 10:57:10 +04:00
}
2005-04-17 02:20:36 +04:00
return err ;
do_confirm :
dst_confirm ( & rt - > u . dst ) ;
if ( ! ( msg - > msg_flags & MSG_PROBE ) | | len )
goto back_from_confirm ;
err = 0 ;
goto out ;
}
2006-11-27 22:10:57 +03:00
int udp_sendpage ( struct sock * sk , struct page * page , int offset ,
size_t size , int flags )
2005-04-17 02:20:36 +04:00
{
struct udp_sock * up = udp_sk ( sk ) ;
int ret ;
if ( ! up - > pending ) {
struct msghdr msg = { . msg_flags = flags | MSG_MORE } ;
/* Call udp_sendmsg to specify destination address which
* sendpage interface can ' t pass .
* This will succeed only when the socket is connected .
*/
ret = udp_sendmsg ( NULL , sk , & msg , 0 ) ;
if ( ret < 0 )
return ret ;
}
lock_sock ( sk ) ;
if ( unlikely ( ! up - > pending ) ) {
release_sock ( sk ) ;
2005-08-10 07:50:53 +04:00
LIMIT_NETDEBUG ( KERN_DEBUG " udp cork app bug 3 \n " ) ;
2005-04-17 02:20:36 +04:00
return - EINVAL ;
}
ret = ip_append_page ( sk , page , offset , size , flags ) ;
if ( ret = = - EOPNOTSUPP ) {
release_sock ( sk ) ;
return sock_no_sendpage ( sk - > sk_socket , page , offset ,
size , flags ) ;
}
if ( ret < 0 ) {
udp_flush_pending_frames ( sk ) ;
goto out ;
}
up - > len + = size ;
if ( ! ( up - > corkflag | | ( flags & MSG_MORE ) ) )
2006-11-27 20:29:59 +03:00
ret = udp_push_pending_frames ( sk ) ;
2005-04-17 02:20:36 +04:00
if ( ! ret )
ret = size ;
out :
release_sock ( sk ) ;
return ret ;
}
/*
* IOCTL requests applicable to the UDP protocol
*/
2007-02-09 17:24:47 +03:00
2005-04-17 02:20:36 +04:00
int udp_ioctl ( struct sock * sk , int cmd , unsigned long arg )
{
2007-03-09 07:41:55 +03:00
switch ( cmd ) {
case SIOCOUTQ :
2005-04-17 02:20:36 +04:00
{
2007-03-09 07:41:55 +03:00
int amount = atomic_read ( & sk - > sk_wmem_alloc ) ;
return put_user ( amount , ( int __user * ) arg ) ;
}
2005-04-17 02:20:36 +04:00
2007-03-09 07:41:55 +03:00
case SIOCINQ :
{
struct sk_buff * skb ;
unsigned long amount ;
amount = 0 ;
spin_lock_bh ( & sk - > sk_receive_queue . lock ) ;
skb = skb_peek ( & sk - > sk_receive_queue ) ;
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 ) ;
2005-04-17 02:20:36 +04:00
}
2007-03-09 07:41:55 +03:00
spin_unlock_bh ( & sk - > sk_receive_queue . lock ) ;
return put_user ( amount , ( int __user * ) arg ) ;
}
2005-04-17 02:20:36 +04:00
2007-03-09 07:41:55 +03:00
default :
return - ENOIOCTLCMD ;
2005-04-17 02:20:36 +04:00
}
2007-03-09 07:41:55 +03:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
/*
* This should be easy , if there is something there we
* return it , otherwise we block .
*/
2006-11-27 22:10:57 +03:00
int udp_recvmsg ( struct kiocb * iocb , struct sock * sk , struct msghdr * msg ,
2007-02-09 17:24:47 +03:00
size_t len , int noblock , int flags , int * addr_len )
2005-04-17 02:20:36 +04:00
{
struct inet_sock * inet = inet_sk ( sk ) ;
2007-02-09 17:24:47 +03:00
struct sockaddr_in * sin = ( struct sockaddr_in * ) msg - > msg_name ;
struct sk_buff * skb ;
2007-03-26 07:10:56 +04:00
unsigned int ulen , copied ;
int err ;
int is_udplite = IS_UDPLITE ( sk ) ;
2005-04-17 02:20:36 +04:00
/*
* Check any passed addresses
*/
if ( addr_len )
* addr_len = sizeof ( * sin ) ;
if ( flags & MSG_ERRQUEUE )
return ip_recv_error ( sk , msg , len ) ;
try_again :
skb = skb_recv_datagram ( sk , flags , noblock , & err ) ;
if ( ! skb )
goto out ;
2007-02-09 17:24:47 +03:00
2007-03-26 07:10:56 +04:00
ulen = skb - > len - sizeof ( struct udphdr ) ;
copied = len ;
if ( copied > ulen )
copied = ulen ;
else if ( copied < ulen )
2005-04-17 02:20:36 +04:00
msg - > msg_flags | = MSG_TRUNC ;
2006-11-27 22:10:57 +03:00
/*
2007-03-26 07:10:56 +04:00
* If checksum is needed at all , try to do it while copying the
* data . If the data is truncated , or if we only want a partial
* coverage checksum ( UDP - Lite ) , do it before the copy .
2006-11-27 22:10:57 +03:00
*/
2007-03-26 07:10:56 +04:00
if ( copied < ulen | | UDP_SKB_CB ( skb ) - > partial_cov ) {
if ( udp_lib_checksum_complete ( skb ) )
2005-04-17 02:20:36 +04:00
goto csum_copy_err ;
2006-11-27 22:10:57 +03:00
}
2007-04-09 22:59:39 +04:00
if ( skb_csum_unnecessary ( skb ) )
2006-11-27 22:10:57 +03:00
err = skb_copy_datagram_iovec ( skb , sizeof ( struct udphdr ) ,
msg - > msg_iov , copied ) ;
else {
2005-04-17 02:20:36 +04:00
err = skb_copy_and_csum_datagram_iovec ( skb , sizeof ( struct udphdr ) , msg - > msg_iov ) ;
if ( err = = - EINVAL )
goto csum_copy_err ;
}
if ( err )
goto out_free ;
sock_recv_timestamp ( msg , sk , skb ) ;
/* Copy the address. */
if ( sin )
{
sin - > sin_family = AF_INET ;
2007-03-13 20:28:48 +03:00
sin - > sin_port = udp_hdr ( skb ) - > source ;
2007-04-21 09:47:35 +04:00
sin - > sin_addr . s_addr = ip_hdr ( skb ) - > saddr ;
2005-04-17 02:20:36 +04:00
memset ( sin - > sin_zero , 0 , sizeof ( sin - > sin_zero ) ) ;
2007-02-09 17:24:47 +03:00
}
2005-04-17 02:20:36 +04:00
if ( inet - > cmsg_flags )
ip_cmsg_recv ( msg , skb ) ;
err = copied ;
if ( flags & MSG_TRUNC )
2007-03-26 07:10:56 +04:00
err = ulen ;
2007-02-09 17:24:47 +03:00
2005-04-17 02:20:36 +04:00
out_free :
2007-02-09 17:24:47 +03:00
skb_free_datagram ( sk , skb ) ;
2005-04-17 02:20:36 +04:00
out :
2007-02-09 17:24:47 +03:00
return err ;
2005-04-17 02:20:36 +04:00
csum_copy_err :
2006-11-27 22:10:57 +03:00
UDP_INC_STATS_BH ( UDP_MIB_INERRORS , is_udplite ) ;
2005-04-17 02:20:36 +04:00
2005-12-14 10:16:37 +03:00
skb_kill_datagram ( sk , skb , flags ) ;
2005-04-17 02:20:36 +04:00
if ( noblock )
2007-02-09 17:24:47 +03:00
return - EAGAIN ;
2005-04-17 02:20:36 +04:00
goto try_again ;
}
int udp_disconnect ( struct sock * sk , int flags )
{
struct inet_sock * inet = inet_sk ( sk ) ;
/*
* 1003.1 g - break association .
*/
2007-02-09 17:24:47 +03:00
2005-04-17 02:20:36 +04:00
sk - > sk_state = TCP_CLOSE ;
inet - > daddr = 0 ;
inet - > dport = 0 ;
sk - > sk_bound_dev_if = 0 ;
if ( ! ( sk - > sk_userlocks & SOCK_BINDADDR_LOCK ) )
inet_reset_saddr ( sk ) ;
if ( ! ( sk - > sk_userlocks & SOCK_BINDPORT_LOCK ) ) {
sk - > sk_prot - > unhash ( sk ) ;
inet - > sport = 0 ;
}
sk_dst_reset ( sk ) ;
return 0 ;
}
/* return:
2007-05-09 10:57:56 +04:00
* 1 if the UDP system should process it
2005-04-17 02:20:36 +04:00
* 0 if we should drop this packet
* - 1 if it should get processed by xfrm4_rcv_encap
*/
static int udp_encap_rcv ( struct sock * sk , struct sk_buff * skb )
{
# ifndef CONFIG_XFRM
2007-02-09 17:24:47 +03:00
return 1 ;
2005-04-17 02:20:36 +04:00
# else
struct udp_sock * up = udp_sk ( sk ) ;
2007-02-09 17:24:47 +03:00
struct udphdr * uh ;
2005-04-17 02:20:36 +04:00
struct iphdr * iph ;
int iphlen , len ;
2007-02-09 17:24:47 +03:00
2006-11-23 07:11:42 +03:00
__u8 * udpdata ;
__be32 * udpdata32 ;
2005-04-17 02:20:36 +04:00
__u16 encap_type = up - > encap_type ;
/* if we're overly short, let UDP handle it */
2006-11-23 07:11:42 +03:00
len = skb - > len - sizeof ( struct udphdr ) ;
if ( len < = 0 )
2005-04-17 02:20:36 +04:00
return 1 ;
/* if this is not encapsulated socket, then just return now */
if ( ! encap_type )
return 1 ;
2006-11-23 07:11:42 +03:00
/* If this is a paged skb, make sure we pull up
* whatever data we need to look at . */
if ( ! pskb_may_pull ( skb , sizeof ( struct udphdr ) + min ( len , 8 ) ) )
return 1 ;
/* Now we can get the pointers */
2007-03-13 20:28:48 +03:00
uh = udp_hdr ( skb ) ;
2006-11-23 07:11:42 +03:00
udpdata = ( __u8 * ) uh + sizeof ( struct udphdr ) ;
udpdata32 = ( __be32 * ) udpdata ;
2005-04-17 02:20:36 +04:00
switch ( encap_type ) {
default :
case UDP_ENCAP_ESPINUDP :
/* Check if this is a keepalive packet. If so, eat it. */
if ( len = = 1 & & udpdata [ 0 ] = = 0xff ) {
return 0 ;
2007-03-09 07:41:55 +03:00
} else if ( len > sizeof ( struct ip_esp_hdr ) & & udpdata32 [ 0 ] ! = 0 ) {
2005-04-17 02:20:36 +04:00
/* ESP Packet without Non-ESP header */
len = sizeof ( struct udphdr ) ;
} else
/* Must be an IKE packet.. pass it through */
return 1 ;
break ;
case UDP_ENCAP_ESPINUDP_NON_IKE :
/* Check if this is a keepalive packet. If so, eat it. */
if ( len = = 1 & & udpdata [ 0 ] = = 0xff ) {
return 0 ;
} else if ( len > 2 * sizeof ( u32 ) + sizeof ( struct ip_esp_hdr ) & &
udpdata32 [ 0 ] = = 0 & & udpdata32 [ 1 ] = = 0 ) {
2007-02-09 17:24:47 +03:00
2005-04-17 02:20:36 +04:00
/* ESP Packet with Non-IKE marker */
len = sizeof ( struct udphdr ) + 2 * sizeof ( u32 ) ;
} else
/* Must be an IKE packet.. pass it through */
return 1 ;
break ;
}
/* At this point we are sure that this is an ESPinUDP packet,
* so we need to remove ' len ' bytes from the packet ( the UDP
* header and optional ESP marker bytes ) and then modify the
* protocol to ESP , and then call into the transform receiver .
*/
2005-04-20 09:48:59 +04:00
if ( skb_cloned ( skb ) & & pskb_expand_head ( skb , 0 , 0 , GFP_ATOMIC ) )
return 0 ;
2005-04-17 02:20:36 +04:00
/* Now we can update and verify the packet length... */
2007-04-21 09:47:35 +04:00
iph = ip_hdr ( skb ) ;
2005-04-17 02:20:36 +04:00
iphlen = iph - > ihl < < 2 ;
iph - > tot_len = htons ( ntohs ( iph - > tot_len ) - len ) ;
if ( skb - > len < iphlen + len ) {
/* packet is too small!?! */
return 0 ;
}
/* pull the data buffer up to the ESP header and set the
* transport header to point to ESP . Keep UDP on the stack
* for later .
*/
2007-03-13 19:06:52 +03:00
__skb_pull ( skb , len ) ;
skb_reset_transport_header ( skb ) ;
2005-04-17 02:20:36 +04:00
/* modify the protocol (it's ESP!) */
iph - > protocol = IPPROTO_ESP ;
/* and let the caller know to send this into the ESP processor... */
return - 1 ;
# endif
}
/* returns:
* - 1 : error
* 0 : success
* > 0 : " udp encap " protocol resubmission
*
* Note that in the success and error cases , the skb is assumed to
* have either been requeued or freed .
*/
2006-11-27 22:10:57 +03:00
int udp_queue_rcv_skb ( struct sock * sk , struct sk_buff * skb )
2005-04-17 02:20:36 +04:00
{
struct udp_sock * up = udp_sk ( sk ) ;
2006-08-15 10:57:10 +04:00
int rc ;
2005-04-17 02:20:36 +04:00
/*
* Charge it to the socket , dropping if the queue is full .
*/
2006-11-27 22:10:57 +03:00
if ( ! xfrm4_policy_check ( sk , XFRM_POLICY_IN , skb ) )
goto drop ;
2006-01-07 10:06:10 +03:00
nf_reset ( skb ) ;
2005-04-17 02:20:36 +04:00
if ( up - > encap_type ) {
/*
* This is an encapsulation socket , so let ' s see if this is
* an encapsulated packet .
* If it ' s a keepalive packet , then just eat it .
* If it ' s an encapsulateed packet , then pass it to the
* IPsec xfrm input and return the response
* appropriately . Otherwise , just fall through and
* pass this up the UDP socket .
*/
int ret ;
ret = udp_encap_rcv ( sk , skb ) ;
if ( ret = = 0 ) {
/* Eat the packet .. */
kfree_skb ( skb ) ;
return 0 ;
}
if ( ret < 0 ) {
/* process the ESP packet */
ret = xfrm4_rcv_encap ( skb , up - > encap_type ) ;
2006-11-27 22:10:57 +03:00
UDP_INC_STATS_BH ( UDP_MIB_INDATAGRAMS , up - > pcflag ) ;
2005-04-17 02:20:36 +04:00
return - ret ;
}
/* FALLTHROUGH -- it's a UDP Packet */
}
2006-11-27 22:10:57 +03:00
/*
* UDP - Lite specific tests , ignored on UDP sockets
*/
if ( ( up - > pcflag & UDPLITE_RECV_CC ) & & UDP_SKB_CB ( skb ) - > partial_cov ) {
/*
* MIB statistics other than incrementing the error count are
* disabled for the following two types of errors : these depend
* on the application settings , not on the functioning of the
* protocol stack as such .
*
* RFC 3828 here recommends ( sec 3.3 ) : " There should also be a
* way . . . to . . . at least let the receiving application block
* delivery of packets with coverage values less than a value
* provided by the application . "
*/
if ( up - > pcrlen = = 0 ) { /* full coverage was set */
LIMIT_NETDEBUG ( KERN_WARNING " UDPLITE: partial coverage "
" %d while full coverage %d requested \n " ,
UDP_SKB_CB ( skb ) - > cscov , skb - > len ) ;
goto drop ;
2005-04-17 02:20:36 +04:00
}
2006-11-27 22:10:57 +03:00
/* The next case involves violating the min. coverage requested
* by the receiver . This is subtle : if receiver wants x and x is
* greater than the buffersize / MTU then receiver will complain
* that it wants x while sender emits packets of smaller size y .
* Therefore the above . . . ( ) - > partial_cov statement is essential .
*/
if ( UDP_SKB_CB ( skb ) - > cscov < up - > pcrlen ) {
LIMIT_NETDEBUG ( KERN_WARNING
" UDPLITE: coverage %d too small, need min %d \n " ,
UDP_SKB_CB ( skb ) - > cscov , up - > pcrlen ) ;
goto drop ;
}
}
2007-03-26 07:10:56 +04:00
if ( sk - > sk_filter ) {
if ( udp_lib_checksum_complete ( skb ) )
2006-11-27 22:10:57 +03:00
goto drop ;
2005-04-17 02:20:36 +04:00
}
2006-08-15 10:57:10 +04:00
if ( ( rc = sock_queue_rcv_skb ( sk , skb ) ) < 0 ) {
/* Note that an ENOMEM error is charged twice */
if ( rc = = - ENOMEM )
2006-11-27 22:10:57 +03:00
UDP_INC_STATS_BH ( UDP_MIB_RCVBUFERRORS , up - > pcflag ) ;
goto drop ;
2005-04-17 02:20:36 +04:00
}
2006-11-27 22:10:57 +03:00
UDP_INC_STATS_BH ( UDP_MIB_INDATAGRAMS , up - > pcflag ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
2006-11-27 22:10:57 +03:00
drop :
UDP_INC_STATS_BH ( UDP_MIB_INERRORS , up - > pcflag ) ;
kfree_skb ( skb ) ;
return - 1 ;
2005-04-17 02:20:36 +04:00
}
/*
* Multicasts and broadcasts go to each listener .
*
* Note : called only from the BH handler context ,
* so we don ' t need to lock the hashes .
*/
2006-11-27 22:10:57 +03:00
static int __udp4_lib_mcast_deliver ( struct sk_buff * skb ,
struct udphdr * uh ,
__be32 saddr , __be32 daddr ,
struct hlist_head udptable [ ] )
2005-04-17 02:20:36 +04:00
{
2007-04-30 11:26:00 +04:00
struct sock * sk , * skw , * sknext ;
2005-04-17 02:20:36 +04:00
int dif ;
2007-05-01 00:35:29 +04:00
int hport = ntohs ( uh - > dest ) ;
2007-05-10 03:42:20 +04:00
unsigned int hash = ipv4_hash_port_and_addr ( hport , daddr ) ;
unsigned int hashwild = udp_hash_port ( hport ) ;
2005-04-17 02:20:36 +04:00
dif = skb - > dev - > ifindex ;
2007-04-30 11:26:00 +04:00
read_lock ( & udp_hash_lock ) ;
sk = sk_head ( & udptable [ hash & ( UDP_HTABLE_SIZE - 1 ) ] ) ;
skw = sk_head ( & udptable [ hashwild & ( UDP_HTABLE_SIZE - 1 ) ] ) ;
2007-05-01 00:35:29 +04:00
sk = udp_v4_mcast_next ( sk , hash , hport , daddr , uh - > source , saddr , dif ) ;
2007-04-30 11:26:00 +04:00
if ( ! sk ) {
hash = hashwild ;
2007-05-01 00:35:29 +04:00
sk = udp_v4_mcast_next ( skw , hash , hport , daddr , uh - > source ,
2007-04-30 11:26:00 +04:00
saddr , dif ) ;
}
if ( sk ) {
2005-04-17 02:20:36 +04:00
do {
struct sk_buff * skb1 = skb ;
2007-05-01 00:35:29 +04:00
sknext = udp_v4_mcast_next ( sk_next ( sk ) , hash , hport ,
daddr , uh - > source , saddr , dif ) ;
2007-04-30 11:26:00 +04:00
if ( ! sknext & & hash ! = hashwild ) {
hash = hashwild ;
2007-05-01 00:35:29 +04:00
sknext = udp_v4_mcast_next ( skw , hash , hport ,
2007-04-30 11:26:00 +04:00
daddr , uh - > source , saddr , dif ) ;
}
2007-03-09 07:41:55 +03:00
if ( sknext )
2005-04-17 02:20:36 +04:00
skb1 = skb_clone ( skb , GFP_ATOMIC ) ;
2007-03-09 07:41:55 +03:00
if ( skb1 ) {
2005-04-17 02:20:36 +04:00
int ret = udp_queue_rcv_skb ( sk , skb1 ) ;
if ( ret > 0 )
2007-04-30 11:26:00 +04:00
/*
* we should probably re - process
* instead of dropping packets here .
*/
2005-04-17 02:20:36 +04:00
kfree_skb ( skb1 ) ;
}
sk = sknext ;
2007-03-09 07:41:55 +03:00
} while ( sknext ) ;
2005-04-17 02:20:36 +04:00
} else
kfree_skb ( skb ) ;
read_unlock ( & udp_hash_lock ) ;
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 .
*/
2007-03-26 07:10:56 +04:00
static inline int udp4_csum_init ( struct sk_buff * skb , struct udphdr * uh ,
int proto )
2005-04-17 02:20:36 +04:00
{
2007-04-21 09:47:35 +04:00
const struct iphdr * iph ;
2007-03-26 07:10:56 +04:00
int err ;
UDP_SKB_CB ( skb ) - > partial_cov = 0 ;
UDP_SKB_CB ( skb ) - > cscov = skb - > len ;
if ( proto = = IPPROTO_UDPLITE ) {
err = udplite_checksum_init ( skb , uh ) ;
if ( err )
return err ;
}
2007-04-21 09:47:35 +04:00
iph = ip_hdr ( skb ) ;
2005-04-17 02:20:36 +04:00
if ( uh - > check = = 0 ) {
skb - > ip_summed = CHECKSUM_UNNECESSARY ;
2006-08-30 03:44:56 +04:00
} else if ( skb - > ip_summed = = CHECKSUM_COMPLETE ) {
2007-04-21 09:47:35 +04:00
if ( ! csum_tcpudp_magic ( iph - > saddr , iph - > daddr , skb - > len ,
proto , skb - > csum ) )
2005-11-11 00:01:24 +03:00
skb - > ip_summed = CHECKSUM_UNNECESSARY ;
2005-04-17 02:20:36 +04:00
}
2007-04-09 22:59:39 +04:00
if ( ! skb_csum_unnecessary ( skb ) )
2007-04-21 09:47:35 +04:00
skb - > csum = csum_tcpudp_nofold ( iph - > saddr , iph - > daddr ,
2007-03-26 07:10:56 +04:00
skb - > len , proto , 0 ) ;
2005-04-17 02:20:36 +04:00
/* Probably, we should checksum udp header (it should be in cache
* in any case ) and data in tiny packets ( < rx copybreak ) .
*/
2006-11-27 22:10:57 +03:00
2007-03-26 07:10:56 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
/*
2007-02-09 17:24:47 +03:00
* All we need to do is get the socket , and then do a checksum .
2005-04-17 02:20:36 +04:00
*/
2007-02-09 17:24:47 +03:00
2006-11-27 22:10:57 +03:00
int __udp4_lib_rcv ( struct sk_buff * skb , struct hlist_head udptable [ ] ,
2007-03-26 07:10:56 +04:00
int proto )
2005-04-17 02:20:36 +04:00
{
2007-02-09 17:24:47 +03:00
struct sock * sk ;
2007-03-13 20:28:48 +03:00
struct udphdr * uh = udp_hdr ( skb ) ;
2005-04-17 02:20:36 +04:00
unsigned short ulen ;
struct rtable * rt = ( struct rtable * ) skb - > dst ;
2007-04-21 09:47:35 +04:00
__be32 saddr = ip_hdr ( skb ) - > saddr ;
__be32 daddr = ip_hdr ( skb ) - > daddr ;
2005-04-17 02:20:36 +04:00
/*
2006-11-27 22:10:57 +03:00
* Validate the packet .
2005-04-17 02:20:36 +04:00
*/
if ( ! pskb_may_pull ( skb , sizeof ( struct udphdr ) ) )
2006-11-27 22:10:57 +03:00
goto drop ; /* No space for header. */
2005-04-17 02:20:36 +04:00
ulen = ntohs ( uh - > len ) ;
2006-11-27 22:10:57 +03:00
if ( ulen > skb - > len )
2005-04-17 02:20:36 +04:00
goto short_packet ;
2007-03-26 07:10:56 +04:00
if ( proto = = IPPROTO_UDP ) {
/* UDP validates ulen. */
2006-11-27 22:10:57 +03:00
if ( ulen < sizeof ( * uh ) | | pskb_trim_rcsum ( skb , ulen ) )
goto short_packet ;
2007-03-13 20:28:48 +03:00
uh = udp_hdr ( skb ) ;
2006-11-27 22:10:57 +03:00
}
2005-04-17 02:20:36 +04:00
2007-03-26 07:10:56 +04:00
if ( udp4_csum_init ( skb , uh , proto ) )
goto csum_error ;
2007-03-09 07:41:55 +03:00
if ( rt - > rt_flags & ( RTCF_BROADCAST | RTCF_MULTICAST ) )
2006-11-27 22:10:57 +03:00
return __udp4_lib_mcast_deliver ( skb , uh , saddr , daddr , udptable ) ;
2005-04-17 02:20:36 +04:00
2006-11-27 22:10:57 +03:00
sk = __udp4_lib_lookup ( saddr , uh - > source , daddr , uh - > dest ,
2007-05-01 00:35:29 +04:00
skb - > dev - > ifindex , udptable ) ;
2005-04-17 02:20:36 +04:00
if ( sk ! = NULL ) {
int ret = udp_queue_rcv_skb ( sk , skb ) ;
sock_put ( sk ) ;
/* a return value > 0 means to resubmit the input, but
2006-11-27 22:10:57 +03:00
* it wants the return to be - protocol , or 0
2005-04-17 02:20:36 +04:00
*/
if ( ret > 0 )
return - ret ;
return 0 ;
}
if ( ! xfrm4_policy_check ( NULL , XFRM_POLICY_IN , skb ) )
goto drop ;
2006-01-07 10:06:10 +03:00
nf_reset ( skb ) ;
2005-04-17 02:20:36 +04:00
/* No socket. Drop packet silently, if checksum is wrong */
2006-11-27 22:10:57 +03:00
if ( udp_lib_checksum_complete ( skb ) )
2005-04-17 02:20:36 +04:00
goto csum_error ;
2007-03-26 07:10:56 +04:00
UDP_INC_STATS_BH ( UDP_MIB_NOPORTS , proto = = IPPROTO_UDPLITE ) ;
2005-04-17 02:20:36 +04:00
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 ) ;
2007-03-09 07:41:55 +03:00
return 0 ;
2005-04-17 02:20:36 +04:00
short_packet :
2006-11-27 22:10:57 +03:00
LIMIT_NETDEBUG ( KERN_DEBUG " UDP%s: short packet: From %u.%u.%u.%u:%u %d/%d to %u.%u.%u.%u:%u \n " ,
2007-03-26 07:10:56 +04:00
proto = = IPPROTO_UDPLITE ? " -Lite " : " " ,
2005-08-10 07:50:53 +04:00
NIPQUAD ( saddr ) ,
ntohs ( uh - > source ) ,
ulen ,
2006-11-27 22:10:57 +03:00
skb - > len ,
2005-08-10 07:50:53 +04:00
NIPQUAD ( daddr ) ,
ntohs ( uh - > dest ) ) ;
2006-11-27 22:10:57 +03:00
goto drop ;
2005-04-17 02:20:36 +04:00
csum_error :
2007-02-09 17:24:47 +03:00
/*
* RFC1122 : OK . Discards the bad packet silently ( as far as
* the network is concerned , anyway ) as per 4.1 .3 .4 ( MUST ) .
2005-04-17 02:20:36 +04:00
*/
2006-11-27 22:10:57 +03:00
LIMIT_NETDEBUG ( KERN_DEBUG " UDP%s: bad checksum. From %d.%d.%d.%d:%d to %d.%d.%d.%d:%d ulen %d \n " ,
2007-03-26 07:10:56 +04:00
proto = = IPPROTO_UDPLITE ? " -Lite " : " " ,
2005-08-10 07:50:53 +04:00
NIPQUAD ( saddr ) ,
ntohs ( uh - > source ) ,
NIPQUAD ( daddr ) ,
ntohs ( uh - > dest ) ,
ulen ) ;
2005-04-17 02:20:36 +04:00
drop :
2007-03-26 07:10:56 +04:00
UDP_INC_STATS_BH ( UDP_MIB_INERRORS , proto = = IPPROTO_UDPLITE ) ;
2005-04-17 02:20:36 +04:00
kfree_skb ( skb ) ;
2007-03-09 07:41:55 +03:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2007-03-09 07:46:41 +03:00
int udp_rcv ( struct sk_buff * skb )
2006-11-27 22:10:57 +03:00
{
2007-03-26 07:10:56 +04:00
return __udp4_lib_rcv ( skb , udp_hash , IPPROTO_UDP ) ;
2006-11-27 22:10:57 +03:00
}
int udp_destroy_sock ( struct sock * sk )
2005-04-17 02:20:36 +04:00
{
lock_sock ( sk ) ;
udp_flush_pending_frames ( sk ) ;
release_sock ( sk ) ;
return 0 ;
}
/*
* Socket option code for UDP
*/
2006-11-27 20:29:59 +03:00
int udp_lib_setsockopt ( struct sock * sk , int level , int optname ,
char __user * optval , int optlen ,
int ( * push_pending_frames ) ( struct sock * ) )
2005-04-17 02:20:36 +04:00
{
struct udp_sock * up = udp_sk ( sk ) ;
int val ;
int err = 0 ;
2007-03-09 07:41:55 +03:00
if ( optlen < sizeof ( int ) )
2005-04-17 02:20:36 +04:00
return - EINVAL ;
if ( get_user ( val , ( int __user * ) optval ) )
return - EFAULT ;
2007-03-09 07:41:55 +03:00
switch ( optname ) {
2005-04-17 02:20:36 +04:00
case UDP_CORK :
if ( val ! = 0 ) {
up - > corkflag = 1 ;
} else {
up - > corkflag = 0 ;
lock_sock ( sk ) ;
2006-11-27 20:29:59 +03:00
( * push_pending_frames ) ( sk ) ;
2005-04-17 02:20:36 +04:00
release_sock ( sk ) ;
}
break ;
2007-02-09 17:24:47 +03:00
2005-04-17 02:20:36 +04:00
case UDP_ENCAP :
switch ( val ) {
case 0 :
case UDP_ENCAP_ESPINUDP :
case UDP_ENCAP_ESPINUDP_NON_IKE :
up - > encap_type = val ;
break ;
default :
err = - ENOPROTOOPT ;
break ;
}
break ;
2006-11-27 22:10:57 +03:00
/*
* UDP - Lite ' s partial checksum coverage ( RFC 3828 ) .
*/
/* The sender sets actual checksum coverage length via this option.
* The case coverage > packet length is handled by send module . */
case UDPLITE_SEND_CSCOV :
if ( ! up - > pcflag ) /* Disable the option on UDP sockets */
return - ENOPROTOOPT ;
if ( val ! = 0 & & val < 8 ) /* Illegal coverage: use default (8) */
val = 8 ;
up - > pcslen = val ;
up - > pcflag | = UDPLITE_SEND_CC ;
break ;
2007-02-09 17:24:47 +03:00
/* The receiver specifies a minimum checksum coverage value. To make
* sense , this should be set to at least 8 ( as done below ) . If zero is
2006-11-27 22:10:57 +03:00
* used , this again means full checksum coverage . */
case UDPLITE_RECV_CSCOV :
if ( ! up - > pcflag ) /* Disable the option on UDP sockets */
return - ENOPROTOOPT ;
if ( val ! = 0 & & val < 8 ) /* Avoid silly minimal values. */
val = 8 ;
up - > pcrlen = val ;
up - > pcflag | = UDPLITE_RECV_CC ;
break ;
2005-04-17 02:20:36 +04:00
default :
err = - ENOPROTOOPT ;
break ;
2007-03-09 07:41:55 +03:00
}
2005-04-17 02:20:36 +04:00
return err ;
}
2006-11-27 22:10:57 +03:00
int udp_setsockopt ( struct sock * sk , int level , int optname ,
char __user * optval , int optlen )
2006-03-21 09:45:21 +03:00
{
2006-11-27 22:10:57 +03:00
if ( level = = SOL_UDP | | level = = SOL_UDPLITE )
2006-11-27 20:29:59 +03:00
return udp_lib_setsockopt ( sk , level , optname , optval , optlen ,
udp_push_pending_frames ) ;
2006-11-27 22:10:57 +03:00
return ip_setsockopt ( sk , level , optname , optval , optlen ) ;
2006-03-21 09:45:21 +03:00
}
# ifdef CONFIG_COMPAT
2006-11-27 22:10:57 +03:00
int compat_udp_setsockopt ( struct sock * sk , int level , int optname ,
char __user * optval , int optlen )
2006-03-21 09:45:21 +03:00
{
2006-11-27 22:10:57 +03:00
if ( level = = SOL_UDP | | level = = SOL_UDPLITE )
2006-11-27 20:29:59 +03:00
return udp_lib_setsockopt ( sk , level , optname , optval , optlen ,
udp_push_pending_frames ) ;
2006-11-27 22:10:57 +03:00
return compat_ip_setsockopt ( sk , level , optname , optval , optlen ) ;
2006-03-21 09:45:21 +03:00
}
# endif
2006-11-27 20:29:59 +03:00
int udp_lib_getsockopt ( struct sock * sk , int level , int optname ,
char __user * optval , int __user * optlen )
2005-04-17 02:20:36 +04:00
{
struct udp_sock * up = udp_sk ( sk ) ;
int val , len ;
2007-03-09 07:41:55 +03:00
if ( get_user ( len , optlen ) )
2005-04-17 02:20:36 +04:00
return - EFAULT ;
len = min_t ( unsigned int , len , sizeof ( int ) ) ;
2007-02-09 17:24:47 +03:00
2007-03-09 07:41:55 +03:00
if ( len < 0 )
2005-04-17 02:20:36 +04:00
return - EINVAL ;
2007-03-09 07:41:55 +03:00
switch ( optname ) {
2005-04-17 02:20:36 +04:00
case UDP_CORK :
val = up - > corkflag ;
break ;
case UDP_ENCAP :
val = up - > encap_type ;
break ;
2006-11-27 22:10:57 +03:00
/* The following two cannot be changed on UDP sockets, the return is
* always 0 ( which corresponds to the full checksum coverage of UDP ) . */
case UDPLITE_SEND_CSCOV :
val = up - > pcslen ;
break ;
case UDPLITE_RECV_CSCOV :
val = up - > pcrlen ;
break ;
2005-04-17 02:20:36 +04:00
default :
return - ENOPROTOOPT ;
2007-03-09 07:41:55 +03:00
}
2005-04-17 02:20:36 +04:00
2007-03-09 07:41:55 +03:00
if ( put_user ( len , optlen ) )
2007-02-09 17:24:47 +03:00
return - EFAULT ;
2007-03-09 07:41:55 +03:00
if ( copy_to_user ( optval , & val , len ) )
2005-04-17 02:20:36 +04:00
return - EFAULT ;
2007-02-09 17:24:47 +03:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2006-11-27 22:10:57 +03:00
int udp_getsockopt ( struct sock * sk , int level , int optname ,
char __user * optval , int __user * optlen )
2006-03-21 09:45:21 +03:00
{
2006-11-27 22:10:57 +03:00
if ( level = = SOL_UDP | | level = = SOL_UDPLITE )
2006-11-27 20:29:59 +03:00
return udp_lib_getsockopt ( sk , level , optname , optval , optlen ) ;
2006-11-27 22:10:57 +03:00
return ip_getsockopt ( sk , level , optname , optval , optlen ) ;
2006-03-21 09:45:21 +03:00
}
# ifdef CONFIG_COMPAT
2006-11-27 22:10:57 +03:00
int compat_udp_getsockopt ( struct sock * sk , int level , int optname ,
2006-03-21 09:48:35 +03:00
char __user * optval , int __user * optlen )
2006-03-21 09:45:21 +03:00
{
2006-11-27 22:10:57 +03:00
if ( level = = SOL_UDP | | level = = SOL_UDPLITE )
2006-11-27 20:29:59 +03:00
return udp_lib_getsockopt ( sk , level , optname , optval , optlen ) ;
2006-11-27 22:10:57 +03:00
return compat_ip_getsockopt ( sk , level , optname , optval , optlen ) ;
2006-03-21 09:45:21 +03:00
}
# endif
2005-04-17 02:20:36 +04:00
/**
* udp_poll - wait for a UDP event .
* @ file - file struct
* @ sock - socket
* @ wait - poll table
*
2007-02-09 17:24:47 +03:00
* This is same as datagram poll , except for the special case of
2005-04-17 02:20:36 +04:00
* blocking sockets . If application is using a blocking fd
* and a packet with checksum error is in the queue ;
* then it could get return from select indicating data available
* but then block when reading it . Add special case code
* to work around these arguably broken applications .
*/
unsigned int udp_poll ( struct file * file , struct socket * sock , poll_table * wait )
{
unsigned int mask = datagram_poll ( file , sock , wait ) ;
struct sock * sk = sock - > sk ;
2006-11-27 22:10:57 +03:00
int is_lite = IS_UDPLITE ( sk ) ;
2005-04-17 02:20:36 +04:00
/* Check for false positives due to checksum errors */
if ( ( mask & POLLRDNORM ) & &
! ( file - > f_flags & O_NONBLOCK ) & &
! ( sk - > sk_shutdown & RCV_SHUTDOWN ) ) {
struct sk_buff_head * rcvq = & sk - > sk_receive_queue ;
struct sk_buff * skb ;
2005-05-31 02:50:15 +04:00
spin_lock_bh ( & rcvq - > lock ) ;
2007-03-26 07:10:56 +04:00
while ( ( skb = skb_peek ( rcvq ) ) ! = NULL & &
udp_lib_checksum_complete ( skb ) ) {
UDP_INC_STATS_BH ( UDP_MIB_INERRORS , is_lite ) ;
__skb_unlink ( skb , rcvq ) ;
kfree_skb ( skb ) ;
2005-04-17 02:20:36 +04:00
}
2005-05-31 02:50:15 +04:00
spin_unlock_bh ( & rcvq - > lock ) ;
2005-04-17 02:20:36 +04:00
/* nothing to see, move along */
if ( skb = = NULL )
mask & = ~ ( POLLIN | POLLRDNORM ) ;
}
return mask ;
2007-02-09 17:24:47 +03:00
2005-04-17 02:20:36 +04:00
}
struct proto udp_prot = {
2007-02-09 17:24:47 +03:00
. name = " UDP " ,
2006-03-21 09:48:35 +03:00
. owner = THIS_MODULE ,
2006-11-27 22:10:57 +03:00
. close = udp_lib_close ,
2006-03-21 09:48:35 +03:00
. connect = ip4_datagram_connect ,
. disconnect = udp_disconnect ,
. ioctl = udp_ioctl ,
. destroy = udp_destroy_sock ,
. setsockopt = udp_setsockopt ,
. getsockopt = udp_getsockopt ,
. sendmsg = udp_sendmsg ,
. recvmsg = udp_recvmsg ,
. sendpage = udp_sendpage ,
. backlog_rcv = udp_queue_rcv_skb ,
2006-11-27 22:10:57 +03:00
. hash = udp_lib_hash ,
. unhash = udp_lib_unhash ,
2006-03-21 09:48:35 +03:00
. get_port = udp_v4_get_port ,
. obj_size = sizeof ( struct udp_sock ) ,
2006-03-21 09:45:21 +03:00
# ifdef CONFIG_COMPAT
2006-03-21 09:48:35 +03:00
. compat_setsockopt = compat_udp_setsockopt ,
. compat_getsockopt = compat_udp_getsockopt ,
2006-03-21 09:45:21 +03:00
# endif
2005-04-17 02:20:36 +04:00
} ;
/* ------------------------------------------------------------------------ */
# ifdef CONFIG_PROC_FS
static struct sock * udp_get_first ( struct seq_file * seq )
{
struct sock * sk ;
struct udp_iter_state * state = seq - > private ;
for ( state - > bucket = 0 ; state - > bucket < UDP_HTABLE_SIZE ; + + state - > bucket ) {
struct hlist_node * node ;
2006-11-27 22:10:57 +03:00
sk_for_each ( sk , node , state - > hashtable + state - > bucket ) {
2005-04-17 02:20:36 +04:00
if ( sk - > sk_family = = state - > family )
goto found ;
}
}
sk = NULL ;
found :
return sk ;
}
static struct sock * udp_get_next ( struct seq_file * seq , struct sock * sk )
{
struct udp_iter_state * state = seq - > private ;
do {
sk = sk_next ( sk ) ;
try_again :
;
} while ( sk & & sk - > sk_family ! = state - > family ) ;
if ( ! sk & & + + state - > bucket < UDP_HTABLE_SIZE ) {
2006-11-27 22:10:57 +03:00
sk = sk_head ( state - > hashtable + state - > bucket ) ;
2005-04-17 02:20:36 +04:00
goto try_again ;
}
return sk ;
}
static struct sock * udp_get_idx ( struct seq_file * seq , loff_t pos )
{
struct sock * sk = udp_get_first ( seq ) ;
if ( sk )
2007-03-09 07:41:55 +03:00
while ( pos & & ( sk = udp_get_next ( seq , sk ) ) ! = NULL )
2005-04-17 02:20:36 +04:00
- - pos ;
return pos ? NULL : sk ;
}
static void * udp_seq_start ( struct seq_file * seq , loff_t * pos )
{
read_lock ( & udp_hash_lock ) ;
return * pos ? udp_get_idx ( seq , * pos - 1 ) : ( void * ) 1 ;
}
static void * udp_seq_next ( struct seq_file * seq , void * v , loff_t * pos )
{
struct sock * sk ;
if ( v = = ( void * ) 1 )
sk = udp_get_idx ( seq , 0 ) ;
else
sk = udp_get_next ( seq , v ) ;
+ + * pos ;
return sk ;
}
static void udp_seq_stop ( struct seq_file * seq , void * v )
{
read_unlock ( & udp_hash_lock ) ;
}
static int udp_seq_open ( struct inode * inode , struct file * file )
{
struct udp_seq_afinfo * afinfo = PDE ( inode ) - > data ;
struct seq_file * seq ;
int rc = - ENOMEM ;
2006-07-22 01:51:30 +04:00
struct udp_iter_state * s = kzalloc ( sizeof ( * s ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! s )
goto out ;
s - > family = afinfo - > family ;
2006-11-27 22:10:57 +03:00
s - > hashtable = afinfo - > hashtable ;
2005-04-17 02:20:36 +04:00
s - > seq_ops . start = udp_seq_start ;
s - > seq_ops . next = udp_seq_next ;
s - > seq_ops . show = afinfo - > seq_show ;
s - > seq_ops . stop = udp_seq_stop ;
rc = seq_open ( file , & s - > seq_ops ) ;
if ( rc )
goto out_kfree ;
seq = file - > private_data ;
seq - > private = s ;
out :
return rc ;
out_kfree :
kfree ( s ) ;
goto out ;
}
/* ------------------------------------------------------------------------ */
int udp_proc_register ( struct udp_seq_afinfo * afinfo )
{
struct proc_dir_entry * p ;
int rc = 0 ;
if ( ! afinfo )
return - EINVAL ;
afinfo - > seq_fops - > owner = afinfo - > owner ;
afinfo - > seq_fops - > open = udp_seq_open ;
afinfo - > seq_fops - > read = seq_read ;
afinfo - > seq_fops - > llseek = seq_lseek ;
afinfo - > seq_fops - > release = seq_release_private ;
p = proc_net_fops_create ( afinfo - > name , S_IRUGO , afinfo - > seq_fops ) ;
if ( p )
p - > data = afinfo ;
else
rc = - ENOMEM ;
return rc ;
}
void udp_proc_unregister ( struct udp_seq_afinfo * afinfo )
{
if ( ! afinfo )
return ;
proc_net_remove ( afinfo - > name ) ;
memset ( afinfo - > seq_fops , 0 , sizeof ( * afinfo - > seq_fops ) ) ;
}
/* ------------------------------------------------------------------------ */
static void udp4_format_sock ( struct sock * sp , char * tmpbuf , int bucket )
{
struct inet_sock * inet = inet_sk ( sp ) ;
2006-09-28 05:37:41 +04:00
__be32 dest = inet - > daddr ;
__be32 src = inet - > rcv_saddr ;
2005-04-17 02:20:36 +04:00
__u16 destp = ntohs ( inet - > dport ) ;
__u16 srcp = ntohs ( inet - > sport ) ;
sprintf ( tmpbuf , " %4d: %08X:%04X %08X:%04X "
" %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p " ,
2007-02-09 17:24:47 +03:00
bucket , src , srcp , dest , destp , sp - > sk_state ,
2005-04-17 02:20:36 +04:00
atomic_read ( & sp - > sk_wmem_alloc ) ,
atomic_read ( & sp - > sk_rmem_alloc ) ,
0 , 0L , 0 , sock_i_uid ( sp ) , 0 , sock_i_ino ( sp ) ,
atomic_read ( & sp - > sk_refcnt ) , sp ) ;
}
2006-11-27 22:10:57 +03:00
int udp4_seq_show ( struct seq_file * seq , void * v )
2005-04-17 02:20:36 +04:00
{
if ( v = = SEQ_START_TOKEN )
seq_printf ( seq , " %-127s \n " ,
" sl local_address rem_address st tx_queue "
" rx_queue tr tm->when retrnsmt uid timeout "
" inode " ) ;
else {
char tmpbuf [ 129 ] ;
struct udp_iter_state * state = seq - > private ;
udp4_format_sock ( v , tmpbuf , state - > bucket ) ;
seq_printf ( seq , " %-127s \n " , tmpbuf ) ;
}
return 0 ;
}
/* ------------------------------------------------------------------------ */
static struct file_operations udp4_seq_fops ;
static struct udp_seq_afinfo udp4_seq_afinfo = {
. owner = THIS_MODULE ,
. name = " udp " ,
. family = AF_INET ,
2006-11-27 22:10:57 +03:00
. hashtable = udp_hash ,
2005-04-17 02:20:36 +04:00
. seq_show = udp4_seq_show ,
. seq_fops = & udp4_seq_fops ,
} ;
int __init udp4_proc_init ( void )
{
return udp_proc_register ( & udp4_seq_afinfo ) ;
}
void udp4_proc_exit ( void )
{
udp_proc_unregister ( & udp4_seq_afinfo ) ;
}
# endif /* CONFIG_PROC_FS */
EXPORT_SYMBOL ( udp_disconnect ) ;
EXPORT_SYMBOL ( udp_hash ) ;
EXPORT_SYMBOL ( udp_hash_lock ) ;
EXPORT_SYMBOL ( udp_ioctl ) ;
2006-08-27 07:06:05 +04:00
EXPORT_SYMBOL ( udp_get_port ) ;
2005-04-17 02:20:36 +04:00
EXPORT_SYMBOL ( udp_prot ) ;
EXPORT_SYMBOL ( udp_sendmsg ) ;
2006-11-27 20:29:59 +03:00
EXPORT_SYMBOL ( udp_lib_getsockopt ) ;
EXPORT_SYMBOL ( udp_lib_setsockopt ) ;
2005-04-17 02:20:36 +04:00
EXPORT_SYMBOL ( udp_poll ) ;
# ifdef CONFIG_PROC_FS
EXPORT_SYMBOL ( udp_proc_register ) ;
EXPORT_SYMBOL ( udp_proc_unregister ) ;
# endif