|
@@ -16,6 +16,7 @@
|
|
*/
|
|
*/
|
|
|
|
|
|
#include "qemu/osdep.h"
|
|
#include "qemu/osdep.h"
|
|
|
|
+#include "qemu/crc32c.h"
|
|
#include "trace.h"
|
|
#include "trace.h"
|
|
#include "net_rx_pkt.h"
|
|
#include "net_rx_pkt.h"
|
|
#include "net/checksum.h"
|
|
#include "net/checksum.h"
|
|
@@ -554,32 +555,73 @@ _net_rx_pkt_calc_l4_csum(struct NetRxPkt *pkt)
|
|
return csum;
|
|
return csum;
|
|
}
|
|
}
|
|
|
|
|
|
-bool net_rx_pkt_validate_l4_csum(struct NetRxPkt *pkt, bool *csum_valid)
|
|
|
|
|
|
+static bool
|
|
|
|
+_net_rx_pkt_validate_sctp_sum(struct NetRxPkt *pkt)
|
|
{
|
|
{
|
|
- uint16_t csum;
|
|
|
|
|
|
+ size_t csum_off;
|
|
|
|
+ size_t off = pkt->l4hdr_off;
|
|
|
|
+ size_t vec_len = pkt->vec_len;
|
|
|
|
+ struct iovec *vec;
|
|
|
|
+ uint32_t calculated = 0;
|
|
|
|
+ uint32_t original;
|
|
|
|
+ bool valid;
|
|
|
|
|
|
- trace_net_rx_pkt_l4_csum_validate_entry();
|
|
|
|
|
|
+ for (vec = pkt->vec; vec->iov_len < off; vec++) {
|
|
|
|
+ off -= vec->iov_len;
|
|
|
|
+ vec_len--;
|
|
|
|
+ }
|
|
|
|
|
|
- if (pkt->l4hdr_info.proto != ETH_L4_HDR_PROTO_TCP &&
|
|
|
|
- pkt->l4hdr_info.proto != ETH_L4_HDR_PROTO_UDP) {
|
|
|
|
- trace_net_rx_pkt_l4_csum_validate_not_xxp();
|
|
|
|
|
|
+ csum_off = off + 8;
|
|
|
|
+
|
|
|
|
+ if (!iov_to_buf(vec, vec_len, csum_off, &original, sizeof(original))) {
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
- if (pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_UDP &&
|
|
|
|
- pkt->l4hdr_info.hdr.udp.uh_sum == 0) {
|
|
|
|
- trace_net_rx_pkt_l4_csum_validate_udp_with_no_checksum();
|
|
|
|
|
|
+ if (!iov_from_buf(vec, vec_len, csum_off,
|
|
|
|
+ &calculated, sizeof(calculated))) {
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ calculated = crc32c(0xffffffff,
|
|
|
|
+ (uint8_t *)vec->iov_base + off, vec->iov_len - off);
|
|
|
|
+ calculated = iov_crc32c(calculated ^ 0xffffffff, vec + 1, vec_len - 1);
|
|
|
|
+ valid = calculated == le32_to_cpu(original);
|
|
|
|
+ iov_from_buf(vec, vec_len, csum_off, &original, sizeof(original));
|
|
|
|
+
|
|
|
|
+ return valid;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+bool net_rx_pkt_validate_l4_csum(struct NetRxPkt *pkt, bool *csum_valid)
|
|
|
|
+{
|
|
|
|
+ uint32_t csum;
|
|
|
|
+
|
|
|
|
+ trace_net_rx_pkt_l4_csum_validate_entry();
|
|
|
|
+
|
|
if (pkt->hasip4 && pkt->ip4hdr_info.fragment) {
|
|
if (pkt->hasip4 && pkt->ip4hdr_info.fragment) {
|
|
trace_net_rx_pkt_l4_csum_validate_ip4_fragment();
|
|
trace_net_rx_pkt_l4_csum_validate_ip4_fragment();
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
- csum = _net_rx_pkt_calc_l4_csum(pkt);
|
|
|
|
|
|
+ switch (pkt->l4hdr_info.proto) {
|
|
|
|
+ case ETH_L4_HDR_PROTO_UDP:
|
|
|
|
+ if (pkt->l4hdr_info.hdr.udp.uh_sum == 0) {
|
|
|
|
+ trace_net_rx_pkt_l4_csum_validate_udp_with_no_checksum();
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ /* fall through */
|
|
|
|
+ case ETH_L4_HDR_PROTO_TCP:
|
|
|
|
+ csum = _net_rx_pkt_calc_l4_csum(pkt);
|
|
|
|
+ *csum_valid = ((csum == 0) || (csum == 0xFFFF));
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ case ETH_L4_HDR_PROTO_SCTP:
|
|
|
|
+ *csum_valid = _net_rx_pkt_validate_sctp_sum(pkt);
|
|
|
|
+ break;
|
|
|
|
|
|
- *csum_valid = ((csum == 0) || (csum == 0xFFFF));
|
|
|
|
|
|
+ default:
|
|
|
|
+ trace_net_rx_pkt_l4_csum_validate_not_xxp();
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
|
|
trace_net_rx_pkt_l4_csum_validate_csum(*csum_valid);
|
|
trace_net_rx_pkt_l4_csum_validate_csum(*csum_valid);
|
|
|
|
|