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