diff options
author | Linus Lüssing <linus.luessing@web.de> | 2014-02-15 11:47:49 -0500 |
---|---|---|
committer | Antonio Quartulli <antonio@meshcoding.com> | 2014-03-22 04:18:56 -0400 |
commit | c5caf4ef34e2779c9a90bf4cbb57fbdf57dc8cbc (patch) | |
tree | 85fef7bf4b8eb836560710fb97214d97c16528dd /net/batman-adv/multicast.c | |
parent | c5d3a652a3cf180e7a4b670d73517a0dfbbefebc (diff) |
batman-adv: Multicast Listener Announcements via Translation Table
With this patch a node which has no bridge interface on top of its soft
interface announces its local multicast listeners via the translation
table.
Signed-off-by: Linus Lüssing <linus.luessing@web.de>
Signed-off-by: Marek Lindner <mareklindner@neomailbox.ch>
Signed-off-by: Antonio Quartulli <antonio@meshcoding.com>
Diffstat (limited to 'net/batman-adv/multicast.c')
-rw-r--r-- | net/batman-adv/multicast.c | 218 |
1 files changed, 218 insertions, 0 deletions
diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c new file mode 100644 index 000000000000..e099fd67403c --- /dev/null +++ b/net/batman-adv/multicast.c | |||
@@ -0,0 +1,218 @@ | |||
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_update - update the own MLAs | ||
182 | * @bat_priv: the bat priv with all the soft interface information | ||
183 | * | ||
184 | * Update the own multicast listener announcements in the translation | ||
185 | * table. | ||
186 | */ | ||
187 | void batadv_mcast_mla_update(struct batadv_priv *bat_priv) | ||
188 | { | ||
189 | struct net_device *soft_iface = bat_priv->soft_iface; | ||
190 | struct hlist_head mcast_list = HLIST_HEAD_INIT; | ||
191 | int ret; | ||
192 | |||
193 | /* Avoid attaching MLAs, if there is a bridge on top of our soft | ||
194 | * interface, we don't support that yet (TODO) | ||
195 | */ | ||
196 | if (batadv_mcast_has_bridge(bat_priv)) | ||
197 | goto update; | ||
198 | |||
199 | ret = batadv_mcast_mla_softif_get(soft_iface, &mcast_list); | ||
200 | if (ret < 0) | ||
201 | goto out; | ||
202 | |||
203 | update: | ||
204 | batadv_mcast_mla_tt_retract(bat_priv, &mcast_list); | ||
205 | batadv_mcast_mla_tt_add(bat_priv, &mcast_list); | ||
206 | |||
207 | out: | ||
208 | batadv_mcast_mla_list_free(&mcast_list); | ||
209 | } | ||
210 | |||
211 | /** | ||
212 | * batadv_mcast_free - free the multicast optimizations structures | ||
213 | * @bat_priv: the bat priv with all the soft interface information | ||
214 | */ | ||
215 | void batadv_mcast_free(struct batadv_priv *bat_priv) | ||
216 | { | ||
217 | batadv_mcast_mla_tt_retract(bat_priv, NULL); | ||
218 | } | ||