| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) | 
|  | 3 | * Licensed under the GPL | 
|  | 4 | */ | 
|  | 5 |  | 
|  | 6 | #include <stddef.h> | 
|  | 7 | #include <stdarg.h> | 
|  | 8 | #include <unistd.h> | 
|  | 9 | #include <stdio.h> | 
|  | 10 | #include <errno.h> | 
|  | 11 | #include <stdlib.h> | 
|  | 12 | #include <string.h> | 
|  | 13 | #include <sys/socket.h> | 
|  | 14 | #include <sys/wait.h> | 
|  | 15 | #include "user.h" | 
|  | 16 | #include "user_util.h" | 
|  | 17 | #include "kern_util.h" | 
|  | 18 | #include "net_user.h" | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 19 | #include "os.h" | 
|  | 20 |  | 
|  | 21 | int tap_open_common(void *dev, char *gate_addr) | 
|  | 22 | { | 
|  | 23 | int tap_addr[4]; | 
|  | 24 |  | 
|  | 25 | if(gate_addr == NULL) return(0); | 
|  | 26 | if(sscanf(gate_addr, "%d.%d.%d.%d", &tap_addr[0], | 
|  | 27 | &tap_addr[1], &tap_addr[2], &tap_addr[3]) != 4){ | 
|  | 28 | printk("Invalid tap IP address - '%s'\n", gate_addr); | 
|  | 29 | return(-EINVAL); | 
|  | 30 | } | 
|  | 31 | return(0); | 
|  | 32 | } | 
|  | 33 |  | 
| Jeff Dike | da00d9a | 2005-06-08 15:48:01 -0700 | [diff] [blame] | 34 | void tap_check_ips(char *gate_addr, unsigned char *eth_addr) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 35 | { | 
|  | 36 | int tap_addr[4]; | 
|  | 37 |  | 
|  | 38 | if((gate_addr != NULL) && | 
|  | 39 | (sscanf(gate_addr, "%d.%d.%d.%d", &tap_addr[0], | 
|  | 40 | &tap_addr[1], &tap_addr[2], &tap_addr[3]) == 4) && | 
|  | 41 | (eth_addr[0] == tap_addr[0]) && | 
|  | 42 | (eth_addr[1] == tap_addr[1]) && | 
|  | 43 | (eth_addr[2] == tap_addr[2]) && | 
|  | 44 | (eth_addr[3] == tap_addr[3])){ | 
|  | 45 | printk("The tap IP address and the UML eth IP address" | 
|  | 46 | " must be different\n"); | 
|  | 47 | } | 
|  | 48 | } | 
|  | 49 |  | 
|  | 50 | void read_output(int fd, char *output, int len) | 
|  | 51 | { | 
|  | 52 | int remain, n, actual; | 
|  | 53 | char c; | 
|  | 54 |  | 
|  | 55 | if(output == NULL){ | 
|  | 56 | output = &c; | 
|  | 57 | len = sizeof(c); | 
|  | 58 | } | 
|  | 59 |  | 
|  | 60 | *output = '\0'; | 
|  | 61 | n = os_read_file(fd, &remain, sizeof(remain)); | 
|  | 62 | if(n != sizeof(remain)){ | 
|  | 63 | printk("read_output - read of length failed, err = %d\n", -n); | 
|  | 64 | return; | 
|  | 65 | } | 
|  | 66 |  | 
|  | 67 | while(remain != 0){ | 
|  | 68 | n = (remain < len) ? remain : len; | 
|  | 69 | actual = os_read_file(fd, output, n); | 
|  | 70 | if(actual != n){ | 
|  | 71 | printk("read_output - read of data failed, " | 
|  | 72 | "err = %d\n", -actual); | 
|  | 73 | return; | 
|  | 74 | } | 
|  | 75 | remain -= actual; | 
|  | 76 | } | 
|  | 77 | return; | 
|  | 78 | } | 
|  | 79 |  | 
|  | 80 | int net_read(int fd, void *buf, int len) | 
|  | 81 | { | 
|  | 82 | int n; | 
|  | 83 |  | 
|  | 84 | n = os_read_file(fd,  buf,  len); | 
|  | 85 |  | 
|  | 86 | if(n == -EAGAIN) | 
|  | 87 | return(0); | 
|  | 88 | else if(n == 0) | 
|  | 89 | return(-ENOTCONN); | 
|  | 90 | return(n); | 
|  | 91 | } | 
|  | 92 |  | 
|  | 93 | int net_recvfrom(int fd, void *buf, int len) | 
|  | 94 | { | 
|  | 95 | int n; | 
|  | 96 |  | 
|  | 97 | while(((n = recvfrom(fd,  buf,  len, 0, NULL, NULL)) < 0) && | 
|  | 98 | (errno == EINTR)) ; | 
|  | 99 |  | 
|  | 100 | if(n < 0){ | 
|  | 101 | if(errno == EAGAIN) return(0); | 
|  | 102 | return(-errno); | 
|  | 103 | } | 
|  | 104 | else if(n == 0) return(-ENOTCONN); | 
|  | 105 | return(n); | 
|  | 106 | } | 
|  | 107 |  | 
|  | 108 | int net_write(int fd, void *buf, int len) | 
|  | 109 | { | 
|  | 110 | int n; | 
|  | 111 |  | 
|  | 112 | n = os_write_file(fd, buf, len); | 
|  | 113 |  | 
|  | 114 | if(n == -EAGAIN) | 
|  | 115 | return(0); | 
|  | 116 | else if(n == 0) | 
|  | 117 | return(-ENOTCONN); | 
|  | 118 | return(n); | 
|  | 119 | } | 
|  | 120 |  | 
|  | 121 | int net_send(int fd, void *buf, int len) | 
|  | 122 | { | 
|  | 123 | int n; | 
|  | 124 |  | 
|  | 125 | while(((n = send(fd, buf, len, 0)) < 0) && (errno == EINTR)) ; | 
|  | 126 | if(n < 0){ | 
|  | 127 | if(errno == EAGAIN) return(0); | 
|  | 128 | return(-errno); | 
|  | 129 | } | 
|  | 130 | else if(n == 0) return(-ENOTCONN); | 
|  | 131 | return(n); | 
|  | 132 | } | 
|  | 133 |  | 
|  | 134 | int net_sendto(int fd, void *buf, int len, void *to, int sock_len) | 
|  | 135 | { | 
|  | 136 | int n; | 
|  | 137 |  | 
|  | 138 | while(((n = sendto(fd, buf, len, 0, (struct sockaddr *) to, | 
|  | 139 | sock_len)) < 0) && (errno == EINTR)) ; | 
|  | 140 | if(n < 0){ | 
|  | 141 | if(errno == EAGAIN) return(0); | 
|  | 142 | return(-errno); | 
|  | 143 | } | 
|  | 144 | else if(n == 0) return(-ENOTCONN); | 
|  | 145 | return(n); | 
|  | 146 | } | 
|  | 147 |  | 
|  | 148 | struct change_pre_exec_data { | 
|  | 149 | int close_me; | 
|  | 150 | int stdout; | 
|  | 151 | }; | 
|  | 152 |  | 
|  | 153 | static void change_pre_exec(void *arg) | 
|  | 154 | { | 
|  | 155 | struct change_pre_exec_data *data = arg; | 
|  | 156 |  | 
|  | 157 | os_close_file(data->close_me); | 
|  | 158 | dup2(data->stdout, 1); | 
|  | 159 | } | 
|  | 160 |  | 
|  | 161 | static int change_tramp(char **argv, char *output, int output_len) | 
|  | 162 | { | 
|  | 163 | int pid, fds[2], err; | 
|  | 164 | struct change_pre_exec_data pe_data; | 
|  | 165 |  | 
|  | 166 | err = os_pipe(fds, 1, 0); | 
|  | 167 | if(err < 0){ | 
|  | 168 | printk("change_tramp - pipe failed, err = %d\n", -err); | 
|  | 169 | return(err); | 
|  | 170 | } | 
|  | 171 | pe_data.close_me = fds[0]; | 
|  | 172 | pe_data.stdout = fds[1]; | 
|  | 173 | pid = run_helper(change_pre_exec, &pe_data, argv, NULL); | 
|  | 174 |  | 
|  | 175 | read_output(fds[0], output, output_len); | 
|  | 176 | os_close_file(fds[0]); | 
|  | 177 | os_close_file(fds[1]); | 
|  | 178 |  | 
|  | 179 | if (pid > 0) | 
|  | 180 | CATCH_EINTR(err = waitpid(pid, NULL, 0)); | 
|  | 181 | return(pid); | 
|  | 182 | } | 
|  | 183 |  | 
|  | 184 | static void change(char *dev, char *what, unsigned char *addr, | 
|  | 185 | unsigned char *netmask) | 
|  | 186 | { | 
|  | 187 | char addr_buf[sizeof("255.255.255.255\0")]; | 
|  | 188 | char netmask_buf[sizeof("255.255.255.255\0")]; | 
|  | 189 | char version[sizeof("nnnnn\0")]; | 
|  | 190 | char *argv[] = { "uml_net", version, what, dev, addr_buf, | 
|  | 191 | netmask_buf, NULL }; | 
|  | 192 | char *output; | 
|  | 193 | int output_len, pid; | 
|  | 194 |  | 
|  | 195 | sprintf(version, "%d", UML_NET_VERSION); | 
|  | 196 | sprintf(addr_buf, "%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]); | 
|  | 197 | sprintf(netmask_buf, "%d.%d.%d.%d", netmask[0], netmask[1], | 
|  | 198 | netmask[2], netmask[3]); | 
|  | 199 |  | 
|  | 200 | output_len = page_size(); | 
|  | 201 | output = um_kmalloc(output_len); | 
|  | 202 | if(output == NULL) | 
|  | 203 | printk("change : failed to allocate output buffer\n"); | 
|  | 204 |  | 
|  | 205 | pid = change_tramp(argv, output, output_len); | 
|  | 206 | if(pid < 0) return; | 
|  | 207 |  | 
|  | 208 | if(output != NULL){ | 
|  | 209 | printk("%s", output); | 
|  | 210 | kfree(output); | 
|  | 211 | } | 
|  | 212 | } | 
|  | 213 |  | 
|  | 214 | void open_addr(unsigned char *addr, unsigned char *netmask, void *arg) | 
|  | 215 | { | 
|  | 216 | change(arg, "add", addr, netmask); | 
|  | 217 | } | 
|  | 218 |  | 
|  | 219 | void close_addr(unsigned char *addr, unsigned char *netmask, void *arg) | 
|  | 220 | { | 
|  | 221 | change(arg, "del", addr, netmask); | 
|  | 222 | } | 
|  | 223 |  | 
|  | 224 | char *split_if_spec(char *str, ...) | 
|  | 225 | { | 
|  | 226 | char **arg, *end; | 
|  | 227 | va_list ap; | 
|  | 228 |  | 
|  | 229 | va_start(ap, str); | 
|  | 230 | while((arg = va_arg(ap, char **)) != NULL){ | 
|  | 231 | if(*str == '\0') | 
|  | 232 | return(NULL); | 
|  | 233 | end = strchr(str, ','); | 
|  | 234 | if(end != str) | 
|  | 235 | *arg = str; | 
|  | 236 | if(end == NULL) | 
|  | 237 | return(NULL); | 
|  | 238 | *end++ = '\0'; | 
|  | 239 | str = end; | 
|  | 240 | } | 
|  | 241 | va_end(ap); | 
|  | 242 | return(str); | 
|  | 243 | } | 
|  | 244 |  | 
|  | 245 | /* | 
|  | 246 | * Overrides for Emacs so that we follow Linus's tabbing style. | 
|  | 247 | * Emacs will notice this stuff at the end of the file and automatically | 
|  | 248 | * adjust the settings for this buffer only.  This must remain at the end | 
|  | 249 | * of the file. | 
|  | 250 | * --------------------------------------------------------------------------- | 
|  | 251 | * Local variables: | 
|  | 252 | * c-file-style: "linux" | 
|  | 253 | * End: | 
|  | 254 | */ |