summaryrefslogtreecommitdiff
path: root/arch/um/drivers/slirp_user.c
blob: 1865089ff41a41d920eadf082a12e06de893785d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/*
 * Copyright (C) 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
 * Licensed under the GPL.
 */

#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/wait.h>
#include "kern_constants.h"
#include "net_user.h"
#include "os.h"
#include "slirp.h"
#include "user.h"

static int slirp_user_init(void *data, void *dev)
{
	struct slirp_data *pri = data;

	pri->dev = dev;
	return 0;
}

struct slirp_pre_exec_data {
	int stdin;
	int stdout;
};

static void slirp_pre_exec(void *arg)
{
	struct slirp_pre_exec_data *data = arg;

	if (data->stdin != -1)
		dup2(data->stdin, 0);
	if (data->stdout != -1)
		dup2(data->stdout, 1);
}

static int slirp_tramp(char **argv, int fd)
{
	struct slirp_pre_exec_data pe_data;
	int pid;

	pe_data.stdin = fd;
	pe_data.stdout = fd;
	pid = run_helper(slirp_pre_exec, &pe_data, argv);

	return pid;
}

static int slirp_open(void *data)
{
	struct slirp_data *pri = data;
	int fds[2], pid, err;

	err = os_pipe(fds, 1, 1);
	if (err)
		return err;

	err = slirp_tramp(pri->argw.argv, fds[1]);
	if (err < 0) {
		printk(UM_KERN_ERR "slirp_tramp failed - errno = %d\n", -err);
		goto out;
	}
	pid = err;

	pri->slave = fds[1];
	pri->slip.pos = 0;
	pri->slip.esc = 0;
	pri->pid = err;

	return fds[0];
out:
	close(fds[0]);
	close(fds[1]);
	return err;
}

static void slirp_close(int fd, void *data)
{
	struct slirp_data *pri = data;
	int status,err;

	close(fd);
	close(pri->slave);

	pri->slave = -1;

	if (pri->pid<1) {
		printk(UM_KERN_ERR "slirp_close: no child process to shut "
		       "down\n");
		return;
	}

#if 0
	if (kill(pri->pid, SIGHUP)<0) {
		printk(UM_KERN_ERR "slirp_close: sending hangup to %d failed "
		       "(%d)\n", pri->pid, errno);
	}
#endif

	CATCH_EINTR(err = waitpid(pri->pid, &status, WNOHANG));
	if (err < 0) {
		printk(UM_KERN_ERR "slirp_close: waitpid returned %d\n", errno);
		return;
	}

	if (err == 0) {
		printk(UM_KERN_ERR "slirp_close: process %d has not exited\n",
		       pri->pid);
		return;
	}

	pri->pid = -1;
}

int slirp_user_read(int fd, void *buf, int len, struct slirp_data *pri)
{
	return slip_proto_read(fd, buf, len, &pri->slip);
}

int slirp_user_write(int fd, void *buf, int len, struct slirp_data *pri)
{
	return slip_proto_write(fd, buf, len, &pri->slip);
}

const struct net_user_info slirp_user_info = {
	.init		= slirp_user_init,
	.open		= slirp_open,
	.close	 	= slirp_close,
	.remove	 	= NULL,
	.add_address	= NULL,
	.delete_address = NULL,
	.mtu		= BUF_SIZE,
	.max_packet	= BUF_SIZE,
};