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 + -
显示快捷键?