2005-04-17 02:20:36 +04:00
/*
* common UDP / RAW code
* Linux INET implementation
*
* Authors :
* Hideaki YOSHIFUJI < yoshfuji @ linux - ipv6 . org >
*
* 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 .
*/
# include <linux/types.h>
# include <linux/module.h>
# include <linux/ip.h>
# include <linux/in.h>
2005-08-16 09:18:02 +04:00
# include <net/ip.h>
2005-04-17 02:20:36 +04:00
# include <net/sock.h>
# include <net/route.h>
2005-08-10 07:08:28 +04:00
# include <net/tcp_states.h>
2005-04-17 02:20:36 +04:00
int ip4_datagram_connect ( struct sock * sk , struct sockaddr * uaddr , int addr_len )
{
struct inet_sock * inet = inet_sk ( sk ) ;
struct sockaddr_in * usin = ( struct sockaddr_in * ) uaddr ;
struct rtable * rt ;
2006-09-27 08:27:15 +04:00
__be32 saddr ;
2005-04-17 02:20:36 +04:00
int oif ;
int err ;
2007-02-09 17:24:47 +03:00
if ( addr_len < sizeof ( * usin ) )
return - EINVAL ;
if ( usin - > sin_family ! = AF_INET )
return - EAFNOSUPPORT ;
2005-04-17 02:20:36 +04:00
sk_dst_reset ( sk ) ;
oif = sk - > sk_bound_dev_if ;
2009-10-15 10:30:45 +04:00
saddr = inet - > inet_saddr ;
2007-12-17 00:45:43 +03:00
if ( ipv4_is_multicast ( usin - > sin_addr . s_addr ) ) {
2005-04-17 02:20:36 +04:00
if ( ! oif )
oif = inet - > mc_index ;
if ( ! saddr )
saddr = inet - > mc_addr ;
}
err = ip_route_connect ( & rt , usin - > sin_addr . s_addr , saddr ,
RT_CONN_FLAGS ( sk ) , oif ,
sk - > sk_protocol ,
2009-10-15 10:30:45 +04:00
inet - > inet_sport , usin - > sin_port , sk , 1 ) ;
2007-06-01 09:49:28 +04:00
if ( err ) {
if ( err = = - ENETUNREACH )
2008-07-17 07:20:11 +04:00
IP_INC_STATS_BH ( sock_net ( sk ) , IPSTATS_MIB_OUTNOROUTES ) ;
2005-04-17 02:20:36 +04:00
return err ;
2007-06-01 09:49:28 +04:00
}
2005-04-17 02:20:36 +04:00
if ( ( rt - > rt_flags & RTCF_BROADCAST ) & & ! sock_flag ( sk , SOCK_BROADCAST ) ) {
ip_rt_put ( rt ) ;
return - EACCES ;
}
2009-10-15 10:30:45 +04:00
if ( ! inet - > inet_saddr )
inet - > inet_saddr = rt - > rt_src ; /* Update source address */
if ( ! inet - > inet_rcv_saddr )
inet - > inet_rcv_saddr = rt - > rt_src ;
inet - > inet_daddr = rt - > rt_dst ;
inet - > inet_dport = usin - > sin_port ;
2005-04-17 02:20:36 +04:00
sk - > sk_state = TCP_ESTABLISHED ;
2009-10-15 10:30:45 +04:00
inet - > inet_id = jiffies ;
2005-04-17 02:20:36 +04:00
sk_dst_set ( sk , & rt - > u . dst ) ;
return ( 0 ) ;
}
EXPORT_SYMBOL ( ip4_datagram_connect ) ;