diff options
author | rrs <rrs@FreeBSD.org> | 2007-03-15 11:27:14 +0000 |
---|---|---|
committer | rrs <rrs@FreeBSD.org> | 2007-03-15 11:27:14 +0000 |
commit | bd8786ed778eb3e2e64f4bc1078d8653aa1a6d54 (patch) | |
tree | 3a099c736ba497f25dc6fd964a7995f33f2282ad /sys/netinet/sctputil.c | |
parent | 7f1d3da162e9e7e9561d1b1ab3e88b00622c7b5e (diff) | |
download | FreeBSD-src-bd8786ed778eb3e2e64f4bc1078d8653aa1a6d54.zip FreeBSD-src-bd8786ed778eb3e2e64f4bc1078d8653aa1a6d54.tar.gz |
- Sysctl's move to seperate file
- moved away from ifn/ifa access to sctp_ifa/sctp_ifn
built and managed by the add-ip code.
- cleaned up add-ip code to use the iterator
- made iterator be a thread, which enables auto-asconf now.
- rewrote and cleaned up source address selection (also
made it use new structures).
- Fixed a couple of memory leaks.
- DACK now settable as to how many packets to delay as
well as time.
- connectx() to latest socket API, new associd arg.
- Fixed issue with revoking and loosing potential to
send when we inflate the flight size. We now inflate
the cwnd too and deflate it later when the revoked
chunk is sent or acked.
- Got rid of some temp debug code
- src addr selection moved to a common file (sctp_output.c)
- Support for simple VRF's (we have support for multi-vfr
via compile switch that is scrubbed from BSD but we won't
need multi-vrf until we first get VRF :-D)
- Rest of mib work for address information now done
- Limit number of addresses in INIT/INIT-ACK to
a #def (30).
Reviewed by: gnn
Diffstat (limited to 'sys/netinet/sctputil.c')
-rw-r--r-- | sys/netinet/sctputil.c | 466 |
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) |