0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017 #include <linux/kernel.h>
0018 #include <linux/export.h>
0019 #include <net/cfg80211.h>
0020 #include <net/ieee80211_radiotap.h>
0021 #include <asm/unaligned.h>
0022
0023
0024
0025 static const struct radiotap_align_size rtap_namespace_sizes[] = {
0026 [IEEE80211_RADIOTAP_TSFT] = { .align = 8, .size = 8, },
0027 [IEEE80211_RADIOTAP_FLAGS] = { .align = 1, .size = 1, },
0028 [IEEE80211_RADIOTAP_RATE] = { .align = 1, .size = 1, },
0029 [IEEE80211_RADIOTAP_CHANNEL] = { .align = 2, .size = 4, },
0030 [IEEE80211_RADIOTAP_FHSS] = { .align = 2, .size = 2, },
0031 [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = { .align = 1, .size = 1, },
0032 [IEEE80211_RADIOTAP_DBM_ANTNOISE] = { .align = 1, .size = 1, },
0033 [IEEE80211_RADIOTAP_LOCK_QUALITY] = { .align = 2, .size = 2, },
0034 [IEEE80211_RADIOTAP_TX_ATTENUATION] = { .align = 2, .size = 2, },
0035 [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = { .align = 2, .size = 2, },
0036 [IEEE80211_RADIOTAP_DBM_TX_POWER] = { .align = 1, .size = 1, },
0037 [IEEE80211_RADIOTAP_ANTENNA] = { .align = 1, .size = 1, },
0038 [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = { .align = 1, .size = 1, },
0039 [IEEE80211_RADIOTAP_DB_ANTNOISE] = { .align = 1, .size = 1, },
0040 [IEEE80211_RADIOTAP_RX_FLAGS] = { .align = 2, .size = 2, },
0041 [IEEE80211_RADIOTAP_TX_FLAGS] = { .align = 2, .size = 2, },
0042 [IEEE80211_RADIOTAP_RTS_RETRIES] = { .align = 1, .size = 1, },
0043 [IEEE80211_RADIOTAP_DATA_RETRIES] = { .align = 1, .size = 1, },
0044 [IEEE80211_RADIOTAP_MCS] = { .align = 1, .size = 3, },
0045 [IEEE80211_RADIOTAP_AMPDU_STATUS] = { .align = 4, .size = 8, },
0046 [IEEE80211_RADIOTAP_VHT] = { .align = 2, .size = 12, },
0047
0048
0049
0050 };
0051
0052 static const struct ieee80211_radiotap_namespace radiotap_ns = {
0053 .n_bits = ARRAY_SIZE(rtap_namespace_sizes),
0054 .align_size = rtap_namespace_sizes,
0055 };
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097 int ieee80211_radiotap_iterator_init(
0098 struct ieee80211_radiotap_iterator *iterator,
0099 struct ieee80211_radiotap_header *radiotap_header,
0100 int max_length, const struct ieee80211_radiotap_vendor_namespaces *vns)
0101 {
0102
0103 if (max_length < sizeof(struct ieee80211_radiotap_header))
0104 return -EINVAL;
0105
0106
0107 if (radiotap_header->it_version)
0108 return -EINVAL;
0109
0110
0111 if (max_length < get_unaligned_le16(&radiotap_header->it_len))
0112 return -EINVAL;
0113
0114 iterator->_rtheader = radiotap_header;
0115 iterator->_max_length = get_unaligned_le16(&radiotap_header->it_len);
0116 iterator->_arg_index = 0;
0117 iterator->_bitmap_shifter = get_unaligned_le32(&radiotap_header->it_present);
0118 iterator->_arg = (uint8_t *)radiotap_header->it_optional;
0119 iterator->_reset_on_ext = 0;
0120 iterator->_next_bitmap = radiotap_header->it_optional;
0121 iterator->_vns = vns;
0122 iterator->current_namespace = &radiotap_ns;
0123 iterator->is_radiotap_ns = 1;
0124
0125
0126
0127 if (iterator->_bitmap_shifter & (BIT(IEEE80211_RADIOTAP_EXT))) {
0128 if ((unsigned long)iterator->_arg -
0129 (unsigned long)iterator->_rtheader + sizeof(uint32_t) >
0130 (unsigned long)iterator->_max_length)
0131 return -EINVAL;
0132 while (get_unaligned_le32(iterator->_arg) &
0133 (BIT(IEEE80211_RADIOTAP_EXT))) {
0134 iterator->_arg += sizeof(uint32_t);
0135
0136
0137
0138
0139
0140
0141
0142 if ((unsigned long)iterator->_arg -
0143 (unsigned long)iterator->_rtheader +
0144 sizeof(uint32_t) >
0145 (unsigned long)iterator->_max_length)
0146 return -EINVAL;
0147 }
0148
0149 iterator->_arg += sizeof(uint32_t);
0150
0151
0152
0153
0154
0155
0156 }
0157
0158 iterator->this_arg = iterator->_arg;
0159
0160
0161
0162 return 0;
0163 }
0164 EXPORT_SYMBOL(ieee80211_radiotap_iterator_init);
0165
0166 static void find_ns(struct ieee80211_radiotap_iterator *iterator,
0167 uint32_t oui, uint8_t subns)
0168 {
0169 int i;
0170
0171 iterator->current_namespace = NULL;
0172
0173 if (!iterator->_vns)
0174 return;
0175
0176 for (i = 0; i < iterator->_vns->n_ns; i++) {
0177 if (iterator->_vns->ns[i].oui != oui)
0178 continue;
0179 if (iterator->_vns->ns[i].subns != subns)
0180 continue;
0181
0182 iterator->current_namespace = &iterator->_vns->ns[i];
0183 break;
0184 }
0185 }
0186
0187
0188
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206
0207
0208
0209
0210
0211
0212 int ieee80211_radiotap_iterator_next(
0213 struct ieee80211_radiotap_iterator *iterator)
0214 {
0215 while (1) {
0216 int hit = 0;
0217 int pad, align, size, subns;
0218 uint32_t oui;
0219
0220
0221 if ((iterator->_arg_index % 32) == IEEE80211_RADIOTAP_EXT &&
0222 !(iterator->_bitmap_shifter & 1))
0223 return -ENOENT;
0224
0225 if (!(iterator->_bitmap_shifter & 1))
0226 goto next_entry;
0227
0228
0229 switch (iterator->_arg_index % 32) {
0230 case IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE:
0231 case IEEE80211_RADIOTAP_EXT:
0232 align = 1;
0233 size = 0;
0234 break;
0235 case IEEE80211_RADIOTAP_VENDOR_NAMESPACE:
0236 align = 2;
0237 size = 6;
0238 break;
0239 default:
0240 if (!iterator->current_namespace ||
0241 iterator->_arg_index >= iterator->current_namespace->n_bits) {
0242 if (iterator->current_namespace == &radiotap_ns)
0243 return -ENOENT;
0244 align = 0;
0245 } else {
0246 align = iterator->current_namespace->align_size[iterator->_arg_index].align;
0247 size = iterator->current_namespace->align_size[iterator->_arg_index].size;
0248 }
0249 if (!align) {
0250
0251 iterator->_arg = iterator->_next_ns_data;
0252
0253 iterator->current_namespace = NULL;
0254 goto next_entry;
0255 }
0256 break;
0257 }
0258
0259
0260
0261
0262
0263
0264
0265
0266
0267
0268
0269
0270
0271 pad = ((unsigned long)iterator->_arg -
0272 (unsigned long)iterator->_rtheader) & (align - 1);
0273
0274 if (pad)
0275 iterator->_arg += align - pad;
0276
0277 if (iterator->_arg_index % 32 == IEEE80211_RADIOTAP_VENDOR_NAMESPACE) {
0278 int vnslen;
0279
0280 if ((unsigned long)iterator->_arg + size -
0281 (unsigned long)iterator->_rtheader >
0282 (unsigned long)iterator->_max_length)
0283 return -EINVAL;
0284
0285 oui = (*iterator->_arg << 16) |
0286 (*(iterator->_arg + 1) << 8) |
0287 *(iterator->_arg + 2);
0288 subns = *(iterator->_arg + 3);
0289
0290 find_ns(iterator, oui, subns);
0291
0292 vnslen = get_unaligned_le16(iterator->_arg + 4);
0293 iterator->_next_ns_data = iterator->_arg + size + vnslen;
0294 if (!iterator->current_namespace)
0295 size += vnslen;
0296 }
0297
0298
0299
0300
0301
0302 iterator->this_arg_index = iterator->_arg_index;
0303 iterator->this_arg = iterator->_arg;
0304 iterator->this_arg_size = size;
0305
0306
0307 iterator->_arg += size;
0308
0309
0310
0311
0312
0313
0314
0315
0316 if ((unsigned long)iterator->_arg -
0317 (unsigned long)iterator->_rtheader >
0318 (unsigned long)iterator->_max_length)
0319 return -EINVAL;
0320
0321
0322 switch (iterator->_arg_index % 32) {
0323 case IEEE80211_RADIOTAP_VENDOR_NAMESPACE:
0324 iterator->_reset_on_ext = 1;
0325
0326 iterator->is_radiotap_ns = 0;
0327
0328
0329
0330
0331
0332
0333 iterator->this_arg_index =
0334 IEEE80211_RADIOTAP_VENDOR_NAMESPACE;
0335 if (!iterator->current_namespace)
0336 hit = 1;
0337 goto next_entry;
0338 case IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE:
0339 iterator->_reset_on_ext = 1;
0340 iterator->current_namespace = &radiotap_ns;
0341 iterator->is_radiotap_ns = 1;
0342 goto next_entry;
0343 case IEEE80211_RADIOTAP_EXT:
0344
0345
0346
0347
0348 iterator->_bitmap_shifter =
0349 get_unaligned_le32(iterator->_next_bitmap);
0350 iterator->_next_bitmap++;
0351 if (iterator->_reset_on_ext)
0352 iterator->_arg_index = 0;
0353 else
0354 iterator->_arg_index++;
0355 iterator->_reset_on_ext = 0;
0356 break;
0357 default:
0358
0359 hit = 1;
0360 next_entry:
0361 iterator->_bitmap_shifter >>= 1;
0362 iterator->_arg_index++;
0363 }
0364
0365
0366 if (hit)
0367 return 0;
0368 }
0369 }
0370 EXPORT_SYMBOL(ieee80211_radiotap_iterator_next);