int ndisc_rcv(struct sk_buff *skb);
 
+struct sk_buff *ndisc_ns_create(struct net_device *dev, const struct in6_addr *solicit,
+                               const struct in6_addr *saddr, u64 nonce);
 void ndisc_send_ns(struct net_device *dev, const struct in6_addr *solicit,
                   const struct in6_addr *daddr, const struct in6_addr *saddr,
                   u64 nonce);
 
+void ndisc_send_skb(struct sk_buff *skb, const struct in6_addr *daddr,
+                   const struct in6_addr *saddr);
+
 void ndisc_send_rs(struct net_device *dev,
                   const struct in6_addr *saddr, const struct in6_addr *daddr);
 void ndisc_send_na(struct net_device *dev, const struct in6_addr *daddr,
 
        hdr->daddr = *daddr;
 }
 
-static void ndisc_send_skb(struct sk_buff *skb,
-                          const struct in6_addr *daddr,
-                          const struct in6_addr *saddr)
+void ndisc_send_skb(struct sk_buff *skb, const struct in6_addr *daddr,
+                   const struct in6_addr *saddr)
 {
        struct dst_entry *dst = skb_dst(skb);
        struct net *net = dev_net(skb->dev);
 
        rcu_read_unlock();
 }
+EXPORT_SYMBOL(ndisc_send_skb);
 
 void ndisc_send_na(struct net_device *dev, const struct in6_addr *daddr,
                   const struct in6_addr *solicited_addr,
        in6_dev_put(idev);
 }
 
-void ndisc_send_ns(struct net_device *dev, const struct in6_addr *solicit,
-                  const struct in6_addr *daddr, const struct in6_addr *saddr,
-                  u64 nonce)
+struct sk_buff *ndisc_ns_create(struct net_device *dev, const struct in6_addr *solicit,
+                               const struct in6_addr *saddr, u64 nonce)
 {
-       struct sk_buff *skb;
-       struct in6_addr addr_buf;
        int inc_opt = dev->addr_len;
-       int optlen = 0;
+       struct sk_buff *skb;
        struct nd_msg *msg;
+       int optlen = 0;
 
-       if (!saddr) {
-               if (ipv6_get_lladdr(dev, &addr_buf,
-                                  (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)))
-                       return;
-               saddr = &addr_buf;
-       }
+       if (!saddr)
+               return NULL;
 
        if (ipv6_addr_any(saddr))
                inc_opt = false;
 
        skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
        if (!skb)
-               return;
+               return NULL;
 
        msg = skb_put(skb, sizeof(*msg));
        *msg = (struct nd_msg) {
                memcpy(opt + 2, &nonce, 6);
        }
 
-       ndisc_send_skb(skb, daddr, saddr);
+       return skb;
+}
+EXPORT_SYMBOL(ndisc_ns_create);
+
+void ndisc_send_ns(struct net_device *dev, const struct in6_addr *solicit,
+                  const struct in6_addr *daddr, const struct in6_addr *saddr,
+                  u64 nonce)
+{
+       struct in6_addr addr_buf;
+       struct sk_buff *skb;
+
+       if (!saddr) {
+               if (ipv6_get_lladdr(dev, &addr_buf,
+                                   (IFA_F_TENTATIVE | IFA_F_OPTIMISTIC)))
+                       return;
+               saddr = &addr_buf;
+       }
+
+       skb = ndisc_ns_create(dev, solicit, saddr, nonce);
+
+       if (skb)
+               ndisc_send_skb(skb, daddr, saddr);
 }
 
 void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr,