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