cregit-Linux how code gets into the kernel

Release 4.18 arch/um/drivers/vector_transports.c

Directory: arch/um/drivers
/*
 * Copyright (C) 2017 - Cambridge Greys Limited
 * Copyright (C) 2011 - 2014 Cisco Systems Inc
 * Licensed under the GPL.
 */

#include <linux/etherdevice.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/slab.h>
#include <asm/byteorder.h>
#include <uapi/linux/ip.h>
#include <uapi/linux/virtio_net.h>
#include <linux/virtio_net.h>
#include <linux/virtio_byteorder.h>
#include <linux/netdev_features.h>
#include "vector_user.h"
#include "vector_kern.h"


#define GOOD_LINEAR 512

#define GSO_ERROR "Incoming GSO frames and GRO disabled on the interface"


struct gre_minimal_header {
	
uint16_t header;
	
uint16_t arptype;
};



struct uml_gre_data {
	
uint32_t rx_key;
	
uint32_t tx_key;
	
uint32_t sequence;

	
bool ipv6;
	
bool has_sequence;
	
bool pin_sequence;
	
bool checksum;
	
bool key;
	
struct gre_minimal_header expected_header;

	
uint32_t checksum_offset;
	
uint32_t key_offset;
	
uint32_t sequence_offset;

};


struct uml_l2tpv3_data {
	
uint64_t rx_cookie;
	
uint64_t tx_cookie;
	
uint64_t rx_session;
	
uint64_t tx_session;
	
uint32_t counter;

	
bool udp;
	
bool ipv6;
	
bool has_counter;
	
bool pin_counter;
	
bool cookie;
	
bool cookie_is_64;

	
uint32_t cookie_offset;
	
uint32_t session_offset;
	
uint32_t counter_offset;
};


