コード例 #1
0
ファイル: udp_usrreq.c プロジェクト: sofuture/bitrig
void
udp_input(struct mbuf *m, ...)
{
	struct ip *ip;
	struct udphdr *uh;
	struct inpcb *inp = NULL;
	struct mbuf *opts = NULL;
	struct ip save_ip;
	int iphlen, len;
	va_list ap;
	u_int16_t savesum;
	union {
		struct sockaddr sa;
		struct sockaddr_in sin;
#ifdef INET6
		struct sockaddr_in6 sin6;
#endif /* INET6 */
	} srcsa, dstsa;
#ifdef INET6
	struct ip6_hdr *ip6;
#endif /* INET6 */
#ifdef IPSEC
	struct m_tag *mtag;
	struct tdb_ident *tdbi;
	struct tdb *tdb;
	int error, s;
#endif /* IPSEC */

	va_start(ap, m);
	iphlen = va_arg(ap, int);
	va_end(ap);

	udpstat.udps_ipackets++;

	switch (mtod(m, struct ip *)->ip_v) {
	case 4:
		ip = mtod(m, struct ip *);
#ifdef INET6
		ip6 = NULL;
#endif /* INET6 */
		srcsa.sa.sa_family = AF_INET;
		break;
#ifdef INET6
	case 6:
		ip = NULL;
		ip6 = mtod(m, struct ip6_hdr *);
		srcsa.sa.sa_family = AF_INET6;
		break;
#endif /* INET6 */
	default:
		goto bad;
	}

	IP6_EXTHDR_GET(uh, struct udphdr *, m, iphlen, sizeof(struct udphdr));
	if (!uh) {
		udpstat.udps_hdrops++;
		return;
	}

	/* Check for illegal destination port 0 */
	if (uh->uh_dport == 0) {
		udpstat.udps_noport++;
		goto bad;
	}

	/*
	 * Make mbuf data length reflect UDP length.
	 * If not enough data to reflect UDP length, drop.
	 */
	len = ntohs((u_int16_t)uh->uh_ulen);
	if (ip) {
		if (m->m_pkthdr.len - iphlen != len) {
			if (len > (m->m_pkthdr.len - iphlen) ||
			    len < sizeof(struct udphdr)) {
				udpstat.udps_badlen++;
				goto bad;
			}
			m_adj(m, len - (m->m_pkthdr.len - iphlen));
		}
	}
#ifdef INET6
	else if (ip6) {
		/* jumbograms */
		if (len == 0 && m->m_pkthdr.len - iphlen > 0xffff)
			len = m->m_pkthdr.len - iphlen;
		if (len != m->m_pkthdr.len - iphlen) {
			udpstat.udps_badlen++;
			goto bad;
		}
	}
#endif
	else /* shouldn't happen */
		goto bad;

	/*
	 * Save a copy of the IP header in case we want restore it
	 * for sending an ICMP error message in response.
	 */
	if (ip)
		save_ip = *ip;

	/*
	 * Checksum extended UDP header and data.
	 * from W.R.Stevens: check incoming udp cksums even if
	 *	udpcksum is not set.
	 */
	savesum = uh->uh_sum;
#ifdef INET6
	if (ip6) {
		/* Be proactive about malicious use of IPv4 mapped address */
		if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) ||
		    IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) {
			/* XXX stat */
			goto bad;
		}

		/*
		 * In IPv6, the UDP checksum is ALWAYS used.
		 */
		if (uh->uh_sum == 0) {
			udpstat.udps_nosum++;
			goto bad;
		}
		if ((m->m_pkthdr.csum_flags & M_UDP_CSUM_IN_OK) == 0) {
			if (m->m_pkthdr.csum_flags & M_UDP_CSUM_IN_BAD) {
				udpstat.udps_badsum++;
				udpstat.udps_inhwcsum++;
				goto bad;
			}

			if ((uh->uh_sum = in6_cksum(m, IPPROTO_UDP,
			    iphlen, len))) {
				udpstat.udps_badsum++;
				goto bad;
			}
		} else {
			m->m_pkthdr.csum_flags &= ~M_UDP_CSUM_IN_OK;
			udpstat.udps_inhwcsum++;
		}
	} else
#endif /* INET6 */
	if (uh->uh_sum) {
		if ((m->m_pkthdr.csum_flags & M_UDP_CSUM_IN_OK) == 0) {
			if (m->m_pkthdr.csum_flags & M_UDP_CSUM_IN_BAD) {
				udpstat.udps_badsum++;
				udpstat.udps_inhwcsum++;
				m_freem(m);
				return;
			}

			if ((uh->uh_sum = in4_cksum(m, IPPROTO_UDP,
			    iphlen, len))) {
				udpstat.udps_badsum++;
				m_freem(m);
				return;
			}
		} else {
			m->m_pkthdr.csum_flags &= ~M_UDP_CSUM_IN_OK;
			udpstat.udps_inhwcsum++;
		}
	} else
		udpstat.udps_nosum++;

