示例#1
0
static void
fib4_rte_to_nh_extended(struct rtentry *rte, struct in_addr dst,
    uint32_t flags, struct nhop4_extended *pnh4)
{
	struct sockaddr_in *gw;
	struct in_ifaddr *ia;

	if ((flags & NHR_IFAIF) != 0)
		pnh4->nh_ifp = rte->rt_ifa->ifa_ifp;
	else
		pnh4->nh_ifp = rte->rt_ifp;
	pnh4->nh_mtu = min(rte->rt_mtu, rte->rt_ifp->if_mtu);
	if (rte->rt_flags & RTF_GATEWAY) {
		gw = (struct sockaddr_in *)rte->rt_gateway;
		pnh4->nh_addr = gw->sin_addr;
	} else
		pnh4->nh_addr = dst;
	/* Set flags */
	pnh4->nh_flags = fib_rte_to_nh_flags(rte->rt_flags);
	gw = (struct sockaddr_in *)rt_key(rte);
	if (gw->sin_addr.s_addr == 0)
		pnh4->nh_flags |= NHF_DEFAULT;
	/* XXX: Set RTF_BROADCAST if GW address is broadcast */

	ia = ifatoia(rte->rt_ifa);
	pnh4->nh_src = IA_SIN(ia)->sin_addr;
}
示例#2
0
文件: igmp.c 项目: AoLaD/rtems
void
igmp_input(struct mbuf *m, int iphlen)
{
	register struct igmp *igmp;
	register struct ip *ip;
	register int igmplen;
	register struct ifnet *ifp = m->m_pkthdr.rcvif;
	register int minlen;
	register struct in_multi *inm;
	register struct in_ifaddr *ia;
	struct in_multistep step;
	struct router_info *rti;
	
	int timer; /** timer value in the igmp query header **/

	++igmpstat.igps_rcv_total;

	ip = mtod(m, struct ip *);
	igmplen = ip->ip_len;

	/*
	 * Validate lengths
	 */
	if (igmplen < IGMP_MINLEN) {
		++igmpstat.igps_rcv_tooshort;
		m_freem(m);
		return;
	}
	minlen = iphlen + IGMP_MINLEN;
	if ((m->m_flags & M_EXT || m->m_len < minlen) &&
	    (m = m_pullup(m, minlen)) == 0) {
		++igmpstat.igps_rcv_tooshort;
		return;
	}

	/*
	 * Validate checksum
	 */
	m->m_data += iphlen;
	m->m_len -= iphlen;
	igmp = mtod(m, struct igmp *);
	if (in_cksum(m, igmplen)) {
		++igmpstat.igps_rcv_badsum;
		m_freem(m);
		return;
	}
	m->m_data -= iphlen;
	m->m_len += iphlen;

	ip = mtod(m, struct ip *);
	timer = igmp->igmp_code * PR_FASTHZ / IGMP_TIMER_SCALE;
	rti = find_rti(ifp);

	/*
	 * In the IGMPv2 specification, there are 3 states and a flag.
	 *
	 * In Non-Member state, we simply don't have a membership record.
	 * In Delaying Member state, our timer is running (inm->inm_timer)
	 * In Idle Member state, our timer is not running (inm->inm_timer==0)
	 *
	 * The flag is inm->inm_state, it is set to IGMP_OTHERMEMBER if
	 * we have heard a report from another member, or IGMP_IREPORTEDLAST
	 * if I sent the last report.
	 */
	switch (igmp->igmp_type) {

	case IGMP_MEMBERSHIP_QUERY:
		++igmpstat.igps_rcv_queries;

		if (ifp->if_flags & IFF_LOOPBACK)
			break;

		if (igmp->igmp_code == 0) {
			/*
			 * Old router.  Remember that the querier on this
			 * interface is old, and set the timer to the
			 * value in RFC 1112.
			 */

			rti->rti_type = IGMP_V1_ROUTER;
			rti->rti_time = 0;

			timer = IGMP_MAX_HOST_REPORT_DELAY * PR_FASTHZ;

			if (ip->ip_dst.s_addr != igmp_all_hosts_group ||
			    igmp->igmp_group.s_addr != 0) {
				++igmpstat.igps_rcv_badqueries;
				m_freem(m);
				return;
			}
		} else {
			/*
			 * New router.  Simply do the new validity check.
			 */
			
			if (igmp->igmp_group.s_addr != 0 &&
			    !IN_MULTICAST(ntohl(igmp->igmp_group.s_addr))) {
				++igmpstat.igps_rcv_badqueries;
				m_freem(m);
				return;
			}
		}

		/*
		 * - Start the timers in all of our membership records
		 *   that the query applies to for the interface on
		 *   which the query arrived excl. those that belong
		 *   to the "all-hosts" group (224.0.0.1).
		 * - Restart any timer that is already running but has
		 *   a value longer than the requested timeout.
		 * - Use the value specified in the query message as
		 *   the maximum timeout.
		 */
		IN_FIRST_MULTI(step, inm);
		while (inm != NULL) {
			if (inm->inm_ifp == ifp &&
			    inm->inm_addr.s_addr != igmp_all_hosts_group &&
			    (igmp->igmp_group.s_addr == 0 ||
			     igmp->igmp_group.s_addr == inm->inm_addr.s_addr)) {
				if (inm->inm_timer == 0 ||
				    inm->inm_timer > timer) {
					inm->inm_timer =
						IGMP_RANDOM_DELAY(timer);
					igmp_timers_are_running = 1;
				}
			}
			IN_NEXT_MULTI(step, inm);
		}

		break;

	case IGMP_V1_MEMBERSHIP_REPORT:
	case IGMP_V2_MEMBERSHIP_REPORT:
		/*
		 * For fast leave to work, we have to know that we are the
		 * last person to send a report for this group.  Reports
		 * can potentially get looped back if we are a multicast
		 * router, so discard reports sourced by me.
		 */
		IFP_TO_IA(ifp, ia);
		if (ia && ip->ip_src.s_addr == IA_SIN(ia)->sin_addr.s_addr)
			break;

		++igmpstat.igps_rcv_reports;

		if (ifp->if_flags & IFF_LOOPBACK)
			break;

		if (!IN_MULTICAST(ntohl(igmp->igmp_group.s_addr))) {
			++igmpstat.igps_rcv_badreports;
			m_freem(m);
			return;
		}

		/*
		 * KLUDGE: if the IP source address of the report has an
		 * unspecified (i.e., zero) subnet number, as is allowed for
		 * a booting host, replace it with the correct subnet number
		 * so that a process-level multicast routing demon can
		 * determine which subnet it arrived from.  This is necessary
		 * to compensate for the lack of any way for a process to
		 * determine the arrival interface of an incoming packet.
		 */
		if ((ntohl(ip->ip_src.s_addr) & IN_CLASSA_NET) == 0)
			if (ia) ip->ip_src.s_addr = htonl(ia->ia_subnet);

		/*
		 * If we belong to the group being reported, stop
		 * our timer for that group.
		 */
		IN_LOOKUP_MULTI(igmp->igmp_group, ifp, inm);

		if (inm != NULL) {
			inm->inm_timer = 0;
			++igmpstat.igps_rcv_ourreports;

			inm->inm_state = IGMP_OTHERMEMBER;
		}

		break;
	}

	/*
	 * Pass all valid IGMP packets up to any process(es) listening
	 * on a raw IGMP socket.
	 */
	rip_input(m, iphlen);
}
int
in_pcbladdr(struct inpcb *inp, struct mbuf *nam, struct sockaddr_in **plocal_sin)
{
	struct in_ifaddr *ia;
	register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);

	if (nam->m_len != sizeof (*sin))
		return (EINVAL);
	if (sin->sin_family != AF_INET)
		return (EAFNOSUPPORT);
	if (sin->sin_port == 0)
		return (EADDRNOTAVAIL);
	if (in_ifaddr) {
		/*
		 * If the destination address is INADDR_ANY,
		 * use the primary local address.
		 * If the supplied address is INADDR_BROADCAST,
		 * and the primary interface supports broadcast,
		 * choose the broadcast address for that interface.
		 */
#define	satosin(sa)	((struct sockaddr_in *)(sa))
#define sintosa(sin)	((struct sockaddr *)(sin))
#define ifatoia(ifa)	((struct in_ifaddr *)(ifa))
		if (sin->sin_addr.s_addr == INADDR_ANY)
		    sin->sin_addr = IA_SIN(in_ifaddr)->sin_addr;
		else if (sin->sin_addr.s_addr == (u_long)INADDR_BROADCAST &&
		  (in_ifaddr->ia_ifp->if_flags & IFF_BROADCAST))
		    sin->sin_addr = satosin(&in_ifaddr->ia_broadaddr)->sin_addr;
	}
	if (inp->inp_laddr.s_addr == INADDR_ANY) {
		register struct route *ro;

		ia = (struct in_ifaddr *)0;
		/*
		 * If route is known or can be allocated now,
		 * our src addr is taken from the i/f, else punt.
		 */
		ro = &inp->inp_route;
		if (ro->ro_rt &&
		    (satosin(&ro->ro_dst)->sin_addr.s_addr !=
			sin->sin_addr.s_addr ||
		    inp->inp_socket->so_options & SO_DONTROUTE)) {
			RTFREE(ro->ro_rt);
			ro->ro_rt = (struct rtentry *)0;
		}
		if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/
		    (ro->ro_rt == (struct rtentry *)0 ||
		    ro->ro_rt->rt_ifp == (struct ifnet *)0)) {
			/* No route yet, so try to acquire one */
			ro->ro_dst.sa_family = AF_INET;
			ro->ro_dst.sa_len = sizeof(struct sockaddr_in);
			((struct sockaddr_in *) &ro->ro_dst)->sin_addr =
				sin->sin_addr;
			rtalloc(ro);
		}
		/*
		 * If we found a route, use the address
		 * corresponding to the outgoing interface
		 * unless it is the loopback (in case a route
		 * to our address on another net goes to loopback).
		 */
		if (ro->ro_rt && !(ro->ro_rt->rt_ifp->if_flags & IFF_LOOPBACK))
			ia = ifatoia(ro->ro_rt->rt_ifa);
		if (ia == 0) {
			u_short fport = sin->sin_port;

			sin->sin_port = 0;
			ia = ifatoia(ifa_ifwithdstaddr(sintosa(sin)));
			if (ia == 0)
				ia = ifatoia(ifa_ifwithnet(sintosa(sin)));
			sin->sin_port = fport;
			if (ia == 0)
				ia = in_ifaddr;
			if (ia == 0)
				return (EADDRNOTAVAIL);
		}
		/*
		 * If the destination address is multicast and an outgoing
		 * interface has been set as a multicast option, use the
		 * address of that interface as our source address.
		 */
		if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr)) &&
		    inp->inp_moptions != NULL) {
			struct ip_moptions *imo;
			struct ifnet *ifp;

			imo = inp->inp_moptions;
			if (imo->imo_multicast_ifp != NULL) {
				ifp = imo->imo_multicast_ifp;
				for (ia = in_ifaddr; ia; ia = ia->ia_next)
					if (ia->ia_ifp == ifp)
						break;
				if (ia == 0)
					return (EADDRNOTAVAIL);
			}
		}
	/*
	 * Don't do pcblookup call here; return interface in plocal_sin
	 * and exit to caller, that will do the lookup.
	 */
		*plocal_sin = &ia->ia_addr;

	}
	return(0);
}
示例#4
0
/*
 * Do option processing on a datagram, possibly discarding it if bad options
 * are encountered, or forwarding it if source-routed.
 *
 * The pass argument is used when operating in the IPSTEALTH mode to tell
 * what options to process: [LS]SRR (pass 0) or the others (pass 1).  The
 * reason for as many as two passes is that when doing IPSTEALTH, non-routing
 * options should be processed only if the packet is for us.
 *
 * Returns 1 if packet has been forwarded/freed, 0 if the packet should be
 * processed further.
 */
