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