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 <sys/time.h> 16 #include "user.h" 17 #include "kern_util.h" 18 #include "net_user.h" 19 #include "os.h" 20 #include "um_malloc.h" 21 #include "kern_constants.h" 22 23 int tap_open_common(void *dev, char *gate_addr) 24 { 25 int tap_addr[4]; 26 27 if(gate_addr == NULL) 28 return 0; 29 if(sscanf(gate_addr, "%d.%d.%d.%d", &tap_addr[0], 30 &tap_addr[1], &tap_addr[2], &tap_addr[3]) != 4){ 31 printk("Invalid tap IP address - '%s'\n", gate_addr); 32 return -EINVAL; 33 } 34 return 0; 35 } 36 37 void tap_check_ips(char *gate_addr, unsigned char *eth_addr) 38 { 39 int tap_addr[4]; 40 41 if((gate_addr != NULL) && 42 (sscanf(gate_addr, "%d.%d.%d.%d", &tap_addr[0], 43 &tap_addr[1], &tap_addr[2], &tap_addr[3]) == 4) && 44 (eth_addr[0] == tap_addr[0]) && 45 (eth_addr[1] == tap_addr[1]) && 46 (eth_addr[2] == tap_addr[2]) && 47 (eth_addr[3] == tap_addr[3])){ 48 printk("The tap IP address and the UML eth IP address" 49 " must be different\n"); 50 } 51 } 52 53 /* Do reliable error handling as this fails frequently enough. */ 54 void read_output(int fd, char *output, int len) 55 { 56 int remain, ret, expected; 57 char c; 58 char *str; 59 60 if(output == NULL){ 61 output = &c; 62 len = sizeof(c); 63 } 64 65 *output = '\0'; 66 ret = os_read_file(fd, &remain, sizeof(remain)); 67 68 if (ret != sizeof(remain)) { 69 expected = sizeof(remain); 70 str = "length"; 71 goto err; 72 } 73 74 while(remain != 0){ 75 expected = (remain < len) ? remain : len; 76 ret = os_read_file(fd, output, expected); 77 if (ret != expected) { 78 str = "data"; 79 goto err; 80 } 81 remain -= ret; 82 } 83 84 return; 85 86 err: 87 if (ret < 0) 88 printk("read_output - read of %s failed, errno = %d\n", str, -ret); 89 else 90 printk("read_output - read of %s failed, read only %d of %d bytes\n", str, ret, expected); 91 } 92 93 int net_read(int fd, void *buf, int len) 94 { 95 int n; 96 97 n = os_read_file(fd, buf, len); 98 99 if(n == -EAGAIN) 100 return 0; 101 else if(n == 0) 102 return -ENOTCONN; 103 return n; 104 } 105 106 int net_recvfrom(int fd, void *buf, int len) 107 { 108 int n; 109 110 CATCH_EINTR(n = recvfrom(fd, buf, len, 0, NULL, NULL)); 111 if(n < 0){ 112 if(errno == EAGAIN) 113 return 0; 114 return -errno; 115 } 116 else if(n == 0) 117 return -ENOTCONN; 118 return n; 119 } 120 121 int net_write(int fd, void *buf, int len) 122 { 123 int n; 124 125 n = os_write_file(fd, buf, len); 126 127 if(n == -EAGAIN) 128 return 0; 129 else if(n == 0) 130 return -ENOTCONN; 131 return n; 132 } 133 134 int net_send(int fd, void *buf, int len) 135 { 136 int n; 137 138 CATCH_EINTR(n = send(fd, buf, len, 0)); 139 if(n < 0){ 140 if(errno == EAGAIN) 141 return 0; 142 return -errno; 143 } 144 else if(n == 0) 145 return -ENOTCONN; 146 return n; 147 } 148 149 int net_sendto(int fd, void *buf, int len, void *to, int sock_len) 150 { 151 int n; 152 153 CATCH_EINTR(n = sendto(fd, buf, len, 0, (struct sockaddr *) to, 154 sock_len)); 155 if(n < 0){ 156 if(errno == EAGAIN) 157 return 0; 158 return -errno; 159 } 160 else if(n == 0) 161 return -ENOTCONN; 162 return n; 163 } 164 165 struct change_pre_exec_data { 166 int close_me; 167 int stdout; 168 }; 169 170 static void change_pre_exec(void *arg) 171 { 172 struct change_pre_exec_data *data = arg; 173 174 os_close_file(data->close_me); 175 dup2(data->stdout, 1); 176 } 177 178 static int change_tramp(char **argv, char *output, int output_len) 179 { 180 int pid, fds[2], err; 181 struct change_pre_exec_data pe_data; 182 183 err = os_pipe(fds, 1, 0); 184 if(err < 0){ 185 printk("change_tramp - pipe failed, err = %d\n", -err); 186 return err; 187 } 188 pe_data.close_me = fds[0]; 189 pe_data.stdout = fds[1]; 190 pid = run_helper(change_pre_exec, &pe_data, argv); 191 192 if (pid > 0) /* Avoid hang as we won't get data in failure case. */ 193 read_output(fds[0], output, output_len); 194 195 os_close_file(fds[0]); 196 os_close_file(fds[1]); 197 198 if (pid > 0) 199 CATCH_EINTR(err = waitpid(pid, NULL, 0)); 200 return pid; 201 } 202 203 static void change(char *dev, char *what, unsigned char *addr, 204 unsigned char *netmask) 205 { 206 char addr_buf[sizeof("255.255.255.255\0")]; 207 char netmask_buf[sizeof("255.255.255.255\0")]; 208 char version[sizeof("nnnnn\0")]; 209 char *argv[] = { "uml_net", version, what, dev, addr_buf, 210 netmask_buf, NULL }; 211 char *output; 212 int output_len, pid; 213 214 sprintf(version, "%d", UML_NET_VERSION); 215 sprintf(addr_buf, "%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]); 216 sprintf(netmask_buf, "%d.%d.%d.%d", netmask[0], netmask[1], 217 netmask[2], netmask[3]); 218 219 output_len = UM_KERN_PAGE_SIZE; 220 output = kmalloc(output_len, UM_GFP_KERNEL); 221 if(output == NULL) 222 printk("change : failed to allocate output buffer\n"); 223 224 pid = change_tramp(argv, output, output_len); 225 if(pid < 0) return; 226 227 if(output != NULL){ 228 printk("%s", output); 229 kfree(output); 230 } 231 } 232 233 void open_addr(unsigned char *addr, unsigned char *netmask, void *arg) 234 { 235 change(arg, "add", addr, netmask); 236 } 237 238 void close_addr(unsigned char *addr, unsigned char *netmask, void *arg) 239 { 240 change(arg, "del", addr, netmask); 241 } 242 243 char *split_if_spec(char *str, ...) 244 { 245 char **arg, *end; 246 va_list ap; 247 248 va_start(ap, str); 249 while((arg = va_arg(ap, char **)) != NULL){ 250 if(*str == '\0') 251 return NULL; 252 end = strchr(str, ','); 253 if(end != str) 254 *arg = str; 255 if(end == NULL) 256 return NULL; 257 *end++ = '\0'; 258 str = end; 259 } 260 va_end(ap); 261 return str; 262 } 263