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