- 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:
Randall Stewart 2007-05-28 11:17:24 +00:00
parent a160e6302c
commit d61a0ae066
17 changed files with 810 additions and 359 deletions

View File

@ -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_ */

View File

@ -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;

View File

@ -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

View File

@ -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++) {

View File

@ -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);

View File

@ -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, &params, 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) {

View File

@ -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);

View File

@ -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).

View File

@ -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);
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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) &&

View File

@ -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 */
};

View File

@ -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;

View File

@ -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;
}

View File

@ -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 *);

View File

@ -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);