aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorHideaki Yoshifuji <yoshfuji@linux-ipv6.org>2004-07-20 17:16:36 +0900
committerHideaki Yoshifuji <yoshfuji@linux-ipv6.org>2004-07-20 17:16:36 +0900
commit587451ba8b58fde2c368de23ef62588065c77c6c (patch)
tree38d779bc0b0db137d5a583923d30bf76b0053eb7 /net
parent1bb0fa189c6ae75cbf440244ae77a8ede9912df1 (diff)
downloadhistory-587451ba8b58fde2c368de23ef62588065c77c6c.tar.gz
[IPV4] Look up route with appropriate protocol when we connect().
Signed-off-by: Hideaki YOSHIFUJI <yoshfuji@linux-ipv6.org>
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/Makefile2
-rw-r--r--net/ipv4/datagram.c73
-rw-r--r--net/ipv4/raw.c2
-rw-r--r--net/ipv4/udp.c51
-rw-r--r--net/ipv6/datagram.c156
-rw-r--r--net/ipv6/raw.c2
-rw-r--r--net/ipv6/udp.c156
7 files changed, 235 insertions, 207 deletions
diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile
index 8289a1d95e9102..0fe409afa0943e 100644
--- a/net/ipv4/Makefile
+++ b/net/ipv4/Makefile
@@ -6,7 +6,7 @@ obj-y := utils.o route.o inetpeer.o protocol.o \
ip_input.o ip_fragment.o ip_forward.o ip_options.o \
ip_output.o ip_sockglue.o \
tcp.o tcp_input.o tcp_output.o tcp_timer.o tcp_ipv4.o tcp_minisocks.o \
- tcp_diag.o raw.o udp.o arp.o icmp.o devinet.o af_inet.o igmp.o \
+ tcp_diag.o datagram.o raw.o udp.o arp.o icmp.o devinet.o af_inet.o igmp.o \
sysctl_net_ipv4.o fib_frontend.o fib_semantics.o fib_hash.o
obj-$(CONFIG_PROC_FS) += proc.o
diff --git a/net/ipv4/datagram.c b/net/ipv4/datagram.c
new file mode 100644
index 00000000000000..f84e1041d2d9c0
--- /dev/null
+++ b/net/ipv4/datagram.c
@@ -0,0 +1,73 @@
+/*
+ * 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/config.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/ip.h>
+#include <linux/in.h>
+#include <net/sock.h>
+#include <net/tcp.h>
+#include <net/route.h>
+
+int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
+{
+ struct inet_opt *inet = inet_sk(sk);
+ struct sockaddr_in *usin = (struct sockaddr_in *) uaddr;
+ struct rtable *rt;
+ u32 saddr;
+ int oif;
+ int err;
+
+
+ if (addr_len < sizeof(*usin))
+ return -EINVAL;
+
+ if (usin->sin_family != AF_INET)
+ return -EAFNOSUPPORT;
+
+ sk_dst_reset(sk);
+
+ oif = sk->sk_bound_dev_if;
+ saddr = inet->saddr;
+ if (MULTICAST(usin->sin_addr.s_addr)) {
+ 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,
+ inet->sport, usin->sin_port, sk);
+ if (err)
+ return err;
+ if ((rt->rt_flags & RTCF_BROADCAST) && !sock_flag(sk, SOCK_BROADCAST)) {
+ ip_rt_put(rt);
+ return -EACCES;
+ }
+ if (!inet->saddr)
+ inet->saddr = rt->rt_src; /* Update source address */
+ if (!inet->rcv_saddr)
+ inet->rcv_saddr = rt->rt_src;
+ inet->daddr = rt->rt_dst;
+ inet->dport = usin->sin_port;
+ sk->sk_state = TCP_ESTABLISHED;
+ inet->id = jiffies;
+
+ sk_dst_set(sk, &rt->u.dst);
+ return(0);
+}
+
+EXPORT_SYMBOL(ip4_datagram_connect);
+
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index ac04153be86336..6106a240ce91b5 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -657,7 +657,7 @@ static int raw_ioctl(struct sock *sk, int cmd, unsigned long arg)
struct proto raw_prot = {
.name = "RAW",
.close = raw_close,
- .connect = udp_connect,
+ .connect = ip4_datagram_connect,
.disconnect = udp_disconnect,
.ioctl = raw_ioctl,
.init = raw_init,
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index bfa78d5ee608b6..181a88efe1c02b 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -858,54 +858,6 @@ csum_copy_err:
goto try_again;
}
-int udp_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
-{
- struct inet_opt *inet = inet_sk(sk);
- struct sockaddr_in *usin = (struct sockaddr_in *) uaddr;
- struct rtable *rt;
- u32 saddr;
- int oif;
- int err;
-
-
- if (addr_len < sizeof(*usin))
- return -EINVAL;
-
- if (usin->sin_family != AF_INET)
- return -EAFNOSUPPORT;
-
- sk_dst_reset(sk);
-
- oif = sk->sk_bound_dev_if;
- saddr = inet->saddr;
- if (MULTICAST(usin->sin_addr.s_addr)) {
- 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,
- IPPROTO_UDP,
- inet->sport, usin->sin_port, sk);
- if (err)
- return err;
- if ((rt->rt_flags & RTCF_BROADCAST) && !sock_flag(sk, SOCK_BROADCAST)) {
- ip_rt_put(rt);
- return -EACCES;
- }
- if (!inet->saddr)
- inet->saddr = rt->rt_src; /* Update source address */
- if (!inet->rcv_saddr)
- inet->rcv_saddr = rt->rt_src;
- inet->daddr = rt->rt_dst;
- inet->dport = usin->sin_port;
- sk->sk_state = TCP_ESTABLISHED;
- inet->id = jiffies;
-
- sk_dst_set(sk, &rt->u.dst);
- return(0);
-}
int udp_disconnect(struct sock *sk, int flags)
{
@@ -1351,7 +1303,7 @@ static int udp_getsockopt(struct sock *sk, int level, int optname,
struct proto udp_prot = {
.name = "UDP",
.close = udp_close,
- .connect = udp_connect,
+ .connect = ip4_datagram_connect,
.disconnect = udp_disconnect,
.ioctl = udp_ioctl,
.destroy = udp_destroy_sock,
@@ -1552,7 +1504,6 @@ void udp4_proc_exit(void)
}
#endif /* CONFIG_PROC_FS */
-EXPORT_SYMBOL(udp_connect);
EXPORT_SYMBOL(udp_disconnect);
EXPORT_SYMBOL(udp_hash);
EXPORT_SYMBOL(udp_hash_lock);
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
index 8bd78996b12fb9..8b1cf3ea49cc05 100644
--- a/net/ipv6/datagram.c
+++ b/net/ipv6/datagram.c
@@ -28,10 +28,166 @@
#include <net/ndisc.h>
#include <net/addrconf.h>
#include <net/transp_v6.h>
+#include <net/ip6_route.h>
#include <linux/errqueue.h>
#include <asm/uaccess.h>
+int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
+{
+ struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr;
+ struct inet_opt *inet = inet_sk(sk);
+ struct ipv6_pinfo *np = inet6_sk(sk);
+ struct in6_addr *daddr;
+ struct dst_entry *dst;
+ struct flowi fl;
+ struct ip6_flowlabel *flowlabel = NULL;
+ int addr_type;
+ int err;
+
+ if (usin->sin6_family == AF_INET) {
+ if (__ipv6_only_sock(sk))
+ return -EAFNOSUPPORT;
+ err = ip4_datagram_connect(sk, uaddr, addr_len);
+ goto ipv4_connected;
+ }
+
+ if (addr_len < SIN6_LEN_RFC2133)
+ return -EINVAL;
+
+ if (usin->sin6_family != AF_INET6)
+ return -EAFNOSUPPORT;
+
+ memset(&fl, 0, sizeof(fl));
+ if (np->sndflow) {
+ fl.fl6_flowlabel = usin->sin6_flowinfo&IPV6_FLOWINFO_MASK;
+ if (fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) {
+ flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel);
+ if (flowlabel == NULL)
+ return -EINVAL;
+ ipv6_addr_copy(&usin->sin6_addr, &flowlabel->dst);
+ }
+ }
+
+ addr_type = ipv6_addr_type(&usin->sin6_addr);
+
+ if (addr_type == IPV6_ADDR_ANY) {
+ /*
+ * connect to self
+ */
+ usin->sin6_addr.s6_addr[15] = 0x01;
+ }
+
+ daddr = &usin->sin6_addr;
+
+ if (addr_type == IPV6_ADDR_MAPPED) {
+ struct sockaddr_in sin;
+
+ if (__ipv6_only_sock(sk)) {
+ err = -ENETUNREACH;
+ goto out;
+ }
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = daddr->s6_addr32[3];
+ sin.sin_port = usin->sin6_port;
+
+ err = ip4_datagram_connect(sk,
+ (struct sockaddr*) &sin,
+ sizeof(sin));
+
+ipv4_connected:
+ if (err)
+ goto out;
+
+ ipv6_addr_set(&np->daddr, 0, 0, htonl(0x0000ffff), inet->daddr);
+
+ if (ipv6_addr_any(&np->saddr)) {
+ ipv6_addr_set(&np->saddr, 0, 0, htonl(0x0000ffff),
+ inet->saddr);
+ }
+
+ if (ipv6_addr_any(&np->rcv_saddr)) {
+ ipv6_addr_set(&np->rcv_saddr, 0, 0, htonl(0x0000ffff),
+ inet->rcv_saddr);
+ }
+ goto out;
+ }
+
+ if (addr_type&IPV6_ADDR_LINKLOCAL) {
+ if (addr_len >= sizeof(struct sockaddr_in6) &&
+ usin->sin6_scope_id) {
+ if (sk->sk_bound_dev_if &&
+ sk->sk_bound_dev_if != usin->sin6_scope_id) {
+ err = -EINVAL;
+ goto out;
+ }
+ sk->sk_bound_dev_if = usin->sin6_scope_id;
+ if (!sk->sk_bound_dev_if &&
+ (addr_type & IPV6_ADDR_MULTICAST))
+ fl.oif = np->mcast_oif;
+ }
+
+ /* Connect to link-local address requires an interface */
+ if (!sk->sk_bound_dev_if) {
+ err = -EINVAL;
+ goto out;
+ }
+ }
+
+ ipv6_addr_copy(&np->daddr, daddr);
+ np->flow_label = fl.fl6_flowlabel;
+
+ inet->dport = usin->sin6_port;
+
+ /*
+ * Check for a route to destination an obtain the
+ * destination cache for it.
+ */
+
+ fl.proto = sk->sk_protocol;
+ ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
+ ipv6_addr_copy(&fl.fl6_src, &np->saddr);
+ fl.oif = sk->sk_bound_dev_if;
+ fl.fl_ip_dport = inet->dport;
+ fl.fl_ip_sport = inet->sport;
+
+ if (!fl.oif && (addr_type&IPV6_ADDR_MULTICAST))
+ fl.oif = np->mcast_oif;
+
+ if (flowlabel) {
+ if (flowlabel->opt && flowlabel->opt->srcrt) {
+ struct rt0_hdr *rt0 = (struct rt0_hdr *) flowlabel->opt->srcrt;
+ ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
+ }
+ } else if (np->opt && np->opt->srcrt) {
+ struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt;
+ ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
+ }
+
+ err = ip6_dst_lookup(sk, &dst, &fl);
+ if (err)
+ goto out;
+
+ /* source address lookup done in ip6_dst_lookup */
+
+ if (ipv6_addr_any(&np->saddr))
+ ipv6_addr_copy(&np->saddr, &fl.fl6_src);
+
+ if (ipv6_addr_any(&np->rcv_saddr)) {
+ ipv6_addr_copy(&np->rcv_saddr, &fl.fl6_src);
+ inet->rcv_saddr = LOOPBACK4_IPV6;
+ }
+
+ ip6_dst_store(sk, dst,
+ !ipv6_addr_cmp(&fl.fl6_dst, &np->daddr) ?
+ &np->daddr : NULL);
+
+ sk->sk_state = TCP_ESTABLISHED;
+out:
+ fl6_sock_release(flowlabel);
+ return err;
+}
+
void ipv6_icmp_error(struct sock *sk, struct sk_buff *skb, int err,
u16 port, u32 info, u8 *payload)
{
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index 447b142d63274b..1f149e61a744da 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -916,7 +916,7 @@ static int rawv6_init_sk(struct sock *sk)
struct proto rawv6_prot = {
.name = "RAW",
.close = rawv6_close,
- .connect = udpv6_connect,
+ .connect = ip6_datagram_connect,
.disconnect = udp_disconnect,
.ioctl = rawv6_ioctl,
.init = rawv6_init_sk,
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 9a6bc46b532b23..de0afb31785f97 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -49,6 +49,7 @@
#include <net/addrconf.h>
#include <net/ip.h>
#include <net/udp.h>
+#include <net/raw.h>
#include <net/inet_common.h>
#include <net/ip6_checksum.h>
@@ -203,159 +204,6 @@ static struct sock *udp_v6_lookup(struct in6_addr *saddr, u16 sport,
*
*/
-int udpv6_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
-{
- struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr;
- struct inet_opt *inet = inet_sk(sk);
- struct ipv6_pinfo *np = inet6_sk(sk);
- struct in6_addr *daddr;
- struct dst_entry *dst;
- struct flowi fl;
- struct ip6_flowlabel *flowlabel = NULL;
- int addr_type;
- int err;
-
- if (usin->sin6_family == AF_INET) {
- if (__ipv6_only_sock(sk))
- return -EAFNOSUPPORT;
- err = udp_connect(sk, uaddr, addr_len);
- goto ipv4_connected;
- }
-
- if (addr_len < SIN6_LEN_RFC2133)
- return -EINVAL;
-
- if (usin->sin6_family != AF_INET6)
- return -EAFNOSUPPORT;
-
- memset(&fl, 0, sizeof(fl));
- if (np->sndflow) {
- fl.fl6_flowlabel = usin->sin6_flowinfo&IPV6_FLOWINFO_MASK;
- if (fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) {
- flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel);
- if (flowlabel == NULL)
- return -EINVAL;
- ipv6_addr_copy(&usin->sin6_addr, &flowlabel->dst);
- }
- }
-
- addr_type = ipv6_addr_type(&usin->sin6_addr);
-
- if (addr_type == IPV6_ADDR_ANY) {
- /*
- * connect to self
- */
- usin->sin6_addr.s6_addr[15] = 0x01;
- }
-
- daddr = &usin->sin6_addr;
-
- if (addr_type == IPV6_ADDR_MAPPED) {
- struct sockaddr_in sin;
-
- if (__ipv6_only_sock(sk)) {
- err = -ENETUNREACH;
- goto out;
- }
- sin.sin_family = AF_INET;
- sin.sin_addr.s_addr = daddr->s6_addr32[3];
- sin.sin_port = usin->sin6_port;
-
- err = udp_connect(sk, (struct sockaddr*) &sin, sizeof(sin));
-
-ipv4_connected:
- if (err)
- goto out;
-
- ipv6_addr_set(&np->daddr, 0, 0, htonl(0x0000ffff), inet->daddr);
-
- if (ipv6_addr_any(&np->saddr)) {
- ipv6_addr_set(&np->saddr, 0, 0, htonl(0x0000ffff),
- inet->saddr);
- }
-
- if (ipv6_addr_any(&np->rcv_saddr)) {
- ipv6_addr_set(&np->rcv_saddr, 0, 0, htonl(0x0000ffff),
- inet->rcv_saddr);
- }
- goto out;
- }
-
- if (addr_type&IPV6_ADDR_LINKLOCAL) {
- if (addr_len >= sizeof(struct sockaddr_in6) &&
- usin->sin6_scope_id) {
- if (sk->sk_bound_dev_if &&
- sk->sk_bound_dev_if != usin->sin6_scope_id) {
- err = -EINVAL;
- goto out;
- }
- sk->sk_bound_dev_if = usin->sin6_scope_id;
- if (!sk->sk_bound_dev_if &&
- (addr_type & IPV6_ADDR_MULTICAST))
- fl.oif = np->mcast_oif;
- }
-
- /* Connect to link-local address requires an interface */
- if (!sk->sk_bound_dev_if) {
- err = -EINVAL;
- goto out;
- }
- }
-
- ipv6_addr_copy(&np->daddr, daddr);
- np->flow_label = fl.fl6_flowlabel;
-
- inet->dport = usin->sin6_port;
-
- /*
- * Check for a route to destination an obtain the
- * destination cache for it.
- */
-
- fl.proto = IPPROTO_UDP;
- ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
- ipv6_addr_copy(&fl.fl6_src, &np->saddr);
- fl.oif = sk->sk_bound_dev_if;
- fl.fl_ip_dport = inet->dport;
- fl.fl_ip_sport = inet->sport;
-
- if (!fl.oif && (addr_type&IPV6_ADDR_MULTICAST))
- fl.oif = np->mcast_oif;
-
- if (flowlabel) {
- if (flowlabel->opt && flowlabel->opt->srcrt) {
- struct rt0_hdr *rt0 = (struct rt0_hdr *) flowlabel->opt->srcrt;
- ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
- }
- } else if (np->opt && np->opt->srcrt) {
- struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt;
- ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
- }
-
- err = ip6_dst_lookup(sk, &dst, &fl);
- if (err)
- goto out;
-
- /* source address lookup done in ip6_dst_lookup */
-
- if (ipv6_addr_any(&np->saddr))
- ipv6_addr_copy(&np->saddr, &fl.fl6_src);
-
- if (ipv6_addr_any(&np->rcv_saddr)) {
- ipv6_addr_copy(&np->rcv_saddr, &fl.fl6_src);
- inet->rcv_saddr = LOOPBACK4_IPV6;
- }
-
- ip6_dst_store(sk, dst,
- !ipv6_addr_cmp(&fl.fl6_dst, &np->daddr) ?
- &np->daddr : NULL);
-
- sk->sk_state = TCP_ESTABLISHED;
-out:
- fl6_sock_release(flowlabel);
- return err;
-}
-
static void udpv6_close(struct sock *sk, long timeout)
{
sk_common_release(sk);
@@ -1174,7 +1022,7 @@ void udp6_proc_exit(void) {
struct proto udpv6_prot = {
.name = "UDP",
.close = udpv6_close,
- .connect = udpv6_connect,
+ .connect = ip6_datagram_connect,
.disconnect = udp_disconnect,
.ioctl = udp_ioctl,
.destroy = udpv6_destroy_sock,