FreeBSD/sys/dev/netmap/netmap_offloadings.c
/* This routine is called by bdg_mismatch_datapath() when it finishes
 * accumulating bytes for a segment, in order to fix some fields in the
 * segment headers (which still contain the same content as the header
 * of the original GSO packet). 'buf' points to the beginning (e.g.
 * the ethernet header) of the segment, and 'len' is its length.
 */
This routine is called by bdg_mismatch_datapath() when it finishes
accumulating bytes for a segment, in order to fix some fields in the
segment headers (which still contain the same content as the header
of the original GSO packet). 'buf' points to the beginning  of the segment, and 'len' is its length.
This routine is called by bdg_mismatch_datapath () when it finishes accumulating bytes for a segment in order to fix some fields in the segment headers ( which still contain the same content as the header of the original GSO packet ) . ' buf ' points to the beginning of the segment and ' len ' is its length .
static void gso_fix_segment(uint8_t *buf, size_t len, u_int idx,
			    u_int segmented_bytes, u_int last_segment,
			    u_int tcp, u_int iphlen)
{
	struct nm_iphdr *iph = (struct nm_iphdr *)(buf + 14);
	struct nm_ipv6hdr *ip6h = (struct nm_ipv6hdr *)(buf + 14);
	uint16_t *check = NULL;
	uint8_t *check_data = NULL;
	if (iphlen == 20) {
		iph->tot_len = htobe16(len-14);
		ND("ip total length %u", be16toh(ip->tot_len));
		iph->id = htobe16(be16toh(iph->id) + idx);
		ND("ip identification %u", be16toh(iph->id));
		iph->check = 0;
		iph->check = nm_csum_ipv4(iph);
		ND("IP csum %x", be16toh(iph->check));
	} else {
		ip6h->payload_len = htobe16(len-14-iphlen);
	}
	if (tcp) {
		struct nm_tcphdr *tcph = (struct nm_tcphdr *)(buf + 14 + iphlen);
		tcph->seq = htobe32(be32toh(tcph->seq) + segmented_bytes);
		ND("tcp seq %u", be32toh(tcph->seq));
		if (!last_segment)
			tcph->flags &= ~(0x8 | 0x1);
		ND("last_segment %u", last_segment);
		check = &tcph->check;
		check_data = (uint8_t *)tcph;
	} else { 
		struct nm_udphdr *udph = (struct nm_udphdr *)(buf + 14 + iphlen);
		udph->len = htobe16(len-14-iphlen);
		check = &udph->check;
		check_data = (uint8_t *)udph;
	}
	*check = 0;
	if (iphlen == 20)
		nm_csum_tcpudp_ipv4(iph, check_data, len-14-iphlen, check);
	else
		nm_csum_tcpudp_ipv6(ip6h, check_data, len-14-iphlen, check);
	ND("TCP/UDP csum %x", be16toh(*check));
}
static void gso_fix_segment ( uint8_t * buf , size_t len , u_int idx , u_int segmented_bytes , u_int last_segment , u_int tcp , u_int iphlen ) { struct nm_iphdr * iph = ( struct nm_iphdr * ) ( buf + 14 ) ; struct nm_ipv6hdr * ip6h = ( struct nm_ipv6hdr * ) ( buf + 14 ) ; uint16_t * check = NULL ; uint8_t * check_data = NULL ; if ( iphlen == 20 ) { iph -> tot_len = htobe16 ( len - 14 ) ; ND ( " " , be16toh ( ip -> tot_len ) ) ; iph -> id = htobe16 ( be16toh ( iph -> id ) + idx ) ; ND ( " " , be16toh ( iph -> id ) ) ; iph -> check = 0 ; iph -> check = nm_csum_ipv4 ( iph ) ; ND ( " " , be16toh ( iph -> check ) ) ; } else { ip6h -> payload_len = htobe16 ( len - 14 - iphlen ) ; } if ( tcp ) { struct nm_tcphdr * tcph = ( struct nm_tcphdr * ) ( buf + 14 + iphlen ) ; tcph -> seq = htobe32 ( be32toh ( tcph -> seq ) + segmented_bytes ) ; ND ( " " , be32toh ( tcph -> seq ) ) ; if ( ! last_segment ) tcph -> flags &= ~ ( 0x8 | 0x1 ) ; ND ( " " , last_segment ) ; check = & tcph -> check ; check_data = ( uint8_t * ) tcph ; } else { struct nm_udphdr * udph = ( struct nm_udphdr * ) ( buf + 14 + iphlen ) ; udph -> len = htobe16 ( len - 14 - iphlen ) ; check = & udph -> check ; check_data = ( uint8_t * ) udph ; } * check = 0 ; if ( iphlen == 20 ) nm_csum_tcpudp_ipv4 ( iph , check_data , len - 14 - iphlen , check ) ; else nm_csum_tcpudp_ipv6 ( ip6h , check_data , len - 14 - iphlen , check ) ; ND ( " " , be16toh ( * check ) ) ; }
This routine is called by bdg_mismatch_datapath() when it finishes
 accumulating bytes for a segment, in order to fix some fields in the
 segment headers (which still contain the same content as the header
 of the original GSO packet).
This routine is called by bdg_mismatch_datapath () when it finishes accumulating bytes for a segment in order to fix some fields in the segment headers ( which still contain the same content as the header of the original GSO packet ) .
/* Set the IPv4 "Total Length" field. */ /* Set the IPv4 "Identification" field. */ /* Compute and insert the IPv4 header checksum. */ /* if (iphlen == 40) */ /* Set the IPv6 "Payload Len" field. */ /* Set the TCP sequence number. */ /* Zero the PSH and FIN TCP flags if this is not the last
		   segment. */ /* UDP */ /* Set the UDP 'Length' field. */ /* Compute and insert TCP/UDP checksum. */