Skip to content

Commit

Permalink
sctp: implement assign_number for sctp_stream_interleave
Browse files Browse the repository at this point in the history
assign_number is added as a member of sctp_stream_interleave, used
to assign ssn for data or mid (message id) for idata, called in
sctp_packet_append_data. sctp_chunk_assign_ssn is left as it is,
and sctp_chunk_assign_mid is added for sctp_stream_interleave_1.

This procedure is described in section 2.2.2 of RFC8260.

All sizeof(struct sctp_data_chunk) in tx path is replaced with
sctp_datachk_len, to make it right for idata as well. And also
adjust sctp_chunk_is_data for SCTP_CID_I_DATA.

After this patch, idata can be built and sent in tx path.

Note that if sp strm_interleave is set, it has to wait_connect in
sctp_sendmsg, as asoc intl_enable need to be known after 4 shake-
hands, to decide if it should use data or idata later. data and
idata can't be mixed to send in one asoc.

Signed-off-by: Xin Long <lucien.xin@gmail.com>
Acked-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Acked-by: Neil Horman <nhorman@tuxdriver.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
lxin authored and davem330 committed Dec 11, 2017
1 parent 0c3f6f6 commit 668c9be
Show file tree
Hide file tree
Showing 9 changed files with 83 additions and 14 deletions.
9 changes: 5 additions & 4 deletions include/net/sctp/constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,12 +145,13 @@ SCTP_SUBTYPE_CONSTRUCTOR(OTHER, enum sctp_event_other, other)
SCTP_SUBTYPE_CONSTRUCTOR(PRIMITIVE, enum sctp_event_primitive, primitive)


#define sctp_chunk_is_data(a) (a->chunk_hdr->type == SCTP_CID_DATA)
#define sctp_chunk_is_data(a) (a->chunk_hdr->type == SCTP_CID_DATA || \
a->chunk_hdr->type == SCTP_CID_I_DATA)

/* Calculate the actual data size in a data chunk */
#define SCTP_DATA_SNDSIZE(c) ((int)((unsigned long)(c->chunk_end)\
- (unsigned long)(c->chunk_hdr)\
- sizeof(struct sctp_data_chunk)))
#define SCTP_DATA_SNDSIZE(c) ((int)((unsigned long)(c->chunk_end) - \
(unsigned long)(c->chunk_hdr) - \
sctp_datachk_len(&c->asoc->stream)))

/* Internal error codes */
enum sctp_ierror {
Expand Down
4 changes: 2 additions & 2 deletions include/net/sctp/sctp.h
Original file line number Diff line number Diff line change
Expand Up @@ -444,13 +444,13 @@ static inline int sctp_frag_point(const struct sctp_association *asoc, int pmtu)
int frag = pmtu;

frag -= sp->pf->af->net_header_len;
frag -= sizeof(struct sctphdr) + sizeof(struct sctp_data_chunk);
frag -= sizeof(struct sctphdr) + sctp_datachk_len(&asoc->stream);

if (asoc->user_frag)
frag = min_t(int, frag, asoc->user_frag);

frag = SCTP_TRUNC4(min_t(int, frag, SCTP_MAX_CHUNK_LEN -
sizeof(struct sctp_data_chunk)));
sctp_datachk_len(&asoc->stream)));

return frag;
}
Expand Down
2 changes: 1 addition & 1 deletion include/net/sctp/sm.h
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ static inline __u16 sctp_data_size(struct sctp_chunk *chunk)
__u16 size;

size = ntohs(chunk->chunk_hdr->length);
size -= sizeof(struct sctp_data_chunk);
size -= sctp_datahdr_len(&chunk->asoc->stream);

return size;
}
Expand Down
1 change: 1 addition & 0 deletions include/net/sctp/stream_interleave.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ struct sctp_stream_interleave {
struct sctp_chunk *(*make_datafrag)(const struct sctp_association *asoc,
const struct sctp_sndrcvinfo *sinfo,
int len, __u8 flags, gfp_t gfp);
void (*assign_number)(struct sctp_chunk *chunk);
};

void sctp_stream_interleave_init(struct sctp_stream *stream);
Expand Down
18 changes: 17 additions & 1 deletion include/net/sctp/structs.h
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,18 @@ void sctp_stream_update(struct sctp_stream *stream, struct sctp_stream *new);
#define sctp_ssn_skip(stream, type, sid, ssn) \
((stream)->type[sid].ssn = ssn + 1)

/* What is the current MID number for this stream? */
#define sctp_mid_peek(stream, type, sid) \
((stream)->type[sid].mid)

/* Return the next MID number for this stream. */
#define sctp_mid_next(stream, type, sid) \
((stream)->type[sid].mid++)

/* Skip over this mid and all below. */
#define sctp_mid_skip(stream, type, sid, mid) \
((stream)->type[sid].mid = mid + 1)

/*
* Pointers to address related SCTP functions.
* (i.e. things that depend on the address family.)
Expand Down Expand Up @@ -623,6 +635,7 @@ struct sctp_chunk {
__u16 rtt_in_progress:1, /* This chunk used for RTT calc? */
has_tsn:1, /* Does this chunk have a TSN yet? */
has_ssn:1, /* Does this chunk have a SSN yet? */
#define has_mid has_ssn
singleton:1, /* Only chunk in the packet? */
end_of_packet:1, /* Last chunk in the packet? */
ecn_ce_done:1, /* Have we processed the ECN CE bit? */
Expand Down Expand Up @@ -1360,7 +1373,10 @@ struct sctp_stream_out_ext {
};

