| 1 | // SPDX-License-Identifier: GPL-2.0-only |
| 2 | /* |
| 3 | * KUnit tests for element parsing |
| 4 | * |
| 5 | * Copyright (C) 2023-2025 Intel Corporation |
| 6 | */ |
| 7 | #include <kunit/test.h> |
| 8 | #include "../ieee80211_i.h" |
| 9 | |
| 10 | MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING" ); |
| 11 | |
| 12 | static void mle_defrag(struct kunit *test) |
| 13 | { |
| 14 | struct ieee80211_elems_parse_params parse_params = { |
| 15 | .link_id = 12, |
| 16 | .from_ap = true, |
| 17 | .mode = IEEE80211_CONN_MODE_EHT, |
| 18 | /* type is not really relevant here */ |
| 19 | .type = IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON, |
| 20 | }; |
| 21 | struct ieee802_11_elems *parsed; |
| 22 | struct sk_buff *skb; |
| 23 | u8 *len_mle, *len_prof; |
| 24 | int i; |
| 25 | |
| 26 | skb = alloc_skb(size: 1024, GFP_KERNEL); |
| 27 | KUNIT_ASSERT_NOT_NULL(test, skb); |
| 28 | |
| 29 | if (skb_pad(skb, pad: skb_tailroom(skb))) { |
| 30 | KUNIT_FAIL(test, "failed to pad skb" ); |
| 31 | return; |
| 32 | } |
| 33 | |
| 34 | /* build a multi-link element */ |
| 35 | skb_put_u8(skb, val: WLAN_EID_EXTENSION); |
| 36 | len_mle = skb_put(skb, len: 1); |
| 37 | skb_put_u8(skb, val: WLAN_EID_EXT_EHT_MULTI_LINK); |
| 38 | |
| 39 | put_unaligned_le16(IEEE80211_ML_CONTROL_TYPE_BASIC, |
| 40 | p: skb_put(skb, len: 2)); |
| 41 | /* struct ieee80211_mle_basic_common_info */ |
| 42 | skb_put_u8(skb, val: 7); /* includes len field */ |
| 43 | skb_put_data(skb, data: "\x00\x00\x00\x00\x00\x00" , ETH_ALEN); /* MLD addr */ |
| 44 | |
| 45 | /* with a STA profile inside */ |
| 46 | skb_put_u8(skb, val: IEEE80211_MLE_SUBELEM_PER_STA_PROFILE); |
| 47 | len_prof = skb_put(skb, len: 1); |
| 48 | put_unaligned_le16(IEEE80211_MLE_STA_CONTROL_COMPLETE_PROFILE | |
| 49 | parse_params.link_id, |
| 50 | p: skb_put(skb, len: 2)); |
| 51 | skb_put_u8(skb, val: 1); /* fake sta_info_len - includes itself */ |
| 52 | /* put a bunch of useless elements into it */ |
| 53 | for (i = 0; i < 20; i++) { |
| 54 | skb_put_u8(skb, val: WLAN_EID_SSID); |
| 55 | skb_put_u8(skb, val: 20); |
| 56 | skb_put(skb, len: 20); |
| 57 | } |
| 58 | |
| 59 | /* fragment STA profile */ |
| 60 | ieee80211_fragment_element(skb, len_pos: len_prof, |
| 61 | frag_id: IEEE80211_MLE_SUBELEM_FRAGMENT); |
| 62 | /* fragment MLE */ |
| 63 | ieee80211_fragment_element(skb, len_pos: len_mle, frag_id: WLAN_EID_FRAGMENT); |
| 64 | |
| 65 | parse_params.start = skb->data; |
| 66 | parse_params.len = skb->len; |
| 67 | parsed = ieee802_11_parse_elems_full(params: &parse_params); |
| 68 | /* should return ERR_PTR or valid, not NULL */ |
| 69 | KUNIT_EXPECT_NOT_NULL(test, parsed); |
| 70 | |
| 71 | if (IS_ERR_OR_NULL(ptr: parsed)) |
| 72 | goto free_skb; |
| 73 | |
| 74 | KUNIT_EXPECT_NOT_NULL(test, parsed->ml_basic); |
| 75 | KUNIT_EXPECT_EQ(test, |
| 76 | parsed->ml_basic_len, |
| 77 | 2 /* control */ + |
| 78 | 7 /* common info */ + |
| 79 | 2 /* sta profile element header */ + |
| 80 | 3 /* sta profile header */ + |
| 81 | 20 * 22 /* sta profile data */ + |
| 82 | 2 /* sta profile fragment element */); |
| 83 | KUNIT_EXPECT_NOT_NULL(test, parsed->prof); |
| 84 | KUNIT_EXPECT_EQ(test, |
| 85 | parsed->sta_prof_len, |
| 86 | 3 /* sta profile header */ + |
| 87 | 20 * 22 /* sta profile data */); |
| 88 | |
| 89 | kfree(objp: parsed); |
| 90 | free_skb: |
| 91 | kfree_skb(skb); |
| 92 | } |
| 93 | |
| 94 | static struct kunit_case element_parsing_test_cases[] = { |
| 95 | KUNIT_CASE(mle_defrag), |
| 96 | {} |
| 97 | }; |
| 98 | |
| 99 | static struct kunit_suite element_parsing = { |
| 100 | .name = "mac80211-element-parsing" , |
| 101 | .test_cases = element_parsing_test_cases, |
| 102 | }; |
| 103 | |
| 104 | kunit_test_suite(element_parsing); |
| 105 | |