// Copyright 2014 Google, Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.

// See http://standards.ieee.org/findstds/standard/802.11-2012.html for info on
// all of the layers in this file.

package layers

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"hash/crc32"
	"net"

	"github.com/google/gopacket"
)

// Dot11Flags contains the set of 8 flags in the IEEE 802.11 frame control
// header, all in one place.
type Dot11Flags uint8

const (
	Dot11FlagsToDS Dot11Flags = 1 << iota
	Dot11FlagsFromDS
	Dot11FlagsMF
	Dot11FlagsRetry
	Dot11FlagsPowerManagement
	Dot11FlagsMD
	Dot11FlagsWEP
	Dot11FlagsOrder
)

func (d Dot11Flags) ToDS() bool {
	return d&Dot11FlagsToDS != 0
}
func (d Dot11Flags) FromDS() bool {
	return d&Dot11FlagsFromDS != 0
}
func (d Dot11Flags) MF() bool {
	return d&Dot11FlagsMF != 0
}
func (d Dot11Flags) Retry() bool {
	return d&Dot11FlagsRetry != 0
}
func (d Dot11Flags) PowerManagement() bool {
	return d&Dot11FlagsPowerManagement != 0
}
func (d Dot11Flags) MD() bool {
	return d&Dot11FlagsMD != 0
}
func (d Dot11Flags) WEP() bool {
	return d&Dot11FlagsWEP != 0
}
func (d Dot11Flags) Order() bool {
	return d&Dot11FlagsOrder != 0
}

// String provides a human readable string for Dot11Flags.
// This string is possibly subject to change over time; if you're storing this
// persistently, you should probably store the Dot11Flags value, not its string.
func (a Dot11Flags) String() string {
	var out bytes.Buffer
	if a.ToDS() {
		out.WriteString("TO-DS,")
	}
	if a.FromDS() {
		out.WriteString("FROM-DS,")
	}
	if a.MF() {
		out.WriteString("MF,")
	}
	if a.Retry() {
		out.WriteString("Retry,")
	}
	if a.PowerManagement() {
		out.WriteString("PowerManagement,")
	}
	if a.MD() {
		out.WriteString("MD,")
	}
	if a.WEP() {
		out.WriteString("WEP,")
	}
	if a.Order() {
		out.WriteString("Order,")
	}

	if length := out.Len(); length > 0 {
		return string(out.Bytes()[:length-1]) // strip final comma
	}
	return ""
}

type Dot11Reason uint16

// TODO: Verify these reasons, and append more reasons if necessary.

const (
	Dot11ReasonReserved          Dot11Reason = 1
	Dot11ReasonUnspecified       Dot11Reason = 2
	Dot11ReasonAuthExpired       Dot11Reason = 3
	Dot11ReasonDeauthStLeaving   Dot11Reason = 4
	Dot11ReasonInactivity        Dot11Reason = 5
	Dot11ReasonApFull            Dot11Reason = 6
	Dot11ReasonClass2FromNonAuth Dot11Reason = 7
	Dot11ReasonClass3FromNonAss  Dot11Reason = 8
	Dot11ReasonDisasStLeaving    Dot11Reason = 9
	Dot11ReasonStNotAuth         Dot11Reason = 10
)

// String provides a human readable string for Dot11Reason.
// This string is possibly subject to change over time; if you're storing this
// persistently, you should probably store the Dot11Reason value, not its string.
func (a Dot11Reason) String() string {
	switch a {
	case Dot11ReasonReserved:
		return "Reserved"
	case Dot11ReasonUnspecified:
		return "Unspecified"
	case Dot11ReasonAuthExpired:
		return "Auth. expired"
	case Dot11ReasonDeauthStLeaving:
		return "Deauth. st. leaving"
	case Dot11ReasonInactivity:
		return "Inactivity"
	case Dot11ReasonApFull:
		return "Ap. full"
	case Dot11ReasonClass2FromNonAuth:
		return "Class2 from non auth."
	case Dot11ReasonClass3FromNonAss:
		return "Class3 from non ass."
	case Dot11ReasonDisasStLeaving:
		return "Disass st. leaving"
	case Dot11ReasonStNotAuth:
		return "St. not auth."
	default:
		return "Unknown reason"
	}
}

type Dot11Status uint16

const (
	Dot11StatusSuccess                      Dot11Status = 0
	Dot11StatusFailure                      Dot11Status = 1  // Unspecified failure
	Dot11StatusCannotSupportAllCapabilities Dot11Status = 10 // Cannot support all requested capabilities in the Capability Information field
	Dot11StatusInabilityExistsAssociation   Dot11Status = 11 // Reassociation denied due to inability to confirm that association exists
	Dot11StatusAssociationDenied            Dot11Status = 12 // Association denied due to reason outside the scope of this standard
	Dot11StatusAlgorithmUnsupported         Dot11Status = 13 // Responding station does not support the specified authentication algorithm
	Dot11StatusOufOfExpectedSequence        Dot11Status = 14 // Received an Authentication frame with authentication transaction sequence number out of expected sequence
	Dot11StatusChallengeFailure             Dot11Status = 15 // Authentication rejected because of challenge failure
	Dot11StatusTimeout                      Dot11Status = 16 // Authentication rejected due to timeout waiting for next frame in sequence
	Dot11StatusAPUnableToHandle             Dot11Status = 17 // Association denied because AP is unable to handle additional associated stations
	Dot11StatusRateUnsupported              Dot11Status = 18 // Association denied due to requesting station not supporting all of the data rates in the BSSBasicRateSet parameter
)

// String provides a human readable string for Dot11Status.
// This string is possibly subject to change over time; if you're storing this
// persistently, you should probably store the Dot11Status value, not its string.
func (a Dot11Status) String() string {
	switch a {
	case Dot11StatusSuccess:
		return "success"
	case Dot11StatusFailure:
		return "failure"
	case Dot11StatusCannotSupportAllCapabilities:
		return "cannot-support-all-capabilities"
	case Dot11StatusInabilityExistsAssociation:
		return "inability-exists-association"
	case Dot11StatusAssociationDenied:
		return "association-denied"
	case Dot11StatusAlgorithmUnsupported:
		return "algorithm-unsupported"
	case Dot11StatusOufOfExpectedSequence:
		return "out-of-expected-sequence"
	case Dot11StatusChallengeFailure:
		return "challenge-failure"
	case Dot11StatusTimeout:
		return "timeout"
	case Dot11StatusAPUnableToHandle:
		return "ap-unable-to-handle"
	case Dot11StatusRateUnsupported:
		return "rate-unsupported"
	default:
		return "unknown status"
	}
}

type Dot11AckPolicy uint8

const (
	Dot11AckPolicyNormal     Dot11AckPolicy = 0
	Dot11AckPolicyNone       Dot11AckPolicy = 1
	Dot11AckPolicyNoExplicit Dot11AckPolicy = 2
	Dot11AckPolicyBlock      Dot11AckPolicy = 3
)

// String provides a human readable string for Dot11AckPolicy.
// This string is possibly subject to change over time; if you're storing this
// persistently, you should probably store the Dot11AckPolicy value, not its string.
func (a Dot11AckPolicy) String() string {
	switch a {
	case Dot11AckPolicyNormal:
		return "normal-ack"
	case Dot11AckPolicyNone:
		return "no-ack"
	case Dot11AckPolicyNoExplicit:
		return "no-explicit-ack"
	case Dot11AckPolicyBlock:
		return "block-ack"
	default:
		return "unknown-ack-policy"
	}
}

type Dot11Algorithm uint16

const (
	Dot11AlgorithmOpen      Dot11Algorithm = 0
	Dot11AlgorithmSharedKey Dot11Algorithm = 1
)

// String provides a human readable string for Dot11Algorithm.
// This string is possibly subject to change over time; if you're storing this
// persistently, you should probably store the Dot11Algorithm value, not its string.
func (a Dot11Algorithm) String() string {
	switch a {
	case Dot11AlgorithmOpen:
		return "open"
	case Dot11AlgorithmSharedKey:
		return "shared-key"
	default:
		return "unknown-algorithm"
	}
}

type Dot11InformationElementID uint8

