net_rx_pkt.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639
  1. /*
  2. * QEMU RX packets abstractions
  3. *
  4. * Copyright (c) 2012 Ravello Systems LTD (http://ravellosystems.com)
  5. *
  6. * Developed by Daynix Computing LTD (http://www.daynix.com)
  7. *
  8. * Authors:
  9. * Dmitry Fleytman <dmitry@daynix.com>
  10. * Tamir Shomer <tamirs@daynix.com>
  11. * Yan Vugenfirer <yan@daynix.com>
  12. *
  13. * This work is licensed under the terms of the GNU GPL, version 2 or later.
  14. * See the COPYING file in the top-level directory.
  15. *
  16. */
  17. #include "qemu/osdep.h"
  18. #include "trace.h"
  19. #include "net_rx_pkt.h"
  20. #include "net/checksum.h"
  21. #include "net/tap.h"
  22. struct NetRxPkt {
  23. struct virtio_net_hdr virt_hdr;
  24. uint8_t ehdr_buf[sizeof(struct eth_header) + sizeof(struct vlan_header)];
  25. struct iovec *vec;
  26. uint16_t vec_len_total;
  27. uint16_t vec_len;
  28. uint32_t tot_len;
  29. uint16_t tci;
  30. size_t ehdr_buf_len;
  31. eth_pkt_types_e packet_type;
  32. /* Analysis results */
  33. bool hasip4;
  34. bool hasip6;
  35. size_t l3hdr_off;
  36. size_t l4hdr_off;
  37. size_t l5hdr_off;
  38. eth_ip6_hdr_info ip6hdr_info;
  39. eth_ip4_hdr_info ip4hdr_info;
  40. eth_l4_hdr_info l4hdr_info;
  41. };
  42. void net_rx_pkt_init(struct NetRxPkt **pkt)
  43. {
  44. struct NetRxPkt *p = g_malloc0(sizeof *p);
  45. p->vec = NULL;
  46. p->vec_len_total = 0;
  47. *pkt = p;
  48. }
  49. void net_rx_pkt_uninit(struct NetRxPkt *pkt)
  50. {
  51. if (pkt->vec_len_total != 0) {
  52. g_free(pkt->vec);
  53. }
  54. g_free(pkt);
  55. }
  56. struct virtio_net_hdr *net_rx_pkt_get_vhdr(struct NetRxPkt *pkt)
  57. {
  58. assert(pkt);
  59. return &pkt->virt_hdr;
  60. }
  61. static inline void
  62. net_rx_pkt_iovec_realloc(struct NetRxPkt *pkt,
  63. int new_iov_len)
  64. {
  65. if (pkt->vec_len_total < new_iov_len) {
  66. g_free(pkt->vec);
  67. pkt->vec = g_malloc(sizeof(*pkt->vec) * new_iov_len);
  68. pkt->vec_len_total = new_iov_len;
  69. }
  70. }
  71. static void
  72. net_rx_pkt_pull_data(struct NetRxPkt *pkt,
  73. const struct iovec *iov, int iovcnt,
  74. size_t ploff)
  75. {
  76. uint32_t pllen = iov_size(iov, iovcnt) - ploff;
  77. if (pkt->ehdr_buf_len) {
  78. net_rx_pkt_iovec_realloc(pkt, iovcnt + 1);
  79. pkt->vec[0].iov_base = pkt->ehdr_buf;
  80. pkt->vec[0].iov_len = pkt->ehdr_buf_len;
  81. pkt->tot_len = pllen + pkt->ehdr_buf_len;
  82. pkt->vec_len = iov_copy(pkt->vec + 1, pkt->vec_len_total - 1,
  83. iov, iovcnt, ploff, pllen) + 1;
  84. } else {
  85. net_rx_pkt_iovec_realloc(pkt, iovcnt);
  86. pkt->tot_len = pllen;
  87. pkt->vec_len = iov_copy(pkt->vec, pkt->vec_len_total,
  88. iov, iovcnt, ploff, pkt->tot_len);
  89. }
  90. eth_get_protocols(pkt->vec, pkt->vec_len, 0, &pkt->hasip4, &pkt->hasip6,
  91. &pkt->l3hdr_off, &pkt->l4hdr_off, &pkt->l5hdr_off,
  92. &pkt->ip6hdr_info, &pkt->ip4hdr_info, &pkt->l4hdr_info);
  93. trace_net_rx_pkt_parsed(pkt->hasip4, pkt->hasip6, pkt->l4hdr_info.proto,
  94. pkt->l3hdr_off, pkt->l4hdr_off, pkt->l5hdr_off);
  95. }
  96. void net_rx_pkt_attach_iovec(struct NetRxPkt *pkt,
  97. const struct iovec *iov, int iovcnt,
  98. size_t iovoff, bool strip_vlan)
  99. {
  100. uint16_t tci = 0;
  101. uint16_t ploff = iovoff;
  102. assert(pkt);
  103. if (strip_vlan) {
  104. pkt->ehdr_buf_len = eth_strip_vlan(iov, iovcnt, iovoff, pkt->ehdr_buf,
  105. &ploff, &tci);
  106. } else {
  107. pkt->ehdr_buf_len = 0;
  108. }
  109. pkt->tci = tci;
  110. net_rx_pkt_pull_data(pkt, iov, iovcnt, ploff);
  111. }
  112. void net_rx_pkt_attach_iovec_ex(struct NetRxPkt *pkt,
  113. const struct iovec *iov, int iovcnt,
  114. size_t iovoff, bool strip_vlan,
  115. uint16_t vet)
  116. {
  117. uint16_t tci = 0;
  118. uint16_t ploff = iovoff;
  119. assert(pkt);
  120. if (strip_vlan) {
  121. pkt->ehdr_buf_len = eth_strip_vlan_ex(iov, iovcnt, iovoff, vet,
  122. pkt->ehdr_buf,
  123. &ploff, &tci);
  124. } else {
  125. pkt->ehdr_buf_len = 0;
  126. }
  127. pkt->tci = tci;
  128. net_rx_pkt_pull_data(pkt, iov, iovcnt, ploff);
  129. }
  130. void net_rx_pkt_dump(struct NetRxPkt *pkt)
  131. {
  132. #ifdef NET_RX_PKT_DEBUG
  133. assert(pkt);
  134. printf("RX PKT: tot_len: %d, ehdr_buf_len: %lu, vlan_tag: %d\n",
  135. pkt->tot_len, pkt->ehdr_buf_len, pkt->tci);
  136. #endif
  137. }
  138. void net_rx_pkt_set_packet_type(struct NetRxPkt *pkt,
  139. eth_pkt_types_e packet_type)
  140. {
  141. assert(pkt);
  142. pkt->packet_type = packet_type;
  143. }
  144. eth_pkt_types_e net_rx_pkt_get_packet_type(struct NetRxPkt *pkt)
  145. {
  146. assert(pkt);
  147. return pkt->packet_type;
  148. }
  149. size_t net_rx_pkt_get_total_len(struct NetRxPkt *pkt)
  150. {
  151. assert(pkt);
  152. return pkt->tot_len;
  153. }
  154. void net_rx_pkt_set_protocols(struct NetRxPkt *pkt,
  155. const struct iovec *iov, size_t iovcnt,
  156. size_t iovoff)
  157. {
  158. assert(pkt);
  159. eth_get_protocols(iov, iovcnt, iovoff, &pkt->hasip4, &pkt->hasip6,
  160. &pkt->l3hdr_off, &pkt->l4hdr_off, &pkt->l5hdr_off,
  161. &pkt->ip6hdr_info, &pkt->ip4hdr_info, &pkt->l4hdr_info);
  162. }
  163. void net_rx_pkt_get_protocols(struct NetRxPkt *pkt,
  164. bool *hasip4, bool *hasip6,
  165. EthL4HdrProto *l4hdr_proto)
  166. {
  167. assert(pkt);
  168. *hasip4 = pkt->hasip4;
  169. *hasip6 = pkt->hasip6;
  170. *l4hdr_proto = pkt->l4hdr_info.proto;
  171. }
  172. size_t net_rx_pkt_get_l3_hdr_offset(struct NetRxPkt *pkt)
  173. {
  174. assert(pkt);
  175. return pkt->l3hdr_off;
  176. }
  177. size_t net_rx_pkt_get_l4_hdr_offset(struct NetRxPkt *pkt)
  178. {
  179. assert(pkt);
  180. return pkt->l4hdr_off;
  181. }
  182. size_t net_rx_pkt_get_l5_hdr_offset(struct NetRxPkt *pkt)
  183. {
  184. assert(pkt);
  185. return pkt->l5hdr_off;
  186. }
  187. eth_ip6_hdr_info *net_rx_pkt_get_ip6_info(struct NetRxPkt *pkt)
  188. {
  189. return &pkt->ip6hdr_info;
  190. }
  191. eth_ip4_hdr_info *net_rx_pkt_get_ip4_info(struct NetRxPkt *pkt)
  192. {
  193. return &pkt->ip4hdr_info;
  194. }
  195. eth_l4_hdr_info *net_rx_pkt_get_l4_info(struct NetRxPkt *pkt)
  196. {
  197. return &pkt->l4hdr_info;
  198. }
  199. static inline void
  200. _net_rx_rss_add_chunk(uint8_t *rss_input, size_t *bytes_written,
  201. void *ptr, size_t size)
  202. {
  203. memcpy(&rss_input[*bytes_written], ptr, size);
  204. trace_net_rx_pkt_rss_add_chunk(ptr, size, *bytes_written);
  205. *bytes_written += size;
  206. }
  207. static inline void
  208. _net_rx_rss_prepare_ip4(uint8_t *rss_input,
  209. struct NetRxPkt *pkt,
  210. size_t *bytes_written)
  211. {
  212. struct ip_header *ip4_hdr = &pkt->ip4hdr_info.ip4_hdr;
  213. _net_rx_rss_add_chunk(rss_input, bytes_written,
  214. &ip4_hdr->ip_src, sizeof(uint32_t));
  215. _net_rx_rss_add_chunk(rss_input, bytes_written,
  216. &ip4_hdr->ip_dst, sizeof(uint32_t));
  217. }
  218. static inline void
  219. _net_rx_rss_prepare_ip6(uint8_t *rss_input,
  220. struct NetRxPkt *pkt,
  221. bool ipv6ex, size_t *bytes_written)
  222. {
  223. eth_ip6_hdr_info *ip6info = &pkt->ip6hdr_info;
  224. _net_rx_rss_add_chunk(rss_input, bytes_written,
  225. (ipv6ex && ip6info->rss_ex_src_valid) ? &ip6info->rss_ex_src
  226. : &ip6info->ip6_hdr.ip6_src,
  227. sizeof(struct in6_address));
  228. _net_rx_rss_add_chunk(rss_input, bytes_written,
  229. (ipv6ex && ip6info->rss_ex_dst_valid) ? &ip6info->rss_ex_dst
  230. : &ip6info->ip6_hdr.ip6_dst,
  231. sizeof(struct in6_address));
  232. }
  233. static inline void
  234. _net_rx_rss_prepare_tcp(uint8_t *rss_input,
  235. struct NetRxPkt *pkt,
  236. size_t *bytes_written)
  237. {
  238. struct tcp_header *tcphdr = &pkt->l4hdr_info.hdr.tcp;
  239. _net_rx_rss_add_chunk(rss_input, bytes_written,
  240. &tcphdr->th_sport, sizeof(uint16_t));
  241. _net_rx_rss_add_chunk(rss_input, bytes_written,
  242. &tcphdr->th_dport, sizeof(uint16_t));
  243. }
  244. static inline void
  245. _net_rx_rss_prepare_udp(uint8_t *rss_input,
  246. struct NetRxPkt *pkt,
  247. size_t *bytes_written)
  248. {
  249. struct udp_header *udphdr = &pkt->l4hdr_info.hdr.udp;
  250. _net_rx_rss_add_chunk(rss_input, bytes_written,
  251. &udphdr->uh_sport, sizeof(uint16_t));
  252. _net_rx_rss_add_chunk(rss_input, bytes_written,
  253. &udphdr->uh_dport, sizeof(uint16_t));
  254. }
  255. uint32_t
  256. net_rx_pkt_calc_rss_hash(struct NetRxPkt *pkt,
  257. NetRxPktRssType type,
  258. uint8_t *key)
  259. {
  260. uint8_t rss_input[36];
  261. size_t rss_length = 0;
  262. uint32_t rss_hash = 0;
  263. net_toeplitz_key key_data;
  264. switch (type) {
  265. case NetPktRssIpV4:
  266. assert(pkt->hasip4);
  267. trace_net_rx_pkt_rss_ip4();
  268. _net_rx_rss_prepare_ip4(&rss_input[0], pkt, &rss_length);
  269. break;
  270. case NetPktRssIpV4Tcp:
  271. assert(pkt->hasip4);
  272. assert(pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_TCP);
  273. trace_net_rx_pkt_rss_ip4_tcp();
  274. _net_rx_rss_prepare_ip4(&rss_input[0], pkt, &rss_length);
  275. _net_rx_rss_prepare_tcp(&rss_input[0], pkt, &rss_length);
  276. break;
  277. case NetPktRssIpV6Tcp:
  278. assert(pkt->hasip6);
  279. assert(pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_TCP);
  280. trace_net_rx_pkt_rss_ip6_tcp();
  281. _net_rx_rss_prepare_ip6(&rss_input[0], pkt, false, &rss_length);
  282. _net_rx_rss_prepare_tcp(&rss_input[0], pkt, &rss_length);
  283. break;
  284. case NetPktRssIpV6:
  285. assert(pkt->hasip6);
  286. trace_net_rx_pkt_rss_ip6();
  287. _net_rx_rss_prepare_ip6(&rss_input[0], pkt, false, &rss_length);
  288. break;
  289. case NetPktRssIpV6Ex:
  290. assert(pkt->hasip6);
  291. trace_net_rx_pkt_rss_ip6_ex();
  292. _net_rx_rss_prepare_ip6(&rss_input[0], pkt, true, &rss_length);
  293. break;
  294. case NetPktRssIpV6TcpEx:
  295. assert(pkt->hasip6);
  296. assert(pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_TCP);
  297. trace_net_rx_pkt_rss_ip6_ex_tcp();
  298. _net_rx_rss_prepare_ip6(&rss_input[0], pkt, true, &rss_length);
  299. _net_rx_rss_prepare_tcp(&rss_input[0], pkt, &rss_length);
  300. break;
  301. case NetPktRssIpV4Udp:
  302. assert(pkt->hasip4);
  303. assert(pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_UDP);
  304. trace_net_rx_pkt_rss_ip4_udp();
  305. _net_rx_rss_prepare_ip4(&rss_input[0], pkt, &rss_length);
  306. _net_rx_rss_prepare_udp(&rss_input[0], pkt, &rss_length);
  307. break;
  308. case NetPktRssIpV6Udp:
  309. assert(pkt->hasip6);
  310. assert(pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_UDP);
  311. trace_net_rx_pkt_rss_ip6_udp();
  312. _net_rx_rss_prepare_ip6(&rss_input[0], pkt, false, &rss_length);
  313. _net_rx_rss_prepare_udp(&rss_input[0], pkt, &rss_length);
  314. break;
  315. case NetPktRssIpV6UdpEx:
  316. assert(pkt->hasip6);
  317. assert(pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_UDP);
  318. trace_net_rx_pkt_rss_ip6_ex_udp();
  319. _net_rx_rss_prepare_ip6(&rss_input[0], pkt, true, &rss_length);
  320. _net_rx_rss_prepare_udp(&rss_input[0], pkt, &rss_length);
  321. break;
  322. default:
  323. assert(false);
  324. break;
  325. }
  326. net_toeplitz_key_init(&key_data, key);
  327. net_toeplitz_add(&rss_hash, rss_input, rss_length, &key_data);
  328. trace_net_rx_pkt_rss_hash(rss_length, rss_hash);
  329. return rss_hash;
  330. }
  331. uint16_t net_rx_pkt_get_ip_id(struct NetRxPkt *pkt)
  332. {
  333. assert(pkt);
  334. if (pkt->hasip4) {
  335. return be16_to_cpu(pkt->ip4hdr_info.ip4_hdr.ip_id);
  336. }
  337. return 0;
  338. }
  339. bool net_rx_pkt_is_tcp_ack(struct NetRxPkt *pkt)
  340. {
  341. assert(pkt);
  342. if (pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_TCP) {
  343. return TCP_HEADER_FLAGS(&pkt->l4hdr_info.hdr.tcp) & TCP_FLAG_ACK;
  344. }
  345. return false;
  346. }
  347. bool net_rx_pkt_has_tcp_data(struct NetRxPkt *pkt)
  348. {
  349. assert(pkt);
  350. if (pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_TCP) {
  351. return pkt->l4hdr_info.has_tcp_data;
  352. }
  353. return false;
  354. }
  355. struct iovec *net_rx_pkt_get_iovec(struct NetRxPkt *pkt)
  356. {
  357. assert(pkt);
  358. return pkt->vec;
  359. }
  360. uint16_t net_rx_pkt_get_iovec_len(struct NetRxPkt *pkt)
  361. {
  362. assert(pkt);
  363. return pkt->vec_len;
  364. }
  365. void net_rx_pkt_set_vhdr(struct NetRxPkt *pkt,
  366. struct virtio_net_hdr *vhdr)
  367. {
  368. assert(pkt);
  369. memcpy(&pkt->virt_hdr, vhdr, sizeof pkt->virt_hdr);
  370. }
  371. void net_rx_pkt_set_vhdr_iovec(struct NetRxPkt *pkt,
  372. const struct iovec *iov, int iovcnt)
  373. {
  374. assert(pkt);
  375. iov_to_buf(iov, iovcnt, 0, &pkt->virt_hdr, sizeof pkt->virt_hdr);
  376. }
  377. void net_rx_pkt_unset_vhdr(struct NetRxPkt *pkt)
  378. {
  379. assert(pkt);
  380. memset(&pkt->virt_hdr, 0, sizeof(pkt->virt_hdr));
  381. }
  382. bool net_rx_pkt_is_vlan_stripped(struct NetRxPkt *pkt)
  383. {
  384. assert(pkt);
  385. return pkt->ehdr_buf_len ? true : false;
  386. }
  387. uint16_t net_rx_pkt_get_vlan_tag(struct NetRxPkt *pkt)
  388. {
  389. assert(pkt);
  390. return pkt->tci;
  391. }
  392. bool net_rx_pkt_validate_l3_csum(struct NetRxPkt *pkt, bool *csum_valid)
  393. {
  394. uint32_t cntr;
  395. uint16_t csum;
  396. uint32_t csl;
  397. trace_net_rx_pkt_l3_csum_validate_entry();
  398. if (!pkt->hasip4) {
  399. trace_net_rx_pkt_l3_csum_validate_not_ip4();
  400. return false;
  401. }
  402. csl = pkt->l4hdr_off - pkt->l3hdr_off;
  403. cntr = net_checksum_add_iov(pkt->vec, pkt->vec_len,
  404. pkt->l3hdr_off,
  405. csl, 0);
  406. csum = net_checksum_finish(cntr);
  407. *csum_valid = (csum == 0);
  408. trace_net_rx_pkt_l3_csum_validate_csum(pkt->l3hdr_off, csl,
  409. cntr, csum, *csum_valid);
  410. return true;
  411. }
  412. static uint16_t
  413. _net_rx_pkt_calc_l4_csum(struct NetRxPkt *pkt)
  414. {
  415. uint32_t cntr;
  416. uint16_t csum;
  417. uint16_t csl;
  418. uint32_t cso;
  419. trace_net_rx_pkt_l4_csum_calc_entry();
  420. if (pkt->hasip4) {
  421. if (pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_UDP) {
  422. csl = be16_to_cpu(pkt->l4hdr_info.hdr.udp.uh_ulen);
  423. trace_net_rx_pkt_l4_csum_calc_ip4_udp();
  424. } else {
  425. csl = be16_to_cpu(pkt->ip4hdr_info.ip4_hdr.ip_len) -
  426. IP_HDR_GET_LEN(&pkt->ip4hdr_info.ip4_hdr);
  427. trace_net_rx_pkt_l4_csum_calc_ip4_tcp();
  428. }
  429. cntr = eth_calc_ip4_pseudo_hdr_csum(&pkt->ip4hdr_info.ip4_hdr,
  430. csl, &cso);
  431. trace_net_rx_pkt_l4_csum_calc_ph_csum(cntr, csl);
  432. } else {
  433. if (pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_UDP) {
  434. csl = be16_to_cpu(pkt->l4hdr_info.hdr.udp.uh_ulen);
  435. trace_net_rx_pkt_l4_csum_calc_ip6_udp();
  436. } else {
  437. struct ip6_header *ip6hdr = &pkt->ip6hdr_info.ip6_hdr;
  438. size_t full_ip6hdr_len = pkt->l4hdr_off - pkt->l3hdr_off;
  439. size_t ip6opts_len = full_ip6hdr_len - sizeof(struct ip6_header);
  440. csl = be16_to_cpu(ip6hdr->ip6_ctlun.ip6_un1.ip6_un1_plen) -
  441. ip6opts_len;
  442. trace_net_rx_pkt_l4_csum_calc_ip6_tcp();
  443. }
  444. cntr = eth_calc_ip6_pseudo_hdr_csum(&pkt->ip6hdr_info.ip6_hdr, csl,
  445. pkt->ip6hdr_info.l4proto, &cso);
  446. trace_net_rx_pkt_l4_csum_calc_ph_csum(cntr, csl);
  447. }
  448. cntr += net_checksum_add_iov(pkt->vec, pkt->vec_len,
  449. pkt->l4hdr_off, csl, cso);
  450. csum = net_checksum_finish_nozero(cntr);
  451. trace_net_rx_pkt_l4_csum_calc_csum(pkt->l4hdr_off, csl, cntr, csum);
  452. return csum;
  453. }
  454. bool net_rx_pkt_validate_l4_csum(struct NetRxPkt *pkt, bool *csum_valid)
  455. {
  456. uint16_t csum;
  457. trace_net_rx_pkt_l4_csum_validate_entry();
  458. if (pkt->l4hdr_info.proto != ETH_L4_HDR_PROTO_TCP &&
  459. pkt->l4hdr_info.proto != ETH_L4_HDR_PROTO_UDP) {
  460. trace_net_rx_pkt_l4_csum_validate_not_xxp();
  461. return false;
  462. }
  463. if (pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_UDP &&
  464. pkt->l4hdr_info.hdr.udp.uh_sum == 0) {
  465. trace_net_rx_pkt_l4_csum_validate_udp_with_no_checksum();
  466. return false;
  467. }
  468. if (pkt->hasip4 && pkt->ip4hdr_info.fragment) {
  469. trace_net_rx_pkt_l4_csum_validate_ip4_fragment();
  470. return false;
  471. }
  472. csum = _net_rx_pkt_calc_l4_csum(pkt);
  473. *csum_valid = ((csum == 0) || (csum == 0xFFFF));
  474. trace_net_rx_pkt_l4_csum_validate_csum(*csum_valid);
  475. return true;
  476. }
  477. bool net_rx_pkt_fix_l4_csum(struct NetRxPkt *pkt)
  478. {
  479. uint16_t csum = 0;
  480. uint32_t l4_cso;
  481. trace_net_rx_pkt_l4_csum_fix_entry();
  482. switch (pkt->l4hdr_info.proto) {
  483. case ETH_L4_HDR_PROTO_TCP:
  484. l4_cso = offsetof(struct tcp_header, th_sum);
  485. trace_net_rx_pkt_l4_csum_fix_tcp(l4_cso);
  486. break;
  487. case ETH_L4_HDR_PROTO_UDP:
  488. if (pkt->l4hdr_info.hdr.udp.uh_sum == 0) {
  489. trace_net_rx_pkt_l4_csum_fix_udp_with_no_checksum();
  490. return false;
  491. }
  492. l4_cso = offsetof(struct udp_header, uh_sum);
  493. trace_net_rx_pkt_l4_csum_fix_udp(l4_cso);
  494. break;
  495. default:
  496. trace_net_rx_pkt_l4_csum_fix_not_xxp();
  497. return false;
  498. }
  499. if (pkt->hasip4 && pkt->ip4hdr_info.fragment) {
  500. trace_net_rx_pkt_l4_csum_fix_ip4_fragment();
  501. return false;
  502. }
  503. /* Set zero to checksum word */
  504. iov_from_buf(pkt->vec, pkt->vec_len,
  505. pkt->l4hdr_off + l4_cso,
  506. &csum, sizeof(csum));
  507. /* Calculate L4 checksum */
  508. csum = cpu_to_be16(_net_rx_pkt_calc_l4_csum(pkt));
  509. /* Set calculated checksum to checksum word */
  510. iov_from_buf(pkt->vec, pkt->vec_len,
  511. pkt->l4hdr_off + l4_cso,
  512. &csum, sizeof(csum));
  513. trace_net_rx_pkt_l4_csum_fix_csum(pkt->l4hdr_off + l4_cso, csum);
  514. return true;
  515. }