patch-2.4.4 linux/net/ipv6/tcp_ipv6.c
Next file: linux/net/ipv6/udp.c
Previous file: linux/net/ipv6/sit.c
Back to the patch index
Back to the overall index
- Lines: 284
- Date:
Wed Apr 25 14:57:39 2001
- Orig file:
v2.4.3/linux/net/ipv6/tcp_ipv6.c
- Orig date:
Sun Mar 25 18:14:25 2001
diff -u --recursive --new-file v2.4.3/linux/net/ipv6/tcp_ipv6.c linux/net/ipv6/tcp_ipv6.c
@@ -5,7 +5,7 @@
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: tcp_ipv6.c,v 1.128 2000/12/08 17:15:54 davem Exp $
+ * $Id: tcp_ipv6.c,v 1.136 2001/04/20 20:46:19 davem Exp $
*
* Based on:
* linux/net/ipv4/tcp.c
@@ -635,6 +635,7 @@
}
ip6_dst_store(sk, dst, NULL);
+ sk->route_caps = dst->dev->features&~NETIF_F_IP_CSUM;
if (saddr == NULL) {
err = ipv6_get_saddr(dst, &np->daddr, &saddr_buf);
@@ -678,25 +679,23 @@
failure:
__sk_dst_reset(sk);
sk->dport = 0;
+ sk->route_caps = 0;
return err;
}
-void tcp_v6_err(struct sk_buff *skb, struct ipv6hdr *hdr,
- struct inet6_skb_parm *opt,
- int type, int code, unsigned char *header, __u32 info)
+void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+ int type, int code, int offset, __u32 info)
{
+ struct ipv6hdr *hdr = (struct ipv6hdr*)skb->data;
struct in6_addr *saddr = &hdr->saddr;
struct in6_addr *daddr = &hdr->daddr;
- struct tcphdr *th = (struct tcphdr *)header;
+ struct tcphdr *th = (struct tcphdr *)(skb->data+offset);
struct ipv6_pinfo *np;
struct sock *sk;
int err;
struct tcp_opt *tp;
__u32 seq;
- if (header + 8 > skb->tail)
- return;
-
sk = tcp_v6_lookup(daddr, th->dest, saddr, th->source, skb->dev->ifindex);
if (sk == NULL) {
@@ -914,10 +913,15 @@
struct sk_buff *skb)
{
struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
-
- th->check = csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP,
- csum_partial((char *)th, th->doff<<2,
- skb->csum));
+
+ if (skb->ip_summed == CHECKSUM_HW) {
+ th->check = csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP, 0);
+ skb->csum = offsetof(struct tcphdr, check);
+ } else {
+ th->check = csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP,
+ csum_partial((char *)th, th->doff<<2,
+ skb->csum));
+ }
}
@@ -1298,6 +1302,7 @@
MOD_INC_USE_COUNT;
ip6_dst_store(newsk, dst, NULL);
+ sk->route_caps = dst->dev->features&~NETIF_F_IP_CSUM;
newtp = &(newsk->tp_pinfo.af_tcp);
@@ -1371,22 +1376,20 @@
static int tcp_v6_checksum_init(struct sk_buff *skb)
{
if (skb->ip_summed == CHECKSUM_HW) {
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ if (!tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr,
+ &skb->nh.ipv6h->daddr,skb->csum))
+ return 0;
+ NETDEBUG(printk(KERN_DEBUG "hw tcp v6 csum failed\n"));
+ }
+ if (skb->len <= 76) {
if (tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr,
- &skb->nh.ipv6h->daddr,skb->csum)) {
- NETDEBUG(printk(KERN_DEBUG "hw tcp v6 csum failed\n"));
+ &skb->nh.ipv6h->daddr,skb_checksum(skb, 0, skb->len, 0)))
return -1;
- }
skb->ip_summed = CHECKSUM_UNNECESSARY;
} else {
- if (skb->len <= 76) {
- if (tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr,
- &skb->nh.ipv6h->daddr,csum_partial((char *)skb->h.th, skb->len, 0)))
- return -1;
- skb->ip_summed = CHECKSUM_UNNECESSARY;
- } else {
- skb->csum = ~tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr,
- &skb->nh.ipv6h->daddr,0);
- }
+ skb->csum = ~tcp_v6_check(skb->h.th,skb->len,&skb->nh.ipv6h->saddr,
+ &skb->nh.ipv6h->daddr,0);
}
return 0;
}
@@ -1526,46 +1529,45 @@
return 0;
}
-int tcp_v6_rcv(struct sk_buff *skb, unsigned long len)
+int tcp_v6_rcv(struct sk_buff *skb)
{
struct tcphdr *th;
struct sock *sk;
- struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
- struct in6_addr *daddr = &skb->nh.ipv6h->daddr;
int ret;
- th = skb->h.th;
-
if (skb->pkt_type != PACKET_HOST)
goto discard_it;
/*
- * Pull up the IP header.
+ * Count it even if it's bad.
*/
+ TCP_INC_STATS_BH(TcpInSegs);
- __skb_pull(skb, skb->h.raw - skb->data);
+ if (!pskb_may_pull(skb, sizeof(struct tcphdr)))
+ goto discard_it;
- /*
- * Count it even if it's bad.
- */
+ th = skb->h.th;
- TCP_INC_STATS_BH(TcpInSegs);
+ if (th->doff < sizeof(struct tcphdr)/4)
+ goto bad_packet;
+ if (!pskb_may_pull(skb, th->doff*4))
+ goto discard_it;
- if (th->doff < sizeof(struct tcphdr)/4 ||
- (skb->ip_summed != CHECKSUM_UNNECESSARY &&
+ if ((skb->ip_summed != CHECKSUM_UNNECESSARY &&
tcp_v6_checksum_init(skb) < 0))
goto bad_packet;
+ th = skb->h.th;
TCP_SKB_CB(skb)->seq = ntohl(th->seq);
TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin +
- len - th->doff*4);
+ skb->len - th->doff*4);
TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq);
TCP_SKB_CB(skb)->when = 0;
TCP_SKB_CB(skb)->flags = ip6_get_dsfield(skb->nh.ipv6h);
TCP_SKB_CB(skb)->sacked = 0;
- skb->used = 0;
- sk = __tcp_v6_lookup(saddr, th->source, daddr, ntohs(th->dest), tcp_v6_iif(skb));
+ sk = __tcp_v6_lookup(&skb->nh.ipv6h->saddr, th->source,
+ &skb->nh.ipv6h->daddr, ntohs(th->dest), tcp_v6_iif(skb));
if (!sk)
goto no_tcp_socket;
@@ -1591,7 +1593,7 @@
return ret;
no_tcp_socket:
- if (len < (th->doff<<2) || tcp_checksum_complete(skb)) {
+ if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) {
bad_packet:
TCP_INC_STATS_BH(TcpInErrs);
} else {
@@ -1612,7 +1614,7 @@
goto discard_it;
do_time_wait:
- if (len < (th->doff<<2) || tcp_checksum_complete(skb)) {
+ if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) {
TCP_INC_STATS_BH(TcpInErrs);
sock_put(sk);
goto discard_it;
@@ -1673,10 +1675,12 @@
if (dst->error) {
err = dst->error;
dst_release(dst);
+ sk->route_caps = 0;
return err;
}
ip6_dst_store(sk, dst, NULL);
+ sk->route_caps = dst->dev->features&~NETIF_F_IP_CSUM;
}
return 0;
@@ -1819,6 +1823,7 @@
sk->tp_pinfo.af_tcp.af_specific = &ipv6_specific;
sk->write_space = tcp_write_space;
+ sk->use_write_queue = 1;
sk->sndbuf = sysctl_tcp_wmem[1];
sk->rcvbuf = sysctl_tcp_rmem[1];
@@ -1837,7 +1842,7 @@
/* Cleanup up the write buffer. */
tcp_writequeue_purge(sk);
- /* Cleans up our, hopefuly empty, out_of_order_queue. */
+ /* Cleans up our, hopefully empty, out_of_order_queue. */
__skb_queue_purge(&tp->out_of_order_queue);
/* Clean prequeue, it must be empty really */
@@ -1847,6 +1852,10 @@
if(sk->prev != NULL)
tcp_put_port(sk);
+ /* If sendmsg cached page exists, toss it. */
+ if (tp->sndmsg_page != NULL)
+ __free_page(tp->sndmsg_page);
+
atomic_dec(&tcp_sockets_allocated);
return inet6_destroy_sock(sk);
@@ -1967,7 +1976,7 @@
off_t begin, pos = 0;
char tmpbuf[LINE_LEN+2];
- if(offset < LINE_LEN+1)
+ if (offset < LINE_LEN+1)
len += sprintf(buffer, LINE_FMT,
" sl " /* 6 */
"local_address " /* 38 */
@@ -1997,7 +2006,7 @@
if (pos >= offset) {
get_tcp6_sock(sk, tmpbuf, num);
len += sprintf(buffer+len, LINE_FMT, tmpbuf);
- if (len >= length) {
+ if (pos >= offset + length) {
tcp_listen_unlock();
goto out_no_bh;
}
@@ -2016,7 +2025,7 @@
continue;
get_openreq6(sk, req, tmpbuf, num, uid);
len += sprintf(buffer+len, LINE_FMT, tmpbuf);
- if(len >= length) {
+ if (pos >= offset + length) {
read_unlock_bh(&tp->syn_wait_lock);
tcp_listen_unlock();
goto out_no_bh;
@@ -2048,7 +2057,7 @@
continue;
get_tcp6_sock(sk, tmpbuf, num);
len += sprintf(buffer+len, LINE_FMT, tmpbuf);
- if(len >= length) {
+ if (pos >= offset + length) {
read_unlock(&head->lock);
goto out;
}
@@ -2063,7 +2072,7 @@
continue;
get_timewait6_sock(tw, tmpbuf, num);
len += sprintf(buffer+len, LINE_FMT, tmpbuf);
- if(len >= length) {
+ if (pos >= offset + length) {
read_unlock(&head->lock);
goto out;
}
@@ -2078,7 +2087,7 @@
begin = len - (pos - offset);
*start = buffer + begin;
len -= begin;
- if(len > length)
+ if (len > length)
len = length;
if (len < 0)
len = 0;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)