Blame view

net/batman-adv/main.c 37.2 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

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

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

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

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

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

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

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

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

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

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

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

bd3524c14   Simon Wunderlich   batman-adv: remov...
198
  	batadv_gw_node_free(bat_priv);
0da003594   Antonio Quartulli   batman-adv: OGMv2...
199
200
  
  	batadv_v_mesh_free(bat_priv);
6c519bad7   Matthias Schiffer   batman-adv: set u...
201
  	batadv_nc_mesh_free(bat_priv);
a43618603   Antonio Quartulli   batman-adv: reord...
202
203
  	batadv_dat_free(bat_priv);
  	batadv_bla_free(bat_priv);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
204

c5caf4ef3   Linus Lüssing   batman-adv: Multi...
205
  	batadv_mcast_free(bat_priv);
a43618603   Antonio Quartulli   batman-adv: reord...
206
207
208
209
  	/* 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...
210
  	batadv_tt_free(bat_priv);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
211

a43618603   Antonio Quartulli   batman-adv: reord...
212
213
214
215
216
217
  	/* 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...
218

414254e34   Marek Lindner   batman-adv: tvlv ...
219
  	batadv_gw_free(bat_priv);
f8214865a   Martin Hundebøll   batman-adv: Add g...
220
  	free_percpu(bat_priv->bat_counters);
f69ae770e   Martin Hundebøll   batman-adv: Avoid...
221
  	bat_priv->bat_counters = NULL;
f8214865a   Martin Hundebøll   batman-adv: Add g...
222

39c75a51e   Sven Eckelmann   batman-adv: Prefi...
223
  	atomic_set(&bat_priv->mesh_state, BATADV_MESH_INACTIVE);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
224
  }
6e0895c2e   David S. Miller   Merge git://git.k...
225
226
227
228
229
  /**
   * 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,...
230
   *
62fe710f6   Sven Eckelmann   batman-adv: Fix k...
231
   * Return: 'true' if the mac address was found, false otherwise.
6e0895c2e   David S. Miller   Merge git://git.k...
232
   */
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
233
  bool batadv_is_my_mac(struct batadv_priv *bat_priv, const u8 *addr)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
234
  {
56303d34a   Sven Eckelmann   batman-adv: Prefi...
235
  	const struct batadv_hard_iface *hard_iface;
e8ad3b1ac   Markus Pargmann   batman-adv: main,...
236
  	bool is_my_mac = false;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
237
238
  
  	rcu_read_lock();
3193e8fdf   Sven Eckelmann   batman-adv: Prefi...
239
  	list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
e9a4f295e   Sven Eckelmann   batman-adv: Prefi...
240
  		if (hard_iface->if_status != BATADV_IF_ACTIVE)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
241
  			continue;
fe8a93b95   Antonio Quartulli   batman-adv: make ...
242
243
  		if (hard_iface->soft_iface != bat_priv->soft_iface)
  			continue;
1eda58bfc   Sven Eckelmann   batman-adv: Prefi...
244
  		if (batadv_compare_eth(hard_iface->net_dev->dev_addr, addr)) {
e8ad3b1ac   Markus Pargmann   batman-adv: main,...
245
246
  			is_my_mac = true;
  			break;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
247
248
249
  		}
  	}
  	rcu_read_unlock();
e8ad3b1ac   Markus Pargmann   batman-adv: main,...
250
  	return is_my_mac;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
251
  }
30da63a6a   Marek Lindner   batman-adv: conso...
252
253
254
255
256
  /**
   * 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...
257
   * Return: primary interface if found or NULL otherwise.
30da63a6a   Marek Lindner   batman-adv: conso...
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
   */
  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...
283
  	batadv_hardif_put(primary_if);
30da63a6a   Marek Lindner   batman-adv: conso...
284
285
286
287
288
  	primary_if = NULL;
  
  out:
  	return primary_if;
  }
c54f38c9a   Simon Wunderlich   batman-adv: set s...
289
  /**
411d6ed93   Marek Lindner   batman-adv: consi...
290
291
292
   * batadv_max_header_len - calculate maximum encapsulation overhead for a
   *  payload packet
   *
62fe710f6   Sven Eckelmann   batman-adv: Fix k...
293
   * Return: the maximum encapsulation overhead in bytes.
411d6ed93   Marek Lindner   batman-adv: consi...
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
   */
  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...
