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.h" 22 #include "os.h" 23 24 #define MAX_PACKET ETH_MAX_PACKET 25 26 static int tuntap_user_init(void *data, void *dev) 27 { 28 struct tuntap_data *pri = data; 29 30 pri->dev = dev; 31 return 0; 32 } 33 34 static void tuntap_add_addr(unsigned char *addr, unsigned char *netmask, 35 void *data) 36 { 37 struct tuntap_data *pri = data; 38 39 tap_check_ips(pri->gate_addr, addr); 40 if((pri->fd == -1) || pri->fixed_config) 41 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) 51 return; 52 close_addr(addr, netmask, pri->dev_name); 53 } 54 55 struct tuntap_pre_exec_data { 56 int stdout; 57 int close_me; 58 }; 59 60 static void tuntap_pre_exec(void *arg) 61 { 62 struct tuntap_pre_exec_data *data = arg; 63 64 dup2(data->stdout, 1); 65 os_close_file(data->close_me); 66 } 67 68 static int tuntap_open_tramp(char *gate, int *fd_out, int me, int remote, 69 char *buffer, int buffer_len, int *used_out) 70 { 71 struct tuntap_pre_exec_data data; 72 char version_buf[sizeof("nnnnn\0")]; 73 char *argv[] = { "uml_net", version_buf, "tuntap", "up", gate, 74 NULL }; 75 char buf[CMSG_SPACE(sizeof(*fd_out))]; 76 struct msghdr msg; 77 struct cmsghdr *cmsg; 78 struct iovec iov; 79 int pid, n, err; 80 81 sprintf(version_buf, "%d", UML_NET_VERSION); 82 83 data.stdout = remote; 84 data.close_me = me; 85 86 pid = run_helper(tuntap_pre_exec, &data, argv, NULL); 87 88 if(pid < 0) 89 return -pid; 90 91 os_close_file(remote); 92 93 msg.msg_name = NULL; 94 msg.msg_namelen = 0; 95 if(buffer != NULL){ 96 iov = ((struct iovec) { buffer, buffer_len }); 97 msg.msg_iov = &iov; 98 msg.msg_iovlen = 1; 99 } 100 else { 101 msg.msg_iov = NULL; 102 msg.msg_iovlen = 0; 103 } 104 msg.msg_control = buf; 105 msg.msg_controllen = sizeof(buf); 106 msg.msg_flags = 0; 107 n = recvmsg(me, &msg, 0); 108 *used_out = n; 109 if(n < 0){ 110 err = -errno; 111 printk("tuntap_open_tramp : recvmsg failed - errno = %d\n", 112 errno); 113 return err; 114 } 115 CATCH_EINTR(waitpid(pid, NULL, 0)); 116 117 cmsg = CMSG_FIRSTHDR(&msg); 118 if(cmsg == NULL){ 119 printk("tuntap_open_tramp : didn't receive a message\n"); 120 return -EINVAL; 121 } 122 if((cmsg->cmsg_level != SOL_SOCKET) || 123 (cmsg->cmsg_type != SCM_RIGHTS)){ 124 printk("tuntap_open_tramp : didn't receive a descriptor\n"); 125 return -EINVAL; 126 } 127 *fd_out = ((int *) CMSG_DATA(cmsg))[0]; 128 os_set_exec_close(*fd_out, 1); 129 return 0; 130 } 131 132 static int tuntap_open(void *data) 133 { 134 struct ifreq ifr; 135 struct tuntap_data *pri = data; 136 char *output, *buffer; 137 int err, fds[2], len, used; 138 139 err = tap_open_common(pri->dev, pri->gate_addr); 140 if(err < 0) 141 return err; 142 143 if(pri->fixed_config){ 144 pri->fd = os_open_file("/dev/net/tun", 145 of_cloexec(of_rdwr(OPENFLAGS())), 0); 146 if(pri->fd < 0){ 147 printk("Failed to open /dev/net/tun, err = %d\n", 148 -pri->fd); 149 return pri->fd; 150 } 151 memset(&ifr, 0, sizeof(ifr)); 152 ifr.ifr_flags = IFF_TAP | IFF_NO_PI; 153 strlcpy(ifr.ifr_name, pri->dev_name, sizeof(ifr.ifr_name)); 154 if(ioctl(pri->fd, TUNSETIFF, (void *) &ifr) < 0){ 155 err = -errno; 156 printk("TUNSETIFF failed, errno = %d\n", errno); 157 os_close_file(pri->fd); 158 return err; 159 } 160 } 161 else { 162 err = os_pipe(fds, 0, 0); 163 if(err < 0){ 164 printk("tuntap_open : os_pipe failed - err = %d\n", 165 -err); 166 return err; 167 } 168 169 buffer = get_output_buffer(&len); 170 if(buffer != NULL) len--; 171 used = 0; 172 173 err = tuntap_open_tramp(pri->gate_addr, &pri->fd, fds[0], 174 fds[1], buffer, len, &used); 175 176 output = buffer; 177 if(err < 0) { 178 printk("%s", output); 179 free_output_buffer(buffer); 180 printk("tuntap_open_tramp failed - err = %d\n", -err); 181 return err; 182 } 183 184 pri->dev_name = uml_strdup(buffer); 185 output += IFNAMSIZ; 186 printk("%s", output); 187 free_output_buffer(buffer); 188 189 os_close_file(fds[0]); 190 iter_addresses(pri->dev, open_addr, pri->dev_name); 191 } 192 193 return pri->fd; 194 } 195 196 static void tuntap_close(int fd, void *data) 197 { 198 struct tuntap_data *pri = data; 199 200 if(!pri->fixed_config) 201 iter_addresses(pri->dev, close_addr, pri->dev_name); 202 os_close_file(fd); 203 pri->fd = -1; 204 } 205 206 static int tuntap_set_mtu(int mtu, void *data) 207 { 208 return mtu; 209 } 210 211 const struct net_user_info tuntap_user_info = { 212 .init = tuntap_user_init, 213 .open = tuntap_open, 214 .close = tuntap_close, 215 .remove = NULL, 216 .set_mtu = tuntap_set_mtu, 217 .add_address = tuntap_add_addr, 218 .delete_address = tuntap_del_addr, 219 .max_packet = MAX_PACKET 220 }; 221