diff options
| author | Daniel Vetter <daniel.vetter@ffwll.ch> | 2012-08-17 10:57:56 +0400 | 
|---|---|---|
| committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2012-08-17 11:01:08 +0400 | 
| commit | a22ddff8bedfe33eeb1330bbb7ef1fbe007a42c4 (patch) | |
| tree | 61a2eb7fa62f5af10c2b913ca429e6b068b0eb2d /net/sctp/socket.c | |
| parent | 20d5a540e55a29daeef12706f9ee73baf5641c16 (diff) | |
| parent | d9875690d9b89a866022ff49e3fcea892345ad92 (diff) | |
| download | linux-a22ddff8bedfe33eeb1330bbb7ef1fbe007a42c4.tar.xz | |
Merge tag 'v3.6-rc2' into drm-intel-next
Backmerge Linux 3.6-rc2 to resolve a few funny conflicts before we put
even more madness on top:
- drivers/gpu/drm/i915/i915_irq.c: Just a spurious WARN removed in
  -fixes, that has been changed in a variable-rename in -next, too.
- drivers/gpu/drm/i915/intel_ringbuffer.c: -next remove scratch_addr
  (since all their users have been extracted in another fucntion),
  -fixes added another user for a hw workaroudn.
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'net/sctp/socket.c')
| -rw-r--r-- | net/sctp/socket.c | 119 | 
1 files changed, 114 insertions, 5 deletions
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index b3b8a8d813eb..5e259817a7f3 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -1231,8 +1231,14 @@ out_free:  	SCTP_DEBUG_PRINTK("About to exit __sctp_connect() free asoc: %p"  			  " kaddrs: %p err: %d\n",  			  asoc, kaddrs, err); -	if (asoc) +	if (asoc) { +		/* sctp_primitive_ASSOCIATE may have added this association +		 * To the hash table, try to unhash it, just in case, its a noop +		 * if it wasn't hashed so we're safe +		 */ +		sctp_unhash_established(asoc);  		sctp_association_free(asoc); +	}  	return err;  } @@ -1853,7 +1859,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,  	}  	if (asoc->pmtu_pending) -		sctp_assoc_pending_pmtu(asoc); +		sctp_assoc_pending_pmtu(sk, asoc);  	/* If fragmentation is disabled and the message length exceeds the  	 * association fragmentation point, return EMSGSIZE.  The I-D @@ -1942,8 +1948,10 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,  	goto out_unlock;  out_free: -	if (new_asoc) +	if (new_asoc) { +		sctp_unhash_established(asoc);  		sctp_association_free(asoc); +	}  out_unlock:  	sctp_release_sock(sk); @@ -2365,7 +2373,7 @@ static int sctp_apply_peer_addr_params(struct sctp_paddrparams *params,  	if ((params->spp_flags & SPP_PMTUD_DISABLE) && params->spp_pathmtu) {  		if (trans) {  			trans->pathmtu = params->spp_pathmtu; -			sctp_assoc_sync_pmtu(asoc); +			sctp_assoc_sync_pmtu(sctp_opt2sk(sp), asoc);  		} else if (asoc) {  			asoc->pathmtu = params->spp_pathmtu;  			sctp_frag_point(asoc, params->spp_pathmtu); @@ -2382,7 +2390,7 @@ static int sctp_apply_peer_addr_params(struct sctp_paddrparams *params,  				(trans->param_flags & ~SPP_PMTUD) | pmtud_change;  			if (update) {  				sctp_transport_pmtu(trans, sctp_opt2sk(sp)); -				sctp_assoc_sync_pmtu(asoc); +				sctp_assoc_sync_pmtu(sctp_opt2sk(sp), asoc);  			}  		} else if (asoc) {  			asoc->param_flags = @@ -3470,6 +3478,56 @@ static int sctp_setsockopt_auto_asconf(struct sock *sk, char __user *optval,  } +/* + * SCTP_PEER_ADDR_THLDS + * + * This option allows us to alter the partially failed threshold for one or all + * transports in an association.  See Section 6.1 of: + * http://www.ietf.org/id/draft-nishida-tsvwg-sctp-failover-05.txt + */ +static int sctp_setsockopt_paddr_thresholds(struct sock *sk, +					    char __user *optval, +					    unsigned int optlen) +{ +	struct sctp_paddrthlds val; +	struct sctp_transport *trans; +	struct sctp_association *asoc; + +	if (optlen < sizeof(struct sctp_paddrthlds)) +		return -EINVAL; +	if (copy_from_user(&val, (struct sctp_paddrthlds __user *)optval, +			   sizeof(struct sctp_paddrthlds))) +		return -EFAULT; + + +	if (sctp_is_any(sk, (const union sctp_addr *)&val.spt_address)) { +		asoc = sctp_id2assoc(sk, val.spt_assoc_id); +		if (!asoc) +			return -ENOENT; +		list_for_each_entry(trans, &asoc->peer.transport_addr_list, +				    transports) { +			if (val.spt_pathmaxrxt) +				trans->pathmaxrxt = val.spt_pathmaxrxt; +			trans->pf_retrans = val.spt_pathpfthld; +		} + +		if (val.spt_pathmaxrxt) +			asoc->pathmaxrxt = val.spt_pathmaxrxt; +		asoc->pf_retrans = val.spt_pathpfthld; +	} else { +		trans = sctp_addr_id2transport(sk, &val.spt_address, +					       val.spt_assoc_id); +		if (!trans) +			return -ENOENT; + +		if (val.spt_pathmaxrxt) +			trans->pathmaxrxt = val.spt_pathmaxrxt; +		trans->pf_retrans = val.spt_pathpfthld; +	} + +	return 0; +} +  /* API 6.2 setsockopt(), getsockopt()   *   * Applications use setsockopt() and getsockopt() to set or retrieve @@ -3619,6 +3677,9 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,  	case SCTP_AUTO_ASCONF:  		retval = sctp_setsockopt_auto_asconf(sk, optval, optlen);  		break; +	case SCTP_PEER_ADDR_THLDS: +		retval = sctp_setsockopt_paddr_thresholds(sk, optval, optlen); +		break;  	default:  		retval = -ENOPROTOOPT;  		break; @@ -5490,6 +5551,51 @@ static int sctp_getsockopt_assoc_ids(struct sock *sk, int len,  	return 0;  } +/* + * SCTP_PEER_ADDR_THLDS + * + * This option allows us to fetch the partially failed threshold for one or all + * transports in an association.  See Section 6.1 of: + * http://www.ietf.org/id/draft-nishida-tsvwg-sctp-failover-05.txt + */ +static int sctp_getsockopt_paddr_thresholds(struct sock *sk, +					    char __user *optval, +					    int len, +					    int __user *optlen) +{ +	struct sctp_paddrthlds val; +	struct sctp_transport *trans; +	struct sctp_association *asoc; + +	if (len < sizeof(struct sctp_paddrthlds)) +		return -EINVAL; +	len = sizeof(struct sctp_paddrthlds); +	if (copy_from_user(&val, (struct sctp_paddrthlds __user *)optval, len)) +		return -EFAULT; + +	if (sctp_is_any(sk, (const union sctp_addr *)&val.spt_address)) { +		asoc = sctp_id2assoc(sk, val.spt_assoc_id); +		if (!asoc) +			return -ENOENT; + +		val.spt_pathpfthld = asoc->pf_retrans; +		val.spt_pathmaxrxt = asoc->pathmaxrxt; +	} else { +		trans = sctp_addr_id2transport(sk, &val.spt_address, +					       val.spt_assoc_id); +		if (!trans) +			return -ENOENT; + +		val.spt_pathmaxrxt = trans->pathmaxrxt; +		val.spt_pathpfthld = trans->pf_retrans; +	} + +	if (put_user(len, optlen) || copy_to_user(optval, &val, len)) +		return -EFAULT; + +	return 0; +} +  SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,  				char __user *optval, int __user *optlen)  { @@ -5628,6 +5734,9 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,  	case SCTP_AUTO_ASCONF:  		retval = sctp_getsockopt_auto_asconf(sk, len, optval, optlen);  		break; +	case SCTP_PEER_ADDR_THLDS: +		retval = sctp_getsockopt_paddr_thresholds(sk, optval, len, optlen); +		break;  	default:  		retval = -ENOPROTOOPT;  		break;  | 
