1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 2 /* 3 * KUnit tests for channel helper functions 4 * 5 * Copyright (C) 2024 Intel Corporation 6 */ 7 #include <kunit/test.h> 8 #include "utils.h" 9 #include "iwl-trans.h" 10 #include "mld.h" 11 #include "sta.h" 12 13 static const struct is_dup_case { 14 const char *desc; 15 struct { 16 /* ieee80211_hdr fields */ 17 __le16 fc; 18 __le16 seq; 19 u8 tid; 20 bool multicast; 21 /* iwl_rx_mpdu_desc fields */ 22 bool is_amsdu; 23 u8 sub_frame_idx; 24 } rx_pkt; 25 struct { 26 __le16 last_seq; 27 u8 last_sub_frame_idx; 28 u8 tid; 29 } dup_data_state; 30 struct { 31 bool is_dup; 32 u32 rx_status_flag; 33 } result; 34 } is_dup_cases[] = { 35 { 36 .desc = "Control frame", 37 .rx_pkt = { 38 .fc = __cpu_to_le16(IEEE80211_FTYPE_CTL), 39 }, 40 .result = { 41 .is_dup = false, 42 .rx_status_flag = 0, 43 } 44 }, 45 { 46 .desc = "Null func frame", 47 .rx_pkt = { 48 .fc = __cpu_to_le16(IEEE80211_FTYPE_DATA | 49 IEEE80211_STYPE_NULLFUNC), 50 }, 51 .result = { 52 .is_dup = false, 53 .rx_status_flag = 0, 54 } 55 }, 56 { 57 .desc = "Multicast data", 58 .rx_pkt = { 59 .fc = __cpu_to_le16(IEEE80211_FTYPE_DATA), 60 .multicast = true, 61 }, 62 .result = { 63 .is_dup = false, 64 .rx_status_flag = 0, 65 } 66 }, 67 { 68 .desc = "QoS null func frame", 69 .rx_pkt = { 70 .fc = __cpu_to_le16(IEEE80211_FTYPE_DATA | 71 IEEE80211_STYPE_QOS_NULLFUNC), 72 }, 73 .result = { 74 .is_dup = false, 75 .rx_status_flag = 0, 76 } 77 }, 78 { 79 .desc = "QoS data new sequence", 80 .rx_pkt = { 81 .fc = __cpu_to_le16(IEEE80211_FTYPE_DATA | 82 IEEE80211_STYPE_QOS_DATA), 83 .seq = __cpu_to_le16(0x101), 84 }, 85 .dup_data_state = { 86 .last_seq = __cpu_to_le16(0x100), 87 .last_sub_frame_idx = 0, 88 }, 89 .result = { 90 .is_dup = false, 91 .rx_status_flag = RX_FLAG_DUP_VALIDATED, 92 }, 93 }, 94 { 95 .desc = "QoS data same sequence, no retry", 96 .rx_pkt = { 97 .fc = __cpu_to_le16(IEEE80211_FTYPE_DATA | 98 IEEE80211_STYPE_QOS_DATA), 99 .seq = __cpu_to_le16(0x100), 100 }, 101 .dup_data_state = { 102 .last_seq = __cpu_to_le16(0x100), 103 .last_sub_frame_idx = 0, 104 }, 105 .result = { 106 .is_dup = false, 107 .rx_status_flag = RX_FLAG_DUP_VALIDATED, 108 }, 109 }, 110 { 111 .desc = "QoS data same sequence, has retry", 112 .rx_pkt = { 113 .fc = __cpu_to_le16(IEEE80211_FTYPE_DATA | 114 IEEE80211_STYPE_QOS_DATA | 115 IEEE80211_FCTL_RETRY), 116 .seq = __cpu_to_le16(0x100), 117 }, 118 .dup_data_state = { 119 .last_seq = __cpu_to_le16(0x100), 120 .last_sub_frame_idx = 0, 121 }, 122 .result = { 123 .is_dup = true, 124 .rx_status_flag = 0, 125 }, 126 }, 127 { 128 .desc = "QoS data invalid tid", 129 .rx_pkt = { 130 .fc = __cpu_to_le16(IEEE80211_FTYPE_DATA | 131 IEEE80211_STYPE_QOS_DATA), 132 .seq = __cpu_to_le16(0x100), 133 .tid = IWL_MAX_TID_COUNT + 1, 134 }, 135 .result = { 136 .is_dup = true, 137 .rx_status_flag = 0, 138 }, 139 }, 140 { 141 .desc = "non-QoS data, same sequence, same tid, no retry", 142 .rx_pkt = { 143 /* Driver will use tid = IWL_MAX_TID_COUNT */ 144 .fc = __cpu_to_le16(IEEE80211_FTYPE_DATA), 145 .seq = __cpu_to_le16(0x100), 146 }, 147 .dup_data_state = { 148 .tid = IWL_MAX_TID_COUNT, 149 .last_seq = __cpu_to_le16(0x100), 150 .last_sub_frame_idx = 0, 151 }, 152 .result = { 153 .is_dup = false, 154 .rx_status_flag = RX_FLAG_DUP_VALIDATED, 155 }, 156 }, 157 { 158 .desc = "non-QoS data, same sequence, same tid, has retry", 159 .rx_pkt = { 160 /* Driver will use tid = IWL_MAX_TID_COUNT */ 161 .fc = __cpu_to_le16(IEEE80211_FTYPE_DATA | 162 IEEE80211_FCTL_RETRY), 163 .seq = __cpu_to_le16(0x100), 164 }, 165 .dup_data_state = { 166 .tid = IWL_MAX_TID_COUNT, 167 .last_seq = __cpu_to_le16(0x100), 168 .last_sub_frame_idx = 0, 169 }, 170 .result = { 171 .is_dup = true, 172 .rx_status_flag = 0, 173 }, 174 }, 175 { 176 .desc = "non-QoS data, same sequence on different tid's", 177 .rx_pkt = { 178 /* Driver will use tid = IWL_MAX_TID_COUNT */ 179 .fc = __cpu_to_le16(IEEE80211_FTYPE_DATA), 180 .seq = __cpu_to_le16(0x100), 181 }, 182 .dup_data_state = { 183 .tid = 7, 184 .last_seq = __cpu_to_le16(0x100), 185 .last_sub_frame_idx = 0, 186 }, 187 .result = { 188 .is_dup = false, 189 .rx_status_flag = RX_FLAG_DUP_VALIDATED, 190 }, 191 }, 192 { 193 .desc = "A-MSDU new subframe, allow same PN", 194 .rx_pkt = { 195 .fc = __cpu_to_le16(IEEE80211_FTYPE_DATA | 196 IEEE80211_STYPE_QOS_DATA), 197 .seq = __cpu_to_le16(0x100), 198 .is_amsdu = true, 199 .sub_frame_idx = 1, 200 }, 201 .dup_data_state = { 202 .last_seq = __cpu_to_le16(0x100), 203 .last_sub_frame_idx = 0, 204 }, 205 .result = { 206 .is_dup = false, 207 .rx_status_flag = RX_FLAG_ALLOW_SAME_PN | 208 RX_FLAG_DUP_VALIDATED, 209 }, 210 }, 211 { 212 .desc = "A-MSDU subframe with smaller idx, disallow same PN", 213 .rx_pkt = { 214 .fc = __cpu_to_le16(IEEE80211_FTYPE_DATA | 215 IEEE80211_STYPE_QOS_DATA), 216 .seq = __cpu_to_le16(0x100), 217 .is_amsdu = true, 218 .sub_frame_idx = 1, 219 }, 220 .dup_data_state = { 221 .last_seq = __cpu_to_le16(0x100), 222 .last_sub_frame_idx = 2, 223 }, 224 .result = { 225 .is_dup = false, 226 .rx_status_flag = RX_FLAG_DUP_VALIDATED, 227 }, 228 }, 229 { 230 .desc = "A-MSDU same subframe, no retry, disallow same PN", 231 .rx_pkt = { 232 .fc = __cpu_to_le16(IEEE80211_FTYPE_DATA | 233 IEEE80211_STYPE_QOS_DATA), 234 .seq = __cpu_to_le16(0x100), 235 .is_amsdu = true, 236 .sub_frame_idx = 0, 237 }, 238 .dup_data_state = { 239 .last_seq = __cpu_to_le16(0x100), 240 .last_sub_frame_idx = 0, 241 }, 242 .result = { 243 .is_dup = false, 244 .rx_status_flag = RX_FLAG_DUP_VALIDATED, 245 }, 246 }, 247 { 248 .desc = "A-MSDU same subframe, has retry", 249 .rx_pkt = { 250 .fc = __cpu_to_le16(IEEE80211_FTYPE_DATA | 251 IEEE80211_STYPE_QOS_DATA | 252 IEEE80211_FCTL_RETRY), 253 .seq = __cpu_to_le16(0x100), 254 .is_amsdu = true, 255 .sub_frame_idx = 0, 256 }, 257 .dup_data_state = { 258 .last_seq = __cpu_to_le16(0x100), 259 .last_sub_frame_idx = 0, 260 }, 261 .result = { 262 .is_dup = true, 263 .rx_status_flag = 0, 264 }, 265 }, 266 }; 267 268 KUNIT_ARRAY_PARAM_DESC(test_is_dup, is_dup_cases, desc); 269 270 static void 271 setup_dup_data_state(struct ieee80211_sta *sta) 272 { 273 struct kunit *test = kunit_get_current_test(); 274 const struct is_dup_case *param = (const void *)(test->param_value); 275 struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(sta); 276 u8 tid = param->dup_data_state.tid; 277 struct iwl_mld_rxq_dup_data *dup_data; 278 279 /* Allocate dup_data only for 1 queue */ 280 KUNIT_ALLOC_AND_ASSERT(test, dup_data); 281 282 /* Initialize dup data, see iwl_mld_alloc_dup_data */ 283 memset(dup_data->last_seq, 0xff, sizeof(dup_data->last_seq)); 284 285 dup_data->last_seq[tid] = param->dup_data_state.last_seq; 286 dup_data->last_sub_frame_idx[tid] = 287 param->dup_data_state.last_sub_frame_idx; 288 289 mld_sta->dup_data = dup_data; 290 } 291 292 static void setup_rx_pkt(const struct is_dup_case *param, 293 struct ieee80211_hdr *hdr, 294 struct iwl_rx_mpdu_desc *mpdu_desc) 295 { 296 u8 tid = param->rx_pkt.tid; 297 298 /* Set "new rx packet" header */ 299 hdr->frame_control = param->rx_pkt.fc; 300 hdr->seq_ctrl = param->rx_pkt.seq; 301 302 if (ieee80211_is_data_qos(hdr->frame_control)) { 303 u8 *qc = ieee80211_get_qos_ctl(hdr); 304 305 qc[0] = tid & IEEE80211_QOS_CTL_TID_MASK; 306 } 307 308 if (param->rx_pkt.multicast) 309 hdr->addr1[0] = 0x1; 310 311 /* Set mpdu_desc */ 312 mpdu_desc->amsdu_info = param->rx_pkt.sub_frame_idx & 313 IWL_RX_MPDU_AMSDU_SUBFRAME_IDX_MASK; 314 if (param->rx_pkt.is_amsdu) 315 mpdu_desc->mac_flags2 |= IWL_RX_MPDU_MFLG2_AMSDU; 316 } 317 318 static void test_is_dup(struct kunit *test) 319 { 320 const struct is_dup_case *param = (const void *)(test->param_value); 321 struct iwl_mld *mld = test->priv; 322 struct iwl_rx_mpdu_desc mpdu_desc = { }; 323 struct ieee80211_rx_status rx_status = { }; 324 struct ieee80211_vif *vif; 325 struct ieee80211_sta *sta; 326 struct ieee80211_hdr hdr; 327 328 vif = iwlmld_kunit_add_vif(false, NL80211_IFTYPE_STATION); 329 sta = iwlmld_kunit_setup_sta(vif, IEEE80211_STA_AUTHORIZED, -1); 330 331 /* Prepare test case state */ 332 setup_dup_data_state(sta); 333 setup_rx_pkt(param, &hdr, &mpdu_desc); 334 335 KUNIT_EXPECT_EQ(test, 336 iwl_mld_is_dup(mld, sta, &hdr, &mpdu_desc, &rx_status, 337 0), /* assuming only 1 queue */ 338 param->result.is_dup); 339 KUNIT_EXPECT_EQ(test, rx_status.flag, param->result.rx_status_flag); 340 } 341 342 static struct kunit_case is_dup_test_cases[] = { 343 KUNIT_CASE_PARAM(test_is_dup, test_is_dup_gen_params), 344 {}, 345 }; 346 347 static struct kunit_suite is_dup = { 348 .name = "iwlmld-rx-is-dup", 349 .test_cases = is_dup_test_cases, 350 .init = iwlmld_kunit_test_init, 351 }; 352 353 kunit_test_suite(is_dup); 354