diff options
Diffstat (limited to 'net/batman-adv/routing.c')
-rw-r--r-- | net/batman-adv/routing.c | 317 |
1 files changed, 262 insertions, 55 deletions
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index 934f1f2f86c6..0ce090c9fe86 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c | |||
@@ -64,27 +64,57 @@ void slide_own_bcast_window(struct hard_iface *hard_iface) | |||
64 | } | 64 | } |
65 | } | 65 | } |
66 | 66 | ||
67 | static void update_TT(struct bat_priv *bat_priv, struct orig_node *orig_node, | 67 | static void update_transtable(struct bat_priv *bat_priv, |
68 | const unsigned char *tt_buff, int tt_buff_len) | 68 | struct orig_node *orig_node, |
69 | const unsigned char *tt_buff, | ||
70 | uint8_t tt_num_changes, uint8_t ttvn, | ||
71 | uint16_t tt_crc) | ||
69 | { | 72 | { |
70 | if ((tt_buff_len != orig_node->tt_buff_len) || | 73 | uint8_t orig_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn); |
71 | ((tt_buff_len > 0) && | 74 | bool full_table = true; |
72 | (orig_node->tt_buff_len > 0) && | 75 | |
73 | (memcmp(orig_node->tt_buff, tt_buff, tt_buff_len) != 0))) { | 76 | /* the ttvn increased by one -> we can apply the attached changes */ |
74 | 77 | if (ttvn - orig_ttvn == 1) { | |
75 | if (orig_node->tt_buff_len > 0) | 78 | /* the OGM could not contain the changes because they were too |
76 | tt_global_del_orig(bat_priv, orig_node, | 79 | * many to fit in one frame or because they have already been |
77 | "originator changed tt"); | 80 | * sent TT_OGM_APPEND_MAX times. In this case send a tt |
78 | 81 | * request */ | |
79 | if ((tt_buff_len > 0) && (tt_buff)) | 82 | if (!tt_num_changes) { |
80 | tt_global_add_orig(bat_priv, orig_node, | 83 | full_table = false; |
81 | tt_buff, tt_buff_len); | 84 | goto request_table; |
85 | } | ||
86 | |||
87 | tt_update_changes(bat_priv, orig_node, tt_num_changes, ttvn, | ||
88 | (struct tt_change *)tt_buff); | ||
89 | |||
90 | /* Even if we received the crc into the OGM, we prefer | ||
91 | * to recompute it to spot any possible inconsistency | ||
92 | * in the global table */ | ||
93 | orig_node->tt_crc = tt_global_crc(bat_priv, orig_node); | ||
94 | /* Roaming phase is over: tables are in sync again. I can | ||
95 | * unset the flag */ | ||
96 | orig_node->tt_poss_change = false; | ||
97 | } else { | ||
98 | /* if we missed more than one change or our tables are not | ||
99 | * in sync anymore -> request fresh tt data */ | ||
100 | if (ttvn != orig_ttvn || orig_node->tt_crc != tt_crc) { | ||
101 | request_table: | ||
102 | bat_dbg(DBG_TT, bat_priv, "TT inconsistency for %pM. " | ||
103 | "Need to retrieve the correct information " | ||
104 | "(ttvn: %u last_ttvn: %u crc: %u last_crc: " | ||
105 | "%u num_changes: %u)\n", orig_node->orig, ttvn, | ||
106 | orig_ttvn, tt_crc, orig_node->tt_crc, | ||
107 | tt_num_changes); | ||
108 | send_tt_request(bat_priv, orig_node, ttvn, tt_crc, | ||
109 | full_table); | ||
110 | return; | ||
111 | } | ||
82 | } | 112 | } |
83 | } | 113 | } |
84 | 114 | ||
85 | static void update_route(struct bat_priv *bat_priv, struct orig_node *orig_node, | 115 | static void update_route(struct bat_priv *bat_priv, |
86 | struct neigh_node *neigh_node, | 116 | struct orig_node *orig_node, |
87 | const unsigned char *tt_buff, int tt_buff_len) | 117 | struct neigh_node *neigh_node) |
88 | { | 118 | { |
89 | struct neigh_node *curr_router; | 119 | struct neigh_node *curr_router; |
90 | 120 | ||
@@ -92,11 +122,10 @@ static void update_route(struct bat_priv *bat_priv, struct orig_node *orig_node, | |||
92 | 122 | ||
93 | /* route deleted */ | 123 | /* route deleted */ |
94 | if ((curr_router) && (!neigh_node)) { | 124 | if ((curr_router) && (!neigh_node)) { |
95 | |||
96 | bat_dbg(DBG_ROUTES, bat_priv, "Deleting route towards: %pM\n", | 125 | bat_dbg(DBG_ROUTES, bat_priv, "Deleting route towards: %pM\n", |
97 | orig_node->orig); | 126 | orig_node->orig); |
98 | tt_global_del_orig(bat_priv, orig_node, | 127 | tt_global_del_orig(bat_priv, orig_node, |
99 | "originator timed out"); | 128 | "Deleted route towards originator"); |
100 | 129 | ||
101 | /* route added */ | 130 | /* route added */ |
102 | } else if ((!curr_router) && (neigh_node)) { | 131 | } else if ((!curr_router) && (neigh_node)) { |
@@ -104,9 +133,6 @@ static void update_route(struct bat_priv *bat_priv, struct orig_node *orig_node, | |||
104 | bat_dbg(DBG_ROUTES, bat_priv, | 133 | bat_dbg(DBG_ROUTES, bat_priv, |
105 | "Adding route towards: %pM (via %pM)\n", | 134 | "Adding route towards: %pM (via %pM)\n", |
106 | orig_node->orig, neigh_node->addr); | 135 | orig_node->orig, neigh_node->addr); |
107 | tt_global_add_orig(bat_priv, orig_node, | ||
108 | tt_buff, tt_buff_len); | ||
109 | |||
110 | /* route changed */ | 136 | /* route changed */ |
111 | } else if (neigh_node && curr_router) { | 137 | } else if (neigh_node && curr_router) { |
112 | bat_dbg(DBG_ROUTES, bat_priv, | 138 | bat_dbg(DBG_ROUTES, bat_priv, |
@@ -133,8 +159,7 @@ static void update_route(struct bat_priv *bat_priv, struct orig_node *orig_node, | |||
133 | } | 159 | } |
134 | 160 | ||
135 | void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_node, | 161 | void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_node, |
136 | struct neigh_node *neigh_node, const unsigned char *tt_buff, | 162 | struct neigh_node *neigh_node) |
137 | int tt_buff_len) | ||
138 | { | 163 | { |
139 | struct neigh_node *router = NULL; | 164 | struct neigh_node *router = NULL; |
140 | 165 | ||
@@ -144,11 +169,7 @@ void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_node, | |||
144 | router = orig_node_get_router(orig_node); | 169 | router = orig_node_get_router(orig_node); |
145 | 170 | ||
146 | if (router != neigh_node) | 171 | if (router != neigh_node) |
147 | update_route(bat_priv, orig_node, neigh_node, | 172 | update_route(bat_priv, orig_node, neigh_node); |
148 | tt_buff, tt_buff_len); | ||
149 | /* may be just TT changed */ | ||
150 | else | ||
151 | update_TT(bat_priv, orig_node, tt_buff, tt_buff_len); | ||
152 | 173 | ||
153 | out: | 174 | out: |
154 | if (router) | 175 | if (router) |
@@ -163,7 +184,7 @@ static int is_bidirectional_neigh(struct orig_node *orig_node, | |||
163 | struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface); | 184 | struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface); |
164 | struct neigh_node *neigh_node = NULL, *tmp_neigh_node; | 185 | struct neigh_node *neigh_node = NULL, *tmp_neigh_node; |
165 | struct hlist_node *node; | 186 | struct hlist_node *node; |
166 | unsigned char total_count; | 187 | uint8_t total_count; |
167 | uint8_t orig_eq_count, neigh_rq_count, tq_own; | 188 | uint8_t orig_eq_count, neigh_rq_count, tq_own; |
168 | int tq_asym_penalty, ret = 0; | 189 | int tq_asym_penalty, ret = 0; |
169 | 190 | ||
@@ -360,14 +381,12 @@ static void update_orig(struct bat_priv *bat_priv, struct orig_node *orig_node, | |||
360 | const struct ethhdr *ethhdr, | 381 | const struct ethhdr *ethhdr, |
361 | const struct batman_packet *batman_packet, | 382 | const struct batman_packet *batman_packet, |
362 | struct hard_iface *if_incoming, | 383 | struct hard_iface *if_incoming, |
363 | const unsigned char *tt_buff, int tt_buff_len, | 384 | const unsigned char *tt_buff, int is_duplicate) |
364 | char is_duplicate) | ||
365 | { | 385 | { |
366 | struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL; | 386 | struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL; |
367 | struct neigh_node *router = NULL; | 387 | struct neigh_node *router = NULL; |
368 | struct orig_node *orig_node_tmp; | 388 | struct orig_node *orig_node_tmp; |
369 | struct hlist_node *node; | 389 | struct hlist_node *node; |
370 | int tmp_tt_buff_len; | ||
371 | uint8_t bcast_own_sum_orig, bcast_own_sum_neigh; | 390 | uint8_t bcast_own_sum_orig, bcast_own_sum_neigh; |
372 | 391 | ||
373 | bat_dbg(DBG_BATMAN, bat_priv, "update_originator(): " | 392 | bat_dbg(DBG_BATMAN, bat_priv, "update_originator(): " |
@@ -432,9 +451,6 @@ static void update_orig(struct bat_priv *bat_priv, struct orig_node *orig_node, | |||
432 | 451 | ||
433 | bonding_candidate_add(orig_node, neigh_node); | 452 | bonding_candidate_add(orig_node, neigh_node); |
434 | 453 | ||
435 | tmp_tt_buff_len = (tt_buff_len > batman_packet->num_tt * ETH_ALEN ? | ||
436 | batman_packet->num_tt * ETH_ALEN : tt_buff_len); | ||
437 | |||
438 | /* if this neighbor already is our next hop there is nothing | 454 | /* if this neighbor already is our next hop there is nothing |
439 | * to change */ | 455 | * to change */ |
440 | router = orig_node_get_router(orig_node); | 456 | router = orig_node_get_router(orig_node); |
@@ -464,15 +480,19 @@ static void update_orig(struct bat_priv *bat_priv, struct orig_node *orig_node, | |||
464 | goto update_tt; | 480 | goto update_tt; |
465 | } | 481 | } |
466 | 482 | ||
467 | update_routes(bat_priv, orig_node, neigh_node, | 483 | update_routes(bat_priv, orig_node, neigh_node); |
468 | tt_buff, tmp_tt_buff_len); | ||
469 | goto update_gw; | ||
470 | 484 | ||
471 | update_tt: | 485 | update_tt: |
472 | update_routes(bat_priv, orig_node, router, | 486 | /* I have to check for transtable changes only if the OGM has been |
473 | tt_buff, tmp_tt_buff_len); | 487 | * sent through a primary interface */ |
488 | if (((batman_packet->orig != ethhdr->h_source) && | ||
489 | (batman_packet->ttl > 2)) || | ||
490 | (batman_packet->flags & PRIMARIES_FIRST_HOP)) | ||
491 | update_transtable(bat_priv, orig_node, tt_buff, | ||
492 | batman_packet->tt_num_changes, | ||
493 | batman_packet->ttvn, | ||
494 | batman_packet->tt_crc); | ||
474 | 495 | ||
475 | update_gw: | ||
476 | if (orig_node->gw_flags != batman_packet->gw_flags) | 496 | if (orig_node->gw_flags != batman_packet->gw_flags) |
477 | gw_node_update(bat_priv, orig_node, batman_packet->gw_flags); | 497 | gw_node_update(bat_priv, orig_node, batman_packet->gw_flags); |
478 | 498 | ||
@@ -528,7 +548,7 @@ static int window_protected(struct bat_priv *bat_priv, | |||
528 | * -1 the packet is old and has been received while the seqno window | 548 | * -1 the packet is old and has been received while the seqno window |
529 | * was protected. Caller should drop it. | 549 | * was protected. Caller should drop it. |
530 | */ | 550 | */ |
531 | static char count_real_packets(const struct ethhdr *ethhdr, | 551 | static int count_real_packets(const struct ethhdr *ethhdr, |
532 | const struct batman_packet *batman_packet, | 552 | const struct batman_packet *batman_packet, |
533 | const struct hard_iface *if_incoming) | 553 | const struct hard_iface *if_incoming) |
534 | { | 554 | { |
@@ -536,7 +556,7 @@ static char count_real_packets(const struct ethhdr *ethhdr, | |||
536 | struct orig_node *orig_node; | 556 | struct orig_node *orig_node; |
537 | struct neigh_node *tmp_neigh_node; | 557 | struct neigh_node *tmp_neigh_node; |
538 | struct hlist_node *node; | 558 | struct hlist_node *node; |
539 | char is_duplicate = 0; | 559 | int is_duplicate = 0; |
540 | int32_t seq_diff; | 560 | int32_t seq_diff; |
541 | int need_update = 0; | 561 | int need_update = 0; |
542 | int set_mark, ret = -1; | 562 | int set_mark, ret = -1; |
@@ -594,7 +614,7 @@ out: | |||
594 | 614 | ||
595 | void receive_bat_packet(const struct ethhdr *ethhdr, | 615 | void receive_bat_packet(const struct ethhdr *ethhdr, |
596 | struct batman_packet *batman_packet, | 616 | struct batman_packet *batman_packet, |
597 | const unsigned char *tt_buff, int tt_buff_len, | 617 | const unsigned char *tt_buff, |
598 | struct hard_iface *if_incoming) | 618 | struct hard_iface *if_incoming) |
599 | { | 619 | { |
600 | struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface); | 620 | struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface); |
@@ -602,10 +622,10 @@ void receive_bat_packet(const struct ethhdr *ethhdr, | |||
602 | struct orig_node *orig_neigh_node, *orig_node; | 622 | struct orig_node *orig_neigh_node, *orig_node; |
603 | struct neigh_node *router = NULL, *router_router = NULL; | 623 | struct neigh_node *router = NULL, *router_router = NULL; |
604 | struct neigh_node *orig_neigh_router = NULL; | 624 | struct neigh_node *orig_neigh_router = NULL; |
605 | char has_directlink_flag; | 625 | int has_directlink_flag; |
606 | char is_my_addr = 0, is_my_orig = 0, is_my_oldorig = 0; | 626 | int is_my_addr = 0, is_my_orig = 0, is_my_oldorig = 0; |
607 | char is_broadcast = 0, is_bidirectional, is_single_hop_neigh; | 627 | int is_broadcast = 0, is_bidirectional, is_single_hop_neigh; |
608 | char is_duplicate; | 628 | int is_duplicate; |
609 | uint32_t if_incoming_seqno; | 629 | uint32_t if_incoming_seqno; |
610 | 630 | ||
611 | /* Silently drop when the batman packet is actually not a | 631 | /* Silently drop when the batman packet is actually not a |
@@ -633,12 +653,14 @@ void receive_bat_packet(const struct ethhdr *ethhdr, | |||
633 | 653 | ||
634 | bat_dbg(DBG_BATMAN, bat_priv, | 654 | bat_dbg(DBG_BATMAN, bat_priv, |
635 | "Received BATMAN packet via NB: %pM, IF: %s [%pM] " | 655 | "Received BATMAN packet via NB: %pM, IF: %s [%pM] " |
636 | "(from OG: %pM, via prev OG: %pM, seqno %d, tq %d, " | 656 | "(from OG: %pM, via prev OG: %pM, seqno %d, ttvn %u, " |
637 | "TTL %d, V %d, IDF %d)\n", | 657 | "crc %u, changes %u, td %d, TTL %d, V %d, IDF %d)\n", |
638 | ethhdr->h_source, if_incoming->net_dev->name, | 658 | ethhdr->h_source, if_incoming->net_dev->name, |
639 | if_incoming->net_dev->dev_addr, batman_packet->orig, | 659 | if_incoming->net_dev->dev_addr, batman_packet->orig, |
640 | batman_packet->prev_sender, batman_packet->seqno, | 660 | batman_packet->prev_sender, batman_packet->seqno, |
641 | batman_packet->tq, batman_packet->ttl, batman_packet->version, | 661 | batman_packet->ttvn, batman_packet->tt_crc, |
662 | batman_packet->tt_num_changes, batman_packet->tq, | ||
663 | batman_packet->ttl, batman_packet->version, | ||
642 | has_directlink_flag); | 664 | has_directlink_flag); |
643 | 665 | ||
644 | rcu_read_lock(); | 666 | rcu_read_lock(); |
@@ -790,14 +812,14 @@ void receive_bat_packet(const struct ethhdr *ethhdr, | |||
790 | ((orig_node->last_real_seqno == batman_packet->seqno) && | 812 | ((orig_node->last_real_seqno == batman_packet->seqno) && |
791 | (orig_node->last_ttl - 3 <= batman_packet->ttl)))) | 813 | (orig_node->last_ttl - 3 <= batman_packet->ttl)))) |
792 | update_orig(bat_priv, orig_node, ethhdr, batman_packet, | 814 | update_orig(bat_priv, orig_node, ethhdr, batman_packet, |
793 | if_incoming, tt_buff, tt_buff_len, is_duplicate); | 815 | if_incoming, tt_buff, is_duplicate); |
794 | 816 | ||
795 | /* is single hop (direct) neighbor */ | 817 | /* is single hop (direct) neighbor */ |
796 | if (is_single_hop_neigh) { | 818 | if (is_single_hop_neigh) { |
797 | 819 | ||
798 | /* mark direct link on incoming interface */ | 820 | /* mark direct link on incoming interface */ |
799 | schedule_forward_packet(orig_node, ethhdr, batman_packet, | 821 | schedule_forward_packet(orig_node, ethhdr, batman_packet, |
800 | 1, tt_buff_len, if_incoming); | 822 | 1, if_incoming); |
801 | 823 | ||
802 | bat_dbg(DBG_BATMAN, bat_priv, "Forwarding packet: " | 824 | bat_dbg(DBG_BATMAN, bat_priv, "Forwarding packet: " |
803 | "rebroadcast neighbor packet with direct link flag\n"); | 825 | "rebroadcast neighbor packet with direct link flag\n"); |
@@ -820,7 +842,7 @@ void receive_bat_packet(const struct ethhdr *ethhdr, | |||
820 | bat_dbg(DBG_BATMAN, bat_priv, | 842 | bat_dbg(DBG_BATMAN, bat_priv, |
821 | "Forwarding packet: rebroadcast originator packet\n"); | 843 | "Forwarding packet: rebroadcast originator packet\n"); |
822 | schedule_forward_packet(orig_node, ethhdr, batman_packet, | 844 | schedule_forward_packet(orig_node, ethhdr, batman_packet, |
823 | 0, tt_buff_len, if_incoming); | 845 | 0, if_incoming); |
824 | 846 | ||
825 | out_neigh: | 847 | out_neigh: |
826 | if ((orig_neigh_node) && (!is_single_hop_neigh)) | 848 | if ((orig_neigh_node) && (!is_single_hop_neigh)) |
@@ -1167,6 +1189,118 @@ static struct neigh_node *find_ifalter_router(struct orig_node *primary_orig, | |||
1167 | return router; | 1189 | return router; |
1168 | } | 1190 | } |
1169 | 1191 | ||
1192 | int recv_tt_query(struct sk_buff *skb, struct hard_iface *recv_if) | ||
1193 | { | ||
1194 | struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface); | ||
1195 | struct tt_query_packet *tt_query; | ||
1196 | struct ethhdr *ethhdr; | ||
1197 | |||
1198 | /* drop packet if it has not necessary minimum size */ | ||
1199 | if (unlikely(!pskb_may_pull(skb, sizeof(struct tt_query_packet)))) | ||
1200 | goto out; | ||
1201 | |||
1202 | /* I could need to modify it */ | ||
1203 | if (skb_cow(skb, sizeof(struct tt_query_packet)) < 0) | ||
1204 | goto out; | ||
1205 | |||
1206 | ethhdr = (struct ethhdr *)skb_mac_header(skb); | ||
1207 | |||
1208 | /* packet with unicast indication but broadcast recipient */ | ||
1209 | if (is_broadcast_ether_addr(ethhdr->h_dest)) | ||
1210 | goto out; | ||
1211 | |||
1212 | /* packet with broadcast sender address */ | ||
1213 | if (is_broadcast_ether_addr(ethhdr->h_source)) | ||
1214 | goto out; | ||
1215 | |||
1216 | tt_query = (struct tt_query_packet *)skb->data; | ||
1217 | |||
1218 | tt_query->tt_data = ntohs(tt_query->tt_data); | ||
1219 | |||
1220 | switch (tt_query->flags & TT_QUERY_TYPE_MASK) { | ||
1221 | case TT_REQUEST: | ||
1222 | /* If we cannot provide an answer the tt_request is | ||
1223 | * forwarded */ | ||
1224 | if (!send_tt_response(bat_priv, tt_query)) { | ||
1225 | bat_dbg(DBG_TT, bat_priv, | ||
1226 | "Routing TT_REQUEST to %pM [%c]\n", | ||
1227 | tt_query->dst, | ||
1228 | (tt_query->flags & TT_FULL_TABLE ? 'F' : '.')); | ||
1229 | tt_query->tt_data = htons(tt_query->tt_data); | ||
1230 | return route_unicast_packet(skb, recv_if); | ||
1231 | } | ||
1232 | break; | ||
1233 | case TT_RESPONSE: | ||
1234 | /* packet needs to be linearised to access the TT changes */ | ||
1235 | if (skb_linearize(skb) < 0) | ||
1236 | goto out; | ||
1237 | |||
1238 | if (is_my_mac(tt_query->dst)) | ||
1239 | handle_tt_response(bat_priv, tt_query); | ||
1240 | else { | ||
1241 | bat_dbg(DBG_TT, bat_priv, | ||
1242 | "Routing TT_RESPONSE to %pM [%c]\n", | ||
1243 | tt_query->dst, | ||
1244 | (tt_query->flags & TT_FULL_TABLE ? 'F' : '.')); | ||
1245 | tt_query->tt_data = htons(tt_query->tt_data); | ||
1246 | return route_unicast_packet(skb, recv_if); | ||
1247 | } | ||
1248 | break; | ||
1249 | } | ||
1250 | |||
1251 | out: | ||
1252 | /* returning NET_RX_DROP will make the caller function kfree the skb */ | ||
1253 | return NET_RX_DROP; | ||
1254 | } | ||
1255 | |||
1256 | int recv_roam_adv(struct sk_buff *skb, struct hard_iface *recv_if) | ||
1257 | { | ||
1258 | struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface); | ||
1259 | struct roam_adv_packet *roam_adv_packet; | ||
1260 | struct orig_node *orig_node; | ||
1261 | struct ethhdr *ethhdr; | ||
1262 | |||
1263 | /* drop packet if it has not necessary minimum size */ | ||
1264 | if (unlikely(!pskb_may_pull(skb, sizeof(struct roam_adv_packet)))) | ||
1265 | goto out; | ||
1266 | |||
1267 | ethhdr = (struct ethhdr *)skb_mac_header(skb); | ||
1268 | |||
1269 | /* packet with unicast indication but broadcast recipient */ | ||
1270 | if (is_broadcast_ether_addr(ethhdr->h_dest)) | ||
1271 | goto out; | ||
1272 | |||
1273 | /* packet with broadcast sender address */ | ||
1274 | if (is_broadcast_ether_addr(ethhdr->h_source)) | ||
1275 | goto out; | ||
1276 | |||
1277 | roam_adv_packet = (struct roam_adv_packet *)skb->data; | ||
1278 | |||
1279 | if (!is_my_mac(roam_adv_packet->dst)) | ||
1280 | return route_unicast_packet(skb, recv_if); | ||
1281 | |||
1282 | orig_node = orig_hash_find(bat_priv, roam_adv_packet->src); | ||
1283 | if (!orig_node) | ||
1284 | goto out; | ||
1285 | |||
1286 | bat_dbg(DBG_TT, bat_priv, "Received ROAMING_ADV from %pM " | ||
1287 | "(client %pM)\n", roam_adv_packet->src, | ||
1288 | roam_adv_packet->client); | ||
1289 | |||
1290 | tt_global_add(bat_priv, orig_node, roam_adv_packet->client, | ||
1291 | atomic_read(&orig_node->last_ttvn) + 1, true); | ||
1292 | |||
1293 | /* Roaming phase starts: I have new information but the ttvn has not | ||
1294 | * been incremented yet. This flag will make me check all the incoming | ||
1295 | * packets for the correct destination. */ | ||
1296 | bat_priv->tt_poss_change = true; | ||
1297 | |||
1298 | orig_node_free_ref(orig_node); | ||
1299 | out: | ||
1300 | /* returning NET_RX_DROP will make the caller function kfree the skb */ | ||
1301 | return NET_RX_DROP; | ||
1302 | } | ||
1303 | |||
1170 | /* find a suitable router for this originator, and use | 1304 | /* find a suitable router for this originator, and use |
1171 | * bonding if possible. increases the found neighbors | 1305 | * bonding if possible. increases the found neighbors |
1172 | * refcount.*/ | 1306 | * refcount.*/ |
@@ -1353,14 +1487,84 @@ out: | |||
1353 | return ret; | 1487 | return ret; |
1354 | } | 1488 | } |
1355 | 1489 | ||
1490 | static int check_unicast_ttvn(struct bat_priv *bat_priv, | ||
1491 | struct sk_buff *skb) { | ||
1492 | uint8_t curr_ttvn; | ||
1493 | struct orig_node *orig_node; | ||
1494 | struct ethhdr *ethhdr; | ||
1495 | struct hard_iface *primary_if; | ||
1496 | struct unicast_packet *unicast_packet; | ||
1497 | bool tt_poss_change; | ||
1498 | |||
1499 | /* I could need to modify it */ | ||
1500 | if (skb_cow(skb, sizeof(struct unicast_packet)) < 0) | ||
1501 | return 0; | ||
1502 | |||
1503 | unicast_packet = (struct unicast_packet *)skb->data; | ||
1504 | |||
1505 | if (is_my_mac(unicast_packet->dest)) { | ||
1506 | tt_poss_change = bat_priv->tt_poss_change; | ||
1507 | curr_ttvn = (uint8_t)atomic_read(&bat_priv->ttvn); | ||
1508 | } else { | ||
1509 | orig_node = orig_hash_find(bat_priv, unicast_packet->dest); | ||
1510 | |||
1511 | if (!orig_node) | ||
1512 | return 0; | ||
1513 | |||
1514 | curr_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn); | ||
1515 | tt_poss_change = orig_node->tt_poss_change; | ||
1516 | orig_node_free_ref(orig_node); | ||
1517 | } | ||
1518 | |||
1519 | /* Check whether I have to reroute the packet */ | ||
1520 | if (seq_before(unicast_packet->ttvn, curr_ttvn) || tt_poss_change) { | ||
1521 | /* Linearize the skb before accessing it */ | ||
1522 | if (skb_linearize(skb) < 0) | ||
1523 | return 0; | ||
1524 | |||
1525 | ethhdr = (struct ethhdr *)(skb->data + | ||
1526 | sizeof(struct unicast_packet)); | ||
1527 | orig_node = transtable_search(bat_priv, ethhdr->h_dest); | ||
1528 | |||
1529 | if (!orig_node) { | ||
1530 | if (!is_my_client(bat_priv, ethhdr->h_dest)) | ||
1531 | return 0; | ||
1532 | primary_if = primary_if_get_selected(bat_priv); | ||
1533 | if (!primary_if) | ||
1534 | return 0; | ||
1535 | memcpy(unicast_packet->dest, | ||
1536 | primary_if->net_dev->dev_addr, ETH_ALEN); | ||
1537 | hardif_free_ref(primary_if); | ||
1538 | } else { | ||
1539 | memcpy(unicast_packet->dest, orig_node->orig, | ||
1540 | ETH_ALEN); | ||
1541 | curr_ttvn = (uint8_t) | ||
1542 | atomic_read(&orig_node->last_ttvn); | ||
1543 | orig_node_free_ref(orig_node); | ||
1544 | } | ||
1545 | |||
1546 | bat_dbg(DBG_ROUTES, bat_priv, "TTVN mismatch (old_ttvn %u " | ||
1547 | "new_ttvn %u)! Rerouting unicast packet (for %pM) to " | ||
1548 | "%pM\n", unicast_packet->ttvn, curr_ttvn, | ||
1549 | ethhdr->h_dest, unicast_packet->dest); | ||
1550 | |||
1551 | unicast_packet->ttvn = curr_ttvn; | ||
1552 | } | ||
1553 | return 1; | ||
1554 | } | ||
1555 | |||
1356 | int recv_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if) | 1556 | int recv_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if) |
1357 | { | 1557 | { |
1558 | struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface); | ||
1358 | struct unicast_packet *unicast_packet; | 1559 | struct unicast_packet *unicast_packet; |
1359 | int hdr_size = sizeof(*unicast_packet); | 1560 | int hdr_size = sizeof(*unicast_packet); |
1360 | 1561 | ||
1361 | if (check_unicast_packet(skb, hdr_size) < 0) | 1562 | if (check_unicast_packet(skb, hdr_size) < 0) |
1362 | return NET_RX_DROP; | 1563 | return NET_RX_DROP; |
1363 | 1564 | ||
1565 | if (!check_unicast_ttvn(bat_priv, skb)) | ||
1566 | return NET_RX_DROP; | ||
1567 | |||
1364 | unicast_packet = (struct unicast_packet *)skb->data; | 1568 | unicast_packet = (struct unicast_packet *)skb->data; |
1365 | 1569 | ||
1366 | /* packet for me */ | 1570 | /* packet for me */ |
@@ -1383,6 +1587,9 @@ int recv_ucast_frag_packet(struct sk_buff *skb, struct hard_iface *recv_if) | |||
1383 | if (check_unicast_packet(skb, hdr_size) < 0) | 1587 | if (check_unicast_packet(skb, hdr_size) < 0) |
1384 | return NET_RX_DROP; | 1588 | return NET_RX_DROP; |
1385 | 1589 | ||
1590 | if (!check_unicast_ttvn(bat_priv, skb)) | ||
1591 | return NET_RX_DROP; | ||
1592 | |||
1386 | unicast_packet = (struct unicast_frag_packet *)skb->data; | 1593 | unicast_packet = (struct unicast_frag_packet *)skb->data; |
1387 | 1594 | ||
1388 | /* packet for me */ | 1595 | /* packet for me */ |