diff options
Diffstat (limited to 'sys/netinet6/sctp6_usrreq.c')
| -rw-r--r-- | sys/netinet6/sctp6_usrreq.c | 221 |
1 files changed, 25 insertions, 196 deletions
diff --git a/sys/netinet6/sctp6_usrreq.c b/sys/netinet6/sctp6_usrreq.c index d2ee49c22dba..ac74d64d0ede 100644 --- a/sys/netinet6/sctp6_usrreq.c +++ b/sys/netinet6/sctp6_usrreq.c @@ -124,42 +124,31 @@ sctp6_input(struct mbuf **i_pak, int *offp, int proto) /* destination port of 0 is illegal, based on RFC2960. */ if (sh->dest_port == 0) goto bad; - if ((sctp_no_csum_on_loopback == 0) || - (!SCTP_IS_IT_LOOPBACK(m))) { - /* - * we do NOT validate things from the loopback if the sysctl - * is set to 1. - */ - check = sh->checksum; /* save incoming checksum */ - if ((check == 0) && (sctp_no_csum_on_loopback)) { - /* - * special hook for where we got a local address - * somehow routed across a non IFT_LOOP type - * interface - */ - if (IN6_ARE_ADDR_EQUAL(&ip6->ip6_src, &ip6->ip6_dst)) - goto sctp_skip_csum; - } - sh->checksum = 0; /* prepare for calc */ - calc_check = sctp_calculate_sum(m, &mlen, iphlen); - if (calc_check != check) { - SCTPDBG(SCTP_DEBUG_INPUT1, "Bad CSUM on SCTP packet calc_check:%x check:%x m:%p mlen:%d iphlen:%d\n", - calc_check, check, m, mlen, iphlen); - stcb = sctp_findassociation_addr(m, iphlen, offset - sizeof(*ch), - sh, ch, &in6p, &net, vrf_id); - /* in6p's ref-count increased && stcb locked */ - if ((in6p) && (stcb)) { - sctp_send_packet_dropped(stcb, net, m, iphlen, 1); - sctp_chunk_output((struct sctp_inpcb *)in6p, stcb, 2); - } else if ((in6p != NULL) && (stcb == NULL)) { - refcount_up = 1; - } - SCTP_STAT_INCR(sctps_badsum); - SCTP_STAT_INCR_COUNTER32(sctps_checksumerrors); - goto bad; + check = sh->checksum; /* save incoming checksum */ + if ((check == 0) && (sctp_no_csum_on_loopback) && + (IN6_ARE_ADDR_EQUAL(&ip6->ip6_src, &ip6->ip6_dst))) { + goto sctp_skip_csum; + } + sh->checksum = 0; /* prepare for calc */ + calc_check = sctp_calculate_sum(m, &mlen, iphlen); + if (calc_check != check) { + SCTPDBG(SCTP_DEBUG_INPUT1, "Bad CSUM on SCTP packet calc_check:%x check:%x m:%p mlen:%d iphlen:%d\n", + calc_check, check, m, mlen, iphlen); + stcb = sctp_findassociation_addr(m, iphlen, offset - sizeof(*ch), + sh, ch, &in6p, &net, vrf_id); + /* in6p's ref-count increased && stcb locked */ + if ((in6p) && (stcb)) { + sctp_send_packet_dropped(stcb, net, m, iphlen, 1); + sctp_chunk_output((struct sctp_inpcb *)in6p, stcb, 2); + } else if ((in6p != NULL) && (stcb == NULL)) { + refcount_up = 1; } - sh->checksum = calc_check; + SCTP_STAT_INCR(sctps_badsum); + SCTP_STAT_INCR_COUNTER32(sctps_checksumerrors); + goto bad; } + sh->checksum = calc_check; + sctp_skip_csum: net = NULL; /* @@ -653,59 +642,7 @@ sctp6_bind(struct socket *so, struct sockaddr *addr, struct thread *p) static void sctp6_close(struct socket *so) { - struct sctp_inpcb *inp; - uint32_t flags; - - inp = (struct sctp_inpcb *)so->so_pcb; - if (inp == 0) - return; - - /* - * Inform all the lower layer assoc that we are done. - */ -sctp_must_try_again: - flags = inp->sctp_flags; -#ifdef SCTP_LOG_CLOSING - sctp_log_closing(inp, NULL, 17); -#endif - if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && - (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) { - if (((so->so_options & SO_LINGER) && (so->so_linger == 0)) || - (so->so_rcv.sb_cc > 0)) { -#ifdef SCTP_LOG_CLOSING - sctp_log_closing(inp, NULL, 13); -#endif - sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT - ,SCTP_CALLED_AFTER_CMPSET_OFCLOSE); - } else { -#ifdef SCTP_LOG_CLOSING - sctp_log_closing(inp, NULL, 14); -#endif - sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_GRACEFUL_CLOSE, - SCTP_CALLED_AFTER_CMPSET_OFCLOSE); - } - /* - * The socket is now detached, no matter what the state of - * the SCTP association. - */ - SOCK_LOCK(so); - SCTP_SB_CLEAR(so->so_snd); - /* - * same for the rcv ones, they are only here for the - * accounting/select. - */ - SCTP_SB_CLEAR(so->so_rcv); - /* Now null out the reference, we are completely detached. */ - so->so_pcb = NULL; - SOCK_UNLOCK(so); - } else { - flags = inp->sctp_flags; - if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) { - goto sctp_must_try_again; - } - } - return; - + sctp_close(so); } /* This could be made common with sctp_detach() since they are identical */ @@ -714,115 +651,7 @@ static int sctp6_disconnect(struct socket *so) { - struct sctp_inpcb *inp; - - inp = (struct sctp_inpcb *)so->so_pcb; - if (inp == NULL) { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOTCONN); - return (ENOTCONN); - } - SCTP_INP_RLOCK(inp); - if (inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) { - if (SCTP_LIST_EMPTY(&inp->sctp_asoc_list)) { - /* No connection */ - SCTP_INP_RUNLOCK(inp); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOTCONN); - return (ENOTCONN); - } else { - int some_on_streamwheel = 0; - struct sctp_association *asoc; - struct sctp_tcb *stcb; - - stcb = LIST_FIRST(&inp->sctp_asoc_list); - if (stcb == NULL) { - SCTP_INP_RUNLOCK(inp); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); - return (EINVAL); - } - SCTP_TCB_LOCK(stcb); - asoc = &stcb->asoc; - if (((so->so_options & SO_LINGER) && - (so->so_linger == 0)) || - (so->so_rcv.sb_cc > 0)) { - if (SCTP_GET_STATE(asoc) != - SCTP_STATE_COOKIE_WAIT) { - /* Left with Data unread */ - struct mbuf *op_err; - - op_err = sctp_generate_invmanparam(SCTP_CAUSE_USER_INITIATED_ABT); - sctp_send_abort_tcb(stcb, op_err); - SCTP_STAT_INCR_COUNTER32(sctps_aborted); - } - SCTP_INP_RUNLOCK(inp); - if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) || - (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { - SCTP_STAT_DECR_GAUGE32(sctps_currestab); - } - if (sctp_free_assoc(inp, stcb, SCTP_DONOT_SETSCOPE, - SCTP_FROM_SCTP6_USRREQ + SCTP_LOC_2) == 0) { - SCTP_TCB_UNLOCK(stcb); - } - /* No unlock tcb assoc is gone */ - return (0); - } - if (!TAILQ_EMPTY(&asoc->out_wheel)) { - /* Check to see if some data queued */ - struct sctp_stream_out *outs; - - TAILQ_FOREACH(outs, &asoc->out_wheel, - next_spoke) { - if (!TAILQ_EMPTY(&outs->outqueue)) { - some_on_streamwheel = 1; - break; - } - } - } - if (TAILQ_EMPTY(&asoc->send_queue) && - TAILQ_EMPTY(&asoc->sent_queue) && - (some_on_streamwheel == 0)) { - /* nothing queued to send, so I'm done... */ - if ((SCTP_GET_STATE(asoc) != - SCTP_STATE_SHUTDOWN_SENT) && - (SCTP_GET_STATE(asoc) != - SCTP_STATE_SHUTDOWN_ACK_SENT)) { - /* only send SHUTDOWN the first time */ - sctp_send_shutdown(stcb, stcb->asoc.primary_destination); - sctp_chunk_output(stcb->sctp_ep, stcb, 1); - if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) || - (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { - SCTP_STAT_DECR_GAUGE32(sctps_currestab); - } - SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT); - sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, - stcb->sctp_ep, stcb, - asoc->primary_destination); - sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, - stcb->sctp_ep, stcb, - asoc->primary_destination); - } - } else { - /* - * we still got (or just got) data to send, - * so set SHUTDOWN_PENDING - */ - /* - * XXX sockets draft says that MSG_EOF - * should be sent with no data. currently, - * we will allow user data to be sent first - * and move to SHUTDOWN-PENDING - */ - asoc->state |= SCTP_STATE_SHUTDOWN_PENDING; - } - SCTP_TCB_UNLOCK(stcb); - SCTP_INP_RUNLOCK(inp); - return (0); - } - } else { - /* UDP model does not support this */ - SCTP_INP_RUNLOCK(inp); - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EOPNOTSUPP); - return EOPNOTSUPP; - } + return (sctp_disconnect(so)); } |
