1 /* Copyright (C) 2014 B.A.T.M.A.N. contributors: 2 * 3 * Linus Lüssing 4 * 5 * This program is free software; you can redistribute it and/or 6 * modify it under the terms of version 2 of the GNU General Public 7 * License as published by the Free Software Foundation. 8 * 9 * This program is distributed in the hope that it will be useful, but 10 * WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 #include "main.h" 19 #include "multicast.h" 20 #include "originator.h" 21 #include "hard-interface.h" 22 #include "translation-table.h" 23 24 /** 25 * batadv_mcast_mla_softif_get - get softif multicast listeners 26 * @dev: the device to collect multicast addresses from 27 * @mcast_list: a list to put found addresses into 28 * 29 * Collect multicast addresses of the local multicast listeners 30 * on the given soft interface, dev, in the given mcast_list. 31 * 32 * Returns -ENOMEM on memory allocation error or the number of 33 * items added to the mcast_list otherwise. 34 */ 35 static int batadv_mcast_mla_softif_get(struct net_device *dev, 36 struct hlist_head *mcast_list) 37 { 38 struct netdev_hw_addr *mc_list_entry; 39 struct batadv_hw_addr *new; 40 int ret = 0; 41 42 netif_addr_lock_bh(dev); 43 netdev_for_each_mc_addr(mc_list_entry, dev) { 44 new = kmalloc(sizeof(*new), GFP_ATOMIC); 45 if (!new) { 46 ret = -ENOMEM; 47 break; 48 } 49 50 ether_addr_copy(new->addr, mc_list_entry->addr); 51 hlist_add_head(&new->list, mcast_list); 52 ret++; 53 } 54 netif_addr_unlock_bh(dev); 55 56 return ret; 57 } 58 59 /** 60 * batadv_mcast_mla_is_duplicate - check whether an address is in a list 61 * @mcast_addr: the multicast address to check 62 * @mcast_list: the list with multicast addresses to search in 63 * 64 * Returns true if the given address is already in the given list. 65 * Otherwise returns false. 66 */ 67 static bool batadv_mcast_mla_is_duplicate(uint8_t *mcast_addr, 68 struct hlist_head *mcast_list) 69 { 70 struct batadv_hw_addr *mcast_entry; 71 72 hlist_for_each_entry(mcast_entry, mcast_list, list) 73 if (batadv_compare_eth(mcast_entry->addr, mcast_addr)) 74 return true; 75 76 return false; 77 } 78 79 /** 80 * batadv_mcast_mla_list_free - free a list of multicast addresses 81 * @mcast_list: the list to free 82 * 83 * Removes and frees all items in the given mcast_list. 84 */ 85 static void batadv_mcast_mla_list_free(struct hlist_head *mcast_list) 86 { 87 struct batadv_hw_addr *mcast_entry; 88 struct hlist_node *tmp; 89 90 hlist_for_each_entry_safe(mcast_entry, tmp, mcast_list, list) { 91 hlist_del(&mcast_entry->list); 92 kfree(mcast_entry); 93 } 94 } 95 96 /** 97 * batadv_mcast_mla_tt_retract - clean up multicast listener announcements 98 * @bat_priv: the bat priv with all the soft interface information 99 * @mcast_list: a list of addresses which should _not_ be removed 100 * 101 * Retracts the announcement of any multicast listener from the 102 * translation table except the ones listed in the given mcast_list. 103 * 104 * If mcast_list is NULL then all are retracted. 105 */ 106 static void batadv_mcast_mla_tt_retract(struct batadv_priv *bat_priv, 107 struct hlist_head *mcast_list) 108 { 109 struct batadv_hw_addr *mcast_entry; 110 struct hlist_node *tmp; 111 112 hlist_for_each_entry_safe(mcast_entry, tmp, &bat_priv->mcast.mla_list, 113 list) { 114 if (mcast_list && 115 batadv_mcast_mla_is_duplicate(mcast_entry->addr, 116 mcast_list)) 117 continue; 118 119 batadv_tt_local_remove(bat_priv, mcast_entry->addr, 120 BATADV_NO_FLAGS, 121 "mcast TT outdated", false); 122 123 hlist_del(&mcast_entry->list); 124 kfree(mcast_entry); 125 } 126 } 127 128 /** 129 * batadv_mcast_mla_tt_add - add multicast listener announcements 130 * @bat_priv: the bat priv with all the soft interface information 131 * @mcast_list: a list of addresses which are going to get added 132 * 133 * Adds multicast listener announcements from the given mcast_list to the 134 * translation table if they have not been added yet. 135 */ 136 static void batadv_mcast_mla_tt_add(struct batadv_priv *bat_priv, 137 struct hlist_head *mcast_list) 138 { 139 struct batadv_hw_addr *mcast_entry; 140 struct hlist_node *tmp; 141 142 if (!mcast_list) 143 return; 144 145 hlist_for_each_entry_safe(mcast_entry, tmp, mcast_list, list) { 146 if (batadv_mcast_mla_is_duplicate(mcast_entry->addr, 147 &bat_priv->mcast.mla_list)) 148 continue; 149 150 if (!batadv_tt_local_add(bat_priv->soft_iface, 151 mcast_entry->addr, BATADV_NO_FLAGS, 152 BATADV_NULL_IFINDEX, BATADV_NO_MARK)) 153 continue; 154 155 hlist_del(&mcast_entry->list); 156 hlist_add_head(&mcast_entry->list, &bat_priv->mcast.mla_list); 157 } 158 } 159 160 /** 161 * batadv_mcast_has_bridge - check whether the soft-iface is bridged 162 * @bat_priv: the bat priv with all the soft interface information 163 * 164 * Checks whether there is a bridge on top of our soft interface. Returns 165 * true if so, false otherwise. 166 */ 167 static bool batadv_mcast_has_bridge(struct batadv_priv *bat_priv) 168 { 169 struct net_device *upper = bat_priv->soft_iface; 170 171 rcu_read_lock(); 172 do { 173 upper = netdev_master_upper_dev_get_rcu(upper); 174 } while (upper && !(upper->priv_flags & IFF_EBRIDGE)); 175 rcu_read_unlock(); 176 177 return upper; 178 } 179 180 /** 181 * batadv_mcast_mla_tvlv_update - update multicast tvlv 182 * @bat_priv: the bat priv with all the soft interface information 183 * 184 * Updates the own multicast tvlv with our current multicast related settings, 185 * capabilities and inabilities. 186 * 187 * Returns true if the tvlv container is registered afterwards. Otherwise 188 * returns false. 189 */ 190 static bool batadv_mcast_mla_tvlv_update(struct batadv_priv *bat_priv) 191 { 192 struct batadv_tvlv_mcast_data mcast_data; 193 194 mcast_data.flags = BATADV_NO_FLAGS; 195 memset(mcast_data.reserved, 0, sizeof(mcast_data.reserved)); 196 197 /* Avoid attaching MLAs, if there is a bridge on top of our soft 198 * interface, we don't support that yet (TODO) 199 */ 200 if (batadv_mcast_has_bridge(bat_priv)) { 201 if (bat_priv->mcast.enabled) { 202 batadv_tvlv_container_unregister(bat_priv, 203 BATADV_TVLV_MCAST, 1); 204 bat_priv->mcast.enabled = false; 205 } 206 207 return false; 208 } 209 210 if (!bat_priv->mcast.enabled || 211 mcast_data.flags != bat_priv->mcast.flags) { 212 batadv_tvlv_container_register(bat_priv, BATADV_TVLV_MCAST, 1, 213 &mcast_data, sizeof(mcast_data)); 214 bat_priv->mcast.flags = mcast_data.flags; 215 bat_priv->mcast.enabled = true; 216 } 217 218 return true; 219 } 220 221 /** 222 * batadv_mcast_mla_update - update the own MLAs 223 * @bat_priv: the bat priv with all the soft interface information 224 * 225 * Updates the own multicast listener announcements in the translation 226 * table as well as the own, announced multicast tvlv container. 227 */ 228 void batadv_mcast_mla_update(struct batadv_priv *bat_priv) 229 { 230 struct net_device *soft_iface = bat_priv->soft_iface; 231 struct hlist_head mcast_list = HLIST_HEAD_INIT; 232 int ret; 233 234 if (!batadv_mcast_mla_tvlv_update(bat_priv)) 235 goto update; 236 237 ret = batadv_mcast_mla_softif_get(soft_iface, &mcast_list); 238 if (ret < 0) 239 goto out; 240 241 update: 242 batadv_mcast_mla_tt_retract(bat_priv, &mcast_list); 243 batadv_mcast_mla_tt_add(bat_priv, &mcast_list); 244 245 out: 246 batadv_mcast_mla_list_free(&mcast_list); 247 } 248 249 /** 250 * batadv_mcast_forw_mode_check_ipv4 - check for optimized forwarding potential 251 * @bat_priv: the bat priv with all the soft interface information 252 * @skb: the IPv4 packet to check 253 * @is_unsnoopable: stores whether the destination is snoopable 254 * 255 * Checks whether the given IPv4 packet has the potential to be forwarded with a 256 * mode more optimal than classic flooding. 257 * 258 * If so then returns 0. Otherwise -EINVAL is returned or -ENOMEM in case of 259 * memory allocation failure. 260 */ 261 static int batadv_mcast_forw_mode_check_ipv4(struct batadv_priv *bat_priv, 262 struct sk_buff *skb, 263 bool *is_unsnoopable) 264 { 265 struct iphdr *iphdr; 266 267 /* We might fail due to out-of-memory -> drop it */ 268 if (!pskb_may_pull(skb, sizeof(struct ethhdr) + sizeof(*iphdr))) 269 return -ENOMEM; 270 271 iphdr = ip_hdr(skb); 272 273 /* TODO: Implement Multicast Router Discovery (RFC4286), 274 * then allow scope > link local, too 275 */ 276 if (!ipv4_is_local_multicast(iphdr->daddr)) 277 return -EINVAL; 278 279 /* link-local multicast listeners behind a bridge are 280 * not snoopable (see RFC4541, section 2.1.2.2) 281 */ 282 *is_unsnoopable = true; 283 284 return 0; 285 } 286 287 /** 288 * batadv_mcast_forw_mode_check_ipv6 - check for optimized forwarding potential 289 * @bat_priv: the bat priv with all the soft interface information 290 * @skb: the IPv6 packet to check 291 * @is_unsnoopable: stores whether the destination is snoopable 292 * 293 * Checks whether the given IPv6 packet has the potential to be forwarded with a 294 * mode more optimal than classic flooding. 295 * 296 * If so then returns 0. Otherwise -EINVAL is returned or -ENOMEM if we are out 297 * of memory. 298 */ 299 static int batadv_mcast_forw_mode_check_ipv6(struct batadv_priv *bat_priv, 300 struct sk_buff *skb, 301 bool *is_unsnoopable) 302 { 303 struct ipv6hdr *ip6hdr; 304 305 /* We might fail due to out-of-memory -> drop it */ 306 if (!pskb_may_pull(skb, sizeof(struct ethhdr) + sizeof(*ip6hdr))) 307 return -ENOMEM; 308 309 ip6hdr = ipv6_hdr(skb); 310 311 /* TODO: Implement Multicast Router Discovery (RFC4286), 312 * then allow scope > link local, too 313 */ 314 if (IPV6_ADDR_MC_SCOPE(&ip6hdr->daddr) != IPV6_ADDR_SCOPE_LINKLOCAL) 315 return -EINVAL; 316 317 /* link-local-all-nodes multicast listeners behind a bridge are 318 * not snoopable (see RFC4541, section 3, paragraph 3) 319 */ 320 if (ipv6_addr_is_ll_all_nodes(&ip6hdr->daddr)) 321 *is_unsnoopable = true; 322 323 return 0; 324 } 325 326 /** 327 * batadv_mcast_forw_mode_check - check for optimized forwarding potential 328 * @bat_priv: the bat priv with all the soft interface information 329 * @skb: the multicast frame to check 330 * @is_unsnoopable: stores whether the destination is snoopable 331 * 332 * Checks whether the given multicast ethernet frame has the potential to be 333 * forwarded with a mode more optimal than classic flooding. 334 * 335 * If so then returns 0. Otherwise -EINVAL is returned or -ENOMEM if we are out 336 * of memory. 337 */ 338 static int batadv_mcast_forw_mode_check(struct batadv_priv *bat_priv, 339 struct sk_buff *skb, 340 bool *is_unsnoopable) 341 { 342 struct ethhdr *ethhdr = eth_hdr(skb); 343 344 if (!atomic_read(&bat_priv->multicast_mode)) 345 return -EINVAL; 346 347 if (atomic_read(&bat_priv->mcast.num_disabled)) 348 return -EINVAL; 349 350 switch (ntohs(ethhdr->h_proto)) { 351 case ETH_P_IP: 352 return batadv_mcast_forw_mode_check_ipv4(bat_priv, skb, 353 is_unsnoopable); 354 case ETH_P_IPV6: 355 return batadv_mcast_forw_mode_check_ipv6(bat_priv, skb, 356 is_unsnoopable); 357 default: 358 return -EINVAL; 359 } 360 } 361 362 /** 363 * batadv_mcast_want_all_ip_count - count nodes with unspecific mcast interest 364 * @bat_priv: the bat priv with all the soft interface information 365 * @ethhdr: ethernet header of a packet 366 * 367 * Returns the number of nodes which want all IPv4 multicast traffic if the 368 * given ethhdr is from an IPv4 packet or the number of nodes which want all 369 * IPv6 traffic if it matches an IPv6 packet. 370 */ 371 static int batadv_mcast_forw_want_all_ip_count(struct batadv_priv *bat_priv, 372 struct ethhdr *ethhdr) 373 { 374 switch (ntohs(ethhdr->h_proto)) { 375 case ETH_P_IP: 376 return atomic_read(&bat_priv->mcast.num_want_all_ipv4); 377 case ETH_P_IPV6: 378 return atomic_read(&bat_priv->mcast.num_want_all_ipv6); 379 default: 380 /* we shouldn't be here... */ 381 return 0; 382 } 383 } 384 385 /** 386 * batadv_mcast_forw_tt_node_get - get a multicast tt node 387 * @bat_priv: the bat priv with all the soft interface information 388 * @ethhdr: the ether header containing the multicast destination 389 * 390 * Returns an orig_node matching the multicast address provided by ethhdr 391 * via a translation table lookup. This increases the returned nodes refcount. 392 */ 393 static struct batadv_orig_node * 394 batadv_mcast_forw_tt_node_get(struct batadv_priv *bat_priv, 395 struct ethhdr *ethhdr) 396 { 397 return batadv_transtable_search(bat_priv, ethhdr->h_source, 398 ethhdr->h_dest, BATADV_NO_FLAGS); 399 } 400 401 /** 402 * batadv_mcast_want_forw_ipv4_node_get - get a node with an ipv4 flag 403 * @bat_priv: the bat priv with all the soft interface information 404 * 405 * Returns an orig_node which has the BATADV_MCAST_WANT_ALL_IPV4 flag set and 406 * increases its refcount. 407 */ 408 static struct batadv_orig_node * 409 batadv_mcast_forw_ipv4_node_get(struct batadv_priv *bat_priv) 410 { 411 struct batadv_orig_node *tmp_orig_node, *orig_node = NULL; 412 413 rcu_read_lock(); 414 hlist_for_each_entry_rcu(tmp_orig_node, 415 &bat_priv->mcast.want_all_ipv4_list, 416 mcast_want_all_ipv4_node) { 417 if (!atomic_inc_not_zero(&tmp_orig_node->refcount)) 418 continue; 419 420 orig_node = tmp_orig_node; 421 break; 422 } 423 rcu_read_unlock(); 424 425 return orig_node; 426 } 427 428 /** 429 * batadv_mcast_want_forw_ipv6_node_get - get a node with an ipv6 flag 430 * @bat_priv: the bat priv with all the soft interface information 431 * 432 * Returns an orig_node which has the BATADV_MCAST_WANT_ALL_IPV6 flag set 433 * and increases its refcount. 434 */ 435 static struct batadv_orig_node * 436 batadv_mcast_forw_ipv6_node_get(struct batadv_priv *bat_priv) 437 { 438 struct batadv_orig_node *tmp_orig_node, *orig_node = NULL; 439 440 rcu_read_lock(); 441 hlist_for_each_entry_rcu(tmp_orig_node, 442 &bat_priv->mcast.want_all_ipv6_list, 443 mcast_want_all_ipv6_node) { 444 if (!atomic_inc_not_zero(&tmp_orig_node->refcount)) 445 continue; 446 447 orig_node = tmp_orig_node; 448 break; 449 } 450 rcu_read_unlock(); 451 452 return orig_node; 453 } 454 455 /** 456 * batadv_mcast_want_forw_ip_node_get - get a node with an ipv4/ipv6 flag 457 * @bat_priv: the bat priv with all the soft interface information 458 * @ethhdr: an ethernet header to determine the protocol family from 459 * 460 * Returns an orig_node which has the BATADV_MCAST_WANT_ALL_IPV4 or 461 * BATADV_MCAST_WANT_ALL_IPV6 flag, depending on the provided ethhdr, set and 462 * increases its refcount. 463 */ 464 static struct batadv_orig_node * 465 batadv_mcast_forw_ip_node_get(struct batadv_priv *bat_priv, 466 struct ethhdr *ethhdr) 467 { 468 switch (ntohs(ethhdr->h_proto)) { 469 case ETH_P_IP: 470 return batadv_mcast_forw_ipv4_node_get(bat_priv); 471 case ETH_P_IPV6: 472 return batadv_mcast_forw_ipv6_node_get(bat_priv); 473 default: 474 /* we shouldn't be here... */ 475 return NULL; 476 } 477 } 478 479 /** 480 * batadv_mcast_want_forw_unsnoop_node_get - get a node with an unsnoopable flag 481 * @bat_priv: the bat priv with all the soft interface information 482 * 483 * Returns an orig_node which has the BATADV_MCAST_WANT_ALL_UNSNOOPABLES flag 484 * set and increases its refcount. 485 */ 486 static struct batadv_orig_node * 487 batadv_mcast_forw_unsnoop_node_get(struct batadv_priv *bat_priv) 488 { 489 struct batadv_orig_node *tmp_orig_node, *orig_node = NULL; 490 491 rcu_read_lock(); 492 hlist_for_each_entry_rcu(tmp_orig_node, 493 &bat_priv->mcast.want_all_unsnoopables_list, 494 mcast_want_all_unsnoopables_node) { 495 if (!atomic_inc_not_zero(&tmp_orig_node->refcount)) 496 continue; 497 498 orig_node = tmp_orig_node; 499 break; 500 } 501 rcu_read_unlock(); 502 503 return orig_node; 504 } 505 506 /** 507 * batadv_mcast_forw_mode - check on how to forward a multicast packet 508 * @bat_priv: the bat priv with all the soft interface information 509 * @skb: The multicast packet to check 510 * @orig: an originator to be set to forward the skb to 511 * 512 * Returns the forwarding mode as enum batadv_forw_mode and in case of 513 * BATADV_FORW_SINGLE set the orig to the single originator the skb 514 * should be forwarded to. 515 */ 516 enum batadv_forw_mode 517 batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb, 518 struct batadv_orig_node **orig) 519 { 520 int ret, tt_count, ip_count, unsnoop_count, total_count; 521 bool is_unsnoopable = false; 522 struct ethhdr *ethhdr; 523 524 ret = batadv_mcast_forw_mode_check(bat_priv, skb, &is_unsnoopable); 525 if (ret == -ENOMEM) 526 return BATADV_FORW_NONE; 527 else if (ret < 0) 528 return BATADV_FORW_ALL; 529 530 ethhdr = eth_hdr(skb); 531 532 tt_count = batadv_tt_global_hash_count(bat_priv, ethhdr->h_dest, 533 BATADV_NO_FLAGS); 534 ip_count = batadv_mcast_forw_want_all_ip_count(bat_priv, ethhdr); 535 unsnoop_count = !is_unsnoopable ? 0 : 536 atomic_read(&bat_priv->mcast.num_want_all_unsnoopables); 537 538 total_count = tt_count + ip_count + unsnoop_count; 539 540 switch (total_count) { 541 case 1: 542 if (tt_count) 543 *orig = batadv_mcast_forw_tt_node_get(bat_priv, ethhdr); 544 else if (ip_count) 545 *orig = batadv_mcast_forw_ip_node_get(bat_priv, ethhdr); 546 else if (unsnoop_count) 547 *orig = batadv_mcast_forw_unsnoop_node_get(bat_priv); 548 549 if (*orig) 550 return BATADV_FORW_SINGLE; 551 552 /* fall through */ 553 case 0: 554 return BATADV_FORW_NONE; 555 default: 556 return BATADV_FORW_ALL; 557 } 558 } 559 560 /** 561 * batadv_mcast_want_unsnoop_update - update unsnoop counter and list 562 * @bat_priv: the bat priv with all the soft interface information 563 * @orig: the orig_node which multicast state might have changed of 564 * @mcast_flags: flags indicating the new multicast state 565 * 566 * If the BATADV_MCAST_WANT_ALL_UNSNOOPABLES flag of this originator, 567 * orig, has toggled then this method updates counter and list accordingly. 568 */ 569 static void batadv_mcast_want_unsnoop_update(struct batadv_priv *bat_priv, 570 struct batadv_orig_node *orig, 571 uint8_t mcast_flags) 572 { 573 /* switched from flag unset to set */ 574 if (mcast_flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES && 575 !(orig->mcast_flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES)) { 576 atomic_inc(&bat_priv->mcast.num_want_all_unsnoopables); 577 578 spin_lock_bh(&bat_priv->mcast.want_lists_lock); 579 hlist_add_head_rcu(&orig->mcast_want_all_unsnoopables_node, 580 &bat_priv->mcast.want_all_unsnoopables_list); 581 spin_unlock_bh(&bat_priv->mcast.want_lists_lock); 582 /* switched from flag set to unset */ 583 } else if (!(mcast_flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES) && 584 orig->mcast_flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES) { 585 atomic_dec(&bat_priv->mcast.num_want_all_unsnoopables); 586 587 spin_lock_bh(&bat_priv->mcast.want_lists_lock); 588 hlist_del_rcu(&orig->mcast_want_all_unsnoopables_node); 589 spin_unlock_bh(&bat_priv->mcast.want_lists_lock); 590 } 591 } 592 593 /** 594 * batadv_mcast_want_ipv4_update - update want-all-ipv4 counter and list 595 * @bat_priv: the bat priv with all the soft interface information 596 * @orig: the orig_node which multicast state might have changed of 597 * @mcast_flags: flags indicating the new multicast state 598 * 599 * If the BATADV_MCAST_WANT_ALL_IPV4 flag of this originator, orig, has 600 * toggled then this method updates counter and list accordingly. 601 */ 602 static void batadv_mcast_want_ipv4_update(struct batadv_priv *bat_priv, 603 struct batadv_orig_node *orig, 604 uint8_t mcast_flags) 605 { 606 /* switched from flag unset to set */ 607 if (mcast_flags & BATADV_MCAST_WANT_ALL_IPV4 && 608 !(orig->mcast_flags & BATADV_MCAST_WANT_ALL_IPV4)) { 609 atomic_inc(&bat_priv->mcast.num_want_all_ipv4); 610 611 spin_lock_bh(&bat_priv->mcast.want_lists_lock); 612 hlist_add_head_rcu(&orig->mcast_want_all_ipv4_node, 613 &bat_priv->mcast.want_all_ipv4_list); 614 spin_unlock_bh(&bat_priv->mcast.want_lists_lock); 615 /* switched from flag set to unset */ 616 } else if (!(mcast_flags & BATADV_MCAST_WANT_ALL_IPV4) && 617 orig->mcast_flags & BATADV_MCAST_WANT_ALL_IPV4) { 618 atomic_dec(&bat_priv->mcast.num_want_all_ipv4); 619 620 spin_lock_bh(&bat_priv->mcast.want_lists_lock); 621 hlist_del_rcu(&orig->mcast_want_all_ipv4_node); 622 spin_unlock_bh(&bat_priv->mcast.want_lists_lock); 623 } 624 } 625 626 /** 627 * batadv_mcast_want_ipv6_update - update want-all-ipv6 counter and list 628 * @bat_priv: the bat priv with all the soft interface information 629 * @orig: the orig_node which multicast state might have changed of 630 * @mcast_flags: flags indicating the new multicast state 631 * 632 * If the BATADV_MCAST_WANT_ALL_IPV6 flag of this originator, orig, has 633 * toggled then this method updates counter and list accordingly. 634 */ 635 static void batadv_mcast_want_ipv6_update(struct batadv_priv *bat_priv, 636 struct batadv_orig_node *orig, 637 uint8_t mcast_flags) 638 { 639 /* switched from flag unset to set */ 640 if (mcast_flags & BATADV_MCAST_WANT_ALL_IPV6 && 641 !(orig->mcast_flags & BATADV_MCAST_WANT_ALL_IPV6)) { 642 atomic_inc(&bat_priv->mcast.num_want_all_ipv6); 643 644 spin_lock_bh(&bat_priv->mcast.want_lists_lock); 645 hlist_add_head_rcu(&orig->mcast_want_all_ipv6_node, 646 &bat_priv->mcast.want_all_ipv6_list); 647 spin_unlock_bh(&bat_priv->mcast.want_lists_lock); 648 /* switched from flag set to unset */ 649 } else if (!(mcast_flags & BATADV_MCAST_WANT_ALL_IPV6) && 650 orig->mcast_flags & BATADV_MCAST_WANT_ALL_IPV6) { 651 atomic_dec(&bat_priv->mcast.num_want_all_ipv6); 652 653 spin_lock_bh(&bat_priv->mcast.want_lists_lock); 654 hlist_del_rcu(&orig->mcast_want_all_ipv6_node); 655 spin_unlock_bh(&bat_priv->mcast.want_lists_lock); 656 } 657 } 658 659 /** 660 * batadv_mcast_tvlv_ogm_handler_v1 - process incoming multicast tvlv container 661 * @bat_priv: the bat priv with all the soft interface information 662 * @orig: the orig_node of the ogm 663 * @flags: flags indicating the tvlv state (see batadv_tvlv_handler_flags) 664 * @tvlv_value: tvlv buffer containing the multicast data 665 * @tvlv_value_len: tvlv buffer length 666 */ 667 static void batadv_mcast_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv, 668 struct batadv_orig_node *orig, 669 uint8_t flags, 670 void *tvlv_value, 671 uint16_t tvlv_value_len) 672 { 673 bool orig_mcast_enabled = !(flags & BATADV_TVLV_HANDLER_OGM_CIFNOTFND); 674 uint8_t mcast_flags = BATADV_NO_FLAGS; 675 bool orig_initialized; 676 677 orig_initialized = orig->capa_initialized & BATADV_ORIG_CAPA_HAS_MCAST; 678 679 /* If mcast support is turned on decrease the disabled mcast node 680 * counter only if we had increased it for this node before. If this 681 * is a completely new orig_node no need to decrease the counter. 682 */ 683 if (orig_mcast_enabled && 684 !(orig->capabilities & BATADV_ORIG_CAPA_HAS_MCAST)) { 685 if (orig_initialized) 686 atomic_dec(&bat_priv->mcast.num_disabled); 687 orig->capabilities |= BATADV_ORIG_CAPA_HAS_MCAST; 688 /* If mcast support is being switched off increase the disabled 689 * mcast node counter. 690 */ 691 } else if (!orig_mcast_enabled && 692 orig->capabilities & BATADV_ORIG_CAPA_HAS_MCAST) { 693 atomic_inc(&bat_priv->mcast.num_disabled); 694 orig->capabilities &= ~BATADV_ORIG_CAPA_HAS_MCAST; 695 } 696 697 orig->capa_initialized |= BATADV_ORIG_CAPA_HAS_MCAST; 698 699 if (orig_mcast_enabled && tvlv_value && 700 (tvlv_value_len >= sizeof(mcast_flags))) 701 mcast_flags = *(uint8_t *)tvlv_value; 702 703 batadv_mcast_want_unsnoop_update(bat_priv, orig, mcast_flags); 704 batadv_mcast_want_ipv4_update(bat_priv, orig, mcast_flags); 705 batadv_mcast_want_ipv6_update(bat_priv, orig, mcast_flags); 706 707 orig->mcast_flags = mcast_flags; 708 } 709 710 /** 711 * batadv_mcast_init - initialize the multicast optimizations structures 712 * @bat_priv: the bat priv with all the soft interface information 713 */ 714 void batadv_mcast_init(struct batadv_priv *bat_priv) 715 { 716 batadv_tvlv_handler_register(bat_priv, batadv_mcast_tvlv_ogm_handler_v1, 717 NULL, BATADV_TVLV_MCAST, 1, 718 BATADV_TVLV_HANDLER_OGM_CIFNOTFND); 719 } 720 721 /** 722 * batadv_mcast_free - free the multicast optimizations structures 723 * @bat_priv: the bat priv with all the soft interface information 724 */ 725 void batadv_mcast_free(struct batadv_priv *bat_priv) 726 { 727 batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_MCAST, 1); 728 batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_MCAST, 1); 729 730 batadv_mcast_mla_tt_retract(bat_priv, NULL); 731 } 732 733 /** 734 * batadv_mcast_purge_orig - reset originator global mcast state modifications 735 * @orig: the originator which is going to get purged 736 */ 737 void batadv_mcast_purge_orig(struct batadv_orig_node *orig) 738 { 739 struct batadv_priv *bat_priv = orig->bat_priv; 740 741 if (!(orig->capabilities & BATADV_ORIG_CAPA_HAS_MCAST)) 742 atomic_dec(&bat_priv->mcast.num_disabled); 743 744 batadv_mcast_want_unsnoop_update(bat_priv, orig, BATADV_NO_FLAGS); 745 batadv_mcast_want_ipv4_update(bat_priv, orig, BATADV_NO_FLAGS); 746 batadv_mcast_want_ipv6_update(bat_priv, orig, BATADV_NO_FLAGS); 747 } 748