int
ip_dooptions(struct mbuf *m, int pass)
{
	struct ip *ip = mtod(m, struct ip *);
	u_char *cp;
	struct in_ifaddr *ia;
	int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0;
	struct in_addr *sin, dst;
	uint32_t ntime;
	struct	sockaddr_in ipaddr = { sizeof(ipaddr), AF_INET };

	/* Ignore or reject packets with IP options. */
	if (ip_doopts == 0)
		return 0;
	else if (ip_doopts == 2) {
		type = ICMP_UNREACH;
		code = ICMP_UNREACH_FILTER_PROHIB;
		goto bad;
	}

	dst = ip->ip_dst;
	cp = (u_char *)(ip + 1);
	cnt = (ip->ip_hl << 2) - sizeof (struct ip);
	for (; cnt > 0; cnt -= optlen, cp += optlen) {
		opt = cp[IPOPT_OPTVAL];
		if (opt == IPOPT_EOL)
			break;
		if (opt == IPOPT_NOP)
			optlen = 1;
		else {
			if (cnt < IPOPT_OLEN + sizeof(*cp)) {
				code = &cp[IPOPT_OLEN] - (u_char *)ip;
				goto bad;
			}
			optlen = cp[IPOPT_OLEN];
			if (optlen < IPOPT_OLEN + sizeof(*cp) || optlen > cnt) {
				code = &cp[IPOPT_OLEN] - (u_char *)ip;
				goto bad;
			}
		}
		switch (opt) {

		default:
			break;

		/*
		 * Source routing with record.  Find interface with current
		 * destination address.  If none on this machine then drop if
		 * strictly routed, or do nothing if loosely routed.  Record
		 * interface address and bring up next address component.  If
		 * strictly routed make sure next address is on directly
		 * accessible net.
		 */
		case IPOPT_LSRR:
		case IPOPT_SSRR:
#ifdef IPSTEALTH
			if (V_ipstealth && pass > 0)
				break;
#endif
			if (optlen < IPOPT_OFFSET + sizeof(*cp)) {
				code = &cp[IPOPT_OLEN] - (u_char *)ip;
				goto bad;
			}
			if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) {
				code = &cp[IPOPT_OFFSET] - (u_char *)ip;
				goto bad;
			}
			ipaddr.sin_addr = ip->ip_dst;
			if (ifa_ifwithaddr_check((struct sockaddr *)&ipaddr)
			    == 0) {
				if (opt == IPOPT_SSRR) {
					type = ICMP_UNREACH;
					code = ICMP_UNREACH_SRCFAIL;
					goto bad;
				}
				if (!ip_dosourceroute)
					goto nosourcerouting;
				/*
				 * Loose routing, and not at next destination
				 * yet; nothing to do except forward.
				 */
				break;
			}
			off--;			/* 0 origin */
			if (off > optlen - (int)sizeof(struct in_addr)) {
				/*
				 * End of source route.  Should be for us.
				 */
				if (!ip_acceptsourceroute)
					goto nosourcerouting;
				save_rte(m, cp, ip->ip_src);
				break;
			}
#ifdef IPSTEALTH
			if (V_ipstealth)
				goto dropit;
#endif
			if (!ip_dosourceroute) {
				if (V_ipforwarding) {
					char buf[16]; /* aaa.bbb.ccc.ddd\0 */
					/*
					 * Acting as a router, so generate
					 * ICMP
					 */
nosourcerouting:
					strcpy(buf, inet_ntoa(ip->ip_dst));
					log(LOG_WARNING, 
					    "attempted source route from %s to %s\n",
					    inet_ntoa(ip->ip_src), buf);
					type = ICMP_UNREACH;
					code = ICMP_UNREACH_SRCFAIL;
					goto bad;
				} else {
					/*
					 * Not acting as a router, so
					 * silently drop.
					 */
#ifdef IPSTEALTH
dropit:
#endif
					IPSTAT_INC(ips_cantforward);
					m_freem(m);
					return (1);
				}
			}

			/*
			 * locate outgoing interface
			 */
			(void)memcpy(&ipaddr.sin_addr, cp + off,
			    sizeof(ipaddr.sin_addr));

			if (opt == IPOPT_SSRR) {
#define	INA	struct in_ifaddr *
#define	SA	struct sockaddr *
			    if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr)) == NULL)
				    ia = (INA)ifa_ifwithnet((SA)&ipaddr, 0);
			} else
/* XXX MRT 0 for routing */
				ia = ip_rtaddr(ipaddr.sin_addr, M_GETFIB(m));
			if (ia == NULL) {
				type = ICMP_UNREACH;
				code = ICMP_UNREACH_SRCFAIL;
				goto bad;
			}
			ip->ip_dst = ipaddr.sin_addr;
			(void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr),
			    sizeof(struct in_addr));
			ifa_free(&ia->ia_ifa);
			cp[IPOPT_OFFSET] += sizeof(struct in_addr);
			/*
			 * Let ip_intr's mcast routing check handle mcast pkts
			 */
			forward = !IN_MULTICAST(ntohl(ip->ip_dst.s_addr));
			break;

		case IPOPT_RR:
#ifdef IPSTEALTH
			if (V_ipstealth && pass == 0)
				break;
#endif
			if (optlen < IPOPT_OFFSET + sizeof(*cp)) {
				code = &cp[IPOPT_OFFSET] - (u_char *)ip;
				goto bad;
			}
			if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) {
				code = &cp[IPOPT_OFFSET] - (u_char *)ip;
				goto bad;
			}
			/*
			 * If no space remains, ignore.
			 */
			off--;			/* 0 origin */
			if (off > optlen - (int)sizeof(struct in_addr))
				break;
			(void)memcpy(&ipaddr.sin_addr, &ip->ip_dst,
			    sizeof(ipaddr.sin_addr));
			/*
			 * Locate outgoing interface; if we're the
			 * destination, use the incoming interface (should be
			 * same).
			 */
			if ((ia = (INA)ifa_ifwithaddr((SA)&ipaddr)) == NULL &&
			    (ia = ip_rtaddr(ipaddr.sin_addr, M_GETFIB(m))) == NULL) {
				type = ICMP_UNREACH;
				code = ICMP_UNREACH_HOST;
				goto bad;
			}
			(void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr),
			    sizeof(struct in_addr));
			ifa_free(&ia->ia_ifa);
			cp[IPOPT_OFFSET] += sizeof(struct in_addr);
			break;

		case IPOPT_TS:
#ifdef IPSTEALTH
			if (V_ipstealth && pass == 0)
				break;
#endif
			code = cp - (u_char *)ip;
			if (optlen < 4 || optlen > 40) {
				code = &cp[IPOPT_OLEN] - (u_char *)ip;
				goto bad;
			}
			if ((off = cp[IPOPT_OFFSET]) < 5) {
				code = &cp[IPOPT_OLEN] - (u_char *)ip;
				goto bad;
			}
			if (off > optlen - (int)sizeof(int32_t)) {
				cp[IPOPT_OFFSET + 1] += (1 << 4);
				if ((cp[IPOPT_OFFSET + 1] & 0xf0) == 0) {
					code = &cp[IPOPT_OFFSET] - (u_char *)ip;
					goto bad;
				}
				break;
			}
			off--;				/* 0 origin */
			sin = (struct in_addr *)(cp + off);
			switch (cp[IPOPT_OFFSET + 1] & 0x0f) {

			case IPOPT_TS_TSONLY:
				break;

			case IPOPT_TS_TSANDADDR:
				if (off + sizeof(uint32_t) +
				    sizeof(struct in_addr) > optlen) {
					code = &cp[IPOPT_OFFSET] - (u_char *)ip;
					goto bad;
				}
				ipaddr.sin_addr = dst;
				ia = (INA)ifaof_ifpforaddr((SA)&ipaddr,
							    m->m_pkthdr.rcvif);
				if (ia == NULL)
					continue;
				(void)memcpy(sin, &IA_SIN(ia)->sin_addr,
				    sizeof(struct in_addr));
				ifa_free(&ia->ia_ifa);
				cp[IPOPT_OFFSET] += sizeof(struct in_addr);
				off += sizeof(struct in_addr);
				break;

			case IPOPT_TS_PRESPEC:
				if (off + sizeof(uint32_t) +
				    sizeof(struct in_addr) > optlen) {
					code = &cp[IPOPT_OFFSET] - (u_char *)ip;
					goto bad;
				}
				(void)memcpy(&ipaddr.sin_addr, sin,
				    sizeof(struct in_addr));
				if (ifa_ifwithaddr_check((SA)&ipaddr) == 0)
					continue;
				cp[IPOPT_OFFSET] += sizeof(struct in_addr);
				off += sizeof(struct in_addr);
				break;

			default:
				code = &cp[IPOPT_OFFSET + 1] - (u_char *)ip;
				goto bad;
			}
			ntime = iptime();
			(void)memcpy(cp + off, &ntime, sizeof(uint32_t));
			cp[IPOPT_OFFSET] += sizeof(uint32_t);
		}
	}
	if (forward && V_ipforwarding) {
		ip_forward(m, 1);
		return (1);
	}
	return (0);