#ifdef IPSEC
	if (udpencap_enable && udpencap_port &&
	    uh->uh_dport == htons(udpencap_port)) {
		u_int32_t spi;
		int skip = iphlen + sizeof(struct udphdr);

		if (m->m_pkthdr.len - skip < sizeof(u_int32_t)) {
			/* packet too short */
			m_freem(m);
			return;
		}
		m_copydata(m, skip, sizeof(u_int32_t), (caddr_t) &spi);
		/*
		 * decapsulate if the SPI is not zero, otherwise pass
		 * to userland
		 */
		if (spi != 0) {
			if ((m = m_pullup(m, skip)) == NULL) {
				udpstat.udps_hdrops++;
				return;
			}

			/* remove the UDP header */
			bcopy(mtod(m, u_char *),
			    mtod(m, u_char *) + sizeof(struct udphdr), iphlen);
			m_adj(m, sizeof(struct udphdr));
			skip -= sizeof(struct udphdr);

			espstat.esps_udpencin++;
			ipsec_common_input(m, skip, offsetof(struct ip, ip_p),
			    srcsa.sa.sa_family, IPPROTO_ESP, 1);
			return;
		}
	}
コード例 #2
0
ファイル: if_enc.c プロジェクト: coyizumi/cs111
int
ipsec_filter(struct mbuf **mp, int dir, int flags)
{
	int error, i;
	struct ip *ip;

	KASSERT(encif != NULL, ("%s: encif is null", __func__));
	KASSERT(flags & (ENC_IN|ENC_OUT),
		("%s: invalid flags: %04x", __func__, flags));

	if ((encif->if_drv_flags & IFF_DRV_RUNNING) == 0)
		return (0);

	if (flags & ENC_IN) {
		if ((flags & ipsec_filter_mask_in) == 0)
			return (0);
	} else {
		if ((flags & ipsec_filter_mask_out) == 0)
			return (0);
	}

	/* Skip pfil(9) if no filters are loaded */
	if (1
#ifdef INET
	    && !PFIL_HOOKED(&V_inet_pfil_hook)
#endif
#ifdef INET6
	    && !PFIL_HOOKED(&V_inet6_pfil_hook)
#endif
	    ) {
		return (0);
	}

	i = min((*mp)->m_pkthdr.len, max_protohdr);
	if ((*mp)->m_len < i) {
		*mp = m_pullup(*mp, i);
		if (*mp == NULL) {
			printf("%s: m_pullup failed\n", __func__);
			return (-1);
		}
	}

	error = 0;
	ip = mtod(*mp, struct ip *);
	switch (ip->ip_v) {
#ifdef INET
		case 4:
			error = pfil_run_hooks(&V_inet_pfil_hook, mp,
			    encif, dir, NULL);
			break;
#endif
#ifdef INET6
		case 6:
			error = pfil_run_hooks(&V_inet6_pfil_hook, mp,
			    encif, dir, NULL);
			break;
#endif
		default:
			printf("%s: unknown IP version\n", __func__);
	}

	/*
	 * If the mbuf was consumed by the filter for requeueing (dummynet, etc)
	 * then error will be zero but we still want to return an error to our
	 * caller so the null mbuf isn't forwarded further.
	 */
	if (*mp == NULL && error == 0)
		return (-1);	/* Consumed by the filter */
	if (*mp == NULL)
		return (error);
	if (error != 0)
		goto bad;

	return (error);

bad:
	m_freem(*mp);
	*mp = NULL;
	return (error);
}
コード例 #3
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;
}
コード例 #4
0
ファイル: ipx_input.c プロジェクト: akash028/Ns3
/*
 * IPX input routine.  Pass to next level.
 */
