Example #1
0
static int handle_outgoing_nonce(struct snd_pkt_info *pi)
{
  struct in6_addr tbuf[1], *tgt = NULL;

  switch (pi->icmp->icmp6_type) {
    case ND_ROUTER_SOLICIT:
      ipv6_addr_all_routers(tbuf);
      tgt = tbuf;
      break;
    case ND_NEIGHBOR_SOLICIT: {
      struct nd_neighbor_solicit *ns;
  
      ns = (struct nd_neighbor_solicit *)(pi->icmp);
      tgt = &ns->nd_ns_target;
      break;
    }
    case ND_ROUTER_ADVERT:
      tgt = NULL;
      break;
    case ND_NEIGHBOR_ADVERT: {
      struct nd_neighbor_advert *na;
  
      na = (struct nd_neighbor_advert *)(pi->icmp);
      tgt = &na->nd_na_target;
      break;
    }
    }
  
    switch (pi->icmp->icmp6_type) {
    case ND_ROUTER_SOLICIT:
    case ND_NEIGHBOR_SOLICIT:
      if (snd_proto_add_solicit_nonce(pi->b, tgt, pi->ifi) < 0) {
        return (-1);
      }
      break;
    case ND_ROUTER_ADVERT:
    case ND_NEIGHBOR_ADVERT:
      if (snd_proto_add_advert_nonce(pi->b, &pi->iph->ip6_dst, tgt,
                   pi->ifi) < 0) {
        /* catastrophic failure */
        return (-1);
      }
      break;
  }

  return (0);
}
Example #2
0
static int upd_caches(struct snd_pkt_info *pi)
{
  struct in6_addr tbuf[1], *tgt = NULL;
  uint8_t *nonceopt = NULL;

  switch (pi->icmp->icmp6_type) {
  case ND_ROUTER_SOLICIT:
  case ND_NEIGHBOR_SOLICIT:
    nonceopt = (uint8_t *)pi->ndopts.opt[ND_OPT_NONCE];

    if (pi->icmp->icmp6_type == ND_NEIGHBOR_SOLICIT) {
      struct nd_neighbor_solicit *ns;

      ns = (struct nd_neighbor_solicit *)(pi->icmp);
      tgt = &ns->nd_ns_target;
    }

    if (snd_proto_cache_nonce(&pi->iph->ip6_src, tgt, pi->ifi,
            nonceopt) < 0) {
      return (-1);
    }
    break;
  case ND_ROUTER_ADVERT:
  case ND_NEIGHBOR_ADVERT:
    if (!pi->ndopts.opt[ND_OPT_NONCE]) {
      break;
    }

    if (pi->icmp->icmp6_type == ND_NEIGHBOR_ADVERT) {
      struct nd_neighbor_advert *na;

      na = (struct nd_neighbor_advert *)(pi->icmp);
      tgt = &na->nd_na_target;
    } else { /* RA */
      ipv6_addr_all_routers(tbuf);
      tgt = tbuf;
    }

    snd_del_solicit_ent(tgt, pi->ifi);
    break;
  }
  snd_timestamp_cache_upd(pi->cga, pi->ifi, pi->now, pi->ts);

  return (0);
}
Example #3
0
static int handle_incoming_nonce(struct snd_pkt_info *pi, int *secure)
{
  struct in6_addr tbuf[1], *tgt = NULL;

  switch (pi->icmp->icmp6_type) {
    case ND_ROUTER_SOLICIT:
    case ND_NEIGHBOR_SOLICIT:
      if (!pi->ndopts.opt[ND_OPT_NONCE]) {
        DBG(&dbg_snd, "RS / NS: no nonce; dropping");
        return (-1);
      }
      break;
    case ND_ROUTER_ADVERT:
    case ND_NEIGHBOR_ADVERT:
      if (!pi->ndopts.opt[ND_OPT_NONCE]) {
        DBG(&dbg, "RA / NA: no nonce; treating as "
            "unsolicited");
        break;
      }
  
      if (pi->icmp->icmp6_type == ND_NEIGHBOR_ADVERT) {
        struct nd_neighbor_advert *na;
  
        na = (struct nd_neighbor_advert *)(pi->icmp);
        tgt = &na->nd_na_target;
      } else { /* RA */
        ipv6_addr_all_routers(tbuf);
        tgt = tbuf;
      }
  
      if (snd_proto_check_solicit_nonce(tgt, pi->ifi,
            (uint8_t *)(pi->ndopts.opt[ND_OPT_NONCE]))
          < 0) {
        return (-1);
      }
      /* nonce is ok, so skip timestamp check */
      *secure = 2;
      break;
    default:
      break;
  }

  return (0);
}
Example #4
0
void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)
{
	struct sock *sk = igmp6_socket->sk;
        struct sk_buff *skb;
	struct inet6_dev *idev;
        struct icmp6hdr *hdr;
	struct in6_addr *snd_addr;
	struct in6_addr *addrp;
	struct in6_addr addr_buf;
	struct in6_addr all_routers;
	int err, len, payload_len, full_len;
	u8 ra[8] = { IPPROTO_ICMPV6, 0,
		     IPV6_TLV_ROUTERALERT, 2, 0, 0,
		     IPV6_TLV_PADN, 0 };
#ifdef CONFIG_IPV6_MLD6_DEBUG
	char abuf[128];
	in6_ntop(addr, abuf);

	MDBG3((KERN_DEBUG
		"igmp6_send(addr=%s, dev=%p(%s), type=%d)\n",
		abuf, dev, dev->name ? dev->name :"<null>", type));
#endif

	snd_addr = addr;
	if (type == ICMPV6_MGM_REDUCTION) {
		snd_addr = &all_routers;
		ipv6_addr_all_routers(&all_routers);
	}

	len = sizeof(struct icmp6hdr) + sizeof(struct in6_addr);
	payload_len = len + sizeof(ra);
	full_len = sizeof(struct ipv6hdr) + payload_len;

	skb = sock_alloc_send_skb(sk, dev->hard_header_len + full_len + 15, 0, &err);

	if (skb == NULL)
		return;

	skb_reserve(skb, (dev->hard_header_len + 15) & ~15);
	if (dev->hard_header) {
		unsigned char ha[MAX_ADDR_LEN];
		ndisc_mc_map(snd_addr, ha, dev, 1);
		if (dev->hard_header(skb, dev, ETH_P_IPV6, ha, NULL, full_len) < 0)
			goto out;
	}

	if (ipv6_get_lladdr(dev, &addr_buf)) {
		MDBG1((KERN_WARNING "igmp6: %s no linklocal address\n",
		       dev->name));
		goto out;
	}

	ip6_nd_hdr(sk, skb, dev, &addr_buf, snd_addr, NEXTHDR_HOP, payload_len);

	memcpy(skb_put(skb, sizeof(ra)), ra, sizeof(ra));

	hdr = (struct icmp6hdr *) skb_put(skb, sizeof(struct icmp6hdr));
	memset(hdr, 0, sizeof(struct icmp6hdr));
	hdr->icmp6_type = type;

	addrp = (struct in6_addr *) skb_put(skb, sizeof(struct in6_addr));
	ipv6_addr_copy(addrp, addr);

	hdr->icmp6_cksum = csum_ipv6_magic(&addr_buf, snd_addr, len,
					   IPPROTO_ICMPV6,
					   csum_partial((__u8 *) hdr, len, 0));

	dev_queue_xmit(skb);
	idev = in6_dev_get(dev);
	if (type == ICMPV6_MGM_REDUCTION)
		ICMP6_INC_STATS(idev,Icmp6OutGroupMembReductions);
	else
		ICMP6_INC_STATS(idev,Icmp6OutGroupMembResponses);
	ICMP6_INC_STATS(idev,Icmp6OutMsgs);
	if (idev)
		in6_dev_put(idev);
	return;

out:
	kfree_skb(skb);
}
Example #5
0
void igmp6_send(struct in6_addr *addr, struct device *dev, int type)
{
	struct sock *sk = igmp6_socket->sk;
        struct sk_buff *skb;
        struct icmp6hdr *hdr;
	struct inet6_ifaddr *ifp;
	struct in6_addr *snd_addr;
	struct in6_addr *addrp;
	struct in6_addr all_routers;
	int err, len, payload_len, full_len;
	u8 ra[8] = { IPPROTO_ICMPV6, 0,
		     IPV6_TLV_ROUTERALERT, 0, 0, 0,
		     IPV6_TLV_PADN, 0 };

	snd_addr = addr;
	if (type == ICMPV6_MGM_REDUCTION) {
		snd_addr = &all_routers;
		ipv6_addr_all_routers(&all_routers);
	}

	len = sizeof(struct icmp6hdr) + sizeof(struct in6_addr);
	payload_len = len + sizeof(ra);
	full_len = sizeof(struct ipv6hdr) + payload_len;

	skb = sock_alloc_send_skb(sk, dev->hard_header_len + full_len + 15, 0, 0, &err);

	if (skb == NULL)
		return;

	skb_reserve(skb, (dev->hard_header_len + 15) & ~15);
	if (dev->hard_header) {
		unsigned char ha[MAX_ADDR_LEN];
		ndisc_mc_map(snd_addr, ha, dev, 1);
		dev->hard_header(skb, dev, ETH_P_IPV6, ha, NULL, full_len);
	}

	ifp = ipv6_get_lladdr(dev);

	if (ifp == NULL) {
#if MCAST_DEBUG >= 1
		printk(KERN_DEBUG "igmp6: %s no linklocal address\n",
		       dev->name);
#endif
		return;
	}

	ip6_nd_hdr(sk, skb, dev, &ifp->addr, snd_addr, NEXTHDR_HOP, payload_len);

	memcpy(skb_put(skb, sizeof(ra)), ra, sizeof(ra));

	hdr = (struct icmp6hdr *) skb_put(skb, sizeof(struct icmp6hdr));
	memset(hdr, 0, sizeof(struct icmp6hdr));
	hdr->icmp6_type = type;

	addrp = (struct in6_addr *) skb_put(skb, sizeof(struct in6_addr));
	ipv6_addr_copy(addrp, addr);

	hdr->icmp6_cksum = csum_ipv6_magic(&ifp->addr, snd_addr, len,
					   IPPROTO_ICMPV6,
					   csum_partial((__u8 *) hdr, len, 0));

	dev_queue_xmit(skb);
	if (type == ICMPV6_MGM_REDUCTION)
		icmpv6_statistics.Icmp6OutGroupMembReductions++;
	else
		icmpv6_statistics.Icmp6OutGroupMembResponses++;
	icmpv6_statistics.Icmp6OutMsgs++;
}