bad:
	icmp_error(m, type, code, 0, 0);
	IPSTAT_INC(ips_badoptions);
	return (1);
}
示例#5
0
static int 
map_fix_local_rlocs(struct locator_chain * lcptr)
{
        int error = EINVAL;
	struct sockaddr_in *rloc_inet = NULL;
	struct sockaddr_in6 *rloc_inet6 = NULL;
	struct in_ifaddr *ia = NULL;
	struct in6_ifaddr *ia6 = NULL;

	while ( lcptr ) {
	       /* Scan the chain checking if the RLOC is the address 
		* of a local interface. 
		*/ 

	        switch (lcptr->rloc.rloc_addr->ss_family) {
      
			case AF_INET:
	
			        rloc_inet = (struct sockaddr_in *) lcptr->rloc.rloc_addr;
				INADDR_TO_IFADDR(rloc_inet->sin_addr, ia); 

				/*
				 * If the address matches, set RLOCF_LIF 
				 * flag and MTU.
				 */
				if ((ia != NULL) &&
				    (IA_SIN(ia)->sin_addr.s_addr == rloc_inet->sin_addr.s_addr)) {
				        lcptr->rloc.rloc_metrix.rlocmtx.flags |= RLOCF_LIF;
					lcptr->rloc.rloc_metrix.rlocmtx.mtu = (ia->ia_ifp)->if_mtu;
					
					error = 0;
  
				};
 
			  
				break;
		    
			case AF_INET6:

			        rloc_inet6 = (struct sockaddr_in6 *) lcptr->rloc.rloc_addr;

			
				ia6 = (struct in6_ifaddr *)ifa_ifwithaddr((struct sockaddr *)(rloc_inet6));



				/*
				 * If the address matches, set RLOCF_LIF 
				 * flag and MTU.
				 */
				if ((ia6 != NULL) &&
				    (IN6_ARE_ADDR_EQUAL(&ia6->ia_addr.sin6_addr,
							&rloc_inet6->sin6_addr))) {

				        lcptr->rloc.rloc_metrix.rlocmtx.flags |= RLOCF_LIF;
					lcptr->rloc.rloc_metrix.rlocmtx.mtu = (ia6->ia_ifp)->if_mtu;
					
					error = 0;
  
				};
				break;

		};

	        lcptr = lcptr->next;

	};

#ifdef LISP_DEBUG
	if (error) {
	        DEBUGLISP("[MAP_FIX_LOCAL_RLOC] No local IF RLOCs Provided for local mapping! \n");
	};
#endif /* LISP_DEBUG */


	return (error);

}  /* map_fix_local_rloc() */
示例#6
0
/*
 * Ip input routine.  Checksum and byte swap header.  If fragmented
 * try to reassemble.  Process options.  Pass to next level.
 */
void
ipintr()
{
    register struct ip *ip;
    register struct mbuf *m;
    register struct ipq *fp;
    register struct in_ifaddr *ia;
    int hlen, s;

next:
    /*
     * Get next datagram off input queue and get IP header
     * in first mbuf.
     */
    s = splimp();
    IF_DEQUEUE(&ipintrq, m);
    splx(s);
    if (m == 0)
        return;
#ifdef  DIAGNOSTIC
    if ((m->m_flags & M_PKTHDR) == 0)
        panic("ipintr no HDR");
#endif
    /*
     * If no IP addresses have been set yet but the interfaces
     * are receiving, can't do anything with incoming packets yet.
     */
    if (in_ifaddr == NULL)
        goto bad;
    ipstat.ips_total++;
    if (m->m_len < sizeof (struct ip) &&
        (m = m_pullup(m, sizeof (struct ip))) == 0) {
        ipstat.ips_toosmall++;
        goto next;
    }
    ip = mtod(m, struct ip *);
    if (ip->ip_v != IPVERSION) {
        ipstat.ips_badvers++;
        goto bad;
    }
    hlen = ip->ip_hl << 2;
    if (hlen < sizeof(struct ip)) { /* minimum header length */
        ipstat.ips_badhlen++;
        goto bad;
    }
    if (hlen > m->m_len) {
        if ((m = m_pullup(m, hlen)) == 0) {
            ipstat.ips_badhlen++;
            goto next;
        }
        ip = mtod(m, struct ip *);
    }
    ip->ip_sum = in_cksum(m, hlen);
    if (ip->ip_sum) {
        ipstat.ips_badsum++;
        goto bad;
    }

    /*
     * Convert fields to host representation.
     */
    NTOHS(ip->ip_len);
    if (ip->ip_len < hlen) {
        ipstat.ips_badlen++;
        goto bad;
    }
    NTOHS(ip->ip_id);
    NTOHS(ip->ip_off);

    /*
     * Check that the amount of data in the buffers
     * is as at least much as the IP header would have us expect.
     * Trim mbufs if longer than we expect.
     * Drop packet if shorter than we expect.
     */
    if (m->m_pkthdr.len < ip->ip_len) {
        ipstat.ips_tooshort++;
        goto bad;
    }
    if (m->m_pkthdr.len > ip->ip_len) {
        if (m->m_len == m->m_pkthdr.len) {
            m->m_len = ip->ip_len;
            m->m_pkthdr.len = ip->ip_len;
        } else
            m_adj(m, ip->ip_len - m->m_pkthdr.len);
    }

    /*
     * Process options and, if not destined for us,
     * ship it on.  ip_dooptions returns 1 when an
     * error was detected (causing an icmp message
     * to be sent and the original packet to be freed).
     */
    ip_nhops = 0;       /* for source routed packets */
    if (hlen > sizeof (struct ip) && ip_dooptions(m))
        goto next;

    /*
     * Check our list of addresses, to see if the packet is for us.
     */
    for (ia = in_ifaddr; ia; ia = ia->ia_next) {
#define satosin(sa) ((struct sockaddr_in *)(sa))

        if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_dst.s_addr)
            goto ours;
        if (
#ifdef  DIRECTED_BROADCAST
            ia->ia_ifp == m->m_pkthdr.rcvif &&
#endif
            (ia->ia_ifp->if_flags & IFF_BROADCAST)) {
            u_long t;

            if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr ==
                ip->ip_dst.s_addr)
                goto ours;
            if (ip->ip_dst.s_addr == ia->ia_netbroadcast.s_addr)
                goto ours;
            /*
             * Look for all-0's host part (old broadcast addr),
             * either for subnet or net.
             */
            t = ntohl(ip->ip_dst.s_addr);
            if (t == ia->ia_subnet)
                goto ours;
            if (t == ia->ia_net)
                goto ours;
        }
    }
    if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
        struct in_multi *inm;
#ifdef MROUTING
        extern struct socket *ip_mrouter;

        if (ip_mrouter) {
            /*
             * If we are acting as a multicast router, all
             * incoming multicast packets are passed to the
             * kernel-level multicast forwarding function.
             * The packet is returned (relatively) intact; if
             * ip_mforward() returns a non-zero value, the packet
             * must be discarded, else it may be accepted below.
             *
             * (The IP ident field is put in the same byte order
             * as expected when ip_mforward() is called from
             * ip_output().)
             */
            ip->ip_id = htons(ip->ip_id);
            if (ip_mforward(m, m->m_pkthdr.rcvif) != 0) {
                ipstat.ips_cantforward++;
                m_freem(m);
                goto next;
            }
            ip->ip_id = ntohs(ip->ip_id);

            /*
             * The process-level routing demon needs to receive
             * all multicast IGMP packets, whether or not this
             * host belongs to their destination groups.
             */
            if (ip->ip_p == IPPROTO_IGMP)
                goto ours;
            ipstat.ips_forward++;
        }
#endif
        /*
         * See if we belong to the destination multicast group on the
         * arrival interface.
         */
        IN_LOOKUP_MULTI(ip->ip_dst, m->m_pkthdr.rcvif, inm);
        if (inm == NULL) {
            ipstat.ips_cantforward++;
            m_freem(m);
            goto next;
        }
        goto ours;
    }
    if (ip->ip_dst.s_addr == (u_long)INADDR_BROADCAST)
        goto ours;
    if (ip->ip_dst.s_addr == INADDR_ANY)
        goto ours;

    /*
     * Not for us; forward if possible and desirable.
     */
    if (ipforwarding == 0) {
        ipstat.ips_cantforward++;
        m_freem(m);
    } else
        ip_forward(m, 0);
    goto next;

