diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/netinet/sctp.h | 2 | ||||
-rw-r--r-- | sys/netinet/sctp_asconf.c | 178 | ||||
-rw-r--r-- | sys/netinet/sctp_asconf.h | 7 | ||||
-rw-r--r-- | sys/netinet/sctp_bsd_addr.c | 6 | ||||
-rw-r--r-- | sys/netinet/sctp_constants.h | 21 | ||||
-rw-r--r-- | sys/netinet/sctp_indata.c | 36 | ||||
-rw-r--r-- | sys/netinet/sctp_input.c | 52 | ||||
-rw-r--r-- | sys/netinet/sctp_output.c | 106 | ||||
-rw-r--r-- | sys/netinet/sctp_pcb.c | 257 | ||||
-rw-r--r-- | sys/netinet/sctp_pcb.h | 21 | ||||
-rw-r--r-- | sys/netinet/sctp_structs.h | 3 | ||||
-rw-r--r-- | sys/netinet/sctp_sysctl.c | 602 | ||||
-rw-r--r-- | sys/netinet/sctp_sysctl.h | 215 | ||||
-rw-r--r-- | sys/netinet/sctp_timer.c | 18 | ||||
-rw-r--r-- | sys/netinet/sctp_timer.h | 4 | ||||
-rw-r--r-- | sys/netinet/sctp_uio.h | 19 | ||||
-rw-r--r-- | sys/netinet/sctp_usrreq.c | 184 | ||||
-rw-r--r-- | sys/netinet/sctp_var.h | 2 | ||||
-rw-r--r-- | sys/netinet/sctputil.c | 61 | ||||
-rw-r--r-- | sys/netinet6/sctp6_usrreq.c | 129 |
20 files changed, 1268 insertions, 655 deletions
diff --git a/sys/netinet/sctp.h b/sys/netinet/sctp.h index 94d407f..a97b07d 100644 --- a/sys/netinet/sctp.h +++ b/sys/netinet/sctp.h @@ -479,7 +479,7 @@ __attribute__((packed)); */ #define SCTP_MOBILITY_BASE 0x00000001 #define SCTP_MOBILITY_FASTHANDOFF 0x00000002 -#define SCTP_MOBILITY_DO_FASTHANDOFF 0x00000004 +#define SCTP_MOBILITY_PRIM_DELETED 0x00000004 #define SCTP_SMALLEST_PMTU 512 /* smallest pmtu allowed when disabling PMTU diff --git a/sys/netinet/sctp_asconf.c b/sys/netinet/sctp_asconf.c index fb51dd4..e75f5de 100644 --- a/sys/netinet/sctp_asconf.c +++ b/sys/netinet/sctp_asconf.c @@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$"); #include <netinet/sctputil.h> #include <netinet/sctp_output.h> #include <netinet/sctp_asconf.h> +#include <netinet/sctp_timer.h> /* * debug flags: @@ -550,6 +551,42 @@ sctp_process_asconf_set_primary(struct mbuf *m, if (response_required) { m_reply = sctp_asconf_success_response(aph->correlation_id); } + /* + * Mobility adaptation. Ideally, when the reception of SET + * PRIMARY with DELETE IP ADDRESS of the previous primary + * destination, unacknowledged DATA are retransmitted + * immediately to the new primary destination for seamless + * handover. If the destination is UNCONFIRMED and marked + * to REQ_PRIM, The retransmission occur when reception of + * the HEARTBEAT-ACK. (See sctp_handle_heartbeat_ack in + * sctp_input.c) Also, when change of the primary + * destination, it is better that all subsequent new DATA + * containing already queued DATA are transmitted to the new + * primary destination. (by micchie) + */ + if ((sctp_is_mobility_feature_on(stcb->sctp_ep, + SCTP_MOBILITY_BASE) || + sctp_is_mobility_feature_on(stcb->sctp_ep, + SCTP_MOBILITY_FASTHANDOFF)) && + sctp_is_mobility_feature_on(stcb->sctp_ep, + SCTP_MOBILITY_PRIM_DELETED) && + (stcb->asoc.primary_destination->dest_state & + SCTP_ADDR_UNCONFIRMED) == 0) { + + sctp_timer_stop(SCTP_TIMER_TYPE_PRIM_DELETED, stcb->sctp_ep, stcb, NULL, SCTP_FROM_SCTP_TIMER + SCTP_LOC_7); + if (sctp_is_mobility_feature_on(stcb->sctp_ep, + SCTP_MOBILITY_FASTHANDOFF)) { + sctp_assoc_immediate_retrans(stcb, + stcb->asoc.primary_destination); + } + if (sctp_is_mobility_feature_on(stcb->sctp_ep, + SCTP_MOBILITY_BASE)) { + sctp_move_chunks_from_deleted_prim(stcb, + stcb->asoc.primary_destination); + } + sctp_delete_prim_timer(stcb->sctp_ep, stcb, + stcb->asoc.deleted_primary); + } } else { /* couldn't set the requested primary address! */ SCTPDBG(SCTP_DEBUG_ASCONF1, @@ -940,26 +977,138 @@ sctp_asconf_nets_cleanup(struct sctp_tcb *stcb, struct sctp_ifn *ifn) } } +void +sctp_move_chunks_from_deleted_prim(struct sctp_tcb *stcb, struct sctp_nets *dst) +{ + struct sctp_association *asoc; + struct sctp_stream_out *outs; + struct sctp_tmit_chunk *chk; + struct sctp_stream_queue_pending *sp; + + if (dst->dest_state & SCTP_ADDR_UNCONFIRMED) { + SCTPDBG(SCTP_DEBUG_ASCONF1, "move_chunks_from_deleted_prim: specified destination is UNCONFIRMED\n"); + return; + } + if (stcb->asoc.deleted_primary == NULL) { + SCTPDBG(SCTP_DEBUG_ASCONF1, "move_chunks_from_deleted_prim: Funny, old primary is not stored\n"); + return; + } + asoc = &stcb->asoc; + + /* + * now through all the streams checking for chunks sent to our bad + * network. + */ + TAILQ_FOREACH(outs, &asoc->out_wheel, next_spoke) { + /* now clean up any chunks here */ + TAILQ_FOREACH(sp, &outs->outqueue, next) { + if (sp->net == asoc->deleted_primary) { + sctp_free_remote_addr(sp->net); + sp->net = dst; + atomic_add_int(&dst->ref_count, 1); + } + } + } + /* Now check the pending queue */ + TAILQ_FOREACH(chk, &asoc->send_queue, sctp_next) { + if (chk->whoTo == asoc->deleted_primary) { + sctp_free_remote_addr(chk->whoTo); + chk->whoTo = dst; + atomic_add_int(&dst->ref_count, 1); + } + } + +} + +extern int cur_oerr; + +void +sctp_assoc_immediate_retrans(struct sctp_tcb *stcb, struct sctp_nets *dstnet) +{ + int error; + struct sctp_tmit_chunk *chk; + + //for debug + if (dstnet->dest_state & SCTP_ADDR_UNCONFIRMED) { + SCTPDBG(SCTP_DEBUG_ASCONF1, "assoc_immediate_retrans: specified destination is UNCONFIRMED\n"); + return; + } + if (stcb->asoc.deleted_primary == NULL) { + SCTPDBG(SCTP_DEBUG_ASCONF1, "assoc_immediate_retrans: Funny, old primary is not stored\n"); + return; + } + if (!TAILQ_EMPTY(&stcb->asoc.sent_queue)) { + SCTPDBG(SCTP_DEBUG_ASCONF1, "Deleted primary is "); + SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, &stcb->asoc.deleted_primary->ro._l_addr.sa); + SCTPDBG(SCTP_DEBUG_ASCONF1, "Current Primary is "); + SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, &stcb->asoc.primary_destination->ro._l_addr.sa); + SCTPDBG(SCTP_DEBUG_ASCONF1, "Stopping send timer and calling t3rxt_timer\n"); + sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, + stcb->asoc.deleted_primary, + SCTP_FROM_SCTP_TIMER + SCTP_LOC_8); + stcb->asoc.num_send_timers_up--; + if (stcb->asoc.num_send_timers_up < 0) { + stcb->asoc.num_send_timers_up = 0; + } + SCTP_TCB_LOCK_ASSERT(stcb); + cur_oerr = stcb->asoc.overall_error_count; + error = sctp_t3rxt_timer(stcb->sctp_ep, stcb, + stcb->asoc.deleted_primary); + if (error) { + SCTPDBG(SCTP_DEBUG_ASCONF1, "t3rxt_timer error\n"); + SCTP_INP_DECR_REF(stcb->sctp_ep); + return; + } + SCTP_TCB_LOCK_ASSERT(stcb); +#ifdef SCTP_AUDITING_ENABLED + sctp_auditing(4, stcb->sctp_ep, stcb->asoc.deleted_primary); +#endif + /* Debug code */ + SCTPDBG(SCTP_DEBUG_ASCONF1, "assoc_immediate_retrans: calling chunk_output, retran_cnt is %d\n", stcb->asoc.sent_queue_retran_cnt); + TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) { + SCTPDBG(SCTP_DEBUG_ASCONF1, "assoc_immediate_retrans: chk->whoTo is "); + SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, &chk->whoTo->ro._l_addr.sa); + SCTPDBG(SCTP_DEBUG_ASCONF1, "state is %d\n", chk->sent); + } + /* end Debug code */ + sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED); + if ((stcb->asoc.num_send_timers_up == 0) && + (stcb->asoc.sent_queue_cnt > 0)) { + struct sctp_tmit_chunk *chk; + + chk = TAILQ_FIRST(&stcb->asoc.sent_queue); + sctp_timer_start(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, + stcb, chk->whoTo); + } + } + return; +} + static int sctp_asconf_queue_mgmt(struct sctp_tcb *, struct sctp_ifa *, uint16_t); -static void +void sctp_net_immediate_retrans(struct sctp_tcb *stcb, struct sctp_nets *net) { struct sctp_tmit_chunk *chk; + int cnt = 0; /* debug */ - SCTPDBG(SCTP_DEBUG_ASCONF2, "net_immediate_retrans()\n"); - SCTPDBG(SCTP_DEBUG_ASCONF2, "RTO is %d\n", net->RTO); + SCTPDBG(SCTP_DEBUG_ASCONF1, "net_immediate_retrans:\n"); + SCTPDBG(SCTP_DEBUG_ASCONF1, "RTO is %d\n", net->RTO); sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_5); stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb, net); net->error_count = 0; TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) { if (chk->whoTo == net) { - chk->sent = SCTP_DATAGRAM_RESEND; - sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); + if (chk->sent < SCTP_DATAGRAM_RESEND) { + chk->sent = SCTP_DATAGRAM_RESEND; + sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); + cnt++; + } } } + SCTPDBG(SCTP_DEBUG_ASCONF1, "%d chunks are marked to RESEND, retran_cnt is %d\n", cnt, stcb->asoc.sent_queue_retran_cnt); } static void @@ -1365,7 +1514,7 @@ sctp_asconf_queue_add_sa(struct sctp_tcb *stcb, struct sockaddr *sa, vrf_id = SCTP_DEFAULT_VRFID; } - ifa = sctp_find_ifa_by_addr(sa, vrf_id, 0); + ifa = sctp_find_ifa_by_addr(sa, vrf_id, SCTP_ADDR_NOT_LOCKED); if (ifa == NULL) { /* Invalid address */ return (-1); @@ -2061,8 +2210,7 @@ sctp_asconf_iterator_stcb(struct sctp_inpcb *inp, struct sctp_tcb *stcb, sctp_rtentry_t *rt; /* delete this address if cached */ - if (net->ro._s_addr && - (net->ro._s_addr->ifa == ifa)) { + if (net->ro._s_addr == ifa) { sctp_free_ifa(net->ro._s_addr); net->ro._s_addr = NULL; net->src_addr_selected = 0; @@ -2223,8 +2371,10 @@ sctp_find_valid_localaddr(struct sctp_tcb *stcb) struct sctp_ifn *sctp_ifn; struct sctp_ifa *sctp_ifa; + SCTP_IPI_ADDR_LOCK(); vrf = sctp_find_vrf(stcb->asoc.vrf_id); if (vrf == NULL) { + SCTP_IPI_ADDR_UNLOCK(); return (NULL); } LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) { @@ -2250,6 +2400,7 @@ sctp_find_valid_localaddr(struct sctp_tcb *stcb) if (sctp_is_addr_restricted(stcb, sctp_ifa)) continue; /* found a valid local v4 address to use */ + SCTP_IPI_ADDR_UNLOCK(); return (&sctp_ifa->address.sa); } else if (sctp_ifa->address.sa.sa_family == AF_INET6 && stcb->asoc.ipv6_addr_legal) { @@ -2271,11 +2422,13 @@ sctp_find_valid_localaddr(struct sctp_tcb *stcb) continue; /* found a valid local v6 address to use */ + SCTP_IPI_ADDR_UNLOCK(); return (&sctp_ifa->address.sa); } } } /* no valid addresses found */ + SCTP_IPI_ADDR_UNLOCK(); return (NULL); } @@ -2566,7 +2719,7 @@ sctp_process_initack_addresses(struct sctp_tcb *stcb, struct mbuf *m, vrf_id = SCTP_DEFAULT_VRFID; } - sctp_ifa = sctp_find_ifa_by_addr(sa, vrf_id, 0); + sctp_ifa = sctp_find_ifa_by_addr(sa, vrf_id, SCTP_ADDR_NOT_LOCKED); if (sctp_ifa == NULL) { /* address doesn't exist anymore */ int status; @@ -2773,8 +2926,10 @@ sctp_check_address_list_all(struct sctp_tcb *stcb, struct mbuf *m, int offset, } else { return; } + SCTP_IPI_ADDR_LOCK(); vrf = sctp_find_vrf(vrf_id); if (vrf == NULL) { + SCTP_IPI_ADDR_UNLOCK(); return; } /* go through all our known interfaces */ @@ -2798,6 +2953,7 @@ sctp_check_address_list_all(struct sctp_tcb *stcb, struct mbuf *m, int offset, } } /* end foreach ifa */ } /* end foreach ifn */ + SCTP_IPI_ADDR_UNLOCK(); } /* @@ -2850,10 +3006,10 @@ sctp_addr_mgmt_ep_sa(struct sctp_inpcb *inp, struct sockaddr *sa, ifa = sctp_ifap; } else if (type == SCTP_ADD_IP_ADDRESS) { /* For an add the address MUST be on the system */ - ifa = sctp_find_ifa_by_addr(sa, vrf_id, 0); + ifa = sctp_find_ifa_by_addr(sa, vrf_id, SCTP_ADDR_NOT_LOCKED); } else if (type == SCTP_DEL_IP_ADDRESS) { /* For a delete we need to find it in the inp */ - ifa = sctp_find_ifa_in_ep(inp, sa, 0); + ifa = sctp_find_ifa_in_ep(inp, sa, SCTP_ADDR_NOT_LOCKED); } else { ifa = NULL; } diff --git a/sys/netinet/sctp_asconf.h b/sys/netinet/sctp_asconf.h index 017f303..86006da 100644 --- a/sys/netinet/sctp_asconf.h +++ b/sys/netinet/sctp_asconf.h @@ -79,6 +79,13 @@ extern void sctp_check_address_list(struct sctp_tcb *, struct mbuf *, int, int, struct sockaddr *, uint16_t, uint16_t, uint16_t, uint16_t); +extern void + sctp_move_chunks_from_deleted_prim(struct sctp_tcb *, struct sctp_nets *); +extern void + sctp_assoc_immediate_retrans(struct sctp_tcb *, struct sctp_nets *); +extern void + sctp_net_immediate_retrans(struct sctp_tcb *, struct sctp_nets *); + #endif /* _KERNEL */ #endif /* !_NETINET_SCTP_ASCONF_H_ */ diff --git a/sys/netinet/sctp_bsd_addr.c b/sys/netinet/sctp_bsd_addr.c index 8b5aaf9..e0aa304 100644 --- a/sys/netinet/sctp_bsd_addr.c +++ b/sys/netinet/sctp_bsd_addr.c @@ -167,6 +167,7 @@ sctp_is_desired_interface_type(struct ifaddr *ifa) case IFT_ISDNBASIC: case IFT_ISDNPRIMARY: case IFT_PTPSERIAL: + case IFT_OTHER: case IFT_PPP: case IFT_LOOP: case IFT_SLIP: @@ -323,7 +324,10 @@ sctp_addr_change(struct ifaddr *ifa, int cmd) (void *)ifa, ifa->ifa_addr, ifa_flags, 1); } else if (cmd == RTM_DELETE) { - sctp_del_addr_from_vrf(SCTP_DEFAULT_VRFID, ifa->ifa_addr, ifa->ifa_ifp->if_index); + sctp_del_addr_from_vrf(SCTP_DEFAULT_VRFID, ifa->ifa_addr, + ifa->ifa_ifp->if_index, + ifa->ifa_ifp->if_xname + ); /* * We don't bump refcount here so when it completes the * final delete will happen. diff --git a/sys/netinet/sctp_constants.h b/sys/netinet/sctp_constants.h index 5d65b78..c059a4d 100644 --- a/sys/netinet/sctp_constants.h +++ b/sys/netinet/sctp_constants.h @@ -471,11 +471,12 @@ __FBSDID("$FreeBSD$"); #define SCTP_NOTIFY_DATAGRAM_SENT 0x0002 #define SCTP_FAILED_THRESHOLD 0x0004 #define SCTP_HEARTBEAT_SUCCESS 0x0008 -#define SCTP_RESPONSE_TO_USER_REQ 0x000f -#define SCTP_INTERNAL_ERROR 0x0010 -#define SCTP_SHUTDOWN_GUARD_EXPIRES 0x0020 -#define SCTP_RECEIVED_SACK 0x0040 -#define SCTP_PEER_FAULTY 0x0080 +#define SCTP_RESPONSE_TO_USER_REQ 0x0010 +#define SCTP_INTERNAL_ERROR 0x0020 +#define SCTP_SHUTDOWN_GUARD_EXPIRES 0x0040 +#define SCTP_RECEIVED_SACK 0x0080 +#define SCTP_PEER_FAULTY 0x0100 +#define SCTP_ICMP_REFUSED 0x0200 /* bits for TOS field */ #define SCTP_ECT0_BIT 0x02 @@ -591,8 +592,9 @@ __FBSDID("$FreeBSD$"); #define SCTP_TIMER_TYPE_ADDR_WQ 19 #define SCTP_TIMER_TYPE_ZERO_COPY 20 #define SCTP_TIMER_TYPE_ZCOPY_SENDQ 21 +#define SCTP_TIMER_TYPE_PRIM_DELETED 22 /* add new timers here - and increment LAST */ -#define SCTP_TIMER_TYPE_LAST 22 +#define SCTP_TIMER_TYPE_LAST 23 #define SCTP_IS_TIMER_TYPE_VALID(t) (((t) > SCTP_TIMER_TYPE_NONE) && \ ((t) < SCTP_TIMER_TYPE_LAST)) @@ -652,6 +654,7 @@ __FBSDID("$FreeBSD$"); */ #define SCTP_ASOC_MAX_CHUNKS_ON_QUEUE 512 + /* The conversion from time to ticks and vice versa is done by rounding * upwards. This way we can test in the code the time to be positive and * know that this corresponds to a positive number of ticks. @@ -1036,6 +1039,12 @@ __FBSDID("$FreeBSD$"); #define SCTP_SO_NOT_LOCKED 0 +/*- + * For address locks, do we hold the lock? + */ +#define SCTP_ADDR_LOCKED 1 +#define SCTP_ADDR_NOT_LOCKED 0 + #define IN4_ISPRIVATE_ADDRESS(a) \ ((((uint8_t *)&(a)->s_addr)[0] == 10) || \ ((((uint8_t *)&(a)->s_addr)[0] == 172) && \ diff --git a/sys/netinet/sctp_indata.c b/sys/netinet/sctp_indata.c index 52881d2..5179e75 100644 --- a/sys/netinet/sctp_indata.c +++ b/sys/netinet/sctp_indata.c @@ -375,8 +375,10 @@ sctp_service_reassembly(struct sctp_tcb *stcb, struct sctp_association *asoc) cntDel = stream_no = 0; if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || + (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) || (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET)) { - /* socket above is long gone */ + /* socket above is long gone or going.. */ +abandon: asoc->fragmented_delivery_inprogress = 0; chk = TAILQ_FIRST(&asoc->reasmqueue); while (chk) { @@ -449,12 +451,16 @@ sctp_service_reassembly(struct sctp_tcb *stcb, struct sctp_association *asoc) * is corrupt, or there is a EOM already on * the mbuf chain. */ - if ((stcb->asoc.control_pdapi == NULL) || (stcb->asoc.control_pdapi->tail_mbuf == NULL)) { - panic("This should not happen control_pdapi NULL?"); + if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { + goto abandon; + } else { + if ((stcb->asoc.control_pdapi == NULL) || (stcb->asoc.control_pdapi->tail_mbuf == NULL)) { + panic("This should not happen control_pdapi NULL?"); + } + /* if we did not panic, it was a EOM */ + panic("Bad chunking ??"); + return; } - /* if we did not panic, it was a EOM */ - panic("Bad chunking ??"); - return; } cntDel++; } @@ -5542,7 +5548,6 @@ slide_out: num_str = fwd_sz / sizeof(struct sctp_strseq); for (i = 0; i < num_str; i++) { uint16_t st; - unsigned char *xx; stseq = (struct sctp_strseq *)sctp_m_getptr(m, offset, sizeof(struct sctp_strseq), @@ -5552,22 +5557,21 @@ slide_out: break; } /* Convert */ - xx = (unsigned char *)&stseq[i]; - st = ntohs(stseq[i].stream); - stseq[i].stream = st; - st = ntohs(stseq[i].sequence); - stseq[i].sequence = st; + st = ntohs(stseq->stream); + stseq->stream = st; + st = ntohs(stseq->sequence); + stseq->sequence = st; /* now process */ - if (stseq[i].stream >= asoc->streamincnt) { + if (stseq->stream >= asoc->streamincnt) { /* screwed up streams, stop! */ break; } - strm = &asoc->strmin[stseq[i].stream]; - if (compare_with_wrap(stseq[i].sequence, + strm = &asoc->strmin[stseq->stream]; + if (compare_with_wrap(stseq->sequence, strm->last_sequence_delivered, MAX_SEQ)) { /* Update the sequence number */ strm->last_sequence_delivered = - stseq[i].sequence; + stseq->sequence; } /* now kick the stream the new way */ sctp_kick_prsctp_reorder_queue(stcb, strm); diff --git a/sys/netinet/sctp_input.c b/sys/netinet/sctp_input.c index 904f79c..bcc5045 100644 --- a/sys/netinet/sctp_input.c +++ b/sys/netinet/sctp_input.c @@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$"); #include <netinet/sctp_indata.h> #include <netinet/sctp_asconf.h> #include <netinet/sctp_bsd_addr.h> +#include <netinet/sctp_timer.h> @@ -548,6 +549,28 @@ sctp_handle_heartbeat_ack(struct sctp_heartbeat_chunk *cp, TAILQ_REMOVE(&stcb->asoc.nets, stcb->asoc.primary_destination, sctp_next); TAILQ_INSERT_HEAD(&stcb->asoc.nets, stcb->asoc.primary_destination, sctp_next); } + /* Mobility adaptation */ + if ((sctp_is_mobility_feature_on(stcb->sctp_ep, + SCTP_MOBILITY_BASE) || + sctp_is_mobility_feature_on(stcb->sctp_ep, + SCTP_MOBILITY_FASTHANDOFF)) && + sctp_is_mobility_feature_on(stcb->sctp_ep, + SCTP_MOBILITY_PRIM_DELETED)) { + + sctp_timer_stop(SCTP_TIMER_TYPE_PRIM_DELETED, stcb->sctp_ep, stcb, NULL, SCTP_FROM_SCTP_TIMER + SCTP_LOC_7); + if (sctp_is_mobility_feature_on(stcb->sctp_ep, + SCTP_MOBILITY_FASTHANDOFF)) { + sctp_assoc_immediate_retrans(stcb, + stcb->asoc.primary_destination); + } + if (sctp_is_mobility_feature_on(stcb->sctp_ep, + SCTP_MOBILITY_BASE)) { + sctp_move_chunks_from_deleted_prim(stcb, + stcb->asoc.primary_destination); + } + sctp_delete_prim_timer(stcb->sctp_ep, stcb, + stcb->asoc.deleted_primary); + } } sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_CONFIRMED, stcb, 0, (void *)r_net, SCTP_SO_NOT_LOCKED); @@ -1255,13 +1278,24 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, * to get into the OPEN state */ if (ntohl(initack_cp->init.initial_tsn) != asoc->init_seq_number) { -#ifdef INVARIANTS - panic("Case D and non-match seq?"); -#else - SCTP_PRINTF("Case D, seq non-match %x vs %x?\n", - ntohl(initack_cp->init.initial_tsn), - asoc->init_seq_number); -#endif + /*- + * Opps, this means that we somehow generated two vtag's + * the same. I.e. we did: + * Us Peer + * <---INIT(tag=a)------ + * ----INIT-ACK(tag=t)--> + * ----INIT(tag=t)------> *1 + * <---INIT-ACK(tag=a)--- + * <----CE(tag=t)------------- *2 + * + * At point *1 we should be generating a different + * tag t'. Which means we would throw away the CE and send + * ours instead. Basically this is case C (throw away side). + */ + if (how_indx < sizeof(asoc->cookie_how)) + asoc->cookie_how[how_indx] = 17; + return (NULL); + } switch SCTP_GET_STATE (asoc) { @@ -2417,6 +2451,7 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset, (SCTP_PCB_COPY_FLAGS & (*inp_p)->sctp_flags) | SCTP_PCB_FLAGS_DONT_WAKE); inp->sctp_features = (*inp_p)->sctp_features; + inp->sctp_mobility_features = (*inp_p)->sctp_mobility_features; inp->sctp_socket = so; inp->sctp_frag_point = (*inp_p)->sctp_frag_point; inp->partial_delivery_point = (*inp_p)->partial_delivery_point; @@ -5101,12 +5136,9 @@ trigger_send: un_sent = (stcb->asoc.total_output_queue_size - stcb->asoc.total_flight); if (!TAILQ_EMPTY(&stcb->asoc.control_send_queue) || - /* For retransmission to new primary destination (by micchie) */ - sctp_is_mobility_feature_on(inp, SCTP_MOBILITY_DO_FASTHANDOFF) || ((un_sent) && (stcb->asoc.peers_rwnd > 0 || (stcb->asoc.peers_rwnd <= 0 && stcb->asoc.total_flight == 0)))) { - sctp_mobility_feature_off(inp, SCTP_MOBILITY_DO_FASTHANDOFF); SCTPDBG(SCTP_DEBUG_INPUT3, "Calling chunk OUTPUT\n"); sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CONTROL_PROC, SCTP_SO_NOT_LOCKED); SCTPDBG(SCTP_DEBUG_INPUT3, "chunk OUTPUT returns\n"); diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c index 3b60f85..64eb825 100644 --- a/sys/netinet/sctp_output.c +++ b/sys/netinet/sctp_output.c @@ -2412,6 +2412,10 @@ once_again: /* address has been removed */ continue; } + if (laddr->action == SCTP_DEL_IP_ADDRESS) { + /* address is being deleted */ + continue; + } sifa = sctp_is_ifa_addr_preferred(laddr->ifa, dest_is_loop, dest_is_priv, fam); if (sifa == NULL) @@ -2437,6 +2441,10 @@ once_again_too: /* address has been removed */ continue; } + if (laddr->action == SCTP_DEL_IP_ADDRESS) { + /* address is being deleted */ + continue; + } sifa = sctp_is_ifa_addr_acceptable(laddr->ifa, dest_is_loop, dest_is_priv, fam); if (sifa == NULL) @@ -2547,6 +2555,10 @@ sctp_from_the_top: /* address has been removed */ continue; } + if (laddr->action == SCTP_DEL_IP_ADDRESS) { + /* address is being deleted */ + continue; + } sifa = sctp_is_ifa_addr_preferred(laddr->ifa, dest_is_loop, dest_is_priv, fam); if (sifa == NULL) continue; @@ -2558,7 +2570,6 @@ sctp_from_the_top: stcb->asoc.last_used_address = laddr; atomic_add_int(&sifa->refcount, 1); return (sifa); - } if (start_at_beginning == 0) { stcb->asoc.last_used_address = NULL; @@ -2579,6 +2590,10 @@ sctp_from_the_top2: /* address has been removed */ continue; } + if (laddr->action == SCTP_DEL_IP_ADDRESS) { + /* address is being deleted */ + continue; + } sifa = sctp_is_ifa_addr_acceptable(laddr->ifa, dest_is_loop, dest_is_priv, fam); if (sifa == NULL) @@ -3396,10 +3411,14 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, /* call the routine to select the src address */ if (net) { - if (net->ro._s_addr && (net->ro._s_addr->localifa_flags & SCTP_BEING_DELETED)) { + if (net->ro._s_addr && (net->ro._s_addr->localifa_flags & (SCTP_BEING_DELETED | SCTP_ADDR_IFA_UNUSEABLE))) { sctp_free_ifa(net->ro._s_addr); net->ro._s_addr = NULL; net->src_addr_selected = 0; + if (ro->ro_rt) { + RTFREE(ro->ro_rt); + ro->ro_rt = NULL; + } } if (net->src_addr_selected == 0) { if (out_of_asoc_ok) { @@ -3671,10 +3690,14 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, lsa6_tmp.sin6_len = sizeof(lsa6_tmp); lsa6 = &lsa6_tmp; if (net) { - if (net->ro._s_addr && net->ro._s_addr->localifa_flags & SCTP_BEING_DELETED) { + if (net->ro._s_addr && (net->ro._s_addr->localifa_flags & (SCTP_BEING_DELETED | SCTP_ADDR_IFA_UNUSEABLE))) { sctp_free_ifa(net->ro._s_addr); net->ro._s_addr = NULL; net->src_addr_selected = 0; + if (ro->ro_rt) { + RTFREE(ro->ro_rt); + ro->ro_rt = NULL; + } } if (net->src_addr_selected == 0) { if (out_of_asoc_ok) { @@ -4922,7 +4945,7 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb, initackm_out->msg.init.initiate_tag = htonl(asoc->my_vtag); initackm_out->msg.init.initial_tsn = htonl(asoc->init_seq_number); } else { - uint32_t vtag; + uint32_t vtag, itsn; if (asoc) { atomic_add_int(&asoc->refcnt, 1); @@ -4930,7 +4953,8 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb, vtag = sctp_select_a_tag(inp); initackm_out->msg.init.initiate_tag = htonl(vtag); /* get a TSN to use too */ - initackm_out->msg.init.initial_tsn = htonl(sctp_select_initial_TSN(&inp->sctp_ep)); + itsn = sctp_select_initial_TSN(&inp->sctp_ep); + initackm_out->msg.init.initial_tsn = htonl(itsn); SCTP_TCB_LOCK(stcb); atomic_add_int(&asoc->refcnt, -1); } else { @@ -5978,7 +6002,7 @@ sctp_sendall(struct sctp_inpcb *inp, struct uio *uio, struct mbuf *m, ca->sndlen += SCTP_BUF_LEN(m); m = SCTP_BUF_NEXT(m); } - ca->m = m; + ca->m = mat; } ret = sctp_initiate_iterator(NULL, sctp_sendall_iterator, NULL, SCTP_PCB_ANY_FLAGS, SCTP_PCB_ANY_FEATURES, @@ -6401,6 +6425,7 @@ re_look: /* No chunk memory */ out_gu: if (send_lock_up) { + /* sa_ignore NO_NULL_CHK */ SCTP_TCB_SEND_UNLOCK(stcb); send_lock_up = 0; } @@ -6972,6 +6997,14 @@ sctp_med_chunk_output(struct sctp_inpcb *inp, net = TAILQ_FIRST(&asoc->nets); } + /* + * JRI-TODO: CMT-MPI. Simply set the first + * destination (net) to be optimized for the next + * message to be pulled out of the outwheel. 1. peek + * at outwheel 2. If large message, set net = + * highest_cwnd 3. If small message, set net = + * lowest rtt + */ } else { net = asoc->primary_destination; if (net == NULL) { @@ -6980,12 +7013,27 @@ sctp_med_chunk_output(struct sctp_inpcb *inp, } } start_at = net; + one_more_time: for (; net != NULL; net = TAILQ_NEXT(net, sctp_next)) { net->window_probe = 0; if (old_startat && (old_startat == net)) { break; } + /* + * JRI: if dest is unreachable or unconfirmed, do + * not send data to it + */ + if ((net->dest_state & SCTP_ADDR_NOT_REACHABLE) || (net->dest_state & SCTP_ADDR_UNCONFIRMED)) { + continue; + } + /* + * JRI: if dest is in PF state, do not send data to + * it + */ + if (sctp_cmt_on_off && sctp_cmt_pf && (net->dest_state & SCTP_ADDR_PF)) { + continue; + } if ((sctp_cmt_on_off == 0) && (net->ref_count < 2)) { /* nothing can be in queue for this guy */ continue; @@ -6996,9 +7044,9 @@ one_more_time: continue; } /* - * @@@ JRI : this for loop we are in takes in each - * net, if its's got space in cwnd and has data sent - * to it (when CMT is off) then it calls + * JRI : this for loop we are in takes in each net, + * if its's got space in cwnd and has data sent to + * it (when CMT is off) then it calls * sctp_fill_outqueue for the net. This gets data on * the send queue for that network. * @@ -7026,6 +7074,7 @@ one_more_time: } skip_the_fill_from_streams: *cwnd_full = cwnd_full_ind; + /* now service each destination and send out what we can for it */ /* Nothing to send? */ if ((TAILQ_FIRST(&asoc->control_send_queue) == NULL) && @@ -8082,8 +8131,6 @@ sctp_send_asconf_ack(struct sctp_tcb *stcb) } latest_ack->last_sent_to = net; - atomic_add_int(&latest_ack->last_sent_to->ref_count, 1); - TAILQ_FOREACH(ack, &stcb->asoc.asconf_ack_sent, next) { if (ack->data == NULL) { continue; @@ -9221,6 +9268,7 @@ sctp_send_sack(struct sctp_tcb *stcb) a_chk->data = NULL; } sctp_free_a_chunk(stcb, a_chk); + /* sa_ignore NO_NULL_CHK */ if (stcb->asoc.delayed_ack) { sctp_timer_stop(SCTP_TIMER_TYPE_RECV, stcb->sctp_ep, stcb, NULL, SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_6); @@ -9916,6 +9964,7 @@ sctp_send_packet_dropped(struct sctp_tcb *stcb, struct sctp_nets *net, struct sctp_chunkhdr *ch, chunk_buf; unsigned int chk_length; + /* sa_ignore NO_NULL_CHK */ asoc = &stcb->asoc; SCTP_TCB_LOCK_ASSERT(stcb); if (asoc->peer_supports_pktdrop == 0) { @@ -11131,8 +11180,7 @@ sctp_lower_sosend(struct socket *so, if ((use_rcvinfo) && (srcv) && ((srcv->sinfo_flags & SCTP_ABORT) || ((srcv->sinfo_flags & SCTP_EOF) && - (uio) && - (uio->uio_resid == 0)))) { + (sndlen == 0)))) { /*- * User asks to abort a non-existant assoc, * or EOF a non-existant assoc with no data @@ -11282,7 +11330,11 @@ sctp_lower_sosend(struct socket *so, (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; + if (sndlen > SCTP_SB_LIMIT_SND(so)) + error = EMSGSIZE; + else + error = EWOULDBLOCK; + atomic_add_int(&stcb->sctp_ep->total_nospaces, 1); goto out_unlocked; } @@ -11402,9 +11454,14 @@ sctp_lower_sosend(struct socket *so, tot_demand = (tot_out + sizeof(struct sctp_paramhdr)); } else { /* Must fit in a MTU */ - if (uio) - tot_out = uio->uio_resid; + tot_out = sndlen; tot_demand = (tot_out + sizeof(struct sctp_paramhdr)); + if (tot_demand > SCTP_DEFAULT_ADD_MORE) { + /* To big */ + SCTP_LTRACE_ERR_RET(NULL, stcb, net, SCTP_FROM_SCTP_OUTPUT, EMSGSIZE); + error = EMSGSIZE; + goto out; + } mm = sctp_get_mbuf_for_msg(tot_demand, 0, M_WAIT, 1, MT_DATA); } if (mm == NULL) { @@ -11491,12 +11548,21 @@ sctp_lower_sosend(struct socket *so, } /* Unless E_EOR mode is on, we must make a send FIT in one call. */ if ((user_marks_eor == 0) && - (uio->uio_resid > (int)SCTP_SB_LIMIT_SND(stcb->sctp_socket))) { + (sndlen > 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_unlocked; } + if ((uio == NULL) && user_marks_eor) { + /*- + * We do not support eeor mode for + * sending with mbuf chains (like sendfile). + */ + SCTP_LTRACE_ERR_RET(NULL, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); + error = EINVAL; + goto out_unlocked; + } if (user_marks_eor) { local_add_more = sctp_add_more_threshold; } else { @@ -11504,7 +11570,7 @@ sctp_lower_sosend(struct socket *so, * For non-eeor the whole message must fit in * the socket send buffer. */ - local_add_more = uio->uio_resid; + local_add_more = sndlen; } len = 0; if (((max_len < local_add_more) && @@ -11517,7 +11583,7 @@ sctp_lower_sosend(struct socket *so, if (sctp_logging_level & SCTP_BLK_LOGGING_ENABLE) { sctp_log_block(SCTP_BLOCK_LOG_INTO_BLKA, - so, asoc, uio->uio_resid); + so, asoc, sndlen); } be.error = 0; stcb->block_entry = &be; @@ -11557,7 +11623,7 @@ sctp_lower_sosend(struct socket *so, * 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 (sndlen == 0) { if (srcv->sinfo_flags & SCTP_EOF) { got_all_of_the_send = 1; goto dataless_eof; diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c index 30fc1cb..e7830fc 100644 --- a/sys/netinet/sctp_pcb.c +++ b/sys/netinet/sctp_pcb.c @@ -296,6 +296,110 @@ sctp_delete_ifn(struct sctp_ifn *sctp_ifnp, int hold_addr_lock) sctp_free_ifn(sctp_ifnp); } +void +sctp_mark_ifa_addr_down(uint32_t vrf_id, struct sockaddr *addr, const char *if_name, uint32_t ifn_index) +{ + struct sctp_vrf *vrf; + struct sctp_ifa *sctp_ifap = NULL; + + SCTP_IPI_ADDR_LOCK(); + vrf = sctp_find_vrf(vrf_id); + if (vrf == NULL) { + SCTPDBG(SCTP_DEBUG_PCB1, "Can't find vrf_id:%d\n", vrf_id); + goto out; + + } + sctp_ifap = sctp_find_ifa_by_addr(addr, vrf->vrf_id, SCTP_ADDR_LOCKED); + if (sctp_ifap == NULL) { + SCTPDBG(SCTP_DEBUG_PCB1, "Can't find sctp_ifap for address\n"); + goto out; + } + if (sctp_ifap->ifn_p == NULL) { + SCTPDBG(SCTP_DEBUG_PCB1, "IFA has no IFN - can't mark unuseable\n"); + goto out; + } + if (if_name) { + int len1, len2; + + len1 = strlen(if_name); + len2 = strlen(sctp_ifap->ifn_p->ifn_name); + if (len1 != len2) { + SCTPDBG(SCTP_DEBUG_PCB1, "IFN of ifa names different lenght %d vs %d - ignored\n", + len1, len2); + goto out; + } + if (strncmp(if_name, sctp_ifap->ifn_p->ifn_name, len1) != 0) { + SCTPDBG(SCTP_DEBUG_PCB1, "IFN %s of IFA not the same as %s\n", + sctp_ifap->ifn_p->ifn_name, + if_name); + goto out; + } + } else { + if (sctp_ifap->ifn_p->ifn_index != ifn_index) { + SCTPDBG(SCTP_DEBUG_PCB1, "IFA owned by ifn_index:%d down command for ifn_index:%d - ignored\n", + sctp_ifap->ifn_p->ifn_index, ifn_index); + goto out; + } + } + + sctp_ifap->localifa_flags &= (~SCTP_ADDR_VALID); + sctp_ifap->localifa_flags |= SCTP_ADDR_IFA_UNUSEABLE; +out: + SCTP_IPI_ADDR_UNLOCK(); +} + +void +sctp_mark_ifa_addr_up(uint32_t vrf_id, struct sockaddr *addr, const char *if_name, uint32_t ifn_index) +{ + struct sctp_vrf *vrf; + struct sctp_ifa *sctp_ifap = NULL; + + SCTP_IPI_ADDR_LOCK(); + vrf = sctp_find_vrf(vrf_id); + if (vrf == NULL) { + SCTPDBG(SCTP_DEBUG_PCB1, "Can't find vrf_id:%d\n", vrf_id); + goto out; + + } + sctp_ifap = sctp_find_ifa_by_addr(addr, vrf->vrf_id, SCTP_ADDR_LOCKED); + if (sctp_ifap == NULL) { + SCTPDBG(SCTP_DEBUG_PCB1, "Can't find sctp_ifap for address\n"); + goto out; + } + if (sctp_ifap->ifn_p == NULL) { + SCTPDBG(SCTP_DEBUG_PCB1, "IFA has no IFN - can't mark unuseable\n"); + goto out; + } + if (if_name) { + int len1, len2; + + len1 = strlen(if_name); + len2 = strlen(sctp_ifap->ifn_p->ifn_name); + if (len1 != len2) { + SCTPDBG(SCTP_DEBUG_PCB1, "IFN of ifa names different lenght %d vs %d - ignored\n", + len1, len2); + goto out; + } + if (strncmp(if_name, sctp_ifap->ifn_p->ifn_name, len1) != 0) { + SCTPDBG(SCTP_DEBUG_PCB1, "IFN %s of IFA not the same as %s\n", + sctp_ifap->ifn_p->ifn_name, + if_name); + goto out; + } + } else { + if (sctp_ifap->ifn_p->ifn_index != ifn_index) { + SCTPDBG(SCTP_DEBUG_PCB1, "IFA owned by ifn_index:%d down command for ifn_index:%d - ignored\n", + sctp_ifap->ifn_p->ifn_index, ifn_index); + goto out; + } + } + + sctp_ifap->localifa_flags &= (~SCTP_ADDR_IFA_UNUSEABLE); + sctp_ifap->localifa_flags |= SCTP_ADDR_VALID; +out: + SCTP_IPI_ADDR_UNLOCK(); +} + struct sctp_ifa * sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index, @@ -361,7 +465,7 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index, atomic_add_int(&sctppcbinfo.ipi_count_ifns, 1); new_ifn_af = 1; } - sctp_ifap = sctp_find_ifa_by_addr(addr, vrf->vrf_id, 1); + sctp_ifap = sctp_find_ifa_by_addr(addr, vrf->vrf_id, SCTP_ADDR_LOCKED); if (sctp_ifap) { /* Hmm, it already exists? */ if ((sctp_ifap->ifn_p) && @@ -384,15 +488,19 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index, } else { if (sctp_ifap->ifn_p) { /* - * The first IFN gets the address, - * duplicates are ignored. + * The last IFN gets the address, old ones + * are deleted. */ if (new_ifn_af) { /* * Remove the created one that we * don't want */ - sctp_delete_ifn(sctp_ifnp, 1); + sctp_free_ifn(sctp_ifap->ifn_p); + if (sctp_ifap->ifn_p->refcount == 1) + sctp_delete_ifn(sctp_ifap->ifn_p, 1); + sctp_ifap->ifn_p = sctp_ifnp; + atomic_add_int(&sctp_ifap->ifn_p->refcount, 1); } goto exit_stage_left; } else { @@ -488,7 +596,7 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index, */ SCTPDBG(SCTP_DEBUG_PCB1, "Lost and address change ???\n"); /* Opps, must decrement the count */ - sctp_del_addr_from_vrf(vrf_id, addr, ifn_index); + sctp_del_addr_from_vrf(vrf_id, addr, ifn_index, if_name); return (NULL); } SCTP_INCR_LADDR_COUNT(); @@ -516,7 +624,7 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index, void sctp_del_addr_from_vrf(uint32_t vrf_id, struct sockaddr *addr, - uint32_t ifn_index) + uint32_t ifn_index, const char *if_name) { struct sctp_vrf *vrf; struct sctp_ifa *sctp_ifap = NULL; @@ -528,8 +636,51 @@ sctp_del_addr_from_vrf(uint32_t vrf_id, struct sockaddr *addr, SCTP_PRINTF("Can't find vrf_id:%d\n", vrf_id); goto out_now; } - sctp_ifap = sctp_find_ifa_by_addr(addr, vrf->vrf_id, 1); + sctp_ifap = sctp_find_ifa_by_addr(addr, vrf->vrf_id, SCTP_ADDR_LOCKED); if (sctp_ifap) { + /* Validate the delete */ + if (sctp_ifap->ifn_p) { + int valid = 0; + + /*- + * The name has priority over the ifn_index + * if its given. We do this especially for + * panda who might recycle indexes fast. + */ + if (if_name) { + int len1, len2; + + len1 = min(SCTP_IFNAMSIZ, strlen(if_name)); + len2 = min(SCTP_IFNAMSIZ, strlen(sctp_ifap->ifn_p->ifn_name)); + if (len1 && len2 && (len1 == len2)) { + /* we can compare them */ + if (strncmp(if_name, sctp_ifap->ifn_p->ifn_name, len1) == 0) { + /* + * They match its a correct + * delete + */ + valid = 1; + } + } + } + if (!valid) { + /* last ditch check ifn_index */ + if (ifn_index == sctp_ifap->ifn_p->ifn_index) { + valid = 1; + } + } + if (!valid) { +#ifdef SCTP_DEBUG + SCTPDBG(SCTP_DEBUG_PCB1, "Deleting address:"); + SCTPDBG_ADDR(SCTP_DEBUG_PCB1, addr); + SCTPDBG(SCTP_DEBUG_PCB1, "ifn:%d ifname:%s does not match addresses\n", + ifn_index, ((if_name == NULL) ? "NULL" : if_name)); + SCTPDBG(SCTP_DEBUG_PCB1, "ifn:%d ifname:%s - ignoring delete\n", + sctp_ifap->ifn_p->ifn_index, sctp_ifap->ifn_p->ifn_name); +#endif + return; + } + } sctp_ifap->localifa_flags &= SCTP_ADDR_VALID; sctp_ifap->localifa_flags |= SCTP_BEING_DELETED; vrf->total_ifa_count--; @@ -1857,8 +2008,8 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id) * unsupported socket type (RAW, etc)- in case we missed it * in protosw */ - SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_ep, inp); SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EOPNOTSUPP); + SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_ep, inp); return (EOPNOTSUPP); } if (sctp_default_frag_interleave == SCTP_FRAG_LEVEL_1) { @@ -1875,8 +2026,8 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id) &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); + SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_ep, inp); return (ENOBUFS); } inp->def_vrf_id = vrf_id; @@ -2086,6 +2237,7 @@ sctp_move_pcb_and_assoc(struct sctp_inpcb *old_inp, struct sctp_inpcb *new_inp, stcb->asoc.shut_guard_timer.ep = (void *)new_inp; stcb->asoc.autoclose_timer.ep = (void *)new_inp; stcb->asoc.delayed_event_timer.ep = (void *)new_inp; + stcb->asoc.delete_prim_timer.ep = (void *)new_inp; /* now what about the nets? */ TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { net->pmtu_timer.ep = (void *)new_inp; @@ -2410,8 +2562,10 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, */ if (sctp_mobility_base == 0) { sctp_mobility_feature_off(inp, SCTP_MOBILITY_BASE); + sctp_mobility_feature_off(inp, SCTP_MOBILITY_PRIM_DELETED); } else { sctp_mobility_feature_on(inp, SCTP_MOBILITY_BASE); + sctp_mobility_feature_off(inp, SCTP_MOBILITY_PRIM_DELETED); } /* * set the automatic mobility_fasthandoff from kernel flag @@ -2419,10 +2573,10 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, */ if (sctp_mobility_fasthandoff == 0) { sctp_mobility_feature_off(inp, SCTP_MOBILITY_FASTHANDOFF); - sctp_mobility_feature_off(inp, SCTP_MOBILITY_DO_FASTHANDOFF); + sctp_mobility_feature_off(inp, SCTP_MOBILITY_PRIM_DELETED); } else { sctp_mobility_feature_on(inp, SCTP_MOBILITY_FASTHANDOFF); - sctp_mobility_feature_off(inp, SCTP_MOBILITY_DO_FASTHANDOFF); + sctp_mobility_feature_off(inp, SCTP_MOBILITY_PRIM_DELETED); } } else { /* @@ -2466,7 +2620,7 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, * (Panda). */ ifa = sctp_find_ifa_by_addr((struct sockaddr *)&store_sa, - vrf_id, 0); + vrf_id, SCTP_ADDR_NOT_LOCKED); } if (ifa == NULL) { /* Can't find an interface with that address */ @@ -2625,6 +2779,10 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from) * via the sockets layer. */ inp->sctp_flags &= ~SCTP_PCB_FLAGS_CLOSE_IP; + /* socket is gone, so no more wakeups allowed */ + inp->sctp_flags |= SCTP_PCB_FLAGS_DONT_WAKE; + inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEINPUT; + inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEOUTPUT; } sctp_timer_stop(SCTP_TIMER_TYPE_NEWCOOKIE, inp, NULL, NULL, SCTP_FROM_SCTP_PCB + SCTP_LOC_1); @@ -3039,7 +3197,7 @@ sctp_is_address_on_local_host(struct sockaddr *addr, uint32_t vrf_id) { struct sctp_ifa *sctp_ifa; - sctp_ifa = sctp_find_ifa_by_addr(addr, vrf_id, 0); + sctp_ifa = sctp_find_ifa_by_addr(addr, vrf_id, SCTP_ADDR_NOT_LOCKED); if (sctp_ifa) { return (1); } else { @@ -3541,6 +3699,8 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr, sctppcbinfo.hashasocmark)]; /* put it in the bucket in the vtag hash of assoc's for the system */ LIST_INSERT_HEAD(head, stcb, sctp_asocs); + sctp_delete_from_timewait(stcb->asoc.my_vtag); + SCTP_INP_INFO_WUNLOCK(); if ((err = sctp_add_remote_addr(stcb, firstaddr, SCTP_DO_SETSCOPE, SCTP_ALLOC_ASOC))) { @@ -3570,6 +3730,7 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr, SCTP_OS_TIMER_INIT(&asoc->shut_guard_timer.timer); SCTP_OS_TIMER_INIT(&asoc->autoclose_timer.timer); SCTP_OS_TIMER_INIT(&asoc->delayed_event_timer.timer); + SCTP_OS_TIMER_INIT(&asoc->delete_prim_timer.timer); LIST_INSERT_HEAD(&inp->sctp_asoc_list, stcb, sctp_tcblist); /* now file the port under the hash as well */ @@ -3597,6 +3758,26 @@ sctp_remove_net(struct sctp_tcb *stcb, struct sctp_nets *net) struct sctp_nets *lnet; lnet = TAILQ_FIRST(&asoc->nets); + /* + * Mobility adaptation Ideally, if deleted destination is + * the primary, it becomes a fast retransmission trigger by + * the subsequent SET PRIMARY. (by micchie) + */ + if (sctp_is_mobility_feature_on(stcb->sctp_ep, + SCTP_MOBILITY_FASTHANDOFF)) { + SCTPDBG(SCTP_DEBUG_ASCONF1, "remove_net: primary dst is deleting\n"); + if (asoc->deleted_primary != NULL) { + SCTPDBG(SCTP_DEBUG_ASCONF1, "remove_net: deleted primary may be already stored\n"); + goto leave; + } + asoc->deleted_primary = net; + atomic_add_int(&net->ref_count, 1); + sctp_mobility_feature_on(stcb->sctp_ep, + SCTP_MOBILITY_PRIM_DELETED); + sctp_timer_start(SCTP_TIMER_TYPE_PRIM_DELETED, + stcb->sctp_ep, stcb, NULL); + } +leave: /* Try to find a confirmed primary */ asoc->primary_destination = sctp_find_alternate_net(stcb, lnet, 0); } @@ -3652,9 +3833,33 @@ sctp_del_remote_addr(struct sctp_tcb *stcb, struct sockaddr *remaddr) return (-2); } +void +sctp_delete_from_timewait(uint32_t tag) +{ + struct sctpvtaghead *chain; + struct sctp_tagblock *twait_block; + int found = 0; + int i; + + chain = &sctppcbinfo.vtag_timewait[(tag % SCTP_STACK_VTAG_HASH_SIZE)]; + if (!SCTP_LIST_EMPTY(chain)) { + LIST_FOREACH(twait_block, chain, sctp_nxt_tagblock) { + for (i = 0; i < SCTP_NUMBER_IN_VTAG_BLOCK; i++) { + if (twait_block->vtag_block[i].v_tag == tag) { + twait_block->vtag_block[i].tv_sec_at_expire = 0; + twait_block->vtag_block[i].v_tag = 0; + found = 1; + break; + } + } + if (found) + break; + } + } +} void -sctp_add_vtag_to_timewait(struct sctp_inpcb *inp, uint32_t tag, uint32_t time) +sctp_add_vtag_to_timewait(uint32_t tag, uint32_t time) { struct sctpvtaghead *chain; struct sctp_tagblock *twait_block; @@ -3843,6 +4048,9 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre asoc->shut_guard_timer.self = NULL; (void)SCTP_OS_TIMER_STOP(&asoc->delayed_event_timer.timer); asoc->delayed_event_timer.self = NULL; + /* Mobility adaptation */ + (void)SCTP_OS_TIMER_STOP(&asoc->delete_prim_timer.timer); + asoc->delete_prim_timer.self = NULL; TAILQ_FOREACH(net, &asoc->nets, sctp_next) { (void)SCTP_OS_TIMER_STOP(&net->fr_timer.timer); net->fr_timer.self = NULL; @@ -3999,7 +4207,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre } /* pull from vtag hash */ LIST_REMOVE(stcb, sctp_asocs); - sctp_add_vtag_to_timewait(inp, asoc->my_vtag, SCTP_TIME_WAIT); + sctp_add_vtag_to_timewait(asoc->my_vtag, SCTP_TIME_WAIT); /* * Now restop the timers to be sure - this is paranoia at is finest! @@ -4246,11 +4454,9 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre SCTP_FREE(aparam, SCTP_M_ASC_ADDR); } while (!TAILQ_EMPTY(&asoc->asconf_ack_sent)) { + /* sa_ignore FREED_MEMORY */ aack = TAILQ_FIRST(&asoc->asconf_ack_sent); TAILQ_REMOVE(&asoc->asconf_ack_sent, aack, next); - if (aack->last_sent_to != NULL) { - sctp_free_remote_addr(aack->last_sent_to); - } if (aack->data != NULL) { sctp_m_freem(aack->data); } @@ -4696,6 +4902,7 @@ sctp_pcb_init() * the sctp_init() funciton. */ int i; + struct timeval tv; if (sctp_pcb_initialized != 0) { /* error I was called twice */ @@ -4704,7 +4911,9 @@ sctp_pcb_init() sctp_pcb_initialized = 1; bzero(&sctpstat, sizeof(struct sctpstat)); - (void)SCTP_GETTIME_TIMEVAL(&sctpstat.sctps_discontinuitytime); + (void)SCTP_GETTIME_TIMEVAL(&tv); + sctpstat.sctps_discontinuitytime.tv_sec = (uint32_t) tv.tv_sec; + sctpstat.sctps_discontinuitytime.tv_usec = (uint32_t) tv.tv_usec; /* init the empty list of (All) Endpoints */ LIST_INIT(&sctppcbinfo.listhead); @@ -5542,7 +5751,15 @@ check_time_wait: } } } - /* Not found, ok to use the tag */ + /*- + * Not found, ok to use the tag, add it to the time wait hash + * as well this will prevent two sucessive cookies from getting + * the same tag or two inits sent quickly on multi-processors. + * We only keep the tag for the life of a cookie and when we + * add this tag to the assoc hash we need to purge it from + * the t-wait hash. + */ + sctp_add_vtag_to_timewait(tag, TICKS_TO_SEC(inp->sctp_ep.def_cookie_life)); SCTP_INP_INFO_WUNLOCK(); return (1); } diff --git a/sys/netinet/sctp_pcb.h b/sys/netinet/sctp_pcb.h index 9235029..bc28eac 100644 --- a/sys/netinet/sctp_pcb.h +++ b/sys/netinet/sctp_pcb.h @@ -297,7 +297,7 @@ struct sctp_pcb { int auto_close_time; uint32_t initial_sequence_debug; uint32_t adaptation_layer_indicator; - char store_at; + uint32_t store_at; uint8_t max_burst; char current_secret_number; char last_secret_number; @@ -445,6 +445,18 @@ struct sctp_vrf *sctp_allocate_vrf(int vrfid); struct sctp_vrf *sctp_find_vrf(uint32_t vrfid); void sctp_free_vrf(struct sctp_vrf *vrf); +/*- + * Change address state, can be used if + * O/S supports telling transports about + * changes to IFA/IFN's (link layer triggers). + * If a ifn goes down, we will do src-addr-selection + * and NOT use that, as a source address. This does + * not stop the routing system from routing out + * that interface, but we won't put it as a source. + */ +void sctp_mark_ifa_addr_down(uint32_t vrf_id, struct sockaddr *addr, const char *if_name, uint32_t ifn_index); +void sctp_mark_ifa_addr_up(uint32_t vrf_id, struct sockaddr *addr, const char *if_name, uint32_t ifn_index); + struct sctp_ifa * sctp_add_addr_to_vrf(uint32_t vrfid, void *ifn, uint32_t ifn_index, uint32_t ifn_type, @@ -460,7 +472,7 @@ void sctp_free_ifa(struct sctp_ifa *sctp_ifap); void sctp_del_addr_from_vrf(uint32_t vrfid, struct sockaddr *addr, - uint32_t ifn_index); + uint32_t ifn_index, const char *if_name); @@ -516,8 +528,11 @@ sctp_aloc_assoc(struct sctp_inpcb *, struct sockaddr *, int sctp_free_assoc(struct sctp_inpcb *, struct sctp_tcb *, int, int); + +void sctp_delete_from_timewait(uint32_t); + void - sctp_add_vtag_to_timewait(struct sctp_inpcb *, uint32_t, uint32_t); + sctp_add_vtag_to_timewait(uint32_t, uint32_t); void sctp_add_local_addr_ep(struct sctp_inpcb *, struct sctp_ifa *, uint32_t); diff --git a/sys/netinet/sctp_structs.h b/sys/netinet/sctp_structs.h index 217f5a0..09e08f0 100644 --- a/sys/netinet/sctp_structs.h +++ b/sys/netinet/sctp_structs.h @@ -584,12 +584,15 @@ struct sctp_association { struct sctp_timer shut_guard_timer; /* shutdown guard */ struct sctp_timer autoclose_timer; /* automatic close timer */ struct sctp_timer delayed_event_timer; /* timer for delayed events */ + struct sctp_timer delete_prim_timer; /* deleting primary dst */ /* list of restricted local addresses */ struct sctpladdr sctp_restricted_addrs; /* last local address pending deletion (waiting for an address add) */ struct sctp_ifa *asconf_addr_del_pending; + /* Deleted primary destination (used to stop timer) */ + struct sctp_nets *deleted_primary; struct sctpnetlisthead nets; /* remote address list */ diff --git a/sys/netinet/sctp_sysctl.c b/sys/netinet/sctp_sysctl.c index 5b95b86..ec28f61 100644 --- a/sys/netinet/sctp_sysctl.c +++ b/sys/netinet/sctp_sysctl.c @@ -40,86 +40,69 @@ __FBSDID("$FreeBSD$"); /* * sysctl tunable variables */ -uint32_t sctp_sendspace = (128 * 1024); -uint32_t sctp_recvspace = 128 * (1024 + -#ifdef INET6 - sizeof(struct sockaddr_in6) -#else - sizeof(struct sockaddr_in) -#endif -); -uint32_t sctp_mbuf_threshold_count = SCTP_DEFAULT_MBUFS_IN_CHAIN; -uint32_t sctp_auto_asconf = SCTP_DEFAULT_AUTO_ASCONF; -uint32_t sctp_ecn_enable = 1; -uint32_t sctp_ecn_nonce = 0; -uint32_t sctp_strict_sacks = 0; -uint32_t sctp_no_csum_on_loopback = 1; -uint32_t sctp_strict_init = 1; -uint32_t sctp_abort_if_one_2_one_hits_limit = 0; -uint32_t sctp_strict_data_order = 0; - +uint32_t sctp_sendspace = SCTPCTL_MAXDGRAM_DEFAULT; +uint32_t sctp_recvspace = SCTPCTL_RECVSPACE_DEFAULT; +uint32_t sctp_auto_asconf = SCTPCTL_AUTOASCONF_DEFAULT; +uint32_t sctp_ecn_enable = SCTPCTL_ECN_ENABLE_DEFAULT; +uint32_t sctp_ecn_nonce = SCTPCTL_ECN_NONCE_DEFAULT; +uint32_t sctp_strict_sacks = SCTPCTL_STRICT_SACKS_DEFAULT; +uint32_t sctp_no_csum_on_loopback = SCTPCTL_LOOPBACK_NOCSUM_DEFAULT; +uint32_t sctp_strict_init = SCTPCTL_STRICT_INIT_DEFAULT; uint32_t sctp_peer_chunk_oh = SCTPCTL_PEER_CHKOH_DEFAULT; -uint32_t sctp_max_burst_default = SCTP_DEF_MAX_BURST; -uint32_t sctp_use_cwnd_based_maxburst = 1; -uint32_t sctp_do_drain = 1; -uint32_t sctp_hb_maxburst = SCTP_DEF_MAX_BURST; -uint32_t sctp_logging_level = SCTPCTL_LOGGING_LEVEL_DEFAULT; - - -uint32_t sctp_max_chunks_on_queue = SCTP_ASOC_MAX_CHUNKS_ON_QUEUE; -uint32_t sctp_delayed_sack_time_default = SCTP_RECV_MSEC; -uint32_t sctp_sack_freq_default = SCTP_DEFAULT_SACK_FREQ; -uint32_t sctp_heartbeat_interval_default = SCTP_HB_DEFAULT_MSEC; -uint32_t sctp_pmtu_raise_time_default = SCTP_DEF_PMTU_RAISE_SEC; -uint32_t sctp_shutdown_guard_time_default = SCTP_DEF_MAX_SHUTDOWN_SEC; -uint32_t sctp_secret_lifetime_default = SCTP_DEFAULT_SECRET_LIFE_SEC; -uint32_t sctp_rto_max_default = SCTP_RTO_UPPER_BOUND; -uint32_t sctp_rto_min_default = SCTP_RTO_LOWER_BOUND; -uint32_t sctp_rto_initial_default = SCTP_RTO_INITIAL; -uint32_t sctp_init_rto_max_default = SCTP_RTO_UPPER_BOUND; -uint32_t sctp_valid_cookie_life_default = SCTP_DEFAULT_COOKIE_LIFE; -uint32_t sctp_init_rtx_max_default = SCTP_DEF_MAX_INIT; -uint32_t sctp_assoc_rtx_max_default = SCTP_DEF_MAX_SEND; -uint32_t sctp_path_rtx_max_default = SCTP_DEF_MAX_PATH_RTX; -uint32_t sctp_nr_outgoing_streams_default = SCTP_OSTREAM_INITIAL; -uint32_t sctp_add_more_threshold = SCTP_DEFAULT_ADD_MORE; -uint32_t sctp_asoc_free_resc_limit = SCTP_DEF_ASOC_RESC_LIMIT; -uint32_t sctp_system_free_resc_limit = SCTP_DEF_SYSTEM_RESC_LIMIT; - -uint32_t sctp_min_split_point = SCTP_DEFAULT_SPLIT_POINT_MIN; -uint32_t sctp_pcbtblsize = SCTP_PCBHASHSIZE; -uint32_t sctp_hashtblsize = SCTP_TCBHASHSIZE; -uint32_t sctp_chunkscale = SCTP_CHUNKQUEUE_SCALE; - -uint32_t sctp_cmt_on_off = 0; -uint32_t sctp_cmt_use_dac = 0; -uint32_t sctp_cmt_pf = 0; +uint32_t sctp_max_burst_default = SCTPCTL_MAXBURST_DEFAULT; +uint32_t sctp_max_chunks_on_queue = SCTPCTL_MAXCHUNKS_DEFAULT; +uint32_t sctp_hashtblsize = SCTPCTL_TCBHASHSIZE_DEFAULT; +uint32_t sctp_pcbtblsize = SCTPCTL_PCBHASHSIZE_DEFAULT; +uint32_t sctp_min_split_point = SCTPCTL_MIN_SPLIT_POINT_DEFAULT; +uint32_t sctp_chunkscale = SCTPCTL_CHUNKSCALE_DEFAULT; +uint32_t sctp_delayed_sack_time_default = SCTPCTL_DELAYED_SACK_TIME_DEFAULT; +uint32_t sctp_sack_freq_default = SCTPCTL_SACK_FREQ_DEFAULT; +uint32_t sctp_system_free_resc_limit = SCTPCTL_SYS_RESOURCE_DEFAULT; +uint32_t sctp_asoc_free_resc_limit = SCTPCTL_ASOC_RESOURCE_DEFAULT; +uint32_t sctp_heartbeat_interval_default = SCTPCTL_HEARTBEAT_INTERVAL_DEFAULT; +uint32_t sctp_pmtu_raise_time_default = SCTPCTL_PMTU_RAISE_TIME_DEFAULT; +uint32_t sctp_shutdown_guard_time_default = SCTPCTL_SHUTDOWN_GUARD_TIME_DEFAULT; +uint32_t sctp_secret_lifetime_default = SCTPCTL_SECRET_LIFETIME_DEFAULT; +uint32_t sctp_rto_max_default = SCTPCTL_RTO_MAX_DEFAULT; +uint32_t sctp_rto_min_default = SCTPCTL_RTO_MIN_DEFAULT; +uint32_t sctp_rto_initial_default = SCTPCTL_RTO_INITIAL_DEFAULT; +uint32_t sctp_init_rto_max_default = SCTPCTL_INIT_RTO_MAX_DEFAULT; +uint32_t sctp_valid_cookie_life_default = SCTPCTL_VALID_COOKIE_LIFE_DEFAULT; +uint32_t sctp_init_rtx_max_default = SCTPCTL_INIT_RTX_MAX_DEFAULT; +uint32_t sctp_assoc_rtx_max_default = SCTPCTL_ASSOC_RTX_MAX_DEFAULT; +uint32_t sctp_path_rtx_max_default = SCTPCTL_PATH_RTX_MAX_DEFAULT; +uint32_t sctp_add_more_threshold = SCTPCTL_ADD_MORE_ON_OUTPUT_DEFAULT; +uint32_t sctp_nr_outgoing_streams_default = SCTPCTL_OUTGOING_STREAMS_DEFAULT; +uint32_t sctp_cmt_on_off = SCTPCTL_CMT_ON_OFF_DEFAULT; +uint32_t sctp_cmt_use_dac = SCTPCTL_CMT_USE_DAC_DEFAULT; +uint32_t sctp_cmt_pf = SCTPCTL_CMT_PF_DEFAULT; +uint32_t sctp_use_cwnd_based_maxburst = SCTPCTL_CWND_MAXBURST_DEFAULT; +uint32_t sctp_early_fr = SCTPCTL_EARLY_FAST_RETRAN_DEFAULT; +uint32_t sctp_early_fr_msec = SCTPCTL_EARLY_FAST_RETRAN_MSEC_DEFAULT; +uint32_t sctp_asconf_auth_nochk = SCTPCTL_ASCONF_AUTH_NOCHK_DEFAULT; +uint32_t sctp_auth_disable = SCTPCTL_AUTH_DISABLE_DEFAULT; +uint32_t sctp_nat_friendly = SCTPCTL_NAT_FRIENDLY_DEFAULT; +uint32_t sctp_L2_abc_variable = SCTPCTL_ABC_L_VAR_DEFAULT; +uint32_t sctp_mbuf_threshold_count = SCTPCTL_MAX_CHAINED_MBUFS_DEFAULT; +uint32_t sctp_do_drain = SCTPCTL_DO_SCTP_DRAIN_DEFAULT; +uint32_t sctp_hb_maxburst = SCTPCTL_HB_MAX_BURST_DEFAULT; +uint32_t sctp_abort_if_one_2_one_hits_limit = SCTPCTL_ABORT_AT_LIMIT_DEFAULT; +uint32_t sctp_strict_data_order = SCTPCTL_STRICT_DATA_ORDER_DEFAULT; +uint32_t sctp_min_residual = SCTPCTL_MIN_RESIDUAL_DEFAULT; uint32_t sctp_max_retran_chunk = SCTPCTL_MAX_RETRAN_CHUNK_DEFAULT; -uint32_t sctp_mobility_base = SCTP_DEFAULT_MOBILITY_BASE; -uint32_t sctp_mobility_fasthandoff = SCTP_DEFAULT_MOBILITY_FASTHANDOFF; +uint32_t sctp_logging_level = SCTPCTL_LOGGING_LEVEL_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; -uint32_t sctp_says_check_for_deadlock = 0; -uint32_t sctp_asconf_auth_nochk = 0; -uint32_t sctp_auth_disable = 0; -uint32_t sctp_nat_friendly = 1; -uint32_t sctp_min_residual = SCTPCTL_MIN_RESIDUAL_DEFAULT;; - - -struct sctpstat sctpstat; +uint32_t sctp_mobility_base = SCTPCTL_MOBILITY_BASE_DEFAULT; +uint32_t sctp_mobility_fasthandoff = SCTPCTL_MOBILITY_FASTHANDOFF_DEFAULT; #ifdef SCTP_DEBUG -uint32_t sctp_debug_on = 0; +uint32_t sctp_debug_on = SCTPCTL_DEBUG_DEFAULT; #endif - +struct sctpstat sctpstat; /* It returns an upper limit. No filtering is done here */ @@ -249,15 +232,14 @@ copy_out_local_addresses(struct sctp_inpcb *inp, struct sctp_tcb *stcb, struct s continue; } else continue; - memset((void *)&xladdr, 0, sizeof(union sctp_sockstore)); + memset((void *)&xladdr, 0, sizeof(struct xsctp_laddr)); memcpy((void *)&xladdr.address, (const void *)&sctp_ifa->address, sizeof(union sctp_sockstore)); - (void)SCTP_GETTIME_TIMEVAL(&xladdr.start_time); SCTP_INP_RUNLOCK(inp); SCTP_INP_INFO_RUNLOCK(); error = SYSCTL_OUT(req, &xladdr, sizeof(struct xsctp_laddr)); - if (error) + if (error) { return (error); - else { + } else { SCTP_INP_INFO_RLOCK(); SCTP_INP_RLOCK(inp); } @@ -268,30 +250,30 @@ copy_out_local_addresses(struct sctp_inpcb *inp, struct sctp_tcb *stcb, struct s /* ignore if blacklisted at association level */ if (stcb && sctp_is_addr_restricted(stcb, laddr->ifa)) continue; - memset((void *)&xladdr, 0, sizeof(union sctp_sockstore)); + memset((void *)&xladdr, 0, sizeof(struct xsctp_laddr)); memcpy((void *)&xladdr.address, (const void *)&laddr->ifa->address, sizeof(union sctp_sockstore)); - xladdr.start_time = laddr->start_time; + xladdr.start_time.tv_sec = (uint32_t) laddr->start_time.tv_sec; + xladdr.start_time.tv_usec = (uint32_t) laddr->start_time.tv_usec; SCTP_INP_RUNLOCK(inp); SCTP_INP_INFO_RUNLOCK(); error = SYSCTL_OUT(req, &xladdr, sizeof(struct xsctp_laddr)); - if (error) + if (error) { return (error); - else { + } else { SCTP_INP_INFO_RLOCK(); SCTP_INP_RLOCK(inp); } } } - memset((void *)&xladdr, 0, sizeof(union sctp_sockstore)); + memset((void *)&xladdr, 0, sizeof(struct xsctp_laddr)); xladdr.last = 1; SCTP_INP_RUNLOCK(inp); SCTP_INP_INFO_RUNLOCK(); error = SYSCTL_OUT(req, &xladdr, sizeof(struct xsctp_laddr)); - if (error) + if (error) { return (error); - - else { + } else { SCTP_INP_INFO_RLOCK(); SCTP_INP_RLOCK(inp); return (0); @@ -362,8 +344,14 @@ sctp_assoclist(SYSCTL_HANDLER_ARGS) xinpcb.total_recvs = inp->total_recvs; xinpcb.total_nospaces = inp->total_nospaces; xinpcb.fragmentation_point = inp->sctp_frag_point; - xinpcb.qlen = inp->sctp_socket->so_qlen; - xinpcb.maxqlen = inp->sctp_socket->so_qlimit; + if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) { + xinpcb.qlen = 0; + xinpcb.maxqlen = 0; + } else { + xinpcb.qlen = inp->sctp_socket->so_qlen; + xinpcb.maxqlen = inp->sctp_socket->so_qlimit; + } SCTP_INP_INCR_REF(inp); SCTP_INP_RUNLOCK(inp); SCTP_INP_INFO_RUNLOCK(); @@ -398,9 +386,10 @@ sctp_assoclist(SYSCTL_HANDLER_ARGS) xstcb.T1_expireries = stcb->asoc.timoinit + stcb->asoc.timocookie; xstcb.T2_expireries = stcb->asoc.timoshutdown + stcb->asoc.timoshutdownack; xstcb.retransmitted_tsns = stcb->asoc.marked_retrans; - xstcb.start_time = stcb->asoc.start_time; - xstcb.discontinuity_time = stcb->asoc.discontinuity_time; - + xstcb.start_time.tv_sec = (uint32_t) stcb->asoc.start_time.tv_sec; + xstcb.start_time.tv_usec = (uint32_t) stcb->asoc.start_time.tv_usec; + xstcb.discontinuity_time.tv_sec = (uint32_t) stcb->asoc.discontinuity_time.tv_sec; + xstcb.discontinuity_time.tv_usec = (uint32_t) stcb->asoc.discontinuity_time.tv_usec; xstcb.total_sends = stcb->total_sends; xstcb.total_recvs = stcb->total_recvs; xstcb.local_tag = stcb->asoc.my_vtag; @@ -416,7 +405,7 @@ sctp_assoclist(SYSCTL_HANDLER_ARGS) error = SYSCTL_OUT(req, &xstcb, sizeof(struct xsctp_tcb)); if (error) { SCTP_INP_DECR_REF(inp); - atomic_add_int(&stcb->asoc.refcnt, -1); + atomic_subtract_int(&stcb->asoc.refcnt, 1); return error; } SCTP_INP_INFO_RLOCK(); @@ -424,7 +413,7 @@ sctp_assoclist(SYSCTL_HANDLER_ARGS) error = copy_out_local_addresses(inp, stcb, req); if (error) { SCTP_INP_DECR_REF(inp); - atomic_add_int(&stcb->asoc.refcnt, -1); + atomic_subtract_int(&stcb->asoc.refcnt, 1); return error; } TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { @@ -440,19 +429,20 @@ sctp_assoclist(SYSCTL_HANDLER_ARGS) xraddr.cwnd = net->cwnd; xraddr.flight_size = net->flight_size; xraddr.mtu = net->mtu; - xraddr.start_time = net->start_time; + xraddr.start_time.tv_sec = (uint32_t) net->start_time.tv_sec; + xraddr.start_time.tv_usec = (uint32_t) net->start_time.tv_usec; SCTP_INP_RUNLOCK(inp); SCTP_INP_INFO_RUNLOCK(); error = SYSCTL_OUT(req, &xraddr, sizeof(struct xsctp_raddr)); if (error) { SCTP_INP_DECR_REF(inp); - atomic_add_int(&stcb->asoc.refcnt, -1); + atomic_subtract_int(&stcb->asoc.refcnt, 1); return error; } SCTP_INP_INFO_RLOCK(); SCTP_INP_RLOCK(inp); } - atomic_add_int(&stcb->asoc.refcnt, -1); + atomic_subtract_int(&stcb->asoc.refcnt, 1); memset((void *)&xraddr, 0, sizeof(struct xsctp_raddr)); xraddr.last = 1; SCTP_INP_RUNLOCK(inp); @@ -465,6 +455,7 @@ sctp_assoclist(SYSCTL_HANDLER_ARGS) SCTP_INP_INFO_RLOCK(); SCTP_INP_RLOCK(inp); } + SCTP_INP_DECR_REF(inp); SCTP_INP_RUNLOCK(inp); SCTP_INP_INFO_RUNLOCK(); memset((void *)&xstcb, 0, sizeof(struct xsctp_tcb)); @@ -474,7 +465,6 @@ sctp_assoclist(SYSCTL_HANDLER_ARGS) return error; } SCTP_INP_INFO_RLOCK(); - SCTP_INP_DECR_REF(inp); } SCTP_INP_INFO_RUNLOCK(); @@ -484,244 +474,326 @@ sctp_assoclist(SYSCTL_HANDLER_ARGS) return error; } +#define RANGECHK(var, min, max) \ + if ((var) < (min)) { (var) = (min); } \ + else if ((var) > (max)) { (var) = (max); } + +static int +sysctl_sctp_check(SYSCTL_HANDLER_ARGS) +{ + int error; + + error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req); + if (error == 0) { + RANGECHK(sctp_sendspace, SCTPCTL_MAXDGRAM_MIN, SCTPCTL_MAXDGRAM_MAX); + RANGECHK(sctp_recvspace, SCTPCTL_RECVSPACE_MIN, SCTPCTL_RECVSPACE_MAX); +#if defined(__FreeBSD__) || defined(SCTP_APPLE_AUTO_ASCONF) + RANGECHK(sctp_auto_asconf, SCTPCTL_AUTOASCONF_MIN, SCTPCTL_AUTOASCONF_MAX); +#endif + RANGECHK(sctp_ecn_enable, SCTPCTL_ECN_ENABLE_MIN, SCTPCTL_ECN_ENABLE_MAX); + RANGECHK(sctp_ecn_nonce, SCTPCTL_ECN_NONCE_MIN, SCTPCTL_ECN_NONCE_MAX); + RANGECHK(sctp_strict_sacks, SCTPCTL_STRICT_SACKS_MIN, SCTPCTL_STRICT_SACKS_MAX); + RANGECHK(sctp_no_csum_on_loopback, SCTPCTL_LOOPBACK_NOCSUM_MIN, SCTPCTL_LOOPBACK_NOCSUM_MAX); + RANGECHK(sctp_strict_init, SCTPCTL_STRICT_INIT_MIN, SCTPCTL_STRICT_INIT_MAX); + RANGECHK(sctp_peer_chunk_oh, SCTPCTL_PEER_CHKOH_MIN, SCTPCTL_PEER_CHKOH_MAX); + RANGECHK(sctp_max_burst_default, SCTPCTL_MAXBURST_MIN, SCTPCTL_MAXBURST_MAX); + RANGECHK(sctp_max_chunks_on_queue, SCTPCTL_MAXCHUNKS_MIN, SCTPCTL_MAXCHUNKS_MAX); + RANGECHK(sctp_hashtblsize, SCTPCTL_TCBHASHSIZE_MIN, SCTPCTL_TCBHASHSIZE_MAX); + RANGECHK(sctp_pcbtblsize, SCTPCTL_PCBHASHSIZE_MIN, SCTPCTL_PCBHASHSIZE_MAX); + RANGECHK(sctp_min_split_point, SCTPCTL_MIN_SPLIT_POINT_MIN, SCTPCTL_MIN_SPLIT_POINT_MAX); + RANGECHK(sctp_chunkscale, SCTPCTL_CHUNKSCALE_MIN, SCTPCTL_CHUNKSCALE_MAX); + RANGECHK(sctp_delayed_sack_time_default, SCTPCTL_DELAYED_SACK_TIME_MIN, SCTPCTL_DELAYED_SACK_TIME_MAX); + RANGECHK(sctp_sack_freq_default, SCTPCTL_SACK_FREQ_MIN, SCTPCTL_SACK_FREQ_MAX); + RANGECHK(sctp_system_free_resc_limit, SCTPCTL_SYS_RESOURCE_MIN, SCTPCTL_SYS_RESOURCE_MAX); + RANGECHK(sctp_asoc_free_resc_limit, SCTPCTL_ASOC_RESOURCE_MIN, SCTPCTL_ASOC_RESOURCE_MAX); + RANGECHK(sctp_heartbeat_interval_default, SCTPCTL_HEARTBEAT_INTERVAL_MIN, SCTPCTL_HEARTBEAT_INTERVAL_MAX); + RANGECHK(sctp_pmtu_raise_time_default, SCTPCTL_PMTU_RAISE_TIME_MIN, SCTPCTL_PMTU_RAISE_TIME_MAX); + RANGECHK(sctp_shutdown_guard_time_default, SCTPCTL_SHUTDOWN_GUARD_TIME_MIN, SCTPCTL_SHUTDOWN_GUARD_TIME_MAX); + RANGECHK(sctp_secret_lifetime_default, SCTPCTL_SECRET_LIFETIME_MIN, SCTPCTL_SECRET_LIFETIME_MAX); + RANGECHK(sctp_rto_max_default, SCTPCTL_RTO_MAX_MIN, SCTPCTL_RTO_MAX_MAX); + RANGECHK(sctp_rto_min_default, SCTPCTL_RTO_MIN_MIN, SCTPCTL_RTO_MIN_MAX); + RANGECHK(sctp_rto_initial_default, SCTPCTL_RTO_INITIAL_MIN, SCTPCTL_RTO_INITIAL_MAX); + RANGECHK(sctp_init_rto_max_default, SCTPCTL_INIT_RTO_MAX_MIN, SCTPCTL_INIT_RTO_MAX_MAX); + RANGECHK(sctp_valid_cookie_life_default, SCTPCTL_VALID_COOKIE_LIFE_MIN, SCTPCTL_VALID_COOKIE_LIFE_MAX); + RANGECHK(sctp_init_rtx_max_default, SCTPCTL_INIT_RTX_MAX_MIN, SCTPCTL_INIT_RTX_MAX_MAX); + RANGECHK(sctp_assoc_rtx_max_default, SCTPCTL_ASSOC_RTX_MAX_MIN, SCTPCTL_ASSOC_RTX_MAX_MAX); + RANGECHK(sctp_path_rtx_max_default, SCTPCTL_PATH_RTX_MAX_MIN, SCTPCTL_PATH_RTX_MAX_MAX); + RANGECHK(sctp_add_more_threshold, SCTPCTL_ADD_MORE_ON_OUTPUT_MIN, SCTPCTL_ADD_MORE_ON_OUTPUT_MAX); + RANGECHK(sctp_nr_outgoing_streams_default, SCTPCTL_OUTGOING_STREAMS_MIN, SCTPCTL_OUTGOING_STREAMS_MAX); + RANGECHK(sctp_cmt_on_off, SCTPCTL_CMT_ON_OFF_MIN, SCTPCTL_CMT_ON_OFF_MAX); + RANGECHK(sctp_cmt_use_dac, SCTPCTL_CMT_USE_DAC_MIN, SCTPCTL_CMT_USE_DAC_MAX); + RANGECHK(sctp_cmt_pf, SCTPCTL_CMT_PF_MIN, SCTPCTL_CMT_PF_MAX); + RANGECHK(sctp_use_cwnd_based_maxburst, SCTPCTL_CWND_MAXBURST_MIN, SCTPCTL_CWND_MAXBURST_MAX); + RANGECHK(sctp_early_fr, SCTPCTL_EARLY_FAST_RETRAN_MIN, SCTPCTL_EARLY_FAST_RETRAN_MAX); + RANGECHK(sctp_early_fr_msec, SCTPCTL_EARLY_FAST_RETRAN_MSEC_MIN, SCTPCTL_EARLY_FAST_RETRAN_MSEC_MAX); + RANGECHK(sctp_asconf_auth_nochk, SCTPCTL_ASCONF_AUTH_NOCHK_MIN, SCTPCTL_ASCONF_AUTH_NOCHK_MAX); + RANGECHK(sctp_auth_disable, SCTPCTL_AUTH_DISABLE_MIN, SCTPCTL_AUTH_DISABLE_MAX); + RANGECHK(sctp_nat_friendly, SCTPCTL_NAT_FRIENDLY_MIN, SCTPCTL_NAT_FRIENDLY_MAX); + RANGECHK(sctp_L2_abc_variable, SCTPCTL_ABC_L_VAR_MIN, SCTPCTL_ABC_L_VAR_MAX); + RANGECHK(sctp_mbuf_threshold_count, SCTPCTL_MAX_CHAINED_MBUFS_MIN, SCTPCTL_MAX_CHAINED_MBUFS_MAX); + RANGECHK(sctp_do_drain, SCTPCTL_DO_SCTP_DRAIN_MIN, SCTPCTL_DO_SCTP_DRAIN_MAX); + RANGECHK(sctp_hb_maxburst, SCTPCTL_HB_MAX_BURST_MIN, SCTPCTL_HB_MAX_BURST_MAX); + RANGECHK(sctp_abort_if_one_2_one_hits_limit, SCTPCTL_ABORT_AT_LIMIT_MIN, SCTPCTL_ABORT_AT_LIMIT_MAX); + RANGECHK(sctp_strict_data_order, SCTPCTL_STRICT_DATA_ORDER_MIN, SCTPCTL_STRICT_DATA_ORDER_MAX); + RANGECHK(sctp_min_residual, SCTPCTL_MIN_RESIDUAL_MIN, SCTPCTL_MIN_RESIDUAL_MAX); + RANGECHK(sctp_max_retran_chunk, SCTPCTL_MAX_RETRAN_CHUNK_MIN, SCTPCTL_MAX_RETRAN_CHUNK_MAX); + RANGECHK(sctp_logging_level, SCTPCTL_LOGGING_LEVEL_MIN, SCTPCTL_LOGGING_LEVEL_MAX); + RANGECHK(sctp_default_cc_module, SCTPCTL_DEFAULT_CC_MODULE_MIN, SCTPCTL_DEFAULT_CC_MODULE_MAX); + RANGECHK(sctp_default_frag_interleave, SCTPCTL_DEFAULT_FRAG_INTERLEAVE_MIN, SCTPCTL_DEFAULT_FRAG_INTERLEAVE_MAX); +#if defined(__FreeBSD__) || defined(SCTP_APPLE_MOBILITY_BASE) + RANGECHK(sctp_mobility_base, SCTPCTL_MOBILITY_BASE_MIN, SCTPCTL_MOBILITY_BASE_MAX); +#endif +#if defined(__FreeBSD__) || defined(SCTP_APPLE_MOBILITY_FASTHANDOFF) + RANGECHK(sctp_mobility_fasthandoff, SCTPCTL_MOBILITY_FASTHANDOFF_MIN, SCTPCTL_MOBILITY_FASTHANDOFF_MAX); +#endif +#ifdef SCTP_DEBUG + RANGECHK(sctp_debug_on, SCTPCTL_DEBUG_MIN, SCTPCTL_DEBUG_MAX); +#endif + } + return (error); +} /* * sysctl definitions */ -SYSCTL_INT(_net_inet_sctp, OID_AUTO, sendspace, CTLFLAG_RW, - &sctp_sendspace, 0, "Maximum outgoing SCTP buffer size"); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, sendspace, CTLTYPE_INT | CTLFLAG_RW, + &sctp_sendspace, 0, sysctl_sctp_check, "IU", + SCTPCTL_MAXDGRAM_DESC); -SYSCTL_INT(_net_inet_sctp, OID_AUTO, recvspace, CTLFLAG_RW, - &sctp_recvspace, 0, "Maximum incoming SCTP buffer size"); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, recvspace, CTLTYPE_INT | CTLFLAG_RW, + &sctp_recvspace, 0, sysctl_sctp_check, "IU", + SCTPCTL_RECVSPACE_DESC); #if defined(__FreeBSD__) || defined(SCTP_APPLE_AUTO_ASCONF) -SYSCTL_INT(_net_inet_sctp, OID_AUTO, auto_asconf, CTLFLAG_RW, - &sctp_auto_asconf, 0, "Enable SCTP Auto-ASCONF"); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, auto_asconf, CTLTYPE_INT | CTLFLAG_RW, + &sctp_auto_asconf, 0, sysctl_sctp_check, "IU", + SCTPCTL_AUTOASCONF_DESC); #endif -SYSCTL_INT(_net_inet_sctp, OID_AUTO, ecn_enable, CTLFLAG_RW, - &sctp_ecn_enable, 0, "Enable SCTP ECN"); - -SYSCTL_INT(_net_inet_sctp, OID_AUTO, ecn_nonce, CTLFLAG_RW, - &sctp_ecn_nonce, 0, "Enable SCTP ECN Nonce"); - -SYSCTL_INT(_net_inet_sctp, OID_AUTO, strict_sacks, CTLFLAG_RW, - &sctp_strict_sacks, 0, "Enable SCTP Strict SACK checking"); - -SYSCTL_INT(_net_inet_sctp, OID_AUTO, loopback_nocsum, CTLFLAG_RW, - &sctp_no_csum_on_loopback, 0, - "Enable NO Csum on packets sent on loopback"); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, ecn_enable, CTLTYPE_INT | CTLFLAG_RW, + &sctp_ecn_enable, 0, sysctl_sctp_check, "IU", + SCTPCTL_ECN_ENABLE_DESC); -SYSCTL_INT(_net_inet_sctp, OID_AUTO, strict_init, CTLFLAG_RW, - &sctp_strict_init, 0, - "Enable strict INIT/INIT-ACK singleton enforcement"); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, ecn_nonce, CTLTYPE_INT | CTLFLAG_RW, + &sctp_ecn_nonce, 0, sysctl_sctp_check, "IU", + SCTPCTL_ECN_NONCE_DESC); -SYSCTL_INT(_net_inet_sctp, OID_AUTO, peer_chkoh, CTLFLAG_RW, - &sctp_peer_chunk_oh, 0, - "Amount to debit peers rwnd per chunk sent"); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, strict_sacks, CTLTYPE_INT | CTLFLAG_RW, + &sctp_strict_sacks, 0, sysctl_sctp_check, "IU", + SCTPCTL_STRICT_SACKS_DESC); -SYSCTL_INT(_net_inet_sctp, OID_AUTO, maxburst, CTLFLAG_RW, - &sctp_max_burst_default, 0, - "Default max burst for sctp endpoints"); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, loopback_nocsum, CTLTYPE_INT | CTLFLAG_RW, + &sctp_no_csum_on_loopback, 0, sysctl_sctp_check, "IU", + SCTPCTL_LOOPBACK_NOCSUM_DESC); -SYSCTL_INT(_net_inet_sctp, OID_AUTO, maxchunks, CTLFLAG_RW, - &sctp_max_chunks_on_queue, 0, - "Default max chunks on queue per asoc"); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, strict_init, CTLTYPE_INT | CTLFLAG_RW, + &sctp_strict_init, 0, sysctl_sctp_check, "IU", + SCTPCTL_STRICT_INIT_DESC); -SYSCTL_INT(_net_inet_sctp, OID_AUTO, tcbhashsize, CTLFLAG_RW, - &sctp_hashtblsize, 0, - "Tuneable for Hash table sizes"); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, peer_chkoh, CTLTYPE_INT | CTLFLAG_RW, + &sctp_peer_chunk_oh, 0, sysctl_sctp_check, "IU", + SCTPCTL_PEER_CHKOH_DESC); -SYSCTL_INT(_net_inet_sctp, OID_AUTO, min_split_point, CTLFLAG_RW, - &sctp_min_split_point, 0, - "Minimum size when splitting a chunk"); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, maxburst, CTLTYPE_INT | CTLFLAG_RW, + &sctp_max_burst_default, 0, sysctl_sctp_check, "IU", + SCTPCTL_MAXBURST_DESC); -SYSCTL_INT(_net_inet_sctp, OID_AUTO, pcbhashsize, CTLFLAG_RW, - &sctp_pcbtblsize, 0, - "Tuneable for PCB Hash table sizes"); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, maxchunks, CTLTYPE_INT | CTLFLAG_RW, + &sctp_max_chunks_on_queue, 0, sysctl_sctp_check, "IU", + SCTPCTL_MAXCHUNKS_DESC); -SYSCTL_INT(_net_inet_sctp, OID_AUTO, sys_resource, CTLFLAG_RW, - &sctp_system_free_resc_limit, 0, - "Max number of cached resources in the system"); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, tcbhashsize, CTLTYPE_INT | CTLFLAG_RW, + &sctp_hashtblsize, 0, sysctl_sctp_check, "IU", + SCTPCTL_TCBHASHSIZE_DESC); -SYSCTL_INT(_net_inet_sctp, OID_AUTO, asoc_resource, CTLFLAG_RW, - &sctp_asoc_free_resc_limit, 0, - "Max number of cached resources in an asoc"); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, pcbhashsize, CTLTYPE_INT | CTLFLAG_RW, + &sctp_pcbtblsize, 0, sysctl_sctp_check, "IU", + SCTPCTL_PCBHASHSIZE_DESC); -SYSCTL_INT(_net_inet_sctp, OID_AUTO, chunkscale, CTLFLAG_RW, - &sctp_chunkscale, 0, - "Tuneable for Scaling of number of chunks and messages"); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, min_split_point, CTLTYPE_INT | CTLFLAG_RW, + &sctp_min_split_point, 0, sysctl_sctp_check, "IU", + SCTPCTL_MIN_SPLIT_POINT_DESC); -SYSCTL_UINT(_net_inet_sctp, OID_AUTO, delayed_sack_time, CTLFLAG_RW, - &sctp_delayed_sack_time_default, 0, - "Default delayed SACK timer in msec"); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, chunkscale, CTLTYPE_INT | CTLFLAG_RW, + &sctp_chunkscale, 0, sysctl_sctp_check, "IU", + SCTPCTL_CHUNKSCALE_DESC); -SYSCTL_UINT(_net_inet_sctp, OID_AUTO, sack_freq, CTLFLAG_RW, - &sctp_sack_freq_default, 0, - "Default SACK frequency"); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, delayed_sack_time, CTLTYPE_INT | CTLFLAG_RW, + &sctp_delayed_sack_time_default, 0, sysctl_sctp_check, "IU", + SCTPCTL_DELAYED_SACK_TIME_DESC); -SYSCTL_UINT(_net_inet_sctp, OID_AUTO, heartbeat_interval, CTLFLAG_RW, - &sctp_heartbeat_interval_default, 0, - "Default heartbeat interval in msec"); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, sack_freq, CTLTYPE_INT | CTLFLAG_RW, + &sctp_sack_freq_default, 0, sysctl_sctp_check, "IU", + SCTPCTL_SACK_FREQ_DESC); -SYSCTL_UINT(_net_inet_sctp, OID_AUTO, pmtu_raise_time, CTLFLAG_RW, - &sctp_pmtu_raise_time_default, 0, - "Default PMTU raise timer in sec"); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, sys_resource, CTLTYPE_INT | CTLFLAG_RW, + &sctp_system_free_resc_limit, 0, sysctl_sctp_check, "IU", + SCTPCTL_SYS_RESOURCE_DESC); -SYSCTL_UINT(_net_inet_sctp, OID_AUTO, shutdown_guard_time, CTLFLAG_RW, - &sctp_shutdown_guard_time_default, 0, - "Default shutdown guard timer in sec"); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, asoc_resource, CTLTYPE_INT | CTLFLAG_RW, + &sctp_asoc_free_resc_limit, 0, sysctl_sctp_check, "IU", + SCTPCTL_ASOC_RESOURCE_DESC); -SYSCTL_UINT(_net_inet_sctp, OID_AUTO, secret_lifetime, CTLFLAG_RW, - &sctp_secret_lifetime_default, 0, - "Default secret lifetime in sec"); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, heartbeat_interval, CTLTYPE_INT | CTLFLAG_RW, + &sctp_heartbeat_interval_default, 0, sysctl_sctp_check, "IU", + SCTPCTL_HEARTBEAT_INTERVAL_DESC); -SYSCTL_UINT(_net_inet_sctp, OID_AUTO, rto_max, CTLFLAG_RW, - &sctp_rto_max_default, 0, - "Default maximum retransmission timeout in msec"); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, pmtu_raise_time, CTLTYPE_INT | CTLFLAG_RW, + &sctp_pmtu_raise_time_default, 0, sysctl_sctp_check, "IU", + SCTPCTL_PMTU_RAISE_TIME_DESC); -SYSCTL_UINT(_net_inet_sctp, OID_AUTO, rto_min, CTLFLAG_RW, - &sctp_rto_min_default, 0, - "Default minimum retransmission timeout in msec"); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, shutdown_guard_time, CTLTYPE_INT | CTLFLAG_RW, + &sctp_shutdown_guard_time_default, 0, sysctl_sctp_check, "IU", + SCTPCTL_SHUTDOWN_GUARD_TIME_DESC); -SYSCTL_UINT(_net_inet_sctp, OID_AUTO, rto_initial, CTLFLAG_RW, - &sctp_rto_initial_default, 0, - "Default initial retransmission timeout in msec"); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, secret_lifetime, CTLTYPE_INT | CTLFLAG_RW, + &sctp_secret_lifetime_default, 0, sysctl_sctp_check, "IU", + SCTPCTL_SECRET_LIFETIME_DESC); -SYSCTL_UINT(_net_inet_sctp, OID_AUTO, init_rto_max, CTLFLAG_RW, - &sctp_init_rto_max_default, 0, - "Default maximum retransmission timeout during association setup in msec"); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, rto_max, CTLTYPE_INT | CTLFLAG_RW, + &sctp_rto_max_default, 0, sysctl_sctp_check, "IU", + SCTPCTL_RTO_MAX_DESC); -SYSCTL_UINT(_net_inet_sctp, OID_AUTO, valid_cookie_life, CTLFLAG_RW, - &sctp_valid_cookie_life_default, 0, - "Default cookie lifetime in ticks"); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, rto_min, CTLTYPE_INT | CTLFLAG_RW, + &sctp_rto_min_default, 0, sysctl_sctp_check, "IU", + SCTPCTL_RTO_MIN_DESC); -SYSCTL_UINT(_net_inet_sctp, OID_AUTO, init_rtx_max, CTLFLAG_RW, - &sctp_init_rtx_max_default, 0, - "Default maximum number of retransmission for INIT chunks"); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, rto_initial, CTLTYPE_INT | CTLFLAG_RW, + &sctp_rto_initial_default, 0, sysctl_sctp_check, "IU", + SCTPCTL_RTO_INITIAL_DESC); -SYSCTL_UINT(_net_inet_sctp, OID_AUTO, assoc_rtx_max, CTLFLAG_RW, - &sctp_assoc_rtx_max_default, 0, - "Default maximum number of retransmissions per association"); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, init_rto_max, CTLTYPE_INT | CTLFLAG_RW, + &sctp_init_rto_max_default, 0, sysctl_sctp_check, "IU", + SCTPCTL_INIT_RTO_MAX_DESC); -SYSCTL_UINT(_net_inet_sctp, OID_AUTO, path_rtx_max, CTLFLAG_RW, - &sctp_path_rtx_max_default, 0, - "Default maximum of retransmissions per path"); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, valid_cookie_life, CTLTYPE_INT | CTLFLAG_RW, + &sctp_valid_cookie_life_default, 0, sysctl_sctp_check, "IU", + SCTPCTL_VALID_COOKIE_LIFE_DESC); -SYSCTL_UINT(_net_inet_sctp, OID_AUTO, add_more_on_output, CTLFLAG_RW, - &sctp_add_more_threshold, 0, - "When space wise is it worthwhile to try to add more to a socket send buffer"); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, init_rtx_max, CTLTYPE_INT | CTLFLAG_RW, + &sctp_init_rtx_max_default, 0, sysctl_sctp_check, "IU", + SCTPCTL_INIT_RTX_MAX_DESC); -SYSCTL_UINT(_net_inet_sctp, OID_AUTO, outgoing_streams, CTLFLAG_RW, - &sctp_nr_outgoing_streams_default, 0, - "Default number of outgoing streams"); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, assoc_rtx_max, CTLTYPE_INT | CTLFLAG_RW, + &sctp_assoc_rtx_max_default, 0, sysctl_sctp_check, "IU", + SCTPCTL_ASSOC_RTX_MAX_DESC); -SYSCTL_UINT(_net_inet_sctp, OID_AUTO, cmt_on_off, CTLFLAG_RW, - &sctp_cmt_on_off, 0, - "CMT ON/OFF flag"); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, path_rtx_max, CTLTYPE_INT | CTLFLAG_RW, + &sctp_path_rtx_max_default, 0, sysctl_sctp_check, "IU", + SCTPCTL_PATH_RTX_MAX_DESC); -SYSCTL_UINT(_net_inet_sctp, OID_AUTO, cmt_pf, CTLFLAG_RW, - &sctp_cmt_pf, 0, - "CMT PF type flag"); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, add_more_on_output, CTLTYPE_INT | CTLFLAG_RW, + &sctp_add_more_threshold, 0, sysctl_sctp_check, "IU", + SCTPCTL_ADD_MORE_ON_OUTPUT_DESC); -SYSCTL_UINT(_net_inet_sctp, OID_AUTO, default_cc_module, CTLFLAG_RW, - &sctp_default_cc_module, 0, - "Default congestion control module"); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, outgoing_streams, CTLTYPE_INT | CTLFLAG_RW, + &sctp_nr_outgoing_streams_default, 0, sysctl_sctp_check, "IU", + SCTPCTL_OUTGOING_STREAMS_DESC); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, cmt_on_off, CTLTYPE_INT | CTLFLAG_RW, + &sctp_cmt_on_off, 0, sysctl_sctp_check, "IU", + SCTPCTL_CMT_ON_OFF_DESC); -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"); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, cmt_use_dac, CTLTYPE_INT | CTLFLAG_RW, + &sctp_cmt_use_dac, 0, sysctl_sctp_check, "IU", + SCTPCTL_CMT_USE_DAC_DESC); -SYSCTL_UINT(_net_inet_sctp, OID_AUTO, early_fast_retran, CTLFLAG_RW, - &sctp_early_fr, 0, - "Early Fast Retransmit with timer"); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, cmt_pf, CTLTYPE_INT | CTLFLAG_RW, + &sctp_cmt_pf, 0, sysctl_sctp_check, "IU", + SCTPCTL_CMT_PF_DESC); -SYSCTL_UINT(_net_inet_sctp, OID_AUTO, deadlock_detect, CTLFLAG_RW, - &sctp_says_check_for_deadlock, 0, - "SMP Deadlock detection on/off"); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, cwnd_maxburst, CTLTYPE_INT | CTLFLAG_RW, + &sctp_use_cwnd_based_maxburst, 0, sysctl_sctp_check, "IU", + SCTPCTL_CWND_MAXBURST_DESC); -SYSCTL_UINT(_net_inet_sctp, OID_AUTO, early_fast_retran_msec, CTLFLAG_RW, - &sctp_early_fr_msec, 0, - "Early Fast Retransmit minimum timer value"); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, early_fast_retran, CTLTYPE_INT | CTLFLAG_RW, + &sctp_early_fr, 0, sysctl_sctp_check, "IU", + SCTPCTL_EARLY_FAST_RETRAN_DESC); -SYSCTL_UINT(_net_inet_sctp, OID_AUTO, asconf_auth_nochk, CTLFLAG_RW, - &sctp_asconf_auth_nochk, 0, - "Disable SCTP ASCONF AUTH requirement"); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, early_fast_retran_msec, CTLTYPE_INT | CTLFLAG_RW, + &sctp_early_fr_msec, 0, sysctl_sctp_check, "IU", + SCTPCTL_EARLY_FAST_RETRAN_MSEC_DESC); -SYSCTL_UINT(_net_inet_sctp, OID_AUTO, auth_disable, CTLFLAG_RW, - &sctp_auth_disable, 0, - "Disable SCTP AUTH function"); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, asconf_auth_nochk, CTLTYPE_INT | CTLFLAG_RW, + &sctp_asconf_auth_nochk, 0, sysctl_sctp_check, "IU", + SCTPCTL_ASCONF_AUTH_NOCHK_DESC); -SYSCTL_UINT(_net_inet_sctp, OID_AUTO, nat_friendly, CTLFLAG_RW, - &sctp_nat_friendly, 0, - "SCTP NAT friendly operation"); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, auth_disable, CTLTYPE_INT | CTLFLAG_RW, + &sctp_auth_disable, 0, sysctl_sctp_check, "IU", + SCTPCTL_AUTH_DISABLE_DESC); -SYSCTL_INT(_net_inet_sctp, OID_AUTO, abc_l_var, CTLFLAG_RW, - &sctp_L2_abc_variable, 0, - "SCTP ABC max increase per SACK (L)"); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, nat_friendly, CTLTYPE_INT | CTLFLAG_RW, + &sctp_nat_friendly, 0, sysctl_sctp_check, "IU", + SCTPCTL_NAT_FRIENDLY_DESC); -SYSCTL_INT(_net_inet_sctp, OID_AUTO, max_chained_mbufs, CTLFLAG_RW, - &sctp_mbuf_threshold_count, 0, - "Default max number of small mbufs on a chain"); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, abc_l_var, CTLTYPE_INT | CTLFLAG_RW, + &sctp_L2_abc_variable, 0, sysctl_sctp_check, "IU", + SCTPCTL_ABC_L_VAR_DESC); -SYSCTL_UINT(_net_inet_sctp, OID_AUTO, cmt_use_dac, CTLFLAG_RW, - &sctp_cmt_use_dac, 0, - "CMT DAC ON/OFF flag"); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, max_chained_mbufs, CTLTYPE_INT | CTLFLAG_RW, + &sctp_mbuf_threshold_count, 0, sysctl_sctp_check, "IU", + SCTPCTL_MAX_CHAINED_MBUFS_DESC); -SYSCTL_INT(_net_inet_sctp, OID_AUTO, do_sctp_drain, CTLFLAG_RW, - &sctp_do_drain, 0, - "Should SCTP respond to the drain calls"); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, do_sctp_drain, CTLTYPE_INT | CTLFLAG_RW, + &sctp_do_drain, 0, sysctl_sctp_check, "IU", + SCTPCTL_DO_SCTP_DRAIN_DESC); -SYSCTL_INT(_net_inet_sctp, OID_AUTO, hb_max_burst, CTLFLAG_RW, - &sctp_hb_maxburst, 0, - "Confirmation Heartbeat max burst?"); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, hb_max_burst, CTLTYPE_INT | CTLFLAG_RW, + &sctp_hb_maxburst, 0, sysctl_sctp_check, "IU", + SCTPCTL_HB_MAX_BURST_DESC); -SYSCTL_INT(_net_inet_sctp, OID_AUTO, abort_at_limit, CTLFLAG_RW, - &sctp_abort_if_one_2_one_hits_limit, 0, - "When one-2-one hits qlimit abort"); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, abort_at_limit, CTLTYPE_INT | CTLFLAG_RW, + &sctp_abort_if_one_2_one_hits_limit, 0, sysctl_sctp_check, "IU", + SCTPCTL_ABORT_AT_LIMIT_DESC); -SYSCTL_INT(_net_inet_sctp, OID_AUTO, strict_data_order, CTLFLAG_RW, - &sctp_strict_data_order, 0, - "Enforce strict data ordering, abort if control inside data"); - -SYSCTL_STRUCT(_net_inet_sctp, OID_AUTO, stats, CTLFLAG_RW, - &sctpstat, sctpstat, - "SCTP statistics (struct sctps_stat, netinet/sctp.h"); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, strict_data_order, CTLTYPE_INT | CTLFLAG_RW, + &sctp_strict_data_order, 0, sysctl_sctp_check, "IU", + SCTPCTL_STRICT_DATA_ORDER_DESC); -SYSCTL_PROC(_net_inet_sctp, OID_AUTO, assoclist, CTLFLAG_RD, - 0, 0, sctp_assoclist, - "S,xassoc", "List of active SCTP associations"); - -SYSCTL_INT(_net_inet_sctp, OID_AUTO, min_residual, CTLFLAG_RW, - &sctp_min_residual, 0, +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, min_residual, CTLTYPE_INT | CTLFLAG_RW, + &sctp_min_residual, 0, sysctl_sctp_check, "IU", SCTPCTL_MIN_RESIDUAL_DESC); -SYSCTL_INT(_net_inet_sctp, OID_AUTO, max_retran_chunk, CTLFLAG_RW, - &sctp_max_retran_chunk, 0, +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, max_retran_chunk, CTLTYPE_INT | CTLFLAG_RW, + &sctp_max_retran_chunk, 0, sysctl_sctp_check, "IU", SCTPCTL_MAX_RETRAN_CHUNK_DESC); -SYSCTL_INT(_net_inet_sctp, OID_AUTO, sctp_logging, CTLFLAG_RW, - &sctp_logging_level, 0, +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, logging, CTLTYPE_INT | CTLFLAG_RW, + &sctp_logging_level, 0, sysctl_sctp_check, "IU", SCTPCTL_LOGGING_LEVEL_DESC); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, default_cc_module, CTLTYPE_INT | CTLFLAG_RW, + &sctp_default_cc_module, 0, sysctl_sctp_check, "IU", + SCTPCTL_DEFAULT_CC_MODULE_DESC); + +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, default_frag_interleave, CTLTYPE_INT | CTLFLAG_RW, + &sctp_default_frag_interleave, 0, sysctl_sctp_check, "IU", + SCTPCTL_DEFAULT_FRAG_INTERLEAVE_DESC); + #if defined(__FreeBSD__) || defined(SCTP_APPLE_MOBILITY_BASE) -SYSCTL_INT(_net_inet_sctp, OID_AUTO, mobility_base, CTLFLAG_RW, - &sctp_mobility_base, 0, "Enable SCTP Mobility"); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, mobility_base, CTLTYPE_INT | CTLFLAG_RW, + &sctp_mobility_base, 0, sysctl_sctp_check, "IU", + SCTPCTL_MOBILITY_BASE_DESC); #endif #if defined(__FreeBSD__) || defined(SCTP_APPLE_MOBILITY_FASTHANDOFF) -SYSCTL_INT(_net_inet_sctp, OID_AUTO, mobility_fasthandoff, CTLFLAG_RW, - &sctp_mobility_fasthandoff, 0, "Enable SCTP fast handoff"); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, mobility_fasthandoff, CTLTYPE_INT | CTLFLAG_RW, + &sctp_mobility_fasthandoff, 0, sysctl_sctp_check, "IU", + SCTPCTL_MOBILITY_FASTHANDOFF_DESC); #endif - #ifdef SCTP_DEBUG -SYSCTL_INT(_net_inet_sctp, OID_AUTO, debug, CTLFLAG_RW, - &sctp_debug_on, 0, "Configure debug output"); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, debug, CTLTYPE_INT | CTLFLAG_RW, + &sctp_debug_on, 0, sysctl_sctp_check, "IU", + SCTPCTL_DEBUG_DESC); #endif /* SCTP_DEBUG */ + + +SYSCTL_STRUCT(_net_inet_sctp, OID_AUTO, stats, CTLFLAG_RW, + &sctpstat, sctpstat, + "SCTP statistics (struct sctps_stat, netinet/sctp.h"); + +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, assoclist, CTLFLAG_RD, + 0, 0, sctp_assoclist, + "S,xassoc", "List of active SCTP associations"); diff --git a/sys/netinet/sctp_sysctl.h b/sys/netinet/sctp_sysctl.h index 573f46b..cb83f4e 100644 --- a/sys/netinet/sctp_sysctl.h +++ b/sys/netinet/sctp_sysctl.h @@ -278,78 +278,76 @@ __FBSDID("$FreeBSD$"); #define SCTPCTL_CMT_ON_OFF_MAX 1 #define SCTPCTL_CMT_ON_OFF_DEFAULT 0 +/* cmt_use_dac: CMT DAC on/off flag */ +#define SCTPCTL_CMT_USE_DAC 35 +#define SCTPCTL_CMT_USE_DAC_DESC "CMT DAC on/off flag" +#define SCTPCTL_CMT_USE_DAC_MIN 0 +#define SCTPCTL_CMT_USE_DAC_MAX 1 +#define SCTPCTL_CMT_USE_DAC_DEFAULT 0 + +/* JRS 5/2107 - CMT PF type flag */ +#define SCTPCTL_CMT_PF 36 +#define SCTPCTL_CMT_PF_DESC "CMT PF type flag" +#define SCTPCTL_CMT_PF_MIN 0 +#define SCTPCTL_CMT_PF_MAX 2 +#define SCTPCTL_CMT_PF_DEFAULT 0 + /* cwnd_maxburst: Use a CWND adjusting maxburst */ -#define SCTPCTL_CWND_MAXBURST 35 +#define SCTPCTL_CWND_MAXBURST 37 #define SCTPCTL_CWND_MAXBURST_DESC "Use a CWND adjusting maxburst" #define SCTPCTL_CWND_MAXBURST_MIN 0 #define SCTPCTL_CWND_MAXBURST_MAX 1 #define SCTPCTL_CWND_MAXBURST_DEFAULT 1 /* early_fast_retran: Early Fast Retransmit with timer */ -#define SCTPCTL_EARLY_FAST_RETRAN 36 +#define SCTPCTL_EARLY_FAST_RETRAN 38 #define SCTPCTL_EARLY_FAST_RETRAN_DESC "Early Fast Retransmit with timer" #define SCTPCTL_EARLY_FAST_RETRAN_MIN 0 #define SCTPCTL_EARLY_FAST_RETRAN_MAX 0xFFFFFFFF #define SCTPCTL_EARLY_FAST_RETRAN_DEFAULT 0 -/* deadlock_detect: SMP Deadlock detection on/off */ -#define SCTPCTL_DEADLOCK_DETECT 37 -#define SCTPCTL_DEADLOCK_DETECT_DESC "SMP Deadlock detection on/off" -#define SCTPCTL_DEADLOCK_DETECT_MIN 0 -#define SCTPCTL_DEADLOCK_DETECT_MAX 1 -#define SCTPCTL_DEADLOCK_DETECT_DEFAULT 0 - /* early_fast_retran_msec: Early Fast Retransmit minimum timer value */ -#define SCTPCTL_EARLY_FAST_RETRAN_MSEC 38 +#define SCTPCTL_EARLY_FAST_RETRAN_MSEC 39 #define SCTPCTL_EARLY_FAST_RETRAN_MSEC_DESC "Early Fast Retransmit minimum timer value" #define SCTPCTL_EARLY_FAST_RETRAN_MSEC_MIN 0 #define SCTPCTL_EARLY_FAST_RETRAN_MSEC_MAX 0xFFFFFFFF #define SCTPCTL_EARLY_FAST_RETRAN_MSEC_DEFAULT SCTP_MINFR_MSEC_TIMER /* asconf_auth_nochk: Disable SCTP ASCONF AUTH requirement */ -#define SCTPCTL_ASCONF_AUTH_NOCHK 39 +#define SCTPCTL_ASCONF_AUTH_NOCHK 40 #define SCTPCTL_ASCONF_AUTH_NOCHK_DESC "Disable SCTP ASCONF AUTH requirement" #define SCTPCTL_ASCONF_AUTH_NOCHK_MIN 0 #define SCTPCTL_ASCONF_AUTH_NOCHK_MAX 1 #define SCTPCTL_ASCONF_AUTH_NOCHK_DEFAULT 0 /* auth_disable: Disable SCTP AUTH function */ -#define SCTPCTL_AUTH_DISABLE 40 +#define SCTPCTL_AUTH_DISABLE 41 #define SCTPCTL_AUTH_DISABLE_DESC "Disable SCTP AUTH function" #define SCTPCTL_AUTH_DISABLE_MIN 0 #define SCTPCTL_AUTH_DISABLE_MAX 1 #define SCTPCTL_AUTH_DISABLE_DEFAULT 0 /* nat_friendly: SCTP NAT friendly operation */ -#define SCTPCTL_NAT_FRIENDLY 41 +#define SCTPCTL_NAT_FRIENDLY 42 #define SCTPCTL_NAT_FRIENDLY_DESC "SCTP NAT friendly operation" #define SCTPCTL_NAT_FRIENDLY_MIN 0 #define SCTPCTL_NAT_FRIENDLY_MAX 1 #define SCTPCTL_NAT_FRIENDLY_DEFAULT 1 - - /* abc_l_var: SCTP ABC max increase per SACK (L) */ -#define SCTPCTL_ABC_L_VAR 42 +#define SCTPCTL_ABC_L_VAR 43 #define SCTPCTL_ABC_L_VAR_DESC "SCTP ABC max increase per SACK (L)" #define SCTPCTL_ABC_L_VAR_MIN 0 #define SCTPCTL_ABC_L_VAR_MAX 0xFFFFFFFF #define SCTPCTL_ABC_L_VAR_DEFAULT 1 /* max_chained_mbufs: Default max number of small mbufs on a chain */ -#define SCTPCTL_MAX_CHAINED_MBUFS 43 +#define SCTPCTL_MAX_CHAINED_MBUFS 44 #define SCTPCTL_MAX_CHAINED_MBUFS_DESC "Default max number of small mbufs on a chain" #define SCTPCTL_MAX_CHAINED_MBUFS_MIN 0 #define SCTPCTL_MAX_CHAINED_MBUFS_MAX 0xFFFFFFFF #define SCTPCTL_MAX_CHAINED_MBUFS_DEFAULT SCTP_DEFAULT_MBUFS_IN_CHAIN -/* cmt_use_dac: CMT DAC on/off flag */ -#define SCTPCTL_CMT_USE_DAC 44 -#define SCTPCTL_CMT_USE_DAC_DESC "CMT DAC on/off flag" -#define SCTPCTL_CMT_USE_DAC_MIN 0 -#define SCTPCTL_CMT_USE_DAC_MAX 1 -#define SCTPCTL_CMT_USE_DAC_DEFAULT 0 - /* do_sctp_drain: Should SCTP respond to the drain calls */ #define SCTPCTL_DO_SCTP_DRAIN 45 #define SCTPCTL_DO_SCTP_DRAIN_DESC "Should SCTP respond to the drain calls" @@ -359,7 +357,7 @@ __FBSDID("$FreeBSD$"); /* hb_max_burst: Confirmation Heartbeat max burst? */ #define SCTPCTL_HB_MAX_BURST 46 -#define SCTPCTL_HB_MAX_BURST_DESC "Confirmation Heartbeat max burst?" +#define SCTPCTL_HB_MAX_BURST_DESC "Confirmation Heartbeat max burst" #define SCTPCTL_HB_MAX_BURST_MIN 1 #define SCTPCTL_HB_MAX_BURST_MAX 0xFFFFFFFF #define SCTPCTL_HB_MAX_BURST_DEFAULT SCTP_DEF_MAX_BURST @@ -399,183 +397,43 @@ __FBSDID("$FreeBSD$"); #define SCTPCTL_LOGGING_LEVEL_MAX 0xffffffff #define SCTPCTL_LOGGING_LEVEL_DEFAULT 0 -/* JRS 5/2107 - CMT PF type flag */ -#define SCTPCTL_CMT_PF 52 -#define SCTPCTL_CMT_PF_DESC "CMT PF type flag" -#define SCTPCTL_CMT_PF_MIN 0 -#define SCTPCTL_CMT_PF_MAX 2 -#define SCTPCTL_CMT_PF_DEFAULT 0 - /* JRS - default congestion control module sysctl */ -#define SCTPCTL_DEFAULT_CC_MODULE 53 +#define SCTPCTL_DEFAULT_CC_MODULE 52 #define SCTPCTL_DEFAULT_CC_MODULE_DESC "Default congestion control module" #define SCTPCTL_DEFAULT_CC_MODULE_MIN 0 #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 53 #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 /* mobility_base: Enable SCTP mobility support */ -#define SCTPCTL_MOBILITY_BASE 55 +#define SCTPCTL_MOBILITY_BASE 54 #define SCTPCTL_MOBILITY_BASE_DESC "Enable SCTP base mobility" #define SCTPCTL_MOBILITY_BASE_MIN 0 #define SCTPCTL_MOBILITY_BASE_MAX 1 #define SCTPCTL_MOBILITY_BASE_DEFAULT SCTP_DEFAULT_MOBILITY_BASE /* mobility_fasthandoff: Enable SCTP fast handoff support */ -#define SCTPCTL_MOBILITY_FASTHANDOFF 56 +#define SCTPCTL_MOBILITY_FASTHANDOFF 55 #define SCTPCTL_MOBILITY_FASTHANDOFF_DESC "Enable SCTP fast handoff" #define SCTPCTL_MOBILITY_FASTHANDOFF_MIN 0 #define SCTPCTL_MOBILITY_FASTHANDOFF_MAX 1 #define SCTPCTL_MOBILITY_FASTHANDOFF_DEFAULT SCTP_DEFAULT_MOBILITY_FASTHANDOFF - -#ifdef SCTP_DEBUG +#if defined(SCTP_DEBUG) /* debug: Configure debug output */ -#define SCTPCTL_DEBUG 57 +#define SCTPCTL_DEBUG 56 #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 57 -#else -#define SCTPCTL_MAXID 58 #endif -/* - * Names for SCTP sysctl objects variables. - * Must match the OIDs above. - */ -#ifdef SCTP_DEBUG -#define SCTPCTL_NAMES { \ - { 0, 0 }, \ - { "sendspace", CTLTYPE_INT }, \ - { "recvspace", CTLTYPE_INT }, \ - { "autoasconf", CTLTYPE_INT }, \ - { "ecn_enable", CTLTYPE_INT }, \ - { "ecn_nonce", CTLTYPE_INT }, \ - { "strict_sack", CTLTYPE_INT }, \ - { "looback_nocsum", CTLTYPE_INT }, \ - { "strict_init", CTLTYPE_INT }, \ - { "peer_chkoh", CTLTYPE_INT }, \ - { "maxburst", CTLTYPE_INT }, \ - { "maxchunks", CTLTYPE_INT }, \ - { "delayed_sack_time", CTLTYPE_INT }, \ - { "sack_freq", CTLTYPE_INT }, \ - { "heartbeat_interval", CTLTYPE_INT }, \ - { "pmtu_raise_time", CTLTYPE_INT }, \ - { "shutdown_guard_time", CTLTYPE_INT }, \ - { "secret_lifetime", CTLTYPE_INT }, \ - { "rto_max", CTLTYPE_INT }, \ - { "rto_min", CTLTYPE_INT }, \ - { "rto_initial", CTLTYPE_INT }, \ - { "init_rto_max", CTLTYPE_INT }, \ - { "valid_cookie_life", CTLTYPE_INT }, \ - { "init_rtx_max", CTLTYPE_INT }, \ - { "assoc_rtx_max", CTLTYPE_INT }, \ - { "path_rtx_max", CTLTYPE_INT }, \ - { "outgoing_streams", CTLTYPE_INT }, \ - { "cmt_on_off", CTLTYPE_INT }, \ - { "cmt_on_pf", CTLTYPE_INT }, \ - { "default_cc_module", CTLTYPE_INT }, \ - { "cwnd_maxburst", CTLTYPE_INT }, \ - { "early_fast_retran", CTLTYPE_INT }, \ - { "deadlock_detect", CTLTYPE_INT }, \ - { "early_fast_retran_msec", CTLTYPE_INT }, \ - { "asconf_auth_nochk", CTLTYPE_INT }, \ - { "auth_disable", CTLTYPE_INT }, \ - { "nat_friendly", CTLTYPE_INT }, \ - { "abc_l_var", CTLTYPE_INT }, \ - { "max_mbuf_chain", CTLTYPE_INT }, \ - { "cmt_use_dac", CTLTYPE_INT }, \ - { "do_sctp_drain", CTLTYPE_INT }, \ - { "warm_crc_table", CTLTYPE_INT }, \ - { "abort_at_limit", CTLTYPE_INT }, \ - { "strict_data_order", CTLTYPE_INT }, \ - { "tcbhashsize", CTLTYPE_INT }, \ - { "pcbhashsize", CTLTYPE_INT }, \ - { "chunkscale", CTLTYPE_INT }, \ - { "min_split_point", CTLTYPE_INT }, \ - { "add_more_on_output", CTLTYPE_INT }, \ - { "sys_resource", CTLTYPE_INT }, \ - { "asoc_resource", CTLTYPE_INT }, \ - { "min_residual", CTLTYPE_INT }, \ - { "max_retran_chunk", CTLTYPE_INT }, \ - { "sctp_logging", CTLTYPE_INT }, \ - { "frag_interleave", CTLTYPE_INT }, \ - { "mobility_base", CTLTYPE_INT }, \ - { "mobility_fasthandoff", CTLTYPE_INT }, \ - { "debug", CTLTYPE_INT }, \ -} -#else -#define SCTPCTL_NAMES { \ - { 0, 0 }, \ - { "sendspace", CTLTYPE_INT }, \ - { "recvspace", CTLTYPE_INT }, \ - { "autoasconf", CTLTYPE_INT }, \ - { "ecn_enable", CTLTYPE_INT }, \ - { "ecn_nonce", CTLTYPE_INT }, \ - { "strict_sack", CTLTYPE_INT }, \ - { "looback_nocsum", CTLTYPE_INT }, \ - { "strict_init", CTLTYPE_INT }, \ - { "peer_chkoh", CTLTYPE_INT }, \ - { "maxburst", CTLTYPE_INT }, \ - { "maxchunks", CTLTYPE_INT }, \ - { "delayed_sack_time", CTLTYPE_INT }, \ - { "sack_freq", CTLTYPE_INT }, \ - { "heartbeat_interval", CTLTYPE_INT }, \ - { "pmtu_raise_time", CTLTYPE_INT }, \ - { "shutdown_guard_time", CTLTYPE_INT }, \ - { "secret_lifetime", CTLTYPE_INT }, \ - { "rto_max", CTLTYPE_INT }, \ - { "rto_min", CTLTYPE_INT }, \ - { "rto_initial", CTLTYPE_INT }, \ - { "init_rto_max", CTLTYPE_INT }, \ - { "valid_cookie_life", CTLTYPE_INT }, \ - { "init_rtx_max", CTLTYPE_INT }, \ - { "assoc_rtx_max", CTLTYPE_INT }, \ - { "path_rtx_max", CTLTYPE_INT }, \ - { "outgoing_streams", CTLTYPE_INT }, \ - { "cmt_on_off", CTLTYPE_INT }, \ - { "cmt_on_pf", CTLTYPE_INT }, \ - { "default_cc_module", CTLTYPE_INT }, \ - { "cwnd_maxburst", CTLTYPE_INT }, \ - { "early_fast_retran", CTLTYPE_INT }, \ - { "deadlock_detect", CTLTYPE_INT }, \ - { "early_fast_retran_msec", CTLTYPE_INT }, \ - { "asconf_auth_nochk", CTLTYPE_INT }, \ - { "auth_disable", CTLTYPE_INT }, \ - { "nat_friendly", CTLTYPE_INT }, \ - { "abc_l_var", CTLTYPE_INT }, \ - { "max_mbuf_chain", CTLTYPE_INT }, \ - { "cmt_use_dac", CTLTYPE_INT }, \ - { "do_sctp_drain", CTLTYPE_INT }, \ - { "warm_crc_table", CTLTYPE_INT }, \ - { "abort_at_limit", CTLTYPE_INT }, \ - { "strict_data_order", CTLTYPE_INT }, \ - { "tcbhashsize", CTLTYPE_INT }, \ - { "pcbhashsize", CTLTYPE_INT }, \ - { "chunkscale", CTLTYPE_INT }, \ - { "min_split_point", CTLTYPE_INT }, \ - { "add_more_on_output", CTLTYPE_INT }, \ - { "sys_resource", CTLTYPE_INT }, \ - { "asoc_resource", CTLTYPE_INT }, \ - { "min_residual", CTLTYPE_INT }, \ - { "max_retran_chunk", CTLTYPE_INT }, \ - { "sctp_logging", CTLTYPE_INT }, \ - { "frag_interleave", CTLTYPE_INT }, \ - { "mobility_base", CTLTYPE_INT }, \ - { "mobility_fasthandoff", CTLTYPE_INT }, \ -} -#endif #if defined(_KERNEL) @@ -617,24 +475,18 @@ extern uint32_t sctp_path_rtx_max_default; extern uint32_t sctp_add_more_threshold; extern uint32_t sctp_nr_outgoing_streams_default; extern uint32_t sctp_cmt_on_off; +extern uint32_t sctp_cmt_use_dac; /* JRS 5/21/07 - CMT PF type flag variables */ 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; -extern uint32_t sctp_says_check_for_deadlock; extern uint32_t sctp_early_fr_msec; extern uint32_t sctp_asconf_auth_nochk; extern uint32_t sctp_auth_disable; extern uint32_t sctp_nat_friendly; extern uint32_t sctp_L2_abc_variable; extern uint32_t sctp_mbuf_threshold_count; -extern uint32_t sctp_cmt_use_dac; extern uint32_t sctp_do_drain; extern uint32_t sctp_hb_maxburst; extern uint32_t sctp_abort_if_one_2_one_hits_limit; @@ -642,6 +494,10 @@ extern uint32_t sctp_strict_data_order; extern uint32_t sctp_min_residual; extern uint32_t sctp_max_retran_chunk; extern uint32_t sctp_logging_level; + +/* 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_mobility_base; extern uint32_t sctp_mobility_fasthandoff; @@ -652,8 +508,7 @@ extern uint32_t sctp_debug_on; extern struct sctpstat sctpstat; - -#ifdef SYSCTL_DECL +#if defined(SYSCTL_DECL) SYSCTL_DECL(_net_inet_sctp); #endif diff --git a/sys/netinet/sctp_timer.c b/sys/netinet/sctp_timer.c index 50550f8..b9d4b62 100644 --- a/sys/netinet/sctp_timer.c +++ b/sys/netinet/sctp_timer.c @@ -1388,6 +1388,24 @@ sctp_asconf_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, return (0); } +/* Mobility adaptation */ +int +sctp_delete_prim_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, + struct sctp_nets *net) +{ + if (stcb->asoc.deleted_primary == NULL) { + SCTPDBG(SCTP_DEBUG_ASCONF1, "delete_prim_timer: deleted_primary is not stored...\n"); + sctp_mobility_feature_off(inp, SCTP_MOBILITY_PRIM_DELETED); + return (0); + } + SCTPDBG(SCTP_DEBUG_ASCONF1, "delete_prim_timer: finished to keep deleted primary "); + SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, &stcb->asoc.deleted_primary->ro._l_addr.sa); + sctp_free_remote_addr(stcb->asoc.deleted_primary); + stcb->asoc.deleted_primary = NULL; + sctp_mobility_feature_off(inp, SCTP_MOBILITY_PRIM_DELETED); + return (0); +} + /* * For the shutdown and shutdown-ack, we do not keep one around on the * control queue. This means we must generate a new one and call the general diff --git a/sys/netinet/sctp_timer.h b/sys/netinet/sctp_timer.h index 425d748..0a0f2f2 100644 --- a/sys/netinet/sctp_timer.h +++ b/sys/netinet/sctp_timer.h @@ -87,6 +87,10 @@ int sctp_asconf_timer(struct sctp_inpcb *, struct sctp_tcb *, struct sctp_nets *); +int +sctp_delete_prim_timer(struct sctp_inpcb *, struct sctp_tcb *, + struct sctp_nets *); + void sctp_autoclose_timer(struct sctp_inpcb *, struct sctp_tcb *, struct sctp_nets *net); diff --git a/sys/netinet/sctp_uio.h b/sys/netinet/sctp_uio.h index 56d6199..477ef58 100644 --- a/sys/netinet/sctp_uio.h +++ b/sys/netinet/sctp_uio.h @@ -41,7 +41,6 @@ __FBSDID("$FreeBSD$"); #endif #include <sys/types.h> #include <sys/socket.h> -#include <sys/time.h> #include <netinet/in.h> typedef uint32_t sctp_assoc_t; @@ -743,6 +742,11 @@ struct sctp_cwnd_log_req { struct sctp_cwnd_log log[0]; }; +struct sctp_timeval { + uint32_t tv_sec; + uint32_t tv_usec; +}; + struct sctpstat { /* MIB according to RFC 3873 */ uint32_t sctps_currestab; /* sctpStats 1 (Gauge32) */ @@ -845,6 +849,8 @@ struct sctpstat { * fired */ uint32_t sctps_timoasconf; /* Number of times an asconf timer * fired */ + uint32_t sctps_timodelprim; /* Number of times a prim_deleted + * timer fired */ uint32_t sctps_timoautoclose; /* Number of times auto close timer * fired */ uint32_t sctps_timoassockill; /* Number of asoc free timers expired */ @@ -921,7 +927,8 @@ struct sctpstat { uint32_t sctps_fwdtsn_map_over; /* number of map array over-runs via * fwd-tsn's */ - struct timeval sctps_discontinuitytime; /* sctpStats 18 (TimeStamp) */ + struct sctp_timeval sctps_discontinuitytime; /* sctpStats 18 + * (TimeStamp) */ }; #define SCTP_STAT_INCR(_x) SCTP_STAT_INCR_BY(_x,1) @@ -984,14 +991,14 @@ struct xsctp_tcb { uint32_t refcnt; uint16_t local_port; /* sctpAssocEntry 3 */ uint16_t remote_port; /* sctpAssocEntry 4 */ - struct timeval start_time; /* sctpAssocEntry 16 */ - struct timeval discontinuity_time; /* sctpAssocEntry 17 */ + struct sctp_timeval start_time; /* sctpAssocEntry 16 */ + struct sctp_timeval discontinuity_time; /* sctpAssocEntry 17 */ }; struct xsctp_laddr { union sctp_sockstore address; /* sctpAssocLocalAddrEntry 1/2 */ uint32_t last; - struct timeval start_time; /* sctpAssocLocalAddrEntry 3 */ + struct sctp_timeval start_time; /* sctpAssocLocalAddrEntry 3 */ }; struct xsctp_raddr { @@ -1007,7 +1014,7 @@ struct xsctp_raddr { uint8_t active; /* sctpAssocLocalRemEntry 3 */ uint8_t confirmed; /* */ uint8_t heartbeat_enabled; /* sctpAssocLocalRemEntry 4 */ - struct timeval start_time; /* sctpAssocLocalRemEntry 8 */ + struct sctp_timeval start_time; /* sctpAssocLocalRemEntry 8 */ }; /* diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c index bf11663..77f15ae 100644 --- a/sys/netinet/sctp_usrreq.c +++ b/sys/netinet/sctp_usrreq.c @@ -223,7 +223,7 @@ sctp_notify_mbuf(struct sctp_inpcb *inp, void sctp_notify(struct sctp_inpcb *inp, - int error, + struct ip *ip, struct sctphdr *sh, struct sockaddr *to, struct sctp_tcb *stcb, @@ -234,110 +234,103 @@ sctp_notify(struct sctp_inpcb *inp, #endif /* protection */ + int reason; + struct icmp *icmph; + + if ((inp == NULL) || (stcb == NULL) || (net == NULL) || (sh == NULL) || (to == NULL)) { + if (stcb) + SCTP_TCB_UNLOCK(stcb); return; } /* First job is to verify the vtag matches what I would send */ if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) { + SCTP_TCB_UNLOCK(stcb); return; } - /* FIX ME FIX ME PROTOPT i.e. no SCTP should ALWAYS be an ABORT */ + icmph = (struct icmp *)((caddr_t)ip - (sizeof(struct icmp) - + sizeof(struct ip))); + if (icmph->icmp_type != ICMP_UNREACH) { + /* We only care about unreachable */ + SCTP_TCB_UNLOCK(stcb); + return; + } + if ((icmph->icmp_code == ICMP_UNREACH_NET) || + (icmph->icmp_code == ICMP_UNREACH_HOST) || + (icmph->icmp_code == ICMP_UNREACH_NET_UNKNOWN) || + (icmph->icmp_code == ICMP_UNREACH_HOST_UNKNOWN) || + (icmph->icmp_code == ICMP_UNREACH_ISOLATED) || + (icmph->icmp_code == ICMP_UNREACH_NET_PROHIB) || + (icmph->icmp_code == ICMP_UNREACH_HOST_PROHIB) || + (icmph->icmp_code == ICMP_UNREACH_FILTER_PROHIB)) { - if ((error == EHOSTUNREACH) || /* Host is not reachable */ - (error == EHOSTDOWN) || /* Host is down */ - (error == ECONNREFUSED) || /* Host refused the connection, (not - * an abort?) */ - (error == ENOPROTOOPT) /* SCTP is not present on host */ - ) { /* * Hmm reachablity problems we must examine closely. If its * not reachable, we may have lost a network. Or if there is * NO protocol at the other end named SCTP. well we consider * it a OOTB abort. */ - if ((error == EHOSTUNREACH) || (error == EHOSTDOWN)) { - if (net->dest_state & SCTP_ADDR_REACHABLE) { - /* Ok that destination is NOT reachable */ - SCTP_PRINTF("ICMP (thresh %d/%d) takes interface %p down\n", - net->error_count, - net->failure_threshold, - net); - - net->dest_state &= ~SCTP_ADDR_REACHABLE; - net->dest_state |= SCTP_ADDR_NOT_REACHABLE; - /* - * JRS 5/14/07 - If a destination is - * unreachable, the PF bit is turned off. - * This allows an unambiguous use of the PF - * bit for destinations that are reachable - * but potentially failed. If the - * destination is set to the unreachable - * state, also set the destination to the PF - * state. - */ - /* - * Add debug message here if destination is - * not in PF state. - */ - /* Stop any running T3 timers here? */ - if (sctp_cmt_on_off && sctp_cmt_pf) { - net->dest_state &= ~SCTP_ADDR_PF; - SCTPDBG(SCTP_DEBUG_TIMER4, "Destination %p moved from PF to unreachable.\n", - net); - } - net->error_count = net->failure_threshold + 1; - sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, - stcb, SCTP_FAILED_THRESHOLD, - (void *)net, SCTP_SO_NOT_LOCKED); - } - if (stcb) { - SCTP_TCB_UNLOCK(stcb); - } - } else { + if (net->dest_state & SCTP_ADDR_REACHABLE) { + /* Ok that destination is NOT reachable */ + SCTP_PRINTF("ICMP (thresh %d/%d) takes interface %p down\n", + net->error_count, + net->failure_threshold, + net); + + net->dest_state &= ~SCTP_ADDR_REACHABLE; + net->dest_state |= SCTP_ADDR_NOT_REACHABLE; /* - * Here the peer is either playing tricks on us, - * including an address that belongs to someone who - * does not support SCTP OR was a userland - * implementation that shutdown and now is dead. In - * either case treat it like a OOTB abort with no - * TCB + * JRS 5/14/07 - If a destination is unreachable, + * the PF bit is turned off. This allows an + * unambiguous use of the PF bit for destinations + * that are reachable but potentially failed. If the + * destination is set to the unreachable state, also + * set the destination to the PF state. */ - sctp_abort_notification(stcb, SCTP_PEER_FAULTY, SCTP_SO_NOT_LOCKED); + /* + * Add debug message here if destination is not in + * PF state. + */ + /* Stop any running T3 timers here? */ + if (sctp_cmt_on_off && sctp_cmt_pf) { + net->dest_state &= ~SCTP_ADDR_PF; + SCTPDBG(SCTP_DEBUG_TIMER4, "Destination %p moved from PF to unreachable.\n", + net); + } + net->error_count = net->failure_threshold + 1; + sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, + stcb, SCTP_FAILED_THRESHOLD, + (void *)net, SCTP_SO_NOT_LOCKED); + } + SCTP_TCB_UNLOCK(stcb); + } else if ((icmph->icmp_code == ICMP_UNREACH_PROTOCOL) || + (icmph->icmp_code == ICMP_UNREACH_PORT)) { + /* + * Here the peer is either playing tricks on us, including + * an address that belongs to someone who does not support + * SCTP OR was a userland implementation that shutdown and + * now is dead. In either case treat it like a OOTB abort + * with no TCB + */ + reason = SCTP_PEER_FAULTY; + sctp_abort_notification(stcb, reason, SCTP_SO_NOT_LOCKED); #if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) - so = SCTP_INP_SO(inp); - atomic_add_int(&stcb->asoc.refcnt, 1); - SCTP_TCB_UNLOCK(stcb); - SCTP_SOCKET_LOCK(so, 1); - SCTP_TCB_LOCK(stcb); - atomic_subtract_int(&stcb->asoc.refcnt, 1); + so = SCTP_INP_SO(inp); + atomic_add_int(&stcb->asoc.refcnt, 1); + SCTP_TCB_UNLOCK(stcb); + SCTP_SOCKET_LOCK(so, 1); + SCTP_TCB_LOCK(stcb); + atomic_subtract_int(&stcb->asoc.refcnt, 1); #endif - (void)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); #if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) - SCTP_SOCKET_UNLOCK(so, 1); - /* - * SCTP_TCB_UNLOCK(stcb); MT: I think this is not - * needed. - */ + SCTP_SOCKET_UNLOCK(so, 1); + /* SCTP_TCB_UNLOCK(stcb); MT: I think this is not needed. */ #endif - /* no need to unlock here, since the TCB is gone */ - } + /* no need to unlock here, since the TCB is gone */ } else { - /* Send all others to the app */ - if (stcb) { - SCTP_TCB_UNLOCK(stcb); - } - if (inp->sctp_socket) { -#ifdef SCTP_LOCK_LOGGING - if (sctp_logging_level & SCTP_LOCK_LOGGING_ENABLE) { - sctp_log_lock(inp, stcb, SCTP_LOG_LOCK_SOCK); - } -#endif - SOCK_LOCK(inp->sctp_socket); - inp->sctp_socket->so_error = error; - sctp_sowwakeup(inp, inp->sctp_socket); - SOCK_UNLOCK(inp->sctp_socket); - } + SCTP_TCB_UNLOCK(stcb); } } @@ -388,14 +381,7 @@ sctp_ctlinput(cmd, sa, vip) &inp, &net, 1, vrf_id); if (stcb != NULL && inp && (inp->sctp_socket != NULL)) { if (cmd != PRC_MSGSIZE) { - int cm; - - if (cmd == PRC_HOSTDEAD) { - cm = EHOSTUNREACH; - } else { - cm = inetctlerrmap[cmd]; - } - sctp_notify(inp, cm, sh, + sctp_notify(inp, ip, sh, (struct sockaddr *)&to, stcb, net); } else { @@ -1070,6 +1056,9 @@ sctp_fill_user_address(struct sockaddr_storage *ss, struct sockaddr *sa) +/* + * NOTE: assumes addr lock is held + */ static size_t sctp_fill_up_addresses_vrf(struct sctp_inpcb *inp, struct sctp_tcb *stcb, @@ -1235,12 +1224,17 @@ sctp_fill_up_addresses(struct sctp_inpcb *inp, { size_t size = 0; + SCTP_IPI_ADDR_LOCK(); /* fill up addresses for the endpoint's default vrf */ size = sctp_fill_up_addresses_vrf(inp, stcb, limit, sas, inp->def_vrf_id); + SCTP_IPI_ADDR_UNLOCK(); return (size); } +/* + * NOTE: assumes addr lock is held + */ static int sctp_count_max_addresses_vrf(struct sctp_inpcb *inp, uint32_t vrf_id) { @@ -1297,8 +1291,10 @@ sctp_count_max_addresses(struct sctp_inpcb *inp) { int cnt = 0; + SCTP_IPI_ADDR_LOCK(); /* count addresses for the endpoint's default VRF */ cnt = sctp_count_max_addresses_vrf(inp, inp->def_vrf_id); + SCTP_IPI_ADDR_UNLOCK(); return (cnt); } @@ -1655,9 +1651,9 @@ flags_out: error = 0; } #endif - if (error) + if (error) { SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); - + } *optsize = sizeof(*av); } break; @@ -3785,7 +3781,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, struct sctp_ifa *ifa; ifa = sctp_find_ifa_by_addr((struct sockaddr *)&sspp->sspp_addr, - stcb->asoc.vrf_id, 0); + stcb->asoc.vrf_id, SCTP_ADDR_NOT_LOCKED); if (ifa == NULL) { SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); error = EINVAL; diff --git a/sys/netinet/sctp_var.h b/sys/netinet/sctp_var.h index aa847ed..8bc6ffd 100644 --- a/sys/netinet/sctp_var.h +++ b/sys/netinet/sctp_var.h @@ -307,7 +307,7 @@ void sctp_pcbinfo_cleanup(void); int sctp_shutdown __P((struct socket *)); void sctp_notify -__P((struct sctp_inpcb *, int, struct sctphdr *, +__P((struct sctp_inpcb *, struct ip *ip, struct sctphdr *, struct sockaddr *, struct sctp_tcb *, struct sctp_nets *)); diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c index 31b9c06..05ab850 100644 --- a/sys/netinet/sctputil.c +++ b/sys/netinet/sctputil.c @@ -806,7 +806,7 @@ sctp_fill_random_store(struct sctp_pcb *m) } uint32_t -sctp_select_initial_TSN(struct sctp_pcb *m) +sctp_select_initial_TSN(struct sctp_pcb *inp) { /* * A true implementation should use random selection process to get @@ -815,27 +815,36 @@ sctp_select_initial_TSN(struct sctp_pcb *m) */ uint32_t x, *xp; uint8_t *p; + int store_at, new_store; - if (m->initial_sequence_debug != 0) { + if (inp->initial_sequence_debug != 0) { uint32_t ret; - ret = m->initial_sequence_debug; - m->initial_sequence_debug++; + ret = inp->initial_sequence_debug; + inp->initial_sequence_debug++; return (ret); } - if ((m->store_at + sizeof(u_long)) > SCTP_SIGNATURE_SIZE) { +retry: + store_at = inp->store_at; + new_store = store_at + sizeof(uint32_t); + if (new_store >= (SCTP_SIGNATURE_SIZE - 3)) { + new_store = 0; + } + if (!atomic_cmpset_int(&inp->store_at, store_at, new_store)) { + goto retry; + } + if (new_store == 0) { /* Refill the random store */ - sctp_fill_random_store(m); + sctp_fill_random_store(inp); } - p = &m->random_store[(int)m->store_at]; + p = &inp->random_store[store_at]; xp = (uint32_t *) p; x = *xp; - m->store_at += sizeof(uint32_t); return (x); } uint32_t -sctp_select_a_tag(struct sctp_inpcb *m) +sctp_select_a_tag(struct sctp_inpcb *inp) { u_long x, not_done; struct timeval now; @@ -843,12 +852,12 @@ sctp_select_a_tag(struct sctp_inpcb *m) (void)SCTP_GETTIME_TIMEVAL(&now); not_done = 1; while (not_done) { - x = sctp_select_initial_TSN(&m->sctp_ep); + x = sctp_select_initial_TSN(&inp->sctp_ep); if (x == 0) { /* we never use 0 */ continue; } - if (sctp_is_vtag_good(m, x, &now)) { + if (sctp_is_vtag_good(inp, x, &now)) { not_done = 0; } } @@ -1758,6 +1767,15 @@ sctp_timeout_handler(void *t) #endif sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_ASCONF_TMR, SCTP_SO_NOT_LOCKED); break; + case SCTP_TIMER_TYPE_PRIM_DELETED: + if ((stcb == NULL) || (inp == NULL)) { + break; + } + if (sctp_delete_prim_timer(inp, stcb, net)) { + goto out_decr; + } + SCTP_STAT_INCR(sctps_timodelprim); + break; case SCTP_TIMER_TYPE_AUTOCLOSE: if ((stcb == NULL) || (inp == NULL)) { @@ -2152,6 +2170,13 @@ sctp_timer_start(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb, } tmr = &stcb->asoc.asconf_timer; break; + case SCTP_TIMER_TYPE_PRIM_DELETED: + if ((stcb == NULL) || (net != NULL)) { + return; + } + to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto); + tmr = &stcb->asoc.delete_prim_timer; + break; case SCTP_TIMER_TYPE_AUTOCLOSE: if (stcb == NULL) { return; @@ -2330,6 +2355,12 @@ sctp_timer_stop(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb, } tmr = &stcb->asoc.asconf_timer; break; + case SCTP_TIMER_TYPE_PRIM_DELETED: + if (stcb == NULL) { + return; + } + tmr = &stcb->asoc.delete_prim_timer; + break; case SCTP_TIMER_TYPE_AUTOCLOSE: if (stcb == NULL) { return; @@ -5629,6 +5660,11 @@ wait_some_more: SOCKBUF_LOCK(&so->so_rcv); hold_sblock = 1; } + if ((copied_so_far) && (control->length == 0) && + (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE)) + ) { + goto release; + } if (so->so_rcv.sb_cc <= control->held_length) { error = sbwait(&so->so_rcv); if (error) { @@ -6339,9 +6375,11 @@ sctp_local_addr_count(struct sctp_tcb *stcb) ipv4_addr_legal = 1; } + SCTP_IPI_ADDR_LOCK(); vrf = sctp_find_vrf(stcb->asoc.vrf_id); if (vrf == NULL) { /* no vrf, no addresses */ + SCTP_IPI_ADDR_UNLOCK(); return (0); } if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { @@ -6417,6 +6455,7 @@ sctp_local_addr_count(struct sctp_tcb *stcb) count++; } } + SCTP_IPI_ADDR_UNLOCK(); return (count); } diff --git a/sys/netinet6/sctp6_usrreq.c b/sys/netinet6/sctp6_usrreq.c index 2d4c82c..89bb51c 100644 --- a/sys/netinet6/sctp6_usrreq.c +++ b/sys/netinet6/sctp6_usrreq.c @@ -315,13 +315,124 @@ out: } +static void +sctp6_notify(struct sctp_inpcb *inp, + struct icmp6_hdr *icmph, + struct sctphdr *sh, + struct sockaddr *to, + struct sctp_tcb *stcb, + struct sctp_nets *net) +{ +#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) + struct socket *so; + +#endif + /* protection */ + int reason; + + + if ((inp == NULL) || (stcb == NULL) || (net == NULL) || + (sh == NULL) || (to == NULL)) { + if (stcb) + SCTP_TCB_UNLOCK(stcb); + return; + } + /* First job is to verify the vtag matches what I would send */ + if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) { + SCTP_TCB_UNLOCK(stcb); + return; + } + if (icmph->icmp6_type != ICMP_UNREACH) { + /* We only care about unreachable */ + SCTP_TCB_UNLOCK(stcb); + return; + } + if ((icmph->icmp6_code == ICMP_UNREACH_NET) || + (icmph->icmp6_code == ICMP_UNREACH_HOST) || + (icmph->icmp6_code == ICMP_UNREACH_NET_UNKNOWN) || + (icmph->icmp6_code == ICMP_UNREACH_HOST_UNKNOWN) || + (icmph->icmp6_code == ICMP_UNREACH_ISOLATED) || + (icmph->icmp6_code == ICMP_UNREACH_NET_PROHIB) || + (icmph->icmp6_code == ICMP_UNREACH_HOST_PROHIB) || + (icmph->icmp6_code == ICMP_UNREACH_FILTER_PROHIB)) { + + /* + * Hmm reachablity problems we must examine closely. If its + * not reachable, we may have lost a network. Or if there is + * NO protocol at the other end named SCTP. well we consider + * it a OOTB abort. + */ + if (net->dest_state & SCTP_ADDR_REACHABLE) { + /* Ok that destination is NOT reachable */ + SCTP_PRINTF("ICMP (thresh %d/%d) takes interface %p down\n", + net->error_count, + net->failure_threshold, + net); + + net->dest_state &= ~SCTP_ADDR_REACHABLE; + net->dest_state |= SCTP_ADDR_NOT_REACHABLE; + /* + * JRS 5/14/07 - If a destination is unreachable, + * the PF bit is turned off. This allows an + * unambiguous use of the PF bit for destinations + * that are reachable but potentially failed. If the + * destination is set to the unreachable state, also + * set the destination to the PF state. + */ + /* + * Add debug message here if destination is not in + * PF state. + */ + /* Stop any running T3 timers here? */ + if (sctp_cmt_on_off && sctp_cmt_pf) { + net->dest_state &= ~SCTP_ADDR_PF; + SCTPDBG(SCTP_DEBUG_TIMER4, "Destination %p moved from PF to unreachable.\n", + net); + } + net->error_count = net->failure_threshold + 1; + sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, + stcb, SCTP_FAILED_THRESHOLD, + (void *)net, SCTP_SO_NOT_LOCKED); + } + SCTP_TCB_UNLOCK(stcb); + } else if ((icmph->icmp6_code == ICMP_UNREACH_PROTOCOL) || + (icmph->icmp6_code == ICMP_UNREACH_PORT)) { + /* + * Here the peer is either playing tricks on us, including + * an address that belongs to someone who does not support + * SCTP OR was a userland implementation that shutdown and + * now is dead. In either case treat it like a OOTB abort + * with no TCB + */ + reason = SCTP_PEER_FAULTY; + sctp_abort_notification(stcb, reason, SCTP_SO_NOT_LOCKED); +#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) + so = SCTP_INP_SO(inp); + atomic_add_int(&stcb->asoc.refcnt, 1); + SCTP_TCB_UNLOCK(stcb); + SCTP_SOCKET_LOCK(so, 1); + SCTP_TCB_LOCK(stcb); + atomic_subtract_int(&stcb->asoc.refcnt, 1); +#endif + (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_2); +#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) + SCTP_SOCKET_UNLOCK(so, 1); + /* SCTP_TCB_UNLOCK(stcb); MT: I think this is not needed. */ +#endif + /* no need to unlock here, since the TCB is gone */ + } else { + SCTP_TCB_UNLOCK(stcb); + } +} + + + void sctp6_ctlinput(int cmd, struct sockaddr *pktdst, void *d) { struct sctphdr sh; struct ip6ctlparam *ip6cp = NULL; uint32_t vrf_id; - int cm; vrf_id = SCTP_DEFAULT_VRFID; @@ -381,12 +492,7 @@ sctp6_ctlinput(int cmd, struct sockaddr *pktdst, void *d) net); /* inp's ref-count reduced && stcb unlocked */ } else { - if (cmd == PRC_HOSTDEAD) { - cm = EHOSTUNREACH; - } else { - cm = inet6ctlerrmap[cmd]; - } - sctp_notify(inp, cm, &sh, + sctp6_notify(inp, ip6cp->ip6c_icmp6, &sh, (struct sockaddr *)&final, stcb, net); /* inp's ref-count reduced && stcb unlocked */ @@ -489,8 +595,10 @@ sctp6_abort(struct socket *so) uint32_t flags; inp = (struct sctp_inpcb *)so->so_pcb; - if (inp == 0) + if (inp == 0) { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); return; + } sctp_must_try_again: flags = inp->sctp_flags; #ifdef SCTP_LOG_CLOSING @@ -627,11 +735,12 @@ sctp6_bind(struct socket *so, struct sockaddr *addr, struct thread *p) sin6_p = (struct sockaddr_in6 *)addr; - if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) + if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) { /* can't bind v4-mapped addrs either! */ /* NOTE: we don't support SIIT */ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); - return EINVAL; + return EINVAL; + } } } error = sctp_inpcb_bind(so, addr, NULL, p); |