const (
	Dot11InformationElementIDSSID                      Dot11InformationElementID = 0
	Dot11InformationElementIDRates                     Dot11InformationElementID = 1
	Dot11InformationElementIDFHSet                     Dot11InformationElementID = 2
	Dot11InformationElementIDDSSet                     Dot11InformationElementID = 3
	Dot11InformationElementIDCFSet                     Dot11InformationElementID = 4
	Dot11InformationElementIDTIM                       Dot11InformationElementID = 5
	Dot11InformationElementIDIBSSSet                   Dot11InformationElementID = 6
	Dot11InformationElementIDCountryInfo               Dot11InformationElementID = 7
	Dot11InformationElementIDHoppingPatternParam       Dot11InformationElementID = 8
	Dot11InformationElementIDHoppingPatternTable       Dot11InformationElementID = 9
	Dot11InformationElementIDRequest                   Dot11InformationElementID = 10
	Dot11InformationElementIDQBSSLoadElem              Dot11InformationElementID = 11
	Dot11InformationElementIDEDCAParamSet              Dot11InformationElementID = 12
	Dot11InformationElementIDTrafficSpec               Dot11InformationElementID = 13
	Dot11InformationElementIDTrafficClass              Dot11InformationElementID = 14
	Dot11InformationElementIDSchedule                  Dot11InformationElementID = 15
	Dot11InformationElementIDChallenge                 Dot11InformationElementID = 16
	Dot11InformationElementIDPowerConst                Dot11InformationElementID = 32
	Dot11InformationElementIDPowerCapability           Dot11InformationElementID = 33
	Dot11InformationElementIDTPCRequest                Dot11InformationElementID = 34
	Dot11InformationElementIDTPCReport                 Dot11InformationElementID = 35
	Dot11InformationElementIDSupportedChannels         Dot11InformationElementID = 36
	Dot11InformationElementIDSwitchChannelAnnounce     Dot11InformationElementID = 37
	Dot11InformationElementIDMeasureRequest            Dot11InformationElementID = 38
	Dot11InformationElementIDMeasureReport             Dot11InformationElementID = 39
	Dot11InformationElementIDQuiet                     Dot11InformationElementID = 40
	Dot11InformationElementIDIBSSDFS                   Dot11InformationElementID = 41
	Dot11InformationElementIDERPInfo                   Dot11InformationElementID = 42
	Dot11InformationElementIDTSDelay                   Dot11InformationElementID = 43
	Dot11InformationElementIDTCLASProcessing           Dot11InformationElementID = 44
	Dot11InformationElementIDHTCapabilities            Dot11InformationElementID = 45
	Dot11InformationElementIDQOSCapability             Dot11InformationElementID = 46
	Dot11InformationElementIDERPInfo2                  Dot11InformationElementID = 47
	Dot11InformationElementIDRSNInfo                   Dot11InformationElementID = 48
	Dot11InformationElementIDESRates                   Dot11InformationElementID = 50
	Dot11InformationElementIDAPChannelReport           Dot11InformationElementID = 51
	Dot11InformationElementIDNeighborReport            Dot11InformationElementID = 52
	Dot11InformationElementIDRCPI                      Dot11InformationElementID = 53
	Dot11InformationElementIDMobilityDomain            Dot11InformationElementID = 54
	Dot11InformationElementIDFastBSSTrans              Dot11InformationElementID = 55
	Dot11InformationElementIDTimeoutInt                Dot11InformationElementID = 56
	Dot11InformationElementIDRICData                   Dot11InformationElementID = 57
	Dot11InformationElementIDDSERegisteredLoc          Dot11InformationElementID = 58
	Dot11InformationElementIDSuppOperatingClass        Dot11InformationElementID = 59
	Dot11InformationElementIDExtChanSwitchAnnounce     Dot11InformationElementID = 60
	Dot11InformationElementIDHTInfo                    Dot11InformationElementID = 61
	Dot11InformationElementIDSecChanOffset             Dot11InformationElementID = 62
	Dot11InformationElementIDBSSAverageAccessDelay     Dot11InformationElementID = 63
	Dot11InformationElementIDAntenna                   Dot11InformationElementID = 64
	Dot11InformationElementIDRSNI                      Dot11InformationElementID = 65
	Dot11InformationElementIDMeasurePilotTrans         Dot11InformationElementID = 66
	Dot11InformationElementIDBSSAvailAdmCapacity       Dot11InformationElementID = 67
	Dot11InformationElementIDBSSACAccDelayWAPIParam    Dot11InformationElementID = 68
	Dot11InformationElementIDTimeAdvertisement         Dot11InformationElementID = 69
	Dot11InformationElementIDRMEnabledCapabilities     Dot11InformationElementID = 70
	Dot11InformationElementIDMultipleBSSID             Dot11InformationElementID = 71
	Dot11InformationElementID2040BSSCoExist            Dot11InformationElementID = 72
	Dot11InformationElementID2040BSSIntChanReport      Dot11InformationElementID = 73
	Dot11InformationElementIDOverlapBSSScanParam       Dot11InformationElementID = 74
	Dot11InformationElementIDRICDescriptor             Dot11InformationElementID = 75
	Dot11InformationElementIDManagementMIC             Dot11InformationElementID = 76
	Dot11InformationElementIDEventRequest              Dot11InformationElementID = 78
	Dot11InformationElementIDEventReport               Dot11InformationElementID = 79
	Dot11InformationElementIDDiagnosticRequest         Dot11InformationElementID = 80
	Dot11InformationElementIDDiagnosticReport          Dot11InformationElementID = 81
	Dot11InformationElementIDLocationParam             Dot11InformationElementID = 82
	Dot11InformationElementIDNonTransBSSIDCapability   Dot11InformationElementID = 83
	Dot11InformationElementIDSSIDList                  Dot11InformationElementID = 84
	Dot11InformationElementIDMultipleBSSIDIndex        Dot11InformationElementID = 85
	Dot11InformationElementIDFMSDescriptor             Dot11InformationElementID = 86
	Dot11InformationElementIDFMSRequest                Dot11InformationElementID = 87
	Dot11InformationElementIDFMSResponse               Dot11InformationElementID = 88
	Dot11InformationElementIDQOSTrafficCapability      Dot11InformationElementID = 89
	Dot11InformationElementIDBSSMaxIdlePeriod          Dot11InformationElementID = 90
	Dot11InformationElementIDTFSRequest                Dot11InformationElementID = 91
	Dot11InformationElementIDTFSResponse               Dot11InformationElementID = 92
	Dot11InformationElementIDWNMSleepMode              Dot11InformationElementID = 93
	Dot11InformationElementIDTIMBroadcastRequest       Dot11InformationElementID = 94
	Dot11InformationElementIDTIMBroadcastResponse      Dot11InformationElementID = 95
	Dot11InformationElementIDCollInterferenceReport    Dot11InformationElementID = 96
	Dot11InformationElementIDChannelUsage              Dot11InformationElementID = 97
	Dot11InformationElementIDTimeZone                  Dot11InformationElementID = 98
	Dot11InformationElementIDDMSRequest                Dot11InformationElementID = 99
	Dot11InformationElementIDDMSResponse               Dot11InformationElementID = 100
	Dot11InformationElementIDLinkIdentifier            Dot11InformationElementID = 101
	Dot11InformationElementIDWakeupSchedule            Dot11InformationElementID = 102
	Dot11InformationElementIDChannelSwitchTiming       Dot11InformationElementID = 104
	Dot11InformationElementIDPTIControl                Dot11InformationElementID = 105
	Dot11InformationElementIDPUBufferStatus            Dot11InformationElementID = 106
	Dot11InformationElementIDInterworking              Dot11InformationElementID = 107
	Dot11InformationElementIDAdvertisementProtocol     Dot11InformationElementID = 108
	Dot11InformationElementIDExpBWRequest              Dot11InformationElementID = 109
	Dot11InformationElementIDQOSMapSet                 Dot11InformationElementID = 110
	Dot11InformationElementIDRoamingConsortium         Dot11InformationElementID = 111
	Dot11InformationElementIDEmergencyAlertIdentifier  Dot11InformationElementID = 112
	Dot11InformationElementIDMeshConfiguration         Dot11InformationElementID = 113
	Dot11InformationElementIDMeshID                    Dot11InformationElementID = 114
	Dot11InformationElementIDMeshLinkMetricReport      Dot11InformationElementID = 115
	Dot11InformationElementIDCongestionNotification    Dot11InformationElementID = 116
	Dot11InformationElementIDMeshPeeringManagement     Dot11InformationElementID = 117
	Dot11InformationElementIDMeshChannelSwitchParam    Dot11InformationElementID = 118
	Dot11InformationElementIDMeshAwakeWindows          Dot11InformationElementID = 119
	Dot11InformationElementIDBeaconTiming              Dot11InformationElementID = 120
	Dot11InformationElementIDMCCAOPSetupRequest        Dot11InformationElementID = 121
	Dot11InformationElementIDMCCAOPSetupReply          Dot11InformationElementID = 122
	Dot11InformationElementIDMCCAOPAdvertisement       Dot11InformationElementID = 123
	Dot11InformationElementIDMCCAOPTeardown            Dot11InformationElementID = 124
	Dot11InformationElementIDGateAnnouncement          Dot11InformationElementID = 125
	Dot11InformationElementIDRootAnnouncement          Dot11InformationElementID = 126
	Dot11InformationElementIDExtCapability             Dot11InformationElementID = 127
	Dot11InformationElementIDAgereProprietary          Dot11InformationElementID = 128
	Dot11InformationElementIDPathRequest               Dot11InformationElementID = 130
	Dot11InformationElementIDPathReply                 Dot11InformationElementID = 131
	Dot11InformationElementIDPathError                 Dot11InformationElementID = 132
	Dot11InformationElementIDCiscoCCX1CKIPDeviceName   Dot11InformationElementID = 133
	Dot11InformationElementIDCiscoCCX2                 Dot11InformationElementID = 136
	Dot11InformationElementIDProxyUpdate               Dot11InformationElementID = 137
	Dot11InformationElementIDProxyUpdateConfirmation   Dot11InformationElementID = 138
	Dot11InformationElementIDAuthMeshPerringExch       Dot11InformationElementID = 139
	Dot11InformationElementIDMIC                       Dot11InformationElementID = 140
	Dot11InformationElementIDDestinationURI            Dot11InformationElementID = 141
	Dot11InformationElementIDUAPSDCoexistence          Dot11InformationElementID = 142
	Dot11InformationElementIDWakeupSchedule80211ad     Dot11InformationElementID = 143
	Dot11InformationElementIDExtendedSchedule          Dot11InformationElementID = 144
	Dot11InformationElementIDSTAAvailability           Dot11InformationElementID = 145
	Dot11InformationElementIDDMGTSPEC                  Dot11InformationElementID = 146
	Dot11InformationElementIDNextDMGATI                Dot11InformationElementID = 147
	Dot11InformationElementIDDMSCapabilities           Dot11InformationElementID = 148
	Dot11InformationElementIDCiscoUnknown95            Dot11InformationElementID = 149
	Dot11InformationElementIDVendor2                   Dot11InformationElementID = 150
	Dot11InformationElementIDDMGOperating              Dot11InformationElementID = 151
	Dot11InformationElementIDDMGBSSParamChange         Dot11InformationElementID = 152
	Dot11InformationElementIDDMGBeamRefinement         Dot11InformationElementID = 153
	Dot11InformationElementIDChannelMeasFeedback       Dot11InformationElementID = 154
	Dot11InformationElementIDAwakeWindow               Dot11InformationElementID = 157
	Dot11InformationElementIDMultiBand                 Dot11InformationElementID = 158
	Dot11InformationElementIDADDBAExtension            Dot11InformationElementID = 159
	Dot11InformationElementIDNEXTPCPList               Dot11InformationElementID = 160
	Dot11InformationElementIDPCPHandover               Dot11InformationElementID = 161
	Dot11InformationElementIDDMGLinkMargin             Dot11InformationElementID = 162
	Dot11InformationElementIDSwitchingStream           Dot11InformationElementID = 163
	Dot11InformationElementIDSessionTransmission       Dot11InformationElementID = 164
	Dot11InformationElementIDDynamicTonePairReport     Dot11InformationElementID = 165
	Dot11InformationElementIDClusterReport             Dot11InformationElementID = 166
	Dot11InformationElementIDRelayCapabilities         Dot11InformationElementID = 167
	Dot11InformationElementIDRelayTransferParameter    Dot11InformationElementID = 168
	Dot11InformationElementIDBeamlinkMaintenance       Dot11InformationElementID = 169
	Dot11InformationElementIDMultipleMacSublayers      Dot11InformationElementID = 170
	Dot11InformationElementIDUPID                      Dot11InformationElementID = 171
	Dot11InformationElementIDDMGLinkAdaptionAck        Dot11InformationElementID = 172
	Dot11InformationElementIDSymbolProprietary         Dot11InformationElementID = 173
	Dot11InformationElementIDMCCAOPAdvertOverview      Dot11InformationElementID = 174
	Dot11InformationElementIDQuietPeriodRequest        Dot11InformationElementID = 175
	Dot11InformationElementIDQuietPeriodResponse       Dot11InformationElementID = 177
	Dot11InformationElementIDECPACPolicy               Dot11InformationElementID = 182
	Dot11InformationElementIDClusterTimeOffset         Dot11InformationElementID = 183
	Dot11InformationElementIDAntennaSectorID           Dot11InformationElementID = 190
	Dot11InformationElementIDVHTCapabilities           Dot11InformationElementID = 191
	Dot11InformationElementIDVHTOperation              Dot11InformationElementID = 192
	Dot11InformationElementIDExtendedBSSLoad           Dot11InformationElementID = 193
	Dot11InformationElementIDWideBWChannelSwitch       Dot11InformationElementID = 194
	Dot11InformationElementIDVHTTxPowerEnvelope        Dot11InformationElementID = 195
	Dot11InformationElementIDChannelSwitchWrapper      Dot11InformationElementID = 196
	Dot11InformationElementIDOperatingModeNotification Dot11InformationElementID = 199
	Dot11InformationElementIDUPSIM                     Dot11InformationElementID = 200
	Dot11InformationElementIDReducedNeighborReport     Dot11InformationElementID = 201
	Dot11InformationElementIDTVHTOperation             Dot11InformationElementID = 202
	Dot11InformationElementIDDeviceLocation            Dot11InformationElementID = 204
	Dot11InformationElementIDWhiteSpaceMap             Dot11InformationElementID = 205
	Dot11InformationElementIDFineTuningMeasureParams   Dot11InformationElementID = 206
	Dot11InformationElementIDVendor                    Dot11InformationElementID = 221
)

