xref: /qemu/net/l2tpv3.c (revision 0c65ef4f)
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)
450c65ef4fSChristian Svensson #define BUFFER_SIZE 16384
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 
l2tpv3_update_fd_handler(NetL2TPV3State * s)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 
l2tpv3_read_poll(NetL2TPV3State * s,bool enable)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 
l2tpv3_write_poll(NetL2TPV3State * s,bool enable)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 
l2tpv3_writable(void * opaque)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 
l2tpv3_send_completed(NetClientState * nc,ssize_t len)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 
l2tpv3_poll(NetClientState * nc,bool enable)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 
l2tpv3_form_header(NetL2TPV3State * s)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 
net_l2tpv3_receive_dgram_iov(NetClientState * nc,const struct iovec * iov,int iovcnt)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 
net_l2tpv3_receive_dgram(NetClientState * nc,const uint8_t * buf,size_t size)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 
l2tpv3_verify_header(NetL2TPV3State * s,uint8_t * buf)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 
net_l2tpv3_process_queue(NetL2TPV3State * s)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 
net_l2tpv3_send(void * opaque)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 
destroy_vector(struct mmsghdr * msgvec,int count,int iovcount)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 
build_l2tpv3_vector(NetL2TPV3State * s,int count)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 
net_l2tpv3_cleanup(NetClientState * nc)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 
net_init_l2tpv3(const Netdev * netdev,const char * name,NetClientState * peer,Error ** errp)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