Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Linux/arch/um/drivers/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 11 kB image not shown  

Quelle  vector_transports.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (C) 2017 - Cambridge Greys Limited
 * Copyright (C) 2011 - 2014 Cisco Systems Inc
 */


#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;
}

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;
}

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;
}

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;
}

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;
}

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;
}

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;
}

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;
}

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;
}

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;
}

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;
}

static int build_hybrid_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 hybrid: 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;
}

static int build_tap_transport_data(struct vector_private *vp)
{
 /* "Pure" tap uses the same fd for rx and tx */
 if (uml_tap_enable_vnet_headers(vp->fds->tx_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: using vnet headers for tso and tx/rx checksum"
  );
  return 0;
 }
 return -1;
}


static int build_bess_transport_data(struct vector_private *vp)
{
 vp->form_header = NULL;
 vp->verify_header = NULL;
 vp->header_size = 0;
 vp->rx_header_size = 0;
 return 0;
}

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);
 if (strncmp(transport, TRANS_HYBRID, TRANS_HYBRID_LEN) == 0)
  return build_hybrid_transport_data(vp);
 if (strncmp(transport, TRANS_BESS, TRANS_BESS_LEN) == 0)
  return build_bess_transport_data(vp);
 return 0;
}


Messung V0.5
C=99 H=100 G=99

¤ Dauer der Verarbeitung: 0.1 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.