diff options
-rw-r--r-- | sys/netinet/sctp_output.c | 185 | ||||
-rw-r--r-- | sys/netinet/sctputil.c | 8 |
2 files changed, 99 insertions, 94 deletions
diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c index 3272ab8..82fe67e 100644 --- a/sys/netinet/sctp_output.c +++ b/sys/netinet/sctp_output.c @@ -2217,15 +2217,6 @@ sctp_is_ifa_addr_preferred(struct sctp_ifa *ifa, SCTPDBG(SCTP_DEBUG_OUTPUT3, "NO:1\n"); return (NULL); } - if (ifa->src_is_priv && ifa->src_is_loop) { - /* - * don't allow fe80::1 to be a src on loop ::1, we - * don't list it to the peer so we will get an - * abort. - */ - SCTPDBG(SCTP_DEBUG_OUTPUT3, "NO:2a\n"); - return (NULL); - } if (ifa->src_is_priv && !ifa->src_is_loop) { if (dest_is_loop) { SCTPDBG(SCTP_DEBUG_OUTPUT3, "NO:2\n"); @@ -2690,6 +2681,16 @@ sctp_select_nth_preferred_addr_from_ifn_boundall(struct sctp_ifn *ifn, continue; #ifdef INET6 if (fam == AF_INET6 && + dest_is_loop && + sifa->src_is_loop && sifa->src_is_priv) { + /* + * don't allow fe80::1 to be a src on loop ::1, we + * don't list it to the peer so we will get an + * abort. + */ + continue; + } + if (fam == AF_INET6 && IN6_IS_ADDR_LINKLOCAL(&sifa->address.sin6.sin6_addr) && IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr)) { /* @@ -2701,13 +2702,6 @@ sctp_select_nth_preferred_addr_from_ifn_boundall(struct sctp_ifn *ifn, if (sin6.sin6_scope_id != lsa6.sin6_scope_id) { continue; } - if (dest_is_loop) { - /* - * we don't give out fe80::1, we must use - * ::1 - */ - continue; - } } #endif /* INET6 */ @@ -3412,10 +3406,11 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, struct sctp_tmit_chunk *chk, int out_of_asoc_ok, uint16_t port, - int so_locked + int so_locked, #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) SCTP_UNUSED #endif + union sctp_sockstore *over_addr ) /* nofragment_flag to tell if IP_DF should be set (IPv4 only) */ { @@ -3575,17 +3570,22 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, } ip->ip_src = net->ro._s_addr->address.sin.sin_addr; } else { - struct sctp_ifa *_lsrc; + if (over_addr == NULL) { + struct sctp_ifa *_lsrc; - _lsrc = sctp_source_address_selection(inp, stcb, ro, - net, - out_of_asoc_ok, - vrf_id); - if (_lsrc == NULL) { - goto no_route; + _lsrc = sctp_source_address_selection(inp, stcb, ro, + net, + out_of_asoc_ok, + vrf_id); + if (_lsrc == NULL) { + goto no_route; + } + ip->ip_src = _lsrc->address.sin.sin_addr; + sctp_free_ifa(_lsrc); + } else { + ip->ip_src = over_addr->sin.sin_addr; + SCTP_RTALLOC((&ro->ro_rt), vrf_id); } - ip->ip_src = _lsrc->address.sin.sin_addr; - sctp_free_ifa(_lsrc); } if (port) { udp = (struct udphdr *)(ip + 1); @@ -3879,28 +3879,33 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, } lsa6->sin6_addr = net->ro._s_addr->address.sin6.sin6_addr; } else { - struct sctp_ifa *_lsrc; - sin6 = (struct sockaddr_in6 *)&ro->ro_dst; /* KAME hack: embed scopeid */ if (sa6_embedscope(sin6, ip6_use_defzone) != 0) { SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); return (EINVAL); } - _lsrc = sctp_source_address_selection(inp, stcb, ro, - net, - out_of_asoc_ok, - vrf_id); - (void)sa6_recoverscope(sin6); - if (_lsrc == NULL) { - goto no_route; + if (over_addr == NULL) { + struct sctp_ifa *_lsrc; + + _lsrc = sctp_source_address_selection(inp, stcb, ro, + net, + out_of_asoc_ok, + vrf_id); + if (_lsrc == NULL) { + goto no_route; + } + lsa6->sin6_addr = _lsrc->address.sin6.sin6_addr; + sctp_free_ifa(_lsrc); + } else { + lsa6->sin6_addr = over_addr->sin6.sin6_addr; + SCTP_RTALLOC((&ro->ro_rt), vrf_id); } - lsa6->sin6_addr = _lsrc->address.sin6.sin6_addr; - sctp_free_ifa(_lsrc); + (void)sa6_recoverscope(sin6); } lsa6->sin6_port = inp->sctp_lport; - if ((ro->ro_rt == NULL)) { + if (ro->ro_rt == NULL) { /* * src addr selection failed to find a route (or * valid source addr), so we can't get there from @@ -4322,7 +4327,7 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked SCTPDBG(SCTP_DEBUG_OUTPUT4, "Sending INIT - calls lowlevel_output\n"); ret = sctp_lowlevel_chunk_output(inp, stcb, net, (struct sockaddr *)&net->ro._l_addr, - m, 0, NULL, 0, 0, NULL, 0, net->port, so_locked); + m, 0, NULL, 0, 0, NULL, 0, net->port, so_locked, NULL); SCTPDBG(SCTP_DEBUG_OUTPUT4, "lowlevel_output - %d\n", ret); SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks); sctp_timer_start(SCTP_TIMER_TYPE_INIT, inp, stcb, net); @@ -4849,14 +4854,13 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb, struct sctp_prsctp_supported_param *prsctp; struct sctp_ecn_nonce_supported_param *ecn_nonce; struct sctp_supported_chunk_types_param *pr_supported; - struct sockaddr_storage store; - struct sockaddr_in *sin; + union sctp_sockstore store, store1, *over_addr; + struct sockaddr_in *sin, *to_sin; #ifdef INET6 - struct sockaddr_in6 *sin6; + struct sockaddr_in6 *sin6, *to_sin6; #endif - sctp_route_t *ro; struct ip *iph; #ifdef INET6 @@ -4896,6 +4900,7 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb, (offset + sizeof(struct sctp_init_chunk)), &abort_flag, (struct sctp_chunkhdr *)init_chk); if (abort_flag) { +do_a_abort: sctp_send_abort(init_pkt, iphlen, sh, init_chk->init.initiate_tag, op_err, vrf_id, port); return; @@ -4961,19 +4966,42 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb, #endif /* now for scope setup */ memset((caddr_t)&store, 0, sizeof(store)); - sin = (struct sockaddr_in *)&store; + memset((caddr_t)&store1, 0, sizeof(store1)); + sin = &store.sin; + to_sin = &store1.sin; +#ifdef INET6 + sin6 = &store.sin6; + to_sin6 = &store1.sin6; +#endif + iph = mtod(init_pkt, struct ip *); + /* establish the to_addr's */ + switch (iph->ip_v) { + case IPVERSION: + to_sin->sin_port = sh->dest_port; + to_sin->sin_family = AF_INET; + to_sin->sin_len = sizeof(struct sockaddr_in); + to_sin->sin_addr = iph->ip_dst; + break; #ifdef INET6 - sin6 = (struct sockaddr_in6 *)&store; + case IPV6_VERSION >> 4: + ip6 = mtod(init_pkt, struct ip6_hdr *); + to_sin6->sin6_addr = ip6->ip6_dst; + to_sin6->sin6_scope_id = 0; + to_sin6->sin6_port = sh->dest_port; + to_sin6->sin6_family = AF_INET6; + to_sin6->sin6_len = sizeof(struct sockaddr_in6); + break; #endif + default: + goto do_a_abort; + break; + }; + if (net == NULL) { to = (struct sockaddr *)&store; - iph = mtod(init_pkt, struct ip *); switch (iph->ip_v) { case IPVERSION: { - struct sctp_ifa *addr; - sctp_route_t iproute; - sin->sin_family = AF_INET; sin->sin_len = sizeof(struct sockaddr_in); sin->sin_port = sh->src_port; @@ -4985,20 +5013,7 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb, stc.address[3] = 0; stc.addr_type = SCTP_IPV4_ADDRESS; /* local from address */ - memset(&iproute, 0, sizeof(iproute)); - ro = &iproute; - memcpy(&ro->ro_dst, sin, sizeof(*sin)); - addr = sctp_source_address_selection(inp, NULL, - ro, NULL, 0, - vrf_id); - if (addr == NULL) - return; - - if (ro->ro_rt) { - RTFREE(ro->ro_rt); - ro->ro_rt = NULL; - } - stc.laddress[0] = addr->address.sin.sin_addr.s_addr; + stc.laddress[0] = to_sin->sin_addr.s_addr; stc.laddress[1] = 0; stc.laddress[2] = 0; stc.laddress[3] = 0; @@ -5019,15 +5034,11 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb, stc.site_scope = 1; stc.local_scope = 0; } - sctp_free_ifa(addr); break; } #ifdef INET6 case IPV6_VERSION >> 4: { - struct sctp_ifa *addr; - struct route_in6 iproute6; - ip6 = mtod(init_pkt, struct ip6_hdr *); sin6->sin6_family = AF_INET6; sin6->sin6_len = sizeof(struct sockaddr_in6); @@ -5091,27 +5102,14 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb, */ stc.site_scope = 1; } - /* local from address */ - memset(&iproute6, 0, sizeof(iproute6)); - ro = (sctp_route_t *) & iproute6; - memcpy(&ro->ro_dst, sin6, sizeof(*sin6)); - addr = sctp_source_address_selection(inp, NULL, - ro, NULL, 0, vrf_id); - if (addr == NULL) - return; - - if (ro->ro_rt) { - RTFREE(ro->ro_rt); - ro->ro_rt = NULL; - } - memcpy(&stc.laddress, &addr->address.sin6.sin6_addr, sizeof(struct in6_addr)); + memcpy(&stc.laddress, &to_sin6->sin6_addr, sizeof(struct in6_addr)); stc.laddr_type = SCTP_IPV6_ADDRESS; - sctp_free_ifa(addr); break; } #endif default: /* TSNH */ + goto do_a_abort; break; } } else { @@ -5493,8 +5491,15 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb, } p_len += padval; } + if (stc.loopback_scope) { + over_addr = &store1; + } else { + over_addr = NULL; + + } + (void)sctp_lowlevel_chunk_output(inp, NULL, NULL, to, m, 0, NULL, 0, 0, - NULL, 0, port, SCTP_SO_NOT_LOCKED); + NULL, 0, port, SCTP_SO_NOT_LOCKED, over_addr); SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks); } @@ -7651,7 +7656,7 @@ again_one_more_time: if ((error = sctp_lowlevel_chunk_output(inp, stcb, net, (struct sockaddr *)&net->ro._l_addr, outchain, auth_offset, auth, - no_fragmentflg, 0, NULL, asconf, net->port, so_locked))) { + no_fragmentflg, 0, NULL, asconf, net->port, so_locked, NULL))) { if (error == ENOBUFS) { asoc->ifp_had_enobuf = 1; SCTP_STAT_INCR(sctps_lowlevelerr); @@ -7878,7 +7883,7 @@ again_one_more_time: if ((error = sctp_lowlevel_chunk_output(inp, stcb, net, (struct sockaddr *)&net->ro._l_addr, outchain, auth_offset, auth, - no_fragmentflg, 0, NULL, asconf, net->port, so_locked))) { + no_fragmentflg, 0, NULL, asconf, net->port, so_locked, NULL))) { if (error == ENOBUFS) { asoc->ifp_had_enobuf = 1; SCTP_STAT_INCR(sctps_lowlevelerr); @@ -8167,7 +8172,7 @@ again_one_more_time: no_fragmentflg, bundle_at, data_list[0], - asconf, net->port, so_locked))) { + asconf, net->port, so_locked, NULL))) { /* error, we could not output */ if (error == ENOBUFS) { SCTP_STAT_INCR(sctps_lowlevelerr); @@ -8881,7 +8886,7 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp, if ((error = sctp_lowlevel_chunk_output(inp, stcb, chk->whoTo, (struct sockaddr *)&chk->whoTo->ro._l_addr, m, auth_offset, - auth, no_fragmentflg, 0, NULL, 0, chk->whoTo->port, so_locked))) { + auth, no_fragmentflg, 0, NULL, 0, chk->whoTo->port, so_locked, NULL))) { SCTP_STAT_INCR(sctps_lowlevelerr); return (error); } @@ -9119,7 +9124,7 @@ one_chunk_around: /* Now lets send it, if there is anything to send :> */ if ((error = sctp_lowlevel_chunk_output(inp, stcb, net, (struct sockaddr *)&net->ro._l_addr, m, auth_offset, - auth, no_fragmentflg, 0, NULL, 0, net->port, so_locked))) { + auth, no_fragmentflg, 0, NULL, 0, net->port, so_locked, NULL))) { /* error, we could not output */ SCTP_STAT_INCR(sctps_lowlevelerr); return (error); @@ -10099,7 +10104,7 @@ sctp_send_abort_tcb(struct sctp_tcb *stcb, struct mbuf *operr, int so_locked (void)sctp_lowlevel_chunk_output(stcb->sctp_ep, stcb, stcb->asoc.primary_destination, (struct sockaddr *)&stcb->asoc.primary_destination->ro._l_addr, - m_out, auth_offset, auth, 1, 0, NULL, 0, stcb->asoc.primary_destination->port, so_locked); + m_out, auth_offset, auth, 1, 0, NULL, 0, stcb->asoc.primary_destination->port, so_locked, NULL); SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks); } @@ -10128,7 +10133,7 @@ sctp_send_shutdown_complete(struct sctp_tcb *stcb, SCTP_BUF_LEN(m_shutdown_comp) = sizeof(struct sctp_shutdown_complete_msg); (void)sctp_lowlevel_chunk_output(stcb->sctp_ep, stcb, net, (struct sockaddr *)&net->ro._l_addr, - m_shutdown_comp, 0, NULL, 1, 0, NULL, 0, net->port, SCTP_SO_NOT_LOCKED); + m_shutdown_comp, 0, NULL, 1, 0, NULL, 0, net->port, SCTP_SO_NOT_LOCKED, NULL); SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks); return; } diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c index 05082ac..2fef0e0 100644 --- a/sys/netinet/sctputil.c +++ b/sys/netinet/sctputil.c @@ -1420,7 +1420,7 @@ sctp_timeout_handler(void *t) struct socket *so; #endif - int did_output; + int did_output, type; struct sctp_iterator *it = NULL; tmr = (struct sctp_timer *)t; @@ -1460,6 +1460,7 @@ sctp_timeout_handler(void *t) it = (struct sctp_iterator *)inp; inp = NULL; } + type = tmr->type; if (inp) { SCTP_INP_INCR_REF(inp); if ((inp->sctp_socket == 0) && @@ -1838,6 +1839,7 @@ sctp_timeout_handler(void *t) sctp_timer_stop(SCTP_TIMER_TYPE_INPKILL, inp, NULL, NULL, SCTP_FROM_SCTPUTIL + SCTP_LOC_3); sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, SCTP_CALLED_DIRECTLY_NOCMPSET); + inp = NULL; goto out_no_decr; default: SCTPDBG(SCTP_DEBUG_TIMER1, "sctp_timeout_handler:unknown timer %d\n", @@ -1869,9 +1871,7 @@ out_decr: } out_no_decr: SCTPDBG(SCTP_DEBUG_TIMER1, "Timer now complete (type %d)\n", - tmr->type); - if (inp) { - } + type); } void |