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" 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 34 void tap_check_ips(char *gate_addr, unsigned char *eth_addr) 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 /* Do reliable error handling as this fails frequently enough. */ 51 void read_output(int fd, char *output, int len) 52 { 53 int remain, ret, expected; 54 char c; 55 char *str; 56 57 if(output == NULL){ 58 output = &c; 59 len = sizeof(c); 60 } 61 62 *output = '\0'; 63 ret = os_read_file(fd, &remain, sizeof(remain)); 64 65 if (ret != sizeof(remain)) { 66 expected = sizeof(remain); 67 str = "length"; 68 goto err; 69 } 70 71 while(remain != 0){ 72 expected = (remain < len) ? remain : len; 73 ret = os_read_file(fd, output, expected); 74 if (ret != expected) { 75 str = "data"; 76 goto err; 77 } 78 remain -= ret; 79 } 80 81 return; 82 83 err: 84 if (ret < 0) 85 printk("read_output - read of %s failed, errno = %d\n", str, -ret); 86 else 87 printk("read_output - read of %s failed, read only %d of %d bytes\n", str, ret, expected); 88 } 89 90 int net_read(int fd, void *buf, int len) 91 { 92 int n; 93 94 n = os_read_file(fd, buf, len); 95 96 if(n == -EAGAIN) 97 return(0); 98 else if(n == 0) 99 return(-ENOTCONN); 100 return(n); 101 } 102 103 int net_recvfrom(int fd, void *buf, int len) 104 { 105 int n; 106 107 while(((n = recvfrom(fd, buf, len, 0, NULL, NULL)) < 0) && 108 (errno == EINTR)) ; 109 110 if(n < 0){ 111 if(errno == EAGAIN) return(0); 112 return(-errno); 113 } 114 else if(n == 0) return(-ENOTCONN); 115 return(n); 116 } 117 118 int net_write(int fd, void *buf, int len) 119 { 120 int n; 121 122 n = os_write_file(fd, buf, len); 123 124 if(n == -EAGAIN) 125 return(0); 126 else if(n == 0) 127 return(-ENOTCONN); 128 return(n); 129 } 130 131 int net_send(int fd, void *buf, int len) 132 { 133 int n; 134 135 while(((n = send(fd, buf, len, 0)) < 0) && (errno == EINTR)) ; 136 if(n < 0){ 137 if(errno == EAGAIN) return(0); 138 return(-errno); 139 } 140 else if(n == 0) return(-ENOTCONN); 141 return(n); 142 } 143 144 int net_sendto(int fd, void *buf, int len, void *to, int sock_len) 145 { 146 int n; 147 148 while(((n = sendto(fd, buf, len, 0, (struct sockaddr *) to, 149 sock_len)) < 0) && (errno == EINTR)) ; 150 if(n < 0){ 151 if(errno == EAGAIN) return(0); 152 return(-errno); 153 } 154 else if(n == 0) return(-ENOTCONN); 155 return(n); 156 } 157 158 struct change_pre_exec_data { 159 int close_me; 160 int stdout; 161 }; 162 163 static void change_pre_exec(void *arg) 164 { 165 struct change_pre_exec_data *data = arg; 166 167 os_close_file(data->close_me); 168 dup2(data->stdout, 1); 169 } 170 171 static int change_tramp(char **argv, char *output, int output_len) 172 { 173 int pid, fds[2], err; 174 struct change_pre_exec_data pe_data; 175 176 err = os_pipe(fds, 1, 0); 177 if(err < 0){ 178 printk("change_tramp - pipe failed, err = %d\n", -err); 179 return(err); 180 } 181 pe_data.close_me = fds[0]; 182 pe_data.stdout = fds[1]; 183 pid = run_helper(change_pre_exec, &pe_data, argv, NULL); 184 185 read_output(fds[0], output, output_len); 186 os_close_file(fds[0]); 187 os_close_file(fds[1]); 188 189 if (pid > 0) 190 CATCH_EINTR(err = waitpid(pid, NULL, 0)); 191 return(pid); 192 } 193 194 static void change(char *dev, char *what, unsigned char *addr, 195 unsigned char *netmask) 196 { 197 char addr_buf[sizeof("255.255.255.255\0")]; 198 char netmask_buf[sizeof("255.255.255.255\0")]; 199 char version[sizeof("nnnnn\0")]; 200 char *argv[] = { "uml_net", version, what, dev, addr_buf, 201 netmask_buf, NULL }; 202 char *output; 203 int output_len, pid; 204 205 sprintf(version, "%d", UML_NET_VERSION); 206 sprintf(addr_buf, "%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]); 207 sprintf(netmask_buf, "%d.%d.%d.%d", netmask[0], netmask[1], 208 netmask[2], netmask[3]); 209 210 output_len = page_size(); 211 output = um_kmalloc(output_len); 212 if(output == NULL) 213 printk("change : failed to allocate output buffer\n"); 214 215 pid = change_tramp(argv, output, output_len); 216 if(pid < 0) return; 217 218 if(output != NULL){ 219 printk("%s", output); 220 kfree(output); 221 } 222 } 223 224 void open_addr(unsigned char *addr, unsigned char *netmask, void *arg) 225 { 226 change(arg, "add", addr, netmask); 227 } 228 229 void close_addr(unsigned char *addr, unsigned char *netmask, void *arg) 230 { 231 change(arg, "del", addr, netmask); 232 } 233 234 char *split_if_spec(char *str, ...) 235 { 236 char **arg, *end; 237 va_list ap; 238 239 va_start(ap, str); 240 while((arg = va_arg(ap, char **)) != NULL){ 241 if(*str == '\0') 242 return(NULL); 243 end = strchr(str, ','); 244 if(end != str) 245 *arg = str; 246 if(end == NULL) 247 return(NULL); 248 *end++ = '\0'; 249 str = end; 250 } 251 va_end(ap); 252 return(str); 253 } 254 255 /* 256 * Overrides for Emacs so that we follow Linus's tabbing style. 257 * Emacs will notice this stuff at the end of the file and automatically 258 * adjust the settings for this buffer only. This must remain at the end 259 * of the file. 260 * --------------------------------------------------------------------------- 261 * Local variables: 262 * c-file-style: "linux" 263 * End: 264 */ 265