// String provides a human readable string for Dot11InformationElementID.
// This string is possibly subject to change over time; if you're storing this
// persistently, you should probably store the Dot11InformationElementID value,
// not its string.
func (a Dot11InformationElementID) String() string {
	switch a {
	case Dot11InformationElementIDSSID:
		return "SSID parameter set"
	case Dot11InformationElementIDRates:
		return "Supported Rates"
	case Dot11InformationElementIDFHSet:
		return "FH Parameter set"
	case Dot11InformationElementIDDSSet:
		return "DS Parameter set"
	case Dot11InformationElementIDCFSet:
		return "CF Parameter set"
	case Dot11InformationElementIDTIM:
		return "Traffic Indication Map (TIM)"
	case Dot11InformationElementIDIBSSSet:
		return "IBSS Parameter set"
	case Dot11InformationElementIDCountryInfo:
		return "Country Information"
	case Dot11InformationElementIDHoppingPatternParam:
		return "Hopping Pattern Parameters"
	case Dot11InformationElementIDHoppingPatternTable:
		return "Hopping Pattern Table"
	case Dot11InformationElementIDRequest:
		return "Request"
	case Dot11InformationElementIDQBSSLoadElem:
		return "QBSS Load Element"
	case Dot11InformationElementIDEDCAParamSet:
		return "EDCA Parameter Set"
	case Dot11InformationElementIDTrafficSpec:
		return "Traffic Specification"
	case Dot11InformationElementIDTrafficClass:
		return "Traffic Classification"
	case Dot11InformationElementIDSchedule:
		return "Schedule"
	case Dot11InformationElementIDChallenge:
		return "Challenge text"
	case Dot11InformationElementIDPowerConst:
		return "Power Constraint"
	case Dot11InformationElementIDPowerCapability:
		return "Power Capability"
	case Dot11InformationElementIDTPCRequest:
		return "TPC Request"
	case Dot11InformationElementIDTPCReport:
		return "TPC Report"
	case Dot11InformationElementIDSupportedChannels:
		return "Supported Channels"
	case Dot11InformationElementIDSwitchChannelAnnounce:
		return "Channel Switch Announcement"
	case Dot11InformationElementIDMeasureRequest:
		return "Measurement Request"
	case Dot11InformationElementIDMeasureReport:
		return "Measurement Report"
	case Dot11InformationElementIDQuiet:
		return "Quiet"
	case Dot11InformationElementIDIBSSDFS:
		return "IBSS DFS"
	case Dot11InformationElementIDERPInfo:
		return "ERP Information"
	case Dot11InformationElementIDTSDelay:
		return "TS Delay"
	case Dot11InformationElementIDTCLASProcessing:
		return "TCLAS Processing"
	case Dot11InformationElementIDHTCapabilities:
		return "HT Capabilities (802.11n D1.10)"
	case Dot11InformationElementIDQOSCapability:
		return "QOS Capability"
	case Dot11InformationElementIDERPInfo2:
		return "ERP Information-2"
	case Dot11InformationElementIDRSNInfo:
		return "RSN Information"
	case Dot11InformationElementIDESRates:
		return "Extended Supported Rates"
	case Dot11InformationElementIDAPChannelReport:
		return "AP Channel Report"
	case Dot11InformationElementIDNeighborReport:
		return "Neighbor Report"
	case Dot11InformationElementIDRCPI:
		return "RCPI"
	case Dot11InformationElementIDMobilityDomain:
		return "Mobility Domain"
	case Dot11InformationElementIDFastBSSTrans:
		return "Fast BSS Transition"
	case Dot11InformationElementIDTimeoutInt:
		return "Timeout Interval"
	case Dot11InformationElementIDRICData:
		return "RIC Data"
	case Dot11InformationElementIDDSERegisteredLoc:
		return "DSE Registered Location"
	case Dot11InformationElementIDSuppOperatingClass:
		return "Supported Operating Classes"
	case Dot11InformationElementIDExtChanSwitchAnnounce:
		return "Extended Channel Switch Announcement"
	case Dot11InformationElementIDHTInfo:
		return "HT Information (802.11n D1.10)"
	case Dot11InformationElementIDSecChanOffset:
		return "Secondary Channel Offset (802.11n D1.10)"
	case Dot11InformationElementIDBSSAverageAccessDelay:
		return "BSS Average Access Delay"
	case Dot11InformationElementIDAntenna:
		return "Antenna"
	case Dot11InformationElementIDRSNI:
		return "RSNI"
	case Dot11InformationElementIDMeasurePilotTrans:
		return "Measurement Pilot Transmission"
	case Dot11InformationElementIDBSSAvailAdmCapacity:
		return "BSS Available Admission Capacity"
	case Dot11InformationElementIDBSSACAccDelayWAPIParam:
		return "BSS AC Access Delay/WAPI Parameter Set"
	case Dot11InformationElementIDTimeAdvertisement:
		return "Time Advertisement"
	case Dot11InformationElementIDRMEnabledCapabilities:
		return "RM Enabled Capabilities"
	case Dot11InformationElementIDMultipleBSSID:
		return "Multiple BSSID"
	case Dot11InformationElementID2040BSSCoExist:
		return "20/40 BSS Coexistence"
	case Dot11InformationElementID2040BSSIntChanReport:
		return "20/40 BSS Intolerant Channel Report"
	case Dot11InformationElementIDOverlapBSSScanParam:
		return "Overlapping BSS Scan Parameters"
	case Dot11InformationElementIDRICDescriptor:
		return "RIC Descriptor"
	case Dot11InformationElementIDManagementMIC:
		return "Management MIC"
	case Dot11InformationElementIDEventRequest:
		return "Event Request"
	case Dot11InformationElementIDEventReport:
		return "Event Report"
	case Dot11InformationElementIDDiagnosticRequest:
		return "Diagnostic Request"
	case Dot11InformationElementIDDiagnosticReport:
		return "Diagnostic Report"
	case Dot11InformationElementIDLocationParam:
		return "Location Parameters"
	case Dot11InformationElementIDNonTransBSSIDCapability:
		return "Non Transmitted BSSID Capability"
	case Dot11InformationElementIDSSIDList:
		return "SSID List"
	case Dot11InformationElementIDMultipleBSSIDIndex:
		return "Multiple BSSID Index"
	case Dot11InformationElementIDFMSDescriptor:
		return "FMS Descriptor"
	case Dot11InformationElementIDFMSRequest:
		return "FMS Request"
	case Dot11InformationElementIDFMSResponse:
		return "FMS Response"
	case Dot11InformationElementIDQOSTrafficCapability:
		return "QoS Traffic Capability"
	case Dot11InformationElementIDBSSMaxIdlePeriod:
		return "BSS Max Idle Period"
	case Dot11InformationElementIDTFSRequest:
		return "TFS Request"
	case Dot11InformationElementIDTFSResponse:
		return "TFS Response"
	case Dot11InformationElementIDWNMSleepMode:
		return "WNM-Sleep Mode"
	case Dot11InformationElementIDTIMBroadcastRequest:
		return "TIM Broadcast Request"
	case Dot11InformationElementIDTIMBroadcastResponse:
		return "TIM Broadcast Response"
	case Dot11InformationElementIDCollInterferenceReport:
		return "Collocated Interference Report"
	case Dot11InformationElementIDChannelUsage:
		return "Channel Usage"
	case Dot11InformationElementIDTimeZone:
		return "Time Zone"
	case Dot11InformationElementIDDMSRequest:
		return "DMS Request"
	case Dot11InformationElementIDDMSResponse:
		return "DMS Response"
	case Dot11InformationElementIDLinkIdentifier:
		return "Link Identifier"
	case Dot11InformationElementIDWakeupSchedule:
		return "Wakeup Schedule"
	case Dot11InformationElementIDChannelSwitchTiming:
		return "Channel Switch Timing"
	case Dot11InformationElementIDPTIControl:
		return "PTI Control"
	case Dot11InformationElementIDPUBufferStatus:
		return "PU Buffer Status"
	case Dot11InformationElementIDInterworking:
		return "Interworking"
	case Dot11InformationElementIDAdvertisementProtocol:
		return "Advertisement Protocol"
	case Dot11InformationElementIDExpBWRequest:
		return "Expedited Bandwidth Request"
	case Dot11InformationElementIDQOSMapSet:
		return "QoS Map Set"
	case Dot11InformationElementIDRoamingConsortium:
		return "Roaming Consortium"
	case Dot11InformationElementIDEmergencyAlertIdentifier:
		return "Emergency Alert Identifier"
	case Dot11InformationElementIDMeshConfiguration:
		return "Mesh Configuration"
	case Dot11InformationElementIDMeshID:
		return "Mesh ID"
	case Dot11InformationElementIDMeshLinkMetricReport:
		return "Mesh Link Metric Report"
	case Dot11InformationElementIDCongestionNotification:
		return "Congestion Notification"
	case Dot11InformationElementIDMeshPeeringManagement:
		return "Mesh Peering Management"
	case Dot11InformationElementIDMeshChannelSwitchParam:
		return "Mesh Channel Switch Parameters"
	case Dot11InformationElementIDMeshAwakeWindows:
		return "Mesh Awake Windows"
	case Dot11InformationElementIDBeaconTiming:
		return "Beacon Timing"
	case Dot11InformationElementIDMCCAOPSetupRequest:
		return "MCCAOP Setup Request"
	case Dot11InformationElementIDMCCAOPSetupReply:
		return "MCCAOP SETUP Reply"
	case Dot11InformationElementIDMCCAOPAdvertisement:
		return "MCCAOP Advertisement"
	case Dot11InformationElementIDMCCAOPTeardown:
		return "MCCAOP Teardown"
	case Dot11InformationElementIDGateAnnouncement:
		return "Gate Announcement"
	case Dot11InformationElementIDRootAnnouncement:
		return "Root Announcement"
	case Dot11InformationElementIDExtCapability:
		return "Extended Capabilities"
	case Dot11InformationElementIDAgereProprietary:
		return "Agere Proprietary"
	case Dot11InformationElementIDPathRequest:
		return "Path Request"
	case Dot11InformationElementIDPathReply:
		return "Path Reply"
	case Dot11InformationElementIDPathError:
		return "Path Error"
	case Dot11InformationElementIDCiscoCCX1CKIPDeviceName:
		return "Cisco CCX1 CKIP + Device Name"
	case Dot11InformationElementIDCiscoCCX2:
		return "Cisco CCX2"
	case Dot11InformationElementIDProxyUpdate:
		return "Proxy Update"
	case Dot11InformationElementIDProxyUpdateConfirmation:
		return "Proxy Update Confirmation"
	case Dot11InformationElementIDAuthMeshPerringExch:
		return "Auhenticated Mesh Perring Exchange"
	case Dot11InformationElementIDMIC:
		return "MIC (Message Integrity Code)"
	case Dot11InformationElementIDDestinationURI:
		return "Destination URI"
	case Dot11InformationElementIDUAPSDCoexistence:
		return "U-APSD Coexistence"
	case Dot11InformationElementIDWakeupSchedule80211ad:
		return "Wakeup Schedule 802.11ad"
	case Dot11InformationElementIDExtendedSchedule:
		return "Extended Schedule"
	case Dot11InformationElementIDSTAAvailability:
		return "STA Availability"
	case Dot11InformationElementIDDMGTSPEC:
		return "DMG TSPEC"
	case Dot11InformationElementIDNextDMGATI:
		return "Next DMG ATI"
	case Dot11InformationElementIDDMSCapabilities:
		return "DMG Capabilities"
	case Dot11InformationElementIDCiscoUnknown95:
		return "Cisco Unknown 95"
	case Dot11InformationElementIDVendor2:
		return "Vendor Specific"
	case Dot11InformationElementIDDMGOperating:
		return "DMG Operating"
	case Dot11InformationElementIDDMGBSSParamChange:
		return "DMG BSS Parameter Change"
	case Dot11InformationElementIDDMGBeamRefinement:
		return "DMG Beam Refinement"
	case Dot11InformationElementIDChannelMeasFeedback:
		return "Channel Measurement Feedback"
	case Dot11InformationElementIDAwakeWindow:
		return "Awake Window"
	case Dot11InformationElementIDMultiBand:
		return "Multi Band"
	case Dot11InformationElementIDADDBAExtension:
		return "ADDBA Extension"
	case Dot11InformationElementIDNEXTPCPList:
		return "NEXTPCP List"
	case Dot11InformationElementIDPCPHandover:
		return "PCP Handover"
	case Dot11InformationElementIDDMGLinkMargin:
		return "DMG Link Margin"
	case Dot11InformationElementIDSwitchingStream:
		return "Switching Stream"
	case Dot11InformationElementIDSessionTransmission:
		return "Session Transmission"
	case Dot11InformationElementIDDynamicTonePairReport:
		return "Dynamic Tone Pairing Report"
	case Dot11InformationElementIDClusterReport:
		return "Cluster Report"
	case Dot11InformationElementIDRelayCapabilities:
		return "Relay Capabilities"
	case Dot11InformationElementIDRelayTransferParameter:
		return "Relay Transfer Parameter"
	case Dot11InformationElementIDBeamlinkMaintenance:
		return "Beamlink Maintenance"
	case Dot11InformationElementIDMultipleMacSublayers:
		return "Multiple MAC Sublayers"
	case Dot11InformationElementIDUPID:
		return "U-PID"
	case Dot11InformationElementIDDMGLinkAdaptionAck:
		return "DMG Link Adaption Acknowledgment"
	case Dot11InformationElementIDSymbolProprietary:
		return "Symbol Proprietary"
	case Dot11InformationElementIDMCCAOPAdvertOverview:
		return "MCCAOP Advertisement Overview"
	case Dot11InformationElementIDQuietPeriodRequest:
		return "Quiet Period Request"
	case Dot11InformationElementIDQuietPeriodResponse:
		return "Quiet Period Response"
	case Dot11InformationElementIDECPACPolicy:
		return "ECPAC Policy"
	case Dot11InformationElementIDClusterTimeOffset:
		return "Cluster Time Offset"
	case Dot11InformationElementIDAntennaSectorID:
		return "Antenna Sector ID"
	case Dot11InformationElementIDVHTCapabilities:
		return "VHT Capabilities (IEEE Std 802.11ac/D3.1)"
	case Dot11InformationElementIDVHTOperation:
		return "VHT Operation (IEEE Std 802.11ac/D3.1)"
	case Dot11InformationElementIDExtendedBSSLoad:
		return "Extended BSS Load"
	case Dot11InformationElementIDWideBWChannelSwitch:
		return "Wide Bandwidth Channel Switch"
	case Dot11InformationElementIDVHTTxPowerEnvelope:
		return "VHT Tx Power Envelope (IEEE Std 802.11ac/D5.0)"
	case Dot11InformationElementIDChannelSwitchWrapper:
		return "Channel Switch Wrapper"
	case Dot11InformationElementIDOperatingModeNotification:
		return "Operating Mode Notification"
	case Dot11InformationElementIDUPSIM:
		return "UP SIM"
	case Dot11InformationElementIDReducedNeighborReport:
		return "Reduced Neighbor Report"
	case Dot11InformationElementIDTVHTOperation:
		return "TVHT Op"
	case Dot11InformationElementIDDeviceLocation:
		return "Device Location"
	case Dot11InformationElementIDWhiteSpaceMap:
		return "White Space Map"
	case Dot11InformationElementIDFineTuningMeasureParams:
		return "Fine Tuning Measure Parameters"
	case Dot11InformationElementIDVendor:
		return "Vendor"
	default:
		return "Unknown information element id"
	}
}

