summaryrefslogtreecommitdiffstats
path: root/sys/netinet/sctputil.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netinet/sctputil.c')
-rw-r--r--sys/netinet/sctputil.c466
1 files changed, 369 insertions, 97 deletions
diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c
index 8372ba6..e3c240c 100644
--- a/sys/netinet/sctputil.c
+++ b/sys/netinet/sctputil.c
@@ -37,6 +37,7 @@ __FBSDID("$FreeBSD$");
#include <netinet/sctp_pcb.h>
#include <netinet/sctputil.h>
#include <netinet/sctp_var.h>
+#include <netinet/sctp_sysctl.h>
#ifdef INET6
#include <netinet6/sctp6_var.h>
#endif
@@ -48,16 +49,10 @@ __FBSDID("$FreeBSD$");
#include <netinet/sctp_indata.h>/* for sctp_deliver_data() */
#include <netinet/sctp_auth.h>
#include <netinet/sctp_asconf.h>
-
-extern int sctp_warm_the_crc32_table;
+#include <netinet/sctp_bsd_addr.h>
#define NUMBER_OF_MTU_SIZES 18
-#ifdef SCTP_DEBUG
-extern uint32_t sctp_debug_on;
-
-#endif
-
#ifdef SCTP_STAT_LOGGING
int global_sctp_cwnd_log_at = 0;
@@ -489,22 +484,22 @@ sctp_log_block(uint8_t from, struct socket *so, struct sctp_association *asoc, i
}
int
-sctp_fill_stat_log(struct mbuf *m)
+sctp_fill_stat_log(void *optval, size_t *optsize)
{
int sctp_cwnd_log_at;
struct sctp_cwnd_log_req *req;
size_t size_limit;
int num, i, at, cnt_out = 0;
- if (m == NULL)
+ if (*optsize < sizeof(struct sctp_cwnd_log_req)) {
return (EINVAL);
-
- size_limit = (SCTP_BUF_LEN(m) - sizeof(struct sctp_cwnd_log_req));
+ }
+ size_limit = (*optsize - sizeof(struct sctp_cwnd_log_req));
if (size_limit < sizeof(struct sctp_cwnd_log)) {
return (EINVAL);
}
sctp_cwnd_log_at = global_sctp_cwnd_log_at;
- req = mtod(m, struct sctp_cwnd_log_req *);
+ req = (struct sctp_cwnd_log_req *)optval;
num = size_limit / sizeof(struct sctp_cwnd_log);
if (global_sctp_cwnd_log_rolled) {
req->num_in_log = SCTP_STAT_LOG_SIZE;
@@ -569,7 +564,7 @@ sctp_fill_stat_log(struct mbuf *m)
if (at >= SCTP_STAT_LOG_SIZE)
at = 0;
}
- SCTP_BUF_LEN(m) = (cnt_out * sizeof(struct sctp_cwnd_log)) + sizeof(struct sctp_cwnd_log_req);
+ *optsize = (cnt_out * sizeof(struct sctp_cwnd_log)) + sizeof(struct sctp_cwnd_log_req);
return (0);
}
@@ -909,7 +904,7 @@ sctp_select_a_tag(struct sctp_inpcb *m)
int
sctp_init_asoc(struct sctp_inpcb *m, struct sctp_association *asoc,
- int for_a_init, uint32_t override_tag)
+ int for_a_init, uint32_t override_tag, uint32_t vrf_id)
{
/*
* Anything set to zero is taken care of by the allocation routine's
@@ -930,13 +925,13 @@ 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;
-#ifdef AF_INET
+#ifdef INET
asoc->default_tos = m->ip_inp.inp.inp_ip_tos;
#else
asoc->default_tos = 0;
#endif
-#ifdef AF_INET6
+#ifdef INET6
asoc->default_flowlabel = ((struct in6pcb *)m)->in6p_flowinfo;
#else
asoc->default_flowlabel = 0;
@@ -957,6 +952,7 @@ sctp_init_asoc(struct sctp_inpcb *m, struct sctp_association *asoc,
/* Get the nonce tags */
asoc->my_vtag_nonce = sctp_select_a_tag(m);
asoc->peer_vtag_nonce = sctp_select_a_tag(m);
+ asoc->vrf_id = vrf_id;
if (sctp_is_feature_on(m, SCTP_PCB_FLAGS_DONOT_HEARTBEAT))
asoc->hb_is_disabled = 1;
@@ -1005,6 +1001,7 @@ sctp_init_asoc(struct sctp_inpcb *m, struct sctp_association *asoc,
asoc->nonce_wait_for_ecne = 0;
asoc->nonce_wait_tsn = 0;
asoc->delayed_ack = TICKS_TO_MSEC(m->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV]);
+ asoc->sack_freq = m->sctp_ep.sctp_sack_freq;
asoc->pr_sctp_cnt = 0;
asoc->total_output_queue_size = 0;
@@ -1039,7 +1036,10 @@ sctp_init_asoc(struct sctp_inpcb *m, struct sctp_association *asoc,
asoc->ecn_echo_cnt_onq = 0;
asoc->stream_locked = 0;
- LIST_INIT(&asoc->sctp_local_addr_list);
+ asoc->send_sack = 1;
+
+ LIST_INIT(&asoc->sctp_restricted_addrs);
+
TAILQ_INIT(&asoc->nets);
TAILQ_INIT(&asoc->pending_reply_queue);
asoc->last_asconf_ack_sent = NULL;
@@ -1141,36 +1141,207 @@ sctp_expand_mapping_array(struct sctp_association *asoc)
return (0);
}
-extern unsigned int sctp_early_fr_msec;
+#if defined(SCTP_USE_THREAD_BASED_ITERATOR)
+static void
+sctp_iterator_work(struct sctp_iterator *it)
+{
+ int iteration_count = 0;
+ int inp_skip = 0;
+
+ SCTP_ITERATOR_LOCK();
+ if (it->inp)
+ SCTP_INP_DECR_REF(it->inp);
+
+ if (it->inp == NULL) {
+ /* iterator is complete */
+done_with_iterator:
+ SCTP_ITERATOR_UNLOCK();
+ if (it->function_atend != NULL) {
+ (*it->function_atend) (it->pointer, it->val);
+ }
+ SCTP_FREE(it);
+ return;
+ }
+select_a_new_ep:
+ SCTP_INP_WLOCK(it->inp);
+ while (((it->pcb_flags) &&
+ ((it->inp->sctp_flags & it->pcb_flags) != it->pcb_flags)) ||
+ ((it->pcb_features) &&
+ ((it->inp->sctp_features & it->pcb_features) != it->pcb_features))) {
+ /* endpoint flags or features don't match, so keep looking */
+ if (it->iterator_flags & SCTP_ITERATOR_DO_SINGLE_INP) {
+ SCTP_INP_WUNLOCK(it->inp);
+ goto done_with_iterator;
+ }
+ SCTP_INP_WUNLOCK(it->inp);
+ it->inp = LIST_NEXT(it->inp, sctp_list);
+ if (it->inp == NULL) {
+ goto done_with_iterator;
+ }
+ SCTP_INP_WLOCK(it->inp);
+ }
+
+ /* mark the current iterator on the endpoint */
+ it->inp->inp_starting_point_for_iterator = it;
+ SCTP_INP_WUNLOCK(it->inp);
+ SCTP_INP_RLOCK(it->inp);
+
+ /* now go through each assoc which is in the desired state */
+ if (it->done_current_ep == 0) {
+ if (it->function_inp != NULL)
+ inp_skip = (*it->function_inp) (it->inp, it->pointer, it->val);
+ it->done_current_ep = 1;
+ }
+ if (it->stcb == NULL) {
+ /* run the per instance function */
+ it->stcb = LIST_FIRST(&it->inp->sctp_asoc_list);
+ }
+ if ((inp_skip) || it->stcb == NULL) {
+ if (it->function_inp_end != NULL) {
+ inp_skip = (*it->function_inp_end) (it->inp,
+ it->pointer,
+ it->val);
+ }
+ SCTP_INP_RUNLOCK(it->inp);
+ goto no_stcb;
+ }
+ if ((it->stcb) &&
+ (it->stcb->asoc.stcb_starting_point_for_iterator == it)) {
+ it->stcb->asoc.stcb_starting_point_for_iterator = NULL;
+ }
+ while (it->stcb) {
+ SCTP_TCB_LOCK(it->stcb);
+ if (it->asoc_state && ((it->stcb->asoc.state & it->asoc_state) != it->asoc_state)) {
+ /* not in the right state... keep looking */
+ SCTP_TCB_UNLOCK(it->stcb);
+ goto next_assoc;
+ }
+ /* mark the current iterator on the assoc */
+ it->stcb->asoc.stcb_starting_point_for_iterator = it;
+ /* see if we have limited out the iterator loop */
+ iteration_count++;
+ if (iteration_count > SCTP_ITERATOR_MAX_AT_ONCE) {
+ /* Pause to let others grab the lock */
+ atomic_add_int(&it->stcb->asoc.refcnt, 1);
+ SCTP_TCB_UNLOCK(it->stcb);
+ SCTP_INP_RUNLOCK(it->inp);
+ SCTP_ITERATOR_UNLOCK();
+ SCTP_ITERATOR_LOCK();
+ SCTP_INP_RLOCK(it->inp);
+ SCTP_TCB_LOCK(it->stcb);
+ atomic_add_int(&it->stcb->asoc.refcnt, -1);
+ iteration_count = 0;
+ }
+ /* run function on this one */
+ (*it->function_assoc) (it->inp, it->stcb, it->pointer, it->val);
+
+ /*
+ * we lie here, it really needs to have its own type but
+ * first I must verify that this won't effect things :-0
+ */
+ if (it->no_chunk_output == 0)
+ sctp_chunk_output(it->inp, it->stcb, SCTP_OUTPUT_FROM_T3);
+
+ SCTP_TCB_UNLOCK(it->stcb);
+next_assoc:
+ it->stcb = LIST_NEXT(it->stcb, sctp_tcblist);
+ if (it->stcb == NULL) {
+ /* Run last function */
+ if (it->function_inp_end != NULL) {
+ inp_skip = (*it->function_inp_end) (it->inp,
+ it->pointer,
+ it->val);
+ }
+ }
+ }
+ SCTP_INP_RUNLOCK(it->inp);
+no_stcb:
+ /* done with all assocs on this endpoint, move on to next endpoint */
+ it->done_current_ep = 0;
+ SCTP_INP_WLOCK(it->inp);
+ it->inp->inp_starting_point_for_iterator = NULL;
+ SCTP_INP_WUNLOCK(it->inp);
+ if (it->iterator_flags & SCTP_ITERATOR_DO_SINGLE_INP) {
+ it->inp = NULL;
+ } else {
+ SCTP_INP_INFO_RLOCK();
+ it->inp = LIST_NEXT(it->inp, sctp_list);
+ SCTP_INP_INFO_RUNLOCK();
+ }
+ if (it->inp == NULL) {
+ goto done_with_iterator;
+ }
+ goto select_a_new_ep;
+}
+
+void
+sctp_iterator_worker(void)
+{
+ struct sctp_iterator *it = NULL;
+
+ /* This function is called with the WQ lock in place */
+
+ sctppcbinfo.iterator_running = 1;
+again:
+ it = TAILQ_FIRST(&sctppcbinfo.iteratorhead);
+ while (it) {
+ /* now lets work on this one */
+ TAILQ_REMOVE(&sctppcbinfo.iteratorhead, it, sctp_nxt_itr);
+ SCTP_IPI_ITERATOR_WQ_UNLOCK();
+ sctp_iterator_work(it);
+ SCTP_IPI_ITERATOR_WQ_LOCK();
+ it = TAILQ_FIRST(&sctppcbinfo.iteratorhead);
+ }
+ if (TAILQ_FIRST(&sctppcbinfo.iteratorhead)) {
+ goto again;
+ }
+ sctppcbinfo.iterator_running = 0;
+ return;
+}
+
+#endif
+
static void
sctp_handle_addr_wq(void)
{
/* deal with the ADDR wq from the rtsock calls */
struct sctp_laddr *wi;
+ struct sctp_asconf_iterator *asc;
- SCTP_IPI_ADDR_LOCK();
- wi = LIST_FIRST(&sctppcbinfo.addr_wq);
- if (wi == NULL) {
- SCTP_IPI_ADDR_UNLOCK();
- return;
- }
- LIST_REMOVE(wi, sctp_nxt_addr);
- if (!SCTP_LIST_EMPTY(&sctppcbinfo.addr_wq)) {
+ SCTP_MALLOC(asc, struct sctp_asconf_iterator *,
+ sizeof(struct sctp_asconf_iterator), "SCTP_ASCONF_ITERATOR");
+ if (asc == NULL) {
+ /* Try later, no memory */
sctp_timer_start(SCTP_TIMER_TYPE_ADDR_WQ,
(struct sctp_inpcb *)NULL,
(struct sctp_tcb *)NULL,
(struct sctp_nets *)NULL);
+ return;
}
- SCTP_IPI_ADDR_UNLOCK();
- if (wi->action == RTM_ADD) {
- sctp_add_ip_address(wi->ifa);
- } else if (wi->action == RTM_DELETE) {
- sctp_delete_ip_address(wi->ifa);
+ LIST_INIT(&asc->list_of_work);
+ asc->cnt = 0;
+ SCTP_IPI_ITERATOR_WQ_LOCK();
+ wi = LIST_FIRST(&sctppcbinfo.addr_wq);
+ while (wi != NULL) {
+ LIST_REMOVE(wi, sctp_nxt_addr);
+ LIST_INSERT_HEAD(&asc->list_of_work, wi, sctp_nxt_addr);
+ asc->cnt++;
+ wi = LIST_FIRST(&sctppcbinfo.addr_wq);
+ }
+ SCTP_IPI_ITERATOR_WQ_UNLOCK();
+ if (asc->cnt == 0) {
+ SCTP_FREE(asc);
+ } else {
+ sctp_initiate_iterator(sctp_iterator_ep,
+ sctp_iterator_stcb,
+ NULL, /* No ep end for boundall */
+ SCTP_PCB_FLAGS_BOUNDALL,
+ SCTP_PCB_ANY_FEATURES,
+ SCTP_ASOC_ANY_STATE, (void *)asc, 0,
+ sctp_iterator_end, NULL, 0);
}
- IFAFREE(wi->ifa);
- SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_laddr, wi);
- SCTP_DECR_LADDR_COUNT();
+
}
void
@@ -1564,7 +1735,7 @@ sctp_timer_start(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
case SCTP_TIMER_TYPE_ADDR_WQ:
/* Only 1 tick away :-) */
tmr = &sctppcbinfo.addr_wq_timer;
- to_ticks = 1;
+ to_ticks = SCTP_ADDRESS_TICK_DELAY;
break;
case SCTP_TIMER_TYPE_ITERATOR:
{
@@ -1658,14 +1829,11 @@ sctp_timer_start(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
rndval = sctp_select_initial_TSN(&inp->sctp_ep);
memcpy(stcb->asoc.hb_random_values, &rndval,
sizeof(stcb->asoc.hb_random_values));
- this_random = stcb->asoc.hb_random_values[0];
stcb->asoc.hb_random_idx = 0;
- stcb->asoc.hb_ect_randombit = 0;
- } else {
- this_random = stcb->asoc.hb_random_values[stcb->asoc.hb_random_idx];
- stcb->asoc.hb_random_idx++;
- stcb->asoc.hb_ect_randombit = 0;
}
+ this_random = stcb->asoc.hb_random_values[stcb->asoc.hb_random_idx];
+ stcb->asoc.hb_random_idx++;
+ stcb->asoc.hb_ect_randombit = 0;
/*
* this_random will be 0 - 256 ms RTO is in ms.
*/
@@ -2631,10 +2799,15 @@ sctp_notify_peer_addr_change(struct sctp_tcb *stcb, uint32_t state,
memcpy(&spc->spc_aaddr, sa, sizeof(struct sockaddr_in6));
- /* recover scope_id for user */
sin6 = (struct sockaddr_in6 *)&spc->spc_aaddr;
if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr)) {
- (void)sa6_recoverscope(sin6);
+ if (sin6->sin6_scope_id == 0) {
+ /* recover scope_id for user */
+ (void)sa6_recoverscope(sin6);
+ } else {
+ /* clear embedded scope_id for user */
+ in6_clearscope(&sin6->sin6_addr);
+ }
}
}
spc->spc_state = state;
@@ -3719,8 +3892,12 @@ sctp_add_to_readq(struct sctp_inpcb *inp,
return;
}
SCTP_INP_READ_LOCK(inp);
- atomic_add_int(&inp->total_recvs, 1);
- atomic_add_int(&stcb->total_recvs, 1);
+ if (!(control->spec_flags & M_NOTIFICATION)) {
+ atomic_add_int(&inp->total_recvs, 1);
+ if (!control->do_not_ref_stcb) {
+ atomic_add_int(&stcb->total_recvs, 1);
+ }
+ }
m = control->data;
control->held_length = 0;
control->length = 0;
@@ -4019,57 +4196,105 @@ sctp_release_pr_sctp_chunk(struct sctp_tcb *stcb, struct sctp_tmit_chunk *tp1,
* and doesn't handle multiple addresses with different zone/scope id's note:
* ifa_ifwithaddr() compares the entire sockaddr struct
*/
-struct ifaddr *
-sctp_find_ifa_by_addr(struct sockaddr *sa)
+struct sctp_ifa *
+sctp_find_ifa_in_ep(struct sctp_inpcb *inp, struct sockaddr *addr, int holds_lock)
{
- struct ifnet *ifn;
- struct ifaddr *ifa;
+ struct sctp_laddr *laddr;
- /* go through all our known interfaces */
- TAILQ_FOREACH(ifn, &ifnet, if_list) {
- /* go through each interface addresses */
- TAILQ_FOREACH(ifa, &ifn->if_addrlist, ifa_list) {
- /* correct family? */
- if (ifa->ifa_addr->sa_family != sa->sa_family)
- continue;
+ if (holds_lock == 0)
+ SCTP_INP_RLOCK(inp);
-#ifdef INET6
- if (ifa->ifa_addr->sa_family == AF_INET6) {
- /* IPv6 address */
- struct sockaddr_in6 *sin1, *sin2, sin6_tmp;
-
- sin1 = (struct sockaddr_in6 *)ifa->ifa_addr;
- if (IN6_IS_SCOPE_LINKLOCAL(&sin1->sin6_addr)) {
- /* create a copy and clear scope */
- memcpy(&sin6_tmp, sin1,
- sizeof(struct sockaddr_in6));
- sin1 = &sin6_tmp;
- in6_clearscope(&sin1->sin6_addr);
- }
- sin2 = (struct sockaddr_in6 *)sa;
- if (memcmp(&sin1->sin6_addr, &sin2->sin6_addr,
- sizeof(struct in6_addr)) == 0) {
- /* found it */
- return (ifa);
- }
- } else
-#endif
- if (ifa->ifa_addr->sa_family == AF_INET) {
- /* IPv4 address */
- struct sockaddr_in *sin1, *sin2;
-
- sin1 = (struct sockaddr_in *)ifa->ifa_addr;
- sin2 = (struct sockaddr_in *)sa;
- if (sin1->sin_addr.s_addr ==
- sin2->sin_addr.s_addr) {
- /* found it */
- return (ifa);
- }
+ LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
+ if (laddr->ifa == NULL)
+ continue;
+ if (addr->sa_family != laddr->ifa->address.sa.sa_family)
+ continue;
+ if (addr->sa_family == AF_INET) {
+ if (((struct sockaddr_in *)addr)->sin_addr.s_addr ==
+ laddr->ifa->address.sin.sin_addr.s_addr) {
+ /* found him. */
+ if (holds_lock == 0)
+ SCTP_INP_RUNLOCK(inp);
+ return (laddr->ifa);
+ break;
+ }
+ } else if (addr->sa_family == AF_INET6) {
+ if (SCTP6_ARE_ADDR_EQUAL(&((struct sockaddr_in6 *)addr)->sin6_addr,
+ &laddr->ifa->address.sin6.sin6_addr)) {
+ /* found him. */
+ if (holds_lock == 0)
+ SCTP_INP_RUNLOCK(inp);
+ return (laddr->ifa);
+ break;
+ }
+ }
+ }
+ if (holds_lock == 0)
+ SCTP_INP_RUNLOCK(inp);
+ return (NULL);
+}
+
+struct sctp_ifa *
+sctp_find_ifa_in_ifn(struct sctp_ifn *sctp_ifnp, struct sockaddr *addr,
+ int holds_lock)
+{
+ struct sctp_ifa *sctp_ifap;
+
+ if (holds_lock == 0)
+ SCTP_IPI_ADDR_LOCK();
+
+ LIST_FOREACH(sctp_ifap, &sctp_ifnp->ifalist, next_ifa) {
+ if (addr->sa_family != sctp_ifap->address.sa.sa_family)
+ continue;
+ if (addr->sa_family == AF_INET) {
+ if (((struct sockaddr_in *)addr)->sin_addr.s_addr ==
+ sctp_ifap->address.sin.sin_addr.s_addr) {
+ /* found him. */
+ if (holds_lock == 0)
+ SCTP_IPI_ADDR_UNLOCK();
+ return (sctp_ifap);
+ break;
+ }
+ } else if (addr->sa_family == AF_INET6) {
+ if (SCTP6_ARE_ADDR_EQUAL(&((struct sockaddr_in6 *)addr)->sin6_addr,
+ &sctp_ifap->address.sin6.sin6_addr)) {
+ /* found him. */
+ if (holds_lock == 0)
+ SCTP_IPI_ADDR_UNLOCK();
+ return (sctp_ifap);
+ break;
}
- /* else, not AF_INET or AF_INET6, so skip */
- } /* end foreach ifa */
- } /* end foreach ifn */
- /* not found! */
+ }
+ }
+ if (holds_lock == 0)
+ SCTP_IPI_ADDR_UNLOCK();
+ return (NULL);
+}
+
+struct sctp_ifa *
+sctp_find_ifa_by_addr(struct sockaddr *addr, uint32_t vrf_id, int holds_lock)
+{
+ struct sctp_ifa *sctp_ifap;
+ struct sctp_ifn *sctp_ifnp = NULL;
+ struct sctp_vrf *vrf;
+
+ vrf = sctp_find_vrf(vrf_id);
+ if (vrf == NULL)
+ return (NULL);
+
+ if (holds_lock == 0)
+ SCTP_IPI_ADDR_LOCK();
+
+ LIST_FOREACH(sctp_ifnp, &vrf->ifnlist, next_ifn) {
+ sctp_ifap = sctp_find_ifa_in_ifn(sctp_ifnp, addr, 1);
+ if (sctp_ifap) {
+ if (holds_lock == 0)
+ SCTP_IPI_ADDR_UNLOCK();
+ return (sctp_ifap);
+ }
+ }
+ if (holds_lock == 0)
+ SCTP_IPI_ADDR_UNLOCK();
return (NULL);
}
@@ -4208,7 +4433,8 @@ sctp_sorecvmsg(struct socket *so,
uint32_t rwnd_req = 0;
int hold_sblock = 0;
int hold_rlock = 0;
- int alen = 0, slen = 0;
+ int alen = 0;
+ int slen = 0;
int held_length = 0;
if (msg_flags) {
@@ -4228,7 +4454,7 @@ sctp_sorecvmsg(struct socket *so,
if ((in_flags & (MSG_DONTWAIT
| MSG_NBIO
)) ||
- (so->so_state & SS_NBIO)) {
+ SCTP_SO_IS_NBIO(so)) {
block_allowed = 0;
}
/* setup the endpoint */
@@ -4573,7 +4799,7 @@ found_one:
if (fromlen && from) {
struct sockaddr *to;
-#ifdef AF_INET
+#ifdef INET
cp_len = min(fromlen, control->whoFrom->ro._l_addr.sin.sin_len);
memcpy(from, &control->whoFrom->ro._l_addr, cp_len);
((struct sockaddr_in *)from)->sin_port = control->port_from;
@@ -4585,7 +4811,7 @@ found_one:
#endif
to = from;
-#if defined(AF_INET) && defined(AF_INET6)
+#if defined(INET) && defined(INET6)
if ((inp->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) &&
(to->sa_family == AF_INET) &&
((size_t)fromlen >= sizeof(struct sockaddr_in6))) {
@@ -4604,7 +4830,7 @@ found_one:
memcpy(from, (caddr_t)&sin6, sizeof(sin6));
}
#endif
-#if defined(AF_INET6)
+#if defined(INET6)
{
struct sockaddr_in6 lsa6, *to6;
@@ -5253,6 +5479,52 @@ sctp_m_freem(struct mbuf *mb)
#endif
+int
+sctp_dynamic_set_primary(struct sockaddr *sa, uint32_t vrf_id)
+{
+ /*
+ * Given a local address. For all associations that holds the
+ * address, request a peer-set-primary.
+ */
+ struct sctp_ifa *ifa;
+ struct sctp_laddr *wi;
+
+ ifa = sctp_find_ifa_by_addr(sa, vrf_id, 0);
+ if (ifa == NULL) {
+ return (EADDRNOTAVAIL);
+ }
+ /*
+ * Now that we have the ifa we must awaken the iterator with this
+ * message.
+ */
+ wi = SCTP_ZONE_GET(sctppcbinfo.ipi_zone_laddr, struct sctp_laddr);
+ if (wi == NULL) {
+ return (ENOMEM);
+ }
+ /* Now incr the count and int wi structure */
+ SCTP_INCR_LADDR_COUNT();
+ bzero(wi, sizeof(*wi));
+ wi->ifa = ifa;
+ wi->action = SCTP_SET_PRIM_ADDR;
+ atomic_add_int(&ifa->refcount, 1);
+
+ /* Now add it to the work queue */
+ SCTP_IPI_ITERATOR_WQ_LOCK();
+ /*
+ * Should this really be a tailq? As it is we will process the
+ * newest first :-0
+ */
+ LIST_INSERT_HEAD(&sctppcbinfo.addr_wq, wi, sctp_nxt_addr);
+ sctp_timer_start(SCTP_TIMER_TYPE_ADDR_WQ,
+ (struct sctp_inpcb *)NULL,
+ (struct sctp_tcb *)NULL,
+ (struct sctp_nets *)NULL);
+ SCTP_IPI_ITERATOR_WQ_UNLOCK();
+ return (0);
+}
+
+
+
int
sctp_soreceive(so, psa, uio, mp0, controlp, flagsp)
OpenPOWER on IntegriCloud