Blame view
net/batman-adv/main.c
37.1 KB
0046b0402
|
1 |
/* Copyright (C) 2007-2016 B.A.T.M.A.N. contributors: |
c6c8fea29
|
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
|
15 |
* along with this program; if not, see <http://www.gnu.org/licenses/>. |
c6c8fea29
|
16 |
*/ |
1e2c2a4fe
|
17 18 19 20 21 |
#include "main.h" #include <linux/atomic.h> #include <linux/bug.h> #include <linux/byteorder/generic.h> |
95a066d82
|
22 |
#include <linux/crc32c.h> |
1e2c2a4fe
|
23 24 25 |
#include <linux/errno.h> #include <linux/fs.h> #include <linux/if_ether.h> |
c54f38c9a
|
26 |
#include <linux/if_vlan.h> |
1e2c2a4fe
|
27 28 29 30 |
#include <linux/init.h> #include <linux/ip.h> #include <linux/ipv6.h> #include <linux/kernel.h> |
f7157dd13
|
31 |
#include <linux/kref.h> |
1e2c2a4fe
|
32 |
#include <linux/list.h> |
2c72d655b
|
33 |
#include <linux/lockdep.h> |
1e2c2a4fe
|
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
|
47 |
#include <net/dsfield.h> |
1e2c2a4fe
|
48 49 50 51 |
#include <net/rtnetlink.h> #include "bat_algo.h" #include "bridge_loop_avoidance.h" |
b706b13b6
|
52 |
#include "debugfs.h" |
1e2c2a4fe
|
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
|
62 63 |
#include "routing.h" #include "send.h" |
c6c8fea29
|
64 |
#include "soft-interface.h" |
c6c8fea29
|
65 |
#include "translation-table.h" |
c6c8fea29
|
66 |
|
c3caf5196
|
67 |
/* List manipulations on hardif_list have to be rtnl_lock()'ed, |
9cfc7bd60
|
68 69 |
* list traversals just rcu-locked */ |
3193e8fdf
|
70 |
struct list_head batadv_hardif_list; |
ee11ad61f
|
71 |
static int (*batadv_rx_handler[256])(struct sk_buff *, |
56303d34a
|
72 |
struct batadv_hard_iface *); |
3193e8fdf
|
73 |
char batadv_routing_algo[20] = "BATMAN_IV"; |
ee11ad61f
|
74 |
static struct hlist_head batadv_algo_list; |
c6c8fea29
|
75 |
|
3193e8fdf
|
76 |
unsigned char batadv_broadcast_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; |
c6c8fea29
|
77 |
|
3193e8fdf
|
78 |
struct workqueue_struct *batadv_event_workqueue; |
c6c8fea29
|
79 |
|
ee11ad61f
|
80 |
static void batadv_recv_handler_init(void); |
ffa995e03
|
81 |
|
ee11ad61f
|
82 |
static int __init batadv_init(void) |
c6c8fea29
|
83 |
{ |
3193e8fdf
|
84 |
INIT_LIST_HEAD(&batadv_hardif_list); |
ee11ad61f
|
85 |
INIT_HLIST_HEAD(&batadv_algo_list); |
1c280471b
|
86 |
|
ee11ad61f
|
87 |
batadv_recv_handler_init(); |
ffa995e03
|
88 |
|
81c524f76
|
89 |
batadv_iv_init(); |
6c519bad7
|
90 |
batadv_nc_init(); |
c6c8fea29
|
91 |
|
3193e8fdf
|
92 |
batadv_event_workqueue = create_singlethread_workqueue("bat_events"); |
c6c8fea29
|
93 |
|
3193e8fdf
|
94 |
if (!batadv_event_workqueue) |
c6c8fea29
|
95 |
return -ENOMEM; |
9039dc7e8
|
96 |
batadv_socket_init(); |
40a072d77
|
97 |
batadv_debugfs_init(); |
c6c8fea29
|
98 |
|
9563877ea
|
99 |
register_netdevice_notifier(&batadv_hard_if_notifier); |
a4ac28c0d
|
100 |
rtnl_link_register(&batadv_link_ops); |
c6c8fea29
|
101 |
|
86ceb3605
|
102 103 |
pr_info("B.A.T.M.A.N. advanced %s (compatibility version %i) loaded ", |
42d0b044b
|
104 |
BATADV_SOURCE_VERSION, BATADV_COMPAT_VERSION); |
c6c8fea29
|
105 106 107 |
return 0; } |
ee11ad61f
|
108 |
static void __exit batadv_exit(void) |
c6c8fea29
|
109 |
{ |
40a072d77
|
110 |
batadv_debugfs_destroy(); |
a4ac28c0d
|
111 |
rtnl_link_unregister(&batadv_link_ops); |
9563877ea
|
112 113 |
unregister_netdevice_notifier(&batadv_hard_if_notifier); batadv_hardif_remove_interfaces(); |
c6c8fea29
|
114 |
|
3193e8fdf
|
115 116 117 |
flush_workqueue(batadv_event_workqueue); destroy_workqueue(batadv_event_workqueue); batadv_event_workqueue = NULL; |
c6c8fea29
|
118 119 120 |
rcu_barrier(); } |
3193e8fdf
|
121 |
int batadv_mesh_init(struct net_device *soft_iface) |
c6c8fea29
|
122 |
{ |
56303d34a
|
123 |
struct batadv_priv *bat_priv = netdev_priv(soft_iface); |
5346c35eb
|
124 |
int ret; |
c6c8fea29
|
125 |
|
c6c8fea29
|
126 127 |
spin_lock_init(&bat_priv->forw_bat_list_lock); spin_lock_init(&bat_priv->forw_bcast_list_lock); |
807736f6e
|
128 129 130 131 |
spin_lock_init(&bat_priv->tt.changes_list_lock); spin_lock_init(&bat_priv->tt.req_list_lock); spin_lock_init(&bat_priv->tt.roam_list_lock); spin_lock_init(&bat_priv->tt.last_changeset_lock); |
a70a9aa99
|
132 |
spin_lock_init(&bat_priv->tt.commit_lock); |
807736f6e
|
133 |
spin_lock_init(&bat_priv->gw.list_lock); |
ab49886e3
|
134 135 136 |
#ifdef CONFIG_BATMAN_ADV_MCAST spin_lock_init(&bat_priv->mcast.want_lists_lock); #endif |
ef2615774
|
137 138 |
spin_lock_init(&bat_priv->tvlv.container_list_lock); spin_lock_init(&bat_priv->tvlv.handler_list_lock); |
5d2c05b21
|
139 |
spin_lock_init(&bat_priv->softif_vlan_list_lock); |
c6c8fea29
|
140 141 142 |
INIT_HLIST_HEAD(&bat_priv->forw_bat_list); INIT_HLIST_HEAD(&bat_priv->forw_bcast_list); |
807736f6e
|
143 |
INIT_HLIST_HEAD(&bat_priv->gw.list); |
ab49886e3
|
144 145 |
#ifdef CONFIG_BATMAN_ADV_MCAST INIT_HLIST_HEAD(&bat_priv->mcast.want_all_unsnoopables_list); |
4c8755d69
|
146 147 |
INIT_HLIST_HEAD(&bat_priv->mcast.want_all_ipv4_list); INIT_HLIST_HEAD(&bat_priv->mcast.want_all_ipv6_list); |
ab49886e3
|
148 |
#endif |
807736f6e
|
149 |
INIT_LIST_HEAD(&bat_priv->tt.changes_list); |
7c26a53ba
|
150 |
INIT_HLIST_HEAD(&bat_priv->tt.req_list); |
807736f6e
|
151 |
INIT_LIST_HEAD(&bat_priv->tt.roam_list); |
c5caf4ef3
|
152 153 154 |
#ifdef CONFIG_BATMAN_ADV_MCAST INIT_HLIST_HEAD(&bat_priv->mcast.mla_list); #endif |
ef2615774
|
155 156 |
INIT_HLIST_HEAD(&bat_priv->tvlv.container_list); INIT_HLIST_HEAD(&bat_priv->tvlv.handler_list); |
5d2c05b21
|
157 |
INIT_HLIST_HEAD(&bat_priv->softif_vlan_list); |
c6c8fea29
|
158 |
|
7d211efc5
|
159 |
ret = batadv_originator_init(bat_priv); |
5346c35eb
|
160 |
if (ret < 0) |
c6c8fea29
|
161 |
goto err; |
08c36d3e8
|
162 |
ret = batadv_tt_init(bat_priv); |
5346c35eb
|
163 |
if (ret < 0) |
c6c8fea29
|
164 |
goto err; |
08adf1512
|
165 |
ret = batadv_bla_init(bat_priv); |
5346c35eb
|
166 |
if (ret < 0) |
23721387c
|
167 |
goto err; |
2f1dfbe18
|
168 169 170 |
ret = batadv_dat_init(bat_priv); if (ret < 0) goto err; |
6c519bad7
|
171 |
ret = batadv_nc_mesh_init(bat_priv); |
d353d8d4d
|
172 173 |
if (ret < 0) goto err; |
414254e34
|
174 |
batadv_gw_init(bat_priv); |
60432d756
|
175 |
batadv_mcast_init(bat_priv); |
414254e34
|
176 |
|
807736f6e
|
177 |
atomic_set(&bat_priv->gw.reselect, 0); |
39c75a51e
|
178 |
atomic_set(&bat_priv->mesh_state, BATADV_MESH_ACTIVE); |
5346c35eb
|
179 180 |
return 0; |
c6c8fea29
|
181 182 |
err: |
3193e8fdf
|
183 |
batadv_mesh_free(soft_iface); |
5346c35eb
|
184 |
return ret; |
c6c8fea29
|
185 |
} |
3193e8fdf
|
186 |
void batadv_mesh_free(struct net_device *soft_iface) |
c6c8fea29
|
187 |
{ |
56303d34a
|
188 |
struct batadv_priv *bat_priv = netdev_priv(soft_iface); |
c6c8fea29
|
189 |
|
39c75a51e
|
190 |
atomic_set(&bat_priv->mesh_state, BATADV_MESH_DEACTIVATING); |
c6c8fea29
|
191 |
|
9455e34cb
|
192 |
batadv_purge_outstanding_packets(bat_priv, NULL); |
c6c8fea29
|
193 |
|
bd3524c14
|
194 |
batadv_gw_node_free(bat_priv); |
6c519bad7
|
195 |
batadv_nc_mesh_free(bat_priv); |
a43618603
|
196 197 |
batadv_dat_free(bat_priv); batadv_bla_free(bat_priv); |
c6c8fea29
|
198 |
|
c5caf4ef3
|
199 |
batadv_mcast_free(bat_priv); |
a43618603
|
200 201 202 203 |
/* Free the TT and the originator tables only after having terminated * all the other depending components which may use these structures for * their purposes. */ |
08c36d3e8
|
204 |
batadv_tt_free(bat_priv); |
c6c8fea29
|
205 |
|
a43618603
|
206 207 208 209 210 211 |
/* Since the originator table clean up routine is accessing the TT * tables as well, it has to be invoked after the TT tables have been * freed and marked as empty. This ensures that no cleanup RCU callbacks * accessing the TT data are scheduled for later execution. */ batadv_originator_free(bat_priv); |
2f1dfbe18
|
212 |
|
414254e34
|
213 |
batadv_gw_free(bat_priv); |
f8214865a
|
214 |
free_percpu(bat_priv->bat_counters); |
f69ae770e
|
215 |
bat_priv->bat_counters = NULL; |
f8214865a
|
216 |
|
39c75a51e
|
217 |
atomic_set(&bat_priv->mesh_state, BATADV_MESH_INACTIVE); |
c6c8fea29
|
218 |
} |
6e0895c2e
|
219 220 221 222 223 |
/** * batadv_is_my_mac - check if the given mac address belongs to any of the real * interfaces in the current mesh * @bat_priv: the bat priv with all the soft interface information * @addr: the address to check |
e8ad3b1ac
|
224 |
* |
62fe710f6
|
225 |
* Return: 'true' if the mac address was found, false otherwise. |
6e0895c2e
|
226 |
*/ |
6b5e971a2
|
227 |
bool batadv_is_my_mac(struct batadv_priv *bat_priv, const u8 *addr) |
c6c8fea29
|
228 |
{ |
56303d34a
|
229 |
const struct batadv_hard_iface *hard_iface; |
e8ad3b1ac
|
230 |
bool is_my_mac = false; |
c6c8fea29
|
231 232 |
rcu_read_lock(); |
3193e8fdf
|
233 |
list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) { |
e9a4f295e
|
234 |
if (hard_iface->if_status != BATADV_IF_ACTIVE) |
c6c8fea29
|
235 |
continue; |
fe8a93b95
|
236 237 |
if (hard_iface->soft_iface != bat_priv->soft_iface) continue; |
1eda58bfc
|
238 |
if (batadv_compare_eth(hard_iface->net_dev->dev_addr, addr)) { |
e8ad3b1ac
|
239 240 |
is_my_mac = true; break; |
c6c8fea29
|
241 242 243 |
} } rcu_read_unlock(); |
e8ad3b1ac
|
244 |
return is_my_mac; |
c6c8fea29
|
245 |
} |
30da63a6a
|
246 247 248 249 250 |
/** * batadv_seq_print_text_primary_if_get - called from debugfs table printing * function that requires the primary interface * @seq: debugfs table seq_file struct * |
62fe710f6
|
251 |
* Return: primary interface if found or NULL otherwise. |
30da63a6a
|
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 |
*/ struct batadv_hard_iface * batadv_seq_print_text_primary_if_get(struct seq_file *seq) { struct net_device *net_dev = (struct net_device *)seq->private; struct batadv_priv *bat_priv = netdev_priv(net_dev); struct batadv_hard_iface *primary_if; primary_if = batadv_primary_if_get_selected(bat_priv); if (!primary_if) { seq_printf(seq, "BATMAN mesh %s disabled - please specify interfaces to enable it ", net_dev->name); goto out; } if (primary_if->if_status == BATADV_IF_ACTIVE) goto out; seq_printf(seq, "BATMAN mesh %s disabled - primary interface not active ", net_dev->name); |
82047ad7f
|
277 |
batadv_hardif_put(primary_if); |
30da63a6a
|
278 279 280 281 282 |
primary_if = NULL; out: return primary_if; } |
c54f38c9a
|
283 |
/** |
411d6ed93
|
284 285 286 |
* batadv_max_header_len - calculate maximum encapsulation overhead for a * payload packet * |
62fe710f6
|
287 |
* Return: the maximum encapsulation overhead in bytes. |
411d6ed93
|
288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 |
*/ int batadv_max_header_len(void) { int header_len = 0; header_len = max_t(int, header_len, sizeof(struct batadv_unicast_packet)); header_len = max_t(int, header_len, sizeof(struct batadv_unicast_4addr_packet)); header_len = max_t(int, header_len, sizeof(struct batadv_bcast_packet)); #ifdef CONFIG_BATMAN_ADV_NC header_len = max_t(int, header_len, sizeof(struct batadv_coded_packet)); #endif |
1df0cbd50
|
304 |
return header_len + ETH_HLEN; |
411d6ed93
|
305 306 307 |
} /** |
c54f38c9a
|
308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 |
* batadv_skb_set_priority - sets skb priority according to packet content * @skb: the packet to be sent * @offset: offset to the packet content * * This function sets a value between 256 and 263 (802.1d priority), which * can be interpreted by the cfg80211 or other drivers. */ void batadv_skb_set_priority(struct sk_buff *skb, int offset) { struct iphdr ip_hdr_tmp, *ip_hdr; struct ipv6hdr ip6_hdr_tmp, *ip6_hdr; struct ethhdr ethhdr_tmp, *ethhdr; struct vlan_ethhdr *vhdr, vhdr_tmp; u32 prio; /* already set, do nothing */ if (skb->priority >= 256 && skb->priority <= 263) return; ethhdr = skb_header_pointer(skb, offset, sizeof(*ethhdr), ðhdr_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
|
360 |
static int batadv_recv_unhandled_packet(struct sk_buff *skb, |
56303d34a
|
361 |
struct batadv_hard_iface *recv_if) |
ffa995e03
|
362 363 364 365 366 367 368 |
{ return NET_RX_DROP; } /* incoming packets with the batman ethertype received on any active hard * interface */ |
3193e8fdf
|
369 370 371 |
int batadv_batman_skb_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *ptype, struct net_device *orig_dev) |
ffa995e03
|
372 |
{ |
56303d34a
|
373 |
struct batadv_priv *bat_priv; |
964126901
|
374 |
struct batadv_ogm_packet *batadv_ogm_packet; |
56303d34a
|
375 |
struct batadv_hard_iface *hard_iface; |
6b5e971a2
|
376 |
u8 idx; |
ffa995e03
|
377 |
int ret; |
56303d34a
|
378 379 |
hard_iface = container_of(ptype, struct batadv_hard_iface, batman_adv_ptype); |
ffa995e03
|
380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 |
skb = skb_share_check(skb, GFP_ATOMIC); /* skb was released by skb_share_check() */ if (!skb) goto err_out; /* packet should hold at least type and version */ if (unlikely(!pskb_may_pull(skb, 2))) goto err_free; /* expect a valid ethernet header here. */ if (unlikely(skb->mac_len != ETH_HLEN || !skb_mac_header(skb))) goto err_free; if (!hard_iface->soft_iface) goto err_free; bat_priv = netdev_priv(hard_iface->soft_iface); |
39c75a51e
|
398 |
if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE) |
ffa995e03
|
399 400 401 |
goto err_free; /* discard frames on not active interfaces */ |
e9a4f295e
|
402 |
if (hard_iface->if_status != BATADV_IF_ACTIVE) |
ffa995e03
|
403 |
goto err_free; |
964126901
|
404 |
batadv_ogm_packet = (struct batadv_ogm_packet *)skb->data; |
ffa995e03
|
405 |
|
a40d9b075
|
406 |
if (batadv_ogm_packet->version != BATADV_COMPAT_VERSION) { |
39c75a51e
|
407 |
batadv_dbg(BATADV_DBG_BATMAN, bat_priv, |
1eda58bfc
|
408 409 |
"Drop packet: incompatible batman version (%i) ", |
a40d9b075
|
410 |
batadv_ogm_packet->version); |
ffa995e03
|
411 412 |
goto err_free; } |
e0d9677ea
|
413 414 |
/* reset control block to avoid left overs from previous users */ memset(skb->cb, 0, sizeof(struct batadv_skb_cb)); |
ffa995e03
|
415 416 417 |
/* all receive handlers return whether they received or reused * the supplied skb. if not, we have to free the skb. */ |
a40d9b075
|
418 |
idx = batadv_ogm_packet->packet_type; |
ee11ad61f
|
419 |
ret = (*batadv_rx_handler[idx])(skb, hard_iface); |
ffa995e03
|
420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 |
if (ret == NET_RX_DROP) kfree_skb(skb); /* return NET_RX_SUCCESS in any case as we * most probably dropped the packet for * routing-logical reasons. */ return NET_RX_SUCCESS; err_free: kfree_skb(skb); err_out: return NET_RX_DROP; } |
ee11ad61f
|
435 |
static void batadv_recv_handler_init(void) |
ffa995e03
|
436 437 |
{ int i; |
ee11ad61f
|
438 439 |
for (i = 0; i < ARRAY_SIZE(batadv_rx_handler); i++) batadv_rx_handler[i] = batadv_recv_unhandled_packet; |
ffa995e03
|
440 |
|
a1f1ac5c4
|
441 442 |
for (i = BATADV_UNICAST_MIN; i <= BATADV_UNICAST_MAX; i++) batadv_rx_handler[i] = batadv_recv_unhandled_unicast_packet; |
031ace8d0
|
443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 |
/* compile time checks for sizes */ BUILD_BUG_ON(sizeof(struct batadv_bla_claim_dst) != 6); BUILD_BUG_ON(sizeof(struct batadv_ogm_packet) != 24); BUILD_BUG_ON(sizeof(struct batadv_icmp_header) != 20); BUILD_BUG_ON(sizeof(struct batadv_icmp_packet) != 20); BUILD_BUG_ON(sizeof(struct batadv_icmp_packet_rr) != 116); BUILD_BUG_ON(sizeof(struct batadv_unicast_packet) != 10); BUILD_BUG_ON(sizeof(struct batadv_unicast_4addr_packet) != 18); BUILD_BUG_ON(sizeof(struct batadv_frag_packet) != 20); BUILD_BUG_ON(sizeof(struct batadv_bcast_packet) != 14); BUILD_BUG_ON(sizeof(struct batadv_coded_packet) != 46); BUILD_BUG_ON(sizeof(struct batadv_unicast_tvlv_packet) != 20); BUILD_BUG_ON(sizeof(struct batadv_tvlv_hdr) != 4); BUILD_BUG_ON(sizeof(struct batadv_tvlv_gateway_data) != 8); BUILD_BUG_ON(sizeof(struct batadv_tvlv_tt_vlan_data) != 8); BUILD_BUG_ON(sizeof(struct batadv_tvlv_tt_change) != 12); BUILD_BUG_ON(sizeof(struct batadv_tvlv_roam_adv) != 8); |
80067c832
|
460 |
|
a1f1ac5c4
|
461 462 463 464 |
/* broadcast packet */ batadv_rx_handler[BATADV_BCAST] = batadv_recv_bcast_packet; /* unicast packets ... */ |
7cdcf6ddd
|
465 466 |
/* unicast with 4 addresses packet */ batadv_rx_handler[BATADV_UNICAST_4ADDR] = batadv_recv_unicast_packet; |
ffa995e03
|
467 |
/* unicast packet */ |
acd34afa8
|
468 |
batadv_rx_handler[BATADV_UNICAST] = batadv_recv_unicast_packet; |
ef2615774
|
469 470 |
/* unicast tvlv packet */ batadv_rx_handler[BATADV_UNICAST_TVLV] = batadv_recv_unicast_tvlv; |
a1f1ac5c4
|
471 472 |
/* batman icmp packet */ batadv_rx_handler[BATADV_ICMP] = batadv_recv_icmp_packet; |
610bfc6bc
|
473 474 |
/* Fragmented packets */ batadv_rx_handler[BATADV_UNICAST_FRAG] = batadv_recv_frag_packet; |
ffa995e03
|
475 |
} |
56303d34a
|
476 |
int |
6b5e971a2
|
477 |
batadv_recv_handler_register(u8 packet_type, |
56303d34a
|
478 479 |
int (*recv_handler)(struct sk_buff *, struct batadv_hard_iface *)) |
ffa995e03
|
480 |
{ |
a1f1ac5c4
|
481 482 483 484 485 486 |
int (*curr)(struct sk_buff *, struct batadv_hard_iface *); curr = batadv_rx_handler[packet_type]; if ((curr != batadv_recv_unhandled_packet) && (curr != batadv_recv_unhandled_unicast_packet)) |
ffa995e03
|
487 |
return -EBUSY; |
ee11ad61f
|
488 |
batadv_rx_handler[packet_type] = recv_handler; |
ffa995e03
|
489 490 |
return 0; } |
6b5e971a2
|
491 |
void batadv_recv_handler_unregister(u8 packet_type) |
ffa995e03
|
492 |
{ |
ee11ad61f
|
493 |
batadv_rx_handler[packet_type] = batadv_recv_unhandled_packet; |
ffa995e03
|
494 |
} |
56303d34a
|
495 |
static struct batadv_algo_ops *batadv_algo_get(char *name) |
1c280471b
|
496 |
{ |
56303d34a
|
497 |
struct batadv_algo_ops *bat_algo_ops = NULL, *bat_algo_ops_tmp; |
1c280471b
|
498 |
|
b67bfe0d4
|
499 |
hlist_for_each_entry(bat_algo_ops_tmp, &batadv_algo_list, list) { |
1c280471b
|
500 501 502 503 504 505 506 507 508 |
if (strcmp(bat_algo_ops_tmp->name, name) != 0) continue; bat_algo_ops = bat_algo_ops_tmp; break; } return bat_algo_ops; } |
56303d34a
|
509 |
int batadv_algo_register(struct batadv_algo_ops *bat_algo_ops) |
1c280471b
|
510 |
{ |
56303d34a
|
511 |
struct batadv_algo_ops *bat_algo_ops_tmp; |
1c280471b
|
512 |
|
ee11ad61f
|
513 |
bat_algo_ops_tmp = batadv_algo_get(bat_algo_ops->name); |
1c280471b
|
514 |
if (bat_algo_ops_tmp) { |
86ceb3605
|
515 516 517 |
pr_info("Trying to register already registered routing algorithm: %s ", bat_algo_ops->name); |
9fb6c6519
|
518 |
return -EEXIST; |
1c280471b
|
519 |
} |
01c4224b5
|
520 |
/* all algorithms must implement all ops (for now) */ |
c2aca0223
|
521 |
if (!bat_algo_ops->bat_iface_enable || |
00a50076a
|
522 |
!bat_algo_ops->bat_iface_disable || |
c32293983
|
523 |
!bat_algo_ops->bat_iface_update_mac || |
cd8b78e7e
|
524 |
!bat_algo_ops->bat_primary_iface_set || |
01c4224b5
|
525 |
!bat_algo_ops->bat_ogm_schedule || |
a3285a8f2
|
526 |
!bat_algo_ops->bat_ogm_emit || |
c43c981e5
|
527 |
!bat_algo_ops->bat_neigh_cmp || |
18165f6f6
|
528 |
!bat_algo_ops->bat_neigh_is_similar_or_better) { |
01c4224b5
|
529 530 531 |
pr_info("Routing algo '%s' does not implement required ops ", bat_algo_ops->name); |
9fb6c6519
|
532 |
return -EINVAL; |
01c4224b5
|
533 |
} |
1c280471b
|
534 |
INIT_HLIST_NODE(&bat_algo_ops->list); |
ee11ad61f
|
535 |
hlist_add_head(&bat_algo_ops->list, &batadv_algo_list); |
1c280471b
|
536 |
|
9fb6c6519
|
537 |
return 0; |
1c280471b
|
538 |
} |
56303d34a
|
539 |
int batadv_algo_select(struct batadv_priv *bat_priv, char *name) |
1c280471b
|
540 |
{ |
56303d34a
|
541 |
struct batadv_algo_ops *bat_algo_ops; |
1c280471b
|
542 |
|
ee11ad61f
|
543 |
bat_algo_ops = batadv_algo_get(name); |
1c280471b
|
544 |
if (!bat_algo_ops) |
f372d0905
|
545 |
return -EINVAL; |
1c280471b
|
546 547 |
bat_priv->bat_algo_ops = bat_algo_ops; |
1c280471b
|
548 |
|
f372d0905
|
549 |
return 0; |
1c280471b
|
550 |
} |
3193e8fdf
|
551 |
int batadv_algo_seq_print_text(struct seq_file *seq, void *offset) |
1c280471b
|
552 |
{ |
56303d34a
|
553 |
struct batadv_algo_ops *bat_algo_ops; |
1c280471b
|
554 |
|
0c8146535
|
555 556 |
seq_puts(seq, "Available routing algorithms: "); |
1c280471b
|
557 |
|
b67bfe0d4
|
558 |
hlist_for_each_entry(bat_algo_ops, &batadv_algo_list, list) { |
854d2a63d
|
559 560 |
seq_printf(seq, " * %s ", bat_algo_ops->name); |
1c280471b
|
561 562 563 564 |
} return 0; } |
95a066d82
|
565 566 567 568 569 570 571 572 573 |
/** * batadv_skb_crc32 - calculate CRC32 of the whole packet and skip bytes in * the header * @skb: skb pointing to fragmented socket buffers * @payload_ptr: Pointer to position inside the head buffer of the skb * marking the start of the data to be CRC'ed * * payload_ptr must always point to an address in the skb head buffer and not to * a fragment. |
7afcbbef6
|
574 575 |
* * Return: big endian crc32c of the checksummed data |
95a066d82
|
576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 |
*/ __be32 batadv_skb_crc32(struct sk_buff *skb, u8 *payload_ptr) { u32 crc = 0; unsigned int from; unsigned int to = skb->len; struct skb_seq_state st; const u8 *data; unsigned int len; unsigned int consumed = 0; from = (unsigned int)(payload_ptr - skb->data); skb_prepare_seq_read(skb, from, to, &st); while ((len = skb_seq_read(consumed, &data, &st)) != 0) { crc = crc32c(crc, data, len); consumed += len; } |
95a066d82
|
594 595 596 |
return htonl(crc); } |
ef2615774
|
597 |
/** |
32836f56f
|
598 599 600 601 602 603 604 605 606 607 608 609 610 |
* batadv_tvlv_handler_release - release tvlv handler from lists and queue for * free after rcu grace period * @ref: kref pointer of the tvlv */ static void batadv_tvlv_handler_release(struct kref *ref) { struct batadv_tvlv_handler *tvlv_handler; tvlv_handler = container_of(ref, struct batadv_tvlv_handler, refcount); kfree_rcu(tvlv_handler, rcu); } /** |
ba610043a
|
611 |
* batadv_tvlv_handler_put - decrement the tvlv container refcounter and |
32836f56f
|
612 |
* possibly release it |
ef2615774
|
613 614 |
* @tvlv_handler: the tvlv handler to free */ |
ba610043a
|
615 |
static void batadv_tvlv_handler_put(struct batadv_tvlv_handler *tvlv_handler) |
ef2615774
|
616 |
{ |
32836f56f
|
617 |
kref_put(&tvlv_handler->refcount, batadv_tvlv_handler_release); |
ef2615774
|
618 619 620 621 622 623 624 625 626 |
} /** * batadv_tvlv_handler_get - retrieve tvlv handler from the tvlv handler list * based on the provided type and version (both need to match) * @bat_priv: the bat priv with all the soft interface information * @type: tvlv handler type to look for * @version: tvlv handler version to look for * |
62fe710f6
|
627 |
* Return: tvlv handler if found or NULL otherwise. |
ef2615774
|
628 629 |
*/ static struct batadv_tvlv_handler |
6b5e971a2
|
630 |
*batadv_tvlv_handler_get(struct batadv_priv *bat_priv, u8 type, u8 version) |
ef2615774
|
631 632 633 634 635 636 637 638 639 640 641 |
{ struct batadv_tvlv_handler *tvlv_handler_tmp, *tvlv_handler = NULL; rcu_read_lock(); hlist_for_each_entry_rcu(tvlv_handler_tmp, &bat_priv->tvlv.handler_list, list) { if (tvlv_handler_tmp->type != type) continue; if (tvlv_handler_tmp->version != version) continue; |
32836f56f
|
642 |
if (!kref_get_unless_zero(&tvlv_handler_tmp->refcount)) |
ef2615774
|
643 644 645 646 647 648 649 650 651 652 653 |
continue; tvlv_handler = tvlv_handler_tmp; break; } rcu_read_unlock(); return tvlv_handler; } /** |
f7157dd13
|
654 655 656 657 658 659 660 661 662 663 664 665 |
* batadv_tvlv_container_release - release tvlv from lists and free * @ref: kref pointer of the tvlv */ static void batadv_tvlv_container_release(struct kref *ref) { struct batadv_tvlv_container *tvlv; tvlv = container_of(ref, struct batadv_tvlv_container, refcount); kfree(tvlv); } /** |
ef2615774
|
666 |
* batadv_tvlv_container_free_ref - decrement the tvlv container refcounter and |
f7157dd13
|
667 |
* possibly release it |
a0e287750
|
668 |
* @tvlv: the tvlv container to free |
ef2615774
|
669 670 671 |
*/ static void batadv_tvlv_container_free_ref(struct batadv_tvlv_container *tvlv) { |
f7157dd13
|
672 |
kref_put(&tvlv->refcount, batadv_tvlv_container_release); |
ef2615774
|
673 674 675 676 677 678 679 680 681 682 683 684 |
} /** * batadv_tvlv_container_get - retrieve tvlv container from the tvlv container * list based on the provided type and version (both need to match) * @bat_priv: the bat priv with all the soft interface information * @type: tvlv container type to look for * @version: tvlv container version to look for * * Has to be called with the appropriate locks being acquired * (tvlv.container_list_lock). * |
62fe710f6
|
685 |
* Return: tvlv container if found or NULL otherwise. |
ef2615774
|
686 687 |
*/ static struct batadv_tvlv_container |
6b5e971a2
|
688 |
*batadv_tvlv_container_get(struct batadv_priv *bat_priv, u8 type, u8 version) |
ef2615774
|
689 690 |
{ struct batadv_tvlv_container *tvlv_tmp, *tvlv = NULL; |
dded06922
|
691 |
lockdep_assert_held(&bat_priv->tvlv.container_list_lock); |
ef2615774
|
692 693 694 695 696 697 |
hlist_for_each_entry(tvlv_tmp, &bat_priv->tvlv.container_list, list) { if (tvlv_tmp->tvlv_hdr.type != type) continue; if (tvlv_tmp->tvlv_hdr.version != version) continue; |
f7157dd13
|
698 |
if (!kref_get_unless_zero(&tvlv_tmp->refcount)) |
ef2615774
|
699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 |
continue; tvlv = tvlv_tmp; break; } return tvlv; } /** * batadv_tvlv_container_list_size - calculate the size of the tvlv container * list entries * @bat_priv: the bat priv with all the soft interface information * * Has to be called with the appropriate locks being acquired * (tvlv.container_list_lock). * |
62fe710f6
|
716 |
* Return: size of all currently registered tvlv containers in bytes. |
ef2615774
|
717 |
*/ |
6b5e971a2
|
718 |
static u16 batadv_tvlv_container_list_size(struct batadv_priv *bat_priv) |
ef2615774
|
719 720 |
{ struct batadv_tvlv_container *tvlv; |
6b5e971a2
|
721 |
u16 tvlv_len = 0; |
ef2615774
|
722 |
|
dded06922
|
723 |
lockdep_assert_held(&bat_priv->tvlv.container_list_lock); |
ef2615774
|
724 725 726 727 728 729 730 731 732 733 734 |
hlist_for_each_entry(tvlv, &bat_priv->tvlv.container_list, list) { tvlv_len += sizeof(struct batadv_tvlv_hdr); tvlv_len += ntohs(tvlv->tvlv_hdr.len); } return tvlv_len; } /** * batadv_tvlv_container_remove - remove tvlv container from the tvlv container * list |
2c72d655b
|
735 |
* @bat_priv: the bat priv with all the soft interface information |
ef2615774
|
736 737 738 739 740 |
* @tvlv: the to be removed tvlv container * * Has to be called with the appropriate locks being acquired * (tvlv.container_list_lock). */ |
2c72d655b
|
741 742 |
static void batadv_tvlv_container_remove(struct batadv_priv *bat_priv, struct batadv_tvlv_container *tvlv) |
ef2615774
|
743 |
{ |
008a37448
|
744 |
lockdep_assert_held(&bat_priv->tvlv.container_list_lock); |
2c72d655b
|
745 |
|
ef2615774
|
746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 |
if (!tvlv) return; hlist_del(&tvlv->list); /* first call to decrement the counter, second call to free */ batadv_tvlv_container_free_ref(tvlv); batadv_tvlv_container_free_ref(tvlv); } /** * batadv_tvlv_container_unregister - unregister tvlv container based on the * provided type and version (both need to match) * @bat_priv: the bat priv with all the soft interface information * @type: tvlv container type to unregister * @version: tvlv container type to unregister */ void batadv_tvlv_container_unregister(struct batadv_priv *bat_priv, |
6b5e971a2
|
764 |
u8 type, u8 version) |
ef2615774
|
765 766 767 768 769 |
{ struct batadv_tvlv_container *tvlv; spin_lock_bh(&bat_priv->tvlv.container_list_lock); tvlv = batadv_tvlv_container_get(bat_priv, type, version); |
2c72d655b
|
770 |
batadv_tvlv_container_remove(bat_priv, tvlv); |
ef2615774
|
771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 |
spin_unlock_bh(&bat_priv->tvlv.container_list_lock); } /** * batadv_tvlv_container_register - register tvlv type, version and content * to be propagated with each (primary interface) OGM * @bat_priv: the bat priv with all the soft interface information * @type: tvlv container type * @version: tvlv container version * @tvlv_value: tvlv container content * @tvlv_value_len: tvlv container content length * * If a container of the same type and version was already registered the new * content is going to replace the old one. */ void batadv_tvlv_container_register(struct batadv_priv *bat_priv, |
6b5e971a2
|
787 788 |
u8 type, u8 version, void *tvlv_value, u16 tvlv_value_len) |
ef2615774
|
789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 |
{ struct batadv_tvlv_container *tvlv_old, *tvlv_new; if (!tvlv_value) tvlv_value_len = 0; tvlv_new = kzalloc(sizeof(*tvlv_new) + tvlv_value_len, GFP_ATOMIC); if (!tvlv_new) return; tvlv_new->tvlv_hdr.version = version; tvlv_new->tvlv_hdr.type = type; tvlv_new->tvlv_hdr.len = htons(tvlv_value_len); memcpy(tvlv_new + 1, tvlv_value, ntohs(tvlv_new->tvlv_hdr.len)); INIT_HLIST_NODE(&tvlv_new->list); |
f7157dd13
|
805 |
kref_init(&tvlv_new->refcount); |
ef2615774
|
806 807 808 |
spin_lock_bh(&bat_priv->tvlv.container_list_lock); tvlv_old = batadv_tvlv_container_get(bat_priv, type, version); |
2c72d655b
|
809 |
batadv_tvlv_container_remove(bat_priv, tvlv_old); |
ef2615774
|
810 811 812 813 814 |
hlist_add_head(&tvlv_new->list, &bat_priv->tvlv.container_list); spin_unlock_bh(&bat_priv->tvlv.container_list_lock); } /** |
3f68785e6
|
815 |
* batadv_tvlv_realloc_packet_buff - reallocate packet buffer to accommodate |
ef2615774
|
816 817 818 |
* requested packet size * @packet_buff: packet buffer * @packet_buff_len: packet buffer size |
a0e287750
|
819 |
* @min_packet_len: requested packet minimum size |
ef2615774
|
820 821 822 |
* @additional_packet_len: requested additional packet size on top of minimum * size * |
62fe710f6
|
823 |
* Return: true of the packet buffer could be changed to the requested size, |
ef2615774
|
824 825 826 827 828 829 830 831 832 833 834 835 |
* false otherwise. */ static bool batadv_tvlv_realloc_packet_buff(unsigned char **packet_buff, int *packet_buff_len, int min_packet_len, int additional_packet_len) { unsigned char *new_buff; new_buff = kmalloc(min_packet_len + additional_packet_len, GFP_ATOMIC); /* keep old buffer if kmalloc should fail */ |
16b9ce83f
|
836 837 838 839 840 841 842 |
if (!new_buff) return false; memcpy(new_buff, *packet_buff, min_packet_len); kfree(*packet_buff); *packet_buff = new_buff; *packet_buff_len = min_packet_len + additional_packet_len; |
ef2615774
|
843 |
|
16b9ce83f
|
844 |
return true; |
ef2615774
|
845 846 847 848 849 850 851 852 853 854 855 856 857 858 |
} /** * batadv_tvlv_container_ogm_append - append tvlv container content to given * OGM packet buffer * @bat_priv: the bat priv with all the soft interface information * @packet_buff: ogm packet buffer * @packet_buff_len: ogm packet buffer size including ogm header and tvlv * content * @packet_min_len: ogm header size to be preserved for the OGM itself * * The ogm packet might be enlarged or shrunk depending on the current size * and the size of the to-be-appended tvlv containers. * |
62fe710f6
|
859 |
* Return: size of all appended tvlv containers in bytes. |
ef2615774
|
860 |
*/ |
6b5e971a2
|
861 862 863 |
u16 batadv_tvlv_container_ogm_append(struct batadv_priv *bat_priv, unsigned char **packet_buff, int *packet_buff_len, int packet_min_len) |
ef2615774
|
864 865 866 |
{ struct batadv_tvlv_container *tvlv; struct batadv_tvlv_hdr *tvlv_hdr; |
6b5e971a2
|
867 |
u16 tvlv_value_len; |
ef2615774
|
868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 |
void *tvlv_value; bool ret; spin_lock_bh(&bat_priv->tvlv.container_list_lock); tvlv_value_len = batadv_tvlv_container_list_size(bat_priv); ret = batadv_tvlv_realloc_packet_buff(packet_buff, packet_buff_len, packet_min_len, tvlv_value_len); if (!ret) goto end; if (!tvlv_value_len) goto end; tvlv_value = (*packet_buff) + packet_min_len; hlist_for_each_entry(tvlv, &bat_priv->tvlv.container_list, list) { tvlv_hdr = tvlv_value; tvlv_hdr->type = tvlv->tvlv_hdr.type; tvlv_hdr->version = tvlv->tvlv_hdr.version; tvlv_hdr->len = tvlv->tvlv_hdr.len; tvlv_value = tvlv_hdr + 1; memcpy(tvlv_value, tvlv + 1, ntohs(tvlv->tvlv_hdr.len)); |
6b5e971a2
|
892 |
tvlv_value = (u8 *)tvlv_value + ntohs(tvlv->tvlv_hdr.len); |
ef2615774
|
893 894 895 896 897 898 899 900 901 902 903 904 |
} end: spin_unlock_bh(&bat_priv->tvlv.container_list_lock); return tvlv_value_len; } /** * batadv_tvlv_call_handler - parse the given tvlv buffer to call the * appropriate handlers * @bat_priv: the bat priv with all the soft interface information * @tvlv_handler: tvlv callback function handling the tvlv content |
c05a57f6f
|
905 |
* @ogm_source: flag indicating whether the tvlv is an ogm or a unicast packet |
ef2615774
|
906 907 908 909 910 911 |
* @orig_node: orig node emitting the ogm packet * @src: source mac address of the unicast packet * @dst: destination mac address of the unicast packet * @tvlv_value: tvlv content * @tvlv_value_len: tvlv content length * |
62fe710f6
|
912 |
* Return: success if handler was not found or the return value of the handler |
ef2615774
|
913 914 915 916 917 918 |
* callback. */ static int batadv_tvlv_call_handler(struct batadv_priv *bat_priv, struct batadv_tvlv_handler *tvlv_handler, bool ogm_source, struct batadv_orig_node *orig_node, |
6b5e971a2
|
919 920 |
u8 *src, u8 *dst, void *tvlv_value, u16 tvlv_value_len) |
ef2615774
|
921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 |
{ if (!tvlv_handler) return NET_RX_SUCCESS; if (ogm_source) { if (!tvlv_handler->ogm_handler) return NET_RX_SUCCESS; if (!orig_node) return NET_RX_SUCCESS; tvlv_handler->ogm_handler(bat_priv, orig_node, BATADV_NO_FLAGS, tvlv_value, tvlv_value_len); tvlv_handler->flags |= BATADV_TVLV_HANDLER_OGM_CALLED; } else { if (!src) return NET_RX_SUCCESS; if (!dst) return NET_RX_SUCCESS; if (!tvlv_handler->unicast_handler) return NET_RX_SUCCESS; return tvlv_handler->unicast_handler(bat_priv, src, dst, tvlv_value, tvlv_value_len); } return NET_RX_SUCCESS; } /** * batadv_tvlv_containers_process - parse the given tvlv buffer to call the * appropriate handlers * @bat_priv: the bat priv with all the soft interface information |
c05a57f6f
|
958 |
* @ogm_source: flag indicating whether the tvlv is an ogm or a unicast packet |
ef2615774
|
959 960 961 962 963 964 |
* @orig_node: orig node emitting the ogm packet * @src: source mac address of the unicast packet * @dst: destination mac address of the unicast packet * @tvlv_value: tvlv content * @tvlv_value_len: tvlv content length * |
62fe710f6
|
965 |
* Return: success when processing an OGM or the return value of all called |
ef2615774
|
966 967 968 969 970 |
* handler callbacks. */ int batadv_tvlv_containers_process(struct batadv_priv *bat_priv, bool ogm_source, struct batadv_orig_node *orig_node, |
6b5e971a2
|
971 972 |
u8 *src, u8 *dst, void *tvlv_value, u16 tvlv_value_len) |
ef2615774
|
973 974 975 |
{ struct batadv_tvlv_handler *tvlv_handler; struct batadv_tvlv_hdr *tvlv_hdr; |
6b5e971a2
|
976 977 |
u16 tvlv_value_cont_len; u8 cifnotfound = BATADV_TVLV_HANDLER_OGM_CIFNOTFND; |
ef2615774
|
978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 |
int ret = NET_RX_SUCCESS; while (tvlv_value_len >= sizeof(*tvlv_hdr)) { tvlv_hdr = tvlv_value; tvlv_value_cont_len = ntohs(tvlv_hdr->len); tvlv_value = tvlv_hdr + 1; tvlv_value_len -= sizeof(*tvlv_hdr); if (tvlv_value_cont_len > tvlv_value_len) break; tvlv_handler = batadv_tvlv_handler_get(bat_priv, tvlv_hdr->type, tvlv_hdr->version); ret |= batadv_tvlv_call_handler(bat_priv, tvlv_handler, ogm_source, orig_node, src, dst, tvlv_value, tvlv_value_cont_len); if (tvlv_handler) |
ba610043a
|
998 |
batadv_tvlv_handler_put(tvlv_handler); |
6b5e971a2
|
999 |
tvlv_value = (u8 *)tvlv_value + tvlv_value_cont_len; |
ef2615774
|
1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 |
tvlv_value_len -= tvlv_value_cont_len; } if (!ogm_source) return ret; rcu_read_lock(); hlist_for_each_entry_rcu(tvlv_handler, &bat_priv->tvlv.handler_list, list) { if ((tvlv_handler->flags & BATADV_TVLV_HANDLER_OGM_CIFNOTFND) && !(tvlv_handler->flags & BATADV_TVLV_HANDLER_OGM_CALLED)) tvlv_handler->ogm_handler(bat_priv, orig_node, cifnotfound, NULL, 0); tvlv_handler->flags &= ~BATADV_TVLV_HANDLER_OGM_CALLED; } rcu_read_unlock(); return NET_RX_SUCCESS; } /** * batadv_tvlv_ogm_receive - process an incoming ogm and call the appropriate * handlers * @bat_priv: the bat priv with all the soft interface information * @batadv_ogm_packet: ogm packet containing the tvlv containers * @orig_node: orig node emitting the ogm packet */ void batadv_tvlv_ogm_receive(struct batadv_priv *bat_priv, struct batadv_ogm_packet *batadv_ogm_packet, struct batadv_orig_node *orig_node) { void *tvlv_value; |
6b5e971a2
|
1033 |
u16 tvlv_value_len; |
ef2615774
|
1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 |
if (!batadv_ogm_packet) return; tvlv_value_len = ntohs(batadv_ogm_packet->tvlv_len); if (!tvlv_value_len) return; tvlv_value = batadv_ogm_packet + 1; batadv_tvlv_containers_process(bat_priv, true, orig_node, NULL, NULL, tvlv_value, tvlv_value_len); } /** * batadv_tvlv_handler_register - register tvlv handler based on the provided * type and version (both need to match) for ogm tvlv payload and/or unicast * payload * @bat_priv: the bat priv with all the soft interface information * @optr: ogm tvlv handler callback function. This function receives the orig * node, flags and the tvlv content as argument to process. * @uptr: unicast tvlv handler callback function. This function receives the * source & destination of the unicast packet as well as the tvlv content * to process. * @type: tvlv handler type to be registered * @version: tvlv handler version to be registered * @flags: flags to enable or disable TVLV API behavior */ void batadv_tvlv_handler_register(struct batadv_priv *bat_priv, void (*optr)(struct batadv_priv *bat_priv, struct batadv_orig_node *orig, |
6b5e971a2
|
1065 |
u8 flags, |
ef2615774
|
1066 |
void *tvlv_value, |
6b5e971a2
|
1067 |
u16 tvlv_value_len), |
ef2615774
|
1068 |
int (*uptr)(struct batadv_priv *bat_priv, |
6b5e971a2
|
1069 |
u8 *src, u8 *dst, |
ef2615774
|
1070 |
void *tvlv_value, |
6b5e971a2
|
1071 1072 |
u16 tvlv_value_len), u8 type, u8 version, u8 flags) |
ef2615774
|
1073 1074 1075 1076 1077 |
{ struct batadv_tvlv_handler *tvlv_handler; tvlv_handler = batadv_tvlv_handler_get(bat_priv, type, version); if (tvlv_handler) { |
ba610043a
|
1078 |
batadv_tvlv_handler_put(tvlv_handler); |
ef2615774
|
1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 |
return; } tvlv_handler = kzalloc(sizeof(*tvlv_handler), GFP_ATOMIC); if (!tvlv_handler) return; tvlv_handler->ogm_handler = optr; tvlv_handler->unicast_handler = uptr; tvlv_handler->type = type; tvlv_handler->version = version; tvlv_handler->flags = flags; |
32836f56f
|
1091 |
kref_init(&tvlv_handler->refcount); |
ef2615774
|
1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 |
INIT_HLIST_NODE(&tvlv_handler->list); spin_lock_bh(&bat_priv->tvlv.handler_list_lock); hlist_add_head_rcu(&tvlv_handler->list, &bat_priv->tvlv.handler_list); spin_unlock_bh(&bat_priv->tvlv.handler_list_lock); } /** * batadv_tvlv_handler_unregister - unregister tvlv handler based on the * provided type and version (both need to match) * @bat_priv: the bat priv with all the soft interface information * @type: tvlv handler type to be unregistered * @version: tvlv handler version to be unregistered */ void batadv_tvlv_handler_unregister(struct batadv_priv *bat_priv, |
6b5e971a2
|
1107 |
u8 type, u8 version) |
ef2615774
|
1108 1109 1110 1111 1112 1113 |
{ struct batadv_tvlv_handler *tvlv_handler; tvlv_handler = batadv_tvlv_handler_get(bat_priv, type, version); if (!tvlv_handler) return; |
ba610043a
|
1114 |
batadv_tvlv_handler_put(tvlv_handler); |
ef2615774
|
1115 1116 1117 |
spin_lock_bh(&bat_priv->tvlv.handler_list_lock); hlist_del_rcu(&tvlv_handler->list); spin_unlock_bh(&bat_priv->tvlv.handler_list_lock); |
ba610043a
|
1118 |
batadv_tvlv_handler_put(tvlv_handler); |
ef2615774
|
1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 |
} /** * batadv_tvlv_unicast_send - send a unicast packet with tvlv payload to the * specified host * @bat_priv: the bat priv with all the soft interface information * @src: source mac address of the unicast packet * @dst: destination mac address of the unicast packet * @type: tvlv type * @version: tvlv version * @tvlv_value: tvlv content * @tvlv_value_len: tvlv content length */ |
6b5e971a2
|
1132 1133 1134 |
void batadv_tvlv_unicast_send(struct batadv_priv *bat_priv, u8 *src, u8 *dst, u8 type, u8 version, void *tvlv_value, u16 tvlv_value_len) |
ef2615774
|
1135 1136 1137 1138 |
{ struct batadv_unicast_tvlv_packet *unicast_tvlv_packet; struct batadv_tvlv_hdr *tvlv_hdr; struct batadv_orig_node *orig_node; |
8bbb7cb23
|
1139 |
struct sk_buff *skb; |
ef2615774
|
1140 1141 1142 |
unsigned char *tvlv_buff; unsigned int tvlv_len; ssize_t hdr_len = sizeof(*unicast_tvlv_packet); |
ef2615774
|
1143 1144 1145 |
orig_node = batadv_orig_hash_find(bat_priv, dst); if (!orig_node) |
8bbb7cb23
|
1146 |
return; |
ef2615774
|
1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 |
tvlv_len = sizeof(*tvlv_hdr) + tvlv_value_len; skb = netdev_alloc_skb_ip_align(NULL, ETH_HLEN + hdr_len + tvlv_len); if (!skb) goto out; skb->priority = TC_PRIO_CONTROL; skb_reserve(skb, ETH_HLEN); tvlv_buff = skb_put(skb, sizeof(*unicast_tvlv_packet) + tvlv_len); unicast_tvlv_packet = (struct batadv_unicast_tvlv_packet *)tvlv_buff; |
a40d9b075
|
1158 1159 1160 |
unicast_tvlv_packet->packet_type = BATADV_UNICAST_TVLV; unicast_tvlv_packet->version = BATADV_COMPAT_VERSION; unicast_tvlv_packet->ttl = BATADV_TTL; |
ef2615774
|
1161 1162 1163 |
unicast_tvlv_packet->reserved = 0; unicast_tvlv_packet->tvlv_len = htons(tvlv_len); unicast_tvlv_packet->align = 0; |
8fdd01530
|
1164 1165 |
ether_addr_copy(unicast_tvlv_packet->src, src); ether_addr_copy(unicast_tvlv_packet->dst, dst); |
ef2615774
|
1166 1167 1168 1169 1170 1171 1172 1173 |
tvlv_buff = (unsigned char *)(unicast_tvlv_packet + 1); tvlv_hdr = (struct batadv_tvlv_hdr *)tvlv_buff; tvlv_hdr->version = version; tvlv_hdr->type = type; tvlv_hdr->len = htons(tvlv_value_len); tvlv_buff += sizeof(*tvlv_hdr); memcpy(tvlv_buff, tvlv_value, tvlv_value_len); |
8bbb7cb23
|
1174 |
if (batadv_send_skb_to_orig(skb, orig_node, NULL) == NET_XMIT_DROP) |
ef2615774
|
1175 |
kfree_skb(skb); |
8bbb7cb23
|
1176 |
out: |
5d9673109
|
1177 |
batadv_orig_node_put(orig_node); |
ef2615774
|
1178 |
} |
c018ad3de
|
1179 1180 1181 1182 1183 |
/** * batadv_get_vid - extract the VLAN identifier from skb if any * @skb: the buffer containing the packet * @header_len: length of the batman header preceding the ethernet header * |
62fe710f6
|
1184 1185 |
* Return: VID with the BATADV_VLAN_HAS_TAG flag when the packet embedded in the * skb is vlan tagged. Otherwise BATADV_NO_FLAGS. |
c018ad3de
|
1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 |
*/ unsigned short batadv_get_vid(struct sk_buff *skb, size_t header_len) { struct ethhdr *ethhdr = (struct ethhdr *)(skb->data + header_len); struct vlan_ethhdr *vhdr; unsigned short vid; if (ethhdr->h_proto != htons(ETH_P_8021Q)) return BATADV_NO_FLAGS; if (!pskb_may_pull(skb, header_len + VLAN_ETH_HLEN)) return BATADV_NO_FLAGS; vhdr = (struct vlan_ethhdr *)(skb->data + header_len); vid = ntohs(vhdr->h_vlan_TCI) & VLAN_VID_MASK; vid |= BATADV_VLAN_HAS_TAG; return vid; } |
eceb22ae0
|
1205 1206 1207 1208 1209 1210 |
/** * batadv_vlan_ap_isola_get - return the AP isolation status for the given vlan * @bat_priv: the bat priv with all the soft interface information * @vid: the VLAN identifier for which the AP isolation attributed as to be * looked up * |
62fe710f6
|
1211 |
* Return: true if AP isolation is on for the VLAN idenfied by vid, false |
eceb22ae0
|
1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 |
* otherwise */ bool batadv_vlan_ap_isola_get(struct batadv_priv *bat_priv, unsigned short vid) { bool ap_isolation_enabled = false; struct batadv_softif_vlan *vlan; /* if the AP isolation is requested on a VLAN, then check for its * setting in the proper VLAN private data structure */ vlan = batadv_softif_vlan_get(bat_priv, vid); if (vlan) { ap_isolation_enabled = atomic_read(&vlan->ap_isolation); batadv_softif_vlan_free_ref(vlan); } return ap_isolation_enabled; } |
ee11ad61f
|
1230 |
static int batadv_param_set_ra(const char *val, const struct kernel_param *kp) |
d419be1fd
|
1231 |
{ |
56303d34a
|
1232 |
struct batadv_algo_ops *bat_algo_ops; |
d8cb54861
|
1233 1234 |
char *algo_name = (char *)val; size_t name_len = strlen(algo_name); |
d419be1fd
|
1235 |
|
293c9c1ce
|
1236 1237 |
if (name_len > 0 && algo_name[name_len - 1] == ' ') |
d8cb54861
|
1238 |
algo_name[name_len - 1] = '\0'; |
ee11ad61f
|
1239 |
bat_algo_ops = batadv_algo_get(algo_name); |
d419be1fd
|
1240 |
if (!bat_algo_ops) { |
d8cb54861
|
1241 1242 |
pr_err("Routing algorithm '%s' is not supported ", algo_name); |
d419be1fd
|
1243 1244 |
return -EINVAL; } |
d8cb54861
|
1245 |
return param_set_copystring(algo_name, kp); |
d419be1fd
|
1246 |
} |
ee11ad61f
|
1247 1248 |
static const struct kernel_param_ops batadv_param_ops_ra = { .set = batadv_param_set_ra, |
d419be1fd
|
1249 1250 |
.get = param_get_string, }; |
ee11ad61f
|
1251 |
static struct kparam_string batadv_param_string_ra = { |
3193e8fdf
|
1252 1253 |
.maxlen = sizeof(batadv_routing_algo), .string = batadv_routing_algo, |
d419be1fd
|
1254 |
}; |
ee11ad61f
|
1255 1256 1257 1258 |
module_param_cb(routing_algo, &batadv_param_ops_ra, &batadv_param_string_ra, 0644); module_init(batadv_init); module_exit(batadv_exit); |
c6c8fea29
|
1259 1260 |
MODULE_LICENSE("GPL"); |
42d0b044b
|
1261 1262 1263 1264 |
MODULE_AUTHOR(BATADV_DRIVER_AUTHOR); MODULE_DESCRIPTION(BATADV_DRIVER_DESC); MODULE_SUPPORTED_DEVICE(BATADV_DRIVER_DEVICE); MODULE_VERSION(BATADV_SOURCE_VERSION); |