1 /* 2 * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) 3 * Licensed under the GPL 4 */ 5 6 #include <stdio.h> 7 #include <stddef.h> 8 #include <stdlib.h> 9 #include <unistd.h> 10 #include <errno.h> 11 #include <sys/wait.h> 12 #include <sys/socket.h> 13 #include <sys/un.h> 14 #include <sys/uio.h> 15 #include <sys/ioctl.h> 16 #include <net/if.h> 17 #include <linux/if_tun.h> 18 #include "net_user.h" 19 #include "tuntap.h" 20 #include "kern_util.h" 21 #include "user_util.h" 22 #include "user.h" 23 #include "helper.h" 24 #include "os.h" 25 26 #define MAX_PACKET ETH_MAX_PACKET 27 28 void tuntap_user_init(void *data, void *dev) 29 { 30 struct tuntap_data *pri = data; 31 32 pri->dev = dev; 33 } 34 35 static void tuntap_add_addr(unsigned char *addr, unsigned char *netmask, 36 void *data) 37 { 38 struct tuntap_data *pri = data; 39 40 tap_check_ips(pri->gate_addr, addr); 41 if((pri->fd == -1) || pri->fixed_config) return; 42 open_addr(addr, netmask, pri->dev_name); 43 } 44 45 static void tuntap_del_addr(unsigned char *addr, unsigned char *netmask, 46 void *data) 47 { 48 struct tuntap_data *pri = data; 49 50 if((pri->fd == -1) || pri->fixed_config) return; 51 close_addr(addr, netmask, pri->dev_name); 52 } 53 54 struct tuntap_pre_exec_data { 55 int stdout; 56 int close_me; 57 }; 58 59 static void tuntap_pre_exec(void *arg) 60 { 61 struct tuntap_pre_exec_data *data = arg; 62 63 dup2(data->stdout, 1); 64 os_close_file(data->close_me); 65 } 66 67 static int tuntap_open_tramp(char *gate, int *fd_out, int me, int remote, 68 char *buffer, int buffer_len, int *used_out) 69 { 70 struct tuntap_pre_exec_data data; 71 char version_buf[sizeof("nnnnn\0")]; 72 char *argv[] = { "uml_net", version_buf, "tuntap", "up", gate, 73 NULL }; 74 char buf[CMSG_SPACE(sizeof(*fd_out))]; 75 struct msghdr msg; 76 struct cmsghdr *cmsg; 77 struct iovec iov; 78 int pid, n; 79 80 sprintf(version_buf, "%d", UML_NET_VERSION); 81 82 data.stdout = remote; 83 data.close_me = me; 84 85 pid = run_helper(tuntap_pre_exec, &data, argv, NULL); 86 87 if(pid < 0) return(-pid); 88 89 os_close_file(remote); 90 91 msg.msg_name = NULL; 92 msg.msg_namelen = 0; 93 if(buffer != NULL){ 94 iov = ((struct iovec) { buffer, buffer_len }); 95 msg.msg_iov = &iov; 96 msg.msg_iovlen = 1; 97 } 98 else { 99 msg.msg_iov = NULL; 100 msg.msg_iovlen = 0; 101 } 102 msg.msg_control = buf; 103 msg.msg_controllen = sizeof(buf); 104 msg.msg_flags = 0; 105 n = recvmsg(me, &msg, 0); 106 *used_out = n; 107 if(n < 0){ 108 printk("tuntap_open_tramp : recvmsg failed - errno = %d\n", 109 errno); 110 return(-errno); 111 } 112 CATCH_EINTR(waitpid(pid, NULL, 0)); 113 114 cmsg = CMSG_FIRSTHDR(&msg); 115 if(cmsg == NULL){ 116 printk("tuntap_open_tramp : didn't receive a message\n"); 117 return(-EINVAL); 118 } 119 if((cmsg->cmsg_level != SOL_SOCKET) || 120 (cmsg->cmsg_type != SCM_RIGHTS)){ 121 printk("tuntap_open_tramp : didn't receive a descriptor\n"); 122 return(-EINVAL); 123 } 124 *fd_out = ((int *) CMSG_DATA(cmsg))[0]; 125 return(0); 126 } 127 128 static int tuntap_open(void *data) 129 { 130 struct ifreq ifr; 131 struct tuntap_data *pri = data; 132 char *output, *buffer; 133 int err, fds[2], len, used; 134 135 err = tap_open_common(pri->dev, pri->gate_addr); 136 if(err < 0) 137 return(err); 138 139 if(pri->fixed_config){ 140 pri->fd = os_open_file("/dev/net/tun", of_rdwr(OPENFLAGS()), 0); 141 if(pri->fd < 0){ 142 printk("Failed to open /dev/net/tun, err = %d\n", 143 -pri->fd); 144 return(pri->fd); 145 } 146 memset(&ifr, 0, sizeof(ifr)); 147 ifr.ifr_flags = IFF_TAP | IFF_NO_PI; 148 strlcpy(ifr.ifr_name, pri->dev_name, sizeof(ifr.ifr_name)); 149 if(ioctl(pri->fd, TUNSETIFF, (void *) &ifr) < 0){ 150 printk("TUNSETIFF failed, errno = %d\n", errno); 151 os_close_file(pri->fd); 152 return(-errno); 153 } 154 } 155 else { 156 err = os_pipe(fds, 0, 0); 157 if(err < 0){ 158 printk("tuntap_open : os_pipe failed - err = %d\n", 159 -err); 160 return(err); 161 } 162 163 buffer = get_output_buffer(&len); 164 if(buffer != NULL) len--; 165 used = 0; 166 167 err = tuntap_open_tramp(pri->gate_addr, &pri->fd, fds[0], 168 fds[1], buffer, len, &used); 169 170 output = buffer; 171 if(err < 0) { 172 printk("%s", output); 173 free_output_buffer(buffer); 174 printk("tuntap_open_tramp failed - err = %d\n", -err); 175 return(err); 176 } 177 178 pri->dev_name = uml_strdup(buffer); 179 output += IFNAMSIZ; 180 printk("%s", output); 181 free_output_buffer(buffer); 182 183 os_close_file(fds[0]); 184 iter_addresses(pri->dev, open_addr, pri->dev_name); 185 } 186 187 return(pri->fd); 188 } 189 190 static void tuntap_close(int fd, void *data) 191 { 192 struct tuntap_data *pri = data; 193 194 if(!pri->fixed_config) 195 iter_addresses(pri->dev, close_addr, pri->dev_name); 196 os_close_file(fd); 197 pri->fd = -1; 198 } 199 200 static int tuntap_set_mtu(int mtu, void *data) 201 { 202 return(mtu); 203 } 204 205 struct net_user_info tuntap_user_info = { 206 .init = tuntap_user_init, 207 .open = tuntap_open, 208 .close = tuntap_close, 209 .remove = NULL, 210 .set_mtu = tuntap_set_mtu, 211 .add_address = tuntap_add_addr, 212 .delete_address = tuntap_del_addr, 213 .max_packet = MAX_PACKET 214 }; 215 216 /* 217 * Overrides for Emacs so that we follow Linus's tabbing style. 218 * Emacs will notice this stuff at the end of the file and automatically 219 * adjust the settings for this buffer only. This must remain at the end 220 * of the file. 221 * --------------------------------------------------------------------------- 222 * Local variables: 223 * c-file-style: "linux" 224 * End: 225 */ 226