diff options
author | Herbert Xu <herbert@gondor.apana.org.au> | 2006-06-22 06:02:40 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-06-23 05:07:33 -0400 |
commit | f4c50d990dcf11a296679dc05de3873783236711 (patch) | |
tree | f4daf1c80fe591d45631e998b0b5d31d6fe76d85 /net/ipv4/af_inet.c | |
parent | f6a78bfcb141f963187464bac838d46a81c3882a (diff) |
[NET]: Add software TSOv4
This patch adds the GSO implementation for IPv4 TCP.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/af_inet.c')
-rw-r--r-- | net/ipv4/af_inet.c | 51 |
1 files changed, 51 insertions, 0 deletions
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 0a277453526b..461216b47948 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c | |||
@@ -68,6 +68,7 @@ | |||
68 | */ | 68 | */ |
69 | 69 | ||
70 | #include <linux/config.h> | 70 | #include <linux/config.h> |
71 | #include <linux/err.h> | ||
71 | #include <linux/errno.h> | 72 | #include <linux/errno.h> |
72 | #include <linux/types.h> | 73 | #include <linux/types.h> |
73 | #include <linux/socket.h> | 74 | #include <linux/socket.h> |
@@ -1096,6 +1097,54 @@ int inet_sk_rebuild_header(struct sock *sk) | |||
1096 | 1097 | ||
1097 | EXPORT_SYMBOL(inet_sk_rebuild_header); | 1098 | EXPORT_SYMBOL(inet_sk_rebuild_header); |
1098 | 1099 | ||
1100 | static struct sk_buff *inet_gso_segment(struct sk_buff *skb, int sg) | ||
1101 | { | ||
1102 | struct sk_buff *segs = ERR_PTR(-EINVAL); | ||
1103 | struct iphdr *iph; | ||
1104 | struct net_protocol *ops; | ||
1105 | int proto; | ||
1106 | int ihl; | ||
1107 | int id; | ||
1108 | |||
1109 | if (!pskb_may_pull(skb, sizeof(*iph))) | ||
1110 | goto out; | ||
1111 | |||
1112 | iph = skb->nh.iph; | ||
1113 | ihl = iph->ihl * 4; | ||
1114 | if (ihl < sizeof(*iph)) | ||
1115 | goto out; | ||
1116 | |||
1117 | if (!pskb_may_pull(skb, ihl)) | ||
1118 | goto out; | ||
1119 | |||
1120 | skb->h.raw = __skb_pull(skb, ihl); | ||
1121 | iph = skb->nh.iph; | ||
1122 | id = ntohs(iph->id); | ||
1123 | proto = iph->protocol & (MAX_INET_PROTOS - 1); | ||
1124 | segs = ERR_PTR(-EPROTONOSUPPORT); | ||
1125 | |||
1126 | rcu_read_lock(); | ||
1127 | ops = rcu_dereference(inet_protos[proto]); | ||
1128 | if (ops && ops->gso_segment) | ||
1129 | segs = ops->gso_segment(skb, sg); | ||
1130 | rcu_read_unlock(); | ||
1131 | |||
1132 | if (IS_ERR(segs)) | ||
1133 | goto out; | ||
1134 | |||
1135 | skb = segs; | ||
1136 | do { | ||
1137 | iph = skb->nh.iph; | ||
1138 | iph->id = htons(id++); | ||
1139 | iph->tot_len = htons(skb->len - skb->mac_len); | ||
1140 | iph->check = 0; | ||
1141 | iph->check = ip_fast_csum(skb->nh.raw, iph->ihl); | ||
1142 | } while ((skb = skb->next)); | ||
1143 | |||
1144 | out: | ||
1145 | return segs; | ||
1146 | } | ||
1147 | |||
1099 | #ifdef CONFIG_IP_MULTICAST | 1148 | #ifdef CONFIG_IP_MULTICAST |
1100 | static struct net_protocol igmp_protocol = { | 1149 | static struct net_protocol igmp_protocol = { |
1101 | .handler = igmp_rcv, | 1150 | .handler = igmp_rcv, |
@@ -1105,6 +1154,7 @@ static struct net_protocol igmp_protocol = { | |||
1105 | static struct net_protocol tcp_protocol = { | 1154 | static struct net_protocol tcp_protocol = { |
1106 | .handler = tcp_v4_rcv, | 1155 | .handler = tcp_v4_rcv, |
1107 | .err_handler = tcp_v4_err, | 1156 | .err_handler = tcp_v4_err, |
1157 | .gso_segment = tcp_tso_segment, | ||
1108 | .no_policy = 1, | 1158 | .no_policy = 1, |
1109 | }; | 1159 | }; |
1110 | 1160 | ||
@@ -1150,6 +1200,7 @@ static int ipv4_proc_init(void); | |||
1150 | static struct packet_type ip_packet_type = { | 1200 | static struct packet_type ip_packet_type = { |
1151 | .type = __constant_htons(ETH_P_IP), | 1201 | .type = __constant_htons(ETH_P_IP), |
1152 | .func = ip_rcv, | 1202 | .func = ip_rcv, |
1203 | .gso_segment = inet_gso_segment, | ||
1153 | }; | 1204 | }; |
1154 | 1205 | ||
1155 | static int __init inet_init(void) | 1206 | static int __init inet_init(void) |