diff options
Diffstat (limited to 'net/ipv6/tcp_ipv6.c')
| -rw-r--r-- | net/ipv6/tcp_ipv6.c | 52 | 
1 files changed, 33 insertions, 19 deletions
| diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 4f4310a36a04..2521690d62d6 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -109,9 +109,9 @@ static u32 tcp_v6_init_seq(const struct sk_buff *skb)  				tcp_hdr(skb)->source);  } -static u32 tcp_v6_init_ts_off(const struct sk_buff *skb) +static u32 tcp_v6_init_ts_off(const struct net *net, const struct sk_buff *skb)  { -	return secure_tcpv6_ts_off(ipv6_hdr(skb)->daddr.s6_addr32, +	return secure_tcpv6_ts_off(net, ipv6_hdr(skb)->daddr.s6_addr32,  				   ipv6_hdr(skb)->saddr.s6_addr32);  } @@ -292,7 +292,8 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,  							 sk->sk_v6_daddr.s6_addr32,  							 inet->inet_sport,  							 inet->inet_dport); -		tp->tsoffset = secure_tcpv6_ts_off(np->saddr.s6_addr32, +		tp->tsoffset = secure_tcpv6_ts_off(sock_net(sk), +						   np->saddr.s6_addr32,  						   sk->sk_v6_daddr.s6_addr32);  	} @@ -514,11 +515,12 @@ static struct tcp_md5sig_key *tcp_v6_md5_lookup(const struct sock *sk,  	return tcp_v6_md5_do_lookup(sk, &addr_sk->sk_v6_daddr);  } -static int tcp_v6_parse_md5_keys(struct sock *sk, char __user *optval, -				 int optlen) +static int tcp_v6_parse_md5_keys(struct sock *sk, int optname, +				 char __user *optval, int optlen)  {  	struct tcp_md5sig cmd;  	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&cmd.tcpm_addr; +	u8 prefixlen;  	if (optlen < sizeof(cmd))  		return -EINVAL; @@ -529,12 +531,22 @@ static int tcp_v6_parse_md5_keys(struct sock *sk, char __user *optval,  	if (sin6->sin6_family != AF_INET6)  		return -EINVAL; +	if (optname == TCP_MD5SIG_EXT && +	    cmd.tcpm_flags & TCP_MD5SIG_FLAG_PREFIX) { +		prefixlen = cmd.tcpm_prefixlen; +		if (prefixlen > 128 || (ipv6_addr_v4mapped(&sin6->sin6_addr) && +					prefixlen > 32)) +			return -EINVAL; +	} else { +		prefixlen = ipv6_addr_v4mapped(&sin6->sin6_addr) ? 32 : 128; +	} +  	if (!cmd.tcpm_keylen) {  		if (ipv6_addr_v4mapped(&sin6->sin6_addr))  			return tcp_md5_do_del(sk, (union tcp_md5_addr *)&sin6->sin6_addr.s6_addr32[3], -					      AF_INET); +					      AF_INET, prefixlen);  		return tcp_md5_do_del(sk, (union tcp_md5_addr *)&sin6->sin6_addr, -				      AF_INET6); +				      AF_INET6, prefixlen);  	}  	if (cmd.tcpm_keylen > TCP_MD5SIG_MAXKEYLEN) @@ -542,10 +554,12 @@ static int tcp_v6_parse_md5_keys(struct sock *sk, char __user *optval,  	if (ipv6_addr_v4mapped(&sin6->sin6_addr))  		return tcp_md5_do_add(sk, (union tcp_md5_addr *)&sin6->sin6_addr.s6_addr32[3], -				      AF_INET, cmd.tcpm_key, cmd.tcpm_keylen, GFP_KERNEL); +				      AF_INET, prefixlen, cmd.tcpm_key, +				      cmd.tcpm_keylen, GFP_KERNEL);  	return tcp_md5_do_add(sk, (union tcp_md5_addr *)&sin6->sin6_addr, -			      AF_INET6, cmd.tcpm_key, cmd.tcpm_keylen, GFP_KERNEL); +			      AF_INET6, prefixlen, cmd.tcpm_key, +			      cmd.tcpm_keylen, GFP_KERNEL);  }  static int tcp_v6_md5_hash_headers(struct tcp_md5sig_pool *hp, @@ -720,7 +734,7 @@ static void tcp_v6_init_req(struct request_sock *req,  	     np->rxopt.bits.rxinfo ||  	     np->rxopt.bits.rxoinfo || np->rxopt.bits.rxhlim ||  	     np->rxopt.bits.rxohlim || np->repflow)) { -		atomic_inc(&skb->users); +		refcount_inc(&skb->users);  		ireq->pktopts = skb;  	}  } @@ -788,7 +802,7 @@ static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32  	skb_reserve(buff, MAX_HEADER + sizeof(struct ipv6hdr) + tot_len); -	t1 = (struct tcphdr *) skb_push(buff, tot_len); +	t1 = skb_push(buff, tot_len);  	skb_reset_transport_header(buff);  	/* Swap the send and the receive. */ @@ -949,7 +963,7 @@ static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb)  	tcp_v6_send_ack(sk, skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt,  			tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale, -			tcp_time_stamp + tcptw->tw_ts_offset, +			tcp_time_stamp_raw() + tcptw->tw_ts_offset,  			tcptw->tw_ts_recent, tw->tw_bound_dev_if, tcp_twsk_md5_key(tcptw),  			tw->tw_tclass, cpu_to_be32(tw->tw_flowlabel)); @@ -971,7 +985,7 @@ static void tcp_v6_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb,  			tcp_rsk(req)->snt_isn + 1 : tcp_sk(sk)->snd_nxt,  			tcp_rsk(req)->rcv_nxt,  			req->rsk_rcv_wnd >> inet_rsk(req)->rcv_wscale, -			tcp_time_stamp + tcp_rsk(req)->ts_off, +			tcp_time_stamp_raw() + tcp_rsk(req)->ts_off,  			req->ts_recent, sk->sk_bound_dev_if,  			tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->daddr),  			0, 0); @@ -1185,7 +1199,7 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *  		 * across. Shucks.  		 */  		tcp_md5_do_add(newsk, (union tcp_md5_addr *)&newsk->sk_v6_daddr, -			       AF_INET6, key->key, key->keylen, +			       AF_INET6, 128, key->key, key->keylen,  			       sk_gfp_mask(sk, GFP_ATOMIC));  	}  #endif @@ -1248,9 +1262,6 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)  	if (skb->protocol == htons(ETH_P_IP))  		return tcp_v4_do_rcv(sk, skb); -	if (tcp_filter(sk, skb)) -		goto discard; -  	/*  	 *	socket locking is here for SMP purposes as backlog rcv  	 *	is currently called with bh processing disabled. @@ -1453,6 +1464,8 @@ process:  		if (nsk == sk) {  			reqsk_put(req);  			tcp_v6_restore_cb(skb); +		} else if (tcp_filter(sk, skb)) { +			goto discard_and_relse;  		} else if (tcp_child_process(sk, nsk, skb)) {  			tcp_v6_send_reset(nsk, skb);  			goto discard_and_relse; @@ -1796,7 +1809,7 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i)  		   from_kuid_munged(seq_user_ns(seq), sock_i_uid(sp)),  		   icsk->icsk_probes_out,  		   sock_i_ino(sp), -		   atomic_read(&sp->sk_refcnt), sp, +		   refcount_read(&sp->sk_refcnt), sp,  		   jiffies_to_clock_t(icsk->icsk_rto),  		   jiffies_to_clock_t(icsk->icsk_ack.ato),  		   (icsk->icsk_ack.quick << 1) | icsk->icsk_ack.pingpong, @@ -1829,7 +1842,7 @@ static void get_timewait6_sock(struct seq_file *seq,  		   dest->s6_addr32[2], dest->s6_addr32[3], destp,  		   tw->tw_substate, 0, 0,  		   3, jiffies_delta_to_clock_t(delta), 0, 0, 0, 0, -		   atomic_read(&tw->tw_refcnt), tw); +		   refcount_read(&tw->tw_refcnt), tw);  }  static int tcp6_seq_show(struct seq_file *seq, void *v) @@ -1909,6 +1922,7 @@ struct proto tcpv6_prot = {  	.unhash			= inet_unhash,  	.get_port		= inet_csk_get_port,  	.enter_memory_pressure	= tcp_enter_memory_pressure, +	.leave_memory_pressure	= tcp_leave_memory_pressure,  	.stream_memory_free	= tcp_stream_memory_free,  	.sockets_allocated	= &tcp_sockets_allocated,  	.memory_allocated	= &tcp_memory_allocated, |