コード例 #1
0
int ipv6_skip_exthdr(const struct sk_buff *skb, int start, u8 *nexthdrp)
{
	u8 nexthdr = *nexthdrp;

	while (ipv6_ext_hdr(nexthdr)) {
		struct ipv6_opt_hdr _hdr, *hp;
		int hdrlen;

		if (nexthdr == NEXTHDR_NONE)
			return -1;
		hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr);
		if (hp == NULL)
			return -1;
		if (nexthdr == NEXTHDR_FRAGMENT) {
			unsigned short _frag_off, *fp;
			fp = skb_header_pointer(skb,
						start+offsetof(struct frag_hdr,
							       frag_off),
						sizeof(_frag_off),
						&_frag_off);
			if (fp == NULL)
				return -1;

			if (ntohs(*fp) & ~0x7)
				break;
			hdrlen = 8;
		} else if (nexthdr == NEXTHDR_AUTH)
コード例 #2
0
int nf_ct_ipv6_skip_exthdr(struct sk_buff *skb, int start, u8 *nexthdrp,
			   int len)
{
	u8 nexthdr = *nexthdrp;

	while (ipv6_ext_hdr(nexthdr)) {
		struct ipv6_opt_hdr hdr;
		int hdrlen;

		if (len < (int)sizeof(struct ipv6_opt_hdr))
			return -1;
		if (nexthdr == NEXTHDR_NONE)
			break;
		if (nexthdr == NEXTHDR_FRAGMENT)
			break;
		if (skb_copy_bits(skb, start, &hdr, sizeof(hdr)))
			BUG();
		if (nexthdr == NEXTHDR_AUTH)
			hdrlen = (hdr.hdrlen+2)<<2;
		else
			hdrlen = ipv6_optlen(&hdr);

		nexthdr = hdr.nexthdr;
		len -= hdrlen;
		start += hdrlen;
	}

	*nexthdrp = nexthdr;
	return start;
}
コード例 #3
0
int qta_ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
		  int target, unsigned short *fragoff)
{
	unsigned int start = skb_network_offset(skb) + sizeof(struct ipv6hdr);
	u8 nexthdr = ipv6_hdr(skb)->nexthdr;
	unsigned int len = skb->len - start;

	if (fragoff)
		*fragoff = 0;

	while (nexthdr != target) {
		struct ipv6_opt_hdr _hdr, *hp;
		unsigned int hdrlen;

		if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE) {
			if (target < 0)
				break;
			return -ENOENT;
		}

		hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr);
		if (hp == NULL)
			return -EBADMSG;
		if (nexthdr == NEXTHDR_FRAGMENT) {
			unsigned short _frag_off;
			__be16 *fp;
			fp = skb_header_pointer(skb,
						start+offsetof(struct frag_hdr,
							       frag_off),
						sizeof(_frag_off),
						&_frag_off);
			if (fp == NULL)
				return -EBADMSG;

			_frag_off = ntohs(*fp) & ~0x7;
			if (_frag_off) {
				if (target < 0 &&
				    ((!ipv6_ext_hdr(hp->nexthdr)) ||
				     hp->nexthdr == NEXTHDR_NONE)) {
					if (fragoff)
						*fragoff = _frag_off;
					return hp->nexthdr;
				}
				return -ENOENT;
			}
			hdrlen = 8;
		} else if (nexthdr == NEXTHDR_AUTH)
