29 #include <linux/module.h>
30 #include <linux/if_vlan.h>
37 #define TCP_HDR_LEN(tcph) (tcph->doff << 2)
38 #define IP_HDR_LEN(iph) (iph->ihl << 2)
39 #define TCP_PAYLOAD_LENGTH(iph, tcph) \
40 (ntohs(iph->tot_len) - IP_HDR_LEN(iph) - TCP_HDR_LEN(tcph))
42 #define IPH_LEN_WO_OPTIONS 5
43 #define TCPH_LEN_WO_OPTIONS 5
44 #define TCPH_LEN_W_TIMESTAMP 8
46 #define LRO_MAX_PG_HLEN 64
48 #define LRO_INC_STATS(lro_mgr, attr) { lro_mgr->stats.attr++; }
54 static int lro_tcp_ip_check(
const struct iphdr *iph,
const struct tcphdr *tcph,
67 if (tcph->cwr || tcph->ece || tcph->urg || !tcph->ack ||
68 tcph->rst || tcph->syn || tcph->fin)
71 if (INET_ECN_is_ce(ipv4_get_dsfield(iph)))
102 static void lro_update_tcp_ip_header(
struct net_lro_desc *lro_desc)
137 tcp_csum = ~csum_unfold(tcph->
check);
144 return csum_sub(csum_sub(tcp_csum, tcp_hdr_csum),
155 nr_frags = skb_shinfo(skb)->nr_frags;
157 lro_desc->
next_frag = &(skb_shinfo(skb)->frags[nr_frags]);
159 lro_desc->
tcph = tcph;
167 if (tcph->doff == 8) {
174 lro_desc->
mss = tcp_data_len;
177 lro_desc->
data_csum = lro_tcp_data_csum(iph, tcph,
181 static inline void lro_clear_desc(
struct net_lro_desc *lro_desc)
187 struct tcphdr *tcph,
int tcp_data_len)
200 topt = (
__be32 *) (tcph + 1);
205 lro_tcp_data_csum(iph, tcph,
209 parent->
len += tcp_data_len;
211 if (tcp_data_len > lro_desc->
mss)
212 lro_desc->
mss = tcp_data_len;
221 lro_add_common(lro_desc, iph, tcph, tcp_data_len);
229 skb_shinfo(parent)->frag_list =
skb;
234 static void lro_add_frags(
struct net_lro_desc *lro_desc,
242 lro_add_common(lro_desc, iph, tcph, tcp_data_len);
247 skb_frag_size_sub(&skb_frags[0], hlen);
249 while (tcp_data_len > 0) {
251 tcp_data_len -= skb_frag_size(skb_frags);
254 skb_shinfo(skb)->nr_frags++;
258 static int lro_check_tcp_conn(
struct net_lro_desc *lro_desc,
262 if ((lro_desc->
iph->saddr != iph->
saddr) ||
263 (lro_desc->
iph->daddr != iph->
daddr) ||
265 (lro_desc->
tcph->dest != tcph->
dest))
280 for (i = 0; i < max_desc; i++) {
283 if (!lro_check_tcp_conn(tmp, iph, tcph)) {
289 for (i = 0; i < max_desc; i++) {
291 lro_desc = &lro_arr[
i];
305 lro_update_tcp_ip_header(lro_desc);
307 skb_shinfo(lro_desc->
parent)->gso_size = lro_desc->
mss;
315 lro_clear_desc(lro_desc);
325 int vlan_hdr_len = 0;
335 lro_desc = lro_get_desc(lro_mgr, lro_mgr->
lro_arr, iph, tcph);
344 if (lro_tcp_ip_check(iph, tcph, skb->
len - vlan_hdr_len,
NULL))
348 lro_init_desc(lro_desc, skb, iph, tcph);
356 if (lro_tcp_ip_check(iph, tcph, skb->
len, lro_desc))
359 lro_add_packet(lro_desc, skb, iph, tcph);
363 lro_desc->
parent->len > (0xFFFF - lro_mgr->
dev->mtu))
364 lro_flush(lro_mgr, lro_desc);
369 lro_flush(lro_mgr, lro_desc);
378 int len,
int true_size,
400 skb_frags = skb_shinfo(skb)->frags;
401 while (data_len > 0) {
403 data_len -= skb_frag_size(frags);
406 skb_shinfo(skb)->nr_frags++;
410 skb_frag_size_sub(&skb_shinfo(skb)->frags[0], hdr_len);
420 int len,
int true_size,
431 int vlan_hdr_len = 0;
435 (
void *)&tcph, &flags, priv)) {
436 mac_hdr = skb_frag_address(frags);
440 if (!(flags & LRO_IPV4) || !(flags &
LRO_TCP))
444 mac_hdr_len = (
int)((
void *)(iph) - mac_hdr);
446 lro_desc = lro_get_desc(lro_mgr, lro_mgr->
lro_arr, iph, tcph);
451 if (lro_tcp_ip_check(iph, tcph, len - mac_hdr_len,
NULL))
454 skb = lro_gen_skb(lro_mgr, frags, len, true_size, mac_hdr,
463 iph = (
void *)(skb->
data + vlan_hdr_len);
464 tcph = (
void *)((
u8 *)skb->
data + vlan_hdr_len
467 lro_init_desc(lro_desc, skb, iph, tcph);
475 if (lro_tcp_ip_check(iph, tcph, len - mac_hdr_len, lro_desc))
478 lro_add_frags(lro_desc, len, hdr_len, true_size, frags, iph, tcph);
481 if ((skb_shinfo(lro_desc->
parent)->nr_frags >= lro_mgr->
max_aggr) ||
482 lro_desc->
parent->len > (0xFFFF - lro_mgr->
dev->mtu))
483 lro_flush(lro_mgr, lro_desc);
488 lro_flush(lro_mgr, lro_desc);
491 skb = lro_gen_skb(lro_mgr, frags, len, true_size, mac_hdr,
501 if (__lro_proc_skb(lro_mgr, skb, priv)) {
512 int len,
int true_size,
void *priv,
__wsum sum)
516 skb = __lro_proc_segment(lro_mgr, frags, len, true_size, priv, sum);
532 for (i = 0; i < lro_mgr->
max_desc; i++) {
534 lro_flush(lro_mgr, &lro_desc[i]);
544 lro_desc = lro_get_desc(lro_mgr, lro_mgr->
lro_arr, iph, tcph);
546 lro_flush(lro_mgr, lro_desc);