Blame view

net/batman-adv/main.c 37.1 KB
0046b0402   Sven Eckelmann   batman-adv: updat...
1
  /* Copyright (C) 2007-2016  B.A.T.M.A.N. contributors:
c6c8fea29   Sven Eckelmann   net: Add batman-a...
2
3
4
5
6
7
8
9
10
11
12
13
14
   *
   * 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
ebf38fb7a   Antonio Quartulli   batman-adv: remov...
15
   * along with this program; if not, see <http://www.gnu.org/licenses/>.
c6c8fea29   Sven Eckelmann   net: Add batman-a...
16
   */
1e2c2a4fe   Sven Eckelmann   batman-adv: Add r...
17
18
19
20
21
  #include "main.h"
  
  #include <linux/atomic.h>
  #include <linux/bug.h>
  #include <linux/byteorder/generic.h>
95a066d82   Sven Eckelmann   batman-adv: Add f...
22
  #include <linux/crc32c.h>
1e2c2a4fe   Sven Eckelmann   batman-adv: Add r...
23
24
25
  #include <linux/errno.h>
  #include <linux/fs.h>
  #include <linux/if_ether.h>
c54f38c9a   Simon Wunderlich   batman-adv: set s...
26
  #include <linux/if_vlan.h>
1e2c2a4fe   Sven Eckelmann   batman-adv: Add r...
27
28
29
30
  #include <linux/init.h>
  #include <linux/ip.h>
  #include <linux/ipv6.h>
  #include <linux/kernel.h>
f7157dd13   Sven Eckelmann   batman-adv: Conve...
31
  #include <linux/kref.h>
1e2c2a4fe   Sven Eckelmann   batman-adv: Add r...
32
  #include <linux/list.h>
2c72d655b   Sven Eckelmann   batman-adv: Annot...
33
  #include <linux/lockdep.h>
1e2c2a4fe   Sven Eckelmann   batman-adv: Add r...
34
35
36
37
38
39
40
41
42
43
44
45
46
  #include <linux/module.h>
  #include <linux/moduleparam.h>
  #include <linux/netdevice.h>
  #include <linux/pkt_sched.h>
  #include <linux/rculist.h>
  #include <linux/rcupdate.h>
  #include <linux/seq_file.h>
  #include <linux/skbuff.h>
  #include <linux/slab.h>
  #include <linux/spinlock.h>
  #include <linux/stddef.h>
  #include <linux/string.h>
  #include <linux/workqueue.h>
c54f38c9a   Simon Wunderlich   batman-adv: set s...
47
  #include <net/dsfield.h>
1e2c2a4fe   Sven Eckelmann   batman-adv: Add r...
48
49
50
51
  #include <net/rtnetlink.h>
  
  #include "bat_algo.h"
  #include "bridge_loop_avoidance.h"
b706b13b6   Sven Eckelmann   batman-adv: Remov...
52
  #include "debugfs.h"
1e2c2a4fe   Sven Eckelmann   batman-adv: Add r...
53
54
55
56
57
58
59
60
61
  #include "distributed-arp-table.h"
  #include "gateway_client.h"
  #include "gateway_common.h"
  #include "hard-interface.h"
  #include "icmp_socket.h"
  #include "multicast.h"
  #include "network-coding.h"
  #include "originator.h"
  #include "packet.h"
c6c8fea29   Sven Eckelmann   net: Add batman-a...
62
63
  #include "routing.h"
  #include "send.h"
c6c8fea29   Sven Eckelmann   net: Add batman-a...
64
  #include "soft-interface.h"
c6c8fea29   Sven Eckelmann   net: Add batman-a...
65
  #include "translation-table.h"
c6c8fea29   Sven Eckelmann   net: Add batman-a...
66

c3caf5196   Sven Eckelmann   batman-adv: Remov...
67
  /* List manipulations on hardif_list have to be rtnl_lock()'ed,
9cfc7bd60   Sven Eckelmann   batman-adv: Refor...
68
69
   * list traversals just rcu-locked
   */
3193e8fdf   Sven Eckelmann   batman-adv: Prefi...
70
  struct list_head batadv_hardif_list;
ee11ad61f   Sven Eckelmann   batman-adv: Prefi...
71
  static int (*batadv_rx_handler[256])(struct sk_buff *,
56303d34a   Sven Eckelmann   batman-adv: Prefi...
72
  				     struct batadv_hard_iface *);
3193e8fdf   Sven Eckelmann   batman-adv: Prefi...
73
  char batadv_routing_algo[20] = "BATMAN_IV";
ee11ad61f   Sven Eckelmann   batman-adv: Prefi...
74
  static struct hlist_head batadv_algo_list;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
75

3193e8fdf   Sven Eckelmann   batman-adv: Prefi...
76
  unsigned char batadv_broadcast_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
c6c8fea29   Sven Eckelmann   net: Add batman-a...
77

3193e8fdf   Sven Eckelmann   batman-adv: Prefi...
78
  struct workqueue_struct *batadv_event_workqueue;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
79

ee11ad61f   Sven Eckelmann   batman-adv: Prefi...
80
  static void batadv_recv_handler_init(void);
ffa995e03   Marek Lindner   batman-adv: intro...
81

ee11ad61f   Sven Eckelmann   batman-adv: Prefi...
82
  static int __init batadv_init(void)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
83
  {
3193e8fdf   Sven Eckelmann   batman-adv: Prefi...
84
  	INIT_LIST_HEAD(&batadv_hardif_list);
ee11ad61f   Sven Eckelmann   batman-adv: Prefi...
85
  	INIT_HLIST_HEAD(&batadv_algo_list);
1c280471b   Marek Lindner   batman-adv: add i...
86

ee11ad61f   Sven Eckelmann   batman-adv: Prefi...
87
  	batadv_recv_handler_init();
ffa995e03   Marek Lindner   batman-adv: intro...
88

81c524f76   Sven Eckelmann   batman-adv: Prefi...
89
  	batadv_iv_init();
6c519bad7   Matthias Schiffer   batman-adv: set u...
90
  	batadv_nc_init();
c6c8fea29   Sven Eckelmann   net: Add batman-a...
91

3193e8fdf   Sven Eckelmann   batman-adv: Prefi...
92
  	batadv_event_workqueue = create_singlethread_workqueue("bat_events");
c6c8fea29   Sven Eckelmann   net: Add batman-a...
93

3193e8fdf   Sven Eckelmann   batman-adv: Prefi...
94
  	if (!batadv_event_workqueue)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
95
  		return -ENOMEM;
9039dc7e8   Sven Eckelmann   batman-adv: Prefi...
96
  	batadv_socket_init();
40a072d77   Sven Eckelmann   batman-adv: Prefi...
97
  	batadv_debugfs_init();
c6c8fea29   Sven Eckelmann   net: Add batman-a...
98

9563877ea   Sven Eckelmann   batman-adv: Prefi...
99
  	register_netdevice_notifier(&batadv_hard_if_notifier);
a4ac28c0d   Sven Eckelmann   batman-adv: Allow...
100
  	rtnl_link_register(&batadv_link_ops);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
101

86ceb3605   Sven Eckelmann   batman-adv: Ignor...
102
103
  	pr_info("B.A.T.M.A.N. advanced %s (compatibility version %i) loaded
  ",
42d0b044b   Sven Eckelmann   batman-adv: Prefi...
104
  		BATADV_SOURCE_VERSION, BATADV_COMPAT_VERSION);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
105
106
107
  
  	return 0;
  }
ee11ad61f   Sven Eckelmann   batman-adv: Prefi...
108
  static void __exit batadv_exit(void)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
109
  {
40a072d77   Sven Eckelmann   batman-adv: Prefi...
110
  	batadv_debugfs_destroy();
a4ac28c0d   Sven Eckelmann   batman-adv: Allow...
111
  	rtnl_link_unregister(&batadv_link_ops);
9563877ea   Sven Eckelmann   batman-adv: Prefi...
112
113
  	unregister_netdevice_notifier(&batadv_hard_if_notifier);
  	batadv_hardif_remove_interfaces();
c6c8fea29   Sven Eckelmann   net: Add batman-a...
114

3193e8fdf   Sven Eckelmann   batman-adv: Prefi...
115
116
117
  	flush_workqueue(batadv_event_workqueue);
  	destroy_workqueue(batadv_event_workqueue);
  	batadv_event_workqueue = NULL;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
118
119
120
  
  	rcu_barrier();
  }
3193e8fdf   Sven Eckelmann   batman-adv: Prefi...
121
  int batadv_mesh_init(struct net_device *soft_iface)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
