diff options
Diffstat (limited to 'net/batman-adv/routing.c')
-rw-r--r-- | net/batman-adv/routing.c | 120 |
1 files changed, 73 insertions, 47 deletions
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index 71fba146ddf1..d4114d775ad6 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c | |||
@@ -260,47 +260,65 @@ bool batadv_check_management_packet(struct sk_buff *skb, | |||
260 | return true; | 260 | return true; |
261 | } | 261 | } |
262 | 262 | ||
263 | /** | ||
264 | * batadv_recv_my_icmp_packet - receive an icmp packet locally | ||
265 | * @bat_priv: the bat priv with all the soft interface information | ||
266 | * @skb: icmp packet to process | ||
267 | * | ||
268 | * Returns NET_RX_SUCCESS if the packet has been consumed or NET_RX_DROP | ||
269 | * otherwise. | ||
270 | */ | ||
263 | static int batadv_recv_my_icmp_packet(struct batadv_priv *bat_priv, | 271 | static int batadv_recv_my_icmp_packet(struct batadv_priv *bat_priv, |
264 | struct sk_buff *skb, size_t icmp_len) | 272 | struct sk_buff *skb) |
265 | { | 273 | { |
266 | struct batadv_hard_iface *primary_if = NULL; | 274 | struct batadv_hard_iface *primary_if = NULL; |
267 | struct batadv_orig_node *orig_node = NULL; | 275 | struct batadv_orig_node *orig_node = NULL; |
268 | struct batadv_icmp_packet_rr *icmp_packet; | 276 | struct batadv_icmp_header *icmph; |
269 | int ret = NET_RX_DROP; | 277 | int res, ret = NET_RX_DROP; |
270 | 278 | ||
271 | icmp_packet = (struct batadv_icmp_packet_rr *)skb->data; | 279 | icmph = (struct batadv_icmp_header *)skb->data; |
272 | 280 | ||
273 | /* add data to device queue */ | 281 | switch (icmph->msg_type) { |
274 | if (icmp_packet->icmph.msg_type != BATADV_ECHO_REQUEST) { | 282 | case BATADV_ECHO_REPLY: |
275 | batadv_socket_receive_packet(icmp_packet, icmp_len); | 283 | case BATADV_DESTINATION_UNREACHABLE: |
276 | goto out; | 284 | case BATADV_TTL_EXCEEDED: |
277 | } | 285 | /* receive the packet */ |
286 | if (skb_linearize(skb) < 0) | ||
287 | break; | ||
278 | 288 | ||
279 | primary_if = batadv_primary_if_get_selected(bat_priv); | 289 | batadv_socket_receive_packet(icmph, skb->len); |
280 | if (!primary_if) | 290 | break; |
281 | goto out; | 291 | case BATADV_ECHO_REQUEST: |
292 | /* answer echo request (ping) */ | ||
293 | primary_if = batadv_primary_if_get_selected(bat_priv); | ||
294 | if (!primary_if) | ||
295 | goto out; | ||
282 | 296 | ||
283 | /* answer echo request (ping) */ | 297 | /* get routing information */ |
284 | /* get routing information */ | 298 | orig_node = batadv_orig_hash_find(bat_priv, icmph->orig); |
285 | orig_node = batadv_orig_hash_find(bat_priv, icmp_packet->icmph.orig); | 299 | if (!orig_node) |
286 | if (!orig_node) | 300 | goto out; |
287 | goto out; | ||
288 | 301 | ||
289 | /* create a copy of the skb, if needed, to modify it. */ | 302 | /* create a copy of the skb, if needed, to modify it. */ |
290 | if (skb_cow(skb, ETH_HLEN) < 0) | 303 | if (skb_cow(skb, ETH_HLEN) < 0) |
291 | goto out; | 304 | goto out; |
292 | 305 | ||
293 | icmp_packet = (struct batadv_icmp_packet_rr *)skb->data; | 306 | icmph = (struct batadv_icmp_header *)skb->data; |
294 | 307 | ||
295 | memcpy(icmp_packet->icmph.dst, icmp_packet->icmph.orig, ETH_ALEN); | 308 | memcpy(icmph->dst, icmph->orig, ETH_ALEN); |
296 | memcpy(icmp_packet->icmph.orig, primary_if->net_dev->dev_addr, | 309 | memcpy(icmph->orig, primary_if->net_dev->dev_addr, ETH_ALEN); |
297 | ETH_ALEN); | 310 | icmph->msg_type = BATADV_ECHO_REPLY; |
298 | icmp_packet->icmph.msg_type = BATADV_ECHO_REPLY; | 311 | icmph->header.ttl = BATADV_TTL; |
299 | icmp_packet->icmph.header.ttl = BATADV_TTL; | ||
300 | 312 | ||
301 | if (batadv_send_skb_to_orig(skb, orig_node, NULL) != NET_XMIT_DROP) | 313 | res = batadv_send_skb_to_orig(skb, orig_node, NULL); |
302 | ret = NET_RX_SUCCESS; | 314 | if (res != NET_XMIT_DROP) |
315 | ret = NET_RX_SUCCESS; | ||
303 | 316 | ||
317 | break; | ||
318 | default: | ||
319 | /* drop unknown type */ | ||
320 | goto out; | ||
321 | } | ||
304 | out: | 322 | out: |
305 | if (primary_if) | 323 | if (primary_if) |
306 | batadv_hardif_free_ref(primary_if); | 324 | batadv_hardif_free_ref(primary_if); |
@@ -363,16 +381,13 @@ int batadv_recv_icmp_packet(struct sk_buff *skb, | |||
363 | struct batadv_hard_iface *recv_if) | 381 | struct batadv_hard_iface *recv_if) |
364 | { | 382 | { |
365 | struct batadv_priv *bat_priv = netdev_priv(recv_if->soft_iface); | 383 | struct batadv_priv *bat_priv = netdev_priv(recv_if->soft_iface); |
366 | struct batadv_icmp_packet_rr *icmp_packet; | 384 | struct batadv_icmp_header *icmph; |
385 | struct batadv_icmp_packet_rr *icmp_packet_rr; | ||
367 | struct ethhdr *ethhdr; | 386 | struct ethhdr *ethhdr; |
368 | struct batadv_orig_node *orig_node = NULL; | 387 | struct batadv_orig_node *orig_node = NULL; |
369 | int hdr_size = sizeof(struct batadv_icmp_packet); | 388 | int hdr_size = sizeof(struct batadv_icmp_header); |
370 | int ret = NET_RX_DROP; | 389 | int ret = NET_RX_DROP; |
371 | 390 | ||
372 | /* we truncate all incoming icmp packets if they don't match our size */ | ||
373 | if (skb->len >= sizeof(struct batadv_icmp_packet_rr)) | ||
374 | hdr_size = sizeof(struct batadv_icmp_packet_rr); | ||
375 | |||
376 | /* drop packet if it has not necessary minimum size */ | 391 | /* drop packet if it has not necessary minimum size */ |
377 | if (unlikely(!pskb_may_pull(skb, hdr_size))) | 392 | if (unlikely(!pskb_may_pull(skb, hdr_size))) |
378 | goto out; | 393 | goto out; |
@@ -391,28 +406,39 @@ int batadv_recv_icmp_packet(struct sk_buff *skb, | |||
391 | if (!batadv_is_my_mac(bat_priv, ethhdr->h_dest)) | 406 | if (!batadv_is_my_mac(bat_priv, ethhdr->h_dest)) |
392 | goto out; | 407 | goto out; |
393 | 408 | ||
394 | icmp_packet = (struct batadv_icmp_packet_rr *)skb->data; | 409 | icmph = (struct batadv_icmp_header *)skb->data; |
395 | 410 | ||
396 | /* add record route information if not full */ | 411 | /* add record route information if not full */ |
397 | if ((icmp_packet->icmph.msg_type == BATADV_ECHO_REPLY || | 412 | if ((icmph->msg_type == BATADV_ECHO_REPLY || |
398 | icmp_packet->icmph.msg_type == BATADV_ECHO_REQUEST) && | 413 | icmph->msg_type == BATADV_ECHO_REQUEST) && |
399 | (hdr_size == sizeof(struct batadv_icmp_packet_rr)) && | 414 | (skb->len >= sizeof(struct batadv_icmp_packet_rr))) { |
400 | (icmp_packet->rr_cur < BATADV_RR_LEN)) { | 415 | if (skb_linearize(skb) < 0) |
401 | memcpy(&(icmp_packet->rr[icmp_packet->rr_cur]), | 416 | goto out; |
417 | |||
418 | /* create a copy of the skb, if needed, to modify it. */ | ||
419 | if (skb_cow(skb, ETH_HLEN) < 0) | ||
420 | goto out; | ||
421 | |||
422 | icmph = (struct batadv_icmp_header *)skb->data; | ||
423 | icmp_packet_rr = (struct batadv_icmp_packet_rr *)icmph; | ||
424 | if (icmp_packet_rr->rr_cur >= BATADV_RR_LEN) | ||
425 | goto out; | ||
426 | |||
427 | memcpy(&(icmp_packet_rr->rr[icmp_packet_rr->rr_cur]), | ||
402 | ethhdr->h_dest, ETH_ALEN); | 428 | ethhdr->h_dest, ETH_ALEN); |
403 | icmp_packet->rr_cur++; | 429 | icmp_packet_rr->rr_cur++; |
404 | } | 430 | } |
405 | 431 | ||
406 | /* packet for me */ | 432 | /* packet for me */ |
407 | if (batadv_is_my_mac(bat_priv, icmp_packet->icmph.dst)) | 433 | if (batadv_is_my_mac(bat_priv, icmph->dst)) |
408 | return batadv_recv_my_icmp_packet(bat_priv, skb, hdr_size); | 434 | return batadv_recv_my_icmp_packet(bat_priv, skb); |
409 | 435 | ||
410 | /* TTL exceeded */ | 436 | /* TTL exceeded */ |
411 | if (icmp_packet->icmph.header.ttl < 2) | 437 | if (icmph->header.ttl < 2) |
412 | return batadv_recv_icmp_ttl_exceeded(bat_priv, skb); | 438 | return batadv_recv_icmp_ttl_exceeded(bat_priv, skb); |
413 | 439 | ||
414 | /* get routing information */ | 440 | /* get routing information */ |
415 | orig_node = batadv_orig_hash_find(bat_priv, icmp_packet->icmph.dst); | 441 | orig_node = batadv_orig_hash_find(bat_priv, icmph->dst); |
416 | if (!orig_node) | 442 | if (!orig_node) |
417 | goto out; | 443 | goto out; |
418 | 444 | ||
@@ -420,10 +446,10 @@ int batadv_recv_icmp_packet(struct sk_buff *skb, | |||
420 | if (skb_cow(skb, ETH_HLEN) < 0) | 446 | if (skb_cow(skb, ETH_HLEN) < 0) |
421 | goto out; | 447 | goto out; |
422 | 448 | ||
423 | icmp_packet = (struct batadv_icmp_packet_rr *)skb->data; | 449 | icmph = (struct batadv_icmp_header *)skb->data; |
424 | 450 | ||
425 | /* decrement ttl */ | 451 | /* decrement ttl */ |
426 | icmp_packet->icmph.header.ttl--; | 452 | icmph->header.ttl--; |
427 | 453 | ||
428 | /* route it */ | 454 | /* route it */ |
429 | if (batadv_send_skb_to_orig(skb, orig_node, recv_if) != NET_XMIT_DROP) | 455 | if (batadv_send_skb_to_orig(skb, orig_node, recv_if) != NET_XMIT_DROP) |