aboutsummaryrefslogtreecommitdiff
path: root/sys/netinet/sctp_pcb.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netinet/sctp_pcb.c')
-rw-r--r--sys/netinet/sctp_pcb.c77
1 files changed, 60 insertions, 17 deletions
diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c
index 3d7ecb708ed0..fdec3e5911de 100644
--- a/sys/netinet/sctp_pcb.c
+++ b/sys/netinet/sctp_pcb.c
@@ -1996,11 +1996,13 @@ sctp_move_pcb_and_assoc(struct sctp_inpcb *old_inp, struct sctp_inpcb *new_inp,
struct sctppcbhead *head;
struct sctp_laddr *laddr, *oladdr;
+ atomic_add_int(&stcb->asoc.refcnt, 1);
SCTP_TCB_UNLOCK(stcb);
SCTP_INP_INFO_WLOCK();
SCTP_INP_WLOCK(old_inp);
SCTP_INP_WLOCK(new_inp);
SCTP_TCB_LOCK(stcb);
+ atomic_subtract_int(&stcb->asoc.refcnt, 1);
new_inp->sctp_ep.time_of_secret_change =
old_inp->sctp_ep.time_of_secret_change;
@@ -2404,6 +2406,26 @@ 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);
}
+ /*
+ * set the automatic mobility_base from kernel flag (by
+ * micchie)
+ */
+ if (sctp_mobility_base == 0) {
+ sctp_mobility_feature_off(inp, SCTP_MOBILITY_BASE);
+ } else {
+ sctp_mobility_feature_on(inp, SCTP_MOBILITY_BASE);
+ }
+ /*
+ * set the automatic mobility_fasthandoff from kernel flag
+ * (by micchie)
+ */
+ if (sctp_mobility_fasthandoff == 0) {
+ sctp_mobility_feature_off(inp, SCTP_MOBILITY_FASTHANDOFF);
+ sctp_mobility_feature_off(inp, SCTP_MOBILITY_DO_FASTHANDOFF);
+ } else {
+ sctp_mobility_feature_on(inp, SCTP_MOBILITY_FASTHANDOFF);
+ sctp_mobility_feature_off(inp, SCTP_MOBILITY_DO_FASTHANDOFF);
+ }
} else {
/*
* bind specific, make sure flags is off and add a new
@@ -2645,18 +2667,13 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
* send()/close or connect/send/close. And
* it wants the data to get across first.
*/
- if (asoc->asoc.total_output_queue_size == 0) {
- /*
- * Just abandon things in the front
- * states
- */
+ /* Just abandon things in the front states */
- if (sctp_free_assoc(inp, asoc, SCTP_PCBFREE_NOFORCE,
- SCTP_FROM_SCTP_PCB + SCTP_LOC_2) == 0) {
- cnt_in_sd++;
- }
- continue;
+ if (sctp_free_assoc(inp, asoc, SCTP_PCBFREE_NOFORCE,
+ SCTP_FROM_SCTP_PCB + SCTP_LOC_2) == 0) {
+ cnt_in_sd++;
}
+ continue;
}
/* Disconnect the socket please */
asoc->sctp_socket = NULL;
@@ -2721,7 +2738,7 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
asoc->asoc.primary_destination);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, asoc->sctp_ep, asoc,
asoc->asoc.primary_destination);
- sctp_chunk_output(inp, asoc, SCTP_OUTPUT_FROM_SHUT_TMR);
+ sctp_chunk_output(inp, asoc, SCTP_OUTPUT_FROM_CLOSING);
}
} else {
/* mark into shutdown pending */
@@ -2782,6 +2799,8 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
cnt_in_sd++;
}
continue;
+ } else {
+ sctp_chunk_output(inp, asoc, SCTP_OUTPUT_FROM_CLOSING);
}
}
cnt_in_sd++;
@@ -3751,6 +3770,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
struct sctp_laddr *laddr;
struct sctp_tmit_chunk *chk;
struct sctp_asconf_addr *aparam;
+ struct sctp_asconf_ack *aack;
struct sctp_stream_reset_list *liste;
struct sctp_queued_to_read *sq;
struct sctp_stream_queue_pending *sp;
@@ -4233,9 +4253,16 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
TAILQ_REMOVE(&asoc->asconf_queue, aparam, next);
SCTP_FREE(aparam, SCTP_M_ASC_ADDR);
}
- if (asoc->last_asconf_ack_sent != NULL) {
- sctp_m_freem(asoc->last_asconf_ack_sent);
- asoc->last_asconf_ack_sent = NULL;
+ while (!TAILQ_EMPTY(&asoc->asconf_ack_sent)) {
+ aack = TAILQ_FIRST(&asoc->asconf_ack_sent);
+ TAILQ_REMOVE(&asoc->asconf_ack_sent, aack, next);
+ if (aack->last_sent_to != NULL) {
+ sctp_free_remote_addr(aack->last_sent_to);
+ }
+ if (aack->data != NULL) {
+ sctp_m_freem(aack->data);
+ }
+ SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_asconf_ack, aack);
}
/* clean up auth stuff */
if (asoc->local_hmacs)
@@ -4746,6 +4773,11 @@ sctp_pcb_init()
sizeof(struct sctp_stream_queue_pending),
(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));
+
+
/* Master Lock INIT for info structure */
SCTP_INP_INFO_LOCK_INIT();
SCTP_STATLOG_INIT_LOCK();
@@ -4830,6 +4862,8 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
uint8_t hmacs_store[SCTP_PARAM_BUFFER_SIZE];
struct sctp_auth_hmac_algo *hmacs = NULL;
uint16_t hmacs_len = 0;
+ uint8_t saw_asconf = 0;
+ uint8_t saw_asconf_ack = 0;
uint8_t chunks_store[SCTP_PARAM_BUFFER_SIZE];
struct sctp_auth_chunk_list *chunks = NULL;
uint16_t num_chunks = 0;
@@ -5107,8 +5141,8 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
(struct sctp_paramhdr *)&ai, sizeof(ai));
aip = (struct sctp_adaptation_layer_indication *)phdr;
if (aip) {
- sctp_ulp_notify(SCTP_NOTIFY_ADAPTATION_INDICATION,
- stcb, ntohl(aip->indication), NULL);
+ stcb->asoc.peers_adaptation = ntohl(aip->indication);
+ stcb->asoc.adaptation_needed = 1;
}
}
} else if (ptype == SCTP_SET_PRIM_ADDR) {
@@ -5279,6 +5313,12 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
for (i = 0; i < num_chunks; i++) {
(void)sctp_auth_add_chunk(chunks->chunk_types[i],
stcb->asoc.peer_auth_chunks);
+ /* record asconf/asconf-ack if listed */
+ if (chunks->chunk_types[i] == SCTP_ASCONF)
+ saw_asconf = 1;
+ if (chunks->chunk_types[i] == SCTP_ASCONF_ACK)
+ saw_asconf_ack = 1;
+
}
got_chklist = 1;
} else if ((ptype == SCTP_HEARTBEAT_INFO) ||
@@ -5341,6 +5381,9 @@ next_param:
!stcb->asoc.peer_supports_auth) {
/* peer supports asconf but not auth? */
return (-32);
+ } else if ((stcb->asoc.peer_supports_asconf) && (stcb->asoc.peer_supports_auth) &&
+ ((saw_asconf == 0) || (saw_asconf_ack == 0))) {
+ return (-33);
}
/* concatenate the full random key */
#ifdef SCTP_AUTH_DRAFT_04
@@ -5376,7 +5419,7 @@ next_param:
#endif
else {
/* failed to get memory for the key */
- return (-33);
+ return (-34);
}
if (stcb->asoc.authinfo.peer_random != NULL)
sctp_free_key(stcb->asoc.authinfo.peer_random);