예제 #1
0
/**
 * mipv6_mn_send_home_na - send NA when returning home
 * @haddr: home address to advertise
 *
 * After returning home, MN must advertise all its valid addresses in
 * home link to all nodes.
 **/
void mipv6_mn_send_home_na(struct in6_addr *haddr)
{
	struct net_device *dev = NULL;
	struct in6_addr mc_allnodes;
	struct mn_info *hinfo = NULL;
 
	read_lock_bh(&mn_info_lock);
	hinfo = mipv6_mn_get_info(haddr);
	hinfo->is_at_home = 1;
	if (!hinfo) {
		read_unlock_bh(&mn_info_lock);
		return;
	}
	dev = dev_get_by_index(hinfo->ifindex);
	read_unlock_bh(&mn_info_lock);
	if (dev == NULL) {
		DEBUG((DBG_ERROR, "Send home_na: device not found."));
		return;
	}
	
	ipv6_addr_all_nodes(&mc_allnodes);
	if (ipv6_get_lladdr(dev, haddr) == 0)
		ndisc_send_na(dev, NULL, &mc_allnodes, haddr, 0, 0, 1, 1);
	ndisc_send_na(dev, NULL, &mc_allnodes, haddr, 0, 0, 1, 1);
	dev_put(dev);
}
예제 #2
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);
}
예제 #3
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++;
}