forked from ~ljy/RK356X_SDK_RELEASE

hc
2023-12-11 072de836f53be56a70cecf70b43ae43b7ce17376
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 }
....@@ -471,7 +467,8 @@
471467
472468 if (pmc->multiaddr == IGMP_ALL_HOSTS)
473469 return skb;
474
- if (ipv4_is_local_multicast(pmc->multiaddr) && !net->ipv4.sysctl_igmp_llm_reports)
470
+ if (ipv4_is_local_multicast(pmc->multiaddr) &&
471
+ !READ_ONCE(net->ipv4.sysctl_igmp_llm_reports))
475472 return skb;
476473
477474 mtu = READ_ONCE(dev->mtu);
....@@ -597,7 +594,7 @@
597594 if (pmc->multiaddr == IGMP_ALL_HOSTS)
598595 continue;
599596 if (ipv4_is_local_multicast(pmc->multiaddr) &&
600
- !net->ipv4.sysctl_igmp_llm_reports)
597
+ !READ_ONCE(net->ipv4.sysctl_igmp_llm_reports))
601598 continue;
602599 spin_lock_bh(&pmc->lock);
603600 if (pmc->sfcount[MCAST_EXCLUDE])
....@@ -740,7 +737,8 @@
740737 if (type == IGMPV3_HOST_MEMBERSHIP_REPORT)
741738 return igmpv3_send_report(in_dev, pmc);
742739
743
- if (ipv4_is_local_multicast(group) && !net->ipv4.sysctl_igmp_llm_reports)
740
+ if (ipv4_is_local_multicast(group) &&
741
+ !READ_ONCE(net->ipv4.sysctl_igmp_llm_reports))
744742 return 0;
745743
746744 if (type == IGMP_HOST_LEAVE_MESSAGE)
....@@ -822,7 +820,7 @@
822820 struct net *net = dev_net(in_dev->dev);
823821 if (IGMP_V1_SEEN(in_dev) || IGMP_V2_SEEN(in_dev))
824822 return;
825
- in_dev->mr_ifc_count = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv;
823
+ in_dev->mr_ifc_count = in_dev->mr_qrv ?: READ_ONCE(net->ipv4.sysctl_igmp_qrv);
826824 igmp_ifc_start_timer(in_dev, 1);
827825 }
828826
....@@ -917,7 +915,8 @@
917915
918916 if (group == IGMP_ALL_HOSTS)
919917 return false;
920
- if (ipv4_is_local_multicast(group) && !net->ipv4.sysctl_igmp_llm_reports)
918
+ if (ipv4_is_local_multicast(group) &&
919
+ !READ_ONCE(net->ipv4.sysctl_igmp_llm_reports))
921920 return false;
922921
923922 rcu_read_lock();
....@@ -1003,7 +1002,7 @@
10031002 * received value was zero, use the default or statically
10041003 * configured value.
10051004 */
1006
- in_dev->mr_qrv = ih3->qrv ?: net->ipv4.sysctl_igmp_qrv;
1005
+ in_dev->mr_qrv = ih3->qrv ?: READ_ONCE(net->ipv4.sysctl_igmp_qrv);
10071006 in_dev->mr_qi = IGMPV3_QQIC(ih3->qqic)*HZ ?: IGMP_QUERY_INTERVAL;
10081007
10091008 /* RFC3376, 8.3. Query Response Interval:
....@@ -1042,7 +1041,7 @@
10421041 if (im->multiaddr == IGMP_ALL_HOSTS)
10431042 continue;
10441043 if (ipv4_is_local_multicast(im->multiaddr) &&
1045
- !net->ipv4.sysctl_igmp_llm_reports)
1044
+ !READ_ONCE(net->ipv4.sysctl_igmp_llm_reports))
10461045 continue;
10471046 spin_lock_bh(&im->lock);
10481047 if (im->tm_running)
....@@ -1163,7 +1162,8 @@
11631162 /*
11641163 * deleted ip_mc_list manipulation
11651164 */
1166
-static void igmpv3_add_delrec(struct in_device *in_dev, struct ip_mc_list *im)
1165
+static void igmpv3_add_delrec(struct in_device *in_dev, struct ip_mc_list *im,
1166
+ gfp_t gfp)
11671167 {
11681168 struct ip_mc_list *pmc;
11691169 struct net *net = dev_net(in_dev->dev);
....@@ -1174,7 +1174,7 @@
11741174 * for deleted items allows change reports to use common code with
11751175 * non-deleted or query-response MCA's.
11761176 */
1177
- pmc = kzalloc(sizeof(*pmc), GFP_KERNEL);
1177
+ pmc = kzalloc(sizeof(*pmc), gfp);
11781178 if (!pmc)
11791179 return;
11801180 spin_lock_init(&pmc->lock);
....@@ -1182,7 +1182,7 @@
11821182 pmc->interface = im->interface;
11831183 in_dev_hold(in_dev);
11841184 pmc->multiaddr = im->multiaddr;
1185
- pmc->crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv;
1185
+ pmc->crcount = in_dev->mr_qrv ?: READ_ONCE(net->ipv4.sysctl_igmp_qrv);
11861186 pmc->sfmode = im->sfmode;
11871187 if (pmc->sfmode == MCAST_INCLUDE) {
11881188 struct ip_sf_list *psf;
....@@ -1233,9 +1233,11 @@
12331233 swap(im->tomb, pmc->tomb);
12341234 swap(im->sources, pmc->sources);
12351235 for (psf = im->sources; psf; psf = psf->sf_next)
1236
- psf->sf_crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv;
1236
+ psf->sf_crcount = in_dev->mr_qrv ?:
1237
+ READ_ONCE(net->ipv4.sysctl_igmp_qrv);
12371238 } else {
1238
- im->crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv;
1239
+ im->crcount = in_dev->mr_qrv ?:
1240
+ READ_ONCE(net->ipv4.sysctl_igmp_qrv);
12391241 }
12401242 in_dev_put(pmc->interface);
12411243 kfree_pmc(pmc);
....@@ -1276,7 +1278,7 @@
12761278 }
12771279 #endif
12781280
1279
-static void igmp_group_dropped(struct ip_mc_list *im)
1281
+static void __igmp_group_dropped(struct ip_mc_list *im, gfp_t gfp)
12801282 {
12811283 struct in_device *in_dev = im->interface;
12821284 #ifdef CONFIG_IP_MULTICAST
....@@ -1292,7 +1294,8 @@
12921294 #ifdef CONFIG_IP_MULTICAST
12931295 if (im->multiaddr == IGMP_ALL_HOSTS)
12941296 return;
1295
- if (ipv4_is_local_multicast(im->multiaddr) && !net->ipv4.sysctl_igmp_llm_reports)
1297
+ if (ipv4_is_local_multicast(im->multiaddr) &&
1298
+ !READ_ONCE(net->ipv4.sysctl_igmp_llm_reports))
12961299 return;
12971300
12981301 reporter = im->reporter;
....@@ -1307,11 +1310,16 @@
13071310 return;
13081311 }
13091312 /* IGMPv3 */
1310
- igmpv3_add_delrec(in_dev, im);
1313
+ igmpv3_add_delrec(in_dev, im, gfp);
13111314
13121315 igmp_ifc_event(in_dev);
13131316 }
13141317 #endif
1318
+}
1319
+
1320
+static void igmp_group_dropped(struct ip_mc_list *im)
1321
+{
1322
+ __igmp_group_dropped(im, GFP_KERNEL);
13151323 }
13161324
13171325 static void igmp_group_added(struct ip_mc_list *im)
....@@ -1329,13 +1337,14 @@
13291337 #ifdef CONFIG_IP_MULTICAST
13301338 if (im->multiaddr == IGMP_ALL_HOSTS)
13311339 return;
1332
- if (ipv4_is_local_multicast(im->multiaddr) && !net->ipv4.sysctl_igmp_llm_reports)
1340
+ if (ipv4_is_local_multicast(im->multiaddr) &&
1341
+ !READ_ONCE(net->ipv4.sysctl_igmp_llm_reports))
13331342 return;
13341343
13351344 if (in_dev->dead)
13361345 return;
13371346
1338
- im->unsolicit_count = net->ipv4.sysctl_igmp_qrv;
1347
+ im->unsolicit_count = READ_ONCE(net->ipv4.sysctl_igmp_qrv);
13391348 if (IGMP_V1_SEEN(in_dev) || IGMP_V2_SEEN(in_dev)) {
13401349 spin_lock_bh(&im->lock);
13411350 igmp_start_timer(im, IGMP_INITIAL_REPORT_DELAY);
....@@ -1349,7 +1358,7 @@
13491358 * IN() to IN(A).
13501359 */
13511360 if (im->sfmode == MCAST_EXCLUDE)
1352
- im->crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv;
1361
+ im->crcount = in_dev->mr_qrv ?: READ_ONCE(net->ipv4.sysctl_igmp_qrv);
13531362
13541363 igmp_ifc_event(in_dev);
13551364 #endif
....@@ -1415,8 +1424,8 @@
14151424 /*
14161425 * A socket has joined a multicast group on device dev.
14171426 */
1418
-static void __ip_mc_inc_group(struct in_device *in_dev, __be32 addr,
1419
- unsigned int mode)
1427
+static void ____ip_mc_inc_group(struct in_device *in_dev, __be32 addr,
1428
+ unsigned int mode, gfp_t gfp)
14201429 {
14211430 struct ip_mc_list *im;
14221431
....@@ -1430,7 +1439,7 @@
14301439 }
14311440 }
14321441
1433
- im = kzalloc(sizeof(*im), GFP_KERNEL);
1442
+ im = kzalloc(sizeof(*im), gfp);
14341443 if (!im)
14351444 goto out;
14361445
....@@ -1463,9 +1472,15 @@
14631472 return;
14641473 }
14651474
1475
+void __ip_mc_inc_group(struct in_device *in_dev, __be32 addr, gfp_t gfp)
1476
+{
1477
+ ____ip_mc_inc_group(in_dev, addr, MCAST_EXCLUDE, gfp);
1478
+}
1479
+EXPORT_SYMBOL(__ip_mc_inc_group);
1480
+
14661481 void ip_mc_inc_group(struct in_device *in_dev, __be32 addr)
14671482 {
1468
- __ip_mc_inc_group(in_dev, addr, MCAST_EXCLUDE);
1483
+ __ip_mc_inc_group(in_dev, addr, GFP_KERNEL);
14691484 }
14701485 EXPORT_SYMBOL(ip_mc_inc_group);
14711486
....@@ -1508,22 +1523,22 @@
15081523
15091524 len += sizeof(struct igmpv3_report);
15101525
1511
- return pskb_may_pull(skb, len) ? 0 : -EINVAL;
1526
+ return ip_mc_may_pull(skb, len) ? 0 : -EINVAL;
15121527 }
15131528
15141529 static int ip_mc_check_igmp_query(struct sk_buff *skb)
15151530 {
1516
- unsigned int len = skb_transport_offset(skb);
1517
-
1518
- len += sizeof(struct igmphdr);
1519
- if (skb->len < len)
1520
- return -EINVAL;
1531
+ unsigned int transport_len = ip_transport_len(skb);
1532
+ unsigned int len;
15211533
15221534 /* IGMPv{1,2}? */
1523
- if (skb->len != len) {
1535
+ if (transport_len != sizeof(struct igmphdr)) {
15241536 /* or IGMPv3? */
1525
- len += sizeof(struct igmpv3_query) - sizeof(struct igmphdr);
1526
- if (skb->len < len || !pskb_may_pull(skb, len))
1537
+ if (transport_len < sizeof(struct igmpv3_query))
1538
+ return -EINVAL;
1539
+
1540
+ len = skb_transport_offset(skb) + sizeof(struct igmpv3_query);
1541
+ if (!ip_mc_may_pull(skb, len))
15271542 return -EINVAL;
15281543 }
15291544
....@@ -1543,7 +1558,6 @@
15431558 case IGMP_HOST_LEAVE_MESSAGE:
15441559 case IGMP_HOST_MEMBERSHIP_REPORT:
15451560 case IGMPV2_HOST_MEMBERSHIP_REPORT:
1546
- /* fall through */
15471561 return 0;
15481562 case IGMPV3_HOST_MEMBERSHIP_REPORT:
15491563 return ip_mc_check_igmp_reportv3(skb);
....@@ -1554,52 +1568,34 @@
15541568 }
15551569 }
15561570
1557
-static inline __sum16 ip_mc_validate_checksum(struct sk_buff *skb)
1571
+static __sum16 ip_mc_validate_checksum(struct sk_buff *skb)
15581572 {
15591573 return skb_checksum_simple_validate(skb);
15601574 }
15611575
1562
-static int __ip_mc_check_igmp(struct sk_buff *skb, struct sk_buff **skb_trimmed)
1563
-
1576
+static int ip_mc_check_igmp_csum(struct sk_buff *skb)
15641577 {
1565
- struct sk_buff *skb_chk;
1566
- unsigned int transport_len;
15671578 unsigned int len = skb_transport_offset(skb) + sizeof(struct igmphdr);
1568
- int ret = -EINVAL;
1579
+ unsigned int transport_len = ip_transport_len(skb);
1580
+ struct sk_buff *skb_chk;
15691581
1570
- transport_len = ntohs(ip_hdr(skb)->tot_len) - ip_hdrlen(skb);
1582
+ if (!ip_mc_may_pull(skb, len))
1583
+ return -EINVAL;
15711584
15721585 skb_chk = skb_checksum_trimmed(skb, transport_len,
15731586 ip_mc_validate_checksum);
15741587 if (!skb_chk)
1575
- goto err;
1588
+ return -EINVAL;
15761589
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)
1590
+ if (skb_chk != skb)
15881591 kfree_skb(skb_chk);
15891592
1590
- ret = 0;
1591
-
1592
-err:
1593
- if (ret && skb_chk && skb_chk != skb)
1594
- kfree_skb(skb_chk);
1595
-
1596
- return ret;
1593
+ return 0;
15971594 }
15981595
15991596 /**
16001597 * ip_mc_check_igmp - checks whether this is a sane IGMP packet
16011598 * @skb: the skb to validate
1602
- * @skb_trimmed: to store an skb pointer trimmed to IPv4 packet tail (optional)
16031599 *
16041600 * Checks whether an IPv4 packet is a valid IGMP packet. If so sets
16051601 * skb transport header accordingly and returns zero.
....@@ -1609,18 +1605,10 @@
16091605 * -ENOMSG: IP header validation succeeded but it is not an IGMP packet.
16101606 * -ENOMEM: A memory allocation failure happened.
16111607 *
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
- *
16201608 * Caller needs to set the skb network header and free any returned skb if it
16211609 * differs from the provided skb.
16221610 */
1623
-int ip_mc_check_igmp(struct sk_buff *skb, struct sk_buff **skb_trimmed)
1611
+int ip_mc_check_igmp(struct sk_buff *skb)
16241612 {
16251613 int ret = ip_mc_check_iphdr(skb);
16261614
....@@ -1630,7 +1618,11 @@
16301618 if (ip_hdr(skb)->protocol != IPPROTO_IGMP)
16311619 return -ENOMSG;
16321620
1633
- return __ip_mc_check_igmp(skb, skb_trimmed);
1621
+ ret = ip_mc_check_igmp_csum(skb);
1622
+ if (ret < 0)
1623
+ return ret;
1624
+
1625
+ return ip_mc_check_igmp_msg(skb);
16341626 }
16351627 EXPORT_SYMBOL(ip_mc_check_igmp);
16361628
....@@ -1650,7 +1642,7 @@
16501642 if (im->multiaddr == IGMP_ALL_HOSTS)
16511643 continue;
16521644 if (ipv4_is_local_multicast(im->multiaddr) &&
1653
- !net->ipv4.sysctl_igmp_llm_reports)
1645
+ !READ_ONCE(net->ipv4.sysctl_igmp_llm_reports))
16541646 continue;
16551647
16561648 /* a failover is happening and switches
....@@ -1671,7 +1663,7 @@
16711663 * A socket has left a multicast group on device dev
16721664 */
16731665
1674
-void ip_mc_dec_group(struct in_device *in_dev, __be32 addr)
1666
+void __ip_mc_dec_group(struct in_device *in_dev, __be32 addr, gfp_t gfp)
16751667 {
16761668 struct ip_mc_list *i;
16771669 struct ip_mc_list __rcu **ip;
....@@ -1686,7 +1678,7 @@
16861678 ip_mc_hash_remove(in_dev, i);
16871679 *ip = i->next_rcu;
16881680 in_dev->mc_count--;
1689
- igmp_group_dropped(i);
1681
+ __igmp_group_dropped(i, gfp);
16901682 ip_mc_clear_src(i);
16911683
16921684 if (!in_dev->dead)
....@@ -1699,7 +1691,7 @@
16991691 }
17001692 }
17011693 }
1702
-EXPORT_SYMBOL(ip_mc_dec_group);
1694
+EXPORT_SYMBOL(__ip_mc_dec_group);
17031695
17041696 /* Device changing type */
17051697
....@@ -1757,7 +1749,7 @@
17571749
17581750 in_dev->mr_qi = IGMP_QUERY_INTERVAL;
17591751 in_dev->mr_qri = IGMP_QUERY_RESPONSE_INTERVAL;
1760
- in_dev->mr_qrv = net->ipv4.sysctl_igmp_qrv;
1752
+ in_dev->mr_qrv = READ_ONCE(net->ipv4.sysctl_igmp_qrv);
17611753 }
17621754 #else
17631755 static void ip_mc_reset(struct in_device *in_dev)
....@@ -1891,7 +1883,7 @@
18911883 #ifdef CONFIG_IP_MULTICAST
18921884 if (psf->sf_oldin &&
18931885 !IGMP_V1_SEEN(in_dev) && !IGMP_V2_SEEN(in_dev)) {
1894
- psf->sf_crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv;
1886
+ psf->sf_crcount = in_dev->mr_qrv ?: READ_ONCE(net->ipv4.sysctl_igmp_qrv);
18951887 psf->sf_next = pmc->tomb;
18961888 pmc->tomb = psf;
18971889 rv = 1;
....@@ -1955,7 +1947,7 @@
19551947 /* filter mode change */
19561948 pmc->sfmode = MCAST_INCLUDE;
19571949 #ifdef CONFIG_IP_MULTICAST
1958
- pmc->crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv;
1950
+ pmc->crcount = in_dev->mr_qrv ?: READ_ONCE(net->ipv4.sysctl_igmp_qrv);
19591951 in_dev->mr_ifc_count = pmc->crcount;
19601952 for (psf = pmc->sources; psf; psf = psf->sf_next)
19611953 psf->sf_crcount = 0;
....@@ -2134,7 +2126,7 @@
21342126 #ifdef CONFIG_IP_MULTICAST
21352127 /* else no filters; keep old mode for reports */
21362128
2137
- pmc->crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv;
2129
+ pmc->crcount = in_dev->mr_qrv ?: READ_ONCE(net->ipv4.sysctl_igmp_qrv);
21382130 in_dev->mr_ifc_count = pmc->crcount;
21392131 for (psf = pmc->sources; psf; psf = psf->sf_next)
21402132 psf->sf_crcount = 0;
....@@ -2200,7 +2192,7 @@
22002192 count++;
22012193 }
22022194 err = -ENOBUFS;
2203
- if (count >= net->ipv4.sysctl_igmp_max_memberships)
2195
+ if (count >= READ_ONCE(net->ipv4.sysctl_igmp_max_memberships))
22042196 goto done;
22052197 iml = sock_kmalloc(sk, sizeof(*iml), GFP_KERNEL);
22062198 if (!iml)
....@@ -2211,7 +2203,7 @@
22112203 iml->sflist = NULL;
22122204 iml->sfmode = mode;
22132205 rcu_assign_pointer(inet->mc_list, iml);
2214
- __ip_mc_inc_group(in_dev, addr, mode);
2206
+ ____ip_mc_inc_group(in_dev, addr, mode, GFP_KERNEL);
22152207 err = 0;
22162208 done:
22172209 return err;
....@@ -2387,7 +2379,7 @@
23872379 }
23882380 /* else, add a new source to the filter */
23892381
2390
- if (psl && psl->sl_count >= net->ipv4.sysctl_igmp_max_msf) {
2382
+ if (psl && psl->sl_count >= READ_ONCE(net->ipv4.sysctl_igmp_max_msf)) {
23912383 err = -ENOBUFS;
23922384 goto done;
23932385 }
....@@ -2409,9 +2401,10 @@
24092401 newpsl->sl_addr[i] = psl->sl_addr[i];
24102402 /* decrease mem now to avoid the memleak warning */
24112403 atomic_sub(IP_SFLSIZE(psl->sl_max), &sk->sk_omem_alloc);
2412
- kfree_rcu(psl, rcu);
24132404 }
24142405 rcu_assign_pointer(pmc->sflist, newpsl);
2406
+ if (psl)
2407
+ kfree_rcu(psl, rcu);
24152408 psl = newpsl;
24162409 }
24172410 rv = 1; /* > 0 for insert logic below if sl_count is 0 */
....@@ -2509,11 +2502,13 @@
25092502 psl->sl_count, psl->sl_addr, 0);
25102503 /* decrease mem now to avoid the memleak warning */
25112504 atomic_sub(IP_SFLSIZE(psl->sl_max), &sk->sk_omem_alloc);
2512
- kfree_rcu(psl, rcu);
2513
- } else
2505
+ } else {
25142506 (void) ip_mc_del_src(in_dev, &msf->imsf_multiaddr, pmc->sfmode,
25152507 0, NULL, 0);
2508
+ }
25162509 rcu_assign_pointer(pmc->sflist, newpsl);
2510
+ if (psl)
2511
+ kfree_rcu(psl, rcu);
25172512 pmc->sfmode = msf->imsf_fmode;
25182513 err = 0;
25192514 done:
....@@ -2581,9 +2576,9 @@
25812576 }
25822577
25832578 int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf,
2584
- struct group_filter __user *optval, int __user *optlen)
2579
+ struct sockaddr_storage __user *p)
25852580 {
2586
- int err, i, count, copycount;
2581
+ int i, count, copycount;
25872582 struct sockaddr_in *psin;
25882583 __be32 addr;
25892584 struct ip_mc_socklist *pmc;
....@@ -2599,37 +2594,29 @@
25992594 if (!ipv4_is_multicast(addr))
26002595 return -EINVAL;
26012596
2602
- err = -EADDRNOTAVAIL;
2603
-
26042597 for_each_pmc_rtnl(inet, pmc) {
26052598 if (pmc->multi.imr_multiaddr.s_addr == addr &&
26062599 pmc->multi.imr_ifindex == gsf->gf_interface)
26072600 break;
26082601 }
26092602 if (!pmc) /* must have a prior join */
2610
- goto done;
2603
+ return -EADDRNOTAVAIL;
26112604 gsf->gf_fmode = pmc->sfmode;
26122605 psl = rtnl_dereference(pmc->sflist);
26132606 count = psl ? psl->sl_count : 0;
26142607 copycount = count < gsf->gf_numsrc ? count : gsf->gf_numsrc;
26152608 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++) {
2609
+ for (i = 0; i < copycount; i++, p++) {
26212610 struct sockaddr_storage ss;
26222611
26232612 psin = (struct sockaddr_in *)&ss;
26242613 memset(&ss, 0, sizeof(ss));
26252614 psin->sin_family = AF_INET;
26262615 psin->sin_addr.s_addr = psl->sl_addr[i];
2627
- if (copy_to_user(&optval->gf_slist[i], &ss, sizeof(ss)))
2616
+ if (copy_to_user(p, &ss, sizeof(ss)))
26282617 return -EFAULT;
26292618 }
26302619 return 0;
2631
-done:
2632
- return err;
26332620 }
26342621
26352622 /*