mptcp: Don't call mptcp_lookup_join on every SYN for IPv4

Use the options parsed for a normal SYN to check if this is a SYN+MP_JOIN.
This avoid parsing the options multiple times searching for MP_JOIN and reuses some of the normal TCP code.
The initial handling code is still present in case a SYN is sent to a socket that is not listening.

Signed-off-by: Mihai P. Andrei <mihai.p.andrei@intel.com>
Signed-off-by: Christoph Paasch <christoph.paasch@uclouvain.be>
mptcp: Minor coding style fixes

Minor coding style fixes for the patch "Don't call mptcp_lookup_join on every SYN for IPv4".

Signed-off-by: Mihai P. Andrei <mihai.p.andrei@intel.com>
Signed-off-by: Christoph Paasch <christoph.paasch@uclouvain.be>
mptcp: Don't call mptcp_lookup_join on every SYN for IPv6

Same changes as for IPv4 are applied to IPv6 functions.

Signed-off-by: Mihai P. Andrei <mihai.p.andrei@intel.com>
Signed-off-by: Christoph Paasch <christoph.paasch@uclouvain.be>
Fix: Correctly initialize security on meta-sk

When creating the meta-sk we have also to set the sk_security-pointer.
Otherwise he will be pointing to the one from the master_sk and will
thus get free'd twice at the end.

Reporde-by: Stephen Hankinson <stephen.hankinson@quarkengineering.com>
Signed-off-by: Christoph Paasch <christoph.paasch@uclouvain.be>
Handle rcv_ssthresh at the meta-level

Signed-off-by: Christoph Paasch <christoph.paasch@uclouvain.be>
Fix: Set pushed_seq and snd_up in mptcp_alloc_mpcb

pushed_seq and snd_up were not initialized correctly in the meta-sk.

Signed-off-by: Christoph Paasch <christoph.paasch@uclouvain.be>
Initialize snd_wl1 and snd_wnd in mptcp_alloc_mpcb

This simplifies a little bit the window-code.

Signed-off-by: Christoph Paasch <christoph.paasch@uclouvain.be>
Set advmss in mptcp_alloc_mpcb

Signed-off-by: Christoph Paasch <christoph.paasch@uclouvain.be>
Cleanup usage of mptcp_update_window_clamp

Signed-off-by: Christoph Paasch <christoph.paasch@uclouvain.be>
Make the rcvbuf fully handled at the meta-level

With the previous design, where tcp_rcv_space_adjust was called on the
subsocket, as soon as copied-seq changed, it behaved as if the
application is reading at infinite speed. Because segments are always
directly taken out of the subflow-receive-queue.

We have to calculate the receive-buffer at the meta-level, taking into
account the application-speed.

This patch fixes this, by calling tcp_rcv_space_adjust on the
meta-socket.

Signed-off-by: Christoph Paasch <christoph.paasch@uclouvain.be>
Restore the old tcp_prequeue

We now add the packets in the meta-level prequeue. This largely
simplifies the code, is safer in terms of receive-buffer-handling and
reduces cpu-cycles as we don't anymore have to iterate over all sockets
in tcp_recvmsg.

Signed-off-by: Christoph Paasch <christoph.paasch@uclouvain.be>
Review buffer-handling when new subflows are added.

We just add the new subflow's rcv-buffer and window-clamp to the
meta-buffer. This allows traffic on the new subflow. Auto-tuning will
later further increase the meta-buffer to allow full speed on the new
subflow.

Signed-off-by: Christoph Paasch <christoph.paasch@uclouvain.be>
Cleanup tcp_copy_to_iovec

Signed-off-by: Christoph Paasch <christoph.paasch@uclouvain.be>
Cleanup: remove some old exports

Signed-off-by: Christoph Paasch <christoph.paasch@uclouvain.be>
Cleanup: Restore old tcp_openreq_init

Signed-off-by: Christoph Paasch <christoph.paasch@uclouvain.be>
Remove BUG() in address-handler

It may be, that the user-space tries to add twice the same address. This
will still generate a net-event. Even if it doesn't has an impact on the
interface-configuration itself.

We would then crash, because the address is already in the list. Adding
twice the same address is maybe not very smart from the user-space, but
he is allowed to do so.

Signed-off-by: Christoph Paasch <christoph.paasch@uclouvain.be>
Call sock_rps_record_flow in mptcp_v*_do_rcv

A call to sock_rps_record_flow was added to mptcp_v*_do_rcv in order to
mimic what is done in tcp_v*_do_rcv. This allows to enable RPS directly
for new subflows when receiving the third ack and not after receiving
the first data segment.

Signed-off-by: Gregory Detal <gregory.detal@uclouvain.be>
Signed-off-by: Christoph Paasch <christoph.paasch@uclouvain.be>
UBUNTU: Start new release

Ignore: yes
Signed-off-by: Luis Henriques <luis.henriques@canonical.com>
UBUNTU: Bump ABI

Ignore: yes
Signed-off-by: Luis Henriques <luis.henriques@canonical.com>
rds: set correct msg_namelen

CVE-2012-3430

BugLink: http://bugs.launchpad.net/bugs/1031112

Jay Fenlason (fenlason@redhat.com) found a bug,
that recvfrom() on an RDS socket can return the contents of random kernel
memory to userspace if it was called with a address length larger than
sizeof(struct sockaddr_in).
rds_recvmsg() also fails to set the addr_len paramater properly before
returning, but that's just a bug.
There are also a number of cases wher recvfrom() can return an entirely bogus
address. Anything in rds_recvmsg() that returns a non-negative value but does
not go through the "sin = (struct sockaddr_in *)msg->msg_name;" code path
at the end of the while(1) loop will return up to 128 bytes of kernel memory
to userspace.

