ip_input.c

来自「eCos操作系统源码」· C语言 代码 · 共 1,992 行 · 第 1/4 页

C
1,992
字号
/* * Save incoming source route for use in replies, * to be picked up later by ip_srcroute if the receiver is interested. */voidsave_rte(option, dst)	u_char *option;	struct in_addr dst;{	unsigned olen;	olen = option[IPOPT_OLEN];#ifdef DIAGNOSTIC	if (ipprintfs)		printf("save_rte: olen %d\n", olen);#endif	if (olen > sizeof(ip_srcrt) - (1 + sizeof(dst)))		return;	bcopy(option, ip_srcrt.srcopt, olen);	ip_nhops = (olen - IPOPT_OFFSET - 1) / sizeof(struct in_addr);	ip_srcrt.dst = dst;}/* * Retrieve incoming source route for use in replies, * in the same form used by setsockopt. * The first hop is placed before the options, will be removed later. */struct mbuf *ip_srcroute(){	register struct in_addr *p, *q;	register struct mbuf *m;	if (ip_nhops == 0)		return ((struct mbuf *)0);	m = m_get(M_DONTWAIT, MT_HEADER);	if (m == 0)		return ((struct mbuf *)0);#define OPTSIZ	(sizeof(ip_srcrt.nop) + sizeof(ip_srcrt.srcopt))	/* length is (nhops+1)*sizeof(addr) + sizeof(nop + srcrt header) */	m->m_len = ip_nhops * sizeof(struct in_addr) + sizeof(struct in_addr) +	    OPTSIZ;#ifdef DIAGNOSTIC	if (ipprintfs)		printf("ip_srcroute: nhops %d mlen %d", ip_nhops, m->m_len);#endif	/*	 * First save first hop for return route	 */	p = &ip_srcrt.route[ip_nhops - 1];	*(mtod(m, struct in_addr *)) = *p--;#ifdef DIAGNOSTIC	if (ipprintfs)		printf(" hops %lx", (u_long)ntohl(mtod(m, struct in_addr *)->s_addr));#endif	/*	 * Copy option fields and padding (nop) to mbuf.	 */	ip_srcrt.nop = IPOPT_NOP;	ip_srcrt.srcopt[IPOPT_OFFSET] = IPOPT_MINOFF;	(void)memcpy(mtod(m, caddr_t) + sizeof(struct in_addr),	    &ip_srcrt.nop, OPTSIZ);	q = (struct in_addr *)(mtod(m, caddr_t) +	    sizeof(struct in_addr) + OPTSIZ);#undef OPTSIZ	/*	 * Record return path as an IP source route,	 * reversing the path (pointers are now aligned).	 */	while (p >= ip_srcrt.route) {#ifdef DIAGNOSTIC		if (ipprintfs)			printf(" %lx", (u_long)ntohl(q->s_addr));#endif		*q++ = *p--;	}	/*	 * Last hop goes to final destination.	 */	*q = ip_srcrt.dst;#ifdef DIAGNOSTIC	if (ipprintfs)		printf(" %lx\n", (u_long)ntohl(q->s_addr));#endif	return (m);}/* * Strip out IP options, at higher * level protocol in the kernel. * Second argument is buffer to which options * will be moved, and return value is their length. * XXX should be deleted; last arg currently ignored. */voidip_stripoptions(m, mopt)	register struct mbuf *m;	struct mbuf *mopt;{	register int i;	struct ip *ip = mtod(m, struct ip *);	register caddr_t opts;	int olen;	olen = (IP_VHL_HL(ip->ip_vhl) << 2) - sizeof (struct ip);	opts = (caddr_t)(ip + 1);	i = m->m_len - (sizeof (struct ip) + olen);	bcopy(opts + olen, opts, (unsigned)i);	m->m_len -= olen;	if (m->m_flags & M_PKTHDR)		m->m_pkthdr.len -= olen;	ip->ip_vhl = IP_MAKE_VHL(IPVERSION, sizeof(struct ip) >> 2);}int inetctlerrmap[PRC_NCMDS] = {	0,		0,		0,		0,	0,		EMSGSIZE,	EHOSTDOWN,	EHOSTUNREACH,	EHOSTUNREACH,	EHOSTUNREACH,	ECONNREFUSED,	ECONNREFUSED,	EMSGSIZE,	EHOSTUNREACH,	0,		0,	0,		0,		0,		0,	ENOPROTOOPT,	ECONNREFUSED};/* * Forward a packet.  If some error occurs return the sender * an icmp packet.  Note we can't always generate a meaningful * icmp message because icmp doesn't have a large enough repertoire * of codes and types. * * If not forwarding, just drop the packet.  This could be confusing * if ipforwarding was zero but some routing protocol was advancing * us as a gateway to somewhere.  However, we must let the routing * protocol deal with that. * * The srcrt parameter indicates whether the packet is being forwarded * via a source route. */#ifdef NATPTvoid#elsestatic void#endifip_forward(m, srcrt)	struct mbuf *m;	int srcrt;{	register struct ip *ip = mtod(m, struct ip *);	register struct sockaddr_in *sin;	register struct rtentry *rt;	int error, type = 0, code = 0;	struct mbuf *mcopy;	n_long dest;	struct ifnet *destifp;#ifdef IPSEC	struct ifnet dummyifp;#endif	dest = 0;#ifdef DIAGNOSTIC	if (ipprintfs)		printf("forward: src %lx dst %lx ttl %x\n",		    (u_long)ip->ip_src.s_addr, (u_long)ip->ip_dst.s_addr,		    ip->ip_ttl);#endif	if (m->m_flags & (M_BCAST|M_MCAST) || in_canforward(ip->ip_dst) == 0) {		ipstat.ips_cantforward++;		m_freem(m);		return;	}#ifdef IPSTEALTH	if (!ipstealth) {#endif		if (ip->ip_ttl <= IPTTLDEC) {			icmp_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS,			    dest, 0);			return;		}#ifdef IPSTEALTH	}#endif	sin = (struct sockaddr_in *)&ipforward_rt.ro_dst;	if ((rt = ipforward_rt.ro_rt) == 0 ||	    ip->ip_dst.s_addr != sin->sin_addr.s_addr) {		if (ipforward_rt.ro_rt) {			RTFREE(ipforward_rt.ro_rt);			ipforward_rt.ro_rt = 0;		}		sin->sin_family = AF_INET;		sin->sin_len = sizeof(*sin);		sin->sin_addr = ip->ip_dst;		rtalloc_ign(&ipforward_rt, RTF_PRCLONING);		if (ipforward_rt.ro_rt == 0) {			icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, dest, 0);			return;		}		rt = ipforward_rt.ro_rt;	}	/*	 * Save the IP header and at most 8 bytes of the payload,	 * in case we need to generate an ICMP message to the src.	 *	 * We don't use m_copy() because it might return a reference	 * to a shared cluster. Both this function and ip_output()	 * assume exclusive access to the IP header in `m', so any	 * data in a cluster may change before we reach icmp_error().	 */	MGET(mcopy, M_DONTWAIT, m->m_type);	if (mcopy != NULL) {		M_COPY_PKTHDR(mcopy, m);		mcopy->m_len = imin((IP_VHL_HL(ip->ip_vhl) << 2) + 8,		    (int)ip->ip_len);		m_copydata(m, 0, mcopy->m_len, mtod(mcopy, caddr_t));	}#ifdef IPSTEALTH	if (!ipstealth) {#endif		ip->ip_ttl -= IPTTLDEC;#ifdef IPSTEALTH	}#endif	/*	 * If forwarding packet using same interface that it came in on,	 * perhaps should send a redirect to sender to shortcut a hop.	 * Only send redirect if source is sending directly to us,	 * and if packet was not source routed (or has any options).	 * Also, don't send redirect if forwarding using a default route	 * or a route modified by a redirect.	 */#define	satosin(sa)	((struct sockaddr_in *)(sa))	if (rt->rt_ifp == m->m_pkthdr.rcvif &&	    (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0 &&	    satosin(rt_key(rt))->sin_addr.s_addr != 0 &&	    ipsendredirects && !srcrt) {#define	RTA(rt)	((struct in_ifaddr *)(rt->rt_ifa))		u_long src = ntohl(ip->ip_src.s_addr);		if (RTA(rt) &&		    (src & RTA(rt)->ia_subnetmask) == RTA(rt)->ia_subnet) {		    if (rt->rt_flags & RTF_GATEWAY)			dest = satosin(rt->rt_gateway)->sin_addr.s_addr;		    else			dest = ip->ip_dst.s_addr;		    /* Router requirements says to only send host redirects */		    type = ICMP_REDIRECT;		    code = ICMP_REDIRECT_HOST;#ifdef DIAGNOSTIC		    if (ipprintfs)		        printf("redirect (%d) to %lx\n", code, (u_long)dest);#endif		}	}	error = ip_output(m, (struct mbuf *)0, &ipforward_rt, 			  IP_FORWARDING, 0);	if (error)		ipstat.ips_cantforward++;	else {		ipstat.ips_forward++;		if (type)			ipstat.ips_redirectsent++;		else {			if (mcopy) {				ipflow_create(&ipforward_rt, mcopy);				m_freem(mcopy);			}			return;		}	}	if (mcopy == NULL)		return;	destifp = NULL;	switch (error) {	case 0:				/* forwarded, but need redirect */		/* type, code set above */		break;	case ENETUNREACH:		/* shouldn't happen, checked above */	case EHOSTUNREACH:	case ENETDOWN:	case EHOSTDOWN:	default:		type = ICMP_UNREACH;		code = ICMP_UNREACH_HOST;		break;	case EMSGSIZE:		type = ICMP_UNREACH;		code = ICMP_UNREACH_NEEDFRAG;#ifndef IPSEC		if (ipforward_rt.ro_rt)			destifp = ipforward_rt.ro_rt->rt_ifp;#else		/*		 * If the packet is routed over IPsec tunnel, tell the		 * originator the tunnel MTU.		 *	tunnel MTU = if MTU - sizeof(IP) - ESP/AH hdrsiz		 * XXX quickhack!!!		 */		if (ipforward_rt.ro_rt) {			struct secpolicy *sp = NULL;			int ipsecerror;			int ipsechdr;			struct route *ro;			sp = ipsec4_getpolicybyaddr(mcopy,						    IPSEC_DIR_OUTBOUND,			                            IP_FORWARDING,			                            &ipsecerror);			if (sp == NULL)				destifp = ipforward_rt.ro_rt->rt_ifp;			else {				/* count IPsec header size */				ipsechdr = ipsec4_hdrsiz(mcopy,							 IPSEC_DIR_OUTBOUND,							 NULL);				/*				 * find the correct route for outer IPv4				 * header, compute tunnel MTU.				 *				 * XXX BUG ALERT				 * The "dummyifp" code relies upon the fact				 * that icmp_error() touches only ifp->if_mtu.				 */				/*XXX*/				destifp = NULL;				if (sp->req != NULL				 && sp->req->sav != NULL				 && sp->req->sav->sah != NULL) {					ro = &sp->req->sav->sah->sa_route;					if (ro->ro_rt && ro->ro_rt->rt_ifp) {						dummyifp.if_mtu =						    ro->ro_rt->rt_ifp->if_mtu;						dummyifp.if_mtu -= ipsechdr;						destifp = &dummyifp;					}				}				key_freesp(sp);			}		}#endif /*IPSEC*/		ipstat.ips_cantfrag++;		break;	case ENOBUFS:#ifdef ALTQ		/*		 * don't generate ICMP_SOURCEQUENCH		 * (RFC1812 Requirements for IP Version 4 Routers)		 */		if (mcopy)			m_freem(mcopy);		return;#else		type = ICMP_SOURCEQUENCH;		code = 0;		break;#endif	case EACCES:			/* ipfw denied packet */		m_freem(mcopy);		return;	}	icmp_error(mcopy, type, code, dest, destifp);}voidip_savecontrol(inp, mp, ip, m)	register struct inpcb *inp;	register struct mbuf **mp;	register struct ip *ip;	register struct mbuf *m;{	if (inp->inp_socket->so_options & SO_TIMESTAMP) {		struct timeval tv;		microtime(&tv);		*mp = sbcreatecontrol((caddr_t) &tv, sizeof(tv),			SCM_TIMESTAMP, SOL_SOCKET);		if (*mp)			mp = &(*mp)->m_next;	}	if (inp->inp_flags & INP_RECVDSTADDR) {		*mp = sbcreatecontrol((caddr_t) &ip->ip_dst,		    sizeof(struct in_addr), IP_RECVDSTADDR, IPPROTO_IP);		if (*mp)			mp = &(*mp)->m_next;	}#ifdef notyet	/* XXX	 * Moving these out of udp_input() made them even more broken	 * than they already were.	 */	/* options were tossed already */	if (inp->inp_flags & INP_RECVOPTS) {		*mp = sbcreatecontrol((caddr_t) opts_deleted_above,		    sizeof(struct in_addr), IP_RECVOPTS, IPPROTO_IP);		if (*mp)			mp = &(*mp)->m_next;	}	/* ip_srcroute doesn't do what we want here, need to fix */	if (inp->inp_flags & INP_RECVRETOPTS) {		*mp = sbcreatecontrol((caddr_t) ip_srcroute(),		    sizeof(struct in_addr), IP_RECVRETOPTS, IPPROTO_IP);		if (*mp)			mp = &(*mp)->m_next;	}#endif	if (inp->inp_flags & INP_RECVIF) {		struct ifnet *ifp;		struct sdlbuf {			struct sockaddr_dl sdl;			u_char	pad[32];		} sdlbuf;		struct sockaddr_dl *sdp;		struct sockaddr_dl *sdl2 = &sdlbuf.sdl;		if (((ifp = m->m_pkthdr.rcvif)) 		&& ( ifp->if_index && (ifp->if_index <= if_index))) {			sdp = (struct sockaddr_dl *)(ifnet_addrs					[ifp->if_index - 1]->ifa_addr);			/*			 * Change our mind and don't try copy.			 */			if ((sdp->sdl_family != AF_LINK)			|| (sdp->sdl_len > sizeof(sdlbuf))) {				goto makedummy;			}			bcopy(sdp, sdl2, sdp->sdl_len);		} else {makedummy:				sdl2->sdl_len				= offsetof(struct sockaddr_dl, sdl_data[0]);			sdl2->sdl_family = AF_LINK;			sdl2->sdl_index = 0;			sdl2->sdl_nlen = sdl2->sdl_alen = sdl2->sdl_slen = 0;		}		*mp = sbcreatecontrol((caddr_t) sdl2, sdl2->sdl_len,			IP_RECVIF, IPPROTO_IP);		if (*mp)			mp = &(*mp)->m_next;	}}intip_rsvp_init(struct socket *so){	if (so->so_type != SOCK_RAW ||	    so->so_proto->pr_protocol != IPPROTO_RSVP)	  return EOPNOTSUPP;	if (ip_rsvpd != NULL)	  return EADDRINUSE;	ip_rsvpd = so;	/*	 * This may seem silly, but we need to be sure we don't over-increment	 * the RSVP counter, in case something slips up.	 */	if (!ip_rsvp_on) {		ip_rsvp_on = 1;		rsvp_on++;	}	return 0;}intip_rsvp_done(void){	ip_rsvpd = NULL;	/*	 * This may seem silly, but we need to be sure we don't over-decrement	 * the RSVP counter, in case something slips up.	 */	if (ip_rsvp_on) {		ip_rsvp_on = 0;		rsvp_on--;	}	return 0;}

⌨️ 快捷键说明

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