struct sctp_stream_out {
__u16 ssn;
union {
__u32 mid;
__u16 ssn;
};
__u8 state;
struct sctp_stream_out_ext *ext;
};
Expand Down
5 changes: 3 additions & 2 deletions net/sctp/output.c
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,7 @@ static enum sctp_xmit __sctp_packet_append_chunk(struct sctp_packet *packet,
/* We believe that this chunk is OK to add to the packet */
switch (chunk->chunk_hdr->type) {
case SCTP_CID_DATA:
case SCTP_CID_I_DATA:
/* Account for the data being in the packet */
sctp_packet_append_data(packet, chunk);
/* Disallow SACK bundling after DATA. */
Expand Down Expand Up @@ -724,7 +725,7 @@ static enum sctp_xmit sctp_packet_can_append_data(struct sctp_packet *packet,
* or delay in hopes of bundling a full sized packet.
*/
if (chunk->skb->len + q->out_qlen > transport->pathmtu -
packet->overhead - sizeof(struct sctp_data_chunk) - 4)
packet->overhead - sctp_datachk_len(&chunk->asoc->stream) - 4)
/* Enough data queued to fill a packet */
return SCTP_XMIT_OK;

Expand Down Expand Up @@ -759,7 +760,7 @@ static void sctp_packet_append_data(struct sctp_packet *packet,

asoc->peer.rwnd = rwnd;
sctp_chunk_assign_tsn(chunk);
sctp_chunk_assign_ssn(chunk);
asoc->stream.si->assign_number(chunk);
}

static enum sctp_xmit sctp_packet_will_fit(struct sctp_packet *packet,
Expand Down
17 changes: 15 additions & 2 deletions net/sctp/socket.c
Original file line number Diff line number Diff line change
Expand Up @@ -2002,7 +2002,20 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len)
if (err < 0)
goto out_free;

wait_connect = true;
/* If stream interleave is enabled, wait_connect has to be
* done earlier than data enqueue, as it needs to make data
* or idata according to asoc->intl_enable which is set
* after connection is done.
*/
if (sctp_sk(asoc->base.sk)->strm_interleave) {
timeo = sock_sndtimeo(sk, 0);
err = sctp_wait_for_connect(asoc, &timeo);
if (err)
goto out_unlock;
} else {
wait_connect = true;
}

pr_debug("%s: we associated primitively\n", __func__);
}

Expand Down Expand Up @@ -3180,7 +3193,7 @@ static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, unsigned
if (val == 0) {
val = asoc->pathmtu - sp->pf->af->net_header_len;
val -= sizeof(struct sctphdr) +
sizeof(struct sctp_data_chunk);
sctp_datachk_len(&asoc->stream);
}
asoc->user_frag = val;
asoc->frag_point = sctp_frag_point(asoc, asoc->pathmtu);
Expand Down
37 changes: 37 additions & 0 deletions net/sctp/stream_interleave.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,16 +57,53 @@ static struct sctp_chunk *sctp_make_idatafrag_empty(
return retval;
}

static void sctp_chunk_assign_mid(struct sctp_chunk *chunk)
{
struct sctp_stream *stream;
struct sctp_chunk *lchunk;
__u32 cfsn = 0;
__u16 sid;

if (chunk->has_mid)
return;

sid = sctp_chunk_stream_no(chunk);
stream = &chunk->asoc->stream;

list_for_each_entry(lchunk, &chunk->msg->chunks, frag_list) {
struct sctp_idatahdr *hdr;

lchunk->has_mid = 1;

if (lchunk->chunk_hdr->flags & SCTP_DATA_UNORDERED)
continue;

hdr = lchunk->subh.idata_hdr;

if (lchunk->chunk_hdr->flags & SCTP_DATA_FIRST_FRAG)
hdr->ppid = lchunk->sinfo.sinfo_ppid;
else
hdr->fsn = htonl(cfsn++);

if (lchunk->chunk_hdr->flags & SCTP_DATA_LAST_FRAG)
hdr->mid = htonl(sctp_mid_next(stream, out, sid));
else
hdr->mid = htonl(sctp_mid_peek(stream, out, sid));
}
}

static struct sctp_stream_interleave sctp_stream_interleave_0 = {
.data_chunk_len = sizeof(struct sctp_data_chunk),
/* DATA process functions */
.make_datafrag = sctp_make_datafrag_empty,
.assign_number = sctp_chunk_assign_ssn,
};

static struct sctp_stream_interleave sctp_stream_interleave_1 = {
.data_chunk_len = sizeof(struct sctp_idata_chunk),
/* I-DATA process functions */
.make_datafrag = sctp_make_idatafrag_empty,
.assign_number = sctp_chunk_assign_mid,
};

void sctp_stream_interleave_init(struct sctp_stream *stream)
Expand Down
4 changes: 2 additions & 2 deletions net/sctp/ulpevent.c
Original file line number Diff line number Diff line change
Expand Up @@ -443,8 +443,8 @@ struct sctp_ulpevent *sctp_ulpevent_make_send_failed(
goto fail;

/* Pull off the common chunk header and DATA header. */
skb_pull(skb, sizeof(struct sctp_data_chunk));
len -= sizeof(struct sctp_data_chunk);
skb_pull(skb, sctp_datachk_len(&asoc->stream));
len -= sctp_datachk_len(&asoc->stream);

/* Embed the event fields inside the cloned skb. */
event = sctp_skb2event(skb);
Expand Down

0 comments on commit 668c9be

Please sign in to comment.