Blame view

arch/um/drivers/slip_user.c 4.94 KB
cd1ae0e49   Jeff Dike   uml: network form...
1
2
3
4
  /*
   * Copyright (C) 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
   * Licensed under the GPL.
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5
6
7
  #include <stdio.h>
  #include <stdlib.h>
  #include <unistd.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8
  #include <errno.h>
cd1ae0e49   Jeff Dike   uml: network form...
9
10
  #include <fcntl.h>
  #include <string.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
11
12
  #include <sys/termios.h>
  #include <sys/wait.h>
37185b332   Al Viro   um: get rid of po...
13
14
  #include <net_user.h>
  #include <os.h>
cd1ae0e49   Jeff Dike   uml: network form...
15
  #include "slip.h"
37185b332   Al Viro   um: get rid of po...
16
  #include <um_malloc.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17

f34d9d2dc   Jeff Dike   uml: network inte...
18
  static int slip_user_init(void *data, void *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19
20
21
22
  {
  	struct slip_data *pri = data;
  
  	pri->dev = dev;
f34d9d2dc   Jeff Dike   uml: network inte...
23
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
26
27
28
29
30
31
  }
  
  static int set_up_tty(int fd)
  {
  	int i;
  	struct termios tios;
  
  	if (tcgetattr(fd, &tios) < 0) {
cd1ae0e49   Jeff Dike   uml: network form...
32
33
34
35
  		printk(UM_KERN_ERR "could not get initial terminal "
  		       "attributes
  ");
  		return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
  	}
  
  	tios.c_cflag = CS8 | CREAD | HUPCL | CLOCAL;
  	tios.c_iflag = IGNBRK | IGNPAR;
  	tios.c_oflag = 0;
  	tios.c_lflag = 0;
  	for (i = 0; i < NCCS; i++)
  		tios.c_cc[i] = 0;
  	tios.c_cc[VMIN] = 1;
  	tios.c_cc[VTIME] = 0;
  
  	cfsetospeed(&tios, B38400);
  	cfsetispeed(&tios, B38400);
  
  	if (tcsetattr(fd, TCSAFLUSH, &tios) < 0) {
cd1ae0e49   Jeff Dike   uml: network form...
51
52
53
  		printk(UM_KERN_ERR "failed to set terminal attributes
  ");
  		return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54
  	}
cd1ae0e49   Jeff Dike   uml: network form...
55
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56
57
58
59
60
61
62
63
64
65
66
  }
  
  struct slip_pre_exec_data {
  	int stdin;
  	int stdout;
  	int close_me;
  };
  
  static void slip_pre_exec(void *arg)
  {
  	struct slip_pre_exec_data *data = arg;
cd1ae0e49   Jeff Dike   uml: network form...
67
68
  	if (data->stdin >= 0)
  		dup2(data->stdin, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69
  	dup2(data->stdout, 1);
cd1ae0e49   Jeff Dike   uml: network form...
70
71
  	if (data->close_me >= 0)
  		close(data->close_me);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
72
73
74
75
76
77
  }
  
  static int slip_tramp(char **argv, int fd)
  {
  	struct slip_pre_exec_data pe_data;
  	char *output;
4dbed85a3   Stanislaw Gruszka   uml: stop gdb fro...
78
  	int pid, fds[2], err, output_len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
79
80
  
  	err = os_pipe(fds, 1, 0);
cd1ae0e49   Jeff Dike   uml: network form...
81
82
83
84
  	if (err < 0) {
  		printk(UM_KERN_ERR "slip_tramp : pipe failed, err = %d
  ",
  		       -err);
a3c77c67a   Jeff Dike   [PATCH] uml: slir...
85
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86
87
88
89
90
91
  	}
  
  	err = 0;
  	pe_data.stdin = fd;
  	pe_data.stdout = fds[1];
  	pe_data.close_me = fds[0];
c43990162   Jeff Dike   uml: simplify hel...
92
  	err = run_helper(slip_pre_exec, &pe_data, argv);
cd1ae0e49   Jeff Dike   uml: network form...
93
  	if (err < 0)
a3c77c67a   Jeff Dike   [PATCH] uml: slir...
94
95
  		goto out_close;
  	pid = err;
1ffb9164f   Jeff Dike   uml: remove page_...
96
  	output_len = UM_KERN_PAGE_SIZE;
43f5b3085   Jeff Dike   uml: fix build wh...
97
  	output = uml_kmalloc(output_len, UM_GFP_KERNEL);
cd1ae0e49   Jeff Dike   uml: network form...
98
99
100
101
  	if (output == NULL) {
  		printk(UM_KERN_ERR "slip_tramp : failed to allocate output "
  		       "buffer
  ");
a3c77c67a   Jeff Dike   [PATCH] uml: slir...
102
103
  		os_kill_process(pid, 1);
  		err = -ENOMEM;
9a8beb930   Vitaliy Ivanov   uml: drivers/slip...
104
  		goto out_close;
a3c77c67a   Jeff Dike   [PATCH] uml: slir...
105
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
106

cd1ae0e49   Jeff Dike   uml: network form...
107
  	close(fds[1]);
a3c77c67a   Jeff Dike   [PATCH] uml: slir...
108
109
  	read_output(fds[0], output, output_len);
  	printk("%s", output);
1aa351a30   Jeff Dike   uml: tidy helper ...
110
  	err = helper_wait(pid);
cd1ae0e49   Jeff Dike   uml: network form...
111
  	close(fds[0]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
112

a3c77c67a   Jeff Dike   [PATCH] uml: slir...
113
114
115
116
  	kfree(output);
  	return err;
  
  out_close:
cd1ae0e49   Jeff Dike   uml: network form...
117
118
  	close(fds[0]);
  	close(fds[1]);
a3c77c67a   Jeff Dike   [PATCH] uml: slir...
119
120
  out:
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
121
122
123
124
125
126
127
  }
  
  static int slip_open(void *data)
  {
  	struct slip_data *pri = data;
  	char version_buf[sizeof("nnnnn\0")];
  	char gate_buf[sizeof("nnn.nnn.nnn.nnn\0")];
cd1ae0e49   Jeff Dike   uml: network form...
128
  	char *argv[] = { "uml_net", version_buf, "slip", "up", gate_buf,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
129
130
  			 NULL };
  	int sfd, mfd, err;
a3c77c67a   Jeff Dike   [PATCH] uml: slir...
131
  	err = get_pty();
cd1ae0e49   Jeff Dike   uml: network form...
132
133
134
135
  	if (err < 0) {
  		printk(UM_KERN_ERR "slip-open : Failed to open pty, err = %d
  ",
  		       -err);
a3c77c67a   Jeff Dike   [PATCH] uml: slir...
136
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
137
  	}
a3c77c67a   Jeff Dike   [PATCH] uml: slir...
138
  	mfd = err;
cd1ae0e49   Jeff Dike   uml: network form...
139
140
141
142
143
  	err = open(ptsname(mfd), O_RDWR, 0);
  	if (err < 0) {
  		printk(UM_KERN_ERR "Couldn't open tty for slip line, "
  		       "err = %d
  ", -err);
a3c77c67a   Jeff Dike   [PATCH] uml: slir...
144
  		goto out_close;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
145
  	}
a3c77c67a   Jeff Dike   [PATCH] uml: slir...
146
  	sfd = err;
cd1ae0e49   Jeff Dike   uml: network form...
147
  	if (set_up_tty(sfd))
a3c77c67a   Jeff Dike   [PATCH] uml: slir...
148
  		goto out_close2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
149
  	pri->slave = sfd;
a3c77c67a   Jeff Dike   [PATCH] uml: slir...
150
151
  	pri->slip.pos = 0;
  	pri->slip.esc = 0;
cd1ae0e49   Jeff Dike   uml: network form...
152
  	if (pri->gate_addr != NULL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
153
154
155
156
  		sprintf(version_buf, "%d", UML_NET_VERSION);
  		strcpy(gate_buf, pri->gate_addr);
  
  		err = slip_tramp(argv, sfd);
cd1ae0e49   Jeff Dike   uml: network form...
157
158
159
160
  		if (err < 0) {
  			printk(UM_KERN_ERR "slip_tramp failed - err = %d
  ",
  			       -err);
a3c77c67a   Jeff Dike   [PATCH] uml: slir...
161
  			goto out_close2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
162
163
  		}
  		err = os_get_ifname(pri->slave, pri->name);
cd1ae0e49   Jeff Dike   uml: network form...
164
165
166
167
  		if (err < 0) {
  			printk(UM_KERN_ERR "get_ifname failed, err = %d
  ",
  			       -err);
a3c77c67a   Jeff Dike   [PATCH] uml: slir...
168
  			goto out_close2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169
170
171
172
173
  		}
  		iter_addresses(pri->dev, open_addr, pri->name);
  	}
  	else {
  		err = os_set_slip(sfd);
cd1ae0e49   Jeff Dike   uml: network form...
174
175
176
177
  		if (err < 0) {
  			printk(UM_KERN_ERR "Failed to set slip discipline "
  			       "encapsulation - err = %d
  ", -err);
a3c77c67a   Jeff Dike   [PATCH] uml: slir...
178
  			goto out_close2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
179
180
  		}
  	}
cd1ae0e49   Jeff Dike   uml: network form...
181
  	return mfd;
a3c77c67a   Jeff Dike   [PATCH] uml: slir...
182
  out_close2:
cd1ae0e49   Jeff Dike   uml: network form...
183
  	close(sfd);
a3c77c67a   Jeff Dike   [PATCH] uml: slir...
184
  out_close:
cd1ae0e49   Jeff Dike   uml: network form...
185
  	close(mfd);
a3c77c67a   Jeff Dike   [PATCH] uml: slir...
186
187
  out:
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
188
189
190
191
192
193
  }
  
  static void slip_close(int fd, void *data)
  {
  	struct slip_data *pri = data;
  	char version_buf[sizeof("nnnnn\0")];
cd1ae0e49   Jeff Dike   uml: network form...
194
  	char *argv[] = { "uml_net", version_buf, "slip", "down", pri->name,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
195
196
  			 NULL };
  	int err;
cd1ae0e49   Jeff Dike   uml: network form...
197
  	if (pri->gate_addr != NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
198
199
200
201
202
  		iter_addresses(pri->dev, close_addr, pri->name);
  
  	sprintf(version_buf, "%d", UML_NET_VERSION);
  
  	err = slip_tramp(argv, pri->slave);
cd1ae0e49   Jeff Dike   uml: network form...
203
204
205
206
207
  	if (err != 0)
  		printk(UM_KERN_ERR "slip_tramp failed - errno = %d
  ", -err);
  	close(fd);
  	close(pri->slave);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
208
209
210
211
212
  	pri->slave = -1;
  }
  
  int slip_user_read(int fd, void *buf, int len, struct slip_data *pri)
  {
a3c77c67a   Jeff Dike   [PATCH] uml: slir...
213
  	return slip_proto_read(fd, buf, len, &pri->slip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
214
215
216
217
  }
  
  int slip_user_write(int fd, void *buf, int len, struct slip_data *pri)
  {
a3c77c67a   Jeff Dike   [PATCH] uml: slir...
218
  	return slip_proto_write(fd, buf, len, &pri->slip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
219
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
220
221
222
223
  static void slip_add_addr(unsigned char *addr, unsigned char *netmask,
  			  void *data)
  {
  	struct slip_data *pri = data;
cd1ae0e49   Jeff Dike   uml: network form...
224
225
  	if (pri->slave < 0)
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
226
227
228
229
230
231
232
  	open_addr(addr, netmask, pri->name);
  }
  
  static void slip_del_addr(unsigned char *addr, unsigned char *netmask,
  			    void *data)
  {
  	struct slip_data *pri = data;
cd1ae0e49   Jeff Dike   uml: network form...
233
234
  	if (pri->slave < 0)
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
235
236
  	close_addr(addr, netmask, pri->name);
  }
5e7672ec3   Jeff Dike   [PATCH] uml: cons...
237
  const struct net_user_info slip_user_info = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
238
239
240
241
  	.init		= slip_user_init,
  	.open		= slip_open,
  	.close	 	= slip_close,
  	.remove	 	= NULL,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
242
243
  	.add_address	= slip_add_addr,
  	.delete_address = slip_del_addr,
b53f35a80   Jeff Dike   uml: network driv...
244
245
  	.mtu		= BUF_SIZE,
  	.max_packet	= BUF_SIZE,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
246
  };