122
  {
56303d34a   Sven Eckelmann   batman-adv: Prefi...
123
  	struct batadv_priv *bat_priv = netdev_priv(soft_iface);
5346c35eb   Sven Eckelmann   batman-adv: Retur...
124
  	int ret;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
125

c6c8fea29   Sven Eckelmann   net: Add batman-a...
126
127
  	spin_lock_init(&bat_priv->forw_bat_list_lock);
  	spin_lock_init(&bat_priv->forw_bcast_list_lock);
807736f6e   Sven Eckelmann   batman-adv: Split...
128
129
130
131
  	spin_lock_init(&bat_priv->tt.changes_list_lock);
  	spin_lock_init(&bat_priv->tt.req_list_lock);
  	spin_lock_init(&bat_priv->tt.roam_list_lock);
  	spin_lock_init(&bat_priv->tt.last_changeset_lock);
a70a9aa99   Antonio Quartulli   batman-adv: lock ...
132
  	spin_lock_init(&bat_priv->tt.commit_lock);
807736f6e   Sven Eckelmann   batman-adv: Split...
133
  	spin_lock_init(&bat_priv->gw.list_lock);
ab49886e3   Linus Lüssing   batman-adv: Add I...
134
135
136
  #ifdef CONFIG_BATMAN_ADV_MCAST
  	spin_lock_init(&bat_priv->mcast.want_lists_lock);
  #endif
ef2615774   Marek Lindner   batman-adv: tvlv ...
137
138
  	spin_lock_init(&bat_priv->tvlv.container_list_lock);
  	spin_lock_init(&bat_priv->tvlv.handler_list_lock);
5d2c05b21   Antonio Quartulli   batman-adv: add p...
139
  	spin_lock_init(&bat_priv->softif_vlan_list_lock);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
140
141
142
  
  	INIT_HLIST_HEAD(&bat_priv->forw_bat_list);
  	INIT_HLIST_HEAD(&bat_priv->forw_bcast_list);
807736f6e   Sven Eckelmann   batman-adv: Split...
143
  	INIT_HLIST_HEAD(&bat_priv->gw.list);
ab49886e3   Linus Lüssing   batman-adv: Add I...
144
145
  #ifdef CONFIG_BATMAN_ADV_MCAST
  	INIT_HLIST_HEAD(&bat_priv->mcast.want_all_unsnoopables_list);
4c8755d69   Linus Lüssing   batman-adv: Send ...
146
147
  	INIT_HLIST_HEAD(&bat_priv->mcast.want_all_ipv4_list);
  	INIT_HLIST_HEAD(&bat_priv->mcast.want_all_ipv6_list);
ab49886e3   Linus Lüssing   batman-adv: Add I...
148
  #endif
807736f6e   Sven Eckelmann   batman-adv: Split...
149
  	INIT_LIST_HEAD(&bat_priv->tt.changes_list);
7c26a53ba   Marek Lindner   batman-adv: conve...
150
  	INIT_HLIST_HEAD(&bat_priv->tt.req_list);
807736f6e   Sven Eckelmann   batman-adv: Split...
151
  	INIT_LIST_HEAD(&bat_priv->tt.roam_list);
c5caf4ef3   Linus Lüssing   batman-adv: Multi...
152
153
154
  #ifdef CONFIG_BATMAN_ADV_MCAST
  	INIT_HLIST_HEAD(&bat_priv->mcast.mla_list);
  #endif
ef2615774   Marek Lindner   batman-adv: tvlv ...
155
156
  	INIT_HLIST_HEAD(&bat_priv->tvlv.container_list);
  	INIT_HLIST_HEAD(&bat_priv->tvlv.handler_list);
5d2c05b21   Antonio Quartulli   batman-adv: add p...
157
  	INIT_HLIST_HEAD(&bat_priv->softif_vlan_list);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
158

7d211efc5   Sven Eckelmann   batman-adv: Prefi...
159
  	ret = batadv_originator_init(bat_priv);
5346c35eb   Sven Eckelmann   batman-adv: Retur...
160
  	if (ret < 0)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
161
  		goto err;
08c36d3e8   Sven Eckelmann   batman-adv: Prefi...
162
  	ret = batadv_tt_init(bat_priv);
5346c35eb   Sven Eckelmann   batman-adv: Retur...
163
  	if (ret < 0)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
164
  		goto err;
08adf1512   Sven Eckelmann   batman-adv: Prefi...
165
  	ret = batadv_bla_init(bat_priv);
5346c35eb   Sven Eckelmann   batman-adv: Retur...
166
  	if (ret < 0)
23721387c   Simon Wunderlich   batman-adv: add b...
167
  		goto err;
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
168
169
170
  	ret = batadv_dat_init(bat_priv);
  	if (ret < 0)
  		goto err;
6c519bad7   Matthias Schiffer   batman-adv: set u...
171
  	ret = batadv_nc_mesh_init(bat_priv);
d353d8d4d   Martin Hundebøll   batman-adv: netwo...
172
173
  	if (ret < 0)
  		goto err;
414254e34   Marek Lindner   batman-adv: tvlv ...
174
  	batadv_gw_init(bat_priv);
60432d756   Linus Lüssing   batman-adv: Annou...
175
  	batadv_mcast_init(bat_priv);
414254e34   Marek Lindner   batman-adv: tvlv ...
176

807736f6e   Sven Eckelmann   batman-adv: Split...
177
  	atomic_set(&bat_priv->gw.reselect, 0);
39c75a51e   Sven Eckelmann   batman-adv: Prefi...
178
  	atomic_set(&bat_priv->mesh_state, BATADV_MESH_ACTIVE);
5346c35eb   Sven Eckelmann   batman-adv: Retur...
179
180
  
  	return 0;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
181
182
  
  err:
3193e8fdf   Sven Eckelmann   batman-adv: Prefi...
183
  	batadv_mesh_free(soft_iface);
5346c35eb   Sven Eckelmann   batman-adv: Retur...
184
  	return ret;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
185
  }
3193e8fdf   Sven Eckelmann   batman-adv: Prefi...
186
  void batadv_mesh_free(struct net_device *soft_iface)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
187
  {
56303d34a   Sven Eckelmann   batman-adv: Prefi...
188
  	struct batadv_priv *bat_priv = netdev_priv(soft_iface);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
189

39c75a51e   Sven Eckelmann   batman-adv: Prefi...
190
  	atomic_set(&bat_priv->mesh_state, BATADV_MESH_DEACTIVATING);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
191

9455e34cb   Sven Eckelmann   batman-adv: Prefi...
192
  	batadv_purge_outstanding_packets(bat_priv, NULL);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
193

bd3524c14   Simon Wunderlich   batman-adv: remov...
194
  	batadv_gw_node_free(bat_priv);
6c519bad7   Matthias Schiffer   batman-adv: set u...
195
  	batadv_nc_mesh_free(bat_priv);
a43618603   Antonio Quartulli   batman-adv: reord...
196
197
  	batadv_dat_free(bat_priv);
  	batadv_bla_free(bat_priv);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
198

c5caf4ef3   Linus Lüssing   batman-adv: Multi...
199
  	batadv_mcast_free(bat_priv);
a43618603   Antonio Quartulli   batman-adv: reord...
200
201
202
203
  	/* Free the TT and the originator tables only after having terminated
  	 * all the other depending components which may use these structures for
  	 * their purposes.
  	 */
08c36d3e8   Sven Eckelmann   batman-adv: Prefi...
204
  	batadv_tt_free(bat_priv);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
205

a43618603   Antonio Quartulli   batman-adv: reord...
206
207
208
209
210
211
  	/* Since the originator table clean up routine is accessing the TT
  	 * tables as well, it has to be invoked after the TT tables have been
  	 * freed and marked as empty. This ensures that no cleanup RCU callbacks
  	 * accessing the TT data are scheduled for later execution.
  	 */
  	batadv_originator_free(bat_priv);
2f1dfbe18   Antonio Quartulli   batman-adv: Distr...
212

414254e34   Marek Lindner   batman-adv: tvlv ...
213
  	batadv_gw_free(bat_priv);
f8214865a   Martin Hundebøll   batman-adv: Add g...
214
  	free_percpu(bat_priv->bat_counters);
f69ae770e   Martin Hundebøll   batman-adv: Avoid...
215
  	bat_priv->bat_counters = NULL;
f8214865a   Martin Hundebøll   batman-adv: Add g...
216

39c75a51e   Sven Eckelmann   batman-adv: Prefi...
217
  	atomic_set(&bat_priv->mesh_state, BATADV_MESH_INACTIVE);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
218
  }
6e0895c2e   David S. Miller   Merge git://git.k...
219
220
221
222
223
  /**
   * batadv_is_my_mac - check if the given mac address belongs to any of the real
   * interfaces in the current mesh
   * @bat_priv: the bat priv with all the soft interface information
   * @addr: the address to check
e8ad3b1ac   Markus Pargmann   batman-adv: main,...
224
   *
62fe710f6   Sven Eckelmann   batman-adv: Fix k...
225
   * Return: 'true' if the mac address was found, false otherwise.
6e0895c2e   David S. Miller   Merge git://git.k...
226
   */
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
227
  bool batadv_is_my_mac(struct batadv_priv *bat_priv, const u8 *addr)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
228
  {
56303d34a   Sven Eckelmann   batman-adv: Prefi...
229
  	const struct batadv_hard_iface *hard_iface;
e8ad3b1ac   Markus Pargmann   batman-adv: main,...
230
  	bool is_my_mac = false;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
231
232
  
  	rcu_read_lock();
3193e8fdf   Sven Eckelmann   batman-adv: Prefi...
233
  	list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
e9a4f295e   Sven Eckelmann   batman-adv: Prefi...
234
  		if (hard_iface->if_status != BATADV_IF_ACTIVE)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
235
  			continue;
fe8a93b95   Antonio Quartulli   batman-adv: make ...
236
237
  		if (hard_iface->soft_iface != bat_priv->soft_iface)
  			continue;
1eda58bfc   Sven Eckelmann   batman-adv: Prefi...
238
  		if (batadv_compare_eth(hard_iface->net_dev->dev_addr, addr)) {
e8ad3b1ac   Markus Pargmann   batman-adv: main,...
239
240
  			is_my_mac = true;
  			break;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
241
242
243
  		}
  	}
  	rcu_read_unlock();
e8ad3b1ac   Markus Pargmann   batman-adv: main,...
244
  	return is_my_mac;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
245
  }
30da63a6a   Marek Lindner   batman-adv: conso...
246
247
248
249
250
  /**
   * batadv_seq_print_text_primary_if_get - called from debugfs table printing
   *  function that requires the primary interface
   * @seq: debugfs table seq_file struct
   *
62fe710f6   Sven Eckelmann   batman-adv: Fix k...
251
   * Return: primary interface if found or NULL otherwise.
30da63a6a   Marek Lindner   batman-adv: conso...
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
   */
  struct batadv_hard_iface *
  batadv_seq_print_text_primary_if_get(struct seq_file *seq)
  {
  	struct net_device *net_dev = (struct net_device *)seq->private;
  	struct batadv_priv *bat_priv = netdev_priv(net_dev);
  	struct batadv_hard_iface *primary_if;
  
  	primary_if = batadv_primary_if_get_selected(bat_priv);
  
  	if (!primary_if) {
  		seq_printf(seq,
  			   "BATMAN mesh %s disabled - please specify interfaces to enable it
  ",
  			   net_dev->name);
  		goto out;
  	}
  
  	if (primary_if->if_status == BATADV_IF_ACTIVE)
  		goto out;
  
  	seq_printf(seq,
  		   "BATMAN mesh %s disabled - primary interface not active
  ",
  		   net_dev->name);
82047ad7f   Sven Eckelmann   batman-adv: Renam...
277
  	batadv_hardif_put(primary_if);
30da63a6a   Marek Lindner   batman-adv: conso...
278
279
280
281
282
  	primary_if = NULL;
  
  out:
  	return primary_if;
  }
