diff options
author | rrs <rrs@FreeBSD.org> | 2007-08-27 05:19:48 +0000 |
---|---|---|
committer | rrs <rrs@FreeBSD.org> | 2007-08-27 05:19:48 +0000 |
commit | e335457f91efbba1e9ccc24574c0ffc73235bd94 (patch) | |
tree | 5c37015ad6945c94641b6d5d3a589608e280afe1 /sys/netinet/sctp_output.c | |
parent | 3eb0fa1342d0b24e14ff06361e7b8a71c4441b06 (diff) | |
download | FreeBSD-src-e335457f91efbba1e9ccc24574c0ffc73235bd94.zip FreeBSD-src-e335457f91efbba1e9ccc24574c0ffc73235bd94.tar.gz |
- During shutdown pending, when the last sack came in and
the last message on the send stream was "null" but still
there, a state we allow, we could get hung and not clean
it up and wait for the shutdown guard timer to clear the
association without a graceful close. Fix this so that
that we properly clean up.
- Added support for Multiple ASCONF per new RFC. We only
(so far) accept input of these and cannot yet generate
a multi-asconf.
- Sysctl'd support for experimental Fast Handover feature. Always
disabled unless sysctl or socket option changes to enable.
- Error case in add-ip where the peer supports AUTH and ADD-IP
but does NOT require AUTH of ASCONF/ASCONF-ACK. We need to
ABORT in this case.
- According to the Kyoto summit of socket api developers
(Solaris, Linux, BSD). We need to have:
o non-eeor mode messages be atomic - Fixed
o Allow implicit setup of an assoc in 1-2-1 model if
using the sctp_**() send calls - Fixed
o Get rid of HAVE_XXX declarations - Done
o add a sctp_pr_policy in hole in sndrcvinfo structure - Done
o add a PR_SCTP_POLICY_VALID type flag - yet to-do in a future patch!
- Optimize sctp6 calls to reuse code in sctp_usrreq. Also optimize
when we close sending out the data and disabling Nagle.
- Change key concatenation order to match the auth RFC
- When sending OOTB shutdown_complete always do csum.
- Don't send PKT-DROP to a PKT-DROP
- For abort chunks just always checksums same for
shutdown-complete.
- inpcb_free front state had a bug where in queue
data could wedge an assoc. We need to just abandon
ones in front states (free_assoc).
- If a peer sends us a 64k abort, we would try to
assemble a response packet which may be larger than
64k. This then would be dropped by IP. Instead make
a "minimum" size for us 64k-2k (we want at least
2k for our initack). If we receive such an init
discard it early without all the processing.
- When we peel off we must increment the tcb ref count
to keep it from being freed from underneath us.
- handling fwd-tsn had bugs that caused memory overwrites
when given faulty data, fixed so can't happen and we
also stop at the first bad stream no.
- Fixed so comm-up generates the adaption indication.
- peeloff did not get the hmac params copied.
- fix it so we lock the addr list when doing src-addr selection
(in future we need to use a multi-reader/one writer lock here)
- During lowlevel output, we could end up with a _l_addr set
to null if the iterator is calling the output routine. This
means we would possibly crash when we gather the MTU info.
Fix so we only do the gather where we have a src address
cached.
- we need to be sure to set abort flag on conn state when
we receive an abort.
- peeloff could leak a socket. Moved code so the close will
find the socket if the peeloff fails (uipc_syscalls.c)
Approved by: re@freebsd.org(Ken Smith)
Diffstat (limited to 'sys/netinet/sctp_output.c')
-rw-r--r-- | sys/netinet/sctp_output.c | 301 |
1 files changed, 207 insertions, 94 deletions
diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c index 85824fd..28b39d1 100644 --- a/sys/netinet/sctp_output.c +++ b/sys/netinet/sctp_output.c @@ -2606,7 +2606,9 @@ sctp_select_nth_preferred_addr_from_ifn_boundall(struct sctp_ifn *ifn, uint8_t dest_is_loop, uint8_t dest_is_priv, int addr_wanted, - sa_family_t fam) + sa_family_t fam, + sctp_route_t * ro +) { struct sctp_ifa *ifa, *sifa; int num_eligible_addr = 0; @@ -2619,6 +2621,27 @@ sctp_select_nth_preferred_addr_from_ifn_boundall(struct sctp_ifn *ifn, dest_is_priv, fam); if (sifa == NULL) continue; + /* + * Check if the IPv6 address matches to next-hop. In the + * mobile case, old IPv6 address may be not deleted from the + * interface. Then, the interface has previous and new + * addresses. We should use one corresponding to the + * next-hop. (by micchie) + */ + if (stcb && fam == AF_INET6 && + sctp_is_mobility_feature_on(stcb->sctp_ep, SCTP_MOBILITY_BASE)) { + if (sctp_v6src_match_nexthop(&sifa->address.sin6, ro) + == 0) { + continue; + } + } + /* Avoid topologically incorrect IPv4 address */ + if (stcb && fam == AF_INET && + sctp_is_mobility_feature_on(stcb->sctp_ep, SCTP_MOBILITY_BASE)) { + if (sctp_v4src_match_nexthop(sifa, ro) == 0) { + continue; + } + } if (stcb) { if ((non_asoc_addr_ok == 0) && sctp_is_addr_restricted(stcb, sifa)) { @@ -2753,7 +2776,7 @@ sctp_choose_boundall(struct sctp_inpcb *inp, SCTPDBG(SCTP_DEBUG_OUTPUT2, "cur_addr_num:%d\n", cur_addr_num); sctp_ifa = sctp_select_nth_preferred_addr_from_ifn_boundall(sctp_ifn, stcb, non_asoc_addr_ok, dest_is_loop, - dest_is_priv, cur_addr_num, fam); + dest_is_priv, cur_addr_num, fam, ro); /* if sctp_ifa is NULL something changed??, fall to plan b. */ if (sctp_ifa) { @@ -2806,7 +2829,7 @@ bound_all_plan_b: cur_addr_num = 0; } sifa = sctp_select_nth_preferred_addr_from_ifn_boundall(sctp_ifn, stcb, non_asoc_addr_ok, dest_is_loop, - dest_is_priv, cur_addr_num, fam); + dest_is_priv, cur_addr_num, fam, ro); if (sifa == NULL) continue; if (net) { @@ -3018,6 +3041,7 @@ sctp_source_address_selection(struct sctp_inpcb *inp, } SCTPDBG(SCTP_DEBUG_OUTPUT2, "Select source addr for:"); SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT2, (struct sockaddr *)to); + SCTP_IPI_ADDR_LOCK(); if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { /* * Bound all case @@ -3025,6 +3049,7 @@ sctp_source_address_selection(struct sctp_inpcb *inp, answer = sctp_choose_boundall(inp, stcb, net, ro, vrf_id, dest_is_priv, dest_is_loop, non_asoc_addr_ok, fam); + SCTP_IPI_ADDR_UNLOCK(); return (answer); } /* @@ -3041,6 +3066,7 @@ sctp_source_address_selection(struct sctp_inpcb *inp, dest_is_priv, dest_is_loop, fam); } + SCTP_IPI_ADDR_UNLOCK(); return (answer); } @@ -3528,7 +3554,8 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, } } else { /* PMTU check versus smallest asoc MTU goes here */ - if (ro->ro_rt != NULL) { + if ((ro->ro_rt != NULL) && + (net->ro._s_addr)) { uint32_t mtu; mtu = SCTP_GATHER_MTU_FROM_ROUTE(net->ro._s_addr, &net->ro._l_addr.sa, ro->ro_rt); @@ -3541,7 +3568,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, sctp_mtu_size_reset(inp, &stcb->asoc, mtu); net->mtu = mtu; } - } else { + } else if (ro->ro_rt == NULL) { /* route was freed */ if (net->ro._s_addr && net->src_addr_selected) { @@ -3772,7 +3799,8 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, } net->src_addr_selected = 0; } - if (ro->ro_rt != NULL) { + if ((ro->ro_rt != NULL) && + (net->ro._s_addr)) { uint32_t mtu; mtu = SCTP_GATHER_MTU_FROM_ROUTE(net->ro._s_addr, &net->ro._l_addr.sa, ro->ro_rt); @@ -7893,7 +7921,6 @@ sctp_send_shutdown_ack(struct sctp_tcb *stcb, struct sctp_nets *net) return; } chk->copy_by_ref = 0; - chk->send_size = sizeof(struct sctp_chunkhdr); chk->rec.chunk_id.id = SCTP_SHUTDOWN_ACK; chk->rec.chunk_id.can_take_data = 1; @@ -8000,79 +8027,81 @@ sctp_send_asconf(struct sctp_tcb *stcb, struct sctp_nets *net) } void -sctp_send_asconf_ack(struct sctp_tcb *stcb, uint32_t retrans) +sctp_send_asconf_ack(struct sctp_tcb *stcb) { /* * formulate and queue a asconf-ack back to sender. the asconf-ack * must be stored in the tcb. */ struct sctp_tmit_chunk *chk; + struct sctp_asconf_ack *ack, *latest_ack; struct mbuf *m_ack, *m; + struct sctp_nets *net = NULL; SCTP_TCB_LOCK_ASSERT(stcb); - /* is there a asconf-ack mbuf chain to send? */ - if (stcb->asoc.last_asconf_ack_sent == NULL) { + /* Get the latest ASCONF-ACK */ + latest_ack = TAILQ_LAST(&stcb->asoc.asconf_ack_sent, sctp_asconf_ackhead); + if (latest_ack == NULL) { return; } - /* copy the asconf_ack */ - m_ack = SCTP_M_COPYM(stcb->asoc.last_asconf_ack_sent, 0, M_COPYALL, - M_DONTWAIT); - if (m_ack == NULL) { - /* couldn't copy it */ - return; - } - sctp_alloc_a_chunk(stcb, chk); - if (chk == NULL) { - /* no memory */ - if (m_ack) - sctp_m_freem(m_ack); - return; - } - chk->copy_by_ref = 0; - /* figure out where it goes to */ - if (retrans) { + if (latest_ack->last_sent_to != NULL && + latest_ack->last_sent_to == stcb->asoc.last_control_chunk_from) { /* we're doing a retransmission */ - if (stcb->asoc.used_alt_asconfack > 2) { - /* tried alternate nets already, go back */ - chk->whoTo = NULL; - } else { - /* need to try and alternate net */ - chk->whoTo = sctp_find_alternate_net(stcb, stcb->asoc.last_control_chunk_from, 0); - stcb->asoc.used_alt_asconfack++; - } - if (chk->whoTo == NULL) { + net = sctp_find_alternate_net(stcb, stcb->asoc.last_control_chunk_from, 0); + if (net == NULL) { /* no alternate */ if (stcb->asoc.last_control_chunk_from == NULL) - chk->whoTo = stcb->asoc.primary_destination; + net = stcb->asoc.primary_destination; else - chk->whoTo = stcb->asoc.last_control_chunk_from; - stcb->asoc.used_alt_asconfack = 0; + net = stcb->asoc.last_control_chunk_from; } } else { /* normal case */ if (stcb->asoc.last_control_chunk_from == NULL) - chk->whoTo = stcb->asoc.primary_destination; + net = stcb->asoc.primary_destination; else - chk->whoTo = stcb->asoc.last_control_chunk_from; - stcb->asoc.used_alt_asconfack = 0; + net = stcb->asoc.last_control_chunk_from; } - chk->data = m_ack; - chk->send_size = 0; - /* Get size */ - m = m_ack; - while (m) { - chk->send_size += SCTP_BUF_LEN(m); - m = SCTP_BUF_NEXT(m); + 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; + } + /* copy the asconf_ack */ + m_ack = SCTP_M_COPYM(ack->data, 0, M_COPYALL, M_DONTWAIT); + if (m_ack == NULL) { + /* couldn't copy it */ + return; + } + sctp_alloc_a_chunk(stcb, chk); + if (chk == NULL) { + /* no memory */ + if (m_ack) + sctp_m_freem(m_ack); + return; + } + chk->copy_by_ref = 0; + + chk->whoTo = net; + chk->data = m_ack; + chk->send_size = 0; + /* Get size */ + m = m_ack; + chk->send_size = ack->len; + chk->rec.chunk_id.id = SCTP_ASCONF_ACK; + chk->rec.chunk_id.can_take_data = 1; + chk->sent = SCTP_DATAGRAM_UNSENT; + chk->snd_count = 0; + chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; /* XXX */ + chk->asoc = &stcb->asoc; + atomic_add_int(&chk->whoTo->ref_count, 1); + + TAILQ_INSERT_TAIL(&chk->asoc->control_send_queue, chk, sctp_next); + chk->asoc->ctrl_queue_cnt++; } - chk->rec.chunk_id.id = SCTP_ASCONF_ACK; - chk->rec.chunk_id.can_take_data = 1; - chk->sent = SCTP_DATAGRAM_UNSENT; - chk->snd_count = 0; - chk->flags = 0; - chk->asoc = &stcb->asoc; - atomic_add_int(&chk->whoTo->ref_count, 1); - TAILQ_INSERT_TAIL(&chk->asoc->control_send_queue, chk, sctp_next); - chk->asoc->ctrl_queue_cnt++; return; } @@ -9516,11 +9545,7 @@ sctp_send_shutdown_complete2(struct mbuf *m, int iphlen, struct sctphdr *sh, comp_cp->shut_cmp.ch.chunk_length = htons(sizeof(struct sctp_shutdown_complete_chunk)); /* add checksum */ - if ((sctp_no_csum_on_loopback) && SCTP_IS_IT_LOOPBACK(mout)) { - comp_cp->sh.checksum = 0; - } else { - comp_cp->sh.checksum = sctp_calculate_sum(mout, NULL, offset_out); - } + comp_cp->sh.checksum = sctp_calculate_sum(mout, NULL, offset_out); if (iph_out != NULL) { sctp_route_t ro; int ret; @@ -9779,8 +9804,7 @@ sctp_send_hb(struct sctp_tcb *stcb, int user_req, struct sctp_nets *u_net) sctp_free_remote_addr(chk->whoTo); chk->whoTo = NULL; } - SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_chunk, chk); - SCTP_DECR_CHK_COUNT(); + sctp_free_a_chunk((struct sctp_tcb *)NULL, chk); return (-1); } } @@ -9905,8 +9929,13 @@ sctp_send_packet_dropped(struct sctp_tcb *stcb, struct sctp_nets *net, break; } switch (ch->chunk_type) { + case SCTP_PACKET_DROPPED: case SCTP_ABORT_ASSOCIATION: - /* we don't respond with an PKT-DROP to an ABORT */ + /*- + * we don't respond with an PKT-DROP to an ABORT + * or PKT-DROP + */ + sctp_free_a_chunk(stcb, chk); return; default: break; @@ -10395,6 +10424,9 @@ sctp_send_abort(struct mbuf *m, int iphlen, struct sctphdr *sh, uint32_t vtag, abm = (struct sctp_abort_msg *)((caddr_t)ip6_out + iphlen_out); } else { /* Currently not supported */ + if (err_cause) + sctp_m_freem(err_cause); + sctp_m_freem(mout); return; } @@ -10436,11 +10468,7 @@ sctp_send_abort(struct mbuf *m, int iphlen, struct sctphdr *sh, uint32_t vtag, } /* add checksum */ - if ((sctp_no_csum_on_loopback) && SCTP_IS_IT_LOOPBACK(m)) { - abm->sh.checksum = 0; - } else { - abm->sh.checksum = sctp_calculate_sum(mout, NULL, iphlen_out); - } + abm->sh.checksum = sctp_calculate_sum(mout, NULL, iphlen_out); if (SCTP_GET_HEADER_FOR_OUTPUT(o_pak)) { /* no mbuf's */ sctp_m_freem(mout); @@ -10546,11 +10574,7 @@ sctp_send_operr_to(struct mbuf *m, int iphlen, struct mbuf *scm, uint32_t vtag, m_copyback(scm, len, padlen, (caddr_t)&cpthis); len += padlen; } - if ((sctp_no_csum_on_loopback) && SCTP_IS_IT_LOOPBACK(m)) { - val = 0; - } else { - val = sctp_calculate_sum(scm, NULL, 0); - } + val = sctp_calculate_sum(scm, NULL, 0); mout = sctp_get_mbuf_for_msg(sizeof(struct ip6_hdr), 1, M_DONTWAIT, 1, MT_DATA); if (mout == NULL) { sctp_m_freem(scm); @@ -10714,14 +10738,6 @@ sctp_copy_it_in(struct sctp_tcb *stcb, int resv_in_first; *error = 0; - /* Unless E_EOR mode is on, we must make a send FIT in one call. */ - if (((user_marks_eor == 0) && non_blocking) && - (uio->uio_resid > (int)SCTP_SB_LIMIT_SND(stcb->sctp_socket))) { - /* It will NEVER fit */ - SCTP_LTRACE_ERR_RET(NULL, stcb, net, SCTP_FROM_SCTP_OUTPUT, EMSGSIZE); - *error = EMSGSIZE; - goto out_now; - } /* Now can we send this? */ if ((SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_SENT) || (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_ACK_SENT) || @@ -10847,6 +10863,7 @@ sctp_lower_sosend(struct socket *so, struct sctp_nets *net; struct sctp_association *asoc; struct sctp_inpcb *t_inp; + int user_marks_eor; int create_lock_applied = 0; int nagle_applies = 0; int some_on_control = 0; @@ -10854,6 +10871,7 @@ sctp_lower_sosend(struct socket *so, int hold_tcblock = 0; int non_blocking = 0; int temp_flags = 0; + uint32_t local_add_more; error = 0; net = NULL; @@ -10869,6 +10887,7 @@ sctp_lower_sosend(struct socket *so, SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); return (EINVAL); } + user_marks_eor = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR); atomic_add_int(&inp->total_sends, 1); if (uio) { if (uio->uio_resid < 0) { @@ -11068,12 +11087,7 @@ sctp_lower_sosend(struct socket *so, } } if (stcb == NULL) { - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || - (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { - SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, ENOTCONN); - error = ENOTCONN; - goto out_unlocked; - } else if (addr == NULL) { + if (addr == NULL) { SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, ENOENT); error = ENOENT; goto out_unlocked; @@ -11226,6 +11240,7 @@ sctp_lower_sosend(struct socket *so, if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NO_FRAGMENT)) { if (sndlen > asoc->smallest_mtu) { + SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EMSGSIZE); error = EMSGSIZE; goto out_unlocked; } @@ -11444,11 +11459,32 @@ sctp_lower_sosend(struct socket *so, error = EFAULT; goto out_unlocked; } + /* 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))) { + /* It will NEVER fit */ + SCTP_LTRACE_ERR_RET(NULL, stcb, net, SCTP_FROM_SCTP_OUTPUT, EMSGSIZE); + error = EMSGSIZE; + goto out_unlocked; + } + if (user_marks_eor) { + local_add_more = sctp_add_more_threshold; + } else { + /*- + * For non-eeor the whole message must fit in + * the socket send buffer. + */ + local_add_more = uio->uio_resid; + } len = 0; - if ((max_len < sctp_add_more_threshold) && (SCTP_SB_LIMIT_SND(so) > sctp_add_more_threshold)) { + if (((max_len < local_add_more) && + (SCTP_SB_LIMIT_SND(so) > local_add_more)) || + ((stcb->asoc.chunks_on_out_queue + stcb->asoc.stream_queue_cnt) > sctp_max_chunks_on_queue)) { /* No room right no ! */ SOCKBUF_LOCK(&so->so_snd); - while (SCTP_SB_LIMIT_SND(so) < (stcb->asoc.total_output_queue_size + sctp_add_more_threshold)) { + while ((SCTP_SB_LIMIT_SND(so) < (stcb->asoc.total_output_queue_size + sctp_add_more_threshold)) || + ((stcb->asoc.stream_queue_cnt + stcb->asoc.chunks_on_out_queue) > sctp_max_chunks_on_queue)) { + if (sctp_logging_level & SCTP_BLK_LOGGING_ENABLE) { sctp_log_block(SCTP_BLOCK_LOG_INTO_BLKA, so, asoc, uio->uio_resid); @@ -11505,7 +11541,6 @@ sctp_lower_sosend(struct socket *so, struct sctp_stream_queue_pending *sp; struct sctp_stream_out *strm; uint32_t sndout, initial_out; - int user_marks_eor; initial_out = uio->uio_resid; @@ -11520,7 +11555,6 @@ sctp_lower_sosend(struct socket *so, SCTP_TCB_SEND_UNLOCK(stcb); strm = &stcb->asoc.strmout[srcv->sinfo_stream]; - user_marks_eor = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR); if (strm->last_msg_incomplete == 0) { do_a_copy_in: sp = sctp_copy_it_in(stcb, asoc, srcv, uio, net, max_len, user_marks_eor, &error, non_blocking); @@ -11937,6 +11971,7 @@ dataless_eof: } sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb, asoc->primary_destination); + sctp_feature_off(inp, SCTP_PCB_FLAGS_NODELAY); } } } @@ -12152,3 +12187,81 @@ sctp_add_auth_chunk(struct mbuf *m, struct mbuf **m_end, return (m); } + +int +sctp_v6src_match_nexthop(struct sockaddr_in6 *src6, sctp_route_t * ro) +{ + struct nd_prefix *pfx = NULL; + struct nd_pfxrouter *pfxrtr = NULL; + struct sockaddr_in6 gw6; + + if (ro == NULL || ro->ro_rt == NULL || src6->sin6_family != AF_INET6) + return (0); + + /* get prefix entry of address */ + LIST_FOREACH(pfx, &nd_prefix, ndpr_entry) { + if (pfx->ndpr_stateflags & NDPRF_DETACHED) + continue; + if (IN6_ARE_MASKED_ADDR_EQUAL(&pfx->ndpr_prefix.sin6_addr, + &src6->sin6_addr, &pfx->ndpr_mask)) + break; + } + /* no prefix entry in the prefix list */ + if (pfx == NULL) { + SCTPDBG(SCTP_DEBUG_OUTPUT2, "No prefix entry for "); + SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT2, (struct sockaddr *)src6); + return (0); + } + SCTPDBG(SCTP_DEBUG_OUTPUT2, "v6src_match_nexthop(), Prefix entry is "); + SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT2, (struct sockaddr *)src6); + + /* search installed gateway from prefix entry */ + for (pfxrtr = pfx->ndpr_advrtrs.lh_first; pfxrtr; pfxrtr = + pfxrtr->pfr_next) { + memset(&gw6, 0, sizeof(struct sockaddr_in6)); + gw6.sin6_family = AF_INET6; + gw6.sin6_len = sizeof(struct sockaddr_in6); + memcpy(&gw6.sin6_addr, &pfxrtr->router->rtaddr, + sizeof(struct in6_addr)); + SCTPDBG(SCTP_DEBUG_OUTPUT2, "prefix router is "); + SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT2, (struct sockaddr *)&gw6); + SCTPDBG(SCTP_DEBUG_OUTPUT2, "installed router is "); + SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT2, ro->ro_rt->rt_gateway); + if (sctp_cmpaddr((struct sockaddr *)&gw6, + ro->ro_rt->rt_gateway)) { + SCTPDBG(SCTP_DEBUG_OUTPUT2, "pfxrouter is installed\n"); + return (1); + } + } + SCTPDBG(SCTP_DEBUG_OUTPUT2, "pfxrouter is not installed\n"); + return (0); +} +int +sctp_v4src_match_nexthop(struct sctp_ifa *sifa, sctp_route_t * ro) +{ + struct sockaddr_in *sin, *mask; + struct ifaddr *ifa; + struct in_addr srcnetaddr, gwnetaddr; + + if (ro == NULL || ro->ro_rt == NULL || + sifa->address.sa.sa_family != AF_INET) { + return (0); + } + ifa = (struct ifaddr *)sifa->ifa; + mask = (struct sockaddr_in *)(ifa->ifa_netmask); + sin = (struct sockaddr_in *)&sifa->address.sin; + srcnetaddr.s_addr = (sin->sin_addr.s_addr & mask->sin_addr.s_addr); + SCTPDBG(SCTP_DEBUG_OUTPUT1, "match_nexthop4: src address is "); + SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT2, &sifa->address.sa); + SCTPDBG(SCTP_DEBUG_OUTPUT1, "network address is %x\n", srcnetaddr.s_addr); + + sin = (struct sockaddr_in *)ro->ro_rt->rt_gateway; + gwnetaddr.s_addr = (sin->sin_addr.s_addr & mask->sin_addr.s_addr); + SCTPDBG(SCTP_DEBUG_OUTPUT1, "match_nexthop4: nexthop is "); + SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT2, ro->ro_rt->rt_gateway); + SCTPDBG(SCTP_DEBUG_OUTPUT1, "network address is %x\n", gwnetaddr.s_addr); + if (srcnetaddr.s_addr == gwnetaddr.s_addr) { + return (1); + } + return (0); +} |