ours:
    /*
     * If offset or IP_MF are set, must reassemble.
     * Otherwise, nothing need be done.
     * (We could look in the reassembly queue to see
     * if the packet was previously fragmented,
     * but it's not worth the time; just let them time out.)
     */
    if (ip->ip_off &~ IP_DF) {
        if (m->m_flags & M_EXT) {       /* XXX */
            if ((m = m_pullup(m, sizeof (struct ip))) == 0) {
                ipstat.ips_toosmall++;
                goto next;
            }
            ip = mtod(m, struct ip *);
        }
        /*
         * Look for queue of fragments
         * of this datagram.
         */
        for (fp = ipq.next; fp != &ipq; fp = fp->next)
            if (ip->ip_id == fp->ipq_id &&
                ip->ip_src.s_addr == fp->ipq_src.s_addr &&
                ip->ip_dst.s_addr == fp->ipq_dst.s_addr &&
                ip->ip_p == fp->ipq_p)
                goto found;
        fp = 0;
found:

        /*
         * Adjust ip_len to not reflect header,
         * set ip_mff if more fragments are expected,
         * convert offset of this to bytes.
         */
        ip->ip_len -= hlen;
        ((struct ipasfrag *)ip)->ipf_mff &= ~1;
        if (ip->ip_off & IP_MF)
            ((struct ipasfrag *)ip)->ipf_mff |= 1;
        ip->ip_off <<= 3;

        /*
         * If datagram marked as having more fragments
         * or if this is not the first fragment,
         * attempt reassembly; if it succeeds, proceed.
         */
        if (((struct ipasfrag *)ip)->ipf_mff & 1 || ip->ip_off) {
            ipstat.ips_fragments++;
            ip = ip_reass((struct ipasfrag *)ip, fp);
            if (ip == 0)
                goto next;
            ipstat.ips_reassembled++;
            m = dtom(ip);
        } else
            if (fp)
                ip_freef(fp);
    } else
示例#7
0
/*
 * Issue an InATMARP Response PDU
 * 
 * Arguments:
 *	uip	pointer to IP interface
 *	tip	pointer to target IP address
 *	tatm	pointer to target ATM address
 *	tsub	pointer to target ATM subaddress
 *	ivp	pointer to vcc over which to send pdu
 *
 * Returns:
 *	0	PDU was successfully sent
 *	else	unable to send PDU
 *
 */
int
uniarp_inarp_rsp(struct uniip *uip, struct in_addr *tip, Atm_addr *tatm,
		 Atm_addr *tsub, struct ipvcc *ivp)
{
	KBuffer		*m;
	struct atmarp_hdr	*ahp;
	struct atm_nif	*nip;
	struct ip_nif	*inp;
	struct siginst	*sip;
	char		*cp;
	int		len, err;

	inp = uip->uip_ipnif;
	nip = inp->inf_nif;
	sip = inp->inf_nif->nif_pif->pif_siginst;

	/*
	 * Figure out how long pdu is going to be
	 */
	len = sizeof(struct atmarp_hdr) + (2 * sizeof(struct in_addr));
	switch (sip->si_addr.address_format) {
	case T_ATM_ENDSYS_ADDR:
		len += sip->si_addr.address_length;
		break;

	case T_ATM_E164_ADDR:
		len += sip->si_addr.address_length;
		if (sip->si_subaddr.address_format == T_ATM_ENDSYS_ADDR)
			len += sip->si_subaddr.address_length;
		break;
	}

	switch (tatm->address_format) {
	case T_ATM_ENDSYS_ADDR:
		len += tatm->address_length;
		break;

	case T_ATM_E164_ADDR:
		len += tatm->address_length;
		if (tsub->address_format == T_ATM_ENDSYS_ADDR)
			len += tsub->address_length;
		break;
	}

	/*
	 * Get a buffer for pdu
	 */
	KB_ALLOCPKT(m, len, KB_F_NOWAIT, KB_T_DATA);
	if (m == NULL)
		return (1);

	/*
	 * Place aligned pdu at end of buffer
	 */
	KB_TAILALIGN(m, len);
	KB_DATASTART(m, ahp, struct atmarp_hdr *);

	/*
	 * Setup variable fields pointer
	 */
	cp = (char *)ahp + sizeof(struct atmarp_hdr);

	/*
	 * Build fields
	 */
	ahp->ah_hrd = htons(ARP_ATMFORUM);
	ahp->ah_pro = htons(ETHERTYPE_IP);
	len = sip->si_addr.address_length;
	switch (sip->si_addr.address_format) {
	case T_ATM_ENDSYS_ADDR:
		ahp->ah_shtl = ARP_TL_NSAPA | (len & ARP_TL_LMASK);

		/* ah_sha */
		KM_COPY(sip->si_addr.address, cp, len - 1);
		((struct atm_addr_nsap *)cp)->aan_sel = nip->nif_sel;
		cp += len;

		ahp->ah_sstl = 0;
		break;

	case T_ATM_E164_ADDR:
		ahp->ah_shtl = ARP_TL_E164 | (len & ARP_TL_LMASK);

		/* ah_sha */
		KM_COPY(sip->si_addr.address, cp, len);
		cp += len;

		if (sip->si_subaddr.address_format == T_ATM_ENDSYS_ADDR) {
			len = sip->si_subaddr.address_length;
			ahp->ah_sstl = ARP_TL_NSAPA | (len & ARP_TL_LMASK);

			/* ah_ssa */
			KM_COPY(sip->si_subaddr.address, cp, len - 1);
			((struct atm_addr_nsap *)cp)->aan_sel = nip->nif_sel;
			cp += len;
		} else
			ahp->ah_sstl = 0;
		break;

	default:
		ahp->ah_shtl = 0;
		ahp->ah_sstl = 0;
	}

	ahp->ah_op = htons(INARP_REPLY);
	ahp->ah_spln = sizeof(struct in_addr);

	/* ah_spa */
	KM_COPY((caddr_t)&(IA_SIN(inp->inf_addr)->sin_addr), cp, 
		sizeof(struct in_addr));
	cp += sizeof(struct in_addr);

	len = tatm->address_length;
	switch (tatm->address_format) {
	case T_ATM_ENDSYS_ADDR:
		ahp->ah_thtl = ARP_TL_NSAPA | (len & ARP_TL_LMASK);

		/* ah_tha */
		KM_COPY(tatm->address, cp, len);
		cp += len;

		ahp->ah_tstl = 0;
		break;

	case T_ATM_E164_ADDR:
		ahp->ah_thtl = ARP_TL_E164 | (len & ARP_TL_LMASK);

		/* ah_tha */
		KM_COPY(tatm->address, cp, len);
		cp += len;

		if (tsub->address_format == T_ATM_ENDSYS_ADDR) {
			len = tsub->address_length;
			ahp->ah_tstl = ARP_TL_NSAPA | (len & ARP_TL_LMASK);

			/* ah_tsa */
			KM_COPY(tsub->address, cp, len);
			cp += len;
		} else
			ahp->ah_tstl = 0;
		break;

	default:
		ahp->ah_thtl = 0;
		ahp->ah_tstl = 0;
	}

	ahp->ah_tpln = sizeof(struct in_addr);

	/* ah_tpa */
	KM_COPY((caddr_t)tip, cp, sizeof(struct in_addr));

	/*
	 * Finally, send the pdu to the vcc peer
	 */
	if (uniarp_print)
		uniarp_pdu_print(ivp, m, "send");
	err = atm_cm_cpcs_data(ivp->iv_arpconn, m);
	if (err) {
		/*
		 * Didn't make it
		 */
		KB_FREEALL(m);
		return (1);
	}

	return (0);
}
示例#8
0
/*
 * Process a SPANS ARP input packet
 * 
 * Arguments:
 *	clp	pointer to interface CLS control block
 *	m	pointer to input packet buffer chain
 *
 * Returns:
 *	none
 *
 */
