FreeBSD/sys/netinet6/ip6_input.c
/*
 * get next header offset.  m will be retained.
 */
get next header offset.  m will be retained.
get next header offset . m will be retained .
int
ip6_nexthdr(const struct mbuf *m, int off, int proto, int *nxtp)
{
	struct ip6_hdr ip6;
	struct ip6_ext ip6e;
	struct ip6_frag fh;
	if (m == NULL)
		panic("ip6_nexthdr: m == NULL");
	if ((m->m_flags & M_PKTHDR) == 0 || m->m_pkthdr.len < off)
		return -1;
	switch (proto) {
	case IPPROTO_IPV6:
		if (m->m_pkthdr.len < off + sizeof(ip6))
			return -1;
		m_copydata(m, off, sizeof(ip6), (caddr_t)&ip6);
		if (nxtp)
			*nxtp = ip6.ip6_nxt;
		off += sizeof(ip6);
		return off;
	case IPPROTO_FRAGMENT:
		if (m->m_pkthdr.len < off + sizeof(fh))
			return -1;
		m_copydata(m, off, sizeof(fh), (caddr_t)&fh);
		if (fh.ip6f_offlg & IP6F_OFF_MASK)
			return -1;
		if (nxtp)
			*nxtp = fh.ip6f_nxt;
		off += sizeof(struct ip6_frag);
		return off;
	case IPPROTO_AH:
		if (m->m_pkthdr.len < off + sizeof(ip6e))
			return -1;
		m_copydata(m, off, sizeof(ip6e), (caddr_t)&ip6e);
		if (nxtp)
			*nxtp = ip6e.ip6e_nxt;
		off += (ip6e.ip6e_len + 2) << 2;
		return off;
	case IPPROTO_HOPOPTS:
	case IPPROTO_ROUTING:
	case IPPROTO_DSTOPTS:
		if (m->m_pkthdr.len < off + sizeof(ip6e))
			return -1;
		m_copydata(m, off, sizeof(ip6e), (caddr_t)&ip6e);
		if (nxtp)
			*nxtp = ip6e.ip6e_nxt;
		off += (ip6e.ip6e_len + 1) << 3;
		return off;
	case IPPROTO_NONE:
	case IPPROTO_ESP:
	case IPPROTO_IPCOMP:
		return -1;
	default:
		return -1;
	}
}
int ip6_nexthdr ( const struct mbuf * m , int off , int proto , int * nxtp ) { struct ip6_hdr ip6 ; struct ip6_ext ip6e ; struct ip6_frag fh ; if ( m == NULL ) panic ( " " ) ; if ( ( m -> m_flags & M_PKTHDR ) == 0 || m -> m_pkthdr . len < off ) return -1 ; switch ( proto ) { case IPPROTO_IPV6 : if ( m -> m_pkthdr . len < off + sizeof ( ip6 ) ) return -1 ; m_copydata ( m , off , sizeof ( ip6 ) , ( caddr_t ) & ip6 ) ; if ( nxtp ) * nxtp = ip6 . ip6_nxt ; off += sizeof ( ip6 ) ; return off ; case IPPROTO_FRAGMENT : if ( m -> m_pkthdr . len < off + sizeof ( fh ) ) return -1 ; m_copydata ( m , off , sizeof ( fh ) , ( caddr_t ) & fh ) ; if ( fh . ip6f_offlg & IP6F_OFF_MASK ) return -1 ; if ( nxtp ) * nxtp = fh . ip6f_nxt ; off += sizeof ( struct ip6_frag ) ; return off ; case IPPROTO_AH : if ( m -> m_pkthdr . len < off + sizeof ( ip6e ) ) return -1 ; m_copydata ( m , off , sizeof ( ip6e ) , ( caddr_t ) & ip6e ) ; if ( nxtp ) * nxtp = ip6e . ip6e_nxt ; off += ( ip6e . ip6e_len + 2 ) << 2 ; return off ; case IPPROTO_HOPOPTS : case IPPROTO_ROUTING : case IPPROTO_DSTOPTS : if ( m -> m_pkthdr . len < off + sizeof ( ip6e ) ) return -1 ; m_copydata ( m , off , sizeof ( ip6e ) , ( caddr_t ) & ip6e ) ; if ( nxtp ) * nxtp = ip6e . ip6e_nxt ; off += ( ip6e . ip6e_len + 1 ) << 3 ; return off ; case IPPROTO_NONE : case IPPROTO_ESP : case IPPROTO_IPCOMP : return -1 ; default : return -1 ; } }
get next header offset.
get next header offset .
/* just in case */ /*
		 * terminate parsing if it is not the first fragment,
		 * it does not make sense to parse through it.
		 */ /* IP6F_OFF_MASK = 0xfff8(BigEndian), 0xf8ff(LittleEndian) */ /* give up */ /* NOTREACHED */