sctp: Fix SCTP_MAXSEG socket option to comply to spec.
We had a bug that we never stored the user-defined value for MAXSEG when setting the value on an association. Thus future PMTU events ended up re-writing the frag point and increasing it past user limit. Additionally, when setting the option on the socket/endpoint, we effect all current associations, which is against spec. Now, we store the user 'maxseg' value along with the computed 'frag_point'. We inherit 'maxseg' from the socket at association creation and use it as an upper limit for 'frag_point' when its set. Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
This commit is contained in:
		
					parent
					
						
							
								cb95ea32a4
							
						
					
				
			
			
				commit
				
					
						f68b2e05f3
					
				
			
		
					 4 changed files with 11 additions and 14 deletions
				
			
		| 
						 | 
				
			
			@ -486,15 +486,16 @@ static inline __s32 sctp_jitter(__u32 rto)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
/* Break down data chunks at this point.  */
 | 
			
		||||
static inline int sctp_frag_point(const struct sctp_sock *sp, int pmtu)
 | 
			
		||||
static inline int sctp_frag_point(const struct sctp_association *asoc, int pmtu)
 | 
			
		||||
{
 | 
			
		||||
	struct sctp_sock *sp = sctp_sk(asoc->base.sk);
 | 
			
		||||
	int frag = pmtu;
 | 
			
		||||
 | 
			
		||||
	frag -= sp->pf->af->net_header_len;
 | 
			
		||||
	frag -= sizeof(struct sctphdr) + sizeof(struct sctp_data_chunk);
 | 
			
		||||
 | 
			
		||||
	if (sp->user_frag)
 | 
			
		||||
		frag = min_t(int, frag, sp->user_frag);
 | 
			
		||||
	if (asoc->user_frag)
 | 
			
		||||
		frag = min_t(int, frag, asoc->user_frag);
 | 
			
		||||
 | 
			
		||||
	frag = min_t(int, frag, SCTP_MAX_CHUNK_LEN);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1763,6 +1763,7 @@ struct sctp_association {
 | 
			
		|||
 | 
			
		||||
	/* The message size at which SCTP fragmentation will occur. */
 | 
			
		||||
	__u32 frag_point;
 | 
			
		||||
	__u32 user_frag;
 | 
			
		||||
 | 
			
		||||
	/* Counter used to count INIT errors. */
 | 
			
		||||
	int init_err_counter;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -112,6 +112,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
 | 
			
		|||
	asoc->cookie_life.tv_usec = (sp->assocparams.sasoc_cookie_life % 1000)
 | 
			
		||||
					* 1000;
 | 
			
		||||
	asoc->frag_point = 0;
 | 
			
		||||
	asoc->user_frag = sp->user_frag;
 | 
			
		||||
 | 
			
		||||
	/* Set the association max_retrans and RTO values from the
 | 
			
		||||
	 * socket values.
 | 
			
		||||
| 
						 | 
				
			
			@ -674,7 +675,7 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
 | 
			
		|||
			  "%d\n", asoc, asoc->pathmtu);
 | 
			
		||||
	peer->pmtu_pending = 0;
 | 
			
		||||
 | 
			
		||||
	asoc->frag_point = sctp_frag_point(sp, asoc->pathmtu);
 | 
			
		||||
	asoc->frag_point = sctp_frag_point(asoc, asoc->pathmtu);
 | 
			
		||||
 | 
			
		||||
	/* The asoc->peer.port might not be meaningful yet, but
 | 
			
		||||
	 * initialize the packet structure anyway.
 | 
			
		||||
| 
						 | 
				
			
			@ -1330,9 +1331,8 @@ void sctp_assoc_sync_pmtu(struct sctp_association *asoc)
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	if (pmtu) {
 | 
			
		||||
		struct sctp_sock *sp = sctp_sk(asoc->base.sk);
 | 
			
		||||
		asoc->pathmtu = pmtu;
 | 
			
		||||
		asoc->frag_point = sctp_frag_point(sp, pmtu);
 | 
			
		||||
		asoc->frag_point = sctp_frag_point(asoc, pmtu);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	SCTP_DEBUG_PRINTK("%s: asoc:%p, pmtu:%d, frag_point:%d\n",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2243,7 +2243,7 @@ static int sctp_apply_peer_addr_params(struct sctp_paddrparams *params,
 | 
			
		|||
			sctp_assoc_sync_pmtu(asoc);
 | 
			
		||||
		} else if (asoc) {
 | 
			
		||||
			asoc->pathmtu = params->spp_pathmtu;
 | 
			
		||||
			sctp_frag_point(sp, params->spp_pathmtu);
 | 
			
		||||
			sctp_frag_point(asoc, params->spp_pathmtu);
 | 
			
		||||
		} else {
 | 
			
		||||
			sp->pathmtu = params->spp_pathmtu;
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -2880,15 +2880,10 @@ static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, int optl
 | 
			
		|||
			val -= sizeof(struct sctphdr) +
 | 
			
		||||
					sizeof(struct sctp_data_chunk);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		asoc->frag_point = val;
 | 
			
		||||
		asoc->user_frag = val;
 | 
			
		||||
		asoc->frag_point = sctp_frag_point(asoc, asoc->pathmtu);
 | 
			
		||||
	} else {
 | 
			
		||||
		sp->user_frag = val;
 | 
			
		||||
 | 
			
		||||
		/* Update the frag_point of the existing associations. */
 | 
			
		||||
		list_for_each_entry(asoc, &(sp->ep->asocs), asocs) {
 | 
			
		||||
			asoc->frag_point = sctp_frag_point(sp, asoc->pathmtu);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue