Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet6/ip6_output.c
Show First 20 Lines • Show All 316 Lines • ▼ Show 20 Lines | ip6_output(struct mbuf *m0, struct ip6_pktopts *opt, | ||||
u_int32_t optlen = 0, plen = 0, unfragpartlen = 0; | u_int32_t optlen = 0, plen = 0, unfragpartlen = 0; | ||||
struct ip6_exthdrs exthdrs; | struct ip6_exthdrs exthdrs; | ||||
struct in6_addr src0, dst0; | struct in6_addr src0, dst0; | ||||
u_int32_t zone; | u_int32_t zone; | ||||
struct route_in6 *ro_pmtu = NULL; | struct route_in6 *ro_pmtu = NULL; | ||||
int hdrsplit = 0; | int hdrsplit = 0; | ||||
int sw_csum, tso; | int sw_csum, tso; | ||||
int needfiblookup; | int needfiblookup; | ||||
int has_fwd_tag = 0; | |||||
uint32_t fibnum; | uint32_t fibnum; | ||||
struct m_tag *fwd_tag = NULL; | |||||
uint32_t id; | uint32_t id; | ||||
if (inp != NULL) { | if (inp != NULL) { | ||||
M_SETFIB(m, inp->inp_inc.inc_fibnum); | M_SETFIB(m, inp->inp_inc.inc_fibnum); | ||||
if ((flags & IP_NODEFAULTFLOWID) == 0) { | if ((flags & IP_NODEFAULTFLOWID) == 0) { | ||||
/* unconditionally set flowid */ | /* unconditionally set flowid */ | ||||
m->m_pkthdr.flowid = inp->inp_flowid; | m->m_pkthdr.flowid = inp->inp_flowid; | ||||
M_HASHTYPE_SET(m, inp->inp_flowtype); | M_HASHTYPE_SET(m, inp->inp_flowtype); | ||||
▲ Show 20 Lines • Show All 207 Lines • ▼ Show 20 Lines | again: | ||||
* Validate route against routing table additions; | * Validate route against routing table additions; | ||||
* a better/more specific route might have been added. | * a better/more specific route might have been added. | ||||
* Make sure address family is set in route. | * Make sure address family is set in route. | ||||
*/ | */ | ||||
if (inp) { | if (inp) { | ||||
ro->ro_dst.sin6_family = AF_INET6; | ro->ro_dst.sin6_family = AF_INET6; | ||||
RT_VALIDATE((struct route *)ro, &inp->inp_rt_cookie, fibnum); | RT_VALIDATE((struct route *)ro, &inp->inp_rt_cookie, fibnum); | ||||
} | } | ||||
if (ro->ro_rt && fwd_tag == NULL && (ro->ro_rt->rt_flags & RTF_UP) && | if (ro->ro_rt && has_fwd_tag && (ro->ro_rt->rt_flags & RTF_UP) && | ||||
ae: This check looks incorrect. | |||||
ro->ro_dst.sin6_family == AF_INET6 && | ro->ro_dst.sin6_family == AF_INET6 && | ||||
IN6_ARE_ADDR_EQUAL(&ro->ro_dst.sin6_addr, &ip6->ip6_dst)) { | IN6_ARE_ADDR_EQUAL(&ro->ro_dst.sin6_addr, &ip6->ip6_dst)) { | ||||
rt = ro->ro_rt; | rt = ro->ro_rt; | ||||
ifp = ro->ro_rt->rt_ifp; | ifp = ro->ro_rt->rt_ifp; | ||||
} else { | } else { | ||||
if (ro->ro_lle) | if (ro->ro_lle) | ||||
LLE_FREE(ro->ro_lle); /* zeros ro_lle */ | LLE_FREE(ro->ro_lle); /* zeros ro_lle */ | ||||
ro->ro_lle = NULL; | ro->ro_lle = NULL; | ||||
if (fwd_tag == NULL) { | if (has_fwd_tag) { | ||||
aeUnsubmitted Done Inline Actionsand this. ae: and this. | |||||
bzero(&dst_sa, sizeof(dst_sa)); | bzero(&dst_sa, sizeof(dst_sa)); | ||||
dst_sa.sin6_family = AF_INET6; | dst_sa.sin6_family = AF_INET6; | ||||
dst_sa.sin6_len = sizeof(dst_sa); | dst_sa.sin6_len = sizeof(dst_sa); | ||||
dst_sa.sin6_addr = ip6->ip6_dst; | dst_sa.sin6_addr = ip6->ip6_dst; | ||||
} | } | ||||
error = in6_selectroute_fib(&dst_sa, opt, im6o, ro, &ifp, | error = in6_selectroute_fib(&dst_sa, opt, im6o, ro, &ifp, | ||||
&rt, fibnum); | &rt, fibnum); | ||||
if (error != 0) { | if (error != 0) { | ||||
▲ Show 20 Lines • Show All 287 Lines • ▼ Show 20 Lines | |||||
#ifdef SCTP | #ifdef SCTP | ||||
if (m->m_pkthdr.csum_flags & CSUM_SCTP_IPV6) | if (m->m_pkthdr.csum_flags & CSUM_SCTP_IPV6) | ||||
m->m_pkthdr.csum_flags |= CSUM_SCTP_VALID; | m->m_pkthdr.csum_flags |= CSUM_SCTP_VALID; | ||||
#endif | #endif | ||||
error = netisr_queue(NETISR_IPV6, m); | error = netisr_queue(NETISR_IPV6, m); | ||||
goto done; | goto done; | ||||
} | } | ||||
/* Or forward to some other address? */ | /* Or forward to some other address? */ | ||||
if ((m->m_flags & M_IP6_NEXTHOP) && | if (IP6_HAS_NEXTHOP(m) && !ip6_get_fwdtag(m, &dst_sa, NULL)) { | ||||
(fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL)) != NULL) { | |||||
dst = (struct sockaddr_in6 *)&ro->ro_dst; | dst = (struct sockaddr_in6 *)&ro->ro_dst; | ||||
bcopy((fwd_tag+1), &dst_sa, sizeof(struct sockaddr_in6)); | |||||
m->m_flags |= M_SKIP_FIREWALL; | m->m_flags |= M_SKIP_FIREWALL; | ||||
m->m_flags &= ~M_IP6_NEXTHOP; | ip6_flush_fwdtag(m); | ||||
m_tag_delete(m, fwd_tag); | has_fwd_tag = 1; | ||||
goto again; | goto again; | ||||
} | } | ||||
passout: | passout: | ||||
/* | /* | ||||
* Send the packet to the outgoing interface. | * Send the packet to the outgoing interface. | ||||
* If necessary, do IPv6 fragmentation before sending. | * If necessary, do IPv6 fragmentation before sending. | ||||
* | * | ||||
▲ Show 20 Lines • Show All 2,212 Lines • ▼ Show 20 Lines | #define elen(x) \ | ||||
len += elen(in6p->in6p_outputopts->ip6po_hbh); | len += elen(in6p->in6p_outputopts->ip6po_hbh); | ||||
if (in6p->in6p_outputopts->ip6po_rthdr) | if (in6p->in6p_outputopts->ip6po_rthdr) | ||||
/* dest1 is valid with rthdr only */ | /* dest1 is valid with rthdr only */ | ||||
len += elen(in6p->in6p_outputopts->ip6po_dest1); | len += elen(in6p->in6p_outputopts->ip6po_dest1); | ||||
len += elen(in6p->in6p_outputopts->ip6po_rthdr); | len += elen(in6p->in6p_outputopts->ip6po_rthdr); | ||||
len += elen(in6p->in6p_outputopts->ip6po_dest2); | len += elen(in6p->in6p_outputopts->ip6po_dest2); | ||||
return len; | return len; | ||||
#undef elen | #undef elen | ||||
} | |||||
int | |||||
ip6_set_fwdtag(struct mbuf *m, struct sockaddr_in6 *dst, u_short ifidx) | |||||
{ | |||||
struct sockaddr_in6 *sa6; | |||||
struct m_tag *fwd_tag; | |||||
(void)ifidx; /* XXX: store after dst, or make struct? */ | |||||
fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL); | |||||
if (fwd_tag != NULL) { | |||||
KASSERT(((struct sockaddr *)(fwd_tag+1))->sa_family == | |||||
AF_INET6, ("%s: !AF_INET6", __func__)); | |||||
m_tag_unlink(m, fwd_tag); | |||||
} else { | |||||
fwd_tag = m_tag_get(PACKET_TAG_IPFORWARD, sizeof(*dst), | |||||
M_NOWAIT); | |||||
if (fwd_tag == NULL) { | |||||
return 1; | |||||
} | |||||
} | |||||
sa6 = (struct sockaddr_in6 *)(fwd_tag+1); | |||||
bcopy(dst, sa6, sizeof(*dst)); | |||||
/* | |||||
* If nh6 address is link-local we should convert | |||||
* it to kernel internal form before doing any | |||||
* comparisons. | |||||
*/ | |||||
if (sa6_embedscope(sa6, V_ip6_use_defzone) != 0) { | |||||
m_tag_free(fwd_tag); | |||||
return 1; | |||||
aeUnsubmitted Done Inline ActionsWe can return EINVAL here due to wrong sin6_scope_id in dst. Or return ENXIO like sa6_embedscope() does. ae: We can return EINVAL here due to wrong sin6_scope_id in dst. Or return ENXIO like… | |||||
} | |||||
if (in6_localip(&sa6->sin6_addr)) | |||||
m->m_flags |= M_FASTFWD_OURS; | |||||
else | |||||
m->m_flags &= ~M_FASTFWD_OURS; | |||||
m->m_flags |= M_IP6_NEXTHOP; | |||||
m_tag_prepend(m, fwd_tag); | |||||
return 0; | |||||
} | |||||
int | |||||
ip6_get_fwdtag(struct mbuf *m, struct sockaddr_in6 *dst, u_short *ifidx) | |||||
{ | |||||
struct m_tag *fwd_tag; | |||||
fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL); | |||||
if (fwd_tag == NULL) { | |||||
return 1; | |||||
} | |||||
KASSERT(((struct sockaddr *)(fwd_tag+1))->sa_family == AF_INET6, | |||||
("%s: !AF_INET6", __func__)); | |||||
if (dst != NULL) { | |||||
bcopy((fwd_tag+1), dst, sizeof(*dst)); | |||||
} | |||||
if (ifidx != NULL) { | |||||
/* XXX ifidx is not yet defined */ | |||||
} | |||||
return 0; | |||||
} | |||||
void | |||||
ip6_flush_fwdtag(struct mbuf *m) | |||||
{ | |||||
struct m_tag *fwd_tag; | |||||
fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL); | |||||
if (fwd_tag != NULL) { | |||||
KASSERT(((struct sockaddr *)(fwd_tag+1))->sa_family == | |||||
AF_INET6, ("%s: !AF_INET6", __func__)); | |||||
m->m_flags &= ~(M_IP6_NEXTHOP | M_FASTFWD_OURS); | |||||
m_tag_delete(m, fwd_tag); | |||||
} | |||||
} | } |
This check looks incorrect.