// Dot11 provides an IEEE 802.11 base packet header.
// See http://standards.ieee.org/findstds/standard/802.11-2012.html
// for excruciating detail.
type Dot11 struct {
	BaseLayer
	Type           Dot11Type
	Proto          uint8
	Flags          Dot11Flags
	DurationID     uint16
	Address1       net.HardwareAddr
	Address2       net.HardwareAddr
	Address3       net.HardwareAddr
	Address4       net.HardwareAddr
	SequenceNumber uint16
	FragmentNumber uint16
	Checksum       uint32
	QOS            *Dot11QOS
	HTControl      *Dot11HTControl
	DataLayer      gopacket.Layer
}

type Dot11QOS struct {
	TID       uint8 /* Traffic IDentifier */
	EOSP      bool  /* End of service period */
	AckPolicy Dot11AckPolicy
	TXOP      uint8
}

type Dot11HTControl struct {
	ACConstraint bool
	RDGMorePPDU  bool

	VHT *Dot11HTControlVHT
	HT  *Dot11HTControlHT
}

type Dot11HTControlHT struct {
	LinkAdapationControl *Dot11LinkAdapationControl
	CalibrationPosition  uint8
	CalibrationSequence  uint8
	CSISteering          uint8
	NDPAnnouncement      bool
	DEI                  bool
}

type Dot11HTControlVHT struct {
	MRQ            bool
	UnsolicitedMFB bool
	MSI            *uint8
	MFB            Dot11HTControlMFB
	CompressedMSI  *uint8
	STBCIndication bool
	MFSI           *uint8
	GID            *uint8
	CodingType     *Dot11CodingType
	FbTXBeamformed bool
}

type Dot11HTControlMFB struct {
	NumSTS uint8
	VHTMCS uint8
	BW     uint8
	SNR    int8
}

type Dot11LinkAdapationControl struct {
	TRQ  bool
	MRQ  bool
	MSI  uint8
	MFSI uint8
	ASEL *Dot11ASEL
	MFB  *uint8
}

type Dot11ASEL struct {
	Command uint8
	Data    uint8
}

type Dot11CodingType uint8

const (
	Dot11CodingTypeBCC  = 0
	Dot11CodingTypeLDPC = 1
)

func (a Dot11CodingType) String() string {
	switch a {
	case Dot11CodingTypeBCC:
		return "BCC"
	case Dot11CodingTypeLDPC:
		return "LDPC"
	default:
		return "Unknown coding type"
	}
}

func (m *Dot11HTControlMFB) NoFeedBackPresent() bool {
	return m.VHTMCS == 15 && m.NumSTS == 7
}

func decodeDot11(data []byte, p gopacket.PacketBuilder) error {
	d := &Dot11{}
	err := d.DecodeFromBytes(data, p)
	if err != nil {
		return err
	}
	p.AddLayer(d)
	if d.DataLayer != nil {
		p.AddLayer(d.DataLayer)
	}
	return p.NextDecoder(d.NextLayerType())
}

func (m *Dot11) LayerType() gopacket.LayerType  { return LayerTypeDot11 }
func (m *Dot11) CanDecode() gopacket.LayerClass { return LayerTypeDot11 }
func (m *Dot11) NextLayerType() gopacket.LayerType {
	if m.DataLayer != nil {
		if m.Flags.WEP() {
			return LayerTypeDot11WEP
		}
		return m.DataLayer.(gopacket.DecodingLayer).NextLayerType()
	}
	return m.Type.LayerType()
}

func createU8(x uint8) *uint8 {
	return &x
}

var dataDecodeMap = map[Dot11Type]func() gopacket.DecodingLayer{
	Dot11TypeData:                   func() gopacket.DecodingLayer { return &Dot11Data{} },
	Dot11TypeDataCFAck:              func() gopacket.DecodingLayer { return &Dot11DataCFAck{} },
	Dot11TypeDataCFPoll:             func() gopacket.DecodingLayer { return &Dot11DataCFPoll{} },
	Dot11TypeDataCFAckPoll:          func() gopacket.DecodingLayer { return &Dot11DataCFAckPoll{} },
	Dot11TypeDataNull:               func() gopacket.DecodingLayer { return &Dot11DataNull{} },
	Dot11TypeDataCFAckNoData:        func() gopacket.DecodingLayer { return &Dot11DataCFAckNoData{} },
	Dot11TypeDataCFPollNoData:       func() gopacket.DecodingLayer { return &Dot11DataCFPollNoData{} },
	Dot11TypeDataCFAckPollNoData:    func() gopacket.DecodingLayer { return &Dot11DataCFAckPollNoData{} },
	Dot11TypeDataQOSData:            func() gopacket.DecodingLayer { return &Dot11DataQOSData{} },
	Dot11TypeDataQOSDataCFAck:       func() gopacket.DecodingLayer { return &Dot11DataQOSDataCFAck{} },
	Dot11TypeDataQOSDataCFPoll:      func() gopacket.DecodingLayer { return &Dot11DataQOSDataCFPoll{} },
	Dot11TypeDataQOSDataCFAckPoll:   func() gopacket.DecodingLayer { return &Dot11DataQOSDataCFAckPoll{} },
	Dot11TypeDataQOSNull:            func() gopacket.DecodingLayer { return &Dot11DataQOSNull{} },
	Dot11TypeDataQOSCFPollNoData:    func() gopacket.DecodingLayer { return &Dot11DataQOSCFPollNoData{} },
	Dot11TypeDataQOSCFAckPollNoData: func() gopacket.DecodingLayer { return &Dot11DataQOSCFAckPollNoData{} },
}

