batman-adv: Announce new capability via multicast TVLV
[cascardo/linux.git] / net / batman-adv / multicast.c
1 /* Copyright (C) 2014 B.A.T.M.A.N. contributors:
2  *
3  * Linus Lüssing
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of version 2 of the GNU General Public
7  * License as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, see <http://www.gnu.org/licenses/>.
16  */
17
18 #include "main.h"
19 #include "multicast.h"
20 #include "originator.h"
21 #include "hard-interface.h"
22 #include "translation-table.h"
23
24 /**
25  * batadv_mcast_mla_softif_get - get softif multicast listeners
26  * @dev: the device to collect multicast addresses from
27  * @mcast_list: a list to put found addresses into
28  *
29  * Collect multicast addresses of the local multicast listeners
30  * on the given soft interface, dev, in the given mcast_list.
31  *
32  * Returns -ENOMEM on memory allocation error or the number of
33  * items added to the mcast_list otherwise.
34  */
35 static int batadv_mcast_mla_softif_get(struct net_device *dev,
36                                        struct hlist_head *mcast_list)
37 {
38         struct netdev_hw_addr *mc_list_entry;
39         struct batadv_hw_addr *new;
40         int ret = 0;
41
42         netif_addr_lock_bh(dev);
43         netdev_for_each_mc_addr(mc_list_entry, dev) {
44                 new = kmalloc(sizeof(*new), GFP_ATOMIC);
45                 if (!new) {
46                         ret = -ENOMEM;
47                         break;
48                 }
49
50                 ether_addr_copy(new->addr, mc_list_entry->addr);
51                 hlist_add_head(&new->list, mcast_list);
52                 ret++;
53         }
54         netif_addr_unlock_bh(dev);
55
56         return ret;
57 }
58
59 /**
60  * batadv_mcast_mla_is_duplicate - check whether an address is in a list
61  * @mcast_addr: the multicast address to check
62  * @mcast_list: the list with multicast addresses to search in
63  *
64  * Returns true if the given address is already in the given list.
65  * Otherwise returns false.
66  */
67 static bool batadv_mcast_mla_is_duplicate(uint8_t *mcast_addr,
68                                           struct hlist_head *mcast_list)
69 {
70         struct batadv_hw_addr *mcast_entry;
71
72         hlist_for_each_entry(mcast_entry, mcast_list, list)
73                 if (batadv_compare_eth(mcast_entry->addr, mcast_addr))
74                         return true;
75
76         return false;
77 }
78
79 /**
80  * batadv_mcast_mla_list_free - free a list of multicast addresses
81  * @mcast_list: the list to free
82  *
83  * Removes and frees all items in the given mcast_list.
84  */
85 static void batadv_mcast_mla_list_free(struct hlist_head *mcast_list)
86 {
87         struct batadv_hw_addr *mcast_entry;
88         struct hlist_node *tmp;
89
90         hlist_for_each_entry_safe(mcast_entry, tmp, mcast_list, list) {
91                 hlist_del(&mcast_entry->list);
92                 kfree(mcast_entry);
93         }
94 }
95
96 /**
97  * batadv_mcast_mla_tt_retract - clean up multicast listener announcements
98  * @bat_priv: the bat priv with all the soft interface information
99  * @mcast_list: a list of addresses which should _not_ be removed
100  *
101  * Retracts the announcement of any multicast listener from the
102  * translation table except the ones listed in the given mcast_list.
103  *
104  * If mcast_list is NULL then all are retracted.
105  */
106 static void batadv_mcast_mla_tt_retract(struct batadv_priv *bat_priv,
107                                         struct hlist_head *mcast_list)
108 {
109         struct batadv_hw_addr *mcast_entry;
110         struct hlist_node *tmp;
111
112         hlist_for_each_entry_safe(mcast_entry, tmp, &bat_priv->mcast.mla_list,
113                                   list) {
114                 if (mcast_list &&
115                     batadv_mcast_mla_is_duplicate(mcast_entry->addr,
116                                                   mcast_list))
117                         continue;
118
119                 batadv_tt_local_remove(bat_priv, mcast_entry->addr,
120                                        BATADV_NO_FLAGS,
121                                        "mcast TT outdated", false);
122
123                 hlist_del(&mcast_entry->list);
124                 kfree(mcast_entry);
125         }
126 }
127
128 /**
129  * batadv_mcast_mla_tt_add - add multicast listener announcements
130  * @bat_priv: the bat priv with all the soft interface information
131  * @mcast_list: a list of addresses which are going to get added
132  *
133  * Adds multicast listener announcements from the given mcast_list to the
134  * translation table if they have not been added yet.
135  */
136 static void batadv_mcast_mla_tt_add(struct batadv_priv *bat_priv,
137                                     struct hlist_head *mcast_list)
138 {
139         struct batadv_hw_addr *mcast_entry;
140         struct hlist_node *tmp;
141
142         if (!mcast_list)
143                 return;
144
145         hlist_for_each_entry_safe(mcast_entry, tmp, mcast_list, list) {
146                 if (batadv_mcast_mla_is_duplicate(mcast_entry->addr,
147                                                   &bat_priv->mcast.mla_list))
148                         continue;
149
150                 if (!batadv_tt_local_add(bat_priv->soft_iface,
151                                          mcast_entry->addr, BATADV_NO_FLAGS,
152                                          BATADV_NULL_IFINDEX, BATADV_NO_MARK))
153                         continue;
154
155                 hlist_del(&mcast_entry->list);
156                 hlist_add_head(&mcast_entry->list, &bat_priv->mcast.mla_list);
157         }
158 }
159
160 /**
161  * batadv_mcast_has_bridge - check whether the soft-iface is bridged
162  * @bat_priv: the bat priv with all the soft interface information
163  *
164  * Checks whether there is a bridge on top of our soft interface. Returns
165  * true if so, false otherwise.
166  */
167 static bool batadv_mcast_has_bridge(struct batadv_priv *bat_priv)
168 {
169         struct net_device *upper = bat_priv->soft_iface;
170
171         rcu_read_lock();
172         do {
173                 upper = netdev_master_upper_dev_get_rcu(upper);
174         } while (upper && !(upper->priv_flags & IFF_EBRIDGE));
175         rcu_read_unlock();
176
177         return upper;
178 }
179
180 /**
181  * batadv_mcast_mla_tvlv_update - update multicast tvlv
182  * @bat_priv: the bat priv with all the soft interface information
183  *
184  * Updates the own multicast tvlv with our current multicast related settings,
185  * capabilities and inabilities.
186  *
187  * Returns true if the tvlv container is registered afterwards. Otherwise
188  * returns false.
189  */
190 static bool batadv_mcast_mla_tvlv_update(struct batadv_priv *bat_priv)
191 {
192         struct batadv_tvlv_mcast_data mcast_data;
193
194         mcast_data.flags = BATADV_NO_FLAGS;
195         memset(mcast_data.reserved, 0, sizeof(mcast_data.reserved));
196
197         /* Avoid attaching MLAs, if there is a bridge on top of our soft
198          * interface, we don't support that yet (TODO)
199          */
200         if (batadv_mcast_has_bridge(bat_priv)) {
201                 if (bat_priv->mcast.enabled) {
202                         batadv_tvlv_container_unregister(bat_priv,
203                                                          BATADV_TVLV_MCAST, 1);
204                         bat_priv->mcast.enabled = false;
205                 }
206
207                 return false;
208         }
209
210         if (!bat_priv->mcast.enabled ||
211             mcast_data.flags != bat_priv->mcast.flags) {
212                 batadv_tvlv_container_register(bat_priv, BATADV_TVLV_MCAST, 1,
213                                                &mcast_data, sizeof(mcast_data));
214                 bat_priv->mcast.flags = mcast_data.flags;
215                 bat_priv->mcast.enabled = true;
216         }
217
218         return true;
219 }
220
221 /**
222  * batadv_mcast_mla_update - update the own MLAs
223  * @bat_priv: the bat priv with all the soft interface information
224  *
225  * Updates the own multicast listener announcements in the translation
226  * table as well as the own, announced multicast tvlv container.
227  */
228 void batadv_mcast_mla_update(struct batadv_priv *bat_priv)
229 {
230         struct net_device *soft_iface = bat_priv->soft_iface;
231         struct hlist_head mcast_list = HLIST_HEAD_INIT;
232         int ret;
233
234         if (!batadv_mcast_mla_tvlv_update(bat_priv))
235                 goto update;
236
237         ret = batadv_mcast_mla_softif_get(soft_iface, &mcast_list);
238         if (ret < 0)
239                 goto out;
240
241 update:
242         batadv_mcast_mla_tt_retract(bat_priv, &mcast_list);
243         batadv_mcast_mla_tt_add(bat_priv, &mcast_list);
244
245 out:
246         batadv_mcast_mla_list_free(&mcast_list);
247 }
248
249 /**
250  * batadv_mcast_tvlv_ogm_handler_v1 - process incoming multicast tvlv container
251  * @bat_priv: the bat priv with all the soft interface information
252  * @orig: the orig_node of the ogm
253  * @flags: flags indicating the tvlv state (see batadv_tvlv_handler_flags)
254  * @tvlv_value: tvlv buffer containing the multicast data
255  * @tvlv_value_len: tvlv buffer length
256  */
257 static void batadv_mcast_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv,
258                                              struct batadv_orig_node *orig,
259                                              uint8_t flags,
260                                              void *tvlv_value,
261                                              uint16_t tvlv_value_len)
262 {
263         bool orig_mcast_enabled = !(flags & BATADV_TVLV_HANDLER_OGM_CIFNOTFND);
264         uint8_t mcast_flags = BATADV_NO_FLAGS;
265         bool orig_initialized;
266
267         orig_initialized = orig->capa_initialized & BATADV_ORIG_CAPA_HAS_MCAST;
268
269         /* If mcast support is turned on decrease the disabled mcast node
270          * counter only if we had increased it for this node before. If this
271          * is a completely new orig_node no need to decrease the counter.
272          */
273         if (orig_mcast_enabled &&
274             !(orig->capabilities & BATADV_ORIG_CAPA_HAS_MCAST)) {
275                 if (orig_initialized)
276                         atomic_dec(&bat_priv->mcast.num_disabled);
277                 orig->capabilities |= BATADV_ORIG_CAPA_HAS_MCAST;
278         /* If mcast support is being switched off increase the disabled
279          * mcast node counter.
280          */
281         } else if (!orig_mcast_enabled &&
282                    orig->capabilities & BATADV_ORIG_CAPA_HAS_MCAST) {
283                 atomic_inc(&bat_priv->mcast.num_disabled);
284                 orig->capabilities &= ~BATADV_ORIG_CAPA_HAS_MCAST;
285         }
286
287         orig->capa_initialized |= BATADV_ORIG_CAPA_HAS_MCAST;
288
289         if (orig_mcast_enabled && tvlv_value &&
290             (tvlv_value_len >= sizeof(mcast_flags)))
291                 mcast_flags = *(uint8_t *)tvlv_value;
292
293         orig->mcast_flags = mcast_flags;
294 }
295
296 /**
297  * batadv_mcast_init - initialize the multicast optimizations structures
298  * @bat_priv: the bat priv with all the soft interface information
299  */
300 void batadv_mcast_init(struct batadv_priv *bat_priv)
301 {
302         batadv_tvlv_handler_register(bat_priv, batadv_mcast_tvlv_ogm_handler_v1,
303                                      NULL, BATADV_TVLV_MCAST, 1,
304                                      BATADV_TVLV_HANDLER_OGM_CIFNOTFND);
305 }
306
307 /**
308  * batadv_mcast_free - free the multicast optimizations structures
309  * @bat_priv: the bat priv with all the soft interface information
310  */
311 void batadv_mcast_free(struct batadv_priv *bat_priv)
312 {
313         batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_MCAST, 1);
314         batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_MCAST, 1);
315
316         batadv_mcast_mla_tt_retract(bat_priv, NULL);
317 }
318
319 /**
320  * batadv_mcast_purge_orig - reset originator global mcast state modifications
321  * @orig: the originator which is going to get purged
322  */
323 void batadv_mcast_purge_orig(struct batadv_orig_node *orig)
324 {
325         struct batadv_priv *bat_priv = orig->bat_priv;
326
327         if (!(orig->capabilities & BATADV_ORIG_CAPA_HAS_MCAST))
328                 atomic_dec(&bat_priv->mcast.num_disabled);
329 }