diff options
Diffstat (limited to 'net/bridge/br_multicast.c')
| -rw-r--r-- | net/bridge/br_multicast.c | 33 |
1 files changed, 30 insertions, 3 deletions
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index ef66365b7354..93067ecdb9a2 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c | |||
| @@ -1127,9 +1127,10 @@ static void br_multicast_query_received(struct net_bridge *br, | |||
| 1127 | struct net_bridge_port *port, | 1127 | struct net_bridge_port *port, |
| 1128 | struct bridge_mcast_querier *querier, | 1128 | struct bridge_mcast_querier *querier, |
| 1129 | int saddr, | 1129 | int saddr, |
| 1130 | bool is_general_query, | ||
| 1130 | unsigned long max_delay) | 1131 | unsigned long max_delay) |
| 1131 | { | 1132 | { |
| 1132 | if (saddr) | 1133 | if (saddr && is_general_query) |
| 1133 | br_multicast_update_querier_timer(br, querier, max_delay); | 1134 | br_multicast_update_querier_timer(br, querier, max_delay); |
| 1134 | else if (timer_pending(&querier->timer)) | 1135 | else if (timer_pending(&querier->timer)) |
| 1135 | return; | 1136 | return; |
| @@ -1181,8 +1182,16 @@ static int br_ip4_multicast_query(struct net_bridge *br, | |||
| 1181 | IGMPV3_MRC(ih3->code) * (HZ / IGMP_TIMER_SCALE) : 1; | 1182 | IGMPV3_MRC(ih3->code) * (HZ / IGMP_TIMER_SCALE) : 1; |
| 1182 | } | 1183 | } |
| 1183 | 1184 | ||
| 1185 | /* RFC2236+RFC3376 (IGMPv2+IGMPv3) require the multicast link layer | ||
| 1186 | * all-systems destination addresses (224.0.0.1) for general queries | ||
| 1187 | */ | ||
| 1188 | if (!group && iph->daddr != htonl(INADDR_ALLHOSTS_GROUP)) { | ||
| 1189 | err = -EINVAL; | ||
| 1190 | goto out; | ||
| 1191 | } | ||
| 1192 | |||
| 1184 | br_multicast_query_received(br, port, &br->ip4_querier, !!iph->saddr, | 1193 | br_multicast_query_received(br, port, &br->ip4_querier, !!iph->saddr, |
| 1185 | max_delay); | 1194 | !group, max_delay); |
| 1186 | 1195 | ||
| 1187 | if (!group) | 1196 | if (!group) |
| 1188 | goto out; | 1197 | goto out; |
| @@ -1228,6 +1237,7 @@ static int br_ip6_multicast_query(struct net_bridge *br, | |||
| 1228 | unsigned long max_delay; | 1237 | unsigned long max_delay; |
| 1229 | unsigned long now = jiffies; | 1238 | unsigned long now = jiffies; |
| 1230 | const struct in6_addr *group = NULL; | 1239 | const struct in6_addr *group = NULL; |
| 1240 | bool is_general_query; | ||
| 1231 | int err = 0; | 1241 | int err = 0; |
| 1232 | 1242 | ||
| 1233 | spin_lock(&br->multicast_lock); | 1243 | spin_lock(&br->multicast_lock); |
| @@ -1235,6 +1245,12 @@ static int br_ip6_multicast_query(struct net_bridge *br, | |||
| 1235 | (port && port->state == BR_STATE_DISABLED)) | 1245 | (port && port->state == BR_STATE_DISABLED)) |
| 1236 | goto out; | 1246 | goto out; |
| 1237 | 1247 | ||
| 1248 | /* RFC2710+RFC3810 (MLDv1+MLDv2) require link-local source addresses */ | ||
| 1249 | if (!(ipv6_addr_type(&ip6h->saddr) & IPV6_ADDR_LINKLOCAL)) { | ||
| 1250 | err = -EINVAL; | ||
| 1251 | goto out; | ||
| 1252 | } | ||
| 1253 | |||
| 1238 | if (skb->len == sizeof(*mld)) { | 1254 | if (skb->len == sizeof(*mld)) { |
| 1239 | if (!pskb_may_pull(skb, sizeof(*mld))) { | 1255 | if (!pskb_may_pull(skb, sizeof(*mld))) { |
| 1240 | err = -EINVAL; | 1256 | err = -EINVAL; |
| @@ -1256,8 +1272,19 @@ static int br_ip6_multicast_query(struct net_bridge *br, | |||
| 1256 | max_delay = max(msecs_to_jiffies(mldv2_mrc(mld2q)), 1UL); | 1272 | max_delay = max(msecs_to_jiffies(mldv2_mrc(mld2q)), 1UL); |
| 1257 | } | 1273 | } |
| 1258 | 1274 | ||
| 1275 | is_general_query = group && ipv6_addr_any(group); | ||
| 1276 | |||
| 1277 | /* RFC2710+RFC3810 (MLDv1+MLDv2) require the multicast link layer | ||
| 1278 | * all-nodes destination address (ff02::1) for general queries | ||
| 1279 | */ | ||
| 1280 | if (is_general_query && !ipv6_addr_is_ll_all_nodes(&ip6h->daddr)) { | ||
| 1281 | err = -EINVAL; | ||
| 1282 | goto out; | ||
| 1283 | } | ||
| 1284 | |||
| 1259 | br_multicast_query_received(br, port, &br->ip6_querier, | 1285 | br_multicast_query_received(br, port, &br->ip6_querier, |
| 1260 | !ipv6_addr_any(&ip6h->saddr), max_delay); | 1286 | !ipv6_addr_any(&ip6h->saddr), |
| 1287 | is_general_query, max_delay); | ||
| 1261 | 1288 | ||
| 1262 | if (!group) | 1289 | if (!group) |
| 1263 | goto out; | 1290 | goto out; |
