The following commit has been merged in the merge/master branch: commit 9c11ed662985e4a48940edc697044d5072fe77a5 Merge: 14d695a7bfadf092dea49a286618303b34417ae6 fb4756fe5f6e58ca2ab208ca634ae4c8dd6e9499 Author: Antonio Quartulli antonio@meshcoding.com Date: Sun Feb 23 17:29:38 2014 +0100
Merge commit 'fb4756fe5f6e58ca2ab208ca634ae4c8dd6e9499' into merge/master
Signed-off-by: Antonio Quartulli antonio@meshcoding.com
Conflicts: net/batman-adv/Makefile net/batman-adv/Makefile.kbuild net/batman-adv/compat.h net/batman-adv/gen-compat-autoconf.sh net/batman-adv/sysfs-class-net-mesh
diff --combined Documentation/ABI/testing/sysfs-class-net-mesh index 4793d3d,c464062..c464062 --- a/Documentation/ABI/testing/sysfs-class-net-mesh +++ b/Documentation/ABI/testing/sysfs-class-net-mesh @@@ -76,6 -76,15 +76,15 @@@ Description is used to classify clients as "isolated" by the Extended Isolation feature.
+ What: /sys/class/net/<mesh_iface>/mesh/multicast_mode + Date: Feb 2014 + Contact: Linus Lüssing linus.luessing@web.de + Description: + Indicates whether multicast optimizations are enabled + or disabled. If set to zero then all nodes in the + mesh are going to use classic flooding for any + multicast packet with no optimizations. + What: /sys/class/net/<mesh_iface>/mesh/network_coding Date: Nov 2012 Contact: Martin Hundeboll martin@hundeboll.net diff --combined net/batman-adv/Kconfig index fa780b7,0000000..d8ee74c mode 100644,000000..100644 --- a/net/batman-adv/Kconfig +++ b/net/batman-adv/Kconfig @@@ -1,60 -1,0 +1,68 @@@ +# +# B.A.T.M.A.N meshing protocol +# + +config BATMAN_ADV + tristate "B.A.T.M.A.N. Advanced Meshing Protocol" + depends on NET + select CRC16 + select LIBCRC32C + default n + help + B.A.T.M.A.N. (better approach to mobile ad-hoc networking) is + a routing protocol for multi-hop ad-hoc mesh networks. The + networks may be wired or wireless. See + http://www.open-mesh.org/ for more information and user space + tools. + +config BATMAN_ADV_BLA + bool "Bridge Loop Avoidance" + depends on BATMAN_ADV && INET + default y + help + This option enables BLA (Bridge Loop Avoidance), a mechanism + to avoid Ethernet frames looping when mesh nodes are connected + to both the same LAN and the same mesh. If you will never use + more than one mesh node in the same LAN, you can safely remove + this feature and save some space. + +config BATMAN_ADV_DAT + bool "Distributed ARP Table" + depends on BATMAN_ADV && INET + default n + help + This option enables DAT (Distributed ARP Table), a DHT based + mechanism that increases ARP reliability on sparse wireless + mesh networks. If you think that your network does not need + this option you can safely remove it and save some space. + +config BATMAN_ADV_NC + bool "Network Coding" + depends on BATMAN_ADV + default n + help + This option enables network coding, a mechanism that aims to + increase the overall network throughput by fusing multiple + packets in one transmission. + Note that interfaces controlled by batman-adv must be manually + configured to have promiscuous mode enabled in order to make + network coding work. + If you think that your network does not need this feature you + can safely disable it and save some space. + ++config BATMAN_ADV_MCAST ++ bool "Multicast optimisation" ++ default n ++ help ++ This option enables the multicast optimisation which aims to ++ reduce the air overhead while improving the reliability of ++ multicast messages. ++ +config BATMAN_ADV_DEBUG + bool "B.A.T.M.A.N. debugging" + depends on BATMAN_ADV + help + This is an option for use by developers; most people should + say N here. This enables compilation of support for + outputting debugging information to the kernel log. The + output is controlled via the module parameter debug. diff --combined net/batman-adv/Makefile index 42df18f,eb7d8c03..eb7d8c03 --- a/net/batman-adv/Makefile +++ b/net/batman-adv/Makefile @@@ -36,3 -36,4 +36,4 @@@ batman-adv-y += send. batman-adv-y += soft-interface.o batman-adv-y += sysfs.o batman-adv-y += translation-table.o + batman-adv-$(CONFIG_BATMAN_ADV_MCAST) += multicast.o diff --combined net/batman-adv/bat_iv_ogm.c index 8323bce,b3bd4ec..b3bd4ec --- a/net/batman-adv/bat_iv_ogm.c +++ b/net/batman-adv/bat_iv_ogm.c @@@ -347,10 -347,10 +347,10 @@@ static void batadv_iv_ogm_iface_update_ unsigned char *ogm_buff = hard_iface->bat_iv.ogm_buff;
batadv_ogm_packet = (struct batadv_ogm_packet *)ogm_buff; - memcpy(batadv_ogm_packet->orig, - hard_iface->net_dev->dev_addr, ETH_ALEN); - memcpy(batadv_ogm_packet->prev_sender, - hard_iface->net_dev->dev_addr, ETH_ALEN); + ether_addr_copy(batadv_ogm_packet->orig, + hard_iface->net_dev->dev_addr); + ether_addr_copy(batadv_ogm_packet->prev_sender, + hard_iface->net_dev->dev_addr); }
static void @@@ -830,7 -830,7 +830,7 @@@ static void batadv_iv_ogm_forward(struc tvlv_len = ntohs(batadv_ogm_packet->tvlv_len);
batadv_ogm_packet->ttl--; - memcpy(batadv_ogm_packet->prev_sender, ethhdr->h_source, ETH_ALEN); + ether_addr_copy(batadv_ogm_packet->prev_sender, ethhdr->h_source);
/* apply hop penalty */ batadv_ogm_packet->tq = batadv_hop_penalty(batadv_ogm_packet->tq, diff --combined net/batman-adv/bridge_loop_avoidance.c index 05f0712,6f0d9ec..6f0d9ec --- a/net/batman-adv/bridge_loop_avoidance.c +++ b/net/batman-adv/bridge_loop_avoidance.c @@@ -191,7 -191,7 +191,7 @@@ batadv_backbone_hash_find(struct batadv if (!hash) return NULL;
- memcpy(search_entry.orig, addr, ETH_ALEN); + ether_addr_copy(search_entry.orig, addr); search_entry.vid = vid;
index = batadv_choose_backbone_gw(&search_entry, hash->size); @@@ -305,7 -305,7 +305,7 @@@ static void batadv_bla_send_claim(struc /* normal claim frame * set Ethernet SRC to the clients mac */ - memcpy(ethhdr->h_source, mac, ETH_ALEN); + ether_addr_copy(ethhdr->h_source, mac); batadv_dbg(BATADV_DBG_BLA, bat_priv, "bla_send_claim(): CLAIM %pM on vid %d\n", mac, BATADV_PRINT_VID(vid)); @@@ -314,7 -314,7 +314,7 @@@ /* unclaim frame * set HW SRC to the clients mac */ - memcpy(hw_src, mac, ETH_ALEN); + ether_addr_copy(hw_src, mac); batadv_dbg(BATADV_DBG_BLA, bat_priv, "bla_send_claim(): UNCLAIM %pM on vid %d\n", mac, BATADV_PRINT_VID(vid)); @@@ -323,7 -323,7 +323,7 @@@ /* announcement frame * set HW SRC to the special mac containg the crc */ - memcpy(hw_src, mac, ETH_ALEN); + ether_addr_copy(hw_src, mac); batadv_dbg(BATADV_DBG_BLA, bat_priv, "bla_send_claim(): ANNOUNCE of %pM on vid %d\n", ethhdr->h_source, BATADV_PRINT_VID(vid)); @@@ -333,8 -333,8 +333,8 @@@ * set HW SRC and header destination to the receiving backbone * gws mac */ - memcpy(hw_src, mac, ETH_ALEN); - memcpy(ethhdr->h_dest, mac, ETH_ALEN); + ether_addr_copy(hw_src, mac); + ether_addr_copy(ethhdr->h_dest, mac); batadv_dbg(BATADV_DBG_BLA, bat_priv, "bla_send_claim(): REQUEST of %pM to %pM on vid %d\n", ethhdr->h_source, ethhdr->h_dest, @@@ -395,7 -395,7 +395,7 @@@ batadv_bla_get_backbone_gw(struct batad entry->bat_priv = bat_priv; atomic_set(&entry->request_sent, 0); atomic_set(&entry->wait_periods, 0); - memcpy(entry->orig, orig, ETH_ALEN); + ether_addr_copy(entry->orig, orig);
/* one for the hash, one for returning */ atomic_set(&entry->refcount, 2); @@@ -563,7 -563,7 +563,7 @@@ static void batadv_bla_add_claim(struc struct batadv_bla_claim search_claim; int hash_added;
- memcpy(search_claim.addr, mac, ETH_ALEN); + ether_addr_copy(search_claim.addr, mac); search_claim.vid = vid; claim = batadv_claim_hash_find(bat_priv, &search_claim);
@@@ -573,7 -573,7 +573,7 @@@ if (!claim) return;
- memcpy(claim->addr, mac, ETH_ALEN); + ether_addr_copy(claim->addr, mac); claim->vid = vid; claim->lasttime = jiffies; claim->backbone_gw = backbone_gw; @@@ -624,7 -624,7 +624,7 @@@ static void batadv_bla_del_claim(struc { struct batadv_bla_claim search_claim, *claim;
- memcpy(search_claim.addr, mac, ETH_ALEN); + ether_addr_copy(search_claim.addr, mac); search_claim.vid = vid; claim = batadv_claim_hash_find(bat_priv, &search_claim); if (!claim) @@@ -882,7 -882,7 +882,7 @@@ static int batadv_bla_process_claim(str proto = ethhdr->h_proto; headlen = ETH_HLEN; if (vid & BATADV_VLAN_HAS_TAG) { - vhdr = (struct vlan_ethhdr *)ethhdr; + vhdr = vlan_eth_hdr(skb); proto = vhdr->h_vlan_encapsulated_proto; headlen += VLAN_HLEN; } @@@ -1103,8 -1103,8 +1103,8 @@@ void batadv_bla_update_orig_address(str oldif->net_dev->dev_addr)) continue;
- memcpy(backbone_gw->orig, - primary_if->net_dev->dev_addr, ETH_ALEN); + ether_addr_copy(backbone_gw->orig, + primary_if->net_dev->dev_addr); /* send an announce frame so others will ask for our * claims and update their tables. */ @@@ -1310,7 -1310,7 +1310,7 @@@ int batadv_bla_check_bcast_duplist(stru entry = &bat_priv->bla.bcast_duplist[curr]; entry->crc = crc; entry->entrytime = jiffies; - memcpy(entry->orig, bcast_packet->orig, ETH_ALEN); + ether_addr_copy(entry->orig, bcast_packet->orig); bat_priv->bla.bcast_duplist_curr = curr;
out: @@@ -1458,7 -1458,7 +1458,7 @@@ int batadv_bla_rx(struct batadv_priv *b if (is_multicast_ether_addr(ethhdr->h_dest) && is_bcast) goto handled;
- memcpy(search_claim.addr, ethhdr->h_source, ETH_ALEN); + ether_addr_copy(search_claim.addr, ethhdr->h_source); search_claim.vid = vid; claim = batadv_claim_hash_find(bat_priv, &search_claim);
@@@ -1547,9 -1547,6 +1547,6 @@@ int batadv_bla_tx(struct batadv_priv *b if (!atomic_read(&bat_priv->bridge_loop_avoidance)) goto allow;
- /* in VLAN case, the mac header might not be set. */ - skb_reset_mac_header(skb); - if (batadv_bla_process_claim(bat_priv, primary_if, skb)) goto handled;
@@@ -1560,7 -1557,7 +1557,7 @@@ if (is_multicast_ether_addr(ethhdr->h_dest)) goto handled;
- memcpy(search_claim.addr, ethhdr->h_source, ETH_ALEN); + ether_addr_copy(search_claim.addr, ethhdr->h_source); search_claim.vid = vid;
claim = batadv_claim_hash_find(bat_priv, &search_claim); diff --combined net/batman-adv/distributed-arp-table.c index 5bb37a8,b25fd64..b25fd64 --- a/net/batman-adv/distributed-arp-table.c +++ b/net/batman-adv/distributed-arp-table.c @@@ -277,7 -277,7 +277,7 @@@ static void batadv_dat_entry_add(struc /* if this entry is already known, just update it */ if (dat_entry) { if (!batadv_compare_eth(dat_entry->mac_addr, mac_addr)) - memcpy(dat_entry->mac_addr, mac_addr, ETH_ALEN); + ether_addr_copy(dat_entry->mac_addr, mac_addr); dat_entry->last_update = jiffies; batadv_dbg(BATADV_DBG_DAT, bat_priv, "Entry updated: %pI4 %pM (vid: %d)\n", @@@ -292,7 -292,7 +292,7 @@@
dat_entry->ip = ip; dat_entry->vid = vid; - memcpy(dat_entry->mac_addr, mac_addr, ETH_ALEN); + ether_addr_copy(dat_entry->mac_addr, mac_addr); dat_entry->last_update = jiffies; atomic_set(&dat_entry->refcount, 2);
diff --combined net/batman-adv/fragmentation.c index 88df9b1,bcc4bea..bcc4bea --- a/net/batman-adv/fragmentation.c +++ b/net/batman-adv/fragmentation.c @@@ -449,8 -449,8 +449,8 @@@ bool batadv_frag_send_packet(struct sk_ frag_header.reserved = 0; frag_header.no = 0; frag_header.total_size = htons(skb->len); - memcpy(frag_header.orig, primary_if->net_dev->dev_addr, ETH_ALEN); - memcpy(frag_header.dest, orig_node->orig, ETH_ALEN); + ether_addr_copy(frag_header.orig, primary_if->net_dev->dev_addr); + ether_addr_copy(frag_header.dest, orig_node->orig);
/* Eat and send fragments from the tail of skb */ while (skb->len > max_fragment_size) { diff --combined net/batman-adv/gateway_client.c index 55cf226,c835e13..c835e13 --- a/net/batman-adv/gateway_client.c +++ b/net/batman-adv/gateway_client.c @@@ -389,8 -389,6 +389,6 @@@ out batadv_neigh_ifinfo_free_ref(router_gw_tq); if (router_orig_tq) batadv_neigh_ifinfo_free_ref(router_orig_tq); - - return; }
/** @@@ -680,7 -678,7 +678,7 @@@ batadv_gw_dhcp_recipient_get(struct sk_ if (!pskb_may_pull(skb, *header_len + ETH_HLEN)) return BATADV_DHCP_NO;
- ethhdr = (struct ethhdr *)skb->data; + ethhdr = eth_hdr(skb); proto = ethhdr->h_proto; *header_len += ETH_HLEN;
@@@ -689,7 -687,7 +687,7 @@@ if (!pskb_may_pull(skb, *header_len + VLAN_HLEN)) return BATADV_DHCP_NO;
- vhdr = (struct vlan_ethhdr *)skb->data; + vhdr = vlan_eth_hdr(skb); proto = vhdr->h_vlan_encapsulated_proto; *header_len += VLAN_HLEN; } @@@ -728,7 -726,7 +726,7 @@@ return BATADV_DHCP_NO;
/* skb->data might have been reallocated by pskb_may_pull() */ - ethhdr = (struct ethhdr *)skb->data; + ethhdr = eth_hdr(skb); if (ntohs(ethhdr->h_proto) == ETH_P_8021Q) ethhdr = (struct ethhdr *)(skb->data + VLAN_HLEN);
@@@ -765,7 -763,7 +763,7 @@@ if (*p != ETH_ALEN) return BATADV_DHCP_NO;
- memcpy(chaddr, skb->data + chaddr_offset, ETH_ALEN); + ether_addr_copy(chaddr, skb->data + chaddr_offset); }
return ret; diff --combined net/batman-adv/icmp_socket.c index abb9d6e,bf07dfd..bf07dfd --- a/net/batman-adv/icmp_socket.c +++ b/net/batman-adv/icmp_socket.c @@@ -158,6 -158,7 +158,7 @@@ static ssize_t batadv_socket_write(stru struct batadv_orig_node *orig_node = NULL; struct batadv_neigh_node *neigh_node = NULL; size_t packet_len = sizeof(struct batadv_icmp_packet); + uint8_t *addr;
if (len < sizeof(struct batadv_icmp_header)) { batadv_dbg(BATADV_DBG_BATMAN, bat_priv, @@@ -227,10 -228,10 +228,10 @@@ goto dst_unreach;
icmp_packet_rr = (struct batadv_icmp_packet_rr *)icmp_header; - if (packet_len == sizeof(*icmp_packet_rr)) - memcpy(icmp_packet_rr->rr, - neigh_node->if_incoming->net_dev->dev_addr, - ETH_ALEN); + if (packet_len == sizeof(*icmp_packet_rr)) { + addr = neigh_node->if_incoming->net_dev->dev_addr; + ether_addr_copy(icmp_packet_rr->rr, addr); + }
break; default: @@@ -250,7 -251,7 +251,7 @@@ goto free_skb; }
- memcpy(icmp_header->orig, primary_if->net_dev->dev_addr, ETH_ALEN); + ether_addr_copy(icmp_header->orig, primary_if->net_dev->dev_addr);
batadv_send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); goto out; diff --combined net/batman-adv/main.c index 66ae135,d1183e8..d1183e8 --- a/net/batman-adv/main.c +++ b/net/batman-adv/main.c @@@ -34,6 -34,7 +34,7 @@@ #include "gateway_client.h" #include "bridge_loop_avoidance.h" #include "distributed-arp-table.h" + #include "multicast.h" #include "gateway_common.h" #include "hash.h" #include "bat_algo.h" @@@ -110,6 -111,9 +111,9 @@@ int batadv_mesh_init(struct net_device spin_lock_init(&bat_priv->tt.last_changeset_lock); spin_lock_init(&bat_priv->tt.commit_lock); spin_lock_init(&bat_priv->gw.list_lock); + #ifdef CONFIG_BATMAN_ADV_MCAST + spin_lock_init(&bat_priv->mcast.want_lists_lock); + #endif spin_lock_init(&bat_priv->tvlv.container_list_lock); spin_lock_init(&bat_priv->tvlv.handler_list_lock); spin_lock_init(&bat_priv->softif_vlan_list_lock); @@@ -117,9 -121,17 +121,17 @@@ INIT_HLIST_HEAD(&bat_priv->forw_bat_list); INIT_HLIST_HEAD(&bat_priv->forw_bcast_list); INIT_HLIST_HEAD(&bat_priv->gw.list); + #ifdef CONFIG_BATMAN_ADV_MCAST + INIT_HLIST_HEAD(&bat_priv->mcast.want_all_unsnoopables_list); + INIT_HLIST_HEAD(&bat_priv->mcast.want_all_ipv4_list); + INIT_HLIST_HEAD(&bat_priv->mcast.want_all_ipv6_list); + #endif INIT_LIST_HEAD(&bat_priv->tt.changes_list); INIT_LIST_HEAD(&bat_priv->tt.req_list); INIT_LIST_HEAD(&bat_priv->tt.roam_list); + #ifdef CONFIG_BATMAN_ADV_MCAST + INIT_HLIST_HEAD(&bat_priv->mcast.mla_list); + #endif INIT_HLIST_HEAD(&bat_priv->tvlv.container_list); INIT_HLIST_HEAD(&bat_priv->tvlv.handler_list); INIT_HLIST_HEAD(&bat_priv->softif_vlan_list); @@@ -145,6 -157,7 +157,7 @@@ goto err;
batadv_gw_init(bat_priv); + batadv_mcast_init(bat_priv);
atomic_set(&bat_priv->gw.reselect, 0); atomic_set(&bat_priv->mesh_state, BATADV_MESH_ACTIVE); @@@ -169,6 -182,8 +182,8 @@@ void batadv_mesh_free(struct net_devic batadv_dat_free(bat_priv); batadv_bla_free(bat_priv);
+ batadv_mcast_free(bat_priv); + /* Free the TT and the originator tables only after having terminated * all the other depending components which may use these structures for * their purposes. @@@ -1133,8 -1148,8 +1148,8 @@@ void batadv_tvlv_unicast_send(struct ba unicast_tvlv_packet->reserved = 0; unicast_tvlv_packet->tvlv_len = htons(tvlv_len); unicast_tvlv_packet->align = 0; - memcpy(unicast_tvlv_packet->src, src, ETH_ALEN); - memcpy(unicast_tvlv_packet->dst, dst, ETH_ALEN); + ether_addr_copy(unicast_tvlv_packet->src, src); + ether_addr_copy(unicast_tvlv_packet->dst, dst);
tvlv_buff = (unsigned char *)(unicast_tvlv_packet + 1); tvlv_hdr = (struct batadv_tvlv_hdr *)tvlv_buff; diff --combined net/batman-adv/main.h index 9374f1a,0000000..515dce7 mode 100644,000000..100644 --- a/net/batman-adv/main.h +++ b/net/batman-adv/main.h @@@ -1,380 -1,0 +1,382 @@@ +/* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors: + * + * Marek Lindner, Simon Wunderlich + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see http://www.gnu.org/licenses/. + */ + +#ifndef _NET_BATMAN_ADV_MAIN_H_ +#define _NET_BATMAN_ADV_MAIN_H_ + +#define BATADV_DRIVER_AUTHOR "Marek Lindner mareklindner@neomailbox.ch, " \ + "Simon Wunderlich sw@simonwunderlich.de" +#define BATADV_DRIVER_DESC "B.A.T.M.A.N. advanced" +#define BATADV_DRIVER_DEVICE "batman-adv" + +#ifndef BATADV_SOURCE_VERSION +#define BATADV_SOURCE_VERSION "2014.1.0" +#endif + +/* B.A.T.M.A.N. parameters */ + +#define BATADV_TQ_MAX_VALUE 255 +#define BATADV_JITTER 20 + +/* Time To Live of broadcast messages */ +#define BATADV_TTL 50 + +/* purge originators after time in seconds if no valid packet comes in + * -> TODO: check influence on BATADV_TQ_LOCAL_WINDOW_SIZE + */ +#define BATADV_PURGE_TIMEOUT 200000 /* 200 seconds */ +#define BATADV_TT_LOCAL_TIMEOUT 600000 /* in milliseconds */ +#define BATADV_TT_CLIENT_ROAM_TIMEOUT 600000 /* in milliseconds */ +#define BATADV_TT_CLIENT_TEMP_TIMEOUT 600000 /* in milliseconds */ +#define BATADV_TT_WORK_PERIOD 5000 /* 5 seconds */ +#define BATADV_ORIG_WORK_PERIOD 1000 /* 1 second */ +#define BATADV_DAT_ENTRY_TIMEOUT (5*60000) /* 5 mins in milliseconds */ +/* sliding packet range of received originator messages in sequence numbers + * (should be a multiple of our word size) + */ +#define BATADV_TQ_LOCAL_WINDOW_SIZE 64 +/* milliseconds we have to keep pending tt_req */ +#define BATADV_TT_REQUEST_TIMEOUT 3000 + +#define BATADV_TQ_GLOBAL_WINDOW_SIZE 5 +#define BATADV_TQ_LOCAL_BIDRECT_SEND_MINIMUM 1 +#define BATADV_TQ_LOCAL_BIDRECT_RECV_MINIMUM 1 +#define BATADV_TQ_TOTAL_BIDRECT_LIMIT 1 + +/* number of OGMs sent with the last tt diff */ +#define BATADV_TT_OGM_APPEND_MAX 3 + +/* Time in which a client can roam at most ROAMING_MAX_COUNT times in + * milliseconds + */ +#define BATADV_ROAMING_MAX_TIME 20000 +#define BATADV_ROAMING_MAX_COUNT 5 + +#define BATADV_NO_FLAGS 0 + +#define BATADV_NULL_IFINDEX 0 /* dummy ifindex used to avoid iface checks */ + +#define BATADV_NO_MARK 0 + +/* default interface for multi interface operation. The default interface is + * used for communication which originated locally (i.e. is not forwarded) + * or where special forwarding is not desired/necessary. + */ +#define BATADV_IF_DEFAULT ((struct batadv_hard_iface *)NULL) + +#define BATADV_NUM_WORDS BITS_TO_LONGS(BATADV_TQ_LOCAL_WINDOW_SIZE) + +#define BATADV_LOG_BUF_LEN 8192 /* has to be a power of 2 */ + +/* number of packets to send for broadcasts on different interface types */ +#define BATADV_NUM_BCASTS_DEFAULT 1 +#define BATADV_NUM_BCASTS_WIRELESS 3 +#define BATADV_NUM_BCASTS_MAX 3 + +/* msecs after which an ARP_REQUEST is sent in broadcast as fallback */ +#define ARP_REQ_DELAY 250 +/* numbers of originator to contact for any PUT/GET DHT operation */ +#define BATADV_DAT_CANDIDATES_NUM 3 + +/** + * BATADV_TQ_SIMILARITY_THRESHOLD - TQ points that a secondary metric can differ + * at most from the primary one in order to be still considered acceptable + */ +#define BATADV_TQ_SIMILARITY_THRESHOLD 50 + +/* how much worse secondary interfaces may be to be considered as bonding + * candidates + */ +#define BATADV_BONDING_TQ_THRESHOLD 50 + +/* should not be bigger than 512 bytes or change the size of + * forw_packet->direct_link_flags + */ +#define BATADV_MAX_AGGREGATION_BYTES 512 +#define BATADV_MAX_AGGREGATION_MS 100 + +#define BATADV_BLA_PERIOD_LENGTH 10000 /* 10 seconds */ +#define BATADV_BLA_BACKBONE_TIMEOUT (BATADV_BLA_PERIOD_LENGTH * 3) +#define BATADV_BLA_CLAIM_TIMEOUT (BATADV_BLA_PERIOD_LENGTH * 10) +#define BATADV_BLA_WAIT_PERIODS 3 + +#define BATADV_DUPLIST_SIZE 16 +#define BATADV_DUPLIST_TIMEOUT 500 /* 500 ms */ +/* don't reset again within 30 seconds */ +#define BATADV_RESET_PROTECTION_MS 30000 +#define BATADV_EXPECTED_SEQNO_RANGE 65536 + +#define BATADV_NC_NODE_TIMEOUT 10000 /* Milliseconds */ + +enum batadv_mesh_state { + BATADV_MESH_INACTIVE, + BATADV_MESH_ACTIVE, + BATADV_MESH_DEACTIVATING, +}; + +#define BATADV_BCAST_QUEUE_LEN 256 +#define BATADV_BATMAN_QUEUE_LEN 256 + +enum batadv_uev_action { + BATADV_UEV_ADD = 0, + BATADV_UEV_DEL, + BATADV_UEV_CHANGE, +}; + +enum batadv_uev_type { + BATADV_UEV_GW = 0, +}; + +#define BATADV_GW_THRESHOLD 50 + +/* Number of fragment chains for each orig_node */ +#define BATADV_FRAG_BUFFER_COUNT 8 +/* Maximum number of fragments for one packet */ +#define BATADV_FRAG_MAX_FRAGMENTS 16 +/* Maxumim size of each fragment */ +#define BATADV_FRAG_MAX_FRAG_SIZE 1400 +/* Time to keep fragments while waiting for rest of the fragments */ +#define BATADV_FRAG_TIMEOUT 10000 + +#define BATADV_DAT_CANDIDATE_NOT_FOUND 0 +#define BATADV_DAT_CANDIDATE_ORIG 1 + +/* Debug Messages */ +#ifdef pr_fmt +#undef pr_fmt +#endif +/* Append 'batman-adv: ' before kernel messages */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +/* Kernel headers */ + +#include <linux/mutex.h> /* mutex */ +#include <linux/module.h> /* needed by all modules */ +#include <linux/netdevice.h> /* netdevice */ +#include <linux/etherdevice.h> /* ethernet address classification */ +#include <linux/if_ether.h> /* ethernet header */ +#include <linux/poll.h> /* poll_table */ +#include <linux/kthread.h> /* kernel threads */ +#include <linux/pkt_sched.h> /* schedule types */ +#include <linux/workqueue.h> /* workqueue */ +#include <linux/percpu.h> +#include <linux/slab.h> +#include <net/sock.h> /* struct sock */ ++#include <net/addrconf.h> /* ipv6 address stuff */ ++#include <linux/ip.h> +#include <net/rtnetlink.h> +#include <linux/jiffies.h> +#include <linux/seq_file.h> +#include <linux/if_vlan.h> + +#include "types.h" + +#define BATADV_PRINT_VID(vid) (vid & BATADV_VLAN_HAS_TAG ? \ + (int)(vid & VLAN_VID_MASK) : -1) + +extern char batadv_routing_algo[]; +extern struct list_head batadv_hardif_list; + +extern unsigned char batadv_broadcast_addr[]; +extern struct workqueue_struct *batadv_event_workqueue; + +int batadv_mesh_init(struct net_device *soft_iface); +void batadv_mesh_free(struct net_device *soft_iface); +int batadv_is_my_mac(struct batadv_priv *bat_priv, const uint8_t *addr); +struct batadv_hard_iface * +batadv_seq_print_text_primary_if_get(struct seq_file *seq); +int batadv_max_header_len(void); +void batadv_skb_set_priority(struct sk_buff *skb, int offset); +int batadv_batman_skb_recv(struct sk_buff *skb, struct net_device *dev, + struct packet_type *ptype, + struct net_device *orig_dev); +int +batadv_recv_handler_register(uint8_t packet_type, + int (*recv_handler)(struct sk_buff *, + struct batadv_hard_iface *)); +void batadv_recv_handler_unregister(uint8_t packet_type); +int batadv_algo_register(struct batadv_algo_ops *bat_algo_ops); +int batadv_algo_select(struct batadv_priv *bat_priv, char *name); +int batadv_algo_seq_print_text(struct seq_file *seq, void *offset); +__be32 batadv_skb_crc32(struct sk_buff *skb, u8 *payload_ptr); + +/** + * enum batadv_dbg_level - available log levels + * @BATADV_DBG_BATMAN: OGM and TQ computations related messages + * @BATADV_DBG_ROUTES: route added / changed / deleted + * @BATADV_DBG_TT: translation table messages + * @BATADV_DBG_BLA: bridge loop avoidance messages + * @BATADV_DBG_DAT: ARP snooping and DAT related messages + * @BATADV_DBG_NC: network coding related messages + * @BATADV_DBG_ALL: the union of all the above log levels + */ +enum batadv_dbg_level { + BATADV_DBG_BATMAN = BIT(0), + BATADV_DBG_ROUTES = BIT(1), + BATADV_DBG_TT = BIT(2), + BATADV_DBG_BLA = BIT(3), + BATADV_DBG_DAT = BIT(4), + BATADV_DBG_NC = BIT(5), + BATADV_DBG_ALL = 63, +}; + +#ifdef CONFIG_BATMAN_ADV_DEBUG +int batadv_debug_log(struct batadv_priv *bat_priv, const char *fmt, ...) +__printf(2, 3); + +#define batadv_dbg(type, bat_priv, fmt, arg...) \ + do { \ + if (atomic_read(&bat_priv->log_level) & type) \ + batadv_debug_log(bat_priv, fmt, ## arg);\ + } \ + while (0) +#else /* !CONFIG_BATMAN_ADV_DEBUG */ +__printf(3, 4) +static inline void batadv_dbg(int type __always_unused, + struct batadv_priv *bat_priv __always_unused, + const char *fmt __always_unused, ...) +{ +} +#endif + +#define batadv_info(net_dev, fmt, arg...) \ + do { \ + struct net_device *_netdev = (net_dev); \ + struct batadv_priv *_batpriv = netdev_priv(_netdev); \ + batadv_dbg(BATADV_DBG_ALL, _batpriv, fmt, ## arg); \ + pr_info("%s: " fmt, _netdev->name, ## arg); \ + } while (0) +#define batadv_err(net_dev, fmt, arg...) \ + do { \ + struct net_device *_netdev = (net_dev); \ + struct batadv_priv *_batpriv = netdev_priv(_netdev); \ + batadv_dbg(BATADV_DBG_ALL, _batpriv, fmt, ## arg); \ + pr_err("%s: " fmt, _netdev->name, ## arg); \ + } while (0) + +/* returns 1 if they are the same ethernet addr + * + * note: can't use ether_addr_equal() as it requires aligned memory + */ +static inline int batadv_compare_eth(const void *data1, const void *data2) +{ + return ether_addr_equal_unaligned(data1, data2); +} + +/** + * has_timed_out - compares current time (jiffies) and timestamp + timeout + * @timestamp: base value to compare with (in jiffies) + * @timeout: added to base value before comparing (in milliseconds) + * + * Returns true if current time is after timestamp + timeout + */ +static inline bool batadv_has_timed_out(unsigned long timestamp, + unsigned int timeout) +{ + return time_is_before_jiffies(timestamp + msecs_to_jiffies(timeout)); +} + +#define batadv_atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0) + +/* Returns the smallest signed integer in two's complement with the sizeof x */ +#define batadv_smallest_signed_int(x) (1u << (7u + 8u * (sizeof(x) - 1u))) + +/* Checks if a sequence number x is a predecessor/successor of y. + * they handle overflows/underflows and can correctly check for a + * predecessor/successor unless the variable sequence number has grown by + * more then 2**(bitwidth(x)-1)-1. + * This means that for a uint8_t with the maximum value 255, it would think: + * - when adding nothing - it is neither a predecessor nor a successor + * - before adding more than 127 to the starting value - it is a predecessor, + * - when adding 128 - it is neither a predecessor nor a successor, + * - after adding more than 127 to the starting value - it is a successor + */ +#define batadv_seq_before(x, y) ({typeof(x) _d1 = (x); \ + typeof(y) _d2 = (y); \ + typeof(x) _dummy = (_d1 - _d2); \ + (void) (&_d1 == &_d2); \ + _dummy > batadv_smallest_signed_int(_dummy); }) +#define batadv_seq_after(x, y) batadv_seq_before(y, x) + +/* Stop preemption on local cpu while incrementing the counter */ +static inline void batadv_add_counter(struct batadv_priv *bat_priv, size_t idx, + size_t count) +{ + this_cpu_add(bat_priv->bat_counters[idx], count); +} + +#define batadv_inc_counter(b, i) batadv_add_counter(b, i, 1) + +/* Sum and return the cpu-local counters for index 'idx' */ +static inline uint64_t batadv_sum_counter(struct batadv_priv *bat_priv, + size_t idx) +{ + uint64_t *counters, sum = 0; + int cpu; + + for_each_possible_cpu(cpu) { + counters = per_cpu_ptr(bat_priv->bat_counters, cpu); + sum += counters[idx]; + } + + return sum; +} + +/* Define a macro to reach the control buffer of the skb. The members of the + * control buffer are defined in struct batadv_skb_cb in types.h. + * The macro is inspired by the similar macro TCP_SKB_CB() in tcp.h. + */ +#define BATADV_SKB_CB(__skb) ((struct batadv_skb_cb *)&((__skb)->cb[0])) + +void batadv_tvlv_container_register(struct batadv_priv *bat_priv, + uint8_t type, uint8_t version, + void *tvlv_value, uint16_t tvlv_value_len); +uint16_t batadv_tvlv_container_ogm_append(struct batadv_priv *bat_priv, + unsigned char **packet_buff, + int *packet_buff_len, + int packet_min_len); +void batadv_tvlv_ogm_receive(struct batadv_priv *bat_priv, + struct batadv_ogm_packet *batadv_ogm_packet, + struct batadv_orig_node *orig_node); +void batadv_tvlv_container_unregister(struct batadv_priv *bat_priv, + uint8_t type, uint8_t version); + +void batadv_tvlv_handler_register(struct batadv_priv *bat_priv, + void (*optr)(struct batadv_priv *bat_priv, + struct batadv_orig_node *orig, + uint8_t flags, + void *tvlv_value, + uint16_t tvlv_value_len), + int (*uptr)(struct batadv_priv *bat_priv, + uint8_t *src, uint8_t *dst, + void *tvlv_value, + uint16_t tvlv_value_len), + uint8_t type, uint8_t version, uint8_t flags); +void batadv_tvlv_handler_unregister(struct batadv_priv *bat_priv, + uint8_t type, uint8_t version); +int batadv_tvlv_containers_process(struct batadv_priv *bat_priv, + bool ogm_source, + struct batadv_orig_node *orig_node, + uint8_t *src, uint8_t *dst, + void *tvlv_buff, uint16_t tvlv_buff_len); +void batadv_tvlv_unicast_send(struct batadv_priv *bat_priv, uint8_t *src, + uint8_t *dst, uint8_t type, uint8_t version, + void *tvlv_value, uint16_t tvlv_value_len); +unsigned short batadv_get_vid(struct sk_buff *skb, size_t header_len); +bool batadv_vlan_ap_isola_get(struct batadv_priv *bat_priv, unsigned short vid); + +#endif /* _NET_BATMAN_ADV_MAIN_H_ */ diff --combined net/batman-adv/multicast.c index 0000000,e69143b..e69143b mode 000000,100644..100644 --- a/net/batman-adv/multicast.c +++ b/net/batman-adv/multicast.c @@@ -1,0 -1,773 +1,773 @@@ + /* Copyright (C) 2014 B.A.T.M.A.N. contributors: + * + * Linus Lüssing + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + + #include "main.h" + #include "multicast.h" + #include "originator.h" + #include "hard-interface.h" + #include "translation-table.h" + #include "multicast.h" + + /** + * batadv_mcast_mla_softif_get - get softif multicast listeners + * @dev: the device to collect multicast addresses from + * @mcast_list: a list to put found addresses into + * + * Collect multicast addresses of the local multicast listeners + * on the given soft interface, dev, in the given mcast_list. + * + * Return -ENOMEM on memory allocation error or the number of + * items added to the mcast_list otherwise. + */ + static int batadv_mcast_mla_softif_get(struct net_device *dev, + struct hlist_head *mcast_list) + { + struct netdev_hw_addr *mc_list_entry; + struct batadv_hw_addr *new; + int ret = 0; + + netif_addr_lock_bh(dev); + netdev_for_each_mc_addr(mc_list_entry, dev) { + new = kmalloc(sizeof(*new), GFP_ATOMIC); + if (!new) { + ret = -ENOMEM; + break; + } + + ether_addr_copy(&new->addr, &mc_list_entry->addr); + hlist_add_head(&new->list, mcast_list); + ret++; + } + netif_addr_unlock_bh(dev); + + return ret; + } + + /** + * batadv_mcast_mla_is_duplicate - check whether an address is in a list + * @mcast_addr: the multicast address to check + * @mcast_list: the list with multicast addresses to search in + * + * Return true if the given address is already in the given list. + * Otherwise returns false. + */ + static bool batadv_mcast_mla_is_duplicate(uint8_t *mcast_addr, + struct hlist_head *mcast_list) + { + struct batadv_hw_addr *mcast_entry; + + hlist_for_each_entry(mcast_entry, mcast_list, list) + if (batadv_compare_eth(mcast_entry->addr, mcast_addr)) + return true; + + return false; + } + + /** + * batadv_mcast_mla_list_free - free a list of multicast addresses + * @mcast_list: the list to free + * + * Remove and free all items in the given mcast_list. + */ + static void batadv_mcast_mla_list_free(struct hlist_head *mcast_list) + { + struct batadv_hw_addr *mcast_entry; + struct hlist_node *tmp; + + hlist_for_each_entry_safe(mcast_entry, tmp, mcast_list, list) { + hlist_del(&mcast_entry->list); + kfree(mcast_entry); + } + } + + /** + * batadv_mcast_mla_tt_retract - clean up multicast listener announcements + * @bat_priv: the bat priv with all the soft interface information + * @mcast_list: a list of addresses which should _not_ be removed + * + * Retract the announcement of any multicast listener from the + * translation table except the ones listed in the given mcast_list. + * + * If mcast_list is NULL then all are retracted. + */ + static void batadv_mcast_mla_tt_retract(struct batadv_priv *bat_priv, + struct hlist_head *mcast_list) + { + struct batadv_hw_addr *mcast_entry; + struct hlist_node *tmp; + + hlist_for_each_entry_safe(mcast_entry, tmp, &bat_priv->mcast.mla_list, + list) { + if (mcast_list && + batadv_mcast_mla_is_duplicate(mcast_entry->addr, + mcast_list)) + continue; + + batadv_tt_local_remove(bat_priv, mcast_entry->addr, + BATADV_NO_FLAGS, + "mcast TT outdated", false); + + hlist_del(&mcast_entry->list); + kfree(mcast_entry); + } + } + + /** + * batadv_mcast_mla_tt_add - add multicast listener announcements + * @bat_priv: the bat priv with all the soft interface information + * @mcast_list: a list of addresses which are going to get added + * + * Add multicast listener announcements from the given mcast_list to the + * translation table if they have not been added yet. + */ + static void batadv_mcast_mla_tt_add(struct batadv_priv *bat_priv, + struct hlist_head *mcast_list) + { + struct batadv_hw_addr *mcast_entry; + struct hlist_node *tmp; + + if (!mcast_list) + return; + + hlist_for_each_entry_safe(mcast_entry, tmp, mcast_list, list) { + if (batadv_mcast_mla_is_duplicate(mcast_entry->addr, + &bat_priv->mcast.mla_list)) + continue; + + if (!batadv_tt_local_add(bat_priv->soft_iface, + mcast_entry->addr, BATADV_NO_FLAGS, + BATADV_NULL_IFINDEX, BATADV_NO_MARK)) + continue; + + hlist_del(&mcast_entry->list); + hlist_add_head(&mcast_entry->list, &bat_priv->mcast.mla_list); + } + } + + /** + * batadv_mcast_get_bridge - get the bridge interface on our soft interface + * @bat_priv: the bat priv with all the soft interface information + * + * Return the next bridge interface on top of our soft interface and increase + * its refcount. If no such bridge interface exists, then return NULL. + */ + static struct net_device * + batadv_mcast_get_bridge(struct batadv_priv *bat_priv) + { + struct net_device *upper = bat_priv->soft_iface; + + rcu_read_lock(); + + do { + upper = netdev_master_upper_dev_get_rcu(upper); + } while (upper && !(upper->priv_flags & IFF_EBRIDGE)); + + if (upper) + dev_hold(upper); + + rcu_read_unlock(); + + return upper; + } + + /** + * batadv_mcast_has_bridge - check whether the soft-iface is bridged + * @bat_priv: the bat priv with all the soft interface information + * + * Check whether there is a bridge on top of our soft interface. Return + * true if so, false otherwise. + */ + static bool batadv_mcast_has_bridge(struct batadv_priv *bat_priv) + { + struct net_device *bridge; + + bridge = batadv_mcast_get_bridge(bat_priv); + if (!bridge) + goto out; + + dev_put(bridge); + return true; + out: + return false; + } + + /** + * batadv_mcast_mla_tvlv_update - update multicast tvlv + * @bat_priv: the bat priv with all the soft interface information + * + * Update the own multicast tvlv with our current multicast related settings, + * capabilities and inabilities. + * + * Return true if the tvlv container is registered afterwards. Otherwise return + * false. + */ + static bool batadv_mcast_mla_tvlv_update(struct batadv_priv *bat_priv) + { + struct batadv_tvlv_mcast_data mcast_data; + + mcast_data.flags = BATADV_NO_FLAGS; + memset(mcast_data.reserved, 0, sizeof(mcast_data.reserved)); + + /* Avoid attaching MLAs, if there is a bridge on top of our soft + * interface, we don't support that yet (TODO) + */ + if (batadv_mcast_has_bridge(bat_priv)) { + if (bat_priv->mcast.enabled) { + batadv_tvlv_container_unregister(bat_priv, + BATADV_TVLV_MCAST, 1); + bat_priv->mcast.enabled = false; + } + + return false; + } + + if (!bat_priv->mcast.enabled || + mcast_data.flags != bat_priv->mcast.flags) { + batadv_tvlv_container_register(bat_priv, BATADV_TVLV_MCAST, 1, + &mcast_data, sizeof(mcast_data)); + bat_priv->mcast.flags = mcast_data.flags; + bat_priv->mcast.enabled = true; + } + + return true; + } + + /** + * batadv_mcast_mla_update - update the own MLAs + * @bat_priv: the bat priv with all the soft interface information + * + * Update the own multicast listener announcements in the translation + * table as well as the own, announced multicast tvlv container. + */ + void batadv_mcast_mla_update(struct batadv_priv *bat_priv) + { + struct net_device *soft_iface = bat_priv->soft_iface; + struct hlist_head mcast_list = HLIST_HEAD_INIT; + int ret; + + if (!batadv_mcast_mla_tvlv_update(bat_priv)) + goto update; + + ret = batadv_mcast_mla_softif_get(soft_iface, &mcast_list); + if (ret < 0) + goto out; + + update: + batadv_mcast_mla_tt_retract(bat_priv, &mcast_list); + batadv_mcast_mla_tt_add(bat_priv, &mcast_list); + + out: + batadv_mcast_mla_list_free(&mcast_list); + } + + /** + * batadv_mcast_forw_mode_check_ipv4 - check for optimized forwarding potential + * @bat_priv: the bat priv with all the soft interface information + * @skb: the IPv4 packet to check + * @is_unsnoopable: stores whether the destination is snoopable + * + * Check whether the given IPv4 packet has the potential to + * be forwarded with a mode more optimal than classic flooding. + * + * If so then return 0. Otherwise -EINVAL is returned or -ENOMEM if we are + * out of memory. + */ + static int batadv_mcast_forw_mode_check_ipv4(struct batadv_priv *bat_priv, + struct sk_buff *skb, + bool *is_unsnoopable) + { + struct iphdr *iphdr; + + /* We might fail due to out-of-memory -> drop it */ + if (!pskb_may_pull(skb, sizeof(struct ethhdr) + sizeof(*iphdr))) + return -ENOMEM; + + iphdr = ip_hdr(skb); + + /* TODO: Implement Multicast Router Discovery (RFC4286), + * then allow scope > link local, too + */ + if (!ipv4_is_local_multicast(iphdr->daddr)) + return -EINVAL; + + /* link-local multicast listeners behind a bridge are + * not snoopable (see RFC4541, section 2.1.2.2) + */ + *is_unsnoopable = true; + + return 0; + } + + /** + * batadv_mcast_forw_mode_check_ipv6 - check for optimized forwarding potential + * @bat_priv: the bat priv with all the soft interface information + * @skb: the IPv6 packet to check + * @is_unsnoopable: stores whether the destination is snoopable + * + * Check whether the given IPv6 packet has the potential to + * be forwarded with a mode more optimal than classic flooding. + * + * If so then return 0. Otherwise -EINVAL is returned or -ENOMEM if we are + * out of memory. + */ + static int batadv_mcast_forw_mode_check_ipv6(struct batadv_priv *bat_priv, + struct sk_buff *skb, + bool *is_unsnoopable) + { + struct ipv6hdr *ip6hdr; + + /* We might fail due to out-of-memory -> drop it */ + if (!pskb_may_pull(skb, sizeof(struct ethhdr) + sizeof(*ip6hdr))) + return -ENOMEM; + + ip6hdr = ipv6_hdr(skb); + + /* TODO: Implement Multicast Router Discovery (RFC4286), + * then allow scope > link local, too + */ + if (IPV6_ADDR_MC_SCOPE(&ip6hdr->daddr) != + IPV6_ADDR_SCOPE_LINKLOCAL) + return -EINVAL; + + /* link-local-all-nodes multicast listeners behind a bridge are + * not snoopable (see RFC4541, section 3, paragraph 3) + */ + if (ipv6_addr_is_ll_all_nodes(&ip6hdr->daddr)) + *is_unsnoopable = true; + + return 0; + } + + /** + * batadv_mcast_forw_mode_check - check for optimized forwarding potential + * @bat_priv: the bat priv with all the soft interface information + * @skb: the multicast frame to check + * @is_unsnoopable: stores whether the destination is snoopable + * + * Check whether the given multicast ethernet frame has the potential to + * be forwarded with a mode more optimal than classic flooding. + * + * If so then return 0. Otherwise -EINVAL is returned or -ENOMEM if we are + * out of memory. + */ + static int batadv_mcast_forw_mode_check(struct batadv_priv *bat_priv, + struct sk_buff *skb, + bool *is_unsnoopable) + { + struct ethhdr *ethhdr = eth_hdr(skb); + + if (!atomic_read(&bat_priv->multicast_mode)) + return -EINVAL; + + if (atomic_read(&bat_priv->mcast.num_disabled)) + return -EINVAL; + + switch (ntohs(ethhdr->h_proto)) { + case ETH_P_IP: + return batadv_mcast_forw_mode_check_ipv4(bat_priv, skb, + is_unsnoopable); + case ETH_P_IPV6: + return batadv_mcast_forw_mode_check_ipv6(bat_priv, skb, + is_unsnoopable); + default: + return -EINVAL; + } + } + + /** + * batadv_mcast_want_all_ip_count - count nodes with unspecific mcast interest + * @bat_priv: the bat priv with all the soft interface information + * @ethhdr: ethernet header of a packet + * + * Return the number of nodes which want all IPv4 multicast traffic if + * the given ethhdr is from an IPv4 packet or the number of nodes which want + * all IPv6 traffic if it matches an IPv6 packet. + */ + static int batadv_mcast_forw_want_all_ip_count(struct batadv_priv *bat_priv, + struct ethhdr *ethhdr) + { + switch (ntohs(ethhdr->h_proto)) { + case ETH_P_IP: + return atomic_read(&bat_priv->mcast.num_want_all_ipv4); + case ETH_P_IPV6: + return atomic_read(&bat_priv->mcast.num_want_all_ipv6); + default: + /* we shouldn't be here... */ + return 0; + } + } + + /** + * batadv_mcast_forw_tt_node_get - get a multicast tt node + * @bat_priv: the bat priv with all the soft interface information + * @ethhdr: the ether header containing the multicast destination + * + * Return an orig_node matching the multicast address provided by ethhdr + * via a translation table lookup. This increases the returned nodes refcount. + */ + static struct batadv_orig_node * + batadv_mcast_forw_tt_node_get(struct batadv_priv *bat_priv, + struct ethhdr *ethhdr) + { + return batadv_transtable_search(bat_priv, ethhdr->h_source, + ethhdr->h_dest, BATADV_NO_FLAGS); + } + + /** + * batadv_mcast_want_forw_ipv4_node_get - get a node with an ipv4 flag + * @bat_priv: the bat priv with all the soft interface information + * + * Return an orig_node which has the BATADV_MCAST_WANT_ALL_IPV4 flag set + * and increase its refcount. + */ + static struct batadv_orig_node * + batadv_mcast_forw_ipv4_node_get(struct batadv_priv *bat_priv) + { + struct batadv_orig_node *orig_node; + + rcu_read_lock(); + hlist_for_each_entry_rcu(orig_node, + &bat_priv->mcast.want_all_ipv4_list, + mcast_want_all_ipv4_node) { + if (atomic_inc_not_zero(&orig_node->refcount)) + goto unlock; + } + + orig_node = NULL; + + unlock: + rcu_read_unlock(); + return orig_node; + } + + /** + * batadv_mcast_want_forw_ipv6_node_get - get a node with an ipv6 flag + * @bat_priv: the bat priv with all the soft interface information + * + * Return an orig_node which has the BATADV_MCAST_WANT_ALL_IPV6 flag set + * and increase its refcount. + */ + static struct batadv_orig_node * + batadv_mcast_forw_ipv6_node_get(struct batadv_priv *bat_priv) + { + struct batadv_orig_node *orig_node; + + rcu_read_lock(); + hlist_for_each_entry_rcu(orig_node, + &bat_priv->mcast.want_all_ipv6_list, + mcast_want_all_ipv6_node) { + if (atomic_inc_not_zero(&orig_node->refcount)) + goto unlock; + } + + orig_node = NULL; + + unlock: + rcu_read_unlock(); + return orig_node; + } + + /** + * batadv_mcast_want_forw_ip_node_get - get a node with an ipv4/ipv6 flag + * @bat_priv: the bat priv with all the soft interface information + * @ethhdr: an ethernet header to determine the protocol family from + * + * Return an orig_node which has the BATADV_MCAST_WANT_ALL_IPV4 or + * BATADV_MCAST_WANT_ALL_IPV6 flag, depending on the provided ethhdr, set + * and increase its refcount. + */ + static struct batadv_orig_node * + batadv_mcast_forw_ip_node_get(struct batadv_priv *bat_priv, + struct ethhdr *ethhdr) + { + switch (ntohs(ethhdr->h_proto)) { + case ETH_P_IP: + return batadv_mcast_forw_ipv4_node_get(bat_priv); + case ETH_P_IPV6: + return batadv_mcast_forw_ipv6_node_get(bat_priv); + default: + /* we shouldn't be here... */ + return NULL; + } + } + + /** + * batadv_mcast_want_forw_unsnoop_node_get - get a node with an unsnoopable flag + * @bat_priv: the bat priv with all the soft interface information + * + * Return an orig_node which has the BATADV_MCAST_WANT_ALL_UNSNOOPABLES flag set + * and increase its refcount. + */ + static struct batadv_orig_node * + batadv_mcast_forw_unsnoop_node_get(struct batadv_priv *bat_priv) + { + struct batadv_orig_node *orig_node; + + rcu_read_lock(); + hlist_for_each_entry_rcu(orig_node, + &bat_priv->mcast.want_all_unsnoopables_list, + mcast_want_all_unsnoopables_node) { + if (atomic_inc_not_zero(&orig_node->refcount)) + goto unlock; + } + + orig_node = NULL; + + unlock: + rcu_read_unlock(); + return orig_node; + } + + /** + * batadv_mcast_forw_mode - check on how to forward a multicast packet + * @bat_priv: the bat priv with all the soft interface information + * @skb: The multicast packet to check + * @orig: an originator to be set to forward the skb to + * + * Return the forwarding mode as enum batadv_forw_mode and in case of + * BATADV_FORW_SINGLE set the orig to the single originator the skb + * should be forwarded to. + */ + enum batadv_forw_mode + batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb, + struct batadv_orig_node **orig) + { + struct ethhdr *ethhdr; + bool is_unsnoopable = false; + int ret, tt_count, ip_count, unsnoop_count, total_count; + + ret = batadv_mcast_forw_mode_check(bat_priv, skb, &is_unsnoopable); + if (ret == -ENOMEM) + return BATADV_FORW_NONE; + else if (ret < 0) + return BATADV_FORW_ALL; + + ethhdr = eth_hdr(skb); + + tt_count = batadv_tt_global_hash_count(bat_priv, ethhdr->h_dest, + BATADV_NO_FLAGS); + ip_count = batadv_mcast_forw_want_all_ip_count(bat_priv, ethhdr); + unsnoop_count = !is_unsnoopable ? 0 : + atomic_read(&bat_priv->mcast.num_want_all_unsnoopables); + + total_count = tt_count + ip_count + unsnoop_count; + + switch (total_count) { + case 1: + if (tt_count) + *orig = batadv_mcast_forw_tt_node_get(bat_priv, ethhdr); + else if (ip_count) + *orig = batadv_mcast_forw_ip_node_get(bat_priv, ethhdr); + else if (unsnoop_count) + *orig = batadv_mcast_forw_unsnoop_node_get(bat_priv); + + if (*orig) + return BATADV_FORW_SINGLE; + + /* fall through */ + case 0: + return BATADV_FORW_NONE; + default: + return BATADV_FORW_ALL; + } + } + + /** + * batadv_mcast_want_unsnoop_update - update unsnoop counter and list + * @bat_priv: the bat priv with all the soft interface information + * @orig: the orig_node which multicast state might have changed of + * @mcast_flags: flags indicating the new multicast state + * + * If the BATADV_MCAST_WANT_ALL_UNSNOOPABLES flag of this originator, + * orig, has toggled then this method updates counter and list accordingly. + */ + static void batadv_mcast_want_unsnoop_update(struct batadv_priv *bat_priv, + struct batadv_orig_node *orig, + uint8_t mcast_flags) + { + /* switched from flag unset to set */ + if (mcast_flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES && + !(orig->mcast_flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES)) { + atomic_inc(&bat_priv->mcast.num_want_all_unsnoopables); + + spin_lock_bh(&bat_priv->mcast.want_lists_lock); + hlist_add_head_rcu(&orig->mcast_want_all_unsnoopables_node, + &bat_priv->mcast.want_all_unsnoopables_list); + spin_unlock_bh(&bat_priv->mcast.want_lists_lock); + /* switched from flag set to unset */ + } else if (!(mcast_flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES) && + orig->mcast_flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES) { + atomic_dec(&bat_priv->mcast.num_want_all_unsnoopables); + + spin_lock_bh(&bat_priv->mcast.want_lists_lock); + hlist_del_rcu(&orig->mcast_want_all_unsnoopables_node); + spin_unlock_bh(&bat_priv->mcast.want_lists_lock); + } + } + + /** + * batadv_mcast_want_ipv4_update - update want-all-ipv4 counter and list + * @bat_priv: the bat priv with all the soft interface information + * @orig: the orig_node which multicast state might have changed of + * @mcast_flags: flags indicating the new multicast state + * + * If the BATADV_MCAST_WANT_ALL_IPV4 flag of this originator, orig, has + * toggled then this method updates counter and list accordingly. + */ + static void batadv_mcast_want_ipv4_update(struct batadv_priv *bat_priv, + struct batadv_orig_node *orig, + uint8_t mcast_flags) + { + /* switched from flag unset to set */ + if (mcast_flags & BATADV_MCAST_WANT_ALL_IPV4 && + !(orig->mcast_flags & BATADV_MCAST_WANT_ALL_IPV4)) { + atomic_inc(&bat_priv->mcast.num_want_all_ipv4); + + spin_lock_bh(&bat_priv->mcast.want_lists_lock); + hlist_add_head_rcu(&orig->mcast_want_all_ipv4_node, + &bat_priv->mcast.want_all_ipv4_list); + spin_unlock_bh(&bat_priv->mcast.want_lists_lock); + /* switched from flag set to unset */ + } else if (!(mcast_flags & BATADV_MCAST_WANT_ALL_IPV4) && + orig->mcast_flags & BATADV_MCAST_WANT_ALL_IPV4) { + atomic_dec(&bat_priv->mcast.num_want_all_ipv4); + + spin_lock_bh(&bat_priv->mcast.want_lists_lock); + hlist_del_rcu(&orig->mcast_want_all_ipv4_node); + spin_unlock_bh(&bat_priv->mcast.want_lists_lock); + } + } + + /** + * batadv_mcast_want_ipv6_update - update want-all-ipv6 counter and list + * @bat_priv: the bat priv with all the soft interface information + * @orig: the orig_node which multicast state might have changed of + * @mcast_flags: flags indicating the new multicast state + * + * If the BATADV_MCAST_WANT_ALL_IPV6 flag of this originator, orig, has + * toggled then this method updates counter and list accordingly. + */ + static void batadv_mcast_want_ipv6_update(struct batadv_priv *bat_priv, + struct batadv_orig_node *orig, + uint8_t mcast_flags) + { + /* switched from flag unset to set */ + if (mcast_flags & BATADV_MCAST_WANT_ALL_IPV6 && + !(orig->mcast_flags & BATADV_MCAST_WANT_ALL_IPV6)) { + atomic_inc(&bat_priv->mcast.num_want_all_ipv6); + + spin_lock_bh(&bat_priv->mcast.want_lists_lock); + hlist_add_head_rcu(&orig->mcast_want_all_ipv6_node, + &bat_priv->mcast.want_all_ipv6_list); + spin_unlock_bh(&bat_priv->mcast.want_lists_lock); + /* switched from flag set to unset */ + } else if (!(mcast_flags & BATADV_MCAST_WANT_ALL_IPV6) && + orig->mcast_flags & BATADV_MCAST_WANT_ALL_IPV6) { + atomic_dec(&bat_priv->mcast.num_want_all_ipv6); + + spin_lock_bh(&bat_priv->mcast.want_lists_lock); + hlist_del_rcu(&orig->mcast_want_all_ipv6_node); + spin_unlock_bh(&bat_priv->mcast.want_lists_lock); + } + } + + /** + * batadv_mcast_tvlv_ogm_handler_v1 - process incoming multicast tvlv container + * @bat_priv: the bat priv with all the soft interface information + * @orig: the orig_node of the ogm + * @flags: flags indicating the tvlv state (see batadv_tvlv_handler_flags) + * @tvlv_value: tvlv buffer containing the multicast data + * @tvlv_value_len: tvlv buffer length + */ + static void batadv_mcast_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv, + struct batadv_orig_node *orig, + uint8_t flags, + void *tvlv_value, + uint16_t tvlv_value_len) + { + bool orig_mcast_enabled = !(flags & BATADV_TVLV_HANDLER_OGM_CIFNOTFND); + uint8_t mcast_flags = BATADV_NO_FLAGS; + bool orig_initialized; + + orig_initialized = orig->capa_initialized & BATADV_ORIG_CAPA_HAS_MCAST; + + /* If mcast support is turned on decrease the disabled mcast node + * counter only if we had increased it for this node before. If this + * is a completely new orig_node no need to decrease the counter. + */ + if (orig_mcast_enabled && + !(orig->capabilities & BATADV_ORIG_CAPA_HAS_MCAST)) { + if (orig_initialized) + atomic_dec(&bat_priv->mcast.num_disabled); + orig->capabilities |= BATADV_ORIG_CAPA_HAS_MCAST; + /* If mcast support is being switched off increase the disabled + * mcast node counter. + */ + } else if (!orig_mcast_enabled && + orig->capabilities & BATADV_ORIG_CAPA_HAS_MCAST) { + atomic_inc(&bat_priv->mcast.num_disabled); + orig->capabilities &= ~BATADV_ORIG_CAPA_HAS_MCAST; + } + + orig->capa_initialized |= BATADV_ORIG_CAPA_HAS_MCAST; + + if (orig_mcast_enabled && tvlv_value && + (tvlv_value_len >= sizeof(mcast_flags))) + mcast_flags = *(uint8_t *)tvlv_value; + + batadv_mcast_want_unsnoop_update(bat_priv, orig, mcast_flags); + batadv_mcast_want_ipv4_update(bat_priv, orig, mcast_flags); + batadv_mcast_want_ipv6_update(bat_priv, orig, mcast_flags); + + orig->mcast_flags = mcast_flags; + } + + /** + * batadv_mcast_init - initialize the multicast optimizations structures + * @bat_priv: the bat priv with all the soft interface information + */ + void batadv_mcast_init(struct batadv_priv *bat_priv) + { + batadv_tvlv_handler_register(bat_priv, batadv_mcast_tvlv_ogm_handler_v1, + NULL, BATADV_TVLV_MCAST, 1, + BATADV_TVLV_HANDLER_OGM_CIFNOTFND); + } + + /** + * batadv_mcast_free - free the multicast optimizations structures + * @bat_priv: the bat priv with all the soft interface information + */ + void batadv_mcast_free(struct batadv_priv *bat_priv) + { + batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_MCAST, 1); + batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_MCAST, 1); + + batadv_mcast_mla_tt_retract(bat_priv, NULL); + } + + /** + * batadv_mcast_purge_orig - reset originator global mcast state modifications + * @orig: the originator which is going to get purged + */ + void batadv_mcast_purge_orig(struct batadv_orig_node *orig) + { + struct batadv_priv *bat_priv = orig->bat_priv; + + if (!(orig->capabilities & BATADV_ORIG_CAPA_HAS_MCAST)) + atomic_dec(&bat_priv->mcast.num_disabled); + + batadv_mcast_want_unsnoop_update(bat_priv, orig, BATADV_NO_FLAGS); + batadv_mcast_want_ipv4_update(bat_priv, orig, BATADV_NO_FLAGS); + batadv_mcast_want_ipv6_update(bat_priv, orig, BATADV_NO_FLAGS); + } diff --combined net/batman-adv/multicast.h index 0000000,a76bc3a..a76bc3a mode 000000,100644..100644 --- a/net/batman-adv/multicast.h +++ b/net/batman-adv/multicast.h @@@ -1,0 -1,77 +1,77 @@@ + /* Copyright (C) 2014 B.A.T.M.A.N. contributors: + * + * Linus Lüssing + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + + #ifndef _NET_BATMAN_ADV_MULTICAST_H_ + #define _NET_BATMAN_ADV_MULTICAST_H_ + + /** + * batadv_forw_mode - the way a packet should be forwarded as + * @BATADV_FORW_ALL: forward the packet to all nodes + * (currently via classic flooding) + * @BATADV_FORW_SINGLE: forward the packet to a single node + * (currently via the BATMAN unicast routing protocol) + * @BATADV_FORW_NONE: don't forward, drop it + */ + enum batadv_forw_mode { + BATADV_FORW_ALL, + BATADV_FORW_SINGLE, + BATADV_FORW_NONE, + }; + + #ifdef CONFIG_BATMAN_ADV_MCAST + + void batadv_mcast_mla_update(struct batadv_priv *bat_priv); + + enum batadv_forw_mode + batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb, + struct batadv_orig_node **mcast_single_orig); + + void batadv_mcast_init(struct batadv_priv *bat_priv); + + void batadv_mcast_free(struct batadv_priv *bat_priv); + + void batadv_mcast_purge_orig(struct batadv_orig_node *orig_node); + + #else + + static inline void batadv_mcast_mla_update(struct batadv_priv *bat_priv) + { + return; + } + + static inline enum batadv_forw_mode + batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb, + struct batadv_orig_node **mcast_single_orig) + { + return BATADV_FORW_ALL; + } + + static inline int batadv_mcast_init(struct batadv_priv *bat_priv) + { + return 0; + } + + static inline void batadv_mcast_free(struct batadv_priv *bat_priv) + { + return; + } + + static inline void batadv_mcast_purge_orig(struct batadv_orig_node *orig_node) + { + return; + } + + #endif /* CONFIG_BATMAN_ADV_MCAST */ + + #endif /* _NET_BATMAN_ADV_MULTICAST_H_ */ diff --combined net/batman-adv/network-coding.c index f1b604d,a9546fe..a9546fe --- a/net/batman-adv/network-coding.c +++ b/net/batman-adv/network-coding.c @@@ -819,7 -819,7 +819,7 @@@ static struct batadv_nc_nod
/* Initialize nc_node */ INIT_LIST_HEAD(&nc_node->list); - memcpy(nc_node->addr, orig_node->orig, ETH_ALEN); + ether_addr_copy(nc_node->addr, orig_node->orig); nc_node->orig_node = orig_neigh_node; atomic_set(&nc_node->refcount, 2);
@@@ -941,8 -941,8 +941,8 @@@ static struct batadv_nc_path *batadv_nc spin_lock_init(&nc_path->packet_list_lock); atomic_set(&nc_path->refcount, 2); nc_path->last_valid = jiffies; - memcpy(nc_path->next_hop, dst, ETH_ALEN); - memcpy(nc_path->prev_hop, src, ETH_ALEN); + ether_addr_copy(nc_path->next_hop, dst); + ether_addr_copy(nc_path->prev_hop, src);
batadv_dbg(BATADV_DBG_NC, bat_priv, "Adding nc_path %pM -> %pM\n", nc_path->prev_hop, @@@ -1114,15 -1114,15 +1114,15 @@@ static bool batadv_nc_code_packets(stru coded_packet->ttl = packet1->ttl;
/* Info about first unicast packet */ - memcpy(coded_packet->first_source, first_source, ETH_ALEN); - memcpy(coded_packet->first_orig_dest, packet1->dest, ETH_ALEN); + ether_addr_copy(coded_packet->first_source, first_source); + ether_addr_copy(coded_packet->first_orig_dest, packet1->dest); coded_packet->first_crc = packet_id1; coded_packet->first_ttvn = packet1->ttvn;
/* Info about second unicast packet */ - memcpy(coded_packet->second_dest, second_dest, ETH_ALEN); - memcpy(coded_packet->second_source, second_source, ETH_ALEN); - memcpy(coded_packet->second_orig_dest, packet2->dest, ETH_ALEN); + ether_addr_copy(coded_packet->second_dest, second_dest); + ether_addr_copy(coded_packet->second_source, second_source); + ether_addr_copy(coded_packet->second_orig_dest, packet2->dest); coded_packet->second_crc = packet_id2; coded_packet->second_ttl = packet2->ttl; coded_packet->second_ttvn = packet2->ttvn; @@@ -1349,8 -1349,8 +1349,8 @@@ static void batadv_nc_skb_store_before_
/* Set the mac header as if we actually sent the packet uncoded */ ethhdr = eth_hdr(skb); - memcpy(ethhdr->h_source, ethhdr->h_dest, ETH_ALEN); - memcpy(ethhdr->h_dest, eth_dst_new, ETH_ALEN); + ether_addr_copy(ethhdr->h_source, ethhdr->h_dest); + ether_addr_copy(ethhdr->h_dest, eth_dst_new);
/* Set data pointer to MAC header to mimic packets from our tx path */ skb_push(skb, ETH_HLEN); @@@ -1636,7 -1636,7 +1636,7 @@@ batadv_nc_skb_decode_packet(struct bata
/* Reconstruct original mac header */ ethhdr = eth_hdr(skb); - memcpy(ethhdr, ðhdr_tmp, sizeof(*ethhdr)); + *ethhdr = ethhdr_tmp;
/* Select the correct unicast header information based on the location * of our mac address in the coded_packet header @@@ -1646,7 -1646,7 +1646,7 @@@ * so the Ethernet address must be copied to h_dest and * pkt_type changed from PACKET_OTHERHOST to PACKET_HOST */ - memcpy(ethhdr->h_dest, coded_packet_tmp.second_dest, ETH_ALEN); + ether_addr_copy(ethhdr->h_dest, coded_packet_tmp.second_dest); skb->pkt_type = PACKET_HOST;
orig_dest = coded_packet_tmp.second_orig_dest; @@@ -1682,7 -1682,7 +1682,7 @@@ unicast_packet->packet_type = BATADV_UNICAST; unicast_packet->version = BATADV_COMPAT_VERSION; unicast_packet->ttl = ttl; - memcpy(unicast_packet->dest, orig_dest, ETH_ALEN); + ether_addr_copy(unicast_packet->dest, orig_dest); unicast_packet->ttvn = ttvn;
batadv_nc_packet_free(nc_packet); diff --combined net/batman-adv/originator.c index 8539416,ffd9dfb..ffd9dfb --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@@ -27,6 -27,7 +27,7 @@@ #include "bridge_loop_avoidance.h" #include "network-coding.h" #include "fragmentation.h" + #include "multicast.h"
/* hash class keys */ static struct lock_class_key batadv_orig_hash_lock_class_key; @@@ -446,7 -447,7 +447,7 @@@ batadv_neigh_node_new(struct batadv_har INIT_HLIST_HEAD(&neigh_node->ifinfo_list); spin_lock_init(&neigh_node->ifinfo_lock);
- memcpy(neigh_node->addr, neigh_addr, ETH_ALEN); + ether_addr_copy(neigh_node->addr, neigh_addr); neigh_node->if_incoming = hard_iface; neigh_node->orig_node = orig_node;
@@@ -557,6 -558,8 +558,8 @@@ static void batadv_orig_node_free_rcu(s } spin_unlock_bh(&orig_node->neigh_list_lock);
+ batadv_mcast_purge_orig(orig_node); + /* Free nc_nodes */ batadv_nc_purge_orig(orig_node->bat_priv, orig_node, NULL);
@@@ -664,15 -667,17 +667,17 @@@ struct batadv_orig_node *batadv_orig_no /* extra reference for return */ atomic_set(&orig_node->refcount, 2);
- orig_node->tt_initialised = false; orig_node->bat_priv = bat_priv; - memcpy(orig_node->orig, addr, ETH_ALEN); + ether_addr_copy(orig_node->orig, addr); batadv_dat_init_orig_node_addr(orig_node); atomic_set(&orig_node->last_ttvn, 0); orig_node->tt_buff = NULL; orig_node->tt_buff_len = 0; reset_time = jiffies - 1 - msecs_to_jiffies(BATADV_RESET_PROTECTION_MS); orig_node->bcast_seqno_reset = reset_time; + #ifdef CONFIG_BATMAN_ADV_MCAST + orig_node->mcast_flags = BATADV_NO_FLAGS; + #endif
/* create a vlan object for the "untagged" LAN */ vlan = batadv_orig_node_vlan_new(orig_node, BATADV_NO_FLAGS); diff --combined net/batman-adv/packet.h index 0a381d1,feaa336..feaa336 --- a/net/batman-adv/packet.h +++ b/net/batman-adv/packet.h @@@ -89,6 -89,19 +89,19 @@@ enum batadv_icmp_packettype BATADV_PARAMETER_PROBLEM = 12, };
+ /** + * enum batadv_mcast_flags - flags for multicast capabilities and settings + * @BATADV_MCAST_WANT_ALL_UNSNOOPABLES: we want all packets destined for + * 224.0.0.0/24 or ff02::1 + * @BATADV_MCAST_WANT_ALL_IPV4: we want all IPv4 multicast packets + * @BATADV_MCAST_WANT_ALL_IPV6: we want all IPv6 multicast packets + */ + enum batadv_mcast_flags { + BATADV_MCAST_WANT_ALL_UNSNOOPABLES = BIT(0), + BATADV_MCAST_WANT_ALL_IPV4 = BIT(1), + BATADV_MCAST_WANT_ALL_IPV6 = BIT(2), + }; + /* tt data subtypes */ #define BATADV_TT_DATA_TYPE_MASK 0x0F
@@@ -145,6 -158,7 +158,7 @@@ enum batadv_bla_claimframe * @BATADV_TVLV_NC: network coding tvlv * @BATADV_TVLV_TT: translation table tvlv * @BATADV_TVLV_ROAM: roaming advertisement tvlv + * @BATADV_TVLV_MCAST: multicast capability tvlv */ enum batadv_tvlv_type { BATADV_TVLV_GW = 0x01, @@@ -152,6 -166,7 +166,7 @@@ BATADV_TVLV_NC = 0x03, BATADV_TVLV_TT = 0x04, BATADV_TVLV_ROAM = 0x05, + BATADV_TVLV_MCAST = 0x06, };
#pragma pack(2) @@@ -504,4 -519,14 +519,14 @@@ struct batadv_tvlv_roam_adv __be16 vid; };
+ /** + * struct batadv_tvlv_mcast_data - payload of a multicast tvlv + * @flags: multicast flags announced by the orig node + * @reserved: reserved field + */ + struct batadv_tvlv_mcast_data { + uint8_t flags; + uint8_t reserved[3]; + }; + #endif /* _NET_BATMAN_ADV_PACKET_H_ */ diff --combined net/batman-adv/routing.c index a953d5b,3855132..3855132 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c @@@ -222,8 -222,8 +222,8 @@@ static int batadv_recv_my_icmp_packet(s
icmph = (struct batadv_icmp_header *)skb->data;
- memcpy(icmph->dst, icmph->orig, ETH_ALEN); - memcpy(icmph->orig, primary_if->net_dev->dev_addr, ETH_ALEN); + ether_addr_copy(icmph->dst, icmph->orig); + ether_addr_copy(icmph->orig, primary_if->net_dev->dev_addr); icmph->msg_type = BATADV_ECHO_REPLY; icmph->ttl = BATADV_TTL;
@@@ -276,9 -276,8 +276,8 @@@ static int batadv_recv_icmp_ttl_exceede
icmp_packet = (struct batadv_icmp_packet *)skb->data;
- memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN); - memcpy(icmp_packet->orig, primary_if->net_dev->dev_addr, - ETH_ALEN); + ether_addr_copy(icmp_packet->dst, icmp_packet->orig); + ether_addr_copy(icmp_packet->orig, primary_if->net_dev->dev_addr); icmp_packet->msg_type = BATADV_TTL_EXCEEDED; icmp_packet->ttl = BATADV_TTL;
@@@ -341,8 -340,8 +340,8 @@@ int batadv_recv_icmp_packet(struct sk_b if (icmp_packet_rr->rr_cur >= BATADV_RR_LEN) goto out;
- memcpy(&(icmp_packet_rr->rr[icmp_packet_rr->rr_cur]), - ethhdr->h_dest, ETH_ALEN); + ether_addr_copy(&(icmp_packet_rr->rr[icmp_packet_rr->rr_cur]), + ethhdr->h_dest); icmp_packet_rr->rr_cur++; }
@@@ -664,7 -663,7 +663,7 @@@ batadv_reroute_unicast_packet(struct ba }
/* update the packet header */ - memcpy(unicast_packet->dest, orig_addr, ETH_ALEN); + ether_addr_copy(unicast_packet->dest, orig_addr); unicast_packet->ttvn = orig_ttvn;
ret = true; @@@ -774,7 -773,7 +773,7 @@@ static int batadv_check_unicast_ttvn(st if (!primary_if) return 0;
- memcpy(unicast_packet->dest, primary_if->net_dev->dev_addr, ETH_ALEN); + ether_addr_copy(unicast_packet->dest, primary_if->net_dev->dev_addr);
batadv_hardif_free_ref(primary_if);
diff --combined net/batman-adv/send.c index 1703a2e,d27161e..d27161e --- a/net/batman-adv/send.c +++ b/net/batman-adv/send.c @@@ -27,6 -27,7 +27,7 @@@ #include "originator.h" #include "network-coding.h" #include "fragmentation.h" + #include "multicast.h"
static void batadv_send_outstanding_bcast_packet(struct work_struct *work);
@@@ -59,8 -60,8 +60,8 @@@ int batadv_send_skb_packet(struct sk_bu skb_reset_mac_header(skb);
ethhdr = eth_hdr(skb); - memcpy(ethhdr->h_source, hard_iface->net_dev->dev_addr, ETH_ALEN); - memcpy(ethhdr->h_dest, dst_addr, ETH_ALEN); + ether_addr_copy(ethhdr->h_source, hard_iface->net_dev->dev_addr); + ether_addr_copy(ethhdr->h_dest, dst_addr); ethhdr->h_proto = htons(ETH_P_BATMAN);
skb_set_network_header(skb, ETH_HLEN); @@@ -165,7 -166,7 +166,7 @@@ batadv_send_skb_push_fill_unicast(struc /* set unicast ttl */ unicast_packet->ttl = BATADV_TTL; /* copy the destination for faster routing */ - memcpy(unicast_packet->dest, orig_node->orig, ETH_ALEN); + ether_addr_copy(unicast_packet->dest, orig_node->orig); /* set the destination tt version number */ unicast_packet->ttvn = ttvn;
@@@ -220,7 -221,7 +221,7 @@@ bool batadv_send_skb_prepare_unicast_4a
uc_4addr_packet = (struct batadv_unicast_4addr_packet *)skb->data; uc_4addr_packet->u.packet_type = BATADV_UNICAST_4ADDR; - memcpy(uc_4addr_packet->src, primary_if->net_dev->dev_addr, ETH_ALEN); + ether_addr_copy(uc_4addr_packet->src, primary_if->net_dev->dev_addr); uc_4addr_packet->subtype = packet_subtype; uc_4addr_packet->reserved = 0;
@@@ -248,14 -249,14 +249,14 @@@ out * * Returns NET_XMIT_DROP in case of error or NET_XMIT_SUCCESS otherwise. */ - static int batadv_send_skb_unicast(struct batadv_priv *bat_priv, - struct sk_buff *skb, int packet_type, - int packet_subtype, - struct batadv_orig_node *orig_node, - unsigned short vid) + int batadv_send_skb_unicast(struct batadv_priv *bat_priv, + struct sk_buff *skb, int packet_type, + int packet_subtype, + struct batadv_orig_node *orig_node, + unsigned short vid) { - struct ethhdr *ethhdr; struct batadv_unicast_packet *unicast_packet; + struct ethhdr *ethhdr; int ret = NET_XMIT_DROP;
if (!orig_node) @@@ -311,6 -312,7 +312,7 @@@ out * @packet_type: the batman unicast packet type to use * @packet_subtype: the unicast 4addr packet subtype (only relevant for unicast * 4addr packets) + * @dst_hint: can be used to override the destination contained in the skb * @vid: the vid to be used to search the translation table * * Look up the recipient node for the destination address in the ethernet diff --combined net/batman-adv/send.h index aaddaa9,38d0ec1..38d0ec1 --- a/net/batman-adv/send.h +++ b/net/batman-adv/send.h @@@ -36,6 -36,11 +36,11 @@@ bool batadv_send_skb_prepare_unicast_4a struct sk_buff *skb, struct batadv_orig_node *orig_node, int packet_subtype); + int batadv_send_skb_unicast(struct batadv_priv *bat_priv, + struct sk_buff *skb, int packet_type, + int packet_subtype, + struct batadv_orig_node *orig_node, + unsigned short vid); int batadv_send_skb_via_tt_generic(struct batadv_priv *bat_priv, struct sk_buff *skb, int packet_type, int packet_subtype, uint8_t *dst_hint, @@@ -47,6 -52,7 +52,7 @@@ int batadv_send_skb_via_gw(struct batad * batadv_send_skb_via_tt - send an skb via TT lookup * @bat_priv: the bat priv with all the soft interface information * @skb: the payload to send + * @dst_hint: can be used to override the destination contained in the skb * @vid: the vid to be used to search the translation table * * Look up the recipient node for the destination address in the ethernet @@@ -68,6 -74,7 +74,7 @@@ static inline int batadv_send_skb_via_t * @bat_priv: the bat priv with all the soft interface information * @skb: the payload to send * @packet_subtype: the unicast 4addr packet subtype to use + * @dst_hint: can be used to override the destination contained in the skb * @vid: the vid to be used to search the translation table * * Look up the recipient node for the destination address in the ethernet diff --combined net/batman-adv/soft-interface.c index f82c267,744a59b..744a59b --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c @@@ -32,6 -32,7 +32,7 @@@ #include <linux/ethtool.h> #include <linux/etherdevice.h> #include <linux/if_vlan.h> + #include "multicast.h" #include "bridge_loop_avoidance.h" #include "network-coding.h"
@@@ -111,8 -112,8 +112,8 @@@ static int batadv_interface_set_mac_add if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL;
- memcpy(old_addr, dev->dev_addr, ETH_ALEN); - memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); + ether_addr_copy(old_addr, dev->dev_addr); + ether_addr_copy(dev->dev_addr, addr->sa_data);
/* only modify transtable if it has been initialized before */ if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_ACTIVE) { @@@ -170,17 -171,19 +171,19 @@@ static int batadv_interface_tx(struct s unsigned short vid; uint32_t seqno; int gw_mode; + enum batadv_forw_mode forw_mode; + struct batadv_orig_node *mcast_single_orig = NULL;
if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE) goto dropped;
soft_iface->trans_start = jiffies; vid = batadv_get_vid(skb, 0); - ethhdr = (struct ethhdr *)skb->data; + ethhdr = eth_hdr(skb);
switch (ntohs(ethhdr->h_proto)) { case ETH_P_8021Q: - vhdr = (struct vlan_ethhdr *)skb->data; + vhdr = vlan_eth_hdr(skb);
if (vhdr->h_vlan_encapsulated_proto != ethertype) break; @@@ -194,7 -197,7 +197,7 @@@ goto dropped;
/* skb->data might have been reallocated by batadv_bla_tx() */ - ethhdr = (struct ethhdr *)skb->data; + ethhdr = eth_hdr(skb);
/* Register the client MAC in the transtable */ if (!is_multicast_ether_addr(ethhdr->h_source)) { @@@ -230,7 -233,7 +233,7 @@@ /* skb->data may have been modified by * batadv_gw_dhcp_recipient_get() */ - ethhdr = (struct ethhdr *)skb->data; + ethhdr = eth_hdr(skb); /* if gw_mode is on, broadcast any non-DHCP message. * All the DHCP packets are going to be sent as unicast */ @@@ -247,9 -250,19 +250,19 @@@ * directed to a DHCP server */ goto dropped; - }
send: + if (do_bcast && !is_broadcast_ether_addr(ethhdr->h_dest)) { + forw_mode = batadv_mcast_forw_mode(bat_priv, skb, + &mcast_single_orig); + if (forw_mode == BATADV_FORW_NONE) + goto dropped; + + if (forw_mode == BATADV_FORW_SINGLE) + do_bcast = false; + } + } + batadv_skb_set_priority(skb, 0);
/* ethernet packet should be broadcasted */ @@@ -279,8 -292,8 +292,8 @@@ /* hw address of first interface is the orig mac because only * this mac is known throughout the mesh */ - memcpy(bcast_packet->orig, - primary_if->net_dev->dev_addr, ETH_ALEN); + ether_addr_copy(bcast_packet->orig, + primary_if->net_dev->dev_addr);
/* set broadcast sequence number */ seqno = atomic_inc_return(&bat_priv->bcast_seqno); @@@ -301,6 -314,10 +314,10 @@@ if (ret) goto dropped; ret = batadv_send_skb_via_gw(bat_priv, skb, vid); + } else if (mcast_single_orig) { + ret = batadv_send_skb_unicast(bat_priv, skb, + BATADV_UNICAST, 0, + mcast_single_orig, vid); } else { if (batadv_dat_snoop_outgoing_arp_request(bat_priv, skb)) @@@ -652,10 -669,7 +669,7 @@@ static void batadv_softif_destroy_finis }
batadv_sysfs_del_meshif(soft_iface); - - rtnl_lock(); - unregister_netdevice(soft_iface); - rtnl_unlock(); + unregister_netdev(soft_iface); }
/** @@@ -692,6 -706,14 +706,14 @@@ static int batadv_softif_init_late(stru #ifdef CONFIG_BATMAN_ADV_DAT atomic_set(&bat_priv->distributed_arp_table, 1); #endif + #ifdef CONFIG_BATMAN_ADV_MCAST + bat_priv->mcast.flags = BATADV_NO_FLAGS; + atomic_set(&bat_priv->multicast_mode, 1); + atomic_set(&bat_priv->mcast.num_disabled, 0); + atomic_set(&bat_priv->mcast.num_want_all_unsnoopables, 0); + atomic_set(&bat_priv->mcast.num_want_all_ipv4, 0); + atomic_set(&bat_priv->mcast.num_want_all_ipv6, 0); + #endif atomic_set(&bat_priv->gw_mode, BATADV_GW_MODE_OFF); atomic_set(&bat_priv->gw_sel_class, 20); atomic_set(&bat_priv->gw.bandwidth_down, 100); diff --combined net/batman-adv/sysfs.c index e456bf6,1ebb0d9..1ebb0d9 --- a/net/batman-adv/sysfs.c +++ b/net/batman-adv/sysfs.c @@@ -539,6 -539,9 +539,9 @@@ BATADV_ATTR_SIF_UINT(gw_sel_class, S_IR batadv_post_gw_reselect); static BATADV_ATTR(gw_bandwidth, S_IRUGO | S_IWUSR, batadv_show_gw_bwidth, batadv_store_gw_bwidth); + #ifdef CONFIG_BATMAN_ADV_MCAST + BATADV_ATTR_SIF_BOOL(multicast_mode, S_IRUGO | S_IWUSR, NULL); + #endif #ifdef CONFIG_BATMAN_ADV_DEBUG BATADV_ATTR_SIF_UINT(log_level, S_IRUGO | S_IWUSR, 0, BATADV_DBG_ALL, NULL); #endif @@@ -558,6 -561,9 +561,9 @@@ static struct batadv_attribute *batadv_ #ifdef CONFIG_BATMAN_ADV_DAT &batadv_attr_distributed_arp_table, #endif + #ifdef CONFIG_BATMAN_ADV_MCAST + &batadv_attr_multicast_mode, + #endif &batadv_attr_fragmentation, &batadv_attr_routing_algo, &batadv_attr_gw_mode, diff --combined net/batman-adv/translation-table.c index 959dde7,dab5c39..dab5c39 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@@ -24,6 -24,7 +24,7 @@@ #include "originator.h" #include "routing.h" #include "bridge_loop_avoidance.h" + #include "multicast.h"
#include <linux/crc32c.h>
@@@ -96,7 -97,7 +97,7 @@@ batadv_tt_hash_find(struct batadv_hasht if (!hash) return NULL;
- memcpy(to_search.addr, addr, ETH_ALEN); + ether_addr_copy(to_search.addr, addr); to_search.vid = vid;
index = batadv_choose_tt(&to_search, hash->size); @@@ -192,6 -193,32 +193,32 @@@ batadv_tt_global_entry_free_ref(struct } }
+ /** + * batadv_tt_global_hash_count - count the number of orig entries + * @hash: hash table containing the tt entries + * @addr: the mac address of the client to count entries for + * @vid: VLAN identifier + * + * Return the number of originators advertising the given address/data + * (excluding ourself). + */ + int batadv_tt_global_hash_count(struct batadv_priv *bat_priv, + const uint8_t *addr, unsigned short vid) + { + struct batadv_tt_global_entry *tt_global_entry; + int count = 0; + + tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid); + if (!tt_global_entry) + goto out; + + count = atomic_read(&tt_global_entry->orig_list_count); + batadv_tt_global_entry_free_ref(tt_global_entry); + + out: + return count; + } + static void batadv_tt_orig_list_entry_free_rcu(struct rcu_head *rcu) { struct batadv_tt_orig_list_entry *orig_entry; @@@ -333,7 -360,7 +360,7 @@@ static void batadv_tt_local_event(struc tt_change_node->change.flags = flags; memset(tt_change_node->change.reserved, 0, sizeof(tt_change_node->change.reserved)); - memcpy(tt_change_node->change.addr, common->addr, ETH_ALEN); + ether_addr_copy(tt_change_node->change.addr, common->addr); tt_change_node->change.vid = htons(common->vid);
del_op_requested = flags & BATADV_TT_CLIENT_DEL; @@@ -484,7 -511,7 +511,7 @@@ bool batadv_tt_local_add(struct net_dev { struct batadv_priv *bat_priv = netdev_priv(soft_iface); struct batadv_tt_local_entry *tt_local; - struct batadv_tt_global_entry *tt_global; + struct batadv_tt_global_entry *tt_global = NULL; struct net_device *in_dev = NULL; struct hlist_head *head; struct batadv_tt_orig_list_entry *orig_entry; @@@ -497,7 -524,9 +524,9 @@@ in_dev = dev_get_by_index(&init_net, ifindex);
tt_local = batadv_tt_local_hash_find(bat_priv, addr, vid); - tt_global = batadv_tt_global_hash_find(bat_priv, addr, vid); + + if (!is_multicast_ether_addr(addr)) + tt_global = batadv_tt_global_hash_find(bat_priv, addr, vid);
if (tt_local) { tt_local->last_seen = jiffies; @@@ -549,7 -578,7 +578,7 @@@ addr, BATADV_PRINT_VID(vid), (uint8_t)atomic_read(&bat_priv->tt.vn));
- memcpy(tt_local->common.addr, addr, ETH_ALEN); + ether_addr_copy(tt_local->common.addr, addr); /* The local entry has to be marked as NEW to avoid to send it in * a full table response going out before the next ttvn increment * (consistency check) @@@ -562,8 -591,11 +591,11 @@@ tt_local->last_seen = jiffies; tt_local->common.added_at = tt_local->last_seen;
- /* the batman interface mac address should never be purged */ - if (batadv_compare_eth(addr, soft_iface->dev_addr)) + /* the batman interface mac and multicast addresses should never be + * purged + */ + if (batadv_compare_eth(addr, soft_iface->dev_addr) || + is_multicast_ether_addr(addr)) tt_local->common.flags |= BATADV_TT_CLIENT_NOPURGE;
hash_added = batadv_hash_add(bat_priv->tt.local_hash, batadv_compare_tt, @@@ -1219,6 -1251,8 +1251,8 @@@ batadv_tt_global_orig_entry_add(struct hlist_add_head_rcu(&orig_entry->list, &tt_global->orig_list); spin_unlock_bh(&tt_global->list_lock); + atomic_inc(&tt_global->orig_list_count); + out: if (orig_entry) batadv_tt_orig_list_entry_free_ref(orig_entry); @@@ -1277,7 -1311,7 +1311,7 @@@ static bool batadv_tt_global_add(struc goto out;
common = &tt_global_entry->common; - memcpy(common->addr, tt_addr, ETH_ALEN); + ether_addr_copy(common->addr, tt_addr); common->vid = vid;
common->flags = flags; @@@ -1292,6 -1326,7 +1326,7 @@@ common->added_at = jiffies;
INIT_HLIST_HEAD(&tt_global_entry->orig_list); + atomic_set(&tt_global_entry->orig_list_count, 0); spin_lock_init(&tt_global_entry->list_lock);
hash_added = batadv_hash_add(bat_priv->tt.global_hash, @@@ -1361,6 -1396,11 +1396,11 @@@ add_orig_entry ret = true;
out_remove: + /* Do not remove multicast addresses from the local hash on + * global additions + */ + if (is_multicast_ether_addr(tt_addr)) + goto out;
/* remove address from local hash if present */ local_flags = batadv_tt_local_remove(bat_priv, tt_addr, vid, @@@ -1552,6 -1592,25 +1592,25 @@@ out return 0; }
+ /** + * batadv_tt_global_del_orig_entry - remove and free an orig_entry + * @tt_global_entry: the global entry to remove the orig_entry from + * @orig_entry: the orig entry to remove and free + * + * Remove an orig_entry from its list in the given tt_global_entry and + * free this orig_entry afterwards. + */ + static void + batadv_tt_global_del_orig_entry(struct batadv_tt_global_entry *tt_global_entry, + struct batadv_tt_orig_list_entry *orig_entry) + { + batadv_tt_global_size_dec(orig_entry->orig_node, + tt_global_entry->common.vid); + atomic_dec(&tt_global_entry->orig_list_count); + hlist_del_rcu(&orig_entry->list); + batadv_tt_orig_list_entry_free_ref(orig_entry); + } + /* deletes the orig list of a tt_global_entry */ static void batadv_tt_global_del_orig_list(struct batadv_tt_global_entry *tt_global_entry) @@@ -1562,20 -1621,26 +1621,26 @@@
spin_lock_bh(&tt_global_entry->list_lock); head = &tt_global_entry->orig_list; - hlist_for_each_entry_safe(orig_entry, safe, head, list) { - hlist_del_rcu(&orig_entry->list); - batadv_tt_global_size_dec(orig_entry->orig_node, - tt_global_entry->common.vid); - batadv_tt_orig_list_entry_free_ref(orig_entry); - } + hlist_for_each_entry_safe(orig_entry, safe, head, list) + batadv_tt_global_del_orig_entry(tt_global_entry, orig_entry); spin_unlock_bh(&tt_global_entry->list_lock); }
+ /** + * batadv_tt_global_del_orig_node - remove orig_node from a global tt entry + * @bat_priv: the bat priv with all the soft interface information + * @tt_global_entry: the global entry to remove the orig_node from + * @orig_node: the originator announcing the client + * @message: message to append to the log on deletion + * + * Remove the given orig_node and its according orig_entry from the given + * global tt entry. + */ static void - batadv_tt_global_del_orig_entry(struct batadv_priv *bat_priv, - struct batadv_tt_global_entry *tt_global_entry, - struct batadv_orig_node *orig_node, - const char *message) + batadv_tt_global_del_orig_node(struct batadv_priv *bat_priv, + struct batadv_tt_global_entry *tt_global_entry, + struct batadv_orig_node *orig_node, + const char *message) { struct hlist_head *head; struct hlist_node *safe; @@@ -1592,10 -1657,8 +1657,8 @@@ orig_node->orig, tt_global_entry->common.addr, BATADV_PRINT_VID(vid), message); - hlist_del_rcu(&orig_entry->list); - batadv_tt_global_size_dec(orig_node, - tt_global_entry->common.vid); - batadv_tt_orig_list_entry_free_ref(orig_entry); + batadv_tt_global_del_orig_entry(tt_global_entry, + orig_entry); } } spin_unlock_bh(&tt_global_entry->list_lock); @@@ -1637,8 -1700,8 +1700,8 @@@ batadv_tt_global_del_roaming(struct bat /* there is another entry, we can simply delete this * one and can still use the other one. */ - batadv_tt_global_del_orig_entry(bat_priv, tt_global_entry, - orig_node, message); + batadv_tt_global_del_orig_node(bat_priv, tt_global_entry, + orig_node, message); }
/** @@@ -1664,8 -1727,8 +1727,8 @@@ static void batadv_tt_global_del(struc goto out;
if (!roaming) { - batadv_tt_global_del_orig_entry(bat_priv, tt_global_entry, - orig_node, message); + batadv_tt_global_del_orig_node(bat_priv, tt_global_entry, + orig_node, message);
if (hlist_empty(&tt_global_entry->orig_list)) batadv_tt_global_free(bat_priv, tt_global_entry, @@@ -1748,8 -1811,8 +1811,8 @@@ void batadv_tt_global_del_orig(struct b struct batadv_tt_global_entry, common);
- batadv_tt_global_del_orig_entry(bat_priv, tt_global, - orig_node, message); + batadv_tt_global_del_orig_node(bat_priv, tt_global, + orig_node, message);
if (hlist_empty(&tt_global->orig_list)) { vid = tt_global->common.vid; @@@ -1763,7 -1826,7 +1826,7 @@@ } spin_unlock_bh(list_lock); } - orig_node->tt_initialised = false; + orig_node->capa_initialized &= ~BATADV_ORIG_CAPA_HAS_TT; }
static bool batadv_tt_global_to_purge(struct batadv_tt_global_entry *tt_global, @@@ -2160,7 -2223,7 +2223,7 @@@ batadv_new_tt_req_node(struct batadv_pr if (!tt_req_node) goto unlock;
- memcpy(tt_req_node->addr, orig_node->orig, ETH_ALEN); + ether_addr_copy(tt_req_node->addr, orig_node->orig); tt_req_node->issued_at = jiffies;
list_add(&tt_req_node->list, &bat_priv->tt.req_list); @@@ -2240,8 -2303,7 +2303,7 @@@ static void batadv_tt_tvlv_generate(str if ((valid_cb) && (!valid_cb(tt_common_entry, cb_data))) continue;
- memcpy(tt_change->addr, tt_common_entry->addr, - ETH_ALEN); + ether_addr_copy(tt_change->addr, tt_common_entry->addr); tt_change->flags = tt_common_entry->flags; tt_change->vid = htons(tt_common_entry->vid); memset(tt_change->reserved, 0, @@@ -2724,7 -2786,7 +2786,7 @@@ static void _batadv_tt_update_changes(s return; } } - orig_node->tt_initialised = true; + orig_node->capa_initialized |= BATADV_ORIG_CAPA_HAS_TT; }
static void batadv_tt_fill_gtable(struct batadv_priv *bat_priv, @@@ -2932,7 -2994,7 +2994,7 @@@ static bool batadv_tt_check_roam_count( tt_roam_node->first_time = jiffies; atomic_set(&tt_roam_node->counter, BATADV_ROAMING_MAX_COUNT - 1); - memcpy(tt_roam_node->addr, client, ETH_ALEN); + ether_addr_copy(tt_roam_node->addr, client);
list_add(&tt_roam_node->list, &bat_priv->tt.roam_list); ret = true; @@@ -3121,6 -3183,9 +3183,9 @@@ static void batadv_tt_local_purge_pendi */ static void batadv_tt_local_commit_changes_nolock(struct batadv_priv *bat_priv) { + /* Update multicast addresses in local translation table */ + batadv_mcast_mla_update(bat_priv); + if (atomic_read(&bat_priv->tt.local_changes) < 1) { if (!batadv_atomic_dec_not_zero(&bat_priv->tt.ogm_append_cnt)) batadv_tt_tvlv_container_update(bat_priv); @@@ -3211,13 -3276,15 +3276,15 @@@ static void batadv_tt_update_orig(struc uint8_t orig_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn); struct batadv_tvlv_tt_vlan_data *tt_vlan; bool full_table = true; + bool has_tt_init;
tt_vlan = (struct batadv_tvlv_tt_vlan_data *)tt_buff; + has_tt_init = orig_node->capa_initialized & BATADV_ORIG_CAPA_HAS_TT; + /* orig table not initialised AND first diff is in the OGM OR the ttvn * increased by one -> we can apply the attached changes */ - if ((!orig_node->tt_initialised && ttvn == 1) || - ttvn - orig_ttvn == 1) { + if ((!has_tt_init && ttvn == 1) || ttvn - orig_ttvn == 1) { /* the OGM could not contain the changes due to their size or * because they have already been sent BATADV_TT_OGM_APPEND_MAX * times. @@@ -3257,7 -3324,7 +3324,7 @@@ /* if we missed more than one change or our tables are not * in sync anymore -> request fresh tt data */ - if (!orig_node->tt_initialised || ttvn != orig_ttvn || + if (!has_tt_init || ttvn != orig_ttvn || !batadv_tt_global_check_crc(orig_node, tt_vlan, tt_num_vlan)) { request_table: diff --combined net/batman-adv/translation-table.h index 20a1d78,ad84d7b..ad84d7b --- a/net/batman-adv/translation-table.h +++ b/net/batman-adv/translation-table.h @@@ -29,6 -29,8 +29,8 @@@ int batadv_tt_global_seq_print_text(str void batadv_tt_global_del_orig(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node, int32_t match_vid, const char *message); + int batadv_tt_global_hash_count(struct batadv_priv *bat_priv, + const uint8_t *addr, unsigned short vid); struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv, const uint8_t *src, const uint8_t *addr, diff --combined net/batman-adv/types.h index 78370ab,d4b923c..d4b923c --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@@ -163,7 -163,7 +163,7 @@@ struct batadv_vlan_tt };
/** - * batadv_orig_node_vlan - VLAN specific data per orig_node + * struct batadv_orig_node_vlan - VLAN specific data per orig_node * @vid: the VLAN identifier * @tt: VLAN specific TT attributes * @list: list node for orig_node::vlan_list @@@ -204,14 -204,18 +204,18 @@@ struct batadv_orig_bat_iv * @batadv_dat_addr_t: address of the orig node in the distributed hash * @last_seen: time when last packet from this node was received * @bcast_seqno_reset: time when the broadcast seqno window was reset + * @mcast_flags: multicast flags announced by the orig node + * @mcast_want_all_unsnoop_node: a list node for the + * mcast.want_all_unsnoopables list + * @mcast_want_all_ipv4_node: a list node for the mcast.want_all_ipv4 list + * @mcast_want_all_ipv6_node: a list node for the mcast.want_all_ipv6 list * @capabilities: announced capabilities of this originator + * @capa_initialized: bitfield to remember whether a capability was initialized * @last_ttvn: last seen translation table version number * @tt_buff: last tt changeset this node received from the orig node * @tt_buff_len: length of the last tt changeset this node received from the * orig node * @tt_buff_lock: lock that protects tt_buff and tt_buff_len - * @tt_initialised: bool keeping track of whether or not this node have received - * any translation table information from the orig node yet * @tt_lock: prevents from updating the table while reading it. Table update is * made up by two operations (data structure update and metdata -CRC/TTVN- * recalculation) and they have to be executed atomically in order to avoid @@@ -247,12 -251,18 +251,18 @@@ struct batadv_orig_node #endif unsigned long last_seen; unsigned long bcast_seqno_reset; + #ifdef CONFIG_BATMAN_ADV_MCAST + uint8_t mcast_flags; + struct hlist_node mcast_want_all_unsnoopables_node; + struct hlist_node mcast_want_all_ipv4_node; + struct hlist_node mcast_want_all_ipv6_node; + #endif uint8_t capabilities; + uint8_t capa_initialized; atomic_t last_ttvn; unsigned char *tt_buff; int16_t tt_buff_len; spinlock_t tt_buff_lock; /* protects tt_buff & tt_buff_len */ - bool tt_initialised; /* prevents from changing the table while reading it */ spinlock_t tt_lock; DECLARE_BITMAP(bcast_bits, BATADV_TQ_LOCAL_WINDOW_SIZE); @@@ -282,10 -292,15 +292,15 @@@ * enum batadv_orig_capabilities - orig node capabilities * @BATADV_ORIG_CAPA_HAS_DAT: orig node has distributed arp table enabled * @BATADV_ORIG_CAPA_HAS_NC: orig node has network coding enabled + * @BATADV_ORIG_CAPA_HAS_TT: orig node has tt capability + * @BATADV_ORIG_CAPA_HAS_MCAST: orig node has some multicast capability + * (= orig node announces a tvlv of type BATADV_TVLV_MCAST) */ enum batadv_orig_capabilities { BATADV_ORIG_CAPA_HAS_DAT = BIT(0), BATADV_ORIG_CAPA_HAS_NC = BIT(1), + BATADV_ORIG_CAPA_HAS_TT = BIT(2), + BATADV_ORIG_CAPA_HAS_MCAST = BIT(3), };
/** @@@ -334,7 -349,7 +349,7 @@@ struct batadv_neigh_node };
/** - * struct batadv_neigh_node_bat_iv - neighbor information per outgoing + * struct batadv_neigh_ifinfo_bat_iv - neighbor information per outgoing * interface for BATMAN IV * @tq_recv: ring buffer of received TQ values from this neigh node * @tq_index: ring buffer index @@@ -544,7 -559,7 +559,7 @@@ struct batadv_priv_bla #endif
/** - * struct batadv_debug_log - debug logging data + * struct batadv_priv_debug_log - debug logging data * @log_buff: buffer holding the logs (ring bufer) * @log_start: index of next character to read * @log_end: index of next character to write @@@ -607,6 -622,39 +622,39 @@@ struct batadv_priv_dat }; #endif
+ #ifdef CONFIG_BATMAN_ADV_MCAST + /** + * struct batadv_priv_mcast - per mesh interface mcast data + * @mla_list: list of multicast addresses we are currently announcing via TT + * @want_all_unsnoopables_list: a list of orig_nodes wanting all unsnoopable + * multicast traffic + * @want_all_ipv4_list: a list of orig_nodes wanting all IPv4 multicast traffic + * @want_all_ipv6_list: a list of orig_nodes wanting all IPv6 multicast traffic + * @flags: the flags we have last sent in our mcast tvlv + * @enabled: whether the multicast tvlv is currently enabled + * @num_disabled: number of nodes that have no mcast tvlv + * @num_want_all_unsnoopables: number of nodes wanting unsnoopable IP traffic + * @num_want_all_ipv4: counter for items in want_all_ipv4_list + * @num_want_all_ipv6: counter for items in want_all_ipv6_list + * @want_lists_lock: lock for protecting modifications to mcast want lists + * (traversals are rcu-locked) + */ + struct batadv_priv_mcast { + struct hlist_head mla_list; + struct hlist_head want_all_unsnoopables_list; + struct hlist_head want_all_ipv4_list; + struct hlist_head want_all_ipv6_list; + uint8_t flags; + bool enabled; + atomic_t num_disabled; + atomic_t num_want_all_unsnoopables; + atomic_t num_want_all_ipv4; + atomic_t num_want_all_ipv6; + /* protects want_all_{unsnoopables,ipv4,ipv6}_list */ + spinlock_t want_lists_lock; + }; + #endif + /** * struct batadv_priv_nc - per mesh interface network coding private data * @work: work queue callback item for cleanup @@@ -672,6 -720,8 +720,8 @@@ struct batadv_softif_vlan * enabled * @distributed_arp_table: bool indicating whether distributed ARP table is * enabled + * @multicast_mode: Enable or disable multicast optimizations on this node's + * sender/originating side * @gw_mode: gateway operation: off, client or server (see batadv_gw_modes) * @gw_sel_class: gateway selection class (applies if gw_mode client) * @orig_interval: OGM broadcast interval in milliseconds @@@ -702,6 -752,7 +752,7 @@@ * @tt: translation table data * @tvlv: type-version-length-value data * @dat: distributed arp table data + * @mcast: multicast data * @network_coding: bool indicating whether network coding is enabled * @batadv_priv_nc: network coding data */ @@@ -721,6 -772,9 +772,9 @@@ struct batadv_priv #ifdef CONFIG_BATMAN_ADV_DAT atomic_t distributed_arp_table; #endif + #ifdef CONFIG_BATMAN_ADV_MCAST + atomic_t multicast_mode; + #endif atomic_t gw_mode; atomic_t gw_sel_class; atomic_t orig_interval; @@@ -759,6 -813,9 +813,9 @@@ #ifdef CONFIG_BATMAN_ADV_DAT struct batadv_priv_dat dat; #endif + #ifdef CONFIG_BATMAN_ADV_MCAST + struct batadv_priv_mcast mcast; + #endif #ifdef CONFIG_BATMAN_ADV_NC atomic_t network_coding; struct batadv_priv_nc nc; @@@ -881,12 -938,14 +938,14 @@@ struct batadv_tt_local_entry * struct batadv_tt_global_entry - translation table global entry data * @common: general translation table data * @orig_list: list of orig nodes announcing this non-mesh client + * @orig_list_count: number of items in the orig_list * @list_lock: lock protecting orig_list * @roam_at: time at which TT_GLOBAL_ROAM was set */ struct batadv_tt_global_entry { struct batadv_tt_common_entry common; struct hlist_head orig_list; + atomic_t orig_list_count; spinlock_t list_lock; /* protects orig_list */ unsigned long roam_at; }; @@@ -1004,8 -1063,8 +1063,8 @@@ struct batadv_nc_packet };
/** - * batadv_skb_cb - control buffer structure used to store private data relevant - * to batman-adv in the skb->cb buffer in skbs. + * struct batadv_skb_cb - control buffer structure used to store private data + * relevant to batman-adv in the skb->cb buffer in skbs. * @decoded: Marks a skb as decoded, which is checked when searching for coding * opportunities in network-coding.c */ @@@ -1116,6 -1175,16 +1175,16 @@@ struct batadv_dat_entry };
/** + * struct batadv_hw_addr - a list entry for a MAC address + * @list: list node for the linking of entries + * @addr: the MAC address of this list entry + */ + struct batadv_hw_addr { + struct hlist_node list; + unsigned char addr[ETH_ALEN]; + }; + + /** * struct batadv_dat_candidate - candidate destination for DAT operations * @type: the type of the selected candidate. It can one of the following: * - BATADV_DAT_CANDIDATE_NOT_FOUND