| 1 | /* |
| 2 | * QEMU System Emulator |
| 3 | * |
| 4 | * Copyright (c) 2003-2008 Fabrice Bellard |
| 5 | * |
| 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
| 7 | * of this software and associated documentation files (the "Software"), to deal |
| 8 | * in the Software without restriction, including without limitation the rights |
| 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| 10 | * copies of the Software, and to permit persons to whom the Software is |
| 11 | * furnished to do so, subject to the following conditions: |
| 12 | * |
| 13 | * The above copyright notice and this permission notice shall be included in |
| 14 | * all copies or substantial portions of the Software. |
| 15 | * |
| 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| 19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| 22 | * THE SOFTWARE. |
| 23 | */ |
| 24 | |
| 25 | #include "qemu/osdep.h" |
| 26 | #include "qapi/error.h" |
| 27 | #include "tap_int.h" |
| 28 | #include "qemu/ctype.h" |
| 29 | #include "qemu/cutils.h" |
| 30 | #include "net/net.h" |
| 31 | |
| 32 | #include <sys/ethernet.h> |
| 33 | #include <sys/sockio.h> |
| 34 | #include <netinet/arp.h> |
| 35 | #include <netinet/in.h> |
| 36 | #include <netinet/in_systm.h> |
| 37 | #include <netinet/ip.h> |
| 38 | #include <netinet/ip_icmp.h> // must come after ip.h |
| 39 | #include <netinet/udp.h> |
| 40 | #include <netinet/tcp.h> |
| 41 | #include <net/if.h> |
| 42 | #include <stropts.h> |
| 43 | #include "qemu/error-report.h" |
| 44 | |
| 45 | ssize_t tap_read_packet(int tapfd, uint8_t *buf, int maxlen) |
| 46 | { |
| 47 | struct strbuf sbuf; |
| 48 | int f = 0; |
| 49 | |
| 50 | sbuf.maxlen = maxlen; |
| 51 | sbuf.buf = (char *)buf; |
| 52 | |
| 53 | return getmsg(tapfd, NULL, &sbuf, &f) >= 0 ? sbuf.len : -1; |
| 54 | } |
| 55 | |
| 56 | #define TUNNEWPPA (('T'<<16) | 0x0001) |
| 57 | /* |
| 58 | * Allocate TAP device, returns opened fd. |
| 59 | * Stores dev name in the first arg(must be large enough). |
| 60 | */ |
| 61 | static int tap_alloc(char *dev, size_t dev_size, Error **errp) |
| 62 | { |
| 63 | /* FIXME leaks like a sieve on error paths */ |
| 64 | /* FIXME suspicious: many errors are reported, then ignored */ |
| 65 | int tap_fd, if_fd, ppa = -1; |
| 66 | static int ip_fd = 0; |
| 67 | char *ptr; |
| 68 | |
| 69 | static int arp_fd = 0; |
| 70 | int ip_muxid, arp_muxid; |
| 71 | struct strioctl strioc_if, strioc_ppa; |
| 72 | int link_type = I_PLINK; |
| 73 | struct lifreq ifr; |
| 74 | char actual_name[32] = ""; |
| 75 | |
| 76 | memset(&ifr, 0x0, sizeof(ifr)); |
| 77 | |
| 78 | if( *dev ){ |
| 79 | ptr = dev; |
| 80 | while( *ptr && !qemu_isdigit((int)*ptr) ) ptr++; |
| 81 | ppa = atoi(ptr); |
| 82 | } |
| 83 | |
| 84 | /* Check if IP device was opened */ |
| 85 | if( ip_fd ) |
| 86 | close(ip_fd); |
| 87 | |
| 88 | ip_fd = RETRY_ON_EINTR(open("/dev/udp", O_RDWR, 0)); |
| 89 | if (ip_fd < 0) { |
| 90 | error_setg_file_open(errp, errno, "/dev/udp"); |
| 91 | return -1; |
| 92 | } |
| 93 | |
| 94 | tap_fd = RETRY_ON_EINTR(open("/dev/tap", O_RDWR, 0)); |
| 95 | if (tap_fd < 0) { |
| 96 | error_setg_file_open(errp, errno, "/dev/tap"); |
| 97 | return -1; |
| 98 | } |
| 99 | |
| 100 | /* Assign a new PPA and get its unit number. */ |
| 101 | strioc_ppa.ic_cmd = TUNNEWPPA; |
| 102 | strioc_ppa.ic_timout = 0; |
| 103 | strioc_ppa.ic_len = sizeof(ppa); |
| 104 | strioc_ppa.ic_dp = (char *)&ppa; |
| 105 | if ((ppa = ioctl (tap_fd, I_STR, &strioc_ppa)) < 0) |
| 106 | error_report("Can't assign new interface"); |
| 107 | |
| 108 | if_fd = RETRY_ON_EINTR(open("/dev/tap", O_RDWR, 0)); |
| 109 | if (if_fd < 0) { |
| 110 | error_setg_file_open(errp, errno, "/dev/tap"); |
| 111 | return -1; |
| 112 | } |
| 113 | if(ioctl(if_fd, I_PUSH, "ip") < 0){ |
| 114 | error_setg(errp, "Can't push IP module"); |
| 115 | return -1; |
| 116 | } |
| 117 | |
| 118 | if (ioctl(if_fd, SIOCGLIFFLAGS, &ifr) < 0) |
| 119 | error_report("Can't get flags"); |
| 120 | |
| 121 | snprintf (actual_name, 32, "tap%d", ppa); |
| 122 | pstrcpy(ifr.lifr_name, sizeof(ifr.lifr_name), actual_name); |
| 123 | |
| 124 | ifr.lifr_ppa = ppa; |
| 125 | /* Assign ppa according to the unit number returned by tun device */ |
| 126 | |
| 127 | if (ioctl (if_fd, SIOCSLIFNAME, &ifr) < 0) |
| 128 | error_report("Can't set PPA %d", ppa); |
| 129 | if (ioctl(if_fd, SIOCGLIFFLAGS, &ifr) <0) |
| 130 | error_report("Can't get flags"); |
| 131 | /* Push arp module to if_fd */ |
| 132 | if (ioctl (if_fd, I_PUSH, "arp") < 0) |
| 133 | error_report("Can't push ARP module (2)"); |
| 134 | |
| 135 | /* Push arp module to ip_fd */ |
| 136 | if (ioctl (ip_fd, I_POP, NULL) < 0) |
| 137 | error_report("I_POP failed"); |
| 138 | if (ioctl (ip_fd, I_PUSH, "arp") < 0) |
| 139 | error_report("Can't push ARP module (3)"); |
| 140 | /* Open arp_fd */ |
| 141 | arp_fd = RETRY_ON_EINTR(open("/dev/tap", O_RDWR, 0)); |
| 142 | if (arp_fd < 0) |
| 143 | error_report("Can't open %s", "/dev/tap"); |
| 144 | |
| 145 | /* Set ifname to arp */ |
| 146 | strioc_if.ic_cmd = SIOCSLIFNAME; |
| 147 | strioc_if.ic_timout = 0; |
| 148 | strioc_if.ic_len = sizeof(ifr); |
| 149 | strioc_if.ic_dp = (char *)𝔦 |
| 150 | if (ioctl(arp_fd, I_STR, &strioc_if) < 0){ |
| 151 | error_report("Can't set ifname to arp"); |
| 152 | } |
| 153 | |
| 154 | if((ip_muxid = ioctl(ip_fd, I_LINK, if_fd)) < 0){ |
| 155 | error_setg(errp, "Can't link TAP device to IP"); |
| 156 | return -1; |
| 157 | } |
| 158 | |
| 159 | if ((arp_muxid = ioctl (ip_fd, link_type, arp_fd)) < 0) |
| 160 | error_report("Can't link TAP device to ARP"); |
| 161 | |
| 162 | close (if_fd); |
| 163 | |
| 164 | memset(&ifr, 0x0, sizeof(ifr)); |
| 165 | pstrcpy(ifr.lifr_name, sizeof(ifr.lifr_name), actual_name); |
| 166 | ifr.lifr_ip_muxid = ip_muxid; |
| 167 | ifr.lifr_arp_muxid = arp_muxid; |
| 168 | |
| 169 | if (ioctl (ip_fd, SIOCSLIFMUXID, &ifr) < 0) |
| 170 | { |
| 171 | ioctl (ip_fd, I_PUNLINK , arp_muxid); |
| 172 | ioctl (ip_fd, I_PUNLINK, ip_muxid); |
| 173 | error_report("Can't set multiplexor id"); |
| 174 | } |
| 175 | |
| 176 | snprintf(dev, dev_size, "tap%d", ppa); |
| 177 | return tap_fd; |
| 178 | } |
| 179 | |
| 180 | int tap_open(char *ifname, int ifname_size, int *vnet_hdr, |
| 181 | int vnet_hdr_required, int mq_required, Error **errp) |
| 182 | { |
| 183 | char dev[10]=""; |
| 184 | int fd; |
| 185 | |
| 186 | fd = tap_alloc(dev, sizeof(dev), errp); |
| 187 | if (fd < 0) { |
| 188 | return -1; |
| 189 | } |
| 190 | pstrcpy(ifname, ifname_size, dev); |
| 191 | if (*vnet_hdr) { |
| 192 | /* Solaris doesn't have IFF_VNET_HDR */ |
| 193 | *vnet_hdr = 0; |
| 194 | |
| 195 | if (vnet_hdr_required && !*vnet_hdr) { |
| 196 | error_setg(errp, "vnet_hdr=1 requested, but no kernel " |
| 197 | "support for IFF_VNET_HDR available"); |
| 198 | close(fd); |
| 199 | return -1; |
| 200 | } |
| 201 | } |
| 202 | |
| 203 | if (!qemu_set_blocking(fd, false, errp)) { |
| 204 | close(fd); |
| 205 | return -1; |
| 206 | } |
| 207 | |
| 208 | return fd; |
| 209 | } |
| 210 | |
| 211 | bool tap_set_sndbuf(int fd, int sndbuf, Error **errp) |
| 212 | { |
| 213 | return true; |
| 214 | } |
| 215 | |
| 216 | int tap_probe_vnet_hdr(int fd, Error **errp) |
| 217 | { |
| 218 | return 0; |
| 219 | } |
| 220 | |
| 221 | int tap_probe_has_ufo(int fd) |
| 222 | { |
| 223 | return 0; |
| 224 | } |
| 225 | |
| 226 | int tap_probe_has_uso(int fd) |
| 227 | { |
| 228 | return 0; |
| 229 | } |
| 230 | |
| 231 | bool tap_probe_has_tunnel(int fd) |
| 232 | { |
| 233 | return false; |
| 234 | } |
| 235 | |
| 236 | void tap_fd_set_vnet_hdr_len(int fd, int len) |
| 237 | { |
| 238 | } |
| 239 | |
| 240 | int tap_fd_set_vnet_le(int fd, int is_le) |
| 241 | { |
| 242 | return -EINVAL; |
| 243 | } |
| 244 | |
| 245 | int tap_fd_set_vnet_be(int fd, int is_be) |
| 246 | { |
| 247 | return -EINVAL; |
| 248 | } |
| 249 | |
| 250 | void tap_fd_set_offload(int fd, const NetOffloads *ol) |
| 251 | { |
| 252 | } |
| 253 | |
| 254 | int tap_fd_enable(int fd) |
| 255 | { |
| 256 | return -1; |
| 257 | } |
| 258 | |
| 259 | int tap_fd_disable(int fd) |
| 260 | { |
| 261 | return -1; |
| 262 | } |
| 263 | |
| 264 | int tap_fd_get_ifname(int fd, char *ifname) |
| 265 | { |
| 266 | return -1; |
| 267 | } |
| 268 | |
| 269 | int tap_fd_set_steering_ebpf(int fd, int prog_fd) |
| 270 | { |
| 271 | return -1; |
| 272 | } |