コード例 #4
0
ファイル: ip6_output.c プロジェクト: guanhe0/kernel
static int ip6_forward_proxy_check(struct sk_buff *skb)
{
	struct ipv6hdr *hdr = ipv6_hdr(skb);
	u8 nexthdr = hdr->nexthdr;
	__be16 frag_off;
	int offset;

	if (ipv6_ext_hdr(nexthdr)) {
		offset = ipv6_skip_exthdr(skb, sizeof(*hdr), &nexthdr, &frag_off);
		if (offset < 0)
			return 0;
	} else
		offset = sizeof(struct ipv6hdr);

	if (nexthdr == IPPROTO_ICMPV6) {
		struct icmp6hdr *icmp6;

		if (!pskb_may_pull(skb, (skb_network_header(skb) +
					 offset + 1 - skb->data)))
			return 0;

		icmp6 = (struct icmp6hdr *)(skb_network_header(skb) + offset);

		switch (icmp6->icmp6_type) {
		case NDISC_ROUTER_SOLICITATION:
		case NDISC_ROUTER_ADVERTISEMENT:
		case NDISC_NEIGHBOUR_SOLICITATION:
		case NDISC_NEIGHBOUR_ADVERTISEMENT:
		case NDISC_REDIRECT:
			/* For reaction involving unicast neighbor discovery
			 * message destined to the proxied address, pass it to
			 * input function.
			 */
			return 1;
		default:
			break;
		}
	}

	/*
	 * The proxying router can't forward traffic sent to a link-local
	 * address, so signal the sender and discard the packet. This
	 * behavior is clarified by the MIPv6 specification.
	 */
	if (ipv6_addr_type(&hdr->daddr) & IPV6_ADDR_LINKLOCAL) {
		dst_link_failure(skb);
		return -1;
	}

	return 0;
}
コード例 #5
0
static __u16
parse_tlv_tnl_enc_lim(struct sk_buff *skb, __u8 * raw)
{
	struct ipv6hdr *ipv6h = (struct ipv6hdr *) raw;
	__u8 nexthdr = ipv6h->nexthdr;
	__u16 off = sizeof (*ipv6h);

	while (ipv6_ext_hdr(nexthdr) && nexthdr != NEXTHDR_NONE) {
		__u16 optlen = 0;
		struct ipv6_opt_hdr *hdr;
		if (raw + off + sizeof (*hdr) > skb->data &&
		    !pskb_may_pull(skb, raw - skb->data + off + sizeof (*hdr)))
			break;

		hdr = (struct ipv6_opt_hdr *) (raw + off);
		if (nexthdr == NEXTHDR_FRAGMENT) {
			struct frag_hdr *frag_hdr = (struct frag_hdr *) hdr;
			if (frag_hdr->frag_off)
				break;
			optlen = 8;
		} else if (nexthdr == NEXTHDR_AUTH) {
			optlen = (hdr->hdrlen + 2) << 2;
		} else {
			optlen = ipv6_optlen(hdr);
		}
		if (nexthdr == NEXTHDR_DEST) {
			__u16 i = off + 2;
			while (1) {
				struct ipv6_tlv_tnl_enc_lim *tel;

				/* No more room for encapsulation limit */
				if (i + sizeof (*tel) > off + optlen)
					break;

				tel = (struct ipv6_tlv_tnl_enc_lim *) &raw[i];
				/* return index of option if found and valid */
				if (tel->type == IPV6_TLV_TNL_ENCAP_LIMIT &&
				    tel->length == 1)
					return i;
				/* else jump to next option */
				if (tel->type)
					i += tel->length + 2;
				else
					i++;
			}
		}
		nexthdr = hdr->nexthdr;
		off += optlen;
	}
	return 0;
}
コード例 #6
0
ファイル: ixgbe_ipsec.c プロジェクト: lumag/linux
/**
 * ixgbe_ipsec_offload_ok - can this packet use the xfrm hw offload
 * @skb: current data packet
 * @xs: pointer to transformer state struct
 **/
static bool ixgbe_ipsec_offload_ok(struct sk_buff *skb, struct xfrm_state *xs)
{
	if (xs->props.family == AF_INET) {
		/* Offload with IPv4 options is not supported yet */
		if (ip_hdr(skb)->ihl != 5)
			return false;
	} else {
		/* Offload with IPv6 extension headers is not support yet */
		if (ipv6_ext_hdr(ipv6_hdr(skb)->nexthdr))
			return false;
	}

	return true;
}
コード例 #7
0
/*
 * find the header just before Fragment Header.
 *
 * if success return 0 and set ...
 * (*prevhdrp): the value of "Next Header Field" in the header
 *		just before Fragment Header.
 * (*prevhoff): the offset of "Next Header Field" in the header
 *		just before Fragment Header.
 * (*fhoff)   : the offset of Fragment Header.
 *
 * Based on ipv6_skip_hdr() in net/ipv6/exthdr.c
 *
 */
