X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=net%2Fipv6%2Ftcp_ipv6.c;h=d58b83ac06fb6abc516b1b27f71a0d1ab703dcbc;hb=ca12a1a443a51298afcca627ad0bcbd8ad1dcddc;hp=cb46749d4c326a3e7133537b70ed3cccce82eb9d;hpb=a4df1ac12dd2d2812713a5fdd56af954d1bc251d;p=linux-2.6 diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index cb46749d4c..d58b83ac06 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -5,8 +5,6 @@ * Authors: * Pedro Roque * - * $Id: tcp_ipv6.c,v 1.144 2002/02/01 22:01:04 davem Exp $ - * * Based on: * linux/net/ipv4/tcp.c * linux/net/ipv4/tcp_input.c @@ -72,8 +70,6 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb); static void tcp_v6_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req); -static void tcp_v6_send_check(struct sock *sk, int len, - struct sk_buff *skb); static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb); @@ -82,6 +78,12 @@ static struct inet_connection_sock_af_ops ipv6_specific; #ifdef CONFIG_TCP_MD5SIG static struct tcp_sock_af_ops tcp_sock_ipv6_specific; static struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific; +#else +static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(struct sock *sk, + struct in6_addr *addr) +{ + return NULL; +} #endif static void tcp_v6_hash(struct sock *sk) @@ -321,8 +323,9 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, int err; struct tcp_sock *tp; __u32 seq; + struct net *net = dev_net(skb->dev); - sk = inet6_lookup(dev_net(skb->dev), &tcp_hashinfo, &hdr->daddr, + sk = inet6_lookup(net, &tcp_hashinfo, &hdr->daddr, th->dest, &hdr->saddr, th->source, skb->dev->ifindex); if (sk == NULL) { @@ -736,78 +739,34 @@ static int tcp_v6_parse_md5_keys (struct sock *sk, char __user *optval, static int tcp_v6_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, struct in6_addr *saddr, struct in6_addr *daddr, - struct tcphdr *th, int protocol, - unsigned int tcplen) + struct tcphdr *th, unsigned int tcplen) { - struct scatterlist sg[4]; - __u16 data_len; - int block = 0; - __sum16 cksum; struct tcp_md5sig_pool *hp; struct tcp6_pseudohdr *bp; - struct hash_desc *desc; int err; - unsigned int nbytes = 0; hp = tcp_get_md5sig_pool(); if (!hp) { printk(KERN_WARNING "%s(): hash pool not found...\n", __func__); goto clear_hash_noput; } + bp = &hp->md5_blk.ip6; - desc = &hp->md5_desc; /* 1. TCP pseudo-header (RFC2460) */ ipv6_addr_copy(&bp->saddr, saddr); ipv6_addr_copy(&bp->daddr, daddr); bp->len = htonl(tcplen); - bp->protocol = htonl(protocol); + bp->protocol = htonl(IPPROTO_TCP); - sg_init_table(sg, 4); + err = tcp_calc_md5_hash(md5_hash, key, sizeof(*bp), + th, tcplen, hp); - sg_set_buf(&sg[block++], bp, sizeof(*bp)); - nbytes += sizeof(*bp); - - /* 2. TCP header, excluding options */ - cksum = th->check; - th->check = 0; - sg_set_buf(&sg[block++], th, sizeof(*th)); - nbytes += sizeof(*th); - - /* 3. TCP segment data (if any) */ - data_len = tcplen - (th->doff << 2); - if (data_len > 0) { - u8 *data = (u8 *)th + (th->doff << 2); - sg_set_buf(&sg[block++], data, data_len); - nbytes += data_len; - } - - /* 4. shared key */ - sg_set_buf(&sg[block++], key->key, key->keylen); - nbytes += key->keylen; - - sg_mark_end(&sg[block - 1]); - - /* Now store the hash into the packet */ - err = crypto_hash_init(desc); - if (err) { - printk(KERN_WARNING "%s(): hash_init failed\n", __func__); - goto clear_hash; - } - err = crypto_hash_update(desc, sg, nbytes); - if (err) { - printk(KERN_WARNING "%s(): hash_update failed\n", __func__); - goto clear_hash; - } - err = crypto_hash_final(desc, md5_hash); - if (err) { - printk(KERN_WARNING "%s(): hash_final failed\n", __func__); + if (err) goto clear_hash; - } - /* Reset header, and free up the crypto */ + /* Free up the crypto pool */ tcp_put_md5sig_pool(); - th->check = cksum; out: return 0; clear_hash: @@ -821,8 +780,7 @@ static int tcp_v6_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, struct sock *sk, struct dst_entry *dst, struct request_sock *req, - struct tcphdr *th, int protocol, - unsigned int tcplen) + struct tcphdr *th, unsigned int tcplen) { struct in6_addr *saddr, *daddr; @@ -835,7 +793,7 @@ static int tcp_v6_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, } return tcp_v6_do_calc_md5_hash(md5_hash, key, saddr, daddr, - th, protocol, tcplen); + th, tcplen); } static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb) @@ -844,43 +802,12 @@ static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb) struct tcp_md5sig_key *hash_expected; struct ipv6hdr *ip6h = ipv6_hdr(skb); struct tcphdr *th = tcp_hdr(skb); - int length = (th->doff << 2) - sizeof (*th); int genhash; - u8 *ptr; u8 newhash[16]; hash_expected = tcp_v6_md5_do_lookup(sk, &ip6h->saddr); + hash_location = tcp_parse_md5sig_option(th); - /* If the TCP option is too short, we can short cut */ - if (length < TCPOLEN_MD5SIG) - return hash_expected ? 1 : 0; - - /* parse options */ - ptr = (u8*)(th + 1); - while (length > 0) { - int opcode = *ptr++; - int opsize; - - switch(opcode) { - case TCPOPT_EOL: - goto done_opts; - case TCPOPT_NOP: - length--; - continue; - default: - opsize = *ptr++; - if (opsize < 2 || opsize > length) - goto done_opts; - if (opcode == TCPOPT_MD5SIG) { - hash_location = ptr; - goto done_opts; - } - } - ptr += opsize - 2; - length -= opsize; - } - -done_opts: /* do we have a hash as expected? */ if (!hash_expected) { if (!hash_location) @@ -910,8 +837,7 @@ done_opts: genhash = tcp_v6_do_calc_md5_hash(newhash, hash_expected, &ip6h->saddr, &ip6h->daddr, - th, sk->sk_protocol, - skb->len); + th, skb->len); if (genhash || memcmp(hash_location, newhash, 16) != 0) { if (net_ratelimit()) { printk(KERN_INFO "MD5 Hash %s for " @@ -1051,7 +977,7 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) tcp_v6_do_calc_md5_hash((__u8 *)&opt[1], key, &ipv6_hdr(skb)->daddr, &ipv6_hdr(skb)->saddr, - t1, IPPROTO_TCP, tot_len); + t1, tot_len); } #endif @@ -1079,8 +1005,8 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) { ip6_xmit(ctl_sk, buff, &fl, NULL, 0); - TCP_INC_STATS_BH(TCP_MIB_OUTSEGS); - TCP_INC_STATS_BH(TCP_MIB_OUTRSTS); + TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS); + TCP_INC_STATS_BH(net, TCP_MIB_OUTRSTS); return; } } @@ -1088,8 +1014,8 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) kfree_skb(buff); } -static void tcp_v6_send_ack(struct tcp_timewait_sock *tw, - struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts) +static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts, + struct tcp_md5sig_key *key) { struct tcphdr *th = tcp_hdr(skb), *t1; struct sk_buff *buff; @@ -1098,22 +1024,6 @@ static void tcp_v6_send_ack(struct tcp_timewait_sock *tw, struct sock *ctl_sk = net->ipv6.tcp_sk; unsigned int tot_len = sizeof(struct tcphdr); __be32 *topt; -#ifdef CONFIG_TCP_MD5SIG - struct tcp_md5sig_key *key; - struct tcp_md5sig_key tw_key; -#endif - -#ifdef CONFIG_TCP_MD5SIG - if (!tw && skb->sk) { - key = tcp_v6_md5_do_lookup(skb->sk, &ipv6_hdr(skb)->daddr); - } else if (tw && tw->tw_md5_keylen) { - tw_key.key = tw->tw_md5_key; - tw_key.keylen = tw->tw_md5_keylen; - key = &tw_key; - } else { - key = NULL; - } -#endif if (ts) tot_len += TCPOLEN_TSTAMP_ALIGNED; @@ -1157,7 +1067,7 @@ static void tcp_v6_send_ack(struct tcp_timewait_sock *tw, tcp_v6_do_calc_md5_hash((__u8 *)topt, key, &ipv6_hdr(skb)->daddr, &ipv6_hdr(skb)->saddr, - t1, IPPROTO_TCP, tot_len); + t1, tot_len); } #endif @@ -1180,7 +1090,7 @@ static void tcp_v6_send_ack(struct tcp_timewait_sock *tw, if (!ip6_dst_lookup(ctl_sk, &buff->dst, &fl)) { if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) { ip6_xmit(ctl_sk, buff, &fl, NULL, 0); - TCP_INC_STATS_BH(TCP_MIB_OUTSEGS); + TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS); return; } } @@ -1193,16 +1103,17 @@ static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb) struct inet_timewait_sock *tw = inet_twsk(sk); struct tcp_timewait_sock *tcptw = tcp_twsk(sk); - tcp_v6_send_ack(tcptw, skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, + tcp_v6_send_ack(skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale, - tcptw->tw_ts_recent); + tcptw->tw_ts_recent, tcp_twsk_md5_key(tcptw)); inet_twsk_put(tw); } static void tcp_v6_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req) { - tcp_v6_send_ack(NULL, skb, tcp_rsk(req)->snt_isn + 1, tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd, req->ts_recent); + tcp_v6_send_ack(skb, tcp_rsk(req)->snt_isn + 1, tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd, req->ts_recent, + tcp_v6_md5_do_lookup(skb->sk, &ipv6_hdr(skb)->daddr)); } @@ -1669,7 +1580,7 @@ discard: kfree_skb(skb); return 0; csum_err: - TCP_INC_STATS_BH(TCP_MIB_INERRS); + TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_INERRS); goto discard; @@ -1707,6 +1618,7 @@ static int tcp_v6_rcv(struct sk_buff *skb) struct tcphdr *th; struct sock *sk; int ret; + struct net *net = dev_net(skb->dev); if (skb->pkt_type != PACKET_HOST) goto discard_it; @@ -1714,7 +1626,7 @@ static int tcp_v6_rcv(struct sk_buff *skb) /* * Count it even if it's bad. */ - TCP_INC_STATS_BH(TCP_MIB_INSEGS); + TCP_INC_STATS_BH(net, TCP_MIB_INSEGS); if (!pskb_may_pull(skb, sizeof(struct tcphdr))) goto discard_it; @@ -1738,7 +1650,7 @@ static int tcp_v6_rcv(struct sk_buff *skb) TCP_SKB_CB(skb)->flags = ipv6_get_dsfield(ipv6_hdr(skb)); TCP_SKB_CB(skb)->sacked = 0; - sk = __inet6_lookup(dev_net(skb->dev), &tcp_hashinfo, + sk = __inet6_lookup(net, &tcp_hashinfo, &ipv6_hdr(skb)->saddr, th->source, &ipv6_hdr(skb)->daddr, ntohs(th->dest), inet6_iif(skb)); @@ -1786,7 +1698,7 @@ no_tcp_socket: if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) { bad_packet: - TCP_INC_STATS_BH(TCP_MIB_INERRS); + TCP_INC_STATS_BH(net, TCP_MIB_INERRS); } else { tcp_v6_send_reset(NULL, skb); } @@ -1811,7 +1723,7 @@ do_time_wait: } if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) { - TCP_INC_STATS_BH(TCP_MIB_INERRS); + TCP_INC_STATS_BH(net, TCP_MIB_INERRS); inet_twsk_put(inet_twsk(sk)); goto discard_it; } @@ -1960,7 +1872,7 @@ static int tcp_v6_init_sock(struct sock *sk) return 0; } -static int tcp_v6_destroy_sock(struct sock *sk) +static void tcp_v6_destroy_sock(struct sock *sk) { #ifdef CONFIG_TCP_MD5SIG /* Clean up the MD5 key list */ @@ -1968,7 +1880,7 @@ static int tcp_v6_destroy_sock(struct sock *sk) tcp_v6_clear_md5_list(sk); #endif tcp_v4_destroy_sock(sk); - return inet6_destroy_sock(sk); + inet6_destroy_sock(sk); } #ifdef CONFIG_PROC_FS @@ -2036,7 +1948,7 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i) seq_printf(seq, "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " - "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %u %u %u %u %d\n", + "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %lu %lu %u %u %d\n", i, src->s6_addr32[0], src->s6_addr32[1], src->s6_addr32[2], src->s6_addr32[3], srcp, @@ -2052,8 +1964,8 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i) icsk->icsk_probes_out, sock_i_ino(sp), atomic_read(&sp->sk_refcnt), sp, - icsk->icsk_rto, - icsk->icsk_ack.ato, + jiffies_to_clock_t(icsk->icsk_rto), + jiffies_to_clock_t(icsk->icsk_ack.ato), (icsk->icsk_ack.quick << 1 ) | icsk->icsk_ack.pingpong, tp->snd_cwnd, tp->snd_ssthresh>=0xFFFF?-1:tp->snd_ssthresh );