c54f38c9a   Simon Wunderlich   batman-adv: set s...
283
  /**
411d6ed93   Marek Lindner   batman-adv: consi...
284
285
286
   * batadv_max_header_len - calculate maximum encapsulation overhead for a
   *  payload packet
   *
62fe710f6   Sven Eckelmann   batman-adv: Fix k...
287
   * Return: the maximum encapsulation overhead in bytes.
411d6ed93   Marek Lindner   batman-adv: consi...
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
   */
  int batadv_max_header_len(void)
  {
  	int header_len = 0;
  
  	header_len = max_t(int, header_len,
  			   sizeof(struct batadv_unicast_packet));
  	header_len = max_t(int, header_len,
  			   sizeof(struct batadv_unicast_4addr_packet));
  	header_len = max_t(int, header_len,
  			   sizeof(struct batadv_bcast_packet));
  
  #ifdef CONFIG_BATMAN_ADV_NC
  	header_len = max_t(int, header_len,
  			   sizeof(struct batadv_coded_packet));
  #endif
1df0cbd50   Marek Lindner   batman-adv: fix b...
304
  	return header_len + ETH_HLEN;
411d6ed93   Marek Lindner   batman-adv: consi...
305
306
307
  }
  
  /**
c54f38c9a   Simon Wunderlich   batman-adv: set s...
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
   * batadv_skb_set_priority - sets skb priority according to packet content
   * @skb: the packet to be sent
   * @offset: offset to the packet content
   *
   * This function sets a value between 256 and 263 (802.1d priority), which
   * can be interpreted by the cfg80211 or other drivers.
   */
  void batadv_skb_set_priority(struct sk_buff *skb, int offset)
  {
  	struct iphdr ip_hdr_tmp, *ip_hdr;
  	struct ipv6hdr ip6_hdr_tmp, *ip6_hdr;
  	struct ethhdr ethhdr_tmp, *ethhdr;
  	struct vlan_ethhdr *vhdr, vhdr_tmp;
  	u32 prio;
  
  	/* already set, do nothing */
  	if (skb->priority >= 256 && skb->priority <= 263)
  		return;
  
  	ethhdr = skb_header_pointer(skb, offset, sizeof(*ethhdr), &ethhdr_tmp);
  	if (!ethhdr)
  		return;
  
  	switch (ethhdr->h_proto) {
  	case htons(ETH_P_8021Q):
  		vhdr = skb_header_pointer(skb, offset + sizeof(*vhdr),
  					  sizeof(*vhdr), &vhdr_tmp);
  		if (!vhdr)
  			return;
  		prio = ntohs(vhdr->h_vlan_TCI) & VLAN_PRIO_MASK;
  		prio = prio >> VLAN_PRIO_SHIFT;
  		break;
  	case htons(ETH_P_IP):
  		ip_hdr = skb_header_pointer(skb, offset + sizeof(*ethhdr),
  					    sizeof(*ip_hdr), &ip_hdr_tmp);
  		if (!ip_hdr)
  			return;
  		prio = (ipv4_get_dsfield(ip_hdr) & 0xfc) >> 5;
  		break;
  	case htons(ETH_P_IPV6):
  		ip6_hdr = skb_header_pointer(skb, offset + sizeof(*ethhdr),
  					     sizeof(*ip6_hdr), &ip6_hdr_tmp);
  		if (!ip6_hdr)
  			return;
  		prio = (ipv6_get_dsfield(ip6_hdr) & 0xfc) >> 5;
  		break;
  	default:
  		return;
  	}
  
  	skb->priority = prio + 256;
  }
ee11ad61f   Sven Eckelmann   batman-adv: Prefi...
360
  static int batadv_recv_unhandled_packet(struct sk_buff *skb,
56303d34a   Sven Eckelmann   batman-adv: Prefi...
361
  					struct batadv_hard_iface *recv_if)
ffa995e03   Marek Lindner   batman-adv: intro...
362
363
364
365
366
367
368
  {
  	return NET_RX_DROP;
  }
  
  /* incoming packets with the batman ethertype received on any active hard
   * interface
   */
3193e8fdf   Sven Eckelmann   batman-adv: Prefi...
369
370
371
  int batadv_batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
  			   struct packet_type *ptype,
  			   struct net_device *orig_dev)
ffa995e03   Marek Lindner   batman-adv: intro...
372
  {
56303d34a   Sven Eckelmann   batman-adv: Prefi...
373
  	struct batadv_priv *bat_priv;
964126901   Sven Eckelmann   batman-adv: Prefi...
374
  	struct batadv_ogm_packet *batadv_ogm_packet;
56303d34a   Sven Eckelmann   batman-adv: Prefi...
375
  	struct batadv_hard_iface *hard_iface;
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
376
  	u8 idx;
ffa995e03   Marek Lindner   batman-adv: intro...
377
  	int ret;
56303d34a   Sven Eckelmann   batman-adv: Prefi...
378
379
  	hard_iface = container_of(ptype, struct batadv_hard_iface,
  				  batman_adv_ptype);
ffa995e03   Marek Lindner   batman-adv: intro...
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
  	skb = skb_share_check(skb, GFP_ATOMIC);
  
  	/* skb was released by skb_share_check() */
  	if (!skb)
  		goto err_out;
  
  	/* packet should hold at least type and version */
  	if (unlikely(!pskb_may_pull(skb, 2)))
  		goto err_free;
  
  	/* expect a valid ethernet header here. */
  	if (unlikely(skb->mac_len != ETH_HLEN || !skb_mac_header(skb)))
  		goto err_free;
  
  	if (!hard_iface->soft_iface)
  		goto err_free;
  
  	bat_priv = netdev_priv(hard_iface->soft_iface);
39c75a51e   Sven Eckelmann   batman-adv: Prefi...
398
  	if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE)
ffa995e03   Marek Lindner   batman-adv: intro...
399
400
401
  		goto err_free;
  
  	/* discard frames on not active interfaces */
e9a4f295e   Sven Eckelmann   batman-adv: Prefi...
402
  	if (hard_iface->if_status != BATADV_IF_ACTIVE)
ffa995e03   Marek Lindner   batman-adv: intro...
403
  		goto err_free;
964126901   Sven Eckelmann   batman-adv: Prefi...
404
  	batadv_ogm_packet = (struct batadv_ogm_packet *)skb->data;
ffa995e03   Marek Lindner   batman-adv: intro...
405

a40d9b075   Simon Wunderlich   batman-adv: fix h...
406
  	if (batadv_ogm_packet->version != BATADV_COMPAT_VERSION) {
39c75a51e   Sven Eckelmann   batman-adv: Prefi...
407
  		batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
1eda58bfc   Sven Eckelmann   batman-adv: Prefi...
408
409
  			   "Drop packet: incompatible batman version (%i)
  ",
a40d9b075   Simon Wunderlich   batman-adv: fix h...
410
  			   batadv_ogm_packet->version);
ffa995e03   Marek Lindner   batman-adv: intro...
411
412
  		goto err_free;
  	}
e0d9677ea   Martin Hundebøll   batman-adv: clear...
413
414
  	/* reset control block to avoid left overs from previous users */
  	memset(skb->cb, 0, sizeof(struct batadv_skb_cb));
ffa995e03   Marek Lindner   batman-adv: intro...
415
416
417
  	/* all receive handlers return whether they received or reused
  	 * the supplied skb. if not, we have to free the skb.
  	 */
a40d9b075   Simon Wunderlich   batman-adv: fix h...
418
  	idx = batadv_ogm_packet->packet_type;
ee11ad61f   Sven Eckelmann   batman-adv: Prefi...
419
  	ret = (*batadv_rx_handler[idx])(skb, hard_iface);
ffa995e03   Marek Lindner   batman-adv: intro...
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
  
  	if (ret == NET_RX_DROP)
  		kfree_skb(skb);
  
  	/* return NET_RX_SUCCESS in any case as we
  	 * most probably dropped the packet for
  	 * routing-logical reasons.
  	 */
  	return NET_RX_SUCCESS;
  
  err_free:
  	kfree_skb(skb);
  err_out:
  	return NET_RX_DROP;
  }
ee11ad61f   Sven Eckelmann   batman-adv: Prefi...
435
  static void batadv_recv_handler_init(void)
ffa995e03   Marek Lindner   batman-adv: intro...
436
437
  {
  	int i;
ee11ad61f   Sven Eckelmann   batman-adv: Prefi...
438
439
  	for (i = 0; i < ARRAY_SIZE(batadv_rx_handler); i++)
  		batadv_rx_handler[i] = batadv_recv_unhandled_packet;
ffa995e03   Marek Lindner   batman-adv: intro...
440

a1f1ac5c4   Simon Wunderlich   batman-adv: reord...
441
442
  	for (i = BATADV_UNICAST_MIN; i <= BATADV_UNICAST_MAX; i++)
  		batadv_rx_handler[i] = batadv_recv_unhandled_unicast_packet;
031ace8d0   Simon Wunderlich   batman-adv: add b...
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
  	/* compile time checks for sizes */
  	BUILD_BUG_ON(sizeof(struct batadv_bla_claim_dst) != 6);
  	BUILD_BUG_ON(sizeof(struct batadv_ogm_packet) != 24);
  	BUILD_BUG_ON(sizeof(struct batadv_icmp_header) != 20);
  	BUILD_BUG_ON(sizeof(struct batadv_icmp_packet) != 20);
  	BUILD_BUG_ON(sizeof(struct batadv_icmp_packet_rr) != 116);
  	BUILD_BUG_ON(sizeof(struct batadv_unicast_packet) != 10);
  	BUILD_BUG_ON(sizeof(struct batadv_unicast_4addr_packet) != 18);
  	BUILD_BUG_ON(sizeof(struct batadv_frag_packet) != 20);
  	BUILD_BUG_ON(sizeof(struct batadv_bcast_packet) != 14);
  	BUILD_BUG_ON(sizeof(struct batadv_coded_packet) != 46);
  	BUILD_BUG_ON(sizeof(struct batadv_unicast_tvlv_packet) != 20);
  	BUILD_BUG_ON(sizeof(struct batadv_tvlv_hdr) != 4);
  	BUILD_BUG_ON(sizeof(struct batadv_tvlv_gateway_data) != 8);
  	BUILD_BUG_ON(sizeof(struct batadv_tvlv_tt_vlan_data) != 8);
  	BUILD_BUG_ON(sizeof(struct batadv_tvlv_tt_change) != 12);
  	BUILD_BUG_ON(sizeof(struct batadv_tvlv_roam_adv) != 8);
80067c832   Simon Wunderlich   batman-adv: add b...
460

a1f1ac5c4   Simon Wunderlich   batman-adv: reord...
461
462
463
464
  	/* broadcast packet */
  	batadv_rx_handler[BATADV_BCAST] = batadv_recv_bcast_packet;
  
  	/* unicast packets ... */
7cdcf6ddd   Antonio Quartulli   batman-adv: add U...
465
466
  	/* unicast with 4 addresses packet */
  	batadv_rx_handler[BATADV_UNICAST_4ADDR] = batadv_recv_unicast_packet;
ffa995e03   Marek Lindner   batman-adv: intro...
467
  	/* unicast packet */
acd34afa8   Sven Eckelmann   batman-adv: Prefi...
468
  	batadv_rx_handler[BATADV_UNICAST] = batadv_recv_unicast_packet;
ef2615774   Marek Lindner   batman-adv: tvlv ...
469
470
  	/* unicast tvlv packet */
  	batadv_rx_handler[BATADV_UNICAST_TVLV] = batadv_recv_unicast_tvlv;
a1f1ac5c4   Simon Wunderlich   batman-adv: reord...
471
472
  	/* batman icmp packet */
  	batadv_rx_handler[BATADV_ICMP] = batadv_recv_icmp_packet;
610bfc6bc   Martin Hundebøll   batman-adv: Recei...
473
474
  	/* Fragmented packets */
  	batadv_rx_handler[BATADV_UNICAST_FRAG] = batadv_recv_frag_packet;
ffa995e03   Marek Lindner   batman-adv: intro...
475
  }
56303d34a   Sven Eckelmann   batman-adv: Prefi...
476
  int
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
477
  batadv_recv_handler_register(u8 packet_type,
56303d34a   Sven Eckelmann   batman-adv: Prefi...
478
479
  			     int (*recv_handler)(struct sk_buff *,
  						 struct batadv_hard_iface *))
ffa995e03   Marek Lindner   batman-adv: intro...
480
  {
a1f1ac5c4   Simon Wunderlich   batman-adv: reord...
481
482
483
484
485
486
  	int (*curr)(struct sk_buff *,
  		    struct batadv_hard_iface *);
  	curr = batadv_rx_handler[packet_type];
  
  	if ((curr != batadv_recv_unhandled_packet) &&
  	    (curr != batadv_recv_unhandled_unicast_packet))
ffa995e03   Marek Lindner   batman-adv: intro...
487
  		return -EBUSY;
ee11ad61f   Sven Eckelmann   batman-adv: Prefi...
488
  	batadv_rx_handler[packet_type] = recv_handler;
ffa995e03   Marek Lindner   batman-adv: intro...
489
490
  	return 0;
  }
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
491
  void batadv_recv_handler_unregister(u8 packet_type)
ffa995e03   Marek Lindner   batman-adv: intro...
492
  {
ee11ad61f   Sven Eckelmann   batman-adv: Prefi...
493
  	batadv_rx_handler[packet_type] = batadv_recv_unhandled_packet;
ffa995e03   Marek Lindner   batman-adv: intro...
494
  }
56303d34a   Sven Eckelmann   batman-adv: Prefi...
495
  static struct batadv_algo_ops *batadv_algo_get(char *name)
1c280471b   Marek Lindner   batman-adv: add i...
496
  {
56303d34a   Sven Eckelmann   batman-adv: Prefi...
497
  	struct batadv_algo_ops *bat_algo_ops = NULL, *bat_algo_ops_tmp;
1c280471b   Marek Lindner   batman-adv: add i...
498

b67bfe0d4   Sasha Levin   hlist: drop the n...
499
  	hlist_for_each_entry(bat_algo_ops_tmp, &batadv_algo_list, list) {
1c280471b   Marek Lindner   batman-adv: add i...
500
501
502
503
504
505
506
507
508
  		if (strcmp(bat_algo_ops_tmp->name, name) != 0)
  			continue;
  
  		bat_algo_ops = bat_algo_ops_tmp;
  		break;
  	}
  
  	return bat_algo_ops;
  }
56303d34a   Sven Eckelmann   batman-adv: Prefi...
509
  int batadv_algo_register(struct batadv_algo_ops *bat_algo_ops)
1c280471b   Marek Lindner   batman-adv: add i...
510
  {
56303d34a   Sven Eckelmann   batman-adv: Prefi...
511
  	struct batadv_algo_ops *bat_algo_ops_tmp;
1c280471b   Marek Lindner   batman-adv: add i...
512

ee11ad61f   Sven Eckelmann   batman-adv: Prefi...
513
  	bat_algo_ops_tmp = batadv_algo_get(bat_algo_ops->name);
1c280471b   Marek Lindner   batman-adv: add i...
514
  	if (bat_algo_ops_tmp) {
86ceb3605   Sven Eckelmann   batman-adv: Ignor...
515
516
517
  		pr_info("Trying to register already registered routing algorithm: %s
  ",
  			bat_algo_ops->name);
9fb6c6519   Markus Pargmann   batman-adv: Remov...
518
  		return -EEXIST;
1c280471b   Marek Lindner   batman-adv: add i...
519
  	}
01c4224b5   Marek Lindner   batman-adv: conve...
520
  	/* all algorithms must implement all ops (for now) */
c2aca0223   Marek Lindner   batman-adv: refac...
521
  	if (!bat_algo_ops->bat_iface_enable ||
00a50076a   Marek Lindner   batman-adv: add i...
522
  	    !bat_algo_ops->bat_iface_disable ||
c32293983   Marek Lindner   batman-adv: refac...
523
  	    !bat_algo_ops->bat_iface_update_mac ||
cd8b78e7e   Marek Lindner   batman-adv: refac...
524
  	    !bat_algo_ops->bat_primary_iface_set ||
01c4224b5   Marek Lindner   batman-adv: conve...
525
  	    !bat_algo_ops->bat_ogm_schedule ||
a3285a8f2   Antonio Quartulli   batman-adv: add b...
526
  	    !bat_algo_ops->bat_ogm_emit ||
c43c981e5   Antonio Quartulli   batman-adv: add b...
527
  	    !bat_algo_ops->bat_neigh_cmp ||
18165f6f6   Simon Wunderlich   batman-adv: renam...
528
  	    !bat_algo_ops->bat_neigh_is_similar_or_better) {
01c4224b5   Marek Lindner   batman-adv: conve...
529
530
531
  		pr_info("Routing algo '%s' does not implement required ops
  ",
  			bat_algo_ops->name);
9fb6c6519   Markus Pargmann   batman-adv: Remov...
532
  		return -EINVAL;
01c4224b5   Marek Lindner   batman-adv: conve...
533
  	}
1c280471b   Marek Lindner   batman-adv: add i...
534
  	INIT_HLIST_NODE(&bat_algo_ops->list);
ee11ad61f   Sven Eckelmann   batman-adv: Prefi...
535
  	hlist_add_head(&bat_algo_ops->list, &batadv_algo_list);
1c280471b   Marek Lindner   batman-adv: add i...
536

9fb6c6519   Markus Pargmann   batman-adv: Remov...
537
  	return 0;
1c280471b   Marek Lindner   batman-adv: add i...
538
  }
56303d34a   Sven Eckelmann   batman-adv: Prefi...
539
  int batadv_algo_select(struct batadv_priv *bat_priv, char *name)
1c280471b   Marek Lindner   batman-adv: add i...
540
  {
56303d34a   Sven Eckelmann   batman-adv: Prefi...
541
  	struct batadv_algo_ops *bat_algo_ops;
1c280471b   Marek Lindner   batman-adv: add i...
542

ee11ad61f   Sven Eckelmann   batman-adv: Prefi...
543
  	bat_algo_ops = batadv_algo_get(name);
1c280471b   Marek Lindner   batman-adv: add i...
544
  	if (!bat_algo_ops)
f372d0905   Markus Pargmann   batman-adv: Remov...
545
  		return -EINVAL;
1c280471b   Marek Lindner   batman-adv: add i...
546
547
  
  	bat_priv->bat_algo_ops = bat_algo_ops;
1c280471b   Marek Lindner   batman-adv: add i...
548

f372d0905   Markus Pargmann   batman-adv: Remov...
549
  	return 0;
1c280471b   Marek Lindner   batman-adv: add i...
550
  }
3193e8fdf   Sven Eckelmann   batman-adv: Prefi...
551
  int batadv_algo_seq_print_text(struct seq_file *seq, void *offset)
