104b6cca3Slucy wang - Sun Microsystems - Beijing China /*
204b6cca3Slucy wang - Sun Microsystems - Beijing China  * CDDL HEADER START
304b6cca3Slucy wang - Sun Microsystems - Beijing China  *
404b6cca3Slucy wang - Sun Microsystems - Beijing China  * The contents of this file are subject to the terms of the
504b6cca3Slucy wang - Sun Microsystems - Beijing China  * Common Development and Distribution License (the "License").
604b6cca3Slucy wang - Sun Microsystems - Beijing China  * You may not use this file except in compliance with the License.
704b6cca3Slucy wang - Sun Microsystems - Beijing China  *
804b6cca3Slucy wang - Sun Microsystems - Beijing China  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
904b6cca3Slucy wang - Sun Microsystems - Beijing China  * or http://www.opensolaris.org/os/licensing.
1004b6cca3Slucy wang - Sun Microsystems - Beijing China  * See the License for the specific language governing permissions
1104b6cca3Slucy wang - Sun Microsystems - Beijing China  * and limitations under the License.
1204b6cca3Slucy wang - Sun Microsystems - Beijing China  *
1304b6cca3Slucy wang - Sun Microsystems - Beijing China  * When distributing Covered Code, include this CDDL HEADER in each
1404b6cca3Slucy wang - Sun Microsystems - Beijing China  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1504b6cca3Slucy wang - Sun Microsystems - Beijing China  * If applicable, add the following below this CDDL HEADER, with the
1604b6cca3Slucy wang - Sun Microsystems - Beijing China  * fields enclosed by brackets "[]" replaced with your own identifying
1704b6cca3Slucy wang - Sun Microsystems - Beijing China  * information: Portions Copyright [yyyy] [name of copyright owner]
1804b6cca3Slucy wang - Sun Microsystems - Beijing China  *
1904b6cca3Slucy wang - Sun Microsystems - Beijing China  * CDDL HEADER END
2004b6cca3Slucy wang - Sun Microsystems - Beijing China  */
2104b6cca3Slucy wang - Sun Microsystems - Beijing China 
2204b6cca3Slucy wang - Sun Microsystems - Beijing China /*
2304b6cca3Slucy wang - Sun Microsystems - Beijing China  * Copyright 2007-2009 Myricom, Inc.  All rights reserved.
2404b6cca3Slucy wang - Sun Microsystems - Beijing China  * Use is subject to license terms.
2504b6cca3Slucy wang - Sun Microsystems - Beijing China  */
2604b6cca3Slucy wang - Sun Microsystems - Beijing China 
2704b6cca3Slucy wang - Sun Microsystems - Beijing China #include "myri10ge_var.h"
2804b6cca3Slucy wang - Sun Microsystems - Beijing China 
2904b6cca3Slucy wang - Sun Microsystems - Beijing China #define	IP_OFFMASK 0x1fff
3004b6cca3Slucy wang - Sun Microsystems - Beijing China #define	TCPOPT_TIMESTAMP 8
3104b6cca3Slucy wang - Sun Microsystems - Beijing China #define	TCPOLEN_TIMESTAMP 10
3204b6cca3Slucy wang - Sun Microsystems - Beijing China #define	TCPOLEN_TSTAMP_APPA 12
3304b6cca3Slucy wang - Sun Microsystems - Beijing China 
3404b6cca3Slucy wang - Sun Microsystems - Beijing China 
3504b6cca3Slucy wang - Sun Microsystems - Beijing China /*
3604b6cca3Slucy wang - Sun Microsystems - Beijing China  * Assume len is a multiple of 4. Note that "raw" must be
3704b6cca3Slucy wang - Sun Microsystems - Beijing China  * suitably aligned. In practice, it will always enter algned on
3804b6cca3Slucy wang - Sun Microsystems - Beijing China  * at least a 4 bytes bounday, due to the alignment of our rx buffers.
3904b6cca3Slucy wang - Sun Microsystems - Beijing China  */
4004b6cca3Slucy wang - Sun Microsystems - Beijing China uint16_t
myri10ge_csum_generic(uint16_t * raw,int len)4104b6cca3Slucy wang - Sun Microsystems - Beijing China myri10ge_csum_generic(uint16_t *raw, int len)
4204b6cca3Slucy wang - Sun Microsystems - Beijing China {
4304b6cca3Slucy wang - Sun Microsystems - Beijing China 	uint32_t csum;
4404b6cca3Slucy wang - Sun Microsystems - Beijing China 	csum = 0;
4504b6cca3Slucy wang - Sun Microsystems - Beijing China 	while (len > 0) {
4604b6cca3Slucy wang - Sun Microsystems - Beijing China 		csum += *raw;
4704b6cca3Slucy wang - Sun Microsystems - Beijing China 		raw++;
4804b6cca3Slucy wang - Sun Microsystems - Beijing China 		csum += *raw;
4904b6cca3Slucy wang - Sun Microsystems - Beijing China 		raw++;
5004b6cca3Slucy wang - Sun Microsystems - Beijing China 		len -= 4;
5104b6cca3Slucy wang - Sun Microsystems - Beijing China 	}
5204b6cca3Slucy wang - Sun Microsystems - Beijing China 	csum = (csum >> 16) + (csum & 0xffff);
5304b6cca3Slucy wang - Sun Microsystems - Beijing China 	csum = (csum >> 16) + (csum & 0xffff);
5404b6cca3Slucy wang - Sun Microsystems - Beijing China 	return ((uint16_t)csum);
5504b6cca3Slucy wang - Sun Microsystems - Beijing China }
5604b6cca3Slucy wang - Sun Microsystems - Beijing China 
5704b6cca3Slucy wang - Sun Microsystems - Beijing China static uint16_t
myri10ge_in_pseudo(unsigned int a,unsigned int b,unsigned int c)5804b6cca3Slucy wang - Sun Microsystems - Beijing China myri10ge_in_pseudo(unsigned int a, unsigned int b,
5904b6cca3Slucy wang - Sun Microsystems - Beijing China     unsigned int c)
6004b6cca3Slucy wang - Sun Microsystems - Beijing China {
6104b6cca3Slucy wang - Sun Microsystems - Beijing China 	uint64_t csum;
6204b6cca3Slucy wang - Sun Microsystems - Beijing China 
6304b6cca3Slucy wang - Sun Microsystems - Beijing China 	csum = (uint64_t)a + b + c;
6404b6cca3Slucy wang - Sun Microsystems - Beijing China 	csum = (csum >> 16) + (csum & 0xffff);
6504b6cca3Slucy wang - Sun Microsystems - Beijing China 	csum = (csum >> 16) + (csum & 0xffff);
6604b6cca3Slucy wang - Sun Microsystems - Beijing China 	return ((uint16_t)csum);
6704b6cca3Slucy wang - Sun Microsystems - Beijing China }
6804b6cca3Slucy wang - Sun Microsystems - Beijing China 
6904b6cca3Slucy wang - Sun Microsystems - Beijing China void
myri10ge_lro_flush(struct myri10ge_slice_state * ss,struct lro_entry * lro,struct myri10ge_mblk_list * mbl)7004b6cca3Slucy wang - Sun Microsystems - Beijing China myri10ge_lro_flush(struct myri10ge_slice_state *ss, struct lro_entry *lro,
71*a3ef5975SToomas Soome     struct myri10ge_mblk_list *mbl)
7204b6cca3Slucy wang - Sun Microsystems - Beijing China {
7304b6cca3Slucy wang - Sun Microsystems - Beijing China 	struct ip *ip;
7404b6cca3Slucy wang - Sun Microsystems - Beijing China 	struct tcphdr *tcp;
7504b6cca3Slucy wang - Sun Microsystems - Beijing China 	uint32_t *ts_ptr;
7604b6cca3Slucy wang - Sun Microsystems - Beijing China 	uint32_t tcplen, tcp_csum;
7704b6cca3Slucy wang - Sun Microsystems - Beijing China 
7804b6cca3Slucy wang - Sun Microsystems - Beijing China 	if (lro->append_cnt) {
7904b6cca3Slucy wang - Sun Microsystems - Beijing China 		/*
8004b6cca3Slucy wang - Sun Microsystems - Beijing China 		 * incorporate the new len into the ip header and
8104b6cca3Slucy wang - Sun Microsystems - Beijing China 		 * re-calculate the checksum
8204b6cca3Slucy wang - Sun Microsystems - Beijing China 		 */
8304b6cca3Slucy wang - Sun Microsystems - Beijing China 		ip = lro->ip;
8404b6cca3Slucy wang - Sun Microsystems - Beijing China 		ip->ip_len = htons(lro->len - ETHERNET_HEADER_SIZE);
8504b6cca3Slucy wang - Sun Microsystems - Beijing China 		ip->ip_sum = 0;
8604b6cca3Slucy wang - Sun Microsystems - Beijing China 		ip->ip_sum = 0xffff ^
8704b6cca3Slucy wang - Sun Microsystems - Beijing China 		    myri10ge_csum_generic((uint16_t *)ip, sizeof (*ip));
8804b6cca3Slucy wang - Sun Microsystems - Beijing China 		/* incorporate the latest ack into the tcp header */
8904b6cca3Slucy wang - Sun Microsystems - Beijing China 		tcp = (struct tcphdr *)(ip + 1);
9004b6cca3Slucy wang - Sun Microsystems - Beijing China 		tcp->th_ack = lro->ack_seq;
9104b6cca3Slucy wang - Sun Microsystems - Beijing China 		tcp->th_win = lro->window;
9204b6cca3Slucy wang - Sun Microsystems - Beijing China 		tcp->th_flags = lro->flags;
9304b6cca3Slucy wang - Sun Microsystems - Beijing China 		/* incorporate latest timestamp into the tcp header */
9404b6cca3Slucy wang - Sun Microsystems - Beijing China 		if (lro->timestamp) {
9504b6cca3Slucy wang - Sun Microsystems - Beijing China 			ts_ptr = (uint32_t *)(tcp + 1);
9604b6cca3Slucy wang - Sun Microsystems - Beijing China 			ts_ptr[1] = htonl(lro->tsval);
9704b6cca3Slucy wang - Sun Microsystems - Beijing China 			ts_ptr[2] = lro->tsecr;
9804b6cca3Slucy wang - Sun Microsystems - Beijing China 		}
9904b6cca3Slucy wang - Sun Microsystems - Beijing China 		/*
10004b6cca3Slucy wang - Sun Microsystems - Beijing China 		 * update checksum in tcp header by re-calculating the
10104b6cca3Slucy wang - Sun Microsystems - Beijing China 		 * tcp pseudoheader checksum, and adding it to the checksum
10204b6cca3Slucy wang - Sun Microsystems - Beijing China 		 * of the tcp payload data
10304b6cca3Slucy wang - Sun Microsystems - Beijing China 		 */
10404b6cca3Slucy wang - Sun Microsystems - Beijing China 		tcp->th_sum = 0;
10504b6cca3Slucy wang - Sun Microsystems - Beijing China 		tcplen = lro->len - sizeof (*ip) - ETHERNET_HEADER_SIZE;
10604b6cca3Slucy wang - Sun Microsystems - Beijing China 		tcp_csum = lro->data_csum;
10704b6cca3Slucy wang - Sun Microsystems - Beijing China 		tcp_csum += myri10ge_in_pseudo(ip->ip_src.s_addr,
10804b6cca3Slucy wang - Sun Microsystems - Beijing China 		    ip->ip_dst.s_addr, htons(tcplen + IPPROTO_TCP));
10904b6cca3Slucy wang - Sun Microsystems - Beijing China 		tcp_csum += myri10ge_csum_generic((uint16_t *)tcp,
11004b6cca3Slucy wang - Sun Microsystems - Beijing China 		    tcp->th_off << 2);
11104b6cca3Slucy wang - Sun Microsystems - Beijing China 		tcp_csum = (tcp_csum & 0xffff) + (tcp_csum >> 16);
11204b6cca3Slucy wang - Sun Microsystems - Beijing China 		tcp_csum = (tcp_csum & 0xffff) + (tcp_csum >> 16);
11304b6cca3Slucy wang - Sun Microsystems - Beijing China 		tcp->th_sum = 0xffff ^ tcp_csum;
11404b6cca3Slucy wang - Sun Microsystems - Beijing China 	}
11504b6cca3Slucy wang - Sun Microsystems - Beijing China 
1160dc2366fSVenugopal Iyer 	mac_hcksum_set(lro->m_head, 0, 0, 0,
1170dc2366fSVenugopal Iyer 	    0, HCK_IPV4_HDRCKSUM_OK | HCK_FULLCKSUM_OK);
11804b6cca3Slucy wang - Sun Microsystems - Beijing China 
11904b6cca3Slucy wang - Sun Microsystems - Beijing China 	mbl->cnt += lro->append_cnt;
12004b6cca3Slucy wang - Sun Microsystems - Beijing China 	myri10ge_mbl_append(ss, mbl, lro->m_head);
12104b6cca3Slucy wang - Sun Microsystems - Beijing China 	MYRI10GE_SLICE_STAT_INC(lro_flushed);
12204b6cca3Slucy wang - Sun Microsystems - Beijing China 	MYRI10GE_SLICE_STAT_ADD(lro_queued, lro->append_cnt + 1);
12304b6cca3Slucy wang - Sun Microsystems - Beijing China 	lro->m_head = NULL;
12404b6cca3Slucy wang - Sun Microsystems - Beijing China 	lro->timestamp = 0;
12504b6cca3Slucy wang - Sun Microsystems - Beijing China 	lro->append_cnt = 0;
12604b6cca3Slucy wang - Sun Microsystems - Beijing China 	lro->next = ss->lro_free;
12704b6cca3Slucy wang - Sun Microsystems - Beijing China 	ss->lro_free = lro;
12804b6cca3Slucy wang - Sun Microsystems - Beijing China }
12904b6cca3Slucy wang - Sun Microsystems - Beijing China 
13004b6cca3Slucy wang - Sun Microsystems - Beijing China int
myri10ge_lro_rx(struct myri10ge_slice_state * ss,mblk_t * m_head,uint32_t csum,struct myri10ge_mblk_list * mbl)13104b6cca3Slucy wang - Sun Microsystems - Beijing China myri10ge_lro_rx(struct myri10ge_slice_state *ss, mblk_t *m_head,
132*a3ef5975SToomas Soome     uint32_t csum, struct myri10ge_mblk_list *mbl)
13304b6cca3Slucy wang - Sun Microsystems - Beijing China {
13404b6cca3Slucy wang - Sun Microsystems - Beijing China 	struct ether_header *eh;
13504b6cca3Slucy wang - Sun Microsystems - Beijing China 	struct ip *ip;
13604b6cca3Slucy wang - Sun Microsystems - Beijing China 	struct tcphdr *tcp;
13704b6cca3Slucy wang - Sun Microsystems - Beijing China 	uint32_t *ts_ptr;
13804b6cca3Slucy wang - Sun Microsystems - Beijing China 	struct lro_entry *lro, *curr;
13904b6cca3Slucy wang - Sun Microsystems - Beijing China 	int hlen, ip_len, tcp_hdr_len, tcp_data_len;
14004b6cca3Slucy wang - Sun Microsystems - Beijing China 	int opt_bytes, trim;
14104b6cca3Slucy wang - Sun Microsystems - Beijing China 	int tot_len = MBLKL(m_head);
14204b6cca3Slucy wang - Sun Microsystems - Beijing China 	uint32_t seq, tmp_csum;
14304b6cca3Slucy wang - Sun Microsystems - Beijing China 
14404b6cca3Slucy wang - Sun Microsystems - Beijing China 	eh = (struct ether_header *)(void *)m_head->b_rptr;
14504b6cca3Slucy wang - Sun Microsystems - Beijing China 	if (eh->ether_type != htons(ETHERTYPE_IP))
14604b6cca3Slucy wang - Sun Microsystems - Beijing China 		return (EINVAL);
14704b6cca3Slucy wang - Sun Microsystems - Beijing China 	ip = (struct ip *)(void *)(eh + 1);
14804b6cca3Slucy wang - Sun Microsystems - Beijing China 	if (ip->ip_p != IPPROTO_TCP)
14904b6cca3Slucy wang - Sun Microsystems - Beijing China 		return (EINVAL);
15004b6cca3Slucy wang - Sun Microsystems - Beijing China 
15104b6cca3Slucy wang - Sun Microsystems - Beijing China 	/* ensure there are no options */
15204b6cca3Slucy wang - Sun Microsystems - Beijing China 	if ((ip->ip_hl << 2) != sizeof (*ip))
15304b6cca3Slucy wang - Sun Microsystems - Beijing China 		return (EINVAL);
15404b6cca3Slucy wang - Sun Microsystems - Beijing China 
15504b6cca3Slucy wang - Sun Microsystems - Beijing China 	/* .. and the packet is not fragmented */
15604b6cca3Slucy wang - Sun Microsystems - Beijing China 	if (ip->ip_off & htons(IP_MF|IP_OFFMASK))
15704b6cca3Slucy wang - Sun Microsystems - Beijing China 		return (EINVAL);
15804b6cca3Slucy wang - Sun Microsystems - Beijing China 
15904b6cca3Slucy wang - Sun Microsystems - Beijing China 	/* verify that the IP header checksum is correct */
16004b6cca3Slucy wang - Sun Microsystems - Beijing China 	tmp_csum = myri10ge_csum_generic((uint16_t *)ip, sizeof (*ip));
16104b6cca3Slucy wang - Sun Microsystems - Beijing China 	if (unlikely((tmp_csum ^ 0xffff) != 0)) {
16204b6cca3Slucy wang - Sun Microsystems - Beijing China 		MYRI10GE_SLICE_STAT_INC(lro_bad_csum);
16304b6cca3Slucy wang - Sun Microsystems - Beijing China 		return (EINVAL);
16404b6cca3Slucy wang - Sun Microsystems - Beijing China 	}
16504b6cca3Slucy wang - Sun Microsystems - Beijing China 
16604b6cca3Slucy wang - Sun Microsystems - Beijing China 	/* find the TCP header */
16704b6cca3Slucy wang - Sun Microsystems - Beijing China 	tcp = (struct tcphdr *)(ip + 1);
16804b6cca3Slucy wang - Sun Microsystems - Beijing China 
16904b6cca3Slucy wang - Sun Microsystems - Beijing China 	/* ensure no bits set besides ack or psh */
17004b6cca3Slucy wang - Sun Microsystems - Beijing China 	if ((tcp->th_flags & ~(TH_ACK | TH_PUSH)) != 0)
17104b6cca3Slucy wang - Sun Microsystems - Beijing China 		return (EINVAL);
17204b6cca3Slucy wang - Sun Microsystems - Beijing China 
17304b6cca3Slucy wang - Sun Microsystems - Beijing China 	/*
17404b6cca3Slucy wang - Sun Microsystems - Beijing China 	 * check for timestamps. Since the only option we handle are
17504b6cca3Slucy wang - Sun Microsystems - Beijing China 	 * timestamps, we only have to handle the simple case of
17604b6cca3Slucy wang - Sun Microsystems - Beijing China 	 * aligned timestamps
17704b6cca3Slucy wang - Sun Microsystems - Beijing China 	 */
17804b6cca3Slucy wang - Sun Microsystems - Beijing China 
17904b6cca3Slucy wang - Sun Microsystems - Beijing China 	opt_bytes = (tcp->th_off << 2) - sizeof (*tcp);
18004b6cca3Slucy wang - Sun Microsystems - Beijing China 	tcp_hdr_len =  sizeof (*tcp) + opt_bytes;
18104b6cca3Slucy wang - Sun Microsystems - Beijing China 	ts_ptr = (uint32_t *)(tcp + 1);
18204b6cca3Slucy wang - Sun Microsystems - Beijing China 	if (opt_bytes != 0) {
18304b6cca3Slucy wang - Sun Microsystems - Beijing China 		if (unlikely(opt_bytes != TCPOLEN_TSTAMP_APPA) ||
18404b6cca3Slucy wang - Sun Microsystems - Beijing China 		    (*ts_ptr !=  ntohl(TCPOPT_NOP<<24|TCPOPT_NOP<<16|
18504b6cca3Slucy wang - Sun Microsystems - Beijing China 		    TCPOPT_TIMESTAMP<<8|TCPOLEN_TIMESTAMP)))
18604b6cca3Slucy wang - Sun Microsystems - Beijing China 			return (EINVAL);
18704b6cca3Slucy wang - Sun Microsystems - Beijing China 	}
18804b6cca3Slucy wang - Sun Microsystems - Beijing China 
18904b6cca3Slucy wang - Sun Microsystems - Beijing China 	ip_len = ntohs(ip->ip_len);
19004b6cca3Slucy wang - Sun Microsystems - Beijing China 	tcp_data_len = ip_len - (tcp->th_off << 2) - sizeof (*ip);
19104b6cca3Slucy wang - Sun Microsystems - Beijing China 
19204b6cca3Slucy wang - Sun Microsystems - Beijing China 	/*
19304b6cca3Slucy wang - Sun Microsystems - Beijing China 	 * If frame is padded beyond the end of the IP packet,
19404b6cca3Slucy wang - Sun Microsystems - Beijing China 	 * then we must trim the extra bytes off the end.
19504b6cca3Slucy wang - Sun Microsystems - Beijing China 	 */
19604b6cca3Slucy wang - Sun Microsystems - Beijing China 	trim = tot_len - (ip_len + ETHERNET_HEADER_SIZE);
19704b6cca3Slucy wang - Sun Microsystems - Beijing China 	if (trim != 0) {
19804b6cca3Slucy wang - Sun Microsystems - Beijing China 		if (trim < 0) {
19904b6cca3Slucy wang - Sun Microsystems - Beijing China 			/* truncated packet */
20004b6cca3Slucy wang - Sun Microsystems - Beijing China 			return (EINVAL);
20104b6cca3Slucy wang - Sun Microsystems - Beijing China 		}
20204b6cca3Slucy wang - Sun Microsystems - Beijing China 		m_head->b_wptr -= trim;
20304b6cca3Slucy wang - Sun Microsystems - Beijing China 		tot_len -= trim;
20404b6cca3Slucy wang - Sun Microsystems - Beijing China 	}
20504b6cca3Slucy wang - Sun Microsystems - Beijing China 
20604b6cca3Slucy wang - Sun Microsystems - Beijing China 	/* Verify TCP checksum */
20704b6cca3Slucy wang - Sun Microsystems - Beijing China 	csum = ntohs((uint16_t)csum);
20804b6cca3Slucy wang - Sun Microsystems - Beijing China 	tmp_csum = csum + myri10ge_in_pseudo(ip->ip_src.s_addr,
20904b6cca3Slucy wang - Sun Microsystems - Beijing China 	    ip->ip_dst.s_addr, htons(tcp_hdr_len + tcp_data_len + IPPROTO_TCP));
21004b6cca3Slucy wang - Sun Microsystems - Beijing China 	tmp_csum = (tmp_csum & 0xffff) + (tmp_csum >> 16);
21104b6cca3Slucy wang - Sun Microsystems - Beijing China 	tmp_csum = (tmp_csum & 0xffff) + (tmp_csum >> 16);
21204b6cca3Slucy wang - Sun Microsystems - Beijing China 	if (tmp_csum != 0xffff) {
21304b6cca3Slucy wang - Sun Microsystems - Beijing China 		MYRI10GE_SLICE_STAT_INC(lro_bad_csum);
21404b6cca3Slucy wang - Sun Microsystems - Beijing China 		return (EINVAL);
21504b6cca3Slucy wang - Sun Microsystems - Beijing China 	}
21604b6cca3Slucy wang - Sun Microsystems - Beijing China 
21704b6cca3Slucy wang - Sun Microsystems - Beijing China 	hlen = ip_len + ETHERNET_HEADER_SIZE - tcp_data_len;
21804b6cca3Slucy wang - Sun Microsystems - Beijing China 	seq = ntohl(tcp->th_seq);
21904b6cca3Slucy wang - Sun Microsystems - Beijing China 
22004b6cca3Slucy wang - Sun Microsystems - Beijing China 	for (lro = ss->lro_active; lro != NULL; lro = lro->next) {
22104b6cca3Slucy wang - Sun Microsystems - Beijing China 		if (lro->source_port == tcp->th_sport &&
22204b6cca3Slucy wang - Sun Microsystems - Beijing China 		    lro->dest_port == tcp->th_dport &&
22304b6cca3Slucy wang - Sun Microsystems - Beijing China 		    lro->source_ip == ip->ip_src.s_addr &&
22404b6cca3Slucy wang - Sun Microsystems - Beijing China 		    lro->dest_ip == ip->ip_dst.s_addr) {
22504b6cca3Slucy wang - Sun Microsystems - Beijing China 			/* Try to append it */
22604b6cca3Slucy wang - Sun Microsystems - Beijing China 
22704b6cca3Slucy wang - Sun Microsystems - Beijing China 			if (unlikely(seq != lro->next_seq)) {
22804b6cca3Slucy wang - Sun Microsystems - Beijing China 				/* out of order packet */
22904b6cca3Slucy wang - Sun Microsystems - Beijing China 				if (ss->lro_active == lro) {
23004b6cca3Slucy wang - Sun Microsystems - Beijing China 					ss->lro_active = lro->next;
23104b6cca3Slucy wang - Sun Microsystems - Beijing China 				} else {
23204b6cca3Slucy wang - Sun Microsystems - Beijing China 					curr = ss->lro_active;
23304b6cca3Slucy wang - Sun Microsystems - Beijing China 					while (curr->next != lro)
23404b6cca3Slucy wang - Sun Microsystems - Beijing China 						curr = curr->next;
23504b6cca3Slucy wang - Sun Microsystems - Beijing China 					curr->next = lro->next;
23604b6cca3Slucy wang - Sun Microsystems - Beijing China 				}
23704b6cca3Slucy wang - Sun Microsystems - Beijing China 				myri10ge_lro_flush(ss, lro, mbl);
23804b6cca3Slucy wang - Sun Microsystems - Beijing China 				return (EINVAL);
23904b6cca3Slucy wang - Sun Microsystems - Beijing China 			}
24004b6cca3Slucy wang - Sun Microsystems - Beijing China 
24104b6cca3Slucy wang - Sun Microsystems - Beijing China 			if (opt_bytes) {
24204b6cca3Slucy wang - Sun Microsystems - Beijing China 				uint32_t tsval = ntohl(*(ts_ptr + 1));
24304b6cca3Slucy wang - Sun Microsystems - Beijing China 				/* make sure timestamp values are increasing */
24404b6cca3Slucy wang - Sun Microsystems - Beijing China 				if (unlikely(lro->tsval > tsval ||
24504b6cca3Slucy wang - Sun Microsystems - Beijing China 				    *(ts_ptr + 2) == 0)) {
24604b6cca3Slucy wang - Sun Microsystems - Beijing China 					return (-8);
24704b6cca3Slucy wang - Sun Microsystems - Beijing China 				}
24804b6cca3Slucy wang - Sun Microsystems - Beijing China 				lro->tsval = tsval;
24904b6cca3Slucy wang - Sun Microsystems - Beijing China 				lro->tsecr = *(ts_ptr + 2);
25004b6cca3Slucy wang - Sun Microsystems - Beijing China 			}
25104b6cca3Slucy wang - Sun Microsystems - Beijing China 
25204b6cca3Slucy wang - Sun Microsystems - Beijing China 			lro->next_seq += tcp_data_len;
25304b6cca3Slucy wang - Sun Microsystems - Beijing China 			lro->ack_seq = tcp->th_ack;
25404b6cca3Slucy wang - Sun Microsystems - Beijing China 			lro->window = tcp->th_win;
25504b6cca3Slucy wang - Sun Microsystems - Beijing China 			lro->flags |= tcp->th_flags;
25604b6cca3Slucy wang - Sun Microsystems - Beijing China 			lro->append_cnt++;
25704b6cca3Slucy wang - Sun Microsystems - Beijing China 			if (tcp_data_len == 0) {
25804b6cca3Slucy wang - Sun Microsystems - Beijing China 				freeb(m_head);
25904b6cca3Slucy wang - Sun Microsystems - Beijing China 				return (0);
26004b6cca3Slucy wang - Sun Microsystems - Beijing China 			}
26104b6cca3Slucy wang - Sun Microsystems - Beijing China 			/*
26204b6cca3Slucy wang - Sun Microsystems - Beijing China 			 * subtract off the checksum of the tcp header
26304b6cca3Slucy wang - Sun Microsystems - Beijing China 			 * from the hardware checksum, and add it to
26404b6cca3Slucy wang - Sun Microsystems - Beijing China 			 * the stored tcp data checksum.  Byteswap
26504b6cca3Slucy wang - Sun Microsystems - Beijing China 			 * the checksum if the total length so far is
26604b6cca3Slucy wang - Sun Microsystems - Beijing China 			 * odd
26704b6cca3Slucy wang - Sun Microsystems - Beijing China 			 */
26804b6cca3Slucy wang - Sun Microsystems - Beijing China 			tmp_csum = myri10ge_csum_generic((uint16_t *)tcp,
26904b6cca3Slucy wang - Sun Microsystems - Beijing China 			    tcp_hdr_len);
27004b6cca3Slucy wang - Sun Microsystems - Beijing China 			csum = csum + (tmp_csum ^ 0xffff);
27104b6cca3Slucy wang - Sun Microsystems - Beijing China 			csum = (csum & 0xffff) + (csum >> 16);
27204b6cca3Slucy wang - Sun Microsystems - Beijing China 			csum = (csum & 0xffff) + (csum >> 16);
27304b6cca3Slucy wang - Sun Microsystems - Beijing China 			if (lro->len & 0x1) {
27404b6cca3Slucy wang - Sun Microsystems - Beijing China 				/* Odd number of bytes so far, flip bytes */
27504b6cca3Slucy wang - Sun Microsystems - Beijing China 				csum = ((csum << 8) | (csum >> 8)) & 0xffff;
27604b6cca3Slucy wang - Sun Microsystems - Beijing China 			}
27704b6cca3Slucy wang - Sun Microsystems - Beijing China 			csum = csum + lro->data_csum;
27804b6cca3Slucy wang - Sun Microsystems - Beijing China 			csum = (csum & 0xffff) + (csum >> 16);
27904b6cca3Slucy wang - Sun Microsystems - Beijing China 			csum = (csum & 0xffff) + (csum >> 16);
28004b6cca3Slucy wang - Sun Microsystems - Beijing China 			lro->data_csum = csum;
28104b6cca3Slucy wang - Sun Microsystems - Beijing China 
28204b6cca3Slucy wang - Sun Microsystems - Beijing China 			lro->len += tcp_data_len;
28304b6cca3Slucy wang - Sun Microsystems - Beijing China 
28404b6cca3Slucy wang - Sun Microsystems - Beijing China 			/*
28504b6cca3Slucy wang - Sun Microsystems - Beijing China 			 * adjust mblk so that rptr points to
28604b6cca3Slucy wang - Sun Microsystems - Beijing China 			 * the first byte of the payload
28704b6cca3Slucy wang - Sun Microsystems - Beijing China 			 */
28804b6cca3Slucy wang - Sun Microsystems - Beijing China 			m_head->b_rptr += hlen;
28904b6cca3Slucy wang - Sun Microsystems - Beijing China 			/* append mbuf chain */
29004b6cca3Slucy wang - Sun Microsystems - Beijing China 			lro->m_tail->b_cont = m_head;
29104b6cca3Slucy wang - Sun Microsystems - Beijing China 			/* advance the last pointer */
29204b6cca3Slucy wang - Sun Microsystems - Beijing China 			lro->m_tail = m_head;
29304b6cca3Slucy wang - Sun Microsystems - Beijing China 			/* flush packet if required */
29404b6cca3Slucy wang - Sun Microsystems - Beijing China 			if (lro->len > (65535 - myri10ge_mtu) ||
29504b6cca3Slucy wang - Sun Microsystems - Beijing China 			    (lro->append_cnt + 1) == myri10ge_lro_max_aggr) {
29604b6cca3Slucy wang - Sun Microsystems - Beijing China 				if (ss->lro_active == lro) {
29704b6cca3Slucy wang - Sun Microsystems - Beijing China 					ss->lro_active = lro->next;
29804b6cca3Slucy wang - Sun Microsystems - Beijing China 				} else {
29904b6cca3Slucy wang - Sun Microsystems - Beijing China 					curr = ss->lro_active;
30004b6cca3Slucy wang - Sun Microsystems - Beijing China 					while (curr->next != lro)
30104b6cca3Slucy wang - Sun Microsystems - Beijing China 						curr = curr->next;
30204b6cca3Slucy wang - Sun Microsystems - Beijing China 					curr->next = lro->next;
30304b6cca3Slucy wang - Sun Microsystems - Beijing China 				}
30404b6cca3Slucy wang - Sun Microsystems - Beijing China 				myri10ge_lro_flush(ss, lro, mbl);
30504b6cca3Slucy wang - Sun Microsystems - Beijing China 			}
30604b6cca3Slucy wang - Sun Microsystems - Beijing China 			return (0);
30704b6cca3Slucy wang - Sun Microsystems - Beijing China 		}
30804b6cca3Slucy wang - Sun Microsystems - Beijing China 	}
30904b6cca3Slucy wang - Sun Microsystems - Beijing China 
31004b6cca3Slucy wang - Sun Microsystems - Beijing China 	if (ss->lro_free == NULL)
31104b6cca3Slucy wang - Sun Microsystems - Beijing China 		return (ENOMEM);
31204b6cca3Slucy wang - Sun Microsystems - Beijing China 
31304b6cca3Slucy wang - Sun Microsystems - Beijing China 	/* start a new chain */
31404b6cca3Slucy wang - Sun Microsystems - Beijing China 	lro = ss->lro_free;
31504b6cca3Slucy wang - Sun Microsystems - Beijing China 	ss->lro_free = lro->next;
31604b6cca3Slucy wang - Sun Microsystems - Beijing China 	lro->next = ss->lro_active;
31704b6cca3Slucy wang - Sun Microsystems - Beijing China 	ss->lro_active = lro;
31804b6cca3Slucy wang - Sun Microsystems - Beijing China 	lro->source_port = tcp->th_sport;
31904b6cca3Slucy wang - Sun Microsystems - Beijing China 	lro->dest_port = tcp->th_dport;
32004b6cca3Slucy wang - Sun Microsystems - Beijing China 	lro->source_ip = ip->ip_src.s_addr;
32104b6cca3Slucy wang - Sun Microsystems - Beijing China 	lro->dest_ip = ip->ip_dst.s_addr;
32204b6cca3Slucy wang - Sun Microsystems - Beijing China 	lro->next_seq = seq + tcp_data_len;
32304b6cca3Slucy wang - Sun Microsystems - Beijing China 	lro->mss = (uint16_t)tcp_data_len;
32404b6cca3Slucy wang - Sun Microsystems - Beijing China 	lro->ack_seq = tcp->th_ack;
32504b6cca3Slucy wang - Sun Microsystems - Beijing China 	lro->window = tcp->th_win;
32604b6cca3Slucy wang - Sun Microsystems - Beijing China 	lro->flags = tcp->th_flags;
32704b6cca3Slucy wang - Sun Microsystems - Beijing China 
32804b6cca3Slucy wang - Sun Microsystems - Beijing China 	/*
32904b6cca3Slucy wang - Sun Microsystems - Beijing China 	 * save the checksum of just the TCP payload by
33004b6cca3Slucy wang - Sun Microsystems - Beijing China 	 * subtracting off the checksum of the TCP header from
33104b6cca3Slucy wang - Sun Microsystems - Beijing China 	 * the entire hardware checksum
33204b6cca3Slucy wang - Sun Microsystems - Beijing China 	 * Since IP header checksum is correct, checksum over
33304b6cca3Slucy wang - Sun Microsystems - Beijing China 	 * the IP header is -0.  Substracting -0 is unnecessary.
33404b6cca3Slucy wang - Sun Microsystems - Beijing China 	 */
33504b6cca3Slucy wang - Sun Microsystems - Beijing China 	tmp_csum = myri10ge_csum_generic((uint16_t *)tcp, tcp_hdr_len);
33604b6cca3Slucy wang - Sun Microsystems - Beijing China 	csum = csum + (tmp_csum ^ 0xffff);
33704b6cca3Slucy wang - Sun Microsystems - Beijing China 	csum = (csum & 0xffff) + (csum >> 16);
33804b6cca3Slucy wang - Sun Microsystems - Beijing China 	csum = (csum & 0xffff) + (csum >> 16);
33904b6cca3Slucy wang - Sun Microsystems - Beijing China 	lro->data_csum = csum;
34004b6cca3Slucy wang - Sun Microsystems - Beijing China 	lro->ip = ip;
34104b6cca3Slucy wang - Sun Microsystems - Beijing China 
34204b6cca3Slucy wang - Sun Microsystems - Beijing China 	/* record timestamp if it is present */
34304b6cca3Slucy wang - Sun Microsystems - Beijing China 	if (opt_bytes) {
34404b6cca3Slucy wang - Sun Microsystems - Beijing China 		lro->timestamp = 1;
34504b6cca3Slucy wang - Sun Microsystems - Beijing China 		lro->tsval = ntohl(*(ts_ptr + 1));
34604b6cca3Slucy wang - Sun Microsystems - Beijing China 		lro->tsecr = *(ts_ptr + 2);
34704b6cca3Slucy wang - Sun Microsystems - Beijing China 	}
34804b6cca3Slucy wang - Sun Microsystems - Beijing China 	lro->len = tot_len;
34904b6cca3Slucy wang - Sun Microsystems - Beijing China 	lro->m_head = m_head;
35004b6cca3Slucy wang - Sun Microsystems - Beijing China 	lro->m_tail = m_head;
35104b6cca3Slucy wang - Sun Microsystems - Beijing China 	return (0);
35204b6cca3Slucy wang - Sun Microsystems - Beijing China }
35304b6cca3Slucy wang - Sun Microsystems - Beijing China 
35404b6cca3Slucy wang - Sun Microsystems - Beijing China /*
35504b6cca3Slucy wang - Sun Microsystems - Beijing China  *  This file uses MyriGE driver indentation.
35604b6cca3Slucy wang - Sun Microsystems - Beijing China  *
35704b6cca3Slucy wang - Sun Microsystems - Beijing China  * Local Variables:
35804b6cca3Slucy wang - Sun Microsystems - Beijing China  * c-file-style:"sun"
35904b6cca3Slucy wang - Sun Microsystems - Beijing China  * tab-width:8
36004b6cca3Slucy wang - Sun Microsystems - Beijing China  * End:
36104b6cca3Slucy wang - Sun Microsystems - Beijing China  */
362