virtio_net.h 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. /* SPDX-License-Identifier: GPL-2.0 */
  2. #ifndef _LINUX_VIRTIO_NET_H
  3. #define _LINUX_VIRTIO_NET_H
  4. #include <linux/if_vlan.h>
  5. #include <uapi/linux/tcp.h>
  6. #include <uapi/linux/udp.h>
  7. #include <uapi/linux/virtio_net.h>
  8. static inline bool virtio_net_hdr_match_proto(__be16 protocol, __u8 gso_type)
  9. {
  10. switch (gso_type & ~VIRTIO_NET_HDR_GSO_ECN) {
  11. case VIRTIO_NET_HDR_GSO_TCPV4:
  12. return protocol == cpu_to_be16(ETH_P_IP);
  13. case VIRTIO_NET_HDR_GSO_TCPV6:
  14. return protocol == cpu_to_be16(ETH_P_IPV6);
  15. case VIRTIO_NET_HDR_GSO_UDP:
  16. return protocol == cpu_to_be16(ETH_P_IP) ||
  17. protocol == cpu_to_be16(ETH_P_IPV6);
  18. default:
  19. return false;
  20. }
  21. }
  22. static inline int virtio_net_hdr_set_proto(struct sk_buff *skb,
  23. const struct virtio_net_hdr *hdr)
  24. {
  25. if (skb->protocol)
  26. return 0;
  27. switch (hdr->gso_type & ~VIRTIO_NET_HDR_GSO_ECN) {
  28. case VIRTIO_NET_HDR_GSO_TCPV4:
  29. case VIRTIO_NET_HDR_GSO_UDP:
  30. skb->protocol = cpu_to_be16(ETH_P_IP);
  31. break;
  32. case VIRTIO_NET_HDR_GSO_TCPV6:
  33. skb->protocol = cpu_to_be16(ETH_P_IPV6);
  34. break;
  35. default:
  36. return -EINVAL;
  37. }
  38. return 0;
  39. }
  40. static inline int virtio_net_hdr_to_skb(struct sk_buff *skb,
  41. const struct virtio_net_hdr *hdr,
  42. bool little_endian)
  43. {
  44. unsigned int gso_type = 0;
  45. unsigned int thlen = 0;
  46. unsigned int p_off = 0;
  47. unsigned int ip_proto;
  48. if (hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) {
  49. switch (hdr->gso_type & ~VIRTIO_NET_HDR_GSO_ECN) {
  50. case VIRTIO_NET_HDR_GSO_TCPV4:
  51. gso_type = SKB_GSO_TCPV4;
  52. ip_proto = IPPROTO_TCP;
  53. thlen = sizeof(struct tcphdr);
  54. break;
  55. case VIRTIO_NET_HDR_GSO_TCPV6:
  56. gso_type = SKB_GSO_TCPV6;
  57. ip_proto = IPPROTO_TCP;
  58. thlen = sizeof(struct tcphdr);
  59. break;
  60. case VIRTIO_NET_HDR_GSO_UDP:
  61. gso_type = SKB_GSO_UDP;
  62. ip_proto = IPPROTO_UDP;
  63. thlen = sizeof(struct udphdr);
  64. break;
  65. default:
  66. return -EINVAL;
  67. }
  68. if (hdr->gso_type & VIRTIO_NET_HDR_GSO_ECN)
  69. gso_type |= SKB_GSO_TCP_ECN;
  70. if (hdr->gso_size == 0)
  71. return -EINVAL;
  72. }
  73. skb_reset_mac_header(skb);
  74. if (hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
  75. u32 start = __virtio16_to_cpu(little_endian, hdr->csum_start);
  76. u32 off = __virtio16_to_cpu(little_endian, hdr->csum_offset);
  77. u32 needed = start + max_t(u32, thlen, off + sizeof(__sum16));
  78. if (!pskb_may_pull(skb, needed))
  79. return -EINVAL;
  80. if (!skb_partial_csum_set(skb, start, off))
  81. return -EINVAL;
  82. p_off = skb_transport_offset(skb) + thlen;
  83. if (!pskb_may_pull(skb, p_off))
  84. return -EINVAL;
  85. } else {
  86. /* gso packets without NEEDS_CSUM do not set transport_offset.
  87. * probe and drop if does not match one of the above types.
  88. */
  89. if (gso_type && skb->network_header) {
  90. struct flow_keys_basic keys;
  91. if (!skb->protocol) {
  92. __be16 protocol = dev_parse_header_protocol(skb);
  93. if (!protocol)
  94. virtio_net_hdr_set_proto(skb, hdr);
  95. else if (!virtio_net_hdr_match_proto(protocol, hdr->gso_type))
  96. return -EINVAL;
  97. else
  98. skb->protocol = protocol;
  99. }
  100. retry:
  101. if (!skb_flow_dissect_flow_keys_basic(NULL, skb, &keys,
  102. NULL, 0, 0, 0,
  103. 0)) {
  104. /* UFO does not specify ipv4 or 6: try both */
  105. if (gso_type & SKB_GSO_UDP &&
  106. skb->protocol == htons(ETH_P_IP)) {
  107. skb->protocol = htons(ETH_P_IPV6);
  108. goto retry;
  109. }
  110. return -EINVAL;
  111. }
  112. p_off = keys.control.thoff + thlen;
  113. if (!pskb_may_pull(skb, p_off) ||
  114. keys.basic.ip_proto != ip_proto)
  115. return -EINVAL;
  116. skb_set_transport_header(skb, keys.control.thoff);
  117. } else if (gso_type) {
  118. p_off = thlen;
  119. if (!pskb_may_pull(skb, p_off))
  120. return -EINVAL;
  121. }
  122. }
  123. if (hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) {
  124. u16 gso_size = __virtio16_to_cpu(little_endian, hdr->gso_size);
  125. unsigned int nh_off = p_off;
  126. struct skb_shared_info *shinfo = skb_shinfo(skb);
  127. /* UFO may not include transport header in gso_size. */
  128. if (gso_type & SKB_GSO_UDP)
  129. nh_off -= thlen;
  130. /* Too small packets are not really GSO ones. */
  131. if (skb->len - nh_off > gso_size) {
  132. shinfo->gso_size = gso_size;
  133. shinfo->gso_type = gso_type;
  134. /* Header must be checked, and gso_segs computed. */
  135. shinfo->gso_type |= SKB_GSO_DODGY;
  136. shinfo->gso_segs = 0;
  137. }
  138. }
  139. return 0;
  140. }
  141. static inline int virtio_net_hdr_from_skb(const struct sk_buff *skb,
  142. struct virtio_net_hdr *hdr,
  143. bool little_endian,
  144. bool has_data_valid,
  145. int vlan_hlen)
  146. {
  147. memset(hdr, 0, sizeof(*hdr)); /* no info leak */
  148. if (skb_is_gso(skb)) {
  149. struct skb_shared_info *sinfo = skb_shinfo(skb);
  150. /* This is a hint as to how much should be linear. */
  151. hdr->hdr_len = __cpu_to_virtio16(little_endian,
  152. skb_headlen(skb));
  153. hdr->gso_size = __cpu_to_virtio16(little_endian,
  154. sinfo->gso_size);
  155. if (sinfo->gso_type & SKB_GSO_TCPV4)
  156. hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
  157. else if (sinfo->gso_type & SKB_GSO_TCPV6)
  158. hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
  159. else
  160. return -EINVAL;
  161. if (sinfo->gso_type & SKB_GSO_TCP_ECN)
  162. hdr->gso_type |= VIRTIO_NET_HDR_GSO_ECN;
  163. } else
  164. hdr->gso_type = VIRTIO_NET_HDR_GSO_NONE;
  165. if (skb->ip_summed == CHECKSUM_PARTIAL) {
  166. hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
  167. hdr->csum_start = __cpu_to_virtio16(little_endian,
  168. skb_checksum_start_offset(skb) + vlan_hlen);
  169. hdr->csum_offset = __cpu_to_virtio16(little_endian,
  170. skb->csum_offset);
  171. } else if (has_data_valid &&
  172. skb->ip_summed == CHECKSUM_UNNECESSARY) {
  173. hdr->flags = VIRTIO_NET_HDR_F_DATA_VALID;
  174. } /* else everything is zero */
  175. return 0;
  176. }
  177. #endif /* _LINUX_VIRTIO_NET_H */