diff options
author | Marek Lindner <lindner_marek@yahoo.de> | 2012-03-01 02:35:17 -0500 |
---|---|---|
committer | Antonio Quartulli <ordex@autistici.org> | 2012-05-11 04:08:10 -0400 |
commit | ffa995e036bef734ea40cbbccda574d1df3a8a58 (patch) | |
tree | 396d7c202f1b0d82dce905e7d70c32708886f404 /net/batman-adv/main.c | |
parent | 75cd33f86396c446f84c4bb620be70c36a2a54f6 (diff) |
batman-adv: introduce packet type handler array for incoming packets
The packet handler array replaces the growing switch statement, thus
dealing with incoming packets in a more efficient way. It also adds
to possibility to register packet handlers on the fly.
Signed-off-by: Marek Lindner <lindner_marek@yahoo.de>
Acked-by: Simon Wunderlich <siwu@hrz.tu-chemnitz.de>
Signed-off-by: Antonio Quartulli <ordex@autistici.org>
Diffstat (limited to 'net/batman-adv/main.c')
-rw-r--r-- | net/batman-adv/main.c | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c index 791327219531..d19b93575d56 100644 --- a/net/batman-adv/main.c +++ b/net/batman-adv/main.c | |||
@@ -39,6 +39,7 @@ | |||
39 | /* List manipulations on hardif_list have to be rtnl_lock()'ed, | 39 | /* List manipulations on hardif_list have to be rtnl_lock()'ed, |
40 | * list traversals just rcu-locked */ | 40 | * list traversals just rcu-locked */ |
41 | struct list_head hardif_list; | 41 | struct list_head hardif_list; |
42 | static int (*recv_packet_handler[256])(struct sk_buff *, struct hard_iface *); | ||
42 | char bat_routing_algo[20] = "BATMAN IV"; | 43 | char bat_routing_algo[20] = "BATMAN IV"; |
43 | static struct hlist_head bat_algo_list; | 44 | static struct hlist_head bat_algo_list; |
44 | 45 | ||
@@ -46,11 +47,15 @@ unsigned char broadcast_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; | |||
46 | 47 | ||
47 | struct workqueue_struct *bat_event_workqueue; | 48 | struct workqueue_struct *bat_event_workqueue; |
48 | 49 | ||
50 | static void recv_handler_init(void); | ||
51 | |||
49 | static int __init batman_init(void) | 52 | static int __init batman_init(void) |
50 | { | 53 | { |
51 | INIT_LIST_HEAD(&hardif_list); | 54 | INIT_LIST_HEAD(&hardif_list); |
52 | INIT_HLIST_HEAD(&bat_algo_list); | 55 | INIT_HLIST_HEAD(&bat_algo_list); |
53 | 56 | ||
57 | recv_handler_init(); | ||
58 | |||
54 | bat_iv_init(); | 59 | bat_iv_init(); |
55 | 60 | ||
56 | /* the name should not be longer than 10 chars - see | 61 | /* the name should not be longer than 10 chars - see |
@@ -179,6 +184,122 @@ int is_my_mac(const uint8_t *addr) | |||
179 | return 0; | 184 | return 0; |
180 | } | 185 | } |
181 | 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 originator packet */ | ||
270 | recv_packet_handler[BAT_IV_OGM] = recv_bat_ogm_packet; | ||
271 | /* batman icmp packet */ | ||
272 | recv_packet_handler[BAT_ICMP] = recv_icmp_packet; | ||
273 | /* unicast packet */ | ||
274 | recv_packet_handler[BAT_UNICAST] = recv_unicast_packet; | ||
275 | /* fragmented unicast packet */ | ||
276 | recv_packet_handler[BAT_UNICAST_FRAG] = recv_ucast_frag_packet; | ||
277 | /* broadcast packet */ | ||
278 | recv_packet_handler[BAT_BCAST] = recv_bcast_packet; | ||
279 | /* vis packet */ | ||
280 | recv_packet_handler[BAT_VIS] = recv_vis_packet; | ||
281 | /* Translation table query (request or response) */ | ||
282 | recv_packet_handler[BAT_TT_QUERY] = recv_tt_query; | ||
283 | /* Roaming advertisement */ | ||
284 | recv_packet_handler[BAT_ROAM_ADV] = recv_roam_adv; | ||
285 | } | ||
286 | |||
287 | int recv_handler_register(uint8_t packet_type, | ||
288 | int (*recv_handler)(struct sk_buff *, | ||
289 | struct hard_iface *)) | ||
290 | { | ||
291 | if (recv_packet_handler[packet_type] != &recv_unhandled_packet) | ||
292 | return -EBUSY; | ||
293 | |||
294 | recv_packet_handler[packet_type] = recv_handler; | ||
295 | return 0; | ||
296 | } | ||
297 | |||
298 | void recv_handler_unregister(uint8_t packet_type) | ||
299 | { | ||
300 | recv_packet_handler[packet_type] = recv_unhandled_packet; | ||
301 | } | ||
302 | |||
182 | static struct bat_algo_ops *bat_algo_get(char *name) | 303 | static struct bat_algo_ops *bat_algo_get(char *name) |
183 | { | 304 | { |
184 | struct bat_algo_ops *bat_algo_ops = NULL, *bat_algo_ops_tmp; | 305 | struct bat_algo_ops *bat_algo_ops = NULL, *bat_algo_ops_tmp; |