sctp_sched_dequeue_common(outq, ch); /* No need to call dequeue_done here because *thechunksarenotscheduledbynow.
*/
/* Mark as failed send. */
sctp_chunk_fail(ch, (__force __u32)SCTP_ERROR_INV_STRM); if (asoc->peer.prsctp_capable &&
SCTP_PR_PRIO_ENABLED(ch->sinfo.sinfo_flags))
asoc->sent_cnt_removable--;
/* Migrates chunks from stream queues to new stream queues if needed, *butnotacrossassociations.Also,removesthosechunkstostreams *higherthanthenewmax.
*/ staticvoid sctp_stream_outq_migrate(struct sctp_stream *stream, struct sctp_stream *new, __u16 outcnt)
{ int i;
if (stream->outcnt > outcnt)
sctp_stream_shrink_out(stream, outcnt);
if (new) { /* Here we actually move the old ext stuff into the new *buffer,becausewewanttokeepit.Then *sctp_stream_updatewillswap->outpointers.
*/ for (i = 0; i < outcnt; i++) {
sctp_stream_free_ext(new, i);
SCTP_SO(new, i)->ext = SCTP_SO(stream, i)->ext;
SCTP_SO(stream, i)->ext = NULL;
}
}
for (i = outcnt; i < stream->outcnt; i++)
sctp_stream_free_ext(stream, i);
}
ret = genradix_prealloc(&stream->in, incnt, gfp); if (ret) return ret;
out:
stream->incnt = incnt; return0;
}
int sctp_stream_init(struct sctp_stream *stream, __u16 outcnt, __u16 incnt,
gfp_t gfp)
{ struct sctp_sched_ops *sched = sctp_sched_ops_from_stream(stream); int i, ret = 0;
gfp |= __GFP_NOWARN;
/* Initial stream->out size may be very big, so free it and alloc *anewonewithnewoutcnttosavememoryifneeded.
*/ if (outcnt == stream->outcnt) goto handle_in;
/* Filter out chunks queued on streams that won't exist anymore */
sched->unsched_all(stream);
sctp_stream_outq_migrate(stream, NULL, outcnt);
sched->sched_all(stream);
ret = sctp_stream_alloc_out(stream, outcnt, gfp); if (ret) return ret;
for (i = 0; i < stream->outcnt; i++)
SCTP_SO(stream, i)->state = SCTP_STREAM_OPEN;
handle_in:
sctp_stream_interleave_init(stream); if (!incnt) return0;
sched->unsched_all(stream); for (i = 0; i < stream->outcnt; i++)
sctp_stream_free_ext(stream, i);
genradix_free(&stream->out);
genradix_free(&stream->in);
}
void sctp_stream_clear(struct sctp_stream *stream)
{ int i;
for (i = 0; i < stream->outcnt; i++) {
SCTP_SO(stream, i)->mid = 0;
SCTP_SO(stream, i)->mid_uo = 0;
}
for (i = 0; i < stream->incnt; i++)
SCTP_SI(stream, i)->mid = 0;
}
if (out) { if (str_nums) for (i = 0; i < str_nums; i++)
SCTP_SO(stream, str_list[i])->state =
SCTP_STREAM_CLOSED; else for (i = 0; i < stream->outcnt; i++)
SCTP_SO(stream, i)->state = SCTP_STREAM_CLOSED;
}
retval = sctp_send_reconf(asoc, chunk); if (retval) {
sctp_chunk_put(asoc->strreset_chunk);
asoc->strreset_chunk = NULL; if (!out) goto out;
if (str_nums) for (i = 0; i < str_nums; i++)
SCTP_SO(stream, str_list[i])->state =
SCTP_STREAM_OPEN; else for (i = 0; i < stream->outcnt; i++)
SCTP_SO(stream, i)->state = SCTP_STREAM_OPEN;
goto out;
}
asoc->strreset_outstanding = out + in;
out: return retval;
}
int sctp_send_reset_assoc(struct sctp_association *asoc)
{ struct sctp_stream *stream = &asoc->stream; struct sctp_chunk *chunk = NULL; int retval;
__u16 i;
if (!asoc->peer.reconf_capable ||
!(asoc->strreset_enable & SCTP_ENABLE_RESET_ASSOC_REQ)) return -ENOPROTOOPT;
if (asoc->strreset_outstanding) return -EINPROGRESS;
if (!sctp_outq_is_empty(&asoc->outqueue)) return -EAGAIN;
chunk = sctp_make_strreset_tsnreq(asoc); if (!chunk) return -ENOMEM;
/* Block further xmit of data until this request is completed */ for (i = 0; i < stream->outcnt; i++)
SCTP_SO(stream, i)->state = SCTP_STREAM_CLOSED;
if (ntohl(outreq->send_reset_at_tsn) >
sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map)) {
result = SCTP_STRRESET_IN_PROGRESS; goto err;
}
if (TSN_lt(asoc->strreset_inseq, request_seq) ||
TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
result = SCTP_STRRESET_ERR_BAD_SEQNO; goto err;
} elseif (TSN_lt(request_seq, asoc->strreset_inseq)) {
i = asoc->strreset_inseq - request_seq - 1;
result = asoc->strreset_result[i]; goto err;
}
asoc->strreset_inseq++;
/* Check strreset_enable after inseq inc, as sender cannot tell *thepeerdoesn'tenablestrresetafterreceivingresponsewith *resultdenied,aswellastokeepconsistentwithbsd.
*/ if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ)) goto out;
nums = (ntohs(param.p->length) - sizeof(*outreq)) / sizeof(__u16);
str_p = outreq->list_of_streams; for (i = 0; i < nums; i++) { if (ntohs(str_p[i]) >= stream->incnt) {
result = SCTP_STRRESET_ERR_WRONG_SSN; goto out;
}
}
if (asoc->strreset_chunk) { if (!sctp_chunk_lookup_strreset_param(
asoc, outreq->response_seq,
SCTP_PARAM_RESET_IN_REQUEST)) { /* same process with outstanding isn't 0 */
result = SCTP_STRRESET_ERR_IN_PROGRESS; goto out;
}
if (nums) for (i = 0; i < nums; i++)
SCTP_SO(stream, ntohs(str_p[i]))->state =
SCTP_STREAM_CLOSED; else for (i = 0; i < stream->outcnt; i++)
SCTP_SO(stream, i)->state = SCTP_STREAM_CLOSED;
if (!sctp_outq_is_empty(&asoc->outqueue)) {
result = SCTP_STRRESET_IN_PROGRESS; goto err;
}
asoc->strreset_inseq++;
if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_ASSOC_REQ)) goto out;
if (asoc->strreset_outstanding) {
result = SCTP_STRRESET_ERR_IN_PROGRESS; goto out;
}
/* G4: The same processing as though a FWD-TSN chunk (as defined in *[RFC3758])withallstreamsaffectedandanewcumulativeTSN *ACKoftheReceiver'sNextTSNminus1werereceivedMUSTbe *performed.
*/
max_tsn_seen = sctp_tsnmap_get_max_tsn_seen(&asoc->peer.tsn_map);
asoc->stream.si->report_ftsn(&asoc->ulpq, max_tsn_seen);
/* G1: Compute an appropriate value for the Receiver's Next TSN -- the *TSNthatthepeershouldusetosendthenextDATAchunk.The *valueSHOULDbethesmallestTSNnotacknowledgedbythe *receiveroftherequestplus2^31.
*/
init_tsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map) + (1U << 31);
sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_INITIAL,
init_tsn, GFP_ATOMIC);
/* G3: The same processing as though a SACK chunk with no gap report *andacumulativeTSNACKoftheSender'sNextTSNminus1were *receivedMUSTbeperformed.
*/
sctp_outq_free(&asoc->outqueue);
/* G2: Compute an appropriate value for the local endpoint's next TSN, *i.e.,thenextTSNassignedbythereceiveroftheSSN/TSNreset *chunk.ThevalueSHOULDbethehighestTSNsentbythereceiver *oftherequestplus1.
*/
next_tsn = asoc->next_tsn;
asoc->ctsn_ack_point = next_tsn - 1;
asoc->adv_peer_ack_point = asoc->ctsn_ack_point;
/* G5: The next expected and outgoing SSNs MUST be reset to 0 for all *incomingandoutgoingstreams.
*/ for (i = 0; i < stream->outcnt; i++) {
SCTP_SO(stream, i)->mid = 0;
SCTP_SO(stream, i)->mid_uo = 0;
} for (i = 0; i < stream->incnt; i++)
SCTP_SI(stream, i)->mid = 0;
request_seq = ntohl(addstrm->request_seq); if (TSN_lt(asoc->strreset_inseq, request_seq) ||
TSN_lt(request_seq, asoc->strreset_inseq - 2)) {
result = SCTP_STRRESET_ERR_BAD_SEQNO; goto err;
} elseif (TSN_lt(request_seq, asoc->strreset_inseq)) {
i = asoc->strreset_inseq - request_seq - 1;
result = asoc->strreset_result[i]; goto err;
}
asoc->strreset_inseq++;
if (!(asoc->strreset_enable & SCTP_ENABLE_CHANGE_ASSOC_REQ)) goto out;
in = ntohs(addstrm->number_of_streams);
incnt = stream->incnt + in; if (!in || incnt > SCTP_MAX_STREAM) goto out;
if (sctp_stream_alloc_in(stream, incnt, GFP_ATOMIC)) goto out;
if (asoc->strreset_chunk) { if (!sctp_chunk_lookup_strreset_param(
asoc, 0, SCTP_PARAM_RESET_ADD_IN_STREAMS)) { /* same process with outstanding isn't 0 */
result = SCTP_STRRESET_ERR_IN_PROGRESS; goto out;
}
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; elseif (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;
__be16 *str_p;
/* Clean up sacked and abandoned queues only. As the *out_chunk_listmaynotbeempty,spliceittotemp, *thengetitbackaftersctp_outq_freeisdone.
*/
list_splice_init(&asoc->outqueue.out_chunk_list, &temp);
sctp_outq_free(&asoc->outqueue);
list_splice_init(&temp, &asoc->outqueue.out_chunk_list);
/* remove everything for this reconf request */ if (!asoc->strreset_outstanding) {
t = asoc->strreset_chunk->transport; if (timer_delete(&t->reconf_timer))
sctp_transport_put(t);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.