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) { | ||||
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; | |||||
| int error; | |||||
| (void)ifidx; /* XXX: store after dst, or make struct? */ | |||||
| KASSERT(dst != NULL, ("%s: !dst", __func__)); | |||||
| KASSERT(dst->sin6_family == AF_INET6, ("%s: !AF_INET6", __func__)); | |||||
| 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 (ENOBUFS); | |||||
| } | |||||
| } | |||||
| 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. | |||||
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… | |||||
| */ | |||||
| error = sa6_embedscope(sa6, V_ip6_use_defzone); | |||||
| if (error != 0) { | |||||
| m_tag_free(fwd_tag); | |||||
| return (error); | |||||
| } | |||||
| 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 (ENOENT); | |||||
| } | |||||
| 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.