310
  	return header_len + ETH_HLEN;
411d6ed93   Marek Lindner   batman-adv: consi...
311
312
313
  }
  
  /**
c54f38c9a   Simon Wunderlich   batman-adv: set s...
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
360
361
362
363
364
365
   * 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...
366
  static int batadv_recv_unhandled_packet(struct sk_buff *skb,
56303d34a   Sven Eckelmann   batman-adv: Prefi...
367
  					struct batadv_hard_iface *recv_if)
ffa995e03   Marek Lindner   batman-adv: intro...
368
369
370
371
372
373
374
  {
  	return NET_RX_DROP;
  }
  
  /* incoming packets with the batman ethertype received on any active hard
   * interface
   */
3193e8fdf   Sven Eckelmann   batman-adv: Prefi...
375
376
377
  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...
378
  {
56303d34a   Sven Eckelmann   batman-adv: Prefi...
379
  	struct batadv_priv *bat_priv;
964126901   Sven Eckelmann   batman-adv: Prefi...
380
  	struct batadv_ogm_packet *batadv_ogm_packet;
56303d34a   Sven Eckelmann   batman-adv: Prefi...
381
  	struct batadv_hard_iface *hard_iface;
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
382
  	u8 idx;
ffa995e03   Marek Lindner   batman-adv: intro...
383
  	int ret;
56303d34a   Sven Eckelmann   batman-adv: Prefi...
384
385
  	hard_iface = container_of(ptype, struct batadv_hard_iface,
  				  batman_adv_ptype);
ffa995e03   Marek Lindner   batman-adv: intro...
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
  	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...
404
  	if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE)
ffa995e03   Marek Lindner   batman-adv: intro...
405
406
407
  		goto err_free;
  
  	/* discard frames on not active interfaces */
e9a4f295e   Sven Eckelmann   batman-adv: Prefi...
408
  	if (hard_iface->if_status != BATADV_IF_ACTIVE)
ffa995e03   Marek Lindner   batman-adv: intro...
409
  		goto err_free;
964126901   Sven Eckelmann   batman-adv: Prefi...
410
  	batadv_ogm_packet = (struct batadv_ogm_packet *)skb->data;
ffa995e03   Marek Lindner   batman-adv: intro...
411

a40d9b075   Simon Wunderlich   batman-adv: fix h...
412
  	if (batadv_ogm_packet->version != BATADV_COMPAT_VERSION) {
39c75a51e   Sven Eckelmann   batman-adv: Prefi...
413
  		batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
1eda58bfc   Sven Eckelmann   batman-adv: Prefi...
414
415
  			   "Drop packet: incompatible batman version (%i)
  ",
a40d9b075   Simon Wunderlich   batman-adv: fix h...
416
  			   batadv_ogm_packet->version);
ffa995e03   Marek Lindner   batman-adv: intro...
417
418
  		goto err_free;
  	}
