diff options
-rw-r--r-- | net/batman-adv/bat_iv_ogm.c | 454 | ||||
-rw-r--r-- | net/batman-adv/distributed-arp-table.c | 3 | ||||
-rw-r--r-- | net/batman-adv/gateway_client.c | 11 | ||||
-rw-r--r-- | net/batman-adv/icmp_socket.c | 3 | ||||
-rw-r--r-- | net/batman-adv/network-coding.c | 25 | ||||
-rw-r--r-- | net/batman-adv/originator.c | 242 | ||||
-rw-r--r-- | net/batman-adv/originator.h | 12 | ||||
-rw-r--r-- | net/batman-adv/routing.c | 38 | ||||
-rw-r--r-- | net/batman-adv/routing.h | 1 | ||||
-rw-r--r-- | net/batman-adv/translation-table.c | 3 | ||||
-rw-r--r-- | net/batman-adv/types.h | 32 |
11 files changed, 605 insertions, 219 deletions
diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c index 157cc1176313..1f9fe4270454 100644 --- a/net/batman-adv/bat_iv_ogm.c +++ b/net/batman-adv/bat_iv_ogm.c | |||
@@ -907,21 +907,21 @@ static void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface) | |||
907 | * originator | 907 | * originator |
908 | * @bat_priv: the bat priv with all the soft interface information | 908 | * @bat_priv: the bat priv with all the soft interface information |
909 | * @orig_node: the orig node who originally emitted the ogm packet | 909 | * @orig_node: the orig node who originally emitted the ogm packet |
910 | * @orig_ifinfo: ifinfo for the outgoing interface of the orig_node | ||
910 | * @ethhdr: Ethernet header of the OGM | 911 | * @ethhdr: Ethernet header of the OGM |
911 | * @batadv_ogm_packet: the ogm packet | 912 | * @batadv_ogm_packet: the ogm packet |
912 | * @if_incoming: interface where the packet was received | 913 | * @if_incoming: interface where the packet was received |
913 | * @if_outgoing: interface for which the retransmission should be considered | 914 | * @if_outgoing: interface for which the retransmission should be considered |
914 | * @tt_buff: pointer to the tt buffer | ||
915 | * @dup_status: the duplicate status of this ogm packet. | 915 | * @dup_status: the duplicate status of this ogm packet. |
916 | */ | 916 | */ |
917 | static void | 917 | static void |
918 | batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv, | 918 | batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv, |
919 | struct batadv_orig_node *orig_node, | 919 | struct batadv_orig_node *orig_node, |
920 | struct batadv_orig_ifinfo *orig_ifinfo, | ||
920 | const struct ethhdr *ethhdr, | 921 | const struct ethhdr *ethhdr, |
921 | const struct batadv_ogm_packet *batadv_ogm_packet, | 922 | const struct batadv_ogm_packet *batadv_ogm_packet, |
922 | struct batadv_hard_iface *if_incoming, | 923 | struct batadv_hard_iface *if_incoming, |
923 | struct batadv_hard_iface *if_outgoing, | 924 | struct batadv_hard_iface *if_outgoing, |
924 | const unsigned char *tt_buff, | ||
925 | enum batadv_dup_status dup_status) | 925 | enum batadv_dup_status dup_status) |
926 | { | 926 | { |
927 | struct batadv_neigh_ifinfo *neigh_ifinfo = NULL; | 927 | struct batadv_neigh_ifinfo *neigh_ifinfo = NULL; |
@@ -1004,14 +1004,14 @@ batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv, | |||
1004 | spin_unlock_bh(&neigh_node->ifinfo_lock); | 1004 | spin_unlock_bh(&neigh_node->ifinfo_lock); |
1005 | 1005 | ||
1006 | if (dup_status == BATADV_NO_DUP) { | 1006 | if (dup_status == BATADV_NO_DUP) { |
1007 | orig_node->last_ttl = batadv_ogm_packet->ttl; | 1007 | orig_ifinfo->last_ttl = batadv_ogm_packet->ttl; |
1008 | neigh_ifinfo->last_ttl = batadv_ogm_packet->ttl; | 1008 | neigh_ifinfo->last_ttl = batadv_ogm_packet->ttl; |
1009 | } | 1009 | } |
1010 | 1010 | ||
1011 | /* if this neighbor already is our next hop there is nothing | 1011 | /* if this neighbor already is our next hop there is nothing |
1012 | * to change | 1012 | * to change |
1013 | */ | 1013 | */ |
1014 | router = batadv_orig_node_get_router(orig_node); | 1014 | router = batadv_orig_router_get(orig_node, if_outgoing); |
1015 | if (router == neigh_node) | 1015 | if (router == neigh_node) |
1016 | goto out; | 1016 | goto out; |
1017 | 1017 | ||
@@ -1048,7 +1048,7 @@ batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv, | |||
1048 | goto out; | 1048 | goto out; |
1049 | } | 1049 | } |
1050 | 1050 | ||
1051 | batadv_update_route(bat_priv, orig_node, neigh_node); | 1051 | batadv_update_route(bat_priv, orig_node, if_outgoing, neigh_node); |
1052 | goto out; | 1052 | goto out; |
1053 | 1053 | ||
1054 | unlock: | 1054 | unlock: |
@@ -1209,6 +1209,7 @@ batadv_iv_ogm_update_seqnos(const struct ethhdr *ethhdr, | |||
1209 | { | 1209 | { |
1210 | struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface); | 1210 | struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface); |
1211 | struct batadv_orig_node *orig_node; | 1211 | struct batadv_orig_node *orig_node; |
1212 | struct batadv_orig_ifinfo *orig_ifinfo = NULL; | ||
1212 | struct batadv_neigh_node *neigh_node; | 1213 | struct batadv_neigh_node *neigh_node; |
1213 | struct batadv_neigh_ifinfo *neigh_ifinfo; | 1214 | struct batadv_neigh_ifinfo *neigh_ifinfo; |
1214 | int is_dup; | 1215 | int is_dup; |
@@ -1225,13 +1226,19 @@ batadv_iv_ogm_update_seqnos(const struct ethhdr *ethhdr, | |||
1225 | if (!orig_node) | 1226 | if (!orig_node) |
1226 | return BATADV_NO_DUP; | 1227 | return BATADV_NO_DUP; |
1227 | 1228 | ||
1229 | orig_ifinfo = batadv_orig_ifinfo_new(orig_node, if_outgoing); | ||
1230 | if (WARN_ON(!orig_ifinfo)) { | ||
1231 | batadv_orig_node_free_ref(orig_node); | ||
1232 | return 0; | ||
1233 | } | ||
1234 | |||
1228 | spin_lock_bh(&orig_node->bat_iv.ogm_cnt_lock); | 1235 | spin_lock_bh(&orig_node->bat_iv.ogm_cnt_lock); |
1229 | seq_diff = seqno - orig_node->last_real_seqno; | 1236 | seq_diff = seqno - orig_ifinfo->last_real_seqno; |
1230 | 1237 | ||
1231 | /* signalize caller that the packet is to be dropped. */ | 1238 | /* signalize caller that the packet is to be dropped. */ |
1232 | if (!hlist_empty(&orig_node->neigh_list) && | 1239 | if (!hlist_empty(&orig_node->neigh_list) && |
1233 | batadv_window_protected(bat_priv, seq_diff, | 1240 | batadv_window_protected(bat_priv, seq_diff, |
1234 | &orig_node->batman_seqno_reset)) { | 1241 | &orig_ifinfo->batman_seqno_reset)) { |
1235 | ret = BATADV_PROTECTED; | 1242 | ret = BATADV_PROTECTED; |
1236 | goto out; | 1243 | goto out; |
1237 | } | 1244 | } |
@@ -1245,7 +1252,7 @@ batadv_iv_ogm_update_seqnos(const struct ethhdr *ethhdr, | |||
1245 | 1252 | ||
1246 | neigh_addr = neigh_node->addr; | 1253 | neigh_addr = neigh_node->addr; |
1247 | is_dup = batadv_test_bit(neigh_ifinfo->bat_iv.real_bits, | 1254 | is_dup = batadv_test_bit(neigh_ifinfo->bat_iv.real_bits, |
1248 | orig_node->last_real_seqno, | 1255 | orig_ifinfo->last_real_seqno, |
1249 | seqno); | 1256 | seqno); |
1250 | 1257 | ||
1251 | if (batadv_compare_eth(neigh_addr, ethhdr->h_source) && | 1258 | if (batadv_compare_eth(neigh_addr, ethhdr->h_source) && |
@@ -1273,163 +1280,65 @@ batadv_iv_ogm_update_seqnos(const struct ethhdr *ethhdr, | |||
1273 | 1280 | ||
1274 | if (need_update) { | 1281 | if (need_update) { |
1275 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, | 1282 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, |
1276 | "updating last_seqno: old %u, new %u\n", | 1283 | "%s updating last_seqno: old %u, new %u\n", |
1277 | orig_node->last_real_seqno, seqno); | 1284 | if_outgoing ? if_outgoing->net_dev->name : "DEFAULT", |
1278 | orig_node->last_real_seqno = seqno; | 1285 | orig_ifinfo->last_real_seqno, seqno); |
1286 | orig_ifinfo->last_real_seqno = seqno; | ||
1279 | } | 1287 | } |
1280 | 1288 | ||
1281 | out: | 1289 | out: |
1282 | spin_unlock_bh(&orig_node->bat_iv.ogm_cnt_lock); | 1290 | spin_unlock_bh(&orig_node->bat_iv.ogm_cnt_lock); |
1283 | batadv_orig_node_free_ref(orig_node); | 1291 | batadv_orig_node_free_ref(orig_node); |
1292 | if (orig_ifinfo) | ||
1293 | batadv_orig_ifinfo_free_ref(orig_ifinfo); | ||
1284 | return ret; | 1294 | return ret; |
1285 | } | 1295 | } |
1286 | 1296 | ||
1287 | static void batadv_iv_ogm_process(const struct ethhdr *ethhdr, | 1297 | |
1288 | struct batadv_ogm_packet *batadv_ogm_packet, | 1298 | /** |
1289 | const unsigned char *tt_buff, | 1299 | * batadv_iv_ogm_process_per_outif - process a batman iv OGM for an outgoing if |
1290 | struct batadv_hard_iface *if_incoming) | 1300 | * @skb: the skb containing the OGM |
1301 | * @orig_node: the (cached) orig node for the originator of this OGM | ||
1302 | * @if_incoming: the interface where this packet was received | ||
1303 | * @if_outgoing: the interface for which the packet should be considered | ||
1304 | */ | ||
1305 | static void | ||
1306 | batadv_iv_ogm_process_per_outif(const struct sk_buff *skb, int ogm_offset, | ||
1307 | struct batadv_orig_node *orig_node, | ||
1308 | struct batadv_hard_iface *if_incoming, | ||
1309 | struct batadv_hard_iface *if_outgoing) | ||
1291 | { | 1310 | { |
1292 | struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface); | 1311 | struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface); |
1293 | struct batadv_hard_iface *hard_iface; | ||
1294 | struct batadv_orig_node *orig_neigh_node, *orig_node, *orig_node_tmp; | ||
1295 | struct batadv_neigh_node *router = NULL, *router_router = NULL; | 1312 | struct batadv_neigh_node *router = NULL, *router_router = NULL; |
1313 | struct batadv_orig_node *orig_neigh_node; | ||
1314 | struct batadv_orig_ifinfo *orig_ifinfo; | ||
1296 | struct batadv_neigh_node *orig_neigh_router = NULL; | 1315 | struct batadv_neigh_node *orig_neigh_router = NULL; |
1297 | struct batadv_neigh_ifinfo *router_ifinfo = NULL; | 1316 | struct batadv_neigh_ifinfo *router_ifinfo = NULL; |
1298 | int has_directlink_flag; | 1317 | struct batadv_ogm_packet *ogm_packet; |
1299 | int is_my_addr = 0, is_my_orig = 0, is_my_oldorig = 0; | ||
1300 | int is_bidirect; | ||
1301 | bool is_single_hop_neigh = false; | ||
1302 | bool is_from_best_next_hop = false; | ||
1303 | int sameseq, similar_ttl; | ||
1304 | enum batadv_dup_status dup_status; | 1318 | enum batadv_dup_status dup_status; |
1305 | uint32_t if_incoming_seqno; | 1319 | bool is_from_best_next_hop = false; |
1320 | bool is_single_hop_neigh = false; | ||
1321 | bool sameseq, similar_ttl; | ||
1322 | struct sk_buff *skb_priv; | ||
1323 | struct ethhdr *ethhdr; | ||
1306 | uint8_t *prev_sender; | 1324 | uint8_t *prev_sender; |
1325 | int is_bidirect; | ||
1307 | 1326 | ||
1308 | /* Silently drop when the batman packet is actually not a | 1327 | /* create a private copy of the skb, as some functions change tq value |
1309 | * correct packet. | 1328 | * and/or flags. |
1310 | * | ||
1311 | * This might happen if a packet is padded (e.g. Ethernet has a | ||
1312 | * minimum frame length of 64 byte) and the aggregation interprets | ||
1313 | * it as an additional length. | ||
1314 | * | ||
1315 | * TODO: A more sane solution would be to have a bit in the | ||
1316 | * batadv_ogm_packet to detect whether the packet is the last | ||
1317 | * packet in an aggregation. Here we expect that the padding | ||
1318 | * is always zero (or not 0x01) | ||
1319 | */ | 1329 | */ |
1320 | if (batadv_ogm_packet->packet_type != BATADV_IV_OGM) | 1330 | skb_priv = skb_copy(skb, GFP_ATOMIC); |
1331 | if (!skb_priv) | ||
1321 | return; | 1332 | return; |
1322 | 1333 | ||
1323 | /* could be changed by schedule_own_packet() */ | 1334 | ethhdr = eth_hdr(skb_priv); |
1324 | if_incoming_seqno = atomic_read(&if_incoming->bat_iv.ogm_seqno); | 1335 | ogm_packet = (struct batadv_ogm_packet *)(skb_priv->data + ogm_offset); |
1325 | |||
1326 | if (batadv_ogm_packet->flags & BATADV_DIRECTLINK) | ||
1327 | has_directlink_flag = 1; | ||
1328 | else | ||
1329 | has_directlink_flag = 0; | ||
1330 | 1336 | ||
1331 | if (batadv_compare_eth(ethhdr->h_source, batadv_ogm_packet->orig)) | 1337 | dup_status = batadv_iv_ogm_update_seqnos(ethhdr, ogm_packet, |
1338 | if_incoming, if_outgoing); | ||
1339 | if (batadv_compare_eth(ethhdr->h_source, ogm_packet->orig)) | ||
1332 | is_single_hop_neigh = true; | 1340 | is_single_hop_neigh = true; |
1333 | 1341 | ||
1334 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, | ||
1335 | "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", | ||
1336 | ethhdr->h_source, if_incoming->net_dev->name, | ||
1337 | if_incoming->net_dev->dev_addr, batadv_ogm_packet->orig, | ||
1338 | batadv_ogm_packet->prev_sender, | ||
1339 | ntohl(batadv_ogm_packet->seqno), batadv_ogm_packet->tq, | ||
1340 | batadv_ogm_packet->ttl, | ||
1341 | batadv_ogm_packet->version, has_directlink_flag); | ||
1342 | |||
1343 | rcu_read_lock(); | ||
1344 | list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) { | ||
1345 | if (hard_iface->if_status != BATADV_IF_ACTIVE) | ||
1346 | continue; | ||
1347 | |||
1348 | if (hard_iface->soft_iface != if_incoming->soft_iface) | ||
1349 | continue; | ||
1350 | |||
1351 | if (batadv_compare_eth(ethhdr->h_source, | ||
1352 | hard_iface->net_dev->dev_addr)) | ||
1353 | is_my_addr = 1; | ||
1354 | |||
1355 | if (batadv_compare_eth(batadv_ogm_packet->orig, | ||
1356 | hard_iface->net_dev->dev_addr)) | ||
1357 | is_my_orig = 1; | ||
1358 | |||
1359 | if (batadv_compare_eth(batadv_ogm_packet->prev_sender, | ||
1360 | hard_iface->net_dev->dev_addr)) | ||
1361 | is_my_oldorig = 1; | ||
1362 | } | ||
1363 | rcu_read_unlock(); | ||
1364 | |||
1365 | if (is_my_addr) { | ||
1366 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, | ||
1367 | "Drop packet: received my own broadcast (sender: %pM)\n", | ||
1368 | ethhdr->h_source); | ||
1369 | return; | ||
1370 | } | ||
1371 | |||
1372 | if (is_my_orig) { | ||
1373 | unsigned long *word; | ||
1374 | int offset; | ||
1375 | int32_t bit_pos; | ||
1376 | int16_t if_num; | ||
1377 | uint8_t *weight; | ||
1378 | |||
1379 | orig_neigh_node = batadv_iv_ogm_orig_get(bat_priv, | ||
1380 | ethhdr->h_source); | ||
1381 | if (!orig_neigh_node) | ||
1382 | return; | ||
1383 | |||
1384 | /* neighbor has to indicate direct link and it has to | ||
1385 | * come via the corresponding interface | ||
1386 | * save packet seqno for bidirectional check | ||
1387 | */ | ||
1388 | if (has_directlink_flag && | ||
1389 | batadv_compare_eth(if_incoming->net_dev->dev_addr, | ||
1390 | batadv_ogm_packet->orig)) { | ||
1391 | if_num = if_incoming->if_num; | ||
1392 | offset = if_num * BATADV_NUM_WORDS; | ||
1393 | |||
1394 | spin_lock_bh(&orig_neigh_node->bat_iv.ogm_cnt_lock); | ||
1395 | word = &(orig_neigh_node->bat_iv.bcast_own[offset]); | ||
1396 | bit_pos = if_incoming_seqno - 2; | ||
1397 | bit_pos -= ntohl(batadv_ogm_packet->seqno); | ||
1398 | batadv_set_bit(word, bit_pos); | ||
1399 | weight = &orig_neigh_node->bat_iv.bcast_own_sum[if_num]; | ||
1400 | *weight = bitmap_weight(word, | ||
1401 | BATADV_TQ_LOCAL_WINDOW_SIZE); | ||
1402 | spin_unlock_bh(&orig_neigh_node->bat_iv.ogm_cnt_lock); | ||
1403 | } | ||
1404 | |||
1405 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, | ||
1406 | "Drop packet: originator packet from myself (via neighbor)\n"); | ||
1407 | batadv_orig_node_free_ref(orig_neigh_node); | ||
1408 | return; | ||
1409 | } | ||
1410 | |||
1411 | if (is_my_oldorig) { | ||
1412 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, | ||
1413 | "Drop packet: ignoring all rebroadcast echos (sender: %pM)\n", | ||
1414 | ethhdr->h_source); | ||
1415 | return; | ||
1416 | } | ||
1417 | |||
1418 | if (batadv_ogm_packet->flags & BATADV_NOT_BEST_NEXT_HOP) { | ||
1419 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, | ||
1420 | "Drop packet: ignoring all packets not forwarded from the best next hop (sender: %pM)\n", | ||
1421 | ethhdr->h_source); | ||
1422 | return; | ||
1423 | } | ||
1424 | |||
1425 | orig_node = batadv_iv_ogm_orig_get(bat_priv, batadv_ogm_packet->orig); | ||
1426 | if (!orig_node) | ||
1427 | return; | ||
1428 | |||
1429 | dup_status = batadv_iv_ogm_update_seqnos(ethhdr, batadv_ogm_packet, | ||
1430 | if_incoming, | ||
1431 | BATADV_IF_DEFAULT); | ||
1432 | |||
1433 | if (dup_status == BATADV_PROTECTED) { | 1342 | if (dup_status == BATADV_PROTECTED) { |
1434 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, | 1343 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, |
1435 | "Drop packet: packet within seqno protection time (sender: %pM)\n", | 1344 | "Drop packet: packet within seqno protection time (sender: %pM)\n", |
@@ -1437,29 +1346,28 @@ static void batadv_iv_ogm_process(const struct ethhdr *ethhdr, | |||
1437 | goto out; | 1346 | goto out; |
1438 | } | 1347 | } |
1439 | 1348 | ||
1440 | if (batadv_ogm_packet->tq == 0) { | 1349 | if (ogm_packet->tq == 0) { |
1441 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, | 1350 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, |
1442 | "Drop packet: originator packet with tq equal 0\n"); | 1351 | "Drop packet: originator packet with tq equal 0\n"); |
1443 | goto out; | 1352 | goto out; |
1444 | } | 1353 | } |
1445 | 1354 | ||
1446 | router = batadv_orig_node_get_router(orig_node); | 1355 | router = batadv_orig_router_get(orig_node, if_outgoing); |
1447 | if (router) { | 1356 | if (router) { |
1448 | orig_node_tmp = router->orig_node; | 1357 | router_router = batadv_orig_router_get(router->orig_node, |
1449 | router_router = batadv_orig_node_get_router(orig_node_tmp); | 1358 | if_outgoing); |
1450 | router_ifinfo = batadv_neigh_ifinfo_get(router, | 1359 | router_ifinfo = batadv_neigh_ifinfo_get(router, if_outgoing); |
1451 | BATADV_IF_DEFAULT); | ||
1452 | } | 1360 | } |
1453 | 1361 | ||
1454 | if ((router && router_ifinfo->bat_iv.tq_avg != 0) && | 1362 | if ((router_ifinfo && router_ifinfo->bat_iv.tq_avg != 0) && |
1455 | (batadv_compare_eth(router->addr, ethhdr->h_source))) | 1363 | (batadv_compare_eth(router->addr, ethhdr->h_source))) |
1456 | is_from_best_next_hop = true; | 1364 | is_from_best_next_hop = true; |
1457 | 1365 | ||
1458 | prev_sender = batadv_ogm_packet->prev_sender; | 1366 | prev_sender = ogm_packet->prev_sender; |
1459 | /* avoid temporary routing loops */ | 1367 | /* avoid temporary routing loops */ |
1460 | if (router && router_router && | 1368 | if (router && router_router && |
1461 | (batadv_compare_eth(router->addr, prev_sender)) && | 1369 | (batadv_compare_eth(router->addr, prev_sender)) && |
1462 | !(batadv_compare_eth(batadv_ogm_packet->orig, prev_sender)) && | 1370 | !(batadv_compare_eth(ogm_packet->orig, prev_sender)) && |
1463 | (batadv_compare_eth(router->addr, router_router->addr))) { | 1371 | (batadv_compare_eth(router->addr, router_router->addr))) { |
1464 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, | 1372 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, |
1465 | "Drop packet: ignoring all rebroadcast packets that may make me loop (sender: %pM)\n", | 1373 | "Drop packet: ignoring all rebroadcast packets that may make me loop (sender: %pM)\n", |
@@ -1467,7 +1375,8 @@ static void batadv_iv_ogm_process(const struct ethhdr *ethhdr, | |||
1467 | goto out; | 1375 | goto out; |
1468 | } | 1376 | } |
1469 | 1377 | ||
1470 | batadv_tvlv_ogm_receive(bat_priv, batadv_ogm_packet, orig_node); | 1378 | if (if_outgoing == BATADV_IF_DEFAULT) |
1379 | batadv_tvlv_ogm_receive(bat_priv, ogm_packet, orig_node); | ||
1471 | 1380 | ||
1472 | /* if sender is a direct neighbor the sender mac equals | 1381 | /* if sender is a direct neighbor the sender mac equals |
1473 | * originator mac | 1382 | * originator mac |
@@ -1483,9 +1392,10 @@ static void batadv_iv_ogm_process(const struct ethhdr *ethhdr, | |||
1483 | 1392 | ||
1484 | /* Update nc_nodes of the originator */ | 1393 | /* Update nc_nodes of the originator */ |
1485 | batadv_nc_update_nc_node(bat_priv, orig_node, orig_neigh_node, | 1394 | batadv_nc_update_nc_node(bat_priv, orig_node, orig_neigh_node, |
1486 | batadv_ogm_packet, is_single_hop_neigh); | 1395 | ogm_packet, is_single_hop_neigh); |
1487 | 1396 | ||
1488 | orig_neigh_router = batadv_orig_node_get_router(orig_neigh_node); | 1397 | orig_neigh_router = batadv_orig_router_get(orig_neigh_node, |
1398 | if_outgoing); | ||
1489 | 1399 | ||
1490 | /* drop packet if sender is not a direct neighbor and if we | 1400 | /* drop packet if sender is not a direct neighbor and if we |
1491 | * don't route towards it | 1401 | * don't route towards it |
@@ -1497,25 +1407,41 @@ static void batadv_iv_ogm_process(const struct ethhdr *ethhdr, | |||
1497 | } | 1407 | } |
1498 | 1408 | ||
1499 | is_bidirect = batadv_iv_ogm_calc_tq(orig_node, orig_neigh_node, | 1409 | is_bidirect = batadv_iv_ogm_calc_tq(orig_node, orig_neigh_node, |
1500 | batadv_ogm_packet, if_incoming, | 1410 | ogm_packet, if_incoming, |
1501 | BATADV_IF_DEFAULT); | 1411 | if_outgoing); |
1502 | 1412 | ||
1503 | /* update ranking if it is not a duplicate or has the same | 1413 | /* update ranking if it is not a duplicate or has the same |
1504 | * seqno and similar ttl as the non-duplicate | 1414 | * seqno and similar ttl as the non-duplicate |
1505 | */ | 1415 | */ |
1506 | sameseq = orig_node->last_real_seqno == ntohl(batadv_ogm_packet->seqno); | 1416 | orig_ifinfo = batadv_orig_ifinfo_new(orig_node, if_outgoing); |
1507 | similar_ttl = orig_node->last_ttl - 3 <= batadv_ogm_packet->ttl; | 1417 | if (!orig_ifinfo) |
1418 | goto out_neigh; | ||
1419 | |||
1420 | sameseq = orig_ifinfo->last_real_seqno == ntohl(ogm_packet->seqno); | ||
1421 | similar_ttl = (orig_ifinfo->last_ttl - 3) <= ogm_packet->ttl; | ||
1422 | |||
1508 | if (is_bidirect && ((dup_status == BATADV_NO_DUP) || | 1423 | if (is_bidirect && ((dup_status == BATADV_NO_DUP) || |
1509 | (sameseq && similar_ttl))) | 1424 | (sameseq && similar_ttl))) { |
1510 | batadv_iv_ogm_orig_update(bat_priv, orig_node, ethhdr, | 1425 | batadv_iv_ogm_orig_update(bat_priv, orig_node, |
1511 | batadv_ogm_packet, if_incoming, | 1426 | orig_ifinfo, ethhdr, |
1512 | BATADV_IF_DEFAULT, tt_buff, | 1427 | ogm_packet, if_incoming, |
1513 | dup_status); | 1428 | if_outgoing, dup_status); |
1429 | } | ||
1430 | batadv_orig_ifinfo_free_ref(orig_ifinfo); | ||
1514 | 1431 | ||
1515 | /* is single hop (direct) neighbor */ | 1432 | /* is single hop (direct) neighbor */ |
1516 | if (is_single_hop_neigh) { | 1433 | if (is_single_hop_neigh) { |
1434 | /* OGMs from secondary interfaces should only scheduled once | ||
1435 | * per interface where it has been received, not multiple times | ||
1436 | */ | ||
1437 | if ((ogm_packet->ttl <= 2) && | ||
1438 | (if_incoming != if_outgoing)) { | ||
1439 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, | ||
1440 | "Drop packet: OGM from secondary interface and wrong outgoing interface\n"); | ||
1441 | goto out_neigh; | ||
1442 | } | ||
1517 | /* mark direct link on incoming interface */ | 1443 | /* mark direct link on incoming interface */ |
1518 | batadv_iv_ogm_forward(orig_node, ethhdr, batadv_ogm_packet, | 1444 | batadv_iv_ogm_forward(orig_node, ethhdr, ogm_packet, |
1519 | is_single_hop_neigh, | 1445 | is_single_hop_neigh, |
1520 | is_from_best_next_hop, if_incoming); | 1446 | is_from_best_next_hop, if_incoming); |
1521 | 1447 | ||
@@ -1537,9 +1463,14 @@ static void batadv_iv_ogm_process(const struct ethhdr *ethhdr, | |||
1537 | goto out_neigh; | 1463 | goto out_neigh; |
1538 | } | 1464 | } |
1539 | 1465 | ||
1466 | /* only forward the packet on the default interface until the | ||
1467 | * OGM forwarding has been reworked to send on specific interfaces. | ||
1468 | */ | ||
1469 | if (if_outgoing != BATADV_IF_DEFAULT) | ||
1470 | goto out_neigh; | ||
1540 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, | 1471 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, |
1541 | "Forwarding packet: rebroadcast originator packet\n"); | 1472 | "Forwarding packet: rebroadcast originator packet\n"); |
1542 | batadv_iv_ogm_forward(orig_node, ethhdr, batadv_ogm_packet, | 1473 | batadv_iv_ogm_forward(orig_node, ethhdr, ogm_packet, |
1543 | is_single_hop_neigh, is_from_best_next_hop, | 1474 | is_single_hop_neigh, is_from_best_next_hop, |
1544 | if_incoming); | 1475 | if_incoming); |
1545 | 1476 | ||
@@ -1554,6 +1485,165 @@ out: | |||
1554 | if (orig_neigh_router) | 1485 | if (orig_neigh_router) |
1555 | batadv_neigh_node_free_ref(orig_neigh_router); | 1486 | batadv_neigh_node_free_ref(orig_neigh_router); |
1556 | 1487 | ||
1488 | kfree_skb(skb_priv); | ||
1489 | } | ||
1490 | |||
1491 | /** | ||
1492 | * batadv_iv_ogm_process - process an incoming batman iv OGM | ||
1493 | * @skb: the skb containing the OGM | ||
1494 | * @ogm_offset: offset to the OGM which should be processed (for aggregates) | ||
1495 | * @if_incoming: the interface where this packet was receved | ||
1496 | */ | ||
1497 | static void batadv_iv_ogm_process(const struct sk_buff *skb, int ogm_offset, | ||
1498 | struct batadv_hard_iface *if_incoming) | ||
1499 | { | ||
1500 | struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface); | ||
1501 | struct batadv_orig_node *orig_neigh_node, *orig_node; | ||
1502 | struct batadv_hard_iface *hard_iface; | ||
1503 | struct batadv_ogm_packet *ogm_packet; | ||
1504 | uint32_t if_incoming_seqno; | ||
1505 | bool has_directlink_flag; | ||
1506 | struct ethhdr *ethhdr; | ||
1507 | bool is_my_oldorig = false; | ||
1508 | bool is_my_addr = false; | ||
1509 | bool is_my_orig = false; | ||
1510 | |||
1511 | ogm_packet = (struct batadv_ogm_packet *)(skb->data + ogm_offset); | ||
1512 | ethhdr = eth_hdr(skb); | ||
1513 | |||
1514 | /* Silently drop when the batman packet is actually not a | ||
1515 | * correct packet. | ||
1516 | * | ||
1517 | * This might happen if a packet is padded (e.g. Ethernet has a | ||
1518 | * minimum frame length of 64 byte) and the aggregation interprets | ||
1519 | * it as an additional length. | ||
1520 | * | ||
1521 | * TODO: A more sane solution would be to have a bit in the | ||
1522 | * batadv_ogm_packet to detect whether the packet is the last | ||
1523 | * packet in an aggregation. Here we expect that the padding | ||
1524 | * is always zero (or not 0x01) | ||
1525 | */ | ||
1526 | if (ogm_packet->packet_type != BATADV_IV_OGM) | ||
1527 | return; | ||
1528 | |||
1529 | /* could be changed by schedule_own_packet() */ | ||
1530 | if_incoming_seqno = atomic_read(&if_incoming->bat_iv.ogm_seqno); | ||
1531 | |||
1532 | if (ogm_packet->flags & BATADV_DIRECTLINK) | ||
1533 | has_directlink_flag = true; | ||
1534 | else | ||
1535 | has_directlink_flag = false; | ||
1536 | |||
1537 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, | ||
1538 | "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", | ||
1539 | ethhdr->h_source, if_incoming->net_dev->name, | ||
1540 | if_incoming->net_dev->dev_addr, ogm_packet->orig, | ||
1541 | ogm_packet->prev_sender, ntohl(ogm_packet->seqno), | ||
1542 | ogm_packet->tq, ogm_packet->ttl, | ||
1543 | ogm_packet->version, has_directlink_flag); | ||
1544 | |||
1545 | rcu_read_lock(); | ||
1546 | list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) { | ||
1547 | if (hard_iface->if_status != BATADV_IF_ACTIVE) | ||
1548 | continue; | ||
1549 | |||
1550 | if (hard_iface->soft_iface != if_incoming->soft_iface) | ||
1551 | continue; | ||
1552 | |||
1553 | if (batadv_compare_eth(ethhdr->h_source, | ||
1554 | hard_iface->net_dev->dev_addr)) | ||
1555 | is_my_addr = true; | ||
1556 | |||
1557 | if (batadv_compare_eth(ogm_packet->orig, | ||
1558 | hard_iface->net_dev->dev_addr)) | ||
1559 | is_my_orig = true; | ||
1560 | |||
1561 | if (batadv_compare_eth(ogm_packet->prev_sender, | ||
1562 | hard_iface->net_dev->dev_addr)) | ||
1563 | is_my_oldorig = true; | ||
1564 | } | ||
1565 | rcu_read_unlock(); | ||
1566 | |||
1567 | if (is_my_addr) { | ||
1568 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, | ||
1569 | "Drop packet: received my own broadcast (sender: %pM)\n", | ||
1570 | ethhdr->h_source); | ||
1571 | return; | ||
1572 | } | ||
1573 | |||
1574 | if (is_my_orig) { | ||
1575 | unsigned long *word; | ||
1576 | int offset; | ||
1577 | int32_t bit_pos; | ||
1578 | int16_t if_num; | ||
1579 | uint8_t *weight; | ||
1580 | |||
1581 | orig_neigh_node = batadv_iv_ogm_orig_get(bat_priv, | ||
1582 | ethhdr->h_source); | ||
1583 | if (!orig_neigh_node) | ||
1584 | return; | ||
1585 | |||
1586 | /* neighbor has to indicate direct link and it has to | ||
1587 | * come via the corresponding interface | ||
1588 | * save packet seqno for bidirectional check | ||
1589 | */ | ||
1590 | if (has_directlink_flag && | ||
1591 | batadv_compare_eth(if_incoming->net_dev->dev_addr, | ||
1592 | ogm_packet->orig)) { | ||
1593 | if_num = if_incoming->if_num; | ||
1594 | offset = if_num * BATADV_NUM_WORDS; | ||
1595 | |||
1596 | spin_lock_bh(&orig_neigh_node->bat_iv.ogm_cnt_lock); | ||
1597 | word = &(orig_neigh_node->bat_iv.bcast_own[offset]); | ||
1598 | bit_pos = if_incoming_seqno - 2; | ||
1599 | bit_pos -= ntohl(ogm_packet->seqno); | ||
1600 | batadv_set_bit(word, bit_pos); | ||
1601 | weight = &orig_neigh_node->bat_iv.bcast_own_sum[if_num]; | ||
1602 | *weight = bitmap_weight(word, | ||
1603 | BATADV_TQ_LOCAL_WINDOW_SIZE); | ||
1604 | spin_unlock_bh(&orig_neigh_node->bat_iv.ogm_cnt_lock); | ||
1605 | } | ||
1606 | |||
1607 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, | ||
1608 | "Drop packet: originator packet from myself (via neighbor)\n"); | ||
1609 | batadv_orig_node_free_ref(orig_neigh_node); | ||
1610 | return; | ||
1611 | } | ||
1612 | |||
1613 | if (is_my_oldorig) { | ||
1614 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, | ||
1615 | "Drop packet: ignoring all rebroadcast echos (sender: %pM)\n", | ||
1616 | ethhdr->h_source); | ||
1617 | return; | ||
1618 | } | ||
1619 | |||
1620 | if (ogm_packet->flags & BATADV_NOT_BEST_NEXT_HOP) { | ||
1621 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, | ||
1622 | "Drop packet: ignoring all packets not forwarded from the best next hop (sender: %pM)\n", | ||
1623 | ethhdr->h_source); | ||
1624 | return; | ||
1625 | } | ||
1626 | |||
1627 | orig_node = batadv_iv_ogm_orig_get(bat_priv, ogm_packet->orig); | ||
1628 | if (!orig_node) | ||
1629 | return; | ||
1630 | |||
1631 | batadv_iv_ogm_process_per_outif(skb, ogm_offset, orig_node, | ||
1632 | if_incoming, BATADV_IF_DEFAULT); | ||
1633 | |||
1634 | rcu_read_lock(); | ||
1635 | list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) { | ||
1636 | if (hard_iface->if_status != BATADV_IF_ACTIVE) | ||
1637 | continue; | ||
1638 | |||
1639 | if (hard_iface->soft_iface != bat_priv->soft_iface) | ||
1640 | continue; | ||
1641 | |||
1642 | batadv_iv_ogm_process_per_outif(skb, ogm_offset, orig_node, | ||
1643 | if_incoming, hard_iface); | ||
1644 | } | ||
1645 | rcu_read_unlock(); | ||
1646 | |||
1557 | batadv_orig_node_free_ref(orig_node); | 1647 | batadv_orig_node_free_ref(orig_node); |
1558 | } | 1648 | } |
1559 | 1649 | ||
@@ -1561,11 +1651,9 @@ static int batadv_iv_ogm_receive(struct sk_buff *skb, | |||
1561 | struct batadv_hard_iface *if_incoming) | 1651 | struct batadv_hard_iface *if_incoming) |
1562 | { | 1652 | { |
1563 | struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface); | 1653 | struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface); |
1564 | struct batadv_ogm_packet *batadv_ogm_packet; | 1654 | struct batadv_ogm_packet *ogm_packet; |
1565 | struct ethhdr *ethhdr; | ||
1566 | int buff_pos = 0, packet_len; | ||
1567 | unsigned char *tvlv_buff, *packet_buff; | ||
1568 | uint8_t *packet_pos; | 1655 | uint8_t *packet_pos; |
1656 | int ogm_offset; | ||
1569 | bool ret; | 1657 | bool ret; |
1570 | 1658 | ||
1571 | ret = batadv_check_management_packet(skb, if_incoming, BATADV_OGM_HLEN); | 1659 | ret = batadv_check_management_packet(skb, if_incoming, BATADV_OGM_HLEN); |
@@ -1582,24 +1670,19 @@ static int batadv_iv_ogm_receive(struct sk_buff *skb, | |||
1582 | batadv_add_counter(bat_priv, BATADV_CNT_MGMT_RX_BYTES, | 1670 | batadv_add_counter(bat_priv, BATADV_CNT_MGMT_RX_BYTES, |
1583 | skb->len + ETH_HLEN); | 1671 | skb->len + ETH_HLEN); |
1584 | 1672 | ||
1585 | packet_len = skb_headlen(skb); | 1673 | ogm_offset = 0; |
1586 | ethhdr = eth_hdr(skb); | 1674 | ogm_packet = (struct batadv_ogm_packet *)skb->data; |
1587 | packet_buff = skb->data; | ||
1588 | batadv_ogm_packet = (struct batadv_ogm_packet *)packet_buff; | ||
1589 | 1675 | ||
1590 | /* unpack the aggregated packets and process them one by one */ | 1676 | /* unpack the aggregated packets and process them one by one */ |
1591 | while (batadv_iv_ogm_aggr_packet(buff_pos, packet_len, | 1677 | while (batadv_iv_ogm_aggr_packet(ogm_offset, skb_headlen(skb), |
1592 | batadv_ogm_packet->tvlv_len)) { | 1678 | ogm_packet->tvlv_len)) { |
1593 | tvlv_buff = packet_buff + buff_pos + BATADV_OGM_HLEN; | 1679 | batadv_iv_ogm_process(skb, ogm_offset, if_incoming); |
1594 | 1680 | ||
1595 | batadv_iv_ogm_process(ethhdr, batadv_ogm_packet, | 1681 | ogm_offset += BATADV_OGM_HLEN; |
1596 | tvlv_buff, if_incoming); | 1682 | ogm_offset += ntohs(ogm_packet->tvlv_len); |
1597 | 1683 | ||
1598 | buff_pos += BATADV_OGM_HLEN; | 1684 | packet_pos = skb->data + ogm_offset; |
1599 | buff_pos += ntohs(batadv_ogm_packet->tvlv_len); | 1685 | ogm_packet = (struct batadv_ogm_packet *)packet_pos; |
1600 | |||
1601 | packet_pos = packet_buff + buff_pos; | ||
1602 | batadv_ogm_packet = (struct batadv_ogm_packet *)packet_pos; | ||
1603 | } | 1686 | } |
1604 | 1687 | ||
1605 | kfree_skb(skb); | 1688 | kfree_skb(skb); |
@@ -1661,7 +1744,8 @@ static void batadv_iv_ogm_orig_print(struct batadv_priv *bat_priv, | |||
1661 | 1744 | ||
1662 | rcu_read_lock(); | 1745 | rcu_read_lock(); |
1663 | hlist_for_each_entry_rcu(orig_node, head, hash_entry) { | 1746 | hlist_for_each_entry_rcu(orig_node, head, hash_entry) { |
1664 | neigh_node = batadv_orig_node_get_router(orig_node); | 1747 | neigh_node = batadv_orig_router_get(orig_node, |
1748 | BATADV_IF_DEFAULT); | ||
1665 | if (!neigh_node) | 1749 | if (!neigh_node) |
1666 | continue; | 1750 | continue; |
1667 | 1751 | ||
diff --git a/net/batman-adv/distributed-arp-table.c b/net/batman-adv/distributed-arp-table.c index 997ae6ac51ff..1d214cd5738e 100644 --- a/net/batman-adv/distributed-arp-table.c +++ b/net/batman-adv/distributed-arp-table.c | |||
@@ -589,7 +589,8 @@ static bool batadv_dat_send_data(struct batadv_priv *bat_priv, | |||
589 | if (cand[i].type == BATADV_DAT_CANDIDATE_NOT_FOUND) | 589 | if (cand[i].type == BATADV_DAT_CANDIDATE_NOT_FOUND) |
590 | continue; | 590 | continue; |
591 | 591 | ||
592 | neigh_node = batadv_orig_node_get_router(cand[i].orig_node); | 592 | neigh_node = batadv_orig_router_get(cand[i].orig_node, |
593 | BATADV_IF_DEFAULT); | ||
593 | if (!neigh_node) | 594 | if (!neigh_node) |
594 | goto free_orig; | 595 | goto free_orig; |
595 | 596 | ||
diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c index 4e8f5b1eedfc..9ece204d3a00 100644 --- a/net/batman-adv/gateway_client.c +++ b/net/batman-adv/gateway_client.c | |||
@@ -146,7 +146,7 @@ batadv_gw_get_best_gw_node(struct batadv_priv *bat_priv) | |||
146 | continue; | 146 | continue; |
147 | 147 | ||
148 | orig_node = gw_node->orig_node; | 148 | orig_node = gw_node->orig_node; |
149 | router = batadv_orig_node_get_router(orig_node); | 149 | router = batadv_orig_router_get(orig_node, BATADV_IF_DEFAULT); |
150 | if (!router) | 150 | if (!router) |
151 | continue; | 151 | continue; |
152 | 152 | ||
@@ -266,7 +266,8 @@ void batadv_gw_election(struct batadv_priv *bat_priv) | |||
266 | if (next_gw) { | 266 | if (next_gw) { |
267 | sprintf(gw_addr, "%pM", next_gw->orig_node->orig); | 267 | sprintf(gw_addr, "%pM", next_gw->orig_node->orig); |
268 | 268 | ||
269 | router = batadv_orig_node_get_router(next_gw->orig_node); | 269 | router = batadv_orig_router_get(next_gw->orig_node, |
270 | BATADV_IF_DEFAULT); | ||
270 | if (!router) { | 271 | if (!router) { |
271 | batadv_gw_reselect(bat_priv); | 272 | batadv_gw_reselect(bat_priv); |
272 | goto out; | 273 | goto out; |
@@ -335,7 +336,7 @@ void batadv_gw_check_election(struct batadv_priv *bat_priv, | |||
335 | if (!curr_gw_orig) | 336 | if (!curr_gw_orig) |
336 | goto reselect; | 337 | goto reselect; |
337 | 338 | ||
338 | router_gw = batadv_orig_node_get_router(curr_gw_orig); | 339 | router_gw = batadv_orig_router_get(curr_gw_orig, BATADV_IF_DEFAULT); |
339 | if (!router_gw) | 340 | if (!router_gw) |
340 | goto reselect; | 341 | goto reselect; |
341 | 342 | ||
@@ -348,7 +349,7 @@ void batadv_gw_check_election(struct batadv_priv *bat_priv, | |||
348 | if (curr_gw_orig == orig_node) | 349 | if (curr_gw_orig == orig_node) |
349 | goto out; | 350 | goto out; |
350 | 351 | ||
351 | router_orig = batadv_orig_node_get_router(orig_node); | 352 | router_orig = batadv_orig_router_get(orig_node, BATADV_IF_DEFAULT); |
352 | if (!router_orig) | 353 | if (!router_orig) |
353 | goto out; | 354 | goto out; |
354 | 355 | ||
@@ -576,7 +577,7 @@ static int batadv_write_buffer_text(struct batadv_priv *bat_priv, | |||
576 | struct batadv_neigh_ifinfo *router_ifinfo = NULL; | 577 | struct batadv_neigh_ifinfo *router_ifinfo = NULL; |
577 | int ret = -1; | 578 | int ret = -1; |
578 | 579 | ||
579 | router = batadv_orig_node_get_router(gw_node->orig_node); | 580 | router = batadv_orig_router_get(gw_node->orig_node, BATADV_IF_DEFAULT); |
580 | if (!router) | 581 | if (!router) |
581 | goto out; | 582 | goto out; |
582 | 583 | ||
diff --git a/net/batman-adv/icmp_socket.c b/net/batman-adv/icmp_socket.c index 3c08eee1b920..b384cb86f5ea 100644 --- a/net/batman-adv/icmp_socket.c +++ b/net/batman-adv/icmp_socket.c | |||
@@ -215,7 +215,8 @@ static ssize_t batadv_socket_write(struct file *file, const char __user *buff, | |||
215 | if (!orig_node) | 215 | if (!orig_node) |
216 | goto dst_unreach; | 216 | goto dst_unreach; |
217 | 217 | ||
218 | neigh_node = batadv_orig_node_get_router(orig_node); | 218 | neigh_node = batadv_orig_router_get(orig_node, |
219 | BATADV_IF_DEFAULT); | ||
219 | if (!neigh_node) | 220 | if (!neigh_node) |
220 | goto dst_unreach; | 221 | goto dst_unreach; |
221 | 222 | ||
diff --git a/net/batman-adv/network-coding.c b/net/batman-adv/network-coding.c index aec3fa564027..6a0b3284219f 100644 --- a/net/batman-adv/network-coding.c +++ b/net/batman-adv/network-coding.c | |||
@@ -718,9 +718,21 @@ static bool batadv_can_nc_with_orig(struct batadv_priv *bat_priv, | |||
718 | struct batadv_orig_node *orig_node, | 718 | struct batadv_orig_node *orig_node, |
719 | struct batadv_ogm_packet *ogm_packet) | 719 | struct batadv_ogm_packet *ogm_packet) |
720 | { | 720 | { |
721 | if (orig_node->last_real_seqno != ntohl(ogm_packet->seqno)) | 721 | struct batadv_orig_ifinfo *orig_ifinfo; |
722 | uint32_t last_real_seqno; | ||
723 | uint8_t last_ttl; | ||
724 | |||
725 | orig_ifinfo = batadv_orig_ifinfo_get(orig_node, BATADV_IF_DEFAULT); | ||
726 | if (!orig_ifinfo) | ||
722 | return false; | 727 | return false; |
723 | if (orig_node->last_ttl != ogm_packet->ttl + 1) | 728 | |
729 | last_ttl = orig_ifinfo->last_ttl; | ||
730 | last_real_seqno = orig_ifinfo->last_real_seqno; | ||
731 | batadv_orig_ifinfo_free_ref(orig_ifinfo); | ||
732 | |||
733 | if (last_real_seqno != ntohl(ogm_packet->seqno)) | ||
734 | return false; | ||
735 | if (last_ttl != ogm_packet->ttl + 1) | ||
724 | return false; | 736 | return false; |
725 | if (!batadv_compare_eth(ogm_packet->orig, ogm_packet->prev_sender)) | 737 | if (!batadv_compare_eth(ogm_packet->orig, ogm_packet->prev_sender)) |
726 | return false; | 738 | return false; |
@@ -1019,7 +1031,11 @@ static bool batadv_nc_code_packets(struct batadv_priv *bat_priv, | |||
1019 | int coded_size = sizeof(*coded_packet); | 1031 | int coded_size = sizeof(*coded_packet); |
1020 | int header_add = coded_size - unicast_size; | 1032 | int header_add = coded_size - unicast_size; |
1021 | 1033 | ||
1022 | router_neigh = batadv_orig_node_get_router(neigh_node->orig_node); | 1034 | /* TODO: do we need to consider the outgoing interface for |
1035 | * coded packets? | ||
1036 | */ | ||
1037 | router_neigh = batadv_orig_router_get(neigh_node->orig_node, | ||
1038 | BATADV_IF_DEFAULT); | ||
1023 | if (!router_neigh) | 1039 | if (!router_neigh) |
1024 | goto out; | 1040 | goto out; |
1025 | 1041 | ||
@@ -1029,7 +1045,8 @@ static bool batadv_nc_code_packets(struct batadv_priv *bat_priv, | |||
1029 | goto out; | 1045 | goto out; |
1030 | 1046 | ||
1031 | neigh_tmp = nc_packet->neigh_node; | 1047 | neigh_tmp = nc_packet->neigh_node; |
1032 | router_coding = batadv_orig_node_get_router(neigh_tmp->orig_node); | 1048 | router_coding = batadv_orig_router_get(neigh_tmp->orig_node, |
1049 | BATADV_IF_DEFAULT); | ||
1033 | if (!router_coding) | 1050 | if (!router_coding) |
1034 | goto out; | 1051 | goto out; |
1035 | 1052 | ||
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index 1a4725f5267d..b8ef41600166 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c | |||
@@ -231,14 +231,31 @@ void batadv_neigh_node_free_ref(struct batadv_neigh_node *neigh_node) | |||
231 | call_rcu(&neigh_node->rcu, batadv_neigh_node_free_rcu); | 231 | call_rcu(&neigh_node->rcu, batadv_neigh_node_free_rcu); |
232 | } | 232 | } |
233 | 233 | ||
234 | /* increases the refcounter of a found router */ | 234 | /** |
235 | * batadv_orig_node_get_router - router to the originator depending on iface | ||
236 | * @orig_node: the orig node for the router | ||
237 | * @if_outgoing: the interface where the payload packet has been received or | ||
238 | * the OGM should be sent to | ||
239 | * | ||
240 | * Returns the neighbor which should be router for this orig_node/iface. | ||
241 | * | ||
242 | * The object is returned with refcounter increased by 1. | ||
243 | */ | ||
235 | struct batadv_neigh_node * | 244 | struct batadv_neigh_node * |
236 | batadv_orig_node_get_router(struct batadv_orig_node *orig_node) | 245 | batadv_orig_router_get(struct batadv_orig_node *orig_node, |
246 | const struct batadv_hard_iface *if_outgoing) | ||
237 | { | 247 | { |
238 | struct batadv_neigh_node *router; | 248 | struct batadv_orig_ifinfo *orig_ifinfo; |
249 | struct batadv_neigh_node *router = NULL; | ||
239 | 250 | ||
240 | rcu_read_lock(); | 251 | rcu_read_lock(); |
241 | router = rcu_dereference(orig_node->router); | 252 | hlist_for_each_entry_rcu(orig_ifinfo, &orig_node->ifinfo_list, list) { |
253 | if (orig_ifinfo->if_outgoing != if_outgoing) | ||
254 | continue; | ||
255 | |||
256 | router = rcu_dereference(orig_ifinfo->router); | ||
257 | break; | ||
258 | } | ||
242 | 259 | ||
243 | if (router && !atomic_inc_not_zero(&router->refcount)) | 260 | if (router && !atomic_inc_not_zero(&router->refcount)) |
244 | router = NULL; | 261 | router = NULL; |
@@ -248,6 +265,86 @@ batadv_orig_node_get_router(struct batadv_orig_node *orig_node) | |||
248 | } | 265 | } |
249 | 266 | ||
250 | /** | 267 | /** |
268 | * batadv_orig_ifinfo_get - find the ifinfo from an orig_node | ||
269 | * @orig_node: the orig node to be queried | ||
270 | * @if_outgoing: the interface for which the ifinfo should be acquired | ||
271 | * | ||
272 | * Returns the requested orig_ifinfo or NULL if not found. | ||
273 | * | ||
274 | * The object is returned with refcounter increased by 1. | ||
275 | */ | ||
276 | struct batadv_orig_ifinfo * | ||
277 | batadv_orig_ifinfo_get(struct batadv_orig_node *orig_node, | ||
278 | struct batadv_hard_iface *if_outgoing) | ||
279 | { | ||
280 | struct batadv_orig_ifinfo *tmp, *orig_ifinfo = NULL; | ||
281 | |||
282 | rcu_read_lock(); | ||
283 | hlist_for_each_entry_rcu(tmp, &orig_node->ifinfo_list, | ||
284 | list) { | ||
285 | if (tmp->if_outgoing != if_outgoing) | ||
286 | continue; | ||
287 | |||
288 | if (!atomic_inc_not_zero(&tmp->refcount)) | ||
289 | continue; | ||
290 | |||
291 | orig_ifinfo = tmp; | ||
292 | break; | ||
293 | } | ||
294 | rcu_read_unlock(); | ||
295 | |||
296 | return orig_ifinfo; | ||
297 | } | ||
298 | |||
299 | /** | ||
300 | * batadv_orig_ifinfo_new - search and possibly create an orig_ifinfo object | ||
301 | * @orig_node: the orig node to be queried | ||
302 | * @if_outgoing: the interface for which the ifinfo should be acquired | ||
303 | * | ||
304 | * Returns NULL in case of failure or the orig_ifinfo object for the if_outgoing | ||
305 | * interface otherwise. The object is created and added to the list | ||
306 | * if it does not exist. | ||
307 | * | ||
308 | * The object is returned with refcounter increased by 1. | ||
309 | */ | ||
310 | struct batadv_orig_ifinfo * | ||
311 | batadv_orig_ifinfo_new(struct batadv_orig_node *orig_node, | ||
312 | struct batadv_hard_iface *if_outgoing) | ||
313 | { | ||
314 | struct batadv_orig_ifinfo *orig_ifinfo = NULL; | ||
315 | unsigned long reset_time; | ||
316 | |||
317 | spin_lock_bh(&orig_node->neigh_list_lock); | ||
318 | |||
319 | orig_ifinfo = batadv_orig_ifinfo_get(orig_node, if_outgoing); | ||
320 | if (orig_ifinfo) | ||
321 | goto out; | ||
322 | |||
323 | orig_ifinfo = kzalloc(sizeof(*orig_ifinfo), GFP_ATOMIC); | ||
324 | if (!orig_ifinfo) | ||
325 | goto out; | ||
326 | |||
327 | if (if_outgoing != BATADV_IF_DEFAULT && | ||
328 | !atomic_inc_not_zero(&if_outgoing->refcount)) { | ||
329 | kfree(orig_ifinfo); | ||
330 | orig_ifinfo = NULL; | ||
331 | goto out; | ||
332 | } | ||
333 | |||
334 | reset_time = jiffies - 1; | ||
335 | reset_time -= msecs_to_jiffies(BATADV_RESET_PROTECTION_MS); | ||
336 | orig_ifinfo->batman_seqno_reset = reset_time; | ||
337 | orig_ifinfo->if_outgoing = if_outgoing; | ||
338 | INIT_HLIST_NODE(&orig_ifinfo->list); | ||
339 | atomic_set(&orig_ifinfo->refcount, 2); | ||
340 | hlist_add_head_rcu(&orig_ifinfo->list, | ||
341 | &orig_node->ifinfo_list); | ||
342 | out: | ||
343 | spin_unlock_bh(&orig_node->neigh_list_lock); | ||
344 | return orig_ifinfo; | ||
345 | } | ||
346 | |||
347 | /** | ||
251 | * batadv_neigh_ifinfo_get - find the ifinfo from an neigh_node | 348 | * batadv_neigh_ifinfo_get - find the ifinfo from an neigh_node |
252 | * @neigh_node: the neigh node to be queried | 349 | * @neigh_node: the neigh node to be queried |
253 | * @if_outgoing: the interface for which the ifinfo should be acquired | 350 | * @if_outgoing: the interface for which the ifinfo should be acquired |
@@ -360,11 +457,51 @@ out: | |||
360 | return neigh_node; | 457 | return neigh_node; |
361 | } | 458 | } |
362 | 459 | ||
460 | /** | ||
461 | * batadv_orig_ifinfo_free_rcu - free the orig_ifinfo object | ||
462 | * @rcu: rcu pointer of the orig_ifinfo object | ||
463 | */ | ||
464 | static void batadv_orig_ifinfo_free_rcu(struct rcu_head *rcu) | ||
465 | { | ||
466 | struct batadv_orig_ifinfo *orig_ifinfo; | ||
467 | |||
468 | orig_ifinfo = container_of(rcu, struct batadv_orig_ifinfo, rcu); | ||
469 | |||
470 | if (orig_ifinfo->if_outgoing != BATADV_IF_DEFAULT) | ||
471 | batadv_hardif_free_ref_now(orig_ifinfo->if_outgoing); | ||
472 | |||
473 | kfree(orig_ifinfo); | ||
474 | } | ||
475 | |||
476 | /** | ||
477 | * batadv_orig_ifinfo_free_ref - decrement the refcounter and possibly free | ||
478 | * the orig_ifinfo (without rcu callback) | ||
479 | * @orig_ifinfo: the orig_ifinfo object to release | ||
480 | */ | ||
481 | static void | ||
482 | batadv_orig_ifinfo_free_ref_now(struct batadv_orig_ifinfo *orig_ifinfo) | ||
483 | { | ||
484 | if (atomic_dec_and_test(&orig_ifinfo->refcount)) | ||
485 | batadv_orig_ifinfo_free_rcu(&orig_ifinfo->rcu); | ||
486 | } | ||
487 | |||
488 | /** | ||
489 | * batadv_orig_ifinfo_free_ref - decrement the refcounter and possibly free | ||
490 | * the orig_ifinfo | ||
491 | * @orig_ifinfo: the orig_ifinfo object to release | ||
492 | */ | ||
493 | void batadv_orig_ifinfo_free_ref(struct batadv_orig_ifinfo *orig_ifinfo) | ||
494 | { | ||
495 | if (atomic_dec_and_test(&orig_ifinfo->refcount)) | ||
496 | call_rcu(&orig_ifinfo->rcu, batadv_orig_ifinfo_free_rcu); | ||
497 | } | ||
498 | |||
363 | static void batadv_orig_node_free_rcu(struct rcu_head *rcu) | 499 | static void batadv_orig_node_free_rcu(struct rcu_head *rcu) |
364 | { | 500 | { |
365 | struct hlist_node *node_tmp; | 501 | struct hlist_node *node_tmp; |
366 | struct batadv_neigh_node *neigh_node; | 502 | struct batadv_neigh_node *neigh_node; |
367 | struct batadv_orig_node *orig_node; | 503 | struct batadv_orig_node *orig_node; |
504 | struct batadv_orig_ifinfo *orig_ifinfo; | ||
368 | 505 | ||
369 | orig_node = container_of(rcu, struct batadv_orig_node, rcu); | 506 | orig_node = container_of(rcu, struct batadv_orig_node, rcu); |
370 | 507 | ||
@@ -377,6 +514,11 @@ static void batadv_orig_node_free_rcu(struct rcu_head *rcu) | |||
377 | batadv_neigh_node_free_ref_now(neigh_node); | 514 | batadv_neigh_node_free_ref_now(neigh_node); |
378 | } | 515 | } |
379 | 516 | ||
517 | hlist_for_each_entry_safe(orig_ifinfo, node_tmp, | ||
518 | &orig_node->ifinfo_list, list) { | ||
519 | hlist_del_rcu(&orig_ifinfo->list); | ||
520 | batadv_orig_ifinfo_free_ref_now(orig_ifinfo); | ||
521 | } | ||
380 | spin_unlock_bh(&orig_node->neigh_list_lock); | 522 | spin_unlock_bh(&orig_node->neigh_list_lock); |
381 | 523 | ||
382 | /* Free nc_nodes */ | 524 | /* Free nc_nodes */ |
@@ -474,6 +616,7 @@ struct batadv_orig_node *batadv_orig_node_new(struct batadv_priv *bat_priv, | |||
474 | 616 | ||
475 | INIT_HLIST_HEAD(&orig_node->neigh_list); | 617 | INIT_HLIST_HEAD(&orig_node->neigh_list); |
476 | INIT_LIST_HEAD(&orig_node->vlan_list); | 618 | INIT_LIST_HEAD(&orig_node->vlan_list); |
619 | INIT_HLIST_HEAD(&orig_node->ifinfo_list); | ||
477 | spin_lock_init(&orig_node->bcast_seqno_lock); | 620 | spin_lock_init(&orig_node->bcast_seqno_lock); |
478 | spin_lock_init(&orig_node->neigh_list_lock); | 621 | spin_lock_init(&orig_node->neigh_list_lock); |
479 | spin_lock_init(&orig_node->tt_buff_lock); | 622 | spin_lock_init(&orig_node->tt_buff_lock); |
@@ -489,13 +632,11 @@ struct batadv_orig_node *batadv_orig_node_new(struct batadv_priv *bat_priv, | |||
489 | orig_node->bat_priv = bat_priv; | 632 | orig_node->bat_priv = bat_priv; |
490 | memcpy(orig_node->orig, addr, ETH_ALEN); | 633 | memcpy(orig_node->orig, addr, ETH_ALEN); |
491 | batadv_dat_init_orig_node_addr(orig_node); | 634 | batadv_dat_init_orig_node_addr(orig_node); |
492 | orig_node->router = NULL; | ||
493 | atomic_set(&orig_node->last_ttvn, 0); | 635 | atomic_set(&orig_node->last_ttvn, 0); |
494 | orig_node->tt_buff = NULL; | 636 | orig_node->tt_buff = NULL; |
495 | orig_node->tt_buff_len = 0; | 637 | orig_node->tt_buff_len = 0; |
496 | reset_time = jiffies - 1 - msecs_to_jiffies(BATADV_RESET_PROTECTION_MS); | 638 | reset_time = jiffies - 1 - msecs_to_jiffies(BATADV_RESET_PROTECTION_MS); |
497 | orig_node->bcast_seqno_reset = reset_time; | 639 | orig_node->bcast_seqno_reset = reset_time; |
498 | orig_node->batman_seqno_reset = reset_time; | ||
499 | 640 | ||
500 | /* create a vlan object for the "untagged" LAN */ | 641 | /* create a vlan object for the "untagged" LAN */ |
501 | vlan = batadv_orig_node_vlan_new(orig_node, BATADV_NO_FLAGS); | 642 | vlan = batadv_orig_node_vlan_new(orig_node, BATADV_NO_FLAGS); |
@@ -520,6 +661,55 @@ free_orig_node: | |||
520 | } | 661 | } |
521 | 662 | ||
522 | /** | 663 | /** |
664 | * batadv_purge_orig_ifinfo - purge obsolete ifinfo entries from originator | ||
665 | * @bat_priv: the bat priv with all the soft interface information | ||
666 | * @orig_node: orig node which is to be checked | ||
667 | * | ||
668 | * Returns true if any ifinfo entry was purged, false otherwise. | ||
669 | */ | ||
670 | static bool | ||
671 | batadv_purge_orig_ifinfo(struct batadv_priv *bat_priv, | ||
672 | struct batadv_orig_node *orig_node) | ||
673 | { | ||
674 | struct batadv_orig_ifinfo *orig_ifinfo; | ||
675 | struct batadv_hard_iface *if_outgoing; | ||
676 | struct hlist_node *node_tmp; | ||
677 | bool ifinfo_purged = false; | ||
678 | |||
679 | spin_lock_bh(&orig_node->neigh_list_lock); | ||
680 | |||
681 | /* for all ifinfo objects for this originator */ | ||
682 | hlist_for_each_entry_safe(orig_ifinfo, node_tmp, | ||
683 | &orig_node->ifinfo_list, list) { | ||
684 | if_outgoing = orig_ifinfo->if_outgoing; | ||
685 | |||
686 | /* always keep the default interface */ | ||
687 | if (if_outgoing == BATADV_IF_DEFAULT) | ||
688 | continue; | ||
689 | |||
690 | /* don't purge if the interface is not (going) down */ | ||
691 | if ((if_outgoing->if_status != BATADV_IF_INACTIVE) && | ||
692 | (if_outgoing->if_status != BATADV_IF_NOT_IN_USE) && | ||
693 | (if_outgoing->if_status != BATADV_IF_TO_BE_REMOVED)) | ||
694 | continue; | ||
695 | |||
696 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, | ||
697 | "router/ifinfo purge: originator %pM, iface: %s\n", | ||
698 | orig_node->orig, if_outgoing->net_dev->name); | ||
699 | |||
700 | ifinfo_purged = true; | ||
701 | |||
702 | hlist_del_rcu(&orig_ifinfo->list); | ||
703 | batadv_orig_ifinfo_free_ref(orig_ifinfo); | ||
704 | } | ||
705 | |||
706 | spin_unlock_bh(&orig_node->neigh_list_lock); | ||
707 | |||
708 | return ifinfo_purged; | ||
709 | } | ||
710 | |||
711 | |||
712 | /** | ||
523 | * batadv_purge_orig_neighbors - purges neighbors from originator | 713 | * batadv_purge_orig_neighbors - purges neighbors from originator |
524 | * @bat_priv: the bat priv with all the soft interface information | 714 | * @bat_priv: the bat priv with all the soft interface information |
525 | * @orig_node: orig node which is to be checked | 715 | * @orig_node: orig node which is to be checked |
@@ -607,10 +797,22 @@ batadv_find_best_neighbor(struct batadv_priv *bat_priv, | |||
607 | return best; | 797 | return best; |
608 | } | 798 | } |
609 | 799 | ||
800 | /** | ||
801 | * batadv_purge_orig_node - purges obsolete information from an orig_node | ||
802 | * @bat_priv: the bat priv with all the soft interface information | ||
803 | * @orig_node: orig node which is to be checked | ||
804 | * | ||
805 | * This function checks if the orig_node or substructures of it have become | ||
806 | * obsolete, and purges this information if that's the case. | ||
807 | * | ||
808 | * Returns true if the orig_node is to be removed, false otherwise. | ||
809 | */ | ||
610 | static bool batadv_purge_orig_node(struct batadv_priv *bat_priv, | 810 | static bool batadv_purge_orig_node(struct batadv_priv *bat_priv, |
611 | struct batadv_orig_node *orig_node) | 811 | struct batadv_orig_node *orig_node) |
612 | { | 812 | { |
613 | struct batadv_neigh_node *best_neigh_node; | 813 | struct batadv_neigh_node *best_neigh_node; |
814 | struct batadv_hard_iface *hard_iface; | ||
815 | bool changed; | ||
614 | 816 | ||
615 | if (batadv_has_timed_out(orig_node->last_seen, | 817 | if (batadv_has_timed_out(orig_node->last_seen, |
616 | 2 * BATADV_PURGE_TIMEOUT)) { | 818 | 2 * BATADV_PURGE_TIMEOUT)) { |
@@ -620,15 +822,39 @@ static bool batadv_purge_orig_node(struct batadv_priv *bat_priv, | |||
620 | jiffies_to_msecs(orig_node->last_seen)); | 822 | jiffies_to_msecs(orig_node->last_seen)); |
621 | return true; | 823 | return true; |
622 | } | 824 | } |
623 | if (!batadv_purge_orig_neighbors(bat_priv, orig_node)) | 825 | changed = batadv_purge_orig_ifinfo(bat_priv, orig_node); |
826 | changed = changed || batadv_purge_orig_neighbors(bat_priv, orig_node); | ||
827 | |||
828 | if (!changed) | ||
624 | return false; | 829 | return false; |
625 | 830 | ||
831 | /* first for NULL ... */ | ||
626 | best_neigh_node = batadv_find_best_neighbor(bat_priv, orig_node, | 832 | best_neigh_node = batadv_find_best_neighbor(bat_priv, orig_node, |
627 | BATADV_IF_DEFAULT); | 833 | BATADV_IF_DEFAULT); |
628 | batadv_update_route(bat_priv, orig_node, best_neigh_node); | 834 | batadv_update_route(bat_priv, orig_node, BATADV_IF_DEFAULT, |
835 | best_neigh_node); | ||
629 | if (best_neigh_node) | 836 | if (best_neigh_node) |
630 | batadv_neigh_node_free_ref(best_neigh_node); | 837 | batadv_neigh_node_free_ref(best_neigh_node); |
631 | 838 | ||
839 | /* ... then for all other interfaces. */ | ||
840 | rcu_read_lock(); | ||
841 | list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) { | ||
842 | if (hard_iface->if_status != BATADV_IF_ACTIVE) | ||
843 | continue; | ||
844 | |||
845 | if (hard_iface->soft_iface != bat_priv->soft_iface) | ||
846 | continue; | ||
847 | |||
848 | best_neigh_node = batadv_find_best_neighbor(bat_priv, | ||
849 | orig_node, | ||
850 | hard_iface); | ||
851 | batadv_update_route(bat_priv, orig_node, hard_iface, | ||
852 | best_neigh_node); | ||
853 | if (best_neigh_node) | ||
854 | batadv_neigh_node_free_ref(best_neigh_node); | ||
855 | } | ||
856 | rcu_read_unlock(); | ||
857 | |||
632 | return false; | 858 | return false; |
633 | } | 859 | } |
634 | 860 | ||
diff --git a/net/batman-adv/originator.h b/net/batman-adv/originator.h index 29fa4c428b59..75a4d7bad620 100644 --- a/net/batman-adv/originator.h +++ b/net/batman-adv/originator.h | |||
@@ -34,7 +34,8 @@ batadv_neigh_node_new(struct batadv_hard_iface *hard_iface, | |||
34 | struct batadv_orig_node *orig_node); | 34 | struct batadv_orig_node *orig_node); |
35 | void batadv_neigh_node_free_ref(struct batadv_neigh_node *neigh_node); | 35 | void batadv_neigh_node_free_ref(struct batadv_neigh_node *neigh_node); |
36 | struct batadv_neigh_node * | 36 | struct batadv_neigh_node * |
37 | batadv_orig_node_get_router(struct batadv_orig_node *orig_node); | 37 | batadv_orig_router_get(struct batadv_orig_node *orig_node, |
38 | const struct batadv_hard_iface *if_outgoing); | ||
38 | struct batadv_neigh_ifinfo * | 39 | struct batadv_neigh_ifinfo * |
39 | batadv_neigh_ifinfo_new(struct batadv_neigh_node *neigh, | 40 | batadv_neigh_ifinfo_new(struct batadv_neigh_node *neigh, |
40 | struct batadv_hard_iface *if_outgoing); | 41 | struct batadv_hard_iface *if_outgoing); |
@@ -42,6 +43,15 @@ struct batadv_neigh_ifinfo * | |||
42 | batadv_neigh_ifinfo_get(struct batadv_neigh_node *neigh, | 43 | batadv_neigh_ifinfo_get(struct batadv_neigh_node *neigh, |
43 | struct batadv_hard_iface *if_outgoing); | 44 | struct batadv_hard_iface *if_outgoing); |
44 | void batadv_neigh_ifinfo_free_ref(struct batadv_neigh_ifinfo *neigh_ifinfo); | 45 | void batadv_neigh_ifinfo_free_ref(struct batadv_neigh_ifinfo *neigh_ifinfo); |
46 | |||
47 | struct batadv_orig_ifinfo * | ||
48 | batadv_orig_ifinfo_get(struct batadv_orig_node *orig_node, | ||
49 | struct batadv_hard_iface *if_outgoing); | ||
50 | struct batadv_orig_ifinfo * | ||
51 | batadv_orig_ifinfo_new(struct batadv_orig_node *orig_node, | ||
52 | struct batadv_hard_iface *if_outgoing); | ||
53 | void batadv_orig_ifinfo_free_ref(struct batadv_orig_ifinfo *orig_ifinfo); | ||
54 | |||
45 | int batadv_orig_seq_print_text(struct seq_file *seq, void *offset); | 55 | int batadv_orig_seq_print_text(struct seq_file *seq, void *offset); |
46 | int batadv_orig_hash_add_if(struct batadv_hard_iface *hard_iface, | 56 | int batadv_orig_hash_add_if(struct batadv_hard_iface *hard_iface, |
47 | int max_if_num); | 57 | int max_if_num); |
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index 4fd2687b88c2..55e9aebcbc80 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c | |||
@@ -33,13 +33,32 @@ | |||
33 | static int batadv_route_unicast_packet(struct sk_buff *skb, | 33 | static int batadv_route_unicast_packet(struct sk_buff *skb, |
34 | struct batadv_hard_iface *recv_if); | 34 | struct batadv_hard_iface *recv_if); |
35 | 35 | ||
36 | /** | ||
37 | * _batadv_update_route - set the router for this originator | ||
38 | * @bat_priv: the bat priv with all the soft interface information | ||
39 | * @orig_node: orig node which is to be configured | ||
40 | * @recv_if: the receive interface for which this route is set | ||
41 | * @neigh_node: neighbor which should be the next router | ||
42 | * | ||
43 | * This function does not perform any error checks | ||
44 | */ | ||
36 | static void _batadv_update_route(struct batadv_priv *bat_priv, | 45 | static void _batadv_update_route(struct batadv_priv *bat_priv, |
37 | struct batadv_orig_node *orig_node, | 46 | struct batadv_orig_node *orig_node, |
47 | struct batadv_hard_iface *recv_if, | ||
38 | struct batadv_neigh_node *neigh_node) | 48 | struct batadv_neigh_node *neigh_node) |
39 | { | 49 | { |
50 | struct batadv_orig_ifinfo *orig_ifinfo; | ||
40 | struct batadv_neigh_node *curr_router; | 51 | struct batadv_neigh_node *curr_router; |
41 | 52 | ||
42 | curr_router = batadv_orig_node_get_router(orig_node); | 53 | orig_ifinfo = batadv_orig_ifinfo_get(orig_node, recv_if); |
54 | if (!orig_ifinfo) | ||
55 | return; | ||
56 | |||
57 | rcu_read_lock(); | ||
58 | curr_router = rcu_dereference(orig_ifinfo->router); | ||
59 | if (curr_router && !atomic_inc_not_zero(&curr_router->refcount)) | ||
60 | curr_router = NULL; | ||
61 | rcu_read_unlock(); | ||
43 | 62 | ||
44 | /* route deleted */ | 63 | /* route deleted */ |
45 | if ((curr_router) && (!neigh_node)) { | 64 | if ((curr_router) && (!neigh_node)) { |
@@ -69,16 +88,25 @@ static void _batadv_update_route(struct batadv_priv *bat_priv, | |||
69 | neigh_node = NULL; | 88 | neigh_node = NULL; |
70 | 89 | ||
71 | spin_lock_bh(&orig_node->neigh_list_lock); | 90 | spin_lock_bh(&orig_node->neigh_list_lock); |
72 | rcu_assign_pointer(orig_node->router, neigh_node); | 91 | rcu_assign_pointer(orig_ifinfo->router, neigh_node); |
73 | spin_unlock_bh(&orig_node->neigh_list_lock); | 92 | spin_unlock_bh(&orig_node->neigh_list_lock); |
93 | batadv_orig_ifinfo_free_ref(orig_ifinfo); | ||
74 | 94 | ||
75 | /* decrease refcount of previous best neighbor */ | 95 | /* decrease refcount of previous best neighbor */ |
76 | if (curr_router) | 96 | if (curr_router) |
77 | batadv_neigh_node_free_ref(curr_router); | 97 | batadv_neigh_node_free_ref(curr_router); |
78 | } | 98 | } |
79 | 99 | ||
100 | /** | ||
101 | * batadv_update_route - set the router for this originator | ||
102 | * @bat_priv: the bat priv with all the soft interface information | ||
103 | * @orig_node: orig node which is to be configured | ||
104 | * @recv_if: the receive interface for which this route is set | ||
105 | * @neigh_node: neighbor which should be the next router | ||
106 | */ | ||
80 | void batadv_update_route(struct batadv_priv *bat_priv, | 107 | void batadv_update_route(struct batadv_priv *bat_priv, |
81 | struct batadv_orig_node *orig_node, | 108 | struct batadv_orig_node *orig_node, |
109 | struct batadv_hard_iface *recv_if, | ||
82 | struct batadv_neigh_node *neigh_node) | 110 | struct batadv_neigh_node *neigh_node) |
83 | { | 111 | { |
84 | struct batadv_neigh_node *router = NULL; | 112 | struct batadv_neigh_node *router = NULL; |
@@ -86,10 +114,10 @@ void batadv_update_route(struct batadv_priv *bat_priv, | |||
86 | if (!orig_node) | 114 | if (!orig_node) |
87 | goto out; | 115 | goto out; |
88 | 116 | ||
89 | router = batadv_orig_node_get_router(orig_node); | 117 | router = batadv_orig_router_get(orig_node, recv_if); |
90 | 118 | ||
91 | if (router != neigh_node) | 119 | if (router != neigh_node) |
92 | _batadv_update_route(bat_priv, orig_node, neigh_node); | 120 | _batadv_update_route(bat_priv, orig_node, recv_if, neigh_node); |
93 | 121 | ||
94 | out: | 122 | out: |
95 | if (router) | 123 | if (router) |
@@ -406,7 +434,7 @@ batadv_find_router(struct batadv_priv *bat_priv, | |||
406 | if (!orig_node) | 434 | if (!orig_node) |
407 | return NULL; | 435 | return NULL; |
408 | 436 | ||
409 | router = batadv_orig_node_get_router(orig_node); | 437 | router = batadv_orig_router_get(orig_node, recv_if); |
410 | 438 | ||
411 | /* TODO: fill this later with new bonding mechanism */ | 439 | /* TODO: fill this later with new bonding mechanism */ |
412 | 440 | ||
diff --git a/net/batman-adv/routing.h b/net/batman-adv/routing.h index 192f0aab7a2b..8920d0b1056c 100644 --- a/net/batman-adv/routing.h +++ b/net/batman-adv/routing.h | |||
@@ -23,6 +23,7 @@ bool batadv_check_management_packet(struct sk_buff *skb, | |||
23 | int header_len); | 23 | int header_len); |
24 | void batadv_update_route(struct batadv_priv *bat_priv, | 24 | void batadv_update_route(struct batadv_priv *bat_priv, |
25 | struct batadv_orig_node *orig_node, | 25 | struct batadv_orig_node *orig_node, |
26 | struct batadv_hard_iface *recv_if, | ||
26 | struct batadv_neigh_node *neigh_node); | 27 | struct batadv_neigh_node *neigh_node); |
27 | int batadv_recv_icmp_packet(struct sk_buff *skb, | 28 | int batadv_recv_icmp_packet(struct sk_buff *skb, |
28 | struct batadv_hard_iface *recv_if); | 29 | struct batadv_hard_iface *recv_if); |
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index 22c32ae12e65..ec89a1b9fc06 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c | |||
@@ -1400,7 +1400,8 @@ batadv_transtable_best_orig(struct batadv_priv *bat_priv, | |||
1400 | 1400 | ||
1401 | head = &tt_global_entry->orig_list; | 1401 | head = &tt_global_entry->orig_list; |
1402 | hlist_for_each_entry_rcu(orig_entry, head, list) { | 1402 | hlist_for_each_entry_rcu(orig_entry, head, list) { |
1403 | router = batadv_orig_node_get_router(orig_entry->orig_node); | 1403 | router = batadv_orig_router_get(orig_entry->orig_node, |
1404 | BATADV_IF_DEFAULT); | ||
1404 | if (!router) | 1405 | if (!router) |
1405 | continue; | 1406 | continue; |
1406 | 1407 | ||
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 8435d7c83a14..d3e2bf486ec0 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h | |||
@@ -101,6 +101,28 @@ struct batadv_hard_iface { | |||
101 | }; | 101 | }; |
102 | 102 | ||
103 | /** | 103 | /** |
104 | * struct batadv_orig_ifinfo - originator info per outgoing interface | ||
105 | * @list: list node for orig_node::ifinfo_list | ||
106 | * @if_outgoing: pointer to outgoing hard interface | ||
107 | * @router: router that should be used to reach this originator | ||
108 | * @last_real_seqno: last and best known sequence number | ||
109 | * @last_ttl: ttl of last received packet | ||
110 | * @batman_seqno_reset: time when the batman seqno window was reset | ||
111 | * @refcount: number of contexts the object is used | ||
112 | * @rcu: struct used for freeing in an RCU-safe manner | ||
113 | */ | ||
114 | struct batadv_orig_ifinfo { | ||
115 | struct hlist_node list; | ||
116 | struct batadv_hard_iface *if_outgoing; | ||
117 | struct batadv_neigh_node __rcu *router; /* rcu protected pointer */ | ||
118 | uint32_t last_real_seqno; | ||
119 | uint8_t last_ttl; | ||
120 | unsigned long batman_seqno_reset; | ||
121 | atomic_t refcount; | ||
122 | struct rcu_head rcu; | ||
123 | }; | ||
124 | |||
125 | /** | ||
104 | * struct batadv_frag_table_entry - head in the fragment buffer table | 126 | * struct batadv_frag_table_entry - head in the fragment buffer table |
105 | * @head: head of list with fragments | 127 | * @head: head of list with fragments |
106 | * @lock: lock to protect the list of fragments | 128 | * @lock: lock to protect the list of fragments |
@@ -175,11 +197,10 @@ struct batadv_orig_bat_iv { | |||
175 | * struct batadv_orig_node - structure for orig_list maintaining nodes of mesh | 197 | * struct batadv_orig_node - structure for orig_list maintaining nodes of mesh |
176 | * @orig: originator ethernet address | 198 | * @orig: originator ethernet address |
177 | * @primary_addr: hosts primary interface address | 199 | * @primary_addr: hosts primary interface address |
178 | * @router: router that should be used to reach this originator | 200 | * @ifinfo_list: list for routers per outgoing interface |
179 | * @batadv_dat_addr_t: address of the orig node in the distributed hash | 201 | * @batadv_dat_addr_t: address of the orig node in the distributed hash |
180 | * @last_seen: time when last packet from this node was received | 202 | * @last_seen: time when last packet from this node was received |
181 | * @bcast_seqno_reset: time when the broadcast seqno window was reset | 203 | * @bcast_seqno_reset: time when the broadcast seqno window was reset |
182 | * @batman_seqno_reset: time when the batman seqno window was reset | ||
183 | * @capabilities: announced capabilities of this originator | 204 | * @capabilities: announced capabilities of this originator |
184 | * @last_ttvn: last seen translation table version number | 205 | * @last_ttvn: last seen translation table version number |
185 | * @tt_buff: last tt changeset this node received from the orig node | 206 | * @tt_buff: last tt changeset this node received from the orig node |
@@ -192,8 +213,6 @@ struct batadv_orig_bat_iv { | |||
192 | * made up by two operations (data structure update and metdata -CRC/TTVN- | 213 | * made up by two operations (data structure update and metdata -CRC/TTVN- |
193 | * recalculation) and they have to be executed atomically in order to avoid | 214 | * recalculation) and they have to be executed atomically in order to avoid |
194 | * another thread to read the table/metadata between those. | 215 | * another thread to read the table/metadata between those. |
195 | * @last_real_seqno: last and best known sequence number | ||
196 | * @last_ttl: ttl of last received packet | ||
197 | * @bcast_bits: bitfield containing the info which payload broadcast originated | 216 | * @bcast_bits: bitfield containing the info which payload broadcast originated |
198 | * from this orig node this host already has seen (relative to | 217 | * from this orig node this host already has seen (relative to |
199 | * last_bcast_seqno) | 218 | * last_bcast_seqno) |
@@ -218,13 +237,12 @@ struct batadv_orig_bat_iv { | |||
218 | struct batadv_orig_node { | 237 | struct batadv_orig_node { |
219 | uint8_t orig[ETH_ALEN]; | 238 | uint8_t orig[ETH_ALEN]; |
220 | uint8_t primary_addr[ETH_ALEN]; | 239 | uint8_t primary_addr[ETH_ALEN]; |
221 | struct batadv_neigh_node __rcu *router; /* rcu protected pointer */ | 240 | struct hlist_head ifinfo_list; |
222 | #ifdef CONFIG_BATMAN_ADV_DAT | 241 | #ifdef CONFIG_BATMAN_ADV_DAT |
223 | batadv_dat_addr_t dat_addr; | 242 | batadv_dat_addr_t dat_addr; |
224 | #endif | 243 | #endif |
225 | unsigned long last_seen; | 244 | unsigned long last_seen; |
226 | unsigned long bcast_seqno_reset; | 245 | unsigned long bcast_seqno_reset; |
227 | unsigned long batman_seqno_reset; | ||
228 | uint8_t capabilities; | 246 | uint8_t capabilities; |
229 | atomic_t last_ttvn; | 247 | atomic_t last_ttvn; |
230 | unsigned char *tt_buff; | 248 | unsigned char *tt_buff; |
@@ -233,8 +251,6 @@ struct batadv_orig_node { | |||
233 | bool tt_initialised; | 251 | bool tt_initialised; |
234 | /* prevents from changing the table while reading it */ | 252 | /* prevents from changing the table while reading it */ |
235 | spinlock_t tt_lock; | 253 | spinlock_t tt_lock; |
236 | uint32_t last_real_seqno; | ||
237 | uint8_t last_ttl; | ||
238 | DECLARE_BITMAP(bcast_bits, BATADV_TQ_LOCAL_WINDOW_SIZE); | 254 | DECLARE_BITMAP(bcast_bits, BATADV_TQ_LOCAL_WINDOW_SIZE); |
239 | uint32_t last_bcast_seqno; | 255 | uint32_t last_bcast_seqno; |
240 | struct hlist_head neigh_list; | 256 | struct hlist_head neigh_list; |