struct sock             *fibnl;
 
        struct sock  * __percpu *icmp_sk;
+       struct sock             *mc_autojoin_sk;
 
        struct inet_peer_base   *peers;
        struct tcpm_hash_bucket *tcp_metrics_hash;
 
        struct sock             *ndisc_sk;
        struct sock             *tcp_sk;
        struct sock             *igmp_sk;
+       struct sock             *mc_autojoin_sk;
 #ifdef CONFIG_IPV6_MROUTE
 #ifndef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES
        struct mr6_table        *mrt6;
 
 #define IFA_F_PERMANENT                0x80
 #define IFA_F_MANAGETEMPADDR   0x100
 #define IFA_F_NOPREFIXROUTE    0x200
+#define IFA_F_MCAUTOJOIN       0x400
 
 struct ifa_cacheinfo {
        __u32   ifa_prefered;
 
        return NULL;
 }
 
+static int ip_mc_config(struct sock *sk, bool join, const struct in_ifaddr *ifa)
+{
+       struct ip_mreqn mreq = {
+               .imr_multiaddr.s_addr = ifa->ifa_address,
+               .imr_ifindex = ifa->ifa_dev->dev->ifindex,
+       };
+       int ret;
+
+       ASSERT_RTNL();
+
+       lock_sock(sk);
+       if (join)
+               ret = __ip_mc_join_group(sk, &mreq);
+       else
+               ret = __ip_mc_leave_group(sk, &mreq);
+       release_sock(sk);
+
+       return ret;
+}
+
 static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh)
 {
        struct net *net = sock_net(skb->sk);
                    !inet_ifa_match(nla_get_be32(tb[IFA_ADDRESS]), ifa)))
                        continue;
 
+               if (ipv4_is_multicast(ifa->ifa_address))
+                       ip_mc_config(net->ipv4.mc_autojoin_sk, false, ifa);
                __inet_del_ifa(in_dev, ifap, 1, nlh, NETLINK_CB(skb).portid);
                return 0;
        }
                 * userspace already relies on not having to provide this.
                 */
                set_ifa_lifetime(ifa, valid_lft, prefered_lft);
+               if (ifa->ifa_flags & IFA_F_MCAUTOJOIN) {
+                       int ret = ip_mc_config(net->ipv4.mc_autojoin_sk,
+                                              true, ifa);
+
+                       if (ret < 0) {
+                               inet_free_ifa(ifa);
+                               return ret;
+                       }
+               }
                return __inet_insert_ifa(ifa, nlh, NETLINK_CB(skb).portid);
        } else {
                inet_free_ifa(ifa);
 
 #include <net/route.h>
 #include <net/sock.h>
 #include <net/checksum.h>
+#include <net/inet_common.h>
 #include <linux/netfilter_ipv4.h>
 #ifdef CONFIG_IP_MROUTE
 #include <linux/mroute.h>
 static int __net_init igmp_net_init(struct net *net)
 {
        struct proc_dir_entry *pde;
+       int err;
 
        pde = proc_create("igmp", S_IRUGO, net->proc_net, &igmp_mc_seq_fops);
        if (!pde)
                          &igmp_mcf_seq_fops);
        if (!pde)
                goto out_mcfilter;
+       err = inet_ctl_sock_create(&net->ipv4.mc_autojoin_sk, AF_INET,
+                                  SOCK_DGRAM, 0, net);
+       if (err < 0) {
+               pr_err("Failed to initialize the IGMP autojoin socket (err %d)\n",
+                      err);
+               goto out_sock;
+       }
+
        return 0;
 
+out_sock:
+       remove_proc_entry("mcfilter", net->proc_net);
 out_mcfilter:
        remove_proc_entry("igmp", net->proc_net);
 out_igmp:
 {
        remove_proc_entry("mcfilter", net->proc_net);
        remove_proc_entry("igmp", net->proc_net);
+       inet_ctl_sock_destroy(net->ipv4.mc_autojoin_sk);
 }
 
 static struct pernet_operations igmp_net_ops = {
 
        return err;
 }
 
+static int ipv6_mc_config(struct sock *sk, bool join,
+                         const struct in6_addr *addr, int ifindex)
+{
+       int ret;
+
+       ASSERT_RTNL();
+
+       lock_sock(sk);
+       if (join)
+               ret = __ipv6_sock_mc_join(sk, ifindex, addr);
+       else
+               ret = __ipv6_sock_mc_drop(sk, ifindex, addr);
+       release_sock(sk);
+
+       return ret;
+}
+
 /*
  *     Manual configuration of address on an interface
  */
        struct inet6_ifaddr *ifp;
        struct inet6_dev *idev;
        struct net_device *dev;
+       unsigned long timeout;
+       clock_t expires;
        int scope;
        u32 flags;
-       clock_t expires;
-       unsigned long timeout;
 
        ASSERT_RTNL();
 
        if (IS_ERR(idev))
                return PTR_ERR(idev);
 
+       if (ifa_flags & IFA_F_MCAUTOJOIN) {
+               int ret = ipv6_mc_config(net->ipv6.mc_autojoin_sk,
+                                        true, pfx, ifindex);
+
+               if (ret < 0)
+                       return ret;
+       }
+
        scope = ipv6_addr_scope(pfx);
 
        timeout = addrconf_timeout_fixup(valid_lft, HZ);
                in6_ifa_put(ifp);
                addrconf_verify_rtnl();
                return 0;
+       } else if (ifa_flags & IFA_F_MCAUTOJOIN) {
+               ipv6_mc_config(net->ipv6.mc_autojoin_sk,
+                              false, pfx, ifindex);
        }
 
        return PTR_ERR(ifp);
                                                 jiffies);
                        ipv6_del_addr(ifp);
                        addrconf_verify_rtnl();
+                       if (ipv6_addr_is_multicast(pfx)) {
+                               ipv6_mc_config(net->ipv6.mc_autojoin_sk,
+                                              false, pfx, dev->ifindex);
+                       }
                        return 0;
                }
        }
 
        /* We ignore other flags so far. */
        ifa_flags &= IFA_F_NODAD | IFA_F_HOMEADDRESS | IFA_F_MANAGETEMPADDR |
-                    IFA_F_NOPREFIXROUTE;
+                    IFA_F_NOPREFIXROUTE | IFA_F_MCAUTOJOIN;
 
        ifa = ipv6_get_ifaddr(net, pfx, dev, 1);
        if (ifa == NULL) {
 
 
        inet6_sk(net->ipv6.igmp_sk)->hop_limit = 1;
 
+       err = inet_ctl_sock_create(&net->ipv6.mc_autojoin_sk, PF_INET6,
+                                  SOCK_RAW, IPPROTO_ICMPV6, net);
+       if (err < 0) {
+               pr_err("Failed to initialize the IGMP6 autojoin socket (err %d)\n",
+                      err);
+               goto out_sock_create;
+       }
+
        err = igmp6_proc_init(net);
        if (err)
-               goto out_sock_create;
-out:
-       return err;
+               goto out_sock_create_autojoin;
+
+       return 0;
 
+out_sock_create_autojoin:
+       inet_ctl_sock_destroy(net->ipv6.mc_autojoin_sk);
 out_sock_create:
        inet_ctl_sock_destroy(net->ipv6.igmp_sk);
-       goto out;
+out:
+       return err;
 }
 
 static void __net_exit igmp6_net_exit(struct net *net)
 {
        inet_ctl_sock_destroy(net->ipv6.igmp_sk);
+       inet_ctl_sock_destroy(net->ipv6.mc_autojoin_sk);
        igmp6_proc_exit(net);
 }