aboutsummaryrefslogtreecommitdiffstats
path: root/net/batman-adv/routing.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/batman-adv/routing.c')
-rw-r--r--net/batman-adv/routing.c120
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 */
263static int batadv_recv_my_icmp_packet(struct batadv_priv *bat_priv, 271static 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 }
304out: 322out:
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)