linux/include/linux/virtio_net.h
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0 */
   2#ifndef _LINUX_VIRTIO_NET_H
   3#define _LINUX_VIRTIO_NET_H
   4
   5#include <linux/if_vlan.h>
   6#include <uapi/linux/virtio_net.h>
   7
   8static inline int virtio_net_hdr_set_proto(struct sk_buff *skb,
   9                                           const struct virtio_net_hdr *hdr)
  10{
  11        switch (hdr->gso_type & ~VIRTIO_NET_HDR_GSO_ECN) {
  12        case VIRTIO_NET_HDR_GSO_TCPV4:
  13        case VIRTIO_NET_HDR_GSO_UDP:
  14                skb->protocol = cpu_to_be16(ETH_P_IP);
  15                break;
  16        case VIRTIO_NET_HDR_GSO_TCPV6:
  17                skb->protocol = cpu_to_be16(ETH_P_IPV6);
  18                break;
  19        default:
  20                return -EINVAL;
  21        }
  22
  23        return 0;
  24}
  25
  26static inline int virtio_net_hdr_to_skb(struct sk_buff *skb,
  27                                        const struct virtio_net_hdr *hdr,
  28                                        bool little_endian)
  29{
  30        unsigned int gso_type = 0;
  31
  32        if (hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) {
  33                switch (hdr->gso_type & ~VIRTIO_NET_HDR_GSO_ECN) {
  34                case VIRTIO_NET_HDR_GSO_TCPV4:
  35                        gso_type = SKB_GSO_TCPV4;
  36                        break;
  37                case VIRTIO_NET_HDR_GSO_TCPV6:
  38                        gso_type = SKB_GSO_TCPV6;
  39                        break;
  40                case VIRTIO_NET_HDR_GSO_UDP:
  41                        gso_type = SKB_GSO_UDP;
  42                        break;
  43                default:
  44                        return -EINVAL;
  45                }
  46
  47                if (hdr->gso_type & VIRTIO_NET_HDR_GSO_ECN)
  48                        gso_type |= SKB_GSO_TCP_ECN;
  49
  50                if (hdr->gso_size == 0)
  51                        return -EINVAL;
  52        }
  53
  54        if (hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
  55                u16 start = __virtio16_to_cpu(little_endian, hdr->csum_start);
  56                u16 off = __virtio16_to_cpu(little_endian, hdr->csum_offset);
  57
  58                if (!skb_partial_csum_set(skb, start, off))
  59                        return -EINVAL;
  60        }
  61
  62        if (hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) {
  63                u16 gso_size = __virtio16_to_cpu(little_endian, hdr->gso_size);
  64
  65                skb_shinfo(skb)->gso_size = gso_size;
  66                skb_shinfo(skb)->gso_type = gso_type;
  67
  68                /* Header must be checked, and gso_segs computed. */
  69                skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY;
  70                skb_shinfo(skb)->gso_segs = 0;
  71        }
  72
  73        return 0;
  74}
  75
  76static inline int virtio_net_hdr_from_skb(const struct sk_buff *skb,
  77                                          struct virtio_net_hdr *hdr,
  78                                          bool little_endian,
  79                                          bool has_data_valid,
  80                                          int vlan_hlen)
  81{
  82        memset(hdr, 0, sizeof(*hdr));   /* no info leak */
  83
  84        if (skb_is_gso(skb)) {
  85                struct skb_shared_info *sinfo = skb_shinfo(skb);
  86
  87                /* This is a hint as to how much should be linear. */
  88                hdr->hdr_len = __cpu_to_virtio16(little_endian,
  89                                                 skb_headlen(skb));
  90                hdr->gso_size = __cpu_to_virtio16(little_endian,
  91                                                  sinfo->gso_size);
  92                if (sinfo->gso_type & SKB_GSO_TCPV4)
  93                        hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
  94                else if (sinfo->gso_type & SKB_GSO_TCPV6)
  95                        hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
  96                else
  97                        return -EINVAL;
  98                if (sinfo->gso_type & SKB_GSO_TCP_ECN)
  99                        hdr->gso_type |= VIRTIO_NET_HDR_GSO_ECN;
 100        } else
 101                hdr->gso_type = VIRTIO_NET_HDR_GSO_NONE;
 102
 103        if (skb->ip_summed == CHECKSUM_PARTIAL) {
 104                hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
 105                hdr->csum_start = __cpu_to_virtio16(little_endian,
 106                        skb_checksum_start_offset(skb) + vlan_hlen);
 107                hdr->csum_offset = __cpu_to_virtio16(little_endian,
 108                                skb->csum_offset);
 109        } else if (has_data_valid &&
 110                   skb->ip_summed == CHECKSUM_UNNECESSARY) {
 111                hdr->flags = VIRTIO_NET_HDR_F_DATA_VALID;
 112        } /* else everything is zero */
 113
 114        return 0;
 115}
 116
 117#endif /* _LINUX_VIRTIO_NET_H */
 118