1c280471b   Marek Lindner   batman-adv: add i...
552
  {
56303d34a   Sven Eckelmann   batman-adv: Prefi...
553
  	struct batadv_algo_ops *bat_algo_ops;
1c280471b   Marek Lindner   batman-adv: add i...
554

0c8146535   Antonio Quartulli   batman-adv: use s...
555
556
  	seq_puts(seq, "Available routing algorithms:
  ");
1c280471b   Marek Lindner   batman-adv: add i...
557

b67bfe0d4   Sasha Levin   hlist: drop the n...
558
  	hlist_for_each_entry(bat_algo_ops, &batadv_algo_list, list) {
854d2a63d   Marek Lindner   batman-adv: beaut...
559
560
  		seq_printf(seq, " * %s
  ", bat_algo_ops->name);
1c280471b   Marek Lindner   batman-adv: add i...
561
562
563
564
  	}
  
  	return 0;
  }
95a066d82   Sven Eckelmann   batman-adv: Add f...
565
566
567
568
569
570
571
572
573
  /**
   * batadv_skb_crc32 - calculate CRC32 of the whole packet and skip bytes in
   *  the header
   * @skb: skb pointing to fragmented socket buffers
   * @payload_ptr: Pointer to position inside the head buffer of the skb
   *  marking the start of the data to be CRC'ed
   *
   * payload_ptr must always point to an address in the skb head buffer and not to
   * a fragment.
7afcbbef6   Sven Eckelmann   batman-adv: Fix k...
574
575
   *
   * Return: big endian crc32c of the checksummed data
95a066d82   Sven Eckelmann   batman-adv: Add f...
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
   */
  __be32 batadv_skb_crc32(struct sk_buff *skb, u8 *payload_ptr)
  {
  	u32 crc = 0;
  	unsigned int from;
  	unsigned int to = skb->len;
  	struct skb_seq_state st;
  	const u8 *data;
  	unsigned int len;
  	unsigned int consumed = 0;
  
  	from = (unsigned int)(payload_ptr - skb->data);
  
  	skb_prepare_seq_read(skb, from, to, &st);
  	while ((len = skb_seq_read(consumed, &data, &st)) != 0) {
  		crc = crc32c(crc, data, len);
  		consumed += len;
  	}
95a066d82   Sven Eckelmann   batman-adv: Add f...
594
595
596
  
  	return htonl(crc);
  }
ef2615774   Marek Lindner   batman-adv: tvlv ...
597
  /**
32836f56f   Sven Eckelmann   batman-adv: Conve...
598
599
600
601
602
603
604
605
606
607
608
609
610
   * batadv_tvlv_handler_release - release tvlv handler from lists and queue for
   *  free after rcu grace period
   * @ref: kref pointer of the tvlv
   */
  static void batadv_tvlv_handler_release(struct kref *ref)
  {
  	struct batadv_tvlv_handler *tvlv_handler;
  
  	tvlv_handler = container_of(ref, struct batadv_tvlv_handler, refcount);
  	kfree_rcu(tvlv_handler, rcu);
  }
  
  /**
ba610043a   Sven Eckelmann   batman-adv: Renam...
611
   * batadv_tvlv_handler_put - decrement the tvlv container refcounter and
32836f56f   Sven Eckelmann   batman-adv: Conve...
612
   *  possibly release it
ef2615774   Marek Lindner   batman-adv: tvlv ...
613
614
   * @tvlv_handler: the tvlv handler to free
   */
ba610043a   Sven Eckelmann   batman-adv: Renam...
615
  static void batadv_tvlv_handler_put(struct batadv_tvlv_handler *tvlv_handler)
ef2615774   Marek Lindner   batman-adv: tvlv ...
616
  {
32836f56f   Sven Eckelmann   batman-adv: Conve...
617
  	kref_put(&tvlv_handler->refcount, batadv_tvlv_handler_release);
ef2615774   Marek Lindner   batman-adv: tvlv ...
618
619
620
621
622
623
624
625
626
  }
  
  /**
   * batadv_tvlv_handler_get - retrieve tvlv handler from the tvlv handler list
   *  based on the provided type and version (both need to match)
   * @bat_priv: the bat priv with all the soft interface information
   * @type: tvlv handler type to look for
   * @version: tvlv handler version to look for
   *
62fe710f6   Sven Eckelmann   batman-adv: Fix k...
627
   * Return: tvlv handler if found or NULL otherwise.
ef2615774   Marek Lindner   batman-adv: tvlv ...
628
629
   */
  static struct batadv_tvlv_handler
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
630
  *batadv_tvlv_handler_get(struct batadv_priv *bat_priv, u8 type, u8 version)
ef2615774   Marek Lindner   batman-adv: tvlv ...
631
632
633
634
635
636
637
638
639
640
641
  {
  	struct batadv_tvlv_handler *tvlv_handler_tmp, *tvlv_handler = NULL;
  
  	rcu_read_lock();
  	hlist_for_each_entry_rcu(tvlv_handler_tmp,
  				 &bat_priv->tvlv.handler_list, list) {
  		if (tvlv_handler_tmp->type != type)
  			continue;
  
  		if (tvlv_handler_tmp->version != version)
  			continue;
32836f56f   Sven Eckelmann   batman-adv: Conve...
642
  		if (!kref_get_unless_zero(&tvlv_handler_tmp->refcount))
ef2615774   Marek Lindner   batman-adv: tvlv ...
643
644
645
646
647
648
649
650
651
652
653
  			continue;
  
  		tvlv_handler = tvlv_handler_tmp;
  		break;
  	}
  	rcu_read_unlock();
  
  	return tvlv_handler;
  }
  
  /**
f7157dd13   Sven Eckelmann   batman-adv: Conve...
654
655
656
657
658
659
660
661
662
663
664
665
   * batadv_tvlv_container_release - release tvlv from lists and free
   * @ref: kref pointer of the tvlv
   */
  static void batadv_tvlv_container_release(struct kref *ref)
  {
  	struct batadv_tvlv_container *tvlv;
  
  	tvlv = container_of(ref, struct batadv_tvlv_container, refcount);
  	kfree(tvlv);
  }
  
  /**
ef2615774   Marek Lindner   batman-adv: tvlv ...
666
   * batadv_tvlv_container_free_ref - decrement the tvlv container refcounter and
f7157dd13   Sven Eckelmann   batman-adv: Conve...
667
   *  possibly release it
a0e287750   Martin Hundebøll   batman-adv: kerne...
668
   * @tvlv: the tvlv container to free
ef2615774   Marek Lindner   batman-adv: tvlv ...
669
670
671
   */
  static void batadv_tvlv_container_free_ref(struct batadv_tvlv_container *tvlv)
  {
f7157dd13   Sven Eckelmann   batman-adv: Conve...
672
  	kref_put(&tvlv->refcount, batadv_tvlv_container_release);
ef2615774   Marek Lindner   batman-adv: tvlv ...
673
674
675
676
677
678
679
680
681
682
683
684
  }
  
  /**
   * batadv_tvlv_container_get - retrieve tvlv container from the tvlv container
   *  list based on the provided type and version (both need to match)
   * @bat_priv: the bat priv with all the soft interface information
   * @type: tvlv container type to look for
   * @version: tvlv container version to look for
   *
   * Has to be called with the appropriate locks being acquired
   * (tvlv.container_list_lock).
   *
62fe710f6   Sven Eckelmann   batman-adv: Fix k...
685
   * Return: tvlv container if found or NULL otherwise.
ef2615774   Marek Lindner   batman-adv: tvlv ...
686
687
   */
  static struct batadv_tvlv_container
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
688
  *batadv_tvlv_container_get(struct batadv_priv *bat_priv, u8 type, u8 version)
ef2615774   Marek Lindner   batman-adv: tvlv ...
689
690
  {
  	struct batadv_tvlv_container *tvlv_tmp, *tvlv = NULL;
dded06922   Sven Eckelmann   batman-adv: Add l...
691
  	lockdep_assert_held(&bat_priv->tvlv.container_list_lock);
ef2615774   Marek Lindner   batman-adv: tvlv ...
692
693
694
695
696
697
  	hlist_for_each_entry(tvlv_tmp, &bat_priv->tvlv.container_list, list) {
  		if (tvlv_tmp->tvlv_hdr.type != type)
  			continue;
  
  		if (tvlv_tmp->tvlv_hdr.version != version)
  			continue;
f7157dd13   Sven Eckelmann   batman-adv: Conve...
698
  		if (!kref_get_unless_zero(&tvlv_tmp->refcount))
ef2615774   Marek Lindner   batman-adv: tvlv ...
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
  			continue;
  
  		tvlv = tvlv_tmp;
  		break;
  	}
  
  	return tvlv;
  }
  
  /**
   * batadv_tvlv_container_list_size - calculate the size of the tvlv container
   *  list entries
   * @bat_priv: the bat priv with all the soft interface information
   *
   * Has to be called with the appropriate locks being acquired
   * (tvlv.container_list_lock).
   *
62fe710f6   Sven Eckelmann   batman-adv: Fix k...
716
   * Return: size of all currently registered tvlv containers in bytes.
ef2615774   Marek Lindner   batman-adv: tvlv ...
717
   */
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
718
  static u16 batadv_tvlv_container_list_size(struct batadv_priv *bat_priv)
ef2615774   Marek Lindner   batman-adv: tvlv ...
719
720
  {
  	struct batadv_tvlv_container *tvlv;
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
721
  	u16 tvlv_len = 0;
ef2615774   Marek Lindner   batman-adv: tvlv ...
722

dded06922   Sven Eckelmann   batman-adv: Add l...
723
  	lockdep_assert_held(&bat_priv->tvlv.container_list_lock);
ef2615774   Marek Lindner   batman-adv: tvlv ...
724
725
726
727
728
729
730
731
732
733
734
  	hlist_for_each_entry(tvlv, &bat_priv->tvlv.container_list, list) {
  		tvlv_len += sizeof(struct batadv_tvlv_hdr);
  		tvlv_len += ntohs(tvlv->tvlv_hdr.len);
  	}
  
  	return tvlv_len;
  }
  
  /**
   * batadv_tvlv_container_remove - remove tvlv container from the tvlv container
   *  list
2c72d655b   Sven Eckelmann   batman-adv: Annot...
735
   * @bat_priv: the bat priv with all the soft interface information
ef2615774   Marek Lindner   batman-adv: tvlv ...
736
737
738
739
740
   * @tvlv: the to be removed tvlv container
   *
   * Has to be called with the appropriate locks being acquired
   * (tvlv.container_list_lock).
   */
2c72d655b   Sven Eckelmann   batman-adv: Annot...
741
742
  static void batadv_tvlv_container_remove(struct batadv_priv *bat_priv,
  					 struct batadv_tvlv_container *tvlv)
ef2615774   Marek Lindner   batman-adv: tvlv ...
743
  {
008a37448   Sven Eckelmann   batman-adv: Fix l...
744
  	lockdep_assert_held(&bat_priv->tvlv.container_list_lock);
2c72d655b   Sven Eckelmann   batman-adv: Annot...
745

ef2615774   Marek Lindner   batman-adv: tvlv ...
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
  	if (!tvlv)
  		return;
  
  	hlist_del(&tvlv->list);
  
  	/* first call to decrement the counter, second call to free */
  	batadv_tvlv_container_free_ref(tvlv);
  	batadv_tvlv_container_free_ref(tvlv);
  }
  
  /**
   * batadv_tvlv_container_unregister - unregister tvlv container based on the
   *  provided type and version (both need to match)
   * @bat_priv: the bat priv with all the soft interface information
   * @type: tvlv container type to unregister
   * @version: tvlv container type to unregister
   */
  void batadv_tvlv_container_unregister(struct batadv_priv *bat_priv,
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
764
  				      u8 type, u8 version)
ef2615774   Marek Lindner   batman-adv: tvlv ...
765
766
767
768
769
  {
  	struct batadv_tvlv_container *tvlv;
  
  	spin_lock_bh(&bat_priv->tvlv.container_list_lock);
  	tvlv = batadv_tvlv_container_get(bat_priv, type, version);
2c72d655b   Sven Eckelmann   batman-adv: Annot...
770
  	batadv_tvlv_container_remove(bat_priv, tvlv);
ef2615774   Marek Lindner   batman-adv: tvlv ...
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
  	spin_unlock_bh(&bat_priv->tvlv.container_list_lock);
  }
  
  /**
   * batadv_tvlv_container_register - register tvlv type, version and content
   *  to be propagated with each (primary interface) OGM
   * @bat_priv: the bat priv with all the soft interface information
   * @type: tvlv container type
   * @version: tvlv container version
   * @tvlv_value: tvlv container content
   * @tvlv_value_len: tvlv container content length
   *
   * If a container of the same type and version was already registered the new
   * content is going to replace the old one.
   */
  void batadv_tvlv_container_register(struct batadv_priv *bat_priv,
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
787
788
  				    u8 type, u8 version,
  				    void *tvlv_value, u16 tvlv_value_len)
ef2615774   Marek Lindner   batman-adv: tvlv ...
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
  {
  	struct batadv_tvlv_container *tvlv_old, *tvlv_new;
  
  	if (!tvlv_value)
  		tvlv_value_len = 0;
  
  	tvlv_new = kzalloc(sizeof(*tvlv_new) + tvlv_value_len, GFP_ATOMIC);
  	if (!tvlv_new)
  		return;
  
  	tvlv_new->tvlv_hdr.version = version;
  	tvlv_new->tvlv_hdr.type = type;
  	tvlv_new->tvlv_hdr.len = htons(tvlv_value_len);
  
  	memcpy(tvlv_new + 1, tvlv_value, ntohs(tvlv_new->tvlv_hdr.len));
  	INIT_HLIST_NODE(&tvlv_new->list);
f7157dd13   Sven Eckelmann   batman-adv: Conve...
805
  	kref_init(&tvlv_new->refcount);
ef2615774   Marek Lindner   batman-adv: tvlv ...
806
807
808
  
  	spin_lock_bh(&bat_priv->tvlv.container_list_lock);
  	tvlv_old = batadv_tvlv_container_get(bat_priv, type, version);
2c72d655b   Sven Eckelmann   batman-adv: Annot...
809
  	batadv_tvlv_container_remove(bat_priv, tvlv_old);
ef2615774   Marek Lindner   batman-adv: tvlv ...
810
811
812
813
814
  	hlist_add_head(&tvlv_new->list, &bat_priv->tvlv.container_list);
  	spin_unlock_bh(&bat_priv->tvlv.container_list_lock);
  }
  
  /**
3f68785e6   Antonio Quartulli   batman-adv: fix m...
815
   * batadv_tvlv_realloc_packet_buff - reallocate packet buffer to accommodate
ef2615774   Marek Lindner   batman-adv: tvlv ...
816
817
818
   *  requested packet size
   * @packet_buff: packet buffer
   * @packet_buff_len: packet buffer size
a0e287750   Martin Hundebøll   batman-adv: kerne...
819
   * @min_packet_len: requested packet minimum size
ef2615774   Marek Lindner   batman-adv: tvlv ...
820
821
822
   * @additional_packet_len: requested additional packet size on top of minimum
   *  size
   *
62fe710f6   Sven Eckelmann   batman-adv: Fix k...
823
   * Return: true of the packet buffer could be changed to the requested size,
ef2615774   Marek Lindner   batman-adv: tvlv ...
824
825
826
827
828
829
830
831
832
833
834
835
   * false otherwise.
   */
  static bool batadv_tvlv_realloc_packet_buff(unsigned char **packet_buff,
  					    int *packet_buff_len,
  					    int min_packet_len,
  					    int additional_packet_len)
  {
  	unsigned char *new_buff;
  
  	new_buff = kmalloc(min_packet_len + additional_packet_len, GFP_ATOMIC);
  
  	/* keep old buffer if kmalloc should fail */
16b9ce83f   Markus Pargmann   batman-adv: tvlv ...
836
837
838
839
840
841
842
  	if (!new_buff)
  		return false;
  
  	memcpy(new_buff, *packet_buff, min_packet_len);
  	kfree(*packet_buff);
  	*packet_buff = new_buff;
  	*packet_buff_len = min_packet_len + additional_packet_len;
ef2615774   Marek Lindner   batman-adv: tvlv ...
843

16b9ce83f   Markus Pargmann   batman-adv: tvlv ...
844
  	return true;
ef2615774   Marek Lindner   batman-adv: tvlv ...
845
846
847
848
849
850
851
852
853
854
855
856
857
858
  }
  
  /**
   * batadv_tvlv_container_ogm_append - append tvlv container content to given
   *  OGM packet buffer
   * @bat_priv: the bat priv with all the soft interface information
   * @packet_buff: ogm packet buffer
   * @packet_buff_len: ogm packet buffer size including ogm header and tvlv
   *  content
   * @packet_min_len: ogm header size to be preserved for the OGM itself
   *
   * The ogm packet might be enlarged or shrunk depending on the current size
   * and the size of the to-be-appended tvlv containers.
   *
62fe710f6   Sven Eckelmann   batman-adv: Fix k...
859
   * Return: size of all appended tvlv containers in bytes.
ef2615774   Marek Lindner   batman-adv: tvlv ...
860
   */
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
861
862
863
  u16 batadv_tvlv_container_ogm_append(struct batadv_priv *bat_priv,
  				     unsigned char **packet_buff,
  				     int *packet_buff_len, int packet_min_len)
ef2615774   Marek Lindner   batman-adv: tvlv ...
864
865
866
  {
  	struct batadv_tvlv_container *tvlv;
  	struct batadv_tvlv_hdr *tvlv_hdr;
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
867
  	u16 tvlv_value_len;
ef2615774   Marek Lindner   batman-adv: tvlv ...
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
  	void *tvlv_value;
  	bool ret;
  
  	spin_lock_bh(&bat_priv->tvlv.container_list_lock);
  	tvlv_value_len = batadv_tvlv_container_list_size(bat_priv);
  
  	ret = batadv_tvlv_realloc_packet_buff(packet_buff, packet_buff_len,
  					      packet_min_len, tvlv_value_len);
  
  	if (!ret)
  		goto end;
  
  	if (!tvlv_value_len)
  		goto end;
  
  	tvlv_value = (*packet_buff) + packet_min_len;
  
  	hlist_for_each_entry(tvlv, &bat_priv->tvlv.container_list, list) {
  		tvlv_hdr = tvlv_value;
  		tvlv_hdr->type = tvlv->tvlv_hdr.type;
  		tvlv_hdr->version = tvlv->tvlv_hdr.version;
  		tvlv_hdr->len = tvlv->tvlv_hdr.len;
  		tvlv_value = tvlv_hdr + 1;
  		memcpy(tvlv_value, tvlv + 1, ntohs(tvlv->tvlv_hdr.len));
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
892
  		tvlv_value = (u8 *)tvlv_value + ntohs(tvlv->tvlv_hdr.len);
ef2615774   Marek Lindner   batman-adv: tvlv ...
893
894
895
896
897
898
899
900
901
902
903
904
  	}
  
  end:
  	spin_unlock_bh(&bat_priv->tvlv.container_list_lock);
  	return tvlv_value_len;
  }
  
  /**
   * batadv_tvlv_call_handler - parse the given tvlv buffer to call the
   *  appropriate handlers
   * @bat_priv: the bat priv with all the soft interface information
   * @tvlv_handler: tvlv callback function handling the tvlv content
c05a57f6f   Sven Eckelmann   batman-adv: Fix t...
905
   * @ogm_source: flag indicating whether the tvlv is an ogm or a unicast packet
ef2615774   Marek Lindner   batman-adv: tvlv ...
906
907
908
909
910
911
   * @orig_node: orig node emitting the ogm packet
   * @src: source mac address of the unicast packet
   * @dst: destination mac address of the unicast packet
   * @tvlv_value: tvlv content
   * @tvlv_value_len: tvlv content length
   *
62fe710f6   Sven Eckelmann   batman-adv: Fix k...
912
   * Return: success if handler was not found or the return value of the handler
ef2615774   Marek Lindner   batman-adv: tvlv ...
913
914
915
916
917
918
   * callback.
   */
  static int batadv_tvlv_call_handler(struct batadv_priv *bat_priv,
  				    struct batadv_tvlv_handler *tvlv_handler,
  				    bool ogm_source,
  				    struct batadv_orig_node *orig_node,
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
919
920
  				    u8 *src, u8 *dst,
  				    void *tvlv_value, u16 tvlv_value_len)
ef2615774   Marek Lindner   batman-adv: tvlv ...
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
  {
  	if (!tvlv_handler)
  		return NET_RX_SUCCESS;
  
  	if (ogm_source) {
  		if (!tvlv_handler->ogm_handler)
  			return NET_RX_SUCCESS;
  
  		if (!orig_node)
  			return NET_RX_SUCCESS;
  
  		tvlv_handler->ogm_handler(bat_priv, orig_node,
  					  BATADV_NO_FLAGS,
  					  tvlv_value, tvlv_value_len);
  		tvlv_handler->flags |= BATADV_TVLV_HANDLER_OGM_CALLED;
  	} else {
  		if (!src)
  			return NET_RX_SUCCESS;
  
  		if (!dst)
  			return NET_RX_SUCCESS;
  
  		if (!tvlv_handler->unicast_handler)
  			return NET_RX_SUCCESS;
  
  		return tvlv_handler->unicast_handler(bat_priv, src,
  						     dst, tvlv_value,
  						     tvlv_value_len);
  	}
  
  	return NET_RX_SUCCESS;
  }
  
  /**
   * batadv_tvlv_containers_process - parse the given tvlv buffer to call the
   *  appropriate handlers
   * @bat_priv: the bat priv with all the soft interface information
c05a57f6f   Sven Eckelmann   batman-adv: Fix t...
958
   * @ogm_source: flag indicating whether the tvlv is an ogm or a unicast packet
ef2615774   Marek Lindner   batman-adv: tvlv ...
959
960
961
962
963
964
   * @orig_node: orig node emitting the ogm packet
   * @src: source mac address of the unicast packet
   * @dst: destination mac address of the unicast packet
   * @tvlv_value: tvlv content
   * @tvlv_value_len: tvlv content length
   *
62fe710f6   Sven Eckelmann   batman-adv: Fix k...
965
   * Return: success when processing an OGM or the return value of all called
ef2615774   Marek Lindner   batman-adv: tvlv ...
966
967
968
969
970
   * handler callbacks.
   */
  int batadv_tvlv_containers_process(struct batadv_priv *bat_priv,
  				   bool ogm_source,
  				   struct batadv_orig_node *orig_node,
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
971
972
  				   u8 *src, u8 *dst,
  				   void *tvlv_value, u16 tvlv_value_len)
ef2615774   Marek Lindner   batman-adv: tvlv ...
973
974
975
  {
  	struct batadv_tvlv_handler *tvlv_handler;
  	struct batadv_tvlv_hdr *tvlv_hdr;
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
976
977
  	u16 tvlv_value_cont_len;
  	u8 cifnotfound = BATADV_TVLV_HANDLER_OGM_CIFNOTFND;
ef2615774   Marek Lindner   batman-adv: tvlv ...
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
  	int ret = NET_RX_SUCCESS;
  
  	while (tvlv_value_len >= sizeof(*tvlv_hdr)) {
  		tvlv_hdr = tvlv_value;
  		tvlv_value_cont_len = ntohs(tvlv_hdr->len);
  		tvlv_value = tvlv_hdr + 1;
  		tvlv_value_len -= sizeof(*tvlv_hdr);
  
  		if (tvlv_value_cont_len > tvlv_value_len)
  			break;
  
  		tvlv_handler = batadv_tvlv_handler_get(bat_priv,
  						       tvlv_hdr->type,
  						       tvlv_hdr->version);
  
  		ret |= batadv_tvlv_call_handler(bat_priv, tvlv_handler,
  						ogm_source, orig_node,
  						src, dst, tvlv_value,
  						tvlv_value_cont_len);
  		if (tvlv_handler)
ba610043a   Sven Eckelmann   batman-adv: Renam...
998
  			batadv_tvlv_handler_put(tvlv_handler);
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
999
  		tvlv_value = (u8 *)tvlv_value + tvlv_value_cont_len;
ef2615774   Marek Lindner   batman-adv: tvlv ...
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
  		tvlv_value_len -= tvlv_value_cont_len;
  	}
  
  	if (!ogm_source)
  		return ret;
  
  	rcu_read_lock();
  	hlist_for_each_entry_rcu(tvlv_handler,
  				 &bat_priv->tvlv.handler_list, list) {
  		if ((tvlv_handler->flags & BATADV_TVLV_HANDLER_OGM_CIFNOTFND) &&
  		    !(tvlv_handler->flags & BATADV_TVLV_HANDLER_OGM_CALLED))
  			tvlv_handler->ogm_handler(bat_priv, orig_node,
  						  cifnotfound, NULL, 0);
  
  		tvlv_handler->flags &= ~BATADV_TVLV_HANDLER_OGM_CALLED;
  	}
  	rcu_read_unlock();
  
  	return NET_RX_SUCCESS;
  }
  
  /**
   * batadv_tvlv_ogm_receive - process an incoming ogm and call the appropriate
   *  handlers
   * @bat_priv: the bat priv with all the soft interface information
   * @batadv_ogm_packet: ogm packet containing the tvlv containers
   * @orig_node: orig node emitting the ogm packet
   */
  void batadv_tvlv_ogm_receive(struct batadv_priv *bat_priv,
  			     struct batadv_ogm_packet *batadv_ogm_packet,
  			     struct batadv_orig_node *orig_node)
  {
  	void *tvlv_value;
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
1033
  	u16 tvlv_value_len;
ef2615774   Marek Lindner   batman-adv: tvlv ...
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
  
  	if (!batadv_ogm_packet)
  		return;
  
  	tvlv_value_len = ntohs(batadv_ogm_packet->tvlv_len);
  	if (!tvlv_value_len)
  		return;
  
  	tvlv_value = batadv_ogm_packet + 1;
  
  	batadv_tvlv_containers_process(bat_priv, true, orig_node, NULL, NULL,
  				       tvlv_value, tvlv_value_len);
  }
  
  /**
   * batadv_tvlv_handler_register - register tvlv handler based on the provided
   *  type and version (both need to match) for ogm tvlv payload and/or unicast
   *  payload
   * @bat_priv: the bat priv with all the soft interface information
   * @optr: ogm tvlv handler callback function. This function receives the orig
   *  node, flags and the tvlv content as argument to process.
   * @uptr: unicast tvlv handler callback function. This function receives the
   *  source & destination of the unicast packet as well as the tvlv content
   *  to process.
   * @type: tvlv handler type to be registered
   * @version: tvlv handler version to be registered
   * @flags: flags to enable or disable TVLV API behavior
   */
  void batadv_tvlv_handler_register(struct batadv_priv *bat_priv,
  				  void (*optr)(struct batadv_priv *bat_priv,
  					       struct batadv_orig_node *orig,
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
1065
  					       u8 flags,
ef2615774   Marek Lindner   batman-adv: tvlv ...
1066
  					       void *tvlv_value,
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
1067
  					       u16 tvlv_value_len),
ef2615774   Marek Lindner   batman-adv: tvlv ...
1068
  				  int (*uptr)(struct batadv_priv *bat_priv,
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
1069
  					      u8 *src, u8 *dst,
ef2615774   Marek Lindner   batman-adv: tvlv ...
1070
  					      void *tvlv_value,
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
1071
1072
  					      u16 tvlv_value_len),
  				  u8 type, u8 version, u8 flags)
ef2615774   Marek Lindner   batman-adv: tvlv ...
1073
1074
1075
1076
1077
  {
  	struct batadv_tvlv_handler *tvlv_handler;
  
  	tvlv_handler = batadv_tvlv_handler_get(bat_priv, type, version);
  	if (tvlv_handler) {
ba610043a   Sven Eckelmann   batman-adv: Renam...
1078
  		batadv_tvlv_handler_put(tvlv_handler);
ef2615774   Marek Lindner   batman-adv: tvlv ...
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
  		return;
  	}
  
  	tvlv_handler = kzalloc(sizeof(*tvlv_handler), GFP_ATOMIC);
  	if (!tvlv_handler)
  		return;
  
  	tvlv_handler->ogm_handler = optr;
  	tvlv_handler->unicast_handler = uptr;
  	tvlv_handler->type = type;
  	tvlv_handler->version = version;
  	tvlv_handler->flags = flags;
32836f56f   Sven Eckelmann   batman-adv: Conve...
1091
  	kref_init(&tvlv_handler->refcount);
ef2615774   Marek Lindner   batman-adv: tvlv ...
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
  	INIT_HLIST_NODE(&tvlv_handler->list);
  
  	spin_lock_bh(&bat_priv->tvlv.handler_list_lock);
  	hlist_add_head_rcu(&tvlv_handler->list, &bat_priv->tvlv.handler_list);
  	spin_unlock_bh(&bat_priv->tvlv.handler_list_lock);
  }
  
  /**
   * batadv_tvlv_handler_unregister - unregister tvlv handler based on the
   *  provided type and version (both need to match)
   * @bat_priv: the bat priv with all the soft interface information
   * @type: tvlv handler type to be unregistered
   * @version: tvlv handler version to be unregistered
   */
  void batadv_tvlv_handler_unregister(struct batadv_priv *bat_priv,
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
1107
  				    u8 type, u8 version)
ef2615774   Marek Lindner   batman-adv: tvlv ...
1108
1109
1110
1111
1112
1113
  {
  	struct batadv_tvlv_handler *tvlv_handler;
  
  	tvlv_handler = batadv_tvlv_handler_get(bat_priv, type, version);
  	if (!tvlv_handler)
  		return;
ba610043a   Sven Eckelmann   batman-adv: Renam...
1114
  	batadv_tvlv_handler_put(tvlv_handler);
ef2615774   Marek Lindner   batman-adv: tvlv ...
1115
1116
1117
  	spin_lock_bh(&bat_priv->tvlv.handler_list_lock);
  	hlist_del_rcu(&tvlv_handler->list);
  	spin_unlock_bh(&bat_priv->tvlv.handler_list_lock);
ba610043a   Sven Eckelmann   batman-adv: Renam...
1118
  	batadv_tvlv_handler_put(tvlv_handler);
ef2615774   Marek Lindner   batman-adv: tvlv ...
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
  }
  
  /**
   * batadv_tvlv_unicast_send - send a unicast packet with tvlv payload to the
   *  specified host
   * @bat_priv: the bat priv with all the soft interface information
   * @src: source mac address of the unicast packet
   * @dst: destination mac address of the unicast packet
   * @type: tvlv type
   * @version: tvlv version
   * @tvlv_value: tvlv content
   * @tvlv_value_len: tvlv content length
   */
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
1132
1133
1134
  void batadv_tvlv_unicast_send(struct batadv_priv *bat_priv, u8 *src,
  			      u8 *dst, u8 type, u8 version,
  			      void *tvlv_value, u16 tvlv_value_len)
ef2615774   Marek Lindner   batman-adv: tvlv ...
1135
1136
1137
1138
  {
  	struct batadv_unicast_tvlv_packet *unicast_tvlv_packet;
  	struct batadv_tvlv_hdr *tvlv_hdr;
  	struct batadv_orig_node *orig_node;
8bbb7cb23   Markus Elfring   batman-adv: Less ...
1139
  	struct sk_buff *skb;
ef2615774   Marek Lindner   batman-adv: tvlv ...
1140
1141
1142
  	unsigned char *tvlv_buff;
  	unsigned int tvlv_len;
  	ssize_t hdr_len = sizeof(*unicast_tvlv_packet);
ef2615774   Marek Lindner   batman-adv: tvlv ...
1143
1144
1145
  
  	orig_node = batadv_orig_hash_find(bat_priv, dst);
  	if (!orig_node)
8bbb7cb23   Markus Elfring   batman-adv: Less ...
1146
  		return;
ef2615774   Marek Lindner   batman-adv: tvlv ...
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
  
  	tvlv_len = sizeof(*tvlv_hdr) + tvlv_value_len;
  
  	skb = netdev_alloc_skb_ip_align(NULL, ETH_HLEN + hdr_len + tvlv_len);
  	if (!skb)
  		goto out;
  
  	skb->priority = TC_PRIO_CONTROL;
  	skb_reserve(skb, ETH_HLEN);
  	tvlv_buff = skb_put(skb, sizeof(*unicast_tvlv_packet) + tvlv_len);
  	unicast_tvlv_packet = (struct batadv_unicast_tvlv_packet *)tvlv_buff;
a40d9b075   Simon Wunderlich   batman-adv: fix h...
1158
1159
1160
  	unicast_tvlv_packet->packet_type = BATADV_UNICAST_TVLV;
  	unicast_tvlv_packet->version = BATADV_COMPAT_VERSION;
  	unicast_tvlv_packet->ttl = BATADV_TTL;
ef2615774   Marek Lindner   batman-adv: tvlv ...
1161
1162
1163
  	unicast_tvlv_packet->reserved = 0;
  	unicast_tvlv_packet->tvlv_len = htons(tvlv_len);
  	unicast_tvlv_packet->align = 0;
8fdd01530   Antonio Quartulli   batman-adv: prefe...
1164
1165
  	ether_addr_copy(unicast_tvlv_packet->src, src);
  	ether_addr_copy(unicast_tvlv_packet->dst, dst);
ef2615774   Marek Lindner   batman-adv: tvlv ...
1166
1167
1168
1169
1170
1171
1172
1173
  
  	tvlv_buff = (unsigned char *)(unicast_tvlv_packet + 1);
  	tvlv_hdr = (struct batadv_tvlv_hdr *)tvlv_buff;
  	tvlv_hdr->version = version;
  	tvlv_hdr->type = type;
  	tvlv_hdr->len = htons(tvlv_value_len);
  	tvlv_buff += sizeof(*tvlv_hdr);
  	memcpy(tvlv_buff, tvlv_value, tvlv_value_len);
8bbb7cb23   Markus Elfring   batman-adv: Less ...
1174
  	if (batadv_send_skb_to_orig(skb, orig_node, NULL) == NET_XMIT_DROP)
ef2615774   Marek Lindner   batman-adv: tvlv ...
1175
  		kfree_skb(skb);
8bbb7cb23   Markus Elfring   batman-adv: Less ...
1176
  out:
5d9673109   Sven Eckelmann   batman-adv: Renam...
1177
  	batadv_orig_node_put(orig_node);
ef2615774   Marek Lindner   batman-adv: tvlv ...
1178
  }
c018ad3de   Antonio Quartulli   batman-adv: add t...
1179
1180
1181
1182
1183
  /**
   * batadv_get_vid - extract the VLAN identifier from skb if any
   * @skb: the buffer containing the packet
   * @header_len: length of the batman header preceding the ethernet header
   *
62fe710f6   Sven Eckelmann   batman-adv: Fix k...
1184
1185
   * Return: VID with the BATADV_VLAN_HAS_TAG flag when the packet embedded in the
   * skb is vlan tagged. Otherwise BATADV_NO_FLAGS.
c018ad3de   Antonio Quartulli   batman-adv: add t...
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
   */
  unsigned short batadv_get_vid(struct sk_buff *skb, size_t header_len)
  {
  	struct ethhdr *ethhdr = (struct ethhdr *)(skb->data + header_len);
  	struct vlan_ethhdr *vhdr;
  	unsigned short vid;
  
  	if (ethhdr->h_proto != htons(ETH_P_8021Q))
  		return BATADV_NO_FLAGS;
  
  	if (!pskb_may_pull(skb, header_len + VLAN_ETH_HLEN))
  		return BATADV_NO_FLAGS;
  
  	vhdr = (struct vlan_ethhdr *)(skb->data + header_len);
  	vid = ntohs(vhdr->h_vlan_TCI) & VLAN_VID_MASK;
  	vid |= BATADV_VLAN_HAS_TAG;
  
  	return vid;
  }
eceb22ae0   Antonio Quartulli   batman-adv: creat...
1205
1206
1207
1208
1209
1210
  /**
   * batadv_vlan_ap_isola_get - return the AP isolation status for the given vlan
   * @bat_priv: the bat priv with all the soft interface information
   * @vid: the VLAN identifier for which the AP isolation attributed as to be
   *  looked up
   *
62fe710f6   Sven Eckelmann   batman-adv: Fix k...
1211
   * Return: true if AP isolation is on for the VLAN idenfied by vid, false
eceb22ae0   Antonio Quartulli   batman-adv: creat...
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
   * otherwise
   */
  bool batadv_vlan_ap_isola_get(struct batadv_priv *bat_priv, unsigned short vid)
  {
  	bool ap_isolation_enabled = false;
  	struct batadv_softif_vlan *vlan;
  
  	/* if the AP isolation is requested on a VLAN, then check for its
  	 * setting in the proper VLAN private data structure
  	 */
  	vlan = batadv_softif_vlan_get(bat_priv, vid);
  	if (vlan) {
  		ap_isolation_enabled = atomic_read(&vlan->ap_isolation);
  		batadv_softif_vlan_free_ref(vlan);
  	}
  
  	return ap_isolation_enabled;
  }
ee11ad61f   Sven Eckelmann   batman-adv: Prefi...
1230
  static int batadv_param_set_ra(const char *val, const struct kernel_param *kp)
d419be1fd   Marek Lindner   batman-adv: allow...
1231
  {
56303d34a   Sven Eckelmann   batman-adv: Prefi...
1232
  	struct batadv_algo_ops *bat_algo_ops;
d8cb54861   Marek Lindner   batman-adv: ignor...
1233
1234
  	char *algo_name = (char *)val;
  	size_t name_len = strlen(algo_name);
d419be1fd   Marek Lindner   batman-adv: allow...
1235

293c9c1ce   Marek Lindner   batman-adv: check...
1236
1237
  	if (name_len > 0 && algo_name[name_len - 1] == '
  ')
d8cb54861   Marek Lindner   batman-adv: ignor...
1238
  		algo_name[name_len - 1] = '\0';
ee11ad61f   Sven Eckelmann   batman-adv: Prefi...
1239
  	bat_algo_ops = batadv_algo_get(algo_name);
d419be1fd   Marek Lindner   batman-adv: allow...
1240
  	if (!bat_algo_ops) {
d8cb54861   Marek Lindner   batman-adv: ignor...
1241
1242
  		pr_err("Routing algorithm '%s' is not supported
  ", algo_name);
d419be1fd   Marek Lindner   batman-adv: allow...
1243
1244
  		return -EINVAL;
  	}
d8cb54861   Marek Lindner   batman-adv: ignor...
1245
  	return param_set_copystring(algo_name, kp);
d419be1fd   Marek Lindner   batman-adv: allow...
1246
  }
ee11ad61f   Sven Eckelmann   batman-adv: Prefi...
1247
1248
  static const struct kernel_param_ops batadv_param_ops_ra = {
  	.set = batadv_param_set_ra,
d419be1fd   Marek Lindner   batman-adv: allow...
1249
1250
  	.get = param_get_string,
  };
ee11ad61f   Sven Eckelmann   batman-adv: Prefi...
1251
  static struct kparam_string batadv_param_string_ra = {
3193e8fdf   Sven Eckelmann   batman-adv: Prefi...
1252
1253
  	.maxlen = sizeof(batadv_routing_algo),
  	.string = batadv_routing_algo,
d419be1fd   Marek Lindner   batman-adv: allow...
1254
  };
ee11ad61f   Sven Eckelmann   batman-adv: Prefi...
1255
1256
1257
1258
  module_param_cb(routing_algo, &batadv_param_ops_ra, &batadv_param_string_ra,
  		0644);
  module_init(batadv_init);
  module_exit(batadv_exit);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
1259
1260
  
  MODULE_LICENSE("GPL");
42d0b044b   Sven Eckelmann   batman-adv: Prefi...
1261
1262
1263
1264
  MODULE_AUTHOR(BATADV_DRIVER_AUTHOR);
  MODULE_DESCRIPTION(BATADV_DRIVER_DESC);
  MODULE_SUPPORTED_DEVICE(BATADV_DRIVER_DEVICE);
  MODULE_VERSION(BATADV_SOURCE_VERSION);