⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ip_output.c

📁 MIPS处理器的bootloader,龙芯就是用的修改过的PMON2
💻 C
📖 第 1 页 / 共 3 页
字号:
/*	$OpenBSD: ip_output.c,v 1.49 1999/07/15 14:15:41 niklas Exp $	*//*	$NetBSD: ip_output.c,v 1.28 1996/02/13 23:43:07 christos Exp $	*//* * 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 <sys/systm.h>#include <sys/kernel.h>#include <sys/proc.h>#include <net/if.h>#include <net/route.h>#include <netinet/in.h>#include <netinet/in_systm.h>#include <netinet/ip.h>#include <netinet/in_pcb.h>#include <netinet/in_var.h>#include <netinet/ip_var.h>#ifdef vax#include <machine/mtpr.h>#endif#include <machine/stdarg.h>#ifdef IPSEC#include <netinet/ip_ah.h>#include <netinet/ip_esp.h>#include <netinet/udp.h>#include <netinet/tcp.h>#ifdef ENCDEBUG#define DPRINTF(x)	if (encdebug) printf x#else#define DPRINTF(x)#endifextern u_int8_t get_sa_require  __P((struct inpcb *));#endifstatic struct mbuf *ip_insertoptions __P((struct mbuf *, struct mbuf *, int *));static void ip_mloopback	__P((struct ifnet *, struct mbuf *, struct sockaddr_in *));#if defined(IPFILTER) || defined(IPFILTER_LKM)int (*fr_checkp) __P((struct ip *, int, struct ifnet *, int, struct mbuf **));#endif#ifdef IPSECextern int ipsec_auth_default_level;extern int ipsec_esp_trans_default_level;extern int ipsec_esp_network_default_level;extern int pfkeyv2_acquire(struct tdb *, int);#endif/* * IP output.  The packet in mbuf chain m contains a skeletal IP * header (with len, off, ttl, proto, tos, src, dst). * The mbuf chain containing the packet will be freed. * The mbuf opt, if present, will not be freed. */int#if __STDC__ip_output(struct mbuf *m0, ...)#elseip_output(m0, va_alist)	struct mbuf *m0;	va_dcl#endif{	register struct ip *ip, *mhip;	register struct ifnet *ifp;	register struct mbuf *m = m0;	register int hlen = sizeof (struct ip);	int len, off, error = 0;	struct route iproute;	struct sockaddr_in *dst;	struct in_ifaddr *ia;	struct mbuf *opt;	struct route *ro;	int flags;	struct ip_moptions *imo;	va_list ap;#ifdef IPSEC	union sockaddr_union sunion;	struct mbuf *mp;	struct udphdr *udp;	struct tcphdr *tcp;	struct inpcb *inp;#endif	va_start(ap, m0);	opt = va_arg(ap, struct mbuf *);	ro = va_arg(ap, struct route *);	flags = va_arg(ap, int);	imo = va_arg(ap, struct ip_moptions *);#ifdef IPSEC	inp = va_arg(ap, struct inpcb *);#endif	va_end(ap);#ifdef	DIAGNOSTIC	if ((m->m_flags & M_PKTHDR) == 0)		panic("ip_output no HDR");#endif	if (opt) {		m = ip_insertoptions(m, opt, &len);		hlen = len;	}	ip = mtod(m, struct ip *);	/*	 * Fill in IP header.	 */	if ((flags & (IP_FORWARDING|IP_RAWOUTPUT)) == 0) {		ip->ip_v = IPVERSION;		ip->ip_off &= IP_DF;		ip->ip_id = ip_randomid();		HTONS(ip->ip_id);		ip->ip_hl = hlen >> 2;		ipstat.ips_localout++;	} else {		hlen = ip->ip_hl << 2;	}#ifdef IPSEC	/*	 * Check if the packet needs encapsulation	 */	if (!(flags & IP_ENCAPSULATED) &&	    (inp == NULL || 	     inp->inp_seclevel[SL_AUTH] != IPSEC_LEVEL_BYPASS ||	     inp->inp_seclevel[SL_ESP_TRANS] != IPSEC_LEVEL_BYPASS ||	     inp->inp_seclevel[SL_ESP_NETWORK] != IPSEC_LEVEL_BYPASS)) {		struct route_enc re0, *re = &re0;		struct sockaddr_encap *ddst, *gw;		struct tdb *tdb, *t;		int s;		u_int8_t sa_require, sa_have = 0;		if (inp == NULL)			sa_require = get_sa_require(inp);		else			sa_require = inp->inp_secrequire;		bzero((caddr_t) re, sizeof(*re));		/*		 * splnet is chosen over spltdb because we are not allowed to		 * lower the level, and udp_output calls us in splnet().		 */		s = splnet();		/* Check if there was a bound outgoing SA */		if (inp && inp->inp_tdb &&		    (inp->inp_tdb->tdb_dst.sin.sin_addr.s_addr ==		     INADDR_ANY ||		     !bcmp(&inp->inp_tdb->tdb_dst.sin.sin_addr,			   &ip->ip_dst, sizeof(ip->ip_dst)))) {			tdb = inp->inp_tdb;			goto have_tdb;		}		if (!ipsec_in_use) {			splx(s);			goto no_encap;		}		ddst = (struct sockaddr_encap *) &re->re_dst;		ddst->sen_family = PF_KEY;		ddst->sen_len = SENT_IP4_LEN;		ddst->sen_type = SENT_IP4;		ddst->sen_ip_src = ip->ip_src;		ddst->sen_ip_dst = ip->ip_dst;		ddst->sen_proto = ip->ip_p;		switch (ip->ip_p) {		case IPPROTO_UDP:			if (m->m_len < hlen + 2 * sizeof(u_int16_t)) {				if ((m = m_pullup(m, hlen + 2 *				    sizeof(u_int16_t))) == 0)					return ENOBUFS;				ip = mtod(m, struct ip *);			}			udp = (struct udphdr *) (mtod(m, u_char *) + hlen);			ddst->sen_sport = ntohs(udp->uh_sport);			ddst->sen_dport = ntohs(udp->uh_dport);			break;		case IPPROTO_TCP:			if (m->m_len < hlen + 2 * sizeof(u_int16_t)) {				if ((m = m_pullup(m, hlen + 2 *				    sizeof(u_int16_t))) == 0)					return ENOBUFS;				ip = mtod(m, struct ip *);			}			tcp = (struct tcphdr *) (mtod(m, u_char *) + hlen);			ddst->sen_sport = ntohs(tcp->th_sport);			ddst->sen_dport = ntohs(tcp->th_dport);			break;		default:			ddst->sen_sport = 0;			ddst->sen_dport = 0;		}		rtalloc((struct route *) re);		if (re->re_rt == NULL) {			splx(s);			goto no_encap;		}		gw = (struct sockaddr_encap *) (re->re_rt->rt_gateway);		/*		 * There might be a specific route, that tells us to avoid		 * doing IPsec; this is useful for specific routes that we		 * don't want to have IPsec applied on.		 */		if ((gw != NULL) && (gw->sen_ipsp_dst.s_addr == 0) &&		    (gw->sen_ipsp_sproto == 0) && (gw->sen_ipsp_spi == 0)) {			splx(s);			goto no_encap;		}		if (gw == NULL || gw->sen_type != SENT_IPSP) {			splx(s);		        DPRINTF(("ip_output(): no gw or gw data not IPSP\n"));			if (re->re_rt)				RTFREE(re->re_rt);			error = EHOSTUNREACH;			m_freem(m);			goto done;		}		/* 		 * For VPNs a route with a reserved SPI of 0 is used to		 * indicate the need for an SA when none is established.		 */		if (ntohl(gw->sen_ipsp_spi) == SPI_LOCAL_USE) {			bzero(&sunion, sizeof(sunion));			sunion.sin.sin_family = AF_INET;			sunion.sin.sin_len = sizeof(struct sockaddr_in);			sunion.sin.sin_addr = gw->sen_ipsp_dst;			tdb = (struct tdb *) gettdb(gw->sen_ipsp_spi, &sunion,						    gw->sen_ipsp_sproto);			if (tdb)			{			    if (tdb->tdb_authalgxform)			      sa_require = NOTIFY_SATYPE_AUTH;			    if (tdb->tdb_encalgxform)			      sa_require |= NOTIFY_SATYPE_CONF;			    if (tdb->tdb_flags & TDBF_TUNNELING)			      sa_require |= NOTIFY_SATYPE_TUNNEL;			}			else /* No TDB found */			{			    /*			     * XXX We should construct a TDB from system			     * default (which should be tunable via sysctl).			     * For now, drop packet and ignore SPD entry.			     */			    goto no_encap;			}			/* PF_KEYv2 notification message */			pfkeyv2_acquire(tdb, 0); /* XXX Check for errors */			splx(s);			/* 			 * When sa_require is set, the packet will be dropped			 * at no_encap.			 */			goto no_encap;		}		/*		 * At this point we have an IPSP "gateway" (tunnel) spec.		 * Use the destination of the tunnel and the SPI to		 * look up the necessary Tunnel Control Block. Look it up,		 * and then pass it, along with the packet and the gw,		 * to the appropriate transformation.		 */		bzero(&sunion, sizeof(sunion));		sunion.sin.sin_family = AF_INET;		sunion.sin.sin_len = sizeof(struct sockaddr_in);		sunion.sin.sin_addr = gw->sen_ipsp_dst;		tdb = (struct tdb *) gettdb(gw->sen_ipsp_spi, &sunion,					    gw->sen_ipsp_sproto);	      have_tdb:		ip->ip_len = htons((u_short)ip->ip_len);		ip->ip_off = htons((u_short)ip->ip_off);		ip->ip_sum = 0;		/*		 * Now we check if this tdb has all the transforms which		 * are requried by the socket or our default policy.		 */		SPI_CHAIN_ATTRIB(sa_have, tdb_onext, tdb);		if (sa_require & ~sa_have)			goto no_encap;		if (tdb == NULL) {			splx(s);		        DPRINTF(("ip_output(): non-existant TDB for SA %s/%08x/%u\n", inet_ntoa4(gw->sen_ipsp_dst), ntohl(gw->sen_ipsp_spi), gw->sen_ipsp_sproto));			if (re->re_rt)                        	RTFREE(re->re_rt);			error = EHOSTUNREACH;			m_freem(m);			goto done;		}		for (t = tdb; t != NULL; t = t->tdb_onext)		    if ((t->tdb_sproto == IPPROTO_ESP && !esp_enable) ||			(t->tdb_sproto == IPPROTO_AH && !ah_enable)) {		        DPRINTF(("ip_output(): IPSec outbound packet dropped due to policy\n"));			if (re->re_rt)                        	RTFREE(re->re_rt);			error = EHOSTUNREACH;			m_freem(m);			goto done;		    }		/* Fix the ip_src field if necessary */		if (ip->ip_src.s_addr == INADDR_ANY) {		    if (tdb && tdb->tdb_src.sin.sin_addr.s_addr != 0 &&			tdb->tdb_src.sa.sa_family == AF_INET)		      ip->ip_src = tdb->tdb_src.sin.sin_addr;		    else		    {			if (ro == 0) {			    ro = &iproute;			    bzero((caddr_t)ro, sizeof (*ro));			}			dst = satosin(&ro->ro_dst);			/*			 * If there is a cached route,			 * check that it is to the same destination			 * and is still up.  If not, free it and try again.			 */			if (ro->ro_rt &&			    ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||			     dst->sin_addr.s_addr != ip->ip_dst.s_addr)) {			    RTFREE(ro->ro_rt);			    ro->ro_rt = (struct rtentry *)0;			}			if (ro->ro_rt == 0) {			    dst->sin_family = AF_INET;			    dst->sin_len = sizeof(*dst);			    dst->sin_addr = ip->ip_dst;			    rtalloc(ro);			}						if (ro->ro_rt == 0) {			    splx(s);			    ipstat.ips_noroute++;			    error = EHOSTUNREACH;			    m_freem(m);			    goto done;			}						ia = ifatoia(ro->ro_rt->rt_ifa);			ro->ro_rt->rt_use++;			ip->ip_src = ia->ia_addr.sin_addr;		    }		}		while (tdb && tdb->tdb_xform) {			/* Check if the SPI is invalid */			if (tdb->tdb_flags & TDBF_INVALID) {				splx(s);			        DPRINTF(("ip_output(): attempt to use invalid SA %s/%08x/%u\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi), tdb->tdb_sproto));				m_freem(m);				if (re->re_rt)					RTFREE(re->re_rt);				return ENXIO;			}			/* Register first use, setup expiration timer */			if (tdb->tdb_first_use == 0) {				tdb->tdb_first_use = time.tv_sec;				tdb_expiration(tdb, TDBEXP_TIMEOUT);			}    			/* Check for tunneling */			if (((tdb->tdb_dst.sin.sin_addr.s_addr !=			      INADDR_ANY &&			      tdb->tdb_dst.sin.sin_addr.s_addr !=			      ip->ip_dst.s_addr) ||			     (tdb->tdb_flags & TDBF_TUNNELING)) &&			     (tdb->tdb_xform->xf_type != XF_IP4))			{			        DPRINTF(("ip_output(): tunneling\n"));				/*				 * Fix checksum here, AH and ESP fix the				 * checksum in their output routines.				 */				ip->ip_sum = in_cksum(m, hlen);				error = ipe4_output(m, gw, tdb, &mp);				if (mp == NULL)					error = EFAULT;				if (error) {					splx(s);					if (re->re_rt)						RTFREE(re->re_rt);					return error;				}				m = mp;			}			if (tdb->tdb_xform->xf_type == XF_IP4) {				/*				 * Fix checksum if IP-IP; AH and ESP fix the				 * IP header checksum in their 				 * output routines.				 */			        ip = mtod(m, struct ip *);				ip->ip_sum = in_cksum(m, hlen);			}			error = (*(tdb->tdb_xform->xf_output))(m, gw,			    tdb, &mp);			if (!error && mp == NULL)				error = EFAULT;			if (error) {				splx(s);				if (mp != NULL)					m_freem(mp);				if (re->re_rt)					RTFREE(re->re_rt);				return error;			}			m = mp;			ip = mtod(m, struct ip *);			if (tdb->tdb_xform->xf_type == XF_IP4)			  ip->ip_sum = in_cksum(m, ip->ip_hl << 2);			tdb = tdb->tdb_onext;		}		splx(s);		/*		 * At this point, m is pointing to an mbuf chain with the		 * processed packet. Call ourselves recursively, but		 * bypass the encap code.		 */		if (re->re_rt)			RTFREE(re->re_rt);		ip = mtod(m, struct ip *);		NTOHS(ip->ip_len);		NTOHS(ip->ip_off);		return ip_output(m, NULL, NULL,		    IP_ENCAPSULATED | IP_RAWOUTPUT, NULL, NULL);no_encap:		/* This is for possible future use, don't move or delete */		if (re->re_rt)			RTFREE(re->re_rt);		/* No IPSec processing though it was required, drop packet */		if (sa_require) {			error = EHOSTUNREACH;			m_freem(m);			goto done;		}	}#endif /* IPSEC */	/*	 * Route packet.	 */	if (ro == 0) {		ro = &iproute;		bzero((caddr_t)ro, sizeof (*ro));	}	dst = satosin(&ro->ro_dst);	/*	 * If there is a cached route,	 * check that it is to the same destination	 * and is still up.  If not, free it and try again.	 */	if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||	    dst->sin_addr.s_addr != ip->ip_dst.s_addr)) {		RTFREE(ro->ro_rt);		ro->ro_rt = (struct rtentry *)0;	}	if (ro->ro_rt == 0) {		dst->sin_family = AF_INET;		dst->sin_len = sizeof(*dst);		dst->sin_addr = ip->ip_dst;	}	/*	 * If routing to interface only,	 * short circuit routing lookup.	 */	if (flags & IP_ROUTETOIF) {		if ((ia = ifatoia(ifa_ifwithdstaddr(sintosa(dst)))) == 0 &&		    (ia = ifatoia(ifa_ifwithnet(sintosa(dst)))) == 0 &&		    (ia = ifatoia(ifa_ifwithaddr(sintosa(dst)))) == 0 ) {			ipstat.ips_noroute++;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -