]> err.no Git - linux-2.6/blobdiff - net/ipv4/igmp.c
[NETFILTER]: CLUSTERIP: fix memcpy() length typo
[linux-2.6] / net / ipv4 / igmp.c
index 111eb678cbac20c80cf6cbc99324cde3f6450d89..44607f4767b871820f5d33ab9dfd230e59933745 100644 (file)
@@ -904,7 +904,7 @@ int igmp_rcv(struct sk_buff *skb)
        case IGMP_MTRACE_RESP:
                break;
        default:
-               NETDEBUG(printk(KERN_DEBUG "New IGMP type=%d, why we do not know about it?\n", ih->type));
+               NETDEBUG(KERN_DEBUG "New IGMP type=%d, why we do not know about it?\n", ih->type);
        }
        in_dev_put(in_dev);
        kfree_skb(skb);
@@ -1687,24 +1687,25 @@ int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr)
 {
        struct inet_sock *inet = inet_sk(sk);
        struct ip_mc_socklist *iml, **imlp;
+       struct in_device *in_dev;
+       u32 group = imr->imr_multiaddr.s_addr;
+       u32 ifindex;
 
        rtnl_lock();
+       in_dev = ip_mc_find_dev(imr);
+       if (!in_dev) {
+               rtnl_unlock();
+               return -ENODEV;
+       }
+       ifindex = imr->imr_ifindex;
        for (imlp = &inet->mc_list; (iml = *imlp) != NULL; imlp = &iml->next) {
-               if (iml->multi.imr_multiaddr.s_addr==imr->imr_multiaddr.s_addr &&
-                   iml->multi.imr_address.s_addr==imr->imr_address.s_addr &&
-                   (!imr->imr_ifindex || iml->multi.imr_ifindex==imr->imr_ifindex)) {
-                       struct in_device *in_dev;
-
-                       in_dev = inetdev_by_index(iml->multi.imr_ifindex);
-                       if (in_dev)
-                               (void) ip_mc_leave_src(sk, iml, in_dev);
+               if (iml->multi.imr_multiaddr.s_addr == group &&
+                   iml->multi.imr_ifindex == ifindex) {
+                       (void) ip_mc_leave_src(sk, iml, in_dev);
 
                        *imlp = iml->next;
 
-                       if (in_dev) {
-                               ip_mc_dec_group(in_dev, imr->imr_multiaddr.s_addr);
-                               in_dev_put(in_dev);
-                       }
+                       ip_mc_dec_group(in_dev, group);
                        rtnl_unlock();
                        sock_kfree_s(sk, iml, sizeof(*iml));
                        return 0;
@@ -1724,6 +1725,7 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct
        struct in_device *in_dev = NULL;
        struct inet_sock *inet = inet_sk(sk);
        struct ip_sf_socklist *psl;
+       int leavegroup = 0;
        int i, j, rv;
 
        if (!MULTICAST(addr))
@@ -1747,12 +1749,16 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct
                    && pmc->multi.imr_ifindex == imr.imr_ifindex)
                        break;
        }
-       if (!pmc)               /* must have a prior join */
+       if (!pmc) {             /* must have a prior join */
+               err = -EINVAL;
                goto done;
+       }
        /* if a source filter was set, must be the same mode as before */
        if (pmc->sflist) {
-               if (pmc->sfmode != omode)
+               if (pmc->sfmode != omode) {
+                       err = -EINVAL;
                        goto done;
+               }
        } else if (pmc->sfmode != omode) {
                /* allow mode switches for empty-set filters */
                ip_mc_add_src(in_dev, &mreqs->imr_multiaddr, omode, 0, NULL, 0);
@@ -1764,7 +1770,7 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct
        psl = pmc->sflist;
        if (!add) {
                if (!psl)
-                       goto done;
+                       goto done;      /* err = -EADDRNOTAVAIL */
                rv = !0;
                for (i=0; i<psl->sl_count; i++) {
                        rv = memcmp(&psl->sl_addr[i], &mreqs->imr_sourceaddr,
@@ -1773,7 +1779,13 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct
                                break;
                }
                if (rv)         /* source not found */
+                       goto done;      /* err = -EADDRNOTAVAIL */
+
+               /* special case - (INCLUDE, empty) == LEAVE_GROUP */
+               if (psl->sl_count == 1 && omode == MCAST_INCLUDE) {
+                       leavegroup = 1;
                        goto done;
+               }
 
                /* update the interface filter */
                ip_mc_del_src(in_dev, &mreqs->imr_multiaddr, omode, 1, 
@@ -1831,18 +1843,21 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct
                &mreqs->imr_sourceaddr, 1);
 done:
        rtnl_shunlock();
+       if (leavegroup)
+               return ip_mc_leave_group(sk, &imr);
        return err;
 }
 
 int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex)
 {
-       int err;
+       int err = 0;
        struct ip_mreqn imr;
        u32 addr = msf->imsf_multiaddr;
        struct ip_mc_socklist *pmc;
        struct in_device *in_dev;
        struct inet_sock *inet = inet_sk(sk);
        struct ip_sf_socklist *newpsl, *psl;
+       int leavegroup = 0;
 
        if (!MULTICAST(addr))
                return -EINVAL;
@@ -1861,15 +1876,22 @@ int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex)
                err = -ENODEV;
                goto done;
        }
-       err = -EADDRNOTAVAIL;
+
+       /* special case - (INCLUDE, empty) == LEAVE_GROUP */
+       if (msf->imsf_fmode == MCAST_INCLUDE && msf->imsf_numsrc == 0) {
+               leavegroup = 1;
+               goto done;
+       }
 
        for (pmc=inet->mc_list; pmc; pmc=pmc->next) {
                if (pmc->multi.imr_multiaddr.s_addr == msf->imsf_multiaddr &&
                    pmc->multi.imr_ifindex == imr.imr_ifindex)
                        break;
        }
-       if (!pmc)               /* must have a prior join */
+       if (!pmc) {             /* must have a prior join */
+               err = -EINVAL;
                goto done;
+       }
        if (msf->imsf_numsrc) {
                newpsl = (struct ip_sf_socklist *)sock_kmalloc(sk,
                                IP_SFLSIZE(msf->imsf_numsrc), GFP_KERNEL);
@@ -1898,8 +1920,11 @@ int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex)
                        0, NULL, 0);
        pmc->sflist = newpsl;
        pmc->sfmode = msf->imsf_fmode;
+       err = 0;
 done:
        rtnl_shunlock();
+       if (leavegroup)
+               err = ip_mc_leave_group(sk, &imr);
        return err;
 }