18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2017 - Cambridge Greys Limited 48c2ecf20Sopenharmony_ci * Copyright (C) 2011 - 2014 Cisco Systems Inc 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 88c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 98c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 108c2ecf20Sopenharmony_ci#include <linux/slab.h> 118c2ecf20Sopenharmony_ci#include <asm/byteorder.h> 128c2ecf20Sopenharmony_ci#include <uapi/linux/ip.h> 138c2ecf20Sopenharmony_ci#include <uapi/linux/virtio_net.h> 148c2ecf20Sopenharmony_ci#include <linux/virtio_net.h> 158c2ecf20Sopenharmony_ci#include <linux/virtio_byteorder.h> 168c2ecf20Sopenharmony_ci#include <linux/netdev_features.h> 178c2ecf20Sopenharmony_ci#include "vector_user.h" 188c2ecf20Sopenharmony_ci#include "vector_kern.h" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#define GOOD_LINEAR 512 218c2ecf20Sopenharmony_ci#define GSO_ERROR "Incoming GSO frames and GRO disabled on the interface" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistruct gre_minimal_header { 248c2ecf20Sopenharmony_ci uint16_t header; 258c2ecf20Sopenharmony_ci uint16_t arptype; 268c2ecf20Sopenharmony_ci}; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistruct uml_gre_data { 308c2ecf20Sopenharmony_ci uint32_t rx_key; 318c2ecf20Sopenharmony_ci uint32_t tx_key; 328c2ecf20Sopenharmony_ci uint32_t sequence; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci bool ipv6; 358c2ecf20Sopenharmony_ci bool has_sequence; 368c2ecf20Sopenharmony_ci bool pin_sequence; 378c2ecf20Sopenharmony_ci bool checksum; 388c2ecf20Sopenharmony_ci bool key; 398c2ecf20Sopenharmony_ci struct gre_minimal_header expected_header; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci uint32_t checksum_offset; 428c2ecf20Sopenharmony_ci uint32_t key_offset; 438c2ecf20Sopenharmony_ci uint32_t sequence_offset; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci}; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistruct uml_l2tpv3_data { 488c2ecf20Sopenharmony_ci uint64_t rx_cookie; 498c2ecf20Sopenharmony_ci uint64_t tx_cookie; 508c2ecf20Sopenharmony_ci uint64_t rx_session; 518c2ecf20Sopenharmony_ci uint64_t tx_session; 528c2ecf20Sopenharmony_ci uint32_t counter; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci bool udp; 558c2ecf20Sopenharmony_ci bool ipv6; 568c2ecf20Sopenharmony_ci bool has_counter; 578c2ecf20Sopenharmony_ci bool pin_counter; 588c2ecf20Sopenharmony_ci bool cookie; 598c2ecf20Sopenharmony_ci bool cookie_is_64; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci uint32_t cookie_offset; 628c2ecf20Sopenharmony_ci uint32_t session_offset; 638c2ecf20Sopenharmony_ci uint32_t counter_offset; 648c2ecf20Sopenharmony_ci}; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistatic int l2tpv3_form_header(uint8_t *header, 678c2ecf20Sopenharmony_ci struct sk_buff *skb, struct vector_private *vp) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci struct uml_l2tpv3_data *td = vp->transport_data; 708c2ecf20Sopenharmony_ci uint32_t *counter; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci if (td->udp) 738c2ecf20Sopenharmony_ci *(uint32_t *) header = cpu_to_be32(L2TPV3_DATA_PACKET); 748c2ecf20Sopenharmony_ci (*(uint32_t *) (header + td->session_offset)) = td->tx_session; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci if (td->cookie) { 778c2ecf20Sopenharmony_ci if (td->cookie_is_64) 788c2ecf20Sopenharmony_ci (*(uint64_t *)(header + td->cookie_offset)) = 798c2ecf20Sopenharmony_ci td->tx_cookie; 808c2ecf20Sopenharmony_ci else 818c2ecf20Sopenharmony_ci (*(uint32_t *)(header + td->cookie_offset)) = 828c2ecf20Sopenharmony_ci td->tx_cookie; 838c2ecf20Sopenharmony_ci } 848c2ecf20Sopenharmony_ci if (td->has_counter) { 858c2ecf20Sopenharmony_ci counter = (uint32_t *)(header + td->counter_offset); 868c2ecf20Sopenharmony_ci if (td->pin_counter) { 878c2ecf20Sopenharmony_ci *counter = 0; 888c2ecf20Sopenharmony_ci } else { 898c2ecf20Sopenharmony_ci td->counter++; 908c2ecf20Sopenharmony_ci *counter = cpu_to_be32(td->counter); 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci return 0; 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistatic int gre_form_header(uint8_t *header, 978c2ecf20Sopenharmony_ci struct sk_buff *skb, struct vector_private *vp) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci struct uml_gre_data *td = vp->transport_data; 1008c2ecf20Sopenharmony_ci uint32_t *sequence; 1018c2ecf20Sopenharmony_ci *((uint32_t *) header) = *((uint32_t *) &td->expected_header); 1028c2ecf20Sopenharmony_ci if (td->key) 1038c2ecf20Sopenharmony_ci (*(uint32_t *) (header + td->key_offset)) = td->tx_key; 1048c2ecf20Sopenharmony_ci if (td->has_sequence) { 1058c2ecf20Sopenharmony_ci sequence = (uint32_t *)(header + td->sequence_offset); 1068c2ecf20Sopenharmony_ci if (td->pin_sequence) 1078c2ecf20Sopenharmony_ci *sequence = 0; 1088c2ecf20Sopenharmony_ci else 1098c2ecf20Sopenharmony_ci *sequence = cpu_to_be32(++td->sequence); 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci return 0; 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_cistatic int raw_form_header(uint8_t *header, 1158c2ecf20Sopenharmony_ci struct sk_buff *skb, struct vector_private *vp) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci struct virtio_net_hdr *vheader = (struct virtio_net_hdr *) header; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci virtio_net_hdr_from_skb( 1208c2ecf20Sopenharmony_ci skb, 1218c2ecf20Sopenharmony_ci vheader, 1228c2ecf20Sopenharmony_ci virtio_legacy_is_little_endian(), 1238c2ecf20Sopenharmony_ci false, 1248c2ecf20Sopenharmony_ci 0 1258c2ecf20Sopenharmony_ci ); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci return 0; 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic int l2tpv3_verify_header( 1318c2ecf20Sopenharmony_ci uint8_t *header, struct sk_buff *skb, struct vector_private *vp) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci struct uml_l2tpv3_data *td = vp->transport_data; 1348c2ecf20Sopenharmony_ci uint32_t *session; 1358c2ecf20Sopenharmony_ci uint64_t cookie; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci if ((!td->udp) && (!td->ipv6)) 1388c2ecf20Sopenharmony_ci header += sizeof(struct iphdr) /* fix for ipv4 raw */; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci /* we do not do a strict check for "data" packets as per 1418c2ecf20Sopenharmony_ci * the RFC spec because the pure IP spec does not have 1428c2ecf20Sopenharmony_ci * that anyway. 1438c2ecf20Sopenharmony_ci */ 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci if (td->cookie) { 1468c2ecf20Sopenharmony_ci if (td->cookie_is_64) 1478c2ecf20Sopenharmony_ci cookie = *(uint64_t *)(header + td->cookie_offset); 1488c2ecf20Sopenharmony_ci else 1498c2ecf20Sopenharmony_ci cookie = *(uint32_t *)(header + td->cookie_offset); 1508c2ecf20Sopenharmony_ci if (cookie != td->rx_cookie) { 1518c2ecf20Sopenharmony_ci if (net_ratelimit()) 1528c2ecf20Sopenharmony_ci netdev_err(vp->dev, "uml_l2tpv3: unknown cookie id"); 1538c2ecf20Sopenharmony_ci return -1; 1548c2ecf20Sopenharmony_ci } 1558c2ecf20Sopenharmony_ci } 1568c2ecf20Sopenharmony_ci session = (uint32_t *) (header + td->session_offset); 1578c2ecf20Sopenharmony_ci if (*session != td->rx_session) { 1588c2ecf20Sopenharmony_ci if (net_ratelimit()) 1598c2ecf20Sopenharmony_ci netdev_err(vp->dev, "uml_l2tpv3: session mismatch"); 1608c2ecf20Sopenharmony_ci return -1; 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci return 0; 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic int gre_verify_header( 1668c2ecf20Sopenharmony_ci uint8_t *header, struct sk_buff *skb, struct vector_private *vp) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci uint32_t key; 1708c2ecf20Sopenharmony_ci struct uml_gre_data *td = vp->transport_data; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci if (!td->ipv6) 1738c2ecf20Sopenharmony_ci header += sizeof(struct iphdr) /* fix for ipv4 raw */; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci if (*((uint32_t *) header) != *((uint32_t *) &td->expected_header)) { 1768c2ecf20Sopenharmony_ci if (net_ratelimit()) 1778c2ecf20Sopenharmony_ci netdev_err(vp->dev, "header type disagreement, expecting %0x, got %0x", 1788c2ecf20Sopenharmony_ci *((uint32_t *) &td->expected_header), 1798c2ecf20Sopenharmony_ci *((uint32_t *) header) 1808c2ecf20Sopenharmony_ci ); 1818c2ecf20Sopenharmony_ci return -1; 1828c2ecf20Sopenharmony_ci } 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci if (td->key) { 1858c2ecf20Sopenharmony_ci key = (*(uint32_t *)(header + td->key_offset)); 1868c2ecf20Sopenharmony_ci if (key != td->rx_key) { 1878c2ecf20Sopenharmony_ci if (net_ratelimit()) 1888c2ecf20Sopenharmony_ci netdev_err(vp->dev, "unknown key id %0x, expecting %0x", 1898c2ecf20Sopenharmony_ci key, td->rx_key); 1908c2ecf20Sopenharmony_ci return -1; 1918c2ecf20Sopenharmony_ci } 1928c2ecf20Sopenharmony_ci } 1938c2ecf20Sopenharmony_ci return 0; 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_cistatic int raw_verify_header( 1978c2ecf20Sopenharmony_ci uint8_t *header, struct sk_buff *skb, struct vector_private *vp) 1988c2ecf20Sopenharmony_ci{ 1998c2ecf20Sopenharmony_ci struct virtio_net_hdr *vheader = (struct virtio_net_hdr *) header; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci if ((vheader->gso_type != VIRTIO_NET_HDR_GSO_NONE) && 2028c2ecf20Sopenharmony_ci (vp->req_size != 65536)) { 2038c2ecf20Sopenharmony_ci if (net_ratelimit()) 2048c2ecf20Sopenharmony_ci netdev_err( 2058c2ecf20Sopenharmony_ci vp->dev, 2068c2ecf20Sopenharmony_ci GSO_ERROR 2078c2ecf20Sopenharmony_ci ); 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci if ((vheader->flags & VIRTIO_NET_HDR_F_DATA_VALID) > 0) 2108c2ecf20Sopenharmony_ci return 1; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci virtio_net_hdr_to_skb(skb, vheader, virtio_legacy_is_little_endian()); 2138c2ecf20Sopenharmony_ci return 0; 2148c2ecf20Sopenharmony_ci} 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_cistatic bool get_uint_param( 2178c2ecf20Sopenharmony_ci struct arglist *def, char *param, unsigned int *result) 2188c2ecf20Sopenharmony_ci{ 2198c2ecf20Sopenharmony_ci char *arg = uml_vector_fetch_arg(def, param); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci if (arg != NULL) { 2228c2ecf20Sopenharmony_ci if (kstrtoint(arg, 0, result) == 0) 2238c2ecf20Sopenharmony_ci return true; 2248c2ecf20Sopenharmony_ci } 2258c2ecf20Sopenharmony_ci return false; 2268c2ecf20Sopenharmony_ci} 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_cistatic bool get_ulong_param( 2298c2ecf20Sopenharmony_ci struct arglist *def, char *param, unsigned long *result) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci char *arg = uml_vector_fetch_arg(def, param); 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci if (arg != NULL) { 2348c2ecf20Sopenharmony_ci if (kstrtoul(arg, 0, result) == 0) 2358c2ecf20Sopenharmony_ci return true; 2368c2ecf20Sopenharmony_ci return true; 2378c2ecf20Sopenharmony_ci } 2388c2ecf20Sopenharmony_ci return false; 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_cistatic int build_gre_transport_data(struct vector_private *vp) 2428c2ecf20Sopenharmony_ci{ 2438c2ecf20Sopenharmony_ci struct uml_gre_data *td; 2448c2ecf20Sopenharmony_ci int temp_int; 2458c2ecf20Sopenharmony_ci int temp_rx; 2468c2ecf20Sopenharmony_ci int temp_tx; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci vp->transport_data = kmalloc(sizeof(struct uml_gre_data), GFP_KERNEL); 2498c2ecf20Sopenharmony_ci if (vp->transport_data == NULL) 2508c2ecf20Sopenharmony_ci return -ENOMEM; 2518c2ecf20Sopenharmony_ci td = vp->transport_data; 2528c2ecf20Sopenharmony_ci td->sequence = 0; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci td->expected_header.arptype = GRE_IRB; 2558c2ecf20Sopenharmony_ci td->expected_header.header = 0; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci vp->form_header = &gre_form_header; 2588c2ecf20Sopenharmony_ci vp->verify_header = &gre_verify_header; 2598c2ecf20Sopenharmony_ci vp->header_size = 4; 2608c2ecf20Sopenharmony_ci td->key_offset = 4; 2618c2ecf20Sopenharmony_ci td->sequence_offset = 4; 2628c2ecf20Sopenharmony_ci td->checksum_offset = 4; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci td->ipv6 = false; 2658c2ecf20Sopenharmony_ci if (get_uint_param(vp->parsed, "v6", &temp_int)) { 2668c2ecf20Sopenharmony_ci if (temp_int > 0) 2678c2ecf20Sopenharmony_ci td->ipv6 = true; 2688c2ecf20Sopenharmony_ci } 2698c2ecf20Sopenharmony_ci td->key = false; 2708c2ecf20Sopenharmony_ci if (get_uint_param(vp->parsed, "rx_key", &temp_rx)) { 2718c2ecf20Sopenharmony_ci if (get_uint_param(vp->parsed, "tx_key", &temp_tx)) { 2728c2ecf20Sopenharmony_ci td->key = true; 2738c2ecf20Sopenharmony_ci td->expected_header.header |= GRE_MODE_KEY; 2748c2ecf20Sopenharmony_ci td->rx_key = cpu_to_be32(temp_rx); 2758c2ecf20Sopenharmony_ci td->tx_key = cpu_to_be32(temp_tx); 2768c2ecf20Sopenharmony_ci vp->header_size += 4; 2778c2ecf20Sopenharmony_ci td->sequence_offset += 4; 2788c2ecf20Sopenharmony_ci } else { 2798c2ecf20Sopenharmony_ci return -EINVAL; 2808c2ecf20Sopenharmony_ci } 2818c2ecf20Sopenharmony_ci } 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci td->sequence = false; 2848c2ecf20Sopenharmony_ci if (get_uint_param(vp->parsed, "sequence", &temp_int)) { 2858c2ecf20Sopenharmony_ci if (temp_int > 0) { 2868c2ecf20Sopenharmony_ci vp->header_size += 4; 2878c2ecf20Sopenharmony_ci td->has_sequence = true; 2888c2ecf20Sopenharmony_ci td->expected_header.header |= GRE_MODE_SEQUENCE; 2898c2ecf20Sopenharmony_ci if (get_uint_param( 2908c2ecf20Sopenharmony_ci vp->parsed, "pin_sequence", &temp_int)) { 2918c2ecf20Sopenharmony_ci if (temp_int > 0) 2928c2ecf20Sopenharmony_ci td->pin_sequence = true; 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci } 2958c2ecf20Sopenharmony_ci } 2968c2ecf20Sopenharmony_ci vp->rx_header_size = vp->header_size; 2978c2ecf20Sopenharmony_ci if (!td->ipv6) 2988c2ecf20Sopenharmony_ci vp->rx_header_size += sizeof(struct iphdr); 2998c2ecf20Sopenharmony_ci return 0; 3008c2ecf20Sopenharmony_ci} 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_cistatic int build_l2tpv3_transport_data(struct vector_private *vp) 3038c2ecf20Sopenharmony_ci{ 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci struct uml_l2tpv3_data *td; 3068c2ecf20Sopenharmony_ci int temp_int, temp_rxs, temp_txs; 3078c2ecf20Sopenharmony_ci unsigned long temp_rx; 3088c2ecf20Sopenharmony_ci unsigned long temp_tx; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci vp->transport_data = kmalloc( 3118c2ecf20Sopenharmony_ci sizeof(struct uml_l2tpv3_data), GFP_KERNEL); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci if (vp->transport_data == NULL) 3148c2ecf20Sopenharmony_ci return -ENOMEM; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci td = vp->transport_data; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci vp->form_header = &l2tpv3_form_header; 3198c2ecf20Sopenharmony_ci vp->verify_header = &l2tpv3_verify_header; 3208c2ecf20Sopenharmony_ci td->counter = 0; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci vp->header_size = 4; 3238c2ecf20Sopenharmony_ci td->session_offset = 0; 3248c2ecf20Sopenharmony_ci td->cookie_offset = 4; 3258c2ecf20Sopenharmony_ci td->counter_offset = 4; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci td->ipv6 = false; 3298c2ecf20Sopenharmony_ci if (get_uint_param(vp->parsed, "v6", &temp_int)) { 3308c2ecf20Sopenharmony_ci if (temp_int > 0) 3318c2ecf20Sopenharmony_ci td->ipv6 = true; 3328c2ecf20Sopenharmony_ci } 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci if (get_uint_param(vp->parsed, "rx_session", &temp_rxs)) { 3358c2ecf20Sopenharmony_ci if (get_uint_param(vp->parsed, "tx_session", &temp_txs)) { 3368c2ecf20Sopenharmony_ci td->tx_session = cpu_to_be32(temp_txs); 3378c2ecf20Sopenharmony_ci td->rx_session = cpu_to_be32(temp_rxs); 3388c2ecf20Sopenharmony_ci } else { 3398c2ecf20Sopenharmony_ci return -EINVAL; 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci } else { 3428c2ecf20Sopenharmony_ci return -EINVAL; 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci td->cookie_is_64 = false; 3468c2ecf20Sopenharmony_ci if (get_uint_param(vp->parsed, "cookie64", &temp_int)) { 3478c2ecf20Sopenharmony_ci if (temp_int > 0) 3488c2ecf20Sopenharmony_ci td->cookie_is_64 = true; 3498c2ecf20Sopenharmony_ci } 3508c2ecf20Sopenharmony_ci td->cookie = false; 3518c2ecf20Sopenharmony_ci if (get_ulong_param(vp->parsed, "rx_cookie", &temp_rx)) { 3528c2ecf20Sopenharmony_ci if (get_ulong_param(vp->parsed, "tx_cookie", &temp_tx)) { 3538c2ecf20Sopenharmony_ci td->cookie = true; 3548c2ecf20Sopenharmony_ci if (td->cookie_is_64) { 3558c2ecf20Sopenharmony_ci td->rx_cookie = cpu_to_be64(temp_rx); 3568c2ecf20Sopenharmony_ci td->tx_cookie = cpu_to_be64(temp_tx); 3578c2ecf20Sopenharmony_ci vp->header_size += 8; 3588c2ecf20Sopenharmony_ci td->counter_offset += 8; 3598c2ecf20Sopenharmony_ci } else { 3608c2ecf20Sopenharmony_ci td->rx_cookie = cpu_to_be32(temp_rx); 3618c2ecf20Sopenharmony_ci td->tx_cookie = cpu_to_be32(temp_tx); 3628c2ecf20Sopenharmony_ci vp->header_size += 4; 3638c2ecf20Sopenharmony_ci td->counter_offset += 4; 3648c2ecf20Sopenharmony_ci } 3658c2ecf20Sopenharmony_ci } else { 3668c2ecf20Sopenharmony_ci return -EINVAL; 3678c2ecf20Sopenharmony_ci } 3688c2ecf20Sopenharmony_ci } 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci td->has_counter = false; 3718c2ecf20Sopenharmony_ci if (get_uint_param(vp->parsed, "counter", &temp_int)) { 3728c2ecf20Sopenharmony_ci if (temp_int > 0) { 3738c2ecf20Sopenharmony_ci td->has_counter = true; 3748c2ecf20Sopenharmony_ci vp->header_size += 4; 3758c2ecf20Sopenharmony_ci if (get_uint_param( 3768c2ecf20Sopenharmony_ci vp->parsed, "pin_counter", &temp_int)) { 3778c2ecf20Sopenharmony_ci if (temp_int > 0) 3788c2ecf20Sopenharmony_ci td->pin_counter = true; 3798c2ecf20Sopenharmony_ci } 3808c2ecf20Sopenharmony_ci } 3818c2ecf20Sopenharmony_ci } 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci if (get_uint_param(vp->parsed, "udp", &temp_int)) { 3848c2ecf20Sopenharmony_ci if (temp_int > 0) { 3858c2ecf20Sopenharmony_ci td->udp = true; 3868c2ecf20Sopenharmony_ci vp->header_size += 4; 3878c2ecf20Sopenharmony_ci td->counter_offset += 4; 3888c2ecf20Sopenharmony_ci td->session_offset += 4; 3898c2ecf20Sopenharmony_ci td->cookie_offset += 4; 3908c2ecf20Sopenharmony_ci } 3918c2ecf20Sopenharmony_ci } 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci vp->rx_header_size = vp->header_size; 3948c2ecf20Sopenharmony_ci if ((!td->ipv6) && (!td->udp)) 3958c2ecf20Sopenharmony_ci vp->rx_header_size += sizeof(struct iphdr); 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci return 0; 3988c2ecf20Sopenharmony_ci} 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_cistatic int build_raw_transport_data(struct vector_private *vp) 4018c2ecf20Sopenharmony_ci{ 4028c2ecf20Sopenharmony_ci if (uml_raw_enable_vnet_headers(vp->fds->rx_fd)) { 4038c2ecf20Sopenharmony_ci if (!uml_raw_enable_vnet_headers(vp->fds->tx_fd)) 4048c2ecf20Sopenharmony_ci return -1; 4058c2ecf20Sopenharmony_ci vp->form_header = &raw_form_header; 4068c2ecf20Sopenharmony_ci vp->verify_header = &raw_verify_header; 4078c2ecf20Sopenharmony_ci vp->header_size = sizeof(struct virtio_net_hdr); 4088c2ecf20Sopenharmony_ci vp->rx_header_size = sizeof(struct virtio_net_hdr); 4098c2ecf20Sopenharmony_ci vp->dev->hw_features |= (NETIF_F_TSO | NETIF_F_GRO); 4108c2ecf20Sopenharmony_ci vp->dev->features |= 4118c2ecf20Sopenharmony_ci (NETIF_F_RXCSUM | NETIF_F_HW_CSUM | 4128c2ecf20Sopenharmony_ci NETIF_F_TSO | NETIF_F_GRO); 4138c2ecf20Sopenharmony_ci netdev_info( 4148c2ecf20Sopenharmony_ci vp->dev, 4158c2ecf20Sopenharmony_ci "raw: using vnet headers for tso and tx/rx checksum" 4168c2ecf20Sopenharmony_ci ); 4178c2ecf20Sopenharmony_ci } 4188c2ecf20Sopenharmony_ci return 0; 4198c2ecf20Sopenharmony_ci} 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_cistatic int build_hybrid_transport_data(struct vector_private *vp) 4228c2ecf20Sopenharmony_ci{ 4238c2ecf20Sopenharmony_ci if (uml_raw_enable_vnet_headers(vp->fds->rx_fd)) { 4248c2ecf20Sopenharmony_ci vp->form_header = &raw_form_header; 4258c2ecf20Sopenharmony_ci vp->verify_header = &raw_verify_header; 4268c2ecf20Sopenharmony_ci vp->header_size = sizeof(struct virtio_net_hdr); 4278c2ecf20Sopenharmony_ci vp->rx_header_size = sizeof(struct virtio_net_hdr); 4288c2ecf20Sopenharmony_ci vp->dev->hw_features |= 4298c2ecf20Sopenharmony_ci (NETIF_F_TSO | NETIF_F_GSO | NETIF_F_GRO); 4308c2ecf20Sopenharmony_ci vp->dev->features |= 4318c2ecf20Sopenharmony_ci (NETIF_F_RXCSUM | NETIF_F_HW_CSUM | 4328c2ecf20Sopenharmony_ci NETIF_F_TSO | NETIF_F_GSO | NETIF_F_GRO); 4338c2ecf20Sopenharmony_ci netdev_info( 4348c2ecf20Sopenharmony_ci vp->dev, 4358c2ecf20Sopenharmony_ci "tap/raw hybrid: using vnet headers for tso and tx/rx checksum" 4368c2ecf20Sopenharmony_ci ); 4378c2ecf20Sopenharmony_ci } else { 4388c2ecf20Sopenharmony_ci return 0; /* do not try to enable tap too if raw failed */ 4398c2ecf20Sopenharmony_ci } 4408c2ecf20Sopenharmony_ci if (uml_tap_enable_vnet_headers(vp->fds->tx_fd)) 4418c2ecf20Sopenharmony_ci return 0; 4428c2ecf20Sopenharmony_ci return -1; 4438c2ecf20Sopenharmony_ci} 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_cistatic int build_tap_transport_data(struct vector_private *vp) 4468c2ecf20Sopenharmony_ci{ 4478c2ecf20Sopenharmony_ci /* "Pure" tap uses the same fd for rx and tx */ 4488c2ecf20Sopenharmony_ci if (uml_tap_enable_vnet_headers(vp->fds->tx_fd)) { 4498c2ecf20Sopenharmony_ci vp->form_header = &raw_form_header; 4508c2ecf20Sopenharmony_ci vp->verify_header = &raw_verify_header; 4518c2ecf20Sopenharmony_ci vp->header_size = sizeof(struct virtio_net_hdr); 4528c2ecf20Sopenharmony_ci vp->rx_header_size = sizeof(struct virtio_net_hdr); 4538c2ecf20Sopenharmony_ci vp->dev->hw_features |= 4548c2ecf20Sopenharmony_ci (NETIF_F_TSO | NETIF_F_GSO | NETIF_F_GRO); 4558c2ecf20Sopenharmony_ci vp->dev->features |= 4568c2ecf20Sopenharmony_ci (NETIF_F_RXCSUM | NETIF_F_HW_CSUM | 4578c2ecf20Sopenharmony_ci NETIF_F_TSO | NETIF_F_GSO | NETIF_F_GRO); 4588c2ecf20Sopenharmony_ci netdev_info( 4598c2ecf20Sopenharmony_ci vp->dev, 4608c2ecf20Sopenharmony_ci "tap: using vnet headers for tso and tx/rx checksum" 4618c2ecf20Sopenharmony_ci ); 4628c2ecf20Sopenharmony_ci return 0; 4638c2ecf20Sopenharmony_ci } 4648c2ecf20Sopenharmony_ci return -1; 4658c2ecf20Sopenharmony_ci} 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_cistatic int build_bess_transport_data(struct vector_private *vp) 4698c2ecf20Sopenharmony_ci{ 4708c2ecf20Sopenharmony_ci vp->form_header = NULL; 4718c2ecf20Sopenharmony_ci vp->verify_header = NULL; 4728c2ecf20Sopenharmony_ci vp->header_size = 0; 4738c2ecf20Sopenharmony_ci vp->rx_header_size = 0; 4748c2ecf20Sopenharmony_ci return 0; 4758c2ecf20Sopenharmony_ci} 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ciint build_transport_data(struct vector_private *vp) 4788c2ecf20Sopenharmony_ci{ 4798c2ecf20Sopenharmony_ci char *transport = uml_vector_fetch_arg(vp->parsed, "transport"); 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci if (strncmp(transport, TRANS_GRE, TRANS_GRE_LEN) == 0) 4828c2ecf20Sopenharmony_ci return build_gre_transport_data(vp); 4838c2ecf20Sopenharmony_ci if (strncmp(transport, TRANS_L2TPV3, TRANS_L2TPV3_LEN) == 0) 4848c2ecf20Sopenharmony_ci return build_l2tpv3_transport_data(vp); 4858c2ecf20Sopenharmony_ci if (strncmp(transport, TRANS_RAW, TRANS_RAW_LEN) == 0) 4868c2ecf20Sopenharmony_ci return build_raw_transport_data(vp); 4878c2ecf20Sopenharmony_ci if (strncmp(transport, TRANS_TAP, TRANS_TAP_LEN) == 0) 4888c2ecf20Sopenharmony_ci return build_tap_transport_data(vp); 4898c2ecf20Sopenharmony_ci if (strncmp(transport, TRANS_HYBRID, TRANS_HYBRID_LEN) == 0) 4908c2ecf20Sopenharmony_ci return build_hybrid_transport_data(vp); 4918c2ecf20Sopenharmony_ci if (strncmp(transport, TRANS_BESS, TRANS_BESS_LEN) == 0) 4928c2ecf20Sopenharmony_ci return build_bess_transport_data(vp); 4938c2ecf20Sopenharmony_ci return 0; 4948c2ecf20Sopenharmony_ci} 4958c2ecf20Sopenharmony_ci 496