PageRenderTime 33ms CodeModel.GetById 21ms app.highlight 10ms RepoModel.GetById 1ms app.codeStats 0ms

/arch/um/drivers/slip_user.c

https://bitbucket.org/ndreys/linux-sunxi
C | 254 lines | 212 code | 38 blank | 4 comment | 24 complexity | 8876a854a03b3e69bf12baa99d249c5d MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0
  1/*
  2 * Copyright (C) 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
  3 * Licensed under the GPL.
  4 */
  5
  6#include <stdio.h>
  7#include <stdlib.h>
  8#include <unistd.h>
  9#include <errno.h>
 10#include <fcntl.h>
 11#include <string.h>
 12#include <sys/termios.h>
 13#include <sys/wait.h>
 14#include "kern_constants.h"
 15#include "net_user.h"
 16#include "os.h"
 17#include "slip.h"
 18#include "um_malloc.h"
 19#include "user.h"
 20
 21static int slip_user_init(void *data, void *dev)
 22{
 23	struct slip_data *pri = data;
 24
 25	pri->dev = dev;
 26	return 0;
 27}
 28
 29static int set_up_tty(int fd)
 30{
 31	int i;
 32	struct termios tios;
 33
 34	if (tcgetattr(fd, &tios) < 0) {
 35		printk(UM_KERN_ERR "could not get initial terminal "
 36		       "attributes\n");
 37		return -1;
 38	}
 39
 40	tios.c_cflag = CS8 | CREAD | HUPCL | CLOCAL;
 41	tios.c_iflag = IGNBRK | IGNPAR;
 42	tios.c_oflag = 0;
 43	tios.c_lflag = 0;
 44	for (i = 0; i < NCCS; i++)
 45		tios.c_cc[i] = 0;
 46	tios.c_cc[VMIN] = 1;
 47	tios.c_cc[VTIME] = 0;
 48
 49	cfsetospeed(&tios, B38400);
 50	cfsetispeed(&tios, B38400);
 51
 52	if (tcsetattr(fd, TCSAFLUSH, &tios) < 0) {
 53		printk(UM_KERN_ERR "failed to set terminal attributes\n");
 54		return -1;
 55	}
 56	return 0;
 57}
 58
 59struct slip_pre_exec_data {
 60	int stdin;
 61	int stdout;
 62	int close_me;
 63};
 64
 65static void slip_pre_exec(void *arg)
 66{
 67	struct slip_pre_exec_data *data = arg;
 68
 69	if (data->stdin >= 0)
 70		dup2(data->stdin, 0);
 71	dup2(data->stdout, 1);
 72	if (data->close_me >= 0)
 73		close(data->close_me);
 74}
 75
 76static int slip_tramp(char **argv, int fd)
 77{
 78	struct slip_pre_exec_data pe_data;
 79	char *output;
 80	int pid, fds[2], err, output_len;
 81
 82	err = os_pipe(fds, 1, 0);
 83	if (err < 0) {
 84		printk(UM_KERN_ERR "slip_tramp : pipe failed, err = %d\n",
 85		       -err);
 86		goto out;
 87	}
 88
 89	err = 0;
 90	pe_data.stdin = fd;
 91	pe_data.stdout = fds[1];
 92	pe_data.close_me = fds[0];
 93	err = run_helper(slip_pre_exec, &pe_data, argv);
 94	if (err < 0)
 95		goto out_close;
 96	pid = err;
 97
 98	output_len = UM_KERN_PAGE_SIZE;
 99	output = uml_kmalloc(output_len, UM_GFP_KERNEL);
100	if (output == NULL) {
101		printk(UM_KERN_ERR "slip_tramp : failed to allocate output "
102		       "buffer\n");
103		os_kill_process(pid, 1);
104		err = -ENOMEM;
105		goto out_free;
106	}
107
108	close(fds[1]);
109	read_output(fds[0], output, output_len);
110	printk("%s", output);
111
112	err = helper_wait(pid);
113	close(fds[0]);
114
115out_free:
116	kfree(output);
117	return err;
118
119out_close:
120	close(fds[0]);
121	close(fds[1]);
122out:
123	return err;
124}
125
126static int slip_open(void *data)
127{
128	struct slip_data *pri = data;
129	char version_buf[sizeof("nnnnn\0")];
130	char gate_buf[sizeof("nnn.nnn.nnn.nnn\0")];
131	char *argv[] = { "uml_net", version_buf, "slip", "up", gate_buf,
132			 NULL };
133	int sfd, mfd, err;
134
135	err = get_pty();
136	if (err < 0) {
137		printk(UM_KERN_ERR "slip-open : Failed to open pty, err = %d\n",
138		       -err);
139		goto out;
140	}
141	mfd = err;
142
143	err = open(ptsname(mfd), O_RDWR, 0);
144	if (err < 0) {
145		printk(UM_KERN_ERR "Couldn't open tty for slip line, "
146		       "err = %d\n", -err);
147		goto out_close;
148	}
149	sfd = err;
150
151	if (set_up_tty(sfd))
152		goto out_close2;
153
154	pri->slave = sfd;
155	pri->slip.pos = 0;
156	pri->slip.esc = 0;
157	if (pri->gate_addr != NULL) {
158		sprintf(version_buf, "%d", UML_NET_VERSION);
159		strcpy(gate_buf, pri->gate_addr);
160
161		err = slip_tramp(argv, sfd);
162
163		if (err < 0) {
164			printk(UM_KERN_ERR "slip_tramp failed - err = %d\n",
165			       -err);
166			goto out_close2;
167		}
168		err = os_get_ifname(pri->slave, pri->name);
169		if (err < 0) {
170			printk(UM_KERN_ERR "get_ifname failed, err = %d\n",
171			       -err);
172			goto out_close2;
173		}
174		iter_addresses(pri->dev, open_addr, pri->name);
175	}
176	else {
177		err = os_set_slip(sfd);
178		if (err < 0) {
179			printk(UM_KERN_ERR "Failed to set slip discipline "
180			       "encapsulation - err = %d\n", -err);
181			goto out_close2;
182		}
183	}
184	return mfd;
185out_close2:
186	close(sfd);
187out_close:
188	close(mfd);
189out:
190	return err;
191}
192
193static void slip_close(int fd, void *data)
194{
195	struct slip_data *pri = data;
196	char version_buf[sizeof("nnnnn\0")];
197	char *argv[] = { "uml_net", version_buf, "slip", "down", pri->name,
198			 NULL };
199	int err;
200
201	if (pri->gate_addr != NULL)
202		iter_addresses(pri->dev, close_addr, pri->name);
203
204	sprintf(version_buf, "%d", UML_NET_VERSION);
205
206	err = slip_tramp(argv, pri->slave);
207
208	if (err != 0)
209		printk(UM_KERN_ERR "slip_tramp failed - errno = %d\n", -err);
210	close(fd);
211	close(pri->slave);
212	pri->slave = -1;
213}
214
215int slip_user_read(int fd, void *buf, int len, struct slip_data *pri)
216{
217	return slip_proto_read(fd, buf, len, &pri->slip);
218}
219
220int slip_user_write(int fd, void *buf, int len, struct slip_data *pri)
221{
222	return slip_proto_write(fd, buf, len, &pri->slip);
223}
224
225static void slip_add_addr(unsigned char *addr, unsigned char *netmask,
226			  void *data)
227{
228	struct slip_data *pri = data;
229
230	if (pri->slave < 0)
231		return;
232	open_addr(addr, netmask, pri->name);
233}
234
235static void slip_del_addr(unsigned char *addr, unsigned char *netmask,
236			    void *data)
237{
238	struct slip_data *pri = data;
239
240	if (pri->slave < 0)
241		return;
242	close_addr(addr, netmask, pri->name);
243}
244
245const struct net_user_info slip_user_info = {
246	.init		= slip_user_init,
247	.open		= slip_open,
248	.close	 	= slip_close,
249	.remove	 	= NULL,
250	.add_address	= slip_add_addr,
251	.delete_address = slip_del_addr,
252	.mtu		= BUF_SIZE,
253	.max_packet	= BUF_SIZE,
254};