- Somehow the disable fragment option got lost. We could

set/clear it but would not do it. Now we will.
-  Moved to latest socket api for extended sndrcv info struct.
-  Moved to support all new levels of fragment interleave.
This commit is contained in:
Randall Stewart 2007-04-22 11:06:27 +00:00
parent 7621783a55
commit 9a6142d8cd
12 changed files with 150 additions and 57 deletions

View File

@ -223,6 +223,15 @@ struct sctp_paramhdr {
/* Debug things that need to be purged */
#define SCTP_SET_INITIAL_DBG_SEQ 0x00009f00
/* fragment interleave constants
* setting must be one of these or
* EINVAL returned.
*/
#define SCTP_FRAG_LEVEL_0 0x00000000
#define SCTP_FRAG_LEVEL_1 0x00000001
#define SCTP_FRAG_LEVEL_2 0x00000002
/*
* user state values
*/

View File

@ -211,6 +211,7 @@ sctp_build_readq_entry(struct sctp_tcb *stcb,
read_queue_e->port_from = stcb->rport;
read_queue_e->do_not_ref_stcb = 0;
read_queue_e->end_added = 0;
read_queue_e->some_taken = 0;
read_queue_e->pdapi_aborted = 0;
failed_build:
return (read_queue_e);
@ -249,6 +250,7 @@ sctp_build_readq_entry_chk(struct sctp_tcb *stcb,
read_queue_e->spec_flags = 0;
read_queue_e->do_not_ref_stcb = 0;
read_queue_e->end_added = 0;
read_queue_e->some_taken = 0;
read_queue_e->pdapi_aborted = 0;
failed_build:
return (read_queue_e);
@ -5810,6 +5812,8 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb,
*/
if ((asoc->fragmented_delivery_inprogress) &&
(chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG)) {
uint32_t str_seq;
/*
* Special case PD-API is up and
* what we fwd-tsn' over includes
@ -5817,8 +5821,10 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb,
* longer need to do the PD-API.
*/
asoc->fragmented_delivery_inprogress = 0;
str_seq = (asoc->str_of_pdapi << 16) | asoc->ssn_of_pdapi;
sctp_ulp_notify(SCTP_NOTIFY_PARTIAL_DELVIERY_INDICATION,
stcb, SCTP_PARTIAL_DELIVERY_ABORTED, (void *)NULL);
stcb, SCTP_PARTIAL_DELIVERY_ABORTED, (void *)&str_seq);
}
break;
@ -5831,8 +5837,11 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb,
* Ok we removed cnt_gone chunks in the PD-API queue that
* were being delivered. So now we must turn off the flag.
*/
uint32_t str_seq;
str_seq = (asoc->str_of_pdapi << 16) | asoc->ssn_of_pdapi;
sctp_ulp_notify(SCTP_NOTIFY_PARTIAL_DELVIERY_INDICATION,
stcb, SCTP_PARTIAL_DELIVERY_ABORTED, (void *)NULL);
stcb, SCTP_PARTIAL_DELIVERY_ABORTED, (void *)&str_seq);
asoc->fragmented_delivery_inprogress = 0;
}
/*************************************************************/

View File

@ -70,7 +70,7 @@ sctp_build_readq_entry(struct sctp_tcb *stcb,
(_ctl)->do_not_ref_stcb = 0; \
(_ctl)->end_added = 0; \
(_ctl)->pdapi_aborted = 0; \
(_ctl)->resv = 0; \
(_ctl)->some_taken = 0; \
} \
} while (0)

View File

@ -287,14 +287,8 @@ sctp_process_init(struct sctp_init_chunk *cp, struct sctp_tcb *stcb,
* supported) when the INIT-ACK arrives.
*/
TAILQ_INIT(&asoc->strmin[i].inqueue);
/*
* we are not on any wheel, pr-sctp streams will go on the
* wheel when they have data waiting for reorder.
*/
asoc->strmin[i].next_spoke.tqe_next = 0;
asoc->strmin[i].next_spoke.tqe_prev = 0;
asoc->strmin[i].delivery_started = 0;
}
/*
* load_address_from_init will put the addresses into the
* association when the COOKIE is processed or the INIT-ACK is

View File

@ -10879,6 +10879,13 @@ sctp_lower_sosend(struct socket *so,
non_blocking = 1;
}
asoc = &stcb->asoc;
if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NO_FRAGMENT)) {
if (sndlen > asoc->smallest_mtu) {
error = EMSGSIZE;
goto out_unlocked;
}
}
/* would we block? */
if (non_blocking) {
if ((SCTP_SB_LIMIT_SND(so) <

View File

@ -3606,9 +3606,12 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
* added right after this
* msg.
*/
uint32_t strseq;
stcb->asoc.control_pdapi = sq;
strseq = (sq->sinfo_stream << 16) | sq->sinfo_ssn;
sctp_notify_partial_delivery_indication(stcb,
SCTP_PARTIAL_DELIVERY_ABORTED, 1);
SCTP_PARTIAL_DELIVERY_ABORTED, 1, strseq);
stcb->asoc.control_pdapi = NULL;
}
}