e0d9677ea   Martin Hundebøll   batman-adv: clear...
419
420
  	/* 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...
421
422
423
  	/* 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...
424
  	idx = batadv_ogm_packet->packet_type;
ee11ad61f   Sven Eckelmann   batman-adv: Prefi...
425
  	ret = (*batadv_rx_handler[idx])(skb, hard_iface);
ffa995e03   Marek Lindner   batman-adv: intro...
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
  
  	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...
441
  static void batadv_recv_handler_init(void)
ffa995e03   Marek Lindner   batman-adv: intro...
442
443
  {
  	int i;
ee11ad61f   Sven Eckelmann   batman-adv: Prefi...
444
445
  	for (i = 0; i < ARRAY_SIZE(batadv_rx_handler); i++)
  		batadv_rx_handler[i] = batadv_recv_unhandled_packet;
ffa995e03   Marek Lindner   batman-adv: intro...
446

a1f1ac5c4   Simon Wunderlich   batman-adv: reord...
447
448
  	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...
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
  	/* 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...
466

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

b67bfe0d4   Sasha Levin   hlist: drop the n...
505
  	hlist_for_each_entry(bat_algo_ops_tmp, &batadv_algo_list, list) {
1c280471b   Marek Lindner   batman-adv: add i...
506
507
508
509
510
511
512
513
514
  		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...
515
  int batadv_algo_register(struct batadv_algo_ops *bat_algo_ops)
1c280471b   Marek Lindner   batman-adv: add i...
516
  {
56303d34a   Sven Eckelmann   batman-adv: Prefi...
517
  	struct batadv_algo_ops *bat_algo_ops_tmp;
1c280471b   Marek Lindner   batman-adv: add i...
518

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

9fb6c6519   Markus Pargmann   batman-adv: Remov...
543
  	return 0;
1c280471b   Marek Lindner   batman-adv: add i...
544
  }
56303d34a   Sven Eckelmann   batman-adv: Prefi...
545
  int batadv_algo_select(struct batadv_priv *bat_priv, char *name)
1c280471b   Marek Lindner   batman-adv: add i...
546
  {
56303d34a   Sven Eckelmann   batman-adv: Prefi...
547
  	struct batadv_algo_ops *bat_algo_ops;
1c280471b   Marek Lindner   batman-adv: add i...
548

ee11ad61f   Sven Eckelmann   batman-adv: Prefi...
549
  	bat_algo_ops = batadv_algo_get(name);
1c280471b   Marek Lindner   batman-adv: add i...
550
  	if (!bat_algo_ops)
f372d0905   Markus Pargmann   batman-adv: Remov...
551
  		return -EINVAL;
1c280471b   Marek Lindner   batman-adv: add i...
552
553
  
  	bat_priv->bat_algo_ops = bat_algo_ops;
1c280471b   Marek Lindner   batman-adv: add i...
554

f372d0905   Markus Pargmann   batman-adv: Remov...
555
  	return 0;
1c280471b   Marek Lindner   batman-adv: add i...
556
  }
3193e8fdf   Sven Eckelmann   batman-adv: Prefi...
557
  int batadv_algo_seq_print_text(struct seq_file *seq, void *offset)
1c280471b   Marek Lindner   batman-adv: add i...
558
  {
56303d34a   Sven Eckelmann   batman-adv: Prefi...
559
  	struct batadv_algo_ops *bat_algo_ops;
1c280471b   Marek Lindner   batman-adv: add i...
560

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

b67bfe0d4   Sasha Levin   hlist: drop the n...
564
  	hlist_for_each_entry(bat_algo_ops, &batadv_algo_list, list) {
854d2a63d   Marek Lindner   batman-adv: beaut...
565
566
  		seq_printf(seq, " * %s
  ", bat_algo_ops->name);
1c280471b   Marek Lindner   batman-adv: add i...
567
568
569
570
  	}
  
  	return 0;
  }
95a066d82   Sven Eckelmann   batman-adv: Add f...
571
572
573
574
575
576
577
578
579
  /**
   * 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...
580
581
   *
   * Return: big endian crc32c of the checksummed data
95a066d82   Sven Eckelmann   batman-adv: Add f...
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
   */
  __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...
600
601
602
  
  	return htonl(crc);
  }
ef2615774   Marek Lindner   batman-adv: tvlv ...
603
  /**
32836f56f   Sven Eckelmann   batman-adv: Conve...
604
605
606
607
608
609
610
611
612
613
614
615
616
   * 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...
617
   * batadv_tvlv_handler_put - decrement the tvlv container refcounter and
32836f56f   Sven Eckelmann   batman-adv: Conve...
618
   *  possibly release it
ef2615774   Marek Lindner   batman-adv: tvlv ...
619
620
   * @tvlv_handler: the tvlv handler to free
   */
ba610043a   Sven Eckelmann   batman-adv: Renam...
621
  static void batadv_tvlv_handler_put(struct batadv_tvlv_handler *tvlv_handler)
ef2615774   Marek Lindner   batman-adv: tvlv ...
622
  {
32836f56f   Sven Eckelmann   batman-adv: Conve...
623
  	kref_put(&tvlv_handler->refcount, batadv_tvlv_handler_release);
ef2615774   Marek Lindner   batman-adv: tvlv ...
624
625
626
627
628
629
630
631
632
  }
  
  /**
   * 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...
633
   * Return: tvlv handler if found or NULL otherwise.
ef2615774   Marek Lindner   batman-adv: tvlv ...
634
635
   */
  static struct batadv_tvlv_handler
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
636
  *batadv_tvlv_handler_get(struct batadv_priv *bat_priv, u8 type, u8 version)
