patch-2.1.30 linux/net/ipv6/tcp_ipv6.c
Next file: linux/net/ipv6/udp.c
Previous file: linux/net/ipv6/sysctl_net_ipv6.c
Back to the patch index
Back to the overall index
- Lines: 1221
- Date:
Thu Mar 20 18:17:15 1997
- Orig file:
v2.1.29/linux/net/ipv6/tcp_ipv6.c
- Orig date:
Tue Mar 4 10:25:27 1997
diff -u --recursive --new-file v2.1.29/linux/net/ipv6/tcp_ipv6.c linux/net/ipv6/tcp_ipv6.c
@@ -5,7 +5,7 @@
* Authors:
* Pedro Roque <[email protected]>
*
- * $Id: tcp_ipv6.c,v 1.11 1997/03/03 18:27:31 davem Exp $
+ * $Id: tcp_ipv6.c,v 1.15 1997/03/18 18:24:56 davem Exp $
*
* Based on:
* linux/net/ipv4/tcp.c
@@ -37,20 +37,22 @@
#include <net/ipv6.h>
#include <net/transp_v6.h>
#include <net/addrconf.h>
-#include <net/ipv6_route.h>
+#include <net/ip6_route.h>
#include <asm/uaccess.h>
-static void tcp_v6_send_reset(struct in6_addr *saddr, struct in6_addr *daddr,
- struct tcphdr *th, struct proto *prot,
- struct ipv6_options *opt,
- struct device *dev, int pri, int hop_limit);
-
-static void tcp_v6_send_check(struct sock *sk, struct tcphdr *th, int len,
- struct sk_buff *skb);
-
-static int tcp_v6_backlog_rcv(struct sock *sk, struct sk_buff *skb);
-static int tcp_v6_build_header(struct sock *sk, struct sk_buff *skb);
+static void tcp_v6_send_reset(struct in6_addr *saddr,
+ struct in6_addr *daddr,
+ struct tcphdr *th, struct proto *prot,
+ struct ipv6_options *opt,
+ struct device *dev, int pri, int hop_limit);
+
+static void tcp_v6_send_check(struct sock *sk, struct tcphdr *th, int len,
+ struct sk_buff *skb);
+
+static int tcp_v6_backlog_rcv(struct sock *sk, struct sk_buff *skb);
+static int tcp_v6_build_header(struct sock *sk, struct sk_buff *skb);
+static void tcp_v6_xmit(struct sk_buff *skb);
static struct tcp_func ipv6_mapped;
static struct tcp_func ipv6_specific;
@@ -86,14 +88,14 @@
SOCKHASH_LOCK();
sk2 = tcp_bound_hash[tcp_sk_bhashfn(sk)];
- for(; sk2 != NULL; sk2 = sk2->prev) {
+ for(; sk2 != NULL; sk2 = sk2->bind_next) {
if((sk2->num == snum) && (sk2 != sk)) {
unsigned char state = sk2->state;
int sk2_reuse = sk2->reuse;
if(addr_type == IPV6_ADDR_ANY || (!sk2->rcv_saddr)) {
if((!sk2_reuse) ||
(!sk_reuse) ||
- (state != TCP_LISTEN)) {
+ (state == TCP_LISTEN)) {
retval = 1;
break;
}
@@ -120,18 +122,16 @@
SOCKHASH_LOCK();
state = sk->state;
if(state != TCP_CLOSE) {
- struct sock **htable;
+ struct sock **skp;
- if(state == TCP_LISTEN) {
- sk->hashent = tcp_sk_listen_hashfn(sk);
- htable = &tcp_listening_hash[0];
- } else {
- sk->hashent = tcp_v6_sk_hashfn(sk);
- htable = &tcp_established_hash[0];
- }
- sk->next = htable[sk->hashent];
- htable[sk->hashent] = sk;
- sk->hashtable = htable;
+ if(state == TCP_LISTEN)
+ skp = &tcp_listening_hash[tcp_sk_listen_hashfn(sk)];
+ else
+ skp = &tcp_established_hash[tcp_v6_sk_hashfn(sk)];
+ if((sk->next = *skp) != NULL)
+ (*skp)->pprev = &sk->next;
+ *skp = sk;
+ sk->pprev = skp;
tcp_sk_bindify(sk);
}
SOCKHASH_UNLOCK();
@@ -139,20 +139,12 @@
static void tcp_v6_unhash(struct sock *sk)
{
- struct sock **htable;
-
SOCKHASH_LOCK();
- htable = sk->hashtable;
- if(htable) {
- struct sock **skp = &(htable[sk->hashent]);
- while(*skp != NULL) {
- if(*skp == sk) {
- *skp = sk->next;
- break;
- }
- skp = &((*skp)->next);
- }
- sk->hashtable = NULL;
+ if(sk->pprev) {
+ if(sk->next)
+ sk->next->pprev = sk->pprev;
+ *sk->pprev = sk->next;
+ sk->pprev = NULL;
tcp_sk_unbindify(sk);
}
SOCKHASH_UNLOCK();
@@ -160,36 +152,31 @@
static void tcp_v6_rehash(struct sock *sk)
{
- struct sock **htable;
unsigned char state;
SOCKHASH_LOCK();
- htable = &(sk->hashtable[sk->hashent]);
state = sk->state;
- if(htable) {
- while(*htable != NULL) {
- if(*htable == sk) {
- *htable = sk->next;
- break;
- }
- htable = &((*htable)->next);
- }
+ if(sk->pprev) {
+ if(sk->next)
+ sk->next->pprev = sk->pprev;
+ *sk->pprev = sk->next;
+ sk->pprev = NULL;
+ tcp_sk_unbindify(sk);
}
- htable = NULL;
if(state != TCP_CLOSE) {
- if(state == TCP_LISTEN) {
- sk->hashent = tcp_sk_listen_hashfn(sk);
- htable = &tcp_listening_hash[0];
- } else {
- sk->hashent = tcp_v6_sk_hashfn(sk);
- htable = &tcp_established_hash[0];
- }
- sk->next = htable[sk->hashent];
- htable[sk->hashent] = sk;
- } else {
- tcp_sk_unbindify(sk);
+ struct sock **skp;
+
+ if(state == TCP_LISTEN)
+ skp = &tcp_listening_hash[tcp_sk_listen_hashfn(sk)];
+ else
+ skp = &tcp_established_hash[tcp_v6_sk_hashfn(sk)];
+
+ if((sk->next = *skp) != NULL)
+ (*skp)->pprev = &sk->next;
+ *skp = sk;
+ sk->pprev = skp;
+ tcp_sk_bindify(sk);
}
- sk->hashtable = htable;
SOCKHASH_UNLOCK();
}
@@ -254,13 +241,10 @@
__u32 si;
__u32 di;
- if (skb->protocol == __constant_htons(ETH_P_IPV6))
- {
+ if (skb->protocol == __constant_htons(ETH_P_IPV6)) {
si = skb->nh.ipv6h->saddr.s6_addr32[3];
di = skb->nh.ipv6h->daddr.s6_addr32[3];
- }
- else
- {
+ } else {
si = skb->nh.iph->saddr;
di = skb->nh.iph->daddr;
}
@@ -276,14 +260,15 @@
struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr;
struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
- struct dest_entry *dc;
struct inet6_ifaddr *ifa;
+ struct in6_addr *saddr = NULL;
+ struct flowi fl;
+ struct dst_entry *dst;
struct tcphdr *th;
- __u8 *ptr;
struct sk_buff *buff;
struct sk_buff *skb1;
+ __u8 *ptr;
int addr_type;
- int tmp;
if (sk->state != TCP_CLOSE)
return(-EISCONN);
@@ -311,9 +296,7 @@
addr_type = ipv6_addr_type(&usin->sin6_addr);
if(addr_type & IPV6_ADDR_MULTICAST)
- {
return -ENETUNREACH;
- }
/*
* connect to self not allowed
@@ -321,9 +304,7 @@
if (ipv6_addr_cmp(&usin->sin6_addr, &np->saddr) == 0 &&
usin->sin6_port == sk->dummy_th.source)
- {
return (-EINVAL);
- }
memcpy(&np->daddr, &usin->sin6_addr, sizeof(struct in6_addr));
@@ -331,24 +312,22 @@
* TCP over IPv4
*/
- if (addr_type == IPV6_ADDR_MAPPED)
- {
+ if (addr_type == IPV6_ADDR_MAPPED) {
struct sockaddr_in sin;
int err;
- printk(KERN_DEBUG "connect: ipv4 mapped\n");
+ SOCK_DEBUG(sk, "connect: ipv4 mapped\n");
sin.sin_family = AF_INET;
sin.sin_port = usin->sin6_port;
sin.sin_addr.s_addr = usin->sin6_addr.s6_addr32[3];
sk->tp_pinfo.af_tcp.af_specific = &ipv6_mapped;
- sk->backlog_rcv = tcp_v4_backlog_rcv;
+ sk->backlog_rcv = tcp_v4_do_rcv;
err = tcp_v4_connect(sk, (struct sockaddr *)&sin, sizeof(sin));
- if (err)
- {
+ if (err) {
sk->tp_pinfo.af_tcp.af_specific = &ipv6_specific;
sk->backlog_rcv = tcp_v6_backlog_rcv;
}
@@ -356,31 +335,47 @@
return err;
}
- dc = ipv6_dst_route(&np->daddr, NULL, (sk->localroute ? RTI_GATEWAY : 0));
+ if (!ipv6_addr_any(&np->rcv_saddr))
+ saddr = &np->rcv_saddr;
+
+ fl.proto = IPPROTO_TCP;
+ fl.nl_u.ip6_u.daddr = &np->daddr;
+ fl.nl_u.ip6_u.saddr = saddr;
+ fl.dev = NULL;
+ fl.uli_u.ports.dport = usin->sin6_port;
+ fl.uli_u.ports.sport = sk->dummy_th.source;
+
+ dst = ip6_route_output(sk, &fl);
- if (dc == NULL)
- {
- return -ENETUNREACH;
+ if (dst->error) {
+ dst_release(dst);
+ return dst->error;
}
- np->dest = dc;
- np->dc_sernum = (dc->rt.fib_node ? dc->rt.fib_node->fn_sernum : 0);
+ ip6_dst_store(sk, dst);
- ifa = ipv6_get_saddr((struct rt6_info *)dc, &np->daddr);
+ np->oif = dst->dev;
- if (ifa == NULL)
- {
- return -ENETUNREACH;
+ if (saddr == NULL) {
+ ifa = ipv6_get_saddr(dst, &np->daddr);
+
+ if (ifa == NULL)
+ return -ENETUNREACH;
+
+ saddr = &ifa->addr;
+
+ /* set the source address */
+ ipv6_addr_copy(&np->rcv_saddr, saddr);
+ ipv6_addr_copy(&np->saddr, saddr);
}
-
/*
* Init variables
*/
lock_sock(sk);
- sk->dummy_th.dest = usin->sin6_port;
+ sk->dummy_th.dest = usin->sin6_port;
sk->write_seq = secure_tcp_sequence_number(np->saddr.s6_addr32[3],
np->daddr.s6_addr32[3],
sk->dummy_th.source,
@@ -400,17 +395,11 @@
buff = sock_wmalloc(sk, MAX_SYN_SIZE, 0, GFP_KERNEL);
if (buff == NULL)
- {
return(-ENOMEM);
- }
+
lock_sock(sk);
-
- tmp = tcp_v6_build_header(sk, buff);
- /* set the source address */
-
- memcpy(&np->saddr, &ifa->addr, sizeof(struct in6_addr));
- memcpy(&np->rcv_saddr, &ifa->addr, sizeof(struct in6_addr));
+ tcp_v6_build_header(sk, buff);
/* build the tcp header */
th = (struct tcphdr *) skb_put(buff,sizeof(struct tcphdr));
@@ -426,13 +415,9 @@
th->syn = 1;
th->doff = 6;
- sk->window_clamp=0;
-
- if ((dc->dc_flags & DCF_PMTU))
- sk->mtu = dc->dc_pmtu;
- else
- sk->mtu = dc->rt.rt_dev->mtu;
+ sk->window_clamp = 0;
+ sk->mtu = dst->pmtu;
sk->mss = sk->mtu - sizeof(struct ipv6hdr) - sizeof(struct tcphdr);
/*
@@ -447,9 +432,9 @@
buff->csum = csum_partial(ptr, 4, 0);
tcp_v6_send_check(sk, th, sizeof(struct tcphdr) + 4, buff);
-
+
tcp_set_state(sk, TCP_SYN_SENT);
-
+
/* Socket identity change complete, no longer
* in TCP_CLOSE, so rehash.
*/
@@ -468,17 +453,17 @@
skb1 = skb_clone(buff, GFP_KERNEL);
skb_set_owner_w(skb1, sk);
- tmp = ipv6_xmit(sk, skb1, &np->saddr, &np->daddr, NULL, IPPROTO_TCP);
+ tcp_v6_xmit(skb1);
/* Timer for repeating the SYN until an answer */
tcp_reset_xmit_timer(sk, TIME_RETRANS, tp->rto);
tcp_statistics.TcpActiveOpens++;
tcp_statistics.TcpOutSegs++;
-
+
release_sock(sk);
-
- return(tmp);
+
+ return(0);
}
static int tcp_v6_sendmsg(struct sock *sk, struct msghdr *msg, int len)
@@ -513,7 +498,7 @@
lock_sock(sk);
retval = tcp_do_sendmsg(sk, msg->msg_iovlen, msg->msg_iov,
- len, msg->msg_flags);
+ msg->msg_flags);
release_sock(sk);
@@ -534,45 +519,52 @@
sk = tcp_v6_lookup(saddr, th->source, daddr, th->dest);
if (sk == NULL)
- {
return;
- }
np = &sk->net_pinfo.af_inet6;
- if (type == ICMPV6_PKT_TOOBIG)
- {
+ if (type == ICMPV6_PKT_TOOBIG) {
/* icmp should have updated the destination cache entry */
- np->dest = ipv6_dst_check(np->dest, &np->daddr, np->dc_sernum,
- 0);
+ dst_check(&np->dst, np->dst_cookie);
- np->dc_sernum = (np->dest->rt.fib_node ?
- np->dest->rt.fib_node->fn_sernum : 0);
+ if (np->dst == NULL) {
+ struct flowi fl;
+ struct dst_entry *dst;
+
+ fl.proto = IPPROTO_TCP;
+ fl.nl_u.ip6_u.daddr = &np->daddr;
+ fl.nl_u.ip6_u.saddr = &np->saddr;
+ fl.dev = np->oif;
+ fl.uli_u.ports.dport = sk->dummy_th.dest;
+ fl.uli_u.ports.sport = sk->dummy_th.source;
- if (np->dest->dc_flags & DCF_PMTU)
- sk->mtu = np->dest->dc_pmtu;
+ dst = ip6_route_output(sk, &fl);
- sk->mtu = (sk->mtu - sizeof(struct ipv6hdr) -
- sizeof(struct tcphdr));
+ ip6_dst_store(sk, dst);
+ }
+
+ if (np->dst->error)
+ sk->err_soft = np->dst->error;
+ else
+ sk->mtu = np->dst->pmtu;
return;
}
opening = (sk->state == TCP_SYN_SENT || sk->state == TCP_SYN_RECV);
- if (icmpv6_err_convert(type, code, &err) || opening)
- {
+ if (icmpv6_err_convert(type, code, &err) || opening) {
sk->err = err;
- if (opening)
- {
+
+ if (opening) {
tcp_statistics.TcpAttemptFails++;
tcp_set_state(sk,TCP_CLOSE);
sk->error_report(sk);
}
- }
- else
+ } else {
sk->err_soft = err;
+ }
}
@@ -583,37 +575,34 @@
struct sk_buff * skb;
struct tcphdr *th;
unsigned char *ptr;
- struct dest_entry *dc;
- int mss;
+ struct dst_entry *dst;
+ struct flowi fl;
skb = sock_wmalloc(sk, MAX_SYN_SIZE, 1, GFP_ATOMIC);
if (skb == NULL)
- {
return;
- }
-
- skb_reserve(skb, (MAX_HEADER + 15) & ~15);
- skb->nh.ipv6h = (struct ipv6hdr *) skb_put(skb, sizeof(struct ipv6hdr));
- dc = ipv6_dst_route(&af_req->rmt_addr, af_req->dev, 0);
+ fl.proto = IPPROTO_TCP;
+ fl.nl_u.ip6_u.daddr = &af_req->rmt_addr;
+ fl.nl_u.ip6_u.saddr = &af_req->loc_addr;
+ fl.dev = af_req->dev;
+ fl.uli_u.ports.dport = req->rmt_port;
+ fl.uli_u.ports.sport = sk->dummy_th.source;
- skb->dev = af_req->dev;
-
- if (dc)
- {
- if (dc->dc_flags & DCF_PMTU)
- mss = dc->dc_pmtu;
- else
- mss = dc->dc_nexthop->dev->mtu;
- mss -= sizeof(struct ipv6hdr) + sizeof(struct tcphdr);
+ dst = ip6_route_output(sk, &fl);
- ipv6_dst_unlock(dc);
+ if (dst->error) {
+ kfree_skb(skb, FREE_WRITE);
+ dst_release(dst);
+ return;
}
- else
- mss = 516;
- th =(struct tcphdr *) skb_put(skb, sizeof(struct tcphdr));
+ skb->dev = dst->dev;
+ skb_reserve(skb, (skb->dev->hard_header_len + 15) & ~15);
+ skb->nh.ipv6h = (struct ipv6hdr *) skb_put(skb,sizeof(struct ipv6hdr));
+
+ th = (struct tcphdr *) skb_put(skb, sizeof(struct tcphdr));
skb->h.th = th;
memset(th, 0, sizeof(struct tcphdr));
@@ -635,19 +624,20 @@
ptr = skb_put(skb, TCPOLEN_MSS);
ptr[0] = TCPOPT_MSS;
ptr[1] = TCPOLEN_MSS;
- ptr[2] = (mss >> 8) & 0xff;
- ptr[3] = mss & 0xff;
+ ptr[2] = (dst->pmtu >> 8) & 0xff;
+ ptr[3] = dst->pmtu & 0xff;
skb->csum = csum_partial(ptr, TCPOLEN_MSS, 0);
- th->check = tcp_v6_check(th, sizeof(*th) + TCPOLEN_MSS, &af_req->loc_addr,
- &af_req->rmt_addr,
- csum_partial((char *)th, sizeof(*th), skb->csum));
-
- ipv6_xmit(sk, skb, &af_req->loc_addr, &af_req->rmt_addr, af_req->opt,
- IPPROTO_TCP);
-
+ th->check = tcp_v6_check(th, sizeof(*th) + TCPOLEN_MSS,
+ &af_req->loc_addr, &af_req->rmt_addr,
+ csum_partial((char *)th, sizeof(*th),
+ skb->csum));
+
+ ip6_dst_store(sk, dst);
+ ip6_xmit(sk, skb, &fl, af_req->opt);
+ dst_release(dst);
+
tcp_statistics.TcpOutSegs++;
-
}
static void tcp_v6_or_free(struct open_request *req)
@@ -666,23 +656,19 @@
struct open_request *req;
/* If the socket is dead, don't accept the connection. */
- if (sk->dead)
- {
- SOCK_DEBUG(sk, "Reset on %p: Connect on dead socket.\n",sk);
+ if (sk->dead) {
+ SOCK_DEBUG(sk, "Reset on %p: Connect on dead socket.\n", sk);
tcp_statistics.TcpAttemptFails++;
- return -ENOTCONN;
+ return -ENOTCONN;
}
if (skb->protocol == __constant_htons(ETH_P_IP))
- {
return tcp_v4_conn_request(sk, skb, ptr, isn);
- }
/*
* There are no SYN attacks on IPv6, yet...
*/
- if (sk->ack_backlog >= sk->max_ack_backlog)
- {
+ if (sk->ack_backlog >= sk->max_ack_backlog) {
printk(KERN_DEBUG "droping syn ack:%d max:%d\n",
sk->ack_backlog, sk->max_ack_backlog);
tcp_statistics.TcpAttemptFails++;
@@ -690,9 +676,8 @@
}
af_req = kmalloc(sizeof(struct tcp_v6_open_req), GFP_ATOMIC);
-
- if (af_req == NULL)
- {
+
+ if (af_req == NULL) {
tcp_statistics.TcpAttemptFails++;
goto exit;
}
@@ -709,9 +694,7 @@
req->mss = tcp_parse_options(skb->h.th);
if (!req->mss)
- {
req->mss = 536;
- }
req->rmt_port = skb->h.th->source;
@@ -733,7 +716,7 @@
sk->data_ready(sk, 0);
- exit:
+exit:
kfree_skb(skb, FREE_READ);
return 0;
}
@@ -754,22 +737,21 @@
{
struct tcp_v6_open_req *af_req = (struct tcp_v6_open_req *) req;
struct ipv6_pinfo *np;
- struct dest_entry *dc;
+ struct dst_entry *dst;
+ struct flowi fl;
struct tcp_opt *newtp;
struct sock *newsk;
-
- if (skb->protocol == __constant_htons(ETH_P_IP))
- {
- /*
- * v6 mapped
+ if (skb->protocol == __constant_htons(ETH_P_IP)) {
+ /*
+ * v6 mapped
*/
-
+
newsk = tcp_v4_syn_recv_sock(sk, skb, req);
if (newsk == NULL)
return NULL;
-
+
np = &newsk->net_pinfo.af_inet6;
ipv6_addr_set(&np->daddr, 0, 0, __constant_htonl(0x0000FFFF),
@@ -781,16 +763,14 @@
ipv6_addr_copy(&np->rcv_saddr, &np->saddr);
newsk->tp_pinfo.af_tcp.af_specific = &ipv6_mapped;
- newsk->backlog_rcv = tcp_v4_backlog_rcv;
+ newsk->backlog_rcv = tcp_v4_do_rcv;
return newsk;
}
newsk = sk_alloc(GFP_ATOMIC);
if (newsk == NULL)
- {
return NULL;
- }
memcpy(newsk, sk, sizeof(*newsk));
@@ -803,13 +783,12 @@
skb_queue_head_init(&newsk->receive_queue);
skb_queue_head_init(&newsk->out_of_order_queue);
skb_queue_head_init(&newsk->error_queue);
-
+
/*
* Unused
*/
newsk->send_head = NULL;
- newsk->send_tail = NULL;
newtp = &(newsk->tp_pinfo.af_tcp);
np = &newsk->net_pinfo.af_inet6;
@@ -826,7 +805,6 @@
newsk->cong_count = 0;
newsk->ssthresh = 0;
newtp->backoff = 0;
- newsk->blog = 0;
newsk->intr = 0;
newsk->proc = 0;
newsk->done = 0;
@@ -870,7 +848,7 @@
newsk->dummy_th.source = sk->dummy_th.source;
newsk->dummy_th.dest = req->rmt_port;
- newsk->users=0;
+ newsk->sock_readers=0;
newtp->rcv_nxt = req->rcv_isn + 1;
newtp->rcv_wup = req->rcv_isn + 1;
@@ -881,30 +859,38 @@
ipv6_addr_copy(&np->daddr, &af_req->rmt_addr);
ipv6_addr_copy(&np->saddr, &af_req->loc_addr);
ipv6_addr_copy(&np->rcv_saddr, &af_req->loc_addr);
-
+ np->oif = af_req->dev;
+
/*
- * options / mss
+ * options / mss / route cache
*/
-
- dc = ipv6_dst_route(&af_req->rmt_addr, af_req->dev, 0);
- np->dest = dc;
- if (np->dest && (np->dest->dc_flags & DCF_PMTU))
- newsk->mtu = np->dest->dc_pmtu;
- else
+ fl.proto = IPPROTO_TCP;
+ fl.nl_u.ip6_u.daddr = &np->daddr;
+ fl.nl_u.ip6_u.saddr = &np->saddr;
+ fl.dev = np->oif;
+ fl.uli_u.ports.dport = newsk->dummy_th.dest;
+ fl.uli_u.ports.sport = newsk->dummy_th.source;
+
+ dst = ip6_route_output(newsk, &fl);
+
+ ip6_dst_store(newsk, dst);
+
+ if (dst->error)
newsk->mtu = af_req->dev->mtu;
+ else
+ newsk->mtu = dst->pmtu;
- newsk->mss = min(req->mss, (newsk->mtu - sizeof(struct ipv6hdr) -
+ newsk->mss = min(req->mss, (newsk->mtu - sizeof(struct ipv6hdr) -
sizeof(struct tcphdr)));
-
+
newsk->daddr = LOOPBACK4_IPV6;
newsk->saddr = LOOPBACK4_IPV6;
newsk->rcv_saddr= LOOPBACK4_IPV6;
-
- newsk->prot->hash(newsk);
+ newsk->prot->hash(newsk);
+ add_to_prot_sklist(newsk);
return newsk;
-
}
static void tcp_v6_reply_reset(struct sk_buff *skb)
@@ -918,6 +904,7 @@
{
struct sk_buff *buff;
struct tcphdr *t1;
+ struct flowi fl;
if(th->rst)
return;
@@ -947,12 +934,9 @@
t1->doff = sizeof(*t1)/4;
t1->rst = 1;
- if(th->ack)
- {
+ if(th->ack) {
t1->seq = th->ack_seq;
- }
- else
- {
+ } else {
t1->ack = 1;
if(!th->syn)
t1->ack_seq = th->seq;
@@ -965,9 +949,14 @@
t1->check = csum_ipv6_magic(saddr, daddr, sizeof(*t1), IPPROTO_TCP,
buff->csum);
-
- ipv6_xmit(NULL, buff, saddr, daddr, NULL, IPPROTO_TCP);
-
+ fl.proto = IPPROTO_TCP;
+ fl.nl_u.ip6_u.daddr = daddr;
+ fl.nl_u.ip6_u.saddr = saddr;
+ fl.dev = dev;
+ fl.uli_u.ports.dport = th->dest;
+ fl.uli_u.ports.sport = th->source;
+
+ ip6_xmit(NULL, buff, &fl, NULL);
tcp_statistics.TcpOutSegs++;
}
@@ -975,22 +964,18 @@
{
struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
struct open_request *req;
-
/*
* assumption: the socket is not in use.
* as we checked the user count on tcp_rcv and we're
* running from a soft interrupt.
*/
-
+
req = tp->syn_wait_queue;
-
if (!req)
- {
return sk;
- }
-
+
do {
struct tcp_v6_open_req *af_req;
@@ -998,12 +983,10 @@
if (!ipv6_addr_cmp(&af_req->rmt_addr, &skb->nh.ipv6h->saddr) &&
!ipv6_addr_cmp(&af_req->loc_addr, &skb->nh.ipv6h->daddr) &&
- req->rmt_port == skb->h.th->source)
- {
+ req->rmt_port == skb->h.th->source) {
u32 flg;
-
- if (req->sk)
- {
+
+ if (req->sk) {
printk(KERN_DEBUG "BUG: syn_recv:"
"socket exists\n");
break;
@@ -1016,10 +999,9 @@
*/
flg = *(((u32 *)skb->h.th) + 3);
flg &= __constant_htonl(0x002f0000);
-
+
if ((flg == __constant_htonl(0x00020000)) &&
- (!after(skb->seq, req->rcv_isn)))
- {
+ (!after(skb->seq, req->rcv_isn))) {
/*
* retransmited syn
* FIXME: must send an ack
@@ -1033,9 +1015,7 @@
tcp_dec_slow_timer(TCP_SLT_SYNACK);
if (sk == NULL)
- {
return NULL;
- }
skb_set_owner_r(skb, sk);
req->expires = 0UL;
@@ -1045,10 +1025,8 @@
req = req->dl_next;
} while (req != tp->syn_wait_queue);
-
return sk;
-
}
int tcp_v6_rcv(struct sk_buff *skb, struct device *dev,
@@ -1070,42 +1048,37 @@
sk = skb->sk;
- if (!redo)
- {
-
+ if (!redo) {
if (skb->pkt_type != PACKET_HOST)
goto discard_it;
/*
* Pull up the IP header.
*/
-
+
skb_pull(skb, skb->h.raw - skb->data);
/*
* Try to use the device checksum if provided.
*/
-
- switch (skb->ip_summed)
- {
- case CHECKSUM_NONE:
- skb->csum = csum_partial((char *)th, len, 0);
- case CHECKSUM_HW:
- if (tcp_v6_check(th,len,saddr,daddr,skb->csum))
- {
- printk(KERN_DEBUG "tcp csum failed\n");
- goto discard_it;
- }
- default:
- /* CHECKSUM_UNNECESSARY */
- }
+
+ switch (skb->ip_summed) {
+ case CHECKSUM_NONE:
+ skb->csum = csum_partial((char *)th, len, 0);
+ case CHECKSUM_HW:
+ if (tcp_v6_check(th,len,saddr,daddr,skb->csum)) {
+ printk(KERN_DEBUG "tcp csum failed\n");
+ goto discard_it;
+ }
+ default:
+ /* CHECKSUM_UNNECESSARY */
+ };
tcp_statistics.TcpInSegs++;
-
+
sk = __tcp_v6_lookup(th, saddr, th->source, daddr, th->dest);
- if (!sk)
- {
+ if (!sk) {
printk(KERN_DEBUG "socket not found\n");
goto no_tcp_socket;
}
@@ -1117,14 +1090,13 @@
skb->acked = 0;
skb->used = 0;
- }
+ }
/*
- * We may need to add it to the backlog here.
+ * We may need to add it to the backlog here.
*/
- if (sk->users)
- {
+ if (sk->sock_readers) {
__skb_queue_tail(&sk->back_log, skb);
return(0);
}
@@ -1133,46 +1105,38 @@
* Signal NDISC that the connection is making
* "forward progress"
*/
- if (sk->state != TCP_LISTEN)
- {
+ if (sk->state != TCP_LISTEN) {
struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
struct tcp_opt *tp=&(sk->tp_pinfo.af_tcp);
if (after(skb->seq, tp->rcv_nxt) ||
- after(skb->ack_seq, tp->snd_una))
- {
- if (np->dest)
- ndisc_validate(np->dest->dc_nexthop);
+ after(skb->ack_seq, tp->snd_una)) {
+ if (np->dst)
+ ndisc_validate(np->dst->neighbour);
}
}
- if (!sk->prot)
- {
+ if (!sk->prot) {
printk(KERN_DEBUG "tcp_rcv: sk->prot == NULL\n");
return(0);
}
skb_set_owner_r(skb, sk);
- if (sk->state == TCP_ESTABLISHED)
- {
+ if (sk->state == TCP_ESTABLISHED) {
if (tcp_rcv_established(sk, skb, th, len))
goto no_tcp_socket;
return 0;
}
-
- if (sk->state == TCP_LISTEN)
- {
+
+ if (sk->state == TCP_LISTEN) {
/*
* find possible connection requests
*/
sk = tcp_v6_check_req(sk, skb);
if (sk == NULL)
- {
goto discard_it;
- }
-
}
if (tcp_rcv_state_process(sk, skb, th, opt, len) == 0)
@@ -1181,11 +1145,11 @@
no_tcp_socket:
/*
- * No such TCB. If th->rst is 0 send a reset
+ * No such TCB. If th->rst is 0 send a reset
* (checked in tcp_send_reset)
*/
- tcp_v6_send_reset(daddr, saddr, th, &tcpv6_prot, opt, dev,
+ tcp_v6_send_reset(daddr, saddr, th, &tcpv6_prot, opt, dev,
skb->nh.ipv6h->priority, 255);
discard_it:
@@ -1196,37 +1160,38 @@
kfree_skb(skb, FREE_READ);
return 0;
-
}
static int tcp_v6_rebuild_header(struct sock *sk, struct sk_buff *skb)
{
struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
-
- if (np->dest)
- {
- np->dest = ipv6_dst_check(np->dest, &np->daddr,
- np->dc_sernum, 0);
-
- }
- else
- {
- np->dest = ipv6_dst_route(&np->daddr, NULL, 0);
+
+ if (np->dst)
+ dst_check(&np->dst, np->dst_cookie);
+
+ if (np->dst == NULL) {
+ struct flowi fl;
+ struct dst_entry *dst;
+
+ fl.proto = IPPROTO_TCP;
+ fl.nl_u.ip6_u.daddr = &np->daddr;
+ fl.nl_u.ip6_u.saddr = &np->saddr;
+ fl.dev = np->oif;
+ fl.uli_u.ports.dport = sk->dummy_th.dest;
+ fl.uli_u.ports.sport = sk->dummy_th.source;
+
+ dst = ip6_route_output(sk, &fl);
+ ip6_dst_store(sk, dst);
}
- if (!np->dest)
- {
+ if (np->dst->error) {
/*
* lost route to destination
*/
- return -1;
+ return -EHOSTUNREACH;
}
-
- np->dc_sernum = (np->dest->rt.fib_node ?
- np->dest->rt.fib_node->fn_sernum : 0);
- ipv6_redo_mac_hdr(skb, np->dest->dc_nexthop,
- skb->tail - (u8*) skb->nh.ipv6h);
+ skb_pull(skb, skb->nh.raw - skb->data);
return 0;
}
@@ -1237,7 +1202,7 @@
res = tcp_v6_rcv(skb, skb->dev,
&skb->nh.ipv6h->saddr, &skb->nh.ipv6h->daddr,
(struct ipv6_options *) skb->cb,
- skb->len, 1,
+ skb->len, 1,
(struct inet6_protocol *) sk->pair);
return res;
}
@@ -1246,20 +1211,16 @@
{
struct in6_addr *saddr;
struct in6_addr *daddr;
- struct sock *sk;
saddr = &skb->nh.ipv6h->saddr;
daddr = &skb->nh.ipv6h->daddr;
-
- sk = tcp_v6_lookup(saddr, th->source, daddr, th->dest);
-
- return sk;
+ return tcp_v6_lookup(saddr, th->source, daddr, th->dest);
}
-
+
static int tcp_v6_build_header(struct sock *sk, struct sk_buff *skb)
{
skb_reserve(skb, (MAX_HEADER + 15) & ~15);
- skb->nh.ipv6h = (struct ipv6hdr *) skb_put(skb, sizeof(struct ipv6hdr));
+ skb->nh.raw = skb_put(skb, sizeof(struct ipv6hdr));
/*
* FIXME: reserve space for option headers
@@ -1273,28 +1234,33 @@
{
struct sock *sk = skb->sk;
struct ipv6_pinfo * np = &sk->net_pinfo.af_inet6;
+ struct flowi fl;
int err;
- err = ipv6_xmit(sk, skb, &np->saddr, &np->daddr, NULL, IPPROTO_TCP);
-
+ fl.proto = IPPROTO_TCP;
+ fl.nl_u.ip6_u.daddr = &np->daddr;
+ fl.nl_u.ip6_u.saddr = &np->saddr;
+ fl.dev = np->oif;
+ fl.uli_u.ports.sport = sk->dummy_th.source;
+ fl.uli_u.ports.dport = sk->dummy_th.dest;
+
+ err = ip6_xmit(sk, skb, &fl, np->opt);
+
/*
* FIXME: check error handling.
*/
sk->err_soft = err;
}
-
-
static void v6_addr2sockaddr(struct sock *sk, struct sockaddr * uaddr)
{
struct ipv6_pinfo * np = &sk->net_pinfo.af_inet6;
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) uaddr;
-
+
sin6->sin6_family = AF_INET6;
memcpy(&sin6->sin6_addr, &np->daddr, sizeof(struct in6_addr));
sin6->sin6_port = sk->dummy_th.dest;
-
}
static struct tcp_func ipv6_specific = {
@@ -1359,19 +1325,16 @@
/* this is how many unacked bytes we will accept for this socket. */
sk->max_unacked = 2048; /* needs to be at most 2 full packets. */
sk->max_ack_backlog = SOMAXCONN;
-
+
sk->mtu = 576;
sk->mss = 516;
sk->dummy_th.doff = sizeof(sk->dummy_th)/4;
-
/*
- * Speed up by setting some standard state for the dummy_th
- * if TCP uses it (maybe move to tcp_init later)
+ * Speed up by setting some standard state for the dummy_th.
*/
-
- sk->dummy_th.ack=1;
+ sk->dummy_th.ack=1;
sk->dummy_th.doff=sizeof(struct tcphdr)>>2;
sk->tp_pinfo.af_tcp.af_specific = &ipv6_specific;
@@ -1385,16 +1348,14 @@
struct sk_buff *skb;
tcp_clear_xmit_timers(sk);
-
+
if (sk->keepopen)
- {
tcp_dec_slow_timer(TCP_SLT_KEEPALIVE);
- }
/*
- * Cleanup up the write buffer.
+ * Cleanup up the write buffer.
*/
-
+
while((skb = skb_dequeue(&sk->write_queue)) != NULL) {
IS_SKB(skb);
kfree_skb(skb, FREE_WRITE);
@@ -1413,15 +1374,12 @@
* Release destination entry
*/
- if (np->dest)
- {
- ipv6_dst_unlock(np->dest);
- }
+ if (np->dst)
+ dst_release(np->dst);
return 0;
}
-
struct proto tcpv6_prot = {
(struct sock *)&tcpv6_prot, /* sklist_next */
(struct sock *)&tcpv6_prot, /* sklist_prev */
@@ -1454,7 +1412,7 @@
0 /* highestinuse */
};
-static struct inet6_protocol tcpv6_protocol =
+static struct inet6_protocol tcpv6_protocol =
{
tcp_v6_rcv, /* TCP handler */
tcp_v6_err, /* TCP error control */
@@ -1465,16 +1423,8 @@
"TCPv6" /* name */
};
-
void tcpv6_init(void)
{
/* register inet6 protocol */
inet6_add_protocol(&tcpv6_protocol);
}
-
-/*
- * Local variables:
- * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strength-reduce -pipe -m486 -DCPU=486 -DMODULE -DMODVERSIONS -include /usr/src/linux/include/linux/modversions.h -c -o tcp_ipv6.o tcp_ipv6.c"
- * c-file-style: "Linux"
- * End:
- */
FUNET's LINUX-ADM group, [email protected]
TCL-scripts by Sam Shen, [email protected]