static int l2tpv3_form_header(uint8_t *header, struct sk_buff *skb, struct vector_private *vp) { struct uml_l2tpv3_data *td = vp->transport_data; uint32_t *counter; if (td->udp) *(uint32_t *) header = cpu_to_be32(L2TPV3_DATA_PACKET); (*(uint32_t *) (header + td->session_offset)) = td->tx_session; if (td->cookie) { if (td->cookie_is_64) (*(uint64_t *)(header + td->cookie_offset)) = td->tx_cookie; else (*(uint32_t *)(header + td->cookie_offset)) = td->tx_cookie; } if (td->has_counter) { counter = (uint32_t *)(header + td->counter_offset); if (td->pin_counter) { *counter = 0; } else { td->counter++; *counter = cpu_to_be32(td->counter); } } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Anton Ivanov179100.00%1100.00%
Total179100.00%1100.00%


static int gre_form_header(uint8_t *header, struct sk_buff *skb, struct vector_private *vp) { struct uml_gre_data *td = vp->transport_data; uint32_t *sequence; *((uint32_t *) header) = *((uint32_t *) &td->expected_header); if (td->key) (*(uint32_t *) (header + td->key_offset)) = td->tx_key; if (td->has_sequence) { sequence = (uint32_t *)(header + td->sequence_offset); if (td->pin_sequence) *sequence = 0; else *sequence = cpu_to_be32(++td->sequence); } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Anton Ivanov127100.00%1100.00%
Total127100.00%1100.00%


static int raw_form_header(uint8_t *header, struct sk_buff *skb, struct vector_private *vp) { struct virtio_net_hdr *vheader = (struct virtio_net_hdr *) header; virtio_net_hdr_from_skb( skb, vheader, virtio_legacy_is_little_endian(), false, 0 ); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Anton Ivanov4795.92%150.00%
Willem de Bruijn24.08%150.00%
Total49100.00%2100.00%


static int l2tpv3_verify_header( uint8_t *header, struct sk_buff *skb, struct vector_private *vp) { struct uml_l2tpv3_data *td = vp->transport_data; uint32_t *session; uint64_t cookie; if ((!td->udp) && (!td->ipv6)) header += sizeof(struct iphdr) /* fix for ipv4 raw */; /* we do not do a strict check for "data" packets as per * the RFC spec because the pure IP spec does not have * that anyway. */ if (td->cookie) { if (td->cookie_is_64) cookie = *(uint64_t *)(header + td->cookie_offset); else cookie = *(uint32_t *)(header + td->cookie_offset); if (cookie != td->rx_cookie) { if (net_ratelimit()) netdev_err(vp->dev, "uml_l2tpv3: unknown cookie id"); return -1; } } session = (uint32_t *) (header + td->session_offset); if (*session != td->rx_session) { if (net_ratelimit()) netdev_err(vp->dev, "uml_l2tpv3: session mismatch"); return -1; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Anton Ivanov181100.00%1100.00%
Total181100.00%1100.00%


static int gre_verify_header( uint8_t *header, struct sk_buff *skb, struct vector_private *vp) { uint32_t key; struct uml_gre_data *td = vp->transport_data; if (!td->ipv6) header += sizeof(struct iphdr) /* fix for ipv4 raw */; if (*((uint32_t *) header) != *((uint32_t *) &td->expected_header)) { if (net_ratelimit()) netdev_err(vp->dev, "header type disagreement, expecting %0x, got %0x", *((uint32_t *) &td->expected_header), *((uint32_t *) header) ); return -1; } if (td->key) { key = (*(uint32_t *)(header + td->key_offset)); if (key != td->rx_key) { if (net_ratelimit()) netdev_err(vp->dev, "unknown key id %0x, expecting %0x", key, td->rx_key); return -1; } } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Anton Ivanov174100.00%1100.00%
Total174100.00%1100.00%


static int raw_verify_header( uint8_t *header, struct sk_buff *skb, struct vector_private *vp) { struct virtio_net_hdr *vheader = (struct virtio_net_hdr *) header; if ((vheader->gso_type != VIRTIO_NET_HDR_GSO_NONE) && (vp->req_size != 65536)) { if (net_ratelimit()) netdev_err( vp->dev, GSO_ERROR ); } if ((vheader->flags & VIRTIO_NET_HDR_F_DATA_VALID) > 0) return 1; virtio_net_hdr_to_skb(skb, vheader, virtio_legacy_is_little_endian()); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Anton Ivanov94100.00%1100.00%
Total94100.00%1100.00%


static bool get_uint_param( struct arglist *def, char *param, unsigned int *result) { char *arg = uml_vector_fetch_arg(def, param); if (arg != NULL) { if (kstrtoint(arg, 0, result) == 0) return true; } return false; }

Contributors

PersonTokensPropCommitsCommitProp
Anton Ivanov58100.00%1100.00%
Total58100.00%1100.00%


static bool get_ulong_param( struct arglist *def, char *param, unsigned long *result) { char *arg = uml_vector_fetch_arg(def, param); if (arg != NULL) { if (kstrtoul(arg, 0, result) == 0) return true; return true; } return false; }

Contributors

PersonTokensPropCommitsCommitProp
Anton Ivanov61100.00%1100.00%
Total61100.00%1100.00%


static int build_gre_transport_data(struct vector_private *vp) { struct uml_gre_data *td; int temp_int; int temp_rx; int temp_tx; vp->transport_data = kmalloc(sizeof(struct uml_gre_data), GFP_KERNEL); if (vp->transport_data == NULL) return -ENOMEM; td = vp->transport_data; td->sequence = 0; td->expected_header.arptype = GRE_IRB; td->expected_header.header = 0; vp->form_header = &gre_form_header; vp->verify_header = &gre_verify_header; vp->header_size = 4; td->key_offset = 4; td->sequence_offset = 4; td->checksum_offset = 4; td->ipv6 = false; if (get_uint_param(vp->parsed, "v6", &temp_int)) { if (temp_int > 0) td->ipv6 = true; } td->key = false; if (get_uint_param(vp->parsed, "rx_key", &temp_rx)) { if (get_uint_param(vp->parsed, "tx_key", &temp_tx)) { td->key = true; td->expected_header.header |= GRE_MODE_KEY; td->rx_key = cpu_to_be32(temp_rx); td->tx_key = cpu_to_be32(temp_tx); vp->header_size += 4; td->sequence_offset += 4; } else { return -EINVAL; } } td->sequence = false; if (get_uint_param(vp->parsed, "sequence", &temp_int)) { if (temp_int > 0) { vp->header_size += 4; td->has_sequence = true; td->expected_header.header |= GRE_MODE_SEQUENCE; if (get_uint_param( vp->parsed, "pin_sequence", &temp_int)) { if (temp_int > 0) td->pin_sequence = true; } } } vp->rx_header_size = vp->header_size; if (!td->ipv6) vp->rx_header_size += sizeof(struct iphdr); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Anton Ivanov347100.00%1100.00%
Total347100.00%1100.00%


static int build_l2tpv3_transport_data(struct vector_private *vp) { struct uml_l2tpv3_data *td; int temp_int, temp_rxs, temp_txs; unsigned long temp_rx; unsigned long temp_tx; vp->transport_data = kmalloc( sizeof(struct uml_l2tpv3_data), GFP_KERNEL); if (vp->transport_data == NULL) return -ENOMEM; td = vp->transport_data; vp->form_header = &l2tpv3_form_header; vp->verify_header = &l2tpv3_verify_header; td->counter = 0; vp->header_size = 4; td->session_offset = 0; td->cookie_offset = 4; td->counter_offset = 4; td->ipv6 = false; if (get_uint_param(vp->parsed, "v6", &temp_int)) { if (temp_int > 0) td->ipv6 = true; } if (get_uint_param(vp->parsed, "rx_session", &temp_rxs)) { if (get_uint_param(vp->parsed, "tx_session", &temp_txs)) { td->tx_session = cpu_to_be32(temp_txs); td->rx_session = cpu_to_be32(temp_rxs); } else { return -EINVAL; } } else { return -EINVAL; } td->cookie_is_64 = false; if (get_uint_param(vp->parsed, "cookie64", &temp_int)) { if (temp_int > 0) td->cookie_is_64 = true; } td->cookie = false; if (get_ulong_param(vp->parsed, "rx_cookie", &temp_rx)) { if (get_ulong_param(vp->parsed, "tx_cookie", &temp_tx)) { td->cookie = true; if (td->cookie_is_64) { td->rx_cookie = cpu_to_be64(temp_rx); td->tx_cookie = cpu_to_be64(temp_tx); vp->header_size += 8; td->counter_offset += 8; } else { td->rx_cookie = cpu_to_be32(temp_rx); td->tx_cookie = cpu_to_be32(temp_tx); vp->header_size += 4; td->counter_offset += 4; } } else { return -EINVAL; } } td->has_counter = false; if (get_uint_param(vp->parsed, "counter", &temp_int)) { if (temp_int > 0) { td->has_counter = true; vp->header_size += 4; if (get_uint_param( vp->parsed, "pin_counter", &temp_int)) { if (temp_int > 0) td->pin_counter = true; } } } if (get_uint_param(vp->parsed, "udp", &temp_int)) { if (temp_int > 0) { td->udp = true; vp->header_size += 4; td->counter_offset += 4; td->session_offset += 4; td->cookie_offset += 4; } } vp->rx_header_size = vp->header_size; if ((!td->ipv6) && (!td->udp)) vp->rx_header_size += sizeof(struct iphdr); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Anton Ivanov523100.00%1100.00%
Total523100.00%1100.00%


static int build_raw_transport_data(struct vector_private *vp) { if (uml_raw_enable_vnet_headers(vp->fds->rx_fd)) { if (!uml_raw_enable_vnet_headers(vp->fds->tx_fd)) return -1; vp->form_header = &raw_form_header; vp->verify_header = &raw_verify_header; vp->header_size = sizeof(struct virtio_net_hdr); vp->rx_header_size = sizeof(struct virtio_net_hdr); vp->dev->hw_features |= (NETIF_F_TSO | NETIF_F_GRO); vp->dev->features |= (NETIF_F_RXCSUM | NETIF_F_HW_CSUM | NETIF_F_TSO | NETIF_F_GRO); netdev_info( vp->dev, "raw: using vnet headers for tso and tx/rx checksum" ); } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Anton Ivanov114100.00%1100.00%
Total114100.00%1100.00%


static int build_tap_transport_data(struct vector_private *vp) { if (uml_raw_enable_vnet_headers(vp->fds->rx_fd)) { vp->form_header = &raw_form_header; vp->verify_header = &raw_verify_header; vp->header_size = sizeof(struct virtio_net_hdr); vp->rx_header_size = sizeof(struct virtio_net_hdr); vp->dev->hw_features |= (NETIF_F_TSO | NETIF_F_GSO | NETIF_F_GRO); vp->dev->features |= (NETIF_F_RXCSUM | NETIF_F_HW_CSUM | NETIF_F_TSO | NETIF_F_GSO | NETIF_F_GRO); netdev_info( vp->dev, "tap/raw: using vnet headers for tso and tx/rx checksum" ); } else { return 0; /* do not try to enable tap too if raw failed */ } if (uml_tap_enable_vnet_headers(vp->fds->tx_fd)) return 0; return -1; }

Contributors

PersonTokensPropCommitsCommitProp
Anton Ivanov124100.00%1100.00%
Total124100.00%1100.00%


int build_transport_data(struct vector_private *vp) { char *transport = uml_vector_fetch_arg(vp->parsed, "transport"); if (strncmp(transport, TRANS_GRE, TRANS_GRE_LEN) == 0) return build_gre_transport_data(vp); if (strncmp(transport, TRANS_L2TPV3, TRANS_L2TPV3_LEN) == 0) return build_l2tpv3_transport_data(vp); if (strncmp(transport, TRANS_RAW, TRANS_RAW_LEN) == 0) return build_raw_transport_data(vp); if (strncmp(transport, TRANS_TAP, TRANS_TAP_LEN) == 0) return build_tap_transport_data(vp); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Anton Ivanov102100.00%1100.00%
Total102100.00%1100.00%


Overall Contributors

PersonTokensPropCommitsCommitProp
Anton Ivanov227699.91%150.00%
Willem de Bruijn20.09%150.00%
Total2278100.00%2100.00%
Directory: arch/um/drivers
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.