void
spansarp_input(struct spanscls *clp, KBuffer *m)
{
	struct spans		*spp = clp->cls_spans;
	struct spanscls_hdr	*chp;
	struct spansarp_hdr	*ahp;
	struct spansarp		*sap;
	struct ip_nif		*inp = clp->cls_ipnif;
	struct in_addr	in_me, in_src, in_targ;
	int		err;

	/*
	 * Make sure IP interface has been activated
	 */
	if (inp == NULL)
		goto free;

	/*
	 * Get the packet together
	 */
	if (KB_LEN(m) < ARP_PACKET_LEN) {
		KB_PULLUP(m, ARP_PACKET_LEN, m);
		if (m == NULL)
			return;
	}
	KB_DATASTART(m, chp, struct spanscls_hdr *);
	ahp = (struct spansarp_hdr *)(chp + 1);

	KM_COPY(ahp->ah_spa, &in_src, sizeof(struct in_addr));
	KM_COPY(ahp->ah_tpa, &in_targ, sizeof(struct in_addr));
	KM_COPY(&(IA_SIN(inp->inf_addr)->sin_addr), &in_me,
		sizeof(struct in_addr));

	/*
	 * Initial packet verification
	 */
	if ((ahp->ah_hrd != htons(ARP_SPANS)) ||
	    (ahp->ah_pro != htons(ETHERTYPE_IP)))
		goto free;

	/*
	 * Validate source addresses
	 * 	can't be from hardware broadcast
	 *	can't be from me
	 */
	if (!spans_addr_cmp(&ahp->ah_sha, &spans_bcastaddr))
		goto free;
	if (!spans_addr_cmp(&ahp->ah_sha, spp->sp_addr.address))
		goto free;
	if (in_src.s_addr == in_me.s_addr) {
		log(LOG_ERR, 
			"duplicate IP address sent from spans address %s\n",
			spans_addr_print(&ahp->ah_sha));
		in_targ = in_me;
		goto chkop;
	}

	/*
	 * If source IP address is from unspecified or broadcast addresses,
	 * don't bother updating arp table, but answer possible requests
	 */
	if (in_broadcast(in_src, &inp->inf_nif->nif_if))
		goto chkop;

	/*
	 * Update arp table with source address info
	 */
	crit_enter();
	SPANSARP_LOOKUP(in_src.s_addr, sap);
	if (sap) {
		/*
		 * Found an entry for the source, but don't
		 * update permanent entries
		 */
		if (sap->sa_origin != SAO_PERM) {

			/*
			 * Update the entry
			 */
			sap->sa_dstatm.address_format = T_ATM_SPANS_ADDR;
			sap->sa_dstatm.address_length = sizeof(spans_addr);
			spans_addr_copy(&ahp->ah_sha, sap->sa_dstatm.address);
			sap->sa_cls = clp;
			sap->sa_reftime = 0;
			if ((sap->sa_flags & SAF_VALID) == 0) {
				/*
				 * Newly valid entry, notify waiting users
				 */
				struct ipvcc	*ivp, *inext;

				sap->sa_flags |= SAF_VALID;
				for (ivp = sap->sa_ivp; ivp; ivp = inext) {
					inext = ivp->iv_arpnext;

					ivp->iv_arpent = (struct arpmap *)sap;
					(*inp->inf_arpnotify)(ivp, MAP_VALID);
				}

				/*
				 * Remove ourselves from the retry chain
				 */
				UNLINK(sap, struct spansarp,
					spansarp_retry_head, sa_rnext);
			}
		}

	} else if (in_targ.s_addr == in_me.s_addr) {
		/*
		 * Source unknown and we're the target - add new entry
		 */
		sap = (struct spansarp *)atm_allocate(&spansarp_pool);
		if (sap) {
			sap->sa_dstip.s_addr = in_src.s_addr;
			sap->sa_dstatm.address_format = T_ATM_SPANS_ADDR;
			sap->sa_dstatm.address_length = sizeof(spans_addr);
			spans_addr_copy(&ahp->ah_sha, sap->sa_dstatm.address);
			sap->sa_dstatmsub.address_format = T_ATM_ABSENT;
			sap->sa_dstatmsub.address_length = 0;
			sap->sa_cls = clp;
			sap->sa_flags = SAF_VALID;
			sap->sa_origin = SAO_LOOKUP;
			SPANSARP_ADD(sap);
		}
	}
	crit_exit();

chkop:
	/*
	 * If this is a request for our address, send a reply 
	 */
	if (ntohs(ahp->ah_op) != ARP_REQUEST)
		goto free;
	if (in_targ.s_addr != in_me.s_addr)
		goto free;

	spans_addr_copy(&chp->ch_src, &chp->ch_dst);
	spans_addr_copy(spp->sp_addr.address, &chp->ch_src);
	ahp->ah_op = htons(ARP_REPLY);
	spans_addr_copy(&ahp->ah_sha, &ahp->ah_tha);
	spans_addr_copy(spp->sp_addr.address, &ahp->ah_sha);
	KM_COPY(ahp->ah_spa, ahp->ah_tpa, sizeof(struct in_addr));
	KM_COPY(&in_me, ahp->ah_spa, sizeof(struct in_addr));

	err = atm_cm_cpcs_data(clp->cls_conn, m);
	if (err)
		goto free;
	return;

free:
	KB_FREEALL(m);
}
示例#9
0
/*
 * Issue a SPANS ARP request packet
 * 
 * Arguments:
 *	sap	pointer to arp table entry
 *
 * Returns:
 *	0	packet was successfully sent
 *	else	unable to send packet
 *
 */
static int
spansarp_request(struct spansarp *sap)
{
	struct spanscls		*clp;
	struct spans		*spp;
	struct spanscls_hdr	*chp;
	struct spansarp_hdr	*ahp;
	KBuffer			*m;
	struct ip_nif		*inp;
	int			err;

	clp = sap->sa_cls;
	spp = clp->cls_spans;
	inp = clp->cls_ipnif;

	/*
	 * Make sure CLS VCC is open and that we know our addresses
	 */
	if (clp->cls_state != CLS_OPEN)
		return (1);
	if (spp->sp_addr.address_format != T_ATM_SPANS_ADDR)
		return (1);
	if (inp == NULL)
		return (1);

	/*
	 * Get a buffer for pdu
	 */
	KB_ALLOCPKT(m, ARP_PACKET_LEN, KB_F_NOWAIT, KB_T_DATA);
	if (m == NULL)
		return (1);

	/*
	 * Place pdu at end of buffer
	 */
	KB_PLENSET(m, ARP_PACKET_LEN);
	KB_TAILALIGN(m, ARP_PACKET_LEN);
	KB_DATASTART(m, chp, struct spanscls_hdr *);
	ahp = (struct spansarp_hdr *)(chp + 1);

	/*
	 * Build headers
	 */
	spans_addr_copy(&spans_bcastaddr, &chp->ch_dst);
	spans_addr_copy(spp->sp_addr.address, &chp->ch_src);
	*(u_int *)&chp->ch_proto = *(u_int *)&spanscls_hdr.ch_proto;
	*(u_int *)&chp->ch_dsap = *(u_int *)&spanscls_hdr.ch_dsap;
	*(u_short *)&chp->ch_oui[1] = *(u_short *)&spanscls_hdr.ch_oui[1];
	chp->ch_pid = htons(ETHERTYPE_ARP);


	/*
	 * Build ARP packet
	 */
	ahp->ah_hrd = htons(ARP_SPANS);
	ahp->ah_pro = htons(ETHERTYPE_IP);
	ahp->ah_hln = sizeof(spans_addr);
	ahp->ah_pln = sizeof(struct in_addr);
	ahp->ah_op = htons(ARP_REQUEST);
	spans_addr_copy(spp->sp_addr.address, &ahp->ah_sha);
	KM_COPY(&(IA_SIN(inp->inf_addr)->sin_addr), ahp->ah_spa,
		sizeof(struct in_addr));
	KM_COPY(&sap->sa_dstip, ahp->ah_tpa, sizeof(struct in_addr));

	/*
	 * Now, send the pdu via the CLS service
	 */
	err = atm_cm_cpcs_data(clp->cls_conn, m);
	if (err) {
		KB_FREEALL(m);
		return (1);
	}

	return (0);
}
示例#10
0
文件: tmp.c 项目: jamjr/Helios-NG
/*
 * Ip input routine.  Checksum and byte swap header.  If fragmented
 * try to reassamble.  If complete and fragment queue exists, discard.
 * Process options.  Pass to next level.
 */
