summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/netinet/sctp.h1
-rw-r--r--sys/netinet/sctp_auth.c10
-rw-r--r--sys/netinet/sctp_bsd_addr.c88
-rw-r--r--sys/netinet/sctp_constants.h5
-rw-r--r--sys/netinet/sctp_header.h11
-rw-r--r--sys/netinet/sctp_indata.c76
-rw-r--r--sys/netinet/sctp_indata.h5
-rw-r--r--sys/netinet/sctp_input.c121
-rw-r--r--sys/netinet/sctp_os_bsd.h7
-rw-r--r--sys/netinet/sctp_output.c338
-rw-r--r--sys/netinet/sctp_output.h5
-rw-r--r--sys/netinet/sctp_pcb.c163
-rw-r--r--sys/netinet/sctp_pcb.h4
-rw-r--r--sys/netinet/sctp_peeloff.c4
-rw-r--r--sys/netinet/sctp_usrreq.c8
-rw-r--r--sys/netinet/sctputil.c57
-rw-r--r--sys/netinet/sctputil.h13
-rw-r--r--sys/netinet6/sctp6_usrreq.c2
18 files changed, 564 insertions, 354 deletions
diff --git a/sys/netinet/sctp.h b/sys/netinet/sctp.h
index e0d7b0b..c89d1c8 100644
--- a/sys/netinet/sctp.h
+++ b/sys/netinet/sctp.h
@@ -400,6 +400,7 @@ struct sctp_error_unrecognized_chunk {
#define SCTP_PCB_FLAGS_BOUNDALL 0x00000004
#define SCTP_PCB_FLAGS_ACCEPTING 0x00000008
#define SCTP_PCB_FLAGS_UNBOUND 0x00000010
+#define SCTP_PCB_FLAGS_LISTENING 0x00000020
#define SCTP_PCB_FLAGS_CLOSE_IP 0x00040000
#define SCTP_PCB_FLAGS_WAS_CONNECTED 0x00080000
#define SCTP_PCB_FLAGS_WAS_ABORTED 0x00100000
diff --git a/sys/netinet/sctp_auth.c b/sys/netinet/sctp_auth.c
index 999e877..2086342 100644
--- a/sys/netinet/sctp_auth.c
+++ b/sys/netinet/sctp_auth.c
@@ -1440,7 +1440,7 @@ sctp_auth_get_cookie_params(struct sctp_tcb *stcb, struct mbuf *m,
if (plen > sizeof(random_store))
break;
phdr = sctp_get_next_param(m, offset,
- (struct sctp_paramhdr *)random_store, plen);
+ (struct sctp_paramhdr *)random_store, min(plen, sizeof(random_store)));
if (phdr == NULL)
return;
/* save the random and length for the key */
@@ -1453,7 +1453,7 @@ sctp_auth_get_cookie_params(struct sctp_tcb *stcb, struct mbuf *m,
if (plen > sizeof(hmacs_store))
break;
phdr = sctp_get_next_param(m, offset,
- (struct sctp_paramhdr *)hmacs_store, plen);
+ (struct sctp_paramhdr *)hmacs_store, min(plen, sizeof(hmacs_store)));
if (phdr == NULL)
return;
/* save the hmacs list and num for the key */
@@ -1475,7 +1475,7 @@ sctp_auth_get_cookie_params(struct sctp_tcb *stcb, struct mbuf *m,
if (plen > sizeof(chunks_store))
break;
phdr = sctp_get_next_param(m, offset,
- (struct sctp_paramhdr *)chunks_store, plen);
+ (struct sctp_paramhdr *)chunks_store, min(plen, sizeof(chunks_store)));
if (phdr == NULL)
return;
chunks = (struct sctp_auth_chunk_list *)phdr;
@@ -1850,7 +1850,7 @@ sctp_validate_init_auth_params(struct mbuf *m, int offset, int limit)
int num_ent, i;
phdr = sctp_get_next_param(m, offset,
- (struct sctp_paramhdr *)&local_store, plen);
+ (struct sctp_paramhdr *)&local_store, min(plen, sizeof(local_store)));
if (phdr == NULL) {
return (-1);
}
@@ -1889,7 +1889,7 @@ sctp_validate_init_auth_params(struct mbuf *m, int offset, int limit)
if (plen > sizeof(store))
break;
phdr = sctp_get_next_param(m, offset,
- (struct sctp_paramhdr *)store, plen);
+ (struct sctp_paramhdr *)store, min(plen, sizeof(store)));
if (phdr == NULL)
return (-1);
hmacs = (struct sctp_auth_hmac_algo *)phdr;
diff --git a/sys/netinet/sctp_bsd_addr.c b/sys/netinet/sctp_bsd_addr.c
index 4f83668..2ad0899 100644
--- a/sys/netinet/sctp_bsd_addr.c
+++ b/sys/netinet/sctp_bsd_addr.c
@@ -44,14 +44,10 @@ __FBSDID("$FreeBSD$");
#include <netinet/sctputil.h>
#include <netinet/sctp_timer.h>
#include <netinet/sctp_asconf.h>
+#include <netinet/sctp_sysctl.h>
#include <netinet/sctp_indata.h>
#include <sys/unistd.h>
-#ifdef SCTP_DEBUG
-extern uint32_t sctp_debug_on;
-
-#endif
-
#if defined(SCTP_USE_THREAD_BASED_ITERATOR)
void
@@ -211,7 +207,7 @@ sctp_init_ifns_for_vrf(int vrfid)
ifn->if_xname,
(void *)ifa,
ifa->ifa_addr,
- ifa_flags
+ ifa_flags, 0
);
if (sctp_ifa) {
sctp_ifa->localifa_flags &= ~SCTP_ADDR_DEFER_USE;
@@ -245,7 +241,6 @@ static uint8_t first_time = 0;
void
sctp_addr_change(struct ifaddr *ifa, int cmd)
{
- struct sctp_laddr *wi;
struct sctp_ifa *ifap = NULL;
uint32_t ifa_flags = 0;
struct in6_ifaddr *ifa6;
@@ -293,58 +288,53 @@ sctp_addr_change(struct ifaddr *ifa, int cmd)
ifap = sctp_add_addr_to_vrf(SCTP_DEFAULT_VRFID, (void *)ifa->ifa_ifp,
ifa->ifa_ifp->if_index, ifa->ifa_ifp->if_type,
ifa->ifa_ifp->if_xname,
- (void *)ifa, ifa->ifa_addr, ifa_flags);
- /*
- * Bump up the refcount so that when the timer completes it
- * will drop back down.
- */
- if (ifap)
- atomic_add_int(&ifap->refcount, 1);
+ (void *)ifa, ifa->ifa_addr, ifa_flags, 1);
} else if (cmd == RTM_DELETE) {
- ifap = sctp_del_addr_from_vrf(SCTP_DEFAULT_VRFID, ifa->ifa_addr, ifa->ifa_ifp->if_index);
+ sctp_del_addr_from_vrf(SCTP_DEFAULT_VRFID, ifa->ifa_addr, ifa->ifa_ifp->if_index);
/*
* We don't bump refcount here so when it completes the
* final delete will happen.
*/
}
- if (ifap == NULL)
- return;
+}
- wi = SCTP_ZONE_GET(sctppcbinfo.ipi_zone_laddr, struct sctp_laddr);
- if (wi == NULL) {
- /*
- * Gak, what can we do? We have lost an address change can
- * you say HOSED?
- */
-#ifdef SCTP_DEBUG
- if (sctp_debug_on & SCTP_DEBUG_PCB1) {
- printf("Lost and address change ???\n");
- }
-#endif /* SCTP_DEBUG */
+struct mbuf *
+sctp_get_mbuf_for_msg(unsigned int space_needed, int want_header,
+ int how, int allonebuf, int type)
+{
+ struct mbuf *m = NULL;
- /* Opps, must decrement the count */
- sctp_free_ifa(ifap);
- return;
+ m = m_getm2(NULL, space_needed, how, type, want_header ? M_PKTHDR : 0);
+ if (m == NULL) {
+ /* bad, no memory */
+ return (m);
}
- SCTP_INCR_LADDR_COUNT();
- bzero(wi, sizeof(*wi));
- wi->ifa = ifap;
- if (cmd == RTM_ADD) {
- wi->action = SCTP_ADD_IP_ADDRESS;
- } else if (cmd == RTM_DELETE) {
- wi->action = SCTP_DEL_IP_ADDRESS;
+ if (allonebuf) {
+ int siz;
+
+ if (SCTP_BUF_IS_EXTENDED(m)) {
+ siz = SCTP_BUF_EXTEND_SIZE(m);
+ } else {
+ if (want_header)
+ siz = MHLEN;
+ else
+ siz = MLEN;
+ }
+ if (siz < space_needed) {
+ m_freem(m);
+ return (NULL);
+ }
}
- SCTP_IPI_ITERATOR_WQ_LOCK();
- /*
- * Should this really be a tailq? As it is we will process the
- * newest first :-0
- */
- LIST_INSERT_HEAD(&sctppcbinfo.addr_wq, wi, sctp_nxt_addr);
- sctp_timer_start(SCTP_TIMER_TYPE_ADDR_WQ,
- (struct sctp_inpcb *)NULL,
- (struct sctp_tcb *)NULL,
- (struct sctp_nets *)NULL);
- SCTP_IPI_ITERATOR_WQ_UNLOCK();
+ if (SCTP_BUF_NEXT(m)) {
+ sctp_m_freem(SCTP_BUF_NEXT(m));
+ SCTP_BUF_NEXT(m) = NULL;
+ }
+#ifdef SCTP_MBUF_LOGGING
+ if (SCTP_BUF_IS_EXTENDED(m)) {
+ sctp_log_mb(m, SCTP_MBUF_IALLOC);
+ }
+#endif
+ return (m);
}
diff --git a/sys/netinet/sctp_constants.h b/sys/netinet/sctp_constants.h
index cf301a2..3922222 100644
--- a/sys/netinet/sctp_constants.h
+++ b/sys/netinet/sctp_constants.h
@@ -196,7 +196,10 @@ __FBSDID("$FreeBSD$");
#define SCTP_FLIGHT_LOG_UP_REVOKE 113
#define SCTP_FLIGHT_LOG_DOWN_PDRP 114
#define SCTP_FLIGHT_LOG_DOWN_PMTU 115
-#define SCTP_LOG_MAX_TYPES 116
+#define SCTP_SACK_LOG_NORMAL 116
+#define SCTP_SACK_LOG_EXPRESS 117
+
+#define SCTP_LOG_MAX_TYPES 118
/*
* To turn on various logging, you must first define SCTP_STAT_LOGGING. Then
* to get something to log you define one of the logging defines i.e.
diff --git a/sys/netinet/sctp_header.h b/sys/netinet/sctp_header.h
index 4b2a758..d2013ff 100644
--- a/sys/netinet/sctp_header.h
+++ b/sys/netinet/sctp_header.h
@@ -64,13 +64,17 @@ struct sctp_cookie_perserve_param {
};
#define SCTP_ARRAY_MIN_LEN 1
-
/* Host Name Address */
struct sctp_host_name_param {
struct sctp_paramhdr ph;/* type=SCTP_HOSTNAME_ADDRESS */
char name[SCTP_ARRAY_MIN_LEN]; /* host name */
};
+/*
+ * This is the maximum padded size of a s-a-p
+ * so paramheadr + 3 address types (6 bytes) + 2 byte pad = 12
+ */
+#define SCTP_MAX_ADDR_PARAMS_SIZE 12
/* supported address type */
struct sctp_supported_addr_param {
struct sctp_paramhdr ph;/* type=SCTP_SUPPORTED_ADDRTYPE */
@@ -121,6 +125,8 @@ struct sctp_asconf_addrv4_param { /* an ASCONF address (v4) parameter */
struct sctp_ipv4addr_param addrp; /* max storage size */
};
+#define SCTP_MAX_SUPPORTED_EXT 256
+
struct sctp_supported_chunk_types_param {
struct sctp_paramhdr ph;/* type = 0x8008 len = x */
uint8_t chunk_types[0];
@@ -490,6 +496,9 @@ struct sctp_stream_reset_resp_tsn {
/*
* Authenticated chunks support draft-ietf-tsvwg-sctp-auth
*/
+
+/* Should we make the max be 32? */
+#define SCTP_RANDOM_MAX_SIZE 256
struct sctp_auth_random {
struct sctp_paramhdr ph;/* type = 0x8002 */
uint8_t random_data[0];
diff --git a/sys/netinet/sctp_indata.c b/sys/netinet/sctp_indata.c
index 2010d2a..bf5727a 100644
--- a/sys/netinet/sctp_indata.c
+++ b/sys/netinet/sctp_indata.c
@@ -1595,6 +1595,18 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
sctp_queue_op_err(stcb, mb);
}
SCTP_STAT_INCR(sctps_badsid);
+ SCTP_SET_TSN_PRESENT(asoc->mapping_array, gap);
+ if (compare_with_wrap(tsn, asoc->highest_tsn_inside_map, MAX_TSN)) {
+ /* we have a new high score */
+ asoc->highest_tsn_inside_map = tsn;
+#ifdef SCTP_MAP_LOGGING
+ sctp_log_map(0, 2, asoc->highest_tsn_inside_map, SCTP_MAP_SLIDE_RESULT);
+#endif
+ }
+ if (tsn == (asoc->cumulative_tsn + 1)) {
+ /* Update cum-ack */
+ asoc->cumulative_tsn = tsn;
+ }
return (0);
}
/*
@@ -1631,10 +1643,6 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
asoc->strmin[strmno].last_sequence_delivered);
}
#endif
- /*
- * throw it in the stream so it gets cleaned up in
- * association destruction
- */
oper = sctp_get_mbuf_for_msg((sizeof(struct sctp_paramhdr) + 3 * sizeof(uint32_t)),
0, M_DONTWAIT, 1, MT_DATA);
if (oper) {
@@ -2014,7 +2022,7 @@ failed_pdapi_express_del:
struct sctp_stream_reset_list *liste;
if (((liste = TAILQ_FIRST(&asoc->resetHead)) != NULL) &&
- ((compare_with_wrap(tsn, liste->tsn, MAX_TSN)) ||
+ ((compare_with_wrap(tsn, ntohl(liste->tsn), MAX_TSN)) ||
(tsn == ntohl(liste->tsn)))
) {
/*
@@ -2181,6 +2189,7 @@ sctp_sack_check(struct sctp_tcb *stcb, int ok_to_sack, int was_a_gap, int *abort
all_ones = 1;
at = 0;
for (i = 0; i < stcb->asoc.mapping_array_size; i++) {
+
if (asoc->mapping_array[i] == 0xff) {
at += 8;
last_all_ones = 1;
@@ -2294,8 +2303,8 @@ sctp_sack_check(struct sctp_tcb *stcb, int ok_to_sack, int was_a_gap, int *abort
}
/* check the special flag for stream resets */
if (((liste = TAILQ_FIRST(&asoc->resetHead)) != NULL) &&
- ((compare_with_wrap(asoc->cumulative_tsn, liste->tsn, MAX_TSN)) ||
- (asoc->cumulative_tsn == liste->tsn))
+ ((compare_with_wrap(asoc->cumulative_tsn, ntohl(liste->tsn), MAX_TSN)) ||
+ (asoc->cumulative_tsn == ntohl(liste->tsn)))
) {
/*
* we have finished working through the backlogged TSN's now
@@ -2322,7 +2331,7 @@ sctp_sack_check(struct sctp_tcb *stcb, int ok_to_sack, int was_a_gap, int *abort
}
} else if (ctl) {
/* more than one in queue */
- while (!compare_with_wrap(ctl->sinfo_tsn, liste->tsn, MAX_TSN)) {
+ while (!compare_with_wrap(ctl->sinfo_tsn, ntohl(liste->tsn), MAX_TSN)) {
/*
* if ctl->sinfo_tsn is <= liste->tsn we can
* process it which is the NOT of
@@ -2522,12 +2531,13 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length,
*/
asoc->last_data_chunk_from = net;
- /*
+ /*-
* Now before we proceed we must figure out if this is a wasted
* cluster... i.e. it is a small packet sent in and yet the driver
* underneath allocated a full cluster for it. If so we must copy it
* to a smaller mbuf and free up the cluster mbuf. This will help
- * with cluster starvation.
+ * with cluster starvation. Note for __Panda__ we don't do this
+ * since it has clusters all the way down to 64 bytes.
*/
if (SCTP_BUF_LEN(m) < (long)MLEN && SCTP_BUF_NEXT(m) == NULL) {
/* we only handle mbufs that are singletons.. not chains */
@@ -3082,6 +3092,11 @@ sctp_check_for_revoked(struct sctp_tcb *stcb,
* time i.e. revoked. If it is MARKED it was ACK'ed
* again.
*/
+ if (compare_with_wrap(tp1->rec.data.TSN_seq, biggest_tsn_acked,
+ MAX_TSN))
+ break;
+
+
if (tp1->sent == SCTP_DATAGRAM_ACKED) {
/* it has been revoked */
tp1->sent = SCTP_DATAGRAM_SENT;
@@ -4148,13 +4163,32 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
uint32_t old_rwnd;
int win_probe_recovery = 0;
int win_probe_recovered = 0;
- int j, done_once;;
+ int j, done_once = 0;
+
+#ifdef SCTP_LOG_SACK_ARRIVALS
+ sctp_misc_ints(SCTP_SACK_LOG_EXPRESS, cumack,
+ rwnd, stcb->asoc.last_acked_seq, stcb->asoc.peers_rwnd);
+#endif
SCTP_TCB_LOCK_ASSERT(stcb);
asoc = &stcb->asoc;
+ old_rwnd = asoc->peers_rwnd;
if (compare_with_wrap(asoc->last_acked_seq, cumack, MAX_TSN)) {
/* old ack */
return;
+ } else if (asoc->last_acked_seq == cumack) {
+ /* Window update sack */
+ asoc->peers_rwnd = sctp_sbspace_sub(rwnd,
+ (uint32_t) (asoc->total_flight + (asoc->sent_queue_cnt * sctp_peer_chunk_oh)));
+ if (asoc->peers_rwnd < stcb->sctp_ep->sctp_ep.sctp_sws_sender) {
+ /* SWS sender side engages */
+ asoc->peers_rwnd = 0;
+ }
+ if (asoc->peers_rwnd > old_rwnd) {
+ goto again;
+ }
+ return;
+
}
/* First setup for CC stuff */
TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
@@ -4210,7 +4244,6 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
#endif
}
}
- old_rwnd = asoc->peers_rwnd;
asoc->this_sack_highest_gap = cumack;
stcb->asoc.overall_error_count = 0;
if (compare_with_wrap(cumack, asoc->last_acked_seq, MAX_TSN)) {
@@ -4411,7 +4444,6 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
win_probe_recovery = 1;
}
/* Now assure a timer where data is queued at */
- done_once = 0;
again:
j = 0;
TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
@@ -4574,7 +4606,7 @@ again:
void
sctp_handle_sack(struct sctp_sack_chunk *ch, struct sctp_tcb *stcb,
- struct sctp_nets *net_from, int *abort_now)
+ struct sctp_nets *net_from, int *abort_now, int sack_len, uint32_t rwnd)
{
struct sctp_association *asoc;
struct sctp_sack *sack;
@@ -4624,22 +4656,18 @@ sctp_handle_sack(struct sctp_sack_chunk *ch, struct sctp_tcb *stcb,
/* CMT DAC algo */
this_sack_lowest_newack = 0;
j = 0;
- sack_length = ntohs(ch->ch.chunk_length);
- if (sack_length < sizeof(struct sctp_sack_chunk)) {
-#ifdef SCTP_DEBUG
- if (sctp_debug_on & SCTP_DEBUG_INDATA1) {
- printf("Bad size on sack chunk .. to small\n");
- }
-#endif
- return;
- }
+ sack_length = (unsigned int)sack_len;
/* ECN Nonce */
SCTP_STAT_INCR(sctps_slowpath_sack);
nonce_sum_flag = ch->ch.chunk_flags & SCTP_SACK_NONCE_SUM;
cum_ack = last_tsn = ntohl(sack->cum_tsn_ack);
num_seg = ntohs(sack->num_gap_ack_blks);
- a_rwnd = (uint32_t) ntohl(sack->a_rwnd);
+ a_rwnd = rwnd;
+#ifdef SCTP_LOG_SACK_ARRIVALS
+ sctp_misc_ints(SCTP_SACK_LOG_NORMAL, cum_ack,
+ rwnd, stcb->asoc.last_acked_seq, stcb->asoc.peers_rwnd);
+#endif
/* CMT DAC algo */
cmt_dac_flag = ch->ch.chunk_flags & SCTP_SACK_CMT_DAC;
num_dup = ntohs(sack->num_dup_tsns);
diff --git a/sys/netinet/sctp_indata.h b/sys/netinet/sctp_indata.h
index f1a9d41..70ba477 100644
--- a/sys/netinet/sctp_indata.h
+++ b/sys/netinet/sctp_indata.h
@@ -91,7 +91,7 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
void
sctp_handle_sack(struct sctp_sack_chunk *, struct sctp_tcb *,
- struct sctp_nets *, int *);
+ struct sctp_nets *, int *, int, uint32_t);
/* draft-ietf-tsvwg-usctp */
void
@@ -109,7 +109,8 @@ sctp_update_acked(struct sctp_tcb *, struct sctp_shutdown_chunk *,
int
sctp_process_data(struct mbuf **, int, int *, int, struct sctphdr *,
- struct sctp_inpcb *, struct sctp_tcb *, struct sctp_nets *, uint32_t *);
+ struct sctp_inpcb *, struct sctp_tcb *,
+ struct sctp_nets *, uint32_t *);
void sctp_sack_check(struct sctp_tcb *, int, int, int *);
diff --git a/sys/netinet/sctp_input.c b/sys/netinet/sctp_input.c
index 90de716..b41db74 100644
--- a/sys/netinet/sctp_input.c
+++ b/sys/netinet/sctp_input.c
@@ -2231,7 +2231,7 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
* another and get the tcb in the right place.
*/
sctp_move_pcb_and_assoc(*inp_p, inp, *stcb);
- sctp_pull_off_control_to_new_inp((*inp_p), inp, *stcb);
+ sctp_pull_off_control_to_new_inp((*inp_p), inp, *stcb, M_NOWAIT);
/*
* now we must check to see if we were aborted while
@@ -2798,9 +2798,11 @@ sctp_find_stream_reset(struct sctp_tcb *stcb, uint32_t seq, struct sctp_tmit_chu
asoc = &stcb->asoc;
if (TAILQ_EMPTY(&stcb->asoc.control_send_queue)) {
+ asoc->stream_reset_outstanding = 0;
return (NULL);
}
if (stcb->asoc.str_reset == NULL) {
+ asoc->stream_reset_outstanding = 0;
return (NULL);
}
chk = stcb->asoc.str_reset;
@@ -3154,6 +3156,7 @@ sctp_handle_stream_reset(struct sctp_tcb *stcb, struct sctp_stream_reset_out_req
return (ret_code);
}
chk->rec.chunk_id.id = SCTP_STREAM_RESET;
+ chk->rec.chunk_id.can_take_data = 0;
chk->asoc = &stcb->asoc;
chk->no_fr_allowed = 0;
chk->book_size = chk->send_size = sizeof(struct sctp_chunkhdr);
@@ -3181,7 +3184,6 @@ strres_nochunk:
ch->chunk_flags = 0;
ch->chunk_length = htons(chk->send_size);
SCTP_BUF_LEN(chk->data) = SCTP_SIZE32(chk->send_size);
-
ph = (struct sctp_paramhdr *)&sr_req->sr_req;
while ((size_t)chk_length >= sizeof(struct sctp_stream_reset_tsn_request)) {
param_len = ntohs(ph->param_length);
@@ -3726,7 +3728,8 @@ process_control_chunks:
* because we don't have to process the peer's COOKIE. All
* others get a complete chunk.
*/
- if (ch->chunk_type == SCTP_INITIATION_ACK) {
+ if ((ch->chunk_type == SCTP_INITIATION_ACK) ||
+ (ch->chunk_type == SCTP_INITIATION)) {
/* get an init-ack chunk */
ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, *offset,
sizeof(struct sctp_init_ack_chunk), chunk_buf);
@@ -3736,6 +3739,29 @@ process_control_chunks:
SCTP_TCB_UNLOCK(locked_tcb);
return (NULL);
}
+ } else if (ch->chunk_type == SCTP_COOKIE_ECHO) {
+ if (chk_length > sizeof(chunk_buf)) {
+ /*
+ * use just the size of the chunk buffer so
+ * the front part of our cookie is intact.
+ * The rest of cookie processing should use
+ * the sctp_m_getptr() function to access
+ * the other parts.
+ */
+ ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, *offset,
+ (sizeof(chunk_buf) - 4),
+ chunk_buf);
+ if (ch == NULL) {
+ *offset = length;
+ if (locked_tcb)
+ SCTP_TCB_UNLOCK(locked_tcb);
+ return (NULL);
+ }
+ } else {
+ /* We can fit it all */
+ goto all_fits;
+ }
+
} else {
/* get a complete chunk... */
if ((size_t)chk_length > sizeof(chunk_buf)) {
@@ -3743,21 +3769,25 @@ process_control_chunks:
struct sctp_paramhdr *phdr;
oper = NULL;
- oper = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr),
- 0, M_DONTWAIT, 1, MT_DATA);
- if (oper) {
- /* pre-reserve some space */
- SCTP_BUF_RESV_UF(oper, sizeof(struct sctp_chunkhdr));
- SCTP_BUF_LEN(oper) = sizeof(struct sctp_paramhdr);
- phdr = mtod(oper, struct sctp_paramhdr *);
- phdr->param_type = htons(SCTP_CAUSE_OUT_OF_RESC);
- phdr->param_length = htons(sizeof(struct sctp_paramhdr));
- sctp_queue_op_err(stcb, oper);
+ if (stcb) {
+ oper = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr),
+ 0, M_DONTWAIT, 1, MT_DATA);
+
+ if (oper) {
+ /* pre-reserve some space */
+ SCTP_BUF_RESV_UF(oper, sizeof(struct sctp_chunkhdr));
+ SCTP_BUF_LEN(oper) = sizeof(struct sctp_paramhdr);
+ phdr = mtod(oper, struct sctp_paramhdr *);
+ phdr->param_type = htons(SCTP_CAUSE_OUT_OF_RESC);
+ phdr->param_length = htons(sizeof(struct sctp_paramhdr));
+ sctp_queue_op_err(stcb, oper);
+ }
}
if (locked_tcb)
SCTP_TCB_UNLOCK(locked_tcb);
return (NULL);
}
+ all_fits:
ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, *offset,
chk_length, chunk_buf);
if (ch == NULL) {
@@ -3902,8 +3932,16 @@ process_control_chunks:
uint16_t num_seg;
int nonce_sum_flag;
+ if (chk_length < sizeof(struct sctp_sack_chunk)) {
+#ifdef SCTP_DEBUG
+ if (sctp_debug_on & SCTP_DEBUG_INDATA1) {
+ printf("Bad size on sack chunk .. to small\n");
+ }
+#endif
+ *offset = length;
+ return (NULL);
+ }
sack = (struct sctp_sack_chunk *)ch;
-
nonce_sum_flag = ch->chunk_flags & SCTP_SACK_NONCE_SUM;
cum_ack = ntohl(sack->sack.cum_tsn_ack);
num_seg = ntohs(sack->sack.num_gap_ack_blks);
@@ -3925,9 +3963,10 @@ process_control_chunks:
* with no missing segments to go
* this way too.
*/
- sctp_express_handle_sack(stcb, cum_ack, a_rwnd, nonce_sum_flag, &abort_now);
+ sctp_express_handle_sack(stcb, cum_ack, a_rwnd, nonce_sum_flag,
+ &abort_now);
} else {
- sctp_handle_sack(sack, stcb, *netp, &abort_now);
+ sctp_handle_sack(sack, stcb, *netp, &abort_now, chk_length, a_rwnd);
}
if (abort_now) {
/* ABORT signal from sack processing */
@@ -3955,7 +3994,11 @@ process_control_chunks:
printf("SCTP_HEARTBEAT-ACK\n");
}
#endif /* SCTP_DEBUG */
-
+ if (chk_length != sizeof(struct sctp_heartbeat_chunk)) {
+ /* Its not ours */
+ *offset = length;
+ return (NULL);
+ }
/* He's alive so give him credit */
stcb->asoc.overall_error_count = 0;
SCTP_STAT_INCR(sctps_recvheartbeatack);
@@ -3979,7 +4022,11 @@ process_control_chunks:
printf("SCTP_SHUTDOWN\n");
}
#endif /* SCTP_DEBUG */
- {
+ if (chk_length != sizeof(struct sctp_shutdown_chunk)) {
+ *offset = length;
+ return (NULL);
+
+ } {
int abort_flag = 0;
sctp_handle_shutdown((struct sctp_shutdown_chunk *)ch,
@@ -4162,6 +4209,11 @@ process_control_chunks:
}
#endif /* SCTP_DEBUG */
/* He's alive so give him credit */
+ if (chk_length != sizeof(struct sctp_ecne_chunk)) {
+ /* Its not ours */
+ *offset = length;
+ return (NULL);
+ }
stcb->asoc.overall_error_count = 0;
sctp_handle_ecn_echo((struct sctp_ecne_chunk *)ch,
stcb);
@@ -4173,6 +4225,11 @@ process_control_chunks:
}
#endif /* SCTP_DEBUG */
/* He's alive so give him credit */
+ if (chk_length != sizeof(struct sctp_cwr_chunk)) {
+ /* Its not ours */
+ *offset = length;
+ return (NULL);
+ }
stcb->asoc.overall_error_count = 0;
sctp_handle_ecn_cwr((struct sctp_cwr_chunk *)ch, stcb);
@@ -4215,6 +4272,11 @@ process_control_chunks:
printf("SCTP_ASCONF-ACK\n");
}
#endif /* SCTP_DEBUG */
+ if (chk_length < sizeof(struct sctp_asconf_ack_chunk)) {
+ /* Its not ours */
+ *offset = length;
+ return (NULL);
+ }
/* He's alive so give him credit */
stcb->asoc.overall_error_count = 0;
@@ -4227,6 +4289,11 @@ process_control_chunks:
printf("SCTP_FWD-TSN\n");
}
#endif /* SCTP_DEBUG */
+ if (chk_length < sizeof(struct sctp_forward_tsn_chunk)) {
+ /* Its not ours */
+ *offset = length;
+ return (NULL);
+ }
/* He's alive so give him credit */
{
int abort_flag = 0;
@@ -4258,6 +4325,11 @@ process_control_chunks:
#endif /* SCTP_DEBUG */
ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, *offset,
chk_length, chunk_buf);
+ if (chk_length < sizeof(struct sctp_stream_reset_tsn_req)) {
+ /* Its not ours */
+ *offset = length;
+ return (NULL);
+ }
if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
/* We are not interested anymore */
sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_29);
@@ -4285,6 +4357,11 @@ process_control_chunks:
}
#endif /* SCTP_DEBUG */
/* re-get it all please */
+ if (chk_length < sizeof(struct sctp_pktdrop_chunk)) {
+ /* Its not ours */
+ *offset = length;
+ return (NULL);
+ }
ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, *offset,
chk_length, chunk_buf);
@@ -4312,6 +4389,12 @@ process_control_chunks:
/* skip this chunk (temporarily) */
goto next_chunk;
}
+ if ((chk_length < (sizeof(struct sctp_auth_chunk))) ||
+ (chk_length > (sizeof(struct sctp_auth_chunk) + SCTP_AUTH_DIGEST_LEN_MAX))) {
+ /* Its not ours */
+ *offset = length;
+ return (NULL);
+ }
if (got_auth == 1) {
/* skip this chunk... it's already auth'd */
goto next_chunk;
@@ -4902,5 +4985,7 @@ bad:
if (m) {
sctp_m_freem(m);
}
+ /* For BSD/MAC this does nothing */
+ SCTP_RELEASE_PAK(i_pak);
return;
}
diff --git a/sys/netinet/sctp_os_bsd.h b/sys/netinet/sctp_os_bsd.h
index 81e028c..b01287e 100644
--- a/sys/netinet/sctp_os_bsd.h
+++ b/sys/netinet/sctp_os_bsd.h
@@ -226,6 +226,7 @@ typedef struct callout sctp_os_timer_t;
#define SCTP_HEADER_TO_CHAIN(m) (m)
#define SCTP_HEADER_LEN(m) (m->m_pkthdr.len)
#define SCTP_GET_HEADER_FOR_OUTPUT(len) sctp_get_mbuf_for_msg(len, 1, M_DONTWAIT, 1, MT_DATA)
+#define SCTP_RELEASE_PAK(i_pak)
/* Attach the chain of data into the sendable packet. */
#define SCTP_ATTACH_CHAIN(pak, m, packet_length) do { \
@@ -242,7 +243,6 @@ typedef struct callout sctp_os_timer_t;
* into the chain of data holders, for BSD
* its a NOP.
*/
-#define SCTP_PAK_TO_BUF(i_pak) (i_pak)
/* Macro's for getting length from V6/V4 header */
#define SCTP_GET_IPV4_LENGTH(iph) (iph->ip_len)
@@ -273,6 +273,11 @@ typedef struct callout sctp_os_timer_t;
typedef struct route sctp_route_t;
+struct mbuf *
+sctp_get_mbuf_for_msg(unsigned int space_needed,
+ int want_header, int how, int allonebuf, int type);
+
+
/*
* SCTP AUTH
*/
diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c
index 71ef568..96d9495 100644
--- a/sys/netinet/sctp_output.c
+++ b/sys/netinet/sctp_output.c
@@ -3160,43 +3160,6 @@ sctp_find_cmsg(int c_type, void *data, struct mbuf *control, int cpsize)
return (0);
}
-
-struct mbuf *
-sctp_get_mbuf_for_msg(unsigned int space_needed, int want_header,
- int how, int allonebuf, int type)
-{
- struct mbuf *m = NULL;
-
- m = m_getm2(NULL, space_needed, how, type, want_header ? M_PKTHDR : 0);
- if (allonebuf) {
- int siz;
-
- if (SCTP_BUF_IS_EXTENDED(m)) {
- siz = SCTP_BUF_EXTEND_SIZE(m);
- } else {
- if (want_header)
- siz = MHLEN;
- else
- siz = MLEN;
- }
- if (siz < space_needed) {
- m_freem(m);
- return (NULL);
- }
- }
- if (SCTP_BUF_NEXT(m)) {
- sctp_m_freem(SCTP_BUF_NEXT(m));
- SCTP_BUF_NEXT(m) = NULL;
- }
-#ifdef SCTP_MBUF_LOGGING
- if (SCTP_BUF_IS_EXTENDED(m)) {
- sctp_log_mb(m, SCTP_MBUF_IALLOC);
- }
-#endif
- return (m);
-}
-
-
static struct mbuf *
sctp_add_cookie(struct sctp_inpcb *inp, struct mbuf *init, int init_offset,
struct mbuf *initack, int initack_offset, struct sctp_state_cookie *stc_in)
@@ -3569,10 +3532,11 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
printf("RTP route is %p through\n", ro->ro_rt);
}
#endif
-
+#ifdef _WHY_THIS_CODE
if ((have_mtu) && (net) && (have_mtu > net->mtu)) {
ro->ro_rt->rt_ifp->if_mtu = net->mtu;
}
+#endif
if (ro != &iproute) {
memcpy(&iproute, ro, sizeof(*ro));
}
@@ -3580,9 +3544,11 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
ro, o_flgs, inp->ip_inp.inp.inp_moptions
,(struct inpcb *)NULL
);
+#ifdef _WHY_THIS_CODE
if ((ro->ro_rt) && (have_mtu) && (net) && (have_mtu > net->mtu)) {
ro->ro_rt->rt_ifp->if_mtu = have_mtu;
}
+#endif
SCTP_STAT_INCR(sctps_sendpackets);
SCTP_STAT_INCR_COUNTER64(sctps_outpackets);
if (ret)
@@ -4150,9 +4116,9 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt,
struct sctp_paramhdr *phdr, params;
struct mbuf *mat, *op_err;
- char tempbuf[SCTP_CHUNK_BUFFER_SIZE];
+ char tempbuf[SCTP_PARAM_BUFFER_SIZE];
int at, limit, pad_needed;
- uint16_t ptype, plen;
+ uint16_t ptype, plen, padded_size;
int err_at;
*abort_processing = 0;
@@ -4166,105 +4132,164 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt,
while ((phdr != NULL) && ((size_t)limit >= sizeof(struct sctp_paramhdr))) {
ptype = ntohs(phdr->param_type);
plen = ntohs(phdr->param_length);
- limit -= SCTP_SIZE32(plen);
- if (plen < sizeof(struct sctp_paramhdr)) {
-#ifdef SCTP_DEBUG
- if (sctp_debug_on & SCTP_DEBUG_OUTPUT4) {
- printf("sctp_output.c:Impossible length in parameter < %d\n", plen);
- }
-#endif
- *abort_processing = 1;
- break;
+ if ((plen > limit) || (plen < sizeof(struct sctp_paramhdr))) {
+ /* wacked parameter */
+ goto invalid_size;
}
- /*
+ limit -= SCTP_SIZE32(plen);
+ /*-
* All parameters for all chunks that we know/understand are
* listed here. We process them other places and make
* appropriate stop actions per the upper bits. However this
* is the generic routine processor's can call to get back
* an operr.. to either incorporate (init-ack) or send.
*/
- if ((ptype == SCTP_HEARTBEAT_INFO) ||
- (ptype == SCTP_IPV4_ADDRESS) ||
- (ptype == SCTP_IPV6_ADDRESS) ||
- (ptype == SCTP_STATE_COOKIE) ||
- (ptype == SCTP_UNRECOG_PARAM) ||
- (ptype == SCTP_COOKIE_PRESERVE) ||
- (ptype == SCTP_SUPPORTED_ADDRTYPE) ||
- (ptype == SCTP_PRSCTP_SUPPORTED) ||
- (ptype == SCTP_ADD_IP_ADDRESS) ||
- (ptype == SCTP_DEL_IP_ADDRESS) ||
- (ptype == SCTP_ECN_CAPABLE) ||
- (ptype == SCTP_ULP_ADAPTATION) ||
- (ptype == SCTP_ERROR_CAUSE_IND) ||
- (ptype == SCTP_RANDOM) ||
- (ptype == SCTP_CHUNK_LIST) ||
- (ptype == SCTP_CHUNK_LIST) ||
- (ptype == SCTP_SET_PRIM_ADDR) ||
- (ptype == SCTP_SUCCESS_REPORT) ||
- (ptype == SCTP_ULP_ADAPTATION) ||
- (ptype == SCTP_SUPPORTED_CHUNK_EXT) ||
- (ptype == SCTP_ECN_NONCE_SUPPORTED)
- ) {
- /* no skip it */
- at += SCTP_SIZE32(plen);
- } else if (ptype == SCTP_HOSTNAME_ADDRESS) {
- /* We can NOT handle HOST NAME addresses!! */
- int l_len;
+ padded_size = SCTP_SIZE32(plen);
+ switch (ptype) {
+ /* Param's with variable size */
+ case SCTP_HEARTBEAT_INFO:
+ case SCTP_STATE_COOKIE:
+ case SCTP_UNRECOG_PARAM:
+ case SCTP_ERROR_CAUSE_IND:
+ /* ok skip fwd */
+ at += padded_size;
+ break;
+ /* Param's with variable size within a range */
+ case SCTP_CHUNK_LIST:
+ case SCTP_SUPPORTED_CHUNK_EXT:
+ if (padded_size > (sizeof(struct sctp_supported_chunk_types_param) + (sizeof(uint8_t) * SCTP_MAX_SUPPORTED_EXT))) {
+ goto invalid_size;
+ }
+ at += padded_size;
+ break;
+ case SCTP_SUPPORTED_ADDRTYPE:
+ if (padded_size > SCTP_MAX_ADDR_PARAMS_SIZE) {
+ goto invalid_size;
+ }
+ at += padded_size;
+ break;
+ case SCTP_RANDOM:
+ if (padded_size > (sizeof(struct sctp_auth_random) + SCTP_RANDOM_MAX_SIZE)) {
+ goto invalid_size;
+ }
+ at += padded_size;
+ break;
+ case SCTP_SET_PRIM_ADDR:
+ case SCTP_DEL_IP_ADDRESS:
+ case SCTP_ADD_IP_ADDRESS:
+ if ((padded_size != sizeof(struct sctp_asconf_addrv4_param)) &&
+ (padded_size != sizeof(struct sctp_asconf_addr_param))) {
+ goto invalid_size;
+ }
+ at += padded_size;
+ break;
+ /* Param's with a fixed size */
+ case SCTP_IPV4_ADDRESS:
+ if (padded_size != sizeof(struct sctp_ipv4addr_param)) {
+ goto invalid_size;
+ }
+ at += padded_size;
+ break;
+ case SCTP_IPV6_ADDRESS:
+ if (padded_size != sizeof(struct sctp_ipv6addr_param)) {
+ goto invalid_size;
+ }
+ at += padded_size;
+ break;
+ case SCTP_COOKIE_PRESERVE:
+ if (padded_size != sizeof(struct sctp_cookie_perserve_param)) {
+ goto invalid_size;
+ }
+ at += padded_size;
+ break;
+ case SCTP_ECN_NONCE_SUPPORTED:
+ case SCTP_PRSCTP_SUPPORTED:
+ if (padded_size != sizeof(struct sctp_paramhdr)) {
+ goto invalid_size;
+ }
+ at += padded_size;
+ break;
+ case SCTP_ECN_CAPABLE:
+ if (padded_size != sizeof(struct sctp_ecn_supported_param)) {
+ goto invalid_size;
+ }
+ at += padded_size;
+ break;
+ case SCTP_ULP_ADAPTATION:
+ if (padded_size != sizeof(struct sctp_adaptation_layer_indication)) {
+ goto invalid_size;
+ }
+ at += padded_size;
+ break;
+ case SCTP_SUCCESS_REPORT:
+ if (padded_size != sizeof(struct sctp_asconf_paramhdr)) {
+ goto invalid_size;
+ }
+ at += padded_size;
+ break;
+ case SCTP_HOSTNAME_ADDRESS:
+ {
+ /* We can NOT handle HOST NAME addresses!! */
+ int l_len;
#ifdef SCTP_DEBUG
- if (sctp_debug_on & SCTP_DEBUG_OUTPUT4) {
- printf("Can't handle hostname addresses.. abort processing\n");
- }
+ if (sctp_debug_on & SCTP_DEBUG_OUTPUT4) {
+ printf("Can't handle hostname addresses.. abort processing\n");
+ }
#endif
- *abort_processing = 1;
- if (op_err == NULL) {
- /* Ok need to try to get a mbuf */
- l_len = sizeof(struct ip6_hdr) + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr);
- l_len += plen;
- l_len += sizeof(struct sctp_paramhdr);
- op_err = sctp_get_mbuf_for_msg(l_len, 0, M_DONTWAIT, 1, MT_DATA);
- if (op_err) {
- SCTP_BUF_LEN(op_err) = 0;
- /*
- * pre-reserve space for ip and sctp
- * header and chunk hdr
- */
- SCTP_BUF_RESV_UF(op_err, sizeof(struct ip6_hdr));
- SCTP_BUF_RESV_UF(op_err, sizeof(struct sctphdr));
- SCTP_BUF_RESV_UF(op_err, sizeof(struct sctp_chunkhdr));
+ *abort_processing = 1;
+ if (op_err == NULL) {
+ /* Ok need to try to get a mbuf */
+ l_len = sizeof(struct ip6_hdr) + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr);
+ l_len += plen;
+ l_len += sizeof(struct sctp_paramhdr);
+ op_err = sctp_get_mbuf_for_msg(l_len, 0, M_DONTWAIT, 1, MT_DATA);
+ if (op_err) {
+ SCTP_BUF_LEN(op_err) = 0;
+ /*
+ * pre-reserve space for ip
+ * and sctp header and
+ * chunk hdr
+ */
+ SCTP_BUF_RESV_UF(op_err, sizeof(struct ip6_hdr));
+ SCTP_BUF_RESV_UF(op_err, sizeof(struct sctphdr));
+ SCTP_BUF_RESV_UF(op_err, sizeof(struct sctp_chunkhdr));
+ }
}
- }
- if (op_err) {
- /* If we have space */
- struct sctp_paramhdr s;
+ if (op_err) {
+ /* If we have space */
+ struct sctp_paramhdr s;
- if (err_at % 4) {
- uint32_t cpthis = 0;
+ if (err_at % 4) {
+ uint32_t cpthis = 0;
- pad_needed = 4 - (err_at % 4);
- m_copyback(op_err, err_at, pad_needed, (caddr_t)&cpthis);
- err_at += pad_needed;
- }
- s.param_type = htons(SCTP_CAUSE_UNRESOLVABLE_ADDR);
- s.param_length = htons(sizeof(s) + plen);
- m_copyback(op_err, err_at, sizeof(s), (caddr_t)&s);
- err_at += sizeof(s);
- phdr = sctp_get_next_param(mat, at, (struct sctp_paramhdr *)tempbuf, plen);
- if (phdr == NULL) {
- sctp_m_freem(op_err);
- /*
- * we are out of memory but we still
- * need to have a look at what to do
- * (the system is in trouble
- * though).
- */
- return (NULL);
+ pad_needed = 4 - (err_at % 4);
+ m_copyback(op_err, err_at, pad_needed, (caddr_t)&cpthis);
+ err_at += pad_needed;
+ }
+ s.param_type = htons(SCTP_CAUSE_UNRESOLVABLE_ADDR);
+ s.param_length = htons(sizeof(s) + plen);
+ m_copyback(op_err, err_at, sizeof(s), (caddr_t)&s);
+ err_at += sizeof(s);
+ phdr = sctp_get_next_param(mat, at, (struct sctp_paramhdr *)tempbuf, min(sizeof(tempbuf), plen));
+ if (phdr == NULL) {
+ sctp_m_freem(op_err);
+ /*
+ * we are out of memory but
+ * we still need to have a
+ * look at what to do (the
+ * system is in trouble
+ * though).
+ */
+ return (NULL);
+ }
+ m_copyback(op_err, err_at, plen, (caddr_t)phdr);
+ err_at += plen;
}
- m_copyback(op_err, err_at, plen, (caddr_t)phdr);
- err_at += plen;
+ return (op_err);
+ break;
}
- return (op_err);
- } else {
+ default:
/*
* we do not recognize the parameter figure out what
* we do.
@@ -4304,7 +4329,7 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt,
if (plen > sizeof(tempbuf)) {
plen = sizeof(tempbuf);
}
- phdr = sctp_get_next_param(mat, at, (struct sctp_paramhdr *)tempbuf, plen);
+ phdr = sctp_get_next_param(mat, at, (struct sctp_paramhdr *)tempbuf, min(sizeof(tempbuf), plen));
if (phdr == NULL) {
sctp_m_freem(op_err);
/*
@@ -4314,6 +4339,7 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt,
* system is in trouble
* though).
*/
+ op_err = NULL;
goto more_processing;
}
m_copyback(op_err, err_at, plen, (caddr_t)phdr);
@@ -4327,11 +4353,43 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt,
/* skip this chunk and continue processing */
at += SCTP_SIZE32(plen);
}
+ break;
}
phdr = sctp_get_next_param(mat, at, &params, sizeof(params));
}
return (op_err);
+invalid_size:
+ *abort_processing = 1;
+ if ((op_err == NULL) && phdr) {
+ int l_len;
+
+ l_len = sizeof(struct ip6_hdr) + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr);
+ l_len += (2 * sizeof(struct sctp_paramhdr));
+ op_err = sctp_get_mbuf_for_msg(l_len, 0, M_DONTWAIT, 1, MT_DATA);
+ SCTP_BUF_LEN(op_err) = 0;
+ SCTP_BUF_RESV_UF(op_err, sizeof(struct ip6_hdr));
+ SCTP_BUF_RESV_UF(op_err, sizeof(struct sctphdr));
+ SCTP_BUF_RESV_UF(op_err, sizeof(struct sctp_chunkhdr));
+ }
+ if ((op_err) && phdr) {
+ struct sctp_paramhdr s;
+
+ if (err_at % 4) {
+ uint32_t cpthis = 0;
+
+ pad_needed = 4 - (err_at % 4);
+ m_copyback(op_err, err_at, pad_needed, (caddr_t)&cpthis);
+ err_at += pad_needed;
+ }
+ s.param_type = htons(SCTP_CAUSE_PROTOCOL_VIOLATION);
+ s.param_length = htons(sizeof(s) + sizeof(struct sctp_paramhdr));
+ m_copyback(op_err, err_at, sizeof(s), (caddr_t)&s);
+ err_at += sizeof(s);
+ /* Only copy back the p-hdr that caused the issue */
+ m_copyback(op_err, err_at, sizeof(struct sctp_paramhdr), (caddr_t)phdr);
+ }
+ return (op_err);
}
static int
@@ -7976,6 +8034,9 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp,
#endif
asoc->sent_queue_cnt = 0;
asoc->sent_queue_cnt_removeable = 0;
+ /* send back 0/0 so we enter normal transmission */
+ *cnt_out = 0;
+ return (0);
}
TAILQ_FOREACH(chk, &asoc->control_send_queue, sctp_next) {
if ((chk->rec.chunk_id.id == SCTP_COOKIE_ECHO) ||
@@ -8444,13 +8505,16 @@ sctp_chunk_output(struct sctp_inpcb *inp,
{
/*-
* Ok this is the generic chunk service queue. we must do the
- * following: - See if there are retransmits pending, if so we must
- * do these first and return. - Service the stream queue that is
- * next, moving any message (note I must get a complete message i.e.
- * FIRST/MIDDLE and LAST to the out queue in one pass) and assigning
- * TSN's - Check to see if the cwnd/rwnd allows any output, if so we
- * go ahead and fomulate and send the low level chunks. Making sure
- * to combine any control in the control chunk queue also.
+ * following:
+ * - See if there are retransmits pending, if so we must
+ * do these first.
+ * - Service the stream queue that is next, moving any
+ * message (note I must get a complete message i.e.
+ * FIRST/MIDDLE and LAST to the out queue in one pass) and assigning
+ * TSN's
+ * - Check to see if the cwnd/rwnd allows any output, if so we
+ * go ahead and fomulate and send the low level chunks. Making sure
+ * to combine any control in the control chunk queue also.
*/
struct sctp_association *asoc;
struct sctp_nets *net;
@@ -8497,7 +8561,7 @@ sctp_chunk_output(struct sctp_inpcb *inp,
*/
if (from_where == SCTP_OUTPUT_FROM_COOKIE_ACK) {
/*-
- *Special hook for handling cookiess discarded
+ * Special hook for handling cookiess discarded
* by peer that carried data. Send cookie-ack only
* and then the next call with get the retran's.
*/
@@ -9064,7 +9128,7 @@ sctp_send_sack(struct sctp_tcb *stcb)
gap_descriptor = (struct sctp_gap_ack_block *)((caddr_t)sack + sizeof(struct sctp_sack_chunk));
siz = (((asoc->highest_tsn_inside_map - asoc->mapping_array_base_tsn) + 1) + 7) / 8;
- if (asoc->cumulative_tsn < asoc->mapping_array_base_tsn) {
+ if (compare_with_wrap(asoc->mapping_array_base_tsn, asoc->cumulative_tsn, MAX_TSN)) {
offset = 1;
/*-
* cum-ack behind the mapping array, so we start and use all
@@ -9075,7 +9139,7 @@ sctp_send_sack(struct sctp_tcb *stcb)
offset = asoc->mapping_array_base_tsn - asoc->cumulative_tsn;
/*-
* we skip the first one when the cum-ack is at or above the
- * mapping array base.
+ * mapping array base. Note this only works if
*/
jstart = 1;
}
@@ -11142,11 +11206,15 @@ sctp_lower_sosend(struct socket *so,
}
initial_out = uio->uio_resid;
+ SCTP_TCB_SEND_LOCK(stcb);
if ((asoc->stream_locked) &&
(asoc->stream_locked_on != srcv->sinfo_stream)) {
+ SCTP_TCB_SEND_UNLOCK(stcb);
error = EAGAIN;
goto out;
}
+ SCTP_TCB_SEND_UNLOCK(stcb);
+
strm = &stcb->asoc.strmout[srcv->sinfo_stream];
user_marks_eor = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR);
if (strm->last_msg_incomplete == 0) {
diff --git a/sys/netinet/sctp_output.h b/sys/netinet/sctp_output.h
index bebce43..584252a 100644
--- a/sys/netinet/sctp_output.h
+++ b/sys/netinet/sctp_output.h
@@ -40,11 +40,6 @@ __FBSDID("$FreeBSD$");
#if defined(_KERNEL)
-struct mbuf *
-sctp_get_mbuf_for_msg(unsigned int space_needed,
- int want_header, int how, int allonebuf, int type);
-
-
struct mbuf *
sctp_add_addresses_to_i_ia(struct sctp_inpcb *inp,
diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c
index 376d511..de7e96e 100644
--- a/sys/netinet/sctp_pcb.c
+++ b/sys/netinet/sctp_pcb.c
@@ -234,7 +234,7 @@ sctp_free_ifa(struct sctp_ifa *sctp_ifap)
struct sctp_ifa *
sctp_add_addr_to_vrf(uint32_t vrfid, void *ifn, uint32_t ifn_index,
uint32_t ifn_type, const char *if_name,
- void *ifa, struct sockaddr *addr, uint32_t ifa_flags)
+ void *ifa, struct sockaddr *addr, uint32_t ifa_flags, int dynamic_add)
{
struct sctp_vrf *vrf;
struct sctp_ifn *sctp_ifnp = NULL;
@@ -364,16 +364,55 @@ sctp_add_addr_to_vrf(uint32_t vrfid, void *ifn, uint32_t ifn_index,
sctp_ifap->in_ifa_list = 1;
vrf->total_ifa_count++;
SCTP_IPI_ADDR_UNLOCK();
+ if (dynamic_add) {
+ /*
+ * Bump up the refcount so that when the timer completes it
+ * will drop back down.
+ */
+ struct sctp_laddr *wi;
+
+ atomic_add_int(&sctp_ifap->refcount, 1);
+ wi = SCTP_ZONE_GET(sctppcbinfo.ipi_zone_laddr, struct sctp_laddr);
+ if (wi == NULL) {
+ /*
+ * Gak, what can we do? We have lost an address
+ * change can you say HOSED?
+ */
+#ifdef SCTP_DEBUG
+ if (sctp_debug_on & SCTP_DEBUG_PCB1) {
+ printf("Lost and address change ???\n");
+ }
+#endif /* SCTP_DEBUG */
+
+ /* Opps, must decrement the count */
+ sctp_free_ifa(sctp_ifap);
+ return (NULL);
+ }
+ SCTP_INCR_LADDR_COUNT();
+ bzero(wi, sizeof(*wi));
+ wi->ifa = sctp_ifap;
+ wi->action = SCTP_ADD_IP_ADDRESS;
+ SCTP_IPI_ITERATOR_WQ_LOCK();
+ /*
+ * Should this really be a tailq? As it is we will process
+ * the newest first :-0
+ */
+ LIST_INSERT_HEAD(&sctppcbinfo.addr_wq, wi, sctp_nxt_addr);
+ sctp_timer_start(SCTP_TIMER_TYPE_ADDR_WQ,
+ (struct sctp_inpcb *)NULL,
+ (struct sctp_tcb *)NULL,
+ (struct sctp_nets *)NULL);
+ SCTP_IPI_ITERATOR_WQ_UNLOCK();
+ }
return (sctp_ifap);
}
-struct sctp_ifa *
+void
sctp_del_addr_from_vrf(uint32_t vrfid, struct sockaddr *addr,
uint32_t ifn_index)
{
struct sctp_vrf *vrf;
struct sctp_ifa *sctp_ifap = NULL;
- struct sctp_ifn *sctp_ifnp = NULL;
SCTP_IPI_ADDR_LOCK();
@@ -382,22 +421,16 @@ sctp_del_addr_from_vrf(uint32_t vrfid, struct sockaddr *addr,
printf("Can't find vrfid:%d\n", vrfid);
goto out_now;
}
- sctp_ifnp = sctp_find_ifn(vrf, (void *)NULL, ifn_index);
- if (sctp_ifnp == NULL) {
- sctp_ifap = sctp_find_ifa_by_addr(addr, vrf->vrf_id, 1);
- } else {
- sctp_ifap = sctp_find_ifa_in_ifn(sctp_ifnp, addr, 1);
- }
-
+ sctp_ifap = sctp_find_ifa_by_addr(addr, vrf->vrf_id, 1);
if (sctp_ifap) {
sctp_ifap->localifa_flags &= SCTP_ADDR_VALID;
sctp_ifap->localifa_flags |= SCTP_BEING_DELETED;
- sctp_ifnp->ifa_count--;
+ sctp_ifap->ifn_p->ifa_count--;
vrf->total_ifa_count--;
LIST_REMOVE(sctp_ifap, next_bucket);
LIST_REMOVE(sctp_ifap, next_ifa);
sctp_ifap->in_ifa_list = 0;
- atomic_add_int(&sctp_ifnp->refcount, -1);
+ atomic_add_int(&sctp_ifap->ifn_p->refcount, -1);
} else {
printf("Del Addr-ifn:%d Could not find address:",
ifn_index);
@@ -405,37 +438,51 @@ sctp_del_addr_from_vrf(uint32_t vrfid, struct sockaddr *addr,
}
out_now:
SCTP_IPI_ADDR_UNLOCK();
- return (sctp_ifap);
-}
+ if (sctp_ifap) {
+ struct sctp_laddr *wi;
-/*
- * Notes on locks for FreeBSD 5 and up. All association lookups that have a
- * definte ep, the INP structure is assumed to be locked for reading. If we
- * need to go find the INP (ususally when a **inp is passed) then we must
- * lock the INFO structure first and if needed lock the INP too. Note that if
- * we lock it we must
- *
- */
+ wi = SCTP_ZONE_GET(sctppcbinfo.ipi_zone_laddr, struct sctp_laddr);
+ if (wi == NULL) {
+ /*
+ * Gak, what can we do? We have lost an address
+ * change can you say HOSED?
+ */
+#ifdef SCTP_DEBUG
+ if (sctp_debug_on & SCTP_DEBUG_PCB1) {
+ printf("Lost and address change ???\n");
+ }
+#endif /* SCTP_DEBUG */
+
+ /* Opps, must decrement the count */
+ sctp_free_ifa(sctp_ifap);
+ return;
+ }
+ SCTP_INCR_LADDR_COUNT();
+ bzero(wi, sizeof(*wi));
+ wi->ifa = sctp_ifap;
+ wi->action = SCTP_DEL_IP_ADDRESS;
+ SCTP_IPI_ITERATOR_WQ_LOCK();
+ /*
+ * Should this really be a tailq? As it is we will process
+ * the newest first :-0
+ */
+ LIST_INSERT_HEAD(&sctppcbinfo.addr_wq, wi, sctp_nxt_addr);
+ sctp_timer_start(SCTP_TIMER_TYPE_ADDR_WQ,
+ (struct sctp_inpcb *)NULL,
+ (struct sctp_tcb *)NULL,
+ (struct sctp_nets *)NULL);
+ SCTP_IPI_ITERATOR_WQ_UNLOCK();
+ }
+ return;
+}
-/*
- * Given a endpoint, look and find in its association list any association
- * with the "to" address given. This can be a "from" address, too, for
- * inbound packets. For outbound packets it is a true "to" address.
- */
static struct sctp_tcb *
sctp_tcb_special_locate(struct sctp_inpcb **inp_p, struct sockaddr *from,
struct sockaddr *to, struct sctp_nets **netp, uint32_t vrf_id)
{
/**** ASSUMSES THE CALLER holds the INP_INFO_RLOCK */
-
- /*
- * Note for this module care must be taken when observing what to is
- * for. In most of the rest of the code the TO field represents my
- * peer and the FROM field represents my address. For this module it
- * is reversed of that.
- */
/*
* If we support the TCP model, then we must now dig through to see
* if we can find our endpoint in the list of tcp ep's.
@@ -468,14 +515,14 @@ sctp_tcb_special_locate(struct sctp_inpcb **inp_p, struct sockaddr *from,
* to this ep and return the tcb from it.
*/
LIST_FOREACH(inp, ephead, sctp_hash) {
- if (lport != inp->sctp_lport) {
- continue;
- }
SCTP_INP_RLOCK(inp);
if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) {
SCTP_INP_RUNLOCK(inp);
continue;
}
+ if (lport != inp->sctp_lport) {
+ continue;
+ }
if (inp->def_vrf_id != vrf_id) {
SCTP_INP_RUNLOCK(inp);
continue;
@@ -1224,7 +1271,7 @@ sctp_findassociation_special_addr(struct mbuf *m, int iphlen, int offset,
struct sctp_ipv4addr_param ip4_parm, *p4;
phdr = sctp_get_next_param(m, offset,
- (struct sctp_paramhdr *)&ip4_parm, plen);
+ (struct sctp_paramhdr *)&ip4_parm, min(plen, sizeof(ip4_parm)));
if (phdr == NULL) {
return (NULL);
}
@@ -1242,7 +1289,7 @@ sctp_findassociation_special_addr(struct mbuf *m, int iphlen, int offset,
struct sctp_ipv6addr_param ip6_parm, *p6;
phdr = sctp_get_next_param(m, offset,
- (struct sctp_paramhdr *)&ip6_parm, plen);
+ (struct sctp_paramhdr *)&ip6_parm, min(plen, sizeof(ip6_parm)));
if (phdr == NULL) {
return (NULL);
}
@@ -1291,8 +1338,7 @@ sctp_findassoc_by_vtag(struct sockaddr *from, uint32_t vtag,
SCTP_INP_RLOCK(stcb->sctp_ep);
if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) {
SCTP_INP_RUNLOCK(stcb->sctp_ep);
- SCTP_INP_INFO_RUNLOCK();
- return (NULL);
+ continue;
}
SCTP_TCB_LOCK(stcb);
SCTP_INP_RUNLOCK(stcb->sctp_ep);
@@ -1426,12 +1472,6 @@ sctp_findassociation_addr(struct mbuf *m, int iphlen, int offset,
sa6_embedscope(to6, ip6_use_defzone);
}
find_tcp_pool = 0;
- /*
- * FIX FIX?, I think we only need to look in the TCP pool if its an
- * INIT or COOKIE-ECHO, We really don't need to find it that way if
- * its a INIT-ACK or COOKIE_ACK since these in bot one-2-one and
- * one-2-N would be in the main pool anyway.
- */
if ((ch->chunk_type != SCTP_INITIATION) &&
(ch->chunk_type != SCTP_INITIATION_ACK) &&
(ch->chunk_type != SCTP_COOKIE_ACK) &&
@@ -1456,7 +1496,7 @@ sctp_findassociation_addr(struct mbuf *m, int iphlen, int offset,
/* Found a EP but not this address */
if ((ch->chunk_type == SCTP_INITIATION) ||
(ch->chunk_type == SCTP_INITIATION_ACK)) {
- /*
+ /*-
* special hook, we do NOT return linp or an
* association that is linked to an existing
* association that is under the TCP pool (i.e. no
@@ -3584,6 +3624,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
/* Now the read queue needs to be cleaned up (only once) */
cnt = 0;
if ((stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0) {
+ stcb->asoc.state |= SCTP_STATE_ABOUT_TO_BE_FREED;
SCTP_INP_READ_LOCK(inp);
TAILQ_FOREACH(sq, &inp->read_queue, next) {
if (sq->stcb == stcb) {
@@ -3627,7 +3668,6 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
stcb->block_entry = NULL;
}
}
- stcb->asoc.state |= SCTP_STATE_ABOUT_TO_BE_FREED;
if ((from_inpcbfree != SCTP_PCBFREE_FORCE) && (stcb->asoc.refcnt)) {
/*
* reader or writer in the way, we have hopefully given him
@@ -4687,6 +4727,10 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
}
p4 = (struct sctp_ipv4addr_param *)phdr;
sin.sin_addr.s_addr = p4->addr;
+ if (IN_MULTICAST(sin.sin_addr.s_addr)) {
+ /* Skip multi-cast addresses */
+ goto next_param;
+ }
sa = (struct sockaddr *)&sin;
inp = stcb->sctp_ep;
atomic_add_int(&stcb->asoc.refcnt, 1);
@@ -4749,6 +4793,17 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
p6 = (struct sctp_ipv6addr_param *)phdr;
memcpy((caddr_t)&sin6.sin6_addr, p6->addr,
sizeof(p6->addr));
+ if (IN6_IS_ADDR_MULTICAST(&sin6.sin6_addr)) {
+ /* Skip multi-cast addresses */
+ goto next_param;
+ }
+ if (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr)) {
+ /*
+ * Link local make no sense without
+ * scope
+ */
+ goto next_param;
+ }
sa = (struct sockaddr *)&sin6;
inp = stcb->sctp_ep;
atomic_add_int(&stcb->asoc.refcnt, 1);
@@ -4822,7 +4877,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
return (-23);
}
phdr = sctp_get_next_param(m, offset,
- (struct sctp_paramhdr *)&lstore, plen);
+ (struct sctp_paramhdr *)&lstore, min(plen, sizeof(lstore)));
if (phdr == NULL) {
return (-24);
}
@@ -4865,7 +4920,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
int num_ent, i;
phdr = sctp_get_next_param(m, offset,
- (struct sctp_paramhdr *)&local_store, plen);
+ (struct sctp_paramhdr *)&local_store, min(sizeof(local_store), plen));
if (phdr == NULL) {
return (-25);
}
@@ -4913,7 +4968,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
}
phdr = sctp_get_next_param(m, offset,
(struct sctp_paramhdr *)random_store,
- plen);
+ min(sizeof(random_store), plen));
if (phdr == NULL)
return (-26);
p_random = (struct sctp_auth_random *)phdr;
@@ -4939,7 +4994,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
}
phdr = sctp_get_next_param(m, offset,
(struct sctp_paramhdr *)hmacs_store,
- plen);
+ min(plen, sizeof(hmacs_store)));
if (phdr == NULL)
return (-28);
hmacs = (struct sctp_auth_hmac_algo *)phdr;
@@ -4970,7 +5025,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
}
phdr = sctp_get_next_param(m, offset,
(struct sctp_paramhdr *)chunks_store,
- plen);
+ min(plen, sizeof(chunks_store)));
if (phdr == NULL)
return (-30);
chunks = (struct sctp_auth_chunk_list *)phdr;
diff --git a/sys/netinet/sctp_pcb.h b/sys/netinet/sctp_pcb.h
index e8f1e12..85e5dc6 100644
--- a/sys/netinet/sctp_pcb.h
+++ b/sys/netinet/sctp_pcb.h
@@ -403,11 +403,11 @@ struct sctp_ifa *
sctp_add_addr_to_vrf(uint32_t vrfid,
void *ifn, uint32_t ifn_index, uint32_t ifn_type,
const char *if_name,
- void *ifa, struct sockaddr *addr, uint32_t ifa_flags);
+ void *ifa, struct sockaddr *addr, uint32_t ifa_flags, int dynamic_add);
void sctp_free_ifa(struct sctp_ifa *sctp_ifap);
-struct sctp_ifa *
+void
sctp_del_addr_from_vrf(uint32_t vrfid, struct sockaddr *addr,
uint32_t ifn_index);
diff --git a/sys/netinet/sctp_peeloff.c b/sys/netinet/sctp_peeloff.c
index 81f3924..35696fd 100644
--- a/sys/netinet/sctp_peeloff.c
+++ b/sys/netinet/sctp_peeloff.c
@@ -99,7 +99,7 @@ sctp_do_peeloff(struct socket *head, struct socket *so, sctp_assoc_t assoc_id)
*/
sctp_move_pcb_and_assoc(inp, n_inp, stcb);
- sctp_pull_off_control_to_new_inp(inp, n_inp, stcb);
+ sctp_pull_off_control_to_new_inp(inp, n_inp, stcb, M_WAITOK);
SCTP_TCB_UNLOCK(stcb);
return (0);
@@ -196,7 +196,7 @@ sctp_get_peeloff(struct socket *head, sctp_assoc_t assoc_id, int *error)
* And now the final hack. We move data in the pending side i.e.
* head to the new socket buffer. Let the GRUBBING begin :-0
*/
- sctp_pull_off_control_to_new_inp(inp, n_inp, stcb);
+ sctp_pull_off_control_to_new_inp(inp, n_inp, stcb, M_WAITOK);
SCTP_TCB_UNLOCK(stcb);
return (newso);
diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c
index b9797a2..8e558cb 100644
--- a/sys/netinet/sctp_usrreq.c
+++ b/sys/netinet/sctp_usrreq.c
@@ -3331,15 +3331,15 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
SCTP_CHECK_AND_CAST(sspp, optval, struct sctp_setpeerprim, optsize);
SCTP_FIND_STCB(inp, stcb, sspp->sspp_assoc_id);
-
- if (stcb) {
+ if (stcb != NULL) {
if (sctp_set_primary_ip_address_sa(stcb, (struct sockaddr *)&sspp->sspp_addr) != 0) {
error = EINVAL;
}
+ SCTP_TCB_UNLOCK(stcb);
} else {
error = EINVAL;
}
- SCTP_TCB_UNLOCK(stcb);
+
}
break;
case SCTP_BINDX_ADD_ADDR:
@@ -3651,6 +3651,7 @@ sctp_listen(struct socket *so, int backlog, struct thread *p)
error = solisten_proto_check(so);
if (error) {
SOCK_UNLOCK(so);
+ SCTP_INP_RUNLOCK(inp);
return (error);
}
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
@@ -3674,7 +3675,6 @@ sctp_listen(struct socket *so, int backlog, struct thread *p)
}
/* It appears for 7.0 and on, we must always call this. */
solisten_proto(so, backlog);
-
if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) {
/* remove the ACCEPTCONN flag for one-to-many sockets */
so->so_options &= ~SO_ACCEPTCONN;
diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c
index 66334b4..0d0c270 100644
--- a/sys/netinet/sctputil.c
+++ b/sys/netinet/sctputil.c
@@ -3846,7 +3846,8 @@ sctp_print_address_pkt(struct ip *iph, struct sctphdr *sh)
void
sctp_pull_off_control_to_new_inp(struct sctp_inpcb *old_inp,
struct sctp_inpcb *new_inp,
- struct sctp_tcb *stcb)
+ struct sctp_tcb *stcb,
+ int waitflags)
{
/*
* go through our old INP and pull off any control structures that
@@ -3861,11 +3862,8 @@ sctp_pull_off_control_to_new_inp(struct sctp_inpcb *old_inp,
old_so = old_inp->sctp_socket;
new_so = new_inp->sctp_socket;
TAILQ_INIT(&tmp_queue);
-
SOCKBUF_LOCK(&(old_so->so_rcv));
-
- error = sblock(&old_so->so_rcv, 0);
-
+ error = sblock(&old_so->so_rcv, waitflags);
SOCKBUF_UNLOCK(&(old_so->so_rcv));
if (error) {
/*
@@ -3904,13 +3902,11 @@ sctp_pull_off_control_to_new_inp(struct sctp_inpcb *old_inp,
control = nctl;
}
SCTP_INP_READ_UNLOCK(old_inp);
-
/* Remove the sb-lock on the old socket */
SOCKBUF_LOCK(&(old_so->so_rcv));
sbunlock(&old_so->so_rcv);
SOCKBUF_UNLOCK(&(old_so->so_rcv));
-
/* Now we move them over to the new socket buffer */
control = TAILQ_FIRST(&tmp_queue);
SCTP_INP_READ_LOCK(new_inp);
@@ -4298,43 +4294,6 @@ sctp_find_ifa_in_ep(struct sctp_inpcb *inp, struct sockaddr *addr, int holds_loc
return (NULL);
}
-struct sctp_ifa *
-sctp_find_ifa_in_ifn(struct sctp_ifn *sctp_ifnp, struct sockaddr *addr,
- int holds_lock)
-{
- struct sctp_ifa *sctp_ifap;
-
- if (holds_lock == 0)
- SCTP_IPI_ADDR_LOCK();
-
- LIST_FOREACH(sctp_ifap, &sctp_ifnp->ifalist, next_ifa) {
- if (addr->sa_family != sctp_ifap->address.sa.sa_family)
- continue;
- if (addr->sa_family == AF_INET) {
- if (((struct sockaddr_in *)addr)->sin_addr.s_addr ==
- sctp_ifap->address.sin.sin_addr.s_addr) {
- /* found him. */
- if (holds_lock == 0)
- SCTP_IPI_ADDR_UNLOCK();
- return (sctp_ifap);
- break;
- }
- } else if (addr->sa_family == AF_INET6) {
- if (SCTP6_ARE_ADDR_EQUAL(&((struct sockaddr_in6 *)addr)->sin6_addr,
- &sctp_ifap->address.sin6.sin6_addr)) {
- /* found him. */
- if (holds_lock == 0)
- SCTP_IPI_ADDR_UNLOCK();
- return (sctp_ifap);
- break;
- }
- }
- }
- if (holds_lock == 0)
- SCTP_IPI_ADDR_UNLOCK();
- return (NULL);
-}
-
uint32_t
sctp_get_ifa_hash_val(struct sockaddr *addr)
{
@@ -4741,6 +4700,10 @@ restart_nosblocks:
}
goto out;
}
+ if (hold_sblock == 1) {
+ SOCKBUF_UNLOCK(&so->so_rcv);
+ hold_sblock = 0;
+ }
error = sblock(&so->so_rcv, (block_allowed ? M_WAITOK : 0));
/* we possibly have data we can read */
control = TAILQ_FIRST(&inp->read_queue);
@@ -4862,9 +4825,6 @@ 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[control->sinfo_stream].delivery_started = 1;
- }
control->some_taken = 1;
if (hold_sblock) {
SOCKBUF_UNLOCK(&so->so_rcv);
@@ -4901,6 +4861,9 @@ found_one:
stcb->freed_by_sorcv_sincelast = 0;
}
}
+ if (stcb && control->do_not_ref_stcb == 0) {
+ stcb->asoc.strmin[control->sinfo_stream].delivery_started = 1;
+ }
/* First lets get off the sinfo and sockaddr info */
if ((sinfo) && filling_sinfo) {
memcpy(sinfo, control, sizeof(struct sctp_nonpad_sndrcvinfo));
diff --git a/sys/netinet/sctputil.h b/sys/netinet/sctputil.h
index e0ae668..3b4acf6 100644
--- a/sys/netinet/sctputil.h
+++ b/sys/netinet/sctputil.h
@@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$");
* Any new logging added must also define SCTP_STAT_LOGGING if
* its not already defined.
*/
+
#if defined(SCTP_LOG_MAXBURST) || defined(SCTP_LOG_RWND) || defined(SCTP_LOG_RWND)
#ifndef SCTP_STAT_LOGGING
#define SCTP_STAT_LOGGING 1
@@ -86,6 +87,13 @@ __FBSDID("$FreeBSD$");
#endif
#endif
+#if defined(SCTP_LOG_SACK_ARRIVALS)
+#ifndef SCTP_STAT_LOGGING
+#define SCTP_STAT_LOGGING 1
+#endif
+#endif
+
+
#ifdef SCTP_ASOCLOG_OF_TSNS
void sctp_print_out_track_log(struct sctp_tcb *stcb);
@@ -112,9 +120,6 @@ sctp_get_ifa_hash_val(struct sockaddr *addr);
struct sctp_ifa *
sctp_find_ifa_in_ep(struct sctp_inpcb *inp, struct sockaddr *addr, int hold_lock);
-struct sctp_ifa *
-sctp_find_ifa_in_ifn(struct sctp_ifn *sctp_ifnp, struct sockaddr *addr,
- int holds_lock);
struct sctp_ifa *
sctp_find_ifa_by_addr(struct sockaddr *addr, uint32_t vrf_id, int holds_lock);
@@ -188,7 +193,7 @@ void sctp_ulp_notify(uint32_t, struct sctp_tcb *, uint32_t, void *);
void
sctp_pull_off_control_to_new_inp(struct sctp_inpcb *old_inp,
struct sctp_inpcb *new_inp,
- struct sctp_tcb *stcb);
+ struct sctp_tcb *stcb, int waitflags);
void sctp_stop_timers_for_shutdown(struct sctp_tcb *);
diff --git a/sys/netinet6/sctp6_usrreq.c b/sys/netinet6/sctp6_usrreq.c
index eddc0ae..07cd299 100644
--- a/sys/netinet6/sctp6_usrreq.c
+++ b/sys/netinet6/sctp6_usrreq.c
@@ -240,6 +240,8 @@ bad:
}
if (m)
m_freem(m);
+ /* For BSD/MAC this does nothing */
+ SCTP_RELEASE_PAK(*i_pak);
return IPPROTO_DONE;
}
OpenPOWER on IntegriCloud