| @@ -72,7 +72,8 @@ __br_multicast_add_group(struct net_bridge *br, · 71 unmodified lines |
| 72 | 72 | struct br_ip *group, |
| 73 | 73 | const unsigned char *src, |
| 74 | 74 | u8 filter_mode, |
| 75 | | − bool igmpv2_mldv1); |
| 75 | + bool igmpv2_mldv1, |
| 76 | + bool blocked); |
| 76 | 77 | static void br_multicast_find_del_pg(struct net_bridge *br, |
| 77 | 78 | struct net_bridge_port_group *pg); |
| 78 | 79 | |
| @@ -211,7 +212,7 @@ static void __fwd_add_star_excl(struct net_bridge_port_group *pg, · 132 unmodified lines |
| 211 | 212 | return; |
| 212 | 213 | |
| 213 | 214 | src_pg = __br_multicast_add_group(br, pg->key.port, sg_ip, pg->eth_addr, |
| 214 | | − MCAST_INCLUDE, false); |
| 215 | + MCAST_INCLUDE, false, false); |
| 215 | 216 | if (IS_ERR_OR_NULL(src_pg) || |
| 216 | 217 | src_pg->rt_protocol != RTPROT_KERNEL) |
| 217 | 218 | return; |
| @@ -343,7 +344,7 @@ void br_multicast_sg_add_exclude_ports(struct net_bridge_mdb_entry *star_mp, · 125 unmodified lines |
| 343 | 344 | src_pg = __br_multicast_add_group(br, pg->key.port, |
| 344 | 345 | &sg->key.addr, |
| 345 | 346 | sg->eth_addr, |
| 346 | | − MCAST_INCLUDE, false); |
| 347 | + MCAST_INCLUDE, false, false); |
| 347 | 348 | if (IS_ERR_OR_NULL(src_pg) || |
| 348 | 349 | src_pg->rt_protocol != RTPROT_KERNEL) |
| 349 | 350 | continue; |
| @@ -364,7 +365,8 @@ static void br_multicast_fwd_src_add(struct net_bridge_group_src *src) · 14 unmodified lines |
| 364 | 365 | sg_ip = src->pg->key.addr; |
| 365 | 366 | sg_ip.src = src->addr.src; |
| 366 | 367 | sg = __br_multicast_add_group(src->br, src->pg->key.port, &sg_ip, |
| 367 | | − src->pg->eth_addr, MCAST_INCLUDE, false); |
| 368 | + src->pg->eth_addr, MCAST_INCLUDE, false, |
| 369 | + !timer_pending(&src->timer)); |
| 368 | 370 | if (IS_ERR_OR_NULL(sg)) |
| 369 | 371 | return; |
| 370 | 372 | src->flags |= BR_SGRP_F_INSTALLED; |
| @@ -415,9 +417,38 @@ static void br_multicast_fwd_src_remove(struct net_bridge_group_src *src) · 44 unmodified lines |
| 415 | 417 | src->flags &= ~BR_SGRP_F_INSTALLED; |
| 416 | 418 | } |
| 417 | 419 | |
| 420 | +/* install S,G and based on src's timer enable or disable forwarding */ |
| 418 | 421 | static void br_multicast_fwd_src_handle(struct net_bridge_group_src *src) |
| 419 | 422 | { |
| 423 | + struct net_bridge_port_group_sg_key sg_key; |
| 424 | + struct net_bridge_port_group *sg; |
| 425 | + u8 old_flags; |
| 426 | + |
| 420 | 427 | br_multicast_fwd_src_add(src); |
| 428 | + |
| 429 | + memset(&sg_key, 0, sizeof(sg_key)); |
| 430 | + sg_key.addr = src->pg->key.addr; |
| 431 | + sg_key.addr.src = src->addr.src; |
| 432 | + sg_key.port = src->pg->key.port; |
| 433 | + |
| 434 | + sg = br_sg_port_find(src->br, &sg_key); |
| 435 | + if (!sg || (sg->flags & MDB_PG_FLAGS_PERMANENT)) |
| 436 | + return; |
| 437 | + |
| 438 | + old_flags = sg->flags; |
| 439 | + if (timer_pending(&src->timer)) |
| 440 | + sg->flags &= ~MDB_PG_FLAGS_BLOCKED; |
| 441 | + else |
| 442 | + sg->flags |= MDB_PG_FLAGS_BLOCKED; |
| 443 | + |
| 444 | + if (old_flags != sg->flags) { |
| 445 | + struct net_bridge_mdb_entry *sg_mp; |
| 446 | + |
| 447 | + sg_mp = br_mdb_ip_get(src->br, &sg_key.addr); |
| 448 | + if (!sg_mp) |
| 449 | + return; |
| 450 | + br_mdb_notify(src->br->dev, sg_mp, sg, RTM_NEWMDB); |
| 451 | + } |
| 421 | 452 | } |
| 422 | 453 | |
| 423 | 454 | static void br_multicast_destroy_mdb_entry(struct net_bridge_mcast_gc *gc) |
| @@ -995,7 +1026,10 @@ static void br_multicast_group_src_expired(struct timer_list *t) · 571 unmodified lines |
| 995 | 1026 | if (!hlist_empty(&pg->src_list)) |
| 996 | 1027 | goto out; |
| 997 | 1028 | br_multicast_find_del_pg(br, pg); |
| 1029 | + } else { |
| 1030 | + br_multicast_fwd_src_handle(src); |
| 998 | 1031 | } |
| 1032 | + |
| 999 | 1033 | out: |
| 1000 | 1034 | spin_unlock(&br->multicast_lock); |
| 1001 | 1035 | } |
| @@ -1131,7 +1165,8 @@ __br_multicast_add_group(struct net_bridge *br, · 129 unmodified lines |
| 1131 | 1165 | struct br_ip *group, |
| 1132 | 1166 | const unsigned char *src, |
| 1133 | 1167 | u8 filter_mode, |
| 1134 | | − bool igmpv2_mldv1) |
| 1168 | + bool igmpv2_mldv1, |
| 1169 | + bool blocked) |
| 1135 | 1170 | { |
| 1136 | 1171 | struct net_bridge_port_group __rcu **pp; |
| 1137 | 1172 | struct net_bridge_port_group *p = NULL; |
| @@ -1167,6 +1202,8 @@ __br_multicast_add_group(struct net_bridge *br, · 29 unmodified lines |
| 1167 | 1202 | goto out; |
| 1168 | 1203 | } |
| 1169 | 1204 | rcu_assign_pointer(*pp, p); |
| 1205 | + if (blocked) |
| 1206 | + p->flags |= MDB_PG_FLAGS_BLOCKED; |
| 1170 | 1207 | br_mdb_notify(br->dev, mp, p, RTM_NEWMDB); |
| 1171 | 1208 | |
| 1172 | 1209 | found: |
| @@ -1189,7 +1226,7 @@ static int br_multicast_add_group(struct net_bridge *br, · 16 unmodified lines |
| 1189 | 1226 | |
| 1190 | 1227 | spin_lock(&br->multicast_lock); |
| 1191 | 1228 | pg = __br_multicast_add_group(br, port, group, src, filter_mode, |
| 1192 | | − igmpv2_mldv1); |
| 1229 | + igmpv2_mldv1, false); |
| 1193 | 1230 | /* NULL is considered valid for host joined groups */ |
| 1194 | 1231 | err = IS_ERR(pg) ? PTR_ERR(pg) : 0; |
| 1195 | 1232 | spin_unlock(&br->multicast_lock); |