1// 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 }
1070