diff options
Diffstat (limited to 'net/batman-adv/translation-table.c')
-rw-r--r-- | net/batman-adv/translation-table.c | 206 |
1 files changed, 176 insertions, 30 deletions
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index fb6931d00cd7..873fb3d8e56f 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c | |||
@@ -183,7 +183,8 @@ static int tt_local_init(struct bat_priv *bat_priv) | |||
183 | return 1; | 183 | return 1; |
184 | } | 184 | } |
185 | 185 | ||
186 | void tt_local_add(struct net_device *soft_iface, const uint8_t *addr) | 186 | void tt_local_add(struct net_device *soft_iface, const uint8_t *addr, |
187 | int ifindex) | ||
187 | { | 188 | { |
188 | struct bat_priv *bat_priv = netdev_priv(soft_iface); | 189 | struct bat_priv *bat_priv = netdev_priv(soft_iface); |
189 | struct tt_local_entry *tt_local_entry = NULL; | 190 | struct tt_local_entry *tt_local_entry = NULL; |
@@ -207,6 +208,8 @@ void tt_local_add(struct net_device *soft_iface, const uint8_t *addr) | |||
207 | memcpy(tt_local_entry->addr, addr, ETH_ALEN); | 208 | memcpy(tt_local_entry->addr, addr, ETH_ALEN); |
208 | tt_local_entry->last_seen = jiffies; | 209 | tt_local_entry->last_seen = jiffies; |
209 | tt_local_entry->flags = NO_FLAGS; | 210 | tt_local_entry->flags = NO_FLAGS; |
211 | if (is_wifi_iface(ifindex)) | ||
212 | tt_local_entry->flags |= TT_CLIENT_WIFI; | ||
210 | atomic_set(&tt_local_entry->refcount, 2); | 213 | atomic_set(&tt_local_entry->refcount, 2); |
211 | 214 | ||
212 | /* the batman interface mac address should never be purged */ | 215 | /* the batman interface mac address should never be purged */ |
@@ -329,7 +332,7 @@ int tt_local_seq_print_text(struct seq_file *seq, void *offset) | |||
329 | 332 | ||
330 | rcu_read_lock(); | 333 | rcu_read_lock(); |
331 | __hlist_for_each_rcu(node, head) | 334 | __hlist_for_each_rcu(node, head) |
332 | buf_size += 21; | 335 | buf_size += 29; |
333 | rcu_read_unlock(); | 336 | rcu_read_unlock(); |
334 | } | 337 | } |
335 | 338 | ||
@@ -348,8 +351,19 @@ int tt_local_seq_print_text(struct seq_file *seq, void *offset) | |||
348 | rcu_read_lock(); | 351 | rcu_read_lock(); |
349 | hlist_for_each_entry_rcu(tt_local_entry, node, | 352 | hlist_for_each_entry_rcu(tt_local_entry, node, |
350 | head, hash_entry) { | 353 | head, hash_entry) { |
351 | pos += snprintf(buff + pos, 22, " * %pM\n", | 354 | pos += snprintf(buff + pos, 30, " * %pM " |
352 | tt_local_entry->addr); | 355 | "[%c%c%c%c%c]\n", |
356 | tt_local_entry->addr, | ||
357 | (tt_local_entry->flags & | ||
358 | TT_CLIENT_ROAM ? 'R' : '.'), | ||
359 | (tt_local_entry->flags & | ||
360 | TT_CLIENT_NOPURGE ? 'P' : '.'), | ||
361 | (tt_local_entry->flags & | ||
362 | TT_CLIENT_NEW ? 'N' : '.'), | ||
363 | (tt_local_entry->flags & | ||
364 | TT_CLIENT_PENDING ? 'X' : '.'), | ||
365 | (tt_local_entry->flags & | ||
366 | TT_CLIENT_WIFI ? 'W' : '.')); | ||
353 | } | 367 | } |
354 | rcu_read_unlock(); | 368 | rcu_read_unlock(); |
355 | } | 369 | } |
@@ -369,8 +383,8 @@ static void tt_local_set_pending(struct bat_priv *bat_priv, | |||
369 | tt_local_event(bat_priv, tt_local_entry->addr, | 383 | tt_local_event(bat_priv, tt_local_entry->addr, |
370 | tt_local_entry->flags | flags); | 384 | tt_local_entry->flags | flags); |
371 | 385 | ||
372 | /* The local client has to be merked as "pending to be removed" but has | 386 | /* The local client has to be marked as "pending to be removed" but has |
373 | * to be kept in the table in order to send it in an full tables | 387 | * to be kept in the table in order to send it in a full table |
374 | * response issued before the net ttvn increment (consistency check) */ | 388 | * response issued before the net ttvn increment (consistency check) */ |
375 | tt_local_entry->flags |= TT_CLIENT_PENDING; | 389 | tt_local_entry->flags |= TT_CLIENT_PENDING; |
376 | } | 390 | } |
@@ -495,7 +509,8 @@ static void tt_changes_list_free(struct bat_priv *bat_priv) | |||
495 | 509 | ||
496 | /* caller must hold orig_node refcount */ | 510 | /* caller must hold orig_node refcount */ |
497 | int tt_global_add(struct bat_priv *bat_priv, struct orig_node *orig_node, | 511 | int tt_global_add(struct bat_priv *bat_priv, struct orig_node *orig_node, |
498 | const unsigned char *tt_addr, uint8_t ttvn, bool roaming) | 512 | const unsigned char *tt_addr, uint8_t ttvn, bool roaming, |
513 | bool wifi) | ||
499 | { | 514 | { |
500 | struct tt_global_entry *tt_global_entry; | 515 | struct tt_global_entry *tt_global_entry; |
501 | struct orig_node *orig_node_tmp; | 516 | struct orig_node *orig_node_tmp; |
@@ -537,6 +552,9 @@ int tt_global_add(struct bat_priv *bat_priv, struct orig_node *orig_node, | |||
537 | tt_global_entry->roam_at = 0; | 552 | tt_global_entry->roam_at = 0; |
538 | } | 553 | } |
539 | 554 | ||
555 | if (wifi) | ||
556 | tt_global_entry->flags |= TT_CLIENT_WIFI; | ||
557 | |||
540 | bat_dbg(DBG_TT, bat_priv, | 558 | bat_dbg(DBG_TT, bat_priv, |
541 | "Creating new global tt entry: %pM (via %pM)\n", | 559 | "Creating new global tt entry: %pM (via %pM)\n", |
542 | tt_global_entry->addr, orig_node->orig); | 560 | tt_global_entry->addr, orig_node->orig); |
@@ -582,8 +600,8 @@ int tt_global_seq_print_text(struct seq_file *seq, void *offset) | |||
582 | seq_printf(seq, | 600 | seq_printf(seq, |
583 | "Globally announced TT entries received via the mesh %s\n", | 601 | "Globally announced TT entries received via the mesh %s\n", |
584 | net_dev->name); | 602 | net_dev->name); |
585 | seq_printf(seq, " %-13s %s %-15s %s\n", | 603 | seq_printf(seq, " %-13s %s %-15s %s %s\n", |
586 | "Client", "(TTVN)", "Originator", "(Curr TTVN)"); | 604 | "Client", "(TTVN)", "Originator", "(Curr TTVN)", "Flags"); |
587 | 605 | ||
588 | buf_size = 1; | 606 | buf_size = 1; |
589 | /* Estimate length for: " * xx:xx:xx:xx:xx:xx (ttvn) via | 607 | /* Estimate length for: " * xx:xx:xx:xx:xx:xx (ttvn) via |
@@ -593,7 +611,7 @@ int tt_global_seq_print_text(struct seq_file *seq, void *offset) | |||
593 | 611 | ||
594 | rcu_read_lock(); | 612 | rcu_read_lock(); |
595 | __hlist_for_each_rcu(node, head) | 613 | __hlist_for_each_rcu(node, head) |
596 | buf_size += 59; | 614 | buf_size += 67; |
597 | rcu_read_unlock(); | 615 | rcu_read_unlock(); |
598 | } | 616 | } |
599 | 617 | ||
@@ -612,14 +630,20 @@ int tt_global_seq_print_text(struct seq_file *seq, void *offset) | |||
612 | rcu_read_lock(); | 630 | rcu_read_lock(); |
613 | hlist_for_each_entry_rcu(tt_global_entry, node, | 631 | hlist_for_each_entry_rcu(tt_global_entry, node, |
614 | head, hash_entry) { | 632 | head, hash_entry) { |
615 | pos += snprintf(buff + pos, 61, | 633 | pos += snprintf(buff + pos, 69, |
616 | " * %pM (%3u) via %pM (%3u)\n", | 634 | " * %pM (%3u) via %pM (%3u) " |
617 | tt_global_entry->addr, | 635 | "[%c%c%c]\n", tt_global_entry->addr, |
618 | tt_global_entry->ttvn, | 636 | tt_global_entry->ttvn, |
619 | tt_global_entry->orig_node->orig, | 637 | tt_global_entry->orig_node->orig, |
620 | (uint8_t) atomic_read( | 638 | (uint8_t) atomic_read( |
621 | &tt_global_entry->orig_node-> | 639 | &tt_global_entry->orig_node-> |
622 | last_ttvn)); | 640 | last_ttvn), |
641 | (tt_global_entry->flags & | ||
642 | TT_CLIENT_ROAM ? 'R' : '.'), | ||
643 | (tt_global_entry->flags & | ||
644 | TT_CLIENT_PENDING ? 'X' : '.'), | ||
645 | (tt_global_entry->flags & | ||
646 | TT_CLIENT_WIFI ? 'W' : '.')); | ||
623 | } | 647 | } |
624 | rcu_read_unlock(); | 648 | rcu_read_unlock(); |
625 | } | 649 | } |
@@ -774,30 +798,56 @@ static void tt_global_table_free(struct bat_priv *bat_priv) | |||
774 | bat_priv->tt_global_hash = NULL; | 798 | bat_priv->tt_global_hash = NULL; |
775 | } | 799 | } |
776 | 800 | ||
801 | static bool _is_ap_isolated(struct tt_local_entry *tt_local_entry, | ||
802 | struct tt_global_entry *tt_global_entry) | ||
803 | { | ||
804 | bool ret = false; | ||
805 | |||
806 | if (tt_local_entry->flags & TT_CLIENT_WIFI && | ||
807 | tt_global_entry->flags & TT_CLIENT_WIFI) | ||
808 | ret = true; | ||
809 | |||
810 | return ret; | ||
811 | } | ||
812 | |||
777 | struct orig_node *transtable_search(struct bat_priv *bat_priv, | 813 | struct orig_node *transtable_search(struct bat_priv *bat_priv, |
778 | const uint8_t *addr) | 814 | const uint8_t *src, const uint8_t *addr) |
779 | { | 815 | { |
780 | struct tt_global_entry *tt_global_entry; | 816 | struct tt_local_entry *tt_local_entry = NULL; |
817 | struct tt_global_entry *tt_global_entry = NULL; | ||
781 | struct orig_node *orig_node = NULL; | 818 | struct orig_node *orig_node = NULL; |
782 | 819 | ||
783 | tt_global_entry = tt_global_hash_find(bat_priv, addr); | 820 | if (src && atomic_read(&bat_priv->ap_isolation)) { |
821 | tt_local_entry = tt_local_hash_find(bat_priv, src); | ||
822 | if (!tt_local_entry) | ||
823 | goto out; | ||
824 | } | ||
784 | 825 | ||
826 | tt_global_entry = tt_global_hash_find(bat_priv, addr); | ||
785 | if (!tt_global_entry) | 827 | if (!tt_global_entry) |
786 | goto out; | 828 | goto out; |
787 | 829 | ||
830 | /* check whether the clients should not communicate due to AP | ||
831 | * isolation */ | ||
832 | if (tt_local_entry && _is_ap_isolated(tt_local_entry, tt_global_entry)) | ||
833 | goto out; | ||
834 | |||
788 | if (!atomic_inc_not_zero(&tt_global_entry->orig_node->refcount)) | 835 | if (!atomic_inc_not_zero(&tt_global_entry->orig_node->refcount)) |
789 | goto free_tt; | 836 | goto out; |
790 | 837 | ||
791 | /* A global client marked as PENDING has already moved from that | 838 | /* A global client marked as PENDING has already moved from that |
792 | * originator */ | 839 | * originator */ |
793 | if (tt_global_entry->flags & TT_CLIENT_PENDING) | 840 | if (tt_global_entry->flags & TT_CLIENT_PENDING) |
794 | goto free_tt; | 841 | goto out; |
795 | 842 | ||
796 | orig_node = tt_global_entry->orig_node; | 843 | orig_node = tt_global_entry->orig_node; |
797 | 844 | ||
798 | free_tt: | ||
799 | tt_global_entry_free_ref(tt_global_entry); | ||
800 | out: | 845 | out: |
846 | if (tt_global_entry) | ||
847 | tt_global_entry_free_ref(tt_global_entry); | ||
848 | if (tt_local_entry) | ||
849 | tt_local_entry_free_ref(tt_local_entry); | ||
850 | |||
801 | return orig_node; | 851 | return orig_node; |
802 | } | 852 | } |
803 | 853 | ||
@@ -999,7 +1049,6 @@ static struct sk_buff *tt_response_fill_table(uint16_t tt_len, uint8_t ttvn, | |||
999 | tt_response = (struct tt_query_packet *)skb_put(skb, | 1049 | tt_response = (struct tt_query_packet *)skb_put(skb, |
1000 | tt_query_size + tt_len); | 1050 | tt_query_size + tt_len); |
1001 | tt_response->ttvn = ttvn; | 1051 | tt_response->ttvn = ttvn; |
1002 | tt_response->tt_data = htons(tt_tot); | ||
1003 | 1052 | ||
1004 | tt_change = (struct tt_change *)(skb->data + tt_query_size); | 1053 | tt_change = (struct tt_change *)(skb->data + tt_query_size); |
1005 | tt_count = 0; | 1054 | tt_count = 0; |
@@ -1025,12 +1074,17 @@ static struct sk_buff *tt_response_fill_table(uint16_t tt_len, uint8_t ttvn, | |||
1025 | } | 1074 | } |
1026 | rcu_read_unlock(); | 1075 | rcu_read_unlock(); |
1027 | 1076 | ||
1077 | /* store in the message the number of entries we have successfully | ||
1078 | * copied */ | ||
1079 | tt_response->tt_data = htons(tt_count); | ||
1080 | |||
1028 | out: | 1081 | out: |
1029 | return skb; | 1082 | return skb; |
1030 | } | 1083 | } |
1031 | 1084 | ||
1032 | int send_tt_request(struct bat_priv *bat_priv, struct orig_node *dst_orig_node, | 1085 | static int send_tt_request(struct bat_priv *bat_priv, |
1033 | uint8_t ttvn, uint16_t tt_crc, bool full_table) | 1086 | struct orig_node *dst_orig_node, |
1087 | uint8_t ttvn, uint16_t tt_crc, bool full_table) | ||
1034 | { | 1088 | { |
1035 | struct sk_buff *skb = NULL; | 1089 | struct sk_buff *skb = NULL; |
1036 | struct tt_query_packet *tt_request; | 1090 | struct tt_query_packet *tt_request; |
@@ -1137,12 +1191,12 @@ static bool send_other_tt_response(struct bat_priv *bat_priv, | |||
1137 | orig_ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn); | 1191 | orig_ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn); |
1138 | req_ttvn = tt_request->ttvn; | 1192 | req_ttvn = tt_request->ttvn; |
1139 | 1193 | ||
1140 | /* I have not the requested data */ | 1194 | /* I don't have the requested data */ |
1141 | if (orig_ttvn != req_ttvn || | 1195 | if (orig_ttvn != req_ttvn || |
1142 | tt_request->tt_data != req_dst_orig_node->tt_crc) | 1196 | tt_request->tt_data != req_dst_orig_node->tt_crc) |
1143 | goto out; | 1197 | goto out; |
1144 | 1198 | ||
1145 | /* If it has explicitly been requested the full table */ | 1199 | /* If the full table has been explicitly requested */ |
1146 | if (tt_request->flags & TT_FULL_TABLE || | 1200 | if (tt_request->flags & TT_FULL_TABLE || |
1147 | !req_dst_orig_node->tt_buff) | 1201 | !req_dst_orig_node->tt_buff) |
1148 | full_table = true; | 1202 | full_table = true; |
@@ -1363,7 +1417,9 @@ static void _tt_update_changes(struct bat_priv *bat_priv, | |||
1363 | (tt_change + i)->flags & TT_CLIENT_ROAM); | 1417 | (tt_change + i)->flags & TT_CLIENT_ROAM); |
1364 | else | 1418 | else |
1365 | if (!tt_global_add(bat_priv, orig_node, | 1419 | if (!tt_global_add(bat_priv, orig_node, |
1366 | (tt_change + i)->addr, ttvn, false)) | 1420 | (tt_change + i)->addr, ttvn, false, |
1421 | (tt_change + i)->flags & | ||
1422 | TT_CLIENT_WIFI)) | ||
1367 | /* In case of problem while storing a | 1423 | /* In case of problem while storing a |
1368 | * global_entry, we stop the updating | 1424 | * global_entry, we stop the updating |
1369 | * procedure without committing the | 1425 | * procedure without committing the |
@@ -1403,9 +1459,10 @@ out: | |||
1403 | orig_node_free_ref(orig_node); | 1459 | orig_node_free_ref(orig_node); |
1404 | } | 1460 | } |
1405 | 1461 | ||
1406 | void tt_update_changes(struct bat_priv *bat_priv, struct orig_node *orig_node, | 1462 | static void tt_update_changes(struct bat_priv *bat_priv, |
1407 | uint16_t tt_num_changes, uint8_t ttvn, | 1463 | struct orig_node *orig_node, |
1408 | struct tt_change *tt_change) | 1464 | uint16_t tt_num_changes, uint8_t ttvn, |
1465 | struct tt_change *tt_change) | ||
1409 | { | 1466 | { |
1410 | _tt_update_changes(bat_priv, orig_node, tt_change, tt_num_changes, | 1467 | _tt_update_changes(bat_priv, orig_node, tt_change, tt_num_changes, |
1411 | ttvn); | 1468 | ttvn); |
@@ -1668,6 +1725,8 @@ static void tt_local_reset_flags(struct bat_priv *bat_priv, uint16_t flags) | |||
1668 | rcu_read_lock(); | 1725 | rcu_read_lock(); |
1669 | hlist_for_each_entry_rcu(tt_local_entry, node, | 1726 | hlist_for_each_entry_rcu(tt_local_entry, node, |
1670 | head, hash_entry) { | 1727 | head, hash_entry) { |
1728 | if (!(tt_local_entry->flags & flags)) | ||
1729 | continue; | ||
1671 | tt_local_entry->flags &= ~flags; | 1730 | tt_local_entry->flags &= ~flags; |
1672 | atomic_inc(&bat_priv->num_local_tt); | 1731 | atomic_inc(&bat_priv->num_local_tt); |
1673 | } | 1732 | } |
@@ -1720,3 +1779,90 @@ void tt_commit_changes(struct bat_priv *bat_priv) | |||
1720 | atomic_inc(&bat_priv->ttvn); | 1779 | atomic_inc(&bat_priv->ttvn); |
1721 | bat_priv->tt_poss_change = false; | 1780 | bat_priv->tt_poss_change = false; |
1722 | } | 1781 | } |
1782 | |||
1783 | bool is_ap_isolated(struct bat_priv *bat_priv, uint8_t *src, uint8_t *dst) | ||
1784 | { | ||
1785 | struct tt_local_entry *tt_local_entry = NULL; | ||
1786 | struct tt_global_entry *tt_global_entry = NULL; | ||
1787 | bool ret = true; | ||
1788 | |||
1789 | if (!atomic_read(&bat_priv->ap_isolation)) | ||
1790 | return false; | ||
1791 | |||
1792 | tt_local_entry = tt_local_hash_find(bat_priv, dst); | ||
1793 | if (!tt_local_entry) | ||
1794 | goto out; | ||
1795 | |||
1796 | tt_global_entry = tt_global_hash_find(bat_priv, src); | ||
1797 | if (!tt_global_entry) | ||
1798 | goto out; | ||
1799 | |||
1800 | if (_is_ap_isolated(tt_local_entry, tt_global_entry)) | ||
1801 | goto out; | ||
1802 | |||
1803 | ret = false; | ||
1804 | |||
1805 | out: | ||
1806 | if (tt_global_entry) | ||
1807 | tt_global_entry_free_ref(tt_global_entry); | ||
1808 | if (tt_local_entry) | ||
1809 | tt_local_entry_free_ref(tt_local_entry); | ||
1810 | return ret; | ||
1811 | } | ||
1812 | |||
1813 | void tt_update_orig(struct bat_priv *bat_priv, struct orig_node *orig_node, | ||
1814 | const unsigned char *tt_buff, uint8_t tt_num_changes, | ||
1815 | uint8_t ttvn, uint16_t tt_crc) | ||
1816 | { | ||
1817 | uint8_t orig_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn); | ||
1818 | bool full_table = true; | ||
1819 | |||
1820 | /* the ttvn increased by one -> we can apply the attached changes */ | ||
1821 | if (ttvn - orig_ttvn == 1) { | ||
1822 | /* the OGM could not contain the changes due to their size or | ||
1823 | * because they have already been sent TT_OGM_APPEND_MAX times. | ||
1824 | * In this case send a tt request */ | ||
1825 | if (!tt_num_changes) { | ||
1826 | full_table = false; | ||
1827 | goto request_table; | ||
1828 | } | ||
1829 | |||
1830 | tt_update_changes(bat_priv, orig_node, tt_num_changes, ttvn, | ||
1831 | (struct tt_change *)tt_buff); | ||
1832 | |||
1833 | /* Even if we received the precomputed crc with the OGM, we | ||
1834 | * prefer to recompute it to spot any possible inconsistency | ||
1835 | * in the global table */ | ||
1836 | orig_node->tt_crc = tt_global_crc(bat_priv, orig_node); | ||
1837 | |||
1838 | /* The ttvn alone is not enough to guarantee consistency | ||
1839 | * because a single value could represent different states | ||
1840 | * (due to the wrap around). Thus a node has to check whether | ||
1841 | * the resulting table (after applying the changes) is still | ||
1842 | * consistent or not. E.g. a node could disconnect while its | ||
1843 | * ttvn is X and reconnect on ttvn = X + TTVN_MAX: in this case | ||
1844 | * checking the CRC value is mandatory to detect the | ||
1845 | * inconsistency */ | ||
1846 | if (orig_node->tt_crc != tt_crc) | ||
1847 | goto request_table; | ||
1848 | |||
1849 | /* Roaming phase is over: tables are in sync again. I can | ||
1850 | * unset the flag */ | ||
1851 | orig_node->tt_poss_change = false; | ||
1852 | } else { | ||
1853 | /* if we missed more than one change or our tables are not | ||
1854 | * in sync anymore -> request fresh tt data */ | ||
1855 | if (ttvn != orig_ttvn || orig_node->tt_crc != tt_crc) { | ||
1856 | request_table: | ||
1857 | bat_dbg(DBG_TT, bat_priv, "TT inconsistency for %pM. " | ||
1858 | "Need to retrieve the correct information " | ||
1859 | "(ttvn: %u last_ttvn: %u crc: %u last_crc: " | ||
1860 | "%u num_changes: %u)\n", orig_node->orig, ttvn, | ||
1861 | orig_ttvn, tt_crc, orig_node->tt_crc, | ||
1862 | tt_num_changes); | ||
1863 | send_tt_request(bat_priv, orig_node, ttvn, tt_crc, | ||
1864 | full_table); | ||
1865 | return; | ||
1866 | } | ||
1867 | } | ||
1868 | } | ||