mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	sctp: implement receiver-side procedures for the Reconf Response Parameter
This patch is to implement Receiver-Side Procedures for the Re-configuration Response Parameter in rfc6525 section 5.2.7. sctp_process_strreset_resp would process the response for any kind of reconf request, and the stream reconf is applied only when the response result is success. Signed-off-by: Xin Long <lucien.xin@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									c5c4ebb3ab
								
							
						
					
					
						commit
						11ae76e67a
					
				
					 3 changed files with 161 additions and 3 deletions
				
			
		| 
						 | 
				
			
			@ -305,6 +305,10 @@ struct sctp_chunk *sctp_process_strreset_addstrm_in(
 | 
			
		|||
				struct sctp_association *asoc,
 | 
			
		||||
				union sctp_params param,
 | 
			
		||||
				struct sctp_ulpevent **evp);
 | 
			
		||||
struct sctp_chunk *sctp_process_strreset_resp(
 | 
			
		||||
				struct sctp_association *asoc,
 | 
			
		||||
				union sctp_params param,
 | 
			
		||||
				struct sctp_ulpevent **evp);
 | 
			
		||||
 | 
			
		||||
/* Prototypes for statetable processing. */
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3881,9 +3881,9 @@ sctp_disposition_t sctp_sf_do_reconf(struct net *net,
 | 
			
		|||
		else if (param.p->type == SCTP_PARAM_RESET_ADD_IN_STREAMS)
 | 
			
		||||
			reply = sctp_process_strreset_addstrm_in(
 | 
			
		||||
				(struct sctp_association *)asoc, param, &ev);
 | 
			
		||||
		/* More handles for other types will be added here, by now it
 | 
			
		||||
		 * just ignores other types.
 | 
			
		||||
		 */
 | 
			
		||||
		else if (param.p->type == SCTP_PARAM_RESET_RESPONSE)
 | 
			
		||||
			reply = sctp_process_strreset_resp(
 | 
			
		||||
				(struct sctp_association *)asoc, param, &ev);
 | 
			
		||||
 | 
			
		||||
		if (ev)
 | 
			
		||||
			sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -675,3 +675,157 @@ struct sctp_chunk *sctp_process_strreset_addstrm_in(
 | 
			
		|||
 | 
			
		||||
	return chunk;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct sctp_chunk *sctp_process_strreset_resp(
 | 
			
		||||
				struct sctp_association *asoc,
 | 
			
		||||
				union sctp_params param,
 | 
			
		||||
				struct sctp_ulpevent **evp)
 | 
			
		||||
{
 | 
			
		||||
	struct sctp_strreset_resp *resp = param.v;
 | 
			
		||||
	struct sctp_stream *stream = asoc->stream;
 | 
			
		||||
	struct sctp_transport *t;
 | 
			
		||||
	__u16 i, nums, flags = 0;
 | 
			
		||||
	sctp_paramhdr_t *req;
 | 
			
		||||
	__u32 result;
 | 
			
		||||
 | 
			
		||||
	req = sctp_chunk_lookup_strreset_param(asoc, resp->response_seq, 0);
 | 
			
		||||
	if (!req)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	result = ntohl(resp->result);
 | 
			
		||||
	if (result != SCTP_STRRESET_PERFORMED) {
 | 
			
		||||
		/* if in progress, do nothing but retransmit */
 | 
			
		||||
		if (result == SCTP_STRRESET_IN_PROGRESS)
 | 
			
		||||
			return NULL;
 | 
			
		||||
		else if (result == SCTP_STRRESET_DENIED)
 | 
			
		||||
			flags = SCTP_STREAM_RESET_DENIED;
 | 
			
		||||
		else
 | 
			
		||||
			flags = SCTP_STREAM_RESET_FAILED;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (req->type == SCTP_PARAM_RESET_OUT_REQUEST) {
 | 
			
		||||
		struct sctp_strreset_outreq *outreq;
 | 
			
		||||
		__u16 *str_p = NULL;
 | 
			
		||||
 | 
			
		||||
		outreq = (struct sctp_strreset_outreq *)req;
 | 
			
		||||
		nums = (ntohs(outreq->param_hdr.length) - sizeof(*outreq)) / 2;
 | 
			
		||||
 | 
			
		||||
		if (result == SCTP_STRRESET_PERFORMED) {
 | 
			
		||||
			if (nums) {
 | 
			
		||||
				str_p = outreq->list_of_streams;
 | 
			
		||||
				for (i = 0; i < nums; i++)
 | 
			
		||||
					stream->out[ntohs(str_p[i])].ssn = 0;
 | 
			
		||||
			} else {
 | 
			
		||||
				for (i = 0; i < stream->outcnt; i++)
 | 
			
		||||
					stream->out[i].ssn = 0;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			flags = SCTP_STREAM_RESET_OUTGOING_SSN;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for (i = 0; i < stream->outcnt; i++)
 | 
			
		||||
			stream->out[i].state = SCTP_STREAM_OPEN;
 | 
			
		||||
 | 
			
		||||
		*evp = sctp_ulpevent_make_stream_reset_event(asoc, flags,
 | 
			
		||||
			nums, str_p, GFP_ATOMIC);
 | 
			
		||||
	} else if (req->type == SCTP_PARAM_RESET_IN_REQUEST) {
 | 
			
		||||
		struct sctp_strreset_inreq *inreq;
 | 
			
		||||
		__u16 *str_p = NULL;
 | 
			
		||||
 | 
			
		||||
		/* if the result is performed, it's impossible for inreq */
 | 
			
		||||
		if (result == SCTP_STRRESET_PERFORMED)
 | 
			
		||||
			return NULL;
 | 
			
		||||
 | 
			
		||||
		inreq = (struct sctp_strreset_inreq *)req;
 | 
			
		||||
		nums = (ntohs(inreq->param_hdr.length) - sizeof(*inreq)) / 2;
 | 
			
		||||
 | 
			
		||||
		str_p = inreq->list_of_streams;
 | 
			
		||||
		*evp = sctp_ulpevent_make_stream_reset_event(asoc, flags,
 | 
			
		||||
			nums, str_p, GFP_ATOMIC);
 | 
			
		||||
	} else if (req->type == SCTP_PARAM_RESET_TSN_REQUEST) {
 | 
			
		||||
		struct sctp_strreset_resptsn *resptsn;
 | 
			
		||||
		__u32 stsn, rtsn;
 | 
			
		||||
 | 
			
		||||
		/* check for resptsn, as sctp_verify_reconf didn't do it*/
 | 
			
		||||
		if (ntohs(param.p->length) != sizeof(*resptsn))
 | 
			
		||||
			return NULL;
 | 
			
		||||
 | 
			
		||||
		resptsn = (struct sctp_strreset_resptsn *)resp;
 | 
			
		||||
		stsn = ntohl(resptsn->senders_next_tsn);
 | 
			
		||||
		rtsn = ntohl(resptsn->receivers_next_tsn);
 | 
			
		||||
 | 
			
		||||
		if (result == SCTP_STRRESET_PERFORMED) {
 | 
			
		||||
			__u32 mtsn = sctp_tsnmap_get_max_tsn_seen(
 | 
			
		||||
						&asoc->peer.tsn_map);
 | 
			
		||||
 | 
			
		||||
			sctp_ulpq_reasm_flushtsn(&asoc->ulpq, mtsn);
 | 
			
		||||
			sctp_ulpq_abort_pd(&asoc->ulpq, GFP_ATOMIC);
 | 
			
		||||
 | 
			
		||||
			sctp_tsnmap_init(&asoc->peer.tsn_map,
 | 
			
		||||
					 SCTP_TSN_MAP_INITIAL,
 | 
			
		||||
					 stsn, GFP_ATOMIC);
 | 
			
		||||
 | 
			
		||||
			sctp_outq_free(&asoc->outqueue);
 | 
			
		||||
 | 
			
		||||
			asoc->next_tsn = rtsn;
 | 
			
		||||
			asoc->ctsn_ack_point = asoc->next_tsn - 1;
 | 
			
		||||
			asoc->adv_peer_ack_point = asoc->ctsn_ack_point;
 | 
			
		||||
 | 
			
		||||
			for (i = 0; i < stream->outcnt; i++)
 | 
			
		||||
				stream->out[i].ssn = 0;
 | 
			
		||||
			for (i = 0; i < stream->incnt; i++)
 | 
			
		||||
				stream->in[i].ssn = 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for (i = 0; i < stream->outcnt; i++)
 | 
			
		||||
			stream->out[i].state = SCTP_STREAM_OPEN;
 | 
			
		||||
 | 
			
		||||
		*evp = sctp_ulpevent_make_assoc_reset_event(asoc, flags,
 | 
			
		||||
			stsn, rtsn, GFP_ATOMIC);
 | 
			
		||||
	} else if (req->type == SCTP_PARAM_RESET_ADD_OUT_STREAMS) {
 | 
			
		||||
		struct sctp_strreset_addstrm *addstrm;
 | 
			
		||||
		__u16 number;
 | 
			
		||||
 | 
			
		||||
		addstrm = (struct sctp_strreset_addstrm *)req;
 | 
			
		||||
		nums = ntohs(addstrm->number_of_streams);
 | 
			
		||||
		number = stream->outcnt - nums;
 | 
			
		||||
 | 
			
		||||
		if (result == SCTP_STRRESET_PERFORMED)
 | 
			
		||||
			for (i = number; i < stream->outcnt; i++)
 | 
			
		||||
				stream->out[i].state = SCTP_STREAM_OPEN;
 | 
			
		||||
		else
 | 
			
		||||
			stream->outcnt = number;
 | 
			
		||||
 | 
			
		||||
		*evp = sctp_ulpevent_make_stream_change_event(asoc, flags,
 | 
			
		||||
			0, nums, GFP_ATOMIC);
 | 
			
		||||
	} else if (req->type == SCTP_PARAM_RESET_ADD_IN_STREAMS) {
 | 
			
		||||
		struct sctp_strreset_addstrm *addstrm;
 | 
			
		||||
 | 
			
		||||
		/* if the result is performed, it's impossible for addstrm in
 | 
			
		||||
		 * request.
 | 
			
		||||
		 */
 | 
			
		||||
		if (result == SCTP_STRRESET_PERFORMED)
 | 
			
		||||
			return NULL;
 | 
			
		||||
 | 
			
		||||
		addstrm = (struct sctp_strreset_addstrm *)req;
 | 
			
		||||
		nums = ntohs(addstrm->number_of_streams);
 | 
			
		||||
 | 
			
		||||
		*evp = sctp_ulpevent_make_stream_change_event(asoc, flags,
 | 
			
		||||
			nums, 0, GFP_ATOMIC);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	asoc->strreset_outstanding--;
 | 
			
		||||
	asoc->strreset_outseq++;
 | 
			
		||||
 | 
			
		||||
	/* remove everything for this reconf request */
 | 
			
		||||
	if (!asoc->strreset_outstanding) {
 | 
			
		||||
		t = asoc->strreset_chunk->transport;
 | 
			
		||||
		if (del_timer(&t->reconf_timer))
 | 
			
		||||
			sctp_transport_put(t);
 | 
			
		||||
 | 
			
		||||
		sctp_chunk_put(asoc->strreset_chunk);
 | 
			
		||||
		asoc->strreset_chunk = NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue