summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorrrs <rrs@FreeBSD.org>2007-04-22 11:06:27 +0000
committerrrs <rrs@FreeBSD.org>2007-04-22 11:06:27 +0000
commit44fd758bd50a08f1cfd0618700424dd54a93571a (patch)
treecdfe74b46c1b17927d990e112c62556cf444c46e /sys
parentc494d6613ee7a2abda270930371858e0da4262f7 (diff)
downloadFreeBSD-src-44fd758bd50a08f1cfd0618700424dd54a93571a.zip
FreeBSD-src-44fd758bd50a08f1cfd0618700424dd54a93571a.tar.gz
- 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.
Diffstat (limited to 'sys')
-rw-r--r--sys/netinet/sctp.h9
-rw-r--r--sys/netinet/sctp_indata.c13
-rw-r--r--sys/netinet/sctp_indata.h2
-rw-r--r--sys/netinet/sctp_input.c8
-rw-r--r--sys/netinet/sctp_output.c7
-rw-r--r--sys/netinet/sctp_pcb.c5
-rw-r--r--sys/netinet/sctp_pcb.h9
-rw-r--r--sys/netinet/sctp_structs.h4
-rw-r--r--sys/netinet/sctp_uio.h22
-rw-r--r--sys/netinet/sctp_usrreq.c26
-rw-r--r--sys/netinet/sctputil.c100
-rw-r--r--sys/netinet/sctputil.h2
12 files changed, 150 insertions, 57 deletions
diff --git a/sys/netinet/sctp.h b/sys/netinet/sctp.h
index ab29820..d89560d 100644
--- a/sys/netinet/sctp.h
+++ b/sys/netinet/sctp.h
@@ -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
*/
diff --git a/sys/netinet/sctp_indata.c b/sys/netinet/sctp_indata.c
index 81d6780..2010d2a 100644
--- a/sys/netinet/sctp_indata.c
+++ b/sys/netinet/sctp_indata.c
@@ -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;
}
/*************************************************************/
diff --git a/sys/netinet/sctp_indata.h b/sys/netinet/sctp_indata.h
index 394e4c9..f1a9d41 100644
--- a/sys/netinet/sctp_indata.h
+++ b/sys/netinet/sctp_indata.h
@@ -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)
diff --git a/sys/netinet/sctp_input.c b/sys/netinet/sctp_input.c
index 6dee5f4..90de716 100644
--- a/sys/netinet/sctp_input.c
+++ b/sys/netinet/sctp_input.c
@@ -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
diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c
index 304d299..71ef568 100644
--- a/sys/netinet/sctp_output.c
+++ b/sys/netinet/sctp_output.c
@@ -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) <
diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c
index 24c04b3..376d511 100644
--- a/sys/netinet/sctp_pcb.c
+++ b/sys/netinet/sctp_pcb.c
@@ -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;
}
}
diff --git a/sys/netinet/sctp_pcb.h b/sys/netinet/sctp_pcb.h
index 022a359..1c6b523 100644
--- a/sys/netinet/sctp_pcb.h
+++ b/sys/netinet/sctp_pcb.h
@@ -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)
diff --git a/sys/netinet/sctp_structs.h b/sys/netinet/sctp_structs.h
index 4e88c1f..fc6588b 100644
--- a/sys/netinet/sctp_structs.h
+++ b/sys/netinet/sctp_structs.h
@@ -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 */
diff --git a/sys/netinet/sctp_uio.h b/sys/netinet/sctp_uio.h
index 263f417..1e54e9c 100644
--- a/sys/netinet/sctp_uio.h
+++ b/sys/netinet/sctp_uio.h
@@ -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;
};
diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c
index 7f9bdf3..b9797a2 100644
--- a/sys/netinet/sctp_usrreq.c
+++ b/sys/netinet/sctp_usrreq.c
@@ -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;
diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c
index c94b2d4..9d03b7c 100644
--- a/sys/netinet/sctputil.c
+++ b/sys/netinet/sctputil.c
@@ -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 @@ restart_nosblocks:
/* 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 @@ found_one:
* 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 @@ found_one:
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 @@ found_one:
* 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 @@ get_more_data:
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 @@ wait_some_more:
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 @@ get_more_data2:
}
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 @@ get_more_data2:
* 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 @@ release_unlocked:
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;
diff --git a/sys/netinet/sctputil.h b/sys/netinet/sctputil.h
index 8496f42..e0ae668 100644
--- a/sys/netinet/sctputil.h
+++ b/sys/netinet/sctputil.h
@@ -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 *,
OpenPOWER on IntegriCloud