View File

@ -84,9 +84,10 @@ TAILQ_HEAD(sctp_streamhead, sctp_stream_queue_pending);
/*
* PCB Features (in sctp_features bitmask)
*/
#define SCTP_PCB_FLAGS_EXT_RCVINFO 0x00000004
#define SCTP_PCB_FLAGS_DONOT_HEARTBEAT 0x00000008
#define SCTP_PCB_FLAGS_FRAG_INTERLEAVE 0x00000010
#define SCTP_PCB_FLAGS_EXT_RCVINFO 0x00000002
#define SCTP_PCB_FLAGS_DONOT_HEARTBEAT 0x00000004
#define SCTP_PCB_FLAGS_FRAG_INTERLEAVE 0x00000008
#define SCTP_PCB_FLAGS_INTERLEAVE_STRMS 0x00000010
#define SCTP_PCB_FLAGS_DO_ASCONF 0x00000020
#define SCTP_PCB_FLAGS_AUTO_ASCONF 0x00000040
/* socket options */
@ -103,7 +104,7 @@ TAILQ_HEAD(sctp_streamhead, sctp_stream_queue_pending);
#define SCTP_PCB_FLAGS_AUTHEVNT 0x00040000
#define SCTP_PCB_FLAGS_STREAM_RESETEVNT 0x00080000
#define SCTP_PCB_FLAGS_NO_FRAGMENT 0x00100000
#define SCTP_PCB_FLAGS_EXPLICIT_EOR 0x00200000
#define SCTP_PCB_FLAGS_EXPLICIT_EOR 0x00400000
#define SCTP_PCBHASH_ALLADDR(port, mask) (port & mask)

View File

@ -375,7 +375,7 @@ struct sctp_queued_to_read { /* sinfo structure Pluse more */
uint8_t do_not_ref_stcb;
uint8_t end_added;
uint8_t pdapi_aborted;
uint8_t resv;
uint8_t some_taken;
};
/* This data structure will be on the outbound
@ -425,9 +425,9 @@ struct sctp_stream_queue_pending {
TAILQ_HEAD(sctpwheelunrel_listhead, sctp_stream_in);
struct sctp_stream_in {
struct sctp_readhead inqueue;
TAILQ_ENTRY(sctp_stream_in) next_spoke;
uint16_t stream_no;
uint16_t last_sequence_delivered; /* used for re-order */
uint8_t delivery_started;
};
/* This struct is used to track the traffic on outbound streams */

View File

@ -105,20 +105,12 @@ struct sctp_sndrcvinfo {
};
struct sctp_extrcvinfo {
uint16_t sinfo_stream;
uint16_t sinfo_ssn;
uint16_t sinfo_flags;
uint32_t sinfo_ppid;
uint32_t sinfo_context;
uint32_t sinfo_timetolive;
uint32_t sinfo_tsn;
uint32_t sinfo_cumtsn;
sctp_assoc_t sinfo_assoc_id;
uint16_t next_flags;
uint16_t next_stream;
uint32_t next_asocid;
uint32_t next_length;
uint32_t next_ppid;
struct sctp_sndrcvinfo sreinfo_sinfo;
uint16_t sreinfo_next_flags;
uint16_t sreinfo_next_stream;
uint32_t sreinfo_next_aid;
uint32_t sreinfo_next_length;
uint32_t sreinfo_next_ppid;
uint8_t __reserve_pad[SCTP_ALIGN_RESV_PAD_SHORT];
};
@ -318,6 +310,8 @@ struct sctp_pdapi_event {
uint16_t pdapi_flags;
uint32_t pdapi_length;
uint32_t pdapi_indication;
uint16_t pdapi_stream;
uint16_t pdapi_seq;
sctp_assoc_t pdapi_assoc_id;
};

View File

