1 /* 2 * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and 3 * James Leu (jleu@mindspring.net). 4 * Copyright (C) 2001 by various other people who didn't put their name here. 5 * Licensed under the GPL. 6 */ 7 8 #include <stdio.h> 9 #include <unistd.h> 10 #include <stddef.h> 11 #include <stdlib.h> 12 #include <sys/errno.h> 13 #include <sys/socket.h> 14 #include <sys/wait.h> 15 #include <sys/un.h> 16 #include <net/if.h> 17 #include "user.h" 18 #include "kern_util.h" 19 #include "user_util.h" 20 #include "net_user.h" 21 #include "etap.h" 22 #include "helper.h" 23 #include "os.h" 24 25 #define MAX_PACKET ETH_MAX_PACKET 26 27 void etap_user_init(void *data, void *dev) 28 { 29 struct ethertap_data *pri = data; 30 31 pri->dev = dev; 32 } 33 34 struct addr_change { 35 enum { ADD_ADDR, DEL_ADDR } what; 36 unsigned char addr[4]; 37 unsigned char netmask[4]; 38 }; 39 40 static void etap_change(int op, unsigned char *addr, unsigned char *netmask, 41 int fd) 42 { 43 struct addr_change change; 44 void *output; 45 int n; 46 47 change.what = op; 48 memcpy(change.addr, addr, sizeof(change.addr)); 49 memcpy(change.netmask, netmask, sizeof(change.netmask)); 50 n = os_write_file(fd, &change, sizeof(change)); 51 if(n != sizeof(change)) 52 printk("etap_change - request failed, err = %d\n", -n); 53 output = um_kmalloc(page_size()); 54 if(output == NULL) 55 printk("etap_change : Failed to allocate output buffer\n"); 56 read_output(fd, output, page_size()); 57 if(output != NULL){ 58 printk("%s", output); 59 kfree(output); 60 } 61 } 62 63 static void etap_open_addr(unsigned char *addr, unsigned char *netmask, 64 void *arg) 65 { 66 etap_change(ADD_ADDR, addr, netmask, *((int *) arg)); 67 } 68 69 static void etap_close_addr(unsigned char *addr, unsigned char *netmask, 70 void *arg) 71 { 72 etap_change(DEL_ADDR, addr, netmask, *((int *) arg)); 73 } 74 75 struct etap_pre_exec_data { 76 int control_remote; 77 int control_me; 78 int data_me; 79 }; 80 81 static void etap_pre_exec(void *arg) 82 { 83 struct etap_pre_exec_data *data = arg; 84 85 dup2(data->control_remote, 1); 86 os_close_file(data->data_me); 87 os_close_file(data->control_me); 88 } 89 90 static int etap_tramp(char *dev, char *gate, int control_me, 91 int control_remote, int data_me, int data_remote) 92 { 93 struct etap_pre_exec_data pe_data; 94 int pid, status, err, n; 95 char version_buf[sizeof("nnnnn\0")]; 96 char data_fd_buf[sizeof("nnnnnn\0")]; 97 char gate_buf[sizeof("nnn.nnn.nnn.nnn\0")]; 98 char *setup_args[] = { "uml_net", version_buf, "ethertap", dev, 99 data_fd_buf, gate_buf, NULL }; 100 char *nosetup_args[] = { "uml_net", version_buf, "ethertap", 101 dev, data_fd_buf, NULL }; 102 char **args, c; 103 104 sprintf(data_fd_buf, "%d", data_remote); 105 sprintf(version_buf, "%d", UML_NET_VERSION); 106 if(gate != NULL){ 107 strcpy(gate_buf, gate); 108 args = setup_args; 109 } 110 else args = nosetup_args; 111 112 err = 0; 113 pe_data.control_remote = control_remote; 114 pe_data.control_me = control_me; 115 pe_data.data_me = data_me; 116 pid = run_helper(etap_pre_exec, &pe_data, args, NULL); 117 118 if(pid < 0) err = pid; 119 os_close_file(data_remote); 120 os_close_file(control_remote); 121 n = os_read_file(control_me, &c, sizeof(c)); 122 if(n != sizeof(c)){ 123 printk("etap_tramp : read of status failed, err = %d\n", -n); 124 return(-EINVAL); 125 } 126 if(c != 1){ 127 printk("etap_tramp : uml_net failed\n"); 128 err = -EINVAL; 129 CATCH_EINTR(n = waitpid(pid, &status, 0)); 130 if(n < 0) 131 err = -errno; 132 else if(!WIFEXITED(status) || (WEXITSTATUS(status) != 1)) 133 printk("uml_net didn't exit with status 1\n"); 134 } 135 return(err); 136 } 137 138 static int etap_open(void *data) 139 { 140 struct ethertap_data *pri = data; 141 char *output; 142 int data_fds[2], control_fds[2], err, output_len; 143 144 err = tap_open_common(pri->dev, pri->gate_addr); 145 if(err) return(err); 146 147 err = os_pipe(data_fds, 0, 0); 148 if(err < 0){ 149 printk("data os_pipe failed - err = %d\n", -err); 150 return(err); 151 } 152 153 err = os_pipe(control_fds, 1, 0); 154 if(err < 0){ 155 printk("control os_pipe failed - err = %d\n", -err); 156 return(err); 157 } 158 159 err = etap_tramp(pri->dev_name, pri->gate_addr, control_fds[0], 160 control_fds[1], data_fds[0], data_fds[1]); 161 output_len = page_size(); 162 output = um_kmalloc(output_len); 163 read_output(control_fds[0], output, output_len); 164 165 if(output == NULL) 166 printk("etap_open : failed to allocate output buffer\n"); 167 else { 168 printk("%s", output); 169 kfree(output); 170 } 171 172 if(err < 0){ 173 printk("etap_tramp failed - err = %d\n", -err); 174 return(err); 175 } 176 177 pri->data_fd = data_fds[0]; 178 pri->control_fd = control_fds[0]; 179 iter_addresses(pri->dev, etap_open_addr, &pri->control_fd); 180 return(data_fds[0]); 181 } 182 183 static void etap_close(int fd, void *data) 184 { 185 struct ethertap_data *pri = data; 186 187 iter_addresses(pri->dev, etap_close_addr, &pri->control_fd); 188 os_close_file(fd); 189 os_shutdown_socket(pri->data_fd, 1, 1); 190 os_close_file(pri->data_fd); 191 pri->data_fd = -1; 192 os_close_file(pri->control_fd); 193 pri->control_fd = -1; 194 } 195 196 static int etap_set_mtu(int mtu, void *data) 197 { 198 return(mtu); 199 } 200 201 static void etap_add_addr(unsigned char *addr, unsigned char *netmask, 202 void *data) 203 { 204 struct ethertap_data *pri = data; 205 206 tap_check_ips(pri->gate_addr, addr); 207 if(pri->control_fd == -1) return; 208 etap_open_addr(addr, netmask, &pri->control_fd); 209 } 210 211 static void etap_del_addr(unsigned char *addr, unsigned char *netmask, 212 void *data) 213 { 214 struct ethertap_data *pri = data; 215 216 if(pri->control_fd == -1) return; 217 etap_close_addr(addr, netmask, &pri->control_fd); 218 } 219 220 struct net_user_info ethertap_user_info = { 221 .init = etap_user_init, 222 .open = etap_open, 223 .close = etap_close, 224 .remove = NULL, 225 .set_mtu = etap_set_mtu, 226 .add_address = etap_add_addr, 227 .delete_address = etap_del_addr, 228 .max_packet = MAX_PACKET - ETH_HEADER_ETHERTAP 229 }; 230 231 /* 232 * Overrides for Emacs so that we follow Linus's tabbing style. 233 * Emacs will notice this stuff at the end of the file and automatically 234 * adjust the settings for this buffer only. This must remain at the end 235 * of the file. 236 * --------------------------------------------------------------------------- 237 * Local variables: 238 * c-file-style: "linux" 239 * End: 240 */ 241