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