/** * 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); }
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); }
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++; }