void
ipxintr()
{
    struct ipx *ipx;
    struct mbuf *m;
    struct ipxpcb *ipxp;
    struct ipx_ifaddr *ia;
    int len, s;

next:
    /*
     * Get next datagram off input queue and get IPX header
     * in first mbuf.
     */
    s = splimp();
    IF_DEQUEUE(&ipxintrq, m);
    splx(s);
    if (m == NULL) {
        return;
    }

    ipxstat.ipxs_total++;

    if ((m->m_flags & M_EXT || m->m_len < sizeof(struct ipx)) &&
            (m = m_pullup(m, sizeof(struct ipx))) == 0) {
        ipxstat.ipxs_toosmall++;
        goto next;
    }

    /*
     * Give any raw listeners a crack at the packet
     */
    for (ipxp = ipxrawcbtable.ipxpt_queue.cqh_first;
            ipxp != (struct ipxpcb *)&ipxrawcbtable.ipxpt_queue;
            ipxp = ipxp->ipxp_queue.cqe_next) {
        struct mbuf *m1 = m_copy(m, 0, (int)M_COPYALL);
        if (m1)
            ipx_input(m1, ipxp);
    }

    ipx = mtod(m, struct ipx *);
    len = ntohs(ipx->ipx_len);
    /*
     * Check that the amount of data in the buffers
     * is as at least much as the IPX header would have us expect.
     * Trim mbufs if longer than we expect.
     * Drop packet if shorter than we expect.
     */
    if (m->m_pkthdr.len < len) {
        ipxstat.ipxs_tooshort++;
        goto bad;
    }
    if (m->m_pkthdr.len > len) {
        if (m->m_len == m->m_pkthdr.len) {
            m->m_len = len;
            m->m_pkthdr.len = len;
        } else
            m_adj(m, len - m->m_pkthdr.len);
    }
    if (ipxcksum && ipx->ipx_sum != 0xffff) {
        if (ipx->ipx_sum != ipx_cksum(m, len)) {
            ipxstat.ipxs_badsum++;
            goto bad;
        }
    }

    /*
     * Propagated (Netbios) packets (type 20) has to be handled
     * different. :-(
     */
    if (ipx->ipx_pt == IPXPROTO_NETBIOS) {
        if (ipxnetbios) {
            ipx_output_type20(m);
            goto next;
        } else
            goto bad;
    }

    /*
     * Is this a directed broadcast?
     */
    if (ipx_hosteqnh(ipx_broadhost,ipx->ipx_dna.ipx_host)) {
        if ((!ipx_neteq(ipx->ipx_dna, ipx->ipx_sna)) &&
                (!ipx_neteqnn(ipx->ipx_dna.ipx_net, ipx_broadnet)) &&
                (!ipx_neteqnn(ipx->ipx_sna.ipx_net, ipx_zeronet)) &&
                (!ipx_neteqnn(ipx->ipx_dna.ipx_net, ipx_zeronet)) ) {
            /*
             * If it is a broadcast to the net where it was
             * received from, treat it as ours.
             */
            for (ia = ipx_ifaddr.tqh_first; ia;
                    ia = ia->ia_list.tqe_next)
                if((ia->ia_ifa.ifa_ifp == m->m_pkthdr.rcvif) &&
                        ipx_neteq(ia->ia_addr.sipx_addr,
                                  ipx->ipx_dna))
                    goto ours;

            /*
             * Look to see if I need to eat this packet.
             * Algorithm is to forward all young packets
             * and prematurely age any packets which will
             * by physically broadcasted.
             * Any very old packets eaten without forwarding
             * would die anyway.
             *
             * Suggestion of Bill Nesheim, Cornell U.
             */
            if (ipx->ipx_tc < IPX_MAXHOPS) {
                ipx_forward(m);
                goto next;
            }
        }
        /*
         * Is this our packet? If not, forward.
         */
    } else {
        for (ia = ipx_ifaddr.tqh_first; ia; ia = ia->ia_list.tqe_next)
            if (ipx_hosteq(ipx->ipx_dna, ia->ia_addr.sipx_addr) &&
                    (ipx_neteq(ipx->ipx_dna, ia->ia_addr.sipx_addr) ||
                     ipx_neteqnn(ipx->ipx_dna.ipx_net, ipx_zeronet)))
                break;

        if (ia == NULL) {
            ipx_forward(m);
            goto next;
        }
    }
ours:
    /*
     * Locate pcb for datagram.
     */
    ipxp = ipx_pcblookup(&ipx->ipx_sna, ipx->ipx_dna.ipx_port,
                         IPX_WILDCARD);
    /*
     * Switch out to protocol's input routine.
     */
    if (ipxp) {
        ipxstat.ipxs_delivered++;
        if ((ipxp->ipxp_flags & IPXP_ALL_PACKETS) == 0)
            switch (ipx->ipx_pt) {

            case IPXPROTO_SPX:
                spx_input(m, ipxp);
                goto next;
            }
        ipx_input(m, ipxp);
    } else
        goto bad;

    goto next;

bad:
    m_freem(m);
    goto next;
}
コード例 #5
0
int
gre_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
           struct rtentry *rt)
{
    int error = 0;
    struct gre_softc *sc = (struct gre_softc *) (ifp->if_softc);
    struct greip *gh = NULL;
    struct ip *inp = NULL;
    u_int8_t ip_tos = 0;
    u_int16_t etype = 0;
    struct mobile_h mob_h;
    struct m_tag *mtag;

