- fixed autclose to not allow setting on 1-2-1 model.
- bounded cookie-life to 1 second minimum in socket option set. - Delayed_ack_time becomes delayed_ack per new socket api document. - Improve port number selection, we now use low/high bounds and no chance of a endless loop. Only one call to random per bind as well. - fixes so set_peer_primary pre-screens addresses to be valid to this host. - maxseg did not allow setting on an assoc basis. We needed to thus track and use an association value instead of a inp value. - Fixed ep get of HB status to report back properly. - use settings flag to tell if assoc level hb is on off not the timer.. since the timer may still run if unconf address are present. - check for crazy ENABLE/DISABLE conditions. - set and get of pmtud (fixed path mtu) not always taking into account ovh. - Getting PMTU info on stcb only needs to return PMTUD_ENABLED if any net is doing PMTU discovery. - Panic or warning fixed to not do so when a valid ip frag is taking place. - sndrcvinfo appearing in both inp and stcb was full size, instead of the non-pad version. This saves about 92 bytes from each struct by carefully converting to use the smaller version. - one-2-one model get(maxseg) would always get ep value, never the tcb's value. - The delayed ack time could be under a tick, this fixes so it bounds it to at least 1 tick for platforms whos tick is more than a ms. - Fragment interleave level set to wrong default value. - Fragment interleave could not set level 0. - Defered stream reset was broken due to a guard check and ntohl issue. - Found two lock order reversals and fixed. - Tighten up address checking, if the user gives an address the sa_len had better be set properly. - Get asoc by assoc-id would return a locked tcb when it was asked not to if the tcb was in the restart hash. - sysctl to dig down and get more association details Reviewed by: gnn
This commit is contained in:
parent
b4b7eeb094
commit
953518c197
@ -91,7 +91,7 @@ struct sctp_paramhdr {
|
||||
/* Without this applied we will give V4 and V6 addresses on a V6 socket */
|
||||
#define SCTP_I_WANT_MAPPED_V4_ADDR 0x0000000d
|
||||
#define SCTP_MAXSEG 0x0000000e
|
||||
#define SCTP_DELAYED_ACK_TIME 0x0000000f
|
||||
#define SCTP_DELAYED_SACK 0x0000000f
|
||||
#define SCTP_FRAGMENT_INTERLEAVE 0x00000010
|
||||
#define SCTP_PARTIAL_DELIVERY_POINT 0x00000011
|
||||
/* authentication support */
|
||||
@ -103,6 +103,7 @@ struct sctp_paramhdr {
|
||||
#define SCTP_USE_EXT_RCVINFO 0x00000017
|
||||
#define SCTP_AUTO_ASCONF 0x00000018 /* rw */
|
||||
#define SCTP_MAXBURST 0x00000019 /* rw */
|
||||
#define SCTP_MAX_BURST 0x00000019 /* rw */
|
||||
/* assoc level context */
|
||||
#define SCTP_CONTEXT 0x0000001a /* rw */
|
||||
/* explict EOR signalling */
|
||||
@ -447,6 +448,9 @@ struct sctp_error_unrecognized_chunk {
|
||||
#define SCTP_PCB_FLAGS_NO_FRAGMENT 0x00100000
|
||||
#define SCTP_PCB_FLAGS_EXPLICIT_EOR 0x00400000
|
||||
|
||||
#define SCTP_SMALLEST_PMTU 512 /* smallest pmtu allowed when disabling PMTU
|
||||
* discovery */
|
||||
|
||||
#include <netinet/sctp_uio.h>
|
||||
|
||||
#endif /* !_NETINET_SCTP_H_ */
|
||||
|
@ -629,6 +629,8 @@ sctp_free_hmaclist(sctp_hmaclist_t * list)
|
||||
int
|
||||
sctp_auth_add_hmacid(sctp_hmaclist_t * list, uint16_t hmac_id)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (list == NULL)
|
||||
return (-1);
|
||||
if (list->num_algo == list->max_algo) {
|
||||
@ -648,6 +650,13 @@ sctp_auth_add_hmacid(sctp_hmaclist_t * list, uint16_t hmac_id)
|
||||
(hmac_id != SCTP_AUTH_HMAC_ID_MD5)) {
|
||||
return (-1);
|
||||
}
|
||||
/* Now is it already in the list */
|
||||
for (i = 0; i < list->num_algo; i++) {
|
||||
if (list->hmac[i] == hmac_id) {
|
||||
/* already in list */
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
SCTPDBG(SCTP_DEBUG_AUTH1, "SCTP: add HMAC id %u to list\n", hmac_id);
|
||||
list->hmac[list->num_algo++] = hmac_id;
|
||||
return (0);
|
||||
@ -1338,7 +1347,11 @@ sctp_auth_setactivekey(struct sctp_tcb *stcb, uint16_t keyid)
|
||||
skey = sctp_find_sharedkey(&stcb->asoc.shared_keys, keyid);
|
||||
if (skey == NULL) {
|
||||
/* if not on the assoc, find the key on the endpoint */
|
||||
atomic_add_int(&stcb->asoc.refcnt, 1);
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
SCTP_INP_RLOCK(stcb->sctp_ep);
|
||||
SCTP_TCB_LOCK(stcb);
|
||||
atomic_add_int(&stcb->asoc.refcnt, -1);
|
||||
skey = sctp_find_sharedkey(&stcb->sctp_ep->sctp_ep.shared_keys,
|
||||
keyid);
|
||||
using_ep_key = 1;
|
||||
|
@ -60,6 +60,8 @@ __FBSDID("$FreeBSD$");
|
||||
/* Number of addresses where we just skip the counting */
|
||||
#define SCTP_COUNT_LIMIT 40
|
||||
|
||||
#define SCTP_ZERO_COPY_TICK_DELAY (((100 * hz) + 999) / 1000)
|
||||
|
||||
/* Number of ticks to delay before running
|
||||
* iterator on an address change.
|
||||
*/
|
||||
@ -542,8 +544,9 @@ __FBSDID("$FreeBSD$");
|
||||
#define SCTP_TIMER_TYPE_EARLYFR 17
|
||||
#define SCTP_TIMER_TYPE_ASOCKILL 18
|
||||
#define SCTP_TIMER_TYPE_ADDR_WQ 19
|
||||
#define SCTP_TIMER_TYPE_ZERO_COPY 20
|
||||
/* add new timers here - and increment LAST */
|
||||
#define SCTP_TIMER_TYPE_LAST 20
|
||||
#define SCTP_TIMER_TYPE_LAST 21
|
||||
|
||||
#define SCTP_IS_TIMER_TYPE_VALID(t) (((t) > SCTP_TIMER_TYPE_NONE) && \
|
||||
((t) < SCTP_TIMER_TYPE_LAST))
|
||||
@ -654,11 +657,12 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#define SCTP_DEF_MAX_INIT 8
|
||||
#define SCTP_DEF_MAX_SEND 10
|
||||
#define SCTP_DEF_MAX_PATH_RTX 4
|
||||
#define SCTP_DEF_MAX_PATH_RTX 5
|
||||
|
||||
#define SCTP_DEF_PMTU_RAISE_SEC 600 /* 10 min between raise attempts */
|
||||
#define SCTP_DEF_PMTU_MIN 600
|
||||
|
||||
|
||||
#define SCTP_MSEC_IN_A_SEC 1000
|
||||
#define SCTP_USEC_IN_A_SEC 1000000
|
||||
#define SCTP_NSEC_IN_A_SEC 1000000000
|
||||
@ -810,6 +814,7 @@ __FBSDID("$FreeBSD$");
|
||||
#define SCTP_FROM_SCTP_ASCONF 0x80000000
|
||||
#define SCTP_FROM_SCTP_OUTPUT 0x90000000
|
||||
#define SCTP_FROM_SCTP_PEELOFF 0xa0000000
|
||||
#define SCTP_FROM_SCTP_PANDA 0xb0000000
|
||||
|
||||
/* Location ID's */
|
||||
#define SCTP_LOC_1 0x00000001
|
||||
|
@ -1609,7 +1609,6 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
|
||||
* only validate the FIRST fragment so the bit must be set.
|
||||
*/
|
||||
strmseq = ntohs(ch->dp.stream_sequence);
|
||||
|
||||
#ifdef SCTP_ASOCLOG_OF_TSNS
|
||||
asoc->in_tsnlog[asoc->tsn_in_at].tsn = tsn;
|
||||
asoc->in_tsnlog[asoc->tsn_in_at].strm = strmno;
|
||||
@ -1623,6 +1622,7 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
|
||||
}
|
||||
#endif
|
||||
if ((chunk_flags & SCTP_DATA_FIRST_FRAG) &&
|
||||
(TAILQ_EMPTY(&asoc->resetHead)) &&
|
||||
(chunk_flags & SCTP_DATA_UNORDERED) == 0 &&
|
||||
(compare_with_wrap(asoc->strmin[strmno].last_sequence_delivered,
|
||||
strmseq, MAX_SEQ) ||
|
||||
@ -2006,11 +2006,8 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
|
||||
* and proceessed by TSN order. It is only the
|
||||
* singletons I must worry about.
|
||||
*/
|
||||
struct sctp_stream_reset_list *liste;
|
||||
|
||||
if (((liste = TAILQ_FIRST(&asoc->resetHead)) != NULL) &&
|
||||
((compare_with_wrap(tsn, ntohl(liste->tsn), MAX_TSN)) ||
|
||||
(tsn == ntohl(liste->tsn)))
|
||||
((compare_with_wrap(tsn, liste->tsn, MAX_TSN)))
|
||||
) {
|
||||
/*
|
||||
* yep its past where we need to reset... go
|
||||
@ -2095,8 +2092,8 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
|
||||
SCTP_SET_TSN_PRESENT(asoc->mapping_array, gap);
|
||||
/* check the special flag for stream resets */
|
||||
if (((liste = TAILQ_FIRST(&asoc->resetHead)) != NULL) &&
|
||||
((compare_with_wrap(asoc->cumulative_tsn, ntohl(liste->tsn), MAX_TSN)) ||
|
||||
(asoc->cumulative_tsn == ntohl(liste->tsn)))
|
||||
((compare_with_wrap(asoc->cumulative_tsn, liste->tsn, MAX_TSN)) ||
|
||||
(asoc->cumulative_tsn == liste->tsn))
|
||||
) {
|
||||
/*
|
||||
* we have finished working through the backlogged TSN's now
|
||||
@ -2124,7 +2121,7 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
|
||||
}
|
||||
} else if (ctl) {
|
||||
/* more than one in queue */
|
||||
while (!compare_with_wrap(ctl->sinfo_tsn, ntohl(liste->tsn), MAX_TSN)) {
|
||||
while (!compare_with_wrap(ctl->sinfo_tsn, liste->tsn, MAX_TSN)) {
|
||||
/*
|
||||
* if ctl->sinfo_tsn is <= liste->tsn we can
|
||||
* process it which is the NOT of
|
||||
@ -2668,12 +2665,12 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length,
|
||||
/* unknown chunk type, use bit rules */
|
||||
if (ch->ch.chunk_type & 0x40) {
|
||||
/* Add a error report to the queue */
|
||||
struct mbuf *mm;
|
||||
struct mbuf *merr;
|
||||
struct sctp_paramhdr *phd;
|
||||
|
||||
mm = sctp_get_mbuf_for_msg(sizeof(*phd), 0, M_DONTWAIT, 1, MT_DATA);
|
||||
if (mm) {
|
||||
phd = mtod(mm, struct sctp_paramhdr *);
|
||||
merr = sctp_get_mbuf_for_msg(sizeof(*phd), 0, M_DONTWAIT, 1, MT_DATA);
|
||||
if (merr) {
|
||||
phd = mtod(merr, struct sctp_paramhdr *);
|
||||
/*
|
||||
* We cheat and use param
|
||||
* type since we did not
|
||||
@ -2686,14 +2683,14 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length,
|
||||
htons(SCTP_CAUSE_UNRECOG_CHUNK);
|
||||
phd->param_length =
|
||||
htons(chk_length + sizeof(*phd));
|
||||
SCTP_BUF_LEN(mm) = sizeof(*phd);
|
||||
SCTP_BUF_NEXT(mm) = SCTP_M_COPYM(m, *offset,
|
||||
SCTP_BUF_LEN(merr) = sizeof(*phd);
|
||||
SCTP_BUF_NEXT(merr) = SCTP_M_COPYM(m, *offset,
|
||||
SCTP_SIZE32(chk_length),
|
||||
M_DONTWAIT);
|
||||
if (SCTP_BUF_NEXT(mm)) {
|
||||
sctp_queue_op_err(stcb, mm);
|
||||
if (SCTP_BUF_NEXT(merr)) {
|
||||
sctp_queue_op_err(stcb, merr);
|
||||
} else {
|
||||
sctp_m_freem(mm);
|
||||
sctp_m_freem(merr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -5893,7 +5890,7 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb,
|
||||
fwd_sz -= sizeof(*fwd);
|
||||
{
|
||||
/* New method. */
|
||||
int num_str, i;
|
||||
unsigned int num_str;
|
||||
|
||||
num_str = fwd_sz / sizeof(struct sctp_strseq);
|
||||
for (i = 0; i < num_str; i++) {
|
||||
|
@ -322,23 +322,8 @@ sctp_process_init_ack(struct mbuf *m, int iphlen, int offset,
|
||||
&abort_flag, (struct sctp_chunkhdr *)cp);
|
||||
if (abort_flag) {
|
||||
/* Send an abort and notify peer */
|
||||
if (op_err != NULL) {
|
||||
sctp_send_operr_to(m, iphlen, op_err,
|
||||
cp->init.initiate_tag, vrf_id,
|
||||
table_id);
|
||||
} else {
|
||||
/*
|
||||
* Just notify (abort_assoc does this if we send an
|
||||
* abort).
|
||||
*/
|
||||
sctp_abort_notification(stcb, 0);
|
||||
/*
|
||||
* No sense in further INIT's since we will get the
|
||||
* same param back
|
||||
*/
|
||||
sctp_free_assoc(stcb->sctp_ep, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_3);
|
||||
*abort_no_unlock = 1;
|
||||
}
|
||||
sctp_abort_an_association(stcb->sctp_ep, stcb, SCTP_CAUSE_PROTOCOL_VIOLATION, op_err);
|
||||
*abort_no_unlock = 1;
|
||||
return (-1);
|
||||
}
|
||||
asoc = &stcb->asoc;
|
||||
@ -393,8 +378,6 @@ sctp_process_init_ack(struct mbuf *m, int iphlen, int offset,
|
||||
*/
|
||||
if (retval == -3) {
|
||||
/* We abort with an error of missing mandatory param */
|
||||
struct mbuf *op_err;
|
||||
|
||||
op_err =
|
||||
sctp_generate_invmanparam(SCTP_CAUSE_MISSING_PARAM);
|
||||
if (op_err) {
|
||||
@ -570,6 +553,7 @@ sctp_handle_shutdown(struct sctp_shutdown_chunk *cp,
|
||||
/* goto SHUTDOWN_RECEIVED state to block new requests */
|
||||
if (stcb->sctp_socket) {
|
||||
if ((SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_RECEIVED) &&
|
||||
(SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_ACK_SENT) &&
|
||||
(SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT)) {
|
||||
asoc->state = SCTP_STATE_SHUTDOWN_RECEIVED;
|
||||
/*
|
||||
@ -2160,7 +2144,14 @@ 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);
|
||||
|
||||
atomic_add_int(&(*stcb)->asoc.refcnt, 1);
|
||||
SCTP_TCB_UNLOCK((*stcb));
|
||||
|
||||
sctp_pull_off_control_to_new_inp((*inp_p), inp, *stcb, M_NOWAIT);
|
||||
SCTP_TCB_LOCK((*stcb));
|
||||
atomic_subtract_int(&(*stcb)->asoc.refcnt, 1);
|
||||
|
||||
|
||||
/*
|
||||
* now we must check to see if we were aborted while
|
||||
@ -3472,6 +3463,8 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
|
||||
|
||||
/* validate chunk header length... */
|
||||
if (ntohs(ch->chunk_length) < sizeof(*ch)) {
|
||||
SCTPDBG(SCTP_DEBUG_INPUT1, "Invalid header length %d\n",
|
||||
ntohs(ch->chunk_length));
|
||||
return (NULL);
|
||||
}
|
||||
/*
|
||||
@ -3483,6 +3476,8 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
|
||||
SCTP_TCB_LOCK_ASSERT(locked_tcb);
|
||||
}
|
||||
if (ch->chunk_type == SCTP_INITIATION) {
|
||||
SCTPDBG(SCTP_DEBUG_INPUT1, "Its an INIT of len:%d vtag:%x\n",
|
||||
ntohs(ch->chunk_length), vtag_in);
|
||||
if (vtag_in != 0) {
|
||||
/* protocol error- silently discard... */
|
||||
SCTP_STAT_INCR(sctps_badvtag);
|
||||
@ -4707,6 +4702,7 @@ sctp_input(i_pak, off)
|
||||
mlen = SCTP_HEADER_LEN(i_pak);
|
||||
iphlen = off;
|
||||
m = SCTP_HEADER_TO_CHAIN(i_pak);
|
||||
|
||||
net = NULL;
|
||||
SCTP_STAT_INCR(sctps_recvpackets);
|
||||
SCTP_STAT_INCR_COUNTER64(sctps_inpackets);
|
||||
|
@ -4047,13 +4047,14 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt,
|
||||
limit = ntohs(cp->chunk_length) - sizeof(struct sctp_init_chunk);
|
||||
at = param_offset;
|
||||
op_err = NULL;
|
||||
|
||||
SCTPDBG(SCTP_DEBUG_OUTPUT1, "Check for unrecognized param's\n");
|
||||
phdr = sctp_get_next_param(mat, at, ¶ms, sizeof(params));
|
||||
while ((phdr != NULL) && ((size_t)limit >= sizeof(struct sctp_paramhdr))) {
|
||||
ptype = ntohs(phdr->param_type);
|
||||
plen = ntohs(phdr->param_length);
|
||||
if ((plen > limit) || (plen < sizeof(struct sctp_paramhdr))) {
|
||||
/* wacked parameter */
|
||||
SCTPDBG(SCTP_DEBUG_OUTPUT1, "Invalid size - error %d\n", plen);
|
||||
goto invalid_size;
|
||||
}
|
||||
limit -= SCTP_SIZE32(plen);
|
||||
@ -4078,18 +4079,21 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt,
|
||||
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))) {
|
||||
SCTPDBG(SCTP_DEBUG_OUTPUT1, "Invalid size - error chklist %d\n", plen);
|
||||
goto invalid_size;
|
||||
}
|
||||
at += padded_size;
|
||||
break;
|
||||
case SCTP_SUPPORTED_ADDRTYPE:
|
||||
if (padded_size > SCTP_MAX_ADDR_PARAMS_SIZE) {
|
||||
SCTPDBG(SCTP_DEBUG_OUTPUT1, "Invalid size - error supaddrtype %d\n", plen);
|
||||
goto invalid_size;
|
||||
}
|
||||
at += padded_size;
|
||||
break;
|
||||
case SCTP_RANDOM:
|
||||
if (padded_size > (sizeof(struct sctp_auth_random) + SCTP_RANDOM_MAX_SIZE)) {
|
||||
SCTPDBG(SCTP_DEBUG_OUTPUT1, "Invalid size - error random %d\n", plen);
|
||||
goto invalid_size;
|
||||
}
|
||||
at += padded_size;
|
||||
@ -4099,6 +4103,7 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt,
|
||||
case SCTP_ADD_IP_ADDRESS:
|
||||
if ((padded_size != sizeof(struct sctp_asconf_addrv4_param)) &&
|
||||
(padded_size != sizeof(struct sctp_asconf_addr_param))) {
|
||||
SCTPDBG(SCTP_DEBUG_OUTPUT1, "Invalid size - error setprim %d\n", plen);
|
||||
goto invalid_size;
|
||||
}
|
||||
at += padded_size;
|
||||
@ -4106,18 +4111,21 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt,
|
||||
/* Param's with a fixed size */
|
||||
case SCTP_IPV4_ADDRESS:
|
||||
if (padded_size != sizeof(struct sctp_ipv4addr_param)) {
|
||||
SCTPDBG(SCTP_DEBUG_OUTPUT1, "Invalid size - error ipv4 addr %d\n", plen);
|
||||
goto invalid_size;
|
||||
}
|
||||
at += padded_size;
|
||||
break;
|
||||
case SCTP_IPV6_ADDRESS:
|
||||
if (padded_size != sizeof(struct sctp_ipv6addr_param)) {
|
||||
SCTPDBG(SCTP_DEBUG_OUTPUT1, "Invalid size - error ipv6 addr %d\n", plen);
|
||||
goto invalid_size;
|
||||
}
|
||||
at += padded_size;
|
||||
break;
|
||||
case SCTP_COOKIE_PRESERVE:
|
||||
if (padded_size != sizeof(struct sctp_cookie_perserve_param)) {
|
||||
SCTPDBG(SCTP_DEBUG_OUTPUT1, "Invalid size - error cookie-preserve %d\n", plen);
|
||||
goto invalid_size;
|
||||
}
|
||||
at += padded_size;
|
||||
@ -4125,24 +4133,28 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt,
|
||||
case SCTP_ECN_NONCE_SUPPORTED:
|
||||
case SCTP_PRSCTP_SUPPORTED:
|
||||
if (padded_size != sizeof(struct sctp_paramhdr)) {
|
||||
SCTPDBG(SCTP_DEBUG_OUTPUT1, "Invalid size - error ecnnonce/prsctp %d\n", plen);
|
||||
goto invalid_size;
|
||||
}
|
||||
at += padded_size;
|
||||
break;
|
||||
case SCTP_ECN_CAPABLE:
|
||||
if (padded_size != sizeof(struct sctp_ecn_supported_param)) {
|
||||
SCTPDBG(SCTP_DEBUG_OUTPUT1, "Invalid size - error ecn %d\n", plen);
|
||||
goto invalid_size;
|
||||
}
|
||||
at += padded_size;
|
||||
break;
|
||||
case SCTP_ULP_ADAPTATION:
|
||||
if (padded_size != sizeof(struct sctp_adaptation_layer_indication)) {
|
||||
SCTPDBG(SCTP_DEBUG_OUTPUT1, "Invalid size - error adapatation %d\n", plen);
|
||||
goto invalid_size;
|
||||
}
|
||||
at += padded_size;
|
||||
break;
|
||||
case SCTP_SUCCESS_REPORT:
|
||||
if (padded_size != sizeof(struct sctp_asconf_paramhdr)) {
|
||||
SCTPDBG(SCTP_DEBUG_OUTPUT1, "Invalid size - error success %d\n", plen);
|
||||
goto invalid_size;
|
||||
}
|
||||
at += padded_size;
|
||||
@ -4152,7 +4164,7 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt,
|
||||
/* We can NOT handle HOST NAME addresses!! */
|
||||
int l_len;
|
||||
|
||||
SCTPDBG(SCTP_DEBUG_OUTPUT4, "Can't handle hostname addresses.. abort processing\n");
|
||||
SCTPDBG(SCTP_DEBUG_OUTPUT1, "Can't handle hostname addresses.. abort processing\n");
|
||||
*abort_processing = 1;
|
||||
if (op_err == NULL) {
|
||||
/* Ok need to try to get a mbuf */
|
||||
@ -4210,8 +4222,10 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt,
|
||||
* we do not recognize the parameter figure out what
|
||||
* we do.
|
||||
*/
|
||||
SCTPDBG(SCTP_DEBUG_OUTPUT1, "Hit default param %x\n", ptype);
|
||||
if ((ptype & 0x4000) == 0x4000) {
|
||||
/* Report bit is set?? */
|
||||
SCTPDBG(SCTP_DEBUG_OUTPUT1, "report op err\n");
|
||||
if (op_err == NULL) {
|
||||
int l_len;
|
||||
|
||||
@ -4264,9 +4278,11 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt,
|
||||
}
|
||||
more_processing:
|
||||
if ((ptype & 0x8000) == 0x0000) {
|
||||
SCTPDBG(SCTP_DEBUG_OUTPUT1, "stop proc\n");
|
||||
return (op_err);
|
||||
} else {
|
||||
/* skip this chunk and continue processing */
|
||||
SCTPDBG(SCTP_DEBUG_OUTPUT1, "move on\n");
|
||||
at += SCTP_SIZE32(plen);
|
||||
}
|
||||
break;
|
||||
@ -4276,6 +4292,7 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt,
|
||||
}
|
||||
return (op_err);
|
||||
invalid_size:
|
||||
SCTPDBG(SCTP_DEBUG_OUTPUT1, "abort flag set\n");
|
||||
*abort_processing = 1;
|
||||
if ((op_err == NULL) && phdr) {
|
||||
int l_len;
|
||||
@ -5229,10 +5246,10 @@ sctp_get_frag_point(struct sctp_tcb *stcb,
|
||||
ovh = SCTP_MED_V4_OVERHEAD;
|
||||
}
|
||||
|
||||
if (stcb->sctp_ep->sctp_frag_point > asoc->smallest_mtu)
|
||||
if (stcb->asoc.sctp_frag_point > asoc->smallest_mtu)
|
||||
siz = asoc->smallest_mtu - ovh;
|
||||
else
|
||||
siz = (stcb->sctp_ep->sctp_frag_point - ovh);
|
||||
siz = (stcb->asoc.sctp_frag_point - ovh);
|
||||
/*
|
||||
* if (siz > (MCLBYTES-sizeof(struct sctp_data_chunk))) {
|
||||
*/
|
||||
@ -5824,7 +5841,7 @@ sctp_sendall(struct sctp_inpcb *inp, struct uio *uio, struct mbuf *m,
|
||||
memset(ca, 0, sizeof(struct sctp_copy_all));
|
||||
|
||||
ca->inp = inp;
|
||||
ca->sndrcv = *srcv;
|
||||
memcpy(&ca->sndrcv, srcv, sizeof(struct sctp_nonpad_sndrcvinfo));
|
||||
/*
|
||||
* take off the sendall flag, it would be bad if we failed to do
|
||||
* this :-0
|
||||
@ -7250,7 +7267,7 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
|
||||
r_mtu = 0;
|
||||
|
||||
to_out += chk->send_size;
|
||||
if (to_out > mx_mtu) {
|
||||
if ((to_out > mx_mtu) && no_fragmentflg) {
|
||||
#ifdef INVARIANTS
|
||||
panic("Exceeding mtu of %d out size is %d", mx_mtu, to_out);
|
||||
#else
|
||||
@ -10588,7 +10605,21 @@ sctp_lower_sosend(struct socket *so,
|
||||
sndlen = SCTP_HEADER_LEN(i_pak);
|
||||
top = SCTP_HEADER_TO_CHAIN(i_pak);
|
||||
}
|
||||
|
||||
/*
|
||||
* Pre-screen address, if one is given the sin-len must be set
|
||||
* correctly!
|
||||
*/
|
||||
if (addr) {
|
||||
if ((addr->sa_family == AF_INET) &&
|
||||
(addr->sa_len != sizeof(struct sockaddr_in))) {
|
||||
error = EINVAL;
|
||||
goto out_unlocked;
|
||||
} else if ((addr->sa_family == AF_INET6) &&
|
||||
(addr->sa_len != sizeof(struct sockaddr_in6))) {
|
||||
error = EINVAL;
|
||||
goto out_unlocked;
|
||||
}
|
||||
}
|
||||
hold_tcblock = 0;
|
||||
|
||||
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
|
||||
@ -10598,7 +10629,8 @@ sctp_lower_sosend(struct socket *so,
|
||||
goto out_unlocked;
|
||||
}
|
||||
if ((use_rcvinfo) && srcv) {
|
||||
if (INVALID_SINFO_FLAG(srcv->sinfo_flags) || PR_SCTP_INVALID_POLICY(srcv->sinfo_flags)) {
|
||||
if (INVALID_SINFO_FLAG(srcv->sinfo_flags) ||
|
||||
PR_SCTP_INVALID_POLICY(srcv->sinfo_flags)) {
|
||||
error = EINVAL;
|
||||
goto out_unlocked;
|
||||
}
|
||||
@ -10769,7 +10801,6 @@ sctp_lower_sosend(struct socket *so,
|
||||
goto out_unlocked;
|
||||
}
|
||||
/* get an asoc/stcb struct */
|
||||
|
||||
vrf_id = inp->def_vrf_id;
|
||||
stcb = sctp_aloc_assoc(inp, addr, 1, &error, 0, vrf_id);
|
||||
if (stcb == NULL) {
|
||||
@ -10936,7 +10967,7 @@ sctp_lower_sosend(struct socket *so,
|
||||
}
|
||||
if ((use_rcvinfo == 0) || (srcv == NULL)) {
|
||||
/* Grab the default stuff from the asoc */
|
||||
srcv = &stcb->asoc.def_send;
|
||||
srcv = (struct sctp_sndrcvinfo *)&stcb->asoc.def_send;
|
||||
}
|
||||
/* we are now done with all control */
|
||||
if (control) {
|
||||
|
@ -452,6 +452,7 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index,
|
||||
}
|
||||
SCTP_INCR_LADDR_COUNT();
|
||||
bzero(wi, sizeof(*wi));
|
||||
(void)SCTP_GETTIME_TIMEVAL(&wi->start_time);
|
||||
wi->ifa = sctp_ifap;
|
||||
wi->action = SCTP_ADD_IP_ADDRESS;
|
||||
SCTP_IPI_ITERATOR_WQ_LOCK();
|
||||
@ -529,6 +530,7 @@ sctp_del_addr_from_vrf(uint32_t vrf_id, struct sockaddr *addr,
|
||||
}
|
||||
SCTP_INCR_LADDR_COUNT();
|
||||
bzero(wi, sizeof(*wi));
|
||||
(void)SCTP_GETTIME_TIMEVAL(&wi->start_time);
|
||||
wi->ifa = sctp_ifap;
|
||||
wi->action = SCTP_DEL_IP_ADDRESS;
|
||||
SCTP_IPI_ITERATOR_WQ_LOCK();
|
||||
@ -994,25 +996,32 @@ sctp_findassociation_ep_asocid(struct sctp_inpcb *inp, sctp_assoc_t asoc_id, int
|
||||
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;
|
||||
}
|
||||
if (want_lock) {
|
||||
SCTP_TCB_LOCK(stcb);
|
||||
}
|
||||
SCTP_TCB_LOCK(stcb);
|
||||
SCTP_INP_RUNLOCK(stcb->sctp_ep);
|
||||
if (stcb->asoc.assoc_id == id) {
|
||||
/* candidate */
|
||||
SCTP_INP_RUNLOCK(stcb->sctp_ep);
|
||||
if (inp != stcb->sctp_ep) {
|
||||
/*
|
||||
* some other guy has the same id active (id
|
||||
* collision ??).
|
||||
*/
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
if (want_lock) {
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
SCTP_INP_INFO_RUNLOCK();
|
||||
return (stcb);
|
||||
} else {
|
||||
SCTP_INP_RUNLOCK(stcb->sctp_ep);
|
||||
}
|
||||
if (want_lock) {
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
}
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
}
|
||||
SCTP_INP_INFO_RUNLOCK();
|
||||
return (NULL);
|
||||
@ -1773,6 +1782,8 @@ sctp_inpcb_alloc(struct socket *so)
|
||||
SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_ep, inp);
|
||||
return (EOPNOTSUPP);
|
||||
}
|
||||
sctp_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE);
|
||||
|
||||
inp->sctp_tcbhash = SCTP_HASH_INIT(sctp_pcbtblsize,
|
||||
&inp->sctp_hashmark);
|
||||
if (inp->sctp_tcbhash == NULL) {
|
||||
@ -1957,6 +1968,7 @@ sctp_move_pcb_and_assoc(struct sctp_inpcb *old_inp, struct sctp_inpcb *new_inp,
|
||||
}
|
||||
SCTP_INCR_LADDR_COUNT();
|
||||
bzero(laddr, sizeof(*laddr));
|
||||
(void)SCTP_GETTIME_TIMEVAL(&laddr->start_time);
|
||||
laddr->ifa = oladdr->ifa;
|
||||
atomic_add_int(&laddr->ifa->refcount, 1);
|
||||
LIST_INSERT_HEAD(&new_inp->sctp_addr_list, laddr,
|
||||
@ -2184,88 +2196,60 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, struct thread *p)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* get any port but lets make sure no one has any address
|
||||
* with this port bound
|
||||
*/
|
||||
uint16_t first, last, candiate;
|
||||
uint16_t count;
|
||||
int done;
|
||||
|
||||
/*
|
||||
* setup the inp to the top (I could use the union but this
|
||||
* is just as easy
|
||||
*/
|
||||
uint32_t port_guess;
|
||||
uint16_t port_attempt;
|
||||
int not_done = 1;
|
||||
int not_found = 1;
|
||||
if (ip_inp->inp_flags & INP_HIGHPORT) {
|
||||
first = ipport_hifirstauto;
|
||||
last = ipport_hilastauto;
|
||||
} else if (ip_inp->inp_flags & INP_LOWPORT) {
|
||||
if (p && (error =
|
||||
priv_check_cred(p->td_ucred,
|
||||
PRIV_NETINET_RESERVEDPORT,
|
||||
SUSER_ALLOWJAIL
|
||||
)
|
||||
)) {
|
||||
SCTP_INP_DECR_REF(inp);
|
||||
SCTP_INP_WUNLOCK(inp);
|
||||
SCTP_INP_INFO_WUNLOCK();
|
||||
return (error);
|
||||
}
|
||||
first = ipport_lowfirstauto;
|
||||
last = ipport_lowlastauto;
|
||||
} else {
|
||||
first = ipport_firstauto;
|
||||
last = ipport_lastauto;
|
||||
}
|
||||
if (first > last) {
|
||||
uint16_t temp;
|
||||
|
||||
while (not_done) {
|
||||
port_guess = sctp_select_initial_TSN(&inp->sctp_ep);
|
||||
port_attempt = (port_guess & 0x0000ffff);
|
||||
if (port_attempt == 0) {
|
||||
goto next_half;
|
||||
}
|
||||
if (port_attempt < IPPORT_RESERVED) {
|
||||
port_attempt += IPPORT_RESERVED;
|
||||
}
|
||||
not_found = 1;
|
||||
vrf_id = inp->def_vrf_id;
|
||||
if (sctp_isport_inuse(inp, htons(port_attempt),
|
||||
vrf_id) == 1) {
|
||||
/* got a port we can use */
|
||||
not_found = 0;
|
||||
}
|
||||
if (not_found == 1) {
|
||||
/* We can use this port */
|
||||
not_done = 0;
|
||||
continue;
|
||||
}
|
||||
/* try upper half */
|
||||
next_half:
|
||||
port_attempt = ((port_guess >> 16) & 0x0000ffff);
|
||||
temp = first;
|
||||
first = last;
|
||||
last = temp;
|
||||
}
|
||||
count = last - first + 1; /* number of candidates */
|
||||
candiate = first + sctp_select_initial_TSN(&inp->sctp_ep) % (count);
|
||||
|
||||
if (port_attempt == 0) {
|
||||
goto last_try;
|
||||
done = 0;
|
||||
while (!done) {
|
||||
if (sctp_isport_inuse(inp, htons(candiate), inp->def_vrf_id) == 0) {
|
||||
done = 1;
|
||||
}
|
||||
if (port_attempt < IPPORT_RESERVED) {
|
||||
port_attempt += IPPORT_RESERVED;
|
||||
}
|
||||
not_found = 1;
|
||||
vrf_id = inp->def_vrf_id;
|
||||
if (sctp_isport_inuse(inp, htons(port_attempt),
|
||||
vrf_id) == 1) {
|
||||
/* got a port we can use */
|
||||
not_found = 0;
|
||||
}
|
||||
if (not_found == 1) {
|
||||
/* We can use this port */
|
||||
not_done = 0;
|
||||
continue;
|
||||
}
|
||||
/* try two half's added together */
|
||||
last_try:
|
||||
port_attempt = (((port_guess >> 16) & 0x0000ffff) +
|
||||
(port_guess & 0x0000ffff));
|
||||
if (port_attempt == 0) {
|
||||
/* get a new random number */
|
||||
continue;
|
||||
}
|
||||
if (port_attempt < IPPORT_RESERVED) {
|
||||
port_attempt += IPPORT_RESERVED;
|
||||
}
|
||||
not_found = 1;
|
||||
vrf_id = inp->def_vrf_id;
|
||||
if (sctp_isport_inuse(inp, htons(port_attempt), vrf_id) == 1) {
|
||||
/* got a port we can use */
|
||||
not_found = 0;
|
||||
}
|
||||
if (not_found == 1) {
|
||||
/* We can use this port */
|
||||
not_done = 0;
|
||||
continue;
|
||||
if (!done) {
|
||||
if (--count == 0) {
|
||||
SCTP_INP_DECR_REF(inp);
|
||||
SCTP_INP_WUNLOCK(inp);
|
||||
SCTP_INP_INFO_WUNLOCK();
|
||||
return (EADDRNOTAVAIL);
|
||||
}
|
||||
if (candiate == last)
|
||||
candiate = first;
|
||||
else
|
||||
candiate = candiate + 1;
|
||||
}
|
||||
}
|
||||
/* we don't get out of the loop until we have a port */
|
||||
lport = htons(port_attempt);
|
||||
lport = htons(candiate);
|
||||
}
|
||||
SCTP_INP_DECR_REF(inp);
|
||||
if (inp->sctp_flags & (SCTP_PCB_FLAGS_SOCKET_GONE |
|
||||
@ -4448,6 +4432,7 @@ sctp_insert_laddr(struct sctpladdr *list, struct sctp_ifa *ifa, uint32_t act)
|
||||
}
|
||||
SCTP_INCR_LADDR_COUNT();
|
||||
bzero(laddr, sizeof(*laddr));
|
||||
(void)SCTP_GETTIME_TIMEVAL(&laddr->start_time);
|
||||
laddr->ifa = ifa;
|
||||
laddr->action = act;
|
||||
atomic_add_int(&ifa->refcount, 1);
|
||||
|
@ -118,6 +118,7 @@ struct sctp_laddr {
|
||||
uint32_t action; /* Used during asconf and adding if no-zero
|
||||
* src-addr selection will not consider this
|
||||
* address. */
|
||||
struct timeval start_time; /* time when this address was created */
|
||||
};
|
||||
|
||||
struct sctp_block_entry {
|
||||
@ -276,6 +277,9 @@ struct sctp_pcb {
|
||||
* change the secret key. The default is once a hour
|
||||
*/
|
||||
struct sctp_timer signature_change;
|
||||
|
||||
/* Zero copy full buffer timer */
|
||||
struct sctp_timer zero_copy_timer;
|
||||
int def_cookie_life;
|
||||
/* defaults to 0 */
|
||||
int auto_close_time;
|
||||
@ -343,7 +347,7 @@ struct sctp_inpcb {
|
||||
uint32_t sctp_frag_point;
|
||||
uint32_t partial_delivery_point;
|
||||
uint32_t sctp_context;
|
||||
struct sctp_sndrcvinfo def_send;
|
||||
struct sctp_nonpad_sndrcvinfo def_send;
|
||||
/*-
|
||||
* These three are here for the sosend_dgram
|
||||
* (pkt, pkt_last and control).
|
||||
|
@ -98,10 +98,12 @@ sctp_do_peeloff(struct socket *head, struct socket *so, sctp_assoc_t assoc_id)
|
||||
* stcb in the right place.
|
||||
*/
|
||||
sctp_move_pcb_and_assoc(inp, n_inp, stcb);
|
||||
atomic_add_int(&stcb->asoc.refcnt, 1);
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
|
||||
sctp_pull_off_control_to_new_inp(inp, n_inp, stcb, M_WAITOK);
|
||||
atomic_subtract_int(&stcb->asoc.refcnt, 1);
|
||||
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -131,6 +133,7 @@ sctp_get_peeloff(struct socket *head, sctp_assoc_t assoc_id, int *error)
|
||||
*error = ENOMEM;
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
return (NULL);
|
||||
|
||||
}
|
||||
n_inp = (struct sctp_inpcb *)newso->so_pcb;
|
||||
SOCK_LOCK(head);
|
||||
@ -183,12 +186,14 @@ sctp_get_peeloff(struct socket *head, sctp_assoc_t assoc_id, int *error)
|
||||
SCTP_INP_WUNLOCK(n_inp);
|
||||
SCTP_INP_WUNLOCK(inp);
|
||||
sctp_move_pcb_and_assoc(inp, n_inp, stcb);
|
||||
atomic_add_int(&stcb->asoc.refcnt, 1);
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
/*
|
||||
* 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, M_WAITOK);
|
||||
atomic_subtract_int(&stcb->asoc.refcnt, 1);
|
||||
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
return (newso);
|
||||
}
|
||||
|
@ -58,17 +58,6 @@ struct sctp_timer {
|
||||
uint32_t stopped_from;
|
||||
};
|
||||
|
||||
struct sctp_nonpad_sndrcvinfo {
|
||||
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;
|
||||
};
|
||||
|
||||
struct sctp_foo_stuff {
|
||||
struct sctp_inpcb *inp;
|
||||
@ -472,6 +461,26 @@ struct sctp_tsn_log {
|
||||
uint16_t flgs;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* This struct is here to cut out the compatiabilty
|
||||
* pad that bulks up both the inp and stcb. The non
|
||||
* pad portion MUST stay in complete sync with
|
||||
* sctp_sndrcvinfo... i.e. if sinfo_xxxx is added
|
||||
* this must be done here too.
|
||||
*/
|
||||
struct sctp_nonpad_sndrcvinfo {
|
||||
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;
|
||||
};
|
||||
|
||||
/*
|
||||
* Here we have information about each individual association that we track.
|
||||
* We probably in production would be more dynamic. But for ease of
|
||||
@ -487,7 +496,7 @@ struct sctp_association {
|
||||
struct timeval time_last_rcvd;
|
||||
struct timeval time_last_sent;
|
||||
struct timeval time_last_sat_advance;
|
||||
struct sctp_sndrcvinfo def_send; /* default send parameters */
|
||||
struct sctp_nonpad_sndrcvinfo def_send;
|
||||
|
||||
/* timers and such */
|
||||
struct sctp_timer hb_timer; /* hb timer */
|
||||
@ -695,6 +704,7 @@ struct sctp_association {
|
||||
uint32_t my_rwnd;
|
||||
uint32_t my_last_reported_rwnd;
|
||||
uint32_t my_rwnd_control_len;
|
||||
uint32_t sctp_frag_point;
|
||||
|
||||
uint32_t total_output_queue_size;
|
||||
|
||||
|
@ -36,7 +36,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <netinet/sctp_sysctl.h>
|
||||
#include <netinet/sctp_pcb.h>
|
||||
#include <netinet/sctputil.h>
|
||||
|
||||
#include <netinet/sctp_output.h>
|
||||
/*
|
||||
* sysctl tunable variables
|
||||
*/
|
||||
@ -112,6 +112,174 @@ uint32_t sctp_debug_on = 0;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* It returns an upper limit. No filtering is done here */
|
||||
static unsigned int
|
||||
number_of_addresses(struct sctp_inpcb *inp)
|
||||
{
|
||||
int cnt;
|
||||
struct sctp_vrf *vrf;
|
||||
struct sctp_ifn *sctp_ifn;
|
||||
struct sctp_ifa *sctp_ifa;
|
||||
struct sctp_laddr *laddr;
|
||||
|
||||
cnt = 0;
|
||||
/* neither Mac OS X nor FreeBSD support mulitple routing functions */
|
||||
if ((vrf = sctp_find_vrf(inp->def_vrf_id)) == NULL) {
|
||||
return (0);
|
||||
}
|
||||
if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
|
||||
LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) {
|
||||
LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
|
||||
if ((sctp_ifa->address.sa.sa_family == AF_INET) ||
|
||||
(sctp_ifa->address.sa.sa_family == AF_INET6)) {
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
|
||||
if ((laddr->ifa->address.sa.sa_family == AF_INET) ||
|
||||
(laddr->ifa->address.sa.sa_family == AF_INET6)) {
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (cnt);
|
||||
}
|
||||
|
||||
static int
|
||||
copy_out_local_addresses(struct sctp_inpcb *inp, struct sctp_tcb *stcb, struct sysctl_req *req)
|
||||
{
|
||||
struct sctp_ifn *sctp_ifn;
|
||||
struct sctp_ifa *sctp_ifa;
|
||||
int loopback_scope, ipv4_local_scope, local_scope, site_scope;
|
||||
int ipv4_addr_legal, ipv6_addr_legal;
|
||||
struct sctp_vrf *vrf;
|
||||
struct xsctp_laddr xladdr;
|
||||
struct sctp_laddr *laddr;
|
||||
int error;
|
||||
|
||||
/* Turn on all the appropriate scope */
|
||||
if (stcb) {
|
||||
/* use association specific values */
|
||||
loopback_scope = stcb->asoc.loopback_scope;
|
||||
ipv4_local_scope = stcb->asoc.ipv4_local_scope;
|
||||
local_scope = stcb->asoc.local_scope;
|
||||
site_scope = stcb->asoc.site_scope;
|
||||
} else {
|
||||
/* use generic values for endpoints */
|
||||
loopback_scope = 1;
|
||||
ipv4_local_scope = 1;
|
||||
local_scope = 1;
|
||||
site_scope = 1;
|
||||
}
|
||||
|
||||
/* use only address families of interest */
|
||||
if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
|
||||
ipv6_addr_legal = 1;
|
||||
if (SCTP_IPV6_V6ONLY(inp)) {
|
||||
ipv4_addr_legal = 0;
|
||||
} else {
|
||||
ipv4_addr_legal = 1;
|
||||
}
|
||||
} else {
|
||||
ipv4_addr_legal = 1;
|
||||
ipv6_addr_legal = 0;
|
||||
}
|
||||
|
||||
error = 0;
|
||||
|
||||
/* neither Mac OS X nor FreeBSD support mulitple routing functions */
|
||||
if ((vrf = sctp_find_vrf(inp->def_vrf_id)) == NULL) {
|
||||
return (-1);
|
||||
}
|
||||
if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
|
||||
LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) {
|
||||
if ((loopback_scope == 0) && SCTP_IFN_IS_IFT_LOOP(sctp_ifn))
|
||||
/* Skip loopback if loopback_scope not set */
|
||||
continue;
|
||||
LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
|
||||
if (stcb) {
|
||||
/*
|
||||
* ignore if blacklisted at
|
||||
* association level
|
||||
*/
|
||||
if (sctp_is_addr_restricted(stcb, sctp_ifa))
|
||||
continue;
|
||||
}
|
||||
if ((sctp_ifa->address.sa.sa_family == AF_INET) && (ipv4_addr_legal)) {
|
||||
struct sockaddr_in *sin;
|
||||
|
||||
sin = (struct sockaddr_in *)&sctp_ifa->address.sa;
|
||||
if (sin->sin_addr.s_addr == 0)
|
||||
continue;
|
||||
if ((ipv4_local_scope == 0) && (IN4_ISPRIVATE_ADDRESS(&sin->sin_addr)))
|
||||
continue;
|
||||
} else if ((sctp_ifa->address.sa.sa_family == AF_INET6) && (ipv6_addr_legal)) {
|
||||
struct sockaddr_in6 *sin6;
|
||||
|
||||
sin6 = (struct sockaddr_in6 *)&sctp_ifa->address.sa;
|
||||
if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr))
|
||||
continue;
|
||||
if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
|
||||
if (local_scope == 0)
|
||||
continue;
|
||||
if (sin6->sin6_scope_id == 0) {
|
||||
/*
|
||||
* bad link local
|
||||
* address
|
||||
*/
|
||||
if (sa6_recoverscope(sin6) != 0)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if ((site_scope == 0) && (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr)))
|
||||
continue;
|
||||
} else
|
||||
continue;
|
||||
memset((void *)&xladdr, 0, sizeof(union sctp_sockstore));
|
||||
memcpy((void *)&xladdr.address, (const void *)&sctp_ifa->address, sizeof(union sctp_sockstore));
|
||||
(void)SCTP_GETTIME_TIMEVAL(&xladdr.start_time);
|
||||
SCTP_INP_RUNLOCK(inp);
|
||||
SCTP_INP_INFO_RUNLOCK();
|
||||
error = SYSCTL_OUT(req, &xladdr, sizeof(struct xsctp_laddr));
|
||||
if (error)
|
||||
return (error);
|
||||
else {
|
||||
SCTP_INP_INFO_RLOCK();
|
||||
SCTP_INP_RLOCK(inp);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
|
||||
/* ignore if blacklisted at association level */
|
||||
if (stcb && sctp_is_addr_restricted(stcb, laddr->ifa))
|
||||
continue;
|
||||
memset((void *)&xladdr, 0, sizeof(union sctp_sockstore));
|
||||
memcpy((void *)&xladdr.address, (const void *)&laddr->ifa->address, sizeof(union sctp_sockstore));
|
||||
xladdr.start_time = laddr->start_time;
|
||||
SCTP_INP_RUNLOCK(inp);
|
||||
SCTP_INP_INFO_RUNLOCK();
|
||||
error = SYSCTL_OUT(req, &xladdr, sizeof(struct xsctp_laddr));
|
||||
if (error)
|
||||
return (error);
|
||||
else {
|
||||
SCTP_INP_INFO_RLOCK();
|
||||
SCTP_INP_RLOCK(inp);
|
||||
}
|
||||
}
|
||||
}
|
||||
memset((void *)&xladdr, 0, sizeof(union sctp_sockstore));
|
||||
xladdr.last = 1;
|
||||
error = SYSCTL_OUT(req, &xladdr, sizeof(struct xsctp_laddr));
|
||||
if (error)
|
||||
return (error);
|
||||
else
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* sysctl functions
|
||||
*/
|
||||
@ -127,11 +295,8 @@ sctp_assoclist(SYSCTL_HANDLER_ARGS)
|
||||
struct sctp_inpcb *inp;
|
||||
struct sctp_tcb *stcb;
|
||||
struct sctp_nets *net;
|
||||
struct sctp_laddr *laddr;
|
||||
struct xsctp_inpcb xinpcb;
|
||||
struct xsctp_tcb xstcb;
|
||||
|
||||
/* struct xsctp_laddr xladdr; */
|
||||
struct xsctp_raddr xraddr;
|
||||
|
||||
number_of_endpoints = 0;
|
||||
@ -144,12 +309,10 @@ sctp_assoclist(SYSCTL_HANDLER_ARGS)
|
||||
LIST_FOREACH(inp, &sctppcbinfo.listhead, sctp_list) {
|
||||
SCTP_INP_RLOCK(inp);
|
||||
number_of_endpoints++;
|
||||
/* FIXME MT */
|
||||
LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
|
||||
number_of_local_addresses++;
|
||||
}
|
||||
number_of_local_addresses += number_of_addresses(inp);
|
||||
LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
|
||||
number_of_associations++;
|
||||
number_of_local_addresses += number_of_addresses(inp);
|
||||
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
|
||||
number_of_remote_addresses++;
|
||||
}
|
||||
@ -158,14 +321,10 @@ sctp_assoclist(SYSCTL_HANDLER_ARGS)
|
||||
}
|
||||
SCTP_INP_INFO_RUNLOCK();
|
||||
n = (number_of_endpoints + 1) * sizeof(struct xsctp_inpcb) +
|
||||
number_of_local_addresses * sizeof(struct xsctp_laddr) +
|
||||
number_of_associations * sizeof(struct xsctp_tcb) +
|
||||
number_of_remote_addresses * sizeof(struct xsctp_raddr);
|
||||
#ifdef SCTP_DEBUG
|
||||
printf("inps = %u, stcbs = %u, laddrs = %u, raddrs = %u\n",
|
||||
number_of_endpoints, number_of_associations,
|
||||
number_of_local_addresses, number_of_remote_addresses);
|
||||
#endif
|
||||
(number_of_local_addresses + number_of_endpoints + number_of_associations) * sizeof(struct xsctp_laddr) +
|
||||
(number_of_associations + number_of_endpoints) * sizeof(struct xsctp_tcb) +
|
||||
(number_of_remote_addresses + number_of_associations) * sizeof(struct xsctp_raddr);
|
||||
|
||||
/* request some more memory than needed */
|
||||
req->oldidx = (n + n / 8);
|
||||
return 0;
|
||||
@ -176,78 +335,53 @@ sctp_assoclist(SYSCTL_HANDLER_ARGS)
|
||||
}
|
||||
LIST_FOREACH(inp, &sctppcbinfo.listhead, sctp_list) {
|
||||
SCTP_INP_RLOCK(inp);
|
||||
number_of_local_addresses = 0;
|
||||
number_of_associations = 0;
|
||||
/*
|
||||
* LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr)
|
||||
* { number_of_local_addresses++; }
|
||||
*/
|
||||
LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
|
||||
number_of_associations++;
|
||||
}
|
||||
xinpcb.last = 0;
|
||||
xinpcb.local_port = ntohs(inp->sctp_lport);
|
||||
xinpcb.number_local_addresses = number_of_local_addresses;
|
||||
xinpcb.number_associations = number_of_associations;
|
||||
xinpcb.flags = inp->sctp_flags;
|
||||
xinpcb.features = inp->sctp_features;
|
||||
xinpcb.total_sends = inp->total_sends;
|
||||
xinpcb.total_recvs = inp->total_recvs;
|
||||
xinpcb.total_nospaces = inp->total_nospaces;
|
||||
xinpcb.fragmentation_point = inp->sctp_frag_point;
|
||||
if (inp->sctp_socket != NULL) {
|
||||
sotoxsocket(inp->sctp_socket, &xinpcb.xsocket);
|
||||
} else {
|
||||
bzero(&xinpcb.xsocket, sizeof xinpcb.xsocket);
|
||||
xinpcb.xsocket.xso_protocol = IPPROTO_SCTP;
|
||||
}
|
||||
xinpcb.qlen = inp->sctp_socket->so_qlen;
|
||||
xinpcb.maxqlen = inp->sctp_socket->so_qlimit;
|
||||
SCTP_INP_INCR_REF(inp);
|
||||
SCTP_INP_RUNLOCK(inp);
|
||||
SCTP_INP_INFO_RUNLOCK();
|
||||
error = SYSCTL_OUT(req, &xinpcb, sizeof(struct xsctp_inpcb));
|
||||
if (error) {
|
||||
SCTP_INP_DECR_REF(inp);
|
||||
return error;
|
||||
}
|
||||
SCTP_INP_INFO_RLOCK();
|
||||
SCTP_INP_RLOCK(inp);
|
||||
/* FIXME MT */
|
||||
/*
|
||||
* LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr)
|
||||
* { error = SYSCTL_OUT(req, &xladdr, sizeof(struct
|
||||
* xsctp_laddr)); if (error) { #if
|
||||
* defined(SCTP_PER_SOCKET_LOCKING)
|
||||
* SCTP_SOCKET_UNLOCK(SCTP_INP_SO(inp), 1);
|
||||
* SCTP_UNLOCK_SHARED(sctppcbinfo.ipi_ep_mtx); #endif
|
||||
* SCTP_INP_RUNLOCK(inp); SCTP_INP_INFO_RUNLOCK(); return
|
||||
* error; } }
|
||||
*/
|
||||
error = copy_out_local_addresses(inp, NULL, req);
|
||||
if (error) {
|
||||
SCTP_INP_DECR_REF(inp);
|
||||
return error;
|
||||
}
|
||||
LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
|
||||
SCTP_TCB_LOCK(stcb);
|
||||
atomic_add_int(&stcb->asoc.refcnt, 1);
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
number_of_local_addresses = 0;
|
||||
number_of_remote_addresses = 0;
|
||||
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
|
||||
number_of_remote_addresses++;
|
||||
}
|
||||
xstcb.LocalPort = ntohs(inp->sctp_lport);
|
||||
xstcb.RemPort = ntohs(stcb->rport);
|
||||
xstcb.last = 0;
|
||||
xstcb.local_port = ntohs(inp->sctp_lport);
|
||||
xstcb.remote_port = ntohs(stcb->rport);
|
||||
if (stcb->asoc.primary_destination != NULL)
|
||||
xstcb.RemPrimAddr = stcb->asoc.primary_destination->ro._l_addr;
|
||||
xstcb.HeartBeatInterval = stcb->asoc.heart_beat_delay;
|
||||
xstcb.State = SCTP_GET_STATE(&stcb->asoc); /* FIXME */
|
||||
xstcb.InStreams = stcb->asoc.streamincnt;
|
||||
xstcb.OutStreams = stcb->asoc.streamoutcnt;
|
||||
xstcb.MaxRetr = stcb->asoc.overall_error_count;
|
||||
xstcb.PrimProcess = 0; /* not really supported yet */
|
||||
xstcb.T1expireds = stcb->asoc.timoinit + stcb->asoc.timocookie;
|
||||
xstcb.T2expireds = stcb->asoc.timoshutdown + stcb->asoc.timoshutdownack;
|
||||
xstcb.RtxChunks = stcb->asoc.marked_retrans;
|
||||
xstcb.StartTime = stcb->asoc.start_time;
|
||||
xstcb.DiscontinuityTime = stcb->asoc.discontinuity_time;
|
||||
xstcb.primary_addr = stcb->asoc.primary_destination->ro._l_addr;
|
||||
xstcb.heartbeat_interval = stcb->asoc.heart_beat_delay;
|
||||
xstcb.state = SCTP_GET_STATE(&stcb->asoc); /* FIXME */
|
||||
xstcb.in_streams = stcb->asoc.streamincnt;
|
||||
xstcb.out_streams = stcb->asoc.streamoutcnt;
|
||||
xstcb.max_nr_retrans = stcb->asoc.overall_error_count;
|
||||
xstcb.primary_process = 0; /* not really supported
|
||||
* yet */
|
||||
xstcb.T1_expireries = stcb->asoc.timoinit + stcb->asoc.timocookie;
|
||||
xstcb.T2_expireries = stcb->asoc.timoshutdown + stcb->asoc.timoshutdownack;
|
||||
xstcb.retransmitted_tsns = stcb->asoc.marked_retrans;
|
||||
xstcb.start_time = stcb->asoc.start_time;
|
||||
xstcb.discontinuity_time = stcb->asoc.discontinuity_time;
|
||||
|
||||
xstcb.number_local_addresses = number_of_local_addresses;
|
||||
xstcb.number_remote_addresses = number_of_remote_addresses;
|
||||
xstcb.total_sends = stcb->total_sends;
|
||||
xstcb.total_recvs = stcb->total_recvs;
|
||||
xstcb.local_tag = stcb->asoc.my_vtag;
|
||||
@ -261,43 +395,71 @@ sctp_assoclist(SYSCTL_HANDLER_ARGS)
|
||||
SCTP_INP_INFO_RUNLOCK();
|
||||
error = SYSCTL_OUT(req, &xstcb, sizeof(struct xsctp_tcb));
|
||||
if (error) {
|
||||
SCTP_INP_DECR_REF(inp);
|
||||
atomic_add_int(&stcb->asoc.refcnt, -1);
|
||||
return error;
|
||||
}
|
||||
SCTP_INP_INFO_RLOCK();
|
||||
SCTP_INP_RLOCK(inp);
|
||||
error = copy_out_local_addresses(inp, stcb, req);
|
||||
if (error) {
|
||||
SCTP_INP_DECR_REF(inp);
|
||||
atomic_add_int(&stcb->asoc.refcnt, -1);
|
||||
return error;
|
||||
}
|
||||
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
|
||||
xraddr.RemAddr = net->ro._l_addr;
|
||||
xraddr.RemAddrActive = ((net->dest_state & SCTP_ADDR_REACHABLE) == SCTP_ADDR_REACHABLE);
|
||||
xraddr.RemAddrConfirmed = ((net->dest_state & SCTP_ADDR_UNCONFIRMED) == 0);
|
||||
xraddr.RemAddrHBActive = ((net->dest_state & SCTP_ADDR_NOHB) == 0);
|
||||
xraddr.RemAddrRTO = net->RTO;
|
||||
xraddr.RemAddrMaxPathRtx = net->failure_threshold;
|
||||
xraddr.RemAddrRtx = net->marked_retrans;
|
||||
xraddr.RemAddrErrorCounter = net->error_count;
|
||||
xraddr.RemAddrCwnd = net->cwnd;
|
||||
xraddr.RemAddrFlightSize = net->flight_size;
|
||||
xraddr.RemAddrStartTime = net->start_time;
|
||||
xraddr.RemAddrMTU = net->mtu;
|
||||
xraddr.last = 0;
|
||||
xraddr.address = net->ro._l_addr;
|
||||
xraddr.active = ((net->dest_state & SCTP_ADDR_REACHABLE) == SCTP_ADDR_REACHABLE);
|
||||
xraddr.confirmed = ((net->dest_state & SCTP_ADDR_UNCONFIRMED) == 0);
|
||||
xraddr.heartbeat_enabled = ((net->dest_state & SCTP_ADDR_NOHB) == 0);
|
||||
xraddr.rto = net->RTO;
|
||||
xraddr.max_path_rtx = net->failure_threshold;
|
||||
xraddr.rtx = net->marked_retrans;
|
||||
xraddr.error_counter = net->error_count;
|
||||
xraddr.cwnd = net->cwnd;
|
||||
xraddr.flight_size = net->flight_size;
|
||||
xraddr.mtu = net->mtu;
|
||||
xraddr.start_time = net->start_time;
|
||||
SCTP_INP_RUNLOCK(inp);
|
||||
SCTP_INP_INFO_RUNLOCK();
|
||||
error = SYSCTL_OUT(req, &xraddr, sizeof(struct xsctp_raddr));
|
||||
if (error) {
|
||||
SCTP_INP_DECR_REF(inp);
|
||||
atomic_add_int(&stcb->asoc.refcnt, -1);
|
||||
return error;
|
||||
}
|
||||
SCTP_INP_INFO_RLOCK();
|
||||
SCTP_INP_RLOCK(inp);
|
||||
}
|
||||
atomic_add_int(&stcb->asoc.refcnt, -1);
|
||||
memset((void *)&xraddr, 0, sizeof(struct xsctp_raddr));
|
||||
xraddr.last = 1;
|
||||
SCTP_INP_RUNLOCK(inp);
|
||||
SCTP_INP_INFO_RUNLOCK();
|
||||
error = SYSCTL_OUT(req, &xraddr, sizeof(struct xsctp_raddr));
|
||||
if (error) {
|
||||
SCTP_INP_DECR_REF(inp);
|
||||
return error;
|
||||
}
|
||||
SCTP_INP_INFO_RLOCK();
|
||||
SCTP_INP_RLOCK(inp);
|
||||
}
|
||||
SCTP_INP_DECR_REF(inp);
|
||||
SCTP_INP_RUNLOCK(inp);
|
||||
SCTP_INP_INFO_RUNLOCK();
|
||||
memset((void *)&xstcb, 0, sizeof(struct xsctp_tcb));
|
||||
xstcb.last = 1;
|
||||
error = SYSCTL_OUT(req, &xstcb, sizeof(struct xsctp_tcb));
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
SCTP_INP_INFO_RLOCK();
|
||||
SCTP_INP_DECR_REF(inp);
|
||||
}
|
||||
SCTP_INP_INFO_RUNLOCK();
|
||||
|
||||
memset((void *)&xinpcb, 0, sizeof(struct xsctp_inpcb));
|
||||
xinpcb.last = 1;
|
||||
xinpcb.local_port = 0;
|
||||
xinpcb.number_local_addresses = 0;
|
||||
xinpcb.number_associations = 0;
|
||||
xinpcb.flags = 0;
|
||||
xinpcb.features = 0;
|
||||
error = SYSCTL_OUT(req, &xinpcb, sizeof(struct xsctp_inpcb));
|
||||
return error;
|
||||
}
|
||||
|
@ -1411,7 +1411,7 @@ sctp_heartbeat_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
|
||||
* this will send out extra hb's up to maxburst if there are
|
||||
* any unconfirmed addresses.
|
||||
*/
|
||||
int cnt_sent = 0;
|
||||
uint32_t cnt_sent = 0;
|
||||
|
||||
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
|
||||
if ((net->dest_state & SCTP_ADDR_UNCONFIRMED) &&
|
||||
|
@ -42,7 +42,6 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socketvar.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
typedef uint32_t sctp_assoc_t;
|
||||
@ -413,8 +412,6 @@ struct sctp_paddrparams {
|
||||
#define SPP_HB_DEMAND 0x00000004
|
||||
#define SPP_PMTUD_ENABLE 0x00000008
|
||||
#define SPP_PMTUD_DISABLE 0x00000010
|
||||
#define SPP_SACKDELAY_ENABLE 0x00000020
|
||||
#define SPP_SACKDELAY_DISABLE 0x00000040
|
||||
#define SPP_HB_TIME_IS_ZERO 0x00000080
|
||||
#define SPP_IPV6_FLOWLABEL 0x00000100
|
||||
#define SPP_IPV4_TOS 0x00000200
|
||||
@ -443,8 +440,6 @@ struct sctp_assocparams {
|
||||
uint32_t sasoc_peer_rwnd;
|
||||
uint32_t sasoc_local_rwnd;
|
||||
uint32_t sasoc_cookie_life;
|
||||
uint32_t sasoc_sack_delay;
|
||||
uint32_t sasoc_sack_freq;
|
||||
};
|
||||
|
||||
struct sctp_setprim {
|
||||
@ -533,6 +528,12 @@ struct sctp_assoc_ids {
|
||||
sctp_assoc_t gaids_assoc_id[0];
|
||||
};
|
||||
|
||||
struct sctp_sack_info {
|
||||
sctp_assoc_t sack_assoc_id;
|
||||
uint32_t sack_delay;
|
||||
uint32_t sack_freq;
|
||||
};
|
||||
|
||||
struct sctp_cwnd_args {
|
||||
struct sctp_nets *net; /* network to */
|
||||
uint32_t cwnd_new_value;/* cwnd in k */
|
||||
@ -923,33 +924,33 @@ union sctp_sockstore {
|
||||
struct xsctp_inpcb {
|
||||
uint32_t last;
|
||||
uint16_t local_port;
|
||||
uint16_t number_local_addresses;
|
||||
uint32_t number_associations;
|
||||
uint32_t flags;
|
||||
uint32_t features;
|
||||
uint32_t total_sends;
|
||||
uint32_t total_recvs;
|
||||
uint32_t total_nospaces;
|
||||
uint32_t fragmentation_point;
|
||||
struct xsocket xsocket;
|
||||
uint16_t qlen;
|
||||
uint16_t maxqlen;
|
||||
/* add more endpoint specific data here */
|
||||
};
|
||||
|
||||
struct xsctp_tcb {
|
||||
uint16_t LocalPort; /* sctpAssocEntry 3 */
|
||||
uint16_t RemPort; /* sctpAssocEntry 4 */
|
||||
union sctp_sockstore RemPrimAddr; /* sctpAssocEntry 5/6 */
|
||||
uint32_t HeartBeatInterval; /* sctpAssocEntry 7 */
|
||||
uint32_t State; /* sctpAssocEntry 8 */
|
||||
uint32_t InStreams; /* sctpAssocEntry 9 */
|
||||
uint32_t OutStreams; /* sctpAssocEntry 10 */
|
||||
uint32_t MaxRetr; /* sctpAssocEntry 11 */
|
||||
uint32_t PrimProcess; /* sctpAssocEntry 12 */
|
||||
uint32_t T1expireds; /* sctpAssocEntry 13 */
|
||||
uint32_t T2expireds; /* sctpAssocEntry 14 */
|
||||
uint32_t RtxChunks; /* sctpAssocEntry 15 */
|
||||
struct timeval StartTime; /* sctpAssocEntry 16 */
|
||||
struct timeval DiscontinuityTime; /* sctpAssocEntry 17 */
|
||||
uint32_t last;
|
||||
uint16_t local_port; /* sctpAssocEntry 3 */
|
||||
uint16_t remote_port; /* sctpAssocEntry 4 */
|
||||
union sctp_sockstore primary_addr; /* sctpAssocEntry 5/6 */
|
||||
uint32_t heartbeat_interval; /* sctpAssocEntry 7 */
|
||||
uint32_t state; /* sctpAssocEntry 8 */
|
||||
uint32_t in_streams; /* sctpAssocEntry 9 */
|
||||
uint32_t out_streams; /* sctpAssocEntry 10 */
|
||||
uint32_t max_nr_retrans;/* sctpAssocEntry 11 */
|
||||
uint32_t primary_process; /* sctpAssocEntry 12 */
|
||||
uint32_t T1_expireries; /* sctpAssocEntry 13 */
|
||||
uint32_t T2_expireries; /* sctpAssocEntry 14 */
|
||||
uint32_t retransmitted_tsns; /* sctpAssocEntry 15 */
|
||||
struct timeval start_time; /* sctpAssocEntry 16 */
|
||||
struct timeval discontinuity_time; /* sctpAssocEntry 17 */
|
||||
uint32_t total_sends;
|
||||
uint32_t total_recvs;
|
||||
uint32_t local_tag;
|
||||
@ -960,29 +961,29 @@ struct xsctp_tcb {
|
||||
uint32_t cumulative_tsn_ack;
|
||||
uint32_t mtu;
|
||||
/* add more association specific data here */
|
||||
uint16_t number_local_addresses;
|
||||
uint16_t number_remote_addresses;
|
||||
};
|
||||
|
||||
struct xsctp_laddr {
|
||||
union sctp_sockstore LocalAddr; /* sctpAssocLocalAddrEntry 1/2 */
|
||||
struct timeval LocalStartTime; /* sctpAssocLocalAddrEntry 3 */
|
||||
uint32_t last;
|
||||
union sctp_sockstore address; /* sctpAssocLocalAddrEntry 1/2 */
|
||||
struct timeval start_time; /* sctpAssocLocalAddrEntry 3 */
|
||||
/* add more local address specific data */
|
||||
};
|
||||
|
||||
struct xsctp_raddr {
|
||||
union sctp_sockstore RemAddr; /* sctpAssocLocalRemEntry 1/2 */
|
||||
uint8_t RemAddrActive; /* sctpAssocLocalRemEntry 3 */
|
||||
uint8_t RemAddrConfirmed; /* */
|
||||
uint8_t RemAddrHBActive;/* sctpAssocLocalRemEntry 4 */
|
||||
uint32_t RemAddrRTO; /* sctpAssocLocalRemEntry 5 */
|
||||
uint32_t RemAddrMaxPathRtx; /* sctpAssocLocalRemEntry 6 */
|
||||
uint32_t RemAddrRtx; /* sctpAssocLocalRemEntry 7 */
|
||||
uint32_t RemAddrErrorCounter; /* */
|
||||
uint32_t RemAddrCwnd; /* */
|
||||
uint32_t RemAddrFlightSize; /* */
|
||||
uint32_t RemAddrMTU; /* */
|
||||
struct timeval RemAddrStartTime; /* sctpAssocLocalRemEntry 8 */
|
||||
uint32_t last;
|
||||
union sctp_sockstore address; /* sctpAssocLocalRemEntry 1/2 */
|
||||
uint8_t active; /* sctpAssocLocalRemEntry 3 */
|
||||
uint8_t confirmed; /* */
|
||||
uint8_t heartbeat_enabled; /* sctpAssocLocalRemEntry 4 */
|
||||
uint32_t rto; /* sctpAssocLocalRemEntry 5 */
|
||||
uint32_t max_path_rtx; /* sctpAssocLocalRemEntry 6 */
|
||||
uint32_t rtx; /* sctpAssocLocalRemEntry 7 */
|
||||
uint32_t error_counter; /* */
|
||||
uint32_t cwnd; /* */
|
||||
uint32_t flight_size; /* */
|
||||
uint32_t mtu; /* */
|
||||
struct timeval start_time; /* sctpAssocLocalRemEntry 8 */
|
||||
/* add more remote address specific data */
|
||||
};
|
||||
|
||||
|
@ -67,7 +67,7 @@ sctp_init(void)
|
||||
*/
|
||||
sb_max_adj = (u_long)((u_quad_t) (SB_MAX) * MCLBYTES / (MSIZE + MCLBYTES));
|
||||
sctp_sendspace = min((min(SB_MAX, sb_max_adj)),
|
||||
((nmbclusters / 2) * SCTP_DEFAULT_MAXSEGMENT));
|
||||
(((uint32_t) nmbclusters / 2) * SCTP_DEFAULT_MAXSEGMENT));
|
||||
/*
|
||||
* Now for the recv window, should we take the same amount? or
|
||||
* should I do 1/2 the SB_MAX instead in the SB_MAX min above. For
|
||||
@ -546,7 +546,9 @@ sctp_bind(struct socket *so, struct sockaddr *addr, struct thread *p)
|
||||
/* must be a v4 address! */
|
||||
return EINVAL;
|
||||
#endif /* INET6 */
|
||||
|
||||
if (addr && (addr->sa_len != sizeof(struct sockaddr_in))) {
|
||||
return EINVAL;
|
||||
}
|
||||
inp = (struct sctp_inpcb *)so->so_pcb;
|
||||
if (inp == 0)
|
||||
return EINVAL;
|
||||
@ -1256,6 +1258,7 @@ sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval,
|
||||
int num_v6 = 0, num_v4 = 0, *totaddrp, totaddr;
|
||||
int added = 0;
|
||||
uint32_t vrf_id;
|
||||
int bad_addresses = 0;
|
||||
sctp_assoc_t *a_id;
|
||||
|
||||
SCTPDBG(SCTP_DEBUG_PCB1, "Connectx called\n");
|
||||
@ -1287,13 +1290,14 @@ sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval,
|
||||
totaddrp = (int *)optval;
|
||||
totaddr = *totaddrp;
|
||||
sa = (struct sockaddr *)(totaddrp + 1);
|
||||
stcb = sctp_connectx_helper_find(inp, sa, &totaddr, &num_v4, &num_v6, &error, (optsize - sizeof(int)));
|
||||
if (stcb != NULL) {
|
||||
stcb = sctp_connectx_helper_find(inp, sa, &totaddr, &num_v4, &num_v6, &error, (optsize - sizeof(int)), &bad_addresses);
|
||||
if ((stcb != NULL) || bad_addresses) {
|
||||
/* Already have or am bring up an association */
|
||||
SCTP_ASOC_CREATE_UNLOCK(inp);
|
||||
creat_lock_on = 0;
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
error = EALREADY;
|
||||
if (bad_addresses == 0)
|
||||
error = EALREADY;
|
||||
goto out_now;
|
||||
}
|
||||
#ifdef INET6
|
||||
@ -1341,8 +1345,13 @@ sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval,
|
||||
else
|
||||
sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in6));
|
||||
|
||||
error = 0;
|
||||
added = sctp_connectx_helper_add(stcb, sa, (totaddr - 1), &error);
|
||||
/* Fill in the return id */
|
||||
if (error) {
|
||||
sctp_free_assoc(inp, stcb, SCTP_PCBFREE_FORCE, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_12);
|
||||
goto out_now;
|
||||
}
|
||||
a_id = (sctp_assoc_t *) optval;
|
||||
*a_id = sctp_get_associd(stcb);
|
||||
|
||||
@ -1594,10 +1603,10 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
|
||||
break;
|
||||
case SCTP_VRF_ID:
|
||||
{
|
||||
uint32_t *vrf_id;
|
||||
uint32_t *default_vrfid;
|
||||
|
||||
SCTP_CHECK_AND_CAST(vrf_id, optval, uint32_t, *optsize);
|
||||
*vrf_id = inp->def_vrf_id;
|
||||
SCTP_CHECK_AND_CAST(default_vrfid, optval, uint32_t, *optsize);
|
||||
*default_vrfid = inp->def_vrf_id;
|
||||
break;
|
||||
}
|
||||
case SCTP_GET_ASOC_VRF:
|
||||
@ -1635,22 +1644,23 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
|
||||
*optsize = sizeof(*gnv);
|
||||
}
|
||||
break;
|
||||
case SCTP_DELAYED_ACK_TIME:
|
||||
case SCTP_DELAYED_SACK:
|
||||
{
|
||||
struct sctp_assoc_value *tm;
|
||||
|
||||
SCTP_CHECK_AND_CAST(tm, optval, struct sctp_assoc_value, *optsize);
|
||||
SCTP_FIND_STCB(inp, stcb, tm->assoc_id);
|
||||
struct sctp_sack_info *sack;
|
||||
|
||||
SCTP_CHECK_AND_CAST(sack, optval, struct sctp_sack_info, *optsize);
|
||||
SCTP_FIND_STCB(inp, stcb, sack->sack_assoc_id);
|
||||
if (stcb) {
|
||||
tm->assoc_value = stcb->asoc.delayed_ack;
|
||||
sack->sack_delay = stcb->asoc.delayed_ack;
|
||||
sack->sack_freq = stcb->asoc.sack_freq;
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
} else {
|
||||
SCTP_INP_RLOCK(inp);
|
||||
tm->assoc_value = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV]);
|
||||
sack->sack_delay = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV]);
|
||||
sack->sack_freq = inp->sctp_ep.sctp_sack_freq;
|
||||
SCTP_INP_RUNLOCK(inp);
|
||||
}
|
||||
*optsize = sizeof(*tm);
|
||||
*optsize = sizeof(*sack);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -1672,7 +1682,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
|
||||
*optsize = sizeof(struct sctp_sockstat);
|
||||
}
|
||||
break;
|
||||
case SCTP_MAXBURST:
|
||||
case SCTP_MAX_BURST:
|
||||
{
|
||||
uint8_t *value;
|
||||
|
||||
@ -1690,11 +1700,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
|
||||
int ovh;
|
||||
|
||||
SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
|
||||
if (av->assoc_id) {
|
||||
SCTP_FIND_STCB(inp, stcb, av->assoc_id);
|
||||
} else {
|
||||
stcb = NULL;
|
||||
}
|
||||
SCTP_FIND_STCB(inp, stcb, av->assoc_id);
|
||||
|
||||
if (stcb) {
|
||||
av->assoc_value = sctp_get_frag_point(stcb, &stcb->asoc);
|
||||
@ -1706,7 +1712,10 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
|
||||
} else {
|
||||
ovh = SCTP_MED_V4_OVERHEAD;
|
||||
}
|
||||
av->assoc_value = inp->sctp_frag_point - ovh;
|
||||
if (inp->sctp_frag_point >= SCTP_DEFAULT_MAXSEGMENT)
|
||||
av->assoc_value = 0;
|
||||
else
|
||||
av->assoc_value = inp->sctp_frag_point - ovh;
|
||||
SCTP_INP_RUNLOCK(inp);
|
||||
}
|
||||
*optsize = sizeof(struct sctp_assoc_value);
|
||||
@ -1927,8 +1936,17 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
|
||||
/* Applys to the specific association */
|
||||
paddrp->spp_flags = 0;
|
||||
if (net) {
|
||||
int ovh;
|
||||
|
||||
if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
|
||||
ovh = SCTP_MED_OVERHEAD;
|
||||
} else {
|
||||
ovh = SCTP_MED_V4_OVERHEAD;
|
||||
}
|
||||
|
||||
|
||||
paddrp->spp_pathmaxrxt = net->failure_threshold;
|
||||
paddrp->spp_pathmtu = net->mtu;
|
||||
paddrp->spp_pathmtu = net->mtu - ovh;
|
||||
/* get flags for HB */
|
||||
if (net->dest_state & SCTP_ADDR_NOHB)
|
||||
paddrp->spp_flags |= SPP_HB_DISABLE;
|
||||
@ -1957,6 +1975,8 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
|
||||
* No destination so return default
|
||||
* value
|
||||
*/
|
||||
int cnt = 0;
|
||||
|
||||
paddrp->spp_pathmaxrxt = stcb->asoc.def_net_failure;
|
||||
paddrp->spp_pathmtu = sctp_get_frag_point(stcb, &stcb->asoc);
|
||||
#ifdef INET
|
||||
@ -1968,8 +1988,18 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
|
||||
paddrp->spp_flags |= SPP_IPV6_FLOWLABEL;
|
||||
#endif
|
||||
/* default settings should be these */
|
||||
if (sctp_is_hb_timer_running(stcb)) {
|
||||
if (stcb->asoc.hb_is_disabled == 0) {
|
||||
paddrp->spp_flags |= SPP_HB_ENABLE;
|
||||
} else {
|
||||
paddrp->spp_flags |= SPP_HB_DISABLE;
|
||||
}
|
||||
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
|
||||
if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
if (cnt) {
|
||||
paddrp->spp_flags |= SPP_PMTUD_ENABLE;
|
||||
}
|
||||
}
|
||||
paddrp->spp_hbinterval = stcb->asoc.heart_beat_delay;
|
||||
@ -1993,11 +2023,16 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
|
||||
}
|
||||
#endif
|
||||
/* can't return this */
|
||||
paddrp->spp_pathmaxrxt = 0;
|
||||
paddrp->spp_pathmtu = 0;
|
||||
/* default behavior, no stcb */
|
||||
paddrp->spp_flags = SPP_HB_ENABLE | SPP_PMTUD_ENABLE;
|
||||
|
||||
/* default behavior, no stcb */
|
||||
paddrp->spp_flags = SPP_PMTUD_ENABLE;
|
||||
|
||||
if (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT)) {
|
||||
paddrp->spp_flags |= SPP_HB_ENABLE;
|
||||
} else {
|
||||
paddrp->spp_flags |= SPP_HB_DISABLE;
|
||||
}
|
||||
SCTP_INP_RUNLOCK(inp);
|
||||
}
|
||||
*optsize = sizeof(struct sctp_paddrparams);
|
||||
@ -2140,8 +2175,6 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
|
||||
sasoc->sasoc_peer_rwnd = stcb->asoc.peers_rwnd;
|
||||
sasoc->sasoc_local_rwnd = stcb->asoc.my_rwnd;
|
||||
sasoc->sasoc_cookie_life = TICKS_TO_MSEC(stcb->asoc.cookie_life);
|
||||
sasoc->sasoc_sack_delay = stcb->asoc.delayed_ack;
|
||||
sasoc->sasoc_sack_freq = stcb->asoc.sack_freq;
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
} else {
|
||||
SCTP_INP_RLOCK(inp);
|
||||
@ -2150,8 +2183,6 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
|
||||
sasoc->sasoc_peer_rwnd = 0;
|
||||
sasoc->sasoc_local_rwnd = sbspace(&inp->sctp_socket->so_rcv);
|
||||
sasoc->sasoc_cookie_life = TICKS_TO_MSEC(inp->sctp_ep.def_cookie_life);
|
||||
sasoc->sasoc_sack_delay = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV]);
|
||||
sasoc->sasoc_sack_freq = inp->sctp_ep.sctp_sack_freq;
|
||||
SCTP_INP_RUNLOCK(inp);
|
||||
}
|
||||
*optsize = sizeof(*sasoc);
|
||||
@ -2165,11 +2196,11 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
|
||||
SCTP_FIND_STCB(inp, stcb, s_info->sinfo_assoc_id);
|
||||
|
||||
if (stcb) {
|
||||
*s_info = stcb->asoc.def_send;
|
||||
memcpy(s_info, &stcb->asoc.def_send, sizeof(stcb->asoc.def_send));
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
} else {
|
||||
SCTP_INP_RLOCK(inp);
|
||||
*s_info = inp->def_send;
|
||||
memcpy(s_info, &inp->def_send, sizeof(inp->def_send));
|
||||
SCTP_INP_RUNLOCK(inp);
|
||||
}
|
||||
*optsize = sizeof(*s_info);
|
||||
@ -2199,8 +2230,15 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
|
||||
|
||||
if (stcb) {
|
||||
/* simply copy out the sockaddr_storage... */
|
||||
memcpy(&ssp->ssp_addr, &stcb->asoc.primary_destination->ro._l_addr,
|
||||
((struct sockaddr *)&stcb->asoc.primary_destination->ro._l_addr)->sa_len);
|
||||
int len;
|
||||
|
||||
len = *optsize;
|
||||
if (len > stcb->asoc.primary_destination->ro._l_addr.sa.sa_len)
|
||||
len = stcb->asoc.primary_destination->ro._l_addr.sa.sa_len;
|
||||
|
||||
memcpy(&ssp->ssp_addr,
|
||||
&stcb->asoc.primary_destination->ro._l_addr,
|
||||
len);
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
} else {
|
||||
error = EINVAL;
|
||||
@ -2395,6 +2433,10 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
|
||||
set_opt = SCTP_PCB_FLAGS_NODELAY;
|
||||
break;
|
||||
case SCTP_AUTOCLOSE:
|
||||
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
|
||||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
|
||||
return (EINVAL);
|
||||
}
|
||||
set_opt = SCTP_PCB_FLAGS_AUTOCLOSE;
|
||||
/*
|
||||
* The value is in ticks. Note this does not effect
|
||||
@ -2436,7 +2478,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
|
||||
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_FRAG_INTERLEAVE);
|
||||
sctp_feature_off(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS);
|
||||
|
||||
} else {
|
||||
@ -2488,14 +2530,14 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
|
||||
break;
|
||||
case SCTP_VRF_ID:
|
||||
{
|
||||
uint32_t *vrf_id;
|
||||
uint32_t *default_vrfid;
|
||||
|
||||
SCTP_CHECK_AND_CAST(vrf_id, optval, uint32_t, optsize);
|
||||
if (*vrf_id > SCTP_MAX_VRF_ID) {
|
||||
SCTP_CHECK_AND_CAST(default_vrfid, optval, uint32_t, optsize);
|
||||
if (*default_vrfid > SCTP_MAX_VRF_ID) {
|
||||
error = EINVAL;
|
||||
break;
|
||||
}
|
||||
inp->def_vrf_id = *vrf_id;
|
||||
inp->def_vrf_id = *default_vrfid;
|
||||
break;
|
||||
}
|
||||
case SCTP_DEL_VRF_ID:
|
||||
@ -2508,20 +2550,34 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
|
||||
error = EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
|
||||
case SCTP_DELAYED_ACK_TIME:
|
||||
case SCTP_DELAYED_SACK:
|
||||
{
|
||||
struct sctp_assoc_value *tm;
|
||||
|
||||
SCTP_CHECK_AND_CAST(tm, optval, struct sctp_assoc_value, optsize);
|
||||
SCTP_FIND_STCB(inp, stcb, tm->assoc_id);
|
||||
struct sctp_sack_info *sack;
|
||||
|
||||
SCTP_CHECK_AND_CAST(sack, optval, struct sctp_sack_info, optsize);
|
||||
SCTP_FIND_STCB(inp, stcb, sack->sack_assoc_id);
|
||||
if (stcb) {
|
||||
stcb->asoc.delayed_ack = tm->assoc_value;
|
||||
if (sack->sack_delay) {
|
||||
if (MSEC_TO_TICKS(sack->sack_delay) < 1) {
|
||||
sack->sack_delay = TICKS_TO_MSEC(1);
|
||||
}
|
||||
stcb->asoc.delayed_ack = sack->sack_delay;
|
||||
}
|
||||
if (sack->sack_freq) {
|
||||
stcb->asoc.sack_freq = sack->sack_freq;
|
||||
}
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
} else {
|
||||
SCTP_INP_WLOCK(inp);
|
||||
inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV] = MSEC_TO_TICKS(tm->assoc_value);
|
||||
if (sack->sack_delay) {
|
||||
if (MSEC_TO_TICKS(sack->sack_delay) < 1) {
|
||||
sack->sack_delay = TICKS_TO_MSEC(1);
|
||||
}
|
||||
inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV] = MSEC_TO_TICKS(sack->sack_delay);
|
||||
}
|
||||
if (sack->sack_freq) {
|
||||
inp->sctp_ep.sctp_sack_freq = sack->sack_freq;
|
||||
}
|
||||
SCTP_INP_WUNLOCK(inp);
|
||||
}
|
||||
break;
|
||||
@ -2618,7 +2674,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
|
||||
struct sctp_hmacalgo *shmac;
|
||||
sctp_hmaclist_t *hmaclist;
|
||||
uint32_t hmacid;
|
||||
size_t size, i;
|
||||
size_t size, i, found;
|
||||
|
||||
SCTP_CHECK_AND_CAST(shmac, optval, struct sctp_hmacalgo, optsize);
|
||||
size = (optsize - sizeof(*shmac)) / sizeof(shmac->shmac_idents[0]);
|
||||
@ -2636,6 +2692,18 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
|
||||
goto sctp_set_hmac_done;
|
||||
}
|
||||
}
|
||||
found = 0;
|
||||
for (i = 0; i < hmaclist->num_algo; i++) {
|
||||
if (hmaclist->hmac[i] == SCTP_AUTH_HMAC_ID_SHA1) {
|
||||
/* already in list */
|
||||
found = 1;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
sctp_free_hmaclist(hmaclist);
|
||||
error = EINVAL;
|
||||
break;
|
||||
}
|
||||
/* set it on the endpoint */
|
||||
SCTP_INP_WLOCK(inp);
|
||||
if (inp->sctp_ep.local_hmacs)
|
||||
@ -2828,7 +2896,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
}
|
||||
break;
|
||||
case SCTP_MAXBURST:
|
||||
case SCTP_MAX_BURST:
|
||||
{
|
||||
uint8_t *burst;
|
||||
|
||||
@ -2849,16 +2917,20 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
|
||||
SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
|
||||
SCTP_FIND_STCB(inp, stcb, av->assoc_id);
|
||||
|
||||
if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
|
||||
ovh = SCTP_MED_OVERHEAD;
|
||||
} else {
|
||||
ovh = SCTP_MED_V4_OVERHEAD;
|
||||
}
|
||||
if (stcb) {
|
||||
error = EINVAL;
|
||||
if (av->assoc_value) {
|
||||
stcb->asoc.sctp_frag_point = (av->assoc_value + ovh);
|
||||
} else {
|
||||
stcb->asoc.sctp_frag_point = SCTP_DEFAULT_MAXSEGMENT;
|
||||
}
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
} else {
|
||||
SCTP_INP_WLOCK(inp);
|
||||
if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
|
||||
ovh = SCTP_MED_OVERHEAD;
|
||||
} else {
|
||||
ovh = SCTP_MED_V4_OVERHEAD;
|
||||
}
|
||||
/*
|
||||
* FIXME MT: I think this is not in tune
|
||||
* with the API ID
|
||||
@ -2866,7 +2938,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
|
||||
if (av->assoc_value) {
|
||||
inp->sctp_frag_point = (av->assoc_value + ovh);
|
||||
} else {
|
||||
error = EINVAL;
|
||||
inp->sctp_frag_point = SCTP_DEFAULT_MAXSEGMENT;
|
||||
}
|
||||
SCTP_INP_WUNLOCK(inp);
|
||||
}
|
||||
@ -2973,14 +3045,14 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
|
||||
|
||||
if (stcb) {
|
||||
if (s_info->sinfo_stream <= stcb->asoc.streamoutcnt) {
|
||||
stcb->asoc.def_send = *s_info;
|
||||
memcpy(&stcb->asoc.def_send, s_info, min(optsize, sizeof(stcb->asoc.def_send)));
|
||||
} else {
|
||||
error = EINVAL;
|
||||
}
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
} else {
|
||||
SCTP_INP_WLOCK(inp);
|
||||
inp->def_send = *s_info;
|
||||
memcpy(&inp->def_send, s_info, min(optsize, sizeof(inp->def_send)));
|
||||
SCTP_INP_WUNLOCK(inp);
|
||||
}
|
||||
}
|
||||
@ -3012,14 +3084,31 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
|
||||
SCTP_INP_DECR_REF(inp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* sanity checks */
|
||||
if ((paddrp->spp_flags & SPP_HB_ENABLE) && (paddrp->spp_flags & SPP_HB_DISABLE)) {
|
||||
if (stcb)
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
return (EINVAL);
|
||||
}
|
||||
if ((paddrp->spp_flags & SPP_PMTUD_ENABLE) && (paddrp->spp_flags & SPP_PMTUD_DISABLE)) {
|
||||
if (stcb)
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
return (EINVAL);
|
||||
}
|
||||
if (stcb) {
|
||||
/************************TCB SPECIFIC SET ******************/
|
||||
/*
|
||||
* do we change the timer for HB, we run
|
||||
* only one?
|
||||
*/
|
||||
int ovh = 0;
|
||||
|
||||
if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
|
||||
ovh = SCTP_MED_OVERHEAD;
|
||||
} else {
|
||||
ovh = SCTP_MED_V4_OVERHEAD;
|
||||
}
|
||||
|
||||
if (paddrp->spp_hbinterval)
|
||||
stcb->asoc.heart_beat_delay = paddrp->spp_hbinterval;
|
||||
else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO)
|
||||
@ -3038,13 +3127,13 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
|
||||
if (paddrp->spp_flags & SPP_HB_ENABLE) {
|
||||
net->dest_state &= ~SCTP_ADDR_NOHB;
|
||||
}
|
||||
if (paddrp->spp_flags & SPP_PMTUD_DISABLE) {
|
||||
if ((paddrp->spp_flags & SPP_PMTUD_DISABLE) && (paddrp->spp_pathmtu >= SCTP_SMALLEST_PMTU)) {
|
||||
if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
|
||||
sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net,
|
||||
SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10);
|
||||
}
|
||||
if (paddrp->spp_pathmtu > SCTP_DEFAULT_MINSEGMENT) {
|
||||
net->mtu = paddrp->spp_pathmtu;
|
||||
net->mtu = paddrp->spp_pathmtu + ovh;
|
||||
if (net->mtu < stcb->asoc.smallest_mtu) {
|
||||
#ifdef SCTP_PRINT_FOR_B_AND_M
|
||||
SCTP_PRINTF("SCTP_PMTU_DISABLE calls sctp_pathmtu_adjustment:%d\n",
|
||||
@ -3085,6 +3174,31 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
|
||||
stcb->asoc.hb_is_disabled = 0;
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net);
|
||||
}
|
||||
if ((paddrp->spp_flags & SPP_PMTUD_DISABLE) && (paddrp->spp_pathmtu >= SCTP_SMALLEST_PMTU)) {
|
||||
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
|
||||
if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
|
||||
sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net,
|
||||
SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10);
|
||||
}
|
||||
if (paddrp->spp_pathmtu > SCTP_DEFAULT_MINSEGMENT) {
|
||||
net->mtu = paddrp->spp_pathmtu + ovh;
|
||||
if (net->mtu < stcb->asoc.smallest_mtu) {
|
||||
#ifdef SCTP_PRINT_FOR_B_AND_M
|
||||
SCTP_PRINTF("SCTP_PMTU_DISABLE calls sctp_pathmtu_adjustment:%d\n",
|
||||
net->mtu);
|
||||
#endif
|
||||
sctp_pathmtu_adjustment(inp, stcb, net, net->mtu);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (paddrp->spp_flags & SPP_PMTUD_ENABLE) {
|
||||
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
|
||||
if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (paddrp->spp_flags & SPP_HB_DISABLE) {
|
||||
int cnt_of_unconf = 0;
|
||||
struct sctp_nets *lnet;
|
||||
@ -3101,12 +3215,17 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
|
||||
* addresses
|
||||
*/
|
||||
if (cnt_of_unconf == 0) {
|
||||
sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_11);
|
||||
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
|
||||
sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net,
|
||||
SCTP_FROM_SCTP_USRREQ + SCTP_LOC_11);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (paddrp->spp_flags & SPP_HB_ENABLE) {
|
||||
/* start up the timer. */
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net);
|
||||
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net);
|
||||
}
|
||||
}
|
||||
#ifdef INET
|
||||
if (paddrp->spp_flags & SPP_IPV4_TOS)
|
||||
@ -3129,9 +3248,14 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
|
||||
if (paddrp->spp_pathmaxrxt) {
|
||||
inp->sctp_ep.def_net_failure = paddrp->spp_pathmaxrxt;
|
||||
}
|
||||
if (paddrp->spp_flags & SPP_HB_ENABLE) {
|
||||
if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO)
|
||||
inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = 0;
|
||||
else if (paddrp->spp_hbinterval)
|
||||
inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = MSEC_TO_TICKS(paddrp->spp_hbinterval);
|
||||
|
||||
if (paddrp->spp_flags & SPP_HB_ENABLE) {
|
||||
sctp_feature_off(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT);
|
||||
|
||||
} else if (paddrp->spp_flags & SPP_HB_DISABLE) {
|
||||
sctp_feature_on(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT);
|
||||
}
|
||||
@ -3206,11 +3330,10 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
|
||||
sasoc->sasoc_number_peer_destinations = stcb->asoc.numnets;
|
||||
sasoc->sasoc_peer_rwnd = 0;
|
||||
sasoc->sasoc_local_rwnd = 0;
|
||||
if (sasoc->sasoc_cookie_life)
|
||||
if (sasoc->sasoc_cookie_life) {
|
||||
if (sasoc->sasoc_cookie_life < 1000)
|
||||
sasoc->sasoc_cookie_life = 1000;
|
||||
stcb->asoc.cookie_life = MSEC_TO_TICKS(sasoc->sasoc_cookie_life);
|
||||
stcb->asoc.delayed_ack = sasoc->sasoc_sack_delay;
|
||||
if (sasoc->sasoc_sack_freq) {
|
||||
stcb->asoc.sack_freq = sasoc->sasoc_sack_freq;
|
||||
}
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
} else {
|
||||
@ -3220,11 +3343,10 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
|
||||
sasoc->sasoc_number_peer_destinations = 0;
|
||||
sasoc->sasoc_peer_rwnd = 0;
|
||||
sasoc->sasoc_local_rwnd = 0;
|
||||
if (sasoc->sasoc_cookie_life)
|
||||
if (sasoc->sasoc_cookie_life) {
|
||||
if (sasoc->sasoc_cookie_life < 1000)
|
||||
sasoc->sasoc_cookie_life = 1000;
|
||||
inp->sctp_ep.def_cookie_life = MSEC_TO_TICKS(sasoc->sasoc_cookie_life);
|
||||
inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV] = MSEC_TO_TICKS(sasoc->sasoc_sack_delay);
|
||||
if (sasoc->sasoc_sack_freq) {
|
||||
inp->sctp_ep.sctp_sack_freq = sasoc->sasoc_sack_freq;
|
||||
}
|
||||
SCTP_INP_WUNLOCK(inp);
|
||||
}
|
||||
@ -3320,9 +3442,43 @@ 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 != NULL) {
|
||||
if (sctp_set_primary_ip_address_sa(stcb, (struct sockaddr *)&sspp->sspp_addr) != 0) {
|
||||
struct sctp_ifa *ifa;
|
||||
|
||||
ifa = sctp_find_ifa_by_addr((struct sockaddr *)&sspp->sspp_addr,
|
||||
stcb->asoc.vrf_id, 0);
|
||||
if (ifa == NULL) {
|
||||
error = EINVAL;
|
||||
goto out_of_it;
|
||||
}
|
||||
if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) {
|
||||
/*
|
||||
* Must validate the ifa found is in
|
||||
* our ep
|
||||
*/
|
||||
struct sctp_laddr *laddr;
|
||||
int found = 0;
|
||||
|
||||
LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
|
||||
if (laddr->ifa == NULL) {
|
||||
SCTPDBG(SCTP_DEBUG_OUTPUT1, "%s: NULL ifa\n",
|
||||
__FUNCTION__);
|
||||
continue;
|
||||
}
|
||||
if (laddr->ifa == ifa) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
error = EINVAL;
|
||||
goto out_of_it;
|
||||
}
|
||||
}
|
||||
if (sctp_set_primary_ip_address_sa(stcb,
|
||||
(struct sockaddr *)&sspp->sspp_addr) != 0) {
|
||||
error = EINVAL;
|
||||
}
|
||||
out_of_it:
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
} else {
|
||||
error = EINVAL;
|
||||
@ -3349,6 +3505,10 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
|
||||
if (addrs->addr->sa_family == AF_INET6) {
|
||||
struct sockaddr_in6 *sin6;
|
||||
|
||||
if (addrs->addr->sa_len != sizeof(struct sockaddr_in6)) {
|
||||
error = EINVAL;
|
||||
break;
|
||||
}
|
||||
sin6 = (struct sockaddr_in6 *)addr_touse;
|
||||
if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
|
||||
in6_sin6_2_sin(&sin, sin6);
|
||||
@ -3356,7 +3516,14 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (addrs->addr->sa_family == AF_INET) {
|
||||
if (addrs->addr->sa_len != sizeof(struct sockaddr_in)) {
|
||||
error = EINVAL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) {
|
||||
|
||||
if (p == NULL) {
|
||||
/* Can't get proc for Net/Open BSD */
|
||||
error = EINVAL;
|
||||
@ -3423,6 +3590,10 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
|
||||
if (addrs->addr->sa_family == AF_INET6) {
|
||||
struct sockaddr_in6 *sin6;
|
||||
|
||||
if (addrs->addr->sa_len != sizeof(struct sockaddr_in6)) {
|
||||
error = EINVAL;
|
||||
break;
|
||||
}
|
||||
sin6 = (struct sockaddr_in6 *)addr_touse;
|
||||
if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
|
||||
in6_sin6_2_sin(&sin, sin6);
|
||||
@ -3430,6 +3601,12 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (addrs->addr->sa_family == AF_INET) {
|
||||
if (addrs->addr->sa_len != sizeof(struct sockaddr_in)) {
|
||||
error = EINVAL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* No lock required mgmt_ep_sa does its own locking.
|
||||
* If the FIX: below is ever changed we may need to
|
||||
@ -3525,6 +3702,15 @@ sctp_connect(struct socket *so, struct sockaddr *addr, struct thread *p)
|
||||
/* I made the same as TCP since we are not setup? */
|
||||
return (ECONNRESET);
|
||||
}
|
||||
if (addr == NULL)
|
||||
return EINVAL;
|
||||
|
||||
if ((addr->sa_family == AF_INET6) && (addr->sa_len != sizeof(struct sockaddr_in6))) {
|
||||
return (EINVAL);
|
||||
}
|
||||
if ((addr->sa_family == AF_INET) && (addr->sa_len != sizeof(struct sockaddr_in))) {
|
||||
return (EINVAL);
|
||||
}
|
||||
SCTP_ASOC_CREATE_LOCK(inp);
|
||||
create_lock_on = 1;
|
||||
|
||||
|
@ -923,6 +923,7 @@ sctp_init_asoc(struct sctp_inpcb *m, struct sctp_association *asoc,
|
||||
asoc->heart_beat_delay = TICKS_TO_MSEC(m->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT]);
|
||||
asoc->cookie_life = m->sctp_ep.def_cookie_life;
|
||||
asoc->sctp_cmt_on_off = (uint8_t) sctp_cmt_on_off;
|
||||
asoc->sctp_frag_point = m->sctp_frag_point;
|
||||
#ifdef INET
|
||||
asoc->default_tos = m->ip_inp.inp.inp_ip_tos;
|
||||
#else
|
||||
@ -1453,6 +1454,11 @@ sctp_timeout_handler(void *t)
|
||||
|
||||
/* call the handler for the appropriate timer type */
|
||||
switch (tmr->type) {
|
||||
case SCTP_TIMER_TYPE_ZERO_COPY:
|
||||
if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_ZERO_COPY_ACTIVE)) {
|
||||
SCTP_ZERO_COPY_EVENT(inp, inp->sctp_socket);
|
||||
}
|
||||
break;
|
||||
case SCTP_TIMER_TYPE_ADDR_WQ:
|
||||
sctp_handle_addr_wq();
|
||||
break;
|
||||
@ -1770,6 +1776,10 @@ sctp_timer_start(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
|
||||
SCTP_TCB_LOCK_ASSERT(stcb);
|
||||
}
|
||||
switch (t_type) {
|
||||
case SCTP_TIMER_TYPE_ZERO_COPY:
|
||||
tmr = &inp->sctp_ep.zero_copy_timer;
|
||||
to_ticks = SCTP_ZERO_COPY_TICK_DELAY;
|
||||
break;
|
||||
case SCTP_TIMER_TYPE_ADDR_WQ:
|
||||
/* Only 1 tick away :-) */
|
||||
tmr = &sctppcbinfo.addr_wq_timer;
|
||||
@ -2117,6 +2127,10 @@ sctp_timer_stop(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
|
||||
SCTP_TCB_LOCK_ASSERT(stcb);
|
||||
}
|
||||
switch (t_type) {
|
||||
case SCTP_TIMER_TYPE_ZERO_COPY:
|
||||
tmr = &inp->sctp_ep.zero_copy_timer;
|
||||
break;
|
||||
|
||||
case SCTP_TIMER_TYPE_ADDR_WQ:
|
||||
tmr = &sctppcbinfo.addr_wq_timer;
|
||||
break;
|
||||
@ -5214,9 +5228,7 @@ sctp_sorecvmsg(struct socket *so,
|
||||
copied_so_far += cp_len;
|
||||
}
|
||||
}
|
||||
if ((out_flags & MSG_EOR) ||
|
||||
(uio->uio_resid == 0)
|
||||
) {
|
||||
if ((out_flags & MSG_EOR) || (uio->uio_resid == 0)) {
|
||||
break;
|
||||
}
|
||||
if (((stcb) && (in_flags & MSG_PEEK) == 0) &&
|
||||
@ -5238,8 +5250,7 @@ sctp_sorecvmsg(struct socket *so,
|
||||
* a MSG_EOR/or read all the user wants... <OR>
|
||||
* control->length == 0.
|
||||
*/
|
||||
if ((out_flags & MSG_EOR) &&
|
||||
((in_flags & MSG_PEEK) == 0)) {
|
||||
if ((out_flags & MSG_EOR) && ((in_flags & MSG_PEEK) == 0)) {
|
||||
/* we are done with this control */
|
||||
if (control->length == 0) {
|
||||
if (control->data) {
|
||||
@ -5592,6 +5603,7 @@ sctp_dynamic_set_primary(struct sockaddr *sa, uint32_t vrf_id)
|
||||
/* Now incr the count and int wi structure */
|
||||
SCTP_INCR_LADDR_COUNT();
|
||||
bzero(wi, sizeof(*wi));
|
||||
(void)SCTP_GETTIME_TIMEVAL(&wi->start_time);
|
||||
wi->ifa = ifa;
|
||||
wi->action = SCTP_SET_PRIM_ADDR;
|
||||
atomic_add_int(&ifa->refcount, 1);
|
||||
@ -5739,7 +5751,8 @@ sctp_l_soreceive(struct socket *so,
|
||||
|
||||
|
||||
int
|
||||
sctp_connectx_helper_add(struct sctp_tcb *stcb, struct sockaddr *addr, int totaddr, int *error)
|
||||
sctp_connectx_helper_add(struct sctp_tcb *stcb, struct sockaddr *addr,
|
||||
int totaddr, int *error)
|
||||
{
|
||||
int added = 0;
|
||||
int i;
|
||||
@ -5777,8 +5790,9 @@ sctp_connectx_helper_add(struct sctp_tcb *stcb, struct sockaddr *addr, int totad
|
||||
}
|
||||
|
||||
struct sctp_tcb *
|
||||
sctp_connectx_helper_find(struct sctp_inpcb *inp, struct sockaddr *addr, int *totaddr,
|
||||
int *num_v4, int *num_v6, int *error, int max)
|
||||
sctp_connectx_helper_find(struct sctp_inpcb *inp, struct sockaddr *addr,
|
||||
int *totaddr, int *num_v4, int *num_v6, int *error,
|
||||
int limit, int *bad_addr)
|
||||
{
|
||||
struct sockaddr *sa;
|
||||
struct sctp_tcb *stcb = NULL;
|
||||
@ -5792,6 +5806,11 @@ sctp_connectx_helper_find(struct sctp_inpcb *inp, struct sockaddr *addr, int *to
|
||||
if (sa->sa_family == AF_INET) {
|
||||
(*num_v4) += 1;
|
||||
incr = sizeof(struct sockaddr_in);
|
||||
if (sa->sa_len != incr) {
|
||||
*error = EINVAL;
|
||||
*bad_addr = 1;
|
||||
return (NULL);
|
||||
}
|
||||
} else if (sa->sa_family == AF_INET6) {
|
||||
struct sockaddr_in6 *sin6;
|
||||
|
||||
@ -5799,21 +5818,30 @@ sctp_connectx_helper_find(struct sctp_inpcb *inp, struct sockaddr *addr, int *to
|
||||
if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
|
||||
/* Must be non-mapped for connectx */
|
||||
*error = EINVAL;
|
||||
*bad_addr = 1;
|
||||
return (NULL);
|
||||
}
|
||||
(*num_v6) += 1;
|
||||
incr = sizeof(struct sockaddr_in6);
|
||||
if (sa->sa_len != incr) {
|
||||
*error = EINVAL;
|
||||
*bad_addr = 1;
|
||||
return (NULL);
|
||||
}
|
||||
} else {
|
||||
*totaddr = i;
|
||||
/* we are done */
|
||||
break;
|
||||
}
|
||||
SCTP_INP_INCR_REF(inp);
|
||||
stcb = sctp_findassociation_ep_addr(&inp, sa, NULL, NULL, NULL);
|
||||
if (stcb != NULL) {
|
||||
/* Already have or am bring up an association */
|
||||
return (stcb);
|
||||
} else {
|
||||
SCTP_INP_DECR_REF(inp);
|
||||
}
|
||||
if ((at + incr) > max) {
|
||||
if ((at + incr) > limit) {
|
||||
*totaddr = i;
|
||||
break;
|
||||
}
|
||||
|
@ -219,11 +219,13 @@ void
|
||||
sctp_handle_ootb(struct mbuf *, int, int, struct sctphdr *,
|
||||
struct sctp_inpcb *, struct mbuf *, uint32_t, uint32_t);
|
||||
|
||||
int sctp_connectx_helper_add(struct sctp_tcb *stcb, struct sockaddr *addr, int totaddr, int *error);
|
||||
int
|
||||
sctp_connectx_helper_add(struct sctp_tcb *stcb, struct sockaddr *addr,
|
||||
int totaddr, int *error);
|
||||
|
||||
struct sctp_tcb *
|
||||
sctp_connectx_helper_find(struct sctp_inpcb *inp, struct sockaddr *addr, int *totaddr,
|
||||
int *num_v4, int *num_v6, int *error, int max);
|
||||
sctp_connectx_helper_find(struct sctp_inpcb *inp, struct sockaddr *addr,
|
||||
int *totaddr, int *num_v4, int *num_v6, int *error, int limit, int *bad_addr);
|
||||
|
||||
int sctp_is_there_an_abort_here(struct mbuf *, int, uint32_t *);
|
||||
uint32_t sctp_is_same_scope(struct sockaddr_in6 *, struct sockaddr_in6 *);
|
||||
|
@ -76,6 +76,7 @@ sctp6_input(i_pak, offp, proto)
|
||||
int length, mlen, offset, iphlen;
|
||||
uint8_t ecn_bits;
|
||||
struct sctp_tcb *stcb = NULL;
|
||||
int pkt_len = 0;
|
||||
int off = *offp;
|
||||
|
||||
/* get the VRF and table id's */
|
||||
@ -88,10 +89,12 @@ sctp6_input(i_pak, offp, proto)
|
||||
return (-1);
|
||||
}
|
||||
m = SCTP_HEADER_TO_CHAIN(*i_pak);
|
||||
pkt_len = SCTP_HEADER_LEN((*i_pak));
|
||||
|
||||
ip6 = mtod(m, struct ip6_hdr *);
|
||||
/* Ensure that (sctphdr + sctp_chunkhdr) in a row. */
|
||||
IP6_EXTHDR_GET(sh, struct sctphdr *, m, off, sizeof(*sh) + sizeof(*ch));
|
||||
IP6_EXTHDR_GET(sh, struct sctphdr *, m, off,
|
||||
(int)(sizeof(*sh) + sizeof(*ch)));
|
||||
if (sh == NULL) {
|
||||
SCTP_STAT_INCR(sctps_hdrops);
|
||||
return IPPROTO_DONE;
|
||||
@ -110,7 +113,7 @@ sctp6_input(i_pak, offp, proto)
|
||||
SCTP_STAT_INCR(sctps_recvpackets);
|
||||
SCTP_STAT_INCR_COUNTER64(sctps_inpackets);
|
||||
SCTPDBG(SCTP_DEBUG_INPUT1, "V6 input gets a packet iphlen:%d pktlen:%d\n",
|
||||
iphlen, SCTP_HEADER_LEN((*i_pak)));
|
||||
iphlen, pkt_len);
|
||||
if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
|
||||
/* No multi-cast support in SCTP */
|
||||
goto bad;
|
||||
@ -588,6 +591,16 @@ sctp6_bind(struct socket *so, struct sockaddr *addr, struct thread *p)
|
||||
if (inp == 0)
|
||||
return EINVAL;
|
||||
|
||||
if (addr) {
|
||||
if ((addr->sa_family == AF_INET6) &&
|
||||
(addr->sa_len != sizeof(struct sockaddr_in6))) {
|
||||
return EINVAL;
|
||||
}
|
||||
if ((addr->sa_family == AF_INET) &&
|
||||
(addr->sa_len != sizeof(struct sockaddr_in))) {
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
inp6 = (struct in6pcb *)inp;
|
||||
inp6->inp_vflag &= ~INP_IPV4;
|
||||
inp6->inp_vflag |= INP_IPV6;
|
||||
@ -938,6 +951,15 @@ sctp6_connect(struct socket *so, struct sockaddr *addr, struct thread *p)
|
||||
return (ECONNRESET); /* I made the same as TCP since we are
|
||||
* not setup? */
|
||||
}
|
||||
if (addr == NULL) {
|
||||
return (EINVAL);
|
||||
}
|
||||
if ((addr->sa_family == AF_INET6) && (addr->sa_len != sizeof(struct sockaddr_in6))) {
|
||||
return (EINVAL);
|
||||
}
|
||||
if ((addr->sa_family == AF_INET) && (addr->sa_len != sizeof(struct sockaddr_in))) {
|
||||
return (EINVAL);
|
||||
}
|
||||
vrf_id = inp->def_vrf_id;
|
||||
SCTP_ASOC_CREATE_LOCK(inp);
|
||||
SCTP_INP_RLOCK(inp);
|
||||
|
Loading…
Reference in New Issue
Block a user