ef2615774   Marek Lindner   batman-adv: tvlv ...
637
638
639
640
641
642
643
644
645
646
647
  {
  	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...
648
  		if (!kref_get_unless_zero(&tvlv_handler_tmp->refcount))
ef2615774   Marek Lindner   batman-adv: tvlv ...
649
650
651
652
653
654
655
656
657
658
659
  			continue;
  
  		tvlv_handler = tvlv_handler_tmp;
  		break;
  	}
  	rcu_read_unlock();
  
  	return tvlv_handler;
  }
  
  /**
f7157dd13   Sven Eckelmann   batman-adv: Conve...
660
661
662
663
664
665
666
667
668
669
670
671
   * 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);
  }
  
  /**
4a13147cb   Sven Eckelmann   batman-adv: Renam...
672
   * batadv_tvlv_container_put - decrement the tvlv container refcounter and
f7157dd13   Sven Eckelmann   batman-adv: Conve...
673
   *  possibly release it
a0e287750   Martin Hundebøll   batman-adv: kerne...
674
   * @tvlv: the tvlv container to free
ef2615774   Marek Lindner   batman-adv: tvlv ...
675
   */
4a13147cb   Sven Eckelmann   batman-adv: Renam...
676
  static void batadv_tvlv_container_put(struct batadv_tvlv_container *tvlv)
ef2615774   Marek Lindner   batman-adv: tvlv ...
677
  {
f7157dd13   Sven Eckelmann   batman-adv: Conve...
678
  	kref_put(&tvlv->refcount, batadv_tvlv_container_release);
ef2615774   Marek Lindner   batman-adv: tvlv ...
679
680
681
682
683
684
685
686
687
688
689
690
  }
  
  /**
   * 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...
691
   * Return: tvlv container if found or NULL otherwise.
ef2615774   Marek Lindner   batman-adv: tvlv ...
692
693
   */
  static struct batadv_tvlv_container
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
694
  *batadv_tvlv_container_get(struct batadv_priv *bat_priv, u8 type, u8 version)
ef2615774   Marek Lindner   batman-adv: tvlv ...
695
696
  {
  	struct batadv_tvlv_container *tvlv_tmp, *tvlv = NULL;
dded06922   Sven Eckelmann   batman-adv: Add l...
697
  	lockdep_assert_held(&bat_priv->tvlv.container_list_lock);
ef2615774   Marek Lindner   batman-adv: tvlv ...
698
699
700
701
702
703
  	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...
704
  		if (!kref_get_unless_zero(&tvlv_tmp->refcount))
ef2615774   Marek Lindner   batman-adv: tvlv ...
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
  			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...
722
   * Return: size of all currently registered tvlv containers in bytes.
ef2615774   Marek Lindner   batman-adv: tvlv ...
723
   */
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
724
  static u16 batadv_tvlv_container_list_size(struct batadv_priv *bat_priv)
ef2615774   Marek Lindner   batman-adv: tvlv ...
725
726
  {
  	struct batadv_tvlv_container *tvlv;
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
727
  	u16 tvlv_len = 0;
ef2615774   Marek Lindner   batman-adv: tvlv ...
728

dded06922   Sven Eckelmann   batman-adv: Add l...
729
  	lockdep_assert_held(&bat_priv->tvlv.container_list_lock);
ef2615774   Marek Lindner   batman-adv: tvlv ...
730
731
732
733
734
735
736
737
738
739
740
  	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...
741
   * @bat_priv: the bat priv with all the soft interface information
ef2615774   Marek Lindner   batman-adv: tvlv ...
742
743
744
745
746
   * @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...
747
748
  static void batadv_tvlv_container_remove(struct batadv_priv *bat_priv,
  					 struct batadv_tvlv_container *tvlv)
ef2615774   Marek Lindner   batman-adv: tvlv ...
749
  {
008a37448   Sven Eckelmann   batman-adv: Fix l...
750
  	lockdep_assert_held(&bat_priv->tvlv.container_list_lock);
2c72d655b   Sven Eckelmann   batman-adv: Annot...
751

ef2615774   Marek Lindner   batman-adv: tvlv ...
752
753
754
755
756
757
  	if (!tvlv)
  		return;
  
  	hlist_del(&tvlv->list);
  
  	/* first call to decrement the counter, second call to free */
4a13147cb   Sven Eckelmann   batman-adv: Renam...
758
759
  	batadv_tvlv_container_put(tvlv);
  	batadv_tvlv_container_put(tvlv);
ef2615774   Marek Lindner   batman-adv: tvlv ...
760
761
762
763
764
765
766
767
768
769
  }
  
  /**
   * 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...
770
  				      u8 type, u8 version)
ef2615774   Marek Lindner   batman-adv: tvlv ...
771
772
773
774
775
  {
  	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...
776
  	batadv_tvlv_container_remove(bat_priv, tvlv);
ef2615774   Marek Lindner   batman-adv: tvlv ...
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
  	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...
793
794
  				    u8 type, u8 version,
  				    void *tvlv_value, u16 tvlv_value_len)
ef2615774   Marek Lindner   batman-adv: tvlv ...
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
  {
  	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...
811
  	kref_init(&tvlv_new->refcount);
ef2615774   Marek Lindner   batman-adv: tvlv ...
812
813
814
  
  	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...
815
  	batadv_tvlv_container_remove(bat_priv, tvlv_old);
ef2615774   Marek Lindner   batman-adv: tvlv ...
816
817
818
819
820
  	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...
821
   * batadv_tvlv_realloc_packet_buff - reallocate packet buffer to accommodate
ef2615774   Marek Lindner   batman-adv: tvlv ...
822
823
824
   *  requested packet size
   * @packet_buff: packet buffer
   * @packet_buff_len: packet buffer size
a0e287750   Martin Hundebøll   batman-adv: kerne...
825
   * @min_packet_len: requested packet minimum size
ef2615774   Marek Lindner   batman-adv: tvlv ...
826
827
828
   * @additional_packet_len: requested additional packet size on top of minimum
   *  size
   *
62fe710f6   Sven Eckelmann   batman-adv: Fix k...
829
   * Return: true of the packet buffer could be changed to the requested size,
ef2615774   Marek Lindner   batman-adv: tvlv ...
830
831
832
833
834
835
836
837
838
839
840
841
   * 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 ...
842
843
844
845
846
847
848
  	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 ...
849

16b9ce83f   Markus Pargmann   batman-adv: tvlv ...
850
  	return true;
ef2615774   Marek Lindner   batman-adv: tvlv ...
851
852
853
854
855
856
857
858
859
860
861
862
863
864
  }
  
  /**
   * 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...
865
   * Return: size of all appended tvlv containers in bytes.
ef2615774   Marek Lindner   batman-adv: tvlv ...
866
   */
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
867
868
869
  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 ...
870
871
872
  {
  	struct batadv_tvlv_container *tvlv;
  	struct batadv_tvlv_hdr *tvlv_hdr;
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
873
  	u16 tvlv_value_len;
ef2615774   Marek Lindner   batman-adv: tvlv ...
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
  	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...
898
  		tvlv_value = (u8 *)tvlv_value + ntohs(tvlv->tvlv_hdr.len);
ef2615774   Marek Lindner   batman-adv: tvlv ...
899
900
901
902
903
904
905
906
907
908
909
910
  	}
  
  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...
911
   * @ogm_source: flag indicating whether the tvlv is an ogm or a unicast packet
ef2615774   Marek Lindner   batman-adv: tvlv ...
912
913
914
915
916
917
   * @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...
918
   * Return: success if handler was not found or the return value of the handler
ef2615774   Marek Lindner   batman-adv: tvlv ...
919
920
921
922
923
924
   * 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...
925
926
  				    u8 *src, u8 *dst,
  				    void *tvlv_value, u16 tvlv_value_len)
ef2615774   Marek Lindner   batman-adv: tvlv ...
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
958
959
960
961
962
963
  {
  	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...
964
   * @ogm_source: flag indicating whether the tvlv is an ogm or a unicast packet
ef2615774   Marek Lindner   batman-adv: tvlv ...
965
966
967
968
969
970
   * @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...
971
   * Return: success when processing an OGM or the return value of all called
ef2615774   Marek Lindner   batman-adv: tvlv ...
972
973
974
975
976
   * 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...
977
978
  				   u8 *src, u8 *dst,
  				   void *tvlv_value, u16 tvlv_value_len)
ef2615774   Marek Lindner   batman-adv: tvlv ...
979
980
981
  {
  	struct batadv_tvlv_handler *tvlv_handler;
  	struct batadv_tvlv_hdr *tvlv_hdr;
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
982
983
  	u16 tvlv_value_cont_len;
  	u8 cifnotfound = BATADV_TVLV_HANDLER_OGM_CIFNOTFND;
ef2615774   Marek Lindner   batman-adv: tvlv ...
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
  	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...
1004
  			batadv_tvlv_handler_put(tvlv_handler);
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
1005
  		tvlv_value = (u8 *)tvlv_value + tvlv_value_cont_len;
ef2615774   Marek Lindner   batman-adv: tvlv ...
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
1033
1034
1035
1036
1037
1038
  		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...
1039
  	u16 tvlv_value_len;
ef2615774   Marek Lindner   batman-adv: tvlv ...
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
1065
1066
1067
1068
1069
1070
  
  	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...
1071
  					       u8 flags,
ef2615774   Marek Lindner   batman-adv: tvlv ...
1072
  					       void *tvlv_value,
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
1073
  					       u16 tvlv_value_len),
ef2615774   Marek Lindner   batman-adv: tvlv ...
1074
  				  int (*uptr)(struct batadv_priv *bat_priv,
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
1075
  					      u8 *src, u8 *dst,
ef2615774   Marek Lindner   batman-adv: tvlv ...
1076
  					      void *tvlv_value,
6b5e971a2   Sven Eckelmann   batman-adv: Repla...
1077
1078
  					      u16 tvlv_value_len),
  				  u8 type, u8 version, u8 flags)
