diff options
Diffstat (limited to 'sys/netinet')
-rw-r--r-- | sys/netinet/sctp.h | 2 | ||||
-rw-r--r-- | sys/netinet/sctp_asconf.c | 14 | ||||
-rw-r--r-- | sys/netinet/sctp_auth.c | 2 | ||||
-rw-r--r-- | sys/netinet/sctp_constants.h | 13 | ||||
-rw-r--r-- | sys/netinet/sctp_header.h | 1 | ||||
-rw-r--r-- | sys/netinet/sctp_indata.c | 58 | ||||
-rw-r--r-- | sys/netinet/sctp_input.c | 167 | ||||
-rw-r--r-- | sys/netinet/sctp_os.h | 1 | ||||
-rw-r--r-- | sys/netinet/sctp_os_bsd.h | 21 | ||||
-rw-r--r-- | sys/netinet/sctp_output.c | 263 | ||||
-rw-r--r-- | sys/netinet/sctp_pcb.c | 119 | ||||
-rw-r--r-- | sys/netinet/sctp_pcb.h | 1 | ||||
-rw-r--r-- | sys/netinet/sctp_peeloff.c | 16 | ||||
-rw-r--r-- | sys/netinet/sctp_structs.h | 6 | ||||
-rw-r--r-- | sys/netinet/sctp_sysctl.c | 8 | ||||
-rw-r--r-- | sys/netinet/sctp_sysctl.h | 18 | ||||
-rw-r--r-- | sys/netinet/sctp_timer.c | 16 | ||||
-rw-r--r-- | sys/netinet/sctp_usrreq.c | 271 | ||||
-rw-r--r-- | sys/netinet/sctp_var.h | 13 | ||||
-rw-r--r-- | sys/netinet/sctputil.c | 164 | ||||
-rw-r--r-- | sys/netinet/sctputil.h | 5 |
21 files changed, 925 insertions, 254 deletions
diff --git a/sys/netinet/sctp.h b/sys/netinet/sctp.h index 659ef4e..bd060d0 100644 --- a/sys/netinet/sctp.h +++ b/sys/netinet/sctp.h @@ -534,5 +534,7 @@ __attribute__((packed)); #define SCTP_LTRACE_CHUNK_ENABLE 0x00400000 #define SCTP_LTRACE_ERROR_ENABLE 0x00800000 #define SCTP_LAST_PACKET_TRACING 0x01000000 +#define SCTP_THRESHOLD_LOGGING 0x02000000 + #endif /* !_NETINET_SCTP_H_ */ diff --git a/sys/netinet/sctp_asconf.c b/sys/netinet/sctp_asconf.c index b66e1b2..d7a8db2 100644 --- a/sys/netinet/sctp_asconf.c +++ b/sys/netinet/sctp_asconf.c @@ -1140,6 +1140,13 @@ sctp_asconf_queue_add(struct sctp_tcb *stcb, struct sctp_ifa *ifa, net->error_count = 0; } stcb->asoc.overall_error_count = 0; + if (sctp_logging_level & SCTP_THRESHOLD_LOGGING) { + sctp_misc_ints(SCTP_THRESHOLD_CLEAR, + stcb->asoc.overall_error_count, + 0, + SCTP_FROM_SCTP_ASCONF, + __LINE__); + } /* queue in an advisory set primary too */ (void)sctp_asconf_queue_mgmt(stcb, ifa, SCTP_SET_PRIM_ADDR); /* let caller know we should send this out immediately */ @@ -2002,7 +2009,7 @@ sctp_asconf_iterator_end(void *ptr, uint32_t val) * sa is the sockaddr to ask the peer to set primary to. * returns: 0 = completed, -1 = error */ -int +int32_t sctp_set_primary_ip_address_sa(struct sctp_tcb *stcb, struct sockaddr *sa) { /* NOTE: we currently don't check the validity of the address! */ @@ -2691,6 +2698,7 @@ sctp_addr_mgmt_ep_sa(struct sctp_inpcb *inp, struct sockaddr *sa, struct sctp_ifa *ifa; if (sa->sa_len == 0) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_ASCONF, EINVAL); return (EINVAL); } if (sctp_ifap) { @@ -2713,12 +2721,14 @@ sctp_addr_mgmt_ep_sa(struct sctp_inpcb *inp, struct sockaddr *sa, sizeof(struct sctp_asconf_iterator), SCTP_M_ASC_IT); if (asc == NULL) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_ASCONF, ENOMEM); return (ENOMEM); } wi = SCTP_ZONE_GET(sctppcbinfo.ipi_zone_laddr, struct sctp_laddr); if (wi == NULL) { SCTP_FREE(asc, SCTP_M_ASC_IT); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_ASCONF, ENOMEM); return (ENOMEM); } if (type == SCTP_ADD_IP_ADDRESS) { @@ -2730,6 +2740,7 @@ sctp_addr_mgmt_ep_sa(struct sctp_inpcb *inp, struct sockaddr *sa, /* can't delete the last local address */ SCTP_FREE(asc, SCTP_M_ASC_IT); SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_laddr, wi); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_ASCONF, EINVAL); return (EINVAL); } LIST_FOREACH(laddr, &inp->sctp_addr_list, @@ -2757,6 +2768,7 @@ sctp_addr_mgmt_ep_sa(struct sctp_inpcb *inp, struct sockaddr *sa, sctp_asconf_iterator_end, inp, 0); } else { /* invalid address! */ + SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_ASCONF, EADDRNOTAVAIL); return (EADDRNOTAVAIL); } return (0); diff --git a/sys/netinet/sctp_auth.c b/sys/netinet/sctp_auth.c index e5bf051..2e7d457 100644 --- a/sys/netinet/sctp_auth.c +++ b/sys/netinet/sctp_auth.c @@ -780,7 +780,7 @@ sctp_alloc_authinfo(void) /* out of memory */ return (NULL); } - bzero(&new_authinfo, sizeof(*new_authinfo)); + bzero(new_authinfo, sizeof(*new_authinfo)); return (new_authinfo); } diff --git a/sys/netinet/sctp_constants.h b/sys/netinet/sctp_constants.h index cf852a4..f6bdf34 100644 --- a/sys/netinet/sctp_constants.h +++ b/sys/netinet/sctp_constants.h @@ -209,8 +209,11 @@ __FBSDID("$FreeBSD$"); #define SCTP_FLIGHT_LOG_DOWN_PMTU 115 #define SCTP_SACK_LOG_NORMAL 116 #define SCTP_SACK_LOG_EXPRESS 117 +#define SCTP_MAP_TSN_ENTERS 118 +#define SCTP_THRESHOLD_CLEAR 119 +#define SCTP_THRESHOLD_INCR 120 -#define SCTP_LOG_MAX_TYPES 118 +#define SCTP_LOG_MAX_TYPES 121 /* * To turn on various logging, you must first enable 'options KTR' and * you might want to bump the entires 'options KTR_ENTRIES=80000'. @@ -220,6 +223,12 @@ __FBSDID("$FreeBSD$"); * This gets the compile in place, but you still need to turn the * logging flag on too in the sysctl (see in sctp.h). */ + +/* For SCTP only logging */ +#define SCTP_MAX_LOGGING_SIZE 30000 +#define SCTP_TRACE_PARAMS 6 + + #define SCTP_LOG_EVENT_UNKNOWN 0 #define SCTP_LOG_EVENT_CWND 1 #define SCTP_LOG_EVENT_BLOCK 2 @@ -480,6 +489,7 @@ __FBSDID("$FreeBSD$"); #define SCTP_STATE_MASK 0x007f #define SCTP_GET_STATE(asoc) ((asoc)->state & SCTP_STATE_MASK) +#define SCTP_SET_STATE(asoc, newstate) ((asoc)->state = ((asoc)->state & ~SCTP_STATE_MASK) | newstate) /* SCTP reachability state for each address */ #define SCTP_ADDR_REACHABLE 0x001 @@ -831,6 +841,7 @@ __FBSDID("$FreeBSD$"); #define SCTP_FROM_SCTP_OUTPUT 0x90000000 #define SCTP_FROM_SCTP_PEELOFF 0xa0000000 #define SCTP_FROM_SCTP_PANDA 0xb0000000 +#define SCTP_FROM_SCTP_SYSCTL 0xc0000000 /* Location ID's */ #define SCTP_LOC_1 0x00000001 diff --git a/sys/netinet/sctp_header.h b/sys/netinet/sctp_header.h index 121c796..090e96d 100644 --- a/sys/netinet/sctp_header.h +++ b/sys/netinet/sctp_header.h @@ -36,7 +36,6 @@ __FBSDID("$FreeBSD$"); #ifndef __sctp_header_h__ #define __sctp_header_h__ - #include <sys/time.h> #include <netinet/sctp.h> #include <netinet/sctp_constants.h> diff --git a/sys/netinet/sctp_indata.c b/sys/netinet/sctp_indata.c index 30aa980..aa85a6f 100644 --- a/sys/netinet/sctp_indata.c +++ b/sys/netinet/sctp_indata.c @@ -775,7 +775,7 @@ doit_again: * but should we? */ if ((sctp_is_all_msg_on_reasm(asoc, &tsize) || - (tsize > stcb->sctp_ep->partial_delivery_point))) { + (tsize >= stcb->sctp_ep->partial_delivery_point))) { /* * Yes, we setup to start reception, by @@ -1452,7 +1452,7 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc, protocol_id = ch->dp.protocol_id; ordered = ((ch->ch.chunk_flags & SCTP_DATA_UNORDERED) == 0); if (sctp_logging_level & SCTP_MAP_LOGGING_ENABLE) { - sctp_log_map(0, tsn, asoc->cumulative_tsn, SCTP_MAP_PREPARE_SLIDE); + sctp_log_map(tsn, asoc->cumulative_tsn, asoc->highest_tsn_inside_map, SCTP_MAP_TSN_ENTERS); } if (stcb == NULL) { return (0); @@ -2209,7 +2209,7 @@ sctp_sack_check(struct sctp_tcb *stcb, int ok_to_sack, int was_a_gap, int *abort */ struct sctp_association *asoc; int i, at; - int all_ones, last_all_ones = 0; + int last_all_ones = 0; int slide_from, slide_end, lgap, distance; uint32_t old_cumack, old_base, old_highest; unsigned char aux_array[64]; @@ -2231,7 +2231,6 @@ sctp_sack_check(struct sctp_tcb *stcb, int ok_to_sack, int was_a_gap, int *abort * We could probably improve this a small bit by calculating the * offset of the current cum-ack as the starting point. */ - all_ones = 1; at = 0; for (i = 0; i < stcb->asoc.mapping_array_size; i++) { @@ -2240,7 +2239,6 @@ sctp_sack_check(struct sctp_tcb *stcb, int ok_to_sack, int was_a_gap, int *abort last_all_ones = 1; } else { /* there is a 0 bit */ - all_ones = 0; at += sctp_map_lookup_tab[asoc->mapping_array[i]]; last_all_ones = 0; break; @@ -2260,24 +2258,16 @@ sctp_sack_check(struct sctp_tcb *stcb, int ok_to_sack, int was_a_gap, int *abort asoc->highest_tsn_inside_map = asoc->cumulative_tsn; #endif } - if (all_ones || - (asoc->cumulative_tsn == asoc->highest_tsn_inside_map && at >= 8)) { + if ((asoc->cumulative_tsn == asoc->highest_tsn_inside_map) && (at >= 8)) { /* The complete array was completed by a single FR */ /* higest becomes the cum-ack */ int clr; asoc->cumulative_tsn = asoc->highest_tsn_inside_map; /* clear the array */ - if (all_ones) + clr = (at >> 3) + 1; + if (clr > asoc->mapping_array_size) { clr = asoc->mapping_array_size; - else { - clr = (at >> 3) + 1; - /* - * this should be the allones case but just in case - * :> - */ - if (clr > asoc->mapping_array_size) - clr = asoc->mapping_array_size; } memset(asoc->mapping_array, 0, clr); /* base becomes one ahead of the cum-ack */ @@ -2467,7 +2457,7 @@ doit_again: * delivery queue and something can be delivered. */ if ((sctp_is_all_msg_on_reasm(asoc, &tsize) || - (tsize > stcb->sctp_ep->partial_delivery_point))) { + (tsize >= stcb->sctp_ep->partial_delivery_point))) { asoc->fragmented_delivery_inprogress = 1; asoc->tsn_last_delivered = chk->rec.data.TSN_seq - 1; asoc->str_of_pdapi = chk->rec.data.stream_number; @@ -2722,10 +2712,17 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length, } if (num_chunks) { /* - * Did we get data, if so update the time for auto-close and + * Did we get data, if sa update the time for auto-close and * give peer credit for being alive. */ SCTP_STAT_INCR(sctps_recvpktwithdata); + if (sctp_logging_level & SCTP_THRESHOLD_LOGGING) { + sctp_misc_ints(SCTP_THRESHOLD_CLEAR, + stcb->asoc.overall_error_count, + 0, + SCTP_FROM_SCTP_INDATA, + __LINE__); + } stcb->asoc.overall_error_count = 0; (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_last_rcvd); } @@ -3866,6 +3863,13 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack, } } asoc->this_sack_highest_gap = cumack; + if (sctp_logging_level & SCTP_THRESHOLD_LOGGING) { + sctp_misc_ints(SCTP_THRESHOLD_CLEAR, + stcb->asoc.overall_error_count, + 0, + SCTP_FROM_SCTP_INDATA, + __LINE__); + } stcb->asoc.overall_error_count = 0; if (compare_with_wrap(cumack, asoc->last_acked_seq, MAX_TSN)) { /* process the new consecutive TSN first */ @@ -4187,7 +4191,7 @@ again: (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { SCTP_STAT_DECR_GAUGE32(sctps_currestab); } - asoc->state = SCTP_STATE_SHUTDOWN_SENT; + SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT); sctp_stop_timers_for_shutdown(stcb); sctp_send_shutdown(stcb, stcb->asoc.primary_destination); @@ -4202,7 +4206,7 @@ again: goto abort_out_now; } SCTP_STAT_DECR_GAUGE32(sctps_currestab); - asoc->state = SCTP_STATE_SHUTDOWN_ACK_SENT; + SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_ACK_SENT); sctp_send_shutdown_ack(stcb, stcb->asoc.primary_destination); @@ -4296,6 +4300,13 @@ sctp_handle_sack(struct mbuf *m, int offset, num_dup = ntohs(sack->num_dup_tsns); old_rwnd = stcb->asoc.peers_rwnd; + if (sctp_logging_level & SCTP_THRESHOLD_LOGGING) { + sctp_misc_ints(SCTP_THRESHOLD_CLEAR, + stcb->asoc.overall_error_count, + 0, + SCTP_FROM_SCTP_INDATA, + __LINE__); + } stcb->asoc.overall_error_count = 0; asoc = &stcb->asoc; if (sctp_logging_level & SCTP_SACK_LOGGING_ENABLE) { @@ -4847,7 +4858,7 @@ done_with_it: (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { SCTP_STAT_DECR_GAUGE32(sctps_currestab); } - asoc->state = SCTP_STATE_SHUTDOWN_SENT; + SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT); sctp_stop_timers_for_shutdown(stcb); sctp_send_shutdown(stcb, stcb->asoc.primary_destination); @@ -4863,7 +4874,7 @@ done_with_it: goto abort_out_now; } SCTP_STAT_DECR_GAUGE32(sctps_currestab); - asoc->state = SCTP_STATE_SHUTDOWN_ACK_SENT; + SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_ACK_SENT); sctp_send_shutdown_ack(stcb, stcb->asoc.primary_destination); @@ -5254,6 +5265,9 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb, if (gap > m_size) { asoc->highest_tsn_inside_map = back_out_htsn; + if (sctp_logging_level & SCTP_MAP_LOGGING_ENABLE) { + sctp_log_map(0, 0, asoc->highest_tsn_inside_map, SCTP_MAP_SLIDE_RESULT); + } if ((long)gap > sctp_sbspace(&stcb->asoc, &stcb->sctp_socket->so_rcv)) { struct mbuf *oper; diff --git a/sys/netinet/sctp_input.c b/sys/netinet/sctp_input.c index 46c23cd..32adf9b 100644 --- a/sys/netinet/sctp_input.c +++ b/sys/netinet/sctp_input.c @@ -425,6 +425,13 @@ sctp_process_init_ack(struct mbuf *m, int iphlen, int offset, op_err = NULL; } /* extract the cookie and queue it to "echo" it back... */ + if (sctp_logging_level & SCTP_THRESHOLD_LOGGING) { + sctp_misc_ints(SCTP_THRESHOLD_CLEAR, + stcb->asoc.overall_error_count, + 0, + SCTP_FROM_SCTP_INPUT, + __LINE__); + } stcb->asoc.overall_error_count = 0; net->error_count = 0; @@ -603,7 +610,8 @@ sctp_handle_abort(struct sctp_abort_chunk *cp, #ifdef SCTP_ASOCLOG_OF_TSNS sctp_print_out_track_log(stcb); #endif - sctp_free_assoc(stcb->sctp_ep, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_6); + (void)sctp_free_assoc(stcb->sctp_ep, stcb, SCTP_NORMAL_PROC, + SCTP_FROM_SCTP_INPUT + SCTP_LOC_6); SCTPDBG(SCTP_DEBUG_INPUT2, "sctp_handle_abort: finished\n"); } @@ -645,7 +653,7 @@ sctp_handle_shutdown(struct sctp_shutdown_chunk *cp, if ((SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_RECEIVED) && (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_ACK_SENT) && (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT)) { - asoc->state = SCTP_STATE_SHUTDOWN_RECEIVED; + SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_RECEIVED); /* * notify upper layer that peer has initiated a * shutdown @@ -680,7 +688,7 @@ sctp_handle_shutdown(struct sctp_shutdown_chunk *cp, (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { SCTP_STAT_DECR_GAUGE32(sctps_currestab); } - asoc->state = SCTP_STATE_SHUTDOWN_ACK_SENT; + SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_ACK_SENT); /* start SHUTDOWN timer */ sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNACK, stcb->sctp_ep, @@ -739,7 +747,7 @@ sctp_handle_shutdown_ack(struct sctp_shutdown_ack_chunk *cp, } SCTP_STAT_INCR_COUNTER32(sctps_shutdown); /* free the TCB but first save off the ep */ - sctp_free_assoc(stcb->sctp_ep, stcb, SCTP_NORMAL_PROC, + (void)sctp_free_assoc(stcb->sctp_ep, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_10); } @@ -866,7 +874,8 @@ sctp_handle_error(struct sctp_chunkhdr *ch, asoc->max_init_times) { sctp_abort_notification(stcb, 0); /* now free the asoc */ - sctp_free_assoc(stcb->sctp_ep, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_11); + (void)sctp_free_assoc(stcb->sctp_ep, stcb, SCTP_NORMAL_PROC, + SCTP_FROM_SCTP_INPUT + SCTP_LOC_11); return (-1); } /* blast back to INIT state */ @@ -941,7 +950,6 @@ sctp_handle_init_ack(struct mbuf *m, int iphlen, int offset, struct sctp_nets *net, int *abort_no_unlock, uint32_t vrf_id) { struct sctp_init_ack *init_ack; - int *state; struct mbuf *op_err; SCTPDBG(SCTP_DEBUG_INPUT2, @@ -995,8 +1003,7 @@ sctp_handle_init_ack(struct mbuf *m, int iphlen, int offset, return (-1); } /* process according to association state... */ - state = &stcb->asoc.state; - switch (*state & SCTP_STATE_MASK) { + switch (stcb->asoc.state & SCTP_STATE_MASK) { case SCTP_STATE_COOKIE_WAIT: /* this is the expected state for this chunk */ /* process the INIT-ACK parameters */ @@ -1020,14 +1027,16 @@ sctp_handle_init_ack(struct mbuf *m, int iphlen, int offset, } /* update our state */ SCTPDBG(SCTP_DEBUG_INPUT2, "moving to COOKIE-ECHOED state\n"); - if (*state & SCTP_STATE_SHUTDOWN_PENDING) { - *state = SCTP_STATE_COOKIE_ECHOED | - SCTP_STATE_SHUTDOWN_PENDING; - } else { - *state = SCTP_STATE_COOKIE_ECHOED; - } + SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_COOKIE_ECHOED); /* reset the RTO calc */ + if (sctp_logging_level & SCTP_THRESHOLD_LOGGING) { + sctp_misc_ints(SCTP_THRESHOLD_CLEAR, + stcb->asoc.overall_error_count, + 0, + SCTP_FROM_SCTP_INPUT, + __LINE__); + } stcb->asoc.overall_error_count = 0; (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); /* @@ -1195,14 +1204,11 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, SCTP_STAT_INCR_COUNTER32(sctps_activeestab); else SCTP_STAT_INCR_COUNTER32(sctps_collisionestab); + + SCTP_SET_STATE(asoc, SCTP_STATE_OPEN); if (asoc->state & SCTP_STATE_SHUTDOWN_PENDING) { - asoc->state = SCTP_STATE_OPEN | SCTP_STATE_SHUTDOWN_PENDING; sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb, asoc->primary_destination); - - } else { - /* if ok, move to OPEN state */ - asoc->state = SCTP_STATE_OPEN; } SCTP_STAT_INCR_GAUGE32(sctps_currestab); sctp_stop_all_cookie_timers(stcb); @@ -1381,13 +1387,11 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, } else { SCTP_STAT_INCR_COUNTER32(sctps_collisionestab); } + SCTP_SET_STATE(asoc, SCTP_STATE_OPEN); if (asoc->state & SCTP_STATE_SHUTDOWN_PENDING) { - asoc->state = SCTP_STATE_OPEN | SCTP_STATE_SHUTDOWN_PENDING; sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb, asoc->primary_destination); - } else { - asoc->state = SCTP_STATE_OPEN; } sctp_stop_all_cookie_timers(stcb); sctp_toss_old_cookies(stcb, asoc); @@ -1438,14 +1442,13 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, SCTP_STAT_INCR_GAUGE32(sctps_collisionestab); } if (asoc->state & SCTP_STATE_SHUTDOWN_PENDING) { - asoc->state = SCTP_STATE_OPEN | - SCTP_STATE_SHUTDOWN_PENDING; + SCTP_SET_STATE(asoc, SCTP_STATE_OPEN); sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb, asoc->primary_destination); } else if (!(asoc->state & SCTP_STATE_SHUTDOWN_SENT)) { /* move to OPEN state, if not in SHUTDOWN_SENT */ - asoc->state = SCTP_STATE_OPEN; + SCTP_SET_STATE(asoc, SCTP_STATE_OPEN); } asoc->pre_open_streams = ntohs(initack_cp->init.num_outbound_streams); @@ -1667,7 +1670,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); - sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, + (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_16); atomic_add_int(&stcb->asoc.refcnt, -1); return (NULL); @@ -1692,7 +1695,7 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset, retval = 0; if (retval < 0) { atomic_add_int(&stcb->asoc.refcnt, 1); - sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_16); + (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_16); atomic_add_int(&stcb->asoc.refcnt, -1); return (NULL); } @@ -1701,7 +1704,7 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset, init_offset + sizeof(struct sctp_init_chunk), initack_offset, sh, init_src)) { atomic_add_int(&stcb->asoc.refcnt, 1); - sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_17); + (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_17); atomic_add_int(&stcb->asoc.refcnt, -1); return (NULL); } @@ -1722,7 +1725,7 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset, SCTPDBG(SCTP_DEBUG_AUTH1, "COOKIE-ECHO: AUTH failed\n"); atomic_add_int(&stcb->asoc.refcnt, 1); - sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_18); + (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_18); atomic_add_int(&stcb->asoc.refcnt, -1); return (NULL); } else { @@ -1732,12 +1735,10 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset, } /* update current state */ SCTPDBG(SCTP_DEBUG_INPUT2, "moving to OPEN state\n"); + SCTP_SET_STATE(asoc, SCTP_STATE_OPEN); if (asoc->state & SCTP_STATE_SHUTDOWN_PENDING) { - asoc->state = SCTP_STATE_OPEN | SCTP_STATE_SHUTDOWN_PENDING; sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb, asoc->primary_destination); - } else { - asoc->state = SCTP_STATE_OPEN; } sctp_stop_all_cookie_timers(stcb); SCTP_STAT_INCR_COUNTER32(sctps_passiveestab); @@ -1772,7 +1773,7 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset, sizeof(sin6->sin6_addr)); } else { atomic_add_int(&stcb->asoc.refcnt, 1); - sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_19); + (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_19); atomic_add_int(&stcb->asoc.refcnt, -1); return (NULL); } @@ -2201,7 +2202,7 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset, op_err = sctp_generate_invmanparam(SCTP_CAUSE_OUT_OF_RESC); sctp_abort_association(*inp_p, NULL, m, iphlen, sh, op_err, vrf_id); - sctp_free_assoc(*inp_p, *stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_20); + (void)sctp_free_assoc(*inp_p, *stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_20); return (NULL); } inp = (struct sctp_inpcb *)so->so_pcb; @@ -2304,13 +2305,11 @@ sctp_handle_cookie_ack(struct sctp_cookie_ack_chunk *cp, if (SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_ECHOED) { /* state change only needed when I am in right state */ SCTPDBG(SCTP_DEBUG_INPUT2, "moving to OPEN state\n"); + SCTP_SET_STATE(asoc, SCTP_STATE_OPEN); if (asoc->state & SCTP_STATE_SHUTDOWN_PENDING) { - asoc->state = SCTP_STATE_OPEN | SCTP_STATE_SHUTDOWN_PENDING; sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb, asoc->primary_destination); - } else { - asoc->state = SCTP_STATE_OPEN; } /* update RTO */ SCTP_STAT_INCR_COUNTER32(sctps_activeestab); @@ -2500,7 +2499,7 @@ sctp_handle_shutdown_complete(struct sctp_shutdown_complete_chunk *cp, sctp_timer_stop(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_22); SCTP_STAT_INCR_COUNTER32(sctps_shutdown); /* free the TCB */ - sctp_free_assoc(stcb->sctp_ep, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_23); + (void)sctp_free_assoc(stcb->sctp_ep, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_23); return; } @@ -3657,6 +3656,13 @@ __attribute__((noinline)) (ch->chunk_type == SCTP_HEARTBEAT_REQUEST)) && (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_ECHOED)) { /* implied cookie-ack.. we must have lost the ack */ + if (sctp_logging_level & SCTP_THRESHOLD_LOGGING) { + sctp_misc_ints(SCTP_THRESHOLD_CLEAR, + stcb->asoc.overall_error_count, + 0, + SCTP_FROM_SCTP_INPUT, + __LINE__); + } stcb->asoc.overall_error_count = 0; sctp_handle_cookie_ack((struct sctp_cookie_ack_chunk *)ch, stcb, *netp); @@ -3826,7 +3832,7 @@ process_control_chunks: } *offset = length; if (stcb) { - sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_27); + (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_27); } return (NULL); } @@ -3927,6 +3933,13 @@ process_control_chunks: chk_length, *netp); /* He's alive so give him credit */ + if (sctp_logging_level & SCTP_THRESHOLD_LOGGING) { + sctp_misc_ints(SCTP_THRESHOLD_CLEAR, + stcb->asoc.overall_error_count, + 0, + SCTP_FROM_SCTP_INPUT, + __LINE__); + } stcb->asoc.overall_error_count = 0; } break; @@ -3941,6 +3954,13 @@ process_control_chunks: return (NULL); } /* He's alive so give him credit */ + if (sctp_logging_level & SCTP_THRESHOLD_LOGGING) { + sctp_misc_ints(SCTP_THRESHOLD_CLEAR, + stcb->asoc.overall_error_count, + 0, + SCTP_FROM_SCTP_INPUT, + __LINE__); + } stcb->asoc.overall_error_count = 0; SCTP_STAT_INCR(sctps_recvheartbeatack); if (netp && *netp) @@ -4130,13 +4150,20 @@ process_control_chunks: if ((stcb) && (stcb->asoc.total_output_queue_size)) { ; } else if (stcb) { - sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_27); + (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_27); *offset = length; return (NULL); } } /* He's alive so give him credit */ if ((stcb) && netp && *netp) { + if (sctp_logging_level & SCTP_THRESHOLD_LOGGING) { + sctp_misc_ints(SCTP_THRESHOLD_CLEAR, + stcb->asoc.overall_error_count, + 0, + SCTP_FROM_SCTP_INPUT, + __LINE__); + } stcb->asoc.overall_error_count = 0; sctp_handle_cookie_ack((struct sctp_cookie_ack_chunk *)ch, stcb, *netp); } @@ -4153,6 +4180,13 @@ process_control_chunks: return (NULL); } if (stcb) { + if (sctp_logging_level & SCTP_THRESHOLD_LOGGING) { + sctp_misc_ints(SCTP_THRESHOLD_CLEAR, + stcb->asoc.overall_error_count, + 0, + SCTP_FROM_SCTP_INPUT, + __LINE__); + } stcb->asoc.overall_error_count = 0; sctp_handle_ecn_echo((struct sctp_ecne_chunk *)ch, stcb); @@ -4170,6 +4204,13 @@ process_control_chunks: return (NULL); } if (stcb) { + if (sctp_logging_level & SCTP_THRESHOLD_LOGGING) { + sctp_misc_ints(SCTP_THRESHOLD_CLEAR, + stcb->asoc.overall_error_count, + 0, + SCTP_FROM_SCTP_INPUT, + __LINE__); + } stcb->asoc.overall_error_count = 0; sctp_handle_ecn_cwr((struct sctp_cwr_chunk *)ch, stcb); } @@ -4196,6 +4237,13 @@ process_control_chunks: SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_ASCONF\n"); /* He's alive so give him credit */ if (stcb) { + if (sctp_logging_level & SCTP_THRESHOLD_LOGGING) { + sctp_misc_ints(SCTP_THRESHOLD_CLEAR, + stcb->asoc.overall_error_count, + 0, + SCTP_FROM_SCTP_INPUT, + __LINE__); + } stcb->asoc.overall_error_count = 0; sctp_handle_asconf(m, *offset, (struct sctp_asconf_chunk *)ch, stcb); @@ -4213,6 +4261,13 @@ process_control_chunks: } if ((stcb) && netp && *netp) { /* He's alive so give him credit */ + if (sctp_logging_level & SCTP_THRESHOLD_LOGGING) { + sctp_misc_ints(SCTP_THRESHOLD_CLEAR, + stcb->asoc.overall_error_count, + 0, + SCTP_FROM_SCTP_INPUT, + __LINE__); + } stcb->asoc.overall_error_count = 0; sctp_handle_asconf_ack(m, *offset, (struct sctp_asconf_ack_chunk *)ch, stcb, *netp); @@ -4233,10 +4288,17 @@ process_control_chunks: int abort_flag = 0; stcb->asoc.overall_error_count = 0; + if (sctp_logging_level & SCTP_THRESHOLD_LOGGING) { + sctp_misc_ints(SCTP_THRESHOLD_CLEAR, + stcb->asoc.overall_error_count, + 0, + SCTP_FROM_SCTP_INPUT, + __LINE__); + } *fwd_tsn_seen = 1; if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { /* We are not interested anymore */ - sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_29); + (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_29); *offset = length; return (NULL); } @@ -4246,6 +4308,13 @@ process_control_chunks: *offset = length; return (NULL); } else { + if (sctp_logging_level & SCTP_THRESHOLD_LOGGING) { + sctp_misc_ints(SCTP_THRESHOLD_CLEAR, + stcb->asoc.overall_error_count, + 0, + SCTP_FROM_SCTP_INPUT, + __LINE__); + } stcb->asoc.overall_error_count = 0; } @@ -4263,7 +4332,7 @@ process_control_chunks: } if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { /* We are not interested anymore */ - sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_30); + (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_30); *offset = length; return (NULL); } @@ -4510,7 +4579,8 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset, /* always clear this before beginning a packet */ stcb->asoc.authenticated = 0; stcb->asoc.seen_a_sack_this_pkt = 0; - if (stcb->asoc.state & SCTP_STATE_WAS_ABORTED) { + if ((stcb->asoc.state & SCTP_STATE_WAS_ABORTED) || + (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED)) { /*- * If we hit here, we had a ref count * up when the assoc was aborted and the @@ -4610,6 +4680,13 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset, * shows us the cookie-ack was lost. Imply it was * there. */ + if (sctp_logging_level & SCTP_THRESHOLD_LOGGING) { + sctp_misc_ints(SCTP_THRESHOLD_CLEAR, + stcb->asoc.overall_error_count, + 0, + SCTP_FROM_SCTP_INPUT, + __LINE__); + } stcb->asoc.overall_error_count = 0; sctp_handle_cookie_ack((struct sctp_cookie_ack_chunk *)ch, stcb, net); break; @@ -4928,9 +5005,7 @@ sctp_skip_csum_4: } if ((inp) && (refcount_up)) { /* reduce ref-count */ - SCTP_INP_WLOCK(inp); SCTP_INP_DECR_REF(inp); - SCTP_INP_WUNLOCK(inp); } return; bad: @@ -4939,9 +5014,7 @@ bad: } if ((inp) && (refcount_up)) { /* reduce ref-count */ - SCTP_INP_WLOCK(inp); SCTP_INP_DECR_REF(inp); - SCTP_INP_WUNLOCK(inp); } if (m) { sctp_m_freem(m); diff --git a/sys/netinet/sctp_os.h b/sys/netinet/sctp_os.h index 1e38cdf..fb7c536 100644 --- a/sys/netinet/sctp_os.h +++ b/sys/netinet/sctp_os.h @@ -61,6 +61,7 @@ __FBSDID("$FreeBSD$"); + /* All os's must implement this address gatherer. If * no VRF's exist, then vrf 0 is the only one and all * addresses and ifn's live here. diff --git a/sys/netinet/sctp_os_bsd.h b/sys/netinet/sctp_os_bsd.h index a6cdbf6..9a1dc43 100644 --- a/sys/netinet/sctp_os_bsd.h +++ b/sys/netinet/sctp_os_bsd.h @@ -121,6 +121,16 @@ MALLOC_DECLARE(SCTP_M_MVRF); MALLOC_DECLARE(SCTP_M_ITER); MALLOC_DECLARE(SCTP_M_SOCKOPT); +#if defined(SCTP_LOCAL_TRACE_BUF) + +#define SCTP_GET_CYCLECOUNT get_cyclecount() +#define SCTP_CTR6 sctp_log_trace + +#else +#define SCTP_CTR6 CTR6 +#endif + + /* * */ @@ -166,11 +176,18 @@ MALLOC_DECLARE(SCTP_M_SOCKOPT); #endif #ifdef SCTP_LTRACE_ERRORS -#define SCTP_LTRACE_ERR(a, b, c, d) if(sctp_logging_level & SCTP_LTRACE_ERROR_ENABLE) CTR6(KTR_SUBSYS, "SCTP:%d[%d]:%x-%x-%x-%x", SCTP_LOG_ERROR_RET, 0, a, b, c, d) +#define SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, net, file, err) if(sctp_logging_level & SCTP_LTRACE_ERROR_ENABLE) \ + printf("mbuf:%p inp:%p stcb:%p net:%p file:%x line:%d error:%d\n", \ + m, inp, stcb, net, file, __LINE__, err); +#define SCTP_LTRACE_ERR_RET(inp, stcb, net, file, err) if(sctp_logging_level & SCTP_LTRACE_ERROR_ENABLE) \ + printf("inp:%p stcb:%p net:%p file:%x line:%d error:%d\n", \ + inp, stcb, net, file, __LINE__, err); #else -#define SCTP_LTRACE_ERR(a, b, c, d) +#define SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, net, file, err) +#define SCTP_LTRACE_ERR_RET(inp, stcb, net, file, err) #endif + /* * Local address and interface list handling */ diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c index 9e4f0f0..85824fd 100644 --- a/sys/netinet/sctp_output.c +++ b/sys/netinet/sctp_output.c @@ -2712,12 +2712,15 @@ sctp_choose_boundall(struct sctp_inpcb *inp, ifn = SCTP_GET_IFN_VOID_FROM_ROUTE(ro); ifn_index = SCTP_GET_IF_INDEX_FROM_ROUTE(ro); - emit_ifn = looked_at = sctp_ifn = sctp_find_ifn(ifn, ifn_index); if (sctp_ifn == NULL) { /* ?? We don't have this guy ?? */ + SCTPDBG(SCTP_DEBUG_OUTPUT2, "No ifn emit interface?\n"); goto bound_all_plan_b; } + SCTPDBG(SCTP_DEBUG_OUTPUT2, "ifn_index:%d name:%s is emit interface\n", + ifn_index, sctp_ifn->ifn_name); + if (net) { cur_addr_num = net->indx_of_eligible_next_to_use; } @@ -2726,8 +2729,8 @@ sctp_choose_boundall(struct sctp_inpcb *inp, non_asoc_addr_ok, dest_is_loop, dest_is_priv, fam); - SCTPDBG(SCTP_DEBUG_OUTPUT2, "Found %d preferred source addresses\n", - num_preferred); + SCTPDBG(SCTP_DEBUG_OUTPUT2, "Found %d preferred source addresses for intf:%s\n", + num_preferred, sctp_ifn->ifn_name); if (num_preferred == 0) { /* * no eligible addresses, we must use some other interface @@ -2768,13 +2771,18 @@ sctp_choose_boundall(struct sctp_inpcb *inp, bound_all_plan_b: SCTPDBG(SCTP_DEBUG_OUTPUT2, "Trying Plan B\n"); LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) { + SCTPDBG(SCTP_DEBUG_OUTPUT2, "Examine interface %s\n", + sctp_ifn->ifn_name); if (dest_is_loop == 0 && SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) { /* wrong base scope */ + SCTPDBG(SCTP_DEBUG_OUTPUT2, "skip\n"); continue; } - if ((sctp_ifn == looked_at) && looked_at) + if ((sctp_ifn == looked_at) && looked_at) { /* already looked at this guy */ + SCTPDBG(SCTP_DEBUG_OUTPUT2, "already seen\n"); continue; + } num_preferred = sctp_count_num_preferred_boundall(sctp_ifn, stcb, non_asoc_addr_ok, dest_is_loop, dest_is_priv, fam); SCTPDBG(SCTP_DEBUG_OUTPUT2, @@ -2782,6 +2790,7 @@ bound_all_plan_b: ifn, num_preferred); if (num_preferred == 0) { /* None on this interface. */ + SCTPDBG(SCTP_DEBUG_OUTPUT2, "No prefered -- skipping to next\n"); continue; } SCTPDBG(SCTP_DEBUG_OUTPUT2, @@ -3259,6 +3268,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, sctp_route_t *ro = NULL; if ((net) && (net->dest_state & SCTP_ADDR_OUT_OF_SCOPE)) { + SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EFAULT); sctp_m_freem(m); return (EFAULT); } @@ -3276,6 +3286,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, sctphdr = mtod(m, struct sctphdr *); if (sctp_no_csum_on_loopback && (stcb) && + (to->sa_family == AF_INET) && (stcb->asoc.loopback_scope)) { sctphdr->checksum = 0; /* @@ -3298,7 +3309,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, newm = sctp_get_mbuf_for_msg(sizeof(struct ip), 1, M_DONTWAIT, 1, MT_DATA); if (newm == NULL) { sctp_m_freem(m); - SCTP_LTRACE_ERR(inp, stcb, ENOMEM, 0); + SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); return (ENOMEM); } SCTP_ALIGN_TO_END(newm, sizeof(struct ip)); @@ -3474,6 +3485,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, } } } + SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, EHOSTUNREACH); sctp_m_freem(m); return (EHOSTUNREACH); } @@ -3489,8 +3501,8 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, if (SCTP_GET_HEADER_FOR_OUTPUT(o_pak)) { /* failed to prepend data, give up */ + SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); sctp_m_freem(m); - SCTP_LTRACE_ERR(inp, stcb, ENOMEM, 0); return (ENOMEM); } #ifdef SCTP_PACKET_LOGGING @@ -3565,7 +3577,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, newm = sctp_get_mbuf_for_msg(sizeof(struct ip6_hdr), 1, M_DONTWAIT, 1, MT_DATA); if (newm == NULL) { sctp_m_freem(m); - SCTP_LTRACE_ERR(inp, stcb, ENOMEM, 0); + SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); return (ENOMEM); } SCTP_ALIGN_TO_END(newm, sizeof(struct ip6_hdr)); @@ -3588,8 +3600,10 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, sin6 = &tmp; /* KAME hack: embed scopeid */ - if (sa6_embedscope(sin6, ip6_use_defzone) != 0) + if (sa6_embedscope(sin6, ip6_use_defzone) != 0) { + SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); return (EINVAL); + } if (net == NULL) { memset(&ip6route, 0, sizeof(ip6route)); ro = (sctp_route_t *) & ip6route; @@ -3681,6 +3695,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, lsa6_storage.sin6_family = AF_INET6; lsa6_storage.sin6_len = sizeof(lsa6_storage); if ((error = sa6_recoverscope(&lsa6_storage)) != 0) { + SCTPDBG(SCTP_DEBUG_OUTPUT3, "recover scope fails error %d\n", error); sctp_m_freem(m); return (error); } @@ -3717,7 +3732,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, if (SCTP_GET_HEADER_FOR_OUTPUT(o_pak)) { /* failed to prepend data, give up */ sctp_m_freem(m); - SCTP_LTRACE_ERR(inp, stcb, ENOMEM, 0); + SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); return (ENOMEM); } #ifdef SCTP_PACKET_LOGGING @@ -3790,6 +3805,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, SCTPDBG(SCTP_DEBUG_OUTPUT1, "Unknown protocol (TSNH) type %d\n", ((struct sockaddr *)to)->sa_family); sctp_m_freem(m); + SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EFAULT); return (EFAULT); } } @@ -3841,6 +3857,7 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb) } if (SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) { /* This case should not happen */ + SCTPDBG(SCTP_DEBUG_OUTPUT4, "Sending INIT - failed timer?\n"); return; } /* start the INIT timer */ @@ -3849,6 +3866,7 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb) m = sctp_get_mbuf_for_msg(MCLBYTES, 1, M_DONTWAIT, 1, MT_DATA); if (m == NULL) { /* No memory, INIT timer will re-attempt. */ + SCTPDBG(SCTP_DEBUG_OUTPUT4, "Sending INIT - mbuf?\n"); return; } SCTP_BUF_LEN(m) = sizeof(struct sctp_init_msg); @@ -4059,9 +4077,11 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb) } p_len += padval; } + SCTPDBG(SCTP_DEBUG_OUTPUT4, "Sending INIT - calls lowlevel_output\n"); ret = sctp_lowlevel_chunk_output(inp, stcb, net, (struct sockaddr *)&net->ro._l_addr, m, 0, NULL, 0, 0, NULL, 0); + SCTPDBG(SCTP_DEBUG_OUTPUT4, "lowlevel_output - %d\n", ret); SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks); sctp_timer_start(SCTP_TIMER_TYPE_INIT, inp, stcb, net); (void)SCTP_GETTIME_TIMEVAL(&net->last_sent_time); @@ -5382,11 +5402,13 @@ sctp_msg_append(struct sctp_tcb *stcb, holds_lock = hold_stcb_lock; if (srcv->sinfo_stream >= stcb->asoc.streamoutcnt) { /* Invalid stream number */ + SCTP_LTRACE_ERR_RET_PKT(m, NULL, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); error = EINVAL; goto out_now; } if ((stcb->asoc.stream_locked) && (stcb->asoc.stream_locked_on != srcv->sinfo_stream)) { + SCTP_LTRACE_ERR_RET_PKT(m, NULL, stcb, net, SCTP_FROM_SCTP_OUTPUT, EAGAIN); error = EAGAIN; goto out_now; } @@ -5397,12 +5419,13 @@ sctp_msg_append(struct sctp_tcb *stcb, (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED) || (stcb->asoc.state & SCTP_STATE_SHUTDOWN_PENDING)) { /* got data while shutting down */ + SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ECONNRESET); error = ECONNRESET; goto out_now; } sctp_alloc_a_strmoq(stcb, sp); if (sp == NULL) { - SCTP_LTRACE_ERR(stcb->sctp_ep, stcb, ENOMEM, 0); + SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); error = ENOMEM; goto out_now; } @@ -5720,7 +5743,7 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr, if (SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) { SCTP_STAT_DECR_GAUGE32(sctps_currestab); } - asoc->state = SCTP_STATE_SHUTDOWN_SENT; + SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT); sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb, asoc->primary_destination); sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb, @@ -5882,7 +5905,7 @@ sctp_sendall(struct sctp_inpcb *inp, struct uio *uio, struct mbuf *m, SCTP_M_COPYAL); if (ca == NULL) { sctp_m_freem(m); - SCTP_LTRACE_ERR(inp, NULL, ENOMEM, 0); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); return (ENOMEM); } memset(ca, 0, sizeof(struct sctp_copy_all)); @@ -5900,7 +5923,7 @@ sctp_sendall(struct sctp_inpcb *inp, struct uio *uio, struct mbuf *m, ca->m = sctp_copy_out_all(uio, ca->sndlen); if (ca->m == NULL) { SCTP_FREE(ca, SCTP_M_COPYAL); - SCTP_LTRACE_ERR(inp, NULL, ENOMEM, 0); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); return (ENOMEM); } } else { @@ -5923,6 +5946,7 @@ sctp_sendall(struct sctp_inpcb *inp, struct uio *uio, struct mbuf *m, if (ret) { SCTP_PRINTF("Failed to initiate iterator for sendall\n"); SCTP_FREE(ca, SCTP_M_COPYAL); + SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, EFAULT); return (EFAULT); } return (0); @@ -6136,6 +6160,14 @@ sctp_can_we_split_this(struct sctp_tcb *stcb, return (goal_mtu); } } + /*- + * For those strange folk that make the send buffer + * smaller than our fragmentation point, we can't + * get a full msg in so we have to allow splitting. + */ + if (SCTP_SB_LIMIT_SND(stcb->sctp_socket) < frag_point) { + return (sp->length); + } if ((sp->length <= goal_mtu) || ((sp->length - goal_mtu) < sctp_min_residual)) { /* Sub-optimial residual don't split in non-eeor mode. */ @@ -6341,7 +6373,7 @@ out_gu: rcv_flags |= SCTP_DATA_UNORDERED; } /* clear out the chunk before setting up */ - memset(chk, sizeof(*chk), 0); + memset(chk, 0, sizeof(*chk)); chk->rec.data.rcv_flags = rcv_flags; if (SCTP_BUF_IS_EXTENDED(sp->data)) { chk->copy_by_ref = 1; @@ -7098,7 +7130,7 @@ again_one_more_time: chk->send_size, chk->copy_by_ref); if (outchain == NULL) { *reason_code = 8; - SCTP_LTRACE_ERR(inp, stcb, ENOMEM, 0); + SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); return (ENOMEM); } SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks); @@ -7195,6 +7227,7 @@ again_one_more_time: SCTP_BUF_PREPEND(outchain, sizeof(struct sctphdr), M_DONTWAIT); if (outchain == NULL) { /* no memory */ + SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, ENOBUFS); error = ENOBUFS; goto error_out_again; } @@ -7361,7 +7394,7 @@ again_one_more_time: sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, net); } *reason_code = 3; - SCTP_LTRACE_ERR(inp, stcb, ENOMEM, 0); + SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); return (ENOMEM); } /* upate our MTU size */ @@ -7467,6 +7500,7 @@ again_one_more_time: SCTP_BUF_PREPEND(outchain, sizeof(struct sctphdr), M_DONTWAIT); if (outchain == NULL) { /* out of mbufs */ + SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, ENOBUFS); error = ENOBUFS; goto errored_send; } @@ -8066,7 +8100,7 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp, struct mbuf *m, *endofchain; struct sctphdr *shdr; int asconf; - struct sctp_nets *net; + struct sctp_nets *net = NULL; uint32_t tsns_sent = 0; int no_fragmentflg, bundle_at, cnt_thru; unsigned int mtu; @@ -8147,6 +8181,7 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp, SCTP_BUF_PREPEND(m, sizeof(struct sctphdr), M_DONTWAIT); if (m == NULL) { + SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, ENOBUFS); return (ENOBUFS); } shdr = mtod(m, struct sctphdr *); @@ -8207,8 +8242,10 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp, SCTP_PRINTF("Gak, chk->snd_count:%d >= max:%d - send abort\n", chk->snd_count, sctp_max_retran_chunk); - sctp_send_abort_tcb(stcb, NULL); - sctp_timer_start(SCTP_TIMER_TYPE_ASOCKILL, inp, stcb, NULL); + atomic_add_int(&stcb->asoc.refcnt, 1); + sctp_abort_an_association(stcb->sctp_ep, stcb, 0, NULL); + SCTP_TCB_LOCK(stcb); + atomic_subtract_int(&stcb->asoc.refcnt, 1); return (SCTP_RETRAN_EXIT); } /* pick up the net */ @@ -8292,7 +8329,7 @@ one_chunk_around: } m = sctp_copy_mbufchain(chk->data, m, &endofchain, 0, chk->send_size, chk->copy_by_ref); if (m == NULL) { - SCTP_LTRACE_ERR(inp, stcb, ENOMEM, 0); + SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); return (ENOMEM); } /* Do clear IP_DF ? */ @@ -8344,7 +8381,7 @@ one_chunk_around: } m = sctp_copy_mbufchain(fwd->data, m, &endofchain, 0, fwd->send_size, fwd->copy_by_ref); if (m == NULL) { - SCTP_LTRACE_ERR(inp, stcb, ENOMEM, 0); + SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); return (ENOMEM); } /* Do clear IP_DF ? */ @@ -8383,6 +8420,7 @@ one_chunk_around: } SCTP_BUF_PREPEND(m, sizeof(struct sctphdr), M_DONTWAIT); if (m == NULL) { + SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, ENOBUFS); return (ENOBUFS); } shdr = mtod(m, struct sctphdr *); @@ -8831,9 +8869,11 @@ sctp_output(inp, m, addr, control, p, flags) int flags; { if (inp == NULL) { + SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, EINVAL); return (EINVAL); } if (inp->sctp_socket == NULL) { + SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, EINVAL); return (EINVAL); } return (sctp_sosend(inp->sctp_socket, @@ -9240,8 +9280,15 @@ sctp_send_sack(struct sctp_tcb *stcb) offset += 8; } if (num_gap_blocks == 0) { - /* reneged all chunks */ - asoc->highest_tsn_inside_map = asoc->cumulative_tsn; + /* + * slide not yet happened, and somehow we got called + * to send a sack. Cumack needs to move up. + */ + int abort_flag = 0; + + asoc->cumulative_tsn = asoc->highest_tsn_inside_map; + sack->sack.cum_tsn_ack = htonl(asoc->cumulative_tsn); + sctp_sack_check(stcb, 0, 0, &abort_flag); } } /* now we must add any dups we are going to report. */ @@ -9333,6 +9380,7 @@ sctp_send_abort_tcb(struct sctp_tcb *stcb, struct mbuf *operr) abort->ch.chunk_flags = 0; abort->ch.chunk_length = htons(sizeof(*abort) + sz); + /* prepend and fill in the SCTP header */ SCTP_BUF_PREPEND(m_out, sizeof(struct sctphdr), M_DONTWAIT); if (m_out == NULL) { @@ -9811,6 +9859,9 @@ sctp_send_packet_dropped(struct sctp_tcb *stcb, struct sctp_nets *net, struct ip *iph; int fullsz = 0, extra = 0; long spc; + int offset; + struct sctp_chunkhdr *ch, chunk_buf; + unsigned int chk_length; asoc = &stcb->asoc; SCTP_TCB_LOCK_ASSERT(stcb); @@ -9843,6 +9894,28 @@ sctp_send_packet_dropped(struct sctp_tcb *stcb, struct sctp_nets *net, ip6h = mtod(m, struct ip6_hdr *); len = chk->send_size = htons(ip6h->ip6_plen); } + /* Validate that we do not have an ABORT in here. */ + offset = iphlen + sizeof(struct sctphdr); + ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset, + sizeof(*ch), (uint8_t *) & chunk_buf); + while (ch != NULL) { + chk_length = ntohs(ch->chunk_length); + if (chk_length < sizeof(*ch)) { + /* break to abort land */ + break; + } + switch (ch->chunk_type) { + case SCTP_ABORT_ASSOCIATION: + /* we don't respond with an PKT-DROP to an ABORT */ + return; + default: + break; + } + offset += SCTP_SIZE32(chk_length); + ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset, + sizeof(*ch), (uint8_t *) & chunk_buf); + } + if ((len + SCTP_MAX_OVERHEAD + sizeof(struct sctp_pktdrop_chunk)) > min(stcb->asoc.smallest_mtu, MCLBYTES)) { /* @@ -10181,19 +10254,22 @@ sctp_send_str_reset_req(struct sctp_tcb *stcb, /*- * Already one pending, must get ACK back to clear the flag. */ + SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, EBUSY); return (EBUSY); } if ((send_out_req == 0) && (send_in_req == 0) && (send_tsn_req == 0)) { /* nothing to do */ + SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, EINVAL); return (EINVAL); } if (send_tsn_req && (send_out_req || send_in_req)) { /* error, can't do that */ + SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, EINVAL); return (EINVAL); } sctp_alloc_a_chunk(stcb, chk); if (chk == NULL) { - SCTP_LTRACE_ERR(stcb->sctp_ep, stcb, ENOMEM, 0); + SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); return (ENOMEM); } chk->copy_by_ref = 0; @@ -10207,7 +10283,7 @@ sctp_send_str_reset_req(struct sctp_tcb *stcb, chk->data = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_DONTWAIT, 1, MT_DATA); if (chk->data == NULL) { sctp_free_a_chunk(stcb, chk); - SCTP_LTRACE_ERR(stcb->sctp_ep, stcb, ENOMEM, 0); + SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); return (ENOMEM); } SCTP_BUF_RESV_UF(chk->data, SCTP_MIN_OVERHEAD); @@ -10586,9 +10662,10 @@ sctp_copy_resume(struct sctp_stream_queue_pending *sp, m = m_uiotombuf(uio, M_WAITOK, max_send_len, 0, (M_PKTHDR | (user_marks_eor ? M_EOR : 0))); - if (m == NULL) + if (m == NULL) { + SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); *error = ENOMEM; - else { + } else { *sndout = m_length(m, NULL); *new_tail = m_last(m); } @@ -10605,9 +10682,10 @@ sctp_copy_one(struct sctp_stream_queue_pending *sp, left = sp->length; sp->data = m_uiotombuf(uio, M_WAITOK, sp->length, resv_upfront, 0); - if (sp->data == NULL) + if (sp->data == NULL) { + SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, ENOMEM); return (ENOMEM); - + } sp->tail_mbuf = m_last(sp->data); return (0); } @@ -10640,6 +10718,7 @@ sctp_copy_it_in(struct sctp_tcb *stcb, if (((user_marks_eor == 0) && non_blocking) && (uio->uio_resid > (int)SCTP_SB_LIMIT_SND(stcb->sctp_socket))) { /* It will NEVER fit */ + SCTP_LTRACE_ERR_RET(NULL, stcb, net, SCTP_FROM_SCTP_OUTPUT, EMSGSIZE); *error = EMSGSIZE; goto out_now; } @@ -10649,11 +10728,13 @@ sctp_copy_it_in(struct sctp_tcb *stcb, (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED) || (asoc->state & SCTP_STATE_SHUTDOWN_PENDING)) { /* got data while shutting down */ + SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ECONNRESET); *error = ECONNRESET; goto out_now; } sctp_alloc_a_strmoq(stcb, sp); if (sp == NULL) { + SCTP_LTRACE_ERR_RET(NULL, stcb, net, SCTP_FROM_SCTP_OUTPUT, ENOMEM); *error = ENOMEM; goto out_now; } @@ -10707,8 +10788,7 @@ sctp_sosend(struct socket *so, struct uio *uio, struct mbuf *top, struct mbuf *control, - int flags - , + int flags, struct thread *p ) { @@ -10781,30 +10861,41 @@ sctp_lower_sosend(struct socket *so, asoc = NULL; t_inp = inp = (struct sctp_inpcb *)so->so_pcb; if (inp == NULL) { + SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, EFAULT); error = EFAULT; goto out_unlocked; } if ((uio == NULL) && (i_pak == NULL)) { + SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); return (EINVAL); } atomic_add_int(&inp->total_sends, 1); - if (uio) + if (uio) { + if (uio->uio_resid < 0) { + SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); + return (EINVAL); + } sndlen = uio->uio_resid; - else { - sndlen = SCTP_HEADER_LEN(i_pak); + } else { top = SCTP_HEADER_TO_CHAIN(i_pak); + sndlen = SCTP_HEADER_LEN(i_pak); } - /* - * Pre-screen address, if one is given the sin-len must be set - * correctly! + SCTPDBG(SCTP_DEBUG_OUTPUT1, "Send called addr:%p send length %d\n", + addr, + sndlen); + /*- + * Pre-screen address, if one is given the sin-len + * must be set correctly! */ if (addr) { if ((addr->sa_family == AF_INET) && (addr->sa_len != sizeof(struct sockaddr_in))) { + SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); error = EINVAL; goto out_unlocked; } else if ((addr->sa_family == AF_INET6) && (addr->sa_len != sizeof(struct sockaddr_in6))) { + SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); error = EINVAL; goto out_unlocked; } @@ -10814,12 +10905,14 @@ sctp_lower_sosend(struct socket *so, if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && (inp->sctp_socket->so_qlimit)) { /* The listener can NOT send */ + SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, EFAULT); error = EFAULT; goto out_unlocked; } if ((use_rcvinfo) && srcv) { if (INVALID_SINFO_FLAG(srcv->sinfo_flags) || PR_SCTP_INVALID_POLICY(srcv->sinfo_flags)) { + SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); error = EINVAL; goto out_unlocked; } @@ -10840,6 +10933,7 @@ sctp_lower_sosend(struct socket *so, stcb = LIST_FIRST(&inp->sctp_asoc_list); if (stcb == NULL) { SCTP_INP_RUNLOCK(inp); + SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, ENOTCONN); error = ENOTCONN; goto out_unlocked; } @@ -10886,6 +10980,7 @@ sctp_lower_sosend(struct socket *so, } } if (net == NULL) { + SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); error = EINVAL; goto out_unlocked; } @@ -10905,6 +11000,7 @@ sctp_lower_sosend(struct socket *so, struct sockaddr_in *sin; if (addr == NULL) { + SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); error = EINVAL; goto out_unlocked; } @@ -10942,12 +11038,14 @@ sctp_lower_sosend(struct socket *so, if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE)) { /* Should I really unlock ? */ + SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, EFAULT); error = EFAULT; goto out_unlocked; } if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) && (addr->sa_family == AF_INET6)) { + SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); error = EINVAL; goto out_unlocked; } @@ -10964,6 +11062,7 @@ sctp_lower_sosend(struct socket *so, hold_tcblock = 1; } if (t_inp != inp) { + SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, ENOTCONN); error = ENOTCONN; goto out_unlocked; } @@ -10971,9 +11070,11 @@ sctp_lower_sosend(struct socket *so, if (stcb == NULL) { if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { + SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, ENOTCONN); error = ENOTCONN; goto out_unlocked; } else if (addr == NULL) { + SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, ENOENT); error = ENOENT; goto out_unlocked; } else { @@ -10992,6 +11093,7 @@ sctp_lower_sosend(struct socket *so, * User asks to abort a non-existant assoc, * or EOF a non-existant assoc with no data */ + SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, ENOENT); error = ENOENT; goto out_unlocked; } @@ -11016,7 +11118,7 @@ sctp_lower_sosend(struct socket *so, */ queue_only = 1; asoc = &stcb->asoc; - asoc->state = SCTP_STATE_COOKIE_WAIT; + SCTP_SET_STATE(asoc, SCTP_STATE_COOKIE_WAIT); (void)SCTP_GETTIME_TIMEVAL(&asoc->time_entered); /* initialize authentication params for the assoc */ @@ -11134,6 +11236,7 @@ sctp_lower_sosend(struct socket *so, (sndlen + stcb->asoc.total_output_queue_size)) || (stcb->asoc.chunks_on_out_queue > sctp_max_chunks_on_queue)) { + SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EWOULDBLOCK); error = EWOULDBLOCK; atomic_add_int(&stcb->sctp_ep->total_nospaces, 1); goto out_unlocked; @@ -11146,6 +11249,7 @@ sctp_lower_sosend(struct socket *so, free_cnt_applied = 1; if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { + SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ECONNRESET); error = ECONNRESET; goto out_unlocked; } @@ -11157,6 +11261,7 @@ sctp_lower_sosend(struct socket *so, /* * Can't queue any data while stream reset is underway. */ + SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EAGAIN); error = EAGAIN; goto out_unlocked; } @@ -11181,6 +11286,7 @@ sctp_lower_sosend(struct socket *so, (srcv->sinfo_flags & SCTP_ABORT)) { ; } else { + SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ECONNRESET); error = ECONNRESET; goto out_unlocked; } @@ -11195,6 +11301,7 @@ sctp_lower_sosend(struct socket *so, } } if (net == NULL) { + SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); error = EINVAL; goto out_unlocked; } @@ -11228,6 +11335,7 @@ sctp_lower_sosend(struct socket *so, (SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_ECHOED)) { /* It has to be up before we abort */ /* how big is the user initiated abort? */ + SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); error = EINVAL; goto out; } @@ -11236,14 +11344,15 @@ sctp_lower_sosend(struct socket *so, hold_tcblock = 0; } if (top) { - struct mbuf *cntm; + struct mbuf *cntm = NULL; mm = sctp_get_mbuf_for_msg(1, 0, M_WAIT, 1, MT_DATA); - - cntm = top; - while (cntm) { - tot_out += SCTP_BUF_LEN(cntm); - cntm = SCTP_BUF_NEXT(cntm); + if (sndlen != 0) { + cntm = top; + while (cntm) { + tot_out += SCTP_BUF_LEN(cntm); + cntm = SCTP_BUF_NEXT(cntm); + } } tot_demand = (tot_out + sizeof(struct sctp_paramhdr)); } else { @@ -11254,6 +11363,7 @@ sctp_lower_sosend(struct socket *so, mm = sctp_get_mbuf_for_msg(tot_demand, 0, M_WAIT, 1, MT_DATA); } if (mm == NULL) { + SCTP_LTRACE_ERR_RET(NULL, stcb, net, SCTP_FROM_SCTP_OUTPUT, ENOMEM); error = ENOMEM; goto out; } @@ -11283,7 +11393,9 @@ sctp_lower_sosend(struct socket *so, mm = NULL; } } else { - SCTP_BUF_NEXT(mm) = top; + if (sndlen != 0) { + SCTP_BUF_NEXT(mm) = top; + } } } if (hold_tcblock == 0) { @@ -11299,6 +11411,14 @@ sctp_lower_sosend(struct socket *so, /* now relock the stcb so everything is sane */ hold_tcblock = 0; stcb = NULL; + /* + * In this case top is already chained to mm avoid double + * free, since we free it below if top != NULL and driver + * would free it after sending the packet out + */ + if (sndlen != 0) { + top = NULL; + } goto out_unlocked; } /* Calculate the maximum we can send */ @@ -11314,16 +11434,18 @@ sctp_lower_sosend(struct socket *so, /* Is the stream no. valid? */ if (srcv->sinfo_stream >= asoc->streamoutcnt) { /* Invalid stream number */ + SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); error = EINVAL; goto out_unlocked; } if (asoc->strmout == NULL) { /* huh? software error */ + SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EFAULT); error = EFAULT; goto out_unlocked; } len = 0; - if (max_len < sctp_add_more_threshold) { + if ((max_len < sctp_add_more_threshold) && (SCTP_SB_LIMIT_SND(so) > sctp_add_more_threshold)) { /* No room right no ! */ SOCKBUF_LOCK(&so->so_snd); while (SCTP_SB_LIMIT_SND(so) < (stcb->asoc.total_output_queue_size + sctp_add_more_threshold)) { @@ -11365,27 +11487,33 @@ sctp_lower_sosend(struct socket *so, goto out_unlocked; } atomic_add_int(&stcb->total_sends, 1); + /* + * sndlen covers for mbuf case uio_resid covers for the non-mbuf + * case NOTE: uio will be null when top/mbuf is passed + */ + if ((sndlen == 0) || ((uio) && (uio->uio_resid == 0))) { + if (srcv->sinfo_flags & SCTP_EOF) { + got_all_of_the_send = 1; + goto dataless_eof; + } else { + SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); + error = EINVAL; + goto out; + } + } if (top == NULL) { struct sctp_stream_queue_pending *sp; struct sctp_stream_out *strm; uint32_t sndout, initial_out; int user_marks_eor; - if (uio->uio_resid == 0) { - if (srcv->sinfo_flags & SCTP_EOF) { - got_all_of_the_send = 1; - goto dataless_eof; - } else { - error = EINVAL; - goto out; - } - } initial_out = uio->uio_resid; SCTP_TCB_SEND_LOCK(stcb); if ((asoc->stream_locked) && (asoc->stream_locked_on != srcv->sinfo_stream)) { SCTP_TCB_SEND_UNLOCK(stcb); + SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EAGAIN); error = EAGAIN; goto out; } @@ -11459,8 +11587,9 @@ sctp_lower_sosend(struct socket *so, max_len = 0; if ((max_len > sctp_add_more_threshold) || + (max_len && (SCTP_SB_LIMIT_SND(so) < sctp_add_more_threshold)) || (uio->uio_resid && - (uio->uio_resid < (int)max_len))) { + (uio->uio_resid <= (int)max_len))) { sndout = 0; new_tail = NULL; if (hold_tcblock) { @@ -11482,8 +11611,10 @@ sctp_lower_sosend(struct socket *so, * aborted. */ sctp_m_freem(mm); - if (stcb->asoc.state & SCTP_PCB_FLAGS_WAS_ABORTED) + if (stcb->asoc.state & SCTP_PCB_FLAGS_WAS_ABORTED) { + SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ECONNRESET); error = ECONNRESET; + } SCTP_TCB_SEND_UNLOCK(stcb); goto out; } @@ -11613,7 +11744,7 @@ sctp_lower_sosend(struct socket *so, queue_only = 0; } else { sctp_send_initiate(inp, stcb); - stcb->asoc.state = SCTP_STATE_COOKIE_WAIT; + SCTP_SET_STATE(asoc, SCTP_STATE_COOKIE_WAIT); queue_only_for_init = 0; queue_only = 1; } @@ -11659,7 +11790,9 @@ sctp_lower_sosend(struct socket *so, * size we KNOW we will get to sleep safely with the * wakeup flag in place. */ - if (SCTP_SB_LIMIT_SND(so) < (stcb->asoc.total_output_queue_size + sctp_add_more_threshold)) { + if (SCTP_SB_LIMIT_SND(so) <= (stcb->asoc.total_output_queue_size + + min(sctp_add_more_threshold, SCTP_SB_LIMIT_SND(so))) + ) { if (sctp_logging_level & SCTP_BLK_LOGGING_ENABLE) { sctp_log_block(SCTP_BLOCK_LOG_INTO_BLK, so, asoc, uio->uio_resid); @@ -11748,7 +11881,7 @@ dataless_eof: if (SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) { SCTP_STAT_DECR_GAUGE32(sctps_currestab); } - asoc->state = SCTP_STATE_SHUTDOWN_SENT; + SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT); sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb, asoc->primary_destination); sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb, @@ -11872,11 +12005,7 @@ skip_out_eof: queue_only = 0; } else { sctp_send_initiate(inp, stcb); - if (stcb->asoc.state & SCTP_STATE_SHUTDOWN_PENDING) - stcb->asoc.state = SCTP_STATE_COOKIE_WAIT | - SCTP_STATE_SHUTDOWN_PENDING; - else - stcb->asoc.state = SCTP_STATE_COOKIE_WAIT; + SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_COOKIE_WAIT); queue_only_for_init = 0; queue_only = 1; } @@ -11916,10 +12045,10 @@ skip_out_eof: (void)sctp_med_chunk_output(inp, stcb, &stcb->asoc, &num_out, &reason, 1, &cwnd_full, 1, &now, &now_filled, frag_point); } - SCTPDBG(SCTP_DEBUG_OUTPUT1, "USR Send complete qo:%d prw:%d unsent:%d tf:%d cooq:%d toqs:%d \n", + SCTPDBG(SCTP_DEBUG_OUTPUT1, "USR Send complete qo:%d prw:%d unsent:%d tf:%d cooq:%d toqs:%d err:%d", queue_only, stcb->asoc.peers_rwnd, un_sent, stcb->asoc.total_flight, stcb->asoc.chunks_on_out_queue, - stcb->asoc.total_output_queue_size); + stcb->asoc.total_output_queue_size, error); out: out_unlocked: diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c index b4c2def..3d7ecb7 100644 --- a/sys/netinet/sctp_pcb.c +++ b/sys/netinet/sctp_pcb.c @@ -368,7 +368,7 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index, (sctp_ifap->ifn_p->ifn_index == ifn_index)) { if (new_ifn_af) { /* Remove the created one that we don't want */ - sctp_delete_ifn(sctp_ifap->ifn_p, 1); + sctp_delete_ifn(sctp_ifnp, 1); } if (sctp_ifap->localifa_flags & SCTP_BEING_DELETED) { /* easy to solve, just switch back to active */ @@ -392,7 +392,7 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index, * Remove the created one that we * don't want */ - sctp_delete_ifn(sctp_ifap->ifn_p, 1); + sctp_delete_ifn(sctp_ifnp, 1); } goto exit_stage_left; } else { @@ -808,6 +808,7 @@ sctp_findassociation_ep_addr(struct sctp_inpcb **inp_p, struct sockaddr *remote, * UN-lock so we can do proper locking here this occurs when * called from load_addresses_from_init. */ + atomic_add_int(&locked_tcb->asoc.refcnt, 1); SCTP_TCB_UNLOCK(locked_tcb); } SCTP_INP_INFO_RLOCK(); @@ -825,13 +826,12 @@ sctp_findassociation_ep_addr(struct sctp_inpcb **inp_p, struct sockaddr *remote, netp, inp->def_vrf_id); if ((stcb != NULL) && (locked_tcb == NULL)) { /* we have a locked tcb, lower refcount */ - SCTP_INP_WLOCK(inp); SCTP_INP_DECR_REF(inp); - SCTP_INP_WUNLOCK(inp); } if ((locked_tcb != NULL) && (locked_tcb != stcb)) { SCTP_INP_RLOCK(locked_tcb->sctp_ep); SCTP_TCB_LOCK(locked_tcb); + atomic_subtract_int(&locked_tcb->asoc.refcnt, 1); SCTP_INP_RUNLOCK(locked_tcb->sctp_ep); } SCTP_INP_INFO_RUNLOCK(); @@ -880,6 +880,9 @@ sctp_findassociation_ep_addr(struct sctp_inpcb **inp_p, struct sockaddr *remote, } else if (locked_tcb != stcb) { SCTP_TCB_LOCK(locked_tcb); } + if (locked_tcb) { + atomic_subtract_int(&locked_tcb->asoc.refcnt, 1); + } SCTP_INP_WUNLOCK(inp); SCTP_INP_INFO_RUNLOCK(); return (stcb); @@ -900,6 +903,9 @@ sctp_findassociation_ep_addr(struct sctp_inpcb **inp_p, struct sockaddr *remote, } else if (locked_tcb != stcb) { SCTP_TCB_LOCK(locked_tcb); } + if (locked_tcb) { + atomic_subtract_int(&locked_tcb->asoc.refcnt, 1); + } SCTP_INP_WUNLOCK(inp); SCTP_INP_INFO_RUNLOCK(); return (stcb); @@ -953,6 +959,9 @@ sctp_findassociation_ep_addr(struct sctp_inpcb **inp_p, struct sockaddr *remote, } else if (locked_tcb != stcb) { SCTP_TCB_LOCK(locked_tcb); } + if (locked_tcb) { + atomic_subtract_int(&locked_tcb->asoc.refcnt, 1); + } SCTP_INP_WUNLOCK(inp); SCTP_INP_INFO_RUNLOCK(); return (stcb); @@ -974,6 +983,9 @@ sctp_findassociation_ep_addr(struct sctp_inpcb **inp_p, struct sockaddr *remote, } else if (locked_tcb != stcb) { SCTP_TCB_LOCK(locked_tcb); } + if (locked_tcb) { + atomic_subtract_int(&locked_tcb->asoc.refcnt, 1); + } SCTP_INP_WUNLOCK(inp); SCTP_INP_INFO_RUNLOCK(); return (stcb); @@ -987,6 +999,7 @@ null_return: /* clean up for returning null */ if (locked_tcb) { SCTP_TCB_LOCK(locked_tcb); + atomic_subtract_int(&locked_tcb->asoc.refcnt, 1); } SCTP_INP_WUNLOCK(inp); SCTP_INP_INFO_RUNLOCK(); @@ -1793,6 +1806,7 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id) if (inp == NULL) { SCTP_PRINTF("Out of SCTP-INPCB structures - no resources\n"); SCTP_INP_INFO_WUNLOCK(); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, ENOBUFS); return (ENOBUFS); } /* zap it */ @@ -1846,15 +1860,25 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id) * in protosw */ SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_ep, inp); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EOPNOTSUPP); return (EOPNOTSUPP); } - sctp_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE); - + if (sctp_default_frag_interleave == SCTP_FRAG_LEVEL_1) { + sctp_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE); + sctp_feature_off(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS); + } else if (sctp_default_frag_interleave == SCTP_FRAG_LEVEL_2) { + sctp_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE); + sctp_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS); + } else if (sctp_default_frag_interleave == SCTP_FRAG_LEVEL_0) { + sctp_feature_off(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE); + sctp_feature_off(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS); + } inp->sctp_tcbhash = SCTP_HASH_INIT(sctp_pcbtblsize, &inp->sctp_hashmark); if (inp->sctp_tcbhash == NULL) { SCTP_PRINTF("Out of SCTP-INPCB->hashinit - no resources\n"); SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_ep, inp); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, ENOBUFS); return (ENOBUFS); } inp->def_vrf_id = vrf_id; @@ -2152,6 +2176,7 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, #endif if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 0) { /* already did a bind, subsequent binds NOT allowed ! */ + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); return (EINVAL); } #ifdef INVARIANTS @@ -2167,11 +2192,13 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, /* IPV6_V6ONLY socket? */ if (SCTP_IPV6_V6ONLY(ip_inp)) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); return (EINVAL); } - if (addr->sa_len != sizeof(*sin)) + if (addr->sa_len != sizeof(*sin)) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); return (EINVAL); - + } sin = (struct sockaddr_in *)addr; lport = sin->sin_port; if (prison) { @@ -2180,8 +2207,10 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, * prison_ip() call will tranmute the ip * address to the proper valie. */ - if (prison_ip(p->td_ucred, 0, &sin->sin_addr.s_addr)) + if (prison_ip(p->td_ucred, 0, &sin->sin_addr.s_addr)) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); return (EINVAL); + } } if (sin->sin_addr.s_addr != INADDR_ANY) { bindall = 0; @@ -2192,9 +2221,10 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, sin6 = (struct sockaddr_in6 *)addr; - if (addr->sa_len != sizeof(*sin6)) + if (addr->sa_len != sizeof(*sin6)) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); return (EINVAL); - + } lport = sin6->sin6_port; /* * Jail checks for IPv6 should go HERE! i.e. add the @@ -2204,12 +2234,15 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { bindall = 0; /* KAME hack: embed scopeid */ - if (sa6_embedscope(sin6, ip6_use_defzone) != 0) + if (sa6_embedscope(sin6, ip6_use_defzone) != 0) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); return (EINVAL); + } } /* this must be cleared for ifa_ifwithaddr() */ sin6->sin6_scope_id = 0; } else { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EAFNOSUPPORT); return (EAFNOSUPPORT); } } @@ -2240,6 +2273,7 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, SCTP_INP_DECR_REF(inp); SCTP_INP_WUNLOCK(inp); SCTP_INP_INFO_WUNLOCK(); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, error); return (error); } SCTP_INP_WUNLOCK(inp); @@ -2258,6 +2292,7 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, SCTP_INP_DECR_REF(inp); /* unlock info */ SCTP_INP_INFO_WUNLOCK(); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EADDRINUSE); return (EADDRINUSE); } } else { @@ -2274,6 +2309,7 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, SCTP_INP_DECR_REF(inp); /* unlock info */ SCTP_INP_INFO_WUNLOCK(); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EADDRINUSE); return (EADDRINUSE); } } @@ -2285,6 +2321,7 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, SCTP_INP_DECR_REF(inp); SCTP_INP_WUNLOCK(inp); SCTP_INP_INFO_WUNLOCK(); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EADDRINUSE); return (EADDRINUSE); } } @@ -2303,6 +2340,7 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, SCTP_INP_DECR_REF(inp); SCTP_INP_WUNLOCK(inp); SCTP_INP_INFO_WUNLOCK(); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, error); return (error); } first = ipport_lowfirstauto; @@ -2331,6 +2369,7 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, SCTP_INP_DECR_REF(inp); SCTP_INP_WUNLOCK(inp); SCTP_INP_INFO_WUNLOCK(); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EADDRINUSE); return (EADDRINUSE); } if (candidate == last) @@ -2350,17 +2389,19 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, */ SCTP_INP_WUNLOCK(inp); SCTP_INP_INFO_WUNLOCK(); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); return (EINVAL); } /* ok we look clear to give out this port, so lets setup the binding */ if (bindall) { /* binding to all addresses, so just set in the proper flags */ inp->sctp_flags |= SCTP_PCB_FLAGS_BOUNDALL; - sctp_feature_on(inp, SCTP_PCB_FLAGS_DO_ASCONF); /* set the automatic addr changes from kernel flag */ if (sctp_auto_asconf == 0) { + sctp_feature_off(inp, SCTP_PCB_FLAGS_DO_ASCONF); sctp_feature_off(inp, SCTP_PCB_FLAGS_AUTO_ASCONF); } else { + sctp_feature_on(inp, SCTP_PCB_FLAGS_DO_ASCONF); sctp_feature_on(inp, SCTP_PCB_FLAGS_AUTO_ASCONF); } } else { @@ -2411,6 +2452,7 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, /* Can't find an interface with that address */ SCTP_INP_WUNLOCK(inp); SCTP_INP_INFO_WUNLOCK(); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EADDRNOTAVAIL); return (EADDRNOTAVAIL); } if (addr->sa_family == AF_INET6) { @@ -2419,6 +2461,7 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, /* Can't bind a non-existent addr. */ SCTP_INP_WUNLOCK(inp); SCTP_INP_INFO_WUNLOCK(); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); return (EINVAL); } } @@ -2586,10 +2629,12 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from) for ((asoc = LIST_FIRST(&inp->sctp_asoc_list)); asoc != NULL; asoc = nasoc) { nasoc = LIST_NEXT(asoc, sctp_tcblist); + SCTP_TCB_LOCK(asoc); if (asoc->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { /* Skip guys being freed */ asoc->sctp_socket = NULL; cnt_in_sd++; + SCTP_TCB_UNLOCK(asoc); continue; } if ((SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_COOKIE_WAIT) || @@ -2605,11 +2650,14 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from) * Just abandon things in the front * states */ - sctp_free_assoc(inp, asoc, SCTP_PCBFREE_NOFORCE, SCTP_FROM_SCTP_PCB + SCTP_LOC_2); + + if (sctp_free_assoc(inp, asoc, SCTP_PCBFREE_NOFORCE, + SCTP_FROM_SCTP_PCB + SCTP_LOC_2) == 0) { + cnt_in_sd++; + } continue; } } - SCTP_TCB_LOCK(asoc); /* Disconnect the socket please */ asoc->sctp_socket = NULL; asoc->asoc.state |= SCTP_STATE_CLOSED_SOCKET; @@ -2645,7 +2693,10 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from) (SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { SCTP_STAT_DECR_GAUGE32(sctps_currestab); } - sctp_free_assoc(inp, asoc, SCTP_PCBFREE_NOFORCE, SCTP_FROM_SCTP_PCB + SCTP_LOC_4); + if (sctp_free_assoc(inp, asoc, + SCTP_PCBFREE_NOFORCE, SCTP_FROM_SCTP_PCB + SCTP_LOC_4) == 0) { + cnt_in_sd++; + } continue; } else if (TAILQ_EMPTY(&asoc->asoc.send_queue) && TAILQ_EMPTY(&asoc->asoc.sent_queue) && @@ -2665,7 +2716,7 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from) (SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { SCTP_STAT_DECR_GAUGE32(sctps_currestab); } - asoc->asoc.state = SCTP_STATE_SHUTDOWN_SENT; + SCTP_SET_STATE(&asoc->asoc, SCTP_STATE_SHUTDOWN_SENT); sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, asoc->sctp_ep, asoc, asoc->asoc.primary_destination); sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, asoc->sctp_ep, asoc, @@ -2725,7 +2776,11 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from) (SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { SCTP_STAT_DECR_GAUGE32(sctps_currestab); } - sctp_free_assoc(inp, asoc, SCTP_PCBFREE_NOFORCE, SCTP_FROM_SCTP_PCB + SCTP_LOC_6); + if (sctp_free_assoc(inp, asoc, + SCTP_PCBFREE_NOFORCE, + SCTP_FROM_SCTP_PCB + SCTP_LOC_6) == 0) { + cnt_in_sd++; + } continue; } } @@ -2801,7 +2856,9 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from) (SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { SCTP_STAT_DECR_GAUGE32(sctps_currestab); } - sctp_free_assoc(inp, asoc, SCTP_PCBFREE_FORCE, SCTP_FROM_SCTP_PCB + SCTP_LOC_8); + if (sctp_free_assoc(inp, asoc, SCTP_PCBFREE_FORCE, SCTP_FROM_SCTP_PCB + SCTP_LOC_8) == 0) { + cnt++; + } } if (cnt) { /* Ok we have someone out there that will kill us */ @@ -3344,10 +3401,12 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr, */ if (sctppcbinfo.ipi_count_asoc >= SCTP_MAX_NUM_OF_ASOC) { /* Hit max assoc, sorry no more */ + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, ENOBUFS); *error = ENOBUFS; return (NULL); } if (firstaddr == NULL) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); *error = EINVAL; return (NULL); } @@ -3360,6 +3419,7 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr, * off, or connected one does this.. its an error. */ SCTP_INP_RUNLOCK(inp); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); *error = EINVAL; return (NULL); } @@ -3380,6 +3440,7 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr, if ((sin->sin_port == 0) || (sin->sin_addr.s_addr == 0)) { /* Invalid address */ SCTP_INP_RUNLOCK(inp); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); *error = EINVAL; return (NULL); } @@ -3392,6 +3453,7 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr, (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr))) { /* Invalid address */ SCTP_INP_RUNLOCK(inp); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); *error = EINVAL; return (NULL); } @@ -3399,6 +3461,7 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr, } else { /* not supported family type */ SCTP_INP_RUNLOCK(inp); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); *error = EINVAL; return (NULL); } @@ -3421,6 +3484,7 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr, stcb = SCTP_ZONE_GET(sctppcbinfo.ipi_zone_asoc, struct sctp_tcb); if (stcb == NULL) { /* out of memory? */ + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, ENOMEM); *error = ENOMEM; return (NULL); } @@ -3454,6 +3518,7 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr, SCTP_INP_WUNLOCK(inp); SCTP_INP_INFO_WUNLOCK(); SCTP_DECR_ASOC_COUNT(); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); *error = EINVAL; return (NULL); } @@ -3481,6 +3546,7 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr, SCTP_TCB_SEND_LOCK_DESTROY(stcb); SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_asoc, stcb); SCTP_INP_WUNLOCK(inp); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, ENOBUFS); *error = ENOBUFS; return (NULL); } @@ -3668,8 +3734,13 @@ sctp_iterator_asoc_being_freed(struct sctp_inpcb *inp, struct sctp_tcb *stcb) } -/* - * Free the association after un-hashing the remote port. +/*- + * Free the association after un-hashing the remote port. This + * function ALWAYS returns holding NO LOCK on the stcb. It DOES + * expect that the input to this function IS a locked TCB. + * It will return 0, if it did NOT destroy the association (instead + * it unlocks it. It will return NON-zero if it either destroyed the + * association OR the association is already destroyed. */ int sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfree, int from_location) @@ -3689,6 +3760,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre int cnt = 0; /* first, lets purge the entry from the hash table. */ + SCTP_TCB_LOCK_ASSERT(stcb); #ifdef SCTP_LOG_CLOSING sctp_log_closing(inp, stcb, 6); @@ -3810,11 +3882,12 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre SCTP_INP_READ_UNLOCK(inp); if (stcb->block_entry) { cnt++; + SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_PCB, ECONNRESET); stcb->block_entry->error = ECONNRESET; stcb->block_entry = NULL; } } - if ((from_inpcbfree != SCTP_PCBFREE_FORCE) && (stcb->asoc.refcnt)) { + if (stcb->asoc.refcnt) { /* * reader or writer in the way, we have hopefully given him * something to chew on above. @@ -4516,6 +4589,7 @@ sctp_insert_laddr(struct sctpladdr *list, struct sctp_ifa *ifa, uint32_t act) laddr = SCTP_ZONE_GET(sctppcbinfo.ipi_zone_laddr, struct sctp_laddr); if (laddr == NULL) { /* out of memory? */ + SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_PCB, EINVAL); return (EINVAL); } SCTP_INCR_LADDR_COUNT(); @@ -5666,6 +5740,7 @@ sctp_initiate_iterator(inp_func inpf, SCTP_MALLOC(it, struct sctp_iterator *, sizeof(struct sctp_iterator), SCTP_M_ITER); if (it == NULL) { + SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_PCB, ENOMEM); return (ENOMEM); } memset(it, 0, sizeof(*it)); diff --git a/sys/netinet/sctp_pcb.h b/sys/netinet/sctp_pcb.h index 6cdf0ca..2ab7adc 100644 --- a/sys/netinet/sctp_pcb.h +++ b/sys/netinet/sctp_pcb.h @@ -533,6 +533,7 @@ int sctp_del_remote_addr(struct sctp_tcb *, struct sockaddr *); void sctp_pcb_init(void); + void sctp_add_local_addr_restricted(struct sctp_tcb *, struct sctp_ifa *); void sctp_del_local_addr_restricted(struct sctp_tcb *, struct sctp_ifa *); diff --git a/sys/netinet/sctp_peeloff.c b/sys/netinet/sctp_peeloff.c index e810e34..daded1f 100644 --- a/sys/netinet/sctp_peeloff.c +++ b/sys/netinet/sctp_peeloff.c @@ -55,10 +55,12 @@ sctp_can_peel_off(struct socket *head, sctp_assoc_t assoc_id) inp = (struct sctp_inpcb *)head->so_pcb; if (inp == NULL) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PEELOFF, EFAULT); return (EFAULT); } stcb = sctp_findassociation_ep_asocid(inp, assoc_id, 1); if (stcb == NULL) { + SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_PEELOFF, ENOTCONN); return (ENOTCONN); } state = SCTP_GET_STATE((&stcb->asoc)); @@ -67,6 +69,7 @@ sctp_can_peel_off(struct socket *head, sctp_assoc_t assoc_id) (state == SCTP_STATE_COOKIE_WAIT) || (state == SCTP_STATE_COOKIE_ECHOED)) { SCTP_TCB_UNLOCK(stcb); + SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_PEELOFF, ENOTCONN); return (ENOTCONN); } SCTP_TCB_UNLOCK(stcb); @@ -82,18 +85,22 @@ sctp_do_peeloff(struct socket *head, struct socket *so, sctp_assoc_t assoc_id) uint32_t state; inp = (struct sctp_inpcb *)head->so_pcb; - if (inp == NULL) + if (inp == NULL) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PEELOFF, EFAULT); return (EFAULT); + } stcb = sctp_findassociation_ep_asocid(inp, assoc_id, 1); - if (stcb == NULL) + if (stcb == NULL) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PEELOFF, ENOTCONN); return (ENOTCONN); - + } state = SCTP_GET_STATE((&stcb->asoc)); if ((state == SCTP_STATE_EMPTY) || (state == SCTP_STATE_INUSE) || (state == SCTP_STATE_COOKIE_WAIT) || (state == SCTP_STATE_COOKIE_ECHOED)) { SCTP_TCB_UNLOCK(stcb); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PEELOFF, ENOTCONN); return (ENOTCONN); } n_inp = (struct sctp_inpcb *)so->so_pcb; @@ -133,11 +140,13 @@ sctp_get_peeloff(struct socket *head, sctp_assoc_t assoc_id, int *error) SCTPDBG(SCTP_DEBUG_PEEL1, "SCTP peel-off called\n"); inp = (struct sctp_inpcb *)head->so_pcb; if (inp == NULL) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PEELOFF, EFAULT); *error = EFAULT; return (NULL); } stcb = sctp_findassociation_ep_asocid(inp, assoc_id, 1); if (stcb == NULL) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PEELOFF, ENOTCONN); *error = ENOTCONN; return (NULL); } @@ -145,6 +154,7 @@ sctp_get_peeloff(struct socket *head, sctp_assoc_t assoc_id, int *error) ); if (newso == NULL) { SCTPDBG(SCTP_DEBUG_PEEL1, "sctp_peeloff:sonewconn failed\n"); + SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_PEELOFF, ENOMEM); *error = ENOMEM; SCTP_TCB_UNLOCK(stcb); return (NULL); diff --git a/sys/netinet/sctp_structs.h b/sys/netinet/sctp_structs.h index 79df612..f4480d4 100644 --- a/sys/netinet/sctp_structs.h +++ b/sys/netinet/sctp_structs.h @@ -781,13 +781,13 @@ struct sctp_association { uint32_t peers_rwnd; uint32_t my_rwnd; uint32_t my_last_reported_rwnd; - uint32_t my_rwnd_control_len; uint32_t sctp_frag_point; uint32_t total_output_queue_size; - uint32_t sb_cc; /* shadow of sb_cc in one-2-one */ - uint32_t sb_mbcnt; /* shadow of sb_mbcnt in one-2-one */ + uint32_t sb_cc; /* shadow of sb_cc */ + uint32_t my_rwnd_control_len; /* shadow of sb_mbcnt used for rwnd + * control */ /* 32 bit nonce stuff */ uint32_t nonce_resync_tsn; uint32_t nonce_wait_tsn; diff --git a/sys/netinet/sctp_sysctl.c b/sys/netinet/sctp_sysctl.c index b3a6783..02450eb 100644 --- a/sys/netinet/sctp_sysctl.c +++ b/sys/netinet/sctp_sysctl.c @@ -99,6 +99,8 @@ uint32_t sctp_max_retran_chunk = SCTPCTL_MAX_RETRAN_CHUNK_DEFAULT; /* JRS - Variable for default congestion control module */ uint32_t sctp_default_cc_module = SCTPCTL_DEFAULT_CC_MODULE_DEFAULT; +uint32_t sctp_default_frag_interleave = SCTPCTL_DEFAULT_FRAG_INTERLEAVE_DEFAULT; + uint32_t sctp_L2_abc_variable = 1; uint32_t sctp_early_fr = 0; uint32_t sctp_early_fr_msec = SCTP_MINFR_MSEC_TIMER; @@ -345,6 +347,7 @@ sctp_assoclist(SYSCTL_HANDLER_ARGS) } if (req->newptr != USER_ADDR_NULL) { SCTP_INP_INFO_RUNLOCK(); + SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_SYSCTL, EPERM); return EPERM; } LIST_FOREACH(inp, &sctppcbinfo.listhead, sctp_list) { @@ -624,6 +627,11 @@ SYSCTL_UINT(_net_inet_sctp, OID_AUTO, default_cc_module, CTLFLAG_RW, &sctp_default_cc_module, 0, "Default congestion control module"); + +SYSCTL_UINT(_net_inet_sctp, OID_AUTO, default_frag_interleave, CTLFLAG_RW, + &sctp_default_frag_interleave, 0, + SCTPCTL_DEFAULT_FRAG_INTERLEAVE_DESC); + SYSCTL_UINT(_net_inet_sctp, OID_AUTO, cwnd_maxburst, CTLFLAG_RW, &sctp_use_cwnd_based_maxburst, 0, "Use a CWND adjusting maxburst"); diff --git a/sys/netinet/sctp_sysctl.h b/sys/netinet/sctp_sysctl.h index 59e0922..86a0f9e 100644 --- a/sys/netinet/sctp_sysctl.h +++ b/sys/netinet/sctp_sysctl.h @@ -413,18 +413,27 @@ __FBSDID("$FreeBSD$"); #define SCTPCTL_DEFAULT_CC_MODULE_MAX 2 #define SCTPCTL_DEFAULT_CC_MODULE_DEFAULT 0 + +/* RRS - default fragment interleave */ +#define SCTPCTL_DEFAULT_FRAG_INTERLEAVE 54 +#define SCTPCTL_DEFAULT_FRAG_INTERLEAVE_DESC "Default fragment interleave level" +#define SCTPCTL_DEFAULT_FRAG_INTERLEAVE_MIN 0 +#define SCTPCTL_DEFAULT_FRAG_INTERLEAVE_MAX 2 +#define SCTPCTL_DEFAULT_FRAG_INTERLEAVE_DEFAULT 1 + + #ifdef SCTP_DEBUG /* debug: Configure debug output */ -#define SCTPCTL_DEBUG 54 +#define SCTPCTL_DEBUG 55 #define SCTPCTL_DEBUG_DESC "Configure debug output" #define SCTPCTL_DEBUG_MIN 0 #define SCTPCTL_DEBUG_MAX 0xFFFFFFFF #define SCTPCTL_DEBUG_DEFAULT 0 -#define SCTPCTL_MAXID 54 -#else #define SCTPCTL_MAXID 55 +#else +#define SCTPCTL_MAXID 56 #endif /* @@ -487,6 +496,7 @@ __FBSDID("$FreeBSD$"); { "min_residual", CTLTYPE_INT }, \ { "max_retran_chunk", CTLTYPE_INT }, \ { "sctp_logging", CTLTYPE_INT }, \ + { "frag_interleave", CTLTYPE_INT }, \ { "debug", CTLTYPE_INT }, \ } #else @@ -545,6 +555,7 @@ __FBSDID("$FreeBSD$"); { "min_residual", CTLTYPE_INT }, \ { "max_retran_chunk", CTLTYPE_INT }, \ { "sctp_logging", CTLTYPE_INT }, \ + { "frag_interleave", CTLTYPE_INT }, \ } #endif @@ -594,6 +605,7 @@ extern uint32_t sctp_cmt_pf; /* JRS - Variable for the default congestion control module */ extern uint32_t sctp_default_cc_module; +extern uint32_t sctp_default_frag_interleave; extern uint32_t sctp_use_cwnd_based_maxburst; extern uint32_t sctp_early_fr; extern uint32_t sctp_use_rttvar_cc; diff --git a/sys/netinet/sctp_timer.c b/sys/netinet/sctp_timer.c index 47720d3..a5322e5 100644 --- a/sys/netinet/sctp_timer.c +++ b/sys/netinet/sctp_timer.c @@ -234,9 +234,23 @@ sctp_threshold_management(struct sctp_inpcb *inp, struct sctp_tcb *stcb, if (net) { if ((net->dest_state & SCTP_ADDR_UNCONFIRMED) == 0) { + if (sctp_logging_level & SCTP_THRESHOLD_LOGGING) { + sctp_misc_ints(SCTP_THRESHOLD_INCR, + stcb->asoc.overall_error_count, + (stcb->asoc.overall_error_count + 1), + SCTP_FROM_SCTP_TIMER, + __LINE__); + } stcb->asoc.overall_error_count++; } } else { + if (sctp_logging_level & SCTP_THRESHOLD_LOGGING) { + sctp_misc_ints(SCTP_THRESHOLD_INCR, + stcb->asoc.overall_error_count, + (stcb->asoc.overall_error_count + 1), + SCTP_FROM_SCTP_TIMER, + __LINE__); + } stcb->asoc.overall_error_count++; } SCTPDBG(SCTP_DEBUG_TIMER4, "Overall error count for %p now %d thresh:%u state:%x\n", @@ -1726,7 +1740,7 @@ sctp_autoclose_timer(struct sctp_inpcb *inp, (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { SCTP_STAT_DECR_GAUGE32(sctps_currestab); } - asoc->state = SCTP_STATE_SHUTDOWN_SENT; + SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT); sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb, asoc->primary_destination); diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c index fa2b922..1cebfba 100644 --- a/sys/netinet/sctp_usrreq.c +++ b/sys/netinet/sctp_usrreq.c @@ -187,7 +187,7 @@ sctp_notify_mbuf(struct sctp_inpcb *inp, } totsz = ip->ip_len; - nxtsz = ntohs(icmph->icmp_seq); + nxtsz = ntohs(icmph->icmp_nextmtu); if (nxtsz == 0) { /* * old type router that does not tell us what the next size @@ -300,7 +300,7 @@ sctp_notify(struct sctp_inpcb *inp, * TCB */ sctp_abort_notification(stcb, SCTP_PEER_FAULTY); - sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_2); + (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_2); /* no need to unlock here, since the TCB is gone */ } } else { @@ -428,6 +428,7 @@ sctp_getcred(SYSCTL_HANDLER_ARGS) SCTP_INP_DECR_REF(inp); goto cred_can_cont; } + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); error = ENOENT; goto out; } @@ -463,9 +464,9 @@ sctp_abort(struct socket *so) uint32_t flags; inp = (struct sctp_inpcb *)so->so_pcb; - if (inp == 0) + if (inp == 0) { return; - + } sctp_must_try_again: flags = inp->sctp_flags; #ifdef SCTP_LOG_CLOSING @@ -512,6 +513,7 @@ sctp_attach(struct socket *so, int proto, struct thread *p) #endif inp = (struct sctp_inpcb *)so->so_pcb; if (inp != 0) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); return EINVAL; } error = SCTP_SORESERVE(so, sctp_sendspace, sctp_recvspace); @@ -558,21 +560,25 @@ sctp_attach(struct socket *so, int proto, struct thread *p) static int sctp_bind(struct socket *so, struct sockaddr *addr, struct thread *p) { - struct sctp_inpcb *inp; + struct sctp_inpcb *inp = NULL; int error; #ifdef INET6 - if (addr && addr->sa_family != AF_INET) + if (addr && addr->sa_family != AF_INET) { /* must be a v4 address! */ + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); return EINVAL; + } #endif /* INET6 */ if (addr && (addr->sa_len != sizeof(struct sockaddr_in))) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); return EINVAL; } inp = (struct sctp_inpcb *)so->so_pcb; - if (inp == 0) + if (inp == 0) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); return EINVAL; - + } error = sctp_inpcb_bind(so, addr, NULL, p); return error; } @@ -654,6 +660,7 @@ sctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, sctp_m_freem(control); control = NULL; } + SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); sctp_m_freem(m); return EINVAL; } @@ -664,6 +671,7 @@ sctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, ) { goto connected_type; } else if (addr == NULL) { + SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EDESTADDRREQ); error = EDESTADDRREQ; sctp_m_freem(m); if (control) { @@ -675,13 +683,14 @@ sctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, #ifdef INET6 if (addr->sa_family != AF_INET) { /* must be a v4 address! */ + SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EDESTADDRREQ); sctp_m_freem(m); if (control) { sctp_m_freem(control); control = NULL; } error = EDESTADDRREQ; - return EINVAL; + return EDESTADDRREQ; } #endif /* INET6 */ connected_type: @@ -731,6 +740,7 @@ sctp_disconnect(struct socket *so) inp = (struct sctp_inpcb *)so->so_pcb; if (inp == NULL) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); return (ENOTCONN); } SCTP_INP_RLOCK(inp); @@ -747,6 +757,7 @@ sctp_disconnect(struct socket *so) stcb = LIST_FIRST(&inp->sctp_asoc_list); if (stcb == NULL) { SCTP_INP_RUNLOCK(inp); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); return (EINVAL); } SCTP_TCB_LOCK(stcb); @@ -786,7 +797,7 @@ sctp_disconnect(struct socket *so) (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { SCTP_STAT_DECR_GAUGE32(sctps_currestab); } - sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_3); + (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_3); /* No unlock tcb assoc is gone */ return (0); } @@ -808,7 +819,7 @@ sctp_disconnect(struct socket *so) (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { SCTP_STAT_DECR_GAUGE32(sctps_currestab); } - asoc->state = SCTP_STATE_SHUTDOWN_SENT; + SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT); sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb, asoc->primary_destination); @@ -877,7 +888,7 @@ sctp_disconnect(struct socket *so) SCTP_STAT_DECR_GAUGE32(sctps_currestab); } SCTP_INP_RUNLOCK(inp); - sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_5); + (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_5); return (0); } } @@ -889,6 +900,7 @@ sctp_disconnect(struct socket *so) } else { /* UDP model does not support this */ SCTP_INP_RUNLOCK(inp); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); return EOPNOTSUPP; } } @@ -900,6 +912,7 @@ sctp_shutdown(struct socket *so) inp = (struct sctp_inpcb *)so->so_pcb; if (inp == 0) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); return EINVAL; } SCTP_INP_RLOCK(inp); @@ -909,6 +922,7 @@ sctp_shutdown(struct socket *so) so->so_rcv.sb_state &= ~SBS_CANTRCVMORE; /* This proc will wakeup for read and do nothing (I hope) */ SCTP_INP_RUNLOCK(inp); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); return (EOPNOTSUPP); } /* @@ -950,7 +964,7 @@ sctp_shutdown(struct socket *so) (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { SCTP_STAT_DECR_GAUGE32(sctps_currestab); } - asoc->state = SCTP_STATE_SHUTDOWN_SENT; + SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT); sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb, asoc->primary_destination); @@ -1286,9 +1300,11 @@ sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval, if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) { /* We are already connected AND the TCP model */ + SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE); return (EADDRINUSE); } if (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) { + SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); return (EINVAL); } if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { @@ -1297,6 +1313,7 @@ sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval, SCTP_INP_RUNLOCK(inp); } if (stcb) { + SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); return (EALREADY); } SCTP_INP_INCR_REF(inp); @@ -1304,6 +1321,7 @@ sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval, creat_lock_on = 1; if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) { + SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EFAULT); error = EFAULT; goto out_now; } @@ -1317,8 +1335,10 @@ sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval, creat_lock_on = 0; if (stcb) SCTP_TCB_UNLOCK(stcb); - if (bad_addresses == 0) + if (bad_addresses == 0) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); error = EALREADY; + } goto out_now; } #ifdef INET6 @@ -1337,6 +1357,7 @@ sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval, * if IPV6_V6ONLY flag, ignore connections destined * to a v4 addr or v4-mapped addr */ + SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); error = EINVAL; goto out_now; } @@ -1361,7 +1382,7 @@ sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval, /* Gak! no memory */ goto out_now; } - stcb->asoc.state = SCTP_STATE_COOKIE_WAIT; + SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_COOKIE_WAIT); /* move to second address */ if (sa->sa_family == AF_INET) sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in)); @@ -1372,7 +1393,7 @@ sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval, added = sctp_connectx_helper_add(stcb, sa, (totaddr - 1), &error); /* Fill in the return id */ if (error) { - sctp_free_assoc(inp, stcb, SCTP_PCBFREE_FORCE, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_12); + (void)sctp_free_assoc(inp, stcb, SCTP_PCBFREE_FORCE, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_12); goto out_now; } a_id = (sctp_assoc_t *) optval; @@ -1415,6 +1436,7 @@ out_now: } else if (assoc_id != 0) { \ stcb = sctp_findassociation_ep_asocid(inp, assoc_id, 1); \ if (stcb == NULL) { \ + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); \ error = ENOENT; \ break; \ } \ @@ -1426,6 +1448,7 @@ out_now: #define SCTP_CHECK_AND_CAST(destp, srcp, type, size) {\ if (size < sizeof(type)) { \ + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); \ error = EINVAL; \ break; \ } else { \ @@ -1437,16 +1460,19 @@ static int sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, void *p) { - struct sctp_inpcb *inp; + struct sctp_inpcb *inp = NULL; int error, val = 0; struct sctp_tcb *stcb = NULL; if (optval == NULL) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); return (EINVAL); } inp = (struct sctp_inpcb *)so->so_pcb; - if (inp == 0) + if (inp == 0) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); return EINVAL; + } error = 0; switch (optname) { @@ -1466,7 +1492,14 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4); break; case SCTP_AUTO_ASCONF: - val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTO_ASCONF); + if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { + /* only valid for bound all sockets */ + val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTO_ASCONF); + } else { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); + error = EINVAL; + goto flags_out; + } break; case SCTP_EXPLICIT_EOR: val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR); @@ -1485,6 +1518,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, break; default: + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); error = ENOPROTOOPT; } /* end switch (sopt->sopt_name) */ if (optname != SCTP_AUTOCLOSE) { @@ -1492,8 +1526,10 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, val = (val != 0); } if (*optsize < sizeof(val)) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); error = EINVAL; } +flags_out: SCTP_INP_RUNLOCK(inp); if (error == 0) { /* return the option value */ @@ -1511,6 +1547,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, ret = sctp_copy_out_packet_log(target, (int)*optsize); *optsize = ret; #else + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); error = EOPNOTSUPP; #endif break; @@ -1553,9 +1590,11 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, SCTP_TCB_UNLOCK(stcb); } else { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); error = ENOTCONN; } } else { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); error = ENOPROTOOPT; } *optsize = sizeof(*av); @@ -1595,6 +1634,9 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, error = 0; } #endif + if (error) + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); + *optsize = sizeof(*av); } break; @@ -1628,6 +1670,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, ids->gaids_assoc_id[at++] = sctp_get_associd(stcb); } else { error = EINVAL; + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); break; } } @@ -1669,6 +1712,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, SCTP_FIND_STCB(inp, stcb, id->assoc_id); if (stcb == NULL) { error = EINVAL; + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); break; } id->assoc_value = stcb->asoc.vrf_id; @@ -1676,6 +1720,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, } case SCTP_GET_VRF_IDS: { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); error = EOPNOTSUPP; break; } @@ -1691,6 +1736,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, gnv->gn_local_tag = stcb->asoc.my_vtag; SCTP_TCB_UNLOCK(stcb); } else { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); error = ENOTCONN; } *optsize = sizeof(*gnv); @@ -1729,6 +1775,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, stcb->asoc.size_on_all_streams); SCTP_TCB_UNLOCK(stcb); } else { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); error = ENOTCONN; } *optsize = sizeof(struct sctp_sockstat); @@ -1878,6 +1925,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, SCTP_TCB_UNLOCK(stcb); *value = (uint32_t) size; } else { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); error = ENOTCONN; } *optsize = sizeof(uint32_t); @@ -1932,6 +1980,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, } SCTP_TCB_UNLOCK(stcb); } else { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); error = ENOENT; } } @@ -1979,7 +2028,37 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, SCTP_INP_DECR_REF(inp); } } + if (stcb && (net == NULL)) { + struct sockaddr *sa; + + sa = (struct sockaddr *)&paddrp->spp_address; + if (sa->sa_family == AF_INET) { + struct sockaddr_in *sin; + sin = (struct sockaddr_in *)sa; + if (sin->sin_addr.s_addr) { + error = EINVAL; + SCTP_TCB_UNLOCK(stcb); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); + break; + } + } else if (sa->sa_family == AF_INET6) { + struct sockaddr_in6 *sin6; + + sin6 = (struct sockaddr_in6 *)sa; + if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { + error = EINVAL; + SCTP_TCB_UNLOCK(stcb); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); + break; + } + } else { + error = EAFNOSUPPORT; + SCTP_TCB_UNLOCK(stcb); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); + break; + } + } if (stcb) { /* Applys to the specific association */ paddrp->spp_flags = 0; @@ -2123,6 +2202,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, if (stcb) { SCTP_TCB_UNLOCK(stcb); } + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); error = ENOENT; } *optsize = sizeof(struct sctp_paddrinfo); @@ -2147,6 +2227,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, SCTP_FIND_STCB(inp, stcb, sstat->sstat_assoc_id); if (stcb == NULL) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); error = EINVAL; break; } @@ -2291,6 +2372,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, len); SCTP_TCB_UNLOCK(stcb); } else { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); error = EINVAL; } *optsize = sizeof(*ssp); @@ -2318,6 +2400,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, size = sizeof(*shmac) + (hmaclist->num_algo * sizeof(shmac->shmac_idents[0])); if ((size_t)(*optsize) < size) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); error = EINVAL; SCTP_INP_RUNLOCK(inp); break; @@ -2365,6 +2448,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, size = sctp_auth_get_chklist_size(chklist); if (*optsize < (sizeof(struct sctp_authchunks) + size)) { error = EINVAL; + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); } else { /* copy in the chunks */ (void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks); @@ -2378,6 +2462,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, size = sctp_auth_get_chklist_size(chklist); if (*optsize < (sizeof(struct sctp_authchunks) + size)) { error = EINVAL; + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); } else { /* copy in the chunks */ (void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks); @@ -2403,12 +2488,14 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, size = sctp_auth_get_chklist_size(chklist); if (*optsize < (sizeof(struct sctp_authchunks) + size)) { error = EINVAL; + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); } else { /* copy in the chunks */ (void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks); } SCTP_TCB_UNLOCK(stcb); } else { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); error = ENOENT; } *optsize = sizeof(struct sctp_authchunks) + size; @@ -2417,6 +2504,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, default: + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); error = ENOPROTOOPT; *optsize = 0; break; @@ -2431,16 +2519,18 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, int error, set_opt; uint32_t *mopt; struct sctp_tcb *stcb = NULL; - struct sctp_inpcb *inp; + struct sctp_inpcb *inp = NULL; uint32_t vrf_id; if (optval == NULL) { SCTP_PRINTF("optval is NULL\n"); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); return (EINVAL); } inp = (struct sctp_inpcb *)so->so_pcb; if (inp == 0) { SCTP_PRINTF("inp is NULL?\n"); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); return EINVAL; } vrf_id = inp->def_vrf_id; @@ -2464,7 +2554,16 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, set_opt = SCTP_PCB_FLAGS_NO_FRAGMENT; break; case SCTP_AUTO_ASCONF: - set_opt = SCTP_PCB_FLAGS_AUTO_ASCONF; + /* + * NOTE: we don't really support this flag + */ + if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { + /* only valid for bound all sockets */ + set_opt = SCTP_PCB_FLAGS_AUTO_ASCONF; + } else { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); + return (EINVAL); + } break; case SCTP_EXPLICIT_EOR: set_opt = SCTP_PCB_FLAGS_EXPLICIT_EOR; @@ -2476,6 +2575,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { set_opt = SCTP_PCB_FLAGS_NEEDS_MAPPED_V4; } else { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); return (EINVAL); } break; @@ -2485,6 +2585,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, case SCTP_AUTOCLOSE: if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); return (EINVAL); } set_opt = SCTP_PCB_FLAGS_AUTOCLOSE; @@ -2509,6 +2610,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, SCTP_CHECK_AND_CAST(value, optval, uint32_t, optsize); if (*value > SCTP_SB_LIMIT_RCV(so)) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); error = EINVAL; break; } @@ -2532,6 +2634,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, sctp_feature_off(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS); } else { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); error = EINVAL; } } @@ -2547,9 +2650,11 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, stcb->asoc.sctp_cmt_on_off = (uint8_t) av->assoc_value; SCTP_TCB_UNLOCK(stcb); } else { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); error = ENOTCONN; } } else { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); error = ENOPROTOOPT; } } @@ -2620,6 +2725,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, */ default: { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); error = EINVAL; SCTP_TCB_UNLOCK(stcb); break; @@ -2633,6 +2739,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, inp->sctp_ep.sctp_default_cc_module = av->assoc_value; break; default: + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); error = EINVAL; break; }; @@ -2640,6 +2747,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, } break; case SCTP_CLR_STAT_LOG: + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); error = EOPNOTSUPP; break; case SCTP_CONTEXT: @@ -2665,6 +2773,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, SCTP_CHECK_AND_CAST(default_vrfid, optval, uint32_t, optsize); if (*default_vrfid > SCTP_MAX_VRF_ID) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); error = EINVAL; break; } @@ -2673,11 +2782,13 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, } case SCTP_DEL_VRF_ID: { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); error = EOPNOTSUPP; break; } case SCTP_ADD_VRF_ID: { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); error = EOPNOTSUPP; break; } @@ -2724,8 +2835,10 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, SCTP_CHECK_AND_CAST(sauth, optval, struct sctp_authchunk, optsize); SCTP_INP_WLOCK(inp); - if (sctp_auth_add_chunk(sauth->sauth_chunk, inp->sctp_ep.local_auth_chunks)) + if (sctp_auth_add_chunk(sauth->sauth_chunk, inp->sctp_ep.local_auth_chunks)) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); error = EINVAL; + } SCTP_INP_WUNLOCK(inp); break; } @@ -2753,6 +2866,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, if (size > 0) { key = sctp_set_key(sca->sca_key, (uint32_t) size); if (key == NULL) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM); error = ENOMEM; SCTP_TCB_UNLOCK(stcb); break; @@ -2761,6 +2875,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, shared_key = sctp_alloc_sharedkey(); if (shared_key == NULL) { sctp_free_key(key); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM); error = ENOMEM; SCTP_TCB_UNLOCK(stcb); break; @@ -2785,6 +2900,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, if (size > 0) { key = sctp_set_key(sca->sca_key, (uint32_t) size); if (key == NULL) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM); error = ENOMEM; SCTP_INP_WUNLOCK(inp); break; @@ -2793,6 +2909,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, shared_key = sctp_alloc_sharedkey(); if (shared_key == NULL) { sctp_free_key(key); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM); error = ENOMEM; SCTP_INP_WUNLOCK(inp); break; @@ -2815,6 +2932,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, size = (optsize - sizeof(*shmac)) / sizeof(shmac->shmac_idents[0]); hmaclist = sctp_alloc_hmaclist(size); if (hmaclist == NULL) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM); error = ENOMEM; break; } @@ -2822,6 +2940,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, hmacid = shmac->shmac_idents[i]; if (sctp_auth_add_hmacid(hmaclist, (uint16_t) hmacid)) { /* invalid HMACs were found */ ; + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); error = EINVAL; sctp_free_hmaclist(hmaclist); goto sctp_set_hmac_done; @@ -2836,6 +2955,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, } if (!found) { sctp_free_hmaclist(hmaclist); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); error = EINVAL; break; } @@ -2858,14 +2978,18 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, /* set the active key on the right place */ if (stcb) { /* set the active key on the assoc */ - if (sctp_auth_setactivekey(stcb, scact->scact_keynumber)) + if (sctp_auth_setactivekey(stcb, scact->scact_keynumber)) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); error = EINVAL; + } SCTP_TCB_UNLOCK(stcb); } else { /* set the active key on the endpoint */ SCTP_INP_WLOCK(inp); - if (sctp_auth_setactivekey_ep(inp, scact->scact_keynumber)) + if (sctp_auth_setactivekey_ep(inp, scact->scact_keynumber)) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); error = EINVAL; + } SCTP_INP_WUNLOCK(inp); } break; @@ -2879,13 +3003,17 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, /* delete the key from the right place */ if (stcb) { - if (sctp_delete_sharedkey(stcb, scdel->scact_keynumber)) + if (sctp_delete_sharedkey(stcb, scdel->scact_keynumber)) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); error = EINVAL; + } SCTP_TCB_UNLOCK(stcb); } else { SCTP_INP_WLOCK(inp); - if (sctp_delete_sharedkey_ep(inp, scdel->scact_keynumber)) + if (sctp_delete_sharedkey_ep(inp, scdel->scact_keynumber)) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); error = EINVAL; + } SCTP_INP_WUNLOCK(inp); } break; @@ -2901,6 +3029,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, SCTP_FIND_STCB(inp, stcb, strrst->strrst_assoc_id); if (stcb == NULL) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); error = ENOENT; break; } @@ -2911,11 +3040,13 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, * for this feature and this peer, not the * socket request in general. */ + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EPROTONOSUPPORT); error = EPROTONOSUPPORT; SCTP_TCB_UNLOCK(stcb); break; } if (stcb->asoc.stream_reset_outstanding) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); error = EALREADY; SCTP_TCB_UNLOCK(stcb); break; @@ -2930,6 +3061,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, } else if (strrst->strrst_flags == SCTP_RESET_TSN) { send_tsn = 1; } else { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); error = EINVAL; SCTP_TCB_UNLOCK(stcb); break; @@ -2938,11 +3070,13 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, if ((send_in) && (strrst->strrst_list[i] > stcb->asoc.streamincnt)) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); error = EINVAL; goto get_out; } if ((send_out) && (strrst->strrst_list[i] > stcb->asoc.streamoutcnt)) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); error = EINVAL; goto get_out; } @@ -2964,6 +3098,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, case SCTP_CONNECT_X: if (optsize < (sizeof(int) + sizeof(struct sockaddr_in))) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); error = EINVAL; break; } @@ -2972,6 +3107,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, case SCTP_CONNECT_X_DELAYED: if (optsize < (sizeof(int) + sizeof(struct sockaddr_in))) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); error = EINVAL; break; } @@ -3011,6 +3147,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, } if (stcb == NULL) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); error = ENOENT; break; } @@ -3026,6 +3163,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, * already expired or did not use delayed * connectx */ + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); error = EALREADY; } SCTP_TCB_UNLOCK(stcb); @@ -3182,6 +3320,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, if (s_info->sinfo_stream <= stcb->asoc.streamoutcnt) { memcpy(&stcb->asoc.def_send, s_info, min(optsize, sizeof(stcb->asoc.def_send))); } else { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); error = EINVAL; } SCTP_TCB_UNLOCK(stcb); @@ -3219,15 +3358,48 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, SCTP_INP_DECR_REF(inp); } } + if (stcb && (net == NULL)) { + struct sockaddr *sa; + + sa = (struct sockaddr *)&paddrp->spp_address; + if (sa->sa_family == AF_INET) { + struct sockaddr_in *sin; + + sin = (struct sockaddr_in *)sa; + if (sin->sin_addr.s_addr) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); + SCTP_TCB_UNLOCK(stcb); + error = EINVAL; + break; + } + } else if (sa->sa_family == AF_INET6) { + struct sockaddr_in6 *sin6; + + sin6 = (struct sockaddr_in6 *)sa; + if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); + SCTP_TCB_UNLOCK(stcb); + error = EINVAL; + break; + } + } else { + error = EAFNOSUPPORT; + SCTP_TCB_UNLOCK(stcb); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); + break; + } + } /* sanity checks */ if ((paddrp->spp_flags & SPP_HB_ENABLE) && (paddrp->spp_flags & SPP_HB_DISABLE)) { if (stcb) SCTP_TCB_UNLOCK(stcb); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); return (EINVAL); } if ((paddrp->spp_flags & SPP_PMTUD_ENABLE) && (paddrp->spp_flags & SPP_PMTUD_DISABLE)) { if (stcb) SCTP_TCB_UNLOCK(stcb); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); return (EINVAL); } if (stcb) { @@ -3256,6 +3428,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, /* on demand HB */ if (sctp_send_hb(stcb, 1, net) < 0) { /* asoc destroyed */ + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); error = EINVAL; break; } @@ -3430,6 +3603,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, stcb->asoc.maxrto = new_max; stcb->asoc.minrto = new_min; } else { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EDOM); error = EDOM; } SCTP_TCB_UNLOCK(stcb); @@ -3452,6 +3626,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, inp->sctp_ep.sctp_maxrto = new_max; inp->sctp_ep.sctp_minrto = new_min; } else { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EDOM); error = EDOM; } SCTP_INP_WUNLOCK(inp); @@ -3557,6 +3732,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, } } } else { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); error = EINVAL; } if (stcb) { @@ -3590,6 +3766,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, ifa = sctp_find_ifa_by_addr((struct sockaddr *)&sspp->sspp_addr, stcb->asoc.vrf_id, 0); if (ifa == NULL) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); error = EINVAL; goto out_of_it; } @@ -3613,17 +3790,20 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, } } if (!found) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); error = EINVAL; goto out_of_it; } } if (sctp_set_primary_ip_address_sa(stcb, (struct sockaddr *)&sspp->sspp_addr) != 0) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); error = EINVAL; } out_of_it: SCTP_TCB_UNLOCK(stcb); } else { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); error = EINVAL; } @@ -3645,15 +3825,18 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, if (addrs->addr->sa_family == AF_INET) { sz = sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in); if (optsize < sz) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); error = EINVAL; break; } if (prison && prison_ip(td->td_ucred, 0, &(((struct sockaddr_in *)(addrs->addr))->sin_addr.s_addr))) { + SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRNOTAVAIL); error = EADDRNOTAVAIL; } } else if (addrs->addr->sa_family == AF_INET6) { sz = sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in6); if (optsize < sz) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); error = EINVAL; break; } @@ -3679,15 +3862,18 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, if (addrs->addr->sa_family == AF_INET) { sz = sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in); if (optsize < sz) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); error = EINVAL; break; } if (prison && prison_ip(td->td_ucred, 0, &(((struct sockaddr_in *)(addrs->addr))->sin_addr.s_addr))) { + SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRNOTAVAIL); error = EADDRNOTAVAIL; } } else if (addrs->addr->sa_family == AF_INET6) { sz = sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in6); if (optsize < sz) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); error = EINVAL; break; } @@ -3699,6 +3885,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, } break; default: + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); error = ENOPROTOOPT; break; } /* end switch (opt) */ @@ -3718,6 +3905,7 @@ sctp_ctloutput(struct socket *so, struct sockopt *sopt) inp = (struct sctp_inpcb *)so->so_pcb; if (inp == 0) { /* I made the same as TCP since we are not setup? */ + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); return (ECONNRESET); } if (sopt->sopt_level != IPPROTO_SCTP) { @@ -3734,6 +3922,7 @@ sctp_ctloutput(struct socket *so, struct sockopt *sopt) if (optsize) { SCTP_MALLOC(optval, void *, optsize, SCTP_M_SOCKOPT); if (optval == NULL) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOBUFS); return (ENOBUFS); } error = sooptcopyin(sopt, optval, optsize, optsize); @@ -3748,6 +3937,7 @@ sctp_ctloutput(struct socket *so, struct sockopt *sopt) } else if (sopt->sopt_dir == SOPT_GET) { error = sctp_getopt(so, sopt->sopt_name, optval, &optsize, p); } else { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); error = EINVAL; } if ((error == 0) && (optval != NULL)) { @@ -3773,15 +3963,19 @@ sctp_connect(struct socket *so, struct sockaddr *addr, struct thread *p) inp = (struct sctp_inpcb *)so->so_pcb; if (inp == 0) { /* I made the same as TCP since we are not setup? */ + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); return (ECONNRESET); } - if (addr == NULL) + if (addr == NULL) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); return EINVAL; - + } if ((addr->sa_family == AF_INET6) && (addr->sa_len != sizeof(struct sockaddr_in6))) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); return (EINVAL); } if ((addr->sa_family == AF_INET) && (addr->sa_len != sizeof(struct sockaddr_in))) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); return (EINVAL); } SCTP_ASOC_CREATE_LOCK(inp); @@ -3791,12 +3985,14 @@ sctp_connect(struct socket *so, struct sockaddr *addr, struct thread *p) if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) { /* Should I really unlock ? */ + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EFAULT); error = EFAULT; goto out_now; } #ifdef INET6 if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) && (addr->sa_family == AF_INET6)) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); error = EINVAL; goto out_now; } @@ -3811,12 +4007,14 @@ sctp_connect(struct socket *so, struct sockaddr *addr, struct thread *p) } /* Now do we connect? */ if (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); error = EINVAL; goto out_now; } if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) { /* We are already connected AND the TCP model */ + SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE); error = EADDRINUSE; goto out_now; } @@ -3840,6 +4038,7 @@ sctp_connect(struct socket *so, struct sockaddr *addr, struct thread *p) } if (stcb != NULL) { /* Already have or am bring up an association */ + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); error = EALREADY; goto out_now; } @@ -3855,7 +4054,7 @@ sctp_connect(struct socket *so, struct sockaddr *addr, struct thread *p) /* Set the connected flag so we can queue data */ soisconnecting(so); } - stcb->asoc.state = SCTP_STATE_COOKIE_WAIT; + SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_COOKIE_WAIT); (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); /* initialize authentication parameters for the assoc */ @@ -3889,6 +4088,7 @@ sctp_listen(struct socket *so, int backlog, struct thread *p) inp = (struct sctp_inpcb *)so->so_pcb; if (inp == 0) { /* I made the same as TCP since we are not setup? */ + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); return (ECONNRESET); } SCTP_INP_RLOCK(inp); @@ -3909,6 +4109,7 @@ sctp_listen(struct socket *so, int backlog, struct thread *p) /* We are already connected AND the TCP model */ SCTP_INP_RUNLOCK(inp); SOCK_UNLOCK(so); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE); return (EADDRINUSE); } if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) { @@ -3951,20 +4152,24 @@ sctp_accept(struct socket *so, struct sockaddr **addr) inp = (struct sctp_inpcb *)so->so_pcb; if (inp == 0) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); return (ECONNRESET); } SCTP_INP_RLOCK(inp); if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) { SCTP_INP_RUNLOCK(inp); - return (ENOTSUP); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); + return (EOPNOTSUPP); } if (so->so_state & SS_ISDISCONNECTED) { SCTP_INP_RUNLOCK(inp); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ECONNABORTED); return (ECONNABORTED); } stcb = LIST_FIRST(&inp->sctp_asoc_list); if (stcb == NULL) { SCTP_INP_RUNLOCK(inp); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); return (ECONNRESET); } SCTP_TCB_LOCK(stcb); @@ -4044,6 +4249,7 @@ sctp_ingetaddr(struct socket *so, struct sockaddr **addr) inp = (struct sctp_inpcb *)so->so_pcb; if (!inp) { SCTP_FREE_SONAME(sin); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); return ECONNRESET; } SCTP_INP_RLOCK(inp); @@ -4112,6 +4318,7 @@ sctp_ingetaddr(struct socket *so, struct sockaddr **addr) if (!fnd) { SCTP_FREE_SONAME(sin); SCTP_INP_RUNLOCK(inp); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); return ENOENT; } } @@ -4135,6 +4342,7 @@ sctp_peeraddr(struct socket *so, struct sockaddr **addr) if ((inp == NULL) || ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)) { /* UDP type and listeners will drop out here */ + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); return (ENOTCONN); } SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin); @@ -4145,6 +4353,7 @@ sctp_peeraddr(struct socket *so, struct sockaddr **addr) inp = (struct sctp_inpcb *)so->so_pcb; if (!inp) { SCTP_FREE_SONAME(sin); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); return ECONNRESET; } SCTP_INP_RLOCK(inp); @@ -4155,6 +4364,7 @@ sctp_peeraddr(struct socket *so, struct sockaddr **addr) SCTP_INP_RUNLOCK(inp); if (stcb == NULL) { SCTP_FREE_SONAME(sin); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); return ECONNRESET; } fnd = 0; @@ -4171,6 +4381,7 @@ sctp_peeraddr(struct socket *so, struct sockaddr **addr) if (!fnd) { /* No IPv4 address */ SCTP_FREE_SONAME(sin); + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); return ENOENT; } (*addr) = (struct sockaddr *)sin; diff --git a/sys/netinet/sctp_var.h b/sys/netinet/sctp_var.h index 38c694b..ba33d9e 100644 --- a/sys/netinet/sctp_var.h +++ b/sys/netinet/sctp_var.h @@ -167,16 +167,10 @@ extern struct pr_usrreqs sctp_usrreqs; if (val < SCTP_BUF_LEN((m))) {\ panic("stcb->sb_cc goes negative"); \ } \ - val = atomic_fetchadd_int(&(stcb)->asoc.sb_mbcnt,-(MSIZE)); \ + val = atomic_fetchadd_int(&(stcb)->asoc.my_rwnd_control_len,-(MSIZE)); \ if (val < MSIZE) { \ panic("asoc->mbcnt goes negative"); \ } \ - if (SCTP_BUF_IS_EXTENDED(m)) { \ - val = atomic_fetchadd_int(&(stcb)->asoc.sb_mbcnt,-(SCTP_BUF_EXTEND_SIZE(m))); \ - if (val < SCTP_BUF_EXTEND_SIZE(m)) { \ - panic("assoc stcb->mbcnt would go negative"); \ - } \ - } \ } \ if (SCTP_BUF_TYPE(m) != MT_DATA && SCTP_BUF_TYPE(m) != MT_HEADER && \ SCTP_BUF_TYPE(m) != MT_OOBDATA) \ @@ -191,9 +185,7 @@ extern struct pr_usrreqs sctp_usrreqs; atomic_add_int(&(sb)->sb_mbcnt,SCTP_BUF_EXTEND_SIZE(m)); \ if (stcb) { \ atomic_add_int(&(stcb)->asoc.sb_cc,SCTP_BUF_LEN((m))); \ - atomic_add_int(&(stcb)->asoc.sb_mbcnt, MSIZE); \ - if (SCTP_BUF_IS_EXTENDED(m)) \ - atomic_add_int(&(stcb)->asoc.sb_mbcnt,SCTP_BUF_EXTEND_SIZE(m)); \ + atomic_add_int(&(stcb)->asoc.my_rwnd_control_len, MSIZE); \ } \ if (SCTP_BUF_TYPE(m) != MT_DATA && SCTP_BUF_TYPE(m) != MT_HEADER && \ SCTP_BUF_TYPE(m) != MT_OOBDATA) \ @@ -291,6 +283,7 @@ extern struct pr_usrreqs sctp_usrreqs; #endif + struct sctp_nets; struct sctp_inpcb; struct sctp_tcb; diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c index e7e0987..76dfc28 100644 --- a/sys/netinet/sctputil.c +++ b/sys/netinet/sctputil.c @@ -71,7 +71,7 @@ sctp_sblog(struct sockbuf *sb, else sctp_clog.x.sb.stcb_sbcc = 0; sctp_clog.x.sb.incr = incr; - CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", + SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", SCTP_LOG_EVENT_SB, from, sctp_clog.x.misc.log1, @@ -95,7 +95,7 @@ sctp_log_closing(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int16_t loc) sctp_clog.x.close.state = 0; } sctp_clog.x.close.loc = loc; - CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", + SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", SCTP_LOG_EVENT_CLOSE, 0, sctp_clog.x.misc.log1, @@ -112,7 +112,7 @@ rto_logging(struct sctp_nets *net, int from) sctp_clog.x.rto.net = (void *)net; sctp_clog.x.rto.rtt = net->prev_rtt; - CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", + SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", SCTP_LOG_EVENT_RTT, from, sctp_clog.x.misc.log1, @@ -133,7 +133,7 @@ sctp_log_strm_del_alt(struct sctp_tcb *stcb, uint32_t tsn, uint16_t sseq, uint16 sctp_clog.x.strlog.e_tsn = 0; sctp_clog.x.strlog.e_sseq = 0; sctp_clog.x.strlog.strm = stream; - CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", + SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", SCTP_LOG_EVENT_STRM, from, sctp_clog.x.misc.log1, @@ -153,7 +153,7 @@ sctp_log_nagle_event(struct sctp_tcb *stcb, int action) sctp_clog.x.nagle.total_in_queue = stcb->asoc.total_output_queue_size; sctp_clog.x.nagle.count_in_queue = stcb->asoc.chunks_on_out_queue; sctp_clog.x.nagle.count_in_flight = stcb->asoc.total_flight_count; - CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", + SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", SCTP_LOG_EVENT_NAGLE, action, sctp_clog.x.misc.log1, @@ -173,7 +173,7 @@ sctp_log_sack(uint32_t old_cumack, uint32_t cumack, uint32_t tsn, uint16_t gaps, sctp_clog.x.sack.tsn = tsn; sctp_clog.x.sack.numGaps = gaps; sctp_clog.x.sack.numDups = dups; - CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", + SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", SCTP_LOG_EVENT_SACK, from, sctp_clog.x.misc.log1, @@ -190,7 +190,7 @@ sctp_log_map(uint32_t map, uint32_t cum, uint32_t high, int from) sctp_clog.x.map.base = map; sctp_clog.x.map.cum = cum; sctp_clog.x.map.high = high; - CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", + SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", SCTP_LOG_EVENT_MAP, from, sctp_clog.x.misc.log1, @@ -208,7 +208,7 @@ sctp_log_fr(uint32_t biggest_tsn, uint32_t biggest_new_tsn, uint32_t tsn, sctp_clog.x.fr.largest_tsn = biggest_tsn; sctp_clog.x.fr.largest_new_tsn = biggest_new_tsn; sctp_clog.x.fr.tsn = tsn; - CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", + SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", SCTP_LOG_EVENT_FR, from, sctp_clog.x.misc.log1, @@ -235,7 +235,7 @@ sctp_log_mb(struct mbuf *m, int from) sctp_clog.x.mb.ext = 0; sctp_clog.x.mb.refcnt = 0; } - CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", + SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", SCTP_LOG_EVENT_MBUF, from, sctp_clog.x.misc.log1, @@ -266,7 +266,7 @@ sctp_log_strm_del(struct sctp_queued_to_read *control, struct sctp_queued_to_rea sctp_clog.x.strlog.e_tsn = 0; sctp_clog.x.strlog.e_sseq = 0; } - CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", + SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", SCTP_LOG_EVENT_STRM, from, sctp_clog.x.misc.log1, @@ -302,7 +302,7 @@ sctp_log_cwnd(struct sctp_tcb *stcb, struct sctp_nets *net, int augment, uint8_t sctp_clog.x.cwnd.meets_pseudo_cumack = stcb->asoc.peers_rwnd; } sctp_clog.x.cwnd.cwnd_augment = augment; - CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", + SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", SCTP_LOG_EVENT_CWND, from, sctp_clog.x.misc.log1, @@ -346,7 +346,7 @@ sctp_log_lock(struct sctp_inpcb *inp, struct sctp_tcb *stcb, uint8_t from) sctp_clog.x.lock.sockrcvbuf_lock = SCTP_LOCK_UNKNOWN; sctp_clog.x.lock.socksndbuf_lock = SCTP_LOCK_UNKNOWN; } - CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", + SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", SCTP_LOG_LOCK_EVENT, from, sctp_clog.x.misc.log1, @@ -373,7 +373,7 @@ sctp_log_maxburst(struct sctp_tcb *stcb, struct sctp_nets *net, int error, int b sctp_clog.x.cwnd.cnt_in_str = 255; else sctp_clog.x.cwnd.cnt_in_str = stcb->asoc.stream_queue_cnt; - CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", + SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", SCTP_LOG_EVENT_MAXBURST, from, sctp_clog.x.misc.log1, @@ -392,7 +392,7 @@ sctp_log_rwnd(uint8_t from, uint32_t peers_rwnd, uint32_t snd_size, uint32_t ove sctp_clog.x.rwnd.send_size = snd_size; sctp_clog.x.rwnd.overhead = overhead; sctp_clog.x.rwnd.new_rwnd = 0; - CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", + SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", SCTP_LOG_EVENT_RWND, from, sctp_clog.x.misc.log1, @@ -410,7 +410,7 @@ sctp_log_rwnd_set(uint8_t from, uint32_t peers_rwnd, uint32_t flight_size, uint3 sctp_clog.x.rwnd.send_size = flight_size; sctp_clog.x.rwnd.overhead = overhead; sctp_clog.x.rwnd.new_rwnd = a_rwndval; - CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", + SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", SCTP_LOG_EVENT_RWND, from, sctp_clog.x.misc.log1, @@ -428,7 +428,7 @@ sctp_log_mbcnt(uint8_t from, uint32_t total_oq, uint32_t book, uint32_t total_mb sctp_clog.x.mbcnt.size_change = book; sctp_clog.x.mbcnt.total_queue_mb_size = total_mbcnt_q; sctp_clog.x.mbcnt.mbcnt_change = mbcnt; - CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", + SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", SCTP_LOG_EVENT_MBCNT, from, sctp_clog.x.misc.log1, @@ -441,7 +441,7 @@ sctp_log_mbcnt(uint8_t from, uint32_t total_oq, uint32_t book, uint32_t total_mb void sctp_misc_ints(uint8_t from, uint32_t a, uint32_t b, uint32_t c, uint32_t d) { - CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", + SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", SCTP_LOG_MISC_EVENT, from, a, b, c, d); @@ -484,7 +484,7 @@ sctp_wakeup_log(struct sctp_tcb *stcb, uint32_t cumtsn, uint32_t wake_cnt, int f } else { sctp_clog.x.wake.sbflags = 0xff; } - CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", + SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", SCTP_LOG_EVENT_WAKE, from, sctp_clog.x.misc.log1, @@ -506,7 +506,7 @@ sctp_log_block(uint8_t from, struct socket *so, struct sctp_association *asoc, i sctp_clog.x.blk.chunks_on_oque = (uint16_t) asoc->chunks_on_out_queue; sctp_clog.x.blk.flight_size = (uint16_t) (asoc->total_flight / 1024); sctp_clog.x.blk.sndlen = sendlen; - CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", + SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", SCTP_LOG_EVENT_BLOCK, from, sctp_clog.x.misc.log1, @@ -876,7 +876,7 @@ sctp_init_asoc(struct sctp_inpcb *m, struct sctp_tcb *stcb, asoc = &stcb->asoc; /* init all variables to a known value. */ - asoc->state = SCTP_STATE_INUSE; + SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_INUSE); asoc->max_burst = m->sctp_ep.max_burst; asoc->heart_beat_delay = TICKS_TO_MSEC(m->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT]); asoc->cookie_life = m->sctp_ep.def_cookie_life; @@ -902,6 +902,7 @@ sctp_init_asoc(struct sctp_inpcb *m, struct sctp_tcb *stcb, if (sctp_is_vtag_good(m, override_tag, &now)) { asoc->my_vtag = override_tag; } else { + SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOMEM); return (ENOMEM); } @@ -1095,6 +1096,7 @@ sctp_init_asoc(struct sctp_inpcb *m, struct sctp_tcb *stcb, SCTP_M_STRMO); if (asoc->strmout == NULL) { /* big trouble no memory */ + SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOMEM); return (ENOMEM); } for (i = 0; i < asoc->streamoutcnt; i++) { @@ -1119,6 +1121,7 @@ sctp_init_asoc(struct sctp_inpcb *m, struct sctp_tcb *stcb, SCTP_M_MAP); if (asoc->mapping_array == NULL) { SCTP_FREE(asoc->strmout, SCTP_M_STRMO); + SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOMEM); return (ENOMEM); } memset(asoc->mapping_array, 0, asoc->mapping_array_size); @@ -1219,8 +1222,6 @@ select_a_new_ep: SCTP_INP_WLOCK(it->inp); } - /* mark the current iterator on the endpoint */ - it->inp->inp_starting_point_for_iterator = it; SCTP_INP_WUNLOCK(it->inp); SCTP_INP_RLOCK(it->inp); @@ -1243,10 +1244,6 @@ select_a_new_ep: SCTP_INP_RUNLOCK(it->inp); goto no_stcb; } - if ((it->stcb) && - (it->stcb->asoc.stcb_starting_point_for_iterator == it)) { - it->stcb->asoc.stcb_starting_point_for_iterator = NULL; - } while (it->stcb) { SCTP_TCB_LOCK(it->stcb); if (it->asoc_state && ((it->stcb->asoc.state & it->asoc_state) != it->asoc_state)) { @@ -1254,18 +1251,20 @@ select_a_new_ep: SCTP_TCB_UNLOCK(it->stcb); goto next_assoc; } - /* mark the current iterator on the assoc */ - it->stcb->asoc.stcb_starting_point_for_iterator = it; /* see if we have limited out the iterator loop */ iteration_count++; if (iteration_count > SCTP_ITERATOR_MAX_AT_ONCE) { /* Pause to let others grab the lock */ atomic_add_int(&it->stcb->asoc.refcnt, 1); SCTP_TCB_UNLOCK(it->stcb); + + SCTP_INP_INCR_REF(it->inp); SCTP_INP_RUNLOCK(it->inp); SCTP_ITERATOR_UNLOCK(); SCTP_ITERATOR_LOCK(); SCTP_INP_RLOCK(it->inp); + + SCTP_INP_DECR_REF(it->inp); SCTP_TCB_LOCK(it->stcb); atomic_add_int(&it->stcb->asoc.refcnt, -1); iteration_count = 0; @@ -1297,7 +1296,6 @@ no_stcb: /* done with all assocs on this endpoint, move on to next endpoint */ it->done_current_ep = 0; SCTP_INP_WLOCK(it->inp); - it->inp->inp_starting_point_for_iterator = NULL; SCTP_INP_WUNLOCK(it->inp); if (it->iterator_flags & SCTP_ITERATOR_DO_SINGLE_INP) { it->inp = NULL; @@ -1582,10 +1580,15 @@ sctp_timeout_handler(void *t) case SCTP_TIMER_TYPE_RECV: if ((stcb == NULL) || (inp == NULL)) { break; + } { + int abort_flag; + + SCTP_STAT_INCR(sctps_timosack); + stcb->asoc.timosack++; + if (stcb->asoc.cumulative_tsn != stcb->asoc.highest_tsn_inside_map) + sctp_sack_check(stcb, 0, 0, &abort_flag); + sctp_send_sack(stcb); } - SCTP_STAT_INCR(sctps_timosack); - stcb->asoc.timosack++; - sctp_send_sack(stcb); #ifdef SCTP_AUDITING_ENABLED sctp_auditing(4, inp, stcb, net); #endif @@ -1769,7 +1772,7 @@ sctp_timeout_handler(void *t) /* Can we free it yet? */ SCTP_INP_DECR_REF(inp); sctp_timer_stop(SCTP_TIMER_TYPE_ASOCKILL, inp, stcb, NULL, SCTP_FROM_SCTPUTIL + SCTP_LOC_1); - sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTPUTIL + SCTP_LOC_2); + (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTPUTIL + SCTP_LOC_2); /* * free asoc, always unlocks (or destroy's) so prevent * duplicate unlock or unlock of a free mtx :-0 @@ -2176,7 +2179,7 @@ sctp_timer_start(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb, tmr->tcb = (void *)stcb; tmr->net = (void *)net; tmr->self = (void *)tmr; - tmr->ticks = ticks; + tmr->ticks = sctp_get_tick_count(); (void)SCTP_OS_TIMER_START(&tmr->timer, to_ticks, sctp_timeout_handler, tmr); return; } @@ -2767,6 +2770,7 @@ sctp_add_pad_tombuf(struct mbuf *m, int padlen) int i; if (padlen > 3) { + SCTP_LTRACE_ERR_RET_PKT(m, NULL, NULL, NULL, SCTP_FROM_SCTPUTIL, ENOBUFS); return (ENOBUFS); } if (M_TRAILINGSPACE(m)) { @@ -2783,6 +2787,7 @@ sctp_add_pad_tombuf(struct mbuf *m, int padlen) tmp = sctp_get_mbuf_for_msg(padlen, 0, M_DONTWAIT, 1, MT_DATA); if (tmp == NULL) { /* Out of space GAK! we are in big trouble. */ + SCTP_LTRACE_ERR_RET_PKT(m, NULL, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); return (ENOSPC); } /* setup and insert in middle */ @@ -2816,6 +2821,7 @@ sctp_pad_lastmbuf(struct mbuf *m, int padval, struct mbuf *last_mbuf) m_at = SCTP_BUF_NEXT(m_at); } } + SCTP_LTRACE_ERR_RET_PKT(m, NULL, NULL, NULL, SCTP_FROM_SCTPUTIL, EFAULT); return (EFAULT); } @@ -2849,10 +2855,13 @@ sctp_notify_assoc_change(uint32_t event, struct sctp_tcb *stcb, if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) && ((event == SCTP_COMM_LOST) || (event == SCTP_CANT_STR_ASSOC))) { - if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_WAIT) + if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_WAIT) { + SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ECONNREFUSED); stcb->sctp_socket->so_error = ECONNREFUSED; - else + } else { + SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ECONNRESET); stcb->sctp_socket->so_error = ECONNRESET; + } /* Wake ANY sleepers */ sorwakeup(stcb->sctp_socket); sowwakeup(stcb->sctp_socket); @@ -3658,7 +3667,7 @@ sctp_abort_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb, sctp_send_abort(m, iphlen, sh, vtag, op_err, vrf_id); if (stcb != NULL) { /* Ok, now lets free it */ - sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTPUTIL + SCTP_LOC_4); + (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTPUTIL + SCTP_LOC_4); } else { if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { if (LIST_FIRST(&inp->sctp_asoc_list) == NULL) { @@ -3766,7 +3775,7 @@ sctp_abort_an_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb, #ifdef SCTP_ASOCLOG_OF_TSNS sctp_print_out_track_log(stcb); #endif - sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTPUTIL + SCTP_LOC_5); + (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTPUTIL + SCTP_LOC_5); } void @@ -4687,6 +4696,7 @@ sctp_sorecvmsg(struct socket *so, int sockbuf_lock = 0; if (uio == NULL) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); return (EINVAL); } if (msg_flags) { @@ -4704,6 +4714,7 @@ sctp_sorecvmsg(struct socket *so, return (EOPNOTSUPP); } if ((in_flags & MSG_PEEK) && (mp != NULL)) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); return (EINVAL); } if ((in_flags & (MSG_DONTWAIT @@ -4715,6 +4726,7 @@ sctp_sorecvmsg(struct socket *so, /* setup the endpoint */ inp = (struct sctp_inpcb *)so->so_pcb; if (inp == NULL) { + SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTPUTIL, EFAULT); return (EFAULT); } rwnd_req = (SCTP_SB_LIMIT_RCV(so) >> SCTP_RWND_HIWAT_SHIFT); @@ -4753,6 +4765,7 @@ restart_nosblocks: if ((in_flags & MSG_PEEK) == 0) so->so_error = 0; } else { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, ENOTCONN); error = ENOTCONN; } goto out; @@ -4773,6 +4786,7 @@ restart_nosblocks: * You were aborted, passive side * always hits here */ + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, ECONNRESET); error = ECONNRESET; /* * You get this once if you are @@ -4792,6 +4806,7 @@ restart_nosblocks: SS_ISCONNECTED); if (error == 0) { if ((inp->sctp_flags & SCTP_PCB_FLAGS_WAS_CONNECTED) == 0) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, ENOTCONN); error = ENOTCONN; } else { inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAS_CONNECTED; @@ -4825,6 +4840,7 @@ restart_nosblocks: * You were aborted, passive * side always hits here */ + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, ECONNRESET); error = ECONNRESET; /* * You get this once if you @@ -4845,6 +4861,7 @@ restart_nosblocks: SS_ISCONNECTED); if (error == 0) { if ((inp->sctp_flags & SCTP_PCB_FLAGS_WAS_CONNECTED) == 0) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, ENOTCONN); error = ENOTCONN; } else { inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAS_CONNECTED; @@ -4853,6 +4870,7 @@ restart_nosblocks: goto out; } } + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EWOULDBLOCK); error = EWOULDBLOCK; } goto out; @@ -5216,6 +5234,7 @@ get_more_data: embuf = m; copied_so_far += cp_len; freed_so_far += cp_len; + freed_so_far += MSIZE; atomic_subtract_int(&control->length, cp_len); control->data = sctp_m_free(m); m = control->data; @@ -5266,6 +5285,7 @@ get_more_data: copied_so_far += cp_len; embuf = m; freed_so_far += cp_len; + freed_so_far += MSIZE; if (sctp_logging_level & SCTP_SB_LOGGING_ENABLE) { sctp_sblog(&so->so_rcv, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0); @@ -5483,6 +5503,7 @@ wait_some_more: } sctp_sbfree(control, stcb, &so->so_rcv, m); freed_so_far += SCTP_BUF_LEN(m); + freed_so_far += MSIZE; if (sctp_logging_level & SCTP_SB_LOGGING_ENABLE) { sctp_sblog(&so->so_rcv, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0); @@ -5612,6 +5633,7 @@ sctp_dynamic_set_primary(struct sockaddr *sa, uint32_t vrf_id) ifa = sctp_find_ifa_by_addr(sa, vrf_id, 0); if (ifa == NULL) { + SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTPUTIL, EADDRNOTAVAIL); return (EADDRNOTAVAIL); } /* @@ -5620,6 +5642,7 @@ sctp_dynamic_set_primary(struct sockaddr *sa, uint32_t vrf_id) */ wi = SCTP_ZONE_GET(sctppcbinfo.ipi_zone_laddr, struct sctp_laddr); if (wi == NULL) { + SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTPUTIL, ENOMEM); return (ENOMEM); } /* Now incr the count and int wi structure */ @@ -5666,6 +5689,7 @@ sctp_soreceive(struct socket *so, inp = (struct sctp_inpcb *)so->so_pcb; /* pickup the assoc we are reading from */ if (inp == NULL) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); return (EINVAL); } if ((sctp_is_feature_off(inp, @@ -5723,6 +5747,7 @@ sctp_l_soreceive(struct socket *so, inp = (struct sctp_inpcb *)so->so_pcb; /* pickup the assoc we are reading from */ if (inp == NULL) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); return (EINVAL); } if ((sctp_is_feature_off(inp, @@ -5790,7 +5815,8 @@ sctp_connectx_helper_add(struct sctp_tcb *stcb, struct sockaddr *addr, incr = sizeof(struct sockaddr_in); if (sctp_add_remote_addr(stcb, sa, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) { /* assoc gone no un-lock */ - sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_7); + SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOBUFS); + (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_7); *error = ENOBUFS; goto out_now; } @@ -5799,7 +5825,8 @@ sctp_connectx_helper_add(struct sctp_tcb *stcb, struct sockaddr *addr, incr = sizeof(struct sockaddr_in6); if (sctp_add_remote_addr(stcb, sa, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) { /* assoc gone no un-lock */ - sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_8); + SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOBUFS); + (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_8); *error = ENOBUFS; goto out_now; } @@ -5829,6 +5856,7 @@ sctp_connectx_helper_find(struct sctp_inpcb *inp, struct sockaddr *addr, (*num_v4) += 1; incr = sizeof(struct sockaddr_in); if (sa->sa_len != incr) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); *error = EINVAL; *bad_addr = 1; return (NULL); @@ -5839,6 +5867,7 @@ sctp_connectx_helper_find(struct sctp_inpcb *inp, struct sockaddr *addr, sin6 = (struct sockaddr_in6 *)sa; if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { /* Must be non-mapped for connectx */ + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); *error = EINVAL; *bad_addr = 1; return (NULL); @@ -5846,6 +5875,7 @@ sctp_connectx_helper_find(struct sctp_inpcb *inp, struct sockaddr *addr, (*num_v6) += 1; incr = sizeof(struct sockaddr_in6); if (sa->sa_len != incr) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); *error = EINVAL; *bad_addr = 1; return (NULL); @@ -5886,6 +5916,7 @@ sctp_bindx_add_address(struct socket *so, struct sctp_inpcb *inp, /* see if we're bound all already! */ if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); *error = EINVAL; return; } @@ -5895,11 +5926,13 @@ sctp_bindx_add_address(struct socket *so, struct sctp_inpcb *inp, struct sockaddr_in6 *sin6; if (sa->sa_len != sizeof(struct sockaddr_in6)) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); *error = EINVAL; return; } if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) { /* can only bind v6 on PF_INET6 sockets */ + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); *error = EINVAL; return; } @@ -5908,6 +5941,7 @@ sctp_bindx_add_address(struct socket *so, struct sctp_inpcb *inp, if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && SCTP_IPV6_V6ONLY(inp)) { /* can't bind v4-mapped on PF_INET sockets */ + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); *error = EINVAL; return; } @@ -5918,12 +5952,14 @@ sctp_bindx_add_address(struct socket *so, struct sctp_inpcb *inp, #endif if (sa->sa_family == AF_INET) { if (sa->sa_len != sizeof(struct sockaddr_in)) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); *error = EINVAL; return; } if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && SCTP_IPV6_V6ONLY(inp)) { /* can't bind v4 on PF_INET sockets */ + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); *error = EINVAL; return; } @@ -5931,6 +5967,7 @@ sctp_bindx_add_address(struct socket *so, struct sctp_inpcb *inp, if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) { if (p == NULL) { /* Can't get proc for Net/Open BSD */ + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); *error = EINVAL; return; } @@ -5950,6 +5987,7 @@ sctp_bindx_add_address(struct socket *so, struct sctp_inpcb *inp, /* validate the incoming port */ if ((lsin->sin_port != 0) && (lsin->sin_port != inp->sctp_lport)) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); *error = EINVAL; return; } else { @@ -6000,6 +6038,7 @@ sctp_bindx_delete_address(struct socket *so, struct sctp_inpcb *inp, /* see if we're bound all already! */ if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); *error = EINVAL; return; } @@ -6009,11 +6048,13 @@ sctp_bindx_delete_address(struct socket *so, struct sctp_inpcb *inp, struct sockaddr_in6 *sin6; if (sa->sa_len != sizeof(struct sockaddr_in6)) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); *error = EINVAL; return; } if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) { /* can only bind v6 on PF_INET6 sockets */ + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); *error = EINVAL; return; } @@ -6022,6 +6063,7 @@ sctp_bindx_delete_address(struct socket *so, struct sctp_inpcb *inp, if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && SCTP_IPV6_V6ONLY(inp)) { /* can't bind mapped-v4 on PF_INET sockets */ + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); *error = EINVAL; return; } @@ -6032,12 +6074,14 @@ sctp_bindx_delete_address(struct socket *so, struct sctp_inpcb *inp, #endif if (sa->sa_family == AF_INET) { if (sa->sa_len != sizeof(struct sockaddr_in)) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); *error = EINVAL; return; } if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && SCTP_IPV6_V6ONLY(inp)) { /* can't bind v4 on PF_INET sockets */ + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); *error = EINVAL; return; } @@ -6168,3 +6212,43 @@ sctp_local_addr_count(struct sctp_tcb *stcb) } return (count); } + +#if defined(SCTP_LOCAL_TRACE_BUF) + +struct sctp_dump_log { + u_int64_t timestamp; + const char *descr; + uint32_t subsys; + uint32_t params[SCTP_TRACE_PARAMS]; +}; +int sctp_log_index = 0; +struct sctp_dump_log sctp_log[SCTP_MAX_LOGGING_SIZE]; + +void +sctp_log_trace(uint32_t subsys, const char *str, uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint32_t e, uint32_t f) +{ + int saveindex, newindex; + + do { + saveindex = sctp_log_index; + if (saveindex >= SCTP_MAX_LOGGING_SIZE) { + newindex = 1; + } else { + newindex = saveindex + 1; + } + } while (atomic_cmpset_int(&sctp_log_index, saveindex, newindex) == 0); + if (saveindex >= SCTP_MAX_LOGGING_SIZE) { + saveindex = 0; + } + sctp_log[saveindex].timestamp = SCTP_GET_CYCLECOUNT; + sctp_log[saveindex].subsys = subsys; + sctp_log[saveindex].descr = str; + sctp_log[saveindex].params[0] = a; + sctp_log[saveindex].params[1] = b; + sctp_log[saveindex].params[2] = c; + sctp_log[saveindex].params[3] = d; + sctp_log[saveindex].params[4] = e; + sctp_log[saveindex].params[5] = f; +} + +#endif diff --git a/sys/netinet/sctputil.h b/sys/netinet/sctputil.h index 46d63d8..b1f5542 100644 --- a/sys/netinet/sctputil.h +++ b/sys/netinet/sctputil.h @@ -54,6 +54,11 @@ void sctp_m_freem(struct mbuf *m); #define sctp_m_freem m_freem #endif +#if defined(SCTP_LOCAL_TRACE_BUF) || defined(__APPLE__) +void + sctp_log_trace(uint32_t fr, const char *str, uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint32_t e, uint32_t f); + +#endif #define sctp_get_associd(stcb) ((sctp_assoc_t)stcb->asoc.assoc_id) |