diff options
Diffstat (limited to 'net/batman-adv/main.c')
-rw-r--r-- | net/batman-adv/main.c | 138 |
1 files changed, 129 insertions, 9 deletions
diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c index 6d51caaf8cec..083a2993efe4 100644 --- a/net/batman-adv/main.c +++ b/net/batman-adv/main.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include "translation-table.h" | 30 | #include "translation-table.h" |
31 | #include "hard-interface.h" | 31 | #include "hard-interface.h" |
32 | #include "gateway_client.h" | 32 | #include "gateway_client.h" |
33 | #include "bridge_loop_avoidance.h" | ||
33 | #include "vis.h" | 34 | #include "vis.h" |
34 | #include "hash.h" | 35 | #include "hash.h" |
35 | #include "bat_algo.h" | 36 | #include "bat_algo.h" |
@@ -38,6 +39,7 @@ | |||
38 | /* List manipulations on hardif_list have to be rtnl_lock()'ed, | 39 | /* List manipulations on hardif_list have to be rtnl_lock()'ed, |
39 | * list traversals just rcu-locked */ | 40 | * list traversals just rcu-locked */ |
40 | struct list_head hardif_list; | 41 | struct list_head hardif_list; |
42 | static int (*recv_packet_handler[256])(struct sk_buff *, struct hard_iface *); | ||
41 | char bat_routing_algo[20] = "BATMAN IV"; | 43 | char bat_routing_algo[20] = "BATMAN IV"; |
42 | static struct hlist_head bat_algo_list; | 44 | static struct hlist_head bat_algo_list; |
43 | 45 | ||
@@ -45,11 +47,15 @@ unsigned char broadcast_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; | |||
45 | 47 | ||
46 | struct workqueue_struct *bat_event_workqueue; | 48 | struct workqueue_struct *bat_event_workqueue; |
47 | 49 | ||
50 | static void recv_handler_init(void); | ||
51 | |||
48 | static int __init batman_init(void) | 52 | static int __init batman_init(void) |
49 | { | 53 | { |
50 | INIT_LIST_HEAD(&hardif_list); | 54 | INIT_LIST_HEAD(&hardif_list); |
51 | INIT_HLIST_HEAD(&bat_algo_list); | 55 | INIT_HLIST_HEAD(&bat_algo_list); |
52 | 56 | ||
57 | recv_handler_init(); | ||
58 | |||
53 | bat_iv_init(); | 59 | bat_iv_init(); |
54 | 60 | ||
55 | /* the name should not be longer than 10 chars - see | 61 | /* the name should not be longer than 10 chars - see |
@@ -96,13 +102,10 @@ int mesh_init(struct net_device *soft_iface) | |||
96 | spin_lock_init(&bat_priv->gw_list_lock); | 102 | spin_lock_init(&bat_priv->gw_list_lock); |
97 | spin_lock_init(&bat_priv->vis_hash_lock); | 103 | spin_lock_init(&bat_priv->vis_hash_lock); |
98 | spin_lock_init(&bat_priv->vis_list_lock); | 104 | spin_lock_init(&bat_priv->vis_list_lock); |
99 | spin_lock_init(&bat_priv->softif_neigh_lock); | ||
100 | spin_lock_init(&bat_priv->softif_neigh_vid_lock); | ||
101 | 105 | ||
102 | INIT_HLIST_HEAD(&bat_priv->forw_bat_list); | 106 | INIT_HLIST_HEAD(&bat_priv->forw_bat_list); |
103 | INIT_HLIST_HEAD(&bat_priv->forw_bcast_list); | 107 | INIT_HLIST_HEAD(&bat_priv->forw_bcast_list); |
104 | INIT_HLIST_HEAD(&bat_priv->gw_list); | 108 | INIT_HLIST_HEAD(&bat_priv->gw_list); |
105 | INIT_HLIST_HEAD(&bat_priv->softif_neigh_vids); | ||
106 | INIT_LIST_HEAD(&bat_priv->tt_changes_list); | 109 | INIT_LIST_HEAD(&bat_priv->tt_changes_list); |
107 | INIT_LIST_HEAD(&bat_priv->tt_req_list); | 110 | INIT_LIST_HEAD(&bat_priv->tt_req_list); |
108 | INIT_LIST_HEAD(&bat_priv->tt_roam_list); | 111 | INIT_LIST_HEAD(&bat_priv->tt_roam_list); |
@@ -118,6 +121,9 @@ int mesh_init(struct net_device *soft_iface) | |||
118 | if (vis_init(bat_priv) < 1) | 121 | if (vis_init(bat_priv) < 1) |
119 | goto err; | 122 | goto err; |
120 | 123 | ||
124 | if (bla_init(bat_priv) < 1) | ||
125 | goto err; | ||
126 | |||
121 | atomic_set(&bat_priv->gw_reselect, 0); | 127 | atomic_set(&bat_priv->gw_reselect, 0); |
122 | atomic_set(&bat_priv->mesh_state, MESH_ACTIVE); | 128 | atomic_set(&bat_priv->mesh_state, MESH_ACTIVE); |
123 | goto end; | 129 | goto end; |
@@ -145,7 +151,7 @@ void mesh_free(struct net_device *soft_iface) | |||
145 | 151 | ||
146 | tt_free(bat_priv); | 152 | tt_free(bat_priv); |
147 | 153 | ||
148 | softif_neigh_purge(bat_priv); | 154 | bla_free(bat_priv); |
149 | 155 | ||
150 | atomic_set(&bat_priv->mesh_state, MESH_INACTIVE); | 156 | atomic_set(&bat_priv->mesh_state, MESH_INACTIVE); |
151 | } | 157 | } |
@@ -178,6 +184,120 @@ int is_my_mac(const uint8_t *addr) | |||
178 | return 0; | 184 | return 0; |
179 | } | 185 | } |
180 | 186 | ||
187 | static int recv_unhandled_packet(struct sk_buff *skb, | ||
188 | struct hard_iface *recv_if) | ||
189 | { | ||
190 | return NET_RX_DROP; | ||
191 | } | ||
192 | |||
193 | /* incoming packets with the batman ethertype received on any active hard | ||
194 | * interface | ||
195 | */ | ||
196 | int batman_skb_recv(struct sk_buff *skb, struct net_device *dev, | ||
197 | struct packet_type *ptype, struct net_device *orig_dev) | ||
198 | { | ||
199 | struct bat_priv *bat_priv; | ||
200 | struct batman_ogm_packet *batman_ogm_packet; | ||
201 | struct hard_iface *hard_iface; | ||
202 | uint8_t idx; | ||
203 | int ret; | ||
204 | |||
205 | hard_iface = container_of(ptype, struct hard_iface, batman_adv_ptype); | ||
206 | skb = skb_share_check(skb, GFP_ATOMIC); | ||
207 | |||
208 | /* skb was released by skb_share_check() */ | ||
209 | if (!skb) | ||
210 | goto err_out; | ||
211 | |||
212 | /* packet should hold at least type and version */ | ||
213 | if (unlikely(!pskb_may_pull(skb, 2))) | ||
214 | goto err_free; | ||
215 | |||
216 | /* expect a valid ethernet header here. */ | ||
217 | if (unlikely(skb->mac_len != ETH_HLEN || !skb_mac_header(skb))) | ||
218 | goto err_free; | ||
219 | |||
220 | if (!hard_iface->soft_iface) | ||
221 | goto err_free; | ||
222 | |||
223 | bat_priv = netdev_priv(hard_iface->soft_iface); | ||
224 | |||
225 | if (atomic_read(&bat_priv->mesh_state) != MESH_ACTIVE) | ||
226 | goto err_free; | ||
227 | |||
228 | /* discard frames on not active interfaces */ | ||
229 | if (hard_iface->if_status != IF_ACTIVE) | ||
230 | goto err_free; | ||
231 | |||
232 | batman_ogm_packet = (struct batman_ogm_packet *)skb->data; | ||
233 | |||
234 | if (batman_ogm_packet->header.version != COMPAT_VERSION) { | ||
235 | bat_dbg(DBG_BATMAN, bat_priv, | ||
236 | "Drop packet: incompatible batman version (%i)\n", | ||
237 | batman_ogm_packet->header.version); | ||
238 | goto err_free; | ||
239 | } | ||
240 | |||
241 | /* all receive handlers return whether they received or reused | ||
242 | * the supplied skb. if not, we have to free the skb. | ||
243 | */ | ||
244 | idx = batman_ogm_packet->header.packet_type; | ||
245 | ret = (*recv_packet_handler[idx])(skb, hard_iface); | ||
246 | |||
247 | if (ret == NET_RX_DROP) | ||
248 | kfree_skb(skb); | ||
249 | |||
250 | /* return NET_RX_SUCCESS in any case as we | ||
251 | * most probably dropped the packet for | ||
252 | * routing-logical reasons. | ||
253 | */ | ||
254 | return NET_RX_SUCCESS; | ||
255 | |||
256 | err_free: | ||
257 | kfree_skb(skb); | ||
258 | err_out: | ||
259 | return NET_RX_DROP; | ||
260 | } | ||
261 | |||
262 | static void recv_handler_init(void) | ||
263 | { | ||
264 | int i; | ||
265 | |||
266 | for (i = 0; i < ARRAY_SIZE(recv_packet_handler); i++) | ||
267 | recv_packet_handler[i] = recv_unhandled_packet; | ||
268 | |||
269 | /* batman icmp packet */ | ||
270 | recv_packet_handler[BAT_ICMP] = recv_icmp_packet; | ||
271 | /* unicast packet */ | ||
272 | recv_packet_handler[BAT_UNICAST] = recv_unicast_packet; | ||
273 | /* fragmented unicast packet */ | ||
274 | recv_packet_handler[BAT_UNICAST_FRAG] = recv_ucast_frag_packet; | ||
275 | /* broadcast packet */ | ||
276 | recv_packet_handler[BAT_BCAST] = recv_bcast_packet; | ||
277 | /* vis packet */ | ||
278 | recv_packet_handler[BAT_VIS] = recv_vis_packet; | ||
279 | /* Translation table query (request or response) */ | ||
280 | recv_packet_handler[BAT_TT_QUERY] = recv_tt_query; | ||
281 | /* Roaming advertisement */ | ||
282 | recv_packet_handler[BAT_ROAM_ADV] = recv_roam_adv; | ||
283 | } | ||
284 | |||
285 | int recv_handler_register(uint8_t packet_type, | ||
286 | int (*recv_handler)(struct sk_buff *, | ||
287 | struct hard_iface *)) | ||
288 | { | ||
289 | if (recv_packet_handler[packet_type] != &recv_unhandled_packet) | ||
290 | return -EBUSY; | ||
291 | |||
292 | recv_packet_handler[packet_type] = recv_handler; | ||
293 | return 0; | ||
294 | } | ||
295 | |||
296 | void recv_handler_unregister(uint8_t packet_type) | ||
297 | { | ||
298 | recv_packet_handler[packet_type] = recv_unhandled_packet; | ||
299 | } | ||
300 | |||
181 | static struct bat_algo_ops *bat_algo_get(char *name) | 301 | static struct bat_algo_ops *bat_algo_get(char *name) |
182 | { | 302 | { |
183 | struct bat_algo_ops *bat_algo_ops = NULL, *bat_algo_ops_tmp; | 303 | struct bat_algo_ops *bat_algo_ops = NULL, *bat_algo_ops_tmp; |
@@ -207,12 +327,12 @@ int bat_algo_register(struct bat_algo_ops *bat_algo_ops) | |||
207 | } | 327 | } |
208 | 328 | ||
209 | /* all algorithms must implement all ops (for now) */ | 329 | /* all algorithms must implement all ops (for now) */ |
210 | if (!bat_algo_ops->bat_ogm_init || | 330 | if (!bat_algo_ops->bat_iface_enable || |
211 | !bat_algo_ops->bat_ogm_init_primary || | 331 | !bat_algo_ops->bat_iface_disable || |
212 | !bat_algo_ops->bat_ogm_update_mac || | 332 | !bat_algo_ops->bat_iface_update_mac || |
333 | !bat_algo_ops->bat_primary_iface_set || | ||
213 | !bat_algo_ops->bat_ogm_schedule || | 334 | !bat_algo_ops->bat_ogm_schedule || |
214 | !bat_algo_ops->bat_ogm_emit || | 335 | !bat_algo_ops->bat_ogm_emit) { |
215 | !bat_algo_ops->bat_ogm_receive) { | ||
216 | pr_info("Routing algo '%s' does not implement required ops\n", | 336 | pr_info("Routing algo '%s' does not implement required ops\n", |
217 | bat_algo_ops->name); | 337 | bat_algo_ops->name); |
218 | goto out; | 338 | goto out; |