ef2615774   Marek Lindner   batman-adv: tvlv ...
1079
1080
1081
1082
1083
  {
  	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...
1084
  		batadv_tvlv_handler_put(tvlv_handler);
ef2615774   Marek Lindner   batman-adv: tvlv ...
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
  		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...
1097
  	kref_init(&tvlv_handler->refcount);
ef2615774   Marek Lindner   batman-adv: tvlv ...
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
  	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...
1113
  				    u8 type, u8 version)
ef2615774   Marek Lindner   batman-adv: tvlv ...
1114
1115
1116
1117
1118
1119
  {
  	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...
1120
  	batadv_tvlv_handler_put(tvlv_handler);
ef2615774   Marek Lindner   batman-adv: tvlv ...
1121
1122
1123
  	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...
1124
  	batadv_tvlv_handler_put(tvlv_handler);
ef2615774   Marek Lindner   batman-adv: tvlv ...
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
  }
  
  /**
   * 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...
1138
1139
1140
  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 ...
1141
1142
1143
1144
  {
  	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 ...
1145
  	struct sk_buff *skb;
ef2615774   Marek Lindner   batman-adv: tvlv ...
1146
1147
1148
  	unsigned char *tvlv_buff;
  	unsigned int tvlv_len;
  	ssize_t hdr_len = sizeof(*unicast_tvlv_packet);
ef2615774   Marek Lindner   batman-adv: tvlv ...
1149
1150
1151
  
  	orig_node = batadv_orig_hash_find(bat_priv, dst);
  	if (!orig_node)
8bbb7cb23   Markus Elfring   batman-adv: Less ...
1152
  		return;
ef2615774   Marek Lindner   batman-adv: tvlv ...
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
  
  	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...
1164
1165
1166
  	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 ...
1167
1168
1169
  	unicast_tvlv_packet->reserved = 0;
  	unicast_tvlv_packet->tvlv_len = htons(tvlv_len);
  	unicast_tvlv_packet->align = 0;
8fdd01530   Antonio Quartulli   batman-adv: prefe...
1170
1171
  	ether_addr_copy(unicast_tvlv_packet->src, src);
  	ether_addr_copy(unicast_tvlv_packet->dst, dst);
ef2615774   Marek Lindner   batman-adv: tvlv ...
1172
1173
1174
1175
1176
1177
1178
1179
  
  	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 ...
1180
  	if (batadv_send_skb_to_orig(skb, orig_node, NULL) == NET_XMIT_DROP)
ef2615774   Marek Lindner   batman-adv: tvlv ...
1181
  		kfree_skb(skb);
8bbb7cb23   Markus Elfring   batman-adv: Less ...
1182
  out:
5d9673109   Sven Eckelmann   batman-adv: Renam...
1183
  	batadv_orig_node_put(orig_node);
ef2615774   Marek Lindner   batman-adv: tvlv ...
1184
  }
c018ad3de   Antonio Quartulli   batman-adv: add t...
1185
1186
1187
1188
1189
  /**
   * 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...
1190
1191
   * 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...
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
   */
  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...
