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