ipintr()
{
	register struct ip *ip;
	register struct mbuf *m;
	struct mbuf *m0;
	register int i;
	register struct ipq *fp;
	register struct in_ifaddr *ia;
	struct ifnet *ifp;
	int hlen, s;

	
	/* IOdebug( "ipintr: called" ); */
next:
	/*
	 * Get next datagram off input queue and get IP header
	 * in first mbuf.
	 */
	s = splimp();
	
	IF_DEQUEUEIF(&ipintrq, m, ifp);
	
	splx(s);
	
	if (m == NULL)
	  {
	    /* IOdebug( "ipintr: no more mbufs" ); */
	    
	    return;
	  }

	/*
	 * If no IP addresses have been set yet but the interfaces
	 * are receiving, can't do anything with incoming packets yet.
	 */
	if (in_ifaddr == NULL)
		goto bad;
	ipstat.ips_total++;
	if ((m->m_off > MMAXOFF || m->m_len < sizeof (struct ip)) &&
	    (m = m_pullup(m, sizeof (struct ip))) == 0) {
		ipstat.ips_toosmall++;
		goto next;
	}
	ip = mtod(m, struct ip *);
	hlen = ip->ip_hl << 2;
	if (hlen < sizeof(struct ip)) {	/* minimum header length */
		ipstat.ips_badhlen++;
		goto bad;
	}
	if (hlen > m->m_len) {
		if ((m = m_pullup(m, hlen)) == 0) {
			ipstat.ips_badhlen++;
			goto next;
		}
		ip = mtod(m, struct ip *);
	}
	if (ipcksum)
		if (ip->ip_sum = in_cksum(m, hlen)) {
			ipstat.ips_badsum++;
			/* IOdebug( "ipintr: bad checksum" ); */
			goto bad;
		}

	/*
	 * Convert fields to host representation.
	 */
	ip->ip_len = ntohs((u_short)ip->ip_len);
	if (ip->ip_len < hlen) {
		ipstat.ips_badlen++;
		goto bad;
	}
	ip->ip_id = ntohs(ip->ip_id);
	ip->ip_off = ntohs((u_short)ip->ip_off);

	/*
	 * Check that the amount of data in the buffers
	 * is as at least much as the IP header would have us expect.
	 * Trim mbufs if longer than we expect.
	 * Drop packet if shorter than we expect.
	 */
	i = -(u_short)ip->ip_len;
	m0 = m;
	for (;;) {
		i += m->m_len;
		if (m->m_next == 0)
			break;
		m = m->m_next;
	}
	if (i != 0) {
		if (i < 0) {
			ipstat.ips_tooshort++;
			m = m0;
			goto bad;
		}
		if (i <= m->m_len)
			m->m_len -= i;
		else
			m_adj(m0, -i);
	}
	m = m0;

	/*
	 * Process options and, if not destined for us,
	 * ship it on.  ip_dooptions returns 1 when an
	 * error was detected (causing an icmp message
	 * to be sent and the original packet to be freed).
	 */
	ip_nhops = 0;		/* for source routed packets */
	if (hlen > sizeof (struct ip) && ip_dooptions(ip, ifp))
		goto next;

	/*
	 * Check our list of addresses, to see if the packet is for us.
	 */
	
	/* IOdebug( "ipintr: checking address" ); */
	
	for (ia = in_ifaddr; ia; ia = ia->ia_next) {
#define	satosin(sa)	((struct sockaddr_in *)(sa))

		if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_dst.s_addr)
			goto ours;
		if (
#ifdef	DIRECTED_BROADCAST
		    ia->ia_ifp == ifp &&
#endif
		    (ia->ia_ifp->if_flags & IFF_BROADCAST)) {
			u_long t;

			if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr ==
			    ip->ip_dst.s_addr)
				goto ours;
			if (ip->ip_dst.s_addr == ia->ia_netbroadcast.s_addr)
				goto ours;
			/*
			 * Look for all-0's host part (old broadcast addr),
			 * either for subnet or net.
			 */
			t = ntohl(ip->ip_dst.s_addr);
			if (t == ia->ia_subnet)
				goto ours;
			if (t == ia->ia_net)
				goto ours;
		}
	}
	if (ip->ip_dst.s_addr == (u_long)INADDR_BROADCAST)
		goto ours;
	if (ip->ip_dst.s_addr == INADDR_ANY)
		goto ours;

	/*
	 * Not for us; forward if possible and desirable.
	 */
	ip_forward(ip, ifp);
	
	/* IOdebug( "ipintr: not for us" ); */
	
	goto next;

ours:
	/* IOdebug( "ipintr: ours" ); */
	
	/*
	 * If offset or IP_MF are set, must reassemble.
	 * Otherwise, nothing need be done.
	 * (We could look in the reassembly queue to see
	 * if the packet was previously fragmented,
	 * but it's not worth the time; just let them time out.)
	 */
	if (ip->ip_off &~ IP_DF) {
		/*
		 * Look for queue of fragments
		 * of this datagram.
		 */
	    
		for (fp = ipq.next; fp != &ipq; fp = fp->next)
			if (ip->ip_id == fp->ipq_id &&
			    ip->ip_src.s_addr == fp->ipq_src.s_addr &&
			    ip->ip_dst.s_addr == fp->ipq_dst.s_addr &&
			    ip->ip_p == fp->ipq_p)
				goto found;
		fp = 0;
found:

		/*
		 * Adjust ip_len to not reflect header,
		 * set ip_mff if more fragments are expected,
		 * convert offset of this to bytes.
		 */
		
		ip->ip_len -= hlen;
		
		((struct ipasfrag *)ip)->ipf_mff = 0;
		
		if (ip->ip_off & IP_MF)
			((struct ipasfrag *)ip)->ipf_mff = 1;
		
		ip->ip_off <<= 3;

		/*
		 * If datagram marked as having more fragments
		 * or if this is not the first fragment,
		 * attempt reassembly; if it succeeds, proceed.
		 */
		
		if (((struct ipasfrag *)ip)->ipf_mff || ip->ip_off)
		  {
		    /* IOdebug( "ipintr: attempting reassembly" ); */
		    
			ipstat.ips_fragments++;
			
			ip = ip_reass((struct ipasfrag *)ip, fp);
			
			if (ip == NULL)
			  {
			    /* IOdebug( "ipintr: attempt failed" ); */
			    
			    goto next;
			  }			
			
			m = dtom(ip);
		  }
		else
			if (fp)
				ip_freef(fp);
	} else
		ip->ip_len -= hlen;
	/*
	 * Switch out to protocol's input routine.
	 */
	
	/* IOdebug( "ipintr: handling packet of len %d", ip->ip_len ); */
	
	(*inetsw[ip_protox[ip->ip_p]].pr_input)(m, ifp);

	/* IOdebug( "ipintr: handled" ); */
	
	goto next;