1211
1212
1213
1214
1215
1216
  /**
   * 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...
1217
   * Return: true if AP isolation is on for the VLAN idenfied by vid, false
eceb22ae0   Antonio Quartulli   batman-adv: creat...
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
   * 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);
9c3bf0818   Sven Eckelmann   batman-adv: Renam...
1231
  		batadv_softif_vlan_put(vlan);
eceb22ae0   Antonio Quartulli   batman-adv: creat...
1232
1233
1234
1235
  	}
  
  	return ap_isolation_enabled;
  }
ee11ad61f   Sven Eckelmann   batman-adv: Prefi...
1236
  static int batadv_param_set_ra(const char *val, const struct kernel_param *kp)
d419be1fd   Marek Lindner   batman-adv: allow...
1237
  {
56303d34a   Sven Eckelmann   batman-adv: Prefi...
1238
  	struct batadv_algo_ops *bat_algo_ops;
d8cb54861   Marek Lindner   batman-adv: ignor...
1239
1240
  	char *algo_name = (char *)val;
  	size_t name_len = strlen(algo_name);
d419be1fd   Marek Lindner   batman-adv: allow...
1241

293c9c1ce   Marek Lindner   batman-adv: check...
1242
1243
  	if (name_len > 0 && algo_name[name_len - 1] == '
  ')
d8cb54861   Marek Lindner   batman-adv: ignor...
1244
  		algo_name[name_len - 1] = '\0';
ee11ad61f   Sven Eckelmann   batman-adv: Prefi...
1245
  	bat_algo_ops = batadv_algo_get(algo_name);
d419be1fd   Marek Lindner   batman-adv: allow...
1246
  	if (!bat_algo_ops) {
d8cb54861   Marek Lindner   batman-adv: ignor...
1247
1248
  		pr_err("Routing algorithm '%s' is not supported
  ", algo_name);
d419be1fd   Marek Lindner   batman-adv: allow...
1249
1250
  		return -EINVAL;
  	}
d8cb54861   Marek Lindner   batman-adv: ignor...
1251
  	return param_set_copystring(algo_name, kp);
d419be1fd   Marek Lindner   batman-adv: allow...
1252
  }
ee11ad61f   Sven Eckelmann   batman-adv: Prefi...
1253
1254
  static const struct kernel_param_ops batadv_param_ops_ra = {
  	.set = batadv_param_set_ra,
d419be1fd   Marek Lindner   batman-adv: allow...
1255
1256
  	.get = param_get_string,
  };
ee11ad61f   Sven Eckelmann   batman-adv: Prefi...
1257
  static struct kparam_string batadv_param_string_ra = {
3193e8fdf   Sven Eckelmann   batman-adv: Prefi...
1258
1259
  	.maxlen = sizeof(batadv_routing_algo),
  	.string = batadv_routing_algo,
d419be1fd   Marek Lindner   batman-adv: allow...
1260
  };
ee11ad61f   Sven Eckelmann   batman-adv: Prefi...
1261
1262
1263
1264
  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...
1265
1266
  
  MODULE_LICENSE("GPL");
42d0b044b   Sven Eckelmann   batman-adv: Prefi...
1267
1268
1269
1270
  MODULE_AUTHOR(BATADV_DRIVER_AUTHOR);
  MODULE_DESCRIPTION(BATADV_DRIVER_DESC);
  MODULE_SUPPORTED_DEVICE(BATADV_DRIVER_DEVICE);
  MODULE_VERSION(BATADV_SOURCE_VERSION);