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 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 */ 255