blob: ee1d847242054d12f982c8ca92459b842863a52e [file] [log] [blame]
Antonio Quartulli0b873932013-01-04 03:05:31 +01001/* Copyright (C) 2009-2013 B.A.T.M.A.N. contributors:
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00002 *
3 * Marek Lindner, Simon Wunderlich
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, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301, USA
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000018 */
19
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000020#include "main.h"
Antonio Quartulli785ea112011-11-23 11:35:44 +010021#include "distributed-arp-table.h"
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000022#include "originator.h"
23#include "hash.h"
24#include "translation-table.h"
25#include "routing.h"
26#include "gateway_client.h"
27#include "hard-interface.h"
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000028#include "soft-interface.h"
Simon Wunderlich23721382012-01-22 20:00:19 +010029#include "bridge_loop_avoidance.h"
Martin Hundebølld56b1702013-01-25 11:12:39 +010030#include "network-coding.h"
Martin Hundebøll610bfc6bc2013-05-23 16:53:02 +020031#include "fragmentation.h"
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000032
Antonio Quartullidec05072012-11-10 11:00:32 +010033/* hash class keys */
34static struct lock_class_key batadv_orig_hash_lock_class_key;
35
Sven Eckelmann03fc7f82012-05-12 18:34:00 +020036static void batadv_purge_orig(struct work_struct *work);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000037
Sven Eckelmannb8e2dd12011-06-15 15:08:59 +020038/* returns 1 if they are the same originator */
Sven Eckelmann03fc7f82012-05-12 18:34:00 +020039static int batadv_compare_orig(const struct hlist_node *node, const void *data2)
Sven Eckelmannb8e2dd12011-06-15 15:08:59 +020040{
Sven Eckelmann56303d32012-06-05 22:31:31 +020041 const void *data1 = container_of(node, struct batadv_orig_node,
42 hash_entry);
Sven Eckelmannb8e2dd12011-06-15 15:08:59 +020043
44 return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0);
45}
46
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +020047/**
48 * batadv_orig_node_vlan_get - get an orig_node_vlan object
49 * @orig_node: the originator serving the VLAN
50 * @vid: the VLAN identifier
51 *
52 * Returns the vlan object identified by vid and belonging to orig_node or NULL
53 * if it does not exist.
54 */
55struct batadv_orig_node_vlan *
56batadv_orig_node_vlan_get(struct batadv_orig_node *orig_node,
57 unsigned short vid)
58{
59 struct batadv_orig_node_vlan *vlan = NULL, *tmp;
60
61 rcu_read_lock();
62 list_for_each_entry_rcu(tmp, &orig_node->vlan_list, list) {
63 if (tmp->vid != vid)
64 continue;
65
66 if (!atomic_inc_not_zero(&tmp->refcount))
67 continue;
68
69 vlan = tmp;
70
71 break;
72 }
73 rcu_read_unlock();
74
75 return vlan;
76}
77
78/**
79 * batadv_orig_node_vlan_new - search and possibly create an orig_node_vlan
80 * object
81 * @orig_node: the originator serving the VLAN
82 * @vid: the VLAN identifier
83 *
84 * Returns NULL in case of failure or the vlan object identified by vid and
85 * belonging to orig_node otherwise. The object is created and added to the list
86 * if it does not exist.
87 *
88 * The object is returned with refcounter increased by 1.
89 */
90struct batadv_orig_node_vlan *
91batadv_orig_node_vlan_new(struct batadv_orig_node *orig_node,
92 unsigned short vid)
93{
94 struct batadv_orig_node_vlan *vlan;
95
96 spin_lock_bh(&orig_node->vlan_list_lock);
97
98 /* first look if an object for this vid already exists */
99 vlan = batadv_orig_node_vlan_get(orig_node, vid);
100 if (vlan)
101 goto out;
102
103 vlan = kzalloc(sizeof(*vlan), GFP_ATOMIC);
104 if (!vlan)
105 goto out;
106
107 atomic_set(&vlan->refcount, 2);
108 vlan->vid = vid;
109
110 list_add_rcu(&vlan->list, &orig_node->vlan_list);
111
112out:
113 spin_unlock_bh(&orig_node->vlan_list_lock);
114
115 return vlan;
116}
117
118/**
119 * batadv_orig_node_vlan_free_ref - decrement the refcounter and possibly free
120 * the originator-vlan object
121 * @orig_vlan: the originator-vlan object to release
122 */
123void batadv_orig_node_vlan_free_ref(struct batadv_orig_node_vlan *orig_vlan)
124{
125 if (atomic_dec_and_test(&orig_vlan->refcount))
126 kfree_rcu(orig_vlan, rcu);
127}
128
Sven Eckelmann56303d32012-06-05 22:31:31 +0200129int batadv_originator_init(struct batadv_priv *bat_priv)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000130{
131 if (bat_priv->orig_hash)
Sven Eckelmann5346c352012-05-05 13:27:28 +0200132 return 0;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000133
Sven Eckelmann1a8eaf02012-05-12 02:09:32 +0200134 bat_priv->orig_hash = batadv_hash_new(1024);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000135
136 if (!bat_priv->orig_hash)
137 goto err;
138
Antonio Quartullidec05072012-11-10 11:00:32 +0100139 batadv_hash_set_lock_class(bat_priv->orig_hash,
140 &batadv_orig_hash_lock_class_key);
141
Antonio Quartulli72414442012-12-25 13:14:37 +0100142 INIT_DELAYED_WORK(&bat_priv->orig_work, batadv_purge_orig);
143 queue_delayed_work(batadv_event_workqueue,
144 &bat_priv->orig_work,
145 msecs_to_jiffies(BATADV_ORIG_WORK_PERIOD));
146
Sven Eckelmann5346c352012-05-05 13:27:28 +0200147 return 0;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000148
149err:
Sven Eckelmann5346c352012-05-05 13:27:28 +0200150 return -ENOMEM;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000151}
152
Sven Eckelmann56303d32012-06-05 22:31:31 +0200153void batadv_neigh_node_free_ref(struct batadv_neigh_node *neigh_node)
Simon Wunderlicha4c135c2011-01-19 20:01:43 +0000154{
Marek Lindner44524fc2011-02-10 14:33:53 +0000155 if (atomic_dec_and_test(&neigh_node->refcount))
Paul E. McKenneyae179ae2011-05-01 23:27:50 -0700156 kfree_rcu(neigh_node, rcu);
Simon Wunderlicha4c135c2011-01-19 20:01:43 +0000157}
158
Linus LĂĽssinge1a5382f2011-03-14 22:43:37 +0000159/* increases the refcounter of a found router */
Sven Eckelmann56303d32012-06-05 22:31:31 +0200160struct batadv_neigh_node *
161batadv_orig_node_get_router(struct batadv_orig_node *orig_node)
Linus LĂĽssinge1a5382f2011-03-14 22:43:37 +0000162{
Sven Eckelmann56303d32012-06-05 22:31:31 +0200163 struct batadv_neigh_node *router;
Linus LĂĽssinge1a5382f2011-03-14 22:43:37 +0000164
165 rcu_read_lock();
166 router = rcu_dereference(orig_node->router);
167
168 if (router && !atomic_inc_not_zero(&router->refcount))
169 router = NULL;
170
171 rcu_read_unlock();
172 return router;
173}
174
Sven Eckelmann56303d32012-06-05 22:31:31 +0200175struct batadv_neigh_node *
176batadv_neigh_node_new(struct batadv_hard_iface *hard_iface,
Antonio Quartulli863dd7a2013-03-25 13:49:46 +0100177 const uint8_t *neigh_addr)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000178{
Sven Eckelmann56303d32012-06-05 22:31:31 +0200179 struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
180 struct batadv_neigh_node *neigh_node;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000181
Sven Eckelmann704509b2011-05-14 23:14:54 +0200182 neigh_node = kzalloc(sizeof(*neigh_node), GFP_ATOMIC);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000183 if (!neigh_node)
Marek Lindner7ae8b282012-03-01 15:35:21 +0800184 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000185
Marek Lindner9591a792010-12-12 21:57:11 +0000186 INIT_HLIST_NODE(&neigh_node->list);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000187
Marek Lindner7ae8b282012-03-01 15:35:21 +0800188 memcpy(neigh_node->addr, neigh_addr, ETH_ALEN);
Marek Lindnere3b0d0d2012-03-17 15:28:32 +0800189 spin_lock_init(&neigh_node->lq_update_lock);
Marek Lindner1605d0d2011-02-18 12:28:11 +0000190
191 /* extra reference for return */
192 atomic_set(&neigh_node->refcount, 2);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000193
Sven Eckelmann39c75a52012-06-03 22:19:22 +0200194 batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
Antonio Quartullid1dc3072013-03-25 13:54:45 +0100195 "Creating new neighbor %pM on interface %s\n", neigh_addr,
196 hard_iface->net_dev->name);
Marek Lindner7ae8b282012-03-01 15:35:21 +0800197
198out:
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000199 return neigh_node;
200}
201
Sven Eckelmann03fc7f82012-05-12 18:34:00 +0200202static void batadv_orig_node_free_rcu(struct rcu_head *rcu)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000203{
Sasha Levinb67bfe02013-02-27 17:06:00 -0800204 struct hlist_node *node_tmp;
Sven Eckelmann56303d32012-06-05 22:31:31 +0200205 struct batadv_neigh_node *neigh_node, *tmp_neigh_node;
206 struct batadv_orig_node *orig_node;
Marek Lindner16b1aba2011-01-19 20:01:42 +0000207
Sven Eckelmann56303d32012-06-05 22:31:31 +0200208 orig_node = container_of(rcu, struct batadv_orig_node, rcu);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000209
Marek Lindnerf987ed62010-12-12 21:57:12 +0000210 spin_lock_bh(&orig_node->neigh_list_lock);
211
Simon Wunderlicha4c135c2011-01-19 20:01:43 +0000212 /* for all bonding members ... */
213 list_for_each_entry_safe(neigh_node, tmp_neigh_node,
214 &orig_node->bond_list, bonding_list) {
215 list_del_rcu(&neigh_node->bonding_list);
Sven Eckelmann7d211ef2012-05-12 02:09:34 +0200216 batadv_neigh_node_free_ref(neigh_node);
Simon Wunderlicha4c135c2011-01-19 20:01:43 +0000217 }
218
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000219 /* for all neighbors towards this originator ... */
Sasha Levinb67bfe02013-02-27 17:06:00 -0800220 hlist_for_each_entry_safe(neigh_node, node_tmp,
Marek Lindner9591a792010-12-12 21:57:11 +0000221 &orig_node->neigh_list, list) {
Marek Lindnerf987ed62010-12-12 21:57:12 +0000222 hlist_del_rcu(&neigh_node->list);
Sven Eckelmann7d211ef2012-05-12 02:09:34 +0200223 batadv_neigh_node_free_ref(neigh_node);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000224 }
225
Marek Lindnerf987ed62010-12-12 21:57:12 +0000226 spin_unlock_bh(&orig_node->neigh_list_lock);
227
Martin Hundebølld56b1702013-01-25 11:12:39 +0100228 /* Free nc_nodes */
229 batadv_nc_purge_orig(orig_node->bat_priv, orig_node, NULL);
230
Martin Hundebøll610bfc6bc2013-05-23 16:53:02 +0200231 batadv_frag_purge_orig(orig_node, NULL);
232
Antonio Quartulli95fb1302013-08-07 18:28:55 +0200233 batadv_tt_global_del_orig(orig_node->bat_priv, orig_node, -1,
Sven Eckelmann08c36d32012-05-12 02:09:39 +0200234 "originator timed out");
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000235
Antonio Quartullia73105b2011-04-27 14:27:44 +0200236 kfree(orig_node->tt_buff);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000237 kfree(orig_node->bcast_own);
238 kfree(orig_node->bcast_own_sum);
239 kfree(orig_node);
240}
241
Linus LĂĽssing72822222013-04-15 21:43:29 +0800242/**
243 * batadv_orig_node_free_ref - decrement the orig node refcounter and possibly
244 * schedule an rcu callback for freeing it
245 * @orig_node: the orig node to free
246 */
Sven Eckelmann56303d32012-06-05 22:31:31 +0200247void batadv_orig_node_free_ref(struct batadv_orig_node *orig_node)
Marek Lindner7b36e8e2011-02-18 12:28:10 +0000248{
249 if (atomic_dec_and_test(&orig_node->refcount))
Sven Eckelmann03fc7f82012-05-12 18:34:00 +0200250 call_rcu(&orig_node->rcu, batadv_orig_node_free_rcu);
Marek Lindner7b36e8e2011-02-18 12:28:10 +0000251}
252
Linus LĂĽssing72822222013-04-15 21:43:29 +0800253/**
254 * batadv_orig_node_free_ref_now - decrement the orig node refcounter and
255 * possibly free it (without rcu callback)
256 * @orig_node: the orig node to free
257 */
258void batadv_orig_node_free_ref_now(struct batadv_orig_node *orig_node)
259{
260 if (atomic_dec_and_test(&orig_node->refcount))
261 batadv_orig_node_free_rcu(&orig_node->rcu);
262}
263
Sven Eckelmann56303d32012-06-05 22:31:31 +0200264void batadv_originator_free(struct batadv_priv *bat_priv)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000265{
Sven Eckelmann5bf74e92012-06-05 22:31:28 +0200266 struct batadv_hashtable *hash = bat_priv->orig_hash;
Sasha Levinb67bfe02013-02-27 17:06:00 -0800267 struct hlist_node *node_tmp;
Marek Lindner16b1aba2011-01-19 20:01:42 +0000268 struct hlist_head *head;
Marek Lindner16b1aba2011-01-19 20:01:42 +0000269 spinlock_t *list_lock; /* spinlock to protect write access */
Sven Eckelmann56303d32012-06-05 22:31:31 +0200270 struct batadv_orig_node *orig_node;
Antonio Quartullic90681b2011-10-05 17:05:25 +0200271 uint32_t i;
Marek Lindner16b1aba2011-01-19 20:01:42 +0000272
273 if (!hash)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000274 return;
275
276 cancel_delayed_work_sync(&bat_priv->orig_work);
277
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000278 bat_priv->orig_hash = NULL;
Marek Lindner16b1aba2011-01-19 20:01:42 +0000279
280 for (i = 0; i < hash->size; i++) {
281 head = &hash->table[i];
282 list_lock = &hash->list_locks[i];
283
284 spin_lock_bh(list_lock);
Sasha Levinb67bfe02013-02-27 17:06:00 -0800285 hlist_for_each_entry_safe(orig_node, node_tmp,
Marek Lindner7aadf882011-02-18 12:28:09 +0000286 head, hash_entry) {
Sasha Levinb67bfe02013-02-27 17:06:00 -0800287 hlist_del_rcu(&orig_node->hash_entry);
Sven Eckelmann7d211ef2012-05-12 02:09:34 +0200288 batadv_orig_node_free_ref(orig_node);
Marek Lindner16b1aba2011-01-19 20:01:42 +0000289 }
290 spin_unlock_bh(list_lock);
291 }
292
Sven Eckelmann1a8eaf02012-05-12 02:09:32 +0200293 batadv_hash_destroy(hash);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000294}
295
296/* this function finds or creates an originator entry for the given
Sven Eckelmann9cfc7bd2012-05-12 02:09:43 +0200297 * address if it does not exits
298 */
Sven Eckelmann56303d32012-06-05 22:31:31 +0200299struct batadv_orig_node *batadv_get_orig_node(struct batadv_priv *bat_priv,
300 const uint8_t *addr)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000301{
Sven Eckelmann56303d32012-06-05 22:31:31 +0200302 struct batadv_orig_node *orig_node;
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200303 struct batadv_orig_node_vlan *vlan;
Martin Hundebøll610bfc6bc2013-05-23 16:53:02 +0200304 int size, i;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000305 int hash_added;
Sven Eckelmann42d0b0442012-06-03 22:19:17 +0200306 unsigned long reset_time;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000307
Sven Eckelmannda641192012-05-12 13:48:56 +0200308 orig_node = batadv_orig_hash_find(bat_priv, addr);
Marek Lindner7aadf882011-02-18 12:28:09 +0000309 if (orig_node)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000310 return orig_node;
311
Sven Eckelmann39c75a52012-06-03 22:19:22 +0200312 batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
313 "Creating new originator: %pM\n", addr);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000314
Sven Eckelmann704509b2011-05-14 23:14:54 +0200315 orig_node = kzalloc(sizeof(*orig_node), GFP_ATOMIC);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000316 if (!orig_node)
317 return NULL;
318
Marek Lindner9591a792010-12-12 21:57:11 +0000319 INIT_HLIST_HEAD(&orig_node->neigh_list);
Simon Wunderlicha4c135c2011-01-19 20:01:43 +0000320 INIT_LIST_HEAD(&orig_node->bond_list);
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200321 INIT_LIST_HEAD(&orig_node->vlan_list);
Marek Lindner2ae2daf2011-01-19 20:01:42 +0000322 spin_lock_init(&orig_node->ogm_cnt_lock);
Marek Lindnerf3e00082011-01-25 21:52:11 +0000323 spin_lock_init(&orig_node->bcast_seqno_lock);
Marek Lindnerf987ed62010-12-12 21:57:12 +0000324 spin_lock_init(&orig_node->neigh_list_lock);
Antonio Quartullia73105b2011-04-27 14:27:44 +0200325 spin_lock_init(&orig_node->tt_buff_lock);
Antonio Quartullia70a9aa2013-07-30 22:16:24 +0200326 spin_lock_init(&orig_node->tt_lock);
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200327 spin_lock_init(&orig_node->vlan_list_lock);
Marek Lindner7b36e8e2011-02-18 12:28:10 +0000328
Martin Hundebølld56b1702013-01-25 11:12:39 +0100329 batadv_nc_init_orig(orig_node);
330
Marek Lindner7b36e8e2011-02-18 12:28:10 +0000331 /* extra reference for return */
332 atomic_set(&orig_node->refcount, 2);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000333
Antonio Quartulli17071572011-11-07 16:36:40 +0100334 orig_node->tt_initialised = false;
Marek Lindner16b1aba2011-01-19 20:01:42 +0000335 orig_node->bat_priv = bat_priv;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000336 memcpy(orig_node->orig, addr, ETH_ALEN);
Antonio Quartulli785ea112011-11-23 11:35:44 +0100337 batadv_dat_init_orig_node_addr(orig_node);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000338 orig_node->router = NULL;
Antonio Quartullic8c991b2011-07-07 01:40:57 +0200339 atomic_set(&orig_node->last_ttvn, 0);
Antonio Quartulli2dafb492011-05-05 08:42:45 +0200340 orig_node->tt_buff = NULL;
Antonio Quartullia73105b2011-04-27 14:27:44 +0200341 orig_node->tt_buff_len = 0;
Sven Eckelmann42d0b0442012-06-03 22:19:17 +0200342 reset_time = jiffies - 1 - msecs_to_jiffies(BATADV_RESET_PROTECTION_MS);
343 orig_node->bcast_seqno_reset = reset_time;
344 orig_node->batman_seqno_reset = reset_time;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000345
Simon Wunderlicha4c135c2011-01-19 20:01:43 +0000346 atomic_set(&orig_node->bond_candidates, 0);
347
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200348 /* create a vlan object for the "untagged" LAN */
349 vlan = batadv_orig_node_vlan_new(orig_node, BATADV_NO_FLAGS);
350 if (!vlan)
351 goto free_orig_node;
352 /* batadv_orig_node_vlan_new() increases the refcounter.
353 * Immediately release vlan since it is not needed anymore in this
354 * context
355 */
356 batadv_orig_node_vlan_free_ref(vlan);
357
Sven Eckelmann42d0b0442012-06-03 22:19:17 +0200358 size = bat_priv->num_ifaces * sizeof(unsigned long) * BATADV_NUM_WORDS;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000359
360 orig_node->bcast_own = kzalloc(size, GFP_ATOMIC);
361 if (!orig_node->bcast_own)
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200362 goto free_vlan;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000363
364 size = bat_priv->num_ifaces * sizeof(uint8_t);
365 orig_node->bcast_own_sum = kzalloc(size, GFP_ATOMIC);
366
Martin Hundebøll610bfc6bc2013-05-23 16:53:02 +0200367 for (i = 0; i < BATADV_FRAG_BUFFER_COUNT; i++) {
368 INIT_HLIST_HEAD(&orig_node->fragments[i].head);
369 spin_lock_init(&orig_node->fragments[i].lock);
370 orig_node->fragments[i].size = 0;
371 }
372
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000373 if (!orig_node->bcast_own_sum)
374 goto free_bcast_own;
375
Sven Eckelmann03fc7f82012-05-12 18:34:00 +0200376 hash_added = batadv_hash_add(bat_priv->orig_hash, batadv_compare_orig,
Sven Eckelmannda641192012-05-12 13:48:56 +0200377 batadv_choose_orig, orig_node,
Sven Eckelmannc0a55922012-05-12 13:48:55 +0200378 &orig_node->hash_entry);
Antonio Quartulli1a1f37d2011-07-10 00:36:36 +0200379 if (hash_added != 0)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000380 goto free_bcast_own_sum;
381
382 return orig_node;
383free_bcast_own_sum:
384 kfree(orig_node->bcast_own_sum);
385free_bcast_own:
386 kfree(orig_node->bcast_own);
Antonio Quartulli7ea7b4a2013-07-30 22:16:25 +0200387free_vlan:
388 batadv_orig_node_vlan_free_ref(vlan);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000389free_orig_node:
390 kfree(orig_node);
391 return NULL;
392}
393
Sven Eckelmann56303d32012-06-05 22:31:31 +0200394static bool
395batadv_purge_orig_neighbors(struct batadv_priv *bat_priv,
396 struct batadv_orig_node *orig_node,
397 struct batadv_neigh_node **best_neigh_node)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000398{
Sasha Levinb67bfe02013-02-27 17:06:00 -0800399 struct hlist_node *node_tmp;
Sven Eckelmann56303d32012-06-05 22:31:31 +0200400 struct batadv_neigh_node *neigh_node;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000401 bool neigh_purged = false;
Marek Lindner0b0094e2012-03-01 15:35:20 +0800402 unsigned long last_seen;
Sven Eckelmann56303d32012-06-05 22:31:31 +0200403 struct batadv_hard_iface *if_incoming;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000404
405 *best_neigh_node = NULL;
406
Marek Lindnerf987ed62010-12-12 21:57:12 +0000407 spin_lock_bh(&orig_node->neigh_list_lock);
408
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000409 /* for all neighbors towards this originator ... */
Sasha Levinb67bfe02013-02-27 17:06:00 -0800410 hlist_for_each_entry_safe(neigh_node, node_tmp,
Marek Lindner9591a792010-12-12 21:57:11 +0000411 &orig_node->neigh_list, list) {
Sven Eckelmann1eda58b2012-05-12 13:48:58 +0200412 last_seen = neigh_node->last_seen;
413 if_incoming = neigh_node->if_incoming;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000414
Sven Eckelmann42d0b0442012-06-03 22:19:17 +0200415 if ((batadv_has_timed_out(last_seen, BATADV_PURGE_TIMEOUT)) ||
Sven Eckelmanne9a4f292012-06-03 22:19:19 +0200416 (if_incoming->if_status == BATADV_IF_INACTIVE) ||
417 (if_incoming->if_status == BATADV_IF_NOT_IN_USE) ||
418 (if_incoming->if_status == BATADV_IF_TO_BE_REMOVED)) {
Sven Eckelmanne9a4f292012-06-03 22:19:19 +0200419 if ((if_incoming->if_status == BATADV_IF_INACTIVE) ||
420 (if_incoming->if_status == BATADV_IF_NOT_IN_USE) ||
421 (if_incoming->if_status == BATADV_IF_TO_BE_REMOVED))
Sven Eckelmann39c75a52012-06-03 22:19:22 +0200422 batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
Sven Eckelmann1eda58b2012-05-12 13:48:58 +0200423 "neighbor purge: originator %pM, neighbor: %pM, iface: %s\n",
424 orig_node->orig, neigh_node->addr,
425 if_incoming->net_dev->name);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000426 else
Sven Eckelmann39c75a52012-06-03 22:19:22 +0200427 batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
Sven Eckelmann1eda58b2012-05-12 13:48:58 +0200428 "neighbor timeout: originator %pM, neighbor: %pM, last_seen: %u\n",
429 orig_node->orig, neigh_node->addr,
430 jiffies_to_msecs(last_seen));
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000431
432 neigh_purged = true;
Marek Lindner9591a792010-12-12 21:57:11 +0000433
Marek Lindnerf987ed62010-12-12 21:57:12 +0000434 hlist_del_rcu(&neigh_node->list);
Sven Eckelmann30d3c512012-05-12 02:09:36 +0200435 batadv_bonding_candidate_del(orig_node, neigh_node);
Sven Eckelmann7d211ef2012-05-12 02:09:34 +0200436 batadv_neigh_node_free_ref(neigh_node);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000437 } else {
438 if ((!*best_neigh_node) ||
439 (neigh_node->tq_avg > (*best_neigh_node)->tq_avg))
440 *best_neigh_node = neigh_node;
441 }
442 }
Marek Lindnerf987ed62010-12-12 21:57:12 +0000443
444 spin_unlock_bh(&orig_node->neigh_list_lock);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000445 return neigh_purged;
446}
447
Sven Eckelmann56303d32012-06-05 22:31:31 +0200448static bool batadv_purge_orig_node(struct batadv_priv *bat_priv,
449 struct batadv_orig_node *orig_node)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000450{
Sven Eckelmann56303d32012-06-05 22:31:31 +0200451 struct batadv_neigh_node *best_neigh_node;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000452
Sven Eckelmann42d0b0442012-06-03 22:19:17 +0200453 if (batadv_has_timed_out(orig_node->last_seen,
454 2 * BATADV_PURGE_TIMEOUT)) {
Sven Eckelmann39c75a52012-06-03 22:19:22 +0200455 batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
Sven Eckelmann1eda58b2012-05-12 13:48:58 +0200456 "Originator timeout: originator %pM, last_seen %u\n",
457 orig_node->orig,
458 jiffies_to_msecs(orig_node->last_seen));
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000459 return true;
460 } else {
Sven Eckelmann03fc7f82012-05-12 18:34:00 +0200461 if (batadv_purge_orig_neighbors(bat_priv, orig_node,
462 &best_neigh_node))
Sven Eckelmann30d3c512012-05-12 02:09:36 +0200463 batadv_update_route(bat_priv, orig_node,
464 best_neigh_node);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000465 }
466
467 return false;
468}
469
Sven Eckelmann56303d32012-06-05 22:31:31 +0200470static void _batadv_purge_orig(struct batadv_priv *bat_priv)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000471{
Sven Eckelmann5bf74e92012-06-05 22:31:28 +0200472 struct batadv_hashtable *hash = bat_priv->orig_hash;
Sasha Levinb67bfe02013-02-27 17:06:00 -0800473 struct hlist_node *node_tmp;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000474 struct hlist_head *head;
Marek Lindnerfb778ea2011-01-19 20:01:40 +0000475 spinlock_t *list_lock; /* spinlock to protect write access */
Sven Eckelmann56303d32012-06-05 22:31:31 +0200476 struct batadv_orig_node *orig_node;
Antonio Quartullic90681b2011-10-05 17:05:25 +0200477 uint32_t i;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000478
479 if (!hash)
480 return;
481
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000482 /* for all origins... */
483 for (i = 0; i < hash->size; i++) {
484 head = &hash->table[i];
Marek Lindnerfb778ea2011-01-19 20:01:40 +0000485 list_lock = &hash->list_locks[i];
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000486
Marek Lindnerfb778ea2011-01-19 20:01:40 +0000487 spin_lock_bh(list_lock);
Sasha Levinb67bfe02013-02-27 17:06:00 -0800488 hlist_for_each_entry_safe(orig_node, node_tmp,
Marek Lindner7aadf882011-02-18 12:28:09 +0000489 head, hash_entry) {
Sven Eckelmann03fc7f82012-05-12 18:34:00 +0200490 if (batadv_purge_orig_node(bat_priv, orig_node)) {
Marek Lindner414254e2013-04-23 21:39:58 +0800491 batadv_gw_node_delete(bat_priv, orig_node);
Sasha Levinb67bfe02013-02-27 17:06:00 -0800492 hlist_del_rcu(&orig_node->hash_entry);
Sven Eckelmann7d211ef2012-05-12 02:09:34 +0200493 batadv_orig_node_free_ref(orig_node);
Marek Lindnerfb778ea2011-01-19 20:01:40 +0000494 continue;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000495 }
Martin Hundebøll610bfc6bc2013-05-23 16:53:02 +0200496
497 batadv_frag_purge_orig(orig_node,
498 batadv_frag_check_entry);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000499 }
Marek Lindnerfb778ea2011-01-19 20:01:40 +0000500 spin_unlock_bh(list_lock);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000501 }
502
Sven Eckelmann7cf06bc2012-05-12 02:09:29 +0200503 batadv_gw_node_purge(bat_priv);
504 batadv_gw_election(bat_priv);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000505}
506
Sven Eckelmann03fc7f82012-05-12 18:34:00 +0200507static void batadv_purge_orig(struct work_struct *work)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000508{
Sven Eckelmann56303d32012-06-05 22:31:31 +0200509 struct delayed_work *delayed_work;
510 struct batadv_priv *bat_priv;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000511
Sven Eckelmann56303d32012-06-05 22:31:31 +0200512 delayed_work = container_of(work, struct delayed_work, work);
513 bat_priv = container_of(delayed_work, struct batadv_priv, orig_work);
Sven Eckelmann03fc7f82012-05-12 18:34:00 +0200514 _batadv_purge_orig(bat_priv);
Antonio Quartulli72414442012-12-25 13:14:37 +0100515 queue_delayed_work(batadv_event_workqueue,
516 &bat_priv->orig_work,
517 msecs_to_jiffies(BATADV_ORIG_WORK_PERIOD));
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000518}
519
Sven Eckelmann56303d32012-06-05 22:31:31 +0200520void batadv_purge_orig_ref(struct batadv_priv *bat_priv)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000521{
Sven Eckelmann03fc7f82012-05-12 18:34:00 +0200522 _batadv_purge_orig(bat_priv);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000523}
524
Sven Eckelmann7d211ef2012-05-12 02:09:34 +0200525int batadv_orig_seq_print_text(struct seq_file *seq, void *offset)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000526{
527 struct net_device *net_dev = (struct net_device *)seq->private;
Sven Eckelmann56303d32012-06-05 22:31:31 +0200528 struct batadv_priv *bat_priv = netdev_priv(net_dev);
Sven Eckelmann5bf74e92012-06-05 22:31:28 +0200529 struct batadv_hashtable *hash = bat_priv->orig_hash;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000530 struct hlist_head *head;
Sven Eckelmann56303d32012-06-05 22:31:31 +0200531 struct batadv_hard_iface *primary_if;
532 struct batadv_orig_node *orig_node;
533 struct batadv_neigh_node *neigh_node, *neigh_node_tmp;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000534 int batman_count = 0;
535 int last_seen_secs;
536 int last_seen_msecs;
Sven Eckelmann0aca2362012-06-19 20:26:30 +0200537 unsigned long last_seen_jiffies;
Antonio Quartullic90681b2011-10-05 17:05:25 +0200538 uint32_t i;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000539
Marek Lindner30da63a2012-08-03 17:15:46 +0200540 primary_if = batadv_seq_print_text_primary_if_get(seq);
541 if (!primary_if)
Marek Lindner32ae9b22011-04-20 15:40:58 +0200542 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000543
Sven Eckelmann44c43492011-07-05 10:42:51 +0200544 seq_printf(seq, "[B.A.T.M.A.N. adv %s, MainIF/MAC: %s/%pM (%s)]\n",
Sven Eckelmann42d0b0442012-06-03 22:19:17 +0200545 BATADV_SOURCE_VERSION, primary_if->net_dev->name,
Marek Lindner32ae9b22011-04-20 15:40:58 +0200546 primary_if->net_dev->dev_addr, net_dev->name);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000547 seq_printf(seq, " %-15s %s (%s/%i) %17s [%10s]: %20s ...\n",
Sven Eckelmann42d0b0442012-06-03 22:19:17 +0200548 "Originator", "last-seen", "#", BATADV_TQ_MAX_VALUE,
549 "Nexthop", "outgoingIF", "Potential nexthops");
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000550
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000551 for (i = 0; i < hash->size; i++) {
552 head = &hash->table[i];
553
Marek Lindnerfb778ea2011-01-19 20:01:40 +0000554 rcu_read_lock();
Sasha Levinb67bfe02013-02-27 17:06:00 -0800555 hlist_for_each_entry_rcu(orig_node, head, hash_entry) {
Sven Eckelmann7d211ef2012-05-12 02:09:34 +0200556 neigh_node = batadv_orig_node_get_router(orig_node);
Linus LĂĽssinge1a5382f2011-03-14 22:43:37 +0000557 if (!neigh_node)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000558 continue;
559
Linus LĂĽssinge1a5382f2011-03-14 22:43:37 +0000560 if (neigh_node->tq_avg == 0)
561 goto next;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000562
Sven Eckelmann0aca2362012-06-19 20:26:30 +0200563 last_seen_jiffies = jiffies - orig_node->last_seen;
564 last_seen_msecs = jiffies_to_msecs(last_seen_jiffies);
565 last_seen_secs = last_seen_msecs / 1000;
566 last_seen_msecs = last_seen_msecs % 1000;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000567
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000568 seq_printf(seq, "%pM %4i.%03is (%3i) %pM [%10s]:",
569 orig_node->orig, last_seen_secs,
570 last_seen_msecs, neigh_node->tq_avg,
571 neigh_node->addr,
572 neigh_node->if_incoming->net_dev->name);
573
Sasha Levinb67bfe02013-02-27 17:06:00 -0800574 hlist_for_each_entry_rcu(neigh_node_tmp,
Marek Lindnerf987ed62010-12-12 21:57:12 +0000575 &orig_node->neigh_list, list) {
Linus LĂĽssinge1a5382f2011-03-14 22:43:37 +0000576 seq_printf(seq, " %pM (%3i)",
577 neigh_node_tmp->addr,
578 neigh_node_tmp->tq_avg);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000579 }
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000580
Antonio Quartulli0c814652013-03-21 09:23:29 +0100581 seq_puts(seq, "\n");
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000582 batman_count++;
Linus LĂĽssinge1a5382f2011-03-14 22:43:37 +0000583
584next:
Sven Eckelmann7d211ef2012-05-12 02:09:34 +0200585 batadv_neigh_node_free_ref(neigh_node);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000586 }
Marek Lindnerfb778ea2011-01-19 20:01:40 +0000587 rcu_read_unlock();
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000588 }
589
Linus LĂĽssinge1a5382f2011-03-14 22:43:37 +0000590 if (batman_count == 0)
Antonio Quartulli0c814652013-03-21 09:23:29 +0100591 seq_puts(seq, "No batman nodes in range ...\n");
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000592
Marek Lindner32ae9b22011-04-20 15:40:58 +0200593out:
594 if (primary_if)
Sven Eckelmanne5d89252012-05-12 13:48:54 +0200595 batadv_hardif_free_ref(primary_if);
Marek Lindner30da63a2012-08-03 17:15:46 +0200596 return 0;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000597}
598
Sven Eckelmann56303d32012-06-05 22:31:31 +0200599static int batadv_orig_node_add_if(struct batadv_orig_node *orig_node,
600 int max_if_num)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000601{
602 void *data_ptr;
Sven Eckelmann42d0b0442012-06-03 22:19:17 +0200603 size_t data_size, old_size;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000604
Sven Eckelmann42d0b0442012-06-03 22:19:17 +0200605 data_size = max_if_num * sizeof(unsigned long) * BATADV_NUM_WORDS;
606 old_size = (max_if_num - 1) * sizeof(unsigned long) * BATADV_NUM_WORDS;
607 data_ptr = kmalloc(data_size, GFP_ATOMIC);
Joe Perches320f4222011-08-29 14:17:24 -0700608 if (!data_ptr)
Sven Eckelmann5346c352012-05-05 13:27:28 +0200609 return -ENOMEM;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000610
Sven Eckelmann42d0b0442012-06-03 22:19:17 +0200611 memcpy(data_ptr, orig_node->bcast_own, old_size);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000612 kfree(orig_node->bcast_own);
613 orig_node->bcast_own = data_ptr;
614
615 data_ptr = kmalloc(max_if_num * sizeof(uint8_t), GFP_ATOMIC);
Joe Perches320f4222011-08-29 14:17:24 -0700616 if (!data_ptr)
Sven Eckelmann5346c352012-05-05 13:27:28 +0200617 return -ENOMEM;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000618
619 memcpy(data_ptr, orig_node->bcast_own_sum,
620 (max_if_num - 1) * sizeof(uint8_t));
621 kfree(orig_node->bcast_own_sum);
622 orig_node->bcast_own_sum = data_ptr;
623
624 return 0;
625}
626
Sven Eckelmann56303d32012-06-05 22:31:31 +0200627int batadv_orig_hash_add_if(struct batadv_hard_iface *hard_iface,
628 int max_if_num)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000629{
Sven Eckelmann56303d32012-06-05 22:31:31 +0200630 struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
Sven Eckelmann5bf74e92012-06-05 22:31:28 +0200631 struct batadv_hashtable *hash = bat_priv->orig_hash;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000632 struct hlist_head *head;
Sven Eckelmann56303d32012-06-05 22:31:31 +0200633 struct batadv_orig_node *orig_node;
Antonio Quartullic90681b2011-10-05 17:05:25 +0200634 uint32_t i;
635 int ret;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000636
637 /* resize all orig nodes because orig_node->bcast_own(_sum) depend on
Sven Eckelmann9cfc7bd2012-05-12 02:09:43 +0200638 * if_num
639 */
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000640 for (i = 0; i < hash->size; i++) {
641 head = &hash->table[i];
642
Marek Lindnerfb778ea2011-01-19 20:01:40 +0000643 rcu_read_lock();
Sasha Levinb67bfe02013-02-27 17:06:00 -0800644 hlist_for_each_entry_rcu(orig_node, head, hash_entry) {
Marek Lindner2ae2daf2011-01-19 20:01:42 +0000645 spin_lock_bh(&orig_node->ogm_cnt_lock);
Sven Eckelmann03fc7f82012-05-12 18:34:00 +0200646 ret = batadv_orig_node_add_if(orig_node, max_if_num);
Marek Lindner2ae2daf2011-01-19 20:01:42 +0000647 spin_unlock_bh(&orig_node->ogm_cnt_lock);
648
Sven Eckelmann5346c352012-05-05 13:27:28 +0200649 if (ret == -ENOMEM)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000650 goto err;
651 }
Marek Lindnerfb778ea2011-01-19 20:01:40 +0000652 rcu_read_unlock();
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000653 }
654
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000655 return 0;
656
657err:
Marek Lindnerfb778ea2011-01-19 20:01:40 +0000658 rcu_read_unlock();
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000659 return -ENOMEM;
660}
661
Sven Eckelmann56303d32012-06-05 22:31:31 +0200662static int batadv_orig_node_del_if(struct batadv_orig_node *orig_node,
Sven Eckelmann03fc7f82012-05-12 18:34:00 +0200663 int max_if_num, int del_if_num)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000664{
665 void *data_ptr = NULL;
666 int chunk_size;
667
668 /* last interface was removed */
669 if (max_if_num == 0)
670 goto free_bcast_own;
671
Sven Eckelmann42d0b0442012-06-03 22:19:17 +0200672 chunk_size = sizeof(unsigned long) * BATADV_NUM_WORDS;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000673 data_ptr = kmalloc(max_if_num * chunk_size, GFP_ATOMIC);
Joe Perches320f4222011-08-29 14:17:24 -0700674 if (!data_ptr)
Sven Eckelmann5346c352012-05-05 13:27:28 +0200675 return -ENOMEM;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000676
677 /* copy first part */
678 memcpy(data_ptr, orig_node->bcast_own, del_if_num * chunk_size);
679
680 /* copy second part */
Sven Eckelmann38e3c5f2011-05-14 23:14:49 +0200681 memcpy((char *)data_ptr + del_if_num * chunk_size,
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000682 orig_node->bcast_own + ((del_if_num + 1) * chunk_size),
683 (max_if_num - del_if_num) * chunk_size);
684
685free_bcast_own:
686 kfree(orig_node->bcast_own);
687 orig_node->bcast_own = data_ptr;
688
689 if (max_if_num == 0)
690 goto free_own_sum;
691
692 data_ptr = kmalloc(max_if_num * sizeof(uint8_t), GFP_ATOMIC);
Joe Perches320f4222011-08-29 14:17:24 -0700693 if (!data_ptr)
Sven Eckelmann5346c352012-05-05 13:27:28 +0200694 return -ENOMEM;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000695
696 memcpy(data_ptr, orig_node->bcast_own_sum,
697 del_if_num * sizeof(uint8_t));
698
Sven Eckelmann38e3c5f2011-05-14 23:14:49 +0200699 memcpy((char *)data_ptr + del_if_num * sizeof(uint8_t),
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000700 orig_node->bcast_own_sum + ((del_if_num + 1) * sizeof(uint8_t)),
701 (max_if_num - del_if_num) * sizeof(uint8_t));
702
703free_own_sum:
704 kfree(orig_node->bcast_own_sum);
705 orig_node->bcast_own_sum = data_ptr;
706
707 return 0;
708}
709
Sven Eckelmann56303d32012-06-05 22:31:31 +0200710int batadv_orig_hash_del_if(struct batadv_hard_iface *hard_iface,
711 int max_if_num)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000712{
Sven Eckelmann56303d32012-06-05 22:31:31 +0200713 struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
Sven Eckelmann5bf74e92012-06-05 22:31:28 +0200714 struct batadv_hashtable *hash = bat_priv->orig_hash;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000715 struct hlist_head *head;
Sven Eckelmann56303d32012-06-05 22:31:31 +0200716 struct batadv_hard_iface *hard_iface_tmp;
717 struct batadv_orig_node *orig_node;
Antonio Quartullic90681b2011-10-05 17:05:25 +0200718 uint32_t i;
719 int ret;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000720
721 /* resize all orig nodes because orig_node->bcast_own(_sum) depend on
Sven Eckelmann9cfc7bd2012-05-12 02:09:43 +0200722 * if_num
723 */
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000724 for (i = 0; i < hash->size; i++) {
725 head = &hash->table[i];
726
Marek Lindnerfb778ea2011-01-19 20:01:40 +0000727 rcu_read_lock();
Sasha Levinb67bfe02013-02-27 17:06:00 -0800728 hlist_for_each_entry_rcu(orig_node, head, hash_entry) {
Marek Lindner2ae2daf2011-01-19 20:01:42 +0000729 spin_lock_bh(&orig_node->ogm_cnt_lock);
Sven Eckelmann03fc7f82012-05-12 18:34:00 +0200730 ret = batadv_orig_node_del_if(orig_node, max_if_num,
731 hard_iface->if_num);
Marek Lindner2ae2daf2011-01-19 20:01:42 +0000732 spin_unlock_bh(&orig_node->ogm_cnt_lock);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000733
Sven Eckelmann5346c352012-05-05 13:27:28 +0200734 if (ret == -ENOMEM)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000735 goto err;
736 }
Marek Lindnerfb778ea2011-01-19 20:01:40 +0000737 rcu_read_unlock();
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000738 }
739
740 /* renumber remaining batman interfaces _inside_ of orig_hash_lock */
741 rcu_read_lock();
Sven Eckelmann3193e8f2012-05-12 02:09:42 +0200742 list_for_each_entry_rcu(hard_iface_tmp, &batadv_hardif_list, list) {
Sven Eckelmanne9a4f292012-06-03 22:19:19 +0200743 if (hard_iface_tmp->if_status == BATADV_IF_NOT_IN_USE)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000744 continue;
745
Marek Lindnere6c10f42011-02-18 12:33:20 +0000746 if (hard_iface == hard_iface_tmp)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000747 continue;
748
Marek Lindnere6c10f42011-02-18 12:33:20 +0000749 if (hard_iface->soft_iface != hard_iface_tmp->soft_iface)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000750 continue;
751
Marek Lindnere6c10f42011-02-18 12:33:20 +0000752 if (hard_iface_tmp->if_num > hard_iface->if_num)
753 hard_iface_tmp->if_num--;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000754 }
755 rcu_read_unlock();
756
Marek Lindnere6c10f42011-02-18 12:33:20 +0000757 hard_iface->if_num = -1;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000758 return 0;
759
760err:
Marek Lindnerfb778ea2011-01-19 20:01:40 +0000761 rcu_read_unlock();
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000762 return -ENOMEM;
763}