func (m *Dot11) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
	if len(data) < 10 {
		df.SetTruncated()
		return fmt.Errorf("Dot11 length %v too short, %v required", len(data), 10)
	}
	m.Type = Dot11Type((data[0])&0xFC) >> 2

	m.DataLayer = nil
	m.Proto = uint8(data[0]) & 0x0003
	m.Flags = Dot11Flags(data[1])
	m.DurationID = binary.LittleEndian.Uint16(data[2:4])
	m.Address1 = net.HardwareAddr(data[4:10])

	offset := 10

	mainType := m.Type.MainType()

	switch mainType {
	case Dot11TypeCtrl:
		switch m.Type {
		case Dot11TypeCtrlRTS, Dot11TypeCtrlPowersavePoll, Dot11TypeCtrlCFEnd, Dot11TypeCtrlCFEndAck:
			if len(data) < offset+6 {
				df.SetTruncated()
				return fmt.Errorf("Dot11 length %v too short, %v required", len(data), offset+6)
			}
			m.Address2 = net.HardwareAddr(data[offset : offset+6])
			offset += 6
		}
	case Dot11TypeMgmt, Dot11TypeData:
		if len(data) < offset+14 {
			df.SetTruncated()
			return fmt.Errorf("Dot11 length %v too short, %v required", len(data), offset+14)
		}
		m.Address2 = net.HardwareAddr(data[offset : offset+6])
		offset += 6
		m.Address3 = net.HardwareAddr(data[offset : offset+6])
		offset += 6

		m.SequenceNumber = (binary.LittleEndian.Uint16(data[offset:offset+2]) & 0xFFF0) >> 4
		m.FragmentNumber = (binary.LittleEndian.Uint16(data[offset:offset+2]) & 0x000F)
		offset += 2
	}

	if mainType == Dot11TypeData && m.Flags.FromDS() && m.Flags.ToDS() {
		if len(data) < offset+6 {
			df.SetTruncated()
			return fmt.Errorf("Dot11 length %v too short, %v required", len(data), offset+6)
		}
		m.Address4 = net.HardwareAddr(data[offset : offset+6])
		offset += 6
	}

	if m.Type.QOS() {
		if len(data) < offset+2 {
			df.SetTruncated()
			return fmt.Errorf("Dot11 length %v too short, %v required", len(data), offset+6)
		}
		m.QOS = &Dot11QOS{
			TID:       (uint8(data[offset]) & 0x0F),
			EOSP:      (uint8(data[offset]) & 0x10) == 0x10,
			AckPolicy: Dot11AckPolicy((uint8(data[offset]) & 0x60) >> 5),
			TXOP:      uint8(data[offset+1]),
		}
		offset += 2
	}
	if m.Flags.Order() && (m.Type.QOS() || mainType == Dot11TypeMgmt) {
		if len(data) < offset+4 {
			df.SetTruncated()
			return fmt.Errorf("Dot11 length %v too short, %v required", len(data), offset+6)
		}

		htc := &Dot11HTControl{
			ACConstraint: data[offset+3]&0x40 != 0,
			RDGMorePPDU:  data[offset+3]&0x80 != 0,
		}
		m.HTControl = htc

		if data[offset]&0x1 != 0 { // VHT Variant
			vht := &Dot11HTControlVHT{}
			htc.VHT = vht
			vht.MRQ = data[offset]&0x4 != 0
			vht.UnsolicitedMFB = data[offset+3]&0x20 != 0
			vht.MFB = Dot11HTControlMFB{
				NumSTS: uint8(data[offset+1] >> 1 & 0x7),
				VHTMCS: uint8(data[offset+1] >> 4 & 0xF),
				BW:     uint8(data[offset+2] & 0x3),
				SNR:    int8((-(data[offset+2] >> 2 & 0x20))+data[offset+2]>>2&0x1F) + 22,
			}

			if vht.UnsolicitedMFB {
				if !vht.MFB.NoFeedBackPresent() {
					vht.CompressedMSI = createU8(data[offset] >> 3 & 0x3)
					vht.STBCIndication = data[offset]&0x20 != 0
					vht.CodingType = (*Dot11CodingType)(createU8(data[offset+3] >> 3 & 0x1))
					vht.FbTXBeamformed = data[offset+3]&0x10 != 0
					vht.GID = createU8(
						data[offset]>>6 +
							(data[offset+1] & 0x1 << 2) +
							data[offset+3]&0x7<<3)
				}
			} else {
				if vht.MRQ {
					vht.MSI = createU8((data[offset] >> 3) & 0x07)
				}
				vht.MFSI = createU8(data[offset]>>6 + (data[offset+1] & 0x1 << 2))
			}

		} else { // HT Variant
			ht := &Dot11HTControlHT{}
			htc.HT = ht

			lac := &Dot11LinkAdapationControl{}
			ht.LinkAdapationControl = lac
			lac.TRQ = data[offset]&0x2 != 0
			lac.MFSI = data[offset]>>6&0x3 + data[offset+1]&0x1<<3
			if data[offset]&0x3C == 0x38 { // ASEL
				lac.ASEL = &Dot11ASEL{
					Command: data[offset+1] >> 1 & 0x7,
					Data:    data[offset+1] >> 4 & 0xF,
				}
			} else {
				lac.MRQ = data[offset]&0x4 != 0
				if lac.MRQ {
					lac.MSI = data[offset] >> 3 & 0x7
				}
				lac.MFB = createU8(data[offset+1] >> 1)
			}
			ht.CalibrationPosition = data[offset+2] & 0x3
			ht.CalibrationSequence = data[offset+2] >> 2 & 0x3
			ht.CSISteering = data[offset+2] >> 6 & 0x3
			ht.NDPAnnouncement = data[offset+3]&0x1 != 0
			if mainType != Dot11TypeMgmt {
				ht.DEI = data[offset+3]&0x20 != 0
			}
		}

		offset += 4
	}

	if len(data) < offset+4 {
		df.SetTruncated()
		return fmt.Errorf("Dot11 length %v too short, %v required", len(data), offset+4)
	}

	m.BaseLayer = BaseLayer{
		Contents: data[0:offset],
		Payload:  data[offset : len(data)-4],
	}

	if mainType == Dot11TypeData {
		l := dataDecodeMap[m.Type]()
		err := l.DecodeFromBytes(m.BaseLayer.Payload, df)
		if err != nil {
			return err
		}
		m.DataLayer = l.(gopacket.Layer)
	}

	m.Checksum = binary.LittleEndian.Uint32(data[len(data)-4 : len(data)])
	return nil
}

func (m *Dot11) ChecksumValid() bool {
	// only for CTRL and MGMT frames
	h := crc32.NewIEEE()
	h.Write(m.Contents)
	h.Write(m.Payload)
	return m.Checksum == h.Sum32()
}

func (m Dot11) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
	buf, err := b.PrependBytes(24)

	if err != nil {
		return err
	}

	buf[0] = (uint8(m.Type) << 2) | m.Proto
	buf[1] = uint8(m.Flags)

	binary.LittleEndian.PutUint16(buf[2:4], m.DurationID)

	copy(buf[4:10], m.Address1)

	offset := 10

	switch m.Type.MainType() {
	case Dot11TypeCtrl:
		switch m.Type {
		case Dot11TypeCtrlRTS, Dot11TypeCtrlPowersavePoll, Dot11TypeCtrlCFEnd, Dot11TypeCtrlCFEndAck:
			copy(buf[offset:offset+6], m.Address2)
			offset += 6
		}
	case Dot11TypeMgmt, Dot11TypeData:
		copy(buf[offset:offset+6], m.Address2)
		offset += 6
		copy(buf[offset:offset+6], m.Address3)
		offset += 6

		binary.LittleEndian.PutUint16(buf[offset:offset+2], (m.SequenceNumber<<4)|m.FragmentNumber)
		offset += 2
	}

	if m.Type.MainType() == Dot11TypeData && m.Flags.FromDS() && m.Flags.ToDS() {
		copy(buf[offset:offset+6], m.Address4)
		offset += 6
	}

	return nil
}

// Dot11Mgmt is a base for all IEEE 802.11 management layers.
type Dot11Mgmt struct {
	BaseLayer
}

func (m *Dot11Mgmt) NextLayerType() gopacket.LayerType { return gopacket.LayerTypePayload }
func (m *Dot11Mgmt) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
	m.Contents = data
	return nil
}

// Dot11Ctrl is a base for all IEEE 802.11 control layers.
type Dot11Ctrl struct {
	BaseLayer
}

func (m *Dot11Ctrl) NextLayerType() gopacket.LayerType { return gopacket.LayerTypePayload }

func (m *Dot11Ctrl) LayerType() gopacket.LayerType  { return LayerTypeDot11Ctrl }
func (m *Dot11Ctrl) CanDecode() gopacket.LayerClass { return LayerTypeDot11Ctrl }
func (m *Dot11Ctrl) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
	m.Contents = data
	return nil
}

func decodeDot11Ctrl(data []byte, p gopacket.PacketBuilder) error {
	d := &Dot11Ctrl{}
	return decodingLayerDecoder(d, data, p)
}

// Dot11WEP contains WEP encrpted IEEE 802.11 data.
type Dot11WEP struct {
	BaseLayer
}

func (m *Dot11WEP) NextLayerType() gopacket.LayerType { return gopacket.LayerTypePayload }

func (m *Dot11WEP) LayerType() gopacket.LayerType  { return LayerTypeDot11WEP }
func (m *Dot11WEP) CanDecode() gopacket.LayerClass { return LayerTypeDot11WEP }
func (m *Dot11WEP) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
	m.Contents = data
	return nil
}

func decodeDot11WEP(data []byte, p gopacket.PacketBuilder) error {
	d := &Dot11WEP{}
	return decodingLayerDecoder(d, data, p)
}

// Dot11Data is a base for all IEEE 802.11 data layers.
type Dot11Data struct {
	BaseLayer
}

func (m *Dot11Data) NextLayerType() gopacket.LayerType {
	return LayerTypeLLC
}

func (m *Dot11Data) LayerType() gopacket.LayerType  { return LayerTypeDot11Data }
func (m *Dot11Data) CanDecode() gopacket.LayerClass { return LayerTypeDot11Data }
func (m *Dot11Data) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
	m.Payload = data
	return nil
}

func decodeDot11Data(data []byte, p gopacket.PacketBuilder) error {
	d := &Dot11Data{}
	return decodingLayerDecoder(d, data, p)
}

type Dot11DataCFAck struct {
	Dot11Data
}

func decodeDot11DataCFAck(data []byte, p gopacket.PacketBuilder) error {
	d := &Dot11DataCFAck{}
	return decodingLayerDecoder(d, data, p)
}

func (m *Dot11DataCFAck) LayerType() gopacket.LayerType  { return LayerTypeDot11DataCFAck }
func (m *Dot11DataCFAck) CanDecode() gopacket.LayerClass { return LayerTypeDot11DataCFAck }
func (m *Dot11DataCFAck) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
	return m.Dot11Data.DecodeFromBytes(data, df)
}

type Dot11DataCFPoll struct {
	Dot11Data
}

func decodeDot11DataCFPoll(data []byte, p gopacket.PacketBuilder) error {
	d := &Dot11DataCFPoll{}
	return decodingLayerDecoder(d, data, p)
}

func (m *Dot11DataCFPoll) LayerType() gopacket.LayerType  { return LayerTypeDot11DataCFPoll }
func (m *Dot11DataCFPoll) CanDecode() gopacket.LayerClass { return LayerTypeDot11DataCFPoll }
func (m *Dot11DataCFPoll) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
	return m.Dot11Data.DecodeFromBytes(data, df)
}

type Dot11DataCFAckPoll struct {
	Dot11Data
}

func decodeDot11DataCFAckPoll(data []byte, p gopacket.PacketBuilder) error {
	d := &Dot11DataCFAckPoll{}
	return decodingLayerDecoder(d, data, p)
}

