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 "net_user.h" 20 #include "etap.h" 21 #include "os.h" 22 #include "um_malloc.h" 23 #include "kern_constants.h" 24 25 #define MAX_PACKET ETH_MAX_PACKET 26 27 static int etap_user_init(void *data, void *dev) 28 { 29 struct ethertap_data *pri = data; 30 31 pri->dev = dev; 32 return 0; 33 } 34 35 struct addr_change { 36 enum { ADD_ADDR, DEL_ADDR } what; 37 unsigned char addr[4]; 38 unsigned char netmask[4]; 39 }; 40 41 static void etap_change(int op, unsigned char *addr, unsigned char *netmask, 42 int fd) 43 { 44 struct addr_change change; 45 char *output; 46 int n; 47 48 change.what = op; 49 memcpy(change.addr, addr, sizeof(change.addr)); 50 memcpy(change.netmask, netmask, sizeof(change.netmask)); 51 CATCH_EINTR(n = write(fd, &change, sizeof(change))); 52 if(n != sizeof(change)){ 53 printk("etap_change - request failed, err = %d\n", errno); 54 return; 55 } 56 57 output = um_kmalloc(UM_KERN_PAGE_SIZE); 58 if(output == NULL) 59 printk("etap_change : Failed to allocate output buffer\n"); 60 read_output(fd, output, UM_KERN_PAGE_SIZE); 61 if(output != NULL){ 62 printk("%s", output); 63 kfree(output); 64 } 65 } 66 67 static void etap_open_addr(unsigned char *addr, unsigned char *netmask, 68 void *arg) 69 { 70 etap_change(ADD_ADDR, addr, netmask, *((int *) arg)); 71 } 72 73 static void etap_close_addr(unsigned char *addr, unsigned char *netmask, 74 void *arg) 75 { 76 etap_change(DEL_ADDR, addr, netmask, *((int *) arg)); 77 } 78 79 struct etap_pre_exec_data { 80 int control_remote; 81 int control_me; 82 int data_me; 83 }; 84 85 static void etap_pre_exec(void *arg) 86 { 87 struct etap_pre_exec_data *data = arg; 88 89 dup2(data->control_remote, 1); 90 os_close_file(data->data_me); 91 os_close_file(data->control_me); 92 } 93 94 static int etap_tramp(char *dev, char *gate, int control_me, 95 int control_remote, int data_me, int data_remote) 96 { 97 struct etap_pre_exec_data pe_data; 98 int pid, status, err, n; 99 char version_buf[sizeof("nnnnn\0")]; 100 char data_fd_buf[sizeof("nnnnnn\0")]; 101 char gate_buf[sizeof("nnn.nnn.nnn.nnn\0")]; 102 char *setup_args[] = { "uml_net", version_buf, "ethertap", dev, 103 data_fd_buf, gate_buf, NULL }; 104 char *nosetup_args[] = { "uml_net", version_buf, "ethertap", 105 dev, data_fd_buf, NULL }; 106 char **args, c; 107 108 sprintf(data_fd_buf, "%d", data_remote); 109 sprintf(version_buf, "%d", UML_NET_VERSION); 110 if(gate != NULL){ 111 strcpy(gate_buf, gate); 112 args = setup_args; 113 } 114 else args = nosetup_args; 115 116 err = 0; 117 pe_data.control_remote = control_remote; 118 pe_data.control_me = control_me; 119 pe_data.data_me = data_me; 120 pid = run_helper(etap_pre_exec, &pe_data, args, NULL); 121 122 if(pid < 0) 123 err = pid; 124 os_close_file(data_remote); 125 os_close_file(control_remote); 126 CATCH_EINTR(n = read(control_me, &c, sizeof(c))); 127 if(n != sizeof(c)){ 128 err = -errno; 129 printk("etap_tramp : read of status failed, err = %d\n", -err); 130 return err; 131 } 132 if(c != 1){ 133 printk("etap_tramp : uml_net failed\n"); 134 err = -EINVAL; 135 CATCH_EINTR(n = waitpid(pid, &status, 0)); 136 if(n < 0) 137 err = -errno; 138 else if(!WIFEXITED(status) || (WEXITSTATUS(status) != 1)) 139 printk("uml_net didn't exit with status 1\n"); 140 } 141 return err; 142 } 143 144 static int etap_open(void *data) 145 { 146 struct ethertap_data *pri = data; 147 char *output; 148 int data_fds[2], control_fds[2], err, output_len; 149 150 err = tap_open_common(pri->dev, pri->gate_addr); 151 if(err) 152 return err; 153 154 err = os_pipe(data_fds, 0, 0); 155 if(err < 0){ 156 printk("data os_pipe failed - err = %d\n", -err); 157 return err; 158 } 159 160 err = os_pipe(control_fds, 1, 0); 161 if(err < 0){ 162 printk("control os_pipe failed - err = %d\n", -err); 163 return err; 164 } 165 166 err = etap_tramp(pri->dev_name, pri->gate_addr, control_fds[0], 167 control_fds[1], data_fds[0], data_fds[1]); 168 output_len = UM_KERN_PAGE_SIZE; 169 output = um_kmalloc(output_len); 170 read_output(control_fds[0], output, output_len); 171 172 if(output == NULL) 173 printk("etap_open : failed to allocate output buffer\n"); 174 else { 175 printk("%s", output); 176 kfree(output); 177 } 178 179 if(err < 0){ 180 printk("etap_tramp failed - err = %d\n", -err); 181 return err; 182 } 183 184 pri->data_fd = data_fds[0]; 185 pri->control_fd = control_fds[0]; 186 iter_addresses(pri->dev, etap_open_addr, &pri->control_fd); 187 return data_fds[0]; 188 } 189 190 static void etap_close(int fd, void *data) 191 { 192 struct ethertap_data *pri = data; 193 194 iter_addresses(pri->dev, etap_close_addr, &pri->control_fd); 195 os_close_file(fd); 196 os_shutdown_socket(pri->data_fd, 1, 1); 197 os_close_file(pri->data_fd); 198 pri->data_fd = -1; 199 os_close_file(pri->control_fd); 200 pri->control_fd = -1; 201 } 202 203 static int etap_set_mtu(int mtu, void *data) 204 { 205 return mtu; 206 } 207 208 static void etap_add_addr(unsigned char *addr, unsigned char *netmask, 209 void *data) 210 { 211 struct ethertap_data *pri = data; 212 213 tap_check_ips(pri->gate_addr, addr); 214 if(pri->control_fd == -1) 215 return; 216 etap_open_addr(addr, netmask, &pri->control_fd); 217 } 218 219 static void etap_del_addr(unsigned char *addr, unsigned char *netmask, 220 void *data) 221 { 222 struct ethertap_data *pri = data; 223 224 if(pri->control_fd == -1) 225 return; 226 etap_close_addr(addr, netmask, &pri->control_fd); 227 } 228 229 const struct net_user_info ethertap_user_info = { 230 .init = etap_user_init, 231 .open = etap_open, 232 .close = etap_close, 233 .remove = NULL, 234 .set_mtu = etap_set_mtu, 235 .add_address = etap_add_addr, 236 .delete_address = etap_del_addr, 237 .max_packet = MAX_PACKET - ETH_HEADER_ETHERTAP 238 }; 239