13fb69aa1SAnton Ivanov /* 23fb69aa1SAnton Ivanov * QEMU System Emulator 33fb69aa1SAnton Ivanov * 43fb69aa1SAnton Ivanov * Copyright (c) 2003-2008 Fabrice Bellard 53fb69aa1SAnton Ivanov * Copyright (c) 2012-2014 Cisco Systems 63fb69aa1SAnton Ivanov * 73fb69aa1SAnton Ivanov * Permission is hereby granted, free of charge, to any person obtaining a copy 83fb69aa1SAnton Ivanov * of this software and associated documentation files (the "Software"), to deal 93fb69aa1SAnton Ivanov * in the Software without restriction, including without limitation the rights 103fb69aa1SAnton Ivanov * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 113fb69aa1SAnton Ivanov * copies of the Software, and to permit persons to whom the Software is 123fb69aa1SAnton Ivanov * furnished to do so, subject to the following conditions: 133fb69aa1SAnton Ivanov * 143fb69aa1SAnton Ivanov * The above copyright notice and this permission notice shall be included in 153fb69aa1SAnton Ivanov * all copies or substantial portions of the Software. 163fb69aa1SAnton Ivanov * 173fb69aa1SAnton Ivanov * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 183fb69aa1SAnton Ivanov * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 193fb69aa1SAnton Ivanov * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 203fb69aa1SAnton Ivanov * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 213fb69aa1SAnton Ivanov * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 223fb69aa1SAnton Ivanov * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 233fb69aa1SAnton Ivanov * THE SOFTWARE. 243fb69aa1SAnton Ivanov */ 253fb69aa1SAnton Ivanov 262744d920SPeter Maydell #include "qemu/osdep.h" 273fb69aa1SAnton Ivanov #include <linux/ip.h> 283fb69aa1SAnton Ivanov #include <netdb.h> 293fb69aa1SAnton Ivanov #include "net/net.h" 303fb69aa1SAnton Ivanov #include "clients.h" 31007e5f87SMarkus Armbruster #include "qapi/error.h" 323fb69aa1SAnton Ivanov #include "qemu/error-report.h" 333fb69aa1SAnton Ivanov #include "qemu/option.h" 343fb69aa1SAnton Ivanov #include "qemu/sockets.h" 353fb69aa1SAnton Ivanov #include "qemu/iov.h" 363fb69aa1SAnton Ivanov #include "qemu/main-loop.h" 375df022cfSPeter Maydell #include "qemu/memalign.h" 383fb69aa1SAnton Ivanov 393fb69aa1SAnton Ivanov /* The buffer size needs to be investigated for optimum numbers and 403fb69aa1SAnton Ivanov * optimum means of paging in on different systems. This size is 413fb69aa1SAnton Ivanov * chosen to be sufficient to accommodate one packet with some headers 423fb69aa1SAnton Ivanov */ 433fb69aa1SAnton Ivanov 443fb69aa1SAnton Ivanov #define BUFFER_ALIGN sysconf(_SC_PAGESIZE) 453fb69aa1SAnton Ivanov #define BUFFER_SIZE 2048 463fb69aa1SAnton Ivanov #define IOVSIZE 2 473fb69aa1SAnton Ivanov #define MAX_L2TPV3_MSGCNT 64 483fb69aa1SAnton Ivanov #define MAX_L2TPV3_IOVCNT (MAX_L2TPV3_MSGCNT * IOVSIZE) 493fb69aa1SAnton Ivanov 503fb69aa1SAnton Ivanov /* Header set to 0x30000 signifies a data packet */ 513fb69aa1SAnton Ivanov 523fb69aa1SAnton Ivanov #define L2TPV3_DATA_PACKET 0x30000 533fb69aa1SAnton Ivanov 543fb69aa1SAnton Ivanov /* IANA-assigned IP protocol ID for L2TPv3 */ 553fb69aa1SAnton Ivanov 563fb69aa1SAnton Ivanov #ifndef IPPROTO_L2TP 573fb69aa1SAnton Ivanov #define IPPROTO_L2TP 0x73 583fb69aa1SAnton Ivanov #endif 593fb69aa1SAnton Ivanov 603fb69aa1SAnton Ivanov typedef struct NetL2TPV3State { 613fb69aa1SAnton Ivanov NetClientState nc; 623fb69aa1SAnton Ivanov int fd; 633fb69aa1SAnton Ivanov 643fb69aa1SAnton Ivanov /* 653fb69aa1SAnton Ivanov * these are used for xmit - that happens packet a time 663fb69aa1SAnton Ivanov * and for first sign of life packet (easier to parse that once) 673fb69aa1SAnton Ivanov */ 683fb69aa1SAnton Ivanov 693fb69aa1SAnton Ivanov uint8_t *header_buf; 703fb69aa1SAnton Ivanov struct iovec *vec; 713fb69aa1SAnton Ivanov 723fb69aa1SAnton Ivanov /* 733fb69aa1SAnton Ivanov * these are used for receive - try to "eat" up to 32 packets at a time 743fb69aa1SAnton Ivanov */ 753fb69aa1SAnton Ivanov 763fb69aa1SAnton Ivanov struct mmsghdr *msgvec; 773fb69aa1SAnton Ivanov 783fb69aa1SAnton Ivanov /* 793fb69aa1SAnton Ivanov * peer address 803fb69aa1SAnton Ivanov */ 813fb69aa1SAnton Ivanov 823fb69aa1SAnton Ivanov struct sockaddr_storage *dgram_dst; 833fb69aa1SAnton Ivanov uint32_t dst_size; 843fb69aa1SAnton Ivanov 853fb69aa1SAnton Ivanov /* 863fb69aa1SAnton Ivanov * L2TPv3 parameters 873fb69aa1SAnton Ivanov */ 883fb69aa1SAnton Ivanov 893fb69aa1SAnton Ivanov uint64_t rx_cookie; 903fb69aa1SAnton Ivanov uint64_t tx_cookie; 913fb69aa1SAnton Ivanov uint32_t rx_session; 923fb69aa1SAnton Ivanov uint32_t tx_session; 933fb69aa1SAnton Ivanov uint32_t header_size; 943fb69aa1SAnton Ivanov uint32_t counter; 953fb69aa1SAnton Ivanov 963fb69aa1SAnton Ivanov /* 973fb69aa1SAnton Ivanov * DOS avoidance in error handling 983fb69aa1SAnton Ivanov */ 993fb69aa1SAnton Ivanov 1003fb69aa1SAnton Ivanov bool header_mismatch; 1013fb69aa1SAnton Ivanov 1023fb69aa1SAnton Ivanov /* 1033fb69aa1SAnton Ivanov * Ring buffer handling 1043fb69aa1SAnton Ivanov */ 1053fb69aa1SAnton Ivanov 1063fb69aa1SAnton Ivanov int queue_head; 1073fb69aa1SAnton Ivanov int queue_tail; 1083fb69aa1SAnton Ivanov int queue_depth; 1093fb69aa1SAnton Ivanov 1103fb69aa1SAnton Ivanov /* 1113fb69aa1SAnton Ivanov * Precomputed offsets 1123fb69aa1SAnton Ivanov */ 1133fb69aa1SAnton Ivanov 1143fb69aa1SAnton Ivanov uint32_t offset; 1153fb69aa1SAnton Ivanov uint32_t cookie_offset; 1163fb69aa1SAnton Ivanov uint32_t counter_offset; 1173fb69aa1SAnton Ivanov uint32_t session_offset; 1183fb69aa1SAnton Ivanov 1193fb69aa1SAnton Ivanov /* Poll Control */ 1203fb69aa1SAnton Ivanov 1213fb69aa1SAnton Ivanov bool read_poll; 1223fb69aa1SAnton Ivanov bool write_poll; 1233fb69aa1SAnton Ivanov 1243fb69aa1SAnton Ivanov /* Flags */ 1253fb69aa1SAnton Ivanov 1263fb69aa1SAnton Ivanov bool ipv6; 1273fb69aa1SAnton Ivanov bool udp; 1283fb69aa1SAnton Ivanov bool has_counter; 1293fb69aa1SAnton Ivanov bool pin_counter; 1303fb69aa1SAnton Ivanov bool cookie; 1313fb69aa1SAnton Ivanov bool cookie_is_64; 1323fb69aa1SAnton Ivanov 1333fb69aa1SAnton Ivanov } NetL2TPV3State; 1343fb69aa1SAnton Ivanov 1353fb69aa1SAnton Ivanov static void net_l2tpv3_send(void *opaque); 1363fb69aa1SAnton Ivanov static void l2tpv3_writable(void *opaque); 1373fb69aa1SAnton Ivanov 1383fb69aa1SAnton Ivanov static void l2tpv3_update_fd_handler(NetL2TPV3State *s) 1393fb69aa1SAnton Ivanov { 14082e1cc4bSFam Zheng qemu_set_fd_handler(s->fd, 1413fb69aa1SAnton Ivanov s->read_poll ? net_l2tpv3_send : NULL, 1423fb69aa1SAnton Ivanov s->write_poll ? l2tpv3_writable : NULL, 1433fb69aa1SAnton Ivanov s); 1443fb69aa1SAnton Ivanov } 1453fb69aa1SAnton Ivanov 1463fb69aa1SAnton Ivanov static void l2tpv3_read_poll(NetL2TPV3State *s, bool enable) 1473fb69aa1SAnton Ivanov { 1483fb69aa1SAnton Ivanov if (s->read_poll != enable) { 1493fb69aa1SAnton Ivanov s->read_poll = enable; 1503fb69aa1SAnton Ivanov l2tpv3_update_fd_handler(s); 1513fb69aa1SAnton Ivanov } 1523fb69aa1SAnton Ivanov } 1533fb69aa1SAnton Ivanov 1543fb69aa1SAnton Ivanov static void l2tpv3_write_poll(NetL2TPV3State *s, bool enable) 1553fb69aa1SAnton Ivanov { 1563fb69aa1SAnton Ivanov if (s->write_poll != enable) { 1573fb69aa1SAnton Ivanov s->write_poll = enable; 1583fb69aa1SAnton Ivanov l2tpv3_update_fd_handler(s); 1593fb69aa1SAnton Ivanov } 1603fb69aa1SAnton Ivanov } 1613fb69aa1SAnton Ivanov 1623fb69aa1SAnton Ivanov static void l2tpv3_writable(void *opaque) 1633fb69aa1SAnton Ivanov { 1643fb69aa1SAnton Ivanov NetL2TPV3State *s = opaque; 1653fb69aa1SAnton Ivanov l2tpv3_write_poll(s, false); 1663fb69aa1SAnton Ivanov qemu_flush_queued_packets(&s->nc); 1673fb69aa1SAnton Ivanov } 1683fb69aa1SAnton Ivanov 1693fb69aa1SAnton Ivanov static void l2tpv3_send_completed(NetClientState *nc, ssize_t len) 1703fb69aa1SAnton Ivanov { 1713fb69aa1SAnton Ivanov NetL2TPV3State *s = DO_UPCAST(NetL2TPV3State, nc, nc); 1723fb69aa1SAnton Ivanov l2tpv3_read_poll(s, true); 1733fb69aa1SAnton Ivanov } 1743fb69aa1SAnton Ivanov 1753fb69aa1SAnton Ivanov static void l2tpv3_poll(NetClientState *nc, bool enable) 1763fb69aa1SAnton Ivanov { 1773fb69aa1SAnton Ivanov NetL2TPV3State *s = DO_UPCAST(NetL2TPV3State, nc, nc); 1783fb69aa1SAnton Ivanov l2tpv3_write_poll(s, enable); 1793fb69aa1SAnton Ivanov l2tpv3_read_poll(s, enable); 1803fb69aa1SAnton Ivanov } 1813fb69aa1SAnton Ivanov 1823fb69aa1SAnton Ivanov static void l2tpv3_form_header(NetL2TPV3State *s) 1833fb69aa1SAnton Ivanov { 1843fb69aa1SAnton Ivanov uint32_t *counter; 1853fb69aa1SAnton Ivanov 1863fb69aa1SAnton Ivanov if (s->udp) { 1873fb69aa1SAnton Ivanov stl_be_p((uint32_t *) s->header_buf, L2TPV3_DATA_PACKET); 1883fb69aa1SAnton Ivanov } 1893fb69aa1SAnton Ivanov stl_be_p( 1903fb69aa1SAnton Ivanov (uint32_t *) (s->header_buf + s->session_offset), 1913fb69aa1SAnton Ivanov s->tx_session 1923fb69aa1SAnton Ivanov ); 1933fb69aa1SAnton Ivanov if (s->cookie) { 1943fb69aa1SAnton Ivanov if (s->cookie_is_64) { 1953fb69aa1SAnton Ivanov stq_be_p( 1963fb69aa1SAnton Ivanov (uint64_t *)(s->header_buf + s->cookie_offset), 1973fb69aa1SAnton Ivanov s->tx_cookie 1983fb69aa1SAnton Ivanov ); 1993fb69aa1SAnton Ivanov } else { 2003fb69aa1SAnton Ivanov stl_be_p( 2013fb69aa1SAnton Ivanov (uint32_t *) (s->header_buf + s->cookie_offset), 2023fb69aa1SAnton Ivanov s->tx_cookie 2033fb69aa1SAnton Ivanov ); 2043fb69aa1SAnton Ivanov } 2053fb69aa1SAnton Ivanov } 2063fb69aa1SAnton Ivanov if (s->has_counter) { 2073fb69aa1SAnton Ivanov counter = (uint32_t *)(s->header_buf + s->counter_offset); 2083fb69aa1SAnton Ivanov if (s->pin_counter) { 2093fb69aa1SAnton Ivanov *counter = 0; 2103fb69aa1SAnton Ivanov } else { 2113fb69aa1SAnton Ivanov stl_be_p(counter, ++s->counter); 2123fb69aa1SAnton Ivanov } 2133fb69aa1SAnton Ivanov } 2143fb69aa1SAnton Ivanov } 2153fb69aa1SAnton Ivanov 2163fb69aa1SAnton Ivanov static ssize_t net_l2tpv3_receive_dgram_iov(NetClientState *nc, 2173fb69aa1SAnton Ivanov const struct iovec *iov, 2183fb69aa1SAnton Ivanov int iovcnt) 2193fb69aa1SAnton Ivanov { 2203fb69aa1SAnton Ivanov NetL2TPV3State *s = DO_UPCAST(NetL2TPV3State, nc, nc); 2213fb69aa1SAnton Ivanov 2223fb69aa1SAnton Ivanov struct msghdr message; 2233fb69aa1SAnton Ivanov int ret; 2243fb69aa1SAnton Ivanov 2253fb69aa1SAnton Ivanov if (iovcnt > MAX_L2TPV3_IOVCNT - 1) { 2263fb69aa1SAnton Ivanov error_report( 2273fb69aa1SAnton Ivanov "iovec too long %d > %d, change l2tpv3.h", 2283fb69aa1SAnton Ivanov iovcnt, MAX_L2TPV3_IOVCNT 2293fb69aa1SAnton Ivanov ); 2303fb69aa1SAnton Ivanov return -1; 2313fb69aa1SAnton Ivanov } 2323fb69aa1SAnton Ivanov l2tpv3_form_header(s); 2333fb69aa1SAnton Ivanov memcpy(s->vec + 1, iov, iovcnt * sizeof(struct iovec)); 2343fb69aa1SAnton Ivanov s->vec->iov_base = s->header_buf; 2353fb69aa1SAnton Ivanov s->vec->iov_len = s->offset; 2363fb69aa1SAnton Ivanov message.msg_name = s->dgram_dst; 2373fb69aa1SAnton Ivanov message.msg_namelen = s->dst_size; 2383fb69aa1SAnton Ivanov message.msg_iov = s->vec; 2393fb69aa1SAnton Ivanov message.msg_iovlen = iovcnt + 1; 2403fb69aa1SAnton Ivanov message.msg_control = NULL; 2413fb69aa1SAnton Ivanov message.msg_controllen = 0; 2423fb69aa1SAnton Ivanov message.msg_flags = 0; 24337b0b24eSNikita Ivanov ret = RETRY_ON_EINTR(sendmsg(s->fd, &message, 0)); 2443fb69aa1SAnton Ivanov if (ret > 0) { 2453fb69aa1SAnton Ivanov ret -= s->offset; 2463fb69aa1SAnton Ivanov } else if (ret == 0) { 2473fb69aa1SAnton Ivanov /* belt and braces - should not occur on DGRAM 2483fb69aa1SAnton Ivanov * we should get an error and never a 0 send 2493fb69aa1SAnton Ivanov */ 2503fb69aa1SAnton Ivanov ret = iov_size(iov, iovcnt); 2513fb69aa1SAnton Ivanov } else { 2523fb69aa1SAnton Ivanov /* signal upper layer that socket buffer is full */ 2533fb69aa1SAnton Ivanov ret = -errno; 2543fb69aa1SAnton Ivanov if (ret == -EAGAIN || ret == -ENOBUFS) { 2553fb69aa1SAnton Ivanov l2tpv3_write_poll(s, true); 2563fb69aa1SAnton Ivanov ret = 0; 2573fb69aa1SAnton Ivanov } 2583fb69aa1SAnton Ivanov } 2593fb69aa1SAnton Ivanov return ret; 2603fb69aa1SAnton Ivanov } 2613fb69aa1SAnton Ivanov 2623fb69aa1SAnton Ivanov static ssize_t net_l2tpv3_receive_dgram(NetClientState *nc, 2633fb69aa1SAnton Ivanov const uint8_t *buf, 2643fb69aa1SAnton Ivanov size_t size) 2653fb69aa1SAnton Ivanov { 2663fb69aa1SAnton Ivanov NetL2TPV3State *s = DO_UPCAST(NetL2TPV3State, nc, nc); 2673fb69aa1SAnton Ivanov 2683fb69aa1SAnton Ivanov struct iovec *vec; 2693fb69aa1SAnton Ivanov struct msghdr message; 2703fb69aa1SAnton Ivanov ssize_t ret = 0; 2713fb69aa1SAnton Ivanov 2723fb69aa1SAnton Ivanov l2tpv3_form_header(s); 2733fb69aa1SAnton Ivanov vec = s->vec; 2743fb69aa1SAnton Ivanov vec->iov_base = s->header_buf; 2753fb69aa1SAnton Ivanov vec->iov_len = s->offset; 2763fb69aa1SAnton Ivanov vec++; 2773fb69aa1SAnton Ivanov vec->iov_base = (void *) buf; 2783fb69aa1SAnton Ivanov vec->iov_len = size; 2793fb69aa1SAnton Ivanov message.msg_name = s->dgram_dst; 2803fb69aa1SAnton Ivanov message.msg_namelen = s->dst_size; 2813fb69aa1SAnton Ivanov message.msg_iov = s->vec; 2823fb69aa1SAnton Ivanov message.msg_iovlen = 2; 2833fb69aa1SAnton Ivanov message.msg_control = NULL; 2843fb69aa1SAnton Ivanov message.msg_controllen = 0; 2853fb69aa1SAnton Ivanov message.msg_flags = 0; 28637b0b24eSNikita Ivanov ret = RETRY_ON_EINTR(sendmsg(s->fd, &message, 0)); 2873fb69aa1SAnton Ivanov if (ret > 0) { 2883fb69aa1SAnton Ivanov ret -= s->offset; 2893fb69aa1SAnton Ivanov } else if (ret == 0) { 2903fb69aa1SAnton Ivanov /* belt and braces - should not occur on DGRAM 2913fb69aa1SAnton Ivanov * we should get an error and never a 0 send 2923fb69aa1SAnton Ivanov */ 2933fb69aa1SAnton Ivanov ret = size; 2943fb69aa1SAnton Ivanov } else { 2953fb69aa1SAnton Ivanov ret = -errno; 2963fb69aa1SAnton Ivanov if (ret == -EAGAIN || ret == -ENOBUFS) { 2973fb69aa1SAnton Ivanov /* signal upper layer that socket buffer is full */ 2983fb69aa1SAnton Ivanov l2tpv3_write_poll(s, true); 2993fb69aa1SAnton Ivanov ret = 0; 3003fb69aa1SAnton Ivanov } 3013fb69aa1SAnton Ivanov } 3023fb69aa1SAnton Ivanov return ret; 3033fb69aa1SAnton Ivanov } 3043fb69aa1SAnton Ivanov 3053fb69aa1SAnton Ivanov static int l2tpv3_verify_header(NetL2TPV3State *s, uint8_t *buf) 3063fb69aa1SAnton Ivanov { 3073fb69aa1SAnton Ivanov 3083fb69aa1SAnton Ivanov uint32_t *session; 3093fb69aa1SAnton Ivanov uint64_t cookie; 3103fb69aa1SAnton Ivanov 3113fb69aa1SAnton Ivanov if ((!s->udp) && (!s->ipv6)) { 3123fb69aa1SAnton Ivanov buf += sizeof(struct iphdr) /* fix for ipv4 raw */; 3133fb69aa1SAnton Ivanov } 3143fb69aa1SAnton Ivanov 3153fb69aa1SAnton Ivanov /* we do not do a strict check for "data" packets as per 3163fb69aa1SAnton Ivanov * the RFC spec because the pure IP spec does not have 3173fb69aa1SAnton Ivanov * that anyway. 3183fb69aa1SAnton Ivanov */ 3193fb69aa1SAnton Ivanov 3203fb69aa1SAnton Ivanov if (s->cookie) { 3213fb69aa1SAnton Ivanov if (s->cookie_is_64) { 3223fb69aa1SAnton Ivanov cookie = ldq_be_p(buf + s->cookie_offset); 3233fb69aa1SAnton Ivanov } else { 3243be9b352SAlexis Dambricourt cookie = ldl_be_p(buf + s->cookie_offset) & 0xffffffffULL; 3253fb69aa1SAnton Ivanov } 3263fb69aa1SAnton Ivanov if (cookie != s->rx_cookie) { 3273fb69aa1SAnton Ivanov if (!s->header_mismatch) { 3283fb69aa1SAnton Ivanov error_report("unknown cookie id"); 3293fb69aa1SAnton Ivanov } 3303fb69aa1SAnton Ivanov return -1; 3313fb69aa1SAnton Ivanov } 3323fb69aa1SAnton Ivanov } 3333fb69aa1SAnton Ivanov session = (uint32_t *) (buf + s->session_offset); 3343fb69aa1SAnton Ivanov if (ldl_be_p(session) != s->rx_session) { 3353fb69aa1SAnton Ivanov if (!s->header_mismatch) { 3363fb69aa1SAnton Ivanov error_report("session mismatch"); 3373fb69aa1SAnton Ivanov } 3383fb69aa1SAnton Ivanov return -1; 3393fb69aa1SAnton Ivanov } 3403fb69aa1SAnton Ivanov return 0; 3413fb69aa1SAnton Ivanov } 3423fb69aa1SAnton Ivanov 3433fb69aa1SAnton Ivanov static void net_l2tpv3_process_queue(NetL2TPV3State *s) 3443fb69aa1SAnton Ivanov { 3453fb69aa1SAnton Ivanov int size = 0; 3463fb69aa1SAnton Ivanov struct iovec *vec; 3473fb69aa1SAnton Ivanov bool bad_read; 3483fb69aa1SAnton Ivanov int data_size; 3493fb69aa1SAnton Ivanov struct mmsghdr *msgvec; 3503fb69aa1SAnton Ivanov 3513fb69aa1SAnton Ivanov /* go into ring mode only if there is a "pending" tail */ 3523fb69aa1SAnton Ivanov if (s->queue_depth > 0) { 3533fb69aa1SAnton Ivanov do { 3543fb69aa1SAnton Ivanov msgvec = s->msgvec + s->queue_tail; 3553fb69aa1SAnton Ivanov if (msgvec->msg_len > 0) { 3563fb69aa1SAnton Ivanov data_size = msgvec->msg_len - s->header_size; 3573fb69aa1SAnton Ivanov vec = msgvec->msg_hdr.msg_iov; 3583fb69aa1SAnton Ivanov if ((data_size > 0) && 3593fb69aa1SAnton Ivanov (l2tpv3_verify_header(s, vec->iov_base) == 0)) { 3603fb69aa1SAnton Ivanov vec++; 3613fb69aa1SAnton Ivanov /* Use the legacy delivery for now, we will 3623fb69aa1SAnton Ivanov * switch to using our own ring as a queueing mechanism 3633fb69aa1SAnton Ivanov * at a later date 3643fb69aa1SAnton Ivanov */ 3653fb69aa1SAnton Ivanov size = qemu_send_packet_async( 3663fb69aa1SAnton Ivanov &s->nc, 3673fb69aa1SAnton Ivanov vec->iov_base, 3683fb69aa1SAnton Ivanov data_size, 3693fb69aa1SAnton Ivanov l2tpv3_send_completed 3703fb69aa1SAnton Ivanov ); 3713fb69aa1SAnton Ivanov if (size == 0) { 3723fb69aa1SAnton Ivanov l2tpv3_read_poll(s, false); 3733fb69aa1SAnton Ivanov } 3743fb69aa1SAnton Ivanov bad_read = false; 3753fb69aa1SAnton Ivanov } else { 3763fb69aa1SAnton Ivanov bad_read = true; 3773fb69aa1SAnton Ivanov if (!s->header_mismatch) { 3783fb69aa1SAnton Ivanov /* report error only once */ 3793fb69aa1SAnton Ivanov error_report("l2tpv3 header verification failed"); 3803fb69aa1SAnton Ivanov s->header_mismatch = true; 3813fb69aa1SAnton Ivanov } 3823fb69aa1SAnton Ivanov } 3833fb69aa1SAnton Ivanov } else { 3843fb69aa1SAnton Ivanov bad_read = true; 3853fb69aa1SAnton Ivanov } 3863fb69aa1SAnton Ivanov s->queue_tail = (s->queue_tail + 1) % MAX_L2TPV3_MSGCNT; 3873fb69aa1SAnton Ivanov s->queue_depth--; 3883fb69aa1SAnton Ivanov } while ( 3893fb69aa1SAnton Ivanov (s->queue_depth > 0) && 3903fb69aa1SAnton Ivanov qemu_can_send_packet(&s->nc) && 3913fb69aa1SAnton Ivanov ((size > 0) || bad_read) 3923fb69aa1SAnton Ivanov ); 3933fb69aa1SAnton Ivanov } 3943fb69aa1SAnton Ivanov } 3953fb69aa1SAnton Ivanov 3963fb69aa1SAnton Ivanov static void net_l2tpv3_send(void *opaque) 3973fb69aa1SAnton Ivanov { 3983fb69aa1SAnton Ivanov NetL2TPV3State *s = opaque; 3993fb69aa1SAnton Ivanov int target_count, count; 4003fb69aa1SAnton Ivanov struct mmsghdr *msgvec; 4013fb69aa1SAnton Ivanov 4023fb69aa1SAnton Ivanov /* go into ring mode only if there is a "pending" tail */ 4033fb69aa1SAnton Ivanov 4043fb69aa1SAnton Ivanov if (s->queue_depth) { 4053fb69aa1SAnton Ivanov 4063fb69aa1SAnton Ivanov /* The ring buffer we use has variable intake 4073fb69aa1SAnton Ivanov * count of how much we can read varies - adjust accordingly 4083fb69aa1SAnton Ivanov */ 4093fb69aa1SAnton Ivanov 4103fb69aa1SAnton Ivanov target_count = MAX_L2TPV3_MSGCNT - s->queue_depth; 4113fb69aa1SAnton Ivanov 4123fb69aa1SAnton Ivanov /* Ensure we do not overrun the ring when we have 4133fb69aa1SAnton Ivanov * a lot of enqueued packets 4143fb69aa1SAnton Ivanov */ 4153fb69aa1SAnton Ivanov 4163fb69aa1SAnton Ivanov if (s->queue_head + target_count > MAX_L2TPV3_MSGCNT) { 4173fb69aa1SAnton Ivanov target_count = MAX_L2TPV3_MSGCNT - s->queue_head; 4183fb69aa1SAnton Ivanov } 4193fb69aa1SAnton Ivanov } else { 4203fb69aa1SAnton Ivanov 4213fb69aa1SAnton Ivanov /* we do not have any pending packets - we can use 4223fb69aa1SAnton Ivanov * the whole message vector linearly instead of using 4233fb69aa1SAnton Ivanov * it as a ring 4243fb69aa1SAnton Ivanov */ 4253fb69aa1SAnton Ivanov 4263fb69aa1SAnton Ivanov s->queue_head = 0; 4273fb69aa1SAnton Ivanov s->queue_tail = 0; 4283fb69aa1SAnton Ivanov target_count = MAX_L2TPV3_MSGCNT; 4293fb69aa1SAnton Ivanov } 4303fb69aa1SAnton Ivanov 4313fb69aa1SAnton Ivanov msgvec = s->msgvec + s->queue_head; 4323fb69aa1SAnton Ivanov if (target_count > 0) { 43337b0b24eSNikita Ivanov count = RETRY_ON_EINTR( 43437b0b24eSNikita Ivanov recvmmsg(s->fd, msgvec, target_count, MSG_DONTWAIT, NULL) 43537b0b24eSNikita Ivanov ); 4363fb69aa1SAnton Ivanov if (count < 0) { 4373fb69aa1SAnton Ivanov /* Recv error - we still need to flush packets here, 4383fb69aa1SAnton Ivanov * (re)set queue head to current position 4393fb69aa1SAnton Ivanov */ 4403fb69aa1SAnton Ivanov count = 0; 4413fb69aa1SAnton Ivanov } 4423fb69aa1SAnton Ivanov s->queue_head = (s->queue_head + count) % MAX_L2TPV3_MSGCNT; 4433fb69aa1SAnton Ivanov s->queue_depth += count; 4443fb69aa1SAnton Ivanov } 4453fb69aa1SAnton Ivanov net_l2tpv3_process_queue(s); 4463fb69aa1SAnton Ivanov } 4473fb69aa1SAnton Ivanov 4483fb69aa1SAnton Ivanov static void destroy_vector(struct mmsghdr *msgvec, int count, int iovcount) 4493fb69aa1SAnton Ivanov { 4503fb69aa1SAnton Ivanov int i, j; 4513fb69aa1SAnton Ivanov struct iovec *iov; 4523fb69aa1SAnton Ivanov struct mmsghdr *cleanup = msgvec; 4533fb69aa1SAnton Ivanov if (cleanup) { 4543fb69aa1SAnton Ivanov for (i = 0; i < count; i++) { 4553fb69aa1SAnton Ivanov if (cleanup->msg_hdr.msg_iov) { 4563fb69aa1SAnton Ivanov iov = cleanup->msg_hdr.msg_iov; 4573fb69aa1SAnton Ivanov for (j = 0; j < iovcount; j++) { 4583fb69aa1SAnton Ivanov g_free(iov->iov_base); 4593fb69aa1SAnton Ivanov iov++; 4603fb69aa1SAnton Ivanov } 4613fb69aa1SAnton Ivanov g_free(cleanup->msg_hdr.msg_iov); 4623fb69aa1SAnton Ivanov } 4633fb69aa1SAnton Ivanov cleanup++; 4643fb69aa1SAnton Ivanov } 4653fb69aa1SAnton Ivanov g_free(msgvec); 4663fb69aa1SAnton Ivanov } 4673fb69aa1SAnton Ivanov } 4683fb69aa1SAnton Ivanov 4693fb69aa1SAnton Ivanov static struct mmsghdr *build_l2tpv3_vector(NetL2TPV3State *s, int count) 4703fb69aa1SAnton Ivanov { 4713fb69aa1SAnton Ivanov int i; 4723fb69aa1SAnton Ivanov struct iovec *iov; 4733fb69aa1SAnton Ivanov struct mmsghdr *msgvec, *result; 4743fb69aa1SAnton Ivanov 47558889fe5SMarkus Armbruster msgvec = g_new(struct mmsghdr, count); 4763fb69aa1SAnton Ivanov result = msgvec; 4773fb69aa1SAnton Ivanov for (i = 0; i < count ; i++) { 4783fb69aa1SAnton Ivanov msgvec->msg_hdr.msg_name = NULL; 4793fb69aa1SAnton Ivanov msgvec->msg_hdr.msg_namelen = 0; 48058889fe5SMarkus Armbruster iov = g_new(struct iovec, IOVSIZE); 4813fb69aa1SAnton Ivanov msgvec->msg_hdr.msg_iov = iov; 4823fb69aa1SAnton Ivanov iov->iov_base = g_malloc(s->header_size); 4833fb69aa1SAnton Ivanov iov->iov_len = s->header_size; 4843fb69aa1SAnton Ivanov iov++ ; 4853fb69aa1SAnton Ivanov iov->iov_base = qemu_memalign(BUFFER_ALIGN, BUFFER_SIZE); 4863fb69aa1SAnton Ivanov iov->iov_len = BUFFER_SIZE; 4873fb69aa1SAnton Ivanov msgvec->msg_hdr.msg_iovlen = 2; 4883fb69aa1SAnton Ivanov msgvec->msg_hdr.msg_control = NULL; 4893fb69aa1SAnton Ivanov msgvec->msg_hdr.msg_controllen = 0; 4903fb69aa1SAnton Ivanov msgvec->msg_hdr.msg_flags = 0; 4913fb69aa1SAnton Ivanov msgvec++; 4923fb69aa1SAnton Ivanov } 4933fb69aa1SAnton Ivanov return result; 4943fb69aa1SAnton Ivanov } 4953fb69aa1SAnton Ivanov 4963fb69aa1SAnton Ivanov static void net_l2tpv3_cleanup(NetClientState *nc) 4973fb69aa1SAnton Ivanov { 4983fb69aa1SAnton Ivanov NetL2TPV3State *s = DO_UPCAST(NetL2TPV3State, nc, nc); 4993fb69aa1SAnton Ivanov qemu_purge_queued_packets(nc); 5003fb69aa1SAnton Ivanov l2tpv3_read_poll(s, false); 5013fb69aa1SAnton Ivanov l2tpv3_write_poll(s, false); 502d4754a95SGonglei if (s->fd >= 0) { 5033fb69aa1SAnton Ivanov close(s->fd); 5043fb69aa1SAnton Ivanov } 5053fb69aa1SAnton Ivanov destroy_vector(s->msgvec, MAX_L2TPV3_MSGCNT, IOVSIZE); 5063fb69aa1SAnton Ivanov g_free(s->vec); 5073fb69aa1SAnton Ivanov g_free(s->header_buf); 5083fb69aa1SAnton Ivanov g_free(s->dgram_dst); 5093fb69aa1SAnton Ivanov } 5103fb69aa1SAnton Ivanov 5113fb69aa1SAnton Ivanov static NetClientInfo net_l2tpv3_info = { 512f394b2e2SEric Blake .type = NET_CLIENT_DRIVER_L2TPV3, 5133fb69aa1SAnton Ivanov .size = sizeof(NetL2TPV3State), 5143fb69aa1SAnton Ivanov .receive = net_l2tpv3_receive_dgram, 5153fb69aa1SAnton Ivanov .receive_iov = net_l2tpv3_receive_dgram_iov, 5163fb69aa1SAnton Ivanov .poll = l2tpv3_poll, 5173fb69aa1SAnton Ivanov .cleanup = net_l2tpv3_cleanup, 5183fb69aa1SAnton Ivanov }; 5193fb69aa1SAnton Ivanov 520cebea510SKővágó, Zoltán int net_init_l2tpv3(const Netdev *netdev, 5213fb69aa1SAnton Ivanov const char *name, 522a30ecde6SMarkus Armbruster NetClientState *peer, Error **errp) 5233fb69aa1SAnton Ivanov { 5243fb69aa1SAnton Ivanov const NetdevL2TPv3Options *l2tpv3; 5253fb69aa1SAnton Ivanov NetL2TPV3State *s; 5263fb69aa1SAnton Ivanov NetClientState *nc; 5273fb69aa1SAnton Ivanov int fd = -1, gairet; 5283fb69aa1SAnton Ivanov struct addrinfo hints; 5293fb69aa1SAnton Ivanov struct addrinfo *result = NULL; 5303fb69aa1SAnton Ivanov char *srcport, *dstport; 5313fb69aa1SAnton Ivanov 5323fb69aa1SAnton Ivanov nc = qemu_new_net_client(&net_l2tpv3_info, peer, "l2tpv3", name); 5333fb69aa1SAnton Ivanov 5343fb69aa1SAnton Ivanov s = DO_UPCAST(NetL2TPV3State, nc, nc); 5353fb69aa1SAnton Ivanov 5363fb69aa1SAnton Ivanov s->queue_head = 0; 5373fb69aa1SAnton Ivanov s->queue_tail = 0; 5383fb69aa1SAnton Ivanov s->header_mismatch = false; 5393fb69aa1SAnton Ivanov 540f394b2e2SEric Blake assert(netdev->type == NET_CLIENT_DRIVER_L2TPV3); 541f394b2e2SEric Blake l2tpv3 = &netdev->u.l2tpv3; 5423fb69aa1SAnton Ivanov 5433fb69aa1SAnton Ivanov if (l2tpv3->has_ipv6 && l2tpv3->ipv6) { 5443fb69aa1SAnton Ivanov s->ipv6 = l2tpv3->ipv6; 5453fb69aa1SAnton Ivanov } else { 5463fb69aa1SAnton Ivanov s->ipv6 = false; 5473fb69aa1SAnton Ivanov } 5483fb69aa1SAnton Ivanov 5493fb69aa1SAnton Ivanov if ((l2tpv3->has_offset) && (l2tpv3->offset > 256)) { 550007e5f87SMarkus Armbruster error_setg(errp, "offset must be less than 256 bytes"); 5513fb69aa1SAnton Ivanov goto outerr; 5523fb69aa1SAnton Ivanov } 5533fb69aa1SAnton Ivanov 5543fb69aa1SAnton Ivanov if (l2tpv3->has_rxcookie || l2tpv3->has_txcookie) { 5553fb69aa1SAnton Ivanov if (l2tpv3->has_rxcookie && l2tpv3->has_txcookie) { 5563fb69aa1SAnton Ivanov s->cookie = true; 5573fb69aa1SAnton Ivanov } else { 558007e5f87SMarkus Armbruster error_setg(errp, 559007e5f87SMarkus Armbruster "require both 'rxcookie' and 'txcookie' or neither"); 5603fb69aa1SAnton Ivanov goto outerr; 5613fb69aa1SAnton Ivanov } 5623fb69aa1SAnton Ivanov } else { 5633fb69aa1SAnton Ivanov s->cookie = false; 5643fb69aa1SAnton Ivanov } 5653fb69aa1SAnton Ivanov 5663fb69aa1SAnton Ivanov if (l2tpv3->has_cookie64 || l2tpv3->cookie64) { 5673fb69aa1SAnton Ivanov s->cookie_is_64 = true; 5683fb69aa1SAnton Ivanov } else { 5693fb69aa1SAnton Ivanov s->cookie_is_64 = false; 5703fb69aa1SAnton Ivanov } 5713fb69aa1SAnton Ivanov 5723fb69aa1SAnton Ivanov if (l2tpv3->has_udp && l2tpv3->udp) { 5733fb69aa1SAnton Ivanov s->udp = true; 5747480874aSMarkus Armbruster if (!(l2tpv3->srcport && l2tpv3->dstport)) { 575007e5f87SMarkus Armbruster error_setg(errp, "need both src and dst port for udp"); 5763fb69aa1SAnton Ivanov goto outerr; 5773fb69aa1SAnton Ivanov } else { 5783fb69aa1SAnton Ivanov srcport = l2tpv3->srcport; 5793fb69aa1SAnton Ivanov dstport = l2tpv3->dstport; 5803fb69aa1SAnton Ivanov } 5813fb69aa1SAnton Ivanov } else { 5823fb69aa1SAnton Ivanov s->udp = false; 5833fb69aa1SAnton Ivanov srcport = NULL; 5843fb69aa1SAnton Ivanov dstport = NULL; 5853fb69aa1SAnton Ivanov } 5863fb69aa1SAnton Ivanov 5873fb69aa1SAnton Ivanov 5883fb69aa1SAnton Ivanov s->offset = 4; 5893fb69aa1SAnton Ivanov s->session_offset = 0; 5903fb69aa1SAnton Ivanov s->cookie_offset = 4; 5913fb69aa1SAnton Ivanov s->counter_offset = 4; 5923fb69aa1SAnton Ivanov 5933fb69aa1SAnton Ivanov s->tx_session = l2tpv3->txsession; 5943fb69aa1SAnton Ivanov if (l2tpv3->has_rxsession) { 5953fb69aa1SAnton Ivanov s->rx_session = l2tpv3->rxsession; 5963fb69aa1SAnton Ivanov } else { 5973fb69aa1SAnton Ivanov s->rx_session = s->tx_session; 5983fb69aa1SAnton Ivanov } 5993fb69aa1SAnton Ivanov 6003fb69aa1SAnton Ivanov if (s->cookie) { 6013fb69aa1SAnton Ivanov s->rx_cookie = l2tpv3->rxcookie; 6023fb69aa1SAnton Ivanov s->tx_cookie = l2tpv3->txcookie; 6033fb69aa1SAnton Ivanov if (s->cookie_is_64 == true) { 6043fb69aa1SAnton Ivanov /* 64 bit cookie */ 6053fb69aa1SAnton Ivanov s->offset += 8; 6063fb69aa1SAnton Ivanov s->counter_offset += 8; 6073fb69aa1SAnton Ivanov } else { 6083fb69aa1SAnton Ivanov /* 32 bit cookie */ 6093fb69aa1SAnton Ivanov s->offset += 4; 6103fb69aa1SAnton Ivanov s->counter_offset += 4; 6113fb69aa1SAnton Ivanov } 6123fb69aa1SAnton Ivanov } 6133fb69aa1SAnton Ivanov 6143fb69aa1SAnton Ivanov memset(&hints, 0, sizeof(hints)); 6153fb69aa1SAnton Ivanov 6163fb69aa1SAnton Ivanov if (s->ipv6) { 6173fb69aa1SAnton Ivanov hints.ai_family = AF_INET6; 6183fb69aa1SAnton Ivanov } else { 6193fb69aa1SAnton Ivanov hints.ai_family = AF_INET; 6203fb69aa1SAnton Ivanov } 6213fb69aa1SAnton Ivanov if (s->udp) { 6223fb69aa1SAnton Ivanov hints.ai_socktype = SOCK_DGRAM; 6233fb69aa1SAnton Ivanov hints.ai_protocol = 0; 6243fb69aa1SAnton Ivanov s->offset += 4; 6253fb69aa1SAnton Ivanov s->counter_offset += 4; 6263fb69aa1SAnton Ivanov s->session_offset += 4; 6273fb69aa1SAnton Ivanov s->cookie_offset += 4; 6283fb69aa1SAnton Ivanov } else { 6293fb69aa1SAnton Ivanov hints.ai_socktype = SOCK_RAW; 6303fb69aa1SAnton Ivanov hints.ai_protocol = IPPROTO_L2TP; 6313fb69aa1SAnton Ivanov } 6323fb69aa1SAnton Ivanov 6333fb69aa1SAnton Ivanov gairet = getaddrinfo(l2tpv3->src, srcport, &hints, &result); 6343fb69aa1SAnton Ivanov 6353fb69aa1SAnton Ivanov if ((gairet != 0) || (result == NULL)) { 636007e5f87SMarkus Armbruster error_setg(errp, "could not resolve src, errno = %s", 637007e5f87SMarkus Armbruster gai_strerror(gairet)); 6383fb69aa1SAnton Ivanov goto outerr; 6393fb69aa1SAnton Ivanov } 6403fb69aa1SAnton Ivanov fd = socket(result->ai_family, result->ai_socktype, result->ai_protocol); 6413fb69aa1SAnton Ivanov if (fd == -1) { 6423fb69aa1SAnton Ivanov fd = -errno; 643007e5f87SMarkus Armbruster error_setg(errp, "socket creation failed, errno = %d", 644007e5f87SMarkus Armbruster -fd); 6453fb69aa1SAnton Ivanov goto outerr; 6463fb69aa1SAnton Ivanov } 6473fb69aa1SAnton Ivanov if (bind(fd, (struct sockaddr *) result->ai_addr, result->ai_addrlen)) { 648007e5f87SMarkus Armbruster error_setg(errp, "could not bind socket err=%i", errno); 6493fb69aa1SAnton Ivanov goto outerr; 6503fb69aa1SAnton Ivanov } 651d949fe64SAlexChen 6523fb69aa1SAnton Ivanov freeaddrinfo(result); 6533fb69aa1SAnton Ivanov 6543fb69aa1SAnton Ivanov memset(&hints, 0, sizeof(hints)); 6553fb69aa1SAnton Ivanov 6563fb69aa1SAnton Ivanov if (s->ipv6) { 6573fb69aa1SAnton Ivanov hints.ai_family = AF_INET6; 6583fb69aa1SAnton Ivanov } else { 6593fb69aa1SAnton Ivanov hints.ai_family = AF_INET; 6603fb69aa1SAnton Ivanov } 6613fb69aa1SAnton Ivanov if (s->udp) { 6623fb69aa1SAnton Ivanov hints.ai_socktype = SOCK_DGRAM; 6633fb69aa1SAnton Ivanov hints.ai_protocol = 0; 6643fb69aa1SAnton Ivanov } else { 6653fb69aa1SAnton Ivanov hints.ai_socktype = SOCK_RAW; 6663fb69aa1SAnton Ivanov hints.ai_protocol = IPPROTO_L2TP; 6673fb69aa1SAnton Ivanov } 6683fb69aa1SAnton Ivanov 6693fb69aa1SAnton Ivanov result = NULL; 6703fb69aa1SAnton Ivanov gairet = getaddrinfo(l2tpv3->dst, dstport, &hints, &result); 6713fb69aa1SAnton Ivanov if ((gairet != 0) || (result == NULL)) { 672007e5f87SMarkus Armbruster error_setg(errp, "could not resolve dst, error = %s", 673007e5f87SMarkus Armbruster gai_strerror(gairet)); 6743fb69aa1SAnton Ivanov goto outerr; 6753fb69aa1SAnton Ivanov } 6763fb69aa1SAnton Ivanov 67771e28e3cSMarkus Armbruster s->dgram_dst = g_new0(struct sockaddr_storage, 1); 6783fb69aa1SAnton Ivanov memcpy(s->dgram_dst, result->ai_addr, result->ai_addrlen); 6793fb69aa1SAnton Ivanov s->dst_size = result->ai_addrlen; 6803fb69aa1SAnton Ivanov 6813fb69aa1SAnton Ivanov freeaddrinfo(result); 6823fb69aa1SAnton Ivanov 6833fb69aa1SAnton Ivanov if (l2tpv3->has_counter && l2tpv3->counter) { 6843fb69aa1SAnton Ivanov s->has_counter = true; 6853fb69aa1SAnton Ivanov s->offset += 4; 6863fb69aa1SAnton Ivanov } else { 6873fb69aa1SAnton Ivanov s->has_counter = false; 6883fb69aa1SAnton Ivanov } 6893fb69aa1SAnton Ivanov 6903fb69aa1SAnton Ivanov if (l2tpv3->has_pincounter && l2tpv3->pincounter) { 6913fb69aa1SAnton Ivanov s->has_counter = true; /* pin counter implies that there is counter */ 6923fb69aa1SAnton Ivanov s->pin_counter = true; 6933fb69aa1SAnton Ivanov } else { 6943fb69aa1SAnton Ivanov s->pin_counter = false; 6953fb69aa1SAnton Ivanov } 6963fb69aa1SAnton Ivanov 6973fb69aa1SAnton Ivanov if (l2tpv3->has_offset) { 6983fb69aa1SAnton Ivanov /* extra offset */ 6993fb69aa1SAnton Ivanov s->offset += l2tpv3->offset; 7003fb69aa1SAnton Ivanov } 7013fb69aa1SAnton Ivanov 7023fb69aa1SAnton Ivanov if ((s->ipv6) || (s->udp)) { 7033fb69aa1SAnton Ivanov s->header_size = s->offset; 7043fb69aa1SAnton Ivanov } else { 7053fb69aa1SAnton Ivanov s->header_size = s->offset + sizeof(struct iphdr); 7063fb69aa1SAnton Ivanov } 7073fb69aa1SAnton Ivanov 7083fb69aa1SAnton Ivanov s->msgvec = build_l2tpv3_vector(s, MAX_L2TPV3_MSGCNT); 70958889fe5SMarkus Armbruster s->vec = g_new(struct iovec, MAX_L2TPV3_IOVCNT); 7103fb69aa1SAnton Ivanov s->header_buf = g_malloc(s->header_size); 7113fb69aa1SAnton Ivanov 712ff5927baSMarc-André Lureau qemu_socket_set_nonblock(fd); 7133fb69aa1SAnton Ivanov 7143fb69aa1SAnton Ivanov s->fd = fd; 7153fb69aa1SAnton Ivanov s->counter = 0; 7163fb69aa1SAnton Ivanov 7173fb69aa1SAnton Ivanov l2tpv3_read_poll(s, true); 7183fb69aa1SAnton Ivanov 71953b85d95SLaurent Vivier qemu_set_info_str(&s->nc, "l2tpv3: connected"); 7203fb69aa1SAnton Ivanov return 0; 7213fb69aa1SAnton Ivanov outerr: 7223fb69aa1SAnton Ivanov qemu_del_net_client(nc); 723d4754a95SGonglei if (fd >= 0) { 7243fb69aa1SAnton Ivanov close(fd); 7253fb69aa1SAnton Ivanov } 7263fb69aa1SAnton Ivanov if (result) { 7273fb69aa1SAnton Ivanov freeaddrinfo(result); 7283fb69aa1SAnton Ivanov } 7293fb69aa1SAnton Ivanov return -1; 7303fb69aa1SAnton Ivanov } 7313fb69aa1SAnton Ivanov 732