Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 32519f11 authored by Arnaldo Carvalho de Melo's avatar Arnaldo Carvalho de Melo Committed by David S. Miller
Browse files

[INET]: Introduce inet_sk_rebuild_header



From tcp_v4_rebuild_header, that already was pretty generic, I only
needed to use sk->sk_protocol instead of the hardcoded IPPROTO_TCP and
establish the requirement that INET transport layer protocols that
want to use this function map TCP_SYN_SENT to its equivalent state.

Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@ghostprotocols.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 6cbb0df7
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -196,6 +196,8 @@ static inline void inet_sk_copy_descendant(struct sock *sk_to,
#endif
#endif

extern int inet_sk_rebuild_header(struct sock *sk);

struct iphdr {
#if defined(__LITTLE_ENDIAN_BITFIELD)
	__u8	ihl:4,
+0 −2
Original line number Diff line number Diff line
@@ -799,8 +799,6 @@ extern void tcp_parse_options(struct sk_buff *skb,
 *	TCP v4 functions exported for the inet6 API
 */

extern int		       	tcp_v4_rebuild_header(struct sock *sk);

extern int		       	tcp_v4_build_header(struct sock *sk, 
						    struct sk_buff *skb);

+113 −0
Original line number Diff line number Diff line
@@ -951,6 +951,119 @@ void inet_unregister_protosw(struct inet_protosw *p)
	}
}

/*
 *      Shall we try to damage output packets if routing dev changes?
 */

int sysctl_ip_dynaddr;

static int inet_sk_reselect_saddr(struct sock *sk)
{
	struct inet_sock *inet = inet_sk(sk);
	int err;
	struct rtable *rt;
	__u32 old_saddr = inet->saddr;
	__u32 new_saddr;
	__u32 daddr = inet->daddr;

	if (inet->opt && inet->opt->srr)
		daddr = inet->opt->faddr;

	/* Query new route. */
	err = ip_route_connect(&rt, daddr, 0,
			       RT_CONN_FLAGS(sk),
			       sk->sk_bound_dev_if,
			       sk->sk_protocol,
			       inet->sport, inet->dport, sk);
	if (err)
		return err;

	sk_setup_caps(sk, &rt->u.dst);

	new_saddr = rt->rt_src;

	if (new_saddr == old_saddr)
		return 0;

	if (sysctl_ip_dynaddr > 1) {
		printk(KERN_INFO "%s(): shifting inet->"
				 "saddr from %d.%d.%d.%d to %d.%d.%d.%d\n",
		       __FUNCTION__,
		       NIPQUAD(old_saddr),
		       NIPQUAD(new_saddr));
	}

	inet->saddr = inet->rcv_saddr = new_saddr;

	/*
	 * XXX The only one ugly spot where we need to
	 * XXX really change the sockets identity after
	 * XXX it has entered the hashes. -DaveM
	 *
	 * Besides that, it does not check for connection
	 * uniqueness. Wait for troubles.
	 */
	__sk_prot_rehash(sk);
	return 0;
}

int inet_sk_rebuild_header(struct sock *sk)
{
	struct inet_sock *inet = inet_sk(sk);
	struct rtable *rt = (struct rtable *)__sk_dst_check(sk, 0);
	u32 daddr;
	int err;

	/* Route is OK, nothing to do. */
	if (rt)
		return 0;

	/* Reroute. */
	daddr = inet->daddr;
	if (inet->opt && inet->opt->srr)
		daddr = inet->opt->faddr;
{
	struct flowi fl = {
		.oif = sk->sk_bound_dev_if,
		.nl_u = {
			.ip4_u = {
				.daddr	= daddr,
				.saddr	= inet->saddr,
				.tos	= RT_CONN_FLAGS(sk),
			},
		},
		.proto = sk->sk_protocol,
		.uli_u = {
			.ports = {
				.sport = inet->sport,
				.dport = inet->dport,
			},
		},
	};
						
	err = ip_route_output_flow(&rt, &fl, sk, 0);
}
	if (!err)
		sk_setup_caps(sk, &rt->u.dst);
	else {
		/* Routing failed... */
		sk->sk_route_caps = 0;
		/*
		 * Other protocols have to map its equivalent state to TCP_SYN_SENT.
		 * DCCP maps its DCCP_REQUESTING state to TCP_SYN_SENT. -acme
		 */
		if (!sysctl_ip_dynaddr ||
		    sk->sk_state != TCP_SYN_SENT ||
		    (sk->sk_userlocks & SOCK_BINDADDR_LOCK) ||
		    (err = inet_sk_reselect_saddr(sk)) != 0)
			sk->sk_err_soft = -err;
	}

	return err;
}

EXPORT_SYMBOL(inet_sk_rebuild_header);

#ifdef CONFIG_IP_MULTICAST
static struct net_protocol igmp_protocol = {
	.handler =	igmp_rcv,
+0 −5
Original line number Diff line number Diff line
@@ -83,11 +83,6 @@
#include <linux/netlink.h>
#include <linux/tcp.h>

/*
 *      Shall we try to damage output packets if routing dev changes?
 */

int sysctl_ip_dynaddr;
int sysctl_ip_default_ttl = IPDEFTTL;

/* Generate a checksum for an outgoing IP datagram. */
+1 −97
Original line number Diff line number Diff line
@@ -1832,101 +1832,6 @@ int tcp_v4_rcv(struct sk_buff *skb)
	goto discard_it;
}

static int tcp_v4_reselect_saddr(struct sock *sk)
{
	struct inet_sock *inet = inet_sk(sk);
	int err;
	struct rtable *rt;
	__u32 old_saddr = inet->saddr;
	__u32 new_saddr;
	__u32 daddr = inet->daddr;

	if (inet->opt && inet->opt->srr)
		daddr = inet->opt->faddr;

	/* Query new route. */
	err = ip_route_connect(&rt, daddr, 0,
			       RT_CONN_FLAGS(sk),
			       sk->sk_bound_dev_if,
			       IPPROTO_TCP,
			       inet->sport, inet->dport, sk);
	if (err)
		return err;

	sk_setup_caps(sk, &rt->u.dst);

	new_saddr = rt->rt_src;

	if (new_saddr == old_saddr)
		return 0;

	if (sysctl_ip_dynaddr > 1) {
		printk(KERN_INFO "tcp_v4_rebuild_header(): shifting inet->"
				 "saddr from %d.%d.%d.%d to %d.%d.%d.%d\n",
		       NIPQUAD(old_saddr),
		       NIPQUAD(new_saddr));
	}

	inet->saddr = new_saddr;
	inet->rcv_saddr = new_saddr;

	/* XXX The only one ugly spot where we need to
	 * XXX really change the sockets identity after
	 * XXX it has entered the hashes. -DaveM
	 *
	 * Besides that, it does not check for connection
	 * uniqueness. Wait for troubles.
	 */
	__sk_prot_rehash(sk);
	return 0;
}

int tcp_v4_rebuild_header(struct sock *sk)
{
	struct inet_sock *inet = inet_sk(sk);
	struct rtable *rt = (struct rtable *)__sk_dst_check(sk, 0);
	u32 daddr;
	int err;

	/* Route is OK, nothing to do. */
	if (rt)
		return 0;

	/* Reroute. */
	daddr = inet->daddr;
	if (inet->opt && inet->opt->srr)
		daddr = inet->opt->faddr;

	{
		struct flowi fl = { .oif = sk->sk_bound_dev_if,
				    .nl_u = { .ip4_u =
					      { .daddr = daddr,
						.saddr = inet->saddr,
						.tos = RT_CONN_FLAGS(sk) } },
				    .proto = IPPROTO_TCP,
				    .uli_u = { .ports =
					       { .sport = inet->sport,
						 .dport = inet->dport } } };
						
		err = ip_route_output_flow(&rt, &fl, sk, 0);
	}
	if (!err) {
		sk_setup_caps(sk, &rt->u.dst);
		return 0;
	}

	/* Routing failed... */
	sk->sk_route_caps = 0;

	if (!sysctl_ip_dynaddr ||
	    sk->sk_state != TCP_SYN_SENT ||
	    (sk->sk_userlocks & SOCK_BINDADDR_LOCK) ||
	    (err = tcp_v4_reselect_saddr(sk)) != 0)
		sk->sk_err_soft = -err;

	return err;
}

static void v4_addr2sockaddr(struct sock *sk, struct sockaddr * uaddr)
{
	struct sockaddr_in *sin = (struct sockaddr_in *) uaddr;
@@ -1998,7 +1903,7 @@ int tcp_v4_tw_remember_stamp(struct tcp_tw_bucket *tw)
struct tcp_func ipv4_specific = {
	.queue_xmit	=	ip_queue_xmit,
	.send_check	=	tcp_v4_send_check,
	.rebuild_header	=	tcp_v4_rebuild_header,
	.rebuild_header	=	inet_sk_rebuild_header,
	.conn_request	=	tcp_v4_conn_request,
	.syn_recv_sock	=	tcp_v4_syn_recv_sock,
	.remember_stamp	=	tcp_v4_remember_stamp,
@@ -2630,7 +2535,6 @@ EXPORT_SYMBOL(tcp_unhash);
EXPORT_SYMBOL(tcp_v4_conn_request);
EXPORT_SYMBOL(tcp_v4_connect);
EXPORT_SYMBOL(tcp_v4_do_rcv);
EXPORT_SYMBOL(tcp_v4_rebuild_header);
EXPORT_SYMBOL(tcp_v4_remember_stamp);
EXPORT_SYMBOL(tcp_v4_send_check);
EXPORT_SYMBOL(tcp_v4_syn_recv_sock);
Loading