.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright (c) 2008, 2009 open80211s Ltd. |
---|
| 4 | + * Copyright (C) 2019 Intel Corporation |
---|
3 | 5 | * Author: Luis Carlos Cobo <luisca@cozybit.com> |
---|
4 | | - * |
---|
5 | | - * This program is free software; you can redistribute it and/or modify |
---|
6 | | - * it under the terms of the GNU General Public License version 2 as |
---|
7 | | - * published by the Free Software Foundation. |
---|
8 | 6 | */ |
---|
9 | 7 | |
---|
10 | 8 | #include <linux/slab.h> |
---|
.. | .. |
---|
214 | 212 | skb->priority = 7; |
---|
215 | 213 | |
---|
216 | 214 | info->control.vif = &sdata->vif; |
---|
217 | | - info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; |
---|
| 215 | + info->control.flags |= IEEE80211_TX_INTCFL_NEED_TXPROCESSING; |
---|
218 | 216 | ieee80211_set_qos_hdr(sdata, skb); |
---|
219 | 217 | ieee80211_mps_set_frame_flags(sdata, NULL, hdr); |
---|
220 | 218 | } |
---|
.. | .. |
---|
300 | 298 | { |
---|
301 | 299 | struct ieee80211_tx_info *txinfo = st->info; |
---|
302 | 300 | int failed; |
---|
| 301 | + struct rate_info rinfo; |
---|
303 | 302 | |
---|
304 | 303 | failed = !(txinfo->flags & IEEE80211_TX_STAT_ACK); |
---|
305 | 304 | |
---|
.. | .. |
---|
310 | 309 | if (ewma_mesh_fail_avg_read(&sta->mesh->fail_avg) > |
---|
311 | 310 | LINK_FAIL_THRESH) |
---|
312 | 311 | mesh_plink_broken(sta); |
---|
| 312 | + |
---|
| 313 | + sta_set_rate_info_tx(sta, &sta->tx_stats.last_rate, &rinfo); |
---|
| 314 | + ewma_mesh_tx_rate_avg_add(&sta->mesh->tx_rate_avg, |
---|
| 315 | + cfg80211_calculate_bitrate(&rinfo)); |
---|
313 | 316 | } |
---|
314 | 317 | |
---|
315 | | -static u32 airtime_link_metric_get(struct ieee80211_local *local, |
---|
316 | | - struct sta_info *sta) |
---|
| 318 | +u32 airtime_link_metric_get(struct ieee80211_local *local, |
---|
| 319 | + struct sta_info *sta) |
---|
317 | 320 | { |
---|
318 | | - struct rate_info rinfo; |
---|
319 | 321 | /* This should be adjusted for each device */ |
---|
320 | 322 | int device_constant = 1 << ARITH_SHIFT; |
---|
321 | 323 | int test_frame_len = TEST_FRAME_LEN << ARITH_SHIFT; |
---|
.. | .. |
---|
342 | 344 | if (fail_avg > LINK_FAIL_THRESH) |
---|
343 | 345 | return MAX_METRIC; |
---|
344 | 346 | |
---|
345 | | - sta_set_rate_info_tx(sta, &sta->tx_stats.last_rate, &rinfo); |
---|
346 | | - rate = cfg80211_calculate_bitrate(&rinfo); |
---|
| 347 | + rate = ewma_mesh_tx_rate_avg_read(&sta->mesh->tx_rate_avg); |
---|
347 | 348 | if (WARN_ON(!rate)) |
---|
348 | 349 | return MAX_METRIC; |
---|
349 | 350 | |
---|
.. | .. |
---|
389 | 390 | unsigned long orig_lifetime, exp_time; |
---|
390 | 391 | u32 last_hop_metric, new_metric; |
---|
391 | 392 | bool process = true; |
---|
| 393 | + u8 hopcount; |
---|
392 | 394 | |
---|
393 | 395 | rcu_read_lock(); |
---|
394 | 396 | sta = sta_info_get(sdata, mgmt->sa); |
---|
.. | .. |
---|
407 | 409 | orig_sn = PREQ_IE_ORIG_SN(hwmp_ie); |
---|
408 | 410 | orig_lifetime = PREQ_IE_LIFETIME(hwmp_ie); |
---|
409 | 411 | orig_metric = PREQ_IE_METRIC(hwmp_ie); |
---|
| 412 | + hopcount = PREQ_IE_HOPCOUNT(hwmp_ie) + 1; |
---|
410 | 413 | break; |
---|
411 | 414 | case MPATH_PREP: |
---|
412 | 415 | /* Originator here refers to the MP that was the target in the |
---|
.. | .. |
---|
418 | 421 | orig_sn = PREP_IE_TARGET_SN(hwmp_ie); |
---|
419 | 422 | orig_lifetime = PREP_IE_LIFETIME(hwmp_ie); |
---|
420 | 423 | orig_metric = PREP_IE_METRIC(hwmp_ie); |
---|
| 424 | + hopcount = PREP_IE_HOPCOUNT(hwmp_ie) + 1; |
---|
421 | 425 | break; |
---|
422 | 426 | default: |
---|
423 | 427 | rcu_read_unlock(); |
---|
.. | .. |
---|
444 | 448 | (mpath->flags & MESH_PATH_SN_VALID)) { |
---|
445 | 449 | if (SN_GT(mpath->sn, orig_sn) || |
---|
446 | 450 | (mpath->sn == orig_sn && |
---|
447 | | - new_metric >= mpath->metric)) { |
---|
| 451 | + (rcu_access_pointer(mpath->next_hop) != |
---|
| 452 | + sta ? |
---|
| 453 | + mult_frac(new_metric, 10, 9) : |
---|
| 454 | + new_metric) >= mpath->metric)) { |
---|
448 | 455 | process = false; |
---|
449 | 456 | fresh_info = false; |
---|
450 | 457 | } |
---|
.. | .. |
---|
479 | 486 | } |
---|
480 | 487 | |
---|
481 | 488 | if (fresh_info) { |
---|
| 489 | + if (rcu_access_pointer(mpath->next_hop) != sta) |
---|
| 490 | + mpath->path_change_count++; |
---|
482 | 491 | mesh_path_assign_nexthop(mpath, sta); |
---|
483 | 492 | mpath->flags |= MESH_PATH_SN_VALID; |
---|
484 | 493 | mpath->metric = new_metric; |
---|
485 | 494 | mpath->sn = orig_sn; |
---|
486 | 495 | mpath->exp_time = time_after(mpath->exp_time, exp_time) |
---|
487 | 496 | ? mpath->exp_time : exp_time; |
---|
| 497 | + mpath->hop_count = hopcount; |
---|
488 | 498 | mesh_path_activate(mpath); |
---|
489 | 499 | spin_unlock_bh(&mpath->state_lock); |
---|
490 | 500 | ewma_mesh_fail_avg_init(&sta->mesh->fail_avg); |
---|
.. | .. |
---|
509 | 519 | if (mpath) { |
---|
510 | 520 | spin_lock_bh(&mpath->state_lock); |
---|
511 | 521 | if ((mpath->flags & MESH_PATH_FIXED) || |
---|
512 | | - ((mpath->flags & MESH_PATH_ACTIVE) && |
---|
513 | | - (last_hop_metric > mpath->metric))) |
---|
| 522 | + ((mpath->flags & MESH_PATH_ACTIVE) && |
---|
| 523 | + ((rcu_access_pointer(mpath->next_hop) != sta ? |
---|
| 524 | + mult_frac(last_hop_metric, 10, 9) : |
---|
| 525 | + last_hop_metric) > mpath->metric))) |
---|
514 | 526 | fresh_info = false; |
---|
515 | 527 | } else { |
---|
516 | 528 | mpath = mesh_path_add(sdata, ta); |
---|
.. | .. |
---|
522 | 534 | } |
---|
523 | 535 | |
---|
524 | 536 | if (fresh_info) { |
---|
| 537 | + if (rcu_access_pointer(mpath->next_hop) != sta) |
---|
| 538 | + mpath->path_change_count++; |
---|
525 | 539 | mesh_path_assign_nexthop(mpath, sta); |
---|
526 | 540 | mpath->metric = last_hop_metric; |
---|
527 | 541 | mpath->exp_time = time_after(mpath->exp_time, exp_time) |
---|
528 | 542 | ? mpath->exp_time : exp_time; |
---|
| 543 | + mpath->hop_count = 1; |
---|
529 | 544 | mesh_path_activate(mpath); |
---|
530 | 545 | spin_unlock_bh(&mpath->state_lock); |
---|
531 | 546 | ewma_mesh_fail_avg_init(&sta->mesh->fail_avg); |
---|
.. | .. |
---|
912 | 927 | |
---|
913 | 928 | baselen = (u8 *) mgmt->u.action.u.mesh_action.variable - (u8 *) mgmt; |
---|
914 | 929 | ieee802_11_parse_elems(mgmt->u.action.u.mesh_action.variable, |
---|
915 | | - len - baselen, false, &elems); |
---|
| 930 | + len - baselen, false, &elems, mgmt->bssid, NULL); |
---|
916 | 931 | |
---|
917 | 932 | if (elems.preq) { |
---|
918 | 933 | if (elems.preq_len != 37) |
---|
.. | .. |
---|
1090 | 1105 | ttl, lifetime, 0, ifmsh->preq_id++, sdata); |
---|
1091 | 1106 | |
---|
1092 | 1107 | spin_lock_bh(&mpath->state_lock); |
---|
1093 | | - if (mpath->flags & MESH_PATH_DELETED) { |
---|
1094 | | - spin_unlock_bh(&mpath->state_lock); |
---|
1095 | | - goto enddiscovery; |
---|
1096 | | - } |
---|
1097 | | - mod_timer(&mpath->timer, jiffies + mpath->discovery_timeout); |
---|
| 1108 | + if (!(mpath->flags & MESH_PATH_DELETED)) |
---|
| 1109 | + mod_timer(&mpath->timer, jiffies + mpath->discovery_timeout); |
---|
1098 | 1110 | spin_unlock_bh(&mpath->state_lock); |
---|
1099 | 1111 | |
---|
1100 | 1112 | enddiscovery: |
---|
.. | .. |
---|
1122 | 1134 | struct mesh_path *mpath; |
---|
1123 | 1135 | struct sk_buff *skb_to_free = NULL; |
---|
1124 | 1136 | u8 *target_addr = hdr->addr3; |
---|
1125 | | - int err = 0; |
---|
1126 | 1137 | |
---|
1127 | 1138 | /* Nulls are only sent to peers for PS and should be pre-addressed */ |
---|
1128 | 1139 | if (ieee80211_is_qos_nullfunc(hdr->frame_control)) |
---|
1129 | 1140 | return 0; |
---|
1130 | 1141 | |
---|
1131 | | - rcu_read_lock(); |
---|
1132 | | - err = mesh_nexthop_lookup(sdata, skb); |
---|
1133 | | - if (!err) |
---|
1134 | | - goto endlookup; |
---|
| 1142 | + /* Allow injected packets to bypass mesh routing */ |
---|
| 1143 | + if (info->control.flags & IEEE80211_TX_CTRL_SKIP_MPATH_LOOKUP) |
---|
| 1144 | + return 0; |
---|
| 1145 | + |
---|
| 1146 | + if (!mesh_nexthop_lookup(sdata, skb)) |
---|
| 1147 | + return 0; |
---|
1135 | 1148 | |
---|
1136 | 1149 | /* no nexthop found, start resolving */ |
---|
1137 | 1150 | mpath = mesh_path_lookup(sdata, target_addr); |
---|
.. | .. |
---|
1139 | 1152 | mpath = mesh_path_add(sdata, target_addr); |
---|
1140 | 1153 | if (IS_ERR(mpath)) { |
---|
1141 | 1154 | mesh_path_discard_frame(sdata, skb); |
---|
1142 | | - err = PTR_ERR(mpath); |
---|
1143 | | - goto endlookup; |
---|
| 1155 | + return PTR_ERR(mpath); |
---|
1144 | 1156 | } |
---|
1145 | 1157 | } |
---|
1146 | 1158 | |
---|
.. | .. |
---|
1151 | 1163 | if (skb_queue_len(&mpath->frame_queue) >= MESH_FRAME_QUEUE_LEN) |
---|
1152 | 1164 | skb_to_free = skb_dequeue(&mpath->frame_queue); |
---|
1153 | 1165 | |
---|
1154 | | - info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; |
---|
| 1166 | + info->control.flags |= IEEE80211_TX_INTCFL_NEED_TXPROCESSING; |
---|
1155 | 1167 | ieee80211_set_qos_hdr(sdata, skb); |
---|
1156 | 1168 | skb_queue_tail(&mpath->frame_queue, skb); |
---|
1157 | | - err = -ENOENT; |
---|
1158 | 1169 | if (skb_to_free) |
---|
1159 | 1170 | mesh_path_discard_frame(sdata, skb_to_free); |
---|
1160 | 1171 | |
---|
1161 | | -endlookup: |
---|
| 1172 | + return -ENOENT; |
---|
| 1173 | +} |
---|
| 1174 | + |
---|
| 1175 | +/** |
---|
| 1176 | + * mesh_nexthop_lookup_nolearn - try to set next hop without path discovery |
---|
| 1177 | + * @skb: 802.11 frame to be sent |
---|
| 1178 | + * @sdata: network subif the frame will be sent through |
---|
| 1179 | + * |
---|
| 1180 | + * Check if the meshDA (addr3) of a unicast frame is a direct neighbor. |
---|
| 1181 | + * And if so, set the RA (addr1) to it to transmit to this node directly, |
---|
| 1182 | + * avoiding PREQ/PREP path discovery. |
---|
| 1183 | + * |
---|
| 1184 | + * Returns: 0 if the next hop was found and -ENOENT otherwise. |
---|
| 1185 | + */ |
---|
| 1186 | +static int mesh_nexthop_lookup_nolearn(struct ieee80211_sub_if_data *sdata, |
---|
| 1187 | + struct sk_buff *skb) |
---|
| 1188 | +{ |
---|
| 1189 | + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; |
---|
| 1190 | + struct sta_info *sta; |
---|
| 1191 | + |
---|
| 1192 | + if (is_multicast_ether_addr(hdr->addr1)) |
---|
| 1193 | + return -ENOENT; |
---|
| 1194 | + |
---|
| 1195 | + rcu_read_lock(); |
---|
| 1196 | + sta = sta_info_get(sdata, hdr->addr3); |
---|
| 1197 | + |
---|
| 1198 | + if (!sta || sta->mesh->plink_state != NL80211_PLINK_ESTAB) { |
---|
| 1199 | + rcu_read_unlock(); |
---|
| 1200 | + return -ENOENT; |
---|
| 1201 | + } |
---|
1162 | 1202 | rcu_read_unlock(); |
---|
1163 | | - return err; |
---|
| 1203 | + |
---|
| 1204 | + memcpy(hdr->addr1, hdr->addr3, ETH_ALEN); |
---|
| 1205 | + memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN); |
---|
| 1206 | + return 0; |
---|
1164 | 1207 | } |
---|
1165 | 1208 | |
---|
1166 | 1209 | /** |
---|
.. | .. |
---|
1176 | 1219 | int mesh_nexthop_lookup(struct ieee80211_sub_if_data *sdata, |
---|
1177 | 1220 | struct sk_buff *skb) |
---|
1178 | 1221 | { |
---|
| 1222 | + struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
---|
1179 | 1223 | struct mesh_path *mpath; |
---|
1180 | 1224 | struct sta_info *next_hop; |
---|
1181 | 1225 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
---|
1182 | 1226 | u8 *target_addr = hdr->addr3; |
---|
1183 | | - int err = -ENOENT; |
---|
1184 | 1227 | |
---|
1185 | | - rcu_read_lock(); |
---|
| 1228 | + if (ifmsh->mshcfg.dot11MeshNolearn && |
---|
| 1229 | + !mesh_nexthop_lookup_nolearn(sdata, skb)) |
---|
| 1230 | + return 0; |
---|
| 1231 | + |
---|
1186 | 1232 | mpath = mesh_path_lookup(sdata, target_addr); |
---|
1187 | | - |
---|
1188 | 1233 | if (!mpath || !(mpath->flags & MESH_PATH_ACTIVE)) |
---|
1189 | | - goto endlookup; |
---|
| 1234 | + return -ENOENT; |
---|
1190 | 1235 | |
---|
1191 | 1236 | if (time_after(jiffies, |
---|
1192 | 1237 | mpath->exp_time - |
---|
.. | .. |
---|
1201 | 1246 | memcpy(hdr->addr1, next_hop->sta.addr, ETH_ALEN); |
---|
1202 | 1247 | memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN); |
---|
1203 | 1248 | ieee80211_mps_set_frame_flags(sdata, next_hop, hdr); |
---|
1204 | | - err = 0; |
---|
| 1249 | + return 0; |
---|
1205 | 1250 | } |
---|
1206 | 1251 | |
---|
1207 | | -endlookup: |
---|
1208 | | - rcu_read_unlock(); |
---|
1209 | | - return err; |
---|
| 1252 | + return -ENOENT; |
---|
1210 | 1253 | } |
---|
1211 | 1254 | |
---|
1212 | 1255 | void mesh_path_timer(struct timer_list *t) |
---|
.. | .. |
---|
1262 | 1305 | break; |
---|
1263 | 1306 | case IEEE80211_PROACTIVE_PREQ_WITH_PREP: |
---|
1264 | 1307 | flags |= IEEE80211_PREQ_PROACTIVE_PREP_FLAG; |
---|
1265 | | - /* fall through */ |
---|
| 1308 | + fallthrough; |
---|
1266 | 1309 | case IEEE80211_PROACTIVE_PREQ_NO_PREP: |
---|
1267 | 1310 | interval = ifmsh->mshcfg.dot11MeshHWMPactivePathToRootTimeout; |
---|
1268 | 1311 | target_flags |= IEEE80211_PREQ_TO_FLAG | |
---|