ip6_output.c
来自「eCos操作系统源码」· C语言 代码 · 共 2,527 行 · 第 1/5 页
C
2,527 行
case IPSEC_POLICY_ENTRUST: default: printf("ip6_output: Invalid policy found. %d\n", sp->policy); }#endif /* OpenBSD */#endif /* IPSEC */ /* * Calculate the total length of the extension header chain. * Keep the length of the unfragmentable part for fragmentation. */ optlen = 0; if (exthdrs.ip6e_hbh) optlen += exthdrs.ip6e_hbh->m_len; if (exthdrs.ip6e_dest1) optlen += exthdrs.ip6e_dest1->m_len; if (exthdrs.ip6e_rthdr) optlen += exthdrs.ip6e_rthdr->m_len;#ifdef MIP6 if (exthdrs.ip6e_haddr) optlen += exthdrs.ip6e_haddr->m_len;#endif /* MIP6 */ unfragpartlen = optlen + sizeof(struct ip6_hdr); /* NOTE: we don't add AH/ESP length here. do that later. */ if (exthdrs.ip6e_dest2) optlen += exthdrs.ip6e_dest2->m_len; /* * If we need IPsec, or there is at least one extension header, * separate IP6 header from the payload. */#ifdef __OpenBSD__ if ((sproto || optlen) && !hdrsplit)#else if ((needipsec || optlen) && !hdrsplit)#endif { if ((error = ip6_splithdr(m, &exthdrs)) != 0) { m = NULL; goto freehdrs; } m = exthdrs.ip6e_ip6; hdrsplit++; } /* adjust pointer */ ip6 = mtod(m, struct ip6_hdr *); /* adjust mbuf packet header length */ m->m_pkthdr.len += optlen; plen = m->m_pkthdr.len - sizeof(*ip6); /* If this is a jumbo payload, insert a jumbo payload option. */ if (plen > IPV6_MAXPACKET) { if (!hdrsplit) { if ((error = ip6_splithdr(m, &exthdrs)) != 0) { m = NULL; goto freehdrs; } m = exthdrs.ip6e_ip6; hdrsplit++; } /* adjust pointer */ ip6 = mtod(m, struct ip6_hdr *); if ((error = ip6_insert_jumboopt(&exthdrs, plen)) != 0) goto freehdrs; ip6->ip6_plen = 0; } else ip6->ip6_plen = htons(plen); /* * Concatenate headers and fill in next header fields. * Here we have, on "m" * IPv6 payload * and we insert headers accordingly. Finally, we should be getting: * IPv6 hbh dest1 rthdr ah* [esp* dest2 payload] * * during the header composing process, "m" points to IPv6 header. * "mprev" points to an extension header prior to esp. */ { u_char *nexthdrp = &ip6->ip6_nxt; struct mbuf *mprev = m; /* * we treat dest2 specially. this makes IPsec processing * much easier. the goal here is to make mprev point the * mbuf prior to dest2. * * result: IPv6 dest2 payload * m and mprev will point to IPv6 header. */ if (exthdrs.ip6e_dest2) { if (!hdrsplit) panic("assumption failed: hdr not split"); exthdrs.ip6e_dest2->m_next = m->m_next; m->m_next = exthdrs.ip6e_dest2; *mtod(exthdrs.ip6e_dest2, u_char *) = ip6->ip6_nxt; ip6->ip6_nxt = IPPROTO_DSTOPTS; }#define MAKE_CHAIN(m, mp, p, i)\ do {\ if (m) {\ if (!hdrsplit) \ panic("assumption failed: hdr not split"); \ *mtod((m), u_char *) = *(p);\ *(p) = (i);\ p = mtod((m), u_char *);\ (m)->m_next = (mp)->m_next;\ (mp)->m_next = (m);\ (mp) = (m);\ }\ } while (0) /* * result: IPv6 hbh dest1 rthdr dest2 payload * m will point to IPv6 header. mprev will point to the * extension header prior to dest2 (rthdr in the above case). */ MAKE_CHAIN(exthdrs.ip6e_hbh, mprev, nexthdrp, IPPROTO_HOPOPTS); MAKE_CHAIN(exthdrs.ip6e_dest1, mprev, nexthdrp, IPPROTO_DSTOPTS); MAKE_CHAIN(exthdrs.ip6e_rthdr, mprev, nexthdrp, IPPROTO_ROUTING);#ifdef MIP6 /* * XXX * MIP6 homeaddress destination option must reside * after rthdr and before ah/esp/frag hdr. * this order is not recommended in the ipv6 spec of course. * result: IPv6 hbh dest1 rthdr ha dest2 payload. */ MAKE_CHAIN(exthdrs.ip6e_haddr, mprev, nexthdrp, IPPROTO_DSTOPTS);#endif /* MIP6 */#if defined(IPSEC) && !defined(__OpenBSD__) if (!needipsec) goto skip_ipsec2; /* * pointers after IPsec headers are not valid any more. * other pointers need a great care too. * (IPsec routines should not mangle mbufs prior to AH/ESP) */ exthdrs.ip6e_dest2 = NULL; { struct ip6_rthdr *rh = NULL; int segleft_org = 0; struct ipsec_output_state state; if (exthdrs.ip6e_rthdr) { rh = mtod(exthdrs.ip6e_rthdr, struct ip6_rthdr *); segleft_org = rh->ip6r_segleft; rh->ip6r_segleft = 0; } bzero(&state, sizeof(state)); state.m = m; error = ipsec6_output_trans(&state, nexthdrp, mprev, sp, flags, &needipsectun); m = state.m; if (error) { /* mbuf is already reclaimed in ipsec6_output_trans. */ m = NULL; switch (error) { case EHOSTUNREACH: case ENETUNREACH: case EMSGSIZE: case ENOBUFS: case ENOMEM: break; default: printf("ip6_output (ipsec): error code %d\n", error); /* fall through */ case ENOENT: /* don't show these error codes to the user */ error = 0; break; } goto bad; } if (exthdrs.ip6e_rthdr) { /* ah6_output doesn't modify mbuf chain */ rh->ip6r_segleft = segleft_org; } }skip_ipsec2:;#endif }#ifdef MIP6 if ((flags & IPV6_FORWARDING) == 0) { /* * After the IPsec processing the IPv6 header source * address (this is the homeaddress of this node) and * the address currently stored in the Home Address * destination option (this is the coa of this node) * must be swapped. */ if ((error = mip6_addr_exchange(m, exthdrs.ip6e_haddr)) != 0) { mip6log((LOG_ERR, "%s:%d: " "addr exchange between haddr and " "coa failed.\n", __FILE__, __LINE__)); goto bad; } } else { /* * this is the forwarding packet. The typical (and * only ?) case is multicast packet forwarding. The * swapping has been already done before (if * necessary). we must not touch any extension * headers at all. */ }#endif /* MIP6 */ /* * If there is a routing header, replace destination address field * with the first hop of the routing header. */ if (exthdrs.ip6e_rthdr) { struct ip6_rthdr *rh = (struct ip6_rthdr *)(mtod(exthdrs.ip6e_rthdr, struct ip6_rthdr *)); struct ip6_rthdr0 *rh0; struct in6_addr *addr; finaldst = ip6->ip6_dst; switch (rh->ip6r_type) { case IPV6_RTHDR_TYPE_0: rh0 = (struct ip6_rthdr0 *)rh; addr = (struct in6_addr *)(rh0 + 1); ip6->ip6_dst = *addr; bcopy((caddr_t)(addr + 1), (caddr_t)addr, sizeof(struct in6_addr) * (rh0->ip6r0_segleft - 1) ); *(addr + rh0->ip6r0_segleft - 1) = finaldst; break; default: /* is it possible? */ error = EINVAL; goto bad; } } /* Source address validation */ if (!(flags & IPV6_UNSPECSRC) && IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) { /* * XXX: we can probably assume validation in the caller, but * we explicitly check the address here for safety. */ error = EOPNOTSUPP; ip6stat.ip6s_badscope++; goto bad; } if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_src)) { error = EOPNOTSUPP; ip6stat.ip6s_badscope++; goto bad; } ip6stat.ip6s_localout++; /* * Route packet. */ if (ro == 0) { ro = &ip6route; bzero((caddr_t)ro, sizeof(*ro)); } ro_pmtu = ro; if (opt && opt->ip6po_rthdr) ro = &opt->ip6po_route;#ifdef MIP6 else if (exthdrs.ip6e_rthdr) { struct sockaddr_in6 *firsthop; struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); /* needed ? */; ro = &mip6_ip6route; bzero((caddr_t)ro, sizeof(*ro)); firsthop = (struct sockaddr_in6 *)&ro->ro_dst; bzero(firsthop, sizeof(*firsthop)); firsthop->sin6_family = AF_INET6; firsthop->sin6_len = sizeof(struct sockaddr_in6); firsthop->sin6_addr = ip6->ip6_dst; }#endif /* MIP6 */ dst = (struct sockaddr_in6 *)&ro->ro_dst;#ifdef IPSEC#ifdef __OpenBSD__ /* * Check if the packet needs encapsulation. * ipsp_process_packet will never come back to here. */ if (sproto != 0) { s = splnet(); /* fill in IPv6 header which would be filled later */ if (!IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { if (opt && opt->ip6po_hlim != -1) ip6->ip6_hlim = opt->ip6po_hlim & 0xff; } else { if (im6o != NULL) ip6->ip6_hlim = im6o->im6o_multicast_hlim; else ip6->ip6_hlim = ip6_defmcasthlim; if (opt && opt->ip6po_hlim != -1) ip6->ip6_hlim = opt->ip6po_hlim & 0xff; /* * XXX what should we do if ip6_hlim == 0 and the packet * gets tunnelled? */ } tdb = gettdb(sspi, &sdst, sproto); if (tdb == NULL) { splx(s); error = EHOSTUNREACH; m_freem(m); goto done; } /* Latch to PCB */ if (inp) tdb_add_inp(tdb, inp, 0); m->m_flags &= ~(M_BCAST | M_MCAST); /* just in case */ /* Callee frees mbuf */ error = ipsp_process_packet(m, tdb, AF_INET6, 0); splx(s); return error; /* Nothing more to be done */ }#else if (needipsec && needipsectun) { struct ipsec_output_state state; /* * All the extension headers will become inaccessible * (since they can be encrypted). * Don't panic, we need no more updates to extension headers * on inner IPv6 packet (since they are now encapsulated). * * IPv6 [ESP|AH] IPv6 [extension headers] payload */ bzero(&exthdrs, sizeof(exthdrs)); exthdrs.ip6e_ip6 = m; bzero(&state, sizeof(state)); state.m = m; state.ro = (struct route *)ro; state.dst = (struct sockaddr *)dst; error = ipsec6_output_tunnel(&state, sp, flags); m = state.m;#ifdef NEW_STRUCT_ROUTE ro = state.ro;#else ro = (struct route_in6 *)state.ro;#endif dst = (struct sockaddr_in6 *)state.dst; if (error) { /* mbuf is already reclaimed in ipsec6_output_tunnel. */ m0 = m = NULL; m = NULL; switch (error) { case EHOSTUNREACH: case ENETUNREACH: case EMSGSIZE: case ENOBUFS: case ENOMEM: break; default: printf("ip6_output (ipsec): error code %d\n", error); /* fall through */ case ENOENT: /* don't show these error codes to the user */ error = 0; break; } goto bad; } exthdrs.ip6e_ip6 = m; }#endif /* OpenBSD */#endif /* IPSEC */ /* if specified, fill in the traffic class field. */ if (opt) { ip6->ip6_flow &= ~htonl(0xff << 20); if (opt->ip6po_tclass >= 0) ip6->ip6_flow |= htonl((opt->ip6po_tclass & 0xff) << 20); } /* fill in or override the hop limit field, if necessary. */ if (opt && opt->ip6po_hlim != -1) ip6->ip6_hlim = opt->ip6po_hlim & 0xff; else if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { if (im6o != NULL) ip6->ip6_hlim = im6o->im6o_multicast_hlim; else ip6->ip6_hlim = ip6_defmcasthlim; } { /* * XXX: using a block just to define a local variables is not * a good style.... */ struct ifnet *ifp0 = NULL; struct sockaddr_in6 src; struct sockaddr_in6 dst0; int clone = 0; int64_t zone; /* * XXX: sockaddr_in6 for the destination should be passed * from the upper layer with a proper scope zone ID, in order * to make a copy here. */ bzero(&dst0, sizeof(dst0)); dst0.sin6_family = AF_INET6; dst0.sin6_len = sizeof(dst0); dst0.sin6_addr = ip6->ip6_dst;#ifdef SCOPEDROUTING /* XXX: in6_recoverscope will clear the embedded ID */ error = in6_recoverscope(&dst0, &dst0.sin6_addr, NULL); if (error != 0) { ip6stat.ip6s_badscope++; in6_ifstat_inc(ifp, ifs6_out_discard); goto bad; }#endif#if defined(__bsdi__) || defined(__FreeBSD__) if (ro != &ip6route && !IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) clone = 1;#endif if ((error = in6_selectroute(&dst0, opt, im6o, ro, &ifp, &rt, clone)) != 0) { switch (error) { case EHOSTUNREACH: ip6stat.ip6s_noroute++; break; case EADDRNOTAVAIL: default: break; /* XXX statistics? */ } if (ifp != NULL) in6_ifstat_inc(ifp, ifs6_out_discard); goto bad; } if (rt == NULL) { /* * If in6_selectroute() does not return a route entry, * dst may not have been updated. */ *dst = dst0; /* XXX */ } /* * then rt (for unicast) and ifp must be non-NULL valid values. */ if ((flags & IPV6_FORWARDING) == 0) { /* XXX: the FORWARDING flag can be set for mrouting. */ in6_ifstat_inc(ifp, ifs6_out_request); } if (rt != NULL) { ia = (struct in6_ifaddr *)(rt->rt_ifa); rt->rt_use++; } /* * The outgoing interface must be in the zone of source and * destination addresses. We should use ia_ifp to support the * case of sending packets to an address of our own. */ if (ia != NULL && ia->ia_ifp) ifp0 = ia->ia_ifp; else ifp0 = ifp; /* XXX: we should not do this conversion for every packet. */ bzero(&src, sizeof(src)); src.sin6_family = AF_INET6; src.sin6_len = sizeof(src); src.sin6_addr = ip6->ip6_src; if ((error = in6_recoverscope(&src, &ip6->ip6_src, NULL)) != 0) { goto badscope; } if ((zone = in6_addr2zoneid(ifp0, &src.sin6_addr)) < 0 || zone != src.sin6_scope_id) {#ifdef SCOPEDEBUG /* will be removed shortly */ printf("ip6 output: bad source scope %s for %s on %s\n", ip6_sprintf(&ip6->ip6_src), ip6_sprintf(&ip6->ip6_dst), if_name(ifp0));#endif
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?