diff options
Diffstat (limited to 'net/batman-adv')
37 files changed, 4696 insertions, 3183 deletions
diff --git a/net/batman-adv/Makefile b/net/batman-adv/Makefile index 489bb36f1b94..4f4aabbd8eab 100644 --- a/net/batman-adv/Makefile +++ b/net/batman-adv/Makefile | |||
@@ -24,6 +24,7 @@ batman-adv-y += bitarray.o | |||
24 | batman-adv-$(CONFIG_BATMAN_ADV_BLA) += bridge_loop_avoidance.o | 24 | batman-adv-$(CONFIG_BATMAN_ADV_BLA) += bridge_loop_avoidance.o |
25 | batman-adv-y += debugfs.o | 25 | batman-adv-y += debugfs.o |
26 | batman-adv-$(CONFIG_BATMAN_ADV_DAT) += distributed-arp-table.o | 26 | batman-adv-$(CONFIG_BATMAN_ADV_DAT) += distributed-arp-table.o |
27 | batman-adv-y += fragmentation.o | ||
27 | batman-adv-y += gateway_client.o | 28 | batman-adv-y += gateway_client.o |
28 | batman-adv-y += gateway_common.o | 29 | batman-adv-y += gateway_common.o |
29 | batman-adv-y += hard-interface.o | 30 | batman-adv-y += hard-interface.o |
@@ -37,5 +38,3 @@ batman-adv-y += send.o | |||
37 | batman-adv-y += soft-interface.o | 38 | batman-adv-y += soft-interface.o |
38 | batman-adv-y += sysfs.o | 39 | batman-adv-y += sysfs.o |
39 | batman-adv-y += translation-table.o | 40 | batman-adv-y += translation-table.o |
40 | batman-adv-y += unicast.o | ||
41 | batman-adv-y += vis.o | ||
diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c index 0a8a80cd4bf1..97b42d3c4bef 100644 --- a/net/batman-adv/bat_iv_ogm.c +++ b/net/batman-adv/bat_iv_ogm.c | |||
@@ -135,9 +135,8 @@ static int batadv_iv_ogm_iface_enable(struct batadv_hard_iface *hard_iface) | |||
135 | batadv_ogm_packet->header.version = BATADV_COMPAT_VERSION; | 135 | batadv_ogm_packet->header.version = BATADV_COMPAT_VERSION; |
136 | batadv_ogm_packet->header.ttl = 2; | 136 | batadv_ogm_packet->header.ttl = 2; |
137 | batadv_ogm_packet->flags = BATADV_NO_FLAGS; | 137 | batadv_ogm_packet->flags = BATADV_NO_FLAGS; |
138 | batadv_ogm_packet->reserved = 0; | ||
138 | batadv_ogm_packet->tq = BATADV_TQ_MAX_VALUE; | 139 | batadv_ogm_packet->tq = BATADV_TQ_MAX_VALUE; |
139 | batadv_ogm_packet->tt_num_changes = 0; | ||
140 | batadv_ogm_packet->ttvn = 0; | ||
141 | 140 | ||
142 | res = 0; | 141 | res = 0; |
143 | 142 | ||
@@ -207,12 +206,12 @@ static uint8_t batadv_hop_penalty(uint8_t tq, | |||
207 | 206 | ||
208 | /* is there another aggregated packet here? */ | 207 | /* is there another aggregated packet here? */ |
209 | static int batadv_iv_ogm_aggr_packet(int buff_pos, int packet_len, | 208 | static int batadv_iv_ogm_aggr_packet(int buff_pos, int packet_len, |
210 | int tt_num_changes) | 209 | __be16 tvlv_len) |
211 | { | 210 | { |
212 | int next_buff_pos = 0; | 211 | int next_buff_pos = 0; |
213 | 212 | ||
214 | next_buff_pos += buff_pos + BATADV_OGM_HLEN; | 213 | next_buff_pos += buff_pos + BATADV_OGM_HLEN; |
215 | next_buff_pos += batadv_tt_len(tt_num_changes); | 214 | next_buff_pos += ntohs(tvlv_len); |
216 | 215 | ||
217 | return (next_buff_pos <= packet_len) && | 216 | return (next_buff_pos <= packet_len) && |
218 | (next_buff_pos <= BATADV_MAX_AGGREGATION_BYTES); | 217 | (next_buff_pos <= BATADV_MAX_AGGREGATION_BYTES); |
@@ -240,7 +239,7 @@ static void batadv_iv_ogm_send_to_if(struct batadv_forw_packet *forw_packet, | |||
240 | 239 | ||
241 | /* adjust all flags and log packets */ | 240 | /* adjust all flags and log packets */ |
242 | while (batadv_iv_ogm_aggr_packet(buff_pos, forw_packet->packet_len, | 241 | while (batadv_iv_ogm_aggr_packet(buff_pos, forw_packet->packet_len, |
243 | batadv_ogm_packet->tt_num_changes)) { | 242 | batadv_ogm_packet->tvlv_len)) { |
244 | /* we might have aggregated direct link packets with an | 243 | /* we might have aggregated direct link packets with an |
245 | * ordinary base packet | 244 | * ordinary base packet |
246 | */ | 245 | */ |
@@ -256,18 +255,18 @@ static void batadv_iv_ogm_send_to_if(struct batadv_forw_packet *forw_packet, | |||
256 | fwd_str = "Sending own"; | 255 | fwd_str = "Sending own"; |
257 | 256 | ||
258 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, | 257 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, |
259 | "%s %spacket (originator %pM, seqno %u, TQ %d, TTL %d, IDF %s, ttvn %d) on interface %s [%pM]\n", | 258 | "%s %spacket (originator %pM, seqno %u, TQ %d, TTL %d, IDF %s) on interface %s [%pM]\n", |
260 | fwd_str, (packet_num > 0 ? "aggregated " : ""), | 259 | fwd_str, (packet_num > 0 ? "aggregated " : ""), |
261 | batadv_ogm_packet->orig, | 260 | batadv_ogm_packet->orig, |
262 | ntohl(batadv_ogm_packet->seqno), | 261 | ntohl(batadv_ogm_packet->seqno), |
263 | batadv_ogm_packet->tq, batadv_ogm_packet->header.ttl, | 262 | batadv_ogm_packet->tq, batadv_ogm_packet->header.ttl, |
264 | (batadv_ogm_packet->flags & BATADV_DIRECTLINK ? | 263 | (batadv_ogm_packet->flags & BATADV_DIRECTLINK ? |
265 | "on" : "off"), | 264 | "on" : "off"), |
266 | batadv_ogm_packet->ttvn, hard_iface->net_dev->name, | 265 | hard_iface->net_dev->name, |
267 | hard_iface->net_dev->dev_addr); | 266 | hard_iface->net_dev->dev_addr); |
268 | 267 | ||
269 | buff_pos += BATADV_OGM_HLEN; | 268 | buff_pos += BATADV_OGM_HLEN; |
270 | buff_pos += batadv_tt_len(batadv_ogm_packet->tt_num_changes); | 269 | buff_pos += ntohs(batadv_ogm_packet->tvlv_len); |
271 | packet_num++; | 270 | packet_num++; |
272 | packet_pos = forw_packet->skb->data + buff_pos; | 271 | packet_pos = forw_packet->skb->data + buff_pos; |
273 | batadv_ogm_packet = (struct batadv_ogm_packet *)packet_pos; | 272 | batadv_ogm_packet = (struct batadv_ogm_packet *)packet_pos; |
@@ -601,7 +600,7 @@ static void batadv_iv_ogm_forward(struct batadv_orig_node *orig_node, | |||
601 | struct batadv_hard_iface *if_incoming) | 600 | struct batadv_hard_iface *if_incoming) |
602 | { | 601 | { |
603 | struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface); | 602 | struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface); |
604 | uint8_t tt_num_changes; | 603 | uint16_t tvlv_len; |
605 | 604 | ||
606 | if (batadv_ogm_packet->header.ttl <= 1) { | 605 | if (batadv_ogm_packet->header.ttl <= 1) { |
607 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "ttl exceeded\n"); | 606 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "ttl exceeded\n"); |
@@ -621,7 +620,7 @@ static void batadv_iv_ogm_forward(struct batadv_orig_node *orig_node, | |||
621 | return; | 620 | return; |
622 | } | 621 | } |
623 | 622 | ||
624 | tt_num_changes = batadv_ogm_packet->tt_num_changes; | 623 | tvlv_len = ntohs(batadv_ogm_packet->tvlv_len); |
625 | 624 | ||
626 | batadv_ogm_packet->header.ttl--; | 625 | batadv_ogm_packet->header.ttl--; |
627 | memcpy(batadv_ogm_packet->prev_sender, ethhdr->h_source, ETH_ALEN); | 626 | memcpy(batadv_ogm_packet->prev_sender, ethhdr->h_source, ETH_ALEN); |
@@ -642,7 +641,7 @@ static void batadv_iv_ogm_forward(struct batadv_orig_node *orig_node, | |||
642 | batadv_ogm_packet->flags &= ~BATADV_DIRECTLINK; | 641 | batadv_ogm_packet->flags &= ~BATADV_DIRECTLINK; |
643 | 642 | ||
644 | batadv_iv_ogm_queue_add(bat_priv, (unsigned char *)batadv_ogm_packet, | 643 | batadv_iv_ogm_queue_add(bat_priv, (unsigned char *)batadv_ogm_packet, |
645 | BATADV_OGM_HLEN + batadv_tt_len(tt_num_changes), | 644 | BATADV_OGM_HLEN + tvlv_len, |
646 | if_incoming, 0, batadv_iv_ogm_fwd_send_time()); | 645 | if_incoming, 0, batadv_iv_ogm_fwd_send_time()); |
647 | } | 646 | } |
648 | 647 | ||
@@ -688,43 +687,29 @@ static void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface) | |||
688 | struct batadv_ogm_packet *batadv_ogm_packet; | 687 | struct batadv_ogm_packet *batadv_ogm_packet; |
689 | struct batadv_hard_iface *primary_if; | 688 | struct batadv_hard_iface *primary_if; |
690 | int *ogm_buff_len = &hard_iface->bat_iv.ogm_buff_len; | 689 | int *ogm_buff_len = &hard_iface->bat_iv.ogm_buff_len; |
691 | int vis_server, tt_num_changes = 0; | ||
692 | uint32_t seqno; | 690 | uint32_t seqno; |
693 | uint8_t bandwidth; | 691 | uint16_t tvlv_len = 0; |
694 | 692 | ||
695 | vis_server = atomic_read(&bat_priv->vis_mode); | ||
696 | primary_if = batadv_primary_if_get_selected(bat_priv); | 693 | primary_if = batadv_primary_if_get_selected(bat_priv); |
697 | 694 | ||
698 | if (hard_iface == primary_if) | 695 | if (hard_iface == primary_if) { |
699 | tt_num_changes = batadv_tt_append_diff(bat_priv, ogm_buff, | 696 | /* tt changes have to be committed before the tvlv data is |
700 | ogm_buff_len, | 697 | * appended as it may alter the tt tvlv container |
701 | BATADV_OGM_HLEN); | 698 | */ |
699 | batadv_tt_local_commit_changes(bat_priv); | ||
700 | tvlv_len = batadv_tvlv_container_ogm_append(bat_priv, ogm_buff, | ||
701 | ogm_buff_len, | ||
702 | BATADV_OGM_HLEN); | ||
703 | } | ||
702 | 704 | ||
703 | batadv_ogm_packet = (struct batadv_ogm_packet *)(*ogm_buff); | 705 | batadv_ogm_packet = (struct batadv_ogm_packet *)(*ogm_buff); |
706 | batadv_ogm_packet->tvlv_len = htons(tvlv_len); | ||
704 | 707 | ||
705 | /* change sequence number to network order */ | 708 | /* change sequence number to network order */ |
706 | seqno = (uint32_t)atomic_read(&hard_iface->bat_iv.ogm_seqno); | 709 | seqno = (uint32_t)atomic_read(&hard_iface->bat_iv.ogm_seqno); |
707 | batadv_ogm_packet->seqno = htonl(seqno); | 710 | batadv_ogm_packet->seqno = htonl(seqno); |
708 | atomic_inc(&hard_iface->bat_iv.ogm_seqno); | 711 | atomic_inc(&hard_iface->bat_iv.ogm_seqno); |
709 | 712 | ||
710 | batadv_ogm_packet->ttvn = atomic_read(&bat_priv->tt.vn); | ||
711 | batadv_ogm_packet->tt_crc = htons(bat_priv->tt.local_crc); | ||
712 | if (tt_num_changes >= 0) | ||
713 | batadv_ogm_packet->tt_num_changes = tt_num_changes; | ||
714 | |||
715 | if (vis_server == BATADV_VIS_TYPE_SERVER_SYNC) | ||
716 | batadv_ogm_packet->flags |= BATADV_VIS_SERVER; | ||
717 | else | ||
718 | batadv_ogm_packet->flags &= ~BATADV_VIS_SERVER; | ||
719 | |||
720 | if (hard_iface == primary_if && | ||
721 | atomic_read(&bat_priv->gw_mode) == BATADV_GW_MODE_SERVER) { | ||
722 | bandwidth = (uint8_t)atomic_read(&bat_priv->gw_bandwidth); | ||
723 | batadv_ogm_packet->gw_flags = bandwidth; | ||
724 | } else { | ||
725 | batadv_ogm_packet->gw_flags = BATADV_NO_FLAGS; | ||
726 | } | ||
727 | |||
728 | batadv_iv_ogm_slide_own_bcast_window(hard_iface); | 713 | batadv_iv_ogm_slide_own_bcast_window(hard_iface); |
729 | batadv_iv_ogm_queue_add(bat_priv, hard_iface->bat_iv.ogm_buff, | 714 | batadv_iv_ogm_queue_add(bat_priv, hard_iface->bat_iv.ogm_buff, |
730 | hard_iface->bat_iv.ogm_buff_len, hard_iface, 1, | 715 | hard_iface->bat_iv.ogm_buff_len, hard_iface, 1, |
@@ -798,7 +783,6 @@ batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv, | |||
798 | 783 | ||
799 | rcu_read_unlock(); | 784 | rcu_read_unlock(); |
800 | 785 | ||
801 | orig_node->flags = batadv_ogm_packet->flags; | ||
802 | neigh_node->last_seen = jiffies; | 786 | neigh_node->last_seen = jiffies; |
803 | 787 | ||
804 | spin_lock_bh(&neigh_node->lq_update_lock); | 788 | spin_lock_bh(&neigh_node->lq_update_lock); |
@@ -820,11 +804,11 @@ batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv, | |||
820 | */ | 804 | */ |
821 | router = batadv_orig_node_get_router(orig_node); | 805 | router = batadv_orig_node_get_router(orig_node); |
822 | if (router == neigh_node) | 806 | if (router == neigh_node) |
823 | goto update_tt; | 807 | goto out; |
824 | 808 | ||
825 | /* if this neighbor does not offer a better TQ we won't consider it */ | 809 | /* if this neighbor does not offer a better TQ we won't consider it */ |
826 | if (router && (router->tq_avg > neigh_node->tq_avg)) | 810 | if (router && (router->tq_avg > neigh_node->tq_avg)) |
827 | goto update_tt; | 811 | goto out; |
828 | 812 | ||
829 | /* if the TQ is the same and the link not more symmetric we | 813 | /* if the TQ is the same and the link not more symmetric we |
830 | * won't consider it either | 814 | * won't consider it either |
@@ -843,35 +827,10 @@ batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv, | |||
843 | spin_unlock_bh(&orig_node_tmp->ogm_cnt_lock); | 827 | spin_unlock_bh(&orig_node_tmp->ogm_cnt_lock); |
844 | 828 | ||
845 | if (sum_orig >= sum_neigh) | 829 | if (sum_orig >= sum_neigh) |
846 | goto update_tt; | 830 | goto out; |
847 | } | 831 | } |
848 | 832 | ||
849 | batadv_update_route(bat_priv, orig_node, neigh_node); | 833 | batadv_update_route(bat_priv, orig_node, neigh_node); |
850 | |||
851 | update_tt: | ||
852 | /* I have to check for transtable changes only if the OGM has been | ||
853 | * sent through a primary interface | ||
854 | */ | ||
855 | if (((batadv_ogm_packet->orig != ethhdr->h_source) && | ||
856 | (batadv_ogm_packet->header.ttl > 2)) || | ||
857 | (batadv_ogm_packet->flags & BATADV_PRIMARIES_FIRST_HOP)) | ||
858 | batadv_tt_update_orig(bat_priv, orig_node, tt_buff, | ||
859 | batadv_ogm_packet->tt_num_changes, | ||
860 | batadv_ogm_packet->ttvn, | ||
861 | ntohs(batadv_ogm_packet->tt_crc)); | ||
862 | |||
863 | if (orig_node->gw_flags != batadv_ogm_packet->gw_flags) | ||
864 | batadv_gw_node_update(bat_priv, orig_node, | ||
865 | batadv_ogm_packet->gw_flags); | ||
866 | |||
867 | orig_node->gw_flags = batadv_ogm_packet->gw_flags; | ||
868 | |||
869 | /* restart gateway selection if fast or late switching was enabled */ | ||
870 | if ((orig_node->gw_flags) && | ||
871 | (atomic_read(&bat_priv->gw_mode) == BATADV_GW_MODE_CLIENT) && | ||
872 | (atomic_read(&bat_priv->gw_sel_class) > 2)) | ||
873 | batadv_gw_check_election(bat_priv, orig_node); | ||
874 | |||
875 | goto out; | 834 | goto out; |
876 | 835 | ||
877 | unlock: | 836 | unlock: |
@@ -1122,13 +1081,11 @@ static void batadv_iv_ogm_process(const struct ethhdr *ethhdr, | |||
1122 | is_single_hop_neigh = true; | 1081 | is_single_hop_neigh = true; |
1123 | 1082 | ||
1124 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, | 1083 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, |
1125 | "Received BATMAN packet via NB: %pM, IF: %s [%pM] (from OG: %pM, via prev OG: %pM, seqno %u, ttvn %u, crc %#.4x, changes %u, tq %d, TTL %d, V %d, IDF %d)\n", | 1084 | "Received BATMAN packet via NB: %pM, IF: %s [%pM] (from OG: %pM, via prev OG: %pM, seqno %u, tq %d, TTL %d, V %d, IDF %d)\n", |
1126 | ethhdr->h_source, if_incoming->net_dev->name, | 1085 | ethhdr->h_source, if_incoming->net_dev->name, |
1127 | if_incoming->net_dev->dev_addr, batadv_ogm_packet->orig, | 1086 | if_incoming->net_dev->dev_addr, batadv_ogm_packet->orig, |
1128 | batadv_ogm_packet->prev_sender, | 1087 | batadv_ogm_packet->prev_sender, |
1129 | ntohl(batadv_ogm_packet->seqno), batadv_ogm_packet->ttvn, | 1088 | ntohl(batadv_ogm_packet->seqno), batadv_ogm_packet->tq, |
1130 | ntohs(batadv_ogm_packet->tt_crc), | ||
1131 | batadv_ogm_packet->tt_num_changes, batadv_ogm_packet->tq, | ||
1132 | batadv_ogm_packet->header.ttl, | 1089 | batadv_ogm_packet->header.ttl, |
1133 | batadv_ogm_packet->header.version, has_directlink_flag); | 1090 | batadv_ogm_packet->header.version, has_directlink_flag); |
1134 | 1091 | ||
@@ -1254,6 +1211,8 @@ static void batadv_iv_ogm_process(const struct ethhdr *ethhdr, | |||
1254 | goto out; | 1211 | goto out; |
1255 | } | 1212 | } |
1256 | 1213 | ||
1214 | batadv_tvlv_ogm_receive(bat_priv, batadv_ogm_packet, orig_node); | ||
1215 | |||
1257 | /* if sender is a direct neighbor the sender mac equals | 1216 | /* if sender is a direct neighbor the sender mac equals |
1258 | * originator mac | 1217 | * originator mac |
1259 | */ | 1218 | */ |
@@ -1350,9 +1309,9 @@ static int batadv_iv_ogm_receive(struct sk_buff *skb, | |||
1350 | struct batadv_ogm_packet *batadv_ogm_packet; | 1309 | struct batadv_ogm_packet *batadv_ogm_packet; |
1351 | struct ethhdr *ethhdr; | 1310 | struct ethhdr *ethhdr; |
1352 | int buff_pos = 0, packet_len; | 1311 | int buff_pos = 0, packet_len; |
1353 | unsigned char *tt_buff, *packet_buff; | 1312 | unsigned char *tvlv_buff, *packet_buff; |
1354 | bool ret; | ||
1355 | uint8_t *packet_pos; | 1313 | uint8_t *packet_pos; |
1314 | bool ret; | ||
1356 | 1315 | ||
1357 | ret = batadv_check_management_packet(skb, if_incoming, BATADV_OGM_HLEN); | 1316 | ret = batadv_check_management_packet(skb, if_incoming, BATADV_OGM_HLEN); |
1358 | if (!ret) | 1317 | if (!ret) |
@@ -1375,14 +1334,14 @@ static int batadv_iv_ogm_receive(struct sk_buff *skb, | |||
1375 | 1334 | ||
1376 | /* unpack the aggregated packets and process them one by one */ | 1335 | /* unpack the aggregated packets and process them one by one */ |
1377 | while (batadv_iv_ogm_aggr_packet(buff_pos, packet_len, | 1336 | while (batadv_iv_ogm_aggr_packet(buff_pos, packet_len, |
1378 | batadv_ogm_packet->tt_num_changes)) { | 1337 | batadv_ogm_packet->tvlv_len)) { |
1379 | tt_buff = packet_buff + buff_pos + BATADV_OGM_HLEN; | 1338 | tvlv_buff = packet_buff + buff_pos + BATADV_OGM_HLEN; |
1380 | 1339 | ||
1381 | batadv_iv_ogm_process(ethhdr, batadv_ogm_packet, tt_buff, | 1340 | batadv_iv_ogm_process(ethhdr, batadv_ogm_packet, |
1382 | if_incoming); | 1341 | tvlv_buff, if_incoming); |
1383 | 1342 | ||
1384 | buff_pos += BATADV_OGM_HLEN; | 1343 | buff_pos += BATADV_OGM_HLEN; |
1385 | buff_pos += batadv_tt_len(batadv_ogm_packet->tt_num_changes); | 1344 | buff_pos += ntohs(batadv_ogm_packet->tvlv_len); |
1386 | 1345 | ||
1387 | packet_pos = packet_buff + buff_pos; | 1346 | packet_pos = packet_buff + buff_pos; |
1388 | batadv_ogm_packet = (struct batadv_ogm_packet *)packet_pos; | 1347 | batadv_ogm_packet = (struct batadv_ogm_packet *)packet_pos; |
diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c index 264de88db320..28eb5e6d0a02 100644 --- a/net/batman-adv/bridge_loop_avoidance.c +++ b/net/batman-adv/bridge_loop_avoidance.c | |||
@@ -411,10 +411,10 @@ batadv_bla_get_backbone_gw(struct batadv_priv *bat_priv, uint8_t *orig, | |||
411 | return NULL; | 411 | return NULL; |
412 | } | 412 | } |
413 | 413 | ||
414 | /* this is a gateway now, remove any tt entries */ | 414 | /* this is a gateway now, remove any TT entry on this VLAN */ |
415 | orig_node = batadv_orig_hash_find(bat_priv, orig); | 415 | orig_node = batadv_orig_hash_find(bat_priv, orig); |
416 | if (orig_node) { | 416 | if (orig_node) { |
417 | batadv_tt_global_del_orig(bat_priv, orig_node, | 417 | batadv_tt_global_del_orig(bat_priv, orig_node, vid, |
418 | "became a backbone gateway"); | 418 | "became a backbone gateway"); |
419 | batadv_orig_node_free_ref(orig_node); | 419 | batadv_orig_node_free_ref(orig_node); |
420 | } | 420 | } |
@@ -858,30 +858,28 @@ static int batadv_bla_process_claim(struct batadv_priv *bat_priv, | |||
858 | struct batadv_hard_iface *primary_if, | 858 | struct batadv_hard_iface *primary_if, |
859 | struct sk_buff *skb) | 859 | struct sk_buff *skb) |
860 | { | 860 | { |
861 | struct ethhdr *ethhdr; | 861 | struct batadv_bla_claim_dst *bla_dst; |
862 | uint8_t *hw_src, *hw_dst; | ||
862 | struct vlan_ethhdr *vhdr; | 863 | struct vlan_ethhdr *vhdr; |
864 | struct ethhdr *ethhdr; | ||
863 | struct arphdr *arphdr; | 865 | struct arphdr *arphdr; |
864 | uint8_t *hw_src, *hw_dst; | 866 | unsigned short vid; |
865 | struct batadv_bla_claim_dst *bla_dst; | 867 | __be16 proto; |
866 | uint16_t proto; | ||
867 | int headlen; | 868 | int headlen; |
868 | unsigned short vid = BATADV_NO_FLAGS; | ||
869 | int ret; | 869 | int ret; |
870 | 870 | ||
871 | vid = batadv_get_vid(skb, 0); | ||
871 | ethhdr = eth_hdr(skb); | 872 | ethhdr = eth_hdr(skb); |
872 | 873 | ||
873 | if (ntohs(ethhdr->h_proto) == ETH_P_8021Q) { | 874 | proto = ethhdr->h_proto; |
875 | headlen = ETH_HLEN; | ||
876 | if (vid & BATADV_VLAN_HAS_TAG) { | ||
874 | vhdr = (struct vlan_ethhdr *)ethhdr; | 877 | vhdr = (struct vlan_ethhdr *)ethhdr; |
875 | vid = ntohs(vhdr->h_vlan_TCI) & VLAN_VID_MASK; | 878 | proto = vhdr->h_vlan_encapsulated_proto; |
876 | vid |= BATADV_VLAN_HAS_TAG; | 879 | headlen += VLAN_HLEN; |
877 | proto = ntohs(vhdr->h_vlan_encapsulated_proto); | ||
878 | headlen = sizeof(*vhdr); | ||
879 | } else { | ||
880 | proto = ntohs(ethhdr->h_proto); | ||
881 | headlen = ETH_HLEN; | ||
882 | } | 880 | } |
883 | 881 | ||
884 | if (proto != ETH_P_ARP) | 882 | if (proto != htons(ETH_P_ARP)) |
885 | return 0; /* not a claim frame */ | 883 | return 0; /* not a claim frame */ |
886 | 884 | ||
887 | /* this must be a ARP frame. check if it is a claim. */ | 885 | /* this must be a ARP frame. check if it is a claim. */ |
@@ -1317,12 +1315,14 @@ out: | |||
1317 | 1315 | ||
1318 | /* @bat_priv: the bat priv with all the soft interface information | 1316 | /* @bat_priv: the bat priv with all the soft interface information |
1319 | * @orig: originator mac address | 1317 | * @orig: originator mac address |
1318 | * @vid: VLAN identifier | ||
1320 | * | 1319 | * |
1321 | * check if the originator is a gateway for any VLAN ID. | 1320 | * Check if the originator is a gateway for the VLAN identified by vid. |
1322 | * | 1321 | * |
1323 | * returns 1 if it is found, 0 otherwise | 1322 | * Returns true if orig is a backbone for this vid, false otherwise. |
1324 | */ | 1323 | */ |
1325 | int batadv_bla_is_backbone_gw_orig(struct batadv_priv *bat_priv, uint8_t *orig) | 1324 | bool batadv_bla_is_backbone_gw_orig(struct batadv_priv *bat_priv, uint8_t *orig, |
1325 | unsigned short vid) | ||
1326 | { | 1326 | { |
1327 | struct batadv_hashtable *hash = bat_priv->bla.backbone_hash; | 1327 | struct batadv_hashtable *hash = bat_priv->bla.backbone_hash; |
1328 | struct hlist_head *head; | 1328 | struct hlist_head *head; |
@@ -1330,25 +1330,26 @@ int batadv_bla_is_backbone_gw_orig(struct batadv_priv *bat_priv, uint8_t *orig) | |||
1330 | int i; | 1330 | int i; |
1331 | 1331 | ||
1332 | if (!atomic_read(&bat_priv->bridge_loop_avoidance)) | 1332 | if (!atomic_read(&bat_priv->bridge_loop_avoidance)) |
1333 | return 0; | 1333 | return false; |
1334 | 1334 | ||
1335 | if (!hash) | 1335 | if (!hash) |
1336 | return 0; | 1336 | return false; |
1337 | 1337 | ||
1338 | for (i = 0; i < hash->size; i++) { | 1338 | for (i = 0; i < hash->size; i++) { |
1339 | head = &hash->table[i]; | 1339 | head = &hash->table[i]; |
1340 | 1340 | ||
1341 | rcu_read_lock(); | 1341 | rcu_read_lock(); |
1342 | hlist_for_each_entry_rcu(backbone_gw, head, hash_entry) { | 1342 | hlist_for_each_entry_rcu(backbone_gw, head, hash_entry) { |
1343 | if (batadv_compare_eth(backbone_gw->orig, orig)) { | 1343 | if (batadv_compare_eth(backbone_gw->orig, orig) && |
1344 | backbone_gw->vid == vid) { | ||
1344 | rcu_read_unlock(); | 1345 | rcu_read_unlock(); |
1345 | return 1; | 1346 | return true; |
1346 | } | 1347 | } |
1347 | } | 1348 | } |
1348 | rcu_read_unlock(); | 1349 | rcu_read_unlock(); |
1349 | } | 1350 | } |
1350 | 1351 | ||
1351 | return 0; | 1352 | return false; |
1352 | } | 1353 | } |
1353 | 1354 | ||
1354 | 1355 | ||
@@ -1365,10 +1366,8 @@ int batadv_bla_is_backbone_gw_orig(struct batadv_priv *bat_priv, uint8_t *orig) | |||
1365 | int batadv_bla_is_backbone_gw(struct sk_buff *skb, | 1366 | int batadv_bla_is_backbone_gw(struct sk_buff *skb, |
1366 | struct batadv_orig_node *orig_node, int hdr_size) | 1367 | struct batadv_orig_node *orig_node, int hdr_size) |
1367 | { | 1368 | { |
1368 | struct ethhdr *ethhdr; | ||
1369 | struct vlan_ethhdr *vhdr; | ||
1370 | struct batadv_bla_backbone_gw *backbone_gw; | 1369 | struct batadv_bla_backbone_gw *backbone_gw; |
1371 | unsigned short vid = BATADV_NO_FLAGS; | 1370 | unsigned short vid; |
1372 | 1371 | ||
1373 | if (!atomic_read(&orig_node->bat_priv->bridge_loop_avoidance)) | 1372 | if (!atomic_read(&orig_node->bat_priv->bridge_loop_avoidance)) |
1374 | return 0; | 1373 | return 0; |
@@ -1377,16 +1376,7 @@ int batadv_bla_is_backbone_gw(struct sk_buff *skb, | |||
1377 | if (!pskb_may_pull(skb, hdr_size + ETH_HLEN)) | 1376 | if (!pskb_may_pull(skb, hdr_size + ETH_HLEN)) |
1378 | return 0; | 1377 | return 0; |
1379 | 1378 | ||
1380 | ethhdr = (struct ethhdr *)(((uint8_t *)skb->data) + hdr_size); | 1379 | vid = batadv_get_vid(skb, hdr_size); |
1381 | |||
1382 | if (ntohs(ethhdr->h_proto) == ETH_P_8021Q) { | ||
1383 | if (!pskb_may_pull(skb, hdr_size + sizeof(struct vlan_ethhdr))) | ||
1384 | return 0; | ||
1385 | |||
1386 | vhdr = (struct vlan_ethhdr *)(skb->data + hdr_size); | ||
1387 | vid = ntohs(vhdr->h_vlan_TCI) & VLAN_VID_MASK; | ||
1388 | vid |= BATADV_VLAN_HAS_TAG; | ||
1389 | } | ||
1390 | 1380 | ||
1391 | /* see if this originator is a backbone gw for this VLAN */ | 1381 | /* see if this originator is a backbone gw for this VLAN */ |
1392 | backbone_gw = batadv_backbone_hash_find(orig_node->bat_priv, | 1382 | backbone_gw = batadv_backbone_hash_find(orig_node->bat_priv, |
diff --git a/net/batman-adv/bridge_loop_avoidance.h b/net/batman-adv/bridge_loop_avoidance.h index 4b102e71e5bd..da173e760e77 100644 --- a/net/batman-adv/bridge_loop_avoidance.h +++ b/net/batman-adv/bridge_loop_avoidance.h | |||
@@ -30,7 +30,8 @@ int batadv_bla_is_backbone_gw(struct sk_buff *skb, | |||
30 | int batadv_bla_claim_table_seq_print_text(struct seq_file *seq, void *offset); | 30 | int batadv_bla_claim_table_seq_print_text(struct seq_file *seq, void *offset); |
31 | int batadv_bla_backbone_table_seq_print_text(struct seq_file *seq, | 31 | int batadv_bla_backbone_table_seq_print_text(struct seq_file *seq, |
32 | void *offset); | 32 | void *offset); |
33 | int batadv_bla_is_backbone_gw_orig(struct batadv_priv *bat_priv, uint8_t *orig); | 33 | bool batadv_bla_is_backbone_gw_orig(struct batadv_priv *bat_priv, uint8_t *orig, |
34 | unsigned short vid); | ||
34 | int batadv_bla_check_bcast_duplist(struct batadv_priv *bat_priv, | 35 | int batadv_bla_check_bcast_duplist(struct batadv_priv *bat_priv, |
35 | struct sk_buff *skb); | 36 | struct sk_buff *skb); |
36 | void batadv_bla_update_orig_address(struct batadv_priv *bat_priv, | 37 | void batadv_bla_update_orig_address(struct batadv_priv *bat_priv, |
@@ -74,10 +75,11 @@ static inline int batadv_bla_backbone_table_seq_print_text(struct seq_file *seq, | |||
74 | return 0; | 75 | return 0; |
75 | } | 76 | } |
76 | 77 | ||
77 | static inline int batadv_bla_is_backbone_gw_orig(struct batadv_priv *bat_priv, | 78 | static inline bool batadv_bla_is_backbone_gw_orig(struct batadv_priv *bat_priv, |
78 | uint8_t *orig) | 79 | uint8_t *orig, |
80 | unsigned short vid) | ||
79 | { | 81 | { |
80 | return 0; | 82 | return false; |
81 | } | 83 | } |
82 | 84 | ||
83 | static inline int | 85 | static inline int |
diff --git a/net/batman-adv/debugfs.c b/net/batman-adv/debugfs.c index f186a55b23c3..049a7a2ac5b6 100644 --- a/net/batman-adv/debugfs.c +++ b/net/batman-adv/debugfs.c | |||
@@ -28,7 +28,6 @@ | |||
28 | #include "gateway_common.h" | 28 | #include "gateway_common.h" |
29 | #include "gateway_client.h" | 29 | #include "gateway_client.h" |
30 | #include "soft-interface.h" | 30 | #include "soft-interface.h" |
31 | #include "vis.h" | ||
32 | #include "icmp_socket.h" | 31 | #include "icmp_socket.h" |
33 | #include "bridge_loop_avoidance.h" | 32 | #include "bridge_loop_avoidance.h" |
34 | #include "distributed-arp-table.h" | 33 | #include "distributed-arp-table.h" |
@@ -300,12 +299,6 @@ static int batadv_transtable_local_open(struct inode *inode, struct file *file) | |||
300 | return single_open(file, batadv_tt_local_seq_print_text, net_dev); | 299 | return single_open(file, batadv_tt_local_seq_print_text, net_dev); |
301 | } | 300 | } |
302 | 301 | ||
303 | static int batadv_vis_data_open(struct inode *inode, struct file *file) | ||
304 | { | ||
305 | struct net_device *net_dev = (struct net_device *)inode->i_private; | ||
306 | return single_open(file, batadv_vis_seq_print_text, net_dev); | ||
307 | } | ||
308 | |||
309 | struct batadv_debuginfo { | 302 | struct batadv_debuginfo { |
310 | struct attribute attr; | 303 | struct attribute attr; |
311 | const struct file_operations fops; | 304 | const struct file_operations fops; |
@@ -356,7 +349,6 @@ static BATADV_DEBUGINFO(dat_cache, S_IRUGO, batadv_dat_cache_open); | |||
356 | #endif | 349 | #endif |
357 | static BATADV_DEBUGINFO(transtable_local, S_IRUGO, | 350 | static BATADV_DEBUGINFO(transtable_local, S_IRUGO, |
358 | batadv_transtable_local_open); | 351 | batadv_transtable_local_open); |
359 | static BATADV_DEBUGINFO(vis_data, S_IRUGO, batadv_vis_data_open); | ||
360 | #ifdef CONFIG_BATMAN_ADV_NC | 352 | #ifdef CONFIG_BATMAN_ADV_NC |
361 | static BATADV_DEBUGINFO(nc_nodes, S_IRUGO, batadv_nc_nodes_open); | 353 | static BATADV_DEBUGINFO(nc_nodes, S_IRUGO, batadv_nc_nodes_open); |
362 | #endif | 354 | #endif |
@@ -373,7 +365,6 @@ static struct batadv_debuginfo *batadv_mesh_debuginfos[] = { | |||
373 | &batadv_debuginfo_dat_cache, | 365 | &batadv_debuginfo_dat_cache, |
374 | #endif | 366 | #endif |
375 | &batadv_debuginfo_transtable_local, | 367 | &batadv_debuginfo_transtable_local, |
376 | &batadv_debuginfo_vis_data, | ||
377 | #ifdef CONFIG_BATMAN_ADV_NC | 368 | #ifdef CONFIG_BATMAN_ADV_NC |
378 | &batadv_debuginfo_nc_nodes, | 369 | &batadv_debuginfo_nc_nodes, |
379 | #endif | 370 | #endif |
diff --git a/net/batman-adv/distributed-arp-table.c b/net/batman-adv/distributed-arp-table.c index 06345d401588..6c8c3934bd7b 100644 --- a/net/batman-adv/distributed-arp-table.c +++ b/net/batman-adv/distributed-arp-table.c | |||
@@ -19,6 +19,7 @@ | |||
19 | 19 | ||
20 | #include <linux/if_ether.h> | 20 | #include <linux/if_ether.h> |
21 | #include <linux/if_arp.h> | 21 | #include <linux/if_arp.h> |
22 | #include <linux/if_vlan.h> | ||
22 | #include <net/arp.h> | 23 | #include <net/arp.h> |
23 | 24 | ||
24 | #include "main.h" | 25 | #include "main.h" |
@@ -29,7 +30,6 @@ | |||
29 | #include "send.h" | 30 | #include "send.h" |
30 | #include "types.h" | 31 | #include "types.h" |
31 | #include "translation-table.h" | 32 | #include "translation-table.h" |
32 | #include "unicast.h" | ||
33 | 33 | ||
34 | static void batadv_dat_purge(struct work_struct *work); | 34 | static void batadv_dat_purge(struct work_struct *work); |
35 | 35 | ||
@@ -206,15 +206,11 @@ static __be32 batadv_arp_ip_dst(struct sk_buff *skb, int hdr_size) | |||
206 | */ | 206 | */ |
207 | static uint32_t batadv_hash_dat(const void *data, uint32_t size) | 207 | static uint32_t batadv_hash_dat(const void *data, uint32_t size) |
208 | { | 208 | { |
209 | const unsigned char *key = data; | ||
210 | uint32_t hash = 0; | 209 | uint32_t hash = 0; |
211 | size_t i; | 210 | const struct batadv_dat_entry *dat = data; |
212 | 211 | ||
213 | for (i = 0; i < 4; i++) { | 212 | hash = batadv_hash_bytes(hash, &dat->ip, sizeof(dat->ip)); |
214 | hash += key[i]; | 213 | hash = batadv_hash_bytes(hash, &dat->vid, sizeof(dat->vid)); |
215 | hash += (hash << 10); | ||
216 | hash ^= (hash >> 6); | ||
217 | } | ||
218 | 214 | ||
219 | hash += (hash << 3); | 215 | hash += (hash << 3); |
220 | hash ^= (hash >> 11); | 216 | hash ^= (hash >> 11); |
@@ -228,21 +224,26 @@ static uint32_t batadv_hash_dat(const void *data, uint32_t size) | |||
228 | * table | 224 | * table |
229 | * @bat_priv: the bat priv with all the soft interface information | 225 | * @bat_priv: the bat priv with all the soft interface information |
230 | * @ip: search key | 226 | * @ip: search key |
227 | * @vid: VLAN identifier | ||
231 | * | 228 | * |
232 | * Returns the dat_entry if found, NULL otherwise. | 229 | * Returns the dat_entry if found, NULL otherwise. |
233 | */ | 230 | */ |
234 | static struct batadv_dat_entry * | 231 | static struct batadv_dat_entry * |
235 | batadv_dat_entry_hash_find(struct batadv_priv *bat_priv, __be32 ip) | 232 | batadv_dat_entry_hash_find(struct batadv_priv *bat_priv, __be32 ip, |
233 | unsigned short vid) | ||
236 | { | 234 | { |
237 | struct hlist_head *head; | 235 | struct hlist_head *head; |
238 | struct batadv_dat_entry *dat_entry, *dat_entry_tmp = NULL; | 236 | struct batadv_dat_entry to_find, *dat_entry, *dat_entry_tmp = NULL; |
239 | struct batadv_hashtable *hash = bat_priv->dat.hash; | 237 | struct batadv_hashtable *hash = bat_priv->dat.hash; |
240 | uint32_t index; | 238 | uint32_t index; |
241 | 239 | ||
242 | if (!hash) | 240 | if (!hash) |
243 | return NULL; | 241 | return NULL; |
244 | 242 | ||
245 | index = batadv_hash_dat(&ip, hash->size); | 243 | to_find.ip = ip; |
244 | to_find.vid = vid; | ||
245 | |||
246 | index = batadv_hash_dat(&to_find, hash->size); | ||
246 | head = &hash->table[index]; | 247 | head = &hash->table[index]; |
247 | 248 | ||
248 | rcu_read_lock(); | 249 | rcu_read_lock(); |
@@ -266,22 +267,24 @@ batadv_dat_entry_hash_find(struct batadv_priv *bat_priv, __be32 ip) | |||
266 | * @bat_priv: the bat priv with all the soft interface information | 267 | * @bat_priv: the bat priv with all the soft interface information |
267 | * @ip: ipv4 to add/edit | 268 | * @ip: ipv4 to add/edit |
268 | * @mac_addr: mac address to assign to the given ipv4 | 269 | * @mac_addr: mac address to assign to the given ipv4 |
270 | * @vid: VLAN identifier | ||
269 | */ | 271 | */ |
270 | static void batadv_dat_entry_add(struct batadv_priv *bat_priv, __be32 ip, | 272 | static void batadv_dat_entry_add(struct batadv_priv *bat_priv, __be32 ip, |
271 | uint8_t *mac_addr) | 273 | uint8_t *mac_addr, unsigned short vid) |
272 | { | 274 | { |
273 | struct batadv_dat_entry *dat_entry; | 275 | struct batadv_dat_entry *dat_entry; |
274 | int hash_added; | 276 | int hash_added; |
275 | 277 | ||
276 | dat_entry = batadv_dat_entry_hash_find(bat_priv, ip); | 278 | dat_entry = batadv_dat_entry_hash_find(bat_priv, ip, vid); |
277 | /* if this entry is already known, just update it */ | 279 | /* if this entry is already known, just update it */ |
278 | if (dat_entry) { | 280 | if (dat_entry) { |
279 | if (!batadv_compare_eth(dat_entry->mac_addr, mac_addr)) | 281 | if (!batadv_compare_eth(dat_entry->mac_addr, mac_addr)) |
280 | memcpy(dat_entry->mac_addr, mac_addr, ETH_ALEN); | 282 | memcpy(dat_entry->mac_addr, mac_addr, ETH_ALEN); |
281 | dat_entry->last_update = jiffies; | 283 | dat_entry->last_update = jiffies; |
282 | batadv_dbg(BATADV_DBG_DAT, bat_priv, | 284 | batadv_dbg(BATADV_DBG_DAT, bat_priv, |
283 | "Entry updated: %pI4 %pM\n", &dat_entry->ip, | 285 | "Entry updated: %pI4 %pM (vid: %d)\n", |
284 | dat_entry->mac_addr); | 286 | &dat_entry->ip, dat_entry->mac_addr, |
287 | BATADV_PRINT_VID(vid)); | ||
285 | goto out; | 288 | goto out; |
286 | } | 289 | } |
287 | 290 | ||
@@ -290,12 +293,13 @@ static void batadv_dat_entry_add(struct batadv_priv *bat_priv, __be32 ip, | |||
290 | goto out; | 293 | goto out; |
291 | 294 | ||
292 | dat_entry->ip = ip; | 295 | dat_entry->ip = ip; |
296 | dat_entry->vid = vid; | ||
293 | memcpy(dat_entry->mac_addr, mac_addr, ETH_ALEN); | 297 | memcpy(dat_entry->mac_addr, mac_addr, ETH_ALEN); |
294 | dat_entry->last_update = jiffies; | 298 | dat_entry->last_update = jiffies; |
295 | atomic_set(&dat_entry->refcount, 2); | 299 | atomic_set(&dat_entry->refcount, 2); |
296 | 300 | ||
297 | hash_added = batadv_hash_add(bat_priv->dat.hash, batadv_compare_dat, | 301 | hash_added = batadv_hash_add(bat_priv->dat.hash, batadv_compare_dat, |
298 | batadv_hash_dat, &dat_entry->ip, | 302 | batadv_hash_dat, dat_entry, |
299 | &dat_entry->hash_entry); | 303 | &dat_entry->hash_entry); |
300 | 304 | ||
301 | if (unlikely(hash_added != 0)) { | 305 | if (unlikely(hash_added != 0)) { |
@@ -304,8 +308,8 @@ static void batadv_dat_entry_add(struct batadv_priv *bat_priv, __be32 ip, | |||
304 | goto out; | 308 | goto out; |
305 | } | 309 | } |
306 | 310 | ||
307 | batadv_dbg(BATADV_DBG_DAT, bat_priv, "New entry added: %pI4 %pM\n", | 311 | batadv_dbg(BATADV_DBG_DAT, bat_priv, "New entry added: %pI4 %pM (vid: %d)\n", |
308 | &dat_entry->ip, dat_entry->mac_addr); | 312 | &dat_entry->ip, dat_entry->mac_addr, BATADV_PRINT_VID(vid)); |
309 | 313 | ||
310 | out: | 314 | out: |
311 | if (dat_entry) | 315 | if (dat_entry) |
@@ -419,6 +423,10 @@ static bool batadv_is_orig_node_eligible(struct batadv_dat_candidate *res, | |||
419 | bool ret = false; | 423 | bool ret = false; |
420 | int j; | 424 | int j; |
421 | 425 | ||
426 | /* check if orig node candidate is running DAT */ | ||
427 | if (!(candidate->capabilities & BATADV_ORIG_CAPA_HAS_DAT)) | ||
428 | goto out; | ||
429 | |||
422 | /* Check if this node has already been selected... */ | 430 | /* Check if this node has already been selected... */ |
423 | for (j = 0; j < select; j++) | 431 | for (j = 0; j < select; j++) |
424 | if (res[j].orig_node == candidate) | 432 | if (res[j].orig_node == candidate) |
@@ -588,9 +596,9 @@ static bool batadv_dat_send_data(struct batadv_priv *bat_priv, | |||
588 | goto free_orig; | 596 | goto free_orig; |
589 | 597 | ||
590 | tmp_skb = pskb_copy(skb, GFP_ATOMIC); | 598 | tmp_skb = pskb_copy(skb, GFP_ATOMIC); |
591 | if (!batadv_unicast_4addr_prepare_skb(bat_priv, tmp_skb, | 599 | if (!batadv_send_skb_prepare_unicast_4addr(bat_priv, tmp_skb, |
592 | cand[i].orig_node, | 600 | cand[i].orig_node, |
593 | packet_subtype)) { | 601 | packet_subtype)) { |
594 | kfree_skb(tmp_skb); | 602 | kfree_skb(tmp_skb); |
595 | goto free_neigh; | 603 | goto free_neigh; |
596 | } | 604 | } |
@@ -626,6 +634,59 @@ out: | |||
626 | } | 634 | } |
627 | 635 | ||
628 | /** | 636 | /** |
637 | * batadv_dat_tvlv_container_update - update the dat tvlv container after dat | ||
638 | * setting change | ||
639 | * @bat_priv: the bat priv with all the soft interface information | ||
640 | */ | ||
641 | static void batadv_dat_tvlv_container_update(struct batadv_priv *bat_priv) | ||
642 | { | ||
643 | char dat_mode; | ||
644 | |||
645 | dat_mode = atomic_read(&bat_priv->distributed_arp_table); | ||
646 | |||
647 | switch (dat_mode) { | ||
648 | case 0: | ||
649 | batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_DAT, 1); | ||
650 | break; | ||
651 | case 1: | ||
652 | batadv_tvlv_container_register(bat_priv, BATADV_TVLV_DAT, 1, | ||
653 | NULL, 0); | ||
654 | break; | ||
655 | } | ||
656 | } | ||
657 | |||
658 | /** | ||
659 | * batadv_dat_status_update - update the dat tvlv container after dat | ||
660 | * setting change | ||
661 | * @net_dev: the soft interface net device | ||
662 | */ | ||
663 | void batadv_dat_status_update(struct net_device *net_dev) | ||
664 | { | ||
665 | struct batadv_priv *bat_priv = netdev_priv(net_dev); | ||
666 | batadv_dat_tvlv_container_update(bat_priv); | ||
667 | } | ||
668 | |||
669 | /** | ||
670 | * batadv_gw_tvlv_ogm_handler_v1 - process incoming dat tvlv container | ||
671 | * @bat_priv: the bat priv with all the soft interface information | ||
672 | * @orig: the orig_node of the ogm | ||
673 | * @flags: flags indicating the tvlv state (see batadv_tvlv_handler_flags) | ||
674 | * @tvlv_value: tvlv buffer containing the gateway data | ||
675 | * @tvlv_value_len: tvlv buffer length | ||
676 | */ | ||
677 | static void batadv_dat_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv, | ||
678 | struct batadv_orig_node *orig, | ||
679 | uint8_t flags, | ||
680 | void *tvlv_value, | ||
681 | uint16_t tvlv_value_len) | ||
682 | { | ||
683 | if (flags & BATADV_TVLV_HANDLER_OGM_CIFNOTFND) | ||
684 | orig->capabilities &= ~BATADV_ORIG_CAPA_HAS_DAT; | ||
685 | else | ||
686 | orig->capabilities |= BATADV_ORIG_CAPA_HAS_DAT; | ||
687 | } | ||
688 | |||
689 | /** | ||
629 | * batadv_dat_hash_free - free the local DAT hash table | 690 | * batadv_dat_hash_free - free the local DAT hash table |
630 | * @bat_priv: the bat priv with all the soft interface information | 691 | * @bat_priv: the bat priv with all the soft interface information |
631 | */ | 692 | */ |
@@ -657,6 +718,10 @@ int batadv_dat_init(struct batadv_priv *bat_priv) | |||
657 | 718 | ||
658 | batadv_dat_start_timer(bat_priv); | 719 | batadv_dat_start_timer(bat_priv); |
659 | 720 | ||
721 | batadv_tvlv_handler_register(bat_priv, batadv_dat_tvlv_ogm_handler_v1, | ||
722 | NULL, BATADV_TVLV_DAT, 1, | ||
723 | BATADV_TVLV_HANDLER_OGM_CIFNOTFND); | ||
724 | batadv_dat_tvlv_container_update(bat_priv); | ||
660 | return 0; | 725 | return 0; |
661 | } | 726 | } |
662 | 727 | ||
@@ -666,6 +731,9 @@ int batadv_dat_init(struct batadv_priv *bat_priv) | |||
666 | */ | 731 | */ |
667 | void batadv_dat_free(struct batadv_priv *bat_priv) | 732 | void batadv_dat_free(struct batadv_priv *bat_priv) |
668 | { | 733 | { |
734 | batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_DAT, 1); | ||
735 | batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_DAT, 1); | ||
736 | |||
669 | cancel_delayed_work_sync(&bat_priv->dat.work); | 737 | cancel_delayed_work_sync(&bat_priv->dat.work); |
670 | 738 | ||
671 | batadv_dat_hash_free(bat_priv); | 739 | batadv_dat_hash_free(bat_priv); |
@@ -693,8 +761,8 @@ int batadv_dat_cache_seq_print_text(struct seq_file *seq, void *offset) | |||
693 | goto out; | 761 | goto out; |
694 | 762 | ||
695 | seq_printf(seq, "Distributed ARP Table (%s):\n", net_dev->name); | 763 | seq_printf(seq, "Distributed ARP Table (%s):\n", net_dev->name); |
696 | seq_printf(seq, " %-7s %-13s %5s\n", "IPv4", "MAC", | 764 | seq_printf(seq, " %-7s %-9s %4s %11s\n", "IPv4", |
697 | "last-seen"); | 765 | "MAC", "VID", "last-seen"); |
698 | 766 | ||
699 | for (i = 0; i < hash->size; i++) { | 767 | for (i = 0; i < hash->size; i++) { |
700 | head = &hash->table[i]; | 768 | head = &hash->table[i]; |
@@ -707,8 +775,9 @@ int batadv_dat_cache_seq_print_text(struct seq_file *seq, void *offset) | |||
707 | last_seen_msecs = last_seen_msecs % 60000; | 775 | last_seen_msecs = last_seen_msecs % 60000; |
708 | last_seen_secs = last_seen_msecs / 1000; | 776 | last_seen_secs = last_seen_msecs / 1000; |
709 | 777 | ||
710 | seq_printf(seq, " * %15pI4 %14pM %6i:%02i\n", | 778 | seq_printf(seq, " * %15pI4 %14pM %4i %6i:%02i\n", |
711 | &dat_entry->ip, dat_entry->mac_addr, | 779 | &dat_entry->ip, dat_entry->mac_addr, |
780 | BATADV_PRINT_VID(dat_entry->vid), | ||
712 | last_seen_mins, last_seen_secs); | 781 | last_seen_mins, last_seen_secs); |
713 | } | 782 | } |
714 | rcu_read_unlock(); | 783 | rcu_read_unlock(); |
@@ -795,6 +864,31 @@ out: | |||
795 | } | 864 | } |
796 | 865 | ||
797 | /** | 866 | /** |
867 | * batadv_dat_get_vid - extract the VLAN identifier from skb if any | ||
868 | * @skb: the buffer containing the packet to extract the VID from | ||
869 | * @hdr_size: the size of the batman-adv header encapsulating the packet | ||
870 | * | ||
871 | * If the packet embedded in the skb is vlan tagged this function returns the | ||
872 | * VID with the BATADV_VLAN_HAS_TAG flag. Otherwise BATADV_NO_FLAGS is returned. | ||
873 | */ | ||
874 | static unsigned short batadv_dat_get_vid(struct sk_buff *skb, int *hdr_size) | ||
875 | { | ||
876 | unsigned short vid; | ||
877 | |||
878 | vid = batadv_get_vid(skb, *hdr_size); | ||
879 | |||
880 | /* ARP parsing functions jump forward of hdr_size + ETH_HLEN. | ||
881 | * If the header contained in the packet is a VLAN one (which is longer) | ||
882 | * hdr_size is updated so that the functions will still skip the | ||
883 | * correct amount of bytes. | ||
884 | */ | ||
885 | if (vid & BATADV_VLAN_HAS_TAG) | ||
886 | *hdr_size += VLAN_HLEN; | ||
887 | |||
888 | return vid; | ||
889 | } | ||
890 | |||
891 | /** | ||
798 | * batadv_dat_snoop_outgoing_arp_request - snoop the ARP request and try to | 892 | * batadv_dat_snoop_outgoing_arp_request - snoop the ARP request and try to |
799 | * answer using DAT | 893 | * answer using DAT |
800 | * @bat_priv: the bat priv with all the soft interface information | 894 | * @bat_priv: the bat priv with all the soft interface information |
@@ -813,26 +907,31 @@ bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv, | |||
813 | bool ret = false; | 907 | bool ret = false; |
814 | struct batadv_dat_entry *dat_entry = NULL; | 908 | struct batadv_dat_entry *dat_entry = NULL; |
815 | struct sk_buff *skb_new; | 909 | struct sk_buff *skb_new; |
910 | int hdr_size = 0; | ||
911 | unsigned short vid; | ||
816 | 912 | ||
817 | if (!atomic_read(&bat_priv->distributed_arp_table)) | 913 | if (!atomic_read(&bat_priv->distributed_arp_table)) |
818 | goto out; | 914 | goto out; |
819 | 915 | ||
820 | type = batadv_arp_get_type(bat_priv, skb, 0); | 916 | vid = batadv_dat_get_vid(skb, &hdr_size); |
917 | |||
918 | type = batadv_arp_get_type(bat_priv, skb, hdr_size); | ||
821 | /* If the node gets an ARP_REQUEST it has to send a DHT_GET unicast | 919 | /* If the node gets an ARP_REQUEST it has to send a DHT_GET unicast |
822 | * message to the selected DHT candidates | 920 | * message to the selected DHT candidates |
823 | */ | 921 | */ |
824 | if (type != ARPOP_REQUEST) | 922 | if (type != ARPOP_REQUEST) |
825 | goto out; | 923 | goto out; |
826 | 924 | ||
827 | batadv_dbg_arp(bat_priv, skb, type, 0, "Parsing outgoing ARP REQUEST"); | 925 | batadv_dbg_arp(bat_priv, skb, type, hdr_size, |
926 | "Parsing outgoing ARP REQUEST"); | ||
828 | 927 | ||
829 | ip_src = batadv_arp_ip_src(skb, 0); | 928 | ip_src = batadv_arp_ip_src(skb, hdr_size); |
830 | hw_src = batadv_arp_hw_src(skb, 0); | 929 | hw_src = batadv_arp_hw_src(skb, hdr_size); |
831 | ip_dst = batadv_arp_ip_dst(skb, 0); | 930 | ip_dst = batadv_arp_ip_dst(skb, hdr_size); |
832 | 931 | ||
833 | batadv_dat_entry_add(bat_priv, ip_src, hw_src); | 932 | batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid); |
834 | 933 | ||
835 | dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst); | 934 | dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst, vid); |
836 | if (dat_entry) { | 935 | if (dat_entry) { |
837 | /* If the ARP request is destined for a local client the local | 936 | /* If the ARP request is destined for a local client the local |
838 | * client will answer itself. DAT would only generate a | 937 | * client will answer itself. DAT would only generate a |
@@ -842,7 +941,8 @@ bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv, | |||
842 | * additional DAT answer may trigger kernel warnings about | 941 | * additional DAT answer may trigger kernel warnings about |
843 | * a packet coming from the wrong port. | 942 | * a packet coming from the wrong port. |
844 | */ | 943 | */ |
845 | if (batadv_is_my_client(bat_priv, dat_entry->mac_addr)) { | 944 | if (batadv_is_my_client(bat_priv, dat_entry->mac_addr, |
945 | BATADV_NO_FLAGS)) { | ||
846 | ret = true; | 946 | ret = true; |
847 | goto out; | 947 | goto out; |
848 | } | 948 | } |
@@ -853,11 +953,15 @@ bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv, | |||
853 | if (!skb_new) | 953 | if (!skb_new) |
854 | goto out; | 954 | goto out; |
855 | 955 | ||
956 | if (vid & BATADV_VLAN_HAS_TAG) | ||
957 | skb_new = vlan_insert_tag(skb_new, htons(ETH_P_8021Q), | ||
958 | vid & VLAN_VID_MASK); | ||
959 | |||
856 | skb_reset_mac_header(skb_new); | 960 | skb_reset_mac_header(skb_new); |
857 | skb_new->protocol = eth_type_trans(skb_new, | 961 | skb_new->protocol = eth_type_trans(skb_new, |
858 | bat_priv->soft_iface); | 962 | bat_priv->soft_iface); |
859 | bat_priv->stats.rx_packets++; | 963 | bat_priv->stats.rx_packets++; |
860 | bat_priv->stats.rx_bytes += skb->len + ETH_HLEN; | 964 | bat_priv->stats.rx_bytes += skb->len + ETH_HLEN + hdr_size; |
861 | bat_priv->soft_iface->last_rx = jiffies; | 965 | bat_priv->soft_iface->last_rx = jiffies; |
862 | 966 | ||
863 | netif_rx(skb_new); | 967 | netif_rx(skb_new); |
@@ -892,11 +996,14 @@ bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv, | |||
892 | struct sk_buff *skb_new; | 996 | struct sk_buff *skb_new; |
893 | struct batadv_dat_entry *dat_entry = NULL; | 997 | struct batadv_dat_entry *dat_entry = NULL; |
894 | bool ret = false; | 998 | bool ret = false; |
999 | unsigned short vid; | ||
895 | int err; | 1000 | int err; |
896 | 1001 | ||
897 | if (!atomic_read(&bat_priv->distributed_arp_table)) | 1002 | if (!atomic_read(&bat_priv->distributed_arp_table)) |
898 | goto out; | 1003 | goto out; |
899 | 1004 | ||
1005 | vid = batadv_dat_get_vid(skb, &hdr_size); | ||
1006 | |||
900 | type = batadv_arp_get_type(bat_priv, skb, hdr_size); | 1007 | type = batadv_arp_get_type(bat_priv, skb, hdr_size); |
901 | if (type != ARPOP_REQUEST) | 1008 | if (type != ARPOP_REQUEST) |
902 | goto out; | 1009 | goto out; |
@@ -908,9 +1015,9 @@ bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv, | |||
908 | batadv_dbg_arp(bat_priv, skb, type, hdr_size, | 1015 | batadv_dbg_arp(bat_priv, skb, type, hdr_size, |
909 | "Parsing incoming ARP REQUEST"); | 1016 | "Parsing incoming ARP REQUEST"); |
910 | 1017 | ||
911 | batadv_dat_entry_add(bat_priv, ip_src, hw_src); | 1018 | batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid); |
912 | 1019 | ||
913 | dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst); | 1020 | dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst, vid); |
914 | if (!dat_entry) | 1021 | if (!dat_entry) |
915 | goto out; | 1022 | goto out; |
916 | 1023 | ||
@@ -921,17 +1028,22 @@ bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv, | |||
921 | if (!skb_new) | 1028 | if (!skb_new) |
922 | goto out; | 1029 | goto out; |
923 | 1030 | ||
1031 | if (vid & BATADV_VLAN_HAS_TAG) | ||
1032 | skb_new = vlan_insert_tag(skb_new, htons(ETH_P_8021Q), | ||
1033 | vid & VLAN_VID_MASK); | ||
1034 | |||
924 | /* To preserve backwards compatibility, the node has choose the outgoing | 1035 | /* To preserve backwards compatibility, the node has choose the outgoing |
925 | * format based on the incoming request packet type. The assumption is | 1036 | * format based on the incoming request packet type. The assumption is |
926 | * that a node not using the 4addr packet format doesn't support it. | 1037 | * that a node not using the 4addr packet format doesn't support it. |
927 | */ | 1038 | */ |
928 | if (hdr_size == sizeof(struct batadv_unicast_4addr_packet)) | 1039 | if (hdr_size == sizeof(struct batadv_unicast_4addr_packet)) |
929 | err = batadv_unicast_4addr_send_skb(bat_priv, skb_new, | 1040 | err = batadv_send_skb_via_tt_4addr(bat_priv, skb_new, |
930 | BATADV_P_DAT_CACHE_REPLY); | 1041 | BATADV_P_DAT_CACHE_REPLY, |
1042 | vid); | ||
931 | else | 1043 | else |
932 | err = batadv_unicast_send_skb(bat_priv, skb_new); | 1044 | err = batadv_send_skb_via_tt(bat_priv, skb_new, vid); |
933 | 1045 | ||
934 | if (!err) { | 1046 | if (err != NET_XMIT_DROP) { |
935 | batadv_inc_counter(bat_priv, BATADV_CNT_DAT_CACHED_REPLY_TX); | 1047 | batadv_inc_counter(bat_priv, BATADV_CNT_DAT_CACHED_REPLY_TX); |
936 | ret = true; | 1048 | ret = true; |
937 | } | 1049 | } |
@@ -954,23 +1066,28 @@ void batadv_dat_snoop_outgoing_arp_reply(struct batadv_priv *bat_priv, | |||
954 | uint16_t type; | 1066 | uint16_t type; |
955 | __be32 ip_src, ip_dst; | 1067 | __be32 ip_src, ip_dst; |
956 | uint8_t *hw_src, *hw_dst; | 1068 | uint8_t *hw_src, *hw_dst; |
1069 | int hdr_size = 0; | ||
1070 | unsigned short vid; | ||
957 | 1071 | ||
958 | if (!atomic_read(&bat_priv->distributed_arp_table)) | 1072 | if (!atomic_read(&bat_priv->distributed_arp_table)) |
959 | return; | 1073 | return; |
960 | 1074 | ||
961 | type = batadv_arp_get_type(bat_priv, skb, 0); | 1075 | vid = batadv_dat_get_vid(skb, &hdr_size); |
1076 | |||
1077 | type = batadv_arp_get_type(bat_priv, skb, hdr_size); | ||
962 | if (type != ARPOP_REPLY) | 1078 | if (type != ARPOP_REPLY) |
963 | return; | 1079 | return; |
964 | 1080 | ||
965 | batadv_dbg_arp(bat_priv, skb, type, 0, "Parsing outgoing ARP REPLY"); | 1081 | batadv_dbg_arp(bat_priv, skb, type, hdr_size, |
1082 | "Parsing outgoing ARP REPLY"); | ||
966 | 1083 | ||
967 | hw_src = batadv_arp_hw_src(skb, 0); | 1084 | hw_src = batadv_arp_hw_src(skb, hdr_size); |
968 | ip_src = batadv_arp_ip_src(skb, 0); | 1085 | ip_src = batadv_arp_ip_src(skb, hdr_size); |
969 | hw_dst = batadv_arp_hw_dst(skb, 0); | 1086 | hw_dst = batadv_arp_hw_dst(skb, hdr_size); |
970 | ip_dst = batadv_arp_ip_dst(skb, 0); | 1087 | ip_dst = batadv_arp_ip_dst(skb, hdr_size); |
971 | 1088 | ||
972 | batadv_dat_entry_add(bat_priv, ip_src, hw_src); | 1089 | batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid); |
973 | batadv_dat_entry_add(bat_priv, ip_dst, hw_dst); | 1090 | batadv_dat_entry_add(bat_priv, ip_dst, hw_dst, vid); |
974 | 1091 | ||
975 | /* Send the ARP reply to the candidates for both the IP addresses that | 1092 | /* Send the ARP reply to the candidates for both the IP addresses that |
976 | * the node obtained from the ARP reply | 1093 | * the node obtained from the ARP reply |
@@ -992,10 +1109,13 @@ bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv, | |||
992 | __be32 ip_src, ip_dst; | 1109 | __be32 ip_src, ip_dst; |
993 | uint8_t *hw_src, *hw_dst; | 1110 | uint8_t *hw_src, *hw_dst; |
994 | bool ret = false; | 1111 | bool ret = false; |
1112 | unsigned short vid; | ||
995 | 1113 | ||
996 | if (!atomic_read(&bat_priv->distributed_arp_table)) | 1114 | if (!atomic_read(&bat_priv->distributed_arp_table)) |
997 | goto out; | 1115 | goto out; |
998 | 1116 | ||
1117 | vid = batadv_dat_get_vid(skb, &hdr_size); | ||
1118 | |||
999 | type = batadv_arp_get_type(bat_priv, skb, hdr_size); | 1119 | type = batadv_arp_get_type(bat_priv, skb, hdr_size); |
1000 | if (type != ARPOP_REPLY) | 1120 | if (type != ARPOP_REPLY) |
1001 | goto out; | 1121 | goto out; |
@@ -1011,13 +1131,13 @@ bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv, | |||
1011 | /* Update our internal cache with both the IP addresses the node got | 1131 | /* Update our internal cache with both the IP addresses the node got |
1012 | * within the ARP reply | 1132 | * within the ARP reply |
1013 | */ | 1133 | */ |
1014 | batadv_dat_entry_add(bat_priv, ip_src, hw_src); | 1134 | batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid); |
1015 | batadv_dat_entry_add(bat_priv, ip_dst, hw_dst); | 1135 | batadv_dat_entry_add(bat_priv, ip_dst, hw_dst, vid); |
1016 | 1136 | ||
1017 | /* if this REPLY is directed to a client of mine, let's deliver the | 1137 | /* if this REPLY is directed to a client of mine, let's deliver the |
1018 | * packet to the interface | 1138 | * packet to the interface |
1019 | */ | 1139 | */ |
1020 | ret = !batadv_is_my_client(bat_priv, hw_dst); | 1140 | ret = !batadv_is_my_client(bat_priv, hw_dst, vid); |
1021 | out: | 1141 | out: |
1022 | if (ret) | 1142 | if (ret) |
1023 | kfree_skb(skb); | 1143 | kfree_skb(skb); |
@@ -1040,7 +1160,8 @@ bool batadv_dat_drop_broadcast_packet(struct batadv_priv *bat_priv, | |||
1040 | __be32 ip_dst; | 1160 | __be32 ip_dst; |
1041 | struct batadv_dat_entry *dat_entry = NULL; | 1161 | struct batadv_dat_entry *dat_entry = NULL; |
1042 | bool ret = false; | 1162 | bool ret = false; |
1043 | const size_t bcast_len = sizeof(struct batadv_bcast_packet); | 1163 | int hdr_size = sizeof(struct batadv_bcast_packet); |
1164 | unsigned short vid; | ||
1044 | 1165 | ||
1045 | if (!atomic_read(&bat_priv->distributed_arp_table)) | 1166 | if (!atomic_read(&bat_priv->distributed_arp_table)) |
1046 | goto out; | 1167 | goto out; |
@@ -1051,12 +1172,14 @@ bool batadv_dat_drop_broadcast_packet(struct batadv_priv *bat_priv, | |||
1051 | if (forw_packet->num_packets) | 1172 | if (forw_packet->num_packets) |
1052 | goto out; | 1173 | goto out; |
1053 | 1174 | ||
1054 | type = batadv_arp_get_type(bat_priv, forw_packet->skb, bcast_len); | 1175 | vid = batadv_dat_get_vid(forw_packet->skb, &hdr_size); |
1176 | |||
1177 | type = batadv_arp_get_type(bat_priv, forw_packet->skb, hdr_size); | ||
1055 | if (type != ARPOP_REQUEST) | 1178 | if (type != ARPOP_REQUEST) |
1056 | goto out; | 1179 | goto out; |
1057 | 1180 | ||
1058 | ip_dst = batadv_arp_ip_dst(forw_packet->skb, bcast_len); | 1181 | ip_dst = batadv_arp_ip_dst(forw_packet->skb, hdr_size); |
1059 | dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst); | 1182 | dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst, vid); |
1060 | /* check if the node already got this entry */ | 1183 | /* check if the node already got this entry */ |
1061 | if (!dat_entry) { | 1184 | if (!dat_entry) { |
1062 | batadv_dbg(BATADV_DBG_DAT, bat_priv, | 1185 | batadv_dbg(BATADV_DBG_DAT, bat_priv, |
diff --git a/net/batman-adv/distributed-arp-table.h b/net/batman-adv/distributed-arp-table.h index 125c8c6fcfad..60d853beb8d8 100644 --- a/net/batman-adv/distributed-arp-table.h +++ b/net/batman-adv/distributed-arp-table.h | |||
@@ -29,6 +29,7 @@ | |||
29 | 29 | ||
30 | #define BATADV_DAT_ADDR_MAX ((batadv_dat_addr_t)~(batadv_dat_addr_t)0) | 30 | #define BATADV_DAT_ADDR_MAX ((batadv_dat_addr_t)~(batadv_dat_addr_t)0) |
31 | 31 | ||
32 | void batadv_dat_status_update(struct net_device *net_dev); | ||
32 | bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv, | 33 | bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv, |
33 | struct sk_buff *skb); | 34 | struct sk_buff *skb); |
34 | bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv, | 35 | bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv, |
@@ -98,6 +99,10 @@ static inline void batadv_dat_inc_counter(struct batadv_priv *bat_priv, | |||
98 | 99 | ||
99 | #else | 100 | #else |
100 | 101 | ||
102 | static inline void batadv_dat_status_update(struct net_device *net_dev) | ||
103 | { | ||
104 | } | ||
105 | |||
101 | static inline bool | 106 | static inline bool |
102 | batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv, | 107 | batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv, |
103 | struct sk_buff *skb) | 108 | struct sk_buff *skb) |
diff --git a/net/batman-adv/fragmentation.c b/net/batman-adv/fragmentation.c new file mode 100644 index 000000000000..271d321b3a04 --- /dev/null +++ b/net/batman-adv/fragmentation.c | |||
@@ -0,0 +1,491 @@ | |||
1 | /* Copyright (C) 2013 B.A.T.M.A.N. contributors: | ||
2 | * | ||
3 | * Martin Hundebøll <martin@hundeboll.net> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of version 2 of the GNU General Public | ||
7 | * License as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, but | ||
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | * General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
17 | * 02110-1301, USA | ||
18 | */ | ||
19 | |||
20 | #include "main.h" | ||
21 | #include "fragmentation.h" | ||
22 | #include "send.h" | ||
23 | #include "originator.h" | ||
24 | #include "routing.h" | ||
25 | #include "hard-interface.h" | ||
26 | #include "soft-interface.h" | ||
27 | |||
28 | |||
29 | /** | ||
30 | * batadv_frag_clear_chain - delete entries in the fragment buffer chain | ||
31 | * @head: head of chain with entries. | ||
32 | * | ||
33 | * Free fragments in the passed hlist. Should be called with appropriate lock. | ||
34 | */ | ||
35 | static void batadv_frag_clear_chain(struct hlist_head *head) | ||
36 | { | ||
37 | struct batadv_frag_list_entry *entry; | ||
38 | struct hlist_node *node; | ||
39 | |||
40 | hlist_for_each_entry_safe(entry, node, head, list) { | ||
41 | hlist_del(&entry->list); | ||
42 | kfree_skb(entry->skb); | ||
43 | kfree(entry); | ||
44 | } | ||
45 | } | ||
46 | |||
47 | /** | ||
48 | * batadv_frag_purge_orig - free fragments associated to an orig | ||
49 | * @orig_node: originator to free fragments from | ||
50 | * @check_cb: optional function to tell if an entry should be purged | ||
51 | */ | ||
52 | void batadv_frag_purge_orig(struct batadv_orig_node *orig_node, | ||
53 | bool (*check_cb)(struct batadv_frag_table_entry *)) | ||
54 | { | ||
55 | struct batadv_frag_table_entry *chain; | ||
56 | uint8_t i; | ||
57 | |||
58 | for (i = 0; i < BATADV_FRAG_BUFFER_COUNT; i++) { | ||
59 | chain = &orig_node->fragments[i]; | ||
60 | spin_lock_bh(&orig_node->fragments[i].lock); | ||
61 | |||
62 | if (!check_cb || check_cb(chain)) { | ||
63 | batadv_frag_clear_chain(&orig_node->fragments[i].head); | ||
64 | orig_node->fragments[i].size = 0; | ||
65 | } | ||
66 | |||
67 | spin_unlock_bh(&orig_node->fragments[i].lock); | ||
68 | } | ||
69 | } | ||
70 | |||
71 | /** | ||
72 | * batadv_frag_size_limit - maximum possible size of packet to be fragmented | ||
73 | * | ||
74 | * Returns the maximum size of payload that can be fragmented. | ||
75 | */ | ||
76 | static int batadv_frag_size_limit(void) | ||
77 | { | ||
78 | int limit = BATADV_FRAG_MAX_FRAG_SIZE; | ||
79 | |||
80 | limit -= sizeof(struct batadv_frag_packet); | ||
81 | limit *= BATADV_FRAG_MAX_FRAGMENTS; | ||
82 | |||
83 | return limit; | ||
84 | } | ||
85 | |||
86 | /** | ||
87 | * batadv_frag_init_chain - check and prepare fragment chain for new fragment | ||
88 | * @chain: chain in fragments table to init | ||
89 | * @seqno: sequence number of the received fragment | ||
90 | * | ||
91 | * Make chain ready for a fragment with sequence number "seqno". Delete existing | ||
92 | * entries if they have an "old" sequence number. | ||
93 | * | ||
94 | * Caller must hold chain->lock. | ||
95 | * | ||
96 | * Returns true if chain is empty and caller can just insert the new fragment | ||
97 | * without searching for the right position. | ||
98 | */ | ||
99 | static bool batadv_frag_init_chain(struct batadv_frag_table_entry *chain, | ||
100 | uint16_t seqno) | ||
101 | { | ||
102 | if (chain->seqno == seqno) | ||
103 | return false; | ||
104 | |||
105 | if (!hlist_empty(&chain->head)) | ||
106 | batadv_frag_clear_chain(&chain->head); | ||
107 | |||
108 | chain->size = 0; | ||
109 | chain->seqno = seqno; | ||
110 | |||
111 | return true; | ||
112 | } | ||
113 | |||
114 | /** | ||
115 | * batadv_frag_insert_packet - insert a fragment into a fragment chain | ||
116 | * @orig_node: originator that the fragment was received from | ||
117 | * @skb: skb to insert | ||
118 | * @chain_out: list head to attach complete chains of fragments to | ||
119 | * | ||
120 | * Insert a new fragment into the reverse ordered chain in the right table | ||
121 | * entry. The hash table entry is cleared if "old" fragments exist in it. | ||
122 | * | ||
123 | * Returns true if skb is buffered, false on error. If the chain has all the | ||
124 | * fragments needed to merge the packet, the chain is moved to the passed head | ||
125 | * to avoid locking the chain in the table. | ||
126 | */ | ||
127 | static bool batadv_frag_insert_packet(struct batadv_orig_node *orig_node, | ||
128 | struct sk_buff *skb, | ||
129 | struct hlist_head *chain_out) | ||
130 | { | ||
131 | struct batadv_frag_table_entry *chain; | ||
132 | struct batadv_frag_list_entry *frag_entry_new = NULL, *frag_entry_curr; | ||
133 | struct batadv_frag_packet *frag_packet; | ||
134 | uint8_t bucket; | ||
135 | uint16_t seqno, hdr_size = sizeof(struct batadv_frag_packet); | ||
136 | bool ret = false; | ||
137 | |||
138 | /* Linearize packet to avoid linearizing 16 packets in a row when doing | ||
139 | * the later merge. Non-linear merge should be added to remove this | ||
140 | * linearization. | ||
141 | */ | ||
142 | if (skb_linearize(skb) < 0) | ||
143 | goto err; | ||
144 | |||
145 | frag_packet = (struct batadv_frag_packet *)skb->data; | ||
146 | seqno = ntohs(frag_packet->seqno); | ||
147 | bucket = seqno % BATADV_FRAG_BUFFER_COUNT; | ||
148 | |||
149 | frag_entry_new = kmalloc(sizeof(*frag_entry_new), GFP_ATOMIC); | ||
150 | if (!frag_entry_new) | ||
151 | goto err; | ||
152 | |||
153 | frag_entry_new->skb = skb; | ||
154 | frag_entry_new->no = frag_packet->no; | ||
155 | |||
156 | /* Select entry in the "chain table" and delete any prior fragments | ||
157 | * with another sequence number. batadv_frag_init_chain() returns true, | ||
158 | * if the list is empty at return. | ||
159 | */ | ||
160 | chain = &orig_node->fragments[bucket]; | ||
161 | spin_lock_bh(&chain->lock); | ||
162 | if (batadv_frag_init_chain(chain, seqno)) { | ||
163 | hlist_add_head(&frag_entry_new->list, &chain->head); | ||
164 | chain->size = skb->len - hdr_size; | ||
165 | chain->timestamp = jiffies; | ||
166 | ret = true; | ||
167 | goto out; | ||
168 | } | ||
169 | |||
170 | /* Find the position for the new fragment. */ | ||
171 | hlist_for_each_entry(frag_entry_curr, &chain->head, list) { | ||
172 | /* Drop packet if fragment already exists. */ | ||
173 | if (frag_entry_curr->no == frag_entry_new->no) | ||
174 | goto err_unlock; | ||
175 | |||
176 | /* Order fragments from highest to lowest. */ | ||
177 | if (frag_entry_curr->no < frag_entry_new->no) { | ||
178 | hlist_add_before(&frag_entry_new->list, | ||
179 | &frag_entry_curr->list); | ||
180 | chain->size += skb->len - hdr_size; | ||
181 | chain->timestamp = jiffies; | ||
182 | ret = true; | ||
183 | goto out; | ||
184 | } | ||
185 | } | ||
186 | |||
187 | /* Reached the end of the list, so insert after 'frag_entry_curr'. */ | ||
188 | if (likely(frag_entry_curr)) { | ||
189 | hlist_add_after(&frag_entry_curr->list, &frag_entry_new->list); | ||
190 | chain->size += skb->len - hdr_size; | ||
191 | chain->timestamp = jiffies; | ||
192 | ret = true; | ||
193 | } | ||
194 | |||
195 | out: | ||
196 | if (chain->size > batadv_frag_size_limit() || | ||
197 | ntohs(frag_packet->total_size) > batadv_frag_size_limit()) { | ||
198 | /* Clear chain if total size of either the list or the packet | ||
199 | * exceeds the maximum size of one merged packet. | ||
200 | */ | ||
201 | batadv_frag_clear_chain(&chain->head); | ||
202 | chain->size = 0; | ||
203 | } else if (ntohs(frag_packet->total_size) == chain->size) { | ||
204 | /* All fragments received. Hand over chain to caller. */ | ||
205 | hlist_move_list(&chain->head, chain_out); | ||
206 | chain->size = 0; | ||
207 | } | ||
208 | |||
209 | err_unlock: | ||
210 | spin_unlock_bh(&chain->lock); | ||
211 | |||
212 | err: | ||
213 | if (!ret) | ||
214 | kfree(frag_entry_new); | ||
215 | |||
216 | return ret; | ||
217 | } | ||
218 | |||
219 | /** | ||
220 | * batadv_frag_merge_packets - merge a chain of fragments | ||
221 | * @chain: head of chain with fragments | ||
222 | * @skb: packet with total size of skb after merging | ||
223 | * | ||
224 | * Expand the first skb in the chain and copy the content of the remaining | ||
225 | * skb's into the expanded one. After doing so, clear the chain. | ||
226 | * | ||
227 | * Returns the merged skb or NULL on error. | ||
228 | */ | ||
229 | static struct sk_buff * | ||
230 | batadv_frag_merge_packets(struct hlist_head *chain, struct sk_buff *skb) | ||
231 | { | ||
232 | struct batadv_frag_packet *packet; | ||
233 | struct batadv_frag_list_entry *entry; | ||
234 | struct sk_buff *skb_out = NULL; | ||
235 | int size, hdr_size = sizeof(struct batadv_frag_packet); | ||
236 | |||
237 | /* Make sure incoming skb has non-bogus data. */ | ||
238 | packet = (struct batadv_frag_packet *)skb->data; | ||
239 | size = ntohs(packet->total_size); | ||
240 | if (size > batadv_frag_size_limit()) | ||
241 | goto free; | ||
242 | |||
243 | /* Remove first entry, as this is the destination for the rest of the | ||
244 | * fragments. | ||
245 | */ | ||
246 | entry = hlist_entry(chain->first, struct batadv_frag_list_entry, list); | ||
247 | hlist_del(&entry->list); | ||
248 | skb_out = entry->skb; | ||
249 | kfree(entry); | ||
250 | |||
251 | /* Make room for the rest of the fragments. */ | ||
252 | if (pskb_expand_head(skb_out, 0, size - skb->len, GFP_ATOMIC) < 0) { | ||
253 | kfree_skb(skb_out); | ||
254 | skb_out = NULL; | ||
255 | goto free; | ||
256 | } | ||
257 | |||
258 | /* Move the existing MAC header to just before the payload. (Override | ||
259 | * the fragment header.) | ||
260 | */ | ||
261 | skb_pull_rcsum(skb_out, hdr_size); | ||
262 | memmove(skb_out->data - ETH_HLEN, skb_mac_header(skb_out), ETH_HLEN); | ||
263 | skb_set_mac_header(skb_out, -ETH_HLEN); | ||
264 | skb_reset_network_header(skb_out); | ||
265 | skb_reset_transport_header(skb_out); | ||
266 | |||
267 | /* Copy the payload of the each fragment into the last skb */ | ||
268 | hlist_for_each_entry(entry, chain, list) { | ||
269 | size = entry->skb->len - hdr_size; | ||
270 | memcpy(skb_put(skb_out, size), entry->skb->data + hdr_size, | ||
271 | size); | ||
272 | } | ||
273 | |||
274 | free: | ||
275 | /* Locking is not needed, because 'chain' is not part of any orig. */ | ||
276 | batadv_frag_clear_chain(chain); | ||
277 | return skb_out; | ||
278 | } | ||
279 | |||
280 | /** | ||
281 | * batadv_frag_skb_buffer - buffer fragment for later merge | ||
282 | * @skb: skb to buffer | ||
283 | * @orig_node_src: originator that the skb is received from | ||
284 | * | ||
285 | * Add fragment to buffer and merge fragments if possible. | ||
286 | * | ||
287 | * There are three possible outcomes: 1) Packet is merged: Return true and | ||
288 | * set *skb to merged packet; 2) Packet is buffered: Return true and set *skb | ||
289 | * to NULL; 3) Error: Return false and leave skb as is. | ||
290 | */ | ||
291 | bool batadv_frag_skb_buffer(struct sk_buff **skb, | ||
292 | struct batadv_orig_node *orig_node_src) | ||
293 | { | ||
294 | struct sk_buff *skb_out = NULL; | ||
295 | struct hlist_head head = HLIST_HEAD_INIT; | ||
296 | bool ret = false; | ||
297 | |||
298 | /* Add packet to buffer and table entry if merge is possible. */ | ||
299 | if (!batadv_frag_insert_packet(orig_node_src, *skb, &head)) | ||
300 | goto out_err; | ||
301 | |||
302 | /* Leave if more fragments are needed to merge. */ | ||
303 | if (hlist_empty(&head)) | ||
304 | goto out; | ||
305 | |||
306 | skb_out = batadv_frag_merge_packets(&head, *skb); | ||
307 | if (!skb_out) | ||
308 | goto out_err; | ||
309 | |||
310 | out: | ||
311 | *skb = skb_out; | ||
312 | ret = true; | ||
313 | out_err: | ||
314 | return ret; | ||
315 | } | ||
316 | |||
317 | /** | ||
318 | * batadv_frag_skb_fwd - forward fragments that would exceed MTU when merged | ||
319 | * @skb: skb to forward | ||
320 | * @recv_if: interface that the skb is received on | ||
321 | * @orig_node_src: originator that the skb is received from | ||
322 | * | ||
323 | * Look up the next-hop of the fragments payload and check if the merged packet | ||
324 | * will exceed the MTU towards the next-hop. If so, the fragment is forwarded | ||
325 | * without merging it. | ||
326 | * | ||
327 | * Returns true if the fragment is consumed/forwarded, false otherwise. | ||
328 | */ | ||
329 | bool batadv_frag_skb_fwd(struct sk_buff *skb, | ||
330 | struct batadv_hard_iface *recv_if, | ||
331 | struct batadv_orig_node *orig_node_src) | ||
332 | { | ||
333 | struct batadv_priv *bat_priv = netdev_priv(recv_if->soft_iface); | ||
334 | struct batadv_orig_node *orig_node_dst = NULL; | ||
335 | struct batadv_neigh_node *neigh_node = NULL; | ||
336 | struct batadv_frag_packet *packet; | ||
337 | uint16_t total_size; | ||
338 | bool ret = false; | ||
339 | |||
340 | packet = (struct batadv_frag_packet *)skb->data; | ||
341 | orig_node_dst = batadv_orig_hash_find(bat_priv, packet->dest); | ||
342 | if (!orig_node_dst) | ||
343 | goto out; | ||
344 | |||
345 | neigh_node = batadv_find_router(bat_priv, orig_node_dst, recv_if); | ||
346 | if (!neigh_node) | ||
347 | goto out; | ||
348 | |||
349 | /* Forward the fragment, if the merged packet would be too big to | ||
350 | * be assembled. | ||
351 | */ | ||
352 | total_size = ntohs(packet->total_size); | ||
353 | if (total_size > neigh_node->if_incoming->net_dev->mtu) { | ||
354 | batadv_inc_counter(bat_priv, BATADV_CNT_FRAG_FWD); | ||
355 | batadv_add_counter(bat_priv, BATADV_CNT_FRAG_FWD_BYTES, | ||
356 | skb->len + ETH_HLEN); | ||
357 | |||
358 | packet->header.ttl--; | ||
359 | batadv_send_skb_packet(skb, neigh_node->if_incoming, | ||
360 | neigh_node->addr); | ||
361 | ret = true; | ||
362 | } | ||
363 | |||
364 | out: | ||
365 | if (orig_node_dst) | ||
366 | batadv_orig_node_free_ref(orig_node_dst); | ||
367 | if (neigh_node) | ||
368 | batadv_neigh_node_free_ref(neigh_node); | ||
369 | return ret; | ||
370 | } | ||
371 | |||
372 | /** | ||
373 | * batadv_frag_create - create a fragment from skb | ||
374 | * @skb: skb to create fragment from | ||
375 | * @frag_head: header to use in new fragment | ||
376 | * @mtu: size of new fragment | ||
377 | * | ||
378 | * Split the passed skb into two fragments: A new one with size matching the | ||
379 | * passed mtu and the old one with the rest. The new skb contains data from the | ||
380 | * tail of the old skb. | ||
381 | * | ||
382 | * Returns the new fragment, NULL on error. | ||
383 | */ | ||
384 | static struct sk_buff *batadv_frag_create(struct sk_buff *skb, | ||
385 | struct batadv_frag_packet *frag_head, | ||
386 | unsigned int mtu) | ||
387 | { | ||
388 | struct sk_buff *skb_fragment; | ||
389 | unsigned header_size = sizeof(*frag_head); | ||
390 | unsigned fragment_size = mtu - header_size; | ||
391 | |||
392 | skb_fragment = netdev_alloc_skb(NULL, mtu + ETH_HLEN); | ||
393 | if (!skb_fragment) | ||
394 | goto err; | ||
395 | |||
396 | skb->priority = TC_PRIO_CONTROL; | ||
397 | |||
398 | /* Eat the last mtu-bytes of the skb */ | ||
399 | skb_reserve(skb_fragment, header_size + ETH_HLEN); | ||
400 | skb_split(skb, skb_fragment, skb->len - fragment_size); | ||
401 | |||
402 | /* Add the header */ | ||
403 | skb_push(skb_fragment, header_size); | ||
404 | memcpy(skb_fragment->data, frag_head, header_size); | ||
405 | |||
406 | err: | ||
407 | return skb_fragment; | ||
408 | } | ||
409 | |||
410 | /** | ||
411 | * batadv_frag_send_packet - create up to 16 fragments from the passed skb | ||
412 | * @skb: skb to create fragments from | ||
413 | * @orig_node: final destination of the created fragments | ||
414 | * @neigh_node: next-hop of the created fragments | ||
415 | * | ||
416 | * Returns true on success, false otherwise. | ||
417 | */ | ||
418 | bool batadv_frag_send_packet(struct sk_buff *skb, | ||
419 | struct batadv_orig_node *orig_node, | ||
420 | struct batadv_neigh_node *neigh_node) | ||
421 | { | ||
422 | struct batadv_priv *bat_priv; | ||
423 | struct batadv_hard_iface *primary_if; | ||
424 | struct batadv_frag_packet frag_header; | ||
425 | struct sk_buff *skb_fragment; | ||
426 | unsigned mtu = neigh_node->if_incoming->net_dev->mtu; | ||
427 | unsigned header_size = sizeof(frag_header); | ||
428 | unsigned max_fragment_size, max_packet_size; | ||
429 | |||
430 | /* To avoid merge and refragmentation at next-hops we never send | ||
431 | * fragments larger than BATADV_FRAG_MAX_FRAG_SIZE | ||
432 | */ | ||
433 | mtu = min_t(unsigned, mtu, BATADV_FRAG_MAX_FRAG_SIZE); | ||
434 | max_fragment_size = (mtu - header_size - ETH_HLEN); | ||
435 | max_packet_size = max_fragment_size * BATADV_FRAG_MAX_FRAGMENTS; | ||
436 | |||
437 | /* Don't even try to fragment, if we need more than 16 fragments */ | ||
438 | if (skb->len > max_packet_size) | ||
439 | goto out_err; | ||
440 | |||
441 | bat_priv = orig_node->bat_priv; | ||
442 | primary_if = batadv_primary_if_get_selected(bat_priv); | ||
443 | if (!primary_if) | ||
444 | goto out_err; | ||
445 | |||
446 | /* Create one header to be copied to all fragments */ | ||
447 | frag_header.header.packet_type = BATADV_UNICAST_FRAG; | ||
448 | frag_header.header.version = BATADV_COMPAT_VERSION; | ||
449 | frag_header.header.ttl = BATADV_TTL; | ||
450 | frag_header.seqno = htons(atomic_inc_return(&bat_priv->frag_seqno)); | ||
451 | frag_header.reserved = 0; | ||
452 | frag_header.no = 0; | ||
453 | frag_header.total_size = htons(skb->len); | ||
454 | memcpy(frag_header.orig, primary_if->net_dev->dev_addr, ETH_ALEN); | ||
455 | memcpy(frag_header.dest, orig_node->orig, ETH_ALEN); | ||
456 | |||
457 | /* Eat and send fragments from the tail of skb */ | ||
458 | while (skb->len > max_fragment_size) { | ||
459 | skb_fragment = batadv_frag_create(skb, &frag_header, mtu); | ||
460 | if (!skb_fragment) | ||
461 | goto out_err; | ||
462 | |||
463 | batadv_inc_counter(bat_priv, BATADV_CNT_FRAG_TX); | ||
464 | batadv_add_counter(bat_priv, BATADV_CNT_FRAG_TX_BYTES, | ||
465 | skb_fragment->len + ETH_HLEN); | ||
466 | batadv_send_skb_packet(skb_fragment, neigh_node->if_incoming, | ||
467 | neigh_node->addr); | ||
468 | frag_header.no++; | ||
469 | |||
470 | /* The initial check in this function should cover this case */ | ||
471 | if (frag_header.no == BATADV_FRAG_MAX_FRAGMENTS - 1) | ||
472 | goto out_err; | ||
473 | } | ||
474 | |||
475 | /* Make room for the fragment header. */ | ||
476 | if (batadv_skb_head_push(skb, header_size) < 0 || | ||
477 | pskb_expand_head(skb, header_size + ETH_HLEN, 0, GFP_ATOMIC) < 0) | ||
478 | goto out_err; | ||
479 | |||
480 | memcpy(skb->data, &frag_header, header_size); | ||
481 | |||
482 | /* Send the last fragment */ | ||
483 | batadv_inc_counter(bat_priv, BATADV_CNT_FRAG_TX); | ||
484 | batadv_add_counter(bat_priv, BATADV_CNT_FRAG_TX_BYTES, | ||
485 | skb->len + ETH_HLEN); | ||
486 | batadv_send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); | ||
487 | |||
488 | return true; | ||
489 | out_err: | ||
490 | return false; | ||
491 | } | ||
diff --git a/net/batman-adv/fragmentation.h b/net/batman-adv/fragmentation.h new file mode 100644 index 000000000000..ca029e2676e7 --- /dev/null +++ b/net/batman-adv/fragmentation.h | |||
@@ -0,0 +1,50 @@ | |||
1 | /* Copyright (C) 2013 B.A.T.M.A.N. contributors: | ||
2 | * | ||
3 | * Martin Hundebøll <martin@hundeboll.net> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of version 2 of the GNU General Public | ||
7 | * License as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, but | ||
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | * General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
17 | * 02110-1301, USA | ||
18 | */ | ||
19 | |||
20 | #ifndef _NET_BATMAN_ADV_FRAGMENTATION_H_ | ||
21 | #define _NET_BATMAN_ADV_FRAGMENTATION_H_ | ||
22 | |||
23 | void batadv_frag_purge_orig(struct batadv_orig_node *orig, | ||
24 | bool (*check_cb)(struct batadv_frag_table_entry *)); | ||
25 | bool batadv_frag_skb_fwd(struct sk_buff *skb, | ||
26 | struct batadv_hard_iface *recv_if, | ||
27 | struct batadv_orig_node *orig_node_src); | ||
28 | bool batadv_frag_skb_buffer(struct sk_buff **skb, | ||
29 | struct batadv_orig_node *orig_node); | ||
30 | bool batadv_frag_send_packet(struct sk_buff *skb, | ||
31 | struct batadv_orig_node *orig_node, | ||
32 | struct batadv_neigh_node *neigh_node); | ||
33 | |||
34 | /** | ||
35 | * batadv_frag_check_entry - check if a list of fragments has timed out | ||
36 | * @frags_entry: table entry to check | ||
37 | * | ||
38 | * Returns true if the frags entry has timed out, false otherwise. | ||
39 | */ | ||
40 | static inline bool | ||
41 | batadv_frag_check_entry(struct batadv_frag_table_entry *frags_entry) | ||
42 | { | ||
43 | if (!hlist_empty(&frags_entry->head) && | ||
44 | batadv_has_timed_out(frags_entry->timestamp, BATADV_FRAG_TIMEOUT)) | ||
45 | return true; | ||
46 | else | ||
47 | return false; | ||
48 | } | ||
49 | |||
50 | #endif /* _NET_BATMAN_ADV_FRAGMENTATION_H_ */ | ||
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 | */ | ||
340 | static void batadv_gw_node_add(struct batadv_priv *bat_priv, | 345 | static 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 | ||
369 | void 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 | */ | ||
382 | static struct batadv_gw_node * | ||
383 | batadv_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 | */ | ||
414 | void 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 | ||
413 | deselect: | 452 | /* Note: We don't need a NULL check here, since curr_gw never |
414 | batadv_gw_deselect(bat_priv); | 453 | * gets dereferenced. |
415 | unlock: | 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 | ||
460 | out: | ||
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 | ||
422 | void batadv_gw_node_delete(struct batadv_priv *bat_priv, | 467 | void 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 | ||
428 | void batadv_gw_node_purge(struct batadv_priv *bat_priv) | 478 | void 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 | */ | ||
673 | bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, | 738 | bool 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) |
diff --git a/net/batman-adv/gateway_client.h b/net/batman-adv/gateway_client.h index ceef4ebe8bcd..d95c2d23195e 100644 --- a/net/batman-adv/gateway_client.h +++ b/net/batman-adv/gateway_client.h | |||
@@ -29,7 +29,7 @@ void batadv_gw_check_election(struct batadv_priv *bat_priv, | |||
29 | struct batadv_orig_node *orig_node); | 29 | struct batadv_orig_node *orig_node); |
30 | void batadv_gw_node_update(struct batadv_priv *bat_priv, | 30 | void batadv_gw_node_update(struct batadv_priv *bat_priv, |
31 | struct batadv_orig_node *orig_node, | 31 | struct batadv_orig_node *orig_node, |
32 | uint8_t new_gwflags); | 32 | struct batadv_tvlv_gateway_data *gateway); |
33 | void batadv_gw_node_delete(struct batadv_priv *bat_priv, | 33 | void batadv_gw_node_delete(struct batadv_priv *bat_priv, |
34 | struct batadv_orig_node *orig_node); | 34 | struct batadv_orig_node *orig_node); |
35 | void batadv_gw_node_purge(struct batadv_priv *bat_priv); | 35 | void batadv_gw_node_purge(struct batadv_priv *bat_priv); |
diff --git a/net/batman-adv/gateway_common.c b/net/batman-adv/gateway_common.c index 84bb2b18d711..b211b0f9cb78 100644 --- a/net/batman-adv/gateway_common.c +++ b/net/batman-adv/gateway_common.c | |||
@@ -21,64 +21,23 @@ | |||
21 | #include "gateway_common.h" | 21 | #include "gateway_common.h" |
22 | #include "gateway_client.h" | 22 | #include "gateway_client.h" |
23 | 23 | ||
24 | /* calculates the gateway class from kbit */ | 24 | /** |
25 | static void batadv_kbit_to_gw_bandwidth(int down, int up, long *gw_srv_class) | 25 | * batadv_parse_gw_bandwidth - parse supplied string buffer to extract download |
26 | { | 26 | * and upload bandwidth information |
27 | int mdown = 0, tdown, tup, difference; | 27 | * @net_dev: the soft interface net device |
28 | uint8_t sbit, part; | 28 | * @buff: string buffer to parse |
29 | 29 | * @down: pointer holding the returned download bandwidth information | |
30 | *gw_srv_class = 0; | 30 | * @up: pointer holding the returned upload bandwidth information |
31 | difference = 0x0FFFFFFF; | 31 | * |
32 | 32 | * Returns false on parse error and true otherwise. | |
33 | /* test all downspeeds */ | 33 | */ |
34 | for (sbit = 0; sbit < 2; sbit++) { | ||
35 | for (part = 0; part < 16; part++) { | ||
36 | tdown = 32 * (sbit + 2) * (1 << part); | ||
37 | |||
38 | if (abs(tdown - down) < difference) { | ||
39 | *gw_srv_class = (sbit << 7) + (part << 3); | ||
40 | difference = abs(tdown - down); | ||
41 | mdown = tdown; | ||
42 | } | ||
43 | } | ||
44 | } | ||
45 | |||
46 | /* test all upspeeds */ | ||
47 | difference = 0x0FFFFFFF; | ||
48 | |||
49 | for (part = 0; part < 8; part++) { | ||
50 | tup = ((part + 1) * (mdown)) / 8; | ||
51 | |||
52 | if (abs(tup - up) < difference) { | ||
53 | *gw_srv_class = (*gw_srv_class & 0xF8) | part; | ||
54 | difference = abs(tup - up); | ||
55 | } | ||
56 | } | ||
57 | } | ||
58 | |||
59 | /* returns the up and downspeeds in kbit, calculated from the class */ | ||
60 | void batadv_gw_bandwidth_to_kbit(uint8_t gw_srv_class, int *down, int *up) | ||
61 | { | ||
62 | int sbit = (gw_srv_class & 0x80) >> 7; | ||
63 | int dpart = (gw_srv_class & 0x78) >> 3; | ||
64 | int upart = (gw_srv_class & 0x07); | ||
65 | |||
66 | if (!gw_srv_class) { | ||
67 | *down = 0; | ||
68 | *up = 0; | ||
69 | return; | ||
70 | } | ||
71 | |||
72 | *down = 32 * (sbit + 2) * (1 << dpart); | ||
73 | *up = ((upart + 1) * (*down)) / 8; | ||
74 | } | ||
75 | |||
76 | static bool batadv_parse_gw_bandwidth(struct net_device *net_dev, char *buff, | 34 | static bool batadv_parse_gw_bandwidth(struct net_device *net_dev, char *buff, |
77 | int *up, int *down) | 35 | uint32_t *down, uint32_t *up) |
78 | { | 36 | { |
79 | int ret, multi = 1; | 37 | enum batadv_bandwidth_units bw_unit_type = BATADV_BW_UNIT_KBIT; |
80 | char *slash_ptr, *tmp_ptr; | 38 | char *slash_ptr, *tmp_ptr; |
81 | long ldown, lup; | 39 | long ldown, lup; |
40 | int ret; | ||
82 | 41 | ||
83 | slash_ptr = strchr(buff, '/'); | 42 | slash_ptr = strchr(buff, '/'); |
84 | if (slash_ptr) | 43 | if (slash_ptr) |
@@ -88,10 +47,10 @@ static bool batadv_parse_gw_bandwidth(struct net_device *net_dev, char *buff, | |||
88 | tmp_ptr = buff + strlen(buff) - 4; | 47 | tmp_ptr = buff + strlen(buff) - 4; |
89 | 48 | ||
90 | if (strnicmp(tmp_ptr, "mbit", 4) == 0) | 49 | if (strnicmp(tmp_ptr, "mbit", 4) == 0) |
91 | multi = 1024; | 50 | bw_unit_type = BATADV_BW_UNIT_MBIT; |
92 | 51 | ||
93 | if ((strnicmp(tmp_ptr, "kbit", 4) == 0) || | 52 | if ((strnicmp(tmp_ptr, "kbit", 4) == 0) || |
94 | (multi > 1)) | 53 | (bw_unit_type == BATADV_BW_UNIT_MBIT)) |
95 | *tmp_ptr = '\0'; | 54 | *tmp_ptr = '\0'; |
96 | } | 55 | } |
97 | 56 | ||
@@ -103,20 +62,28 @@ static bool batadv_parse_gw_bandwidth(struct net_device *net_dev, char *buff, | |||
103 | return false; | 62 | return false; |
104 | } | 63 | } |
105 | 64 | ||
106 | *down = ldown * multi; | 65 | switch (bw_unit_type) { |
66 | case BATADV_BW_UNIT_MBIT: | ||
67 | *down = ldown * 10; | ||
68 | break; | ||
69 | case BATADV_BW_UNIT_KBIT: | ||
70 | default: | ||
71 | *down = ldown / 100; | ||
72 | break; | ||
73 | } | ||
107 | 74 | ||
108 | /* we also got some upload info */ | 75 | /* we also got some upload info */ |
109 | if (slash_ptr) { | 76 | if (slash_ptr) { |
110 | multi = 1; | 77 | bw_unit_type = BATADV_BW_UNIT_KBIT; |
111 | 78 | ||
112 | if (strlen(slash_ptr + 1) > 4) { | 79 | if (strlen(slash_ptr + 1) > 4) { |
113 | tmp_ptr = slash_ptr + 1 - 4 + strlen(slash_ptr + 1); | 80 | tmp_ptr = slash_ptr + 1 - 4 + strlen(slash_ptr + 1); |
114 | 81 | ||
115 | if (strnicmp(tmp_ptr, "mbit", 4) == 0) | 82 | if (strnicmp(tmp_ptr, "mbit", 4) == 0) |
116 | multi = 1024; | 83 | bw_unit_type = BATADV_BW_UNIT_MBIT; |
117 | 84 | ||
118 | if ((strnicmp(tmp_ptr, "kbit", 4) == 0) || | 85 | if ((strnicmp(tmp_ptr, "kbit", 4) == 0) || |
119 | (multi > 1)) | 86 | (bw_unit_type == BATADV_BW_UNIT_MBIT)) |
120 | *tmp_ptr = '\0'; | 87 | *tmp_ptr = '\0'; |
121 | } | 88 | } |
122 | 89 | ||
@@ -128,52 +95,149 @@ static bool batadv_parse_gw_bandwidth(struct net_device *net_dev, char *buff, | |||
128 | return false; | 95 | return false; |
129 | } | 96 | } |
130 | 97 | ||
131 | *up = lup * multi; | 98 | switch (bw_unit_type) { |
99 | case BATADV_BW_UNIT_MBIT: | ||
100 | *up = lup * 10; | ||
101 | break; | ||
102 | case BATADV_BW_UNIT_KBIT: | ||
103 | default: | ||
104 | *up = lup / 100; | ||
105 | break; | ||
106 | } | ||
132 | } | 107 | } |
133 | 108 | ||
134 | return true; | 109 | return true; |
135 | } | 110 | } |
136 | 111 | ||
112 | /** | ||
113 | * batadv_gw_tvlv_container_update - update the gw tvlv container after gateway | ||
114 | * setting change | ||
115 | * @bat_priv: the bat priv with all the soft interface information | ||
116 | */ | ||
117 | void batadv_gw_tvlv_container_update(struct batadv_priv *bat_priv) | ||
118 | { | ||
119 | struct batadv_tvlv_gateway_data gw; | ||
120 | uint32_t down, up; | ||
121 | char gw_mode; | ||
122 | |||
123 | gw_mode = atomic_read(&bat_priv->gw_mode); | ||
124 | |||
125 | switch (gw_mode) { | ||
126 | case BATADV_GW_MODE_OFF: | ||
127 | case BATADV_GW_MODE_CLIENT: | ||
128 | batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_GW, 1); | ||
129 | break; | ||
130 | case BATADV_GW_MODE_SERVER: | ||
131 | down = atomic_read(&bat_priv->gw.bandwidth_down); | ||
132 | up = atomic_read(&bat_priv->gw.bandwidth_up); | ||
133 | gw.bandwidth_down = htonl(down); | ||
134 | gw.bandwidth_up = htonl(up); | ||
135 | batadv_tvlv_container_register(bat_priv, BATADV_TVLV_GW, 1, | ||
136 | &gw, sizeof(gw)); | ||
137 | break; | ||
138 | } | ||
139 | } | ||
140 | |||
137 | ssize_t batadv_gw_bandwidth_set(struct net_device *net_dev, char *buff, | 141 | ssize_t batadv_gw_bandwidth_set(struct net_device *net_dev, char *buff, |
138 | size_t count) | 142 | size_t count) |
139 | { | 143 | { |
140 | struct batadv_priv *bat_priv = netdev_priv(net_dev); | 144 | struct batadv_priv *bat_priv = netdev_priv(net_dev); |
141 | long gw_bandwidth_tmp = 0; | 145 | uint32_t down_curr, up_curr, down_new = 0, up_new = 0; |
142 | int up = 0, down = 0; | ||
143 | bool ret; | 146 | bool ret; |
144 | 147 | ||
145 | ret = batadv_parse_gw_bandwidth(net_dev, buff, &up, &down); | 148 | down_curr = (unsigned int)atomic_read(&bat_priv->gw.bandwidth_down); |
149 | up_curr = (unsigned int)atomic_read(&bat_priv->gw.bandwidth_up); | ||
150 | |||
151 | ret = batadv_parse_gw_bandwidth(net_dev, buff, &down_new, &up_new); | ||
146 | if (!ret) | 152 | if (!ret) |
147 | goto end; | 153 | goto end; |
148 | 154 | ||
149 | if ((!down) || (down < 256)) | 155 | if (!down_new) |
150 | down = 2000; | 156 | down_new = 1; |
151 | |||
152 | if (!up) | ||
153 | up = down / 5; | ||
154 | 157 | ||
155 | batadv_kbit_to_gw_bandwidth(down, up, &gw_bandwidth_tmp); | 158 | if (!up_new) |
159 | up_new = down_new / 5; | ||
156 | 160 | ||
157 | /* the gw bandwidth we guessed above might not match the given | 161 | if (!up_new) |
158 | * speeds, hence we need to calculate it back to show the number | 162 | up_new = 1; |
159 | * that is going to be propagated | ||
160 | */ | ||
161 | batadv_gw_bandwidth_to_kbit((uint8_t)gw_bandwidth_tmp, &down, &up); | ||
162 | 163 | ||
163 | if (atomic_read(&bat_priv->gw_bandwidth) == gw_bandwidth_tmp) | 164 | if ((down_curr == down_new) && (up_curr == up_new)) |
164 | return count; | 165 | return count; |
165 | 166 | ||
166 | batadv_gw_deselect(bat_priv); | 167 | batadv_gw_deselect(bat_priv); |
167 | batadv_info(net_dev, | 168 | batadv_info(net_dev, |
168 | "Changing gateway bandwidth from: '%i' to: '%ld' (propagating: %d%s/%d%s)\n", | 169 | "Changing gateway bandwidth from: '%u.%u/%u.%u MBit' to: '%u.%u/%u.%u MBit'\n", |
169 | atomic_read(&bat_priv->gw_bandwidth), gw_bandwidth_tmp, | 170 | down_curr / 10, down_curr % 10, up_curr / 10, up_curr % 10, |
170 | (down > 2048 ? down / 1024 : down), | 171 | down_new / 10, down_new % 10, up_new / 10, up_new % 10); |
171 | (down > 2048 ? "MBit" : "KBit"), | ||
172 | (up > 2048 ? up / 1024 : up), | ||
173 | (up > 2048 ? "MBit" : "KBit")); | ||
174 | 172 | ||
175 | atomic_set(&bat_priv->gw_bandwidth, gw_bandwidth_tmp); | 173 | atomic_set(&bat_priv->gw.bandwidth_down, down_new); |
174 | atomic_set(&bat_priv->gw.bandwidth_up, up_new); | ||
175 | batadv_gw_tvlv_container_update(bat_priv); | ||
176 | 176 | ||
177 | end: | 177 | end: |
178 | return count; | 178 | return count; |
179 | } | 179 | } |
180 | |||
181 | /** | ||
182 | * batadv_gw_tvlv_ogm_handler_v1 - process incoming gateway tvlv container | ||
183 | * @bat_priv: the bat priv with all the soft interface information | ||
184 | * @orig: the orig_node of the ogm | ||
185 | * @flags: flags indicating the tvlv state (see batadv_tvlv_handler_flags) | ||
186 | * @tvlv_value: tvlv buffer containing the gateway data | ||
187 | * @tvlv_value_len: tvlv buffer length | ||
188 | */ | ||
189 | static void batadv_gw_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv, | ||
190 | struct batadv_orig_node *orig, | ||
191 | uint8_t flags, | ||
192 | void *tvlv_value, | ||
193 | uint16_t tvlv_value_len) | ||
194 | { | ||
195 | struct batadv_tvlv_gateway_data gateway, *gateway_ptr; | ||
196 | |||
197 | /* only fetch the tvlv value if the handler wasn't called via the | ||
198 | * CIFNOTFND flag and if there is data to fetch | ||
199 | */ | ||
200 | if ((flags & BATADV_TVLV_HANDLER_OGM_CIFNOTFND) || | ||
201 | (tvlv_value_len < sizeof(gateway))) { | ||
202 | gateway.bandwidth_down = 0; | ||
203 | gateway.bandwidth_up = 0; | ||
204 | } else { | ||
205 | gateway_ptr = tvlv_value; | ||
206 | gateway.bandwidth_down = gateway_ptr->bandwidth_down; | ||
207 | gateway.bandwidth_up = gateway_ptr->bandwidth_up; | ||
208 | if ((gateway.bandwidth_down == 0) || | ||
209 | (gateway.bandwidth_up == 0)) { | ||
210 | gateway.bandwidth_down = 0; | ||
211 | gateway.bandwidth_up = 0; | ||
212 | } | ||
213 | } | ||
214 | |||
215 | batadv_gw_node_update(bat_priv, orig, &gateway); | ||
216 | |||
217 | /* restart gateway selection if fast or late switching was enabled */ | ||
218 | if ((gateway.bandwidth_down != 0) && | ||
219 | (atomic_read(&bat_priv->gw_mode) == BATADV_GW_MODE_CLIENT) && | ||
220 | (atomic_read(&bat_priv->gw_sel_class) > 2)) | ||
221 | batadv_gw_check_election(bat_priv, orig); | ||
222 | } | ||
223 | |||
224 | /** | ||
225 | * batadv_gw_init - initialise the gateway handling internals | ||
226 | * @bat_priv: the bat priv with all the soft interface information | ||
227 | */ | ||
228 | void batadv_gw_init(struct batadv_priv *bat_priv) | ||
229 | { | ||
230 | batadv_tvlv_handler_register(bat_priv, batadv_gw_tvlv_ogm_handler_v1, | ||
231 | NULL, BATADV_TVLV_GW, 1, | ||
232 | BATADV_TVLV_HANDLER_OGM_CIFNOTFND); | ||
233 | } | ||
234 | |||
235 | /** | ||
236 | * batadv_gw_free - free the gateway handling internals | ||
237 | * @bat_priv: the bat priv with all the soft interface information | ||
238 | */ | ||
239 | void batadv_gw_free(struct batadv_priv *bat_priv) | ||
240 | { | ||
241 | batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_GW, 1); | ||
242 | batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_GW, 1); | ||
243 | } | ||
diff --git a/net/batman-adv/gateway_common.h b/net/batman-adv/gateway_common.h index 509b2bf8c2f4..56384a4cd18c 100644 --- a/net/batman-adv/gateway_common.h +++ b/net/batman-adv/gateway_common.h | |||
@@ -26,12 +26,24 @@ enum batadv_gw_modes { | |||
26 | BATADV_GW_MODE_SERVER, | 26 | BATADV_GW_MODE_SERVER, |
27 | }; | 27 | }; |
28 | 28 | ||
29 | /** | ||
30 | * enum batadv_bandwidth_units - bandwidth unit types | ||
31 | * @BATADV_BW_UNIT_KBIT: unit type kbit | ||
32 | * @BATADV_BW_UNIT_MBIT: unit type mbit | ||
33 | */ | ||
34 | enum batadv_bandwidth_units { | ||
35 | BATADV_BW_UNIT_KBIT, | ||
36 | BATADV_BW_UNIT_MBIT, | ||
37 | }; | ||
38 | |||
29 | #define BATADV_GW_MODE_OFF_NAME "off" | 39 | #define BATADV_GW_MODE_OFF_NAME "off" |
30 | #define BATADV_GW_MODE_CLIENT_NAME "client" | 40 | #define BATADV_GW_MODE_CLIENT_NAME "client" |
31 | #define BATADV_GW_MODE_SERVER_NAME "server" | 41 | #define BATADV_GW_MODE_SERVER_NAME "server" |
32 | 42 | ||
33 | void batadv_gw_bandwidth_to_kbit(uint8_t gw_class, int *down, int *up); | ||
34 | ssize_t batadv_gw_bandwidth_set(struct net_device *net_dev, char *buff, | 43 | ssize_t batadv_gw_bandwidth_set(struct net_device *net_dev, char *buff, |
35 | size_t count); | 44 | size_t count); |
45 | void batadv_gw_tvlv_container_update(struct batadv_priv *bat_priv); | ||
46 | void batadv_gw_init(struct batadv_priv *bat_priv); | ||
47 | void batadv_gw_free(struct batadv_priv *bat_priv); | ||
36 | 48 | ||
37 | #endif /* _NET_BATMAN_ADV_GATEWAY_COMMON_H_ */ | 49 | #endif /* _NET_BATMAN_ADV_GATEWAY_COMMON_H_ */ |
diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c index c478e6bcf89b..c5f871f218c6 100644 --- a/net/batman-adv/hard-interface.c +++ b/net/batman-adv/hard-interface.c | |||
@@ -194,22 +194,13 @@ out: | |||
194 | static void batadv_primary_if_update_addr(struct batadv_priv *bat_priv, | 194 | static void batadv_primary_if_update_addr(struct batadv_priv *bat_priv, |
195 | struct batadv_hard_iface *oldif) | 195 | struct batadv_hard_iface *oldif) |
196 | { | 196 | { |
197 | struct batadv_vis_packet *vis_packet; | ||
198 | struct batadv_hard_iface *primary_if; | 197 | struct batadv_hard_iface *primary_if; |
199 | struct sk_buff *skb; | ||
200 | 198 | ||
201 | primary_if = batadv_primary_if_get_selected(bat_priv); | 199 | primary_if = batadv_primary_if_get_selected(bat_priv); |
202 | if (!primary_if) | 200 | if (!primary_if) |
203 | goto out; | 201 | goto out; |
204 | 202 | ||
205 | batadv_dat_init_own_addr(bat_priv, primary_if); | 203 | batadv_dat_init_own_addr(bat_priv, primary_if); |
206 | |||
207 | skb = bat_priv->vis.my_info->skb_packet; | ||
208 | vis_packet = (struct batadv_vis_packet *)skb->data; | ||
209 | memcpy(vis_packet->vis_orig, primary_if->net_dev->dev_addr, ETH_ALEN); | ||
210 | memcpy(vis_packet->sender_orig, | ||
211 | primary_if->net_dev->dev_addr, ETH_ALEN); | ||
212 | |||
213 | batadv_bla_update_orig_address(bat_priv, primary_if, oldif); | 204 | batadv_bla_update_orig_address(bat_priv, primary_if, oldif); |
214 | out: | 205 | out: |
215 | if (primary_if) | 206 | if (primary_if) |
@@ -278,9 +269,10 @@ int batadv_hardif_min_mtu(struct net_device *soft_iface) | |||
278 | const struct batadv_priv *bat_priv = netdev_priv(soft_iface); | 269 | const struct batadv_priv *bat_priv = netdev_priv(soft_iface); |
279 | const struct batadv_hard_iface *hard_iface; | 270 | const struct batadv_hard_iface *hard_iface; |
280 | /* allow big frames if all devices are capable to do so | 271 | /* allow big frames if all devices are capable to do so |
281 | * (have MTU > 1500 + BAT_HEADER_LEN) | 272 | * (have MTU > 1500 + batadv_max_header_len()) |
282 | */ | 273 | */ |
283 | int min_mtu = ETH_DATA_LEN; | 274 | int min_mtu = ETH_DATA_LEN; |
275 | int max_header_len = batadv_max_header_len(); | ||
284 | 276 | ||
285 | if (atomic_read(&bat_priv->fragmentation)) | 277 | if (atomic_read(&bat_priv->fragmentation)) |
286 | goto out; | 278 | goto out; |
@@ -294,8 +286,7 @@ int batadv_hardif_min_mtu(struct net_device *soft_iface) | |||
294 | if (hard_iface->soft_iface != soft_iface) | 286 | if (hard_iface->soft_iface != soft_iface) |
295 | continue; | 287 | continue; |
296 | 288 | ||
297 | min_mtu = min_t(int, | 289 | min_mtu = min_t(int, hard_iface->net_dev->mtu - max_header_len, |
298 | hard_iface->net_dev->mtu - BATADV_HEADER_LEN, | ||
299 | min_mtu); | 290 | min_mtu); |
300 | } | 291 | } |
301 | rcu_read_unlock(); | 292 | rcu_read_unlock(); |
@@ -388,7 +379,8 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface, | |||
388 | { | 379 | { |
389 | struct batadv_priv *bat_priv; | 380 | struct batadv_priv *bat_priv; |
390 | struct net_device *soft_iface, *master; | 381 | struct net_device *soft_iface, *master; |
391 | __be16 ethertype = __constant_htons(ETH_P_BATMAN); | 382 | __be16 ethertype = htons(ETH_P_BATMAN); |
383 | int max_header_len = batadv_max_header_len(); | ||
392 | int ret; | 384 | int ret; |
393 | 385 | ||
394 | if (hard_iface->if_status != BATADV_IF_NOT_IN_USE) | 386 | if (hard_iface->if_status != BATADV_IF_NOT_IN_USE) |
@@ -453,23 +445,22 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface, | |||
453 | hard_iface->batman_adv_ptype.dev = hard_iface->net_dev; | 445 | hard_iface->batman_adv_ptype.dev = hard_iface->net_dev; |
454 | dev_add_pack(&hard_iface->batman_adv_ptype); | 446 | dev_add_pack(&hard_iface->batman_adv_ptype); |
455 | 447 | ||
456 | atomic_set(&hard_iface->frag_seqno, 1); | ||
457 | batadv_info(hard_iface->soft_iface, "Adding interface: %s\n", | 448 | batadv_info(hard_iface->soft_iface, "Adding interface: %s\n", |
458 | hard_iface->net_dev->name); | 449 | hard_iface->net_dev->name); |
459 | 450 | ||
460 | if (atomic_read(&bat_priv->fragmentation) && | 451 | if (atomic_read(&bat_priv->fragmentation) && |
461 | hard_iface->net_dev->mtu < ETH_DATA_LEN + BATADV_HEADER_LEN) | 452 | hard_iface->net_dev->mtu < ETH_DATA_LEN + max_header_len) |
462 | batadv_info(hard_iface->soft_iface, | 453 | batadv_info(hard_iface->soft_iface, |
463 | "The MTU of interface %s is too small (%i) to handle the transport of batman-adv packets. Packets going over this interface will be fragmented on layer2 which could impact the performance. Setting the MTU to %zi would solve the problem.\n", | 454 | "The MTU of interface %s is too small (%i) to handle the transport of batman-adv packets. Packets going over this interface will be fragmented on layer2 which could impact the performance. Setting the MTU to %i would solve the problem.\n", |
464 | hard_iface->net_dev->name, hard_iface->net_dev->mtu, | 455 | hard_iface->net_dev->name, hard_iface->net_dev->mtu, |
465 | ETH_DATA_LEN + BATADV_HEADER_LEN); | 456 | ETH_DATA_LEN + max_header_len); |
466 | 457 | ||
467 | if (!atomic_read(&bat_priv->fragmentation) && | 458 | if (!atomic_read(&bat_priv->fragmentation) && |
468 | hard_iface->net_dev->mtu < ETH_DATA_LEN + BATADV_HEADER_LEN) | 459 | hard_iface->net_dev->mtu < ETH_DATA_LEN + max_header_len) |
469 | batadv_info(hard_iface->soft_iface, | 460 | batadv_info(hard_iface->soft_iface, |
470 | "The MTU of interface %s is too small (%i) to handle the transport of batman-adv packets. If you experience problems getting traffic through try increasing the MTU to %zi.\n", | 461 | "The MTU of interface %s is too small (%i) to handle the transport of batman-adv packets. If you experience problems getting traffic through try increasing the MTU to %i.\n", |
471 | hard_iface->net_dev->name, hard_iface->net_dev->mtu, | 462 | hard_iface->net_dev->name, hard_iface->net_dev->mtu, |
472 | ETH_DATA_LEN + BATADV_HEADER_LEN); | 463 | ETH_DATA_LEN + max_header_len); |
473 | 464 | ||
474 | if (batadv_hardif_is_iface_up(hard_iface)) | 465 | if (batadv_hardif_is_iface_up(hard_iface)) |
475 | batadv_hardif_activate_interface(hard_iface); | 466 | batadv_hardif_activate_interface(hard_iface); |
@@ -652,6 +643,8 @@ static int batadv_hard_if_event(struct notifier_block *this, | |||
652 | 643 | ||
653 | if (batadv_softif_is_valid(net_dev) && event == NETDEV_REGISTER) { | 644 | if (batadv_softif_is_valid(net_dev) && event == NETDEV_REGISTER) { |
654 | batadv_sysfs_add_meshif(net_dev); | 645 | batadv_sysfs_add_meshif(net_dev); |
646 | bat_priv = netdev_priv(net_dev); | ||
647 | batadv_softif_create_vlan(bat_priv, BATADV_NO_FLAGS); | ||
655 | return NOTIFY_DONE; | 648 | return NOTIFY_DONE; |
656 | } | 649 | } |
657 | 650 | ||
diff --git a/net/batman-adv/icmp_socket.c b/net/batman-adv/icmp_socket.c index 5a99bb4b6b82..82ac6472fa6f 100644 --- a/net/batman-adv/icmp_socket.c +++ b/net/batman-adv/icmp_socket.c | |||
@@ -192,25 +192,25 @@ static ssize_t batadv_socket_write(struct file *file, const char __user *buff, | |||
192 | goto free_skb; | 192 | goto free_skb; |
193 | } | 193 | } |
194 | 194 | ||
195 | if (icmp_packet->header.packet_type != BATADV_ICMP) { | 195 | if (icmp_packet->icmph.header.packet_type != BATADV_ICMP) { |
196 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, | 196 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, |
197 | "Error - can't send packet from char device: got bogus packet type (expected: BAT_ICMP)\n"); | 197 | "Error - can't send packet from char device: got bogus packet type (expected: BAT_ICMP)\n"); |
198 | len = -EINVAL; | 198 | len = -EINVAL; |
199 | goto free_skb; | 199 | goto free_skb; |
200 | } | 200 | } |
201 | 201 | ||
202 | if (icmp_packet->msg_type != BATADV_ECHO_REQUEST) { | 202 | if (icmp_packet->icmph.msg_type != BATADV_ECHO_REQUEST) { |
203 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, | 203 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, |
204 | "Error - can't send packet from char device: got bogus message type (expected: ECHO_REQUEST)\n"); | 204 | "Error - can't send packet from char device: got bogus message type (expected: ECHO_REQUEST)\n"); |
205 | len = -EINVAL; | 205 | len = -EINVAL; |
206 | goto free_skb; | 206 | goto free_skb; |
207 | } | 207 | } |
208 | 208 | ||
209 | icmp_packet->uid = socket_client->index; | 209 | icmp_packet->icmph.uid = socket_client->index; |
210 | 210 | ||
211 | if (icmp_packet->header.version != BATADV_COMPAT_VERSION) { | 211 | if (icmp_packet->icmph.header.version != BATADV_COMPAT_VERSION) { |
212 | icmp_packet->msg_type = BATADV_PARAMETER_PROBLEM; | 212 | icmp_packet->icmph.msg_type = BATADV_PARAMETER_PROBLEM; |
213 | icmp_packet->header.version = BATADV_COMPAT_VERSION; | 213 | icmp_packet->icmph.header.version = BATADV_COMPAT_VERSION; |
214 | batadv_socket_add_packet(socket_client, icmp_packet, | 214 | batadv_socket_add_packet(socket_client, icmp_packet, |
215 | packet_len); | 215 | packet_len); |
216 | goto free_skb; | 216 | goto free_skb; |
@@ -219,7 +219,7 @@ static ssize_t batadv_socket_write(struct file *file, const char __user *buff, | |||
219 | if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE) | 219 | if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE) |
220 | goto dst_unreach; | 220 | goto dst_unreach; |
221 | 221 | ||
222 | orig_node = batadv_orig_hash_find(bat_priv, icmp_packet->dst); | 222 | orig_node = batadv_orig_hash_find(bat_priv, icmp_packet->icmph.dst); |
223 | if (!orig_node) | 223 | if (!orig_node) |
224 | goto dst_unreach; | 224 | goto dst_unreach; |
225 | 225 | ||
@@ -233,7 +233,7 @@ static ssize_t batadv_socket_write(struct file *file, const char __user *buff, | |||
233 | if (neigh_node->if_incoming->if_status != BATADV_IF_ACTIVE) | 233 | if (neigh_node->if_incoming->if_status != BATADV_IF_ACTIVE) |
234 | goto dst_unreach; | 234 | goto dst_unreach; |
235 | 235 | ||
236 | memcpy(icmp_packet->orig, | 236 | memcpy(icmp_packet->icmph.orig, |
237 | primary_if->net_dev->dev_addr, ETH_ALEN); | 237 | primary_if->net_dev->dev_addr, ETH_ALEN); |
238 | 238 | ||
239 | if (packet_len == sizeof(struct batadv_icmp_packet_rr)) | 239 | if (packet_len == sizeof(struct batadv_icmp_packet_rr)) |
@@ -244,7 +244,7 @@ static ssize_t batadv_socket_write(struct file *file, const char __user *buff, | |||
244 | goto out; | 244 | goto out; |
245 | 245 | ||
246 | dst_unreach: | 246 | dst_unreach: |
247 | icmp_packet->msg_type = BATADV_DESTINATION_UNREACHABLE; | 247 | icmp_packet->icmph.msg_type = BATADV_DESTINATION_UNREACHABLE; |
248 | batadv_socket_add_packet(socket_client, icmp_packet, packet_len); | 248 | batadv_socket_add_packet(socket_client, icmp_packet, packet_len); |
249 | free_skb: | 249 | free_skb: |
250 | kfree_skb(skb); | 250 | kfree_skb(skb); |
@@ -318,7 +318,7 @@ static void batadv_socket_add_packet(struct batadv_socket_client *socket_client, | |||
318 | /* while waiting for the lock the socket_client could have been | 318 | /* while waiting for the lock the socket_client could have been |
319 | * deleted | 319 | * deleted |
320 | */ | 320 | */ |
321 | if (!batadv_socket_client_hash[icmp_packet->uid]) { | 321 | if (!batadv_socket_client_hash[icmp_packet->icmph.uid]) { |
322 | spin_unlock_bh(&socket_client->lock); | 322 | spin_unlock_bh(&socket_client->lock); |
323 | kfree(socket_packet); | 323 | kfree(socket_packet); |
324 | return; | 324 | return; |
@@ -347,7 +347,7 @@ void batadv_socket_receive_packet(struct batadv_icmp_packet_rr *icmp_packet, | |||
347 | { | 347 | { |
348 | struct batadv_socket_client *hash; | 348 | struct batadv_socket_client *hash; |
349 | 349 | ||
350 | hash = batadv_socket_client_hash[icmp_packet->uid]; | 350 | hash = batadv_socket_client_hash[icmp_packet->icmph.uid]; |
351 | if (hash) | 351 | if (hash) |
352 | batadv_socket_add_packet(hash, icmp_packet, icmp_len); | 352 | batadv_socket_add_packet(hash, icmp_packet, icmp_len); |
353 | } | 353 | } |
diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c index 1356af660b5b..3159a148c1ac 100644 --- a/net/batman-adv/main.c +++ b/net/batman-adv/main.c | |||
@@ -36,10 +36,11 @@ | |||
36 | #include "gateway_client.h" | 36 | #include "gateway_client.h" |
37 | #include "bridge_loop_avoidance.h" | 37 | #include "bridge_loop_avoidance.h" |
38 | #include "distributed-arp-table.h" | 38 | #include "distributed-arp-table.h" |
39 | #include "vis.h" | 39 | #include "gateway_common.h" |
40 | #include "hash.h" | 40 | #include "hash.h" |
41 | #include "bat_algo.h" | 41 | #include "bat_algo.h" |
42 | #include "network-coding.h" | 42 | #include "network-coding.h" |
43 | #include "fragmentation.h" | ||
43 | 44 | ||
44 | 45 | ||
45 | /* List manipulations on hardif_list have to be rtnl_lock()'ed, | 46 | /* List manipulations on hardif_list have to be rtnl_lock()'ed, |
@@ -109,9 +110,11 @@ int batadv_mesh_init(struct net_device *soft_iface) | |||
109 | spin_lock_init(&bat_priv->tt.req_list_lock); | 110 | spin_lock_init(&bat_priv->tt.req_list_lock); |
110 | spin_lock_init(&bat_priv->tt.roam_list_lock); | 111 | spin_lock_init(&bat_priv->tt.roam_list_lock); |
111 | spin_lock_init(&bat_priv->tt.last_changeset_lock); | 112 | spin_lock_init(&bat_priv->tt.last_changeset_lock); |
113 | spin_lock_init(&bat_priv->tt.commit_lock); | ||
112 | spin_lock_init(&bat_priv->gw.list_lock); | 114 | spin_lock_init(&bat_priv->gw.list_lock); |
113 | spin_lock_init(&bat_priv->vis.hash_lock); | 115 | spin_lock_init(&bat_priv->tvlv.container_list_lock); |
114 | spin_lock_init(&bat_priv->vis.list_lock); | 116 | spin_lock_init(&bat_priv->tvlv.handler_list_lock); |
117 | spin_lock_init(&bat_priv->softif_vlan_list_lock); | ||
115 | 118 | ||
116 | INIT_HLIST_HEAD(&bat_priv->forw_bat_list); | 119 | INIT_HLIST_HEAD(&bat_priv->forw_bat_list); |
117 | INIT_HLIST_HEAD(&bat_priv->forw_bcast_list); | 120 | INIT_HLIST_HEAD(&bat_priv->forw_bcast_list); |
@@ -119,6 +122,9 @@ int batadv_mesh_init(struct net_device *soft_iface) | |||
119 | INIT_LIST_HEAD(&bat_priv->tt.changes_list); | 122 | INIT_LIST_HEAD(&bat_priv->tt.changes_list); |
120 | INIT_LIST_HEAD(&bat_priv->tt.req_list); | 123 | INIT_LIST_HEAD(&bat_priv->tt.req_list); |
121 | INIT_LIST_HEAD(&bat_priv->tt.roam_list); | 124 | INIT_LIST_HEAD(&bat_priv->tt.roam_list); |
125 | INIT_HLIST_HEAD(&bat_priv->tvlv.container_list); | ||
126 | INIT_HLIST_HEAD(&bat_priv->tvlv.handler_list); | ||
127 | INIT_HLIST_HEAD(&bat_priv->softif_vlan_list); | ||
122 | 128 | ||
123 | ret = batadv_originator_init(bat_priv); | 129 | ret = batadv_originator_init(bat_priv); |
124 | if (ret < 0) | 130 | if (ret < 0) |
@@ -128,13 +134,6 @@ int batadv_mesh_init(struct net_device *soft_iface) | |||
128 | if (ret < 0) | 134 | if (ret < 0) |
129 | goto err; | 135 | goto err; |
130 | 136 | ||
131 | batadv_tt_local_add(soft_iface, soft_iface->dev_addr, | ||
132 | BATADV_NULL_IFINDEX); | ||
133 | |||
134 | ret = batadv_vis_init(bat_priv); | ||
135 | if (ret < 0) | ||
136 | goto err; | ||
137 | |||
138 | ret = batadv_bla_init(bat_priv); | 137 | ret = batadv_bla_init(bat_priv); |
139 | if (ret < 0) | 138 | if (ret < 0) |
140 | goto err; | 139 | goto err; |
@@ -147,6 +146,8 @@ int batadv_mesh_init(struct net_device *soft_iface) | |||
147 | if (ret < 0) | 146 | if (ret < 0) |
148 | goto err; | 147 | goto err; |
149 | 148 | ||
149 | batadv_gw_init(bat_priv); | ||
150 | |||
150 | atomic_set(&bat_priv->gw.reselect, 0); | 151 | atomic_set(&bat_priv->gw.reselect, 0); |
151 | atomic_set(&bat_priv->mesh_state, BATADV_MESH_ACTIVE); | 152 | atomic_set(&bat_priv->mesh_state, BATADV_MESH_ACTIVE); |
152 | 153 | ||
@@ -165,8 +166,6 @@ void batadv_mesh_free(struct net_device *soft_iface) | |||
165 | 166 | ||
166 | batadv_purge_outstanding_packets(bat_priv, NULL); | 167 | batadv_purge_outstanding_packets(bat_priv, NULL); |
167 | 168 | ||
168 | batadv_vis_quit(bat_priv); | ||
169 | |||
170 | batadv_gw_node_purge(bat_priv); | 169 | batadv_gw_node_purge(bat_priv); |
171 | batadv_nc_mesh_free(bat_priv); | 170 | batadv_nc_mesh_free(bat_priv); |
172 | batadv_dat_free(bat_priv); | 171 | batadv_dat_free(bat_priv); |
@@ -185,6 +184,8 @@ void batadv_mesh_free(struct net_device *soft_iface) | |||
185 | */ | 184 | */ |
186 | batadv_originator_free(bat_priv); | 185 | batadv_originator_free(bat_priv); |
187 | 186 | ||
187 | batadv_gw_free(bat_priv); | ||
188 | |||
188 | free_percpu(bat_priv->bat_counters); | 189 | free_percpu(bat_priv->bat_counters); |
189 | bat_priv->bat_counters = NULL; | 190 | bat_priv->bat_counters = NULL; |
190 | 191 | ||
@@ -255,6 +256,31 @@ out: | |||
255 | } | 256 | } |
256 | 257 | ||
257 | /** | 258 | /** |
259 | * batadv_max_header_len - calculate maximum encapsulation overhead for a | ||
260 | * payload packet | ||
261 | * | ||
262 | * Return the maximum encapsulation overhead in bytes. | ||
263 | */ | ||
264 | int batadv_max_header_len(void) | ||
265 | { | ||
266 | int header_len = 0; | ||
267 | |||
268 | header_len = max_t(int, header_len, | ||
269 | sizeof(struct batadv_unicast_packet)); | ||
270 | header_len = max_t(int, header_len, | ||
271 | sizeof(struct batadv_unicast_4addr_packet)); | ||
272 | header_len = max_t(int, header_len, | ||
273 | sizeof(struct batadv_bcast_packet)); | ||
274 | |||
275 | #ifdef CONFIG_BATMAN_ADV_NC | ||
276 | header_len = max_t(int, header_len, | ||
277 | sizeof(struct batadv_coded_packet)); | ||
278 | #endif | ||
279 | |||
280 | return header_len; | ||
281 | } | ||
282 | |||
283 | /** | ||
258 | * batadv_skb_set_priority - sets skb priority according to packet content | 284 | * batadv_skb_set_priority - sets skb priority according to packet content |
259 | * @skb: the packet to be sent | 285 | * @skb: the packet to be sent |
260 | * @offset: offset to the packet content | 286 | * @offset: offset to the packet content |
@@ -392,22 +418,31 @@ static void batadv_recv_handler_init(void) | |||
392 | for (i = 0; i < ARRAY_SIZE(batadv_rx_handler); i++) | 418 | for (i = 0; i < ARRAY_SIZE(batadv_rx_handler); i++) |
393 | batadv_rx_handler[i] = batadv_recv_unhandled_packet; | 419 | batadv_rx_handler[i] = batadv_recv_unhandled_packet; |
394 | 420 | ||
395 | /* batman icmp packet */ | 421 | for (i = BATADV_UNICAST_MIN; i <= BATADV_UNICAST_MAX; i++) |
396 | batadv_rx_handler[BATADV_ICMP] = batadv_recv_icmp_packet; | 422 | batadv_rx_handler[i] = batadv_recv_unhandled_unicast_packet; |
423 | |||
424 | /* compile time checks for struct member offsets */ | ||
425 | BUILD_BUG_ON(offsetof(struct batadv_unicast_4addr_packet, src) != 10); | ||
426 | BUILD_BUG_ON(offsetof(struct batadv_unicast_packet, dest) != 4); | ||
427 | BUILD_BUG_ON(offsetof(struct batadv_unicast_tvlv_packet, dst) != 4); | ||
428 | BUILD_BUG_ON(offsetof(struct batadv_frag_packet, dest) != 4); | ||
429 | BUILD_BUG_ON(offsetof(struct batadv_icmp_packet, icmph.dst) != 4); | ||
430 | BUILD_BUG_ON(offsetof(struct batadv_icmp_packet_rr, icmph.dst) != 4); | ||
431 | |||
432 | /* broadcast packet */ | ||
433 | batadv_rx_handler[BATADV_BCAST] = batadv_recv_bcast_packet; | ||
434 | |||
435 | /* unicast packets ... */ | ||
397 | /* unicast with 4 addresses packet */ | 436 | /* unicast with 4 addresses packet */ |
398 | batadv_rx_handler[BATADV_UNICAST_4ADDR] = batadv_recv_unicast_packet; | 437 | batadv_rx_handler[BATADV_UNICAST_4ADDR] = batadv_recv_unicast_packet; |
399 | /* unicast packet */ | 438 | /* unicast packet */ |
400 | batadv_rx_handler[BATADV_UNICAST] = batadv_recv_unicast_packet; | 439 | batadv_rx_handler[BATADV_UNICAST] = batadv_recv_unicast_packet; |
401 | /* fragmented unicast packet */ | 440 | /* unicast tvlv packet */ |
402 | batadv_rx_handler[BATADV_UNICAST_FRAG] = batadv_recv_ucast_frag_packet; | 441 | batadv_rx_handler[BATADV_UNICAST_TVLV] = batadv_recv_unicast_tvlv; |
403 | /* broadcast packet */ | 442 | /* batman icmp packet */ |
404 | batadv_rx_handler[BATADV_BCAST] = batadv_recv_bcast_packet; | 443 | batadv_rx_handler[BATADV_ICMP] = batadv_recv_icmp_packet; |
405 | /* vis packet */ | 444 | /* Fragmented packets */ |
406 | batadv_rx_handler[BATADV_VIS] = batadv_recv_vis_packet; | 445 | batadv_rx_handler[BATADV_UNICAST_FRAG] = batadv_recv_frag_packet; |
407 | /* Translation table query (request or response) */ | ||
408 | batadv_rx_handler[BATADV_TT_QUERY] = batadv_recv_tt_query; | ||
409 | /* Roaming advertisement */ | ||
410 | batadv_rx_handler[BATADV_ROAM_ADV] = batadv_recv_roam_adv; | ||
411 | } | 446 | } |
412 | 447 | ||
413 | int | 448 | int |
@@ -415,7 +450,12 @@ batadv_recv_handler_register(uint8_t packet_type, | |||
415 | int (*recv_handler)(struct sk_buff *, | 450 | int (*recv_handler)(struct sk_buff *, |
416 | struct batadv_hard_iface *)) | 451 | struct batadv_hard_iface *)) |
417 | { | 452 | { |
418 | if (batadv_rx_handler[packet_type] != &batadv_recv_unhandled_packet) | 453 | int (*curr)(struct sk_buff *, |
454 | struct batadv_hard_iface *); | ||
455 | curr = batadv_rx_handler[packet_type]; | ||
456 | |||
457 | if ((curr != batadv_recv_unhandled_packet) && | ||
458 | (curr != batadv_recv_unhandled_unicast_packet)) | ||
419 | return -EBUSY; | 459 | return -EBUSY; |
420 | 460 | ||
421 | batadv_rx_handler[packet_type] = recv_handler; | 461 | batadv_rx_handler[packet_type] = recv_handler; |
@@ -536,6 +576,601 @@ __be32 batadv_skb_crc32(struct sk_buff *skb, u8 *payload_ptr) | |||
536 | return htonl(crc); | 576 | return htonl(crc); |
537 | } | 577 | } |
538 | 578 | ||
579 | /** | ||
580 | * batadv_tvlv_handler_free_ref - decrement the tvlv handler refcounter and | ||
581 | * possibly free it | ||
582 | * @tvlv_handler: the tvlv handler to free | ||
583 | */ | ||
584 | static void | ||
585 | batadv_tvlv_handler_free_ref(struct batadv_tvlv_handler *tvlv_handler) | ||
586 | { | ||
587 | if (atomic_dec_and_test(&tvlv_handler->refcount)) | ||
588 | kfree_rcu(tvlv_handler, rcu); | ||
589 | } | ||
590 | |||
591 | /** | ||
592 | * batadv_tvlv_handler_get - retrieve tvlv handler from the tvlv handler list | ||
593 | * based on the provided type and version (both need to match) | ||
594 | * @bat_priv: the bat priv with all the soft interface information | ||
595 | * @type: tvlv handler type to look for | ||
596 | * @version: tvlv handler version to look for | ||
597 | * | ||
598 | * Returns tvlv handler if found or NULL otherwise. | ||
599 | */ | ||
600 | static struct batadv_tvlv_handler | ||
601 | *batadv_tvlv_handler_get(struct batadv_priv *bat_priv, | ||
602 | uint8_t type, uint8_t version) | ||
603 | { | ||
604 | struct batadv_tvlv_handler *tvlv_handler_tmp, *tvlv_handler = NULL; | ||
605 | |||
606 | rcu_read_lock(); | ||
607 | hlist_for_each_entry_rcu(tvlv_handler_tmp, | ||
608 | &bat_priv->tvlv.handler_list, list) { | ||
609 | if (tvlv_handler_tmp->type != type) | ||
610 | continue; | ||
611 | |||
612 | if (tvlv_handler_tmp->version != version) | ||
613 | continue; | ||
614 | |||
615 | if (!atomic_inc_not_zero(&tvlv_handler_tmp->refcount)) | ||
616 | continue; | ||
617 | |||
618 | tvlv_handler = tvlv_handler_tmp; | ||
619 | break; | ||
620 | } | ||
621 | rcu_read_unlock(); | ||
622 | |||
623 | return tvlv_handler; | ||
624 | } | ||
625 | |||
626 | /** | ||
627 | * batadv_tvlv_container_free_ref - decrement the tvlv container refcounter and | ||
628 | * possibly free it | ||
629 | * @tvlv_handler: the tvlv container to free | ||
630 | */ | ||
631 | static void batadv_tvlv_container_free_ref(struct batadv_tvlv_container *tvlv) | ||
632 | { | ||
633 | if (atomic_dec_and_test(&tvlv->refcount)) | ||
634 | kfree(tvlv); | ||
635 | } | ||
636 | |||
637 | /** | ||
638 | * batadv_tvlv_container_get - retrieve tvlv container from the tvlv container | ||
639 | * list based on the provided type and version (both need to match) | ||
640 | * @bat_priv: the bat priv with all the soft interface information | ||
641 | * @type: tvlv container type to look for | ||
642 | * @version: tvlv container version to look for | ||
643 | * | ||
644 | * Has to be called with the appropriate locks being acquired | ||
645 | * (tvlv.container_list_lock). | ||
646 | * | ||
647 | * Returns tvlv container if found or NULL otherwise. | ||
648 | */ | ||
649 | static struct batadv_tvlv_container | ||
650 | *batadv_tvlv_container_get(struct batadv_priv *bat_priv, | ||
651 | uint8_t type, uint8_t version) | ||
652 | { | ||
653 | struct batadv_tvlv_container *tvlv_tmp, *tvlv = NULL; | ||
654 | |||
655 | hlist_for_each_entry(tvlv_tmp, &bat_priv->tvlv.container_list, list) { | ||
656 | if (tvlv_tmp->tvlv_hdr.type != type) | ||
657 | continue; | ||
658 | |||
659 | if (tvlv_tmp->tvlv_hdr.version != version) | ||
660 | continue; | ||
661 | |||
662 | if (!atomic_inc_not_zero(&tvlv_tmp->refcount)) | ||
663 | continue; | ||
664 | |||
665 | tvlv = tvlv_tmp; | ||
666 | break; | ||
667 | } | ||
668 | |||
669 | return tvlv; | ||
670 | } | ||
671 | |||
672 | /** | ||
673 | * batadv_tvlv_container_list_size - calculate the size of the tvlv container | ||
674 | * list entries | ||
675 | * @bat_priv: the bat priv with all the soft interface information | ||
676 | * | ||
677 | * Has to be called with the appropriate locks being acquired | ||
678 | * (tvlv.container_list_lock). | ||
679 | * | ||
680 | * Returns size of all currently registered tvlv containers in bytes. | ||
681 | */ | ||
682 | static uint16_t batadv_tvlv_container_list_size(struct batadv_priv *bat_priv) | ||
683 | { | ||
684 | struct batadv_tvlv_container *tvlv; | ||
685 | uint16_t tvlv_len = 0; | ||
686 | |||
687 | hlist_for_each_entry(tvlv, &bat_priv->tvlv.container_list, list) { | ||
688 | tvlv_len += sizeof(struct batadv_tvlv_hdr); | ||
689 | tvlv_len += ntohs(tvlv->tvlv_hdr.len); | ||
690 | } | ||
691 | |||
692 | return tvlv_len; | ||
693 | } | ||
694 | |||
695 | /** | ||
696 | * batadv_tvlv_container_remove - remove tvlv container from the tvlv container | ||
697 | * list | ||
698 | * @tvlv: the to be removed tvlv container | ||
699 | * | ||
700 | * Has to be called with the appropriate locks being acquired | ||
701 | * (tvlv.container_list_lock). | ||
702 | */ | ||
703 | static void batadv_tvlv_container_remove(struct batadv_tvlv_container *tvlv) | ||
704 | { | ||
705 | if (!tvlv) | ||
706 | return; | ||
707 | |||
708 | hlist_del(&tvlv->list); | ||
709 | |||
710 | /* first call to decrement the counter, second call to free */ | ||
711 | batadv_tvlv_container_free_ref(tvlv); | ||
712 | batadv_tvlv_container_free_ref(tvlv); | ||
713 | } | ||
714 | |||
715 | /** | ||
716 | * batadv_tvlv_container_unregister - unregister tvlv container based on the | ||
717 | * provided type and version (both need to match) | ||
718 | * @bat_priv: the bat priv with all the soft interface information | ||
719 | * @type: tvlv container type to unregister | ||
720 | * @version: tvlv container type to unregister | ||
721 | */ | ||
722 | void batadv_tvlv_container_unregister(struct batadv_priv *bat_priv, | ||
723 | uint8_t type, uint8_t version) | ||
724 | { | ||
725 | struct batadv_tvlv_container *tvlv; | ||
726 | |||
727 | spin_lock_bh(&bat_priv->tvlv.container_list_lock); | ||
728 | tvlv = batadv_tvlv_container_get(bat_priv, type, version); | ||
729 | batadv_tvlv_container_remove(tvlv); | ||
730 | spin_unlock_bh(&bat_priv->tvlv.container_list_lock); | ||
731 | } | ||
732 | |||
733 | /** | ||
734 | * batadv_tvlv_container_register - register tvlv type, version and content | ||
735 | * to be propagated with each (primary interface) OGM | ||
736 | * @bat_priv: the bat priv with all the soft interface information | ||
737 | * @type: tvlv container type | ||
738 | * @version: tvlv container version | ||
739 | * @tvlv_value: tvlv container content | ||
740 | * @tvlv_value_len: tvlv container content length | ||
741 | * | ||
742 | * If a container of the same type and version was already registered the new | ||
743 | * content is going to replace the old one. | ||
744 | */ | ||
745 | void batadv_tvlv_container_register(struct batadv_priv *bat_priv, | ||
746 | uint8_t type, uint8_t version, | ||
747 | void *tvlv_value, uint16_t tvlv_value_len) | ||
748 | { | ||
749 | struct batadv_tvlv_container *tvlv_old, *tvlv_new; | ||
750 | |||
751 | if (!tvlv_value) | ||
752 | tvlv_value_len = 0; | ||
753 | |||
754 | tvlv_new = kzalloc(sizeof(*tvlv_new) + tvlv_value_len, GFP_ATOMIC); | ||
755 | if (!tvlv_new) | ||
756 | return; | ||
757 | |||
758 | tvlv_new->tvlv_hdr.version = version; | ||
759 | tvlv_new->tvlv_hdr.type = type; | ||
760 | tvlv_new->tvlv_hdr.len = htons(tvlv_value_len); | ||
761 | |||
762 | memcpy(tvlv_new + 1, tvlv_value, ntohs(tvlv_new->tvlv_hdr.len)); | ||
763 | INIT_HLIST_NODE(&tvlv_new->list); | ||
764 | atomic_set(&tvlv_new->refcount, 1); | ||
765 | |||
766 | spin_lock_bh(&bat_priv->tvlv.container_list_lock); | ||
767 | tvlv_old = batadv_tvlv_container_get(bat_priv, type, version); | ||
768 | batadv_tvlv_container_remove(tvlv_old); | ||
769 | hlist_add_head(&tvlv_new->list, &bat_priv->tvlv.container_list); | ||
770 | spin_unlock_bh(&bat_priv->tvlv.container_list_lock); | ||
771 | } | ||
772 | |||
773 | /** | ||
774 | * batadv_tvlv_realloc_packet_buff - reallocate packet buffer to accomodate | ||
775 | * requested packet size | ||
776 | * @packet_buff: packet buffer | ||
777 | * @packet_buff_len: packet buffer size | ||
778 | * @packet_min_len: requested packet minimum size | ||
779 | * @additional_packet_len: requested additional packet size on top of minimum | ||
780 | * size | ||
781 | * | ||
782 | * Returns true of the packet buffer could be changed to the requested size, | ||
783 | * false otherwise. | ||
784 | */ | ||
785 | static bool batadv_tvlv_realloc_packet_buff(unsigned char **packet_buff, | ||
786 | int *packet_buff_len, | ||
787 | int min_packet_len, | ||
788 | int additional_packet_len) | ||
789 | { | ||
790 | unsigned char *new_buff; | ||
791 | |||
792 | new_buff = kmalloc(min_packet_len + additional_packet_len, GFP_ATOMIC); | ||
793 | |||
794 | /* keep old buffer if kmalloc should fail */ | ||
795 | if (new_buff) { | ||
796 | memcpy(new_buff, *packet_buff, min_packet_len); | ||
797 | kfree(*packet_buff); | ||
798 | *packet_buff = new_buff; | ||
799 | *packet_buff_len = min_packet_len + additional_packet_len; | ||
800 | return true; | ||
801 | } | ||
802 | |||
803 | return false; | ||
804 | } | ||
805 | |||
806 | /** | ||
807 | * batadv_tvlv_container_ogm_append - append tvlv container content to given | ||
808 | * OGM packet buffer | ||
809 | * @bat_priv: the bat priv with all the soft interface information | ||
810 | * @packet_buff: ogm packet buffer | ||
811 | * @packet_buff_len: ogm packet buffer size including ogm header and tvlv | ||
812 | * content | ||
813 | * @packet_min_len: ogm header size to be preserved for the OGM itself | ||
814 | * | ||
815 | * The ogm packet might be enlarged or shrunk depending on the current size | ||
816 | * and the size of the to-be-appended tvlv containers. | ||
817 | * | ||
818 | * Returns size of all appended tvlv containers in bytes. | ||
819 | */ | ||
820 | uint16_t batadv_tvlv_container_ogm_append(struct batadv_priv *bat_priv, | ||
821 | unsigned char **packet_buff, | ||
822 | int *packet_buff_len, | ||
823 | int packet_min_len) | ||
824 | { | ||
825 | struct batadv_tvlv_container *tvlv; | ||
826 | struct batadv_tvlv_hdr *tvlv_hdr; | ||
827 | uint16_t tvlv_value_len; | ||
828 | void *tvlv_value; | ||
829 | bool ret; | ||
830 | |||
831 | spin_lock_bh(&bat_priv->tvlv.container_list_lock); | ||
832 | tvlv_value_len = batadv_tvlv_container_list_size(bat_priv); | ||
833 | |||
834 | ret = batadv_tvlv_realloc_packet_buff(packet_buff, packet_buff_len, | ||
835 | packet_min_len, tvlv_value_len); | ||
836 | |||
837 | if (!ret) | ||
838 | goto end; | ||
839 | |||
840 | if (!tvlv_value_len) | ||
841 | goto end; | ||
842 | |||
843 | tvlv_value = (*packet_buff) + packet_min_len; | ||
844 | |||
845 | hlist_for_each_entry(tvlv, &bat_priv->tvlv.container_list, list) { | ||
846 | tvlv_hdr = tvlv_value; | ||
847 | tvlv_hdr->type = tvlv->tvlv_hdr.type; | ||
848 | tvlv_hdr->version = tvlv->tvlv_hdr.version; | ||
849 | tvlv_hdr->len = tvlv->tvlv_hdr.len; | ||
850 | tvlv_value = tvlv_hdr + 1; | ||
851 | memcpy(tvlv_value, tvlv + 1, ntohs(tvlv->tvlv_hdr.len)); | ||
852 | tvlv_value = (uint8_t *)tvlv_value + ntohs(tvlv->tvlv_hdr.len); | ||
853 | } | ||
854 | |||
855 | end: | ||
856 | spin_unlock_bh(&bat_priv->tvlv.container_list_lock); | ||
857 | return tvlv_value_len; | ||
858 | } | ||
859 | |||
860 | /** | ||
861 | * batadv_tvlv_call_handler - parse the given tvlv buffer to call the | ||
862 | * appropriate handlers | ||
863 | * @bat_priv: the bat priv with all the soft interface information | ||
864 | * @tvlv_handler: tvlv callback function handling the tvlv content | ||
865 | * @ogm_source: flag indicating wether the tvlv is an ogm or a unicast packet | ||
866 | * @orig_node: orig node emitting the ogm packet | ||
867 | * @src: source mac address of the unicast packet | ||
868 | * @dst: destination mac address of the unicast packet | ||
869 | * @tvlv_value: tvlv content | ||
870 | * @tvlv_value_len: tvlv content length | ||
871 | * | ||
872 | * Returns success if handler was not found or the return value of the handler | ||
873 | * callback. | ||
874 | */ | ||
875 | static int batadv_tvlv_call_handler(struct batadv_priv *bat_priv, | ||
876 | struct batadv_tvlv_handler *tvlv_handler, | ||
877 | bool ogm_source, | ||
878 | struct batadv_orig_node *orig_node, | ||
879 | uint8_t *src, uint8_t *dst, | ||
880 | void *tvlv_value, uint16_t tvlv_value_len) | ||
881 | { | ||
882 | if (!tvlv_handler) | ||
883 | return NET_RX_SUCCESS; | ||
884 | |||
885 | if (ogm_source) { | ||
886 | if (!tvlv_handler->ogm_handler) | ||
887 | return NET_RX_SUCCESS; | ||
888 | |||
889 | if (!orig_node) | ||
890 | return NET_RX_SUCCESS; | ||
891 | |||
892 | tvlv_handler->ogm_handler(bat_priv, orig_node, | ||
893 | BATADV_NO_FLAGS, | ||
894 | tvlv_value, tvlv_value_len); | ||
895 | tvlv_handler->flags |= BATADV_TVLV_HANDLER_OGM_CALLED; | ||
896 | } else { | ||
897 | if (!src) | ||
898 | return NET_RX_SUCCESS; | ||
899 | |||
900 | if (!dst) | ||
901 | return NET_RX_SUCCESS; | ||
902 | |||
903 | if (!tvlv_handler->unicast_handler) | ||
904 | return NET_RX_SUCCESS; | ||
905 | |||
906 | return tvlv_handler->unicast_handler(bat_priv, src, | ||
907 | dst, tvlv_value, | ||
908 | tvlv_value_len); | ||
909 | } | ||
910 | |||
911 | return NET_RX_SUCCESS; | ||
912 | } | ||
913 | |||
914 | /** | ||
915 | * batadv_tvlv_containers_process - parse the given tvlv buffer to call the | ||
916 | * appropriate handlers | ||
917 | * @bat_priv: the bat priv with all the soft interface information | ||
918 | * @ogm_source: flag indicating wether the tvlv is an ogm or a unicast packet | ||
919 | * @orig_node: orig node emitting the ogm packet | ||
920 | * @src: source mac address of the unicast packet | ||
921 | * @dst: destination mac address of the unicast packet | ||
922 | * @tvlv_value: tvlv content | ||
923 | * @tvlv_value_len: tvlv content length | ||
924 | * | ||
925 | * Returns success when processing an OGM or the return value of all called | ||
926 | * handler callbacks. | ||
927 | */ | ||
928 | int batadv_tvlv_containers_process(struct batadv_priv *bat_priv, | ||
929 | bool ogm_source, | ||
930 | struct batadv_orig_node *orig_node, | ||
931 | uint8_t *src, uint8_t *dst, | ||
932 | void *tvlv_value, uint16_t tvlv_value_len) | ||
933 | { | ||
934 | struct batadv_tvlv_handler *tvlv_handler; | ||
935 | struct batadv_tvlv_hdr *tvlv_hdr; | ||
936 | uint16_t tvlv_value_cont_len; | ||
937 | uint8_t cifnotfound = BATADV_TVLV_HANDLER_OGM_CIFNOTFND; | ||
938 | int ret = NET_RX_SUCCESS; | ||
939 | |||
940 | while (tvlv_value_len >= sizeof(*tvlv_hdr)) { | ||
941 | tvlv_hdr = tvlv_value; | ||
942 | tvlv_value_cont_len = ntohs(tvlv_hdr->len); | ||
943 | tvlv_value = tvlv_hdr + 1; | ||
944 | tvlv_value_len -= sizeof(*tvlv_hdr); | ||
945 | |||
946 | if (tvlv_value_cont_len > tvlv_value_len) | ||
947 | break; | ||
948 | |||
949 | tvlv_handler = batadv_tvlv_handler_get(bat_priv, | ||
950 | tvlv_hdr->type, | ||
951 | tvlv_hdr->version); | ||
952 | |||
953 | ret |= batadv_tvlv_call_handler(bat_priv, tvlv_handler, | ||
954 | ogm_source, orig_node, | ||
955 | src, dst, tvlv_value, | ||
956 | tvlv_value_cont_len); | ||
957 | if (tvlv_handler) | ||
958 | batadv_tvlv_handler_free_ref(tvlv_handler); | ||
959 | tvlv_value = (uint8_t *)tvlv_value + tvlv_value_cont_len; | ||
960 | tvlv_value_len -= tvlv_value_cont_len; | ||
961 | } | ||
962 | |||
963 | if (!ogm_source) | ||
964 | return ret; | ||
965 | |||
966 | rcu_read_lock(); | ||
967 | hlist_for_each_entry_rcu(tvlv_handler, | ||
968 | &bat_priv->tvlv.handler_list, list) { | ||
969 | if ((tvlv_handler->flags & BATADV_TVLV_HANDLER_OGM_CIFNOTFND) && | ||
970 | !(tvlv_handler->flags & BATADV_TVLV_HANDLER_OGM_CALLED)) | ||
971 | tvlv_handler->ogm_handler(bat_priv, orig_node, | ||
972 | cifnotfound, NULL, 0); | ||
973 | |||
974 | tvlv_handler->flags &= ~BATADV_TVLV_HANDLER_OGM_CALLED; | ||
975 | } | ||
976 | rcu_read_unlock(); | ||
977 | |||
978 | return NET_RX_SUCCESS; | ||
979 | } | ||
980 | |||
981 | /** | ||
982 | * batadv_tvlv_ogm_receive - process an incoming ogm and call the appropriate | ||
983 | * handlers | ||
984 | * @bat_priv: the bat priv with all the soft interface information | ||
985 | * @batadv_ogm_packet: ogm packet containing the tvlv containers | ||
986 | * @orig_node: orig node emitting the ogm packet | ||
987 | */ | ||
988 | void batadv_tvlv_ogm_receive(struct batadv_priv *bat_priv, | ||
989 | struct batadv_ogm_packet *batadv_ogm_packet, | ||
990 | struct batadv_orig_node *orig_node) | ||
991 | { | ||
992 | void *tvlv_value; | ||
993 | uint16_t tvlv_value_len; | ||
994 | |||
995 | if (!batadv_ogm_packet) | ||
996 | return; | ||
997 | |||
998 | tvlv_value_len = ntohs(batadv_ogm_packet->tvlv_len); | ||
999 | if (!tvlv_value_len) | ||
1000 | return; | ||
1001 | |||
1002 | tvlv_value = batadv_ogm_packet + 1; | ||
1003 | |||
1004 | batadv_tvlv_containers_process(bat_priv, true, orig_node, NULL, NULL, | ||
1005 | tvlv_value, tvlv_value_len); | ||
1006 | } | ||
1007 | |||
1008 | /** | ||
1009 | * batadv_tvlv_handler_register - register tvlv handler based on the provided | ||
1010 | * type and version (both need to match) for ogm tvlv payload and/or unicast | ||
1011 | * payload | ||
1012 | * @bat_priv: the bat priv with all the soft interface information | ||
1013 | * @optr: ogm tvlv handler callback function. This function receives the orig | ||
1014 | * node, flags and the tvlv content as argument to process. | ||
1015 | * @uptr: unicast tvlv handler callback function. This function receives the | ||
1016 | * source & destination of the unicast packet as well as the tvlv content | ||
1017 | * to process. | ||
1018 | * @type: tvlv handler type to be registered | ||
1019 | * @version: tvlv handler version to be registered | ||
1020 | * @flags: flags to enable or disable TVLV API behavior | ||
1021 | */ | ||
1022 | void batadv_tvlv_handler_register(struct batadv_priv *bat_priv, | ||
1023 | void (*optr)(struct batadv_priv *bat_priv, | ||
1024 | struct batadv_orig_node *orig, | ||
1025 | uint8_t flags, | ||
1026 | void *tvlv_value, | ||
1027 | uint16_t tvlv_value_len), | ||
1028 | int (*uptr)(struct batadv_priv *bat_priv, | ||
1029 | uint8_t *src, uint8_t *dst, | ||
1030 | void *tvlv_value, | ||
1031 | uint16_t tvlv_value_len), | ||
1032 | uint8_t type, uint8_t version, uint8_t flags) | ||
1033 | { | ||
1034 | struct batadv_tvlv_handler *tvlv_handler; | ||
1035 | |||
1036 | tvlv_handler = batadv_tvlv_handler_get(bat_priv, type, version); | ||
1037 | if (tvlv_handler) { | ||
1038 | batadv_tvlv_handler_free_ref(tvlv_handler); | ||
1039 | return; | ||
1040 | } | ||
1041 | |||
1042 | tvlv_handler = kzalloc(sizeof(*tvlv_handler), GFP_ATOMIC); | ||
1043 | if (!tvlv_handler) | ||
1044 | return; | ||
1045 | |||
1046 | tvlv_handler->ogm_handler = optr; | ||
1047 | tvlv_handler->unicast_handler = uptr; | ||
1048 | tvlv_handler->type = type; | ||
1049 | tvlv_handler->version = version; | ||
1050 | tvlv_handler->flags = flags; | ||
1051 | atomic_set(&tvlv_handler->refcount, 1); | ||
1052 | INIT_HLIST_NODE(&tvlv_handler->list); | ||
1053 | |||
1054 | spin_lock_bh(&bat_priv->tvlv.handler_list_lock); | ||
1055 | hlist_add_head_rcu(&tvlv_handler->list, &bat_priv->tvlv.handler_list); | ||
1056 | spin_unlock_bh(&bat_priv->tvlv.handler_list_lock); | ||
1057 | } | ||
1058 | |||
1059 | /** | ||
1060 | * batadv_tvlv_handler_unregister - unregister tvlv handler based on the | ||
1061 | * provided type and version (both need to match) | ||
1062 | * @bat_priv: the bat priv with all the soft interface information | ||
1063 | * @type: tvlv handler type to be unregistered | ||
1064 | * @version: tvlv handler version to be unregistered | ||
1065 | */ | ||
1066 | void batadv_tvlv_handler_unregister(struct batadv_priv *bat_priv, | ||
1067 | uint8_t type, uint8_t version) | ||
1068 | { | ||
1069 | struct batadv_tvlv_handler *tvlv_handler; | ||
1070 | |||
1071 | tvlv_handler = batadv_tvlv_handler_get(bat_priv, type, version); | ||
1072 | if (!tvlv_handler) | ||
1073 | return; | ||
1074 | |||
1075 | batadv_tvlv_handler_free_ref(tvlv_handler); | ||
1076 | spin_lock_bh(&bat_priv->tvlv.handler_list_lock); | ||
1077 | hlist_del_rcu(&tvlv_handler->list); | ||
1078 | spin_unlock_bh(&bat_priv->tvlv.handler_list_lock); | ||
1079 | batadv_tvlv_handler_free_ref(tvlv_handler); | ||
1080 | } | ||
1081 | |||
1082 | /** | ||
1083 | * batadv_tvlv_unicast_send - send a unicast packet with tvlv payload to the | ||
1084 | * specified host | ||
1085 | * @bat_priv: the bat priv with all the soft interface information | ||
1086 | * @src: source mac address of the unicast packet | ||
1087 | * @dst: destination mac address of the unicast packet | ||
1088 | * @type: tvlv type | ||
1089 | * @version: tvlv version | ||
1090 | * @tvlv_value: tvlv content | ||
1091 | * @tvlv_value_len: tvlv content length | ||
1092 | */ | ||
1093 | void batadv_tvlv_unicast_send(struct batadv_priv *bat_priv, uint8_t *src, | ||
1094 | uint8_t *dst, uint8_t type, uint8_t version, | ||
1095 | void *tvlv_value, uint16_t tvlv_value_len) | ||
1096 | { | ||
1097 | struct batadv_unicast_tvlv_packet *unicast_tvlv_packet; | ||
1098 | struct batadv_tvlv_hdr *tvlv_hdr; | ||
1099 | struct batadv_orig_node *orig_node; | ||
1100 | struct sk_buff *skb = NULL; | ||
1101 | unsigned char *tvlv_buff; | ||
1102 | unsigned int tvlv_len; | ||
1103 | ssize_t hdr_len = sizeof(*unicast_tvlv_packet); | ||
1104 | bool ret = false; | ||
1105 | |||
1106 | orig_node = batadv_orig_hash_find(bat_priv, dst); | ||
1107 | if (!orig_node) | ||
1108 | goto out; | ||
1109 | |||
1110 | tvlv_len = sizeof(*tvlv_hdr) + tvlv_value_len; | ||
1111 | |||
1112 | skb = netdev_alloc_skb_ip_align(NULL, ETH_HLEN + hdr_len + tvlv_len); | ||
1113 | if (!skb) | ||
1114 | goto out; | ||
1115 | |||
1116 | skb->priority = TC_PRIO_CONTROL; | ||
1117 | skb_reserve(skb, ETH_HLEN); | ||
1118 | tvlv_buff = skb_put(skb, sizeof(*unicast_tvlv_packet) + tvlv_len); | ||
1119 | unicast_tvlv_packet = (struct batadv_unicast_tvlv_packet *)tvlv_buff; | ||
1120 | unicast_tvlv_packet->header.packet_type = BATADV_UNICAST_TVLV; | ||
1121 | unicast_tvlv_packet->header.version = BATADV_COMPAT_VERSION; | ||
1122 | unicast_tvlv_packet->header.ttl = BATADV_TTL; | ||
1123 | unicast_tvlv_packet->reserved = 0; | ||
1124 | unicast_tvlv_packet->tvlv_len = htons(tvlv_len); | ||
1125 | unicast_tvlv_packet->align = 0; | ||
1126 | memcpy(unicast_tvlv_packet->src, src, ETH_ALEN); | ||
1127 | memcpy(unicast_tvlv_packet->dst, dst, ETH_ALEN); | ||
1128 | |||
1129 | tvlv_buff = (unsigned char *)(unicast_tvlv_packet + 1); | ||
1130 | tvlv_hdr = (struct batadv_tvlv_hdr *)tvlv_buff; | ||
1131 | tvlv_hdr->version = version; | ||
1132 | tvlv_hdr->type = type; | ||
1133 | tvlv_hdr->len = htons(tvlv_value_len); | ||
1134 | tvlv_buff += sizeof(*tvlv_hdr); | ||
1135 | memcpy(tvlv_buff, tvlv_value, tvlv_value_len); | ||
1136 | |||
1137 | if (batadv_send_skb_to_orig(skb, orig_node, NULL) != NET_XMIT_DROP) | ||
1138 | ret = true; | ||
1139 | |||
1140 | out: | ||
1141 | if (skb && !ret) | ||
1142 | kfree_skb(skb); | ||
1143 | if (orig_node) | ||
1144 | batadv_orig_node_free_ref(orig_node); | ||
1145 | } | ||
1146 | |||
1147 | /** | ||
1148 | * batadv_get_vid - extract the VLAN identifier from skb if any | ||
1149 | * @skb: the buffer containing the packet | ||
1150 | * @header_len: length of the batman header preceding the ethernet header | ||
1151 | * | ||
1152 | * If the packet embedded in the skb is vlan tagged this function returns the | ||
1153 | * VID with the BATADV_VLAN_HAS_TAG flag. Otherwise BATADV_NO_FLAGS is returned. | ||
1154 | */ | ||
1155 | unsigned short batadv_get_vid(struct sk_buff *skb, size_t header_len) | ||
1156 | { | ||
1157 | struct ethhdr *ethhdr = (struct ethhdr *)(skb->data + header_len); | ||
1158 | struct vlan_ethhdr *vhdr; | ||
1159 | unsigned short vid; | ||
1160 | |||
1161 | if (ethhdr->h_proto != htons(ETH_P_8021Q)) | ||
1162 | return BATADV_NO_FLAGS; | ||
1163 | |||
1164 | if (!pskb_may_pull(skb, header_len + VLAN_ETH_HLEN)) | ||
1165 | return BATADV_NO_FLAGS; | ||
1166 | |||
1167 | vhdr = (struct vlan_ethhdr *)(skb->data + header_len); | ||
1168 | vid = ntohs(vhdr->h_vlan_TCI) & VLAN_VID_MASK; | ||
1169 | vid |= BATADV_VLAN_HAS_TAG; | ||
1170 | |||
1171 | return vid; | ||
1172 | } | ||
1173 | |||
539 | static int batadv_param_set_ra(const char *val, const struct kernel_param *kp) | 1174 | static int batadv_param_set_ra(const char *val, const struct kernel_param *kp) |
540 | { | 1175 | { |
541 | struct batadv_algo_ops *bat_algo_ops; | 1176 | struct batadv_algo_ops *bat_algo_ops; |
diff --git a/net/batman-adv/main.h b/net/batman-adv/main.h index 24675523930f..d7dfafe45f29 100644 --- a/net/batman-adv/main.h +++ b/net/batman-adv/main.h | |||
@@ -20,8 +20,8 @@ | |||
20 | #ifndef _NET_BATMAN_ADV_MAIN_H_ | 20 | #ifndef _NET_BATMAN_ADV_MAIN_H_ |
21 | #define _NET_BATMAN_ADV_MAIN_H_ | 21 | #define _NET_BATMAN_ADV_MAIN_H_ |
22 | 22 | ||
23 | #define BATADV_DRIVER_AUTHOR "Marek Lindner <lindner_marek@yahoo.de>, " \ | 23 | #define BATADV_DRIVER_AUTHOR "Marek Lindner <mareklindner@neomailbox.ch>, " \ |
24 | "Simon Wunderlich <siwu@hrz.tu-chemnitz.de>" | 24 | "Simon Wunderlich <sw@simonwunderlich.de>" |
25 | #define BATADV_DRIVER_DESC "B.A.T.M.A.N. advanced" | 25 | #define BATADV_DRIVER_DESC "B.A.T.M.A.N. advanced" |
26 | #define BATADV_DRIVER_DEVICE "batman-adv" | 26 | #define BATADV_DRIVER_DEVICE "batman-adv" |
27 | 27 | ||
@@ -86,8 +86,6 @@ | |||
86 | /* numbers of originator to contact for any PUT/GET DHT operation */ | 86 | /* numbers of originator to contact for any PUT/GET DHT operation */ |
87 | #define BATADV_DAT_CANDIDATES_NUM 3 | 87 | #define BATADV_DAT_CANDIDATES_NUM 3 |
88 | 88 | ||
89 | #define BATADV_VIS_INTERVAL 5000 /* 5 seconds */ | ||
90 | |||
91 | /* how much worse secondary interfaces may be to be considered as bonding | 89 | /* how much worse secondary interfaces may be to be considered as bonding |
92 | * candidates | 90 | * candidates |
93 | */ | 91 | */ |
@@ -133,6 +131,15 @@ enum batadv_uev_type { | |||
133 | 131 | ||
134 | #define BATADV_GW_THRESHOLD 50 | 132 | #define BATADV_GW_THRESHOLD 50 |
135 | 133 | ||
134 | /* Number of fragment chains for each orig_node */ | ||
135 | #define BATADV_FRAG_BUFFER_COUNT 8 | ||
136 | /* Maximum number of fragments for one packet */ | ||
137 | #define BATADV_FRAG_MAX_FRAGMENTS 16 | ||
138 | /* Maxumim size of each fragment */ | ||
139 | #define BATADV_FRAG_MAX_FRAG_SIZE 1400 | ||
140 | /* Time to keep fragments while waiting for rest of the fragments */ | ||
141 | #define BATADV_FRAG_TIMEOUT 10000 | ||
142 | |||
136 | #define BATADV_DAT_CANDIDATE_NOT_FOUND 0 | 143 | #define BATADV_DAT_CANDIDATE_NOT_FOUND 0 |
137 | #define BATADV_DAT_CANDIDATE_ORIG 1 | 144 | #define BATADV_DAT_CANDIDATE_ORIG 1 |
138 | 145 | ||
@@ -160,15 +167,9 @@ enum batadv_uev_type { | |||
160 | #include <net/rtnetlink.h> | 167 | #include <net/rtnetlink.h> |
161 | #include <linux/jiffies.h> | 168 | #include <linux/jiffies.h> |
162 | #include <linux/seq_file.h> | 169 | #include <linux/seq_file.h> |
163 | #include "types.h" | 170 | #include <linux/if_vlan.h> |
164 | 171 | ||
165 | /** | 172 | #include "types.h" |
166 | * batadv_vlan_flags - flags for the four MSB of any vlan ID field | ||
167 | * @BATADV_VLAN_HAS_TAG: whether the field contains a valid vlan tag or not | ||
168 | */ | ||
169 | enum batadv_vlan_flags { | ||
170 | BATADV_VLAN_HAS_TAG = BIT(15), | ||
171 | }; | ||
172 | 173 | ||
173 | #define BATADV_PRINT_VID(vid) (vid & BATADV_VLAN_HAS_TAG ? \ | 174 | #define BATADV_PRINT_VID(vid) (vid & BATADV_VLAN_HAS_TAG ? \ |
174 | (int)(vid & VLAN_VID_MASK) : -1) | 175 | (int)(vid & VLAN_VID_MASK) : -1) |
@@ -184,6 +185,7 @@ void batadv_mesh_free(struct net_device *soft_iface); | |||
184 | int batadv_is_my_mac(struct batadv_priv *bat_priv, const uint8_t *addr); | 185 | int batadv_is_my_mac(struct batadv_priv *bat_priv, const uint8_t *addr); |
185 | struct batadv_hard_iface * | 186 | struct batadv_hard_iface * |
186 | batadv_seq_print_text_primary_if_get(struct seq_file *seq); | 187 | batadv_seq_print_text_primary_if_get(struct seq_file *seq); |
188 | int batadv_max_header_len(void); | ||
187 | void batadv_skb_set_priority(struct sk_buff *skb, int offset); | 189 | void batadv_skb_set_priority(struct sk_buff *skb, int offset); |
188 | int batadv_batman_skb_recv(struct sk_buff *skb, struct net_device *dev, | 190 | int batadv_batman_skb_recv(struct sk_buff *skb, struct net_device *dev, |
189 | struct packet_type *ptype, | 191 | struct packet_type *ptype, |
@@ -326,4 +328,40 @@ static inline uint64_t batadv_sum_counter(struct batadv_priv *bat_priv, | |||
326 | */ | 328 | */ |
327 | #define BATADV_SKB_CB(__skb) ((struct batadv_skb_cb *)&((__skb)->cb[0])) | 329 | #define BATADV_SKB_CB(__skb) ((struct batadv_skb_cb *)&((__skb)->cb[0])) |
328 | 330 | ||
331 | void batadv_tvlv_container_register(struct batadv_priv *bat_priv, | ||
332 | uint8_t type, uint8_t version, | ||
333 | void *tvlv_value, uint16_t tvlv_value_len); | ||
334 | uint16_t batadv_tvlv_container_ogm_append(struct batadv_priv *bat_priv, | ||
335 | unsigned char **packet_buff, | ||
336 | int *packet_buff_len, | ||
337 | int packet_min_len); | ||
338 | void batadv_tvlv_ogm_receive(struct batadv_priv *bat_priv, | ||
339 | struct batadv_ogm_packet *batadv_ogm_packet, | ||
340 | struct batadv_orig_node *orig_node); | ||
341 | void batadv_tvlv_container_unregister(struct batadv_priv *bat_priv, | ||
342 | uint8_t type, uint8_t version); | ||
343 | |||
344 | void batadv_tvlv_handler_register(struct batadv_priv *bat_priv, | ||
345 | void (*optr)(struct batadv_priv *bat_priv, | ||
346 | struct batadv_orig_node *orig, | ||
347 | uint8_t flags, | ||
348 | void *tvlv_value, | ||
349 | uint16_t tvlv_value_len), | ||
350 | int (*uptr)(struct batadv_priv *bat_priv, | ||
351 | uint8_t *src, uint8_t *dst, | ||
352 | void *tvlv_value, | ||
353 | uint16_t tvlv_value_len), | ||
354 | uint8_t type, uint8_t version, uint8_t flags); | ||
355 | void batadv_tvlv_handler_unregister(struct batadv_priv *bat_priv, | ||
356 | uint8_t type, uint8_t version); | ||
357 | int batadv_tvlv_containers_process(struct batadv_priv *bat_priv, | ||
358 | bool ogm_source, | ||
359 | struct batadv_orig_node *orig_node, | ||
360 | uint8_t *src, uint8_t *dst, | ||
361 | void *tvlv_buff, uint16_t tvlv_buff_len); | ||
362 | void batadv_tvlv_unicast_send(struct batadv_priv *bat_priv, uint8_t *src, | ||
363 | uint8_t *dst, uint8_t type, uint8_t version, | ||
364 | void *tvlv_value, uint16_t tvlv_value_len); | ||
365 | unsigned short batadv_get_vid(struct sk_buff *skb, size_t header_len); | ||
366 | |||
329 | #endif /* _NET_BATMAN_ADV_MAIN_H_ */ | 367 | #endif /* _NET_BATMAN_ADV_MAIN_H_ */ |
diff --git a/net/batman-adv/network-coding.c b/net/batman-adv/network-coding.c index 4ecc0b6bf8ab..23f611bedb0f 100644 --- a/net/batman-adv/network-coding.c +++ b/net/batman-adv/network-coding.c | |||
@@ -59,6 +59,59 @@ static void batadv_nc_start_timer(struct batadv_priv *bat_priv) | |||
59 | } | 59 | } |
60 | 60 | ||
61 | /** | 61 | /** |
62 | * batadv_nc_tvlv_container_update - update the network coding tvlv container | ||
63 | * after network coding setting change | ||
64 | * @bat_priv: the bat priv with all the soft interface information | ||
65 | */ | ||
66 | static void batadv_nc_tvlv_container_update(struct batadv_priv *bat_priv) | ||
67 | { | ||
68 | char nc_mode; | ||
69 | |||
70 | nc_mode = atomic_read(&bat_priv->network_coding); | ||
71 | |||
72 | switch (nc_mode) { | ||
73 | case 0: | ||
74 | batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_NC, 1); | ||
75 | break; | ||
76 | case 1: | ||
77 | batadv_tvlv_container_register(bat_priv, BATADV_TVLV_NC, 1, | ||
78 | NULL, 0); | ||
79 | break; | ||
80 | } | ||
81 | } | ||
82 | |||
83 | /** | ||
84 | * batadv_nc_status_update - update the network coding tvlv container after | ||
85 | * network coding setting change | ||
86 | * @net_dev: the soft interface net device | ||
87 | */ | ||
88 | void batadv_nc_status_update(struct net_device *net_dev) | ||
89 | { | ||
90 | struct batadv_priv *bat_priv = netdev_priv(net_dev); | ||
91 | batadv_nc_tvlv_container_update(bat_priv); | ||
92 | } | ||
93 | |||
94 | /** | ||
95 | * batadv_nc_tvlv_ogm_handler_v1 - process incoming nc tvlv container | ||
96 | * @bat_priv: the bat priv with all the soft interface information | ||
97 | * @orig: the orig_node of the ogm | ||
98 | * @flags: flags indicating the tvlv state (see batadv_tvlv_handler_flags) | ||
99 | * @tvlv_value: tvlv buffer containing the gateway data | ||
100 | * @tvlv_value_len: tvlv buffer length | ||
101 | */ | ||
102 | static void batadv_nc_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv, | ||
103 | struct batadv_orig_node *orig, | ||
104 | uint8_t flags, | ||
105 | void *tvlv_value, | ||
106 | uint16_t tvlv_value_len) | ||
107 | { | ||
108 | if (flags & BATADV_TVLV_HANDLER_OGM_CIFNOTFND) | ||
109 | orig->capabilities &= ~BATADV_ORIG_CAPA_HAS_NC; | ||
110 | else | ||
111 | orig->capabilities |= BATADV_ORIG_CAPA_HAS_NC; | ||
112 | } | ||
113 | |||
114 | /** | ||
62 | * batadv_nc_mesh_init - initialise coding hash table and start house keeping | 115 | * batadv_nc_mesh_init - initialise coding hash table and start house keeping |
63 | * @bat_priv: the bat priv with all the soft interface information | 116 | * @bat_priv: the bat priv with all the soft interface information |
64 | */ | 117 | */ |
@@ -87,6 +140,10 @@ int batadv_nc_mesh_init(struct batadv_priv *bat_priv) | |||
87 | INIT_DELAYED_WORK(&bat_priv->nc.work, batadv_nc_worker); | 140 | INIT_DELAYED_WORK(&bat_priv->nc.work, batadv_nc_worker); |
88 | batadv_nc_start_timer(bat_priv); | 141 | batadv_nc_start_timer(bat_priv); |
89 | 142 | ||
143 | batadv_tvlv_handler_register(bat_priv, batadv_nc_tvlv_ogm_handler_v1, | ||
144 | NULL, BATADV_TVLV_NC, 1, | ||
145 | BATADV_TVLV_HANDLER_OGM_CIFNOTFND); | ||
146 | batadv_nc_tvlv_container_update(bat_priv); | ||
90 | return 0; | 147 | return 0; |
91 | 148 | ||
92 | err: | 149 | err: |
@@ -802,6 +859,10 @@ void batadv_nc_update_nc_node(struct batadv_priv *bat_priv, | |||
802 | if (!atomic_read(&bat_priv->network_coding)) | 859 | if (!atomic_read(&bat_priv->network_coding)) |
803 | goto out; | 860 | goto out; |
804 | 861 | ||
862 | /* check if orig node is network coding enabled */ | ||
863 | if (!(orig_node->capabilities & BATADV_ORIG_CAPA_HAS_NC)) | ||
864 | goto out; | ||
865 | |||
805 | /* accept ogms from 'good' neighbors and single hop neighbors */ | 866 | /* accept ogms from 'good' neighbors and single hop neighbors */ |
806 | if (!batadv_can_nc_with_orig(bat_priv, orig_node, ogm_packet) && | 867 | if (!batadv_can_nc_with_orig(bat_priv, orig_node, ogm_packet) && |
807 | !is_single_hop_neigh) | 868 | !is_single_hop_neigh) |
@@ -1735,6 +1796,8 @@ free_nc_packet: | |||
1735 | */ | 1796 | */ |
1736 | void batadv_nc_mesh_free(struct batadv_priv *bat_priv) | 1797 | void batadv_nc_mesh_free(struct batadv_priv *bat_priv) |
1737 | { | 1798 | { |
1799 | batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_NC, 1); | ||
1800 | batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_NC, 1); | ||
1738 | cancel_delayed_work_sync(&bat_priv->nc.work); | 1801 | cancel_delayed_work_sync(&bat_priv->nc.work); |
1739 | 1802 | ||
1740 | batadv_nc_purge_paths(bat_priv, bat_priv->nc.coding_hash, NULL); | 1803 | batadv_nc_purge_paths(bat_priv, bat_priv->nc.coding_hash, NULL); |
diff --git a/net/batman-adv/network-coding.h b/net/batman-adv/network-coding.h index ddfa618e80bf..d4fd315b5261 100644 --- a/net/batman-adv/network-coding.h +++ b/net/batman-adv/network-coding.h | |||
@@ -22,6 +22,7 @@ | |||
22 | 22 | ||
23 | #ifdef CONFIG_BATMAN_ADV_NC | 23 | #ifdef CONFIG_BATMAN_ADV_NC |
24 | 24 | ||
25 | void batadv_nc_status_update(struct net_device *net_dev); | ||
25 | int batadv_nc_init(void); | 26 | int batadv_nc_init(void); |
26 | int batadv_nc_mesh_init(struct batadv_priv *bat_priv); | 27 | int batadv_nc_mesh_init(struct batadv_priv *bat_priv); |
27 | void batadv_nc_mesh_free(struct batadv_priv *bat_priv); | 28 | void batadv_nc_mesh_free(struct batadv_priv *bat_priv); |
@@ -47,6 +48,10 @@ int batadv_nc_init_debugfs(struct batadv_priv *bat_priv); | |||
47 | 48 | ||
48 | #else /* ifdef CONFIG_BATMAN_ADV_NC */ | 49 | #else /* ifdef CONFIG_BATMAN_ADV_NC */ |
49 | 50 | ||
51 | static inline void batadv_nc_status_update(struct net_device *net_dev) | ||
52 | { | ||
53 | } | ||
54 | |||
50 | static inline int batadv_nc_init(void) | 55 | static inline int batadv_nc_init(void) |
51 | { | 56 | { |
52 | return 0; | 57 | return 0; |
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index f50553a7de62..ee1d84724205 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c | |||
@@ -25,10 +25,10 @@ | |||
25 | #include "routing.h" | 25 | #include "routing.h" |
26 | #include "gateway_client.h" | 26 | #include "gateway_client.h" |
27 | #include "hard-interface.h" | 27 | #include "hard-interface.h" |
28 | #include "unicast.h" | ||
29 | #include "soft-interface.h" | 28 | #include "soft-interface.h" |
30 | #include "bridge_loop_avoidance.h" | 29 | #include "bridge_loop_avoidance.h" |
31 | #include "network-coding.h" | 30 | #include "network-coding.h" |
31 | #include "fragmentation.h" | ||
32 | 32 | ||
33 | /* hash class keys */ | 33 | /* hash class keys */ |
34 | static struct lock_class_key batadv_orig_hash_lock_class_key; | 34 | static struct lock_class_key batadv_orig_hash_lock_class_key; |
@@ -44,6 +44,88 @@ static int batadv_compare_orig(const struct hlist_node *node, const void *data2) | |||
44 | return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0); | 44 | return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0); |
45 | } | 45 | } |
46 | 46 | ||
47 | /** | ||
48 | * batadv_orig_node_vlan_get - get an orig_node_vlan object | ||
49 | * @orig_node: the originator serving the VLAN | ||
50 | * @vid: the VLAN identifier | ||
51 | * | ||
52 | * Returns the vlan object identified by vid and belonging to orig_node or NULL | ||
53 | * if it does not exist. | ||
54 | */ | ||
55 | struct batadv_orig_node_vlan * | ||
56 | batadv_orig_node_vlan_get(struct batadv_orig_node *orig_node, | ||
57 | unsigned short vid) | ||
58 | { | ||
59 | struct batadv_orig_node_vlan *vlan = NULL, *tmp; | ||
60 | |||
61 | rcu_read_lock(); | ||
62 | list_for_each_entry_rcu(tmp, &orig_node->vlan_list, list) { | ||
63 | if (tmp->vid != vid) | ||
64 | continue; | ||
65 | |||
66 | if (!atomic_inc_not_zero(&tmp->refcount)) | ||
67 | continue; | ||
68 | |||
69 | vlan = tmp; | ||
70 | |||
71 | break; | ||
72 | } | ||
73 | rcu_read_unlock(); | ||
74 | |||
75 | return vlan; | ||
76 | } | ||
77 | |||
78 | /** | ||
79 | * batadv_orig_node_vlan_new - search and possibly create an orig_node_vlan | ||
80 | * object | ||
81 | * @orig_node: the originator serving the VLAN | ||
82 | * @vid: the VLAN identifier | ||
83 | * | ||
84 | * Returns NULL in case of failure or the vlan object identified by vid and | ||
85 | * belonging to orig_node otherwise. The object is created and added to the list | ||
86 | * if it does not exist. | ||
87 | * | ||
88 | * The object is returned with refcounter increased by 1. | ||
89 | */ | ||
90 | struct batadv_orig_node_vlan * | ||
91 | batadv_orig_node_vlan_new(struct batadv_orig_node *orig_node, | ||
92 | unsigned short vid) | ||
93 | { | ||
94 | struct batadv_orig_node_vlan *vlan; | ||
95 | |||
96 | spin_lock_bh(&orig_node->vlan_list_lock); | ||
97 | |||
98 | /* first look if an object for this vid already exists */ | ||
99 | vlan = batadv_orig_node_vlan_get(orig_node, vid); | ||
100 | if (vlan) | ||
101 | goto out; | ||
102 | |||
103 | vlan = kzalloc(sizeof(*vlan), GFP_ATOMIC); | ||
104 | if (!vlan) | ||
105 | goto out; | ||
106 | |||
107 | atomic_set(&vlan->refcount, 2); | ||
108 | vlan->vid = vid; | ||
109 | |||
110 | list_add_rcu(&vlan->list, &orig_node->vlan_list); | ||
111 | |||
112 | out: | ||
113 | spin_unlock_bh(&orig_node->vlan_list_lock); | ||
114 | |||
115 | return vlan; | ||
116 | } | ||
117 | |||
118 | /** | ||
119 | * batadv_orig_node_vlan_free_ref - decrement the refcounter and possibly free | ||
120 | * the originator-vlan object | ||
121 | * @orig_vlan: the originator-vlan object to release | ||
122 | */ | ||
123 | void batadv_orig_node_vlan_free_ref(struct batadv_orig_node_vlan *orig_vlan) | ||
124 | { | ||
125 | if (atomic_dec_and_test(&orig_vlan->refcount)) | ||
126 | kfree_rcu(orig_vlan, rcu); | ||
127 | } | ||
128 | |||
47 | int batadv_originator_init(struct batadv_priv *bat_priv) | 129 | int batadv_originator_init(struct batadv_priv *bat_priv) |
48 | { | 130 | { |
49 | if (bat_priv->orig_hash) | 131 | if (bat_priv->orig_hash) |
@@ -146,8 +228,9 @@ static void batadv_orig_node_free_rcu(struct rcu_head *rcu) | |||
146 | /* Free nc_nodes */ | 228 | /* Free nc_nodes */ |
147 | batadv_nc_purge_orig(orig_node->bat_priv, orig_node, NULL); | 229 | batadv_nc_purge_orig(orig_node->bat_priv, orig_node, NULL); |
148 | 230 | ||
149 | batadv_frag_list_free(&orig_node->frag_list); | 231 | batadv_frag_purge_orig(orig_node, NULL); |
150 | batadv_tt_global_del_orig(orig_node->bat_priv, orig_node, | 232 | |
233 | batadv_tt_global_del_orig(orig_node->bat_priv, orig_node, -1, | ||
151 | "originator timed out"); | 234 | "originator timed out"); |
152 | 235 | ||
153 | kfree(orig_node->tt_buff); | 236 | kfree(orig_node->tt_buff); |
@@ -217,7 +300,8 @@ struct batadv_orig_node *batadv_get_orig_node(struct batadv_priv *bat_priv, | |||
217 | const uint8_t *addr) | 300 | const uint8_t *addr) |
218 | { | 301 | { |
219 | struct batadv_orig_node *orig_node; | 302 | struct batadv_orig_node *orig_node; |
220 | int size; | 303 | struct batadv_orig_node_vlan *vlan; |
304 | int size, i; | ||
221 | int hash_added; | 305 | int hash_added; |
222 | unsigned long reset_time; | 306 | unsigned long reset_time; |
223 | 307 | ||
@@ -234,10 +318,13 @@ struct batadv_orig_node *batadv_get_orig_node(struct batadv_priv *bat_priv, | |||
234 | 318 | ||
235 | INIT_HLIST_HEAD(&orig_node->neigh_list); | 319 | INIT_HLIST_HEAD(&orig_node->neigh_list); |
236 | INIT_LIST_HEAD(&orig_node->bond_list); | 320 | INIT_LIST_HEAD(&orig_node->bond_list); |
321 | INIT_LIST_HEAD(&orig_node->vlan_list); | ||
237 | spin_lock_init(&orig_node->ogm_cnt_lock); | 322 | spin_lock_init(&orig_node->ogm_cnt_lock); |
238 | spin_lock_init(&orig_node->bcast_seqno_lock); | 323 | spin_lock_init(&orig_node->bcast_seqno_lock); |
239 | spin_lock_init(&orig_node->neigh_list_lock); | 324 | spin_lock_init(&orig_node->neigh_list_lock); |
240 | spin_lock_init(&orig_node->tt_buff_lock); | 325 | spin_lock_init(&orig_node->tt_buff_lock); |
326 | spin_lock_init(&orig_node->tt_lock); | ||
327 | spin_lock_init(&orig_node->vlan_list_lock); | ||
241 | 328 | ||
242 | batadv_nc_init_orig(orig_node); | 329 | batadv_nc_init_orig(orig_node); |
243 | 330 | ||
@@ -249,28 +336,39 @@ struct batadv_orig_node *batadv_get_orig_node(struct batadv_priv *bat_priv, | |||
249 | memcpy(orig_node->orig, addr, ETH_ALEN); | 336 | memcpy(orig_node->orig, addr, ETH_ALEN); |
250 | batadv_dat_init_orig_node_addr(orig_node); | 337 | batadv_dat_init_orig_node_addr(orig_node); |
251 | orig_node->router = NULL; | 338 | orig_node->router = NULL; |
252 | orig_node->tt_crc = 0; | ||
253 | atomic_set(&orig_node->last_ttvn, 0); | 339 | atomic_set(&orig_node->last_ttvn, 0); |
254 | orig_node->tt_buff = NULL; | 340 | orig_node->tt_buff = NULL; |
255 | orig_node->tt_buff_len = 0; | 341 | orig_node->tt_buff_len = 0; |
256 | atomic_set(&orig_node->tt_size, 0); | ||
257 | reset_time = jiffies - 1 - msecs_to_jiffies(BATADV_RESET_PROTECTION_MS); | 342 | reset_time = jiffies - 1 - msecs_to_jiffies(BATADV_RESET_PROTECTION_MS); |
258 | orig_node->bcast_seqno_reset = reset_time; | 343 | orig_node->bcast_seqno_reset = reset_time; |
259 | orig_node->batman_seqno_reset = reset_time; | 344 | orig_node->batman_seqno_reset = reset_time; |
260 | 345 | ||
261 | atomic_set(&orig_node->bond_candidates, 0); | 346 | atomic_set(&orig_node->bond_candidates, 0); |
262 | 347 | ||
348 | /* create a vlan object for the "untagged" LAN */ | ||
349 | vlan = batadv_orig_node_vlan_new(orig_node, BATADV_NO_FLAGS); | ||
350 | if (!vlan) | ||
351 | goto free_orig_node; | ||
352 | /* batadv_orig_node_vlan_new() increases the refcounter. | ||
353 | * Immediately release vlan since it is not needed anymore in this | ||
354 | * context | ||
355 | */ | ||
356 | batadv_orig_node_vlan_free_ref(vlan); | ||
357 | |||
263 | size = bat_priv->num_ifaces * sizeof(unsigned long) * BATADV_NUM_WORDS; | 358 | size = bat_priv->num_ifaces * sizeof(unsigned long) * BATADV_NUM_WORDS; |
264 | 359 | ||
265 | orig_node->bcast_own = kzalloc(size, GFP_ATOMIC); | 360 | orig_node->bcast_own = kzalloc(size, GFP_ATOMIC); |
266 | if (!orig_node->bcast_own) | 361 | if (!orig_node->bcast_own) |
267 | goto free_orig_node; | 362 | goto free_vlan; |
268 | 363 | ||
269 | size = bat_priv->num_ifaces * sizeof(uint8_t); | 364 | size = bat_priv->num_ifaces * sizeof(uint8_t); |
270 | orig_node->bcast_own_sum = kzalloc(size, GFP_ATOMIC); | 365 | orig_node->bcast_own_sum = kzalloc(size, GFP_ATOMIC); |
271 | 366 | ||
272 | INIT_LIST_HEAD(&orig_node->frag_list); | 367 | for (i = 0; i < BATADV_FRAG_BUFFER_COUNT; i++) { |
273 | orig_node->last_frag_packet = 0; | 368 | INIT_HLIST_HEAD(&orig_node->fragments[i].head); |
369 | spin_lock_init(&orig_node->fragments[i].lock); | ||
370 | orig_node->fragments[i].size = 0; | ||
371 | } | ||
274 | 372 | ||
275 | if (!orig_node->bcast_own_sum) | 373 | if (!orig_node->bcast_own_sum) |
276 | goto free_bcast_own; | 374 | goto free_bcast_own; |
@@ -286,6 +384,8 @@ free_bcast_own_sum: | |||
286 | kfree(orig_node->bcast_own_sum); | 384 | kfree(orig_node->bcast_own_sum); |
287 | free_bcast_own: | 385 | free_bcast_own: |
288 | kfree(orig_node->bcast_own); | 386 | kfree(orig_node->bcast_own); |
387 | free_vlan: | ||
388 | batadv_orig_node_vlan_free_ref(vlan); | ||
289 | free_orig_node: | 389 | free_orig_node: |
290 | kfree(orig_node); | 390 | kfree(orig_node); |
291 | return NULL; | 391 | return NULL; |
@@ -388,17 +488,14 @@ static void _batadv_purge_orig(struct batadv_priv *bat_priv) | |||
388 | hlist_for_each_entry_safe(orig_node, node_tmp, | 488 | hlist_for_each_entry_safe(orig_node, node_tmp, |
389 | head, hash_entry) { | 489 | head, hash_entry) { |
390 | if (batadv_purge_orig_node(bat_priv, orig_node)) { | 490 | if (batadv_purge_orig_node(bat_priv, orig_node)) { |
391 | if (orig_node->gw_flags) | 491 | batadv_gw_node_delete(bat_priv, orig_node); |
392 | batadv_gw_node_delete(bat_priv, | ||
393 | orig_node); | ||
394 | hlist_del_rcu(&orig_node->hash_entry); | 492 | hlist_del_rcu(&orig_node->hash_entry); |
395 | batadv_orig_node_free_ref(orig_node); | 493 | batadv_orig_node_free_ref(orig_node); |
396 | continue; | 494 | continue; |
397 | } | 495 | } |
398 | 496 | ||
399 | if (batadv_has_timed_out(orig_node->last_frag_packet, | 497 | batadv_frag_purge_orig(orig_node, |
400 | BATADV_FRAG_TIMEOUT)) | 498 | batadv_frag_check_entry); |
401 | batadv_frag_list_free(&orig_node->frag_list); | ||
402 | } | 499 | } |
403 | spin_unlock_bh(list_lock); | 500 | spin_unlock_bh(list_lock); |
404 | } | 501 | } |
diff --git a/net/batman-adv/originator.h b/net/batman-adv/originator.h index 7887b84a9af4..cc6d686cfe6d 100644 --- a/net/batman-adv/originator.h +++ b/net/batman-adv/originator.h | |||
@@ -40,6 +40,13 @@ int batadv_orig_hash_add_if(struct batadv_hard_iface *hard_iface, | |||
40 | int max_if_num); | 40 | int max_if_num); |
41 | int batadv_orig_hash_del_if(struct batadv_hard_iface *hard_iface, | 41 | int batadv_orig_hash_del_if(struct batadv_hard_iface *hard_iface, |
42 | int max_if_num); | 42 | int max_if_num); |
43 | struct batadv_orig_node_vlan * | ||
44 | batadv_orig_node_vlan_new(struct batadv_orig_node *orig_node, | ||
45 | unsigned short vid); | ||
46 | struct batadv_orig_node_vlan * | ||
47 | batadv_orig_node_vlan_get(struct batadv_orig_node *orig_node, | ||
48 | unsigned short vid); | ||
49 | void batadv_orig_node_vlan_free_ref(struct batadv_orig_node_vlan *orig_vlan); | ||
43 | 50 | ||
44 | 51 | ||
45 | /* hashfunction to choose an entry in a hash table of given size | 52 | /* hashfunction to choose an entry in a hash table of given size |
diff --git a/net/batman-adv/packet.h b/net/batman-adv/packet.h index a51ccfc39da4..9fbcaacc345a 100644 --- a/net/batman-adv/packet.h +++ b/net/batman-adv/packet.h | |||
@@ -20,17 +20,34 @@ | |||
20 | #ifndef _NET_BATMAN_ADV_PACKET_H_ | 20 | #ifndef _NET_BATMAN_ADV_PACKET_H_ |
21 | #define _NET_BATMAN_ADV_PACKET_H_ | 21 | #define _NET_BATMAN_ADV_PACKET_H_ |
22 | 22 | ||
23 | /** | ||
24 | * enum batadv_packettype - types for batman-adv encapsulated packets | ||
25 | * @BATADV_IV_OGM: originator messages for B.A.T.M.A.N. IV | ||
26 | * @BATADV_BCAST: broadcast packets carrying broadcast payload | ||
27 | * @BATADV_CODED: network coded packets | ||
28 | * | ||
29 | * @BATADV_UNICAST: unicast packets carrying unicast payload traffic | ||
30 | * @BATADV_UNICAST_FRAG: unicast packets carrying a fragment of the original | ||
31 | * payload packet | ||
32 | * @BATADV_UNICAST_4ADDR: unicast packet including the originator address of | ||
33 | * the sender | ||
34 | * @BATADV_ICMP: unicast packet like IP ICMP used for ping or traceroute | ||
35 | * @BATADV_UNICAST_TVLV: unicast packet carrying TVLV containers | ||
36 | */ | ||
23 | enum batadv_packettype { | 37 | enum batadv_packettype { |
24 | BATADV_IV_OGM = 0x01, | 38 | /* 0x00 - 0x3f: local packets or special rules for handling */ |
25 | BATADV_ICMP = 0x02, | 39 | BATADV_IV_OGM = 0x00, |
26 | BATADV_UNICAST = 0x03, | 40 | BATADV_BCAST = 0x01, |
27 | BATADV_BCAST = 0x04, | 41 | BATADV_CODED = 0x02, |
28 | BATADV_VIS = 0x05, | 42 | /* 0x40 - 0x7f: unicast */ |
29 | BATADV_UNICAST_FRAG = 0x06, | 43 | #define BATADV_UNICAST_MIN 0x40 |
30 | BATADV_TT_QUERY = 0x07, | 44 | BATADV_UNICAST = 0x40, |
31 | BATADV_ROAM_ADV = 0x08, | 45 | BATADV_UNICAST_FRAG = 0x41, |
32 | BATADV_UNICAST_4ADDR = 0x09, | 46 | BATADV_UNICAST_4ADDR = 0x42, |
33 | BATADV_CODED = 0x0a, | 47 | BATADV_ICMP = 0x43, |
48 | BATADV_UNICAST_TVLV = 0x44, | ||
49 | #define BATADV_UNICAST_MAX 0x7f | ||
50 | /* 0x80 - 0xff: reserved */ | ||
34 | }; | 51 | }; |
35 | 52 | ||
36 | /** | 53 | /** |
@@ -48,13 +65,21 @@ enum batadv_subtype { | |||
48 | }; | 65 | }; |
49 | 66 | ||
50 | /* this file is included by batctl which needs these defines */ | 67 | /* this file is included by batctl which needs these defines */ |
51 | #define BATADV_COMPAT_VERSION 14 | 68 | #define BATADV_COMPAT_VERSION 15 |
52 | 69 | ||
70 | /** | ||
71 | * enum batadv_iv_flags - flags used in B.A.T.M.A.N. IV OGM packets | ||
72 | * @BATADV_NOT_BEST_NEXT_HOP: flag is set when ogm packet is forwarded and was | ||
73 | * previously received from someone else than the best neighbor. | ||
74 | * @BATADV_PRIMARIES_FIRST_HOP: flag is set when the primary interface address | ||
75 | * is used, and the packet travels its first hop. | ||
76 | * @BATADV_DIRECTLINK: flag is for the first hop or if rebroadcasted from a | ||
77 | * one hop neighbor on the interface where it was originally received. | ||
78 | */ | ||
53 | enum batadv_iv_flags { | 79 | enum batadv_iv_flags { |
54 | BATADV_NOT_BEST_NEXT_HOP = BIT(3), | 80 | BATADV_NOT_BEST_NEXT_HOP = BIT(0), |
55 | BATADV_PRIMARIES_FIRST_HOP = BIT(4), | 81 | BATADV_PRIMARIES_FIRST_HOP = BIT(1), |
56 | BATADV_VIS_SERVER = BIT(5), | 82 | BATADV_DIRECTLINK = BIT(2), |
57 | BATADV_DIRECTLINK = BIT(6), | ||
58 | }; | 83 | }; |
59 | 84 | ||
60 | /* ICMP message types */ | 85 | /* ICMP message types */ |
@@ -66,29 +91,21 @@ enum batadv_icmp_packettype { | |||
66 | BATADV_PARAMETER_PROBLEM = 12, | 91 | BATADV_PARAMETER_PROBLEM = 12, |
67 | }; | 92 | }; |
68 | 93 | ||
69 | /* vis defines */ | 94 | /* tt data subtypes */ |
70 | enum batadv_vis_packettype { | 95 | #define BATADV_TT_DATA_TYPE_MASK 0x0F |
71 | BATADV_VIS_TYPE_SERVER_SYNC = 0, | ||
72 | BATADV_VIS_TYPE_CLIENT_UPDATE = 1, | ||
73 | }; | ||
74 | |||
75 | /* fragmentation defines */ | ||
76 | enum batadv_unicast_frag_flags { | ||
77 | BATADV_UNI_FRAG_HEAD = BIT(0), | ||
78 | BATADV_UNI_FRAG_LARGETAIL = BIT(1), | ||
79 | }; | ||
80 | 96 | ||
81 | /* TT_QUERY subtypes */ | 97 | /** |
82 | #define BATADV_TT_QUERY_TYPE_MASK 0x3 | 98 | * enum batadv_tt_data_flags - flags for tt data tvlv |
83 | 99 | * @BATADV_TT_OGM_DIFF: TT diff propagated through OGM | |
84 | enum batadv_tt_query_packettype { | 100 | * @BATADV_TT_REQUEST: TT request message |
85 | BATADV_TT_REQUEST = 0, | 101 | * @BATADV_TT_RESPONSE: TT response message |
86 | BATADV_TT_RESPONSE = 1, | 102 | * @BATADV_TT_FULL_TABLE: contains full table to replace existing table |
87 | }; | 103 | */ |
88 | 104 | enum batadv_tt_data_flags { | |
89 | /* TT_QUERY flags */ | 105 | BATADV_TT_OGM_DIFF = BIT(0), |
90 | enum batadv_tt_query_flags { | 106 | BATADV_TT_REQUEST = BIT(1), |
91 | BATADV_TT_FULL_TABLE = BIT(2), | 107 | BATADV_TT_RESPONSE = BIT(2), |
108 | BATADV_TT_FULL_TABLE = BIT(4), | ||
92 | }; | 109 | }; |
93 | 110 | ||
94 | /* BATADV_TT_CLIENT flags. | 111 | /* BATADV_TT_CLIENT flags. |
@@ -99,10 +116,18 @@ enum batadv_tt_client_flags { | |||
99 | BATADV_TT_CLIENT_DEL = BIT(0), | 116 | BATADV_TT_CLIENT_DEL = BIT(0), |
100 | BATADV_TT_CLIENT_ROAM = BIT(1), | 117 | BATADV_TT_CLIENT_ROAM = BIT(1), |
101 | BATADV_TT_CLIENT_WIFI = BIT(2), | 118 | BATADV_TT_CLIENT_WIFI = BIT(2), |
102 | BATADV_TT_CLIENT_TEMP = BIT(3), | ||
103 | BATADV_TT_CLIENT_NOPURGE = BIT(8), | 119 | BATADV_TT_CLIENT_NOPURGE = BIT(8), |
104 | BATADV_TT_CLIENT_NEW = BIT(9), | 120 | BATADV_TT_CLIENT_NEW = BIT(9), |
105 | BATADV_TT_CLIENT_PENDING = BIT(10), | 121 | BATADV_TT_CLIENT_PENDING = BIT(10), |
122 | BATADV_TT_CLIENT_TEMP = BIT(11), | ||
123 | }; | ||
124 | |||
125 | /** | ||
126 | * batadv_vlan_flags - flags for the four MSB of any vlan ID field | ||
127 | * @BATADV_VLAN_HAS_TAG: whether the field contains a valid vlan tag or not | ||
128 | */ | ||
129 | enum batadv_vlan_flags { | ||
130 | BATADV_VLAN_HAS_TAG = BIT(15), | ||
106 | }; | 131 | }; |
107 | 132 | ||
108 | /* claim frame types for the bridge loop avoidance */ | 133 | /* claim frame types for the bridge loop avoidance */ |
@@ -113,6 +138,22 @@ enum batadv_bla_claimframe { | |||
113 | BATADV_CLAIM_TYPE_REQUEST = 0x03, | 138 | BATADV_CLAIM_TYPE_REQUEST = 0x03, |
114 | }; | 139 | }; |
115 | 140 | ||
141 | /** | ||
142 | * enum batadv_tvlv_type - tvlv type definitions | ||
143 | * @BATADV_TVLV_GW: gateway tvlv | ||
144 | * @BATADV_TVLV_DAT: distributed arp table tvlv | ||
145 | * @BATADV_TVLV_NC: network coding tvlv | ||
146 | * @BATADV_TVLV_TT: translation table tvlv | ||
147 | * @BATADV_TVLV_ROAM: roaming advertisement tvlv | ||
148 | */ | ||
149 | enum batadv_tvlv_type { | ||
150 | BATADV_TVLV_GW = 0x01, | ||
151 | BATADV_TVLV_DAT = 0x02, | ||
152 | BATADV_TVLV_NC = 0x03, | ||
153 | BATADV_TVLV_TT = 0x04, | ||
154 | BATADV_TVLV_ROAM = 0x05, | ||
155 | }; | ||
156 | |||
116 | /* the destination hardware field in the ARP frame is used to | 157 | /* the destination hardware field in the ARP frame is used to |
117 | * transport the claim type and the group id | 158 | * transport the claim type and the group id |
118 | */ | 159 | */ |
@@ -131,44 +172,69 @@ struct batadv_header { | |||
131 | */ | 172 | */ |
132 | }; | 173 | }; |
133 | 174 | ||
175 | /** | ||
176 | * struct batadv_ogm_packet - ogm (routing protocol) packet | ||
177 | * @header: common batman packet header | ||
178 | * @flags: contains routing relevant flags - see enum batadv_iv_flags | ||
179 | * @tvlv_len: length of tvlv data following the ogm header | ||
180 | */ | ||
134 | struct batadv_ogm_packet { | 181 | struct batadv_ogm_packet { |
135 | struct batadv_header header; | 182 | struct batadv_header header; |
136 | uint8_t flags; /* 0x40: DIRECTLINK flag, 0x20 VIS_SERVER flag... */ | 183 | uint8_t flags; |
137 | __be32 seqno; | 184 | __be32 seqno; |
138 | uint8_t orig[ETH_ALEN]; | 185 | uint8_t orig[ETH_ALEN]; |
139 | uint8_t prev_sender[ETH_ALEN]; | 186 | uint8_t prev_sender[ETH_ALEN]; |
140 | uint8_t gw_flags; /* flags related to gateway class */ | 187 | uint8_t reserved; |
141 | uint8_t tq; | 188 | uint8_t tq; |
142 | uint8_t tt_num_changes; | 189 | __be16 tvlv_len; |
143 | uint8_t ttvn; /* translation table version number */ | 190 | /* __packed is not needed as the struct size is divisible by 4, |
144 | __be16 tt_crc; | 191 | * and the largest data type in this struct has a size of 4. |
145 | } __packed; | 192 | */ |
193 | }; | ||
146 | 194 | ||
147 | #define BATADV_OGM_HLEN sizeof(struct batadv_ogm_packet) | 195 | #define BATADV_OGM_HLEN sizeof(struct batadv_ogm_packet) |
148 | 196 | ||
149 | struct batadv_icmp_packet { | 197 | /** |
198 | * batadv_icmp_header - common ICMP header | ||
199 | * @header: common batman header | ||
200 | * @msg_type: ICMP packet type | ||
201 | * @dst: address of the destination node | ||
202 | * @orig: address of the source node | ||
203 | * @uid: local ICMP socket identifier | ||
204 | */ | ||
205 | struct batadv_icmp_header { | ||
150 | struct batadv_header header; | 206 | struct batadv_header header; |
151 | uint8_t msg_type; /* see ICMP message types above */ | 207 | uint8_t msg_type; /* see ICMP message types above */ |
152 | uint8_t dst[ETH_ALEN]; | 208 | uint8_t dst[ETH_ALEN]; |
153 | uint8_t orig[ETH_ALEN]; | 209 | uint8_t orig[ETH_ALEN]; |
154 | __be16 seqno; | ||
155 | uint8_t uid; | 210 | uint8_t uid; |
211 | }; | ||
212 | |||
213 | /** | ||
214 | * batadv_icmp_packet - ICMP packet | ||
215 | * @icmph: common ICMP header | ||
216 | * @reserved: not used - useful for alignment | ||
217 | * @seqno: ICMP sequence number | ||
218 | */ | ||
219 | struct batadv_icmp_packet { | ||
220 | struct batadv_icmp_header icmph; | ||
156 | uint8_t reserved; | 221 | uint8_t reserved; |
222 | __be16 seqno; | ||
157 | }; | 223 | }; |
158 | 224 | ||
159 | #define BATADV_RR_LEN 16 | 225 | #define BATADV_RR_LEN 16 |
160 | 226 | ||
161 | /* icmp_packet_rr must start with all fields from imcp_packet | 227 | /** |
162 | * as this is assumed by code that handles ICMP packets | 228 | * batadv_icmp_packet_rr - ICMP RouteRecord packet |
229 | * @icmph: common ICMP header | ||
230 | * @rr_cur: number of entries the rr array | ||
231 | * @seqno: ICMP sequence number | ||
232 | * @rr: route record array | ||
163 | */ | 233 | */ |
164 | struct batadv_icmp_packet_rr { | 234 | struct batadv_icmp_packet_rr { |
165 | struct batadv_header header; | 235 | struct batadv_icmp_header icmph; |
166 | uint8_t msg_type; /* see ICMP message types above */ | ||
167 | uint8_t dst[ETH_ALEN]; | ||
168 | uint8_t orig[ETH_ALEN]; | ||
169 | __be16 seqno; | ||
170 | uint8_t uid; | ||
171 | uint8_t rr_cur; | 236 | uint8_t rr_cur; |
237 | __be16 seqno; | ||
172 | uint8_t rr[BATADV_RR_LEN][ETH_ALEN]; | 238 | uint8_t rr[BATADV_RR_LEN][ETH_ALEN]; |
173 | }; | 239 | }; |
174 | 240 | ||
@@ -209,15 +275,32 @@ struct batadv_unicast_4addr_packet { | |||
209 | */ | 275 | */ |
210 | }; | 276 | }; |
211 | 277 | ||
212 | struct batadv_unicast_frag_packet { | 278 | /** |
213 | struct batadv_header header; | 279 | * struct batadv_frag_packet - fragmented packet |
214 | uint8_t ttvn; /* destination translation table version number */ | 280 | * @header: common batman packet header with type, compatversion, and ttl |
215 | uint8_t dest[ETH_ALEN]; | 281 | * @dest: final destination used when routing fragments |
216 | uint8_t flags; | 282 | * @orig: originator of the fragment used when merging the packet |
217 | uint8_t align; | 283 | * @no: fragment number within this sequence |
218 | uint8_t orig[ETH_ALEN]; | 284 | * @reserved: reserved byte for alignment |
219 | __be16 seqno; | 285 | * @seqno: sequence identification |
220 | } __packed; | 286 | * @total_size: size of the merged packet |
287 | */ | ||
288 | struct batadv_frag_packet { | ||
289 | struct batadv_header header; | ||
290 | #if defined(__BIG_ENDIAN_BITFIELD) | ||
291 | uint8_t no:4; | ||
292 | uint8_t reserved:4; | ||
293 | #elif defined(__LITTLE_ENDIAN_BITFIELD) | ||
294 | uint8_t reserved:4; | ||
295 | uint8_t no:4; | ||
296 | #else | ||
297 | #error "unknown bitfield endianess" | ||
298 | #endif | ||
299 | uint8_t dest[ETH_ALEN]; | ||
300 | uint8_t orig[ETH_ALEN]; | ||
301 | __be16 seqno; | ||
302 | __be16 total_size; | ||
303 | }; | ||
221 | 304 | ||
222 | struct batadv_bcast_packet { | 305 | struct batadv_bcast_packet { |
223 | struct batadv_header header; | 306 | struct batadv_header header; |
@@ -231,54 +314,6 @@ struct batadv_bcast_packet { | |||
231 | 314 | ||
232 | #pragma pack() | 315 | #pragma pack() |
233 | 316 | ||
234 | struct batadv_vis_packet { | ||
235 | struct batadv_header header; | ||
236 | uint8_t vis_type; /* which type of vis-participant sent this? */ | ||
237 | __be32 seqno; /* sequence number */ | ||
238 | uint8_t entries; /* number of entries behind this struct */ | ||
239 | uint8_t reserved; | ||
240 | uint8_t vis_orig[ETH_ALEN]; /* originator reporting its neighbors */ | ||
241 | uint8_t target_orig[ETH_ALEN]; /* who should receive this packet */ | ||
242 | uint8_t sender_orig[ETH_ALEN]; /* who sent or forwarded this packet */ | ||
243 | }; | ||
244 | |||
245 | struct batadv_tt_query_packet { | ||
246 | struct batadv_header header; | ||
247 | /* the flag field is a combination of: | ||
248 | * - TT_REQUEST or TT_RESPONSE | ||
249 | * - TT_FULL_TABLE | ||
250 | */ | ||
251 | uint8_t flags; | ||
252 | uint8_t dst[ETH_ALEN]; | ||
253 | uint8_t src[ETH_ALEN]; | ||
254 | /* the ttvn field is: | ||
255 | * if TT_REQUEST: ttvn that triggered the | ||
256 | * request | ||
257 | * if TT_RESPONSE: new ttvn for the src | ||
258 | * orig_node | ||
259 | */ | ||
260 | uint8_t ttvn; | ||
261 | /* tt_data field is: | ||
262 | * if TT_REQUEST: crc associated with the | ||
263 | * ttvn | ||
264 | * if TT_RESPONSE: table_size | ||
265 | */ | ||
266 | __be16 tt_data; | ||
267 | } __packed; | ||
268 | |||
269 | struct batadv_roam_adv_packet { | ||
270 | struct batadv_header header; | ||
271 | uint8_t reserved; | ||
272 | uint8_t dst[ETH_ALEN]; | ||
273 | uint8_t src[ETH_ALEN]; | ||
274 | uint8_t client[ETH_ALEN]; | ||
275 | } __packed; | ||
276 | |||
277 | struct batadv_tt_change { | ||
278 | uint8_t flags; | ||
279 | uint8_t addr[ETH_ALEN]; | ||
280 | } __packed; | ||
281 | |||
282 | /** | 317 | /** |
283 | * struct batadv_coded_packet - network coded packet | 318 | * struct batadv_coded_packet - network coded packet |
284 | * @header: common batman packet header and ttl of first included packet | 319 | * @header: common batman packet header and ttl of first included packet |
@@ -311,4 +346,96 @@ struct batadv_coded_packet { | |||
311 | __be16 coded_len; | 346 | __be16 coded_len; |
312 | }; | 347 | }; |
313 | 348 | ||
349 | /** | ||
350 | * struct batadv_unicast_tvlv - generic unicast packet with tvlv payload | ||
351 | * @header: common batman packet header | ||
352 | * @reserved: reserved field (for packet alignment) | ||
353 | * @src: address of the source | ||
354 | * @dst: address of the destination | ||
355 | * @tvlv_len: length of tvlv data following the unicast tvlv header | ||
356 | * @align: 2 bytes to align the header to a 4 byte boundry | ||
357 | */ | ||
358 | struct batadv_unicast_tvlv_packet { | ||
359 | struct batadv_header header; | ||
360 | uint8_t reserved; | ||
361 | uint8_t dst[ETH_ALEN]; | ||
362 | uint8_t src[ETH_ALEN]; | ||
363 | __be16 tvlv_len; | ||
364 | uint16_t align; | ||
365 | }; | ||
366 | |||
367 | /** | ||
368 | * struct batadv_tvlv_hdr - base tvlv header struct | ||
369 | * @type: tvlv container type (see batadv_tvlv_type) | ||
370 | * @version: tvlv container version | ||
371 | * @len: tvlv container length | ||
372 | */ | ||
373 | struct batadv_tvlv_hdr { | ||
374 | uint8_t type; | ||
375 | uint8_t version; | ||
376 | __be16 len; | ||
377 | }; | ||
378 | |||
379 | /** | ||
380 | * struct batadv_tvlv_gateway_data - gateway data propagated through gw tvlv | ||
381 | * container | ||
382 | * @bandwidth_down: advertised uplink download bandwidth | ||
383 | * @bandwidth_up: advertised uplink upload bandwidth | ||
384 | */ | ||
385 | struct batadv_tvlv_gateway_data { | ||
386 | __be32 bandwidth_down; | ||
387 | __be32 bandwidth_up; | ||
388 | }; | ||
389 | |||
390 | /** | ||
391 | * struct batadv_tvlv_tt_data - tt data propagated through the tt tvlv container | ||
392 | * @flags: translation table flags (see batadv_tt_data_flags) | ||
393 | * @ttvn: translation table version number | ||
394 | * @vlan_num: number of announced VLANs. In the TVLV this struct is followed by | ||
395 | * one batadv_tvlv_tt_vlan_data object per announced vlan | ||
396 | */ | ||
397 | struct batadv_tvlv_tt_data { | ||
398 | uint8_t flags; | ||
399 | uint8_t ttvn; | ||
400 | __be16 num_vlan; | ||
401 | }; | ||
402 | |||
403 | /** | ||
404 | * struct batadv_tvlv_tt_vlan_data - vlan specific tt data propagated through | ||
405 | * the tt tvlv container | ||
406 | * @crc: crc32 checksum of the entries belonging to this vlan | ||
407 | * @vid: vlan identifier | ||
408 | * @reserved: unused, useful for alignment purposes | ||
409 | */ | ||
410 | struct batadv_tvlv_tt_vlan_data { | ||
411 | __be32 crc; | ||
412 | __be16 vid; | ||
413 | uint16_t reserved; | ||
414 | }; | ||
415 | |||
416 | /** | ||
417 | * struct batadv_tvlv_tt_change - translation table diff data | ||
418 | * @flags: status indicators concerning the non-mesh client (see | ||
419 | * batadv_tt_client_flags) | ||
420 | * @reserved: reserved field | ||
421 | * @addr: mac address of non-mesh client that triggered this tt change | ||
422 | * @vid: VLAN identifier | ||
423 | */ | ||
424 | struct batadv_tvlv_tt_change { | ||
425 | uint8_t flags; | ||
426 | uint8_t reserved; | ||
427 | uint8_t addr[ETH_ALEN]; | ||
428 | __be16 vid; | ||
429 | }; | ||
430 | |||
431 | /** | ||
432 | * struct batadv_tvlv_roam_adv - roaming advertisement | ||
433 | * @client: mac address of roaming client | ||
434 | * @vid: VLAN identifier | ||
435 | */ | ||
436 | struct batadv_tvlv_roam_adv { | ||
437 | uint8_t client[ETH_ALEN]; | ||
438 | __be16 vid; | ||
439 | }; | ||
440 | |||
314 | #endif /* _NET_BATMAN_ADV_PACKET_H_ */ | 441 | #endif /* _NET_BATMAN_ADV_PACKET_H_ */ |
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index 0439395d7ba5..4bcf22129ffe 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c | |||
@@ -25,11 +25,12 @@ | |||
25 | #include "icmp_socket.h" | 25 | #include "icmp_socket.h" |
26 | #include "translation-table.h" | 26 | #include "translation-table.h" |
27 | #include "originator.h" | 27 | #include "originator.h" |
28 | #include "vis.h" | ||
29 | #include "unicast.h" | ||
30 | #include "bridge_loop_avoidance.h" | 28 | #include "bridge_loop_avoidance.h" |
31 | #include "distributed-arp-table.h" | 29 | #include "distributed-arp-table.h" |
32 | #include "network-coding.h" | 30 | #include "network-coding.h" |
31 | #include "fragmentation.h" | ||
32 | |||
33 | #include <linux/if_vlan.h> | ||
33 | 34 | ||
34 | static int batadv_route_unicast_packet(struct sk_buff *skb, | 35 | static int batadv_route_unicast_packet(struct sk_buff *skb, |
35 | struct batadv_hard_iface *recv_if); | 36 | struct batadv_hard_iface *recv_if); |
@@ -46,7 +47,7 @@ static void _batadv_update_route(struct batadv_priv *bat_priv, | |||
46 | if ((curr_router) && (!neigh_node)) { | 47 | if ((curr_router) && (!neigh_node)) { |
47 | batadv_dbg(BATADV_DBG_ROUTES, bat_priv, | 48 | batadv_dbg(BATADV_DBG_ROUTES, bat_priv, |
48 | "Deleting route towards: %pM\n", orig_node->orig); | 49 | "Deleting route towards: %pM\n", orig_node->orig); |
49 | batadv_tt_global_del_orig(bat_priv, orig_node, | 50 | batadv_tt_global_del_orig(bat_priv, orig_node, -1, |
50 | "Deleted route towards originator"); | 51 | "Deleted route towards originator"); |
51 | 52 | ||
52 | /* route added */ | 53 | /* route added */ |
@@ -259,7 +260,7 @@ static int batadv_recv_my_icmp_packet(struct batadv_priv *bat_priv, | |||
259 | icmp_packet = (struct batadv_icmp_packet_rr *)skb->data; | 260 | icmp_packet = (struct batadv_icmp_packet_rr *)skb->data; |
260 | 261 | ||
261 | /* add data to device queue */ | 262 | /* add data to device queue */ |
262 | if (icmp_packet->msg_type != BATADV_ECHO_REQUEST) { | 263 | if (icmp_packet->icmph.msg_type != BATADV_ECHO_REQUEST) { |
263 | batadv_socket_receive_packet(icmp_packet, icmp_len); | 264 | batadv_socket_receive_packet(icmp_packet, icmp_len); |
264 | goto out; | 265 | goto out; |
265 | } | 266 | } |
@@ -270,7 +271,7 @@ static int batadv_recv_my_icmp_packet(struct batadv_priv *bat_priv, | |||
270 | 271 | ||
271 | /* answer echo request (ping) */ | 272 | /* answer echo request (ping) */ |
272 | /* get routing information */ | 273 | /* get routing information */ |
273 | orig_node = batadv_orig_hash_find(bat_priv, icmp_packet->orig); | 274 | orig_node = batadv_orig_hash_find(bat_priv, icmp_packet->icmph.orig); |
274 | if (!orig_node) | 275 | if (!orig_node) |
275 | goto out; | 276 | goto out; |
276 | 277 | ||
@@ -280,10 +281,11 @@ static int batadv_recv_my_icmp_packet(struct batadv_priv *bat_priv, | |||
280 | 281 | ||
281 | icmp_packet = (struct batadv_icmp_packet_rr *)skb->data; | 282 | icmp_packet = (struct batadv_icmp_packet_rr *)skb->data; |
282 | 283 | ||
283 | memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN); | 284 | memcpy(icmp_packet->icmph.dst, icmp_packet->icmph.orig, ETH_ALEN); |
284 | memcpy(icmp_packet->orig, primary_if->net_dev->dev_addr, ETH_ALEN); | 285 | memcpy(icmp_packet->icmph.orig, primary_if->net_dev->dev_addr, |
285 | icmp_packet->msg_type = BATADV_ECHO_REPLY; | 286 | ETH_ALEN); |
286 | icmp_packet->header.ttl = BATADV_TTL; | 287 | icmp_packet->icmph.msg_type = BATADV_ECHO_REPLY; |
288 | icmp_packet->icmph.header.ttl = BATADV_TTL; | ||
287 | 289 | ||
288 | if (batadv_send_skb_to_orig(skb, orig_node, NULL) != NET_XMIT_DROP) | 290 | if (batadv_send_skb_to_orig(skb, orig_node, NULL) != NET_XMIT_DROP) |
289 | ret = NET_RX_SUCCESS; | 291 | ret = NET_RX_SUCCESS; |
@@ -307,9 +309,9 @@ static int batadv_recv_icmp_ttl_exceeded(struct batadv_priv *bat_priv, | |||
307 | icmp_packet = (struct batadv_icmp_packet *)skb->data; | 309 | icmp_packet = (struct batadv_icmp_packet *)skb->data; |
308 | 310 | ||
309 | /* send TTL exceeded if packet is an echo request (traceroute) */ | 311 | /* send TTL exceeded if packet is an echo request (traceroute) */ |
310 | if (icmp_packet->msg_type != BATADV_ECHO_REQUEST) { | 312 | if (icmp_packet->icmph.msg_type != BATADV_ECHO_REQUEST) { |
311 | pr_debug("Warning - can't forward icmp packet from %pM to %pM: ttl exceeded\n", | 313 | pr_debug("Warning - can't forward icmp packet from %pM to %pM: ttl exceeded\n", |
312 | icmp_packet->orig, icmp_packet->dst); | 314 | icmp_packet->icmph.orig, icmp_packet->icmph.dst); |
313 | goto out; | 315 | goto out; |
314 | } | 316 | } |
315 | 317 | ||
@@ -318,7 +320,7 @@ static int batadv_recv_icmp_ttl_exceeded(struct batadv_priv *bat_priv, | |||
318 | goto out; | 320 | goto out; |
319 | 321 | ||
320 | /* get routing information */ | 322 | /* get routing information */ |
321 | orig_node = batadv_orig_hash_find(bat_priv, icmp_packet->orig); | 323 | orig_node = batadv_orig_hash_find(bat_priv, icmp_packet->icmph.orig); |
322 | if (!orig_node) | 324 | if (!orig_node) |
323 | goto out; | 325 | goto out; |
324 | 326 | ||
@@ -328,10 +330,11 @@ static int batadv_recv_icmp_ttl_exceeded(struct batadv_priv *bat_priv, | |||
328 | 330 | ||
329 | icmp_packet = (struct batadv_icmp_packet *)skb->data; | 331 | icmp_packet = (struct batadv_icmp_packet *)skb->data; |
330 | 332 | ||
331 | memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN); | 333 | memcpy(icmp_packet->icmph.dst, icmp_packet->icmph.orig, ETH_ALEN); |
332 | memcpy(icmp_packet->orig, primary_if->net_dev->dev_addr, ETH_ALEN); | 334 | memcpy(icmp_packet->icmph.orig, primary_if->net_dev->dev_addr, |
333 | icmp_packet->msg_type = BATADV_TTL_EXCEEDED; | 335 | ETH_ALEN); |
334 | icmp_packet->header.ttl = BATADV_TTL; | 336 | icmp_packet->icmph.msg_type = BATADV_TTL_EXCEEDED; |
337 | icmp_packet->icmph.header.ttl = BATADV_TTL; | ||
335 | 338 | ||
336 | if (batadv_send_skb_to_orig(skb, orig_node, NULL) != NET_XMIT_DROP) | 339 | if (batadv_send_skb_to_orig(skb, orig_node, NULL) != NET_XMIT_DROP) |
337 | ret = NET_RX_SUCCESS; | 340 | ret = NET_RX_SUCCESS; |
@@ -380,7 +383,9 @@ int batadv_recv_icmp_packet(struct sk_buff *skb, | |||
380 | icmp_packet = (struct batadv_icmp_packet_rr *)skb->data; | 383 | icmp_packet = (struct batadv_icmp_packet_rr *)skb->data; |
381 | 384 | ||
382 | /* add record route information if not full */ | 385 | /* add record route information if not full */ |
383 | if ((hdr_size == sizeof(struct batadv_icmp_packet_rr)) && | 386 | if ((icmp_packet->icmph.msg_type == BATADV_ECHO_REPLY || |
387 | icmp_packet->icmph.msg_type == BATADV_ECHO_REQUEST) && | ||
388 | (hdr_size == sizeof(struct batadv_icmp_packet_rr)) && | ||
384 | (icmp_packet->rr_cur < BATADV_RR_LEN)) { | 389 | (icmp_packet->rr_cur < BATADV_RR_LEN)) { |
385 | memcpy(&(icmp_packet->rr[icmp_packet->rr_cur]), | 390 | memcpy(&(icmp_packet->rr[icmp_packet->rr_cur]), |
386 | ethhdr->h_dest, ETH_ALEN); | 391 | ethhdr->h_dest, ETH_ALEN); |
@@ -388,15 +393,15 @@ int batadv_recv_icmp_packet(struct sk_buff *skb, | |||
388 | } | 393 | } |
389 | 394 | ||
390 | /* packet for me */ | 395 | /* packet for me */ |
391 | if (batadv_is_my_mac(bat_priv, icmp_packet->dst)) | 396 | if (batadv_is_my_mac(bat_priv, icmp_packet->icmph.dst)) |
392 | return batadv_recv_my_icmp_packet(bat_priv, skb, hdr_size); | 397 | return batadv_recv_my_icmp_packet(bat_priv, skb, hdr_size); |
393 | 398 | ||
394 | /* TTL exceeded */ | 399 | /* TTL exceeded */ |
395 | if (icmp_packet->header.ttl < 2) | 400 | if (icmp_packet->icmph.header.ttl < 2) |
396 | return batadv_recv_icmp_ttl_exceeded(bat_priv, skb); | 401 | return batadv_recv_icmp_ttl_exceeded(bat_priv, skb); |
397 | 402 | ||
398 | /* get routing information */ | 403 | /* get routing information */ |
399 | orig_node = batadv_orig_hash_find(bat_priv, icmp_packet->dst); | 404 | orig_node = batadv_orig_hash_find(bat_priv, icmp_packet->icmph.dst); |
400 | if (!orig_node) | 405 | if (!orig_node) |
401 | goto out; | 406 | goto out; |
402 | 407 | ||
@@ -407,7 +412,7 @@ int batadv_recv_icmp_packet(struct sk_buff *skb, | |||
407 | icmp_packet = (struct batadv_icmp_packet_rr *)skb->data; | 412 | icmp_packet = (struct batadv_icmp_packet_rr *)skb->data; |
408 | 413 | ||
409 | /* decrement ttl */ | 414 | /* decrement ttl */ |
410 | icmp_packet->header.ttl--; | 415 | icmp_packet->icmph.header.ttl--; |
411 | 416 | ||
412 | /* route it */ | 417 | /* route it */ |
413 | if (batadv_send_skb_to_orig(skb, orig_node, recv_if) != NET_XMIT_DROP) | 418 | if (batadv_send_skb_to_orig(skb, orig_node, recv_if) != NET_XMIT_DROP) |
@@ -557,126 +562,6 @@ static int batadv_check_unicast_packet(struct batadv_priv *bat_priv, | |||
557 | return 0; | 562 | return 0; |
558 | } | 563 | } |
559 | 564 | ||
560 | int batadv_recv_tt_query(struct sk_buff *skb, struct batadv_hard_iface *recv_if) | ||
561 | { | ||
562 | struct batadv_priv *bat_priv = netdev_priv(recv_if->soft_iface); | ||
563 | struct batadv_tt_query_packet *tt_query; | ||
564 | uint16_t tt_size; | ||
565 | int hdr_size = sizeof(*tt_query); | ||
566 | char tt_flag; | ||
567 | size_t packet_size; | ||
568 | |||
569 | if (batadv_check_unicast_packet(bat_priv, skb, hdr_size) < 0) | ||
570 | return NET_RX_DROP; | ||
571 | |||
572 | /* I could need to modify it */ | ||
573 | if (skb_cow(skb, sizeof(struct batadv_tt_query_packet)) < 0) | ||
574 | goto out; | ||
575 | |||
576 | tt_query = (struct batadv_tt_query_packet *)skb->data; | ||
577 | |||
578 | switch (tt_query->flags & BATADV_TT_QUERY_TYPE_MASK) { | ||
579 | case BATADV_TT_REQUEST: | ||
580 | batadv_inc_counter(bat_priv, BATADV_CNT_TT_REQUEST_RX); | ||
581 | |||
582 | /* If we cannot provide an answer the tt_request is | ||
583 | * forwarded | ||
584 | */ | ||
585 | if (!batadv_send_tt_response(bat_priv, tt_query)) { | ||
586 | if (tt_query->flags & BATADV_TT_FULL_TABLE) | ||
587 | tt_flag = 'F'; | ||
588 | else | ||
589 | tt_flag = '.'; | ||
590 | |||
591 | batadv_dbg(BATADV_DBG_TT, bat_priv, | ||
592 | "Routing TT_REQUEST to %pM [%c]\n", | ||
593 | tt_query->dst, | ||
594 | tt_flag); | ||
595 | return batadv_route_unicast_packet(skb, recv_if); | ||
596 | } | ||
597 | break; | ||
598 | case BATADV_TT_RESPONSE: | ||
599 | batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_RX); | ||
600 | |||
601 | if (batadv_is_my_mac(bat_priv, tt_query->dst)) { | ||
602 | /* packet needs to be linearized to access the TT | ||
603 | * changes | ||
604 | */ | ||
605 | if (skb_linearize(skb) < 0) | ||
606 | goto out; | ||
607 | /* skb_linearize() possibly changed skb->data */ | ||
608 | tt_query = (struct batadv_tt_query_packet *)skb->data; | ||
609 | |||
610 | tt_size = batadv_tt_len(ntohs(tt_query->tt_data)); | ||
611 | |||
612 | /* Ensure we have all the claimed data */ | ||
613 | packet_size = sizeof(struct batadv_tt_query_packet); | ||
614 | packet_size += tt_size; | ||
615 | if (unlikely(skb_headlen(skb) < packet_size)) | ||
616 | goto out; | ||
617 | |||
618 | batadv_handle_tt_response(bat_priv, tt_query); | ||
619 | } else { | ||
620 | if (tt_query->flags & BATADV_TT_FULL_TABLE) | ||
621 | tt_flag = 'F'; | ||
622 | else | ||
623 | tt_flag = '.'; | ||
624 | batadv_dbg(BATADV_DBG_TT, bat_priv, | ||
625 | "Routing TT_RESPONSE to %pM [%c]\n", | ||
626 | tt_query->dst, | ||
627 | tt_flag); | ||
628 | return batadv_route_unicast_packet(skb, recv_if); | ||
629 | } | ||
630 | break; | ||
631 | } | ||
632 | |||
633 | out: | ||
634 | /* returning NET_RX_DROP will make the caller function kfree the skb */ | ||
635 | return NET_RX_DROP; | ||
636 | } | ||
637 | |||
638 | int batadv_recv_roam_adv(struct sk_buff *skb, struct batadv_hard_iface *recv_if) | ||
639 | { | ||
640 | struct batadv_priv *bat_priv = netdev_priv(recv_if->soft_iface); | ||
641 | struct batadv_roam_adv_packet *roam_adv_packet; | ||
642 | struct batadv_orig_node *orig_node; | ||
643 | |||
644 | if (batadv_check_unicast_packet(bat_priv, skb, | ||
645 | sizeof(*roam_adv_packet)) < 0) | ||
646 | goto out; | ||
647 | |||
648 | batadv_inc_counter(bat_priv, BATADV_CNT_TT_ROAM_ADV_RX); | ||
649 | |||
650 | roam_adv_packet = (struct batadv_roam_adv_packet *)skb->data; | ||
651 | |||
652 | if (!batadv_is_my_mac(bat_priv, roam_adv_packet->dst)) | ||
653 | return batadv_route_unicast_packet(skb, recv_if); | ||
654 | |||
655 | /* check if it is a backbone gateway. we don't accept | ||
656 | * roaming advertisement from it, as it has the same | ||
657 | * entries as we have. | ||
658 | */ | ||
659 | if (batadv_bla_is_backbone_gw_orig(bat_priv, roam_adv_packet->src)) | ||
660 | goto out; | ||
661 | |||
662 | orig_node = batadv_orig_hash_find(bat_priv, roam_adv_packet->src); | ||
663 | if (!orig_node) | ||
664 | goto out; | ||
665 | |||
666 | batadv_dbg(BATADV_DBG_TT, bat_priv, | ||
667 | "Received ROAMING_ADV from %pM (client %pM)\n", | ||
668 | roam_adv_packet->src, roam_adv_packet->client); | ||
669 | |||
670 | batadv_tt_global_add(bat_priv, orig_node, roam_adv_packet->client, | ||
671 | BATADV_TT_CLIENT_ROAM, | ||
672 | atomic_read(&orig_node->last_ttvn) + 1); | ||
673 | |||
674 | batadv_orig_node_free_ref(orig_node); | ||
675 | out: | ||
676 | /* returning NET_RX_DROP will make the caller function kfree the skb */ | ||
677 | return NET_RX_DROP; | ||
678 | } | ||
679 | |||
680 | /* find a suitable router for this originator, and use | 565 | /* find a suitable router for this originator, and use |
681 | * bonding if possible. increases the found neighbors | 566 | * bonding if possible. increases the found neighbors |
682 | * refcount. | 567 | * refcount. |
@@ -772,11 +657,9 @@ static int batadv_route_unicast_packet(struct sk_buff *skb, | |||
772 | { | 657 | { |
773 | struct batadv_priv *bat_priv = netdev_priv(recv_if->soft_iface); | 658 | struct batadv_priv *bat_priv = netdev_priv(recv_if->soft_iface); |
774 | struct batadv_orig_node *orig_node = NULL; | 659 | struct batadv_orig_node *orig_node = NULL; |
775 | struct batadv_neigh_node *neigh_node = NULL; | ||
776 | struct batadv_unicast_packet *unicast_packet; | 660 | struct batadv_unicast_packet *unicast_packet; |
777 | struct ethhdr *ethhdr = eth_hdr(skb); | 661 | struct ethhdr *ethhdr = eth_hdr(skb); |
778 | int res, hdr_len, ret = NET_RX_DROP; | 662 | int res, hdr_len, ret = NET_RX_DROP; |
779 | struct sk_buff *new_skb; | ||
780 | 663 | ||
781 | unicast_packet = (struct batadv_unicast_packet *)skb->data; | 664 | unicast_packet = (struct batadv_unicast_packet *)skb->data; |
782 | 665 | ||
@@ -793,46 +676,12 @@ static int batadv_route_unicast_packet(struct sk_buff *skb, | |||
793 | if (!orig_node) | 676 | if (!orig_node) |
794 | goto out; | 677 | goto out; |
795 | 678 | ||
796 | /* find_router() increases neigh_nodes refcount if found. */ | ||
797 | neigh_node = batadv_find_router(bat_priv, orig_node, recv_if); | ||
798 | |||
799 | if (!neigh_node) | ||
800 | goto out; | ||
801 | |||
802 | /* create a copy of the skb, if needed, to modify it. */ | 679 | /* create a copy of the skb, if needed, to modify it. */ |
803 | if (skb_cow(skb, ETH_HLEN) < 0) | 680 | if (skb_cow(skb, ETH_HLEN) < 0) |
804 | goto out; | 681 | goto out; |
805 | 682 | ||
806 | unicast_packet = (struct batadv_unicast_packet *)skb->data; | ||
807 | |||
808 | if (unicast_packet->header.packet_type == BATADV_UNICAST && | ||
809 | atomic_read(&bat_priv->fragmentation) && | ||
810 | skb->len > neigh_node->if_incoming->net_dev->mtu) { | ||
811 | ret = batadv_frag_send_skb(skb, bat_priv, | ||
812 | neigh_node->if_incoming, | ||
813 | neigh_node->addr); | ||
814 | goto out; | ||
815 | } | ||
816 | |||
817 | if (unicast_packet->header.packet_type == BATADV_UNICAST_FRAG && | ||
818 | batadv_frag_can_reassemble(skb, | ||
819 | neigh_node->if_incoming->net_dev->mtu)) { | ||
820 | ret = batadv_frag_reassemble_skb(skb, bat_priv, &new_skb); | ||
821 | |||
822 | if (ret == NET_RX_DROP) | ||
823 | goto out; | ||
824 | |||
825 | /* packet was buffered for late merge */ | ||
826 | if (!new_skb) { | ||
827 | ret = NET_RX_SUCCESS; | ||
828 | goto out; | ||
829 | } | ||
830 | |||
831 | skb = new_skb; | ||
832 | unicast_packet = (struct batadv_unicast_packet *)skb->data; | ||
833 | } | ||
834 | |||
835 | /* decrement ttl */ | 683 | /* decrement ttl */ |
684 | unicast_packet = (struct batadv_unicast_packet *)skb->data; | ||
836 | unicast_packet->header.ttl--; | 685 | unicast_packet->header.ttl--; |
837 | 686 | ||
838 | switch (unicast_packet->header.packet_type) { | 687 | switch (unicast_packet->header.packet_type) { |
@@ -867,8 +716,6 @@ static int batadv_route_unicast_packet(struct sk_buff *skb, | |||
867 | } | 716 | } |
868 | 717 | ||
869 | out: | 718 | out: |
870 | if (neigh_node) | ||
871 | batadv_neigh_node_free_ref(neigh_node); | ||
872 | if (orig_node) | 719 | if (orig_node) |
873 | batadv_orig_node_free_ref(orig_node); | 720 | batadv_orig_node_free_ref(orig_node); |
874 | return ret; | 721 | return ret; |
@@ -879,6 +726,7 @@ out: | |||
879 | * @bat_priv: the bat priv with all the soft interface information | 726 | * @bat_priv: the bat priv with all the soft interface information |
880 | * @unicast_packet: the unicast header to be updated | 727 | * @unicast_packet: the unicast header to be updated |
881 | * @dst_addr: the payload destination | 728 | * @dst_addr: the payload destination |
729 | * @vid: VLAN identifier | ||
882 | * | 730 | * |
883 | * Search the translation table for dst_addr and update the unicast header with | 731 | * Search the translation table for dst_addr and update the unicast header with |
884 | * the new corresponding information (originator address where the destination | 732 | * the new corresponding information (originator address where the destination |
@@ -889,21 +737,22 @@ out: | |||
889 | static bool | 737 | static bool |
890 | batadv_reroute_unicast_packet(struct batadv_priv *bat_priv, | 738 | batadv_reroute_unicast_packet(struct batadv_priv *bat_priv, |
891 | struct batadv_unicast_packet *unicast_packet, | 739 | struct batadv_unicast_packet *unicast_packet, |
892 | uint8_t *dst_addr) | 740 | uint8_t *dst_addr, unsigned short vid) |
893 | { | 741 | { |
894 | struct batadv_orig_node *orig_node = NULL; | 742 | struct batadv_orig_node *orig_node = NULL; |
895 | struct batadv_hard_iface *primary_if = NULL; | 743 | struct batadv_hard_iface *primary_if = NULL; |
896 | bool ret = false; | 744 | bool ret = false; |
897 | uint8_t *orig_addr, orig_ttvn; | 745 | uint8_t *orig_addr, orig_ttvn; |
898 | 746 | ||
899 | if (batadv_is_my_client(bat_priv, dst_addr)) { | 747 | if (batadv_is_my_client(bat_priv, dst_addr, vid)) { |
900 | primary_if = batadv_primary_if_get_selected(bat_priv); | 748 | primary_if = batadv_primary_if_get_selected(bat_priv); |
901 | if (!primary_if) | 749 | if (!primary_if) |
902 | goto out; | 750 | goto out; |
903 | orig_addr = primary_if->net_dev->dev_addr; | 751 | orig_addr = primary_if->net_dev->dev_addr; |
904 | orig_ttvn = (uint8_t)atomic_read(&bat_priv->tt.vn); | 752 | orig_ttvn = (uint8_t)atomic_read(&bat_priv->tt.vn); |
905 | } else { | 753 | } else { |
906 | orig_node = batadv_transtable_search(bat_priv, NULL, dst_addr); | 754 | orig_node = batadv_transtable_search(bat_priv, NULL, dst_addr, |
755 | vid); | ||
907 | if (!orig_node) | 756 | if (!orig_node) |
908 | goto out; | 757 | goto out; |
909 | 758 | ||
@@ -930,11 +779,12 @@ out: | |||
930 | 779 | ||
931 | static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv, | 780 | static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv, |
932 | struct sk_buff *skb, int hdr_len) { | 781 | struct sk_buff *skb, int hdr_len) { |
933 | uint8_t curr_ttvn, old_ttvn; | 782 | struct batadv_unicast_packet *unicast_packet; |
783 | struct batadv_hard_iface *primary_if; | ||
934 | struct batadv_orig_node *orig_node; | 784 | struct batadv_orig_node *orig_node; |
785 | uint8_t curr_ttvn, old_ttvn; | ||
935 | struct ethhdr *ethhdr; | 786 | struct ethhdr *ethhdr; |
936 | struct batadv_hard_iface *primary_if; | 787 | unsigned short vid; |
937 | struct batadv_unicast_packet *unicast_packet; | ||
938 | int is_old_ttvn; | 788 | int is_old_ttvn; |
939 | 789 | ||
940 | /* check if there is enough data before accessing it */ | 790 | /* check if there is enough data before accessing it */ |
@@ -946,6 +796,7 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv, | |||
946 | return 0; | 796 | return 0; |
947 | 797 | ||
948 | unicast_packet = (struct batadv_unicast_packet *)skb->data; | 798 | unicast_packet = (struct batadv_unicast_packet *)skb->data; |
799 | vid = batadv_get_vid(skb, hdr_len); | ||
949 | ethhdr = (struct ethhdr *)(skb->data + hdr_len); | 800 | ethhdr = (struct ethhdr *)(skb->data + hdr_len); |
950 | 801 | ||
951 | /* check if the destination client was served by this node and it is now | 802 | /* check if the destination client was served by this node and it is now |
@@ -953,9 +804,9 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv, | |||
953 | * message and that it knows the new destination in the mesh to re-route | 804 | * message and that it knows the new destination in the mesh to re-route |
954 | * the packet to | 805 | * the packet to |
955 | */ | 806 | */ |
956 | if (batadv_tt_local_client_is_roaming(bat_priv, ethhdr->h_dest)) { | 807 | if (batadv_tt_local_client_is_roaming(bat_priv, ethhdr->h_dest, vid)) { |
957 | if (batadv_reroute_unicast_packet(bat_priv, unicast_packet, | 808 | if (batadv_reroute_unicast_packet(bat_priv, unicast_packet, |
958 | ethhdr->h_dest)) | 809 | ethhdr->h_dest, vid)) |
959 | net_ratelimited_function(batadv_dbg, BATADV_DBG_TT, | 810 | net_ratelimited_function(batadv_dbg, BATADV_DBG_TT, |
960 | bat_priv, | 811 | bat_priv, |
961 | "Rerouting unicast packet to %pM (dst=%pM): Local Roaming\n", | 812 | "Rerouting unicast packet to %pM (dst=%pM): Local Roaming\n", |
@@ -1001,7 +852,7 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv, | |||
1001 | * target host | 852 | * target host |
1002 | */ | 853 | */ |
1003 | if (batadv_reroute_unicast_packet(bat_priv, unicast_packet, | 854 | if (batadv_reroute_unicast_packet(bat_priv, unicast_packet, |
1004 | ethhdr->h_dest)) { | 855 | ethhdr->h_dest, vid)) { |
1005 | net_ratelimited_function(batadv_dbg, BATADV_DBG_TT, bat_priv, | 856 | net_ratelimited_function(batadv_dbg, BATADV_DBG_TT, bat_priv, |
1006 | "Rerouting unicast packet to %pM (dst=%pM): TTVN mismatch old_ttvn=%u new_ttvn=%u\n", | 857 | "Rerouting unicast packet to %pM (dst=%pM): TTVN mismatch old_ttvn=%u new_ttvn=%u\n", |
1007 | unicast_packet->dest, ethhdr->h_dest, | 858 | unicast_packet->dest, ethhdr->h_dest, |
@@ -1013,7 +864,7 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv, | |||
1013 | * currently served by this node or there is no destination at all and | 864 | * currently served by this node or there is no destination at all and |
1014 | * it is possible to drop the packet | 865 | * it is possible to drop the packet |
1015 | */ | 866 | */ |
1016 | if (!batadv_is_my_client(bat_priv, ethhdr->h_dest)) | 867 | if (!batadv_is_my_client(bat_priv, ethhdr->h_dest, vid)) |
1017 | return 0; | 868 | return 0; |
1018 | 869 | ||
1019 | /* update the header in order to let the packet be delivered to this | 870 | /* update the header in order to let the packet be delivered to this |
@@ -1032,6 +883,34 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv, | |||
1032 | return 1; | 883 | return 1; |
1033 | } | 884 | } |
1034 | 885 | ||
886 | /** | ||
887 | * batadv_recv_unhandled_unicast_packet - receive and process packets which | ||
888 | * are in the unicast number space but not yet known to the implementation | ||
889 | * @skb: unicast tvlv packet to process | ||
890 | * @recv_if: pointer to interface this packet was received on | ||
891 | * | ||
892 | * Returns NET_RX_SUCCESS if the packet has been consumed or NET_RX_DROP | ||
893 | * otherwise. | ||
894 | */ | ||
895 | int batadv_recv_unhandled_unicast_packet(struct sk_buff *skb, | ||
896 | struct batadv_hard_iface *recv_if) | ||
897 | { | ||
898 | struct batadv_unicast_packet *unicast_packet; | ||
899 | struct batadv_priv *bat_priv = netdev_priv(recv_if->soft_iface); | ||
900 | int check, hdr_size = sizeof(*unicast_packet); | ||
901 | |||
902 | check = batadv_check_unicast_packet(bat_priv, skb, hdr_size); | ||
903 | if (check < 0) | ||
904 | return NET_RX_DROP; | ||
905 | |||
906 | /* we don't know about this type, drop it. */ | ||
907 | unicast_packet = (struct batadv_unicast_packet *)skb->data; | ||
908 | if (batadv_is_my_mac(bat_priv, unicast_packet->dest)) | ||
909 | return NET_RX_DROP; | ||
910 | |||
911 | return batadv_route_unicast_packet(skb, recv_if); | ||
912 | } | ||
913 | |||
1035 | int batadv_recv_unicast_packet(struct sk_buff *skb, | 914 | int batadv_recv_unicast_packet(struct sk_buff *skb, |
1036 | struct batadv_hard_iface *recv_if) | 915 | struct batadv_hard_iface *recv_if) |
1037 | { | 916 | { |
@@ -1094,51 +973,112 @@ rx_success: | |||
1094 | return batadv_route_unicast_packet(skb, recv_if); | 973 | return batadv_route_unicast_packet(skb, recv_if); |
1095 | } | 974 | } |
1096 | 975 | ||
1097 | int batadv_recv_ucast_frag_packet(struct sk_buff *skb, | 976 | /** |
1098 | struct batadv_hard_iface *recv_if) | 977 | * batadv_recv_unicast_tvlv - receive and process unicast tvlv packets |
978 | * @skb: unicast tvlv packet to process | ||
979 | * @recv_if: pointer to interface this packet was received on | ||
980 | * @dst_addr: the payload destination | ||
981 | * | ||
982 | * Returns NET_RX_SUCCESS if the packet has been consumed or NET_RX_DROP | ||
983 | * otherwise. | ||
984 | */ | ||
985 | int batadv_recv_unicast_tvlv(struct sk_buff *skb, | ||
986 | struct batadv_hard_iface *recv_if) | ||
1099 | { | 987 | { |
1100 | struct batadv_priv *bat_priv = netdev_priv(recv_if->soft_iface); | 988 | struct batadv_priv *bat_priv = netdev_priv(recv_if->soft_iface); |
1101 | struct batadv_unicast_frag_packet *unicast_packet; | 989 | struct batadv_unicast_tvlv_packet *unicast_tvlv_packet; |
1102 | int hdr_size = sizeof(*unicast_packet); | 990 | unsigned char *tvlv_buff; |
1103 | struct sk_buff *new_skb = NULL; | 991 | uint16_t tvlv_buff_len; |
1104 | int ret; | 992 | int hdr_size = sizeof(*unicast_tvlv_packet); |
993 | int ret = NET_RX_DROP; | ||
1105 | 994 | ||
1106 | if (batadv_check_unicast_packet(bat_priv, skb, hdr_size) < 0) | 995 | if (batadv_check_unicast_packet(bat_priv, skb, hdr_size) < 0) |
1107 | return NET_RX_DROP; | 996 | return NET_RX_DROP; |
1108 | 997 | ||
1109 | if (!batadv_check_unicast_ttvn(bat_priv, skb, hdr_size)) | 998 | /* the header is likely to be modified while forwarding */ |
999 | if (skb_cow(skb, hdr_size) < 0) | ||
1110 | return NET_RX_DROP; | 1000 | return NET_RX_DROP; |
1111 | 1001 | ||
1112 | unicast_packet = (struct batadv_unicast_frag_packet *)skb->data; | 1002 | /* packet needs to be linearized to access the tvlv content */ |
1003 | if (skb_linearize(skb) < 0) | ||
1004 | return NET_RX_DROP; | ||
1113 | 1005 | ||
1114 | /* packet for me */ | 1006 | unicast_tvlv_packet = (struct batadv_unicast_tvlv_packet *)skb->data; |
1115 | if (batadv_is_my_mac(bat_priv, unicast_packet->dest)) { | ||
1116 | ret = batadv_frag_reassemble_skb(skb, bat_priv, &new_skb); | ||
1117 | 1007 | ||
1118 | if (ret == NET_RX_DROP) | 1008 | tvlv_buff = (unsigned char *)(skb->data + hdr_size); |
1119 | return NET_RX_DROP; | 1009 | tvlv_buff_len = ntohs(unicast_tvlv_packet->tvlv_len); |
1120 | 1010 | ||
1121 | /* packet was buffered for late merge */ | 1011 | if (tvlv_buff_len > skb->len - hdr_size) |
1122 | if (!new_skb) | 1012 | return NET_RX_DROP; |
1123 | return NET_RX_SUCCESS; | ||
1124 | 1013 | ||
1125 | if (batadv_dat_snoop_incoming_arp_request(bat_priv, new_skb, | 1014 | ret = batadv_tvlv_containers_process(bat_priv, false, NULL, |
1126 | hdr_size)) | 1015 | unicast_tvlv_packet->src, |
1127 | goto rx_success; | 1016 | unicast_tvlv_packet->dst, |
1128 | if (batadv_dat_snoop_incoming_arp_reply(bat_priv, new_skb, | 1017 | tvlv_buff, tvlv_buff_len); |
1129 | hdr_size)) | ||
1130 | goto rx_success; | ||
1131 | 1018 | ||
1132 | batadv_interface_rx(recv_if->soft_iface, new_skb, recv_if, | 1019 | if (ret != NET_RX_SUCCESS) |
1133 | sizeof(struct batadv_unicast_packet), NULL); | 1020 | ret = batadv_route_unicast_packet(skb, recv_if); |
1134 | 1021 | ||
1135 | rx_success: | 1022 | return ret; |
1136 | return NET_RX_SUCCESS; | 1023 | } |
1024 | |||
1025 | /** | ||
1026 | * batadv_recv_frag_packet - process received fragment | ||
1027 | * @skb: the received fragment | ||
1028 | * @recv_if: interface that the skb is received on | ||
1029 | * | ||
1030 | * This function does one of the three following things: 1) Forward fragment, if | ||
1031 | * the assembled packet will exceed our MTU; 2) Buffer fragment, if we till | ||
1032 | * lack further fragments; 3) Merge fragments, if we have all needed parts. | ||
1033 | * | ||
1034 | * Return NET_RX_DROP if the skb is not consumed, NET_RX_SUCCESS otherwise. | ||
1035 | */ | ||
1036 | int batadv_recv_frag_packet(struct sk_buff *skb, | ||
1037 | struct batadv_hard_iface *recv_if) | ||
1038 | { | ||
1039 | struct batadv_priv *bat_priv = netdev_priv(recv_if->soft_iface); | ||
1040 | struct batadv_orig_node *orig_node_src = NULL; | ||
1041 | struct batadv_frag_packet *frag_packet; | ||
1042 | int ret = NET_RX_DROP; | ||
1043 | |||
1044 | if (batadv_check_unicast_packet(bat_priv, skb, | ||
1045 | sizeof(*frag_packet)) < 0) | ||
1046 | goto out; | ||
1047 | |||
1048 | frag_packet = (struct batadv_frag_packet *)skb->data; | ||
1049 | orig_node_src = batadv_orig_hash_find(bat_priv, frag_packet->orig); | ||
1050 | if (!orig_node_src) | ||
1051 | goto out; | ||
1052 | |||
1053 | /* Route the fragment if it is not for us and too big to be merged. */ | ||
1054 | if (!batadv_is_my_mac(bat_priv, frag_packet->dest) && | ||
1055 | batadv_frag_skb_fwd(skb, recv_if, orig_node_src)) { | ||
1056 | ret = NET_RX_SUCCESS; | ||
1057 | goto out; | ||
1137 | } | 1058 | } |
1138 | 1059 | ||
1139 | return batadv_route_unicast_packet(skb, recv_if); | 1060 | batadv_inc_counter(bat_priv, BATADV_CNT_FRAG_RX); |
1140 | } | 1061 | batadv_add_counter(bat_priv, BATADV_CNT_FRAG_RX_BYTES, skb->len); |
1141 | 1062 | ||
1063 | /* Add fragment to buffer and merge if possible. */ | ||
1064 | if (!batadv_frag_skb_buffer(&skb, orig_node_src)) | ||
1065 | goto out; | ||
1066 | |||
1067 | /* Deliver merged packet to the appropriate handler, if it was | ||
1068 | * merged | ||
1069 | */ | ||
1070 | if (skb) | ||
1071 | batadv_batman_skb_recv(skb, recv_if->net_dev, | ||
1072 | &recv_if->batman_adv_ptype, NULL); | ||
1073 | |||
1074 | ret = NET_RX_SUCCESS; | ||
1075 | |||
1076 | out: | ||
1077 | if (orig_node_src) | ||
1078 | batadv_orig_node_free_ref(orig_node_src); | ||
1079 | |||
1080 | return ret; | ||
1081 | } | ||
1142 | 1082 | ||
1143 | int batadv_recv_bcast_packet(struct sk_buff *skb, | 1083 | int batadv_recv_bcast_packet(struct sk_buff *skb, |
1144 | struct batadv_hard_iface *recv_if) | 1084 | struct batadv_hard_iface *recv_if) |
@@ -1240,53 +1180,3 @@ out: | |||
1240 | batadv_orig_node_free_ref(orig_node); | 1180 | batadv_orig_node_free_ref(orig_node); |
1241 | return ret; | 1181 | return ret; |
1242 | } | 1182 | } |
1243 | |||
1244 | int batadv_recv_vis_packet(struct sk_buff *skb, | ||
1245 | struct batadv_hard_iface *recv_if) | ||
1246 | { | ||
1247 | struct batadv_vis_packet *vis_packet; | ||
1248 | struct ethhdr *ethhdr; | ||
1249 | struct batadv_priv *bat_priv = netdev_priv(recv_if->soft_iface); | ||
1250 | int hdr_size = sizeof(*vis_packet); | ||
1251 | |||
1252 | /* keep skb linear */ | ||
1253 | if (skb_linearize(skb) < 0) | ||
1254 | return NET_RX_DROP; | ||
1255 | |||
1256 | if (unlikely(!pskb_may_pull(skb, hdr_size))) | ||
1257 | return NET_RX_DROP; | ||
1258 | |||
1259 | vis_packet = (struct batadv_vis_packet *)skb->data; | ||
1260 | ethhdr = eth_hdr(skb); | ||
1261 | |||
1262 | /* not for me */ | ||
1263 | if (!batadv_is_my_mac(bat_priv, ethhdr->h_dest)) | ||
1264 | return NET_RX_DROP; | ||
1265 | |||
1266 | /* ignore own packets */ | ||
1267 | if (batadv_is_my_mac(bat_priv, vis_packet->vis_orig)) | ||
1268 | return NET_RX_DROP; | ||
1269 | |||
1270 | if (batadv_is_my_mac(bat_priv, vis_packet->sender_orig)) | ||
1271 | return NET_RX_DROP; | ||
1272 | |||
1273 | switch (vis_packet->vis_type) { | ||
1274 | case BATADV_VIS_TYPE_SERVER_SYNC: | ||
1275 | batadv_receive_server_sync_packet(bat_priv, vis_packet, | ||
1276 | skb_headlen(skb)); | ||
1277 | break; | ||
1278 | |||
1279 | case BATADV_VIS_TYPE_CLIENT_UPDATE: | ||
1280 | batadv_receive_client_update_packet(bat_priv, vis_packet, | ||
1281 | skb_headlen(skb)); | ||
1282 | break; | ||
1283 | |||
1284 | default: /* ignore unknown packet */ | ||
1285 | break; | ||
1286 | } | ||
1287 | |||
1288 | /* We take a copy of the data in the packet, so we should | ||
1289 | * always free the skbuf. | ||
1290 | */ | ||
1291 | return NET_RX_DROP; | ||
1292 | } | ||
diff --git a/net/batman-adv/routing.h b/net/batman-adv/routing.h index 72a29bde2010..55d637a90621 100644 --- a/net/batman-adv/routing.h +++ b/net/batman-adv/routing.h | |||
@@ -30,16 +30,18 @@ int batadv_recv_icmp_packet(struct sk_buff *skb, | |||
30 | struct batadv_hard_iface *recv_if); | 30 | struct batadv_hard_iface *recv_if); |
31 | int batadv_recv_unicast_packet(struct sk_buff *skb, | 31 | int batadv_recv_unicast_packet(struct sk_buff *skb, |
32 | struct batadv_hard_iface *recv_if); | 32 | struct batadv_hard_iface *recv_if); |
33 | int batadv_recv_ucast_frag_packet(struct sk_buff *skb, | 33 | int batadv_recv_frag_packet(struct sk_buff *skb, |
34 | struct batadv_hard_iface *recv_if); | 34 | struct batadv_hard_iface *iface); |
35 | int batadv_recv_bcast_packet(struct sk_buff *skb, | 35 | int batadv_recv_bcast_packet(struct sk_buff *skb, |
36 | struct batadv_hard_iface *recv_if); | 36 | struct batadv_hard_iface *recv_if); |
37 | int batadv_recv_vis_packet(struct sk_buff *skb, | ||
38 | struct batadv_hard_iface *recv_if); | ||
39 | int batadv_recv_tt_query(struct sk_buff *skb, | 37 | int batadv_recv_tt_query(struct sk_buff *skb, |
40 | struct batadv_hard_iface *recv_if); | 38 | struct batadv_hard_iface *recv_if); |
41 | int batadv_recv_roam_adv(struct sk_buff *skb, | 39 | int batadv_recv_roam_adv(struct sk_buff *skb, |
42 | struct batadv_hard_iface *recv_if); | 40 | struct batadv_hard_iface *recv_if); |
41 | int batadv_recv_unicast_tvlv(struct sk_buff *skb, | ||
42 | struct batadv_hard_iface *recv_if); | ||
43 | int batadv_recv_unhandled_unicast_packet(struct sk_buff *skb, | ||
44 | struct batadv_hard_iface *recv_if); | ||
43 | struct batadv_neigh_node * | 45 | struct batadv_neigh_node * |
44 | batadv_find_router(struct batadv_priv *bat_priv, | 46 | batadv_find_router(struct batadv_priv *bat_priv, |
45 | struct batadv_orig_node *orig_node, | 47 | struct batadv_orig_node *orig_node, |
diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c index 0266edd0fa7f..c83be5ebaa28 100644 --- a/net/batman-adv/send.c +++ b/net/batman-adv/send.c | |||
@@ -24,12 +24,11 @@ | |||
24 | #include "translation-table.h" | 24 | #include "translation-table.h" |
25 | #include "soft-interface.h" | 25 | #include "soft-interface.h" |
26 | #include "hard-interface.h" | 26 | #include "hard-interface.h" |
27 | #include "vis.h" | ||
28 | #include "gateway_common.h" | 27 | #include "gateway_common.h" |
28 | #include "gateway_client.h" | ||
29 | #include "originator.h" | 29 | #include "originator.h" |
30 | #include "network-coding.h" | 30 | #include "network-coding.h" |
31 | 31 | #include "fragmentation.h" | |
32 | #include <linux/if_ether.h> | ||
33 | 32 | ||
34 | static void batadv_send_outstanding_bcast_packet(struct work_struct *work); | 33 | static void batadv_send_outstanding_bcast_packet(struct work_struct *work); |
35 | 34 | ||
@@ -64,10 +63,10 @@ int batadv_send_skb_packet(struct sk_buff *skb, | |||
64 | ethhdr = eth_hdr(skb); | 63 | ethhdr = eth_hdr(skb); |
65 | memcpy(ethhdr->h_source, hard_iface->net_dev->dev_addr, ETH_ALEN); | 64 | memcpy(ethhdr->h_source, hard_iface->net_dev->dev_addr, ETH_ALEN); |
66 | memcpy(ethhdr->h_dest, dst_addr, ETH_ALEN); | 65 | memcpy(ethhdr->h_dest, dst_addr, ETH_ALEN); |
67 | ethhdr->h_proto = __constant_htons(ETH_P_BATMAN); | 66 | ethhdr->h_proto = htons(ETH_P_BATMAN); |
68 | 67 | ||
69 | skb_set_network_header(skb, ETH_HLEN); | 68 | skb_set_network_header(skb, ETH_HLEN); |
70 | skb->protocol = __constant_htons(ETH_P_BATMAN); | 69 | skb->protocol = htons(ETH_P_BATMAN); |
71 | 70 | ||
72 | skb->dev = hard_iface->net_dev; | 71 | skb->dev = hard_iface->net_dev; |
73 | 72 | ||
@@ -109,7 +108,19 @@ int batadv_send_skb_to_orig(struct sk_buff *skb, | |||
109 | /* batadv_find_router() increases neigh_nodes refcount if found. */ | 108 | /* batadv_find_router() increases neigh_nodes refcount if found. */ |
110 | neigh_node = batadv_find_router(bat_priv, orig_node, recv_if); | 109 | neigh_node = batadv_find_router(bat_priv, orig_node, recv_if); |
111 | if (!neigh_node) | 110 | if (!neigh_node) |
112 | return ret; | 111 | goto out; |
112 | |||
113 | /* Check if the skb is too large to send in one piece and fragment | ||
114 | * it if needed. | ||
115 | */ | ||
116 | if (atomic_read(&bat_priv->fragmentation) && | ||
117 | skb->len > neigh_node->if_incoming->net_dev->mtu) { | ||
118 | /* Fragment and send packet. */ | ||
119 | if (batadv_frag_send_packet(skb, orig_node, neigh_node)) | ||
120 | ret = NET_XMIT_SUCCESS; | ||
121 | |||
122 | goto out; | ||
123 | } | ||
113 | 124 | ||
114 | /* try to network code the packet, if it is received on an interface | 125 | /* try to network code the packet, if it is received on an interface |
115 | * (i.e. being forwarded). If the packet originates from this node or if | 126 | * (i.e. being forwarded). If the packet originates from this node or if |
@@ -123,11 +134,225 @@ int batadv_send_skb_to_orig(struct sk_buff *skb, | |||
123 | ret = NET_XMIT_SUCCESS; | 134 | ret = NET_XMIT_SUCCESS; |
124 | } | 135 | } |
125 | 136 | ||
126 | batadv_neigh_node_free_ref(neigh_node); | 137 | out: |
138 | if (neigh_node) | ||
139 | batadv_neigh_node_free_ref(neigh_node); | ||
140 | |||
141 | return ret; | ||
142 | } | ||
143 | |||
144 | /** | ||
145 | * batadv_send_skb_push_fill_unicast - extend the buffer and initialize the | ||
146 | * common fields for unicast packets | ||
147 | * @skb: the skb carrying the unicast header to initialize | ||
148 | * @hdr_size: amount of bytes to push at the beginning of the skb | ||
149 | * @orig_node: the destination node | ||
150 | * | ||
151 | * Returns false if the buffer extension was not possible or true otherwise. | ||
152 | */ | ||
153 | static bool | ||
154 | batadv_send_skb_push_fill_unicast(struct sk_buff *skb, int hdr_size, | ||
155 | struct batadv_orig_node *orig_node) | ||
156 | { | ||
157 | struct batadv_unicast_packet *unicast_packet; | ||
158 | uint8_t ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn); | ||
159 | |||
160 | if (batadv_skb_head_push(skb, hdr_size) < 0) | ||
161 | return false; | ||
162 | |||
163 | unicast_packet = (struct batadv_unicast_packet *)skb->data; | ||
164 | unicast_packet->header.version = BATADV_COMPAT_VERSION; | ||
165 | /* batman packet type: unicast */ | ||
166 | unicast_packet->header.packet_type = BATADV_UNICAST; | ||
167 | /* set unicast ttl */ | ||
168 | unicast_packet->header.ttl = BATADV_TTL; | ||
169 | /* copy the destination for faster routing */ | ||
170 | memcpy(unicast_packet->dest, orig_node->orig, ETH_ALEN); | ||
171 | /* set the destination tt version number */ | ||
172 | unicast_packet->ttvn = ttvn; | ||
173 | |||
174 | return true; | ||
175 | } | ||
176 | |||
177 | /** | ||
178 | * batadv_send_skb_prepare_unicast - encapsulate an skb with a unicast header | ||
179 | * @skb: the skb containing the payload to encapsulate | ||
180 | * @orig_node: the destination node | ||
181 | * | ||
182 | * Returns false if the payload could not be encapsulated or true otherwise. | ||
183 | */ | ||
184 | static bool batadv_send_skb_prepare_unicast(struct sk_buff *skb, | ||
185 | struct batadv_orig_node *orig_node) | ||
186 | { | ||
187 | size_t uni_size = sizeof(struct batadv_unicast_packet); | ||
188 | |||
189 | return batadv_send_skb_push_fill_unicast(skb, uni_size, orig_node); | ||
190 | } | ||
191 | |||
192 | /** | ||
193 | * batadv_send_skb_prepare_unicast_4addr - encapsulate an skb with a | ||
194 | * unicast 4addr header | ||
195 | * @bat_priv: the bat priv with all the soft interface information | ||
196 | * @skb: the skb containing the payload to encapsulate | ||
197 | * @orig_node: the destination node | ||
198 | * @packet_subtype: the unicast 4addr packet subtype to use | ||
199 | * | ||
200 | * Returns false if the payload could not be encapsulated or true otherwise. | ||
201 | */ | ||
202 | bool batadv_send_skb_prepare_unicast_4addr(struct batadv_priv *bat_priv, | ||
203 | struct sk_buff *skb, | ||
204 | struct batadv_orig_node *orig, | ||
205 | int packet_subtype) | ||
206 | { | ||
207 | struct batadv_hard_iface *primary_if; | ||
208 | struct batadv_unicast_4addr_packet *uc_4addr_packet; | ||
209 | bool ret = false; | ||
210 | |||
211 | primary_if = batadv_primary_if_get_selected(bat_priv); | ||
212 | if (!primary_if) | ||
213 | goto out; | ||
214 | |||
215 | /* Pull the header space and fill the unicast_packet substructure. | ||
216 | * We can do that because the first member of the uc_4addr_packet | ||
217 | * is of type struct unicast_packet | ||
218 | */ | ||
219 | if (!batadv_send_skb_push_fill_unicast(skb, sizeof(*uc_4addr_packet), | ||
220 | orig)) | ||
221 | goto out; | ||
222 | |||
223 | uc_4addr_packet = (struct batadv_unicast_4addr_packet *)skb->data; | ||
224 | uc_4addr_packet->u.header.packet_type = BATADV_UNICAST_4ADDR; | ||
225 | memcpy(uc_4addr_packet->src, primary_if->net_dev->dev_addr, ETH_ALEN); | ||
226 | uc_4addr_packet->subtype = packet_subtype; | ||
227 | uc_4addr_packet->reserved = 0; | ||
228 | |||
229 | ret = true; | ||
230 | out: | ||
231 | if (primary_if) | ||
232 | batadv_hardif_free_ref(primary_if); | ||
233 | return ret; | ||
234 | } | ||
235 | |||
236 | /** | ||
237 | * batadv_send_skb_unicast - encapsulate and send an skb via unicast | ||
238 | * @bat_priv: the bat priv with all the soft interface information | ||
239 | * @skb: payload to send | ||
240 | * @packet_type: the batman unicast packet type to use | ||
241 | * @packet_subtype: the unicast 4addr packet subtype (only relevant for unicast | ||
242 | * 4addr packets) | ||
243 | * @orig_node: the originator to send the packet to | ||
244 | * @vid: the vid to be used to search the translation table | ||
245 | * | ||
246 | * Wrap the given skb into a batman-adv unicast or unicast-4addr header | ||
247 | * depending on whether BATADV_UNICAST or BATADV_UNICAST_4ADDR was supplied | ||
248 | * as packet_type. Then send this frame to the given orig_node and release a | ||
249 | * reference to this orig_node. | ||
250 | * | ||
251 | * Returns NET_XMIT_DROP in case of error or NET_XMIT_SUCCESS otherwise. | ||
252 | */ | ||
253 | static int batadv_send_skb_unicast(struct batadv_priv *bat_priv, | ||
254 | struct sk_buff *skb, int packet_type, | ||
255 | int packet_subtype, | ||
256 | struct batadv_orig_node *orig_node, | ||
257 | unsigned short vid) | ||
258 | { | ||
259 | struct ethhdr *ethhdr = (struct ethhdr *)skb->data; | ||
260 | struct batadv_unicast_packet *unicast_packet; | ||
261 | int ret = NET_XMIT_DROP; | ||
262 | |||
263 | if (!orig_node) | ||
264 | goto out; | ||
265 | |||
266 | switch (packet_type) { | ||
267 | case BATADV_UNICAST: | ||
268 | if (!batadv_send_skb_prepare_unicast(skb, orig_node)) | ||
269 | goto out; | ||
270 | break; | ||
271 | case BATADV_UNICAST_4ADDR: | ||
272 | if (!batadv_send_skb_prepare_unicast_4addr(bat_priv, skb, | ||
273 | orig_node, | ||
274 | packet_subtype)) | ||
275 | goto out; | ||
276 | break; | ||
277 | default: | ||
278 | /* this function supports UNICAST and UNICAST_4ADDR only. It | ||
279 | * should never be invoked with any other packet type | ||
280 | */ | ||
281 | goto out; | ||
282 | } | ||
283 | |||
284 | unicast_packet = (struct batadv_unicast_packet *)skb->data; | ||
285 | |||
286 | /* inform the destination node that we are still missing a correct route | ||
287 | * for this client. The destination will receive this packet and will | ||
288 | * try to reroute it because the ttvn contained in the header is less | ||
289 | * than the current one | ||
290 | */ | ||
291 | if (batadv_tt_global_client_is_roaming(bat_priv, ethhdr->h_dest, vid)) | ||
292 | unicast_packet->ttvn = unicast_packet->ttvn - 1; | ||
127 | 293 | ||
294 | if (batadv_send_skb_to_orig(skb, orig_node, NULL) != NET_XMIT_DROP) | ||
295 | ret = NET_XMIT_SUCCESS; | ||
296 | |||
297 | out: | ||
298 | if (orig_node) | ||
299 | batadv_orig_node_free_ref(orig_node); | ||
300 | if (ret == NET_XMIT_DROP) | ||
301 | kfree_skb(skb); | ||
128 | return ret; | 302 | return ret; |
129 | } | 303 | } |
130 | 304 | ||
305 | /** | ||
306 | * batadv_send_skb_via_tt_generic - send an skb via TT lookup | ||
307 | * @bat_priv: the bat priv with all the soft interface information | ||
308 | * @skb: payload to send | ||
309 | * @packet_type: the batman unicast packet type to use | ||
310 | * @packet_subtype: the unicast 4addr packet subtype (only relevant for unicast | ||
311 | * 4addr packets) | ||
312 | * @vid: the vid to be used to search the translation table | ||
313 | * | ||
314 | * Look up the recipient node for the destination address in the ethernet | ||
315 | * header via the translation table. Wrap the given skb into a batman-adv | ||
316 | * unicast or unicast-4addr header depending on whether BATADV_UNICAST or | ||
317 | * BATADV_UNICAST_4ADDR was supplied as packet_type. Then send this frame | ||
318 | * to the according destination node. | ||
319 | * | ||
320 | * Returns NET_XMIT_DROP in case of error or NET_XMIT_SUCCESS otherwise. | ||
321 | */ | ||
322 | int batadv_send_skb_via_tt_generic(struct batadv_priv *bat_priv, | ||
323 | struct sk_buff *skb, int packet_type, | ||
324 | int packet_subtype, unsigned short vid) | ||
325 | { | ||
326 | struct ethhdr *ethhdr = (struct ethhdr *)skb->data; | ||
327 | struct batadv_orig_node *orig_node; | ||
328 | |||
329 | orig_node = batadv_transtable_search(bat_priv, ethhdr->h_source, | ||
330 | ethhdr->h_dest, vid); | ||
331 | return batadv_send_skb_unicast(bat_priv, skb, packet_type, | ||
332 | packet_subtype, orig_node, vid); | ||
333 | } | ||
334 | |||
335 | /** | ||
336 | * batadv_send_skb_via_gw - send an skb via gateway lookup | ||
337 | * @bat_priv: the bat priv with all the soft interface information | ||
338 | * @skb: payload to send | ||
339 | * @vid: the vid to be used to search the translation table | ||
340 | * | ||
341 | * Look up the currently selected gateway. Wrap the given skb into a batman-adv | ||
342 | * unicast header and send this frame to this gateway node. | ||
343 | * | ||
344 | * Returns NET_XMIT_DROP in case of error or NET_XMIT_SUCCESS otherwise. | ||
345 | */ | ||
346 | int batadv_send_skb_via_gw(struct batadv_priv *bat_priv, struct sk_buff *skb, | ||
347 | unsigned short vid) | ||
348 | { | ||
349 | struct batadv_orig_node *orig_node; | ||
350 | |||
351 | orig_node = batadv_gw_get_selected_orig(bat_priv); | ||
352 | return batadv_send_skb_unicast(bat_priv, skb, BATADV_UNICAST, 0, | ||
353 | orig_node, vid); | ||
354 | } | ||
355 | |||
131 | void batadv_schedule_bat_ogm(struct batadv_hard_iface *hard_iface) | 356 | void batadv_schedule_bat_ogm(struct batadv_hard_iface *hard_iface) |
132 | { | 357 | { |
133 | struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface); | 358 | struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface); |
diff --git a/net/batman-adv/send.h b/net/batman-adv/send.h index e7b17880fca4..aa2e2537a739 100644 --- a/net/batman-adv/send.h +++ b/net/batman-adv/send.h | |||
@@ -34,5 +34,58 @@ void batadv_send_outstanding_bat_ogm_packet(struct work_struct *work); | |||
34 | void | 34 | void |
35 | batadv_purge_outstanding_packets(struct batadv_priv *bat_priv, | 35 | batadv_purge_outstanding_packets(struct batadv_priv *bat_priv, |
36 | const struct batadv_hard_iface *hard_iface); | 36 | const struct batadv_hard_iface *hard_iface); |
37 | bool batadv_send_skb_prepare_unicast_4addr(struct batadv_priv *bat_priv, | ||
38 | struct sk_buff *skb, | ||
39 | struct batadv_orig_node *orig_node, | ||
40 | int packet_subtype); | ||
41 | int batadv_send_skb_via_tt_generic(struct batadv_priv *bat_priv, | ||
42 | struct sk_buff *skb, int packet_type, | ||
43 | int packet_subtype, unsigned short vid); | ||
44 | int batadv_send_skb_via_gw(struct batadv_priv *bat_priv, struct sk_buff *skb, | ||
45 | unsigned short vid); | ||
46 | |||
47 | /** | ||
48 | * batadv_send_skb_via_tt - send an skb via TT lookup | ||
49 | * @bat_priv: the bat priv with all the soft interface information | ||
50 | * @skb: the payload to send | ||
51 | * @vid: the vid to be used to search the translation table | ||
52 | * | ||
53 | * Look up the recipient node for the destination address in the ethernet | ||
54 | * header via the translation table. Wrap the given skb into a batman-adv | ||
55 | * unicast header. Then send this frame to the according destination node. | ||
56 | * | ||
57 | * Returns NET_XMIT_DROP in case of error or NET_XMIT_SUCCESS otherwise. | ||
58 | */ | ||
59 | static inline int batadv_send_skb_via_tt(struct batadv_priv *bat_priv, | ||
60 | struct sk_buff *skb, | ||
61 | unsigned short vid) | ||
62 | { | ||
63 | return batadv_send_skb_via_tt_generic(bat_priv, skb, BATADV_UNICAST, 0, | ||
64 | vid); | ||
65 | } | ||
66 | |||
67 | /** | ||
68 | * batadv_send_skb_via_tt_4addr - send an skb via TT lookup | ||
69 | * @bat_priv: the bat priv with all the soft interface information | ||
70 | * @skb: the payload to send | ||
71 | * @packet_subtype: the unicast 4addr packet subtype to use | ||
72 | * @vid: the vid to be used to search the translation table | ||
73 | * | ||
74 | * Look up the recipient node for the destination address in the ethernet | ||
75 | * header via the translation table. Wrap the given skb into a batman-adv | ||
76 | * unicast-4addr header. Then send this frame to the according destination | ||
77 | * node. | ||
78 | * | ||
79 | * Returns NET_XMIT_DROP in case of error or NET_XMIT_SUCCESS otherwise. | ||
80 | */ | ||
81 | static inline int batadv_send_skb_via_tt_4addr(struct batadv_priv *bat_priv, | ||
82 | struct sk_buff *skb, | ||
83 | int packet_subtype, | ||
84 | unsigned short vid) | ||
85 | { | ||
86 | return batadv_send_skb_via_tt_generic(bat_priv, skb, | ||
87 | BATADV_UNICAST_4ADDR, | ||
88 | packet_subtype, vid); | ||
89 | } | ||
37 | 90 | ||
38 | #endif /* _NET_BATMAN_ADV_SEND_H_ */ | 91 | #endif /* _NET_BATMAN_ADV_SEND_H_ */ |
diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index 813db4e64602..e70f530d8568 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c | |||
@@ -34,8 +34,6 @@ | |||
34 | #include <linux/ethtool.h> | 34 | #include <linux/ethtool.h> |
35 | #include <linux/etherdevice.h> | 35 | #include <linux/etherdevice.h> |
36 | #include <linux/if_vlan.h> | 36 | #include <linux/if_vlan.h> |
37 | #include <linux/if_ether.h> | ||
38 | #include "unicast.h" | ||
39 | #include "bridge_loop_avoidance.h" | 37 | #include "bridge_loop_avoidance.h" |
40 | #include "network-coding.h" | 38 | #include "network-coding.h" |
41 | 39 | ||
@@ -120,9 +118,10 @@ static int batadv_interface_set_mac_addr(struct net_device *dev, void *p) | |||
120 | 118 | ||
121 | /* only modify transtable if it has been initialized before */ | 119 | /* only modify transtable if it has been initialized before */ |
122 | if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_ACTIVE) { | 120 | if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_ACTIVE) { |
123 | batadv_tt_local_remove(bat_priv, old_addr, | 121 | batadv_tt_local_remove(bat_priv, old_addr, BATADV_NO_FLAGS, |
124 | "mac address changed", false); | 122 | "mac address changed", false); |
125 | batadv_tt_local_add(dev, addr->sa_data, BATADV_NULL_IFINDEX); | 123 | batadv_tt_local_add(dev, addr->sa_data, BATADV_NO_FLAGS, |
124 | BATADV_NULL_IFINDEX); | ||
126 | } | 125 | } |
127 | 126 | ||
128 | return 0; | 127 | return 0; |
@@ -139,36 +138,48 @@ static int batadv_interface_change_mtu(struct net_device *dev, int new_mtu) | |||
139 | return 0; | 138 | return 0; |
140 | } | 139 | } |
141 | 140 | ||
141 | /** | ||
142 | * batadv_interface_set_rx_mode - set the rx mode of a device | ||
143 | * @dev: registered network device to modify | ||
144 | * | ||
145 | * We do not actually need to set any rx filters for the virtual batman | ||
146 | * soft interface. However a dummy handler enables a user to set static | ||
147 | * multicast listeners for instance. | ||
148 | */ | ||
149 | static void batadv_interface_set_rx_mode(struct net_device *dev) | ||
150 | { | ||
151 | } | ||
152 | |||
142 | static int batadv_interface_tx(struct sk_buff *skb, | 153 | static int batadv_interface_tx(struct sk_buff *skb, |
143 | struct net_device *soft_iface) | 154 | struct net_device *soft_iface) |
144 | { | 155 | { |
145 | struct ethhdr *ethhdr = (struct ethhdr *)skb->data; | 156 | struct ethhdr *ethhdr; |
146 | struct batadv_priv *bat_priv = netdev_priv(soft_iface); | 157 | struct batadv_priv *bat_priv = netdev_priv(soft_iface); |
147 | struct batadv_hard_iface *primary_if = NULL; | 158 | struct batadv_hard_iface *primary_if = NULL; |
148 | struct batadv_bcast_packet *bcast_packet; | 159 | struct batadv_bcast_packet *bcast_packet; |
149 | struct vlan_ethhdr *vhdr; | 160 | __be16 ethertype = htons(ETH_P_BATMAN); |
150 | __be16 ethertype = __constant_htons(ETH_P_BATMAN); | ||
151 | static const uint8_t stp_addr[ETH_ALEN] = {0x01, 0x80, 0xC2, 0x00, | 161 | static const uint8_t stp_addr[ETH_ALEN] = {0x01, 0x80, 0xC2, 0x00, |
152 | 0x00, 0x00}; | 162 | 0x00, 0x00}; |
153 | static const uint8_t ectp_addr[ETH_ALEN] = {0xCF, 0x00, 0x00, 0x00, | 163 | static const uint8_t ectp_addr[ETH_ALEN] = {0xCF, 0x00, 0x00, 0x00, |
154 | 0x00, 0x00}; | 164 | 0x00, 0x00}; |
165 | struct vlan_ethhdr *vhdr; | ||
155 | unsigned int header_len = 0; | 166 | unsigned int header_len = 0; |
156 | int data_len = skb->len, ret; | 167 | int data_len = skb->len, ret; |
157 | unsigned short vid __maybe_unused = BATADV_NO_FLAGS; | 168 | unsigned long brd_delay = 1; |
158 | bool do_bcast = false; | 169 | bool do_bcast = false; |
170 | unsigned short vid; | ||
159 | uint32_t seqno; | 171 | uint32_t seqno; |
160 | unsigned long brd_delay = 1; | ||
161 | 172 | ||
162 | if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE) | 173 | if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE) |
163 | goto dropped; | 174 | goto dropped; |
164 | 175 | ||
165 | soft_iface->trans_start = jiffies; | 176 | soft_iface->trans_start = jiffies; |
177 | vid = batadv_get_vid(skb, 0); | ||
178 | ethhdr = (struct ethhdr *)skb->data; | ||
166 | 179 | ||
167 | switch (ntohs(ethhdr->h_proto)) { | 180 | switch (ntohs(ethhdr->h_proto)) { |
168 | case ETH_P_8021Q: | 181 | case ETH_P_8021Q: |
169 | vhdr = (struct vlan_ethhdr *)skb->data; | 182 | vhdr = (struct vlan_ethhdr *)skb->data; |
170 | vid = ntohs(vhdr->h_vlan_TCI) & VLAN_VID_MASK; | ||
171 | vid |= BATADV_VLAN_HAS_TAG; | ||
172 | 183 | ||
173 | if (vhdr->h_vlan_encapsulated_proto != ethertype) | 184 | if (vhdr->h_vlan_encapsulated_proto != ethertype) |
174 | break; | 185 | break; |
@@ -186,7 +197,8 @@ static int batadv_interface_tx(struct sk_buff *skb, | |||
186 | 197 | ||
187 | /* Register the client MAC in the transtable */ | 198 | /* Register the client MAC in the transtable */ |
188 | if (!is_multicast_ether_addr(ethhdr->h_source)) | 199 | if (!is_multicast_ether_addr(ethhdr->h_source)) |
189 | batadv_tt_local_add(soft_iface, ethhdr->h_source, skb->skb_iif); | 200 | batadv_tt_local_add(soft_iface, ethhdr->h_source, vid, |
201 | skb->skb_iif); | ||
190 | 202 | ||
191 | /* don't accept stp packets. STP does not help in meshes. | 203 | /* don't accept stp packets. STP does not help in meshes. |
192 | * better use the bridge loop avoidance ... | 204 | * better use the bridge loop avoidance ... |
@@ -286,8 +298,12 @@ static int batadv_interface_tx(struct sk_buff *skb, | |||
286 | 298 | ||
287 | batadv_dat_snoop_outgoing_arp_reply(bat_priv, skb); | 299 | batadv_dat_snoop_outgoing_arp_reply(bat_priv, skb); |
288 | 300 | ||
289 | ret = batadv_unicast_send_skb(bat_priv, skb); | 301 | if (is_multicast_ether_addr(ethhdr->h_dest)) |
290 | if (ret != 0) | 302 | ret = batadv_send_skb_via_gw(bat_priv, skb, vid); |
303 | else | ||
304 | ret = batadv_send_skb_via_tt(bat_priv, skb, vid); | ||
305 | |||
306 | if (ret == NET_XMIT_DROP) | ||
291 | goto dropped_freed; | 307 | goto dropped_freed; |
292 | } | 308 | } |
293 | 309 | ||
@@ -309,12 +325,12 @@ void batadv_interface_rx(struct net_device *soft_iface, | |||
309 | struct sk_buff *skb, struct batadv_hard_iface *recv_if, | 325 | struct sk_buff *skb, struct batadv_hard_iface *recv_if, |
310 | int hdr_size, struct batadv_orig_node *orig_node) | 326 | int hdr_size, struct batadv_orig_node *orig_node) |
311 | { | 327 | { |
328 | struct batadv_header *batadv_header = (struct batadv_header *)skb->data; | ||
312 | struct batadv_priv *bat_priv = netdev_priv(soft_iface); | 329 | struct batadv_priv *bat_priv = netdev_priv(soft_iface); |
313 | struct ethhdr *ethhdr; | 330 | __be16 ethertype = htons(ETH_P_BATMAN); |
314 | struct vlan_ethhdr *vhdr; | 331 | struct vlan_ethhdr *vhdr; |
315 | struct batadv_header *batadv_header = (struct batadv_header *)skb->data; | 332 | struct ethhdr *ethhdr; |
316 | unsigned short vid __maybe_unused = BATADV_NO_FLAGS; | 333 | unsigned short vid; |
317 | __be16 ethertype = __constant_htons(ETH_P_BATMAN); | ||
318 | bool is_bcast; | 334 | bool is_bcast; |
319 | 335 | ||
320 | is_bcast = (batadv_header->packet_type == BATADV_BCAST); | 336 | is_bcast = (batadv_header->packet_type == BATADV_BCAST); |
@@ -326,13 +342,12 @@ void batadv_interface_rx(struct net_device *soft_iface, | |||
326 | skb_pull_rcsum(skb, hdr_size); | 342 | skb_pull_rcsum(skb, hdr_size); |
327 | skb_reset_mac_header(skb); | 343 | skb_reset_mac_header(skb); |
328 | 344 | ||
345 | vid = batadv_get_vid(skb, hdr_size); | ||
329 | ethhdr = eth_hdr(skb); | 346 | ethhdr = eth_hdr(skb); |
330 | 347 | ||
331 | switch (ntohs(ethhdr->h_proto)) { | 348 | switch (ntohs(ethhdr->h_proto)) { |
332 | case ETH_P_8021Q: | 349 | case ETH_P_8021Q: |
333 | vhdr = (struct vlan_ethhdr *)skb->data; | 350 | vhdr = (struct vlan_ethhdr *)skb->data; |
334 | vid = ntohs(vhdr->h_vlan_TCI) & VLAN_VID_MASK; | ||
335 | vid |= BATADV_VLAN_HAS_TAG; | ||
336 | 351 | ||
337 | if (vhdr->h_vlan_encapsulated_proto != ethertype) | 352 | if (vhdr->h_vlan_encapsulated_proto != ethertype) |
338 | break; | 353 | break; |
@@ -368,9 +383,10 @@ void batadv_interface_rx(struct net_device *soft_iface, | |||
368 | 383 | ||
369 | if (orig_node) | 384 | if (orig_node) |
370 | batadv_tt_add_temporary_global_entry(bat_priv, orig_node, | 385 | batadv_tt_add_temporary_global_entry(bat_priv, orig_node, |
371 | ethhdr->h_source); | 386 | ethhdr->h_source, vid); |
372 | 387 | ||
373 | if (batadv_is_ap_isolated(bat_priv, ethhdr->h_source, ethhdr->h_dest)) | 388 | if (batadv_is_ap_isolated(bat_priv, ethhdr->h_source, ethhdr->h_dest, |
389 | vid)) | ||
374 | goto dropped; | 390 | goto dropped; |
375 | 391 | ||
376 | netif_rx(skb); | 392 | netif_rx(skb); |
@@ -382,6 +398,177 @@ out: | |||
382 | return; | 398 | return; |
383 | } | 399 | } |
384 | 400 | ||
401 | /** | ||
402 | * batadv_softif_vlan_free_ref - decrease the vlan object refcounter and | ||
403 | * possibly free it | ||
404 | * @softif_vlan: the vlan object to release | ||
405 | */ | ||
406 | void batadv_softif_vlan_free_ref(struct batadv_softif_vlan *softif_vlan) | ||
407 | { | ||
408 | if (atomic_dec_and_test(&softif_vlan->refcount)) | ||
409 | kfree_rcu(softif_vlan, rcu); | ||
410 | } | ||
411 | |||
412 | /** | ||
413 | * batadv_softif_vlan_get - get the vlan object for a specific vid | ||
414 | * @bat_priv: the bat priv with all the soft interface information | ||
415 | * @vid: the identifier of the vlan object to retrieve | ||
416 | * | ||
417 | * Returns the private data of the vlan matching the vid passed as argument or | ||
418 | * NULL otherwise. The refcounter of the returned object is incremented by 1. | ||
419 | */ | ||
420 | struct batadv_softif_vlan *batadv_softif_vlan_get(struct batadv_priv *bat_priv, | ||
421 | unsigned short vid) | ||
422 | { | ||
423 | struct batadv_softif_vlan *vlan_tmp, *vlan = NULL; | ||
424 | |||
425 | rcu_read_lock(); | ||
426 | hlist_for_each_entry_rcu(vlan_tmp, &bat_priv->softif_vlan_list, list) { | ||
427 | if (vlan_tmp->vid != vid) | ||
428 | continue; | ||
429 | |||
430 | if (!atomic_inc_not_zero(&vlan_tmp->refcount)) | ||
431 | continue; | ||
432 | |||
433 | vlan = vlan_tmp; | ||
434 | break; | ||
435 | } | ||
436 | rcu_read_unlock(); | ||
437 | |||
438 | return vlan; | ||
439 | } | ||
440 | |||
441 | /** | ||
442 | * batadv_create_vlan - allocate the needed resources for a new vlan | ||
443 | * @bat_priv: the bat priv with all the soft interface information | ||
444 | * @vid: the VLAN identifier | ||
445 | * | ||
446 | * Returns 0 on success, a negative error otherwise. | ||
447 | */ | ||
448 | int batadv_softif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid) | ||
449 | { | ||
450 | struct batadv_softif_vlan *vlan; | ||
451 | int err; | ||
452 | |||
453 | vlan = batadv_softif_vlan_get(bat_priv, vid); | ||
454 | if (vlan) { | ||
455 | batadv_softif_vlan_free_ref(vlan); | ||
456 | return -EEXIST; | ||
457 | } | ||
458 | |||
459 | vlan = kzalloc(sizeof(*vlan), GFP_ATOMIC); | ||
460 | if (!vlan) | ||
461 | return -ENOMEM; | ||
462 | |||
463 | vlan->vid = vid; | ||
464 | atomic_set(&vlan->refcount, 1); | ||
465 | |||
466 | atomic_set(&vlan->ap_isolation, 0); | ||
467 | |||
468 | err = batadv_sysfs_add_vlan(bat_priv->soft_iface, vlan); | ||
469 | if (err) { | ||
470 | kfree(vlan); | ||
471 | return err; | ||
472 | } | ||
473 | |||
474 | /* add a new TT local entry. This one will be marked with the NOPURGE | ||
475 | * flag | ||
476 | */ | ||
477 | batadv_tt_local_add(bat_priv->soft_iface, | ||
478 | bat_priv->soft_iface->dev_addr, vid, | ||
479 | BATADV_NULL_IFINDEX); | ||
480 | |||
481 | spin_lock_bh(&bat_priv->softif_vlan_list_lock); | ||
482 | hlist_add_head_rcu(&vlan->list, &bat_priv->softif_vlan_list); | ||
483 | spin_unlock_bh(&bat_priv->softif_vlan_list_lock); | ||
484 | |||
485 | return 0; | ||
486 | } | ||
487 | |||
488 | /** | ||
489 | * batadv_softif_destroy_vlan - remove and destroy a softif_vlan object | ||
490 | * @bat_priv: the bat priv with all the soft interface information | ||
491 | * @vlan: the object to remove | ||
492 | */ | ||
493 | static void batadv_softif_destroy_vlan(struct batadv_priv *bat_priv, | ||
494 | struct batadv_softif_vlan *vlan) | ||
495 | { | ||
496 | spin_lock_bh(&bat_priv->softif_vlan_list_lock); | ||
497 | hlist_del_rcu(&vlan->list); | ||
498 | spin_unlock_bh(&bat_priv->softif_vlan_list_lock); | ||
499 | |||
500 | batadv_sysfs_del_vlan(bat_priv, vlan); | ||
501 | |||
502 | /* explicitly remove the associated TT local entry because it is marked | ||
503 | * with the NOPURGE flag | ||
504 | */ | ||
505 | batadv_tt_local_remove(bat_priv, bat_priv->soft_iface->dev_addr, | ||
506 | vlan->vid, "vlan interface destroyed", false); | ||
507 | |||
508 | batadv_softif_vlan_free_ref(vlan); | ||
509 | } | ||
510 | |||
511 | /** | ||
512 | * batadv_interface_add_vid - ndo_add_vid API implementation | ||
513 | * @dev: the netdev of the mesh interface | ||
514 | * @vid: identifier of the new vlan | ||
515 | * | ||
516 | * Set up all the internal structures for handling the new vlan on top of the | ||
517 | * mesh interface | ||
518 | * | ||
519 | * Returns 0 on success or a negative error code in case of failure. | ||
520 | */ | ||
521 | static int batadv_interface_add_vid(struct net_device *dev, __be16 proto, | ||
522 | unsigned short vid) | ||
523 | { | ||
524 | struct batadv_priv *bat_priv = netdev_priv(dev); | ||
525 | |||
526 | /* only 802.1Q vlans are supported. | ||
527 | * batman-adv does not know how to handle other types | ||
528 | */ | ||
529 | if (proto != htons(ETH_P_8021Q)) | ||
530 | return -EINVAL; | ||
531 | |||
532 | vid |= BATADV_VLAN_HAS_TAG; | ||
533 | |||
534 | return batadv_softif_create_vlan(bat_priv, vid); | ||
535 | } | ||
536 | |||
537 | /** | ||
538 | * batadv_interface_kill_vid - ndo_kill_vid API implementation | ||
539 | * @dev: the netdev of the mesh interface | ||
540 | * @vid: identifier of the deleted vlan | ||
541 | * | ||
542 | * Destroy all the internal structures used to handle the vlan identified by vid | ||
543 | * on top of the mesh interface | ||
544 | * | ||
545 | * Returns 0 on success, -EINVAL if the specified prototype is not ETH_P_8021Q | ||
546 | * or -ENOENT if the specified vlan id wasn't registered. | ||
547 | */ | ||
548 | static int batadv_interface_kill_vid(struct net_device *dev, __be16 proto, | ||
549 | unsigned short vid) | ||
550 | { | ||
551 | struct batadv_priv *bat_priv = netdev_priv(dev); | ||
552 | struct batadv_softif_vlan *vlan; | ||
553 | |||
554 | /* only 802.1Q vlans are supported. batman-adv does not know how to | ||
555 | * handle other types | ||
556 | */ | ||
557 | if (proto != htons(ETH_P_8021Q)) | ||
558 | return -EINVAL; | ||
559 | |||
560 | vlan = batadv_softif_vlan_get(bat_priv, vid | BATADV_VLAN_HAS_TAG); | ||
561 | if (!vlan) | ||
562 | return -ENOENT; | ||
563 | |||
564 | batadv_softif_destroy_vlan(bat_priv, vlan); | ||
565 | |||
566 | /* finally free the vlan object */ | ||
567 | batadv_softif_vlan_free_ref(vlan); | ||
568 | |||
569 | return 0; | ||
570 | } | ||
571 | |||
385 | /* batman-adv network devices have devices nesting below it and are a special | 572 | /* batman-adv network devices have devices nesting below it and are a special |
386 | * "super class" of normal network devices; split their locks off into a | 573 | * "super class" of normal network devices; split their locks off into a |
387 | * separate class since they always nest. | 574 | * separate class since they always nest. |
@@ -421,6 +608,7 @@ static void batadv_set_lockdep_class(struct net_device *dev) | |||
421 | */ | 608 | */ |
422 | static void batadv_softif_destroy_finish(struct work_struct *work) | 609 | static void batadv_softif_destroy_finish(struct work_struct *work) |
423 | { | 610 | { |
611 | struct batadv_softif_vlan *vlan; | ||
424 | struct batadv_priv *bat_priv; | 612 | struct batadv_priv *bat_priv; |
425 | struct net_device *soft_iface; | 613 | struct net_device *soft_iface; |
426 | 614 | ||
@@ -428,6 +616,13 @@ static void batadv_softif_destroy_finish(struct work_struct *work) | |||
428 | cleanup_work); | 616 | cleanup_work); |
429 | soft_iface = bat_priv->soft_iface; | 617 | soft_iface = bat_priv->soft_iface; |
430 | 618 | ||
619 | /* destroy the "untagged" VLAN */ | ||
620 | vlan = batadv_softif_vlan_get(bat_priv, BATADV_NO_FLAGS); | ||
621 | if (vlan) { | ||
622 | batadv_softif_destroy_vlan(bat_priv, vlan); | ||
623 | batadv_softif_vlan_free_ref(vlan); | ||
624 | } | ||
625 | |||
431 | batadv_sysfs_del_meshif(soft_iface); | 626 | batadv_sysfs_del_meshif(soft_iface); |
432 | 627 | ||
433 | rtnl_lock(); | 628 | rtnl_lock(); |
@@ -444,6 +639,7 @@ static void batadv_softif_destroy_finish(struct work_struct *work) | |||
444 | static int batadv_softif_init_late(struct net_device *dev) | 639 | static int batadv_softif_init_late(struct net_device *dev) |
445 | { | 640 | { |
446 | struct batadv_priv *bat_priv; | 641 | struct batadv_priv *bat_priv; |
642 | uint32_t random_seqno; | ||
447 | int ret; | 643 | int ret; |
448 | size_t cnt_len = sizeof(uint64_t) * BATADV_CNT_NUM; | 644 | size_t cnt_len = sizeof(uint64_t) * BATADV_CNT_NUM; |
449 | 645 | ||
@@ -468,11 +664,10 @@ static int batadv_softif_init_late(struct net_device *dev) | |||
468 | #ifdef CONFIG_BATMAN_ADV_DAT | 664 | #ifdef CONFIG_BATMAN_ADV_DAT |
469 | atomic_set(&bat_priv->distributed_arp_table, 1); | 665 | atomic_set(&bat_priv->distributed_arp_table, 1); |
470 | #endif | 666 | #endif |
471 | atomic_set(&bat_priv->ap_isolation, 0); | ||
472 | atomic_set(&bat_priv->vis_mode, BATADV_VIS_TYPE_CLIENT_UPDATE); | ||
473 | atomic_set(&bat_priv->gw_mode, BATADV_GW_MODE_OFF); | 667 | atomic_set(&bat_priv->gw_mode, BATADV_GW_MODE_OFF); |
474 | atomic_set(&bat_priv->gw_sel_class, 20); | 668 | atomic_set(&bat_priv->gw_sel_class, 20); |
475 | atomic_set(&bat_priv->gw_bandwidth, 41); | 669 | atomic_set(&bat_priv->gw.bandwidth_down, 100); |
670 | atomic_set(&bat_priv->gw.bandwidth_up, 20); | ||
476 | atomic_set(&bat_priv->orig_interval, 1000); | 671 | atomic_set(&bat_priv->orig_interval, 1000); |
477 | atomic_set(&bat_priv->hop_penalty, 30); | 672 | atomic_set(&bat_priv->hop_penalty, 30); |
478 | #ifdef CONFIG_BATMAN_ADV_DEBUG | 673 | #ifdef CONFIG_BATMAN_ADV_DEBUG |
@@ -493,6 +688,10 @@ static int batadv_softif_init_late(struct net_device *dev) | |||
493 | bat_priv->tt.last_changeset = NULL; | 688 | bat_priv->tt.last_changeset = NULL; |
494 | bat_priv->tt.last_changeset_len = 0; | 689 | bat_priv->tt.last_changeset_len = 0; |
495 | 690 | ||
691 | /* randomize initial seqno to avoid collision */ | ||
692 | get_random_bytes(&random_seqno, sizeof(random_seqno)); | ||
693 | atomic_set(&bat_priv->frag_seqno, random_seqno); | ||
694 | |||
496 | bat_priv->primary_if = NULL; | 695 | bat_priv->primary_if = NULL; |
497 | bat_priv->num_ifaces = 0; | 696 | bat_priv->num_ifaces = 0; |
498 | 697 | ||
@@ -578,8 +777,11 @@ static const struct net_device_ops batadv_netdev_ops = { | |||
578 | .ndo_open = batadv_interface_open, | 777 | .ndo_open = batadv_interface_open, |
579 | .ndo_stop = batadv_interface_release, | 778 | .ndo_stop = batadv_interface_release, |
580 | .ndo_get_stats = batadv_interface_stats, | 779 | .ndo_get_stats = batadv_interface_stats, |
780 | .ndo_vlan_rx_add_vid = batadv_interface_add_vid, | ||
781 | .ndo_vlan_rx_kill_vid = batadv_interface_kill_vid, | ||
581 | .ndo_set_mac_address = batadv_interface_set_mac_addr, | 782 | .ndo_set_mac_address = batadv_interface_set_mac_addr, |
582 | .ndo_change_mtu = batadv_interface_change_mtu, | 783 | .ndo_change_mtu = batadv_interface_change_mtu, |
784 | .ndo_set_rx_mode = batadv_interface_set_rx_mode, | ||
583 | .ndo_start_xmit = batadv_interface_tx, | 785 | .ndo_start_xmit = batadv_interface_tx, |
584 | .ndo_validate_addr = eth_validate_addr, | 786 | .ndo_validate_addr = eth_validate_addr, |
585 | .ndo_add_slave = batadv_softif_slave_add, | 787 | .ndo_add_slave = batadv_softif_slave_add, |
@@ -616,6 +818,7 @@ static void batadv_softif_init_early(struct net_device *dev) | |||
616 | 818 | ||
617 | dev->netdev_ops = &batadv_netdev_ops; | 819 | dev->netdev_ops = &batadv_netdev_ops; |
618 | dev->destructor = batadv_softif_free; | 820 | dev->destructor = batadv_softif_free; |
821 | dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER; | ||
619 | dev->tx_queue_len = 0; | 822 | dev->tx_queue_len = 0; |
620 | 823 | ||
621 | /* can't call min_mtu, because the needed variables | 824 | /* can't call min_mtu, because the needed variables |
@@ -623,7 +826,7 @@ static void batadv_softif_init_early(struct net_device *dev) | |||
623 | */ | 826 | */ |
624 | dev->mtu = ETH_DATA_LEN; | 827 | dev->mtu = ETH_DATA_LEN; |
625 | /* reserve more space in the skbuff for our header */ | 828 | /* reserve more space in the skbuff for our header */ |
626 | dev->hard_header_len = BATADV_HEADER_LEN; | 829 | dev->hard_header_len = batadv_max_header_len(); |
627 | 830 | ||
628 | /* generate random address */ | 831 | /* generate random address */ |
629 | eth_hw_addr_random(dev); | 832 | eth_hw_addr_random(dev); |
@@ -760,6 +963,12 @@ static const struct { | |||
760 | { "mgmt_tx_bytes" }, | 963 | { "mgmt_tx_bytes" }, |
761 | { "mgmt_rx" }, | 964 | { "mgmt_rx" }, |
762 | { "mgmt_rx_bytes" }, | 965 | { "mgmt_rx_bytes" }, |
966 | { "frag_tx" }, | ||
967 | { "frag_tx_bytes" }, | ||
968 | { "frag_rx" }, | ||
969 | { "frag_rx_bytes" }, | ||
970 | { "frag_fwd" }, | ||
971 | { "frag_fwd_bytes" }, | ||
763 | { "tt_request_tx" }, | 972 | { "tt_request_tx" }, |
764 | { "tt_request_rx" }, | 973 | { "tt_request_rx" }, |
765 | { "tt_response_tx" }, | 974 | { "tt_response_tx" }, |
diff --git a/net/batman-adv/soft-interface.h b/net/batman-adv/soft-interface.h index 2f2472c2ea0d..06fc91ff5a02 100644 --- a/net/batman-adv/soft-interface.h +++ b/net/batman-adv/soft-interface.h | |||
@@ -28,5 +28,9 @@ struct net_device *batadv_softif_create(const char *name); | |||
28 | void batadv_softif_destroy_sysfs(struct net_device *soft_iface); | 28 | void batadv_softif_destroy_sysfs(struct net_device *soft_iface); |
29 | int batadv_softif_is_valid(const struct net_device *net_dev); | 29 | int batadv_softif_is_valid(const struct net_device *net_dev); |
30 | extern struct rtnl_link_ops batadv_link_ops; | 30 | extern struct rtnl_link_ops batadv_link_ops; |
31 | int batadv_softif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid); | ||
32 | void batadv_softif_vlan_free_ref(struct batadv_softif_vlan *softif_vlan); | ||
33 | struct batadv_softif_vlan *batadv_softif_vlan_get(struct batadv_priv *bat_priv, | ||
34 | unsigned short vid); | ||
31 | 35 | ||
32 | #endif /* _NET_BATMAN_ADV_SOFT_INTERFACE_H_ */ | 36 | #endif /* _NET_BATMAN_ADV_SOFT_INTERFACE_H_ */ |
diff --git a/net/batman-adv/sysfs.c b/net/batman-adv/sysfs.c index 4114b961bc2c..6335433310af 100644 --- a/net/batman-adv/sysfs.c +++ b/net/batman-adv/sysfs.c | |||
@@ -21,11 +21,12 @@ | |||
21 | #include "sysfs.h" | 21 | #include "sysfs.h" |
22 | #include "translation-table.h" | 22 | #include "translation-table.h" |
23 | #include "distributed-arp-table.h" | 23 | #include "distributed-arp-table.h" |
24 | #include "network-coding.h" | ||
24 | #include "originator.h" | 25 | #include "originator.h" |
25 | #include "hard-interface.h" | 26 | #include "hard-interface.h" |
27 | #include "soft-interface.h" | ||
26 | #include "gateway_common.h" | 28 | #include "gateway_common.h" |
27 | #include "gateway_client.h" | 29 | #include "gateway_client.h" |
28 | #include "vis.h" | ||
29 | 30 | ||
30 | static struct net_device *batadv_kobj_to_netdev(struct kobject *obj) | 31 | static struct net_device *batadv_kobj_to_netdev(struct kobject *obj) |
31 | { | 32 | { |
@@ -39,6 +40,53 @@ static struct batadv_priv *batadv_kobj_to_batpriv(struct kobject *obj) | |||
39 | return netdev_priv(net_dev); | 40 | return netdev_priv(net_dev); |
40 | } | 41 | } |
41 | 42 | ||
43 | /** | ||
44 | * batadv_vlan_kobj_to_batpriv - convert a vlan kobj in the associated batpriv | ||
45 | * @obj: kobject to covert | ||
46 | * | ||
47 | * Returns the associated batadv_priv struct. | ||
48 | */ | ||
49 | static struct batadv_priv *batadv_vlan_kobj_to_batpriv(struct kobject *obj) | ||
50 | { | ||
51 | /* VLAN specific attributes are located in the root sysfs folder if they | ||
52 | * refer to the untagged VLAN.. | ||
53 | */ | ||
54 | if (!strcmp(BATADV_SYSFS_IF_MESH_SUBDIR, obj->name)) | ||
55 | return batadv_kobj_to_batpriv(obj); | ||
56 | |||
57 | /* ..while the attributes for the tagged vlans are located in | ||
58 | * the in the corresponding "vlan%VID" subfolder | ||
59 | */ | ||
60 | return batadv_kobj_to_batpriv(obj->parent); | ||
61 | } | ||
62 | |||
63 | /** | ||
64 | * batadv_kobj_to_vlan - convert a kobj in the associated softif_vlan struct | ||
65 | * @obj: kobject to covert | ||
66 | * | ||
67 | * Returns the associated softif_vlan struct if found, NULL otherwise. | ||
68 | */ | ||
69 | static struct batadv_softif_vlan * | ||
70 | batadv_kobj_to_vlan(struct batadv_priv *bat_priv, struct kobject *obj) | ||
71 | { | ||
72 | struct batadv_softif_vlan *vlan_tmp, *vlan = NULL; | ||
73 | |||
74 | rcu_read_lock(); | ||
75 | hlist_for_each_entry_rcu(vlan_tmp, &bat_priv->softif_vlan_list, list) { | ||
76 | if (vlan_tmp->kobj != obj) | ||
77 | continue; | ||
78 | |||
79 | if (!atomic_inc_not_zero(&vlan_tmp->refcount)) | ||
80 | continue; | ||
81 | |||
82 | vlan = vlan_tmp; | ||
83 | break; | ||
84 | } | ||
85 | rcu_read_unlock(); | ||
86 | |||
87 | return vlan; | ||
88 | } | ||
89 | |||
42 | #define BATADV_UEV_TYPE_VAR "BATTYPE=" | 90 | #define BATADV_UEV_TYPE_VAR "BATTYPE=" |
43 | #define BATADV_UEV_ACTION_VAR "BATACTION=" | 91 | #define BATADV_UEV_ACTION_VAR "BATACTION=" |
44 | #define BATADV_UEV_DATA_VAR "BATDATA=" | 92 | #define BATADV_UEV_DATA_VAR "BATDATA=" |
@@ -53,6 +101,15 @@ static char *batadv_uev_type_str[] = { | |||
53 | "gw" | 101 | "gw" |
54 | }; | 102 | }; |
55 | 103 | ||
104 | /* Use this, if you have customized show and store functions for vlan attrs */ | ||
105 | #define BATADV_ATTR_VLAN(_name, _mode, _show, _store) \ | ||
106 | struct batadv_attribute batadv_attr_vlan_##_name = { \ | ||
107 | .attr = {.name = __stringify(_name), \ | ||
108 | .mode = _mode }, \ | ||
109 | .show = _show, \ | ||
110 | .store = _store, \ | ||
111 | }; | ||
112 | |||
56 | /* Use this, if you have customized show and store functions */ | 113 | /* Use this, if you have customized show and store functions */ |
57 | #define BATADV_ATTR(_name, _mode, _show, _store) \ | 114 | #define BATADV_ATTR(_name, _mode, _show, _store) \ |
58 | struct batadv_attribute batadv_attr_##_name = { \ | 115 | struct batadv_attribute batadv_attr_##_name = { \ |
@@ -122,6 +179,41 @@ ssize_t batadv_show_##_name(struct kobject *kobj, \ | |||
122 | static BATADV_ATTR(_name, _mode, batadv_show_##_name, \ | 179 | static BATADV_ATTR(_name, _mode, batadv_show_##_name, \ |
123 | batadv_store_##_name) | 180 | batadv_store_##_name) |
124 | 181 | ||
182 | #define BATADV_ATTR_VLAN_STORE_BOOL(_name, _post_func) \ | ||
183 | ssize_t batadv_store_vlan_##_name(struct kobject *kobj, \ | ||
184 | struct attribute *attr, char *buff, \ | ||
185 | size_t count) \ | ||
186 | { \ | ||
187 | struct batadv_priv *bat_priv = batadv_vlan_kobj_to_batpriv(kobj);\ | ||
188 | struct batadv_softif_vlan *vlan = batadv_kobj_to_vlan(bat_priv, \ | ||
189 | kobj); \ | ||
190 | size_t res = __batadv_store_bool_attr(buff, count, _post_func, \ | ||
191 | attr, &vlan->_name, \ | ||
192 | bat_priv->soft_iface); \ | ||
193 | batadv_softif_vlan_free_ref(vlan); \ | ||
194 | return res; \ | ||
195 | } | ||
196 | |||
197 | #define BATADV_ATTR_VLAN_SHOW_BOOL(_name) \ | ||
198 | ssize_t batadv_show_vlan_##_name(struct kobject *kobj, \ | ||
199 | struct attribute *attr, char *buff) \ | ||
200 | { \ | ||
201 | struct batadv_priv *bat_priv = batadv_vlan_kobj_to_batpriv(kobj);\ | ||
202 | struct batadv_softif_vlan *vlan = batadv_kobj_to_vlan(bat_priv, \ | ||
203 | kobj); \ | ||
204 | size_t res = sprintf(buff, "%s\n", \ | ||
205 | atomic_read(&vlan->_name) == 0 ? \ | ||
206 | "disabled" : "enabled"); \ | ||
207 | batadv_softif_vlan_free_ref(vlan); \ | ||
208 | return res; \ | ||
209 | } | ||
210 | |||
211 | /* Use this, if you are going to turn a [name] in the vlan struct on or off */ | ||
212 | #define BATADV_ATTR_VLAN_BOOL(_name, _mode, _post_func) \ | ||
213 | static BATADV_ATTR_VLAN_STORE_BOOL(_name, _post_func) \ | ||
214 | static BATADV_ATTR_VLAN_SHOW_BOOL(_name) \ | ||
215 | static BATADV_ATTR_VLAN(_name, _mode, batadv_show_vlan_##_name, \ | ||
216 | batadv_store_vlan_##_name) | ||
125 | 217 | ||
126 | static int batadv_store_bool_attr(char *buff, size_t count, | 218 | static int batadv_store_bool_attr(char *buff, size_t count, |
127 | struct net_device *net_dev, | 219 | struct net_device *net_dev, |
@@ -230,74 +322,6 @@ __batadv_store_uint_attr(const char *buff, size_t count, | |||
230 | return ret; | 322 | return ret; |
231 | } | 323 | } |
232 | 324 | ||
233 | static ssize_t batadv_show_vis_mode(struct kobject *kobj, | ||
234 | struct attribute *attr, char *buff) | ||
235 | { | ||
236 | struct batadv_priv *bat_priv = batadv_kobj_to_batpriv(kobj); | ||
237 | int vis_mode = atomic_read(&bat_priv->vis_mode); | ||
238 | const char *mode; | ||
239 | |||
240 | if (vis_mode == BATADV_VIS_TYPE_CLIENT_UPDATE) | ||
241 | mode = "client"; | ||
242 | else | ||
243 | mode = "server"; | ||
244 | |||
245 | return sprintf(buff, "%s\n", mode); | ||
246 | } | ||
247 | |||
248 | static ssize_t batadv_store_vis_mode(struct kobject *kobj, | ||
249 | struct attribute *attr, char *buff, | ||
250 | size_t count) | ||
251 | { | ||
252 | struct net_device *net_dev = batadv_kobj_to_netdev(kobj); | ||
253 | struct batadv_priv *bat_priv = netdev_priv(net_dev); | ||
254 | unsigned long val; | ||
255 | int ret, vis_mode_tmp = -1; | ||
256 | const char *old_mode, *new_mode; | ||
257 | |||
258 | ret = kstrtoul(buff, 10, &val); | ||
259 | |||
260 | if (((count == 2) && (!ret) && | ||
261 | (val == BATADV_VIS_TYPE_CLIENT_UPDATE)) || | ||
262 | (strncmp(buff, "client", 6) == 0) || | ||
263 | (strncmp(buff, "off", 3) == 0)) | ||
264 | vis_mode_tmp = BATADV_VIS_TYPE_CLIENT_UPDATE; | ||
265 | |||
266 | if (((count == 2) && (!ret) && | ||
267 | (val == BATADV_VIS_TYPE_SERVER_SYNC)) || | ||
268 | (strncmp(buff, "server", 6) == 0)) | ||
269 | vis_mode_tmp = BATADV_VIS_TYPE_SERVER_SYNC; | ||
270 | |||
271 | if (vis_mode_tmp < 0) { | ||
272 | if (buff[count - 1] == '\n') | ||
273 | buff[count - 1] = '\0'; | ||
274 | |||
275 | batadv_info(net_dev, | ||
276 | "Invalid parameter for 'vis mode' setting received: %s\n", | ||
277 | buff); | ||
278 | return -EINVAL; | ||
279 | } | ||
280 | |||
281 | if (atomic_read(&bat_priv->vis_mode) == vis_mode_tmp) | ||
282 | return count; | ||
283 | |||
284 | if (atomic_read(&bat_priv->vis_mode) == BATADV_VIS_TYPE_CLIENT_UPDATE) | ||
285 | old_mode = "client"; | ||
286 | else | ||
287 | old_mode = "server"; | ||
288 | |||
289 | if (vis_mode_tmp == BATADV_VIS_TYPE_CLIENT_UPDATE) | ||
290 | new_mode = "client"; | ||
291 | else | ||
292 | new_mode = "server"; | ||
293 | |||
294 | batadv_info(net_dev, "Changing vis mode from: %s to: %s\n", old_mode, | ||
295 | new_mode); | ||
296 | |||
297 | atomic_set(&bat_priv->vis_mode, (unsigned int)vis_mode_tmp); | ||
298 | return count; | ||
299 | } | ||
300 | |||
301 | static ssize_t batadv_show_bat_algo(struct kobject *kobj, | 325 | static ssize_t batadv_show_bat_algo(struct kobject *kobj, |
302 | struct attribute *attr, char *buff) | 326 | struct attribute *attr, char *buff) |
303 | { | 327 | { |
@@ -390,6 +414,7 @@ static ssize_t batadv_store_gw_mode(struct kobject *kobj, | |||
390 | */ | 414 | */ |
391 | batadv_gw_check_client_stop(bat_priv); | 415 | batadv_gw_check_client_stop(bat_priv); |
392 | atomic_set(&bat_priv->gw_mode, (unsigned int)gw_mode_tmp); | 416 | atomic_set(&bat_priv->gw_mode, (unsigned int)gw_mode_tmp); |
417 | batadv_gw_tvlv_container_update(bat_priv); | ||
393 | return count; | 418 | return count; |
394 | } | 419 | } |
395 | 420 | ||
@@ -397,15 +422,13 @@ static ssize_t batadv_show_gw_bwidth(struct kobject *kobj, | |||
397 | struct attribute *attr, char *buff) | 422 | struct attribute *attr, char *buff) |
398 | { | 423 | { |
399 | struct batadv_priv *bat_priv = batadv_kobj_to_batpriv(kobj); | 424 | struct batadv_priv *bat_priv = batadv_kobj_to_batpriv(kobj); |
400 | int down, up; | 425 | uint32_t down, up; |
401 | int gw_bandwidth = atomic_read(&bat_priv->gw_bandwidth); | 426 | |
402 | 427 | down = atomic_read(&bat_priv->gw.bandwidth_down); | |
403 | batadv_gw_bandwidth_to_kbit(gw_bandwidth, &down, &up); | 428 | up = atomic_read(&bat_priv->gw.bandwidth_up); |
404 | return sprintf(buff, "%i%s/%i%s\n", | 429 | |
405 | (down > 2048 ? down / 1024 : down), | 430 | return sprintf(buff, "%u.%u/%u.%u MBit\n", down / 10, |
406 | (down > 2048 ? "MBit" : "KBit"), | 431 | down % 10, up / 10, up % 10); |
407 | (up > 2048 ? up / 1024 : up), | ||
408 | (up > 2048 ? "MBit" : "KBit")); | ||
409 | } | 432 | } |
410 | 433 | ||
411 | static ssize_t batadv_store_gw_bwidth(struct kobject *kobj, | 434 | static ssize_t batadv_store_gw_bwidth(struct kobject *kobj, |
@@ -426,12 +449,10 @@ BATADV_ATTR_SIF_BOOL(bonding, S_IRUGO | S_IWUSR, NULL); | |||
426 | BATADV_ATTR_SIF_BOOL(bridge_loop_avoidance, S_IRUGO | S_IWUSR, NULL); | 449 | BATADV_ATTR_SIF_BOOL(bridge_loop_avoidance, S_IRUGO | S_IWUSR, NULL); |
427 | #endif | 450 | #endif |
428 | #ifdef CONFIG_BATMAN_ADV_DAT | 451 | #ifdef CONFIG_BATMAN_ADV_DAT |
429 | BATADV_ATTR_SIF_BOOL(distributed_arp_table, S_IRUGO | S_IWUSR, NULL); | 452 | BATADV_ATTR_SIF_BOOL(distributed_arp_table, S_IRUGO | S_IWUSR, |
453 | batadv_dat_status_update); | ||
430 | #endif | 454 | #endif |
431 | BATADV_ATTR_SIF_BOOL(fragmentation, S_IRUGO | S_IWUSR, batadv_update_min_mtu); | 455 | BATADV_ATTR_SIF_BOOL(fragmentation, S_IRUGO | S_IWUSR, batadv_update_min_mtu); |
432 | BATADV_ATTR_SIF_BOOL(ap_isolation, S_IRUGO | S_IWUSR, NULL); | ||
433 | static BATADV_ATTR(vis_mode, S_IRUGO | S_IWUSR, batadv_show_vis_mode, | ||
434 | batadv_store_vis_mode); | ||
435 | static BATADV_ATTR(routing_algo, S_IRUGO, batadv_show_bat_algo, NULL); | 456 | static BATADV_ATTR(routing_algo, S_IRUGO, batadv_show_bat_algo, NULL); |
436 | static BATADV_ATTR(gw_mode, S_IRUGO | S_IWUSR, batadv_show_gw_mode, | 457 | static BATADV_ATTR(gw_mode, S_IRUGO | S_IWUSR, batadv_show_gw_mode, |
437 | batadv_store_gw_mode); | 458 | batadv_store_gw_mode); |
@@ -447,7 +468,8 @@ static BATADV_ATTR(gw_bandwidth, S_IRUGO | S_IWUSR, batadv_show_gw_bwidth, | |||
447 | BATADV_ATTR_SIF_UINT(log_level, S_IRUGO | S_IWUSR, 0, BATADV_DBG_ALL, NULL); | 468 | BATADV_ATTR_SIF_UINT(log_level, S_IRUGO | S_IWUSR, 0, BATADV_DBG_ALL, NULL); |
448 | #endif | 469 | #endif |
449 | #ifdef CONFIG_BATMAN_ADV_NC | 470 | #ifdef CONFIG_BATMAN_ADV_NC |
450 | BATADV_ATTR_SIF_BOOL(network_coding, S_IRUGO | S_IWUSR, NULL); | 471 | BATADV_ATTR_SIF_BOOL(network_coding, S_IRUGO | S_IWUSR, |
472 | batadv_nc_status_update); | ||
451 | #endif | 473 | #endif |
452 | 474 | ||
453 | static struct batadv_attribute *batadv_mesh_attrs[] = { | 475 | static struct batadv_attribute *batadv_mesh_attrs[] = { |
@@ -460,8 +482,6 @@ static struct batadv_attribute *batadv_mesh_attrs[] = { | |||
460 | &batadv_attr_distributed_arp_table, | 482 | &batadv_attr_distributed_arp_table, |
461 | #endif | 483 | #endif |
462 | &batadv_attr_fragmentation, | 484 | &batadv_attr_fragmentation, |
463 | &batadv_attr_ap_isolation, | ||
464 | &batadv_attr_vis_mode, | ||
465 | &batadv_attr_routing_algo, | 485 | &batadv_attr_routing_algo, |
466 | &batadv_attr_gw_mode, | 486 | &batadv_attr_gw_mode, |
467 | &batadv_attr_orig_interval, | 487 | &batadv_attr_orig_interval, |
@@ -477,6 +497,16 @@ static struct batadv_attribute *batadv_mesh_attrs[] = { | |||
477 | NULL, | 497 | NULL, |
478 | }; | 498 | }; |
479 | 499 | ||
500 | BATADV_ATTR_VLAN_BOOL(ap_isolation, S_IRUGO | S_IWUSR, NULL); | ||
501 | |||
502 | /** | ||
503 | * batadv_vlan_attrs - array of vlan specific sysfs attributes | ||
504 | */ | ||
505 | static struct batadv_attribute *batadv_vlan_attrs[] = { | ||
506 | &batadv_attr_vlan_ap_isolation, | ||
507 | NULL, | ||
508 | }; | ||
509 | |||
480 | int batadv_sysfs_add_meshif(struct net_device *dev) | 510 | int batadv_sysfs_add_meshif(struct net_device *dev) |
481 | { | 511 | { |
482 | struct kobject *batif_kobject = &dev->dev.kobj; | 512 | struct kobject *batif_kobject = &dev->dev.kobj; |
@@ -527,6 +557,80 @@ void batadv_sysfs_del_meshif(struct net_device *dev) | |||
527 | bat_priv->mesh_obj = NULL; | 557 | bat_priv->mesh_obj = NULL; |
528 | } | 558 | } |
529 | 559 | ||
560 | /** | ||
561 | * batadv_sysfs_add_vlan - add all the needed sysfs objects for the new vlan | ||
562 | * @dev: netdev of the mesh interface | ||
563 | * @vlan: private data of the newly added VLAN interface | ||
564 | * | ||
565 | * Returns 0 on success and -ENOMEM if any of the structure allocations fails. | ||
566 | */ | ||
567 | int batadv_sysfs_add_vlan(struct net_device *dev, | ||
568 | struct batadv_softif_vlan *vlan) | ||
569 | { | ||
570 | char vlan_subdir[sizeof(BATADV_SYSFS_VLAN_SUBDIR_PREFIX) + 5]; | ||
571 | struct batadv_priv *bat_priv = netdev_priv(dev); | ||
572 | struct batadv_attribute **bat_attr; | ||
573 | int err; | ||
574 | |||
575 | if (vlan->vid & BATADV_VLAN_HAS_TAG) { | ||
576 | sprintf(vlan_subdir, BATADV_SYSFS_VLAN_SUBDIR_PREFIX "%hu", | ||
577 | vlan->vid & VLAN_VID_MASK); | ||
578 | |||
579 | vlan->kobj = kobject_create_and_add(vlan_subdir, | ||
580 | bat_priv->mesh_obj); | ||
581 | if (!vlan->kobj) { | ||
582 | batadv_err(dev, "Can't add sysfs directory: %s/%s\n", | ||
583 | dev->name, vlan_subdir); | ||
584 | goto out; | ||
585 | } | ||
586 | } else { | ||
587 | /* the untagged LAN uses the root folder to store its "VLAN | ||
588 | * specific attributes" | ||
589 | */ | ||
590 | vlan->kobj = bat_priv->mesh_obj; | ||
591 | kobject_get(bat_priv->mesh_obj); | ||
592 | } | ||
593 | |||
594 | for (bat_attr = batadv_vlan_attrs; *bat_attr; ++bat_attr) { | ||
595 | err = sysfs_create_file(vlan->kobj, | ||
596 | &((*bat_attr)->attr)); | ||
597 | if (err) { | ||
598 | batadv_err(dev, "Can't add sysfs file: %s/%s/%s\n", | ||
599 | dev->name, vlan_subdir, | ||
600 | ((*bat_attr)->attr).name); | ||
601 | goto rem_attr; | ||
602 | } | ||
603 | } | ||
604 | |||
605 | return 0; | ||
606 | |||
607 | rem_attr: | ||
608 | for (bat_attr = batadv_vlan_attrs; *bat_attr; ++bat_attr) | ||
609 | sysfs_remove_file(vlan->kobj, &((*bat_attr)->attr)); | ||
610 | |||
611 | kobject_put(vlan->kobj); | ||
612 | vlan->kobj = NULL; | ||
613 | out: | ||
614 | return -ENOMEM; | ||
615 | } | ||
616 | |||
617 | /** | ||
618 | * batadv_sysfs_del_vlan - remove all the sysfs objects for a given VLAN | ||
619 | * @bat_priv: the bat priv with all the soft interface information | ||
620 | * @vlan: the private data of the VLAN to destroy | ||
621 | */ | ||
622 | void batadv_sysfs_del_vlan(struct batadv_priv *bat_priv, | ||
623 | struct batadv_softif_vlan *vlan) | ||
624 | { | ||
625 | struct batadv_attribute **bat_attr; | ||
626 | |||
627 | for (bat_attr = batadv_vlan_attrs; *bat_attr; ++bat_attr) | ||
628 | sysfs_remove_file(vlan->kobj, &((*bat_attr)->attr)); | ||
629 | |||
630 | kobject_put(vlan->kobj); | ||
631 | vlan->kobj = NULL; | ||
632 | } | ||
633 | |||
530 | static ssize_t batadv_show_mesh_iface(struct kobject *kobj, | 634 | static ssize_t batadv_show_mesh_iface(struct kobject *kobj, |
531 | struct attribute *attr, char *buff) | 635 | struct attribute *attr, char *buff) |
532 | { | 636 | { |
diff --git a/net/batman-adv/sysfs.h b/net/batman-adv/sysfs.h index 479acf4c16f4..c7d725de50ad 100644 --- a/net/batman-adv/sysfs.h +++ b/net/batman-adv/sysfs.h | |||
@@ -22,6 +22,12 @@ | |||
22 | 22 | ||
23 | #define BATADV_SYSFS_IF_MESH_SUBDIR "mesh" | 23 | #define BATADV_SYSFS_IF_MESH_SUBDIR "mesh" |
24 | #define BATADV_SYSFS_IF_BAT_SUBDIR "batman_adv" | 24 | #define BATADV_SYSFS_IF_BAT_SUBDIR "batman_adv" |
25 | /** | ||
26 | * BATADV_SYSFS_VLAN_SUBDIR_PREFIX - prefix of the subfolder that will be | ||
27 | * created in the sysfs hierarchy for each VLAN interface. The subfolder will | ||
28 | * be named "BATADV_SYSFS_VLAN_SUBDIR_PREFIX%vid". | ||
29 | */ | ||
30 | #define BATADV_SYSFS_VLAN_SUBDIR_PREFIX "vlan" | ||
25 | 31 | ||
26 | struct batadv_attribute { | 32 | struct batadv_attribute { |
27 | struct attribute attr; | 33 | struct attribute attr; |
@@ -36,6 +42,10 @@ void batadv_sysfs_del_meshif(struct net_device *dev); | |||
36 | int batadv_sysfs_add_hardif(struct kobject **hardif_obj, | 42 | int batadv_sysfs_add_hardif(struct kobject **hardif_obj, |
37 | struct net_device *dev); | 43 | struct net_device *dev); |
38 | void batadv_sysfs_del_hardif(struct kobject **hardif_obj); | 44 | void batadv_sysfs_del_hardif(struct kobject **hardif_obj); |
45 | int batadv_sysfs_add_vlan(struct net_device *dev, | ||
46 | struct batadv_softif_vlan *vlan); | ||
47 | void batadv_sysfs_del_vlan(struct batadv_priv *bat_priv, | ||
48 | struct batadv_softif_vlan *vlan); | ||
39 | int batadv_throw_uevent(struct batadv_priv *bat_priv, enum batadv_uev_type type, | 49 | int batadv_throw_uevent(struct batadv_priv *bat_priv, enum batadv_uev_type type, |
40 | enum batadv_uev_action action, const char *data); | 50 | enum batadv_uev_action action, const char *data); |
41 | 51 | ||
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index 34510f38708f..7731eaed737d 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c | |||
@@ -27,13 +27,14 @@ | |||
27 | #include "routing.h" | 27 | #include "routing.h" |
28 | #include "bridge_loop_avoidance.h" | 28 | #include "bridge_loop_avoidance.h" |
29 | 29 | ||
30 | #include <linux/crc16.h> | 30 | #include <linux/crc32c.h> |
31 | 31 | ||
32 | /* hash class keys */ | 32 | /* hash class keys */ |
33 | static struct lock_class_key batadv_tt_local_hash_lock_class_key; | 33 | static struct lock_class_key batadv_tt_local_hash_lock_class_key; |
34 | static struct lock_class_key batadv_tt_global_hash_lock_class_key; | 34 | static struct lock_class_key batadv_tt_global_hash_lock_class_key; |
35 | 35 | ||
36 | static void batadv_send_roam_adv(struct batadv_priv *bat_priv, uint8_t *client, | 36 | static void batadv_send_roam_adv(struct batadv_priv *bat_priv, uint8_t *client, |
37 | unsigned short vid, | ||
37 | struct batadv_orig_node *orig_node); | 38 | struct batadv_orig_node *orig_node); |
38 | static void batadv_tt_purge(struct work_struct *work); | 39 | static void batadv_tt_purge(struct work_struct *work); |
39 | static void | 40 | static void |
@@ -41,7 +42,8 @@ batadv_tt_global_del_orig_list(struct batadv_tt_global_entry *tt_global_entry); | |||
41 | static void batadv_tt_global_del(struct batadv_priv *bat_priv, | 42 | static void batadv_tt_global_del(struct batadv_priv *bat_priv, |
42 | struct batadv_orig_node *orig_node, | 43 | struct batadv_orig_node *orig_node, |
43 | const unsigned char *addr, | 44 | const unsigned char *addr, |
44 | const char *message, bool roaming); | 45 | unsigned short vid, const char *message, |
46 | bool roaming); | ||
45 | 47 | ||
46 | /* returns 1 if they are the same mac addr */ | 48 | /* returns 1 if they are the same mac addr */ |
47 | static int batadv_compare_tt(const struct hlist_node *node, const void *data2) | 49 | static int batadv_compare_tt(const struct hlist_node *node, const void *data2) |
@@ -52,43 +54,93 @@ static int batadv_compare_tt(const struct hlist_node *node, const void *data2) | |||
52 | return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0); | 54 | return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0); |
53 | } | 55 | } |
54 | 56 | ||
57 | /** | ||
58 | * batadv_choose_tt - return the index of the tt entry in the hash table | ||
59 | * @data: pointer to the tt_common_entry object to map | ||
60 | * @size: the size of the hash table | ||
61 | * | ||
62 | * Returns the hash index where the object represented by 'data' should be | ||
63 | * stored at. | ||
64 | */ | ||
65 | static inline uint32_t batadv_choose_tt(const void *data, uint32_t size) | ||
66 | { | ||
67 | struct batadv_tt_common_entry *tt; | ||
68 | uint32_t hash = 0; | ||
69 | |||
70 | tt = (struct batadv_tt_common_entry *)data; | ||
71 | hash = batadv_hash_bytes(hash, &tt->addr, ETH_ALEN); | ||
72 | hash = batadv_hash_bytes(hash, &tt->vid, sizeof(tt->vid)); | ||
73 | |||
74 | hash += (hash << 3); | ||
75 | hash ^= (hash >> 11); | ||
76 | hash += (hash << 15); | ||
77 | |||
78 | return hash % size; | ||
79 | } | ||
80 | |||
81 | /** | ||
82 | * batadv_tt_hash_find - look for a client in the given hash table | ||
83 | * @hash: the hash table to search | ||
84 | * @addr: the mac address of the client to look for | ||
85 | * @vid: VLAN identifier | ||
86 | * | ||
87 | * Returns a pointer to the tt_common struct belonging to the searched client if | ||
88 | * found, NULL otherwise. | ||
89 | */ | ||
55 | static struct batadv_tt_common_entry * | 90 | static struct batadv_tt_common_entry * |
56 | batadv_tt_hash_find(struct batadv_hashtable *hash, const void *data) | 91 | batadv_tt_hash_find(struct batadv_hashtable *hash, const uint8_t *addr, |
92 | unsigned short vid) | ||
57 | { | 93 | { |
58 | struct hlist_head *head; | 94 | struct hlist_head *head; |
59 | struct batadv_tt_common_entry *tt_common_entry; | 95 | struct batadv_tt_common_entry to_search, *tt, *tt_tmp = NULL; |
60 | struct batadv_tt_common_entry *tt_common_entry_tmp = NULL; | ||
61 | uint32_t index; | 96 | uint32_t index; |
62 | 97 | ||
63 | if (!hash) | 98 | if (!hash) |
64 | return NULL; | 99 | return NULL; |
65 | 100 | ||
66 | index = batadv_choose_orig(data, hash->size); | 101 | memcpy(to_search.addr, addr, ETH_ALEN); |
102 | to_search.vid = vid; | ||
103 | |||
104 | index = batadv_choose_tt(&to_search, hash->size); | ||
67 | head = &hash->table[index]; | 105 | head = &hash->table[index]; |
68 | 106 | ||
69 | rcu_read_lock(); | 107 | rcu_read_lock(); |
70 | hlist_for_each_entry_rcu(tt_common_entry, head, hash_entry) { | 108 | hlist_for_each_entry_rcu(tt, head, hash_entry) { |
71 | if (!batadv_compare_eth(tt_common_entry, data)) | 109 | if (!batadv_compare_eth(tt, addr)) |
110 | continue; | ||
111 | |||
112 | if (tt->vid != vid) | ||
72 | continue; | 113 | continue; |
73 | 114 | ||
74 | if (!atomic_inc_not_zero(&tt_common_entry->refcount)) | 115 | if (!atomic_inc_not_zero(&tt->refcount)) |
75 | continue; | 116 | continue; |
76 | 117 | ||
77 | tt_common_entry_tmp = tt_common_entry; | 118 | tt_tmp = tt; |
78 | break; | 119 | break; |
79 | } | 120 | } |
80 | rcu_read_unlock(); | 121 | rcu_read_unlock(); |
81 | 122 | ||
82 | return tt_common_entry_tmp; | 123 | return tt_tmp; |
83 | } | 124 | } |
84 | 125 | ||
126 | /** | ||
127 | * batadv_tt_local_hash_find - search the local table for a given client | ||
128 | * @bat_priv: the bat priv with all the soft interface information | ||
129 | * @addr: the mac address of the client to look for | ||
130 | * @vid: VLAN identifier | ||
131 | * | ||
132 | * Returns a pointer to the corresponding tt_local_entry struct if the client is | ||
133 | * found, NULL otherwise. | ||
134 | */ | ||
85 | static struct batadv_tt_local_entry * | 135 | static struct batadv_tt_local_entry * |
86 | batadv_tt_local_hash_find(struct batadv_priv *bat_priv, const void *data) | 136 | batadv_tt_local_hash_find(struct batadv_priv *bat_priv, const uint8_t *addr, |
137 | unsigned short vid) | ||
87 | { | 138 | { |
88 | struct batadv_tt_common_entry *tt_common_entry; | 139 | struct batadv_tt_common_entry *tt_common_entry; |
89 | struct batadv_tt_local_entry *tt_local_entry = NULL; | 140 | struct batadv_tt_local_entry *tt_local_entry = NULL; |
90 | 141 | ||
91 | tt_common_entry = batadv_tt_hash_find(bat_priv->tt.local_hash, data); | 142 | tt_common_entry = batadv_tt_hash_find(bat_priv->tt.local_hash, addr, |
143 | vid); | ||
92 | if (tt_common_entry) | 144 | if (tt_common_entry) |
93 | tt_local_entry = container_of(tt_common_entry, | 145 | tt_local_entry = container_of(tt_common_entry, |
94 | struct batadv_tt_local_entry, | 146 | struct batadv_tt_local_entry, |
@@ -96,13 +148,24 @@ batadv_tt_local_hash_find(struct batadv_priv *bat_priv, const void *data) | |||
96 | return tt_local_entry; | 148 | return tt_local_entry; |
97 | } | 149 | } |
98 | 150 | ||
151 | /** | ||
152 | * batadv_tt_global_hash_find - search the global table for a given client | ||
153 | * @bat_priv: the bat priv with all the soft interface information | ||
154 | * @addr: the mac address of the client to look for | ||
155 | * @vid: VLAN identifier | ||
156 | * | ||
157 | * Returns a pointer to the corresponding tt_global_entry struct if the client | ||
158 | * is found, NULL otherwise. | ||
159 | */ | ||
99 | static struct batadv_tt_global_entry * | 160 | static struct batadv_tt_global_entry * |
100 | batadv_tt_global_hash_find(struct batadv_priv *bat_priv, const void *data) | 161 | batadv_tt_global_hash_find(struct batadv_priv *bat_priv, const uint8_t *addr, |
162 | unsigned short vid) | ||
101 | { | 163 | { |
102 | struct batadv_tt_common_entry *tt_common_entry; | 164 | struct batadv_tt_common_entry *tt_common_entry; |
103 | struct batadv_tt_global_entry *tt_global_entry = NULL; | 165 | struct batadv_tt_global_entry *tt_global_entry = NULL; |
104 | 166 | ||
105 | tt_common_entry = batadv_tt_hash_find(bat_priv->tt.global_hash, data); | 167 | tt_common_entry = batadv_tt_hash_find(bat_priv->tt.global_hash, addr, |
168 | vid); | ||
106 | if (tt_common_entry) | 169 | if (tt_common_entry) |
107 | tt_global_entry = container_of(tt_common_entry, | 170 | tt_global_entry = container_of(tt_common_entry, |
108 | struct batadv_tt_global_entry, | 171 | struct batadv_tt_global_entry, |
@@ -117,25 +180,17 @@ batadv_tt_local_entry_free_ref(struct batadv_tt_local_entry *tt_local_entry) | |||
117 | kfree_rcu(tt_local_entry, common.rcu); | 180 | kfree_rcu(tt_local_entry, common.rcu); |
118 | } | 181 | } |
119 | 182 | ||
120 | static void batadv_tt_global_entry_free_rcu(struct rcu_head *rcu) | 183 | /** |
121 | { | 184 | * batadv_tt_global_entry_free_ref - decrement the refcounter for a |
122 | struct batadv_tt_common_entry *tt_common_entry; | 185 | * tt_global_entry and possibly free it |
123 | struct batadv_tt_global_entry *tt_global_entry; | 186 | * @tt_global_entry: the object to free |
124 | 187 | */ | |
125 | tt_common_entry = container_of(rcu, struct batadv_tt_common_entry, rcu); | ||
126 | tt_global_entry = container_of(tt_common_entry, | ||
127 | struct batadv_tt_global_entry, common); | ||
128 | |||
129 | kfree(tt_global_entry); | ||
130 | } | ||
131 | |||
132 | static void | 188 | static void |
133 | batadv_tt_global_entry_free_ref(struct batadv_tt_global_entry *tt_global_entry) | 189 | batadv_tt_global_entry_free_ref(struct batadv_tt_global_entry *tt_global_entry) |
134 | { | 190 | { |
135 | if (atomic_dec_and_test(&tt_global_entry->common.refcount)) { | 191 | if (atomic_dec_and_test(&tt_global_entry->common.refcount)) { |
136 | batadv_tt_global_del_orig_list(tt_global_entry); | 192 | batadv_tt_global_del_orig_list(tt_global_entry); |
137 | call_rcu(&tt_global_entry->common.rcu, | 193 | kfree_rcu(tt_global_entry, common.rcu); |
138 | batadv_tt_global_entry_free_rcu); | ||
139 | } | 194 | } |
140 | } | 195 | } |
141 | 196 | ||
@@ -153,13 +208,107 @@ static void batadv_tt_orig_list_entry_free_rcu(struct rcu_head *rcu) | |||
153 | kfree(orig_entry); | 208 | kfree(orig_entry); |
154 | } | 209 | } |
155 | 210 | ||
211 | /** | ||
212 | * batadv_tt_local_size_mod - change the size by v of the local table identified | ||
213 | * by vid | ||
214 | * @bat_priv: the bat priv with all the soft interface information | ||
215 | * @vid: the VLAN identifier of the sub-table to change | ||
216 | * @v: the amount to sum to the local table size | ||
217 | */ | ||
218 | static void batadv_tt_local_size_mod(struct batadv_priv *bat_priv, | ||
219 | unsigned short vid, int v) | ||
220 | { | ||
221 | struct batadv_softif_vlan *vlan; | ||
222 | |||
223 | vlan = batadv_softif_vlan_get(bat_priv, vid); | ||
224 | if (!vlan) | ||
225 | return; | ||
226 | |||
227 | atomic_add(v, &vlan->tt.num_entries); | ||
228 | |||
229 | batadv_softif_vlan_free_ref(vlan); | ||
230 | } | ||
231 | |||
232 | /** | ||
233 | * batadv_tt_local_size_inc - increase by one the local table size for the given | ||
234 | * vid | ||
235 | * @bat_priv: the bat priv with all the soft interface information | ||
236 | * @vid: the VLAN identifier | ||
237 | */ | ||
238 | static void batadv_tt_local_size_inc(struct batadv_priv *bat_priv, | ||
239 | unsigned short vid) | ||
240 | { | ||
241 | batadv_tt_local_size_mod(bat_priv, vid, 1); | ||
242 | } | ||
243 | |||
244 | /** | ||
245 | * batadv_tt_local_size_dec - decrease by one the local table size for the given | ||
246 | * vid | ||
247 | * @bat_priv: the bat priv with all the soft interface information | ||
248 | * @vid: the VLAN identifier | ||
249 | */ | ||
250 | static void batadv_tt_local_size_dec(struct batadv_priv *bat_priv, | ||
251 | unsigned short vid) | ||
252 | { | ||
253 | batadv_tt_local_size_mod(bat_priv, vid, -1); | ||
254 | } | ||
255 | |||
256 | /** | ||
257 | * batadv_tt_global_size_mod - change the size by v of the local table | ||
258 | * identified by vid | ||
259 | * @bat_priv: the bat priv with all the soft interface information | ||
260 | * @vid: the VLAN identifier | ||
261 | * @v: the amount to sum to the global table size | ||
262 | */ | ||
263 | static void batadv_tt_global_size_mod(struct batadv_orig_node *orig_node, | ||
264 | unsigned short vid, int v) | ||
265 | { | ||
266 | struct batadv_orig_node_vlan *vlan; | ||
267 | |||
268 | vlan = batadv_orig_node_vlan_new(orig_node, vid); | ||
269 | if (!vlan) | ||
270 | return; | ||
271 | |||
272 | if (atomic_add_return(v, &vlan->tt.num_entries) == 0) { | ||
273 | spin_lock_bh(&orig_node->vlan_list_lock); | ||
274 | list_del_rcu(&vlan->list); | ||
275 | spin_unlock_bh(&orig_node->vlan_list_lock); | ||
276 | batadv_orig_node_vlan_free_ref(vlan); | ||
277 | } | ||
278 | |||
279 | batadv_orig_node_vlan_free_ref(vlan); | ||
280 | } | ||
281 | |||
282 | /** | ||
283 | * batadv_tt_global_size_inc - increase by one the global table size for the | ||
284 | * given vid | ||
285 | * @orig_node: the originator which global table size has to be decreased | ||
286 | * @vid: the vlan identifier | ||
287 | */ | ||
288 | static void batadv_tt_global_size_inc(struct batadv_orig_node *orig_node, | ||
289 | unsigned short vid) | ||
290 | { | ||
291 | batadv_tt_global_size_mod(orig_node, vid, 1); | ||
292 | } | ||
293 | |||
294 | /** | ||
295 | * batadv_tt_global_size_dec - decrease by one the global table size for the | ||
296 | * given vid | ||
297 | * @orig_node: the originator which global table size has to be decreased | ||
298 | * @vid: the vlan identifier | ||
299 | */ | ||
300 | static void batadv_tt_global_size_dec(struct batadv_orig_node *orig_node, | ||
301 | unsigned short vid) | ||
302 | { | ||
303 | batadv_tt_global_size_mod(orig_node, vid, -1); | ||
304 | } | ||
305 | |||
156 | static void | 306 | static void |
157 | batadv_tt_orig_list_entry_free_ref(struct batadv_tt_orig_list_entry *orig_entry) | 307 | batadv_tt_orig_list_entry_free_ref(struct batadv_tt_orig_list_entry *orig_entry) |
158 | { | 308 | { |
159 | if (!atomic_dec_and_test(&orig_entry->refcount)) | 309 | if (!atomic_dec_and_test(&orig_entry->refcount)) |
160 | return; | 310 | return; |
161 | /* to avoid race conditions, immediately decrease the tt counter */ | 311 | |
162 | atomic_dec(&orig_entry->orig_node->tt_size); | ||
163 | call_rcu(&orig_entry->rcu, batadv_tt_orig_list_entry_free_rcu); | 312 | call_rcu(&orig_entry->rcu, batadv_tt_orig_list_entry_free_rcu); |
164 | } | 313 | } |
165 | 314 | ||
@@ -180,12 +329,13 @@ static void batadv_tt_local_event(struct batadv_priv *bat_priv, | |||
180 | bool del_op_requested, del_op_entry; | 329 | bool del_op_requested, del_op_entry; |
181 | 330 | ||
182 | tt_change_node = kmalloc(sizeof(*tt_change_node), GFP_ATOMIC); | 331 | tt_change_node = kmalloc(sizeof(*tt_change_node), GFP_ATOMIC); |
183 | |||
184 | if (!tt_change_node) | 332 | if (!tt_change_node) |
185 | return; | 333 | return; |
186 | 334 | ||
187 | tt_change_node->change.flags = flags; | 335 | tt_change_node->change.flags = flags; |
336 | tt_change_node->change.reserved = 0; | ||
188 | memcpy(tt_change_node->change.addr, common->addr, ETH_ALEN); | 337 | memcpy(tt_change_node->change.addr, common->addr, ETH_ALEN); |
338 | tt_change_node->change.vid = htons(common->vid); | ||
189 | 339 | ||
190 | del_op_requested = flags & BATADV_TT_CLIENT_DEL; | 340 | del_op_requested = flags & BATADV_TT_CLIENT_DEL; |
191 | 341 | ||
@@ -229,9 +379,26 @@ unlock: | |||
229 | atomic_inc(&bat_priv->tt.local_changes); | 379 | atomic_inc(&bat_priv->tt.local_changes); |
230 | } | 380 | } |
231 | 381 | ||
232 | int batadv_tt_len(int changes_num) | 382 | /** |
383 | * batadv_tt_len - compute length in bytes of given number of tt changes | ||
384 | * @changes_num: number of tt changes | ||
385 | * | ||
386 | * Returns computed length in bytes. | ||
387 | */ | ||
388 | static int batadv_tt_len(int changes_num) | ||
233 | { | 389 | { |
234 | return changes_num * sizeof(struct batadv_tt_change); | 390 | return changes_num * sizeof(struct batadv_tvlv_tt_change); |
391 | } | ||
392 | |||
393 | /** | ||
394 | * batadv_tt_entries - compute the number of entries fitting in tt_len bytes | ||
395 | * @tt_len: available space | ||
396 | * | ||
397 | * Returns the number of entries. | ||
398 | */ | ||
399 | static uint16_t batadv_tt_entries(uint16_t tt_len) | ||
400 | { | ||
401 | return tt_len / batadv_tt_len(1); | ||
235 | } | 402 | } |
236 | 403 | ||
237 | static int batadv_tt_local_init(struct batadv_priv *bat_priv) | 404 | static int batadv_tt_local_init(struct batadv_priv *bat_priv) |
@@ -255,16 +422,26 @@ static void batadv_tt_global_free(struct batadv_priv *bat_priv, | |||
255 | const char *message) | 422 | const char *message) |
256 | { | 423 | { |
257 | batadv_dbg(BATADV_DBG_TT, bat_priv, | 424 | batadv_dbg(BATADV_DBG_TT, bat_priv, |
258 | "Deleting global tt entry %pM: %s\n", | 425 | "Deleting global tt entry %pM (vid: %d): %s\n", |
259 | tt_global->common.addr, message); | 426 | tt_global->common.addr, |
427 | BATADV_PRINT_VID(tt_global->common.vid), message); | ||
260 | 428 | ||
261 | batadv_hash_remove(bat_priv->tt.global_hash, batadv_compare_tt, | 429 | batadv_hash_remove(bat_priv->tt.global_hash, batadv_compare_tt, |
262 | batadv_choose_orig, tt_global->common.addr); | 430 | batadv_choose_tt, &tt_global->common); |
263 | batadv_tt_global_entry_free_ref(tt_global); | 431 | batadv_tt_global_entry_free_ref(tt_global); |
264 | } | 432 | } |
265 | 433 | ||
434 | /** | ||
435 | * batadv_tt_local_add - add a new client to the local table or update an | ||
436 | * existing client | ||
437 | * @soft_iface: netdev struct of the mesh interface | ||
438 | * @addr: the mac address of the client to add | ||
439 | * @vid: VLAN identifier | ||
440 | * @ifindex: index of the interface where the client is connected to (useful to | ||
441 | * identify wireless clients) | ||
442 | */ | ||
266 | void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr, | 443 | void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr, |
267 | int ifindex) | 444 | unsigned short vid, int ifindex) |
268 | { | 445 | { |
269 | struct batadv_priv *bat_priv = netdev_priv(soft_iface); | 446 | struct batadv_priv *bat_priv = netdev_priv(soft_iface); |
270 | struct batadv_tt_local_entry *tt_local; | 447 | struct batadv_tt_local_entry *tt_local; |
@@ -274,14 +451,15 @@ void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr, | |||
274 | int hash_added; | 451 | int hash_added; |
275 | bool roamed_back = false; | 452 | bool roamed_back = false; |
276 | 453 | ||
277 | tt_local = batadv_tt_local_hash_find(bat_priv, addr); | 454 | tt_local = batadv_tt_local_hash_find(bat_priv, addr, vid); |
278 | tt_global = batadv_tt_global_hash_find(bat_priv, addr); | 455 | tt_global = batadv_tt_global_hash_find(bat_priv, addr, vid); |
279 | 456 | ||
280 | if (tt_local) { | 457 | if (tt_local) { |
281 | tt_local->last_seen = jiffies; | 458 | tt_local->last_seen = jiffies; |
282 | if (tt_local->common.flags & BATADV_TT_CLIENT_PENDING) { | 459 | if (tt_local->common.flags & BATADV_TT_CLIENT_PENDING) { |
283 | batadv_dbg(BATADV_DBG_TT, bat_priv, | 460 | batadv_dbg(BATADV_DBG_TT, bat_priv, |
284 | "Re-adding pending client %pM\n", addr); | 461 | "Re-adding pending client %pM (vid: %d)\n", |
462 | addr, BATADV_PRINT_VID(vid)); | ||
285 | /* whatever the reason why the PENDING flag was set, | 463 | /* whatever the reason why the PENDING flag was set, |
286 | * this is a client which was enqueued to be removed in | 464 | * this is a client which was enqueued to be removed in |
287 | * this orig_interval. Since it popped up again, the | 465 | * this orig_interval. Since it popped up again, the |
@@ -293,8 +471,8 @@ void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr, | |||
293 | 471 | ||
294 | if (tt_local->common.flags & BATADV_TT_CLIENT_ROAM) { | 472 | if (tt_local->common.flags & BATADV_TT_CLIENT_ROAM) { |
295 | batadv_dbg(BATADV_DBG_TT, bat_priv, | 473 | batadv_dbg(BATADV_DBG_TT, bat_priv, |
296 | "Roaming client %pM came back to its original location\n", | 474 | "Roaming client %pM (vid: %d) came back to its original location\n", |
297 | addr); | 475 | addr, BATADV_PRINT_VID(vid)); |
298 | /* the ROAM flag is set because this client roamed away | 476 | /* the ROAM flag is set because this client roamed away |
299 | * and the node got a roaming_advertisement message. Now | 477 | * and the node got a roaming_advertisement message. Now |
300 | * that the client popped up again at its original | 478 | * that the client popped up again at its original |
@@ -311,7 +489,8 @@ void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr, | |||
311 | goto out; | 489 | goto out; |
312 | 490 | ||
313 | batadv_dbg(BATADV_DBG_TT, bat_priv, | 491 | batadv_dbg(BATADV_DBG_TT, bat_priv, |
314 | "Creating new local tt entry: %pM (ttvn: %d)\n", addr, | 492 | "Creating new local tt entry: %pM (vid: %d, ttvn: %d)\n", |
493 | addr, BATADV_PRINT_VID(vid), | ||
315 | (uint8_t)atomic_read(&bat_priv->tt.vn)); | 494 | (uint8_t)atomic_read(&bat_priv->tt.vn)); |
316 | 495 | ||
317 | memcpy(tt_local->common.addr, addr, ETH_ALEN); | 496 | memcpy(tt_local->common.addr, addr, ETH_ALEN); |
@@ -320,6 +499,7 @@ void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr, | |||
320 | * (consistency check) | 499 | * (consistency check) |
321 | */ | 500 | */ |
322 | tt_local->common.flags = BATADV_TT_CLIENT_NEW; | 501 | tt_local->common.flags = BATADV_TT_CLIENT_NEW; |
502 | tt_local->common.vid = vid; | ||
323 | if (batadv_is_wifi_iface(ifindex)) | 503 | if (batadv_is_wifi_iface(ifindex)) |
324 | tt_local->common.flags |= BATADV_TT_CLIENT_WIFI; | 504 | tt_local->common.flags |= BATADV_TT_CLIENT_WIFI; |
325 | atomic_set(&tt_local->common.refcount, 2); | 505 | atomic_set(&tt_local->common.refcount, 2); |
@@ -331,7 +511,7 @@ void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr, | |||
331 | tt_local->common.flags |= BATADV_TT_CLIENT_NOPURGE; | 511 | tt_local->common.flags |= BATADV_TT_CLIENT_NOPURGE; |
332 | 512 | ||
333 | hash_added = batadv_hash_add(bat_priv->tt.local_hash, batadv_compare_tt, | 513 | hash_added = batadv_hash_add(bat_priv->tt.local_hash, batadv_compare_tt, |
334 | batadv_choose_orig, &tt_local->common, | 514 | batadv_choose_tt, &tt_local->common, |
335 | &tt_local->common.hash_entry); | 515 | &tt_local->common.hash_entry); |
336 | 516 | ||
337 | if (unlikely(hash_added != 0)) { | 517 | if (unlikely(hash_added != 0)) { |
@@ -353,6 +533,7 @@ check_roaming: | |||
353 | rcu_read_lock(); | 533 | rcu_read_lock(); |
354 | hlist_for_each_entry_rcu(orig_entry, head, list) { | 534 | hlist_for_each_entry_rcu(orig_entry, head, list) { |
355 | batadv_send_roam_adv(bat_priv, tt_global->common.addr, | 535 | batadv_send_roam_adv(bat_priv, tt_global->common.addr, |
536 | tt_global->common.vid, | ||
356 | orig_entry->orig_node); | 537 | orig_entry->orig_node); |
357 | } | 538 | } |
358 | rcu_read_unlock(); | 539 | rcu_read_unlock(); |
@@ -376,71 +557,192 @@ out: | |||
376 | batadv_tt_global_entry_free_ref(tt_global); | 557 | batadv_tt_global_entry_free_ref(tt_global); |
377 | } | 558 | } |
378 | 559 | ||
379 | static void batadv_tt_realloc_packet_buff(unsigned char **packet_buff, | 560 | /** |
380 | int *packet_buff_len, | 561 | * batadv_tt_prepare_tvlv_global_data - prepare the TVLV TT header to send |
381 | int min_packet_len, | 562 | * within a TT Response directed to another node |
382 | int new_packet_len) | 563 | * @orig_node: originator for which the TT data has to be prepared |
564 | * @tt_data: uninitialised pointer to the address of the TVLV buffer | ||
565 | * @tt_change: uninitialised pointer to the address of the area where the TT | ||
566 | * changed can be stored | ||
567 | * @tt_len: pointer to the length to reserve to the tt_change. if -1 this | ||
568 | * function reserves the amount of space needed to send the entire global TT | ||
569 | * table. In case of success the value is updated with the real amount of | ||
570 | * reserved bytes | ||
571 | |||
572 | * Allocate the needed amount of memory for the entire TT TVLV and write its | ||
573 | * header made up by one tvlv_tt_data object and a series of tvlv_tt_vlan_data | ||
574 | * objects, one per active VLAN served by the originator node. | ||
575 | * | ||
576 | * Return the size of the allocated buffer or 0 in case of failure. | ||
577 | */ | ||
578 | static uint16_t | ||
579 | batadv_tt_prepare_tvlv_global_data(struct batadv_orig_node *orig_node, | ||
580 | struct batadv_tvlv_tt_data **tt_data, | ||
581 | struct batadv_tvlv_tt_change **tt_change, | ||
582 | int32_t *tt_len) | ||
383 | { | 583 | { |
384 | unsigned char *new_buff; | 584 | uint16_t num_vlan = 0, num_entries = 0, change_offset, tvlv_len; |
585 | struct batadv_tvlv_tt_vlan_data *tt_vlan; | ||
586 | struct batadv_orig_node_vlan *vlan; | ||
587 | uint8_t *tt_change_ptr; | ||
588 | |||
589 | rcu_read_lock(); | ||
590 | list_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) { | ||
591 | num_vlan++; | ||
592 | num_entries += atomic_read(&vlan->tt.num_entries); | ||
593 | } | ||
594 | |||
595 | change_offset = sizeof(**tt_data); | ||
596 | change_offset += num_vlan * sizeof(*tt_vlan); | ||
385 | 597 | ||
386 | new_buff = kmalloc(new_packet_len, GFP_ATOMIC); | 598 | /* if tt_len is negative, allocate the space needed by the full table */ |
599 | if (*tt_len < 0) | ||
600 | *tt_len = batadv_tt_len(num_entries); | ||
387 | 601 | ||
388 | /* keep old buffer if kmalloc should fail */ | 602 | tvlv_len = *tt_len; |
389 | if (new_buff) { | 603 | tvlv_len += change_offset; |
390 | memcpy(new_buff, *packet_buff, min_packet_len); | 604 | |
391 | kfree(*packet_buff); | 605 | *tt_data = kmalloc(tvlv_len, GFP_ATOMIC); |
392 | *packet_buff = new_buff; | 606 | if (!*tt_data) { |
393 | *packet_buff_len = new_packet_len; | 607 | *tt_len = 0; |
608 | goto out; | ||
394 | } | 609 | } |
610 | |||
611 | (*tt_data)->flags = BATADV_NO_FLAGS; | ||
612 | (*tt_data)->ttvn = atomic_read(&orig_node->last_ttvn); | ||
613 | (*tt_data)->num_vlan = htons(num_vlan); | ||
614 | |||
615 | tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(*tt_data + 1); | ||
616 | list_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) { | ||
617 | tt_vlan->vid = htons(vlan->vid); | ||
618 | tt_vlan->crc = htonl(vlan->tt.crc); | ||
619 | |||
620 | tt_vlan++; | ||
621 | } | ||
622 | |||
623 | tt_change_ptr = (uint8_t *)*tt_data + change_offset; | ||
624 | *tt_change = (struct batadv_tvlv_tt_change *)tt_change_ptr; | ||
625 | |||
626 | out: | ||
627 | rcu_read_unlock(); | ||
628 | return tvlv_len; | ||
395 | } | 629 | } |
396 | 630 | ||
397 | static void batadv_tt_prepare_packet_buff(struct batadv_priv *bat_priv, | 631 | /** |
398 | unsigned char **packet_buff, | 632 | * batadv_tt_prepare_tvlv_local_data - allocate and prepare the TT TVLV for this |
399 | int *packet_buff_len, | 633 | * node |
400 | int min_packet_len) | 634 | * @bat_priv: the bat priv with all the soft interface information |
401 | { | 635 | * @tt_data: uninitialised pointer to the address of the TVLV buffer |
402 | int req_len; | 636 | * @tt_change: uninitialised pointer to the address of the area where the TT |
637 | * changes can be stored | ||
638 | * @tt_len: pointer to the length to reserve to the tt_change. if -1 this | ||
639 | * function reserves the amount of space needed to send the entire local TT | ||
640 | * table. In case of success the value is updated with the real amount of | ||
641 | * reserved bytes | ||
642 | * | ||
643 | * Allocate the needed amount of memory for the entire TT TVLV and write its | ||
644 | * header made up by one tvlv_tt_data object and a series of tvlv_tt_vlan_data | ||
645 | * objects, one per active VLAN. | ||
646 | * | ||
647 | * Return the size of the allocated buffer or 0 in case of failure. | ||
648 | */ | ||
649 | static uint16_t | ||
650 | batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv, | ||
651 | struct batadv_tvlv_tt_data **tt_data, | ||
652 | struct batadv_tvlv_tt_change **tt_change, | ||
653 | int32_t *tt_len) | ||
654 | { | ||
655 | struct batadv_tvlv_tt_vlan_data *tt_vlan; | ||
656 | struct batadv_softif_vlan *vlan; | ||
657 | uint16_t num_vlan = 0, num_entries = 0, tvlv_len; | ||
658 | uint8_t *tt_change_ptr; | ||
659 | int change_offset; | ||
403 | 660 | ||
404 | req_len = min_packet_len; | 661 | rcu_read_lock(); |
405 | req_len += batadv_tt_len(atomic_read(&bat_priv->tt.local_changes)); | 662 | hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) { |
663 | num_vlan++; | ||
664 | num_entries += atomic_read(&vlan->tt.num_entries); | ||
665 | } | ||
406 | 666 | ||
407 | /* if we have too many changes for one packet don't send any | 667 | change_offset = sizeof(**tt_data); |
408 | * and wait for the tt table request which will be fragmented | 668 | change_offset += num_vlan * sizeof(*tt_vlan); |
409 | */ | ||
410 | if (req_len > bat_priv->soft_iface->mtu) | ||
411 | req_len = min_packet_len; | ||
412 | 669 | ||
413 | batadv_tt_realloc_packet_buff(packet_buff, packet_buff_len, | 670 | /* if tt_len is negative, allocate the space needed by the full table */ |
414 | min_packet_len, req_len); | 671 | if (*tt_len < 0) |
672 | *tt_len = batadv_tt_len(num_entries); | ||
673 | |||
674 | tvlv_len = *tt_len; | ||
675 | tvlv_len += change_offset; | ||
676 | |||
677 | *tt_data = kmalloc(tvlv_len, GFP_ATOMIC); | ||
678 | if (!*tt_data) { | ||
679 | tvlv_len = 0; | ||
680 | goto out; | ||
681 | } | ||
682 | |||
683 | (*tt_data)->flags = BATADV_NO_FLAGS; | ||
684 | (*tt_data)->ttvn = atomic_read(&bat_priv->tt.vn); | ||
685 | (*tt_data)->num_vlan = htons(num_vlan); | ||
686 | |||
687 | tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(*tt_data + 1); | ||
688 | hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) { | ||
689 | tt_vlan->vid = htons(vlan->vid); | ||
690 | tt_vlan->crc = htonl(vlan->tt.crc); | ||
691 | |||
692 | tt_vlan++; | ||
693 | } | ||
694 | |||
695 | tt_change_ptr = (uint8_t *)*tt_data + change_offset; | ||
696 | *tt_change = (struct batadv_tvlv_tt_change *)tt_change_ptr; | ||
697 | |||
698 | out: | ||
699 | rcu_read_unlock(); | ||
700 | return tvlv_len; | ||
415 | } | 701 | } |
416 | 702 | ||
417 | static int batadv_tt_changes_fill_buff(struct batadv_priv *bat_priv, | 703 | /** |
418 | unsigned char **packet_buff, | 704 | * batadv_tt_tvlv_container_update - update the translation table tvlv container |
419 | int *packet_buff_len, | 705 | * after local tt changes have been committed |
420 | int min_packet_len) | 706 | * @bat_priv: the bat priv with all the soft interface information |
707 | */ | ||
708 | static void batadv_tt_tvlv_container_update(struct batadv_priv *bat_priv) | ||
421 | { | 709 | { |
422 | struct batadv_tt_change_node *entry, *safe; | 710 | struct batadv_tt_change_node *entry, *safe; |
423 | int count = 0, tot_changes = 0, new_len; | 711 | struct batadv_tvlv_tt_data *tt_data; |
424 | unsigned char *tt_buff; | 712 | struct batadv_tvlv_tt_change *tt_change; |
713 | int tt_diff_len, tt_change_len = 0; | ||
714 | int tt_diff_entries_num = 0, tt_diff_entries_count = 0; | ||
715 | uint16_t tvlv_len; | ||
716 | |||
717 | tt_diff_entries_num = atomic_read(&bat_priv->tt.local_changes); | ||
718 | tt_diff_len = batadv_tt_len(tt_diff_entries_num); | ||
719 | |||
720 | /* if we have too many changes for one packet don't send any | ||
721 | * and wait for the tt table request which will be fragmented | ||
722 | */ | ||
723 | if (tt_diff_len > bat_priv->soft_iface->mtu) | ||
724 | tt_diff_len = 0; | ||
425 | 725 | ||
426 | batadv_tt_prepare_packet_buff(bat_priv, packet_buff, | 726 | tvlv_len = batadv_tt_prepare_tvlv_local_data(bat_priv, &tt_data, |
427 | packet_buff_len, min_packet_len); | 727 | &tt_change, &tt_diff_len); |
728 | if (!tvlv_len) | ||
729 | return; | ||
428 | 730 | ||
429 | new_len = *packet_buff_len - min_packet_len; | 731 | tt_data->flags = BATADV_TT_OGM_DIFF; |
430 | tt_buff = *packet_buff + min_packet_len; | ||
431 | 732 | ||
432 | if (new_len > 0) | 733 | if (tt_diff_len == 0) |
433 | tot_changes = new_len / batadv_tt_len(1); | 734 | goto container_register; |
434 | 735 | ||
435 | spin_lock_bh(&bat_priv->tt.changes_list_lock); | 736 | spin_lock_bh(&bat_priv->tt.changes_list_lock); |
436 | atomic_set(&bat_priv->tt.local_changes, 0); | 737 | atomic_set(&bat_priv->tt.local_changes, 0); |
437 | 738 | ||
438 | list_for_each_entry_safe(entry, safe, &bat_priv->tt.changes_list, | 739 | list_for_each_entry_safe(entry, safe, &bat_priv->tt.changes_list, |
439 | list) { | 740 | list) { |
440 | if (count < tot_changes) { | 741 | if (tt_diff_entries_count < tt_diff_entries_num) { |
441 | memcpy(tt_buff + batadv_tt_len(count), | 742 | memcpy(tt_change + tt_diff_entries_count, |
442 | &entry->change, sizeof(struct batadv_tt_change)); | 743 | &entry->change, |
443 | count++; | 744 | sizeof(struct batadv_tvlv_tt_change)); |
745 | tt_diff_entries_count++; | ||
444 | } | 746 | } |
445 | list_del(&entry->list); | 747 | list_del(&entry->list); |
446 | kfree(entry); | 748 | kfree(entry); |
@@ -452,20 +754,25 @@ static int batadv_tt_changes_fill_buff(struct batadv_priv *bat_priv, | |||
452 | kfree(bat_priv->tt.last_changeset); | 754 | kfree(bat_priv->tt.last_changeset); |
453 | bat_priv->tt.last_changeset_len = 0; | 755 | bat_priv->tt.last_changeset_len = 0; |
454 | bat_priv->tt.last_changeset = NULL; | 756 | bat_priv->tt.last_changeset = NULL; |
757 | tt_change_len = batadv_tt_len(tt_diff_entries_count); | ||
455 | /* check whether this new OGM has no changes due to size problems */ | 758 | /* check whether this new OGM has no changes due to size problems */ |
456 | if (new_len > 0) { | 759 | if (tt_diff_entries_count > 0) { |
457 | /* if kmalloc() fails we will reply with the full table | 760 | /* if kmalloc() fails we will reply with the full table |
458 | * instead of providing the diff | 761 | * instead of providing the diff |
459 | */ | 762 | */ |
460 | bat_priv->tt.last_changeset = kmalloc(new_len, GFP_ATOMIC); | 763 | bat_priv->tt.last_changeset = kzalloc(tt_diff_len, GFP_ATOMIC); |
461 | if (bat_priv->tt.last_changeset) { | 764 | if (bat_priv->tt.last_changeset) { |
462 | memcpy(bat_priv->tt.last_changeset, tt_buff, new_len); | 765 | memcpy(bat_priv->tt.last_changeset, |
463 | bat_priv->tt.last_changeset_len = new_len; | 766 | tt_change, tt_change_len); |
767 | bat_priv->tt.last_changeset_len = tt_diff_len; | ||
464 | } | 768 | } |
465 | } | 769 | } |
466 | spin_unlock_bh(&bat_priv->tt.last_changeset_lock); | 770 | spin_unlock_bh(&bat_priv->tt.last_changeset_lock); |
467 | 771 | ||
468 | return count; | 772 | container_register: |
773 | batadv_tvlv_container_register(bat_priv, BATADV_TVLV_TT, 1, tt_data, | ||
774 | tvlv_len); | ||
775 | kfree(tt_data); | ||
469 | } | 776 | } |
470 | 777 | ||
471 | int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset) | 778 | int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset) |
@@ -476,7 +783,9 @@ int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset) | |||
476 | struct batadv_tt_common_entry *tt_common_entry; | 783 | struct batadv_tt_common_entry *tt_common_entry; |
477 | struct batadv_tt_local_entry *tt_local; | 784 | struct batadv_tt_local_entry *tt_local; |
478 | struct batadv_hard_iface *primary_if; | 785 | struct batadv_hard_iface *primary_if; |
786 | struct batadv_softif_vlan *vlan; | ||
479 | struct hlist_head *head; | 787 | struct hlist_head *head; |
788 | unsigned short vid; | ||
480 | uint32_t i; | 789 | uint32_t i; |
481 | int last_seen_secs; | 790 | int last_seen_secs; |
482 | int last_seen_msecs; | 791 | int last_seen_msecs; |
@@ -489,11 +798,10 @@ int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset) | |||
489 | goto out; | 798 | goto out; |
490 | 799 | ||
491 | seq_printf(seq, | 800 | seq_printf(seq, |
492 | "Locally retrieved addresses (from %s) announced via TT (TTVN: %u CRC: %#.4x):\n", | 801 | "Locally retrieved addresses (from %s) announced via TT (TTVN: %u):\n", |
493 | net_dev->name, (uint8_t)atomic_read(&bat_priv->tt.vn), | 802 | net_dev->name, (uint8_t)atomic_read(&bat_priv->tt.vn)); |
494 | bat_priv->tt.local_crc); | 803 | seq_printf(seq, " %-13s %s %-7s %-9s (%-10s)\n", "Client", "VID", |
495 | seq_printf(seq, " %-13s %-7s %-10s\n", "Client", "Flags", | 804 | "Flags", "Last seen", "CRC"); |
496 | "Last seen"); | ||
497 | 805 | ||
498 | for (i = 0; i < hash->size; i++) { | 806 | for (i = 0; i < hash->size; i++) { |
499 | head = &hash->table[i]; | 807 | head = &hash->table[i]; |
@@ -504,6 +812,7 @@ int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset) | |||
504 | tt_local = container_of(tt_common_entry, | 812 | tt_local = container_of(tt_common_entry, |
505 | struct batadv_tt_local_entry, | 813 | struct batadv_tt_local_entry, |
506 | common); | 814 | common); |
815 | vid = tt_common_entry->vid; | ||
507 | last_seen_jiffies = jiffies - tt_local->last_seen; | 816 | last_seen_jiffies = jiffies - tt_local->last_seen; |
508 | last_seen_msecs = jiffies_to_msecs(last_seen_jiffies); | 817 | last_seen_msecs = jiffies_to_msecs(last_seen_jiffies); |
509 | last_seen_secs = last_seen_msecs / 1000; | 818 | last_seen_secs = last_seen_msecs / 1000; |
@@ -511,8 +820,17 @@ int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset) | |||
511 | 820 | ||
512 | no_purge = tt_common_entry->flags & np_flag; | 821 | no_purge = tt_common_entry->flags & np_flag; |
513 | 822 | ||
514 | seq_printf(seq, " * %pM [%c%c%c%c%c] %3u.%03u\n", | 823 | vlan = batadv_softif_vlan_get(bat_priv, vid); |
824 | if (!vlan) { | ||
825 | seq_printf(seq, "Cannot retrieve VLAN %d\n", | ||
826 | BATADV_PRINT_VID(vid)); | ||
827 | continue; | ||
828 | } | ||
829 | |||
830 | seq_printf(seq, | ||
831 | " * %pM %4i [%c%c%c%c%c] %3u.%03u (%#.8x)\n", | ||
515 | tt_common_entry->addr, | 832 | tt_common_entry->addr, |
833 | BATADV_PRINT_VID(tt_common_entry->vid), | ||
516 | (tt_common_entry->flags & | 834 | (tt_common_entry->flags & |
517 | BATADV_TT_CLIENT_ROAM ? 'R' : '.'), | 835 | BATADV_TT_CLIENT_ROAM ? 'R' : '.'), |
518 | no_purge ? 'P' : '.', | 836 | no_purge ? 'P' : '.', |
@@ -523,7 +841,10 @@ int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset) | |||
523 | (tt_common_entry->flags & | 841 | (tt_common_entry->flags & |
524 | BATADV_TT_CLIENT_WIFI ? 'W' : '.'), | 842 | BATADV_TT_CLIENT_WIFI ? 'W' : '.'), |
525 | no_purge ? 0 : last_seen_secs, | 843 | no_purge ? 0 : last_seen_secs, |
526 | no_purge ? 0 : last_seen_msecs); | 844 | no_purge ? 0 : last_seen_msecs, |
845 | vlan->tt.crc); | ||
846 | |||
847 | batadv_softif_vlan_free_ref(vlan); | ||
527 | } | 848 | } |
528 | rcu_read_unlock(); | 849 | rcu_read_unlock(); |
529 | } | 850 | } |
@@ -547,27 +868,29 @@ batadv_tt_local_set_pending(struct batadv_priv *bat_priv, | |||
547 | tt_local_entry->common.flags |= BATADV_TT_CLIENT_PENDING; | 868 | tt_local_entry->common.flags |= BATADV_TT_CLIENT_PENDING; |
548 | 869 | ||
549 | batadv_dbg(BATADV_DBG_TT, bat_priv, | 870 | batadv_dbg(BATADV_DBG_TT, bat_priv, |
550 | "Local tt entry (%pM) pending to be removed: %s\n", | 871 | "Local tt entry (%pM, vid: %d) pending to be removed: %s\n", |
551 | tt_local_entry->common.addr, message); | 872 | tt_local_entry->common.addr, |
873 | BATADV_PRINT_VID(tt_local_entry->common.vid), message); | ||
552 | } | 874 | } |
553 | 875 | ||
554 | /** | 876 | /** |
555 | * batadv_tt_local_remove - logically remove an entry from the local table | 877 | * batadv_tt_local_remove - logically remove an entry from the local table |
556 | * @bat_priv: the bat priv with all the soft interface information | 878 | * @bat_priv: the bat priv with all the soft interface information |
557 | * @addr: the MAC address of the client to remove | 879 | * @addr: the MAC address of the client to remove |
880 | * @vid: VLAN identifier | ||
558 | * @message: message to append to the log on deletion | 881 | * @message: message to append to the log on deletion |
559 | * @roaming: true if the deletion is due to a roaming event | 882 | * @roaming: true if the deletion is due to a roaming event |
560 | * | 883 | * |
561 | * Returns the flags assigned to the local entry before being deleted | 884 | * Returns the flags assigned to the local entry before being deleted |
562 | */ | 885 | */ |
563 | uint16_t batadv_tt_local_remove(struct batadv_priv *bat_priv, | 886 | uint16_t batadv_tt_local_remove(struct batadv_priv *bat_priv, |
564 | const uint8_t *addr, const char *message, | 887 | const uint8_t *addr, unsigned short vid, |
565 | bool roaming) | 888 | const char *message, bool roaming) |
566 | { | 889 | { |
567 | struct batadv_tt_local_entry *tt_local_entry; | 890 | struct batadv_tt_local_entry *tt_local_entry; |
568 | uint16_t flags, curr_flags = BATADV_NO_FLAGS; | 891 | uint16_t flags, curr_flags = BATADV_NO_FLAGS; |
569 | 892 | ||
570 | tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr); | 893 | tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid); |
571 | if (!tt_local_entry) | 894 | if (!tt_local_entry) |
572 | goto out; | 895 | goto out; |
573 | 896 | ||
@@ -784,7 +1107,7 @@ batadv_tt_global_orig_entry_add(struct batadv_tt_global_entry *tt_global, | |||
784 | 1107 | ||
785 | INIT_HLIST_NODE(&orig_entry->list); | 1108 | INIT_HLIST_NODE(&orig_entry->list); |
786 | atomic_inc(&orig_node->refcount); | 1109 | atomic_inc(&orig_node->refcount); |
787 | atomic_inc(&orig_node->tt_size); | 1110 | batadv_tt_global_size_inc(orig_node, tt_global->common.vid); |
788 | orig_entry->orig_node = orig_node; | 1111 | orig_entry->orig_node = orig_node; |
789 | orig_entry->ttvn = ttvn; | 1112 | orig_entry->ttvn = ttvn; |
790 | atomic_set(&orig_entry->refcount, 2); | 1113 | atomic_set(&orig_entry->refcount, 2); |
@@ -803,6 +1126,7 @@ out: | |||
803 | * @bat_priv: the bat priv with all the soft interface information | 1126 | * @bat_priv: the bat priv with all the soft interface information |
804 | * @orig_node: the originator announcing the client | 1127 | * @orig_node: the originator announcing the client |
805 | * @tt_addr: the mac address of the non-mesh client | 1128 | * @tt_addr: the mac address of the non-mesh client |
1129 | * @vid: VLAN identifier | ||
806 | * @flags: TT flags that have to be set for this non-mesh client | 1130 | * @flags: TT flags that have to be set for this non-mesh client |
807 | * @ttvn: the tt version number ever announcing this non-mesh client | 1131 | * @ttvn: the tt version number ever announcing this non-mesh client |
808 | * | 1132 | * |
@@ -813,21 +1137,28 @@ out: | |||
813 | * If a TT local entry exists for this non-mesh client remove it. | 1137 | * If a TT local entry exists for this non-mesh client remove it. |
814 | * | 1138 | * |
815 | * The caller must hold orig_node refcount. | 1139 | * The caller must hold orig_node refcount. |
1140 | * | ||
1141 | * Return true if the new entry has been added, false otherwise | ||
816 | */ | 1142 | */ |
817 | int batadv_tt_global_add(struct batadv_priv *bat_priv, | 1143 | static bool batadv_tt_global_add(struct batadv_priv *bat_priv, |
818 | struct batadv_orig_node *orig_node, | 1144 | struct batadv_orig_node *orig_node, |
819 | const unsigned char *tt_addr, uint16_t flags, | 1145 | const unsigned char *tt_addr, |
820 | uint8_t ttvn) | 1146 | unsigned short vid, uint16_t flags, |
1147 | uint8_t ttvn) | ||
821 | { | 1148 | { |
822 | struct batadv_tt_global_entry *tt_global_entry; | 1149 | struct batadv_tt_global_entry *tt_global_entry; |
823 | struct batadv_tt_local_entry *tt_local_entry; | 1150 | struct batadv_tt_local_entry *tt_local_entry; |
824 | int ret = 0; | 1151 | bool ret = false; |
825 | int hash_added; | 1152 | int hash_added; |
826 | struct batadv_tt_common_entry *common; | 1153 | struct batadv_tt_common_entry *common; |
827 | uint16_t local_flags; | 1154 | uint16_t local_flags; |
828 | 1155 | ||
829 | tt_global_entry = batadv_tt_global_hash_find(bat_priv, tt_addr); | 1156 | /* ignore global entries from backbone nodes */ |
830 | tt_local_entry = batadv_tt_local_hash_find(bat_priv, tt_addr); | 1157 | if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig, vid)) |
1158 | return true; | ||
1159 | |||
1160 | tt_global_entry = batadv_tt_global_hash_find(bat_priv, tt_addr, vid); | ||
1161 | tt_local_entry = batadv_tt_local_hash_find(bat_priv, tt_addr, vid); | ||
831 | 1162 | ||
832 | /* if the node already has a local client for this entry, it has to wait | 1163 | /* if the node already has a local client for this entry, it has to wait |
833 | * for a roaming advertisement instead of manually messing up the global | 1164 | * for a roaming advertisement instead of manually messing up the global |
@@ -844,6 +1175,7 @@ int batadv_tt_global_add(struct batadv_priv *bat_priv, | |||
844 | 1175 | ||
845 | common = &tt_global_entry->common; | 1176 | common = &tt_global_entry->common; |
846 | memcpy(common->addr, tt_addr, ETH_ALEN); | 1177 | memcpy(common->addr, tt_addr, ETH_ALEN); |
1178 | common->vid = vid; | ||
847 | 1179 | ||
848 | common->flags = flags; | 1180 | common->flags = flags; |
849 | tt_global_entry->roam_at = 0; | 1181 | tt_global_entry->roam_at = 0; |
@@ -861,7 +1193,7 @@ int batadv_tt_global_add(struct batadv_priv *bat_priv, | |||
861 | 1193 | ||
862 | hash_added = batadv_hash_add(bat_priv->tt.global_hash, | 1194 | hash_added = batadv_hash_add(bat_priv->tt.global_hash, |
863 | batadv_compare_tt, | 1195 | batadv_compare_tt, |
864 | batadv_choose_orig, common, | 1196 | batadv_choose_tt, common, |
865 | &common->hash_entry); | 1197 | &common->hash_entry); |
866 | 1198 | ||
867 | if (unlikely(hash_added != 0)) { | 1199 | if (unlikely(hash_added != 0)) { |
@@ -920,14 +1252,15 @@ add_orig_entry: | |||
920 | batadv_tt_global_orig_entry_add(tt_global_entry, orig_node, ttvn); | 1252 | batadv_tt_global_orig_entry_add(tt_global_entry, orig_node, ttvn); |
921 | 1253 | ||
922 | batadv_dbg(BATADV_DBG_TT, bat_priv, | 1254 | batadv_dbg(BATADV_DBG_TT, bat_priv, |
923 | "Creating new global tt entry: %pM (via %pM)\n", | 1255 | "Creating new global tt entry: %pM (vid: %d, via %pM)\n", |
924 | common->addr, orig_node->orig); | 1256 | common->addr, BATADV_PRINT_VID(common->vid), |
925 | ret = 1; | 1257 | orig_node->orig); |
1258 | ret = true; | ||
926 | 1259 | ||
927 | out_remove: | 1260 | out_remove: |
928 | 1261 | ||
929 | /* remove address from local hash if present */ | 1262 | /* remove address from local hash if present */ |
930 | local_flags = batadv_tt_local_remove(bat_priv, tt_addr, | 1263 | local_flags = batadv_tt_local_remove(bat_priv, tt_addr, vid, |
931 | "global tt received", | 1264 | "global tt received", |
932 | flags & BATADV_TT_CLIENT_ROAM); | 1265 | flags & BATADV_TT_CLIENT_ROAM); |
933 | tt_global_entry->common.flags |= local_flags & BATADV_TT_CLIENT_WIFI; | 1266 | tt_global_entry->common.flags |= local_flags & BATADV_TT_CLIENT_WIFI; |
@@ -988,42 +1321,71 @@ static void | |||
988 | batadv_tt_global_print_entry(struct batadv_tt_global_entry *tt_global_entry, | 1321 | batadv_tt_global_print_entry(struct batadv_tt_global_entry *tt_global_entry, |
989 | struct seq_file *seq) | 1322 | struct seq_file *seq) |
990 | { | 1323 | { |
991 | struct hlist_head *head; | ||
992 | struct batadv_tt_orig_list_entry *orig_entry, *best_entry; | 1324 | struct batadv_tt_orig_list_entry *orig_entry, *best_entry; |
993 | struct batadv_tt_common_entry *tt_common_entry; | 1325 | struct batadv_tt_common_entry *tt_common_entry; |
994 | uint16_t flags; | 1326 | struct batadv_orig_node_vlan *vlan; |
1327 | struct hlist_head *head; | ||
995 | uint8_t last_ttvn; | 1328 | uint8_t last_ttvn; |
1329 | uint16_t flags; | ||
996 | 1330 | ||
997 | tt_common_entry = &tt_global_entry->common; | 1331 | tt_common_entry = &tt_global_entry->common; |
998 | flags = tt_common_entry->flags; | 1332 | flags = tt_common_entry->flags; |
999 | 1333 | ||
1000 | best_entry = batadv_transtable_best_orig(tt_global_entry); | 1334 | best_entry = batadv_transtable_best_orig(tt_global_entry); |
1001 | if (best_entry) { | 1335 | if (best_entry) { |
1336 | vlan = batadv_orig_node_vlan_get(best_entry->orig_node, | ||
1337 | tt_common_entry->vid); | ||
1338 | if (!vlan) { | ||
1339 | seq_printf(seq, | ||
1340 | " * Cannot retrieve VLAN %d for originator %pM\n", | ||
1341 | BATADV_PRINT_VID(tt_common_entry->vid), | ||
1342 | best_entry->orig_node->orig); | ||
1343 | goto print_list; | ||
1344 | } | ||
1345 | |||
1002 | last_ttvn = atomic_read(&best_entry->orig_node->last_ttvn); | 1346 | last_ttvn = atomic_read(&best_entry->orig_node->last_ttvn); |
1003 | seq_printf(seq, | 1347 | seq_printf(seq, |
1004 | " %c %pM (%3u) via %pM (%3u) (%#.4x) [%c%c%c]\n", | 1348 | " %c %pM %4i (%3u) via %pM (%3u) (%#.8x) [%c%c%c]\n", |
1005 | '*', tt_global_entry->common.addr, | 1349 | '*', tt_global_entry->common.addr, |
1350 | BATADV_PRINT_VID(tt_global_entry->common.vid), | ||
1006 | best_entry->ttvn, best_entry->orig_node->orig, | 1351 | best_entry->ttvn, best_entry->orig_node->orig, |
1007 | last_ttvn, best_entry->orig_node->tt_crc, | 1352 | last_ttvn, vlan->tt.crc, |
1008 | (flags & BATADV_TT_CLIENT_ROAM ? 'R' : '.'), | 1353 | (flags & BATADV_TT_CLIENT_ROAM ? 'R' : '.'), |
1009 | (flags & BATADV_TT_CLIENT_WIFI ? 'W' : '.'), | 1354 | (flags & BATADV_TT_CLIENT_WIFI ? 'W' : '.'), |
1010 | (flags & BATADV_TT_CLIENT_TEMP ? 'T' : '.')); | 1355 | (flags & BATADV_TT_CLIENT_TEMP ? 'T' : '.')); |
1356 | |||
1357 | batadv_orig_node_vlan_free_ref(vlan); | ||
1011 | } | 1358 | } |
1012 | 1359 | ||
1360 | print_list: | ||
1013 | head = &tt_global_entry->orig_list; | 1361 | head = &tt_global_entry->orig_list; |
1014 | 1362 | ||
1015 | hlist_for_each_entry_rcu(orig_entry, head, list) { | 1363 | hlist_for_each_entry_rcu(orig_entry, head, list) { |
1016 | if (best_entry == orig_entry) | 1364 | if (best_entry == orig_entry) |
1017 | continue; | 1365 | continue; |
1018 | 1366 | ||
1367 | vlan = batadv_orig_node_vlan_get(orig_entry->orig_node, | ||
1368 | tt_common_entry->vid); | ||
1369 | if (!vlan) { | ||
1370 | seq_printf(seq, | ||
1371 | " + Cannot retrieve VLAN %d for originator %pM\n", | ||
1372 | BATADV_PRINT_VID(tt_common_entry->vid), | ||
1373 | orig_entry->orig_node->orig); | ||
1374 | continue; | ||
1375 | } | ||
1376 | |||
1019 | last_ttvn = atomic_read(&orig_entry->orig_node->last_ttvn); | 1377 | last_ttvn = atomic_read(&orig_entry->orig_node->last_ttvn); |
1020 | seq_printf(seq, " %c %pM (%3u) via %pM (%3u) [%c%c%c]\n", | 1378 | seq_printf(seq, |
1379 | " %c %pM %4d (%3u) via %pM (%3u) (%#.8x) [%c%c%c]\n", | ||
1021 | '+', tt_global_entry->common.addr, | 1380 | '+', tt_global_entry->common.addr, |
1381 | BATADV_PRINT_VID(tt_global_entry->common.vid), | ||
1022 | orig_entry->ttvn, orig_entry->orig_node->orig, | 1382 | orig_entry->ttvn, orig_entry->orig_node->orig, |
1023 | last_ttvn, | 1383 | last_ttvn, vlan->tt.crc, |
1024 | (flags & BATADV_TT_CLIENT_ROAM ? 'R' : '.'), | 1384 | (flags & BATADV_TT_CLIENT_ROAM ? 'R' : '.'), |
1025 | (flags & BATADV_TT_CLIENT_WIFI ? 'W' : '.'), | 1385 | (flags & BATADV_TT_CLIENT_WIFI ? 'W' : '.'), |
1026 | (flags & BATADV_TT_CLIENT_TEMP ? 'T' : '.')); | 1386 | (flags & BATADV_TT_CLIENT_TEMP ? 'T' : '.')); |
1387 | |||
1388 | batadv_orig_node_vlan_free_ref(vlan); | ||
1027 | } | 1389 | } |
1028 | } | 1390 | } |
1029 | 1391 | ||
@@ -1045,9 +1407,9 @@ int batadv_tt_global_seq_print_text(struct seq_file *seq, void *offset) | |||
1045 | seq_printf(seq, | 1407 | seq_printf(seq, |
1046 | "Globally announced TT entries received via the mesh %s\n", | 1408 | "Globally announced TT entries received via the mesh %s\n", |
1047 | net_dev->name); | 1409 | net_dev->name); |
1048 | seq_printf(seq, " %-13s %s %-15s %s (%-6s) %s\n", | 1410 | seq_printf(seq, " %-13s %s %s %-15s %s (%-10s) %s\n", |
1049 | "Client", "(TTVN)", "Originator", "(Curr TTVN)", "CRC", | 1411 | "Client", "VID", "(TTVN)", "Originator", "(Curr TTVN)", |
1050 | "Flags"); | 1412 | "CRC", "Flags"); |
1051 | 1413 | ||
1052 | for (i = 0; i < hash->size; i++) { | 1414 | for (i = 0; i < hash->size; i++) { |
1053 | head = &hash->table[i]; | 1415 | head = &hash->table[i]; |
@@ -1080,6 +1442,8 @@ batadv_tt_global_del_orig_list(struct batadv_tt_global_entry *tt_global_entry) | |||
1080 | head = &tt_global_entry->orig_list; | 1442 | head = &tt_global_entry->orig_list; |
1081 | hlist_for_each_entry_safe(orig_entry, safe, head, list) { | 1443 | hlist_for_each_entry_safe(orig_entry, safe, head, list) { |
1082 | hlist_del_rcu(&orig_entry->list); | 1444 | hlist_del_rcu(&orig_entry->list); |
1445 | batadv_tt_global_size_dec(orig_entry->orig_node, | ||
1446 | tt_global_entry->common.vid); | ||
1083 | batadv_tt_orig_list_entry_free_ref(orig_entry); | 1447 | batadv_tt_orig_list_entry_free_ref(orig_entry); |
1084 | } | 1448 | } |
1085 | spin_unlock_bh(&tt_global_entry->list_lock); | 1449 | spin_unlock_bh(&tt_global_entry->list_lock); |
@@ -1094,16 +1458,21 @@ batadv_tt_global_del_orig_entry(struct batadv_priv *bat_priv, | |||
1094 | struct hlist_head *head; | 1458 | struct hlist_head *head; |
1095 | struct hlist_node *safe; | 1459 | struct hlist_node *safe; |
1096 | struct batadv_tt_orig_list_entry *orig_entry; | 1460 | struct batadv_tt_orig_list_entry *orig_entry; |
1461 | unsigned short vid; | ||
1097 | 1462 | ||
1098 | spin_lock_bh(&tt_global_entry->list_lock); | 1463 | spin_lock_bh(&tt_global_entry->list_lock); |
1099 | head = &tt_global_entry->orig_list; | 1464 | head = &tt_global_entry->orig_list; |
1100 | hlist_for_each_entry_safe(orig_entry, safe, head, list) { | 1465 | hlist_for_each_entry_safe(orig_entry, safe, head, list) { |
1101 | if (orig_entry->orig_node == orig_node) { | 1466 | if (orig_entry->orig_node == orig_node) { |
1467 | vid = tt_global_entry->common.vid; | ||
1102 | batadv_dbg(BATADV_DBG_TT, bat_priv, | 1468 | batadv_dbg(BATADV_DBG_TT, bat_priv, |
1103 | "Deleting %pM from global tt entry %pM: %s\n", | 1469 | "Deleting %pM from global tt entry %pM (vid: %d): %s\n", |
1104 | orig_node->orig, | 1470 | orig_node->orig, |
1105 | tt_global_entry->common.addr, message); | 1471 | tt_global_entry->common.addr, |
1472 | BATADV_PRINT_VID(vid), message); | ||
1106 | hlist_del_rcu(&orig_entry->list); | 1473 | hlist_del_rcu(&orig_entry->list); |
1474 | batadv_tt_global_size_dec(orig_node, | ||
1475 | tt_global_entry->common.vid); | ||
1107 | batadv_tt_orig_list_entry_free_ref(orig_entry); | 1476 | batadv_tt_orig_list_entry_free_ref(orig_entry); |
1108 | } | 1477 | } |
1109 | } | 1478 | } |
@@ -1150,17 +1519,25 @@ batadv_tt_global_del_roaming(struct batadv_priv *bat_priv, | |||
1150 | orig_node, message); | 1519 | orig_node, message); |
1151 | } | 1520 | } |
1152 | 1521 | ||
1153 | 1522 | /** | |
1154 | 1523 | * batadv_tt_global_del - remove a client from the global table | |
1524 | * @bat_priv: the bat priv with all the soft interface information | ||
1525 | * @orig_node: an originator serving this client | ||
1526 | * @addr: the mac address of the client | ||
1527 | * @vid: VLAN identifier | ||
1528 | * @message: a message explaining the reason for deleting the client to print | ||
1529 | * for debugging purpose | ||
1530 | * @roaming: true if the deletion has been triggered by a roaming event | ||
1531 | */ | ||
1155 | static void batadv_tt_global_del(struct batadv_priv *bat_priv, | 1532 | static void batadv_tt_global_del(struct batadv_priv *bat_priv, |
1156 | struct batadv_orig_node *orig_node, | 1533 | struct batadv_orig_node *orig_node, |
1157 | const unsigned char *addr, | 1534 | const unsigned char *addr, unsigned short vid, |
1158 | const char *message, bool roaming) | 1535 | const char *message, bool roaming) |
1159 | { | 1536 | { |
1160 | struct batadv_tt_global_entry *tt_global_entry; | 1537 | struct batadv_tt_global_entry *tt_global_entry; |
1161 | struct batadv_tt_local_entry *local_entry = NULL; | 1538 | struct batadv_tt_local_entry *local_entry = NULL; |
1162 | 1539 | ||
1163 | tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr); | 1540 | tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid); |
1164 | if (!tt_global_entry) | 1541 | if (!tt_global_entry) |
1165 | goto out; | 1542 | goto out; |
1166 | 1543 | ||
@@ -1189,7 +1566,8 @@ static void batadv_tt_global_del(struct batadv_priv *bat_priv, | |||
1189 | * the global entry, since it is useless now. | 1566 | * the global entry, since it is useless now. |
1190 | */ | 1567 | */ |
1191 | local_entry = batadv_tt_local_hash_find(bat_priv, | 1568 | local_entry = batadv_tt_local_hash_find(bat_priv, |
1192 | tt_global_entry->common.addr); | 1569 | tt_global_entry->common.addr, |
1570 | vid); | ||
1193 | if (local_entry) { | 1571 | if (local_entry) { |
1194 | /* local entry exists, case 2: client roamed to us. */ | 1572 | /* local entry exists, case 2: client roamed to us. */ |
1195 | batadv_tt_global_del_orig_list(tt_global_entry); | 1573 | batadv_tt_global_del_orig_list(tt_global_entry); |
@@ -1207,8 +1585,18 @@ out: | |||
1207 | batadv_tt_local_entry_free_ref(local_entry); | 1585 | batadv_tt_local_entry_free_ref(local_entry); |
1208 | } | 1586 | } |
1209 | 1587 | ||
1588 | /** | ||
1589 | * batadv_tt_global_del_orig - remove all the TT global entries belonging to the | ||
1590 | * given originator matching the provided vid | ||
1591 | * @bat_priv: the bat priv with all the soft interface information | ||
1592 | * @orig_node: the originator owning the entries to remove | ||
1593 | * @match_vid: the VLAN identifier to match. If negative all the entries will be | ||
1594 | * removed | ||
1595 | * @message: debug message to print as "reason" | ||
1596 | */ | ||
1210 | void batadv_tt_global_del_orig(struct batadv_priv *bat_priv, | 1597 | void batadv_tt_global_del_orig(struct batadv_priv *bat_priv, |
1211 | struct batadv_orig_node *orig_node, | 1598 | struct batadv_orig_node *orig_node, |
1599 | int32_t match_vid, | ||
1212 | const char *message) | 1600 | const char *message) |
1213 | { | 1601 | { |
1214 | struct batadv_tt_global_entry *tt_global; | 1602 | struct batadv_tt_global_entry *tt_global; |
@@ -1218,6 +1606,7 @@ void batadv_tt_global_del_orig(struct batadv_priv *bat_priv, | |||
1218 | struct hlist_node *safe; | 1606 | struct hlist_node *safe; |
1219 | struct hlist_head *head; | 1607 | struct hlist_head *head; |
1220 | spinlock_t *list_lock; /* protects write access to the hash lists */ | 1608 | spinlock_t *list_lock; /* protects write access to the hash lists */ |
1609 | unsigned short vid; | ||
1221 | 1610 | ||
1222 | if (!hash) | 1611 | if (!hash) |
1223 | return; | 1612 | return; |
@@ -1229,6 +1618,10 @@ void batadv_tt_global_del_orig(struct batadv_priv *bat_priv, | |||
1229 | spin_lock_bh(list_lock); | 1618 | spin_lock_bh(list_lock); |
1230 | hlist_for_each_entry_safe(tt_common_entry, safe, | 1619 | hlist_for_each_entry_safe(tt_common_entry, safe, |
1231 | head, hash_entry) { | 1620 | head, hash_entry) { |
1621 | /* remove only matching entries */ | ||
1622 | if (match_vid >= 0 && tt_common_entry->vid != match_vid) | ||
1623 | continue; | ||
1624 | |||
1232 | tt_global = container_of(tt_common_entry, | 1625 | tt_global = container_of(tt_common_entry, |
1233 | struct batadv_tt_global_entry, | 1626 | struct batadv_tt_global_entry, |
1234 | common); | 1627 | common); |
@@ -1237,9 +1630,11 @@ void batadv_tt_global_del_orig(struct batadv_priv *bat_priv, | |||
1237 | orig_node, message); | 1630 | orig_node, message); |
1238 | 1631 | ||
1239 | if (hlist_empty(&tt_global->orig_list)) { | 1632 | if (hlist_empty(&tt_global->orig_list)) { |
1633 | vid = tt_global->common.vid; | ||
1240 | batadv_dbg(BATADV_DBG_TT, bat_priv, | 1634 | batadv_dbg(BATADV_DBG_TT, bat_priv, |
1241 | "Deleting global tt entry %pM: %s\n", | 1635 | "Deleting global tt entry %pM (vid: %d): %s\n", |
1242 | tt_global->common.addr, message); | 1636 | tt_global->common.addr, |
1637 | BATADV_PRINT_VID(vid), message); | ||
1243 | hlist_del_rcu(&tt_common_entry->hash_entry); | 1638 | hlist_del_rcu(&tt_common_entry->hash_entry); |
1244 | batadv_tt_global_entry_free_ref(tt_global); | 1639 | batadv_tt_global_entry_free_ref(tt_global); |
1245 | } | 1640 | } |
@@ -1297,8 +1692,10 @@ static void batadv_tt_global_purge(struct batadv_priv *bat_priv) | |||
1297 | continue; | 1692 | continue; |
1298 | 1693 | ||
1299 | batadv_dbg(BATADV_DBG_TT, bat_priv, | 1694 | batadv_dbg(BATADV_DBG_TT, bat_priv, |
1300 | "Deleting global tt entry (%pM): %s\n", | 1695 | "Deleting global tt entry %pM (vid: %d): %s\n", |
1301 | tt_global->common.addr, msg); | 1696 | tt_global->common.addr, |
1697 | BATADV_PRINT_VID(tt_global->common.vid), | ||
1698 | msg); | ||
1302 | 1699 | ||
1303 | hlist_del_rcu(&tt_common->hash_entry); | 1700 | hlist_del_rcu(&tt_common->hash_entry); |
1304 | 1701 | ||
@@ -1357,23 +1754,49 @@ _batadv_is_ap_isolated(struct batadv_tt_local_entry *tt_local_entry, | |||
1357 | return ret; | 1754 | return ret; |
1358 | } | 1755 | } |
1359 | 1756 | ||
1757 | /** | ||
1758 | * batadv_transtable_search - get the mesh destination for a given client | ||
1759 | * @bat_priv: the bat priv with all the soft interface information | ||
1760 | * @src: mac address of the source client | ||
1761 | * @addr: mac address of the destination client | ||
1762 | * @vid: VLAN identifier | ||
1763 | * | ||
1764 | * Returns a pointer to the originator that was selected as destination in the | ||
1765 | * mesh for contacting the client 'addr', NULL otherwise. | ||
1766 | * In case of multiple originators serving the same client, the function returns | ||
1767 | * the best one (best in terms of metric towards the destination node). | ||
1768 | * | ||
1769 | * If the two clients are AP isolated the function returns NULL. | ||
1770 | */ | ||
1360 | struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv, | 1771 | struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv, |
1361 | const uint8_t *src, | 1772 | const uint8_t *src, |
1362 | const uint8_t *addr) | 1773 | const uint8_t *addr, |
1774 | unsigned short vid) | ||
1363 | { | 1775 | { |
1364 | struct batadv_tt_local_entry *tt_local_entry = NULL; | 1776 | struct batadv_tt_local_entry *tt_local_entry = NULL; |
1365 | struct batadv_tt_global_entry *tt_global_entry = NULL; | 1777 | struct batadv_tt_global_entry *tt_global_entry = NULL; |
1366 | struct batadv_orig_node *orig_node = NULL; | 1778 | struct batadv_orig_node *orig_node = NULL; |
1367 | struct batadv_tt_orig_list_entry *best_entry; | 1779 | struct batadv_tt_orig_list_entry *best_entry; |
1780 | bool ap_isolation_enabled = false; | ||
1781 | struct batadv_softif_vlan *vlan; | ||
1368 | 1782 | ||
1369 | if (src && atomic_read(&bat_priv->ap_isolation)) { | 1783 | /* if the AP isolation is requested on a VLAN, then check for its |
1370 | tt_local_entry = batadv_tt_local_hash_find(bat_priv, src); | 1784 | * setting in the proper VLAN private data structure |
1785 | */ | ||
1786 | vlan = batadv_softif_vlan_get(bat_priv, vid); | ||
1787 | if (vlan) { | ||
1788 | ap_isolation_enabled = atomic_read(&vlan->ap_isolation); | ||
1789 | batadv_softif_vlan_free_ref(vlan); | ||
1790 | } | ||
1791 | |||
1792 | if (src && ap_isolation_enabled) { | ||
1793 | tt_local_entry = batadv_tt_local_hash_find(bat_priv, src, vid); | ||
1371 | if (!tt_local_entry || | 1794 | if (!tt_local_entry || |
1372 | (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING)) | 1795 | (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING)) |
1373 | goto out; | 1796 | goto out; |
1374 | } | 1797 | } |
1375 | 1798 | ||
1376 | tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr); | 1799 | tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid); |
1377 | if (!tt_global_entry) | 1800 | if (!tt_global_entry) |
1378 | goto out; | 1801 | goto out; |
1379 | 1802 | ||
@@ -1402,17 +1825,39 @@ out: | |||
1402 | return orig_node; | 1825 | return orig_node; |
1403 | } | 1826 | } |
1404 | 1827 | ||
1405 | /* Calculates the checksum of the local table of a given orig_node */ | 1828 | /** |
1406 | static uint16_t batadv_tt_global_crc(struct batadv_priv *bat_priv, | 1829 | * batadv_tt_global_crc - calculates the checksum of the local table belonging |
1407 | struct batadv_orig_node *orig_node) | 1830 | * to the given orig_node |
1831 | * @bat_priv: the bat priv with all the soft interface information | ||
1832 | * @orig_node: originator for which the CRC should be computed | ||
1833 | * @vid: VLAN identifier for which the CRC32 has to be computed | ||
1834 | * | ||
1835 | * This function computes the checksum for the global table corresponding to a | ||
1836 | * specific originator. In particular, the checksum is computed as follows: For | ||
1837 | * each client connected to the originator the CRC32C of the MAC address and the | ||
1838 | * VID is computed and then all the CRC32Cs of the various clients are xor'ed | ||
1839 | * together. | ||
1840 | * | ||
1841 | * The idea behind is that CRC32C should be used as much as possible in order to | ||
1842 | * produce a unique hash of the table, but since the order which is used to feed | ||
1843 | * the CRC32C function affects the result and since every node in the network | ||
1844 | * probably sorts the clients differently, the hash function cannot be directly | ||
1845 | * computed over the entire table. Hence the CRC32C is used only on | ||
1846 | * the single client entry, while all the results are then xor'ed together | ||
1847 | * because the XOR operation can combine them all while trying to reduce the | ||
1848 | * noise as much as possible. | ||
1849 | * | ||
1850 | * Returns the checksum of the global table of a given originator. | ||
1851 | */ | ||
1852 | static uint32_t batadv_tt_global_crc(struct batadv_priv *bat_priv, | ||
1853 | struct batadv_orig_node *orig_node, | ||
1854 | unsigned short vid) | ||
1408 | { | 1855 | { |
1409 | uint16_t total = 0, total_one; | ||
1410 | struct batadv_hashtable *hash = bat_priv->tt.global_hash; | 1856 | struct batadv_hashtable *hash = bat_priv->tt.global_hash; |
1411 | struct batadv_tt_common_entry *tt_common; | 1857 | struct batadv_tt_common_entry *tt_common; |
1412 | struct batadv_tt_global_entry *tt_global; | 1858 | struct batadv_tt_global_entry *tt_global; |
1413 | struct hlist_head *head; | 1859 | struct hlist_head *head; |
1414 | uint32_t i; | 1860 | uint32_t i, crc_tmp, crc = 0; |
1415 | int j; | ||
1416 | 1861 | ||
1417 | for (i = 0; i < hash->size; i++) { | 1862 | for (i = 0; i < hash->size; i++) { |
1418 | head = &hash->table[i]; | 1863 | head = &hash->table[i]; |
@@ -1422,6 +1867,12 @@ static uint16_t batadv_tt_global_crc(struct batadv_priv *bat_priv, | |||
1422 | tt_global = container_of(tt_common, | 1867 | tt_global = container_of(tt_common, |
1423 | struct batadv_tt_global_entry, | 1868 | struct batadv_tt_global_entry, |
1424 | common); | 1869 | common); |
1870 | /* compute the CRC only for entries belonging to the | ||
1871 | * VLAN identified by the vid passed as parameter | ||
1872 | */ | ||
1873 | if (tt_common->vid != vid) | ||
1874 | continue; | ||
1875 | |||
1425 | /* Roaming clients are in the global table for | 1876 | /* Roaming clients are in the global table for |
1426 | * consistency only. They don't have to be | 1877 | * consistency only. They don't have to be |
1427 | * taken into account while computing the | 1878 | * taken into account while computing the |
@@ -1443,48 +1894,59 @@ static uint16_t batadv_tt_global_crc(struct batadv_priv *bat_priv, | |||
1443 | orig_node)) | 1894 | orig_node)) |
1444 | continue; | 1895 | continue; |
1445 | 1896 | ||
1446 | total_one = 0; | 1897 | crc_tmp = crc32c(0, &tt_common->vid, |
1447 | for (j = 0; j < ETH_ALEN; j++) | 1898 | sizeof(tt_common->vid)); |
1448 | total_one = crc16_byte(total_one, | 1899 | crc ^= crc32c(crc_tmp, tt_common->addr, ETH_ALEN); |
1449 | tt_common->addr[j]); | ||
1450 | total ^= total_one; | ||
1451 | } | 1900 | } |
1452 | rcu_read_unlock(); | 1901 | rcu_read_unlock(); |
1453 | } | 1902 | } |
1454 | 1903 | ||
1455 | return total; | 1904 | return crc; |
1456 | } | 1905 | } |
1457 | 1906 | ||
1458 | /* Calculates the checksum of the local table */ | 1907 | /** |
1459 | static uint16_t batadv_tt_local_crc(struct batadv_priv *bat_priv) | 1908 | * batadv_tt_local_crc - calculates the checksum of the local table |
1909 | * @bat_priv: the bat priv with all the soft interface information | ||
1910 | * @vid: VLAN identifier for which the CRC32 has to be computed | ||
1911 | * | ||
1912 | * For details about the computation, please refer to the documentation for | ||
1913 | * batadv_tt_global_crc(). | ||
1914 | * | ||
1915 | * Returns the checksum of the local table | ||
1916 | */ | ||
1917 | static uint32_t batadv_tt_local_crc(struct batadv_priv *bat_priv, | ||
1918 | unsigned short vid) | ||
1460 | { | 1919 | { |
1461 | uint16_t total = 0, total_one; | ||
1462 | struct batadv_hashtable *hash = bat_priv->tt.local_hash; | 1920 | struct batadv_hashtable *hash = bat_priv->tt.local_hash; |
1463 | struct batadv_tt_common_entry *tt_common; | 1921 | struct batadv_tt_common_entry *tt_common; |
1464 | struct hlist_head *head; | 1922 | struct hlist_head *head; |
1465 | uint32_t i; | 1923 | uint32_t i, crc_tmp, crc = 0; |
1466 | int j; | ||
1467 | 1924 | ||
1468 | for (i = 0; i < hash->size; i++) { | 1925 | for (i = 0; i < hash->size; i++) { |
1469 | head = &hash->table[i]; | 1926 | head = &hash->table[i]; |
1470 | 1927 | ||
1471 | rcu_read_lock(); | 1928 | rcu_read_lock(); |
1472 | hlist_for_each_entry_rcu(tt_common, head, hash_entry) { | 1929 | hlist_for_each_entry_rcu(tt_common, head, hash_entry) { |
1930 | /* compute the CRC only for entries belonging to the | ||
1931 | * VLAN identified by vid | ||
1932 | */ | ||
1933 | if (tt_common->vid != vid) | ||
1934 | continue; | ||
1935 | |||
1473 | /* not yet committed clients have not to be taken into | 1936 | /* not yet committed clients have not to be taken into |
1474 | * account while computing the CRC | 1937 | * account while computing the CRC |
1475 | */ | 1938 | */ |
1476 | if (tt_common->flags & BATADV_TT_CLIENT_NEW) | 1939 | if (tt_common->flags & BATADV_TT_CLIENT_NEW) |
1477 | continue; | 1940 | continue; |
1478 | total_one = 0; | 1941 | |
1479 | for (j = 0; j < ETH_ALEN; j++) | 1942 | crc_tmp = crc32c(0, &tt_common->vid, |
1480 | total_one = crc16_byte(total_one, | 1943 | sizeof(tt_common->vid)); |
1481 | tt_common->addr[j]); | 1944 | crc ^= crc32c(crc_tmp, tt_common->addr, ETH_ALEN); |
1482 | total ^= total_one; | ||
1483 | } | 1945 | } |
1484 | rcu_read_unlock(); | 1946 | rcu_read_unlock(); |
1485 | } | 1947 | } |
1486 | 1948 | ||
1487 | return total; | 1949 | return crc; |
1488 | } | 1950 | } |
1489 | 1951 | ||
1490 | static void batadv_tt_req_list_free(struct batadv_priv *bat_priv) | 1952 | static void batadv_tt_req_list_free(struct batadv_priv *bat_priv) |
@@ -1503,11 +1965,9 @@ static void batadv_tt_req_list_free(struct batadv_priv *bat_priv) | |||
1503 | 1965 | ||
1504 | static void batadv_tt_save_orig_buffer(struct batadv_priv *bat_priv, | 1966 | static void batadv_tt_save_orig_buffer(struct batadv_priv *bat_priv, |
1505 | struct batadv_orig_node *orig_node, | 1967 | struct batadv_orig_node *orig_node, |
1506 | const unsigned char *tt_buff, | 1968 | const void *tt_buff, |
1507 | uint8_t tt_num_changes) | 1969 | uint16_t tt_buff_len) |
1508 | { | 1970 | { |
1509 | uint16_t tt_buff_len = batadv_tt_len(tt_num_changes); | ||
1510 | |||
1511 | /* Replace the old buffer only if I received something in the | 1971 | /* Replace the old buffer only if I received something in the |
1512 | * last OGM (the OGM could carry no changes) | 1972 | * last OGM (the OGM could carry no changes) |
1513 | */ | 1973 | */ |
@@ -1569,9 +2029,14 @@ unlock: | |||
1569 | return tt_req_node; | 2029 | return tt_req_node; |
1570 | } | 2030 | } |
1571 | 2031 | ||
1572 | /* data_ptr is useless here, but has to be kept to respect the prototype */ | 2032 | /** |
1573 | static int batadv_tt_local_valid_entry(const void *entry_ptr, | 2033 | * batadv_tt_local_valid - verify that given tt entry is a valid one |
1574 | const void *data_ptr) | 2034 | * @entry_ptr: to be checked local tt entry |
2035 | * @data_ptr: not used but definition required to satisfy the callback prototype | ||
2036 | * | ||
2037 | * Returns 1 if the entry is a valid, 0 otherwise. | ||
2038 | */ | ||
2039 | static int batadv_tt_local_valid(const void *entry_ptr, const void *data_ptr) | ||
1575 | { | 2040 | { |
1576 | const struct batadv_tt_common_entry *tt_common_entry = entry_ptr; | 2041 | const struct batadv_tt_common_entry *tt_common_entry = entry_ptr; |
1577 | 2042 | ||
@@ -1598,41 +2063,30 @@ static int batadv_tt_global_valid(const void *entry_ptr, | |||
1598 | return batadv_tt_global_entry_has_orig(tt_global_entry, orig_node); | 2063 | return batadv_tt_global_entry_has_orig(tt_global_entry, orig_node); |
1599 | } | 2064 | } |
1600 | 2065 | ||
1601 | static struct sk_buff * | 2066 | /** |
1602 | batadv_tt_response_fill_table(uint16_t tt_len, uint8_t ttvn, | 2067 | * batadv_tt_tvlv_generate - fill the tvlv buff with the tt entries from the |
1603 | struct batadv_hashtable *hash, | 2068 | * specified tt hash |
1604 | struct batadv_priv *bat_priv, | 2069 | * @bat_priv: the bat priv with all the soft interface information |
1605 | int (*valid_cb)(const void *, const void *), | 2070 | * @hash: hash table containing the tt entries |
1606 | void *cb_data) | 2071 | * @tt_len: expected tvlv tt data buffer length in number of bytes |
2072 | * @tvlv_buff: pointer to the buffer to fill with the TT data | ||
2073 | * @valid_cb: function to filter tt change entries | ||
2074 | * @cb_data: data passed to the filter function as argument | ||
2075 | */ | ||
2076 | static void batadv_tt_tvlv_generate(struct batadv_priv *bat_priv, | ||
2077 | struct batadv_hashtable *hash, | ||
2078 | void *tvlv_buff, uint16_t tt_len, | ||
2079 | int (*valid_cb)(const void *, const void *), | ||
2080 | void *cb_data) | ||
1607 | { | 2081 | { |
1608 | struct batadv_tt_common_entry *tt_common_entry; | 2082 | struct batadv_tt_common_entry *tt_common_entry; |
1609 | struct batadv_tt_query_packet *tt_response; | 2083 | struct batadv_tvlv_tt_change *tt_change; |
1610 | struct batadv_tt_change *tt_change; | ||
1611 | struct hlist_head *head; | 2084 | struct hlist_head *head; |
1612 | struct sk_buff *skb = NULL; | 2085 | uint16_t tt_tot, tt_num_entries = 0; |
1613 | uint16_t tt_tot, tt_count; | ||
1614 | ssize_t tt_query_size = sizeof(struct batadv_tt_query_packet); | ||
1615 | uint32_t i; | 2086 | uint32_t i; |
1616 | size_t len; | ||
1617 | |||
1618 | if (tt_query_size + tt_len > bat_priv->soft_iface->mtu) { | ||
1619 | tt_len = bat_priv->soft_iface->mtu - tt_query_size; | ||
1620 | tt_len -= tt_len % sizeof(struct batadv_tt_change); | ||
1621 | } | ||
1622 | tt_tot = tt_len / sizeof(struct batadv_tt_change); | ||
1623 | |||
1624 | len = tt_query_size + tt_len; | ||
1625 | skb = netdev_alloc_skb_ip_align(NULL, len + ETH_HLEN); | ||
1626 | if (!skb) | ||
1627 | goto out; | ||
1628 | 2087 | ||
1629 | skb->priority = TC_PRIO_CONTROL; | 2088 | tt_tot = batadv_tt_entries(tt_len); |
1630 | skb_reserve(skb, ETH_HLEN); | 2089 | tt_change = (struct batadv_tvlv_tt_change *)tvlv_buff; |
1631 | tt_response = (struct batadv_tt_query_packet *)skb_put(skb, len); | ||
1632 | tt_response->ttvn = ttvn; | ||
1633 | |||
1634 | tt_change = (struct batadv_tt_change *)(skb->data + tt_query_size); | ||
1635 | tt_count = 0; | ||
1636 | 2090 | ||
1637 | rcu_read_lock(); | 2091 | rcu_read_lock(); |
1638 | for (i = 0; i < hash->size; i++) { | 2092 | for (i = 0; i < hash->size; i++) { |
@@ -1640,7 +2094,7 @@ batadv_tt_response_fill_table(uint16_t tt_len, uint8_t ttvn, | |||
1640 | 2094 | ||
1641 | hlist_for_each_entry_rcu(tt_common_entry, | 2095 | hlist_for_each_entry_rcu(tt_common_entry, |
1642 | head, hash_entry) { | 2096 | head, hash_entry) { |
1643 | if (tt_count == tt_tot) | 2097 | if (tt_tot == tt_num_entries) |
1644 | break; | 2098 | break; |
1645 | 2099 | ||
1646 | if ((valid_cb) && (!valid_cb(tt_common_entry, cb_data))) | 2100 | if ((valid_cb) && (!valid_cb(tt_common_entry, cb_data))) |
@@ -1649,33 +2103,123 @@ batadv_tt_response_fill_table(uint16_t tt_len, uint8_t ttvn, | |||
1649 | memcpy(tt_change->addr, tt_common_entry->addr, | 2103 | memcpy(tt_change->addr, tt_common_entry->addr, |
1650 | ETH_ALEN); | 2104 | ETH_ALEN); |
1651 | tt_change->flags = tt_common_entry->flags; | 2105 | tt_change->flags = tt_common_entry->flags; |
2106 | tt_change->vid = htons(tt_common_entry->vid); | ||
2107 | tt_change->reserved = 0; | ||
1652 | 2108 | ||
1653 | tt_count++; | 2109 | tt_num_entries++; |
1654 | tt_change++; | 2110 | tt_change++; |
1655 | } | 2111 | } |
1656 | } | 2112 | } |
1657 | rcu_read_unlock(); | 2113 | rcu_read_unlock(); |
2114 | } | ||
1658 | 2115 | ||
1659 | /* store in the message the number of entries we have successfully | 2116 | /** |
1660 | * copied | 2117 | * batadv_tt_global_check_crc - check if all the CRCs are correct |
1661 | */ | 2118 | * @orig_node: originator for which the CRCs have to be checked |
1662 | tt_response->tt_data = htons(tt_count); | 2119 | * @tt_vlan: pointer to the first tvlv VLAN entry |
2120 | * @num_vlan: number of tvlv VLAN entries | ||
2121 | * @create: if true, create VLAN objects if not found | ||
2122 | * | ||
2123 | * Return true if all the received CRCs match the locally stored ones, false | ||
2124 | * otherwise | ||
2125 | */ | ||
2126 | static bool batadv_tt_global_check_crc(struct batadv_orig_node *orig_node, | ||
2127 | struct batadv_tvlv_tt_vlan_data *tt_vlan, | ||
2128 | uint16_t num_vlan) | ||
2129 | { | ||
2130 | struct batadv_tvlv_tt_vlan_data *tt_vlan_tmp; | ||
2131 | struct batadv_orig_node_vlan *vlan; | ||
2132 | int i; | ||
1663 | 2133 | ||
1664 | out: | 2134 | /* check if each received CRC matches the locally stored one */ |
1665 | return skb; | 2135 | for (i = 0; i < num_vlan; i++) { |
2136 | tt_vlan_tmp = tt_vlan + i; | ||
2137 | |||
2138 | /* if orig_node is a backbone node for this VLAN, don't check | ||
2139 | * the CRC as we ignore all the global entries over it | ||
2140 | */ | ||
2141 | if (batadv_bla_is_backbone_gw_orig(orig_node->bat_priv, | ||
2142 | orig_node->orig, | ||
2143 | ntohs(tt_vlan_tmp->vid))) | ||
2144 | continue; | ||
2145 | |||
2146 | vlan = batadv_orig_node_vlan_get(orig_node, | ||
2147 | ntohs(tt_vlan_tmp->vid)); | ||
2148 | if (!vlan) | ||
2149 | return false; | ||
2150 | |||
2151 | if (vlan->tt.crc != ntohl(tt_vlan_tmp->crc)) | ||
2152 | return false; | ||
2153 | } | ||
2154 | |||
2155 | return true; | ||
1666 | } | 2156 | } |
1667 | 2157 | ||
2158 | /** | ||
2159 | * batadv_tt_local_update_crc - update all the local CRCs | ||
2160 | * @bat_priv: the bat priv with all the soft interface information | ||
2161 | */ | ||
2162 | static void batadv_tt_local_update_crc(struct batadv_priv *bat_priv) | ||
2163 | { | ||
2164 | struct batadv_softif_vlan *vlan; | ||
2165 | |||
2166 | /* recompute the global CRC for each VLAN */ | ||
2167 | rcu_read_lock(); | ||
2168 | hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) { | ||
2169 | vlan->tt.crc = batadv_tt_local_crc(bat_priv, vlan->vid); | ||
2170 | } | ||
2171 | rcu_read_unlock(); | ||
2172 | } | ||
2173 | |||
2174 | /** | ||
2175 | * batadv_tt_global_update_crc - update all the global CRCs for this orig_node | ||
2176 | * @bat_priv: the bat priv with all the soft interface information | ||
2177 | * @orig_node: the orig_node for which the CRCs have to be updated | ||
2178 | */ | ||
2179 | static void batadv_tt_global_update_crc(struct batadv_priv *bat_priv, | ||
2180 | struct batadv_orig_node *orig_node) | ||
2181 | { | ||
2182 | struct batadv_orig_node_vlan *vlan; | ||
2183 | uint32_t crc; | ||
2184 | |||
2185 | /* recompute the global CRC for each VLAN */ | ||
2186 | rcu_read_lock(); | ||
2187 | list_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) { | ||
2188 | /* if orig_node is a backbone node for this VLAN, don't compute | ||
2189 | * the CRC as we ignore all the global entries over it | ||
2190 | */ | ||
2191 | if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig, | ||
2192 | vlan->vid)) | ||
2193 | continue; | ||
2194 | |||
2195 | crc = batadv_tt_global_crc(bat_priv, orig_node, vlan->vid); | ||
2196 | vlan->tt.crc = crc; | ||
2197 | } | ||
2198 | rcu_read_unlock(); | ||
2199 | } | ||
2200 | |||
2201 | /** | ||
2202 | * batadv_send_tt_request - send a TT Request message to a given node | ||
2203 | * @bat_priv: the bat priv with all the soft interface information | ||
2204 | * @dst_orig_node: the destination of the message | ||
2205 | * @ttvn: the version number that the source of the message is looking for | ||
2206 | * @tt_vlan: pointer to the first tvlv VLAN object to request | ||
2207 | * @num_vlan: number of tvlv VLAN entries | ||
2208 | * @full_table: ask for the entire translation table if true, while only for the | ||
2209 | * last TT diff otherwise | ||
2210 | */ | ||
1668 | static int batadv_send_tt_request(struct batadv_priv *bat_priv, | 2211 | static int batadv_send_tt_request(struct batadv_priv *bat_priv, |
1669 | struct batadv_orig_node *dst_orig_node, | 2212 | struct batadv_orig_node *dst_orig_node, |
1670 | uint8_t ttvn, uint16_t tt_crc, | 2213 | uint8_t ttvn, |
1671 | bool full_table) | 2214 | struct batadv_tvlv_tt_vlan_data *tt_vlan, |
2215 | uint16_t num_vlan, bool full_table) | ||
1672 | { | 2216 | { |
1673 | struct sk_buff *skb = NULL; | 2217 | struct batadv_tvlv_tt_data *tvlv_tt_data = NULL; |
1674 | struct batadv_tt_query_packet *tt_request; | ||
1675 | struct batadv_hard_iface *primary_if; | ||
1676 | struct batadv_tt_req_node *tt_req_node = NULL; | 2218 | struct batadv_tt_req_node *tt_req_node = NULL; |
1677 | int ret = 1; | 2219 | struct batadv_tvlv_tt_vlan_data *tt_vlan_req; |
1678 | size_t tt_req_len; | 2220 | struct batadv_hard_iface *primary_if; |
2221 | bool ret = false; | ||
2222 | int i, size; | ||
1679 | 2223 | ||
1680 | primary_if = batadv_primary_if_get_selected(bat_priv); | 2224 | primary_if = batadv_primary_if_get_selected(bat_priv); |
1681 | if (!primary_if) | 2225 | if (!primary_if) |
@@ -1688,157 +2232,162 @@ static int batadv_send_tt_request(struct batadv_priv *bat_priv, | |||
1688 | if (!tt_req_node) | 2232 | if (!tt_req_node) |
1689 | goto out; | 2233 | goto out; |
1690 | 2234 | ||
1691 | skb = netdev_alloc_skb_ip_align(NULL, sizeof(*tt_request) + ETH_HLEN); | 2235 | size = sizeof(*tvlv_tt_data) + sizeof(*tt_vlan_req) * num_vlan; |
1692 | if (!skb) | 2236 | tvlv_tt_data = kzalloc(size, GFP_ATOMIC); |
2237 | if (!tvlv_tt_data) | ||
1693 | goto out; | 2238 | goto out; |
1694 | 2239 | ||
1695 | skb->priority = TC_PRIO_CONTROL; | 2240 | tvlv_tt_data->flags = BATADV_TT_REQUEST; |
1696 | skb_reserve(skb, ETH_HLEN); | 2241 | tvlv_tt_data->ttvn = ttvn; |
2242 | tvlv_tt_data->num_vlan = htons(num_vlan); | ||
1697 | 2243 | ||
1698 | tt_req_len = sizeof(*tt_request); | 2244 | /* send all the CRCs within the request. This is needed by intermediate |
1699 | tt_request = (struct batadv_tt_query_packet *)skb_put(skb, tt_req_len); | 2245 | * nodes to ensure they have the correct table before replying |
2246 | */ | ||
2247 | tt_vlan_req = (struct batadv_tvlv_tt_vlan_data *)(tvlv_tt_data + 1); | ||
2248 | for (i = 0; i < num_vlan; i++) { | ||
2249 | tt_vlan_req->vid = tt_vlan->vid; | ||
2250 | tt_vlan_req->crc = tt_vlan->crc; | ||
1700 | 2251 | ||
1701 | tt_request->header.packet_type = BATADV_TT_QUERY; | 2252 | tt_vlan_req++; |
1702 | tt_request->header.version = BATADV_COMPAT_VERSION; | 2253 | tt_vlan++; |
1703 | memcpy(tt_request->src, primary_if->net_dev->dev_addr, ETH_ALEN); | 2254 | } |
1704 | memcpy(tt_request->dst, dst_orig_node->orig, ETH_ALEN); | ||
1705 | tt_request->header.ttl = BATADV_TTL; | ||
1706 | tt_request->ttvn = ttvn; | ||
1707 | tt_request->tt_data = htons(tt_crc); | ||
1708 | tt_request->flags = BATADV_TT_REQUEST; | ||
1709 | 2255 | ||
1710 | if (full_table) | 2256 | if (full_table) |
1711 | tt_request->flags |= BATADV_TT_FULL_TABLE; | 2257 | tvlv_tt_data->flags |= BATADV_TT_FULL_TABLE; |
1712 | 2258 | ||
1713 | batadv_dbg(BATADV_DBG_TT, bat_priv, "Sending TT_REQUEST to %pM [%c]\n", | 2259 | batadv_dbg(BATADV_DBG_TT, bat_priv, "Sending TT_REQUEST to %pM [%c]\n", |
1714 | dst_orig_node->orig, (full_table ? 'F' : '.')); | 2260 | dst_orig_node->orig, full_table ? 'F' : '.'); |
1715 | 2261 | ||
1716 | batadv_inc_counter(bat_priv, BATADV_CNT_TT_REQUEST_TX); | 2262 | batadv_inc_counter(bat_priv, BATADV_CNT_TT_REQUEST_TX); |
1717 | 2263 | batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr, | |
1718 | if (batadv_send_skb_to_orig(skb, dst_orig_node, NULL) != NET_XMIT_DROP) | 2264 | dst_orig_node->orig, BATADV_TVLV_TT, 1, |
1719 | ret = 0; | 2265 | tvlv_tt_data, size); |
2266 | ret = true; | ||
1720 | 2267 | ||
1721 | out: | 2268 | out: |
1722 | if (primary_if) | 2269 | if (primary_if) |
1723 | batadv_hardif_free_ref(primary_if); | 2270 | batadv_hardif_free_ref(primary_if); |
1724 | if (ret) | ||
1725 | kfree_skb(skb); | ||
1726 | if (ret && tt_req_node) { | 2271 | if (ret && tt_req_node) { |
1727 | spin_lock_bh(&bat_priv->tt.req_list_lock); | 2272 | spin_lock_bh(&bat_priv->tt.req_list_lock); |
1728 | list_del(&tt_req_node->list); | 2273 | list_del(&tt_req_node->list); |
1729 | spin_unlock_bh(&bat_priv->tt.req_list_lock); | 2274 | spin_unlock_bh(&bat_priv->tt.req_list_lock); |
1730 | kfree(tt_req_node); | 2275 | kfree(tt_req_node); |
1731 | } | 2276 | } |
2277 | kfree(tvlv_tt_data); | ||
1732 | return ret; | 2278 | return ret; |
1733 | } | 2279 | } |
1734 | 2280 | ||
1735 | static bool | 2281 | /** |
1736 | batadv_send_other_tt_response(struct batadv_priv *bat_priv, | 2282 | * batadv_send_other_tt_response - send reply to tt request concerning another |
1737 | struct batadv_tt_query_packet *tt_request) | 2283 | * node's translation table |
2284 | * @bat_priv: the bat priv with all the soft interface information | ||
2285 | * @tt_data: tt data containing the tt request information | ||
2286 | * @req_src: mac address of tt request sender | ||
2287 | * @req_dst: mac address of tt request recipient | ||
2288 | * | ||
2289 | * Returns true if tt request reply was sent, false otherwise. | ||
2290 | */ | ||
2291 | static bool batadv_send_other_tt_response(struct batadv_priv *bat_priv, | ||
2292 | struct batadv_tvlv_tt_data *tt_data, | ||
2293 | uint8_t *req_src, uint8_t *req_dst) | ||
1738 | { | 2294 | { |
1739 | struct batadv_orig_node *req_dst_orig_node; | 2295 | struct batadv_orig_node *req_dst_orig_node; |
1740 | struct batadv_orig_node *res_dst_orig_node = NULL; | 2296 | struct batadv_orig_node *res_dst_orig_node = NULL; |
1741 | uint8_t orig_ttvn, req_ttvn, ttvn; | 2297 | struct batadv_tvlv_tt_change *tt_change; |
1742 | int res, ret = false; | 2298 | struct batadv_tvlv_tt_data *tvlv_tt_data = NULL; |
1743 | unsigned char *tt_buff; | 2299 | struct batadv_tvlv_tt_vlan_data *tt_vlan; |
1744 | bool full_table; | 2300 | bool ret = false, full_table; |
1745 | uint16_t tt_len, tt_tot; | 2301 | uint8_t orig_ttvn, req_ttvn; |
1746 | struct sk_buff *skb = NULL; | 2302 | uint16_t tvlv_len; |
1747 | struct batadv_tt_query_packet *tt_response; | 2303 | int32_t tt_len; |
1748 | uint8_t *packet_pos; | ||
1749 | size_t len; | ||
1750 | 2304 | ||
1751 | batadv_dbg(BATADV_DBG_TT, bat_priv, | 2305 | batadv_dbg(BATADV_DBG_TT, bat_priv, |
1752 | "Received TT_REQUEST from %pM for ttvn: %u (%pM) [%c]\n", | 2306 | "Received TT_REQUEST from %pM for ttvn: %u (%pM) [%c]\n", |
1753 | tt_request->src, tt_request->ttvn, tt_request->dst, | 2307 | req_src, tt_data->ttvn, req_dst, |
1754 | (tt_request->flags & BATADV_TT_FULL_TABLE ? 'F' : '.')); | 2308 | (tt_data->flags & BATADV_TT_FULL_TABLE ? 'F' : '.')); |
1755 | 2309 | ||
1756 | /* Let's get the orig node of the REAL destination */ | 2310 | /* Let's get the orig node of the REAL destination */ |
1757 | req_dst_orig_node = batadv_orig_hash_find(bat_priv, tt_request->dst); | 2311 | req_dst_orig_node = batadv_orig_hash_find(bat_priv, req_dst); |
1758 | if (!req_dst_orig_node) | 2312 | if (!req_dst_orig_node) |
1759 | goto out; | 2313 | goto out; |
1760 | 2314 | ||
1761 | res_dst_orig_node = batadv_orig_hash_find(bat_priv, tt_request->src); | 2315 | res_dst_orig_node = batadv_orig_hash_find(bat_priv, req_src); |
1762 | if (!res_dst_orig_node) | 2316 | if (!res_dst_orig_node) |
1763 | goto out; | 2317 | goto out; |
1764 | 2318 | ||
1765 | orig_ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn); | 2319 | orig_ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn); |
1766 | req_ttvn = tt_request->ttvn; | 2320 | req_ttvn = tt_data->ttvn; |
1767 | 2321 | ||
1768 | /* I don't have the requested data */ | 2322 | tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(tt_data + 1); |
2323 | /* this node doesn't have the requested data */ | ||
1769 | if (orig_ttvn != req_ttvn || | 2324 | if (orig_ttvn != req_ttvn || |
1770 | tt_request->tt_data != htons(req_dst_orig_node->tt_crc)) | 2325 | !batadv_tt_global_check_crc(req_dst_orig_node, tt_vlan, |
2326 | ntohs(tt_data->num_vlan))) | ||
1771 | goto out; | 2327 | goto out; |
1772 | 2328 | ||
1773 | /* If the full table has been explicitly requested */ | 2329 | /* If the full table has been explicitly requested */ |
1774 | if (tt_request->flags & BATADV_TT_FULL_TABLE || | 2330 | if (tt_data->flags & BATADV_TT_FULL_TABLE || |
1775 | !req_dst_orig_node->tt_buff) | 2331 | !req_dst_orig_node->tt_buff) |
1776 | full_table = true; | 2332 | full_table = true; |
1777 | else | 2333 | else |
1778 | full_table = false; | 2334 | full_table = false; |
1779 | 2335 | ||
1780 | /* In this version, fragmentation is not implemented, then | 2336 | /* TT fragmentation hasn't been implemented yet, so send as many |
1781 | * I'll send only one packet with as much TT entries as I can | 2337 | * TT entries fit a single packet as possible only |
1782 | */ | 2338 | */ |
1783 | if (!full_table) { | 2339 | if (!full_table) { |
1784 | spin_lock_bh(&req_dst_orig_node->tt_buff_lock); | 2340 | spin_lock_bh(&req_dst_orig_node->tt_buff_lock); |
1785 | tt_len = req_dst_orig_node->tt_buff_len; | 2341 | tt_len = req_dst_orig_node->tt_buff_len; |
1786 | tt_tot = tt_len / sizeof(struct batadv_tt_change); | ||
1787 | 2342 | ||
1788 | len = sizeof(*tt_response) + tt_len; | 2343 | tvlv_len = batadv_tt_prepare_tvlv_global_data(req_dst_orig_node, |
1789 | skb = netdev_alloc_skb_ip_align(NULL, len + ETH_HLEN); | 2344 | &tvlv_tt_data, |
1790 | if (!skb) | 2345 | &tt_change, |
2346 | &tt_len); | ||
2347 | if (!tt_len) | ||
1791 | goto unlock; | 2348 | goto unlock; |
1792 | 2349 | ||
1793 | skb->priority = TC_PRIO_CONTROL; | ||
1794 | skb_reserve(skb, ETH_HLEN); | ||
1795 | packet_pos = skb_put(skb, len); | ||
1796 | tt_response = (struct batadv_tt_query_packet *)packet_pos; | ||
1797 | tt_response->ttvn = req_ttvn; | ||
1798 | tt_response->tt_data = htons(tt_tot); | ||
1799 | |||
1800 | tt_buff = skb->data + sizeof(*tt_response); | ||
1801 | /* Copy the last orig_node's OGM buffer */ | 2350 | /* Copy the last orig_node's OGM buffer */ |
1802 | memcpy(tt_buff, req_dst_orig_node->tt_buff, | 2351 | memcpy(tt_change, req_dst_orig_node->tt_buff, |
1803 | req_dst_orig_node->tt_buff_len); | 2352 | req_dst_orig_node->tt_buff_len); |
1804 | |||
1805 | spin_unlock_bh(&req_dst_orig_node->tt_buff_lock); | 2353 | spin_unlock_bh(&req_dst_orig_node->tt_buff_lock); |
1806 | } else { | 2354 | } else { |
1807 | tt_len = (uint16_t)atomic_read(&req_dst_orig_node->tt_size); | 2355 | /* allocate the tvlv, put the tt_data and all the tt_vlan_data |
1808 | tt_len *= sizeof(struct batadv_tt_change); | 2356 | * in the initial part |
1809 | ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn); | 2357 | */ |
1810 | 2358 | tt_len = -1; | |
1811 | skb = batadv_tt_response_fill_table(tt_len, ttvn, | 2359 | tvlv_len = batadv_tt_prepare_tvlv_global_data(req_dst_orig_node, |
1812 | bat_priv->tt.global_hash, | 2360 | &tvlv_tt_data, |
1813 | bat_priv, | 2361 | &tt_change, |
1814 | batadv_tt_global_valid, | 2362 | &tt_len); |
1815 | req_dst_orig_node); | 2363 | if (!tt_len) |
1816 | if (!skb) | ||
1817 | goto out; | 2364 | goto out; |
1818 | 2365 | ||
1819 | tt_response = (struct batadv_tt_query_packet *)skb->data; | 2366 | /* fill the rest of the tvlv with the real TT entries */ |
2367 | batadv_tt_tvlv_generate(bat_priv, bat_priv->tt.global_hash, | ||
2368 | tt_change, tt_len, | ||
2369 | batadv_tt_global_valid, | ||
2370 | req_dst_orig_node); | ||
1820 | } | 2371 | } |
1821 | 2372 | ||
1822 | tt_response->header.packet_type = BATADV_TT_QUERY; | 2373 | tvlv_tt_data->flags = BATADV_TT_RESPONSE; |
1823 | tt_response->header.version = BATADV_COMPAT_VERSION; | 2374 | tvlv_tt_data->ttvn = req_ttvn; |
1824 | tt_response->header.ttl = BATADV_TTL; | ||
1825 | memcpy(tt_response->src, req_dst_orig_node->orig, ETH_ALEN); | ||
1826 | memcpy(tt_response->dst, tt_request->src, ETH_ALEN); | ||
1827 | tt_response->flags = BATADV_TT_RESPONSE; | ||
1828 | 2375 | ||
1829 | if (full_table) | 2376 | if (full_table) |
1830 | tt_response->flags |= BATADV_TT_FULL_TABLE; | 2377 | tvlv_tt_data->flags |= BATADV_TT_FULL_TABLE; |
1831 | 2378 | ||
1832 | batadv_dbg(BATADV_DBG_TT, bat_priv, | 2379 | batadv_dbg(BATADV_DBG_TT, bat_priv, |
1833 | "Sending TT_RESPONSE %pM for %pM (ttvn: %u)\n", | 2380 | "Sending TT_RESPONSE %pM for %pM [%c] (ttvn: %u)\n", |
1834 | res_dst_orig_node->orig, req_dst_orig_node->orig, req_ttvn); | 2381 | res_dst_orig_node->orig, req_dst_orig_node->orig, |
2382 | full_table ? 'F' : '.', req_ttvn); | ||
1835 | 2383 | ||
1836 | batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_TX); | 2384 | batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_TX); |
1837 | 2385 | ||
1838 | res = batadv_send_skb_to_orig(skb, res_dst_orig_node, NULL); | 2386 | batadv_tvlv_unicast_send(bat_priv, req_dst_orig_node->orig, |
1839 | if (res != NET_XMIT_DROP) | 2387 | req_src, BATADV_TVLV_TT, 1, tvlv_tt_data, |
1840 | ret = true; | 2388 | tvlv_len); |
1841 | 2389 | ||
2390 | ret = true; | ||
1842 | goto out; | 2391 | goto out; |
1843 | 2392 | ||
1844 | unlock: | 2393 | unlock: |
@@ -1849,37 +2398,43 @@ out: | |||
1849 | batadv_orig_node_free_ref(res_dst_orig_node); | 2398 | batadv_orig_node_free_ref(res_dst_orig_node); |
1850 | if (req_dst_orig_node) | 2399 | if (req_dst_orig_node) |
1851 | batadv_orig_node_free_ref(req_dst_orig_node); | 2400 | batadv_orig_node_free_ref(req_dst_orig_node); |
1852 | if (!ret) | 2401 | kfree(tvlv_tt_data); |
1853 | kfree_skb(skb); | ||
1854 | return ret; | 2402 | return ret; |
1855 | } | 2403 | } |
1856 | 2404 | ||
1857 | static bool | 2405 | /** |
1858 | batadv_send_my_tt_response(struct batadv_priv *bat_priv, | 2406 | * batadv_send_my_tt_response - send reply to tt request concerning this node's |
1859 | struct batadv_tt_query_packet *tt_request) | 2407 | * translation table |
2408 | * @bat_priv: the bat priv with all the soft interface information | ||
2409 | * @tt_data: tt data containing the tt request information | ||
2410 | * @req_src: mac address of tt request sender | ||
2411 | * | ||
2412 | * Returns true if tt request reply was sent, false otherwise. | ||
2413 | */ | ||
2414 | static bool batadv_send_my_tt_response(struct batadv_priv *bat_priv, | ||
2415 | struct batadv_tvlv_tt_data *tt_data, | ||
2416 | uint8_t *req_src) | ||
1860 | { | 2417 | { |
1861 | struct batadv_orig_node *orig_node; | 2418 | struct batadv_tvlv_tt_data *tvlv_tt_data = NULL; |
1862 | struct batadv_hard_iface *primary_if = NULL; | 2419 | struct batadv_hard_iface *primary_if = NULL; |
1863 | uint8_t my_ttvn, req_ttvn, ttvn; | 2420 | struct batadv_tvlv_tt_change *tt_change; |
1864 | int ret = false; | 2421 | struct batadv_orig_node *orig_node; |
1865 | unsigned char *tt_buff; | 2422 | uint8_t my_ttvn, req_ttvn; |
2423 | uint16_t tvlv_len; | ||
1866 | bool full_table; | 2424 | bool full_table; |
1867 | uint16_t tt_len, tt_tot; | 2425 | int32_t tt_len; |
1868 | struct sk_buff *skb = NULL; | ||
1869 | struct batadv_tt_query_packet *tt_response; | ||
1870 | uint8_t *packet_pos; | ||
1871 | size_t len; | ||
1872 | 2426 | ||
1873 | batadv_dbg(BATADV_DBG_TT, bat_priv, | 2427 | batadv_dbg(BATADV_DBG_TT, bat_priv, |
1874 | "Received TT_REQUEST from %pM for ttvn: %u (me) [%c]\n", | 2428 | "Received TT_REQUEST from %pM for ttvn: %u (me) [%c]\n", |
1875 | tt_request->src, tt_request->ttvn, | 2429 | req_src, tt_data->ttvn, |
1876 | (tt_request->flags & BATADV_TT_FULL_TABLE ? 'F' : '.')); | 2430 | (tt_data->flags & BATADV_TT_FULL_TABLE ? 'F' : '.')); |
1877 | 2431 | ||
2432 | spin_lock_bh(&bat_priv->tt.commit_lock); | ||
1878 | 2433 | ||
1879 | my_ttvn = (uint8_t)atomic_read(&bat_priv->tt.vn); | 2434 | my_ttvn = (uint8_t)atomic_read(&bat_priv->tt.vn); |
1880 | req_ttvn = tt_request->ttvn; | 2435 | req_ttvn = tt_data->ttvn; |
1881 | 2436 | ||
1882 | orig_node = batadv_orig_hash_find(bat_priv, tt_request->src); | 2437 | orig_node = batadv_orig_hash_find(bat_priv, req_src); |
1883 | if (!orig_node) | 2438 | if (!orig_node) |
1884 | goto out; | 2439 | goto out; |
1885 | 2440 | ||
@@ -1890,103 +2445,104 @@ batadv_send_my_tt_response(struct batadv_priv *bat_priv, | |||
1890 | /* If the full table has been explicitly requested or the gap | 2445 | /* If the full table has been explicitly requested or the gap |
1891 | * is too big send the whole local translation table | 2446 | * is too big send the whole local translation table |
1892 | */ | 2447 | */ |
1893 | if (tt_request->flags & BATADV_TT_FULL_TABLE || my_ttvn != req_ttvn || | 2448 | if (tt_data->flags & BATADV_TT_FULL_TABLE || my_ttvn != req_ttvn || |
1894 | !bat_priv->tt.last_changeset) | 2449 | !bat_priv->tt.last_changeset) |
1895 | full_table = true; | 2450 | full_table = true; |
1896 | else | 2451 | else |
1897 | full_table = false; | 2452 | full_table = false; |
1898 | 2453 | ||
1899 | /* In this version, fragmentation is not implemented, then | 2454 | /* TT fragmentation hasn't been implemented yet, so send as many |
1900 | * I'll send only one packet with as much TT entries as I can | 2455 | * TT entries fit a single packet as possible only |
1901 | */ | 2456 | */ |
1902 | if (!full_table) { | 2457 | if (!full_table) { |
1903 | spin_lock_bh(&bat_priv->tt.last_changeset_lock); | 2458 | spin_lock_bh(&bat_priv->tt.last_changeset_lock); |
1904 | tt_len = bat_priv->tt.last_changeset_len; | ||
1905 | tt_tot = tt_len / sizeof(struct batadv_tt_change); | ||
1906 | 2459 | ||
1907 | len = sizeof(*tt_response) + tt_len; | 2460 | tt_len = bat_priv->tt.last_changeset_len; |
1908 | skb = netdev_alloc_skb_ip_align(NULL, len + ETH_HLEN); | 2461 | tvlv_len = batadv_tt_prepare_tvlv_local_data(bat_priv, |
1909 | if (!skb) | 2462 | &tvlv_tt_data, |
2463 | &tt_change, | ||
2464 | &tt_len); | ||
2465 | if (!tt_len) | ||
1910 | goto unlock; | 2466 | goto unlock; |
1911 | 2467 | ||
1912 | skb->priority = TC_PRIO_CONTROL; | 2468 | /* Copy the last orig_node's OGM buffer */ |
1913 | skb_reserve(skb, ETH_HLEN); | 2469 | memcpy(tt_change, bat_priv->tt.last_changeset, |
1914 | packet_pos = skb_put(skb, len); | ||
1915 | tt_response = (struct batadv_tt_query_packet *)packet_pos; | ||
1916 | tt_response->ttvn = req_ttvn; | ||
1917 | tt_response->tt_data = htons(tt_tot); | ||
1918 | |||
1919 | tt_buff = skb->data + sizeof(*tt_response); | ||
1920 | memcpy(tt_buff, bat_priv->tt.last_changeset, | ||
1921 | bat_priv->tt.last_changeset_len); | 2470 | bat_priv->tt.last_changeset_len); |
1922 | spin_unlock_bh(&bat_priv->tt.last_changeset_lock); | 2471 | spin_unlock_bh(&bat_priv->tt.last_changeset_lock); |
1923 | } else { | 2472 | } else { |
1924 | tt_len = (uint16_t)atomic_read(&bat_priv->tt.local_entry_num); | 2473 | req_ttvn = (uint8_t)atomic_read(&bat_priv->tt.vn); |
1925 | tt_len *= sizeof(struct batadv_tt_change); | 2474 | |
1926 | ttvn = (uint8_t)atomic_read(&bat_priv->tt.vn); | 2475 | /* allocate the tvlv, put the tt_data and all the tt_vlan_data |
1927 | 2476 | * in the initial part | |
1928 | skb = batadv_tt_response_fill_table(tt_len, ttvn, | 2477 | */ |
1929 | bat_priv->tt.local_hash, | 2478 | tt_len = -1; |
1930 | bat_priv, | 2479 | tvlv_len = batadv_tt_prepare_tvlv_local_data(bat_priv, |
1931 | batadv_tt_local_valid_entry, | 2480 | &tvlv_tt_data, |
1932 | NULL); | 2481 | &tt_change, |
1933 | if (!skb) | 2482 | &tt_len); |
2483 | if (!tt_len) | ||
1934 | goto out; | 2484 | goto out; |
1935 | 2485 | ||
1936 | tt_response = (struct batadv_tt_query_packet *)skb->data; | 2486 | /* fill the rest of the tvlv with the real TT entries */ |
2487 | batadv_tt_tvlv_generate(bat_priv, bat_priv->tt.local_hash, | ||
2488 | tt_change, tt_len, | ||
2489 | batadv_tt_local_valid, NULL); | ||
1937 | } | 2490 | } |
1938 | 2491 | ||
1939 | tt_response->header.packet_type = BATADV_TT_QUERY; | 2492 | tvlv_tt_data->flags = BATADV_TT_RESPONSE; |
1940 | tt_response->header.version = BATADV_COMPAT_VERSION; | 2493 | tvlv_tt_data->ttvn = req_ttvn; |
1941 | tt_response->header.ttl = BATADV_TTL; | ||
1942 | memcpy(tt_response->src, primary_if->net_dev->dev_addr, ETH_ALEN); | ||
1943 | memcpy(tt_response->dst, tt_request->src, ETH_ALEN); | ||
1944 | tt_response->flags = BATADV_TT_RESPONSE; | ||
1945 | 2494 | ||
1946 | if (full_table) | 2495 | if (full_table) |
1947 | tt_response->flags |= BATADV_TT_FULL_TABLE; | 2496 | tvlv_tt_data->flags |= BATADV_TT_FULL_TABLE; |
1948 | 2497 | ||
1949 | batadv_dbg(BATADV_DBG_TT, bat_priv, | 2498 | batadv_dbg(BATADV_DBG_TT, bat_priv, |
1950 | "Sending TT_RESPONSE to %pM [%c]\n", | 2499 | "Sending TT_RESPONSE to %pM [%c] (ttvn: %u)\n", |
1951 | orig_node->orig, | 2500 | orig_node->orig, full_table ? 'F' : '.', req_ttvn); |
1952 | (tt_response->flags & BATADV_TT_FULL_TABLE ? 'F' : '.')); | ||
1953 | 2501 | ||
1954 | batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_TX); | 2502 | batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_TX); |
1955 | 2503 | ||
1956 | if (batadv_send_skb_to_orig(skb, orig_node, NULL) != NET_XMIT_DROP) | 2504 | batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr, |
1957 | ret = true; | 2505 | req_src, BATADV_TVLV_TT, 1, tvlv_tt_data, |
2506 | tvlv_len); | ||
2507 | |||
1958 | goto out; | 2508 | goto out; |
1959 | 2509 | ||
1960 | unlock: | 2510 | unlock: |
1961 | spin_unlock_bh(&bat_priv->tt.last_changeset_lock); | 2511 | spin_unlock_bh(&bat_priv->tt.last_changeset_lock); |
1962 | out: | 2512 | out: |
2513 | spin_unlock_bh(&bat_priv->tt.commit_lock); | ||
1963 | if (orig_node) | 2514 | if (orig_node) |
1964 | batadv_orig_node_free_ref(orig_node); | 2515 | batadv_orig_node_free_ref(orig_node); |
1965 | if (primary_if) | 2516 | if (primary_if) |
1966 | batadv_hardif_free_ref(primary_if); | 2517 | batadv_hardif_free_ref(primary_if); |
1967 | if (!ret) | 2518 | kfree(tvlv_tt_data); |
1968 | kfree_skb(skb); | 2519 | /* The packet was for this host, so it doesn't need to be re-routed */ |
1969 | /* This packet was for me, so it doesn't need to be re-routed */ | ||
1970 | return true; | 2520 | return true; |
1971 | } | 2521 | } |
1972 | 2522 | ||
1973 | bool batadv_send_tt_response(struct batadv_priv *bat_priv, | 2523 | /** |
1974 | struct batadv_tt_query_packet *tt_request) | 2524 | * batadv_send_tt_response - send reply to tt request |
2525 | * @bat_priv: the bat priv with all the soft interface information | ||
2526 | * @tt_data: tt data containing the tt request information | ||
2527 | * @req_src: mac address of tt request sender | ||
2528 | * @req_dst: mac address of tt request recipient | ||
2529 | * | ||
2530 | * Returns true if tt request reply was sent, false otherwise. | ||
2531 | */ | ||
2532 | static bool batadv_send_tt_response(struct batadv_priv *bat_priv, | ||
2533 | struct batadv_tvlv_tt_data *tt_data, | ||
2534 | uint8_t *req_src, uint8_t *req_dst) | ||
1975 | { | 2535 | { |
1976 | if (batadv_is_my_mac(bat_priv, tt_request->dst)) { | 2536 | if (batadv_is_my_mac(bat_priv, req_dst)) |
1977 | /* don't answer backbone gws! */ | 2537 | return batadv_send_my_tt_response(bat_priv, tt_data, req_src); |
1978 | if (batadv_bla_is_backbone_gw_orig(bat_priv, tt_request->src)) | 2538 | else |
1979 | return true; | 2539 | return batadv_send_other_tt_response(bat_priv, tt_data, |
1980 | 2540 | req_src, req_dst); | |
1981 | return batadv_send_my_tt_response(bat_priv, tt_request); | ||
1982 | } else { | ||
1983 | return batadv_send_other_tt_response(bat_priv, tt_request); | ||
1984 | } | ||
1985 | } | 2541 | } |
1986 | 2542 | ||
1987 | static void _batadv_tt_update_changes(struct batadv_priv *bat_priv, | 2543 | static void _batadv_tt_update_changes(struct batadv_priv *bat_priv, |
1988 | struct batadv_orig_node *orig_node, | 2544 | struct batadv_orig_node *orig_node, |
1989 | struct batadv_tt_change *tt_change, | 2545 | struct batadv_tvlv_tt_change *tt_change, |
1990 | uint16_t tt_num_changes, uint8_t ttvn) | 2546 | uint16_t tt_num_changes, uint8_t ttvn) |
1991 | { | 2547 | { |
1992 | int i; | 2548 | int i; |
@@ -1997,11 +2553,13 @@ static void _batadv_tt_update_changes(struct batadv_priv *bat_priv, | |||
1997 | roams = (tt_change + i)->flags & BATADV_TT_CLIENT_ROAM; | 2553 | roams = (tt_change + i)->flags & BATADV_TT_CLIENT_ROAM; |
1998 | batadv_tt_global_del(bat_priv, orig_node, | 2554 | batadv_tt_global_del(bat_priv, orig_node, |
1999 | (tt_change + i)->addr, | 2555 | (tt_change + i)->addr, |
2556 | ntohs((tt_change + i)->vid), | ||
2000 | "tt removed by changes", | 2557 | "tt removed by changes", |
2001 | roams); | 2558 | roams); |
2002 | } else { | 2559 | } else { |
2003 | if (!batadv_tt_global_add(bat_priv, orig_node, | 2560 | if (!batadv_tt_global_add(bat_priv, orig_node, |
2004 | (tt_change + i)->addr, | 2561 | (tt_change + i)->addr, |
2562 | ntohs((tt_change + i)->vid), | ||
2005 | (tt_change + i)->flags, ttvn)) | 2563 | (tt_change + i)->flags, ttvn)) |
2006 | /* In case of problem while storing a | 2564 | /* In case of problem while storing a |
2007 | * global_entry, we stop the updating | 2565 | * global_entry, we stop the updating |
@@ -2016,21 +2574,22 @@ static void _batadv_tt_update_changes(struct batadv_priv *bat_priv, | |||
2016 | } | 2574 | } |
2017 | 2575 | ||
2018 | static void batadv_tt_fill_gtable(struct batadv_priv *bat_priv, | 2576 | static void batadv_tt_fill_gtable(struct batadv_priv *bat_priv, |
2019 | struct batadv_tt_query_packet *tt_response) | 2577 | struct batadv_tvlv_tt_change *tt_change, |
2578 | uint8_t ttvn, uint8_t *resp_src, | ||
2579 | uint16_t num_entries) | ||
2020 | { | 2580 | { |
2021 | struct batadv_orig_node *orig_node; | 2581 | struct batadv_orig_node *orig_node; |
2022 | 2582 | ||
2023 | orig_node = batadv_orig_hash_find(bat_priv, tt_response->src); | 2583 | orig_node = batadv_orig_hash_find(bat_priv, resp_src); |
2024 | if (!orig_node) | 2584 | if (!orig_node) |
2025 | goto out; | 2585 | goto out; |
2026 | 2586 | ||
2027 | /* Purge the old table first.. */ | 2587 | /* Purge the old table first.. */ |
2028 | batadv_tt_global_del_orig(bat_priv, orig_node, "Received full table"); | 2588 | batadv_tt_global_del_orig(bat_priv, orig_node, -1, |
2589 | "Received full table"); | ||
2029 | 2590 | ||
2030 | _batadv_tt_update_changes(bat_priv, orig_node, | 2591 | _batadv_tt_update_changes(bat_priv, orig_node, tt_change, num_entries, |
2031 | (struct batadv_tt_change *)(tt_response + 1), | 2592 | ttvn); |
2032 | ntohs(tt_response->tt_data), | ||
2033 | tt_response->ttvn); | ||
2034 | 2593 | ||
2035 | spin_lock_bh(&orig_node->tt_buff_lock); | 2594 | spin_lock_bh(&orig_node->tt_buff_lock); |
2036 | kfree(orig_node->tt_buff); | 2595 | kfree(orig_node->tt_buff); |
@@ -2038,7 +2597,7 @@ static void batadv_tt_fill_gtable(struct batadv_priv *bat_priv, | |||
2038 | orig_node->tt_buff = NULL; | 2597 | orig_node->tt_buff = NULL; |
2039 | spin_unlock_bh(&orig_node->tt_buff_lock); | 2598 | spin_unlock_bh(&orig_node->tt_buff_lock); |
2040 | 2599 | ||
2041 | atomic_set(&orig_node->last_ttvn, tt_response->ttvn); | 2600 | atomic_set(&orig_node->last_ttvn, ttvn); |
2042 | 2601 | ||
2043 | out: | 2602 | out: |
2044 | if (orig_node) | 2603 | if (orig_node) |
@@ -2048,22 +2607,31 @@ out: | |||
2048 | static void batadv_tt_update_changes(struct batadv_priv *bat_priv, | 2607 | static void batadv_tt_update_changes(struct batadv_priv *bat_priv, |
2049 | struct batadv_orig_node *orig_node, | 2608 | struct batadv_orig_node *orig_node, |
2050 | uint16_t tt_num_changes, uint8_t ttvn, | 2609 | uint16_t tt_num_changes, uint8_t ttvn, |
2051 | struct batadv_tt_change *tt_change) | 2610 | struct batadv_tvlv_tt_change *tt_change) |
2052 | { | 2611 | { |
2053 | _batadv_tt_update_changes(bat_priv, orig_node, tt_change, | 2612 | _batadv_tt_update_changes(bat_priv, orig_node, tt_change, |
2054 | tt_num_changes, ttvn); | 2613 | tt_num_changes, ttvn); |
2055 | 2614 | ||
2056 | batadv_tt_save_orig_buffer(bat_priv, orig_node, | 2615 | batadv_tt_save_orig_buffer(bat_priv, orig_node, tt_change, |
2057 | (unsigned char *)tt_change, tt_num_changes); | 2616 | batadv_tt_len(tt_num_changes)); |
2058 | atomic_set(&orig_node->last_ttvn, ttvn); | 2617 | atomic_set(&orig_node->last_ttvn, ttvn); |
2059 | } | 2618 | } |
2060 | 2619 | ||
2061 | bool batadv_is_my_client(struct batadv_priv *bat_priv, const uint8_t *addr) | 2620 | /** |
2621 | * batadv_is_my_client - check if a client is served by the local node | ||
2622 | * @bat_priv: the bat priv with all the soft interface information | ||
2623 | * @addr: the mac adress of the client to check | ||
2624 | * @vid: VLAN identifier | ||
2625 | * | ||
2626 | * Returns true if the client is served by this node, false otherwise. | ||
2627 | */ | ||
2628 | bool batadv_is_my_client(struct batadv_priv *bat_priv, const uint8_t *addr, | ||
2629 | unsigned short vid) | ||
2062 | { | 2630 | { |
2063 | struct batadv_tt_local_entry *tt_local_entry; | 2631 | struct batadv_tt_local_entry *tt_local_entry; |
2064 | bool ret = false; | 2632 | bool ret = false; |
2065 | 2633 | ||
2066 | tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr); | 2634 | tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid); |
2067 | if (!tt_local_entry) | 2635 | if (!tt_local_entry) |
2068 | goto out; | 2636 | goto out; |
2069 | /* Check if the client has been logically deleted (but is kept for | 2637 | /* Check if the client has been logically deleted (but is kept for |
@@ -2079,72 +2647,68 @@ out: | |||
2079 | return ret; | 2647 | return ret; |
2080 | } | 2648 | } |
2081 | 2649 | ||
2082 | void batadv_handle_tt_response(struct batadv_priv *bat_priv, | 2650 | /** |
2083 | struct batadv_tt_query_packet *tt_response) | 2651 | * batadv_handle_tt_response - process incoming tt reply |
2652 | * @bat_priv: the bat priv with all the soft interface information | ||
2653 | * @tt_data: tt data containing the tt request information | ||
2654 | * @resp_src: mac address of tt reply sender | ||
2655 | * @num_entries: number of tt change entries appended to the tt data | ||
2656 | */ | ||
2657 | static void batadv_handle_tt_response(struct batadv_priv *bat_priv, | ||
2658 | struct batadv_tvlv_tt_data *tt_data, | ||
2659 | uint8_t *resp_src, uint16_t num_entries) | ||
2084 | { | 2660 | { |
2085 | struct batadv_tt_req_node *node, *safe; | 2661 | struct batadv_tt_req_node *node, *safe; |
2086 | struct batadv_orig_node *orig_node = NULL; | 2662 | struct batadv_orig_node *orig_node = NULL; |
2087 | struct batadv_tt_change *tt_change; | 2663 | struct batadv_tvlv_tt_change *tt_change; |
2664 | uint8_t *tvlv_ptr = (uint8_t *)tt_data; | ||
2665 | uint16_t change_offset; | ||
2088 | 2666 | ||
2089 | batadv_dbg(BATADV_DBG_TT, bat_priv, | 2667 | batadv_dbg(BATADV_DBG_TT, bat_priv, |
2090 | "Received TT_RESPONSE from %pM for ttvn %d t_size: %d [%c]\n", | 2668 | "Received TT_RESPONSE from %pM for ttvn %d t_size: %d [%c]\n", |
2091 | tt_response->src, tt_response->ttvn, | 2669 | resp_src, tt_data->ttvn, num_entries, |
2092 | ntohs(tt_response->tt_data), | 2670 | (tt_data->flags & BATADV_TT_FULL_TABLE ? 'F' : '.')); |
2093 | (tt_response->flags & BATADV_TT_FULL_TABLE ? 'F' : '.')); | ||
2094 | |||
2095 | /* we should have never asked a backbone gw */ | ||
2096 | if (batadv_bla_is_backbone_gw_orig(bat_priv, tt_response->src)) | ||
2097 | goto out; | ||
2098 | 2671 | ||
2099 | orig_node = batadv_orig_hash_find(bat_priv, tt_response->src); | 2672 | orig_node = batadv_orig_hash_find(bat_priv, resp_src); |
2100 | if (!orig_node) | 2673 | if (!orig_node) |
2101 | goto out; | 2674 | goto out; |
2102 | 2675 | ||
2103 | if (tt_response->flags & BATADV_TT_FULL_TABLE) { | 2676 | spin_lock_bh(&orig_node->tt_lock); |
2104 | batadv_tt_fill_gtable(bat_priv, tt_response); | 2677 | |
2678 | change_offset = sizeof(struct batadv_tvlv_tt_vlan_data); | ||
2679 | change_offset *= ntohs(tt_data->num_vlan); | ||
2680 | change_offset += sizeof(*tt_data); | ||
2681 | tvlv_ptr += change_offset; | ||
2682 | |||
2683 | tt_change = (struct batadv_tvlv_tt_change *)tvlv_ptr; | ||
2684 | if (tt_data->flags & BATADV_TT_FULL_TABLE) { | ||
2685 | batadv_tt_fill_gtable(bat_priv, tt_change, tt_data->ttvn, | ||
2686 | resp_src, num_entries); | ||
2105 | } else { | 2687 | } else { |
2106 | tt_change = (struct batadv_tt_change *)(tt_response + 1); | 2688 | batadv_tt_update_changes(bat_priv, orig_node, num_entries, |
2107 | batadv_tt_update_changes(bat_priv, orig_node, | 2689 | tt_data->ttvn, tt_change); |
2108 | ntohs(tt_response->tt_data), | ||
2109 | tt_response->ttvn, tt_change); | ||
2110 | } | 2690 | } |
2111 | 2691 | ||
2692 | /* Recalculate the CRC for this orig_node and store it */ | ||
2693 | batadv_tt_global_update_crc(bat_priv, orig_node); | ||
2694 | |||
2695 | spin_unlock_bh(&orig_node->tt_lock); | ||
2696 | |||
2112 | /* Delete the tt_req_node from pending tt_requests list */ | 2697 | /* Delete the tt_req_node from pending tt_requests list */ |
2113 | spin_lock_bh(&bat_priv->tt.req_list_lock); | 2698 | spin_lock_bh(&bat_priv->tt.req_list_lock); |
2114 | list_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) { | 2699 | list_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) { |
2115 | if (!batadv_compare_eth(node->addr, tt_response->src)) | 2700 | if (!batadv_compare_eth(node->addr, resp_src)) |
2116 | continue; | 2701 | continue; |
2117 | list_del(&node->list); | 2702 | list_del(&node->list); |
2118 | kfree(node); | 2703 | kfree(node); |
2119 | } | 2704 | } |
2120 | spin_unlock_bh(&bat_priv->tt.req_list_lock); | ||
2121 | 2705 | ||
2122 | /* Recalculate the CRC for this orig_node and store it */ | 2706 | spin_unlock_bh(&bat_priv->tt.req_list_lock); |
2123 | orig_node->tt_crc = batadv_tt_global_crc(bat_priv, orig_node); | ||
2124 | out: | 2707 | out: |
2125 | if (orig_node) | 2708 | if (orig_node) |
2126 | batadv_orig_node_free_ref(orig_node); | 2709 | batadv_orig_node_free_ref(orig_node); |
2127 | } | 2710 | } |
2128 | 2711 | ||
2129 | int batadv_tt_init(struct batadv_priv *bat_priv) | ||
2130 | { | ||
2131 | int ret; | ||
2132 | |||
2133 | ret = batadv_tt_local_init(bat_priv); | ||
2134 | if (ret < 0) | ||
2135 | return ret; | ||
2136 | |||
2137 | ret = batadv_tt_global_init(bat_priv); | ||
2138 | if (ret < 0) | ||
2139 | return ret; | ||
2140 | |||
2141 | INIT_DELAYED_WORK(&bat_priv->tt.work, batadv_tt_purge); | ||
2142 | queue_delayed_work(batadv_event_workqueue, &bat_priv->tt.work, | ||
2143 | msecs_to_jiffies(BATADV_TT_WORK_PERIOD)); | ||
2144 | |||
2145 | return 1; | ||
2146 | } | ||
2147 | |||
2148 | static void batadv_tt_roam_list_free(struct batadv_priv *bat_priv) | 2712 | static void batadv_tt_roam_list_free(struct batadv_priv *bat_priv) |
2149 | { | 2713 | { |
2150 | struct batadv_tt_roam_node *node, *safe; | 2714 | struct batadv_tt_roam_node *node, *safe; |
@@ -2225,14 +2789,28 @@ unlock: | |||
2225 | return ret; | 2789 | return ret; |
2226 | } | 2790 | } |
2227 | 2791 | ||
2792 | /** | ||
2793 | * batadv_send_roam_adv - send a roaming advertisement message | ||
2794 | * @bat_priv: the bat priv with all the soft interface information | ||
2795 | * @client: mac address of the roaming client | ||
2796 | * @vid: VLAN identifier | ||
2797 | * @orig_node: message destination | ||
2798 | * | ||
2799 | * Send a ROAMING_ADV message to the node which was previously serving this | ||
2800 | * client. This is done to inform the node that from now on all traffic destined | ||
2801 | * for this particular roamed client has to be forwarded to the sender of the | ||
2802 | * roaming message. | ||
2803 | */ | ||
2228 | static void batadv_send_roam_adv(struct batadv_priv *bat_priv, uint8_t *client, | 2804 | static void batadv_send_roam_adv(struct batadv_priv *bat_priv, uint8_t *client, |
2805 | unsigned short vid, | ||
2229 | struct batadv_orig_node *orig_node) | 2806 | struct batadv_orig_node *orig_node) |
2230 | { | 2807 | { |
2231 | struct sk_buff *skb = NULL; | ||
2232 | struct batadv_roam_adv_packet *roam_adv_packet; | ||
2233 | int ret = 1; | ||
2234 | struct batadv_hard_iface *primary_if; | 2808 | struct batadv_hard_iface *primary_if; |
2235 | size_t len = sizeof(*roam_adv_packet); | 2809 | struct batadv_tvlv_roam_adv tvlv_roam; |
2810 | |||
2811 | primary_if = batadv_primary_if_get_selected(bat_priv); | ||
2812 | if (!primary_if) | ||
2813 | goto out; | ||
2236 | 2814 | ||
2237 | /* before going on we have to check whether the client has | 2815 | /* before going on we have to check whether the client has |
2238 | * already roamed to us too many times | 2816 | * already roamed to us too many times |
@@ -2240,40 +2818,22 @@ static void batadv_send_roam_adv(struct batadv_priv *bat_priv, uint8_t *client, | |||
2240 | if (!batadv_tt_check_roam_count(bat_priv, client)) | 2818 | if (!batadv_tt_check_roam_count(bat_priv, client)) |
2241 | goto out; | 2819 | goto out; |
2242 | 2820 | ||
2243 | skb = netdev_alloc_skb_ip_align(NULL, len + ETH_HLEN); | ||
2244 | if (!skb) | ||
2245 | goto out; | ||
2246 | |||
2247 | skb->priority = TC_PRIO_CONTROL; | ||
2248 | skb_reserve(skb, ETH_HLEN); | ||
2249 | |||
2250 | roam_adv_packet = (struct batadv_roam_adv_packet *)skb_put(skb, len); | ||
2251 | |||
2252 | roam_adv_packet->header.packet_type = BATADV_ROAM_ADV; | ||
2253 | roam_adv_packet->header.version = BATADV_COMPAT_VERSION; | ||
2254 | roam_adv_packet->header.ttl = BATADV_TTL; | ||
2255 | roam_adv_packet->reserved = 0; | ||
2256 | primary_if = batadv_primary_if_get_selected(bat_priv); | ||
2257 | if (!primary_if) | ||
2258 | goto out; | ||
2259 | memcpy(roam_adv_packet->src, primary_if->net_dev->dev_addr, ETH_ALEN); | ||
2260 | batadv_hardif_free_ref(primary_if); | ||
2261 | memcpy(roam_adv_packet->dst, orig_node->orig, ETH_ALEN); | ||
2262 | memcpy(roam_adv_packet->client, client, ETH_ALEN); | ||
2263 | |||
2264 | batadv_dbg(BATADV_DBG_TT, bat_priv, | 2821 | batadv_dbg(BATADV_DBG_TT, bat_priv, |
2265 | "Sending ROAMING_ADV to %pM (client %pM)\n", | 2822 | "Sending ROAMING_ADV to %pM (client %pM, vid: %d)\n", |
2266 | orig_node->orig, client); | 2823 | orig_node->orig, client, BATADV_PRINT_VID(vid)); |
2267 | 2824 | ||
2268 | batadv_inc_counter(bat_priv, BATADV_CNT_TT_ROAM_ADV_TX); | 2825 | batadv_inc_counter(bat_priv, BATADV_CNT_TT_ROAM_ADV_TX); |
2269 | 2826 | ||
2270 | if (batadv_send_skb_to_orig(skb, orig_node, NULL) != NET_XMIT_DROP) | 2827 | memcpy(tvlv_roam.client, client, sizeof(tvlv_roam.client)); |
2271 | ret = 0; | 2828 | tvlv_roam.vid = htons(vid); |
2829 | |||
2830 | batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr, | ||
2831 | orig_node->orig, BATADV_TVLV_ROAM, 1, | ||
2832 | &tvlv_roam, sizeof(tvlv_roam)); | ||
2272 | 2833 | ||
2273 | out: | 2834 | out: |
2274 | if (ret && skb) | 2835 | if (primary_if) |
2275 | kfree_skb(skb); | 2836 | batadv_hardif_free_ref(primary_if); |
2276 | return; | ||
2277 | } | 2837 | } |
2278 | 2838 | ||
2279 | static void batadv_tt_purge(struct work_struct *work) | 2839 | static void batadv_tt_purge(struct work_struct *work) |
@@ -2297,6 +2857,9 @@ static void batadv_tt_purge(struct work_struct *work) | |||
2297 | 2857 | ||
2298 | void batadv_tt_free(struct batadv_priv *bat_priv) | 2858 | void batadv_tt_free(struct batadv_priv *bat_priv) |
2299 | { | 2859 | { |
2860 | batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_TT, 1); | ||
2861 | batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_TT, 1); | ||
2862 | |||
2300 | cancel_delayed_work_sync(&bat_priv->tt.work); | 2863 | cancel_delayed_work_sync(&bat_priv->tt.work); |
2301 | 2864 | ||
2302 | batadv_tt_local_table_free(bat_priv); | 2865 | batadv_tt_local_table_free(bat_priv); |
@@ -2308,19 +2871,25 @@ void batadv_tt_free(struct batadv_priv *bat_priv) | |||
2308 | kfree(bat_priv->tt.last_changeset); | 2871 | kfree(bat_priv->tt.last_changeset); |
2309 | } | 2872 | } |
2310 | 2873 | ||
2311 | /* This function will enable or disable the specified flags for all the entries | 2874 | /** |
2312 | * in the given hash table and returns the number of modified entries | 2875 | * batadv_tt_local_set_flags - set or unset the specified flags on the local |
2876 | * table and possibly count them in the TT size | ||
2877 | * @bat_priv: the bat priv with all the soft interface information | ||
2878 | * @flags: the flag to switch | ||
2879 | * @enable: whether to set or unset the flag | ||
2880 | * @count: whether to increase the TT size by the number of changed entries | ||
2313 | */ | 2881 | */ |
2314 | static uint16_t batadv_tt_set_flags(struct batadv_hashtable *hash, | 2882 | static void batadv_tt_local_set_flags(struct batadv_priv *bat_priv, |
2315 | uint16_t flags, bool enable) | 2883 | uint16_t flags, bool enable, bool count) |
2316 | { | 2884 | { |
2317 | uint32_t i; | 2885 | struct batadv_hashtable *hash = bat_priv->tt.local_hash; |
2886 | struct batadv_tt_common_entry *tt_common_entry; | ||
2318 | uint16_t changed_num = 0; | 2887 | uint16_t changed_num = 0; |
2319 | struct hlist_head *head; | 2888 | struct hlist_head *head; |
2320 | struct batadv_tt_common_entry *tt_common_entry; | 2889 | uint32_t i; |
2321 | 2890 | ||
2322 | if (!hash) | 2891 | if (!hash) |
2323 | goto out; | 2892 | return; |
2324 | 2893 | ||
2325 | for (i = 0; i < hash->size; i++) { | 2894 | for (i = 0; i < hash->size; i++) { |
2326 | head = &hash->table[i]; | 2895 | head = &hash->table[i]; |
@@ -2338,11 +2907,15 @@ static uint16_t batadv_tt_set_flags(struct batadv_hashtable *hash, | |||
2338 | tt_common_entry->flags &= ~flags; | 2907 | tt_common_entry->flags &= ~flags; |
2339 | } | 2908 | } |
2340 | changed_num++; | 2909 | changed_num++; |
2910 | |||
2911 | if (!count) | ||
2912 | continue; | ||
2913 | |||
2914 | batadv_tt_local_size_inc(bat_priv, | ||
2915 | tt_common_entry->vid); | ||
2341 | } | 2916 | } |
2342 | rcu_read_unlock(); | 2917 | rcu_read_unlock(); |
2343 | } | 2918 | } |
2344 | out: | ||
2345 | return changed_num; | ||
2346 | } | 2919 | } |
2347 | 2920 | ||
2348 | /* Purge out all the tt local entries marked with BATADV_TT_CLIENT_PENDING */ | 2921 | /* Purge out all the tt local entries marked with BATADV_TT_CLIENT_PENDING */ |
@@ -2370,10 +2943,11 @@ static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv) | |||
2370 | continue; | 2943 | continue; |
2371 | 2944 | ||
2372 | batadv_dbg(BATADV_DBG_TT, bat_priv, | 2945 | batadv_dbg(BATADV_DBG_TT, bat_priv, |
2373 | "Deleting local tt entry (%pM): pending\n", | 2946 | "Deleting local tt entry (%pM, vid: %d): pending\n", |
2374 | tt_common->addr); | 2947 | tt_common->addr, |
2948 | BATADV_PRINT_VID(tt_common->vid)); | ||
2375 | 2949 | ||
2376 | atomic_dec(&bat_priv->tt.local_entry_num); | 2950 | batadv_tt_local_size_dec(bat_priv, tt_common->vid); |
2377 | hlist_del_rcu(&tt_common->hash_entry); | 2951 | hlist_del_rcu(&tt_common->hash_entry); |
2378 | tt_local = container_of(tt_common, | 2952 | tt_local = container_of(tt_common, |
2379 | struct batadv_tt_local_entry, | 2953 | struct batadv_tt_local_entry, |
@@ -2384,22 +2958,25 @@ static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv) | |||
2384 | } | 2958 | } |
2385 | } | 2959 | } |
2386 | 2960 | ||
2387 | static int batadv_tt_commit_changes(struct batadv_priv *bat_priv, | 2961 | /** |
2388 | unsigned char **packet_buff, | 2962 | * batadv_tt_local_commit_changes - commit all pending local tt changes which |
2389 | int *packet_buff_len, int packet_min_len) | 2963 | * have been queued in the time since the last commit |
2964 | * @bat_priv: the bat priv with all the soft interface information | ||
2965 | */ | ||
2966 | void batadv_tt_local_commit_changes(struct batadv_priv *bat_priv) | ||
2390 | { | 2967 | { |
2391 | uint16_t changed_num = 0; | 2968 | spin_lock_bh(&bat_priv->tt.commit_lock); |
2392 | 2969 | ||
2393 | if (atomic_read(&bat_priv->tt.local_changes) < 1) | 2970 | if (atomic_read(&bat_priv->tt.local_changes) < 1) { |
2394 | return -ENOENT; | 2971 | if (!batadv_atomic_dec_not_zero(&bat_priv->tt.ogm_append_cnt)) |
2972 | batadv_tt_tvlv_container_update(bat_priv); | ||
2973 | goto out; | ||
2974 | } | ||
2395 | 2975 | ||
2396 | changed_num = batadv_tt_set_flags(bat_priv->tt.local_hash, | 2976 | batadv_tt_local_set_flags(bat_priv, BATADV_TT_CLIENT_NEW, false, true); |
2397 | BATADV_TT_CLIENT_NEW, false); | ||
2398 | 2977 | ||
2399 | /* all reset entries have to be counted as local entries */ | ||
2400 | atomic_add(changed_num, &bat_priv->tt.local_entry_num); | ||
2401 | batadv_tt_local_purge_pending_clients(bat_priv); | 2978 | batadv_tt_local_purge_pending_clients(bat_priv); |
2402 | bat_priv->tt.local_crc = batadv_tt_local_crc(bat_priv); | 2979 | batadv_tt_local_update_crc(bat_priv); |
2403 | 2980 | ||
2404 | /* Increment the TTVN only once per OGM interval */ | 2981 | /* Increment the TTVN only once per OGM interval */ |
2405 | atomic_inc(&bat_priv->tt.vn); | 2982 | atomic_inc(&bat_priv->tt.vn); |
@@ -2409,49 +2986,29 @@ static int batadv_tt_commit_changes(struct batadv_priv *bat_priv, | |||
2409 | 2986 | ||
2410 | /* reset the sending counter */ | 2987 | /* reset the sending counter */ |
2411 | atomic_set(&bat_priv->tt.ogm_append_cnt, BATADV_TT_OGM_APPEND_MAX); | 2988 | atomic_set(&bat_priv->tt.ogm_append_cnt, BATADV_TT_OGM_APPEND_MAX); |
2989 | batadv_tt_tvlv_container_update(bat_priv); | ||
2412 | 2990 | ||
2413 | return batadv_tt_changes_fill_buff(bat_priv, packet_buff, | 2991 | out: |
2414 | packet_buff_len, packet_min_len); | 2992 | spin_unlock_bh(&bat_priv->tt.commit_lock); |
2415 | } | ||
2416 | |||
2417 | /* when calling this function (hard_iface == primary_if) has to be true */ | ||
2418 | int batadv_tt_append_diff(struct batadv_priv *bat_priv, | ||
2419 | unsigned char **packet_buff, int *packet_buff_len, | ||
2420 | int packet_min_len) | ||
2421 | { | ||
2422 | int tt_num_changes; | ||
2423 | |||
2424 | /* if at least one change happened */ | ||
2425 | tt_num_changes = batadv_tt_commit_changes(bat_priv, packet_buff, | ||
2426 | packet_buff_len, | ||
2427 | packet_min_len); | ||
2428 | |||
2429 | /* if the changes have been sent often enough */ | ||
2430 | if ((tt_num_changes < 0) && | ||
2431 | (!batadv_atomic_dec_not_zero(&bat_priv->tt.ogm_append_cnt))) { | ||
2432 | batadv_tt_realloc_packet_buff(packet_buff, packet_buff_len, | ||
2433 | packet_min_len, packet_min_len); | ||
2434 | tt_num_changes = 0; | ||
2435 | } | ||
2436 | |||
2437 | return tt_num_changes; | ||
2438 | } | 2993 | } |
2439 | 2994 | ||
2440 | bool batadv_is_ap_isolated(struct batadv_priv *bat_priv, uint8_t *src, | 2995 | bool batadv_is_ap_isolated(struct batadv_priv *bat_priv, uint8_t *src, |
2441 | uint8_t *dst) | 2996 | uint8_t *dst, unsigned short vid) |
2442 | { | 2997 | { |
2443 | struct batadv_tt_local_entry *tt_local_entry = NULL; | 2998 | struct batadv_tt_local_entry *tt_local_entry = NULL; |
2444 | struct batadv_tt_global_entry *tt_global_entry = NULL; | 2999 | struct batadv_tt_global_entry *tt_global_entry = NULL; |
3000 | struct batadv_softif_vlan *vlan; | ||
2445 | bool ret = false; | 3001 | bool ret = false; |
2446 | 3002 | ||
2447 | if (!atomic_read(&bat_priv->ap_isolation)) | 3003 | vlan = batadv_softif_vlan_get(bat_priv, vid); |
3004 | if (!vlan || !atomic_read(&vlan->ap_isolation)) | ||
2448 | goto out; | 3005 | goto out; |
2449 | 3006 | ||
2450 | tt_local_entry = batadv_tt_local_hash_find(bat_priv, dst); | 3007 | tt_local_entry = batadv_tt_local_hash_find(bat_priv, dst, vid); |
2451 | if (!tt_local_entry) | 3008 | if (!tt_local_entry) |
2452 | goto out; | 3009 | goto out; |
2453 | 3010 | ||
2454 | tt_global_entry = batadv_tt_global_hash_find(bat_priv, src); | 3011 | tt_global_entry = batadv_tt_global_hash_find(bat_priv, src, vid); |
2455 | if (!tt_global_entry) | 3012 | if (!tt_global_entry) |
2456 | goto out; | 3013 | goto out; |
2457 | 3014 | ||
@@ -2461,6 +3018,8 @@ bool batadv_is_ap_isolated(struct batadv_priv *bat_priv, uint8_t *src, | |||
2461 | ret = true; | 3018 | ret = true; |
2462 | 3019 | ||
2463 | out: | 3020 | out: |
3021 | if (vlan) | ||
3022 | batadv_softif_vlan_free_ref(vlan); | ||
2464 | if (tt_global_entry) | 3023 | if (tt_global_entry) |
2465 | batadv_tt_global_entry_free_ref(tt_global_entry); | 3024 | batadv_tt_global_entry_free_ref(tt_global_entry); |
2466 | if (tt_local_entry) | 3025 | if (tt_local_entry) |
@@ -2468,19 +3027,29 @@ out: | |||
2468 | return ret; | 3027 | return ret; |
2469 | } | 3028 | } |
2470 | 3029 | ||
2471 | void batadv_tt_update_orig(struct batadv_priv *bat_priv, | 3030 | /** |
2472 | struct batadv_orig_node *orig_node, | 3031 | * batadv_tt_update_orig - update global translation table with new tt |
2473 | const unsigned char *tt_buff, uint8_t tt_num_changes, | 3032 | * information received via ogms |
2474 | uint8_t ttvn, uint16_t tt_crc) | 3033 | * @bat_priv: the bat priv with all the soft interface information |
3034 | * @orig: the orig_node of the ogm | ||
3035 | * @tt_vlan: pointer to the first tvlv VLAN entry | ||
3036 | * @tt_num_vlan: number of tvlv VLAN entries | ||
3037 | * @tt_change: pointer to the first entry in the TT buffer | ||
3038 | * @tt_num_changes: number of tt changes inside the tt buffer | ||
3039 | * @ttvn: translation table version number of this changeset | ||
3040 | * @tt_crc: crc32 checksum of orig node's translation table | ||
3041 | */ | ||
3042 | static void batadv_tt_update_orig(struct batadv_priv *bat_priv, | ||
3043 | struct batadv_orig_node *orig_node, | ||
3044 | const void *tt_buff, uint16_t tt_num_vlan, | ||
3045 | struct batadv_tvlv_tt_change *tt_change, | ||
3046 | uint16_t tt_num_changes, uint8_t ttvn) | ||
2475 | { | 3047 | { |
2476 | uint8_t orig_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn); | 3048 | uint8_t orig_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn); |
3049 | struct batadv_tvlv_tt_vlan_data *tt_vlan; | ||
2477 | bool full_table = true; | 3050 | bool full_table = true; |
2478 | struct batadv_tt_change *tt_change; | ||
2479 | |||
2480 | /* don't care about a backbone gateways updates. */ | ||
2481 | if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig)) | ||
2482 | return; | ||
2483 | 3051 | ||
3052 | tt_vlan = (struct batadv_tvlv_tt_vlan_data *)tt_buff; | ||
2484 | /* orig table not initialised AND first diff is in the OGM OR the ttvn | 3053 | /* orig table not initialised AND first diff is in the OGM OR the ttvn |
2485 | * increased by one -> we can apply the attached changes | 3054 | * increased by one -> we can apply the attached changes |
2486 | */ | 3055 | */ |
@@ -2496,7 +3065,9 @@ void batadv_tt_update_orig(struct batadv_priv *bat_priv, | |||
2496 | goto request_table; | 3065 | goto request_table; |
2497 | } | 3066 | } |
2498 | 3067 | ||
2499 | tt_change = (struct batadv_tt_change *)tt_buff; | 3068 | spin_lock_bh(&orig_node->tt_lock); |
3069 | |||
3070 | tt_change = (struct batadv_tvlv_tt_change *)tt_buff; | ||
2500 | batadv_tt_update_changes(bat_priv, orig_node, tt_num_changes, | 3071 | batadv_tt_update_changes(bat_priv, orig_node, tt_num_changes, |
2501 | ttvn, tt_change); | 3072 | ttvn, tt_change); |
2502 | 3073 | ||
@@ -2504,7 +3075,9 @@ void batadv_tt_update_orig(struct batadv_priv *bat_priv, | |||
2504 | * prefer to recompute it to spot any possible inconsistency | 3075 | * prefer to recompute it to spot any possible inconsistency |
2505 | * in the global table | 3076 | * in the global table |
2506 | */ | 3077 | */ |
2507 | orig_node->tt_crc = batadv_tt_global_crc(bat_priv, orig_node); | 3078 | batadv_tt_global_update_crc(bat_priv, orig_node); |
3079 | |||
3080 | spin_unlock_bh(&orig_node->tt_lock); | ||
2508 | 3081 | ||
2509 | /* The ttvn alone is not enough to guarantee consistency | 3082 | /* The ttvn alone is not enough to guarantee consistency |
2510 | * because a single value could represent different states | 3083 | * because a single value could represent different states |
@@ -2515,37 +3088,46 @@ void batadv_tt_update_orig(struct batadv_priv *bat_priv, | |||
2515 | * checking the CRC value is mandatory to detect the | 3088 | * checking the CRC value is mandatory to detect the |
2516 | * inconsistency | 3089 | * inconsistency |
2517 | */ | 3090 | */ |
2518 | if (orig_node->tt_crc != tt_crc) | 3091 | if (!batadv_tt_global_check_crc(orig_node, tt_vlan, |
3092 | tt_num_vlan)) | ||
2519 | goto request_table; | 3093 | goto request_table; |
2520 | } else { | 3094 | } else { |
2521 | /* if we missed more than one change or our tables are not | 3095 | /* if we missed more than one change or our tables are not |
2522 | * in sync anymore -> request fresh tt data | 3096 | * in sync anymore -> request fresh tt data |
2523 | */ | 3097 | */ |
2524 | if (!orig_node->tt_initialised || ttvn != orig_ttvn || | 3098 | if (!orig_node->tt_initialised || ttvn != orig_ttvn || |
2525 | orig_node->tt_crc != tt_crc) { | 3099 | !batadv_tt_global_check_crc(orig_node, tt_vlan, |
3100 | tt_num_vlan)) { | ||
2526 | request_table: | 3101 | request_table: |
2527 | batadv_dbg(BATADV_DBG_TT, bat_priv, | 3102 | batadv_dbg(BATADV_DBG_TT, bat_priv, |
2528 | "TT inconsistency for %pM. Need to retrieve the correct information (ttvn: %u last_ttvn: %u crc: %#.4x last_crc: %#.4x num_changes: %u)\n", | 3103 | "TT inconsistency for %pM. Need to retrieve the correct information (ttvn: %u last_ttvn: %u num_changes: %u)\n", |
2529 | orig_node->orig, ttvn, orig_ttvn, tt_crc, | 3104 | orig_node->orig, ttvn, orig_ttvn, |
2530 | orig_node->tt_crc, tt_num_changes); | 3105 | tt_num_changes); |
2531 | batadv_send_tt_request(bat_priv, orig_node, ttvn, | 3106 | batadv_send_tt_request(bat_priv, orig_node, ttvn, |
2532 | tt_crc, full_table); | 3107 | tt_vlan, tt_num_vlan, |
3108 | full_table); | ||
2533 | return; | 3109 | return; |
2534 | } | 3110 | } |
2535 | } | 3111 | } |
2536 | } | 3112 | } |
2537 | 3113 | ||
2538 | /* returns true whether we know that the client has moved from its old | 3114 | /** |
2539 | * originator to another one. This entry is kept is still kept for consistency | 3115 | * batadv_tt_global_client_is_roaming - check if a client is marked as roaming |
2540 | * purposes | 3116 | * @bat_priv: the bat priv with all the soft interface information |
3117 | * @addr: the mac address of the client to check | ||
3118 | * @vid: VLAN identifier | ||
3119 | * | ||
3120 | * Returns true if we know that the client has moved from its old originator | ||
3121 | * to another one. This entry is still kept for consistency purposes and will be | ||
3122 | * deleted later by a DEL or because of timeout | ||
2541 | */ | 3123 | */ |
2542 | bool batadv_tt_global_client_is_roaming(struct batadv_priv *bat_priv, | 3124 | bool batadv_tt_global_client_is_roaming(struct batadv_priv *bat_priv, |
2543 | uint8_t *addr) | 3125 | uint8_t *addr, unsigned short vid) |
2544 | { | 3126 | { |
2545 | struct batadv_tt_global_entry *tt_global_entry; | 3127 | struct batadv_tt_global_entry *tt_global_entry; |
2546 | bool ret = false; | 3128 | bool ret = false; |
2547 | 3129 | ||
2548 | tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr); | 3130 | tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid); |
2549 | if (!tt_global_entry) | 3131 | if (!tt_global_entry) |
2550 | goto out; | 3132 | goto out; |
2551 | 3133 | ||
@@ -2558,19 +3140,20 @@ out: | |||
2558 | /** | 3140 | /** |
2559 | * batadv_tt_local_client_is_roaming - tells whether the client is roaming | 3141 | * batadv_tt_local_client_is_roaming - tells whether the client is roaming |
2560 | * @bat_priv: the bat priv with all the soft interface information | 3142 | * @bat_priv: the bat priv with all the soft interface information |
2561 | * @addr: the MAC address of the local client to query | 3143 | * @addr: the mac address of the local client to query |
3144 | * @vid: VLAN identifier | ||
2562 | * | 3145 | * |
2563 | * Returns true if the local client is known to be roaming (it is not served by | 3146 | * Returns true if the local client is known to be roaming (it is not served by |
2564 | * this node anymore) or not. If yes, the client is still present in the table | 3147 | * this node anymore) or not. If yes, the client is still present in the table |
2565 | * to keep the latter consistent with the node TTVN | 3148 | * to keep the latter consistent with the node TTVN |
2566 | */ | 3149 | */ |
2567 | bool batadv_tt_local_client_is_roaming(struct batadv_priv *bat_priv, | 3150 | bool batadv_tt_local_client_is_roaming(struct batadv_priv *bat_priv, |
2568 | uint8_t *addr) | 3151 | uint8_t *addr, unsigned short vid) |
2569 | { | 3152 | { |
2570 | struct batadv_tt_local_entry *tt_local_entry; | 3153 | struct batadv_tt_local_entry *tt_local_entry; |
2571 | bool ret = false; | 3154 | bool ret = false; |
2572 | 3155 | ||
2573 | tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr); | 3156 | tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid); |
2574 | if (!tt_local_entry) | 3157 | if (!tt_local_entry) |
2575 | goto out; | 3158 | goto out; |
2576 | 3159 | ||
@@ -2582,26 +3165,224 @@ out: | |||
2582 | 3165 | ||
2583 | bool batadv_tt_add_temporary_global_entry(struct batadv_priv *bat_priv, | 3166 | bool batadv_tt_add_temporary_global_entry(struct batadv_priv *bat_priv, |
2584 | struct batadv_orig_node *orig_node, | 3167 | struct batadv_orig_node *orig_node, |
2585 | const unsigned char *addr) | 3168 | const unsigned char *addr, |
3169 | unsigned short vid) | ||
2586 | { | 3170 | { |
2587 | bool ret = false; | 3171 | bool ret = false; |
2588 | 3172 | ||
2589 | /* if the originator is a backbone node (meaning it belongs to the same | 3173 | if (!batadv_tt_global_add(bat_priv, orig_node, addr, vid, |
2590 | * LAN of this node) the temporary client must not be added because to | ||
2591 | * reach such destination the node must use the LAN instead of the mesh | ||
2592 | */ | ||
2593 | if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig)) | ||
2594 | goto out; | ||
2595 | |||
2596 | if (!batadv_tt_global_add(bat_priv, orig_node, addr, | ||
2597 | BATADV_TT_CLIENT_TEMP, | 3174 | BATADV_TT_CLIENT_TEMP, |
2598 | atomic_read(&orig_node->last_ttvn))) | 3175 | atomic_read(&orig_node->last_ttvn))) |
2599 | goto out; | 3176 | goto out; |
2600 | 3177 | ||
2601 | batadv_dbg(BATADV_DBG_TT, bat_priv, | 3178 | batadv_dbg(BATADV_DBG_TT, bat_priv, |
2602 | "Added temporary global client (addr: %pM orig: %pM)\n", | 3179 | "Added temporary global client (addr: %pM, vid: %d, orig: %pM)\n", |
2603 | addr, orig_node->orig); | 3180 | addr, BATADV_PRINT_VID(vid), orig_node->orig); |
2604 | ret = true; | 3181 | ret = true; |
2605 | out: | 3182 | out: |
2606 | return ret; | 3183 | return ret; |
2607 | } | 3184 | } |
3185 | |||
3186 | /** | ||
3187 | * batadv_tt_tvlv_ogm_handler_v1 - process incoming tt tvlv container | ||
3188 | * @bat_priv: the bat priv with all the soft interface information | ||
3189 | * @orig: the orig_node of the ogm | ||
3190 | * @flags: flags indicating the tvlv state (see batadv_tvlv_handler_flags) | ||
3191 | * @tvlv_value: tvlv buffer containing the gateway data | ||
3192 | * @tvlv_value_len: tvlv buffer length | ||
3193 | */ | ||
3194 | static void batadv_tt_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv, | ||
3195 | struct batadv_orig_node *orig, | ||
3196 | uint8_t flags, void *tvlv_value, | ||
3197 | uint16_t tvlv_value_len) | ||
3198 | { | ||
3199 | struct batadv_tvlv_tt_vlan_data *tt_vlan; | ||
3200 | struct batadv_tvlv_tt_change *tt_change; | ||
3201 | struct batadv_tvlv_tt_data *tt_data; | ||
3202 | uint16_t num_entries, num_vlan; | ||
3203 | |||
3204 | if (tvlv_value_len < sizeof(*tt_data)) | ||
3205 | return; | ||
3206 | |||
3207 | tt_data = (struct batadv_tvlv_tt_data *)tvlv_value; | ||
3208 | tvlv_value_len -= sizeof(*tt_data); | ||
3209 | |||
3210 | num_vlan = ntohs(tt_data->num_vlan); | ||
3211 | |||
3212 | if (tvlv_value_len < sizeof(*tt_vlan) * num_vlan) | ||
3213 | return; | ||
3214 | |||
3215 | tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(tt_data + 1); | ||
3216 | tt_change = (struct batadv_tvlv_tt_change *)(tt_vlan + num_vlan); | ||
3217 | tvlv_value_len -= sizeof(*tt_vlan) * num_vlan; | ||
3218 | |||
3219 | num_entries = batadv_tt_entries(tvlv_value_len); | ||
3220 | |||
3221 | batadv_tt_update_orig(bat_priv, orig, tt_vlan, num_vlan, tt_change, | ||
3222 | num_entries, tt_data->ttvn); | ||
3223 | } | ||
3224 | |||
3225 | /** | ||
3226 | * batadv_tt_tvlv_unicast_handler_v1 - process incoming (unicast) tt tvlv | ||
3227 | * container | ||
3228 | * @bat_priv: the bat priv with all the soft interface information | ||
3229 | * @src: mac address of tt tvlv sender | ||
3230 | * @dst: mac address of tt tvlv recipient | ||
3231 | * @tvlv_value: tvlv buffer containing the tt data | ||
3232 | * @tvlv_value_len: tvlv buffer length | ||
3233 | * | ||
3234 | * Returns NET_RX_DROP if the tt tvlv is to be re-routed, NET_RX_SUCCESS | ||
3235 | * otherwise. | ||
3236 | */ | ||
3237 | static int batadv_tt_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv, | ||
3238 | uint8_t *src, uint8_t *dst, | ||
3239 | void *tvlv_value, | ||
3240 | uint16_t tvlv_value_len) | ||
3241 | { | ||
3242 | struct batadv_tvlv_tt_data *tt_data; | ||
3243 | uint16_t tt_vlan_len, tt_num_entries; | ||
3244 | char tt_flag; | ||
3245 | bool ret; | ||
3246 | |||
3247 | if (tvlv_value_len < sizeof(*tt_data)) | ||
3248 | return NET_RX_SUCCESS; | ||
3249 | |||
3250 | tt_data = (struct batadv_tvlv_tt_data *)tvlv_value; | ||
3251 | tvlv_value_len -= sizeof(*tt_data); | ||
3252 | |||
3253 | tt_vlan_len = sizeof(struct batadv_tvlv_tt_vlan_data); | ||
3254 | tt_vlan_len *= ntohs(tt_data->num_vlan); | ||
3255 | |||
3256 | if (tvlv_value_len < tt_vlan_len) | ||
3257 | return NET_RX_SUCCESS; | ||
3258 | |||
3259 | tvlv_value_len -= tt_vlan_len; | ||
3260 | tt_num_entries = batadv_tt_entries(tvlv_value_len); | ||
3261 | |||
3262 | switch (tt_data->flags & BATADV_TT_DATA_TYPE_MASK) { | ||
3263 | case BATADV_TT_REQUEST: | ||
3264 | batadv_inc_counter(bat_priv, BATADV_CNT_TT_REQUEST_RX); | ||
3265 | |||
3266 | /* If this node cannot provide a TT response the tt_request is | ||
3267 | * forwarded | ||
3268 | */ | ||
3269 | ret = batadv_send_tt_response(bat_priv, tt_data, src, dst); | ||
3270 | if (!ret) { | ||
3271 | if (tt_data->flags & BATADV_TT_FULL_TABLE) | ||
3272 | tt_flag = 'F'; | ||
3273 | else | ||
3274 | tt_flag = '.'; | ||
3275 | |||
3276 | batadv_dbg(BATADV_DBG_TT, bat_priv, | ||
3277 | "Routing TT_REQUEST to %pM [%c]\n", | ||
3278 | dst, tt_flag); | ||
3279 | /* tvlv API will re-route the packet */ | ||
3280 | return NET_RX_DROP; | ||
3281 | } | ||
3282 | break; | ||
3283 | case BATADV_TT_RESPONSE: | ||
3284 | batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_RX); | ||
3285 | |||
3286 | if (batadv_is_my_mac(bat_priv, dst)) { | ||
3287 | batadv_handle_tt_response(bat_priv, tt_data, | ||
3288 | src, tt_num_entries); | ||
3289 | return NET_RX_SUCCESS; | ||
3290 | } | ||
3291 | |||
3292 | if (tt_data->flags & BATADV_TT_FULL_TABLE) | ||
3293 | tt_flag = 'F'; | ||
3294 | else | ||
3295 | tt_flag = '.'; | ||
3296 | |||
3297 | batadv_dbg(BATADV_DBG_TT, bat_priv, | ||
3298 | "Routing TT_RESPONSE to %pM [%c]\n", dst, tt_flag); | ||
3299 | |||
3300 | /* tvlv API will re-route the packet */ | ||
3301 | return NET_RX_DROP; | ||
3302 | } | ||
3303 | |||
3304 | return NET_RX_SUCCESS; | ||
3305 | } | ||
3306 | |||
3307 | /** | ||
3308 | * batadv_roam_tvlv_unicast_handler_v1 - process incoming tt roam tvlv container | ||
3309 | * @bat_priv: the bat priv with all the soft interface information | ||
3310 | * @src: mac address of tt tvlv sender | ||
3311 | * @dst: mac address of tt tvlv recipient | ||
3312 | * @tvlv_value: tvlv buffer containing the tt data | ||
3313 | * @tvlv_value_len: tvlv buffer length | ||
3314 | * | ||
3315 | * Returns NET_RX_DROP if the tt roam tvlv is to be re-routed, NET_RX_SUCCESS | ||
3316 | * otherwise. | ||
3317 | */ | ||
3318 | static int batadv_roam_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv, | ||
3319 | uint8_t *src, uint8_t *dst, | ||
3320 | void *tvlv_value, | ||
3321 | uint16_t tvlv_value_len) | ||
3322 | { | ||
3323 | struct batadv_tvlv_roam_adv *roaming_adv; | ||
3324 | struct batadv_orig_node *orig_node = NULL; | ||
3325 | |||
3326 | /* If this node is not the intended recipient of the | ||
3327 | * roaming advertisement the packet is forwarded | ||
3328 | * (the tvlv API will re-route the packet). | ||
3329 | */ | ||
3330 | if (!batadv_is_my_mac(bat_priv, dst)) | ||
3331 | return NET_RX_DROP; | ||
3332 | |||
3333 | if (tvlv_value_len < sizeof(*roaming_adv)) | ||
3334 | goto out; | ||
3335 | |||
3336 | orig_node = batadv_orig_hash_find(bat_priv, src); | ||
3337 | if (!orig_node) | ||
3338 | goto out; | ||
3339 | |||
3340 | batadv_inc_counter(bat_priv, BATADV_CNT_TT_ROAM_ADV_RX); | ||
3341 | roaming_adv = (struct batadv_tvlv_roam_adv *)tvlv_value; | ||
3342 | |||
3343 | batadv_dbg(BATADV_DBG_TT, bat_priv, | ||
3344 | "Received ROAMING_ADV from %pM (client %pM)\n", | ||
3345 | src, roaming_adv->client); | ||
3346 | |||
3347 | batadv_tt_global_add(bat_priv, orig_node, roaming_adv->client, | ||
3348 | ntohs(roaming_adv->vid), BATADV_TT_CLIENT_ROAM, | ||
3349 | atomic_read(&orig_node->last_ttvn) + 1); | ||
3350 | |||
3351 | out: | ||
3352 | if (orig_node) | ||
3353 | batadv_orig_node_free_ref(orig_node); | ||
3354 | return NET_RX_SUCCESS; | ||
3355 | } | ||
3356 | |||
3357 | /** | ||
3358 | * batadv_tt_init - initialise the translation table internals | ||
3359 | * @bat_priv: the bat priv with all the soft interface information | ||
3360 | * | ||
3361 | * Return 0 on success or negative error number in case of failure. | ||
3362 | */ | ||
3363 | int batadv_tt_init(struct batadv_priv *bat_priv) | ||
3364 | { | ||
3365 | int ret; | ||
3366 | |||
3367 | ret = batadv_tt_local_init(bat_priv); | ||
3368 | if (ret < 0) | ||
3369 | return ret; | ||
3370 | |||
3371 | ret = batadv_tt_global_init(bat_priv); | ||
3372 | if (ret < 0) | ||
3373 | return ret; | ||
3374 | |||
3375 | batadv_tvlv_handler_register(bat_priv, batadv_tt_tvlv_ogm_handler_v1, | ||
3376 | batadv_tt_tvlv_unicast_handler_v1, | ||
3377 | BATADV_TVLV_TT, 1, BATADV_NO_FLAGS); | ||
3378 | |||
3379 | batadv_tvlv_handler_register(bat_priv, NULL, | ||
3380 | batadv_roam_tvlv_unicast_handler_v1, | ||
3381 | BATADV_TVLV_ROAM, 1, BATADV_NO_FLAGS); | ||
3382 | |||
3383 | INIT_DELAYED_WORK(&bat_priv->tt.work, batadv_tt_purge); | ||
3384 | queue_delayed_work(batadv_event_workqueue, &bat_priv->tt.work, | ||
3385 | msecs_to_jiffies(BATADV_TT_WORK_PERIOD)); | ||
3386 | |||
3387 | return 1; | ||
3388 | } | ||
diff --git a/net/batman-adv/translation-table.h b/net/batman-adv/translation-table.h index 659a3bb759ce..dc6db4e00a43 100644 --- a/net/batman-adv/translation-table.h +++ b/net/batman-adv/translation-table.h | |||
@@ -20,49 +20,34 @@ | |||
20 | #ifndef _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ | 20 | #ifndef _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ |
21 | #define _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ | 21 | #define _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ |
22 | 22 | ||
23 | int batadv_tt_len(int changes_num); | ||
24 | int batadv_tt_init(struct batadv_priv *bat_priv); | 23 | int batadv_tt_init(struct batadv_priv *bat_priv); |
25 | void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr, | 24 | void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr, |
26 | int ifindex); | 25 | unsigned short vid, int ifindex); |
27 | uint16_t batadv_tt_local_remove(struct batadv_priv *bat_priv, | 26 | uint16_t batadv_tt_local_remove(struct batadv_priv *bat_priv, |
28 | const uint8_t *addr, const char *message, | 27 | const uint8_t *addr, unsigned short vid, |
29 | bool roaming); | 28 | const char *message, bool roaming); |
30 | int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset); | 29 | int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset); |
31 | void batadv_tt_global_add_orig(struct batadv_priv *bat_priv, | ||
32 | struct batadv_orig_node *orig_node, | ||
33 | const unsigned char *tt_buff, int tt_buff_len); | ||
34 | int batadv_tt_global_add(struct batadv_priv *bat_priv, | ||
35 | struct batadv_orig_node *orig_node, | ||
36 | const unsigned char *addr, uint16_t flags, | ||
37 | uint8_t ttvn); | ||
38 | int batadv_tt_global_seq_print_text(struct seq_file *seq, void *offset); | 30 | int batadv_tt_global_seq_print_text(struct seq_file *seq, void *offset); |
39 | void batadv_tt_global_del_orig(struct batadv_priv *bat_priv, | 31 | void batadv_tt_global_del_orig(struct batadv_priv *bat_priv, |
40 | struct batadv_orig_node *orig_node, | 32 | struct batadv_orig_node *orig_node, |
41 | const char *message); | 33 | int32_t match_vid, const char *message); |
42 | struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv, | 34 | struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv, |
43 | const uint8_t *src, | 35 | const uint8_t *src, |
44 | const uint8_t *addr); | 36 | const uint8_t *addr, |
37 | unsigned short vid); | ||
45 | void batadv_tt_free(struct batadv_priv *bat_priv); | 38 | void batadv_tt_free(struct batadv_priv *bat_priv); |
46 | bool batadv_send_tt_response(struct batadv_priv *bat_priv, | 39 | bool batadv_is_my_client(struct batadv_priv *bat_priv, const uint8_t *addr, |
47 | struct batadv_tt_query_packet *tt_request); | 40 | unsigned short vid); |
48 | bool batadv_is_my_client(struct batadv_priv *bat_priv, const uint8_t *addr); | ||
49 | void batadv_handle_tt_response(struct batadv_priv *bat_priv, | ||
50 | struct batadv_tt_query_packet *tt_response); | ||
51 | bool batadv_is_ap_isolated(struct batadv_priv *bat_priv, uint8_t *src, | 41 | bool batadv_is_ap_isolated(struct batadv_priv *bat_priv, uint8_t *src, |
52 | uint8_t *dst); | 42 | uint8_t *dst, unsigned short vid); |
53 | void batadv_tt_update_orig(struct batadv_priv *bat_priv, | 43 | void batadv_tt_local_commit_changes(struct batadv_priv *bat_priv); |
54 | struct batadv_orig_node *orig_node, | ||
55 | const unsigned char *tt_buff, uint8_t tt_num_changes, | ||
56 | uint8_t ttvn, uint16_t tt_crc); | ||
57 | int batadv_tt_append_diff(struct batadv_priv *bat_priv, | ||
58 | unsigned char **packet_buff, int *packet_buff_len, | ||
59 | int packet_min_len); | ||
60 | bool batadv_tt_global_client_is_roaming(struct batadv_priv *bat_priv, | 44 | bool batadv_tt_global_client_is_roaming(struct batadv_priv *bat_priv, |
61 | uint8_t *addr); | 45 | uint8_t *addr, unsigned short vid); |
62 | bool batadv_tt_local_client_is_roaming(struct batadv_priv *bat_priv, | 46 | bool batadv_tt_local_client_is_roaming(struct batadv_priv *bat_priv, |
63 | uint8_t *addr); | 47 | uint8_t *addr, unsigned short vid); |
64 | bool batadv_tt_add_temporary_global_entry(struct batadv_priv *bat_priv, | 48 | bool batadv_tt_add_temporary_global_entry(struct batadv_priv *bat_priv, |
65 | struct batadv_orig_node *orig_node, | 49 | struct batadv_orig_node *orig_node, |
66 | const unsigned char *addr); | 50 | const unsigned char *addr, |
51 | unsigned short vid); | ||
67 | 52 | ||
68 | #endif /* _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ */ | 53 | #endif /* _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ */ |
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index b2c94e139319..ff53933b5a59 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h | |||
@@ -24,13 +24,6 @@ | |||
24 | #include "bitarray.h" | 24 | #include "bitarray.h" |
25 | #include <linux/kernel.h> | 25 | #include <linux/kernel.h> |
26 | 26 | ||
27 | /** | ||
28 | * Maximum overhead for the encapsulation for a payload packet | ||
29 | */ | ||
30 | #define BATADV_HEADER_LEN \ | ||
31 | (ETH_HLEN + max(sizeof(struct batadv_unicast_packet), \ | ||
32 | sizeof(struct batadv_bcast_packet))) | ||
33 | |||
34 | #ifdef CONFIG_BATMAN_ADV_DAT | 27 | #ifdef CONFIG_BATMAN_ADV_DAT |
35 | 28 | ||
36 | /* batadv_dat_addr_t is the type used for all DHT addresses. If it is changed, | 29 | /* batadv_dat_addr_t is the type used for all DHT addresses. If it is changed, |
@@ -60,7 +53,6 @@ struct batadv_hard_iface_bat_iv { | |||
60 | * @if_num: identificator of the interface | 53 | * @if_num: identificator of the interface |
61 | * @if_status: status of the interface for batman-adv | 54 | * @if_status: status of the interface for batman-adv |
62 | * @net_dev: pointer to the net_device | 55 | * @net_dev: pointer to the net_device |
63 | * @frag_seqno: last fragment sequence number sent by this interface | ||
64 | * @num_bcasts: number of payload re-broadcasts on this interface (ARQ) | 56 | * @num_bcasts: number of payload re-broadcasts on this interface (ARQ) |
65 | * @hardif_obj: kobject of the per interface sysfs "mesh" directory | 57 | * @hardif_obj: kobject of the per interface sysfs "mesh" directory |
66 | * @refcount: number of contexts the object is used | 58 | * @refcount: number of contexts the object is used |
@@ -76,7 +68,6 @@ struct batadv_hard_iface { | |||
76 | int16_t if_num; | 68 | int16_t if_num; |
77 | char if_status; | 69 | char if_status; |
78 | struct net_device *net_dev; | 70 | struct net_device *net_dev; |
79 | atomic_t frag_seqno; | ||
80 | uint8_t num_bcasts; | 71 | uint8_t num_bcasts; |
81 | struct kobject *hardif_obj; | 72 | struct kobject *hardif_obj; |
82 | atomic_t refcount; | 73 | atomic_t refcount; |
@@ -88,6 +79,60 @@ struct batadv_hard_iface { | |||
88 | }; | 79 | }; |
89 | 80 | ||
90 | /** | 81 | /** |
82 | * struct batadv_frag_table_entry - head in the fragment buffer table | ||
83 | * @head: head of list with fragments | ||
84 | * @lock: lock to protect the list of fragments | ||
85 | * @timestamp: time (jiffie) of last received fragment | ||
86 | * @seqno: sequence number of the fragments in the list | ||
87 | * @size: accumulated size of packets in list | ||
88 | */ | ||
89 | struct batadv_frag_table_entry { | ||
90 | struct hlist_head head; | ||
91 | spinlock_t lock; /* protects head */ | ||
92 | unsigned long timestamp; | ||
93 | uint16_t seqno; | ||
94 | uint16_t size; | ||
95 | }; | ||
96 | |||
97 | /** | ||
98 | * struct batadv_frag_list_entry - entry in a list of fragments | ||
99 | * @list: list node information | ||
100 | * @skb: fragment | ||
101 | * @no: fragment number in the set | ||
102 | */ | ||
103 | struct batadv_frag_list_entry { | ||
104 | struct hlist_node list; | ||
105 | struct sk_buff *skb; | ||
106 | uint8_t no; | ||
107 | }; | ||
108 | |||
109 | /** | ||
110 | * struct batadv_vlan_tt - VLAN specific TT attributes | ||
111 | * @crc: CRC32 checksum of the entries belonging to this vlan | ||
112 | * @num_entries: number of TT entries for this VLAN | ||
113 | */ | ||
114 | struct batadv_vlan_tt { | ||
115 | uint32_t crc; | ||
116 | atomic_t num_entries; | ||
117 | }; | ||
118 | |||
119 | /** | ||
120 | * batadv_orig_node_vlan - VLAN specific data per orig_node | ||
121 | * @vid: the VLAN identifier | ||
122 | * @tt: VLAN specific TT attributes | ||
123 | * @list: list node for orig_node::vlan_list | ||
124 | * @refcount: number of context where this object is currently in use | ||
125 | * @rcu: struct used for freeing in a RCU-safe manner | ||
126 | */ | ||
127 | struct batadv_orig_node_vlan { | ||
128 | unsigned short vid; | ||
129 | struct batadv_vlan_tt tt; | ||
130 | struct list_head list; | ||
131 | atomic_t refcount; | ||
132 | struct rcu_head rcu; | ||
133 | }; | ||
134 | |||
135 | /** | ||
91 | * struct batadv_orig_node - structure for orig_list maintaining nodes of mesh | 136 | * struct batadv_orig_node - structure for orig_list maintaining nodes of mesh |
92 | * @orig: originator ethernet address | 137 | * @orig: originator ethernet address |
93 | * @primary_addr: hosts primary interface address | 138 | * @primary_addr: hosts primary interface address |
@@ -99,17 +144,18 @@ struct batadv_hard_iface { | |||
99 | * @last_seen: time when last packet from this node was received | 144 | * @last_seen: time when last packet from this node was received |
100 | * @bcast_seqno_reset: time when the broadcast seqno window was reset | 145 | * @bcast_seqno_reset: time when the broadcast seqno window was reset |
101 | * @batman_seqno_reset: time when the batman seqno window was reset | 146 | * @batman_seqno_reset: time when the batman seqno window was reset |
102 | * @gw_flags: flags related to gateway class | 147 | * @capabilities: announced capabilities of this originator |
103 | * @flags: for now only VIS_SERVER flag | ||
104 | * @last_ttvn: last seen translation table version number | 148 | * @last_ttvn: last seen translation table version number |
105 | * @tt_crc: CRC of the translation table | ||
106 | * @tt_buff: last tt changeset this node received from the orig node | 149 | * @tt_buff: last tt changeset this node received from the orig node |
107 | * @tt_buff_len: length of the last tt changeset this node received from the | 150 | * @tt_buff_len: length of the last tt changeset this node received from the |
108 | * orig node | 151 | * orig node |
109 | * @tt_buff_lock: lock that protects tt_buff and tt_buff_len | 152 | * @tt_buff_lock: lock that protects tt_buff and tt_buff_len |
110 | * @tt_size: number of global TT entries announced by the orig node | ||
111 | * @tt_initialised: bool keeping track of whether or not this node have received | 153 | * @tt_initialised: bool keeping track of whether or not this node have received |
112 | * any translation table information from the orig node yet | 154 | * any translation table information from the orig node yet |
155 | * @tt_lock: prevents from updating the table while reading it. Table update is | ||
156 | * made up by two operations (data structure update and metdata -CRC/TTVN- | ||
157 | * recalculation) and they have to be executed atomically in order to avoid | ||
158 | * another thread to read the table/metadata between those. | ||
113 | * @last_real_seqno: last and best known sequence number | 159 | * @last_real_seqno: last and best known sequence number |
114 | * @last_ttl: ttl of last received packet | 160 | * @last_ttl: ttl of last received packet |
115 | * @bcast_bits: bitfield containing the info which payload broadcast originated | 161 | * @bcast_bits: bitfield containing the info which payload broadcast originated |
@@ -117,9 +163,6 @@ struct batadv_hard_iface { | |||
117 | * last_bcast_seqno) | 163 | * last_bcast_seqno) |
118 | * @last_bcast_seqno: last broadcast sequence number received by this host | 164 | * @last_bcast_seqno: last broadcast sequence number received by this host |
119 | * @neigh_list: list of potential next hop neighbor towards this orig node | 165 | * @neigh_list: list of potential next hop neighbor towards this orig node |
120 | * @frag_list: fragmentation buffer list for fragment re-assembly | ||
121 | * @last_frag_packet: time when last fragmented packet from this node was | ||
122 | * received | ||
123 | * @neigh_list_lock: lock protecting neigh_list, router and bonding_list | 166 | * @neigh_list_lock: lock protecting neigh_list, router and bonding_list |
124 | * @hash_entry: hlist node for batadv_priv::orig_hash | 167 | * @hash_entry: hlist node for batadv_priv::orig_hash |
125 | * @bat_priv: pointer to soft_iface this orig node belongs to | 168 | * @bat_priv: pointer to soft_iface this orig node belongs to |
@@ -134,6 +177,10 @@ struct batadv_hard_iface { | |||
134 | * @out_coding_list: list of nodes that can hear this orig | 177 | * @out_coding_list: list of nodes that can hear this orig |
135 | * @in_coding_list_lock: protects in_coding_list | 178 | * @in_coding_list_lock: protects in_coding_list |
136 | * @out_coding_list_lock: protects out_coding_list | 179 | * @out_coding_list_lock: protects out_coding_list |
180 | * @fragments: array with heads for fragment chains | ||
181 | * @vlan_list: a list of orig_node_vlan structs, one per VLAN served by the | ||
182 | * originator represented by this object | ||
183 | * @vlan_list_lock: lock protecting vlan_list | ||
137 | */ | 184 | */ |
138 | struct batadv_orig_node { | 185 | struct batadv_orig_node { |
139 | uint8_t orig[ETH_ALEN]; | 186 | uint8_t orig[ETH_ALEN]; |
@@ -147,22 +194,19 @@ struct batadv_orig_node { | |||
147 | unsigned long last_seen; | 194 | unsigned long last_seen; |
148 | unsigned long bcast_seqno_reset; | 195 | unsigned long bcast_seqno_reset; |
149 | unsigned long batman_seqno_reset; | 196 | unsigned long batman_seqno_reset; |
150 | uint8_t gw_flags; | 197 | uint8_t capabilities; |
151 | uint8_t flags; | ||
152 | atomic_t last_ttvn; | 198 | atomic_t last_ttvn; |
153 | uint16_t tt_crc; | ||
154 | unsigned char *tt_buff; | 199 | unsigned char *tt_buff; |
155 | int16_t tt_buff_len; | 200 | int16_t tt_buff_len; |
156 | spinlock_t tt_buff_lock; /* protects tt_buff & tt_buff_len */ | 201 | spinlock_t tt_buff_lock; /* protects tt_buff & tt_buff_len */ |
157 | atomic_t tt_size; | ||
158 | bool tt_initialised; | 202 | bool tt_initialised; |
203 | /* prevents from changing the table while reading it */ | ||
204 | spinlock_t tt_lock; | ||
159 | uint32_t last_real_seqno; | 205 | uint32_t last_real_seqno; |
160 | uint8_t last_ttl; | 206 | uint8_t last_ttl; |
161 | DECLARE_BITMAP(bcast_bits, BATADV_TQ_LOCAL_WINDOW_SIZE); | 207 | DECLARE_BITMAP(bcast_bits, BATADV_TQ_LOCAL_WINDOW_SIZE); |
162 | uint32_t last_bcast_seqno; | 208 | uint32_t last_bcast_seqno; |
163 | struct hlist_head neigh_list; | 209 | struct hlist_head neigh_list; |
164 | struct list_head frag_list; | ||
165 | unsigned long last_frag_packet; | ||
166 | /* neigh_list_lock protects: neigh_list, router & bonding_list */ | 210 | /* neigh_list_lock protects: neigh_list, router & bonding_list */ |
167 | spinlock_t neigh_list_lock; | 211 | spinlock_t neigh_list_lock; |
168 | struct hlist_node hash_entry; | 212 | struct hlist_node hash_entry; |
@@ -183,12 +227,27 @@ struct batadv_orig_node { | |||
183 | spinlock_t in_coding_list_lock; /* Protects in_coding_list */ | 227 | spinlock_t in_coding_list_lock; /* Protects in_coding_list */ |
184 | spinlock_t out_coding_list_lock; /* Protects out_coding_list */ | 228 | spinlock_t out_coding_list_lock; /* Protects out_coding_list */ |
185 | #endif | 229 | #endif |
230 | struct batadv_frag_table_entry fragments[BATADV_FRAG_BUFFER_COUNT]; | ||
231 | struct list_head vlan_list; | ||
232 | spinlock_t vlan_list_lock; /* protects vlan_list */ | ||
233 | }; | ||
234 | |||
235 | /** | ||
236 | * enum batadv_orig_capabilities - orig node capabilities | ||
237 | * @BATADV_ORIG_CAPA_HAS_DAT: orig node has distributed arp table enabled | ||
238 | * @BATADV_ORIG_CAPA_HAS_NC: orig node has network coding enabled | ||
239 | */ | ||
240 | enum batadv_orig_capabilities { | ||
241 | BATADV_ORIG_CAPA_HAS_DAT = BIT(0), | ||
242 | BATADV_ORIG_CAPA_HAS_NC = BIT(1), | ||
186 | }; | 243 | }; |
187 | 244 | ||
188 | /** | 245 | /** |
189 | * struct batadv_gw_node - structure for orig nodes announcing gw capabilities | 246 | * struct batadv_gw_node - structure for orig nodes announcing gw capabilities |
190 | * @list: list node for batadv_priv_gw::list | 247 | * @list: list node for batadv_priv_gw::list |
191 | * @orig_node: pointer to corresponding orig node | 248 | * @orig_node: pointer to corresponding orig node |
249 | * @bandwidth_down: advertised uplink download bandwidth | ||
250 | * @bandwidth_up: advertised uplink upload bandwidth | ||
192 | * @deleted: this struct is scheduled for deletion | 251 | * @deleted: this struct is scheduled for deletion |
193 | * @refcount: number of contexts the object is used | 252 | * @refcount: number of contexts the object is used |
194 | * @rcu: struct used for freeing in an RCU-safe manner | 253 | * @rcu: struct used for freeing in an RCU-safe manner |
@@ -196,6 +255,8 @@ struct batadv_orig_node { | |||
196 | struct batadv_gw_node { | 255 | struct batadv_gw_node { |
197 | struct hlist_node list; | 256 | struct hlist_node list; |
198 | struct batadv_orig_node *orig_node; | 257 | struct batadv_orig_node *orig_node; |
258 | uint32_t bandwidth_down; | ||
259 | uint32_t bandwidth_up; | ||
199 | unsigned long deleted; | 260 | unsigned long deleted; |
200 | atomic_t refcount; | 261 | atomic_t refcount; |
201 | struct rcu_head rcu; | 262 | struct rcu_head rcu; |
@@ -265,6 +326,12 @@ struct batadv_bcast_duplist_entry { | |||
265 | * @BATADV_CNT_MGMT_TX_BYTES: transmitted routing protocol traffic bytes counter | 326 | * @BATADV_CNT_MGMT_TX_BYTES: transmitted routing protocol traffic bytes counter |
266 | * @BATADV_CNT_MGMT_RX: received routing protocol traffic packet counter | 327 | * @BATADV_CNT_MGMT_RX: received routing protocol traffic packet counter |
267 | * @BATADV_CNT_MGMT_RX_BYTES: received routing protocol traffic bytes counter | 328 | * @BATADV_CNT_MGMT_RX_BYTES: received routing protocol traffic bytes counter |
329 | * @BATADV_CNT_FRAG_TX: transmitted fragment traffic packet counter | ||
330 | * @BATADV_CNT_FRAG_TX_BYTES: transmitted fragment traffic bytes counter | ||
331 | * @BATADV_CNT_FRAG_RX: received fragment traffic packet counter | ||
332 | * @BATADV_CNT_FRAG_RX_BYTES: received fragment traffic bytes counter | ||
333 | * @BATADV_CNT_FRAG_FWD: forwarded fragment traffic packet counter | ||
334 | * @BATADV_CNT_FRAG_FWD_BYTES: forwarded fragment traffic bytes counter | ||
268 | * @BATADV_CNT_TT_REQUEST_TX: transmitted tt req traffic packet counter | 335 | * @BATADV_CNT_TT_REQUEST_TX: transmitted tt req traffic packet counter |
269 | * @BATADV_CNT_TT_REQUEST_RX: received tt req traffic packet counter | 336 | * @BATADV_CNT_TT_REQUEST_RX: received tt req traffic packet counter |
270 | * @BATADV_CNT_TT_RESPONSE_TX: transmitted tt resp traffic packet counter | 337 | * @BATADV_CNT_TT_RESPONSE_TX: transmitted tt resp traffic packet counter |
@@ -302,6 +369,12 @@ enum batadv_counters { | |||
302 | BATADV_CNT_MGMT_TX_BYTES, | 369 | BATADV_CNT_MGMT_TX_BYTES, |
303 | BATADV_CNT_MGMT_RX, | 370 | BATADV_CNT_MGMT_RX, |
304 | BATADV_CNT_MGMT_RX_BYTES, | 371 | BATADV_CNT_MGMT_RX_BYTES, |
372 | BATADV_CNT_FRAG_TX, | ||
373 | BATADV_CNT_FRAG_TX_BYTES, | ||
374 | BATADV_CNT_FRAG_RX, | ||
375 | BATADV_CNT_FRAG_RX_BYTES, | ||
376 | BATADV_CNT_FRAG_FWD, | ||
377 | BATADV_CNT_FRAG_FWD_BYTES, | ||
305 | BATADV_CNT_TT_REQUEST_TX, | 378 | BATADV_CNT_TT_REQUEST_TX, |
306 | BATADV_CNT_TT_REQUEST_RX, | 379 | BATADV_CNT_TT_REQUEST_RX, |
307 | BATADV_CNT_TT_RESPONSE_TX, | 380 | BATADV_CNT_TT_RESPONSE_TX, |
@@ -343,11 +416,14 @@ enum batadv_counters { | |||
343 | * @changes_list_lock: lock protecting changes_list | 416 | * @changes_list_lock: lock protecting changes_list |
344 | * @req_list_lock: lock protecting req_list | 417 | * @req_list_lock: lock protecting req_list |
345 | * @roam_list_lock: lock protecting roam_list | 418 | * @roam_list_lock: lock protecting roam_list |
346 | * @local_entry_num: number of entries in the local hash table | ||
347 | * @local_crc: Checksum of the local table, recomputed before sending a new OGM | ||
348 | * @last_changeset: last tt changeset this host has generated | 419 | * @last_changeset: last tt changeset this host has generated |
349 | * @last_changeset_len: length of last tt changeset this host has generated | 420 | * @last_changeset_len: length of last tt changeset this host has generated |
350 | * @last_changeset_lock: lock protecting last_changeset & last_changeset_len | 421 | * @last_changeset_lock: lock protecting last_changeset & last_changeset_len |
422 | * @commit_lock: prevents from executing a local TT commit while reading the | ||
423 | * local table. The local TT commit is made up by two operations (data | ||
424 | * structure update and metdata -CRC/TTVN- recalculation) and they have to be | ||
425 | * executed atomically in order to avoid another thread to read the | ||
426 | * table/metadata between those. | ||
351 | * @work: work queue callback item for translation table purging | 427 | * @work: work queue callback item for translation table purging |
352 | */ | 428 | */ |
353 | struct batadv_priv_tt { | 429 | struct batadv_priv_tt { |
@@ -362,12 +438,12 @@ struct batadv_priv_tt { | |||
362 | spinlock_t changes_list_lock; /* protects changes */ | 438 | spinlock_t changes_list_lock; /* protects changes */ |
363 | spinlock_t req_list_lock; /* protects req_list */ | 439 | spinlock_t req_list_lock; /* protects req_list */ |
364 | spinlock_t roam_list_lock; /* protects roam_list */ | 440 | spinlock_t roam_list_lock; /* protects roam_list */ |
365 | atomic_t local_entry_num; | ||
366 | uint16_t local_crc; | ||
367 | unsigned char *last_changeset; | 441 | unsigned char *last_changeset; |
368 | int16_t last_changeset_len; | 442 | int16_t last_changeset_len; |
369 | /* protects last_changeset & last_changeset_len */ | 443 | /* protects last_changeset & last_changeset_len */ |
370 | spinlock_t last_changeset_lock; | 444 | spinlock_t last_changeset_lock; |
445 | /* prevents from executing a commit while reading the table */ | ||
446 | spinlock_t commit_lock; | ||
371 | struct delayed_work work; | 447 | struct delayed_work work; |
372 | }; | 448 | }; |
373 | 449 | ||
@@ -420,31 +496,31 @@ struct batadv_priv_debug_log { | |||
420 | * @list: list of available gateway nodes | 496 | * @list: list of available gateway nodes |
421 | * @list_lock: lock protecting gw_list & curr_gw | 497 | * @list_lock: lock protecting gw_list & curr_gw |
422 | * @curr_gw: pointer to currently selected gateway node | 498 | * @curr_gw: pointer to currently selected gateway node |
499 | * @bandwidth_down: advertised uplink download bandwidth (if gw_mode server) | ||
500 | * @bandwidth_up: advertised uplink upload bandwidth (if gw_mode server) | ||
423 | * @reselect: bool indicating a gateway re-selection is in progress | 501 | * @reselect: bool indicating a gateway re-selection is in progress |
424 | */ | 502 | */ |
425 | struct batadv_priv_gw { | 503 | struct batadv_priv_gw { |
426 | struct hlist_head list; | 504 | struct hlist_head list; |
427 | spinlock_t list_lock; /* protects gw_list & curr_gw */ | 505 | spinlock_t list_lock; /* protects gw_list & curr_gw */ |
428 | struct batadv_gw_node __rcu *curr_gw; /* rcu protected pointer */ | 506 | struct batadv_gw_node __rcu *curr_gw; /* rcu protected pointer */ |
507 | atomic_t bandwidth_down; | ||
508 | atomic_t bandwidth_up; | ||
429 | atomic_t reselect; | 509 | atomic_t reselect; |
430 | }; | 510 | }; |
431 | 511 | ||
432 | /** | 512 | /** |
433 | * struct batadv_priv_vis - per mesh interface vis data | 513 | * struct batadv_priv_tvlv - per mesh interface tvlv data |
434 | * @send_list: list of batadv_vis_info packets to sent | 514 | * @container_list: list of registered tvlv containers to be sent with each OGM |
435 | * @hash: hash table containing vis data from other nodes in the network | 515 | * @handler_list: list of the various tvlv content handlers |
436 | * @hash_lock: lock protecting the hash table | 516 | * @container_list_lock: protects tvlv container list access |
437 | * @list_lock: lock protecting my_info::recv_list | 517 | * @handler_list_lock: protects handler list access |
438 | * @work: work queue callback item for vis packet sending | ||
439 | * @my_info: holds this node's vis data sent on a regular basis | ||
440 | */ | 518 | */ |
441 | struct batadv_priv_vis { | 519 | struct batadv_priv_tvlv { |
442 | struct list_head send_list; | 520 | struct hlist_head container_list; |
443 | struct batadv_hashtable *hash; | 521 | struct hlist_head handler_list; |
444 | spinlock_t hash_lock; /* protects hash */ | 522 | spinlock_t container_list_lock; /* protects container_list */ |
445 | spinlock_t list_lock; /* protects my_info::recv_list */ | 523 | spinlock_t handler_list_lock; /* protects handler_list */ |
446 | struct delayed_work work; | ||
447 | struct batadv_vis_info *my_info; | ||
448 | }; | 524 | }; |
449 | 525 | ||
450 | /** | 526 | /** |
@@ -491,6 +567,26 @@ struct batadv_priv_nc { | |||
491 | }; | 567 | }; |
492 | 568 | ||
493 | /** | 569 | /** |
570 | * struct batadv_softif_vlan - per VLAN attributes set | ||
571 | * @vid: VLAN identifier | ||
572 | * @kobj: kobject for sysfs vlan subdirectory | ||
573 | * @ap_isolation: AP isolation state | ||
574 | * @tt: TT private attributes (VLAN specific) | ||
575 | * @list: list node for bat_priv::softif_vlan_list | ||
576 | * @refcount: number of context where this object is currently in use | ||
577 | * @rcu: struct used for freeing in a RCU-safe manner | ||
578 | */ | ||
579 | struct batadv_softif_vlan { | ||
580 | unsigned short vid; | ||
581 | struct kobject *kobj; | ||
582 | atomic_t ap_isolation; /* boolean */ | ||
583 | struct batadv_vlan_tt tt; | ||
584 | struct hlist_node list; | ||
585 | atomic_t refcount; | ||
586 | struct rcu_head rcu; | ||
587 | }; | ||
588 | |||
589 | /** | ||
494 | * struct batadv_priv - per mesh interface data | 590 | * struct batadv_priv - per mesh interface data |
495 | * @mesh_state: current status of the mesh (inactive/active/deactivating) | 591 | * @mesh_state: current status of the mesh (inactive/active/deactivating) |
496 | * @soft_iface: net device which holds this struct as private data | 592 | * @soft_iface: net device which holds this struct as private data |
@@ -499,15 +595,13 @@ struct batadv_priv_nc { | |||
499 | * @aggregated_ogms: bool indicating whether OGM aggregation is enabled | 595 | * @aggregated_ogms: bool indicating whether OGM aggregation is enabled |
500 | * @bonding: bool indicating whether traffic bonding is enabled | 596 | * @bonding: bool indicating whether traffic bonding is enabled |
501 | * @fragmentation: bool indicating whether traffic fragmentation is enabled | 597 | * @fragmentation: bool indicating whether traffic fragmentation is enabled |
502 | * @ap_isolation: bool indicating whether ap isolation is enabled | 598 | * @frag_seqno: incremental counter to identify chains of egress fragments |
503 | * @bridge_loop_avoidance: bool indicating whether bridge loop avoidance is | 599 | * @bridge_loop_avoidance: bool indicating whether bridge loop avoidance is |
504 | * enabled | 600 | * enabled |
505 | * @distributed_arp_table: bool indicating whether distributed ARP table is | 601 | * @distributed_arp_table: bool indicating whether distributed ARP table is |
506 | * enabled | 602 | * enabled |
507 | * @vis_mode: vis operation: client or server (see batadv_vis_packettype) | ||
508 | * @gw_mode: gateway operation: off, client or server (see batadv_gw_modes) | 603 | * @gw_mode: gateway operation: off, client or server (see batadv_gw_modes) |
509 | * @gw_sel_class: gateway selection class (applies if gw_mode client) | 604 | * @gw_sel_class: gateway selection class (applies if gw_mode client) |
510 | * @gw_bandwidth: gateway announced bandwidth (applies if gw_mode server) | ||
511 | * @orig_interval: OGM broadcast interval in milliseconds | 605 | * @orig_interval: OGM broadcast interval in milliseconds |
512 | * @hop_penalty: penalty which will be applied to an OGM's tq-field on every hop | 606 | * @hop_penalty: penalty which will be applied to an OGM's tq-field on every hop |
513 | * @log_level: configured log level (see batadv_dbg_level) | 607 | * @log_level: configured log level (see batadv_dbg_level) |
@@ -527,11 +621,14 @@ struct batadv_priv_nc { | |||
527 | * @primary_if: one of the hard interfaces assigned to this mesh interface | 621 | * @primary_if: one of the hard interfaces assigned to this mesh interface |
528 | * becomes the primary interface | 622 | * becomes the primary interface |
529 | * @bat_algo_ops: routing algorithm used by this mesh interface | 623 | * @bat_algo_ops: routing algorithm used by this mesh interface |
624 | * @softif_vlan_list: a list of softif_vlan structs, one per VLAN created on top | ||
625 | * of the mesh interface represented by this object | ||
626 | * @softif_vlan_list_lock: lock protecting softif_vlan_list | ||
530 | * @bla: bridge loope avoidance data | 627 | * @bla: bridge loope avoidance data |
531 | * @debug_log: holding debug logging relevant data | 628 | * @debug_log: holding debug logging relevant data |
532 | * @gw: gateway data | 629 | * @gw: gateway data |
533 | * @tt: translation table data | 630 | * @tt: translation table data |
534 | * @vis: vis data | 631 | * @tvlv: type-version-length-value data |
535 | * @dat: distributed arp table data | 632 | * @dat: distributed arp table data |
536 | * @network_coding: bool indicating whether network coding is enabled | 633 | * @network_coding: bool indicating whether network coding is enabled |
537 | * @batadv_priv_nc: network coding data | 634 | * @batadv_priv_nc: network coding data |
@@ -544,17 +641,15 @@ struct batadv_priv { | |||
544 | atomic_t aggregated_ogms; | 641 | atomic_t aggregated_ogms; |
545 | atomic_t bonding; | 642 | atomic_t bonding; |
546 | atomic_t fragmentation; | 643 | atomic_t fragmentation; |
547 | atomic_t ap_isolation; | 644 | atomic_t frag_seqno; |
548 | #ifdef CONFIG_BATMAN_ADV_BLA | 645 | #ifdef CONFIG_BATMAN_ADV_BLA |
549 | atomic_t bridge_loop_avoidance; | 646 | atomic_t bridge_loop_avoidance; |
550 | #endif | 647 | #endif |
551 | #ifdef CONFIG_BATMAN_ADV_DAT | 648 | #ifdef CONFIG_BATMAN_ADV_DAT |
552 | atomic_t distributed_arp_table; | 649 | atomic_t distributed_arp_table; |
553 | #endif | 650 | #endif |
554 | atomic_t vis_mode; | ||
555 | atomic_t gw_mode; | 651 | atomic_t gw_mode; |
556 | atomic_t gw_sel_class; | 652 | atomic_t gw_sel_class; |
557 | atomic_t gw_bandwidth; | ||
558 | atomic_t orig_interval; | 653 | atomic_t orig_interval; |
559 | atomic_t hop_penalty; | 654 | atomic_t hop_penalty; |
560 | #ifdef CONFIG_BATMAN_ADV_DEBUG | 655 | #ifdef CONFIG_BATMAN_ADV_DEBUG |
@@ -575,6 +670,8 @@ struct batadv_priv { | |||
575 | struct work_struct cleanup_work; | 670 | struct work_struct cleanup_work; |
576 | struct batadv_hard_iface __rcu *primary_if; /* rcu protected pointer */ | 671 | struct batadv_hard_iface __rcu *primary_if; /* rcu protected pointer */ |
577 | struct batadv_algo_ops *bat_algo_ops; | 672 | struct batadv_algo_ops *bat_algo_ops; |
673 | struct hlist_head softif_vlan_list; | ||
674 | spinlock_t softif_vlan_list_lock; /* protects softif_vlan_list */ | ||
578 | #ifdef CONFIG_BATMAN_ADV_BLA | 675 | #ifdef CONFIG_BATMAN_ADV_BLA |
579 | struct batadv_priv_bla bla; | 676 | struct batadv_priv_bla bla; |
580 | #endif | 677 | #endif |
@@ -583,7 +680,7 @@ struct batadv_priv { | |||
583 | #endif | 680 | #endif |
584 | struct batadv_priv_gw gw; | 681 | struct batadv_priv_gw gw; |
585 | struct batadv_priv_tt tt; | 682 | struct batadv_priv_tt tt; |
586 | struct batadv_priv_vis vis; | 683 | struct batadv_priv_tvlv tvlv; |
587 | #ifdef CONFIG_BATMAN_ADV_DAT | 684 | #ifdef CONFIG_BATMAN_ADV_DAT |
588 | struct batadv_priv_dat dat; | 685 | struct batadv_priv_dat dat; |
589 | #endif | 686 | #endif |
@@ -677,6 +774,7 @@ struct batadv_bla_claim { | |||
677 | /** | 774 | /** |
678 | * struct batadv_tt_common_entry - tt local & tt global common data | 775 | * struct batadv_tt_common_entry - tt local & tt global common data |
679 | * @addr: mac address of non-mesh client | 776 | * @addr: mac address of non-mesh client |
777 | * @vid: VLAN identifier | ||
680 | * @hash_entry: hlist node for batadv_priv_tt::local_hash or for | 778 | * @hash_entry: hlist node for batadv_priv_tt::local_hash or for |
681 | * batadv_priv_tt::global_hash | 779 | * batadv_priv_tt::global_hash |
682 | * @flags: various state handling flags (see batadv_tt_client_flags) | 780 | * @flags: various state handling flags (see batadv_tt_client_flags) |
@@ -686,6 +784,7 @@ struct batadv_bla_claim { | |||
686 | */ | 784 | */ |
687 | struct batadv_tt_common_entry { | 785 | struct batadv_tt_common_entry { |
688 | uint8_t addr[ETH_ALEN]; | 786 | uint8_t addr[ETH_ALEN]; |
787 | unsigned short vid; | ||
689 | struct hlist_node hash_entry; | 788 | struct hlist_node hash_entry; |
690 | uint16_t flags; | 789 | uint16_t flags; |
691 | unsigned long added_at; | 790 | unsigned long added_at; |
@@ -740,7 +839,7 @@ struct batadv_tt_orig_list_entry { | |||
740 | */ | 839 | */ |
741 | struct batadv_tt_change_node { | 840 | struct batadv_tt_change_node { |
742 | struct list_head list; | 841 | struct list_head list; |
743 | struct batadv_tt_change change; | 842 | struct batadv_tvlv_tt_change change; |
744 | }; | 843 | }; |
745 | 844 | ||
746 | /** | 845 | /** |
@@ -866,78 +965,6 @@ struct batadv_forw_packet { | |||
866 | }; | 965 | }; |
867 | 966 | ||
868 | /** | 967 | /** |
869 | * struct batadv_frag_packet_list_entry - storage for fragment packet | ||
870 | * @list: list node for orig_node::frag_list | ||
871 | * @seqno: sequence number of the fragment | ||
872 | * @skb: fragment's skb buffer | ||
873 | */ | ||
874 | struct batadv_frag_packet_list_entry { | ||
875 | struct list_head list; | ||
876 | uint16_t seqno; | ||
877 | struct sk_buff *skb; | ||
878 | }; | ||
879 | |||
880 | /** | ||
881 | * struct batadv_vis_info - local data for vis information | ||
882 | * @first_seen: timestamp used for purging stale vis info entries | ||
883 | * @recv_list: List of server-neighbors we have received this packet from. This | ||
884 | * packet should not be re-forward to them again. List elements are struct | ||
885 | * batadv_vis_recvlist_node | ||
886 | * @send_list: list of packets to be forwarded | ||
887 | * @refcount: number of contexts the object is used | ||
888 | * @hash_entry: hlist node for batadv_priv_vis::hash | ||
889 | * @bat_priv: pointer to soft_iface this orig node belongs to | ||
890 | * @skb_packet: contains the vis packet | ||
891 | */ | ||
892 | struct batadv_vis_info { | ||
893 | unsigned long first_seen; | ||
894 | struct list_head recv_list; | ||
895 | struct list_head send_list; | ||
896 | struct kref refcount; | ||
897 | struct hlist_node hash_entry; | ||
898 | struct batadv_priv *bat_priv; | ||
899 | struct sk_buff *skb_packet; | ||
900 | } __packed; | ||
901 | |||
902 | /** | ||
903 | * struct batadv_vis_info_entry - contains link information for vis | ||
904 | * @src: source MAC of the link, all zero for local TT entry | ||
905 | * @dst: destination MAC of the link, client mac address for local TT entry | ||
906 | * @quality: transmission quality of the link, or 0 for local TT entry | ||
907 | */ | ||
908 | struct batadv_vis_info_entry { | ||
909 | uint8_t src[ETH_ALEN]; | ||
910 | uint8_t dest[ETH_ALEN]; | ||
911 | uint8_t quality; | ||
912 | } __packed; | ||
913 | |||
914 | /** | ||
915 | * struct batadv_vis_recvlist_node - list entry for batadv_vis_info::recv_list | ||
916 | * @list: list node for batadv_vis_info::recv_list | ||
917 | * @mac: MAC address of the originator from where the vis_info was received | ||
918 | */ | ||
919 | struct batadv_vis_recvlist_node { | ||
920 | struct list_head list; | ||
921 | uint8_t mac[ETH_ALEN]; | ||
922 | }; | ||
923 | |||
924 | /** | ||
925 | * struct batadv_vis_if_list_entry - auxiliary data for vis data generation | ||
926 | * @addr: MAC address of the interface | ||
927 | * @primary: true if this interface is the primary interface | ||
928 | * @list: list node the interface list | ||
929 | * | ||
930 | * While scanning for vis-entries of a particular vis-originator | ||
931 | * this list collects its interfaces to create a subgraph/cluster | ||
932 | * out of them later | ||
933 | */ | ||
934 | struct batadv_vis_if_list_entry { | ||
935 | uint8_t addr[ETH_ALEN]; | ||
936 | bool primary; | ||
937 | struct hlist_node list; | ||
938 | }; | ||
939 | |||
940 | /** | ||
941 | * struct batadv_algo_ops - mesh algorithm callbacks | 968 | * struct batadv_algo_ops - mesh algorithm callbacks |
942 | * @list: list node for the batadv_algo_list | 969 | * @list: list node for the batadv_algo_list |
943 | * @name: name of the algorithm | 970 | * @name: name of the algorithm |
@@ -965,6 +992,7 @@ struct batadv_algo_ops { | |||
965 | * is used to stored ARP entries needed for the global DAT cache | 992 | * is used to stored ARP entries needed for the global DAT cache |
966 | * @ip: the IPv4 corresponding to this DAT/ARP entry | 993 | * @ip: the IPv4 corresponding to this DAT/ARP entry |
967 | * @mac_addr: the MAC address associated to the stored IPv4 | 994 | * @mac_addr: the MAC address associated to the stored IPv4 |
995 | * @vid: the vlan ID associated to this entry | ||
968 | * @last_update: time in jiffies when this entry was refreshed last time | 996 | * @last_update: time in jiffies when this entry was refreshed last time |
969 | * @hash_entry: hlist node for batadv_priv_dat::hash | 997 | * @hash_entry: hlist node for batadv_priv_dat::hash |
970 | * @refcount: number of contexts the object is used | 998 | * @refcount: number of contexts the object is used |
@@ -973,6 +1001,7 @@ struct batadv_algo_ops { | |||
973 | struct batadv_dat_entry { | 1001 | struct batadv_dat_entry { |
974 | __be32 ip; | 1002 | __be32 ip; |
975 | uint8_t mac_addr[ETH_ALEN]; | 1003 | uint8_t mac_addr[ETH_ALEN]; |
1004 | unsigned short vid; | ||
976 | unsigned long last_update; | 1005 | unsigned long last_update; |
977 | struct hlist_node hash_entry; | 1006 | struct hlist_node hash_entry; |
978 | atomic_t refcount; | 1007 | atomic_t refcount; |
@@ -992,4 +1021,60 @@ struct batadv_dat_candidate { | |||
992 | struct batadv_orig_node *orig_node; | 1021 | struct batadv_orig_node *orig_node; |
993 | }; | 1022 | }; |
994 | 1023 | ||
1024 | /** | ||
1025 | * struct batadv_tvlv_container - container for tvlv appended to OGMs | ||
1026 | * @list: hlist node for batadv_priv_tvlv::container_list | ||
1027 | * @tvlv_hdr: tvlv header information needed to construct the tvlv | ||
1028 | * @value_len: length of the buffer following this struct which contains | ||
1029 | * the actual tvlv payload | ||
1030 | * @refcount: number of contexts the object is used | ||
1031 | */ | ||
1032 | struct batadv_tvlv_container { | ||
1033 | struct hlist_node list; | ||
1034 | struct batadv_tvlv_hdr tvlv_hdr; | ||
1035 | atomic_t refcount; | ||
1036 | }; | ||
1037 | |||
1038 | /** | ||
1039 | * struct batadv_tvlv_handler - handler for specific tvlv type and version | ||
1040 | * @list: hlist node for batadv_priv_tvlv::handler_list | ||
1041 | * @ogm_handler: handler callback which is given the tvlv payload to process on | ||
1042 | * incoming OGM packets | ||
1043 | * @unicast_handler: handler callback which is given the tvlv payload to process | ||
1044 | * on incoming unicast tvlv packets | ||
1045 | * @type: tvlv type this handler feels responsible for | ||
1046 | * @version: tvlv version this handler feels responsible for | ||
1047 | * @flags: tvlv handler flags | ||
1048 | * @refcount: number of contexts the object is used | ||
1049 | * @rcu: struct used for freeing in an RCU-safe manner | ||
1050 | */ | ||
1051 | struct batadv_tvlv_handler { | ||
1052 | struct hlist_node list; | ||
1053 | void (*ogm_handler)(struct batadv_priv *bat_priv, | ||
1054 | struct batadv_orig_node *orig, | ||
1055 | uint8_t flags, | ||
1056 | void *tvlv_value, uint16_t tvlv_value_len); | ||
1057 | int (*unicast_handler)(struct batadv_priv *bat_priv, | ||
1058 | uint8_t *src, uint8_t *dst, | ||
1059 | void *tvlv_value, uint16_t tvlv_value_len); | ||
1060 | uint8_t type; | ||
1061 | uint8_t version; | ||
1062 | uint8_t flags; | ||
1063 | atomic_t refcount; | ||
1064 | struct rcu_head rcu; | ||
1065 | }; | ||
1066 | |||
1067 | /** | ||
1068 | * enum batadv_tvlv_handler_flags - tvlv handler flags definitions | ||
1069 | * @BATADV_TVLV_HANDLER_OGM_CIFNOTFND: tvlv ogm processing function will call | ||
1070 | * this handler even if its type was not found (with no data) | ||
1071 | * @BATADV_TVLV_HANDLER_OGM_CALLED: interval tvlv handling flag - the API marks | ||
1072 | * a handler as being called, so it won't be called if the | ||
1073 | * BATADV_TVLV_HANDLER_OGM_CIFNOTFND flag was set | ||
1074 | */ | ||
1075 | enum batadv_tvlv_handler_flags { | ||
1076 | BATADV_TVLV_HANDLER_OGM_CIFNOTFND = BIT(1), | ||
1077 | BATADV_TVLV_HANDLER_OGM_CALLED = BIT(2), | ||
1078 | }; | ||
1079 | |||
995 | #endif /* _NET_BATMAN_ADV_TYPES_H_ */ | 1080 | #endif /* _NET_BATMAN_ADV_TYPES_H_ */ |
diff --git a/net/batman-adv/unicast.c b/net/batman-adv/unicast.c deleted file mode 100644 index 48b31d33ce6b..000000000000 --- a/net/batman-adv/unicast.c +++ /dev/null | |||
@@ -1,491 +0,0 @@ | |||
1 | /* Copyright (C) 2010-2013 B.A.T.M.A.N. contributors: | ||
2 | * | ||
3 | * Andreas Langer | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of version 2 of the GNU General Public | ||
7 | * License as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, but | ||
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | * General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
17 | * 02110-1301, USA | ||
18 | */ | ||
19 | |||
20 | #include "main.h" | ||
21 | #include "unicast.h" | ||
22 | #include "send.h" | ||
23 | #include "soft-interface.h" | ||
24 | #include "gateway_client.h" | ||
25 | #include "originator.h" | ||
26 | #include "hash.h" | ||
27 | #include "translation-table.h" | ||
28 | #include "routing.h" | ||
29 | #include "hard-interface.h" | ||
30 | |||
31 | |||
32 | static struct sk_buff * | ||
33 | batadv_frag_merge_packet(struct list_head *head, | ||
34 | struct batadv_frag_packet_list_entry *tfp, | ||
35 | struct sk_buff *skb) | ||
36 | { | ||
37 | struct batadv_unicast_frag_packet *up; | ||
38 | struct sk_buff *tmp_skb; | ||
39 | struct batadv_unicast_packet *unicast_packet; | ||
40 | int hdr_len = sizeof(*unicast_packet); | ||
41 | int uni_diff = sizeof(*up) - hdr_len; | ||
42 | uint8_t *packet_pos; | ||
43 | |||
44 | up = (struct batadv_unicast_frag_packet *)skb->data; | ||
45 | /* set skb to the first part and tmp_skb to the second part */ | ||
46 | if (up->flags & BATADV_UNI_FRAG_HEAD) { | ||
47 | tmp_skb = tfp->skb; | ||
48 | } else { | ||
49 | tmp_skb = skb; | ||
50 | skb = tfp->skb; | ||
51 | } | ||
52 | |||
53 | if (skb_linearize(skb) < 0 || skb_linearize(tmp_skb) < 0) | ||
54 | goto err; | ||
55 | |||
56 | skb_pull(tmp_skb, sizeof(*up)); | ||
57 | if (pskb_expand_head(skb, 0, tmp_skb->len, GFP_ATOMIC) < 0) | ||
58 | goto err; | ||
59 | |||
60 | /* move free entry to end */ | ||
61 | tfp->skb = NULL; | ||
62 | tfp->seqno = 0; | ||
63 | list_move_tail(&tfp->list, head); | ||
64 | |||
65 | memcpy(skb_put(skb, tmp_skb->len), tmp_skb->data, tmp_skb->len); | ||
66 | kfree_skb(tmp_skb); | ||
67 | |||
68 | memmove(skb->data + uni_diff, skb->data, hdr_len); | ||
69 | packet_pos = skb_pull(skb, uni_diff); | ||
70 | unicast_packet = (struct batadv_unicast_packet *)packet_pos; | ||
71 | unicast_packet->header.packet_type = BATADV_UNICAST; | ||
72 | |||
73 | return skb; | ||
74 | |||
75 | err: | ||
76 | /* free buffered skb, skb will be freed later */ | ||
77 | kfree_skb(tfp->skb); | ||
78 | return NULL; | ||
79 | } | ||
80 | |||
81 | static void batadv_frag_create_entry(struct list_head *head, | ||
82 | struct sk_buff *skb) | ||
83 | { | ||
84 | struct batadv_frag_packet_list_entry *tfp; | ||
85 | struct batadv_unicast_frag_packet *up; | ||
86 | |||
87 | up = (struct batadv_unicast_frag_packet *)skb->data; | ||
88 | |||
89 | /* free and oldest packets stand at the end */ | ||
90 | tfp = list_entry((head)->prev, typeof(*tfp), list); | ||
91 | kfree_skb(tfp->skb); | ||
92 | |||
93 | tfp->seqno = ntohs(up->seqno); | ||
94 | tfp->skb = skb; | ||
95 | list_move(&tfp->list, head); | ||
96 | return; | ||
97 | } | ||
98 | |||
99 | static int batadv_frag_create_buffer(struct list_head *head) | ||
100 | { | ||
101 | int i; | ||
102 | struct batadv_frag_packet_list_entry *tfp; | ||
103 | |||
104 | for (i = 0; i < BATADV_FRAG_BUFFER_SIZE; i++) { | ||
105 | tfp = kmalloc(sizeof(*tfp), GFP_ATOMIC); | ||
106 | if (!tfp) { | ||
107 | batadv_frag_list_free(head); | ||
108 | return -ENOMEM; | ||
109 | } | ||
110 | tfp->skb = NULL; | ||
111 | tfp->seqno = 0; | ||
112 | INIT_LIST_HEAD(&tfp->list); | ||
113 | list_add(&tfp->list, head); | ||
114 | } | ||
115 | |||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | static struct batadv_frag_packet_list_entry * | ||
120 | batadv_frag_search_packet(struct list_head *head, | ||
121 | const struct batadv_unicast_frag_packet *up) | ||
122 | { | ||
123 | struct batadv_frag_packet_list_entry *tfp; | ||
124 | struct batadv_unicast_frag_packet *tmp_up = NULL; | ||
125 | bool is_head_tmp, is_head; | ||
126 | uint16_t search_seqno; | ||
127 | |||
128 | if (up->flags & BATADV_UNI_FRAG_HEAD) | ||
129 | search_seqno = ntohs(up->seqno)+1; | ||
130 | else | ||
131 | search_seqno = ntohs(up->seqno)-1; | ||
132 | |||
133 | is_head = up->flags & BATADV_UNI_FRAG_HEAD; | ||
134 | |||
135 | list_for_each_entry(tfp, head, list) { | ||
136 | if (!tfp->skb) | ||
137 | continue; | ||
138 | |||
139 | if (tfp->seqno == ntohs(up->seqno)) | ||
140 | goto mov_tail; | ||
141 | |||
142 | tmp_up = (struct batadv_unicast_frag_packet *)tfp->skb->data; | ||
143 | |||
144 | if (tfp->seqno == search_seqno) { | ||
145 | is_head_tmp = tmp_up->flags & BATADV_UNI_FRAG_HEAD; | ||
146 | if (is_head_tmp != is_head) | ||
147 | return tfp; | ||
148 | else | ||
149 | goto mov_tail; | ||
150 | } | ||
151 | } | ||
152 | return NULL; | ||
153 | |||
154 | mov_tail: | ||
155 | list_move_tail(&tfp->list, head); | ||
156 | return NULL; | ||
157 | } | ||
158 | |||
159 | void batadv_frag_list_free(struct list_head *head) | ||
160 | { | ||
161 | struct batadv_frag_packet_list_entry *pf, *tmp_pf; | ||
162 | |||
163 | if (!list_empty(head)) { | ||
164 | list_for_each_entry_safe(pf, tmp_pf, head, list) { | ||
165 | kfree_skb(pf->skb); | ||
166 | list_del(&pf->list); | ||
167 | kfree(pf); | ||
168 | } | ||
169 | } | ||
170 | return; | ||
171 | } | ||
172 | |||
173 | /* frag_reassemble_skb(): | ||
174 | * returns NET_RX_DROP if the operation failed - skb is left intact | ||
175 | * returns NET_RX_SUCCESS if the fragment was buffered (skb_new will be NULL) | ||
176 | * or the skb could be reassembled (skb_new will point to the new packet and | ||
177 | * skb was freed) | ||
178 | */ | ||
179 | int batadv_frag_reassemble_skb(struct sk_buff *skb, | ||
180 | struct batadv_priv *bat_priv, | ||
181 | struct sk_buff **new_skb) | ||
182 | { | ||
183 | struct batadv_orig_node *orig_node; | ||
184 | struct batadv_frag_packet_list_entry *tmp_frag_entry; | ||
185 | int ret = NET_RX_DROP; | ||
186 | struct batadv_unicast_frag_packet *unicast_packet; | ||
187 | |||
188 | unicast_packet = (struct batadv_unicast_frag_packet *)skb->data; | ||
189 | *new_skb = NULL; | ||
190 | |||
191 | orig_node = batadv_orig_hash_find(bat_priv, unicast_packet->orig); | ||
192 | if (!orig_node) | ||
193 | goto out; | ||
194 | |||
195 | orig_node->last_frag_packet = jiffies; | ||
196 | |||
197 | if (list_empty(&orig_node->frag_list) && | ||
198 | batadv_frag_create_buffer(&orig_node->frag_list)) { | ||
199 | pr_debug("couldn't create frag buffer\n"); | ||
200 | goto out; | ||
201 | } | ||
202 | |||
203 | tmp_frag_entry = batadv_frag_search_packet(&orig_node->frag_list, | ||
204 | unicast_packet); | ||
205 | |||
206 | if (!tmp_frag_entry) { | ||
207 | batadv_frag_create_entry(&orig_node->frag_list, skb); | ||
208 | ret = NET_RX_SUCCESS; | ||
209 | goto out; | ||
210 | } | ||
211 | |||
212 | *new_skb = batadv_frag_merge_packet(&orig_node->frag_list, | ||
213 | tmp_frag_entry, skb); | ||
214 | /* if not, merge failed */ | ||
215 | if (*new_skb) | ||
216 | ret = NET_RX_SUCCESS; | ||
217 | |||
218 | out: | ||
219 | if (orig_node) | ||
220 | batadv_orig_node_free_ref(orig_node); | ||
221 | return ret; | ||
222 | } | ||
223 | |||
224 | int batadv_frag_send_skb(struct sk_buff *skb, struct batadv_priv *bat_priv, | ||
225 | struct batadv_hard_iface *hard_iface, | ||
226 | const uint8_t dstaddr[]) | ||
227 | { | ||
228 | struct batadv_unicast_packet tmp_uc, *unicast_packet; | ||
229 | struct batadv_hard_iface *primary_if; | ||
230 | struct sk_buff *frag_skb; | ||
231 | struct batadv_unicast_frag_packet *frag1, *frag2; | ||
232 | int uc_hdr_len = sizeof(*unicast_packet); | ||
233 | int ucf_hdr_len = sizeof(*frag1); | ||
234 | int data_len = skb->len - uc_hdr_len; | ||
235 | int large_tail = 0, ret = NET_RX_DROP; | ||
236 | uint16_t seqno; | ||
237 | |||
238 | primary_if = batadv_primary_if_get_selected(bat_priv); | ||
239 | if (!primary_if) | ||
240 | goto dropped; | ||
241 | |||
242 | frag_skb = dev_alloc_skb(data_len - (data_len / 2) + ucf_hdr_len); | ||
243 | if (!frag_skb) | ||
244 | goto dropped; | ||
245 | |||
246 | skb->priority = TC_PRIO_CONTROL; | ||
247 | skb_reserve(frag_skb, ucf_hdr_len); | ||
248 | |||
249 | unicast_packet = (struct batadv_unicast_packet *)skb->data; | ||
250 | memcpy(&tmp_uc, unicast_packet, uc_hdr_len); | ||
251 | skb_split(skb, frag_skb, data_len / 2 + uc_hdr_len); | ||
252 | |||
253 | if (batadv_skb_head_push(skb, ucf_hdr_len - uc_hdr_len) < 0 || | ||
254 | batadv_skb_head_push(frag_skb, ucf_hdr_len) < 0) | ||
255 | goto drop_frag; | ||
256 | |||
257 | frag1 = (struct batadv_unicast_frag_packet *)skb->data; | ||
258 | frag2 = (struct batadv_unicast_frag_packet *)frag_skb->data; | ||
259 | |||
260 | memcpy(frag1, &tmp_uc, sizeof(tmp_uc)); | ||
261 | |||
262 | frag1->header.ttl--; | ||
263 | frag1->header.version = BATADV_COMPAT_VERSION; | ||
264 | frag1->header.packet_type = BATADV_UNICAST_FRAG; | ||
265 | |||
266 | memcpy(frag1->orig, primary_if->net_dev->dev_addr, ETH_ALEN); | ||
267 | memcpy(frag2, frag1, sizeof(*frag2)); | ||
268 | |||
269 | if (data_len & 1) | ||
270 | large_tail = BATADV_UNI_FRAG_LARGETAIL; | ||
271 | |||
272 | frag1->flags = BATADV_UNI_FRAG_HEAD | large_tail; | ||
273 | frag2->flags = large_tail; | ||
274 | |||
275 | seqno = atomic_add_return(2, &hard_iface->frag_seqno); | ||
276 | frag1->seqno = htons(seqno - 1); | ||
277 | frag2->seqno = htons(seqno); | ||
278 | |||
279 | batadv_send_skb_packet(skb, hard_iface, dstaddr); | ||
280 | batadv_send_skb_packet(frag_skb, hard_iface, dstaddr); | ||
281 | ret = NET_RX_SUCCESS; | ||
282 | goto out; | ||
283 | |||
284 | drop_frag: | ||
285 | kfree_skb(frag_skb); | ||
286 | dropped: | ||
287 | kfree_skb(skb); | ||
288 | out: | ||
289 | if (primary_if) | ||
290 | batadv_hardif_free_ref(primary_if); | ||
291 | return ret; | ||
292 | } | ||
293 | |||
294 | /** | ||
295 | * batadv_unicast_push_and_fill_skb - extends the buffer and initializes the | ||
296 | * common fields for unicast packets | ||
297 | * @skb: packet | ||
298 | * @hdr_size: amount of bytes to push at the beginning of the skb | ||
299 | * @orig_node: the destination node | ||
300 | * | ||
301 | * Returns false if the buffer extension was not possible or true otherwise | ||
302 | */ | ||
303 | static bool batadv_unicast_push_and_fill_skb(struct sk_buff *skb, int hdr_size, | ||
304 | struct batadv_orig_node *orig_node) | ||
305 | { | ||
306 | struct batadv_unicast_packet *unicast_packet; | ||
307 | uint8_t ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn); | ||
308 | |||
309 | if (batadv_skb_head_push(skb, hdr_size) < 0) | ||
310 | return false; | ||
311 | |||
312 | unicast_packet = (struct batadv_unicast_packet *)skb->data; | ||
313 | unicast_packet->header.version = BATADV_COMPAT_VERSION; | ||
314 | /* batman packet type: unicast */ | ||
315 | unicast_packet->header.packet_type = BATADV_UNICAST; | ||
316 | /* set unicast ttl */ | ||
317 | unicast_packet->header.ttl = BATADV_TTL; | ||
318 | /* copy the destination for faster routing */ | ||
319 | memcpy(unicast_packet->dest, orig_node->orig, ETH_ALEN); | ||
320 | /* set the destination tt version number */ | ||
321 | unicast_packet->ttvn = ttvn; | ||
322 | |||
323 | return true; | ||
324 | } | ||
325 | |||
326 | /** | ||
327 | * batadv_unicast_prepare_skb - encapsulate an skb with a unicast header | ||
328 | * @skb: the skb containing the payload to encapsulate | ||
329 | * @orig_node: the destination node | ||
330 | * | ||
331 | * Returns false if the payload could not be encapsulated or true otherwise. | ||
332 | * | ||
333 | * This call might reallocate skb data. | ||
334 | */ | ||
335 | static bool batadv_unicast_prepare_skb(struct sk_buff *skb, | ||
336 | struct batadv_orig_node *orig_node) | ||
337 | { | ||
338 | size_t uni_size = sizeof(struct batadv_unicast_packet); | ||
339 | return batadv_unicast_push_and_fill_skb(skb, uni_size, orig_node); | ||
340 | } | ||
341 | |||
342 | /** | ||
343 | * batadv_unicast_4addr_prepare_skb - encapsulate an skb with a unicast4addr | ||
344 | * header | ||
345 | * @bat_priv: the bat priv with all the soft interface information | ||
346 | * @skb: the skb containing the payload to encapsulate | ||
347 | * @orig_node: the destination node | ||
348 | * @packet_subtype: the batman 4addr packet subtype to use | ||
349 | * | ||
350 | * Returns false if the payload could not be encapsulated or true otherwise. | ||
351 | * | ||
352 | * This call might reallocate skb data. | ||
353 | */ | ||
354 | bool batadv_unicast_4addr_prepare_skb(struct batadv_priv *bat_priv, | ||
355 | struct sk_buff *skb, | ||
356 | struct batadv_orig_node *orig, | ||
357 | int packet_subtype) | ||
358 | { | ||
359 | struct batadv_hard_iface *primary_if; | ||
360 | struct batadv_unicast_4addr_packet *unicast_4addr_packet; | ||
361 | bool ret = false; | ||
362 | |||
363 | primary_if = batadv_primary_if_get_selected(bat_priv); | ||
364 | if (!primary_if) | ||
365 | goto out; | ||
366 | |||
367 | /* pull the header space and fill the unicast_packet substructure. | ||
368 | * We can do that because the first member of the unicast_4addr_packet | ||
369 | * is of type struct unicast_packet | ||
370 | */ | ||
371 | if (!batadv_unicast_push_and_fill_skb(skb, | ||
372 | sizeof(*unicast_4addr_packet), | ||
373 | orig)) | ||
374 | goto out; | ||
375 | |||
376 | unicast_4addr_packet = (struct batadv_unicast_4addr_packet *)skb->data; | ||
377 | unicast_4addr_packet->u.header.packet_type = BATADV_UNICAST_4ADDR; | ||
378 | memcpy(unicast_4addr_packet->src, primary_if->net_dev->dev_addr, | ||
379 | ETH_ALEN); | ||
380 | unicast_4addr_packet->subtype = packet_subtype; | ||
381 | unicast_4addr_packet->reserved = 0; | ||
382 | |||
383 | ret = true; | ||
384 | out: | ||
385 | if (primary_if) | ||
386 | batadv_hardif_free_ref(primary_if); | ||
387 | return ret; | ||
388 | } | ||
389 | |||
390 | /** | ||
391 | * batadv_unicast_generic_send_skb - send an skb as unicast | ||
392 | * @bat_priv: the bat priv with all the soft interface information | ||
393 | * @skb: payload to send | ||
394 | * @packet_type: the batman unicast packet type to use | ||
395 | * @packet_subtype: the batman packet subtype. It is ignored if packet_type is | ||
396 | * not BATADV_UNICAT_4ADDR | ||
397 | * | ||
398 | * Returns 1 in case of error or 0 otherwise | ||
399 | */ | ||
400 | int batadv_unicast_generic_send_skb(struct batadv_priv *bat_priv, | ||
401 | struct sk_buff *skb, int packet_type, | ||
402 | int packet_subtype) | ||
403 | { | ||
404 | struct ethhdr *ethhdr = (struct ethhdr *)skb->data; | ||
405 | struct batadv_unicast_packet *unicast_packet; | ||
406 | struct batadv_orig_node *orig_node; | ||
407 | struct batadv_neigh_node *neigh_node; | ||
408 | int data_len = skb->len; | ||
409 | int ret = NET_RX_DROP; | ||
410 | unsigned int dev_mtu, header_len; | ||
411 | |||
412 | /* get routing information */ | ||
413 | if (is_multicast_ether_addr(ethhdr->h_dest)) { | ||
414 | orig_node = batadv_gw_get_selected_orig(bat_priv); | ||
415 | if (orig_node) | ||
416 | goto find_router; | ||
417 | } | ||
418 | |||
419 | /* check for tt host - increases orig_node refcount. | ||
420 | * returns NULL in case of AP isolation | ||
421 | */ | ||
422 | orig_node = batadv_transtable_search(bat_priv, ethhdr->h_source, | ||
423 | ethhdr->h_dest); | ||
424 | |||
425 | find_router: | ||
426 | /* find_router(): | ||
427 | * - if orig_node is NULL it returns NULL | ||
428 | * - increases neigh_nodes refcount if found. | ||
429 | */ | ||
430 | neigh_node = batadv_find_router(bat_priv, orig_node, NULL); | ||
431 | |||
432 | if (!neigh_node) | ||
433 | goto out; | ||
434 | |||
435 | switch (packet_type) { | ||
436 | case BATADV_UNICAST: | ||
437 | if (!batadv_unicast_prepare_skb(skb, orig_node)) | ||
438 | goto out; | ||
439 | |||
440 | header_len = sizeof(struct batadv_unicast_packet); | ||
441 | break; | ||
442 | case BATADV_UNICAST_4ADDR: | ||
443 | if (!batadv_unicast_4addr_prepare_skb(bat_priv, skb, orig_node, | ||
444 | packet_subtype)) | ||
445 | goto out; | ||
446 | |||
447 | header_len = sizeof(struct batadv_unicast_4addr_packet); | ||
448 | break; | ||
449 | default: | ||
450 | /* this function supports UNICAST and UNICAST_4ADDR only. It | ||
451 | * should never be invoked with any other packet type | ||
452 | */ | ||
453 | goto out; | ||
454 | } | ||
455 | |||
456 | ethhdr = (struct ethhdr *)(skb->data + header_len); | ||
457 | unicast_packet = (struct batadv_unicast_packet *)skb->data; | ||
458 | |||
459 | /* inform the destination node that we are still missing a correct route | ||
460 | * for this client. The destination will receive this packet and will | ||
461 | * try to reroute it because the ttvn contained in the header is less | ||
462 | * than the current one | ||
463 | */ | ||
464 | if (batadv_tt_global_client_is_roaming(bat_priv, ethhdr->h_dest)) | ||
465 | unicast_packet->ttvn = unicast_packet->ttvn - 1; | ||
466 | |||
467 | dev_mtu = neigh_node->if_incoming->net_dev->mtu; | ||
468 | /* fragmentation mechanism only works for UNICAST (now) */ | ||
469 | if (packet_type == BATADV_UNICAST && | ||
470 | atomic_read(&bat_priv->fragmentation) && | ||
471 | data_len + sizeof(*unicast_packet) > dev_mtu) { | ||
472 | /* send frag skb decreases ttl */ | ||
473 | unicast_packet->header.ttl++; | ||
474 | ret = batadv_frag_send_skb(skb, bat_priv, | ||
475 | neigh_node->if_incoming, | ||
476 | neigh_node->addr); | ||
477 | goto out; | ||
478 | } | ||
479 | |||
480 | if (batadv_send_skb_to_orig(skb, orig_node, NULL) != NET_XMIT_DROP) | ||
481 | ret = 0; | ||
482 | |||
483 | out: | ||
484 | if (neigh_node) | ||
485 | batadv_neigh_node_free_ref(neigh_node); | ||
486 | if (orig_node) | ||
487 | batadv_orig_node_free_ref(orig_node); | ||
488 | if (ret == NET_RX_DROP) | ||
489 | kfree_skb(skb); | ||
490 | return ret; | ||
491 | } | ||
diff --git a/net/batman-adv/unicast.h b/net/batman-adv/unicast.h deleted file mode 100644 index 429cf8a4a31e..000000000000 --- a/net/batman-adv/unicast.h +++ /dev/null | |||
@@ -1,92 +0,0 @@ | |||
1 | /* Copyright (C) 2010-2013 B.A.T.M.A.N. contributors: | ||
2 | * | ||
3 | * Andreas Langer | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of version 2 of the GNU General Public | ||
7 | * License as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, but | ||
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | * General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
17 | * 02110-1301, USA | ||
18 | */ | ||
19 | |||
20 | #ifndef _NET_BATMAN_ADV_UNICAST_H_ | ||
21 | #define _NET_BATMAN_ADV_UNICAST_H_ | ||
22 | |||
23 | #include "packet.h" | ||
24 | |||
25 | #define BATADV_FRAG_TIMEOUT 10000 /* purge frag list entries after time in ms */ | ||
26 | #define BATADV_FRAG_BUFFER_SIZE 6 /* number of list elements in buffer */ | ||
27 | |||
28 | int batadv_frag_reassemble_skb(struct sk_buff *skb, | ||
29 | struct batadv_priv *bat_priv, | ||
30 | struct sk_buff **new_skb); | ||
31 | void batadv_frag_list_free(struct list_head *head); | ||
32 | int batadv_frag_send_skb(struct sk_buff *skb, struct batadv_priv *bat_priv, | ||
33 | struct batadv_hard_iface *hard_iface, | ||
34 | const uint8_t dstaddr[]); | ||
35 | bool batadv_unicast_4addr_prepare_skb(struct batadv_priv *bat_priv, | ||
36 | struct sk_buff *skb, | ||
37 | struct batadv_orig_node *orig_node, | ||
38 | int packet_subtype); | ||
39 | int batadv_unicast_generic_send_skb(struct batadv_priv *bat_priv, | ||
40 | struct sk_buff *skb, int packet_type, | ||
41 | int packet_subtype); | ||
42 | |||
43 | |||
44 | /** | ||
45 | * batadv_unicast_send_skb - send the skb encapsulated in a unicast packet | ||
46 | * @bat_priv: the bat priv with all the soft interface information | ||
47 | * @skb: the payload to send | ||
48 | */ | ||
49 | static inline int batadv_unicast_send_skb(struct batadv_priv *bat_priv, | ||
50 | struct sk_buff *skb) | ||
51 | { | ||
52 | return batadv_unicast_generic_send_skb(bat_priv, skb, BATADV_UNICAST, | ||
53 | 0); | ||
54 | } | ||
55 | |||
56 | /** | ||
57 | * batadv_unicast_send_skb - send the skb encapsulated in a unicast4addr packet | ||
58 | * @bat_priv: the bat priv with all the soft interface information | ||
59 | * @skb: the payload to send | ||
60 | * @packet_subtype: the batman 4addr packet subtype to use | ||
61 | */ | ||
62 | static inline int batadv_unicast_4addr_send_skb(struct batadv_priv *bat_priv, | ||
63 | struct sk_buff *skb, | ||
64 | int packet_subtype) | ||
65 | { | ||
66 | return batadv_unicast_generic_send_skb(bat_priv, skb, | ||
67 | BATADV_UNICAST_4ADDR, | ||
68 | packet_subtype); | ||
69 | } | ||
70 | |||
71 | static inline int batadv_frag_can_reassemble(const struct sk_buff *skb, int mtu) | ||
72 | { | ||
73 | const struct batadv_unicast_frag_packet *unicast_packet; | ||
74 | int uneven_correction = 0; | ||
75 | unsigned int merged_size; | ||
76 | |||
77 | unicast_packet = (struct batadv_unicast_frag_packet *)skb->data; | ||
78 | |||
79 | if (unicast_packet->flags & BATADV_UNI_FRAG_LARGETAIL) { | ||
80 | if (unicast_packet->flags & BATADV_UNI_FRAG_HEAD) | ||
81 | uneven_correction = 1; | ||
82 | else | ||
83 | uneven_correction = -1; | ||
84 | } | ||
85 | |||
86 | merged_size = (skb->len - sizeof(*unicast_packet)) * 2; | ||
87 | merged_size += sizeof(struct batadv_unicast_packet) + uneven_correction; | ||
88 | |||
89 | return merged_size <= mtu; | ||
90 | } | ||
91 | |||
92 | #endif /* _NET_BATMAN_ADV_UNICAST_H_ */ | ||
diff --git a/net/batman-adv/vis.c b/net/batman-adv/vis.c deleted file mode 100644 index d8ea31a58457..000000000000 --- a/net/batman-adv/vis.c +++ /dev/null | |||
@@ -1,938 +0,0 @@ | |||
1 | /* Copyright (C) 2008-2013 B.A.T.M.A.N. contributors: | ||
2 | * | ||
3 | * Simon Wunderlich | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of version 2 of the GNU General Public | ||
7 | * License as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, but | ||
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | * General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
17 | * 02110-1301, USA | ||
18 | */ | ||
19 | |||
20 | #include "main.h" | ||
21 | #include "send.h" | ||
22 | #include "translation-table.h" | ||
23 | #include "vis.h" | ||
24 | #include "soft-interface.h" | ||
25 | #include "hard-interface.h" | ||
26 | #include "hash.h" | ||
27 | #include "originator.h" | ||
28 | |||
29 | #define BATADV_MAX_VIS_PACKET_SIZE 1000 | ||
30 | |||
31 | /* hash class keys */ | ||
32 | static struct lock_class_key batadv_vis_hash_lock_class_key; | ||
33 | |||
34 | /* free the info */ | ||
35 | static void batadv_free_info(struct kref *ref) | ||
36 | { | ||
37 | struct batadv_vis_info *info; | ||
38 | struct batadv_priv *bat_priv; | ||
39 | struct batadv_vis_recvlist_node *entry, *tmp; | ||
40 | |||
41 | info = container_of(ref, struct batadv_vis_info, refcount); | ||
42 | bat_priv = info->bat_priv; | ||
43 | |||
44 | list_del_init(&info->send_list); | ||
45 | spin_lock_bh(&bat_priv->vis.list_lock); | ||
46 | list_for_each_entry_safe(entry, tmp, &info->recv_list, list) { | ||
47 | list_del(&entry->list); | ||
48 | kfree(entry); | ||
49 | } | ||
50 | |||
51 | spin_unlock_bh(&bat_priv->vis.list_lock); | ||
52 | kfree_skb(info->skb_packet); | ||
53 | kfree(info); | ||
54 | } | ||
55 | |||
56 | /* Compare two vis packets, used by the hashing algorithm */ | ||
57 | static int batadv_vis_info_cmp(const struct hlist_node *node, const void *data2) | ||
58 | { | ||
59 | const struct batadv_vis_info *d1, *d2; | ||
60 | const struct batadv_vis_packet *p1, *p2; | ||
61 | |||
62 | d1 = container_of(node, struct batadv_vis_info, hash_entry); | ||
63 | d2 = data2; | ||
64 | p1 = (struct batadv_vis_packet *)d1->skb_packet->data; | ||
65 | p2 = (struct batadv_vis_packet *)d2->skb_packet->data; | ||
66 | return batadv_compare_eth(p1->vis_orig, p2->vis_orig); | ||
67 | } | ||
68 | |||
69 | /* hash function to choose an entry in a hash table of given size | ||
70 | * hash algorithm from http://en.wikipedia.org/wiki/Hash_table | ||
71 | */ | ||
72 | static uint32_t batadv_vis_info_choose(const void *data, uint32_t size) | ||
73 | { | ||
74 | const struct batadv_vis_info *vis_info = data; | ||
75 | const struct batadv_vis_packet *packet; | ||
76 | const unsigned char *key; | ||
77 | uint32_t hash = 0; | ||
78 | size_t i; | ||
79 | |||
80 | packet = (struct batadv_vis_packet *)vis_info->skb_packet->data; | ||
81 | key = packet->vis_orig; | ||
82 | for (i = 0; i < ETH_ALEN; i++) { | ||
83 | hash += key[i]; | ||
84 | hash += (hash << 10); | ||
85 | hash ^= (hash >> 6); | ||
86 | } | ||
87 | |||
88 | hash += (hash << 3); | ||
89 | hash ^= (hash >> 11); | ||
90 | hash += (hash << 15); | ||
91 | |||
92 | return hash % size; | ||
93 | } | ||
94 | |||
95 | static struct batadv_vis_info * | ||
96 | batadv_vis_hash_find(struct batadv_priv *bat_priv, const void *data) | ||
97 | { | ||
98 | struct batadv_hashtable *hash = bat_priv->vis.hash; | ||
99 | struct hlist_head *head; | ||
100 | struct batadv_vis_info *vis_info, *vis_info_tmp = NULL; | ||
101 | uint32_t index; | ||
102 | |||
103 | if (!hash) | ||
104 | return NULL; | ||
105 | |||
106 | index = batadv_vis_info_choose(data, hash->size); | ||
107 | head = &hash->table[index]; | ||
108 | |||
109 | rcu_read_lock(); | ||
110 | hlist_for_each_entry_rcu(vis_info, head, hash_entry) { | ||
111 | if (!batadv_vis_info_cmp(&vis_info->hash_entry, data)) | ||
112 | continue; | ||
113 | |||
114 | vis_info_tmp = vis_info; | ||
115 | break; | ||
116 | } | ||
117 | rcu_read_unlock(); | ||
118 | |||
119 | return vis_info_tmp; | ||
120 | } | ||
121 | |||
122 | /* insert interface to the list of interfaces of one originator, if it | ||
123 | * does not already exist in the list | ||
124 | */ | ||
125 | static void batadv_vis_data_insert_interface(const uint8_t *interface, | ||
126 | struct hlist_head *if_list, | ||
127 | bool primary) | ||
128 | { | ||
129 | struct batadv_vis_if_list_entry *entry; | ||
130 | |||
131 | hlist_for_each_entry(entry, if_list, list) { | ||
132 | if (batadv_compare_eth(entry->addr, interface)) | ||
133 | return; | ||
134 | } | ||
135 | |||
136 | /* it's a new address, add it to the list */ | ||
137 | entry = kmalloc(sizeof(*entry), GFP_ATOMIC); | ||
138 | if (!entry) | ||
139 | return; | ||
140 | memcpy(entry->addr, interface, ETH_ALEN); | ||
141 | entry->primary = primary; | ||
142 | hlist_add_head(&entry->list, if_list); | ||
143 | } | ||
144 | |||
145 | static void batadv_vis_data_read_prim_sec(struct seq_file *seq, | ||
146 | const struct hlist_head *if_list) | ||
147 | { | ||
148 | struct batadv_vis_if_list_entry *entry; | ||
149 | |||
150 | hlist_for_each_entry(entry, if_list, list) { | ||
151 | if (entry->primary) | ||
152 | seq_puts(seq, "PRIMARY, "); | ||
153 | else | ||
154 | seq_printf(seq, "SEC %pM, ", entry->addr); | ||
155 | } | ||
156 | } | ||
157 | |||
158 | /* read an entry */ | ||
159 | static ssize_t | ||
160 | batadv_vis_data_read_entry(struct seq_file *seq, | ||
161 | const struct batadv_vis_info_entry *entry, | ||
162 | const uint8_t *src, bool primary) | ||
163 | { | ||
164 | if (primary && entry->quality == 0) | ||
165 | return seq_printf(seq, "TT %pM, ", entry->dest); | ||
166 | else if (batadv_compare_eth(entry->src, src)) | ||
167 | return seq_printf(seq, "TQ %pM %d, ", entry->dest, | ||
168 | entry->quality); | ||
169 | |||
170 | return 0; | ||
171 | } | ||
172 | |||
173 | static void | ||
174 | batadv_vis_data_insert_interfaces(struct hlist_head *list, | ||
175 | struct batadv_vis_packet *packet, | ||
176 | struct batadv_vis_info_entry *entries) | ||
177 | { | ||
178 | int i; | ||
179 | |||
180 | for (i = 0; i < packet->entries; i++) { | ||
181 | if (entries[i].quality == 0) | ||
182 | continue; | ||
183 | |||
184 | if (batadv_compare_eth(entries[i].src, packet->vis_orig)) | ||
185 | continue; | ||
186 | |||
187 | batadv_vis_data_insert_interface(entries[i].src, list, false); | ||
188 | } | ||
189 | } | ||
190 | |||
191 | static void batadv_vis_data_read_entries(struct seq_file *seq, | ||
192 | struct hlist_head *list, | ||
193 | struct batadv_vis_packet *packet, | ||
194 | struct batadv_vis_info_entry *entries) | ||
195 | { | ||
196 | int i; | ||
197 | struct batadv_vis_if_list_entry *entry; | ||
198 | |||
199 | hlist_for_each_entry(entry, list, list) { | ||
200 | seq_printf(seq, "%pM,", entry->addr); | ||
201 | |||
202 | for (i = 0; i < packet->entries; i++) | ||
203 | batadv_vis_data_read_entry(seq, &entries[i], | ||
204 | entry->addr, entry->primary); | ||
205 | |||
206 | /* add primary/secondary records */ | ||
207 | if (batadv_compare_eth(entry->addr, packet->vis_orig)) | ||
208 | batadv_vis_data_read_prim_sec(seq, list); | ||
209 | |||
210 | seq_puts(seq, "\n"); | ||
211 | } | ||
212 | } | ||
213 | |||
214 | static void batadv_vis_seq_print_text_bucket(struct seq_file *seq, | ||
215 | const struct hlist_head *head) | ||
216 | { | ||
217 | struct batadv_vis_info *info; | ||
218 | struct batadv_vis_packet *packet; | ||
219 | uint8_t *entries_pos; | ||
220 | struct batadv_vis_info_entry *entries; | ||
221 | struct batadv_vis_if_list_entry *entry; | ||
222 | struct hlist_node *n; | ||
223 | |||
224 | HLIST_HEAD(vis_if_list); | ||
225 | |||
226 | hlist_for_each_entry_rcu(info, head, hash_entry) { | ||
227 | packet = (struct batadv_vis_packet *)info->skb_packet->data; | ||
228 | entries_pos = (uint8_t *)packet + sizeof(*packet); | ||
229 | entries = (struct batadv_vis_info_entry *)entries_pos; | ||
230 | |||
231 | batadv_vis_data_insert_interface(packet->vis_orig, &vis_if_list, | ||
232 | true); | ||
233 | batadv_vis_data_insert_interfaces(&vis_if_list, packet, | ||
234 | entries); | ||
235 | batadv_vis_data_read_entries(seq, &vis_if_list, packet, | ||
236 | entries); | ||
237 | |||
238 | hlist_for_each_entry_safe(entry, n, &vis_if_list, list) { | ||
239 | hlist_del(&entry->list); | ||
240 | kfree(entry); | ||
241 | } | ||
242 | } | ||
243 | } | ||
244 | |||
245 | int batadv_vis_seq_print_text(struct seq_file *seq, void *offset) | ||
246 | { | ||
247 | struct batadv_hard_iface *primary_if; | ||
248 | struct hlist_head *head; | ||
249 | struct net_device *net_dev = (struct net_device *)seq->private; | ||
250 | struct batadv_priv *bat_priv = netdev_priv(net_dev); | ||
251 | struct batadv_hashtable *hash = bat_priv->vis.hash; | ||
252 | uint32_t i; | ||
253 | int ret = 0; | ||
254 | int vis_server = atomic_read(&bat_priv->vis_mode); | ||
255 | |||
256 | primary_if = batadv_primary_if_get_selected(bat_priv); | ||
257 | if (!primary_if) | ||
258 | goto out; | ||
259 | |||
260 | if (vis_server == BATADV_VIS_TYPE_CLIENT_UPDATE) | ||
261 | goto out; | ||
262 | |||
263 | spin_lock_bh(&bat_priv->vis.hash_lock); | ||
264 | for (i = 0; i < hash->size; i++) { | ||
265 | head = &hash->table[i]; | ||
266 | batadv_vis_seq_print_text_bucket(seq, head); | ||
267 | } | ||
268 | spin_unlock_bh(&bat_priv->vis.hash_lock); | ||
269 | |||
270 | out: | ||
271 | if (primary_if) | ||
272 | batadv_hardif_free_ref(primary_if); | ||
273 | return ret; | ||
274 | } | ||
275 | |||
276 | /* add the info packet to the send list, if it was not | ||
277 | * already linked in. | ||
278 | */ | ||
279 | static void batadv_send_list_add(struct batadv_priv *bat_priv, | ||
280 | struct batadv_vis_info *info) | ||
281 | { | ||
282 | if (list_empty(&info->send_list)) { | ||
283 | kref_get(&info->refcount); | ||
284 | list_add_tail(&info->send_list, &bat_priv->vis.send_list); | ||
285 | } | ||
286 | } | ||
287 | |||
288 | /* delete the info packet from the send list, if it was | ||
289 | * linked in. | ||
290 | */ | ||
291 | static void batadv_send_list_del(struct batadv_vis_info *info) | ||
292 | { | ||
293 | if (!list_empty(&info->send_list)) { | ||
294 | list_del_init(&info->send_list); | ||
295 | kref_put(&info->refcount, batadv_free_info); | ||
296 | } | ||
297 | } | ||
298 | |||
299 | /* tries to add one entry to the receive list. */ | ||
300 | static void batadv_recv_list_add(struct batadv_priv *bat_priv, | ||
301 | struct list_head *recv_list, const char *mac) | ||
302 | { | ||
303 | struct batadv_vis_recvlist_node *entry; | ||
304 | |||
305 | entry = kmalloc(sizeof(*entry), GFP_ATOMIC); | ||
306 | if (!entry) | ||
307 | return; | ||
308 | |||
309 | memcpy(entry->mac, mac, ETH_ALEN); | ||
310 | spin_lock_bh(&bat_priv->vis.list_lock); | ||
311 | list_add_tail(&entry->list, recv_list); | ||
312 | spin_unlock_bh(&bat_priv->vis.list_lock); | ||
313 | } | ||
314 | |||
315 | /* returns 1 if this mac is in the recv_list */ | ||
316 | static int batadv_recv_list_is_in(struct batadv_priv *bat_priv, | ||
317 | const struct list_head *recv_list, | ||
318 | const char *mac) | ||
319 | { | ||
320 | const struct batadv_vis_recvlist_node *entry; | ||
321 | |||
322 | spin_lock_bh(&bat_priv->vis.list_lock); | ||
323 | list_for_each_entry(entry, recv_list, list) { | ||
324 | if (batadv_compare_eth(entry->mac, mac)) { | ||
325 | spin_unlock_bh(&bat_priv->vis.list_lock); | ||
326 | return 1; | ||
327 | } | ||
328 | } | ||
329 | spin_unlock_bh(&bat_priv->vis.list_lock); | ||
330 | return 0; | ||
331 | } | ||
332 | |||
333 | /* try to add the packet to the vis_hash. return NULL if invalid (e.g. too old, | ||
334 | * broken.. ). vis hash must be locked outside. is_new is set when the packet | ||
335 | * is newer than old entries in the hash. | ||
336 | */ | ||
337 | static struct batadv_vis_info * | ||
338 | batadv_add_packet(struct batadv_priv *bat_priv, | ||
339 | struct batadv_vis_packet *vis_packet, int vis_info_len, | ||
340 | int *is_new, int make_broadcast) | ||
341 | { | ||
342 | struct batadv_vis_info *info, *old_info; | ||
343 | struct batadv_vis_packet *search_packet, *old_packet; | ||
344 | struct batadv_vis_info search_elem; | ||
345 | struct batadv_vis_packet *packet; | ||
346 | struct sk_buff *tmp_skb; | ||
347 | int hash_added; | ||
348 | size_t len; | ||
349 | size_t max_entries; | ||
350 | |||
351 | *is_new = 0; | ||
352 | /* sanity check */ | ||
353 | if (!bat_priv->vis.hash) | ||
354 | return NULL; | ||
355 | |||
356 | /* see if the packet is already in vis_hash */ | ||
357 | search_elem.skb_packet = dev_alloc_skb(sizeof(*search_packet)); | ||
358 | if (!search_elem.skb_packet) | ||
359 | return NULL; | ||
360 | len = sizeof(*search_packet); | ||
361 | tmp_skb = search_elem.skb_packet; | ||
362 | search_packet = (struct batadv_vis_packet *)skb_put(tmp_skb, len); | ||
363 | |||
364 | memcpy(search_packet->vis_orig, vis_packet->vis_orig, ETH_ALEN); | ||
365 | old_info = batadv_vis_hash_find(bat_priv, &search_elem); | ||
366 | kfree_skb(search_elem.skb_packet); | ||
367 | |||
368 | if (old_info) { | ||
369 | tmp_skb = old_info->skb_packet; | ||
370 | old_packet = (struct batadv_vis_packet *)tmp_skb->data; | ||
371 | if (!batadv_seq_after(ntohl(vis_packet->seqno), | ||
372 | ntohl(old_packet->seqno))) { | ||
373 | if (old_packet->seqno == vis_packet->seqno) { | ||
374 | batadv_recv_list_add(bat_priv, | ||
375 | &old_info->recv_list, | ||
376 | vis_packet->sender_orig); | ||
377 | return old_info; | ||
378 | } else { | ||
379 | /* newer packet is already in hash. */ | ||
380 | return NULL; | ||
381 | } | ||
382 | } | ||
383 | /* remove old entry */ | ||
384 | batadv_hash_remove(bat_priv->vis.hash, batadv_vis_info_cmp, | ||
385 | batadv_vis_info_choose, old_info); | ||
386 | batadv_send_list_del(old_info); | ||
387 | kref_put(&old_info->refcount, batadv_free_info); | ||
388 | } | ||
389 | |||
390 | info = kmalloc(sizeof(*info), GFP_ATOMIC); | ||
391 | if (!info) | ||
392 | return NULL; | ||
393 | |||
394 | len = sizeof(*packet) + vis_info_len; | ||
395 | info->skb_packet = netdev_alloc_skb_ip_align(NULL, len + ETH_HLEN); | ||
396 | if (!info->skb_packet) { | ||
397 | kfree(info); | ||
398 | return NULL; | ||
399 | } | ||
400 | info->skb_packet->priority = TC_PRIO_CONTROL; | ||
401 | skb_reserve(info->skb_packet, ETH_HLEN); | ||
402 | packet = (struct batadv_vis_packet *)skb_put(info->skb_packet, len); | ||
403 | |||
404 | kref_init(&info->refcount); | ||
405 | INIT_LIST_HEAD(&info->send_list); | ||
406 | INIT_LIST_HEAD(&info->recv_list); | ||
407 | info->first_seen = jiffies; | ||
408 | info->bat_priv = bat_priv; | ||
409 | memcpy(packet, vis_packet, len); | ||
410 | |||
411 | /* initialize and add new packet. */ | ||
412 | *is_new = 1; | ||
413 | |||
414 | /* Make it a broadcast packet, if required */ | ||
415 | if (make_broadcast) | ||
416 | memcpy(packet->target_orig, batadv_broadcast_addr, ETH_ALEN); | ||
417 | |||
418 | /* repair if entries is longer than packet. */ | ||
419 | max_entries = vis_info_len / sizeof(struct batadv_vis_info_entry); | ||
420 | if (packet->entries > max_entries) | ||
421 | packet->entries = max_entries; | ||
422 | |||
423 | batadv_recv_list_add(bat_priv, &info->recv_list, packet->sender_orig); | ||
424 | |||
425 | /* try to add it */ | ||
426 | hash_added = batadv_hash_add(bat_priv->vis.hash, batadv_vis_info_cmp, | ||
427 | batadv_vis_info_choose, info, | ||
428 | &info->hash_entry); | ||
429 | if (hash_added != 0) { | ||
430 | /* did not work (for some reason) */ | ||
431 | kref_put(&info->refcount, batadv_free_info); | ||
432 | info = NULL; | ||
433 | } | ||
434 | |||
435 | return info; | ||
436 | } | ||
437 | |||
438 | /* handle the server sync packet, forward if needed. */ | ||
439 | void batadv_receive_server_sync_packet(struct batadv_priv *bat_priv, | ||
440 | struct batadv_vis_packet *vis_packet, | ||
441 | int vis_info_len) | ||
442 | { | ||
443 | struct batadv_vis_info *info; | ||
444 | int is_new, make_broadcast; | ||
445 | int vis_server = atomic_read(&bat_priv->vis_mode); | ||
446 | |||
447 | make_broadcast = (vis_server == BATADV_VIS_TYPE_SERVER_SYNC); | ||
448 | |||
449 | spin_lock_bh(&bat_priv->vis.hash_lock); | ||
450 | info = batadv_add_packet(bat_priv, vis_packet, vis_info_len, | ||
451 | &is_new, make_broadcast); | ||
452 | if (!info) | ||
453 | goto end; | ||
454 | |||
455 | /* only if we are server ourselves and packet is newer than the one in | ||
456 | * hash. | ||
457 | */ | ||
458 | if (vis_server == BATADV_VIS_TYPE_SERVER_SYNC && is_new) | ||
459 | batadv_send_list_add(bat_priv, info); | ||
460 | end: | ||
461 | spin_unlock_bh(&bat_priv->vis.hash_lock); | ||
462 | } | ||
463 | |||
464 | /* handle an incoming client update packet and schedule forward if needed. */ | ||
465 | void batadv_receive_client_update_packet(struct batadv_priv *bat_priv, | ||
466 | struct batadv_vis_packet *vis_packet, | ||
467 | int vis_info_len) | ||
468 | { | ||
469 | struct batadv_vis_info *info; | ||
470 | struct batadv_vis_packet *packet; | ||
471 | int is_new; | ||
472 | int vis_server = atomic_read(&bat_priv->vis_mode); | ||
473 | int are_target = 0; | ||
474 | |||
475 | /* clients shall not broadcast. */ | ||
476 | if (is_broadcast_ether_addr(vis_packet->target_orig)) | ||
477 | return; | ||
478 | |||
479 | /* Are we the target for this VIS packet? */ | ||
480 | if (vis_server == BATADV_VIS_TYPE_SERVER_SYNC && | ||
481 | batadv_is_my_mac(bat_priv, vis_packet->target_orig)) | ||
482 | are_target = 1; | ||
483 | |||
484 | spin_lock_bh(&bat_priv->vis.hash_lock); | ||
485 | info = batadv_add_packet(bat_priv, vis_packet, vis_info_len, | ||
486 | &is_new, are_target); | ||
487 | |||
488 | if (!info) | ||
489 | goto end; | ||
490 | /* note that outdated packets will be dropped at this point. */ | ||
491 | |||
492 | packet = (struct batadv_vis_packet *)info->skb_packet->data; | ||
493 | |||
494 | /* send only if we're the target server or ... */ | ||
495 | if (are_target && is_new) { | ||
496 | packet->vis_type = BATADV_VIS_TYPE_SERVER_SYNC; /* upgrade! */ | ||
497 | batadv_send_list_add(bat_priv, info); | ||
498 | |||
499 | /* ... we're not the recipient (and thus need to forward). */ | ||
500 | } else if (!batadv_is_my_mac(bat_priv, packet->target_orig)) { | ||
501 | batadv_send_list_add(bat_priv, info); | ||
502 | } | ||
503 | |||
504 | end: | ||
505 | spin_unlock_bh(&bat_priv->vis.hash_lock); | ||
506 | } | ||
507 | |||
508 | /* Walk the originators and find the VIS server with the best tq. Set the packet | ||
509 | * address to its address and return the best_tq. | ||
510 | * | ||
511 | * Must be called with the originator hash locked | ||
512 | */ | ||
513 | static int batadv_find_best_vis_server(struct batadv_priv *bat_priv, | ||
514 | struct batadv_vis_info *info) | ||
515 | { | ||
516 | struct batadv_hashtable *hash = bat_priv->orig_hash; | ||
517 | struct batadv_neigh_node *router; | ||
518 | struct hlist_head *head; | ||
519 | struct batadv_orig_node *orig_node; | ||
520 | struct batadv_vis_packet *packet; | ||
521 | int best_tq = -1; | ||
522 | uint32_t i; | ||
523 | |||
524 | packet = (struct batadv_vis_packet *)info->skb_packet->data; | ||
525 | |||
526 | for (i = 0; i < hash->size; i++) { | ||
527 | head = &hash->table[i]; | ||
528 | |||
529 | rcu_read_lock(); | ||
530 | hlist_for_each_entry_rcu(orig_node, head, hash_entry) { | ||
531 | router = batadv_orig_node_get_router(orig_node); | ||
532 | if (!router) | ||
533 | continue; | ||
534 | |||
535 | if ((orig_node->flags & BATADV_VIS_SERVER) && | ||
536 | (router->tq_avg > best_tq)) { | ||
537 | best_tq = router->tq_avg; | ||
538 | memcpy(packet->target_orig, orig_node->orig, | ||
539 | ETH_ALEN); | ||
540 | } | ||
541 | batadv_neigh_node_free_ref(router); | ||
542 | } | ||
543 | rcu_read_unlock(); | ||
544 | } | ||
545 | |||
546 | return best_tq; | ||
547 | } | ||
548 | |||
549 | /* Return true if the vis packet is full. */ | ||
550 | static bool batadv_vis_packet_full(const struct batadv_vis_info *info) | ||
551 | { | ||
552 | const struct batadv_vis_packet *packet; | ||
553 | size_t num; | ||
554 | |||
555 | packet = (struct batadv_vis_packet *)info->skb_packet->data; | ||
556 | num = BATADV_MAX_VIS_PACKET_SIZE / sizeof(struct batadv_vis_info_entry); | ||
557 | |||
558 | if (num < packet->entries + 1) | ||
559 | return true; | ||
560 | return false; | ||
561 | } | ||
562 | |||
563 | /* generates a packet of own vis data, | ||
564 | * returns 0 on success, -1 if no packet could be generated | ||
565 | */ | ||
566 | static int batadv_generate_vis_packet(struct batadv_priv *bat_priv) | ||
567 | { | ||
568 | struct batadv_hashtable *hash = bat_priv->orig_hash; | ||
569 | struct hlist_head *head; | ||
570 | struct batadv_orig_node *orig_node; | ||
571 | struct batadv_neigh_node *router; | ||
572 | struct batadv_vis_info *info = bat_priv->vis.my_info; | ||
573 | struct batadv_vis_packet *packet; | ||
574 | struct batadv_vis_info_entry *entry; | ||
575 | struct batadv_tt_common_entry *tt_common_entry; | ||
576 | uint8_t *packet_pos; | ||
577 | int best_tq = -1; | ||
578 | uint32_t i; | ||
579 | |||
580 | info->first_seen = jiffies; | ||
581 | packet = (struct batadv_vis_packet *)info->skb_packet->data; | ||
582 | packet->vis_type = atomic_read(&bat_priv->vis_mode); | ||
583 | |||
584 | memcpy(packet->target_orig, batadv_broadcast_addr, ETH_ALEN); | ||
585 | packet->header.ttl = BATADV_TTL; | ||
586 | packet->seqno = htonl(ntohl(packet->seqno) + 1); | ||
587 | packet->entries = 0; | ||
588 | packet->reserved = 0; | ||
589 | skb_trim(info->skb_packet, sizeof(*packet)); | ||
590 | |||
591 | if (packet->vis_type == BATADV_VIS_TYPE_CLIENT_UPDATE) { | ||
592 | best_tq = batadv_find_best_vis_server(bat_priv, info); | ||
593 | |||
594 | if (best_tq < 0) | ||
595 | return best_tq; | ||
596 | } | ||
597 | |||
598 | for (i = 0; i < hash->size; i++) { | ||
599 | head = &hash->table[i]; | ||
600 | |||
601 | rcu_read_lock(); | ||
602 | hlist_for_each_entry_rcu(orig_node, head, hash_entry) { | ||
603 | router = batadv_orig_node_get_router(orig_node); | ||
604 | if (!router) | ||
605 | continue; | ||
606 | |||
607 | if (!batadv_compare_eth(router->addr, orig_node->orig)) | ||
608 | goto next; | ||
609 | |||
610 | if (router->if_incoming->if_status != BATADV_IF_ACTIVE) | ||
611 | goto next; | ||
612 | |||
613 | if (router->tq_avg < 1) | ||
614 | goto next; | ||
615 | |||
616 | /* fill one entry into buffer. */ | ||
617 | packet_pos = skb_put(info->skb_packet, sizeof(*entry)); | ||
618 | entry = (struct batadv_vis_info_entry *)packet_pos; | ||
619 | memcpy(entry->src, | ||
620 | router->if_incoming->net_dev->dev_addr, | ||
621 | ETH_ALEN); | ||
622 | memcpy(entry->dest, orig_node->orig, ETH_ALEN); | ||
623 | entry->quality = router->tq_avg; | ||
624 | packet->entries++; | ||
625 | |||
626 | next: | ||
627 | batadv_neigh_node_free_ref(router); | ||
628 | |||
629 | if (batadv_vis_packet_full(info)) | ||
630 | goto unlock; | ||
631 | } | ||
632 | rcu_read_unlock(); | ||
633 | } | ||
634 | |||
635 | hash = bat_priv->tt.local_hash; | ||
636 | |||
637 | for (i = 0; i < hash->size; i++) { | ||
638 | head = &hash->table[i]; | ||
639 | |||
640 | rcu_read_lock(); | ||
641 | hlist_for_each_entry_rcu(tt_common_entry, head, | ||
642 | hash_entry) { | ||
643 | packet_pos = skb_put(info->skb_packet, sizeof(*entry)); | ||
644 | entry = (struct batadv_vis_info_entry *)packet_pos; | ||
645 | memset(entry->src, 0, ETH_ALEN); | ||
646 | memcpy(entry->dest, tt_common_entry->addr, ETH_ALEN); | ||
647 | entry->quality = 0; /* 0 means TT */ | ||
648 | packet->entries++; | ||
649 | |||
650 | if (batadv_vis_packet_full(info)) | ||
651 | goto unlock; | ||
652 | } | ||
653 | rcu_read_unlock(); | ||
654 | } | ||
655 | |||
656 | return 0; | ||
657 | |||
658 | unlock: | ||
659 | rcu_read_unlock(); | ||
660 | return 0; | ||
661 | } | ||
662 | |||
663 | /* free old vis packets. Must be called with this vis_hash_lock | ||
664 | * held | ||
665 | */ | ||
666 | static void batadv_purge_vis_packets(struct batadv_priv *bat_priv) | ||
667 | { | ||
668 | uint32_t i; | ||
669 | struct batadv_hashtable *hash = bat_priv->vis.hash; | ||
670 | struct hlist_node *node_tmp; | ||
671 | struct hlist_head *head; | ||
672 | struct batadv_vis_info *info; | ||
673 | |||
674 | for (i = 0; i < hash->size; i++) { | ||
675 | head = &hash->table[i]; | ||
676 | |||
677 | hlist_for_each_entry_safe(info, node_tmp, | ||
678 | head, hash_entry) { | ||
679 | /* never purge own data. */ | ||
680 | if (info == bat_priv->vis.my_info) | ||
681 | continue; | ||
682 | |||
683 | if (batadv_has_timed_out(info->first_seen, | ||
684 | BATADV_VIS_TIMEOUT)) { | ||
685 | hlist_del(&info->hash_entry); | ||
686 | batadv_send_list_del(info); | ||
687 | kref_put(&info->refcount, batadv_free_info); | ||
688 | } | ||
689 | } | ||
690 | } | ||
691 | } | ||
692 | |||
693 | static void batadv_broadcast_vis_packet(struct batadv_priv *bat_priv, | ||
694 | struct batadv_vis_info *info) | ||
695 | { | ||
696 | struct batadv_hashtable *hash = bat_priv->orig_hash; | ||
697 | struct hlist_head *head; | ||
698 | struct batadv_orig_node *orig_node; | ||
699 | struct batadv_vis_packet *packet; | ||
700 | struct sk_buff *skb; | ||
701 | uint32_t i, res; | ||
702 | |||
703 | |||
704 | packet = (struct batadv_vis_packet *)info->skb_packet->data; | ||
705 | |||
706 | /* send to all routers in range. */ | ||
707 | for (i = 0; i < hash->size; i++) { | ||
708 | head = &hash->table[i]; | ||
709 | |||
710 | rcu_read_lock(); | ||
711 | hlist_for_each_entry_rcu(orig_node, head, hash_entry) { | ||
712 | /* if it's a vis server and reachable, send it. */ | ||
713 | if (!(orig_node->flags & BATADV_VIS_SERVER)) | ||
714 | continue; | ||
715 | |||
716 | /* don't send it if we already received the packet from | ||
717 | * this node. | ||
718 | */ | ||
719 | if (batadv_recv_list_is_in(bat_priv, &info->recv_list, | ||
720 | orig_node->orig)) | ||
721 | continue; | ||
722 | |||
723 | memcpy(packet->target_orig, orig_node->orig, ETH_ALEN); | ||
724 | skb = skb_clone(info->skb_packet, GFP_ATOMIC); | ||
725 | if (!skb) | ||
726 | continue; | ||
727 | |||
728 | res = batadv_send_skb_to_orig(skb, orig_node, NULL); | ||
729 | if (res == NET_XMIT_DROP) | ||
730 | kfree_skb(skb); | ||
731 | } | ||
732 | rcu_read_unlock(); | ||
733 | } | ||
734 | } | ||
735 | |||
736 | static void batadv_unicast_vis_packet(struct batadv_priv *bat_priv, | ||
737 | struct batadv_vis_info *info) | ||
738 | { | ||
739 | struct batadv_orig_node *orig_node; | ||
740 | struct sk_buff *skb; | ||
741 | struct batadv_vis_packet *packet; | ||
742 | |||
743 | packet = (struct batadv_vis_packet *)info->skb_packet->data; | ||
744 | |||
745 | orig_node = batadv_orig_hash_find(bat_priv, packet->target_orig); | ||
746 | if (!orig_node) | ||
747 | goto out; | ||
748 | |||
749 | skb = skb_clone(info->skb_packet, GFP_ATOMIC); | ||
750 | if (!skb) | ||
751 | goto out; | ||
752 | |||
753 | if (batadv_send_skb_to_orig(skb, orig_node, NULL) == NET_XMIT_DROP) | ||
754 | kfree_skb(skb); | ||
755 | |||
756 | out: | ||
757 | if (orig_node) | ||
758 | batadv_orig_node_free_ref(orig_node); | ||
759 | } | ||
760 | |||
761 | /* only send one vis packet. called from batadv_send_vis_packets() */ | ||
762 | static void batadv_send_vis_packet(struct batadv_priv *bat_priv, | ||
763 | struct batadv_vis_info *info) | ||
764 | { | ||
765 | struct batadv_hard_iface *primary_if; | ||
766 | struct batadv_vis_packet *packet; | ||
767 | |||
768 | primary_if = batadv_primary_if_get_selected(bat_priv); | ||
769 | if (!primary_if) | ||
770 | goto out; | ||
771 | |||
772 | packet = (struct batadv_vis_packet *)info->skb_packet->data; | ||
773 | if (packet->header.ttl < 2) { | ||
774 | pr_debug("Error - can't send vis packet: ttl exceeded\n"); | ||
775 | goto out; | ||
776 | } | ||
777 | |||
778 | memcpy(packet->sender_orig, primary_if->net_dev->dev_addr, ETH_ALEN); | ||
779 | packet->header.ttl--; | ||
780 | |||
781 | if (is_broadcast_ether_addr(packet->target_orig)) | ||
782 | batadv_broadcast_vis_packet(bat_priv, info); | ||
783 | else | ||
784 | batadv_unicast_vis_packet(bat_priv, info); | ||
785 | packet->header.ttl++; /* restore TTL */ | ||
786 | |||
787 | out: | ||
788 | if (primary_if) | ||
789 | batadv_hardif_free_ref(primary_if); | ||
790 | } | ||
791 | |||
792 | /* called from timer; send (and maybe generate) vis packet. */ | ||
793 | static void batadv_send_vis_packets(struct work_struct *work) | ||
794 | { | ||
795 | struct delayed_work *delayed_work; | ||
796 | struct batadv_priv *bat_priv; | ||
797 | struct batadv_priv_vis *priv_vis; | ||
798 | struct batadv_vis_info *info; | ||
799 | |||
800 | delayed_work = container_of(work, struct delayed_work, work); | ||
801 | priv_vis = container_of(delayed_work, struct batadv_priv_vis, work); | ||
802 | bat_priv = container_of(priv_vis, struct batadv_priv, vis); | ||
803 | spin_lock_bh(&bat_priv->vis.hash_lock); | ||
804 | batadv_purge_vis_packets(bat_priv); | ||
805 | |||
806 | if (batadv_generate_vis_packet(bat_priv) == 0) { | ||
807 | /* schedule if generation was successful */ | ||
808 | batadv_send_list_add(bat_priv, bat_priv->vis.my_info); | ||
809 | } | ||
810 | |||
811 | while (!list_empty(&bat_priv->vis.send_list)) { | ||
812 | info = list_first_entry(&bat_priv->vis.send_list, | ||
813 | typeof(*info), send_list); | ||
814 | |||
815 | kref_get(&info->refcount); | ||
816 | spin_unlock_bh(&bat_priv->vis.hash_lock); | ||
817 | |||
818 | batadv_send_vis_packet(bat_priv, info); | ||
819 | |||
820 | spin_lock_bh(&bat_priv->vis.hash_lock); | ||
821 | batadv_send_list_del(info); | ||
822 | kref_put(&info->refcount, batadv_free_info); | ||
823 | } | ||
824 | spin_unlock_bh(&bat_priv->vis.hash_lock); | ||
825 | |||
826 | queue_delayed_work(batadv_event_workqueue, &bat_priv->vis.work, | ||
827 | msecs_to_jiffies(BATADV_VIS_INTERVAL)); | ||
828 | } | ||
829 | |||
830 | /* init the vis server. this may only be called when if_list is already | ||
831 | * initialized (e.g. bat0 is initialized, interfaces have been added) | ||
832 | */ | ||
833 | int batadv_vis_init(struct batadv_priv *bat_priv) | ||
834 | { | ||
835 | struct batadv_vis_packet *packet; | ||
836 | int hash_added; | ||
837 | unsigned int len; | ||
838 | unsigned long first_seen; | ||
839 | struct sk_buff *tmp_skb; | ||
840 | |||
841 | if (bat_priv->vis.hash) | ||
842 | return 0; | ||
843 | |||
844 | spin_lock_bh(&bat_priv->vis.hash_lock); | ||
845 | |||
846 | bat_priv->vis.hash = batadv_hash_new(256); | ||
847 | if (!bat_priv->vis.hash) { | ||
848 | pr_err("Can't initialize vis_hash\n"); | ||
849 | goto err; | ||
850 | } | ||
851 | |||
852 | batadv_hash_set_lock_class(bat_priv->vis.hash, | ||
853 | &batadv_vis_hash_lock_class_key); | ||
854 | |||
855 | bat_priv->vis.my_info = kmalloc(BATADV_MAX_VIS_PACKET_SIZE, GFP_ATOMIC); | ||
856 | if (!bat_priv->vis.my_info) | ||
857 | goto err; | ||
858 | |||
859 | len = sizeof(*packet) + BATADV_MAX_VIS_PACKET_SIZE + ETH_HLEN; | ||
860 | bat_priv->vis.my_info->skb_packet = netdev_alloc_skb_ip_align(NULL, | ||
861 | len); | ||
862 | if (!bat_priv->vis.my_info->skb_packet) | ||
863 | goto free_info; | ||
864 | |||
865 | bat_priv->vis.my_info->skb_packet->priority = TC_PRIO_CONTROL; | ||
866 | skb_reserve(bat_priv->vis.my_info->skb_packet, ETH_HLEN); | ||
867 | tmp_skb = bat_priv->vis.my_info->skb_packet; | ||
868 | packet = (struct batadv_vis_packet *)skb_put(tmp_skb, sizeof(*packet)); | ||
869 | |||
870 | /* prefill the vis info */ | ||
871 | first_seen = jiffies - msecs_to_jiffies(BATADV_VIS_INTERVAL); | ||
872 | bat_priv->vis.my_info->first_seen = first_seen; | ||
873 | INIT_LIST_HEAD(&bat_priv->vis.my_info->recv_list); | ||
874 | INIT_LIST_HEAD(&bat_priv->vis.my_info->send_list); | ||
875 | kref_init(&bat_priv->vis.my_info->refcount); | ||
876 | bat_priv->vis.my_info->bat_priv = bat_priv; | ||
877 | packet->header.version = BATADV_COMPAT_VERSION; | ||
878 | packet->header.packet_type = BATADV_VIS; | ||
879 | packet->header.ttl = BATADV_TTL; | ||
880 | packet->seqno = 0; | ||
881 | packet->reserved = 0; | ||
882 | packet->entries = 0; | ||
883 | |||
884 | INIT_LIST_HEAD(&bat_priv->vis.send_list); | ||
885 | |||
886 | hash_added = batadv_hash_add(bat_priv->vis.hash, batadv_vis_info_cmp, | ||
887 | batadv_vis_info_choose, | ||
888 | bat_priv->vis.my_info, | ||
889 | &bat_priv->vis.my_info->hash_entry); | ||
890 | if (hash_added != 0) { | ||
891 | pr_err("Can't add own vis packet into hash\n"); | ||
892 | /* not in hash, need to remove it manually. */ | ||
893 | kref_put(&bat_priv->vis.my_info->refcount, batadv_free_info); | ||
894 | goto err; | ||
895 | } | ||
896 | |||
897 | spin_unlock_bh(&bat_priv->vis.hash_lock); | ||
898 | |||
899 | INIT_DELAYED_WORK(&bat_priv->vis.work, batadv_send_vis_packets); | ||
900 | queue_delayed_work(batadv_event_workqueue, &bat_priv->vis.work, | ||
901 | msecs_to_jiffies(BATADV_VIS_INTERVAL)); | ||
902 | |||
903 | return 0; | ||
904 | |||
905 | free_info: | ||
906 | kfree(bat_priv->vis.my_info); | ||
907 | bat_priv->vis.my_info = NULL; | ||
908 | err: | ||
909 | spin_unlock_bh(&bat_priv->vis.hash_lock); | ||
910 | batadv_vis_quit(bat_priv); | ||
911 | return -ENOMEM; | ||
912 | } | ||
913 | |||
914 | /* Decrease the reference count on a hash item info */ | ||
915 | static void batadv_free_info_ref(struct hlist_node *node, void *arg) | ||
916 | { | ||
917 | struct batadv_vis_info *info; | ||
918 | |||
919 | info = container_of(node, struct batadv_vis_info, hash_entry); | ||
920 | batadv_send_list_del(info); | ||
921 | kref_put(&info->refcount, batadv_free_info); | ||
922 | } | ||
923 | |||
924 | /* shutdown vis-server */ | ||
925 | void batadv_vis_quit(struct batadv_priv *bat_priv) | ||
926 | { | ||
927 | if (!bat_priv->vis.hash) | ||
928 | return; | ||
929 | |||
930 | cancel_delayed_work_sync(&bat_priv->vis.work); | ||
931 | |||
932 | spin_lock_bh(&bat_priv->vis.hash_lock); | ||
933 | /* properly remove, kill timers ... */ | ||
934 | batadv_hash_delete(bat_priv->vis.hash, batadv_free_info_ref, NULL); | ||
935 | bat_priv->vis.hash = NULL; | ||
936 | bat_priv->vis.my_info = NULL; | ||
937 | spin_unlock_bh(&bat_priv->vis.hash_lock); | ||
938 | } | ||
diff --git a/net/batman-adv/vis.h b/net/batman-adv/vis.h deleted file mode 100644 index ad92b0e3c230..000000000000 --- a/net/batman-adv/vis.h +++ /dev/null | |||
@@ -1,36 +0,0 @@ | |||
1 | /* Copyright (C) 2008-2013 B.A.T.M.A.N. contributors: | ||
2 | * | ||
3 | * Simon Wunderlich, Marek Lindner | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of version 2 of the GNU General Public | ||
7 | * License as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, but | ||
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | * General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
17 | * 02110-1301, USA | ||
18 | */ | ||
19 | |||
20 | #ifndef _NET_BATMAN_ADV_VIS_H_ | ||
21 | #define _NET_BATMAN_ADV_VIS_H_ | ||
22 | |||
23 | /* timeout of vis packets in milliseconds */ | ||
24 | #define BATADV_VIS_TIMEOUT 200000 | ||
25 | |||
26 | int batadv_vis_seq_print_text(struct seq_file *seq, void *offset); | ||
27 | void batadv_receive_server_sync_packet(struct batadv_priv *bat_priv, | ||
28 | struct batadv_vis_packet *vis_packet, | ||
29 | int vis_info_len); | ||
30 | void batadv_receive_client_update_packet(struct batadv_priv *bat_priv, | ||
31 | struct batadv_vis_packet *vis_packet, | ||
32 | int vis_info_len); | ||
33 | int batadv_vis_init(struct batadv_priv *bat_priv); | ||
34 | void batadv_vis_quit(struct batadv_priv *bat_priv); | ||
35 | |||
36 | #endif /* _NET_BATMAN_ADV_VIS_H_ */ | ||