hc
2024-05-11 04dd17822334871b23ea2862f7798fb0e0007777
kernel/net/ipv4/igmp.c
....@@ -1,3 +1,4 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * Linux NET3: Internet Group Management Protocol [IGMP]
34 *
....@@ -10,11 +11,6 @@
1011 *
1112 * Authors:
1213 * Alan Cox <alan@lxorguk.ukuu.org.uk>
13
- *
14
- * This program is free software; you can redistribute it and/or
15
- * modify it under the terms of the GNU General Public License
16
- * as published by the Free Software Foundation; either version
17
- * 2 of the License, or (at your option) any later version.
1814 *
1915 * Fixes:
2016 *
....@@ -111,8 +107,6 @@
111107 #ifdef CONFIG_IP_MULTICAST
112108 /* Parameter names and values are taken from igmp-v2-06 draft */
113109
114
-#define IGMP_V2_UNSOLICITED_REPORT_INTERVAL (10*HZ)
115
-#define IGMP_V3_UNSOLICITED_REPORT_INTERVAL (1*HZ)
116110 #define IGMP_QUERY_INTERVAL (125*HZ)
117111 #define IGMP_QUERY_RESPONSE_INTERVAL (10*HZ)
118112
....@@ -159,7 +153,8 @@
159153 return interval_jiffies;
160154 }
161155
162
-static void igmpv3_add_delrec(struct in_device *in_dev, struct ip_mc_list *im);
156
+static void igmpv3_add_delrec(struct in_device *in_dev, struct ip_mc_list *im,
157
+ gfp_t gfp);
163158 static void igmpv3_del_delrec(struct in_device *in_dev, struct ip_mc_list *im);
164159 static void igmpv3_clear_delrec(struct in_device *in_dev);
165160 static int sf_setstate(struct ip_mc_list *pmc);
....@@ -335,14 +330,15 @@
335330 const struct flowi4 *fl4)
336331 {
337332 struct in_device *in_dev = __in_dev_get_rcu(dev);
333
+ const struct in_ifaddr *ifa;
338334
339335 if (!in_dev)
340336 return htonl(INADDR_ANY);
341337
342
- for_ifa(in_dev) {
338
+ in_dev_for_each_ifa_rcu(ifa, in_dev) {
343339 if (fl4->saddr == ifa->ifa_local)
344340 return fl4->saddr;
345
- } endfor_ifa(in_dev);
341
+ }
346342
347343 return htonl(INADDR_ANY);
348344 }
....@@ -357,8 +353,9 @@
357353 struct flowi4 fl4;
358354 int hlen = LL_RESERVED_SPACE(dev);
359355 int tlen = dev->needed_tailroom;
360
- unsigned int size = mtu;
356
+ unsigned int size;
361357
358
+ size = min(mtu, IP_MAX_MTU);
362359 while (1) {
363360 skb = alloc_skb(size + hlen + tlen,
364361 GFP_ATOMIC | __GFP_NOWARN);
....@@ -471,7 +468,8 @@
471468
472469 if (pmc->multiaddr == IGMP_ALL_HOSTS)
473470 return skb;
474
- if (ipv4_is_local_multicast(pmc->multiaddr) && !net->ipv4.sysctl_igmp_llm_reports)
471
+ if (ipv4_is_local_multicast(pmc->multiaddr) &&
472
+ !READ_ONCE(net->ipv4.sysctl_igmp_llm_reports))
475473 return skb;
476474
477475 mtu = READ_ONCE(dev->mtu);
....@@ -597,7 +595,7 @@
597595 if (pmc->multiaddr == IGMP_ALL_HOSTS)
598596 continue;
599597 if (ipv4_is_local_multicast(pmc->multiaddr) &&
600
- !net->ipv4.sysctl_igmp_llm_reports)
598
+ !READ_ONCE(net->ipv4.sysctl_igmp_llm_reports))
601599 continue;
602600 spin_lock_bh(&pmc->lock);
603601 if (pmc->sfcount[MCAST_EXCLUDE])
....@@ -740,7 +738,8 @@
740738 if (type == IGMPV3_HOST_MEMBERSHIP_REPORT)
741739 return igmpv3_send_report(in_dev, pmc);
742740
743
- if (ipv4_is_local_multicast(group) && !net->ipv4.sysctl_igmp_llm_reports)
741
+ if (ipv4_is_local_multicast(group) &&
742
+ !READ_ONCE(net->ipv4.sysctl_igmp_llm_reports))
744743 return 0;
745744
746745 if (type == IGMP_HOST_LEAVE_MESSAGE)
....@@ -822,7 +821,7 @@
822821 struct net *net = dev_net(in_dev->dev);
823822 if (IGMP_V1_SEEN(in_dev) || IGMP_V2_SEEN(in_dev))
824823 return;
825
- in_dev->mr_ifc_count = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv;
824
+ in_dev->mr_ifc_count = in_dev->mr_qrv ?: READ_ONCE(net->ipv4.sysctl_igmp_qrv);
826825 igmp_ifc_start_timer(in_dev, 1);
827826 }
828827
....@@ -917,7 +916,8 @@
917916
918917 if (group == IGMP_ALL_HOSTS)
919918 return false;
920
- if (ipv4_is_local_multicast(group) && !net->ipv4.sysctl_igmp_llm_reports)
919
+ if (ipv4_is_local_multicast(group) &&
920
+ !READ_ONCE(net->ipv4.sysctl_igmp_llm_reports))
921921 return false;
922922
923923 rcu_read_lock();
....@@ -1003,7 +1003,7 @@
10031003 * received value was zero, use the default or statically
10041004 * configured value.
10051005 */
1006
- in_dev->mr_qrv = ih3->qrv ?: net->ipv4.sysctl_igmp_qrv;
1006
+ in_dev->mr_qrv = ih3->qrv ?: READ_ONCE(net->ipv4.sysctl_igmp_qrv);
10071007 in_dev->mr_qi = IGMPV3_QQIC(ih3->qqic)*HZ ?: IGMP_QUERY_INTERVAL;
10081008
10091009 /* RFC3376, 8.3. Query Response Interval:
....@@ -1042,7 +1042,7 @@
10421042 if (im->multiaddr == IGMP_ALL_HOSTS)
10431043 continue;
10441044 if (ipv4_is_local_multicast(im->multiaddr) &&
1045
- !net->ipv4.sysctl_igmp_llm_reports)
1045
+ !READ_ONCE(net->ipv4.sysctl_igmp_llm_reports))
10461046 continue;
10471047 spin_lock_bh(&im->lock);
10481048 if (im->tm_running)
....@@ -1163,7 +1163,8 @@
11631163 /*
11641164 * deleted ip_mc_list manipulation
11651165 */
1166
-static void igmpv3_add_delrec(struct in_device *in_dev, struct ip_mc_list *im)
1166
+static void igmpv3_add_delrec(struct in_device *in_dev, struct ip_mc_list *im,
1167
+ gfp_t gfp)
11671168 {
11681169 struct ip_mc_list *pmc;
11691170 struct net *net = dev_net(in_dev->dev);
....@@ -1174,7 +1175,7 @@
11741175 * for deleted items allows change reports to use common code with
11751176 * non-deleted or query-response MCA's.
11761177 */
1177
- pmc = kzalloc(sizeof(*pmc), GFP_KERNEL);
1178
+ pmc = kzalloc(sizeof(*pmc), gfp);
11781179 if (!pmc)
11791180 return;
11801181 spin_lock_init(&pmc->lock);
....@@ -1182,7 +1183,7 @@
11821183 pmc->interface = im->interface;
11831184 in_dev_hold(in_dev);
11841185 pmc->multiaddr = im->multiaddr;
1185
- pmc->crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv;
1186
+ pmc->crcount = in_dev->mr_qrv ?: READ_ONCE(net->ipv4.sysctl_igmp_qrv);
11861187 pmc->sfmode = im->sfmode;
11871188 if (pmc->sfmode == MCAST_INCLUDE) {
11881189 struct ip_sf_list *psf;
....@@ -1233,9 +1234,11 @@
12331234 swap(im->tomb, pmc->tomb);
12341235 swap(im->sources, pmc->sources);
12351236 for (psf = im->sources; psf; psf = psf->sf_next)
1236
- psf->sf_crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv;
1237
+ psf->sf_crcount = in_dev->mr_qrv ?:
1238
+ READ_ONCE(net->ipv4.sysctl_igmp_qrv);
12371239 } else {
1238
- im->crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv;
1240
+ im->crcount = in_dev->mr_qrv ?:
1241
+ READ_ONCE(net->ipv4.sysctl_igmp_qrv);
12391242 }
12401243 in_dev_put(pmc->interface);
12411244 kfree_pmc(pmc);
....@@ -1276,7 +1279,7 @@
12761279 }
12771280 #endif
12781281
1279
-static void igmp_group_dropped(struct ip_mc_list *im)
1282
+static void __igmp_group_dropped(struct ip_mc_list *im, gfp_t gfp)
12801283 {
12811284 struct in_device *in_dev = im->interface;
12821285 #ifdef CONFIG_IP_MULTICAST
....@@ -1292,7 +1295,8 @@
12921295 #ifdef CONFIG_IP_MULTICAST
12931296 if (im->multiaddr == IGMP_ALL_HOSTS)
12941297 return;
1295
- if (ipv4_is_local_multicast(im->multiaddr) && !net->ipv4.sysctl_igmp_llm_reports)
1298
+ if (ipv4_is_local_multicast(im->multiaddr) &&
1299
+ !READ_ONCE(net->ipv4.sysctl_igmp_llm_reports))
12961300 return;
12971301
12981302 reporter = im->reporter;
....@@ -1307,11 +1311,16 @@
13071311 return;
13081312 }
13091313 /* IGMPv3 */
1310
- igmpv3_add_delrec(in_dev, im);
1314
+ igmpv3_add_delrec(in_dev, im, gfp);
13111315
13121316 igmp_ifc_event(in_dev);
13131317 }
13141318 #endif
1319
+}
1320
+
1321
+static void igmp_group_dropped(struct ip_mc_list *im)
1322
+{
1323
+ __igmp_group_dropped(im, GFP_KERNEL);
13151324 }
13161325
13171326 static void igmp_group_added(struct ip_mc_list *im)
....@@ -1329,13 +1338,14 @@
13291338 #ifdef CONFIG_IP_MULTICAST
13301339 if (im->multiaddr == IGMP_ALL_HOSTS)
13311340 return;
1332
- if (ipv4_is_local_multicast(im->multiaddr) && !net->ipv4.sysctl_igmp_llm_reports)
1341
+ if (ipv4_is_local_multicast(im->multiaddr) &&
1342
+ !READ_ONCE(net->ipv4.sysctl_igmp_llm_reports))
13331343 return;
13341344
13351345 if (in_dev->dead)
13361346 return;
13371347
1338
- im->unsolicit_count = net->ipv4.sysctl_igmp_qrv;
1348
+ im->unsolicit_count = READ_ONCE(net->ipv4.sysctl_igmp_qrv);
13391349 if (IGMP_V1_SEEN(in_dev) || IGMP_V2_SEEN(in_dev)) {
13401350 spin_lock_bh(&im->lock);
13411351 igmp_start_timer(im, IGMP_INITIAL_REPORT_DELAY);
....@@ -1349,7 +1359,7 @@
13491359 * IN() to IN(A).
13501360 */
13511361 if (im->sfmode == MCAST_EXCLUDE)
1352
- im->crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv;
1362
+ im->crcount = in_dev->mr_qrv ?: READ_ONCE(net->ipv4.sysctl_igmp_qrv);
13531363
13541364 igmp_ifc_event(in_dev);
13551365 #endif
....@@ -1415,8 +1425,8 @@
14151425 /*
14161426 * A socket has joined a multicast group on device dev.
14171427 */
1418
-static void __ip_mc_inc_group(struct in_device *in_dev, __be32 addr,
1419
- unsigned int mode)
1428
+static void ____ip_mc_inc_group(struct in_device *in_dev, __be32 addr,
1429
+ unsigned int mode, gfp_t gfp)
14201430 {
14211431 struct ip_mc_list *im;
14221432
....@@ -1430,7 +1440,7 @@
14301440 }
14311441 }
14321442
1433
- im = kzalloc(sizeof(*im), GFP_KERNEL);
1443
+ im = kzalloc(sizeof(*im), gfp);
14341444 if (!im)
14351445 goto out;
14361446
....@@ -1463,9 +1473,15 @@
14631473 return;
14641474 }
14651475
1476
+void __ip_mc_inc_group(struct in_device *in_dev, __be32 addr, gfp_t gfp)
1477
+{
1478
+ ____ip_mc_inc_group(in_dev, addr, MCAST_EXCLUDE, gfp);
1479
+}
1480
+EXPORT_SYMBOL(__ip_mc_inc_group);
1481
+
14661482 void ip_mc_inc_group(struct in_device *in_dev, __be32 addr)
14671483 {
1468
- __ip_mc_inc_group(in_dev, addr, MCAST_EXCLUDE);
1484
+ __ip_mc_inc_group(in_dev, addr, GFP_KERNEL);
14691485 }
14701486 EXPORT_SYMBOL(ip_mc_inc_group);
14711487
....@@ -1508,22 +1524,22 @@
15081524
15091525 len += sizeof(struct igmpv3_report);
15101526
1511
- return pskb_may_pull(skb, len) ? 0 : -EINVAL;
1527
+ return ip_mc_may_pull(skb, len) ? 0 : -EINVAL;
15121528 }
15131529
15141530 static int ip_mc_check_igmp_query(struct sk_buff *skb)
15151531 {
1516
- unsigned int len = skb_transport_offset(skb);
1517
-
1518
- len += sizeof(struct igmphdr);
1519
- if (skb->len < len)
1520
- return -EINVAL;
1532
+ unsigned int transport_len = ip_transport_len(skb);
1533
+ unsigned int len;
15211534
15221535 /* IGMPv{1,2}? */
1523
- if (skb->len != len) {
1536
+ if (transport_len != sizeof(struct igmphdr)) {
15241537 /* or IGMPv3? */
1525
- len += sizeof(struct igmpv3_query) - sizeof(struct igmphdr);
1526
- if (skb->len < len || !pskb_may_pull(skb, len))
1538
+ if (transport_len < sizeof(struct igmpv3_query))
1539
+ return -EINVAL;
1540
+
1541
+ len = skb_transport_offset(skb) + sizeof(struct igmpv3_query);
1542
+ if (!ip_mc_may_pull(skb, len))
15271543 return -EINVAL;
15281544 }
15291545
....@@ -1543,7 +1559,6 @@
15431559 case IGMP_HOST_LEAVE_MESSAGE:
15441560 case IGMP_HOST_MEMBERSHIP_REPORT:
15451561 case IGMPV2_HOST_MEMBERSHIP_REPORT:
1546
- /* fall through */
15471562 return 0;
15481563 case IGMPV3_HOST_MEMBERSHIP_REPORT:
15491564 return ip_mc_check_igmp_reportv3(skb);
....@@ -1554,52 +1569,34 @@
15541569 }
15551570 }
15561571
1557
-static inline __sum16 ip_mc_validate_checksum(struct sk_buff *skb)
1572
+static __sum16 ip_mc_validate_checksum(struct sk_buff *skb)
15581573 {
15591574 return skb_checksum_simple_validate(skb);
15601575 }
15611576
1562
-static int __ip_mc_check_igmp(struct sk_buff *skb, struct sk_buff **skb_trimmed)
1563
-
1577
+static int ip_mc_check_igmp_csum(struct sk_buff *skb)
15641578 {
1565
- struct sk_buff *skb_chk;
1566
- unsigned int transport_len;
15671579 unsigned int len = skb_transport_offset(skb) + sizeof(struct igmphdr);
1568
- int ret = -EINVAL;
1580
+ unsigned int transport_len = ip_transport_len(skb);
1581
+ struct sk_buff *skb_chk;
15691582
1570
- transport_len = ntohs(ip_hdr(skb)->tot_len) - ip_hdrlen(skb);
1583
+ if (!ip_mc_may_pull(skb, len))
1584
+ return -EINVAL;
15711585
15721586 skb_chk = skb_checksum_trimmed(skb, transport_len,
15731587 ip_mc_validate_checksum);
15741588 if (!skb_chk)
1575
- goto err;
1589
+ return -EINVAL;
15761590
1577
- if (!pskb_may_pull(skb_chk, len))
1578
- goto err;
1579
-
1580
- ret = ip_mc_check_igmp_msg(skb_chk);
1581
- if (ret)
1582
- goto err;
1583
-
1584
- if (skb_trimmed)
1585
- *skb_trimmed = skb_chk;
1586
- /* free now unneeded clone */
1587
- else if (skb_chk != skb)
1591
+ if (skb_chk != skb)
15881592 kfree_skb(skb_chk);
15891593
1590
- ret = 0;
1591
-
1592
-err:
1593
- if (ret && skb_chk && skb_chk != skb)
1594
- kfree_skb(skb_chk);
1595
-
1596
- return ret;
1594
+ return 0;
15971595 }
15981596
15991597 /**
16001598 * ip_mc_check_igmp - checks whether this is a sane IGMP packet
16011599 * @skb: the skb to validate
1602
- * @skb_trimmed: to store an skb pointer trimmed to IPv4 packet tail (optional)
16031600 *
16041601 * Checks whether an IPv4 packet is a valid IGMP packet. If so sets
16051602 * skb transport header accordingly and returns zero.
....@@ -1609,18 +1606,10 @@
16091606 * -ENOMSG: IP header validation succeeded but it is not an IGMP packet.
16101607 * -ENOMEM: A memory allocation failure happened.
16111608 *
1612
- * Optionally, an skb pointer might be provided via skb_trimmed (or set it
1613
- * to NULL): After parsing an IGMP packet successfully it will point to
1614
- * an skb which has its tail aligned to the IP packet end. This might
1615
- * either be the originally provided skb or a trimmed, cloned version if
1616
- * the skb frame had data beyond the IP packet. A cloned skb allows us
1617
- * to leave the original skb and its full frame unchanged (which might be
1618
- * desirable for layer 2 frame jugglers).
1619
- *
16201609 * Caller needs to set the skb network header and free any returned skb if it
16211610 * differs from the provided skb.
16221611 */
1623
-int ip_mc_check_igmp(struct sk_buff *skb, struct sk_buff **skb_trimmed)
1612
+int ip_mc_check_igmp(struct sk_buff *skb)
16241613 {
16251614 int ret = ip_mc_check_iphdr(skb);
16261615
....@@ -1630,7 +1619,11 @@
16301619 if (ip_hdr(skb)->protocol != IPPROTO_IGMP)
16311620 return -ENOMSG;
16321621
1633
- return __ip_mc_check_igmp(skb, skb_trimmed);
1622
+ ret = ip_mc_check_igmp_csum(skb);
1623
+ if (ret < 0)
1624
+ return ret;
1625
+
1626
+ return ip_mc_check_igmp_msg(skb);
16341627 }
16351628 EXPORT_SYMBOL(ip_mc_check_igmp);
16361629
....@@ -1650,7 +1643,7 @@
16501643 if (im->multiaddr == IGMP_ALL_HOSTS)
16511644 continue;
16521645 if (ipv4_is_local_multicast(im->multiaddr) &&
1653
- !net->ipv4.sysctl_igmp_llm_reports)
1646
+ !READ_ONCE(net->ipv4.sysctl_igmp_llm_reports))
16541647 continue;
16551648
16561649 /* a failover is happening and switches
....@@ -1671,7 +1664,7 @@
16711664 * A socket has left a multicast group on device dev
16721665 */
16731666
1674
-void ip_mc_dec_group(struct in_device *in_dev, __be32 addr)
1667
+void __ip_mc_dec_group(struct in_device *in_dev, __be32 addr, gfp_t gfp)
16751668 {
16761669 struct ip_mc_list *i;
16771670 struct ip_mc_list __rcu **ip;
....@@ -1686,7 +1679,7 @@
16861679 ip_mc_hash_remove(in_dev, i);
16871680 *ip = i->next_rcu;
16881681 in_dev->mc_count--;
1689
- igmp_group_dropped(i);
1682
+ __igmp_group_dropped(i, gfp);
16901683 ip_mc_clear_src(i);
16911684
16921685 if (!in_dev->dead)
....@@ -1699,7 +1692,7 @@
16991692 }
17001693 }
17011694 }
1702
-EXPORT_SYMBOL(ip_mc_dec_group);
1695
+EXPORT_SYMBOL(__ip_mc_dec_group);
17031696
17041697 /* Device changing type */
17051698
....@@ -1757,7 +1750,7 @@
17571750
17581751 in_dev->mr_qi = IGMP_QUERY_INTERVAL;
17591752 in_dev->mr_qri = IGMP_QUERY_RESPONSE_INTERVAL;
1760
- in_dev->mr_qrv = net->ipv4.sysctl_igmp_qrv;
1753
+ in_dev->mr_qrv = READ_ONCE(net->ipv4.sysctl_igmp_qrv);
17611754 }
17621755 #else
17631756 static void ip_mc_reset(struct in_device *in_dev)
....@@ -1891,7 +1884,7 @@
18911884 #ifdef CONFIG_IP_MULTICAST
18921885 if (psf->sf_oldin &&
18931886 !IGMP_V1_SEEN(in_dev) && !IGMP_V2_SEEN(in_dev)) {
1894
- psf->sf_crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv;
1887
+ psf->sf_crcount = in_dev->mr_qrv ?: READ_ONCE(net->ipv4.sysctl_igmp_qrv);
18951888 psf->sf_next = pmc->tomb;
18961889 pmc->tomb = psf;
18971890 rv = 1;
....@@ -1955,7 +1948,7 @@
19551948 /* filter mode change */
19561949 pmc->sfmode = MCAST_INCLUDE;
19571950 #ifdef CONFIG_IP_MULTICAST
1958
- pmc->crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv;
1951
+ pmc->crcount = in_dev->mr_qrv ?: READ_ONCE(net->ipv4.sysctl_igmp_qrv);
19591952 in_dev->mr_ifc_count = pmc->crcount;
19601953 for (psf = pmc->sources; psf; psf = psf->sf_next)
19611954 psf->sf_crcount = 0;
....@@ -2134,7 +2127,7 @@
21342127 #ifdef CONFIG_IP_MULTICAST
21352128 /* else no filters; keep old mode for reports */
21362129
2137
- pmc->crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv;
2130
+ pmc->crcount = in_dev->mr_qrv ?: READ_ONCE(net->ipv4.sysctl_igmp_qrv);
21382131 in_dev->mr_ifc_count = pmc->crcount;
21392132 for (psf = pmc->sources; psf; psf = psf->sf_next)
21402133 psf->sf_crcount = 0;
....@@ -2200,7 +2193,7 @@
22002193 count++;
22012194 }
22022195 err = -ENOBUFS;
2203
- if (count >= net->ipv4.sysctl_igmp_max_memberships)
2196
+ if (count >= READ_ONCE(net->ipv4.sysctl_igmp_max_memberships))
22042197 goto done;
22052198 iml = sock_kmalloc(sk, sizeof(*iml), GFP_KERNEL);
22062199 if (!iml)
....@@ -2211,7 +2204,7 @@
22112204 iml->sflist = NULL;
22122205 iml->sfmode = mode;
22132206 rcu_assign_pointer(inet->mc_list, iml);
2214
- __ip_mc_inc_group(in_dev, addr, mode);
2207
+ ____ip_mc_inc_group(in_dev, addr, mode, GFP_KERNEL);
22152208 err = 0;
22162209 done:
22172210 return err;
....@@ -2387,7 +2380,7 @@
23872380 }
23882381 /* else, add a new source to the filter */
23892382
2390
- if (psl && psl->sl_count >= net->ipv4.sysctl_igmp_max_msf) {
2383
+ if (psl && psl->sl_count >= READ_ONCE(net->ipv4.sysctl_igmp_max_msf)) {
23912384 err = -ENOBUFS;
23922385 goto done;
23932386 }
....@@ -2409,9 +2402,10 @@
24092402 newpsl->sl_addr[i] = psl->sl_addr[i];
24102403 /* decrease mem now to avoid the memleak warning */
24112404 atomic_sub(IP_SFLSIZE(psl->sl_max), &sk->sk_omem_alloc);
2412
- kfree_rcu(psl, rcu);
24132405 }
24142406 rcu_assign_pointer(pmc->sflist, newpsl);
2407
+ if (psl)
2408
+ kfree_rcu(psl, rcu);
24152409 psl = newpsl;
24162410 }
24172411 rv = 1; /* > 0 for insert logic below if sl_count is 0 */
....@@ -2509,11 +2503,13 @@
25092503 psl->sl_count, psl->sl_addr, 0);
25102504 /* decrease mem now to avoid the memleak warning */
25112505 atomic_sub(IP_SFLSIZE(psl->sl_max), &sk->sk_omem_alloc);
2512
- kfree_rcu(psl, rcu);
2513
- } else
2506
+ } else {
25142507 (void) ip_mc_del_src(in_dev, &msf->imsf_multiaddr, pmc->sfmode,
25152508 0, NULL, 0);
2509
+ }
25162510 rcu_assign_pointer(pmc->sflist, newpsl);
2511
+ if (psl)
2512
+ kfree_rcu(psl, rcu);
25172513 pmc->sfmode = msf->imsf_fmode;
25182514 err = 0;
25192515 done:
....@@ -2581,9 +2577,9 @@
25812577 }
25822578
25832579 int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf,
2584
- struct group_filter __user *optval, int __user *optlen)
2580
+ struct sockaddr_storage __user *p)
25852581 {
2586
- int err, i, count, copycount;
2582
+ int i, count, copycount;
25872583 struct sockaddr_in *psin;
25882584 __be32 addr;
25892585 struct ip_mc_socklist *pmc;
....@@ -2599,37 +2595,29 @@
25992595 if (!ipv4_is_multicast(addr))
26002596 return -EINVAL;
26012597
2602
- err = -EADDRNOTAVAIL;
2603
-
26042598 for_each_pmc_rtnl(inet, pmc) {
26052599 if (pmc->multi.imr_multiaddr.s_addr == addr &&
26062600 pmc->multi.imr_ifindex == gsf->gf_interface)
26072601 break;
26082602 }
26092603 if (!pmc) /* must have a prior join */
2610
- goto done;
2604
+ return -EADDRNOTAVAIL;
26112605 gsf->gf_fmode = pmc->sfmode;
26122606 psl = rtnl_dereference(pmc->sflist);
26132607 count = psl ? psl->sl_count : 0;
26142608 copycount = count < gsf->gf_numsrc ? count : gsf->gf_numsrc;
26152609 gsf->gf_numsrc = count;
2616
- if (put_user(GROUP_FILTER_SIZE(copycount), optlen) ||
2617
- copy_to_user(optval, gsf, GROUP_FILTER_SIZE(0))) {
2618
- return -EFAULT;
2619
- }
2620
- for (i = 0; i < copycount; i++) {
2610
+ for (i = 0; i < copycount; i++, p++) {
26212611 struct sockaddr_storage ss;
26222612
26232613 psin = (struct sockaddr_in *)&ss;
26242614 memset(&ss, 0, sizeof(ss));
26252615 psin->sin_family = AF_INET;
26262616 psin->sin_addr.s_addr = psl->sl_addr[i];
2627
- if (copy_to_user(&optval->gf_slist[i], &ss, sizeof(ss)))
2617
+ if (copy_to_user(p, &ss, sizeof(ss)))
26282618 return -EFAULT;
26292619 }
26302620 return 0;
2631
-done:
2632
- return err;
26332621 }
26342622
26352623 /*