2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
|
|
|
|
* Licensed under the GPL
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stddef.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <sys/wait.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/un.h>
|
|
|
|
#include <sys/uio.h>
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <net/if.h>
|
|
|
|
#include <linux/if_tun.h>
|
|
|
|
#include "net_user.h"
|
|
|
|
#include "tuntap.h"
|
|
|
|
#include "kern_util.h"
|
|
|
|
#include "user.h"
|
|
|
|
#include "os.h"
|
|
|
|
|
|
|
|
#define MAX_PACKET ETH_MAX_PACKET
|
|
|
|
|
uml: network interface hotplug error handling
This fixes a number of problems associated with network interface hotplug.
The userspace initialization function can fail in some cases, but the
failure was never passed back to eth_configure, which proceeded with the
configuration. This results in a zombie device that is present, but can't
work. This is fixed by allowing the initialization routines to return an
error, which is checked, and the configuration aborted on failure.
eth_configure failed to check for many failures. Even when it did check,
it didn't undo whatever initializations has already happened, so a present,
but partially initialized and non-working device could result. It now
checks everything that can fail, and bails out, undoing whatever had been
done.
The return value of eth_configure was always ignored, so it is now just
void.
Signed-off-by: Jeff Dike <jdike@linux.intel.com>
Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
Cc: Jeff Garzik <jeff@garzik.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-05-07 05:51:04 +08:00
|
|
|
static int tuntap_user_init(void *data, void *dev)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
struct tuntap_data *pri = data;
|
|
|
|
|
|
|
|
pri->dev = dev;
|
uml: network interface hotplug error handling
This fixes a number of problems associated with network interface hotplug.
The userspace initialization function can fail in some cases, but the
failure was never passed back to eth_configure, which proceeded with the
configuration. This results in a zombie device that is present, but can't
work. This is fixed by allowing the initialization routines to return an
error, which is checked, and the configuration aborted on failure.
eth_configure failed to check for many failures. Even when it did check,
it didn't undo whatever initializations has already happened, so a present,
but partially initialized and non-working device could result. It now
checks everything that can fail, and bails out, undoing whatever had been
done.
The return value of eth_configure was always ignored, so it is now just
void.
Signed-off-by: Jeff Dike <jdike@linux.intel.com>
Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
Cc: Jeff Garzik <jeff@garzik.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-05-07 05:51:04 +08:00
|
|
|
return 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void tuntap_add_addr(unsigned char *addr, unsigned char *netmask,
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
struct tuntap_data *pri = data;
|
|
|
|
|
|
|
|
tap_check_ips(pri->gate_addr, addr);
|
2007-05-07 05:51:02 +08:00
|
|
|
if((pri->fd == -1) || pri->fixed_config)
|
|
|
|
return;
|
2005-04-17 06:20:36 +08:00
|
|
|
open_addr(addr, netmask, pri->dev_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void tuntap_del_addr(unsigned char *addr, unsigned char *netmask,
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
struct tuntap_data *pri = data;
|
|
|
|
|
2007-05-07 05:51:02 +08:00
|
|
|
if((pri->fd == -1) || pri->fixed_config)
|
|
|
|
return;
|
2005-04-17 06:20:36 +08:00
|
|
|
close_addr(addr, netmask, pri->dev_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct tuntap_pre_exec_data {
|
|
|
|
int stdout;
|
|
|
|
int close_me;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void tuntap_pre_exec(void *arg)
|
|
|
|
{
|
|
|
|
struct tuntap_pre_exec_data *data = arg;
|
2007-05-07 05:51:02 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
dup2(data->stdout, 1);
|
|
|
|
os_close_file(data->close_me);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int tuntap_open_tramp(char *gate, int *fd_out, int me, int remote,
|
|
|
|
char *buffer, int buffer_len, int *used_out)
|
|
|
|
{
|
|
|
|
struct tuntap_pre_exec_data data;
|
|
|
|
char version_buf[sizeof("nnnnn\0")];
|
|
|
|
char *argv[] = { "uml_net", version_buf, "tuntap", "up", gate,
|
|
|
|
NULL };
|
|
|
|
char buf[CMSG_SPACE(sizeof(*fd_out))];
|
|
|
|
struct msghdr msg;
|
|
|
|
struct cmsghdr *cmsg;
|
|
|
|
struct iovec iov;
|
[PATCH] uml: preserve errno in error paths
The poster child for this patch is the third tuntap_user hunk. When an ioctl
fails, it properly closes the opened file descriptor and returns. However,
the close resets errno to 0, and the 'return errno' that follows returns 0
rather than the value that ioctl set. This caused the caller to believe that
the device open succeeded and had opened file descriptor 0, which caused no
end of interesting behavior.
The rest of this patch is a pass through the UML sources looking for places
where errno could be reset before being passed back out. A common culprit is
printk, which could call write, being called before errno is returned.
In some cases, where the code ends up being much smaller, I just deleted the
printk.
There was another case where a caller of run_helper looked at errno after a
failure, rather than the return value of run_helper, which was the errno value
that it wanted.
Signed-off-by: Jeff Dike <jdike@addtoit.com>
Cc: Paolo Giarrusso <blaisorblade@yahoo.it>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2005-09-17 10:27:49 +08:00
|
|
|
int pid, n, err;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
sprintf(version_buf, "%d", UML_NET_VERSION);
|
|
|
|
|
|
|
|
data.stdout = remote;
|
|
|
|
data.close_me = me;
|
|
|
|
|
2007-07-16 14:38:56 +08:00
|
|
|
pid = run_helper(tuntap_pre_exec, &data, argv);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-05-07 05:51:02 +08:00
|
|
|
if(pid < 0)
|
|
|
|
return -pid;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
os_close_file(remote);
|
|
|
|
|
|
|
|
msg.msg_name = NULL;
|
|
|
|
msg.msg_namelen = 0;
|
|
|
|
if(buffer != NULL){
|
|
|
|
iov = ((struct iovec) { buffer, buffer_len });
|
|
|
|
msg.msg_iov = &iov;
|
|
|
|
msg.msg_iovlen = 1;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
msg.msg_iov = NULL;
|
|
|
|
msg.msg_iovlen = 0;
|
|
|
|
}
|
|
|
|
msg.msg_control = buf;
|
|
|
|
msg.msg_controllen = sizeof(buf);
|
|
|
|
msg.msg_flags = 0;
|
|
|
|
n = recvmsg(me, &msg, 0);
|
|
|
|
*used_out = n;
|
|
|
|
if(n < 0){
|
[PATCH] uml: preserve errno in error paths
The poster child for this patch is the third tuntap_user hunk. When an ioctl
fails, it properly closes the opened file descriptor and returns. However,
the close resets errno to 0, and the 'return errno' that follows returns 0
rather than the value that ioctl set. This caused the caller to believe that
the device open succeeded and had opened file descriptor 0, which caused no
end of interesting behavior.
The rest of this patch is a pass through the UML sources looking for places
where errno could be reset before being passed back out. A common culprit is
printk, which could call write, being called before errno is returned.
In some cases, where the code ends up being much smaller, I just deleted the
printk.
There was another case where a caller of run_helper looked at errno after a
failure, rather than the return value of run_helper, which was the errno value
that it wanted.
Signed-off-by: Jeff Dike <jdike@addtoit.com>
Cc: Paolo Giarrusso <blaisorblade@yahoo.it>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2005-09-17 10:27:49 +08:00
|
|
|
err = -errno;
|
2005-04-17 06:20:36 +08:00
|
|
|
printk("tuntap_open_tramp : recvmsg failed - errno = %d\n",
|
|
|
|
errno);
|
[PATCH] uml: preserve errno in error paths
The poster child for this patch is the third tuntap_user hunk. When an ioctl
fails, it properly closes the opened file descriptor and returns. However,
the close resets errno to 0, and the 'return errno' that follows returns 0
rather than the value that ioctl set. This caused the caller to believe that
the device open succeeded and had opened file descriptor 0, which caused no
end of interesting behavior.
The rest of this patch is a pass through the UML sources looking for places
where errno could be reset before being passed back out. A common culprit is
printk, which could call write, being called before errno is returned.
In some cases, where the code ends up being much smaller, I just deleted the
printk.
There was another case where a caller of run_helper looked at errno after a
failure, rather than the return value of run_helper, which was the errno value
that it wanted.
Signed-off-by: Jeff Dike <jdike@addtoit.com>
Cc: Paolo Giarrusso <blaisorblade@yahoo.it>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2005-09-17 10:27:49 +08:00
|
|
|
return err;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
CATCH_EINTR(waitpid(pid, NULL, 0));
|
|
|
|
|
|
|
|
cmsg = CMSG_FIRSTHDR(&msg);
|
|
|
|
if(cmsg == NULL){
|
|
|
|
printk("tuntap_open_tramp : didn't receive a message\n");
|
2007-05-07 05:51:02 +08:00
|
|
|
return -EINVAL;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
if((cmsg->cmsg_level != SOL_SOCKET) ||
|
|
|
|
(cmsg->cmsg_type != SCM_RIGHTS)){
|
|
|
|
printk("tuntap_open_tramp : didn't receive a descriptor\n");
|
2007-05-07 05:51:02 +08:00
|
|
|
return -EINVAL;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
*fd_out = ((int *) CMSG_DATA(cmsg))[0];
|
2006-02-08 04:58:41 +08:00
|
|
|
os_set_exec_close(*fd_out, 1);
|
2007-05-07 05:51:02 +08:00
|
|
|
return 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int tuntap_open(void *data)
|
|
|
|
{
|
|
|
|
struct ifreq ifr;
|
|
|
|
struct tuntap_data *pri = data;
|
|
|
|
char *output, *buffer;
|
|
|
|
int err, fds[2], len, used;
|
|
|
|
|
|
|
|
err = tap_open_common(pri->dev, pri->gate_addr);
|
|
|
|
if(err < 0)
|
2007-05-07 05:51:02 +08:00
|
|
|
return err;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
if(pri->fixed_config){
|
2006-02-08 04:58:41 +08:00
|
|
|
pri->fd = os_open_file("/dev/net/tun",
|
|
|
|
of_cloexec(of_rdwr(OPENFLAGS())), 0);
|
2005-04-17 06:20:36 +08:00
|
|
|
if(pri->fd < 0){
|
|
|
|
printk("Failed to open /dev/net/tun, err = %d\n",
|
|
|
|
-pri->fd);
|
2007-05-07 05:51:02 +08:00
|
|
|
return pri->fd;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
memset(&ifr, 0, sizeof(ifr));
|
|
|
|
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
|
|
|
|
strlcpy(ifr.ifr_name, pri->dev_name, sizeof(ifr.ifr_name));
|
|
|
|
if(ioctl(pri->fd, TUNSETIFF, (void *) &ifr) < 0){
|
[PATCH] uml: preserve errno in error paths
The poster child for this patch is the third tuntap_user hunk. When an ioctl
fails, it properly closes the opened file descriptor and returns. However,
the close resets errno to 0, and the 'return errno' that follows returns 0
rather than the value that ioctl set. This caused the caller to believe that
the device open succeeded and had opened file descriptor 0, which caused no
end of interesting behavior.
The rest of this patch is a pass through the UML sources looking for places
where errno could be reset before being passed back out. A common culprit is
printk, which could call write, being called before errno is returned.
In some cases, where the code ends up being much smaller, I just deleted the
printk.
There was another case where a caller of run_helper looked at errno after a
failure, rather than the return value of run_helper, which was the errno value
that it wanted.
Signed-off-by: Jeff Dike <jdike@addtoit.com>
Cc: Paolo Giarrusso <blaisorblade@yahoo.it>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2005-09-17 10:27:49 +08:00
|
|
|
err = -errno;
|
2005-04-17 06:20:36 +08:00
|
|
|
printk("TUNSETIFF failed, errno = %d\n", errno);
|
|
|
|
os_close_file(pri->fd);
|
[PATCH] uml: preserve errno in error paths
The poster child for this patch is the third tuntap_user hunk. When an ioctl
fails, it properly closes the opened file descriptor and returns. However,
the close resets errno to 0, and the 'return errno' that follows returns 0
rather than the value that ioctl set. This caused the caller to believe that
the device open succeeded and had opened file descriptor 0, which caused no
end of interesting behavior.
The rest of this patch is a pass through the UML sources looking for places
where errno could be reset before being passed back out. A common culprit is
printk, which could call write, being called before errno is returned.
In some cases, where the code ends up being much smaller, I just deleted the
printk.
There was another case where a caller of run_helper looked at errno after a
failure, rather than the return value of run_helper, which was the errno value
that it wanted.
Signed-off-by: Jeff Dike <jdike@addtoit.com>
Cc: Paolo Giarrusso <blaisorblade@yahoo.it>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2005-09-17 10:27:49 +08:00
|
|
|
return err;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
err = os_pipe(fds, 0, 0);
|
|
|
|
if(err < 0){
|
|
|
|
printk("tuntap_open : os_pipe failed - err = %d\n",
|
|
|
|
-err);
|
2007-05-07 05:51:02 +08:00
|
|
|
return err;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
buffer = get_output_buffer(&len);
|
|
|
|
if(buffer != NULL) len--;
|
|
|
|
used = 0;
|
|
|
|
|
|
|
|
err = tuntap_open_tramp(pri->gate_addr, &pri->fd, fds[0],
|
|
|
|
fds[1], buffer, len, &used);
|
|
|
|
|
|
|
|
output = buffer;
|
|
|
|
if(err < 0) {
|
|
|
|
printk("%s", output);
|
|
|
|
free_output_buffer(buffer);
|
|
|
|
printk("tuntap_open_tramp failed - err = %d\n", -err);
|
2007-05-07 05:51:02 +08:00
|
|
|
return err;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
pri->dev_name = uml_strdup(buffer);
|
|
|
|
output += IFNAMSIZ;
|
|
|
|
printk("%s", output);
|
|
|
|
free_output_buffer(buffer);
|
|
|
|
|
|
|
|
os_close_file(fds[0]);
|
|
|
|
iter_addresses(pri->dev, open_addr, pri->dev_name);
|
|
|
|
}
|
|
|
|
|
2007-05-07 05:51:02 +08:00
|
|
|
return pri->fd;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void tuntap_close(int fd, void *data)
|
|
|
|
{
|
|
|
|
struct tuntap_data *pri = data;
|
|
|
|
|
|
|
|
if(!pri->fixed_config)
|
|
|
|
iter_addresses(pri->dev, close_addr, pri->dev_name);
|
|
|
|
os_close_file(fd);
|
|
|
|
pri->fd = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int tuntap_set_mtu(int mtu, void *data)
|
|
|
|
{
|
2007-05-07 05:51:02 +08:00
|
|
|
return mtu;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2006-09-27 16:50:33 +08:00
|
|
|
const struct net_user_info tuntap_user_info = {
|
2005-04-17 06:20:36 +08:00
|
|
|
.init = tuntap_user_init,
|
|
|
|
.open = tuntap_open,
|
|
|
|
.close = tuntap_close,
|
|
|
|
.remove = NULL,
|
|
|
|
.set_mtu = tuntap_set_mtu,
|
|
|
|
.add_address = tuntap_add_addr,
|
|
|
|
.delete_address = tuntap_del_addr,
|
|
|
|
.max_packet = MAX_PACKET
|
|
|
|
};
|