From c79bec9c7509f55bcc0a9e30de53a6cb26b94605 Mon Sep 17 00:00:00 2001 From: Michael Tuexen Date: Tue, 12 Aug 2014 11:30:16 +0000 Subject: [PATCH] Add support for the SCTP_AUTH_SUPPORTED and SCTP_ASCONF_SUPPORTED socket options. Add also a sysctl to control the support of ASCONF. MFC after: 1 week --- lib/libc/net/sctp_sys_calls.c | 7 ++ sys/netinet/sctp.h | 6 +- sys/netinet/sctp_asconf.c | 26 ++----- sys/netinet/sctp_auth.c | 15 ---- sys/netinet/sctp_auth.h | 1 - sys/netinet/sctp_input.c | 53 ++++++++----- sys/netinet/sctp_output.c | 86 ++++++++++----------- sys/netinet/sctp_pcb.c | 114 +++++++++++++++++---------- sys/netinet/sctp_pcb.h | 2 + sys/netinet/sctp_peeloff.c | 2 + sys/netinet/sctp_structs.h | 6 +- sys/netinet/sctp_sysctl.c | 66 ++++++++++++++-- sys/netinet/sctp_sysctl.h | 21 +++-- sys/netinet/sctp_usrreq.c | 140 ++++++++++++++++++++++++++++++++++ sys/netinet/sctputil.c | 14 ++-- 15 files changed, 395 insertions(+), 164 deletions(-) diff --git a/lib/libc/net/sctp_sys_calls.c b/lib/libc/net/sctp_sys_calls.c index 8e7d709c29fb..6a57061a7046 100644 --- a/lib/libc/net/sctp_sys_calls.c +++ b/lib/libc/net/sctp_sys_calls.c @@ -356,6 +356,12 @@ sctp_opt_info(int sd, sctp_assoc_t id, int opt, void *arg, socklen_t * size) case SCTP_PR_SUPPORTED: ((struct sctp_assoc_value *)arg)->assoc_id = id; break; + case SCTP_AUTH_SUPPORTED: + ((struct sctp_assoc_value *)arg)->assoc_id = id; + break; + case SCTP_ASCONF_SUPPORTED: + ((struct sctp_assoc_value *)arg)->assoc_id = id; + break; case SCTP_RECONFIG_SUPPORTED: ((struct sctp_assoc_value *)arg)->assoc_id = id; break; @@ -590,6 +596,7 @@ sctp_sendmsg(int s, cmsg->cmsg_type = SCTP_SNDRCV; cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg); + memset(sinfo, 0, sizeof(struct sctp_sndrcvinfo)); sinfo->sinfo_stream = stream_no; sinfo->sinfo_ssn = 0; sinfo->sinfo_flags = flags; diff --git a/sys/netinet/sctp.h b/sys/netinet/sctp.h index 324609ca5502..c2497a7d40b4 100644 --- a/sys/netinet/sctp.h +++ b/sys/netinet/sctp.h @@ -123,9 +123,11 @@ struct sctp_paramhdr { #define SCTP_REMOTE_UDP_ENCAPS_PORT 0x00000024 #define SCTP_ECN_SUPPORTED 0x00000025 #define SCTP_PR_SUPPORTED 0x00000026 -#define SCTP_NRSACK_SUPPORTED 0x00000027 -#define SCTP_PKTDROP_SUPPORTED 0x00000028 +#define SCTP_AUTH_SUPPORTED 0x00000027 +#define SCTP_ASCONF_SUPPORTED 0x00000028 #define SCTP_RECONFIG_SUPPORTED 0x00000029 +#define SCTP_NRSACK_SUPPORTED 0x00000030 +#define SCTP_PKTDROP_SUPPORTED 0x00000031 /* * read-only options diff --git a/sys/netinet/sctp_asconf.c b/sys/netinet/sctp_asconf.c index ed88b3c91f11..127710171c38 100644 --- a/sys/netinet/sctp_asconf.c +++ b/sys/netinet/sctp_asconf.c @@ -724,13 +724,11 @@ sctp_handle_asconf(struct mbuf *m, unsigned int offset, } switch (param_type) { case SCTP_ADD_IP_ADDRESS: - asoc->peer_supports_asconf = 1; m_result = sctp_process_asconf_add_ip(src, aph, stcb, (cnt < SCTP_BASE_SYSCTL(sctp_hb_maxburst)), error); cnt++; break; case SCTP_DEL_IP_ADDRESS: - asoc->peer_supports_asconf = 1; m_result = sctp_process_asconf_delete_ip(src, aph, stcb, error); break; @@ -738,7 +736,6 @@ sctp_handle_asconf(struct mbuf *m, unsigned int offset, /* not valid in an ASCONF chunk */ break; case SCTP_SET_PRIM_ADDR: - asoc->peer_supports_asconf = 1; m_result = sctp_process_asconf_set_primary(src, aph, stcb, error); break; @@ -930,8 +927,6 @@ sctp_addr_match(struct sctp_paramhdr *ph, struct sockaddr *sa) void sctp_asconf_cleanup(struct sctp_tcb *stcb, struct sctp_nets *net) { - /* mark peer as ASCONF incapable */ - stcb->asoc.peer_supports_asconf = 0; /* * clear out any existing asconfs going out */ @@ -1340,7 +1335,7 @@ sctp_asconf_queue_add(struct sctp_tcb *stcb, struct sctp_ifa *ifa, int pending_delete_queued = 0; /* see if peer supports ASCONF */ - if (stcb->asoc.peer_supports_asconf == 0) { + if (stcb->asoc.asconf_supported == 0) { return (-1); } /* @@ -1430,7 +1425,7 @@ sctp_asconf_queue_sa_delete(struct sctp_tcb *stcb, struct sockaddr *sa) return (-1); } /* see if peer supports ASCONF */ - if (stcb->asoc.peer_supports_asconf == 0) { + if (stcb->asoc.asconf_supported == 0) { return (-1); } /* make sure the request isn't already in the queue */ @@ -1550,7 +1545,7 @@ sctp_asconf_find_param(struct sctp_tcb *stcb, uint32_t correlation_id) * notifications based on the error response */ static void -sctp_asconf_process_error(struct sctp_tcb *stcb, +sctp_asconf_process_error(struct sctp_tcb *stcb SCTP_UNUSED, struct sctp_asconf_paramhdr *aph) { struct sctp_error_cause *eh; @@ -1588,10 +1583,7 @@ sctp_asconf_process_error(struct sctp_tcb *stcb, switch (param_type) { case SCTP_ADD_IP_ADDRESS: case SCTP_DEL_IP_ADDRESS: - stcb->asoc.peer_supports_asconf = 0; - break; case SCTP_SET_PRIM_ADDR: - stcb->asoc.peer_supports_asconf = 0; break; default: break; @@ -1627,8 +1619,6 @@ sctp_asconf_process_param_ack(struct sctp_tcb *stcb, 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; break; default: /* should NEVER happen */ @@ -1646,11 +1636,11 @@ sctp_asconf_process_param_ack(struct sctp_tcb *stcb, * cleanup from a bad asconf ack parameter */ static void -sctp_asconf_ack_clear(struct sctp_tcb *stcb) +sctp_asconf_ack_clear(struct sctp_tcb *stcb SCTP_UNUSED) { /* assume peer doesn't really know how to do asconfs */ - stcb->asoc.peer_supports_asconf = 0; /* XXX we could free the pending queue here */ + } void @@ -1988,7 +1978,7 @@ sctp_addr_mgmt_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, /* 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) { + if (stcb->asoc.asconf_supported) { /* queue an asconf for this addr */ status = sctp_asconf_queue_add(stcb, ifa, type); @@ -2238,7 +2228,7 @@ sctp_asconf_iterator_stcb(struct sctp_inpcb *inp, struct sctp_tcb *stcb, } /* queue an asconf for this address add/delete */ if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_DO_ASCONF) && - stcb->asoc.peer_supports_asconf) { + stcb->asoc.asconf_supported == 1) { /* queue an asconf for this addr */ status = sctp_asconf_queue_add(stcb, ifa, type); /* @@ -2886,7 +2876,7 @@ sctp_process_initack_addresses(struct sctp_tcb *stcb, struct mbuf *m, /* are ASCONFs allowed ? */ if ((sctp_is_feature_on(stcb->sctp_ep, SCTP_PCB_FLAGS_DO_ASCONF)) && - stcb->asoc.peer_supports_asconf) { + stcb->asoc.asconf_supported) { /* queue an ASCONF DEL_IP_ADDRESS */ status = sctp_asconf_queue_sa_delete(stcb, sa); /* diff --git a/sys/netinet/sctp_auth.c b/sys/netinet/sctp_auth.c index cd55e2558085..1f301030b2d4 100644 --- a/sys/netinet/sctp_auth.c +++ b/sys/netinet/sctp_auth.c @@ -133,11 +133,6 @@ sctp_auth_delete_chunk(uint8_t chunk, sctp_auth_chklist_t * list) if (list == NULL) return (-1); - /* is chunk restricted? */ - if ((chunk == SCTP_ASCONF) || - (chunk == SCTP_ASCONF_ACK)) { - return (-1); - } if (list->chunks[chunk] == 1) { list->chunks[chunk] = 0; list->num_chunks--; @@ -157,16 +152,6 @@ sctp_auth_get_chklist_size(const sctp_auth_chklist_t * list) return (list->num_chunks); } -/* - * set the default list of chunks requiring AUTH - */ -void -sctp_auth_set_default_chunks(sctp_auth_chklist_t * list) -{ - (void)sctp_auth_add_chunk(SCTP_ASCONF, list); - (void)sctp_auth_add_chunk(SCTP_ASCONF_ACK, list); -} - /* * return the current number and list of required chunks caller must * guarantee ptr has space for up to 256 bytes diff --git a/sys/netinet/sctp_auth.h b/sys/netinet/sctp_auth.h index 535c0fc0de12..423a5cc50538 100644 --- a/sys/netinet/sctp_auth.h +++ b/sys/netinet/sctp_auth.h @@ -112,7 +112,6 @@ extern sctp_auth_chklist_t *sctp_copy_chunklist(sctp_auth_chklist_t * chklist); extern int sctp_auth_add_chunk(uint8_t chunk, sctp_auth_chklist_t * list); extern int sctp_auth_delete_chunk(uint8_t chunk, sctp_auth_chklist_t * list); extern size_t sctp_auth_get_chklist_size(const sctp_auth_chklist_t * list); -extern void sctp_auth_set_default_chunks(sctp_auth_chklist_t * list); extern int sctp_serialize_auth_chunks(const sctp_auth_chklist_t * list, uint8_t * ptr); diff --git a/sys/netinet/sctp_input.c b/sys/netinet/sctp_input.c index 8848b7e1b5bb..3af6710740d4 100644 --- a/sys/netinet/sctp_input.c +++ b/sys/netinet/sctp_input.c @@ -480,7 +480,7 @@ sctp_process_init_ack(struct mbuf *m, int iphlen, int offset, return (-1); } /* if the peer doesn't support asconf, flush the asconf queue */ - if (asoc->peer_supports_asconf == 0) { + if (asoc->asconf_supported == 0) { struct sctp_asconf_addr *param, *nparam; TAILQ_FOREACH_SAFE(param, &asoc->asconf_queue, next, nparam) { @@ -756,7 +756,7 @@ sctp_handle_nat_missing_state(struct sctp_tcb *stcb, * return 0 means we want you to proceed with the abort non-zero * means no abort processing */ - if (stcb->asoc.peer_supports_auth == 0) { + if (stcb->asoc.auth_supported == 0) { SCTPDBG(SCTP_DEBUG_INPUT2, "sctp_handle_nat_missing_state: Peer does not support AUTH, cannot send an asconf\n"); return (0); } @@ -1096,6 +1096,7 @@ sctp_process_unrecog_chunk(struct sctp_tcb *stcb, struct sctp_paramhdr *phdr, * Skip past the param header and then we will find the param that caused the * problem. There are a number of param's in a ASCONF OR the prsctp param * these will turn of specific features. + * XXX: Is this the right thing to do? */ static void sctp_process_unrecog_param(struct sctp_tcb *stcb, struct sctp_paramhdr *phdr) @@ -1117,14 +1118,14 @@ sctp_process_unrecog_param(struct sctp_tcb *stcb, struct sctp_paramhdr *phdr) case SCTP_ADD_IP_ADDRESS: case SCTP_DEL_IP_ADDRESS: case SCTP_SET_PRIM_ADDR: - stcb->asoc.peer_supports_asconf = 0; + stcb->asoc.asconf_supported = 0; break; case SCTP_SUCCESS_REPORT: case SCTP_ERROR_CAUSE_IND: SCTPDBG(SCTP_DEBUG_INPUT2, "Huh, the peer does not support success? or error cause?\n"); SCTPDBG(SCTP_DEBUG_INPUT2, "Turning off ASCONF to this strange peer\n"); - stcb->asoc.peer_supports_asconf = 0; + stcb->asoc.asconf_supported = 0; break; default: SCTPDBG(SCTP_DEBUG_INPUT2, @@ -2787,6 +2788,8 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset, inp->sctp_cmt_on_off = (*inp_p)->sctp_cmt_on_off; inp->ecn_supported = (*inp_p)->ecn_supported; inp->prsctp_supported = (*inp_p)->prsctp_supported; + inp->auth_supported = (*inp_p)->auth_supported; + inp->asconf_supported = (*inp_p)->asconf_supported; inp->reconfig_supported = (*inp_p)->reconfig_supported; inp->nrsack_supported = (*inp_p)->nrsack_supported; inp->pktdrop_supported = (*inp_p)->pktdrop_supported; @@ -2966,7 +2969,7 @@ sctp_handle_cookie_ack(struct sctp_cookie_ack_chunk *cp SCTP_UNUSED, * in flight) */ if ((sctp_is_feature_on(stcb->sctp_ep, SCTP_PCB_FLAGS_DO_ASCONF)) && - (stcb->asoc.peer_supports_asconf) && + (stcb->asoc.asconf_supported == 1) && (!TAILQ_EMPTY(&stcb->asoc.asconf_queue))) { #ifdef SCTP_TIMER_BASED_ASCONF sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, @@ -4439,7 +4442,7 @@ __attribute__((noinline)) */ if ((ch->chunk_type == SCTP_AUTHENTICATION) && (stcb == NULL) && - !SCTP_BASE_SYSCTL(sctp_auth_disable)) { + (inp->auth_supported == 1)) { /* save this chunk for later processing */ auth_skipped = 1; auth_offset = *offset; @@ -4706,7 +4709,7 @@ process_control_chunks: /* check to see if this chunk required auth, but isn't */ if ((stcb != NULL) && - !SCTP_BASE_SYSCTL(sctp_auth_disable) && + (stcb->asoc.auth_supported == 1) && sctp_auth_is_required_chunk(ch->chunk_type, stcb->asoc.local_auth_chunks) && !stcb->asoc.authenticated) { /* "silently" ignore */ @@ -5225,6 +5228,9 @@ process_control_chunks: return (NULL); } if (stcb) { + if (stcb->asoc.ecn_supported == 0) { + goto unknown_chunk; + } if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) { sctp_misc_ints(SCTP_THRESHOLD_CLEAR, stcb->asoc.overall_error_count, @@ -5250,6 +5256,9 @@ process_control_chunks: return (NULL); } if (stcb) { + if (stcb->asoc.ecn_supported == 0) { + goto unknown_chunk; + } if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) { sctp_misc_ints(SCTP_THRESHOLD_CLEAR, stcb->asoc.overall_error_count, @@ -5283,6 +5292,9 @@ process_control_chunks: SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_ASCONF\n"); /* He's alive so give him credit */ if (stcb) { + if (stcb->asoc.asconf_supported == 0) { + goto unknown_chunk; + } if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) { sctp_misc_ints(SCTP_THRESHOLD_CLEAR, stcb->asoc.overall_error_count, @@ -5307,6 +5319,9 @@ process_control_chunks: return (NULL); } if ((stcb) && netp && *netp) { + if (stcb->asoc.asconf_supported == 0) { + goto unknown_chunk; + } /* He's alive so give him credit */ if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) { sctp_misc_ints(SCTP_THRESHOLD_CLEAR, @@ -5336,6 +5351,9 @@ process_control_chunks: if (stcb) { int abort_flag = 0; + if (stcb->asoc.prsctp_supported == 0) { + goto unknown_chunk; + } stcb->asoc.overall_error_count = 0; if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) { sctp_misc_ints(SCTP_THRESHOLD_CLEAR, @@ -5391,12 +5409,7 @@ process_control_chunks: return (NULL); } if (stcb->asoc.reconfig_supported == 0) { - /* - * hmm, peer should have announced this, but - * we will turn it on since he is sending us - * a stream reset. - */ - stcb->asoc.reconfig_supported = 1; + goto unknown_chunk; } if (sctp_handle_stream_reset(stcb, m, *offset, ch)) { /* stop processing */ @@ -5416,18 +5429,17 @@ process_control_chunks: return (NULL); } if (ch && (stcb) && netp && (*netp)) { + if (stcb->asoc.pktdrop_supported == 0) { + goto unknown_chunk; + } sctp_handle_packet_dropped((struct sctp_pktdrop_chunk *)ch, stcb, *netp, min(chk_length, (sizeof(chunk_buf) - 4))); } break; - case SCTP_AUTHENTICATION: SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_AUTHENTICATION\n"); - if (SCTP_BASE_SYSCTL(sctp_auth_disable)) - goto unknown_chunk; - if (stcb == NULL) { /* save the first AUTH for later processing */ if (auth_skipped == 0) { @@ -5438,6 +5450,9 @@ process_control_chunks: /* skip this chunk (temporarily) */ goto next_chunk; } + if (stcb->asoc.auth_supported == 0) { + goto unknown_chunk; + } if ((chk_length < (sizeof(struct sctp_auth_chunk))) || (chk_length > (sizeof(struct sctp_auth_chunk) + SCTP_AUTH_DIGEST_LEN_MAX))) { @@ -5778,7 +5793,7 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset, int lengt * chunks */ if ((stcb != NULL) && - !SCTP_BASE_SYSCTL(sctp_auth_disable) && + (stcb->asoc.auth_supported == 1) && sctp_auth_is_required_chunk(SCTP_DATA, stcb->asoc.local_auth_chunks)) { /* "silently" ignore */ SCTP_STAT_INCR(sctps_recvauthmissing); @@ -5820,7 +5835,7 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset, int lengt */ if ((length > offset) && (stcb != NULL) && - !SCTP_BASE_SYSCTL(sctp_auth_disable) && + (stcb->asoc.auth_supported == 1) && sctp_auth_is_required_chunk(SCTP_DATA, stcb->asoc.local_auth_chunks) && !stcb->asoc.authenticated) { /* "silently" ignore */ diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c index 5165f5f805c3..b9b85733dfcd 100644 --- a/sys/netinet/sctp_output.c +++ b/sys/netinet/sctp_output.c @@ -4753,12 +4753,6 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked } chunk_len = (uint16_t) sizeof(struct sctp_init_chunk); padding_len = 0; - /* - * assume peer supports asconf in order to be able to queue local - * address changes while an INIT is in flight and before the assoc - * is established. - */ - stcb->asoc.peer_supports_asconf = 1; /* Now lets put the chunk header in place */ init = mtod(m, struct sctp_init_chunk *); /* now the chunk header */ @@ -4811,31 +4805,34 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked /* And now tell the peer which extensions we support */ num_ext = 0; pr_supported = (struct sctp_supported_chunk_types_param *)(mtod(m, caddr_t)+chunk_len); - pr_supported->ph.param_type = htons(SCTP_SUPPORTED_CHUNK_EXT); - pr_supported->chunk_types[num_ext++] = SCTP_ASCONF; - pr_supported->chunk_types[num_ext++] = SCTP_ASCONF_ACK; if (stcb->asoc.prsctp_supported == 1) { pr_supported->chunk_types[num_ext++] = SCTP_FORWARD_CUM_TSN; } - if (stcb->asoc.pktdrop_supported == 1) { - pr_supported->chunk_types[num_ext++] = SCTP_PACKET_DROPPED; + if (stcb->asoc.auth_supported == 1) { + pr_supported->chunk_types[num_ext++] = SCTP_AUTHENTICATION; + } + if (stcb->asoc.asconf_supported == 1) { + pr_supported->chunk_types[num_ext++] = SCTP_ASCONF; + pr_supported->chunk_types[num_ext++] = SCTP_ASCONF_ACK; } if (stcb->asoc.reconfig_supported == 1) { pr_supported->chunk_types[num_ext++] = SCTP_STREAM_RESET; } - if (!SCTP_BASE_SYSCTL(sctp_auth_disable)) { - pr_supported->chunk_types[num_ext++] = SCTP_AUTHENTICATION; - } if (stcb->asoc.nrsack_supported == 1) { pr_supported->chunk_types[num_ext++] = SCTP_NR_SELECTIVE_ACK; } - parameter_len = (uint16_t) sizeof(struct sctp_supported_chunk_types_param) + num_ext; - pr_supported->ph.param_length = htons(parameter_len); - padding_len = SCTP_SIZE32(parameter_len) - parameter_len; - chunk_len += parameter_len; - + if (stcb->asoc.pktdrop_supported == 1) { + pr_supported->chunk_types[num_ext++] = SCTP_PACKET_DROPPED; + } + if (num_ext > 0) { + parameter_len = (uint16_t) sizeof(struct sctp_supported_chunk_types_param) + num_ext; + pr_supported->ph.param_type = htons(SCTP_SUPPORTED_CHUNK_EXT); + pr_supported->ph.param_length = htons(parameter_len); + padding_len = SCTP_SIZE32(parameter_len) - parameter_len; + chunk_len += parameter_len; + } /* add authentication parameters */ - if (!SCTP_BASE_SYSCTL(sctp_auth_disable)) { + if (stcb->asoc.auth_supported) { /* attach RANDOM parameter, if available */ if (stcb->asoc.authinfo.random != NULL) { struct sctp_auth_random *randp; @@ -4853,8 +4850,7 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked chunk_len += parameter_len; } /* add HMAC_ALGO parameter */ - if ((stcb->asoc.local_hmacs != NULL) && - (stcb->asoc.local_hmacs->num_algo > 0)) { + if (stcb->asoc.local_hmacs != NULL) { struct sctp_auth_hmac_algo *hmacs; if (padding_len > 0) { @@ -4872,7 +4868,7 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked chunk_len += parameter_len; } /* add CHUNKS parameter */ - if (sctp_auth_get_chklist_size(stcb->asoc.local_auth_chunks) > 0) { + if (stcb->asoc.local_auth_chunks != NULL) { struct sctp_auth_chunk_list *chunks; if (padding_len > 0) { @@ -5917,35 +5913,41 @@ do_a_abort: /* And now tell the peer which extensions we support */ num_ext = 0; pr_supported = (struct sctp_supported_chunk_types_param *)(mtod(m, caddr_t)+chunk_len); - pr_supported->ph.param_type = htons(SCTP_SUPPORTED_CHUNK_EXT); - pr_supported->chunk_types[num_ext++] = SCTP_ASCONF; - pr_supported->chunk_types[num_ext++] = SCTP_ASCONF_ACK; if (((asoc != NULL) && (asoc->prsctp_supported == 1)) || ((asoc == NULL) && (inp->prsctp_supported == 1))) { pr_supported->chunk_types[num_ext++] = SCTP_FORWARD_CUM_TSN; } - if (((asoc != NULL) && (asoc->pktdrop_supported == 1)) || - ((asoc == NULL) && (inp->pktdrop_supported == 1))) { - pr_supported->chunk_types[num_ext++] = SCTP_PACKET_DROPPED; + if (((asoc != NULL) && (asoc->auth_supported == 1)) || + ((asoc == NULL) && (inp->auth_supported == 1))) { + pr_supported->chunk_types[num_ext++] = SCTP_AUTHENTICATION; + } + if (((asoc != NULL) && (asoc->asconf_supported == 1)) || + ((asoc == NULL) && (inp->asconf_supported == 1))) { + pr_supported->chunk_types[num_ext++] = SCTP_ASCONF; + pr_supported->chunk_types[num_ext++] = SCTP_ASCONF_ACK; } if (((asoc != NULL) && (asoc->reconfig_supported == 1)) || ((asoc == NULL) && (inp->reconfig_supported == 1))) { pr_supported->chunk_types[num_ext++] = SCTP_STREAM_RESET; } - if (!SCTP_BASE_SYSCTL(sctp_auth_disable)) { - pr_supported->chunk_types[num_ext++] = SCTP_AUTHENTICATION; - } if (((asoc != NULL) && (asoc->nrsack_supported == 1)) || ((asoc == NULL) && (inp->nrsack_supported == 1))) { pr_supported->chunk_types[num_ext++] = SCTP_NR_SELECTIVE_ACK; } - parameter_len = (uint16_t) sizeof(struct sctp_supported_chunk_types_param) + num_ext; - pr_supported->ph.param_length = htons(parameter_len); - padding_len = SCTP_SIZE32(parameter_len) - parameter_len; - chunk_len += parameter_len; - + if (((asoc != NULL) && (asoc->pktdrop_supported == 1)) || + ((asoc == NULL) && (inp->pktdrop_supported == 1))) { + pr_supported->chunk_types[num_ext++] = SCTP_PACKET_DROPPED; + } + if (num_ext > 0) { + parameter_len = (uint16_t) sizeof(struct sctp_supported_chunk_types_param) + num_ext; + pr_supported->ph.param_type = htons(SCTP_SUPPORTED_CHUNK_EXT); + pr_supported->ph.param_length = htons(parameter_len); + padding_len = SCTP_SIZE32(parameter_len) - parameter_len; + chunk_len += parameter_len; + } /* add authentication parameters */ - if (!SCTP_BASE_SYSCTL(sctp_auth_disable)) { + if (((asoc != NULL) && (asoc->auth_supported == 1)) || + ((asoc == NULL) && (inp->auth_supported == 1))) { struct sctp_auth_random *randp; struct sctp_auth_hmac_algo *hmacs; struct sctp_auth_chunk_list *chunks; @@ -7806,7 +7808,6 @@ sctp_med_chunk_output(struct sctp_inpcb *inp, *num_out = 0; auth_keyid = stcb->asoc.authinfo.active_keyid; - if ((asoc->state & SCTP_STATE_SHUTDOWN_PENDING) || (asoc->state & SCTP_STATE_SHUTDOWN_RECEIVED) || (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR))) { @@ -13417,12 +13418,7 @@ sctp_add_auth_chunk(struct mbuf *m, struct mbuf **m_end, (stcb == NULL)) return (m); - /* sysctl disabled auth? */ - if (SCTP_BASE_SYSCTL(sctp_auth_disable)) - return (m); - - /* peer doesn't do auth... */ - if (!stcb->asoc.peer_supports_auth) { + if (stcb->asoc.auth_supported == 0) { return (m); } /* does the requested chunk require auth? */ diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c index 67ee1faf79ed..fdd70ee3d46a 100644 --- a/sys/netinet/sctp_pcb.c +++ b/sys/netinet/sctp_pcb.c @@ -2485,6 +2485,12 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id) inp->sctp_cmt_on_off = SCTP_BASE_SYSCTL(sctp_cmt_on_off); inp->ecn_supported = (uint8_t) SCTP_BASE_SYSCTL(sctp_ecn_enable); inp->prsctp_supported = (uint8_t) SCTP_BASE_SYSCTL(sctp_pr_enable); + if (SCTP_BASE_SYSCTL(sctp_auth_disable)) { + inp->auth_supported = 0; + } else { + inp->auth_supported = 1; + } + inp->asconf_supported = (uint8_t) SCTP_BASE_SYSCTL(sctp_asconf_enable); inp->reconfig_supported = (uint8_t) SCTP_BASE_SYSCTL(sctp_reconfig_enable); inp->nrsack_supported = (uint8_t) SCTP_BASE_SYSCTL(sctp_nrsack_enable); inp->pktdrop_supported = (uint8_t) SCTP_BASE_SYSCTL(sctp_pktdrop_enable); @@ -2651,12 +2657,15 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id) */ m->local_hmacs = sctp_default_supported_hmaclist(); m->local_auth_chunks = sctp_alloc_chunklist(); + if (inp->asconf_supported) { + sctp_auth_add_chunk(SCTP_ASCONF, m->local_auth_chunks); + sctp_auth_add_chunk(SCTP_ASCONF_ACK, m->local_auth_chunks); + } m->default_dscp = 0; #ifdef INET6 m->default_flowlabel = 0; #endif m->port = 0; /* encapsulation disabled by default */ - sctp_auth_set_default_chunks(m->local_auth_chunks); LIST_INIT(&m->shared_keys); /* add default NULL key as key id 0 */ null_key = sctp_alloc_sharedkey(); @@ -6085,11 +6094,14 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, sctp_key_t *new_key; uint32_t keylen; int got_random = 0, got_hmacs = 0, got_chklist = 0; - uint8_t ecn_supported; - uint8_t prsctp_supported; - uint8_t reconfig_supported; - uint8_t nrsack_supported; - uint8_t pktdrop_supported; + uint8_t peer_supports_ecn; + uint8_t peer_supports_prsctp; + uint8_t peer_supports_auth; + uint8_t peer_supports_asconf; + uint8_t peer_supports_asconf_ack; + uint8_t peer_supports_reconfig; + uint8_t peer_supports_nrsack; + uint8_t peer_supports_pktdrop; #ifdef INET struct sockaddr_in sin; @@ -6118,11 +6130,14 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, } else { sa = src; } - ecn_supported = 0; - prsctp_supported = 0; - reconfig_supported = 0; - nrsack_supported = 0; - pktdrop_supported = 0; + peer_supports_ecn = 0; + peer_supports_prsctp = 0; + peer_supports_auth = 0; + peer_supports_asconf = 0; + peer_supports_asconf = 0; + peer_supports_reconfig = 0; + peer_supports_nrsack = 0; + peer_supports_pktdrop = 0; TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { /* mark all addresses that we have currently on the list */ net->dest_state |= SCTP_ADDR_NOT_IN_ASSOC; @@ -6172,12 +6187,6 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, /* the assoc was freed? */ return (-4); } - /* - * peer must explicitly turn this on. This may have been initialized - * to be "on" in order to allow local addr changes while INIT's are - * in flight. - */ - stcb->asoc.peer_supports_asconf = 0; /* now we must go through each of the params. */ phdr = sctp_get_next_param(m, offset, &parm_buf, sizeof(parm_buf)); while (phdr) { @@ -6371,7 +6380,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, } else #endif if (ptype == SCTP_ECN_CAPABLE) { - ecn_supported = 1; + peer_supports_ecn = 1; } else if (ptype == SCTP_ULP_ADAPTATION) { if (stcb->asoc.state != SCTP_STATE_OPEN) { struct sctp_adaptation_layer_indication ai, @@ -6395,7 +6404,9 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, #endif - stcb->asoc.peer_supports_asconf = 1; + if (stcb->asoc.asconf_supported == 0) { + return (-100); + } if (plen > sizeof(lstore)) { return (-23); } @@ -6447,7 +6458,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, stcb->asoc.peer_supports_nat = 1; } else if (ptype == SCTP_PRSCTP_SUPPORTED) { /* Peer supports pr-sctp */ - prsctp_supported = 1; + peer_supports_prsctp = 1; } else if (ptype == SCTP_SUPPORTED_CHUNK_EXT) { /* A supported extension chunk */ struct sctp_supported_chunk_types_param *pr_supported; @@ -6459,30 +6470,29 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, if (phdr == NULL) { return (-25); } - stcb->asoc.peer_supports_asconf = 0; - stcb->asoc.peer_supports_auth = 0; pr_supported = (struct sctp_supported_chunk_types_param *)phdr; num_ent = plen - sizeof(struct sctp_paramhdr); for (i = 0; i < num_ent; i++) { switch (pr_supported->chunk_types[i]) { case SCTP_ASCONF: + peer_supports_asconf = 1; case SCTP_ASCONF_ACK: - stcb->asoc.peer_supports_asconf = 1; + peer_supports_asconf_ack = 1; break; case SCTP_FORWARD_CUM_TSN: - prsctp_supported = 1; + peer_supports_prsctp = 1; break; case SCTP_PACKET_DROPPED: - pktdrop_supported = 1; + peer_supports_pktdrop = 1; break; case SCTP_NR_SELECTIVE_ACK: - nrsack_supported = 1; + peer_supports_nrsack = 1; break; case SCTP_STREAM_RESET: - reconfig_supported = 1; + peer_supports_reconfig = 1; break; case SCTP_AUTHENTICATION: - stcb->asoc.peer_supports_auth = 1; + peer_supports_auth = 1; break; default: /* one I have not learned yet */ @@ -6619,25 +6629,47 @@ next_param: } } } - stcb->asoc.ecn_supported &= ecn_supported; - stcb->asoc.prsctp_supported &= prsctp_supported; - stcb->asoc.reconfig_supported &= reconfig_supported; - stcb->asoc.nrsack_supported &= nrsack_supported; - stcb->asoc.pktdrop_supported &= pktdrop_supported; - /* validate authentication required parameters */ - if (got_random && got_hmacs) { - stcb->asoc.peer_supports_auth = 1; - } else { - stcb->asoc.peer_supports_auth = 0; + if ((stcb->asoc.ecn_supported == 1) && + (peer_supports_ecn == 0)) { + stcb->asoc.ecn_supported = 0; } - if (!stcb->asoc.peer_supports_auth && got_chklist) { + if ((stcb->asoc.prsctp_supported == 1) && + (peer_supports_prsctp == 0)) { + stcb->asoc.prsctp_supported = 0; + } + if ((stcb->asoc.auth_supported == 1) && + ((peer_supports_auth == 0) || + (got_random == 0) || (got_hmacs == 0))) { + stcb->asoc.auth_supported = 0; + } + if ((stcb->asoc.asconf_supported == 1) && + ((peer_supports_asconf == 0) || (peer_supports_asconf_ack == 0) || + (stcb->asoc.auth_supported == 0) || + (saw_asconf == 0) || (saw_asconf_ack == 0))) { + stcb->asoc.asconf_supported = 0; + } + if ((stcb->asoc.reconfig_supported == 1) && + (peer_supports_reconfig == 0)) { + stcb->asoc.reconfig_supported = 0; + } + if ((stcb->asoc.nrsack_supported == 1) && + (peer_supports_nrsack == 0)) { + stcb->asoc.nrsack_supported = 0; + } + if ((stcb->asoc.pktdrop_supported == 1) && + (peer_supports_pktdrop == 0)) { + stcb->asoc.pktdrop_supported = 0; + } + /* validate authentication required parameters */ + if ((peer_supports_auth == 0) && (got_chklist == 1)) { /* peer does not support auth but sent a chunks list? */ return (-31); } - if (stcb->asoc.peer_supports_asconf && !stcb->asoc.peer_supports_auth) { + if ((peer_supports_asconf == 1) && (peer_supports_auth == 0)) { /* peer supports asconf but not auth? */ return (-32); - } else if ((stcb->asoc.peer_supports_asconf) && (stcb->asoc.peer_supports_auth) && + } else if ((peer_supports_asconf == 1) && + (peer_supports_auth == 1) && ((saw_asconf == 0) || (saw_asconf_ack == 0))) { return (-33); } diff --git a/sys/netinet/sctp_pcb.h b/sys/netinet/sctp_pcb.h index 694148ad1261..c9183b1d8207 100644 --- a/sys/netinet/sctp_pcb.h +++ b/sys/netinet/sctp_pcb.h @@ -408,6 +408,8 @@ struct sctp_inpcb { uint32_t sctp_cmt_on_off; uint8_t ecn_supported; uint8_t prsctp_supported; + uint8_t auth_supported; + uint8_t asconf_supported; uint8_t reconfig_supported; uint8_t nrsack_supported; uint8_t pktdrop_supported; diff --git a/sys/netinet/sctp_peeloff.c b/sys/netinet/sctp_peeloff.c index ed4ef49145ba..cf41d29f71cd 100644 --- a/sys/netinet/sctp_peeloff.c +++ b/sys/netinet/sctp_peeloff.c @@ -120,6 +120,8 @@ sctp_do_peeloff(struct socket *head, struct socket *so, sctp_assoc_t assoc_id) n_inp->sctp_cmt_on_off = inp->sctp_cmt_on_off; n_inp->ecn_supported = inp->ecn_supported; n_inp->prsctp_supported = inp->prsctp_supported; + n_inp->auth_supported = inp->auth_supported; + n_inp->asconf_supported = inp->asconf_supported; n_inp->reconfig_supported = inp->reconfig_supported; n_inp->nrsack_supported = inp->nrsack_supported; n_inp->pktdrop_supported = inp->pktdrop_supported; diff --git a/sys/netinet/sctp_structs.h b/sys/netinet/sctp_structs.h index 5c63f8509550..9be861493c67 100644 --- a/sys/netinet/sctp_structs.h +++ b/sys/netinet/sctp_structs.h @@ -1153,6 +1153,8 @@ struct sctp_association { /* Flags whether an extension is supported or not */ uint8_t ecn_supported; uint8_t prsctp_supported; + uint8_t auth_supported; + uint8_t asconf_supported; uint8_t reconfig_supported; uint8_t nrsack_supported; uint8_t pktdrop_supported; @@ -1160,10 +1162,6 @@ struct sctp_association { /* Did the peer make the stream config (add out) request */ uint8_t peer_req_out; - /* flag to indicate if peer can do asconf */ - uint8_t peer_supports_asconf; - /* peer authentication support flag */ - uint8_t peer_supports_auth; uint8_t local_strreset_support; uint8_t peer_supports_nat; diff --git a/sys/netinet/sctp_sysctl.c b/sys/netinet/sctp_sysctl.c index 8dfda5627fb9..48706484efab 100644 --- a/sys/netinet/sctp_sysctl.c +++ b/sys/netinet/sctp_sysctl.c @@ -55,6 +55,8 @@ sctp_init_sysctls() SCTP_BASE_SYSCTL(sctp_multiple_asconfs) = SCTPCTL_MULTIPLEASCONFS_DEFAULT; SCTP_BASE_SYSCTL(sctp_ecn_enable) = SCTPCTL_ECN_ENABLE_DEFAULT; SCTP_BASE_SYSCTL(sctp_pr_enable) = SCTPCTL_PR_ENABLE_DEFAULT; + SCTP_BASE_SYSCTL(sctp_auth_disable) = SCTPCTL_AUTH_DISABLE_DEFAULT; + SCTP_BASE_SYSCTL(sctp_asconf_enable) = SCTPCTL_ASCONF_ENABLE_DEFAULT; SCTP_BASE_SYSCTL(sctp_reconfig_enable) = SCTPCTL_RECONFIG_ENABLE_DEFAULT; SCTP_BASE_SYSCTL(sctp_nrsack_enable) = SCTPCTL_NRSACK_ENABLE_DEFAULT; SCTP_BASE_SYSCTL(sctp_pktdrop_enable) = SCTPCTL_PKTDROP_ENABLE_DEFAULT; @@ -90,7 +92,6 @@ sctp_init_sysctls() SCTP_BASE_SYSCTL(sctp_cmt_on_off) = SCTPCTL_CMT_ON_OFF_DEFAULT; SCTP_BASE_SYSCTL(sctp_cmt_use_dac) = SCTPCTL_CMT_USE_DAC_DEFAULT; SCTP_BASE_SYSCTL(sctp_use_cwnd_based_maxburst) = SCTPCTL_CWND_MAXBURST_DEFAULT; - SCTP_BASE_SYSCTL(sctp_auth_disable) = SCTPCTL_AUTH_DISABLE_DEFAULT; SCTP_BASE_SYSCTL(sctp_nat_friendly) = SCTPCTL_NAT_FRIENDLY_DEFAULT; SCTP_BASE_SYSCTL(sctp_L2_abc_variable) = SCTPCTL_ABC_L_VAR_DEFAULT; SCTP_BASE_SYSCTL(sctp_mbuf_threshold_count) = SCTPCTL_MAX_CHAINED_MBUFS_DEFAULT; @@ -638,7 +639,6 @@ sysctl_sctp_check(SYSCTL_HANDLER_ARGS) RANGECHK(SCTP_BASE_SYSCTL(sctp_cmt_on_off), SCTPCTL_CMT_ON_OFF_MIN, SCTPCTL_CMT_ON_OFF_MAX); RANGECHK(SCTP_BASE_SYSCTL(sctp_cmt_use_dac), SCTPCTL_CMT_USE_DAC_MIN, SCTPCTL_CMT_USE_DAC_MAX); RANGECHK(SCTP_BASE_SYSCTL(sctp_use_cwnd_based_maxburst), SCTPCTL_CWND_MAXBURST_MIN, SCTPCTL_CWND_MAXBURST_MAX); - RANGECHK(SCTP_BASE_SYSCTL(sctp_auth_disable), SCTPCTL_AUTH_DISABLE_MIN, SCTPCTL_AUTH_DISABLE_MAX); RANGECHK(SCTP_BASE_SYSCTL(sctp_nat_friendly), SCTPCTL_NAT_FRIENDLY_MIN, SCTPCTL_NAT_FRIENDLY_MAX); RANGECHK(SCTP_BASE_SYSCTL(sctp_L2_abc_variable), SCTPCTL_ABC_L_VAR_MIN, SCTPCTL_ABC_L_VAR_MAX); RANGECHK(SCTP_BASE_SYSCTL(sctp_mbuf_threshold_count), SCTPCTL_MAX_CHAINED_MBUFS_MIN, SCTPCTL_MAX_CHAINED_MBUFS_MAX); @@ -677,6 +677,56 @@ sysctl_sctp_check(SYSCTL_HANDLER_ARGS) return (error); } +static int +sysctl_sctp_auth_check(SYSCTL_HANDLER_ARGS) +{ + int error; + + error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req); + if (error == 0) { + if (SCTP_BASE_SYSCTL(sctp_auth_disable) < SCTPCTL_AUTH_DISABLE_MIN) { + SCTP_BASE_SYSCTL(sctp_auth_disable) = SCTPCTL_AUTH_DISABLE_MIN; + } + if (SCTP_BASE_SYSCTL(sctp_auth_disable) > SCTPCTL_AUTH_DISABLE_MAX) { + SCTP_BASE_SYSCTL(sctp_auth_disable) = SCTPCTL_AUTH_DISABLE_MAX; + } + if ((SCTP_BASE_SYSCTL(sctp_auth_disable) == 1) && + (SCTP_BASE_SYSCTL(sctp_asconf_enable) == 1)) { + /* + * You can't disable AUTH with disabling ASCONF + * first + */ + SCTP_BASE_SYSCTL(sctp_auth_disable) = 0; + } + } + return (error); +} + +static int +sysctl_sctp_asconf_check(SYSCTL_HANDLER_ARGS) +{ + int error; + + error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req); + if (error == 0) { + if (SCTP_BASE_SYSCTL(sctp_asconf_enable) < SCTPCTL_ASCONF_ENABLE_MIN) { + SCTP_BASE_SYSCTL(sctp_asconf_enable) = SCTPCTL_ASCONF_ENABLE_MIN; + } + if (SCTP_BASE_SYSCTL(sctp_asconf_enable) > SCTPCTL_ASCONF_ENABLE_MAX) { + SCTP_BASE_SYSCTL(sctp_asconf_enable) = SCTPCTL_ASCONF_ENABLE_MAX; + } + if ((SCTP_BASE_SYSCTL(sctp_asconf_enable) == 1) && + (SCTP_BASE_SYSCTL(sctp_auth_disable) == 1)) { + /* + * You can't enable ASCONF without enabling AUTH + * first + */ + SCTP_BASE_SYSCTL(sctp_asconf_enable) = 0; + } + } + return (error); +} + #if defined(__FreeBSD__) && defined(SMP) && defined(SCTP_USE_PERCPU_STAT) static int sysctl_stat_get(SYSCTL_HANDLER_ARGS) @@ -869,6 +919,14 @@ SYSCTL_VNET_PROC(_net_inet_sctp, OID_AUTO, pr_enable, CTLTYPE_UINT | CTLFLAG_RW, &SCTP_BASE_SYSCTL(sctp_pr_enable), 0, sysctl_sctp_check, "IU", SCTPCTL_PR_ENABLE_DESC); +SYSCTL_VNET_PROC(_net_inet_sctp, OID_AUTO, auth_disable, CTLTYPE_UINT | CTLFLAG_RW, + &SCTP_BASE_SYSCTL(sctp_auth_disable), 0, sysctl_sctp_auth_check, "IU", + SCTPCTL_AUTH_DISABLE_DESC); + +SYSCTL_VNET_PROC(_net_inet_sctp, OID_AUTO, asconf_enable, CTLTYPE_UINT | CTLFLAG_RW, + &SCTP_BASE_SYSCTL(sctp_asconf_enable), 0, sysctl_sctp_asconf_check, "IU", + SCTPCTL_ASCONF_ENABLE_DESC); + SYSCTL_VNET_PROC(_net_inet_sctp, OID_AUTO, reconfig_enable, CTLTYPE_UINT | CTLFLAG_RW, &SCTP_BASE_SYSCTL(sctp_reconfig_enable), 0, sysctl_sctp_check, "IU", SCTPCTL_RECONFIG_ENABLE_DESC); @@ -1010,10 +1068,6 @@ SYSCTL_VNET_PROC(_net_inet_sctp, OID_AUTO, cwnd_maxburst, CTLTYPE_UINT | CTLFLAG &SCTP_BASE_SYSCTL(sctp_use_cwnd_based_maxburst), 0, sysctl_sctp_check, "IU", SCTPCTL_CWND_MAXBURST_DESC); -SYSCTL_VNET_PROC(_net_inet_sctp, OID_AUTO, auth_disable, CTLTYPE_UINT | CTLFLAG_RW, - &SCTP_BASE_SYSCTL(sctp_auth_disable), 0, sysctl_sctp_check, "IU", - SCTPCTL_AUTH_DISABLE_DESC); - SYSCTL_VNET_PROC(_net_inet_sctp, OID_AUTO, nat_friendly, CTLTYPE_UINT | CTLFLAG_RW, &SCTP_BASE_SYSCTL(sctp_nat_friendly), 0, sysctl_sctp_check, "IU", SCTPCTL_NAT_FRIENDLY_DESC); diff --git a/sys/netinet/sctp_sysctl.h b/sys/netinet/sctp_sysctl.h index bcf270f36c08..9e457633e02b 100644 --- a/sys/netinet/sctp_sysctl.h +++ b/sys/netinet/sctp_sysctl.h @@ -46,6 +46,8 @@ struct sctp_sysctl { uint32_t sctp_multiple_asconfs; uint32_t sctp_ecn_enable; uint32_t sctp_pr_enable; + uint32_t sctp_auth_disable; + uint32_t sctp_asconf_enable; uint32_t sctp_reconfig_enable; uint32_t sctp_nrsack_enable; uint32_t sctp_pktdrop_enable; @@ -81,7 +83,6 @@ struct sctp_sysctl { uint32_t sctp_cmt_on_off; uint32_t sctp_cmt_use_dac; uint32_t sctp_use_cwnd_based_maxburst; - uint32_t sctp_auth_disable; uint32_t sctp_nat_friendly; uint32_t sctp_L2_abc_variable; uint32_t sctp_mbuf_threshold_count; @@ -162,6 +163,18 @@ struct sctp_sysctl { #define SCTPCTL_PR_ENABLE_MAX 1 #define SCTPCTL_PR_ENABLE_DEFAULT 1 +/* auth_disable: Disable SCTP AUTH function */ +#define SCTPCTL_AUTH_DISABLE_DESC "Disable SCTP AUTH function" +#define SCTPCTL_AUTH_DISABLE_MIN 0 +#define SCTPCTL_AUTH_DISABLE_MAX 1 +#define SCTPCTL_AUTH_DISABLE_DEFAULT 0 + +/* asconf_enable: Enable SCTP ASCONF */ +#define SCTPCTL_ASCONF_ENABLE_DESC "Enable SCTP ASCONF" +#define SCTPCTL_ASCONF_ENABLE_MIN 0 +#define SCTPCTL_ASCONF_ENABLE_MAX 1 +#define SCTPCTL_ASCONF_ENABLE_DEFAULT 1 + /* reconfig_enable: Enable SCTP RE-CONFIG */ #define SCTPCTL_RECONFIG_ENABLE_DESC "Enable SCTP RE-CONFIG" #define SCTPCTL_RECONFIG_ENABLE_MIN 0 @@ -379,12 +392,6 @@ struct sctp_sysctl { #define SCTPCTL_CWND_MAXBURST_MAX 1 #define SCTPCTL_CWND_MAXBURST_DEFAULT 1 -/* auth_disable: Disable SCTP AUTH function */ -#define SCTPCTL_AUTH_DISABLE_DESC "Disable SCTP AUTH function" -#define SCTPCTL_AUTH_DISABLE_MIN 0 -#define SCTPCTL_AUTH_DISABLE_MAX 1 -#define SCTPCTL_AUTH_DISABLE_DEFAULT 0 - /* nat_friendly: SCTP NAT friendly operation */ #define SCTPCTL_NAT_FRIENDLY_DESC "SCTP NAT friendly operation" #define SCTPCTL_NAT_FRIENDLY_MIN 0 diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c index 01f5376c9a3e..1d49ef591567 100644 --- a/sys/netinet/sctp_usrreq.c +++ b/sys/netinet/sctp_usrreq.c @@ -3348,6 +3348,60 @@ flags_out: } break; } + case SCTP_AUTH_SUPPORTED: + { + struct sctp_assoc_value *av; + + SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); + SCTP_FIND_STCB(inp, stcb, av->assoc_id); + + if (stcb) { + av->assoc_value = stcb->asoc.auth_supported; + SCTP_TCB_UNLOCK(stcb); + } else { + if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || + (av->assoc_id == SCTP_FUTURE_ASSOC)) { + SCTP_INP_RLOCK(inp); + av->assoc_value = inp->auth_supported; + SCTP_INP_RUNLOCK(inp); + } else { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); + error = EINVAL; + } + } + if (error == 0) { + *optsize = sizeof(struct sctp_assoc_value); + } + break; + } + case SCTP_ASCONF_SUPPORTED: + { + struct sctp_assoc_value *av; + + SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); + SCTP_FIND_STCB(inp, stcb, av->assoc_id); + + if (stcb) { + av->assoc_value = stcb->asoc.asconf_supported; + SCTP_TCB_UNLOCK(stcb); + } else { + if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || + (av->assoc_id == SCTP_FUTURE_ASSOC)) { + SCTP_INP_RLOCK(inp); + av->assoc_value = inp->asconf_supported; + SCTP_INP_RUNLOCK(inp); + } else { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); + error = EINVAL; + } + } + if (error == 0) { + *optsize = sizeof(struct sctp_assoc_value); + } + break; + } case SCTP_RECONFIG_SUPPORTED: { struct sctp_assoc_value *av; @@ -6050,6 +6104,92 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, } break; } + case SCTP_AUTH_SUPPORTED: + { + struct sctp_assoc_value *av; + + SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); + SCTP_FIND_STCB(inp, stcb, av->assoc_id); + + if (stcb) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); + error = EINVAL; + SCTP_TCB_UNLOCK(stcb); + } else { + if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || + (av->assoc_id == SCTP_FUTURE_ASSOC)) { + if ((av->assoc_value == 0) && + (inp->asconf_supported == 1)) { + /* + * AUTH is required for + * ASCONF + */ + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); + error = EINVAL; + } else { + SCTP_INP_WLOCK(inp); + if (av->assoc_value == 0) { + inp->auth_supported = 0; + } else { + inp->auth_supported = 1; + } + SCTP_INP_WUNLOCK(inp); + } + } else { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); + error = EINVAL; + } + } + break; + } + case SCTP_ASCONF_SUPPORTED: + { + struct sctp_assoc_value *av; + + SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); + SCTP_FIND_STCB(inp, stcb, av->assoc_id); + + if (stcb) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); + error = EINVAL; + SCTP_TCB_UNLOCK(stcb); + } else { + if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || + (av->assoc_id == SCTP_FUTURE_ASSOC)) { + if ((av->assoc_value != 0) && + (inp->auth_supported == 0)) { + /* + * AUTH is required for + * ASCONF + */ + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); + error = EINVAL; + } else { + SCTP_INP_WLOCK(inp); + if (av->assoc_value == 0) { + inp->asconf_supported = 0; + sctp_auth_delete_chunk(SCTP_ASCONF, + inp->sctp_ep.local_auth_chunks); + sctp_auth_delete_chunk(SCTP_ASCONF_ACK, + inp->sctp_ep.local_auth_chunks); + } else { + inp->asconf_supported = 1; + sctp_auth_add_chunk(SCTP_ASCONF, + inp->sctp_ep.local_auth_chunks); + sctp_auth_add_chunk(SCTP_ASCONF_ACK, + inp->sctp_ep.local_auth_chunks); + } + SCTP_INP_WUNLOCK(inp); + } + } else { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); + error = EINVAL; + } + } + break; + } case SCTP_RECONFIG_SUPPORTED: { struct sctp_assoc_value *av; diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c index 8c2ec4864f30..d2a1f8f16a48 100644 --- a/sys/netinet/sctputil.c +++ b/sys/netinet/sctputil.c @@ -906,6 +906,8 @@ sctp_init_asoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, asoc->sctp_cmt_on_off = inp->sctp_cmt_on_off; asoc->ecn_supported = inp->ecn_supported; asoc->prsctp_supported = inp->prsctp_supported; + asoc->auth_supported = inp->auth_supported; + asoc->asconf_supported = inp->asconf_supported; asoc->reconfig_supported = inp->reconfig_supported; asoc->nrsack_supported = inp->nrsack_supported; asoc->pktdrop_supported = inp->pktdrop_supported; @@ -2622,17 +2624,17 @@ sctp_notify_assoc_change(uint16_t state, struct sctp_tcb *stcb, if (notif_len > sizeof(struct sctp_assoc_change)) { if ((state == SCTP_COMM_UP) || (state == SCTP_RESTART)) { i = 0; - if (stcb->asoc.prsctp_supported) { + if (stcb->asoc.prsctp_supported == 1) { sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_PR; } - if (stcb->asoc.peer_supports_auth) { + if (stcb->asoc.auth_supported == 1) { sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_AUTH; } - if (stcb->asoc.peer_supports_asconf) { + if (stcb->asoc.asconf_supported == 1) { sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_ASCONF; } sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_MULTIBUF; - if (stcb->asoc.reconfig_supported) { + if (stcb->asoc.reconfig_supported == 1) { sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_RE_CONFIG; } sac->sac_length += i; @@ -3541,7 +3543,7 @@ sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb, if (stcb->asoc.adaptation_needed && (stcb->asoc.adaptation_sent == 0)) { sctp_notify_adaptation_layer(stcb); } - if (stcb->asoc.peer_supports_auth == 0) { + if (stcb->asoc.auth_supported == 0) { sctp_ulp_notify(SCTP_NOTIFY_NO_PEER_AUTH, stcb, 0, NULL, so_locked); } @@ -3615,7 +3617,7 @@ sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb, break; case SCTP_NOTIFY_ASSOC_RESTART: sctp_notify_assoc_change(SCTP_RESTART, stcb, error, NULL, 0, so_locked); - if (stcb->asoc.peer_supports_auth == 0) { + if (stcb->asoc.auth_supported == 0) { sctp_ulp_notify(SCTP_NOTIFY_NO_PEER_AUTH, stcb, 0, NULL, so_locked); }