func (m *Dot11DataCFAckPoll) LayerType() gopacket.LayerType  { return LayerTypeDot11DataCFAckPoll }
func (m *Dot11DataCFAckPoll) CanDecode() gopacket.LayerClass { return LayerTypeDot11DataCFAckPoll }
func (m *Dot11DataCFAckPoll) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
	return m.Dot11Data.DecodeFromBytes(data, df)
}

type Dot11DataNull struct {
	Dot11Data
}

func decodeDot11DataNull(data []byte, p gopacket.PacketBuilder) error {
	d := &Dot11DataNull{}
	return decodingLayerDecoder(d, data, p)
}

func (m *Dot11DataNull) LayerType() gopacket.LayerType  { return LayerTypeDot11DataNull }
func (m *Dot11DataNull) CanDecode() gopacket.LayerClass { return LayerTypeDot11DataNull }
func (m *Dot11DataNull) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
	return m.Dot11Data.DecodeFromBytes(data, df)
}

type Dot11DataCFAckNoData struct {
	Dot11Data
}

func decodeDot11DataCFAckNoData(data []byte, p gopacket.PacketBuilder) error {
	d := &Dot11DataCFAckNoData{}
	return decodingLayerDecoder(d, data, p)
}

func (m *Dot11DataCFAckNoData) LayerType() gopacket.LayerType  { return LayerTypeDot11DataCFAckNoData }
func (m *Dot11DataCFAckNoData) CanDecode() gopacket.LayerClass { return LayerTypeDot11DataCFAckNoData }
func (m *Dot11DataCFAckNoData) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
	return m.Dot11Data.DecodeFromBytes(data, df)
}

type Dot11DataCFPollNoData struct {
	Dot11Data
}

func decodeDot11DataCFPollNoData(data []byte, p gopacket.PacketBuilder) error {
	d := &Dot11DataCFPollNoData{}
	return decodingLayerDecoder(d, data, p)
}

func (m *Dot11DataCFPollNoData) LayerType() gopacket.LayerType  { return LayerTypeDot11DataCFPollNoData }
func (m *Dot11DataCFPollNoData) CanDecode() gopacket.LayerClass { return LayerTypeDot11DataCFPollNoData }
func (m *Dot11DataCFPollNoData) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
	return m.Dot11Data.DecodeFromBytes(data, df)
}

type Dot11DataCFAckPollNoData struct {
	Dot11Data
}

func decodeDot11DataCFAckPollNoData(data []byte, p gopacket.PacketBuilder) error {
	d := &Dot11DataCFAckPollNoData{}
	return decodingLayerDecoder(d, data, p)
}

func (m *Dot11DataCFAckPollNoData) LayerType() gopacket.LayerType {
	return LayerTypeDot11DataCFAckPollNoData
}
func (m *Dot11DataCFAckPollNoData) CanDecode() gopacket.LayerClass {
	return LayerTypeDot11DataCFAckPollNoData
}
func (m *Dot11DataCFAckPollNoData) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
	return m.Dot11Data.DecodeFromBytes(data, df)
}

type Dot11DataQOS struct {
	Dot11Ctrl
}

func (m *Dot11DataQOS) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
	m.BaseLayer = BaseLayer{Payload: data}
	return nil
}

type Dot11DataQOSData struct {
	Dot11DataQOS
}

func decodeDot11DataQOSData(data []byte, p gopacket.PacketBuilder) error {
	d := &Dot11DataQOSData{}
	return decodingLayerDecoder(d, data, p)
}

func (m *Dot11DataQOSData) LayerType() gopacket.LayerType  { return LayerTypeDot11DataQOSData }
func (m *Dot11DataQOSData) CanDecode() gopacket.LayerClass { return LayerTypeDot11DataQOSData }

func (m *Dot11DataQOSData) NextLayerType() gopacket.LayerType {
	return LayerTypeDot11Data
}

type Dot11DataQOSDataCFAck struct {
	Dot11DataQOS
}

func decodeDot11DataQOSDataCFAck(data []byte, p gopacket.PacketBuilder) error {
	d := &Dot11DataQOSDataCFAck{}
	return decodingLayerDecoder(d, data, p)
}

func (m *Dot11DataQOSDataCFAck) LayerType() gopacket.LayerType     { return LayerTypeDot11DataQOSDataCFAck }
func (m *Dot11DataQOSDataCFAck) CanDecode() gopacket.LayerClass    { return LayerTypeDot11DataQOSDataCFAck }
func (m *Dot11DataQOSDataCFAck) NextLayerType() gopacket.LayerType { return LayerTypeDot11DataCFAck }

type Dot11DataQOSDataCFPoll struct {
	Dot11DataQOS
}

func decodeDot11DataQOSDataCFPoll(data []byte, p gopacket.PacketBuilder) error {
	d := &Dot11DataQOSDataCFPoll{}
	return decodingLayerDecoder(d, data, p)
}

func (m *Dot11DataQOSDataCFPoll) LayerType() gopacket.LayerType {
	return LayerTypeDot11DataQOSDataCFPoll
}
func (m *Dot11DataQOSDataCFPoll) CanDecode() gopacket.LayerClass {
	return LayerTypeDot11DataQOSDataCFPoll
}
func (m *Dot11DataQOSDataCFPoll) NextLayerType() gopacket.LayerType { return LayerTypeDot11DataCFPoll }

type Dot11DataQOSDataCFAckPoll struct {
	Dot11DataQOS
}

func decodeDot11DataQOSDataCFAckPoll(data []byte, p gopacket.PacketBuilder) error {
	d := &Dot11DataQOSDataCFAckPoll{}
	return decodingLayerDecoder(d, data, p)
}

func (m *Dot11DataQOSDataCFAckPoll) LayerType() gopacket.LayerType {
	return LayerTypeDot11DataQOSDataCFAckPoll
}
func (m *Dot11DataQOSDataCFAckPoll) CanDecode() gopacket.LayerClass {
	return LayerTypeDot11DataQOSDataCFAckPoll
}
func (m *Dot11DataQOSDataCFAckPoll) NextLayerType() gopacket.LayerType {
	return LayerTypeDot11DataCFAckPoll
}

type Dot11DataQOSNull struct {
	Dot11DataQOS
}

func decodeDot11DataQOSNull(data []byte, p gopacket.PacketBuilder) error {
	d := &Dot11DataQOSNull{}
	return decodingLayerDecoder(d, data, p)
}

func (m *Dot11DataQOSNull) LayerType() gopacket.LayerType     { return LayerTypeDot11DataQOSNull }
func (m *Dot11DataQOSNull) CanDecode() gopacket.LayerClass    { return LayerTypeDot11DataQOSNull }
func (m *Dot11DataQOSNull) NextLayerType() gopacket.LayerType { return LayerTypeDot11DataNull }

type Dot11DataQOSCFPollNoData struct {
	Dot11DataQOS
}

func decodeDot11DataQOSCFPollNoData(data []byte, p gopacket.PacketBuilder) error {
	d := &Dot11DataQOSCFPollNoData{}
	return decodingLayerDecoder(d, data, p)
}

func (m *Dot11DataQOSCFPollNoData) LayerType() gopacket.LayerType {
	return LayerTypeDot11DataQOSCFPollNoData
}
func (m *Dot11DataQOSCFPollNoData) CanDecode() gopacket.LayerClass {
	return LayerTypeDot11DataQOSCFPollNoData
}
func (m *Dot11DataQOSCFPollNoData) NextLayerType() gopacket.LayerType {
	return LayerTypeDot11DataCFPollNoData
}

type Dot11DataQOSCFAckPollNoData struct {
	Dot11DataQOS
}

func decodeDot11DataQOSCFAckPollNoData(data []byte, p gopacket.PacketBuilder) error {
	d := &Dot11DataQOSCFAckPollNoData{}
	return decodingLayerDecoder(d, data, p)
}

func (m *Dot11DataQOSCFAckPollNoData) LayerType() gopacket.LayerType {
	return LayerTypeDot11DataQOSCFAckPollNoData
}
func (m *Dot11DataQOSCFAckPollNoData) CanDecode() gopacket.LayerClass {
	return LayerTypeDot11DataQOSCFAckPollNoData
}
func (m *Dot11DataQOSCFAckPollNoData) NextLayerType() gopacket.LayerType {
	return LayerTypeDot11DataCFAckPollNoData
}

type Dot11InformationElement struct {
	BaseLayer
	ID     Dot11InformationElementID
	Length uint8
	OUI    []byte
	Info   []byte
}

func (m *Dot11InformationElement) LayerType() gopacket.LayerType {
	return LayerTypeDot11InformationElement
}
func (m *Dot11InformationElement) CanDecode() gopacket.LayerClass {
	return LayerTypeDot11InformationElement
}

func (m *Dot11InformationElement) NextLayerType() gopacket.LayerType {
	return LayerTypeDot11InformationElement
}

func (m *Dot11InformationElement) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
	if len(data) < 2 {
		df.SetTruncated()
		return fmt.Errorf("Dot11InformationElement length %v too short, %v required", len(data), 2)
	}
	m.ID = Dot11InformationElementID(data[0])
	m.Length = data[1]
	offset := int(2)

	if len(data) < offset+int(m.Length) {
		df.SetTruncated()
		return fmt.Errorf("Dot11InformationElement length %v too short, %v required", len(data), offset+int(m.Length))
	}
	if m.ID == 221 {
		// Vendor extension
		m.OUI = data[offset : offset+4]
		m.Info = data[offset+4 : offset+int(m.Length)]
	} else {
		m.Info = data[offset : offset+int(m.Length)]
	}

	offset += int(m.Length)

	m.BaseLayer = BaseLayer{Contents: data[:offset], Payload: data[offset:]}
	return nil
}

func (d *Dot11InformationElement) String() string {
	if d.ID == 0 {
		return fmt.Sprintf("802.11 Information Element (ID: %v, Length: %v, SSID: %v)", d.ID, d.Length, string(d.Info))
	} else if d.ID == 1 {
		rates := ""
		for i := 0; i < len(d.Info); i++ {
			if d.Info[i]&0x80 == 0 {
				rates += fmt.Sprintf("%.1f ", float32(d.Info[i])*0.5)
			} else {
				rates += fmt.Sprintf("%.1f* ", float32(d.Info[i]&0x7F)*0.5)
			}
		}
		return fmt.Sprintf("802.11 Information Element (ID: %v, Length: %v, Rates: %s Mbit)", d.ID, d.Length, rates)
	} else if d.ID == 221 {
		return fmt.Sprintf("802.11 Information Element (ID: %v, Length: %v, OUI: %X, Info: %X)", d.ID, d.Length, d.OUI, d.Info)
	} else {
		return fmt.Sprintf("802.11 Information Element (ID: %v, Length: %v, Info: %X)", d.ID, d.Length, d.Info)
	}
}

func (m Dot11InformationElement) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
	length := len(m.Info) + len(m.OUI)
	if buf, err := b.PrependBytes(2 + length); err != nil {
		return err
	} else {
		buf[0] = uint8(m.ID)
		buf[1] = uint8(length)
		copy(buf[2:], m.OUI)
		copy(buf[2+len(m.OUI):], m.Info)
	}
	return nil
}

func decodeDot11InformationElement(data []byte, p gopacket.PacketBuilder) error {
	d := &Dot11InformationElement{}
	return decodingLayerDecoder(d, data, p)
}

