ethertap_user.c 6.1 KB
Newer Older
L
Linus Torvalds 已提交
1
/*
J
Jeff Dike 已提交
2
 * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
J
Jeff Dike 已提交
3
 * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and
L
Linus Torvalds 已提交
4 5 6 7 8 9 10
 * James Leu (jleu@mindspring.net).
 * Copyright (C) 2001 by various other people who didn't put their name here.
 * Licensed under the GPL.
 */

#include <stdio.h>
#include <unistd.h>
J
Jeff Dike 已提交
11 12
#include <errno.h>
#include <string.h>
L
Linus Torvalds 已提交
13 14 15
#include <sys/socket.h>
#include <sys/wait.h>
#include "etap.h"
J
Jeff Dike 已提交
16
#include "kern_constants.h"
L
Linus Torvalds 已提交
17
#include "os.h"
J
Jeff Dike 已提交
18
#include "net_user.h"
19
#include "um_malloc.h"
J
Jeff Dike 已提交
20
#include "user.h"
L
Linus Torvalds 已提交
21 22 23

#define MAX_PACKET ETH_MAX_PACKET

24
static int etap_user_init(void *data, void *dev)
L
Linus Torvalds 已提交
25 26 27 28
{
	struct ethertap_data *pri = data;

	pri->dev = dev;
29
	return 0;
L
Linus Torvalds 已提交
30 31 32 33 34 35 36 37 38 39 40 41
}

struct addr_change {
	enum { ADD_ADDR, DEL_ADDR } what;
	unsigned char addr[4];
	unsigned char netmask[4];
};

static void etap_change(int op, unsigned char *addr, unsigned char *netmask,
			int fd)
{
	struct addr_change change;
42
	char *output;
L
Linus Torvalds 已提交
43 44 45 46 47
	int n;

	change.what = op;
	memcpy(change.addr, addr, sizeof(change.addr));
	memcpy(change.netmask, netmask, sizeof(change.netmask));
48
	CATCH_EINTR(n = write(fd, &change, sizeof(change)));
J
Jeff Dike 已提交
49 50 51
	if (n != sizeof(change)) {
		printk(UM_KERN_ERR "etap_change - request failed, err = %d\n",
		       errno);
J
Jeff Dike 已提交
52 53 54
		return;
	}

55
	output = kmalloc(UM_KERN_PAGE_SIZE, UM_GFP_KERNEL);
J
Jeff Dike 已提交
56 57 58
	if (output == NULL)
		printk(UM_KERN_ERR "etap_change : Failed to allocate output "
		       "buffer\n");
J
Jeff Dike 已提交
59
	read_output(fd, output, UM_KERN_PAGE_SIZE);
J
Jeff Dike 已提交
60
	if (output != NULL) {
L
Linus Torvalds 已提交
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
		printk("%s", output);
		kfree(output);
	}
}

static void etap_open_addr(unsigned char *addr, unsigned char *netmask,
			   void *arg)
{
	etap_change(ADD_ADDR, addr, netmask, *((int *) arg));
}

static void etap_close_addr(unsigned char *addr, unsigned char *netmask,
			    void *arg)
{
	etap_change(DEL_ADDR, addr, netmask, *((int *) arg));
}

struct etap_pre_exec_data {
	int control_remote;
	int control_me;
	int data_me;
};

static void etap_pre_exec(void *arg)
{
	struct etap_pre_exec_data *data = arg;

	dup2(data->control_remote, 1);
89 90
	close(data->data_me);
	close(data->control_me);
L
Linus Torvalds 已提交
91 92
}

