br_multicast.c (0436862e417e8c68e7b85ebf66ffca9d54c43e9a) br_multicast.c (e6231bca6a27dcc718e258b71bad42977ca3344e)
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Bridge multicast support.
4 *
5 * Copyright (c) 2010 Herbert Xu <herbert@gondor.apana.org.au>
6 */
7
8#include <linux/err.h>

--- 1215 unchanged lines hidden (view full) ---

1224 del_timer(&port->multicast_router_timer);
1225 del_timer(&port->ip4_own_query.timer);
1226#if IS_ENABLED(CONFIG_IPV6)
1227 del_timer(&port->ip6_own_query.timer);
1228#endif
1229 spin_unlock(&br->multicast_lock);
1230}
1231
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Bridge multicast support.
4 *
5 * Copyright (c) 2010 Herbert Xu <herbert@gondor.apana.org.au>
6 */
7
8#include <linux/err.h>

--- 1215 unchanged lines hidden (view full) ---

1224 del_timer(&port->multicast_router_timer);
1225 del_timer(&port->ip4_own_query.timer);
1226#if IS_ENABLED(CONFIG_IPV6)
1227 del_timer(&port->ip6_own_query.timer);
1228#endif
1229 spin_unlock(&br->multicast_lock);
1230}
1231
1232static int __grp_src_delete_marked(struct net_bridge_port_group *pg)
1233{
1234 struct net_bridge_group_src *ent;
1235 struct hlist_node *tmp;
1236 int deleted = 0;
1237
1238 hlist_for_each_entry_safe(ent, tmp, &pg->src_list, node)
1239 if (ent->flags & BR_SGRP_F_DELETE) {
1240 br_multicast_del_group_src(ent);
1241 deleted++;
1242 }
1243
1244 return deleted;
1245}
1246
1232/* State Msg type New state Actions
1233 * INCLUDE (A) IS_IN (B) INCLUDE (A+B) (B)=GMI
1234 * INCLUDE (A) ALLOW (B) INCLUDE (A+B) (B)=GMI
1235 * EXCLUDE (X,Y) ALLOW (A) EXCLUDE (X+A,Y-A) (A)=GMI
1236 */
1237static bool br_multicast_isinc_allow(struct net_bridge_port_group *pg,
1238 void *srcs, u32 nsrcs, size_t src_size)
1239{

--- 18 unchanged lines hidden (view full) ---

1258 if (ent)
1259 mod_timer(&ent->timer, now + br_multicast_gmi(br));
1260 srcs += src_size;
1261 }
1262
1263 return changed;
1264}
1265
1247/* State Msg type New state Actions
1248 * INCLUDE (A) IS_IN (B) INCLUDE (A+B) (B)=GMI
1249 * INCLUDE (A) ALLOW (B) INCLUDE (A+B) (B)=GMI
1250 * EXCLUDE (X,Y) ALLOW (A) EXCLUDE (X+A,Y-A) (A)=GMI
1251 */
1252static bool br_multicast_isinc_allow(struct net_bridge_port_group *pg,
1253 void *srcs, u32 nsrcs, size_t src_size)
1254{

--- 18 unchanged lines hidden (view full) ---

1273 if (ent)
1274 mod_timer(&ent->timer, now + br_multicast_gmi(br));
1275 srcs += src_size;
1276 }
1277
1278 return changed;
1279}
1280
1281/* State Msg type New state Actions
1282 * INCLUDE (A) IS_EX (B) EXCLUDE (A*B,B-A) (B-A)=0
1283 * Delete (A-B)
1284 * Group Timer=GMI
1285 */
1286static void __grp_src_isexc_incl(struct net_bridge_port_group *pg,
1287 void *srcs, u32 nsrcs, size_t src_size)
1288{
1289 struct net_bridge_group_src *ent;
1290 struct br_ip src_ip;
1291 u32 src_idx;
1292
1293 hlist_for_each_entry(ent, &pg->src_list, node)
1294 ent->flags |= BR_SGRP_F_DELETE;
1295
1296 memset(&src_ip, 0, sizeof(src_ip));
1297 src_ip.proto = pg->addr.proto;
1298 for (src_idx = 0; src_idx < nsrcs; src_idx++) {
1299 memcpy(&src_ip.u, srcs, src_size);
1300 ent = br_multicast_find_group_src(pg, &src_ip);
1301 if (ent)
1302 ent->flags &= ~BR_SGRP_F_DELETE;
1303 else
1304 br_multicast_new_group_src(pg, &src_ip);
1305 srcs += src_size;
1306 }
1307
1308 __grp_src_delete_marked(pg);
1309}
1310
1311/* State Msg type New state Actions
1312 * EXCLUDE (X,Y) IS_EX (A) EXCLUDE (A-Y,Y*A) (A-X-Y)=GMI
1313 * Delete (X-A)
1314 * Delete (Y-A)
1315 * Group Timer=GMI
1316 */
1317static bool __grp_src_isexc_excl(struct net_bridge_port_group *pg,
1318 void *srcs, u32 nsrcs, size_t src_size)
1319{
1320 struct net_bridge *br = pg->port->br;
1321 struct net_bridge_group_src *ent;
1322 unsigned long now = jiffies;
1323 bool changed = false;
1324 struct br_ip src_ip;
1325 u32 src_idx;
1326
1327 hlist_for_each_entry(ent, &pg->src_list, node)
1328 ent->flags |= BR_SGRP_F_DELETE;
1329
1330 memset(&src_ip, 0, sizeof(src_ip));
1331 src_ip.proto = pg->addr.proto;
1332 for (src_idx = 0; src_idx < nsrcs; src_idx++) {
1333 memcpy(&src_ip.u, srcs, src_size);
1334 ent = br_multicast_find_group_src(pg, &src_ip);
1335 if (ent) {
1336 ent->flags &= ~BR_SGRP_F_DELETE;
1337 } else {
1338 ent = br_multicast_new_group_src(pg, &src_ip);
1339 if (ent) {
1340 mod_timer(&ent->timer,
1341 now + br_multicast_gmi(br));
1342 changed = true;
1343 }
1344 }
1345 srcs += src_size;
1346 }
1347
1348 if (__grp_src_delete_marked(pg))
1349 changed = true;
1350
1351 return changed;
1352}
1353
1354static bool br_multicast_isexc(struct net_bridge_port_group *pg,
1355 void *srcs, u32 nsrcs, size_t src_size)
1356{
1357 struct net_bridge *br = pg->port->br;
1358 bool changed = false;
1359
1360 switch (pg->filter_mode) {
1361 case MCAST_INCLUDE:
1362 __grp_src_isexc_incl(pg, srcs, nsrcs, src_size);
1363 changed = true;
1364 break;
1365 case MCAST_EXCLUDE:
1366 changed = __grp_src_isexc_excl(pg, srcs, nsrcs, src_size);
1367 break;
1368 }
1369
1370 pg->filter_mode = MCAST_EXCLUDE;
1371 mod_timer(&pg->timer, jiffies + br_multicast_gmi(br));
1372
1373 return changed;
1374}
1375
1266static struct net_bridge_port_group *
1267br_multicast_find_port(struct net_bridge_mdb_entry *mp,
1268 struct net_bridge_port *p,
1269 const unsigned char *src)
1270{
1271 struct net_bridge_port_group *pg;
1272 struct net_bridge *br = mp->br;
1273

--- 81 unchanged lines hidden (view full) ---

1355 goto unlock_continue;
1356 /* reload grec */
1357 grec = (void *)(skb->data + len - sizeof(*grec) - (nsrcs * 4));
1358 switch (type) {
1359 case IGMPV3_ALLOW_NEW_SOURCES:
1360 changed = br_multicast_isinc_allow(pg, grec->grec_src,
1361 nsrcs, sizeof(__be32));
1362 break;
1376static struct net_bridge_port_group *
1377br_multicast_find_port(struct net_bridge_mdb_entry *mp,
1378 struct net_bridge_port *p,
1379 const unsigned char *src)
1380{
1381 struct net_bridge_port_group *pg;
1382 struct net_bridge *br = mp->br;
1383

--- 81 unchanged lines hidden (view full) ---

1465 goto unlock_continue;
1466 /* reload grec */
1467 grec = (void *)(skb->data + len - sizeof(*grec) - (nsrcs * 4));
1468 switch (type) {
1469 case IGMPV3_ALLOW_NEW_SOURCES:
1470 changed = br_multicast_isinc_allow(pg, grec->grec_src,
1471 nsrcs, sizeof(__be32));
1472 break;
1473 case IGMPV3_MODE_IS_INCLUDE:
1474 changed = br_multicast_isinc_allow(pg, grec->grec_src, nsrcs,
1475 sizeof(__be32));
1476 break;
1477 case IGMPV3_MODE_IS_EXCLUDE:
1478 changed = br_multicast_isexc(pg, grec->grec_src, nsrcs,
1479 sizeof(__be32));
1480 break;
1363 }
1364 if (changed)
1365 br_mdb_notify(br->dev, mdst, pg, RTM_NEWMDB);
1366unlock_continue:
1367 spin_unlock_bh(&br->multicast_lock);
1368 }
1369
1370 return err;

--- 90 unchanged lines hidden (view full) ---

1461 if (!pg || (pg->flags & MDB_PG_FLAGS_PERMANENT))
1462 goto unlock_continue;
1463 switch (grec->grec_type) {
1464 case MLD2_ALLOW_NEW_SOURCES:
1465 changed = br_multicast_isinc_allow(pg, grec->grec_src,
1466 nsrcs,
1467 sizeof(struct in6_addr));
1468 break;
1481 }
1482 if (changed)
1483 br_mdb_notify(br->dev, mdst, pg, RTM_NEWMDB);
1484unlock_continue:
1485 spin_unlock_bh(&br->multicast_lock);
1486 }
1487
1488 return err;

--- 90 unchanged lines hidden (view full) ---

1579 if (!pg || (pg->flags & MDB_PG_FLAGS_PERMANENT))
1580 goto unlock_continue;
1581 switch (grec->grec_type) {
1582 case MLD2_ALLOW_NEW_SOURCES:
1583 changed = br_multicast_isinc_allow(pg, grec->grec_src,
1584 nsrcs,
1585 sizeof(struct in6_addr));
1586 break;
1587 case MLD2_MODE_IS_INCLUDE:
1588 changed = br_multicast_isinc_allow(pg, grec->grec_src, nsrcs,
1589 sizeof(struct in6_addr));
1590 break;
1591 case MLD2_MODE_IS_EXCLUDE:
1592 changed = br_multicast_isexc(pg, grec->grec_src, nsrcs,
1593 sizeof(struct in6_addr));
1594 break;
1469 }
1470 if (changed)
1471 br_mdb_notify(br->dev, mdst, pg, RTM_NEWMDB);
1472unlock_continue:
1473 spin_unlock_bh(&br->multicast_lock);
1474 }
1475
1476 return err;

--- 1447 unchanged lines hidden ---
1595 }
1596 if (changed)
1597 br_mdb_notify(br->dev, mdst, pg, RTM_NEWMDB);
1598unlock_continue:
1599 spin_unlock_bh(&br->multicast_lock);
1600 }
1601
1602 return err;

--- 1447 unchanged lines hidden ---