@ -1516,7 +1516,15 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
uint32_t *value;
SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
*value = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE);
if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE)) {
if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS)) {
*value = SCTP_FRAG_LEVEL_2;
} else {
*value = SCTP_FRAG_LEVEL_1;
}
} else {
*value = SCTP_FRAG_LEVEL_0;
}
*optsize = sizeof(uint32_t);
}
break;
@ -2457,13 +2465,21 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
case SCTP_FRAGMENT_INTERLEAVE:
/* not yet until we re-write sctp_recvmsg() */
{
uint32_t *on_off;
uint32_t *level;
SCTP_CHECK_AND_CAST(on_off, optval, uint32_t, optsize);
if (*on_off) {
SCTP_CHECK_AND_CAST(level, optval, uint32_t, optsize);
if (*level == SCTP_FRAG_LEVEL_2) {
sctp_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE);
sctp_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS);
} else if (*level == SCTP_FRAG_LEVEL_1) {
sctp_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE);
sctp_feature_off(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS);
} else if (*level == SCTP_FRAG_LEVEL_0) {
sctp_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE);
sctp_feature_off(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS);
} else {
sctp_feature_off(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE);
error = EINVAL;
}
}
break;

View File

@ -3002,7 +3002,7 @@ sctp_notify_adaptation_layer(struct sctp_tcb *stcb,
/* This always must be called with the read-queue LOCKED in the INP */
void
sctp_notify_partial_delivery_indication(struct sctp_tcb *stcb,
uint32_t error, int nolock)
uint32_t error, int nolock, uint32_t val)
{
struct mbuf *m_notify;
struct sctp_pdapi_event *pdapi;
@ -3023,6 +3023,8 @@ sctp_notify_partial_delivery_indication(struct sctp_tcb *stcb,
pdapi->pdapi_flags = 0;
pdapi->pdapi_length = sizeof(struct sctp_pdapi_event);
pdapi->pdapi_indication = error;
pdapi->pdapi_stream = (val >> 16);
pdapi->pdapi_seq = (val & 0x0000ffff);
pdapi->pdapi_assoc_id = sctp_get_associd(stcb);
SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_pdapi_event);
@ -3265,7 +3267,13 @@ sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb,
sctp_notify_adaptation_layer(stcb, error);
break;
case SCTP_NOTIFY_PARTIAL_DELVIERY_INDICATION:
sctp_notify_partial_delivery_indication(stcb, error, 0);
{
uint32_t val;
val = *((uint32_t *) data);
sctp_notify_partial_delivery_indication(stcb, error, 0, val);
}
break;
case SCTP_NOTIFY_STRDATA_ERR:
break;
@ -4803,8 +4811,31 @@ sctp_sorecvmsg(struct socket *so,
/* find a more suitable one then this */
ctl = TAILQ_NEXT(control, next);
while (ctl) {
if ((ctl->stcb != control->stcb) && (ctl->length)) {
/* found one */
if ((ctl->stcb != control->stcb) && (ctl->length) &&
(ctl->some_taken ||
((ctl->do_not_ref_stcb == 0) &&
(ctl->stcb->asoc.strmin[ctl->sinfo_stream].delivery_started == 0)))
) {
/*-
* If we have a different TCB next, and there is data
* present. If we have already taken some (pdapi), OR we can
* ref the tcb and no delivery as started on this stream, we
* take it.
*/
control = ctl;
goto found_one;
} else if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS)) &&
(ctl->length) &&
((ctl->some_taken) ||
((ctl->do_not_ref_stcb == 0) &&
(ctl->stcb->asoc.strmin[ctl->sinfo_stream].delivery_started == 0)))
) {
/*-
* If we have the same tcb, and there is data present, and we
* have the strm interleave feature present. Then if we have
* taken some (pdapi) or we can refer to tht tcb AND we have
* not started a delivery for this stream, we can take it.
*/
control = ctl;
goto found_one;
}
@ -4831,6 +4862,10 @@ sctp_sorecvmsg(struct socket *so,
* If we reach here, control has a some data for us to read off.
* Note that stcb COULD be NULL.
*/
if (control->do_not_ref_stcb == 0) {
control->stcb->asoc.strmin[ctl->sinfo_stream].delivery_started = 1;
}
control->some_taken = 1;
if (hold_sblock) {
SOCKBUF_UNLOCK(&so->so_rcv);
hold_sblock = 0;
@ -4874,21 +4909,22 @@ sctp_sorecvmsg(struct socket *so,
struct sctp_extrcvinfo *s_extra;
s_extra = (struct sctp_extrcvinfo *)sinfo;
if (nxt) {
s_extra->next_flags = SCTP_NEXT_MSG_AVAIL;
if ((nxt) &&
(nxt->length)) {
s_extra->sreinfo_next_flags = SCTP_NEXT_MSG_AVAIL;
if (nxt->sinfo_flags & SCTP_UNORDERED) {
s_extra->next_flags |= SCTP_NEXT_MSG_IS_UNORDERED;
s_extra->sreinfo_next_flags |= SCTP_NEXT_MSG_IS_UNORDERED;
}
if (nxt->spec_flags & M_NOTIFICATION) {
s_extra->next_flags |= SCTP_NEXT_MSG_IS_NOTIFICATION;
s_extra->sreinfo_next_flags |= SCTP_NEXT_MSG_IS_NOTIFICATION;
}
s_extra->next_asocid = nxt->sinfo_assoc_id;
s_extra->next_length = nxt->length;
s_extra->next_ppid = nxt->sinfo_ppid;
s_extra->next_stream = nxt->sinfo_stream;
s_extra->sreinfo_next_aid = nxt->sinfo_assoc_id;
s_extra->sreinfo_next_length = nxt->length;
s_extra->sreinfo_next_ppid = nxt->sinfo_ppid;
s_extra->sreinfo_next_stream = nxt->sinfo_stream;
if (nxt->tail_mbuf != NULL) {
if (nxt->end_added) {
s_extra->next_flags |= SCTP_NEXT_MSG_ISCOMPLETE;
s_extra->sreinfo_next_flags |= SCTP_NEXT_MSG_ISCOMPLETE;
}
}
} else {
@ -4898,11 +4934,12 @@ sctp_sorecvmsg(struct socket *so,
* sinfo_ that is on the control's structure
* :-D
*/
s_extra->next_flags = SCTP_NO_NEXT_MSG;
s_extra->next_asocid = 0;
s_extra->next_length = 0;
s_extra->next_ppid = 0;
s_extra->next_stream = 0;
nxt = NULL;
s_extra->sreinfo_next_flags = SCTP_NO_NEXT_MSG;
s_extra->sreinfo_next_aid = 0;
s_extra->sreinfo_next_length = 0;
s_extra->sreinfo_next_ppid = 0;
s_extra->sreinfo_next_stream = 0;
}
}
/*
@ -5023,6 +5060,8 @@ sctp_sorecvmsg(struct socket *so,
if ((SCTP_BUF_NEXT(m) == NULL) &&
(control->end_added)) {
out_flags |= MSG_EOR;
if (control->do_not_ref_stcb == 0)
control->stcb->asoc.strmin[ctl->sinfo_stream].delivery_started = 0;
}
if (control->spec_flags & M_NOTIFICATION) {
out_flags |= MSG_NOTIFICATION;
@ -5293,8 +5332,15 @@ sctp_sorecvmsg(struct socket *so,
if (control->end_added == 1) {
/* he aborted, or is done i.e.did a shutdown */
out_flags |= MSG_EOR;
if (control->pdapi_aborted)
if (control->pdapi_aborted) {
if (control->do_not_ref_stcb == 0)
control->stcb->asoc.strmin[ctl->sinfo_stream].delivery_started = 0;
out_flags |= MSG_TRUNC;
} else {
if (control->do_not_ref_stcb == 0)
control->stcb->asoc.strmin[ctl->sinfo_stream].delivery_started = 0;
}
goto done_with_control;
}
if (so->so_rcv.sb_cc > held_length) {
@ -5343,6 +5389,8 @@ sctp_sorecvmsg(struct socket *so,
}
if (control->end_added) {
out_flags |= MSG_EOR;
if (control->do_not_ref_stcb == 0)
control->stcb->asoc.strmin[ctl->sinfo_stream].delivery_started = 0;
}
if (control->spec_flags & M_NOTIFICATION) {
out_flags |= MSG_NOTIFICATION;
@ -5405,8 +5453,11 @@ sctp_sorecvmsg(struct socket *so,
* shutdown
*/
out_flags |= MSG_EOR;
if (control->pdapi_aborted)
if (control->pdapi_aborted) {
out_flags |= MSG_TRUNC;
if (control->do_not_ref_stcb == 0)
control->stcb->asoc.strmin[ctl->sinfo_stream].delivery_started = 0;
}
goto done_with_control;
}
if (so->so_rcv.sb_cc > held_length) {
@ -5535,6 +5586,15 @@ sctp_sorecvmsg(struct socket *so,
if (msg_flags)
*msg_flags |= out_flags;
out:
if (((out_flags & MSG_EOR) == 0) &&
((in_flags & MSG_PEEK) == 0) &&
(sinfo) &&
(sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO))) {
struct sctp_extrcvinfo *s_extra;
s_extra = (struct sctp_extrcvinfo *)sinfo;
s_extra->sreinfo_next_flags = SCTP_NO_NEXT_MSG;
}
if (hold_rlock == 1) {
SCTP_INP_READ_UNLOCK(inp);
hold_rlock = 0;

View File

@ -242,7 +242,7 @@ void sctp_print_address_pkt(struct ip *, struct sctphdr *);
void
sctp_notify_partial_delivery_indication(struct sctp_tcb *stcb,
uint32_t error, int no_lock);
uint32_t error, int no_lock, uint32_t strseq);
int
sctp_release_pr_sctp_chunk(struct sctp_tcb *, struct sctp_tmit_chunk *,