- ndisc_flow_init(&fl, NDISC_NEIGHBOUR_SOLICITATION, saddr, daddr,
- dev->ifindex);
-
- dst = ndisc_dst_alloc(dev, neigh, daddr, ip6_output);
- if (!dst)
- return;
-
- err = xfrm_lookup(&dst, &fl, NULL, 0);
- if (err < 0)
- return;
-
- len = sizeof(struct icmp6hdr) + sizeof(struct in6_addr);
- send_llinfo = dev->addr_len && !ipv6_addr_any(saddr);
- if (send_llinfo)
- len += ndisc_opt_addr_space(dev);
-
- skb = sock_alloc_send_skb(sk,
- (MAX_HEADER + sizeof(struct ipv6hdr) +
- len + LL_RESERVED_SPACE(dev)),
- 1, &err);
- if (skb == NULL) {
- ND_PRINTK0(KERN_ERR
- "ICMPv6 NA: %s() failed to allocate an skb.\n",
- __FUNCTION__);
- dst_release(dst);
- return;
- }
-
- skb_reserve(skb, LL_RESERVED_SPACE(dev));
- ip6_nd_hdr(sk, skb, dev, saddr, daddr, IPPROTO_ICMPV6, len);
-
- msg = (struct nd_msg *)skb_put(skb, len);
- skb->h.raw = (unsigned char*)msg;
- msg->icmph.icmp6_type = NDISC_NEIGHBOUR_SOLICITATION;
- msg->icmph.icmp6_code = 0;
- msg->icmph.icmp6_cksum = 0;
- msg->icmph.icmp6_unused = 0;
-
- /* Set the target address. */
- ipv6_addr_copy(&msg->target, solicit);
-
- if (send_llinfo)
- ndisc_fill_addr_option(msg->opt, ND_OPT_SOURCE_LL_ADDR, dev->dev_addr,
- dev->addr_len, dev->type);
-
- /* checksum */
- msg->icmph.icmp6_cksum = csum_ipv6_magic(&skb->nh.ipv6h->saddr,
- daddr, len,
- IPPROTO_ICMPV6,
- csum_partial((__u8 *) msg,
- len, 0));
- /* send it! */
- skb->dst = dst;
- idev = in6_dev_get(dst->dev);
- IP6_INC_STATS(idev, IPSTATS_MIB_OUTREQUESTS);
- err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, dst_output);
- if (!err) {
- ICMP6_INC_STATS(idev, ICMP6_MIB_OUTNEIGHBORSOLICITS);
- ICMP6_INC_STATS(idev, ICMP6_MIB_OUTMSGS);
- }
-
- if (likely(idev != NULL))
- in6_dev_put(idev);