aboutsummaryrefslogtreecommitdiffstats
path: root/net/batman-adv/gateway_client.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/batman-adv/gateway_client.c')
-rw-r--r--net/batman-adv/gateway_client.c235
1 files changed, 153 insertions, 82 deletions
diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c
index 1ce4b8763ef2..20fa053b7f57 100644
--- a/net/batman-adv/gateway_client.c
+++ b/net/batman-adv/gateway_client.c
@@ -118,7 +118,6 @@ batadv_gw_get_best_gw_node(struct batadv_priv *bat_priv)
118 uint32_t max_gw_factor = 0, tmp_gw_factor = 0; 118 uint32_t max_gw_factor = 0, tmp_gw_factor = 0;
119 uint32_t gw_divisor; 119 uint32_t gw_divisor;
120 uint8_t max_tq = 0; 120 uint8_t max_tq = 0;
121 int down, up;
122 uint8_t tq_avg; 121 uint8_t tq_avg;
123 struct batadv_orig_node *orig_node; 122 struct batadv_orig_node *orig_node;
124 123
@@ -142,10 +141,9 @@ batadv_gw_get_best_gw_node(struct batadv_priv *bat_priv)
142 141
143 switch (atomic_read(&bat_priv->gw_sel_class)) { 142 switch (atomic_read(&bat_priv->gw_sel_class)) {
144 case 1: /* fast connection */ 143 case 1: /* fast connection */
145 batadv_gw_bandwidth_to_kbit(orig_node->gw_flags, 144 tmp_gw_factor = tq_avg * tq_avg;
146 &down, &up); 145 tmp_gw_factor *= gw_node->bandwidth_down;
147 146 tmp_gw_factor *= 100 * 100;
148 tmp_gw_factor = tq_avg * tq_avg * down * 100 * 100;
149 tmp_gw_factor /= gw_divisor; 147 tmp_gw_factor /= gw_divisor;
150 148
151 if ((tmp_gw_factor > max_gw_factor) || 149 if ((tmp_gw_factor > max_gw_factor) ||
@@ -223,11 +221,6 @@ void batadv_gw_election(struct batadv_priv *bat_priv)
223 struct batadv_neigh_node *router = NULL; 221 struct batadv_neigh_node *router = NULL;
224 char gw_addr[18] = { '\0' }; 222 char gw_addr[18] = { '\0' };
225 223
226 /* The batman daemon checks here if we already passed a full originator
227 * cycle in order to make sure we don't choose the first gateway we
228 * hear about. This check is based on the daemon's uptime which we
229 * don't have.
230 */
231 if (atomic_read(&bat_priv->gw_mode) != BATADV_GW_MODE_CLIENT) 224 if (atomic_read(&bat_priv->gw_mode) != BATADV_GW_MODE_CLIENT)
232 goto out; 225 goto out;
233 226
@@ -258,16 +251,22 @@ void batadv_gw_election(struct batadv_priv *bat_priv)
258 NULL); 251 NULL);
259 } else if ((!curr_gw) && (next_gw)) { 252 } else if ((!curr_gw) && (next_gw)) {
260 batadv_dbg(BATADV_DBG_BATMAN, bat_priv, 253 batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
261 "Adding route to gateway %pM (gw_flags: %i, tq: %i)\n", 254 "Adding route to gateway %pM (bandwidth: %u.%u/%u.%u MBit, tq: %i)\n",
262 next_gw->orig_node->orig, 255 next_gw->orig_node->orig,
263 next_gw->orig_node->gw_flags, router->tq_avg); 256 next_gw->bandwidth_down / 10,
257 next_gw->bandwidth_down % 10,
258 next_gw->bandwidth_up / 10,
259 next_gw->bandwidth_up % 10, router->tq_avg);
264 batadv_throw_uevent(bat_priv, BATADV_UEV_GW, BATADV_UEV_ADD, 260 batadv_throw_uevent(bat_priv, BATADV_UEV_GW, BATADV_UEV_ADD,
265 gw_addr); 261 gw_addr);
266 } else { 262 } else {
267 batadv_dbg(BATADV_DBG_BATMAN, bat_priv, 263 batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
268 "Changing route to gateway %pM (gw_flags: %i, tq: %i)\n", 264 "Changing route to gateway %pM (bandwidth: %u.%u/%u.%u MBit, tq: %i)\n",
269 next_gw->orig_node->orig, 265 next_gw->orig_node->orig,
270 next_gw->orig_node->gw_flags, router->tq_avg); 266 next_gw->bandwidth_down / 10,
267 next_gw->bandwidth_down % 10,
268 next_gw->bandwidth_up / 10,
269 next_gw->bandwidth_up % 10, router->tq_avg);
271 batadv_throw_uevent(bat_priv, BATADV_UEV_GW, BATADV_UEV_CHANGE, 270 batadv_throw_uevent(bat_priv, BATADV_UEV_GW, BATADV_UEV_CHANGE,
272 gw_addr); 271 gw_addr);
273 } 272 }
@@ -337,12 +336,20 @@ out:
337 return; 336 return;
338} 337}
339 338
339/**
340 * batadv_gw_node_add - add gateway node to list of available gateways
341 * @bat_priv: the bat priv with all the soft interface information
342 * @orig_node: originator announcing gateway capabilities
343 * @gateway: announced bandwidth information
344 */
340static void batadv_gw_node_add(struct batadv_priv *bat_priv, 345static void batadv_gw_node_add(struct batadv_priv *bat_priv,
341 struct batadv_orig_node *orig_node, 346 struct batadv_orig_node *orig_node,
342 uint8_t new_gwflags) 347 struct batadv_tvlv_gateway_data *gateway)
343{ 348{
344 struct batadv_gw_node *gw_node; 349 struct batadv_gw_node *gw_node;
345 int down, up; 350
351 if (gateway->bandwidth_down == 0)
352 return;
346 353
347 gw_node = kzalloc(sizeof(*gw_node), GFP_ATOMIC); 354 gw_node = kzalloc(sizeof(*gw_node), GFP_ATOMIC);
348 if (!gw_node) 355 if (!gw_node)
@@ -356,73 +363,116 @@ static void batadv_gw_node_add(struct batadv_priv *bat_priv,
356 hlist_add_head_rcu(&gw_node->list, &bat_priv->gw.list); 363 hlist_add_head_rcu(&gw_node->list, &bat_priv->gw.list);
357 spin_unlock_bh(&bat_priv->gw.list_lock); 364 spin_unlock_bh(&bat_priv->gw.list_lock);
358 365
359 batadv_gw_bandwidth_to_kbit(new_gwflags, &down, &up);
360 batadv_dbg(BATADV_DBG_BATMAN, bat_priv, 366 batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
361 "Found new gateway %pM -> gw_class: %i - %i%s/%i%s\n", 367 "Found new gateway %pM -> gw bandwidth: %u.%u/%u.%u MBit\n",
362 orig_node->orig, new_gwflags, 368 orig_node->orig,
363 (down > 2048 ? down / 1024 : down), 369 ntohl(gateway->bandwidth_down) / 10,
364 (down > 2048 ? "MBit" : "KBit"), 370 ntohl(gateway->bandwidth_down) % 10,
365 (up > 2048 ? up / 1024 : up), 371 ntohl(gateway->bandwidth_up) / 10,
366 (up > 2048 ? "MBit" : "KBit")); 372 ntohl(gateway->bandwidth_up) % 10);
367} 373}
368 374
369void batadv_gw_node_update(struct batadv_priv *bat_priv, 375/**
370 struct batadv_orig_node *orig_node, 376 * batadv_gw_node_get - retrieve gateway node from list of available gateways
371 uint8_t new_gwflags) 377 * @bat_priv: the bat priv with all the soft interface information
378 * @orig_node: originator announcing gateway capabilities
379 *
380 * Returns gateway node if found or NULL otherwise.
381 */
382static struct batadv_gw_node *
383batadv_gw_node_get(struct batadv_priv *bat_priv,
384 struct batadv_orig_node *orig_node)
372{ 385{
373 struct batadv_gw_node *gw_node, *curr_gw; 386 struct batadv_gw_node *gw_node_tmp, *gw_node = NULL;
374
375 /* Note: We don't need a NULL check here, since curr_gw never gets
376 * dereferenced. If curr_gw is NULL we also should not exit as we may
377 * have this gateway in our list (duplication check!) even though we
378 * have no currently selected gateway.
379 */
380 curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
381 387
382 rcu_read_lock(); 388 rcu_read_lock();
383 hlist_for_each_entry_rcu(gw_node, &bat_priv->gw.list, list) { 389 hlist_for_each_entry_rcu(gw_node_tmp, &bat_priv->gw.list, list) {
384 if (gw_node->orig_node != orig_node) 390 if (gw_node_tmp->orig_node != orig_node)
385 continue; 391 continue;
386 392
387 batadv_dbg(BATADV_DBG_BATMAN, bat_priv, 393 if (gw_node_tmp->deleted)
388 "Gateway class of originator %pM changed from %i to %i\n", 394 continue;
389 orig_node->orig, gw_node->orig_node->gw_flags,
390 new_gwflags);
391 395
392 gw_node->deleted = 0; 396 if (!atomic_inc_not_zero(&gw_node_tmp->refcount))
397 continue;
393 398
394 if (new_gwflags == BATADV_NO_FLAGS) { 399 gw_node = gw_node_tmp;
395 gw_node->deleted = jiffies; 400 break;
396 batadv_dbg(BATADV_DBG_BATMAN, bat_priv, 401 }
397 "Gateway %pM removed from gateway list\n", 402 rcu_read_unlock();
398 orig_node->orig);
399 403
400 if (gw_node == curr_gw) 404 return gw_node;
401 goto deselect; 405}
402 }
403 406
404 goto unlock; 407/**
408 * batadv_gw_node_update - update list of available gateways with changed
409 * bandwidth information
410 * @bat_priv: the bat priv with all the soft interface information
411 * @orig_node: originator announcing gateway capabilities
412 * @gateway: announced bandwidth information
413 */
414void batadv_gw_node_update(struct batadv_priv *bat_priv,
415 struct batadv_orig_node *orig_node,
416 struct batadv_tvlv_gateway_data *gateway)
417{
418 struct batadv_gw_node *gw_node, *curr_gw = NULL;
419
420 gw_node = batadv_gw_node_get(bat_priv, orig_node);
421 if (!gw_node) {
422 batadv_gw_node_add(bat_priv, orig_node, gateway);
423 goto out;
405 } 424 }
406 425
407 if (new_gwflags == BATADV_NO_FLAGS) 426 if ((gw_node->bandwidth_down == ntohl(gateway->bandwidth_down)) &&
408 goto unlock; 427 (gw_node->bandwidth_up == ntohl(gateway->bandwidth_up)))
428 goto out;
409 429
410 batadv_gw_node_add(bat_priv, orig_node, new_gwflags); 430 batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
411 goto unlock; 431 "Gateway bandwidth of originator %pM changed from %u.%u/%u.%u MBit to %u.%u/%u.%u MBit\n",
432 orig_node->orig,
433 gw_node->bandwidth_down / 10,
434 gw_node->bandwidth_down % 10,
435 gw_node->bandwidth_up / 10,
436 gw_node->bandwidth_up % 10,
437 ntohl(gateway->bandwidth_down) / 10,
438 ntohl(gateway->bandwidth_down) % 10,
439 ntohl(gateway->bandwidth_up) / 10,
440 ntohl(gateway->bandwidth_up) % 10);
441
442 gw_node->bandwidth_down = ntohl(gateway->bandwidth_down);
443 gw_node->bandwidth_up = ntohl(gateway->bandwidth_up);
444
445 gw_node->deleted = 0;
446 if (ntohl(gateway->bandwidth_down) == 0) {
447 gw_node->deleted = jiffies;
448 batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
449 "Gateway %pM removed from gateway list\n",
450 orig_node->orig);
412 451
413deselect: 452 /* Note: We don't need a NULL check here, since curr_gw never
414 batadv_gw_deselect(bat_priv); 453 * gets dereferenced.
415unlock: 454 */
416 rcu_read_unlock(); 455 curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
456 if (gw_node == curr_gw)
457 batadv_gw_deselect(bat_priv);
458 }
417 459
460out:
418 if (curr_gw) 461 if (curr_gw)
419 batadv_gw_node_free_ref(curr_gw); 462 batadv_gw_node_free_ref(curr_gw);
463 if (gw_node)
464 batadv_gw_node_free_ref(gw_node);
420} 465}
421 466
422void batadv_gw_node_delete(struct batadv_priv *bat_priv, 467void batadv_gw_node_delete(struct batadv_priv *bat_priv,
423 struct batadv_orig_node *orig_node) 468 struct batadv_orig_node *orig_node)
424{ 469{
425 batadv_gw_node_update(bat_priv, orig_node, 0); 470 struct batadv_tvlv_gateway_data gateway;
471
472 gateway.bandwidth_down = 0;
473 gateway.bandwidth_up = 0;
474
475 batadv_gw_node_update(bat_priv, orig_node, &gateway);
426} 476}
427 477
428void batadv_gw_node_purge(struct batadv_priv *bat_priv) 478void batadv_gw_node_purge(struct batadv_priv *bat_priv)
@@ -467,9 +517,7 @@ static int batadv_write_buffer_text(struct batadv_priv *bat_priv,
467{ 517{
468 struct batadv_gw_node *curr_gw; 518 struct batadv_gw_node *curr_gw;
469 struct batadv_neigh_node *router; 519 struct batadv_neigh_node *router;
470 int down, up, ret = -1; 520 int ret = -1;
471
472 batadv_gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags, &down, &up);
473 521
474 router = batadv_orig_node_get_router(gw_node->orig_node); 522 router = batadv_orig_node_get_router(gw_node->orig_node);
475 if (!router) 523 if (!router)
@@ -477,16 +525,15 @@ static int batadv_write_buffer_text(struct batadv_priv *bat_priv,
477 525
478 curr_gw = batadv_gw_get_selected_gw_node(bat_priv); 526 curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
479 527
480 ret = seq_printf(seq, "%s %pM (%3i) %pM [%10s]: %3i - %i%s/%i%s\n", 528 ret = seq_printf(seq, "%s %pM (%3i) %pM [%10s]: %u.%u/%u.%u MBit\n",
481 (curr_gw == gw_node ? "=>" : " "), 529 (curr_gw == gw_node ? "=>" : " "),
482 gw_node->orig_node->orig, 530 gw_node->orig_node->orig,
483 router->tq_avg, router->addr, 531 router->tq_avg, router->addr,
484 router->if_incoming->net_dev->name, 532 router->if_incoming->net_dev->name,
485 gw_node->orig_node->gw_flags, 533 gw_node->bandwidth_down / 10,
486 (down > 2048 ? down / 1024 : down), 534 gw_node->bandwidth_down % 10,
487 (down > 2048 ? "MBit" : "KBit"), 535 gw_node->bandwidth_up / 10,
488 (up > 2048 ? up / 1024 : up), 536 gw_node->bandwidth_up % 10);
489 (up > 2048 ? "MBit" : "KBit"));
490 537
491 batadv_neigh_node_free_ref(router); 538 batadv_neigh_node_free_ref(router);
492 if (curr_gw) 539 if (curr_gw)
@@ -508,7 +555,7 @@ int batadv_gw_client_seq_print_text(struct seq_file *seq, void *offset)
508 goto out; 555 goto out;
509 556
510 seq_printf(seq, 557 seq_printf(seq,
511 " %-12s (%s/%i) %17s [%10s]: gw_class ... [B.A.T.M.A.N. adv %s, MainIF/MAC: %s/%pM (%s)]\n", 558 " %-12s (%s/%i) %17s [%10s]: advertised uplink bandwidth ... [B.A.T.M.A.N. adv %s, MainIF/MAC: %s/%pM (%s)]\n",
512 "Gateway", "#", BATADV_TQ_MAX_VALUE, "Nexthop", "outgoingIF", 559 "Gateway", "#", BATADV_TQ_MAX_VALUE, "Nexthop", "outgoingIF",
513 BATADV_SOURCE_VERSION, primary_if->net_dev->name, 560 BATADV_SOURCE_VERSION, primary_if->net_dev->name,
514 primary_if->net_dev->dev_addr, net_dev->name); 561 primary_if->net_dev->dev_addr, net_dev->name);
@@ -603,24 +650,29 @@ bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len)
603 struct iphdr *iphdr; 650 struct iphdr *iphdr;
604 struct ipv6hdr *ipv6hdr; 651 struct ipv6hdr *ipv6hdr;
605 struct udphdr *udphdr; 652 struct udphdr *udphdr;
653 struct vlan_ethhdr *vhdr;
654 __be16 proto;
606 655
607 /* check for ethernet header */ 656 /* check for ethernet header */
608 if (!pskb_may_pull(skb, *header_len + ETH_HLEN)) 657 if (!pskb_may_pull(skb, *header_len + ETH_HLEN))
609 return false; 658 return false;
610 ethhdr = (struct ethhdr *)skb->data; 659 ethhdr = (struct ethhdr *)skb->data;
660 proto = ethhdr->h_proto;
611 *header_len += ETH_HLEN; 661 *header_len += ETH_HLEN;
612 662
613 /* check for initial vlan header */ 663 /* check for initial vlan header */
614 if (ntohs(ethhdr->h_proto) == ETH_P_8021Q) { 664 if (proto == htons(ETH_P_8021Q)) {
615 if (!pskb_may_pull(skb, *header_len + VLAN_HLEN)) 665 if (!pskb_may_pull(skb, *header_len + VLAN_HLEN))
616 return false; 666 return false;
617 ethhdr = (struct ethhdr *)(skb->data + VLAN_HLEN); 667
668 vhdr = (struct vlan_ethhdr *)skb->data;
669 proto = vhdr->h_vlan_encapsulated_proto;
618 *header_len += VLAN_HLEN; 670 *header_len += VLAN_HLEN;
619 } 671 }
620 672
621 /* check for ip header */ 673 /* check for ip header */
622 switch (ntohs(ethhdr->h_proto)) { 674 switch (proto) {
623 case ETH_P_IP: 675 case htons(ETH_P_IP):
624 if (!pskb_may_pull(skb, *header_len + sizeof(*iphdr))) 676 if (!pskb_may_pull(skb, *header_len + sizeof(*iphdr)))
625 return false; 677 return false;
626 iphdr = (struct iphdr *)(skb->data + *header_len); 678 iphdr = (struct iphdr *)(skb->data + *header_len);
@@ -631,7 +683,7 @@ bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len)
631 return false; 683 return false;
632 684
633 break; 685 break;
634 case ETH_P_IPV6: 686 case htons(ETH_P_IPV6):
635 if (!pskb_may_pull(skb, *header_len + sizeof(*ipv6hdr))) 687 if (!pskb_may_pull(skb, *header_len + sizeof(*ipv6hdr)))
636 return false; 688 return false;
637 ipv6hdr = (struct ipv6hdr *)(skb->data + *header_len); 689 ipv6hdr = (struct ipv6hdr *)(skb->data + *header_len);
@@ -658,28 +710,44 @@ bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len)
658 *header_len += sizeof(*udphdr); 710 *header_len += sizeof(*udphdr);
659 711
660 /* check for bootp port */ 712 /* check for bootp port */
661 if ((ntohs(ethhdr->h_proto) == ETH_P_IP) && 713 if ((proto == htons(ETH_P_IP)) &&
662 (ntohs(udphdr->dest) != 67)) 714 (udphdr->dest != htons(67)))
663 return false; 715 return false;
664 716
665 if ((ntohs(ethhdr->h_proto) == ETH_P_IPV6) && 717 if ((proto == htons(ETH_P_IPV6)) &&
666 (ntohs(udphdr->dest) != 547)) 718 (udphdr->dest != htons(547)))
667 return false; 719 return false;
668 720
669 return true; 721 return true;
670} 722}
671 723
672/* this call might reallocate skb data */ 724/**
725 * batadv_gw_out_of_range - check if the dhcp request destination is the best gw
726 * @bat_priv: the bat priv with all the soft interface information
727 * @skb: the outgoing packet
728 *
729 * Check if the skb is a DHCP request and if it is sent to the current best GW
730 * server. Due to topology changes it may be the case that the GW server
731 * previously selected is not the best one anymore.
732 *
733 * Returns true if the packet destination is unicast and it is not the best gw,
734 * false otherwise.
735 *
736 * This call might reallocate skb data.
737 */
673bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, 738bool batadv_gw_out_of_range(struct batadv_priv *bat_priv,
674 struct sk_buff *skb) 739 struct sk_buff *skb)
675{ 740{
676 struct batadv_neigh_node *neigh_curr = NULL, *neigh_old = NULL; 741 struct batadv_neigh_node *neigh_curr = NULL, *neigh_old = NULL;
677 struct batadv_orig_node *orig_dst_node = NULL; 742 struct batadv_orig_node *orig_dst_node = NULL;
678 struct batadv_gw_node *curr_gw = NULL; 743 struct batadv_gw_node *gw_node = NULL, *curr_gw = NULL;
679 struct ethhdr *ethhdr; 744 struct ethhdr *ethhdr;
680 bool ret, out_of_range = false; 745 bool ret, out_of_range = false;
681 unsigned int header_len = 0; 746 unsigned int header_len = 0;
682 uint8_t curr_tq_avg; 747 uint8_t curr_tq_avg;
748 unsigned short vid;
749
750 vid = batadv_get_vid(skb, 0);
683 751
684 ret = batadv_gw_is_dhcp_target(skb, &header_len); 752 ret = batadv_gw_is_dhcp_target(skb, &header_len);
685 if (!ret) 753 if (!ret)
@@ -687,11 +755,12 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv,
687 755
688 ethhdr = (struct ethhdr *)skb->data; 756 ethhdr = (struct ethhdr *)skb->data;
689 orig_dst_node = batadv_transtable_search(bat_priv, ethhdr->h_source, 757 orig_dst_node = batadv_transtable_search(bat_priv, ethhdr->h_source,
690 ethhdr->h_dest); 758 ethhdr->h_dest, vid);
691 if (!orig_dst_node) 759 if (!orig_dst_node)
692 goto out; 760 goto out;
693 761
694 if (!orig_dst_node->gw_flags) 762 gw_node = batadv_gw_node_get(bat_priv, orig_dst_node);
763 if (!gw_node->bandwidth_down == 0)
695 goto out; 764 goto out;
696 765
697 ret = batadv_is_type_dhcprequest(skb, header_len); 766 ret = batadv_is_type_dhcprequest(skb, header_len);
@@ -742,6 +811,8 @@ out:
742 batadv_orig_node_free_ref(orig_dst_node); 811 batadv_orig_node_free_ref(orig_dst_node);
743 if (curr_gw) 812 if (curr_gw)
744 batadv_gw_node_free_ref(curr_gw); 813 batadv_gw_node_free_ref(curr_gw);
814 if (gw_node)
815 batadv_gw_node_free_ref(gw_node);
745 if (neigh_old) 816 if (neigh_old)
746 batadv_neigh_node_free_ref(neigh_old); 817 batadv_neigh_node_free_ref(neigh_old);
747 if (neigh_curr) 818 if (neigh_curr)