at v4.13 2.9 kB view raw
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 */