patch-2.1.53 linux/net/ipv6/tcp_ipv6.c
Next file: linux/net/ipx/af_ipx.c
Previous file: linux/net/ipv6/af_inet6.c
Back to the patch index
Back to the overall index
- Lines: 250
- Date:
Thu Sep 4 13:25:29 1997
- Orig file:
v2.1.52/linux/net/ipv6/tcp_ipv6.c
- Orig date:
Mon Aug 4 16:25:41 1997
diff -u --recursive --new-file v2.1.52/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.35 1997/07/23 15:18:04 freitag Exp $
+ * $Id: tcp_ipv6.c,v 1.37 1997/08/22 19:15:40 freitag Exp $
*
* Based on:
* linux/net/ipv4/tcp.c
@@ -536,6 +536,7 @@
return retval;
}
+/* XXX: this functions needs to be updated like tcp_v4_err. */
void tcp_v6_err(int type, int code, unsigned char *header, __u32 info,
struct in6_addr *saddr, struct in6_addr *daddr,
struct inet6_protocol *protocol)
@@ -553,7 +554,7 @@
np = &sk->net_pinfo.af_inet6;
- if (type == ICMPV6_PKT_TOOBIG) {
+ if (type == ICMPV6_PKT_TOOBIG && sk->state != TCP_LISTEN) {
/* icmp should have updated the destination cache entry */
dst_check(&np->dst, np->dst_cookie);
@@ -579,11 +580,12 @@
else
sk->mtu = np->dst->pmtu;
+ release_sock(sk);
return;
}
+ /* FIXME: This is wrong. Need to check for open_requests here. */
opening = (sk->state == TCP_SYN_SENT || sk->state == TCP_SYN_RECV);
-
if (icmpv6_err_convert(type, code, &err) || opening) {
sk->err = err;
@@ -657,13 +659,15 @@
}
if (req->rcv_wnd == 0) {
+ __u8 rcv_wscale;
/* Set this up on the first call only */
req->window_clamp = 0; /* FIXME: should be in dst cache */
tcp_select_initial_window(sock_rspace(sk)/2,req->mss,
&req->rcv_wnd,
&req->window_clamp,
req->wscale_ok,
- &req->rcv_wscale);
+ &rcv_wscale);
+ req->rcv_wscale = rcv_wscale;
}
th->window = htons(req->rcv_wnd);
@@ -764,7 +768,6 @@
sk->data_ready(sk, 0);
exit:
- kfree_skb(skb, FREE_READ);
return 0;
}
@@ -814,7 +817,7 @@
return newsk;
}
- newsk = sk_alloc(GFP_ATOMIC);
+ newsk = sk_alloc(AF_INET6, GFP_ATOMIC);
if (newsk == NULL) {
if (dst)
dst_release(dst);
@@ -1021,58 +1024,30 @@
tcp_statistics.TcpOutSegs++;
}
-struct sock *tcp_v6_check_req(struct sock *sk, struct sk_buff *skb)
-{
- struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
- struct open_request *req = tp->syn_wait_queue;
+static struct open_request *tcp_v6_search_req(struct tcp_opt *tp,
+ void *header,
+ struct tcphdr *th,
+ struct open_request **prevp)
+{
+ struct ipv6hdr *ip6h = header;
+ struct open_request *req, *prev;
+ __u16 rport = th->source;
/* assumption: the socket is not in use.
* as we checked the user count on tcp_rcv and we're
* running from a soft interrupt.
*/
- if (!req)
- return sk;
-
- while(req) {
- if (!ipv6_addr_cmp(&req->af.v6_req.rmt_addr, &skb->nh.ipv6h->saddr) &&
- !ipv6_addr_cmp(&req->af.v6_req.loc_addr, &skb->nh.ipv6h->daddr) &&
- req->rmt_port == skb->h.th->source) {
- u32 flg;
-
- if (req->sk) {
- printk(KERN_DEBUG "BUG: syn_recv:"
- "socket exists\n");
- break;
- }
-
- /* Check for syn retransmission */
- flg = *(((u32 *)skb->h.th) + 3);
- flg &= __constant_htonl(0x001f0000);
-
- if ((flg == __constant_htonl(0x00020000)) &&
- (!after(skb->seq, req->rcv_isn))) {
- /* retransmited syn
- * FIXME: must send an ack
- */
- return NULL;
- }
-
- skb_orphan(skb);
- sk = tp->af_specific->syn_recv_sock(sk, skb, req, NULL);
-
- tcp_dec_slow_timer(TCP_SLT_SYNACK);
-
- if (sk == NULL)
- return NULL;
-
- skb_set_owner_r(skb, sk);
- req->expires = 0UL;
- req->sk = sk;
- break;
+ prev = (struct open_request *) (&tp->syn_wait_queue);
+ for (req = prev->dl_next; req; req = req->dl_next) {
+ if (!ipv6_addr_cmp(&req->af.v6_req.rmt_addr, &ip6h->saddr) &&
+ !ipv6_addr_cmp(&req->af.v6_req.loc_addr, &ip6h->daddr) &&
+ req->rmt_port == rport) {
+ *prevp = prev;
+ return req;
}
- req = req->dl_next;
+ prev = req;
}
- return sk;
+ return NULL;
}
int tcp_v6_rcv(struct sk_buff *skb, struct device *dev,
@@ -1149,10 +1124,11 @@
/*
* Signal NDISC that the connection is making
* "forward progress"
+ * This is in the fast path and should be _really_ speed up! -Ak
*/
if (sk->state != TCP_LISTEN) {
struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
- struct tcp_opt *tp=&(sk->tp_pinfo.af_tcp);
+ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
if (after(skb->seq, tp->rcv_nxt) ||
after(skb->ack_seq, tp->snd_una)) {
@@ -1168,18 +1144,19 @@
skb_set_owner_r(skb, sk);
+ /* I don't understand why lock_sock()/release_sock() is not
+ * called here. IPv4 does this. It looks like a bug to me. -AK
+ */
if (sk->state == TCP_ESTABLISHED) {
if (tcp_rcv_established(sk, skb, th, len))
goto no_tcp_socket;
return 0;
}
- if (sk->state == TCP_LISTEN) {
- /*
- * find possible connection requests
- */
- sk = tcp_v6_check_req(sk, skb);
+ if (sk->state == TCP_LISTEN &&
+ ((u32 *)th)[3] & __constant_htonl(0x00120000)) {
+ sk = tcp_check_req(sk, skb, opt);
if (sk == NULL)
goto discard_it;
}
@@ -1308,6 +1285,12 @@
sin6->sin6_port = sk->dummy_th.dest;
}
+static struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb,
+ void *opt)
+{
+ return sk; /* dummy */
+}
+
static struct tcp_func ipv6_specific = {
tcp_v6_build_header,
tcp_v6_xmit,
@@ -1320,6 +1303,8 @@
ipv6_getsockopt,
v6_addr2sockaddr,
tcp_v6_reply_reset,
+ tcp_v6_search_req,
+ /* not implemented yet: */ cookie_v6_check,
sizeof(struct sockaddr_in6)
};
@@ -1339,6 +1324,8 @@
ipv6_getsockopt,
v6_addr2sockaddr,
tcp_v6_reply_reset,
+ tcp_v6_search_req,
+ cookie_v6_check, /* not implemented yet. */
sizeof(struct sockaddr_in6)
};
@@ -1360,11 +1347,20 @@
tp->rcv_wnd = 0;
tp->in_mss = 536;
/* tp->rcv_wnd = 8192; */
+ tp->tstamp_ok = 0;
+ tp->sack_ok = 0;
+ tp->wscale_ok = 0;
+ tp->snd_wscale = 0;
+ tp->sacks = 0;
+ tp->saw_tstamp = 0;
+ tp->syn_backlog = 0;
/* start with only sending one packet at a time. */
tp->snd_cwnd = 1;
tp->snd_ssthresh = 0x7fffffff;
+
+
sk->priority = 1;
sk->state = TCP_CLOSE;
@@ -1384,8 +1380,7 @@
sk->dummy_th.doff=sizeof(struct tcphdr)>>2;
/* Init SYN queue. */
- tp->syn_wait_queue = NULL;
- tp->syn_wait_last = &tp->syn_wait_queue;
+ tcp_synq_init(tp);
sk->tp_pinfo.af_tcp.af_specific = &ipv6_specific;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov