- Adds support for the multi-asconf (From Kozuka-san)

- Adds some prepwork (Not all yet) for vimage in particular
  support the delete the sctppcbinfo.xx structs. There is
  still a leak in here if it were to be called plus we stil
  need the regrouping (From Me and Michael Tuexen)
- Adds support for UDP tunneling. For BSD there is no
  socket yet setup so its disabled, but major argument
  changes are in here to emcompass the passing of the port
  number (zero when you don't have a udp tunnel, the default
  for BSD). Will add some hooks in UDP here shortly (discussed
  with Robert) that will allow easy tunneling. (Mainly from
  Peter Lei and Michael Tuexen with some BSD work from me :-D)
- Some ease for windows, evidently leave is reserved by their
  compile move label leave: -> out:

MFC after:	1 week
This commit is contained in:
Randall Stewart 2008-05-20 13:47:46 +00:00
parent 7840976da5
commit c54a18d26b
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=179157
23 changed files with 1303 additions and 554 deletions

View File

@ -472,6 +472,7 @@ __attribute__((packed));
#define SCTP_PCB_FLAGS_NO_FRAGMENT 0x00100000
#define SCTP_PCB_FLAGS_EXPLICIT_EOR 0x00400000
#define SCTP_PCB_FLAGS_NEEDS_MAPPED_V4 0x00800000
#define SCTP_PCB_FLAGS_MULTIPLE_ASCONFS 0x01000000
/*-
* mobility_features parameters (by micchie).Note

View File

@ -930,6 +930,56 @@ sctp_asconf_addr_match(struct sctp_asconf_addr *aa, struct sockaddr *sa)
return (0);
}
/*
* does the address match? returns 0 if not, 1 if so
*/
static uint32_t
sctp_addr_match(
#ifdef INET6
struct sctp_ipv6addr_param *v6addr,
#else
struct sctp_ipv4addr_param *v4addr,
#endif
struct sockaddr *sa)
{
uint16_t param_type, param_length;
#ifdef INET6
struct sctp_ipv4addr_param *v4addr = (struct sctp_ipv4addr_param *)v6addr;
if (sa->sa_family == AF_INET6) {
/* IPv6 sa address */
/* XXX scopeid */
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
param_type = ntohs(v6addr->ph.param_type);
param_length = ntohs(v6addr->ph.param_length);
if ((param_type == SCTP_IPV6_ADDRESS) &&
param_length == sizeof(struct sctp_ipv6addr_param) &&
(memcmp(&v6addr->addr, &sin6->sin6_addr,
sizeof(struct in6_addr)) == 0)) {
return (1);
}
} else
#endif /* INET6 */
if (sa->sa_family == AF_INET) {
/* IPv4 sa address */
struct sockaddr_in *sin = (struct sockaddr_in *)sa;
param_type = ntohs(v4addr->ph.param_type);
param_length = ntohs(v4addr->ph.param_length);
if ((param_type == SCTP_IPV4_ADDRESS) &&
param_length == sizeof(struct sctp_ipv4addr_param) &&
(memcmp(&v4addr->addr, &sin->sin_addr,
sizeof(struct in_addr)) == 0)) {
return (1);
}
}
return (0);
}
/*
* Cleanup for non-responded/OP ERR'd ASCONF
*/
@ -943,7 +993,7 @@ sctp_asconf_cleanup(struct sctp_tcb *stcb, struct sctp_nets *net)
*/
sctp_timer_stop(SCTP_TIMER_TYPE_ASCONF, stcb->sctp_ep, stcb, net,
SCTP_FROM_SCTP_ASCONF + SCTP_LOC_2);
stcb->asoc.asconf_seq_out++;
stcb->asoc.asconf_seq_out_acked = stcb->asoc.asconf_seq_out;
/* remove the old ASCONF on our outbound queue */
sctp_toss_old_asconf(stcb);
}
@ -1259,8 +1309,14 @@ sctp_asconf_queue_mgmt(struct sctp_tcb *stcb, struct sctp_ifa *ifa,
/* address match? */
if (sctp_asconf_addr_match(aa, &ifa->address.sa) == 0)
continue;
/* is the request already in queue (sent or not) */
if (aa->ap.aph.ph.param_type == type) {
/*
* is the request already in queue but not sent? pass the
* request already sent in order to resolve the following
* case: 1. arrival of ADD, then sent 2. arrival of DEL. we
* can't remove the ADD request already sent 3. arrival of
* ADD
*/
if (aa->ap.aph.ph.param_type == type && aa->sent == 0) {
return (-1);
}
/* is the negative request already in queue, and not sent */
@ -1334,31 +1390,21 @@ sctp_asconf_queue_mgmt(struct sctp_tcb *stcb, struct sctp_ifa *ifa,
}
aa->sent = 0; /* clear sent flag */
/*
* if we are deleting an address it should go out last otherwise,
* add it to front of the pending queue
*/
if (type == SCTP_ADD_IP_ADDRESS) {
/* add goes to the front of the queue */
TAILQ_INSERT_HEAD(&stcb->asoc.asconf_queue, aa, next);
SCTPDBG(SCTP_DEBUG_ASCONF2,
"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 */
TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next);
TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next);
#ifdef SCTP_DEBUG
if (sctp_debug_on && SCTP_DEBUG_ASCONF2) {
if (type == SCTP_DEL_IP_ADDRESS) {
SCTP_PRINTF("asconf_queue_mgmt: appended asconf DEL_IP_ADDRESS: ");
SCTPDBG_ADDR(SCTP_DEBUG_ASCONF2, sa);
} else {
SCTP_PRINTF("asconf_queue_mgmt: appended asconf SET_PRIM_ADDR: ");
SCTPDBG_ADDR(SCTP_DEBUG_ASCONF2, sa);
}
if (sctp_debug_on && SCTP_DEBUG_ASCONF2) {
if (type == SCTP_ADD_IP_ADDRESS) {
SCTP_PRINTF("asconf_queue_mgmt: inserted asconf ADD_IP_ADDRESS: ");
SCTPDBG_ADDR(SCTP_DEBUG_ASCONF2, sa);
} else if (type == SCTP_DEL_IP_ADDRESS) {
SCTP_PRINTF("asconf_queue_mgmt: appended asconf DEL_IP_ADDRESS: ");
SCTPDBG_ADDR(SCTP_DEBUG_ASCONF2, sa);
} else {
SCTP_PRINTF("asconf_queue_mgmt: appended asconf SET_PRIM_ADDR: ");
SCTPDBG_ADDR(SCTP_DEBUG_ASCONF2, sa);
}
#endif
}
#endif
return (0);
}
@ -1395,12 +1441,15 @@ sctp_asconf_queue_add(struct sctp_tcb *stcb, struct sctp_ifa *ifa,
"asconf_queue_add: mark delete last address pending\n");
return (-1);
}
/* queue an asconf parameter */
status = sctp_asconf_queue_mgmt(stcb, ifa, type);
/*
* 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) {
if ((type == SCTP_ADD_IP_ADDRESS) && stcb->asoc.asconf_del_pending && (status == 0)) {
/* queue in the pending delete */
if (sctp_asconf_queue_mgmt(stcb,
stcb->asoc.asconf_addr_del_pending,
@ -1413,10 +1462,7 @@ sctp_asconf_queue_add(struct sctp_tcb *stcb, struct sctp_ifa *ifa,
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)) {
if (pending_delete_queued) {
struct sctp_nets *net;
/*
@ -1652,6 +1698,8 @@ sctp_asconf_process_param_ack(struct sctp_tcb *stcb,
/* nothing really to do... lists already updated */
break;
case SCTP_SET_PRIM_ADDR:
SCTPDBG(SCTP_DEBUG_ASCONF1,
"process_param_ack: set primary IP address\n");
/* nothing to do... peer may start using this addr */
if (flag == 0)
stcb->asoc.peer_supports_asconf = 0;
@ -1725,23 +1773,17 @@ sctp_handle_asconf_ack(struct mbuf *m, int offset,
*abort_no_unlock = 1;
return;
}
if (serial_num != asoc->asconf_seq_out) {
if (serial_num != asoc->asconf_seq_out_acked + 1) {
/* got a duplicate/unexpected ASCONF-ACK */
SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf_ack: got duplicate/unexpected serial number = %xh (expected = %xh)\n",
serial_num, asoc->asconf_seq_out);
serial_num, asoc->asconf_seq_out_acked + 1);
return;
}
if (stcb->asoc.asconf_sent == 0) {
/* got a unexpected ASCONF-ACK for serial not in flight */
SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf_ack: got serial number = %xh but not in flight\n",
serial_num);
/* nothing to do... duplicate ACK received */
return;
if (serial_num == asoc->asconf_seq_out - 1) {
/* stop our timer */
sctp_timer_stop(SCTP_TIMER_TYPE_ASCONF, stcb->sctp_ep, stcb, net,
SCTP_FROM_SCTP_ASCONF + SCTP_LOC_3);
}
/* stop our timer */
sctp_timer_stop(SCTP_TIMER_TYPE_ASCONF, stcb->sctp_ep, stcb, net,
SCTP_FROM_SCTP_ASCONF + SCTP_LOC_3);
/* process the ASCONF-ACK contents */
ack_length = ntohs(cp->ch.chunk_length) -
sizeof(struct sctp_asconf_ack_chunk);
@ -1855,11 +1897,9 @@ sctp_handle_asconf_ack(struct mbuf *m, int offset,
}
/* update the next sequence number to use */
asoc->asconf_seq_out++;
asoc->asconf_seq_out_acked++;
/* remove the old ASCONF on our outbound queue */
sctp_toss_old_asconf(stcb);
/* 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 */
@ -2379,6 +2419,102 @@ sctp_set_primary_ip_address(struct sctp_ifa *ifa)
} /* for each inp */
}
int
sctp_is_addr_pending(struct sctp_tcb *stcb, struct sctp_ifa *sctp_ifa)
{
struct sctp_tmit_chunk *chk, *nchk;
unsigned int offset, asconf_limit;
struct sctp_asconf_chunk *acp;
struct sctp_asconf_paramhdr *aph;
uint8_t aparam_buf[SCTP_PARAM_BUFFER_SIZE];
struct sctp_ipv6addr_param *p_addr;
int add_cnt, del_cnt;
uint16_t last_param_type;
add_cnt = del_cnt = 0;
last_param_type = 0;
for (chk = TAILQ_FIRST(&stcb->asoc.asconf_send_queue); chk != NULL;
chk = nchk) {
/* get next chk */
nchk = TAILQ_NEXT(chk, sctp_next);
if (chk->data == NULL) {
SCTPDBG(SCTP_DEBUG_ASCONF1, "is_addr_pending: No mbuf data?\n");
continue;
}
offset = 0;
acp = mtod(chk->data, struct sctp_asconf_chunk *);
offset += sizeof(struct sctp_asconf_chunk);
asconf_limit = ntohs(acp->ch.chunk_length);
p_addr = (struct sctp_ipv6addr_param *)sctp_m_getptr(chk->data, offset, sizeof(struct sctp_paramhdr), aparam_buf);
if (p_addr == NULL) {
SCTPDBG(SCTP_DEBUG_ASCONF1, "is_addr_pending: couldn't get lookup addr!\n");
continue;
}
offset += ntohs(p_addr->ph.param_length);
aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(chk->data, offset, sizeof(struct sctp_asconf_paramhdr), aparam_buf);
if (aph == NULL) {
SCTPDBG(SCTP_DEBUG_ASCONF1, "is_addr_pending: Empty ASCONF will be sent?\n");
continue;
}
while (aph != NULL) {
unsigned int param_length, param_type;
param_type = ntohs(aph->ph.param_type);
param_length = ntohs(aph->ph.param_length);
if (offset + param_length > asconf_limit) {
/* parameter goes beyond end of chunk! */
break;
}
if (param_length > sizeof(aparam_buf)) {
SCTPDBG(SCTP_DEBUG_ASCONF1, "is_addr_pending: param length (%u) larger than buffer size!\n", param_length);
break;
}
if (param_length <= sizeof(struct sctp_paramhdr)) {
SCTPDBG(SCTP_DEBUG_ASCONF1, "is_addr_pending: param length(%u) too short\n", param_length);
break;
}
aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(chk->data, offset, param_length, aparam_buf);
if (aph == NULL) {
SCTPDBG(SCTP_DEBUG_ASCONF1, "is_addr_pending: couldn't get entire param\n");
break;
}
p_addr = (struct sctp_ipv6addr_param *)(aph + 1);
if (sctp_addr_match(p_addr, &sctp_ifa->address.sa) != 0) {
switch (param_type) {
case SCTP_ADD_IP_ADDRESS:
add_cnt++;
break;
case SCTP_DEL_IP_ADDRESS:
del_cnt++;
break;
default:
break;
}
last_param_type = param_type;
}
offset += SCTP_SIZE32(param_length);
if (offset >= asconf_limit) {
/* no more data in the mbuf chain */
break;
}
/* get pointer to next asconf param */
aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(chk->data, offset, sizeof(struct sctp_asconf_paramhdr), aparam_buf);
}
}
/*
* we want to find the sequences which consist of ADD -> DEL -> ADD
* or DEL -> ADD
*/
if (add_cnt > del_cnt ||
(add_cnt == del_cnt && last_param_type == SCTP_ADD_IP_ADDRESS)) {
return 1;
}
return 0;
}
static struct sockaddr *
sctp_find_valid_localaddr(struct sctp_tcb *stcb, int addr_locked)
{
@ -2414,7 +2550,8 @@ sctp_find_valid_localaddr(struct sctp_tcb *stcb, int addr_locked)
IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))
continue;
if (sctp_is_addr_restricted(stcb, sctp_ifa))
if (sctp_is_addr_restricted(stcb, sctp_ifa) &&
(!sctp_is_addr_pending(stcb, sctp_ifa)))
continue;
/* found a valid local v4 address to use */
if (addr_locked == SCTP_ADDR_NOT_LOCKED)
@ -2439,6 +2576,9 @@ sctp_find_valid_localaddr(struct sctp_tcb *stcb, int addr_locked)
IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))
continue;
if (sctp_is_addr_restricted(stcb, sctp_ifa) &&
(!sctp_is_addr_pending(stcb, sctp_ifa)))
continue;
/* found a valid local v6 address to use */
if (addr_locked == SCTP_ADDR_NOT_LOCKED)
SCTP_IPI_ADDR_RUNLOCK();
@ -2462,7 +2602,8 @@ sctp_find_valid_localaddr_ep(struct sctp_tcb *stcb)
continue;
}
/* is the address restricted ? */
if (sctp_is_addr_restricted(stcb, laddr->ifa))
if (sctp_is_addr_restricted(stcb, laddr->ifa) &&
(!sctp_is_addr_pending(stcb, laddr->ifa)))
continue;
/* found a valid local address to use */
@ -2490,13 +2631,13 @@ sctp_compose_asconf(struct sctp_tcb *stcb, int *retlen, int addr_locked)
uint8_t lookup_used = 0;
/* are there any asconf params to send? */
if (TAILQ_EMPTY(&stcb->asoc.asconf_queue)) {
return (NULL);
TAILQ_FOREACH(aa, &stcb->asoc.asconf_queue, next) {
if (aa->sent == 0)
break;
}
/* can't send a new one if there is one in flight already */
if (stcb->asoc.asconf_sent > 0) {
if (aa == NULL)
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
@ -2529,9 +2670,12 @@ sctp_compose_asconf(struct sctp_tcb *stcb, int *retlen, int addr_locked)
acp->ch.chunk_type = SCTP_ASCONF;
acp->ch.chunk_flags = 0;
acp->serial_number = htonl(stcb->asoc.asconf_seq_out);
stcb->asoc.asconf_seq_out++;
/* add parameters... up to smallest MTU allowed */
TAILQ_FOREACH(aa, &stcb->asoc.asconf_queue, next) {
if (aa->sent)
continue;
/* get the parameter length */
p_length = SCTP_SIZE32(aa->ap.aph.ph.param_length);
/* will it fit in current chunk? */
@ -2647,9 +2791,6 @@ sctp_compose_asconf(struct sctp_tcb *stcb, int *retlen, int addr_locked)
*retlen = SCTP_BUF_LEN(m_asconf_chk) + SCTP_BUF_LEN(m_asconf);
acp->ch.chunk_length = ntohs(*retlen);
/* update "sent" flag */
stcb->asoc.asconf_sent++;
return (m_asconf_chk);
}

View File

@ -86,6 +86,9 @@ extern void
extern void
sctp_net_immediate_retrans(struct sctp_tcb *, struct sctp_nets *);
extern int
sctp_is_addr_pending(struct sctp_tcb *, struct sctp_ifa *);
#endif /* _KERNEL */
#endif /* !_NETINET_SCTP_ASCONF_H_ */

View File

@ -49,13 +49,10 @@ sctp_set_initial_cc_param(struct sctp_tcb *stcb, struct sctp_nets *net)
{
/*
* We take the max of the burst limit times a MTU or the
* INITIAL_CWND. We then limit this to 4 MTU's of sending.
* INITIAL_CWND. We then limit this to 4 MTU's of sending. cwnd must
* be at least 2 MTU.
*/
net->cwnd = min((net->mtu * 4), max((2 * net->mtu), SCTP_INITIAL_CWND));
/* we always get at LEAST 2 MTU's */
if (net->cwnd < (2 * net->mtu)) {
net->cwnd = 2 * net->mtu;
}
net->ssthresh = stcb->asoc.peers_rwnd;
if (sctp_logging_level & (SCTP_CWND_MONITOR_ENABLE | SCTP_CWND_LOGGING_ENABLE)) {
@ -277,8 +274,7 @@ sctp_cwnd_update_after_sack(struct sctp_tcb *stcb,
/* If the cumulative ack moved we can proceed */
if (net->cwnd <= net->ssthresh) {
/* We are in slow start */
if (net->flight_size + net->net_ack >=
net->cwnd) {
if (net->flight_size + net->net_ack >= net->cwnd) {
if (net->net_ack > (net->mtu * sctp_L2_abc_variable)) {
net->cwnd += (net->mtu * sctp_L2_abc_variable);
if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) {
@ -293,10 +289,6 @@ sctp_cwnd_update_after_sack(struct sctp_tcb *stcb,
}
}
} else {
unsigned int dif;
dif = net->cwnd - (net->flight_size +
net->net_ack);
if (sctp_logging_level & SCTP_CWND_LOGGING_ENABLE) {
sctp_log_cwnd(stcb, net, net->net_ack,
SCTP_CWND_LOG_NOADV_SS);
@ -307,8 +299,7 @@ sctp_cwnd_update_after_sack(struct sctp_tcb *stcb,
/*
* Add to pba
*/
net->partial_bytes_acked +=
net->net_ack;
net->partial_bytes_acked += net->net_ack;
if ((net->flight_size + net->net_ack >= net->cwnd) &&
(net->partial_bytes_acked >= net->cwnd)) {
@ -352,23 +343,182 @@ sctp_cwnd_update_after_sack(struct sctp_tcb *stcb,
}
void
sctp_cwnd_update_after_timeout(struct sctp_tcb *stcb,
struct sctp_nets *net)
sctp_cwnd_update_after_timeout(struct sctp_tcb *stcb, struct sctp_nets *net)
{
int old_cwnd = net->cwnd;
net->ssthresh = net->cwnd >> 1;
if (net->ssthresh < (net->mtu << 1)) {
net->ssthresh = (net->mtu << 1);
}
net->ssthresh = max(net->cwnd / 2, 2 * net->mtu);
net->cwnd = net->mtu;
/* floor of 1 mtu */
if (net->cwnd < net->mtu)
net->cwnd = net->mtu;
net->partial_bytes_acked = 0;
if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) {
sctp_log_cwnd(stcb, net, net->cwnd - old_cwnd, SCTP_CWND_LOG_FROM_RTX);
}
net->partial_bytes_acked = 0;
}
void
sctp_cwnd_update_after_ecn_echo(struct sctp_tcb *stcb, struct sctp_nets *net)
{
int old_cwnd = net->cwnd;
SCTP_STAT_INCR(sctps_ecnereducedcwnd);
net->ssthresh = net->cwnd / 2;
if (net->ssthresh < net->mtu) {
net->ssthresh = net->mtu;
/* here back off the timer as well, to slow us down */
net->RTO <<= 1;
}
net->cwnd = net->ssthresh;
if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) {
sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SAT);
}
}
void
sctp_cwnd_update_after_packet_dropped(struct sctp_tcb *stcb,
struct sctp_nets *net, struct sctp_pktdrop_chunk *cp,
uint32_t * bottle_bw, uint32_t * on_queue)
{
uint32_t bw_avail;
int rtt, incr;
int old_cwnd = net->cwnd;
/* need real RTT for this calc */
rtt = ((net->lastsa >> 2) + net->lastsv) >> 1;
/* get bottle neck bw */
*bottle_bw = ntohl(cp->bottle_bw);
/* and whats on queue */
*on_queue = ntohl(cp->current_onq);
/*
* adjust the on-queue if our flight is more it could be that the
* router has not yet gotten data "in-flight" to it
*/
if (*on_queue < net->flight_size)
*on_queue = net->flight_size;
/* calculate the available space */
bw_avail = (*bottle_bw * rtt) / 1000;
if (bw_avail > *bottle_bw) {
/*
* Cap the growth to no more than the bottle neck. This can
* happen as RTT slides up due to queues. It also means if
* you have more than a 1 second RTT with a empty queue you
* will be limited to the bottle_bw per second no matter if
* other points have 1/2 the RTT and you could get more
* out...
*/
bw_avail = *bottle_bw;
}
if (*on_queue > bw_avail) {
/*
* No room for anything else don't allow anything else to be
* "added to the fire".
*/
int seg_inflight, seg_onqueue, my_portion;
net->partial_bytes_acked = 0;
/* how much are we over queue size? */
incr = *on_queue - bw_avail;
if (stcb->asoc.seen_a_sack_this_pkt) {
/*
* undo any cwnd adjustment that the sack might have
* made
*/
net->cwnd = net->prev_cwnd;
}
/* Now how much of that is mine? */
seg_inflight = net->flight_size / net->mtu;
seg_onqueue = *on_queue / net->mtu;
my_portion = (incr * seg_inflight) / seg_onqueue;
/* Have I made an adjustment already */
if (net->cwnd > net->flight_size) {
/*
* for this flight I made an adjustment we need to
* decrease the portion by a share our previous
* adjustment.
*/
int diff_adj;
diff_adj = net->cwnd - net->flight_size;
if (diff_adj > my_portion)
my_portion = 0;
else
my_portion -= diff_adj;
}
/*
* back down to the previous cwnd (assume we have had a sack
* before this packet). minus what ever portion of the
* overage is my fault.
*/
net->cwnd -= my_portion;
/* we will NOT back down more than 1 MTU */
if (net->cwnd <= net->mtu) {
net->cwnd = net->mtu;
}
/* force into CA */
net->ssthresh = net->cwnd - 1;
} else {
/*
* Take 1/4 of the space left or max burst up .. whichever
* is less.
*/
incr = min((bw_avail - *on_queue) >> 2,
stcb->asoc.max_burst * net->mtu);
net->cwnd += incr;
}
if (net->cwnd > bw_avail) {
/* We can't exceed the pipe size */
net->cwnd = bw_avail;
}
if (net->cwnd < net->mtu) {
/* We always have 1 MTU */
net->cwnd = net->mtu;
}
if (net->cwnd - old_cwnd != 0) {
/* log only changes */
if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) {
sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd),
SCTP_CWND_LOG_FROM_SAT);
}
}
}
void
sctp_cwnd_update_after_output(struct sctp_tcb *stcb,
struct sctp_nets *net, int burst_limit)
{
int old_cwnd = net->cwnd;
if (net->ssthresh < net->cwnd)
net->ssthresh = net->cwnd;
net->cwnd = (net->flight_size + (burst_limit * net->mtu));
if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) {
sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_BRST);
}
}
void
sctp_cwnd_update_after_fr_timer(struct sctp_inpcb *inp,
struct sctp_tcb *stcb, struct sctp_nets *net)
{
int old_cwnd = net->cwnd;
sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_EARLY_FR_TMR, SCTP_SO_NOT_LOCKED);
/*
* make a small adjustment to cwnd and force to CA.
*/
if (net->cwnd > net->mtu)
/* drop down one MTU after sending */
net->cwnd -= net->mtu;
if (net->cwnd < net->ssthresh)
/* still in SS move to CA */
net->ssthresh = net->cwnd - 1;
if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) {
sctp_log_cwnd(stcb, net, (old_cwnd - net->cwnd), SCTP_CWND_LOG_FROM_FR);
}
}
struct sctp_hs_raise_drop {
@ -741,16 +891,11 @@ sctp_hs_cwnd_update_after_sack(struct sctp_tcb *stcb,
/* If the cumulative ack moved we can proceed */
if (net->cwnd <= net->ssthresh) {
/* We are in slow start */
if (net->flight_size + net->net_ack >=
net->cwnd) {
if (net->flight_size + net->net_ack >= net->cwnd) {
sctp_hs_cwnd_increase(stcb, net);
} else {
unsigned int dif;
dif = net->cwnd - (net->flight_size +
net->net_ack);
if (sctp_logging_level & SCTP_CWND_LOGGING_ENABLE) {
sctp_log_cwnd(stcb, net, net->net_ack,
SCTP_CWND_LOG_NOADV_SS);
@ -758,50 +903,20 @@ sctp_hs_cwnd_update_after_sack(struct sctp_tcb *stcb,
}
} else {
/* We are in congestion avoidance */
if (net->flight_size + net->net_ack >=
net->cwnd) {
/*
* add to pba only if we had a
* cwnd's worth (or so) in flight OR
* the burst limit was applied.
*/
net->partial_bytes_acked +=
net->net_ack;
/*
* Do we need to increase (if pba is
* > cwnd)?
*/
if (net->partial_bytes_acked >=
net->cwnd) {
if (net->cwnd <
net->partial_bytes_acked) {
net->partial_bytes_acked -=
net->cwnd;
} else {
net->partial_bytes_acked =
0;
}
net->cwnd += net->mtu;
if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) {
sctp_log_cwnd(stcb, net, net->mtu,
SCTP_CWND_LOG_FROM_CA);
}
} else {
if (sctp_logging_level & SCTP_CWND_LOGGING_ENABLE) {
sctp_log_cwnd(stcb, net, net->net_ack,
SCTP_CWND_LOG_NOADV_CA);
}
net->partial_bytes_acked += net->net_ack;
if ((net->flight_size + net->net_ack >= net->cwnd) &&
(net->partial_bytes_acked >= net->cwnd)) {
net->partial_bytes_acked -= net->cwnd;
net->cwnd += net->mtu;
if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) {
sctp_log_cwnd(stcb, net, net->mtu,
SCTP_CWND_LOG_FROM_CA);
}
} else {
unsigned int dif;
if (sctp_logging_level & SCTP_CWND_LOGGING_ENABLE) {
sctp_log_cwnd(stcb, net, net->net_ack,
SCTP_CWND_LOG_NOADV_CA);
}
dif = net->cwnd - (net->flight_size +
net->net_ack);
}
}
} else {
@ -830,176 +945,6 @@ sctp_hs_cwnd_update_after_sack(struct sctp_tcb *stcb,
}
}
void
sctp_cwnd_update_after_ecn_echo(struct sctp_tcb *stcb,
struct sctp_nets *net)
{
int old_cwnd;
old_cwnd = net->cwnd;
SCTP_STAT_INCR(sctps_ecnereducedcwnd);
net->ssthresh = net->cwnd / 2;
if (net->ssthresh < net->mtu) {
net->ssthresh = net->mtu;
/* here back off the timer as well, to slow us down */
net->RTO <<= 1;
}
net->cwnd = net->ssthresh;
if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) {
sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SAT);
}
}
void
sctp_cwnd_update_after_packet_dropped(struct sctp_tcb *stcb,
struct sctp_nets *net, struct sctp_pktdrop_chunk *cp,
uint32_t * bottle_bw, uint32_t * on_queue)
{
uint32_t bw_avail;
int rtt, incr;
int old_cwnd = net->cwnd;
/* need real RTT for this calc */
rtt = ((net->lastsa >> 2) + net->lastsv) >> 1;
/* get bottle neck bw */
*bottle_bw = ntohl(cp->bottle_bw);
/* and whats on queue */
*on_queue = ntohl(cp->current_onq);
/*
* adjust the on-queue if our flight is more it could be that the
* router has not yet gotten data "in-flight" to it
*/
if (*on_queue < net->flight_size)
*on_queue = net->flight_size;
/* calculate the available space */
bw_avail = (*bottle_bw * rtt) / 1000;
if (bw_avail > *bottle_bw) {
/*
* Cap the growth to no more than the bottle neck. This can
* happen as RTT slides up due to queues. It also means if
* you have more than a 1 second RTT with a empty queue you
* will be limited to the bottle_bw per second no matter if
* other points have 1/2 the RTT and you could get more
* out...
*/
bw_avail = *bottle_bw;
}
if (*on_queue > bw_avail) {
/*
* No room for anything else don't allow anything else to be
* "added to the fire".
*/
int seg_inflight, seg_onqueue, my_portion;
net->partial_bytes_acked = 0;
/* how much are we over queue size? */
incr = *on_queue - bw_avail;
if (stcb->asoc.seen_a_sack_this_pkt) {
/*
* undo any cwnd adjustment that the sack might have
* made
*/
net->cwnd = net->prev_cwnd;
}
/* Now how much of that is mine? */
seg_inflight = net->flight_size / net->mtu;
seg_onqueue = *on_queue / net->mtu;
my_portion = (incr * seg_inflight) / seg_onqueue;
/* Have I made an adjustment already */
if (net->cwnd > net->flight_size) {
/*
* for this flight I made an adjustment we need to
* decrease the portion by a share our previous
* adjustment.
*/
int diff_adj;
diff_adj = net->cwnd - net->flight_size;
if (diff_adj > my_portion)
my_portion = 0;
else
my_portion -= diff_adj;
}
/*
* back down to the previous cwnd (assume we have had a sack
* before this packet). minus what ever portion of the
* overage is my fault.
*/
net->cwnd -= my_portion;
/* we will NOT back down more than 1 MTU */
if (net->cwnd <= net->mtu) {
net->cwnd = net->mtu;
}
/* force into CA */
net->ssthresh = net->cwnd - 1;
} else {
/*
* Take 1/4 of the space left or max burst up .. whichever
* is less.
*/
incr = min((bw_avail - *on_queue) >> 2,
stcb->asoc.max_burst * net->mtu);
net->cwnd += incr;
}
if (net->cwnd > bw_avail) {
/* We can't exceed the pipe size */
net->cwnd = bw_avail;
}
if (net->cwnd < net->mtu) {
/* We always have 1 MTU */
net->cwnd = net->mtu;
}
if (net->cwnd - old_cwnd != 0) {
/* log only changes */
if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) {
sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd),
SCTP_CWND_LOG_FROM_SAT);
}
}
}
void
sctp_cwnd_update_after_output(struct sctp_tcb *stcb,
struct sctp_nets *net, int burst_limit)
{
int old_cwnd;
if (net->ssthresh < net->cwnd)
net->ssthresh = net->cwnd;
old_cwnd = net->cwnd;
net->cwnd = (net->flight_size + (burst_limit * net->mtu));
if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) {
sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_BRST);
}
}
void
sctp_cwnd_update_after_fr_timer(struct sctp_inpcb *inp,
struct sctp_tcb *stcb, struct sctp_nets *net)
{
int old_cwnd;
old_cwnd = net->cwnd;
sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_EARLY_FR_TMR, SCTP_SO_NOT_LOCKED);
/*
* make a small adjustment to cwnd and force to CA.
*/
if (net->cwnd > net->mtu)
/* drop down one MTU after sending */
net->cwnd -= net->mtu;
if (net->cwnd < net->ssthresh)
/* still in SS move to CA */
net->ssthresh = net->cwnd - 1;
if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) {
sctp_log_cwnd(stcb, net, (old_cwnd - net->cwnd), SCTP_CWND_LOG_FROM_FR);
}
}
/*
* H-TCP congestion control. The algorithm is detailed in:
@ -1220,10 +1165,6 @@ htcp_cong_avoid(struct sctp_tcb *stcb, struct sctp_nets *net)
}
}
} else {
unsigned int dif;
dif = net->cwnd - (net->flight_size +
net->net_ack);
if (sctp_logging_level & SCTP_CWND_LOGGING_ENABLE) {
sctp_log_cwnd(stcb, net, net->net_ack,
SCTP_CWND_LOG_NOADV_SS);
@ -1289,10 +1230,6 @@ sctp_htcp_set_initial_cc_param(struct sctp_tcb *stcb, struct sctp_nets *net)
* INITIAL_CWND. We then limit this to 4 MTU's of sending.
*/
net->cwnd = min((net->mtu * 4), max((2 * net->mtu), SCTP_INITIAL_CWND));
/* we always get at LEAST 2 MTU's */
if (net->cwnd < (2 * net->mtu)) {
net->cwnd = 2 * net->mtu;
}
net->ssthresh = stcb->asoc.peers_rwnd;
htcp_init(stcb, net);
@ -1549,13 +1486,10 @@ sctp_htcp_cwnd_update_after_timeout(struct sctp_tcb *stcb,
htcp_reset(&net->htcp_ca);
net->ssthresh = htcp_recalc_ssthresh(stcb, net);
net->cwnd = net->mtu;
/* floor of 1 mtu */
if (net->cwnd < net->mtu)
net->cwnd = net->mtu;
net->partial_bytes_acked = 0;
if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) {
sctp_log_cwnd(stcb, net, net->cwnd - old_cwnd, SCTP_CWND_LOG_FROM_RTX);
}
net->partial_bytes_acked = 0;
}
void

View File

@ -36,6 +36,9 @@ __FBSDID("$FreeBSD$");
#ifndef __sctp_constants_h__
#define __sctp_constants_h__
/* IANA assigned port number for SCTP over UDP encapsulation */
#define SCTP_OVER_UDP_TUNNELING_PORT 9899
/* Number of packets to get before sack sent by default */
#define SCTP_DEFAULT_SACK_FREQ 2
@ -268,6 +271,9 @@ __FBSDID("$FreeBSD$");
#define SCTP_DEFAULT_AUTO_ASCONF 1
#endif
/* default MULTIPLE_ASCONF mode enable(1)/disable(0) value (sysctl) */
#define SCTP_DEFAULT_MULTIPLE_ASCONFS 0
/* default MOBILITY_BASE mode enable(1)/disable(0) value (sysctl) */
#if defined (__APPLE__) && !defined(SCTP_APPLE_MOBILITY_BASE)
#define SCTP_DEFAULT_MOBILITY_BASE 0

View File

@ -2620,7 +2620,7 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length,
}
stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_19;
sctp_abort_association(inp, stcb, m, iphlen, sh,
op_err, 0);
op_err, 0, net->port);
return (2);
}
#ifdef SCTP_AUDITING_ENABLED
@ -2683,7 +2683,7 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length,
struct mbuf *op_err;
op_err = sctp_generate_invmanparam(SCTP_CAUSE_PROTOCOL_VIOLATION);
sctp_abort_association(inp, stcb, m, iphlen, sh, op_err, 0);
sctp_abort_association(inp, stcb, m, iphlen, sh, op_err, 0, net->port);
return (2);
}
break;

View File

@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$");
#include <netinet/sctp_asconf.h>
#include <netinet/sctp_bsd_addr.h>
#include <netinet/sctp_timer.h>
#include <netinet/udp.h>
@ -79,7 +80,7 @@ sctp_stop_all_cookie_timers(struct sctp_tcb *stcb)
static void
sctp_handle_init(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh,
struct sctp_init_chunk *cp, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
struct sctp_nets *net, int *abort_no_unlock, uint32_t vrf_id)
struct sctp_nets *net, int *abort_no_unlock, uint32_t vrf_id, uint16_t port)
{
struct sctp_init *init;
struct mbuf *op_err;
@ -113,7 +114,7 @@ sctp_handle_init(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh,
* state :-)
*/
sctp_abort_association(inp, stcb, m, iphlen, sh, op_err,
vrf_id);
vrf_id, port);
if (stcb)
*abort_no_unlock = 1;
goto outnow;
@ -122,7 +123,7 @@ sctp_handle_init(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh,
/* Invalid length */
op_err = sctp_generate_invmanparam(SCTP_CAUSE_INVALID_PARAM);
sctp_abort_association(inp, stcb, m, iphlen, sh, op_err,
vrf_id);
vrf_id, port);
if (stcb)
*abort_no_unlock = 1;
goto outnow;
@ -132,7 +133,7 @@ sctp_handle_init(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh,
/* protocol error... send abort */
op_err = sctp_generate_invmanparam(SCTP_CAUSE_INVALID_PARAM);
sctp_abort_association(inp, stcb, m, iphlen, sh, op_err,
vrf_id);
vrf_id, port);
if (stcb)
*abort_no_unlock = 1;
goto outnow;
@ -141,7 +142,7 @@ sctp_handle_init(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh,
/* invalid parameter... send abort */
op_err = sctp_generate_invmanparam(SCTP_CAUSE_INVALID_PARAM);
sctp_abort_association(inp, stcb, m, iphlen, sh, op_err,
vrf_id);
vrf_id, port);
if (stcb)
*abort_no_unlock = 1;
goto outnow;
@ -150,7 +151,7 @@ sctp_handle_init(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh,
/* protocol error... send abort */
op_err = sctp_generate_invmanparam(SCTP_CAUSE_INVALID_PARAM);
sctp_abort_association(inp, stcb, m, iphlen, sh, op_err,
vrf_id);
vrf_id, port);
if (stcb)
*abort_no_unlock = 1;
goto outnow;
@ -159,7 +160,7 @@ sctp_handle_init(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh,
/* protocol error... send abort */
op_err = sctp_generate_invmanparam(SCTP_CAUSE_INVALID_PARAM);
sctp_abort_association(inp, stcb, m, iphlen, sh, op_err,
vrf_id);
vrf_id, port);
if (stcb)
*abort_no_unlock = 1;
goto outnow;
@ -168,14 +169,14 @@ sctp_handle_init(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh,
if (sctp_validate_init_auth_params(m, offset + sizeof(*cp),
init_limit)) {
/* auth parameter(s) error... send abort */
sctp_abort_association(inp, stcb, m, iphlen, sh, NULL, vrf_id);
sctp_abort_association(inp, stcb, m, iphlen, sh, NULL, vrf_id, port);
if (stcb)
*abort_no_unlock = 1;
goto outnow;
}
/* send an INIT-ACK w/cookie */
SCTPDBG(SCTP_DEBUG_INPUT3, "sctp_handle_init: sending INIT-ACK\n");
sctp_send_initiate_ack(inp, stcb, m, iphlen, offset, sh, cp, vrf_id,
sctp_send_initiate_ack(inp, stcb, m, iphlen, offset, sh, cp, vrf_id, port,
((stcb == NULL) ? SCTP_HOLDS_LOCK : SCTP_NOT_LOCKED));
outnow:
if (stcb == NULL) {
@ -422,7 +423,7 @@ sctp_process_init_ack(struct mbuf *m, int iphlen, int offset,
"Load addresses from INIT causes an abort %d\n",
retval);
sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen, sh,
NULL, 0);
NULL, 0, net->port);
*abort_no_unlock = 1;
return (-1);
}
@ -497,7 +498,7 @@ sctp_process_init_ack(struct mbuf *m, int iphlen, int offset,
mp->resv = 0;
}
sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen,
sh, op_err, 0);
sh, op_err, 0, net->port);
*abort_no_unlock = 1;
}
return (retval);
@ -1105,7 +1106,7 @@ sctp_handle_init_ack(struct mbuf *m, int iphlen, int offset,
/* Invalid length */
op_err = sctp_generate_invmanparam(SCTP_CAUSE_INVALID_PARAM);
sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen, sh,
op_err, 0);
op_err, 0, net->port);
*abort_no_unlock = 1;
return (-1);
}
@ -1115,7 +1116,7 @@ sctp_handle_init_ack(struct mbuf *m, int iphlen, int offset,
/* protocol error... send an abort */
op_err = sctp_generate_invmanparam(SCTP_CAUSE_INVALID_PARAM);
sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen, sh,
op_err, 0);
op_err, 0, net->port);
*abort_no_unlock = 1;
return (-1);
}
@ -1123,7 +1124,7 @@ sctp_handle_init_ack(struct mbuf *m, int iphlen, int offset,
/* protocol error... send an abort */
op_err = sctp_generate_invmanparam(SCTP_CAUSE_INVALID_PARAM);
sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen, sh,
op_err, 0);
op_err, 0, net->port);
*abort_no_unlock = 1;
return (-1);
}
@ -1131,7 +1132,7 @@ sctp_handle_init_ack(struct mbuf *m, int iphlen, int offset,
/* protocol error... send an abort */
op_err = sctp_generate_invmanparam(SCTP_CAUSE_INVALID_PARAM);
sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen, sh,
op_err, 0);
op_err, 0, net->port);
*abort_no_unlock = 1;
return (-1);
}
@ -1139,7 +1140,7 @@ sctp_handle_init_ack(struct mbuf *m, int iphlen, int offset,
/* protocol error... send an abort */
op_err = sctp_generate_invmanparam(SCTP_CAUSE_INVALID_PARAM);
sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen, sh,
op_err, 0);
op_err, 0, net->port);
*abort_no_unlock = 1;
return (-1);
}
@ -1269,7 +1270,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
ph->param_type = htons(SCTP_CAUSE_COOKIE_IN_SHUTDOWN);
ph->param_length = htons(sizeof(struct sctp_paramhdr));
sctp_send_operr_to(m, iphlen, op_err, cookie->peers_vtag,
vrf_id);
vrf_id, net->port);
if (how_indx < sizeof(asoc->cookie_how))
asoc->cookie_how[how_indx] = 2;
return (NULL);
@ -1646,6 +1647,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
ntohs(initack_cp->init.num_outbound_streams);
asoc->init_seq_number = ntohl(initack_cp->init.initial_tsn);
asoc->sending_seq = asoc->asconf_seq_out = asoc->str_reset_seq_out = asoc->init_seq_number;
asoc->asconf_seq_out_acked = asoc->asconf_seq_out - 1;
asoc->last_cwr_tsn = asoc->init_seq_number - 1;
asoc->asconf_seq_in = asoc->last_acked_seq = asoc->init_seq_number - 1;
@ -1749,7 +1751,7 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
struct sctp_inpcb *inp, struct sctp_nets **netp,
struct sockaddr *init_src, int *notification,
int auth_skipped, uint32_t auth_offset, uint32_t auth_len,
uint32_t vrf_id)
uint32_t vrf_id, uint16_t port)
{
struct sctp_tcb *stcb;
struct sctp_init_chunk *init_cp, init_buf;
@ -1841,7 +1843,7 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
op_err = sctp_generate_invmanparam(SCTP_CAUSE_OUT_OF_RESC);
sctp_abort_association(inp, (struct sctp_tcb *)NULL, m, iphlen,
sh, op_err, vrf_id);
sh, op_err, vrf_id, port);
return (NULL);
}
/* get the correct sctp_nets */
@ -1867,7 +1869,7 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
atomic_add_int(&stcb->asoc.refcnt, 1);
op_err = sctp_generate_invmanparam(SCTP_CAUSE_OUT_OF_RESC);
sctp_abort_association(inp, (struct sctp_tcb *)NULL, m, iphlen,
sh, op_err, vrf_id);
sh, op_err, vrf_id, port);
#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
SCTP_TCB_UNLOCK(stcb);
SCTP_SOCKET_LOCK(so, 1);
@ -1888,6 +1890,7 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
asoc->pre_open_streams = ntohs(initack_cp->init.num_outbound_streams);
asoc->init_seq_number = ntohl(initack_cp->init.initial_tsn);
asoc->sending_seq = asoc->asconf_seq_out = asoc->str_reset_seq_out = asoc->init_seq_number;
asoc->asconf_seq_out_acked = asoc->asconf_seq_out - 1;
asoc->last_cwr_tsn = asoc->init_seq_number - 1;
asoc->asconf_seq_in = asoc->last_acked_seq = asoc->init_seq_number - 1;
asoc->str_reset_seq_in = asoc->init_seq_number;
@ -2095,7 +2098,7 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
struct sctphdr *sh, struct sctp_cookie_echo_chunk *cp,
struct sctp_inpcb **inp_p, struct sctp_tcb **stcb, struct sctp_nets **netp,
int auth_skipped, uint32_t auth_offset, uint32_t auth_len,
struct sctp_tcb **locked_tcb, uint32_t vrf_id)
struct sctp_tcb **locked_tcb, uint32_t vrf_id, uint16_t port)
{
struct sctp_state_cookie *cookie;
struct sockaddr_in6 sin6;
@ -2329,7 +2332,7 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
tim = now.tv_usec - cookie->time_entered.tv_usec;
scm->time_usec = htonl(tim);
sctp_send_operr_to(m, iphlen, op_err, cookie->peers_vtag,
vrf_id);
vrf_id, port);
return (NULL);
}
/*
@ -2409,7 +2412,7 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
/* this is the "normal" case... get a new TCB */
*stcb = sctp_process_cookie_new(m, iphlen, offset, sh, cookie,
cookie_len, *inp_p, netp, to, &notification,
auth_skipped, auth_offset, auth_len, vrf_id);
auth_skipped, auth_offset, auth_len, vrf_id, port);
} else {
/* this is abnormal... cookie-echo on existing TCB */
had_a_existing_tcb = 1;
@ -2489,7 +2492,7 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
SCTPDBG(SCTP_DEBUG_INPUT1, "process_cookie_new: no room for another socket!\n");
op_err = sctp_generate_invmanparam(SCTP_CAUSE_OUT_OF_RESC);
sctp_abort_association(*inp_p, NULL, m, iphlen,
sh, op_err, vrf_id);
sh, op_err, vrf_id, port);
#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
pcb_so = SCTP_INP_SO(*inp_p);
atomic_add_int(&(*stcb)->asoc.refcnt, 1);
@ -3814,7 +3817,7 @@ __attribute__((noinline))
sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
struct sctphdr *sh, struct sctp_chunkhdr *ch, struct sctp_inpcb *inp,
struct sctp_tcb *stcb, struct sctp_nets **netp, int *fwd_tsn_seen,
uint32_t vrf_id)
uint32_t vrf_id, uint16_t port)
{
struct sctp_association *asoc;
uint32_t vtag_in;
@ -3968,7 +3971,7 @@ __attribute__((noinline))
if (stcb == NULL) {
/* no association, so it's out of the blue... */
sctp_handle_ootb(m, iphlen, *offset, sh, inp, NULL,
vrf_id);
vrf_id, port);
*offset = length;
if (locked_tcb) {
SCTP_TCB_UNLOCK(locked_tcb);
@ -4005,7 +4008,7 @@ __attribute__((noinline))
SCTP_TCB_UNLOCK(locked_tcb);
}
sctp_handle_ootb(m, iphlen, *offset, sh, inp,
NULL, vrf_id);
NULL, vrf_id, port);
return (NULL);
}
} else {
@ -4182,7 +4185,7 @@ __attribute__((noinline))
if (netp) {
sctp_handle_init(m, iphlen, *offset, sh,
(struct sctp_init_chunk *)ch, inp,
stcb, *netp, &abort_no_unlock, vrf_id);
stcb, *netp, &abort_no_unlock, vrf_id, port);
}
if (abort_no_unlock)
return (NULL);
@ -4448,7 +4451,7 @@ __attribute__((noinline))
htons(sizeof(struct sctp_paramhdr));
}
sctp_abort_association(inp, stcb, m,
iphlen, sh, oper, vrf_id);
iphlen, sh, oper, vrf_id, port);
}
*offset = length;
return (NULL);
@ -4475,7 +4478,8 @@ __attribute__((noinline))
auth_offset,
auth_len,
&locked_tcb,
vrf_id);
vrf_id,
port);
} else {
ret_buf = NULL;
}
@ -4984,7 +4988,7 @@ void
sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset,
int length, struct sctphdr *sh, struct sctp_chunkhdr *ch,
struct sctp_inpcb *inp, struct sctp_tcb *stcb, struct sctp_nets *net,
uint8_t ecn_bits, uint32_t vrf_id)
uint8_t ecn_bits, uint32_t vrf_id, uint16_t port)
{
/*
* Control chunk processing
@ -5020,7 +5024,7 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset,
*/
SCTP_TCB_UNLOCK(stcb);
sctp_handle_ootb(m, iphlen, offset, sh, inp, NULL,
vrf_id);
vrf_id, port);
goto out_now;
}
}
@ -5028,7 +5032,7 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset,
/* process the control portion of the SCTP packet */
/* sa_ignore NO_NULL_CHK */
stcb = sctp_process_control(m, iphlen, &offset, length, sh, ch,
inp, stcb, &net, &fwd_tsn_seen, vrf_id);
inp, stcb, &net, &fwd_tsn_seen, vrf_id, port);
if (stcb) {
/*
* This covers us if the cookie-echo was there and
@ -5058,7 +5062,7 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset,
if (stcb == NULL) {
/* out of the blue DATA chunk */
sctp_handle_ootb(m, iphlen, offset, sh, inp, NULL,
vrf_id);
vrf_id, port);
goto out_now;
}
if (stcb->asoc.my_vtag != ntohl(sh->v_tag)) {
@ -5126,7 +5130,7 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset,
* We consider OOTB any data sent during asoc setup.
*/
sctp_handle_ootb(m, iphlen, offset, sh, inp, NULL,
vrf_id);
vrf_id, port);
SCTP_TCB_UNLOCK(stcb);
goto out_now;
/* sa_ignore NOTREACHED */
@ -5221,12 +5225,11 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset,
}
void
sctp_input(i_pak, off)
sctp_input_with_port(i_pak, off, port)
struct mbuf *i_pak;
int off;
uint16_t port;
{
#ifdef SCTP_MBUF_LOGGING
struct mbuf *mat;
@ -5329,6 +5332,12 @@ sctp_input(i_pak, off)
offset - sizeof(*ch),
sh, ch, &inp, &net,
vrf_id);
if ((net) && (port)) {
if (net->port == 0) {
sctp_pathmtu_adjustment(inp, stcb, net, net->mtu - sizeof(struct udphdr));
}
net->port = port;
}
if ((inp) && (stcb)) {
sctp_send_packet_dropped(stcb, net, m, iphlen, 1);
sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_INPUT_ERROR, SCTP_SO_NOT_LOCKED);
@ -5357,6 +5366,12 @@ sctp_input(i_pak, off)
*/
stcb = sctp_findassociation_addr(m, iphlen, offset - sizeof(*ch),
sh, ch, &inp, &net, vrf_id);
if ((net) && (port)) {
if (net->port == 0) {
sctp_pathmtu_adjustment(inp, stcb, net, net->mtu - sizeof(struct udphdr));
}
net->port = port;
}
/* inp's ref-count increased && stcb locked */
if (inp == NULL) {
struct sctp_init_chunk *init_chk, chunk_buf;
@ -5386,14 +5401,14 @@ sctp_input(i_pak, off)
sh->v_tag = init_chk->init.initiate_tag;
}
if (ch->chunk_type == SCTP_SHUTDOWN_ACK) {
sctp_send_shutdown_complete2(m, iphlen, sh, vrf_id);
sctp_send_shutdown_complete2(m, iphlen, sh, vrf_id, port);
goto bad;
}
if (ch->chunk_type == SCTP_SHUTDOWN_COMPLETE) {
goto bad;
}
if (ch->chunk_type != SCTP_ABORT_ASSOCIATION)
sctp_send_abort(m, iphlen, sh, 0, NULL, vrf_id);
sctp_send_abort(m, iphlen, sh, 0, NULL, vrf_id, port);
goto bad;
} else if (stcb == NULL) {
refcount_up = 1;
@ -5420,7 +5435,7 @@ sctp_input(i_pak, off)
/* sa_ignore NO_NULL_CHK */
sctp_common_input_processing(&m, iphlen, offset, length, sh, ch,
inp, stcb, net, ecn_bits, vrf_id);
inp, stcb, net, ecn_bits, vrf_id, port);
/* inp's ref-count reduced && stcb unlocked */
if (m) {
sctp_m_freem(m);
@ -5443,3 +5458,10 @@ sctp_input(i_pak, off)
}
return;
}
void
sctp_input(i_pak, off)
struct mbuf *i_pak;
int off;
{
sctp_input_with_port(i_pak, off, 0);
}

View File

@ -40,7 +40,7 @@ __FBSDID("$FreeBSD$");
void
sctp_common_input_processing(struct mbuf **, int, int, int,
struct sctphdr *, struct sctp_chunkhdr *, struct sctp_inpcb *,
struct sctp_tcb *, struct sctp_nets *, uint8_t, uint32_t);
struct sctp_tcb *, struct sctp_nets *, uint8_t, uint32_t, uint16_t);
struct sctp_stream_reset_out_request *
sctp_find_stream_reset(struct sctp_tcb *stcb, uint32_t seq,

View File

@ -83,10 +83,10 @@ extern int sctp_logoff_stuff;
#define SCTP_STATLOG_DESTROY()
#define SCTP_INP_INFO_LOCK_DESTROY() do { \
if(rw_wowned(sctppcbinfo.ipi_ep_mtx)) { \
if(rw_wowned(&sctppcbinfo.ipi_ep_mtx)) { \
rw_wunlock(&sctppcbinfo.ipi_ep_mtx); \
} \
rw_destroy(sctppcbinfo.ipi_ep_mtx); \
rw_destroy(&sctppcbinfo.ipi_ep_mtx); \
} while (0)
#define SCTP_INP_INFO_LOCK_INIT() \
@ -111,10 +111,10 @@ extern int sctp_logoff_stuff;
rw_init(&sctppcbinfo.ipi_addr_mtx, "sctp-addr")
#define SCTP_IPI_ADDR_DESTROY() do { \
if(rw_wowned(sctppcbinfo.ipi_addr_mtx)) { \
if(rw_wowned(&sctppcbinfo.ipi_addr_mtx)) { \
rw_wunlock(&sctppcbinfo.ipi_addr_mtx); \
} \
rw_destroy(&sctppcbinfo.ipi_addr_mtx) \
rw_destroy(&sctppcbinfo.ipi_addr_mtx); \
} while (0)

View File

@ -202,6 +202,7 @@ MALLOC_DECLARE(SCTP_M_SOCKOPT);
#define SCTP_INIT_VRF_TABLEID(vrf)
#define SCTP_IFN_IS_IFT_LOOP(ifn) ((ifn)->ifn_type == IFT_LOOP)
#define SCTP_ROUTE_IS_REAL_LOOP(ro) ((ro)->ro_rt && (ro)->ro_rt->rt_ifa && (ro)->ro_rt->rt_ifa->ifa_ifp && (ro)->ro_rt->rt_ifa->ifa_ifp->if_type == IFT_LOOP)
/*
* Access to IFN's to help with src-addr-selection
@ -234,6 +235,7 @@ MALLOC_DECLARE(SCTP_M_SOCKOPT);
* zone allocation functions
*/
#include <vm/uma.h>
/* SCTP_ZONE_INIT: initialize the zone */
typedef struct uma_zone *sctp_zone_t;
@ -244,6 +246,8 @@ typedef struct uma_zone *sctp_zone_t;
uma_zone_set_max(zone, number); \
}
#define SCTP_ZONE_DESTROY(zone) uma_zdestroy(zone)
/* SCTP_ZONE_GET: allocate element from the zone */
#define SCTP_ZONE_GET(zone, type) \
(type *)uma_zalloc(zone, M_NOWAIT);
@ -251,6 +255,7 @@ typedef struct uma_zone *sctp_zone_t;
/* SCTP_ZONE_FREE: free element from the zone */
#define SCTP_ZONE_FREE(zone, element) \
uma_zfree(zone, element);
#define SCTP_HASH_INIT(size, hashmark) hashinit_flags(size, M_PCB, hashmark, HASH_NOWAIT)
#define SCTP_HASH_FREE(table, hashmark) hashdestroy(table, M_PCB, hashmark)
@ -262,6 +267,7 @@ typedef struct uma_zone *sctp_zone_t;
#include <sys/callout.h>
typedef struct callout sctp_os_timer_t;
#define SCTP_OS_TIMER_INIT(tmr) callout_init(tmr, 1)
#define SCTP_OS_TIMER_START callout_reset
#define SCTP_OS_TIMER_STOP callout_stop

File diff suppressed because it is too large Load Diff

View File

@ -84,7 +84,7 @@ sctp_send_initiate(struct sctp_inpcb *, struct sctp_tcb *, int
void
sctp_send_initiate_ack(struct sctp_inpcb *, struct sctp_tcb *,
struct mbuf *, int, int, struct sctphdr *, struct sctp_init_chunk *,
uint32_t, int);
uint32_t, uint16_t, int);
struct mbuf *
sctp_arethere_unrecognized_parameters(struct mbuf *, int, int *,
@ -110,7 +110,7 @@ void sctp_send_shutdown_complete(struct sctp_tcb *, struct sctp_nets *);
void
sctp_send_shutdown_complete2(struct mbuf *, int, struct sctphdr *,
uint32_t);
uint32_t, uint16_t);
void sctp_send_asconf(struct sctp_tcb *, struct sctp_nets *, int addr_locked);
@ -197,9 +197,9 @@ sctp_send_str_reset_req(struct sctp_tcb *stcb,
void
sctp_send_abort(struct mbuf *, int, struct sctphdr *, uint32_t,
struct mbuf *, uint32_t);
struct mbuf *, uint32_t, uint16_t);
void sctp_send_operr_to(struct mbuf *, int, struct mbuf *, uint32_t, uint32_t);
void sctp_send_operr_to(struct mbuf *, int, struct mbuf *, uint32_t, uint32_t, uint16_t);
int
sctp_sosend(struct socket *so,

View File

@ -45,24 +45,30 @@ __FBSDID("$FreeBSD$");
#include <netinet/sctp_output.h>
#include <netinet/sctp_timer.h>
#include <netinet/sctp_bsd_addr.h>
#include <netinet/udp.h>
void sctp_pcb_finish(void);
struct sctp_epinfo sctppcbinfo;
/* FIX: we don't handle multiple link local scopes */
/* "scopeless" replacement IN6_ARE_ADDR_EQUAL */
#ifdef INET6
int
SCTP6_ARE_ADDR_EQUAL(struct in6_addr *a, struct in6_addr *b)
SCTP6_ARE_ADDR_EQUAL(struct sockaddr_in6 *a, struct sockaddr_in6 *b)
{
struct in6_addr tmp_a, tmp_b;
struct sockaddr_in6 tmp_a, tmp_b;
/* use a copy of a and b */
tmp_a = *a;
tmp_b = *b;
in6_clearscope(&tmp_a);
in6_clearscope(&tmp_b);
return (IN6_ARE_ADDR_EQUAL(&tmp_a, &tmp_b));
memcpy(&tmp_a, a, sizeof(struct sockaddr_in6));
if (sa6_embedscope(&tmp_a, ip6_use_defzone) != 0) {
return 0;
}
memcpy(&tmp_b, b, sizeof(struct sockaddr_in6));
if (sa6_embedscope(&tmp_b, ip6_use_defzone) != 0) {
return 0;
}
return (IN6_ARE_ADDR_EQUAL(&tmp_a.sin6_addr, &tmp_b.sin6_addr));
}
#endif
@ -916,8 +922,8 @@ sctp_tcb_special_locate(struct sctp_inpcb **inp_p, struct sockaddr *from,
to;
intf_addr6 = &laddr->ifa->address.sin6;
if (SCTP6_ARE_ADDR_EQUAL(&sin6->sin6_addr,
&intf_addr6->sin6_addr)) {
if (SCTP6_ARE_ADDR_EQUAL(sin6,
intf_addr6)) {
match = 1;
break;
}
@ -990,8 +996,8 @@ sctp_tcb_special_locate(struct sctp_inpcb **inp_p, struct sockaddr *from,
sin6 = (struct sockaddr_in6 *)&net->ro._l_addr;
rsin6 = (struct sockaddr_in6 *)from;
if (SCTP6_ARE_ADDR_EQUAL(&sin6->sin6_addr,
&rsin6->sin6_addr)) {
if (SCTP6_ARE_ADDR_EQUAL(sin6,
rsin6)) {
/* found it */
if (netp != NULL) {
*netp = net;
@ -1147,8 +1153,8 @@ sctp_findassociation_ep_addr(struct sctp_inpcb **inp_p, struct sockaddr *remote,
sin6 = (struct sockaddr_in6 *)&net->ro._l_addr;
rsin6 = (struct sockaddr_in6 *)remote;
if (SCTP6_ARE_ADDR_EQUAL(&sin6->sin6_addr,
&rsin6->sin6_addr)) {
if (SCTP6_ARE_ADDR_EQUAL(sin6,
rsin6)) {
/* found it */
if (netp != NULL) {
*netp = net;
@ -1245,8 +1251,8 @@ sctp_findassociation_ep_addr(struct sctp_inpcb **inp_p, struct sockaddr *remote,
sin6 = (struct sockaddr_in6 *)
&net->ro._l_addr;
rsin6 = (struct sockaddr_in6 *)remote;
if (SCTP6_ARE_ADDR_EQUAL(&sin6->sin6_addr,
&rsin6->sin6_addr)) {
if (SCTP6_ARE_ADDR_EQUAL(sin6,
rsin6)) {
/* found it */
if (netp != NULL) {
*netp = net;
@ -1536,8 +1542,8 @@ sctp_endpoint_probe(struct sockaddr *nam, struct sctppcbhead *head,
#ifdef INET6
case AF_INET6:
intf_addr6 = &laddr->ifa->address.sin6;
if (SCTP6_ARE_ADDR_EQUAL(&sin6->sin6_addr,
&intf_addr6->sin6_addr)) {
if (SCTP6_ARE_ADDR_EQUAL(sin6,
intf_addr6)) {
SCTP_INP_RUNLOCK(inp);
return (inp);
}
@ -2775,6 +2781,11 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr,
sctp_feature_on(inp, SCTP_PCB_FLAGS_DO_ASCONF);
sctp_feature_on(inp, SCTP_PCB_FLAGS_AUTO_ASCONF);
}
if (sctp_multiple_asconfs == 0) {
sctp_feature_off(inp, SCTP_PCB_FLAGS_MULTIPLE_ASCONFS);
} else {
sctp_feature_on(inp, SCTP_PCB_FLAGS_MULTIPLE_ASCONFS);
}
/*
* set the automatic mobility_base from kernel flag (by
* micchie)
@ -3506,6 +3517,7 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr,
addr_inscope = 0;
}
}
#ifdef INET6
} else if (newaddr->sa_family == AF_INET6) {
struct sockaddr_in6 *sin6;
@ -3553,6 +3565,7 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr,
addr_inscope = 0;
}
}
#endif
} else {
/* not supported family type */
return (-1);
@ -3599,6 +3612,11 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr,
stcb->asoc.numnets++;
*(&net->ref_count) = 1;
net->tos_flowlabel = 0;
if (sctp_udp_tunneling_for_client_enable) {
net->port = htons(sctp_udp_tunneling_port);
} else {
net->port = 0;
}
#ifdef INET
if (newaddr->sa_family == AF_INET)
net->tos_flowlabel = stcb->asoc.default_tos;
@ -3625,14 +3643,6 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr,
#endif
SCTP_RTALLOC((sctp_route_t *) & net->ro, stcb->asoc.vrf_id);
#ifdef INET6
if (newaddr->sa_family == AF_INET6) {
struct sockaddr_in6 *sin6;
sin6 = (struct sockaddr_in6 *)&net->ro._l_addr;
(void)sa6_recoverscope(sin6);
}
#endif
if (SCTP_ROUTE_HAS_VALID_IFN(&net->ro)) {
/* Get source address */
net->ro._s_addr = sctp_source_address_selection(stcb->sctp_ep,
@ -3685,6 +3695,17 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr,
} else {
net->mtu = stcb->asoc.smallest_mtu;
}
#ifdef INET6
if (newaddr->sa_family == AF_INET6) {
struct sockaddr_in6 *sin6;
sin6 = (struct sockaddr_in6 *)&net->ro._l_addr;
(void)sa6_recoverscope(sin6);
}
#endif
if (net->port) {
net->mtu -= sizeof(struct udphdr);
}
if (stcb->asoc.smallest_mtu > net->mtu) {
#ifdef SCTP_PRINT_FOR_B_AND_M
SCTP_PRINTF("new address mtu:%d smaller than smallest:%d\n",
@ -4004,7 +4025,7 @@ sctp_remove_net(struct sctp_tcb *stcb, struct sctp_nets *net)
SCTPDBG(SCTP_DEBUG_ASCONF1, "remove_net: primary dst is deleting\n");
if (asoc->deleted_primary != NULL) {
SCTPDBG(SCTP_DEBUG_ASCONF1, "remove_net: deleted primary may be already stored\n");
goto leave;
goto out;
}
asoc->deleted_primary = net;
atomic_add_int(&net->ref_count, 1);
@ -4015,7 +4036,7 @@ sctp_remove_net(struct sctp_tcb *stcb, struct sctp_nets *net)
sctp_timer_start(SCTP_TIMER_TYPE_PRIM_DELETED,
stcb->sctp_ep, stcb, NULL);
}
leave:
out:
/* Try to find a confirmed primary */
asoc->primary_destination = sctp_find_alternate_net(stcb, lnet, 0);
}
@ -4625,6 +4646,30 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
ccnt = 0;
}
*/
/* ASCONF queue MAY not be empty */
if (!TAILQ_EMPTY(&asoc->asconf_send_queue)) {
chk = TAILQ_FIRST(&asoc->asconf_send_queue);
while (chk) {
TAILQ_REMOVE(&asoc->asconf_send_queue, chk, sctp_next);
if (chk->data) {
sctp_m_freem(chk->data);
chk->data = NULL;
}
ccnt++;
sctp_free_remote_addr(chk->whoTo);
SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_chunk, chk);
SCTP_DECR_CHK_COUNT();
/* sa_ignore FREED_MEMORY */
chk = TAILQ_FIRST(&asoc->asconf_send_queue);
}
}
/*
if(ccnt) {
printf("Freed %d from asconf_queue\n", ccnt);
ccnt = 0;
}
*/
if (!TAILQ_EMPTY(&asoc->reasmqueue)) {
chk = TAILQ_FIRST(&asoc->reasmqueue);
while (chk) {
@ -5239,6 +5284,10 @@ sctp_pcb_init()
sizeof(struct sctp_stream_queue_pending),
(sctp_max_number_of_assoc * sctp_chunkscale));
SCTP_ZONE_INIT(sctppcbinfo.ipi_zone_asconf, "sctp_asconf",
sizeof(struct sctp_asconf),
(sctp_max_number_of_assoc * sctp_chunkscale));
SCTP_ZONE_INIT(sctppcbinfo.ipi_zone_asconf_ack, "sctp_asconf_ack",
sizeof(struct sctp_asconf_ack),
(sctp_max_number_of_assoc * sctp_chunkscale));
@ -5298,6 +5347,73 @@ sctp_pcb_init()
}
/*
* Assumes that the sctppcbinfo lock is NOT held.
*/
void
sctp_pcb_finish(void)
{
struct sctp_vrflist *vrf_bucket;
struct sctp_vrf *vrf;
struct sctp_ifn *ifn;
struct sctp_ifa *ifa;
/* FIXME MT */
/*
* free the vrf/ifn/ifa lists and hashes (be sure address monitor is
* destroyed first).
*/
vrf_bucket = &sctppcbinfo.sctp_vrfhash[(SCTP_DEFAULT_VRFID & sctppcbinfo.hashvrfmark)];
vrf = LIST_FIRST(vrf_bucket);
while (vrf) {
ifn = LIST_FIRST(&vrf->ifnlist);
while (ifn) {
ifa = LIST_FIRST(&ifn->ifalist);
while (ifa) {
/* free the ifa */
LIST_REMOVE(ifa, next_bucket);
LIST_REMOVE(ifa, next_ifa);
SCTP_FREE(ifa, SCTP_M_IFA);
ifa = LIST_FIRST(&ifn->ifalist);
}
/* free the ifn */
LIST_REMOVE(ifn, next_bucket);
LIST_REMOVE(ifn, next_ifn);
SCTP_FREE(ifn, SCTP_M_IFN);
ifn = LIST_FIRST(&vrf->ifnlist);
}
SCTP_HASH_FREE(vrf->vrf_addr_hash, vrf->vrf_addr_hashmark);
/* free the vrf */
LIST_REMOVE(vrf, next_vrf);
SCTP_FREE(vrf, SCTP_M_VRF);
vrf = LIST_FIRST(vrf_bucket);
}
/* free the vrf hashes */
SCTP_HASH_FREE(sctppcbinfo.sctp_vrfhash, sctppcbinfo.hashvrfmark);
SCTP_HASH_FREE(sctppcbinfo.vrf_ifn_hash, sctppcbinfo.vrf_ifn_hashmark);
/* free the locks and mutexes */
#ifdef SCTP_PACKET_LOGGING
SCTP_IP_PKTLOG_DESTROY();
#endif
SCTP_IPI_ITERATOR_WQ_DESTROY();
SCTP_IPI_ADDR_DESTROY();
SCTP_ITERATOR_LOCK_DESTROY();
SCTP_STATLOG_DESTROY();
SCTP_INP_INFO_LOCK_DESTROY();
SCTP_ZONE_DESTROY(sctppcbinfo.ipi_zone_ep);
SCTP_ZONE_DESTROY(sctppcbinfo.ipi_zone_asoc);
SCTP_ZONE_DESTROY(sctppcbinfo.ipi_zone_laddr);
SCTP_ZONE_DESTROY(sctppcbinfo.ipi_zone_net);
SCTP_ZONE_DESTROY(sctppcbinfo.ipi_zone_chunk);
SCTP_ZONE_DESTROY(sctppcbinfo.ipi_zone_readq);
SCTP_ZONE_DESTROY(sctppcbinfo.ipi_zone_strmoq);
SCTP_ZONE_DESTROY(sctppcbinfo.ipi_zone_asconf);
SCTP_ZONE_DESTROY(sctppcbinfo.ipi_zone_asconf_ack);
}
int
sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,

View File

@ -184,6 +184,7 @@ struct sctp_epinfo {
sctp_zone_t ipi_zone_chunk;
sctp_zone_t ipi_zone_readq;
sctp_zone_t ipi_zone_strmoq;
sctp_zone_t ipi_zone_asconf;
sctp_zone_t ipi_zone_asconf_ack;
struct rwlock ipi_ep_mtx;
@ -435,7 +436,7 @@ struct sctp_tcb {
extern struct sctp_epinfo sctppcbinfo;
#ifdef INET6
int SCTP6_ARE_ADDR_EQUAL(struct in6_addr *a, struct in6_addr *b);
int SCTP6_ARE_ADDR_EQUAL(struct sockaddr_in6 *a, struct sockaddr_in6 *b);
#endif

View File

@ -257,6 +257,8 @@ struct sctp_nets {
uint16_t failure_threshold;
/* error stats on destination */
uint16_t error_count;
/* UDP port number in case of UDP tunneling */
uint16_t port;
uint8_t fast_retran_loss_recovery;
uint8_t will_exit_fast_recovery;
@ -547,6 +549,16 @@ struct sctp_cc_functions {
struct sctp_tcb *stcb, struct sctp_nets *net);
};
/* used to save ASCONF chunks for retransmission */
TAILQ_HEAD(sctp_asconf_head, sctp_asconf);
struct sctp_asconf {
TAILQ_ENTRY(sctp_asconf) next;
uint32_t serial_number;
uint16_t snd_count;
struct mbuf *data;
uint16_t len;
};
/* used to save ASCONF-ACK chunks for retransmission */
TAILQ_HEAD(sctp_asconf_ackhead, sctp_asconf_ack);
struct sctp_asconf_ack {
@ -602,6 +614,9 @@ struct sctp_association {
/* Control chunk queue */
struct sctpchunk_listhead control_send_queue;
/* ASCONF chunk queue */
struct sctpchunk_listhead asconf_send_queue;
/*
* Once a TSN hits the wire it is moved to the sent_queue. We
* maintain two counts here (don't know if any but retran_cnt is
@ -686,6 +701,7 @@ struct sctp_association {
uint32_t cookie_preserve_req;
/* ASCONF next seq I am sending out, inits at init-tsn */
uint32_t asconf_seq_out;
uint32_t asconf_seq_out_acked;
/* ASCONF last received ASCONF from peer, starts at peer's TSN-1 */
uint32_t asconf_seq_in;
@ -919,8 +935,6 @@ struct sctp_association {
* lock flag: 0 is ok to send, 1+ (duals as a retran count) is
* awaiting ACK
*/
uint16_t asconf_sent;
uint16_t mapping_array_size;
uint16_t last_strm_seq_delivered;

View File

@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$");
uint32_t sctp_sendspace = SCTPCTL_MAXDGRAM_DEFAULT;
uint32_t sctp_recvspace = SCTPCTL_RECVSPACE_DEFAULT;
uint32_t sctp_auto_asconf = SCTPCTL_AUTOASCONF_DEFAULT;
uint32_t sctp_multiple_asconfs = SCTPCTL_MULTIPLEASCONFS_DEFAULT;
uint32_t sctp_ecn_enable = SCTPCTL_ECN_ENABLE_DEFAULT;
uint32_t sctp_ecn_nonce = SCTPCTL_ECN_NONCE_DEFAULT;
uint32_t sctp_strict_sacks = SCTPCTL_STRICT_SACKS_DEFAULT;
@ -102,6 +103,9 @@ uint32_t sctp_mobility_fasthandoff = SCTPCTL_MOBILITY_FASTHANDOFF_DEFAULT;
struct sctp_log sctp_log;
#endif
uint32_t sctp_udp_tunneling_for_client_enable = SCTPCTL_UDP_TUNNELING_FOR_CLIENT_ENABLE_DEFAULT;
uint32_t sctp_udp_tunneling_port = SCTPCTL_UDP_TUNNELING_PORT_DEFAULT;
#ifdef SCTP_DEBUG
uint32_t sctp_debug_on = SCTPCTL_DEBUG_DEFAULT;
@ -493,10 +497,34 @@ sctp_assoclist(SYSCTL_HANDLER_ARGS)
return error;
}
#define RANGECHK(var, min, max) \
if ((var) < (min)) { (var) = (min); } \
else if ((var) > (max)) { (var) = (max); }
static int
sysctl_sctp_udp_tunneling_check(SYSCTL_HANDLER_ARGS)
{
int error;
uint32_t old_sctp_udp_tunneling_port;
old_sctp_udp_tunneling_port = sctp_udp_tunneling_port;
error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
if (error == 0) {
RANGECHK(sctp_udp_tunneling_port, SCTPCTL_UDP_TUNNELING_PORT_MIN, SCTPCTL_UDP_TUNNELING_PORT_MAX);
if (old_sctp_udp_tunneling_port) {
sctp_over_udp_stop();
}
if (sctp_udp_tunneling_port) {
if (sctp_over_udp_start()) {
sctp_udp_tunneling_port = 0;
}
}
}
return (error);
}
static int
sysctl_sctp_check(SYSCTL_HANDLER_ARGS)
{
@ -565,6 +593,7 @@ sysctl_sctp_check(SYSCTL_HANDLER_ARGS)
#if defined(__FreeBSD__) || defined(SCTP_APPLE_MOBILITY_FASTHANDOFF)
RANGECHK(sctp_mobility_fasthandoff, SCTPCTL_MOBILITY_FASTHANDOFF_MIN, SCTPCTL_MOBILITY_FASTHANDOFF_MAX);
#endif
RANGECHK(sctp_udp_tunneling_for_client_enable, SCTPCTL_UDP_TUNNELING_FOR_CLIENT_ENABLE_MIN, SCTPCTL_UDP_TUNNELING_FOR_CLIENT_ENABLE_MAX);
#ifdef SCTP_DEBUG
RANGECHK(sctp_debug_on, SCTPCTL_DEBUG_MIN, SCTPCTL_DEBUG_MAX);
#endif
@ -808,6 +837,14 @@ SYSCTL_STRUCT(_net_inet_sctp, OID_AUTO, log, CTLFLAG_RD,
"SCTP logging (struct sctp_log)");
#endif
SYSCTL_PROC(_net_inet_sctp, OID_AUTO, udp_tunneling_for_client_enable, CTLTYPE_INT | CTLFLAG_RW,
&sctp_udp_tunneling_for_client_enable, 0, sysctl_sctp_check, "IU",
SCTPCTL_UDP_TUNNELING_FOR_CLIENT_ENABLE_DESC);
SYSCTL_PROC(_net_inet_sctp, OID_AUTO, udp_tunneling_port, CTLTYPE_INT | CTLFLAG_RW,
&sctp_udp_tunneling_port, 0, sysctl_sctp_udp_tunneling_check, "IU",
SCTPCTL_UDP_TUNNELING_PORT_DESC);
#ifdef SCTP_DEBUG
SYSCTL_PROC(_net_inet_sctp, OID_AUTO, debug, CTLTYPE_INT | CTLFLAG_RW,
&sctp_debug_on, 0, sysctl_sctp_check, "IU",

View File

@ -58,6 +58,12 @@ __FBSDID("$FreeBSD$");
#define SCTPCTL_AUTOASCONF_MAX 1
#define SCTPCTL_AUTOASCONF_DEFAULT SCTP_DEFAULT_AUTO_ASCONF
/* autoasconf: Enable SCTP Auto-ASCONF */
#define SCTPCTL_MULTIPLEASCONFS_DESC "Enable SCTP Muliple-ASCONFs"
#define SCTPCTL_MULTIPLEASCONFS_MIN 0
#define SCTPCTL_MULTIPLEASCONFS_MAX 1
#define SCTPCTL_MULTIPLEASCONFS_DEFAULT SCTP_DEFAULT_MULTIPLE_ASCONFS
/* ecn_enable: Enable SCTP ECN */
#define SCTPCTL_ECN_ENABLE_DESC "Enable SCTP ECN"
#define SCTPCTL_ECN_ENABLE_MIN 0
@ -370,6 +376,18 @@ __FBSDID("$FreeBSD$");
#define SCTPCTL_MOBILITY_FASTHANDOFF_MAX 1
#define SCTPCTL_MOBILITY_FASTHANDOFF_DEFAULT SCTP_DEFAULT_MOBILITY_FASTHANDOFF
/* Enable SCTP/UDP tunneling for clients*/
#define SCTPCTL_UDP_TUNNELING_FOR_CLIENT_ENABLE_DESC "Enable SCTP/UDP tunneling for client"
#define SCTPCTL_UDP_TUNNELING_FOR_CLIENT_ENABLE_MIN 0
#define SCTPCTL_UDP_TUNNELING_FOR_CLIENT_ENABLE_MAX 1
#define SCTPCTL_UDP_TUNNELING_FOR_CLIENT_ENABLE_DEFAULT SCTPCTL_UDP_TUNNELING_FOR_CLIENT_ENABLE_MIN
/* Enable SCTP/UDP tunneling port */
#define SCTPCTL_UDP_TUNNELING_PORT_DESC "Set the SCTP/UDP tunneling port"
#define SCTPCTL_UDP_TUNNELING_PORT_MIN 0
#define SCTPCTL_UDP_TUNNELING_PORT_MAX 65535
#define SCTPCTL_UDP_TUNNELING_PORT_DEFAULT SCTP_OVER_UDP_TUNNELING_PORT
#if defined(SCTP_DEBUG)
/* debug: Configure debug output */
#define SCTPCTL_DEBUG_DESC "Configure debug output"
@ -388,6 +406,7 @@ __FBSDID("$FreeBSD$");
extern uint32_t sctp_sendspace;
extern uint32_t sctp_recvspace;
extern uint32_t sctp_auto_asconf;
extern uint32_t sctp_multiple_asconfs;
extern uint32_t sctp_ecn_enable;
extern uint32_t sctp_ecn_nonce;
extern uint32_t sctp_strict_sacks;
@ -449,6 +468,9 @@ extern uint32_t sctp_mobility_fasthandoff;
extern struct sctp_log sctp_log;
#endif
extern uint32_t sctp_udp_tunneling_for_client_enable;
extern uint32_t sctp_udp_tunneling_port;
#if defined(SCTP_DEBUG)
extern uint32_t sctp_debug_on;

View File

@ -173,6 +173,11 @@ sctp_audit_retranmission_queue(struct sctp_association *asoc)
sctp_ucount_incr(asoc->sent_queue_retran_cnt);
}
}
TAILQ_FOREACH(chk, &asoc->asconf_send_queue, sctp_next) {
if (chk->sent == SCTP_DATAGRAM_RESEND) {
sctp_ucount_incr(asoc->sent_queue_retran_cnt);
}
}
SCTPDBG(SCTP_DEBUG_TIMER4, "Audit completes retran:%d onqueue:%d\n",
asoc->sent_queue_retran_cnt,
asoc->sent_queue_cnt);
@ -1314,10 +1319,10 @@ sctp_asconf_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
struct sctp_nets *net)
{
struct sctp_nets *alt;
struct sctp_tmit_chunk *asconf, *chk;
struct sctp_tmit_chunk *asconf, *chk, *nchk;
/* is this a first send, or a retransmission? */
if (stcb->asoc.asconf_sent == 0) {
if (TAILQ_EMPTY(&stcb->asoc.asconf_send_queue)) {
/* compose a new ASCONF chunk and send it */
sctp_send_asconf(stcb, net, SCTP_ADDR_NOT_LOCKED);
} else {
@ -1326,12 +1331,7 @@ sctp_asconf_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
*/
/* find the existing ASCONF */
TAILQ_FOREACH(asconf, &stcb->asoc.control_send_queue,
sctp_next) {
if (asconf->rec.chunk_id.id == SCTP_ASCONF) {
break;
}
}
asconf = TAILQ_FIRST(&stcb->asoc.asconf_send_queue);
if (asconf == NULL) {
return (0);
}
@ -1359,10 +1359,11 @@ sctp_asconf_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
*/
sctp_backoff_on_timeout(stcb, asconf->whoTo, 1, 0);
alt = sctp_find_alternate_net(stcb, asconf->whoTo, 0);
sctp_free_remote_addr(asconf->whoTo);
asconf->whoTo = alt;
atomic_add_int(&alt->ref_count, 1);
if (asconf->whoTo != alt) {
sctp_free_remote_addr(asconf->whoTo);
asconf->whoTo = alt;
atomic_add_int(&alt->ref_count, 1);
}
/* See if an ECN Echo is also stranded */
TAILQ_FOREACH(chk, &stcb->asoc.control_send_queue, sctp_next) {
if ((chk->whoTo == net) &&
@ -1376,17 +1377,32 @@ sctp_asconf_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
atomic_add_int(&alt->ref_count, 1);
}
}
for (chk = asconf; chk; chk = nchk) {
nchk = TAILQ_NEXT(chk, sctp_next);
if (chk->whoTo != alt) {
sctp_free_remote_addr(chk->whoTo);
chk->whoTo = alt;
atomic_add_int(&alt->ref_count, 1);
}
if (asconf->sent != SCTP_DATAGRAM_RESEND && chk->sent != SCTP_DATAGRAM_UNSENT)
sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt);
chk->sent = SCTP_DATAGRAM_RESEND;
}
if (net->dest_state & SCTP_ADDR_NOT_REACHABLE) {
/*
* If the address went un-reachable, we need to move
* to the alternate for ALL chunks in queue
*/
sctp_move_all_chunks_to_alt(stcb, net, alt);
net = alt;
}
/* mark the retran info */
if (asconf->sent != SCTP_DATAGRAM_RESEND)
sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt);
asconf->sent = SCTP_DATAGRAM_RESEND;
/* send another ASCONF if any and we can do */
sctp_send_asconf(stcb, alt, SCTP_ADDR_NOT_LOCKED);
}
return (0);
}
@ -1677,16 +1693,11 @@ sctp_pathmtu_timer(struct sctp_inpcb *inp,
struct sctp_tcb *stcb,
struct sctp_nets *net)
{
uint32_t next_mtu;
uint32_t next_mtu, mtu;
/* restart the timer in any case */
next_mtu = sctp_getnext_mtu(inp, net->mtu);
if (next_mtu <= net->mtu) {
/* nothing to do */
return;
} {
uint32_t mtu;
if ((next_mtu > net->mtu) && (net->port == 0)) {
if ((net->src_addr_selected == 0) ||
(net->ro._s_addr == NULL) ||
(net->ro._s_addr->localifa_flags & SCTP_BEING_DELETED)) {
@ -1695,10 +1706,26 @@ sctp_pathmtu_timer(struct sctp_inpcb *inp,
net->ro._s_addr = NULL;
net->src_addr_selected = 0;
} else if (net->ro._s_addr == NULL) {
#if defined(INET6) && defined(SCTP_EMBEDDED_V6_SCOPE)
if (net->ro._l_addr.sa.sa_family == AF_INET6) {
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&net->ro._l_addr;
/* KAME hack: embed scopeid */
(void)sa6_embedscope(sin6, ip6_use_defzone);
}
#endif
net->ro._s_addr = sctp_source_address_selection(inp,
stcb,
(sctp_route_t *) & net->ro,
net, 0, stcb->asoc.vrf_id);
#if defined(INET6) && defined(SCTP_EMBEDDED_V6_SCOPE)
if (net->ro._l_addr.sa.sa_family == AF_INET6) {
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&net->ro._l_addr;
(void)sa6_recoverscope(sin6);
}
#endif /* INET6 */
}
if (net->ro._s_addr)
net->src_addr_selected = 1;

View File

@ -102,7 +102,7 @@ sctp_pcbinfo_cleanup(void)
}
static void
void
sctp_pathmtu_adjustment(struct sctp_inpcb *inp,
struct sctp_tcb *stcb,
struct sctp_nets *net,

View File

@ -300,7 +300,9 @@ int sctp_disconnect(struct socket *so);
void sctp_ctlinput __P((int, struct sockaddr *, void *));
int sctp_ctloutput __P((struct socket *, struct sockopt *));
void sctp_input_with_port __P((struct mbuf *, int, uint16_t));
void sctp_input __P((struct mbuf *, int));
void sctp_pathmtu_adjustment __P((struct sctp_inpcb *, struct sctp_tcb *, struct sctp_nets *, uint16_t));
void sctp_drain __P((void));
void sctp_init __P((void));

View File

@ -956,6 +956,7 @@ sctp_init_asoc(struct sctp_inpcb *m, struct sctp_tcb *stcb,
asoc->assoc_id = asoc->my_vtag;
asoc->asconf_seq_out = asoc->str_reset_seq_out = asoc->init_seq_number = asoc->sending_seq =
sctp_select_initial_TSN(&m->sctp_ep);
asoc->asconf_seq_out_acked = asoc->asconf_seq_out - 1;
/* we are optimisitic here */
asoc->peer_supports_pktdrop = 1;
@ -1151,6 +1152,7 @@ sctp_init_asoc(struct sctp_inpcb *m, struct sctp_tcb *stcb,
TAILQ_INIT(&asoc->free_chunks);
TAILQ_INIT(&asoc->out_wheel);
TAILQ_INIT(&asoc->control_send_queue);
TAILQ_INIT(&asoc->asconf_send_queue);
TAILQ_INIT(&asoc->send_queue);
TAILQ_INIT(&asoc->sent_queue);
TAILQ_INIT(&asoc->reasmqueue);
@ -3792,7 +3794,7 @@ sctp_abort_notification(struct sctp_tcb *stcb, int error, int so_locked
void
sctp_abort_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
struct mbuf *m, int iphlen, struct sctphdr *sh, struct mbuf *op_err,
uint32_t vrf_id)
uint32_t vrf_id, uint16_t port)
{
uint32_t vtag;
@ -3810,7 +3812,7 @@ sctp_abort_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
vrf_id = stcb->asoc.vrf_id;
stcb->asoc.state |= SCTP_STATE_WAS_ABORTED;
}
sctp_send_abort(m, iphlen, sh, vtag, op_err, vrf_id);
sctp_send_abort(m, iphlen, sh, vtag, op_err, vrf_id, port);
if (stcb != NULL) {
/* Ok, now lets free it */
#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
@ -3967,7 +3969,7 @@ sctp_abort_an_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
void
sctp_handle_ootb(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh,
struct sctp_inpcb *inp, struct mbuf *op_err, uint32_t vrf_id)
struct sctp_inpcb *inp, struct mbuf *op_err, uint32_t vrf_id, uint16_t port)
{
struct sctp_chunkhdr *ch, chunk_buf;
unsigned int chk_length;
@ -4005,7 +4007,7 @@ sctp_handle_ootb(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh,
*/
return;
case SCTP_SHUTDOWN_ACK:
sctp_send_shutdown_complete2(m, iphlen, sh, vrf_id);
sctp_send_shutdown_complete2(m, iphlen, sh, vrf_id, port);
return;
default:
break;
@ -4014,7 +4016,7 @@ sctp_handle_ootb(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh,
ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset,
sizeof(*ch), (uint8_t *) & chunk_buf);
}
sctp_send_abort(m, iphlen, sh, 0, op_err, vrf_id);
sctp_send_abort(m, iphlen, sh, 0, op_err, vrf_id, port);
}
/*
@ -4140,8 +4142,8 @@ sctp_cmpaddr(struct sockaddr *sa1, struct sockaddr *sa2)
sin6_1 = (struct sockaddr_in6 *)sa1;
sin6_2 = (struct sockaddr_in6 *)sa2;
return (SCTP6_ARE_ADDR_EQUAL(&sin6_1->sin6_addr,
&sin6_2->sin6_addr));
return (SCTP6_ARE_ADDR_EQUAL(sin6_1,
sin6_2));
}
#endif
case AF_INET:
@ -4776,8 +4778,8 @@ sctp_find_ifa_in_ep(struct sctp_inpcb *inp, struct sockaddr *addr,
}
#ifdef INET6
if (addr->sa_family == AF_INET6) {
if (SCTP6_ARE_ADDR_EQUAL(&((struct sockaddr_in6 *)addr)->sin6_addr,
&laddr->ifa->address.sin6.sin6_addr)) {
if (SCTP6_ARE_ADDR_EQUAL((struct sockaddr_in6 *)addr,
&laddr->ifa->address.sin6)) {
/* found him. */
if (holds_lock == 0) {
SCTP_INP_RUNLOCK(inp);
@ -4866,8 +4868,8 @@ sctp_find_ifa_by_addr(struct sockaddr *addr, uint32_t vrf_id, int holds_lock)
}
#ifdef INET6
if (addr->sa_family == AF_INET6) {
if (SCTP6_ARE_ADDR_EQUAL(&((struct sockaddr_in6 *)addr)->sin6_addr,
&sctp_ifap->address.sin6.sin6_addr)) {
if (SCTP6_ARE_ADDR_EQUAL((struct sockaddr_in6 *)addr,
&sctp_ifap->address.sin6)) {
/* found him. */
if (holds_lock == 0)
SCTP_IPI_ADDR_RUNLOCK();
@ -6605,3 +6607,19 @@ sctp_log_trace(uint32_t subsys, const char *str SCTP_UNUSED, uint32_t a, uint32_
}
#endif
/* We will need to add support
* to bind the ports and such here
* so we can do UDP tunneling. In
* the mean-time, we return error
*/
void
sctp_over_udp_stop(void)
{
return;
}
int
sctp_over_udp_start(void)
{
return (-1);
}

View File

@ -178,7 +178,7 @@ sctp_abort_notification(struct sctp_tcb *, int, int
/* We abort responding to an IP packet for some reason */
void
sctp_abort_association(struct sctp_inpcb *, struct sctp_tcb *,
struct mbuf *, int, struct sctphdr *, struct mbuf *, uint32_t);
struct mbuf *, int, struct sctphdr *, struct mbuf *, uint32_t, uint16_t);
/* We choose to abort via user input */
@ -192,7 +192,7 @@ sctp_abort_an_association(struct sctp_inpcb *, struct sctp_tcb *, int,
void
sctp_handle_ootb(struct mbuf *, int, int, struct sctphdr *,
struct sctp_inpcb *, struct mbuf *, uint32_t);
struct sctp_inpcb *, struct mbuf *, uint32_t, uint16_t);
int
sctp_connectx_helper_add(struct sctp_tcb *stcb, struct sockaddr *addr,
@ -314,6 +314,9 @@ do { \
} \
} while (0)
/* new functions to start/stop udp tunneling */
void sctp_over_udp_stop(void);
int sctp_over_udp_start(void);
int
sctp_soreceive(struct socket *so, struct sockaddr **psa,

View File

@ -177,14 +177,14 @@ sctp6_input(struct mbuf **i_pak, int *offp, int proto)
sh->v_tag = 0;
}
if (ch->chunk_type == SCTP_SHUTDOWN_ACK) {
sctp_send_shutdown_complete2(m, iphlen, sh, vrf_id);
sctp_send_shutdown_complete2(m, iphlen, sh, vrf_id, 0);
goto bad;
}
if (ch->chunk_type == SCTP_SHUTDOWN_COMPLETE) {
goto bad;
}
if (ch->chunk_type != SCTP_ABORT_ASSOCIATION)
sctp_send_abort(m, iphlen, sh, 0, NULL, vrf_id);
sctp_send_abort(m, iphlen, sh, 0, NULL, vrf_id, 0);
goto bad;
} else if (stcb == NULL) {
refcount_up = 1;
@ -212,7 +212,7 @@ sctp6_input(struct mbuf **i_pak, int *offp, int proto)
/* sa_ignore NO_NULL_CHK */
sctp_common_input_processing(&m, iphlen, offset, length, sh, ch,
in6p, stcb, net, ecn_bits, vrf_id);
in6p, stcb, net, ecn_bits, vrf_id, 0);
/* inp's ref-count reduced && stcb unlocked */
/* XXX this stuff below gets moved to appropriate parts later... */
if (m)