static int
find_prev_fhdr(struct sk_buff *skb, u8 *prevhdrp, int *prevhoff, int *fhoff)
{
        u8 nexthdr = skb->nh.ipv6h->nexthdr;
	u8 prev_nhoff = (u8 *)&skb->nh.ipv6h->nexthdr - skb->data;
	int start = (u8 *)(skb->nh.ipv6h+1) - skb->data;
	int len = skb->len - start;
	u8 prevhdr = NEXTHDR_IPV6;

        while (nexthdr != NEXTHDR_FRAGMENT) {
                struct ipv6_opt_hdr hdr;
                int hdrlen;

		if (!ipv6_ext_hdr(nexthdr)) {
			return -1;
		}
                if (len < (int)sizeof(struct ipv6_opt_hdr)) {
			DEBUGP("too short\n");
			return -1;
		}
                if (nexthdr == NEXTHDR_NONE) {
			DEBUGP("next header is none\n");
			return -1;
		}
                if (skb_copy_bits(skb, start, &hdr, sizeof(hdr)))
                        BUG();
                if (nexthdr == NEXTHDR_AUTH)
                        hdrlen = (hdr.hdrlen+2)<<2;
                else
                        hdrlen = ipv6_optlen(&hdr);

		prevhdr = nexthdr;
		prev_nhoff = start;

                nexthdr = hdr.nexthdr;
                len -= hdrlen;
                start += hdrlen;
        }

	if (len < 0)
		return -1;

	*prevhdrp = prevhdr;
	*prevhoff = prev_nhoff;
	*fhoff = start;

	return 0;
}
コード例 #8
0
int ip6_mc_input(struct sk_buff *skb)
{
	struct ipv6hdr *hdr;
	int deliver;

	IP6_INC_STATS_BH(dev_net(skb->dst->dev),
			 ip6_dst_idev(skb->dst), IPSTATS_MIB_INMCASTPKTS);

	hdr = ipv6_hdr(skb);
	deliver = ipv6_chk_mcast_addr(skb->dev, &hdr->daddr, NULL);

    /* <DTS2012071401081  w00211169 2012-7-14 begin */
#if 1   
    if(!deliver && (skb->dev->flags & IFF_MULTICAST) 
        && (IPPROTO_ICMPV6 == hdr->nexthdr)
        && !strcmp(skb->dev->name, "rmnet0"))
    {
        if (NDISC_NEIGHBOUR_SOLICITATION == icmp6_hdr(skb)->icmp6_type)
        {
            ip6_input_icmp_cheat(skb);
            return 0;
        }
    }
#endif    
    /* DTS2012071401081  w00211169 2012-7-14 end> */
       
#ifdef CONFIG_IPV6_MROUTE
	/*
	 *      IPv6 multicast router mode is now supported ;)
	 */
	if (dev_net(skb->dev)->ipv6.devconf_all->mc_forwarding &&
	    !(ipv6_addr_type(&hdr->daddr) & IPV6_ADDR_LINKLOCAL) &&
	    likely(!(IP6CB(skb)->flags & IP6SKB_FORWARDED))) {
		/*
		 * Okay, we try to forward - split and duplicate
		 * packets.
		 */
		struct sk_buff *skb2;
		struct inet6_skb_parm *opt = IP6CB(skb);

		/* Check for MLD */
		if (unlikely(opt->ra)) {
			/* Check if this is a mld message */
			u8 *ptr = skb_network_header(skb) + opt->ra;
			struct icmp6hdr *icmp6;
			u8 nexthdr = hdr->nexthdr;
			int offset;

			/* Check if the value of Router Alert
			 * is for MLD (0x0000).
			 */
			if ((ptr[2] | ptr[3]) == 0) {
				deliver = 0;

				if (!ipv6_ext_hdr(nexthdr)) {
					/* BUG */
					goto out;
				}
				offset = ipv6_skip_exthdr(skb, sizeof(*hdr),
							  &nexthdr);
				if (offset < 0)
					goto out;

				if (nexthdr != IPPROTO_ICMPV6)
					goto out;

				if (!pskb_may_pull(skb, (skb_network_header(skb) +
						   offset + 1 - skb->data)))
					goto out;

				icmp6 = (struct icmp6hdr *)(skb_network_header(skb) + offset);

				switch (icmp6->icmp6_type) {
				case ICMPV6_MGM_QUERY:
				case ICMPV6_MGM_REPORT:
				case ICMPV6_MGM_REDUCTION:
				case ICMPV6_MLD2_REPORT:
					deliver = 1;
					break;
				}
				goto out;
			}
			/* unknown RA - process it normally */
		}

		if (deliver)
			skb2 = skb_clone(skb, GFP_ATOMIC);
		else {
			skb2 = skb;
			skb = NULL;
		}

		if (skb2) {
			ip6_mr_input(skb2);
		}
	}
out:
#endif
	if (likely(deliver))
		ip6_input(skb);
	else {
		/* discard */
		kfree_skb(skb);
	}

	return 0;
}
コード例 #9
0
ファイル: ip6_input.c プロジェクト: oldzhu/linux
int ip6_mc_input(struct sk_buff *skb)
{
    const struct ipv6hdr *hdr;
    bool deliver;

    __IP6_UPD_PO_STATS(dev_net(skb_dst(skb)->dev),
                       ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_INMCAST,
                       skb->len);

    hdr = ipv6_hdr(skb);
    deliver = ipv6_chk_mcast_addr(skb->dev, &hdr->daddr, NULL);

#ifdef CONFIG_IPV6_MROUTE
    /*
     *      IPv6 multicast router mode is now supported ;)
     */
    if (dev_net(skb->dev)->ipv6.devconf_all->mc_forwarding &&
            !(ipv6_addr_type(&hdr->daddr) &
              (IPV6_ADDR_LOOPBACK|IPV6_ADDR_LINKLOCAL)) &&
            likely(!(IP6CB(skb)->flags & IP6SKB_FORWARDED))) {
        /*
         * Okay, we try to forward - split and duplicate
         * packets.
         */
        struct sk_buff *skb2;
        struct inet6_skb_parm *opt = IP6CB(skb);

        /* Check for MLD */
        if (unlikely(opt->flags & IP6SKB_ROUTERALERT)) {
            /* Check if this is a mld message */
            u8 nexthdr = hdr->nexthdr;
            __be16 frag_off;
            int offset;

            /* Check if the value of Router Alert
             * is for MLD (0x0000).
             */
            if (opt->ra == htons(IPV6_OPT_ROUTERALERT_MLD)) {
                deliver = false;

                if (!ipv6_ext_hdr(nexthdr)) {
                    /* BUG */
                    goto out;
                }
                offset = ipv6_skip_exthdr(skb, sizeof(*hdr),
                                          &nexthdr, &frag_off);
                if (offset < 0)
                    goto out;

                if (ipv6_is_mld(skb, nexthdr, offset))
                    deliver = true;

                goto out;
            }
            /* unknown RA - process it normally */
        }

        if (deliver)
            skb2 = skb_clone(skb, GFP_ATOMIC);
        else {
            skb2 = skb;
            skb = NULL;
        }

        if (skb2) {
            ip6_mr_input(skb2);
        }
    }
out:
#endif
    if (likely(deliver))
        ip6_input(skb);
    else {
        /* discard */
        kfree_skb(skb);
    }

    return 0;
}
コード例 #10
0
int ip6_mc_input(struct sk_buff *skb)
{
	const struct ipv6hdr *hdr;
	int deliver;

	IP6_UPD_PO_STATS_BH(dev_net(skb_dst(skb)->dev),
			 ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_INMCAST,
			 skb->len);

	hdr = ipv6_hdr(skb);
	deliver = ipv6_chk_mcast_addr(skb->dev, &hdr->daddr, NULL);

#ifdef CONFIG_IPV6_MROUTE
	/*
	 *      IPv6 multicast router mode is now supported ;)
	 */
	if (dev_net(skb->dev)->ipv6.devconf_all->mc_forwarding &&
	    !(ipv6_addr_type(&hdr->daddr) &
	      (IPV6_ADDR_LOOPBACK|IPV6_ADDR_LINKLOCAL)) &&
	    likely(!(IP6CB(skb)->flags & IP6SKB_FORWARDED))) {
		/*
		 * Okay, we try to forward - split and duplicate
		 * packets.
		 */
		struct sk_buff *skb2;
		struct inet6_skb_parm *opt = IP6CB(skb);

		/* Check for MLD */
		if (unlikely(opt->ra)) {
			/* Check if this is a mld message */
			u8 *ptr = skb_network_header(skb) + opt->ra;
			struct icmp6hdr *icmp6;
			u8 nexthdr = hdr->nexthdr;
			__be16 frag_off;
			int offset;

			/* Check if the value of Router Alert
			 * is for MLD (0x0000).
			 */
			if ((ptr[2] | ptr[3]) == 0) {
				deliver = 0;

				if (!ipv6_ext_hdr(nexthdr)) {
					/* BUG */
					goto out;
				}
				offset = ipv6_skip_exthdr(skb, sizeof(*hdr),
							  &nexthdr, &frag_off);
				if (offset < 0)
					goto out;

				if (nexthdr != IPPROTO_ICMPV6)
					goto out;

				if (!pskb_may_pull(skb, (skb_network_header(skb) +
						   offset + 1 - skb->data)))
					goto out;

				icmp6 = (struct icmp6hdr *)(skb_network_header(skb) + offset);

				switch (icmp6->icmp6_type) {
				case ICMPV6_MGM_QUERY:
				case ICMPV6_MGM_REPORT:
				case ICMPV6_MGM_REDUCTION:
				case ICMPV6_MLD2_REPORT:
					deliver = 1;
					break;
				}
				goto out;
			}
			
		}

		if (deliver)
			skb2 = skb_clone(skb, GFP_ATOMIC);
		else {
			skb2 = skb;
			skb = NULL;
		}

		if (skb2) {
			ip6_mr_input(skb2);
		}
	}
out:
#endif
	if (likely(deliver))
		ip6_input(skb);
	else {
		
		kfree_skb(skb);
	}

	return 0;
}
コード例 #11
0
static int
match(const struct sk_buff *skb,
      const struct net_device *in,
      const struct net_device *out,
      const void *matchinfo,
      int offset,
      const void *protohdr,
      u_int16_t datalen,
      int *hotdrop)
{
       struct frag_hdr *frag = NULL;
       const struct ip6t_frag *fraginfo = matchinfo;
       unsigned int temp;
       int len;
       u8 nexthdr;
       unsigned int ptr;
       unsigned int hdrlen = 0;

       /* type of the 1st exthdr */
       nexthdr = skb->nh.ipv6h->nexthdr;
       /* pointer to the 1st exthdr */
       ptr = sizeof(struct ipv6hdr);
       /* available length */
       len = skb->len - ptr;
       temp = 0;

        while (ipv6_ext_hdr(nexthdr)) {
               struct ipv6_opt_hdr *hdr;

              DEBUGP("ipv6_frag header iteration \n");

              /* Is there enough space for the next ext header? */
                if (len < (int)sizeof(struct ipv6_opt_hdr))
                        return 0;
              /* No more exthdr -> evaluate */
                if (nexthdr == NEXTHDR_NONE) {
                     break;
              }
              /* ESP -> evaluate */
                if (nexthdr == NEXTHDR_ESP) {
                     break;
              }

              hdr=(struct ipv6_opt_hdr *)(skb->data+ptr);

              /* Calculate the header length */
                if (nexthdr == NEXTHDR_FRAGMENT) {
                        hdrlen = 8;
                } else if (nexthdr == NEXTHDR_AUTH)
                        hdrlen = (hdr->hdrlen+2)<<2;
                else
                        hdrlen = ipv6_optlen(hdr);

              /* FRAG -> evaluate */
                if (nexthdr == NEXTHDR_FRAGMENT) {
                     temp |= MASK_FRAGMENT;
                     break;
              }


              /* set the flag */
              switch (nexthdr){
                     case NEXTHDR_HOP:
                     case NEXTHDR_ROUTING:
                     case NEXTHDR_FRAGMENT:
                     case NEXTHDR_AUTH:
                     case NEXTHDR_DEST:
                            break;
                     default:
                            DEBUGP("ipv6_frag match: unknown nextheader %u\n",nexthdr);
                            return 0;
                            break;
              }

                nexthdr = hdr->nexthdr;
                len -= hdrlen;
                ptr += hdrlen;
		if ( ptr > skb->len ) {
			DEBUGP("ipv6_frag: new pointer too large! \n");
			break;
		}
        }

       /* FRAG header not found */
       if ( temp != MASK_FRAGMENT ) return 0;

       if (len < sizeof(struct frag_hdr)){
	       *hotdrop = 1;
       		return 0;
       }

       frag = (struct frag_hdr *) (skb->data + ptr);

       DEBUGP("INFO %04X ", frag->frag_off);
       DEBUGP("OFFSET %04X ", ntohs(frag->frag_off) & ~0x7);
       DEBUGP("RES %02X %04X", frag->reserved, ntohs(frag->frag_off) & 0x6);
       DEBUGP("MF %04X ", frag->frag_off & htons(IP6_MF));
       DEBUGP("ID %u %08X\n", ntohl(frag->identification),
	      ntohl(frag->identification));

       DEBUGP("IPv6 FRAG id %02X ",
       		(id_match(fraginfo->ids[0], fraginfo->ids[1],
                           ntohl(frag->identification),
                           !!(fraginfo->invflags & IP6T_FRAG_INV_IDS))));
       DEBUGP("res %02X %02X%04X %02X ", 
       		(fraginfo->flags & IP6T_FRAG_RES), frag->reserved,
		ntohs(frag->frag_off) & 0x6,
       		!((fraginfo->flags & IP6T_FRAG_RES)
			&& (frag->reserved || (ntohs(frag->frag_off) & 0x6))));
       DEBUGP("first %02X %02X %02X ", 
       		(fraginfo->flags & IP6T_FRAG_FST),
		ntohs(frag->frag_off) & ~0x7,
       		!((fraginfo->flags & IP6T_FRAG_FST)
			&& (ntohs(frag->frag_off) & ~0x7)));
       DEBUGP("mf %02X %02X %02X ", 
       		(fraginfo->flags & IP6T_FRAG_MF),
		ntohs(frag->frag_off) & IP6_MF,
       		!((fraginfo->flags & IP6T_FRAG_MF)
			&& !((ntohs(frag->frag_off) & IP6_MF))));
       DEBUGP("last %02X %02X %02X\n", 
       		(fraginfo->flags & IP6T_FRAG_NMF),
		ntohs(frag->frag_off) & IP6_MF,
       		!((fraginfo->flags & IP6T_FRAG_NMF)
			&& (ntohs(frag->frag_off) & IP6_MF)));

       return (frag != NULL)
       		&&
       		(id_match(fraginfo->ids[0], fraginfo->ids[1],
			  ntohl(frag->identification),
                           !!(fraginfo->invflags & IP6T_FRAG_INV_IDS)))
		&&
		!((fraginfo->flags & IP6T_FRAG_RES)
			&& (frag->reserved || (ntohs(frag->frag_off) & 0x6)))
		&&
		!((fraginfo->flags & IP6T_FRAG_FST)
			&& (ntohs(frag->frag_off) & ~0x7))
		&&
		!((fraginfo->flags & IP6T_FRAG_MF)
			&& !(ntohs(frag->frag_off) & IP6_MF))
		&&
		!((fraginfo->flags & IP6T_FRAG_NMF)
			&& (ntohs(frag->frag_off) & IP6_MF));
}
コード例 #12
0
ファイル: ip6_input.c プロジェクト: helicopter3/wl500g
int ip6_mc_input(struct sk_buff *skb)
{
    const struct ipv6hdr *hdr;
    int deliver;

    IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_INMCASTPKTS);

    hdr = ipv6_hdr(skb);
    deliver = ipv6_chk_mcast_addr(skb->dev, &hdr->daddr, NULL);

