summaryrefslogtreecommitdiffstats
path: root/sys/netinet/sctputil.c
diff options
context:
space:
mode:
authortuexen <tuexen@FreeBSD.org>2009-08-15 21:10:52 +0000
committertuexen <tuexen@FreeBSD.org>2009-08-15 21:10:52 +0000
commitef372dbfb6d9a094ce850ec82b25a162727ed45b (patch)
treeef6e9b55aa7950e3d1aaad64652c4b08594450a2 /sys/netinet/sctputil.c
parent38b19229005fffeb77983ebf0cc00d252f9a8e77 (diff)
downloadFreeBSD-src-ef372dbfb6d9a094ce850ec82b25a162727ed45b.zip
FreeBSD-src-ef372dbfb6d9a094ce850ec82b25a162727ed45b.tar.gz
* Fix a bug where PR-SCTP settings are ignore when using implicit
association setup. * Fix a bug where message with illegal stream ids are not deleted. * Fix a crash when reporting back unsent messages from the send_queue. * Fix a bug related to INIT retransmission when the socket is already closed. * Fix a bug where associations were stalled when partial delivery API was enabled. * Fix a bug where the receive buffer size was smaller than the partial_delivery_point. Approved by: re, rrs (mentor) MFC after: One day.
Diffstat (limited to 'sys/netinet/sctputil.c')
-rw-r--r--sys/netinet/sctputil.c90
1 files changed, 72 insertions, 18 deletions
diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c
index 420f4a1..53d84b7 100644
--- a/sys/netinet/sctputil.c
+++ b/sys/netinet/sctputil.c
@@ -1484,6 +1484,7 @@ sctp_timeout_handler(void *t)
SCTP_INP_INCR_REF(inp);
if ((inp->sctp_socket == 0) &&
((tmr->type != SCTP_TIMER_TYPE_INPKILL) &&
+ (tmr->type != SCTP_TIMER_TYPE_INIT) &&
(tmr->type != SCTP_TIMER_TYPE_SEND) &&
(tmr->type != SCTP_TIMER_TYPE_RECV) &&
(tmr->type != SCTP_TIMER_TYPE_HEARTBEAT) &&
@@ -2984,8 +2985,6 @@ sctp_notify_send_failed(struct sctp_tcb *stcb, uint32_t error,
ssf->ssf_info.sinfo_assoc_id = sctp_get_associd(stcb);
ssf->ssf_assoc_id = sctp_get_associd(stcb);
- SCTP_BUF_NEXT(m_notify) = chk->data;
- SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_send_failed);
if (chk->data) {
/*
* trim off the sctp chunk header(it should be there)
@@ -2996,6 +2995,8 @@ sctp_notify_send_failed(struct sctp_tcb *stcb, uint32_t error,
chk->send_size -= sizeof(struct sctp_data_chunk);
}
}
+ SCTP_BUF_NEXT(m_notify) = chk->data;
+ SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_send_failed);
/* Steal off the mbuf */
chk->data = NULL;
/*
@@ -3146,9 +3147,13 @@ sctp_notify_adaptation_layer(struct sctp_tcb *stcb,
}
/* This always must be called with the read-queue LOCKED in the INP */
-void
+static void
sctp_notify_partial_delivery_indication(struct sctp_tcb *stcb, uint32_t error,
- int nolock, uint32_t val)
+ uint32_t val, int so_locked
+#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
+ SCTP_UNUSED
+#endif
+)
{
struct mbuf *m_notify;
struct sctp_pdapi_event *pdapi;
@@ -3189,9 +3194,6 @@ sctp_notify_partial_delivery_indication(struct sctp_tcb *stcb, uint32_t error,
control->tail_mbuf = m_notify;
control->held_length = 0;
control->length = 0;
- if (nolock == 0) {
- SCTP_INP_READ_LOCK(stcb->sctp_ep);
- }
sb = &stcb->sctp_socket->so_rcv;
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) {
sctp_sblog(sb, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBALLOC, SCTP_BUF_LEN(m_notify));
@@ -3208,12 +3210,30 @@ sctp_notify_partial_delivery_indication(struct sctp_tcb *stcb, uint32_t error,
/* we really should not see this case */
TAILQ_INSERT_TAIL(&stcb->sctp_ep->read_queue, control, next);
}
- if (nolock == 0) {
- SCTP_INP_READ_UNLOCK(stcb->sctp_ep);
- }
if (stcb->sctp_ep && stcb->sctp_socket) {
/* This should always be the case */
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ struct socket *so;
+
+ so = SCTP_INP_SO(stcb->sctp_ep);
+ if (!so_locked) {
+ atomic_add_int(&stcb->asoc.refcnt, 1);
+ SCTP_TCB_UNLOCK(stcb);
+ SCTP_SOCKET_LOCK(so, 1);
+ SCTP_TCB_LOCK(stcb);
+ atomic_subtract_int(&stcb->asoc.refcnt, 1);
+ if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
+ SCTP_SOCKET_UNLOCK(so, 1);
+ return;
+ }
+ }
+#endif
sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ if (!so_locked) {
+ SCTP_SOCKET_UNLOCK(so, 1);
+ }
+#endif
}
}
@@ -3540,9 +3560,9 @@ sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb,
val = *((uint32_t *) data);
- sctp_notify_partial_delivery_indication(stcb, error, 0, val);
+ sctp_notify_partial_delivery_indication(stcb, error, val, so_locked);
+ break;
}
- break;
case SCTP_NOTIFY_STRDATA_ERR:
break;
case SCTP_NOTIFY_ASSOC_ABORTED:
@@ -3585,11 +3605,9 @@ sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb,
case SCTP_NOTIFY_STR_RESET_FAILED_OUT:
sctp_notify_stream_reset(stcb, error, ((uint16_t *) data), (SCTP_STRRESET_OUTBOUND_STR | SCTP_STRRESET_FAILED));
break;
-
case SCTP_NOTIFY_STR_RESET_FAILED_IN:
sctp_notify_stream_reset(stcb, error, ((uint16_t *) data), (SCTP_STRRESET_INBOUND_STR | SCTP_STRRESET_FAILED));
break;
-
case SCTP_NOTIFY_ASCONF_ADD_IP:
sctp_notify_peer_addr_change(stcb, SCTP_ADDR_ADDED, data,
error);
@@ -3671,8 +3689,10 @@ sctp_report_all_outbound(struct sctp_tcb *stcb, int holds_lock, int so_locked
sctp_free_bufspace(stcb, asoc, chk, 1);
sctp_ulp_notify(SCTP_NOTIFY_DG_FAIL, stcb,
SCTP_NOTIFY_DATAGRAM_SENT, chk, so_locked);
- sctp_m_freem(chk->data);
- chk->data = NULL;
+ if (chk->data) {
+ sctp_m_freem(chk->data);
+ chk->data = NULL;
+ }
}
sctp_free_a_chunk(stcb, chk);
/* sa_ignore FREED_MEMORY */
@@ -3689,8 +3709,10 @@ sctp_report_all_outbound(struct sctp_tcb *stcb, int holds_lock, int so_locked
sctp_free_bufspace(stcb, asoc, chk, 1);
sctp_ulp_notify(SCTP_NOTIFY_DG_FAIL, stcb,
SCTP_NOTIFY_DATAGRAM_UNSENT, chk, so_locked);
- sctp_m_freem(chk->data);
- chk->data = NULL;
+ if (chk->data) {
+ sctp_m_freem(chk->data);
+ chk->data = NULL;
+ }
}
sctp_free_a_chunk(stcb, chk);
/* sa_ignore FREED_MEMORY */
@@ -5346,6 +5368,38 @@ restart_nosblocks:
}
goto restart;
}
+ if ((control->length == 0) &&
+ (control->end_added == 1)) {
+ /*
+ * Do we also need to check for (control->pdapi_aborted ==
+ * 1)?
+ */
+ if (hold_rlock == 0) {
+ hold_rlock = 1;
+ SCTP_INP_READ_LOCK(inp);
+ }
+ TAILQ_REMOVE(&inp->read_queue, control, next);
+ if (control->data) {
+#ifdef INVARIANTS
+ panic("control->data not null but control->length == 0");
+#else
+ SCTP_PRINTF("Strange, data left in the control buffer. Cleaning up.\n");
+ sctp_m_freem(control->data);
+ control->data = NULL;
+#endif
+ }
+ if (control->aux_data) {
+ sctp_m_free(control->aux_data);
+ control->aux_data = NULL;
+ }
+ sctp_free_remote_addr(control->whoFrom);
+ sctp_free_a_readq(stcb, control);
+ if (hold_rlock) {
+ hold_rlock = 0;
+ SCTP_INP_READ_UNLOCK(inp);
+ }
+ goto restart;
+ }
if (control->length == 0) {
if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE)) &&
(filling_sinfo)) {
OpenPOWER on IntegriCloud