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