#ifdef CONFIG_IPV6_MROUTE
    /*
     *      IPv6 multicast router mode is now supported ;)
     */
    if (ipv6_devconf.mc_forwarding &&
            likely(!(IP6CB(skb)->flags & IP6SKB_FORWARDED))) {
        /*
         * Okay, we try to forward - split and duplicate
         * packets.
         */
        struct sk_buff *skb2;
        struct inet6_skb_parm *opt = IP6CB(skb);

        /* Check for MLD */
        if (unlikely(opt->flags & IP6SKB_ROUTERALERT)) {
            /* Check if this is a mld message */
            struct icmp6hdr *icmp6;
            u8 nexthdr = hdr->nexthdr;
            int offset;

            /* Check if the value of Router Alert
             * is for MLD (0x0000).
             */
            if (opt->ra == htons(IPV6_OPT_ROUTERALERT_MLD)) {
                deliver = 0;

                if (!ipv6_ext_hdr(nexthdr)) {
                    /* BUG */
                    goto out;
                }
                offset = ipv6_skip_exthdr(skb, sizeof(*hdr),
                                          &nexthdr);
                if (offset < 0)
                    goto out;

                if (nexthdr != IPPROTO_ICMPV6)
                    goto out;

                if (!pskb_may_pull(skb, (skb_network_header(skb) +
                                         offset + 1 - skb->data)))
                    goto out;

                icmp6 = (struct icmp6hdr *)(skb_network_header(skb) + offset);

                switch (icmp6->icmp6_type) {
                case ICMPV6_MGM_QUERY:
                case ICMPV6_MGM_REPORT:
                case ICMPV6_MGM_REDUCTION:
                case ICMPV6_MLD2_REPORT:
                    deliver = 1;
                    break;
                }
                goto out;
            }
            /* unknown RA - process it normally */
        }

        if (deliver)
            skb2 = skb_clone(skb, GFP_ATOMIC);
        else {
            skb2 = skb;
            skb = NULL;
        }

        if (skb2) {
            skb2->dev = skb2->dst->dev;
            ip6_mr_input(skb2);
        }
    }
