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