diff options
author | rrs <rrs@FreeBSD.org> | 2007-04-22 11:06:27 +0000 |
---|---|---|
committer | rrs <rrs@FreeBSD.org> | 2007-04-22 11:06:27 +0000 |
commit | 44fd758bd50a08f1cfd0618700424dd54a93571a (patch) | |
tree | cdfe74b46c1b17927d990e112c62556cf444c46e /sys | |
parent | c494d6613ee7a2abda270930371858e0da4262f7 (diff) | |
download | FreeBSD-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.h | 9 | ||||
-rw-r--r-- | sys/netinet/sctp_indata.c | 13 | ||||
-rw-r--r-- | sys/netinet/sctp_indata.h | 2 | ||||
-rw-r--r-- | sys/netinet/sctp_input.c | 8 | ||||
-rw-r--r-- | sys/netinet/sctp_output.c | 7 | ||||
-rw-r--r-- | sys/netinet/sctp_pcb.c | 5 | ||||
-rw-r--r-- | sys/netinet/sctp_pcb.h | 9 | ||||
-rw-r--r-- | sys/netinet/sctp_structs.h | 4 | ||||
-rw-r--r-- | sys/netinet/sctp_uio.h | 22 | ||||
-rw-r--r-- | sys/netinet/sctp_usrreq.c | 26 | ||||
-rw-r--r-- | sys/netinet/sctputil.c | 100 | ||||
-rw-r--r-- | sys/netinet/sctputil.h | 2 |
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 *, |