diff options
Diffstat (limited to 'net')
| -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; |