type Dot11CtrlCTS struct {
	Dot11Ctrl
}

func decodeDot11CtrlCTS(data []byte, p gopacket.PacketBuilder) error {
	d := &Dot11CtrlCTS{}
	return decodingLayerDecoder(d, data, p)
}

func (m *Dot11CtrlCTS) LayerType() gopacket.LayerType {
	return LayerTypeDot11CtrlCTS
}
func (m *Dot11CtrlCTS) CanDecode() gopacket.LayerClass {
	return LayerTypeDot11CtrlCTS
}
func (m *Dot11CtrlCTS) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
	return m.Dot11Ctrl.DecodeFromBytes(data, df)
}

type Dot11CtrlRTS struct {
	Dot11Ctrl
}

func decodeDot11CtrlRTS(data []byte, p gopacket.PacketBuilder) error {
	d := &Dot11CtrlRTS{}
	return decodingLayerDecoder(d, data, p)
}

func (m *Dot11CtrlRTS) LayerType() gopacket.LayerType {
	return LayerTypeDot11CtrlRTS
}
func (m *Dot11CtrlRTS) CanDecode() gopacket.LayerClass {
	return LayerTypeDot11CtrlRTS
}
func (m *Dot11CtrlRTS) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
	return m.Dot11Ctrl.DecodeFromBytes(data, df)
}

type Dot11CtrlBlockAckReq struct {
	Dot11Ctrl
}

func decodeDot11CtrlBlockAckReq(data []byte, p gopacket.PacketBuilder) error {
	d := &Dot11CtrlBlockAckReq{}
	return decodingLayerDecoder(d, data, p)
}

func (m *Dot11CtrlBlockAckReq) LayerType() gopacket.LayerType {
	return LayerTypeDot11CtrlBlockAckReq
}
func (m *Dot11CtrlBlockAckReq) CanDecode() gopacket.LayerClass {
	return LayerTypeDot11CtrlBlockAckReq
}
func (m *Dot11CtrlBlockAckReq) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
	return m.Dot11Ctrl.DecodeFromBytes(data, df)
}

type Dot11CtrlBlockAck struct {
	Dot11Ctrl
}

func decodeDot11CtrlBlockAck(data []byte, p gopacket.PacketBuilder) error {
	d := &Dot11CtrlBlockAck{}
	return decodingLayerDecoder(d, data, p)
}

func (m *Dot11CtrlBlockAck) LayerType() gopacket.LayerType  { return LayerTypeDot11CtrlBlockAck }
func (m *Dot11CtrlBlockAck) CanDecode() gopacket.LayerClass { return LayerTypeDot11CtrlBlockAck }
func (m *Dot11CtrlBlockAck) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
	return m.Dot11Ctrl.DecodeFromBytes(data, df)
}

type Dot11CtrlPowersavePoll struct {
	Dot11Ctrl
}

func decodeDot11CtrlPowersavePoll(data []byte, p gopacket.PacketBuilder) error {
	d := &Dot11CtrlPowersavePoll{}
	return decodingLayerDecoder(d, data, p)
}

func (m *Dot11CtrlPowersavePoll) LayerType() gopacket.LayerType {
	return LayerTypeDot11CtrlPowersavePoll
}
func (m *Dot11CtrlPowersavePoll) CanDecode() gopacket.LayerClass {
	return LayerTypeDot11CtrlPowersavePoll
}
func (m *Dot11CtrlPowersavePoll) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
	return m.Dot11Ctrl.DecodeFromBytes(data, df)
}

type Dot11CtrlAck struct {
	Dot11Ctrl
}

func decodeDot11CtrlAck(data []byte, p gopacket.PacketBuilder) error {
	d := &Dot11CtrlAck{}
	return decodingLayerDecoder(d, data, p)
}

func (m *Dot11CtrlAck) LayerType() gopacket.LayerType  { return LayerTypeDot11CtrlAck }
func (m *Dot11CtrlAck) CanDecode() gopacket.LayerClass { return LayerTypeDot11CtrlAck }
func (m *Dot11CtrlAck) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
	return m.Dot11Ctrl.DecodeFromBytes(data, df)
}

type Dot11CtrlCFEnd struct {
	Dot11Ctrl
}

func decodeDot11CtrlCFEnd(data []byte, p gopacket.PacketBuilder) error {
	d := &Dot11CtrlCFEnd{}
	return decodingLayerDecoder(d, data, p)
}

func (m *Dot11CtrlCFEnd) LayerType() gopacket.LayerType {
	return LayerTypeDot11CtrlCFEnd
}
func (m *Dot11CtrlCFEnd) CanDecode() gopacket.LayerClass {
	return LayerTypeDot11CtrlCFEnd
}
func (m *Dot11CtrlCFEnd) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
	return m.Dot11Ctrl.DecodeFromBytes(data, df)
}

type Dot11CtrlCFEndAck struct {
	Dot11Ctrl
}

func decodeDot11CtrlCFEndAck(data []byte, p gopacket.PacketBuilder) error {
	d := &Dot11CtrlCFEndAck{}
	return decodingLayerDecoder(d, data, p)
}

func (m *Dot11CtrlCFEndAck) LayerType() gopacket.LayerType {
	return LayerTypeDot11CtrlCFEndAck
}
func (m *Dot11CtrlCFEndAck) CanDecode() gopacket.LayerClass {
	return LayerTypeDot11CtrlCFEndAck
}
func (m *Dot11CtrlCFEndAck) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
	return m.Dot11Ctrl.DecodeFromBytes(data, df)
}

type Dot11MgmtAssociationReq struct {
	Dot11Mgmt
	CapabilityInfo uint16
	ListenInterval uint16
}

func decodeDot11MgmtAssociationReq(data []byte, p gopacket.PacketBuilder) error {
	d := &Dot11MgmtAssociationReq{}
	return decodingLayerDecoder(d, data, p)
}

func (m *Dot11MgmtAssociationReq) LayerType() gopacket.LayerType {
	return LayerTypeDot11MgmtAssociationReq
}
func (m *Dot11MgmtAssociationReq) CanDecode() gopacket.LayerClass {
	return LayerTypeDot11MgmtAssociationReq
}
func (m *Dot11MgmtAssociationReq) NextLayerType() gopacket.LayerType {
	return LayerTypeDot11InformationElement
}
func (m *Dot11MgmtAssociationReq) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
	if len(data) < 4 {
		df.SetTruncated()
		return fmt.Errorf("Dot11MgmtAssociationReq length %v too short, %v required", len(data), 4)
	}
	m.CapabilityInfo = binary.LittleEndian.Uint16(data[0:2])
	m.ListenInterval = binary.LittleEndian.Uint16(data[2:4])
	m.Payload = data[4:]
	return m.Dot11Mgmt.DecodeFromBytes(data, df)
}

func (m Dot11MgmtAssociationReq) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
	buf, err := b.PrependBytes(4)

	if err != nil {
		return err
	}

	binary.LittleEndian.PutUint16(buf[0:2], m.CapabilityInfo)
	binary.LittleEndian.PutUint16(buf[2:4], m.ListenInterval)

	return nil
}

type Dot11MgmtAssociationResp struct {
	Dot11Mgmt
	CapabilityInfo uint16
	Status         Dot11Status
	AID            uint16
}

func decodeDot11MgmtAssociationResp(data []byte, p gopacket.PacketBuilder) error {
	d := &Dot11MgmtAssociationResp{}
	return decodingLayerDecoder(d, data, p)
}

func (m *Dot11MgmtAssociationResp) CanDecode() gopacket.LayerClass {
	return LayerTypeDot11MgmtAssociationResp
}
func (m *Dot11MgmtAssociationResp) LayerType() gopacket.LayerType {
	return LayerTypeDot11MgmtAssociationResp
}
func (m *Dot11MgmtAssociationResp) NextLayerType() gopacket.LayerType {
	return LayerTypeDot11InformationElement
}
func (m *Dot11MgmtAssociationResp) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
	if len(data) < 6 {
		df.SetTruncated()
		return fmt.Errorf("Dot11MgmtAssociationResp length %v too short, %v required", len(data), 6)
	}
	m.CapabilityInfo = binary.LittleEndian.Uint16(data[0:2])
	m.Status = Dot11Status(binary.LittleEndian.Uint16(data[2:4]))
	m.AID = binary.LittleEndian.Uint16(data[4:6])
	m.Payload = data[6:]
	return m.Dot11Mgmt.DecodeFromBytes(data, df)
}

func (m Dot11MgmtAssociationResp) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
	buf, err := b.PrependBytes(6)

	if err != nil {
		return err
	}

	binary.LittleEndian.PutUint16(buf[0:2], m.CapabilityInfo)
	binary.LittleEndian.PutUint16(buf[2:4], uint16(m.Status))
	binary.LittleEndian.PutUint16(buf[4:6], m.AID)

	return nil
}

type Dot11MgmtReassociationReq struct {
	Dot11Mgmt
	CapabilityInfo   uint16
	ListenInterval   uint16
	CurrentApAddress net.HardwareAddr
}

func decodeDot11MgmtReassociationReq(data []byte, p gopacket.PacketBuilder) error {
	d := &Dot11MgmtReassociationReq{}
	return decodingLayerDecoder(d, data, p)
}

func (m *Dot11MgmtReassociationReq) LayerType() gopacket.LayerType {
	return LayerTypeDot11MgmtReassociationReq
}
func (m *Dot11MgmtReassociationReq) CanDecode() gopacket.LayerClass {
	return LayerTypeDot11MgmtReassociationReq
}
func (m *Dot11MgmtReassociationReq) NextLayerType() gopacket.LayerType {
	return LayerTypeDot11InformationElement
}
func (m *Dot11MgmtReassociationReq) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
	if len(data) < 10 {
		df.SetTruncated()
		return fmt.Errorf("Dot11MgmtReassociationReq length %v too short, %v required", len(data), 10)
	}
	m.CapabilityInfo = binary.LittleEndian.Uint16(data[0:2])
	m.ListenInterval = binary.LittleEndian.Uint16(data[2:4])
	m.CurrentApAddress = net.HardwareAddr(data[4:10])
	m.Payload = data[10:]
	return m.Dot11Mgmt.DecodeFromBytes(data, df)
}

func (m Dot11MgmtReassociationReq) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
	buf, err := b.PrependBytes(10)

	if err != nil {
		return err
	}

	binary.LittleEndian.PutUint16(buf[0:2], m.CapabilityInfo)
	binary.LittleEndian.PutUint16(buf[2:4], m.ListenInterval)

	copy(buf[4:10], m.CurrentApAddress)

	return nil
}

type Dot11MgmtReassociationResp struct {
	Dot11Mgmt
}

func decodeDot11MgmtReassociationResp(data []byte, p gopacket.PacketBuilder) error {
	d := &Dot11MgmtReassociationResp{}
	return decodingLayerDecoder(d, data, p)
}

func (m *Dot11MgmtReassociationResp) LayerType() gopacket.LayerType {
	return LayerTypeDot11MgmtReassociationResp
}
func (m *Dot11MgmtReassociationResp) CanDecode() gopacket.LayerClass {
	return LayerTypeDot11MgmtReassociationResp
}
func (m *Dot11MgmtReassociationResp) NextLayerType() gopacket.LayerType {
	return LayerTypeDot11InformationElement
}

