blob: d09559f793e2a28f6ab88a39a7cc2b8b8298dfd7 [file] [log] [blame]
Naveen Sampath04696f72022-06-13 15:19:14 +05301// Copyright 2014 Google, Inc. All rights reserved.
2//
3// Use of this source code is governed by a BSD-style license
4// that can be found in the LICENSE file in the root of the source
5// tree.
6
7package layers
8
9import (
10 "bytes"
11 "encoding/binary"
12 "errors"
13 "fmt"
14 "hash/crc32"
15 "strings"
16
17 "github.com/google/gopacket"
18)
19
20// align calculates the number of bytes needed to align with the width
21// on the offset, returning the number of bytes we need to skip to
22// align to the offset (width).
23func align(offset uint16, width uint16) uint16 {
24 return ((((offset) + ((width) - 1)) & (^((width) - 1))) - offset)
25}
26
27type RadioTapPresent uint32
28
29const (
30 RadioTapPresentTSFT RadioTapPresent = 1 << iota
31 RadioTapPresentFlags
32 RadioTapPresentRate
33 RadioTapPresentChannel
34 RadioTapPresentFHSS
35 RadioTapPresentDBMAntennaSignal
36 RadioTapPresentDBMAntennaNoise
37 RadioTapPresentLockQuality
38 RadioTapPresentTxAttenuation
39 RadioTapPresentDBTxAttenuation
40 RadioTapPresentDBMTxPower
41 RadioTapPresentAntenna
42 RadioTapPresentDBAntennaSignal
43 RadioTapPresentDBAntennaNoise
44 RadioTapPresentRxFlags
45 RadioTapPresentTxFlags
46 RadioTapPresentRtsRetries
47 RadioTapPresentDataRetries
48 _
49 RadioTapPresentMCS
50 RadioTapPresentAMPDUStatus
51 RadioTapPresentVHT
52 RadioTapPresentEXT RadioTapPresent = 1 << 31
53)
54
55func (r RadioTapPresent) TSFT() bool {
56 return r&RadioTapPresentTSFT != 0
57}
58func (r RadioTapPresent) Flags() bool {
59 return r&RadioTapPresentFlags != 0
60}
61func (r RadioTapPresent) Rate() bool {
62 return r&RadioTapPresentRate != 0
63}
64func (r RadioTapPresent) Channel() bool {
65 return r&RadioTapPresentChannel != 0
66}
67func (r RadioTapPresent) FHSS() bool {
68 return r&RadioTapPresentFHSS != 0
69}
70func (r RadioTapPresent) DBMAntennaSignal() bool {
71 return r&RadioTapPresentDBMAntennaSignal != 0
72}
73func (r RadioTapPresent) DBMAntennaNoise() bool {
74 return r&RadioTapPresentDBMAntennaNoise != 0
75}
76func (r RadioTapPresent) LockQuality() bool {
77 return r&RadioTapPresentLockQuality != 0
78}
79func (r RadioTapPresent) TxAttenuation() bool {
80 return r&RadioTapPresentTxAttenuation != 0
81}
82func (r RadioTapPresent) DBTxAttenuation() bool {
83 return r&RadioTapPresentDBTxAttenuation != 0
84}
85func (r RadioTapPresent) DBMTxPower() bool {
86 return r&RadioTapPresentDBMTxPower != 0
87}
88func (r RadioTapPresent) Antenna() bool {
89 return r&RadioTapPresentAntenna != 0
90}
91func (r RadioTapPresent) DBAntennaSignal() bool {
92 return r&RadioTapPresentDBAntennaSignal != 0
93}
94func (r RadioTapPresent) DBAntennaNoise() bool {
95 return r&RadioTapPresentDBAntennaNoise != 0
96}
97func (r RadioTapPresent) RxFlags() bool {
98 return r&RadioTapPresentRxFlags != 0
99}
100func (r RadioTapPresent) TxFlags() bool {
101 return r&RadioTapPresentTxFlags != 0
102}
103func (r RadioTapPresent) RtsRetries() bool {
104 return r&RadioTapPresentRtsRetries != 0
105}
106func (r RadioTapPresent) DataRetries() bool {
107 return r&RadioTapPresentDataRetries != 0
108}
109func (r RadioTapPresent) MCS() bool {
110 return r&RadioTapPresentMCS != 0
111}
112func (r RadioTapPresent) AMPDUStatus() bool {
113 return r&RadioTapPresentAMPDUStatus != 0
114}
115func (r RadioTapPresent) VHT() bool {
116 return r&RadioTapPresentVHT != 0
117}
118func (r RadioTapPresent) EXT() bool {
119 return r&RadioTapPresentEXT != 0
120}
121
122type RadioTapChannelFlags uint16
123
124const (
125 RadioTapChannelFlagsTurbo RadioTapChannelFlags = 0x0010 // Turbo channel
126 RadioTapChannelFlagsCCK RadioTapChannelFlags = 0x0020 // CCK channel
127 RadioTapChannelFlagsOFDM RadioTapChannelFlags = 0x0040 // OFDM channel
128 RadioTapChannelFlagsGhz2 RadioTapChannelFlags = 0x0080 // 2 GHz spectrum channel.
129 RadioTapChannelFlagsGhz5 RadioTapChannelFlags = 0x0100 // 5 GHz spectrum channel
130 RadioTapChannelFlagsPassive RadioTapChannelFlags = 0x0200 // Only passive scan allowed
131 RadioTapChannelFlagsDynamic RadioTapChannelFlags = 0x0400 // Dynamic CCK-OFDM channel
132 RadioTapChannelFlagsGFSK RadioTapChannelFlags = 0x0800 // GFSK channel (FHSS PHY)
133)
134
135func (r RadioTapChannelFlags) Turbo() bool {
136 return r&RadioTapChannelFlagsTurbo != 0
137}
138func (r RadioTapChannelFlags) CCK() bool {
139 return r&RadioTapChannelFlagsCCK != 0
140}
141func (r RadioTapChannelFlags) OFDM() bool {
142 return r&RadioTapChannelFlagsOFDM != 0
143}
144func (r RadioTapChannelFlags) Ghz2() bool {
145 return r&RadioTapChannelFlagsGhz2 != 0
146}
147func (r RadioTapChannelFlags) Ghz5() bool {
148 return r&RadioTapChannelFlagsGhz5 != 0
149}
150func (r RadioTapChannelFlags) Passive() bool {
151 return r&RadioTapChannelFlagsPassive != 0
152}
153func (r RadioTapChannelFlags) Dynamic() bool {
154 return r&RadioTapChannelFlagsDynamic != 0
155}
156func (r RadioTapChannelFlags) GFSK() bool {
157 return r&RadioTapChannelFlagsGFSK != 0
158}
159
160// String provides a human readable string for RadioTapChannelFlags.
161// This string is possibly subject to change over time; if you're storing this
162// persistently, you should probably store the RadioTapChannelFlags value, not its string.
163func (a RadioTapChannelFlags) String() string {
164 var out bytes.Buffer
165 if a.Turbo() {
166 out.WriteString("Turbo,")
167 }
168 if a.CCK() {
169 out.WriteString("CCK,")
170 }
171 if a.OFDM() {
172 out.WriteString("OFDM,")
173 }
174 if a.Ghz2() {
175 out.WriteString("Ghz2,")
176 }
177 if a.Ghz5() {
178 out.WriteString("Ghz5,")
179 }
180 if a.Passive() {
181 out.WriteString("Passive,")
182 }
183 if a.Dynamic() {
184 out.WriteString("Dynamic,")
185 }
186 if a.GFSK() {
187 out.WriteString("GFSK,")
188 }
189
190 if length := out.Len(); length > 0 {
191 return string(out.Bytes()[:length-1]) // strip final comma
192 }
193 return ""
194}
195
196type RadioTapFlags uint8
197
198const (
199 RadioTapFlagsCFP RadioTapFlags = 1 << iota // sent/received during CFP
200 RadioTapFlagsShortPreamble // sent/received * with short * preamble
201 RadioTapFlagsWEP // sent/received * with WEP encryption
202 RadioTapFlagsFrag // sent/received * with fragmentation
203 RadioTapFlagsFCS // frame includes FCS
204 RadioTapFlagsDatapad // frame has padding between * 802.11 header and payload * (to 32-bit boundary)
205 RadioTapFlagsBadFCS // does not pass FCS check
206 RadioTapFlagsShortGI // HT short GI
207)
208
209func (r RadioTapFlags) CFP() bool {
210 return r&RadioTapFlagsCFP != 0
211}
212func (r RadioTapFlags) ShortPreamble() bool {
213 return r&RadioTapFlagsShortPreamble != 0
214}
215func (r RadioTapFlags) WEP() bool {
216 return r&RadioTapFlagsWEP != 0
217}
218func (r RadioTapFlags) Frag() bool {
219 return r&RadioTapFlagsFrag != 0
220}
221func (r RadioTapFlags) FCS() bool {
222 return r&RadioTapFlagsFCS != 0
223}
224func (r RadioTapFlags) Datapad() bool {
225 return r&RadioTapFlagsDatapad != 0
226}
227func (r RadioTapFlags) BadFCS() bool {
228 return r&RadioTapFlagsBadFCS != 0
229}
230func (r RadioTapFlags) ShortGI() bool {
231 return r&RadioTapFlagsShortGI != 0
232}
233
234// String provides a human readable string for RadioTapFlags.
235// This string is possibly subject to change over time; if you're storing this
236// persistently, you should probably store the RadioTapFlags value, not its string.
237func (a RadioTapFlags) String() string {
238 var out bytes.Buffer
239 if a.CFP() {
240 out.WriteString("CFP,")
241 }
242 if a.ShortPreamble() {
243 out.WriteString("SHORT-PREAMBLE,")
244 }
245 if a.WEP() {
246 out.WriteString("WEP,")
247 }
248 if a.Frag() {
249 out.WriteString("FRAG,")
250 }
251 if a.FCS() {
252 out.WriteString("FCS,")
253 }
254 if a.Datapad() {
255 out.WriteString("DATAPAD,")
256 }
257 if a.ShortGI() {
258 out.WriteString("SHORT-GI,")
259 }
260
261 if length := out.Len(); length > 0 {
262 return string(out.Bytes()[:length-1]) // strip final comma
263 }
264 return ""
265}
266
267type RadioTapRate uint8
268
269func (a RadioTapRate) String() string {
270 return fmt.Sprintf("%v Mb/s", 0.5*float32(a))
271}
272
273type RadioTapChannelFrequency uint16
274
275func (a RadioTapChannelFrequency) String() string {
276 return fmt.Sprintf("%d MHz", a)
277}
278
279type RadioTapRxFlags uint16
280
281const (
282 RadioTapRxFlagsBadPlcp RadioTapRxFlags = 0x0002
283)
284
285func (self RadioTapRxFlags) BadPlcp() bool {
286 return self&RadioTapRxFlagsBadPlcp != 0
287}
288
289func (self RadioTapRxFlags) String() string {
290 if self.BadPlcp() {
291 return "BADPLCP"
292 }
293 return ""
294}
295
296type RadioTapTxFlags uint16
297
298const (
299 RadioTapTxFlagsFail RadioTapTxFlags = 1 << iota
300 RadioTapTxFlagsCTS
301 RadioTapTxFlagsRTS
302 RadioTapTxFlagsNoACK
303)
304
305func (self RadioTapTxFlags) Fail() bool { return self&RadioTapTxFlagsFail != 0 }
306func (self RadioTapTxFlags) CTS() bool { return self&RadioTapTxFlagsCTS != 0 }
307func (self RadioTapTxFlags) RTS() bool { return self&RadioTapTxFlagsRTS != 0 }
308func (self RadioTapTxFlags) NoACK() bool { return self&RadioTapTxFlagsNoACK != 0 }
309
310func (self RadioTapTxFlags) String() string {
311 var tokens []string
312 if self.Fail() {
313 tokens = append(tokens, "Fail")
314 }
315 if self.CTS() {
316 tokens = append(tokens, "CTS")
317 }
318 if self.RTS() {
319 tokens = append(tokens, "RTS")
320 }
321 if self.NoACK() {
322 tokens = append(tokens, "NoACK")
323 }
324 return strings.Join(tokens, ",")
325}
326
327type RadioTapMCS struct {
328 Known RadioTapMCSKnown
329 Flags RadioTapMCSFlags
330 MCS uint8
331}
332
333func (self RadioTapMCS) String() string {
334 var tokens []string
335 if self.Known.Bandwidth() {
336 token := "?"
337 switch self.Flags.Bandwidth() {
338 case 0:
339 token = "20"
340 case 1:
341 token = "40"
342 case 2:
343 token = "40(20L)"
344 case 3:
345 token = "40(20U)"
346 }
347 tokens = append(tokens, token)
348 }
349 if self.Known.MCSIndex() {
350 tokens = append(tokens, fmt.Sprintf("MCSIndex#%d", self.MCS))
351 }
352 if self.Known.GuardInterval() {
353 if self.Flags.ShortGI() {
354 tokens = append(tokens, fmt.Sprintf("shortGI"))
355 } else {
356 tokens = append(tokens, fmt.Sprintf("longGI"))
357 }
358 }
359 if self.Known.HTFormat() {
360 if self.Flags.Greenfield() {
361 tokens = append(tokens, fmt.Sprintf("HT-greenfield"))
362 } else {
363 tokens = append(tokens, fmt.Sprintf("HT-mixed"))
364 }
365 }
366 if self.Known.FECType() {
367 if self.Flags.FECLDPC() {
368 tokens = append(tokens, fmt.Sprintf("LDPC"))
369 } else {
370 tokens = append(tokens, fmt.Sprintf("BCC"))
371 }
372 }
373 if self.Known.STBC() {
374 tokens = append(tokens, fmt.Sprintf("STBC#%d", self.Flags.STBC()))
375 }
376 if self.Known.NESS() {
377 num := 0
378 if self.Known.NESS1() {
379 num |= 0x02
380 }
381 if self.Flags.NESS0() {
382 num |= 0x01
383 }
384 tokens = append(tokens, fmt.Sprintf("num-of-ESS#%d", num))
385 }
386 return strings.Join(tokens, ",")
387}
388
389type RadioTapMCSKnown uint8
390
391const (
392 RadioTapMCSKnownBandwidth RadioTapMCSKnown = 1 << iota
393 RadioTapMCSKnownMCSIndex
394 RadioTapMCSKnownGuardInterval
395 RadioTapMCSKnownHTFormat
396 RadioTapMCSKnownFECType
397 RadioTapMCSKnownSTBC
398 RadioTapMCSKnownNESS
399 RadioTapMCSKnownNESS1
400)
401
402func (self RadioTapMCSKnown) Bandwidth() bool { return self&RadioTapMCSKnownBandwidth != 0 }
403func (self RadioTapMCSKnown) MCSIndex() bool { return self&RadioTapMCSKnownMCSIndex != 0 }
404func (self RadioTapMCSKnown) GuardInterval() bool { return self&RadioTapMCSKnownGuardInterval != 0 }
405func (self RadioTapMCSKnown) HTFormat() bool { return self&RadioTapMCSKnownHTFormat != 0 }
406func (self RadioTapMCSKnown) FECType() bool { return self&RadioTapMCSKnownFECType != 0 }
407func (self RadioTapMCSKnown) STBC() bool { return self&RadioTapMCSKnownSTBC != 0 }
408func (self RadioTapMCSKnown) NESS() bool { return self&RadioTapMCSKnownNESS != 0 }
409func (self RadioTapMCSKnown) NESS1() bool { return self&RadioTapMCSKnownNESS1 != 0 }
410
411type RadioTapMCSFlags uint8
412
413const (
414 RadioTapMCSFlagsBandwidthMask RadioTapMCSFlags = 0x03
415 RadioTapMCSFlagsShortGI = 0x04
416 RadioTapMCSFlagsGreenfield = 0x08
417 RadioTapMCSFlagsFECLDPC = 0x10
418 RadioTapMCSFlagsSTBCMask = 0x60
419 RadioTapMCSFlagsNESS0 = 0x80
420)
421
422func (self RadioTapMCSFlags) Bandwidth() int {
423 return int(self & RadioTapMCSFlagsBandwidthMask)
424}
425func (self RadioTapMCSFlags) ShortGI() bool { return self&RadioTapMCSFlagsShortGI != 0 }
426func (self RadioTapMCSFlags) Greenfield() bool { return self&RadioTapMCSFlagsGreenfield != 0 }
427func (self RadioTapMCSFlags) FECLDPC() bool { return self&RadioTapMCSFlagsFECLDPC != 0 }
428func (self RadioTapMCSFlags) STBC() int {
429 return int(self&RadioTapMCSFlagsSTBCMask) >> 5
430}
431func (self RadioTapMCSFlags) NESS0() bool { return self&RadioTapMCSFlagsNESS0 != 0 }
432
433type RadioTapAMPDUStatus struct {
434 Reference uint32
435 Flags RadioTapAMPDUStatusFlags
436 CRC uint8
437}
438
439func (self RadioTapAMPDUStatus) String() string {
440 tokens := []string{
441 fmt.Sprintf("ref#%x", self.Reference),
442 }
443 if self.Flags.ReportZerolen() && self.Flags.IsZerolen() {
444 tokens = append(tokens, fmt.Sprintf("zero-length"))
445 }
446 if self.Flags.LastKnown() && self.Flags.IsLast() {
447 tokens = append(tokens, "last")
448 }
449 if self.Flags.DelimCRCErr() {
450 tokens = append(tokens, "delimiter CRC error")
451 }
452 if self.Flags.DelimCRCKnown() {
453 tokens = append(tokens, fmt.Sprintf("delimiter-CRC=%02x", self.CRC))
454 }
455 return strings.Join(tokens, ",")
456}
457
458type RadioTapAMPDUStatusFlags uint16
459
460const (
461 RadioTapAMPDUStatusFlagsReportZerolen RadioTapAMPDUStatusFlags = 1 << iota
462 RadioTapAMPDUIsZerolen
463 RadioTapAMPDULastKnown
464 RadioTapAMPDUIsLast
465 RadioTapAMPDUDelimCRCErr
466 RadioTapAMPDUDelimCRCKnown
467)
468
469func (self RadioTapAMPDUStatusFlags) ReportZerolen() bool {
470 return self&RadioTapAMPDUStatusFlagsReportZerolen != 0
471}
472func (self RadioTapAMPDUStatusFlags) IsZerolen() bool { return self&RadioTapAMPDUIsZerolen != 0 }
473func (self RadioTapAMPDUStatusFlags) LastKnown() bool { return self&RadioTapAMPDULastKnown != 0 }
474func (self RadioTapAMPDUStatusFlags) IsLast() bool { return self&RadioTapAMPDUIsLast != 0 }
475func (self RadioTapAMPDUStatusFlags) DelimCRCErr() bool { return self&RadioTapAMPDUDelimCRCErr != 0 }
476func (self RadioTapAMPDUStatusFlags) DelimCRCKnown() bool {
477 return self&RadioTapAMPDUDelimCRCKnown != 0
478}
479
480type RadioTapVHT struct {
481 Known RadioTapVHTKnown
482 Flags RadioTapVHTFlags
483 Bandwidth uint8
484 MCSNSS [4]RadioTapVHTMCSNSS
485 Coding uint8
486 GroupId uint8
487 PartialAID uint16
488}
489
490func (self RadioTapVHT) String() string {
491 var tokens []string
492 if self.Known.STBC() {
493 if self.Flags.STBC() {
494 tokens = append(tokens, "STBC")
495 } else {
496 tokens = append(tokens, "no STBC")
497 }
498 }
499 if self.Known.TXOPPSNotAllowed() {
500 if self.Flags.TXOPPSNotAllowed() {
501 tokens = append(tokens, "TXOP doze not allowed")
502 } else {
503 tokens = append(tokens, "TXOP doze allowed")
504 }
505 }
506 if self.Known.GI() {
507 if self.Flags.SGI() {
508 tokens = append(tokens, "short GI")
509 } else {
510 tokens = append(tokens, "long GI")
511 }
512 }
513 if self.Known.SGINSYMDisambiguation() {
514 if self.Flags.SGINSYMMod() {
515 tokens = append(tokens, "NSYM mod 10=9")
516 } else {
517 tokens = append(tokens, "NSYM mod 10!=9 or no short GI")
518 }
519 }
520 if self.Known.LDPCExtraOFDMSymbol() {
521 if self.Flags.LDPCExtraOFDMSymbol() {
522 tokens = append(tokens, "LDPC extra OFDM symbols")
523 } else {
524 tokens = append(tokens, "no LDPC extra OFDM symbols")
525 }
526 }
527 if self.Known.Beamformed() {
528 if self.Flags.Beamformed() {
529 tokens = append(tokens, "beamformed")
530 } else {
531 tokens = append(tokens, "no beamformed")
532 }
533 }
534 if self.Known.Bandwidth() {
535 token := "?"
536 switch self.Bandwidth & 0x1f {
537 case 0:
538 token = "20"
539 case 1:
540 token = "40"
541 case 2:
542 token = "40(20L)"
543 case 3:
544 token = "40(20U)"
545 case 4:
546 token = "80"
547 case 5:
548 token = "80(40L)"
549 case 6:
550 token = "80(40U)"
551 case 7:
552 token = "80(20LL)"
553 case 8:
554 token = "80(20LU)"
555 case 9:
556 token = "80(20UL)"
557 case 10:
558 token = "80(20UU)"
559 case 11:
560 token = "160"
561 case 12:
562 token = "160(80L)"
563 case 13:
564 token = "160(80U)"
565 case 14:
566 token = "160(40LL)"
567 case 15:
568 token = "160(40LU)"
569 case 16:
570 token = "160(40UL)"
571 case 17:
572 token = "160(40UU)"
573 case 18:
574 token = "160(20LLL)"
575 case 19:
576 token = "160(20LLU)"
577 case 20:
578 token = "160(20LUL)"
579 case 21:
580 token = "160(20LUU)"
581 case 22:
582 token = "160(20ULL)"
583 case 23:
584 token = "160(20ULU)"
585 case 24:
586 token = "160(20UUL)"
587 case 25:
588 token = "160(20UUU)"
589 }
590 tokens = append(tokens, token)
591 }
592 for i, MCSNSS := range self.MCSNSS {
593 if MCSNSS.Present() {
594 fec := "?"
595 switch self.Coding & (1 << uint8(i)) {
596 case 0:
597 fec = "BCC"
598 case 1:
599 fec = "LDPC"
600 }
601 tokens = append(tokens, fmt.Sprintf("user%d(%s,%s)", i, MCSNSS.String(), fec))
602 }
603 }
604 if self.Known.GroupId() {
605 tokens = append(tokens,
606 fmt.Sprintf("group=%d", self.GroupId))
607 }
608 if self.Known.PartialAID() {
609 tokens = append(tokens,
610 fmt.Sprintf("partial-AID=%d", self.PartialAID))
611 }
612 return strings.Join(tokens, ",")
613}
614
615type RadioTapVHTKnown uint16
616
617const (
618 RadioTapVHTKnownSTBC RadioTapVHTKnown = 1 << iota
619 RadioTapVHTKnownTXOPPSNotAllowed
620 RadioTapVHTKnownGI
621 RadioTapVHTKnownSGINSYMDisambiguation
622 RadioTapVHTKnownLDPCExtraOFDMSymbol
623 RadioTapVHTKnownBeamformed
624 RadioTapVHTKnownBandwidth
625 RadioTapVHTKnownGroupId
626 RadioTapVHTKnownPartialAID
627)
628
629func (self RadioTapVHTKnown) STBC() bool { return self&RadioTapVHTKnownSTBC != 0 }
630func (self RadioTapVHTKnown) TXOPPSNotAllowed() bool {
631 return self&RadioTapVHTKnownTXOPPSNotAllowed != 0
632}
633func (self RadioTapVHTKnown) GI() bool { return self&RadioTapVHTKnownGI != 0 }
634func (self RadioTapVHTKnown) SGINSYMDisambiguation() bool {
635 return self&RadioTapVHTKnownSGINSYMDisambiguation != 0
636}
637func (self RadioTapVHTKnown) LDPCExtraOFDMSymbol() bool {
638 return self&RadioTapVHTKnownLDPCExtraOFDMSymbol != 0
639}
640func (self RadioTapVHTKnown) Beamformed() bool { return self&RadioTapVHTKnownBeamformed != 0 }
641func (self RadioTapVHTKnown) Bandwidth() bool { return self&RadioTapVHTKnownBandwidth != 0 }
642func (self RadioTapVHTKnown) GroupId() bool { return self&RadioTapVHTKnownGroupId != 0 }
643func (self RadioTapVHTKnown) PartialAID() bool { return self&RadioTapVHTKnownPartialAID != 0 }
644
645type RadioTapVHTFlags uint8
646
647const (
648 RadioTapVHTFlagsSTBC RadioTapVHTFlags = 1 << iota
649 RadioTapVHTFlagsTXOPPSNotAllowed
650 RadioTapVHTFlagsSGI
651 RadioTapVHTFlagsSGINSYMMod
652 RadioTapVHTFlagsLDPCExtraOFDMSymbol
653 RadioTapVHTFlagsBeamformed
654)
655
656func (self RadioTapVHTFlags) STBC() bool { return self&RadioTapVHTFlagsSTBC != 0 }
657func (self RadioTapVHTFlags) TXOPPSNotAllowed() bool {
658 return self&RadioTapVHTFlagsTXOPPSNotAllowed != 0
659}
660func (self RadioTapVHTFlags) SGI() bool { return self&RadioTapVHTFlagsSGI != 0 }
661func (self RadioTapVHTFlags) SGINSYMMod() bool { return self&RadioTapVHTFlagsSGINSYMMod != 0 }
662func (self RadioTapVHTFlags) LDPCExtraOFDMSymbol() bool {
663 return self&RadioTapVHTFlagsLDPCExtraOFDMSymbol != 0
664}
665func (self RadioTapVHTFlags) Beamformed() bool { return self&RadioTapVHTFlagsBeamformed != 0 }
666
667type RadioTapVHTMCSNSS uint8
668
669func (self RadioTapVHTMCSNSS) Present() bool {
670 return self&0x0F != 0
671}
672
673func (self RadioTapVHTMCSNSS) String() string {
674 return fmt.Sprintf("NSS#%dMCS#%d", uint32(self&0xf), uint32(self>>4))
675}
676
677func decodeRadioTap(data []byte, p gopacket.PacketBuilder) error {
678 d := &RadioTap{}
679 // TODO: Should we set LinkLayer here? And implement LinkFlow
680 return decodingLayerDecoder(d, data, p)
681}
682
683type RadioTap struct {
684 BaseLayer
685
686 // Version 0. Only increases for drastic changes, introduction of compatible new fields does not count.
687 Version uint8
688 // Length of the whole header in bytes, including it_version, it_pad, it_len, and data fields.
689 Length uint16
690 // Present is a bitmap telling which fields are present. Set bit 31 (0x80000000) to extend the bitmap by another 32 bits. Additional extensions are made by setting bit 31.
691 Present RadioTapPresent
692 // TSFT: value in microseconds of the MAC's 64-bit 802.11 Time Synchronization Function timer when the first bit of the MPDU arrived at the MAC. For received frames, only.
693 TSFT uint64
694 Flags RadioTapFlags
695 // Rate Tx/Rx data rate
696 Rate RadioTapRate
697 // ChannelFrequency Tx/Rx frequency in MHz, followed by flags
698 ChannelFrequency RadioTapChannelFrequency
699 ChannelFlags RadioTapChannelFlags
700 // FHSS For frequency-hopping radios, the hop set (first byte) and pattern (second byte).
701 FHSS uint16
702 // DBMAntennaSignal RF signal power at the antenna, decibel difference from one milliwatt.
703 DBMAntennaSignal int8
704 // DBMAntennaNoise RF noise power at the antenna, decibel difference from one milliwatt.
705 DBMAntennaNoise int8
706 // LockQuality Quality of Barker code lock. Unitless. Monotonically nondecreasing with "better" lock strength. Called "Signal Quality" in datasheets.
707 LockQuality uint16
708 // TxAttenuation Transmit power expressed as unitless distance from max power set at factory calibration. 0 is max power. Monotonically nondecreasing with lower power levels.
709 TxAttenuation uint16
710 // DBTxAttenuation Transmit power expressed as decibel distance from max power set at factory calibration. 0 is max power. Monotonically nondecreasing with lower power levels.
711 DBTxAttenuation uint16
712 // DBMTxPower Transmit power expressed as dBm (decibels from a 1 milliwatt reference). This is the absolute power level measured at the antenna port.
713 DBMTxPower int8
714 // Antenna Unitless indication of the Rx/Tx antenna for this packet. The first antenna is antenna 0.
715 Antenna uint8
716 // DBAntennaSignal RF signal power at the antenna, decibel difference from an arbitrary, fixed reference.
717 DBAntennaSignal uint8
718 // DBAntennaNoise RF noise power at the antenna, decibel difference from an arbitrary, fixed reference point.
719 DBAntennaNoise uint8
720 //
721 RxFlags RadioTapRxFlags
722 TxFlags RadioTapTxFlags
723 RtsRetries uint8
724 DataRetries uint8
725 MCS RadioTapMCS
726 AMPDUStatus RadioTapAMPDUStatus
727 VHT RadioTapVHT
728}
729
730func (m *RadioTap) LayerType() gopacket.LayerType { return LayerTypeRadioTap }
731
732func (m *RadioTap) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
733 if len(data) < 8 {
734 df.SetTruncated()
735 return errors.New("RadioTap too small")
736 }
737 m.Version = uint8(data[0])
738 m.Length = binary.LittleEndian.Uint16(data[2:4])
739 m.Present = RadioTapPresent(binary.LittleEndian.Uint32(data[4:8]))
740
741 offset := uint16(4)
742
743 for (binary.LittleEndian.Uint32(data[offset:offset+4]) & 0x80000000) != 0 {
744 // This parser only handles standard radiotap namespace,
745 // and expects all fields are packed in the first it_present.
746 // Extended bitmap will be just ignored.
747 offset += 4
748 }
749 offset += 4 // skip the bitmap
750
751 if m.Present.TSFT() {
752 offset += align(offset, 8)
753 m.TSFT = binary.LittleEndian.Uint64(data[offset : offset+8])
754 offset += 8
755 }
756 if m.Present.Flags() {
757 m.Flags = RadioTapFlags(data[offset])
758 offset++
759 }
760 if m.Present.Rate() {
761 m.Rate = RadioTapRate(data[offset])
762 offset++
763 }
764 if m.Present.Channel() {
765 offset += align(offset, 2)
766 m.ChannelFrequency = RadioTapChannelFrequency(binary.LittleEndian.Uint16(data[offset : offset+2]))
767 offset += 2
768 m.ChannelFlags = RadioTapChannelFlags(binary.LittleEndian.Uint16(data[offset : offset+2]))
769 offset += 2
770 }
771 if m.Present.FHSS() {
772 m.FHSS = binary.LittleEndian.Uint16(data[offset : offset+2])
773 offset += 2
774 }
775 if m.Present.DBMAntennaSignal() {
776 m.DBMAntennaSignal = int8(data[offset])
777 offset++
778 }
779 if m.Present.DBMAntennaNoise() {
780 m.DBMAntennaNoise = int8(data[offset])
781 offset++
782 }
783 if m.Present.LockQuality() {
784 offset += align(offset, 2)
785 m.LockQuality = binary.LittleEndian.Uint16(data[offset : offset+2])
786 offset += 2
787 }
788 if m.Present.TxAttenuation() {
789 offset += align(offset, 2)
790 m.TxAttenuation = binary.LittleEndian.Uint16(data[offset : offset+2])
791 offset += 2
792 }
793 if m.Present.DBTxAttenuation() {
794 offset += align(offset, 2)
795 m.DBTxAttenuation = binary.LittleEndian.Uint16(data[offset : offset+2])
796 offset += 2
797 }
798 if m.Present.DBMTxPower() {
799 m.DBMTxPower = int8(data[offset])
800 offset++
801 }
802 if m.Present.Antenna() {
803 m.Antenna = uint8(data[offset])
804 offset++
805 }
806 if m.Present.DBAntennaSignal() {
807 m.DBAntennaSignal = uint8(data[offset])
808 offset++
809 }
810 if m.Present.DBAntennaNoise() {
811 m.DBAntennaNoise = uint8(data[offset])
812 offset++
813 }
814 if m.Present.RxFlags() {
815 offset += align(offset, 2)
816 m.RxFlags = RadioTapRxFlags(binary.LittleEndian.Uint16(data[offset:]))
817 offset += 2
818 }
819 if m.Present.TxFlags() {
820 offset += align(offset, 2)
821 m.TxFlags = RadioTapTxFlags(binary.LittleEndian.Uint16(data[offset:]))
822 offset += 2
823 }
824 if m.Present.RtsRetries() {
825 m.RtsRetries = uint8(data[offset])
826 offset++
827 }
828 if m.Present.DataRetries() {
829 m.DataRetries = uint8(data[offset])
830 offset++
831 }
832 if m.Present.MCS() {
833 m.MCS = RadioTapMCS{
834 RadioTapMCSKnown(data[offset]),
835 RadioTapMCSFlags(data[offset+1]),
836 uint8(data[offset+2]),
837 }
838 offset += 3
839 }
840 if m.Present.AMPDUStatus() {
841 offset += align(offset, 4)
842 m.AMPDUStatus = RadioTapAMPDUStatus{
843 Reference: binary.LittleEndian.Uint32(data[offset:]),
844 Flags: RadioTapAMPDUStatusFlags(binary.LittleEndian.Uint16(data[offset+4:])),
845 CRC: uint8(data[offset+6]),
846 }
847 offset += 8
848 }
849 if m.Present.VHT() {
850 offset += align(offset, 2)
851 m.VHT = RadioTapVHT{
852 Known: RadioTapVHTKnown(binary.LittleEndian.Uint16(data[offset:])),
853 Flags: RadioTapVHTFlags(data[offset+2]),
854 Bandwidth: uint8(data[offset+3]),
855 MCSNSS: [4]RadioTapVHTMCSNSS{
856 RadioTapVHTMCSNSS(data[offset+4]),
857 RadioTapVHTMCSNSS(data[offset+5]),
858 RadioTapVHTMCSNSS(data[offset+6]),
859 RadioTapVHTMCSNSS(data[offset+7]),
860 },
861 Coding: uint8(data[offset+8]),
862 GroupId: uint8(data[offset+9]),
863 PartialAID: binary.LittleEndian.Uint16(data[offset+10:]),
864 }
865 offset += 12
866 }
867
868 payload := data[m.Length:]
869
870 // Remove non standard padding used by some Wi-Fi drivers
871 if m.Flags.Datapad() &&
872 payload[0]&0xC == 0x8 { //&& // Data frame
873 headlen := 24
874 if payload[0]&0x8C == 0x88 { // QoS
875 headlen += 2
876 }
877 if payload[1]&0x3 == 0x3 { // 4 addresses
878 headlen += 2
879 }
880 if headlen%4 == 2 {
881 payload = append(payload[:headlen], payload[headlen+2:len(payload)]...)
882 }
883 }
884
885 if !m.Flags.FCS() {
886 // Dot11.DecodeFromBytes() expects FCS present and performs a hard chop on the checksum
887 // If a user is handing in subslices or packets from a buffered stream, the capacity of the slice
888 // may extend beyond the len, rather than expecting callers to enforce cap==len on every packet
889 // we take the hit in this one case and do a reallocation. If the user DOES enforce cap==len
890 // then the reallocation will happen anyway on the append. This is requried because the append
891 // write to the memory directly after the payload if there is sufficient capacity, which callers
892 // may not expect.
893 reallocPayload := make([]byte, len(payload)+4)
894 copy(reallocPayload[0:len(payload)], payload)
895 h := crc32.NewIEEE()
896 h.Write(payload)
897 binary.LittleEndian.PutUint32(reallocPayload[len(payload):], h.Sum32())
898 payload = reallocPayload
899 }
900 m.BaseLayer = BaseLayer{Contents: data[:m.Length], Payload: payload}
901
902 return nil
903}
904
905func (m RadioTap) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
906 buf := make([]byte, 1024)
907
908 buf[0] = m.Version
909 buf[1] = 0
910
911 binary.LittleEndian.PutUint32(buf[4:8], uint32(m.Present))
912
913 offset := uint16(4)
914
915 for (binary.LittleEndian.Uint32(buf[offset:offset+4]) & 0x80000000) != 0 {
916 offset += 4
917 }
918
919 offset += 4
920
921 if m.Present.TSFT() {
922 offset += align(offset, 8)
923 binary.LittleEndian.PutUint64(buf[offset:offset+8], m.TSFT)
924 offset += 8
925 }
926
927 if m.Present.Flags() {
928 buf[offset] = uint8(m.Flags)
929 offset++
930 }
931
932 if m.Present.Rate() {
933 buf[offset] = uint8(m.Rate)
934 offset++
935 }
936
937 if m.Present.Channel() {
938 offset += align(offset, 2)
939 binary.LittleEndian.PutUint16(buf[offset:offset+2], uint16(m.ChannelFrequency))
940 offset += 2
941 binary.LittleEndian.PutUint16(buf[offset:offset+2], uint16(m.ChannelFlags))
942 offset += 2
943 }
944
945 if m.Present.FHSS() {
946 binary.LittleEndian.PutUint16(buf[offset:offset+2], m.FHSS)
947 offset += 2
948 }
949
950 if m.Present.DBMAntennaSignal() {
951 buf[offset] = byte(m.DBMAntennaSignal)
952 offset++
953 }
954
955 if m.Present.DBMAntennaNoise() {
956 buf[offset] = byte(m.DBMAntennaNoise)
957 offset++
958 }
959
960 if m.Present.LockQuality() {
961 offset += align(offset, 2)
962 binary.LittleEndian.PutUint16(buf[offset:offset+2], m.LockQuality)
963 offset += 2
964 }
965
966 if m.Present.TxAttenuation() {
967 offset += align(offset, 2)
968 binary.LittleEndian.PutUint16(buf[offset:offset+2], m.TxAttenuation)
969 offset += 2
970 }
971
972 if m.Present.DBTxAttenuation() {
973 offset += align(offset, 2)
974 binary.LittleEndian.PutUint16(buf[offset:offset+2], m.DBTxAttenuation)
975 offset += 2
976 }
977
978 if m.Present.DBMTxPower() {
979 buf[offset] = byte(m.DBMTxPower)
980 offset++
981 }
982
983 if m.Present.Antenna() {
984 buf[offset] = uint8(m.Antenna)
985 offset++
986 }
987
988 if m.Present.DBAntennaSignal() {
989 buf[offset] = uint8(m.DBAntennaSignal)
990 offset++
991 }
992
993 if m.Present.DBAntennaNoise() {
994 buf[offset] = uint8(m.DBAntennaNoise)
995 offset++
996 }
997
998 if m.Present.RxFlags() {
999 offset += align(offset, 2)
1000 binary.LittleEndian.PutUint16(buf[offset:offset+2], uint16(m.RxFlags))
1001 offset += 2
1002 }
1003
1004 if m.Present.TxFlags() {
1005 offset += align(offset, 2)
1006 binary.LittleEndian.PutUint16(buf[offset:offset+2], uint16(m.TxFlags))
1007 offset += 2
1008 }
1009
1010 if m.Present.RtsRetries() {
1011 buf[offset] = m.RtsRetries
1012 offset++
1013 }
1014
1015 if m.Present.DataRetries() {
1016 buf[offset] = m.DataRetries
1017 offset++
1018 }
1019
1020 if m.Present.MCS() {
1021 buf[offset] = uint8(m.MCS.Known)
1022 buf[offset+1] = uint8(m.MCS.Flags)
1023 buf[offset+2] = uint8(m.MCS.MCS)
1024
1025 offset += 3
1026 }
1027
1028 if m.Present.AMPDUStatus() {
1029 offset += align(offset, 4)
1030
1031 binary.LittleEndian.PutUint32(buf[offset:offset+4], m.AMPDUStatus.Reference)
1032 binary.LittleEndian.PutUint16(buf[offset+4:offset+6], uint16(m.AMPDUStatus.Flags))
1033
1034 buf[offset+6] = m.AMPDUStatus.CRC
1035
1036 offset += 8
1037 }
1038
1039 if m.Present.VHT() {
1040 offset += align(offset, 2)
1041
1042 binary.LittleEndian.PutUint16(buf[offset:], uint16(m.VHT.Known))
1043
1044 buf[offset+2] = uint8(m.VHT.Flags)
1045 buf[offset+3] = uint8(m.VHT.Bandwidth)
1046 buf[offset+4] = uint8(m.VHT.MCSNSS[0])
1047 buf[offset+5] = uint8(m.VHT.MCSNSS[1])
1048 buf[offset+6] = uint8(m.VHT.MCSNSS[2])
1049 buf[offset+7] = uint8(m.VHT.MCSNSS[3])
1050 buf[offset+8] = uint8(m.VHT.Coding)
1051 buf[offset+9] = uint8(m.VHT.GroupId)
1052
1053 binary.LittleEndian.PutUint16(buf[offset+10:offset+12], m.VHT.PartialAID)
1054
1055 offset += 12
1056 }
1057
1058 packetBuf, err := b.PrependBytes(int(offset))
1059
1060 if err != nil {
1061 return err
1062 }
1063
1064 if opts.FixLengths {
1065 m.Length = offset
1066 }
1067
1068 binary.LittleEndian.PutUint16(buf[2:4], m.Length)
1069
1070 copy(packetBuf, buf)
1071
1072 return nil
1073}
1074
1075func (m *RadioTap) CanDecode() gopacket.LayerClass { return LayerTypeRadioTap }
1076func (m *RadioTap) NextLayerType() gopacket.LayerType { return LayerTypeDot11 }