Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 122717
b: refs/heads/master
c: bf296b1
h: refs/heads/master
i:
  122715: 20d921e
v: v3
  • Loading branch information
Herbert Xu authored and David S. Miller committed Dec 16, 2008
1 parent df1a163 commit 2e76a6d
Show file tree
Hide file tree
Showing 5 changed files with 144 additions and 1 deletion.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 71d93b39e52e92aea35f1058d957cf12250d0b75
refs/heads/master: bf296b125b21b8d558ceb6ec30bb4eba2730cd6b
6 changes: 6 additions & 0 deletions trunk/include/net/tcp.h
Original file line number Diff line number Diff line change
Expand Up @@ -1358,6 +1358,12 @@ extern void tcp_v4_destroy_sock(struct sock *sk);

extern int tcp_v4_gso_send_check(struct sk_buff *skb);
extern struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int features);
extern struct sk_buff **tcp_gro_receive(struct sk_buff **head,
struct sk_buff *skb);
extern struct sk_buff **tcp4_gro_receive(struct sk_buff **head,
struct sk_buff *skb);
extern int tcp_gro_complete(struct sk_buff *skb);
extern int tcp4_gro_complete(struct sk_buff *skb);

#ifdef CONFIG_PROC_FS
extern int tcp4_proc_init(void);
Expand Down
2 changes: 2 additions & 0 deletions trunk/net/ipv4/af_inet.c
Original file line number Diff line number Diff line change
Expand Up @@ -1410,6 +1410,8 @@ static struct net_protocol tcp_protocol = {
.err_handler = tcp_v4_err,
.gso_send_check = tcp_v4_gso_send_check,
.gso_segment = tcp_tso_segment,
.gro_receive = tcp4_gro_receive,
.gro_complete = tcp4_gro_complete,
.no_policy = 1,
.netns_ok = 1,
};
Expand Down
100 changes: 100 additions & 0 deletions trunk/net/ipv4/tcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -2465,6 +2465,106 @@ struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int features)
}
EXPORT_SYMBOL(tcp_tso_segment);

struct sk_buff **tcp_gro_receive(struct sk_buff **head, struct sk_buff *skb)
{
struct sk_buff **pp = NULL;
struct sk_buff *p;
struct tcphdr *th;
struct tcphdr *th2;
unsigned int thlen;
unsigned int flags;
unsigned int total;
unsigned int mss = 1;
int flush = 1;

if (!pskb_may_pull(skb, sizeof(*th)))
goto out;

th = tcp_hdr(skb);
thlen = th->doff * 4;
if (thlen < sizeof(*th))
goto out;

if (!pskb_may_pull(skb, thlen))
goto out;

th = tcp_hdr(skb);
__skb_pull(skb, thlen);

flags = tcp_flag_word(th);

for (; (p = *head); head = &p->next) {
if (!NAPI_GRO_CB(p)->same_flow)
continue;

th2 = tcp_hdr(p);

if (th->source != th2->source || th->dest != th2->dest) {
NAPI_GRO_CB(p)->same_flow = 0;
continue;
}

goto found;
}

goto out_check_final;

found:
flush = NAPI_GRO_CB(p)->flush;
flush |= flags & TCP_FLAG_CWR;
flush |= (flags ^ tcp_flag_word(th2)) &
~(TCP_FLAG_CWR | TCP_FLAG_FIN | TCP_FLAG_PSH);
flush |= th->ack_seq != th2->ack_seq || th->window != th2->window;
flush |= memcmp(th + 1, th2 + 1, thlen - sizeof(*th));

total = p->len;
mss = total;
if (skb_shinfo(p)->frag_list)
mss = skb_shinfo(p)->frag_list->len;

flush |= skb->len > mss || skb->len <= 0;
flush |= ntohl(th2->seq) + total != ntohl(th->seq);

if (flush || skb_gro_receive(head, skb)) {
mss = 1;
goto out_check_final;
}

p = *head;
th2 = tcp_hdr(p);
tcp_flag_word(th2) |= flags & (TCP_FLAG_FIN | TCP_FLAG_PSH);

out_check_final:
flush = skb->len < mss;
flush |= flags & (TCP_FLAG_URG | TCP_FLAG_PSH | TCP_FLAG_RST |
TCP_FLAG_SYN | TCP_FLAG_FIN);

if (p && (!NAPI_GRO_CB(skb)->same_flow || flush))
pp = head;

out:
NAPI_GRO_CB(skb)->flush |= flush;

return pp;
}

int tcp_gro_complete(struct sk_buff *skb)
{
struct tcphdr *th = tcp_hdr(skb);

skb->csum_start = skb_transport_header(skb) - skb->head;
skb->csum_offset = offsetof(struct tcphdr, check);
skb->ip_summed = CHECKSUM_PARTIAL;

skb_shinfo(skb)->gso_size = skb_shinfo(skb)->frag_list->len;
skb_shinfo(skb)->gso_segs = NAPI_GRO_CB(skb)->count;

if (th->cwr)
skb_shinfo(skb)->gso_type |= SKB_GSO_TCP_ECN;

return 0;
}

#ifdef CONFIG_TCP_MD5SIG
static unsigned long tcp_md5sig_users;
static struct tcp_md5sig_pool **tcp_md5sig_pool;
Expand Down
35 changes: 35 additions & 0 deletions trunk/net/ipv4/tcp_ipv4.c
Original file line number Diff line number Diff line change
Expand Up @@ -2346,6 +2346,41 @@ void tcp4_proc_exit(void)
}
#endif /* CONFIG_PROC_FS */

struct sk_buff **tcp4_gro_receive(struct sk_buff **head, struct sk_buff *skb)
{
struct iphdr *iph = ip_hdr(skb);

switch (skb->ip_summed) {
case CHECKSUM_COMPLETE:
if (!tcp_v4_check(skb->len, iph->saddr, iph->daddr,
skb->csum)) {
skb->ip_summed = CHECKSUM_UNNECESSARY;
break;
}

/* fall through */
case CHECKSUM_NONE:
NAPI_GRO_CB(skb)->flush = 1;
return NULL;
}

return tcp_gro_receive(head, skb);
}
EXPORT_SYMBOL(tcp4_gro_receive);

int tcp4_gro_complete(struct sk_buff *skb)
{
struct iphdr *iph = ip_hdr(skb);
struct tcphdr *th = tcp_hdr(skb);

th->check = ~tcp_v4_check(skb->len - skb_transport_offset(skb),
iph->saddr, iph->daddr, 0);
skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;

return tcp_gro_complete(skb);
}
EXPORT_SYMBOL(tcp4_gro_complete);

struct proto tcp_prot = {
.name = "TCP",
.owner = THIS_MODULE,
Expand Down

0 comments on commit 2e76a6d

Please sign in to comment.