162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2017 - Cambridge Greys Limited 462306a36Sopenharmony_ci * Copyright (C) 2011 - 2014 Cisco Systems Inc 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/etherdevice.h> 862306a36Sopenharmony_ci#include <linux/netdevice.h> 962306a36Sopenharmony_ci#include <linux/skbuff.h> 1062306a36Sopenharmony_ci#include <linux/slab.h> 1162306a36Sopenharmony_ci#include <asm/byteorder.h> 1262306a36Sopenharmony_ci#include <uapi/linux/ip.h> 1362306a36Sopenharmony_ci#include <uapi/linux/virtio_net.h> 1462306a36Sopenharmony_ci#include <linux/virtio_net.h> 1562306a36Sopenharmony_ci#include <linux/virtio_byteorder.h> 1662306a36Sopenharmony_ci#include <linux/netdev_features.h> 1762306a36Sopenharmony_ci#include "vector_user.h" 1862306a36Sopenharmony_ci#include "vector_kern.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#define GOOD_LINEAR 512 2162306a36Sopenharmony_ci#define GSO_ERROR "Incoming GSO frames and GRO disabled on the interface" 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistruct gre_minimal_header { 2462306a36Sopenharmony_ci uint16_t header; 2562306a36Sopenharmony_ci uint16_t arptype; 2662306a36Sopenharmony_ci}; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_cistruct uml_gre_data { 3062306a36Sopenharmony_ci uint32_t rx_key; 3162306a36Sopenharmony_ci uint32_t tx_key; 3262306a36Sopenharmony_ci uint32_t sequence; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci bool ipv6; 3562306a36Sopenharmony_ci bool has_sequence; 3662306a36Sopenharmony_ci bool pin_sequence; 3762306a36Sopenharmony_ci bool checksum; 3862306a36Sopenharmony_ci bool key; 3962306a36Sopenharmony_ci struct gre_minimal_header expected_header; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci uint32_t checksum_offset; 4262306a36Sopenharmony_ci uint32_t key_offset; 4362306a36Sopenharmony_ci uint32_t sequence_offset; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci}; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistruct uml_l2tpv3_data { 4862306a36Sopenharmony_ci uint64_t rx_cookie; 4962306a36Sopenharmony_ci uint64_t tx_cookie; 5062306a36Sopenharmony_ci uint64_t rx_session; 5162306a36Sopenharmony_ci uint64_t tx_session; 5262306a36Sopenharmony_ci uint32_t counter; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci bool udp; 5562306a36Sopenharmony_ci bool ipv6; 5662306a36Sopenharmony_ci bool has_counter; 5762306a36Sopenharmony_ci bool pin_counter; 5862306a36Sopenharmony_ci bool cookie; 5962306a36Sopenharmony_ci bool cookie_is_64; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci uint32_t cookie_offset; 6262306a36Sopenharmony_ci uint32_t session_offset; 6362306a36Sopenharmony_ci uint32_t counter_offset; 6462306a36Sopenharmony_ci}; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistatic int l2tpv3_form_header(uint8_t *header, 6762306a36Sopenharmony_ci struct sk_buff *skb, struct vector_private *vp) 6862306a36Sopenharmony_ci{ 6962306a36Sopenharmony_ci struct uml_l2tpv3_data *td = vp->transport_data; 7062306a36Sopenharmony_ci uint32_t *counter; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci if (td->udp) 7362306a36Sopenharmony_ci *(uint32_t *) header = cpu_to_be32(L2TPV3_DATA_PACKET); 7462306a36Sopenharmony_ci (*(uint32_t *) (header + td->session_offset)) = td->tx_session; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci if (td->cookie) { 7762306a36Sopenharmony_ci if (td->cookie_is_64) 7862306a36Sopenharmony_ci (*(uint64_t *)(header + td->cookie_offset)) = 7962306a36Sopenharmony_ci td->tx_cookie; 8062306a36Sopenharmony_ci else 8162306a36Sopenharmony_ci (*(uint32_t *)(header + td->cookie_offset)) = 8262306a36Sopenharmony_ci td->tx_cookie; 8362306a36Sopenharmony_ci } 8462306a36Sopenharmony_ci if (td->has_counter) { 8562306a36Sopenharmony_ci counter = (uint32_t *)(header + td->counter_offset); 8662306a36Sopenharmony_ci if (td->pin_counter) { 8762306a36Sopenharmony_ci *counter = 0; 8862306a36Sopenharmony_ci } else { 8962306a36Sopenharmony_ci td->counter++; 9062306a36Sopenharmony_ci *counter = cpu_to_be32(td->counter); 9162306a36Sopenharmony_ci } 9262306a36Sopenharmony_ci } 9362306a36Sopenharmony_ci return 0; 9462306a36Sopenharmony_ci} 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_cistatic int gre_form_header(uint8_t *header, 9762306a36Sopenharmony_ci struct sk_buff *skb, struct vector_private *vp) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci struct uml_gre_data *td = vp->transport_data; 10062306a36Sopenharmony_ci uint32_t *sequence; 10162306a36Sopenharmony_ci *((uint32_t *) header) = *((uint32_t *) &td->expected_header); 10262306a36Sopenharmony_ci if (td->key) 10362306a36Sopenharmony_ci (*(uint32_t *) (header + td->key_offset)) = td->tx_key; 10462306a36Sopenharmony_ci if (td->has_sequence) { 10562306a36Sopenharmony_ci sequence = (uint32_t *)(header + td->sequence_offset); 10662306a36Sopenharmony_ci if (td->pin_sequence) 10762306a36Sopenharmony_ci *sequence = 0; 10862306a36Sopenharmony_ci else 10962306a36Sopenharmony_ci *sequence = cpu_to_be32(++td->sequence); 11062306a36Sopenharmony_ci } 11162306a36Sopenharmony_ci return 0; 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistatic int raw_form_header(uint8_t *header, 11562306a36Sopenharmony_ci struct sk_buff *skb, struct vector_private *vp) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci struct virtio_net_hdr *vheader = (struct virtio_net_hdr *) header; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci virtio_net_hdr_from_skb( 12062306a36Sopenharmony_ci skb, 12162306a36Sopenharmony_ci vheader, 12262306a36Sopenharmony_ci virtio_legacy_is_little_endian(), 12362306a36Sopenharmony_ci false, 12462306a36Sopenharmony_ci 0 12562306a36Sopenharmony_ci ); 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci return 0; 12862306a36Sopenharmony_ci} 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cistatic int l2tpv3_verify_header( 13162306a36Sopenharmony_ci uint8_t *header, struct sk_buff *skb, struct vector_private *vp) 13262306a36Sopenharmony_ci{ 13362306a36Sopenharmony_ci struct uml_l2tpv3_data *td = vp->transport_data; 13462306a36Sopenharmony_ci uint32_t *session; 13562306a36Sopenharmony_ci uint64_t cookie; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci if ((!td->udp) && (!td->ipv6)) 13862306a36Sopenharmony_ci header += sizeof(struct iphdr) /* fix for ipv4 raw */; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci /* we do not do a strict check for "data" packets as per 14162306a36Sopenharmony_ci * the RFC spec because the pure IP spec does not have 14262306a36Sopenharmony_ci * that anyway. 14362306a36Sopenharmony_ci */ 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci if (td->cookie) { 14662306a36Sopenharmony_ci if (td->cookie_is_64) 14762306a36Sopenharmony_ci cookie = *(uint64_t *)(header + td->cookie_offset); 14862306a36Sopenharmony_ci else 14962306a36Sopenharmony_ci cookie = *(uint32_t *)(header + td->cookie_offset); 15062306a36Sopenharmony_ci if (cookie != td->rx_cookie) { 15162306a36Sopenharmony_ci if (net_ratelimit()) 15262306a36Sopenharmony_ci netdev_err(vp->dev, "uml_l2tpv3: unknown cookie id"); 15362306a36Sopenharmony_ci return -1; 15462306a36Sopenharmony_ci } 15562306a36Sopenharmony_ci } 15662306a36Sopenharmony_ci session = (uint32_t *) (header + td->session_offset); 15762306a36Sopenharmony_ci if (*session != td->rx_session) { 15862306a36Sopenharmony_ci if (net_ratelimit()) 15962306a36Sopenharmony_ci netdev_err(vp->dev, "uml_l2tpv3: session mismatch"); 16062306a36Sopenharmony_ci return -1; 16162306a36Sopenharmony_ci } 16262306a36Sopenharmony_ci return 0; 16362306a36Sopenharmony_ci} 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_cistatic int gre_verify_header( 16662306a36Sopenharmony_ci uint8_t *header, struct sk_buff *skb, struct vector_private *vp) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci uint32_t key; 17062306a36Sopenharmony_ci struct uml_gre_data *td = vp->transport_data; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci if (!td->ipv6) 17362306a36Sopenharmony_ci header += sizeof(struct iphdr) /* fix for ipv4 raw */; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci if (*((uint32_t *) header) != *((uint32_t *) &td->expected_header)) { 17662306a36Sopenharmony_ci if (net_ratelimit()) 17762306a36Sopenharmony_ci netdev_err(vp->dev, "header type disagreement, expecting %0x, got %0x", 17862306a36Sopenharmony_ci *((uint32_t *) &td->expected_header), 17962306a36Sopenharmony_ci *((uint32_t *) header) 18062306a36Sopenharmony_ci ); 18162306a36Sopenharmony_ci return -1; 18262306a36Sopenharmony_ci } 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci if (td->key) { 18562306a36Sopenharmony_ci key = (*(uint32_t *)(header + td->key_offset)); 18662306a36Sopenharmony_ci if (key != td->rx_key) { 18762306a36Sopenharmony_ci if (net_ratelimit()) 18862306a36Sopenharmony_ci netdev_err(vp->dev, "unknown key id %0x, expecting %0x", 18962306a36Sopenharmony_ci key, td->rx_key); 19062306a36Sopenharmony_ci return -1; 19162306a36Sopenharmony_ci } 19262306a36Sopenharmony_ci } 19362306a36Sopenharmony_ci return 0; 19462306a36Sopenharmony_ci} 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_cistatic int raw_verify_header( 19762306a36Sopenharmony_ci uint8_t *header, struct sk_buff *skb, struct vector_private *vp) 19862306a36Sopenharmony_ci{ 19962306a36Sopenharmony_ci struct virtio_net_hdr *vheader = (struct virtio_net_hdr *) header; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci if ((vheader->gso_type != VIRTIO_NET_HDR_GSO_NONE) && 20262306a36Sopenharmony_ci (vp->req_size != 65536)) { 20362306a36Sopenharmony_ci if (net_ratelimit()) 20462306a36Sopenharmony_ci netdev_err( 20562306a36Sopenharmony_ci vp->dev, 20662306a36Sopenharmony_ci GSO_ERROR 20762306a36Sopenharmony_ci ); 20862306a36Sopenharmony_ci } 20962306a36Sopenharmony_ci if ((vheader->flags & VIRTIO_NET_HDR_F_DATA_VALID) > 0) 21062306a36Sopenharmony_ci return 1; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci virtio_net_hdr_to_skb(skb, vheader, virtio_legacy_is_little_endian()); 21362306a36Sopenharmony_ci return 0; 21462306a36Sopenharmony_ci} 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_cistatic bool get_uint_param( 21762306a36Sopenharmony_ci struct arglist *def, char *param, unsigned int *result) 21862306a36Sopenharmony_ci{ 21962306a36Sopenharmony_ci char *arg = uml_vector_fetch_arg(def, param); 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci if (arg != NULL) { 22262306a36Sopenharmony_ci if (kstrtoint(arg, 0, result) == 0) 22362306a36Sopenharmony_ci return true; 22462306a36Sopenharmony_ci } 22562306a36Sopenharmony_ci return false; 22662306a36Sopenharmony_ci} 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_cistatic bool get_ulong_param( 22962306a36Sopenharmony_ci struct arglist *def, char *param, unsigned long *result) 23062306a36Sopenharmony_ci{ 23162306a36Sopenharmony_ci char *arg = uml_vector_fetch_arg(def, param); 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci if (arg != NULL) { 23462306a36Sopenharmony_ci if (kstrtoul(arg, 0, result) == 0) 23562306a36Sopenharmony_ci return true; 23662306a36Sopenharmony_ci return true; 23762306a36Sopenharmony_ci } 23862306a36Sopenharmony_ci return false; 23962306a36Sopenharmony_ci} 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_cistatic int build_gre_transport_data(struct vector_private *vp) 24262306a36Sopenharmony_ci{ 24362306a36Sopenharmony_ci struct uml_gre_data *td; 24462306a36Sopenharmony_ci int temp_int; 24562306a36Sopenharmony_ci int temp_rx; 24662306a36Sopenharmony_ci int temp_tx; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci vp->transport_data = kmalloc(sizeof(struct uml_gre_data), GFP_KERNEL); 24962306a36Sopenharmony_ci if (vp->transport_data == NULL) 25062306a36Sopenharmony_ci return -ENOMEM; 25162306a36Sopenharmony_ci td = vp->transport_data; 25262306a36Sopenharmony_ci td->sequence = 0; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci td->expected_header.arptype = GRE_IRB; 25562306a36Sopenharmony_ci td->expected_header.header = 0; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci vp->form_header = &gre_form_header; 25862306a36Sopenharmony_ci vp->verify_header = &gre_verify_header; 25962306a36Sopenharmony_ci vp->header_size = 4; 26062306a36Sopenharmony_ci td->key_offset = 4; 26162306a36Sopenharmony_ci td->sequence_offset = 4; 26262306a36Sopenharmony_ci td->checksum_offset = 4; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci td->ipv6 = false; 26562306a36Sopenharmony_ci if (get_uint_param(vp->parsed, "v6", &temp_int)) { 26662306a36Sopenharmony_ci if (temp_int > 0) 26762306a36Sopenharmony_ci td->ipv6 = true; 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci td->key = false; 27062306a36Sopenharmony_ci if (get_uint_param(vp->parsed, "rx_key", &temp_rx)) { 27162306a36Sopenharmony_ci if (get_uint_param(vp->parsed, "tx_key", &temp_tx)) { 27262306a36Sopenharmony_ci td->key = true; 27362306a36Sopenharmony_ci td->expected_header.header |= GRE_MODE_KEY; 27462306a36Sopenharmony_ci td->rx_key = cpu_to_be32(temp_rx); 27562306a36Sopenharmony_ci td->tx_key = cpu_to_be32(temp_tx); 27662306a36Sopenharmony_ci vp->header_size += 4; 27762306a36Sopenharmony_ci td->sequence_offset += 4; 27862306a36Sopenharmony_ci } else { 27962306a36Sopenharmony_ci return -EINVAL; 28062306a36Sopenharmony_ci } 28162306a36Sopenharmony_ci } 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci td->sequence = false; 28462306a36Sopenharmony_ci if (get_uint_param(vp->parsed, "sequence", &temp_int)) { 28562306a36Sopenharmony_ci if (temp_int > 0) { 28662306a36Sopenharmony_ci vp->header_size += 4; 28762306a36Sopenharmony_ci td->has_sequence = true; 28862306a36Sopenharmony_ci td->expected_header.header |= GRE_MODE_SEQUENCE; 28962306a36Sopenharmony_ci if (get_uint_param( 29062306a36Sopenharmony_ci vp->parsed, "pin_sequence", &temp_int)) { 29162306a36Sopenharmony_ci if (temp_int > 0) 29262306a36Sopenharmony_ci td->pin_sequence = true; 29362306a36Sopenharmony_ci } 29462306a36Sopenharmony_ci } 29562306a36Sopenharmony_ci } 29662306a36Sopenharmony_ci vp->rx_header_size = vp->header_size; 29762306a36Sopenharmony_ci if (!td->ipv6) 29862306a36Sopenharmony_ci vp->rx_header_size += sizeof(struct iphdr); 29962306a36Sopenharmony_ci return 0; 30062306a36Sopenharmony_ci} 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_cistatic int build_l2tpv3_transport_data(struct vector_private *vp) 30362306a36Sopenharmony_ci{ 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci struct uml_l2tpv3_data *td; 30662306a36Sopenharmony_ci int temp_int, temp_rxs, temp_txs; 30762306a36Sopenharmony_ci unsigned long temp_rx; 30862306a36Sopenharmony_ci unsigned long temp_tx; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci vp->transport_data = kmalloc( 31162306a36Sopenharmony_ci sizeof(struct uml_l2tpv3_data), GFP_KERNEL); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci if (vp->transport_data == NULL) 31462306a36Sopenharmony_ci return -ENOMEM; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci td = vp->transport_data; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci vp->form_header = &l2tpv3_form_header; 31962306a36Sopenharmony_ci vp->verify_header = &l2tpv3_verify_header; 32062306a36Sopenharmony_ci td->counter = 0; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci vp->header_size = 4; 32362306a36Sopenharmony_ci td->session_offset = 0; 32462306a36Sopenharmony_ci td->cookie_offset = 4; 32562306a36Sopenharmony_ci td->counter_offset = 4; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci td->ipv6 = false; 32962306a36Sopenharmony_ci if (get_uint_param(vp->parsed, "v6", &temp_int)) { 33062306a36Sopenharmony_ci if (temp_int > 0) 33162306a36Sopenharmony_ci td->ipv6 = true; 33262306a36Sopenharmony_ci } 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci if (get_uint_param(vp->parsed, "rx_session", &temp_rxs)) { 33562306a36Sopenharmony_ci if (get_uint_param(vp->parsed, "tx_session", &temp_txs)) { 33662306a36Sopenharmony_ci td->tx_session = cpu_to_be32(temp_txs); 33762306a36Sopenharmony_ci td->rx_session = cpu_to_be32(temp_rxs); 33862306a36Sopenharmony_ci } else { 33962306a36Sopenharmony_ci return -EINVAL; 34062306a36Sopenharmony_ci } 34162306a36Sopenharmony_ci } else { 34262306a36Sopenharmony_ci return -EINVAL; 34362306a36Sopenharmony_ci } 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci td->cookie_is_64 = false; 34662306a36Sopenharmony_ci if (get_uint_param(vp->parsed, "cookie64", &temp_int)) { 34762306a36Sopenharmony_ci if (temp_int > 0) 34862306a36Sopenharmony_ci td->cookie_is_64 = true; 34962306a36Sopenharmony_ci } 35062306a36Sopenharmony_ci td->cookie = false; 35162306a36Sopenharmony_ci if (get_ulong_param(vp->parsed, "rx_cookie", &temp_rx)) { 35262306a36Sopenharmony_ci if (get_ulong_param(vp->parsed, "tx_cookie", &temp_tx)) { 35362306a36Sopenharmony_ci td->cookie = true; 35462306a36Sopenharmony_ci if (td->cookie_is_64) { 35562306a36Sopenharmony_ci td->rx_cookie = cpu_to_be64(temp_rx); 35662306a36Sopenharmony_ci td->tx_cookie = cpu_to_be64(temp_tx); 35762306a36Sopenharmony_ci vp->header_size += 8; 35862306a36Sopenharmony_ci td->counter_offset += 8; 35962306a36Sopenharmony_ci } else { 36062306a36Sopenharmony_ci td->rx_cookie = cpu_to_be32(temp_rx); 36162306a36Sopenharmony_ci td->tx_cookie = cpu_to_be32(temp_tx); 36262306a36Sopenharmony_ci vp->header_size += 4; 36362306a36Sopenharmony_ci td->counter_offset += 4; 36462306a36Sopenharmony_ci } 36562306a36Sopenharmony_ci } else { 36662306a36Sopenharmony_ci return -EINVAL; 36762306a36Sopenharmony_ci } 36862306a36Sopenharmony_ci } 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci td->has_counter = false; 37162306a36Sopenharmony_ci if (get_uint_param(vp->parsed, "counter", &temp_int)) { 37262306a36Sopenharmony_ci if (temp_int > 0) { 37362306a36Sopenharmony_ci td->has_counter = true; 37462306a36Sopenharmony_ci vp->header_size += 4; 37562306a36Sopenharmony_ci if (get_uint_param( 37662306a36Sopenharmony_ci vp->parsed, "pin_counter", &temp_int)) { 37762306a36Sopenharmony_ci if (temp_int > 0) 37862306a36Sopenharmony_ci td->pin_counter = true; 37962306a36Sopenharmony_ci } 38062306a36Sopenharmony_ci } 38162306a36Sopenharmony_ci } 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci if (get_uint_param(vp->parsed, "udp", &temp_int)) { 38462306a36Sopenharmony_ci if (temp_int > 0) { 38562306a36Sopenharmony_ci td->udp = true; 38662306a36Sopenharmony_ci vp->header_size += 4; 38762306a36Sopenharmony_ci td->counter_offset += 4; 38862306a36Sopenharmony_ci td->session_offset += 4; 38962306a36Sopenharmony_ci td->cookie_offset += 4; 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci } 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci vp->rx_header_size = vp->header_size; 39462306a36Sopenharmony_ci if ((!td->ipv6) && (!td->udp)) 39562306a36Sopenharmony_ci vp->rx_header_size += sizeof(struct iphdr); 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci return 0; 39862306a36Sopenharmony_ci} 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_cistatic int build_raw_transport_data(struct vector_private *vp) 40162306a36Sopenharmony_ci{ 40262306a36Sopenharmony_ci if (uml_raw_enable_vnet_headers(vp->fds->rx_fd)) { 40362306a36Sopenharmony_ci if (!uml_raw_enable_vnet_headers(vp->fds->tx_fd)) 40462306a36Sopenharmony_ci return -1; 40562306a36Sopenharmony_ci vp->form_header = &raw_form_header; 40662306a36Sopenharmony_ci vp->verify_header = &raw_verify_header; 40762306a36Sopenharmony_ci vp->header_size = sizeof(struct virtio_net_hdr); 40862306a36Sopenharmony_ci vp->rx_header_size = sizeof(struct virtio_net_hdr); 40962306a36Sopenharmony_ci vp->dev->hw_features |= (NETIF_F_TSO | NETIF_F_GRO); 41062306a36Sopenharmony_ci vp->dev->features |= 41162306a36Sopenharmony_ci (NETIF_F_RXCSUM | NETIF_F_HW_CSUM | 41262306a36Sopenharmony_ci NETIF_F_TSO | NETIF_F_GRO); 41362306a36Sopenharmony_ci netdev_info( 41462306a36Sopenharmony_ci vp->dev, 41562306a36Sopenharmony_ci "raw: using vnet headers for tso and tx/rx checksum" 41662306a36Sopenharmony_ci ); 41762306a36Sopenharmony_ci } 41862306a36Sopenharmony_ci return 0; 41962306a36Sopenharmony_ci} 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_cistatic int build_hybrid_transport_data(struct vector_private *vp) 42262306a36Sopenharmony_ci{ 42362306a36Sopenharmony_ci if (uml_raw_enable_vnet_headers(vp->fds->rx_fd)) { 42462306a36Sopenharmony_ci vp->form_header = &raw_form_header; 42562306a36Sopenharmony_ci vp->verify_header = &raw_verify_header; 42662306a36Sopenharmony_ci vp->header_size = sizeof(struct virtio_net_hdr); 42762306a36Sopenharmony_ci vp->rx_header_size = sizeof(struct virtio_net_hdr); 42862306a36Sopenharmony_ci vp->dev->hw_features |= 42962306a36Sopenharmony_ci (NETIF_F_TSO | NETIF_F_GSO | NETIF_F_GRO); 43062306a36Sopenharmony_ci vp->dev->features |= 43162306a36Sopenharmony_ci (NETIF_F_RXCSUM | NETIF_F_HW_CSUM | 43262306a36Sopenharmony_ci NETIF_F_TSO | NETIF_F_GSO | NETIF_F_GRO); 43362306a36Sopenharmony_ci netdev_info( 43462306a36Sopenharmony_ci vp->dev, 43562306a36Sopenharmony_ci "tap/raw hybrid: using vnet headers for tso and tx/rx checksum" 43662306a36Sopenharmony_ci ); 43762306a36Sopenharmony_ci } else { 43862306a36Sopenharmony_ci return 0; /* do not try to enable tap too if raw failed */ 43962306a36Sopenharmony_ci } 44062306a36Sopenharmony_ci if (uml_tap_enable_vnet_headers(vp->fds->tx_fd)) 44162306a36Sopenharmony_ci return 0; 44262306a36Sopenharmony_ci return -1; 44362306a36Sopenharmony_ci} 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_cistatic int build_tap_transport_data(struct vector_private *vp) 44662306a36Sopenharmony_ci{ 44762306a36Sopenharmony_ci /* "Pure" tap uses the same fd for rx and tx */ 44862306a36Sopenharmony_ci if (uml_tap_enable_vnet_headers(vp->fds->tx_fd)) { 44962306a36Sopenharmony_ci vp->form_header = &raw_form_header; 45062306a36Sopenharmony_ci vp->verify_header = &raw_verify_header; 45162306a36Sopenharmony_ci vp->header_size = sizeof(struct virtio_net_hdr); 45262306a36Sopenharmony_ci vp->rx_header_size = sizeof(struct virtio_net_hdr); 45362306a36Sopenharmony_ci vp->dev->hw_features |= 45462306a36Sopenharmony_ci (NETIF_F_TSO | NETIF_F_GSO | NETIF_F_GRO); 45562306a36Sopenharmony_ci vp->dev->features |= 45662306a36Sopenharmony_ci (NETIF_F_RXCSUM | NETIF_F_HW_CSUM | 45762306a36Sopenharmony_ci NETIF_F_TSO | NETIF_F_GSO | NETIF_F_GRO); 45862306a36Sopenharmony_ci netdev_info( 45962306a36Sopenharmony_ci vp->dev, 46062306a36Sopenharmony_ci "tap: using vnet headers for tso and tx/rx checksum" 46162306a36Sopenharmony_ci ); 46262306a36Sopenharmony_ci return 0; 46362306a36Sopenharmony_ci } 46462306a36Sopenharmony_ci return -1; 46562306a36Sopenharmony_ci} 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_cistatic int build_bess_transport_data(struct vector_private *vp) 46962306a36Sopenharmony_ci{ 47062306a36Sopenharmony_ci vp->form_header = NULL; 47162306a36Sopenharmony_ci vp->verify_header = NULL; 47262306a36Sopenharmony_ci vp->header_size = 0; 47362306a36Sopenharmony_ci vp->rx_header_size = 0; 47462306a36Sopenharmony_ci return 0; 47562306a36Sopenharmony_ci} 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ciint build_transport_data(struct vector_private *vp) 47862306a36Sopenharmony_ci{ 47962306a36Sopenharmony_ci char *transport = uml_vector_fetch_arg(vp->parsed, "transport"); 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci if (strncmp(transport, TRANS_GRE, TRANS_GRE_LEN) == 0) 48262306a36Sopenharmony_ci return build_gre_transport_data(vp); 48362306a36Sopenharmony_ci if (strncmp(transport, TRANS_L2TPV3, TRANS_L2TPV3_LEN) == 0) 48462306a36Sopenharmony_ci return build_l2tpv3_transport_data(vp); 48562306a36Sopenharmony_ci if (strncmp(transport, TRANS_RAW, TRANS_RAW_LEN) == 0) 48662306a36Sopenharmony_ci return build_raw_transport_data(vp); 48762306a36Sopenharmony_ci if (strncmp(transport, TRANS_TAP, TRANS_TAP_LEN) == 0) 48862306a36Sopenharmony_ci return build_tap_transport_data(vp); 48962306a36Sopenharmony_ci if (strncmp(transport, TRANS_HYBRID, TRANS_HYBRID_LEN) == 0) 49062306a36Sopenharmony_ci return build_hybrid_transport_data(vp); 49162306a36Sopenharmony_ci if (strncmp(transport, TRANS_BESS, TRANS_BESS_LEN) == 0) 49262306a36Sopenharmony_ci return build_bess_transport_data(vp); 49362306a36Sopenharmony_ci return 0; 49462306a36Sopenharmony_ci} 49562306a36Sopenharmony_ci 496