| 1 | --- a/include/net/mac80211.h |
| 2 | +++ b/include/net/mac80211.h |
| 3 | @@ -816,6 +816,9 @@ enum mac80211_rx_flags { |
| 4 | * @signal: signal strength when receiving this frame, either in dBm, in dB or |
| 5 | * unspecified depending on the hardware capabilities flags |
| 6 | * @IEEE80211_HW_SIGNAL_* |
| 7 | + * @chains: bitmask of receive chains for which separate signal strength |
| 8 | + * values were filled. |
| 9 | + * @chain_signal: per-chain signal strength, same format as @signal |
| 10 | * @antenna: antenna used |
| 11 | * @rate_idx: index of data rate into band's supported rates or MCS index if |
| 12 | * HT or VHT is used (%RX_FLAG_HT/%RX_FLAG_VHT) |
| 13 | @@ -847,6 +850,8 @@ struct ieee80211_rx_status { |
| 14 | u8 band; |
| 15 | u8 antenna; |
| 16 | s8 signal; |
| 17 | + u8 chains; |
| 18 | + s8 chain_signal[4]; |
| 19 | u8 ampdu_delimiter_crc; |
| 20 | u8 vendor_radiotap_align; |
| 21 | u8 vendor_radiotap_oui[3]; |
| 22 | --- a/net/mac80211/sta_info.h |
| 23 | +++ b/net/mac80211/sta_info.h |
| 24 | @@ -329,6 +329,11 @@ struct sta_info { |
| 25 | int last_signal; |
| 26 | struct ewma avg_signal; |
| 27 | int last_ack_signal; |
| 28 | + |
| 29 | + u8 chains; |
| 30 | + s8 chain_signal_last[4]; |
| 31 | + struct ewma chain_signal_avg[4]; |
| 32 | + |
| 33 | /* Plus 1 for non-QoS frames */ |
| 34 | __le16 last_seq_ctrl[IEEE80211_NUM_TIDS + 1]; |
| 35 | |
| 36 | --- a/net/mac80211/rx.c |
| 37 | +++ b/net/mac80211/rx.c |
| 38 | @@ -1375,6 +1375,7 @@ ieee80211_rx_h_sta_process(struct ieee80 |
| 39 | struct sk_buff *skb = rx->skb; |
| 40 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); |
| 41 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; |
| 42 | + int i; |
| 43 | |
| 44 | if (!sta) |
| 45 | return RX_CONTINUE; |
| 46 | @@ -1425,6 +1426,19 @@ ieee80211_rx_h_sta_process(struct ieee80 |
| 47 | ewma_add(&sta->avg_signal, -status->signal); |
| 48 | } |
| 49 | |
| 50 | + if (status->chains) { |
| 51 | + sta->chains = status->chains; |
| 52 | + for (i = 0; i < 4; i++) { |
| 53 | + int signal = status->chain_signal[i]; |
| 54 | + |
| 55 | + if (!(status->chains & BIT(i))) |
| 56 | + continue; |
| 57 | + |
| 58 | + sta->chain_signal_last[i] = signal; |
| 59 | + ewma_add(&sta->chain_signal_avg[i], -signal); |
| 60 | + } |
| 61 | + } |
| 62 | + |
| 63 | /* |
| 64 | * Change STA power saving mode only at the end of a frame |
| 65 | * exchange sequence. |
| 66 | --- a/net/mac80211/sta_info.c |
| 67 | +++ b/net/mac80211/sta_info.c |
| 68 | @@ -324,6 +324,8 @@ struct sta_info *sta_info_alloc(struct i |
| 69 | do_posix_clock_monotonic_gettime(&uptime); |
| 70 | sta->last_connected = uptime.tv_sec; |
| 71 | ewma_init(&sta->avg_signal, 1024, 8); |
| 72 | + for (i = 0; i < ARRAY_SIZE(sta->chain_signal_avg); i++) |
| 73 | + ewma_init(&sta->chain_signal_avg[i], 1024, 8); |
| 74 | |
| 75 | if (sta_prepare_rate_control(local, sta, gfp)) { |
| 76 | kfree(sta); |
| 77 | --- a/include/net/cfg80211.h |
| 78 | +++ b/include/net/cfg80211.h |
| 79 | @@ -653,6 +653,8 @@ struct station_parameters { |
| 80 | * @STATION_INFO_STA_FLAGS: @sta_flags filled |
| 81 | * @STATION_INFO_BEACON_LOSS_COUNT: @beacon_loss_count filled |
| 82 | * @STATION_INFO_T_OFFSET: @t_offset filled |
| 83 | + * @STATION_INFO_CHAIN_SIGNAL: @chain_signal filled |
| 84 | + * @STATION_INFO_CHAIN_SIGNAL_AVG: @chain_signal_avg filled |
| 85 | */ |
| 86 | enum station_info_flags { |
| 87 | STATION_INFO_INACTIVE_TIME = 1<<0, |
| 88 | @@ -676,6 +678,8 @@ enum station_info_flags { |
| 89 | STATION_INFO_STA_FLAGS = 1<<18, |
| 90 | STATION_INFO_BEACON_LOSS_COUNT = 1<<19, |
| 91 | STATION_INFO_T_OFFSET = 1<<20, |
| 92 | + STATION_INFO_CHAIN_SIGNAL = 1<<21, |
| 93 | + STATION_INFO_CHAIN_SIGNAL_AVG = 1<<22, |
| 94 | }; |
| 95 | |
| 96 | /** |
| 97 | @@ -769,6 +773,9 @@ struct sta_bss_parameters { |
| 98 | * For CFG80211_SIGNAL_TYPE_MBM, value is expressed in _dBm_. |
| 99 | * @signal_avg: Average signal strength, type depends on the wiphy's signal_type. |
| 100 | * For CFG80211_SIGNAL_TYPE_MBM, value is expressed in _dBm_. |
| 101 | + * @chains: bitmask for filled values in @chain_signal, @chain_signal_avg |
| 102 | + * @chain_signal: per-chain signal strength of last received packet in dBm |
| 103 | + * @chain_signal_avg: per-chain signal strength average in dBm |
| 104 | * @txrate: current unicast bitrate from this station |
| 105 | * @rxrate: current unicast bitrate to this station |
| 106 | * @rx_packets: packets received from this station |
| 107 | @@ -801,6 +808,11 @@ struct station_info { |
| 108 | u8 plink_state; |
| 109 | s8 signal; |
| 110 | s8 signal_avg; |
| 111 | + |
| 112 | + u8 chains; |
| 113 | + s8 chain_signal[4]; |
| 114 | + s8 chain_signal_avg[4]; |
| 115 | + |
| 116 | struct rate_info txrate; |
| 117 | struct rate_info rxrate; |
| 118 | u32 rx_packets; |
| 119 | --- a/drivers/net/wireless/ath/ath9k/mac.h |
| 120 | +++ b/drivers/net/wireless/ath/ath9k/mac.h |
| 121 | @@ -133,12 +133,8 @@ struct ath_rx_status { |
| 122 | u8 rs_rate; |
| 123 | u8 rs_antenna; |
| 124 | u8 rs_more; |
| 125 | - int8_t rs_rssi_ctl0; |
| 126 | - int8_t rs_rssi_ctl1; |
| 127 | - int8_t rs_rssi_ctl2; |
| 128 | - int8_t rs_rssi_ext0; |
| 129 | - int8_t rs_rssi_ext1; |
| 130 | - int8_t rs_rssi_ext2; |
| 131 | + int8_t rs_rssi_ctl[3]; |
| 132 | + int8_t rs_rssi_ext[3]; |
| 133 | u8 rs_isaggr; |
| 134 | u8 rs_moreaggr; |
| 135 | u8 rs_num_delims; |
| 136 | --- a/drivers/net/wireless/ath/ath9k/recv.c |
| 137 | +++ b/drivers/net/wireless/ath/ath9k/recv.c |
| 138 | @@ -955,6 +955,7 @@ static int ath9k_rx_skb_preprocess(struc |
| 139 | bool *decrypt_error) |
| 140 | { |
| 141 | struct ath_hw *ah = common->ah; |
| 142 | + int i, j; |
| 143 | |
| 144 | /* |
| 145 | * everything but the rate is checked here, the rate check is done |
| 146 | @@ -980,6 +981,20 @@ static int ath9k_rx_skb_preprocess(struc |
| 147 | if (rx_stats->rs_moreaggr) |
| 148 | rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL; |
| 149 | |
| 150 | + for (i = 0, j = 0; i < ARRAY_SIZE(rx_stats->rs_rssi_ctl); i++) { |
| 151 | + s8 rssi; |
| 152 | + |
| 153 | + if (!(ah->rxchainmask & BIT(i))) |
| 154 | + continue; |
| 155 | + |
| 156 | + rssi = rx_stats->rs_rssi_ctl[i]; |
| 157 | + if (rssi != ATH9K_RSSI_BAD) { |
| 158 | + rx_status->chains |= BIT(j); |
| 159 | + rx_status->chain_signal[j] = ah->noise + rssi; |
| 160 | + } |
| 161 | + j++; |
| 162 | + } |
| 163 | + |
| 164 | return 0; |
| 165 | } |
| 166 | |
| 167 | --- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c |
| 168 | +++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c |
| 169 | @@ -475,12 +475,12 @@ int ath9k_hw_process_rxdesc_edma(struct |
| 170 | |
| 171 | /* XXX: Keycache */ |
| 172 | rxs->rs_rssi = MS(rxsp->status5, AR_RxRSSICombined); |
| 173 | - rxs->rs_rssi_ctl0 = MS(rxsp->status1, AR_RxRSSIAnt00); |
| 174 | - rxs->rs_rssi_ctl1 = MS(rxsp->status1, AR_RxRSSIAnt01); |
| 175 | - rxs->rs_rssi_ctl2 = MS(rxsp->status1, AR_RxRSSIAnt02); |
| 176 | - rxs->rs_rssi_ext0 = MS(rxsp->status5, AR_RxRSSIAnt10); |
| 177 | - rxs->rs_rssi_ext1 = MS(rxsp->status5, AR_RxRSSIAnt11); |
| 178 | - rxs->rs_rssi_ext2 = MS(rxsp->status5, AR_RxRSSIAnt12); |
| 179 | + rxs->rs_rssi_ctl[0] = MS(rxsp->status1, AR_RxRSSIAnt00); |
| 180 | + rxs->rs_rssi_ctl[1] = MS(rxsp->status1, AR_RxRSSIAnt01); |
| 181 | + rxs->rs_rssi_ctl[2] = MS(rxsp->status1, AR_RxRSSIAnt02); |
| 182 | + rxs->rs_rssi_ext[0] = MS(rxsp->status5, AR_RxRSSIAnt10); |
| 183 | + rxs->rs_rssi_ext[1] = MS(rxsp->status5, AR_RxRSSIAnt11); |
| 184 | + rxs->rs_rssi_ext[2] = MS(rxsp->status5, AR_RxRSSIAnt12); |
| 185 | |
| 186 | if (rxsp->status11 & AR_RxKeyIdxValid) |
| 187 | rxs->rs_keyix = MS(rxsp->status11, AR_KeyIdx); |
| 188 | --- a/drivers/net/wireless/ath/ath9k/mac.c |
| 189 | +++ b/drivers/net/wireless/ath/ath9k/mac.c |
| 190 | @@ -553,25 +553,25 @@ int ath9k_hw_rxprocdesc(struct ath_hw *a |
| 191 | |
| 192 | if (ads.ds_rxstatus8 & AR_PostDelimCRCErr) { |
| 193 | rs->rs_rssi = ATH9K_RSSI_BAD; |
| 194 | - rs->rs_rssi_ctl0 = ATH9K_RSSI_BAD; |
| 195 | - rs->rs_rssi_ctl1 = ATH9K_RSSI_BAD; |
| 196 | - rs->rs_rssi_ctl2 = ATH9K_RSSI_BAD; |
| 197 | - rs->rs_rssi_ext0 = ATH9K_RSSI_BAD; |
| 198 | - rs->rs_rssi_ext1 = ATH9K_RSSI_BAD; |
| 199 | - rs->rs_rssi_ext2 = ATH9K_RSSI_BAD; |
| 200 | + rs->rs_rssi_ctl[0] = ATH9K_RSSI_BAD; |
| 201 | + rs->rs_rssi_ctl[1] = ATH9K_RSSI_BAD; |
| 202 | + rs->rs_rssi_ctl[2] = ATH9K_RSSI_BAD; |
| 203 | + rs->rs_rssi_ext[0] = ATH9K_RSSI_BAD; |
| 204 | + rs->rs_rssi_ext[1] = ATH9K_RSSI_BAD; |
| 205 | + rs->rs_rssi_ext[2] = ATH9K_RSSI_BAD; |
| 206 | } else { |
| 207 | rs->rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined); |
| 208 | - rs->rs_rssi_ctl0 = MS(ads.ds_rxstatus0, |
| 209 | + rs->rs_rssi_ctl[0] = MS(ads.ds_rxstatus0, |
| 210 | AR_RxRSSIAnt00); |
| 211 | - rs->rs_rssi_ctl1 = MS(ads.ds_rxstatus0, |
| 212 | + rs->rs_rssi_ctl[1] = MS(ads.ds_rxstatus0, |
| 213 | AR_RxRSSIAnt01); |
| 214 | - rs->rs_rssi_ctl2 = MS(ads.ds_rxstatus0, |
| 215 | + rs->rs_rssi_ctl[2] = MS(ads.ds_rxstatus0, |
| 216 | AR_RxRSSIAnt02); |
| 217 | - rs->rs_rssi_ext0 = MS(ads.ds_rxstatus4, |
| 218 | + rs->rs_rssi_ext[0] = MS(ads.ds_rxstatus4, |
| 219 | AR_RxRSSIAnt10); |
| 220 | - rs->rs_rssi_ext1 = MS(ads.ds_rxstatus4, |
| 221 | + rs->rs_rssi_ext[1] = MS(ads.ds_rxstatus4, |
| 222 | AR_RxRSSIAnt11); |
| 223 | - rs->rs_rssi_ext2 = MS(ads.ds_rxstatus4, |
| 224 | + rs->rs_rssi_ext[2] = MS(ads.ds_rxstatus4, |
| 225 | AR_RxRSSIAnt12); |
| 226 | } |
| 227 | if (ads.ds_rxstatus8 & AR_RxKeyIdxValid) |
| 228 | --- a/drivers/net/wireless/ath/ath9k/debug.c |
| 229 | +++ b/drivers/net/wireless/ath/ath9k/debug.c |
| 230 | @@ -939,12 +939,12 @@ void ath_debug_stat_rx(struct ath_softc |
| 231 | #ifdef CONFIG_ATH9K_MAC_DEBUG |
| 232 | spin_lock(&sc->debug.samp_lock); |
| 233 | RX_SAMP_DBG(jiffies) = jiffies; |
| 234 | - RX_SAMP_DBG(rssi_ctl0) = rs->rs_rssi_ctl0; |
| 235 | - RX_SAMP_DBG(rssi_ctl1) = rs->rs_rssi_ctl1; |
| 236 | - RX_SAMP_DBG(rssi_ctl2) = rs->rs_rssi_ctl2; |
| 237 | - RX_SAMP_DBG(rssi_ext0) = rs->rs_rssi_ext0; |
| 238 | - RX_SAMP_DBG(rssi_ext1) = rs->rs_rssi_ext1; |
| 239 | - RX_SAMP_DBG(rssi_ext2) = rs->rs_rssi_ext2; |
| 240 | + RX_SAMP_DBG(rssi_ctl0) = rs->rs_rssi_ctl[0]; |
| 241 | + RX_SAMP_DBG(rssi_ctl1) = rs->rs_rssi_ctl[1]; |
| 242 | + RX_SAMP_DBG(rssi_ctl2) = rs->rs_rssi_ctl[2]; |
| 243 | + RX_SAMP_DBG(rssi_ext0) = rs->rs_rssi_ext[0]; |
| 244 | + RX_SAMP_DBG(rssi_ext1) = rs->rs_rssi_ext[1]; |
| 245 | + RX_SAMP_DBG(rssi_ext2) = rs->rs_rssi_ext[2]; |
| 246 | RX_SAMP_DBG(antenna) = rs->rs_antenna; |
| 247 | RX_SAMP_DBG(rssi) = rs->rs_rssi; |
| 248 | RX_SAMP_DBG(rate) = rs->rs_rate; |
| 249 | --- a/include/uapi/linux/nl80211.h |
| 250 | +++ b/include/uapi/linux/nl80211.h |
| 251 | @@ -1834,6 +1834,8 @@ enum nl80211_sta_bss_param { |
| 252 | * @NL80211_STA_INFO_STA_FLAGS: Contains a struct nl80211_sta_flag_update. |
| 253 | * @NL80211_STA_INFO_BEACON_LOSS: count of times beacon loss was detected (u32) |
| 254 | * @NL80211_STA_INFO_T_OFFSET: timing offset with respect to this STA (s64) |
| 255 | + * @NL80211_STA_INFO_CHAIN_SIGNAL: per-chain signal strength of last PPDU |
| 256 | + * @NL80211_STA_INFO_CHAIN_SIGNAL_AVG: per-chain signal strength average |
| 257 | * @__NL80211_STA_INFO_AFTER_LAST: internal |
| 258 | * @NL80211_STA_INFO_MAX: highest possible station info attribute |
| 259 | */ |
| 260 | @@ -1858,6 +1860,8 @@ enum nl80211_sta_info { |
| 261 | NL80211_STA_INFO_STA_FLAGS, |
| 262 | NL80211_STA_INFO_BEACON_LOSS, |
| 263 | NL80211_STA_INFO_T_OFFSET, |
| 264 | + NL80211_STA_INFO_CHAIN_SIGNAL, |
| 265 | + NL80211_STA_INFO_CHAIN_SIGNAL_AVG, |
| 266 | |
| 267 | /* keep last */ |
| 268 | __NL80211_STA_INFO_AFTER_LAST, |
| 269 | --- a/net/wireless/nl80211.c |
| 270 | +++ b/net/wireless/nl80211.c |
| 271 | @@ -2910,6 +2910,32 @@ static bool nl80211_put_sta_rate(struct |
| 272 | return true; |
| 273 | } |
| 274 | |
| 275 | +static bool nl80211_put_signal(struct sk_buff *msg, u8 mask, s8 *signal, |
| 276 | + int id) |
| 277 | +{ |
| 278 | + void *attr; |
| 279 | + int i = 0; |
| 280 | + |
| 281 | + if (!mask) |
| 282 | + return true; |
| 283 | + |
| 284 | + attr = nla_nest_start(msg, id); |
| 285 | + if (!attr) |
| 286 | + return false; |
| 287 | + |
| 288 | + for (i = 0; i < 4; i++) { |
| 289 | + if (!(mask & BIT(i))) |
| 290 | + continue; |
| 291 | + |
| 292 | + if (nla_put_u8(msg, i, signal[i])) |
| 293 | + return false; |
| 294 | + } |
| 295 | + |
| 296 | + nla_nest_end(msg, attr); |
| 297 | + |
| 298 | + return true; |
| 299 | +} |
| 300 | + |
| 301 | static int nl80211_send_station(struct sk_buff *msg, u32 portid, u32 seq, |
| 302 | int flags, |
| 303 | struct cfg80211_registered_device *rdev, |
| 304 | @@ -2971,6 +2997,18 @@ static int nl80211_send_station(struct s |
| 305 | default: |
| 306 | break; |
| 307 | } |
| 308 | + if (sinfo->filled & STATION_INFO_CHAIN_SIGNAL) { |
| 309 | + if (!nl80211_put_signal(msg, sinfo->chains, |
| 310 | + sinfo->chain_signal, |
| 311 | + NL80211_STA_INFO_CHAIN_SIGNAL)) |
| 312 | + goto nla_put_failure; |
| 313 | + } |
| 314 | + if (sinfo->filled & STATION_INFO_CHAIN_SIGNAL_AVG) { |
| 315 | + if (!nl80211_put_signal(msg, sinfo->chains, |
| 316 | + sinfo->chain_signal_avg, |
| 317 | + NL80211_STA_INFO_CHAIN_SIGNAL_AVG)) |
| 318 | + goto nla_put_failure; |
| 319 | + } |
| 320 | if (sinfo->filled & STATION_INFO_TX_BITRATE) { |
| 321 | if (!nl80211_put_sta_rate(msg, &sinfo->txrate, |
| 322 | NL80211_STA_INFO_TX_BITRATE)) |
| 323 | --- a/net/mac80211/cfg.c |
| 324 | +++ b/net/mac80211/cfg.c |
| 325 | @@ -435,6 +435,7 @@ static void sta_set_sinfo(struct sta_inf |
| 326 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
| 327 | struct ieee80211_local *local = sdata->local; |
| 328 | struct timespec uptime; |
| 329 | + int i; |
| 330 | |
| 331 | sinfo->generation = sdata->local->sta_generation; |
| 332 | |
| 333 | @@ -474,6 +475,17 @@ static void sta_set_sinfo(struct sta_inf |
| 334 | sinfo->signal = (s8)sta->last_signal; |
| 335 | sinfo->signal_avg = (s8) -ewma_read(&sta->avg_signal); |
| 336 | } |
| 337 | + if (sta->chains) { |
| 338 | + sinfo->filled |= STATION_INFO_CHAIN_SIGNAL | |
| 339 | + STATION_INFO_CHAIN_SIGNAL_AVG; |
| 340 | + |
| 341 | + sinfo->chains = sta->chains; |
| 342 | + for (i = 0; i < ARRAY_SIZE(sinfo->chain_signal); i++) { |
| 343 | + sinfo->chain_signal[i] = sta->chain_signal_last[i]; |
| 344 | + sinfo->chain_signal_avg[i] = |
| 345 | + (s8) -ewma_read(&sta->chain_signal_avg[i]); |
| 346 | + } |
| 347 | + } |
| 348 | |
| 349 | sta_set_rate_info_tx(sta, &sta->last_tx_rate, &sinfo->txrate); |
| 350 | sta_set_rate_info_rx(sta, &sinfo->rxrate); |
| 351 | --- a/drivers/net/wireless/ath/ath9k/dfs.c |
| 352 | +++ b/drivers/net/wireless/ath/ath9k/dfs.c |
| 353 | @@ -164,8 +164,8 @@ void ath9k_dfs_process_phyerr(struct ath |
| 354 | return; |
| 355 | } |
| 356 | |
| 357 | - ard.rssi = rs->rs_rssi_ctl0; |
| 358 | - ard.ext_rssi = rs->rs_rssi_ext0; |
| 359 | + ard.rssi = rs->rs_rssi_ctl[0]; |
| 360 | + ard.ext_rssi = rs->rs_rssi_ext[0]; |
| 361 | |
| 362 | /* |
| 363 | * hardware stores this as 8 bit signed value. |
| 364 | --- a/drivers/net/wireless/ath/ath9k/antenna.c |
| 365 | +++ b/drivers/net/wireless/ath/ath9k/antenna.c |
| 366 | @@ -546,14 +546,14 @@ void ath_ant_comb_scan(struct ath_softc |
| 367 | struct ath_ant_comb *antcomb = &sc->ant_comb; |
| 368 | int alt_ratio = 0, alt_rssi_avg = 0, main_rssi_avg = 0, curr_alt_set; |
| 369 | int curr_main_set; |
| 370 | - int main_rssi = rs->rs_rssi_ctl0; |
| 371 | - int alt_rssi = rs->rs_rssi_ctl1; |
| 372 | + int main_rssi = rs->rs_rssi_ctl[0]; |
| 373 | + int alt_rssi = rs->rs_rssi_ctl[1]; |
| 374 | int rx_ant_conf, main_ant_conf; |
| 375 | bool short_scan = false; |
| 376 | |
| 377 | - rx_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_CURRENT_SHIFT) & |
| 378 | + rx_ant_conf = (rs->rs_rssi_ctl[2] >> ATH_ANT_RX_CURRENT_SHIFT) & |
| 379 | ATH_ANT_RX_MASK; |
| 380 | - main_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_MAIN_SHIFT) & |
| 381 | + main_ant_conf = (rs->rs_rssi_ctl[2] >> ATH_ANT_RX_MAIN_SHIFT) & |
| 382 | ATH_ANT_RX_MASK; |
| 383 | |
| 384 | /* Record packet only when both main_rssi and alt_rssi is positive */ |
| 385 | |