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