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 <linux/ip.h> 7 #include <linux/ipv6.h> 8 #include <linux/udp.h> 9 #include <uapi/linux/tcp.h> 10 #include <uapi/linux/virtio_net.h> 11 12 static inline bool virtio_net_hdr_match_proto(__be16 protocol, __u8 gso_type) 13 { 14 switch (gso_type & ~VIRTIO_NET_HDR_GSO_ECN) { 15 case VIRTIO_NET_HDR_GSO_TCPV4: 16 return protocol == cpu_to_be16(ETH_P_IP); 17 case VIRTIO_NET_HDR_GSO_TCPV6: 18 return protocol == cpu_to_be16(ETH_P_IPV6); 19 case VIRTIO_NET_HDR_GSO_UDP: 20 case VIRTIO_NET_HDR_GSO_UDP_L4: 21 return protocol == cpu_to_be16(ETH_P_IP) || 22 protocol == cpu_to_be16(ETH_P_IPV6); 23 default: 24 return false; 25 } 26 } 27 28 static inline int virtio_net_hdr_set_proto(struct sk_buff *skb, 29 const struct virtio_net_hdr *hdr) 30 { 31 if (skb->protocol) 32 return 0; 33 34 switch (hdr->gso_type & ~VIRTIO_NET_HDR_GSO_ECN) { 35 case VIRTIO_NET_HDR_GSO_TCPV4: 36 case VIRTIO_NET_HDR_GSO_UDP: 37 case VIRTIO_NET_HDR_GSO_UDP_L4: 38 skb->protocol = cpu_to_be16(ETH_P_IP); 39 break; 40 case VIRTIO_NET_HDR_GSO_TCPV6: 41 skb->protocol = cpu_to_be16(ETH_P_IPV6); 42 break; 43 default: 44 return -EINVAL; 45 } 46 47 return 0; 48 } 49 50 static inline int virtio_net_hdr_to_skb(struct sk_buff *skb, 51 const struct virtio_net_hdr *hdr, 52 bool little_endian) 53 { 54 unsigned int nh_min_len = sizeof(struct iphdr); 55 unsigned int gso_type = 0; 56 unsigned int thlen = 0; 57 unsigned int p_off = 0; 58 unsigned int ip_proto; 59 60 if (hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) { 61 switch (hdr->gso_type & ~VIRTIO_NET_HDR_GSO_ECN) { 62 case VIRTIO_NET_HDR_GSO_TCPV4: 63 gso_type = SKB_GSO_TCPV4; 64 ip_proto = IPPROTO_TCP; 65 thlen = sizeof(struct tcphdr); 66 break; 67 case VIRTIO_NET_HDR_GSO_TCPV6: 68 gso_type = SKB_GSO_TCPV6; 69 ip_proto = IPPROTO_TCP; 70 thlen = sizeof(struct tcphdr); 71 nh_min_len = sizeof(struct ipv6hdr); 72 break; 73 case VIRTIO_NET_HDR_GSO_UDP: 74 gso_type = SKB_GSO_UDP; 75 ip_proto = IPPROTO_UDP; 76 thlen = sizeof(struct udphdr); 77 break; 78 case VIRTIO_NET_HDR_GSO_UDP_L4: 79 gso_type = SKB_GSO_UDP_L4; 80 ip_proto = IPPROTO_UDP; 81 thlen = sizeof(struct udphdr); 82 break; 83 default: 84 return -EINVAL; 85 } 86 87 if (hdr->gso_type & VIRTIO_NET_HDR_GSO_ECN) 88 gso_type |= SKB_GSO_TCP_ECN; 89 90 if (hdr->gso_size == 0) 91 return -EINVAL; 92 } 93 94 skb_reset_mac_header(skb); 95 96 if (hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) { 97 u32 start = __virtio16_to_cpu(little_endian, hdr->csum_start); 98 u32 off = __virtio16_to_cpu(little_endian, hdr->csum_offset); 99 u32 needed = start + max_t(u32, thlen, off + sizeof(__sum16)); 100 101 if (!pskb_may_pull(skb, needed)) 102 return -EINVAL; 103 104 if (!skb_partial_csum_set(skb, start, off)) 105 return -EINVAL; 106 107 nh_min_len = max_t(u32, nh_min_len, skb_transport_offset(skb)); 108 p_off = nh_min_len + thlen; 109 if (!pskb_may_pull(skb, p_off)) 110 return -EINVAL; 111 } else { 112 /* gso packets without NEEDS_CSUM do not set transport_offset. 113 * probe and drop if does not match one of the above types. 114 */ 115 if (gso_type && skb->network_header) { 116 struct flow_keys_basic keys; 117 118 if (!skb->protocol) { 119 __be16 protocol = dev_parse_header_protocol(skb); 120 121 if (!protocol) 122 virtio_net_hdr_set_proto(skb, hdr); 123 else if (!virtio_net_hdr_match_proto(protocol, hdr->gso_type)) 124 return -EINVAL; 125 else 126 skb->protocol = protocol; 127 } 128 retry: 129 if (!skb_flow_dissect_flow_keys_basic(NULL, skb, &keys, 130 NULL, 0, 0, 0, 131 0)) { 132 /* UFO does not specify ipv4 or 6: try both */ 133 if (gso_type & SKB_GSO_UDP && 134 skb->protocol == htons(ETH_P_IP)) { 135 skb->protocol = htons(ETH_P_IPV6); 136 goto retry; 137 } 138 return -EINVAL; 139 } 140 141 p_off = keys.control.thoff + thlen; 142 if (!pskb_may_pull(skb, p_off) || 143 keys.basic.ip_proto != ip_proto) 144 return -EINVAL; 145 146 skb_set_transport_header(skb, keys.control.thoff); 147 } else if (gso_type) { 148 p_off = nh_min_len + thlen; 149 if (!pskb_may_pull(skb, p_off)) 150 return -EINVAL; 151 } 152 } 153 154 if (hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) { 155 u16 gso_size = __virtio16_to_cpu(little_endian, hdr->gso_size); 156 unsigned int nh_off = p_off; 157 struct skb_shared_info *shinfo = skb_shinfo(skb); 158 159 switch (gso_type & ~SKB_GSO_TCP_ECN) { 160 case SKB_GSO_UDP: 161 /* UFO may not include transport header in gso_size. */ 162 nh_off -= thlen; 163 break; 164 case SKB_GSO_UDP_L4: 165 if (!(hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM)) 166 return -EINVAL; 167 if (skb->csum_offset != offsetof(struct udphdr, check)) 168 return -EINVAL; 169 if (skb->len - p_off > gso_size * UDP_MAX_SEGMENTS) 170 return -EINVAL; 171 if (gso_type != SKB_GSO_UDP_L4) 172 return -EINVAL; 173 break; 174 case SKB_GSO_TCPV4: 175 case SKB_GSO_TCPV6: 176 if (skb->csum_offset != offsetof(struct tcphdr, check)) 177 return -EINVAL; 178 break; 179 } 180 181 /* Kernel has a special handling for GSO_BY_FRAGS. */ 182 if (gso_size == GSO_BY_FRAGS) 183 return -EINVAL; 184 185 /* Too small packets are not really GSO ones. */ 186 if (skb->len - nh_off > gso_size) { 187 shinfo->gso_size = gso_size; 188 shinfo->gso_type = gso_type; 189 190 /* Header must be checked, and gso_segs computed. */ 191 shinfo->gso_type |= SKB_GSO_DODGY; 192 shinfo->gso_segs = 0; 193 } 194 } 195 196 return 0; 197 } 198 199 static inline int virtio_net_hdr_from_skb(const struct sk_buff *skb, 200 struct virtio_net_hdr *hdr, 201 bool little_endian, 202 bool has_data_valid, 203 int vlan_hlen) 204 { 205 memset(hdr, 0, sizeof(*hdr)); /* no info leak */ 206 207 if (skb_is_gso(skb)) { 208 struct skb_shared_info *sinfo = skb_shinfo(skb); 209 210 /* This is a hint as to how much should be linear. */ 211 hdr->hdr_len = __cpu_to_virtio16(little_endian, 212 skb_headlen(skb)); 213 hdr->gso_size = __cpu_to_virtio16(little_endian, 214 sinfo->gso_size); 215 if (sinfo->gso_type & SKB_GSO_TCPV4) 216 hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4; 217 else if (sinfo->gso_type & SKB_GSO_TCPV6) 218 hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV6; 219 else if (sinfo->gso_type & SKB_GSO_UDP_L4) 220 hdr->gso_type = VIRTIO_NET_HDR_GSO_UDP_L4; 221 else 222 return -EINVAL; 223 if (sinfo->gso_type & SKB_GSO_TCP_ECN) 224 hdr->gso_type |= VIRTIO_NET_HDR_GSO_ECN; 225 } else 226 hdr->gso_type = VIRTIO_NET_HDR_GSO_NONE; 227 228 if (skb->ip_summed == CHECKSUM_PARTIAL) { 229 hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM; 230 hdr->csum_start = __cpu_to_virtio16(little_endian, 231 skb_checksum_start_offset(skb) + vlan_hlen); 232 hdr->csum_offset = __cpu_to_virtio16(little_endian, 233 skb->csum_offset); 234 } else if (has_data_valid && 235 skb->ip_summed == CHECKSUM_UNNECESSARY) { 236 hdr->flags = VIRTIO_NET_HDR_F_DATA_VALID; 237 } /* else everything is zero */ 238 239 return 0; 240 } 241 242 #endif /* _LINUX_VIRTIO_NET_H */ 243