93
static int etap_tramp(char *dev, char *gate, int control_me,
L
Linus Torvalds 已提交
94 95 96 97 98 99 100 101 102
		      int control_remote, int data_me, int data_remote)
{
	struct etap_pre_exec_data pe_data;
	int pid, status, err, n;
	char version_buf[sizeof("nnnnn\0")];
	char data_fd_buf[sizeof("nnnnnn\0")];
	char gate_buf[sizeof("nnn.nnn.nnn.nnn\0")];
	char *setup_args[] = { "uml_net", version_buf, "ethertap", dev,
			       data_fd_buf, gate_buf, NULL };
103
	char *nosetup_args[] = { "uml_net", version_buf, "ethertap",
L
Linus Torvalds 已提交
104 105 106 107 108
				 dev, data_fd_buf, NULL };
	char **args, c;

	sprintf(data_fd_buf, "%d", data_remote);
	sprintf(version_buf, "%d", UML_NET_VERSION);
J
Jeff Dike 已提交
109
	if (gate != NULL) {
L
Linus Torvalds 已提交
110 111 112 113 114 115 116 117 118
		strcpy(gate_buf, gate);
		args = setup_args;
	}
	else args = nosetup_args;

	err = 0;
	pe_data.control_remote = control_remote;
	pe_data.control_me = control_me;
	pe_data.data_me = data_me;
J
Jeff Dike 已提交
119
	pid = run_helper(etap_pre_exec, &pe_data, args);
L
Linus Torvalds 已提交
120

J
Jeff Dike 已提交
121
	if (pid < 0)
J
Jeff Dike 已提交
122
		err = pid;
123 124
	close(data_remote);
	close(control_remote);
125
	CATCH_EINTR(n = read(control_me, &c, sizeof(c)));
J
Jeff Dike 已提交
126
	if (n != sizeof(c)) {
127
		err = -errno;
J
Jeff Dike 已提交
128 129
		printk(UM_KERN_ERR "etap_tramp : read of status failed, "
		       "err = %d\n", -err);
130
		return err;
L
Linus Torvalds 已提交
131
	}
J
Jeff Dike 已提交
132 133
	if (c != 1) {
		printk(UM_KERN_ERR "etap_tramp : uml_net failed\n");
L
Linus Torvalds 已提交
134 135
		err = -EINVAL;
		CATCH_EINTR(n = waitpid(pid, &status, 0));
J
Jeff Dike 已提交
136
		if (n < 0)
L
Linus Torvalds 已提交
137
			err = -errno;
J
Jeff Dike 已提交
138 139 140
		else if (!WIFEXITED(status) || (WEXITSTATUS(status) != 1))
			printk(UM_KERN_ERR "uml_net didn't exit with "
			       "status 1\n");
L
Linus Torvalds 已提交
141
	}
J
Jeff Dike 已提交
142
	return err;
L
Linus Torvalds 已提交
143 144 145 146 147 148 149 150 151
}