    if ((ifp->if_flags & IFF_UP) == 0 ||
            sc->g_src.s_addr == INADDR_ANY || sc->g_dst.s_addr == INADDR_ANY) {
        m_freem(m);
        error = ENETDOWN;
        goto end;
    }

    /* Try to limit infinite recursion through misconfiguration. */
    for (mtag = m_tag_find(m, PACKET_TAG_GRE, NULL); mtag;
            mtag = m_tag_find(m, PACKET_TAG_GRE, mtag)) {
        if (!bcmp((caddr_t)(mtag + 1), &ifp, sizeof(struct ifnet *))) {
            IF_DROP(&ifp->if_snd);
            m_freem(m);
            error = EIO;
            goto end;
        }
    }

    mtag = m_tag_get(PACKET_TAG_GRE, sizeof(struct ifnet *), M_NOWAIT);
    if (mtag == NULL) {
        IF_DROP(&ifp->if_snd);
        m_freem(m);
        error = ENOBUFS;
        goto end;
    }
    bcopy(&ifp, (caddr_t)(mtag + 1), sizeof(struct ifnet *));
    m_tag_prepend(m, mtag);

    m->m_flags &= ~(M_BCAST|M_MCAST);

#if NBPFILTER >0
    if (ifp->if_bpf)
        bpf_mtap_af(ifp->if_bpf, dst->sa_family, m, BPF_DIRECTION_OUT);
#endif

    if (sc->g_proto == IPPROTO_MOBILE) {
        if (ip_mobile_allow == 0) {
            IF_DROP(&ifp->if_snd);
            m_freem(m);
            error = EACCES;
            goto end;
        }

        if (dst->sa_family == AF_INET) {
            struct mbuf *m0;
            int msiz;

            /*
             * Make sure the complete IP header (with options)
             * is in the first mbuf.
             */
            if (m->m_len < sizeof(struct ip)) {
                m = m_pullup(m, sizeof(struct ip));
                if (m == NULL) {
                    IF_DROP(&ifp->if_snd);
                    error = ENOBUFS;
                    goto end;
                } else
                    inp = mtod(m, struct ip *);

                if (m->m_len < inp->ip_hl << 2) {
                    m = m_pullup(m, inp->ip_hl << 2);
                    if (m == NULL) {
                        IF_DROP(&ifp->if_snd);
                        error = ENOBUFS;
                        goto end;
                    }
                }
            }

            inp = mtod(m, struct ip *);

            bzero(&mob_h, MOB_H_SIZ_L);
            mob_h.proto = (inp->ip_p) << 8;
            mob_h.odst = inp->ip_dst.s_addr;
            inp->ip_dst.s_addr = sc->g_dst.s_addr;

            /*
             * If the packet comes from our host, we only change
             * the destination address in the IP header.
             * Otherwise we need to save and change the source.
             */
            if (inp->ip_src.s_addr == sc->g_src.s_addr) {
                msiz = MOB_H_SIZ_S;
            } else {
                mob_h.proto |= MOB_H_SBIT;
                mob_h.osrc = inp->ip_src.s_addr;
                inp->ip_src.s_addr = sc->g_src.s_addr;
                msiz = MOB_H_SIZ_L;
            }

            HTONS(mob_h.proto);
            mob_h.hcrc = gre_in_cksum((u_int16_t *) &mob_h, msiz);

            /* Squeeze in the mobility header */
            if ((m->m_data - msiz) < m->m_pktdat) {
                /* Need new mbuf */
                MGETHDR(m0, M_DONTWAIT, MT_HEADER);
                if (m0 == NULL) {
                    IF_DROP(&ifp->if_snd);
                    m_freem(m);
                    error = ENOBUFS;
                    goto end;
                }
                M_MOVE_HDR(m0, m);

                m0->m_len = msiz + (inp->ip_hl << 2);
                m0->m_data += max_linkhdr;
                m0->m_pkthdr.len = m->m_pkthdr.len + msiz;
                m->m_data += inp->ip_hl << 2;
                m->m_len -= inp->ip_hl << 2;

                bcopy((caddr_t) inp, mtod(m0, caddr_t),
                      sizeof(struct ip));

                m0->m_next = m;
                m = m0;
            } else {  /* we have some space left in the old one */
                m->m_data -= msiz;
                m->m_len += msiz;
                m->m_pkthdr.len += msiz;
                bcopy(inp, mtod(m, caddr_t),
                      inp->ip_hl << 2);
            }

            /* Copy Mobility header */
            inp = mtod(m, struct ip *);
            bcopy(&mob_h, (caddr_t)(inp + 1), (unsigned) msiz);
            inp->ip_len = htons(ntohs(inp->ip_len) + msiz);
        } else {  /* AF_INET */