ip6_output.c
来自「eCos操作系统源码」· C语言 代码 · 共 2,527 行 · 第 1/5 页
C
2,527 行
//==========================================================================//// src/sys/netinet6/ip6_output.c////==========================================================================//####BSDCOPYRIGHTBEGIN####//// -------------------------------------------//// Portions of this software may have been derived from OpenBSD, // FreeBSD or other sources, and are covered by the appropriate// copyright disclaimers included herein.//// Portions created by Red Hat are// Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.//// -------------------------------------------////####BSDCOPYRIGHTEND####//==========================================================================/* $KAME: ip6_output.c,v 1.272 2001/12/26 01:03:28 jinmei Exp $ *//* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. *//* * Copyright (c) 1982, 1986, 1988, 1990, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)ip_output.c 8.3 (Berkeley) 1/21/94 */#include <sys/param.h>#include <sys/malloc.h>#include <sys/mbuf.h>#include <sys/errno.h>#include <sys/protosw.h>#include <sys/socket.h>#include <sys/socketvar.h>#include <net/if.h>#include <net/route.h>#include <netinet/in.h>#include <netinet/in_var.h>#include <netinet6/in6_var.h>#include <netinet/ip6.h>#include <netinet/icmp6.h>#include <netinet6/ip6_var.h>#include <netinet/in_pcb.h>#include <netinet6/nd6.h>#include <netinet6/ip6protosw.h>#include <netinet6/scope6_var.h>#ifdef IPSEC#ifdef __OpenBSD__#include <netinet/ip_ah.h>#include <netinet/ip_esp.h>#include <netinet/udp.h>#include <netinet/tcp.h>#include <net/pfkeyv2.h>extern u_int8_t get_sa_require __P((struct inpcb *));extern int ipsec_auth_default_level;extern int ipsec_esp_trans_default_level;extern int ipsec_esp_network_default_level;extern int ipsec_ipcomp_default_level;#else#include <netinet6/ipsec.h>#include <netkey/key.h>#endif#endif /* IPSEC */#if defined(IPV6FIREWALL) || (defined(__FreeBSD__) && __FreeBSD__ >= 4)#include <netinet6/ip6_fw.h>#endif#ifdef MIP6#include <sys/syslog.h>#include <netinet6/mip6.h>#endif /* MIP6 */struct ip6_exthdrs { struct mbuf *ip6e_ip6; struct mbuf *ip6e_hbh; struct mbuf *ip6e_dest1; struct mbuf *ip6e_rthdr; struct mbuf *ip6e_haddr; /* for MIP6 */ struct mbuf *ip6e_dest2;};static int ip6_pcbopt __P((int, u_char *, int, struct ip6_pktopts **, int));#if defined(__FreeBSD__) && __FreeBSD__ >= 3static int ip6_pcbopts __P((struct ip6_pktopts **, struct mbuf *, struct socket *, struct sockopt *));static int ip6_getpcbopt __P((struct ip6_pktopts *, int, struct sockopt *));#elsestatic int ip6_pcbopts __P((struct ip6_pktopts **, struct mbuf *, struct socket *));static int ip6_getpcbopt __P((struct ip6_pktopts *, int, struct mbuf **));#endifstatic int ip6_setpktoption __P((int, u_char *, int, struct ip6_pktopts *, int, int, int));static int ip6_setmoptions __P((int, struct ip6_moptions **, struct mbuf *));static int ip6_getmoptions __P((int, struct ip6_moptions *, struct mbuf **));static int ip6_copyexthdr __P((struct mbuf **, caddr_t, int));static int ip6_insertfraghdr __P((struct mbuf *, struct mbuf *, int, struct ip6_frag **));static int ip6_insert_jumboopt __P((struct ip6_exthdrs *, u_int32_t));static int ip6_splithdr __P((struct mbuf *, struct ip6_exthdrs *));#ifdef NEW_STRUCT_ROUTEstatic int ip6_getpmtu __P((struct route *, struct route *, struct ifnet *, struct in6_addr *, u_long *));#elsestatic int ip6_getpmtu __P((struct route *, struct route *, struct ifnet *, struct in6_addr *, u_long *));#endif#ifdef __bsdi__#if _BSDI_VERSION < 199802extern struct ifnet loif;#elseextern struct ifnet *loifp;#endif#endif#if defined(__NetBSD__)extern struct ifnet loif[NLOOP];#endif/* * IP6 output. The packet in mbuf chain m contains a skeletal IP6 * header (with pri, len, nxt, hlim, src, dst). * This function may modify ver and hlim only. * The mbuf chain containing the packet will be freed. * The mbuf opt, if present, will not be freed. * * type of "mtu": rt_rmx.rmx_mtu is u_long, ifnet.ifr_mtu is int, and * nd_ifinfo.linkmtu is u_int32_t. so we use u_long to hold largest one, * which is rt_rmx.rmx_mtu. */intip6_output(m0, opt, ro, flags, im6o, ifpp) struct mbuf *m0; struct ip6_pktopts *opt;#ifdef NEW_STRUCT_ROUTE struct route *ro;#else struct route_in6 *ro;#endif int flags; struct ip6_moptions *im6o; struct ifnet **ifpp; /* XXX: just for statistics */{ struct ip6_hdr *ip6, *mhip6; struct ifnet *ifp, *origifp; struct mbuf *m = m0; int hlen, tlen, len, off;#ifdef NEW_STRUCT_ROUTE struct route ip6route;#else struct route_in6 ip6route;#endif struct rtentry *rt = NULL; struct sockaddr_in6 *dst; int error = 0; struct in6_ifaddr *ia = NULL; u_long mtu; u_int32_t optlen = 0, plen = 0, unfragpartlen = 0; struct ip6_exthdrs exthdrs; struct in6_addr finaldst;#ifdef NEW_STRUCT_ROUTE struct route *ro_pmtu = NULL;#else struct route_in6 *ro_pmtu = NULL;#endif int hdrsplit = 0;#ifdef __OpenBSD__ u_int8_t sproto = 0;#else int needipsec = 0;#endif#if defined(__NetBSD__) && defined(PFIL_HOOKS) struct packet_filter_hook *pfh; struct mbuf *m1; int rv;#endif /* PFIL_HOOKS */#if defined(__bsdi__) && _BSDI_VERSION < 199802 struct ifnet *loifp = &loif;#endif#ifdef MIP6 struct mip6_pktopts mip6opt;#ifdef NEW_STRUCT_ROUTE struct route mip6_ip6route;#else struct route_in6 mip6_ip6route;#endif#endif /* MIP6 */#ifdef IPSEC#ifdef __OpenBSD__ struct m_tag *mtag; union sockaddr_union sdst; struct tdb_ident *tdbi; u_int32_t sspi; struct inpcb *inp; struct tdb *tdb; int s; inp = NULL; /* XXX */ if (inp && (inp->inp_flags & INP_IPV6) == 0) panic("ip6_output: IPv4 pcb is passed");#else int needipsectun = 0; struct socket *so; struct secpolicy *sp = NULL; /* for AH processing. stupid to have "socket" variable in IP layer... */ so = ipsec_getsocket(m); (void)ipsec_setsocket(m, NULL); ip6 = mtod(m, struct ip6_hdr *);#endif#endif /* IPSEC */#define MAKE_EXTHDR(hp, mp) \ do { \ if (hp) { \ struct ip6_ext *eh = (struct ip6_ext *)(hp); \ error = ip6_copyexthdr((mp), (caddr_t)(hp), \ ((eh)->ip6e_len + 1) << 3); \ if (error) \ goto freehdrs; \ } \ } while (0) bzero(&exthdrs, sizeof(exthdrs)); if (opt) { /* Hop-by-Hop options header */ MAKE_EXTHDR(opt->ip6po_hbh, &exthdrs.ip6e_hbh); /* Destination options header(1st part) */ if (opt->ip6po_rthdr) { /* * Destination options header(1st part) * This only makes sence with a routing header. * See Section 9.2 of * draft-ietf-ipngwg-rfc2292bis-02.txt. * Disabling this part just for MIP6 convenience is * a bad idea. We need to think carefully about a * way to make the advanced API coexist with MIP6 * options, which might automatically be inserted in * the kernel. */ MAKE_EXTHDR(opt->ip6po_dest1, &exthdrs.ip6e_dest1); } /* Routing header */ MAKE_EXTHDR(opt->ip6po_rthdr, &exthdrs.ip6e_rthdr); /* Destination options header(2nd part) */ MAKE_EXTHDR(opt->ip6po_dest2, &exthdrs.ip6e_dest2); }#ifdef MIP6 bzero((caddr_t)&mip6opt, sizeof(mip6opt)); if ((flags & IPV6_FORWARDING) == 0) { /* * XXX: reconsider the following routine. */ /* * MIP6 extention headers handling. * insert HA, BU, BA, BR options if necessary. */ if (mip6_exthdr_create(m, opt, &mip6opt)) goto freehdrs; if (((opt != NULL) && (opt->ip6po_rthdr != NULL)) || (mip6opt.mip6po_rthdr != NULL)) { m_freem(exthdrs.ip6e_rthdr); if (mip6opt.mip6po_rthdr != NULL) { /* * there is no rthdr specified in the * ip6_pktopts. but mip6 create a * rthdr for the router optimization * purpose. */ MAKE_EXTHDR(mip6opt.mip6po_rthdr, &exthdrs.ip6e_rthdr); } else { /* * there is a rthdr specified in the * ip6_pktopts. if mip6 require the * route optimization, the rthdr for * that purpose is already included in * the ip6po_rthdr in the * mip6_destopt_create(). */ MAKE_EXTHDR(opt->ip6po_rthdr, &exthdrs.ip6e_rthdr); } /* * if a routing header exists dest1 must be * inserted if it exists. */ if ((opt != NULL) && (opt->ip6po_dest1)) { m_freem(exthdrs.ip6e_dest1); MAKE_EXTHDR(opt->ip6po_dest1, &exthdrs.ip6e_dest1); } } MAKE_EXTHDR(mip6opt.mip6po_haddr, &exthdrs.ip6e_haddr); if (mip6opt.mip6po_dest2) { m_freem(exthdrs.ip6e_dest2); MAKE_EXTHDR(mip6opt.mip6po_dest2, &exthdrs.ip6e_dest2); } } else { /* * this is the forwarding packet. do not modify any * extension headers. */ }#endif /* MIP6 */#ifdef IPSEC#ifdef __OpenBSD__ /* * splnet is chosen over spltdb because we are not allowed to * lower the level, and udp6_output calls us in splnet(). XXX check */ s = splnet(); /* * Check if there was an outgoing SA bound to the flow * from a transport protocol. */ ip6 = mtod(m, struct ip6_hdr *); /* Do we have any pending SAs to apply ? */ mtag = m_tag_find(m, PACKET_TAG_IPSEC_PENDING_TDB, NULL); if (mtag != NULL) {#ifdef DIAGNOSTIC if (mtag->m_tag_len != sizeof (struct tdb_ident)) panic("ip6_output: tag of length %d (should be %d", mtag->m_tag_len, sizeof (struct tdb_ident));#endif tdbi = (struct tdb_ident *)(mtag + 1); tdb = gettdb(tdbi->spi, &tdbi->dst, tdbi->proto); if (tdb == NULL) error = -EINVAL; m_tag_delete(m, mtag); } else tdb = ipsp_spd_lookup(m, AF_INET6, sizeof(struct ip6_hdr), &error, IPSP_DIRECTION_OUT, NULL, inp); if (tdb == NULL) { splx(s); if (error == 0) { /* * No IPsec processing required, we'll just send the * packet out. */ sproto = 0; /* Fall through to routing/multicast handling */ } else { /* * -EINVAL is used to indicate that the packet should * be silently dropped, typically because we've asked * key management for an SA. */ if (error == -EINVAL) /* Should silently drop packet */ error = 0; goto freehdrs; } } else { /* Loop detection */ for (mtag = m_tag_first(m); mtag != NULL; mtag = m_tag_next(m, mtag)) { if (mtag->m_tag_id != PACKET_TAG_IPSEC_OUT_DONE && mtag->m_tag_id != PACKET_TAG_IPSEC_OUT_CRYPTO_NEEDED) continue; tdbi = (struct tdb_ident *)(mtag + 1); if (tdbi->spi == tdb->tdb_spi && tdbi->proto == tdb->tdb_sproto && !bcmp(&tdbi->dst, &tdb->tdb_dst, sizeof(union sockaddr_union))) { splx(s); sproto = 0; /* mark as no-IPsec-needed */ goto done_spd; } } /* We need to do IPsec */ bcopy(&tdb->tdb_dst, &sdst, sizeof(sdst)); sspi = tdb->tdb_spi; sproto = tdb->tdb_sproto; splx(s);#if 1 /* XXX */ /* if we have any extension header, we cannot perform IPsec */ if (exthdrs.ip6e_hbh || exthdrs.ip6e_dest1 ||#ifdef MIP6 exthdrs.ip6e_haddr ||#endif /* MIP6 */ exthdrs.ip6e_rthdr || exthdrs.ip6e_dest2) { error = EHOSTUNREACH; goto freehdrs; }#endif } /* Fall through to the routing/multicast handling code */ done_spd:#else /* get a security policy for this packet */ if (so == NULL) sp = ipsec6_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND, 0, &error); else sp = ipsec6_getpolicybysock(m, IPSEC_DIR_OUTBOUND, so, &error); if (sp == NULL) { ipsec6stat.out_inval++; goto freehdrs; } error = 0; /* check policy */ switch (sp->policy) { case IPSEC_POLICY_DISCARD: /* * This packet is just discarded. */ ipsec6stat.out_polvio++; goto freehdrs; case IPSEC_POLICY_BYPASS: case IPSEC_POLICY_NONE: /* no need to do IPsec. */ needipsec = 0; break; case IPSEC_POLICY_IPSEC: if (sp->req == NULL) { /* acquire a policy */ error = key_spdacquire(sp); goto freehdrs; } needipsec = 1; break;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?