bad:
	/* IOdebug( "ipintr: bad input" ); */
	
	m_freem(m);
	goto next;
}
示例#11
0
文件: in_arp.c 项目: SbIm/xnu-env
/*
 * Parallel to llc_rtrequest.
 */
static void
arp_rtrequest(
	int req,
	struct rtentry *rt,
	__unused struct sockaddr *sa)
{
	struct sockaddr *gate = rt->rt_gateway;
	struct llinfo_arp *la = rt->rt_llinfo;
	static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK, 0, 0, 0, 0, 0, {0}};
	struct timeval timenow;

	if (!arpinit_done) {
		panic("%s: ARP has not been initialized", __func__);
		/* NOTREACHED */
	}
	lck_mtx_assert(rnh_lock, LCK_MTX_ASSERT_OWNED);
	RT_LOCK_ASSERT_HELD(rt);

	if (rt->rt_flags & RTF_GATEWAY)
		return;
	getmicrotime(&timenow);
	switch (req) {

	case RTM_ADD:
		/*
		 * XXX: If this is a manually added route to interface
		 * such as older version of routed or gated might provide,
		 * restore cloning bit.
		 */
		if ((rt->rt_flags & RTF_HOST) == 0 &&
		    SIN(rt_mask(rt))->sin_addr.s_addr != 0xffffffff)
			rt->rt_flags |= RTF_CLONING;
		if (rt->rt_flags & RTF_CLONING) {
			/*
			 * Case 1: This route should come from a route to iface.
			 */
			if (rt_setgate(rt, rt_key(rt),
			    (struct sockaddr *)&null_sdl) == 0) {
				gate = rt->rt_gateway;
				SDL(gate)->sdl_type = rt->rt_ifp->if_type;
				SDL(gate)->sdl_index = rt->rt_ifp->if_index;
				/*
				 * In case we're called before 1.0 sec.
				 * has elapsed.
				 */
				rt->rt_expire = MAX(timenow.tv_sec, 1);
			}
			break;
		}
		/* Announce a new entry if requested. */
		if (rt->rt_flags & RTF_ANNOUNCE) {
			RT_UNLOCK(rt);
			dlil_send_arp(rt->rt_ifp, ARPOP_REQUEST,
			    SDL(gate), rt_key(rt), NULL, rt_key(rt));
			RT_LOCK(rt);
		}
		/*FALLTHROUGH*/
	case RTM_RESOLVE:
		if (gate->sa_family != AF_LINK ||
		    gate->sa_len < sizeof(null_sdl)) {
		        if (log_arp_warnings)
				log(LOG_DEBUG, "arp_rtrequest: bad gateway value\n");
			break;
		}
		SDL(gate)->sdl_type = rt->rt_ifp->if_type;
		SDL(gate)->sdl_index = rt->rt_ifp->if_index;
		if (la != 0)
			break; /* This happens on a route change */
		/*
		 * Case 2:  This route may come from cloning, or a manual route
		 * add with a LL address.
		 */
		rt->rt_llinfo = la = arp_llinfo_alloc();
		if (la == NULL) {
			if (log_arp_warnings)
				log(LOG_DEBUG, "%s: malloc failed\n", __func__);
			break;
		}
		rt->rt_llinfo_free = arp_llinfo_free;

		arp_inuse++, arp_allocated++;
		Bzero(la, sizeof(*la));
		la->la_rt = rt;
		rt->rt_flags |= RTF_LLINFO;
		LIST_INSERT_HEAD(&llinfo_arp, la, la_le);

		/*
		 * This keeps the multicast addresses from showing up
		 * in `arp -a' listings as unresolved.  It's not actually
		 * functional.  Then the same for broadcast.
		 */
		if (IN_MULTICAST(ntohl(SIN(rt_key(rt))->sin_addr.s_addr))) {
			RT_UNLOCK(rt);
			dlil_resolve_multi(rt->rt_ifp, rt_key(rt), gate,
			    sizeof(struct sockaddr_dl));
			RT_LOCK(rt);
			rt->rt_expire = 0;
		}
		else if (in_broadcast(SIN(rt_key(rt))->sin_addr, rt->rt_ifp)) {
			struct sockaddr_dl	*gate_ll = SDL(gate);
			size_t	broadcast_len;
			ifnet_llbroadcast_copy_bytes(rt->rt_ifp,
			    LLADDR(gate_ll), sizeof(gate_ll->sdl_data),
			    &broadcast_len);
			gate_ll->sdl_alen = broadcast_len;
			gate_ll->sdl_family = AF_LINK;
			gate_ll->sdl_len = sizeof(struct sockaddr_dl);
			/* In case we're called before 1.0 sec. has elapsed */
			rt->rt_expire = MAX(timenow.tv_sec, 1);
		}

		if (SIN(rt_key(rt))->sin_addr.s_addr ==
		    (IA_SIN(rt->rt_ifa))->sin_addr.s_addr) {
		    /*
		     * This test used to be
		     *	if (loif.if_flags & IFF_UP)
		     * It allowed local traffic to be forced
		     * through the hardware by configuring the loopback down.
		     * However, it causes problems during network configuration
		     * for boards that can't receive packets they send.
		     * It is now necessary to clear "useloopback" and remove
		     * the route to force traffic out to the hardware.
		     */
			rt->rt_expire = 0;
			ifnet_lladdr_copy_bytes(rt->rt_ifp, LLADDR(SDL(gate)), SDL(gate)->sdl_alen = 6);
			if (useloopback) {
#if IFNET_ROUTE_REFCNT
				/* Adjust route ref count for the interfaces */
				if (rt->rt_if_ref_fn != NULL &&
				    rt->rt_ifp != lo_ifp) {
					rt->rt_if_ref_fn(lo_ifp, 1);
					rt->rt_if_ref_fn(rt->rt_ifp, -1);
				}
#endif /* IFNET_ROUTE_REFCNT */
				rt->rt_ifp = lo_ifp;
			}

		}
		break;

	case RTM_DELETE:
		if (la == 0)
			break;
		arp_inuse--;
		/*
		 * Unchain it but defer the actual freeing until the route
		 * itself is to be freed.  rt->rt_llinfo still points to
		 * llinfo_arp, and likewise, la->la_rt still points to this
		 * route entry, except that RTF_LLINFO is now cleared.
		 */
		LIST_REMOVE(la, la_le);
		la->la_le.le_next = NULL;
		la->la_le.le_prev = NULL;
		rt->rt_flags &= ~RTF_LLINFO;
		if (la->la_hold != NULL)
			m_freem(la->la_hold);
		la->la_hold = NULL;
	}
}