type Dot11MgmtProbeReq struct {
	Dot11Mgmt
}

func decodeDot11MgmtProbeReq(data []byte, p gopacket.PacketBuilder) error {
	d := &Dot11MgmtProbeReq{}
	return decodingLayerDecoder(d, data, p)
}

func (m *Dot11MgmtProbeReq) LayerType() gopacket.LayerType  { return LayerTypeDot11MgmtProbeReq }
func (m *Dot11MgmtProbeReq) CanDecode() gopacket.LayerClass { return LayerTypeDot11MgmtProbeReq }
func (m *Dot11MgmtProbeReq) NextLayerType() gopacket.LayerType {
	return LayerTypeDot11InformationElement
}

type Dot11MgmtProbeResp struct {
	Dot11Mgmt
	Timestamp uint64
	Interval  uint16
	Flags     uint16
}

func decodeDot11MgmtProbeResp(data []byte, p gopacket.PacketBuilder) error {
	d := &Dot11MgmtProbeResp{}
	return decodingLayerDecoder(d, data, p)
}

func (m *Dot11MgmtProbeResp) LayerType() gopacket.LayerType  { return LayerTypeDot11MgmtProbeResp }
func (m *Dot11MgmtProbeResp) CanDecode() gopacket.LayerClass { return LayerTypeDot11MgmtProbeResp }
func (m *Dot11MgmtProbeResp) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
	if len(data) < 12 {
		df.SetTruncated()

		return fmt.Errorf("Dot11MgmtProbeResp length %v too short, %v required", len(data), 12)
	}

	m.Timestamp = binary.LittleEndian.Uint64(data[0:8])
	m.Interval = binary.LittleEndian.Uint16(data[8:10])
	m.Flags = binary.LittleEndian.Uint16(data[10:12])
	m.Payload = data[12:]

	return m.Dot11Mgmt.DecodeFromBytes(data, df)
}

func (m *Dot11MgmtProbeResp) NextLayerType() gopacket.LayerType {
	return LayerTypeDot11InformationElement
}

func (m Dot11MgmtProbeResp) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
	buf, err := b.PrependBytes(12)

	if err != nil {
		return err
	}

	binary.LittleEndian.PutUint64(buf[0:8], m.Timestamp)
	binary.LittleEndian.PutUint16(buf[8:10], m.Interval)
	binary.LittleEndian.PutUint16(buf[10:12], m.Flags)

	return nil
}

type Dot11MgmtMeasurementPilot struct {
	Dot11Mgmt
}

func decodeDot11MgmtMeasurementPilot(data []byte, p gopacket.PacketBuilder) error {
	d := &Dot11MgmtMeasurementPilot{}
	return decodingLayerDecoder(d, data, p)
}

func (m *Dot11MgmtMeasurementPilot) LayerType() gopacket.LayerType {
	return LayerTypeDot11MgmtMeasurementPilot
}
func (m *Dot11MgmtMeasurementPilot) CanDecode() gopacket.LayerClass {
	return LayerTypeDot11MgmtMeasurementPilot
}

type Dot11MgmtBeacon struct {
	Dot11Mgmt
	Timestamp uint64
	Interval  uint16
	Flags     uint16
}

func decodeDot11MgmtBeacon(data []byte, p gopacket.PacketBuilder) error {
	d := &Dot11MgmtBeacon{}
	return decodingLayerDecoder(d, data, p)
}

func (m *Dot11MgmtBeacon) LayerType() gopacket.LayerType  { return LayerTypeDot11MgmtBeacon }
func (m *Dot11MgmtBeacon) CanDecode() gopacket.LayerClass { return LayerTypeDot11MgmtBeacon }
func (m *Dot11MgmtBeacon) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
	if len(data) < 12 {
		df.SetTruncated()
		return fmt.Errorf("Dot11MgmtBeacon length %v too short, %v required", len(data), 12)
	}
	m.Timestamp = binary.LittleEndian.Uint64(data[0:8])
	m.Interval = binary.LittleEndian.Uint16(data[8:10])
	m.Flags = binary.LittleEndian.Uint16(data[10:12])
	m.Payload = data[12:]
	return m.Dot11Mgmt.DecodeFromBytes(data, df)
}

func (m *Dot11MgmtBeacon) NextLayerType() gopacket.LayerType { return LayerTypeDot11InformationElement }

func (m Dot11MgmtBeacon) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
	buf, err := b.PrependBytes(12)

	if err != nil {
		return err
	}

	binary.LittleEndian.PutUint64(buf[0:8], m.Timestamp)
	binary.LittleEndian.PutUint16(buf[8:10], m.Interval)
	binary.LittleEndian.PutUint16(buf[10:12], m.Flags)

	return nil
}

type Dot11MgmtATIM struct {
	Dot11Mgmt
}

func decodeDot11MgmtATIM(data []byte, p gopacket.PacketBuilder) error {
	d := &Dot11MgmtATIM{}
	return decodingLayerDecoder(d, data, p)
}

func (m *Dot11MgmtATIM) LayerType() gopacket.LayerType  { return LayerTypeDot11MgmtATIM }
func (m *Dot11MgmtATIM) CanDecode() gopacket.LayerClass { return LayerTypeDot11MgmtATIM }

type Dot11MgmtDisassociation struct {
	Dot11Mgmt
	Reason Dot11Reason
}

func decodeDot11MgmtDisassociation(data []byte, p gopacket.PacketBuilder) error {
	d := &Dot11MgmtDisassociation{}
	return decodingLayerDecoder(d, data, p)
}

func (m *Dot11MgmtDisassociation) LayerType() gopacket.LayerType {
	return LayerTypeDot11MgmtDisassociation
}
func (m *Dot11MgmtDisassociation) CanDecode() gopacket.LayerClass {
	return LayerTypeDot11MgmtDisassociation
}
func (m *Dot11MgmtDisassociation) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
	if len(data) < 2 {
		df.SetTruncated()
		return fmt.Errorf("Dot11MgmtDisassociation length %v too short, %v required", len(data), 2)
	}
	m.Reason = Dot11Reason(binary.LittleEndian.Uint16(data[0:2]))
	return m.Dot11Mgmt.DecodeFromBytes(data, df)
}

func (m Dot11MgmtDisassociation) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
	buf, err := b.PrependBytes(2)

	if err != nil {
		return err
	}

	binary.LittleEndian.PutUint16(buf[0:2], uint16(m.Reason))

	return nil
}

type Dot11MgmtAuthentication struct {
	Dot11Mgmt
	Algorithm Dot11Algorithm
	Sequence  uint16
	Status    Dot11Status
}

func decodeDot11MgmtAuthentication(data []byte, p gopacket.PacketBuilder) error {
	d := &Dot11MgmtAuthentication{}
	return decodingLayerDecoder(d, data, p)
}

func (m *Dot11MgmtAuthentication) LayerType() gopacket.LayerType {
	return LayerTypeDot11MgmtAuthentication
}
func (m *Dot11MgmtAuthentication) CanDecode() gopacket.LayerClass {
	return LayerTypeDot11MgmtAuthentication
}
func (m *Dot11MgmtAuthentication) NextLayerType() gopacket.LayerType {
	return LayerTypeDot11InformationElement
}
func (m *Dot11MgmtAuthentication) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
	if len(data) < 6 {
		df.SetTruncated()
		return fmt.Errorf("Dot11MgmtAuthentication length %v too short, %v required", len(data), 6)
	}
	m.Algorithm = Dot11Algorithm(binary.LittleEndian.Uint16(data[0:2]))
	m.Sequence = binary.LittleEndian.Uint16(data[2:4])
	m.Status = Dot11Status(binary.LittleEndian.Uint16(data[4:6]))
	m.Payload = data[6:]
	return m.Dot11Mgmt.DecodeFromBytes(data, df)
}

func (m Dot11MgmtAuthentication) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
	buf, err := b.PrependBytes(6)

	if err != nil {
		return err
	}

	binary.LittleEndian.PutUint16(buf[0:2], uint16(m.Algorithm))
	binary.LittleEndian.PutUint16(buf[2:4], m.Sequence)
	binary.LittleEndian.PutUint16(buf[4:6], uint16(m.Status))

	return nil
}

type Dot11MgmtDeauthentication struct {
	Dot11Mgmt
	Reason Dot11Reason
}

func decodeDot11MgmtDeauthentication(data []byte, p gopacket.PacketBuilder) error {
	d := &Dot11MgmtDeauthentication{}
	return decodingLayerDecoder(d, data, p)
}

func (m *Dot11MgmtDeauthentication) LayerType() gopacket.LayerType {
	return LayerTypeDot11MgmtDeauthentication
}
func (m *Dot11MgmtDeauthentication) CanDecode() gopacket.LayerClass {
	return LayerTypeDot11MgmtDeauthentication
}
func (m *Dot11MgmtDeauthentication) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
	if len(data) < 2 {
		df.SetTruncated()
		return fmt.Errorf("Dot11MgmtDeauthentication length %v too short, %v required", len(data), 2)
	}
	m.Reason = Dot11Reason(binary.LittleEndian.Uint16(data[0:2]))
	return m.Dot11Mgmt.DecodeFromBytes(data, df)
}

func (m Dot11MgmtDeauthentication) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
	buf, err := b.PrependBytes(2)

	if err != nil {
		return err
	}

	binary.LittleEndian.PutUint16(buf[0:2], uint16(m.Reason))

	return nil
}

type Dot11MgmtAction struct {
	Dot11Mgmt
}

func decodeDot11MgmtAction(data []byte, p gopacket.PacketBuilder) error {
	d := &Dot11MgmtAction{}
	return decodingLayerDecoder(d, data, p)
}

func (m *Dot11MgmtAction) LayerType() gopacket.LayerType  { return LayerTypeDot11MgmtAction }
func (m *Dot11MgmtAction) CanDecode() gopacket.LayerClass { return LayerTypeDot11MgmtAction }

type Dot11MgmtActionNoAck struct {
	Dot11Mgmt
}

func decodeDot11MgmtActionNoAck(data []byte, p gopacket.PacketBuilder) error {
	d := &Dot11MgmtActionNoAck{}
	return decodingLayerDecoder(d, data, p)
}

func (m *Dot11MgmtActionNoAck) LayerType() gopacket.LayerType  { return LayerTypeDot11MgmtActionNoAck }
func (m *Dot11MgmtActionNoAck) CanDecode() gopacket.LayerClass { return LayerTypeDot11MgmtActionNoAck }

type Dot11MgmtArubaWLAN struct {
	Dot11Mgmt
}

func decodeDot11MgmtArubaWLAN(data []byte, p gopacket.PacketBuilder) error {
	d := &Dot11MgmtArubaWLAN{}
	return decodingLayerDecoder(d, data, p)
}

func (m *Dot11MgmtArubaWLAN) LayerType() gopacket.LayerType  { return LayerTypeDot11MgmtArubaWLAN }
func (m *Dot11MgmtArubaWLAN) CanDecode() gopacket.LayerClass { return LayerTypeDot11MgmtArubaWLAN }