static int etap_open(void *data)
{
	struct ethertap_data *pri = data;
	char *output;
	int data_fds[2], control_fds[2], err, output_len;

	err = tap_open_common(pri->dev, pri->gate_addr);
J
Jeff Dike 已提交
152
	if (err)
J
Jeff Dike 已提交
153
		return err;
L
Linus Torvalds 已提交
154

155
	err = socketpair(AF_UNIX, SOCK_DGRAM, 0, data_fds);
J
Jeff Dike 已提交
156
	if (err) {
157
		err = -errno;
J
Jeff Dike 已提交
158 159
		printk(UM_KERN_ERR "etap_open - data socketpair failed - "
		       "err = %d\n", errno);
J
Jeff Dike 已提交
160
		return err;
L
Linus Torvalds 已提交
161 162
	}

163
	err = socketpair(AF_UNIX, SOCK_STREAM, 0, control_fds);
J
Jeff Dike 已提交
164
	if (err) {
165
		err = -errno;
J
Jeff Dike 已提交
166 167
		printk(UM_KERN_ERR "etap_open - control socketpair failed - "
		       "err = %d\n", errno);
168
		goto out_close_data;
L
Linus Torvalds 已提交
169
	}
J
Jeff Dike 已提交
170

171
	err = etap_tramp(pri->dev_name, pri->gate_addr, control_fds[0],
L
Linus Torvalds 已提交
172
			 control_fds[1], data_fds[0], data_fds[1]);
J
Jeff Dike 已提交
173
	output_len = UM_KERN_PAGE_SIZE;
174
	output = kmalloc(output_len, UM_GFP_KERNEL);
L
Linus Torvalds 已提交
175 176
	read_output(control_fds[0], output, output_len);

J
Jeff Dike 已提交
177 178 179
	if (output == NULL)
		printk(UM_KERN_ERR "etap_open : failed to allocate output "
		       "buffer\n");
L
Linus Torvalds 已提交
180 181 182 183 184
	else {
		printk("%s", output);
		kfree(output);
	}

J
Jeff Dike 已提交
185 186
	if (err < 0) {
		printk(UM_KERN_ERR "etap_tramp failed - err = %d\n", -err);
187
		goto out_close_control;
L
Linus Torvalds 已提交
188 189 190 191 192
	}

	pri->data_fd = data_fds[0];
	pri->control_fd = control_fds[0];
	iter_addresses(pri->dev, etap_open_addr, &pri->control_fd);
J
Jeff Dike 已提交
193
	return data_fds[0];
194 195 196 197 198 199 200 201

out_close_control:
	close(control_fds[0]);
	close(control_fds[1]);
out_close_data:
	close(data_fds[0]);
	close(data_fds[1]);
	return err;
L
Linus Torvalds 已提交
202 203 204 205 206 207 208
}

static void etap_close(int fd, void *data)
{
	struct ethertap_data *pri = data;

	iter_addresses(pri->dev, etap_close_addr, &pri->control_fd);
209 210
	close(fd);

J
Jeff Dike 已提交
211 212
	if (shutdown(pri->data_fd, SHUT_RDWR) < 0)
		printk(UM_KERN_ERR "etap_close - shutdown data socket failed, "
213 214
		       "errno = %d\n", errno);

J
Jeff Dike 已提交
215 216 217 218
	if (shutdown(pri->control_fd, SHUT_RDWR) < 0)
		printk(UM_KERN_ERR "etap_close - shutdown control socket "
		       "failed, errno = %d\n", errno);

219
	close(pri->data_fd);
L
Linus Torvalds 已提交
220
	pri->data_fd = -1;
221
	close(pri->control_fd);
L
Linus Torvalds 已提交
222 223 224 225 226 227 228 229 230
	pri->control_fd = -1;
}

static void etap_add_addr(unsigned char *addr, unsigned char *netmask,
			  void *data)
{
	struct ethertap_data *pri = data;

	tap_check_ips(pri->gate_addr, addr);
J
Jeff Dike 已提交
231
	if (pri->control_fd == -1)
J
Jeff Dike 已提交
232
		return;
L
Linus Torvalds 已提交
233 234 235
	etap_open_addr(addr, netmask, &pri->control_fd);
}

236
static void etap_del_addr(unsigned char *addr, unsigned char *netmask,
L
Linus Torvalds 已提交
237 238 239 240
			  void *data)
{
	struct ethertap_data *pri = data;

J
Jeff Dike 已提交
241
	if (pri->control_fd == -1)
J
Jeff Dike 已提交
242
		return;
243

L
Linus Torvalds 已提交
244 245 246
	etap_close_addr(addr, netmask, &pri->control_fd);
}

J
Jeff Dike 已提交
247
const struct net_user_info ethertap_user_info = {
L
Linus Torvalds 已提交
248 249 250 251 252 253
	.init		= etap_user_init,
	.open		= etap_open,
	.close	 	= etap_close,
	.remove	 	= NULL,
	.add_address	= etap_add_addr,
	.delete_address = etap_del_addr,
J
Jeff Dike 已提交
254 255
	.mtu		= ETH_MAX_PACKET,
	.max_packet	= ETH_MAX_PACKET + ETH_HEADER_ETHERTAP,
L
Linus Torvalds 已提交
256
};