blob: c72d1bcdcf4906a1a23808cab2a464804a3fcda6 [file] [log] [blame]
Antonio Quartulli0b873932013-01-04 03:05:31 +01001/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00002 *
3 * Marek Lindner, Simon Wunderlich
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of version 2 of the GNU General Public
7 * License as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301, USA
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000018 */
19
Sven Eckelmann95a066d2012-10-17 21:10:39 +020020#include <linux/crc32c.h>
21#include <linux/highmem.h>
Simon Wunderlichc54f38c2013-07-29 17:56:44 +020022#include <linux/if_vlan.h>
23#include <net/ip.h>
24#include <net/ipv6.h>
25#include <net/dsfield.h>
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000026#include "main.h"
Sven Eckelmannb706b132012-06-10 23:58:51 +020027#include "sysfs.h"
28#include "debugfs.h"
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000029#include "routing.h"
30#include "send.h"
31#include "originator.h"
32#include "soft-interface.h"
33#include "icmp_socket.h"
34#include "translation-table.h"
35#include "hard-interface.h"
36#include "gateway_client.h"
Simon Wunderlich23721382012-01-22 20:00:19 +010037#include "bridge_loop_avoidance.h"
Antonio Quartulli2f1dfbe2012-06-30 20:01:19 +020038#include "distributed-arp-table.h"
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000039#include "vis.h"
40#include "hash.h"
Marek Lindner1c280472011-11-28 17:40:17 +080041#include "bat_algo.h"
Martin Hundebølld353d8d2013-01-25 11:12:38 +010042#include "network-coding.h"
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000043
Sven Eckelmannc3caf512011-05-03 11:51:38 +020044
45/* List manipulations on hardif_list have to be rtnl_lock()'ed,
Sven Eckelmann9cfc7bd2012-05-12 02:09:43 +020046 * list traversals just rcu-locked
47 */
Sven Eckelmann3193e8f2012-05-12 02:09:42 +020048struct list_head batadv_hardif_list;
Sven Eckelmannee11ad62012-05-16 20:23:19 +020049static int (*batadv_rx_handler[256])(struct sk_buff *,
Sven Eckelmann56303d32012-06-05 22:31:31 +020050 struct batadv_hard_iface *);
Sven Eckelmann3193e8f2012-05-12 02:09:42 +020051char batadv_routing_algo[20] = "BATMAN_IV";
Sven Eckelmannee11ad62012-05-16 20:23:19 +020052static struct hlist_head batadv_algo_list;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000053
Sven Eckelmann3193e8f2012-05-12 02:09:42 +020054unsigned char batadv_broadcast_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000055
Sven Eckelmann3193e8f2012-05-12 02:09:42 +020056struct workqueue_struct *batadv_event_workqueue;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000057
Sven Eckelmannee11ad62012-05-16 20:23:19 +020058static void batadv_recv_handler_init(void);
Marek Lindnerffa995e2012-03-01 15:35:17 +080059
Sven Eckelmannee11ad62012-05-16 20:23:19 +020060static int __init batadv_init(void)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000061{
Sven Eckelmann3193e8f2012-05-12 02:09:42 +020062 INIT_LIST_HEAD(&batadv_hardif_list);
Sven Eckelmannee11ad62012-05-16 20:23:19 +020063 INIT_HLIST_HEAD(&batadv_algo_list);
Marek Lindner1c280472011-11-28 17:40:17 +080064
Sven Eckelmannee11ad62012-05-16 20:23:19 +020065 batadv_recv_handler_init();
Marek Lindnerffa995e2012-03-01 15:35:17 +080066
Sven Eckelmann81c524f2012-05-12 02:09:22 +020067 batadv_iv_init();
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000068
Sven Eckelmann3193e8f2012-05-12 02:09:42 +020069 batadv_event_workqueue = create_singlethread_workqueue("bat_events");
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000070
Sven Eckelmann3193e8f2012-05-12 02:09:42 +020071 if (!batadv_event_workqueue)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000072 return -ENOMEM;
73
Sven Eckelmann9039dc72012-05-12 02:09:33 +020074 batadv_socket_init();
Sven Eckelmann40a072d2012-05-12 02:09:23 +020075 batadv_debugfs_init();
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000076
Sven Eckelmann95638772012-05-12 02:09:31 +020077 register_netdevice_notifier(&batadv_hard_if_notifier);
Sven Eckelmanna4ac28c2013-02-11 17:10:26 +080078 rtnl_link_register(&batadv_link_ops);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000079
Sven Eckelmann86ceb362012-03-07 09:07:45 +010080 pr_info("B.A.T.M.A.N. advanced %s (compatibility version %i) loaded\n",
Sven Eckelmann42d0b042012-06-03 22:19:17 +020081 BATADV_SOURCE_VERSION, BATADV_COMPAT_VERSION);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000082
83 return 0;
84}
85
Sven Eckelmannee11ad62012-05-16 20:23:19 +020086static void __exit batadv_exit(void)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000087{
Sven Eckelmann40a072d2012-05-12 02:09:23 +020088 batadv_debugfs_destroy();
Sven Eckelmanna4ac28c2013-02-11 17:10:26 +080089 rtnl_link_unregister(&batadv_link_ops);
Sven Eckelmann95638772012-05-12 02:09:31 +020090 unregister_netdevice_notifier(&batadv_hard_if_notifier);
91 batadv_hardif_remove_interfaces();
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000092
Sven Eckelmann3193e8f2012-05-12 02:09:42 +020093 flush_workqueue(batadv_event_workqueue);
94 destroy_workqueue(batadv_event_workqueue);
95 batadv_event_workqueue = NULL;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000096
97 rcu_barrier();
98}
99
Sven Eckelmann3193e8f2012-05-12 02:09:42 +0200100int batadv_mesh_init(struct net_device *soft_iface)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000101{
Sven Eckelmann56303d32012-06-05 22:31:31 +0200102 struct batadv_priv *bat_priv = netdev_priv(soft_iface);
Sven Eckelmann5346c352012-05-05 13:27:28 +0200103 int ret;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000104
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000105 spin_lock_init(&bat_priv->forw_bat_list_lock);
106 spin_lock_init(&bat_priv->forw_bcast_list_lock);
Sven Eckelmann807736f2012-07-15 22:26:51 +0200107 spin_lock_init(&bat_priv->tt.changes_list_lock);
108 spin_lock_init(&bat_priv->tt.req_list_lock);
109 spin_lock_init(&bat_priv->tt.roam_list_lock);
110 spin_lock_init(&bat_priv->tt.last_changeset_lock);
111 spin_lock_init(&bat_priv->gw.list_lock);
112 spin_lock_init(&bat_priv->vis.hash_lock);
113 spin_lock_init(&bat_priv->vis.list_lock);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000114
115 INIT_HLIST_HEAD(&bat_priv->forw_bat_list);
116 INIT_HLIST_HEAD(&bat_priv->forw_bcast_list);
Sven Eckelmann807736f2012-07-15 22:26:51 +0200117 INIT_HLIST_HEAD(&bat_priv->gw.list);
118 INIT_LIST_HEAD(&bat_priv->tt.changes_list);
119 INIT_LIST_HEAD(&bat_priv->tt.req_list);
120 INIT_LIST_HEAD(&bat_priv->tt.roam_list);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000121
Sven Eckelmann7d211ef2012-05-12 02:09:34 +0200122 ret = batadv_originator_init(bat_priv);
Sven Eckelmann5346c352012-05-05 13:27:28 +0200123 if (ret < 0)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000124 goto err;
125
Sven Eckelmann08c36d32012-05-12 02:09:39 +0200126 ret = batadv_tt_init(bat_priv);
Sven Eckelmann5346c352012-05-05 13:27:28 +0200127 if (ret < 0)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000128 goto err;
129
Sven Eckelmann42d0b042012-06-03 22:19:17 +0200130 batadv_tt_local_add(soft_iface, soft_iface->dev_addr,
131 BATADV_NULL_IFINDEX);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000132
Sven Eckelmannd0f714f2012-05-12 02:09:41 +0200133 ret = batadv_vis_init(bat_priv);
Sven Eckelmann5346c352012-05-05 13:27:28 +0200134 if (ret < 0)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000135 goto err;
136
Sven Eckelmann08adf152012-05-12 13:38:47 +0200137 ret = batadv_bla_init(bat_priv);
Sven Eckelmann5346c352012-05-05 13:27:28 +0200138 if (ret < 0)
Simon Wunderlich23721382012-01-22 20:00:19 +0100139 goto err;
140
Antonio Quartulli2f1dfbe2012-06-30 20:01:19 +0200141 ret = batadv_dat_init(bat_priv);
142 if (ret < 0)
143 goto err;
144
Martin Hundebølld353d8d2013-01-25 11:12:38 +0100145 ret = batadv_nc_init(bat_priv);
146 if (ret < 0)
147 goto err;
148
Sven Eckelmann807736f2012-07-15 22:26:51 +0200149 atomic_set(&bat_priv->gw.reselect, 0);
Sven Eckelmann39c75a52012-06-03 22:19:22 +0200150 atomic_set(&bat_priv->mesh_state, BATADV_MESH_ACTIVE);
Sven Eckelmann5346c352012-05-05 13:27:28 +0200151
152 return 0;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000153
154err:
Sven Eckelmann3193e8f2012-05-12 02:09:42 +0200155 batadv_mesh_free(soft_iface);
Sven Eckelmann5346c352012-05-05 13:27:28 +0200156 return ret;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000157}
158
Sven Eckelmann3193e8f2012-05-12 02:09:42 +0200159void batadv_mesh_free(struct net_device *soft_iface)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000160{
Sven Eckelmann56303d32012-06-05 22:31:31 +0200161 struct batadv_priv *bat_priv = netdev_priv(soft_iface);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000162
Sven Eckelmann39c75a52012-06-03 22:19:22 +0200163 atomic_set(&bat_priv->mesh_state, BATADV_MESH_DEACTIVATING);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000164
Sven Eckelmann9455e342012-05-12 02:09:37 +0200165 batadv_purge_outstanding_packets(bat_priv, NULL);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000166
Sven Eckelmannd0f714f2012-05-12 02:09:41 +0200167 batadv_vis_quit(bat_priv);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000168
Sven Eckelmann7cf06bc2012-05-12 02:09:29 +0200169 batadv_gw_node_purge(bat_priv);
Martin Hundebølld353d8d2013-01-25 11:12:38 +0100170 batadv_nc_free(bat_priv);
Antonio Quartullia4361862013-05-07 01:06:18 +0200171 batadv_dat_free(bat_priv);
Sven Eckelmann08adf152012-05-12 13:38:47 +0200172 batadv_bla_free(bat_priv);
Simon Wunderlich23721382012-01-22 20:00:19 +0100173
Antonio Quartullia4361862013-05-07 01:06:18 +0200174 /* Free the TT and the originator tables only after having terminated
175 * all the other depending components which may use these structures for
176 * their purposes.
177 */
178 batadv_tt_free(bat_priv);
179
180 /* Since the originator table clean up routine is accessing the TT
181 * tables as well, it has to be invoked after the TT tables have been
182 * freed and marked as empty. This ensures that no cleanup RCU callbacks
183 * accessing the TT data are scheduled for later execution.
184 */
185 batadv_originator_free(bat_priv);
Antonio Quartulli2f1dfbe2012-06-30 20:01:19 +0200186
Martin Hundebøllf8214862012-04-20 17:02:45 +0200187 free_percpu(bat_priv->bat_counters);
Martin Hundebøllf69ae772013-04-17 21:13:16 +0200188 bat_priv->bat_counters = NULL;
Martin Hundebøllf8214862012-04-20 17:02:45 +0200189
Sven Eckelmann39c75a52012-06-03 22:19:22 +0200190 atomic_set(&bat_priv->mesh_state, BATADV_MESH_INACTIVE);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000191}
192
David S. Miller6e0895c2013-04-22 20:32:51 -0400193/**
194 * batadv_is_my_mac - check if the given mac address belongs to any of the real
195 * interfaces in the current mesh
196 * @bat_priv: the bat priv with all the soft interface information
197 * @addr: the address to check
198 */
Antonio Quartullife8a93b2013-04-03 19:10:26 +0200199int batadv_is_my_mac(struct batadv_priv *bat_priv, const uint8_t *addr)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000200{
Sven Eckelmann56303d32012-06-05 22:31:31 +0200201 const struct batadv_hard_iface *hard_iface;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000202
203 rcu_read_lock();
Sven Eckelmann3193e8f2012-05-12 02:09:42 +0200204 list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
Sven Eckelmanne9a4f292012-06-03 22:19:19 +0200205 if (hard_iface->if_status != BATADV_IF_ACTIVE)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000206 continue;
207
Antonio Quartullife8a93b2013-04-03 19:10:26 +0200208 if (hard_iface->soft_iface != bat_priv->soft_iface)
209 continue;
210
Sven Eckelmann1eda58b2012-05-12 13:48:58 +0200211 if (batadv_compare_eth(hard_iface->net_dev->dev_addr, addr)) {
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000212 rcu_read_unlock();
213 return 1;
214 }
215 }
216 rcu_read_unlock();
217 return 0;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000218}
219
Marek Lindner30da63a2012-08-03 17:15:46 +0200220/**
221 * batadv_seq_print_text_primary_if_get - called from debugfs table printing
222 * function that requires the primary interface
223 * @seq: debugfs table seq_file struct
224 *
225 * Returns primary interface if found or NULL otherwise.
226 */
227struct batadv_hard_iface *
228batadv_seq_print_text_primary_if_get(struct seq_file *seq)
229{
230 struct net_device *net_dev = (struct net_device *)seq->private;
231 struct batadv_priv *bat_priv = netdev_priv(net_dev);
232 struct batadv_hard_iface *primary_if;
233
234 primary_if = batadv_primary_if_get_selected(bat_priv);
235
236 if (!primary_if) {
237 seq_printf(seq,
238 "BATMAN mesh %s disabled - please specify interfaces to enable it\n",
239 net_dev->name);
240 goto out;
241 }
242
243 if (primary_if->if_status == BATADV_IF_ACTIVE)
244 goto out;
245
246 seq_printf(seq,
247 "BATMAN mesh %s disabled - primary interface not active\n",
248 net_dev->name);
249 batadv_hardif_free_ref(primary_if);
250 primary_if = NULL;
251
252out:
253 return primary_if;
254}
255
Simon Wunderlichc54f38c2013-07-29 17:56:44 +0200256/**
257 * batadv_skb_set_priority - sets skb priority according to packet content
258 * @skb: the packet to be sent
259 * @offset: offset to the packet content
260 *
261 * This function sets a value between 256 and 263 (802.1d priority), which
262 * can be interpreted by the cfg80211 or other drivers.
263 */
264void batadv_skb_set_priority(struct sk_buff *skb, int offset)
265{
266 struct iphdr ip_hdr_tmp, *ip_hdr;
267 struct ipv6hdr ip6_hdr_tmp, *ip6_hdr;
268 struct ethhdr ethhdr_tmp, *ethhdr;
269 struct vlan_ethhdr *vhdr, vhdr_tmp;
270 u32 prio;
271
272 /* already set, do nothing */
273 if (skb->priority >= 256 && skb->priority <= 263)
274 return;
275
276 ethhdr = skb_header_pointer(skb, offset, sizeof(*ethhdr), &ethhdr_tmp);
277 if (!ethhdr)
278 return;
279
280 switch (ethhdr->h_proto) {
281 case htons(ETH_P_8021Q):
282 vhdr = skb_header_pointer(skb, offset + sizeof(*vhdr),
283 sizeof(*vhdr), &vhdr_tmp);
284 if (!vhdr)
285 return;
286 prio = ntohs(vhdr->h_vlan_TCI) & VLAN_PRIO_MASK;
287 prio = prio >> VLAN_PRIO_SHIFT;
288 break;
289 case htons(ETH_P_IP):
290 ip_hdr = skb_header_pointer(skb, offset + sizeof(*ethhdr),
291 sizeof(*ip_hdr), &ip_hdr_tmp);
292 if (!ip_hdr)
293 return;
294 prio = (ipv4_get_dsfield(ip_hdr) & 0xfc) >> 5;
295 break;
296 case htons(ETH_P_IPV6):
297 ip6_hdr = skb_header_pointer(skb, offset + sizeof(*ethhdr),
298 sizeof(*ip6_hdr), &ip6_hdr_tmp);
299 if (!ip6_hdr)
300 return;
301 prio = (ipv6_get_dsfield(ip6_hdr) & 0xfc) >> 5;
302 break;
303 default:
304 return;
305 }
306
307 skb->priority = prio + 256;
308}
309
Sven Eckelmannee11ad62012-05-16 20:23:19 +0200310static int batadv_recv_unhandled_packet(struct sk_buff *skb,
Sven Eckelmann56303d32012-06-05 22:31:31 +0200311 struct batadv_hard_iface *recv_if)
Marek Lindnerffa995e2012-03-01 15:35:17 +0800312{
313 return NET_RX_DROP;
314}
315
316/* incoming packets with the batman ethertype received on any active hard
317 * interface
318 */
Sven Eckelmann3193e8f2012-05-12 02:09:42 +0200319int batadv_batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
320 struct packet_type *ptype,
321 struct net_device *orig_dev)
Marek Lindnerffa995e2012-03-01 15:35:17 +0800322{
Sven Eckelmann56303d32012-06-05 22:31:31 +0200323 struct batadv_priv *bat_priv;
Sven Eckelmann96412692012-06-05 22:31:30 +0200324 struct batadv_ogm_packet *batadv_ogm_packet;
Sven Eckelmann56303d32012-06-05 22:31:31 +0200325 struct batadv_hard_iface *hard_iface;
Marek Lindnerffa995e2012-03-01 15:35:17 +0800326 uint8_t idx;
327 int ret;
328
Sven Eckelmann56303d32012-06-05 22:31:31 +0200329 hard_iface = container_of(ptype, struct batadv_hard_iface,
330 batman_adv_ptype);
Marek Lindnerffa995e2012-03-01 15:35:17 +0800331 skb = skb_share_check(skb, GFP_ATOMIC);
332
333 /* skb was released by skb_share_check() */
334 if (!skb)
335 goto err_out;
336
337 /* packet should hold at least type and version */
338 if (unlikely(!pskb_may_pull(skb, 2)))
339 goto err_free;
340
341 /* expect a valid ethernet header here. */
342 if (unlikely(skb->mac_len != ETH_HLEN || !skb_mac_header(skb)))
343 goto err_free;
344
345 if (!hard_iface->soft_iface)
346 goto err_free;
347
348 bat_priv = netdev_priv(hard_iface->soft_iface);
349
Sven Eckelmann39c75a52012-06-03 22:19:22 +0200350 if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE)
Marek Lindnerffa995e2012-03-01 15:35:17 +0800351 goto err_free;
352
353 /* discard frames on not active interfaces */
Sven Eckelmanne9a4f292012-06-03 22:19:19 +0200354 if (hard_iface->if_status != BATADV_IF_ACTIVE)
Marek Lindnerffa995e2012-03-01 15:35:17 +0800355 goto err_free;
356
Sven Eckelmann96412692012-06-05 22:31:30 +0200357 batadv_ogm_packet = (struct batadv_ogm_packet *)skb->data;
Marek Lindnerffa995e2012-03-01 15:35:17 +0800358
Sven Eckelmann96412692012-06-05 22:31:30 +0200359 if (batadv_ogm_packet->header.version != BATADV_COMPAT_VERSION) {
Sven Eckelmann39c75a52012-06-03 22:19:22 +0200360 batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
Sven Eckelmann1eda58b2012-05-12 13:48:58 +0200361 "Drop packet: incompatible batman version (%i)\n",
Sven Eckelmann96412692012-06-05 22:31:30 +0200362 batadv_ogm_packet->header.version);
Marek Lindnerffa995e2012-03-01 15:35:17 +0800363 goto err_free;
364 }
365
366 /* all receive handlers return whether they received or reused
367 * the supplied skb. if not, we have to free the skb.
368 */
Sven Eckelmann96412692012-06-05 22:31:30 +0200369 idx = batadv_ogm_packet->header.packet_type;
Sven Eckelmannee11ad62012-05-16 20:23:19 +0200370 ret = (*batadv_rx_handler[idx])(skb, hard_iface);
Marek Lindnerffa995e2012-03-01 15:35:17 +0800371
372 if (ret == NET_RX_DROP)
373 kfree_skb(skb);
374
375 /* return NET_RX_SUCCESS in any case as we
376 * most probably dropped the packet for
377 * routing-logical reasons.
378 */
379 return NET_RX_SUCCESS;
380
381err_free:
382 kfree_skb(skb);
383err_out:
384 return NET_RX_DROP;
385}
386
Sven Eckelmannee11ad62012-05-16 20:23:19 +0200387static void batadv_recv_handler_init(void)
Marek Lindnerffa995e2012-03-01 15:35:17 +0800388{
389 int i;
390
Sven Eckelmannee11ad62012-05-16 20:23:19 +0200391 for (i = 0; i < ARRAY_SIZE(batadv_rx_handler); i++)
392 batadv_rx_handler[i] = batadv_recv_unhandled_packet;
Marek Lindnerffa995e2012-03-01 15:35:17 +0800393
Marek Lindnerffa995e2012-03-01 15:35:17 +0800394 /* batman icmp packet */
Sven Eckelmannacd34af2012-06-03 22:19:21 +0200395 batadv_rx_handler[BATADV_ICMP] = batadv_recv_icmp_packet;
Antonio Quartulli7cdcf6d2012-10-01 09:57:35 +0200396 /* unicast with 4 addresses packet */
397 batadv_rx_handler[BATADV_UNICAST_4ADDR] = batadv_recv_unicast_packet;
Marek Lindnerffa995e2012-03-01 15:35:17 +0800398 /* unicast packet */
Sven Eckelmannacd34af2012-06-03 22:19:21 +0200399 batadv_rx_handler[BATADV_UNICAST] = batadv_recv_unicast_packet;
Marek Lindnerffa995e2012-03-01 15:35:17 +0800400 /* fragmented unicast packet */
Sven Eckelmannacd34af2012-06-03 22:19:21 +0200401 batadv_rx_handler[BATADV_UNICAST_FRAG] = batadv_recv_ucast_frag_packet;
Marek Lindnerffa995e2012-03-01 15:35:17 +0800402 /* broadcast packet */
Sven Eckelmannacd34af2012-06-03 22:19:21 +0200403 batadv_rx_handler[BATADV_BCAST] = batadv_recv_bcast_packet;
Marek Lindnerffa995e2012-03-01 15:35:17 +0800404 /* vis packet */
Sven Eckelmannacd34af2012-06-03 22:19:21 +0200405 batadv_rx_handler[BATADV_VIS] = batadv_recv_vis_packet;
Marek Lindnerffa995e2012-03-01 15:35:17 +0800406 /* Translation table query (request or response) */
Sven Eckelmannacd34af2012-06-03 22:19:21 +0200407 batadv_rx_handler[BATADV_TT_QUERY] = batadv_recv_tt_query;
Marek Lindnerffa995e2012-03-01 15:35:17 +0800408 /* Roaming advertisement */
Sven Eckelmannacd34af2012-06-03 22:19:21 +0200409 batadv_rx_handler[BATADV_ROAM_ADV] = batadv_recv_roam_adv;
Marek Lindnerffa995e2012-03-01 15:35:17 +0800410}
411
Sven Eckelmann56303d32012-06-05 22:31:31 +0200412int
413batadv_recv_handler_register(uint8_t packet_type,
414 int (*recv_handler)(struct sk_buff *,
415 struct batadv_hard_iface *))
Marek Lindnerffa995e2012-03-01 15:35:17 +0800416{
Sven Eckelmannee11ad62012-05-16 20:23:19 +0200417 if (batadv_rx_handler[packet_type] != &batadv_recv_unhandled_packet)
Marek Lindnerffa995e2012-03-01 15:35:17 +0800418 return -EBUSY;
419
Sven Eckelmannee11ad62012-05-16 20:23:19 +0200420 batadv_rx_handler[packet_type] = recv_handler;
Marek Lindnerffa995e2012-03-01 15:35:17 +0800421 return 0;
422}
423
Sven Eckelmann3193e8f2012-05-12 02:09:42 +0200424void batadv_recv_handler_unregister(uint8_t packet_type)
Marek Lindnerffa995e2012-03-01 15:35:17 +0800425{
Sven Eckelmannee11ad62012-05-16 20:23:19 +0200426 batadv_rx_handler[packet_type] = batadv_recv_unhandled_packet;
Marek Lindnerffa995e2012-03-01 15:35:17 +0800427}
428
Sven Eckelmann56303d32012-06-05 22:31:31 +0200429static struct batadv_algo_ops *batadv_algo_get(char *name)
Marek Lindner1c280472011-11-28 17:40:17 +0800430{
Sven Eckelmann56303d32012-06-05 22:31:31 +0200431 struct batadv_algo_ops *bat_algo_ops = NULL, *bat_algo_ops_tmp;
Marek Lindner1c280472011-11-28 17:40:17 +0800432
Sasha Levinb67bfe02013-02-27 17:06:00 -0800433 hlist_for_each_entry(bat_algo_ops_tmp, &batadv_algo_list, list) {
Marek Lindner1c280472011-11-28 17:40:17 +0800434 if (strcmp(bat_algo_ops_tmp->name, name) != 0)
435 continue;
436
437 bat_algo_ops = bat_algo_ops_tmp;
438 break;
439 }
440
441 return bat_algo_ops;
442}
443
Sven Eckelmann56303d32012-06-05 22:31:31 +0200444int batadv_algo_register(struct batadv_algo_ops *bat_algo_ops)
Marek Lindner1c280472011-11-28 17:40:17 +0800445{
Sven Eckelmann56303d32012-06-05 22:31:31 +0200446 struct batadv_algo_ops *bat_algo_ops_tmp;
Sven Eckelmann5346c352012-05-05 13:27:28 +0200447 int ret;
Marek Lindner1c280472011-11-28 17:40:17 +0800448
Sven Eckelmannee11ad62012-05-16 20:23:19 +0200449 bat_algo_ops_tmp = batadv_algo_get(bat_algo_ops->name);
Marek Lindner1c280472011-11-28 17:40:17 +0800450 if (bat_algo_ops_tmp) {
Sven Eckelmann86ceb362012-03-07 09:07:45 +0100451 pr_info("Trying to register already registered routing algorithm: %s\n",
452 bat_algo_ops->name);
Sven Eckelmann5346c352012-05-05 13:27:28 +0200453 ret = -EEXIST;
Marek Lindner1c280472011-11-28 17:40:17 +0800454 goto out;
455 }
456
Marek Lindner01c42242011-11-28 21:31:55 +0800457 /* all algorithms must implement all ops (for now) */
Marek Lindnerc2aca022012-02-07 17:20:45 +0800458 if (!bat_algo_ops->bat_iface_enable ||
Marek Lindner00a50072012-02-07 17:20:47 +0800459 !bat_algo_ops->bat_iface_disable ||
Marek Lindnerc3229392012-03-11 06:17:50 +0800460 !bat_algo_ops->bat_iface_update_mac ||
Marek Lindnercd8b78e2012-02-07 17:20:49 +0800461 !bat_algo_ops->bat_primary_iface_set ||
Marek Lindner01c42242011-11-28 21:31:55 +0800462 !bat_algo_ops->bat_ogm_schedule ||
Marek Lindnerc3e29312012-03-04 16:56:25 +0800463 !bat_algo_ops->bat_ogm_emit) {
Marek Lindner01c42242011-11-28 21:31:55 +0800464 pr_info("Routing algo '%s' does not implement required ops\n",
465 bat_algo_ops->name);
Sven Eckelmann5346c352012-05-05 13:27:28 +0200466 ret = -EINVAL;
Marek Lindner01c42242011-11-28 21:31:55 +0800467 goto out;
468 }
469
Marek Lindner1c280472011-11-28 17:40:17 +0800470 INIT_HLIST_NODE(&bat_algo_ops->list);
Sven Eckelmannee11ad62012-05-16 20:23:19 +0200471 hlist_add_head(&bat_algo_ops->list, &batadv_algo_list);
Marek Lindner1c280472011-11-28 17:40:17 +0800472 ret = 0;
473
474out:
475 return ret;
476}
477
Sven Eckelmann56303d32012-06-05 22:31:31 +0200478int batadv_algo_select(struct batadv_priv *bat_priv, char *name)
Marek Lindner1c280472011-11-28 17:40:17 +0800479{
Sven Eckelmann56303d32012-06-05 22:31:31 +0200480 struct batadv_algo_ops *bat_algo_ops;
Sven Eckelmann5346c352012-05-05 13:27:28 +0200481 int ret = -EINVAL;
Marek Lindner1c280472011-11-28 17:40:17 +0800482
Sven Eckelmannee11ad62012-05-16 20:23:19 +0200483 bat_algo_ops = batadv_algo_get(name);
Marek Lindner1c280472011-11-28 17:40:17 +0800484 if (!bat_algo_ops)
485 goto out;
486
487 bat_priv->bat_algo_ops = bat_algo_ops;
488 ret = 0;
489
490out:
491 return ret;
492}
493
Sven Eckelmann3193e8f2012-05-12 02:09:42 +0200494int batadv_algo_seq_print_text(struct seq_file *seq, void *offset)
Marek Lindner1c280472011-11-28 17:40:17 +0800495{
Sven Eckelmann56303d32012-06-05 22:31:31 +0200496 struct batadv_algo_ops *bat_algo_ops;
Marek Lindner1c280472011-11-28 17:40:17 +0800497
Antonio Quartulli0c814652013-03-21 09:23:29 +0100498 seq_puts(seq, "Available routing algorithms:\n");
Marek Lindner1c280472011-11-28 17:40:17 +0800499
Sasha Levinb67bfe02013-02-27 17:06:00 -0800500 hlist_for_each_entry(bat_algo_ops, &batadv_algo_list, list) {
Marek Lindner1c280472011-11-28 17:40:17 +0800501 seq_printf(seq, "%s\n", bat_algo_ops->name);
502 }
503
504 return 0;
505}
506
Sven Eckelmann95a066d2012-10-17 21:10:39 +0200507/**
508 * batadv_skb_crc32 - calculate CRC32 of the whole packet and skip bytes in
509 * the header
510 * @skb: skb pointing to fragmented socket buffers
511 * @payload_ptr: Pointer to position inside the head buffer of the skb
512 * marking the start of the data to be CRC'ed
513 *
514 * payload_ptr must always point to an address in the skb head buffer and not to
515 * a fragment.
516 */
517__be32 batadv_skb_crc32(struct sk_buff *skb, u8 *payload_ptr)
518{
519 u32 crc = 0;
520 unsigned int from;
521 unsigned int to = skb->len;
522 struct skb_seq_state st;
523 const u8 *data;
524 unsigned int len;
525 unsigned int consumed = 0;
526
527 from = (unsigned int)(payload_ptr - skb->data);
528
529 skb_prepare_seq_read(skb, from, to, &st);
530 while ((len = skb_seq_read(consumed, &data, &st)) != 0) {
531 crc = crc32c(crc, data, len);
532 consumed += len;
533 }
Sven Eckelmann95a066d2012-10-17 21:10:39 +0200534
535 return htonl(crc);
536}
537
Sven Eckelmannee11ad62012-05-16 20:23:19 +0200538static int batadv_param_set_ra(const char *val, const struct kernel_param *kp)
Marek Lindnerd419be12011-12-10 19:45:53 +0800539{
Sven Eckelmann56303d32012-06-05 22:31:31 +0200540 struct batadv_algo_ops *bat_algo_ops;
Marek Lindnerd8cb54862012-04-18 17:16:39 +0800541 char *algo_name = (char *)val;
542 size_t name_len = strlen(algo_name);
Marek Lindnerd419be12011-12-10 19:45:53 +0800543
Marek Lindner293c9c12013-04-27 16:22:28 +0800544 if (name_len > 0 && algo_name[name_len - 1] == '\n')
Marek Lindnerd8cb54862012-04-18 17:16:39 +0800545 algo_name[name_len - 1] = '\0';
546
Sven Eckelmannee11ad62012-05-16 20:23:19 +0200547 bat_algo_ops = batadv_algo_get(algo_name);
Marek Lindnerd419be12011-12-10 19:45:53 +0800548 if (!bat_algo_ops) {
Marek Lindnerd8cb54862012-04-18 17:16:39 +0800549 pr_err("Routing algorithm '%s' is not supported\n", algo_name);
Marek Lindnerd419be12011-12-10 19:45:53 +0800550 return -EINVAL;
551 }
552
Marek Lindnerd8cb54862012-04-18 17:16:39 +0800553 return param_set_copystring(algo_name, kp);
Marek Lindnerd419be12011-12-10 19:45:53 +0800554}
555
Sven Eckelmannee11ad62012-05-16 20:23:19 +0200556static const struct kernel_param_ops batadv_param_ops_ra = {
557 .set = batadv_param_set_ra,
Marek Lindnerd419be12011-12-10 19:45:53 +0800558 .get = param_get_string,
559};
560
Sven Eckelmannee11ad62012-05-16 20:23:19 +0200561static struct kparam_string batadv_param_string_ra = {
Sven Eckelmann3193e8f2012-05-12 02:09:42 +0200562 .maxlen = sizeof(batadv_routing_algo),
563 .string = batadv_routing_algo,
Marek Lindnerd419be12011-12-10 19:45:53 +0800564};
565
Sven Eckelmannee11ad62012-05-16 20:23:19 +0200566module_param_cb(routing_algo, &batadv_param_ops_ra, &batadv_param_string_ra,
567 0644);
568module_init(batadv_init);
569module_exit(batadv_exit);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000570
571MODULE_LICENSE("GPL");
572
Sven Eckelmann42d0b042012-06-03 22:19:17 +0200573MODULE_AUTHOR(BATADV_DRIVER_AUTHOR);
574MODULE_DESCRIPTION(BATADV_DRIVER_DESC);
575MODULE_SUPPORTED_DEVICE(BATADV_DRIVER_DEVICE);
576MODULE_VERSION(BATADV_SOURCE_VERSION);