1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 4 */ 5 6 #include <stdbool.h> 7 #include <stdio.h> 8 #include <unistd.h> 9 #include <stdarg.h> 10 #include <errno.h> 11 #include <stddef.h> 12 #include <string.h> 13 #include <sys/ioctl.h> 14 #include <net/if.h> 15 #include <linux/if_tun.h> 16 #include <arpa/inet.h> 17 #include <sys/types.h> 18 #include <sys/stat.h> 19 #include <fcntl.h> 20 #include <sys/socket.h> 21 #include <sys/un.h> 22 #include <netinet/ip.h> 23 #include <linux/if_ether.h> 24 #include <linux/if_packet.h> 25 #include <sys/wait.h> 26 #include <sys/uio.h> 27 #include <linux/virtio_net.h> 28 #include <netdb.h> 29 #include <stdlib.h> 30 #include <os.h> 31 #include <limits.h> 32 #include <um_malloc.h> 33 #include "vector_user.h" 34 35 #define ID_GRE 0 36 #define ID_L2TPV3 1 37 #define ID_BESS 2 38 #define ID_MAX 2 39 40 #define TOKEN_IFNAME "ifname" 41 #define TOKEN_SCRIPT "ifup" 42 43 #define TRANS_RAW "raw" 44 #define TRANS_RAW_LEN strlen(TRANS_RAW) 45 46 #define TRANS_FD "fd" 47 #define TRANS_FD_LEN strlen(TRANS_FD) 48 49 #define VNET_HDR_FAIL "could not enable vnet headers on fd %d" 50 #define TUN_GET_F_FAIL "tapraw: TUNGETFEATURES failed: %s" 51 #define L2TPV3_BIND_FAIL "l2tpv3_open : could not bind socket err=%i" 52 #define UNIX_BIND_FAIL "unix_open : could not bind socket err=%i" 53 #define BPF_ATTACH_FAIL "Failed to attach filter size %d prog %px to %d, err %d\n" 54 #define BPF_DETACH_FAIL "Failed to detach filter size %d prog %px to %d, err %d\n" 55 56 #define MAX_UN_LEN 107 57 58 static const char padchar[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 59 static const char *template = "tapXXXXXX"; 60 61 /* This is very ugly and brute force lookup, but it is done 62 * only once at initialization so not worth doing hashes or 63 * anything more intelligent 64 */ 65 66 char *uml_vector_fetch_arg(struct arglist *ifspec, char *token) 67 { 68 int i; 69 70 for (i = 0; i < ifspec->numargs; i++) { 71 if (strcmp(ifspec->tokens[i], token) == 0) 72 return ifspec->values[i]; 73 } 74 return NULL; 75 76 } 77 78 struct arglist *uml_parse_vector_ifspec(char *arg) 79 { 80 struct arglist *result; 81 int pos, len; 82 bool parsing_token = true, next_starts = true; 83 84 if (arg == NULL) 85 return NULL; 86 result = uml_kmalloc(sizeof(struct arglist), UM_GFP_KERNEL); 87 if (result == NULL) 88 return NULL; 89 result->numargs = 0; 90 len = strlen(arg); 91 for (pos = 0; pos < len; pos++) { 92 if (next_starts) { 93 if (parsing_token) { 94 result->tokens[result->numargs] = arg + pos; 95 } else { 96 result->values[result->numargs] = arg + pos; 97 result->numargs++; 98 } 99 next_starts = false; 100 } 101 if (*(arg + pos) == '=') { 102 if (parsing_token) 103 parsing_token = false; 104 else 105 goto cleanup; 106 next_starts = true; 107 (*(arg + pos)) = '\0'; 108 } 109 if (*(arg + pos) == ',') { 110 parsing_token = true; 111 next_starts = true; 112 (*(arg + pos)) = '\0'; 113 } 114 } 115 return result; 116 cleanup: 117 printk(UM_KERN_ERR "vector_setup - Couldn't parse '%s'\n", arg); 118 kfree(result); 119 return NULL; 120 } 121 122 /* 123 * Socket/FD configuration functions. These return an structure 124 * of rx and tx descriptors to cover cases where these are not 125 * the same (f.e. read via raw socket and write via tap). 126 */ 127 128 #define PATH_NET_TUN "/dev/net/tun" 129 130 131 static int create_tap_fd(char *iface) 132 { 133 struct ifreq ifr; 134 int fd = -1; 135 int err = -ENOMEM, offload; 136 137 fd = open(PATH_NET_TUN, O_RDWR); 138 if (fd < 0) { 139 printk(UM_KERN_ERR "uml_tap: failed to open tun device\n"); 140 goto tap_fd_cleanup; 141 } 142 memset(&ifr, 0, sizeof(ifr)); 143 ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_VNET_HDR; 144 strscpy(ifr.ifr_name, iface); 145 146 err = ioctl(fd, TUNSETIFF, (void *) &ifr); 147 if (err != 0) { 148 printk(UM_KERN_ERR "uml_tap: failed to select tap interface\n"); 149 goto tap_fd_cleanup; 150 } 151 152 offload = TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6; 153 ioctl(fd, TUNSETOFFLOAD, offload); 154 return fd; 155 tap_fd_cleanup: 156 if (fd >= 0) 157 os_close_file(fd); 158 return err; 159 } 160 161 static int create_raw_fd(char *iface, int flags, int proto) 162 { 163 struct ifreq ifr; 164 int fd = -1; 165 struct sockaddr_ll sock; 166 int err = -ENOMEM; 167 168 fd = socket(AF_PACKET, SOCK_RAW, flags); 169 if (fd == -1) { 170 err = -errno; 171 goto raw_fd_cleanup; 172 } 173 memset(&ifr, 0, sizeof(ifr)); 174 strscpy(ifr.ifr_name, iface); 175 if (ioctl(fd, SIOCGIFINDEX, (void *) &ifr) < 0) { 176 err = -errno; 177 goto raw_fd_cleanup; 178 } 179 180 sock.sll_family = AF_PACKET; 181 sock.sll_protocol = htons(proto); 182 sock.sll_ifindex = ifr.ifr_ifindex; 183 184 if (bind(fd, 185 (struct sockaddr *) &sock, sizeof(struct sockaddr_ll)) < 0) { 186 err = -errno; 187 goto raw_fd_cleanup; 188 } 189 return fd; 190 raw_fd_cleanup: 191 printk(UM_KERN_ERR "user_init_raw: init failed, error %d", err); 192 if (fd >= 0) 193 os_close_file(fd); 194 return err; 195 } 196 197 198 static struct vector_fds *user_init_tap_fds(struct arglist *ifspec) 199 { 200 int fd = -1, i; 201 char *iface; 202 struct vector_fds *result = NULL; 203 bool dynamic = false; 204 char dynamic_ifname[IFNAMSIZ]; 205 char *argv[] = {NULL, NULL, NULL, NULL}; 206 207 iface = uml_vector_fetch_arg(ifspec, TOKEN_IFNAME); 208 if (iface == NULL) { 209 dynamic = true; 210 iface = dynamic_ifname; 211 srand(getpid()); 212 } 213 214 result = uml_kmalloc(sizeof(struct vector_fds), UM_GFP_KERNEL); 215 if (result == NULL) { 216 printk(UM_KERN_ERR "uml_tap: failed to allocate file descriptors\n"); 217 goto tap_cleanup; 218 } 219 result->rx_fd = -1; 220 result->tx_fd = -1; 221 result->remote_addr = NULL; 222 result->remote_addr_size = 0; 223 224 /* TAP */ 225 do { 226 if (dynamic) { 227 strcpy(iface, template); 228 for (i = 0; i < strlen(iface); i++) { 229 if (iface[i] == 'X') { 230 iface[i] = padchar[rand() % strlen(padchar)]; 231 } 232 } 233 } 234 fd = create_tap_fd(iface); 235 if ((fd < 0) && (!dynamic)) { 236 printk(UM_KERN_ERR "uml_tap: failed to create tun interface\n"); 237 goto tap_cleanup; 238 } 239 result->tx_fd = fd; 240 result->rx_fd = fd; 241 } while (fd < 0); 242 243 argv[0] = uml_vector_fetch_arg(ifspec, TOKEN_SCRIPT); 244 if (argv[0]) { 245 argv[1] = iface; 246 run_helper(NULL, NULL, argv); 247 } 248 249 return result; 250 tap_cleanup: 251 printk(UM_KERN_ERR "user_init_tap: init failed, error %d", fd); 252 kfree(result); 253 return NULL; 254 } 255 256 static struct vector_fds *user_init_hybrid_fds(struct arglist *ifspec) 257 { 258 char *iface; 259 struct vector_fds *result = NULL; 260 char *argv[] = {NULL, NULL, NULL, NULL}; 261 262 iface = uml_vector_fetch_arg(ifspec, TOKEN_IFNAME); 263 if (iface == NULL) { 264 printk(UM_KERN_ERR "uml_tap: failed to parse interface spec\n"); 265 goto hybrid_cleanup; 266 } 267 268 result = uml_kmalloc(sizeof(struct vector_fds), UM_GFP_KERNEL); 269 if (result == NULL) { 270 printk(UM_KERN_ERR "uml_tap: failed to allocate file descriptors\n"); 271 goto hybrid_cleanup; 272 } 273 result->rx_fd = -1; 274 result->tx_fd = -1; 275 result->remote_addr = NULL; 276 result->remote_addr_size = 0; 277 278 /* TAP */ 279 280 result->tx_fd = create_tap_fd(iface); 281 if (result->tx_fd < 0) { 282 printk(UM_KERN_ERR "uml_tap: failed to create tun interface: %i\n", result->tx_fd); 283 goto hybrid_cleanup; 284 } 285 286 /* RAW */ 287 288 result->rx_fd = create_raw_fd(iface, ETH_P_ALL, ETH_P_ALL); 289 if (result->rx_fd == -1) { 290 printk(UM_KERN_ERR 291 "uml_tap: failed to create paired raw socket: %i\n", result->rx_fd); 292 goto hybrid_cleanup; 293 } 294 295 argv[0] = uml_vector_fetch_arg(ifspec, TOKEN_SCRIPT); 296 if (argv[0]) { 297 argv[1] = iface; 298 run_helper(NULL, NULL, argv); 299 } 300 return result; 301 hybrid_cleanup: 302 printk(UM_KERN_ERR "user_init_hybrid: init failed"); 303 kfree(result); 304 return NULL; 305 } 306 307 static struct vector_fds *user_init_unix_fds(struct arglist *ifspec, int id) 308 { 309 int fd = -1; 310 int socktype; 311 char *src, *dst; 312 struct vector_fds *result = NULL; 313 struct sockaddr_un *local_addr = NULL, *remote_addr = NULL; 314 315 src = uml_vector_fetch_arg(ifspec, "src"); 316 dst = uml_vector_fetch_arg(ifspec, "dst"); 317 result = uml_kmalloc(sizeof(struct vector_fds), UM_GFP_KERNEL); 318 if (result == NULL) { 319 printk(UM_KERN_ERR "unix open:cannot allocate remote addr"); 320 goto unix_cleanup; 321 } 322 remote_addr = uml_kmalloc(sizeof(struct sockaddr_un), UM_GFP_KERNEL); 323 if (remote_addr == NULL) { 324 printk(UM_KERN_ERR "unix open:cannot allocate remote addr"); 325 goto unix_cleanup; 326 } 327 328 switch (id) { 329 case ID_BESS: 330 socktype = SOCK_SEQPACKET; 331 if ((src != NULL) && (strlen(src) <= MAX_UN_LEN)) { 332 local_addr = uml_kmalloc(sizeof(struct sockaddr_un), UM_GFP_KERNEL); 333 if (local_addr == NULL) { 334 printk(UM_KERN_ERR "bess open:cannot allocate local addr"); 335 goto unix_cleanup; 336 } 337 local_addr->sun_family = AF_UNIX; 338 memcpy(local_addr->sun_path, src, strlen(src) + 1); 339 } 340 if ((dst == NULL) || (strlen(dst) > MAX_UN_LEN)) 341 goto unix_cleanup; 342 remote_addr->sun_family = AF_UNIX; 343 memcpy(remote_addr->sun_path, dst, strlen(dst) + 1); 344 break; 345 default: 346 printk(KERN_ERR "Unsupported unix socket type\n"); 347 return NULL; 348 } 349 350 fd = socket(AF_UNIX, socktype, 0); 351 if (fd == -1) { 352 printk(UM_KERN_ERR 353 "unix open: could not open socket, error = %d", 354 -errno 355 ); 356 goto unix_cleanup; 357 } 358 if (local_addr != NULL) { 359 if (bind(fd, (struct sockaddr *) local_addr, sizeof(struct sockaddr_un))) { 360 printk(UM_KERN_ERR UNIX_BIND_FAIL, errno); 361 goto unix_cleanup; 362 } 363 } 364 switch (id) { 365 case ID_BESS: 366 if (connect(fd, (const struct sockaddr *) remote_addr, sizeof(struct sockaddr_un)) < 0) { 367 printk(UM_KERN_ERR "bess open:cannot connect to %s %i", remote_addr->sun_path, -errno); 368 goto unix_cleanup; 369 } 370 break; 371 } 372 result->rx_fd = fd; 373 result->tx_fd = fd; 374 result->remote_addr_size = sizeof(struct sockaddr_un); 375 result->remote_addr = remote_addr; 376 return result; 377 unix_cleanup: 378 if (fd >= 0) 379 os_close_file(fd); 380 kfree(remote_addr); 381 kfree(result); 382 return NULL; 383 } 384 385 static int strtofd(const char *nptr) 386 { 387 long fd; 388 char *endptr; 389 390 if (nptr == NULL) 391 return -1; 392 393 errno = 0; 394 fd = strtol(nptr, &endptr, 10); 395 if (nptr == endptr || 396 errno != 0 || 397 *endptr != '\0' || 398 fd < 0 || 399 fd > INT_MAX) { 400 return -1; 401 } 402 return fd; 403 } 404 405 static struct vector_fds *user_init_fd_fds(struct arglist *ifspec) 406 { 407 int fd = -1; 408 char *fdarg = NULL; 409 struct vector_fds *result = NULL; 410 411 fdarg = uml_vector_fetch_arg(ifspec, "fd"); 412 fd = strtofd(fdarg); 413 if (fd == -1) { 414 printk(UM_KERN_ERR "fd open: bad or missing fd argument"); 415 goto fd_cleanup; 416 } 417 418 result = uml_kmalloc(sizeof(struct vector_fds), UM_GFP_KERNEL); 419 if (result == NULL) { 420 printk(UM_KERN_ERR "fd open: allocation failed"); 421 goto fd_cleanup; 422 } 423 424 result->rx_fd = fd; 425 result->tx_fd = fd; 426 result->remote_addr_size = 0; 427 result->remote_addr = NULL; 428 return result; 429 430 fd_cleanup: 431 if (fd >= 0) 432 os_close_file(fd); 433 kfree(result); 434 return NULL; 435 } 436 437 static struct vector_fds *user_init_raw_fds(struct arglist *ifspec) 438 { 439 int rxfd = -1, txfd = -1; 440 int err = -ENOMEM; 441 char *iface; 442 struct vector_fds *result = NULL; 443 char *argv[] = {NULL, NULL, NULL, NULL}; 444 445 iface = uml_vector_fetch_arg(ifspec, TOKEN_IFNAME); 446 if (iface == NULL) 447 goto raw_cleanup; 448 449 rxfd = create_raw_fd(iface, ETH_P_ALL, ETH_P_ALL); 450 if (rxfd == -1) { 451 err = -errno; 452 goto raw_cleanup; 453 } 454 txfd = create_raw_fd(iface, 0, ETH_P_IP); /* Turn off RX on this fd */ 455 if (txfd == -1) { 456 err = -errno; 457 goto raw_cleanup; 458 } 459 result = uml_kmalloc(sizeof(struct vector_fds), UM_GFP_KERNEL); 460 if (result != NULL) { 461 result->rx_fd = rxfd; 462 result->tx_fd = txfd; 463 result->remote_addr = NULL; 464 result->remote_addr_size = 0; 465 } 466 argv[0] = uml_vector_fetch_arg(ifspec, TOKEN_SCRIPT); 467 if (argv[0]) { 468 argv[1] = iface; 469 run_helper(NULL, NULL, argv); 470 } 471 return result; 472 raw_cleanup: 473 printk(UM_KERN_ERR "user_init_raw: init failed, error %d", err); 474 kfree(result); 475 return NULL; 476 } 477 478 479 bool uml_raw_enable_qdisc_bypass(int fd) 480 { 481 int optval = 1; 482 483 if (setsockopt(fd, 484 SOL_PACKET, PACKET_QDISC_BYPASS, 485 &optval, sizeof(optval)) != 0) { 486 return false; 487 } 488 return true; 489 } 490 491 bool uml_raw_enable_vnet_headers(int fd) 492 { 493 int optval = 1; 494 495 if (setsockopt(fd, 496 SOL_PACKET, PACKET_VNET_HDR, 497 &optval, sizeof(optval)) != 0) { 498 printk(UM_KERN_INFO VNET_HDR_FAIL, fd); 499 return false; 500 } 501 return true; 502 } 503 bool uml_tap_enable_vnet_headers(int fd) 504 { 505 unsigned int features; 506 int len = sizeof(struct virtio_net_hdr); 507 508 if (ioctl(fd, TUNGETFEATURES, &features) == -1) { 509 printk(UM_KERN_INFO TUN_GET_F_FAIL, strerror(errno)); 510 return false; 511 } 512 if ((features & IFF_VNET_HDR) == 0) { 513 printk(UM_KERN_INFO "tapraw: No VNET HEADER support"); 514 return false; 515 } 516 ioctl(fd, TUNSETVNETHDRSZ, &len); 517 return true; 518 } 519 520 static struct vector_fds *user_init_socket_fds(struct arglist *ifspec, int id) 521 { 522 int err = -ENOMEM; 523 int fd = -1, gairet; 524 struct addrinfo srchints; 525 struct addrinfo dsthints; 526 bool v6, udp; 527 char *value; 528 char *src, *dst, *srcport, *dstport; 529 struct addrinfo *gairesult = NULL; 530 struct vector_fds *result = NULL; 531 532 533 value = uml_vector_fetch_arg(ifspec, "v6"); 534 v6 = false; 535 udp = false; 536 if (value != NULL) { 537 if (strtol((const char *) value, NULL, 10) > 0) 538 v6 = true; 539 } 540 541 value = uml_vector_fetch_arg(ifspec, "udp"); 542 if (value != NULL) { 543 if (strtol((const char *) value, NULL, 10) > 0) 544 udp = true; 545 } 546 src = uml_vector_fetch_arg(ifspec, "src"); 547 dst = uml_vector_fetch_arg(ifspec, "dst"); 548 srcport = uml_vector_fetch_arg(ifspec, "srcport"); 549 dstport = uml_vector_fetch_arg(ifspec, "dstport"); 550 551 memset(&dsthints, 0, sizeof(dsthints)); 552 553 if (v6) 554 dsthints.ai_family = AF_INET6; 555 else 556 dsthints.ai_family = AF_INET; 557 558 switch (id) { 559 case ID_GRE: 560 dsthints.ai_socktype = SOCK_RAW; 561 dsthints.ai_protocol = IPPROTO_GRE; 562 break; 563 case ID_L2TPV3: 564 if (udp) { 565 dsthints.ai_socktype = SOCK_DGRAM; 566 dsthints.ai_protocol = 0; 567 } else { 568 dsthints.ai_socktype = SOCK_RAW; 569 dsthints.ai_protocol = IPPROTO_L2TP; 570 } 571 break; 572 default: 573 printk(KERN_ERR "Unsupported socket type\n"); 574 return NULL; 575 } 576 memcpy(&srchints, &dsthints, sizeof(struct addrinfo)); 577 578 gairet = getaddrinfo(src, srcport, &dsthints, &gairesult); 579 if ((gairet != 0) || (gairesult == NULL)) { 580 printk(UM_KERN_ERR 581 "socket_open : could not resolve src, error = %s", 582 gai_strerror(gairet) 583 ); 584 return NULL; 585 } 586 fd = socket(gairesult->ai_family, 587 gairesult->ai_socktype, gairesult->ai_protocol); 588 if (fd == -1) { 589 printk(UM_KERN_ERR 590 "socket_open : could not open socket, error = %d", 591 -errno 592 ); 593 goto cleanup; 594 } 595 if (bind(fd, 596 (struct sockaddr *) gairesult->ai_addr, 597 gairesult->ai_addrlen)) { 598 printk(UM_KERN_ERR L2TPV3_BIND_FAIL, errno); 599 goto cleanup; 600 } 601 602 if (gairesult != NULL) 603 freeaddrinfo(gairesult); 604 605 gairesult = NULL; 606 607 gairet = getaddrinfo(dst, dstport, &dsthints, &gairesult); 608 if ((gairet != 0) || (gairesult == NULL)) { 609 printk(UM_KERN_ERR 610 "socket_open : could not resolve dst, error = %s", 611 gai_strerror(gairet) 612 ); 613 return NULL; 614 } 615 616 result = uml_kmalloc(sizeof(struct vector_fds), UM_GFP_KERNEL); 617 if (result != NULL) { 618 result->rx_fd = fd; 619 result->tx_fd = fd; 620 result->remote_addr = uml_kmalloc( 621 gairesult->ai_addrlen, UM_GFP_KERNEL); 622 if (result->remote_addr == NULL) 623 goto cleanup; 624 result->remote_addr_size = gairesult->ai_addrlen; 625 memcpy( 626 result->remote_addr, 627 gairesult->ai_addr, 628 gairesult->ai_addrlen 629 ); 630 } 631 freeaddrinfo(gairesult); 632 return result; 633 cleanup: 634 if (gairesult != NULL) 635 freeaddrinfo(gairesult); 636 printk(UM_KERN_ERR "user_init_socket: init failed, error %d", err); 637 if (fd >= 0) 638 os_close_file(fd); 639 if (result != NULL) { 640 kfree(result->remote_addr); 641 kfree(result); 642 } 643 return NULL; 644 } 645 646 struct vector_fds *uml_vector_user_open( 647 int unit, 648 struct arglist *parsed 649 ) 650 { 651 char *transport; 652 653 if (parsed == NULL) { 654 printk(UM_KERN_ERR "no parsed config for unit %d\n", unit); 655 return NULL; 656 } 657 transport = uml_vector_fetch_arg(parsed, "transport"); 658 if (transport == NULL) { 659 printk(UM_KERN_ERR "missing transport for unit %d\n", unit); 660 return NULL; 661 } 662 if (strncmp(transport, TRANS_RAW, TRANS_RAW_LEN) == 0) 663 return user_init_raw_fds(parsed); 664 if (strncmp(transport, TRANS_HYBRID, TRANS_HYBRID_LEN) == 0) 665 return user_init_hybrid_fds(parsed); 666 if (strncmp(transport, TRANS_TAP, TRANS_TAP_LEN) == 0) 667 return user_init_tap_fds(parsed); 668 if (strncmp(transport, TRANS_GRE, TRANS_GRE_LEN) == 0) 669 return user_init_socket_fds(parsed, ID_GRE); 670 if (strncmp(transport, TRANS_L2TPV3, TRANS_L2TPV3_LEN) == 0) 671 return user_init_socket_fds(parsed, ID_L2TPV3); 672 if (strncmp(transport, TRANS_BESS, TRANS_BESS_LEN) == 0) 673 return user_init_unix_fds(parsed, ID_BESS); 674 if (strncmp(transport, TRANS_FD, TRANS_FD_LEN) == 0) 675 return user_init_fd_fds(parsed); 676 return NULL; 677 } 678 679 680 int uml_vector_sendmsg(int fd, void *hdr, int flags) 681 { 682 int n; 683 684 CATCH_EINTR(n = sendmsg(fd, (struct msghdr *) hdr, flags)); 685 if ((n < 0) && (errno == EAGAIN)) 686 return 0; 687 if (n >= 0) 688 return n; 689 else 690 return -errno; 691 } 692 693 int uml_vector_recvmsg(int fd, void *hdr, int flags) 694 { 695 int n; 696 struct msghdr *msg = (struct msghdr *) hdr; 697 698 CATCH_EINTR(n = readv(fd, msg->msg_iov, msg->msg_iovlen)); 699 if ((n < 0) && (errno == EAGAIN)) 700 return 0; 701 if (n >= 0) 702 return n; 703 else 704 return -errno; 705 } 706 707 int uml_vector_writev(int fd, void *hdr, int iovcount) 708 { 709 int n; 710 711 CATCH_EINTR(n = writev(fd, (struct iovec *) hdr, iovcount)); 712 if ((n < 0) && ((errno == EAGAIN) || (errno == ENOBUFS))) 713 return 0; 714 if (n >= 0) 715 return n; 716 else 717 return -errno; 718 } 719 720 int uml_vector_sendmmsg( 721 int fd, 722 void *msgvec, 723 unsigned int vlen, 724 unsigned int flags) 725 { 726 int n; 727 728 CATCH_EINTR(n = sendmmsg(fd, (struct mmsghdr *) msgvec, vlen, flags)); 729 if ((n < 0) && ((errno == EAGAIN) || (errno == ENOBUFS))) 730 return 0; 731 if (n >= 0) 732 return n; 733 else 734 return -errno; 735 } 736 737 int uml_vector_recvmmsg( 738 int fd, 739 void *msgvec, 740 unsigned int vlen, 741 unsigned int flags) 742 { 743 int n; 744 745 CATCH_EINTR( 746 n = recvmmsg(fd, (struct mmsghdr *) msgvec, vlen, flags, 0)); 747 if ((n < 0) && (errno == EAGAIN)) 748 return 0; 749 if (n >= 0) 750 return n; 751 else 752 return -errno; 753 } 754 int uml_vector_attach_bpf(int fd, void *bpf) 755 { 756 struct sock_fprog *prog = bpf; 757 758 int err = setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, bpf, sizeof(struct sock_fprog)); 759 760 if (err < 0) 761 printk(KERN_ERR BPF_ATTACH_FAIL, prog->len, prog->filter, fd, -errno); 762 return err; 763 } 764 765 int uml_vector_detach_bpf(int fd, void *bpf) 766 { 767 struct sock_fprog *prog = bpf; 768 769 int err = setsockopt(fd, SOL_SOCKET, SO_DETACH_FILTER, bpf, sizeof(struct sock_fprog)); 770 if (err < 0) 771 printk(KERN_ERR BPF_DETACH_FAIL, prog->len, prog->filter, fd, -errno); 772 return err; 773 } 774 void *uml_vector_default_bpf(const void *mac) 775 { 776 struct sock_filter *bpf; 777 uint32_t *mac1 = (uint32_t *)(mac + 2); 778 uint16_t *mac2 = (uint16_t *) mac; 779 struct sock_fprog *bpf_prog; 780 781 bpf_prog = uml_kmalloc(sizeof(struct sock_fprog), UM_GFP_KERNEL); 782 if (bpf_prog) { 783 bpf_prog->len = DEFAULT_BPF_LEN; 784 bpf_prog->filter = NULL; 785 } else { 786 return NULL; 787 } 788 bpf = uml_kmalloc( 789 sizeof(struct sock_filter) * DEFAULT_BPF_LEN, UM_GFP_KERNEL); 790 if (bpf) { 791 bpf_prog->filter = bpf; 792 /* ld [8] */ 793 bpf[0] = (struct sock_filter){ 0x20, 0, 0, 0x00000008 }; 794 /* jeq #0xMAC[2-6] jt 2 jf 5*/ 795 bpf[1] = (struct sock_filter){ 0x15, 0, 3, ntohl(*mac1)}; 796 /* ldh [6] */ 797 bpf[2] = (struct sock_filter){ 0x28, 0, 0, 0x00000006 }; 798 /* jeq #0xMAC[0-1] jt 4 jf 5 */ 799 bpf[3] = (struct sock_filter){ 0x15, 0, 1, ntohs(*mac2)}; 800 /* ret #0 */ 801 bpf[4] = (struct sock_filter){ 0x6, 0, 0, 0x00000000 }; 802 /* ret #0x40000 */ 803 bpf[5] = (struct sock_filter){ 0x6, 0, 0, 0x00040000 }; 804 } else { 805 kfree(bpf_prog); 806 bpf_prog = NULL; 807 } 808 return bpf_prog; 809 } 810 811 /* Note - this function requires a valid mac being passed as an arg */ 812 813 void *uml_vector_user_bpf(char *filename) 814 { 815 struct sock_filter *bpf; 816 struct sock_fprog *bpf_prog; 817 struct stat statbuf; 818 int res, ffd = -1; 819 820 if (filename == NULL) 821 return NULL; 822 823 if (stat(filename, &statbuf) < 0) { 824 printk(KERN_ERR "Error %d reading bpf file", -errno); 825 return false; 826 } 827 bpf_prog = uml_kmalloc(sizeof(struct sock_fprog), UM_GFP_KERNEL); 828 if (bpf_prog == NULL) { 829 printk(KERN_ERR "Failed to allocate bpf prog buffer"); 830 return NULL; 831 } 832 bpf_prog->len = statbuf.st_size / sizeof(struct sock_filter); 833 bpf_prog->filter = NULL; 834 ffd = os_open_file(filename, of_read(OPENFLAGS()), 0); 835 if (ffd < 0) { 836 printk(KERN_ERR "Error %d opening bpf file", -errno); 837 goto bpf_failed; 838 } 839 bpf = uml_kmalloc(statbuf.st_size, UM_GFP_KERNEL); 840 if (bpf == NULL) { 841 printk(KERN_ERR "Failed to allocate bpf buffer"); 842 goto bpf_failed; 843 } 844 bpf_prog->filter = bpf; 845 res = os_read_file(ffd, bpf, statbuf.st_size); 846 if (res < statbuf.st_size) { 847 printk(KERN_ERR "Failed to read bpf program %s, error %d", filename, res); 848 kfree(bpf); 849 goto bpf_failed; 850 } 851 os_close_file(ffd); 852 return bpf_prog; 853 bpf_failed: 854 if (ffd > 0) 855 os_close_file(ffd); 856 kfree(bpf_prog); 857 return NULL; 858 } 859
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.