- take out a needless panic under invariants for sctp_output.c
- Fix addrs's error checking of sctp_sendx(3) when addrcnt is less than SCTP_SMALL_IOVEC_SIZE - re-add back inpcb_bind local address check bypass capability - Fix it so sctp_opt_info is independant of assoc_id postion. - Fix cookie life set to use MSEC_TO_TICKS() macro. - asconf changes o More comment changes/clarifications related to the old local address "not" list which is now an explicit restricted list. o Rename some functions for clarity: - sctp_add/del_local_addr_assoc to xxx_local_addr_restricted() - asconf related iterator functions to sctp_asconf_iterator_xxx() o Fix bug when the same address is deleted and added (and removed from the asconf queue) where the ifa is "freed" twice refcount wise, possibly freeing it completely. o Fix bug in output where the first ASCONF would not go out after the last address is changed (e.g. only goes out when retransmitted). o Fix bug where multiple ASCONFs can be bundled in the same packet with the and with the same serial numbers. o Fix asconf stcb iterator to not send ASCONF until after all work queue entries have been processed. o Change behavior so that when the last address is deleted (auto asconf on a bound all endpoint) no action is taken until an address is added; at that time, an ASCONF add+delete is sent (if the assoc is still up). o Fix local address counting so that address scoping is taken into account. o #ifdef SCTP_TIMER_BASED_ASCONF the old timer triggered sending of ASCONF (after an RTO). The default now is to send ASCONF immediately (except for the case of changing/deleting the last usable address). Approved by: re(ken smith)@freebsd.org
This commit is contained in:
parent
064d25a08a
commit
1b649582bb
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=171572
@ -240,7 +240,10 @@ sctp_bindx(int sd, struct sockaddr *addrs, int addrcnt, int flags)
|
||||
{
|
||||
struct sctp_getaddresses *gaddrs;
|
||||
struct sockaddr *sa;
|
||||
struct sockaddr_in *sin;
|
||||
struct sockaddr_in6 *sin6;
|
||||
int i, sz, argsz;
|
||||
uint16_t sport = 0;
|
||||
|
||||
/* validate the flags */
|
||||
if ((flags != SCTP_BINDX_ADD_ADDR) &&
|
||||
@ -260,7 +263,58 @@ sctp_bindx(int sd, struct sockaddr *addrs, int addrcnt, int flags)
|
||||
errno = ENOMEM;
|
||||
return (-1);
|
||||
}
|
||||
/* First pre-screen the addresses */
|
||||
sa = addrs;
|
||||
for (i = 0; i < addrcnt; i++) {
|
||||
sz = sa->sa_len;
|
||||
if (sa->sa_family == AF_INET) {
|
||||
if (sa->sa_len != sizeof(struct sockaddr_in))
|
||||
goto out_error;
|
||||
sin = (struct sockaddr_in *)sa;
|
||||
if (sin->sin_port) {
|
||||
/* non-zero port, check or save */
|
||||
if (sport) {
|
||||
/* Check against our port */
|
||||
if (sport != sin->sin_port) {
|
||||
goto out_error;
|
||||
}
|
||||
} else {
|
||||
/* save off the port */
|
||||
sport = sin->sin_port;
|
||||
}
|
||||
}
|
||||
} else if (sa->sa_family == AF_INET6) {
|
||||
if (sa->sa_len != sizeof(struct sockaddr_in6))
|
||||
goto out_error;
|
||||
sin6 = (struct sockaddr_in6 *)sa;
|
||||
if (sin6->sin6_port) {
|
||||
/* non-zero port, check or save */
|
||||
if (sport) {
|
||||
/* Check against our port */
|
||||
if (sport != sin6->sin6_port) {
|
||||
goto out_error;
|
||||
}
|
||||
} else {
|
||||
/* save off the port */
|
||||
sport = sin6->sin6_port;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* invalid address family specified */
|
||||
goto out_error;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
sa = addrs;
|
||||
/*
|
||||
* Now if there was a port mentioned, assure that the first address
|
||||
* has that port to make sure it fails or succeeds correctly.
|
||||
*/
|
||||
if (sport) {
|
||||
sin = (struct sockaddr_in *)sa;
|
||||
sin->sin_port = sport;
|
||||
}
|
||||
for (i = 0; i < addrcnt; i++) {
|
||||
sz = sa->sa_len;
|
||||
if (sa->sa_family == AF_INET) {
|
||||
@ -298,7 +352,55 @@ sctp_opt_info(int sd, sctp_assoc_t id, int opt, void *arg, socklen_t * size)
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
*(sctp_assoc_t *) arg = id;
|
||||
switch (opt) {
|
||||
case SCTP_RTOINFO:
|
||||
((struct sctp_rtoinfo *)arg)->srto_assoc_id = id;
|
||||
break;
|
||||
case SCTP_ASSOCINFO:
|
||||
((struct sctp_assocparams *)arg)->sasoc_assoc_id = id;
|
||||
break;
|
||||
case SCTP_DEFAULT_SEND_PARAM:
|
||||
((struct sctp_assocparams *)arg)->sasoc_assoc_id = id;
|
||||
break;
|
||||
case SCTP_SET_PEER_PRIMARY_ADDR:
|
||||
((struct sctp_setpeerprim *)arg)->sspp_assoc_id = id;
|
||||
break;
|
||||
case SCTP_PRIMARY_ADDR:
|
||||
((struct sctp_setprim *)arg)->ssp_assoc_id = id;
|
||||
break;
|
||||
case SCTP_PEER_ADDR_PARAMS:
|
||||
((struct sctp_paddrparams *)arg)->spp_assoc_id = id;
|
||||
break;
|
||||
case SCTP_MAXSEG:
|
||||
((struct sctp_assoc_value *)arg)->assoc_id = id;
|
||||
break;
|
||||
case SCTP_AUTH_KEY:
|
||||
((struct sctp_authkey *)arg)->sca_assoc_id = id;
|
||||
break;
|
||||
case SCTP_AUTH_ACTIVE_KEY:
|
||||
((struct sctp_authkeyid *)arg)->scact_assoc_id = id;
|
||||
break;
|
||||
case SCTP_DELAYED_SACK:
|
||||
((struct sctp_sack_info *)arg)->sack_assoc_id = id;
|
||||
break;
|
||||
case SCTP_CONTEXT:
|
||||
((struct sctp_assoc_value *)arg)->assoc_id = id;
|
||||
break;
|
||||
case SCTP_STATUS:
|
||||
((struct sctp_status *)arg)->sstat_assoc_id = id;
|
||||
break;
|
||||
case SCTP_GET_PEER_ADDR_INFO:
|
||||
((struct sctp_paddrinfo *)arg)->spinfo_assoc_id = id;
|
||||
break;
|
||||
case SCTP_PEER_AUTH_CHUNKS:
|
||||
((struct sctp_authchunks *)arg)->gauth_assoc_id = id;
|
||||
break;
|
||||
case SCTP_LOCAL_AUTH_CHUNKS:
|
||||
((struct sctp_authchunks *)arg)->gauth_assoc_id = id;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return (getsockopt(sd, IPPROTO_SCTP, opt, arg, size));
|
||||
}
|
||||
|
||||
@ -628,7 +730,10 @@ sctp_sendx(int sd, const void *msg, size_t msg_len,
|
||||
int add_len, len, no_end_cx = 0;
|
||||
struct sockaddr *at;
|
||||
|
||||
|
||||
if (addrs == NULL) {
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
#ifdef SYS_sctp_generic_sendmsg
|
||||
if (addrcnt < SCTP_SMALL_IOVEC_SIZE) {
|
||||
socklen_t l;
|
||||
@ -643,10 +748,6 @@ sctp_sendx(int sd, const void *msg, size_t msg_len,
|
||||
}
|
||||
#endif
|
||||
|
||||
if (addrs == NULL) {
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
len = sizeof(int);
|
||||
at = addrs;
|
||||
cnt = 0;
|
||||
|
@ -295,8 +295,7 @@ sctp_process_asconf_add_ip(struct mbuf *m, struct sctp_asconf_paramhdr *aph,
|
||||
}
|
||||
|
||||
static int
|
||||
sctp_asconf_del_remote_addrs_except(struct sctp_tcb *stcb,
|
||||
struct sockaddr *src)
|
||||
sctp_asconf_del_remote_addrs_except(struct sctp_tcb *stcb, struct sockaddr *src)
|
||||
{
|
||||
struct sctp_nets *src_net, *net;
|
||||
|
||||
@ -459,8 +458,8 @@ sctp_process_asconf_delete_ip(struct mbuf *m, struct sctp_asconf_paramhdr *aph,
|
||||
|
||||
static struct mbuf *
|
||||
sctp_process_asconf_set_primary(struct mbuf *m,
|
||||
struct sctp_asconf_paramhdr *aph, struct sctp_tcb *stcb,
|
||||
int response_required)
|
||||
struct sctp_asconf_paramhdr *aph,
|
||||
struct sctp_tcb *stcb, int response_required)
|
||||
{
|
||||
struct mbuf *m_reply = NULL;
|
||||
struct sockaddr_storage sa_source, sa_store;
|
||||
@ -874,7 +873,7 @@ sctp_asconf_cleanup(struct sctp_tcb *stcb, struct sctp_nets *net)
|
||||
|
||||
/*
|
||||
* process an ADD/DELETE IP ack from peer.
|
||||
* addr corresponding sctp_ifa to the address being added/deleted.
|
||||
* addr: corresponding sctp_ifa to the address being added/deleted.
|
||||
* type: SCTP_ADD_IP_ADDRESS or SCTP_DEL_IP_ADDRESS.
|
||||
* flag: 1=success, 0=failure.
|
||||
*/
|
||||
@ -892,31 +891,28 @@ sctp_asconf_addr_mgmt_ack(struct sctp_tcb *stcb, struct sctp_ifa *addr,
|
||||
* DEL_IP_ADDRESS is never actually added to the list...
|
||||
*/
|
||||
if (flag) {
|
||||
/* success case, so remove from the list */
|
||||
sctp_del_local_addr_assoc(stcb, addr);
|
||||
/* success case, so remove from the restricted list */
|
||||
sctp_del_local_addr_restricted(stcb, addr);
|
||||
}
|
||||
/* else, leave it on the list */
|
||||
}
|
||||
|
||||
/*
|
||||
* add an asconf add/delete IP address parameter to the queue.
|
||||
* add an asconf add/delete/set primary IP address parameter to the queue.
|
||||
* type = SCTP_ADD_IP_ADDRESS, SCTP_DEL_IP_ADDRESS, SCTP_SET_PRIM_ADDR.
|
||||
* returns 0 if completed, non-zero if not completed.
|
||||
* NOTE: if adding, but delete already scheduled (and not yet sent out),
|
||||
* simply remove from queue. Same for deleting an address already scheduled
|
||||
* for add. If a duplicate operation is found, ignore the new one.
|
||||
* returns 0 if queued, -1 if not queued/removed.
|
||||
* NOTE: if adding, but a delete for the same address is already scheduled
|
||||
* (and not yet sent out), simply remove it from queue. Same for deleting
|
||||
* an address already scheduled for add. If a duplicate operation is found,
|
||||
* ignore the new one.
|
||||
*/
|
||||
static uint32_t
|
||||
sctp_asconf_queue_add(struct sctp_tcb *stcb, struct sctp_ifa *ifa,
|
||||
static int
|
||||
sctp_asconf_queue_mgmt(struct sctp_tcb *stcb, struct sctp_ifa *ifa,
|
||||
uint16_t type)
|
||||
{
|
||||
struct sctp_asconf_addr *aa, *aa_next;
|
||||
struct sockaddr *sa;
|
||||
|
||||
/* see if peer supports ASCONF */
|
||||
if (stcb->asoc.peer_supports_asconf == 0) {
|
||||
return (-1);
|
||||
}
|
||||
/* make sure the request isn't already in the queue */
|
||||
for (aa = TAILQ_FIRST(&stcb->asoc.asconf_queue); aa != NULL;
|
||||
aa = aa_next) {
|
||||
@ -929,30 +925,36 @@ sctp_asconf_queue_add(struct sctp_tcb *stcb, struct sctp_ifa *ifa,
|
||||
return (-1);
|
||||
}
|
||||
/* is the negative request already in queue, and not sent */
|
||||
if (aa->sent == 0 &&
|
||||
/* add requested, delete already queued */
|
||||
((type == SCTP_ADD_IP_ADDRESS &&
|
||||
aa->ap.aph.ph.param_type == SCTP_DEL_IP_ADDRESS) ||
|
||||
/* delete requested, add already queued */
|
||||
(type == SCTP_DEL_IP_ADDRESS &&
|
||||
aa->ap.aph.ph.param_type == SCTP_ADD_IP_ADDRESS))) {
|
||||
/* delete the existing entry in the queue */
|
||||
if ((aa->sent == 0) && (type == SCTP_ADD_IP_ADDRESS) &&
|
||||
(aa->ap.aph.ph.param_type == SCTP_DEL_IP_ADDRESS)) {
|
||||
/* add requested, delete already queued */
|
||||
TAILQ_REMOVE(&stcb->asoc.asconf_queue, aa, next);
|
||||
/* take the entry off the appropriate list */
|
||||
sctp_asconf_addr_mgmt_ack(stcb, aa->ifa, type, 1);
|
||||
/* free the entry */
|
||||
sctp_free_ifa(aa->ifa);
|
||||
/* remove the ifa from the restricted list */
|
||||
sctp_del_local_addr_restricted(stcb, ifa);
|
||||
/* free the asconf param */
|
||||
SCTP_FREE(aa, SCTP_M_ASC_ADDR);
|
||||
SCTPDBG(SCTP_DEBUG_ASCONF2, "asconf_queue_mgmt: add removes queued entry\n");
|
||||
return (-1);
|
||||
}
|
||||
if ((aa->sent == 0) && (type == SCTP_DEL_IP_ADDRESS) &&
|
||||
(aa->ap.aph.ph.param_type == SCTP_ADD_IP_ADDRESS)) {
|
||||
/* delete requested, add already queued */
|
||||
TAILQ_REMOVE(&stcb->asoc.asconf_queue, aa, next);
|
||||
/* remove the aa->ifa from the restricted list */
|
||||
sctp_del_local_addr_restricted(stcb, aa->ifa);
|
||||
/* free the asconf param */
|
||||
SCTP_FREE(aa, SCTP_M_ASC_ADDR);
|
||||
SCTPDBG(SCTP_DEBUG_ASCONF2, "asconf_queue_mgmt: delete removes queued entry\n");
|
||||
return (-1);
|
||||
}
|
||||
} /* for each aa */
|
||||
|
||||
/* adding new request to the queue */
|
||||
SCTP_MALLOC(aa, struct sctp_asconf_addr *, sizeof(*aa), SCTP_M_ASC_ADDR);
|
||||
SCTP_MALLOC(aa, struct sctp_asconf_addr *, sizeof(*aa),
|
||||
SCTP_M_ASC_ADDR);
|
||||
if (aa == NULL) {
|
||||
/* didn't get memory */
|
||||
SCTPDBG(SCTP_DEBUG_ASCONF1,
|
||||
"asconf_queue_add: failed to get memory!\n");
|
||||
SCTPDBG(SCTP_DEBUG_ASCONF1, "asconf_queue_mgmt: failed to get memory!\n");
|
||||
return (-1);
|
||||
}
|
||||
/* fill in asconf address parameter fields */
|
||||
@ -969,20 +971,19 @@ sctp_asconf_queue_add(struct sctp_tcb *stcb, struct sctp_ifa *ifa,
|
||||
sa = (struct sockaddr *)sin6;
|
||||
aa->ap.addrp.ph.param_type = SCTP_IPV6_ADDRESS;
|
||||
aa->ap.addrp.ph.param_length = (sizeof(struct sctp_ipv6addr_param));
|
||||
aa->ap.aph.ph.param_length =
|
||||
sizeof(struct sctp_asconf_paramhdr) +
|
||||
aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_paramhdr) +
|
||||
sizeof(struct sctp_ipv6addr_param);
|
||||
memcpy(&aa->ap.addrp.addr, &sin6->sin6_addr,
|
||||
sizeof(struct in6_addr));
|
||||
} else if (ifa->address.sa.sa_family == AF_INET) {
|
||||
/* IPv4 address */
|
||||
struct sockaddr_in *sin = (struct sockaddr_in *)&ifa->address.sa;
|
||||
struct sockaddr_in *sin;
|
||||
|
||||
sin = (struct sockaddr_in *)&ifa->address.sa;
|
||||
sa = (struct sockaddr *)sin;
|
||||
aa->ap.addrp.ph.param_type = SCTP_IPV4_ADDRESS;
|
||||
aa->ap.addrp.ph.param_length = (sizeof(struct sctp_ipv4addr_param));
|
||||
aa->ap.aph.ph.param_length =
|
||||
sizeof(struct sctp_asconf_paramhdr) +
|
||||
aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_paramhdr) +
|
||||
sizeof(struct sctp_ipv4addr_param);
|
||||
memcpy(&aa->ap.addrp.addr, &sin->sin_addr,
|
||||
sizeof(struct in_addr));
|
||||
@ -1001,7 +1002,7 @@ sctp_asconf_queue_add(struct sctp_tcb *stcb, struct sctp_ifa *ifa,
|
||||
/* add goes to the front of the queue */
|
||||
TAILQ_INSERT_HEAD(&stcb->asoc.asconf_queue, aa, next);
|
||||
SCTPDBG(SCTP_DEBUG_ASCONF2,
|
||||
"asconf_queue_add: appended asconf ADD_IP_ADDRESS: ");
|
||||
"asconf_queue_mgmt: inserted asconf ADD_IP_ADDRESS: ");
|
||||
SCTPDBG_ADDR(SCTP_DEBUG_ASCONF2, sa);
|
||||
} else {
|
||||
/* delete and set primary goes to the back of the queue */
|
||||
@ -1009,10 +1010,10 @@ sctp_asconf_queue_add(struct sctp_tcb *stcb, struct sctp_ifa *ifa,
|
||||
#ifdef SCTP_DEBUG
|
||||
if (sctp_debug_on && SCTP_DEBUG_ASCONF2) {
|
||||
if (type == SCTP_DEL_IP_ADDRESS) {
|
||||
SCTP_PRINTF("asconf_queue_add: inserted asconf DEL_IP_ADDRESS: ");
|
||||
SCTP_PRINTF("asconf_queue_mgmt: appended asconf DEL_IP_ADDRESS: ");
|
||||
SCTPDBG_ADDR(SCTP_DEBUG_ASCONF2, sa);
|
||||
} else {
|
||||
SCTP_PRINTF("asconf_queue_add: inserted asconf SET_PRIM_ADDR: ");
|
||||
SCTP_PRINTF("asconf_queue_mgmt: appended asconf SET_PRIM_ADDR: ");
|
||||
SCTPDBG_ADDR(SCTP_DEBUG_ASCONF2, sa);
|
||||
}
|
||||
}
|
||||
@ -1022,6 +1023,84 @@ sctp_asconf_queue_add(struct sctp_tcb *stcb, struct sctp_ifa *ifa,
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* add an asconf operation for the given ifa and type.
|
||||
* type = SCTP_ADD_IP_ADDRESS, SCTP_DEL_IP_ADDRESS, SCTP_SET_PRIM_ADDR.
|
||||
* returns 0 if completed, -1 if not completed, 1 if immediate send is
|
||||
* advisable.
|
||||
*/
|
||||
static int
|
||||
sctp_asconf_queue_add(struct sctp_tcb *stcb, struct sctp_ifa *ifa,
|
||||
uint16_t type)
|
||||
{
|
||||
uint32_t status;
|
||||
int pending_delete_queued = 0;
|
||||
|
||||
/* see if peer supports ASCONF */
|
||||
if (stcb->asoc.peer_supports_asconf == 0) {
|
||||
return (-1);
|
||||
}
|
||||
/*
|
||||
* if this is deleting the last address from the assoc, mark it as
|
||||
* pending.
|
||||
*/
|
||||
if ((type == SCTP_DEL_IP_ADDRESS) && !stcb->asoc.asconf_del_pending &&
|
||||
(sctp_local_addr_count(stcb) < 2)) {
|
||||
/* set the pending delete info only */
|
||||
stcb->asoc.asconf_del_pending = 1;
|
||||
stcb->asoc.asconf_addr_del_pending = ifa;
|
||||
atomic_add_int(&ifa->refcount, 1);
|
||||
SCTPDBG(SCTP_DEBUG_ASCONF2,
|
||||
"asconf_queue_add: mark delete last address pending\n");
|
||||
return (-1);
|
||||
}
|
||||
/*
|
||||
* if this is an add, and there is a delete also pending (i.e. the
|
||||
* last local address is being changed), queue the pending delete
|
||||
* too.
|
||||
*/
|
||||
if ((type == SCTP_ADD_IP_ADDRESS) && stcb->asoc.asconf_del_pending) {
|
||||
/* queue in the pending delete */
|
||||
if (sctp_asconf_queue_mgmt(stcb,
|
||||
stcb->asoc.asconf_addr_del_pending,
|
||||
SCTP_DEL_IP_ADDRESS) == 0) {
|
||||
SCTPDBG(SCTP_DEBUG_ASCONF2, "asconf_queue_add: queing pending delete\n");
|
||||
pending_delete_queued = 1;
|
||||
/* clear out the pending delete info */
|
||||
stcb->asoc.asconf_del_pending = 0;
|
||||
sctp_free_ifa(stcb->asoc.asconf_addr_del_pending);
|
||||
stcb->asoc.asconf_addr_del_pending = NULL;
|
||||
}
|
||||
}
|
||||
/* queue an asconf parameter */
|
||||
status = sctp_asconf_queue_mgmt(stcb, ifa, type);
|
||||
|
||||
if (pending_delete_queued && (status == 0)) {
|
||||
struct sctp_nets *net;
|
||||
|
||||
/*
|
||||
* since we know that the only/last address is now being
|
||||
* changed in this case, reset the cwnd/rto on all nets to
|
||||
* start as a new address and path. Also clear the error
|
||||
* counts to give the assoc the best chance to complete the
|
||||
* address change.
|
||||
*/
|
||||
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
|
||||
stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb,
|
||||
net);
|
||||
net->RTO = 0;
|
||||
net->error_count = 0;
|
||||
}
|
||||
stcb->asoc.overall_error_count = 0;
|
||||
/* queue in an advisory set primary too */
|
||||
(void)sctp_asconf_queue_mgmt(stcb, ifa, SCTP_SET_PRIM_ADDR);
|
||||
/* let caller know we should send this out immediately */
|
||||
status = 1;
|
||||
}
|
||||
return (status);
|
||||
}
|
||||
|
||||
/*
|
||||
* add an asconf add/delete IP address parameter to the queue by addr.
|
||||
* type = SCTP_ADD_IP_ADDRESS, SCTP_DEL_IP_ADDRESS, SCTP_SET_PRIM_ADDR.
|
||||
@ -1030,7 +1109,7 @@ sctp_asconf_queue_add(struct sctp_tcb *stcb, struct sctp_ifa *ifa,
|
||||
* simply remove from queue. Same for deleting an address already scheduled
|
||||
* for add. If a duplicate operation is found, ignore the new one.
|
||||
*/
|
||||
static uint32_t
|
||||
static int
|
||||
sctp_asconf_queue_add_sa(struct sctp_tcb *stcb, struct sockaddr *sa,
|
||||
uint16_t type)
|
||||
{
|
||||
@ -1065,8 +1144,8 @@ sctp_asconf_queue_add_sa(struct sctp_tcb *stcb, struct sockaddr *sa,
|
||||
|
||||
/* delete the existing entry in the queue */
|
||||
TAILQ_REMOVE(&stcb->asoc.asconf_queue, aa, next);
|
||||
/* free the entry */
|
||||
sctp_free_ifa(aa->ifa);
|
||||
/* free the entry */
|
||||
SCTP_FREE(aa, SCTP_M_ASC_ADDR);
|
||||
return (-1);
|
||||
} else if (type == SCTP_DEL_IP_ADDRESS &&
|
||||
@ -1075,10 +1154,8 @@ sctp_asconf_queue_add_sa(struct sctp_tcb *stcb, struct sockaddr *sa,
|
||||
|
||||
/* delete the existing entry in the queue */
|
||||
TAILQ_REMOVE(&stcb->asoc.asconf_queue, aa, next);
|
||||
/* take the entry off the appropriate list */
|
||||
sctp_asconf_addr_mgmt_ack(stcb, aa->ifa, type, 1);
|
||||
sctp_del_local_addr_restricted(stcb, aa->ifa);
|
||||
/* free the entry */
|
||||
sctp_free_ifa(aa->ifa);
|
||||
SCTP_FREE(aa, SCTP_M_ASC_ADDR);
|
||||
return (-1);
|
||||
}
|
||||
@ -1095,7 +1172,8 @@ sctp_asconf_queue_add_sa(struct sctp_tcb *stcb, struct sockaddr *sa,
|
||||
return (-1);
|
||||
}
|
||||
/* adding new request to the queue */
|
||||
SCTP_MALLOC(aa, struct sctp_asconf_addr *, sizeof(*aa), SCTP_M_ASC_ADDR);
|
||||
SCTP_MALLOC(aa, struct sctp_asconf_addr *, sizeof(*aa),
|
||||
SCTP_M_ASC_ADDR);
|
||||
if (aa == NULL) {
|
||||
/* didn't get memory */
|
||||
SCTPDBG(SCTP_DEBUG_ASCONF1,
|
||||
@ -1454,9 +1532,14 @@ sctp_handle_asconf_ack(struct mbuf *m, int offset,
|
||||
/* clear the sent flag to allow new ASCONFs */
|
||||
asoc->asconf_sent = 0;
|
||||
if (!TAILQ_EMPTY(&stcb->asoc.asconf_queue)) {
|
||||
#ifdef SCTP_TIMER_BASED_ASCONF
|
||||
/* we have more params, so restart our timer */
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, stcb->sctp_ep,
|
||||
stcb, net);
|
||||
#else
|
||||
/* we have more params, so send out more */
|
||||
sctp_send_asconf(stcb, net);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -1528,7 +1611,7 @@ sctp_addr_mgmt_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
|
||||
}
|
||||
}
|
||||
/* put this address on the "pending/do not use yet" list */
|
||||
sctp_add_local_addr_assoc(stcb, ifa, 1);
|
||||
sctp_add_local_addr_restricted(stcb, ifa);
|
||||
/*
|
||||
* check address scope if address is out of scope, don't queue
|
||||
* anything... note: this would leave the address on both inp and
|
||||
@ -1585,16 +1668,20 @@ sctp_addr_mgmt_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
|
||||
if (stcb->asoc.peer_supports_asconf) {
|
||||
/* queue an asconf for this addr */
|
||||
status = sctp_asconf_queue_add(stcb, ifa, type);
|
||||
|
||||
/*
|
||||
* if queued ok, and in correct state, set the
|
||||
* ASCONF timer if in non-open state, we will set
|
||||
* this timer when the state does go open and do all
|
||||
* the asconf's
|
||||
* if queued ok, and in the open state, send out the
|
||||
* ASCONF. If in the non-open state, these will be
|
||||
* sent when the state goes open.
|
||||
*/
|
||||
if (status == 0 &&
|
||||
SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) {
|
||||
#ifdef SCTP_TIMER_BASED_ASCONF
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, inp,
|
||||
stcb, stcb->asoc.primary_destination);
|
||||
#else
|
||||
sctp_send_asconf(stcb, stcb->asoc.primary_destination);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1602,7 +1689,7 @@ sctp_addr_mgmt_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
|
||||
|
||||
|
||||
int
|
||||
sctp_iterator_ep(struct sctp_inpcb *inp, void *ptr, uint32_t val)
|
||||
sctp_asconf_iterator_ep(struct sctp_inpcb *inp, void *ptr, uint32_t val)
|
||||
{
|
||||
struct sctp_asconf_iterator *asc;
|
||||
struct sctp_ifa *ifa;
|
||||
@ -1648,8 +1735,8 @@ sctp_iterator_ep(struct sctp_inpcb *inp, void *ptr, uint32_t val)
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
sctp_iterator_ep_end(struct sctp_inpcb *inp, void *ptr, uint32_t val)
|
||||
static int
|
||||
sctp_asconf_iterator_ep_end(struct sctp_inpcb *inp, void *ptr, uint32_t val)
|
||||
{
|
||||
struct sctp_ifa *ifa;
|
||||
struct sctp_asconf_iterator *asc;
|
||||
@ -1683,14 +1770,15 @@ sctp_iterator_ep_end(struct sctp_inpcb *inp, void *ptr, uint32_t val)
|
||||
}
|
||||
|
||||
void
|
||||
sctp_iterator_stcb(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr,
|
||||
uint32_t val)
|
||||
sctp_asconf_iterator_stcb(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
|
||||
void *ptr, uint32_t val)
|
||||
{
|
||||
struct sctp_asconf_iterator *asc;
|
||||
struct sctp_ifa *ifa;
|
||||
struct sctp_laddr *l;
|
||||
int cnt_invalid = 0;
|
||||
int type, status;
|
||||
int num_queued = 0;
|
||||
|
||||
asc = (struct sctp_asconf_iterator *)ptr;
|
||||
LIST_FOREACH(l, &asc->list_of_work, sctp_nxt_addr) {
|
||||
@ -1764,9 +1852,9 @@ sctp_iterator_stcb(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr,
|
||||
continue;
|
||||
}
|
||||
|
||||
/* put this address on the "pending/do not use yet" list */
|
||||
if (type == SCTP_ADD_IP_ADDRESS) {
|
||||
sctp_add_local_addr_assoc(stcb, ifa, 1);
|
||||
/* prevent this address from being used as a source */
|
||||
sctp_add_local_addr_restricted(stcb, ifa);
|
||||
} else if (type == SCTP_DEL_IP_ADDRESS) {
|
||||
struct sctp_nets *net;
|
||||
|
||||
@ -1797,10 +1885,7 @@ sctp_iterator_stcb(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr,
|
||||
}
|
||||
} else if (type == SCTP_SET_PRIM_ADDR) {
|
||||
if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) {
|
||||
/*
|
||||
* must validate the ifa in question is in
|
||||
* the ep
|
||||
*/
|
||||
/* must validate the ifa is in the ep */
|
||||
if (sctp_is_addr_in_ep(stcb->sctp_ep, ifa) == 0) {
|
||||
continue;
|
||||
}
|
||||
@ -1818,29 +1903,32 @@ sctp_iterator_stcb(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr,
|
||||
}
|
||||
}
|
||||
/* queue an asconf for this address add/delete */
|
||||
if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_DO_ASCONF)) {
|
||||
/* does the peer do asconf? */
|
||||
if (stcb->asoc.peer_supports_asconf) {
|
||||
/* queue an asconf for this addr */
|
||||
status = sctp_asconf_queue_add(stcb, ifa, type);
|
||||
/*
|
||||
* if queued ok, and in correct state, set
|
||||
* the ASCONF timer if in non-open state, we
|
||||
* will set this timer when the state does
|
||||
* go open and do all the asconf's
|
||||
*/
|
||||
if (status == 0 &&
|
||||
SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) {
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, inp,
|
||||
stcb, stcb->asoc.primary_destination);
|
||||
if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_DO_ASCONF) &&
|
||||
stcb->asoc.peer_supports_asconf) {
|
||||
/* queue an asconf for this addr */
|
||||
status = sctp_asconf_queue_add(stcb, ifa, type);
|
||||
/*
|
||||
* if queued ok, and in the open state, update the
|
||||
* count of queued params. If in the non-open
|
||||
* state, these get sent when the assoc goes open.
|
||||
*/
|
||||
if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) {
|
||||
if (status >= 0) {
|
||||
num_queued++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* If we have queued params in the open state, send out an ASCONF.
|
||||
*/
|
||||
if (num_queued > 0) {
|
||||
sctp_send_asconf(stcb, stcb->asoc.primary_destination);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
sctp_iterator_end(void *ptr, uint32_t val)
|
||||
void
|
||||
sctp_asconf_iterator_end(void *ptr, uint32_t val)
|
||||
{
|
||||
struct sctp_asconf_iterator *asc;
|
||||
struct sctp_ifa *ifa;
|
||||
@ -1864,10 +1952,10 @@ sctp_iterator_end(void *ptr, uint32_t val)
|
||||
}
|
||||
|
||||
/*
|
||||
* sa is the sockaddr to ask the peer to set primary to returns: 0 =
|
||||
* completed, -1 = error
|
||||
* sa is the sockaddr to ask the peer to set primary to.
|
||||
* returns: 0 = completed, -1 = error
|
||||
*/
|
||||
int32_t
|
||||
int
|
||||
sctp_set_primary_ip_address_sa(struct sctp_tcb *stcb, struct sockaddr *sa)
|
||||
{
|
||||
/* NOTE: we currently don't check the validity of the address! */
|
||||
@ -1875,15 +1963,19 @@ sctp_set_primary_ip_address_sa(struct sctp_tcb *stcb, struct sockaddr *sa)
|
||||
/* queue an ASCONF:SET_PRIM_ADDR to be sent */
|
||||
if (!sctp_asconf_queue_add_sa(stcb, sa, SCTP_SET_PRIM_ADDR)) {
|
||||
/* set primary queuing succeeded */
|
||||
if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) {
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_ASCONF,
|
||||
stcb->sctp_ep, stcb,
|
||||
stcb->asoc.primary_destination);
|
||||
}
|
||||
SCTPDBG(SCTP_DEBUG_ASCONF1,
|
||||
"set_primary_ip_address_sa: queued on tcb=%p, ",
|
||||
stcb);
|
||||
SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa);
|
||||
if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) {
|
||||
#ifdef SCTP_TIMER_BASED_ASCONF
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_ASCONF,
|
||||
stcb->sctp_ep, stcb,
|
||||
stcb->asoc.primary_destination);
|
||||
#else
|
||||
sctp_send_asconf(stcb, stcb->asoc.primary_destination);
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
SCTPDBG(SCTP_DEBUG_ASCONF1, "set_primary_ip_address_sa: failed to add to queue on tcb=%p, ",
|
||||
stcb);
|
||||
@ -1908,15 +2000,18 @@ sctp_set_primary_ip_address(struct sctp_ifa *ifa)
|
||||
if (!sctp_asconf_queue_add(stcb, ifa,
|
||||
SCTP_SET_PRIM_ADDR)) {
|
||||
/* set primary queuing succeeded */
|
||||
if (SCTP_GET_STATE(&stcb->asoc) ==
|
||||
SCTP_STATE_OPEN) {
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_ASCONF,
|
||||
stcb->sctp_ep, stcb,
|
||||
stcb->asoc.primary_destination);
|
||||
}
|
||||
SCTPDBG(SCTP_DEBUG_ASCONF1, "set_primary_ip_address: queued on stcb=%p, ",
|
||||
stcb);
|
||||
SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, &ifa->address.sa);
|
||||
if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) {
|
||||
#ifdef SCTP_TIMER_BASED_ASCONF
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_ASCONF,
|
||||
stcb->sctp_ep, stcb,
|
||||
stcb->asoc.primary_destination);
|
||||
#else
|
||||
sctp_send_asconf(stcb, stcb->asoc.primary_destination);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
} /* for each stcb */
|
||||
} /* for each inp */
|
||||
@ -2026,6 +2121,10 @@ sctp_compose_asconf(struct sctp_tcb *stcb, int *retlen)
|
||||
if (TAILQ_EMPTY(&stcb->asoc.asconf_queue)) {
|
||||
return (NULL);
|
||||
}
|
||||
/* can't send a new one if there is one in flight already */
|
||||
if (stcb->asoc.asconf_sent > 0) {
|
||||
return (NULL);
|
||||
}
|
||||
/*
|
||||
* get a chunk header mbuf and a cluster for the asconf params since
|
||||
* it's simpler to fill in the asconf chunk header lookup address on
|
||||
@ -2281,15 +2380,19 @@ sctp_process_initack_addresses(struct sctp_tcb *stcb, struct mbuf *m,
|
||||
status = sctp_asconf_queue_add_sa(stcb, sa,
|
||||
SCTP_DEL_IP_ADDRESS);
|
||||
/*
|
||||
* if queued ok, and in correct state, set
|
||||
* the ASCONF timer
|
||||
* if queued ok, and in correct state, send
|
||||
* out the ASCONF.
|
||||
*/
|
||||
if (status == 0 &&
|
||||
SCTP_GET_STATE(&stcb->asoc) ==
|
||||
SCTP_STATE_OPEN) {
|
||||
#ifdef SCTP_TIMER_BASED_ASCONF
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_ASCONF,
|
||||
stcb->sctp_ep, stcb,
|
||||
stcb->asoc.primary_destination);
|
||||
#else
|
||||
sctp_send_asconf(stcb, stcb->asoc.primary_destination);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2597,13 +2700,14 @@ sctp_addr_mgmt_ep_sa(struct sctp_inpcb *inp, struct sockaddr *sa,
|
||||
wi->action = type;
|
||||
atomic_add_int(&ifa->refcount, 1);
|
||||
LIST_INSERT_HEAD(&asc->list_of_work, wi, sctp_nxt_addr);
|
||||
(void)sctp_initiate_iterator(sctp_iterator_ep,
|
||||
sctp_iterator_stcb,
|
||||
sctp_iterator_ep_end,
|
||||
(void)sctp_initiate_iterator(sctp_asconf_iterator_ep,
|
||||
sctp_asconf_iterator_stcb,
|
||||
sctp_asconf_iterator_ep_end,
|
||||
SCTP_PCB_ANY_FLAGS,
|
||||
SCTP_PCB_ANY_FEATURES,
|
||||
SCTP_ASOC_ANY_STATE, (void *)asc, 0,
|
||||
sctp_iterator_end, inp, 0);
|
||||
SCTP_ASOC_ANY_STATE,
|
||||
(void *)asc, 0,
|
||||
sctp_asconf_iterator_end, inp, 0);
|
||||
} else {
|
||||
/* invalid address! */
|
||||
return (EADDRNOTAVAIL);
|
||||
|
@ -58,10 +58,14 @@ sctp_addr_mgmt_ep_sa(struct sctp_inpcb *, struct sockaddr *,
|
||||
uint32_t, uint32_t, struct sctp_ifa *);
|
||||
|
||||
|
||||
int sctp_iterator_ep(struct sctp_inpcb *inp, void *ptr, uint32_t val);
|
||||
void sctp_iterator_stcb(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr, uint32_t type);
|
||||
int sctp_iterator_ep_end(struct sctp_inpcb *inp, void *ptr, uint32_t val);
|
||||
void sctp_iterator_end(void *ptr, uint32_t val);
|
||||
extern int
|
||||
sctp_asconf_iterator_ep(struct sctp_inpcb *inp, void *ptr,
|
||||
uint32_t val);
|
||||
extern void
|
||||
sctp_asconf_iterator_stcb(struct sctp_inpcb *inp,
|
||||
struct sctp_tcb *stcb,
|
||||
void *ptr, uint32_t type);
|
||||
extern void sctp_asconf_iterator_end(void *ptr, uint32_t val);
|
||||
|
||||
|
||||
extern int32_t
|
||||
|
@ -2345,15 +2345,20 @@ sctp_handle_cookie_ack(struct sctp_cookie_ack_chunk *cp,
|
||||
stcb->sctp_ep, stcb, NULL);
|
||||
}
|
||||
/*
|
||||
* set ASCONF timer if ASCONFs are pending and allowed (eg.
|
||||
* addresses changed when init/cookie echo in flight)
|
||||
* send ASCONF if parameters are pending and ASCONFs are
|
||||
* allowed (eg. addresses changed when init/cookie echo were
|
||||
* in flight)
|
||||
*/
|
||||
if ((sctp_is_feature_on(stcb->sctp_ep, SCTP_PCB_FLAGS_DO_ASCONF)) &&
|
||||
(stcb->asoc.peer_supports_asconf) &&
|
||||
(!TAILQ_EMPTY(&stcb->asoc.asconf_queue))) {
|
||||
#ifdef SCTP_TIMER_BASED_ASCONF
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_ASCONF,
|
||||
stcb->sctp_ep, stcb,
|
||||
stcb->asoc.primary_destination);
|
||||
#else
|
||||
sctp_send_asconf(stcb, stcb->asoc.primary_destination);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
/* Toss the cookie if I can */
|
||||
|
@ -2380,9 +2380,12 @@ sctp_choose_boundspecific_inp(struct sctp_inpcb *inp,
|
||||
if (sctp_ifn) {
|
||||
/* is a preferred one on the interface we route out? */
|
||||
LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
|
||||
if ((sctp_ifa->localifa_flags & SCTP_ADDR_DEFER_USE) && (non_asoc_addr_ok == 0))
|
||||
if ((sctp_ifa->localifa_flags & SCTP_ADDR_DEFER_USE) &&
|
||||
(non_asoc_addr_ok == 0))
|
||||
continue;
|
||||
sifa = sctp_is_ifa_addr_preferred(sctp_ifa, dest_is_loop, dest_is_priv, fam);
|
||||
sifa = sctp_is_ifa_addr_preferred(sctp_ifa,
|
||||
dest_is_loop,
|
||||
dest_is_priv, fam);
|
||||
if (sifa == NULL)
|
||||
continue;
|
||||
if (sctp_is_addr_in_ep(inp, sifa)) {
|
||||
@ -2403,12 +2406,14 @@ sctp_choose_boundspecific_inp(struct sctp_inpcb *inp,
|
||||
inp->next_addr_touse = LIST_FIRST(&inp->sctp_addr_list);
|
||||
resettotop = 1;
|
||||
}
|
||||
for (laddr = inp->next_addr_touse; laddr; laddr = LIST_NEXT(laddr, sctp_nxt_addr)) {
|
||||
for (laddr = inp->next_addr_touse; laddr;
|
||||
laddr = LIST_NEXT(laddr, sctp_nxt_addr)) {
|
||||
if (laddr->ifa == NULL) {
|
||||
/* address has been removed */
|
||||
continue;
|
||||
}
|
||||
sifa = sctp_is_ifa_addr_preferred(laddr->ifa, dest_is_loop, dest_is_priv, fam);
|
||||
sifa = sctp_is_ifa_addr_preferred(laddr->ifa, dest_is_loop,
|
||||
dest_is_priv, fam);
|
||||
if (sifa == NULL)
|
||||
continue;
|
||||
atomic_add_int(&sifa->refcount, 1);
|
||||
@ -2426,12 +2431,14 @@ sctp_choose_boundspecific_inp(struct sctp_inpcb *inp,
|
||||
resettotop = 1;
|
||||
}
|
||||
/* ok, what about an acceptable address in the inp */
|
||||
for (laddr = inp->next_addr_touse; laddr; laddr = LIST_NEXT(laddr, sctp_nxt_addr)) {
|
||||
for (laddr = inp->next_addr_touse; laddr;
|
||||
laddr = LIST_NEXT(laddr, sctp_nxt_addr)) {
|
||||
if (laddr->ifa == NULL) {
|
||||
/* address has been removed */
|
||||
continue;
|
||||
}
|
||||
sifa = sctp_is_ifa_addr_acceptable(laddr->ifa, dest_is_loop, dest_is_priv, fam);
|
||||
sifa = sctp_is_ifa_addr_acceptable(laddr->ifa, dest_is_loop,
|
||||
dest_is_priv, fam);
|
||||
if (sifa == NULL)
|
||||
continue;
|
||||
atomic_add_int(&sifa->refcount, 1);
|
||||
@ -2836,7 +2843,7 @@ sctp_choose_boundall(struct sctp_inpcb *inp,
|
||||
plan_d:
|
||||
/*
|
||||
* plan_d: We are in trouble. No preferred address on the emit
|
||||
* interface. And not even a perfered address on all interfaces. Go
|
||||
* interface. And not even a preferred address on all interfaces. Go
|
||||
* out and see if we can find an acceptable address somewhere
|
||||
* amongst all interfaces.
|
||||
*/
|
||||
@ -2875,8 +2882,8 @@ sctp_choose_boundall(struct sctp_inpcb *inp,
|
||||
}
|
||||
/*
|
||||
* Ok we can find NO address to source from that is not on our
|
||||
* negative list and non_asoc_address is NOT ok, or its on our
|
||||
* negative list. We cant source to it :-(
|
||||
* restricted list and non_asoc_address is NOT ok, or it is on our
|
||||
* restricted list. We can't source to it :-(
|
||||
*/
|
||||
return (NULL);
|
||||
}
|
||||
@ -2939,7 +2946,7 @@ sctp_source_address_selection(struct sctp_inpcb *inp,
|
||||
*
|
||||
* Decisions:
|
||||
*
|
||||
* - count the number of addresses on the interface. - if its one, no
|
||||
* - count the number of addresses on the interface. - if it is one, no
|
||||
* problem except case <c>. For <a> we will assume a NAT out there.
|
||||
* - if there are more than one, then we need to worry about scope P
|
||||
* or G. We should prefer G -> G and P -> P if possible. Then as a
|
||||
@ -2994,8 +3001,7 @@ sctp_source_address_selection(struct sctp_inpcb *inp,
|
||||
SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT2, (struct sockaddr *)to);
|
||||
if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
|
||||
/*
|
||||
* When bound to all if the address list is set it is a
|
||||
* negative list. Addresses being added by asconf.
|
||||
* Bound all case
|
||||
*/
|
||||
answer = sctp_choose_boundall(inp, stcb, net, ro, vrf_id,
|
||||
dest_is_priv, dest_is_loop,
|
||||
@ -3003,21 +3009,7 @@ sctp_source_address_selection(struct sctp_inpcb *inp,
|
||||
return (answer);
|
||||
}
|
||||
/*
|
||||
* Three possiblities here:
|
||||
*
|
||||
* a) stcb is NULL, which means we operate only from the list of
|
||||
* addresses (ifa's) bound to the endpoint and we care not about the
|
||||
* list. b) stcb is NOT-NULL, which means we have an assoc structure
|
||||
* and auto-asconf is on. This means that the list of addresses is a
|
||||
* NOT list. We use the list from the inp, but any listed address in
|
||||
* our list is NOT yet added. However if the non_asoc_addr_ok is set
|
||||
* we CAN use an address NOT available (i.e. being added). Its a
|
||||
* negative list. c) stcb is NOT-NULL, which means we have an assoc
|
||||
* structure and auto-asconf is off. This means that the list of
|
||||
* addresses is the ONLY addresses I can use.. its positive.
|
||||
*
|
||||
* Note we collapse b & c into the same function just like in the v6
|
||||
* address selection.
|
||||
* Subset bound case
|
||||
*/
|
||||
if (stcb) {
|
||||
answer = sctp_choose_boundspecific_stcb(inp, stcb, net, ro,
|
||||
@ -3358,6 +3350,10 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
|
||||
net->src_addr_selected = 0;
|
||||
}
|
||||
if (net->src_addr_selected == 0) {
|
||||
if (out_of_asoc_ok) {
|
||||
/* do not cache */
|
||||
goto temp_v4_src;
|
||||
}
|
||||
/* Cache the source address */
|
||||
net->ro._s_addr = sctp_source_address_selection(inp, stcb,
|
||||
ro, net, out_of_asoc_ok,
|
||||
@ -3373,8 +3369,11 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
|
||||
} else {
|
||||
struct sctp_ifa *_lsrc;
|
||||
|
||||
_lsrc = sctp_source_address_selection(inp,
|
||||
stcb, ro, net, out_of_asoc_ok, vrf_id);
|
||||
temp_v4_src:
|
||||
_lsrc = sctp_source_address_selection(inp, stcb, ro,
|
||||
net,
|
||||
out_of_asoc_ok,
|
||||
vrf_id);
|
||||
if (_lsrc == NULL) {
|
||||
goto no_route;
|
||||
}
|
||||
@ -3621,6 +3620,10 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
|
||||
net->src_addr_selected = 0;
|
||||
}
|
||||
if (net->src_addr_selected == 0) {
|
||||
if (out_of_asoc_ok) {
|
||||
/* do not cache */
|
||||
goto temp_v6_src;
|
||||
}
|
||||
/* Cache the source address */
|
||||
net->ro._s_addr = sctp_source_address_selection(inp,
|
||||
stcb,
|
||||
@ -3639,7 +3642,11 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
|
||||
} else {
|
||||
struct sctp_ifa *_lsrc;
|
||||
|
||||
_lsrc = sctp_source_address_selection(inp, stcb, ro, net, out_of_asoc_ok, vrf_id);
|
||||
temp_v6_src:
|
||||
_lsrc = sctp_source_address_selection(inp, stcb, ro,
|
||||
net,
|
||||
out_of_asoc_ok,
|
||||
vrf_id);
|
||||
if (_lsrc == NULL) {
|
||||
goto no_route;
|
||||
}
|
||||
@ -7145,6 +7152,12 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
|
||||
*/
|
||||
hbflag = 1;
|
||||
asconf = 1;
|
||||
/*
|
||||
* should sysctl this: don't
|
||||
* bundle data with ASCONF
|
||||
* since it requires AUTH
|
||||
*/
|
||||
no_data_chunks = 1;
|
||||
}
|
||||
chk->sent = SCTP_DATAGRAM_SENT;
|
||||
chk->snd_count++;
|
||||
@ -7158,7 +7171,12 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
|
||||
*/
|
||||
if (asconf) {
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, inp, stcb, net);
|
||||
asconf = 0;
|
||||
/*
|
||||
* do NOT clear the asconf
|
||||
* flag as it is used to do
|
||||
* appropriate source
|
||||
* address selection.
|
||||
*/
|
||||
}
|
||||
if (cookie) {
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_COOKIE, inp, stcb, net);
|
||||
@ -7406,8 +7424,13 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
|
||||
if (outchain) {
|
||||
/* We may need to start a control timer or two */
|
||||
if (asconf) {
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, inp, stcb, net);
|
||||
asconf = 0;
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, inp,
|
||||
stcb, net);
|
||||
/*
|
||||
* do NOT clear the asconf flag as it is
|
||||
* used to do appropriate source address
|
||||
* selection.
|
||||
*/
|
||||
}
|
||||
if (cookie) {
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_COOKIE, inp, stcb, net);
|
||||
@ -7895,15 +7918,14 @@ void
|
||||
sctp_send_asconf(struct sctp_tcb *stcb, struct sctp_nets *net)
|
||||
{
|
||||
/*
|
||||
* formulate and queue an ASCONF to the peer ASCONF parameters
|
||||
* should be queued on the assoc queue
|
||||
* formulate and queue an ASCONF to the peer. ASCONF parameters
|
||||
* should be queued on the assoc queue.
|
||||
*/
|
||||
struct sctp_tmit_chunk *chk;
|
||||
struct mbuf *m_asconf;
|
||||
struct sctp_asconf_chunk *acp;
|
||||
int len;
|
||||
|
||||
|
||||
SCTP_TCB_LOCK_ASSERT(stcb);
|
||||
/* compose an ASCONF chunk, maximum length is PMTU */
|
||||
m_asconf = sctp_compose_asconf(stcb, &len);
|
||||
@ -7937,8 +7959,8 @@ void
|
||||
sctp_send_asconf_ack(struct sctp_tcb *stcb, uint32_t retrans)
|
||||
{
|
||||
/*
|
||||
* formulate and queue a asconf-ack back to sender the asconf-ack
|
||||
* must be stored in the tcb
|
||||
* formulate and queue a asconf-ack back to sender. the asconf-ack
|
||||
* must be stored in the tcb.
|
||||
*/
|
||||
struct sctp_tmit_chunk *chk;
|
||||
struct mbuf *m_ack, *m;
|
||||
@ -7949,10 +7971,10 @@ sctp_send_asconf_ack(struct sctp_tcb *stcb, uint32_t retrans)
|
||||
return;
|
||||
}
|
||||
/* copy the asconf_ack */
|
||||
m_ack = SCTP_M_COPYM(stcb->asoc.last_asconf_ack_sent, 0, M_COPYALL, M_DONTWAIT);
|
||||
m_ack = SCTP_M_COPYM(stcb->asoc.last_asconf_ack_sent, 0, M_COPYALL,
|
||||
M_DONTWAIT);
|
||||
if (m_ack == NULL) {
|
||||
/* couldn't copy it */
|
||||
|
||||
return;
|
||||
}
|
||||
sctp_alloc_a_chunk(stcb, chk);
|
||||
@ -11335,11 +11357,6 @@ sctp_lower_sosend(struct socket *so,
|
||||
atomic_add_int(&stcb->total_sends, 1);
|
||||
if (top == NULL) {
|
||||
struct sctp_stream_queue_pending *sp;
|
||||
|
||||
#ifdef INVARIANTS
|
||||
struct sctp_stream_queue_pending *msp;
|
||||
|
||||
#endif
|
||||
struct sctp_stream_out *strm;
|
||||
uint32_t sndout, initial_out;
|
||||
int user_marks_eor;
|
||||
@ -11373,11 +11390,6 @@ sctp_lower_sosend(struct socket *so,
|
||||
goto out;
|
||||
}
|
||||
SCTP_TCB_SEND_LOCK(stcb);
|
||||
#ifdef INVARIANTS
|
||||
msp = TAILQ_LAST(&strm->outqueue, sctp_streamhead);
|
||||
if (msp && (msp->msg_is_complete == 0))
|
||||
panic("Huh, new mesg and old not done?");
|
||||
#endif
|
||||
if (sp->msg_is_complete) {
|
||||
strm->last_msg_incomplete = 0;
|
||||
asoc->stream_locked = 0;
|
||||
|
@ -2123,9 +2123,10 @@ sctp_isport_inuse(struct sctp_inpcb *inp, uint16_t lport, uint32_t vrf_id)
|
||||
|
||||
|
||||
|
||||
/* sctp_ifap is used to bypass normal local address validation checks */
|
||||
int
|
||||
sctp_inpcb_bind(struct socket *so, struct sockaddr *addr,
|
||||
struct thread *p)
|
||||
struct sctp_ifa *sctp_ifap, struct thread *p)
|
||||
{
|
||||
/* bind a ep to a socket address */
|
||||
struct sctppcbhead *head;
|
||||
@ -2396,8 +2397,17 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr,
|
||||
* zero out the port to find the address! yuck! can't do
|
||||
* this earlier since need port for sctp_pcb_findep()
|
||||
*/
|
||||
ifa = sctp_find_ifa_by_addr((struct sockaddr *)&store_sa,
|
||||
vrf_id, 0);
|
||||
if (sctp_ifap != NULL)
|
||||
ifa = sctp_ifap;
|
||||
else {
|
||||
/*
|
||||
* Note for BSD we hit here always other O/S's will
|
||||
* pass things in via the sctp_ifap argument
|
||||
* (Panda).
|
||||
*/
|
||||
ifa = sctp_find_ifa_by_addr((struct sockaddr *)&store_sa,
|
||||
vrf_id, 0);
|
||||
}
|
||||
if (ifa == NULL) {
|
||||
/* Can't find an interface with that address */
|
||||
SCTP_INP_WUNLOCK(inp);
|
||||
@ -3401,6 +3411,7 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr,
|
||||
*/
|
||||
if ((err = sctp_inpcb_bind(inp->sctp_socket,
|
||||
(struct sockaddr *)NULL,
|
||||
(struct sctp_ifa *)NULL,
|
||||
p
|
||||
))) {
|
||||
/* bind error, probably perm */
|
||||
@ -4461,13 +4472,12 @@ sctp_del_local_addr_ep(struct sctp_inpcb *inp, struct sctp_ifa *ifa)
|
||||
}
|
||||
|
||||
/*
|
||||
* Add the addr to the TCB local address list For the BOUNDALL or dynamic
|
||||
* case, this is a "pending" address list (eg. addresses waiting for an
|
||||
* ASCONF-ACK response) For the subset binding, static case, this is a
|
||||
* "valid" address list
|
||||
* Add the address to the TCB local address restricted list.
|
||||
* This is a "pending" address list (eg. addresses waiting for an
|
||||
* ASCONF-ACK response) and cannot be used as a valid source address.
|
||||
*/
|
||||
void
|
||||
sctp_add_local_addr_assoc(struct sctp_tcb *stcb, struct sctp_ifa *ifa, int restricted_list)
|
||||
sctp_add_local_addr_restricted(struct sctp_tcb *stcb, struct sctp_ifa *ifa)
|
||||
{
|
||||
struct sctp_inpcb *inp;
|
||||
struct sctp_laddr *laddr;
|
||||
@ -4538,10 +4548,10 @@ sctp_remove_laddr(struct sctp_laddr *laddr)
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove an address from the TCB local address list
|
||||
* Remove a local address from the TCB local address restricted list
|
||||
*/
|
||||
void
|
||||
sctp_del_local_addr_assoc(struct sctp_tcb *stcb, struct sctp_ifa *ifa)
|
||||
sctp_del_local_addr_restricted(struct sctp_tcb *stcb, struct sctp_ifa *ifa)
|
||||
{
|
||||
struct sctp_inpcb *inp;
|
||||
struct sctp_laddr *laddr;
|
||||
|
@ -468,7 +468,7 @@ struct sctp_inpcb *sctp_pcb_findep(struct sockaddr *, int, int, uint32_t);
|
||||
|
||||
int
|
||||
sctp_inpcb_bind(struct socket *, struct sockaddr *,
|
||||
struct thread *);
|
||||
struct sctp_ifa *, struct thread *);
|
||||
|
||||
struct sctp_tcb *
|
||||
sctp_findassociation_addr(struct mbuf *, int, int,
|
||||
@ -533,9 +533,8 @@ int sctp_del_remote_addr(struct sctp_tcb *, struct sockaddr *);
|
||||
|
||||
void sctp_pcb_init(void);
|
||||
|
||||
void sctp_add_local_addr_assoc(struct sctp_tcb *, struct sctp_ifa *, int);
|
||||
|
||||
void sctp_del_local_addr_assoc(struct sctp_tcb *, struct sctp_ifa *);
|
||||
void sctp_add_local_addr_restricted(struct sctp_tcb *, struct sctp_ifa *);
|
||||
void sctp_del_local_addr_restricted(struct sctp_tcb *, struct sctp_ifa *);
|
||||
|
||||
int
|
||||
sctp_load_addresses_from_init(struct sctp_tcb *, struct mbuf *, int, int,
|
||||
|
@ -556,8 +556,10 @@ struct sctp_cc_functions {
|
||||
struct sctp_association {
|
||||
/* association state */
|
||||
int state;
|
||||
|
||||
/* queue of pending addrs to add/delete */
|
||||
struct sctp_asconf_addrhead asconf_queue;
|
||||
|
||||
struct timeval time_entered; /* time we entered state */
|
||||
struct timeval time_last_rcvd;
|
||||
struct timeval time_last_sent;
|
||||
@ -567,21 +569,23 @@ struct sctp_association {
|
||||
/* timers and such */
|
||||
struct sctp_timer hb_timer; /* hb timer */
|
||||
struct sctp_timer dack_timer; /* Delayed ack timer */
|
||||
struct sctp_timer asconf_timer; /* Asconf */
|
||||
struct sctp_timer asconf_timer; /* asconf */
|
||||
struct sctp_timer strreset_timer; /* stream reset */
|
||||
struct sctp_timer shut_guard_timer; /* guard */
|
||||
struct sctp_timer shut_guard_timer; /* shutdown guard */
|
||||
struct sctp_timer autoclose_timer; /* automatic close timer */
|
||||
struct sctp_timer delayed_event_timer; /* timer for delayed events */
|
||||
|
||||
/* list of local addresses when add/del in progress */
|
||||
/* list of restricted local addresses */
|
||||
struct sctpladdr sctp_restricted_addrs;
|
||||
|
||||
struct sctpnetlisthead nets;
|
||||
/* last local address pending deletion (waiting for an address add) */
|
||||
struct sctp_ifa *asconf_addr_del_pending;
|
||||
|
||||
struct sctpnetlisthead nets; /* remote address list */
|
||||
|
||||
/* Free chunk list */
|
||||
struct sctpchunk_listhead free_chunks;
|
||||
|
||||
|
||||
/* Control chunk queue */
|
||||
struct sctpchunk_listhead control_send_queue;
|
||||
|
||||
@ -595,7 +599,6 @@ struct sctp_association {
|
||||
struct sctpchunk_listhead sent_queue;
|
||||
struct sctpchunk_listhead send_queue;
|
||||
|
||||
|
||||
/* re-assembly queue for fragmented chunks on the inbound path */
|
||||
struct sctpchunk_listhead reasmqueue;
|
||||
|
||||
@ -618,12 +621,6 @@ struct sctp_association {
|
||||
/* If an iterator is looking at me, this is it */
|
||||
struct sctp_iterator *stcb_starting_point_for_iterator;
|
||||
|
||||
/* ASCONF destination address last sent to */
|
||||
/* struct sctp_nets *asconf_last_sent_to;*/
|
||||
/* Peter, greppign for the above shows only on strange set
|
||||
* I don't think we need it so I have commented it out.
|
||||
*/
|
||||
|
||||
/* ASCONF save the last ASCONF-ACK so we can resend it if necessary */
|
||||
struct mbuf *last_asconf_ack_sent;
|
||||
|
||||
@ -907,7 +904,8 @@ struct sctp_association {
|
||||
* lock flag: 0 is ok to send, 1+ (duals as a retran count) is
|
||||
* awaiting ACK
|
||||
*/
|
||||
uint16_t asconf_sent; /* possibly removable REM */
|
||||
uint16_t asconf_sent;
|
||||
|
||||
uint16_t mapping_array_size;
|
||||
|
||||
uint16_t last_strm_seq_delivered;
|
||||
@ -944,6 +942,7 @@ struct sctp_association {
|
||||
uint8_t hb_random_idx;
|
||||
uint8_t hb_is_disabled; /* is the hb disabled? */
|
||||
uint8_t default_tos;
|
||||
uint8_t asconf_del_pending; /* asconf delete last addr pending */
|
||||
|
||||
/* ECN Nonce stuff */
|
||||
uint8_t receiver_nonce_sum; /* nonce I sum and put in my sack */
|
||||
|
@ -1301,12 +1301,14 @@ sctp_asconf_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
|
||||
struct sctp_nets *alt;
|
||||
struct sctp_tmit_chunk *asconf, *chk;
|
||||
|
||||
/* is this the first send, or a retransmission? */
|
||||
/* is this a first send, or a retransmission? */
|
||||
if (stcb->asoc.asconf_sent == 0) {
|
||||
/* compose a new ASCONF chunk and send it */
|
||||
sctp_send_asconf(stcb, net);
|
||||
} else {
|
||||
/* Retransmission of the existing ASCONF needed... */
|
||||
/*
|
||||
* Retransmission of the existing ASCONF is needed
|
||||
*/
|
||||
|
||||
/* find the existing ASCONF */
|
||||
TAILQ_FOREACH(asconf, &stcb->asoc.control_send_queue,
|
||||
@ -1324,25 +1326,21 @@ sctp_asconf_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
|
||||
/* Assoc is over */
|
||||
return (1);
|
||||
}
|
||||
/*
|
||||
* PETER? FIX? How will the following code ever run? If the
|
||||
* max_send_times is hit, threshold managment will blow away
|
||||
* the association?
|
||||
*/
|
||||
if (asconf->snd_count > stcb->asoc.max_send_times) {
|
||||
/*
|
||||
* Something is rotten, peer is not responding to
|
||||
* ASCONFs but maybe is to data etc. e.g. it is not
|
||||
* properly handling the chunk type upper bits Mark
|
||||
* this peer as ASCONF incapable and cleanup
|
||||
* Something is rotten: our peer is not responding
|
||||
* to ASCONFs but apparently is to other chunks.
|
||||
* i.e. it is not properly handling the chunk type
|
||||
* upper bits. Mark this peer as ASCONF incapable
|
||||
* and cleanup.
|
||||
*/
|
||||
SCTPDBG(SCTP_DEBUG_TIMER1, "asconf_timer: Peer has not responded to our repeated ASCONFs\n");
|
||||
sctp_asconf_cleanup(stcb, net);
|
||||
return (0);
|
||||
}
|
||||
/*
|
||||
* cleared theshold management now lets backoff the address
|
||||
* & select an alternate
|
||||
* cleared threshold management, so now backoff the net and
|
||||
* select an alternate
|
||||
*/
|
||||
sctp_backoff_on_timeout(stcb, asconf->whoTo, 1, 0);
|
||||
alt = sctp_find_alternate_net(stcb, asconf->whoTo, 0);
|
||||
@ -1350,7 +1348,7 @@ sctp_asconf_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
|
||||
asconf->whoTo = alt;
|
||||
atomic_add_int(&alt->ref_count, 1);
|
||||
|
||||
/* See if a ECN Echo is also stranded */
|
||||
/* See if an ECN Echo is also stranded */
|
||||
TAILQ_FOREACH(chk, &stcb->asoc.control_send_queue, sctp_next) {
|
||||
if ((chk->whoTo == net) &&
|
||||
(chk->rec.chunk_id.id == SCTP_ECN_ECHO)) {
|
||||
@ -1366,7 +1364,7 @@ sctp_asconf_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
|
||||
if (net->dest_state & SCTP_ADDR_NOT_REACHABLE) {
|
||||
/*
|
||||
* If the address went un-reachable, we need to move
|
||||
* to alternates for ALL chk's in queue
|
||||
* to the alternate for ALL chunks in queue
|
||||
*/
|
||||
sctp_move_all_chunks_to_alt(stcb, net, alt);
|
||||
}
|
||||
|
@ -573,7 +573,7 @@ sctp_bind(struct socket *so, struct sockaddr *addr, struct thread *p)
|
||||
if (inp == 0)
|
||||
return EINVAL;
|
||||
|
||||
error = sctp_inpcb_bind(so, addr, p);
|
||||
error = sctp_inpcb_bind(so, addr, NULL, p);
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -1170,7 +1170,6 @@ sctp_fill_up_addresses_vrf(struct sctp_inpcb *inp,
|
||||
} else {
|
||||
struct sctp_laddr *laddr;
|
||||
|
||||
/* The list is a NEGATIVE list */
|
||||
LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
|
||||
if (stcb) {
|
||||
if (sctp_is_addr_restricted(stcb, laddr->ifa)) {
|
||||
@ -1345,7 +1344,7 @@ sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval,
|
||||
if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) ==
|
||||
SCTP_PCB_FLAGS_UNBOUND) {
|
||||
/* Bind a ephemeral port */
|
||||
error = sctp_inpcb_bind(so, NULL, p);
|
||||
error = sctp_inpcb_bind(so, NULL, NULL, p);
|
||||
if (error) {
|
||||
goto out_now;
|
||||
}
|
||||
@ -3479,7 +3478,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
|
||||
sasoc->sasoc_peer_rwnd = 0;
|
||||
sasoc->sasoc_local_rwnd = 0;
|
||||
if (sasoc->sasoc_cookie_life) {
|
||||
stcb->asoc.cookie_life = sasoc->sasoc_cookie_life;
|
||||
stcb->asoc.cookie_life = MSEC_TO_TICKS(sasoc->sasoc_cookie_life);
|
||||
|
||||
}
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
@ -3805,7 +3804,7 @@ sctp_connect(struct socket *so, struct sockaddr *addr, struct thread *p)
|
||||
if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) ==
|
||||
SCTP_PCB_FLAGS_UNBOUND) {
|
||||
/* Bind a ephemeral port */
|
||||
error = sctp_inpcb_bind(so, NULL, p);
|
||||
error = sctp_inpcb_bind(so, NULL, NULL, p);
|
||||
if (error) {
|
||||
goto out_now;
|
||||
}
|
||||
@ -3916,7 +3915,7 @@ sctp_listen(struct socket *so, int backlog, struct thread *p)
|
||||
/* We must do a bind. */
|
||||
SOCK_UNLOCK(so);
|
||||
SCTP_INP_RUNLOCK(inp);
|
||||
if ((error = sctp_inpcb_bind(so, NULL, p))) {
|
||||
if ((error = sctp_inpcb_bind(so, NULL, NULL, p))) {
|
||||
/* bind error, probably perm */
|
||||
return (error);
|
||||
}
|
||||
|
@ -1373,15 +1373,15 @@ sctp_handle_addr_wq(void)
|
||||
if (asc->cnt == 0) {
|
||||
SCTP_FREE(asc, SCTP_M_ASC_IT);
|
||||
} else {
|
||||
(void)sctp_initiate_iterator(sctp_iterator_ep,
|
||||
sctp_iterator_stcb,
|
||||
(void)sctp_initiate_iterator(sctp_asconf_iterator_ep,
|
||||
sctp_asconf_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);
|
||||
SCTP_ASOC_ANY_STATE,
|
||||
(void *)asc, 0,
|
||||
sctp_asconf_iterator_end, NULL, 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int retcode = 0;
|
||||
@ -2078,8 +2078,8 @@ sctp_timer_start(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
|
||||
break;
|
||||
case SCTP_TIMER_TYPE_STRRESET:
|
||||
/*
|
||||
* Here the timer comes from the inp but its value is from
|
||||
* the RTO.
|
||||
* Here the timer comes from the stcb but its value is from
|
||||
* the net's RTO.
|
||||
*/
|
||||
if ((stcb == NULL) || (net == NULL)) {
|
||||
return;
|
||||
@ -2122,8 +2122,8 @@ sctp_timer_start(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
|
||||
break;
|
||||
case SCTP_TIMER_TYPE_ASCONF:
|
||||
/*
|
||||
* Here the timer comes from the inp but its value is from
|
||||
* the RTO.
|
||||
* Here the timer comes from the stcb but its value is from
|
||||
* the net's RTO.
|
||||
*/
|
||||
if ((stcb == NULL) || (net == NULL)) {
|
||||
return;
|
||||
@ -5932,7 +5932,7 @@ sctp_bindx_add_address(struct socket *so, struct sctp_inpcb *inp,
|
||||
*error = EINVAL;
|
||||
return;
|
||||
}
|
||||
*error = sctp_inpcb_bind(so, addr_touse, p);
|
||||
*error = sctp_inpcb_bind(so, addr_touse, NULL, p);
|
||||
return;
|
||||
}
|
||||
/*
|
||||
@ -6056,3 +6056,113 @@ sctp_bindx_delete_address(struct socket *so, struct sctp_inpcb *inp,
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* returns the valid local address count for an assoc, taking into account
|
||||
* all scoping rules
|
||||
*/
|
||||
int
|
||||
sctp_local_addr_count(struct sctp_tcb *stcb)
|
||||
{
|
||||
int loopback_scope, ipv4_local_scope, local_scope, site_scope;
|
||||
int ipv4_addr_legal, ipv6_addr_legal;
|
||||
struct sctp_vrf *vrf;
|
||||
struct sctp_ifn *sctp_ifn;
|
||||
struct sctp_ifa *sctp_ifa;
|
||||
int count = 0;
|
||||
|
||||
/* Turn on all the appropriate scopes */
|
||||
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;
|
||||
ipv4_addr_legal = ipv6_addr_legal = 0;
|
||||
if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
|
||||
ipv6_addr_legal = 1;
|
||||
if (SCTP_IPV6_V6ONLY(stcb->sctp_ep) == 0) {
|
||||
ipv4_addr_legal = 1;
|
||||
}
|
||||
} else {
|
||||
ipv4_addr_legal = 1;
|
||||
}
|
||||
|
||||
vrf = sctp_find_vrf(stcb->asoc.vrf_id);
|
||||
if (vrf == NULL) {
|
||||
/* no vrf, no addresses */
|
||||
return (0);
|
||||
}
|
||||
if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
|
||||
/*
|
||||
* bound all case: go through all ifns on the vrf
|
||||
*/
|
||||
LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) {
|
||||
if ((loopback_scope == 0) &&
|
||||
SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) {
|
||||
continue;
|
||||
}
|
||||
LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
|
||||
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) {
|
||||
/* skip unspecified addrs */
|
||||
continue;
|
||||
}
|
||||
if ((ipv4_local_scope == 0) &&
|
||||
(IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) {
|
||||
continue;
|
||||
}
|
||||
/* count this one */
|
||||
count++;
|
||||
} 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) {
|
||||
if (sa6_recoverscope(sin6) != 0)
|
||||
/*
|
||||
* bad link
|
||||
* local
|
||||
* address
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if ((site_scope == 0) &&
|
||||
(IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))) {
|
||||
continue;
|
||||
}
|
||||
/* count this one */
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* subset bound case
|
||||
*/
|
||||
struct sctp_laddr *laddr;
|
||||
|
||||
LIST_FOREACH(laddr, &stcb->sctp_ep->sctp_addr_list,
|
||||
sctp_nxt_addr) {
|
||||
if (sctp_is_addr_restricted(stcb, laddr->ifa)) {
|
||||
continue;
|
||||
}
|
||||
/* count this one */
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return (count);
|
||||
}
|
||||
|
@ -219,6 +219,8 @@ sctp_bindx_delete_address(struct socket *so, struct sctp_inpcb *inp,
|
||||
struct sockaddr *sa, sctp_assoc_t assoc_id,
|
||||
uint32_t vrf_id, int *error);
|
||||
|
||||
int sctp_local_addr_count(struct sctp_tcb *stcb);
|
||||
|
||||
#ifdef SCTP_MBCNT_LOGGING
|
||||
void
|
||||
sctp_free_bufspace(struct sctp_tcb *, struct sctp_association *,
|
||||
|
@ -614,7 +614,7 @@ sctp6_bind(struct socket *so, struct sockaddr *addr, struct thread *p)
|
||||
in6_sin6_2_sin(&sin, sin6_p);
|
||||
inp6->inp_vflag |= INP_IPV4;
|
||||
inp6->inp_vflag &= ~INP_IPV6;
|
||||
error = sctp_inpcb_bind(so, (struct sockaddr *)&sin, p);
|
||||
error = sctp_inpcb_bind(so, (struct sockaddr *)&sin, NULL, p);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
@ -634,7 +634,7 @@ sctp6_bind(struct socket *so, struct sockaddr *addr, struct thread *p)
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
error = sctp_inpcb_bind(so, addr, p);
|
||||
error = sctp_inpcb_bind(so, addr, NULL, p);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user