out:
#endif
    if (likely(deliver)) {
        ip6_input(skb);
    } else {
        /* discard */
        kfree_skb(skb);
    }

    return 0;
}
コード例 #13
0
ファイル: exthdrs_core.c プロジェクト: dventurino/ovs-rstp
/*
 * find the offset to specified header or the protocol number of last header
 * if target < 0. "last header" is transport protocol header, ESP, or
 * "No next header".
 *
 * Note that *offset is used as input/output parameter. an if it is not zero,
 * then it must be a valid offset to an inner IPv6 header. This can be used
 * to explore inner IPv6 header, eg. ICMPv6 error messages.
 *
 * If target header is found, its offset is set in *offset and return protocol
 * number. Otherwise, return -1.
 *
 * If the first fragment doesn't contain the final protocol header or
 * NEXTHDR_NONE it is considered invalid.
 *
 * Note that non-1st fragment is special case that "the protocol number
 * of last header" is "next header" field in Fragment header. In this case,
 * *offset is meaningless and fragment offset is stored in *fragoff if fragoff
 * isn't NULL.
 *
 * if flags is not NULL and it's a fragment, then the frag flag
 * IP6_FH_F_FRAG will be set. If it's an AH header, the
 * IP6_FH_F_AUTH flag is set and target < 0, then this function will
 * stop at the AH header. If IP6_FH_F_SKIP_RH flag was passed, then this
 * function will skip all those routing headers, where segements_left was 0.
 */