And I write two test programs to reproduce this bug, you will see that in
rds_server, fromAddr will be overwritten and the following sock_fd will be
destroyed.
Yes, it is the programmer's fault to set msg_namelen incorrectly, but it is
better to make the kernel copy the real length of address to user space in
such case.

How to run the test programs ?
I test them on 32bit x86 system, 3.5.0-rc7.

1 compile
gcc -o rds_client rds_client.c
gcc -o rds_server rds_server.c

2 run ./rds_server on one console

3 run ./rds_client on another console

4 you will see something like:
server is waiting to receive data...
old socket fd=3
server received data from client:data from client
msg.msg_namelen=32
new socket fd=-1067277685
sendmsg()
: Bad file descriptor

/***************** rds_client.c ********************/

int main(void)
{
	int sock_fd;
	struct sockaddr_in serverAddr;
	struct sockaddr_in toAddr;
	char recvBuffer[128] = "data from client";
	struct msghdr msg;
	struct iovec iov;

	sock_fd = socket(AF_RDS, SOCK_SEQPACKET, 0);
	if (sock_fd < 0) {
		perror("create socket error\n");
		exit(1);
	}

	memset(&serverAddr, 0, sizeof(serverAddr));
	serverAddr.sin_family = AF_INET;
	serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
	serverAddr.sin_port = htons(4001);

	if (bind(sock_fd, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) < 0) {
		perror("bind() error\n");
		close(sock_fd);
		exit(1);
	}

	memset(&toAddr, 0, sizeof(toAddr));
	toAddr.sin_family = AF_INET;
	toAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
	toAddr.sin_port = htons(4000);
	msg.msg_name = &toAddr;
	msg.msg_namelen = sizeof(toAddr);
	msg.msg_iov = &iov;
	msg.msg_iovlen = 1;
	msg.msg_iov->iov_base = recvBuffer;
	msg.msg_iov->iov_len = strlen(recvBuffer) + 1;
	msg.msg_control = 0;
	msg.msg_controllen = 0;
	msg.msg_flags = 0;

	if (sendmsg(sock_fd, &msg, 0) == -1) {
		perror("sendto() error\n");
		close(sock_fd);
		exit(1);
	}

	printf("client send data:%s\n", recvBuffer);

	memset(recvBuffer, '\0', 128);

	msg.msg_name = &toAddr;
	msg.msg_namelen = sizeof(toAddr);
	msg.msg_iov = &iov;
	msg.msg_iovlen = 1;
	msg.msg_iov->iov_base = recvBuffer;
	msg.msg_iov->iov_len = 128;
	msg.msg_control = 0;
	msg.msg_controllen = 0;
	msg.msg_flags = 0;
	if (recvmsg(sock_fd, &msg, 0) == -1) {
		perror("recvmsg() error\n");
		close(sock_fd);
		exit(1);
	}

	printf("receive data from server:%s\n", recvBuffer);

	close(sock_fd);

	return 0;
}

/***************** rds_server.c ********************/

int main(void)
{
	struct sockaddr_in fromAddr;
	int sock_fd;
	struct sockaddr_in serverAddr;
	unsigned int addrLen;
	char recvBuffer[128];
	struct msghdr msg;
	struct iovec iov;

	sock_fd = socket(AF_RDS, SOCK_SEQPACKET, 0);
	if(sock_fd < 0) {
		perror("create socket error\n");
		exit(0);
	}

	memset(&serverAddr, 0, sizeof(serverAddr));
	serverAddr.sin_family = AF_INET;
	serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
	serverAddr.sin_port = htons(4000);
	if (bind(sock_fd, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) < 0) {
		perror("bind error\n");
		close(sock_fd);
		exit(1);
	}

	printf("server is waiting to receive data...\n");
	msg.msg_name = &fromAddr;

	/*
	 * I add 16 to sizeof(fromAddr), ie 32,
	 * and pay attention to the definition of fromAddr,
	 * recvmsg() will overwrite sock_fd,
	 * since kernel will copy 32 bytes to userspace.
	 *
	 * If you just use sizeof(fromAddr), it works fine.
	 * */
	msg.msg_namelen = sizeof(fromAddr) + 16;
	/* msg.msg_namelen = sizeof(fromAddr); */
	msg.msg_iov = &iov;
	msg.msg_iovlen = 1;
	msg.msg_iov->iov_base = recvBuffer;
	msg.msg_iov->iov_len = 128;
	msg.msg_control = 0;
	msg.msg_controllen = 0;
	msg.msg_flags = 0;

	while (1) {
		printf("old socket fd=%d\n", sock_fd);
		if (recvmsg(sock_fd, &msg, 0) == -1) {
			perror("recvmsg() error\n");
			close(sock_fd);
			exit(1);
		}
		printf("server received data from client:%s\n", recvBuffer);
		printf("msg.msg_namelen=%d\n", msg.msg_namelen);
		printf("new socket fd=%d\n", sock_fd);
		strcat(recvBuffer, "--data from server");
		if (sendmsg(sock_fd, &msg, 0) == -1) {
			perror("sendmsg()\n");
			close(sock_fd);
			exit(1);
		}
	}

	close(sock_fd);
	return 0;
}

Signed-off-by: Weiping Pan <wpan@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
(cherry picked from commit 06b6a1cf6e776426766298d055bb3991957d90a7)
Signed-off-by: Brad Figg <brad.figg@canonical.com>
Signed-off-by: Tim Gardner <tim.gardner@canonical.com>