int rpl_ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
                      int target, unsigned short *fragoff, int *flags)
{
    unsigned int start = skb_network_offset(skb) + sizeof(struct ipv6hdr);
    u8 nexthdr = ipv6_hdr(skb)->nexthdr;
    unsigned int len;
    bool found;

    if (fragoff)
        *fragoff = 0;

    if (*offset) {
        struct ipv6hdr _ip6, *ip6;

        ip6 = skb_header_pointer(skb, *offset, sizeof(_ip6), &_ip6);
        if (!ip6 || (ip6->version != 6)) {
            printk(KERN_ERR "IPv6 header not found\n");
            return -EBADMSG;
        }
        start = *offset + sizeof(struct ipv6hdr);
        nexthdr = ip6->nexthdr;
    }
    len = skb->len - start;

    do {
        struct ipv6_opt_hdr _hdr, *hp;
        unsigned int hdrlen;
        found = (nexthdr == target);

        if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE) {
            if (target < 0 || found)
                break;
            return -ENOENT;
        }

        hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr);
        if (hp == NULL)
            return -EBADMSG;

        if (nexthdr == NEXTHDR_ROUTING) {
            struct ipv6_rt_hdr _rh, *rh;

            rh = skb_header_pointer(skb, start, sizeof(_rh),
                                    &_rh);
            if (rh == NULL)
                return -EBADMSG;

            if (flags && (*flags & IP6_FH_F_SKIP_RH) &&
                    rh->segments_left == 0)
                found = false;
        }

        if (nexthdr == NEXTHDR_FRAGMENT) {
            unsigned short _frag_off;
            __be16 *fp;

            if (flags)	/* Indicate that this is a fragment */
                *flags |= IP6_FH_F_FRAG;
            fp = skb_header_pointer(skb,
                                    start+offsetof(struct frag_hdr,
                                                   frag_off),
                                    sizeof(_frag_off),
                                    &_frag_off);
            if (fp == NULL)
                return -EBADMSG;

            _frag_off = ntohs(*fp) & ~0x7;
            if (_frag_off) {
                if (target < 0 &&
                        ((!ipv6_ext_hdr(hp->nexthdr)) ||
                         hp->nexthdr == NEXTHDR_NONE)) {
                    if (fragoff)
                        *fragoff = _frag_off;
                    return hp->nexthdr;
                }
                return -ENOENT;
            }
            hdrlen = 8;
        } else if (nexthdr == NEXTHDR_AUTH) {
            if (flags && (*flags & IP6_FH_F_AUTH) && (target < 0))
                break;
            hdrlen = (hp->hdrlen + 2) << 2;
        } else
            hdrlen = ipv6_optlen(hp);

        if (!found) {
            nexthdr = hp->nexthdr;
            len -= hdrlen;
            start += hdrlen;
        }
    } while (!found);
コード例 #14
0
static int
match(const struct sk_buff *skb,
      const struct net_device *in,
      const struct net_device *out,
      const void *matchinfo,
      int offset,
      const void *protohdr,
      u_int16_t datalen,
      int *hotdrop)
{
       struct ipv6_rt_hdr *route = NULL;
       const struct ip6t_rt *rtinfo = matchinfo;
       unsigned int temp;
       unsigned int len;
       u8 nexthdr;
       unsigned int ptr;
       unsigned int hdrlen = 0;
       unsigned int ret = 0;

       /* type of the 1st exthdr */
       nexthdr = skb->nh.ipv6h->nexthdr;
       /* pointer to the 1st exthdr */
       ptr = sizeof(struct ipv6hdr);
       /* available length */
       len = skb->len - ptr;
       temp = 0;

        while (ipv6_ext_hdr(nexthdr)) {
               struct ipv6_opt_hdr *hdr;

              DEBUGP("ipv6_rt header iteration \n");

              /* Is there enough space for the next ext header? */
                if (len < (int)sizeof(struct ipv6_opt_hdr))
                        return 0;
              /* No more exthdr -> evaluate */
                if (nexthdr == NEXTHDR_NONE) {
                     break;
              }
              /* ESP -> evaluate */
                if (nexthdr == NEXTHDR_ESP) {
                     break;
              }

              hdr=skb->data+ptr;

              /* Calculate the header length */
                if (nexthdr == NEXTHDR_FRAGMENT) {
                        hdrlen = 8;
                } else if (nexthdr == NEXTHDR_AUTH)
                        hdrlen = (hdr->hdrlen+2)<<2;
                else
                        hdrlen = ipv6_optlen(hdr);

              /* ROUTING -> evaluate */
                if (nexthdr == NEXTHDR_ROUTING) {
                     temp |= MASK_ROUTING;
                     break;
              }


              /* set the flag */
              switch (nexthdr){
                     case NEXTHDR_HOP:
                     case NEXTHDR_ROUTING:
                     case NEXTHDR_FRAGMENT:
                     case NEXTHDR_AUTH:
                     case NEXTHDR_DEST:
                            break;
                     default:
                            DEBUGP("ipv6_rt match: unknown nextheader %u\n",nexthdr);
                            return 0;
                            break;
              }

                nexthdr = hdr->nexthdr;
                len -= hdrlen;
                ptr += hdrlen;
		if ( ptr > skb->len ) {
			DEBUGP("ipv6_rt: new pointer is too large! \n");
			break;
		}
        }

       /* ROUTING header not found */
       if ( temp != MASK_ROUTING ) return 0;

       if (len < (int)sizeof(struct ipv6_rt_hdr)){
	       *hotdrop = 1;
       		return 0;
       }

       if (len < hdrlen){
	       /* Pcket smaller than its length field */
       		return 0;
       }

       route=skb->data+ptr;

       DEBUGP("IPv6 RT LEN %u %u ", hdrlen, route->hdrlen);
       DEBUGP("TYPE %04X ", route->type);
       DEBUGP("SGS_LEFT %u %08X\n", ntohl(route->segments_left), ntohl(route->segments_left));

       DEBUGP("IPv6 RT segsleft %02X ",
       		(segsleft_match(rtinfo->segsleft[0], rtinfo->segsleft[1],
                           ntohl(route->segments_left),
                           !!(rtinfo->invflags & IP6T_RT_INV_SGS))));
       DEBUGP("type %02X %02X %02X ",
       		rtinfo->rt_type, route->type, 
       		(!(rtinfo->flags & IP6T_RT_TYP) ||
                           ((rtinfo->rt_type == route->type) ^
                           !!(rtinfo->invflags & IP6T_RT_INV_TYP))));
       DEBUGP("len %02X %04X %02X ",
       		rtinfo->hdrlen, hdrlen,
       		(!(rtinfo->flags & IP6T_RT_LEN) ||
                           ((rtinfo->hdrlen == hdrlen) ^
                           !!(rtinfo->invflags & IP6T_RT_INV_LEN))));
       DEBUGP("res %02X %02X %02X ", 
       		(rtinfo->flags & IP6T_RT_RES), ((struct rt0_hdr *)route)->reserved,
       		!((rtinfo->flags & IP6T_RT_RES) && (((struct rt0_hdr *)route)->reserved)));

       ret = (route != NULL)
       		&&
       		(segsleft_match(rtinfo->segsleft[0], rtinfo->segsleft[1],
                           ntohl(route->segments_left),
                           !!(rtinfo->invflags & IP6T_RT_INV_SGS)))
		&&
	      	(!(rtinfo->flags & IP6T_RT_LEN) ||
                           ((rtinfo->hdrlen == hdrlen) ^
                           !!(rtinfo->invflags & IP6T_RT_INV_LEN)))
		&&
       		(!(rtinfo->flags & IP6T_RT_TYP) ||
                           ((rtinfo->rt_type == route->type) ^
                           !!(rtinfo->invflags & IP6T_RT_INV_TYP)))
		&&
       		!((rtinfo->flags & IP6T_RT_RES) && (((struct rt0_hdr *)route)->reserved));

	DEBUGP("#%d ",rtinfo->addrnr);
       temp = len = ptr = 0;
       if ( !(rtinfo->flags & IP6T_RT_FST) ){
	       return ret;
	} else if (rtinfo->flags & IP6T_RT_FST_NSTRICT) {
		DEBUGP("Not strict ");
		if ( rtinfo->addrnr > (unsigned int)((hdrlen-8)/16) ){
			DEBUGP("There isn't enough space\n");
			return 0;
		} else {
			DEBUGP("#%d ",rtinfo->addrnr);
			ptr = 0;
			for(temp=0; temp<(unsigned int)((hdrlen-8)/16); temp++){
				len = 0;
				while ((u8)(((struct rt0_hdr *)route)->
						addr[temp].s6_addr[len]) ==
					(u8)(rtinfo->addrs[ptr].s6_addr[len])){
					DEBUGP("%02X?%02X ",
		(u8)(((struct rt0_hdr *)route)->addr[temp].s6_addr[len]),
					(u8)(rtinfo->addrs[ptr].s6_addr[len]));
					len++;
					if ( len == 16 ) break;
				}
				if (len==16) {
					DEBUGP("ptr=%d temp=%d;\n",ptr,temp);
					ptr++;
				} else {
					DEBUGP("%02X?%02X ",
		(u8)(((struct rt0_hdr *)route)->addr[temp].s6_addr[len]),
					(u8)(rtinfo->addrs[ptr].s6_addr[len]));
					DEBUGP("!ptr=%d temp=%d;\n",ptr,temp);
				}
				if (ptr==rtinfo->addrnr) break;
			}
			DEBUGP("ptr=%d len=%d #%d\n",ptr,len, rtinfo->addrnr);
			if ( (len == 16) && (ptr == rtinfo->addrnr))
				return ret;
			else return 0;
		}
	} else {
		DEBUGP("Strict ");
		if ( rtinfo->addrnr > (unsigned int)((hdrlen-8)/16) ){
			DEBUGP("There isn't enough space\n");
			return 0;
		} else {
			DEBUGP("#%d ",rtinfo->addrnr);
			for(temp=0; temp<rtinfo->addrnr; temp++){
				len = 0;
				while ((u8)(((struct rt0_hdr *)route)->
						addr[temp].s6_addr[len]) ==
					(u8)(rtinfo->addrs[temp].s6_addr[len])){
					DEBUGP("%02X?%02X ",
		(u8)(((struct rt0_hdr *)route)->addr[temp].s6_addr[len]),
					(u8)(rtinfo->addrs[temp].s6_addr[len]));
					len++;
					if ( len == 16 ) break;
				}
				if (len!=16) {
					DEBUGP("%02X?%02X ",
		(u8)(((struct rt0_hdr *)route)->addr[temp].s6_addr[len]),
					(u8)(rtinfo->addrs[temp].s6_addr[len]));
					DEBUGP("!len=%d temp=%d;\n",len,temp);
					break;
				}
			}
			DEBUGP("temp=%d len=%d #%d\n",temp,len,rtinfo->addrnr);
			if ( (len == 16) && (temp == rtinfo->addrnr) && (temp == (unsigned int)((hdrlen-8)/16)))
				return ret;
			else return 0;
		}
	}

	return 0;
}
コード例 #15
0
int ip6_mc_input(struct sk_buff *skb)
{
	struct ipv6hdr *hdr;
	int deliver;

	IP6_INC_STATS_BH(IPSTATS_MIB_INMCASTPKTS);

	hdr = skb->nh.ipv6h;
	deliver = likely(!(skb->dev->flags & (IFF_PROMISC|IFF_ALLMULTI))) ||
	    ipv6_chk_mcast_addr(skb->dev, &hdr->daddr, NULL);

#ifdef CONFIG_IPV6_MROUTE
	/*
	 *      IPv6 multicast router mode is now supported ;)
	 */

	if ((ipv6_addr_type(&hdr->daddr) & IPV6_ADDR_MULTICAST) && 
	    (IPV6_ADDR_MC_SCOPE(&hdr->daddr) == 0))
		goto out;

	if (ipv6_devconf.mc_forwarding &&	
	    !(ipv6_addr_type(&hdr->daddr) & IPV6_ADDR_LINKLOCAL) &&
	    likely(!(IP6CB(skb)->flags & IP6SKB_FORWARDED))) {
		/*
		 * Okay, we try to forward - split and duplicate
		 * packets.
		 */
		struct sk_buff *skb2;
		struct inet6_skb_parm *opt = IP6CB(skb);

		/* Check for MLD */
		if (unlikely(opt->ra)) {
			/* Check if this is a mld message */
			//u8 *ptr = skb_network_header(skb) + opt->ra;
			u8 *ptr;
			struct icmp6hdr *icmp6;
			u8 nexthdr = hdr->nexthdr;
			int offset;

			ptr = (u8 *) (skb->nh.raw + opt->ra); //chunru: copy from ip6_output
			/* Check if the value of Router Alert
			 * is for MLD (0x0000).
			 */
			if ((ptr[2] | ptr[3]) == 0) {
				deliver = 0;
				if (!ipv6_ext_hdr(nexthdr)) {
					/* BUG */
					goto out;
				}

				offset = ipv6_skip_exthdr(skb, sizeof(*hdr),
							  &nexthdr);
				if (offset < 0)
					goto out;

				if (nexthdr != IPPROTO_ICMPV6)
					goto out;

				if (!pskb_may_pull(skb, (skb->nh.raw + offset + 1 - skb->data)))
					goto out;

				icmp6 = (struct icmp6hdr *)( skb->nh.raw + offset);

				switch (icmp6->icmp6_type) {
				case ICMPV6_MGM_QUERY:
				case ICMPV6_MGM_REPORT:
				case ICMPV6_MGM_REDUCTION:
				case ICMPV6_MLD2_REPORT:
					deliver = 1;
					break;
				}
				goto out;
			}
			/* unknown RA - process it normally */
		}

		if (deliver)
		{
			skb2 = skb_clone(skb, GFP_ATOMIC);
		}
		else {
			skb2 = skb;
			skb = NULL;
		}

		if (skb2) {
			ip6_mr_input(skb2);
		}
	}
out:
#endif
	if (likely(deliver)) {
		ip6_input(skb);
		return 0;
	}
#ifdef CONFIG_IPV6_MROUTE
	else if(skb) {
		/* discard */
		kfree_skb(skb);
	}
#else
	/* discard */
	kfree_skb(skb);
#endif

	return 0;
}